From 6f56acafb25ed0e0b1518f636ccf7096ab3f8aa1 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Fri, 9 Sep 2011 00:05:15 +0200 Subject: [PATCH 0001/5359] First implementation of the CLI, focussed on plugin actions --- engine/command.php | 26 +++++++ engine/config.php | 18 +++++ library/commands/plugins.php | 143 +++++++++++++++++++++++++++++++++++ wp | 36 +++++++++ 4 files changed, 223 insertions(+) create mode 100644 engine/command.php create mode 100644 engine/config.php create mode 100644 library/commands/plugins.php create mode 100755 wp diff --git a/engine/command.php b/engine/command.php new file mode 100644 index 000000000..22825a74c --- /dev/null +++ b/engine/command.php @@ -0,0 +1,26 @@ +$sub_command($args); + } + else { + $this->help($args); + } + } + + public function help() { + print_r(get_class_methods($this)); + } + + protected function parse_args() { + + } + + protected function _echo($string) { + echo $string."\n"; + } +} \ No newline at end of file diff --git a/engine/config.php b/engine/config.php new file mode 100644 index 000000000..a940cd171 --- /dev/null +++ b/engine/config.php @@ -0,0 +1,18 @@ +parse_name($name); + + $details = $this->get_details($file); + + $this->_echo('Plugin '.$name.' details:'); + $this->_echo(' Active: '.((int) is_plugin_active($file))); + if(is_multisite()) { + $this->_echo(' Network: '.((int) is_plugin_active_for_network($file))); + } + $this->_echo(' Version: '.$details['Version']); + } + } + + function activate($args) { + if(!empty($args)) { + $name = $args[0]; + $file = $this->parse_name($name); + + if(is_plugin_active($file)) { + $this->_echo('The plugin is already active: '.$name); + } + elseif(activate_plugin($file) === null) { + $this->_echo('Plugin activated: '.$name); + } + } + } + + function deactivate($args) { + if(!empty($args)) { + $name = $args[0]; + $file = $this->parse_name($name); + + if(is_plugin_inactive($file)) { + $this->_echo('The plugin is already deactivate: '.$name); + } + elseif(deactivate_plugins($file) === null) { + $this->_echo('Plugin deactivated: '.$name); + } + } + } + + function install($args) { + if(!empty($args)) { + $name = $args[0]; + + $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); + $status = install_plugin_install_status($api); + echo 'Updating '.$name.": "; + ob_start('strip_tags'); + + switch($status['status']) { + case 'update_available': + case 'install': + $upgrader = new Plugin_Upgrader(); + $upgrader->install($api->download_link); + break; + case 'newer_installed': + $this->_echo(sprintf('Newer Version (%s) Installed', $status['version'])); + break; + case 'latest_installed': + $this->_echo('Latest Version Installed'); + $file = $this->parse_name($name); + + if(is_plugin_inactive($file)) { + $this->_echo('If you want to activate the plugin, run \'wp plugins activate '.$name.'\''); + } + break; + } + } + } + + function delete($args) { + if(!empty($args)) { + $name = $args[0]; + $file = $this->parse_name($name); + + $success = delete_plugins(array($file)); + } + } + + function update($args) { + if(!empty($args)) { + $name = $args[0]; + $file = $this->parse_name($name); + + wp_update_plugins(); + + echo 'Updating '.$name.": "; + ob_start('strip_tags'); + $success = wp_update_plugin($file); + } + else { + echo 'Usage: wp plugins update .'."\n"; + } + } + + private function get_details($file) { + $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); + $plugin_file = basename(($file)); + + return $plugin_folder[$plugin_file]; + } +} \ No newline at end of file diff --git a/wp b/wp new file mode 100755 index 000000000..a5f066cf4 --- /dev/null +++ b/wp @@ -0,0 +1,36 @@ +#!/usr/bin/env php + Date: Fri, 9 Sep 2011 23:08:16 +0200 Subject: [PATCH 0002/5359] * New command for core actions * Updated the plugin commands * Added a Wordpress Uprade skin: CLI_Upgrade_Skin to prevent the output buffer to be flushed --- engine/functions.php | 71 ++++++++++++++++++++++++++++++++++++ library/commands/core.php | 28 ++++++++++++++ library/commands/plugins.php | 30 ++++++++++----- wp | 8 ++-- 4 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 engine/functions.php create mode 100644 library/commands/core.php diff --git a/engine/functions.php b/engine/functions.php new file mode 100644 index 000000000..e0744a4e0 --- /dev/null +++ b/engine/functions.php @@ -0,0 +1,71 @@ +get_error_code() ) { + foreach ( $errors->get_error_messages() as $message ) { + if ( $errors->get_error_data() ) + return $message . ' ' . $errors->get_error_data(); + else + return $message; + } + } +} + +class CLI_Upgrader_Skin { + var $upgrader; + var $done_header = false; + var $result = false; + + function __construct($args = array()) { + $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); + $this->options = wp_parse_args($args, $defaults); + } + + function set_upgrader(&$upgrader) { + if ( is_object($upgrader) ) + $this->upgrader =& $upgrader; + $this->add_strings(); + } + + function add_strings() {} + + function set_result($result) { + $this->result = $result; + } + + function request_filesystem_credentials($error = false) { + $url = $this->options['url']; + $context = $this->options['context']; + if ( !empty($this->options['nonce']) ) + $url = wp_nonce_url($url, $this->options['nonce']); + return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now. + } + + function header() {} + function footer() {} + + function error($errors) { + $this->feedback(error_to_string($errors)); + } + + function feedback($string) { + if ( isset( $this->upgrader->strings[$string] ) ) + $string = $this->upgrader->strings[$string]; + + if ( strpos($string, '%') !== false ) { + $args = func_get_args(); + $args = array_splice($args, 1); + if ( !empty($args) ) + $string = vsprintf($string, $args); + } + if ( empty($string) ) + return; + + echo $string; + } + function before() {} + function after() {} +} \ No newline at end of file diff --git a/library/commands/core.php b/library/commands/core.php new file mode 100644 index 000000000..7b49a7445 --- /dev/null +++ b/library/commands/core.php @@ -0,0 +1,28 @@ +upgrade($current); + $feedback = ob_get_clean(); + $this->_echo($feedback); + + // Borrowed verbatim from wp-admin/update-core.php + if(is_wp_error($result) ) { + $this->_echo(error_to_string($result)); + if('up_to_date' != $result->get_error_code()) { + $this->_echo('Installation Failed'); + } + } + else { + $this->_echo('WordPress upgraded successfully'); + } + } +} \ No newline at end of file diff --git a/library/commands/plugins.php b/library/commands/plugins.php index 987d25f40..0bd2ed65c 100644 --- a/library/commands/plugins.php +++ b/library/commands/plugins.php @@ -5,8 +5,6 @@ require_once(ABSPATH.'wp-admin/includes/plugin.php'); require_once(ABSPATH.'wp-admin/includes/plugin-install.php'); -require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); - /** * Returns current plugin version. @@ -86,13 +84,18 @@ function install($args) { $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); $status = install_plugin_install_status($api); echo 'Updating '.$name.": "; - ob_start('strip_tags'); - + switch($status['status']) { case 'update_available': case 'install': - $upgrader = new Plugin_Upgrader(); - $upgrader->install($api->download_link); + ob_start(); + if(!class_exists('Plugin_Upgrader')) { + require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); + } + $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); + $result = $upgrader->install($api->download_link); + $feedback = ob_get_clean(); + $this->_echo($feedback); break; case 'newer_installed': $this->_echo(sprintf('Newer Version (%s) Installed', $status['version'])); @@ -126,11 +129,20 @@ function update($args) { wp_update_plugins(); echo 'Updating '.$name.": "; - ob_start('strip_tags'); - $success = wp_update_plugin($file); + ob_start(); + + if(!class_exists('Plugin_Upgrader')) { + require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); + } + + $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); + $success = $upgrader->upgrade($file); + + $feedback = ob_get_clean(); + $this->_echo($feedback); } else { - echo 'Usage: wp plugins update .'."\n"; + $this->_echo('Usage: wp plugins update .'); } } diff --git a/wp b/wp index a5f066cf4..4ebd1399a 100755 --- a/wp +++ b/wp @@ -15,11 +15,13 @@ class WP_CLI { include 'engine/command.php'; include 'engine/config.php'; -include 'library/commands/plugins.php'; +include 'engine/functions.php'; -// Start output buffering to stop WordPress from spitting out its usual output. +foreach (glob('library/commands/*.php') as $filename) { + include $filename; +} -//print_r($GLOBALS['argv']); +// Start output buffering to stop WordPress from spitting out its usual output. // Remove the first entry $arguments = array_shift($GLOBALS['argv']); From d5719fe30803df956989a2de1162606a2cc9afb5 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Fri, 9 Sep 2011 23:17:04 +0200 Subject: [PATCH 0003/5359] - Implemented a script to find the right php cli - Moved some things around --- engine/command.php | 12 +++-- wp | 131 ++++++++++++++++++++++++++++++++------------- wp.php | 30 +++++++++++ 3 files changed, 131 insertions(+), 42 deletions(-) create mode 100755 wp.php diff --git a/engine/command.php b/engine/command.php index 22825a74c..c33d1d996 100644 --- a/engine/command.php +++ b/engine/command.php @@ -1,5 +1,13 @@ /dev/null), then the +# error message is suppressed, but tput cols becomes confused about the +# terminal and prints out the default value (80). +if [ -z $COLUMNS ] && [ -n "$TERM" ] && [ "$TERM" != dumb ] ; then + # Note to cygwin users: install the ncurses package to get tput command. + if COLUMNS=$(tput cols); then + export COLUMNS + fi +fi + +if [ ! -z "$WP_CLI_PHP" ] ; then + # Use the WP_CLI_PHP environment variable if it is available. + php="$WP_CLI_PHP" +else + # Default to using the php that we find on the PATH. + # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 + php=`which php` + + # We check for a command line (cli) version of php, and if found use that. + which php-cli >/dev/null 2>&1 + if [ "$?" = 0 ] ; then + php=`which php-cli` + fi + + # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. + for amp_php in /Applications/MAMP/bin/php5/bin/php /Applications/MAMP/bin/php5.2/bin/php /Applications/MAMP/bin/php5.3/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + if [ -x $amp_php ]; then + php=$amp_php + fi + done +fi + +# Check to see if the user has provided a php.ini file or wp-cli.ini file in any conf dir +# Last found wins, so search in reverse priority order +for conf_dir in $(dirname "$SELF_PATH") /etc/wp-cli $HOME/.wp-cli ; do + if [ -f $conf_dir/php.ini ] ; then + wp_cli_php_ini=$conf_dir/php.ini + fi + if [ -f $conf_dir/wp-cli.ini ] ; then + wp_cli_php_override=$conf_dir/wp-cli.ini + fi +done + +# Add in the php file location and/or the php override variables as appropriate +if [ "x$wp_cli_php_ini" != "x" ] ; then + php="$php --php-ini $wp_cli_php_ini" +fi +if [ "x$wp_cli_php_override" != "x" ] ; then + wp_cli_override_vars=`grep '^[a-z_A-Z0-9]\+ *=' $wp_cli_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' ' '` + php="$php $wp_cli_override_vars" +fi + +# Pass in the path to php so that wp-cli knows which one +# to use if it re-launches itself to run subcommands +exec $php "$SCRIPT_PATH" "$@" \ No newline at end of file diff --git a/wp.php b/wp.php new file mode 100755 index 000000000..a5ec58840 --- /dev/null +++ b/wp.php @@ -0,0 +1,30 @@ +#!/usr/bin/env php + Date: Sat, 10 Sep 2011 11:42:51 +0200 Subject: [PATCH 0004/5359] New general structure Changed the structure to look more like a native Wordpress folder. --- .../command.php => class-wp-cli-command.php | 10 +-- class-wp-cli.php | 9 +++ {library/commands => commands}/core.php | 4 +- {library/commands => commands}/plugins.php | 48 ++++++------- engine/functions.php | 71 ------------------- wp | 4 +- engine/config.php => wp-cli.php | 30 +++++++- wp.php | 30 -------- 8 files changed, 67 insertions(+), 139 deletions(-) rename engine/command.php => class-wp-cli-command.php (68%) create mode 100644 class-wp-cli.php rename {library/commands => commands}/core.php (88%) rename {library/commands => commands}/plugins.php (95%) delete mode 100644 engine/functions.php rename engine/config.php => wp-cli.php (50%) mode change 100644 => 100755 delete mode 100755 wp.php diff --git a/engine/command.php b/class-wp-cli-command.php similarity index 68% rename from engine/command.php rename to class-wp-cli-command.php index c33d1d996..a4e3660f7 100644 --- a/engine/command.php +++ b/class-wp-cli-command.php @@ -1,14 +1,6 @@ parse_name($name); + $file = $this->parse_name($name); $details = $this->get_details($file); $this->_echo('Plugin '.$name.' details:'); @@ -152,4 +132,24 @@ private function get_details($file) { return $plugin_folder[$plugin_file]; } + + private function parse_name($name) { + $plugins = get_plugins('/'.$name); + + if(!empty($plugins)) { + $keys = array_keys($plugins); + $file = $name.'/'.$keys[0]; + } + else { + $plugins = get_plugins(); + if(isset($plugins[$name.'.php'])) { + $file = $name.'.php'; + } + else { + die('This plugin does not exists: '.$name."\n"); + } + } + + return $file; + } } \ No newline at end of file diff --git a/engine/functions.php b/engine/functions.php deleted file mode 100644 index e0744a4e0..000000000 --- a/engine/functions.php +++ /dev/null @@ -1,71 +0,0 @@ -get_error_code() ) { - foreach ( $errors->get_error_messages() as $message ) { - if ( $errors->get_error_data() ) - return $message . ' ' . $errors->get_error_data(); - else - return $message; - } - } -} - -class CLI_Upgrader_Skin { - var $upgrader; - var $done_header = false; - var $result = false; - - function __construct($args = array()) { - $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); - $this->options = wp_parse_args($args, $defaults); - } - - function set_upgrader(&$upgrader) { - if ( is_object($upgrader) ) - $this->upgrader =& $upgrader; - $this->add_strings(); - } - - function add_strings() {} - - function set_result($result) { - $this->result = $result; - } - - function request_filesystem_credentials($error = false) { - $url = $this->options['url']; - $context = $this->options['context']; - if ( !empty($this->options['nonce']) ) - $url = wp_nonce_url($url, $this->options['nonce']); - return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now. - } - - function header() {} - function footer() {} - - function error($errors) { - $this->feedback(error_to_string($errors)); - } - - function feedback($string) { - if ( isset( $this->upgrader->strings[$string] ) ) - $string = $this->upgrader->strings[$string]; - - if ( strpos($string, '%') !== false ) { - $args = func_get_args(); - $args = array_splice($args, 1); - if ( !empty($args) ) - $string = vsprintf($string, $args); - } - if ( empty($string) ) - return; - - echo $string; - } - function before() {} - function after() {} -} \ No newline at end of file diff --git a/wp b/wp index b8f52543f..5a949ca97 100755 --- a/wp +++ b/wp @@ -6,7 +6,7 @@ # And 0.09% to the author of this project: # https://github.com/88mph/wpadmin/blob/master/wpadmin.php # -# This is a wrapper script that will run wp.php with the most appropriate +# This is a wrapper script that will run wp-cli.php with the most appropriate # php executable it can find on your system. # @@ -27,7 +27,7 @@ done cd "$ORIGDIR" # Build the path to wp-cli.php. -SCRIPT_PATH=$(dirname "$SELF_PATH")/wp.php +SCRIPT_PATH=$(dirname "$SELF_PATH")/wp-cli.php case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; diff --git a/engine/config.php b/wp-cli.php old mode 100644 new mode 100755 similarity index 50% rename from engine/config.php rename to wp-cli.php index a940cd171..40df98f26 --- a/engine/config.php +++ b/wp-cli.php @@ -1,7 +1,15 @@ +#!/usr/bin/env php Date: Sat, 10 Sep 2011 14:51:26 +0200 Subject: [PATCH 0005/5359] Documentation and command line tools - Documented all functions and classes - Added php-cli-tools to interact with the cli --- .gitignore | 1 + .gitmodules | 3 + class-wp-cli-command.php | 77 +++++++- class-wp-cli.php | 183 ++++++++++++++++++- commands/{ => internals}/core.php | 27 ++- commands/internals/home.php | 47 +++++ commands/internals/plugins.php | 288 ++++++++++++++++++++++++++++++ commands/plugins.php | 155 ---------------- php-cli-tools | 1 + wp-cli.php | 55 ++++-- 10 files changed, 656 insertions(+), 181 deletions(-) create mode 100644 .gitignore create mode 100644 .gitmodules rename commands/{ => internals}/core.php (50%) create mode 100644 commands/internals/home.php create mode 100644 commands/internals/plugins.php delete mode 100644 commands/plugins.php create mode 160000 php-cli-tools diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e43b0f988 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..a2f6eaebb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "php-cli-tools"] + path = php-cli-tools + url = git://github.com/jlogsdon/php-cli-tools.git diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index a4e3660f7..73eea5fd4 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -1,22 +1,87 @@ $sub_command($args); } + // Otherwise, show the help for this command else { $this->help($args); } } - public function help() { - print_r(get_class_methods($this)); + /** + * General help function for this command + * + * @param Array $args + * @return void + * @author Andreas Creten + */ + public function help($args = array()) { + // Get the cli arguments + $arguments = $GLOBALS['argv']; + + // Remove the first entry + array_shift($arguments); + + // Get the command + $used_command = array_shift($arguments); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + WP_CLI::out(' wp '.$used_command); + $methods = WP_CLI_Command::getMethods($this); + if(!empty($methods)) { + WP_CLI::out(' ['.implode('|', $methods).']'); + } + WP_CLI::line(' ...'); + WP_CLI::line(); + + // Send a warning to the user because there is no custom help function defined in the command + // Make usure there always is a help method in your command class + WP_CLI::warning('The command has no dedicated help function, ask the creator to fix it.'); } - protected function _echo($string) { - echo $string."\n"; + /** + * Get the filtered list of methods for a class + * + * @param string $class + * @return Array The list of methods + * @author Andreas Creten + */ + static function getMethods($class) { + // Methods that don't need to be included in the method list + $blacklist = array('__construct', 'getMethods'); + + // Get all the methods of the class + $methods = get_class_methods($class); + + // Remove the blacklisted methods + foreach($blacklist as $method) { + $in_array = array_search($method, $methods); + if($in_array !== false) { + unset($methods[$in_array]); + } + } + + // Only return the values, to fill up the gaps + return array_values($methods); } } \ No newline at end of file diff --git a/class-wp-cli.php b/class-wp-cli.php index 02aa50124..7f9c08d63 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -1,9 +1,190 @@ get_error_code()){ + foreach($errors->get_error_messages() as $message){ + if($errors->get_error_data() ) + return $message . ' ' . $errors->get_error_data(); + else + return $message; + } + } + } + + /** + * Display the help function for the wp-cli + * + * @return void + * @author Andreas Creten + */ + static function generalHelp() { + self::line('Example usage:'); + foreach(self::$commands as $name => $command) { + self::out(' wp '.$name); + $methods = WP_CLI_Command::getMethods($command); + if(!empty($methods)) { + self::out(' ['.implode('|', $methods).']'); + } + self::line(' ...'); + } + } +} + +/** + * A Upgrader Skin for Wordpress that only generates plain-text + * + * @package wp-cli + * @author Andreas Creten + */ +class CLI_Upgrader_Skin { + var $upgrader; + var $done_header = false; + var $result = false; + + function __construct($args = array()) { + $defaults = array('url' => '', 'nonce' => '', 'title' => '', 'context' => false); + $this->options = wp_parse_args($args, $defaults); + } + + function set_upgrader(&$upgrader) { + if(is_object($upgrader)) { + $this->upgrader =& $upgrader; + } + + $this->add_strings(); + } + + function add_strings() {} + + function set_result($result) { + $this->result = $result; + } + + function request_filesystem_credentials($error = false) { + $url = $this->options['url']; + $context = $this->options['context']; + if(!empty($this->options['nonce'])) { + $url = wp_nonce_url($url, $this->options['nonce']); + } + + return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now. + } + + function header() {} + function footer() {} + + function error($errors) { + $this->feedback(WP_CLI::errorToString($errors)); + } + + function feedback($string) { + if(isset( $this->upgrader->strings[$string])) + $string = $this->upgrader->strings[$string]; + + if(strpos($string, '%') !== false) { + $args = func_get_args(); + $args = array_splice($args, 1); + if(!empty($args)) { + $string = vsprintf($string, $args); + } + + } + if(empty($string)) { + return; + } + + echo $string; + } + + function before() {} + function after() {} } \ No newline at end of file diff --git a/commands/core.php b/commands/internals/core.php similarity index 50% rename from commands/core.php rename to commands/internals/core.php index d485daf23..17e83a0c5 100644 --- a/commands/core.php +++ b/commands/internals/core.php @@ -1,10 +1,26 @@ upgrade($current); $feedback = ob_get_clean(); - $this->_echo($feedback); // Borrowed verbatim from wp-admin/update-core.php if(is_wp_error($result) ) { - $this->_echo(error_to_string($result)); if('up_to_date' != $result->get_error_code()) { - $this->_echo('Installation Failed'); + WP_CLI::error('Installation failed ('.WP_CLI::errorToString($result).').'); + } + else { + WP_CLI::success(WP_CLI::errorToString($result)); } } else { - $this->_echo('WordPress upgraded successfully'); + WP_CLI::success('WordPress upgraded successfully.'); } } } \ No newline at end of file diff --git a/commands/internals/home.php b/commands/internals/home.php new file mode 100644 index 000000000..203a8d999 --- /dev/null +++ b/commands/internals/home.php @@ -0,0 +1,47 @@ +check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + // Get the plugin details + $details = $this->get_details($file); + + // Display the plugin details + WP_CLI::line('Plugin %2'.$name.'%n details:'); + WP_CLI::line(' Active: '.((int) is_plugin_active($file))); + if(is_multisite()) { + WP_CLI::line(' Network: '.((int) is_plugin_active_for_network($file))); + } + WP_CLI::line(' Version: '.$details['Version']); + } + + /** + * Activate a plugin + * + * @param string $args + * @return void + * @author Andreas Creten + */ + function activate($args) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + // Check if the plugin is already active + if(is_plugin_active($file)) { + WP_CLI::error('The plugin is already active: '.$name); + } + // Try to activate the plugin + elseif(activate_plugin($file) === null) { + WP_CLI::success('Plugin activated: '.$name); + } + else { + WP_CLI::error('The plugin could not be activated: '.$name); + } + } + + /** + * Deactivate a plugin + * + * @param string $args + * @return void + * @author Andreas Creten + */ + function deactivate($args) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + // Check if the plugin is already deactivated + if(is_plugin_inactive($file)) { + WP_CLI::error('The plugin is already deactivated: '.$name); + } + // Try to deactivate the plugin + elseif(deactivate_plugins($file) === null) { + WP_CLI::success('Plugin deactivated: '.$name); + } + else { + WP_CLI::error('Could not deactivate this plugin: '.$name); + } + } + + /** + * Install a new plugin + * + * @param string $args + * @return void + * @author Andreas Creten + */ + function install($args) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name, false); + + // Force Wordpress to update the plugin list + wp_update_plugins(); + + // Get plugin info from the Wordpress servers + $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); + $status = install_plugin_install_status($api); + + WP_CLI::line('Installing '.$api->name.' ('.$api->version.')'); + + // Check what to do + switch($status['status']) { + case 'update_available': + case 'install': + if(!class_exists('Plugin_Upgrader')) { + require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); + } + + // Install the plugin + ob_start('strip_tags'); + $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); + $result = $upgrader->install($api->download_link); + $feedback = ob_get_clean(); + + if($result !== null) { + WP_CLI::error($result); + } + else { + WP_CLI::line(); + WP_CLI::line(str_replace(array('…', 'Plugin installed successfully.'), array(" ...\n", ''), html_entity_decode($feedback))); + WP_CLI::success('The plugin is successfully installed'); + } + break; + case 'newer_installed': + WP_CLI::error(sprintf('Newer version (%s) installed', $status['version'])); + break; + case 'latest_installed': + WP_CLI::error('Latest version already installed'); + + if(is_plugin_inactive($file)) { + WP_CLI::warning('If you want to activate the plugin, run: %2wp plugins activate '.$name.'%n'); + } + break; + } + } + + /** + * Delete a plugin + * + * @param string $args + * @return void + * @author Andreas Creten + */ + function delete($args) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + if(delete_plugins(array($file))) { + WP_CLI::success('The plugin is successfully deleted.'); + } + else { + WP_CLI::error('There was an error while deleting the plugin.'); + } + } + + /** + * Update a plugin + * + * @param string $args + * @return void + * @author Andreas Creten + */ + function update($args) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + // Force Wordpress to update the plugin list + wp_update_plugins(); + + if(!class_exists('Plugin_Upgrader')) { + require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); + } + + WP_CLI::line('Updating '.$name); + + // Upgrading the plugin + ob_start('strip_tags'); + $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); + $result = $upgrader->upgrade($file); + $feedback = ob_get_clean(); + + if($result !== null) { + WP_CLI::error($feedback); + } + else { + WP_CLI::line(); + WP_CLI::line(html_entity_decode($feedback)); + WP_CLI::success('The plugin is successfully updated.'); + } + } + + /* PRIVATES */ + + /** + * Get the details of a plugin + * + * @param string $file + * @return array + * @author Andreas Creten + */ + private function get_details($file) { + $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); + $plugin_file = basename(($file)); + + return $plugin_folder[$plugin_file]; + } + + /** + * Parse the name of a plugin to a filename, check if it exists + * + * @param string $name + * @param string $exit + * @return mixed + * @author Andreas Creten + */ + private function parse_name($name, $exit = true) { + $plugins = get_plugins('/'.$name); + + if(!empty($plugins)) { + $keys = array_keys($plugins); + $file = $name.'/'.$keys[0]; + } + else { + $plugins = get_plugins(); + if(isset($plugins[$name.'.php'])) { + $file = $name.'.php'; + } + else { + if($exit) { + WP_CLI::error('The plugin \''.$name.'\' could not be found.'); + exit(); + } + + return false; + } + } + + return $file; + } + + /** + * Check if there is a name set in the arguments, if not show the help function + * + * @param string $args + * @param string $exit + * @return void + * @author Andreas Creten + */ + private function check_name($args, $exit = true) { + if(empty($args)) { + WP_CLI::error('Please specify a plugin.'); + WP_CLI::line(); + $this->help(); + + if($exit) { + exit(); + } + } + + return $args[0]; + } +} \ No newline at end of file diff --git a/commands/plugins.php b/commands/plugins.php deleted file mode 100644 index 25e91dcf2..000000000 --- a/commands/plugins.php +++ /dev/null @@ -1,155 +0,0 @@ -parse_name($name); - $details = $this->get_details($file); - - $this->_echo('Plugin '.$name.' details:'); - $this->_echo(' Active: '.((int) is_plugin_active($file))); - if(is_multisite()) { - $this->_echo(' Network: '.((int) is_plugin_active_for_network($file))); - } - $this->_echo(' Version: '.$details['Version']); - } - } - - function activate($args) { - if(!empty($args)) { - $name = $args[0]; - $file = $this->parse_name($name); - - if(is_plugin_active($file)) { - $this->_echo('The plugin is already active: '.$name); - } - elseif(activate_plugin($file) === null) { - $this->_echo('Plugin activated: '.$name); - } - } - } - - function deactivate($args) { - if(!empty($args)) { - $name = $args[0]; - $file = $this->parse_name($name); - - if(is_plugin_inactive($file)) { - $this->_echo('The plugin is already deactivate: '.$name); - } - elseif(deactivate_plugins($file) === null) { - $this->_echo('Plugin deactivated: '.$name); - } - } - } - - function install($args) { - if(!empty($args)) { - $name = $args[0]; - - $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); - $status = install_plugin_install_status($api); - echo 'Updating '.$name.": "; - - switch($status['status']) { - case 'update_available': - case 'install': - ob_start(); - if(!class_exists('Plugin_Upgrader')) { - require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); - } - $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); - $result = $upgrader->install($api->download_link); - $feedback = ob_get_clean(); - $this->_echo($feedback); - break; - case 'newer_installed': - $this->_echo(sprintf('Newer Version (%s) Installed', $status['version'])); - break; - case 'latest_installed': - $this->_echo('Latest Version Installed'); - $file = $this->parse_name($name); - - if(is_plugin_inactive($file)) { - $this->_echo('If you want to activate the plugin, run \'wp plugins activate '.$name.'\''); - } - break; - } - } - } - - function delete($args) { - if(!empty($args)) { - $name = $args[0]; - $file = $this->parse_name($name); - - $success = delete_plugins(array($file)); - } - } - - function update($args) { - if(!empty($args)) { - $name = $args[0]; - $file = $this->parse_name($name); - - wp_update_plugins(); - - echo 'Updating '.$name.": "; - ob_start(); - - if(!class_exists('Plugin_Upgrader')) { - require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); - } - - $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); - $success = $upgrader->upgrade($file); - - $feedback = ob_get_clean(); - $this->_echo($feedback); - } - else { - $this->_echo('Usage: wp plugins update .'); - } - } - - private function get_details($file) { - $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); - $plugin_file = basename(($file)); - - return $plugin_folder[$plugin_file]; - } - - private function parse_name($name) { - $plugins = get_plugins('/'.$name); - - if(!empty($plugins)) { - $keys = array_keys($plugins); - $file = $name.'/'.$keys[0]; - } - else { - $plugins = get_plugins(); - if(isset($plugins[$name.'.php'])) { - $file = $name.'.php'; - } - else { - die('This plugin does not exists: '.$name."\n"); - } - } - - return $file; - } -} \ No newline at end of file diff --git a/php-cli-tools b/php-cli-tools new file mode 160000 index 000000000..1fd565ce6 --- /dev/null +++ b/php-cli-tools @@ -0,0 +1 @@ +Subproject commit 1fd565ce6c989c1e1faf8571e2af6da7d88b8b32 diff --git a/wp-cli.php b/wp-cli.php index 40df98f26..014749e0a 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -5,16 +5,22 @@ die('Only cli access'); } +// Define the Wordpress location define('WP_ROOT', '../wordpress/'); +// Set a constant that can be used to check if we are running wp-cli or not +define('WP_CLI', true); + +// Include the wp-cli classes include 'class-wp-cli.php'; include 'class-wp-cli-command.php'; -// Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php - -// Does the user have access to read the directory? If so, allow them to use the -// command line tool. +// Include the command line tools, taken from here: https://github.com/jlogsdon/php-cli-tools +include 'php-cli-tools/lib/cli/cli.php'; +\cli\register_autoload(); +// Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php +// Does the user have access to read the directory? If so, allow them to use the command line tool. if(true == is_readable(WP_ROOT . 'wp-load.php')){ // Load WordPress libs. require_once(WP_ROOT . 'wp-load.php'); @@ -22,25 +28,46 @@ require_once(ABSPATH . 'wp-admin/includes/admin.php'); } else { - die("Either this is not a WordPress document root or you do not have permission to administer this site. \n"); + WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); + exit(); +} + +// Load all internal commands +foreach (glob('commands/internals/*.php') as $filename) { + include $filename; +} + +// Load all plugin commands +foreach (glob('commands/plugins/*.php') as $filename) { + include $filename; } -foreach (glob('library/commands/*.php') as $filename) { +// Load all theme commands +foreach (glob('commands/themes/*.php') as $filename) { include $filename; } -// Start output buffering to stop WordPress from spitting out its usual output. +// Get the cli arguments +$arguments = $GLOBALS['argv']; // Remove the first entry -$arguments = array_shift($GLOBALS['argv']); +array_shift($arguments); // Get the command -$command = array_shift($GLOBALS['argv']); +$command = array_shift($arguments); -// -if(isset(WP_CLI::$commands[$command])) { - new WP_CLI::$commands[$command]($GLOBALS['argv']); +// Check if there are commands installed +if(empty(WP_CLI::$commands)) { + WP_CLI::error('No commands installed'); + WP_CLI::line(); + WP_CLI::line('Visit the wp-cli page on github on more information on how to install commands.'); + exit(); } -else { - echo 'Unknown command'."\n"; +// Try to load the class, otherwise it's an Unknown command +elseif(isset(WP_CLI::$commands[$command])) { + new WP_CLI::$commands[$command]($arguments); } +// Show the general help for wp-cli +else { + WP_CLI::generalHelp(); +} \ No newline at end of file From 5c08e34e2adef786d85db8ea827420a33d2b2ce9 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 10 Sep 2011 15:04:57 +0200 Subject: [PATCH 0006/5359] Readme & config --- README.md | 38 ++++++++++++++++++++++++++++++++++ commands/internals/plugins.php | 4 ++-- wp-cli.php | 2 +- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..99ab42b26 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +WP-CLI: Wordpress Command Line Tools +============================ + +What is wp-cli +-------------- + +A command line tool to do maintenance work on a Wordpress install from the command line. + +Installing +---------- + +Installing wp-cli is extremely simple: place the wp-cli folder in your Wordpress root, (on the same level as wp-admin and wp-content). +That's it! + +Usage +----- + +In your terminal, go into the wp-cli folder. + +Type the following command: +`./wp help` + +This will show you an output similar to this: +`Example usage: + wp google-sitemap [build|help] ... + wp core [update|help] ... + wp home [help] ... + wp plugins [status|activate|deactivate|install|delete|update|help] ...` + +Adding commands +--------------- + +Adding commands to wp-cli is very easy. You can even add them from within your own plugin. + +Requirements +------------ + + * PHP >= 5.3 \ No newline at end of file diff --git a/commands/internals/plugins.php b/commands/internals/plugins.php index 8ed09e6be..4a8a2e560 100644 --- a/commands/internals/plugins.php +++ b/commands/internals/plugins.php @@ -137,7 +137,7 @@ function install($args) { } else { WP_CLI::line(); - WP_CLI::line(str_replace(array('…', 'Plugin installed successfully.'), array(" ...\n", ''), html_entity_decode($feedback))); + WP_CLI::line(strip_tags(str_replace(array('…', 'Plugin installed successfully.'), array(" ...\n", ''), html_entity_decode($feedback)))); WP_CLI::success('The plugin is successfully installed'); } break; @@ -210,7 +210,7 @@ function update($args) { } else { WP_CLI::line(); - WP_CLI::line(html_entity_decode($feedback)); + WP_CLI::line(html_entity_decode(strip_tags($feedback))); WP_CLI::success('The plugin is successfully updated.'); } } diff --git a/wp-cli.php b/wp-cli.php index 014749e0a..5bd1bdf54 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -6,7 +6,7 @@ } // Define the Wordpress location -define('WP_ROOT', '../wordpress/'); +define('WP_ROOT', '../'); // Set a constant that can be used to check if we are running wp-cli or not define('WP_CLI', true); From b388fde1ef01d0661c4f15bdd6b2c56debabcab6 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 10 Sep 2011 15:20:26 +0200 Subject: [PATCH 0007/5359] License and read me update --- LICENSE | 19 +++++++++++++++++++ README.md | 26 +++++++++++++++++++++----- commands/internals/home.php | 3 +-- commands/internals/plugins.php | 31 +++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..8a2f6b51e --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Andreas Creten + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 99ab42b26..93c773951 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,31 @@ Usage In your terminal, go into the wp-cli folder. -Type the following command: -`./wp help` +Typing the following command: `./wp help`, will show you an output similar to this: -This will show you an output similar to this: -`Example usage: +``` +Example usage: wp google-sitemap [build|help] ... wp core [update|help] ... wp home [help] ... - wp plugins [status|activate|deactivate|install|delete|update|help] ...` + wp plugins [status|activate|deactivate|install|delete|update|help] ... +``` + +So this tells us that there are 4 commands installed: google-sitemap, core, home and pluggins. +Between brackets you can see their sub command. + +Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly` + +Output: +``` +Installing Hello Dolly (1.5) + +Downloading install package from http://downloads.wordpress.org/plugin/hello-dolly.1.5.zip ... +Unpacking the package ... +Installing the plugin ... + +Success: The plugin is successfully installed +``` Adding commands --------------- diff --git a/commands/internals/home.php b/commands/internals/home.php index 203a8d999..f5b8ff28a 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -36,8 +36,7 @@ function __construct($args) { * @param string $args * @return void * @author Andreas Creten - **/ - + */ public function help($args = array()) { WP_CLI::line('This command has no arguments, when called it will open the wp-cli homepage in your browser.'); WP_CLI::line(); diff --git a/commands/internals/plugins.php b/commands/internals/plugins.php index 4a8a2e560..df34ddbd8 100644 --- a/commands/internals/plugins.php +++ b/commands/internals/plugins.php @@ -285,4 +285,35 @@ private function check_name($args, $exit = true) { return $args[0]; } + + /** + * Help function for this command + * + * @param string $args + * @return void + * @author Andreas Creten + */ + public function help($args = array()) { + // Get the cli arguments + $arguments = $GLOBALS['argv']; + + // Remove the first entry + array_shift($arguments); + + // Get the command + $used_command = array_shift($arguments); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + + $methods = WP_CLI_Command::getMethods($this); + foreach ($methods as $method) { + if($method != 'help') { + WP_CLI::line(' wp '.$used_command.' '.$method.' '); + } + else { + WP_CLI::line(' wp '.$used_command.' '.$method); + } + } + } } \ No newline at end of file From d17ab796f2086e3df856ed7a8b0e3d824c7bddaa Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 10 Sep 2011 15:23:00 +0200 Subject: [PATCH 0008/5359] Readme update --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 93c773951..de8593f7c 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,10 @@ A command line tool to do maintenance work on a Wordpress install from the comma Installing ---------- -Installing wp-cli is extremely simple: place the wp-cli folder in your Wordpress root, (on the same level as wp-admin and wp-content). -That's it! +Installing wp-cli is extremely simple: + +1. Place the `wp-cli` folder in your Wordpress root (on the same level as `wp-admin` and `wp-content`). +1. That's it! Usage ----- @@ -33,6 +35,7 @@ Between brackets you can see their sub command. Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly` Output: + ``` Installing Hello Dolly (1.5) From f59b5c726cbce3f8804086ebf95835b88894646b Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 10 Sep 2011 15:23:59 +0200 Subject: [PATCH 0009/5359] Readme update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de8593f7c..5e02d4c55 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,11 @@ Example usage: wp plugins [status|activate|deactivate|install|delete|update|help] ... ``` -So this tells us that there are 4 commands installed: google-sitemap, core, home and pluggins. -Between brackets you can see their sub command. +So this tells us that there are 4 commands installed: google-sitemap, core, home and plugins. +Between brackets you can see their sub commands. -Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly` +Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. Output: ``` From 8fe9f26a4df9ef08b98605a4431310669e9d49c7 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 10 Sep 2011 15:43:59 +0200 Subject: [PATCH 0010/5359] Edited gitignore, struggling with submodules --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e43b0f988..c1468184d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +php-cli-tools/ \ No newline at end of file From 661de01fcea4bac15b295628d4161e40d80ef0d5 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 09:53:03 +0200 Subject: [PATCH 0011/5359] Example and README update --- README.md | 46 +++++++++- class-wp-cli-command.php | 152 ++++++++++++++++----------------- class-wp-cli.php | 123 +++++++++++++------------- commands/community/example.php | 76 +++++++++++++++++ 4 files changed, 258 insertions(+), 139 deletions(-) create mode 100644 commands/community/example.php diff --git a/README.md b/README.md index 5e02d4c55..f82212d55 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ Installing ---------- Installing wp-cli is extremely simple: - + +1. Download the latest version or clone wp-cli from Github and init and update the submodules 1. Place the `wp-cli` folder in your Wordpress root (on the same level as `wp-admin` and `wp-content`). 1. That's it! @@ -32,7 +33,6 @@ Example usage: So this tells us that there are 4 commands installed: google-sitemap, core, home and plugins. Between brackets you can see their sub commands. - Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. Output: @@ -51,6 +51,48 @@ Adding commands Adding commands to wp-cli is very easy. You can even add them from within your own plugin. +Each command has its own class, the methods of that class are the sub commands of the command. The base class for the commands is the abstract `WP_CLI_Command`, it handles some essential functionality (like default help for your command). + +You can add new commands to the `commands/community` in the wp-cli plugin, they will be auto-loaded on startup. You can also add commands from within your plugins by just calling the wp-cli hooks from there. + +A wp-cli class is structured like this: + +``` php +$sub_command($args); - } - // Otherwise, show the help for this command - else { - $this->help($args); - } - } - - /** - * General help function for this command - * - * @param Array $args - * @return void - * @author Andreas Creten - */ - public function help($args = array()) { - // Get the cli arguments - $arguments = $GLOBALS['argv']; - - // Remove the first entry - array_shift($arguments); + /** + * Construct for this class, transfers the cli arguments to the right class + * + * @param Array $args + * @author Andreas Creten + */ + function __construct($args = array()) { + // The first command is the sub command + $sub_command = array_shift($args); + + // If the method exists, try to load it + if(method_exists($this, $sub_command)) { + $this->$sub_command($args); + } + // Otherwise, show the help for this command + else { + $this->help($args); + } + } + + /** + * General help function for this command + * + * @param Array $args + * @return void + * @author Andreas Creten + */ + public function help($args = array()) { + // Get the cli arguments + $arguments = $GLOBALS['argv']; + + // Remove the first entry + array_shift($arguments); - // Get the command - $used_command = array_shift($arguments); - - // Show the list of sub-commands for this command - WP_CLI::line('Example usage:'); - WP_CLI::out(' wp '.$used_command); - $methods = WP_CLI_Command::getMethods($this); - if(!empty($methods)) { - WP_CLI::out(' ['.implode('|', $methods).']'); - } - WP_CLI::line(' ...'); - WP_CLI::line(); - - // Send a warning to the user because there is no custom help function defined in the command - // Make usure there always is a help method in your command class - WP_CLI::warning('The command has no dedicated help function, ask the creator to fix it.'); - } - - /** - * Get the filtered list of methods for a class - * - * @param string $class - * @return Array The list of methods - * @author Andreas Creten - */ - static function getMethods($class) { - // Methods that don't need to be included in the method list - $blacklist = array('__construct', 'getMethods'); - - // Get all the methods of the class - $methods = get_class_methods($class); - - // Remove the blacklisted methods - foreach($blacklist as $method) { - $in_array = array_search($method, $methods); - if($in_array !== false) { - unset($methods[$in_array]); - } - } - - // Only return the values, to fill up the gaps - return array_values($methods); - } + // Get the command + $used_command = array_shift($arguments); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + WP_CLI::out(' wp '.$used_command); + $methods = WP_CLI_Command::getMethods($this); + if(!empty($methods)) { + WP_CLI::out(' ['.implode('|', $methods).']'); + } + WP_CLI::line(' ...'); + WP_CLI::line(); + + // Send a warning to the user because there is no custom help function defined in the command + // Make usure there always is a help method in your command class + WP_CLI::warning('The command has no dedicated help function, ask the creator to fix it.'); + } + + /** + * Get the filtered list of methods for a class + * + * @param string $class + * @return Array The list of methods + * @author Andreas Creten + */ + static function getMethods($class) { + // Methods that don't need to be included in the method list + $blacklist = array('__construct', 'getMethods'); + + // Get all the methods of the class + $methods = get_class_methods($class); + + // Remove the blacklisted methods + foreach($blacklist as $method) { + $in_array = array_search($method, $methods); + if($in_array !== false) { + unset($methods[$in_array]); + } + } + + // Only return the values, to fill up the gaps + return array_values($methods); + } } \ No newline at end of file diff --git a/class-wp-cli.php b/class-wp-cli.php index 7f9c08d63..32ab17950 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -87,17 +87,17 @@ static function warning($message, $label = 'Warning') { * @author Andreas Creten */ static function errorToString($errors) { - if(is_string($errors)){ - return $errors; - } - elseif(is_wp_error($errors) && $errors->get_error_code()){ - foreach($errors->get_error_messages() as $message){ - if($errors->get_error_data() ) - return $message . ' ' . $errors->get_error_data(); - else - return $message; - } - } + if(is_string($errors)){ + return $errors; + } + elseif(is_wp_error($errors) && $errors->get_error_code()){ + foreach($errors->get_error_messages() as $message){ + if($errors->get_error_data() ) + return $message . ' ' . $errors->get_error_data(); + else + return $message; + } + } } /** @@ -109,7 +109,7 @@ static function errorToString($errors) { static function generalHelp() { self::line('Example usage:'); foreach(self::$commands as $name => $command) { - self::out(' wp '.$name); + self::out(' wp '.$name); $methods = WP_CLI_Command::getMethods($command); if(!empty($methods)) { self::out(' ['.implode('|', $methods).']'); @@ -126,65 +126,66 @@ static function generalHelp() { * @author Andreas Creten */ class CLI_Upgrader_Skin { - var $upgrader; - var $done_header = false; - var $result = false; - - function __construct($args = array()) { - $defaults = array('url' => '', 'nonce' => '', 'title' => '', 'context' => false); - $this->options = wp_parse_args($args, $defaults); - } + var $upgrader; + var $done_header = false; + var $result = false; - function set_upgrader(&$upgrader) { - if(is_object($upgrader)) { + function __construct($args = array()) { + $defaults = array('url' => '', 'nonce' => '', 'title' => '', 'context' => false); + $this->options = wp_parse_args($args, $defaults); + } + + function set_upgrader(&$upgrader) { + if(is_object($upgrader)) { $this->upgrader =& $upgrader; } - $this->add_strings(); - } - - function add_strings() {} - - function set_result($result) { - $this->result = $result; - } - - function request_filesystem_credentials($error = false) { - $url = $this->options['url']; - $context = $this->options['context']; - if(!empty($this->options['nonce'])) { + $this->add_strings(); + } + + function add_strings() {} + + function set_result($result) { + $this->result = $result; + } + + function request_filesystem_credentials($error = false) { + $url = $this->options['url']; + $context = $this->options['context']; + if(!empty($this->options['nonce'])) { $url = wp_nonce_url($url, $this->options['nonce']); } - - return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now. - } - - function header() {} - function footer() {} - - function error($errors) { - $this->feedback(WP_CLI::errorToString($errors)); - } - - function feedback($string) { - if(isset( $this->upgrader->strings[$string])) - $string = $this->upgrader->strings[$string]; + + // Possible to bring inline, Leaving as is for now. + return request_filesystem_credentials($url, '', $error, $context); + } + + function header() {} + function footer() {} + + function error($errors) { + $this->feedback(WP_CLI::errorToString($errors)); + } - if(strpos($string, '%') !== false) { - $args = func_get_args(); - $args = array_splice($args, 1); - if(!empty($args)) { + function feedback($string) { + if(isset( $this->upgrader->strings[$string])) + $string = $this->upgrader->strings[$string]; + + if(strpos($string, '%') !== false) { + $args = func_get_args(); + $args = array_splice($args, 1); + if(!empty($args)) { $string = vsprintf($string, $args); } - - } - if(empty($string)) { + + } + if(empty($string)) { return; } - - echo $string; - } + + echo $string; + } - function before() {} - function after() {} + function before() {} + function after() {} } \ No newline at end of file diff --git a/commands/community/example.php b/commands/community/example.php new file mode 100644 index 000000000..3e669233a --- /dev/null +++ b/commands/community/example.php @@ -0,0 +1,76 @@ +'); + } + else { + WP_CLI::line(' wp '.$used_command.' '.$method); + } + } + } +} \ No newline at end of file From 3e00376b4fe2b172f9229cf071f466333c52bfac Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 10:02:07 +0200 Subject: [PATCH 0012/5359] Another readme/example update --- README.md | 9 +++++---- commands/community/example.php | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f82212d55..0872603f3 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ Installing ---------- Installing wp-cli is extremely simple: - -1. Download the latest version or clone wp-cli from Github and init and update the submodules + 1. Place the `wp-cli` folder in your Wordpress root (on the same level as `wp-admin` and `wp-content`). 1. That's it! @@ -53,7 +52,7 @@ Adding commands to wp-cli is very easy. You can even add them from within your o Each command has its own class, the methods of that class are the sub commands of the command. The base class for the commands is the abstract `WP_CLI_Command`, it handles some essential functionality (like default help for your command). -You can add new commands to the `commands/community` in the wp-cli plugin, they will be auto-loaded on startup. You can also add commands from within your plugins by just calling the wp-cli hooks from there. +You can add new commands to the `commands/community` folder in the wp-cli plugin, they will be auto-loaded on startup. You can also add commands from within your plugins by just calling the wp-cli hooks from there. A wp-cli class is structured like this: @@ -89,10 +88,12 @@ To register this class under the `example` command, add the following line to th WP_CLI::addCommand('example', 'ExampleCommand'); ``` -This will register the comand `wp example`, and the subcommand `wp example example`. If you run `wp example example`, the text `Success: Success message` will be printed to the command line and the script will end. +This will register the comand `wp example` and the subcommand `wp example example`. If you run `wp example example`, the text `Success: Success message` will be printed to the command line and the script will end. You can take a look at the example command file in `commands/community/example.php` for more details. For the ways to interact with the command line, you should take a look at the WP_CLI class in the `class-wp-cli.php` file. +**Please share the commands you make, issue a pull request to get them included in wp-cli by default.** + Requirements ------------ diff --git a/commands/community/example.php b/commands/community/example.php index 3e669233a..8a08c01e2 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -20,7 +20,10 @@ class ExampleCommand extends WP_CLI_Command { */ function example($args) { // Print a string - WP_CLI::line('Prints a string -- '); + WP_CLI::out('Prints a string -- '); + + // Print a second string + WP_CLI::out('Prints a second string -- '); // Print a single line WP_CLI::line('Prints out a line'); From 0149f7895460ea7fb604d6fc8caa77f234d12dbb Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 11:56:32 +0200 Subject: [PATCH 0013/5359] Readme update --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0872603f3..433570159 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Example usage: So this tells us that there are 4 commands installed: google-sitemap, core, home and plugins. Between brackets you can see their sub commands. -Let's for example try to update the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. +Let's for example try to install the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. Output: ``` @@ -92,6 +92,15 @@ This will register the comand `wp example` and the subcommand `wp example exampl You can take a look at the example command file in `commands/community/example.php` for more details. For the ways to interact with the command line, you should take a look at the WP_CLI class in the `class-wp-cli.php` file. +If you want to register the command from within your plugin you might want to add a check to see if wp-cli is active to your plugin. By doing this you can implement the wp-cli by default, even if wp-cli is not installed on the Wordpress installation. You can use the `WP_CLI` constant to check if wp-cli is running: + +```php + Date: Wed, 28 Sep 2011 11:57:48 +0200 Subject: [PATCH 0014/5359] Readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 433570159..9a23eb421 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ This will register the comand `wp example` and the subcommand `wp example exampl You can take a look at the example command file in `commands/community/example.php` for more details. For the ways to interact with the command line, you should take a look at the WP_CLI class in the `class-wp-cli.php` file. -If you want to register the command from within your plugin you might want to add a check to see if wp-cli is active to your plugin. By doing this you can implement the wp-cli by default, even if wp-cli is not installed on the Wordpress installation. You can use the `WP_CLI` constant to check if wp-cli is running: +If you want to register the command from within your plugin you might want to add a check to see if wp-cli is running. By doing this you can implement your wp-cli command by default, even if wp-cli is not installed on the Wordpress installation. You can use the `WP_CLI` constant to check if wp-cli is running: ```php Date: Wed, 28 Sep 2011 19:52:34 +0200 Subject: [PATCH 0015/5359] Option command Add, update, delete and get option values. --- commands/internals/option.php | 135 ++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 commands/internals/option.php diff --git a/commands/internals/option.php b/commands/internals/option.php new file mode 100644 index 000000000..e5583948d --- /dev/null +++ b/commands/internals/option.php @@ -0,0 +1,135 @@ + '); + WP_CLI::line(' wp option update '); + WP_CLI::line(' wp option delete '); + WP_CLI::line(' wp option get '); + WP_CLI::line(''); + WP_CLI::line('%9--- DETAILS ---%n'); + WP_CLI::line(''); + WP_CLI::line('Adding a new option:'); + WP_CLI::line(' wp option add '); + WP_CLI::line(''); + WP_CLI::line('Updating an option:'); + WP_CLI::line(' wp option update '); + WP_CLI::line(''); + WP_CLI::line('Deleting an option:'); + WP_CLI::line(' wp option delete '); + WP_CLI::line(''); + WP_CLI::line('Get the value of an option:'); + WP_CLI::line(' wp option get '); + } +} \ No newline at end of file From 7d8d0aef709bae8a3d0049ac97e5e17d9f695ab1 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 20:26:44 +0200 Subject: [PATCH 0016/5359] Theme command Get list of installed themes, get details of a theme. Activation of a theme is work in progress. --- class-wp-cli-command.php | 12 +++++ commands/internals/theme.php | 94 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 commands/internals/theme.php diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 18aa2f5f2..44f652e3d 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -21,6 +21,11 @@ function __construct($args = array()) { if(method_exists($this, $sub_command)) { $this->$sub_command($args); } + // If a dummy method exists, use it. This if for reserved keywords in php (like list, isset) + elseif(method_exists($this, '_'.$sub_command)) { + $sub_command = '_'.$sub_command; + $this->$sub_command($args); + } // Otherwise, show the help for this command else { $this->help($args); @@ -81,6 +86,13 @@ static function getMethods($class) { } } + // Fix dummy function names + foreach($methods as $key => $method) { + if(strpos($method, '_') === 0) { + $methods[$key] = substr($method, 1, strlen($method)); + } + } + // Only return the values, to fill up the gaps return array_values($methods); } diff --git a/commands/internals/theme.php b/commands/internals/theme.php new file mode 100644 index 000000000..78c1a8f7a --- /dev/null +++ b/commands/internals/theme.php @@ -0,0 +1,94 @@ + $theme) { + WP_CLI::line(' - '.$theme['Stylesheet']); + } + } + + /** + * Get theme details + * + * @param string $args + * @return void + * @author Andreas Creten + **/ + public function details($args = array()) { + // Get the info of the theme + $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + + // Get the current theme + $theme_name = get_current_theme(); + + WP_CLI::line('Theme %2'.$details['Name'].'%n details:'); + WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); + WP_CLI::line(' Version: '.$details['Version']); + WP_CLI::line(' Author: '.strip_tags($details['Author'])); + //WP_CLI::line(' Description: '.strip_tags($details['Description'])); + } + + /** + * Activate a theme + * + * @param string $args + * @return void + * @author Andreas Creten + **/ + public function activate($args = array()) { + WP_CLI::warning('This command is not ready yet!'); + + // Get the info of the theme + $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + + // Switch to the theme + switch_theme($args[0], WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + + // Get the current theme + $theme_name = get_current_theme(); + } + + /** + * Help function for this command + * + * @param string $args + * @return void + * @author Andreas Creten + */ + public function help($args = array()) { + WP_CLI::line('Example usage:'); + WP_CLI::line(' wp theme list'); + WP_CLI::line(' wp theme details '); + WP_CLI::line(''); + WP_CLI::line('%9--- DETAILS ---%n'); + WP_CLI::line(''); + WP_CLI::line('Get a list of the installed themes:'); + WP_CLI::line(' wp theme list'); + WP_CLI::line(''); + WP_CLI::line('Get the details for a theme:'); + WP_CLI::line(' wp theme details '); + } +} \ No newline at end of file From 70aae1e32c5af514fd88de493cd106c4ccea0647 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 20:32:14 +0200 Subject: [PATCH 0017/5359] Readme update --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9a23eb421..8f045d6d8 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,12 @@ Typing the following command: `./wp help`, will show you an output similar to t ``` Example usage: - wp google-sitemap [build|help] ... - wp core [update|help] ... - wp home [help] ... - wp plugins [status|activate|deactivate|install|delete|update|help] ... + wp google-sitemap [build|help] ... + wp core [update|help] ... + wp home [help] ... + wp option [add|update|delete|get|help] ... + wp plugins [status|activate|deactivate|install|delete|update|help] ... + wp theme [list|details|activate|help] ... ``` So this tells us that there are 4 commands installed: google-sitemap, core, home and plugins. From a0f5cdc9597b85c3d58fc3a36e697c5b19dc7784 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 20:35:54 +0200 Subject: [PATCH 0018/5359] Readme update --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 8f045d6d8..09bf1f91f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,15 @@ Installing wp-cli is extremely simple: 1. Place the `wp-cli` folder in your Wordpress root (on the same level as `wp-admin` and `wp-content`). 1. That's it! +Commands +-------- + +- `wp core` - Update the Wordpress core +- `wp home` - Open the wp-cli project on Github +- `wp option ...` - Manipulate the Wordpress options +- `wp plugins ...` - Do cool things with the installed plugins +- `wp theme ...` - Get details on the installed and current theme + Usage ----- From beb0a897f82a665ff9b46be4edbcd414f34a3082 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 21:07:28 +0200 Subject: [PATCH 0019/5359] Readme fix --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 09bf1f91f..1dd422fd0 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Example usage: wp theme [list|details|activate|help] ... ``` -So this tells us that there are 4 commands installed: google-sitemap, core, home and plugins. +So this tells us which commandsa are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. Let's for example try to install the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. @@ -114,6 +114,14 @@ if(defined('WP_CLI') && WP_CLI) { **Please share the commands you make, issue a pull request to get them included in wp-cli by default.** +Todo +---- + +Commands to be written: +- User management +- Post management (not sure yet if we really need this) + + Requirements ------------ From d5f6608ef227631e98fabbe1b33801487d75c098 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 22:08:56 +0300 Subject: [PATCH 0020/5359] Edited README.md via GitHub --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dd422fd0..63b26371a 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Example usage: wp theme [list|details|activate|help] ... ``` -So this tells us which commandsa are installed: eg. google-sitemap, core, home, ... +So this tells us which commands are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. Let's for example try to install the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. @@ -118,6 +118,7 @@ Todo ---- Commands to be written: + - User management - Post management (not sure yet if we really need this) From d113d8398b50d117b92faa40c4171525aa282943 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 23:01:43 +0200 Subject: [PATCH 0021/5359] Fix for home command on linux (fixes #1) --- commands/internals/home.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/commands/internals/home.php b/commands/internals/home.php index f5b8ff28a..dd02b7020 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -19,8 +19,20 @@ class HomeCommand extends WP_CLI_Command { */ function __construct($args) { if(empty($args)) { + // Check if the x-www-browser command exists + $result = exec('which x-www-browser'); + // Open the wp-cli page in the browser - exec('open https://github.com/andreascreten/wp-cli'); + if(exec('which x-www-browser')) { + system('x-www-browser http://github.comandreascreten/wp-cli'); + } + elseif(exec('which open')) { + system('open https://github.com/andreascreten/wp-cli'); + } + else { + WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: https://github.com/andreascreten/wp-cli'); + return; + } WP_CLI::success('The wp-cli homepage should be opening in your browser.'); } From 4bc6e8f8f3cad383ddf0c89971b3dcad4919f11e Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 23:04:29 +0200 Subject: [PATCH 0022/5359] Changed Wordpress to WordPress Matt apparently is as hard as me on this. It should be WordPress, not Wordpress. --- README.md | 16 ++++++++-------- class-wp-cli.php | 2 +- commands/internals/core.php | 4 ++-- commands/internals/plugins.php | 6 +++--- wp-cli.php | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 63b26371a..11bbadb26 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ -WP-CLI: Wordpress Command Line Tools +WP-CLI: WordPress Command Line Tools ============================ What is wp-cli -------------- -A command line tool to do maintenance work on a Wordpress install from the command line. +A command line tool to do maintenance work on a WordPress install from the command line. Installing ---------- Installing wp-cli is extremely simple: -1. Place the `wp-cli` folder in your Wordpress root (on the same level as `wp-admin` and `wp-content`). +1. Place the `wp-cli` folder in your WordPress root (on the same level as `wp-admin` and `wp-content`). 1. That's it! Commands -------- -- `wp core` - Update the Wordpress core +- `wp core` - Update the WordPress core - `wp home` - Open the wp-cli project on Github -- `wp option ...` - Manipulate the Wordpress options +- `wp option ...` - Manipulate the WordPress options - `wp plugins ...` - Do cool things with the installed plugins - `wp theme ...` - Get details on the installed and current theme @@ -43,13 +43,13 @@ Example usage: So this tells us which commands are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. -Let's for example try to install the hello dolly plugin from Wordpress: `./wp plugins install hello-dolly`. +Let's for example try to install the hello dolly plugin from WordPress: `./wp plugins install hello-dolly`. Output: ``` Installing Hello Dolly (1.5) -Downloading install package from http://downloads.wordpress.org/plugin/hello-dolly.1.5.zip ... +Downloading install package from http://downloads.WordPress.org/plugin/hello-dolly.1.5.zip ... Unpacking the package ... Installing the plugin ... @@ -103,7 +103,7 @@ This will register the comand `wp example` and the subcommand `wp example exampl You can take a look at the example command file in `commands/community/example.php` for more details. For the ways to interact with the command line, you should take a look at the WP_CLI class in the `class-wp-cli.php` file. -If you want to register the command from within your plugin you might want to add a check to see if wp-cli is running. By doing this you can implement your wp-cli command by default, even if wp-cli is not installed on the Wordpress installation. You can use the `WP_CLI` constant to check if wp-cli is running: +If you want to register the command from within your plugin you might want to add a check to see if wp-cli is running. By doing this you can implement your wp-cli command by default, even if wp-cli is not installed on the WordPress installation. You can use the `WP_CLI` constant to check if wp-cli is running: ```php parse_name($name, false); - // Force Wordpress to update the plugin list + // Force WordPress to update the plugin list wp_update_plugins(); - // Get plugin info from the Wordpress servers + // Get plugin info from the WordPress servers $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); $status = install_plugin_install_status($api); @@ -190,7 +190,7 @@ function update($args) { // Get the plugin file name $file = $this->parse_name($name); - // Force Wordpress to update the plugin list + // Force WordPress to update the plugin list wp_update_plugins(); if(!class_exists('Plugin_Upgrader')) { diff --git a/wp-cli.php b/wp-cli.php index 5bd1bdf54..6f2d434d4 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -5,7 +5,7 @@ die('Only cli access'); } -// Define the Wordpress location +// Define the WordPress location define('WP_ROOT', '../'); // Set a constant that can be used to check if we are running wp-cli or not From 9e37e9415b31161937b346cf2cc7db524f1a70c3 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 23:07:04 +0200 Subject: [PATCH 0023/5359] Fix for repo url on Linux (fixes #1) --- commands/internals/home.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/internals/home.php b/commands/internals/home.php index dd02b7020..26f172b51 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -24,7 +24,7 @@ function __construct($args) { // Open the wp-cli page in the browser if(exec('which x-www-browser')) { - system('x-www-browser http://github.comandreascreten/wp-cli'); + system('x-www-browser http://github.com/andreascreten/wp-cli'); } elseif(exec('which open')) { system('open https://github.com/andreascreten/wp-cli'); From 354c1824942436e15cf9e0fe310719c823f82d54 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Wed, 28 Sep 2011 23:10:53 +0200 Subject: [PATCH 0024/5359] Removed unused var --- commands/internals/home.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/commands/internals/home.php b/commands/internals/home.php index 26f172b51..ea4eacc15 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -19,18 +19,18 @@ class HomeCommand extends WP_CLI_Command { */ function __construct($args) { if(empty($args)) { - // Check if the x-www-browser command exists - $result = exec('which x-www-browser'); + // The url for the wp-cli repository + $repository_url = 'http://github.com/andreascreten/wp-cli'; // Open the wp-cli page in the browser if(exec('which x-www-browser')) { - system('x-www-browser http://github.com/andreascreten/wp-cli'); + system('x-www-browser '.$repository_url); } elseif(exec('which open')) { - system('open https://github.com/andreascreten/wp-cli'); + system('open '.$repository_url); } else { - WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: https://github.com/andreascreten/wp-cli'); + WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: '.$repository_url); return; } From 9a3fcf0347e30bcbb5c3081602099d89d393568f Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 00:08:09 +0200 Subject: [PATCH 0025/5359] Command updates and renames - Renamed the plugins command to plugin - Updated the example and the readme - Renamed the theme/list command to theme/status - Added extra functionality to the plugin/status command (asked in #2) --- README.md | 6 +- commands/community/example.php | 2 +- .../internals/{plugins.php => plugin.php} | 64 +++++++++++++------ commands/internals/theme.php | 14 +++- 4 files changed, 58 insertions(+), 28 deletions(-) rename commands/internals/{plugins.php => plugin.php} (82%) diff --git a/README.md b/README.md index 11bbadb26..03aea4728 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Commands - `wp core` - Update the WordPress core - `wp home` - Open the wp-cli project on Github - `wp option ...` - Manipulate the WordPress options -- `wp plugins ...` - Do cool things with the installed plugins +- `wp plugin ...` - Do cool things with the installed plugins - `wp theme ...` - Get details on the installed and current theme Usage @@ -36,7 +36,7 @@ Example usage: wp core [update|help] ... wp home [help] ... wp option [add|update|delete|get|help] ... - wp plugins [status|activate|deactivate|install|delete|update|help] ... + wp plugin [status|activate|deactivate|install|delete|update|help] ... wp theme [list|details|activate|help] ... ``` @@ -84,7 +84,7 @@ class ExampleCommand extends WP_CLI_Command { * @return void * @author Andreas Creten */ - function example($args) { + function example($args = array()) { // Print a success message WP_CLI::success('Success message'); } diff --git a/commands/community/example.php b/commands/community/example.php index 8a08c01e2..2f292e44a 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -18,7 +18,7 @@ class ExampleCommand extends WP_CLI_Command { * @return void * @author Andreas Creten */ - function example($args) { + function example($args = array()) { // Print a string WP_CLI::out('Prints a string -- '); diff --git a/commands/internals/plugins.php b/commands/internals/plugin.php similarity index 82% rename from commands/internals/plugins.php rename to commands/internals/plugin.php index 52ba177e6..0c496d18a 100644 --- a/commands/internals/plugins.php +++ b/commands/internals/plugin.php @@ -1,20 +1,20 @@ check_name($args); - - // Get the plugin file name - $file = $this->parse_name($name); - - // Get the plugin details - $details = $this->get_details($file); - - // Display the plugin details - WP_CLI::line('Plugin %2'.$name.'%n details:'); - WP_CLI::line(' Active: '.((int) is_plugin_active($file))); - if(is_multisite()) { - WP_CLI::line(' Network: '.((int) is_plugin_active_for_network($file))); + if(!empty($args)) { + // Get the plugin name from the arguments + $name = $this->check_name($args); + + // Get the plugin file name + $file = $this->parse_name($name); + + // Get the plugin details + $details = $this->get_details($file); + + // Display the plugin details + WP_CLI::line('Plugin %2'.$name.'%n details:'); + WP_CLI::line(' Active: '.((int) is_plugin_active($file))); + if(is_multisite()) { + WP_CLI::line(' Network: '.((int) is_plugin_active_for_network($file))); + } + WP_CLI::line(' Version: '.$details['Version']); + } + else { + // Get the list of plugins + $plugins = get_plugins(); + + // Print the header + WP_CLI::line('Installed plugins:'); + + // Show the list if themes + foreach ($plugins as $file => $plugin) { + // Check plugin status + $network = is_plugin_active_for_network($file); + $status = is_plugin_active($file); + + WP_CLI::line(' '.($status ? '%g'.($network ? '%bN' : '').'A' : 'I').' '.$plugin['Name'].'%n'); + } + + // Print the footer + WP_CLI::line(); + WP_CLI::line('Codes: I = Inactive, A = Active, NA = Network Active'); } - WP_CLI::line(' Version: '.$details['Version']); } /** @@ -76,7 +98,7 @@ function activate($args) { * @author Andreas Creten */ function deactivate($args) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); // Get the plugin file name @@ -148,7 +170,7 @@ function install($args) { WP_CLI::error('Latest version already installed'); if(is_plugin_inactive($file)) { - WP_CLI::warning('If you want to activate the plugin, run: %2wp plugins activate '.$name.'%n'); + WP_CLI::warning('If you want to activate the plugin, run: %2wp plugin activate '.$name.'%n'); } break; } @@ -309,7 +331,7 @@ public function help($args = array()) { $methods = WP_CLI_Command::getMethods($this); foreach ($methods as $method) { if($method != 'help') { - WP_CLI::line(' wp '.$used_command.' '.$method.' '); + WP_CLI::line(' wp '.$used_command.' '.$method.' hello-dolly'); } else { WP_CLI::line(' wp '.$used_command.' '.$method); diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 78c1a8f7a..a58a02fff 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -12,22 +12,30 @@ */ class ThemeCommand extends WP_CLI_Command { /** - * List all themes + * Get the status of all themes * * @param string $args * @return void * @author Andreas Creten **/ - public function _list($args = array()) { + public function status($args = array()) { // Get the list of themes $themes = get_themes(); + // Print the header WP_CLI::line('Installed themes:'); + // Get the current theme + $theme_name = get_current_theme(); + // Show the list if themes foreach ($themes as $key => $theme) { - WP_CLI::line(' - '.$theme['Stylesheet']); + WP_CLI::line(' '.($theme['Name'] == $theme_name ? '%gA' : 'I').' '.$theme['Stylesheet'].'%n'); } + + // Print the footer + WP_CLI::line(); + WP_CLI::line('Codes: I = Inactive, A = Active'); } /** From 4317fa96ed8576a388dd6e225ec87a7ebe0af580 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 00:32:34 +0200 Subject: [PATCH 0026/5359] Updates on plugin status Implemented suggestions from #2 --- commands/internals/plugin.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 0c496d18a..4d5075ff6 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -45,6 +45,12 @@ function status($args) { // Get the list of plugins $plugins = get_plugins(); + // Get list of mu plugins + $mu_plugins = get_mu_plugins(); + + // Merge the two plugin arrays + $plugins = array_merge($plugins, $mu_plugins); + // Print the header WP_CLI::line('Installed plugins:'); @@ -53,13 +59,15 @@ function status($args) { // Check plugin status $network = is_plugin_active_for_network($file); $status = is_plugin_active($file); + $must_use = isset($mu_plugins[$file]); + $name = dirname($file) ? dirname($file) : str_replace('.php', '', basename($file)); - WP_CLI::line(' '.($status ? '%g'.($network ? '%bN' : '').'A' : 'I').' '.$plugin['Name'].'%n'); + WP_CLI::line(' '.($must_use ? '%cM' : ($status ? ($network ? '%bN' : '%gA') : 'I')).' '.$name.'%n'); } // Print the footer WP_CLI::line(); - WP_CLI::line('Codes: I = Inactive, A = Active, NA = Network Active'); + WP_CLI::line('Codes: M = Must Use, I = Inactive, A = Active, N = Network Active'); } } From b481335b4ec1ac31f710567a286fc911b18666e7 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 04:25:57 +0300 Subject: [PATCH 0027/5359] s/list/status for theme command in readme and usage example --- README.md | 4 ++-- commands/internals/theme.php | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 03aea4728..e92a39643 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Example usage: wp home [help] ... wp option [add|update|delete|get|help] ... wp plugin [status|activate|deactivate|install|delete|update|help] ... - wp theme [list|details|activate|help] ... + wp theme [status|details|activate|help] ... ``` So this tells us which commands are installed: eg. google-sitemap, core, home, ... @@ -126,4 +126,4 @@ Commands to be written: Requirements ------------ - * PHP >= 5.3 \ No newline at end of file + * PHP >= 5.3 diff --git a/commands/internals/theme.php b/commands/internals/theme.php index a58a02fff..fe65b728a 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -21,23 +21,23 @@ class ThemeCommand extends WP_CLI_Command { public function status($args = array()) { // Get the list of themes $themes = get_themes(); - + // Print the header WP_CLI::line('Installed themes:'); - + // Get the current theme $theme_name = get_current_theme(); - + // Show the list if themes foreach ($themes as $key => $theme) { WP_CLI::line(' '.($theme['Name'] == $theme_name ? '%gA' : 'I').' '.$theme['Stylesheet'].'%n'); } - + // Print the footer WP_CLI::line(); WP_CLI::line('Codes: I = Inactive, A = Active'); } - + /** * Get theme details * @@ -48,17 +48,17 @@ public function status($args = array()) { public function details($args = array()) { // Get the info of the theme $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); - + // Get the current theme $theme_name = get_current_theme(); - + WP_CLI::line('Theme %2'.$details['Name'].'%n details:'); WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); WP_CLI::line(' Version: '.$details['Version']); WP_CLI::line(' Author: '.strip_tags($details['Author'])); //WP_CLI::line(' Description: '.strip_tags($details['Description'])); } - + /** * Activate a theme * @@ -67,18 +67,18 @@ public function details($args = array()) { * @author Andreas Creten **/ public function activate($args = array()) { - WP_CLI::warning('This command is not ready yet!'); - + WP_CLI::warning('This command is not ready yet!'); + // Get the info of the theme $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); - + // Switch to the theme switch_theme($args[0], WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); - + // Get the current theme $theme_name = get_current_theme(); } - + /** * Help function for this command * @@ -88,15 +88,15 @@ public function activate($args = array()) { */ public function help($args = array()) { WP_CLI::line('Example usage:'); - WP_CLI::line(' wp theme list'); + WP_CLI::line(' wp theme status'); WP_CLI::line(' wp theme details '); WP_CLI::line(''); WP_CLI::line('%9--- DETAILS ---%n'); WP_CLI::line(''); - WP_CLI::line('Get a list of the installed themes:'); - WP_CLI::line(' wp theme list'); + WP_CLI::line('Get a status of the installed themes:'); + WP_CLI::line(' wp theme status'); WP_CLI::line(''); WP_CLI::line('Get the details for a theme:'); WP_CLI::line(' wp theme details '); } -} \ No newline at end of file +} From 028a3c089a64ff9a50498fa883f6cda1c8f80cc9 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 04:32:59 +0300 Subject: [PATCH 0028/5359] replace Codes with Legend and order statuses alphabetically --- commands/internals/plugin.php | 122 +++++++++++++++++----------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 4d5075ff6..e8299c08e 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -18,13 +18,13 @@ class PluginCommand extends WP_CLI_Command { /** * Get the status of one plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function status($args) { if(!empty($args)) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); // Get the plugin file name @@ -44,13 +44,13 @@ function status($args) { else { // Get the list of plugins $plugins = get_plugins(); - + // Get list of mu plugins $mu_plugins = get_mu_plugins(); - + // Merge the two plugin arrays $plugins = array_merge($plugins, $mu_plugins); - + // Print the header WP_CLI::line('Installed plugins:'); @@ -61,30 +61,30 @@ function status($args) { $status = is_plugin_active($file); $must_use = isset($mu_plugins[$file]); $name = dirname($file) ? dirname($file) : str_replace('.php', '', basename($file)); - + WP_CLI::line(' '.($must_use ? '%cM' : ($status ? ($network ? '%bN' : '%gA') : 'I')).' '.$name.'%n'); } // Print the footer WP_CLI::line(); - WP_CLI::line('Codes: M = Must Use, I = Inactive, A = Active, N = Network Active'); + WP_CLI::line('Legend: A = Active, I = Inactive, M = Must Use, N = Network Active'); } } - + /** * Activate a plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function activate($args) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); - + // Get the plugin file name $file = $this->parse_name($name); - + // Check if the plugin is already active if(is_plugin_active($file)) { WP_CLI::error('The plugin is already active: '.$name); @@ -97,21 +97,21 @@ function activate($args) { WP_CLI::error('The plugin could not be activated: '.$name); } } - + /** * Deactivate a plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function deactivate($args) { // Get the plugin name from the arguments $name = $this->check_name($args); - + // Get the plugin file name $file = $this->parse_name($name); - + // Check if the plugin is already deactivated if(is_plugin_inactive($file)) { WP_CLI::error('The plugin is already deactivated: '.$name); @@ -124,30 +124,30 @@ function deactivate($args) { WP_CLI::error('Could not deactivate this plugin: '.$name); } } - + /** * Install a new plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function install($args) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); - + // Get the plugin file name $file = $this->parse_name($name, false); - + // Force WordPress to update the plugin list wp_update_plugins(); - + // Get plugin info from the WordPress servers $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); $status = install_plugin_install_status($api); - + WP_CLI::line('Installing '.$api->name.' ('.$api->version.')'); - + // Check what to do switch($status['status']) { case 'update_available': @@ -155,13 +155,13 @@ function install($args) { if(!class_exists('Plugin_Upgrader')) { require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); } - + // Install the plugin ob_start('strip_tags'); $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); $result = $upgrader->install($api->download_link); $feedback = ob_get_clean(); - + if($result !== null) { WP_CLI::error($result); } @@ -176,28 +176,28 @@ function install($args) { break; case 'latest_installed': WP_CLI::error('Latest version already installed'); - + if(is_plugin_inactive($file)) { WP_CLI::warning('If you want to activate the plugin, run: %2wp plugin activate '.$name.'%n'); } break; } } - + /** * Delete a plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function delete($args) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); - + // Get the plugin file name $file = $this->parse_name($name); - + if(delete_plugins(array($file))) { WP_CLI::success('The plugin is successfully deleted.'); } @@ -205,36 +205,36 @@ function delete($args) { WP_CLI::error('There was an error while deleting the plugin.'); } } - + /** * Update a plugin * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ function update($args) { - // Get the plugin name from the arguments + // Get the plugin name from the arguments $name = $this->check_name($args); - + // Get the plugin file name $file = $this->parse_name($name); - + // Force WordPress to update the plugin list wp_update_plugins(); - + if(!class_exists('Plugin_Upgrader')) { require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); } - + WP_CLI::line('Updating '.$name); - + // Upgrading the plugin ob_start('strip_tags'); $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); $result = $upgrader->upgrade($file); $feedback = ob_get_clean(); - + if($result !== null) { WP_CLI::error($feedback); } @@ -244,28 +244,28 @@ function update($args) { WP_CLI::success('The plugin is successfully updated.'); } } - + /* PRIVATES */ - + /** * Get the details of a plugin * - * @param string $file + * @param string $file * @return array * @author Andreas Creten */ private function get_details($file) { $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); $plugin_file = basename(($file)); - + return $plugin_folder[$plugin_file]; } - + /** * Parse the name of a plugin to a filename, check if it exists * - * @param string $name - * @param string $exit + * @param string $name + * @param string $exit * @return mixed * @author Andreas Creten */ @@ -286,19 +286,19 @@ private function parse_name($name, $exit = true) { WP_CLI::error('The plugin \''.$name.'\' could not be found.'); exit(); } - + return false; } } - + return $file; } - + /** * Check if there is a name set in the arguments, if not show the help function * - * @param string $args - * @param string $exit + * @param string $args + * @param string $exit * @return void * @author Andreas Creten */ @@ -307,35 +307,35 @@ private function check_name($args, $exit = true) { WP_CLI::error('Please specify a plugin.'); WP_CLI::line(); $this->help(); - + if($exit) { exit(); } } - + return $args[0]; } - + /** * Help function for this command * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ public function help($args = array()) { // Get the cli arguments $arguments = $GLOBALS['argv']; - + // Remove the first entry array_shift($arguments); // Get the command $used_command = array_shift($arguments); - + // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - + $methods = WP_CLI_Command::getMethods($this); foreach ($methods as $method) { if($method != 'help') { @@ -346,4 +346,4 @@ public function help($args = array()) { } } } -} \ No newline at end of file +} From e1d515dba8a5e1fd51c787f6793571b5b4845bf9 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 04:49:16 +0300 Subject: [PATCH 0029/5359] fix mu plugin names --- commands/internals/plugin.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index e8299c08e..bcfe840ef 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -54,20 +54,31 @@ function status($args) { // Print the header WP_CLI::line('Installed plugins:'); - // Show the list if themes foreach ($plugins as $file => $plugin) { - // Check plugin status - $network = is_plugin_active_for_network($file); - $status = is_plugin_active($file); - $must_use = isset($mu_plugins[$file]); - $name = dirname($file) ? dirname($file) : str_replace('.php', '', basename($file)); + if ( false === strpos( $file, '/' ) ) + $name = str_replace('.php', '', basename($file)); + else + $name = dirname($file); - WP_CLI::line(' '.($must_use ? '%cM' : ($status ? ($network ? '%bN' : '%gA') : 'I')).' '.$name.'%n'); + $line = ' '; + + if ( isset($mu_plugins[$file]) ) + $line .= '%cM'; + elseif ( is_plugin_active_for_network($file) ) + $line .= '%bN'; + elseif ( is_plugin_active($file) ) + $line .= '%gA'; + else + $line .= 'I'; + + $line .= ' '.$name.'%n'; + + WP_CLI::line( $line ); } // Print the footer WP_CLI::line(); - WP_CLI::line('Legend: A = Active, I = Inactive, M = Must Use, N = Network Active'); + WP_CLI::line('Legend: %gA%n = Active, I = Inactive, M = Must Use, N = Network Active'); } } From 48a1d67ae9abefeaebd33ea435b91f2b830ed774 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 04:55:42 +0300 Subject: [PATCH 0030/5359] color code legend line too --- commands/internals/plugin.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index bcfe840ef..265ee071c 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -78,7 +78,19 @@ function status($args) { // Print the footer WP_CLI::line(); - WP_CLI::line('Legend: %gA%n = Active, I = Inactive, M = Must Use, N = Network Active'); + + $legend = array( + '%gA' => 'Active', + 'I' => 'Inactive', + '%cM' => 'Must Use', + '%bN' => 'Network Active', + ); + + $legend_line = array(); + foreach ( $legend as $key => $title ) + $legend_line[] = "$key = $title%n"; + + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } } From 0d5334d206f60974146bba748d93d852ae192033 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 04:58:38 +0300 Subject: [PATCH 0031/5359] don't show N in legend unless it's a multisite install --- commands/internals/plugin.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 265ee071c..4b47ed680 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -80,12 +80,14 @@ function status($args) { WP_CLI::line(); $legend = array( - '%gA' => 'Active', 'I' => 'Inactive', + '%gA' => 'Active', '%cM' => 'Must Use', - '%bN' => 'Network Active', ); + if ( is_multisite() ) + $legend['%bN'] = 'Network Active'; + $legend_line = array(); foreach ( $legend as $key => $title ) $legend_line[] = "$key = $title%n"; From e39f87e73ed9e24dbffd84399c1c4e4cdca82898 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 05:21:57 +0300 Subject: [PATCH 0032/5359] add update available notification --- commands/internals/plugin.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 4b47ed680..091b10b41 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -54,13 +54,20 @@ function status($args) { // Print the header WP_CLI::line('Installed plugins:'); + $update_plugins = get_site_transient( 'update_plugins' ); + if ( isset( $update_plugins->response ) ) + $update_plugins = array_keys( $update_plugins->response ); + else + $update_plugins = array(); + foreach ($plugins as $file => $plugin) { if ( false === strpos( $file, '/' ) ) $name = str_replace('.php', '', basename($file)); else $name = dirname($file); - $line = ' '; + $line = ' '; + $line .= in_array( $file, $update_plugins ) ? '%yU%n' : ' '; if ( isset($mu_plugins[$file]) ) $line .= '%cM'; @@ -88,6 +95,8 @@ function status($args) { if ( is_multisite() ) $legend['%bN'] = 'Network Active'; + $legend['%yU'] = 'Update Available'; + $legend_line = array(); foreach ( $legend as $key => $title ) $legend_line[] = "$key = $title%n"; From e3eb8b362aeaf67ba61bab8d1690a12bb7f57a5f Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 05:40:46 +0300 Subject: [PATCH 0033/5359] color code theme status legend too --- class-wp-cli.php | 74 +++++++++++++++++++++-------------- commands/internals/plugin.php | 6 +-- commands/internals/theme.php | 16 +++++--- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 4c5764bc3..44258a2f4 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -13,76 +13,90 @@ class WP_CLI { * Add a command to the wp-cli list of commands * * @param string $name The name of the command that will be used in the cli - * @param string $class The class to manage the command + * @param string $class The class to manage the command * @return void * @author Andreas Creten */ public function addCommand($name, $class) { self::$commands[$name] = $class; } - + /** * Display a message in the cli * - * @param string $message + * @param string $message * @return void * @author Andreas Creten */ static function out($message) { \cli\out($message); } - + /** * Display a message in the CLI and end with a newline * - * @param string $message + * @param string $message * @return void * @author Andreas Creten */ static function line($message = '') { \cli\line($message); } - + /** * Display an error in the CLI and end with a newline * - * @param string $message - * @param string $label + * @param string $message + * @param string $label * @return void * @author Andreas Creten */ static function error($message, $label = 'Error') { \cli\line('%R'.$label.': %n'.self::errorToString($message)); } - + /** * Display a success in the CLI and end with a newline * - * @param string $message - * @param string $label + * @param string $message + * @param string $label * @return void * @author Andreas Creten */ static function success($message, $label = 'Success') { \cli\line('%G'.$label.': %n'.$message); } - + /** * Display a warning in the CLI and end with a newline * - * @param string $message - * @param string $label + * @param string $message + * @param string $label * @return void * @author Andreas Creten */ static function warning($message, $label = 'Warning') { \cli\line('%C'.$label.': %n'.$message); } - + + /** + * Display a legend + * + * @param array( code => title ) $legend + * @return void + */ + static function legend($legend) { + $legend_line = array(); + foreach ( $legend as $key => $title ) + $legend_line[] = "$key = $title%n"; + + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + } + /** * Convert a wp_error into a String * - * @param mixed $errors + * @param mixed $errors * @return string * @author Andreas Creten */ @@ -99,7 +113,7 @@ static function errorToString($errors) { } } } - + /** * Display the help function for the wp-cli * @@ -134,35 +148,35 @@ function __construct($args = array()) { $defaults = array('url' => '', 'nonce' => '', 'title' => '', 'context' => false); $this->options = wp_parse_args($args, $defaults); } - + function set_upgrader(&$upgrader) { if(is_object($upgrader)) { $this->upgrader =& $upgrader; } - + $this->add_strings(); } - + function add_strings() {} - + function set_result($result) { $this->result = $result; } - + function request_filesystem_credentials($error = false) { $url = $this->options['url']; $context = $this->options['context']; if(!empty($this->options['nonce'])) { $url = wp_nonce_url($url, $this->options['nonce']); } - + // Possible to bring inline, Leaving as is for now. return request_filesystem_credentials($url, '', $error, $context); } - + function header() {} function footer() {} - + function error($errors) { $this->feedback(WP_CLI::errorToString($errors)); } @@ -170,22 +184,22 @@ function error($errors) { function feedback($string) { if(isset( $this->upgrader->strings[$string])) $string = $this->upgrader->strings[$string]; - + if(strpos($string, '%') !== false) { $args = func_get_args(); $args = array_splice($args, 1); if(!empty($args)) { $string = vsprintf($string, $args); } - + } if(empty($string)) { return; } - + echo $string; } - + function before() {} function after() {} -} \ No newline at end of file +} diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 091b10b41..991699c3e 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -97,11 +97,7 @@ function status($args) { $legend['%yU'] = 'Update Available'; - $legend_line = array(); - foreach ( $legend as $key => $title ) - $legend_line[] = "$key = $title%n"; - - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + WP_CLI::legend( $legend ); } } diff --git a/commands/internals/theme.php b/commands/internals/theme.php index fe65b728a..dd06096fe 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -14,7 +14,7 @@ class ThemeCommand extends WP_CLI_Command { /** * Get the status of all themes * - * @param string $args + * @param string $args * @return void * @author Andreas Creten **/ @@ -35,13 +35,19 @@ public function status($args = array()) { // Print the footer WP_CLI::line(); - WP_CLI::line('Codes: I = Inactive, A = Active'); + + $legend = array( + 'I' => 'Inactive', + '%gA' => 'Active', + ); + + WP_CLI::legend( $legend ); } /** * Get theme details * - * @param string $args + * @param string $args * @return void * @author Andreas Creten **/ @@ -62,7 +68,7 @@ public function details($args = array()) { /** * Activate a theme * - * @param string $args + * @param string $args * @return void * @author Andreas Creten **/ @@ -82,7 +88,7 @@ public function activate($args = array()) { /** * Help function for this command * - * @param string $args + * @param string $args * @return void * @author Andreas Creten */ From 1dc94fb625b570f7b2cbcf6dc9d06d1ceacb79eb Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 05:58:15 +0300 Subject: [PATCH 0034/5359] display update notification for themes --- class-wp-cli.php | 47 ++++++++++++++++++++++++----------- commands/internals/plugin.php | 11 +------- commands/internals/theme.php | 13 +++++++--- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 44258a2f4..b678223e1 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -79,20 +79,6 @@ static function warning($message, $label = 'Warning') { \cli\line('%C'.$label.': %n'.$message); } - /** - * Display a legend - * - * @param array( code => title ) $legend - * @return void - */ - static function legend($legend) { - $legend_line = array(); - foreach ( $legend as $key => $title ) - $legend_line[] = "$key = $title%n"; - - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); - } - /** * Convert a wp_error into a String * @@ -131,6 +117,39 @@ static function generalHelp() { self::line(' ...'); } } + + /** + * Display a legend + * + * @param array( code => title ) $legend + * @return void + */ + static function legend($legend) { + $legend['%yU'] = 'Update Available'; + + $legend_line = array(); + foreach ( $legend as $key => $title ) + $legend_line[] = "$key = $title%n"; + + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + } + + /** + * Return the beginning of the status line for a certain plugin or theme + * + * @param string $item The plugin or theme name + * @param string $key The transient key + * + * @return string + */ + static function get_update_status( $item, $key ) { + $update_list = get_site_transient( $key ); + + if ( isset( $update_list->response[ $item ] ) ) + return ' %yU%n'; + + return ' '; + } } /** diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 991699c3e..125c0f159 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -54,20 +54,13 @@ function status($args) { // Print the header WP_CLI::line('Installed plugins:'); - $update_plugins = get_site_transient( 'update_plugins' ); - if ( isset( $update_plugins->response ) ) - $update_plugins = array_keys( $update_plugins->response ); - else - $update_plugins = array(); - foreach ($plugins as $file => $plugin) { if ( false === strpos( $file, '/' ) ) $name = str_replace('.php', '', basename($file)); else $name = dirname($file); - $line = ' '; - $line .= in_array( $file, $update_plugins ) ? '%yU%n' : ' '; + $line = WP_CLI::get_update_status( $file, 'update_plugins' ); if ( isset($mu_plugins[$file]) ) $line .= '%cM'; @@ -95,8 +88,6 @@ function status($args) { if ( is_multisite() ) $legend['%bN'] = 'Network Active'; - $legend['%yU'] = 'Update Available'; - WP_CLI::legend( $legend ); } } diff --git a/commands/internals/theme.php b/commands/internals/theme.php index dd06096fe..a1e590cc1 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -25,12 +25,19 @@ public function status($args = array()) { // Print the header WP_CLI::line('Installed themes:'); - // Get the current theme $theme_name = get_current_theme(); - // Show the list if themes foreach ($themes as $key => $theme) { - WP_CLI::line(' '.($theme['Name'] == $theme_name ? '%gA' : 'I').' '.$theme['Stylesheet'].'%n'); + $line = WP_CLI::get_update_status( $theme['Stylesheet'], 'update_themes' ); + + if ( $theme['Name'] == $theme_name ) + $line .= '%gA'; + else + $line .= 'I'; + + $line .= ' ' . $theme['Stylesheet'].'%n'; + + WP_CLI::line( $line ); } // Print the footer From 170256ba10b43faf268c19366b4113c4cf8792ff Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 07:43:12 +0200 Subject: [PATCH 0035/5359] Removed the @author tags from the method command blocks (fixes #5) --- class-wp-cli-command.php | 3 --- class-wp-cli.php | 8 -------- commands/community/example.php | 2 -- commands/internals/core.php | 1 - commands/internals/home.php | 2 -- commands/internals/option.php | 5 ----- commands/internals/plugin.php | 10 ---------- commands/internals/theme.php | 4 ---- 8 files changed, 35 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 44f652e3d..cbf7c225e 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -11,7 +11,6 @@ abstract class WP_CLI_Command { * Construct for this class, transfers the cli arguments to the right class * * @param Array $args - * @author Andreas Creten */ function __construct($args = array()) { // The first command is the sub command @@ -37,7 +36,6 @@ function __construct($args = array()) { * * @param Array $args * @return void - * @author Andreas Creten */ public function help($args = array()) { // Get the cli arguments @@ -69,7 +67,6 @@ public function help($args = array()) { * * @param string $class * @return Array The list of methods - * @author Andreas Creten */ static function getMethods($class) { // Methods that don't need to be included in the method list diff --git a/class-wp-cli.php b/class-wp-cli.php index b678223e1..5ba54be8d 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -15,7 +15,6 @@ class WP_CLI { * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command * @return void - * @author Andreas Creten */ public function addCommand($name, $class) { self::$commands[$name] = $class; @@ -26,7 +25,6 @@ public function addCommand($name, $class) { * * @param string $message * @return void - * @author Andreas Creten */ static function out($message) { \cli\out($message); @@ -37,7 +35,6 @@ static function out($message) { * * @param string $message * @return void - * @author Andreas Creten */ static function line($message = '') { \cli\line($message); @@ -49,7 +46,6 @@ static function line($message = '') { * @param string $message * @param string $label * @return void - * @author Andreas Creten */ static function error($message, $label = 'Error') { \cli\line('%R'.$label.': %n'.self::errorToString($message)); @@ -61,7 +57,6 @@ static function error($message, $label = 'Error') { * @param string $message * @param string $label * @return void - * @author Andreas Creten */ static function success($message, $label = 'Success') { \cli\line('%G'.$label.': %n'.$message); @@ -73,7 +68,6 @@ static function success($message, $label = 'Success') { * @param string $message * @param string $label * @return void - * @author Andreas Creten */ static function warning($message, $label = 'Warning') { \cli\line('%C'.$label.': %n'.$message); @@ -84,7 +78,6 @@ static function warning($message, $label = 'Warning') { * * @param mixed $errors * @return string - * @author Andreas Creten */ static function errorToString($errors) { if(is_string($errors)){ @@ -104,7 +97,6 @@ static function errorToString($errors) { * Display the help function for the wp-cli * * @return void - * @author Andreas Creten */ static function generalHelp() { self::line('Example usage:'); diff --git a/commands/community/example.php b/commands/community/example.php index 2f292e44a..810588853 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -16,7 +16,6 @@ class ExampleCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten */ function example($args = array()) { // Print a string @@ -51,7 +50,6 @@ function example($args = array()) { * * @param string $args * @return void - * @author Andreas Creten */ public function help($args = array()) { // Get the cli arguments diff --git a/commands/internals/core.php b/commands/internals/core.php index 02c87144b..6b17113b1 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -16,7 +16,6 @@ class CoreCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten */ function update($args) { WP_CLI::line('Updating the WordPress core.'); diff --git a/commands/internals/home.php b/commands/internals/home.php index ea4eacc15..13c20f1e3 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -15,7 +15,6 @@ class HomeCommand extends WP_CLI_Command { * Overwrite the construct to have a command without subcommand * * @param string $args - * @author Andreas Creten */ function __construct($args) { if(empty($args)) { @@ -47,7 +46,6 @@ function __construct($args) { * * @param string $args * @return void - * @author Andreas Creten */ public function help($args = array()) { WP_CLI::line('This command has no arguments, when called it will open the wp-cli homepage in your browser.'); diff --git a/commands/internals/option.php b/commands/internals/option.php index e5583948d..1281b181f 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -16,7 +16,6 @@ class OptionCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten **/ public function add($args = array()) { // Check if the required arguments are there @@ -39,7 +38,6 @@ public function add($args = array()) { * * @param string $args * @return void - * @author Andreas Creten **/ public function update($args = array()) { // Check if the required arguments are there @@ -62,7 +60,6 @@ public function update($args = array()) { * * @param string $args * @return void - * @author Andreas Creten **/ public function delete($args = array()) { // Check if the required arguments are there @@ -85,7 +82,6 @@ public function delete($args = array()) { * * @param string $args * @return void - * @author Andreas Creten **/ public function get($args = array()) { // Check if the required arguments are there @@ -109,7 +105,6 @@ public function get($args = array()) { * * @param string $args * @return void - * @author Andreas Creten */ public function help($args = array()) { WP_CLI::line('Example usage:'); diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 125c0f159..962d11359 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -20,7 +20,6 @@ class PluginCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten */ function status($args) { if(!empty($args)) { @@ -97,7 +96,6 @@ function status($args) { * * @param string $args * @return void - * @author Andreas Creten */ function activate($args) { // Get the plugin name from the arguments @@ -124,7 +122,6 @@ function activate($args) { * * @param string $args * @return void - * @author Andreas Creten */ function deactivate($args) { // Get the plugin name from the arguments @@ -151,7 +148,6 @@ function deactivate($args) { * * @param string $args * @return void - * @author Andreas Creten */ function install($args) { // Get the plugin name from the arguments @@ -210,7 +206,6 @@ function install($args) { * * @param string $args * @return void - * @author Andreas Creten */ function delete($args) { // Get the plugin name from the arguments @@ -232,7 +227,6 @@ function delete($args) { * * @param string $args * @return void - * @author Andreas Creten */ function update($args) { // Get the plugin name from the arguments @@ -273,7 +267,6 @@ function update($args) { * * @param string $file * @return array - * @author Andreas Creten */ private function get_details($file) { $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); @@ -288,7 +281,6 @@ private function get_details($file) { * @param string $name * @param string $exit * @return mixed - * @author Andreas Creten */ private function parse_name($name, $exit = true) { $plugins = get_plugins('/'.$name); @@ -321,7 +313,6 @@ private function parse_name($name, $exit = true) { * @param string $args * @param string $exit * @return void - * @author Andreas Creten */ private function check_name($args, $exit = true) { if(empty($args)) { @@ -342,7 +333,6 @@ private function check_name($args, $exit = true) { * * @param string $args * @return void - * @author Andreas Creten */ public function help($args = array()) { // Get the cli arguments diff --git a/commands/internals/theme.php b/commands/internals/theme.php index a1e590cc1..383b0dd85 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -16,7 +16,6 @@ class ThemeCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten **/ public function status($args = array()) { // Get the list of themes @@ -56,7 +55,6 @@ public function status($args = array()) { * * @param string $args * @return void - * @author Andreas Creten **/ public function details($args = array()) { // Get the info of the theme @@ -77,7 +75,6 @@ public function details($args = array()) { * * @param string $args * @return void - * @author Andreas Creten **/ public function activate($args = array()) { WP_CLI::warning('This command is not ready yet!'); @@ -97,7 +94,6 @@ public function activate($args = array()) { * * @param string $args * @return void - * @author Andreas Creten */ public function help($args = array()) { WP_CLI::line('Example usage:'); From ef88fa7c71e9cf3ed554d92c3e6de2a631bb4e5b Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 07:55:39 +0200 Subject: [PATCH 0036/5359] Added contributors to the readme file --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e92a39643..ce8332476 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,11 @@ Commands to be written: - User management - Post management (not sure yet if we really need this) +Contributors +------------ + +- Andreas Creten ([@andreascreten](http://twitter.com/andreascreten)) +- Silviu-Cristian Burcă ([@scribu](http://twitter.com/scribu)) Requirements ------------ From 475589a2eed3c734fcb655438f54aae737c1191d Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 09:28:31 +0200 Subject: [PATCH 0037/5359] PHP version check and globalization - The wp shell script now checks the PHP version needed for wp-cli - Globalized the wp-cli.php script so that it can be called from anywhere on your filesystem (related to #3) --- wp | 16 ++++++++++++++++ wp-cli.php | 20 +++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/wp b/wp index 5a949ca97..5a7349061 100755 --- a/wp +++ b/wp @@ -10,6 +10,9 @@ # php executable it can find on your system. # +# Set the required PHP version +CHECK_VERSION='5.3.0' + # Get the absolute path of this executable ORIGDIR=$(pwd) SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") @@ -88,6 +91,19 @@ if [ "x$wp_cli_php_override" != "x" ] ; then php="$php $wp_cli_override_vars" fi +# Get the php version +PHP_VERSION=$($php -r echo\ phpversion\(\)\;) + +# Format version numbers +CURRENT_NUMBER=$(echo "$PHP_VERSION" | tr -d '.') +NEW_NUMBER=$(echo "$CHECK_VERSION" | tr -d '.') + +# Compare version numbers and exit if needed +if [ "$CURRENT_NUMBER" -lt "$NEW_NUMBER" ] ; then + echo "Error: PHP version $CHECK_VERSION is required to run wp-cli. You are running version $PHP_VERSION."; + exit +fi + # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands exec $php "$SCRIPT_PATH" "$@" \ No newline at end of file diff --git a/wp-cli.php b/wp-cli.php index 6f2d434d4..d70853bb3 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -6,17 +6,20 @@ } // Define the WordPress location -define('WP_ROOT', '../'); +define('WP_ROOT', $_SERVER['PWD'] . '/'); + +// Define the wp-cli location +define('WP_CLI_ROOT', __DIR__ . '/'); // Set a constant that can be used to check if we are running wp-cli or not define('WP_CLI', true); // Include the wp-cli classes -include 'class-wp-cli.php'; -include 'class-wp-cli-command.php'; +include WP_CLI_ROOT.'class-wp-cli.php'; +include WP_CLI_ROOT.'class-wp-cli-command.php'; // Include the command line tools, taken from here: https://github.com/jlogsdon/php-cli-tools -include 'php-cli-tools/lib/cli/cli.php'; +include WP_CLI_ROOT.'php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php @@ -33,17 +36,12 @@ } // Load all internal commands -foreach (glob('commands/internals/*.php') as $filename) { +foreach (glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename) { include $filename; } // Load all plugin commands -foreach (glob('commands/plugins/*.php') as $filename) { - include $filename; -} - -// Load all theme commands -foreach (glob('commands/themes/*.php') as $filename) { +foreach (glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename) { include $filename; } From 17b81c36d6d30ef4d0cea918a7fc2100fa754e9a Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 09:40:34 +0200 Subject: [PATCH 0038/5359] Allow the script to be called from one level deeper in the WordPress tree --- wp-cli.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wp-cli.php b/wp-cli.php index d70853bb3..d3e2e525f 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -6,7 +6,12 @@ } // Define the WordPress location -define('WP_ROOT', $_SERVER['PWD'] . '/'); +if(is_readable($_SERVER['PWD'] . '/../wp-load.php')) { + define('WP_ROOT', $_SERVER['PWD'] . '/../'); +} +else { + define('WP_ROOT', $_SERVER['PWD'] . '/'); +} // Define the wp-cli location define('WP_CLI_ROOT', __DIR__ . '/'); From b6ad93d2cfa11a49842f538f756c726047d0f7e0 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 15:09:22 +0300 Subject: [PATCH 0039/5359] Edited README.md via GitHub --- README.md | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ce8332476..0a365ce9a 100644 --- a/README.md +++ b/README.md @@ -9,26 +9,15 @@ A command line tool to do maintenance work on a WordPress install from the comma Installing ---------- -Installing wp-cli is extremely simple: - -1. Place the `wp-cli` folder in your WordPress root (on the same level as `wp-admin` and `wp-content`). -1. That's it! - -Commands --------- - -- `wp core` - Update the WordPress core -- `wp home` - Open the wp-cli project on Github -- `wp option ...` - Manipulate the WordPress options -- `wp plugin ...` - Do cool things with the installed plugins -- `wp theme ...` - Get details on the installed and current theme +1. Clone the project: `git clone https://github.com/andreascreten/wp-cli.git` +1. Make a symlink to the executable: `ln -s /path-to-wp-cli-dir/wp ~/bin/` Usage ----- -In your terminal, go into the wp-cli folder. +In your terminal, go into the wp root folder. -Typing the following command: `./wp help`, will show you an output similar to this: +Typing the following command: `wp help`, will show you an output similar to this: ``` Example usage: @@ -43,7 +32,7 @@ Example usage: So this tells us which commands are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. -Let's for example try to install the hello dolly plugin from WordPress: `./wp plugins install hello-dolly`. +Let's for example try to install the hello dolly plugin from WordPress: `wp plugins install hello-dolly`. Output: ``` From 451fb8e0d6366c5d11681ae0b787722c2f221fa7 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 15:14:19 +0300 Subject: [PATCH 0040/5359] more readme modifications --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a365ce9a..f65fe9588 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Installing Usage ----- -In your terminal, go into the wp root folder. +In your terminal, go into the WordPress root folder. Typing the following command: `wp help`, will show you an output similar to this: @@ -32,7 +32,8 @@ Example usage: So this tells us which commands are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. -Let's for example try to install the hello dolly plugin from WordPress: `wp plugins install hello-dolly`. +Let's for example try to install the hello dolly plugin from wordpress.org: `wp plugin install hello-dolly`. + Output: ``` @@ -115,7 +116,7 @@ Contributors ------------ - Andreas Creten ([@andreascreten](http://twitter.com/andreascreten)) -- Silviu-Cristian Burcă ([@scribu](http://twitter.com/scribu)) +- Cristi Burcă ([@scribu](http://twitter.com/scribu)) Requirements ------------ From a353401f8de6bf7a29f61163d6ace9c0c75b00e3 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 15:35:06 +0300 Subject: [PATCH 0041/5359] add command descriptions to generalHelp() --- class-wp-cli.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/class-wp-cli.php b/class-wp-cli.php index 5ba54be8d..6362b1d55 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -108,6 +108,30 @@ static function generalHelp() { } self::line(' ...'); } + + self::block( << help' for more information on a specific command. +EOB + ); + } + + /** + * Display multiple lines of content + * + * @param string $content + * @return void + */ + function block( $content ) { + foreach ( explode( "\n", $content ) as $line ) + self::line( $line ); } /** From 4ec29dab989bec7f74e148307a137f474f7a8ec5 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 15:37:07 +0300 Subject: [PATCH 0042/5359] use /usr/local/bin/ instead of ~/bin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f65fe9588..80f2bfec9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Installing ---------- 1. Clone the project: `git clone https://github.com/andreascreten/wp-cli.git` -1. Make a symlink to the executable: `ln -s /path-to-wp-cli-dir/wp ~/bin/` +1. Make a symlink to the executable: `sudo ln -s /path-to-wp-cli-dir/wp /usr/local/bin/` Usage ----- From 368f28131039b7f5d2d3e6359f9a2fb07f70e316 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 15:23:10 +0200 Subject: [PATCH 0043/5359] Removed todo's from readme --- README.md | 8 -------- wp-cli.php | 18 +++++++++--------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 80f2bfec9..85ac2a962 100644 --- a/README.md +++ b/README.md @@ -104,14 +104,6 @@ if(defined('WP_CLI') && WP_CLI) { **Please share the commands you make, issue a pull request to get them included in wp-cli by default.** -Todo ----- - -Commands to be written: - -- User management -- Post management (not sure yet if we really need this) - Contributors ------------ diff --git a/wp-cli.php b/wp-cli.php index d3e2e525f..24e4e71e1 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -7,10 +7,10 @@ // Define the WordPress location if(is_readable($_SERVER['PWD'] . '/../wp-load.php')) { - define('WP_ROOT', $_SERVER['PWD'] . '/../'); + define('WP_ROOT', $_SERVER['PWD'] . '/../'); } else { - define('WP_ROOT', $_SERVER['PWD'] . '/'); + define('WP_ROOT', $_SERVER['PWD'] . '/'); } // Define the wp-cli location @@ -30,24 +30,24 @@ // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php // Does the user have access to read the directory? If so, allow them to use the command line tool. if(true == is_readable(WP_ROOT . 'wp-load.php')){ - // Load WordPress libs. - require_once(WP_ROOT . 'wp-load.php'); - require_once(ABSPATH . WPINC . '/template-loader.php'); - require_once(ABSPATH . 'wp-admin/includes/admin.php'); + // Load WordPress libs. + require_once(WP_ROOT . 'wp-load.php'); + require_once(ABSPATH . WPINC . '/template-loader.php'); + require_once(ABSPATH . 'wp-admin/includes/admin.php'); } else { WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); - exit(); + exit(); } // Load all internal commands foreach (glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename) { - include $filename; + include $filename; } // Load all plugin commands foreach (glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename) { - include $filename; + include $filename; } // Get the cli arguments From 3f75fded92b59cfbf6d4cc511b8ecd7fea92f8d5 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Sep 2011 18:46:45 +0300 Subject: [PATCH 0044/5359] more robust PHP version handling --- wp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wp b/wp index 5a7349061..91c73f6d4 100755 --- a/wp +++ b/wp @@ -92,7 +92,9 @@ if [ "x$wp_cli_php_override" != "x" ] ; then fi # Get the php version -PHP_VERSION=$($php -r echo\ phpversion\(\)\;) +PHP_VERSION=$($php -r 'echo phpversion();') +# Keep only major version number +PHP_VERSION=${PHP_VERSION%%-*} # Format version numbers CURRENT_NUMBER=$(echo "$PHP_VERSION" | tr -d '.') @@ -106,4 +108,4 @@ fi # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands -exec $php "$SCRIPT_PATH" "$@" \ No newline at end of file +exec $php "$SCRIPT_PATH" "$@" From 0323047dd34b02f9fbbe3d10ba159d4e65d84dff Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 29 Sep 2011 19:05:10 +0200 Subject: [PATCH 0045/5359] Basic code completion (related to #6) --- wp-cli-completion.bash | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 wp-cli-completion.bash diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash new file mode 100644 index 000000000..54e522acb --- /dev/null +++ b/wp-cli-completion.bash @@ -0,0 +1,15 @@ +# Very basic code completion +# +# Code taken from here: http://www.debian-administration.org/article/317/An_introduction_to_bash_completion_part_2 +_wp() +{ + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="core plugin option theme home help" + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 +} +complete -F _wp wp \ No newline at end of file From 468d6a0f78a428cf6293f9b5ee24feec97f1b4a7 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 05:31:31 +0300 Subject: [PATCH 0046/5359] use out() instead of block() --- class-wp-cli.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 6362b1d55..355867cd0 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -109,7 +109,7 @@ static function generalHelp() { self::line(' ...'); } - self::block( << help' for more information on a specific command. + EOB ); } - /** - * Display multiple lines of content - * - * @param string $content - * @return void - */ - function block( $content ) { - foreach ( explode( "\n", $content ) as $line ) - self::line( $line ); - } - /** * Display a legend * From f6abf48a7b422b84da8944762912833e1fce1b80 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 05:43:32 +0300 Subject: [PATCH 0047/5359] check if there are any commands before doing anything with the args --- wp-cli.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/wp-cli.php b/wp-cli.php index 24e4e71e1..75955e333 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -50,6 +50,14 @@ include $filename; } +// Check if there are commands installed +if(empty(WP_CLI::$commands)) { + WP_CLI::error('No commands installed'); + WP_CLI::line(); + WP_CLI::line('Visit the wp-cli page on github on more information on how to install commands.'); + exit(); +} + // Get the cli arguments $arguments = $GLOBALS['argv']; @@ -59,18 +67,11 @@ // Get the command $command = array_shift($arguments); -// Check if there are commands installed -if(empty(WP_CLI::$commands)) { - WP_CLI::error('No commands installed'); - WP_CLI::line(); - WP_CLI::line('Visit the wp-cli page on github on more information on how to install commands.'); - exit(); -} // Try to load the class, otherwise it's an Unknown command -elseif(isset(WP_CLI::$commands[$command])) { +if(isset(WP_CLI::$commands[$command])) { new WP_CLI::$commands[$command]($arguments); } // Show the general help for wp-cli else { WP_CLI::generalHelp(); -} \ No newline at end of file +} From 859ca444f4f9cc814e62062216b6e6cf5a357eca Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 06:32:49 +0300 Subject: [PATCH 0048/5359] introduce WP_CLI::parse_args() --- class-wp-cli.php | 22 ++++++++++++++++++++++ wp-cli.php | 34 +++++++++++++++------------------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 355867cd0..6c9accd2e 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -93,6 +93,28 @@ static function errorToString($errors) { } } + /** + * Splits regular arguments from associative arguments. + * + * @return array + */ + static function parse_args( $arguments ) { + $global_arg_names = array( 'blog' ); + + $regular_args = array(); + $assoc_args = array(); + + foreach ( $arguments as $arg ) { + if ( preg_match( '/^--(\w+)=(\w+)/', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = $matches[2]; + } else { + $regular_args[] = $arg; + } + } + + return array( $regular_args, $assoc_args ); + } + /** * Display the help function for the wp-cli * diff --git a/wp-cli.php b/wp-cli.php index 75955e333..9e6863040 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -28,18 +28,16 @@ \cli\register_autoload(); // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php -// Does the user have access to read the directory? If so, allow them to use the command line tool. -if(true == is_readable(WP_ROOT . 'wp-load.php')){ - // Load WordPress libs. - require_once(WP_ROOT . 'wp-load.php'); - require_once(ABSPATH . WPINC . '/template-loader.php'); - require_once(ABSPATH . 'wp-admin/includes/admin.php'); -} -else { +if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); exit(); } +// Load WordPress libs. +require_once(WP_ROOT . 'wp-load.php'); +require_once(ABSPATH . WPINC . '/template-loader.php'); +require_once(ABSPATH . 'wp-admin/includes/admin.php'); + // Load all internal commands foreach (glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename) { include $filename; @@ -59,19 +57,17 @@ } // Get the cli arguments -$arguments = $GLOBALS['argv']; +$arguments = array_slice( $GLOBALS['argv'], 1 ); -// Remove the first entry -array_shift($arguments); +list( $arguments, $assoc_args ) = WP_CLI::parse_args( $arguments ); -// Get the command -$command = array_shift($arguments); +// Get the top-level command +$command = array_shift( $arguments ); -// Try to load the class, otherwise it's an Unknown command -if(isset(WP_CLI::$commands[$command])) { - new WP_CLI::$commands[$command]($arguments); -} -// Show the general help for wp-cli -else { +if ( !isset( WP_CLI::$commands[$command] ) ) { WP_CLI::generalHelp(); + exit(); } + +new WP_CLI::$commands[$command]( $arguments, $assoc_args ); + From 4d700f9bf16f993dab0b54da9763a207ee0bbec9 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 07:15:23 +0300 Subject: [PATCH 0049/5359] handle --blog parameter --- class-wp-cli.php | 2 +- wp-cli.php | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 6c9accd2e..765636ba1 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -105,7 +105,7 @@ static function parse_args( $arguments ) { $assoc_args = array(); foreach ( $arguments as $arg ) { - if ( preg_match( '/^--(\w+)=(\w+)/', $arg, $matches ) ) { + if ( preg_match( '|^--(\w+)=(.+)|', $arg, $matches ) ) { $assoc_args[ $matches[1] ] = $matches[2]; } else { $regular_args[] = $arg; diff --git a/wp-cli.php b/wp-cli.php index 9e6863040..dfff9bb00 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -33,7 +33,21 @@ exit(); } -// Load WordPress libs. +// Get the cli arguments +list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + +// Handle --blog parameter +if ( isset( $assoc_args['blog'] ) ) { + list( $domain, $path ) = explode( '/', $assoc_args['blog'], 2 ); + + unset( $assoc_args['blog'] ); + + $_SERVER['HTTP_HOST'] = $domain; + + $_SERVER['REQUEST_URI'] = '/' . $path; +} + +// Load WordPress libs require_once(WP_ROOT . 'wp-load.php'); require_once(ABSPATH . WPINC . '/template-loader.php'); require_once(ABSPATH . 'wp-admin/includes/admin.php'); @@ -56,11 +70,6 @@ exit(); } -// Get the cli arguments -$arguments = array_slice( $GLOBALS['argv'], 1 ); - -list( $arguments, $assoc_args ) = WP_CLI::parse_args( $arguments ); - // Get the top-level command $command = array_shift( $arguments ); From 720aa412db23c121c0c285af945c600b7fd496ef Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 07:27:38 +0300 Subject: [PATCH 0050/5359] don't include template-loader.php; it's not needed --- wp-cli.php | 1 - 1 file changed, 1 deletion(-) diff --git a/wp-cli.php b/wp-cli.php index dfff9bb00..2d833b0b3 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -49,7 +49,6 @@ // Load WordPress libs require_once(WP_ROOT . 'wp-load.php'); -require_once(ABSPATH . WPINC . '/template-loader.php'); require_once(ABSPATH . 'wp-admin/includes/admin.php'); // Load all internal commands From 441ae704dc50a19675c99eb68228bc072a6d0596 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 17:22:31 +0300 Subject: [PATCH 0051/5359] look for a wp-cli-blog file when --blog is not set --- wp-cli.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wp-cli.php b/wp-cli.php index 2d833b0b3..71dd9de36 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -38,9 +38,14 @@ // Handle --blog parameter if ( isset( $assoc_args['blog'] ) ) { - list( $domain, $path ) = explode( '/', $assoc_args['blog'], 2 ); - + $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); +} elseif ( is_readable( WP_ROOT . '/wp-cli-blog' ) ) { + $blog = file_get_contents( WP_ROOT . '/wp-cli-blog' ); +} + +if ( isset( $blog ) ) { + list( $domain, $path ) = explode( '/', $blog, 2 ); $_SERVER['HTTP_HOST'] = $domain; From 0760b36679b435aa5d7803f19886443e6cc0f848 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 17:29:36 +0300 Subject: [PATCH 0052/5359] add multisite section to readme --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 85ac2a962..50c4eec9c 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,33 @@ Installing the plugin ... Success: The plugin is successfully installed ``` +Multisite +--------- + +On a multisite installation, you need to pass a --blog parameter, so that WP knows which site it's supposed to be operating on: + +``` +wp theme status --blog=localhost/wp/test +``` + +If you have a subdomain installation, it would look like this: + +``` +wp theme status --blog=test.example.com +``` + +If you're usually working on the same site most of the time, you can put the url of that site in a file called 'wp-cli-blog' in your root WP dir: + +``` +echo 'test.example.com' > wp-cli-blog +``` + +Then, you can call `wp` without the --blog parameter again: + +``` +wp theme status +``` + Adding commands --------------- From 287a5ada50f5575ed3f231e5e1c91fcb4b16e801 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 22:06:28 +0300 Subject: [PATCH 0053/5359] pass assoc args to sub-command handlers --- class-wp-cli-command.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index cbf7c225e..d29f688ad 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -12,41 +12,41 @@ abstract class WP_CLI_Command { * * @param Array $args */ - function __construct($args = array()) { + function __construct( $args, $assoc_args ) { // The first command is the sub command $sub_command = array_shift($args); - + // If the method exists, try to load it if(method_exists($this, $sub_command)) { - $this->$sub_command($args); + $this->$sub_command($args, $assoc_args); } // If a dummy method exists, use it. This if for reserved keywords in php (like list, isset) elseif(method_exists($this, '_'.$sub_command)) { $sub_command = '_'.$sub_command; - $this->$sub_command($args); + $this->$sub_command($args, $assoc_args); } // Otherwise, show the help for this command else { $this->help($args); } } - + /** * General help function for this command * - * @param Array $args + * @param Array $args * @return void */ public function help($args = array()) { // Get the cli arguments $arguments = $GLOBALS['argv']; - + // Remove the first entry array_shift($arguments); // Get the command $used_command = array_shift($arguments); - + // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); WP_CLI::out(' wp '.$used_command); @@ -56,12 +56,12 @@ public function help($args = array()) { } WP_CLI::line(' ...'); WP_CLI::line(); - + // Send a warning to the user because there is no custom help function defined in the command // Make usure there always is a help method in your command class WP_CLI::warning('The command has no dedicated help function, ask the creator to fix it.'); } - + /** * Get the filtered list of methods for a class * @@ -71,10 +71,10 @@ public function help($args = array()) { static function getMethods($class) { // Methods that don't need to be included in the method list $blacklist = array('__construct', 'getMethods'); - + // Get all the methods of the class $methods = get_class_methods($class); - + // Remove the blacklisted methods foreach($blacklist as $method) { $in_array = array_search($method, $methods); @@ -82,15 +82,15 @@ static function getMethods($class) { unset($methods[$in_array]); } } - + // Fix dummy function names foreach($methods as $key => $method) { if(strpos($method, '_') === 0) { $methods[$key] = substr($method, 1, strlen($method)); } } - + // Only return the values, to fill up the gaps return array_values($methods); } -} \ No newline at end of file +} From 1951deeb73466b64a735fac91ba1956079c0e5da Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 22:37:46 +0300 Subject: [PATCH 0054/5359] don't use raw argv global in WP_CLI_Command::help() --- class-wp-cli-command.php | 26 +++++++++----------------- wp-cli.php | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index d29f688ad..be5fa5f6e 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -7,12 +7,13 @@ * @author Andreas Creten */ abstract class WP_CLI_Command { + /** * Construct for this class, transfers the cli arguments to the right class * * @param Array $args */ - function __construct( $args, $assoc_args ) { + function __construct( $command, $args, $assoc_args ) { // The first command is the sub command $sub_command = array_shift($args); @@ -27,29 +28,22 @@ function __construct( $args, $assoc_args ) { } // Otherwise, show the help for this command else { - $this->help($args); + $this->help($command, $sub_command); } } /** * General help function for this command * - * @param Array $args + * @param string $command + * @param string $sub_command * @return void */ - public function help($args = array()) { - // Get the cli arguments - $arguments = $GLOBALS['argv']; - - // Remove the first entry - array_shift($arguments); - - // Get the command - $used_command = array_shift($arguments); - + public function help( $command, $sub_command = false ) { // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - WP_CLI::out(' wp '.$used_command); + WP_CLI::out(' wp '.$command); + $methods = WP_CLI_Command::getMethods($this); if(!empty($methods)) { WP_CLI::out(' ['.implode('|', $methods).']'); @@ -57,9 +51,7 @@ public function help($args = array()) { WP_CLI::line(' ...'); WP_CLI::line(); - // Send a warning to the user because there is no custom help function defined in the command - // Make usure there always is a help method in your command class - WP_CLI::warning('The command has no dedicated help function, ask the creator to fix it.'); + WP_CLI::warning('The command has no dedicated help function; ask the creator to fix it.'); } /** diff --git a/wp-cli.php b/wp-cli.php index 71dd9de36..7789d561e 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -82,5 +82,5 @@ exit(); } -new WP_CLI::$commands[$command]( $arguments, $assoc_args ); +new WP_CLI::$commands[$command]( $command, $arguments, $assoc_args ); From 61c9991348a4f84cdb10cb1831ff89ab3be15b3e Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 22:42:39 +0300 Subject: [PATCH 0055/5359] add generate command --- commands/internals/generate.php | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 commands/internals/generate.php diff --git a/commands/internals/generate.php b/commands/internals/generate.php new file mode 100644 index 000000000..09a7cc1ef --- /dev/null +++ b/commands/internals/generate.php @@ -0,0 +1,52 @@ + 100, + 'type' => 'post', + 'status' => 'publish' + ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( !post_type_exists( $type ) ) { + WP_CLI::warning( "Invalid post type: $type" ); + exit; + } + + // Get the total number of posts + $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $type ) ); + + $label = get_post_type_object( $type )->labels->singular_name; + + $limit = $count + $total; + + for ( $i = $count; $i < $limit; $i++ ) { + wp_insert_post( array( + 'post_type' => $type, + 'post_title' => "$label $i", + 'post_status' => $status + ) ); + } + } +} From 1a442c868d1dd3ba721bb0c59414d565fb657815 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 2 Oct 2011 22:50:24 +0300 Subject: [PATCH 0056/5359] start at $total not at $count --- commands/internals/generate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 09a7cc1ef..28554a594 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -41,7 +41,7 @@ public function posts( $args, $assoc_args ) { $limit = $count + $total; - for ( $i = $count; $i < $limit; $i++ ) { + for ( $i = $total; $i < $limit; $i++ ) { wp_insert_post( array( 'post_type' => $type, 'post_title' => "$label $i", From b50f3fa8f923c0b4fd7799ddd8f8e28a0535ddb4 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 00:38:32 +0300 Subject: [PATCH 0057/5359] formatting in bash completion --- wp-cli-completion.bash | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash index 54e522acb..ed3a37ce9 100644 --- a/wp-cli-completion.bash +++ b/wp-cli-completion.bash @@ -1,15 +1,14 @@ # Very basic code completion # # Code taken from here: http://www.debian-administration.org/article/317/An_introduction_to_bash_completion_part_2 -_wp() -{ - local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="core plugin option theme home help" - - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 +_wp() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="core plugin option theme home help" + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 } -complete -F _wp wp \ No newline at end of file +complete -F _wp wp From fb0ec6a44f7d7c0567de7a93f3e3e170ae0665ac Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 00:50:34 +0300 Subject: [PATCH 0058/5359] forgot that the help method could be called explicitly --- class-wp-cli-command.php | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index be5fa5f6e..ca8b91566 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -8,28 +8,34 @@ */ abstract class WP_CLI_Command { + /** + * Keeps a reference to the current command name + * + * @param string + */ + protected $command; + /** * Construct for this class, transfers the cli arguments to the right class * * @param Array $args */ function __construct( $command, $args, $assoc_args ) { + $this->command = $command; + // The first command is the sub command $sub_command = array_shift($args); - // If the method exists, try to load it - if(method_exists($this, $sub_command)) { - $this->$sub_command($args, $assoc_args); - } - // If a dummy method exists, use it. This if for reserved keywords in php (like list, isset) - elseif(method_exists($this, '_'.$sub_command)) { - $sub_command = '_'.$sub_command; - $this->$sub_command($args, $assoc_args); - } - // Otherwise, show the help for this command - else { - $this->help($command, $sub_command); - } + if ( !method_exists($this, $sub_command) ) { + // This if for reserved keywords in php (like list, isset) + $sub_command = '_'.$sub_command; + } + + if ( !method_exists($this, $sub_command) ) { + $sub_command = 'help'; + } + + $this->$sub_command($args, $assoc_args); } /** @@ -39,10 +45,10 @@ function __construct( $command, $args, $assoc_args ) { * @param string $sub_command * @return void */ - public function help( $command, $sub_command = false ) { + public function help( $args, $assoc_args ) { // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - WP_CLI::out(' wp '.$command); + WP_CLI::out(' wp '.$this->command); $methods = WP_CLI_Command::getMethods($this); if(!empty($methods)) { From a27dd0e8c40a1292b9554533c2ed8723e6126bb4 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 01:23:59 +0300 Subject: [PATCH 0059/5359] introduce mandatory get_description() method to WP_CLI_Command class --- class-wp-cli-command.php | 53 +++++++++++++++++---------------- class-wp-cli.php | 14 +-------- commands/community/example.php | 31 +++++++++++-------- commands/internals/core.php | 15 ++++++---- commands/internals/generate.php | 4 +++ commands/internals/home.php | 17 +++++++---- commands/internals/option.php | 25 +++++++++------- commands/internals/plugin.php | 5 ++++ commands/internals/theme.php | 5 ++++ 9 files changed, 97 insertions(+), 72 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index ca8b91566..0095ebeca 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -8,6 +8,13 @@ */ abstract class WP_CLI_Command { + /** + * Return a short description for the command. + * + * @return string + */ + abstract public static function get_description(); + /** * Keeps a reference to the current command name * @@ -41,11 +48,15 @@ function __construct( $command, $args, $assoc_args ) { /** * General help function for this command * - * @param string $command - * @param string $sub_command + * @param string $args + * @param string $assoc_args * @return void */ - public function help( $args, $assoc_args ) { + public function help( $args = array(), $assoc_args = array() ) { + // Shot the command description + WP_CLI::line( $this->get_description() ); + WP_CLI::line(); + // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); WP_CLI::out(' wp '.$this->command); @@ -56,8 +67,6 @@ public function help( $args, $assoc_args ) { } WP_CLI::line(' ...'); WP_CLI::line(); - - WP_CLI::warning('The command has no dedicated help function; ask the creator to fix it.'); } /** @@ -67,28 +76,22 @@ public function help( $args, $assoc_args ) { * @return Array The list of methods */ static function getMethods($class) { - // Methods that don't need to be included in the method list - $blacklist = array('__construct', 'getMethods'); - - // Get all the methods of the class - $methods = get_class_methods($class); - - // Remove the blacklisted methods - foreach($blacklist as $method) { - $in_array = array_search($method, $methods); - if($in_array !== false) { - unset($methods[$in_array]); - } - } + $reflection = new ReflectionClass( $class ); + + $methods = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { + $name = $method->name; + + if ( strpos($name, '_') === 0 ) { + $name = substr( $method, 1 ); + } - // Fix dummy function names - foreach($methods as $key => $method) { - if(strpos($method, '_') === 0) { - $methods[$key] = substr($method, 1, strlen($method)); - } + $methods[] = $name; + } } - // Only return the values, to fill up the gaps - return array_values($methods); + return $methods; } } diff --git a/class-wp-cli.php b/class-wp-cli.php index 765636ba1..5037f8ba0 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -131,19 +131,7 @@ static function generalHelp() { self::line(' ...'); } - self::out( << help' for more information on a specific command. - -EOB - ); + self::line( "See 'wp help' for more information on a specific command." ); } /** diff --git a/commands/community/example.php b/commands/community/example.php index 810588853..f4bfa44ca 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -11,59 +11,64 @@ * @author Andreas Creten */ class ExampleCommand extends WP_CLI_Command { + + public static function get_description() { + return 'An example command.'; + } + /** * Example method * - * @param string $args + * @param string $args * @return void */ function example($args = array()) { // Print a string WP_CLI::out('Prints a string -- '); - + // Print a second string WP_CLI::out('Prints a second string -- '); - + // Print a single line WP_CLI::line('Prints out a line'); - + // Run through the commands foreach ($args as $arg) { WP_CLI::line($arg); } - + // Print an error message WP_CLI::error('Error message'); // Result: Error: Error message - + // Print a warning message WP_CLI::warning('Warning message'); // Result: Warning: Warning message - + // Print a success message WP_CLI::success('Success message'); // Result: Success: Success message } - + /** * Help function for this command * - * @param string $args + * @param string $args * @return void */ public function help($args = array()) { // Get the cli arguments $arguments = $GLOBALS['argv']; - + // Remove the first entry array_shift($arguments); // Get the command $used_command = array_shift($arguments); - + // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - + $methods = WP_CLI_Command::getMethods($this); foreach ($methods as $method) { if($method != 'help') { @@ -74,4 +79,4 @@ public function help($args = array()) { } } } -} \ No newline at end of file +} diff --git a/commands/internals/core.php b/commands/internals/core.php index 6b17113b1..62cd85d10 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -11,15 +11,20 @@ * @author Andreas Creten */ class CoreCommand extends WP_CLI_Command { + + public static function get_description() { + return 'Update the WordPress core.'; + } + /** * Update the WordPress core * - * @param string $args + * @param string $args * @return void */ function update($args) { WP_CLI::line('Updating the WordPress core.'); - + if(!class_exists('Core_Upgrader')) { require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); } @@ -27,7 +32,7 @@ function update($args) { $upgrader = new Core_Upgrader(new CLI_Upgrader_Skin); $result = $upgrader->upgrade($current); $feedback = ob_get_clean(); - + // Borrowed verbatim from wp-admin/update-core.php if(is_wp_error($result) ) { if('up_to_date' != $result->get_error_code()) { @@ -36,9 +41,9 @@ function update($args) { else { WP_CLI::success(WP_CLI::errorToString($result)); } - } + } else { WP_CLI::success('WordPress upgraded successfully.'); } } -} \ No newline at end of file +} diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 28554a594..a3d12bedf 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -12,6 +12,10 @@ */ class GenerateCommand extends WP_CLI_Command { + public static function get_description() { + return 'Generate a certain number of objects.'; + } + /** * Generate posts * diff --git a/commands/internals/home.php b/commands/internals/home.php index 13c20f1e3..2636f78ec 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -11,16 +11,21 @@ * @author Andreas Creten */ class HomeCommand extends WP_CLI_Command { + + public static function get_description() { + return 'Open the wp-cli project on Github.'; + } + /** * Overwrite the construct to have a command without subcommand * - * @param string $args + * @param string $args */ function __construct($args) { if(empty($args)) { // The url for the wp-cli repository $repository_url = 'http://github.com/andreascreten/wp-cli'; - + // Open the wp-cli page in the browser if(exec('which x-www-browser')) { system('x-www-browser '.$repository_url); @@ -32,7 +37,7 @@ function __construct($args) { WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: '.$repository_url); return; } - + WP_CLI::success('The wp-cli homepage should be opening in your browser.'); } else { @@ -40,11 +45,11 @@ function __construct($args) { parent::__construct($args); } } - + /** * Help function for this command * - * @param string $args + * @param string $args * @return void */ public function help($args = array()) { @@ -53,4 +58,4 @@ public function help($args = array()) { WP_CLI::line('Example usage:'); WP_CLI::line(' wp home'); } -} \ No newline at end of file +} diff --git a/commands/internals/option.php b/commands/internals/option.php index 1281b181f..388aa3b75 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -11,10 +11,15 @@ * @author Andreas Creten */ class OptionCommand extends WP_CLI_Command { + + public static function get_description() { + return 'Manipulate the WordPress options.'; + } + /** * Add an option * - * @param string $args + * @param string $args * @return void **/ public function add($args = array()) { @@ -32,11 +37,11 @@ public function add($args = array()) { WP_CLI::error('This command needs exactly two arguments.'); } } - + /** * Update an option * - * @param string $args + * @param string $args * @return void **/ public function update($args = array()) { @@ -54,11 +59,11 @@ public function update($args = array()) { WP_CLI::error('This command needs exactly two arguments.'); } } - + /** * Delete an option * - * @param string $args + * @param string $args * @return void **/ public function delete($args = array()) { @@ -76,11 +81,11 @@ public function delete($args = array()) { WP_CLI::error('This command needs exactly one argument.'); } } - + /** * Get an option * - * @param string $args + * @param string $args * @return void **/ public function get($args = array()) { @@ -99,11 +104,11 @@ public function get($args = array()) { WP_CLI::error('This command needs exactly one argument.'); } } - + /** * Help function for this command * - * @param string $args + * @param string $args * @return void */ public function help($args = array()) { @@ -127,4 +132,4 @@ public function help($args = array()) { WP_CLI::line('Get the value of an option:'); WP_CLI::line(' wp option get '); } -} \ No newline at end of file +} diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 962d11359..28c5204ca 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -15,6 +15,11 @@ * @author Andreas Creten */ class PluginCommand extends WP_CLI_Command { + + public static function get_description() { + return 'Do cool things with plugins.'; + } + /** * Get the status of one plugin * diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 383b0dd85..04364dbef 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -11,6 +11,11 @@ * @author Andreas Creten */ class ThemeCommand extends WP_CLI_Command { + + public static function get_description() { + return 'Do cool things with themes.'; + } + /** * Get the status of all themes * From 43560c51e6eeef6c9ddd7b2f5d83dc8973a96ffd Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 01:33:16 +0300 Subject: [PATCH 0060/5359] rename getMethods() to get_methods() --- class-wp-cli-command.php | 12 ++++++------ class-wp-cli.php | 4 +--- commands/community/example.php | 2 +- commands/internals/plugin.php | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 0095ebeca..a76a4d4b1 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -25,7 +25,7 @@ abstract public static function get_description(); /** * Construct for this class, transfers the cli arguments to the right class * - * @param Array $args + * @param array $args */ function __construct( $command, $args, $assoc_args ) { $this->command = $command; @@ -61,7 +61,7 @@ public function help( $args = array(), $assoc_args = array() ) { WP_CLI::line('Example usage:'); WP_CLI::out(' wp '.$this->command); - $methods = WP_CLI_Command::getMethods($this); + $methods = WP_CLI_Command::get_methods($this); if(!empty($methods)) { WP_CLI::out(' ['.implode('|', $methods).']'); } @@ -70,12 +70,12 @@ public function help( $args = array(), $assoc_args = array() ) { } /** - * Get the filtered list of methods for a class + * Get the filtered list of methods for a class. * * @param string $class - * @return Array The list of methods + * @return array The list of methods */ - static function getMethods($class) { + static function get_methods($class) { $reflection = new ReflectionClass( $class ); $methods = array(); @@ -84,7 +84,7 @@ static function getMethods($class) { if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { $name = $method->name; - if ( strpos($name, '_') === 0 ) { + if ( strpos( $name, '_' ) === 0 ) { $name = substr( $method, 1 ); } diff --git a/class-wp-cli.php b/class-wp-cli.php index 5037f8ba0..0af7061c6 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -124,14 +124,12 @@ static function generalHelp() { self::line('Example usage:'); foreach(self::$commands as $name => $command) { self::out(' wp '.$name); - $methods = WP_CLI_Command::getMethods($command); + $methods = WP_CLI_Command::get_methods($command); if(!empty($methods)) { self::out(' ['.implode('|', $methods).']'); } self::line(' ...'); } - - self::line( "See 'wp help' for more information on a specific command." ); } /** diff --git a/commands/community/example.php b/commands/community/example.php index f4bfa44ca..655709a0a 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -69,7 +69,7 @@ public function help($args = array()) { // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - $methods = WP_CLI_Command::getMethods($this); + $methods = WP_CLI_Command::get_methods($this); foreach ($methods as $method) { if($method != 'help') { WP_CLI::line(' wp '.$used_command.' '.$method.' '); diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 28c5204ca..7f1a12848 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -352,7 +352,7 @@ public function help($args = array()) { // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - $methods = WP_CLI_Command::getMethods($this); + $methods = WP_CLI_Command::get_methods($this); foreach ($methods as $method) { if($method != 'help') { WP_CLI::line(' wp '.$used_command.' '.$method.' hello-dolly'); From 4107bed87af03f13d13ccdf8bd4ec1369dec0e3b Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 01:44:46 +0300 Subject: [PATCH 0061/5359] move most of constructor into a dispatch() method --- class-wp-cli-command.php | 12 ++++++++++++ commands/internals/home.php | 15 ++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index a76a4d4b1..602ce6643 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -25,11 +25,23 @@ abstract public static function get_description(); /** * Construct for this class, transfers the cli arguments to the right class * + * @param string $command * @param array $args + * @param array $assoc_args */ function __construct( $command, $args, $assoc_args ) { $this->command = $command; + $this->dispatch( $args, $assoc_args ); + } + + /** + * Transfers the handling to the appropriate method + * + * @param array $args + * @param array $assoc_args + */ + protected function dispatch( $args, $assoc_args ) { // The first command is the sub command $sub_command = array_shift($args); diff --git a/commands/internals/home.php b/commands/internals/home.php index 2636f78ec..d70cf2975 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -17,11 +17,12 @@ public static function get_description() { } /** - * Overwrite the construct to have a command without subcommand - * - * @param string $args + * Overwrite the dispatch method to have a command without sub-commands. + * + * @param array $args + * @param array $assoc_args */ - function __construct($args) { + protected function dispatch( $args, $assoc_args ) { if(empty($args)) { // The url for the wp-cli repository $repository_url = 'http://github.com/andreascreten/wp-cli'; @@ -42,18 +43,18 @@ function __construct($args) { } else { // Call the parent constructor - parent::__construct($args); + parent::dispatch( $args, $assoc_args ); } } /** - * Help function for this command + * Help function for this command. * * @param string $args * @return void */ public function help($args = array()) { - WP_CLI::line('This command has no arguments, when called it will open the wp-cli homepage in your browser.'); + WP_CLI::line('This command has no arguments; when called it will open the wp-cli homepage in your browser.'); WP_CLI::line(); WP_CLI::line('Example usage:'); WP_CLI::line(' wp home'); From 0c0222a60074d43123ba74aadcdc000e05309dfb Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 01:51:37 +0300 Subject: [PATCH 0062/5359] update plugin help method --- class-wp-cli-command.php | 2 +- commands/internals/plugin.php | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 602ce6643..bb9db4c55 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -67,7 +67,7 @@ protected function dispatch( $args, $assoc_args ) { public function help( $args = array(), $assoc_args = array() ) { // Shot the command description WP_CLI::line( $this->get_description() ); - WP_CLI::line(); + WP_CLI::line(); // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 7f1a12848..ff10e1de0 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -340,25 +340,19 @@ private function check_name($args, $exit = true) { * @return void */ public function help($args = array()) { - // Get the cli arguments - $arguments = $GLOBALS['argv']; - - // Remove the first entry - array_shift($arguments); - - // Get the command - $used_command = array_shift($arguments); + // Shot the command description + WP_CLI::line( $this->get_description() ); + WP_CLI::line(); // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - $methods = WP_CLI_Command::get_methods($this); - foreach ($methods as $method) { + foreach (WP_CLI_Command::get_methods($this) as $method) { if($method != 'help') { - WP_CLI::line(' wp '.$used_command.' '.$method.' hello-dolly'); + WP_CLI::line(' wp '.$this->command.' '.$method.' hello-dolly'); } else { - WP_CLI::line(' wp '.$used_command.' '.$method); + WP_CLI::line(' wp '.$this->command.' '.$method); } } } From fd0a37b45324d2bd0f17b3c749f735337edd1841 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 01:56:48 +0300 Subject: [PATCH 0063/5359] make get_description() method optional --- README.md | 1 - class-wp-cli-command.php | 18 +++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 50c4eec9c..1d83505b8 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,6 @@ class ExampleCommand extends WP_CLI_Command { * * @param string $args * @return void - * @author Andreas Creten */ function example($args = array()) { // Print a success message diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index bb9db4c55..83ce288fc 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -13,7 +13,9 @@ abstract class WP_CLI_Command { * * @return string */ - abstract public static function get_description(); + public static function get_description() { + return false; + } /** * Keeps a reference to the current command name @@ -65,16 +67,18 @@ protected function dispatch( $args, $assoc_args ) { * @return void */ public function help( $args = array(), $assoc_args = array() ) { - // Shot the command description - WP_CLI::line( $this->get_description() ); - WP_CLI::line(); + $desc = $this->get_description(); + if ( $desc ) { + WP_CLI::line( $desc ); + WP_CLI::line(); + } // Show the list of sub-commands for this command - WP_CLI::line('Example usage:'); - WP_CLI::out(' wp '.$this->command); + WP_CLI::line( 'Example usage:' ); + WP_CLI::out( ' wp '.$this->command ); $methods = WP_CLI_Command::get_methods($this); - if(!empty($methods)) { + if ( !empty( $methods ) ) { WP_CLI::out(' ['.implode('|', $methods).']'); } WP_CLI::line(' ...'); From ff99eb5b130906f3dc99be866317d4d7cef19d24 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 3 Oct 2011 10:06:43 +0100 Subject: [PATCH 0064/5359] Spelling mistake. --- commands/community/example.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/community/example.php b/commands/community/example.php index 655709a0a..56e420ce8 100644 --- a/commands/community/example.php +++ b/commands/community/example.php @@ -7,7 +7,7 @@ * Implement example command * * @package wp-cli - * @subpackage commands/cummunity + * @subpackage commands/community * @author Andreas Creten */ class ExampleCommand extends WP_CLI_Command { From dd4661d36cf43595d85d19ea79ab0cce14897f04 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 17:22:41 +0300 Subject: [PATCH 0065/5359] make wp theme activate work --- commands/internals/theme.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 04364dbef..488d974df 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -78,20 +78,32 @@ public function details($args = array()) { /** * Activate a theme * - * @param string $args + * @param array $args * @return void **/ public function activate($args = array()) { - WP_CLI::warning('This command is not ready yet!'); + if ( empty( $args ) ) { + WP_CLI::line('usage: wp theme activate '); + exit; + } - // Get the info of the theme - $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + $theme = array_shift( $args ); - // Switch to the theme - switch_theme($args[0], WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + $stylesheet = WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; - // Get the current theme - $theme_name = get_current_theme(); + if ( !is_readable( $stylesheet ) ) { + WP_CLI::warning( 'theme not found' ); + exit; + } + + $details = get_theme_data( $stylesheet ); + + $child = $theme; + $parent = $details['Template']; + if ( empty( $parent ) ) + $parent = $child; + + switch_theme( $parent, $child ); } /** From 1c4a5feb414ce6b3b30ac67443a566f9ba3d668d Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 18:05:05 +0300 Subject: [PATCH 0066/5359] check if parent theme is valid --- commands/internals/theme.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 488d974df..5c1223d53 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -87,9 +87,9 @@ public function activate($args = array()) { exit; } - $theme = array_shift( $args ); + $child = array_shift( $args ); - $stylesheet = WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; + $stylesheet = $this->get_stylesheet_path( $child ); if ( !is_readable( $stylesheet ) ) { WP_CLI::warning( 'theme not found' ); @@ -98,14 +98,22 @@ public function activate($args = array()) { $details = get_theme_data( $stylesheet ); - $child = $theme; $parent = $details['Template']; - if ( empty( $parent ) ) + + if ( empty( $parent ) ) { $parent = $child; + } elseif ( !is_readable( $this->get_stylesheet_path ( $parent ) ) ) { + WP_CLI::warning( 'parent theme not found' ); + exit; + } switch_theme( $parent, $child ); } + protected function get_stylesheet_path( $theme ) { + return WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; + } + /** * Help function for this command * From 9d222c3355b54d4186fd7b6a07f6582e55b2628b Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 3 Oct 2011 23:41:52 +0300 Subject: [PATCH 0067/5359] add --version flag --- class-wp-cli.php | 6 +++--- wp-cli.php | 30 +++++++++++++++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 0af7061c6..5e7778e2c 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -99,13 +99,13 @@ static function errorToString($errors) { * @return array */ static function parse_args( $arguments ) { - $global_arg_names = array( 'blog' ); - $regular_args = array(); $assoc_args = array(); foreach ( $arguments as $arg ) { - if ( preg_match( '|^--(\w+)=(.+)|', $arg, $matches ) ) { + if ( preg_match( '|^--(\w+)$|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = true; + } elseif ( preg_match( '|^--(\w+)=(.+)|', $arg, $matches ) ) { $assoc_args[ $matches[1] ] = $matches[2]; } else { $regular_args[] = $arg; diff --git a/wp-cli.php b/wp-cli.php index 7789d561e..9a6b4f0b8 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -5,13 +5,7 @@ die('Only cli access'); } -// Define the WordPress location -if(is_readable($_SERVER['PWD'] . '/../wp-load.php')) { - define('WP_ROOT', $_SERVER['PWD'] . '/../'); -} -else { - define('WP_ROOT', $_SERVER['PWD'] . '/'); -} +define( 'WP_CLI_VERSION', '0.1' ); // Define the wp-cli location define('WP_CLI_ROOT', __DIR__ . '/'); @@ -23,19 +17,33 @@ include WP_CLI_ROOT.'class-wp-cli.php'; include WP_CLI_ROOT.'class-wp-cli-command.php'; -// Include the command line tools, taken from here: https://github.com/jlogsdon/php-cli-tools +// Include the command line tools include WP_CLI_ROOT.'php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); +// Get the cli arguments +list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + +// Handle --version parameter +if ( isset( $assoc_args['version'] ) ) { + WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); + exit; +} + +// Define the WordPress location +if(is_readable($_SERVER['PWD'] . '/../wp-load.php')) { + define('WP_ROOT', $_SERVER['PWD'] . '/../'); +} +else { + define('WP_ROOT', $_SERVER['PWD'] . '/'); +} + // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); exit(); } -// Get the cli arguments -list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); - // Handle --blog parameter if ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; From 9a57d334a1abe510a7590af787e43c86fededda9 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 00:05:43 +0300 Subject: [PATCH 0068/5359] installation instructions: need to fetch the submodules too --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1d83505b8..a11b1520f 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,30 @@ A command line tool to do maintenance work on a WordPress install from the comma Installing ---------- -1. Clone the project: `git clone https://github.com/andreascreten/wp-cli.git` -1. Make a symlink to the executable: `sudo ln -s /path-to-wp-cli-dir/wp /usr/local/bin/` +1. Clone the project: + +``` +git clone https://github.com/andreascreten/wp-cli.git +cd wp-cli +git submodule update --init +``` + +Make a symlink to the executable: + +``` +sudo ln -s /path-to-wp-cli-dir/wp /usr/local/bin/ +``` Usage ----- -In your terminal, go into the WordPress root folder. +Go into a WordPress root folder: + +``` +cd /var/www/wp/ # your path might be something else +``` -Typing the following command: `wp help`, will show you an output similar to this: +Typing the following command: `wp help` will show you an output similar to this: ``` Example usage: From 93a91c380db482f1a3bafedae89cf7616f337221 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 00:07:23 +0300 Subject: [PATCH 0069/5359] more install instructions cleanup --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a11b1520f..c3f27e193 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A command line tool to do maintenance work on a WordPress install from the comma Installing ---------- -1. Clone the project: +Clone the project: ``` git clone https://github.com/andreascreten/wp-cli.git @@ -29,10 +29,10 @@ Usage Go into a WordPress root folder: ``` -cd /var/www/wp/ # your path might be something else +cd /var/www/wp/ ``` -Typing the following command: `wp help` will show you an output similar to this: +Typing `wp help` should show you an output similar to this: ``` Example usage: @@ -47,7 +47,11 @@ Example usage: So this tells us which commands are installed: eg. google-sitemap, core, home, ... Between brackets you can see their sub commands. -Let's for example try to install the hello dolly plugin from wordpress.org: `wp plugin install hello-dolly`. +Let's for example try to install the hello dolly plugin from wordpress.org: + +``` +wp plugin install hello-dolly +``` Output: From 365e1799200b3f33f3bd1061c8b0c5dd88b55200 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 00:14:49 +0300 Subject: [PATCH 0070/5359] remove repetition from wp-cli description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3f27e193..00a419ef1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ WP-CLI: WordPress Command Line Tools What is wp-cli -------------- -A command line tool to do maintenance work on a WordPress install from the command line. +A tool to control WordPress installations from the command line. Installing ---------- From a62175a3ce6be0919389f81a9a986a5ca537733e Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 01:30:26 +0300 Subject: [PATCH 0071/5359] dynamically fetch the list of commands. see #6 --- wp-cli-completion.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash index ed3a37ce9..16d83a105 100644 --- a/wp-cli-completion.bash +++ b/wp-cli-completion.bash @@ -6,7 +6,8 @@ _wp() { COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="core plugin option theme home help" + + opts=$(wp help | awk '/wp / {print $2}') COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 From 5c28d7178715e48bb3c50e64ca6846fac19ccc01 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 01:48:43 +0300 Subject: [PATCH 0072/5359] add instructions for installing completion file. see #6 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 00a419ef1..ef6681ca5 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ Make a symlink to the executable: sudo ln -s /path-to-wp-cli-dir/wp /usr/local/bin/ ``` +Make a symlink to the autocomplete file (Linux): + +``` +sudo ln -s /path-to-wp-cli-dir/wp-cli-completion.bash /etc/bash_completion.d/wp +``` + Usage ----- From 1d7534091ad5ec33bbbc35c628efc11bb6357f73 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Tue, 4 Oct 2011 01:16:49 +0200 Subject: [PATCH 0073/5359] Added the community command super-cache (for the WP Super Cache plugin) Also added support for --help in the cli, it does exactly the same as the normal help. --- class-wp-cli-command.php | 7 +- commands/community/wp-super-cache.php | 167 ++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 commands/community/wp-super-cache.php diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 83ce288fc..6539265b4 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -47,15 +47,18 @@ protected function dispatch( $args, $assoc_args ) { // The first command is the sub command $sub_command = array_shift($args); + // Assosciative arguments keys + $assoc_keys = array_keys($assoc_args); + if ( !method_exists($this, $sub_command) ) { // This if for reserved keywords in php (like list, isset) $sub_command = '_'.$sub_command; } - if ( !method_exists($this, $sub_command) ) { + if ( !method_exists($this, $sub_command) || in_array( 'help', $assoc_keys ) ) { $sub_command = 'help'; } - + $this->$sub_command($args, $assoc_args); } diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php new file mode 100644 index 000000000..10d086280 --- /dev/null +++ b/commands/community/wp-super-cache.php @@ -0,0 +1,167 @@ + time() - 3600 * 24 ) { + global $super_cache_enabled; + WP_CLI::line( 'Cache status: ' . ($super_cache_enabled ? '%gOn%n' : '%rOff%n') ); + WP_CLI::line( 'Cache content on ' . date('r', $cache_stats['generated'] ) . ': ' ); + WP_CLI::line(); + WP_CLI::line( ' WordPress cache:' ); + WP_CLI::line( ' Cached: ' . $cache_stats[ 'wpcache' ][ 'cached' ] ); + WP_CLI::line( ' Expired: ' . $cache_stats[ 'wpcache' ][ 'expired' ] ); + WP_CLI::line(); + WP_CLI::line( ' WP Super Cache:' ); + WP_CLI::line( ' Cached: ' . $cache_stats[ 'supercache' ][ 'cached' ] ); + WP_CLI::line( ' Expired: ' . $cache_stats[ 'supercache' ][ 'expired' ] ); + } else { + WP_CLI::error('The WP Super Cache stats are too old to work with (older than 24 hours).'); + } + } else { + WP_CLI::error('No WP Super Cache stats found.'); + } + } + + /** + * Enable the WP Super Cache + * + * @param array $args + * @param array $vars + * @return void + * @author Andreas Creten + */ + function enable( $args = array(), $vars = array() ) { + if ( function_exists( 'wp_super_cache_enable' ) ) { + global $super_cache_enabled; + wp_super_cache_enable(); + if($super_cache_enabled) { + WP_CLI::success( 'The WP Super Cache is enabled.' ); + } else { + WP_CLI::error('The WP Super Cache is not enabled, check its settings page for more info.'); + } + } else { + WP_CLI::error('The WP Super Cache could not be found, is it installed?'); + } + } + + /** + * Disable the WP Super Cache + * + * @param array $args + * @param array $vars + * @return void + * @author Andreas Creten + */ + function disable( $args = array(), $vars = array() ) { + if ( function_exists( 'wp_super_cache_disable' ) ) { + global $super_cache_enabled; + wp_super_cache_disable(); + if(!$super_cache_enabled) { + WP_CLI::success( 'The WP Super Cache is disabled.' ); + } else { + WP_CLI::error('The WP Super Cache is still enabled, check its settings page for more info.'); + } + } else { + WP_CLI::error('The WP Super Cache could not be found, is it installed?'); + } + } + + /** + * Help function for this command + * + * @param string $args + * @return void + */ + public function help($args = array()) { + // Shot the command description + WP_CLI::line( $this->get_description() ); + WP_CLI::line(); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + WP_CLI::line(' wp wp-super-cache clean [--post_id=] [--permalink=]'); + WP_CLI::line(' wp wp-super-cache status'); + WP_CLI::line(' wp wp-super-cache enable'); + WP_CLI::line(' wp wp-super-cache disable'); + WP_CLI::line(); + WP_CLI::line('%9--- DETAILS ---%n'); + WP_CLI::line(); + WP_CLI::line('Remove the whole cache content:'); + WP_CLI::line(' wp wp-super-cache clean'); + WP_CLI::line(); + WP_CLI::line('Remove the caches for one blog post based on the id:'); + WP_CLI::line(' wp wp-super-cache clean --post_id=1'); + WP_CLI::line(); + WP_CLI::line('Remove the caches for one blog post based on the permalink:'); + WP_CLI::line(' wp wp-super-cache clean --permalink=http://example.com'); + WP_CLI::line(); + WP_CLI::line('Get details on the WP Super Cache content:'); + WP_CLI::line(' wp wp-super-cache status'); + WP_CLI::line(); + WP_CLI::line('Enable the WP Super Cache:'); + WP_CLI::line(' wp wp-super-cache enable'); + WP_CLI::line(); + WP_CLI::line('Disable the WP Super Cache:'); + WP_CLI::line(' wp wp-super-cache disable'); + } +} From b80620de67fcbf96fcac380940c96971a610b5e1 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Tue, 4 Oct 2011 01:31:38 +0200 Subject: [PATCH 0074/5359] Added the community command google-sitemap (for the Google Sitemap Generator plugin) --- class-wp-cli-command.php | 5 +- .../community/google-sitemap-generator.php | 52 +++++++++++++++++++ commands/community/wp-super-cache.php | 9 ++-- 3 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 commands/community/google-sitemap-generator.php diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 6539265b4..e6a6dee47 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -47,15 +47,12 @@ protected function dispatch( $args, $assoc_args ) { // The first command is the sub command $sub_command = array_shift($args); - // Assosciative arguments keys - $assoc_keys = array_keys($assoc_args); - if ( !method_exists($this, $sub_command) ) { // This if for reserved keywords in php (like list, isset) $sub_command = '_'.$sub_command; } - if ( !method_exists($this, $sub_command) || in_array( 'help', $assoc_keys ) ) { + if ( !method_exists($this, $sub_command) || isset( $assoc_args[ 'help' ] ) ) { $sub_command = 'help'; } diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php new file mode 100644 index 000000000..7a47c2f6c --- /dev/null +++ b/commands/community/google-sitemap-generator.php @@ -0,0 +1,52 @@ +get_description() ); + WP_CLI::line(); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + WP_CLI::line(' wp google-sitemap rebuild'); + WP_CLI::line(); + WP_CLI::line('%9--- DETAILS ---%n'); + WP_CLI::line(); + WP_CLI::line('Rebuild the Google sitemaps:'); + WP_CLI::line(' wp google-sitemap rebuild'); + } +} \ No newline at end of file diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 10d086280..dd9d0c47a 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -1,7 +1,9 @@ Date: Tue, 4 Oct 2011 02:42:50 +0300 Subject: [PATCH 0075/5359] remove example.php command; don't need it actually available --- commands/community/example.php | 82 ---------------------------------- 1 file changed, 82 deletions(-) delete mode 100644 commands/community/example.php diff --git a/commands/community/example.php b/commands/community/example.php deleted file mode 100644 index 56e420ce8..000000000 --- a/commands/community/example.php +++ /dev/null @@ -1,82 +0,0 @@ -'); - } - else { - WP_CLI::line(' wp '.$used_command.' '.$method); - } - } - } -} From 3e9074e2d6f93444a79fa7ae7b5ddeff5c294894 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 03:05:22 +0300 Subject: [PATCH 0076/5359] provide completions for sub-commands. see #6 --- wp-cli-completion.bash | 7 +++++-- wp-cli.php | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash index 16d83a105..5e376f5ff 100644 --- a/wp-cli-completion.bash +++ b/wp-cli-completion.bash @@ -7,9 +7,12 @@ _wp() { cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts=$(wp help | awk '/wp / {print $2}') + if [[ 'wp' = $prev ]]; then + opts=$(wp --completions | cut -d ' ' -f 1) + else + opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2-) + fi COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 } complete -F _wp wp diff --git a/wp-cli.php b/wp-cli.php index 9a6b4f0b8..241d08e93 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -82,6 +82,14 @@ exit(); } +// Handle --completions parameter +if ( isset( $assoc_args['completions'] ) ) { + foreach ( WP_CLI::$commands as $name => $command ) { + WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_methods($command) ) ); + } + exit; +} + // Get the top-level command $command = array_shift( $arguments ); From 097b8d909f555d27e95f960bc5221d83f3190157 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 03:38:33 +0300 Subject: [PATCH 0077/5359] faster way to fetch php version --- wp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wp b/wp index 91c73f6d4..b8336b6da 100755 --- a/wp +++ b/wp @@ -92,9 +92,7 @@ if [ "x$wp_cli_php_override" != "x" ] ; then fi # Get the php version -PHP_VERSION=$($php -r 'echo phpversion();') -# Keep only major version number -PHP_VERSION=${PHP_VERSION%%-*} +PHP_VERSION=$(php -v | awk '/^PHP / {print $2}' | cut -d '-' -f 1) # Format version numbers CURRENT_NUMBER=$(echo "$PHP_VERSION" | tr -d '.') From 4d7628f9e24ce7ab82ea7e51a1f7cd948582b9e5 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 03:59:37 +0300 Subject: [PATCH 0078/5359] convert newlines to spaces. see #6 --- wp-cli-completion.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash index 5e376f5ff..d04b8e089 100644 --- a/wp-cli-completion.bash +++ b/wp-cli-completion.bash @@ -8,11 +8,11 @@ _wp() { prev="${COMP_WORDS[COMP_CWORD-1]}" if [[ 'wp' = $prev ]]; then - opts=$(wp --completions | cut -d ' ' -f 1) + opts=$(wp --completions | cut -d ' ' -f 1 | tr '\n' ' ') else - opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2-) + opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2- | tr '\n' ' ') fi - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + COMPREPLY=( $(compgen -W "$opts" -- $cur) ) } complete -F _wp wp From bd762babc93a0892cc9b9adb470e444bc37d5b56 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 04:05:38 +0300 Subject: [PATCH 0079/5359] remove unneeded assignment of COMPREPLY --- wp-cli-completion.bash | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/wp-cli-completion.bash b/wp-cli-completion.bash index d04b8e089..39ec5b649 100644 --- a/wp-cli-completion.bash +++ b/wp-cli-completion.bash @@ -1,11 +1,12 @@ -# Very basic code completion -# -# Code taken from here: http://www.debian-administration.org/article/317/An_introduction_to_bash_completion_part_2 +#!bash +# +# bash completion support for the wp command +# _wp() { local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" + + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} if [[ 'wp' = $prev ]]; then opts=$(wp --completions | cut -d ' ' -f 1 | tr '\n' ' ') From 2a52e2cf011e42d68837617748bfe98adce8cec7 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Tue, 4 Oct 2011 09:02:27 +0200 Subject: [PATCH 0080/5359] Added the community command total-cache (for the W3 Total Cache plugin) --- .../community/google-sitemap-generator.php | 2 +- commands/community/w3-total-cache.php | 121 ++++++++++++++++++ commands/community/wp-super-cache.php | 10 +- 3 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 commands/community/w3-total-cache.php diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index 7a47c2f6c..c5d7dbaa4 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -6,7 +6,7 @@ } /** - * The WP Super Cache plugin + * Manage the Google XML Sitemap plugin * * @package wp-cli * @subpackage commands/community diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php new file mode 100644 index 000000000..98d0fcca1 --- /dev/null +++ b/commands/community/w3-total-cache.php @@ -0,0 +1,121 @@ +get_description() ); + WP_CLI::line(); + + // Show the list of sub-commands for this command + WP_CLI::line('Example usage:'); + WP_CLI::line(' wp total-cache flush [post|database|minify|object] [--post_id=] [--permalink=]'); + WP_CLI::line(); + WP_CLI::line('%9--- DETAILS ---%n'); + WP_CLI::line(); + WP_CLI::line('Remove all post/page caches:'); + WP_CLI::line(' wp total-cache flush'); + WP_CLI::line(); + WP_CLI::line('Remove the caches for one blog post based on the id:'); + WP_CLI::line(' wp total-cache flush --post_id=1'); + WP_CLI::line(); + WP_CLI::line('Remove the caches for one blog post based on the permalink:'); + WP_CLI::line(' wp total-cache flush --permalink=http://example.com'); + WP_CLI::line(); + WP_CLI::line('Remove the database cache:'); + WP_CLI::line(' wp total-cache flush database'); + WP_CLI::line(); + WP_CLI::line('Remove the object cache:'); + WP_CLI::line(' wp total-cache flush object'); + WP_CLI::line(); + WP_CLI::line('Remove the minify cache:'); + WP_CLI::line(' wp total-cache flush minify'); + } +} diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index dd9d0c47a..c78238698 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -25,7 +25,7 @@ public static function get_description() { * @param array $vars * @return void */ - function clear( $args = array(), $vars = array() ) { + function flush( $args = array(), $vars = array() ) { if ( function_exists( 'wp_cache_clear_cache' ) ) { if ( isset($vars['post_id']) ) { if ( is_numeric( $vars['post_id'] ) ) { @@ -138,7 +138,7 @@ public function help($args = array()) { // Show the list of sub-commands for this command WP_CLI::line('Example usage:'); - WP_CLI::line(' wp wp-super-cache clean [--post_id=] [--permalink=]'); + WP_CLI::line(' wp wp-super-cache flush [--post_id=] [--permalink=]'); WP_CLI::line(' wp wp-super-cache status'); WP_CLI::line(' wp wp-super-cache enable'); WP_CLI::line(' wp wp-super-cache disable'); @@ -146,13 +146,13 @@ public function help($args = array()) { WP_CLI::line('%9--- DETAILS ---%n'); WP_CLI::line(); WP_CLI::line('Remove the whole cache content:'); - WP_CLI::line(' wp wp-super-cache clean'); + WP_CLI::line(' wp wp-super-cache flush'); WP_CLI::line(); WP_CLI::line('Remove the caches for one blog post based on the id:'); - WP_CLI::line(' wp wp-super-cache clean --post_id=1'); + WP_CLI::line(' wp wp-super-cache flush --post_id=1'); WP_CLI::line(); WP_CLI::line('Remove the caches for one blog post based on the permalink:'); - WP_CLI::line(' wp wp-super-cache clean --permalink=http://example.com'); + WP_CLI::line(' wp wp-super-cache flush --permalink=http://example.com'); WP_CLI::line(); WP_CLI::line('Get details on the WP Super Cache content:'); WP_CLI::line(' wp wp-super-cache status'); From 0d7d3599e85b471da41f71b1ae88e59bb8d77865 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Tue, 4 Oct 2011 09:22:33 +0200 Subject: [PATCH 0081/5359] Updated plugin status command to add more details for a single plugin (fixes #11) --- class-wp-cli.php | 4 +-- commands/internals/plugin.php | 46 +++++++++++++++++++++++++---------- commands/internals/theme.php | 6 ++++- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/class-wp-cli.php b/class-wp-cli.php index 5e7778e2c..290339069 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -160,9 +160,9 @@ static function get_update_status( $item, $key ) { $update_list = get_site_transient( $key ); if ( isset( $update_list->response[ $item ] ) ) - return ' %yU%n'; + return true; - return ' '; + return false; } } diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index ff10e1de0..b850d25c7 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -26,24 +26,40 @@ public static function get_description() { * @param string $args * @return void */ - function status($args) { - if(!empty($args)) { + function status( $args = array(), $vars = array() ) { + // Force WordPress to update the plugin list + wp_update_plugins(); + + if(!empty( $args )) { // Get the plugin name from the arguments - $name = $this->check_name($args); + $name = $this->check_name( $args ); // Get the plugin file name - $file = $this->parse_name($name); + $file = $this->parse_name( $name ); + + // Get list of mu plugins + $mu_plugins = get_mu_plugins(); // Get the plugin details - $details = $this->get_details($file); - + $details = $this->get_details( $file ); + + // Get the plugin status + if ( isset( $mu_plugins[ $file ] ) ) + $status = '%cMust Use'; + elseif ( is_plugin_active_for_network( $file ) ) + $status = '%bNetwork Activated'; + elseif ( is_plugin_active( $file ) ) + $status = '%gYes'; + else + $status = '%rNo'; + // Display the plugin details - WP_CLI::line('Plugin %2'.$name.'%n details:'); - WP_CLI::line(' Active: '.((int) is_plugin_active($file))); - if(is_multisite()) { - WP_CLI::line(' Network: '.((int) is_plugin_active_for_network($file))); - } - WP_CLI::line(' Version: '.$details['Version']); + WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); + WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Active: ' . $status .'%n' ); + WP_CLI::line( ' Version: ' . $details[ 'Version' ] . ( WP_CLI::get_update_status( $file, 'update_plugins' ) ? ' (%gUpdate available%n)' : '' ) ); + WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); + WP_CLI::line( ' Author: ' . $details[ 'Author' ]); } else { // Get the list of plugins @@ -64,7 +80,11 @@ function status($args) { else $name = dirname($file); - $line = WP_CLI::get_update_status( $file, 'update_plugins' ); + if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { + $line = ' %yU%n'; + } else { + $line = ' '; + } if ( isset($mu_plugins[$file]) ) $line .= '%cM'; diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 5c1223d53..22c6f6b96 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -32,7 +32,11 @@ public function status($args = array()) { $theme_name = get_current_theme(); foreach ($themes as $key => $theme) { - $line = WP_CLI::get_update_status( $theme['Stylesheet'], 'update_themes' ); + if ( WP_CLI::get_update_status( $theme['Stylesheet'], 'update_themes' ) ) { + $line = ' %yU%n'; + } else { + $line = ' '; + } if ( $theme['Name'] == $theme_name ) $line .= '%gA'; From 5090932a9d3d526697a56f077c71e08eaab04f14 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 4 Oct 2011 21:30:00 +0300 Subject: [PATCH 0082/5359] add `wp generate users` command --- commands/internals/generate.php | 47 +++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/commands/internals/generate.php b/commands/internals/generate.php index a3d12bedf..0d1d654ae 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -19,7 +19,8 @@ public static function get_description() { /** * Generate posts * - * @param string $args + * @param array $args + * @param array $assoc_args * @return void **/ public function posts( $args, $assoc_args ) { @@ -34,7 +35,7 @@ public function posts( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); if ( !post_type_exists( $type ) ) { - WP_CLI::warning( "Invalid post type: $type" ); + WP_CLI::warning( 'invalid post type.' ); exit; } @@ -53,4 +54,46 @@ public function posts( $args, $assoc_args ) { ) ); } } + + /** + * Generate users + * + * @param array $args + * @param array $assoc_args + * @return void + **/ + public function users( $args, $assoc_args ) { + global $blog_id; + + $defaults = array( + 'count' => 100, + 'role' => get_option('default_role'), + ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( is_null( get_role( $role ) ) ) { + WP_CLI::warning( "invalid role." ); + exit; + } + + $user_count = count_users(); + + $total = $user_count['total_users']; + + $limit = $count + $total; + + for ( $i = $total; $i < $limit; $i++ ) { + $login = sprintf( 'user_%d_%d', $blog_id, $i ); + $name = "User $i"; + + $r = wp_insert_user( array( + 'user_login' => $login, + 'user_pass' => $login, + 'nickname' => $name, + 'display_name' => $name, + 'role' => $role + ) ); + } + } } From 57725ff57d73112a397941fe58142f2e9d362b41 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 5 Oct 2011 08:05:35 +0300 Subject: [PATCH 0083/5359] plugin.php cleanup * silence plugin sub-commands which don't involve HTTP requests * don't error if plugin is already (de)activated * remove some obvious comments * coding standards --- commands/internals/plugin.php | 210 ++++++++++++++-------------------- 1 file changed, 89 insertions(+), 121 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index b850d25c7..4cab54c2e 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -1,9 +1,7 @@ check_name( $args ); - // Get the plugin file name $file = $this->parse_name( $name ); - - // Get list of mu plugins + $mu_plugins = get_mu_plugins(); - // Get the plugin details $details = $this->get_details( $file ); - + // Get the plugin status if ( isset( $mu_plugins[ $file ] ) ) $status = '%cMust Use'; @@ -52,7 +46,7 @@ function status( $args = array(), $vars = array() ) { $status = '%gYes'; else $status = '%rNo'; - + // Display the plugin details WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); @@ -62,13 +56,10 @@ function status( $args = array(), $vars = array() ) { WP_CLI::line( ' Author: ' . $details[ 'Author' ]); } else { - // Get the list of plugins $plugins = get_plugins(); - // Get list of mu plugins $mu_plugins = get_mu_plugins(); - // Merge the two plugin arrays $plugins = array_merge($plugins, $mu_plugins); // Print the header @@ -122,23 +113,15 @@ function status( $args = array(), $vars = array() ) { * @param string $args * @return void */ - function activate($args) { - // Get the plugin name from the arguments - $name = $this->check_name($args); + function activate( $args ) { + $name = $this->check_name( $args ); - // Get the plugin file name - $file = $this->parse_name($name); + $file = $this->parse_name( $name ); - // Check if the plugin is already active - if(is_plugin_active($file)) { - WP_CLI::error('The plugin is already active: '.$name); - } - // Try to activate the plugin - elseif(activate_plugin($file) === null) { - WP_CLI::success('Plugin activated: '.$name); - } - else { - WP_CLI::error('The plugin could not be activated: '.$name); + activate_plugin( $file ); + + if ( !is_plugin_active( $file ) ) { + WP_CLI::error( 'Could not activate this plugin: ' . $name ); } } @@ -148,23 +131,15 @@ function activate($args) { * @param string $args * @return void */ - function deactivate($args) { - // Get the plugin name from the arguments - $name = $this->check_name($args); + function deactivate( $args ) { + $name = $this->check_name( $args ); - // Get the plugin file name - $file = $this->parse_name($name); + $file = $this->parse_name( $name ); - // Check if the plugin is already deactivated - if(is_plugin_inactive($file)) { - WP_CLI::error('The plugin is already deactivated: '.$name); - } - // Try to deactivate the plugin - elseif(deactivate_plugins($file) === null) { - WP_CLI::success('Plugin deactivated: '.$name); - } - else { - WP_CLI::error('Could not deactivate this plugin: '.$name); + deactivate_plugins( $file ); + + if ( !is_plugin_inactive( $file ) ) { + WP_CLI::error( 'Could not deactivate this plugin: '.$name ); } } @@ -174,54 +149,54 @@ function deactivate($args) { * @param string $args * @return void */ - function install($args) { + function install( $args ) { // Get the plugin name from the arguments - $name = $this->check_name($args); + $name = $this->check_name( $args ); // Get the plugin file name - $file = $this->parse_name($name, false); + $file = $this->parse_name( $name, false ); // Force WordPress to update the plugin list wp_update_plugins(); // Get plugin info from the WordPress servers - $api = plugins_api('plugin_information', array('slug' => stripslashes($name))); - $status = install_plugin_install_status($api); + $api = plugins_api( 'plugin_information', array( 'slug' => stripslashes( $name ) ) ); + $status = install_plugin_install_status( $api ); - WP_CLI::line('Installing '.$api->name.' ('.$api->version.')'); + WP_CLI::line( 'Installing '.$api->name.' ('.$api->version.')' ); // Check what to do - switch($status['status']) { - case 'update_available': - case 'install': - if(!class_exists('Plugin_Upgrader')) { - require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); - } + switch ( $status['status'] ) { + case 'update_available': + case 'install': + if ( !class_exists( 'Plugin_Upgrader' ) ) { + require_once( ABSPATH.'wp-admin/includes/class-wp-upgrader.php' ); + } - // Install the plugin - ob_start('strip_tags'); - $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); - $result = $upgrader->install($api->download_link); - $feedback = ob_get_clean(); + // Install the plugin + ob_start( 'strip_tags' ); + $upgrader = new Plugin_Upgrader( new CLI_Upgrader_Skin ); + $result = $upgrader->install( $api->download_link ); + $feedback = ob_get_clean(); - if($result !== null) { - WP_CLI::error($result); - } - else { - WP_CLI::line(); - WP_CLI::line(strip_tags(str_replace(array('…', 'Plugin installed successfully.'), array(" ...\n", ''), html_entity_decode($feedback)))); - WP_CLI::success('The plugin is successfully installed'); - } + if ( $result !== null ) { + WP_CLI::error( $result ); + } + else { + WP_CLI::line(); + WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( " ...\n", '' ), html_entity_decode( $feedback ) ) ) ); + WP_CLI::success( 'The plugin is successfully installed' ); + } break; - case 'newer_installed': - WP_CLI::error(sprintf('Newer version (%s) installed', $status['version'])); + case 'newer_installed': + WP_CLI::error( sprintf( 'Newer version ( %s ) installed', $status['version'] ) ); break; - case 'latest_installed': - WP_CLI::error('Latest version already installed'); + case 'latest_installed': + WP_CLI::error( 'Latest version already installed' ); - if(is_plugin_inactive($file)) { - WP_CLI::warning('If you want to activate the plugin, run: %2wp plugin activate '.$name.'%n'); - } + if ( is_plugin_inactive( $file ) ) { + WP_CLI::warning( 'If you want to activate the plugin, run: %2wp plugin activate '.$name.'%n' ); + } break; } } @@ -232,18 +207,13 @@ function install($args) { * @param string $args * @return void */ - function delete($args) { - // Get the plugin name from the arguments - $name = $this->check_name($args); + function delete( $args ) { + $name = $this->check_name( $args ); - // Get the plugin file name - $file = $this->parse_name($name); + $file = $this->parse_name( $name ); - if(delete_plugins(array($file))) { - WP_CLI::success('The plugin is successfully deleted.'); - } - else { - WP_CLI::error('There was an error while deleting the plugin.'); + if ( !delete_plugins( array( $file ) ) ) { + WP_CLI::error( 'There was an error while deleting the plugin.' ); } } @@ -253,35 +223,33 @@ function delete($args) { * @param string $args * @return void */ - function update($args) { - // Get the plugin name from the arguments - $name = $this->check_name($args); + function update( $args ) { + $name = $this->check_name( $args ); - // Get the plugin file name - $file = $this->parse_name($name); + $file = $this->parse_name( $name ); // Force WordPress to update the plugin list wp_update_plugins(); - if(!class_exists('Plugin_Upgrader')) { - require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); + if ( !class_exists( 'Plugin_Upgrader' ) ) { + require_once( ABSPATH.'wp-admin/includes/class-wp-upgrader.php' ); } - WP_CLI::line('Updating '.$name); + WP_CLI::line( 'Updating '.$name ); // Upgrading the plugin - ob_start('strip_tags'); - $upgrader = new Plugin_Upgrader(new CLI_Upgrader_Skin); - $result = $upgrader->upgrade($file); + ob_start( 'strip_tags' ); + $upgrader = new Plugin_Upgrader( new CLI_Upgrader_Skin ); + $result = $upgrader->upgrade( $file ); $feedback = ob_get_clean(); - if($result !== null) { - WP_CLI::error($feedback); + if ( $result !== null ) { + WP_CLI::error( $feedback ); } else { WP_CLI::line(); - WP_CLI::line(html_entity_decode(strip_tags($feedback))); - WP_CLI::success('The plugin is successfully updated.'); + WP_CLI::line( html_entity_decode( strip_tags( $feedback ) ) ); + WP_CLI::success( 'The plugin is successfully updated.' ); } } @@ -293,9 +261,9 @@ function update($args) { * @param string $file * @return array */ - private function get_details($file) { - $plugin_folder = get_plugins( '/' . plugin_basename(dirname($file))); - $plugin_file = basename(($file)); + private function get_details( $file ) { + $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); + $plugin_file = basename( ( $file ) ); return $plugin_folder[$plugin_file]; } @@ -307,21 +275,21 @@ private function get_details($file) { * @param string $exit * @return mixed */ - private function parse_name($name, $exit = true) { - $plugins = get_plugins('/'.$name); + private function parse_name( $name, $exit = true ) { + $plugins = get_plugins( '/'.$name ); - if(!empty($plugins)) { - $keys = array_keys($plugins); + if ( !empty( $plugins ) ) { + $keys = array_keys( $plugins ); $file = $name.'/'.$keys[0]; } else { $plugins = get_plugins(); - if(isset($plugins[$name.'.php'])) { + if ( isset( $plugins[$name.'.php'] ) ) { $file = $name.'.php'; } else { - if($exit) { - WP_CLI::error('The plugin \''.$name.'\' could not be found.'); + if ( $exit ) { + WP_CLI::error( 'The plugin \''.$name.'\' could not be found.' ); exit(); } @@ -339,13 +307,13 @@ private function parse_name($name, $exit = true) { * @param string $exit * @return void */ - private function check_name($args, $exit = true) { - if(empty($args)) { - WP_CLI::error('Please specify a plugin.'); + private function check_name( $args, $exit = true ) { + if ( empty( $args ) ) { + WP_CLI::error( 'Please specify a plugin.' ); WP_CLI::line(); $this->help(); - if($exit) { + if ( $exit ) { exit(); } } @@ -359,20 +327,20 @@ private function check_name($args, $exit = true) { * @param string $args * @return void */ - public function help($args = array()) { + public function help( $args = array() ) { // Shot the command description WP_CLI::line( $this->get_description() ); WP_CLI::line(); // Show the list of sub-commands for this command - WP_CLI::line('Example usage:'); + WP_CLI::line( 'Example usage:' ); - foreach (WP_CLI_Command::get_methods($this) as $method) { - if($method != 'help') { - WP_CLI::line(' wp '.$this->command.' '.$method.' hello-dolly'); + foreach ( WP_CLI_Command::get_methods( $this ) as $method ) { + if ( $method != 'help' ) { + WP_CLI::line( ' wp '.$this->command.' '.$method.' hello-dolly' ); } else { - WP_CLI::line(' wp '.$this->command.' '.$method); + WP_CLI::line( ' wp '.$this->command.' '.$method ); } } } From 899ab3c3767ebb09a30830b14a03cbfcf0e46f9e Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 5 Oct 2011 15:25:09 +0100 Subject: [PATCH 0084/5359] Same spelling mistake as before. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef6681ca5..680af9b74 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ A wp-cli class is structured like this: * Implement example command * * @package wp-cli - * @subpackage commands/cummunity + * @subpackage commands/community * @author Andreas Creten */ class ExampleCommand extends WP_CLI_Command { From d1581b182b6b3e0073d01ff473263dff33892e36 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 19:50:41 +0300 Subject: [PATCH 0085/5359] add wp plugin toggle command --- commands/internals/plugin.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 4cab54c2e..9bb0c23b0 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -122,6 +122,8 @@ function activate( $args ) { if ( !is_plugin_active( $file ) ) { WP_CLI::error( 'Could not activate this plugin: ' . $name ); + } else { + WP_CLI::line( 'Plugin activated.' ); } } @@ -140,6 +142,26 @@ function deactivate( $args ) { if ( !is_plugin_inactive( $file ) ) { WP_CLI::error( 'Could not deactivate this plugin: '.$name ); + } else { + WP_CLI::line( 'Plugin deactivated.' ); + } + } + + /** + * Toggle a plugin's activation state + * + * @param string $args + * @return void + */ + function toggle( $args ) { + $name = $this->check_name( $args ); + + $file = $this->parse_name( $name ); + + if ( is_plugin_active( $file ) ) { + $this->deactivate( $args ); + } else { + $this->activate( $args ); } } From b065aa849e480e3f81313fa03a919c2299563241 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 19:51:07 +0300 Subject: [PATCH 0086/5359] some code cleanup in parse_name() --- commands/internals/plugin.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 9bb0c23b0..50c060254 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -29,7 +29,7 @@ function status( $args = array(), $vars = array() ) { wp_update_plugins(); if ( !empty( $args ) ) { - $name = $this->check_name( $args ); + $name = $args[0]; $file = $this->parse_name( $name ); @@ -298,20 +298,17 @@ private function get_details( $file ) { * @return mixed */ private function parse_name( $name, $exit = true ) { - $plugins = get_plugins( '/'.$name ); + $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { - $keys = array_keys( $plugins ); - $file = $name.'/'.$keys[0]; + $file = $name . '/' . key( $plugins ); } else { + $file = $name . '.php'; $plugins = get_plugins(); - if ( isset( $plugins[$name.'.php'] ) ) { - $file = $name.'.php'; - } - else { + if ( !isset( $plugins[$file] ) ) { if ( $exit ) { - WP_CLI::error( 'The plugin \''.$name.'\' could not be found.' ); + WP_CLI::error( "The plugin '$name' could not be found." ); exit(); } From aaa8a2885a96ec64623ae5a90ba87777848d7cb8 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 19:52:45 +0300 Subject: [PATCH 0087/5359] $args is always an array --- class-wp-cli-command.php | 2 +- .../community/google-sitemap-generator.php | 2 +- commands/community/w3-total-cache.php | 2 +- commands/community/wp-super-cache.php | 2 +- commands/internals/core.php | 2 +- commands/internals/home.php | 2 +- commands/internals/option.php | 10 +++++----- commands/internals/plugin.php | 18 +++++++++--------- commands/internals/theme.php | 6 +++--- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index e6a6dee47..e8c75c43c 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -62,7 +62,7 @@ protected function dispatch( $args, $assoc_args ) { /** * General help function for this command * - * @param string $args + * @param array $args * @param string $assoc_args * @return void */ diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index c5d7dbaa4..6f6b90526 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -32,7 +32,7 @@ function rebuild( $args = array(), $vars = array() ) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index 98d0fcca1..c3dfe9960 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -86,7 +86,7 @@ function flush( $args = array(), $vars = array() ) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index c78238698..a24c4ff57 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -128,7 +128,7 @@ function disable( $args = array(), $vars = array() ) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { diff --git a/commands/internals/core.php b/commands/internals/core.php index 62cd85d10..a496f7aef 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -19,7 +19,7 @@ public static function get_description() { /** * Update the WordPress core * - * @param string $args + * @param array $args * @return void */ function update($args) { diff --git a/commands/internals/home.php b/commands/internals/home.php index d70cf2975..7e34a80b1 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -50,7 +50,7 @@ protected function dispatch( $args, $assoc_args ) { /** * Help function for this command. * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { diff --git a/commands/internals/option.php b/commands/internals/option.php index 388aa3b75..69b325e74 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -19,7 +19,7 @@ public static function get_description() { /** * Add an option * - * @param string $args + * @param array $args * @return void **/ public function add($args = array()) { @@ -41,7 +41,7 @@ public function add($args = array()) { /** * Update an option * - * @param string $args + * @param array $args * @return void **/ public function update($args = array()) { @@ -63,7 +63,7 @@ public function update($args = array()) { /** * Delete an option * - * @param string $args + * @param array $args * @return void **/ public function delete($args = array()) { @@ -85,7 +85,7 @@ public function delete($args = array()) { /** * Get an option * - * @param string $args + * @param array $args * @return void **/ public function get($args = array()) { @@ -108,7 +108,7 @@ public function get($args = array()) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 50c060254..d789a6b04 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -21,7 +21,7 @@ public static function get_description() { /** * Get the status of one plugin * - * @param string $args + * @param array $args * @return void */ function status( $args = array(), $vars = array() ) { @@ -110,7 +110,7 @@ function status( $args = array(), $vars = array() ) { /** * Activate a plugin * - * @param string $args + * @param array $args * @return void */ function activate( $args ) { @@ -130,7 +130,7 @@ function activate( $args ) { /** * Deactivate a plugin * - * @param string $args + * @param array $args * @return void */ function deactivate( $args ) { @@ -150,7 +150,7 @@ function deactivate( $args ) { /** * Toggle a plugin's activation state * - * @param string $args + * @param array $args * @return void */ function toggle( $args ) { @@ -168,7 +168,7 @@ function toggle( $args ) { /** * Install a new plugin * - * @param string $args + * @param array $args * @return void */ function install( $args ) { @@ -226,7 +226,7 @@ function install( $args ) { /** * Delete a plugin * - * @param string $args + * @param array $args * @return void */ function delete( $args ) { @@ -242,7 +242,7 @@ function delete( $args ) { /** * Update a plugin * - * @param string $args + * @param array $args * @return void */ function update( $args ) { @@ -322,7 +322,7 @@ private function parse_name( $name, $exit = true ) { /** * Check if there is a name set in the arguments, if not show the help function * - * @param string $args + * @param array $args * @param string $exit * @return void */ @@ -343,7 +343,7 @@ private function check_name( $args, $exit = true ) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help( $args = array() ) { diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 22c6f6b96..22c8a50f2 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -19,7 +19,7 @@ public static function get_description() { /** * Get the status of all themes * - * @param string $args + * @param array $args * @return void **/ public function status($args = array()) { @@ -62,7 +62,7 @@ public function status($args = array()) { /** * Get theme details * - * @param string $args + * @param array $args * @return void **/ public function details($args = array()) { @@ -121,7 +121,7 @@ protected function get_stylesheet_path( $theme ) { /** * Help function for this command * - * @param string $args + * @param array $args * @return void */ public function help($args = array()) { From 58bd416cce6539c9e9c2139bb27af7e5e676042e Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 20:53:56 +0300 Subject: [PATCH 0088/5359] when plugin name is missing, show simple usage example instead of generic help --- commands/internals/plugin.php | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index d789a6b04..6e3379665 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -114,7 +114,7 @@ function status( $args = array(), $vars = array() ) { * @return void */ function activate( $args ) { - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); $file = $this->parse_name( $name ); @@ -134,7 +134,7 @@ function activate( $args ) { * @return void */ function deactivate( $args ) { - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); $file = $this->parse_name( $name ); @@ -154,7 +154,7 @@ function deactivate( $args ) { * @return void */ function toggle( $args ) { - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); $file = $this->parse_name( $name ); @@ -172,10 +172,8 @@ function toggle( $args ) { * @return void */ function install( $args ) { - // Get the plugin name from the arguments - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); - // Get the plugin file name $file = $this->parse_name( $name, false ); // Force WordPress to update the plugin list @@ -230,7 +228,7 @@ function install( $args ) { * @return void */ function delete( $args ) { - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); $file = $this->parse_name( $name ); @@ -246,7 +244,7 @@ function delete( $args ) { * @return void */ function update( $args ) { - $name = $this->check_name( $args ); + $name = $this->check_name( $args, __FUNCTION__ ); $file = $this->parse_name( $name ); @@ -320,21 +318,16 @@ private function parse_name( $name, $exit = true ) { } /** - * Check if there is a name set in the arguments, if not show the help function + * Check if there is a name set in the arguments; if not show usage example * * @param array $args - * @param string $exit - * @return void + * @param string $sub_command + * @return string */ - private function check_name( $args, $exit = true ) { + private function check_name( $args, $sub_command ) { if ( empty( $args ) ) { - WP_CLI::error( 'Please specify a plugin.' ); - WP_CLI::line(); - $this->help(); - - if ( $exit ) { - exit(); - } + WP_CLI::line( "usage: wp plugin $sub_command " ); + exit; } return $args[0]; From c80bed8c22f49b1bca8cbfb06a2bae69e90e1d03 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 21:06:49 +0300 Subject: [PATCH 0089/5359] merge check_name() into parse_name() --- commands/internals/plugin.php | 62 +++++++++++------------------------ 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 6e3379665..4ad7e5787 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -29,9 +29,7 @@ function status( $args = array(), $vars = array() ) { wp_update_plugins(); if ( !empty( $args ) ) { - $name = $args[0]; - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $mu_plugins = get_mu_plugins(); @@ -114,9 +112,7 @@ function status( $args = array(), $vars = array() ) { * @return void */ function activate( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); activate_plugin( $file ); @@ -134,9 +130,7 @@ function activate( $args ) { * @return void */ function deactivate( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); deactivate_plugins( $file ); @@ -154,9 +148,7 @@ function deactivate( $args ) { * @return void */ function toggle( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); if ( is_plugin_active( $file ) ) { $this->deactivate( $args ); @@ -172,9 +164,7 @@ function toggle( $args ) { * @return void */ function install( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name, false ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__, false ); // Force WordPress to update the plugin list wp_update_plugins(); @@ -228,9 +218,7 @@ function install( $args ) { * @return void */ function delete( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); if ( !delete_plugins( array( $file ) ) ) { WP_CLI::error( 'There was an error while deleting the plugin.' ); @@ -244,9 +232,7 @@ function delete( $args ) { * @return void */ function update( $args ) { - $name = $this->check_name( $args, __FUNCTION__ ); - - $file = $this->parse_name( $name ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); // Force WordPress to update the plugin list wp_update_plugins(); @@ -291,11 +277,19 @@ private function get_details( $file ) { /** * Parse the name of a plugin to a filename, check if it exists * - * @param string $name - * @param string $exit - * @return mixed + * @param array $args + * @param string $sub_command + * @param bool $exit + * @return array */ - private function parse_name( $name, $exit = true ) { + private function parse_name( $args, $sub_command, $exit = true ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp plugin $sub_command " ); + exit; + } + + $name = $args[0]; + $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { @@ -314,23 +308,7 @@ private function parse_name( $name, $exit = true ) { } } - return $file; - } - - /** - * Check if there is a name set in the arguments; if not show usage example - * - * @param array $args - * @param string $sub_command - * @return string - */ - private function check_name( $args, $sub_command ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp plugin $sub_command " ); - exit; - } - - return $args[0]; + return array( $file, $name ); } /** From 9c336a0b967512d7c6ed0925693f23caff0d49de Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 21:14:02 +0300 Subject: [PATCH 0090/5359] rename `wp theme details` to `wp theme status` to match wp plugin status --- commands/internals/plugin.php | 130 ++++++++++++++++++---------------- commands/internals/theme.php | 43 ++++++----- 2 files changed, 88 insertions(+), 85 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 4ad7e5787..847e1d49d 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -19,90 +19,94 @@ public static function get_description() { } /** - * Get the status of one plugin + * Get the status of one or all plugins * * @param array $args * @return void */ function status( $args = array(), $vars = array() ) { - // Force WordPress to update the plugin list - wp_update_plugins(); + if ( empty( $args ) ) { + $this->list_plugins(); + return; + } - if ( !empty( $args ) ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - $mu_plugins = get_mu_plugins(); + $mu_plugins = get_mu_plugins(); + + $details = $this->get_details( $file ); + + // Get the plugin status + if ( isset( $mu_plugins[ $file ] ) ) + $status = '%cMust Use'; + elseif ( is_plugin_active_for_network( $file ) ) + $status = '%bNetwork Activated'; + elseif ( is_plugin_active( $file ) ) + $status = '%gYes'; + else + $status = '%rNo'; + + // Display the plugin details + WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); + WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Active: ' . $status .'%n' ); + WP_CLI::line( ' Version: ' . $details[ 'Version' ] . ( WP_CLI::get_update_status( $file, 'update_plugins' ) ? ' (%gUpdate available%n)' : '' ) ); + WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); + WP_CLI::line( ' Author: ' . $details[ 'Author' ]); + } - $details = $this->get_details( $file ); + private function list_plugins() { + // Force WordPress to update the plugin list + wp_update_plugins(); - // Get the plugin status - if ( isset( $mu_plugins[ $file ] ) ) - $status = '%cMust Use'; - elseif ( is_plugin_active_for_network( $file ) ) - $status = '%bNetwork Activated'; - elseif ( is_plugin_active( $file ) ) - $status = '%gYes'; - else - $status = '%rNo'; - - // Display the plugin details - WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); - WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); - WP_CLI::line( ' Active: ' . $status .'%n' ); - WP_CLI::line( ' Version: ' . $details[ 'Version' ] . ( WP_CLI::get_update_status( $file, 'update_plugins' ) ? ' (%gUpdate available%n)' : '' ) ); - WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); - WP_CLI::line( ' Author: ' . $details[ 'Author' ]); - } - else { - $plugins = get_plugins(); + $plugins = get_plugins(); - $mu_plugins = get_mu_plugins(); + $mu_plugins = get_mu_plugins(); - $plugins = array_merge($plugins, $mu_plugins); + $plugins = array_merge($plugins, $mu_plugins); - // Print the header - WP_CLI::line('Installed plugins:'); + // Print the header + WP_CLI::line('Installed plugins:'); - foreach ($plugins as $file => $plugin) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace('.php', '', basename($file)); - else - $name = dirname($file); + foreach ($plugins as $file => $plugin) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace('.php', '', basename($file)); + else + $name = dirname($file); - if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { - $line = ' %yU%n'; - } else { - $line = ' '; - } + if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { + $line = ' %yU%n'; + } else { + $line = ' '; + } - if ( isset($mu_plugins[$file]) ) - $line .= '%cM'; - elseif ( is_plugin_active_for_network($file) ) - $line .= '%bN'; - elseif ( is_plugin_active($file) ) - $line .= '%gA'; - else - $line .= 'I'; + if ( isset($mu_plugins[$file]) ) + $line .= '%cM'; + elseif ( is_plugin_active_for_network($file) ) + $line .= '%bN'; + elseif ( is_plugin_active($file) ) + $line .= '%gA'; + else + $line .= 'I'; - $line .= ' '.$name.'%n'; + $line .= ' '.$name.'%n'; - WP_CLI::line( $line ); - } + WP_CLI::line( $line ); + } - // Print the footer - WP_CLI::line(); + // Print the footer + WP_CLI::line(); - $legend = array( - 'I' => 'Inactive', - '%gA' => 'Active', - '%cM' => 'Must Use', - ); + $legend = array( + 'I' => 'Inactive', + '%gA' => 'Active', + '%cM' => 'Must Use', + ); - if ( is_multisite() ) - $legend['%bN'] = 'Network Active'; + if ( is_multisite() ) + $legend['%bN'] = 'Network Active'; - WP_CLI::legend( $legend ); - } + WP_CLI::legend( $legend ); } /** diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 22c8a50f2..43e9d1f5c 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -17,12 +17,31 @@ public static function get_description() { } /** - * Get the status of all themes + * Get the status of one or all themes * * @param array $args * @return void **/ - public function status($args = array()) { + public function status( $args = array() ) { + if ( empty( $args ) ) { + $this->list_themes(); + return; + } + + // Get the info of the theme + $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + + // Get the current theme + $theme_name = get_current_theme(); + + WP_CLI::line('Theme %2'.$details['Name'].'%n details:'); + WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); + WP_CLI::line(' Version: '.$details['Version']); + WP_CLI::line(' Author: '.strip_tags($details['Author'])); + //WP_CLI::line(' Description: '.strip_tags($details['Description'])); + } + + private function list_themes() { // Get the list of themes $themes = get_themes(); @@ -59,26 +78,6 @@ public function status($args = array()) { WP_CLI::legend( $legend ); } - /** - * Get theme details - * - * @param array $args - * @return void - **/ - public function details($args = array()) { - // Get the info of the theme - $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); - - // Get the current theme - $theme_name = get_current_theme(); - - WP_CLI::line('Theme %2'.$details['Name'].'%n details:'); - WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); - WP_CLI::line(' Version: '.$details['Version']); - WP_CLI::line(' Author: '.strip_tags($details['Author'])); - //WP_CLI::line(' Description: '.strip_tags($details['Description'])); - } - /** * Activate a theme * From c5bc34aa949ad30848fa8711f96748cdfb1e9112 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 21:27:24 +0300 Subject: [PATCH 0091/5359] use helper function for determining plugin status --- commands/internals/plugin.php | 53 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 847e1d49d..1ceb56643 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -18,6 +18,8 @@ public static function get_description() { return 'Do cool things with plugins.'; } + private $mu_plugins; + /** * Get the status of one or all plugins * @@ -25,6 +27,8 @@ public static function get_description() { * @return void */ function status( $args = array(), $vars = array() ) { + $this->mu_plugins = get_mu_plugins(); + if ( empty( $args ) ) { $this->list_plugins(); return; @@ -32,24 +36,13 @@ function status( $args = array(), $vars = array() ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - $mu_plugins = get_mu_plugins(); - $details = $this->get_details( $file ); - // Get the plugin status - if ( isset( $mu_plugins[ $file ] ) ) - $status = '%cMust Use'; - elseif ( is_plugin_active_for_network( $file ) ) - $status = '%bNetwork Activated'; - elseif ( is_plugin_active( $file ) ) - $status = '%gYes'; - else - $status = '%rNo'; - - // Display the plugin details + $status = $this->get_status( $file, true ); + WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); - WP_CLI::line( ' Active: ' . $status .'%n' ); + WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Version: ' . $details[ 'Version' ] . ( WP_CLI::get_update_status( $file, 'update_plugins' ) ? ' (%gUpdate available%n)' : '' ) ); WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); WP_CLI::line( ' Author: ' . $details[ 'Author' ]); @@ -61,9 +54,7 @@ private function list_plugins() { $plugins = get_plugins(); - $mu_plugins = get_mu_plugins(); - - $plugins = array_merge($plugins, $mu_plugins); + $plugins = array_merge( $plugins, $this->mu_plugins ); // Print the header WP_CLI::line('Installed plugins:'); @@ -80,16 +71,7 @@ private function list_plugins() { $line = ' '; } - if ( isset($mu_plugins[$file]) ) - $line .= '%cM'; - elseif ( is_plugin_active_for_network($file) ) - $line .= '%bN'; - elseif ( is_plugin_active($file) ) - $line .= '%gA'; - else - $line .= 'I'; - - $line .= ' '.$name.'%n'; + $line .= $this->get_status( $file ) . " $name%n"; WP_CLI::line( $line ); } @@ -109,6 +91,23 @@ private function list_plugins() { WP_CLI::legend( $legend ); } + private function get_status( $file, $long = false ) { + if ( isset( $this->mu_plugins[ $file ] ) ) { + $line = '%c'; + $line .= $long ? 'Must Use' : 'M'; + } elseif ( is_plugin_active_for_network( $file ) ) { + $line = '%b'; + $line .= $long ? 'Network Active' : 'N'; + } elseif ( is_plugin_active( $file ) ) { + $line = '%g'; + $line .= $long ? 'Active' : 'A'; + } else { + $line = $long ? 'Inactive' : 'I'; + } + + return $line; + } + /** * Activate a plugin * From de970025ba79285cebdb5bdc6a158581f0f2364c Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 21:36:45 +0300 Subject: [PATCH 0092/5359] use bold text for theme name, as for plugins --- commands/internals/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 43e9d1f5c..e1b7979f4 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -34,7 +34,7 @@ public function status( $args = array() ) { // Get the current theme $theme_name = get_current_theme(); - WP_CLI::line('Theme %2'.$details['Name'].'%n details:'); + WP_CLI::line('Theme %9'.$details['Name'].'%n details:'); WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); WP_CLI::line(' Version: '.$details['Version']); WP_CLI::line(' Author: '.strip_tags($details['Author'])); From bfed58d9769a2db7594893ffdc5a7f7482cf7f98 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 6 Oct 2011 22:04:01 +0300 Subject: [PATCH 0093/5359] make `wp theme status` more similar to `wp plugin status` --- commands/internals/plugin.php | 11 +++++--- commands/internals/theme.php | 50 ++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 1ceb56643..543094f5d 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -40,12 +40,17 @@ function status( $args = array(), $vars = array() ) { $status = $this->get_status( $file, true ); + $version = $details[ 'Version' ]; + + if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) + $version .= ' (%gUpdate available%n)'; + WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); - WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); WP_CLI::line( ' Status: ' . $status .'%n' ); - WP_CLI::line( ' Version: ' . $details[ 'Version' ] . ( WP_CLI::get_update_status( $file, 'update_plugins' ) ? ' (%gUpdate available%n)' : '' ) ); + WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Version: ' . $version ); + WP_CLI::line( ' Author: ' . $details[ 'Author' ] ); WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); - WP_CLI::line( ' Author: ' . $details[ 'Author' ]); } private function list_plugins() { diff --git a/commands/internals/theme.php b/commands/internals/theme.php index e1b7979f4..92bbd0d3b 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -28,41 +28,36 @@ public function status( $args = array() ) { return; } - // Get the info of the theme - $details = get_theme_data(WP_CONTENT_DIR.'/themes/'.$args[0].'/style.css'); + $name = $args[0]; - // Get the current theme - $theme_name = get_current_theme(); + $details = get_theme_data( $this->get_stylesheet_path( $name ) ); - WP_CLI::line('Theme %9'.$details['Name'].'%n details:'); - WP_CLI::line(' Active: '.((int) ($details['Name'] == $theme_name))); - WP_CLI::line(' Version: '.$details['Version']); - WP_CLI::line(' Author: '.strip_tags($details['Author'])); - //WP_CLI::line(' Description: '.strip_tags($details['Description'])); + $status = $this->get_status( $details['Name'], true ); + + $version = $details[ 'Version' ]; + + if ( WP_CLI::get_update_status( $name, 'update_themes' ) ) + $version .= ' (%gUpdate available%n)'; + + WP_CLI::line( 'Theme %9' . $name . '%n details:' ); + WP_CLI::line( ' Status: ' . $status .'%n' ); + WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Version: ' . $version ); + WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } private function list_themes() { - // Get the list of themes - $themes = get_themes(); - // Print the header - WP_CLI::line('Installed themes:'); - - $theme_name = get_current_theme(); + WP_CLI::line( 'Installed themes:' ); - foreach ($themes as $key => $theme) { + foreach ( get_themes() as $theme ) { if ( WP_CLI::get_update_status( $theme['Stylesheet'], 'update_themes' ) ) { $line = ' %yU%n'; } else { $line = ' '; } - if ( $theme['Name'] == $theme_name ) - $line .= '%gA'; - else - $line .= 'I'; - - $line .= ' ' . $theme['Stylesheet'].'%n'; + $line .= $this->get_status( $theme['Name'] ) . ' ' . $theme['Stylesheet'] . '%n'; WP_CLI::line( $line ); } @@ -78,6 +73,17 @@ private function list_themes() { WP_CLI::legend( $legend ); } + private function get_status( $theme_name, $long = false ) { + if ( get_current_theme() == $theme_name ) { + $line = '%g'; + $line .= $long ? 'Active' : 'A'; + } else { + $line = $long ? 'Inactive' : 'I'; + } + + return $line; + } + /** * Activate a theme * From 1a0df2276870f23b6dbe8170ef72f95e6c889af1 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 03:39:12 +0300 Subject: [PATCH 0094/5359] deprecate get_description() method in favor of dedicated help methods --- class-wp-cli-command.php | 16 +++------------- commands/internals/core.php | 18 ++++++++++++++---- commands/internals/generate.php | 27 +++++++++++++++++++++++---- commands/internals/home.php | 15 +++++++-------- commands/internals/option.php | 31 ++++++++----------------------- commands/internals/plugin.php | 33 ++++++++++++++------------------- commands/internals/theme.php | 24 +++++++++--------------- 7 files changed, 78 insertions(+), 86 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index e8c75c43c..d1808bbef 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -8,15 +8,6 @@ */ abstract class WP_CLI_Command { - /** - * Return a short description for the command. - * - * @return string - */ - public static function get_description() { - return false; - } - /** * Keeps a reference to the current command name * @@ -55,7 +46,7 @@ protected function dispatch( $args, $assoc_args ) { if ( !method_exists($this, $sub_command) || isset( $assoc_args[ 'help' ] ) ) { $sub_command = 'help'; } - + $this->$sub_command($args, $assoc_args); } @@ -67,9 +58,8 @@ protected function dispatch( $args, $assoc_args ) { * @return void */ public function help( $args = array(), $assoc_args = array() ) { - $desc = $this->get_description(); - if ( $desc ) { - WP_CLI::line( $desc ); + if ( method_exists( $this, 'get_description' ) ) { + WP_CLI::line( $this->get_description() ); WP_CLI::line(); } diff --git a/commands/internals/core.php b/commands/internals/core.php index a496f7aef..d1af5d6b3 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -12,10 +12,6 @@ */ class CoreCommand extends WP_CLI_Command { - public static function get_description() { - return 'Update the WordPress core.'; - } - /** * Update the WordPress core * @@ -46,4 +42,18 @@ function update($args) { WP_CLI::success('WordPress upgraded successfully.'); } } + + /** + * Help function for this command + * + * @param array $args + * @return void + */ + public function help( $args = array() ) { + WP_CLI::line( 'usage: wp core update' ); + + WP_CLI::sub_commands( array( + 'update' => 'update the WordPress core files from wordpress.org', + ) ); + } } diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 0d1d654ae..9329e0401 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -12,10 +12,6 @@ */ class GenerateCommand extends WP_CLI_Command { - public static function get_description() { - return 'Generate a certain number of objects.'; - } - /** * Generate posts * @@ -96,4 +92,27 @@ public function users( $args, $assoc_args ) { ) ); } } + + /** + * Help function for this command + * + * @param array $args + * @return void + */ + public function help( $args = array() ) { + WP_CLI::out( << [--count=100] + +Available object types: + posts generate some posts + --count number of users to generate (default: 100) + --type post type (default: 'post') + --status post status (default: 'publish') + users generate some users + --count number of users to generate (default: 100) + --role user role (default: default_role option) + +EOB + ); + } } diff --git a/commands/internals/home.php b/commands/internals/home.php index 7e34a80b1..6bab53e12 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -12,10 +12,6 @@ */ class HomeCommand extends WP_CLI_Command { - public static function get_description() { - return 'Open the wp-cli project on Github.'; - } - /** * Overwrite the dispatch method to have a command without sub-commands. * @@ -54,9 +50,12 @@ protected function dispatch( $args, $assoc_args ) { * @return void */ public function help($args = array()) { - WP_CLI::line('This command has no arguments; when called it will open the wp-cli homepage in your browser.'); - WP_CLI::line(); - WP_CLI::line('Example usage:'); - WP_CLI::line(' wp home'); + WP_CLI::out( << '); - WP_CLI::line(' wp option update '); - WP_CLI::line(' wp option delete '); - WP_CLI::line(' wp option get '); - WP_CLI::line(''); - WP_CLI::line('%9--- DETAILS ---%n'); - WP_CLI::line(''); - WP_CLI::line('Adding a new option:'); - WP_CLI::line(' wp option add '); - WP_CLI::line(''); - WP_CLI::line('Updating an option:'); - WP_CLI::line(' wp option update '); - WP_CLI::line(''); - WP_CLI::line('Deleting an option:'); - WP_CLI::line(' wp option delete '); - WP_CLI::line(''); - WP_CLI::line('Get the value of an option:'); - WP_CLI::line(' wp option get '); + WP_CLI::out( << + or: wp option add + or: wp option update + or: wp option delete + +EOB + ); } } diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 543094f5d..fe800e2dc 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -14,10 +14,6 @@ */ class PluginCommand extends WP_CLI_Command { - public static function get_description() { - return 'Do cool things with plugins.'; - } - private $mu_plugins; /** @@ -326,20 +322,19 @@ private function parse_name( $args, $sub_command, $exit = true ) { * @return void */ public function help( $args = array() ) { - // Shot the command description - WP_CLI::line( $this->get_description() ); - WP_CLI::line(); - - // Show the list of sub-commands for this command - WP_CLI::line( 'Example usage:' ); - - foreach ( WP_CLI_Command::get_methods( $this ) as $method ) { - if ( $method != 'help' ) { - WP_CLI::line( ' wp '.$this->command.' '.$method.' hello-dolly' ); - } - else { - WP_CLI::line( ' wp '.$this->command.' '.$method ); - } - } + WP_CLI::out( << [] + +Available sub-commands: + status display status of all installed plugins or of a particular plugin + activate activate a particular plugin + deactivate deactivate a particular plugin + toggle toggle activation state of a particular plugin + install install a plugin from wordpress.org + update update a plugin from wordpress.org + delete delete a plugin + +EOB + ); } } diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 92bbd0d3b..ed8373cce 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -12,10 +12,6 @@ */ class ThemeCommand extends WP_CLI_Command { - public static function get_description() { - return 'Do cool things with themes.'; - } - /** * Get the status of one or all themes * @@ -130,16 +126,14 @@ protected function get_stylesheet_path( $theme ) { * @return void */ public function help($args = array()) { - WP_CLI::line('Example usage:'); - WP_CLI::line(' wp theme status'); - WP_CLI::line(' wp theme details '); - WP_CLI::line(''); - WP_CLI::line('%9--- DETAILS ---%n'); - WP_CLI::line(''); - WP_CLI::line('Get a status of the installed themes:'); - WP_CLI::line(' wp theme status'); - WP_CLI::line(''); - WP_CLI::line('Get the details for a theme:'); - WP_CLI::line(' wp theme details '); + WP_CLI::out( << [] + +Available sub-commands: + status display status of all installed themes or of a particular theme + activate activate a particular theme + +EOB + ); } } From fe72efd28ce903a6f4c0c965c7b138cbda02480d Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 03:44:00 +0300 Subject: [PATCH 0095/5359] make GenerateCommand::help() output more compact --- commands/internals/generate.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 9329e0401..89e676150 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -101,17 +101,8 @@ public function users( $args, $assoc_args ) { */ public function help( $args = array() ) { WP_CLI::out( << [--count=100] - -Available object types: - posts generate some posts - --count number of users to generate (default: 100) - --type post type (default: 'post') - --status post status (default: 'publish') - users generate some users - --count number of users to generate (default: 100) - --role user role (default: default_role option) - +usage: wp generate posts [--count=100] [--type=post] [--status=publish] + or: wp generate users [--count=100] [--role=] EOB ); } From e32684ccffd17159f1eb6dafb5cf8e8193da8d13 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 04:18:59 +0300 Subject: [PATCH 0096/5359] introduce help command. fixes #22 --- class-wp-cli-command.php | 2 +- class-wp-cli.php | 17 ------------ commands/internals/generate.php | 1 + commands/internals/help.php | 49 +++++++++++++++++++++++++++++++++ wp-cli.php | 4 +-- 5 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 commands/internals/help.php diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index d1808bbef..4ec9adae5 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -87,7 +87,7 @@ static function get_methods($class) { $methods = array(); foreach ( $reflection->getMethods() as $method ) { - if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { + if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() && 'help' != $method->name ) { $name = $method->name; if ( strpos( $name, '_' ) === 0 ) { diff --git a/class-wp-cli.php b/class-wp-cli.php index 290339069..1c463c5ad 100644 --- a/class-wp-cli.php +++ b/class-wp-cli.php @@ -115,23 +115,6 @@ static function parse_args( $arguments ) { return array( $regular_args, $assoc_args ); } - /** - * Display the help function for the wp-cli - * - * @return void - */ - static function generalHelp() { - self::line('Example usage:'); - foreach(self::$commands as $name => $command) { - self::out(' wp '.$name); - $methods = WP_CLI_Command::get_methods($command); - if(!empty($methods)) { - self::out(' ['.implode('|', $methods).']'); - } - self::line(' ...'); - } - } - /** * Display a legend * diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 89e676150..8cfc085c0 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -103,6 +103,7 @@ public function help( $args = array() ) { WP_CLI::out( <<] + EOB ); } diff --git a/commands/internals/help.php b/commands/internals/help.php new file mode 100644 index 000000000..547f86744 --- /dev/null +++ b/commands/internals/help.php @@ -0,0 +1,49 @@ +generalHelp(); + } else { + $command = $args[0]; + if ( 'help' == $command || !isset( WP_CLI::$commands[$command] ) ) { + $this->generalHelp(); + } else { + new WP_CLI::$commands[$command]( $command, array( 'help' ), array() ); + } + } + } + + private function generalHelp() { + WP_CLI::line('Example usage:'); + foreach ( WP_CLI::$commands as $name => $command ) { + if ( 'help' == $name ) + continue; + + WP_CLI::out( ' wp ' . $name ); + $methods = WP_CLI_Command::get_methods( $command ); + if( !empty( $methods ) ) { + WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); + } + WP_CLI::line(' ...'); + } + WP_CLI::line(' wp --version'); + WP_CLI::line(); + WP_CLI::line( "See 'wp help ' for more information on a specific command." ); + } +} diff --git a/wp-cli.php b/wp-cli.php index 241d08e93..f188f5f80 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -94,8 +94,8 @@ $command = array_shift( $arguments ); if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::generalHelp(); - exit(); + WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + exit; } new WP_CLI::$commands[$command]( $command, $arguments, $assoc_args ); From b60273e6a39bed830d88e9b32a407a0b341e7ecd Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 06:02:44 +0300 Subject: [PATCH 0097/5359] default to 'help' command again when no arguments are passed --- wp-cli.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wp-cli.php b/wp-cli.php index f188f5f80..4cf9cb71d 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -91,7 +91,10 @@ } // Get the top-level command -$command = array_shift( $arguments ); +if ( empty( $arguments ) ) + $command = 'help'; +else + $command = array_shift( $arguments ); if ( !isset( WP_CLI::$commands[$command] ) ) { WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); From 5d2676d83372948309fc7dafdc60b7a2a0eb3a4c Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 06:07:52 +0300 Subject: [PATCH 0098/5359] move bash scripts to bin directory --- README.md | 4 ++-- wp => bin/wp | 8 ++++---- wp-cli-completion.bash => bin/wp-cli-completion.bash | 0 3 files changed, 6 insertions(+), 6 deletions(-) rename wp => bin/wp (96%) rename wp-cli-completion.bash => bin/wp-cli-completion.bash (100%) mode change 100644 => 100755 diff --git a/README.md b/README.md index 680af9b74..e2e148c1a 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ git submodule update --init Make a symlink to the executable: ``` -sudo ln -s /path-to-wp-cli-dir/wp /usr/local/bin/ +sudo ln -s /path-to-wp-cli-dir/bin/wp /usr/local/bin/ ``` Make a symlink to the autocomplete file (Linux): ``` -sudo ln -s /path-to-wp-cli-dir/wp-cli-completion.bash /etc/bash_completion.d/wp +sudo ln -s /path-to-wp-cli-dir/bin/wp-cli-completion.bash /etc/bash_completion.d/wp ``` Usage diff --git a/wp b/bin/wp similarity index 96% rename from wp rename to bin/wp index b8336b6da..dd4fd48d9 100755 --- a/wp +++ b/bin/wp @@ -1,13 +1,13 @@ #!/usr/bin/env sh # -# This script has been adapted from the drush wrapper script +# This script has been adapted from the drush wrapper script # and 99.9% of all credit should go to the authors of that project: # http://drupal.org/project/drush # And 0.09% to the author of this project: # https://github.com/88mph/wpadmin/blob/master/wpadmin.php -# +# # This is a wrapper script that will run wp-cli.php with the most appropriate -# php executable it can find on your system. +# php executable it can find on your system. # # Set the required PHP version @@ -30,7 +30,7 @@ done cd "$ORIGDIR" # Build the path to wp-cli.php. -SCRIPT_PATH=$(dirname "$SELF_PATH")/wp-cli.php +SCRIPT_PATH=$(dirname "$SELF_PATH")/../wp-cli.php case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; diff --git a/wp-cli-completion.bash b/bin/wp-cli-completion.bash old mode 100644 new mode 100755 similarity index 100% rename from wp-cli-completion.bash rename to bin/wp-cli-completion.bash From ed8e6f198f2c041972b302128ce18c355f2d459b Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 06:28:58 +0300 Subject: [PATCH 0099/5359] don't need #!bash in completion script --- bin/wp-cli-completion.bash | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) mode change 100755 => 100644 bin/wp-cli-completion.bash diff --git a/bin/wp-cli-completion.bash b/bin/wp-cli-completion.bash old mode 100755 new mode 100644 index 39ec5b649..2e7e42025 --- a/bin/wp-cli-completion.bash +++ b/bin/wp-cli-completion.bash @@ -1,7 +1,5 @@ -#!bash -# -# bash completion support for the wp command -# +# bash completion for the wp command + _wp() { local cur prev opts From 30e51c29cfef3688faddf9ccc7673d41eeccb4f6 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 07:38:13 +0300 Subject: [PATCH 0100/5359] add build-deb bash script --- bin/build-deb | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 bin/build-deb diff --git a/bin/build-deb b/bin/build-deb new file mode 100755 index 000000000..047082958 --- /dev/null +++ b/bin/build-deb @@ -0,0 +1,72 @@ +#!/bin/bash + +# script for generating a .deb file + +SOURCE_DIR=$(pwd) + +ROOT_DIR='usr/share/php/wp-cli' + +rm -rf /tmp/wp-cli + +mkdir -p /tmp/wp-cli/DEBIAN + +cd /tmp/wp-cli + +mkdir -p $ROOT_DIR + +rsync -r --exclude='*.git*' $SOURCE_DIR/* $ROOT_DIR/ + +# remove junk files +find . -name "*~" -exec rm {} \; +find . -name "*.swp" -exec rm {} \; + +# reset permsissions and ownership +chown -R root . +chgrp -R root . +find . -type f -exec chmod 644 {} \; +find . -type d -exec chmod 755 {} \; + +# use a simple bash wrapper for the command, since we know where everything is +mkdir -p usr/bin + +cat > usr/bin/wp < DEBIAN/control <= 5.3) +Installed-Size: 150 +Maintainer: Cristi Burca +Description: WordPress command-line interface + A tool for controlling WordPress installations via the command-line. +EOT + +cat > DEBIAN/postinst < DEBIAN/postinst < Date: Fri, 7 Oct 2011 07:42:50 +0300 Subject: [PATCH 0101/5359] add link to .deb download. see #7 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e2e148c1a..c2d64e1bf 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ A tool to control WordPress installations from the command line. Installing ---------- +If you're on Ubuntu or Debian, just use the [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) + Clone the project: ``` From 678a05368b0903a38743b26034c32cb727ea2362 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Fri, 7 Oct 2011 10:35:21 +0200 Subject: [PATCH 0102/5359] Pushed to version 0.2 --- bin/build-deb | 2 +- wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-deb b/bin/build-deb index 047082958..4a0a53830 100755 --- a/bin/build-deb +++ b/bin/build-deb @@ -43,7 +43,7 @@ mv $ROOT_DIR/LICENSE usr/share/doc/wp-cli/copyright cat > DEBIAN/control < Date: Fri, 7 Oct 2011 15:00:16 +0100 Subject: [PATCH 0103/5359] Removed deprecated description function. --- commands/community/google-sitemap-generator.php | 6 +----- commands/community/w3-total-cache.php | 6 +----- commands/community/wp-super-cache.php | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index c5d7dbaa4..4485fadb1 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -14,10 +14,6 @@ */ class GoogleSitemapGeneratorCommand extends WP_CLI_Command { - public static function get_description() { - return 'Generate Google Sitemaps.'; - } - /** * Re-generate the sitemap * @@ -37,7 +33,7 @@ function rebuild( $args = array(), $vars = array() ) { */ public function help($args = array()) { // Shot the command description - WP_CLI::line( $this->get_description() ); + WP_CLI::line( 'Generate Google Sitemaps.' ); WP_CLI::line(); // Show the list of sub-commands for this command diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index 98d0fcca1..a0c7913f4 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -14,10 +14,6 @@ */ class W3TotalCacheCommand extends WP_CLI_Command { - public static function get_description() { - return 'Manage the W3 Total Cache.'; - } - /** * Clear something from the cache * @@ -91,7 +87,7 @@ function flush( $args = array(), $vars = array() ) { */ public function help($args = array()) { // Shot the command description - WP_CLI::line( $this->get_description() ); + WP_CLI::line( 'Manage the W3 Total Cache.' ); WP_CLI::line(); // Show the list of sub-commands for this command diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index c78238698..08cc90fc0 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -14,10 +14,6 @@ */ class WPSuperCacheCommand extends WP_CLI_Command { - public static function get_description() { - return 'Manage the WP Super Cache.'; - } - /** * Clear something from the cache * @@ -133,7 +129,7 @@ function disable( $args = array(), $vars = array() ) { */ public function help($args = array()) { // Shot the command description - WP_CLI::line( $this->get_description() ); + WP_CLI::line( 'Manage the WP Super Cache.' ); WP_CLI::line(); // Show the list of sub-commands for this command From 6569531912a3b451b602e7ac7937a5982ef58e53 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 7 Oct 2011 15:31:21 +0100 Subject: [PATCH 0104/5359] Reformed documentation. --- commands/community/w3-total-cache.php | 38 ++++++++----------------- commands/community/wp-super-cache.php | 41 +++++++-------------------- 2 files changed, 23 insertions(+), 56 deletions(-) diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index a38c528e6..8d6da3bc9 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -86,32 +86,18 @@ function flush( $args = array(), $vars = array() ) { * @return void */ public function help($args = array()) { - // Shot the command description - WP_CLI::line( 'Manage the W3 Total Cache.' ); - WP_CLI::line(); + // Show the command description + WP_CLI::out( <<] [--permalink=] - // Show the list of sub-commands for this command - WP_CLI::line('Example usage:'); - WP_CLI::line(' wp total-cache flush [post|database|minify|object] [--post_id=] [--permalink=]'); - WP_CLI::line(); - WP_CLI::line('%9--- DETAILS ---%n'); - WP_CLI::line(); - WP_CLI::line('Remove all post/page caches:'); - WP_CLI::line(' wp total-cache flush'); - WP_CLI::line(); - WP_CLI::line('Remove the caches for one blog post based on the id:'); - WP_CLI::line(' wp total-cache flush --post_id=1'); - WP_CLI::line(); - WP_CLI::line('Remove the caches for one blog post based on the permalink:'); - WP_CLI::line(' wp total-cache flush --permalink=http://example.com'); - WP_CLI::line(); - WP_CLI::line('Remove the database cache:'); - WP_CLI::line(' wp total-cache flush database'); - WP_CLI::line(); - WP_CLI::line('Remove the object cache:'); - WP_CLI::line(' wp total-cache flush object'); - WP_CLI::line(); - WP_CLI::line('Remove the minify cache:'); - WP_CLI::line(' wp total-cache flush minify'); +Avaliable sub-commands: + flush Flushes whole cache + --post_id= Flush specific ID + --permalink= Flush specific permalink + database Flushes database cache + object Flush object cache + minify Flush minify cache +EOB + ); } } diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 1369a849a..4a664c7e0 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -128,35 +128,16 @@ function disable( $args = array(), $vars = array() ) { * @return void */ public function help($args = array()) { - // Shot the command description - WP_CLI::line( 'Manage the WP Super Cache.' ); - WP_CLI::line(); + // Show the command description + WP_CLI::out( << - // Show the list of sub-commands for this command - WP_CLI::line('Example usage:'); - WP_CLI::line(' wp wp-super-cache flush [--post_id=] [--permalink=]'); - WP_CLI::line(' wp wp-super-cache status'); - WP_CLI::line(' wp wp-super-cache enable'); - WP_CLI::line(' wp wp-super-cache disable'); - WP_CLI::line(); - WP_CLI::line('%9--- DETAILS ---%n'); - WP_CLI::line(); - WP_CLI::line('Remove the whole cache content:'); - WP_CLI::line(' wp wp-super-cache flush'); - WP_CLI::line(); - WP_CLI::line('Remove the caches for one blog post based on the id:'); - WP_CLI::line(' wp wp-super-cache flush --post_id=1'); - WP_CLI::line(); - WP_CLI::line('Remove the caches for one blog post based on the permalink:'); - WP_CLI::line(' wp wp-super-cache flush --permalink=http://example.com'); - WP_CLI::line(); - WP_CLI::line('Get details on the WP Super Cache content:'); - WP_CLI::line(' wp wp-super-cache status'); - WP_CLI::line(); - WP_CLI::line('Enable the WP Super Cache:'); - WP_CLI::line(' wp wp-super-cache enable'); - WP_CLI::line(); - WP_CLI::line('Disable the WP Super Cache:'); - WP_CLI::line(' wp wp-super-cache disable'); - } +Avaliable sub-commands: + flush Flushes whole cache, or post with given permalink or ID --post_id= --permalink= + status shows status of WP Super Cache + enable enables WP Super Cache + disable Disables WP Super Cache +EOB + ); + } } From 474c2990329a82cf4977e2c8ca3ef5fcc1e6d9d8 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 7 Oct 2011 15:32:26 +0100 Subject: [PATCH 0105/5359] Added additional details. --- commands/community/wp-super-cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 4a664c7e0..ae60e0c9d 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -130,7 +130,7 @@ function disable( $args = array(), $vars = array() ) { public function help($args = array()) { // Show the command description WP_CLI::out( << +usage: wp super-cache [flush|status|enable|disable] --post_id= --permalink= Avaliable sub-commands: flush Flushes whole cache, or post with given permalink or ID --post_id= --permalink= From 5f7dcff4b5cb95b12fb07d3b1ca3a3b05c2131fd Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 7 Oct 2011 15:35:52 +0100 Subject: [PATCH 0106/5359] Reformatted help command. --- .../community/google-sitemap-generator.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index 2df220283..b75966434 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -32,17 +32,13 @@ function rebuild( $args = array(), $vars = array() ) { * @return void */ public function help($args = array()) { - // Shot the command description - WP_CLI::line( 'Generate Google Sitemaps.' ); - WP_CLI::line(); + // Show the command description + WP_CLI::out( << Date: Fri, 7 Oct 2011 15:38:37 +0100 Subject: [PATCH 0107/5359] Consistency of capitalisation. --- commands/community/google-sitemap-generator.php | 2 +- commands/community/w3-total-cache.php | 12 ++++++------ commands/community/wp-super-cache.php | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index b75966434..80ac37e3d 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -37,7 +37,7 @@ public function help($args = array()) { usage: wp google-sitemap [rebuild] Avaliable sub-commands: - rebuild Rebuild Google sitemap + rebuild rebuild Google sitemap EOB ); } diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index 8d6da3bc9..c7d4a48e7 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -91,12 +91,12 @@ public function help($args = array()) { usage: wp total-cache flush [post|database|minify|object] [--post_id=] [--permalink=] Avaliable sub-commands: - flush Flushes whole cache - --post_id= Flush specific ID - --permalink= Flush specific permalink - database Flushes database cache - object Flush object cache - minify Flush minify cache + flush flushes whole cache + --post_id= flush specific ID + --permalink= flush specific permalink + database flushes database cache + object flush object cache + minify flush minify cache EOB ); } diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index ae60e0c9d..ac780064c 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -133,10 +133,10 @@ public function help($args = array()) { usage: wp super-cache [flush|status|enable|disable] --post_id= --permalink= Avaliable sub-commands: - flush Flushes whole cache, or post with given permalink or ID --post_id= --permalink= + flush flushes whole cache, or post with given permalink or ID --post_id= --permalink= status shows status of WP Super Cache enable enables WP Super Cache - disable Disables WP Super Cache + disable disables WP Super Cache EOB ); } From fffda6326c33c4ff592d11050adf82745b2a2c7e Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 19:40:16 +0300 Subject: [PATCH 0108/5359] don't even look for get_description() anymore --- class-wp-cli-command.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 4ec9adae5..e1ea58a37 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -51,23 +51,17 @@ protected function dispatch( $args, $assoc_args ) { } /** - * General help function for this command + * General help function for the current command * * @param array $args - * @param string $assoc_args * @return void */ - public function help( $args = array(), $assoc_args = array() ) { - if ( method_exists( $this, 'get_description' ) ) { - WP_CLI::line( $this->get_description() ); - WP_CLI::line(); - } - + public function help( $args = array() ) { // Show the list of sub-commands for this command WP_CLI::line( 'Example usage:' ); WP_CLI::out( ' wp '.$this->command ); - $methods = WP_CLI_Command::get_methods($this); + $methods = self::get_methods($this); if ( !empty( $methods ) ) { WP_CLI::out(' ['.implode('|', $methods).']'); } From 59cad8224925c7bf87a4349be7618aeae7761aa6 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 19:42:46 +0300 Subject: [PATCH 0109/5359] rename get_methods() to get_subcommands() --- class-wp-cli-command.php | 6 +++--- commands/internals/help.php | 2 +- wp-cli.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index e1ea58a37..ada3571dc 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -61,7 +61,7 @@ public function help( $args = array() ) { WP_CLI::line( 'Example usage:' ); WP_CLI::out( ' wp '.$this->command ); - $methods = self::get_methods($this); + $methods = self::get_subcommands($this); if ( !empty( $methods ) ) { WP_CLI::out(' ['.implode('|', $methods).']'); } @@ -70,12 +70,12 @@ public function help( $args = array() ) { } /** - * Get the filtered list of methods for a class. + * Get the list of subcommands for a class. * * @param string $class * @return array The list of methods */ - static function get_methods($class) { + static function get_subcommands($class) { $reflection = new ReflectionClass( $class ); $methods = array(); diff --git a/commands/internals/help.php b/commands/internals/help.php index 547f86744..dda5cc805 100644 --- a/commands/internals/help.php +++ b/commands/internals/help.php @@ -36,7 +36,7 @@ private function generalHelp() { continue; WP_CLI::out( ' wp ' . $name ); - $methods = WP_CLI_Command::get_methods( $command ); + $methods = WP_CLI_Command::get_subcommands( $command ); if( !empty( $methods ) ) { WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); } diff --git a/wp-cli.php b/wp-cli.php index 5d24c4cb0..4922200bd 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -85,7 +85,7 @@ // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { foreach ( WP_CLI::$commands as $name => $command ) { - WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_methods($command) ) ); + WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_subcommands($command) ) ); } exit; } From 5d1af832430d5949f87813814b08463929c0c2d2 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 19:48:06 +0300 Subject: [PATCH 0110/5359] fix some comments --- class-wp-cli-command.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index ada3571dc..93d754b2c 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -16,7 +16,7 @@ abstract class WP_CLI_Command { protected $command; /** - * Construct for this class, transfers the cli arguments to the right class + * Constructor * * @param string $command * @param array $args @@ -35,19 +35,18 @@ function __construct( $command, $args, $assoc_args ) { * @param array $assoc_args */ protected function dispatch( $args, $assoc_args ) { - // The first command is the sub command - $sub_command = array_shift($args); + $sub_command = array_shift( $args ); - if ( !method_exists($this, $sub_command) ) { + if ( !method_exists( $this, $sub_command ) ) { // This if for reserved keywords in php (like list, isset) $sub_command = '_'.$sub_command; } - if ( !method_exists($this, $sub_command) || isset( $assoc_args[ 'help' ] ) ) { + if ( !method_exists( $this, $sub_command ) || isset( $assoc_args[ 'help' ] ) ) { $sub_command = 'help'; } - $this->$sub_command($args, $assoc_args); + $this->$sub_command( $args, $assoc_args ); } /** From 9023fc1bf1269979e9ac17e2bd7a2d21091ba86c Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 19:53:11 +0300 Subject: [PATCH 0111/5359] fix help method for the command --- commands/internals/core.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/commands/internals/core.php b/commands/internals/core.php index d1af5d6b3..3abffb873 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -50,10 +50,12 @@ function update($args) { * @return void */ public function help( $args = array() ) { - WP_CLI::line( 'usage: wp core update' ); + WP_CLI::out( << 'update the WordPress core files from wordpress.org', - ) ); +Update the WordPress core files from wordpress.org + +EOB + ); } } From 2a4efd68736cbcbce1423bf15ec3357266507d16 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 19:58:17 +0300 Subject: [PATCH 0112/5359] use WP_CLI::line() instead of WP_CLI::out() for help commands --- .../community/google-sitemap-generator.php | 9 +++---- commands/community/w3-total-cache.php | 27 +++++++++---------- commands/community/wp-super-cache.php | 27 +++++++++---------- commands/internals/core.php | 3 +-- commands/internals/generate.php | 3 +-- commands/internals/home.php | 3 +-- commands/internals/option.php | 3 +-- commands/internals/plugin.php | 3 +-- commands/internals/theme.php | 3 +-- 9 files changed, 36 insertions(+), 45 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index 80ac37e3d..494cd5e01 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -32,13 +32,12 @@ function rebuild( $args = array(), $vars = array() ) { * @return void */ public function help($args = array()) { - // Show the command description - WP_CLI::out( <<] [--permalink=] -Avaliable sub-commands: - flush flushes whole cache - --post_id= flush specific ID - --permalink= flush specific permalink - database flushes database cache - object flush object cache - minify flush minify cache +Available sub-commands: + flush flushes whole cache + --post_id= flush specific ID + --permalink= flush specific permalink + database flushes database cache + object flush object cache + minify flush minify cache EOB - ); + ); } } diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index ac780064c..64e77f942 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -29,12 +29,12 @@ function flush( $args = array(), $vars = array() ) { } else { WP_CLI::error('This is not a valid post id.'); } - + wp_cache_post_change( $vars['post_id'] ); } elseif ( isset( $vars['permalink'] ) ) { $id = url_to_postid( $vars['permalink'] ); - + if ( is_numeric( $id ) ) { wp_cache_post_change( $id ); } else { @@ -47,7 +47,7 @@ function flush( $args = array(), $vars = array() ) { WP_CLI::error('The WP Super Cache could not be found, is it installed?'); } } - + /** * Get the status of the cache * @@ -57,7 +57,7 @@ function flush( $args = array(), $vars = array() ) { */ function status( $args = array(), $vars = array() ) { $cache_stats = get_option( 'supercache_stats' ); - + if ( !empty( $cache_stats ) ) { if ( $cache_stats['generated'] > time() - 3600 * 24 ) { global $super_cache_enabled; @@ -78,7 +78,7 @@ function status( $args = array(), $vars = array() ) { WP_CLI::error('No WP Super Cache stats found.'); } } - + /** * Enable the WP Super Cache * @@ -99,7 +99,7 @@ function enable( $args = array(), $vars = array() ) { WP_CLI::error('The WP Super Cache could not be found, is it installed?'); } } - + /** * Disable the WP Super Cache * @@ -128,16 +128,15 @@ function disable( $args = array(), $vars = array() ) { * @return void */ public function help($args = array()) { - // Show the command description - WP_CLI::out( << --permalink= -Avaliable sub-commands: - flush flushes whole cache, or post with given permalink or ID --post_id= --permalink= - status shows status of WP Super Cache - enable enables WP Super Cache - disable disables WP Super Cache +Available sub-commands: + flush flushes whole cache, or post with given permalink or ID --post_id= --permalink= + status shows status of WP Super Cache + enable enables WP Super Cache + disable disables WP Super Cache EOB - ); + ); } } diff --git a/commands/internals/core.php b/commands/internals/core.php index 3abffb873..2febca34a 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -50,11 +50,10 @@ function update($args) { * @return void */ public function help( $args = array() ) { - WP_CLI::out( <<] - EOB ); } diff --git a/commands/internals/home.php b/commands/internals/home.php index 6bab53e12..a226fe608 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -50,11 +50,10 @@ protected function dispatch( $args, $assoc_args ) { * @return void */ public function help($args = array()) { - WP_CLI::out( << or: wp option add or: wp option update or: wp option delete - EOB ); } diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index fe800e2dc..e426799cc 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -322,7 +322,7 @@ private function parse_name( $args, $sub_command, $exit = true ) { * @return void */ public function help( $args = array() ) { - WP_CLI::out( << [] Available sub-commands: @@ -333,7 +333,6 @@ public function help( $args = array() ) { install install a plugin from wordpress.org update update a plugin from wordpress.org delete delete a plugin - EOB ); } diff --git a/commands/internals/theme.php b/commands/internals/theme.php index ed8373cce..e2f1af9b4 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -126,13 +126,12 @@ protected function get_stylesheet_path( $theme ) { * @return void */ public function help($args = array()) { - WP_CLI::out( << [] Available sub-commands: status display status of all installed themes or of a particular theme activate activate a particular theme - EOB ); } From 48a8887d46be25e0c0ad326975729ec816c17331 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 7 Oct 2011 20:42:50 +0300 Subject: [PATCH 0113/5359] make help method static; revert to __construct() instead of dispatch() --- class-wp-cli-command.php | 45 ++----------------- .../community/google-sitemap-generator.php | 5 +-- commands/community/w3-total-cache.php | 5 +-- commands/community/wp-super-cache.php | 5 +-- commands/internals/core.php | 5 +-- commands/internals/generate.php | 5 +-- commands/internals/help.php | 33 +++++++++----- commands/internals/home.php | 13 +++--- commands/internals/option.php | 5 +-- commands/internals/plugin.php | 5 +-- commands/internals/theme.php | 5 +-- wp-cli.php | 2 +- 12 files changed, 39 insertions(+), 94 deletions(-) diff --git a/class-wp-cli-command.php b/class-wp-cli-command.php index 93d754b2c..b86d8ec39 100644 --- a/class-wp-cli-command.php +++ b/class-wp-cli-command.php @@ -8,33 +8,13 @@ */ abstract class WP_CLI_Command { - /** - * Keeps a reference to the current command name - * - * @param string - */ - protected $command; - - /** - * Constructor - * - * @param string $command - * @param array $args - * @param array $assoc_args - */ - function __construct( $command, $args, $assoc_args ) { - $this->command = $command; - - $this->dispatch( $args, $assoc_args ); - } - /** * Transfers the handling to the appropriate method * * @param array $args * @param array $assoc_args */ - protected function dispatch( $args, $assoc_args ) { + public function __construct( $args, $assoc_args ) { $sub_command = array_shift( $args ); if ( !method_exists( $this, $sub_command ) ) { @@ -49,38 +29,19 @@ protected function dispatch( $args, $assoc_args ) { $this->$sub_command( $args, $assoc_args ); } - /** - * General help function for the current command - * - * @param array $args - * @return void - */ - public function help( $args = array() ) { - // Show the list of sub-commands for this command - WP_CLI::line( 'Example usage:' ); - WP_CLI::out( ' wp '.$this->command ); - - $methods = self::get_subcommands($this); - if ( !empty( $methods ) ) { - WP_CLI::out(' ['.implode('|', $methods).']'); - } - WP_CLI::line(' ...'); - WP_CLI::line(); - } - /** * Get the list of subcommands for a class. * * @param string $class * @return array The list of methods */ - static function get_subcommands($class) { + static function get_subcommands( $class ) { $reflection = new ReflectionClass( $class ); $methods = array(); foreach ( $reflection->getMethods() as $method ) { - if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() && 'help' != $method->name ) { + if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { $name = $method->name; if ( strpos( $name, '_' ) === 0 ) { diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index 494cd5e01..a5a1d3303 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -27,11 +27,8 @@ function rebuild( $args = array(), $vars = array() ) { /** * Help function for this command - * - * @param array $args - * @return void */ - public function help($args = array()) { + public static function help() { WP_CLI::line( <<] [--permalink=] diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 64e77f942..231e4de8a 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -123,11 +123,8 @@ function disable( $args = array(), $vars = array() ) { /** * Help function for this command - * - * @param array $args - * @return void */ - public function help($args = array()) { + public static function help() { WP_CLI::line( << --permalink= diff --git a/commands/internals/core.php b/commands/internals/core.php index 2febca34a..319266bec 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -45,11 +45,8 @@ function update($args) { /** * Help function for this command - * - * @param array $args - * @return void */ - public function help( $args = array() ) { + public static function help() { WP_CLI::line( <<] diff --git a/commands/internals/help.php b/commands/internals/help.php index dda5cc805..fab8542d7 100644 --- a/commands/internals/help.php +++ b/commands/internals/help.php @@ -12,38 +12,49 @@ class HelpCommand extends WP_CLI_Command { /** - * Overwrite the dispatch method to have a command without sub-commands. + * Overwrite the constructor to have a command without sub-commands. * * @param array $args */ - protected function dispatch( $args ) { + public function __construct( $args ) { if ( empty( $args ) ) { - $this->generalHelp(); + $this->general_help(); } else { $command = $args[0]; if ( 'help' == $command || !isset( WP_CLI::$commands[$command] ) ) { $this->generalHelp(); } else { - new WP_CLI::$commands[$command]( $command, array( 'help' ), array() ); + $class = WP_CLI::$commands[$command]; + + if ( method_exists( $class, 'help' ) ) { + $class::help(); + } else { + WP_CLI::line( 'Example usage:' ); + $this->single_command_help( $command, $class ); + } } } } - private function generalHelp() { + private function general_help() { WP_CLI::line('Example usage:'); foreach ( WP_CLI::$commands as $name => $command ) { if ( 'help' == $name ) continue; - WP_CLI::out( ' wp ' . $name ); - $methods = WP_CLI_Command::get_subcommands( $command ); - if( !empty( $methods ) ) { - WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); - } - WP_CLI::line(' ...'); + $this->single_command_help( $name, $command ); } WP_CLI::line(' wp --version'); WP_CLI::line(); WP_CLI::line( "See 'wp help ' for more information on a specific command." ); } + + private function single_command_help( $name, $command ) { + WP_CLI::out( ' wp ' . $name ); + $methods = WP_CLI_Command::get_subcommands( $command ); + if ( !empty( $methods ) ) { + WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); + } + WP_CLI::line(' ...'); + } } diff --git a/commands/internals/home.php b/commands/internals/home.php index a226fe608..14e4e1734 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -13,12 +13,12 @@ class HomeCommand extends WP_CLI_Command { /** - * Overwrite the dispatch method to have a command without sub-commands. + * Overwrite the constructor to have a command without sub-commands. * * @param array $args * @param array $assoc_args */ - protected function dispatch( $args, $assoc_args ) { + public function __construct( $args, $assoc_args ) { if(empty($args)) { // The url for the wp-cli repository $repository_url = 'http://github.com/andreascreten/wp-cli'; @@ -39,17 +39,14 @@ protected function dispatch( $args, $assoc_args ) { } else { // Call the parent constructor - parent::dispatch( $args, $assoc_args ); + parent::__construct( $args, $assoc_args ); } } /** - * Help function for this command. - * - * @param array $args - * @return void + * Help function for this command */ - public function help($args = array()) { + public static function help() { WP_CLI::line( << or: wp option add diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index e426799cc..f27ffb861 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -317,11 +317,8 @@ private function parse_name( $args, $sub_command, $exit = true ) { /** * Help function for this command - * - * @param array $args - * @return void */ - public function help( $args = array() ) { + public static function help() { WP_CLI::line( << [] diff --git a/commands/internals/theme.php b/commands/internals/theme.php index e2f1af9b4..bd9a38ebe 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -121,11 +121,8 @@ protected function get_stylesheet_path( $theme ) { /** * Help function for this command - * - * @param array $args - * @return void */ - public function help($args = array()) { + public static function help() { WP_CLI::line( << [] diff --git a/wp-cli.php b/wp-cli.php index 4922200bd..a597bc0b8 100755 --- a/wp-cli.php +++ b/wp-cli.php @@ -101,5 +101,5 @@ exit; } -new WP_CLI::$commands[$command]( $command, $arguments, $assoc_args ); +new WP_CLI::$commands[$command]( $arguments, $assoc_args ); From af3fbcea29e7ad4a2306e21ea27df15243df4848 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 03:30:24 +0300 Subject: [PATCH 0114/5359] move php files to a 'core' dir and build-deb to a 'utils' dir. see #7 --- bin/wp | 2 +- bin/{wp-cli-completion.bash => wp-completion.bash} | 0 class-wp-cli-command.php => core/class-wp-cli-command.php | 0 class-wp-cli.php => core/class-wp-cli.php | 0 wp-cli.php => core/wp-cli.php | 6 +++--- {bin => utils}/build-deb | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename bin/{wp-cli-completion.bash => wp-completion.bash} (100%) rename class-wp-cli-command.php => core/class-wp-cli-command.php (100%) rename class-wp-cli.php => core/class-wp-cli.php (100%) rename wp-cli.php => core/wp-cli.php (94%) rename {bin => utils}/build-deb (100%) diff --git a/bin/wp b/bin/wp index dd4fd48d9..9c0894e5c 100755 --- a/bin/wp +++ b/bin/wp @@ -30,7 +30,7 @@ done cd "$ORIGDIR" # Build the path to wp-cli.php. -SCRIPT_PATH=$(dirname "$SELF_PATH")/../wp-cli.php +SCRIPT_PATH=$(dirname "$SELF_PATH")/../core/wp-cli.php case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; diff --git a/bin/wp-cli-completion.bash b/bin/wp-completion.bash similarity index 100% rename from bin/wp-cli-completion.bash rename to bin/wp-completion.bash diff --git a/class-wp-cli-command.php b/core/class-wp-cli-command.php similarity index 100% rename from class-wp-cli-command.php rename to core/class-wp-cli-command.php diff --git a/class-wp-cli.php b/core/class-wp-cli.php similarity index 100% rename from class-wp-cli.php rename to core/class-wp-cli.php diff --git a/wp-cli.php b/core/wp-cli.php similarity index 94% rename from wp-cli.php rename to core/wp-cli.php index a597bc0b8..f0ae07d24 100755 --- a/wp-cli.php +++ b/core/wp-cli.php @@ -8,14 +8,14 @@ define( 'WP_CLI_VERSION', '0.2' ); // Define the wp-cli location -define('WP_CLI_ROOT', __DIR__ . '/'); +define( 'WP_CLI_ROOT', realpath( __DIR__ . '/..' ) . '/' ); // Set a constant that can be used to check if we are running wp-cli or not define('WP_CLI', true); // Include the wp-cli classes -include WP_CLI_ROOT.'class-wp-cli.php'; -include WP_CLI_ROOT.'class-wp-cli-command.php'; +include WP_CLI_ROOT.'core/class-wp-cli.php'; +include WP_CLI_ROOT.'core/class-wp-cli-command.php'; // Include the command line tools include WP_CLI_ROOT.'php-cli-tools/lib/cli/cli.php'; diff --git a/bin/build-deb b/utils/build-deb similarity index 100% rename from bin/build-deb rename to utils/build-deb From 77ea557ddc25814eb54c33ec6fda3f8375fa62ce Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 03:33:01 +0300 Subject: [PATCH 0115/5359] remove .gitignore; use your personal .gitignore file for excluding temporary files --- .gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c1468184d..000000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -php-cli-tools/ \ No newline at end of file From 78738a02596c0fe6f108d609d4765638f0ad794b Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 04:43:25 +0300 Subject: [PATCH 0116/5359] update build-deb; change wp-cli version to '0.2-alpha'. see #7 --- core/wp-cli.php | 11 +++++------ utils/build-deb | 50 ++++++++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/core/wp-cli.php b/core/wp-cli.php index f0ae07d24..9fb6888ac 100755 --- a/core/wp-cli.php +++ b/core/wp-cli.php @@ -1,11 +1,10 @@ -#!/usr/bin/env php usr/bin/wp < DEBIAN/control < DEBIAN/postinst < DEBIAN/postinst < Date: Sun, 9 Oct 2011 04:48:36 +0300 Subject: [PATCH 0117/5359] update installation instructions --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2d64e1bf..b008fffc1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,11 @@ A tool to control WordPress installations from the command line. Installing ---------- -If you're on Ubuntu or Debian, just use the [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) +**Via package manager:** + +Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) + +**From source:** Clone the project: @@ -28,7 +32,7 @@ sudo ln -s /path-to-wp-cli-dir/bin/wp /usr/local/bin/ Make a symlink to the autocomplete file (Linux): ``` -sudo ln -s /path-to-wp-cli-dir/bin/wp-cli-completion.bash /etc/bash_completion.d/wp +sudo ln -s /path-to-wp-cli-dir/bin/wp-completion.bash /etc/bash_completion.d/wp ``` Usage From f28bd2951fef413cfcd133609d9eabe9ab57fb75 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 15:58:35 +0300 Subject: [PATCH 0118/5359] plugin command fixes. closes #25 --- commands/internals/plugin.php | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index f27ffb861..9d2d4a78e 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -168,7 +168,7 @@ function toggle( $args ) { * @return void */ function install( $args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__, false ); + $name = $args[0]; // Force WordPress to update the plugin list wp_update_plugins(); @@ -193,10 +193,7 @@ function install( $args ) { $result = $upgrader->install( $api->download_link ); $feedback = ob_get_clean(); - if ( $result !== null ) { - WP_CLI::error( $result ); - } - else { + if ( $result ) { WP_CLI::line(); WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( " ...\n", '' ), html_entity_decode( $feedback ) ) ) ); WP_CLI::success( 'The plugin is successfully installed' ); @@ -207,10 +204,6 @@ function install( $args ) { break; case 'latest_installed': WP_CLI::error( 'Latest version already installed' ); - - if ( is_plugin_inactive( $file ) ) { - WP_CLI::warning( 'If you want to activate the plugin, run: %2wp plugin activate '.$name.'%n' ); - } break; } } @@ -286,7 +279,7 @@ private function get_details( $file ) { * @param bool $exit * @return array */ - private function parse_name( $args, $sub_command, $exit = true ) { + private function parse_name( $args, $sub_command ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp plugin $sub_command " ); exit; @@ -301,15 +294,13 @@ private function parse_name( $args, $sub_command, $exit = true ) { } else { $file = $name . '.php'; - $plugins = get_plugins(); - if ( !isset( $plugins[$file] ) ) { - if ( $exit ) { - WP_CLI::error( "The plugin '$name' could not be found." ); - exit(); - } - - return false; - } + } + + $plugins = get_plugins(); + + if ( !isset( $plugins[$file] ) ) { + WP_CLI::error( "The plugin '$name' could not be found." ); + exit(); } return array( $file, $name ); From 4a70fec820288c48630c41230678b4c0b292e513 Mon Sep 17 00:00:00 2001 From: Bartosz Romanowski Date: Sun, 9 Oct 2011 14:25:40 +0300 Subject: [PATCH 0119/5359] Workaround for an invalid plugin status returned from the 'install_plugin_install_status' when trying to install a non-existing plugin. --- commands/internals/plugin.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 9d2d4a78e..264e3a06f 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -179,6 +179,11 @@ function install( $args ) { WP_CLI::line( 'Installing '.$api->name.' ('.$api->version.')' ); + if ( stripslashes( $name ) != $api->slug ) { + WP_CLI::error( 'Can\'t find the plugin in the WordPress.org plugins repository.' ); + exit(); + } + // Check what to do switch ( $status['status'] ) { case 'update_available': From 5fa68d75943aacbb8907d3dd7c766f6ea16fe6dd Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 16:16:22 +0300 Subject: [PATCH 0120/5359] check for null response from plugins_api() instead of attempting to match the slug. see #26 --- commands/internals/plugin.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 264e3a06f..0f9a72283 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -175,15 +175,15 @@ function install( $args ) { // Get plugin info from the WordPress servers $api = plugins_api( 'plugin_information', array( 'slug' => stripslashes( $name ) ) ); - $status = install_plugin_install_status( $api ); - - WP_CLI::line( 'Installing '.$api->name.' ('.$api->version.')' ); - - if ( stripslashes( $name ) != $api->slug ) { + if ( !$api ) { WP_CLI::error( 'Can\'t find the plugin in the WordPress.org plugins repository.' ); exit(); } + $status = install_plugin_install_status( $api ); + + WP_CLI::line( 'Installing '.$api->name.' ('.$api->version.')' ); + // Check what to do switch ( $status['status'] ) { case 'update_available': From bb4229024ecf50f30d555888acaa77dc565f8dbd Mon Sep 17 00:00:00 2001 From: Bartosz Romanowski Date: Sun, 9 Oct 2011 14:34:02 +0300 Subject: [PATCH 0121/5359] Fixed messages formatting for plugin updates. --- commands/internals/plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 0f9a72283..3526e8bed 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -200,7 +200,7 @@ function install( $args ) { if ( $result ) { WP_CLI::line(); - WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( " ...\n", '' ), html_entity_decode( $feedback ) ) ) ); + WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( "...\n", '' ), html_entity_decode( $feedback ) ) ) ); WP_CLI::success( 'The plugin is successfully installed' ); } break; @@ -256,7 +256,7 @@ function update( $args ) { } else { WP_CLI::line(); - WP_CLI::line( html_entity_decode( strip_tags( $feedback ) ) ); + WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin updates successfully.' ), array( "...\n", '' ), html_entity_decode( $feedback ) ) ) ); WP_CLI::success( 'The plugin is successfully updated.' ); } } From 07b87f982949f100131baa03dfc5e3844ab64256 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 17:20:13 +0300 Subject: [PATCH 0122/5359] defer to github for listing contributors and their impact --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b008fffc1..cf567622a 100644 --- a/README.md +++ b/README.md @@ -164,8 +164,8 @@ if(defined('WP_CLI') && WP_CLI) { Contributors ------------ -- Andreas Creten ([@andreascreten](http://twitter.com/andreascreten)) -- Cristi Burcă ([@scribu](http://twitter.com/scribu)) +- [Contributor list](https://github.com/andreascreten/wp-cli/contributors) +- [Contributor impact](https://github.com/andreascreten/wp-cli/graphs/impact) Requirements ------------ From b8552745b66d59e2b0a2bc89bb2e32fcb1c52283 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 17:24:39 +0300 Subject: [PATCH 0123/5359] merge Requirements section into Installing --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cf567622a..e87889b79 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli **From source:** +First, make sure you have `php-cli` version 5.3 or newer installed. + Clone the project: ``` @@ -166,8 +168,3 @@ Contributors - [Contributor list](https://github.com/andreascreten/wp-cli/contributors) - [Contributor impact](https://github.com/andreascreten/wp-cli/graphs/impact) - -Requirements ------------- - - * PHP >= 5.3 From c69832bd5df0ecd168ef4d5ea9a04f1563e1e1bc Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 21:44:03 +0300 Subject: [PATCH 0124/5359] simplify HomeCommand::__construct() --- commands/internals/home.php | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/commands/internals/home.php b/commands/internals/home.php index 14e4e1734..e62514475 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -19,28 +19,22 @@ class HomeCommand extends WP_CLI_Command { * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { - if(empty($args)) { - // The url for the wp-cli repository - $repository_url = 'http://github.com/andreascreten/wp-cli'; + // The url for the wp-cli repository + $repository_url = 'http://github.com/andreascreten/wp-cli'; - // Open the wp-cli page in the browser - if(exec('which x-www-browser')) { - system('x-www-browser '.$repository_url); - } - elseif(exec('which open')) { - system('open '.$repository_url); - } - else { - WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: '.$repository_url); - return; - } - - WP_CLI::success('The wp-cli homepage should be opening in your browser.'); + // Open the wp-cli page in the browser + if(exec('which x-www-browser')) { + system('x-www-browser '.$repository_url); + } + elseif(exec('which open')) { + system('open '.$repository_url); } else { - // Call the parent constructor - parent::__construct( $args, $assoc_args ); + WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: '.$repository_url); + return; } + + WP_CLI::success('The wp-cli homepage should be opening in your browser.'); } /** From 7bba53b0ac335ea17609feff44b2a38fa5291b3a Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 21:45:51 +0300 Subject: [PATCH 0125/5359] introduce default_subcommand property. fixes #29 --- commands/internals/plugin.php | 2 ++ commands/internals/theme.php | 2 ++ core/class-wp-cli-command.php | 17 +++++++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 3526e8bed..886d4c3e8 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -14,6 +14,8 @@ */ class PluginCommand extends WP_CLI_Command { + protected $default_subcommand = 'status'; + private $mu_plugins; /** diff --git a/commands/internals/theme.php b/commands/internals/theme.php index bd9a38ebe..2c6346741 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -12,6 +12,8 @@ */ class ThemeCommand extends WP_CLI_Command { + protected $default_subcommand = 'status'; + /** * Get the status of one or all themes * diff --git a/core/class-wp-cli-command.php b/core/class-wp-cli-command.php index b86d8ec39..291b342d8 100644 --- a/core/class-wp-cli-command.php +++ b/core/class-wp-cli-command.php @@ -8,6 +8,8 @@ */ abstract class WP_CLI_Command { + protected $default_subcommand = 'help'; + /** * Transfers the handling to the appropriate method * @@ -15,18 +17,21 @@ abstract class WP_CLI_Command { * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { - $sub_command = array_shift( $args ); + if ( empty( $args ) ) + $subcommand = $this->default_subcommand; + else + $subcommand = array_shift( $args ); - if ( !method_exists( $this, $sub_command ) ) { + if ( !method_exists( $this, $subcommand ) ) { // This if for reserved keywords in php (like list, isset) - $sub_command = '_'.$sub_command; + $subcommand = '_'.$subcommand; } - if ( !method_exists( $this, $sub_command ) || isset( $assoc_args[ 'help' ] ) ) { - $sub_command = 'help'; + if ( !method_exists( $this, $subcommand ) || isset( $assoc_args[ 'help' ] ) ) { + $subcommand = 'help'; } - $this->$sub_command( $args, $assoc_args ); + $this->$subcommand( $args, $assoc_args ); } /** From c811b3d54a62e0231404c4a90cd4d845de6d5aa8 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 23:22:20 +0300 Subject: [PATCH 0126/5359] show usage when plugin install has no args. see #25 --- commands/internals/plugin.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 886d4c3e8..8814f0518 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -170,6 +170,11 @@ function toggle( $args ) { * @return void */ function install( $args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp plugin install " ); + exit; + } + $name = $args[0]; // Force WordPress to update the plugin list From 60123b03305ac4ce7cff820023f6263207da835b Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 23:24:05 +0300 Subject: [PATCH 0127/5359] s/sub_command/subcommand/g --- commands/internals/plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 8814f0518..1a7ac33f8 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -287,13 +287,13 @@ private function get_details( $file ) { * Parse the name of a plugin to a filename, check if it exists * * @param array $args - * @param string $sub_command + * @param string $subcommand * @param bool $exit * @return array */ - private function parse_name( $args, $sub_command ) { + private function parse_name( $args, $subcommand ) { if ( empty( $args ) ) { - WP_CLI::line( "usage: wp plugin $sub_command " ); + WP_CLI::line( "usage: wp plugin $subcommand " ); exit; } From dc596e0742a1a1d7ce6a5025e3009c75535f7de6 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 23:41:17 +0300 Subject: [PATCH 0128/5359] add --activate flag to `wp plugin install` command; introduce WP_CLI::compose_args(). fixes #30 --- commands/internals/plugin.php | 8 ++++++-- core/class-wp-cli.php | 22 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 1a7ac33f8..4b6ae2a6c 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -167,9 +167,9 @@ function toggle( $args ) { * Install a new plugin * * @param array $args - * @return void + * @param array $assoc_args */ - function install( $args ) { + function install( $args, $assoc_args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp plugin install " ); exit; @@ -209,6 +209,10 @@ function install( $args ) { WP_CLI::line(); WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( "...\n", '' ), html_entity_decode( $feedback ) ) ) ); WP_CLI::success( 'The plugin is successfully installed' ); + + if ( isset( $assoc_args['activate'] ) ) { + system( "wp plugin activate " . WP_CLI::compose_args( $args, $assoc_args ) ); + } } break; case 'newer_installed': diff --git a/core/class-wp-cli.php b/core/class-wp-cli.php index 1c463c5ad..6387daa5f 100644 --- a/core/class-wp-cli.php +++ b/core/class-wp-cli.php @@ -94,8 +94,9 @@ static function errorToString($errors) { } /** - * Splits regular arguments from associative arguments. + * Splits a string into positional and associative arguments. * + * @param string * @return array */ static function parse_args( $arguments ) { @@ -115,6 +116,25 @@ static function parse_args( $arguments ) { return array( $regular_args, $assoc_args ); } + /** + * Composes positional and associative arguments into a string + * + * @param array + * @return string + */ + static function compose_args( $args, $assoc_args = array() ) { + $str = implode( ' ', $args ); + + foreach ( $assoc_args as $key => $value ) { + if ( true == $value ) + $str .= " --$key"; + else + $str .= " --$key=$value"; + } + + return $str; + } + /** * Display a legend * From 28037b6086b890e5f9cafb95eb8e2679d61cde2c Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 9 Oct 2011 23:45:02 +0300 Subject: [PATCH 0129/5359] use WP_CLI::success() in wp plugin (de)activate for consistency --- commands/internals/plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 4b6ae2a6c..66627833d 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -125,7 +125,7 @@ function activate( $args ) { if ( !is_plugin_active( $file ) ) { WP_CLI::error( 'Could not activate this plugin: ' . $name ); } else { - WP_CLI::line( 'Plugin activated.' ); + WP_CLI::success( "Plugin '$name' activated." ); } } @@ -143,7 +143,7 @@ function deactivate( $args ) { if ( !is_plugin_inactive( $file ) ) { WP_CLI::error( 'Could not deactivate this plugin: '.$name ); } else { - WP_CLI::line( 'Plugin deactivated.' ); + WP_CLI::success( "Plugin '$name' deactivated." ); } } From 8ca86ddd71ee1abdec90b2a09d1560310a652ea9 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Mon, 10 Oct 2011 09:09:25 +0200 Subject: [PATCH 0130/5359] Updated the core to comply with the coding standards Also updated the README with install details for Mac. --- README.md | 2 ++ core/class-wp-cli.php | 74 +++++++++++++++++++++---------------------- core/wp-cli.php | 10 +++--- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e87889b79..b14e39060 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Installing Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) +On Mac, install [Homebrew](http://mxcl.github.com/homebrew/) and run `brew install wp-cli`. + **From source:** First, make sure you have `php-cli` version 5.3 or newer installed. diff --git a/core/class-wp-cli.php b/core/class-wp-cli.php index 6387daa5f..47a7985e8 100644 --- a/core/class-wp-cli.php +++ b/core/class-wp-cli.php @@ -16,7 +16,7 @@ class WP_CLI { * @param string $class The class to manage the command * @return void */ - public function addCommand($name, $class) { + public function addCommand( $name, $class ) { self::$commands[$name] = $class; } @@ -26,7 +26,7 @@ public function addCommand($name, $class) { * @param string $message * @return void */ - static function out($message) { + static function out( $message ) { \cli\out($message); } @@ -36,7 +36,7 @@ static function out($message) { * @param string $message * @return void */ - static function line($message = '') { + static function line( $message = '' ) { \cli\line($message); } @@ -47,8 +47,8 @@ static function line($message = '') { * @param string $label * @return void */ - static function error($message, $label = 'Error') { - \cli\line('%R'.$label.': %n'.self::errorToString($message)); + static function error( $message, $label = 'Error' ) { + \cli\line( '%R' . $label . ': %n' . self::errorToString( $message ) ); } /** @@ -58,8 +58,8 @@ static function error($message, $label = 'Error') { * @param string $label * @return void */ - static function success($message, $label = 'Success') { - \cli\line('%G'.$label.': %n'.$message); + static function success( $message, $label = 'Success' ) { + \cli\line( '%G' . $label . ': %n' . $message ); } /** @@ -69,8 +69,8 @@ static function success($message, $label = 'Success') { * @param string $label * @return void */ - static function warning($message, $label = 'Warning') { - \cli\line('%C'.$label.': %n'.$message); + static function warning( $message, $label = 'Warning' ) { + \cli\line( '%C' . $label . ': %n' . $message ); } /** @@ -79,13 +79,12 @@ static function warning($message, $label = 'Warning') { * @param mixed $errors * @return string */ - static function errorToString($errors) { - if(is_string($errors)){ + static function errorToString( $errors ) { + if( is_string( $errors ) ) { return $errors; - } - elseif(is_wp_error($errors) && $errors->get_error_code()){ - foreach($errors->get_error_messages() as $message){ - if($errors->get_error_data() ) + } elseif( is_wp_error( $errors ) && $errors->get_error_code() ) { + foreach( $errors->get_error_messages() as $message ) { + if( $errors->get_error_data() ) return $message . ' ' . $errors->get_error_data(); else return $message; @@ -141,8 +140,8 @@ static function compose_args( $args, $assoc_args = array() ) { * @param array( code => title ) $legend * @return void */ - static function legend($legend) { - $legend['%yU'] = 'Update Available'; + static function legend( $legend ) { + $legend[ '%yU' ] = 'Update Available'; $legend_line = array(); foreach ( $legend as $key => $title ) @@ -180,13 +179,13 @@ class CLI_Upgrader_Skin { var $done_header = false; var $result = false; - function __construct($args = array()) { - $defaults = array('url' => '', 'nonce' => '', 'title' => '', 'context' => false); - $this->options = wp_parse_args($args, $defaults); + function __construct( $args = array() ) { + $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); + $this->options = wp_parse_args( $args, $defaults ); } - function set_upgrader(&$upgrader) { - if(is_object($upgrader)) { + function set_upgrader( &$upgrader ) { + if( is_object( $upgrader ) ) { $this->upgrader =& $upgrader; } @@ -195,41 +194,42 @@ function set_upgrader(&$upgrader) { function add_strings() {} - function set_result($result) { + function set_result( $result ) { $this->result = $result; } - function request_filesystem_credentials($error = false) { + function request_filesystem_credentials( $error = false ) { $url = $this->options['url']; $context = $this->options['context']; - if(!empty($this->options['nonce'])) { - $url = wp_nonce_url($url, $this->options['nonce']); + if( !empty( $this->options['nonce'] ) ) { + $url = wp_nonce_url( $url, $this->options['nonce']) ; } // Possible to bring inline, Leaving as is for now. - return request_filesystem_credentials($url, '', $error, $context); + return request_filesystem_credentials( $url, '', $error, $context ); } function header() {} function footer() {} - function error($errors) { - $this->feedback(WP_CLI::errorToString($errors)); + function error( $errors ) { + $this->feedback( WP_CLI::errorToString($errors) ); } - function feedback($string) { - if(isset( $this->upgrader->strings[$string])) + function feedback( $string ) { + if(isset( $this->upgrader->strings[$string] ) ) $string = $this->upgrader->strings[$string]; - if(strpos($string, '%') !== false) { + if( strpos( $string, '%' ) !== false ) { $args = func_get_args(); - $args = array_splice($args, 1); - if(!empty($args)) { - $string = vsprintf($string, $args); + $args = array_splice( $args, 1 ); + if( !empty( $args ) ) { + $string = vsprintf( $string, $args ); } } - if(empty($string)) { + + if( empty( $string ) ) { return; } @@ -238,4 +238,4 @@ function feedback($string) { function before() {} function after() {} -} +} \ No newline at end of file diff --git a/core/wp-cli.php b/core/wp-cli.php index 9fb6888ac..438c30a1d 100755 --- a/core/wp-cli.php +++ b/core/wp-cli.php @@ -13,11 +13,13 @@ define('WP_CLI', true); // Include the wp-cli classes - include WP_CLI_ROOT.'core/class-wp-cli.php'; - include WP_CLI_ROOT.'core/class-wp-cli-command.php'; +include WP_CLI_ROOT . 'core/class-wp-cli.php'; +include WP_CLI_ROOT . 'core/class-wp-cli-command.php'; - // Include the command line tools - include WP_CLI_ROOT.'php-cli-tools/lib/cli/cli.php'; +// Include the command line tools +include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; + +// Register the cli tools autoload \cli\register_autoload(); // Get the cli arguments From 4acde50032e48417233a82bb595c4b3e9c03108f Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Mon, 10 Oct 2011 15:09:27 +0300 Subject: [PATCH 0131/5359] Edited README.md via GitHub --- README.md | 56 +++---------------------------------------------------- 1 file changed, 3 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index b14e39060..3e20deaab 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,8 @@ Installing **Via package manager:** -Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) - -On Mac, install [Homebrew](http://mxcl.github.com/homebrew/) and run `brew install wp-cli`. +* Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) +* Mac: install [Homebrew](http://mxcl.github.com/homebrew/) and run `brew install wp-cli`. **From source:** @@ -112,56 +111,7 @@ Adding commands --------------- Adding commands to wp-cli is very easy. You can even add them from within your own plugin. - -Each command has its own class, the methods of that class are the sub commands of the command. The base class for the commands is the abstract `WP_CLI_Command`, it handles some essential functionality (like default help for your command). - -You can add new commands to the `commands/community` folder in the wp-cli plugin, they will be auto-loaded on startup. You can also add commands from within your plugins by just calling the wp-cli hooks from there. - -A wp-cli class is structured like this: - -``` php - Date: Mon, 10 Oct 2011 00:42:42 +0100 Subject: [PATCH 0132/5359] Add version command --- commands/internals/version.php | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 commands/internals/version.php diff --git a/commands/internals/version.php b/commands/internals/version.php new file mode 100644 index 000000000..dc0a99eae --- /dev/null +++ b/commands/internals/version.php @@ -0,0 +1,58 @@ + + */ +class VersionCommand extends WP_CLI_Command { + + var $default_subcommand = 'core'; + + public function core( $args = array() ) { + global $wp_version; + $color = '%G'; + $version_text = $wp_version; + $version_types = array( + '-RC' => array( 'release candidate', '%y' ), + '-beta' => array( 'beta', '%B' ), + '-' => array( 'in development', '%R' ), + ); + foreach( $version_types as $needle => $type ) { + if ( stristr( $wp_version, $needle ) ) { + list( $version_text, $color ) = $type; + $version_text = "$color$wp_version%n (stability: $version_text)"; + break; + } + } + WP_CLI::line( "WordPress version:\t$version_text" ); + } + + public function extra( $args = array() ) { + global $wp_version, $wp_db_version, $tinymce_version, $manifest_version; + $this->core( $args ); + WP_CLI::line(); + WP_CLI::line( "Database revision:\t$wp_db_version" ); + + preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); + $human_readable_tiny_mce = $match? $match[1] . '.' . $match[2] : ''; + WP_CLI::line( "TinyMCE version:\t" . ( $human_readable_tiny_mce? "$human_readable_tiny_mce ($tinymce_version)" : $tinymce_version ) ); + + WP_CLI::line( "Manifest revision:\t$manifest_version" ); + } + + public static function help() { + WP_CLI::line( << + +Available sub-commands: + core WordPress core version + extra Detailed version information +EOB + ); + } +} \ No newline at end of file From 4e3979f290909b84eb6cd3573da9928adbd718d8 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 12 Oct 2011 22:18:26 +0300 Subject: [PATCH 0133/5359] replace @author with @maintainer; keep only for community commands --- commands/community/google-sitemap-generator.php | 2 +- commands/community/w3-total-cache.php | 2 +- commands/community/wp-super-cache.php | 2 +- commands/internals/core.php | 1 - commands/internals/generate.php | 1 - commands/internals/home.php | 1 - commands/internals/option.php | 1 - commands/internals/plugin.php | 1 - commands/internals/theme.php | 1 - commands/internals/version.php | 1 - core/class-wp-cli-command.php | 1 - core/class-wp-cli.php | 2 -- 12 files changed, 3 insertions(+), 13 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index a5a1d3303..c9e8eb006 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -10,7 +10,7 @@ * * @package wp-cli * @subpackage commands/community - * @author Andreas Creten + * @maintainer Andreas Creten */ class GoogleSitemapGeneratorCommand extends WP_CLI_Command { diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index 75f5b00ee..62d5ee15d 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -10,7 +10,7 @@ * * @package wp-cli * @subpackage commands/community - * @author Andreas Creten + * @maintainer Andreas Creten */ class W3TotalCacheCommand extends WP_CLI_Command { diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 231e4de8a..6751fde06 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -10,7 +10,7 @@ * * @package wp-cli * @subpackage commands/community - * @author Andreas Creten + * @maintainer Andreas Creten */ class WPSuperCacheCommand extends WP_CLI_Command { diff --git a/commands/internals/core.php b/commands/internals/core.php index 319266bec..3229eafe3 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Andreas Creten */ class CoreCommand extends WP_CLI_Command { diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 65953a6ab..4fbac253c 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Cristi Burca */ class GenerateCommand extends WP_CLI_Command { diff --git a/commands/internals/home.php b/commands/internals/home.php index e62514475..fc6b0acc1 100644 --- a/commands/internals/home.php +++ b/commands/internals/home.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Andreas Creten */ class HomeCommand extends WP_CLI_Command { diff --git a/commands/internals/option.php b/commands/internals/option.php index 491053904..a87866cba 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Andreas Creten */ class OptionCommand extends WP_CLI_Command { diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 66627833d..a8417428c 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -10,7 +10,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Andreas Creten */ class PluginCommand extends WP_CLI_Command { diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 2c6346741..74b784ddd 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Andreas Creten */ class ThemeCommand extends WP_CLI_Command { diff --git a/commands/internals/version.php b/commands/internals/version.php index dc0a99eae..29bb4383e 100644 --- a/commands/internals/version.php +++ b/commands/internals/version.php @@ -7,7 +7,6 @@ * * @package wp-cli * @subpackage commands/internals - * @author Nikolay Bachiyski */ class VersionCommand extends WP_CLI_Command { diff --git a/core/class-wp-cli-command.php b/core/class-wp-cli-command.php index 291b342d8..abbbc1616 100644 --- a/core/class-wp-cli-command.php +++ b/core/class-wp-cli-command.php @@ -4,7 +4,6 @@ * Base class for WP-CLI commands * * @package wp-cli - * @author Andreas Creten */ abstract class WP_CLI_Command { diff --git a/core/class-wp-cli.php b/core/class-wp-cli.php index 47a7985e8..2c5c3a043 100644 --- a/core/class-wp-cli.php +++ b/core/class-wp-cli.php @@ -4,7 +4,6 @@ * Wrapper class for WP-CLI * * @package wp-cli - * @author Andreas Creten */ class WP_CLI { static $commands = array(); @@ -172,7 +171,6 @@ static function get_update_status( $item, $key ) { * A Upgrader Skin for WordPress that only generates plain-text * * @package wp-cli - * @author Andreas Creten */ class CLI_Upgrader_Skin { var $upgrader; From 3eef8c0009cee8f97414d241ca01f981f72769f6 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 12 Oct 2011 22:28:04 +0300 Subject: [PATCH 0134/5359] make `version` a subcommand of `core`. see #31 --- commands/internals/core.php | 34 ++++++++++++++++++++ commands/internals/version.php | 57 ---------------------------------- 2 files changed, 34 insertions(+), 57 deletions(-) delete mode 100644 commands/internals/version.php diff --git a/commands/internals/core.php b/commands/internals/core.php index 3229eafe3..52e61cb80 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -11,6 +11,40 @@ */ class CoreCommand extends WP_CLI_Command { + /** + * Display the WordPress version. + */ + public function version( $args = array(), $assoc_args = array() ) { + global $wp_version, $wp_db_version, $tinymce_version, $manifest_version; + + $color = '%G'; + $version_text = $wp_version; + $version_types = array( + '-RC' => array( 'release candidate', '%y' ), + '-beta' => array( 'beta', '%B' ), + '-' => array( 'in development', '%R' ), + ); + foreach( $version_types as $needle => $type ) { + if ( stristr( $wp_version, $needle ) ) { + list( $version_text, $color ) = $type; + $version_text = "$color$wp_version%n (stability: $version_text)"; + break; + } + } + WP_CLI::line( "WordPress version:\t$version_text" ); + + if ( isset( $assoc_args['extra'] ) ) { + WP_CLI::line(); + WP_CLI::line( "Database revision:\t$wp_db_version" ); + + preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); + $human_readable_tiny_mce = $match? $match[1] . '.' . $match[2] : ''; + WP_CLI::line( "TinyMCE version:\t" . ( $human_readable_tiny_mce? "$human_readable_tiny_mce ($tinymce_version)" : $tinymce_version ) ); + + WP_CLI::line( "Manifest revision:\t$manifest_version" ); + } + } + /** * Update the WordPress core * diff --git a/commands/internals/version.php b/commands/internals/version.php deleted file mode 100644 index 29bb4383e..000000000 --- a/commands/internals/version.php +++ /dev/null @@ -1,57 +0,0 @@ - array( 'release candidate', '%y' ), - '-beta' => array( 'beta', '%B' ), - '-' => array( 'in development', '%R' ), - ); - foreach( $version_types as $needle => $type ) { - if ( stristr( $wp_version, $needle ) ) { - list( $version_text, $color ) = $type; - $version_text = "$color$wp_version%n (stability: $version_text)"; - break; - } - } - WP_CLI::line( "WordPress version:\t$version_text" ); - } - - public function extra( $args = array() ) { - global $wp_version, $wp_db_version, $tinymce_version, $manifest_version; - $this->core( $args ); - WP_CLI::line(); - WP_CLI::line( "Database revision:\t$wp_db_version" ); - - preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); - $human_readable_tiny_mce = $match? $match[1] . '.' . $match[2] : ''; - WP_CLI::line( "TinyMCE version:\t" . ( $human_readable_tiny_mce? "$human_readable_tiny_mce ($tinymce_version)" : $tinymce_version ) ); - - WP_CLI::line( "Manifest revision:\t$manifest_version" ); - } - - public static function help() { - WP_CLI::line( << - -Available sub-commands: - core WordPress core version - extra Detailed version information -EOB - ); - } -} \ No newline at end of file From 93797635ac67280c5caf111a12fa18ed5b70e6cd Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 12 Oct 2011 22:36:40 +0300 Subject: [PATCH 0135/5359] update `core` help. see #31 --- commands/internals/core.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/commands/internals/core.php b/commands/internals/core.php index 52e61cb80..869a46392 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -82,8 +82,7 @@ function update($args) { public static function help() { WP_CLI::line( << Date: Thu, 13 Oct 2011 03:58:33 +0300 Subject: [PATCH 0136/5359] delete '@return void' lines --- commands/community/google-sitemap-generator.php | 1 - commands/community/w3-total-cache.php | 1 - commands/community/wp-super-cache.php | 4 ---- commands/internals/core.php | 1 - commands/internals/generate.php | 2 -- commands/internals/option.php | 4 ---- commands/internals/plugin.php | 6 ------ commands/internals/theme.php | 2 -- core/class-wp-cli.php | 7 ------- 9 files changed, 28 deletions(-) diff --git a/commands/community/google-sitemap-generator.php b/commands/community/google-sitemap-generator.php index c9e8eb006..1bcad0c2e 100644 --- a/commands/community/google-sitemap-generator.php +++ b/commands/community/google-sitemap-generator.php @@ -19,7 +19,6 @@ class GoogleSitemapGeneratorCommand extends WP_CLI_Command { * * @param array $args * @param array $vars - * @return void */ function rebuild( $args = array(), $vars = array() ) { do_action( 'sm_rebuild' ); diff --git a/commands/community/w3-total-cache.php b/commands/community/w3-total-cache.php index 62d5ee15d..4f0344c7b 100644 --- a/commands/community/w3-total-cache.php +++ b/commands/community/w3-total-cache.php @@ -19,7 +19,6 @@ class W3TotalCacheCommand extends WP_CLI_Command { * * @param array $args * @param array $vars - * @return void */ function flush( $args = array(), $vars = array() ) { if ( function_exists( 'w3tc_pgcache_flush' ) ) { diff --git a/commands/community/wp-super-cache.php b/commands/community/wp-super-cache.php index 6751fde06..54f7cb063 100644 --- a/commands/community/wp-super-cache.php +++ b/commands/community/wp-super-cache.php @@ -19,7 +19,6 @@ class WPSuperCacheCommand extends WP_CLI_Command { * * @param array $args * @param array $vars - * @return void */ function flush( $args = array(), $vars = array() ) { if ( function_exists( 'wp_cache_clear_cache' ) ) { @@ -53,7 +52,6 @@ function flush( $args = array(), $vars = array() ) { * * @param array $args * @param array $vars - * @return void */ function status( $args = array(), $vars = array() ) { $cache_stats = get_option( 'supercache_stats' ); @@ -84,7 +82,6 @@ function status( $args = array(), $vars = array() ) { * * @param array $args * @param array $vars - * @return void */ function enable( $args = array(), $vars = array() ) { if ( function_exists( 'wp_super_cache_enable' ) ) { @@ -105,7 +102,6 @@ function enable( $args = array(), $vars = array() ) { * * @param array $args * @param array $vars - * @return void */ function disable( $args = array(), $vars = array() ) { if ( function_exists( 'wp_super_cache_disable' ) ) { diff --git a/commands/internals/core.php b/commands/internals/core.php index 869a46392..5f378e098 100644 --- a/commands/internals/core.php +++ b/commands/internals/core.php @@ -49,7 +49,6 @@ public function version( $args = array(), $assoc_args = array() ) { * Update the WordPress core * * @param array $args - * @return void */ function update($args) { WP_CLI::line('Updating the WordPress core.'); diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 4fbac253c..263eb8d01 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -16,7 +16,6 @@ class GenerateCommand extends WP_CLI_Command { * * @param array $args * @param array $assoc_args - * @return void **/ public function posts( $args, $assoc_args ) { global $wpdb; @@ -55,7 +54,6 @@ public function posts( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - * @return void **/ public function users( $args, $assoc_args ) { global $blog_id; diff --git a/commands/internals/option.php b/commands/internals/option.php index a87866cba..8e9706184 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -15,7 +15,6 @@ class OptionCommand extends WP_CLI_Command { * Add an option * * @param array $args - * @return void **/ public function add($args = array()) { // Check if the required arguments are there @@ -37,7 +36,6 @@ public function add($args = array()) { * Update an option * * @param array $args - * @return void **/ public function update($args = array()) { // Check if the required arguments are there @@ -59,7 +57,6 @@ public function update($args = array()) { * Delete an option * * @param array $args - * @return void **/ public function delete($args = array()) { // Check if the required arguments are there @@ -81,7 +78,6 @@ public function delete($args = array()) { * Get an option * * @param array $args - * @return void **/ public function get($args = array()) { // Check if the required arguments are there diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index a8417428c..475f635b5 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -21,7 +21,6 @@ class PluginCommand extends WP_CLI_Command { * Get the status of one or all plugins * * @param array $args - * @return void */ function status( $args = array(), $vars = array() ) { $this->mu_plugins = get_mu_plugins(); @@ -114,7 +113,6 @@ private function get_status( $file, $long = false ) { * Activate a plugin * * @param array $args - * @return void */ function activate( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); @@ -132,7 +130,6 @@ function activate( $args ) { * Deactivate a plugin * * @param array $args - * @return void */ function deactivate( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); @@ -150,7 +147,6 @@ function deactivate( $args ) { * Toggle a plugin's activation state * * @param array $args - * @return void */ function toggle( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); @@ -227,7 +223,6 @@ function install( $args, $assoc_args ) { * Delete a plugin * * @param array $args - * @return void */ function delete( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); @@ -241,7 +236,6 @@ function delete( $args ) { * Update a plugin * * @param array $args - * @return void */ function update( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 74b784ddd..b6024a320 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -17,7 +17,6 @@ class ThemeCommand extends WP_CLI_Command { * Get the status of one or all themes * * @param array $args - * @return void **/ public function status( $args = array() ) { if ( empty( $args ) ) { @@ -85,7 +84,6 @@ private function get_status( $theme_name, $long = false ) { * Activate a theme * * @param array $args - * @return void **/ public function activate($args = array()) { if ( empty( $args ) ) { diff --git a/core/class-wp-cli.php b/core/class-wp-cli.php index 2c5c3a043..a70b2926d 100644 --- a/core/class-wp-cli.php +++ b/core/class-wp-cli.php @@ -13,7 +13,6 @@ class WP_CLI { * * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command - * @return void */ public function addCommand( $name, $class ) { self::$commands[$name] = $class; @@ -23,7 +22,6 @@ public function addCommand( $name, $class ) { * Display a message in the cli * * @param string $message - * @return void */ static function out( $message ) { \cli\out($message); @@ -33,7 +31,6 @@ static function out( $message ) { * Display a message in the CLI and end with a newline * * @param string $message - * @return void */ static function line( $message = '' ) { \cli\line($message); @@ -44,7 +41,6 @@ static function line( $message = '' ) { * * @param string $message * @param string $label - * @return void */ static function error( $message, $label = 'Error' ) { \cli\line( '%R' . $label . ': %n' . self::errorToString( $message ) ); @@ -55,7 +51,6 @@ static function error( $message, $label = 'Error' ) { * * @param string $message * @param string $label - * @return void */ static function success( $message, $label = 'Success' ) { \cli\line( '%G' . $label . ': %n' . $message ); @@ -66,7 +61,6 @@ static function success( $message, $label = 'Success' ) { * * @param string $message * @param string $label - * @return void */ static function warning( $message, $label = 'Warning' ) { \cli\line( '%C' . $label . ': %n' . $message ); @@ -137,7 +131,6 @@ static function compose_args( $args, $assoc_args = array() ) { * Display a legend * * @param array( code => title ) $legend - * @return void */ static function legend( $legend ) { $legend[ '%yU' ] = 'Update Available'; From e9389c26237542958eae72c56de1b0aa96389da2 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 13 Oct 2011 04:12:05 +0300 Subject: [PATCH 0137/5359] implement wp plugin path. closes #35 --- commands/internals/plugin.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 475f635b5..2bfd282b6 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -158,6 +158,26 @@ function toggle( $args ) { } } + /** + * Get a plugin path + * + * @param array $args + * @param array $assoc_args + */ + function path( $args, $assoc_args ) { + if ( empty( $args ) ) { + $path = WP_PLUGIN_DIR; + } else { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + $path = untrailingslashit( WP_PLUGIN_DIR ) . '/' . $file; + + if ( isset( $assoc_args['directory'] ) ) + $path = dirname( $path ); + } + + WP_CLI::line( $path ); + } + /** * Install a new plugin * @@ -321,12 +341,15 @@ private function parse_name( $args, $subcommand ) { public static function help() { WP_CLI::line( << [] + or: wp plugin path [] [--directory] + or: wp plugin install [--activate] Available sub-commands: status display status of all installed plugins or of a particular plugin activate activate a particular plugin deactivate deactivate a particular plugin toggle toggle activation state of a particular plugin + path print path to the plugin's file install install a plugin from wordpress.org update update a plugin from wordpress.org delete delete a plugin From 6a75cfe1da1edc31e007f5186a4a47f5d6f3ac87 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 13 Oct 2011 04:37:55 +0300 Subject: [PATCH 0138/5359] implement `wp theme path`. see #35 --- commands/internals/plugin.php | 8 ++--- commands/internals/theme.php | 56 ++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 2bfd282b6..906a712b8 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -165,11 +165,11 @@ function toggle( $args ) { * @param array $assoc_args */ function path( $args, $assoc_args ) { - if ( empty( $args ) ) { - $path = WP_PLUGIN_DIR; - } else { + $path = untrailingslashit( WP_PLUGIN_DIR ); + + if ( !empty( $args ) ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - $path = untrailingslashit( WP_PLUGIN_DIR ) . '/' . $file; + $path .= '/' . $file; if ( isset( $assoc_args['directory'] ) ) $path = dirname( $path ); diff --git a/commands/internals/theme.php b/commands/internals/theme.php index b6024a320..4f3ff1a3c 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -85,33 +85,59 @@ private function get_status( $theme_name, $long = false ) { * * @param array $args **/ - public function activate($args = array()) { - if ( empty( $args ) ) { - WP_CLI::line('usage: wp theme activate '); + public function activate( $args = array() ) { + list( $stylesheet, $child ) = $this->parse_name( $args, __FUNCTION__ ); + + $details = get_theme_data( $stylesheet ); + + $parent = $details['Template']; + + if ( empty( $parent ) ) { + $parent = $child; + } elseif ( !is_readable( $this->get_stylesheet_path( $parent ) ) ) { + WP_CLI::warning( 'parent theme not found' ); exit; } - $child = array_shift( $args ); + switch_theme( $parent, $child ); + } - $stylesheet = $this->get_stylesheet_path( $child ); + /** + * Get a theme path + * + * @param array $args + * @param array $assoc_args + */ + function path( $args, $assoc_args ) { + if ( empty( $args ) ) { + $path = WP_CONTENT_DIR . '/themes'; + } else { + list( $stylesheet, $name ) = $this->parse_name( $args, __FUNCTION__ ); + $path = $stylesheet; - if ( !is_readable( $stylesheet ) ) { - WP_CLI::warning( 'theme not found' ); + if ( isset( $assoc_args['directory'] ) ) + $path = dirname( $path ); + } + + WP_CLI::line( $path ); + } + + protected function parse_name( $args, $subcommand ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp theme $subcommand " ); exit; } - $details = get_theme_data( $stylesheet ); + $name = $args[0]; - $parent = $details['Template']; + $stylesheet = $this->get_stylesheet_path( $name ); - if ( empty( $parent ) ) { - $parent = $child; - } elseif ( !is_readable( $this->get_stylesheet_path ( $parent ) ) ) { - WP_CLI::warning( 'parent theme not found' ); + if ( !is_readable( $stylesheet ) ) { + WP_CLI::error( "The theme '$name' could not be found." ); exit; } - switch_theme( $parent, $child ); + return array( $stylesheet, $name ); } protected function get_stylesheet_path( $theme ) { @@ -124,10 +150,12 @@ protected function get_stylesheet_path( $theme ) { public static function help() { WP_CLI::line( << [] + or: wp theme path [] [--directory] Available sub-commands: status display status of all installed themes or of a particular theme activate activate a particular theme + path print path to the theme's stylesheet EOB ); } From 53e31d5940287ed2319b001ecd49b047311da6ec Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 14 Oct 2011 00:47:18 +0300 Subject: [PATCH 0139/5359] fix warning when --blog does not contain trailing slash --- core/wp-cli.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/wp-cli.php b/core/wp-cli.php index 438c30a1d..b31ffcc8f 100755 --- a/core/wp-cli.php +++ b/core/wp-cli.php @@ -54,6 +54,9 @@ } if ( isset( $blog ) ) { + if ( false === strpos( $blog, '/' ) ) + $blog .= '/'; + list( $domain, $path ) = explode( '/', $blog, 2 ); $_SERVER['HTTP_HOST'] = $domain; From 23a6b63eed527443c70026b1ecb0622ba486c166 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 14 Oct 2011 00:50:24 +0300 Subject: [PATCH 0140/5359] put Status after Name. just seems more natural --- commands/internals/plugin.php | 2 +- commands/internals/theme.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/internals/plugin.php b/commands/internals/plugin.php index 906a712b8..04ff2470d 100644 --- a/commands/internals/plugin.php +++ b/commands/internals/plugin.php @@ -42,8 +42,8 @@ function status( $args = array(), $vars = array() ) { $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); - WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Version: ' . $version ); WP_CLI::line( ' Author: ' . $details[ 'Author' ] ); WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); diff --git a/commands/internals/theme.php b/commands/internals/theme.php index 4f3ff1a3c..70c55ebf8 100644 --- a/commands/internals/theme.php +++ b/commands/internals/theme.php @@ -36,8 +36,8 @@ public function status( $args = array() ) { $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Theme %9' . $name . '%n details:' ); - WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Version: ' . $version ); WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } From a442200f4443b93521b305a9c648ea8c31ef1c1e Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 19 Oct 2011 03:53:37 +0300 Subject: [PATCH 0141/5359] allow wp generate users --role=none --- commands/internals/generate.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commands/internals/generate.php b/commands/internals/generate.php index 263eb8d01..e4aa15803 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -65,7 +65,9 @@ public function users( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - if ( is_null( get_role( $role ) ) ) { + if ( 'none' == $role ) + $role = false; + elseif ( is_null( get_role( $role ) ) ) { WP_CLI::warning( "invalid role." ); exit; } From 2649a4ea20ec20b17571eb7a1fe2cb383424b88f Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 19 Oct 2011 06:02:56 +0300 Subject: [PATCH 0142/5359] explicitly delete capabilites when role=none --- commands/internals/generate.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/commands/internals/generate.php b/commands/internals/generate.php index e4aa15803..d38efbc0d 100644 --- a/commands/internals/generate.php +++ b/commands/internals/generate.php @@ -65,9 +65,9 @@ public function users( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - if ( 'none' == $role ) + if ( 'none' == $role ) { $role = false; - elseif ( is_null( get_role( $role ) ) ) { + } elseif ( is_null( get_role( $role ) ) ) { WP_CLI::warning( "invalid role." ); exit; } @@ -82,13 +82,18 @@ public function users( $args, $assoc_args ) { $login = sprintf( 'user_%d_%d', $blog_id, $i ); $name = "User $i"; - $r = wp_insert_user( array( + $user_id = wp_insert_user( array( 'user_login' => $login, 'user_pass' => $login, 'nickname' => $name, 'display_name' => $name, 'role' => $role ) ); + + if ( false === $role ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } } } From cd673787a7a95729317de3293498a5b4a7d96f59 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 25 Oct 2011 20:45:47 +0300 Subject: [PATCH 0143/5359] improve `wp option get` output. see #37 --- commands/internals/option.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/commands/internals/option.php b/commands/internals/option.php index 8e9706184..1cabe8915 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -80,19 +80,22 @@ public function delete($args = array()) { * @param array $args **/ public function get($args = array()) { - // Check if the required arguments are there - if(count($args) == 1) { - // Try to get the option - $option = get_option($args[0]); - if($option) { - WP_CLI::success('The value of option %9'.$args[0].'%n is \'%9'.$option.'%n\'.'); - } - else { - WP_CLI::error('Option %9'.$args[0].'%n could not be found. Does it exist?'); - } + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp option get " ); + exit; } - else { - WP_CLI::error('This command needs exactly one argument.'); + + $key = $args[0]; + + $value = get_option( $key ); + + if ( false === $value ) + return; + + if ( is_array( $value ) || is_object( $value ) ) { + WP_CLI::line( var_export( $value ) ); + } else { + WP_CLI::line( $value ); } } From a53adfd5b5bcbafe7c9bdc678a42957b153cd7df Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 25 Oct 2011 21:12:45 +0300 Subject: [PATCH 0144/5359] clean up the rest of the option subcommands. see #37 --- commands/internals/option.php | 70 ++++++++++++++++------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/commands/internals/option.php b/commands/internals/option.php index 1cabe8915..8dc34c7f3 100644 --- a/commands/internals/option.php +++ b/commands/internals/option.php @@ -16,19 +16,16 @@ class OptionCommand extends WP_CLI_Command { * * @param array $args **/ - public function add($args = array()) { - // Check if the required arguments are there - if(count($args) == 2) { - // Try to add the option - if(add_option($args[0], $args[1])) { - WP_CLI::success('Added option %9'.$args[0].'%n to \'%9'.$args[1].'%n\'.'); - } - else { - WP_CLI::error('Option %9'.$args[0].'%n could not be added. Does it already exist?'); - } + public function add( $args ) { + if ( count( $args ) < 2 ) { + WP_CLI::line( "usage: wp option add " ); + exit; } - else { - WP_CLI::error('This command needs exactly two arguments.'); + + list( $key, $value ) = $args; + + if ( !add_option( $key, $value ) ) { + WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); } } @@ -37,19 +34,19 @@ public function add($args = array()) { * * @param array $args **/ - public function update($args = array()) { - // Check if the required arguments are there - if(count($args) == 2) { - // Try to update the option - if(update_option($args[0], $args[1])) { - WP_CLI::success('Updated option %9'.$args[0].'%n to \'%9'.$args[1].'%n\'.'); - } - else { - WP_CLI::error('Option %9'.$args[0].'%n could not be updated. Does it exist? Is the value already \'%9'.$args[1].'%n\'?'); - } + public function update( $args ) { + if ( count( $args ) < 2 ) { + WP_CLI::line( "usage: wp option update " ); + exit; } - else { - WP_CLI::error('This command needs exactly two arguments.'); + + list( $key, $value ) = $args; + + if ( $value === get_option( $key ) ) + return; + + if ( !update_option( $key, $value ) ) { + WP_CLI::error( "Could not update option '$key'." ); } } @@ -58,19 +55,16 @@ public function update($args = array()) { * * @param array $args **/ - public function delete($args = array()) { - // Check if the required arguments are there - if(count($args) == 1) { - // Try to delete the option - if(delete_option($args[0])) { - WP_CLI::success('Deleted option %9'.$args[0].'%n.'); - } - else { - WP_CLI::error('Option %9'.$args[0].'%n could not be deleted. Does it exist?'); - } + public function delete( $args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp option get " ); + exit; } - else { - WP_CLI::error('This command needs exactly one argument.'); + + list( $key ) = $args; + + if ( !delete_option( $key ) ) { + WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); } } @@ -79,13 +73,13 @@ public function delete($args = array()) { * * @param array $args **/ - public function get($args = array()) { + public function get( $args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp option get " ); exit; } - $key = $args[0]; + list( $key ) = $args; $value = get_option( $key ); From 4b907b2d5ff6f96162516d5ced2e51ffbfd6ea21 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Oct 2011 17:09:16 +0300 Subject: [PATCH 0145/5359] use --recurse-submodules option --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 3e20deaab..95aafc311 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,7 @@ First, make sure you have `php-cli` version 5.3 or newer installed. Clone the project: ``` -git clone https://github.com/andreascreten/wp-cli.git -cd wp-cli -git submodule update --init +git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git ``` Make a symlink to the executable: From 42c8cfdbb5498b9c05db23c6aec6bdad5a5123b6 Mon Sep 17 00:00:00 2001 From: Edgar Marca Date: Thu, 27 Oct 2011 11:21:03 -0500 Subject: [PATCH 0146/5359] SQL command for wp-cli --- commands/internals/sql.php | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 commands/internals/sql.php diff --git a/commands/internals/sql.php b/commands/internals/sql.php new file mode 100644 index 000000000..2b2c7d3e6 --- /dev/null +++ b/commands/internals/sql.php @@ -0,0 +1,63 @@ + STDIN, 1 => STDOUT, 2 => STDERR), $pipes) ); + } + + /** + * Exports the wordpress DB as SQL using mysqldump or equivalent. + * @param string $args + * @return void + */ + function dump( $args, $assoc_args ) { + if ( !isset($assoc_args['file']) ) { + $result_file = sprintf('%s.sql', DB_NAME); + } else { + $result_file = $assoc_args['file']; + } + + $exec = sprintf('mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD); + exec($exec); + } + +} From b22dc21ebb12bd146094c5a7308e052e65f1bc29 Mon Sep 17 00:00:00 2001 From: Edgar Marca Date: Thu, 27 Oct 2011 11:40:10 -0500 Subject: [PATCH 0147/5359] Following wordpress coding standards --- commands/internals/sql.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 2b2c7d3e6..4cef97a38 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -9,7 +9,7 @@ // Add the command to the wp-cli -WP_CLI::addCommand('sql', 'SqlCommand'); +WP_CLI::addCommand( 'sql', 'SqlCommand' ); /** * Implement sql command @@ -39,9 +39,9 @@ function connect( $args = array() ) { * @return void */ function cli() { - $exec = sprintf('mysql --user=%s --password=%s', DB_USER, DB_PASSWORD); + $exec = sprintf( 'mysql --user=%s --password=%s', DB_USER, DB_PASSWORD ); - proc_close( proc_open($exec , array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $pipes) ); + proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); } /** @@ -50,14 +50,14 @@ function cli() { * @return void */ function dump( $args, $assoc_args ) { - if ( !isset($assoc_args['file']) ) { - $result_file = sprintf('%s.sql', DB_NAME); + if ( !isset( $assoc_args['file'] ) ) { + $result_file = sprintf( '%s.sql', DB_NAME ); } else { $result_file = $assoc_args['file']; } - $exec = sprintf('mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD); - exec($exec); + $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); + exec( $exec ); } } From 5befc322dee420e1f41f6257264e78d73cb6ba1e Mon Sep 17 00:00:00 2001 From: Edgar Marca Date: Thu, 27 Oct 2011 12:09:43 -0500 Subject: [PATCH 0148/5359] Add query sub command --- commands/internals/sql.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 4cef97a38..70d95f07d 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -60,4 +60,21 @@ function dump( $args, $assoc_args ) { exec( $exec ); } + /** + * Execute a query against the site database. + * @param string $args + * @return void + */ + + function query( $args, $assoc_args ) { + if ( !$args[0] ) { + WP_CLI::line( 'Please add a query.' ); + } + + $query = $args[0]; + $connect = 'mysql --database=' . DB_NAME . ' --user=' . DB_USER . ' --password=' . DB_PASSWORD; + $exec = sprintf( 'mysql --database=%s --user=%s --password=%s --execute="%s"', DB_NAME, DB_USER, DB_PASSWORD, $query ); + $result = exec( $exec ); + WP_CLI::line( $result ); + } } From 8829097e079d338928024e98a9a15469f0f9fd1d Mon Sep 17 00:00:00 2001 From: Edgar Marca Date: Thu, 27 Oct 2011 12:14:34 -0500 Subject: [PATCH 0149/5359] Remove TODO text --- commands/internals/sql.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 70d95f07d..d16ba6f81 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -1,12 +1,4 @@ Date: Thu, 27 Oct 2011 13:26:26 -0500 Subject: [PATCH 0150/5359] Add private function that return the string connection --- commands/internals/sql.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index d16ba6f81..50fe8b45a 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -14,6 +14,18 @@ class SqlCommand extends WP_CLI_Command { protected $default_subcommand = 'cli'; + /** + * return a string to connecting to the DB. + * + * @param void + * @return string $connect + */ + protected function connect_string() { + $connect = sprintf( 'mysql --database=%s --user=%s --password=%s', + DB_NAME, DB_USER, DB_PASSWORD); + return $connect; + } + /** * A string for connecting to the DB. * @@ -21,7 +33,7 @@ class SqlCommand extends WP_CLI_Command { * @return void */ function connect( $args = array() ) { - $connect = 'mysql --database=' . DB_NAME . ' --user=' . DB_USER . ' --password=' . DB_PASSWORD; + $connect = $this->connect_string(); WP_CLI::line( $connect ); } @@ -31,7 +43,7 @@ function connect( $args = array() ) { * @return void */ function cli() { - $exec = sprintf( 'mysql --user=%s --password=%s', DB_USER, DB_PASSWORD ); + $exec = $this->connect_string(); proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); } @@ -49,6 +61,7 @@ function dump( $args, $assoc_args ) { } $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); + exec( $exec ); } @@ -64,8 +77,10 @@ function query( $args, $assoc_args ) { } $query = $args[0]; - $connect = 'mysql --database=' . DB_NAME . ' --user=' . DB_USER . ' --password=' . DB_PASSWORD; - $exec = sprintf( 'mysql --database=%s --user=%s --password=%s --execute="%s"', DB_NAME, DB_USER, DB_PASSWORD, $query ); + + $exec = $this->connect_string(); + $exec .= sprintf(' --execute="%s"', $query); + $result = exec( $exec ); WP_CLI::line( $result ); } From 829667a20c346a4ca893cf209f79bce6aae84df9 Mon Sep 17 00:00:00 2001 From: Edgar Marca Date: Thu, 27 Oct 2011 13:31:55 -0500 Subject: [PATCH 0151/5359] Add help --- commands/internals/sql.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 50fe8b45a..f12e54586 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -84,4 +84,17 @@ function query( $args, $assoc_args ) { $result = exec( $exec ); WP_CLI::line( $result ); } + + /** + * Help function for this command + */ + public static function help() { + WP_CLI::line( << Date: Thu, 27 Oct 2011 23:29:28 +0300 Subject: [PATCH 0152/5359] some string fixes. see #38 --- commands/internals/sql.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index f12e54586..915bde7e0 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -29,7 +29,7 @@ protected function connect_string() { /** * A string for connecting to the DB. * - * @param string $args + * @param string $args * @return void */ function connect( $args = array() ) { @@ -38,19 +38,19 @@ function connect( $args = array() ) { } /** - * Open a SQL command-line interface using Wordpress's credentials. - * @param string $args + * Open a SQL command-line interface using WordPress's credentials. + * @param string $args * @return void */ function cli() { $exec = $this->connect_string(); proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); - } + } /** - * Exports the wordpress DB as SQL using mysqldump or equivalent. - * @param string $args + * Exports the WordPress DB as SQL using mysqldump or equivalent. + * @param string $args * @return void */ function dump( $args, $assoc_args ) { @@ -63,11 +63,11 @@ function dump( $args, $assoc_args ) { $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); exec( $exec ); - } - + } + /** * Execute a query against the site database. - * @param string $args + * @param string $args * @return void */ @@ -90,10 +90,10 @@ function query( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( << Date: Thu, 27 Oct 2011 23:34:52 +0300 Subject: [PATCH 0153/5359] internal commands don't have a single maintainer; they're public property. see #38 --- commands/internals/sql.php | 1 - 1 file changed, 1 deletion(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 915bde7e0..436d76c5a 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -8,7 +8,6 @@ * * @package wp-cli * @subpackage commands/internals - * @maintainer Edgar Marca (http://twitter.com/matiskay) **/ class SqlCommand extends WP_CLI_Command { From c9fa9f9f73d53c22111ef021ddb8cea54234b934 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 27 Oct 2011 23:43:32 +0300 Subject: [PATCH 0154/5359] fix indentation. #38 --- commands/internals/sql.php | 141 +++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/commands/internals/sql.php b/commands/internals/sql.php index 436d76c5a..8e76699d5 100644 --- a/commands/internals/sql.php +++ b/commands/internals/sql.php @@ -13,76 +13,77 @@ class SqlCommand extends WP_CLI_Command { protected $default_subcommand = 'cli'; - /** - * return a string to connecting to the DB. - * - * @param void - * @return string $connect - */ - protected function connect_string() { - $connect = sprintf( 'mysql --database=%s --user=%s --password=%s', - DB_NAME, DB_USER, DB_PASSWORD); - return $connect; - } - - /** - * A string for connecting to the DB. - * - * @param string $args - * @return void - */ - function connect( $args = array() ) { - $connect = $this->connect_string(); - WP_CLI::line( $connect ); - } - - /** - * Open a SQL command-line interface using WordPress's credentials. - * @param string $args - * @return void - */ - function cli() { - $exec = $this->connect_string(); - - proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); - } - - /** - * Exports the WordPress DB as SQL using mysqldump or equivalent. - * @param string $args - * @return void - */ - function dump( $args, $assoc_args ) { - if ( !isset( $assoc_args['file'] ) ) { - $result_file = sprintf( '%s.sql', DB_NAME ); - } else { - $result_file = $assoc_args['file']; - } - - $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); - - exec( $exec ); - } - - /** - * Execute a query against the site database. - * @param string $args - * @return void - */ - - function query( $args, $assoc_args ) { - if ( !$args[0] ) { - WP_CLI::line( 'Please add a query.' ); - } - - $query = $args[0]; - - $exec = $this->connect_string(); - $exec .= sprintf(' --execute="%s"', $query); - - $result = exec( $exec ); - WP_CLI::line( $result ); - } + /** + * return a string to connecting to the DB. + * + * @param void + * @return string $connect + */ + protected function connect_string() { + $connect = sprintf( 'mysql --database=%s --user=%s --password=%s', + DB_NAME, DB_USER, DB_PASSWORD); + return $connect; + } + + /** + * A string for connecting to the DB. + * + * @param string $args + * @return void + */ + function connect( $args = array() ) { + $connect = $this->connect_string(); + WP_CLI::line( $connect ); + } + + /** + * Open a SQL command-line interface using WordPress's credentials. + * @param string $args + * @return void + */ + function cli() { + $exec = $this->connect_string(); + + proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); + } + + /** + * Exports the WordPress DB as SQL using mysqldump or equivalent. + * @param string $args + * @return void + */ + function dump( $args, $assoc_args ) { + if ( !isset( $assoc_args['file'] ) ) { + $result_file = sprintf( '%s.sql', DB_NAME ); + } else { + $result_file = $assoc_args['file']; + } + + $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); + + exec( $exec ); + } + + /** + * Execute a query against the site database. + * @param string $args + * @return void + */ + + function query( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp sql query " ); + exit; + } + + $query = $args[0]; + + $exec = $this->connect_string(); + $exec .= sprintf(' --execute="%s"', $query); + + $result = exec( $exec ); + WP_CLI::line( $result ); + } /** * Help function for this command From bfd5a9d26a78e75571f89b5949fc704ac92b6def Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 5 Nov 2011 22:48:00 +0200 Subject: [PATCH 0155/5359] tentative 0.2 version --- core/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/wp-cli.php b/core/wp-cli.php index b31ffcc8f..293ffe1c2 100755 --- a/core/wp-cli.php +++ b/core/wp-cli.php @@ -4,7 +4,7 @@ die('Only cli access'); } -define( 'WP_CLI_VERSION', '0.2-alpha' ); +define( 'WP_CLI_VERSION', '0.2' ); // Define the wp-cli location define( 'WP_CLI_ROOT', realpath( __DIR__ . '/..' ) . '/' ); From 9f1289be7eac653afa0b64fb4734d489fe3d6a63 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 01:02:22 +0200 Subject: [PATCH 0156/5359] re-organize files --- .gitmodules | 4 ++-- LICENSE => LICENSE.txt | 0 README.md | 4 ++-- {bin => src/bin}/wp | 2 +- {bin => src/bin}/wp-completion.bash | 0 {core => src/php}/class-wp-cli-command.php | 0 {core => src/php}/class-wp-cli.php | 0 .../php/commands}/community/google-sitemap-generator.php | 0 {commands => src/php/commands}/community/w3-total-cache.php | 0 {commands => src/php/commands}/community/wp-super-cache.php | 0 {commands => src/php/commands}/internals/core.php | 0 {commands => src/php/commands}/internals/generate.php | 0 {commands => src/php/commands}/internals/help.php | 0 {commands => src/php/commands}/internals/home.php | 0 {commands => src/php/commands}/internals/option.php | 0 {commands => src/php/commands}/internals/plugin.php | 0 {commands => src/php/commands}/internals/sql.php | 0 {commands => src/php/commands}/internals/theme.php | 0 php-cli-tools => src/php/php-cli-tools | 0 {core => src/php}/wp-cli.php | 6 +++--- 20 files changed, 8 insertions(+), 8 deletions(-) rename LICENSE => LICENSE.txt (100%) rename {bin => src/bin}/wp (98%) rename {bin => src/bin}/wp-completion.bash (100%) rename {core => src/php}/class-wp-cli-command.php (100%) rename {core => src/php}/class-wp-cli.php (100%) rename {commands => src/php/commands}/community/google-sitemap-generator.php (100%) rename {commands => src/php/commands}/community/w3-total-cache.php (100%) rename {commands => src/php/commands}/community/wp-super-cache.php (100%) rename {commands => src/php/commands}/internals/core.php (100%) rename {commands => src/php/commands}/internals/generate.php (100%) rename {commands => src/php/commands}/internals/help.php (100%) rename {commands => src/php/commands}/internals/home.php (100%) rename {commands => src/php/commands}/internals/option.php (100%) rename {commands => src/php/commands}/internals/plugin.php (100%) rename {commands => src/php/commands}/internals/sql.php (100%) rename {commands => src/php/commands}/internals/theme.php (100%) rename php-cli-tools => src/php/php-cli-tools (100%) rename {core => src/php}/wp-cli.php (94%) diff --git a/.gitmodules b/.gitmodules index a2f6eaebb..44afb303c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "php-cli-tools"] - path = php-cli-tools +[submodule "src/php/php-cli-tools"] + path = src/php/php-cli-tools url = git://github.com/jlogsdon/php-cli-tools.git diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/README.md b/README.md index 95aafc311..acd340c9f 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,13 @@ git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git Make a symlink to the executable: ``` -sudo ln -s /path-to-wp-cli-dir/bin/wp /usr/local/bin/ +sudo ln -s /path-to-wp-cli-dir/src/bin/wp /usr/local/bin/ ``` Make a symlink to the autocomplete file (Linux): ``` -sudo ln -s /path-to-wp-cli-dir/bin/wp-completion.bash /etc/bash_completion.d/wp +sudo ln -s /path-to-wp-cli-dir/src/bin/wp-completion.bash /etc/bash_completion.d/wp ``` Usage diff --git a/bin/wp b/src/bin/wp similarity index 98% rename from bin/wp rename to src/bin/wp index 9c0894e5c..fed73b5e6 100755 --- a/bin/wp +++ b/src/bin/wp @@ -30,7 +30,7 @@ done cd "$ORIGDIR" # Build the path to wp-cli.php. -SCRIPT_PATH=$(dirname "$SELF_PATH")/../core/wp-cli.php +SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/wp-cli.php case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; diff --git a/bin/wp-completion.bash b/src/bin/wp-completion.bash similarity index 100% rename from bin/wp-completion.bash rename to src/bin/wp-completion.bash diff --git a/core/class-wp-cli-command.php b/src/php/class-wp-cli-command.php similarity index 100% rename from core/class-wp-cli-command.php rename to src/php/class-wp-cli-command.php diff --git a/core/class-wp-cli.php b/src/php/class-wp-cli.php similarity index 100% rename from core/class-wp-cli.php rename to src/php/class-wp-cli.php diff --git a/commands/community/google-sitemap-generator.php b/src/php/commands/community/google-sitemap-generator.php similarity index 100% rename from commands/community/google-sitemap-generator.php rename to src/php/commands/community/google-sitemap-generator.php diff --git a/commands/community/w3-total-cache.php b/src/php/commands/community/w3-total-cache.php similarity index 100% rename from commands/community/w3-total-cache.php rename to src/php/commands/community/w3-total-cache.php diff --git a/commands/community/wp-super-cache.php b/src/php/commands/community/wp-super-cache.php similarity index 100% rename from commands/community/wp-super-cache.php rename to src/php/commands/community/wp-super-cache.php diff --git a/commands/internals/core.php b/src/php/commands/internals/core.php similarity index 100% rename from commands/internals/core.php rename to src/php/commands/internals/core.php diff --git a/commands/internals/generate.php b/src/php/commands/internals/generate.php similarity index 100% rename from commands/internals/generate.php rename to src/php/commands/internals/generate.php diff --git a/commands/internals/help.php b/src/php/commands/internals/help.php similarity index 100% rename from commands/internals/help.php rename to src/php/commands/internals/help.php diff --git a/commands/internals/home.php b/src/php/commands/internals/home.php similarity index 100% rename from commands/internals/home.php rename to src/php/commands/internals/home.php diff --git a/commands/internals/option.php b/src/php/commands/internals/option.php similarity index 100% rename from commands/internals/option.php rename to src/php/commands/internals/option.php diff --git a/commands/internals/plugin.php b/src/php/commands/internals/plugin.php similarity index 100% rename from commands/internals/plugin.php rename to src/php/commands/internals/plugin.php diff --git a/commands/internals/sql.php b/src/php/commands/internals/sql.php similarity index 100% rename from commands/internals/sql.php rename to src/php/commands/internals/sql.php diff --git a/commands/internals/theme.php b/src/php/commands/internals/theme.php similarity index 100% rename from commands/internals/theme.php rename to src/php/commands/internals/theme.php diff --git a/php-cli-tools b/src/php/php-cli-tools similarity index 100% rename from php-cli-tools rename to src/php/php-cli-tools diff --git a/core/wp-cli.php b/src/php/wp-cli.php similarity index 94% rename from core/wp-cli.php rename to src/php/wp-cli.php index 293ffe1c2..36f7fac15 100755 --- a/core/wp-cli.php +++ b/src/php/wp-cli.php @@ -7,14 +7,14 @@ define( 'WP_CLI_VERSION', '0.2' ); // Define the wp-cli location -define( 'WP_CLI_ROOT', realpath( __DIR__ . '/..' ) . '/' ); +define( 'WP_CLI_ROOT', __DIR__ . '/' ); // Set a constant that can be used to check if we are running wp-cli or not define('WP_CLI', true); // Include the wp-cli classes -include WP_CLI_ROOT . 'core/class-wp-cli.php'; -include WP_CLI_ROOT . 'core/class-wp-cli-command.php'; +include WP_CLI_ROOT . 'class-wp-cli.php'; +include WP_CLI_ROOT . 'class-wp-cli-command.php'; // Include the command line tools include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; From 330600f13a09be4eaff50ce6187371b1afb06700 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 03:18:32 +0200 Subject: [PATCH 0157/5359] add pear package files --- .gitignore | 6 + build.local.xml | 6 + build.properties | 13 ++ build.xml | 440 +++++++++++++++++++++++++++++++++++++++++++++ package.xml | 71 ++++++++ src/php/wp-cli.php | 2 +- 6 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 build.local.xml create mode 100644 build.properties create mode 100644 build.xml create mode 100644 package.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e89c07b32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.build +dist +.tmp +nbproject +review +vendor diff --git a/build.local.xml b/build.local.xml new file mode 100644 index 000000000..90aa3bc92 --- /dev/null +++ b/build.local.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/build.properties b/build.properties new file mode 100644 index 000000000..ea12db9df --- /dev/null +++ b/build.properties @@ -0,0 +1,13 @@ +project.name=wpcli +project.channel=andreascreten.github.com/wp-cli +project.majorVersion=1 +project.minorVersion=0 +project.patchLevel=0 +project.snapshot=false + +checkstyle.standard=Zend + +component.type=php-library +component.version=10 + +pear.local=/var/www/${project.channel} diff --git a/build.xml b/build.xml new file mode 100644 index 000000000..a3b507921 --- /dev/null +++ b/build.xml @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The code coverage report is in file://${project.review.codecoveragedir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Populating vendor/ with dependencies + + + + Your vendor/ folder has been built. + You only need to run 'phing build-vendor' again if you change the + dependencies listed in your package.xml file. + + + + + + + Creating vendor/ as a sandboxed PEAR install folder + + + + + + + + + + + + + + + + + Building release directory + + + + + + + + + + + + + + + + + + + + Creating ${project.tarfile} PEAR package + + + + + + + + + + + + project.lastBuiltTarfile=${project.tarfile} + + + Your PEAR package is in ${project.tarfile} + + + + + + + + + + + Please run 'phing pear-package' first, then try again. + + + + + + + + + + Cannot find PEAR package file ${project.lastBuiltTarfile} + Run 'phing pear-package' to create a new PEAR package, then try again + + + + + + + + + + + + Please run 'phing pear-package' first, then try again. + + + + + + + + + + Cannot find PEAR package file ${project.lastBuiltTarfile} + Run 'phing pear-package' to create a new PEAR package, then try again + + + + + + + + + + + + Please run 'phing pear-package' first, then try again. + + + + + + + + + + + + + + + + + + Cannot find PEAR package file ${project.lastBuiltTarfile} + Run 'phing pear-package' to create a new PEAR package, then try again + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package.xml b/package.xml new file mode 100644 index 000000000..aa11e65f2 --- /dev/null +++ b/package.xml @@ -0,0 +1,71 @@ + + + ${project.name} + ${project.channel} + WordPress CLI interface + + A tool for controlling WordPress through the command line. + + + Andreas Creten + andreascreten + + yes + + + scribu + scribu + mail@scribu.net + yes + + ${build.date} + + + ${project.version} + ${project.majorVersion}.${project.minorVersion} + + + ${project.stability} + stable + + GPL 2+ + + No notes. + + + +${contents} + + + + + + 5.3.0 + + + 1.9.4 + + + + + + + + X.Y.Z + X.Y + + + stable + stable + + Your release date + All rights reserved + + + + + + diff --git a/src/php/wp-cli.php b/src/php/wp-cli.php index 36f7fac15..8fd82d215 100755 --- a/src/php/wp-cli.php +++ b/src/php/wp-cli.php @@ -4,7 +4,7 @@ die('Only cli access'); } -define( 'WP_CLI_VERSION', '0.2' ); +define( 'WP_CLI_VERSION', '1.0.0' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 1313d6711fd67f922f30d328d68feebbcbe98dfd Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 14:05:23 +0200 Subject: [PATCH 0158/5359] fix pear package; set version to 0.3.0 --- build.properties | 4 ++-- src/bin/wp | 6 ++++- src/php/{ => wp-cli}/class-wp-cli-command.php | 0 src/php/{ => wp-cli}/class-wp-cli.php | 0 .../community/google-sitemap-generator.php | 0 .../commands/community/w3-total-cache.php | 0 .../commands/community/wp-super-cache.php | 0 .../{ => wp-cli}/commands/internals/core.php | 0 .../commands/internals/generate.php | 0 .../{ => wp-cli}/commands/internals/help.php | 0 .../{ => wp-cli}/commands/internals/home.php | 0 .../commands/internals/option.php | 0 .../commands/internals/plugin.php | 0 .../{ => wp-cli}/commands/internals/sql.php | 0 .../{ => wp-cli}/commands/internals/theme.php | 0 src/php/{ => wp-cli}/wp-cli.php | 4 ++-- utils/build-pear | 23 +++++++++++++++++++ {src/bin => utils}/wp-completion.bash | 0 18 files changed, 32 insertions(+), 5 deletions(-) rename src/php/{ => wp-cli}/class-wp-cli-command.php (100%) rename src/php/{ => wp-cli}/class-wp-cli.php (100%) rename src/php/{ => wp-cli}/commands/community/google-sitemap-generator.php (100%) rename src/php/{ => wp-cli}/commands/community/w3-total-cache.php (100%) rename src/php/{ => wp-cli}/commands/community/wp-super-cache.php (100%) rename src/php/{ => wp-cli}/commands/internals/core.php (100%) rename src/php/{ => wp-cli}/commands/internals/generate.php (100%) rename src/php/{ => wp-cli}/commands/internals/help.php (100%) rename src/php/{ => wp-cli}/commands/internals/home.php (100%) rename src/php/{ => wp-cli}/commands/internals/option.php (100%) rename src/php/{ => wp-cli}/commands/internals/plugin.php (100%) rename src/php/{ => wp-cli}/commands/internals/sql.php (100%) rename src/php/{ => wp-cli}/commands/internals/theme.php (100%) rename src/php/{ => wp-cli}/wp-cli.php (96%) create mode 100755 utils/build-pear rename {src/bin => utils}/wp-completion.bash (100%) diff --git a/build.properties b/build.properties index ea12db9df..8079bf947 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=andreascreten.github.com/wp-cli -project.majorVersion=1 -project.minorVersion=0 +project.majorVersion=0 +project.minorVersion=3 project.patchLevel=0 project.snapshot=false diff --git a/src/bin/wp b/src/bin/wp index fed73b5e6..20e984096 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -30,7 +30,11 @@ done cd "$ORIGDIR" # Build the path to wp-cli.php. -SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/wp-cli.php +SCRIPT_PATH='@@PHP_DIR@@/wp-cli/wp-cli.php' +if [ ! -f $SCRIPT_PATH ]; then + SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/wp-cli/wp-cli.php +fi + case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; diff --git a/src/php/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php similarity index 100% rename from src/php/class-wp-cli-command.php rename to src/php/wp-cli/class-wp-cli-command.php diff --git a/src/php/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php similarity index 100% rename from src/php/class-wp-cli.php rename to src/php/wp-cli/class-wp-cli.php diff --git a/src/php/commands/community/google-sitemap-generator.php b/src/php/wp-cli/commands/community/google-sitemap-generator.php similarity index 100% rename from src/php/commands/community/google-sitemap-generator.php rename to src/php/wp-cli/commands/community/google-sitemap-generator.php diff --git a/src/php/commands/community/w3-total-cache.php b/src/php/wp-cli/commands/community/w3-total-cache.php similarity index 100% rename from src/php/commands/community/w3-total-cache.php rename to src/php/wp-cli/commands/community/w3-total-cache.php diff --git a/src/php/commands/community/wp-super-cache.php b/src/php/wp-cli/commands/community/wp-super-cache.php similarity index 100% rename from src/php/commands/community/wp-super-cache.php rename to src/php/wp-cli/commands/community/wp-super-cache.php diff --git a/src/php/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php similarity index 100% rename from src/php/commands/internals/core.php rename to src/php/wp-cli/commands/internals/core.php diff --git a/src/php/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php similarity index 100% rename from src/php/commands/internals/generate.php rename to src/php/wp-cli/commands/internals/generate.php diff --git a/src/php/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php similarity index 100% rename from src/php/commands/internals/help.php rename to src/php/wp-cli/commands/internals/help.php diff --git a/src/php/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php similarity index 100% rename from src/php/commands/internals/home.php rename to src/php/wp-cli/commands/internals/home.php diff --git a/src/php/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php similarity index 100% rename from src/php/commands/internals/option.php rename to src/php/wp-cli/commands/internals/option.php diff --git a/src/php/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php similarity index 100% rename from src/php/commands/internals/plugin.php rename to src/php/wp-cli/commands/internals/plugin.php diff --git a/src/php/commands/internals/sql.php b/src/php/wp-cli/commands/internals/sql.php similarity index 100% rename from src/php/commands/internals/sql.php rename to src/php/wp-cli/commands/internals/sql.php diff --git a/src/php/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php similarity index 100% rename from src/php/commands/internals/theme.php rename to src/php/wp-cli/commands/internals/theme.php diff --git a/src/php/wp-cli.php b/src/php/wp-cli/wp-cli.php similarity index 96% rename from src/php/wp-cli.php rename to src/php/wp-cli/wp-cli.php index 8fd82d215..3276ecd09 100755 --- a/src/php/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die('Only cli access'); } -define( 'WP_CLI_VERSION', '1.0.0' ); +define( 'WP_CLI_VERSION', '0.3.0' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); @@ -17,7 +17,7 @@ include WP_CLI_ROOT . 'class-wp-cli-command.php'; // Include the command line tools -include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; +include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; // Register the cli tools autoload \cli\register_autoload(); diff --git a/utils/build-pear b/utils/build-pear new file mode 100755 index 000000000..0d8e51c7d --- /dev/null +++ b/utils/build-pear @@ -0,0 +1,23 @@ +#!/bin/bash + +# generate package +find -name '*~' -delete +phing pear-package + +version=$(cat dist/lastBuilt) +version="${version/*wpcli-/}" +version="${version/.tgz/}" + +#sudo phing install-system + +# update channel files +cd ../wp-cli-pages +pirum add . ../wp-cli/dist/wpcli-$version.tgz +pirum build . + +exit + +# push changes +git add -A +git ci -m "release $version" +git push origin gh-pages diff --git a/src/bin/wp-completion.bash b/utils/wp-completion.bash similarity index 100% rename from src/bin/wp-completion.bash rename to utils/wp-completion.bash From ad66023011928e0db28ec3e952dfa89a280ad6fe Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 14:12:26 +0200 Subject: [PATCH 0159/5359] add changelog --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index acd340c9f..b40472cdd 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,25 @@ You can find more information about adding commands in the [Commands Cookbook](h **Please share the commands you make, issue a pull request to get them included in wp-cli by default.** +Changelog +--------------- + +**0.3** +- added `wp sql` +- improved `wp option` +- pear installer + +**0.2** +- added multisite support +- improved `wp plugin` and `wp theme` +- added `wp generate` +- added `wp core version` +- added `wp --version` +- added bash completion script + +**0.1** +- initial release + Contributors ------------ From bb26f6f2d28e0f30448c181647b418b31cfcfad1 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 14:39:51 +0200 Subject: [PATCH 0160/5359] update installation instructions --- README.md | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b40472cdd..f8028d9df 100644 --- a/README.md +++ b/README.md @@ -9,32 +9,28 @@ A tool to control WordPress installations from the command line. Installing ---------- -**Via package manager:** +**Via PEAR:** -* Ubuntu, Debian: [.deb package](https://github.com/downloads/andreascreten/wp-cli/wp-cli_0.1.deb) -* Mac: install [Homebrew](http://mxcl.github.com/homebrew/) and run `brew install wp-cli`. +``` +pear config-set auto_discover 1 +sudo pear install andreascreten.github.com/wp-cli/wpcli +``` **From source:** -First, make sure you have `php-cli` version 5.3 or newer installed. - -Clone the project: - -``` -git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git ``` +# Clone the project +git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git ~/git/wp-cli -Make a symlink to the executable: +# Make a symlink to the binary +sudo ln -s ~/git/wp-cli/src/bin/wp /usr/bin/ -``` -sudo ln -s /path-to-wp-cli-dir/src/bin/wp /usr/local/bin/ +# Make a symlink to the bash completion file +sudo ln -s ~/git/wp-cli/utils/wp-completion.bash /etc/bash_completion.d/wp ``` -Make a symlink to the autocomplete file (Linux): +You can replace `~/git/wp-cli` with whatever you want. -``` -sudo ln -s /path-to-wp-cli-dir/src/bin/wp-completion.bash /etc/bash_completion.d/wp -``` Usage ----- From 8b6595b809e81dd40b178d588c8cc453aaa5bf87 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 14:43:19 +0200 Subject: [PATCH 0161/5359] fix changelog --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f8028d9df..9d16f743c 100644 --- a/README.md +++ b/README.md @@ -113,11 +113,13 @@ Changelog --------------- **0.3** + - added `wp sql` - improved `wp option` - pear installer **0.2** + - added multisite support - improved `wp plugin` and `wp theme` - added `wp generate` @@ -126,6 +128,7 @@ Changelog - added bash completion script **0.1** + - initial release Contributors From 9adf47d20dcc319d7d84da39edf31b0c155768a5 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 14:57:19 +0200 Subject: [PATCH 0162/5359] readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d16f743c..fc6f31878 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,14 @@ Installing **Via PEAR:** -``` +```sh pear config-set auto_discover 1 sudo pear install andreascreten.github.com/wp-cli/wpcli ``` **From source:** -``` +```sh # Clone the project git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git ~/git/wp-cli From 44ead87ef48a1619419f13e2cc65f4f0afac1500 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 15:02:02 +0200 Subject: [PATCH 0163/5359] use git read-only url in install instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc6f31878..25ee163b7 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ sudo pear install andreascreten.github.com/wp-cli/wpcli ```sh # Clone the project -git clone --recurse-submodules https://github.com/andreascreten/wp-cli.git ~/git/wp-cli +git clone --recurse-submodules git://github.com/andreascreten/wp-cli.git ~/git/wp-cli # Make a symlink to the binary sudo ln -s ~/git/wp-cli/src/bin/wp /usr/bin/ From d3c21db7fafc545e18a0bfccb8d7d4fadc579a6f Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 6 Nov 2011 15:04:43 +0200 Subject: [PATCH 0164/5359] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25ee163b7..a8a32e337 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ sudo ln -s ~/git/wp-cli/utils/wp-completion.bash /etc/bash_completion.d/wp You can replace `~/git/wp-cli` with whatever you want. -Usage +Using ----- Go into a WordPress root folder: From 05dc7a0176469a5df16408590222304a6f47f039 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 8 Nov 2011 22:11:03 +0200 Subject: [PATCH 0165/5359] add usage example when --blog is used as a flag --- src/php/wp-cli/wp-cli.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3276ecd09..219f57382 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -49,6 +49,9 @@ if ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); + if ( true === $blog ) { + WP_CLI::line( 'usage: wp --blog=example.com' ); + } } elseif ( is_readable( WP_ROOT . '/wp-cli-blog' ) ) { $blog = file_get_contents( WP_ROOT . '/wp-cli-blog' ); } From 2dfe52377bd18f7991dd1aaeb73e64e9fd1b3245 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 8 Nov 2011 22:11:16 +0200 Subject: [PATCH 0166/5359] coding standards --- src/php/wp-cli/wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 219f57382..9c593e3d7 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -72,12 +72,12 @@ require_once(ABSPATH . 'wp-admin/includes/admin.php'); // Load all internal commands -foreach (glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename) { +foreach ( glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename ) { include $filename; } // Load all plugin commands -foreach (glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename) { +foreach ( glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename ) { include $filename; } From 830eb61695e5a64af76e55ce5fadf087cdb7ee8d Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 10 Nov 2011 21:32:49 +0200 Subject: [PATCH 0167/5359] implement eval command; fixes #41 --- src/php/wp-cli/commands/internals/eval.php | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/eval.php diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/internals/eval.php new file mode 100644 index 000000000..aab1a6eca --- /dev/null +++ b/src/php/wp-cli/commands/internals/eval.php @@ -0,0 +1,42 @@ +" ); + exit; + } + + $name = $args[0]; + eval( $args[0] ); + } + + /** + * Help function for this command + */ + public static function help() { + WP_CLI::line( << Date: Thu, 10 Nov 2011 21:34:49 +0200 Subject: [PATCH 0168/5359] bump version to 0.4.0-dev --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 9c593e3d7..89df36ad8 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die('Only cli access'); } -define( 'WP_CLI_VERSION', '0.3.0' ); +define( 'WP_CLI_VERSION', '0.4.0-dev' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From d3a844cb3078f1ddab00c216045ff80ebc30f241 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 10 Nov 2011 21:55:07 +0200 Subject: [PATCH 0169/5359] add eval-file command. see #41 --- .../wp-cli/commands/internals/eval-file.php | 46 +++++++++++++++++++ src/php/wp-cli/commands/internals/eval.php | 2 - 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/php/wp-cli/commands/internals/eval-file.php diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/internals/eval-file.php new file mode 100644 index 000000000..d8ef5dc5a --- /dev/null +++ b/src/php/wp-cli/commands/internals/eval-file.php @@ -0,0 +1,46 @@ +" ); + exit; + } + + foreach ( $args as $file ) { + if ( !file_exists( $file ) ) { + WP_CLI::error( "'$file' does not exist." ); + } else { + include( $file ); + } + } + } + + /** + * Help function for this command + */ + public static function help() { + WP_CLI::line( << Date: Thu, 10 Nov 2011 22:25:22 +0200 Subject: [PATCH 0170/5359] remove redundant comments --- src/php/wp-cli/commands/community/google-sitemap-generator.php | 1 - src/php/wp-cli/commands/community/w3-total-cache.php | 1 - src/php/wp-cli/commands/community/wp-super-cache.php | 1 - src/php/wp-cli/commands/internals/core.php | 1 - src/php/wp-cli/commands/internals/eval-file.php | 1 - src/php/wp-cli/commands/internals/eval.php | 1 - src/php/wp-cli/commands/internals/generate.php | 1 - src/php/wp-cli/commands/internals/help.php | 1 - src/php/wp-cli/commands/internals/home.php | 1 - src/php/wp-cli/commands/internals/option.php | 1 - src/php/wp-cli/commands/internals/sql.php | 1 - src/php/wp-cli/commands/internals/theme.php | 1 - 12 files changed, 12 deletions(-) diff --git a/src/php/wp-cli/commands/community/google-sitemap-generator.php b/src/php/wp-cli/commands/community/google-sitemap-generator.php index 1bcad0c2e..a35acbcd1 100644 --- a/src/php/wp-cli/commands/community/google-sitemap-generator.php +++ b/src/php/wp-cli/commands/community/google-sitemap-generator.php @@ -1,6 +1,5 @@ Date: Thu, 10 Nov 2011 22:32:05 +0200 Subject: [PATCH 0171/5359] fix indentation --- .../community/google-sitemap-generator.php | 6 +- .../commands/community/w3-total-cache.php | 86 +++++++++---------- .../commands/community/wp-super-cache.php | 12 +-- src/php/wp-cli/commands/internals/core.php | 2 +- .../wp-cli/commands/internals/eval-file.php | 6 +- src/php/wp-cli/commands/internals/eval.php | 6 +- .../wp-cli/commands/internals/generate.php | 2 +- src/php/wp-cli/commands/internals/help.php | 4 +- src/php/wp-cli/commands/internals/home.php | 6 +- src/php/wp-cli/commands/internals/option.php | 2 +- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/sql.php | 2 +- 12 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/php/wp-cli/commands/community/google-sitemap-generator.php b/src/php/wp-cli/commands/community/google-sitemap-generator.php index a35acbcd1..268518701 100644 --- a/src/php/wp-cli/commands/community/google-sitemap-generator.php +++ b/src/php/wp-cli/commands/community/google-sitemap-generator.php @@ -27,12 +27,12 @@ function rebuild( $args = array(), $vars = array() ) { * Help function for this command */ public static function help() { - WP_CLI::line( <<] [--permalink=] Available sub-commands: - flush flushes whole cache - --post_id= flush specific ID - --permalink= flush specific permalink - database flushes database cache - object flush object cache - minify flush minify cache + flush flushes whole cache + --post_id= flush specific ID + --permalink= flush specific permalink + database flushes database cache + object flush object cache + minify flush minify cache EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/community/wp-super-cache.php b/src/php/wp-cli/commands/community/wp-super-cache.php index f0ede07b0..3501658c4 100644 --- a/src/php/wp-cli/commands/community/wp-super-cache.php +++ b/src/php/wp-cli/commands/community/wp-super-cache.php @@ -124,11 +124,11 @@ public static function help() { usage: wp super-cache [flush|status|enable|disable] --post_id= --permalink= Available sub-commands: - flush flushes whole cache, or post with given permalink or ID --post_id= --permalink= - status shows status of WP Super Cache - enable enables WP Super Cache - disable disables WP Super Cache + flush flushes whole cache, or post with given permalink or ID --post_id= --permalink= + status shows status of WP Super Cache + enable enables WP Super Cache + disable disables WP Super Cache EOB - ); - } + ); + } } diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 1376541a9..3d0cf2b76 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -82,6 +82,6 @@ public static function help() { usage: wp core update or: wp core version [--extra] EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/internals/eval-file.php index ebf1cd36a..b508b32db 100644 --- a/src/php/wp-cli/commands/internals/eval-file.php +++ b/src/php/wp-cli/commands/internals/eval-file.php @@ -12,8 +12,8 @@ class EvalFileCommand extends WP_CLI_Command { /** * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args + * + * @param array $args * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { @@ -40,6 +40,6 @@ public static function help() { Loads and executes a PHP file after bootstrapping WordPress. EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/internals/eval.php index 62d23139c..4d931abb2 100644 --- a/src/php/wp-cli/commands/internals/eval.php +++ b/src/php/wp-cli/commands/internals/eval.php @@ -12,8 +12,8 @@ class EvalCommand extends WP_CLI_Command { /** * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args + * + * @param array $args * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { @@ -34,6 +34,6 @@ public static function help() { Executes arbitrary PHP code after bootstrapping WordPress. EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 6f311a9dc..7f8189400 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -104,6 +104,6 @@ public static function help() { usage: wp generate posts [--count=100] [--type=post] [--status=publish] or: wp generate users [--count=100] [--role=] EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 086f92885..4a8e68882 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -12,8 +12,8 @@ class HelpCommand extends WP_CLI_Command { /** * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args + * + * @param array $args */ public function __construct( $args ) { if ( empty( $args ) ) { diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index f411cb390..4f3304fc5 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -12,8 +12,8 @@ class HomeCommand extends WP_CLI_Command { /** * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args + * + * @param array $args * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { @@ -44,6 +44,6 @@ public static function help() { Opens the wp-cli homepage in your browser. EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 145316e89..26be3b1cc 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -102,6 +102,6 @@ public static function help() { or: wp option update or: wp option delete EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 04ff2470d..b3acf0d3d 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -354,6 +354,6 @@ public static function help() { update update a plugin from wordpress.org delete delete a plugin EOB - ); + ); } } diff --git a/src/php/wp-cli/commands/internals/sql.php b/src/php/wp-cli/commands/internals/sql.php index 8e10609a0..a3f2e8ffc 100644 --- a/src/php/wp-cli/commands/internals/sql.php +++ b/src/php/wp-cli/commands/internals/sql.php @@ -94,6 +94,6 @@ public static function help() { wp sql dump Exports the WordPress database as SQL using mysqldump or equivalent. wp sql query Execute a query against the WordPress database. EOB - ); + ); } } From 6f3602572a51b65f99d809b21369ad5549bbfd3e Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 10 Nov 2011 23:14:03 +0200 Subject: [PATCH 0172/5359] remove extra line endings from wp-cli-blog content --- src/php/wp-cli/wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 89df36ad8..8c3679bbe 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -52,8 +52,8 @@ if ( true === $blog ) { WP_CLI::line( 'usage: wp --blog=example.com' ); } -} elseif ( is_readable( WP_ROOT . '/wp-cli-blog' ) ) { - $blog = file_get_contents( WP_ROOT . '/wp-cli-blog' ); +} elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { + $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); } if ( isset( $blog ) ) { From b7f0934687acbe9107df7ccac0a147a1d4c2ee0d Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 20 Nov 2011 16:08:49 +0200 Subject: [PATCH 0173/5359] remove old build-deb script --- utils/build-deb | 70 ------------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100755 utils/build-deb diff --git a/utils/build-deb b/utils/build-deb deleted file mode 100755 index 9a3c583fd..000000000 --- a/utils/build-deb +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -# script for generating a .deb file - -SOURCE_DIR=$(pwd) - -rm -rf /tmp/wp-cli - -mkdir -p /tmp/wp-cli/DEBIAN - -cd /tmp/wp-cli - -# copy php files -ROOT_DIR='usr/share/php/wp-cli' - -mkdir -p $ROOT_DIR -for dir in 'php-cli-tools' 'core' 'commands'; do - cp -r $SOURCE_DIR/$dir $ROOT_DIR/ -done - -rm -rf $ROOT_DIR/php-cli-tools/.git* - -# copy completion file -ROOT_DIR='etc/bash_completion.d' - -mkdir -p $ROOT_DIR -cp $SOURCE_DIR/bin/wp-completion.bash $ROOT_DIR/wp - -# copy license file -ROOT_DIR='usr/share/doc/wp-cli' - -mkdir -p $ROOT_DIR -cp $SOURCE_DIR/LICENSE $ROOT_DIR/copyright - -# remove junk files -for name in '*~' '*.swp'; do - find . -name $name -exec rm {} \; -done - -# reset permsissions and ownership -chown -R root . -chgrp -R root . -find . -type f -exec chmod 644 {} \; -find . -type d -exec chmod 755 {} \; - -# use a simple bash wrapper for the command, since we know where everything is -mkdir -p usr/bin - -cat > usr/bin/wp < DEBIAN/control <= 5.3) -Installed-Size: 150 -Maintainer: Cristi Burca -Description: WordPress command-line interface - A tool for controlling WordPress installations via the command-line. -EOT - -dpkg --build /tmp/wp-cli From 55dfda323cd6313e4a8d5a87fae256f7102ce3da Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 20 Nov 2011 16:17:20 +0200 Subject: [PATCH 0174/5359] add build-dev script --- README.md | 11 +++-------- utils/build-dev | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) create mode 100755 utils/build-dev diff --git a/README.md b/README.md index a8a32e337..68a99dce4 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,12 @@ pear config-set auto_discover 1 sudo pear install andreascreten.github.com/wp-cli/wpcli ``` -**From source:** +**Via GIT:** ```sh -# Clone the project git clone --recurse-submodules git://github.com/andreascreten/wp-cli.git ~/git/wp-cli - -# Make a symlink to the binary -sudo ln -s ~/git/wp-cli/src/bin/wp /usr/bin/ - -# Make a symlink to the bash completion file -sudo ln -s ~/git/wp-cli/utils/wp-completion.bash /etc/bash_completion.d/wp +cd ~/git/wp-cli +sudo utils/build-dev ``` You can replace `~/git/wp-cli` with whatever you want. diff --git a/utils/build-dev b/utils/build-dev new file mode 100755 index 000000000..c1a39ad87 --- /dev/null +++ b/utils/build-dev @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +ln -s $(pwd)/src/bin/wp /usr/bin/wp +ln -s $(pwd)/utils/wp-completion.bash /etc/bash_completion.d/wp From 0a3b579c14407fa75d8a41230d06f361c5b65cfc Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 20 Nov 2011 16:54:05 +0200 Subject: [PATCH 0175/5359] output errors to STDERR and exit with status 1 --- src/php/wp-cli/class-wp-cli.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index a70b2926d..56967f960 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -43,7 +43,8 @@ static function line( $message = '' ) { * @param string $label */ static function error( $message, $label = 'Error' ) { - \cli\line( '%R' . $label . ': %n' . self::errorToString( $message ) ); + \cli\err( '%R' . $label . ': %n' . self::errorToString( $message ) ); + exit(1); } /** @@ -219,7 +220,7 @@ function feedback( $string ) { } } - + if( empty( $string ) ) { return; } @@ -229,4 +230,4 @@ function feedback( $string ) { function before() {} function after() {} -} \ No newline at end of file +} From 14eae3f585cf19c0079f887bc2c9cf6e6995d849 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 8 Dec 2011 16:46:46 +0200 Subject: [PATCH 0176/5359] readme --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 68a99dce4..3583bdd8d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ -WP-CLI: WordPress Command Line Tools -============================ - -What is wp-cli +What is wp-cli? -------------- -A tool to control WordPress installations from the command line. +A set of tools for controlling WordPress installations from the command line. Installing ---------- From 8e0076c634b659cf3776b4c984816572d3aeb689 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 11 Dec 2011 21:15:50 +0200 Subject: [PATCH 0177/5359] add --dev flag to wp plugin install. see #45 --- src/php/wp-cli/commands/internals/plugin.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index b3acf0d3d..1cb45955e 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -190,21 +190,28 @@ function install( $args, $assoc_args ) { exit; } - $name = $args[0]; + $slug = stripslashes( $args[0] ); // Force WordPress to update the plugin list wp_update_plugins(); // Get plugin info from the WordPress servers - $api = plugins_api( 'plugin_information', array( 'slug' => stripslashes( $name ) ) ); + $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( !$api ) { WP_CLI::error( 'Can\'t find the plugin in the WordPress.org plugins repository.' ); exit(); } + if ( isset( $assoc_args['dev'] ) ) { + list( $link ) = explode( $slug, $api->download_link ); + + $api->download_link = $link . $slug . '.zip'; + $api->version = 'Development Version'; + } + $status = install_plugin_install_status( $api ); - WP_CLI::line( 'Installing '.$api->name.' ('.$api->version.')' ); + WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); // Check what to do switch ( $status['status'] ) { @@ -231,7 +238,7 @@ function install( $args, $assoc_args ) { } break; case 'newer_installed': - WP_CLI::error( sprintf( 'Newer version ( %s ) installed', $status['version'] ) ); + WP_CLI::error( sprintf( 'Newer version (%s) installed', $status['version'] ) ); break; case 'latest_installed': WP_CLI::error( 'Latest version already installed' ); From d27f5b479aafb8ae63bbb460207724b8d0ab24a6 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 11 Dec 2011 21:21:54 +0200 Subject: [PATCH 0178/5359] document the --dev flag. see #45 --- src/php/wp-cli/commands/internals/plugin.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 1cb45955e..24e78c00a 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -349,16 +349,25 @@ public static function help() { WP_CLI::line( << [] or: wp plugin path [] [--directory] - or: wp plugin install [--activate] + or: wp plugin install [--activate] [--dev] Available sub-commands: status display status of all installed plugins or of a particular plugin + activate activate a particular plugin + deactivate deactivate a particular plugin + toggle toggle activation state of a particular plugin + path print path to the plugin's file + install install a plugin from wordpress.org + --activate activate the plugin after installing it + --dev install the development version + update update a plugin from wordpress.org + delete delete a plugin EOB ); From 51fff68164e696470d92984ad52f99c024b3d827 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 11 Dec 2011 21:25:19 +0200 Subject: [PATCH 0179/5359] document the --directory flag --- src/php/wp-cli/commands/internals/plugin.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 24e78c00a..9e26f7b82 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -361,10 +361,11 @@ public static function help() { toggle toggle activation state of a particular plugin path print path to the plugin's file + --directory get the path to the closest parent directory install install a plugin from wordpress.org - --activate activate the plugin after installing it - --dev install the development version + --activate activate the plugin after installing it + --dev install the development version update update a plugin from wordpress.org From da3ea7d2290ff3f3c2cae6e5723e0ee3e7cf7509 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 19 Dec 2011 18:48:14 +0200 Subject: [PATCH 0180/5359] make build-dev OS X compatible. fixes #48 --- utils/build-dev | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/utils/build-dev b/utils/build-dev index c1a39ad87..6b5d96744 100755 --- a/utils/build-dev +++ b/utils/build-dev @@ -1,4 +1,10 @@ #!/usr/bin/env bash -ln -s $(pwd)/src/bin/wp /usr/bin/wp -ln -s $(pwd)/utils/wp-completion.bash /etc/bash_completion.d/wp +ln -sf $(pwd)/src/bin/wp /usr/bin/wp + +for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do + if [ -d $dir ]; then + ln -sf $(pwd)/utils/wp-completion.bash $dir/wp + break + fi +done From 2b6d6f8ee6d6c3756f984c7eae5f0a3356762e17 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 20 Dec 2011 11:03:22 +0000 Subject: [PATCH 0181/5359] Add installation commands --- .../wp-cli/commands/internals/installer.php | 49 +++++++++++++++++++ src/php/wp-cli/wp-cli.php | 6 +++ 2 files changed, 55 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/installer.php diff --git a/src/php/wp-cli/commands/internals/installer.php b/src/php/wp-cli/commands/internals/installer.php new file mode 100644 index 000000000..9e6ad644a --- /dev/null +++ b/src/php/wp-cli/commands/internals/installer.php @@ -0,0 +1,49 @@ + --username= --password= --email_address= + or: wp installer is_installed +EOB + ); + } +} + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 8c3679bbe..e22011e69 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -67,6 +67,12 @@ $_SERVER['REQUEST_URI'] = '/' . $path; } +// Set installer flag before loading any Wordpress libs +$installing = count( $arguments ) > 0 && $arguments[0] === "installer"; +if ( $installing ) { + define( 'WP_INSTALLING', true ); +} + // Load WordPress libs require_once(WP_ROOT . 'wp-load.php'); require_once(ABSPATH . 'wp-admin/includes/admin.php'); From cbd6cc9cb909d756e613b66bddacc2d0d1ace34a Mon Sep 17 00:00:00 2001 From: Thorsten Ott Date: Wed, 21 Dec 2011 02:05:08 +0200 Subject: [PATCH 0182/5359] Migrating https://github.com/tott/WordPress-CLI-Exporter to the WP-CLI framework This should address https://github.com/andreascreten/wp-cli/issues/44 --- src/php/wp-cli/commands/internals/export.php | 522 +++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/export.php diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php new file mode 100644 index 000000000..3e7e91356 --- /dev/null +++ b/src/php/wp-cli/commands/internals/export.php @@ -0,0 +1,522 @@ + --user= + wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + +Required parameters: + --path Full Path to directory where WXR export files should be stored + --user Username/ID the import should run as + +Optional filters: + --start_date Export only posts new than this date in format YYYY-MM-DD + --end_date Export only posts older than this date in format YYYY-MM-DD + --post_type Export only posts with this post_type + --author Export only posts by this author + --category Export only posts in this category + --post_status Export only posts with this post_status + --skip_comments Don't export comments +EOB + ); + } + + private function dispatch() { + WP_CLI::line(); + WP_CLI::line( 'Starting export processs' ); + WP_CLI::line(); + $this->export_wp( $this->export_args ); + } + + + /** + * Argument validation functions below + */ + + public function validate_arguments( $args, $assoc_args ) { + $defaults = array( + 'path' => NULL, + 'user' => NULL, + 'start_date' => NULL, + 'end_date' => NULL, + 'post_type' => NULL, + 'author' => NULL, + 'category' => NULL, + 'post_status' => NULL, + 'skip_comments' => NULL, + ); + + $args = wp_parse_args( $assoc_args, $defaults ); + + $has_errors = false; + + foreach( $defaults as $argument => $default_value ) { + if ( is_callable( array( &$this, 'check_' . $argument ) ) ) { + $result = call_user_func( array( &$this, 'check_' . $argument ), $args[$argument] ); + if ( false === $result && false === $has_errors ) + $has_errors = true; + } + } + + if ( true === $has_errors ) { + WP_CLI::error( 'There were errors. Please review the items listed above' ); + exit; + } + + $this->wxr_path = $assoc_args['path']; + + $this->dispatch(); + } + + private function check_path( $path ) { + if ( empty( $path ) ) { + $this->help(); + exit; + } + + if ( !is_dir( $path ) ) { + WP_CLI::error( sprintf( "The path %s does not exist", $path ) ); + exit; + } + + return true; + } + + private function check_user( $user ) { + if ( empty( $user ) ) { + $this->help(); + exit; + } + + if ( is_numeric( $user ) ) { + $user_id = (int) $user; + } else { + $user_id = (int) username_exists( $user ); + } + if ( !$user_id || !wp_set_current_user( $user_id ) ) { + WP_CLI::error( sprintf( "Could not get a user_id for this user: %s", var_export( $user_id, true ) ) ); + exit; + } + + $current_user = wp_get_current_user(); + $this->user_id = (int) $user_id; + + return true; + } + + private function check_start_date( $date ) { + if ( is_null( $date ) ) + return true; + + $time = strtotime( $date ); + if ( !empty( $date ) && !$time ) { + WP_CLI::warning( sprintf( "The start_date %s is invalid", $date ) ); + return false; + } + $this->export_args['start_date'] = date( 'Y-m-d', $time ); + return true; + } + + private function check_end_date( $date ) { + if ( is_null( $date ) ) + return true; + + $time = strtotime( $date ); + if ( !empty( $date ) && !$time ) { + WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) ); + return false; + } + $this->export_args['start_date'] = date( 'Y-m-d', $time ); + return true; + } + + private function check_post_type( $post_type ) { + if ( is_null( $post_type ) ) + return true; + + $post_types = get_post_types(); + if ( !in_array( $post_type, $post_types ) ) { + WP_CLI::warning( sprintf( 'The post type %s does not exists. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); + return false; + } + $this->export_args['content'] = $post_type; + return true; + } + + private function check_author( $author ) { + if ( is_null( $author ) ) + return true; + + $authors = get_users_of_blog(); + if ( empty( $authors ) || is_wp_error( $authors ) ) { + WP_CLI::warning( sprintf( "Could not find any authors in this blog" ) ); + return false; + } + $hit = false; + foreach( $authors as $user ) { + if ( $hit ) + break; + if ( (int) $author == $user->ID || $author == $user->user_login ) + $hit = $user->ID; + } + if ( false === $hit ) { + $authors_nice = array(); + foreach( $authors as $_author ) + $authors_nice[] = sprintf( '%s (%s)', $_author->user_login, $_author->display_name ); + WP_CLI::warning( sprintf( 'Could not find a matching author for %s. The following authors exist: %s', $author, implode( ", ", $authors_nice ) ) ); + return false; + } + + $this->export_args['author'] = $hit; + return true; + } + + private function check_category( $category ) { + if ( is_null( $category ) ) + return true; + + $term = category_exists( $category ); + if ( empty( $term ) || is_wp_error( $term ) ) { + WP_CLI::warning( sprintf( 'Could not find a category matching %s', $category ) ); + return false; + } + $this->export_args['category'] = $category; + return true; + } + + private function check_post_status( $status ) { + if ( is_null( $status ) ) + return true; + + $stati = get_post_statuses(); + if ( empty( $stati ) || is_wp_error( $stati ) ) { + WP_CLI::warning( sprintf( 'Could not find any post stati', $category ) ); + return false; + } + + if ( !isset( $stati[$status] ) ) { + WP_CLI::warning( sprintf( 'Could not find a post_status matching %s. Here is a list of available stati: %s', $status, implode( ", ", array_keys( $stati ) ) ) ); + return false; + } + $this->export_args['status'] = $status; + return true; + } + + private function check_skip_comments( $skip ) { + if ( is_null( $skip ) ) + return true; + + if ( (int) $skip <> 0 && (int) $skip <> 1 ) { + WP_CLI::warning( sprintf( 'skip_comments needs to be 0 (no) or 1 (yes)', $category ) ); + return false; + } + $this->export_args['skip_comments'] = $skip; + return true; + } + + + /** + * Workaround to prevent memory leaks from growing variables + */ + + private function stop_the_insanity() { + global $wpdb, $wp_object_cache; + $wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); + if ( !is_object( $wp_object_cache ) ) + return; + $wp_object_cache->group_ops = array(); + $wp_object_cache->stats = array(); + $wp_object_cache->memcache_debug = array(); + $wp_object_cache->cache = array(); + $wp_object_cache->__remoteset(); // important + } + + /** + * Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php + */ + + private function export_wp( $args = array() ) { + require_once ABSPATH . 'wp-admin/includes/export.php'; + + global $wpdb, $post; + // call export_wp as we need the functions defined in it. + $dummy_args = array( 'content' => 'i-do-not-exist' ); + ob_start(); + export_wp( $dummy_args ); + ob_end_clean(); + + /** + * This is mostly the original code of export_wp defined in wp-admin/includes/export.php + */ + $defaults = array( 'content' => 'all', 'author' => false, 'category' => false, + 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, + ); + $args = wp_parse_args( $args, $defaults ); + + WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); + + do_action( 'export_wp' ); + + $sitename = sanitize_key( get_bloginfo( 'name' ) ); + if ( ! empty( $sitename ) ) + $sitename .= '.'; + + $append = array( date( 'Y-m-d' ) ); + foreach( array_keys( $args ) as $arg_key ) { + if ( $defaults[$arg_key] <> $args[$arg_key] ) + $append[]= "$arg_key-" . (string) $args[$arg_key]; + } + $file_name_base = $sitename . 'wordpress.' . implode( ".", $append ); + + if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) { + $ptype = get_post_type_object( $args['content'] ); + if ( ! $ptype->can_export ) + $args['content'] = 'post'; + + $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] ); + } else { + $post_types = get_post_types( array( 'can_export' => true ) ); + $esses = array_fill( 0, count( $post_types ), '%s' ); + $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); + } + + if ( $args['status'] && ( 'post' == $args['content'] || 'page' == $args['content'] ) ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] ); + else + $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; + + $join = ''; + if ( $args['category'] && 'post' == $args['content'] ) { + if ( $term = term_exists( $args['category'], 'category' ) ) { + $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)"; + $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] ); + } + } + + if ( 'post' == $args['content'] || 'page' == $args['content'] ) { + if ( $args['author'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); + + if ( $args['start_date'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); + + if ( $args['end_date'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( '+1 month', strtotime( $args['end_date'] ) ) ) ); + } + + // grab a snapshot of post IDs, just in case it changes during the export + $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); + + // get the requested terms ready, empty unless posts filtered by category or all content + $cats = $tags = $terms = array(); + if ( isset( $term ) && $term ) { + $cat = get_term( $term['term_id'], 'category' ); + $cats = array( $cat->term_id => $cat ); + unset( $term, $cat ); + } else if ( 'all' == $args['content'] ) { + $categories = (array) get_categories( array( 'get' => 'all' ) ); + $tags = (array) get_tags( array( 'get' => 'all' ) ); + + $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); + $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); + + // put categories in order with no child going before its parent + while ( $cat = array_shift( $categories ) ) { + if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) + $cats[$cat->term_id] = $cat; + else + $categories[] = $cat; + } + + // put terms in order with no child going before its parent + while ( $t = array_shift( $custom_terms ) ) { + if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) + $terms[$t->term_id] = $t; + else + $custom_terms[] = $t; + } + + unset( $categories, $custom_taxonomies, $custom_terms ); + } + + + WP_CLI::line( 'Exporting ' . count( $post_ids ) . ' items' ); + WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); + WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); + WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); + WP_CLI::line(); + + $progress = $this->progress_bar( 'exporting', count( $post_ids ) ); + + ob_start(); + echo '\n"; + +?> + + + + + + + + + + + + + + + + + + + + + + <?php bloginfo_rss( 'name' ); ?> + + + + + + + + + + + + term_id ?>slug; ?>parent ? $cats[$c->parent]->slug : ''; ?> + + + term_id ?>slug; ?> + + + term_id ?>taxonomy; ?>slug; ?>parent ? $terms[$t->parent]->slug : ''; ?> + + + + + +in_the_loop = true; // Fake being in the loop. + + // fetch 20 posts at a time rather than loading the entire table into memory + while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { + + $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; + $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); + + // Begin Loop + foreach ( $posts as $post ) { + + $progress->tick(); + + setup_postdata( $post ); + $is_sticky = is_sticky( $post->ID ) ? 1 : 0; +?> + + <?php echo apply_filters( 'the_title_rss', $post->post_title ); ?> + + + + + + post_content ) ); ?> + post_excerpt ) ); ?> + ID; ?> + post_date; ?> + post_date_gmt; ?> + comment_status; ?> + ping_status; ?> + post_name; ?> + post_status; ?> + post_parent; ?> + menu_order; ?> + post_type; ?> + post_password; ?> + +post_type == 'attachment' ) : ?> + ID ); ?> + + +get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); + foreach ( $postmeta as $meta ) : if ( $meta->meta_key != '_edit_lock' ) : ?> + + meta_key; ?> + meta_value ); ?> + + + +get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); + foreach ( $comments as $c ) : ?> + + comment_ID; ?> + comment_author ); ?> + comment_author_email; ?> + comment_author_url ); ?> + comment_author_IP; ?> + comment_date; ?> + comment_date_gmt; ?> + comment_content ) ?> + comment_approved; ?> + comment_type; ?> + comment_parent; ?> + user_id; ?> +get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); + foreach ( $c_meta as $meta ) : ?> + + meta_key; ?> + meta_value ); ?> + + + + + + + + + +wxr_path . $file_name_base . '.wxr'; + + if ( !file_exists( $full_path ) || is_writeable( $full_path ) ) { + WP_CLI::line( 'Writing to ' . $full_path ); + file_put_contents( $full_path, $result ); + } + } + + /** + * Implement progress bar + */ + private function progress_bar( $title, $total, $interval = 100 ) { + return new \cli\progress\Bar( $title, $total, $interval ); + } + +} \ No newline at end of file From 233c387f8b0b949d1a1ba9860be43dd10f5f215e Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 21 Dec 2011 03:52:25 +0200 Subject: [PATCH 0183/5359] fix allignment in export help method; see #44 --- src/php/wp-cli/commands/internals/export.php | 118 +++++++++---------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 3e7e91356..9ac685487 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -10,15 +10,13 @@ */ class ExportCommand extends WP_CLI_Command { protected $default_subcommand = 'validate_arguments'; - + public $export_args = array(); - - public static function help() { - WP_CLI::warning( << --user= - wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + public static function help() { + WP_CLI::line( << --user= + or: wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 Required parameters: --path Full Path to directory where WXR export files should be stored @@ -42,12 +40,12 @@ private function dispatch() { WP_CLI::line(); $this->export_wp( $this->export_args ); } - - + + /** * Argument validation functions below */ - + public function validate_arguments( $args, $assoc_args ) { $defaults = array( 'path' => NULL, @@ -62,47 +60,47 @@ public function validate_arguments( $args, $assoc_args ) { ); $args = wp_parse_args( $assoc_args, $defaults ); - + $has_errors = false; - + foreach( $defaults as $argument => $default_value ) { if ( is_callable( array( &$this, 'check_' . $argument ) ) ) { $result = call_user_func( array( &$this, 'check_' . $argument ), $args[$argument] ); if ( false === $result && false === $has_errors ) $has_errors = true; } - } - + } + if ( true === $has_errors ) { WP_CLI::error( 'There were errors. Please review the items listed above' ); exit; } - + $this->wxr_path = $assoc_args['path']; - + $this->dispatch(); } - + private function check_path( $path ) { if ( empty( $path ) ) { $this->help(); exit; } - + if ( !is_dir( $path ) ) { WP_CLI::error( sprintf( "The path %s does not exist", $path ) ); exit; } - + return true; } - + private function check_user( $user ) { if ( empty( $user ) ) { $this->help(); exit; } - + if ( is_numeric( $user ) ) { $user_id = (int) $user; } else { @@ -115,14 +113,14 @@ private function check_user( $user ) { $current_user = wp_get_current_user(); $this->user_id = (int) $user_id; - + return true; } - + private function check_start_date( $date ) { if ( is_null( $date ) ) return true; - + $time = strtotime( $date ); if ( !empty( $date ) && !$time ) { WP_CLI::warning( sprintf( "The start_date %s is invalid", $date ) ); @@ -131,11 +129,11 @@ private function check_start_date( $date ) { $this->export_args['start_date'] = date( 'Y-m-d', $time ); return true; } - + private function check_end_date( $date ) { if ( is_null( $date ) ) return true; - + $time = strtotime( $date ); if ( !empty( $date ) && !$time ) { WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) ); @@ -144,11 +142,11 @@ private function check_end_date( $date ) { $this->export_args['start_date'] = date( 'Y-m-d', $time ); return true; } - + private function check_post_type( $post_type ) { if ( is_null( $post_type ) ) return true; - + $post_types = get_post_types(); if ( !in_array( $post_type, $post_types ) ) { WP_CLI::warning( sprintf( 'The post type %s does not exists. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); @@ -157,11 +155,11 @@ private function check_post_type( $post_type ) { $this->export_args['content'] = $post_type; return true; } - + private function check_author( $author ) { if ( is_null( $author ) ) return true; - + $authors = get_users_of_blog(); if ( empty( $authors ) || is_wp_error( $authors ) ) { WP_CLI::warning( sprintf( "Could not find any authors in this blog" ) ); @@ -181,15 +179,15 @@ private function check_author( $author ) { WP_CLI::warning( sprintf( 'Could not find a matching author for %s. The following authors exist: %s', $author, implode( ", ", $authors_nice ) ) ); return false; } - + $this->export_args['author'] = $hit; return true; } - + private function check_category( $category ) { if ( is_null( $category ) ) return true; - + $term = category_exists( $category ); if ( empty( $term ) || is_wp_error( $term ) ) { WP_CLI::warning( sprintf( 'Could not find a category matching %s', $category ) ); @@ -198,17 +196,17 @@ private function check_category( $category ) { $this->export_args['category'] = $category; return true; } - + private function check_post_status( $status ) { if ( is_null( $status ) ) return true; - + $stati = get_post_statuses(); if ( empty( $stati ) || is_wp_error( $stati ) ) { WP_CLI::warning( sprintf( 'Could not find any post stati', $category ) ); return false; } - + if ( !isset( $stati[$status] ) ) { WP_CLI::warning( sprintf( 'Could not find a post_status matching %s. Here is a list of available stati: %s', $status, implode( ", ", array_keys( $stati ) ) ) ); return false; @@ -216,11 +214,11 @@ private function check_post_status( $status ) { $this->export_args['status'] = $status; return true; } - + private function check_skip_comments( $skip ) { if ( is_null( $skip ) ) return true; - + if ( (int) $skip <> 0 && (int) $skip <> 1 ) { WP_CLI::warning( sprintf( 'skip_comments needs to be 0 (no) or 1 (yes)', $category ) ); return false; @@ -228,12 +226,12 @@ private function check_skip_comments( $skip ) { $this->export_args['skip_comments'] = $skip; return true; } - - + + /** * Workaround to prevent memory leaks from growing variables */ - + private function stop_the_insanity() { global $wpdb, $wp_object_cache; $wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); @@ -245,21 +243,21 @@ private function stop_the_insanity() { $wp_object_cache->cache = array(); $wp_object_cache->__remoteset(); // important } - + /** * Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php */ - + private function export_wp( $args = array() ) { require_once ABSPATH . 'wp-admin/includes/export.php'; - + global $wpdb, $post; // call export_wp as we need the functions defined in it. $dummy_args = array( 'content' => 'i-do-not-exist' ); ob_start(); export_wp( $dummy_args ); ob_end_clean(); - + /** * This is mostly the original code of export_wp defined in wp-admin/includes/export.php */ @@ -269,7 +267,7 @@ private function export_wp( $args = array() ) { $args = wp_parse_args( $args, $defaults ); WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); - + do_action( 'export_wp' ); $sitename = sanitize_key( get_bloginfo( 'name' ) ); @@ -282,7 +280,7 @@ private function export_wp( $args = array() ) { $append[]= "$arg_key-" . (string) $args[$arg_key]; } $file_name_base = $sitename . 'wordpress.' . implode( ".", $append ); - + if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) { $ptype = get_post_type_object( $args['content'] ); if ( ! $ptype->can_export ) @@ -321,7 +319,7 @@ private function export_wp( $args = array() ) { // grab a snapshot of post IDs, just in case it changes during the export $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); - + // get the requested terms ready, empty unless posts filtered by category or all content $cats = $tags = $terms = array(); if ( isset( $term ) && $term ) { @@ -354,13 +352,13 @@ private function export_wp( $args = array() ) { unset( $categories, $custom_taxonomies, $custom_terms ); } - + WP_CLI::line( 'Exporting ' . count( $post_ids ) . ' items' ); WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); WP_CLI::line(); - + $progress = $this->progress_bar( 'exporting', count( $post_ids ) ); ob_start(); @@ -424,15 +422,15 @@ private function export_wp( $args = array() ) { // fetch 20 posts at a time rather than loading the entire table into memory while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { - + $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); // Begin Loop foreach ( $posts as $post ) { - + $progress->tick(); - + setup_postdata( $post ); $is_sticky = is_sticky( $post->ID ) ? 1 : 0; ?> @@ -503,20 +501,20 @@ private function export_wp( $args = array() ) { wxr_path . $file_name_base . '.wxr'; - + if ( !file_exists( $full_path ) || is_writeable( $full_path ) ) { WP_CLI::line( 'Writing to ' . $full_path ); file_put_contents( $full_path, $result ); } } - - /** - * Implement progress bar + + /** + * Implement progress bar */ private function progress_bar( $title, $total, $interval = 100 ) { return new \cli\progress\Bar( $title, $total, $interval ); } - -} \ No newline at end of file + +} From ca4c14c4ebf5e621526ccf5a21e6be571e8bda6a Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 21 Dec 2011 03:56:35 +0200 Subject: [PATCH 0184/5359] more specific warnings. see #44 --- src/php/wp-cli/commands/internals/export.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 9ac685487..7ecaa5d47 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -72,7 +72,6 @@ public function validate_arguments( $args, $assoc_args ) { } if ( true === $has_errors ) { - WP_CLI::error( 'There were errors. Please review the items listed above' ); exit; } @@ -83,8 +82,8 @@ public function validate_arguments( $args, $assoc_args ) { private function check_path( $path ) { if ( empty( $path ) ) { - $this->help(); - exit; + WP_CLI::warning( 'missing --path parameter' ); + return false; } if ( !is_dir( $path ) ) { @@ -97,8 +96,8 @@ private function check_path( $path ) { private function check_user( $user ) { if ( empty( $user ) ) { - $this->help(); - exit; + WP_CLI::warning( 'missing --user parameter' ); + return false; } if ( is_numeric( $user ) ) { From 5d4cd7823d80a823c2a83f036a1a84aff0c656d3 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 21 Dec 2011 14:06:04 +0000 Subject: [PATCH 0185/5359] Move installation commands to core --- src/php/wp-cli/commands/internals/core.php | 36 ++++++++++++++ .../wp-cli/commands/internals/installer.php | 49 ------------------- src/php/wp-cli/wp-cli.php | 5 +- 3 files changed, 40 insertions(+), 50 deletions(-) delete mode 100644 src/php/wp-cli/commands/internals/installer.php diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 3d0cf2b76..e05284c6b 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -2,6 +2,8 @@ WP_CLI::addCommand('core', 'CoreCommand'); +require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + /** * Implement core command * @@ -73,6 +75,38 @@ function update($args) { WP_CLI::success('WordPress upgraded successfully.'); } } + + public function install( $args, $assoc_args ) { + if ( is_blog_installed() ) { + WP_CLI::error( 'Wordpress is already installed.' ); + exit( 1 ); + } + $site_title = $assoc_args["site_title"]; + $username = $assoc_args["username"]; + $admin_email = $assoc_args["email_address"]; + $public = true; + $admin_password = $assoc_args["password"]; + + if ( ! $site_title || ! $username || ! $admin_email || ! $admin_password ) { + WP_CLI::error( 'Missing installation arguments' ); + exit( 1 ); + } + + $result = wp_install( $site_title, $username, $admin_email, $public, '', $admin_password ); + if ( is_wp_error( $result ) ) { + WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); + } else { + WP_CLI::success( 'WordPress installed successfully.' ); + } + } + + public function is_installed( $filename ) { + if ( is_blog_installed() ) { + exit( 0 ); + } else { + exit( 1 ); + } + } /** * Help function for this command @@ -81,6 +115,8 @@ public static function help() { WP_CLI::line( << --username= --password= --email_address= + or: wp core is_installed EOB ); } diff --git a/src/php/wp-cli/commands/internals/installer.php b/src/php/wp-cli/commands/internals/installer.php deleted file mode 100644 index 9e6ad644a..000000000 --- a/src/php/wp-cli/commands/internals/installer.php +++ /dev/null @@ -1,49 +0,0 @@ - --username= --password= --email_address= - or: wp installer is_installed -EOB - ); - } -} - diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e22011e69..964d04d7f 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -68,7 +68,10 @@ } // Set installer flag before loading any Wordpress libs -$installing = count( $arguments ) > 0 && $arguments[0] === "installer"; +$installing = count( $arguments ) >= 2 && + $arguments[0] === "core" && + ($arguments[1] === "install" || $arguments[1] == "is_installed"); + if ( $installing ) { define( 'WP_INSTALLING', true ); } From fef05208fd6f198ec3a7643a31329c72bc9dde1d Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 21 Dec 2011 14:22:06 +0000 Subject: [PATCH 0186/5359] Add some documentation for the two installer commands --- src/php/wp-cli/commands/internals/core.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index e05284c6b..2c544732d 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -76,6 +76,9 @@ function update($args) { } } + /** + * Run wp_install. Assumes that wp-config.php is already in place. + */ public function install( $args, $assoc_args ) { if ( is_blog_installed() ) { WP_CLI::error( 'Wordpress is already installed.' ); @@ -100,7 +103,11 @@ public function install( $args, $assoc_args ) { } } - public function is_installed( $filename ) { + /** + * Determine if Wordpress is already installed. Exits with 0 if + * Wordpress is installed, 1 if not. + */ + public function is_installed() { if ( is_blog_installed() ) { exit( 0 ); } else { From efcb90d1e308089930af76e83317643ca9e59e6d Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 21 Dec 2011 19:07:36 +0200 Subject: [PATCH 0187/5359] add `wp plugin uninstall`. fixes #52 --- src/php/wp-cli/commands/internals/plugin.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 9e26f7b82..205d16200 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -246,6 +246,17 @@ function install( $args, $assoc_args ) { } } + /** + * Uninstall a plugin + * + * @param array $args + */ + function uninstall( $args ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + uninstall_plugin( $file ); + } + /** * Delete a plugin * @@ -369,6 +380,8 @@ public static function help() { update update a plugin from wordpress.org + uninstall run the uninstallation procedure for a plugin + delete delete a plugin EOB ); From 0d2376a3e35a4234a4190870cd4203df2a91f01f Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 21 Dec 2011 20:05:44 +0200 Subject: [PATCH 0188/5359] don't attempt to uninstall active plugin. see #52 --- src/php/wp-cli/commands/internals/plugin.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 205d16200..cc68549d3 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -254,6 +254,10 @@ function install( $args, $assoc_args ) { function uninstall( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + if ( is_plugin_active( $file ) ) { + WP_CLI::error( 'The plugin is active.' ); + } + uninstall_plugin( $file ); } From 30f56f51daf58ae3b873f246762840fdce9c30bf Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 22 Dec 2011 14:49:06 +0200 Subject: [PATCH 0189/5359] remove is_installed command. see #51 --- src/php/wp-cli/commands/internals/core.php | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 2c544732d..22e4aac27 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -75,7 +75,7 @@ function update($args) { WP_CLI::success('WordPress upgraded successfully.'); } } - + /** * Run wp_install. Assumes that wp-config.php is already in place. */ @@ -89,12 +89,12 @@ public function install( $args, $assoc_args ) { $admin_email = $assoc_args["email_address"]; $public = true; $admin_password = $assoc_args["password"]; - + if ( ! $site_title || ! $username || ! $admin_email || ! $admin_password ) { WP_CLI::error( 'Missing installation arguments' ); exit( 1 ); } - + $result = wp_install( $site_title, $username, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); @@ -103,18 +103,6 @@ public function install( $args, $assoc_args ) { } } - /** - * Determine if Wordpress is already installed. Exits with 0 if - * Wordpress is installed, 1 if not. - */ - public function is_installed() { - if ( is_blog_installed() ) { - exit( 0 ); - } else { - exit( 1 ); - } - } - /** * Help function for this command */ @@ -123,8 +111,8 @@ public static function help() { usage: wp core update or: wp core version [--extra] or: wp core install --site_title= --username= --password= --email_address= - or: wp core is_installed EOB ); } } + From 3224eee095ea943b40b536e720fb6be9f02473bf Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 22 Dec 2011 14:50:31 +0200 Subject: [PATCH 0190/5359] capital P dammit --- src/php/wp-cli/commands/internals/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 22e4aac27..bcb68ec4f 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -81,9 +81,9 @@ function update($args) { */ public function install( $args, $assoc_args ) { if ( is_blog_installed() ) { - WP_CLI::error( 'Wordpress is already installed.' ); - exit( 1 ); + WP_CLI::error( 'WordPress is already installed.' ); } + $site_title = $assoc_args["site_title"]; $username = $assoc_args["username"]; $admin_email = $assoc_args["email_address"]; From b706d3128713d7a120abe6a819b0c0c415abda5b Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 22 Dec 2011 15:03:28 +0200 Subject: [PATCH 0191/5359] standardize parameter names; make admin name optional. see #51 --- src/php/wp-cli/commands/internals/core.php | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index bcb68ec4f..fcddfcc38 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -84,18 +84,28 @@ public function install( $args, $assoc_args ) { WP_CLI::error( 'WordPress is already installed.' ); } - $site_title = $assoc_args["site_title"]; - $username = $assoc_args["username"]; - $admin_email = $assoc_args["email_address"]; + extract( wp_parse_args( $assoc_args, array( + 'site_title' => '', + 'admin_name' => 'admin', + 'admin_email' => '', + 'admin_password' => '' + ) ), EXTR_SKIP ); + + $missing = false; + foreach ( array( 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { + if ( empty( $$required_arg ) ) { + WP_CLI::warning( "missing --$required_arg parameter" ); + $missing = true; + } + } + + if ( $missing ) + exit(1); + $public = true; - $admin_password = $assoc_args["password"]; - if ( ! $site_title || ! $username || ! $admin_email || ! $admin_password ) { - WP_CLI::error( 'Missing installation arguments' ); - exit( 1 ); - } + $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); - $result = wp_install( $site_title, $username, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); } else { @@ -110,7 +120,7 @@ public static function help() { WP_CLI::line( << --username= --password= --email_address= + or: wp core install --site_title= [--admin_name=] --admin_password= --admin_email= EOB ); } From 159acd1ffa60f5d0ffac6fcb788cf498dbbe7d6a Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 22 Dec 2011 15:21:05 +0200 Subject: [PATCH 0192/5359] add necessary site_url parameter. see #51 --- src/php/wp-cli/class-wp-cli.php | 16 ++++++++++++++++ src/php/wp-cli/commands/internals/core.php | 8 ++++++-- src/php/wp-cli/wp-cli.php | 17 +++-------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 56967f960..d71b12feb 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -143,6 +143,22 @@ static function legend( $legend ) { WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } + /** + * Sets the appropriate $_SERVER keys based on a given string + * + * @param string $url The URL + */ + static function set_url( $url ) { + if ( false === strpos( $url, '/' ) ) + $url .= '/'; + + list( $domain, $path ) = explode( '/', $url, 2 ); + + $_SERVER['HTTP_HOST'] = $domain; + + $_SERVER['REQUEST_URI'] = '/' . $path; + } + /** * Return the beginning of the status line for a certain plugin or theme * diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index fcddfcc38..4fff92ca6 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -85,6 +85,7 @@ public function install( $args, $assoc_args ) { } extract( wp_parse_args( $assoc_args, array( + 'site_url' => defined( 'WP_SITEURL' ) ? WP_SITEURL : '', 'site_title' => '', 'admin_name' => 'admin', 'admin_email' => '', @@ -92,13 +93,16 @@ public function install( $args, $assoc_args ) { ) ), EXTR_SKIP ); $missing = false; - foreach ( array( 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { + foreach ( array( 'site_url', 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { if ( empty( $$required_arg ) ) { WP_CLI::warning( "missing --$required_arg parameter" ); $missing = true; } } + if ( $site_url ) + WP_CLI::set_url( $site_url ); + if ( $missing ) exit(1); @@ -120,7 +124,7 @@ public static function help() { WP_CLI::line( << [--admin_name=] --admin_password= --admin_email= + or: wp core install --site_url=example.com --site_title= [--admin_name=] --admin_password= --admin_email= EOB ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 964d04d7f..58b8a8f0b 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -57,22 +57,11 @@ } if ( isset( $blog ) ) { - if ( false === strpos( $blog, '/' ) ) - $blog .= '/'; - - list( $domain, $path ) = explode( '/', $blog, 2 ); - - $_SERVER['HTTP_HOST'] = $domain; - - $_SERVER['REQUEST_URI'] = '/' . $path; + WP_CLI::set_url( $blog ); } -// Set installer flag before loading any Wordpress libs -$installing = count( $arguments ) >= 2 && - $arguments[0] === "core" && - ($arguments[1] === "install" || $arguments[1] == "is_installed"); - -if ( $installing ) { +// Set installer flag before loading any WP files +if ( $arguments[0] == 'core' && $arguments[1] == 'install' ) { define( 'WP_INSTALLING', true ); } From 23671f538e54fd74f03e9a3ae2db9eebf3a04939 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 22 Dec 2011 15:24:57 +0200 Subject: [PATCH 0193/5359] add preliminary changelog for 0.4 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 3583bdd8d..6e35d9f95 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,14 @@ You can find more information about adding commands in the [Commands Cookbook](h Changelog --------------- +**0.4** + +- added `wp eval` and `wp eval-file` +- added `wp export` +- added `wp core install` +- added `--dev` flag to `wp plugin install` +- added `wp plugin uninstall` + **0.3** - added `wp sql` From 930f1f0cbf92f6dcfb5d8017745d2f1b2dd5432d Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 26 Dec 2011 15:12:26 +0200 Subject: [PATCH 0194/5359] prevent notice when checking for install sub-command --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 58b8a8f0b..578f51d43 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -61,7 +61,7 @@ } // Set installer flag before loading any WP files -if ( $arguments[0] == 'core' && $arguments[1] == 'install' ) { +if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { define( 'WP_INSTALLING', true ); } From 01cc90655f154994c5595f62042c473f4570aeed Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 26 Dec 2011 16:26:05 +0200 Subject: [PATCH 0195/5359] require upgrade.php only when doing the upgrade --- src/php/wp-cli/commands/internals/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 4fff92ca6..049c7fe0e 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -2,8 +2,6 @@ WP_CLI::addCommand('core', 'CoreCommand'); -require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - /** * Implement core command * @@ -52,6 +50,8 @@ public function version( $args = array(), $assoc_args = array() ) { * @param array $args */ function update($args) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + WP_CLI::line('Updating the WordPress core.'); if(!class_exists('Core_Upgrader')) { From 3b0e12c8a6f1e08ad7c93c6a8517ee2b5bf97212 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 26 Dec 2011 16:44:35 +0200 Subject: [PATCH 0196/5359] load plugin files only when the plugin command is invoked --- src/php/wp-cli/commands/internals/plugin.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index cc68549d3..c5e12664a 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -2,9 +2,6 @@ WP_CLI::addCommand('plugin', 'PluginCommand'); -require_once(ABSPATH.'wp-admin/includes/plugin.php'); -require_once(ABSPATH.'wp-admin/includes/plugin-install.php'); - /** * Implement plugin command * @@ -17,6 +14,13 @@ class PluginCommand extends WP_CLI_Command { private $mu_plugins; + function __construct( $args, $assoc_args ) { + require_once ABSPATH.'wp-admin/includes/plugin.php'; + require_once ABSPATH.'wp-admin/includes/plugin-install.php'; + + parent::__construct( $args, $assoc_args ); + } + /** * Get the status of one or all plugins * From 9ac855708994aa9d474e58b3d8e8c62dcd8d9310 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 26 Dec 2011 18:07:23 +0300 Subject: [PATCH 0197/5359] move CLI_Upgrader_Skin to separate file; add get_upgrader() helper --- src/php/wp-cli/class-cli-upgrader-skin.php | 73 ++++++++++++++++++++ src/php/wp-cli/class-wp-cli.php | 73 ++------------------ src/php/wp-cli/commands/internals/core.php | 5 +- src/php/wp-cli/commands/internals/plugin.php | 11 +-- 4 files changed, 82 insertions(+), 80 deletions(-) create mode 100644 src/php/wp-cli/class-cli-upgrader-skin.php diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php new file mode 100644 index 000000000..b9967c18c --- /dev/null +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -0,0 +1,73 @@ + '', 'nonce' => '', 'title' => '', 'context' => false ); + $this->options = wp_parse_args( $args, $defaults ); + } + + function set_upgrader( &$upgrader ) { + if( is_object( $upgrader ) ) { + $this->upgrader =& $upgrader; + } + + $this->add_strings(); + } + + function add_strings() {} + + function set_result( $result ) { + $this->result = $result; + } + + function request_filesystem_credentials( $error = false ) { + $url = $this->options['url']; + $context = $this->options['context']; + if( !empty( $this->options['nonce'] ) ) { + $url = wp_nonce_url( $url, $this->options['nonce']) ; + } + + // Possible to bring inline, Leaving as is for now. + return request_filesystem_credentials( $url, '', $error, $context ); + } + + function header() {} + function footer() {} + + function error( $errors ) { + $this->feedback( WP_CLI::errorToString($errors) ); + } + + function feedback( $string ) { + if(isset( $this->upgrader->strings[$string] ) ) + $string = $this->upgrader->strings[$string]; + + if( strpos( $string, '%' ) !== false ) { + $args = func_get_args(); + $args = array_splice( $args, 1 ); + if( !empty( $args ) ) { + $string = vsprintf( $string, $args ); + } + + } + + if( empty( $string ) ) { + return; + } + + echo $string; + } + + function before() {} + function after() {} +} + diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d71b12feb..e75f6b86c 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -175,75 +175,14 @@ static function get_update_status( $item, $key ) { return false; } -} - -/** - * A Upgrader Skin for WordPress that only generates plain-text - * - * @package wp-cli - */ -class CLI_Upgrader_Skin { - var $upgrader; - var $done_header = false; - var $result = false; - - function __construct( $args = array() ) { - $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); - $this->options = wp_parse_args( $args, $defaults ); - } - - function set_upgrader( &$upgrader ) { - if( is_object( $upgrader ) ) { - $this->upgrader =& $upgrader; - } - - $this->add_strings(); - } - - function add_strings() {} - - function set_result( $result ) { - $this->result = $result; - } - function request_filesystem_credentials( $error = false ) { - $url = $this->options['url']; - $context = $this->options['context']; - if( !empty( $this->options['nonce'] ) ) { - $url = wp_nonce_url( $url, $this->options['nonce']) ; - } - - // Possible to bring inline, Leaving as is for now. - return request_filesystem_credentials( $url, '', $error, $context ); - } - - function header() {} - function footer() {} - - function error( $errors ) { - $this->feedback( WP_CLI::errorToString($errors) ); - } - - function feedback( $string ) { - if(isset( $this->upgrader->strings[$string] ) ) - $string = $this->upgrader->strings[$string]; + static function get_upgrader( $class ) { + if ( !class_exists( 'WP_Upgrader' ) ) + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - if( strpos( $string, '%' ) !== false ) { - $args = func_get_args(); - $args = array_splice( $args, 1 ); - if( !empty( $args ) ) { - $string = vsprintf( $string, $args ); - } - - } + require WP_CLI_ROOT . '/class-cli-upgrader-skin.php'; - if( empty( $string ) ) { - return; - } - - echo $string; + return new $class( new CLI_Upgrader_Skin ); } - - function before() {} - function after() {} } + diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 049c7fe0e..3d5e27a07 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -54,11 +54,8 @@ function update($args) { WP_CLI::line('Updating the WordPress core.'); - if(!class_exists('Core_Upgrader')) { - require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); - } ob_start(); - $upgrader = new Core_Upgrader(new CLI_Upgrader_Skin); + $upgrader = WP_CLI::get_upgrader( 'Core_Upgrader' ); $result = $upgrader->upgrade($current); $feedback = ob_get_clean(); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index c5e12664a..d2751b100 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -221,13 +221,10 @@ function install( $args, $assoc_args ) { switch ( $status['status'] ) { case 'update_available': case 'install': - if ( !class_exists( 'Plugin_Upgrader' ) ) { - require_once( ABSPATH.'wp-admin/includes/class-wp-upgrader.php' ); - } // Install the plugin ob_start( 'strip_tags' ); - $upgrader = new Plugin_Upgrader( new CLI_Upgrader_Skin ); + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); $result = $upgrader->install( $api->download_link ); $feedback = ob_get_clean(); @@ -289,15 +286,11 @@ function update( $args ) { // Force WordPress to update the plugin list wp_update_plugins(); - if ( !class_exists( 'Plugin_Upgrader' ) ) { - require_once( ABSPATH.'wp-admin/includes/class-wp-upgrader.php' ); - } - WP_CLI::line( 'Updating '.$name ); // Upgrading the plugin ob_start( 'strip_tags' ); - $upgrader = new Plugin_Upgrader( new CLI_Upgrader_Skin ); + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); $result = $upgrader->upgrade( $file ); $feedback = ob_get_clean(); From 7e0f7de6857a5f5d636d28a165884003bbaeaa7b Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 28 Dec 2011 13:05:59 +0200 Subject: [PATCH 0198/5359] revamp plugin upgrader handling. fixes #53 --- src/php/wp-cli/class-cli-upgrader-skin.php | 66 ++++++-------------- src/php/wp-cli/commands/internals/plugin.php | 55 +++++----------- 2 files changed, 35 insertions(+), 86 deletions(-) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index b9967c18c..d59958c6b 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -5,69 +5,41 @@ * * @package wp-cli */ -class CLI_Upgrader_Skin { - var $upgrader; - var $done_header = false; - var $result = false; +class CLI_Upgrader_Skin extends WP_Upgrader_Skin { - function __construct( $args = array() ) { - $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false ); - $this->options = wp_parse_args( $args, $defaults ); - } - - function set_upgrader( &$upgrader ) { - if( is_object( $upgrader ) ) { - $this->upgrader =& $upgrader; - } - - $this->add_strings(); - } - - function add_strings() {} - - function set_result( $result ) { - $this->result = $result; - } + function header() {} + function footer() {} + // TODO: show prompt function request_filesystem_credentials( $error = false ) { - $url = $this->options['url']; - $context = $this->options['context']; - if( !empty( $this->options['nonce'] ) ) { - $url = wp_nonce_url( $url, $this->options['nonce']) ; - } - - // Possible to bring inline, Leaving as is for now. - return request_filesystem_credentials( $url, '', $error, $context ); + $this->error( $error ); } - function header() {} - function footer() {} + function error( $error ) { + if ( !$error ) + return; - function error( $errors ) { - $this->feedback( WP_CLI::errorToString($errors) ); + // TODO: show all errors, not just the first one + WP_CLI::warning( WP_CLI::errorToString( $error ) ); } function feedback( $string ) { - if(isset( $this->upgrader->strings[$string] ) ) + if ( isset( $this->upgrader->strings[$string] ) ) $string = $this->upgrader->strings[$string]; - if( strpos( $string, '%' ) !== false ) { + if ( strpos($string, '%') !== false ) { $args = func_get_args(); - $args = array_splice( $args, 1 ); - if( !empty( $args ) ) { - $string = vsprintf( $string, $args ); - } - + $args = array_splice($args, 1); + if ( !empty($args) ) + $string = vsprintf($string, $args); } - if( empty( $string ) ) { + if ( empty($string) ) return; - } - echo $string; - } + $string = str_replace( '…', '...', strip_tags( $string ) ); - function before() {} - function after() {} + WP_CLI::line( $string ); + } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d2751b100..37f5dfea8 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -199,7 +199,6 @@ function install( $args, $assoc_args ) { // Force WordPress to update the plugin list wp_update_plugins(); - // Get plugin info from the WordPress servers $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( !$api ) { WP_CLI::error( 'Can\'t find the plugin in the WordPress.org plugins repository.' ); @@ -217,26 +216,18 @@ function install( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - // Check what to do switch ( $status['status'] ) { case 'update_available': case 'install': - - // Install the plugin - ob_start( 'strip_tags' ); $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); $result = $upgrader->install( $api->download_link ); - $feedback = ob_get_clean(); if ( $result ) { - WP_CLI::line(); - WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin installed successfully.' ), array( "...\n", '' ), html_entity_decode( $feedback ) ) ) ); - WP_CLI::success( 'The plugin is successfully installed' ); - if ( isset( $assoc_args['activate'] ) ) { system( "wp plugin activate " . WP_CLI::compose_args( $args, $assoc_args ) ); } } + break; case 'newer_installed': WP_CLI::error( sprintf( 'Newer version (%s) installed', $status['version'] ) ); @@ -247,6 +238,21 @@ function install( $args, $assoc_args ) { } } + /** + * Update a plugin + * + * @param array $args + */ + function update( $args ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + // Force WordPress to update the plugin list + wp_update_plugins(); + + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); + $result = $upgrader->upgrade( $file ); + } + /** * Uninstall a plugin * @@ -275,35 +281,6 @@ function delete( $args ) { } } - /** - * Update a plugin - * - * @param array $args - */ - function update( $args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - - // Force WordPress to update the plugin list - wp_update_plugins(); - - WP_CLI::line( 'Updating '.$name ); - - // Upgrading the plugin - ob_start( 'strip_tags' ); - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); - $result = $upgrader->upgrade( $file ); - $feedback = ob_get_clean(); - - if ( $result !== null ) { - WP_CLI::error( $feedback ); - } - else { - WP_CLI::line(); - WP_CLI::line( strip_tags( str_replace( array( '…', 'Plugin updates successfully.' ), array( "...\n", '' ), html_entity_decode( $feedback ) ) ) ); - WP_CLI::success( 'The plugin is successfully updated.' ); - } - } - /* PRIVATES */ /** From a0b31ccd863b2e8c6137ac8bd36effca0e8fe50f Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 28 Dec 2011 13:32:54 +0200 Subject: [PATCH 0199/5359] load upgrade.php before calling wp_install() --- src/php/wp-cli/commands/internals/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 3d5e27a07..9426556a9 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -77,6 +77,8 @@ function update($args) { * Run wp_install. Assumes that wp-config.php is already in place. */ public function install( $args, $assoc_args ) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + if ( is_blog_installed() ) { WP_CLI::error( 'WordPress is already installed.' ); } From b3055c2dd05f76e29a589dba82808dc9fc13724f Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 28 Dec 2011 14:09:09 +0200 Subject: [PATCH 0200/5359] fix wp core update. closes #43 --- src/php/wp-cli/commands/internals/core.php | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 9426556a9..f40a4c318 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -50,26 +50,29 @@ public function version( $args = array(), $assoc_args = array() ) { * @param array $args */ function update($args) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + wp_version_check(); - WP_CLI::line('Updating the WordPress core.'); + $from_api = get_site_transient( 'update_core' ); - ob_start(); - $upgrader = WP_CLI::get_upgrader( 'Core_Upgrader' ); - $result = $upgrader->upgrade($current); - $feedback = ob_get_clean(); + if ( empty( $from_api->updates ) ) + $update = false; + else + list( $update ) = $from_api->updates; - // Borrowed verbatim from wp-admin/update-core.php - if(is_wp_error($result) ) { - if('up_to_date' != $result->get_error_code()) { - WP_CLI::error('Installation failed ('.WP_CLI::errorToString($result).').'); - } - else { - WP_CLI::success(WP_CLI::errorToString($result)); + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + + $upgrader = WP_CLI::get_upgrader( 'Core_Upgrader' ); + $result = $upgrader->upgrade( $update ); + + if ( is_wp_error($result) ) { + $msg = WP_CLI::errorToString( $result ); + if ( 'up_to_date' != $result->get_error_code() ) { + WP_CLI::error( $msg ); + } else { + WP_CLI::success( $msg ); } - } - else { - WP_CLI::success('WordPress upgraded successfully.'); + } else { + WP_CLI::success('WordPress updated successfully.'); } } From 6cf1929a9e54d138eba1e490a6a31015fa1f1d19 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 28 Dec 2011 14:27:51 +0200 Subject: [PATCH 0201/5359] changelog --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6e35d9f95..1d6a9e088 100644 --- a/README.md +++ b/README.md @@ -109,8 +109,10 @@ Changelog - added `wp eval` and `wp eval-file` - added `wp export` - added `wp core install` +- fixed `wp core update` - added `--dev` flag to `wp plugin install` - added `wp plugin uninstall` +- fixed `wp plugin install` and `wp plugin update` **0.3** From f214187b768f52e45054bed331fe1a526a50c090 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 28 Dec 2011 15:02:51 +0200 Subject: [PATCH 0202/5359] remove unlikely case when there are no commands at all --- src/php/wp-cli/wp-cli.php | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 578f51d43..e60b2a358 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -1,7 +1,7 @@ $command ) { From 959ebd94778389b8e5a38f714212820a97e9150e Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 29 Dec 2011 16:47:22 +0200 Subject: [PATCH 0203/5359] release version 0.4.0 --- build.properties | 2 +- src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.properties b/build.properties index 8079bf947..27cb6bd81 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=andreascreten.github.com/wp-cli project.majorVersion=0 -project.minorVersion=3 +project.minorVersion=4 project.patchLevel=0 project.snapshot=false diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e60b2a358..e89911350 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die( 'Only cli access' ); } -define( 'WP_CLI_VERSION', '0.4.0-dev' ); +define( 'WP_CLI_VERSION', '0.4.0' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 56f6b791e70e101b7d297e69e799ab0e0458df45 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 2 Jan 2012 17:50:55 +0200 Subject: [PATCH 0204/5359] replace old reference to generalHelp() with general_help() --- src/php/wp-cli/commands/internals/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 4a8e68882..cc237c791 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -21,7 +21,7 @@ public function __construct( $args ) { } else { $command = $args[0]; if ( 'help' == $command || !isset( WP_CLI::$commands[$command] ) ) { - $this->generalHelp(); + $this->general_help(); } else { $class = WP_CLI::$commands[$command]; From 6f8e3e535062cdd8e834e11cf8ca9c3ea35d4dd6 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 26 Jan 2012 07:37:19 +0100 Subject: [PATCH 0205/5359] Added requirements to the README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1d6a9e088..d9fa906e5 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ What is wp-cli? A set of tools for controlling WordPress installations from the command line. +Requirements +------------ + +PHP >= 5.3 + Installing ---------- From bb162f940d80d5a880232f16889093fd767f0956 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Sun, 5 Feb 2012 19:51:14 -0500 Subject: [PATCH 0206/5359] Add "download" command. Downloads the current version of WP to the current working directory via SVN. I hardcoded the command instead of creating a subclass of WP_CLI because WP file check happens earlier than the subclasses are included. --- src/php/wp-cli/wp-cli.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e89911350..a0051b1f9 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -39,6 +39,16 @@ define('WP_ROOT', $_SERVER['PWD'] . '/'); } +//Download fresh copy of WordPress via SVN +if ( $arguments[0] == "download" ) { + if ( ! file_exists( 'wp-load.php' ) && ! file_exists( '/../wp-load.php' ) ) { + cli\line("Downloading WordPress via SVN..."); + exec("svn export --force http://core.svn.wordpress.org/tags/3.3.1/ ./"); + WP_CLI::success('WordPress downloaded successfully.'); + exit; + } +} + // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); From c491fd508f06cb1134e888bd05ae8307616df3cb Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Sun, 5 Feb 2012 22:12:02 -0500 Subject: [PATCH 0207/5359] Download WP via latest.zip link instead of SVN repo. --- src/php/wp-cli/wp-cli.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index a0051b1f9..31ca24f2b 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -42,9 +42,15 @@ //Download fresh copy of WordPress via SVN if ( $arguments[0] == "download" ) { if ( ! file_exists( 'wp-load.php' ) && ! file_exists( '/../wp-load.php' ) ) { - cli\line("Downloading WordPress via SVN..."); - exec("svn export --force http://core.svn.wordpress.org/tags/3.3.1/ ./"); - WP_CLI::success('WordPress downloaded successfully.'); + cli\line("Downloading WordPress..."); + exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); + WP_CLI::success('WordPress downloaded.'); + cli\line("Unzipping..."); + exec("unzip /tmp/wordpress.zip"); + exec("rm /tmp/wordpress.zip"); + exec("mv wordpress/* ./"); + exec("rm -r wordpress"); + WP_CLI::success('WordPress unzipped.'); exit; } } From e3e03722fa7dc7a0750b98dc6077487c136171fb Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Sun, 5 Feb 2012 23:32:02 -0500 Subject: [PATCH 0208/5359] change call of \cli\line to the corresponding method line() within WP_CLI class. --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 31ca24f2b..f234f732a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -42,12 +42,11 @@ //Download fresh copy of WordPress via SVN if ( $arguments[0] == "download" ) { if ( ! file_exists( 'wp-load.php' ) && ! file_exists( '/../wp-load.php' ) ) { - cli\line("Downloading WordPress..."); + WP_CLI::line("Downloading WordPress..."); exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); WP_CLI::success('WordPress downloaded.'); - cli\line("Unzipping..."); + WP_CLI::line("Unzipping..."); exec("unzip /tmp/wordpress.zip"); - exec("rm /tmp/wordpress.zip"); exec("mv wordpress/* ./"); exec("rm -r wordpress"); WP_CLI::success('WordPress unzipped.'); @@ -55,6 +54,7 @@ } } + // Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); From 426b5b973fe5268a8614e5f79112e95f901eea29 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 7 Feb 2012 02:17:01 +0200 Subject: [PATCH 0209/5359] integrate download command into existing check --- src/php/wp-cli/wp-cli.php | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index f234f732a..0042bafb5 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -39,28 +39,23 @@ define('WP_ROOT', $_SERVER['PWD'] . '/'); } -//Download fresh copy of WordPress via SVN -if ( $arguments[0] == "download" ) { - if ( ! file_exists( 'wp-load.php' ) && ! file_exists( '/../wp-load.php' ) ) { +// Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php +if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { + // Download fresh copy of WordPress in the current dir + if ( isset( $arguments[0] ) && $arguments[0] == 'download' ) { WP_CLI::line("Downloading WordPress..."); exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); - WP_CLI::success('WordPress downloaded.'); - WP_CLI::line("Unzipping..."); exec("unzip /tmp/wordpress.zip"); exec("mv wordpress/* ./"); exec("rm -r wordpress"); - WP_CLI::success('WordPress unzipped.'); + WP_CLI::success('WordPress downloaded.'); + exit; + } else { + WP_CLI::error('This does not seem to be a WordPress install. Try running `wp download`.'); exit; } } - -// Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php -if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { - WP_CLI::error('Either this is not a WordPress document root or you do not have permission to administer this site.'); - exit(); -} - // Handle --blog parameter if ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; From 2136017fc0544eb16510d85982b5343c1c0d003b Mon Sep 17 00:00:00 2001 From: John Gray Date: Tue, 7 Feb 2012 12:01:39 -0600 Subject: [PATCH 0210/5359] use host in sql connect and dump commands --- src/php/wp-cli/commands/internals/sql.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/sql.php b/src/php/wp-cli/commands/internals/sql.php index a3f2e8ffc..1d6b2e907 100644 --- a/src/php/wp-cli/commands/internals/sql.php +++ b/src/php/wp-cli/commands/internals/sql.php @@ -19,8 +19,8 @@ class SqlCommand extends WP_CLI_Command { * @return string $connect */ protected function connect_string() { - $connect = sprintf( 'mysql --database=%s --user=%s --password=%s', - DB_NAME, DB_USER, DB_PASSWORD); + $connect = sprintf( 'mysql --host=%s --database=%s --user=%s --password=%s', + DB_HOST, DB_NAME, DB_USER, DB_PASSWORD); return $connect; } @@ -58,7 +58,7 @@ function dump( $args, $assoc_args ) { $result_file = $assoc_args['file']; } - $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD ); + $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s --host=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD, DB_HOST ); exec( $exec ); } From ad9b35053de2774ec5c4d1362bd8914246aa7b89 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 7 Feb 2012 20:15:46 +0200 Subject: [PATCH 0211/5359] formatting fixes in sql.php --- src/php/wp-cli/commands/internals/sql.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/sql.php b/src/php/wp-cli/commands/internals/sql.php index 1d6b2e907..b47cc9764 100644 --- a/src/php/wp-cli/commands/internals/sql.php +++ b/src/php/wp-cli/commands/internals/sql.php @@ -19,9 +19,8 @@ class SqlCommand extends WP_CLI_Command { * @return string $connect */ protected function connect_string() { - $connect = sprintf( 'mysql --host=%s --database=%s --user=%s --password=%s', - DB_HOST, DB_NAME, DB_USER, DB_PASSWORD); - return $connect; + return sprintf( 'mysql --host=%s --database=%s --user=%s --password=%s', + DB_HOST, DB_NAME, DB_USER, DB_PASSWORD ); } /** @@ -58,7 +57,8 @@ function dump( $args, $assoc_args ) { $result_file = $assoc_args['file']; } - $exec = sprintf( 'mysqldump %s --result-file %s --user=%s --password=%s --host=%s', DB_NAME, $result_file, DB_USER, DB_PASSWORD, DB_HOST ); + $exec = sprintf( 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', + DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); } From ca655b7f2dcf7901899612cf6eac69468211807d Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 7 Feb 2012 20:16:34 +0200 Subject: [PATCH 0212/5359] add success message to wp sql dump --- src/php/wp-cli/commands/internals/sql.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/sql.php b/src/php/wp-cli/commands/internals/sql.php index b47cc9764..ba8479328 100644 --- a/src/php/wp-cli/commands/internals/sql.php +++ b/src/php/wp-cli/commands/internals/sql.php @@ -61,6 +61,8 @@ function dump( $args, $assoc_args ) { DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); + + WP_CLI::success( sprintf( 'Dumped to %s', $result_file ) ); } /** From 044c07366cfe786d5392968a8c84fba092ceed37 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 7 Feb 2012 20:25:17 +0200 Subject: [PATCH 0213/5359] rename 'sql' command to 'db'. fixes #54 --- .../commands/internals/{sql.php => db.php} | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) rename src/php/wp-cli/commands/internals/{sql.php => db.php} (55%) diff --git a/src/php/wp-cli/commands/internals/sql.php b/src/php/wp-cli/commands/internals/db.php similarity index 55% rename from src/php/wp-cli/commands/internals/sql.php rename to src/php/wp-cli/commands/internals/db.php index ba8479328..01fb3028d 100644 --- a/src/php/wp-cli/commands/internals/sql.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -1,22 +1,19 @@ connect_string(); - WP_CLI::line( $connect ); + function connect() { + WP_CLI::line( $this->connect_string() ); } /** * Open a SQL command-line interface using WordPress's credentials. - * @param string $args - * @return void */ function cli() { - $exec = $this->connect_string(); - - proc_close( proc_open( $exec , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); + proc_close( proc_open( $this->connect_string() , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); } /** - * Exports the WordPress DB as SQL using mysqldump or equivalent. - * @param string $args - * @return void + * Exports the WordPress DB as SQL using mysqldump. */ function dump( $args, $assoc_args ) { if ( !isset( $assoc_args['file'] ) ) { @@ -67,10 +54,7 @@ function dump( $args, $assoc_args ) { /** * Execute a query against the site database. - * @param string $args - * @return void */ - function query( $args, $assoc_args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp sql query " ); @@ -91,10 +75,10 @@ function query( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( << Date: Tue, 7 Feb 2012 20:27:18 +0200 Subject: [PATCH 0214/5359] add 'sql' alias for backwards compatibility. see #54 --- src/php/wp-cli/wp-cli.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 0042bafb5..5ba9ef2fa 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -104,6 +104,14 @@ else $command = array_shift( $arguments ); +// Translate aliases +$aliases = array( + 'sql' => 'db' +); + +if ( isset( $aliases[ $command ] ) ) + $command = $aliases[ $command ]; + if ( !isset( WP_CLI::$commands[$command] ) ) { WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); exit; From 136c62cfcd6ccd062b9fd0050dca8ba49b0a7d3e Mon Sep 17 00:00:00 2001 From: John Gray Date: Tue, 7 Feb 2012 18:42:10 -0600 Subject: [PATCH 0215/5359] list users with 'wp user all' --- src/php/wp-cli/commands/internals/user.php | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/user.php diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php new file mode 100644 index 000000000..e81d55777 --- /dev/null +++ b/src/php/wp-cli/commands/internals/user.php @@ -0,0 +1,101 @@ +setHeaders($fields); + + foreach ( $users as $user ) { + $line = array(); + + foreach ( $fields as $field ) { + $line[] = $user->$field; + } + + $table->addRow($line); + } + + $table->display(); + + $total = count_users(); + WP_CLI::line( 'Total: ' . $total['total_users'] . ' users' ); + } + + /** + * Create a user + * + * @param array $args + * @param array $assoc_args + **/ + public function users( $args, $assoc_args ) { + global $blog_id; + + $defaults = array( + 'count' => 100, + 'role' => get_option('default_role'), + ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( 'none' == $role ) { + $role = false; + } elseif ( is_null( get_role( $role ) ) ) { + WP_CLI::warning( "invalid role." ); + exit; + } + + $user_count = count_users(); + + $total = $user_count['total_users']; + + $limit = $count + $total; + + for ( $i = $total; $i < $limit; $i++ ) { + $login = sprintf( 'user_%d_%d', $blog_id, $i ); + $name = "User $i"; + + $user_id = wp_insert_user( array( + 'user_login' => $login, + 'user_pass' => $login, + 'nickname' => $name, + 'display_name' => $name, + 'role' => $role + ) ); + + if ( false === $role ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } + } + } + + /** + * Help function for this command + */ + public static function help() { + WP_CLI::line( <<] +EOB + ); + } +} From 620b55a18161c07d72e3f2ec66f0394bf869e18e Mon Sep 17 00:00:00 2001 From: John Gray Date: Tue, 7 Feb 2012 20:15:39 -0600 Subject: [PATCH 0216/5359] fix user count, add roles to list, add create subcommand --- src/php/wp-cli/commands/internals/user.php | 69 ++++++++++++---------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index e81d55777..23fb0c0c4 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -18,11 +18,12 @@ class UserCommand extends WP_CLI_Command { public function all( $args, $assoc_args ) { global $blog_id; - $users = get_users("blog_id=$blog_id"); - $fields = array('ID', 'user_login', 'display_name', 'user_email', - 'user_registered', 'user_status'); $table = new \cli\Table(); - $table->setHeaders($fields); + $users = get_users("blog_id=$blog_id&fields=all_with_meta"); + $fields = array('ID', 'user_login', 'display_name', 'user_email', + 'user_registered'); + + $table->setHeaders( array_merge($fields, array('roles')) ); foreach ( $users as $user ) { $line = array(); @@ -30,14 +31,14 @@ public function all( $args, $assoc_args ) { foreach ( $fields as $field ) { $line[] = $user->$field; } + $line[] = implode( ',', $user->roles ); $table->addRow($line); } $table->display(); - $total = count_users(); - WP_CLI::line( 'Total: ' . $total['total_users'] . ' users' ); + WP_CLI::line( 'Total: ' . count($users) . ' users' ); } /** @@ -46,12 +47,20 @@ public function all( $args, $assoc_args ) { * @param array $args * @param array $assoc_args **/ - public function users( $args, $assoc_args ) { + public function create( $args, $assoc_args ) { global $blog_id; + $user_login = $args[0]; + $user_email = $args[1]; + + if ( ! $user_login || ! $user_email ) { + WP_CLI::error("Login and email required (see 'wp user help')."); + } + $defaults = array( - 'count' => 100, 'role' => get_option('default_role'), + 'user_pass' => wp_generate_password(), + 'user_registered' => strftime( "%F %T", time() ), ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); @@ -63,29 +72,25 @@ public function users( $args, $assoc_args ) { exit; } - $user_count = count_users(); - - $total = $user_count['total_users']; - - $limit = $count + $total; - - for ( $i = $total; $i < $limit; $i++ ) { - $login = sprintf( 'user_%d_%d', $blog_id, $i ); - $name = "User $i"; - - $user_id = wp_insert_user( array( - 'user_login' => $login, - 'user_pass' => $login, - 'nickname' => $name, - 'display_name' => $name, - 'role' => $role - ) ); + $user_id = wp_insert_user( array( + 'user_email' => $user_email, + 'user_login' => $user_login, + 'user_pass' => $user_pass, + 'user_registered' => $user_registered, + 'display_name' => $display_name, + 'role' => $role, + ) ); + + if ( is_wp_error($user_id) ) { + WP_CLI::error( $user_id->get_error_message() ); + } else { + if ( false === $role ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } + } - if ( false === $role ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - } + WP_CLI::line( "Created user $user_id" ); } /** @@ -93,8 +98,8 @@ public function users( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( <<] +usage: wp user all + or: wp user create [--role=] EOB ); } From 0d6ba8f92c9d0cc6a04d8b7c0a5c0fc518ca541b Mon Sep 17 00:00:00 2001 From: John Gray Date: Tue, 7 Feb 2012 20:34:59 -0600 Subject: [PATCH 0217/5359] delete subcommand --- src/php/wp-cli/commands/internals/user.php | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 23fb0c0c4..8bae0ab10 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -41,6 +41,33 @@ public function all( $args, $assoc_args ) { WP_CLI::line( 'Total: ' . count($users) . ' users' ); } + /** + * Delete a user + * + * @param array $args + * @param array $assoc_args + **/ + public function delete( $args, $assoc_args ) { + global $blog_id; + + $user_id = $args[0]; + + if ( ! is_numeric($user_id) ) { + WP_CLI::error("User ID required (see 'wp user help')"); + } + + $defaults = array( 'reassign' => NULL ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( wp_delete_user( $user_id, $reassign ) ) { + WP_CLI::line( "Deleted user $user_id" ); + } else { + WP_CLI::error( "Failed deleting user $user_id" ); + } + + } + /** * Create a user * From 54fa4888ae850309557fd37bacaac624205d5419 Mon Sep 17 00:00:00 2001 From: John Gray Date: Tue, 7 Feb 2012 20:56:17 -0600 Subject: [PATCH 0218/5359] update subcommand --- src/php/wp-cli/commands/internals/user.php | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 8bae0ab10..0d4c41ec1 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -120,6 +120,34 @@ public function create( $args, $assoc_args ) { WP_CLI::line( "Created user $user_id" ); } + /** + * Update a user + * + * @param array $args + * @param array $assoc_args + **/ + public function update( $args, $assoc_args ) { + $user_id = $args[0]; + + if ( ! is_numeric($user_id) ) { + WP_CLI::error( "User ID required (see 'wp user help')" ); + } + + if ( ! count($assoc_args) ) { + WP_CLI::error( "Need some fields to update" ); + } + + $params = array_merge( array('ID' => $user_id), $assoc_args ); + + $updated_id = wp_update_user( $params ); + + if ( is_wp_error($updated_id) ) { + WP_CLI::error( $updated_id->get_error_message() ); + } else { + WP_CLI::line( "Updated user $updated_id" ); + } + } + /** * Help function for this command */ @@ -127,6 +155,8 @@ public static function help() { WP_CLI::line( << [--role=] + or: wp user update [--field_name=] + or: wp user delete [--reassign=] EOB ); } From f94c2b17fc1d3bce76750e76523f97bb542fbccd Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 8 Feb 2012 07:31:28 +0200 Subject: [PATCH 0219/5359] fix indentation --- src/php/wp-cli/class-wp-cli-command.php | 30 ++++++++++++------------- src/php/wp-cli/class-wp-cli.php | 1 + 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index abbbc1616..1213df53f 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -11,8 +11,8 @@ abstract class WP_CLI_Command { /** * Transfers the handling to the appropriate method - * - * @param array $args + * + * @param array $args * @param array $assoc_args */ public function __construct( $args, $assoc_args ) { @@ -23,7 +23,7 @@ public function __construct( $args, $assoc_args ) { if ( !method_exists( $this, $subcommand ) ) { // This if for reserved keywords in php (like list, isset) - $subcommand = '_'.$subcommand; + $subcommand = '_' . $subcommand; } if ( !method_exists( $this, $subcommand ) || isset( $assoc_args[ 'help' ] ) ) { @@ -31,18 +31,18 @@ public function __construct( $args, $assoc_args ) { } $this->$subcommand( $args, $assoc_args ); - } - - /** - * Get the list of subcommands for a class. - * - * @param string $class - * @return array The list of methods - */ - static function get_subcommands( $class ) { + } + + /** + * Get the list of subcommands for a class. + * + * @param string $class + * @return array The list of methods + */ + static function get_subcommands( $class ) { $reflection = new ReflectionClass( $class ); - $methods = array(); + $methods = array(); foreach ( $reflection->getMethods() as $method ) { if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { @@ -54,8 +54,8 @@ static function get_subcommands( $class ) { $methods[] = $name; } - } + } return $methods; - } + } } diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index e75f6b86c..710756b03 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -6,6 +6,7 @@ * @package wp-cli */ class WP_CLI { + static $commands = array(); /** From e693da9ca5a4d323e558230aff6d260f5f21d1d8 Mon Sep 17 00:00:00 2001 From: John Gray Date: Wed, 8 Feb 2012 09:30:44 -0600 Subject: [PATCH 0220/5359] add --role option to user list --- src/php/wp-cli/commands/internals/user.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 0d4c41ec1..654337b45 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -18,8 +18,17 @@ class UserCommand extends WP_CLI_Command { public function all( $args, $assoc_args ) { global $blog_id; + $params = array( + 'blog_id' => $blog_id, + 'fields' => 'all_with_meta', + ); + + if ( array_key_exists('role', $assoc_args) ) { + $params['role'] = $assoc_args['role']; + } + $table = new \cli\Table(); - $users = get_users("blog_id=$blog_id&fields=all_with_meta"); + $users = get_users( $params ); $fields = array('ID', 'user_login', 'display_name', 'user_email', 'user_registered'); @@ -153,7 +162,7 @@ public function update( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( <<] or: wp user create [--role=] or: wp user update [--field_name=] or: wp user delete [--reassign=] From 41aa6d5eafd99388b6a44f4d18f3577711e07839 Mon Sep 17 00:00:00 2001 From: John Gray Date: Wed, 8 Feb 2012 09:31:30 -0600 Subject: [PATCH 0221/5359] change all to list --- src/php/wp-cli/commands/internals/user.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 654337b45..fc694d0f0 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -15,7 +15,7 @@ class UserCommand extends WP_CLI_Command { * @param array $args * @param array $assoc_args **/ - public function all( $args, $assoc_args ) { + public function _list( $args, $assoc_args ) { global $blog_id; $params = array( @@ -162,7 +162,7 @@ public function update( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( <<] +usage: wp user list [--role=] or: wp user create [--role=] or: wp user update [--field_name=] or: wp user delete [--reassign=] From 582d4e271da529534dcaf0fb67949a9e8b8d4125 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 8 Feb 2012 18:59:04 +0200 Subject: [PATCH 0222/5359] fix get_subcommands() --- src/php/wp-cli/class-wp-cli-command.php | 2 +- src/php/wp-cli/commands/internals/help.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 1213df53f..85202d36d 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -49,7 +49,7 @@ static function get_subcommands( $class ) { $name = $method->name; if ( strpos( $name, '_' ) === 0 ) { - $name = substr( $method, 1 ); + $name = substr( $name, 1 ); } $methods[] = $name; diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index cc237c791..0a8dd0151 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -50,7 +50,9 @@ private function general_help() { private function single_command_help( $name, $command ) { WP_CLI::out( ' wp ' . $name ); + $methods = WP_CLI_Command::get_subcommands( $command ); + if ( !empty( $methods ) ) { WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); } From 870f7c4b2192fc0063710a129924411dbf01f15a Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 15 Feb 2012 19:44:14 +0200 Subject: [PATCH 0223/5359] `wp download` -> `wp core download` see #62 --- src/php/wp-cli/wp-cli.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 5ba9ef2fa..bba3b8d97 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -39,11 +39,9 @@ define('WP_ROOT', $_SERVER['PWD'] . '/'); } -// Taken from https://github.com/88mph/wpadmin/blob/master/wpadmin.php if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { - // Download fresh copy of WordPress in the current dir - if ( isset( $arguments[0] ) && $arguments[0] == 'download' ) { - WP_CLI::line("Downloading WordPress..."); + if ( array( 'core', 'download' ) == $arguments ) { + WP_CLI::line('Downloading WordPress...'); exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); exec("unzip /tmp/wordpress.zip"); exec("mv wordpress/* ./"); @@ -51,7 +49,7 @@ WP_CLI::success('WordPress downloaded.'); exit; } else { - WP_CLI::error('This does not seem to be a WordPress install. Try running `wp download`.'); + WP_CLI::error('This does not seem to be a WordPress install. Try running `wp core download`.'); exit; } } From 8329ba8af5168c2b2350995dc2b3620981025f9f Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 16 Feb 2012 22:45:44 +0200 Subject: [PATCH 0224/5359] first pass at `wp core config`. see #65 --- src/php/wp-cli/wp-cli.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index bba3b8d97..b82ee39dc 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -54,6 +54,18 @@ } } +if ( array( 'core', 'config' ) == $arguments ) { + $_POST['dbname'] = $assoc_args['name']; + $_POST['uname'] = $assoc_args['user']; + $_POST['pwd'] = $assoc_args['pass']; + $_POST['dbhost'] = isset( $assoc_args['host'] ) ? $assoc_args['host'] : 'localhost'; + $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : ''; + + $_GET['step'] = 2; + require WP_ROOT . '/wp-admin/setup-config.php'; + exit; +} + // Handle --blog parameter if ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; From f9fd476f816b44d40f7565eee39c495a8aee2e28 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 17:46:54 +0200 Subject: [PATCH 0225/5359] add theme delete subcommand. fixes #70 --- src/php/wp-cli/commands/internals/theme.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index ee9d18d62..76be9b533 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -121,6 +121,21 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } + /** + * Delete a theme + * + * @param array $args + */ + function delete( $args ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + $r = delete_theme( $name ); + + if ( is_wp_error( $r ) ) { + WP_CLI::error( $r ); + } + } + protected function parse_name( $args, $subcommand ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp theme $subcommand " ); @@ -155,6 +170,7 @@ public static function help() { status display status of all installed themes or of a particular theme activate activate a particular theme path print path to the theme's stylesheet + delete delete a theme EOB ); } From e523df3c737ab307bc3b528ac0a0c201c6d636cf Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 18:25:44 +0200 Subject: [PATCH 0226/5359] mysqldump, not mydbdump --- src/php/wp-cli/commands/internals/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 01fb3028d..162d5bc22 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -77,7 +77,7 @@ public static function help() { WP_CLI::line( << Date: Sat, 18 Feb 2012 21:51:23 +0200 Subject: [PATCH 0227/5359] check is_plugin_active() before calling delete_plugins() --- src/php/wp-cli/commands/internals/plugin.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 37f5dfea8..dcca8a2f1 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -276,6 +276,10 @@ function uninstall( $args ) { function delete( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + if ( is_plugin_active( $file ) ) { + WP_CLI::error( 'The plugin is active.' ); + } + if ( !delete_plugins( array( $file ) ) ) { WP_CLI::error( 'There was an error while deleting the plugin.' ); } From e2728327ff9e065f08cc94054f00534a6dae534c Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 22:46:54 +0200 Subject: [PATCH 0228/5359] add progress bars for `generate` command --- src/php/wp-cli/commands/internals/generate.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 7f8189400..2f732507d 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -39,13 +39,19 @@ public function posts( $args, $assoc_args ) { $limit = $count + $total; + $notify = new \cli\progress\Bar( 'Generating posts', $count ); + for ( $i = $total; $i < $limit; $i++ ) { wp_insert_post( array( 'post_type' => $type, 'post_title' => "$label $i", 'post_status' => $status ) ); + + $notify->tick(); } + + $notify->finish(); } /** @@ -77,6 +83,8 @@ public function users( $args, $assoc_args ) { $limit = $count + $total; + $notify = new \cli\progress\Bar( 'Generating users', $count ); + for ( $i = $total; $i < $limit; $i++ ) { $login = sprintf( 'user_%d_%d', $blog_id, $i ); $name = "User $i"; @@ -93,7 +101,11 @@ public function users( $args, $assoc_args ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } + + $notify->tick(); } + + $notify->finish(); } /** From be5016fffbb739a9b278a1f2f784b1074590ca26 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 22:49:37 +0200 Subject: [PATCH 0229/5359] uppercase progress bar message --- src/php/wp-cli/commands/internals/export.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 7ecaa5d47..1794c9461 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -358,7 +358,7 @@ private function export_wp( $args = array() ) { WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); WP_CLI::line(); - $progress = $this->progress_bar( 'exporting', count( $post_ids ) ); + $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); ob_start(); echo '\n"; @@ -508,12 +508,5 @@ private function export_wp( $args = array() ) { file_put_contents( $full_path, $result ); } } - - /** - * Implement progress bar - */ - private function progress_bar( $title, $total, $interval = 100 ) { - return new \cli\progress\Bar( $title, $total, $interval ); - } - } + From b099b2fb8ffc003e0aa3e483c9ed254de4642cc3 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 23:05:24 +0200 Subject: [PATCH 0230/5359] call $progress->finish(); --- src/php/wp-cli/commands/internals/export.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 1794c9461..07b311464 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -499,6 +499,8 @@ private function export_wp( $args = array() ) { finish(); + $result = ob_get_clean(); $full_path = $this->wxr_path . $file_name_base . '.wxr'; From 71465de750fe26c6e29dba803403de8769ff0b31 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 18 Feb 2012 23:07:25 +0200 Subject: [PATCH 0231/5359] processs -> process... --- src/php/wp-cli/commands/internals/export.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 07b311464..62967b586 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -34,18 +34,9 @@ public static function help() { ); } - private function dispatch() { - WP_CLI::line(); - WP_CLI::line( 'Starting export processs' ); - WP_CLI::line(); - $this->export_wp( $this->export_args ); - } - - /** * Argument validation functions below */ - public function validate_arguments( $args, $assoc_args ) { $defaults = array( 'path' => NULL, @@ -77,7 +68,9 @@ public function validate_arguments( $args, $assoc_args ) { $this->wxr_path = $assoc_args['path']; - $this->dispatch(); + WP_CLI::line( 'Starting export process...' ); + WP_CLI::line(); + $this->export_wp( $this->export_args ); } private function check_path( $path ) { From dc78b9f88ab7bcfd344b23865459ece794160969 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 17:04:26 +0200 Subject: [PATCH 0232/5359] remove redundant text in `wp core version` --- src/php/wp-cli/commands/internals/core.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index f40a4c318..651c4c47a 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -30,10 +30,9 @@ public function version( $args = array(), $assoc_args = array() ) { break; } } - WP_CLI::line( "WordPress version:\t$version_text" ); - if ( isset( $assoc_args['extra'] ) ) { - WP_CLI::line(); + WP_CLI::line( "WordPress version:\t$version_text" ); + WP_CLI::line( "Database revision:\t$wp_db_version" ); preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); @@ -41,6 +40,8 @@ public function version( $args = array(), $assoc_args = array() ) { WP_CLI::line( "TinyMCE version:\t" . ( $human_readable_tiny_mce? "$human_readable_tiny_mce ($tinymce_version)" : $tinymce_version ) ); WP_CLI::line( "Manifest revision:\t$manifest_version" ); + } else { + WP_CLI::line( $version_text ); } } From 2d304217308bcb34c0e8bd0dc3a12db700ec325d Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 21:40:18 +0200 Subject: [PATCH 0233/5359] user.php: indentation --- src/php/wp-cli/commands/internals/user.php | 208 ++++++++++----------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index fc694d0f0..562059cca 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -9,73 +9,73 @@ * @subpackage commands/internals */ class UserCommand extends WP_CLI_Command { - /** - * List users - * - * @param array $args - * @param array $assoc_args - **/ - public function _list( $args, $assoc_args ) { - global $blog_id; - $params = array( - 'blog_id' => $blog_id, - 'fields' => 'all_with_meta', - ); + /** + * List users + * + * @param array $args + * @param array $assoc_args + **/ + public function _list( $args, $assoc_args ) { + global $blog_id; - if ( array_key_exists('role', $assoc_args) ) { - $params['role'] = $assoc_args['role']; - } + $params = array( + 'blog_id' => $blog_id, + 'fields' => 'all_with_meta', + ); - $table = new \cli\Table(); - $users = get_users( $params ); - $fields = array('ID', 'user_login', 'display_name', 'user_email', - 'user_registered'); + if ( array_key_exists('role', $assoc_args) ) { + $params['role'] = $assoc_args['role']; + } - $table->setHeaders( array_merge($fields, array('roles')) ); + $table = new \cli\Table(); + $users = get_users( $params ); + $fields = array('ID', 'user_login', 'display_name', 'user_email', + 'user_registered'); - foreach ( $users as $user ) { - $line = array(); + $table->setHeaders( array_merge($fields, array('roles')) ); - foreach ( $fields as $field ) { - $line[] = $user->$field; - } - $line[] = implode( ',', $user->roles ); + foreach ( $users as $user ) { + $line = array(); - $table->addRow($line); - } + foreach ( $fields as $field ) { + $line[] = $user->$field; + } + $line[] = implode( ',', $user->roles ); - $table->display(); + $table->addRow($line); + } - WP_CLI::line( 'Total: ' . count($users) . ' users' ); - } + $table->display(); - /** - * Delete a user - * - * @param array $args - * @param array $assoc_args - **/ - public function delete( $args, $assoc_args ) { - global $blog_id; + WP_CLI::line( 'Total: ' . count($users) . ' users' ); + } - $user_id = $args[0]; + /** + * Delete a user + * + * @param array $args + * @param array $assoc_args + **/ + public function delete( $args, $assoc_args ) { + global $blog_id; - if ( ! is_numeric($user_id) ) { - WP_CLI::error("User ID required (see 'wp user help')"); - } + $user_id = $args[0]; - $defaults = array( 'reassign' => NULL ); + if ( ! is_numeric($user_id) ) { + WP_CLI::error("User ID required (see 'wp user help')"); + } - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + $defaults = array( 'reassign' => NULL ); - if ( wp_delete_user( $user_id, $reassign ) ) { - WP_CLI::line( "Deleted user $user_id" ); - } else { - WP_CLI::error( "Failed deleting user $user_id" ); - } + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - } + if ( wp_delete_user( $user_id, $reassign ) ) { + WP_CLI::line( "Deleted user $user_id" ); + } else { + WP_CLI::error( "Failed deleting user $user_id" ); + } + } /** * Create a user @@ -86,17 +86,17 @@ public function delete( $args, $assoc_args ) { public function create( $args, $assoc_args ) { global $blog_id; - $user_login = $args[0]; - $user_email = $args[1]; + $user_login = $args[0]; + $user_email = $args[1]; - if ( ! $user_login || ! $user_email ) { - WP_CLI::error("Login and email required (see 'wp user help')."); - } + if ( ! $user_login || ! $user_email ) { + WP_CLI::error("Login and email required (see 'wp user help')."); + } $defaults = array( 'role' => get_option('default_role'), - 'user_pass' => wp_generate_password(), - 'user_registered' => strftime( "%F %T", time() ), + 'user_pass' => wp_generate_password(), + 'user_registered' => strftime( "%F %T", time() ), ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); @@ -108,54 +108,54 @@ public function create( $args, $assoc_args ) { exit; } - $user_id = wp_insert_user( array( - 'user_email' => $user_email, - 'user_login' => $user_login, - 'user_pass' => $user_pass, - 'user_registered' => $user_registered, - 'display_name' => $display_name, - 'role' => $role, - ) ); - - if ( is_wp_error($user_id) ) { - WP_CLI::error( $user_id->get_error_message() ); - } else { - if ( false === $role ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - } - - WP_CLI::line( "Created user $user_id" ); + $user_id = wp_insert_user( array( + 'user_email' => $user_email, + 'user_login' => $user_login, + 'user_pass' => $user_pass, + 'user_registered' => $user_registered, + 'display_name' => $display_name, + 'role' => $role, + ) ); + + if ( is_wp_error($user_id) ) { + WP_CLI::error( $user_id->get_error_message() ); + } else { + if ( false === $role ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } + } + + WP_CLI::line( "Created user $user_id" ); } - /** - * Update a user - * - * @param array $args - * @param array $assoc_args - **/ - public function update( $args, $assoc_args ) { - $user_id = $args[0]; - - if ( ! is_numeric($user_id) ) { - WP_CLI::error( "User ID required (see 'wp user help')" ); - } - - if ( ! count($assoc_args) ) { - WP_CLI::error( "Need some fields to update" ); - } - - $params = array_merge( array('ID' => $user_id), $assoc_args ); - - $updated_id = wp_update_user( $params ); - - if ( is_wp_error($updated_id) ) { - WP_CLI::error( $updated_id->get_error_message() ); - } else { - WP_CLI::line( "Updated user $updated_id" ); - } - } + /** + * Update a user + * + * @param array $args + * @param array $assoc_args + **/ + public function update( $args, $assoc_args ) { + $user_id = $args[0]; + + if ( ! is_numeric($user_id) ) { + WP_CLI::error( "User ID required (see 'wp user help')" ); + } + + if ( ! count($assoc_args) ) { + WP_CLI::error( "Need some fields to update" ); + } + + $params = array_merge( array('ID' => $user_id), $assoc_args ); + + $updated_id = wp_update_user( $params ); + + if ( is_wp_error($updated_id) ) { + WP_CLI::error( $updated_id->get_error_message() ); + } else { + WP_CLI::line( "Updated user $updated_id" ); + } + } /** * Help function for this command From 180014c43903bb40c2bf69d48b3f7b2122252d56 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 21:42:12 +0200 Subject: [PATCH 0234/5359] user.php: prevent notice when --display_name is not passed --- src/php/wp-cli/commands/internals/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 562059cca..9ff4f1b1e 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -97,6 +97,7 @@ public function create( $args, $assoc_args ) { 'role' => get_option('default_role'), 'user_pass' => wp_generate_password(), 'user_registered' => strftime( "%F %T", time() ), + 'display_name' => false, ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); From 005e7cbe2f7a09fa99d923b87649e6e2f259b0a8 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 21:46:35 +0200 Subject: [PATCH 0235/5359] user.php: pass whole error object to WP_CLI::error --- src/php/wp-cli/commands/internals/user.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 9ff4f1b1e..1d415c8c7 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -119,7 +119,7 @@ public function create( $args, $assoc_args ) { ) ); if ( is_wp_error($user_id) ) { - WP_CLI::error( $user_id->get_error_message() ); + WP_CLI::error( $user_id ); } else { if ( false === $role ) { delete_user_option( $user_id, 'capabilities' ); @@ -152,7 +152,7 @@ public function update( $args, $assoc_args ) { $updated_id = wp_update_user( $params ); if ( is_wp_error($updated_id) ) { - WP_CLI::error( $updated_id->get_error_message() ); + WP_CLI::error( $updated_id ); } else { WP_CLI::line( "Updated user $updated_id" ); } From 92b3be4ff84da2ab4c6c6877171ec9576e8b5386 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 22:03:19 +0200 Subject: [PATCH 0236/5359] user.php: Use success() instead of line() and error() instead of warning() --- src/php/wp-cli/commands/internals/user.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 1d415c8c7..ea6bbf948 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -71,7 +71,7 @@ public function delete( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); if ( wp_delete_user( $user_id, $reassign ) ) { - WP_CLI::line( "Deleted user $user_id" ); + WP_CLI::success( "Deleted user $user_id" ); } else { WP_CLI::error( "Failed deleting user $user_id" ); } @@ -105,8 +105,7 @@ public function create( $args, $assoc_args ) { if ( 'none' == $role ) { $role = false; } elseif ( is_null( get_role( $role ) ) ) { - WP_CLI::warning( "invalid role." ); - exit; + WP_CLI::error( "Invalid role." ); } $user_id = wp_insert_user( array( @@ -127,7 +126,7 @@ public function create( $args, $assoc_args ) { } } - WP_CLI::line( "Created user $user_id" ); + WP_CLI::success( "Created user $user_id" ); } /** @@ -154,7 +153,7 @@ public function update( $args, $assoc_args ) { if ( is_wp_error($updated_id) ) { WP_CLI::error( $updated_id ); } else { - WP_CLI::line( "Updated user $updated_id" ); + WP_CLI::success( "Updated user $updated_id" ); } } From 0eb538a48618a07bc1a55dc9e5a9c9ffd78cfb61 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 19 Feb 2012 22:07:12 +0200 Subject: [PATCH 0237/5359] user.php: dots --- src/php/wp-cli/commands/internals/user.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index ea6bbf948..f5bb9846e 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -71,9 +71,9 @@ public function delete( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); if ( wp_delete_user( $user_id, $reassign ) ) { - WP_CLI::success( "Deleted user $user_id" ); + WP_CLI::success( "Deleted user $user_id." ); } else { - WP_CLI::error( "Failed deleting user $user_id" ); + WP_CLI::error( "Failed deleting user $user_id." ); } } @@ -126,7 +126,7 @@ public function create( $args, $assoc_args ) { } } - WP_CLI::success( "Created user $user_id" ); + WP_CLI::success( "Created user $user_id." ); } /** @@ -139,21 +139,21 @@ public function update( $args, $assoc_args ) { $user_id = $args[0]; if ( ! is_numeric($user_id) ) { - WP_CLI::error( "User ID required (see 'wp user help')" ); + WP_CLI::error( "User ID required (see 'wp user help')." ); } - if ( ! count($assoc_args) ) { - WP_CLI::error( "Need some fields to update" ); + if ( empty( $assoc_args ) ) { + WP_CLI::error( "Need some fields to update." ); } - $params = array_merge( array('ID' => $user_id), $assoc_args ); + $params = array_merge( array( 'ID' => $user_id ), $assoc_args ); $updated_id = wp_update_user( $params ); - if ( is_wp_error($updated_id) ) { + if ( is_wp_error( $updated_id ) ) { WP_CLI::error( $updated_id ); } else { - WP_CLI::success( "Updated user $updated_id" ); + WP_CLI::success( "Updated user $updated_id." ); } } From aacdb13ca8b3f42e97e56f52a74c59530bcf6912 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 21 Feb 2012 16:07:33 +0200 Subject: [PATCH 0238/5359] handle options with % in them. fixes #71 --- src/php/wp-cli/commands/internals/option.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 26be3b1cc..bb223dc7b 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -86,9 +86,9 @@ public function get( $args ) { return; if ( is_array( $value ) || is_object( $value ) ) { - WP_CLI::line( var_export( $value ) ); + echo var_export( $value ) . "\n"; } else { - WP_CLI::line( $value ); + echo $value . "\n"; } } From ad1c72bd081fe3b7d8fd9fbaa97ca5663ada30be Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 23 Feb 2012 17:59:22 +0200 Subject: [PATCH 0239/5359] add --author param to wp generate posts. fixes #74 --- src/php/wp-cli/commands/internals/generate.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 2f732507d..02f848540 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -22,7 +22,8 @@ public function posts( $args, $assoc_args ) { $defaults = array( 'count' => 100, 'type' => 'post', - 'status' => 'publish' + 'status' => 'publish', + 'author' => false ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); @@ -32,6 +33,13 @@ public function posts( $args, $assoc_args ) { exit; } + if ( $author ) { + $author = get_user_by( 'login', $author ); + + if ( $author ) + $author = $author->ID; + } + // Get the total number of posts $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $type ) ); @@ -45,7 +53,8 @@ public function posts( $args, $assoc_args ) { wp_insert_post( array( 'post_type' => $type, 'post_title' => "$label $i", - 'post_status' => $status + 'post_status' => $status, + 'post_author' => $author ) ); $notify->tick(); @@ -113,7 +122,7 @@ public function users( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( <<] or: wp generate users [--count=100] [--role=] EOB ); From 80337a4f605cc8dd68c0c9722d2a1e8d0486e26e Mon Sep 17 00:00:00 2001 From: Chris Svajlenka Date: Wed, 29 Feb 2012 15:30:19 -0800 Subject: [PATCH 0240/5359] Added db import [--file] to import database files, as query will not run a file of queries. --- src/php/wp-cli/commands/internals/db.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 162d5bc22..6ae668698 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -70,6 +70,21 @@ function query( $args, $assoc_args ) { WP_CLI::line( $result ); } + function import( $args, $assoc_args ) { + if ( !isset( $assoc_args['file'] ) ) { + $result_file = sprintf( '%s.sql', DB_NAME ); + } else { + $result_file = $assoc_args['file']; + } + + $exec = sprintf( 'mysql %s --user=%s --password=%s --host=%s < %s', + DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); + + exec( $exec ); + + WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); + } + /** * Help function for this command */ @@ -79,6 +94,7 @@ public static function help() { wp db connect Print a string for connecting to the database. wp db dump Exports the WordPress database using mysqldump. wp db query Execute a query against the WordPress database. +wp db import Import a database dumped via mysqldump. EOB ); } From 2908029eaa2748a7c5a33346c8d8196627daf880 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 1 Mar 2012 02:58:20 +0200 Subject: [PATCH 0241/5359] wp db dump -> wp db export. see #75 --- src/php/wp-cli/class-wp-cli-command.php | 5 +++++ src/php/wp-cli/commands/internals/db.php | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 85202d36d..c21846b72 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -9,6 +9,8 @@ abstract class WP_CLI_Command { protected $default_subcommand = 'help'; + protected $aliases = array(); + /** * Transfers the handling to the appropriate method * @@ -21,6 +23,9 @@ public function __construct( $args, $assoc_args ) { else $subcommand = array_shift( $args ); + if ( isset( $this->aliases[ $subcommand ] ) ) + $subcommand = $this->aliases[ $subcommand ]; + if ( !method_exists( $this, $subcommand ) ) { // This if for reserved keywords in php (like list, isset) $subcommand = '_' . $subcommand; diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 6ae668698..de88a992a 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -12,6 +12,8 @@ class DBCommand extends WP_CLI_Command { protected $default_subcommand = 'cli'; + protected $aliases = array( 'dump' => 'export' ); + /** * Return a string for connecting to the DB. */ @@ -37,7 +39,7 @@ function cli() { /** * Exports the WordPress DB as SQL using mysqldump. */ - function dump( $args, $assoc_args ) { + function export( $args, $assoc_args ) { if ( !isset( $assoc_args['file'] ) ) { $result_file = sprintf( '%s.sql', DB_NAME ); } else { @@ -92,9 +94,9 @@ public static function help() { WP_CLI::line( << Date: Thu, 1 Mar 2012 09:21:49 +0100 Subject: [PATCH 0242/5359] Replaced the use of echo in the option command with WP_CLI::line --- src/php/wp-cli/commands/internals/option.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index bb223dc7b..842c99a1a 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -86,9 +86,9 @@ public function get( $args ) { return; if ( is_array( $value ) || is_object( $value ) ) { - echo var_export( $value ) . "\n"; + WP_CLI::line( var_export( $value, true ) ); } else { - echo $value . "\n"; + WP_CLI::line( $value ); } } @@ -102,6 +102,6 @@ public static function help() { or: wp option update or: wp option delete EOB - ); + ); } -} +} \ No newline at end of file From bd5ceb532708d8eaba23d8f977269519b81baecd Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 1 Mar 2012 09:23:03 +0100 Subject: [PATCH 0243/5359] Added --silent flag, see #63 --- src/php/wp-cli/class-wp-cli.php | 4 ++++ src/php/wp-cli/wp-cli.php | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 710756b03..ae36ec8f6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -25,6 +25,7 @@ public function addCommand( $name, $class ) { * @param string $message */ static function out( $message ) { + if ( WP_CLI_SILENT ) return; \cli\out($message); } @@ -34,6 +35,7 @@ static function out( $message ) { * @param string $message */ static function line( $message = '' ) { + if ( WP_CLI_SILENT ) return; \cli\line($message); } @@ -55,6 +57,7 @@ static function error( $message, $label = 'Error' ) { * @param string $label */ static function success( $message, $label = 'Success' ) { + if ( WP_CLI_SILENT ) return; \cli\line( '%G' . $label . ': %n' . $message ); } @@ -65,6 +68,7 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { + if ( WP_CLI_SILENT ) return; \cli\line( '%C' . $label . ': %n' . $message ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index b82ee39dc..f69163942 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -81,6 +81,13 @@ WP_CLI::set_url( $blog ); } +// Implement --silent flag +if ( isset( $assoc_args['silent'] ) ) { + define('WP_CLI_SILENT', true); +} else { + define('WP_CLI_SILENT', false); +} + // Set installer flag before loading any WP files if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { define( 'WP_INSTALLING', true ); From 35270db9dd7a685eac549ca36c1b6efd2d8b4511 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 1 Mar 2012 10:03:09 +0100 Subject: [PATCH 0244/5359] Revert of echo replaced by WP_CLI::line in option command --- src/php/wp-cli/commands/internals/option.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 842c99a1a..f8ad70e7e 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -86,9 +86,9 @@ public function get( $args ) { return; if ( is_array( $value ) || is_object( $value ) ) { - WP_CLI::line( var_export( $value, true ) ); + echo var_export( $value ) . "\n"; } else { - WP_CLI::line( $value ); + echo $value . "\n"; } } From 8924c97ce92c256a0723fe59249d5ce35f4376c2 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 1 Mar 2012 10:10:47 +0100 Subject: [PATCH 0245/5359] Added --url global parameter, see #69 --- src/php/wp-cli/class-wp-cli.php | 18 ++++++++++-------- src/php/wp-cli/wp-cli.php | 12 ++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index ae36ec8f6..c77ab67ae 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -154,14 +154,16 @@ static function legend( $legend ) { * @param string $url The URL */ static function set_url( $url ) { - if ( false === strpos( $url, '/' ) ) - $url .= '/'; - - list( $domain, $path ) = explode( '/', $url, 2 ); - - $_SERVER['HTTP_HOST'] = $domain; - - $_SERVER['REQUEST_URI'] = '/' . $path; + $url_parts = parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + + $_SERVER['HTTP_HOST'] = $url_parts['host']; + $_SERVER['REQUEST_URI'] = $url_parts['path'] . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); + $_SERVER['REQUEST_URL'] = $url_parts['path']; + $_SERVER['QUERY_STRING'] = $url_parts['query']; } /** diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index f69163942..363ccc260 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -66,6 +66,10 @@ exit; } +if ( isset( $assoc_args['url'] ) ) { + WP_CLI::set_url( $assoc_args['url'] ); +} + // Handle --blog parameter if ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; @@ -97,6 +101,14 @@ require_once(WP_ROOT . 'wp-load.php'); require_once(ABSPATH . 'wp-admin/includes/admin.php'); +// Load the right info into the global wp_query +if ( isset( $assoc_args['url'] ) ) { + if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { + $GLOBALS['wp']->parse_request(); + $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); + } +} + // Load all internal commands foreach ( glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename ) { include $filename; From 1f568eb9660245b633f66d0c46ffb9c1554c504a Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 1 Mar 2012 10:12:46 +0100 Subject: [PATCH 0246/5359] --url now supersedes --blog --- src/php/wp-cli/wp-cli.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 363ccc260..76daa0bdc 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -66,12 +66,10 @@ exit; } +// Handle --url and --blog parameters if ( isset( $assoc_args['url'] ) ) { - WP_CLI::set_url( $assoc_args['url'] ); -} - -// Handle --blog parameter -if ( isset( $assoc_args['blog'] ) ) { + $blog = $assoc_args['url']; +} elseif ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); if ( true === $blog ) { From 6c59680634c69b2bce471f70a0e6abf921b19fa4 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Thu, 1 Mar 2012 10:35:37 +0100 Subject: [PATCH 0247/5359] Auto-discovery for the current blog, see #42 --- src/php/wp-cli/wp-cli.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 76daa0bdc..d6035675a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -79,6 +79,26 @@ $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); } +// Try to find the blog parameter in the wp-config file +if ( !isset( $blog ) ) { + if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { + $wp_config_file = file_get_contents( WP_ROOT . '/wp-config.php' ); + $hit = array(); + if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { + foreach( $matches[2] as $def_key => $def_name ) { + if ( 'DOMAIN_CURRENT_SITE' == $def_name ) + $hit['domain'] = $matches[5][$def_key]; + if ( 'PATH_CURRENT_SITE' == $def_name ) + $hit['path'] = $matches[5][$def_key]; + } + } + if ( !empty( $hit ) && isset( $hit['domain'] ) ) + $blog = $hit['domain']; + if ( !empty( $hit ) && isset( $hit['path'] ) ) + $blog .= $hit['path']; + } +} + if ( isset( $blog ) ) { WP_CLI::set_url( $blog ); } From 70bb55465ff1199b037107006523e0c78c50faea Mon Sep 17 00:00:00 2001 From: "John P. Bloch" Date: Thu, 1 Mar 2012 14:20:12 -0500 Subject: [PATCH 0248/5359] Add checks to see if WP_CLI_SILENT is defined before using it as if it were. --- src/php/wp-cli/class-wp-cli.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index c77ab67ae..bd694b9a0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -25,7 +25,7 @@ public function addCommand( $name, $class ) { * @param string $message */ static function out( $message ) { - if ( WP_CLI_SILENT ) return; + if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; \cli\out($message); } @@ -35,7 +35,7 @@ static function out( $message ) { * @param string $message */ static function line( $message = '' ) { - if ( WP_CLI_SILENT ) return; + if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; \cli\line($message); } @@ -57,7 +57,7 @@ static function error( $message, $label = 'Error' ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - if ( WP_CLI_SILENT ) return; + if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; \cli\line( '%G' . $label . ': %n' . $message ); } @@ -68,7 +68,7 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - if ( WP_CLI_SILENT ) return; + if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; \cli\line( '%C' . $label . ': %n' . $message ); } From 89e05995d6ab624538da5175541c08606d4cfbdc Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 2 Mar 2012 14:46:44 +0200 Subject: [PATCH 0249/5359] bump version to 0.5.0-dev --- src/php/wp-cli/wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index d6035675a..369a62ecd 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die( 'Only cli access' ); } -define( 'WP_CLI_VERSION', '0.4.0' ); +define( 'WP_CLI_VERSION', '0.5.0-dev' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); @@ -88,7 +88,7 @@ foreach( $matches[2] as $def_key => $def_name ) { if ( 'DOMAIN_CURRENT_SITE' == $def_name ) $hit['domain'] = $matches[5][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) + if ( 'PATH_CURRENT_SITE' == $def_name ) $hit['path'] = $matches[5][$def_key]; } } From a2caf35787a3f9320432799d7b973661ad8b33d2 Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Fri, 2 Mar 2012 14:52:33 +0100 Subject: [PATCH 0250/5359] Fix for warnings caused by implementation of #69 --- src/php/wp-cli/class-wp-cli.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index bd694b9a0..7a8d4b084 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -160,10 +160,10 @@ static function set_url( $url ) { $url_parts = parse_url( 'http://' . $url ); } - $_SERVER['HTTP_HOST'] = $url_parts['host']; - $_SERVER['REQUEST_URI'] = $url_parts['path'] . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); - $_SERVER['REQUEST_URL'] = $url_parts['path']; - $_SERVER['QUERY_STRING'] = $url_parts['query']; + $_SERVER['HTTP_HOST'] = isset($url_parts['host']) ? $url_parts['host'] : ''; + $_SERVER['REQUEST_URI'] = (isset($url_parts['path']) ? $url_parts['path'] : '') . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); + $_SERVER['REQUEST_URL'] = isset($url_parts['path']) ? $url_parts['path'] : ''; + $_SERVER['QUERY_STRING'] = isset($url_parts['query']) ? $url_parts['query'] : ''; } /** From 443ec9c72d557f26fabea45323bec6282fb50b43 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 10 Mar 2012 16:04:59 +0200 Subject: [PATCH 0251/5359] only ignore files generated by build-pear --- .gitignore | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e89c07b32..d9cdde38e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ -.build -dist -.tmp -nbproject -review -vendor +/.build +/dist From 8a6960ca4c75cef3ce48587113c0e38b3f85cc63 Mon Sep 17 00:00:00 2001 From: Mike O'Malley Date: Sat, 10 Mar 2012 02:13:49 -0500 Subject: [PATCH 0252/5359] Add script to allow for non-root installation. sourcing build-local will set up your environment to run wp-cli, including support for bash completion without the need to run as root and modify /etc/bash_completion.d/ --- utils/build-local | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 utils/build-local diff --git a/utils/build-local b/utils/build-local new file mode 100755 index 000000000..1adabb76f --- /dev/null +++ b/utils/build-local @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ "$BASH_SOURCE" = "$0" ]; then + echo "This file should not be executed. It should be sourced into your current shell like this:" + echo + echo "source $BASH_SOURCE" + echo + echo "Add the above line to your .bashrc or .bash_profile to have this environment set up" + echo "automatically when you log in." + exit 1 +fi + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +alias wp='$DIR/../src/bin/wp' + +. $DIR/wp-completion.bash From 298eb69ed1ef2a3dbac2a5a32b9579da6b82785a Mon Sep 17 00:00:00 2001 From: Mike O'Malley Date: Sat, 10 Mar 2012 02:17:49 -0500 Subject: [PATCH 0253/5359] set default table_prefix to "wp_" --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 369a62ecd..11808c891 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -59,7 +59,7 @@ $_POST['uname'] = $assoc_args['user']; $_POST['pwd'] = $assoc_args['pass']; $_POST['dbhost'] = isset( $assoc_args['host'] ) ? $assoc_args['host'] : 'localhost'; - $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : ''; + $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : 'wp_'; $_GET['step'] = 2; require WP_ROOT . '/wp-admin/setup-config.php'; From 8851d476d8a31a7a398cca0059d5ee8ae499c110 Mon Sep 17 00:00:00 2001 From: Mike O'Malley Date: Sat, 10 Mar 2012 02:18:24 -0500 Subject: [PATCH 0254/5359] Add support for --wproot It is no longer required to run wp from inside of the wordpress root directory. --- src/php/wp-cli/wp-cli.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 11808c891..342818422 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -34,8 +34,10 @@ // Define the WordPress location if ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { define('WP_ROOT', $_SERVER['PWD'] . '/../'); -} -else { +} elseif (isset($assoc_args['wproot'])) { + $root = (preg_match('@/$@', $assoc_args['wproot'])) ? $assoc_args['wproot'] : $assoc_args['wproot'] . "/"; + define('WP_ROOT', $root); +} else { define('WP_ROOT', $_SERVER['PWD'] . '/'); } From 4d1c7244e63d625191b4cda16019c9951ce3dd68 Mon Sep 17 00:00:00 2001 From: Mike O'Malley Date: Sat, 10 Mar 2012 02:23:20 -0500 Subject: [PATCH 0255/5359] change error to include new --wproot flag --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 342818422..bf8e9ffe8 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -51,7 +51,7 @@ WP_CLI::success('WordPress downloaded.'); exit; } else { - WP_CLI::error('This does not seem to be a WordPress install. Try running `wp core download`.'); + WP_CLI::error('This does not seem to be a WordPress install. Pass --wproot=`path/to/wordpress` or run `wp core download`.'); exit; } } From e0eed0d986bb0279011dab8bfcd1c1a03e77222a Mon Sep 17 00:00:00 2001 From: Mike O'Malley Date: Sat, 10 Mar 2012 02:23:49 -0500 Subject: [PATCH 0256/5359] add --path flag to allow wordpress installation somewhere other than ./ --- src/php/wp-cli/wp-cli.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index bf8e9ffe8..e4f97a25d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -43,10 +43,12 @@ if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { if ( array( 'core', 'download' ) == $arguments ) { + if (isset($assoc_args['path'])) $docroot = $assoc_args['path']; + else $docroot = './' WP_CLI::line('Downloading WordPress...'); exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); exec("unzip /tmp/wordpress.zip"); - exec("mv wordpress/* ./"); + exec("mv wordpress/* $docroot"); exec("rm -r wordpress"); WP_CLI::success('WordPress downloaded.'); exit; From 84c90cdd556b44fa8c957d2055db476de096a997 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 10 Mar 2012 16:12:23 +0200 Subject: [PATCH 0257/5359] rename --wproot to --path. see #80 --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e4f97a25d..09c3a9876 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -34,8 +34,8 @@ // Define the WordPress location if ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { define('WP_ROOT', $_SERVER['PWD'] . '/../'); -} elseif (isset($assoc_args['wproot'])) { - $root = (preg_match('@/$@', $assoc_args['wproot'])) ? $assoc_args['wproot'] : $assoc_args['wproot'] . "/"; +} elseif (isset($assoc_args['path'])) { + $root = (preg_match('@/$@', $assoc_args['path'])) ? $assoc_args['path'] : $assoc_args['path'] . "/"; define('WP_ROOT', $root); } else { define('WP_ROOT', $_SERVER['PWD'] . '/'); @@ -53,7 +53,7 @@ WP_CLI::success('WordPress downloaded.'); exit; } else { - WP_CLI::error('This does not seem to be a WordPress install. Pass --wproot=`path/to/wordpress` or run `wp core download`.'); + WP_CLI::error('This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.'); exit; } } From 404362b1e1b790a2c08adaa937c042fc91023754 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Fri, 9 Mar 2012 17:02:46 -0800 Subject: [PATCH 0258/5359] Adds plugin update_all to internal commands --- src/php/wp-cli/class-cli-upgrader-skin.php | 2 + src/php/wp-cli/commands/internals/plugin.php | 44 ++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index d59958c6b..98eb1d275 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -9,6 +9,8 @@ class CLI_Upgrader_Skin extends WP_Upgrader_Skin { function header() {} function footer() {} + function bulk_header() {} + function bulk_footer() {} // TODO: show prompt function request_filesystem_credentials( $error = false ) { diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index dcca8a2f1..021cc24c5 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -253,6 +253,48 @@ function update( $args ) { $result = $upgrader->upgrade( $file ); } + /** + * Update all plugins + * + * @param array $args + */ + function update_all( $args ) { + // Force WordPress to update plugin status transients + wp_update_plugins(); + $plugins = get_plugins(); + $plugins = array_merge( $plugins, get_mu_plugins() ); + + // Grab all Plugins that need Updates + $plugins_to_update = array(); + foreach ( $plugins as $file => $plugin ) { + if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { + $plugins_to_update[] = $file; + } + } + + if ( empty( $plugins_to_update ) ) { + WP_CLI::warning( 'Nothing to Update!' ); + return; + } + + // Update ALL THE THINGS + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); + $result = $upgrader->bulk_upgrade( $plugins_to_update ); + + // Let the user know the results. + $num_to_update = count( $plugins_to_update ); + $num_updated = count( array_filter( $result ) ); + + $line = "Updated $num_updated/$num_to_update Plugins."; + if ( $num_to_update == $num_updated ) { + WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + WP_CLI::warning( $line ); + } else { + WP_CLI::error( $line ); + } + } + /** * Uninstall a plugin * @@ -362,6 +404,8 @@ public static function help() { update update a plugin from wordpress.org + update_all update all plugins from wordpress.org + uninstall run the uninstallation procedure for a plugin delete delete a plugin From 79a84852e403a15c86144cd76a6ca5d5d7a83378 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Sat, 10 Mar 2012 16:27:02 -0800 Subject: [PATCH 0259/5359] Move update_all into update with --all * Update all plugins with wp plugin update --all * List plugins with available updates with wp plugin update --- src/php/wp-cli/commands/internals/plugin.php | 72 ++++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 021cc24c5..aa9f946f0 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -242,56 +242,71 @@ function install( $args, $assoc_args ) { * Update a plugin * * @param array $args + * @param array $assoc_args */ - function update( $args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - + function update( $args, $assoc_args ) { // Force WordPress to update the plugin list wp_update_plugins(); - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); - $result = $upgrader->upgrade( $file ); - } + // If we have arguments and not updating all, update named plugin + if ( ! empty( $args ) && ! isset( $assoc_args['all'] ) ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - /** - * Update all plugins - * - * @param array $args - */ - function update_all( $args ) { - // Force WordPress to update plugin status transients - wp_update_plugins(); + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); + $result = $upgrader->upgrade( $file ); + return; + } + + // If not, fall through and load plugin info. $plugins = get_plugins(); $plugins = array_merge( $plugins, get_mu_plugins() ); // Grab all Plugins that need Updates + // If we have no sub-arguments, add them to the output list. + $plugin_list = "Plugin Updates Available:"; $plugins_to_update = array(); foreach ( $plugins as $file => $plugin ) { if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { $plugins_to_update[] = $file; + + if ( empty( $assoc_args ) ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace('.php', '', basename($file)); + else + $name = dirname($file); + + $plugin_list .= "\n\t%y$name%n"; + } } } if ( empty( $plugins_to_update ) ) { - WP_CLI::warning( 'Nothing to Update!' ); + WP_CLI::warning( 'No Plugin Updates Available.' ); return; } - // Update ALL THE THINGS - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); - $result = $upgrader->bulk_upgrade( $plugins_to_update ); + // If --all, UPDATE ALL THE THINGS + if ( isset( $assoc_args['all'] ) ) + { + $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); + $result = $upgrader->bulk_upgrade( $plugins_to_update ); - // Let the user know the results. - $num_to_update = count( $plugins_to_update ); - $num_updated = count( array_filter( $result ) ); + // Let the user know the results. + $num_to_update = count( $plugins_to_update ); + $num_updated = count( array_filter( $result ) ); - $line = "Updated $num_updated/$num_to_update Plugins."; - if ( $num_to_update == $num_updated ) { - WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - WP_CLI::warning( $line ); + $line = "Updated $num_updated/$num_to_update Plugins."; + if ( $num_to_update == $num_updated ) { + WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + WP_CLI::warning( $line ); + } else { + WP_CLI::error( $line ); + } + + // Else list plugins that require updates } else { - WP_CLI::error( $line ); + WP_CLI::line( $plugin_list ); } } @@ -403,8 +418,7 @@ public static function help() { --dev install the development version update update a plugin from wordpress.org - - update_all update all plugins from wordpress.org + --all update all plugins from wordpress.org uninstall run the uninstallation procedure for a plugin From b8421104efd4bbff24ade96c78c12783e6b74fef Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 14:37:45 +0200 Subject: [PATCH 0260/5359] force direct filesystem access. fixes #79 --- src/php/wp-cli/class-cli-upgrader-skin.php | 5 ----- src/php/wp-cli/wp-cli.php | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index 98eb1d275..a6d748490 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -12,11 +12,6 @@ function footer() {} function bulk_header() {} function bulk_footer() {} - // TODO: show prompt - function request_filesystem_credentials( $error = false ) { - $this->error( $error ); - } - function error( $error ) { if ( !$error ) return; diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 09c3a9876..9900762e3 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -131,6 +131,9 @@ } } +// Set filesystem method +add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); + // Load all internal commands foreach ( glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename ) { include $filename; From 74810c2a0c094fb4862453fbdd8db6515c76df99 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 16:32:31 +0200 Subject: [PATCH 0261/5359] add missing semicolon --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 9900762e3..412c2a4bf 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -44,7 +44,7 @@ if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { if ( array( 'core', 'download' ) == $arguments ) { if (isset($assoc_args['path'])) $docroot = $assoc_args['path']; - else $docroot = './' + else $docroot = './'; WP_CLI::line('Downloading WordPress...'); exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); exec("unzip /tmp/wordpress.zip"); From 7991478b2c847963b83bba2445f28eb49a5450ad Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 16:33:21 +0200 Subject: [PATCH 0262/5359] use require() when possible --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 412c2a4bf..23b6eb9e4 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -119,9 +119,9 @@ define( 'WP_INSTALLING', true ); } -// Load WordPress libs -require_once(WP_ROOT . 'wp-load.php'); -require_once(ABSPATH . 'wp-admin/includes/admin.php'); +// Load WordPress +require WP_ROOT . 'wp-load.php'; +require ABSPATH . 'wp-admin/includes/admin.php'; // Load the right info into the global wp_query if ( isset( $assoc_args['url'] ) ) { From 218b0eb50f6bbb5eef79f260852c8eee55b1fb43 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 16:39:22 +0200 Subject: [PATCH 0263/5359] rename set_url() to set_url_params() --- src/php/wp-cli/class-wp-cli.php | 2 +- src/php/wp-cli/commands/internals/core.php | 2 +- src/php/wp-cli/wp-cli.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 7a8d4b084..4aa6bae2a 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -153,7 +153,7 @@ static function legend( $legend ) { * * @param string $url The URL */ - static function set_url( $url ) { + static function set_url_params( $url ) { $url_parts = parse_url( $url ); if ( !isset( $url_parts['scheme'] ) ) { diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 651c4c47a..afa6f07f9 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -104,7 +104,7 @@ public function install( $args, $assoc_args ) { } if ( $site_url ) - WP_CLI::set_url( $site_url ); + WP_CLI::set_url_params( $site_url ); if ( $missing ) exit(1); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 23b6eb9e4..7e4ba3bb5 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -104,7 +104,7 @@ } if ( isset( $blog ) ) { - WP_CLI::set_url( $blog ); + WP_CLI::set_url_params( $blog ); } // Implement --silent flag From fef1b1e1a55ffcf565682796901eca719206b462 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 16:43:38 +0200 Subject: [PATCH 0264/5359] move URL seeking code to WP_CLI::_set_url() --- src/php/wp-cli/class-wp-cli.php | 45 +++++++++++++++++++++++++++++++-- src/php/wp-cli/wp-cli.php | 36 +------------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 4aa6bae2a..8310a8043 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -155,11 +155,11 @@ static function legend( $legend ) { */ static function set_url_params( $url ) { $url_parts = parse_url( $url ); - + if ( !isset( $url_parts['scheme'] ) ) { $url_parts = parse_url( 'http://' . $url ); } - + $_SERVER['HTTP_HOST'] = isset($url_parts['host']) ? $url_parts['host'] : ''; $_SERVER['REQUEST_URI'] = (isset($url_parts['path']) ? $url_parts['path'] : '') . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); $_SERVER['REQUEST_URL'] = isset($url_parts['path']) ? $url_parts['path'] : ''; @@ -191,5 +191,46 @@ static function get_upgrader( $class ) { return new $class( new CLI_Upgrader_Skin ); } + + /** + * Set url based on --url, --blog or wp-config.php + */ + static function _set_url() { + if ( isset( $assoc_args['url'] ) ) { + $blog = $assoc_args['url']; + } elseif ( isset( $assoc_args['blog'] ) ) { + $blog = $assoc_args['blog']; + unset( $assoc_args['blog'] ); + if ( true === $blog ) { + WP_CLI::line( 'usage: wp --blog=example.com' ); + } + } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { + $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); + } + + // Try to find the blog parameter in the wp-config file + if ( !isset( $blog ) ) { + if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { + $wp_config_file = file_get_contents( WP_ROOT . '/wp-config.php' ); + $hit = array(); + if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { + foreach( $matches[2] as $def_key => $def_name ) { + if ( 'DOMAIN_CURRENT_SITE' == $def_name ) + $hit['domain'] = $matches[5][$def_key]; + if ( 'PATH_CURRENT_SITE' == $def_name ) + $hit['path'] = $matches[5][$def_key]; + } + } + if ( !empty( $hit ) && isset( $hit['domain'] ) ) + $blog = $hit['domain']; + if ( !empty( $hit ) && isset( $hit['path'] ) ) + $blog .= $hit['path']; + } + } + + if ( isset( $blog ) ) { + WP_CLI::set_url_params( $blog ); + } + } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 7e4ba3bb5..e272c903b 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -71,41 +71,7 @@ } // Handle --url and --blog parameters -if ( isset( $assoc_args['url'] ) ) { - $blog = $assoc_args['url']; -} elseif ( isset( $assoc_args['blog'] ) ) { - $blog = $assoc_args['blog']; - unset( $assoc_args['blog'] ); - if ( true === $blog ) { - WP_CLI::line( 'usage: wp --blog=example.com' ); - } -} elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { - $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); -} - -// Try to find the blog parameter in the wp-config file -if ( !isset( $blog ) ) { - if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { - $wp_config_file = file_get_contents( WP_ROOT . '/wp-config.php' ); - $hit = array(); - if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { - foreach( $matches[2] as $def_key => $def_name ) { - if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[5][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[5][$def_key]; - } - } - if ( !empty( $hit ) && isset( $hit['domain'] ) ) - $blog = $hit['domain']; - if ( !empty( $hit ) && isset( $hit['path'] ) ) - $blog .= $hit['path']; - } -} - -if ( isset( $blog ) ) { - WP_CLI::set_url_params( $blog ); -} +WP_CLI::_set_url(); // Implement --silent flag if ( isset( $assoc_args['silent'] ) ) { From cd1204f6a263523046636dfc4ff2b28bca65b971 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 16:46:03 +0200 Subject: [PATCH 0265/5359] WP_CLI_SILENT is always defined --- src/php/wp-cli/class-wp-cli.php | 8 ++++---- src/php/wp-cli/wp-cli.php | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8310a8043..6ba659d79 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -25,7 +25,7 @@ public function addCommand( $name, $class ) { * @param string $message */ static function out( $message ) { - if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; + if ( WP_CLI_SILENT ) return; \cli\out($message); } @@ -35,7 +35,7 @@ static function out( $message ) { * @param string $message */ static function line( $message = '' ) { - if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; + if ( WP_CLI_SILENT ) return; \cli\line($message); } @@ -57,7 +57,7 @@ static function error( $message, $label = 'Error' ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; + if ( WP_CLI_SILENT ) return; \cli\line( '%G' . $label . ': %n' . $message ); } @@ -68,7 +68,7 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - if ( defined( 'WP_CLI_SILENT' ) && WP_CLI_SILENT ) return; + if ( WP_CLI_SILENT ) return; \cli\line( '%C' . $label . ': %n' . $message ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e272c903b..0ba5b669d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -74,11 +74,7 @@ WP_CLI::_set_url(); // Implement --silent flag -if ( isset( $assoc_args['silent'] ) ) { - define('WP_CLI_SILENT', true); -} else { - define('WP_CLI_SILENT', false); -} +define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); // Set installer flag before loading any WP files if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { From bd9bef64dc7e5d2d03687fcbdc31c889c57ac2e5 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 17:14:05 +0200 Subject: [PATCH 0266/5359] move core download and core config to core.php --- src/php/wp-cli/commands/internals/core.php | 122 +++++++++++++-------- src/php/wp-cli/wp-cli.php | 26 ++--- 2 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index afa6f07f9..508473877 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -10,6 +10,83 @@ */ class CoreCommand extends WP_CLI_Command { + /** + * Download the core files from wordpress.org + */ + public function download( $args, $assoc_args ) { + if ( is_readable( WP_ROOT . 'wp-load.php' ) ) + WP_CLI::error( 'WordPress files seem to already be present here.' ); + + if (isset($assoc_args['path'])) + $docroot = $assoc_args['path']; + else + $docroot = './'; + + WP_CLI::line('Downloading WordPress...'); + exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); + exec("unzip /tmp/wordpress.zip"); + exec("mv wordpress/* $docroot"); + exec("rm -r wordpress"); + WP_CLI::success('WordPress downloaded.'); + } + + /** + * Set up a wp-config.php file. + */ + public function config( $args, $assoc_args ) { + $_POST['dbname'] = $assoc_args['name']; + $_POST['uname'] = $assoc_args['user']; + $_POST['pwd'] = $assoc_args['pass']; + $_POST['dbhost'] = isset( $assoc_args['host'] ) ? $assoc_args['host'] : 'localhost'; + $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : 'wp_'; + + $_GET['step'] = 2; + require WP_ROOT . '/wp-admin/setup-config.php'; + } + + /** + * Run wp_install. Assumes that wp-config.php is already in place. + */ + public function install( $args, $assoc_args ) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + + if ( is_blog_installed() ) { + WP_CLI::error( 'WordPress is already installed.' ); + } + + extract( wp_parse_args( $assoc_args, array( + 'site_url' => defined( 'WP_SITEURL' ) ? WP_SITEURL : '', + 'site_title' => '', + 'admin_name' => 'admin', + 'admin_email' => '', + 'admin_password' => '' + ) ), EXTR_SKIP ); + + $missing = false; + foreach ( array( 'site_url', 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { + if ( empty( $$required_arg ) ) { + WP_CLI::warning( "missing --$required_arg parameter" ); + $missing = true; + } + } + + if ( $site_url ) + WP_CLI::set_url_params( $site_url ); + + if ( $missing ) + exit(1); + + $public = true; + + $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); + + if ( is_wp_error( $result ) ) { + WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); + } else { + WP_CLI::success( 'WordPress installed successfully.' ); + } + } + /** * Display the WordPress version. */ @@ -50,7 +127,7 @@ public function version( $args = array(), $assoc_args = array() ) { * * @param array $args */ - function update($args) { + function update( $args ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); @@ -77,49 +154,6 @@ function update($args) { } } - /** - * Run wp_install. Assumes that wp-config.php is already in place. - */ - public function install( $args, $assoc_args ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - - if ( is_blog_installed() ) { - WP_CLI::error( 'WordPress is already installed.' ); - } - - extract( wp_parse_args( $assoc_args, array( - 'site_url' => defined( 'WP_SITEURL' ) ? WP_SITEURL : '', - 'site_title' => '', - 'admin_name' => 'admin', - 'admin_email' => '', - 'admin_password' => '' - ) ), EXTR_SKIP ); - - $missing = false; - foreach ( array( 'site_url', 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { - if ( empty( $$required_arg ) ) { - WP_CLI::warning( "missing --$required_arg parameter" ); - $missing = true; - } - } - - if ( $site_url ) - WP_CLI::set_url_params( $site_url ); - - if ( $missing ) - exit(1); - - $public = true; - - $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); - - if ( is_wp_error( $result ) ) { - WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); - } else { - WP_CLI::success( 'WordPress installed successfully.' ); - } - } - /** * Help function for this command */ diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 0ba5b669d..d066b335f 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -43,14 +43,8 @@ if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { if ( array( 'core', 'download' ) == $arguments ) { - if (isset($assoc_args['path'])) $docroot = $assoc_args['path']; - else $docroot = './'; - WP_CLI::line('Downloading WordPress...'); - exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); - exec("unzip /tmp/wordpress.zip"); - exec("mv wordpress/* $docroot"); - exec("rm -r wordpress"); - WP_CLI::success('WordPress downloaded.'); + include WP_CLI_ROOT.'/commands/internals/core.php'; + new WP_CLI::$commands['core']( $arguments, $assoc_args ); exit; } else { WP_CLI::error('This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.'); @@ -59,21 +53,15 @@ } if ( array( 'core', 'config' ) == $arguments ) { - $_POST['dbname'] = $assoc_args['name']; - $_POST['uname'] = $assoc_args['user']; - $_POST['pwd'] = $assoc_args['pass']; - $_POST['dbhost'] = isset( $assoc_args['host'] ) ? $assoc_args['host'] : 'localhost'; - $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : 'wp_'; - - $_GET['step'] = 2; - require WP_ROOT . '/wp-admin/setup-config.php'; + include WP_CLI_ROOT.'/commands/internals/core.php'; + new WP_CLI::$commands['core']( $arguments, $assoc_args ); exit; } // Handle --url and --blog parameters WP_CLI::_set_url(); -// Implement --silent flag +// Check --silent flag define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); // Set installer flag before loading any WP files @@ -98,10 +86,10 @@ // Load all internal commands foreach ( glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename ) { - include $filename; + include_once $filename; } -// Load all plugin commands +// Load all community commands foreach ( glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename ) { include $filename; } From 37656a3031d565b47e0f39310ae81901341707fc Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 17:14:50 +0200 Subject: [PATCH 0267/5359] define WP_CLI_SILENT earlier --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index d066b335f..a0edf8a11 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -25,6 +25,9 @@ // Get the cli arguments list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); +// Check --silent flag +define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); + // Handle --version parameter if ( isset( $assoc_args['version'] ) ) { WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); @@ -61,9 +64,6 @@ // Handle --url and --blog parameters WP_CLI::_set_url(); -// Check --silent flag -define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); - // Set installer flag before loading any WP files if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { define( 'WP_INSTALLING', true ); From e9222d9c5be00b349cb3d61e6f61da82da3f3117 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 17:28:18 +0200 Subject: [PATCH 0268/5359] use rtrim() instead of preg_match(). see #80 --- src/php/wp-cli/wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index a0edf8a11..8a2636960 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -36,12 +36,12 @@ // Define the WordPress location if ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { - define('WP_ROOT', $_SERVER['PWD'] . '/../'); -} elseif (isset($assoc_args['path'])) { - $root = (preg_match('@/$@', $assoc_args['path'])) ? $assoc_args['path'] : $assoc_args['path'] . "/"; - define('WP_ROOT', $root); + define( 'WP_ROOT', $_SERVER['PWD'] . '/../' ); +} elseif ( !empty( $assoc_args['path'] ) ) { + // trailingslashit() isn't available yet + define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); } else { - define('WP_ROOT', $_SERVER['PWD'] . '/'); + define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { From 10bdee6409fc2aaa1633ac25bd7b01bd836a6398 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 17:35:53 +0200 Subject: [PATCH 0269/5359] add _run_core_command() helper --- src/php/wp-cli/class-wp-cli.php | 8 ++++++++ src/php/wp-cli/wp-cli.php | 8 ++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 6ba659d79..5c16813f6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -232,5 +232,13 @@ static function _set_url() { WP_CLI::set_url_params( $blog ); } } + + static function _run_core_command( $arguments, $assoc_args ) { + array_shift( $arguments ); + + include WP_CLI_ROOT.'/commands/internals/core.php'; + new WP_CLI::$commands['core']( $arguments, $assoc_args ); + exit; + } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 8a2636960..5eb1d9c68 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -46,9 +46,7 @@ if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { if ( array( 'core', 'download' ) == $arguments ) { - include WP_CLI_ROOT.'/commands/internals/core.php'; - new WP_CLI::$commands['core']( $arguments, $assoc_args ); - exit; + WP_CLI::_run_core_command( $arguments, $assoc_args ); } else { WP_CLI::error('This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.'); exit; @@ -56,9 +54,7 @@ } if ( array( 'core', 'config' ) == $arguments ) { - include WP_CLI_ROOT.'/commands/internals/core.php'; - new WP_CLI::$commands['core']( $arguments, $assoc_args ); - exit; + WP_CLI::_run_core_command( $arguments, $assoc_args ); } // Handle --url and --blog parameters From 5634673d59927d7c2aa2cd1aa629d7af364229fc Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 12 Mar 2012 17:53:56 +0200 Subject: [PATCH 0270/5359] load all commands only when needed --- src/php/wp-cli/class-wp-cli.php | 41 +++++++++++++++++++++++++++++---- src/php/wp-cli/wp-cli.php | 37 ++++------------------------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 5c16813f6..13997d183 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -233,11 +233,44 @@ static function _set_url() { } } - static function _run_core_command( $arguments, $assoc_args ) { - array_shift( $arguments ); + static function load_all_commands() { + foreach ( array( 'internals', 'community' ) as $dir ) { + foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { + include $filename; + } + } + } + + static function run_command( $arguments, $assoc_args ) { + if ( empty( $arguments ) ) { + WP_CLI::load_all_commands(); + $command = 'help'; + } else { + $command = array_shift( $arguments ); + + $aliases = array( + 'sql' => 'db' + ); + + if ( isset( $aliases[ $command ] ) ) + $command = $aliases[ $command ]; + + foreach ( array( 'internals', 'community' ) as $dir ) { + $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + + if ( is_readable( $path ) ) { + include $path; + break; + } + } + } + + if ( !isset( WP_CLI::$commands[$command] ) ) { + WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + exit; + } - include WP_CLI_ROOT.'/commands/internals/core.php'; - new WP_CLI::$commands['core']( $arguments, $assoc_args ); + new WP_CLI::$commands[$command]( $arguments, $assoc_args ); exit; } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 5eb1d9c68..3824c92dd 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -46,7 +46,7 @@ if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { if ( array( 'core', 'download' ) == $arguments ) { - WP_CLI::_run_core_command( $arguments, $assoc_args ); + WP_CLI::run_command( $arguments, $assoc_args ); } else { WP_CLI::error('This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.'); exit; @@ -54,7 +54,7 @@ } if ( array( 'core', 'config' ) == $arguments ) { - WP_CLI::_run_core_command( $arguments, $assoc_args ); + WP_CLI::run_command( $arguments, $assoc_args ); } // Handle --url and --blog parameters @@ -80,42 +80,15 @@ // Set filesystem method add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); -// Load all internal commands -foreach ( glob(WP_CLI_ROOT.'/commands/internals/*.php') as $filename ) { - include_once $filename; -} - -// Load all community commands -foreach ( glob(WP_CLI_ROOT.'/commands/community/*.php') as $filename ) { - include $filename; -} - // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { + WP_CLI::load_all_commands(); + foreach ( WP_CLI::$commands as $name => $command ) { WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_subcommands($command) ) ); } exit; } -// Get the top-level command -if ( empty( $arguments ) ) - $command = 'help'; -else - $command = array_shift( $arguments ); - -// Translate aliases -$aliases = array( - 'sql' => 'db' -); - -if ( isset( $aliases[ $command ] ) ) - $command = $aliases[ $command ]; - -if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); - exit; -} - -new WP_CLI::$commands[$command]( $arguments, $assoc_args ); +WP_CLI::run_command( $arguments, $assoc_args ); From ccfb07a5a9b833a90cfa9ec17f7e7020ff201dbb Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 16:33:06 +0200 Subject: [PATCH 0271/5359] always load all commands when 'help' is involved. fixes #84 --- src/php/wp-cli/class-wp-cli.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 13997d183..ab6e99f52 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -243,7 +243,6 @@ static function load_all_commands() { static function run_command( $arguments, $assoc_args ) { if ( empty( $arguments ) ) { - WP_CLI::load_all_commands(); $command = 'help'; } else { $command = array_shift( $arguments ); @@ -254,7 +253,12 @@ static function run_command( $arguments, $assoc_args ) { if ( isset( $aliases[ $command ] ) ) $command = $aliases[ $command ]; + } + if ( 'help' == $command ) { + self::load_all_commands(); + } + else { foreach ( array( 'internals', 'community' ) as $dir ) { $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; From 12e0debc3467fcb5275234b4691473489d1644ca Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 16:36:48 +0200 Subject: [PATCH 0272/5359] show error when wp help receives an invalid parameter --- src/php/wp-cli/commands/internals/help.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 0a8dd0151..64f67f2bf 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -20,7 +20,11 @@ public function __construct( $args ) { $this->general_help(); } else { $command = $args[0]; - if ( 'help' == $command || !isset( WP_CLI::$commands[$command] ) ) { + + if ( !isset( WP_CLI::$commands[$command] ) ) { + WP_CLI::error( "'$command' is not a registered wp command." ); + } elseif ( 'help' == $command ) { + // prevent endless loop $this->general_help(); } else { $class = WP_CLI::$commands[$command]; From f99868242a6526ff1003f4b18162483a8539fefd Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 16:58:51 +0200 Subject: [PATCH 0273/5359] plugin update strings. #82 --- src/php/wp-cli/commands/internals/plugin.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index aa9f946f0..8d04e5c44 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -263,7 +263,7 @@ function update( $args, $assoc_args ) { // Grab all Plugins that need Updates // If we have no sub-arguments, add them to the output list. - $plugin_list = "Plugin Updates Available:"; + $plugin_list = "Available plugin updates:"; $plugins_to_update = array(); foreach ( $plugins as $file => $plugin ) { if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { @@ -281,13 +281,12 @@ function update( $args, $assoc_args ) { } if ( empty( $plugins_to_update ) ) { - WP_CLI::warning( 'No Plugin Updates Available.' ); + WP_CLI::line( 'No plugin updates available.' ); return; } // If --all, UPDATE ALL THE THINGS - if ( isset( $assoc_args['all'] ) ) - { + if ( isset( $assoc_args['all'] ) ) { $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); $result = $upgrader->bulk_upgrade( $plugins_to_update ); From 9e8c7ba682480bdcf7c2f87a4ad7bd70fd14ca1f Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 17:22:56 +0200 Subject: [PATCH 0274/5359] split plugin update() into update_single() and update_multiple() --- src/php/wp-cli/commands/internals/plugin.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 8d04e5c44..d7c391a1d 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -248,16 +248,20 @@ function update( $args, $assoc_args ) { // Force WordPress to update the plugin list wp_update_plugins(); - // If we have arguments and not updating all, update named plugin - if ( ! empty( $args ) && ! isset( $assoc_args['all'] ) ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); - $result = $upgrader->upgrade( $file ); - return; + if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { + $this->update_single( $args, $assoc_args ); + } else { + $this->update_multiple( $args, $assoc_args ); } + } + + private function update_single( $args, $assoc_args ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + WP_CLI::get_upgrader( 'Plugin_Upgrader' )->upgrade( $file ); + } - // If not, fall through and load plugin info. + private function update_multiple( $args, $assoc_args ) { $plugins = get_plugins(); $plugins = array_merge( $plugins, get_mu_plugins() ); From 97bba512595ccbbed05f9aae533ce2849aa6cfb0 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 17:24:01 +0200 Subject: [PATCH 0275/5359] must-use plugin updates are not supported, so let's not load them at all --- src/php/wp-cli/commands/internals/plugin.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d7c391a1d..a5b4d05a9 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -263,7 +263,6 @@ private function update_single( $args, $assoc_args ) { private function update_multiple( $args, $assoc_args ) { $plugins = get_plugins(); - $plugins = array_merge( $plugins, get_mu_plugins() ); // Grab all Plugins that need Updates // If we have no sub-arguments, add them to the output list. From 02022f8c892b3135def683bd20e513d90a93afe4 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 13 Mar 2012 17:34:35 +0200 Subject: [PATCH 0276/5359] fix _set_url() --- src/php/wp-cli/class-wp-cli.php | 12 ++++-------- src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index ab6e99f52..a4d447ace 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -192,12 +192,10 @@ static function get_upgrader( $class ) { return new $class( new CLI_Upgrader_Skin ); } - /** - * Set url based on --url, --blog or wp-config.php - */ - static function _set_url() { + static function _set_url( &$assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; + unset( $assoc_args['url'] ); } elseif ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); @@ -206,10 +204,8 @@ static function _set_url() { } } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); - } - - // Try to find the blog parameter in the wp-config file - if ( !isset( $blog ) ) { + } else { + // Try to find the blog parameter in the wp-config file if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { $wp_config_file = file_get_contents( WP_ROOT . '/wp-config.php' ); $hit = array(); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3824c92dd..61bc0bc79 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -58,7 +58,7 @@ } // Handle --url and --blog parameters -WP_CLI::_set_url(); +WP_CLI::_set_url( $assoc_args ); // Set installer flag before loading any WP files if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { From 0158f1ab4b8c8f9275639f7777b8e138b9701826 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Thu, 15 Mar 2012 14:56:06 -0700 Subject: [PATCH 0277/5359] Add whitespace to theme help to allow subcommands, and add path --directory help. --- src/php/wp-cli/commands/internals/theme.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 76be9b533..9babbb815 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -168,8 +168,12 @@ public static function help() { Available sub-commands: status display status of all installed themes or of a particular theme + activate activate a particular theme + path print path to the theme's stylesheet + --directory get the path to the closest parent directory + delete delete a theme EOB ); From 799834e0b5746696daf452761d91626e1985bb4d Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Thu, 15 Mar 2012 15:00:11 -0700 Subject: [PATCH 0278/5359] Add theme update functionality to themes internal --- src/php/wp-cli/commands/internals/theme.php | 74 +++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 9babbb815..35263029f 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -121,6 +121,77 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } + /** + * Update a theme + * + * @param array $args + * @param array $assoc_args + */ + function update( $args, $assoc_args ) { + // Force WordPress to update the theme list + wp_update_themes(); + + // If we have arguments and not updating all, update named theme + if ( ! empty( $args ) && ! isset( $assoc_args['all'] ) ) { + list( $theme, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + $upgrader = WP_CLI::get_upgrader( 'Theme_Upgrader' ); + $result = $upgrader->upgrade( $name ); + return; + } + + // If not, fall through and load theme info. + $themes = get_themes(); + + // Grab all Themes that need Updates + // If we have no sub-arguments, add them to the output list. + $theme_list = "Available theme updates:"; + $themes_to_update = array(); + foreach ( $themes as $theme ) { + $file = $theme['Stylesheet']; + if ( WP_CLI::get_update_status( $file, 'update_themes' ) ) { + $themes_to_update[] = $file; + + if ( empty( $assoc_args ) ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace('.php', '', basename($file)); + else + $name = dirname($file); + + $theme_list .= "\n\t%y$name%n"; + } + } + } + + if ( empty( $themes_to_update ) ) { + WP_CLI::line( 'No theme updates available.' ); + return; + } + + // If --all, UPDATE ALL THE THINGS + if ( isset( $assoc_args['all'] ) ) { + $upgrader = WP_CLI::get_upgrader( 'Theme_Upgrader' ); + $result = $upgrader->bulk_upgrade( $themes_to_update ); + + // Let the user know the results. + $num_to_update = count( $themes_to_update ); + $num_updated = count( array_filter( $result ) ); + + $line = "Updated $num_updated/$num_to_update Themes."; + if ( $num_to_update == $num_updated ) { + WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + WP_CLI::warning( $line ); + } else { + WP_CLI::error( $line ); + } + + // Else list themes that require updates + } else { + WP_CLI::line( $theme_list ); + } + } + /** * Delete a theme * @@ -174,6 +245,9 @@ public static function help() { path print path to the theme's stylesheet --directory get the path to the closest parent directory + update update a theme from wordpress.org + --all update all themes from wordpress.org + delete delete a theme EOB ); From 7cf4678b27f26d080d134b56cfab003c966c0c72 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Thu, 15 Mar 2012 16:34:04 -0700 Subject: [PATCH 0279/5359] Split theme update into update_single() and update_multiple() to match plugin update. --- src/php/wp-cli/commands/internals/theme.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 35263029f..677c75f31 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -131,16 +131,20 @@ function update( $args, $assoc_args ) { // Force WordPress to update the theme list wp_update_themes(); - // If we have arguments and not updating all, update named theme - if ( ! empty( $args ) && ! isset( $assoc_args['all'] ) ) { - list( $theme, $name ) = $this->parse_name( $args, __FUNCTION__ ); - - $upgrader = WP_CLI::get_upgrader( 'Theme_Upgrader' ); - $result = $upgrader->upgrade( $name ); - return; + if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { + $this->update_single( $args, $assoc_args ); + } else { + $this->update_multiple( $args, $assoc_args ); } + } + + private function update_single( $args, $assoc_args ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + WP_CLI::get_upgrader( 'Theme_Upgrader' )->upgrade( $name ); + } - // If not, fall through and load theme info. + private function update_multiple( $args, $assoc_args ) { $themes = get_themes(); // Grab all Themes that need Updates From 127d288020129ae7e1c8c81b91a257c6b8a206d7 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 16 Mar 2012 02:18:03 +0200 Subject: [PATCH 0280/5359] s/--directory/--dir/g --- src/php/wp-cli/commands/internals/plugin.php | 6 +++--- src/php/wp-cli/commands/internals/theme.php | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index a5b4d05a9..d894c734b 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -175,7 +175,7 @@ function path( $args, $assoc_args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $path .= '/' . $file; - if ( isset( $assoc_args['directory'] ) ) + if ( isset( $assoc_args['dir'] ) ) $path = dirname( $path ); } @@ -400,7 +400,7 @@ private function parse_name( $args, $subcommand ) { public static function help() { WP_CLI::line( << [] - or: wp plugin path [] [--directory] + or: wp plugin path [] [--dir] or: wp plugin install [--activate] [--dev] Available sub-commands: @@ -413,7 +413,7 @@ public static function help() { toggle toggle activation state of a particular plugin path print path to the plugin's file - --directory get the path to the closest parent directory + --dir get the path to the closest parent directory install install a plugin from wordpress.org --activate activate the plugin after installing it diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 677c75f31..7017eb597 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -114,7 +114,7 @@ function path( $args, $assoc_args ) { list( $stylesheet, $name ) = $this->parse_name( $args, __FUNCTION__ ); $path = $stylesheet; - if ( isset( $assoc_args['directory'] ) ) + if ( isset( $assoc_args['dir'] ) ) $path = dirname( $path ); } @@ -239,7 +239,7 @@ protected function get_stylesheet_path( $theme ) { public static function help() { WP_CLI::line( << [] - or: wp theme path [] [--directory] + or: wp theme path [] [--dir] Available sub-commands: status display status of all installed themes or of a particular theme @@ -247,10 +247,10 @@ public static function help() { activate activate a particular theme path print path to the theme's stylesheet - --directory get the path to the closest parent directory + --dir get the path to the closest parent directory - update update a theme from wordpress.org - --all update all themes from wordpress.org + update update a theme from wordpress.org + --all update all themes from wordpress.org delete delete a theme EOB From 9cf1c8af7964d0df5a8f0810ffe98a756ff42666 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 16 Mar 2012 03:03:43 +0200 Subject: [PATCH 0281/5359] add unfortunately named WP_CLI_Command_With_Upgrade class and make plugin and theme commands inherit from it --- .../class-wp-cli-command-with-upgrade.php | 87 ++++++++++++++++++ src/php/wp-cli/class-wp-cli.php | 17 ---- src/php/wp-cli/commands/internals/core.php | 3 +- src/php/wp-cli/commands/internals/plugin.php | 87 +++--------------- src/php/wp-cli/commands/internals/theme.php | 88 +++---------------- src/php/wp-cli/wp-cli.php | 1 + 6 files changed, 109 insertions(+), 174 deletions(-) create mode 100644 src/php/wp-cli/class-wp-cli-command-with-upgrade.php diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php new file mode 100644 index 000000000..03c1aef42 --- /dev/null +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -0,0 +1,87 @@ +upgrade_refresh ); + + if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + WP_CLI::get_upgrader( $this->upgrader )->upgrade( $name ); + } else { + $this->update_multiple( $args, $assoc_args ); + } + } + + private function update_multiple( $args, $assoc_args ) { + // Grab all items that need updates + // If we have no sub-arguments, add them to the output list. + $item_list = "Available {$this->item_type} updates:"; + $items_to_update = array(); + foreach ( $this->get_item_list() as $file ) { + if ( $this->get_update_status( $file ) ) { + $items_to_update[] = $file; + + if ( empty( $assoc_args ) ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace('.php', '', basename($file)); + else + $name = dirname($file); + + $item_list .= "\n\t%y$name%n"; + } + } + } + + if ( empty( $items_to_update ) ) { + WP_CLI::line( "No {$this->item_type} updates available." ); + return; + } + + // If --all, UPDATE ALL THE THINGS + if ( isset( $assoc_args['all'] ) ) { + $upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $result = $upgrader->bulk_upgrade( $items_to_update ); + + // Let the user know the results. + $num_to_update = count( $items_to_update ); + $num_updated = count( array_filter( $result ) ); + + $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; + if ( $num_to_update == $num_updated ) { + WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + WP_CLI::warning( $line ); + } else { + WP_CLI::error( $line ); + } + + // Else list items that require updates + } else { + WP_CLI::line( $item_list ); + } + } + + /** + * Check wether an item has an update available or not. + * + * @param string $item The plugin/theme theme path + * + * @return bool + */ + protected function get_update_status( $file ) { + $update_list = get_site_transient( $this->upgrade_transient ); + + return isset( $update_list->response[ $file ] ); + } +} + diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index a4d447ace..4613ae3b8 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -166,23 +166,6 @@ static function set_url_params( $url ) { $_SERVER['QUERY_STRING'] = isset($url_parts['query']) ? $url_parts['query'] : ''; } - /** - * Return the beginning of the status line for a certain plugin or theme - * - * @param string $item The plugin or theme name - * @param string $key The transient key - * - * @return string - */ - static function get_update_status( $item, $key ) { - $update_list = get_site_transient( $key ); - - if ( isset( $update_list->response[ $item ] ) ) - return true; - - return false; - } - static function get_upgrader( $class ) { if ( !class_exists( 'WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 508473877..680d8d427 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -139,8 +139,7 @@ function update( $args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $upgrader = WP_CLI::get_upgrader( 'Core_Upgrader' ); - $result = $upgrader->upgrade( $update ); + $result = WP_CLI::get_upgrader( 'Core_Upgrader' )->upgrade( $update ); if ( is_wp_error($result) ) { $msg = WP_CLI::errorToString( $result ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d894c734b..115549870 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -8,9 +8,12 @@ * @package wp-cli * @subpackage commands/internals */ -class PluginCommand extends WP_CLI_Command { +class PluginCommand extends WP_CLI_Command_With_Upgrade { - protected $default_subcommand = 'status'; + protected $item_type = 'plugin'; + protected $upgrader = 'Plugin_Upgrader'; + protected $upgrade_refresh = 'wp_update_plugins'; + protected $upgrade_transient = 'update_plugins'; private $mu_plugins; @@ -42,7 +45,7 @@ function status( $args = array(), $vars = array() ) { $version = $details[ 'Version' ]; - if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) + if ( $this->get_update_status( $file ) ) $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); @@ -70,7 +73,7 @@ private function list_plugins() { else $name = dirname($file); - if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { + if ( $this->get_update_status( $file ) ) { $line = ' %yU%n'; } else { $line = ' '; @@ -238,78 +241,8 @@ function install( $args, $assoc_args ) { } } - /** - * Update a plugin - * - * @param array $args - * @param array $assoc_args - */ - function update( $args, $assoc_args ) { - // Force WordPress to update the plugin list - wp_update_plugins(); - - if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { - $this->update_single( $args, $assoc_args ); - } else { - $this->update_multiple( $args, $assoc_args ); - } - } - - private function update_single( $args, $assoc_args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - - WP_CLI::get_upgrader( 'Plugin_Upgrader' )->upgrade( $file ); - } - - private function update_multiple( $args, $assoc_args ) { - $plugins = get_plugins(); - - // Grab all Plugins that need Updates - // If we have no sub-arguments, add them to the output list. - $plugin_list = "Available plugin updates:"; - $plugins_to_update = array(); - foreach ( $plugins as $file => $plugin ) { - if ( WP_CLI::get_update_status( $file, 'update_plugins' ) ) { - $plugins_to_update[] = $file; - - if ( empty( $assoc_args ) ) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace('.php', '', basename($file)); - else - $name = dirname($file); - - $plugin_list .= "\n\t%y$name%n"; - } - } - } - - if ( empty( $plugins_to_update ) ) { - WP_CLI::line( 'No plugin updates available.' ); - return; - } - - // If --all, UPDATE ALL THE THINGS - if ( isset( $assoc_args['all'] ) ) { - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); - $result = $upgrader->bulk_upgrade( $plugins_to_update ); - - // Let the user know the results. - $num_to_update = count( $plugins_to_update ); - $num_updated = count( array_filter( $result ) ); - - $line = "Updated $num_updated/$num_to_update Plugins."; - if ( $num_to_update == $num_updated ) { - WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - WP_CLI::warning( $line ); - } else { - WP_CLI::error( $line ); - } - - // Else list plugins that require updates - } else { - WP_CLI::line( $plugin_list ); - } + protected function get_item_list() { + return array_keys( get_plugins() ); } /** @@ -367,7 +300,7 @@ private function get_details( $file ) { * @param bool $exit * @return array */ - private function parse_name( $args, $subcommand ) { + protected function parse_name( $args, $subcommand ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp plugin $subcommand " ); exit; diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 7017eb597..e8856ada3 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -8,9 +8,12 @@ * @package wp-cli * @subpackage commands/internals */ -class ThemeCommand extends WP_CLI_Command { +class ThemeCommand extends WP_CLI_Command_With_Upgrade { - protected $default_subcommand = 'status'; + protected $item_type = 'theme'; + protected $upgrader = 'Theme_Upgrader'; + protected $upgrade_refresh = 'wp_update_themes'; + protected $upgrade_transient = 'update_themes'; /** * Get the status of one or all themes @@ -29,9 +32,9 @@ public function status( $args = array() ) { $status = $this->get_status( $details['Name'], true ); - $version = $details[ 'Version' ]; + $version = $details['Version']; - if ( WP_CLI::get_update_status( $name, 'update_themes' ) ) + if ( $this->get_update_status( $details['Stylesheet'] ) ) $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Theme %9' . $name . '%n details:' ); @@ -46,7 +49,7 @@ private function list_themes() { WP_CLI::line( 'Installed themes:' ); foreach ( get_themes() as $theme ) { - if ( WP_CLI::get_update_status( $theme['Stylesheet'], 'update_themes' ) ) { + if ( $this->get_update_status( $theme['Stylesheet'] ) ) { $line = ' %yU%n'; } else { $line = ' '; @@ -121,79 +124,8 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } - /** - * Update a theme - * - * @param array $args - * @param array $assoc_args - */ - function update( $args, $assoc_args ) { - // Force WordPress to update the theme list - wp_update_themes(); - - if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { - $this->update_single( $args, $assoc_args ); - } else { - $this->update_multiple( $args, $assoc_args ); - } - } - - private function update_single( $args, $assoc_args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - - WP_CLI::get_upgrader( 'Theme_Upgrader' )->upgrade( $name ); - } - - private function update_multiple( $args, $assoc_args ) { - $themes = get_themes(); - - // Grab all Themes that need Updates - // If we have no sub-arguments, add them to the output list. - $theme_list = "Available theme updates:"; - $themes_to_update = array(); - foreach ( $themes as $theme ) { - $file = $theme['Stylesheet']; - if ( WP_CLI::get_update_status( $file, 'update_themes' ) ) { - $themes_to_update[] = $file; - - if ( empty( $assoc_args ) ) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace('.php', '', basename($file)); - else - $name = dirname($file); - - $theme_list .= "\n\t%y$name%n"; - } - } - } - - if ( empty( $themes_to_update ) ) { - WP_CLI::line( 'No theme updates available.' ); - return; - } - - // If --all, UPDATE ALL THE THINGS - if ( isset( $assoc_args['all'] ) ) { - $upgrader = WP_CLI::get_upgrader( 'Theme_Upgrader' ); - $result = $upgrader->bulk_upgrade( $themes_to_update ); - - // Let the user know the results. - $num_to_update = count( $themes_to_update ); - $num_updated = count( array_filter( $result ) ); - - $line = "Updated $num_updated/$num_to_update Themes."; - if ( $num_to_update == $num_updated ) { - WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - WP_CLI::warning( $line ); - } else { - WP_CLI::error( $line ); - } - - // Else list themes that require updates - } else { - WP_CLI::line( $theme_list ); - } + protected function get_item_list() { + return wp_list_pluck( get_themes(), 'Stylesheet' ); } /** diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 61bc0bc79..7e08f72d4 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -15,6 +15,7 @@ // Include the wp-cli classes include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; +include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; // Include the command line tools include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; From 455f55ddb0c9dccd59553a6a9162c0bf7bdcb617 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 16 Mar 2012 17:34:28 +0200 Subject: [PATCH 0282/5359] attempt to use /usr/local/bin in build-dev. fixes #87 --- utils/build-dev | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/utils/build-dev b/utils/build-dev index 6b5d96744..ea70e6be6 100755 --- a/utils/build-dev +++ b/utils/build-dev @@ -1,6 +1,11 @@ #!/usr/bin/env bash -ln -sf $(pwd)/src/bin/wp /usr/bin/wp +for dir in /usr/bin /usr/local/bin; do + if [ -d $dir ]; then + ln -sf $(pwd)/src/bin/wp $dir/wp + break + fi +done for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do if [ -d $dir ]; then From b4c5b3381f814385e9d2eb5d5f9120d6a1db1937 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 18 Mar 2012 21:31:36 +0200 Subject: [PATCH 0283/5359] make --user a global parameter. fixes #81 --- src/php/wp-cli/commands/internals/export.php | 24 -------------------- src/php/wp-cli/wp-cli.php | 14 ++++++++++++ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 62967b586..d74ab2077 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -20,7 +20,6 @@ public static function help() { Required parameters: --path Full Path to directory where WXR export files should be stored - --user Username/ID the import should run as Optional filters: --start_date Export only posts new than this date in format YYYY-MM-DD @@ -40,7 +39,6 @@ public static function help() { public function validate_arguments( $args, $assoc_args ) { $defaults = array( 'path' => NULL, - 'user' => NULL, 'start_date' => NULL, 'end_date' => NULL, 'post_type' => NULL, @@ -87,28 +85,6 @@ private function check_path( $path ) { return true; } - private function check_user( $user ) { - if ( empty( $user ) ) { - WP_CLI::warning( 'missing --user parameter' ); - return false; - } - - if ( is_numeric( $user ) ) { - $user_id = (int) $user; - } else { - $user_id = (int) username_exists( $user ); - } - if ( !$user_id || !wp_set_current_user( $user_id ) ) { - WP_CLI::error( sprintf( "Could not get a user_id for this user: %s", var_export( $user_id, true ) ) ); - exit; - } - - $current_user = wp_get_current_user(); - $this->user_id = (int) $user_id; - - return true; - } - private function check_start_date( $date ) { if ( is_null( $date ) ) return true; diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 7e08f72d4..adb97c0be 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -78,6 +78,20 @@ } } +// Set the user +if ( isset( $assoc_args['user'] ) ) { + $user = $assoc_args['user']; + if ( is_numeric( $user ) ) { + $user_id = (int) $user; + } else { + $user_id = (int) username_exists( $user ); + } + if ( !$user_id || !wp_set_current_user( $user_id ) ) { + WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); + } + unset( $user); +} + // Set filesystem method add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); From 1f88e39224dacb9dbc978a6714870c0e08b2aec2 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 18 Mar 2012 21:36:41 +0200 Subject: [PATCH 0284/5359] document global parameters --- src/php/wp-cli/commands/internals/help.php | 8 ++++++-- src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 64f67f2bf..0028f3cba 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -40,16 +40,20 @@ public function __construct( $args ) { } private function general_help() { - WP_CLI::line('Example usage:'); + WP_CLI::line( 'Available commands:' ); foreach ( WP_CLI::$commands as $name => $command ) { if ( 'help' == $name ) continue; $this->single_command_help( $name, $command ); } - WP_CLI::line(' wp --version'); WP_CLI::line(); WP_CLI::line( "See 'wp help ' for more information on a specific command." ); + WP_CLI::line(); + WP_CLI::line( 'Global parameters:' ); + WP_CLI::line( ' --user= set the current user' ); + WP_CLI::line( ' --url= set the current URL' ); + WP_CLI::line( ' --version print wp-cli version' ); } private function single_command_help( $name, $command ) { diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index adb97c0be..51a5b8f5a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -89,7 +89,7 @@ if ( !$user_id || !wp_set_current_user( $user_id ) ) { WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); } - unset( $user); + unset( $user ); } // Set filesystem method From 826b2a957bd01e4c87f8db9f75eee3502608ddaa Mon Sep 17 00:00:00 2001 From: Andreas Creten Date: Sat, 24 Mar 2012 11:56:42 +0100 Subject: [PATCH 0285/5359] Updated reference to the repo to link to the newly created organisation --- README.md | 10 +++++----- build.properties | 2 +- src/php/wp-cli/commands/internals/home.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d9fa906e5..b3aae8f4b 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ Installing ```sh pear config-set auto_discover 1 -sudo pear install andreascreten.github.com/wp-cli/wpcli +sudo pear install wp-cli.github.com/wp-cli/wpcli ``` **Via GIT:** ```sh -git clone --recurse-submodules git://github.com/andreascreten/wp-cli.git ~/git/wp-cli +git clone --recurse-submodules git://github.com/wp-cli/wp-cli.git ~/git/wp-cli cd ~/git/wp-cli sudo utils/build-dev ``` @@ -102,7 +102,7 @@ Adding commands --------------- Adding commands to wp-cli is very easy. You can even add them from within your own plugin. -You can find more information about adding commands in the [Commands Cookbook](https://github.com/andreascreten/wp-cli/wiki/Commands-Cookbook) on our Wiki. +You can find more information about adding commands in the [Commands Cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook) on our Wiki. **Please share the commands you make, issue a pull request to get them included in wp-cli by default.** @@ -141,5 +141,5 @@ Changelog Contributors ------------ -- [Contributor list](https://github.com/andreascreten/wp-cli/contributors) -- [Contributor impact](https://github.com/andreascreten/wp-cli/graphs/impact) +- [Contributor list](https://github.com/wp-cli/wp-cli/contributors) +- [Contributor impact](https://github.com/wp-cli/wp-cli/graphs/impact) diff --git a/build.properties b/build.properties index 27cb6bd81..8ad6b5930 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ project.name=wpcli -project.channel=andreascreten.github.com/wp-cli +project.channel=wp-cli.github.com/wp-cli project.majorVersion=0 project.minorVersion=4 project.patchLevel=0 diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index 4f3304fc5..a8fd6d631 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -18,7 +18,7 @@ class HomeCommand extends WP_CLI_Command { */ public function __construct( $args, $assoc_args ) { // The url for the wp-cli repository - $repository_url = 'http://github.com/andreascreten/wp-cli'; + $repository_url = 'http://github.com/wp-cli/wp-cli'; // Open the wp-cli page in the browser if(exec('which x-www-browser')) { From ebf89e659c5d66f00536acbac0e70d80e919ea7c Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:00:28 +0300 Subject: [PATCH 0286/5359] update PEAR channel URL --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 8ad6b5930..431558f75 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ project.name=wpcli -project.channel=wp-cli.github.com/wp-cli +project.channel=wp-cli.github.com/pear project.majorVersion=0 project.minorVersion=4 project.patchLevel=0 From 844ee1320b537de6bb5d062f98adbacd5a7de041 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:14:35 +0300 Subject: [PATCH 0287/5359] update channel URL in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3aae8f4b..199a9d87f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Installing ```sh pear config-set auto_discover 1 -sudo pear install wp-cli.github.com/wp-cli/wpcli +sudo pear install wp-cli.github.com/pear/wpcli ``` **Via GIT:** From 40ef80762266a36ec0b983908696eb09d5fc224e Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:20:58 +0300 Subject: [PATCH 0288/5359] document --path global param --- src/php/wp-cli/commands/internals/help.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 0028f3cba..4d6e28f13 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -53,6 +53,7 @@ private function general_help() { WP_CLI::line( 'Global parameters:' ); WP_CLI::line( ' --user= set the current user' ); WP_CLI::line( ' --url= set the current URL' ); + WP_CLI::line( ' --path= set the current path to the WP install' ); WP_CLI::line( ' --version print wp-cli version' ); } From 202c1506d68067bb1ef12ca3c513598b51430037 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:25:40 +0300 Subject: [PATCH 0289/5359] 0.5.0 changelog --- README.md | 11 +++++++++++ src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 199a9d87f..3e6a32ad3 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,17 @@ You can find more information about adding commands in the [Commands Cookbook](h Changelog --------------- +**0.5** + +- added `wp user` +- added `wp core download` +- added `wp core config` +- added `wp plugin update --all` +- added `wp theme update` +- added `wp db import` +- added `--url` `--path` and `--user` global parameters +- various bugfixes + **0.4** - added `wp eval` and `wp eval-file` diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 51a5b8f5a..60400ab3d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die( 'Only cli access' ); } -define( 'WP_CLI_VERSION', '0.5.0-dev' ); +define( 'WP_CLI_VERSION', '0.5.0' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 95e4276050e414d788b37ef0fe6dbffc71b37640 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:37:18 +0300 Subject: [PATCH 0290/5359] fix build-pear --- utils/build-pear | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/utils/build-pear b/utils/build-pear index 0d8e51c7d..2172050ec 100755 --- a/utils/build-pear +++ b/utils/build-pear @@ -11,12 +11,10 @@ version="${version/.tgz/}" #sudo phing install-system # update channel files -cd ../wp-cli-pages +cd ../wp-cli-pear pirum add . ../wp-cli/dist/wpcli-$version.tgz pirum build . -exit - # push changes git add -A git ci -m "release $version" From 532b35d3393a0c830a8ea301649d6cc43a0e46eb Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 27 Mar 2012 13:37:36 +0300 Subject: [PATCH 0291/5359] update pear package to 0.5.0 --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 431558f75..2a40f3cd4 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=wp-cli.github.com/pear project.majorVersion=0 -project.minorVersion=4 +project.minorVersion=5 project.patchLevel=0 project.snapshot=false From 0e6302c3a67645296449814714c7cf20034ef73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20Burc=C4=83?= Date: Wed, 28 Mar 2012 16:32:04 +0300 Subject: [PATCH 0292/5359] remove redundant quotes --- utils/build-local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build-local b/utils/build-local index 1adabb76f..edf89736e 100755 --- a/utils/build-local +++ b/utils/build-local @@ -10,7 +10,7 @@ if [ "$BASH_SOURCE" = "$0" ]; then exit 1 fi -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd) alias wp='$DIR/../src/bin/wp' From 72b13453b1f77cfe1f24c32a113e9d47ccd5f4c2 Mon Sep 17 00:00:00 2001 From: Soulou Date: Tue, 10 Apr 2012 00:34:08 +0200 Subject: [PATCH 0293/5359] Quote the arguments when executing 'wp db cli|export|import' --- src/php/wp-cli/commands/internals/db.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index de88a992a..6137de9b6 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -18,7 +18,7 @@ class DBCommand extends WP_CLI_Command { * Return a string for connecting to the DB. */ protected function connect_string() { - return sprintf( 'mysql --host=%s --database=%s --user=%s --password=%s', + return sprintf( 'mysql --host="%s" --database="%s" --user="%s" --password="%s"', DB_HOST, DB_NAME, DB_USER, DB_PASSWORD ); } @@ -46,7 +46,7 @@ function export( $args, $assoc_args ) { $result_file = $assoc_args['file']; } - $exec = sprintf( 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', + $exec = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); @@ -79,7 +79,7 @@ function import( $args, $assoc_args ) { $result_file = $assoc_args['file']; } - $exec = sprintf( 'mysql %s --user=%s --password=%s --host=%s < %s', + $exec = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); From d3d314f2c4300080874b33638507d1e7af91468b Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 04:32:08 +0300 Subject: [PATCH 0294/5359] update wp db help text --- src/php/wp-cli/commands/internals/db.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 6137de9b6..187b5d929 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -92,11 +92,18 @@ function import( $args, $assoc_args ) { */ public static function help() { WP_CLI::line( << [] + +Available sub-commands: + cli Open a SQL command-line interface using the WordPress credentials. + + connect Print a string for connecting to the database. + + export Export the WordPress database using mysqldump. + + import Import a database exported via mysqldump. + + query Execute a query against the WordPress database. EOB ); } From feaa9a69d9338a9be0af57883c85b19311832ce1 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 04:40:53 +0300 Subject: [PATCH 0295/5359] make --file parameter positional. fixes #91 --- src/php/wp-cli/commands/internals/db.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 187b5d929..21857e548 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -40,18 +40,14 @@ function cli() { * Exports the WordPress DB as SQL using mysqldump. */ function export( $args, $assoc_args ) { - if ( !isset( $assoc_args['file'] ) ) { - $result_file = sprintf( '%s.sql', DB_NAME ); - } else { - $result_file = $assoc_args['file']; - } + $result_file = $this->get_file_name( $args ); $exec = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); - WP_CLI::success( sprintf( 'Dumped to %s', $result_file ) ); + WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } /** @@ -73,18 +69,21 @@ function query( $args, $assoc_args ) { } function import( $args, $assoc_args ) { - if ( !isset( $assoc_args['file'] ) ) { - $result_file = sprintf( '%s.sql', DB_NAME ); - } else { - $result_file = $assoc_args['file']; - } + $result_file = $this->get_file_name( $args ); $exec = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); exec( $exec ); - WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); + WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); + } + + private function get_file_name( $args ) { + if ( empty( $args ) ) + return sprintf( '%s.sql', DB_NAME ); + + return $args[0]; } /** From 48b34f16a9ba60fa68c53172a254bec26b254b66 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 04:43:05 +0300 Subject: [PATCH 0296/5359] move the export() method above the import() method --- src/php/wp-cli/commands/internals/db.php | 31 +++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 21857e548..034b72c57 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -36,20 +36,6 @@ function cli() { proc_close( proc_open( $this->connect_string() , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); } - /** - * Exports the WordPress DB as SQL using mysqldump. - */ - function export( $args, $assoc_args ) { - $result_file = $this->get_file_name( $args ); - - $exec = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', - DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - - exec( $exec ); - - WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); - } - /** * Execute a query against the site database. */ @@ -68,6 +54,23 @@ function query( $args, $assoc_args ) { WP_CLI::line( $result ); } + /** + * Exports the WordPress DB as SQL using mysqldump. + */ + function export( $args, $assoc_args ) { + $result_file = $this->get_file_name( $args ); + + $exec = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', + DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); + + exec( $exec ); + + WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); + } + + /** + * Imports a database from a file. + */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); From 06af4f573d9ba3c5da5a85fb75c07dbf86ed9ca9 Mon Sep 17 00:00:00 2001 From: "John P. Bloch" Date: Tue, 10 Apr 2012 13:52:58 -0300 Subject: [PATCH 0297/5359] Allow silent downloads with curl. --- src/php/wp-cli/commands/internals/core.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 680d8d427..cc132d6ea 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -22,8 +22,12 @@ public function download( $args, $assoc_args ) { else $docroot = './'; + $silent = ''; + if( !empty( $assoc_args['silent'] ) ) + $silent = '--silent '; + WP_CLI::line('Downloading WordPress...'); - exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); + exec("curl {$silent}http://wordpress.org/latest.zip > /tmp/wordpress.zip"); exec("unzip /tmp/wordpress.zip"); exec("mv wordpress/* $docroot"); exec("rm -r wordpress"); From 4ebf481ff0987db0cd6041e04232d9fc40c4c90c Mon Sep 17 00:00:00 2001 From: Marco Solazzi Date: Tue, 10 Apr 2012 12:49:22 +0200 Subject: [PATCH 0298/5359] added --version parameter to install specific versions of core and plugins --- src/php/wp-cli/commands/internals/core.php | 13 ++++++++++++- src/php/wp-cli/commands/internals/plugin.php | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 680d8d427..d1aa583cd 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -21,9 +21,20 @@ public function download( $args, $assoc_args ) { $docroot = $assoc_args['path']; else $docroot = './'; + + if (isset($assoc_args['version'])) { + $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + } else { + $download_url = 'http://wordpress.org/latest.zip'; + } + $version_check_response = wp_remote_head($download_url); + if (!$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream') { + WP_CLI::error( 'Unable to download remote file ' . $download_url); + exit(); + } WP_CLI::line('Downloading WordPress...'); - exec("curl http://wordpress.org/latest.zip > /tmp/wordpress.zip"); + exec("curl {$download_url} > /tmp/wordpress.zip"); exec("unzip /tmp/wordpress.zip"); exec("mv wordpress/* $docroot"); exec("rm -r wordpress"); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 115549870..d409c56a9 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -213,6 +213,18 @@ function install( $args, $assoc_args ) { $api->download_link = $link . $slug . '.zip'; $api->version = 'Development Version'; + } else if ( isset( $assoc_args['version'] ) ) { + list( $link ) = explode( $slug, $api->download_link ); + + $api->download_link = $link . $slug . '.' . $assoc_args['version'] .'.zip'; + $api->version = $assoc_args['version']; + + //check if the requested version exists + $version_check_response = wp_remote_head($api->download_link); + if (!$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream') { + WP_CLI::error( 'Can\'t find the requested plugin\'s version ' . $assoc_args['version'] . ' in the WordPress.org plugins repository.'); + exit(); + } } $status = install_plugin_install_status( $api ); From 8ea157269b0496dd55304f0a3dd6e7ff25e7b0f7 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 20:16:21 +0300 Subject: [PATCH 0299/5359] minor cleanup. see #92 --- src/php/wp-cli/commands/internals/core.php | 12 +++++++----- src/php/wp-cli/commands/internals/plugin.php | 14 +++++++------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index d1aa583cd..f4ca44f07 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -21,15 +21,16 @@ public function download( $args, $assoc_args ) { $docroot = $assoc_args['path']; else $docroot = './'; - - if (isset($assoc_args['version'])) { + + if ( isset( $assoc_args['version'] ) ) { $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; } else { $download_url = 'http://wordpress.org/latest.zip'; } - $version_check_response = wp_remote_head($download_url); - if (!$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream') { - WP_CLI::error( 'Unable to download remote file ' . $download_url); + + $version_check_response = wp_remote_head( $download_url ); + if ( !$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream' ) { + WP_CLI::error( 'Unable to download remote file ' . $download_url ); exit(); } @@ -171,6 +172,7 @@ public static function help() { WP_CLI::line( << [--admin_name=] --admin_password= --admin_email= EOB ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d409c56a9..aa616164a 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -218,12 +218,11 @@ function install( $args, $assoc_args ) { $api->download_link = $link . $slug . '.' . $assoc_args['version'] .'.zip'; $api->version = $assoc_args['version']; - - //check if the requested version exists - $version_check_response = wp_remote_head($api->download_link); - if (!$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream') { - WP_CLI::error( 'Can\'t find the requested plugin\'s version ' . $assoc_args['version'] . ' in the WordPress.org plugins repository.'); - exit(); + + // check if the requested version exists + $version_check_response = wp_remote_head( $api->download_link ); + if ( !$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream' ) { + WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . "in the WordPress.org plugins repository." ); } } @@ -346,7 +345,7 @@ public static function help() { WP_CLI::line( << [] or: wp plugin path [] [--dir] - or: wp plugin install [--activate] [--dev] + or: wp plugin install [--activate] [--dev] [--version=1.2.3] Available sub-commands: status display status of all installed plugins or of a particular plugin @@ -363,6 +362,7 @@ public static function help() { install install a plugin from wordpress.org --activate activate the plugin after installing it --dev install the development version + --version install a specific version update update a plugin from wordpress.org --all update all plugins from wordpress.org From 5a5c8baeb2d15f9f55b1bf382bc731d45808b3f2 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 20:26:03 +0300 Subject: [PATCH 0300/5359] Show wp-cli version only if there's no command passed. see #92 --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 60400ab3d..69e22d041 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -30,7 +30,7 @@ define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); // Handle --version parameter -if ( isset( $assoc_args['version'] ) ) { +if ( isset( $assoc_args['version'] ) && empty( $arguments ) ) { WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); exit; } From 5dc3069a75c791e6fc18ce5438bf129e39e5a511 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 20:26:49 +0300 Subject: [PATCH 0301/5359] don't validate WP core version. Just let curl handle it. closes #92 --- src/php/wp-cli/commands/internals/core.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 39e8d829c..38bdff797 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -28,12 +28,6 @@ public function download( $args, $assoc_args ) { $download_url = 'http://wordpress.org/latest.zip'; } - $version_check_response = wp_remote_head( $download_url ); - if ( !$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream' ) { - WP_CLI::error( 'Unable to download remote file ' . $download_url ); - exit(); - } - $silent = ''; if( !empty( $assoc_args['silent'] ) ) $silent = '--silent '; From 0cf4117771ea9d91ba2f1dd604004d18b879283b Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 10 Apr 2012 20:28:37 +0300 Subject: [PATCH 0302/5359] fix some plugin command messages --- src/php/wp-cli/commands/internals/plugin.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index aa616164a..e8f3a0e69 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -204,7 +204,7 @@ function install( $args, $assoc_args ) { $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( !$api ) { - WP_CLI::error( 'Can\'t find the plugin in the WordPress.org plugins repository.' ); + WP_CLI::error( "Can't find the plugin in the WordPress.org plugins repository." ); exit(); } @@ -222,7 +222,7 @@ function install( $args, $assoc_args ) { // check if the requested version exists $version_check_response = wp_remote_head( $api->download_link ); if ( !$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream' ) { - WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . "in the WordPress.org plugins repository." ); + WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . " in the WordPress.org plugins repository." ); } } @@ -244,10 +244,10 @@ function install( $args, $assoc_args ) { break; case 'newer_installed': - WP_CLI::error( sprintf( 'Newer version (%s) installed', $status['version'] ) ); + WP_CLI::error( sprintf( 'Newer version (%s) installed.', $status['version'] ) ); break; case 'latest_installed': - WP_CLI::error( 'Latest version already installed' ); + WP_CLI::error( 'Latest version already installed.' ); break; } } From 50beb9387e02342b2785d821c08cb3635f8f48df Mon Sep 17 00:00:00 2001 From: Zack Tollman Date: Fri, 13 Apr 2012 01:43:22 -0700 Subject: [PATCH 0303/5359] Added transient commands Added a new class that adds a wp transient command. The command takes "get", "set" and "delete", which correspond with "get_transient", "set_transient" and "delete_transient", respectively. Additionally, a fourth command, "type", indicates whether the transients API is using the database or object cache for storage. --- .../wp-cli/commands/internals/transient.php | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/transient.php diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php new file mode 100644 index 000000000..5bbe6e2e8 --- /dev/null +++ b/src/php/wp-cli/commands/internals/transient.php @@ -0,0 +1,109 @@ +' ); + exit; + } + + list( $key ) = $args; + + $value = get_transient( $key ); + + if ( false === $value ) { + WP_CLI::warning( 'Transient with key "' . $key . '" is not set.' ); + exit; + } + + if ( is_array( $value ) || is_object( $value ) ) + WP_CLI::line( var_export( $value ) ); + else + WP_CLI::success( $value ); + } + + /** + * Sets a value using the "set_transient" function. + * + * @param array $args + */ + public function set( $args ) { + if ( count( $args ) < 2 ) { + WP_CLI::error( 'usage: wp transient set [expiration]' ); + exit; + } + + list( $key, $value, $expiration ) = $args; + + $expiration = isset( $expiration ) ? $expiration : 0; + + if ( set_transient( $key, $value, $expiration ) ) + WP_CLI::success( 'Transient added.' ); + else + WP_CLI::error( 'Transient could not be set.' ); + } + + /** + * Deletes a value using the "delete_transient" function. + * + * @param array $args + */ + public function delete( $args ) { + if ( empty( $args ) ) { + WP_CLI::warning( 'Usage: wp transient delete ' ); + exit; + } + + list( $key ) = $args; + + if ( delete_transient( $key ) ) { + WP_CLI::success( 'Transient deleted.' ); + } else { + if ( get_transient( $key ) ) + WP_CLI::error( 'Transient was not deleted even though the transient appears to exist.' ); + else + WP_CLI::warning( 'Transient was not deleted; however, the transient does not appear to exist.' ); + } + } + + /** + * Indicates whether the transients API is using the object cache or options table in the current environment. + */ + public function type() { + global $_wp_using_ext_object_cache, $wpdb; + + if ( $_wp_using_ext_object_cache ) + $message = 'Transients are saved to the object cache.'; + else + $message = 'Transients are saved to the ' . $wpdb->prefix . 'options table.'; + + WP_CLI::line( $message ); + } + + /** + * Displays the help message. + */ + static function help() { + WP_CLI::line( << + or: wp transient set [expiration] + or: wp transient delete + or: wp transient type +EOB + ); + } +} \ No newline at end of file From c026106fb619abcab4e9d1d454c36074bcebc167 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 13 Apr 2012 19:00:59 +0300 Subject: [PATCH 0304/5359] remove --user param after handling it --- src/php/wp-cli/wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 69e22d041..42d217d6e 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -78,7 +78,10 @@ } } -// Set the user +// Set filesystem method +add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); + +// Handle --user parameter if ( isset( $assoc_args['user'] ) ) { $user = $assoc_args['user']; if ( is_numeric( $user ) ) { @@ -89,12 +92,9 @@ if ( !$user_id || !wp_set_current_user( $user_id ) ) { WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); } - unset( $user ); + unset( $assoc_args['user'], $user ); } -// Set filesystem method -add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { WP_CLI::load_all_commands(); From db00e40d4911b0dd36762787ac81429204a731a1 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 13 Apr 2012 19:01:32 +0300 Subject: [PATCH 0305/5359] implement --require global parameter. fixes #94 --- src/php/wp-cli/commands/internals/help.php | 1 + src/php/wp-cli/wp-cli.php | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 4d6e28f13..21d4388df 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -54,6 +54,7 @@ private function general_help() { WP_CLI::line( ' --user= set the current user' ); WP_CLI::line( ' --url= set the current URL' ); WP_CLI::line( ' --path= set the current path to the WP install' ); + WP_CLI::line( ' --require= load a certain file before running the command' ); WP_CLI::line( ' --version print wp-cli version' ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 42d217d6e..c993122e0 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -95,6 +95,12 @@ unset( $assoc_args['user'], $user ); } +// Handle --require parameter +if ( isset( $assoc_args['require'] ) ) { + require $assoc_args['require']; + unset( $assoc_args['require'] ); +} + // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { WP_CLI::load_all_commands(); From 96fabe98ee811940e4b57814cee0a59cb6d7ff5a Mon Sep 17 00:00:00 2001 From: Zack Tollman Date: Fri, 13 Apr 2012 15:02:55 -0700 Subject: [PATCH 0306/5359] Remove use of WP_CLI::line when outputting transient value In the main project, issue #71 outlines a problem with using this method to output option values when "%" is used. The transient get command is also susceptible to this issue. The same fix has been applied here. --- src/php/wp-cli/commands/internals/transient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php index 5bbe6e2e8..4e7c8b1c8 100644 --- a/src/php/wp-cli/commands/internals/transient.php +++ b/src/php/wp-cli/commands/internals/transient.php @@ -31,9 +31,9 @@ public function get( $args ) { } if ( is_array( $value ) || is_object( $value ) ) - WP_CLI::line( var_export( $value ) ); + echo var_export( $value ) . "\n"; else - WP_CLI::success( $value ); + echo $value . "\n"; } /** From 9bd5ade184b4f07f7036e738698519588565dbe9 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 16 Apr 2012 18:59:30 +0300 Subject: [PATCH 0307/5359] make file names match command names. fixes #99 --- .../{google-sitemap-generator.php => google-sitemap.php} | 0 .../commands/community/{wp-super-cache.php => super-cache.php} | 0 .../commands/community/{w3-total-cache.php => total-cache.php} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/php/wp-cli/commands/community/{google-sitemap-generator.php => google-sitemap.php} (100%) rename src/php/wp-cli/commands/community/{wp-super-cache.php => super-cache.php} (100%) rename src/php/wp-cli/commands/community/{w3-total-cache.php => total-cache.php} (100%) diff --git a/src/php/wp-cli/commands/community/google-sitemap-generator.php b/src/php/wp-cli/commands/community/google-sitemap.php similarity index 100% rename from src/php/wp-cli/commands/community/google-sitemap-generator.php rename to src/php/wp-cli/commands/community/google-sitemap.php diff --git a/src/php/wp-cli/commands/community/wp-super-cache.php b/src/php/wp-cli/commands/community/super-cache.php similarity index 100% rename from src/php/wp-cli/commands/community/wp-super-cache.php rename to src/php/wp-cli/commands/community/super-cache.php diff --git a/src/php/wp-cli/commands/community/w3-total-cache.php b/src/php/wp-cli/commands/community/total-cache.php similarity index 100% rename from src/php/wp-cli/commands/community/w3-total-cache.php rename to src/php/wp-cli/commands/community/total-cache.php From bbbde0747e9fc33e45dbd4257cec7c1ced69ef87 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 11:12:01 -0700 Subject: [PATCH 0308/5359] Correct spelling in comment --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 03c1aef42..ee287cd2e 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -72,7 +72,7 @@ private function update_multiple( $args, $assoc_args ) { } /** - * Check wether an item has an update available or not. + * Check whether an item has an update available or not. * * @param string $item The plugin/theme theme path * From d00b8494075d2699759bdb6d0f0a5c3e4731ff9e Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 11:12:32 -0700 Subject: [PATCH 0309/5359] Initial commit for 'wp theme install' command. Ported from 'wp plugin install'. --- src/php/wp-cli/commands/internals/theme.php | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index e8856ada3..94c41d54e 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -124,6 +124,65 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } + /** + * Install a new theme + * + * @param array $args + * @param array $assoc_args + */ + function install( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp theme install " ); + exit(); + } + + $slug = stripslashes( $args[0] ); + + // Force WordPress to update the theme list + wp_update_themes(); + + // If --file is set, install from file. + if ( isset( $assoc_args['file'] ) ) { + $result = WP_CLI::get_upgrader( $this->upgrader )->install( $args[0] ); + + // Else, install from .org theme repo. + } else { + $result = 0; + + $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); + if ( is_wp_error( $api ) ) { + WP_CLI::error( "Can't find the theme in the WordPress.org theme repository." ); + exit(); + } + + // Check to see if we should update, rather than install. + if ( $this->get_update_status( $api->slug ) ) { + WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); + $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $api->slug ); + + /** + * Else, if there's no update, it's either not installed, + * or it's newer than what we've got. + */ + } else if ( !is_readable( $this->get_stylesheet_path( $api->slug ) ) ) { + WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); + } else { + $result = 1; + WP_CLI::warning( 'Theme already installed and up to date.' ); + } + + /** + * Finally, activate theme if requested. + * At the moment, this only works with themes installed from repo. + */ + if ( $result && isset( $assoc_args['activate'] ) ) { + WP_CLI::line( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } + } + } + protected function get_item_list() { return wp_list_pluck( get_themes(), 'Stylesheet' ); } @@ -181,6 +240,10 @@ public static function help() { path print path to the theme's stylesheet --dir get the path to the closest parent directory + install install a theme from wordpress.org + --activate activate the theme after installing it + --file install from ZIP file + update update a theme from wordpress.org --all update all themes from wordpress.org From d209b44602be3f9caeafbaafaf05ed9050abccc0 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 16:31:00 -0700 Subject: [PATCH 0310/5359] Move to --file=file.zip and fix --activate with --file --- src/php/wp-cli/commands/internals/theme.php | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 94c41d54e..76272468a 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -131,22 +131,26 @@ function path( $args, $assoc_args ) { * @param array $assoc_args */ function install( $args, $assoc_args ) { - if ( empty( $args ) ) { + if ( empty( $args ) && empty( $assoc_args ) ) { WP_CLI::line( "usage: wp theme install " ); exit(); } - $slug = stripslashes( $args[0] ); + $slug = ''; // Force WordPress to update the theme list wp_update_themes(); // If --file is set, install from file. if ( isset( $assoc_args['file'] ) ) { - $result = WP_CLI::get_upgrader( $this->upgrader )->install( $args[0] ); + $upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $result = $upgrader->install( $assoc_args['file'] ); + + $slug = $upgrader->result['destination_name']; // Else, install from .org theme repo. } else { + $slug = stripslashes( $args[0] ); $result = 0; $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); @@ -168,18 +172,14 @@ function install( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); } else { - $result = 1; - WP_CLI::warning( 'Theme already installed and up to date.' ); + WP_CLI::error( 'Theme already installed and up to date.' ); } + } - /** - * Finally, activate theme if requested. - * At the moment, this only works with themes installed from repo. - */ - if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::line( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + // Finally, activate theme if requested. + if ( $result && isset( $assoc_args['activate'] ) ) { + WP_CLI::line( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); } } From 415808baefb2d80e2e869bf93ade9c734740e702 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 16:46:48 -0700 Subject: [PATCH 0311/5359] Use .zip to decide if theme is a file Actually, just kidding. Let's use .zip to decide if we should install as a file, and avoid --file altogether. --- src/php/wp-cli/commands/internals/theme.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 76272468a..4c09c8ad8 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -131,7 +131,7 @@ function path( $args, $assoc_args ) { * @param array $assoc_args */ function install( $args, $assoc_args ) { - if ( empty( $args ) && empty( $assoc_args ) ) { + if ( empty( $args ) ) { WP_CLI::line( "usage: wp theme install " ); exit(); } @@ -141,10 +141,10 @@ function install( $args, $assoc_args ) { // Force WordPress to update the theme list wp_update_themes(); - // If --file is set, install from file. - if ( isset( $assoc_args['file'] ) ) { + // If argument ends in .zip, install from file. + if ( preg_match( '/\.zip$/', $args[0] ) ) { $upgrader = WP_CLI::get_upgrader( $this->upgrader ); - $result = $upgrader->install( $assoc_args['file'] ); + $result = $upgrader->install( $args[0] ); $slug = $upgrader->result['destination_name']; @@ -242,7 +242,6 @@ public static function help() { install install a theme from wordpress.org --activate activate the theme after installing it - --file install from ZIP file update update a theme from wordpress.org --all update all themes from wordpress.org From 4dec8b4368c9d218aab2c149cc2a1469be3d76d7 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 17:00:39 -0700 Subject: [PATCH 0312/5359] Rename $upgrader to $file_upgrader like a good boy. --- src/php/wp-cli/commands/internals/theme.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 4c09c8ad8..211209394 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -143,10 +143,10 @@ function install( $args, $assoc_args ) { // If argument ends in .zip, install from file. if ( preg_match( '/\.zip$/', $args[0] ) ) { - $upgrader = WP_CLI::get_upgrader( $this->upgrader ); - $result = $upgrader->install( $args[0] ); + $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $result = $file_upgrader->install( $args[0] ); - $slug = $upgrader->result['destination_name']; + $slug = $file_upgrader->result['destination_name']; // Else, install from .org theme repo. } else { From 05b55779ccceb539baff6d92e34776a0ac6d19a3 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 17:52:35 -0700 Subject: [PATCH 0313/5359] Add install_from_file and add .zip support to plugins Add install_from_file to WP_CLI_Command_With_Upgrade Add support to plugins for .zip through install_from_file Fix $result scope, and NULL by default. Use $slug instead of $api->slug when possible --- .../class-wp-cli-command-with-upgrade.php | 18 +++++++++++++++++- src/php/wp-cli/commands/internals/plugin.php | 12 ++++++++++++ src/php/wp-cli/commands/internals/theme.php | 14 +++++--------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index ee287cd2e..3b8f15231 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -83,5 +83,21 @@ protected function get_update_status( $file ) { return isset( $update_list->response[ $file ] ); } -} + /** + * Install a plugin/theme from a ZIP file + * + * @param string $file + * + * @return string The plugin/theme's slug, or NULL on failed install. + */ + protected function install_from_file( $file ) { + $slug = NULL; + $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); + + if ( $file_upgrader->install( $file ) ) + $slug = $file_upgrader->result['destination_name']; + + return $slug; + } +} diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index e8f3a0e69..23a3e8794 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -202,6 +202,18 @@ function install( $args, $assoc_args ) { // Force WordPress to update the plugin list wp_update_plugins(); + // If argument ends in .zip, install from file. + if ( preg_match( '/\.zip$/', $args[0] ) ) { + $slug = $this->install_from_file( $args[0] ); + + if ( $slug && isset( $assoc_args['activate'] ) ) { + WP_CLI::line( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } + + exit(); + } + $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( !$api ) { WP_CLI::error( "Can't find the plugin in the WordPress.org plugins repository." ); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 211209394..d0e36026a 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -136,22 +136,18 @@ function install( $args, $assoc_args ) { exit(); } - $slug = ''; + $slug = $result = NULL; // Force WordPress to update the theme list wp_update_themes(); // If argument ends in .zip, install from file. if ( preg_match( '/\.zip$/', $args[0] ) ) { - $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); - $result = $file_upgrader->install( $args[0] ); - - $slug = $file_upgrader->result['destination_name']; + $slug = $result = $this->install_from_file( $args[0] ); // Else, install from .org theme repo. } else { $slug = stripslashes( $args[0] ); - $result = 0; $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { @@ -160,15 +156,15 @@ function install( $args, $assoc_args ) { } // Check to see if we should update, rather than install. - if ( $this->get_update_status( $api->slug ) ) { + if ( $this->get_update_status( $slug ) ) { WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $api->slug ); + $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $slug ); /** * Else, if there's no update, it's either not installed, * or it's newer than what we've got. */ - } else if ( !is_readable( $this->get_stylesheet_path( $api->slug ) ) ) { + } else if ( !is_readable( $this->get_stylesheet_path( $slug ) ) ) { WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); } else { From fba595644b0b32a472309e5b228ff51c39e1a49b Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 18:41:22 -0700 Subject: [PATCH 0314/5359] Make $result slightly more poetic. --- src/php/wp-cli/commands/internals/theme.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index d0e36026a..6353116aa 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -143,7 +143,12 @@ function install( $args, $assoc_args ) { // If argument ends in .zip, install from file. if ( preg_match( '/\.zip$/', $args[0] ) ) { - $slug = $result = $this->install_from_file( $args[0] ); + $slug = $this->install_from_file( $args[0] ); + + // If install_from_file() returns non-NULL, install succeeded. + if ( !is_null( $slug ) ) { + $result = 1; + } // Else, install from .org theme repo. } else { From 3611d07e8c1935f8c91a35cc1e3ed46e92637f95 Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 18 Apr 2012 18:54:48 -0700 Subject: [PATCH 0315/5359] Avoid extra run of wp-cli on plugin install --activate --- src/php/wp-cli/commands/internals/plugin.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 23a3e8794..a8827b68d 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -248,10 +248,9 @@ function install( $args, $assoc_args ) { $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); $result = $upgrader->install( $api->download_link ); - if ( $result ) { - if ( isset( $assoc_args['activate'] ) ) { - system( "wp plugin activate " . WP_CLI::compose_args( $args, $assoc_args ) ); - } + if ( $result && isset( $assoc_args['activate'] ) ) { + WP_CLI::line( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); } break; From 6da4a618e744355cac4c10a771055c4781621367 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 19 Apr 2012 17:13:09 +0300 Subject: [PATCH 0316/5359] replace install_from_file() with maybe_install_from_zip(). see #100 --- .../class-wp-cli-command-with-upgrade.php | 17 +++--- src/php/wp-cli/commands/internals/plugin.php | 17 ++---- src/php/wp-cli/commands/internals/theme.php | 52 ++++++++----------- 3 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 3b8f15231..7988dd3d9 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -88,16 +88,21 @@ protected function get_update_status( $file ) { * Install a plugin/theme from a ZIP file * * @param string $file - * - * @return string The plugin/theme's slug, or NULL on failed install. + * @param bool $activate */ - protected function install_from_file( $file ) { - $slug = NULL; + protected function maybe_install_from_zip( $file, $activate ) { + if ( '.zip' != substr( $file, -4 ) ) + return; + $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); - if ( $file_upgrader->install( $file ) ) + if ( $file_upgrader->install( $file ) ) { $slug = $file_upgrader->result['destination_name']; - return $slug; + if ( $activate ) + $this->activate( array( $slug ) ); + } + + exit; } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index a8827b68d..04c43da12 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -197,23 +197,14 @@ function install( $args, $assoc_args ) { exit; } - $slug = stripslashes( $args[0] ); - // Force WordPress to update the plugin list wp_update_plugins(); - // If argument ends in .zip, install from file. - if ( preg_match( '/\.zip$/', $args[0] ) ) { - $slug = $this->install_from_file( $args[0] ); - - if ( $slug && isset( $assoc_args['activate'] ) ) { - WP_CLI::line( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + $slug = stripslashes( $args[0] ); - exit(); - } + $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); + // Not a zip, so try to install from wp.org $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( !$api ) { WP_CLI::error( "Can't find the plugin in the WordPress.org plugins repository." ); @@ -370,7 +361,7 @@ public static function help() { path print path to the plugin's file --dir get the path to the closest parent directory - install install a plugin from wordpress.org + install install a plugin from wordpress.org or from a zip file --activate activate the plugin after installing it --dev install the development version --version install a specific version diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 6353116aa..1f6ba5eee 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -97,11 +97,12 @@ public function activate( $args = array() ) { if ( empty( $parent ) ) { $parent = $child; } elseif ( !is_readable( $this->get_stylesheet_path( $parent ) ) ) { - WP_CLI::warning( 'parent theme not found' ); - exit; + WP_CLI::error( 'Parent theme not found.' ); } switch_theme( $parent, $child ); + + WP_CLI::success( "Switched to '{$details['Title']}' theme." ); } /** @@ -136,45 +137,36 @@ function install( $args, $assoc_args ) { exit(); } - $slug = $result = NULL; - // Force WordPress to update the theme list wp_update_themes(); - // If argument ends in .zip, install from file. - if ( preg_match( '/\.zip$/', $args[0] ) ) { - $slug = $this->install_from_file( $args[0] ); + $slug = stripslashes( $args[0] ); - // If install_from_file() returns non-NULL, install succeeded. - if ( !is_null( $slug ) ) { - $result = 1; - } + $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); - // Else, install from .org theme repo. - } else { - $slug = stripslashes( $args[0] ); + // Not a zip, so try to install from wp.org + $result = NULL; - $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); - if ( is_wp_error( $api ) ) { - WP_CLI::error( "Can't find the theme in the WordPress.org theme repository." ); - exit(); - } + $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); + if ( is_wp_error( $api ) ) { + WP_CLI::error( "Can't find the theme in the WordPress.org theme repository." ); + exit(); + } - // Check to see if we should update, rather than install. - if ( $this->get_update_status( $slug ) ) { - WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $slug ); + // Check to see if we should update, rather than install. + if ( $this->get_update_status( $slug ) ) { + WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); + $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $slug ); /** * Else, if there's no update, it's either not installed, * or it's newer than what we've got. */ - } else if ( !is_readable( $this->get_stylesheet_path( $slug ) ) ) { - WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); - } else { - WP_CLI::error( 'Theme already installed and up to date.' ); - } + } else if ( !is_readable( $this->get_stylesheet_path( $slug ) ) ) { + WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); + } else { + WP_CLI::error( 'Theme already installed and up to date.' ); } // Finally, activate theme if requested. @@ -241,7 +233,7 @@ public static function help() { path print path to the theme's stylesheet --dir get the path to the closest parent directory - install install a theme from wordpress.org + install install a theme from wordpress.org or from a zip file --activate activate the theme after installing it update update a theme from wordpress.org From 812abfacbe8c12208d9b13ab3d416e32a3c407eb Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 22 Apr 2012 02:48:35 +0300 Subject: [PATCH 0317/5359] update copyright notice --- LICENSE.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 8a2f6b51e..745e84216 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,8 @@ -Copyright (c) 2011 Andreas Creten +======================================== +wp-cli is licensed under the MIT License +======================================== + +Copyright (C) 2011-2012 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From e152cf481ce2ca7519fee326e6517f04b69cbc2a Mon Sep 17 00:00:00 2001 From: "John P. Bloch" Date: Tue, 24 Apr 2012 10:54:59 -0400 Subject: [PATCH 0318/5359] Put the total cache flush function in a do .. while loop so we can send in multiple arguments at a time, such as: wp total-cache flush object post to flush both the object cache and the page cache at the same time. Uses array_unique on $args to make sure the explicitly defined switch cases are only hit once. Use a variable and check if it's set and true to keep the whole page cache from being flushed multiple times. --- .../wp-cli/commands/community/total-cache.php | 97 ++++++++++--------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index bac1dd8b8..5d24bd808 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -21,57 +21,64 @@ class W3TotalCacheCommand extends WP_CLI_Command { */ function flush( $args = array(), $vars = array() ) { if ( function_exists( 'w3tc_pgcache_flush' ) ) { - $cache_type = array_shift($args); + $args = array_unique( $args ); + do { + $cache_type = array_shift($args); - switch($cache_type) { - case 'db': - case 'database': - if ( w3tc_dbcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + switch($cache_type) { + case 'db': + case 'database': + if ( w3tc_dbcache_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'minify': - if ( w3tc_minify_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + case 'minify': + if ( w3tc_minify_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'object': - if ( w3tc_objectcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + case 'object': + if ( w3tc_objectcache_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'post': - default: - if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) ) { - w3tc_pgcache_flush_post( $vars['post_id'] ); - } else { - WP_CLI::error('This is not a valid post id.'); - } + case 'post': + default: + if ( isset($vars['post_id']) ) { + if ( is_numeric( $vars['post_id'] ) ) { + w3tc_pgcache_flush_post( $vars['post_id'] ); + } else { + WP_CLI::error('This is not a valid post id.'); + } - w3tc_pgcache_flush_post( $vars['post_id'] ); - } - elseif ( isset( $vars['permalink'] ) ) { - $id = url_to_postid( $vars['permalink'] ); + w3tc_pgcache_flush_post( $vars['post_id'] ); + } + elseif ( isset( $vars['permalink'] ) ) { + $id = url_to_postid( $vars['permalink'] ); - if ( is_numeric( $id ) ) { - w3tc_pgcache_flush_post( $id ); - } else { - WP_CLI::error('There is no post with this permalink.'); - } - } else { - w3tc_pgcache_flush(); - } - } + if ( is_numeric( $id ) ) { + w3tc_pgcache_flush_post( $id ); + } else { + WP_CLI::error('There is no post with this permalink.'); + } + } else { + if ( isset( $flushed_page_cache ) && $flushed_page_cache ) + break; + + $flushed_page_cache = true; + w3tc_pgcache_flush(); + } + } + } while ( !empty( $args ) ); } else { WP_CLI::error('The W3 Total Cache could not be found, is it installed?'); } From 6aa5f9b1a2bdb86a98ddedc8e6dd859bc3520198 Mon Sep 17 00:00:00 2001 From: "John P. Bloch" Date: Tue, 24 Apr 2012 11:37:26 -0400 Subject: [PATCH 0319/5359] Formatting issues... --- .../wp-cli/commands/community/total-cache.php | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index 5d24bd808..365f8c973 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -21,64 +21,64 @@ class W3TotalCacheCommand extends WP_CLI_Command { */ function flush( $args = array(), $vars = array() ) { if ( function_exists( 'w3tc_pgcache_flush' ) ) { - $args = array_unique( $args ); - do { - $cache_type = array_shift($args); + $args = array_unique( $args ); + do { + $cache_type = array_shift($args); - switch($cache_type) { - case 'db': - case 'database': - if ( w3tc_dbcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + switch($cache_type) { + case 'db': + case 'database': + if ( w3tc_dbcache_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'minify': - if ( w3tc_minify_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + case 'minify': + if ( w3tc_minify_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'object': - if ( w3tc_objectcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + case 'object': + if ( w3tc_objectcache_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'post': - default: - if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) ) { - w3tc_pgcache_flush_post( $vars['post_id'] ); - } else { - WP_CLI::error('This is not a valid post id.'); - } + case 'post': + default: + if ( isset($vars['post_id']) ) { + if ( is_numeric( $vars['post_id'] ) ) { + w3tc_pgcache_flush_post( $vars['post_id'] ); + } else { + WP_CLI::error('This is not a valid post id.'); + } - w3tc_pgcache_flush_post( $vars['post_id'] ); - } - elseif ( isset( $vars['permalink'] ) ) { - $id = url_to_postid( $vars['permalink'] ); + w3tc_pgcache_flush_post( $vars['post_id'] ); + } + elseif ( isset( $vars['permalink'] ) ) { + $id = url_to_postid( $vars['permalink'] ); - if ( is_numeric( $id ) ) { - w3tc_pgcache_flush_post( $id ); - } else { - WP_CLI::error('There is no post with this permalink.'); - } - } else { - if ( isset( $flushed_page_cache ) && $flushed_page_cache ) - break; + if ( is_numeric( $id ) ) { + w3tc_pgcache_flush_post( $id ); + } else { + WP_CLI::error('There is no post with this permalink.'); + } + } else { + if ( isset( $flushed_page_cache ) && $flushed_page_cache ) + break; - $flushed_page_cache = true; - w3tc_pgcache_flush(); - } - } - } while ( !empty( $args ) ); + $flushed_page_cache = true; + w3tc_pgcache_flush(); + } + } + } while ( !empty( $args ) ); } else { WP_CLI::error('The W3 Total Cache could not be found, is it installed?'); } From e773d611635f8c4838995b07380b185c05330b74 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 25 Apr 2012 23:37:39 +0300 Subject: [PATCH 0320/5359] replace contributor impact link with contributor guide link (since the contributors page shows activity too now) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e6a32ad3..f715fdfae 100644 --- a/README.md +++ b/README.md @@ -153,4 +153,4 @@ Contributors ------------ - [Contributor list](https://github.com/wp-cli/wp-cli/contributors) -- [Contributor impact](https://github.com/wp-cli/wp-cli/graphs/impact) +- [Contributor guide](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook) From 95aad0bc962c398508ffb88ca9a7f6dd61306b52 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 00:11:25 +0300 Subject: [PATCH 0321/5359] more readable check for core install --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c993122e0..a1b975b79 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -62,7 +62,7 @@ WP_CLI::_set_url( $assoc_args ); // Set installer flag before loading any WP files -if ( count( $arguments ) >= 2 && $arguments[0] == 'core' && $arguments[1] == 'install' ) { +if ( array( 'core', 'install' ) == $arguments ) { define( 'WP_INSTALLING', true ); } From e7c34cbfcda486eb903925607c83b769684e3b61 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 00:33:49 +0300 Subject: [PATCH 0322/5359] introduce `wp db create` command. fixes #103 --- src/php/wp-cli/class-wp-cli.php | 13 +++++++++++++ src/php/wp-cli/commands/internals/db.php | 18 ++++++++++++++---- src/php/wp-cli/wp-cli.php | 5 +++++ src/php/wp-cli/wp-settings.php | 4 ++++ 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/php/wp-cli/wp-settings.php diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 4613ae3b8..5247099a3 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -212,6 +212,19 @@ static function _set_url( &$assoc_args ) { } } + // Loads wp-config.php without loading the rest of WP + static function load_wp_config() { + define( 'ABSPATH', dirname(__FILE__) . '/' ); + + if ( file_exists( WP_ROOT . 'wp-config.php' ) ) { + require_once( WP_ROOT . 'wp-config.php' ); + } elseif ( file_exists( dirname(WP_ROOT) . '/wp-config.php' ) && ! file_exists( dirname(WP_ROOT) . '/wp-settings.php' ) ) { + require_once( dirname(WP_ROOT) . '/wp-config.php' ); + } else { + WP_CLI::error( 'No wp-config.php file.' ); + } + } + static function load_all_commands() { foreach ( array( 'internals', 'community' ) as $dir ) { foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 034b72c57..942f15cc7 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -15,11 +15,11 @@ class DBCommand extends WP_CLI_Command { protected $aliases = array( 'dump' => 'export' ); /** - * Return a string for connecting to the DB. + * Creates the database according to the wp-config.php file */ - protected function connect_string() { - return sprintf( 'mysql --host="%s" --database="%s" --user="%s" --password="%s"', - DB_HOST, DB_NAME, DB_USER, DB_PASSWORD ); + function create() { + exec( sprintf( 'mysql --host="%s" --user="%s" --password="%s" --execute="CREATE DATABASE %s"', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); } /** @@ -82,6 +82,14 @@ function import( $args, $assoc_args ) { WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } + /** + * Return a string for connecting to the DB. + */ + private function connect_string() { + return sprintf( 'mysql --host="%s" --user="%s" --password="%s" --database="%s"', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); + } + private function get_file_name( $args ) { if ( empty( $args ) ) return sprintf( '%s.sql', DB_NAME ); @@ -106,6 +114,8 @@ public static function help() { import Import a database exported via mysqldump. query Execute a query against the WordPress database. + + create Create a database using the info from wp-config.php. EOB ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index a1b975b79..9049ffa54 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -58,6 +58,11 @@ WP_CLI::run_command( $arguments, $assoc_args ); } +if ( array( 'db', 'create' ) == $arguments ) { + WP_CLI::load_wp_config(); + WP_CLI::run_command( $arguments, $assoc_args ); +} + // Handle --url and --blog parameters WP_CLI::_set_url( $assoc_args ); diff --git a/src/php/wp-cli/wp-settings.php b/src/php/wp-cli/wp-settings.php new file mode 100644 index 000000000..648622d87 --- /dev/null +++ b/src/php/wp-cli/wp-settings.php @@ -0,0 +1,4 @@ + Date: Fri, 27 Apr 2012 00:50:08 +0300 Subject: [PATCH 0323/5359] load all commands only when generic help is needed --- src/php/wp-cli/class-wp-cli.php | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 5247099a3..33fc2e2ee 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -248,17 +248,14 @@ static function run_command( $arguments, $assoc_args ) { } if ( 'help' == $command ) { - self::load_all_commands(); - } - else { - foreach ( array( 'internals', 'community' ) as $dir ) { - $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; - - if ( is_readable( $path ) ) { - include $path; - break; - } + if ( empty( $arguments ) ) { + self::load_all_commands(); + } else { + self::load_command( 'help' ); + self::load_command( $arguments[0] ); } + } else { + self::load_command( $command ); } if ( !isset( WP_CLI::$commands[$command] ) ) { @@ -269,5 +266,16 @@ static function run_command( $arguments, $assoc_args ) { new WP_CLI::$commands[$command]( $arguments, $assoc_args ); exit; } + + private function load_command( $command ) { + foreach ( array( 'internals', 'community' ) as $dir ) { + $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + + if ( is_readable( $path ) ) { + include $path; + break; + } + } + } } From 926edfc92745c92a0a5b2890998d9358926fea4b Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 02:15:49 +0300 Subject: [PATCH 0324/5359] don't call get_plugins() a second time if we already found a match --- src/php/wp-cli/commands/internals/plugin.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 04c43da12..401323d63 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -324,17 +324,17 @@ protected function parse_name( $args, $subcommand ) { $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { - $file = $name . '/' . key( $plugins ); + $file = key( $plugins ); } else { $file = $name . '.php'; - } - $plugins = get_plugins(); + $plugins = get_plugins(); - if ( !isset( $plugins[$file] ) ) { - WP_CLI::error( "The plugin '$name' could not be found." ); - exit(); + if ( !isset( $plugins[$file] ) ) { + WP_CLI::error( "The plugin '$name' could not be found." ); + exit(); + } } return array( $file, $name ); From 223b524cead1a02455b209042d795ccbad00e941 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 02:45:41 +0300 Subject: [PATCH 0325/5359] add db prefix to parameter names. see #65 --- src/php/wp-cli/commands/internals/core.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 38bdff797..e3e8d65a1 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -44,11 +44,11 @@ public function download( $args, $assoc_args ) { * Set up a wp-config.php file. */ public function config( $args, $assoc_args ) { - $_POST['dbname'] = $assoc_args['name']; - $_POST['uname'] = $assoc_args['user']; - $_POST['pwd'] = $assoc_args['pass']; - $_POST['dbhost'] = isset( $assoc_args['host'] ) ? $assoc_args['host'] : 'localhost'; - $_POST['prefix'] = isset( $assoc_args['prefix'] ) ? $assoc_args['prefix'] : 'wp_'; + $_POST['dbname'] = $assoc_args['dbname']; + $_POST['uname'] = $assoc_args['dbuser']; + $_POST['pwd'] = $assoc_args['dbpass']; + $_POST['dbhost'] = isset( $assoc_args['dbhost'] ) ? $assoc_args['dbhost'] : 'localhost'; + $_POST['prefix'] = isset( $assoc_args['dbprefix'] ) ? $assoc_args['dbprefix'] : 'wp_'; $_GET['step'] = 2; require WP_ROOT . '/wp-admin/setup-config.php'; From ae947a2f3903c3579d1ec79a8c087fd6b0973942 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 03:16:52 +0300 Subject: [PATCH 0326/5359] add wp core config example. see #65 --- src/php/wp-cli/commands/internals/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index e3e8d65a1..cbfe6a6bd 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -171,6 +171,7 @@ public static function help() { usage: wp core update or: wp core version [--extra] or: wp core download [--version=1.2.3] + or: wp core config --dbname= --dbuser= --dbpass= [--dbhost=localhost] [--dbprefix=wp_] or: wp core install --site_url=example.com --site_title= [--admin_name=] --admin_password= --admin_email= EOB ); From 400201eb28d7bb1e42adc58b8eb9675b1cab8a79 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 18:29:44 +0300 Subject: [PATCH 0327/5359] call errorToString internally in WP_CLI::warning() --- src/php/wp-cli/class-cli-upgrader-skin.php | 2 +- src/php/wp-cli/class-wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index a6d748490..93488b8ca 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -17,7 +17,7 @@ function error( $error ) { return; // TODO: show all errors, not just the first one - WP_CLI::warning( WP_CLI::errorToString( $error ) ); + WP_CLI::warning( $error ); } function feedback( $string ) { diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 33fc2e2ee..d39cadbe0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -69,7 +69,7 @@ static function success( $message, $label = 'Success' ) { */ static function warning( $message, $label = 'Warning' ) { if ( WP_CLI_SILENT ) return; - \cli\line( '%C' . $label . ': %n' . $message ); + \cli\line( '%C' . $label . ': %n' . self::errorToString( $message ) ); } /** From 88b1eeb9bc6598942779c62305f25411cd98dc0e Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 18:30:34 +0300 Subject: [PATCH 0328/5359] add underscores to command class names --- src/php/wp-cli/commands/community/google-sitemap.php | 4 ++-- src/php/wp-cli/commands/community/super-cache.php | 4 ++-- src/php/wp-cli/commands/community/total-cache.php | 4 ++-- src/php/wp-cli/commands/internals/core.php | 4 ++-- src/php/wp-cli/commands/internals/db.php | 4 ++-- src/php/wp-cli/commands/internals/eval-file.php | 4 ++-- src/php/wp-cli/commands/internals/eval.php | 4 ++-- src/php/wp-cli/commands/internals/export.php | 4 ++-- src/php/wp-cli/commands/internals/generate.php | 4 ++-- src/php/wp-cli/commands/internals/help.php | 4 ++-- src/php/wp-cli/commands/internals/home.php | 4 ++-- src/php/wp-cli/commands/internals/option.php | 4 ++-- src/php/wp-cli/commands/internals/plugin.php | 4 ++-- src/php/wp-cli/commands/internals/theme.php | 4 ++-- src/php/wp-cli/commands/internals/transient.php | 4 ++-- src/php/wp-cli/commands/internals/user.php | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/php/wp-cli/commands/community/google-sitemap.php b/src/php/wp-cli/commands/community/google-sitemap.php index 268518701..6a0a94a9c 100644 --- a/src/php/wp-cli/commands/community/google-sitemap.php +++ b/src/php/wp-cli/commands/community/google-sitemap.php @@ -1,7 +1,7 @@ Date: Fri, 27 Apr 2012 18:31:25 +0300 Subject: [PATCH 0329/5359] rename errorToString() to error_to_string() --- src/php/wp-cli/class-wp-cli.php | 8 ++++---- src/php/wp-cli/commands/internals/core.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d39cadbe0..b142edd6e 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -46,7 +46,7 @@ static function line( $message = '' ) { * @param string $label */ static function error( $message, $label = 'Error' ) { - \cli\err( '%R' . $label . ': %n' . self::errorToString( $message ) ); + \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); exit(1); } @@ -69,16 +69,16 @@ static function success( $message, $label = 'Success' ) { */ static function warning( $message, $label = 'Warning' ) { if ( WP_CLI_SILENT ) return; - \cli\line( '%C' . $label . ': %n' . self::errorToString( $message ) ); + \cli\line( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } /** - * Convert a wp_error into a String + * Convert a wp_error into a string * * @param mixed $errors * @return string */ - static function errorToString( $errors ) { + static function error_to_string( $errors ) { if( is_string( $errors ) ) { return $errors; } elseif( is_wp_error( $errors ) && $errors->get_error_code() ) { diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 4159f96c4..a55efb3c0 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -91,7 +91,7 @@ public function install( $args, $assoc_args ) { $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { - WP_CLI::error( 'Installation failed (' . WP_CLI::errorToString($result) . ').' ); + WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); } else { WP_CLI::success( 'WordPress installed successfully.' ); } @@ -152,7 +152,7 @@ function update( $args ) { $result = WP_CLI::get_upgrader( 'Core_Upgrader' )->upgrade( $update ); if ( is_wp_error($result) ) { - $msg = WP_CLI::errorToString( $result ); + $msg = WP_CLI::error_to_string( $result ); if ( 'up_to_date' != $result->get_error_code() ) { WP_CLI::error( $msg ); } else { From d40828dc48e43b6c417dabfb6497a4da13711617 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 27 Apr 2012 19:55:32 +0300 Subject: [PATCH 0330/5359] rename addCommand() to add_command() --- src/php/wp-cli/class-wp-cli.php | 7 ++++++- src/php/wp-cli/commands/community/google-sitemap.php | 2 +- src/php/wp-cli/commands/community/super-cache.php | 2 +- src/php/wp-cli/commands/community/total-cache.php | 2 +- src/php/wp-cli/commands/internals/core.php | 2 +- src/php/wp-cli/commands/internals/db.php | 2 +- src/php/wp-cli/commands/internals/eval-file.php | 2 +- src/php/wp-cli/commands/internals/eval.php | 2 +- src/php/wp-cli/commands/internals/export.php | 2 +- src/php/wp-cli/commands/internals/generate.php | 2 +- src/php/wp-cli/commands/internals/help.php | 2 +- src/php/wp-cli/commands/internals/home.php | 2 +- src/php/wp-cli/commands/internals/option.php | 2 +- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 2 +- src/php/wp-cli/commands/internals/transient.php | 2 +- src/php/wp-cli/commands/internals/user.php | 2 +- 17 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index b142edd6e..656e94ce9 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -15,7 +15,7 @@ class WP_CLI { * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command */ - public function addCommand( $name, $class ) { + public function add_command( $name, $class ) { self::$commands[$name] = $class; } @@ -277,5 +277,10 @@ private function load_command( $command ) { } } } + + // back-compat + public function addCommand( $name, $class ) { + self::add_command( $name, $class ); + } } diff --git a/src/php/wp-cli/commands/community/google-sitemap.php b/src/php/wp-cli/commands/community/google-sitemap.php index 6a0a94a9c..424837323 100644 --- a/src/php/wp-cli/commands/community/google-sitemap.php +++ b/src/php/wp-cli/commands/community/google-sitemap.php @@ -1,7 +1,7 @@ Date: Sun, 29 Apr 2012 14:23:06 +0300 Subject: [PATCH 0331/5359] plugins_api() returns WP_Error --- src/php/wp-cli/commands/internals/plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index c957cab6e..74fec8b89 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -206,9 +206,9 @@ function install( $args, $assoc_args ) { // Not a zip, so try to install from wp.org $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); - if ( !$api ) { - WP_CLI::error( "Can't find the plugin in the WordPress.org plugins repository." ); - exit(); + + if ( is_wp_error( $api ) ) { + WP_CLI::error( $api ); } if ( isset( $assoc_args['dev'] ) ) { From 5e80652e000498ab14caac7845f0fb6785ac42d0 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 14:41:55 +0300 Subject: [PATCH 0332/5359] fix Plugin_Command::parse_name() --- src/php/wp-cli/commands/internals/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 74fec8b89..e32d2b5dc 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -324,7 +324,7 @@ protected function parse_name( $args, $subcommand ) { $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { - $file = key( $plugins ); + $file = $name . '/' . key( $plugins ); } else { $file = $name . '.php'; From 96ca68dafa0628e8b60da622b22238d0bda1951e Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 15:17:49 +0300 Subject: [PATCH 0333/5359] update docs for get_update_status --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 7988dd3d9..639573f83 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -74,14 +74,14 @@ private function update_multiple( $args, $assoc_args ) { /** * Check whether an item has an update available or not. * - * @param string $item The plugin/theme theme path + * @param string $slug The plugin/theme slug * * @return bool */ - protected function get_update_status( $file ) { + protected function get_update_status( $slug ) { $update_list = get_site_transient( $this->upgrade_transient ); - return isset( $update_list->response[ $file ] ); + return isset( $update_list->response[ $slug ] ); } /** From b0402c857df335c8d7874c619ae43ca169b385ba Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 15:25:24 +0300 Subject: [PATCH 0334/5359] introduce precise is_active_theme() method --- src/php/wp-cli/commands/internals/theme.php | 31 +++++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 4eaec4ccd..b897b224a 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -26,15 +26,16 @@ public function status( $args = array() ) { return; } - $name = $args[0]; + $slug = stripslashes( $args[0] ); - $details = get_theme_data( $this->get_stylesheet_path( $name ) ); + $stylesheet = $this->get_stylesheet_path( $slug ); + $details = get_theme_data( $stylesheet ); - $status = $this->get_status( $details['Name'], true ); + $status = $this->get_status( $stylesheet, true ); $version = $details['Version']; - if ( $this->get_update_status( $details['Stylesheet'] ) ) + if ( $this->get_update_status( $slug ) ) $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Theme %9' . $name . '%n details:' ); @@ -48,14 +49,16 @@ private function list_themes() { // Print the header WP_CLI::line( 'Installed themes:' ); - foreach ( get_themes() as $theme ) { + foreach ( get_themes() as $key => $theme ) { if ( $this->get_update_status( $theme['Stylesheet'] ) ) { $line = ' %yU%n'; } else { $line = ' '; } - $line .= $this->get_status( $theme['Name'] ) . ' ' . $theme['Stylesheet'] . '%n'; + $stylesheet = $this->get_stylesheet_path( $theme['Stylesheet'] ); + + $line .= $this->get_status( $stylesheet ) . ' ' . $theme['Stylesheet'] . '%n'; WP_CLI::line( $line ); } @@ -71,8 +74,8 @@ private function list_themes() { WP_CLI::legend( $legend ); } - private function get_status( $theme_name, $long = false ) { - if ( get_current_theme() == $theme_name ) { + private function get_status( $stylesheet, $long = false ) { + if ( $this->is_active_theme( $stylesheet ) ) { $line = '%g'; $line .= $long ? 'Active' : 'A'; } else { @@ -102,7 +105,17 @@ public function activate( $args = array() ) { switch_theme( $parent, $child ); - WP_CLI::success( "Switched to '{$details['Title']}' theme." ); + $name = $details['Title']; + + if ( $this->is_active_theme( $stylesheet ) ) { + WP_CLI::success( "Switched to '$name' theme." ); + } else { + WP_CLI::error( "Could not switch to '$name' theme." ); + } + } + + private function is_active_theme( $stylesheet ) { + return dirname( $stylesheet ) == get_stylesheet_directory(); } /** From 27a6acffbb14ecda5232e195d72d6d4efde45e25 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 15:26:05 +0300 Subject: [PATCH 0335/5359] call wp_update_themes() at the top of list_themes() --- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index e32d2b5dc..4f5f4d3a2 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -57,7 +57,7 @@ function status( $args = array(), $vars = array() ) { } private function list_plugins() { - // Force WordPress to update the plugin list + // Force WordPress to check for plugin updates wp_update_plugins(); $plugins = get_plugins(); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index b897b224a..2dfbe9ea3 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -46,6 +46,9 @@ public function status( $args = array() ) { } private function list_themes() { + // Force WordPress to check for theme updates + wp_update_themes(); + // Print the header WP_CLI::line( 'Installed themes:' ); From da2b8769b27a7740241bf763d960f1a952b83f73 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 15:55:33 +0300 Subject: [PATCH 0336/5359] move status() method up to WP_CLI_Command_With_Upgrade --- .../class-wp-cli-command-with-upgrade.php | 18 ++++++++++++++ src/php/wp-cli/commands/internals/plugin.php | 23 ++++-------------- src/php/wp-cli/commands/internals/theme.php | 24 ++++--------------- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 639573f83..579e76ef3 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -4,6 +4,24 @@ class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { protected $default_subcommand = 'status'; + /** + * Get the status of one or all items + * + * @param array $args + */ + function status( $args = array() ) { + // Force WordPress to check for updates + call_user_func( $this->upgrade_refresh ); + + if ( empty( $args ) ) { + $this->status_all(); + } else { + list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + + $this->status_single( $file, $name ); + } + } + /** * Update a plugin/theme * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 4f5f4d3a2..5776823b2 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -24,21 +24,8 @@ function __construct( $args, $assoc_args ) { parent::__construct( $args, $assoc_args ); } - /** - * Get the status of one or all plugins - * - * @param array $args - */ - function status( $args = array(), $vars = array() ) { - $this->mu_plugins = get_mu_plugins(); - - if ( empty( $args ) ) { - $this->list_plugins(); - return; - } - - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - + // Show details about a single plugin + protected function status_single( $file, $name ) { $details = $this->get_details( $file ); $status = $this->get_status( $file, true ); @@ -56,9 +43,9 @@ function status( $args = array(), $vars = array() ) { WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); } - private function list_plugins() { - // Force WordPress to check for plugin updates - wp_update_plugins(); + // Show details about all plugins + protected function status_all() { + $this->mu_plugins = get_mu_plugins(); $plugins = get_plugins(); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 2dfbe9ea3..16c75ea92 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -15,27 +15,15 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; - /** - * Get the status of one or all themes - * - * @param array $args - **/ - public function status( $args = array() ) { - if ( empty( $args ) ) { - $this->list_themes(); - return; - } - - $slug = stripslashes( $args[0] ); - - $stylesheet = $this->get_stylesheet_path( $slug ); + // Show details about a single theme + protected function status_single( $stylesheet, $name ) { $details = get_theme_data( $stylesheet ); $status = $this->get_status( $stylesheet, true ); $version = $details['Version']; - if ( $this->get_update_status( $slug ) ) + if ( $this->get_update_status( $name ) ) $version .= ' (%gUpdate available%n)'; WP_CLI::line( 'Theme %9' . $name . '%n details:' ); @@ -45,10 +33,8 @@ public function status( $args = array() ) { WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } - private function list_themes() { - // Force WordPress to check for theme updates - wp_update_themes(); - + // Show details about all themes + protected function status_all() { // Print the header WP_CLI::line( 'Installed themes:' ); From 43e92314e6a72210ce271bad6e37056bc9732e70 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 16:15:25 +0300 Subject: [PATCH 0337/5359] move install() method up to WP_CLI_Command_With_Upgrade --- .../class-wp-cli-command-with-upgrade.php | 23 +++++++++++++++++++ src/php/wp-cli/commands/internals/plugin.php | 21 +---------------- src/php/wp-cli/commands/internals/theme.php | 21 +---------------- 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 579e76ef3..f4c89dab4 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -22,6 +22,29 @@ function status( $args = array() ) { } } + /** + * Install a new plugin/theme + * + * @param array $args + * @param array $assoc_args + */ + function install( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp $this->item_type install " ); + exit; + } + + // Force WordPress to check for updates + call_user_func( $this->upgrade_refresh ); + + $slug = stripslashes( $args[0] ); + + $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); + + // Not a zip, so try to install from wp.org + $this->install_from_repo( $slug, $assoc_args ); + } + /** * Update a plugin/theme * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 5776823b2..bd051ba55 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -172,26 +172,7 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } - /** - * Install a new plugin - * - * @param array $args - * @param array $assoc_args - */ - function install( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp plugin install " ); - exit; - } - - // Force WordPress to update the plugin list - wp_update_plugins(); - - $slug = stripslashes( $args[0] ); - - $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); - - // Not a zip, so try to install from wp.org + protected function install_from_repo( $slug, $assoc_args ) { $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 16c75ea92..fe9fb4d5d 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -127,26 +127,7 @@ function path( $args, $assoc_args ) { WP_CLI::line( $path ); } - /** - * Install a new theme - * - * @param array $args - * @param array $assoc_args - */ - function install( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp theme install " ); - exit(); - } - - // Force WordPress to update the theme list - wp_update_themes(); - - $slug = stripslashes( $args[0] ); - - $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); - - // Not a zip, so try to install from wp.org + protected function install_from_repo( $slug, $assoc_args ) { $result = NULL; $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); From 7c8ee9d902622621b57f979a70324c5a77bd936c Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 29 Apr 2012 16:23:23 +0300 Subject: [PATCH 0338/5359] merge maybe_install_from_zip() into install() --- .../class-wp-cli-command-with-upgrade.php | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index f4c89dab4..cad2fd1d8 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -39,10 +39,20 @@ function install( $args, $assoc_args ) { $slug = stripslashes( $args[0] ); - $this->maybe_install_from_zip( $slug, isset( $assoc_args['activate'] ) ); + if ( '.zip' == substr( $slug, -4 ) ) { + $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); - // Not a zip, so try to install from wp.org - $this->install_from_repo( $slug, $assoc_args ); + if ( $file_upgrader->install( $slug ) ) { + $slug = $file_upgrader->result['destination_name']; + + if ( isset( $assoc_args['activate'] ) ) { + WP_CLI::line( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } + } + } else { + $this->install_from_repo( $slug, $assoc_args ); + } } /** @@ -124,26 +134,4 @@ protected function get_update_status( $slug ) { return isset( $update_list->response[ $slug ] ); } - - /** - * Install a plugin/theme from a ZIP file - * - * @param string $file - * @param bool $activate - */ - protected function maybe_install_from_zip( $file, $activate ) { - if ( '.zip' != substr( $file, -4 ) ) - return; - - $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); - - if ( $file_upgrader->install( $file ) ) { - $slug = $file_upgrader->result['destination_name']; - - if ( $activate ) - $this->activate( array( $slug ) ); - } - - exit; - } } From 5218ea61093b52aa91dc3869bcc050c7cdaf64b9 Mon Sep 17 00:00:00 2001 From: Evan Anderson Date: Wed, 4 Apr 2012 16:12:01 -0600 Subject: [PATCH 0339/5359] Initial add of blog commands --- src/php/wp-cli/commands/internals/blog.php | 166 +++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/blog.php diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php new file mode 100644 index 000000000..45cb7d2bc --- /dev/null +++ b/src/php/wp-cli/commands/internals/blog.php @@ -0,0 +1,166 @@ + [email] [site_id] [public=(1 or 0)] []" ); + } + + private function get_site($site_id) { + global $wpdb; + // Load site data + $sites = $wpdb->get_results("SELECT * FROM $wpdb->site WHERE `id` = ".$site_id); + if (count($sites) > 0) { + // Only care about domain and path which are set here + return $sites[0]; + } + + return false; + } + + public function create($args) { + if (!is_multisite()) { + WP_CLI::line("ERROR: not a multisite instance"); + exit; + } + global $wpdb; + + // domain required + // title required + // email optional + // site optional + // public optional + if (empty($args[0]) || empty($args[1])) { + $this->_create_usage(); + exit; + } + + $base = $args[0]; + $title = $args[1]; + $email = empty($args[2]) ? '' : $args[2]; + // Site + if (!empty($args[3])) { + $site = $this->get_site($args[3]); + if ($site === false) { + WP_CLI::line('ERROR: Site with id '.$args[3].'does not exist'); + exit; + } + } + else { + $site = wpmu_current_site(); + } + // Public + if (!empty($args[4])) { + $public = $args[4]; + // Check for 1 or 0 + if ($public != '1' && $public != '0') { + $this->_create_usage(); + } + } + else { + $public = 1; + } + + $domain = ''; + if (preg_match( '|^([a-zA-Z0-9-])+$|', $blog['domain'])) { + $domain = strtolower( $blog['domain'] ); + } + + // If not a subdomain install, make sure the domain isn't a reserved word + if (!is_subdomain_install()) { + $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); + if (in_array($domain, $subdirectory_reserved_names)) { + WP_CLI::line(sprintf(__('ERROR: The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); + exit; + } + } + + + // Check for valid email, if not, use the first Super Admin found + // Probably a more efficient way to do this so we dont query for the + // User twice if super admin + $email = sanitize_email($email); + if (empty($email) || !is_email($email)) { + //@TODO just use super admin email if not specified + $super_admins = get_super_admins(); + + $email = ''; + if (!empty($super_admins) && is_array($super_admins)) { + // Just get the first one + $super_login = $super_admins[0]; + $super_user = get_user_by('login', $super_login); + if ($super_user) { + $email = $super_user->user_email; + } + } + } + + if ( is_subdomain_install() ) { + $newdomain = $base . '.' . preg_replace( '|^www\.|', '', $site->domain ); + $path = $site->path; + $url = $newdomain; + } else { + $newdomain = $site->domain; + $path = $site->domain.$site->path.$base.'/'; + $url = $path; + } + + $password = 'N/A'; + $user_id = email_exists($email); + if (!$user_id) { // Create a new user with a random password + $password = wp_generate_password(12, false); + $user_id = wpmu_create_user($base, $password, $email); + if (false == $user_id ) { + WP_CLI::line('ERROR: There was an issue creating the user.'); + exit; + } + else { + wp_new_user_notification($user_id, $password); + } + } + + $wpdb->hide_errors(); + $id = wpmu_create_blog($newdomain, $path, $title, $user_id, array( 'public' => $public ), $site->id); + $wpdb->show_errors(); + if (!is_wp_error($id)) { + if ( !is_super_admin($user_id) && !get_user_option('primary_blog', $user_id)) { + update_user_option($user_id, 'primary_blog', $id, true); + } +// $content_mail = sprintf(__( "New site created by WP Command Line Interface\n\nAddress: %2s\nName: %3s"), get_site_url($id), stripslashes($title)); + //@TODO Current site +// wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); + } + else { + WP_CLI::line($id->get_error_message()); + exit; + } + WP_CLI::line('Blog created with URL: '.$url); + } + + public function update($args) {} + + public function delete($args) {} + + public function help() { + WP_CLI::line( <<<EOB +usage: wp blog <sub-command> [<theme-name>] + +Available sub-commands: + create display status of all installed themes or of a particular theme + + update activate a particular theme + + delete print path to the theme's stylesheet + --dir get the path to the closest parent directory +EOB + ); + } +} \ No newline at end of file From 8d15c5f3d119e6d11eec8c8853edf4ab7912dcb9 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Wed, 4 Apr 2012 16:14:11 -0600 Subject: [PATCH 0340/5359] strtolower on base, not some unknown $blog var --- src/php/wp-cli/commands/internals/blog.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 45cb7d2bc..05705b212 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -69,9 +69,8 @@ public function create($args) { $public = 1; } - $domain = ''; - if (preg_match( '|^([a-zA-Z0-9-])+$|', $blog['domain'])) { - $domain = strtolower( $blog['domain'] ); + if (preg_match( '|^([a-zA-Z0-9-])+$|', $base)) { + $base = strtolower($base); } // If not a subdomain install, make sure the domain isn't a reserved word From d82a9e0d65065bd1e858118560f1765b1dab0c10 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Wed, 4 Apr 2012 16:32:48 -0600 Subject: [PATCH 0341/5359] Code format tweaks, help dialog actually helpful --- src/php/wp-cli/commands/internals/blog.php | 32 ++++++++++------------ 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 05705b212..e1a2402d8 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -10,8 +10,8 @@ */ class BlogCommand extends WP_CLI_Command { - private function _create_usage() { - WP_CLI::line( "usage: wp blog create <base> <title> [email] [site_id] [public=(1 or 0)] []" ); + private function _create_usage_string() { + return "usage: wp blog create <domain-base> <title> [email] [site_id] [public=(1 or 0)]"; } private function get_site($site_id) { @@ -39,7 +39,7 @@ public function create($args) { // site optional // public optional if (empty($args[0]) || empty($args[1])) { - $this->_create_usage(); + WP_CLI::line($this->_create_usage_string()); exit; } @@ -88,9 +88,7 @@ public function create($args) { // User twice if super admin $email = sanitize_email($email); if (empty($email) || !is_email($email)) { - //@TODO just use super admin email if not specified $super_admins = get_super_admins(); - $email = ''; if (!empty($super_admins) && is_array($super_admins)) { // Just get the first one @@ -102,11 +100,12 @@ public function create($args) { } } - if ( is_subdomain_install() ) { - $newdomain = $base . '.' . preg_replace( '|^www\.|', '', $site->domain ); + if (is_subdomain_install()) { + $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); $path = $site->path; $url = $newdomain; - } else { + } + else { $newdomain = $site->domain; $path = $site->domain.$site->path.$base.'/'; $url = $path; @@ -117,7 +116,7 @@ public function create($args) { if (!$user_id) { // Create a new user with a random password $password = wp_generate_password(12, false); $user_id = wpmu_create_user($base, $password, $email); - if (false == $user_id ) { + if (false == $user_id) { WP_CLI::line('ERROR: There was an issue creating the user.'); exit; } @@ -149,17 +148,16 @@ public function update($args) {} public function delete($args) {} public function help() { - WP_CLI::line( <<<EOB -usage: wp blog <sub-command> [<theme-name>] + WP_CLI::line(" +usage: wp blog <sub-command> [options] Available sub-commands: - create display status of all installed themes or of a particular theme + create create a new blog + ".$this->_create_usage_string()." - update activate a particular theme + update //TODO - delete print path to the theme's stylesheet - --dir get the path to the closest parent directory -EOB - ); + delete //TODO +"); } } \ No newline at end of file From 42ce8f2df47779bf6cac41128e6ffdd97620cc93 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Wed, 4 Apr 2012 16:46:52 -0600 Subject: [PATCH 0342/5359] Make wp blog arugments associative due to the number of optional params --- src/php/wp-cli/commands/internals/blog.php | 37 +++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index e1a2402d8..2c40dd352 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -10,11 +10,12 @@ */ class BlogCommand extends WP_CLI_Command { + //@TODO make associative due to optional params private function _create_usage_string() { - return "usage: wp blog create <domain-base> <title> [email] [site_id] [public=(1 or 0)]"; + return "usage: wp blog create --domain_base=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; } - private function get_site($site_id) { + private function _get_site($site_id) { global $wpdb; // Load site data $sites = $wpdb->get_results("SELECT * FROM $wpdb->site WHERE `id` = ".$site_id); @@ -26,7 +27,7 @@ private function get_site($site_id) { return false; } - public function create($args) { + public function create($args, $assoc_args) { if (!is_multisite()) { WP_CLI::line("ERROR: not a multisite instance"); exit; @@ -38,19 +39,20 @@ public function create($args) { // email optional // site optional // public optional - if (empty($args[0]) || empty($args[1])) { + error_log(print_r($assoc_args,1)); + if (empty($assoc_args['domain_base']) || empty($assoc_args['title'])) { WP_CLI::line($this->_create_usage_string()); exit; } - $base = $args[0]; - $title = $args[1]; - $email = empty($args[2]) ? '' : $args[2]; + $base = $assoc_args['domain_base']; + $title = $assoc_args['title']; + $email = empty($assoc_args['email']) ? '' : $assoc_args['email']; // Site - if (!empty($args[3])) { - $site = $this->get_site($args[3]); + if (!empty($assoc_args['site_id'])) { + $site = $this->_get_site($assoc_args['site_id']); if ($site === false) { - WP_CLI::line('ERROR: Site with id '.$args[3].'does not exist'); + WP_CLI::line('ERROR: Site with id '.$assoc_args['site_id'].'does not exist'); exit; } } @@ -58,8 +60,8 @@ public function create($args) { $site = wpmu_current_site(); } // Public - if (!empty($args[4])) { - $public = $args[4]; + if (!empty($assoc_args['public'])) { + $public = $args['public']; // Check for 1 or 0 if ($public != '1' && $public != '0') { $this->_create_usage(); @@ -148,16 +150,21 @@ public function update($args) {} public function delete($args) {} public function help() { - WP_CLI::line(" + WP_CLI::line(<<<EOB usage: wp blog <sub-command> [options] Available sub-commands: create create a new blog - ".$this->_create_usage_string()." + --domain_base Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs + --title Title of the new blog + [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included + [--site-id] Site to associate new blog with. Defaults to current site (typically 1) + [--public] Whether or not the new site is public (indexed) update //TODO delete //TODO -"); +EOB + ); } } \ No newline at end of file From be2f501026acad7fab791b08cc40168e978054ae Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Fri, 6 Apr 2012 15:22:43 -0600 Subject: [PATCH 0343/5359] Correct usage for site_id --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 2c40dd352..40e3b3435 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -158,7 +158,7 @@ public function help() { --domain_base Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs --title Title of the new blog [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included - [--site-id] Site to associate new blog with. Defaults to current site (typically 1) + [--site_id] Site to associate new blog with. Defaults to current site (typically 1) [--public] Whether or not the new site is public (indexed) update //TODO From 2d6c4eea8fa0ebd9d20040f5e96f755dc6d97a64 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Tue, 17 Apr 2012 15:05:31 -0600 Subject: [PATCH 0344/5359] Tweaks for sub directory install --- src/php/wp-cli/commands/internals/blog.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 40e3b3435..ac63abaee 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -39,7 +39,6 @@ public function create($args, $assoc_args) { // email optional // site optional // public optional - error_log(print_r($assoc_args,1)); if (empty($assoc_args['domain_base']) || empty($assoc_args['title'])) { WP_CLI::line($this->_create_usage_string()); exit; @@ -102,15 +101,18 @@ public function create($args, $assoc_args) { } } - if (is_subdomain_install()) { - $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); - $path = $site->path; - $url = $newdomain; + if (is_subdomain_install()) { + $path = '/'; + $url = $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); + } else { $newdomain = $site->domain; - $path = $site->domain.$site->path.$base.'/'; - $url = $path; + $path = $base; + if (strpos($path, '/') !== 0) { + $path = '/'.$path; + } + $url = $site->domain; } $password = 'N/A'; @@ -139,10 +141,10 @@ public function create($args, $assoc_args) { // wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); } else { - WP_CLI::line($id->get_error_message()); + WP_CLI::line('ERROR: '.$id->get_error_message()); exit; } - WP_CLI::line('Blog created with URL: '.$url); + WP_CLI::line('Blog created with URL: '.$url.' ID: '.$id); } public function update($args) {} From 4b52401f689d92c4edff4202ee932e8d8277fe6b Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Fri, 20 Apr 2012 15:18:37 -0600 Subject: [PATCH 0345/5359] Adjustments to output domain, url and Id --- src/php/wp-cli/commands/internals/blog.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index ac63abaee..7a374b05b 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -96,6 +96,8 @@ public function create($args, $assoc_args) { $super_login = $super_admins[0]; $super_user = get_user_by('login', $super_login); if ($super_user) { + error_log($super_user->user_email); + error_log($super_user->email); $email = $super_user->user_email; } } @@ -112,7 +114,7 @@ public function create($args, $assoc_args) { if (strpos($path, '/') !== 0) { $path = '/'.$path; } - $url = $site->domain; + $url = $site->domain.$path; } $password = 'N/A'; @@ -144,7 +146,7 @@ public function create($args, $assoc_args) { WP_CLI::line('ERROR: '.$id->get_error_message()); exit; } - WP_CLI::line('Blog created with URL: '.$url.' ID: '.$id); + WP_CLI::line('Blog created with DOMAIN: '.$site->domain.' URL: '.$url.' ID: '.$id); } public function update($args) {} From 54e8bfb9d56f3de15cd3923d92dc1288f8b9e2c0 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Mon, 30 Apr 2012 16:41:38 -0600 Subject: [PATCH 0346/5359] Cleanup of testing code, using built in error method to provide errors --- src/php/wp-cli/commands/internals/blog.php | 47 +++++++++++++--------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 7a374b05b..63a837f39 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -10,15 +10,20 @@ */ class BlogCommand extends WP_CLI_Command { - //@TODO make associative due to optional params private function _create_usage_string() { return "usage: wp blog create --domain_base=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; } + /** + * Get site (network) data for a given id + * + * @param int $site_id + * @return bool|array False if no network found with given id, array otherwise + */ private function _get_site($site_id) { global $wpdb; // Load site data - $sites = $wpdb->get_results("SELECT * FROM $wpdb->site WHERE `id` = ".$site_id); + $sites = $wpdb->get_results("SELECT * FROM $wpdb->site WHERE `id` = ".$wpdb->escape($site_id)); if (count($sites) > 0) { // Only care about domain and path which are set here return $sites[0]; @@ -27,9 +32,16 @@ private function _get_site($site_id) { return false; } + /** + * Create a blog via passed in arguments + * + * @see BlogCommand::help() + * @param array $args + * @param array $assoc_args + */ public function create($args, $assoc_args) { if (!is_multisite()) { - WP_CLI::line("ERROR: not a multisite instance"); + WP_CLI::error("Not a multisite instance"); exit; } global $wpdb; @@ -51,25 +63,27 @@ public function create($args, $assoc_args) { if (!empty($assoc_args['site_id'])) { $site = $this->_get_site($assoc_args['site_id']); if ($site === false) { - WP_CLI::line('ERROR: Site with id '.$assoc_args['site_id'].'does not exist'); + WP_CLI::error('Site with id '.$assoc_args['site_id'].' does not exist'); exit; } } else { $site = wpmu_current_site(); } - // Public + // Public, default is true (1) if (!empty($assoc_args['public'])) { $public = $args['public']; // Check for 1 or 0 if ($public != '1' && $public != '0') { $this->_create_usage(); + exit; } } else { $public = 1; } - + + // Sanitize if (preg_match( '|^([a-zA-Z0-9-])+$|', $base)) { $base = strtolower($base); } @@ -78,12 +92,11 @@ public function create($args, $assoc_args) { if (!is_subdomain_install()) { $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); if (in_array($domain, $subdirectory_reserved_names)) { - WP_CLI::line(sprintf(__('ERROR: The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); + WP_CLI::error(sprintf(__('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); exit; } } - // Check for valid email, if not, use the first Super Admin found // Probably a more efficient way to do this so we dont query for the // User twice if super admin @@ -96,8 +109,6 @@ public function create($args, $assoc_args) { $super_login = $super_admins[0]; $super_user = get_user_by('login', $super_login); if ($super_user) { - error_log($super_user->user_email); - error_log($super_user->email); $email = $super_user->user_email; } } @@ -106,7 +117,6 @@ public function create($args, $assoc_args) { if (is_subdomain_install()) { $path = '/'; $url = $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); - } else { $newdomain = $site->domain; @@ -123,7 +133,7 @@ public function create($args, $assoc_args) { $password = wp_generate_password(12, false); $user_id = wpmu_create_user($base, $password, $email); if (false == $user_id) { - WP_CLI::line('ERROR: There was an issue creating the user.'); + WP_CLI::error('There was an issue creating the user.'); exit; } else { @@ -138,15 +148,16 @@ public function create($args, $assoc_args) { if ( !is_super_admin($user_id) && !get_user_option('primary_blog', $user_id)) { update_user_option($user_id, 'primary_blog', $id, true); } -// $content_mail = sprintf(__( "New site created by WP Command Line Interface\n\nAddress: %2s\nName: %3s"), get_site_url($id), stripslashes($title)); - //@TODO Current site -// wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); + // Prevent mailing admins of new sites + // @TODO argument to pass in? + // $content_mail = sprintf(__( "New site created by WP Command Line Interface\n\nAddress: %2s\nName: %3s"), get_site_url($id), stripslashes($title)); + // wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); } else { - WP_CLI::line('ERROR: '.$id->get_error_message()); + WP_CLI::error($id->get_error_message()); exit; } - WP_CLI::line('Blog created with DOMAIN: '.$site->domain.' URL: '.$url.' ID: '.$id); + WP_CLI::line('Blog created with domain: '.$site->domain.' url: '.$url.' id: '.$id); } public function update($args) {} @@ -162,7 +173,7 @@ public function help() { --domain_base Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs --title Title of the new blog [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included - [--site_id] Site to associate new blog with. Defaults to current site (typically 1) + [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) [--public] Whether or not the new site is public (indexed) update //TODO From 5cbd7fcc759c85675729ceeb605063afd04c88a2 Mon Sep 17 00:00:00 2001 From: Evan Anderson <ejdanderson@gmail.com> Date: Mon, 30 Apr 2012 17:12:44 -0600 Subject: [PATCH 0347/5359] no need to exit when using error --- src/php/wp-cli/commands/internals/blog.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 63a837f39..100b34a6b 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -42,7 +42,6 @@ private function _get_site($site_id) { public function create($args, $assoc_args) { if (!is_multisite()) { WP_CLI::error("Not a multisite instance"); - exit; } global $wpdb; @@ -53,7 +52,7 @@ public function create($args, $assoc_args) { // public optional if (empty($assoc_args['domain_base']) || empty($assoc_args['title'])) { WP_CLI::line($this->_create_usage_string()); - exit; + exit(1); } $base = $assoc_args['domain_base']; @@ -64,7 +63,6 @@ public function create($args, $assoc_args) { $site = $this->_get_site($assoc_args['site_id']); if ($site === false) { WP_CLI::error('Site with id '.$assoc_args['site_id'].' does not exist'); - exit; } } else { @@ -93,7 +91,6 @@ public function create($args, $assoc_args) { $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); if (in_array($domain, $subdirectory_reserved_names)) { WP_CLI::error(sprintf(__('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); - exit; } } @@ -134,7 +131,6 @@ public function create($args, $assoc_args) { $user_id = wpmu_create_user($base, $password, $email); if (false == $user_id) { WP_CLI::error('There was an issue creating the user.'); - exit; } else { wp_new_user_notification($user_id, $password); @@ -155,7 +151,6 @@ public function create($args, $assoc_args) { } else { WP_CLI::error($id->get_error_message()); - exit; } WP_CLI::line('Blog created with domain: '.$site->domain.' url: '.$url.' id: '.$id); } From d776f58e60409c6cda1f90c92e0c8a87c6f632cb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 02:53:29 +0300 Subject: [PATCH 0348/5359] s/BlogCommand/Blog_Command/g --- src/php/wp-cli/commands/internals/blog.php | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 100b34a6b..f86e38ab7 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -1,6 +1,6 @@ <?php -WP_CLI::addCommand('blog', 'BlogCommand'); +WP_CLI::addCommand('blog', 'Blog_Command'); /** * Implement core command @@ -8,16 +8,16 @@ * @package wp-cli * @subpackage commands/internals */ -class BlogCommand extends WP_CLI_Command { - +class Blog_Command extends WP_CLI_Command { + private function _create_usage_string() { return "usage: wp blog create --domain_base=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; } - + /** * Get site (network) data for a given id * - * @param int $site_id + * @param int $site_id * @return bool|array False if no network found with given id, array otherwise */ private function _get_site($site_id) { @@ -28,23 +28,23 @@ private function _get_site($site_id) { // Only care about domain and path which are set here return $sites[0]; } - + return false; } - + /** * Create a blog via passed in arguments * * @see BlogCommand::help() - * @param array $args - * @param array $assoc_args + * @param array $args + * @param array $assoc_args */ public function create($args, $assoc_args) { if (!is_multisite()) { WP_CLI::error("Not a multisite instance"); } global $wpdb; - + // domain required // title required // email optional @@ -54,7 +54,7 @@ public function create($args, $assoc_args) { WP_CLI::line($this->_create_usage_string()); exit(1); } - + $base = $assoc_args['domain_base']; $title = $assoc_args['title']; $email = empty($assoc_args['email']) ? '' : $assoc_args['email']; @@ -80,12 +80,12 @@ public function create($args, $assoc_args) { else { $public = 1; } - + // Sanitize if (preg_match( '|^([a-zA-Z0-9-])+$|', $base)) { $base = strtolower($base); } - + // If not a subdomain install, make sure the domain isn't a reserved word if (!is_subdomain_install()) { $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); @@ -93,7 +93,7 @@ public function create($args, $assoc_args) { WP_CLI::error(sprintf(__('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); } } - + // Check for valid email, if not, use the first Super Admin found // Probably a more efficient way to do this so we dont query for the // User twice if super admin @@ -111,10 +111,10 @@ public function create($args, $assoc_args) { } } - if (is_subdomain_install()) { + if (is_subdomain_install()) { $path = '/'; $url = $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); - } + } else { $newdomain = $site->domain; $path = $base; @@ -123,7 +123,7 @@ public function create($args, $assoc_args) { } $url = $site->domain.$path; } - + $password = 'N/A'; $user_id = email_exists($email); if (!$user_id) { // Create a new user with a random password @@ -136,7 +136,7 @@ public function create($args, $assoc_args) { wp_new_user_notification($user_id, $password); } } - + $wpdb->hide_errors(); $id = wpmu_create_blog($newdomain, $path, $title, $user_id, array( 'public' => $public ), $site->id); $wpdb->show_errors(); @@ -148,17 +148,17 @@ public function create($args, $assoc_args) { // @TODO argument to pass in? // $content_mail = sprintf(__( "New site created by WP Command Line Interface\n\nAddress: %2s\nName: %3s"), get_site_url($id), stripslashes($title)); // wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); - } + } else { WP_CLI::error($id->get_error_message()); - } + } WP_CLI::line('Blog created with domain: '.$site->domain.' url: '.$url.' id: '.$id); } - + public function update($args) {} - + public function delete($args) {} - + public function help() { WP_CLI::line(<<<EOB usage: wp blog <sub-command> [options] @@ -177,4 +177,4 @@ public function help() { EOB ); } -} \ No newline at end of file +} From 8ec98c720c06e160b6b87319a9355b84b04e6c33 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 02:58:07 +0300 Subject: [PATCH 0349/5359] rename domain_base parameter to slug. see #104 --- src/php/wp-cli/commands/internals/blog.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index f86e38ab7..246ed88c0 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -11,7 +11,7 @@ class Blog_Command extends WP_CLI_Command { private function _create_usage_string() { - return "usage: wp blog create --domain_base=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; + return "usage: wp blog create --slug=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; } /** @@ -50,12 +50,12 @@ public function create($args, $assoc_args) { // email optional // site optional // public optional - if (empty($assoc_args['domain_base']) || empty($assoc_args['title'])) { + if (empty($assoc_args['slug']) || empty($assoc_args['title'])) { WP_CLI::line($this->_create_usage_string()); exit(1); } - $base = $assoc_args['domain_base']; + $base = $assoc_args['slug']; $title = $assoc_args['title']; $email = empty($assoc_args['email']) ? '' : $assoc_args['email']; // Site @@ -165,7 +165,7 @@ public function help() { Available sub-commands: create create a new blog - --domain_base Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs + --slug Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs --title Title of the new blog [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) From 67a987a1d4838581e6f957b929822080e0af110e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 03:03:14 +0300 Subject: [PATCH 0350/5359] use correct variable --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 246ed88c0..136d37bd8 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -89,7 +89,7 @@ public function create($args, $assoc_args) { // If not a subdomain install, make sure the domain isn't a reserved word if (!is_subdomain_install()) { $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); - if (in_array($domain, $subdirectory_reserved_names)) { + if (in_array($base, $subdirectory_reserved_names)) { WP_CLI::error(sprintf(__('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); } } From 4dc51211ca8e057d0767007d819c55c78a0f7ba8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 03:25:05 +0300 Subject: [PATCH 0351/5359] use WP_CLI::success() and make message more compact. see #104 --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 136d37bd8..6ff19c4fc 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -152,7 +152,7 @@ public function create($args, $assoc_args) { else { WP_CLI::error($id->get_error_message()); } - WP_CLI::line('Blog created with domain: '.$site->domain.' url: '.$url.' id: '.$id); + WP_CLI::success("Blog $id created: $url"); } public function update($args) {} From 7753240e2c210b1a7a97ff1e17f59627d5f3442d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 03:30:09 +0300 Subject: [PATCH 0352/5359] terser error message --- src/php/wp-cli/commands/internals/blog.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 6ff19c4fc..a666cb95a 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -124,13 +124,12 @@ public function create($args, $assoc_args) { $url = $site->domain.$path; } - $password = 'N/A'; $user_id = email_exists($email); if (!$user_id) { // Create a new user with a random password $password = wp_generate_password(12, false); $user_id = wpmu_create_user($base, $password, $email); if (false == $user_id) { - WP_CLI::error('There was an issue creating the user.'); + WP_CLI::error("Can't create user."); } else { wp_new_user_notification($user_id, $password); From 5d5e8ece9ec3a811773a72fdc47da712ce872859 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 03:38:30 +0300 Subject: [PATCH 0353/5359] always add trailing slash to path. see #104 --- src/php/wp-cli/commands/internals/blog.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index a666cb95a..6859dd579 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -117,11 +117,8 @@ public function create($args, $assoc_args) { } else { $newdomain = $site->domain; - $path = $base; - if (strpos($path, '/') !== 0) { - $path = '/'.$path; - } - $url = $site->domain.$path; + $path = '/' . trim( $base, '/' ) . '/'; + $url = $site->domain . $path; } $user_id = email_exists($email); From 6dcfd1580dcbd74842539c959593df7314b8fb92 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 17:55:10 +0300 Subject: [PATCH 0354/5359] disable placeholder commands so that they don't show up in the general help --- src/php/wp-cli/commands/internals/blog.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 6859dd579..b6f1b0a2a 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -151,9 +151,9 @@ public function create($args, $assoc_args) { WP_CLI::success("Blog $id created: $url"); } - public function update($args) {} + /* public function update($args) {} */ - public function delete($args) {} + /* public function delete($args) {} */ public function help() { WP_CLI::line(<<<EOB @@ -166,10 +166,6 @@ public function help() { [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) [--public] Whether or not the new site is public (indexed) - - update //TODO - - delete //TODO EOB ); } From c4e3999f3a0d55e863cbf0e5168f07366c5b8383 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 17:56:17 +0300 Subject: [PATCH 0355/5359] don't enable the blog command on non-multisite installs. see #104 --- src/php/wp-cli/commands/internals/blog.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index b6f1b0a2a..f9cf7ed6f 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -1,6 +1,8 @@ <?php -WP_CLI::addCommand('blog', 'Blog_Command'); +if ( is_multisite() ) { + WP_CLI::addCommand( 'blog', 'Blog_Command' ); +} /** * Implement core command @@ -40,9 +42,6 @@ private function _get_site($site_id) { * @param array $assoc_args */ public function create($args, $assoc_args) { - if (!is_multisite()) { - WP_CLI::error("Not a multisite instance"); - } global $wpdb; // domain required From ede7ca89a5d8af0825750c2fce99bd9fc4741190 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 17:58:27 +0300 Subject: [PATCH 0356/5359] use add_command() --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index f9cf7ed6f..7449e1b91 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -1,7 +1,7 @@ <?php if ( is_multisite() ) { - WP_CLI::addCommand( 'blog', 'Blog_Command' ); + WP_CLI::add_command( 'blog', 'Blog_Command' ); } /** From 87b2f215120832b56717548aa43ad1b1fadb3719 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 18:00:39 +0300 Subject: [PATCH 0357/5359] coding standards --- src/php/wp-cli/commands/internals/blog.php | 90 +++++++++++----------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 7449e1b91..8c88b31fc 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -19,14 +19,14 @@ private function _create_usage_string() { /** * Get site (network) data for a given id * - * @param int $site_id + * @param int $site_id * @return bool|array False if no network found with given id, array otherwise */ - private function _get_site($site_id) { + private function _get_site( $site_id ) { global $wpdb; // Load site data - $sites = $wpdb->get_results("SELECT * FROM $wpdb->site WHERE `id` = ".$wpdb->escape($site_id)); - if (count($sites) > 0) { + $sites = $wpdb->get_results( "SELECT * FROM $wpdb->site WHERE `id` = ".$wpdb->escape( $site_id ) ); + if ( count( $sites ) > 0 ) { // Only care about domain and path which are set here return $sites[0]; } @@ -38,10 +38,10 @@ private function _get_site($site_id) { * Create a blog via passed in arguments * * @see BlogCommand::help() - * @param array $args - * @param array $assoc_args + * @param array $args + * @param array $assoc_args */ - public function create($args, $assoc_args) { + public function create( $args, $assoc_args ) { global $wpdb; // domain required @@ -49,29 +49,29 @@ public function create($args, $assoc_args) { // email optional // site optional // public optional - if (empty($assoc_args['slug']) || empty($assoc_args['title'])) { - WP_CLI::line($this->_create_usage_string()); - exit(1); + if ( empty( $assoc_args['slug'] ) || empty( $assoc_args['title'] ) ) { + WP_CLI::line( $this->_create_usage_string() ); + exit( 1 ); } $base = $assoc_args['slug']; $title = $assoc_args['title']; - $email = empty($assoc_args['email']) ? '' : $assoc_args['email']; + $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; // Site - if (!empty($assoc_args['site_id'])) { - $site = $this->_get_site($assoc_args['site_id']); - if ($site === false) { - WP_CLI::error('Site with id '.$assoc_args['site_id'].' does not exist'); + if ( !empty( $assoc_args['site_id'] ) ) { + $site = $this->_get_site( $assoc_args['site_id'] ); + if ( $site === false ) { + WP_CLI::error( 'Site with id '.$assoc_args['site_id'].' does not exist' ); } } else { $site = wpmu_current_site(); } // Public, default is true (1) - if (!empty($assoc_args['public'])) { + if ( !empty( $assoc_args['public'] ) ) { $public = $args['public']; // Check for 1 or 0 - if ($public != '1' && $public != '0') { + if ( $public != '1' && $public != '0' ) { $this->_create_usage(); exit; } @@ -81,38 +81,38 @@ public function create($args, $assoc_args) { } // Sanitize - if (preg_match( '|^([a-zA-Z0-9-])+$|', $base)) { - $base = strtolower($base); + if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { + $base = strtolower( $base ); } // If not a subdomain install, make sure the domain isn't a reserved word - if (!is_subdomain_install()) { - $subdirectory_reserved_names = apply_filters('subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' )); - if (in_array($base, $subdirectory_reserved_names)) { - WP_CLI::error(sprintf(__('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>'), implode('</code>, <code>', $subdirectory_reserved_names))); + if ( !is_subdomain_install() ) { + $subdirectory_reserved_names = apply_filters( 'subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' ) ); + if ( in_array( $base, $subdirectory_reserved_names ) ) { + WP_CLI::error( sprintf( __( 'The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>' ), implode( '</code>, <code>', $subdirectory_reserved_names ) ) ); } } // Check for valid email, if not, use the first Super Admin found // Probably a more efficient way to do this so we dont query for the // User twice if super admin - $email = sanitize_email($email); - if (empty($email) || !is_email($email)) { + $email = sanitize_email( $email ); + if ( empty( $email ) || !is_email( $email ) ) { $super_admins = get_super_admins(); $email = ''; - if (!empty($super_admins) && is_array($super_admins)) { + if ( !empty( $super_admins ) && is_array( $super_admins ) ) { // Just get the first one $super_login = $super_admins[0]; - $super_user = get_user_by('login', $super_login); - if ($super_user) { + $super_user = get_user_by( 'login', $super_login ); + if ( $super_user ) { $email = $super_user->user_email; } } } - if (is_subdomain_install()) { + if ( is_subdomain_install() ) { $path = '/'; - $url = $newdomain = $base.'.'.preg_replace('|^www\.|', '', $site->domain); + $url = $newdomain = $base.'.'.preg_replace( '|^www\.|', '', $site->domain ); } else { $newdomain = $site->domain; @@ -120,24 +120,24 @@ public function create($args, $assoc_args) { $url = $site->domain . $path; } - $user_id = email_exists($email); - if (!$user_id) { // Create a new user with a random password - $password = wp_generate_password(12, false); - $user_id = wpmu_create_user($base, $password, $email); - if (false == $user_id) { - WP_CLI::error("Can't create user."); + $user_id = email_exists( $email ); + if ( !$user_id ) { // Create a new user with a random password + $password = wp_generate_password( 12, false ); + $user_id = wpmu_create_user( $base, $password, $email ); + if ( false == $user_id ) { + WP_CLI::error( "Can't create user." ); } else { - wp_new_user_notification($user_id, $password); + wp_new_user_notification( $user_id, $password ); } } $wpdb->hide_errors(); - $id = wpmu_create_blog($newdomain, $path, $title, $user_id, array( 'public' => $public ), $site->id); + $id = wpmu_create_blog( $newdomain, $path, $title, $user_id, array( 'public' => $public ), $site->id ); $wpdb->show_errors(); - if (!is_wp_error($id)) { - if ( !is_super_admin($user_id) && !get_user_option('primary_blog', $user_id)) { - update_user_option($user_id, 'primary_blog', $id, true); + if ( !is_wp_error( $id ) ) { + if ( !is_super_admin( $user_id ) && !get_user_option( 'primary_blog', $user_id ) ) { + update_user_option( $user_id, 'primary_blog', $id, true ); } // Prevent mailing admins of new sites // @TODO argument to pass in? @@ -145,9 +145,9 @@ public function create($args, $assoc_args) { // wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); } else { - WP_CLI::error($id->get_error_message()); + WP_CLI::error( $id->get_error_message() ); } - WP_CLI::success("Blog $id created: $url"); + WP_CLI::success( "Blog $id created: $url" ); } /* public function update($args) {} */ @@ -155,7 +155,7 @@ public function create($args, $assoc_args) { /* public function delete($args) {} */ public function help() { - WP_CLI::line(<<<EOB + WP_CLI::line( <<<EOB usage: wp blog <sub-command> [options] Available sub-commands: @@ -166,6 +166,6 @@ public function help() { [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) [--public] Whether or not the new site is public (indexed) EOB - ); + ); } } From c6b8ca54a3f40913140f8723062079fb0203323d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 18:05:32 +0300 Subject: [PATCH 0358/5359] more appropriate error message for reserved blog names --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 8c88b31fc..627e87a39 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -89,7 +89,7 @@ public function create( $args, $assoc_args ) { if ( !is_subdomain_install() ) { $subdirectory_reserved_names = apply_filters( 'subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' ) ); if ( in_array( $base, $subdirectory_reserved_names ) ) { - WP_CLI::error( sprintf( __( 'The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>' ), implode( '</code>, <code>', $subdirectory_reserved_names ) ) ); + WP_CLI::error( 'The following words are reserved and cannot be used as blog names: ' . implode( ', ', $subdirectory_reserved_names ) ); } } From 7e504c4335f46f2444448d81d36df562a7eb9f8a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 18:14:14 +0300 Subject: [PATCH 0359/5359] export: exit with an error status when not all required parameters are set --- src/php/wp-cli/commands/internals/export.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 6c6e15cdd..d24b13da5 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -60,8 +60,8 @@ public function validate_arguments( $args, $assoc_args ) { } } - if ( true === $has_errors ) { - exit; + if ( $has_errors ) { + exit(1); } $this->wxr_path = $assoc_args['path']; @@ -79,7 +79,6 @@ private function check_path( $path ) { if ( !is_dir( $path ) ) { WP_CLI::error( sprintf( "The path %s does not exist", $path ) ); - exit; } return true; From 3d50bbf12227d886d41da5c5f39c1ee4e8264309 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 18:14:49 +0300 Subject: [PATCH 0360/5359] show missing parameters instead of just usage string --- src/php/wp-cli/commands/internals/blog.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 627e87a39..3d50ee1d1 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -44,16 +44,18 @@ private function _get_site( $site_id ) { public function create( $args, $assoc_args ) { global $wpdb; - // domain required - // title required - // email optional - // site optional - // public optional - if ( empty( $assoc_args['slug'] ) || empty( $assoc_args['title'] ) ) { - WP_CLI::line( $this->_create_usage_string() ); - exit( 1 ); + $has_errors = false; + + foreach ( array( 'slug', 'title' ) as $required ) { + if ( empty( $assoc_args[$required] ) ) { + WP_CLI::warning( "missing --$required parameter" ); + $has_errors = true; + } } + if ( $has_errors ) + exit(1); + $base = $assoc_args['slug']; $title = $assoc_args['title']; $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; From 4936d5ce36f0fdf6ea0f74497bccc79c35b8c822 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 21:44:35 +0300 Subject: [PATCH 0361/5359] look for {command}.md files for help info --- src/doc/general.md | 9 ++++ src/php/wp-cli/class-wp-cli.php | 10 +++- src/php/wp-cli/commands/internals/help.php | 53 ++++++++++++---------- 3 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 src/doc/general.md diff --git a/src/doc/general.md b/src/doc/general.md new file mode 100644 index 000000000..7a7fbfbd7 --- /dev/null +++ b/src/doc/general.md @@ -0,0 +1,9 @@ + +See 'wp help <command>' for more information on a specific command. + +Global parameters: + --user=<id|login> set the current user + --url=<url> set the current URL + --path=<path> set the current path to the WP install + --require=<path> load a certain file before running the command + --version print wp-cli version diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 656e94ce9..79bbecb49 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -278,8 +278,16 @@ private function load_command( $command ) { } } + static function get_path( $which ) { + switch ( $which ) { + case 'doc': + // TODO: pear config-get doc_dir + return WP_CLI_ROOT . "../../doc/"; + } + } + // back-compat - public function addCommand( $name, $class ) { + static function addCommand( $name, $class ) { self::add_command( $name, $class ); } } diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 98b6d1580..2453240c3 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -18,27 +18,37 @@ class Help_Command extends WP_CLI_Command { public function __construct( $args ) { if ( empty( $args ) ) { $this->general_help(); - } else { - $command = $args[0]; - - if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::error( "'$command' is not a registered wp command." ); - } elseif ( 'help' == $command ) { - // prevent endless loop - $this->general_help(); + return; + } + + $command = $args[0]; + + if ( !isset( WP_CLI::$commands[$command] ) ) + WP_CLI::error( "'$command' is not a registered wp command." ); + + if ( !$this->show_help( $command ) ) { + $class = WP_CLI::$commands[$command]; + + if ( method_exists( $class, 'help' ) ) { + $class::help(); } else { - $class = WP_CLI::$commands[$command]; - - if ( method_exists( $class, 'help' ) ) { - $class::help(); - } else { - WP_CLI::line( 'Example usage:' ); - $this->single_command_help( $command, $class ); - } + WP_CLI::line( 'Example usage:' ); + $this->single_command_help( $command, $class ); } } } + private function show_help( $command ) { + $doc_file = WP_CLI::get_path( 'doc' ) . "$command.md"; + + if ( !is_readable( $doc_file ) ) + return false; + + echo file_get_contents( $doc_file ); + + return true; + } + private function general_help() { WP_CLI::line( 'Available commands:' ); foreach ( WP_CLI::$commands as $name => $command ) { @@ -47,15 +57,8 @@ private function general_help() { $this->single_command_help( $name, $command ); } - WP_CLI::line(); - WP_CLI::line( "See 'wp help <command>' for more information on a specific command." ); - WP_CLI::line(); - WP_CLI::line( 'Global parameters:' ); - WP_CLI::line( ' --user=<id|login> set the current user' ); - WP_CLI::line( ' --url=<url> set the current URL' ); - WP_CLI::line( ' --path=<path> set the current path to the WP install' ); - WP_CLI::line( ' --require=<path> load a certain file before running the command' ); - WP_CLI::line( ' --version print wp-cli version' ); + + $this->show_help( 'general' ); } private function single_command_help( $name, $command ) { From 15c2ac739a175040df9377d877383a1c0cafee11 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 19:43:42 +0300 Subject: [PATCH 0362/5359] move help text to doc dir for internal commands --- src/doc/blog.md | 9 +++++ src/doc/core.md | 5 +++ src/doc/db.md | 14 ++++++++ src/doc/eval-file.md | 3 ++ src/doc/eval.md | 3 ++ src/doc/export.md | 14 ++++++++ src/doc/generate.md | 2 ++ src/doc/home.md | 3 ++ src/doc/option.md | 4 +++ src/doc/plugin.md | 27 ++++++++++++++ src/doc/theme.md | 18 ++++++++++ src/doc/transient.md | 4 +++ src/doc/user.md | 4 +++ src/php/wp-cli/commands/internals/blog.php | 19 ---------- src/php/wp-cli/commands/internals/core.php | 14 -------- src/php/wp-cli/commands/internals/db.php | 23 ------------ .../wp-cli/commands/internals/eval-file.php | 12 ------- src/php/wp-cli/commands/internals/eval.php | 12 ------- src/php/wp-cli/commands/internals/export.php | 23 ------------ .../wp-cli/commands/internals/generate.php | 11 ------ src/php/wp-cli/commands/internals/home.php | 12 ------- src/php/wp-cli/commands/internals/option.php | 15 +------- src/php/wp-cli/commands/internals/plugin.php | 36 ------------------- src/php/wp-cli/commands/internals/theme.php | 27 -------------- .../wp-cli/commands/internals/transient.php | 19 ++-------- src/php/wp-cli/commands/internals/user.php | 13 ------- 26 files changed, 114 insertions(+), 232 deletions(-) create mode 100644 src/doc/blog.md create mode 100644 src/doc/core.md create mode 100644 src/doc/db.md create mode 100644 src/doc/eval-file.md create mode 100644 src/doc/eval.md create mode 100644 src/doc/export.md create mode 100644 src/doc/generate.md create mode 100644 src/doc/home.md create mode 100644 src/doc/option.md create mode 100644 src/doc/plugin.md create mode 100644 src/doc/theme.md create mode 100644 src/doc/transient.md create mode 100644 src/doc/user.md diff --git a/src/doc/blog.md b/src/doc/blog.md new file mode 100644 index 000000000..15ceea00f --- /dev/null +++ b/src/doc/blog.md @@ -0,0 +1,9 @@ +usage: wp blog <sub-command> [options] + +Available sub-commands: + create create a new blog + --slug Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs + --title Title of the new blog + [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included + [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) + [--public] Whether or not the new site is public (indexed) diff --git a/src/doc/core.md b/src/doc/core.md new file mode 100644 index 000000000..eddc818af --- /dev/null +++ b/src/doc/core.md @@ -0,0 +1,5 @@ +usage: wp core update + or: wp core version [--extra] + or: wp core download [--version=1.2.3] + or: wp core config --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=localhost] [--dbprefix=wp_] + or: wp core install --site_url=example.com --site_title=<site-title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email-address> diff --git a/src/doc/db.md b/src/doc/db.md new file mode 100644 index 000000000..e318225e4 --- /dev/null +++ b/src/doc/db.md @@ -0,0 +1,14 @@ +usage: wp db <sub-command> [<file>] + +Available sub-commands: + cli Open a SQL command-line interface using the WordPress credentials. + + connect Print a string for connecting to the database. + + export Export the WordPress database using mysqldump. + + import Import a database exported via mysqldump. + + query Execute a query against the WordPress database. + + create Create a database using the info from wp-config.php. diff --git a/src/doc/eval-file.md b/src/doc/eval-file.md new file mode 100644 index 000000000..c626a9353 --- /dev/null +++ b/src/doc/eval-file.md @@ -0,0 +1,3 @@ +example: wp eval-file some-file.php + +Loads and executes a PHP file after bootstrapping WordPress. diff --git a/src/doc/eval.md b/src/doc/eval.md new file mode 100644 index 000000000..1005333a6 --- /dev/null +++ b/src/doc/eval.md @@ -0,0 +1,3 @@ +example: wp eval 'echo WP_CONTENT_DIR;' + +Executes arbitrary PHP code after bootstrapping WordPress. diff --git a/src/doc/export.md b/src/doc/export.md new file mode 100644 index 000000000..ea644d862 --- /dev/null +++ b/src/doc/export.md @@ -0,0 +1,14 @@ +usage: wp export --path=<export-path> --user=<username/id> + or: wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + +Required parameters: + --path Full Path to directory where WXR export files should be stored + +Optional filters: + --start_date Export only posts new than this date in format YYYY-MM-DD + --end_date Export only posts older than this date in format YYYY-MM-DD + --post_type Export only posts with this post_type + --author Export only posts by this author + --category Export only posts in this category + --post_status Export only posts with this post_status + --skip_comments Don't export comments diff --git a/src/doc/generate.md b/src/doc/generate.md new file mode 100644 index 000000000..8b2364fb2 --- /dev/null +++ b/src/doc/generate.md @@ -0,0 +1,2 @@ +usage: wp generate posts [--count=100] [--type=post] [--status=publish] [--author=<login>] + or: wp generate users [--count=100] [--role=<role>] diff --git a/src/doc/home.md b/src/doc/home.md new file mode 100644 index 000000000..5abbdf995 --- /dev/null +++ b/src/doc/home.md @@ -0,0 +1,3 @@ +usage: wp home + +Opens the wp-cli homepage in your browser. diff --git a/src/doc/option.md b/src/doc/option.md new file mode 100644 index 000000000..2985f7b7f --- /dev/null +++ b/src/doc/option.md @@ -0,0 +1,4 @@ +usage: wp option get <option-name> + or: wp option add <option-name> <option-value> + or: wp option update <option-name> <option-value> + or: wp option delete <option-name> diff --git a/src/doc/plugin.md b/src/doc/plugin.md new file mode 100644 index 000000000..6903e1290 --- /dev/null +++ b/src/doc/plugin.md @@ -0,0 +1,27 @@ +usage: wp plugin <sub-command> [<plugin-name>] + or: wp plugin path [<plugin-name>] [--dir] + or: wp plugin install <plugin-name> [--activate] [--dev] [--version=1.2.3] + +Available sub-commands: + status display status of all installed plugins or of a particular plugin + + activate activate a particular plugin + + deactivate deactivate a particular plugin + + toggle toggle activation state of a particular plugin + + path print path to the plugin's file + --dir get the path to the closest parent directory + + install install a plugin from wordpress.org or from a zip file + --activate activate the plugin after installing it + --dev install the development version + --version install a specific version + + update update a plugin from wordpress.org + --all update all plugins from wordpress.org + + uninstall run the uninstallation procedure for a plugin + + delete delete a plugin diff --git a/src/doc/theme.md b/src/doc/theme.md new file mode 100644 index 000000000..094d7be4a --- /dev/null +++ b/src/doc/theme.md @@ -0,0 +1,18 @@ +usage: wp theme <sub-command> [<theme-name>] + or: wp theme path [<theme-name>] [--dir] + +Available sub-commands: + status display status of all installed themes or of a particular theme + + activate activate a particular theme + + path print path to the theme's stylesheet + --dir get the path to the closest parent directory + + install install a theme from wordpress.org or from a zip file + --activate activate the theme after installing it + + update update a theme from wordpress.org + --all update all themes from wordpress.org + + delete delete a theme diff --git a/src/doc/transient.md b/src/doc/transient.md new file mode 100644 index 000000000..440f67f49 --- /dev/null +++ b/src/doc/transient.md @@ -0,0 +1,4 @@ +usage: wp transient get <key> + or: wp transient set <key> <value> [expiration] + or: wp transient delete <key> + or: wp transient type diff --git a/src/doc/user.md b/src/doc/user.md new file mode 100644 index 000000000..ce3f19c5f --- /dev/null +++ b/src/doc/user.md @@ -0,0 +1,4 @@ +usage: wp user list [--role=<role>] + or: wp user create <user_login> <user_email> [--role=<default_role>] + or: wp user update <ID> [--field_name=<field_value>] + or: wp user delete <ID> [--reassign=<reassign_id>] diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 3d50ee1d1..ed94c7841 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -151,23 +151,4 @@ public function create( $args, $assoc_args ) { } WP_CLI::success( "Blog $id created: $url" ); } - - /* public function update($args) {} */ - - /* public function delete($args) {} */ - - public function help() { - WP_CLI::line( <<<EOB -usage: wp blog <sub-command> [options] - -Available sub-commands: - create create a new blog - --slug Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs - --title Title of the new blog - [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included - [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) - [--public] Whether or not the new site is public (indexed) -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 5fa81ed09..e1764c050 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -162,19 +162,5 @@ function update( $args ) { WP_CLI::success('WordPress updated successfully.'); } } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp core update - or: wp core version [--extra] - or: wp core download [--version=1.2.3] - or: wp core config --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=localhost] [--dbprefix=wp_] - or: wp core install --site_url=example.com --site_title=<site-title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email-address> -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 448a933f7..3687a1d77 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -96,27 +96,4 @@ private function get_file_name( $args ) { return $args[0]; } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp db <sub-command> [<file>] - -Available sub-commands: - cli Open a SQL command-line interface using the WordPress credentials. - - connect Print a string for connecting to the database. - - export Export the WordPress database using mysqldump. - - import Import a database exported via mysqldump. - - query Execute a query against the WordPress database. - - create Create a database using the info from wp-config.php. -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/internals/eval-file.php index 9626ab1b5..006f5dc00 100644 --- a/src/php/wp-cli/commands/internals/eval-file.php +++ b/src/php/wp-cli/commands/internals/eval-file.php @@ -30,16 +30,4 @@ public function __construct( $args, $assoc_args ) { } } } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -example: wp eval-file some-file.php - -Loads and executes a PHP file after bootstrapping WordPress. -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/internals/eval.php index fd0e737fe..0915224bc 100644 --- a/src/php/wp-cli/commands/internals/eval.php +++ b/src/php/wp-cli/commands/internals/eval.php @@ -24,16 +24,4 @@ public function __construct( $args, $assoc_args ) { eval( $args[0] ); } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -example: wp eval 'echo WP_CONTENT_DIR;' - -Executes arbitrary PHP code after bootstrapping WordPress. -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index d24b13da5..555a29d38 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -9,29 +9,6 @@ * @subpackage commands/internals */ class Export_Command extends WP_CLI_Command { - protected $default_subcommand = 'validate_arguments'; - - public $export_args = array(); - - public static function help() { - WP_CLI::line( <<<EOB -usage: wp export --path=<export-path> --user=<username/id> - or: wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 - -Required parameters: - --path Full Path to directory where WXR export files should be stored - -Optional filters: - --start_date Export only posts new than this date in format YYYY-MM-DD - --end_date Export only posts older than this date in format YYYY-MM-DD - --post_type Export only posts with this post_type - --author Export only posts by this author - --category Export only posts in this category - --post_status Export only posts with this post_status - --skip_comments Don't export comments -EOB - ); - } /** * Argument validation functions below diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 2d40fbdbe..c4bddf222 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -116,15 +116,4 @@ public function users( $args, $assoc_args ) { $notify->finish(); } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp generate posts [--count=100] [--type=post] [--status=publish] [--author=<login>] - or: wp generate users [--count=100] [--role=<role>] -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index c16bf6f42..ce8efce9f 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -34,16 +34,4 @@ public function __construct( $args, $assoc_args ) { WP_CLI::success('The wp-cli homepage should be opening in your browser.'); } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp home - -Opens the wp-cli homepage in your browser. -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 5e4b20f04..79825b4b2 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -91,17 +91,4 @@ public function get( $args ) { echo $value . "\n"; } } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp option get <option-name> - or: wp option add <option-name> <option-value> - or: wp option update <option-name> <option-value> - or: wp option delete <option-name> -EOB - ); - } -} \ No newline at end of file +} diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index bd051ba55..5877e9b98 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -307,40 +307,4 @@ protected function parse_name( $args, $subcommand ) { return array( $file, $name ); } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp plugin <sub-command> [<plugin-name>] - or: wp plugin path [<plugin-name>] [--dir] - or: wp plugin install <plugin-name> [--activate] [--dev] [--version=1.2.3] - -Available sub-commands: - status display status of all installed plugins or of a particular plugin - - activate activate a particular plugin - - deactivate deactivate a particular plugin - - toggle toggle activation state of a particular plugin - - path print path to the plugin's file - --dir get the path to the closest parent directory - - install install a plugin from wordpress.org or from a zip file - --activate activate the plugin after installing it - --dev install the development version - --version install a specific version - - update update a plugin from wordpress.org - --all update all plugins from wordpress.org - - uninstall run the uninstallation procedure for a plugin - - delete delete a plugin -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index fe9fb4d5d..8313d8d44 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -199,31 +199,4 @@ protected function parse_name( $args, $subcommand ) { protected function get_stylesheet_path( $theme ) { return WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp theme <sub-command> [<theme-name>] - or: wp theme path [<theme-name>] [--dir] - -Available sub-commands: - status display status of all installed themes or of a particular theme - - activate activate a particular theme - - path print path to the theme's stylesheet - --dir get the path to the closest parent directory - - install install a theme from wordpress.org or from a zip file - --activate activate the theme after installing it - - update update a theme from wordpress.org - --all update all themes from wordpress.org - - delete delete a theme -EOB - ); - } } diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php index 86a373e37..9d8236894 100644 --- a/src/php/wp-cli/commands/internals/transient.php +++ b/src/php/wp-cli/commands/internals/transient.php @@ -29,7 +29,7 @@ public function get( $args ) { WP_CLI::warning( 'Transient with key "' . $key . '" is not set.' ); exit; } - + if ( is_array( $value ) || is_object( $value ) ) echo var_export( $value ) . "\n"; else @@ -86,24 +86,11 @@ public function delete( $args ) { public function type() { global $_wp_using_ext_object_cache, $wpdb; - if ( $_wp_using_ext_object_cache ) + if ( $_wp_using_ext_object_cache ) $message = 'Transients are saved to the object cache.'; else $message = 'Transients are saved to the ' . $wpdb->prefix . 'options table.'; WP_CLI::line( $message ); } - - /** - * Displays the help message. - */ - static function help() { - WP_CLI::line( <<<EOB -usage: wp transient get <key> - or: wp transient set <key> <value> [expiration] - or: wp transient delete <key> - or: wp transient type -EOB - ); - } -} \ No newline at end of file +} diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index f9fd30a00..7515979d4 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -156,17 +156,4 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp user list [--role=<role>] - or: wp user create <user_login> <user_email> [--role=<default_role>] - or: wp user update <ID> [--field_name=<field_value>] - or: wp user delete <ID> [--reassign=<reassign_id>] -EOB - ); - } } From 19e195f4bc9890e34d81c13ffb191828522e5552 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 22:40:08 +0300 Subject: [PATCH 0363/5359] convert blog.md to ronn format --- src/doc/blog.md | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/doc/blog.md b/src/doc/blog.md index 15ceea00f..5fc9e3ccf 100644 --- a/src/doc/blog.md +++ b/src/doc/blog.md @@ -1,9 +1,28 @@ -usage: wp blog <sub-command> [options] - -Available sub-commands: - create create a new blog - --slug Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs - --title Title of the new blog - [--email] Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included - [--site_id] Site (network) to associate new blog with. Defaults to current site (typically 1) - [--public] Whether or not the new site is public (indexed) +wp-blog-create(1) -- Create a new blog in a multisite install. +==== + +## SYNOPSIS + +`wp blog create` --slug=<slug> --title=<Title> + +## OPTIONS + +* `--slug`=<slug>: + + Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs. + +* `--title`=<title>: + + Title of the new blog. + +* `--email`=<email>: + + Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. + +* `--site_id`=<site-id>: + + Site (network) to associate new blog with. Defaults to current site (typically 1). + +* `--public`: + + Whether or not the new site is public (indexed). From 511085317e86bd1c373755db9d3e8ebcdbae6b8c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 22:58:49 +0300 Subject: [PATCH 0364/5359] move blog.md to blog-create.md --- src/doc/{blog.md => blog-create.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/doc/{blog.md => blog-create.md} (100%) diff --git a/src/doc/blog.md b/src/doc/blog-create.md similarity index 100% rename from src/doc/blog.md rename to src/doc/blog-create.md From f4da7c6ad8cae1627ec7e8ccd841323cebf68232 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:01:28 +0300 Subject: [PATCH 0365/5359] fix encoding issue in blog-create.md --- src/doc/blog-create.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/blog-create.md b/src/doc/blog-create.md index 5fc9e3ccf..c19c96639 100644 --- a/src/doc/blog-create.md +++ b/src/doc/blog-create.md @@ -11,7 +11,7 @@ wp-blog-create(1) -- Create a new blog in a multisite install. Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs. -* `--title`=<title>: +* `--title`=<title>: Title of the new blog. From dc9877fc57c9b57900a7133dda83bfe85ac8d2c5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:03:30 +0300 Subject: [PATCH 0366/5359] add optional parameters to synopsis in blog-create.md --- src/doc/blog-create.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/blog-create.md b/src/doc/blog-create.md index c19c96639..fc4710e18 100644 --- a/src/doc/blog-create.md +++ b/src/doc/blog-create.md @@ -3,7 +3,7 @@ wp-blog-create(1) -- Create a new blog in a multisite install. ## SYNOPSIS -`wp blog create` --slug=<slug> --title=<Title> +`wp blog create` --slug=<slug> --title=<Title> [--email=<email>] [--site_id=<site-id>] [--public=true] ## OPTIONS From 0e9fe2ca3dbd86fee8ecf6fc16eff7ebb45bf20a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:16:48 +0300 Subject: [PATCH 0367/5359] look for nested doc files --- src/php/wp-cli/commands/internals/help.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 2453240c3..5d94cf7f5 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -26,11 +26,11 @@ public function __construct( $args ) { if ( !isset( WP_CLI::$commands[$command] ) ) WP_CLI::error( "'$command' is not a registered wp command." ); - if ( !$this->show_help( $command ) ) { + if ( !$this->show_help( $args ) ) { $class = WP_CLI::$commands[$command]; if ( method_exists( $class, 'help' ) ) { - $class::help(); + $class::help( $subcommand ); } else { WP_CLI::line( 'Example usage:' ); $this->single_command_help( $command, $class ); @@ -38,8 +38,8 @@ public function __construct( $args ) { } } - private function show_help( $command ) { - $doc_file = WP_CLI::get_path( 'doc' ) . "$command.md"; + private function show_help( $args ) { + $doc_file = WP_CLI::get_path( 'doc' ) . implode( '-', $args ) . '.md'; if ( !is_readable( $doc_file ) ) return false; From b4cd34da3272af54e293507cac28f21046a93838 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:47:15 +0300 Subject: [PATCH 0368/5359] change doc extension from .md to .txt --- src/doc/{blog-create.md => blog-create.txt} | 0 src/doc/{core.md => core.txt} | 0 src/doc/{db.md => db.txt} | 0 src/doc/{eval-file.md => eval-file.txt} | 0 src/doc/{eval.md => eval.txt} | 0 src/doc/{export.md => export.txt} | 0 src/doc/{general.md => general.txt} | 0 src/doc/{generate.md => generate.txt} | 0 src/doc/{home.md => home.txt} | 0 src/doc/{option.md => option.txt} | 0 src/doc/{plugin.md => plugin.txt} | 0 src/doc/{theme.md => theme.txt} | 0 src/doc/{transient.md => transient.txt} | 0 src/doc/{user.md => user.txt} | 0 src/php/wp-cli/commands/internals/help.php | 2 +- 15 files changed, 1 insertion(+), 1 deletion(-) rename src/doc/{blog-create.md => blog-create.txt} (100%) rename src/doc/{core.md => core.txt} (100%) rename src/doc/{db.md => db.txt} (100%) rename src/doc/{eval-file.md => eval-file.txt} (100%) rename src/doc/{eval.md => eval.txt} (100%) rename src/doc/{export.md => export.txt} (100%) rename src/doc/{general.md => general.txt} (100%) rename src/doc/{generate.md => generate.txt} (100%) rename src/doc/{home.md => home.txt} (100%) rename src/doc/{option.md => option.txt} (100%) rename src/doc/{plugin.md => plugin.txt} (100%) rename src/doc/{theme.md => theme.txt} (100%) rename src/doc/{transient.md => transient.txt} (100%) rename src/doc/{user.md => user.txt} (100%) diff --git a/src/doc/blog-create.md b/src/doc/blog-create.txt similarity index 100% rename from src/doc/blog-create.md rename to src/doc/blog-create.txt diff --git a/src/doc/core.md b/src/doc/core.txt similarity index 100% rename from src/doc/core.md rename to src/doc/core.txt diff --git a/src/doc/db.md b/src/doc/db.txt similarity index 100% rename from src/doc/db.md rename to src/doc/db.txt diff --git a/src/doc/eval-file.md b/src/doc/eval-file.txt similarity index 100% rename from src/doc/eval-file.md rename to src/doc/eval-file.txt diff --git a/src/doc/eval.md b/src/doc/eval.txt similarity index 100% rename from src/doc/eval.md rename to src/doc/eval.txt diff --git a/src/doc/export.md b/src/doc/export.txt similarity index 100% rename from src/doc/export.md rename to src/doc/export.txt diff --git a/src/doc/general.md b/src/doc/general.txt similarity index 100% rename from src/doc/general.md rename to src/doc/general.txt diff --git a/src/doc/generate.md b/src/doc/generate.txt similarity index 100% rename from src/doc/generate.md rename to src/doc/generate.txt diff --git a/src/doc/home.md b/src/doc/home.txt similarity index 100% rename from src/doc/home.md rename to src/doc/home.txt diff --git a/src/doc/option.md b/src/doc/option.txt similarity index 100% rename from src/doc/option.md rename to src/doc/option.txt diff --git a/src/doc/plugin.md b/src/doc/plugin.txt similarity index 100% rename from src/doc/plugin.md rename to src/doc/plugin.txt diff --git a/src/doc/theme.md b/src/doc/theme.txt similarity index 100% rename from src/doc/theme.md rename to src/doc/theme.txt diff --git a/src/doc/transient.md b/src/doc/transient.txt similarity index 100% rename from src/doc/transient.md rename to src/doc/transient.txt diff --git a/src/doc/user.md b/src/doc/user.txt similarity index 100% rename from src/doc/user.md rename to src/doc/user.txt diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 5d94cf7f5..52df87369 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -39,7 +39,7 @@ public function __construct( $args ) { } private function show_help( $args ) { - $doc_file = WP_CLI::get_path( 'doc' ) . implode( '-', $args ) . '.md'; + $doc_file = WP_CLI::get_path( 'doc' ) . implode( '-', $args ) . '.txt'; if ( !is_readable( $doc_file ) ) return false; From be1c437bce7d78552d3ff4ffaeb31f8c132dba48 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:49:46 +0300 Subject: [PATCH 0369/5359] replace --public with --private. see #104 --- src/php/wp-cli/commands/internals/blog.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index ed94c7841..b1efc2ce3 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -13,7 +13,7 @@ class Blog_Command extends WP_CLI_Command { private function _create_usage_string() { - return "usage: wp blog create --slug=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--public]"; + return "usage: wp blog create --slug=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--private]"; } /** @@ -69,18 +69,8 @@ public function create( $args, $assoc_args ) { else { $site = wpmu_current_site(); } - // Public, default is true (1) - if ( !empty( $assoc_args['public'] ) ) { - $public = $args['public']; - // Check for 1 or 0 - if ( $public != '1' && $public != '0' ) { - $this->_create_usage(); - exit; - } - } - else { - $public = 1; - } + + $public = isset( $assoc_args['private'] ) ? 0 : 1; // Sanitize if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { From 3398b956a239a745b47722e1a6c2caabaa801bab Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 May 2012 23:53:39 +0300 Subject: [PATCH 0370/5359] update blog-create.txt --- src/doc/blog-create.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/blog-create.txt b/src/doc/blog-create.txt index fc4710e18..991e19caf 100644 --- a/src/doc/blog-create.txt +++ b/src/doc/blog-create.txt @@ -23,6 +23,6 @@ wp-blog-create(1) -- Create a new blog in a multisite install. Site (network) to associate new blog with. Defaults to current site (typically 1). -* `--public`: +* `--private`: - Whether or not the new site is public (indexed). + If set, the new blog will be non-public (not indexed) From e751d0ce423d85cbaebff072d554cf33022df116 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 00:07:38 +0300 Subject: [PATCH 0371/5359] add build-doc script --- .gitignore | 1 + utils/build-doc | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100755 utils/build-doc diff --git a/.gitignore b/.gitignore index d9cdde38e..472657eea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.build /dist +/man diff --git a/utils/build-doc b/utils/build-doc new file mode 100755 index 000000000..9b8866e41 --- /dev/null +++ b/utils/build-doc @@ -0,0 +1,9 @@ +#!/bin/bash + +# generate man pages + +mkdir -p man + +for file in $(ls src/doc/*.txt); do + cat $file | ronn --roff --manual="WP-CLI" > man/$(basename $file .txt).1 +done From b3494ae07cd97c11798562fe586288a451ab391e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 00:30:34 +0300 Subject: [PATCH 0372/5359] use generated man file --- src/php/wp-cli/class-wp-cli.php | 17 +++++++++-------- src/php/wp-cli/commands/internals/db.php | 2 +- src/php/wp-cli/commands/internals/help.php | 10 +++++++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 79bbecb49..1185314f8 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -148,6 +148,15 @@ static function legend( $legend ) { WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } + /** + * Launch an external process, closing the current one + * + * @param string Command to call + */ + static function launch( $command ) { + proc_close( proc_open( $command, array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); + } + /** * Sets the appropriate $_SERVER keys based on a given string * @@ -278,14 +287,6 @@ private function load_command( $command ) { } } - static function get_path( $which ) { - switch ( $which ) { - case 'doc': - // TODO: pear config-get doc_dir - return WP_CLI_ROOT . "../../doc/"; - } - } - // back-compat static function addCommand( $name, $class ) { self::add_command( $name, $class ); diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 3687a1d77..77e631ee1 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -33,7 +33,7 @@ function connect() { * Open a SQL command-line interface using WordPress's credentials. */ function cli() { - proc_close( proc_open( $this->connect_string() , array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); + WP_CLI::launch( $this->connect_string() ); } /** diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 52df87369..3673429ee 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -39,7 +39,15 @@ public function __construct( $args ) { } private function show_help( $args ) { - $doc_file = WP_CLI::get_path( 'doc' ) . implode( '-', $args ) . '.txt'; + $fname = implode( '-', $args ); + + $man_file = WP_CLI_ROOT . "../../../man/$fname.1"; + + if ( is_readable( $man_file ) ) { + WP_CLI::launch( "man $man_file" ); + } + + $doc_file = WP_CLI_ROOT . "../../doc/$fname.txt"; if ( !is_readable( $doc_file ) ) return false; From a14bcce96e6e6baf746f369e6a1e538386d28e84 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 00:35:05 +0300 Subject: [PATCH 0373/5359] move general help text back to the help command --- src/doc/general.txt | 9 --------- src/php/wp-cli/commands/internals/help.php | 13 ++++++++++++- 2 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 src/doc/general.txt diff --git a/src/doc/general.txt b/src/doc/general.txt deleted file mode 100644 index 7a7fbfbd7..000000000 --- a/src/doc/general.txt +++ /dev/null @@ -1,9 +0,0 @@ - -See 'wp help <command>' for more information on a specific command. - -Global parameters: - --user=<id|login> set the current user - --url=<url> set the current URL - --path=<path> set the current path to the WP install - --require=<path> load a certain file before running the command - --version print wp-cli version diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 3673429ee..39c96c7a4 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -66,7 +66,18 @@ private function general_help() { $this->single_command_help( $name, $command ); } - $this->show_help( 'general' ); + WP_CLI::line(<<<EOB + +See 'wp help <command>' for more information on a specific command. + +Global parameters: + --user=<id|login> set the current user + --url=<url> set the current URL + --path=<path> set the current path to the WP install + --require=<path> load a certain file before running the command + --version print wp-cli version +EOB + ); } private function single_command_help( $name, $command ) { From b69526dc8662311c9ed4208a986073706dea967b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 01:18:07 +0300 Subject: [PATCH 0374/5359] remove help related code from WP_CLI and make WP_CLI::$private private --- src/php/wp-cli/class-wp-cli.php | 37 +++++++------ src/php/wp-cli/commands/internals/help.php | 61 ++++++++++------------ src/php/wp-cli/wp-cli.php | 4 +- 3 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 1185314f8..8a6982e5c 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -7,7 +7,7 @@ */ class WP_CLI { - static $commands = array(); + private static $commands = array(); /** * Add a command to the wp-cli list of commands @@ -237,9 +237,16 @@ static function load_wp_config() { static function load_all_commands() { foreach ( array( 'internals', 'community' ) as $dir ) { foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { + $command = substr( basename( $filename ), 0, -4 ); + + if ( isset( self::$commands[ $command ] ) ) + continue; + include $filename; } } + + return self::$commands; } static function run_command( $arguments, $assoc_args ) { @@ -256,27 +263,12 @@ static function run_command( $arguments, $assoc_args ) { $command = $aliases[ $command ]; } - if ( 'help' == $command ) { - if ( empty( $arguments ) ) { - self::load_all_commands(); - } else { - self::load_command( 'help' ); - self::load_command( $arguments[0] ); - } - } else { - self::load_command( $command ); - } - - if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); - exit; - } + $class = self::load_command( $command ); - new WP_CLI::$commands[$command]( $arguments, $assoc_args ); - exit; + new $class( $arguments, $assoc_args ); } - private function load_command( $command ) { + static function load_command( $command ) { foreach ( array( 'internals', 'community' ) as $dir ) { $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; @@ -285,6 +277,13 @@ private function load_command( $command ) { break; } } + + if ( !isset( WP_CLI::$commands[$command] ) ) { + WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + exit; + } + + return WP_CLI::$commands[$command]; } // back-compat diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 39c96c7a4..04e7c22a3 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -21,49 +21,45 @@ public function __construct( $args ) { return; } - $command = $args[0]; + $this->maybe_load_man_page( $args ); - if ( !isset( WP_CLI::$commands[$command] ) ) - WP_CLI::error( "'$command' is not a registered wp command." ); + $this->show_available_subcommands( $args[0] ); + } + + private function maybe_load_man_page( $args ) { + $man_dir = WP_CLI_ROOT . "../../../man/"; - if ( !$this->show_help( $args ) ) { - $class = WP_CLI::$commands[$command]; + if ( !is_dir( $man_dir ) ) { + WP_CLI::warning( "man pages do not seem to be installed." ); + } else { + $man_file = $man_dir . implode( '-', $args ) . '.1'; - if ( method_exists( $class, 'help' ) ) { - $class::help( $subcommand ); - } else { - WP_CLI::line( 'Example usage:' ); - $this->single_command_help( $command, $class ); + if ( is_readable( $man_file ) ) { + WP_CLI::launch( "man $man_file" ); } } } - private function show_help( $args ) { - $fname = implode( '-', $args ); + private function show_available_subcommands( $command ) { + $class = WP_CLI::load_command( $command ); - $man_file = WP_CLI_ROOT . "../../../man/$fname.1"; - - if ( is_readable( $man_file ) ) { - WP_CLI::launch( "man $man_file" ); + if ( method_exists( $class, 'help' ) ) { + $class::help(); + } else { + WP_CLI::line( 'Example usage:' ); + $this->single_command_help( $command, $class ); + WP_CLI::line(); + WP_CLI::line( "See 'wp help blog <subcommand>' for more information on a specific subcommand." ); } - - $doc_file = WP_CLI_ROOT . "../../doc/$fname.txt"; - - if ( !is_readable( $doc_file ) ) - return false; - - echo file_get_contents( $doc_file ); - - return true; } private function general_help() { WP_CLI::line( 'Available commands:' ); - foreach ( WP_CLI::$commands as $name => $command ) { + foreach ( WP_CLI::load_all_commands() as $name => $class ) { if ( 'help' == $name ) continue; - $this->single_command_help( $name, $command ); + $this->single_command_help( $name, $class ); } WP_CLI::line(<<<EOB @@ -80,14 +76,15 @@ private function general_help() { ); } - private function single_command_help( $name, $command ) { - WP_CLI::out( ' wp ' . $name ); + private function single_command_help( $name, $class ) { + $out = " wp $name"; - $methods = WP_CLI_Command::get_subcommands( $command ); + $methods = WP_CLI_Command::get_subcommands( $class ); if ( !empty( $methods ) ) { - WP_CLI::out( ' [' . implode( '|', $methods ) . ']' ); + $out .= ' [' . implode( '|', $methods ) . ']'; } - WP_CLI::line(' ...'); + + WP_CLI::line( $out ); } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 9049ffa54..80681c8a7 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -108,9 +108,7 @@ // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { - WP_CLI::load_all_commands(); - - foreach ( WP_CLI::$commands as $name => $command ) { + foreach ( WP_CLI::load_all_commands() as $name => $command ) { WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_subcommands($command) ) ); } exit; From a87410d8725c65db7ab0f6bfb187468dbb3c636e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 03:29:32 +0300 Subject: [PATCH 0375/5359] Built-in help improvements - introduce WP_CLI_Command::describe_command() - short-circuit `wp [command] __construct` --- src/php/wp-cli/class-wp-cli-command.php | 44 +++++++++++++++++----- src/php/wp-cli/class-wp-cli.php | 16 +++++--- src/php/wp-cli/commands/internals/help.php | 41 ++++++-------------- src/php/wp-cli/wp-cli.php | 3 +- 4 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index c21846b72..aabf1c8db 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -7,7 +7,7 @@ */ abstract class WP_CLI_Command { - protected $default_subcommand = 'help'; + protected $default_subcommand; protected $aliases = array(); @@ -31,11 +31,33 @@ public function __construct( $args, $assoc_args ) { $subcommand = '_' . $subcommand; } - if ( !method_exists( $this, $subcommand ) || isset( $assoc_args[ 'help' ] ) ) { - $subcommand = 'help'; + if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) || isset( $assoc_args[ 'help' ] ) ) { + self::describe_command( get_class( $this ), WP_CLI_COMMAND ); + } else { + $this->$subcommand( $args, $assoc_args ); } + } + + static function describe_command( $class, $command ) { + if ( method_exists( $class, 'help' ) ) { + $class::help(); + return; + } + + $methods = self::get_subcommands( $class ); + + $out = "usage: wp $command"; - $this->$subcommand( $args, $assoc_args ); + if ( empty( $methods ) ) { + WP_CLI::line( $out ); + } else { + $out .= ' [' . implode( '|', $methods ) . ']'; + + WP_CLI::line( $out ); + + WP_CLI::line(); + WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); + } } /** @@ -50,17 +72,19 @@ static function get_subcommands( $class ) { $methods = array(); foreach ( $reflection->getMethods() as $method ) { - if ( $method->isPublic() && !$method->isStatic() && !$method->isConstructor() ) { - $name = $method->name; + if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) + continue; - if ( strpos( $name, '_' ) === 0 ) { - $name = substr( $name, 1 ); - } + $name = $method->name; - $methods[] = $name; + if ( strpos( $name, '_' ) === 0 ) { + $name = substr( $name, 1 ); } + + $methods[] = $name; } return $methods; } } + diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8a6982e5c..5387b4914 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -265,16 +265,20 @@ static function run_command( $arguments, $assoc_args ) { $class = self::load_command( $command ); - new $class( $arguments, $assoc_args ); + define( 'WP_CLI_COMMAND', $command ); + + $instance = new $class( $arguments, $assoc_args ); } static function load_command( $command ) { - foreach ( array( 'internals', 'community' ) as $dir ) { - $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + if ( !isset( WP_CLI::$commands[$command] ) ) { + foreach ( array( 'internals', 'community' ) as $dir ) { + $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; - if ( is_readable( $path ) ) { - include $path; - break; + if ( is_readable( $path ) ) { + include $path; + break; + } } } diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 04e7c22a3..185348409 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -10,11 +10,6 @@ */ class Help_Command extends WP_CLI_Command { - /** - * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args - */ public function __construct( $args ) { if ( empty( $args ) ) { $this->general_help(); @@ -42,24 +37,24 @@ private function maybe_load_man_page( $args ) { private function show_available_subcommands( $command ) { $class = WP_CLI::load_command( $command ); - - if ( method_exists( $class, 'help' ) ) { - $class::help(); - } else { - WP_CLI::line( 'Example usage:' ); - $this->single_command_help( $command, $class ); - WP_CLI::line(); - WP_CLI::line( "See 'wp help blog <subcommand>' for more information on a specific subcommand." ); - } + WP_CLI_Command::describe_command( $class, $command ); } private function general_help() { WP_CLI::line( 'Available commands:' ); - foreach ( WP_CLI::load_all_commands() as $name => $class ) { - if ( 'help' == $name ) + foreach ( WP_CLI::load_all_commands() as $command => $class ) { + if ( 'help' == $command ) continue; - $this->single_command_help( $name, $class ); + $out = " wp $command"; + + $methods = WP_CLI_Command::get_subcommands( $class ); + + if ( !empty( $methods ) ) { + $out .= ' [' . implode( '|', $methods ) . ']'; + } + + WP_CLI::line( $out ); } WP_CLI::line(<<<EOB @@ -75,16 +70,4 @@ private function general_help() { EOB ); } - - private function single_command_help( $name, $class ) { - $out = " wp $name"; - - $methods = WP_CLI_Command::get_subcommands( $class ); - - if ( !empty( $methods ) ) { - $out .= ' [' . implode( '|', $methods ) . ']'; - } - - WP_CLI::line( $out ); - } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 80681c8a7..8a7c030f0 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -109,7 +109,8 @@ // Handle --completions parameter if ( isset( $assoc_args['completions'] ) ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { - WP_CLI::line( $name . ' ' . implode( ' ', WP_CLI_Command::get_subcommands($command) ) ); + $subcommands = implode( ' ', WP_CLI_Command::get_subcommands( $command ) ); + WP_CLI::line( $name . ' ' . $subcommands ); } exit; } From bbac551c39538544514a02f2e31acb456e3e5a09 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 04:52:05 +0300 Subject: [PATCH 0376/5359] add required WP version to readme. see #58 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f715fdfae..7474ba4a9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Requirements ------------ PHP >= 5.3 +WP >= 3.3 Installing ---------- From 470dd65341f66d27075b0b152df61aed0271f660 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 04:52:41 +0300 Subject: [PATCH 0377/5359] put requirements in a list --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7474ba4a9..e2578d61b 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ A set of tools for controlling WordPress installations from the command line. Requirements ------------ -PHP >= 5.3 -WP >= 3.3 +* PHP >= 5.3 +* WP >= 3.3 Installing ---------- From 865b926907c4017ecd0bb994a71b9ca7c578172c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:01:43 +0300 Subject: [PATCH 0378/5359] core: create doc files for each subcommand --- src/doc/core-config.txt | 28 ++++++++++++++++++++++++++++ src/doc/core-download.txt | 16 ++++++++++++++++ src/doc/core-install.txt | 28 ++++++++++++++++++++++++++++ src/doc/core-update.txt | 6 ++++++ src/doc/core-version.txt | 12 ++++++++++++ src/doc/core.txt | 5 ----- 6 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 src/doc/core-config.txt create mode 100644 src/doc/core-download.txt create mode 100644 src/doc/core-install.txt create mode 100644 src/doc/core-update.txt create mode 100644 src/doc/core-version.txt delete mode 100644 src/doc/core.txt diff --git a/src/doc/core-config.txt b/src/doc/core-config.txt new file mode 100644 index 000000000..01f71b1a0 --- /dev/null +++ b/src/doc/core-config.txt @@ -0,0 +1,28 @@ +wp-core-config(1) -- Create a wp-config.php file. +==== + +## SYNOPSIS + +`wp core config` --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=localhost] [--dbprefix=wp_] + +## OPTIONS + +* `--dbname`=<dbname>: + + Set the database name. + +* `--dbuser`=<dbuser>: + + Set the database user. + +* `--dbpass`=<dbpass>: + + Set the database user password. + +* `--dbhost`=<dbhost>: + + Set the database host. Default: 'localhost' + +* `--dbprefix`=<dbprefix>: + + Set the database table prefix. Default: 'wp_' diff --git a/src/doc/core-download.txt b/src/doc/core-download.txt new file mode 100644 index 000000000..fe858f152 --- /dev/null +++ b/src/doc/core-download.txt @@ -0,0 +1,16 @@ +wp-core-download(1) -- Download core WordPress files. +==== + +## SYNOPSIS + +`wp core download` [--version=<version>] + +## OPTIONS + +* `--version`=<version>: + + Select which version you want to download. + +## EXAMPLES + + Download version 3.3: wp core download --version=3.3 diff --git a/src/doc/core-install.txt b/src/doc/core-install.txt new file mode 100644 index 000000000..20c14827d --- /dev/null +++ b/src/doc/core-install.txt @@ -0,0 +1,28 @@ +wp-core-install(1) -- Install the WordPress tables in the database. +==== + +## SYNOPSIS + +`wp core install` --site_url=<url> --site_title=<title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email> + +## OPTIONS + +* `--site_url`=<url>: + + The address of the new site. + +* `--site_title`=<title>: + + The title of the new site. + +* `--admin_name`=<username>: + + The name of the admin user. Default: 'admin' + +* `--admin_password`=<password>: + + The password for the admin user. + +* `--admin_email`=<email>: + + The email address for the admin user. diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt new file mode 100644 index 000000000..8a6d15bd8 --- /dev/null +++ b/src/doc/core-update.txt @@ -0,0 +1,6 @@ +wp-core-update(1) -- Update WordPress to the latest version. +==== + +## SYNOPSIS + +`wp core update` diff --git a/src/doc/core-version.txt b/src/doc/core-version.txt new file mode 100644 index 000000000..ecbdc4d48 --- /dev/null +++ b/src/doc/core-version.txt @@ -0,0 +1,12 @@ +wp-core-version(1) -- Show the WordPress version. +==== + +## SYNOPSIS + +`wp core version` [--extra] + +## OPTIONS + +* `--extra`: + + Show extended version information. diff --git a/src/doc/core.txt b/src/doc/core.txt deleted file mode 100644 index eddc818af..000000000 --- a/src/doc/core.txt +++ /dev/null @@ -1,5 +0,0 @@ -usage: wp core update - or: wp core version [--extra] - or: wp core download [--version=1.2.3] - or: wp core config --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=localhost] [--dbprefix=wp_] - or: wp core install --site_url=example.com --site_title=<site-title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email-address> From ebbabe5982110685cd64327f65b6659e72624c80 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:09:18 +0300 Subject: [PATCH 0379/5359] treat --help as an alias for wp help --- src/php/wp-cli/class-wp-cli-command.php | 2 +- src/php/wp-cli/wp-cli.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index aabf1c8db..79eee88ac 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -31,7 +31,7 @@ public function __construct( $args, $assoc_args ) { $subcommand = '_' . $subcommand; } - if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) || isset( $assoc_args[ 'help' ] ) ) { + if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) ) { self::describe_command( get_class( $this ), WP_CLI_COMMAND ); } else { $this->$subcommand( $args, $assoc_args ); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 8a7c030f0..a2c7e2ffd 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -115,5 +115,11 @@ exit; } +// Handle --help parameter +if ( isset( $assoc_args['help'] ) ) { + array_unshift( $arguments, 'help' ); + unset( $assoc_args['help'] ); +} + WP_CLI::run_command( $arguments, $assoc_args ); From 40a0c98b1c46c55f9455b6862846e3532d65157f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:11:24 +0300 Subject: [PATCH 0380/5359] don't show command description after loading man page --- src/php/wp-cli/commands/internals/help.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 185348409..ae8dc1024 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -31,6 +31,7 @@ private function maybe_load_man_page( $args ) { if ( is_readable( $man_file ) ) { WP_CLI::launch( "man $man_file" ); + exit; } } } From f110d80c863a11750d0bc13b11f7f0661dfbbfe3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:31:00 +0300 Subject: [PATCH 0381/5359] db: create doc files for each subcommand --- src/doc/db-cli.txt | 6 ++++++ src/doc/db-connect.txt | 6 ++++++ src/doc/db-create.txt | 6 ++++++ src/doc/db-export.txt | 12 ++++++++++++ src/doc/db-import.txt | 12 ++++++++++++ src/doc/db-query.txt | 12 ++++++++++++ src/doc/db.txt | 14 -------------- src/php/wp-cli/commands/internals/db.php | 2 +- 8 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 src/doc/db-cli.txt create mode 100644 src/doc/db-connect.txt create mode 100644 src/doc/db-create.txt create mode 100644 src/doc/db-export.txt create mode 100644 src/doc/db-import.txt create mode 100644 src/doc/db-query.txt delete mode 100644 src/doc/db.txt diff --git a/src/doc/db-cli.txt b/src/doc/db-cli.txt new file mode 100644 index 000000000..10753c08b --- /dev/null +++ b/src/doc/db-cli.txt @@ -0,0 +1,6 @@ +wp-db-cli(1) -- Open a SQL command-line interface to the WordPress database. +==== + +## SYNOPSIS + +`wp db cli` diff --git a/src/doc/db-connect.txt b/src/doc/db-connect.txt new file mode 100644 index 000000000..b724452e1 --- /dev/null +++ b/src/doc/db-connect.txt @@ -0,0 +1,6 @@ +wp-db-connect(1) -- Print a string for connecting to the database. +==== + +## SYNOPSIS + +`wp db connect` diff --git a/src/doc/db-create.txt b/src/doc/db-create.txt new file mode 100644 index 000000000..27a6b7c74 --- /dev/null +++ b/src/doc/db-create.txt @@ -0,0 +1,6 @@ +wp-db-create(1) -- Create a database using the credentials from wp-config.php. +==== + +## SYNOPSIS + +`wp db create` diff --git a/src/doc/db-export.txt b/src/doc/db-export.txt new file mode 100644 index 000000000..c5019c2af --- /dev/null +++ b/src/doc/db-export.txt @@ -0,0 +1,12 @@ +wp-db-export(1) -- Export the WordPress database using mysqldump. +==== + +## SYNOPSIS + +`wp db export` [<file>] + +## OPTIONS + +* `<file>`: + + The name of the export file. If omitted, it will be '{dbname}.sql' diff --git a/src/doc/db-import.txt b/src/doc/db-import.txt new file mode 100644 index 000000000..a0e65c2b9 --- /dev/null +++ b/src/doc/db-import.txt @@ -0,0 +1,12 @@ +wp-db-import(1) -- Import a database from a text file. +==== + +## SYNOPSIS + +`wp db import` [<file>] + +## OPTIONS + +* `<file>`: + + The name of the import file. If omitted, it will be '{dbname}.sql' diff --git a/src/doc/db-query.txt b/src/doc/db-query.txt new file mode 100644 index 000000000..b4e986ba2 --- /dev/null +++ b/src/doc/db-query.txt @@ -0,0 +1,12 @@ +wp-db-query(1) -- Execute a query against the WordPress database. +==== + +## SYNOPSIS + +`wp db query` <SQL> + +## OPTIONS + +* `<SQL>`: + + A SQL query. diff --git a/src/doc/db.txt b/src/doc/db.txt deleted file mode 100644 index e318225e4..000000000 --- a/src/doc/db.txt +++ /dev/null @@ -1,14 +0,0 @@ -usage: wp db <sub-command> [<file>] - -Available sub-commands: - cli Open a SQL command-line interface using the WordPress credentials. - - connect Print a string for connecting to the database. - - export Export the WordPress database using mysqldump. - - import Import a database exported via mysqldump. - - query Execute a query against the WordPress database. - - create Create a database using the info from wp-config.php. diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 77e631ee1..9239e1811 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -41,7 +41,7 @@ function cli() { */ function query( $args, $assoc_args ) { if ( empty( $args ) ) { - WP_CLI::line( "usage: wp sql query <SQL>" ); + WP_CLI::line( "usage: wp db query <SQL>" ); exit; } From eb62635235afbc782f79cff2977b3e2beaadac70 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:31:43 +0300 Subject: [PATCH 0382/5359] handle --help parameter sooner, so that it works for special commands, such as `wp db create` --- src/php/wp-cli/wp-cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index a2c7e2ffd..b932b719f 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -35,6 +35,12 @@ exit; } +// Handle --help parameter +if ( isset( $assoc_args['help'] ) ) { + array_unshift( $arguments, 'help' ); + unset( $assoc_args['help'] ); +} + // Define the WordPress location if ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { define( 'WP_ROOT', $_SERVER['PWD'] . '/../' ); @@ -115,11 +121,5 @@ exit; } -// Handle --help parameter -if ( isset( $assoc_args['help'] ) ) { - array_unshift( $arguments, 'help' ); - unset( $assoc_args['help'] ); -} - WP_CLI::run_command( $arguments, $assoc_args ); From 4b520808d822a29c223b0e4bd7b16bf10abea2c0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:43:16 +0300 Subject: [PATCH 0383/5359] update eval.txt and eval-file.txt --- src/doc/eval-file.txt | 11 +++++++++-- src/doc/eval.txt | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/doc/eval-file.txt b/src/doc/eval-file.txt index c626a9353..47e6764bc 100644 --- a/src/doc/eval-file.txt +++ b/src/doc/eval-file.txt @@ -1,3 +1,10 @@ -example: wp eval-file some-file.php +wp-eval-file(1) -- Loads and executes a PHP file after loading WordPress. +==== -Loads and executes a PHP file after bootstrapping WordPress. +## SYNOPSIS + +`wp eval-file` <file> + +## EXAMPLES + + wp eval-file my-code.php diff --git a/src/doc/eval.txt b/src/doc/eval.txt index 1005333a6..97db070a9 100644 --- a/src/doc/eval.txt +++ b/src/doc/eval.txt @@ -1,3 +1,10 @@ -example: wp eval 'echo WP_CONTENT_DIR;' +wp-eval(1) -- Executes arbitrary PHP code after loading WordPress. +==== -Executes arbitrary PHP code after bootstrapping WordPress. +## SYNOPSIS + +`wp eval` <PHP> + +## EXAMPLES + + wp eval 'echo WP_CONTENT_DIR;' From e0443a5d68190c3aee51d7f68b6515a6d76e9c27 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 18:53:18 +0300 Subject: [PATCH 0384/5359] update export.txt --- src/doc/export.txt | 60 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/doc/export.txt b/src/doc/export.txt index ea644d862..9a27e63ab 100644 --- a/src/doc/export.txt +++ b/src/doc/export.txt @@ -1,14 +1,46 @@ -usage: wp export --path=<export-path> --user=<username/id> - or: wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 - -Required parameters: - --path Full Path to directory where WXR export files should be stored - -Optional filters: - --start_date Export only posts new than this date in format YYYY-MM-DD - --end_date Export only posts older than this date in format YYYY-MM-DD - --post_type Export only posts with this post_type - --author Export only posts by this author - --category Export only posts in this category - --post_status Export only posts with this post_status - --skip_comments Don't export comments +wp-export(1) -- Create a WXR file. +==== + +## SYNOPSIS + +`wp export` --path=<dirname> [filters] [--skip_comments] + +## OPTIONS + +* `--path`=<dirname>: + + Full Path to directory where WXR export files should be stored. + +* `--skip_comments`: + + Don't export comments. + +## FILTERS + +* `--start_date`=<date>: + + Export only posts newer than this date in format YYYY-MM-DD. + +* `--end_date`=<date>: + + Export only posts older than this date in format YYYY-MM-DD. + +* `--post_type`=<post_type>: + + Export only posts with this post_type. + +* `--author`=<login/id>: + + Export only posts by this author. + +* `--category`=<category-id>: + + Export only posts in this category. + +* `--post_status`=<status>: + + Export only posts with this status. + +## EXAMPLES + + wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 From 854a872b0da41effc3d615d256835e24dac19598 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 19:02:23 +0300 Subject: [PATCH 0385/5359] generate: create doc files for each subcommand --- src/doc/generate-posts.txt | 24 ++++++++++++++++++++++++ src/doc/generate-users.txt | 16 ++++++++++++++++ src/doc/generate.txt | 2 -- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/doc/generate-posts.txt create mode 100644 src/doc/generate-users.txt delete mode 100644 src/doc/generate.txt diff --git a/src/doc/generate-posts.txt b/src/doc/generate-posts.txt new file mode 100644 index 000000000..2f9b15606 --- /dev/null +++ b/src/doc/generate-posts.txt @@ -0,0 +1,24 @@ +wp-generate-posts(1) -- Generate a bunch of posts. +==== + +## SYNOPSIS + +`wp generate posts` [--count=100] [--type=post] [--status=publish] [--author=<login>] + +## OPTIONS + +* `--count`=<number>: + + How many posts to generate. Default: 100 + +* `--type`=<post_type>: + + The type of the generated posts. Default: 'post' + +* `--status`=<post_status>: + + The status of the generated posts. Default: 'publish' + +* `--author`=<login>: + + The author of the generated posts. Default: none diff --git a/src/doc/generate-users.txt b/src/doc/generate-users.txt new file mode 100644 index 000000000..3b2da84a1 --- /dev/null +++ b/src/doc/generate-users.txt @@ -0,0 +1,16 @@ +wp-generate-users(1) -- Generate a bunch of users. +==== + +## SYNOPSIS + +`wp generate users` [--count=100] [--role=<role>] + +## OPTIONS + +* `--count`=<number>: + + How many users to generate. Default: 100 + +* `--role`=<role>: + + The role of the generated users. Default: default role from WP diff --git a/src/doc/generate.txt b/src/doc/generate.txt deleted file mode 100644 index 8b2364fb2..000000000 --- a/src/doc/generate.txt +++ /dev/null @@ -1,2 +0,0 @@ -usage: wp generate posts [--count=100] [--type=post] [--status=publish] [--author=<login>] - or: wp generate users [--count=100] [--role=<role>] From ec04fd163b744a7bb9f207ae89cbbebf1251eb3e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 20:09:08 +0300 Subject: [PATCH 0386/5359] update home.txt --- src/doc/home.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/doc/home.txt b/src/doc/home.txt index 5abbdf995..32d55a279 100644 --- a/src/doc/home.txt +++ b/src/doc/home.txt @@ -1,3 +1,6 @@ -usage: wp home +wp-home(1) -- Opens the wp-cli homepage in your browser. +==== -Opens the wp-cli homepage in your browser. +## SYNOPSIS + +`wp home` From 85b13921f3b9c608d2659d0cdc49aca9f438e8b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 20:14:54 +0300 Subject: [PATCH 0387/5359] update option.txt --- src/doc/option.txt | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/doc/option.txt b/src/doc/option.txt index 2985f7b7f..05f5e7da3 100644 --- a/src/doc/option.txt +++ b/src/doc/option.txt @@ -1,4 +1,40 @@ -usage: wp option get <option-name> - or: wp option add <option-name> <option-value> - or: wp option update <option-name> <option-value> - or: wp option delete <option-name> +wp-option(1) -- Manage WordPress options. +==== + +## SYNOPSIS + +wp option get <key> + +wp option add <key> <value> + +wp option update <key> <value> + +wp option delete <key> + +## SUBCOMMANDS + +* `get`: + + Get an option value. + +* `add`: + + Add a new option. + +* `update`: + + Update an existing option. + +* `delete`: + + Delete an option. + +## EXAMPLES + + wp option get siteurl + + wp option add my_option foobar + + wp option update my_option barfoo + + wp option delete my_option From 77811b51a746fb06228a39fe8a43cae88bbcccd9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 May 2012 20:23:17 +0300 Subject: [PATCH 0388/5359] update transient.txt --- src/doc/transient.txt | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/doc/transient.txt b/src/doc/transient.txt index 440f67f49..33a167aaa 100644 --- a/src/doc/transient.txt +++ b/src/doc/transient.txt @@ -1,4 +1,35 @@ -usage: wp transient get <key> - or: wp transient set <key> <value> [expiration] - or: wp transient delete <key> - or: wp transient type +wp-transient(1) -- Manage WordPress transients. +==== + +## SYNOPSIS + +wp transient get <key> + +wp transient set <key> <value> [<expiration>] + +wp transient delete <key> + +wp transient type + +## SUBCOMMANDS + +* `get`: + + Get a transient value. + +* `set`: + + Set a transient value. <expiration> is the time until expiration, in +seconds. + +* `delete`: + + Delete a transient value. + +* `type`: + + Delete an option. + +## EXAMPLES + +wp transient set my_key my_value 300 From 7a8eb1efab1208b0a69a907ab6990061ca3bc8f5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 00:44:28 +0300 Subject: [PATCH 0389/5359] user: create doc files for each subcommand --- src/doc/user-create.txt | 24 ++++++++++++++++++++++++ src/doc/user-delete.txt | 20 ++++++++++++++++++++ src/doc/user-list.txt | 12 ++++++++++++ src/doc/user-update.txt | 20 ++++++++++++++++++++ src/doc/user.txt | 4 ---- 5 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 src/doc/user-create.txt create mode 100644 src/doc/user-delete.txt create mode 100644 src/doc/user-list.txt create mode 100644 src/doc/user-update.txt delete mode 100644 src/doc/user.txt diff --git a/src/doc/user-create.txt b/src/doc/user-create.txt new file mode 100644 index 000000000..1173efcf4 --- /dev/null +++ b/src/doc/user-create.txt @@ -0,0 +1,24 @@ +wp-user-create(1) -- Create a new WordPress user. +==== + +## SYNOPSIS + +`wp user create` <user-login> <user-email> [--role=<role>] + +## OPTIONS + +* `<user-login>`: + + The login of the user to create. + +* `<user-email>`: + + The email address of the user to create. + +* `--role`=<role>: + + The role of the user to create. + +## EXAMPLES + + wp user create bob bob@example.com --role=author diff --git a/src/doc/user-delete.txt b/src/doc/user-delete.txt new file mode 100644 index 000000000..6d8832c6c --- /dev/null +++ b/src/doc/user-delete.txt @@ -0,0 +1,20 @@ +wp-user-delete(1) -- Delete a WordPress user. +==== + +## SYNOPSIS + +`wp user delete` <ID> [--reassign=<ID>] + +## OPTIONS + +* `<ID>`: + + The ID of the user to delete. + +* `--reassign`=<ID>: + + User to reassign the posts to. + +## EXAMPLES + + wp user delete 123 --reassign=567 diff --git a/src/doc/user-list.txt b/src/doc/user-list.txt new file mode 100644 index 000000000..32b88daad --- /dev/null +++ b/src/doc/user-list.txt @@ -0,0 +1,12 @@ +wp-user-list(1) -- List WordPress users. +==== + +## SYNOPSIS + +`wp user list` [--role=<role>] + +## OPTIONS + +* `--role`=<role>: + + Only display users with a certain role. diff --git a/src/doc/user-update.txt b/src/doc/user-update.txt new file mode 100644 index 000000000..ca46b7e4e --- /dev/null +++ b/src/doc/user-update.txt @@ -0,0 +1,20 @@ +wp-user-update(1) -- Update a WordPress user. +==== + +## SYNOPSIS + +`wp user update` <ID> --<field>=<value> [--<field>=<value>...] + +## OPTIONS + +* `<ID>`: + + The ID of the user to update. + +* `--<field>`=<value>: + + One or more fields to update. For accepted fields, see wp_update_user(). + +## EXAMPLES + + wp user update 123 --user_login=mary --display_name=Mary diff --git a/src/doc/user.txt b/src/doc/user.txt deleted file mode 100644 index ce3f19c5f..000000000 --- a/src/doc/user.txt +++ /dev/null @@ -1,4 +0,0 @@ -usage: wp user list [--role=<role>] - or: wp user create <user_login> <user_email> [--role=<default_role>] - or: wp user update <ID> [--field_name=<field_value>] - or: wp user delete <ID> [--reassign=<reassign_id>] From 0b411030b69a9a1c66f86450387bc84b9902d6e5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 00:56:00 +0300 Subject: [PATCH 0390/5359] fix doc for wp transient type --- src/doc/transient.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/transient.txt b/src/doc/transient.txt index 33a167aaa..50dece19d 100644 --- a/src/doc/transient.txt +++ b/src/doc/transient.txt @@ -28,7 +28,8 @@ seconds. * `type`: - Delete an option. + See wether the transients API is using an object cache or the options +table. ## EXAMPLES From b63d11264727969b3c4c0cdae90536c40fe1e0a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 01:20:24 +0300 Subject: [PATCH 0391/5359] plugin install: merge --dev into --version=dev. fixes #107 --- src/php/wp-cli/commands/internals/plugin.php | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 5877e9b98..13963a78e 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -179,21 +179,21 @@ protected function install_from_repo( $slug, $assoc_args ) { WP_CLI::error( $api ); } - if ( isset( $assoc_args['dev'] ) ) { + if ( isset( $assoc_args['version'] ) ) { list( $link ) = explode( $slug, $api->download_link ); - $api->download_link = $link . $slug . '.zip'; - $api->version = 'Development Version'; - } else if ( isset( $assoc_args['version'] ) ) { - list( $link ) = explode( $slug, $api->download_link ); - - $api->download_link = $link . $slug . '.' . $assoc_args['version'] .'.zip'; - $api->version = $assoc_args['version']; - - // check if the requested version exists - $version_check_response = wp_remote_head( $api->download_link ); - if ( !$version_check_response || $version_check_response['headers']['content-type'] != 'application/octet-stream' ) { - WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . " in the WordPress.org plugins repository." ); + if ( 'dev' == $assoc_args['version'] ) { + $api->download_link = $link . $slug . '.zip'; + $api->version = 'Development Version'; + } else { + $api->download_link = $link . $slug . '.' . $assoc_args['version'] .'.zip'; + $api->version = $assoc_args['version']; + + // check if the requested version exists + $response = wp_remote_head( $api->download_link ); + if ( !$response || $response['headers']['content-type'] != 'application/octet-stream' ) { + WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . " in the WordPress.org plugins repository." ); + } } } From c76a068c642c896223cdf0959a3d2d9935e1d153 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 01:34:21 +0300 Subject: [PATCH 0392/5359] plugin: create doc files for each subcommand --- src/doc/plugin-activate.txt | 12 ++++++++++++ src/doc/plugin-deactivate.txt | 12 ++++++++++++ src/doc/plugin-delete.txt | 16 ++++++++++++++++ src/doc/plugin-install.txt | 25 +++++++++++++++++++++++++ src/doc/plugin-path.txt | 18 ++++++++++++++++++ src/doc/plugin-status.txt | 12 ++++++++++++ src/doc/plugin-toggle.txt | 12 ++++++++++++ src/doc/plugin-uninstall.txt | 16 ++++++++++++++++ src/doc/plugin-update.txt | 23 +++++++++++++++++++++++ src/doc/plugin.txt | 27 --------------------------- 10 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 src/doc/plugin-activate.txt create mode 100644 src/doc/plugin-deactivate.txt create mode 100644 src/doc/plugin-delete.txt create mode 100644 src/doc/plugin-install.txt create mode 100644 src/doc/plugin-path.txt create mode 100644 src/doc/plugin-status.txt create mode 100644 src/doc/plugin-toggle.txt create mode 100644 src/doc/plugin-uninstall.txt create mode 100644 src/doc/plugin-update.txt delete mode 100644 src/doc/plugin.txt diff --git a/src/doc/plugin-activate.txt b/src/doc/plugin-activate.txt new file mode 100644 index 000000000..58760b709 --- /dev/null +++ b/src/doc/plugin-activate.txt @@ -0,0 +1,12 @@ +wp-plugin-activate(1) -- Activate an installed plugin. +==== + +## SYNOPSIS + +`wp plugin activate` <plugin> + +## OPTIONS + +* `<plugin>`: + + The plugin to activate. diff --git a/src/doc/plugin-deactivate.txt b/src/doc/plugin-deactivate.txt new file mode 100644 index 000000000..e6093a838 --- /dev/null +++ b/src/doc/plugin-deactivate.txt @@ -0,0 +1,12 @@ +wp-plugin-deactivate(1) -- Deactivate an active plugin. +==== + +## SYNOPSIS + +`wp plugin deactivate` <plugin> + +## OPTIONS + +* `<plugin>`: + + The plugin to deactivate. diff --git a/src/doc/plugin-delete.txt b/src/doc/plugin-delete.txt new file mode 100644 index 000000000..e36d303fe --- /dev/null +++ b/src/doc/plugin-delete.txt @@ -0,0 +1,16 @@ +wp-plugin-delete(1) -- Delete a plugin's files, without removing it's data. +==== + +## SYNOPSIS + +`wp plugin delete` <plugin> + +## OPTIONS + +* <plugin>: + + The plugin to delete. + +## EXAMPLES + + wp plugin delete hello diff --git a/src/doc/plugin-install.txt b/src/doc/plugin-install.txt new file mode 100644 index 000000000..b1b794009 --- /dev/null +++ b/src/doc/plugin-install.txt @@ -0,0 +1,25 @@ +wp-plugin-install(1) -- Install a plugin from wordpress.org or from a zip file. +==== + +## SYNOPSIS + +`wp plugin install` <plugin/zip> [--version=<version>] [--activate] + +## OPTIONS + +* <plugin>: + + A plugin slug or the path to a zip file. + +* `--version`=<version>: + + If set, get that particular version from wordpress.org, instead of the +stable version. + +## EXAMPLES + + wp plugin install bbpress --version=2.1 + + wp plugin install bbpress --version=dev + + wp plugin install ../my-plugin.zip diff --git a/src/doc/plugin-path.txt b/src/doc/plugin-path.txt new file mode 100644 index 000000000..805b88212 --- /dev/null +++ b/src/doc/plugin-path.txt @@ -0,0 +1,18 @@ +wp-plugin-path(1) -- Activate/Deactivate an installed plugin. +==== + +## SYNOPSIS + +`wp plugin path` [<plugin>] [--dir] + +## OPTIONS + +* `<plugin>`: + + The plugin to get the path to. If not set, will return the path to the +plugins directory. + +* `--dir`: + + If set, get the path to the closest parent directory, instead of the +plugin file. diff --git a/src/doc/plugin-status.txt b/src/doc/plugin-status.txt new file mode 100644 index 000000000..5ee1022dc --- /dev/null +++ b/src/doc/plugin-status.txt @@ -0,0 +1,12 @@ +wp-plugin-status(1) -- See the status of one or all plugins. +==== + +## SYNOPSIS + +`wp plugin status` [<plugin>] + +## OPTIONS + +* `<plugin>`: + + A particular plugin to show the status for. diff --git a/src/doc/plugin-toggle.txt b/src/doc/plugin-toggle.txt new file mode 100644 index 000000000..5f90c0543 --- /dev/null +++ b/src/doc/plugin-toggle.txt @@ -0,0 +1,12 @@ +wp-plugin-deactivate(1) -- Activate/Deactivate an installed plugin. +==== + +## SYNOPSIS + +`wp plugin toggle` <plugin> + +## OPTIONS + +* `<plugin>`: + + The plugin to toggle. diff --git a/src/doc/plugin-uninstall.txt b/src/doc/plugin-uninstall.txt new file mode 100644 index 000000000..cc2fb5327 --- /dev/null +++ b/src/doc/plugin-uninstall.txt @@ -0,0 +1,16 @@ +wp-plugin-uninstall(1) -- Run the uninstallation procedure for a plugin. +==== + +## SYNOPSIS + +`wp plugin uninstall` <plugin> + +## OPTIONS + +* <plugin>: + + The plugin to uninstall. + +## EXAMPLES + + wp plugin uninstall hello diff --git a/src/doc/plugin-update.txt b/src/doc/plugin-update.txt new file mode 100644 index 000000000..f909d53bf --- /dev/null +++ b/src/doc/plugin-update.txt @@ -0,0 +1,23 @@ +wp-plugin-update(1) -- Update an installed plugin. +==== + +## SYNOPSIS + +`wp plugin update` [<plugin>] [--all] + +## OPTIONS + +* <plugin>: + + The plugin to update. Can be omitted when --all is passed. + +* `--all`: + + If set, updates for all plugins will be performed. Use `wp plugin status` +to see which plugins have updates available. + +## EXAMPLES + + wp plugin update bbpress + + wp plugin update --all diff --git a/src/doc/plugin.txt b/src/doc/plugin.txt deleted file mode 100644 index 6903e1290..000000000 --- a/src/doc/plugin.txt +++ /dev/null @@ -1,27 +0,0 @@ -usage: wp plugin <sub-command> [<plugin-name>] - or: wp plugin path [<plugin-name>] [--dir] - or: wp plugin install <plugin-name> [--activate] [--dev] [--version=1.2.3] - -Available sub-commands: - status display status of all installed plugins or of a particular plugin - - activate activate a particular plugin - - deactivate deactivate a particular plugin - - toggle toggle activation state of a particular plugin - - path print path to the plugin's file - --dir get the path to the closest parent directory - - install install a plugin from wordpress.org or from a zip file - --activate activate the plugin after installing it - --dev install the development version - --version install a specific version - - update update a plugin from wordpress.org - --all update all plugins from wordpress.org - - uninstall run the uninstallation procedure for a plugin - - delete delete a plugin From 041b70ae2d71f1b7ec3fcd2f3417f2f1fe592781 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 01:39:55 +0300 Subject: [PATCH 0393/5359] document --activate flag --- src/doc/plugin-install.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/plugin-install.txt b/src/doc/plugin-install.txt index b1b794009..e39aadedb 100644 --- a/src/doc/plugin-install.txt +++ b/src/doc/plugin-install.txt @@ -16,9 +16,13 @@ wp-plugin-install(1) -- Install a plugin from wordpress.org or from a zip file. If set, get that particular version from wordpress.org, instead of the stable version. +* `--activate`: + + If set, the plugin will be activated immediately after install. + ## EXAMPLES - wp plugin install bbpress --version=2.1 + wp plugin install bbpress --version=2.1 --activate wp plugin install bbpress --version=dev From e4da376edee681de577812283d396a79caa12cf3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 01:50:49 +0300 Subject: [PATCH 0394/5359] fix plugin path description --- src/doc/plugin-path.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/plugin-path.txt b/src/doc/plugin-path.txt index 805b88212..08e804aa1 100644 --- a/src/doc/plugin-path.txt +++ b/src/doc/plugin-path.txt @@ -1,4 +1,4 @@ -wp-plugin-path(1) -- Activate/Deactivate an installed plugin. +wp-plugin-path(1) -- Get the path to a plugin or to the plugin directory. ==== ## SYNOPSIS From ea746df1873c8ba3c075f20fb4b683896bf49cc0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 01:55:04 +0300 Subject: [PATCH 0395/5359] theme: create doc files for each subcommand --- src/doc/theme-activate.txt | 12 ++++++++++++ src/doc/theme-delete.txt | 16 ++++++++++++++++ src/doc/theme-install.txt | 18 ++++++++++++++++++ src/doc/theme-path.txt | 18 ++++++++++++++++++ src/doc/theme-status.txt | 12 ++++++++++++ src/doc/theme-update.txt | 23 +++++++++++++++++++++++ src/doc/theme.txt | 18 ------------------ 7 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 src/doc/theme-activate.txt create mode 100644 src/doc/theme-delete.txt create mode 100644 src/doc/theme-install.txt create mode 100644 src/doc/theme-path.txt create mode 100644 src/doc/theme-status.txt create mode 100644 src/doc/theme-update.txt delete mode 100644 src/doc/theme.txt diff --git a/src/doc/theme-activate.txt b/src/doc/theme-activate.txt new file mode 100644 index 000000000..24a492d71 --- /dev/null +++ b/src/doc/theme-activate.txt @@ -0,0 +1,12 @@ +wp-theme-activate(1) -- Activate an installed theme. +==== + +## SYNOPSIS + +`wp theme activate` <theme> + +## OPTIONS + +* `<theme>`: + + The theme to activate. diff --git a/src/doc/theme-delete.txt b/src/doc/theme-delete.txt new file mode 100644 index 000000000..94fa90cca --- /dev/null +++ b/src/doc/theme-delete.txt @@ -0,0 +1,16 @@ +wp-theme-delete(1) -- Delete a theme. +==== + +## SYNOPSIS + +`wp theme delete` <theme> + +## OPTIONS + +* <theme>: + + The theme to delete. + +## EXAMPLES + + wp theme delete twentyeleven diff --git a/src/doc/theme-install.txt b/src/doc/theme-install.txt new file mode 100644 index 000000000..4f06c251b --- /dev/null +++ b/src/doc/theme-install.txt @@ -0,0 +1,18 @@ +wp-theme-install(1) -- Install a theme from wordpress.org or from a zip file. +==== + +## SYNOPSIS + +`wp theme install` <theme/zip> + +## OPTIONS + +* <theme>: + + A theme slug or the path to a zip file. + +## EXAMPLES + + wp theme install twentytwelve + + wp theme install ../my-theme.zip diff --git a/src/doc/theme-path.txt b/src/doc/theme-path.txt new file mode 100644 index 000000000..32bb5c876 --- /dev/null +++ b/src/doc/theme-path.txt @@ -0,0 +1,18 @@ +wp-theme-path(1) -- Get the path to a theme or to the theme directory. +==== + +## SYNOPSIS + +`wp theme path` [<theme>] [--dir] + +## OPTIONS + +* `<theme>`: + + The theme to get the path to. If not set, will return the path to the +themes directory. + +* `--dir`: + + If set, get the path to the closest parent directory, instead of the +theme file. diff --git a/src/doc/theme-status.txt b/src/doc/theme-status.txt new file mode 100644 index 000000000..48b5dfe14 --- /dev/null +++ b/src/doc/theme-status.txt @@ -0,0 +1,12 @@ +wp-theme-status(1) -- See the status of one or all themes. +==== + +## SYNOPSIS + +`wp theme status` [<theme>] + +## OPTIONS + +* `<theme>`: + + A particular theme to show the status for. diff --git a/src/doc/theme-update.txt b/src/doc/theme-update.txt new file mode 100644 index 000000000..e6f5c5e01 --- /dev/null +++ b/src/doc/theme-update.txt @@ -0,0 +1,23 @@ +wp-theme-update(1) -- Update an installed theme. +==== + +## SYNOPSIS + +`wp theme update` [<theme>] [--all] + +## OPTIONS + +* <theme>: + + The theme to update. Can be omitted when --all is passed. + +* `--all`: + + If set, updates for all themes will be performed. Use `wp theme status` +to see which themes have updates available. + +## EXAMPLES + + wp theme update twentytwelve + + wp theme update --all diff --git a/src/doc/theme.txt b/src/doc/theme.txt deleted file mode 100644 index 094d7be4a..000000000 --- a/src/doc/theme.txt +++ /dev/null @@ -1,18 +0,0 @@ -usage: wp theme <sub-command> [<theme-name>] - or: wp theme path [<theme-name>] [--dir] - -Available sub-commands: - status display status of all installed themes or of a particular theme - - activate activate a particular theme - - path print path to the theme's stylesheet - --dir get the path to the closest parent directory - - install install a theme from wordpress.org or from a zip file - --activate activate the theme after installing it - - update update a theme from wordpress.org - --all update all themes from wordpress.org - - delete delete a theme From 88dbebf0872e366786c64e5711ac3cfc2f5c93ab Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 May 2012 02:03:03 +0300 Subject: [PATCH 0396/5359] add generated ROFF files to git, for convenience --- .gitignore | 1 - man/blog-create.1 | 43 +++++++++++++++++++++++++ man/core-config.1 | 43 +++++++++++++++++++++++++ man/core-download.1 | 27 ++++++++++++++++ man/core-install.1 | 43 +++++++++++++++++++++++++ man/core-update.1 | 10 ++++++ man/core-version.1 | 19 +++++++++++ man/db-cli.1 | 10 ++++++ man/db-connect.1 | 10 ++++++ man/db-create.1 | 10 ++++++ man/db-export.1 | 19 +++++++++++ man/db-import.1 | 19 +++++++++++ man/db-query.1 | 19 +++++++++++ man/eval-file.1 | 19 +++++++++++ man/eval.1 | 19 +++++++++++ man/export.1 | 71 +++++++++++++++++++++++++++++++++++++++++ man/generate-posts.1 | 37 +++++++++++++++++++++ man/generate-users.1 | 25 +++++++++++++++ man/home.1 | 10 ++++++ man/option.1 | 60 ++++++++++++++++++++++++++++++++++ man/plugin-activate.1 | 19 +++++++++++ man/plugin-deactivate.1 | 19 +++++++++++ man/plugin-delete.1 | 27 ++++++++++++++++ man/plugin-install.1 | 43 +++++++++++++++++++++++++ man/plugin-path.1 | 25 +++++++++++++++ man/plugin-status.1 | 19 +++++++++++ man/plugin-toggle.1 | 19 +++++++++++ man/plugin-uninstall.1 | 27 ++++++++++++++++ man/plugin-update.1 | 35 ++++++++++++++++++++ man/theme-activate.1 | 19 +++++++++++ man/theme-delete.1 | 27 ++++++++++++++++ man/theme-install.1 | 29 +++++++++++++++++ man/theme-path.1 | 25 +++++++++++++++ man/theme-status.1 | 19 +++++++++++ man/theme-update.1 | 35 ++++++++++++++++++++ man/transient.1 | 48 ++++++++++++++++++++++++++++ man/user-create.1 | 39 ++++++++++++++++++++++ man/user-delete.1 | 33 +++++++++++++++++++ man/user-list.1 | 19 +++++++++++ man/user-update.1 | 33 +++++++++++++++++++ utils/build-doc | 1 + 41 files changed, 1073 insertions(+), 1 deletion(-) create mode 100644 man/blog-create.1 create mode 100644 man/core-config.1 create mode 100644 man/core-download.1 create mode 100644 man/core-install.1 create mode 100644 man/core-update.1 create mode 100644 man/core-version.1 create mode 100644 man/db-cli.1 create mode 100644 man/db-connect.1 create mode 100644 man/db-create.1 create mode 100644 man/db-export.1 create mode 100644 man/db-import.1 create mode 100644 man/db-query.1 create mode 100644 man/eval-file.1 create mode 100644 man/eval.1 create mode 100644 man/export.1 create mode 100644 man/generate-posts.1 create mode 100644 man/generate-users.1 create mode 100644 man/home.1 create mode 100644 man/option.1 create mode 100644 man/plugin-activate.1 create mode 100644 man/plugin-deactivate.1 create mode 100644 man/plugin-delete.1 create mode 100644 man/plugin-install.1 create mode 100644 man/plugin-path.1 create mode 100644 man/plugin-status.1 create mode 100644 man/plugin-toggle.1 create mode 100644 man/plugin-uninstall.1 create mode 100644 man/plugin-update.1 create mode 100644 man/theme-activate.1 create mode 100644 man/theme-delete.1 create mode 100644 man/theme-install.1 create mode 100644 man/theme-path.1 create mode 100644 man/theme-status.1 create mode 100644 man/theme-update.1 create mode 100644 man/transient.1 create mode 100644 man/user-create.1 create mode 100644 man/user-delete.1 create mode 100644 man/user-list.1 create mode 100644 man/user-update.1 diff --git a/.gitignore b/.gitignore index 472657eea..d9cdde38e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /.build /dist -/man diff --git a/man/blog-create.1 b/man/blog-create.1 new file mode 100644 index 000000000..e75b5ee6c --- /dev/null +++ b/man/blog-create.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-BLOG\-CREATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-blog\-create\fR \- Create a new blog in a multisite install\. +. +.SH "SYNOPSIS" +\fBwp blog create\fR \-\-slug=\fIslug\fR \-\-title=\fITitle\fR [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-public=true] +. +.SH "OPTIONS" +. +.TP +\fB\-\-slug\fR=\fIslug\fR: +. +.IP +Base for the new domain\. Subdomain on subdomain installs, directory on subdirectory installs\. +. +.TP +\fB\-\-title\fR=<title>: +. +.IP +Title of the new blog\. +. +.TP +\fB\-\-email\fR=\fIemail\fR: +. +.IP +Email for Admin user\. User will be created if none exists\. Assignement to Super Admin if not included\. +. +.TP +\fB\-\-site_id\fR=\fIsite\-id\fR: +. +.IP +Site (network) to associate new blog with\. Defaults to current site (typically 1)\. +. +.TP +\fB\-\-private\fR: +. +.IP +If set, the new blog will be non\-public (not indexed) + diff --git a/man/core-config.1 b/man/core-config.1 new file mode 100644 index 000000000..0235a39bc --- /dev/null +++ b/man/core-config.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-CONFIG" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-config\fR \- Create a wp\-config\.php file\. +. +.SH "SYNOPSIS" +\fBwp core config\fR \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=localhost] [\-\-dbprefix=wp_] +. +.SH "OPTIONS" +. +.TP +\fB\-\-dbname\fR=\fIdbname\fR: +. +.IP +Set the database name\. +. +.TP +\fB\-\-dbuser\fR=\fIdbuser\fR: +. +.IP +Set the database user\. +. +.TP +\fB\-\-dbpass\fR=\fIdbpass\fR: +. +.IP +Set the database user password\. +. +.TP +\fB\-\-dbhost\fR=\fIdbhost\fR: +. +.IP +Set the database host\. Default: \'localhost\' +. +.TP +\fB\-\-dbprefix\fR=\fIdbprefix\fR: +. +.IP +Set the database table prefix\. Default: \'wp_\' + diff --git a/man/core-download.1 b/man/core-download.1 new file mode 100644 index 000000000..95d38d781 --- /dev/null +++ b/man/core-download.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-DOWNLOAD" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-download\fR \- Download core WordPress files\. +. +.SH "SYNOPSIS" +\fBwp core download\fR [\-\-version=\fIversion\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-version\fR=\fIversion\fR: +. +.IP +Select which version you want to download\. +. +.SH "EXAMPLES" +. +.nf + +Download version 3\.3: wp core download \-\-version=3\.3 +. +.fi + diff --git a/man/core-install.1 b/man/core-install.1 new file mode 100644 index 000000000..e8ab09478 --- /dev/null +++ b/man/core-install.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-INSTALL" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-install\fR \- Install the WordPress tables in the database\. +. +.SH "SYNOPSIS" +\fBwp core install\fR \-\-site_url=\fIurl\fR \-\-site_title=\fItitle> [\-\-admin_name=<username\fR] \-\-admin_password=\fIpassword\fR \-\-admin_email=\fIemail\fR +. +.SH "OPTIONS" +. +.TP +\fB\-\-site_url\fR=\fIurl\fR: +. +.IP +The address of the new site\. +. +.TP +\fB\-\-site_title\fR=<title>: +. +.IP +The title of the new site\. +. +.TP +\fB\-\-admin_name\fR=\fIusername\fR: +. +.IP +The name of the admin user\. Default: \'admin\' +. +.TP +\fB\-\-admin_password\fR=\fIpassword\fR: +. +.IP +The password for the admin user\. +. +.TP +\fB\-\-admin_email\fR=\fIemail\fR: +. +.IP +The email address for the admin user\. + diff --git a/man/core-update.1 b/man/core-update.1 new file mode 100644 index 000000000..24a01f15e --- /dev/null +++ b/man/core-update.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-UPDATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-update\fR \- Update WordPress to the latest version\. +. +.SH "SYNOPSIS" +\fBwp core update\fR diff --git a/man/core-version.1 b/man/core-version.1 new file mode 100644 index 000000000..160ccb376 --- /dev/null +++ b/man/core-version.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-VERSION" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-version\fR \- Show the WordPress version\. +. +.SH "SYNOPSIS" +\fBwp core version\fR [\-\-extra] +. +.SH "OPTIONS" +. +.TP +\fB\-\-extra\fR: +. +.IP +Show extended version information\. + diff --git a/man/db-cli.1 b/man/db-cli.1 new file mode 100644 index 000000000..22f397c05 --- /dev/null +++ b/man/db-cli.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-CLI" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-cli\fR \- Open a SQL command\-line interface to the WordPress database\. +. +.SH "SYNOPSIS" +\fBwp db cli\fR diff --git a/man/db-connect.1 b/man/db-connect.1 new file mode 100644 index 000000000..ea799644f --- /dev/null +++ b/man/db-connect.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-CONNECT" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-connect\fR \- Print a string for connecting to the database\. +. +.SH "SYNOPSIS" +\fBwp db connect\fR diff --git a/man/db-create.1 b/man/db-create.1 new file mode 100644 index 000000000..93f929582 --- /dev/null +++ b/man/db-create.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-CREATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-create\fR \- Create a database using the credentials from wp\-config\.php\. +. +.SH "SYNOPSIS" +\fBwp db create\fR diff --git a/man/db-export.1 b/man/db-export.1 new file mode 100644 index 000000000..33648242f --- /dev/null +++ b/man/db-export.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-EXPORT" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-export\fR \- Export the WordPress database using mysqldump\. +. +.SH "SYNOPSIS" +\fBwp db export\fR [\fIfile\fR] +. +.SH "OPTIONS" +. +.TP +\fB<file>\fR: +. +.IP +The name of the export file\. If omitted, it will be \'{dbname}\.sql\' + diff --git a/man/db-import.1 b/man/db-import.1 new file mode 100644 index 000000000..987cade49 --- /dev/null +++ b/man/db-import.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-IMPORT" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-import\fR \- Import a database from a text file\. +. +.SH "SYNOPSIS" +\fBwp db import\fR [\fIfile\fR] +. +.SH "OPTIONS" +. +.TP +\fB<file>\fR: +. +.IP +The name of the import file\. If omitted, it will be \'{dbname}\.sql\' + diff --git a/man/db-query.1 b/man/db-query.1 new file mode 100644 index 000000000..0326bd394 --- /dev/null +++ b/man/db-query.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-QUERY" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-query\fR \- Execute a query against the WordPress database\. +. +.SH "SYNOPSIS" +\fBwp db query\fR \fISQL\fR +. +.SH "OPTIONS" +. +.TP +\fB<SQL>\fR: +. +.IP +A SQL query\. + diff --git a/man/eval-file.1 b/man/eval-file.1 new file mode 100644 index 000000000..5060788e1 --- /dev/null +++ b/man/eval-file.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-EVAL\-FILE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. +. +.SH "SYNOPSIS" +\fBwp eval\-file\fR \fIfile\fR +. +.SH "EXAMPLES" +. +.nf + +wp eval\-file my\-code\.php +. +.fi + diff --git a/man/eval.1 b/man/eval.1 new file mode 100644 index 000000000..473ec61df --- /dev/null +++ b/man/eval.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-EVAL" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. +. +.SH "SYNOPSIS" +\fBwp eval\fR \fIPHP\fR +. +.SH "EXAMPLES" +. +.nf + +wp eval \'echo WP_CONTENT_DIR;\' +. +.fi + diff --git a/man/export.1 b/man/export.1 new file mode 100644 index 000000000..d064d5db0 --- /dev/null +++ b/man/export.1 @@ -0,0 +1,71 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-EXPORT" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-export\fR \- Create a WXR file\. +. +.SH "SYNOPSIS" +\fBwp export\fR \-\-path=\fIdirname\fR [filters] [\-\-skip_comments] +. +.SH "OPTIONS" +. +.TP +\fB\-\-path\fR=\fIdirname\fR: +. +.IP +Full Path to directory where WXR export files should be stored\. +. +.TP +\fB\-\-skip_comments\fR: +. +.IP +Don\'t export comments\. +. +.SH "FILTERS" +. +.TP +\fB\-\-start_date\fR=\fIdate\fR: +. +.IP +Export only posts newer than this date in format YYYY\-MM\-DD\. +. +.TP +\fB\-\-end_date\fR=\fIdate\fR: +. +.IP +Export only posts older than this date in format YYYY\-MM\-DD\. +. +.TP +\fB\-\-post_type\fR=\fIpost_type\fR: +. +.IP +Export only posts with this post_type\. +. +.TP +\fB\-\-author\fR=<login/id>: +. +.IP +Export only posts by this author\. +. +.TP +\fB\-\-category\fR=\fIcategory\-id\fR: +. +.IP +Export only posts in this category\. +. +.TP +\fB\-\-post_status\fR=\fIstatus\fR: +. +.IP +Export only posts with this status\. +. +.SH "EXAMPLES" +. +.nf + +wp export \-\-path=/tmp/ \-\-user=admin \-\-post_type=post \-\-start_date=2011\-01\-01 \-\-end_date=2011\-12\-31 +. +.fi + diff --git a/man/generate-posts.1 b/man/generate-posts.1 new file mode 100644 index 000000000..c014d4ff6 --- /dev/null +++ b/man/generate-posts.1 @@ -0,0 +1,37 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-GENERATE\-POSTS" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-generate\-posts\fR \- Generate a bunch of posts\. +. +.SH "SYNOPSIS" +\fBwp generate posts\fR [\-\-count=100] [\-\-type=post] [\-\-status=publish] [\-\-author=\fIlogin\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-count\fR=\fInumber\fR: +. +.IP +How many posts to generate\. Default: 100 +. +.TP +\fB\-\-type\fR=\fIpost_type\fR: +. +.IP +The type of the generated posts\. Default: \'post\' +. +.TP +\fB\-\-status\fR=\fIpost_status\fR: +. +.IP +The status of the generated posts\. Default: \'publish\' +. +.TP +\fB\-\-author\fR=\fIlogin\fR: +. +.IP +The author of the generated posts\. Default: none + diff --git a/man/generate-users.1 b/man/generate-users.1 new file mode 100644 index 000000000..9fadb9950 --- /dev/null +++ b/man/generate-users.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-GENERATE\-USERS" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-generate\-users\fR \- Generate a bunch of users\. +. +.SH "SYNOPSIS" +\fBwp generate users\fR [\-\-count=100] [\-\-role=\fIrole\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-count\fR=\fInumber\fR: +. +.IP +How many users to generate\. Default: 100 +. +.TP +\fB\-\-role\fR=\fIrole\fR: +. +.IP +The role of the generated users\. Default: default role from WP + diff --git a/man/home.1 b/man/home.1 new file mode 100644 index 000000000..069590884 --- /dev/null +++ b/man/home.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-HOME" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-home\fR \- Opens the wp\-cli homepage in your browser\. +. +.SH "SYNOPSIS" +\fBwp home\fR diff --git a/man/option.1 b/man/option.1 new file mode 100644 index 000000000..30580ae81 --- /dev/null +++ b/man/option.1 @@ -0,0 +1,60 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-OPTION" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-option\fR \- Manage WordPress options\. +. +.SH "SYNOPSIS" +wp option get \fIkey\fR +. +.P +wp option add \fIkey\fR \fIvalue\fR +. +.P +wp option update \fIkey\fR \fIvalue\fR +. +.P +wp option delete \fIkey\fR +. +.SH "SUBCOMMANDS" +. +.TP +\fBget\fR: +. +.IP +Get an option value\. +. +.TP +\fBadd\fR: +. +.IP +Add a new option\. +. +.TP +\fBupdate\fR: +. +.IP +Update an existing option\. +. +.TP +\fBdelete\fR: +. +.IP +Delete an option\. +. +.SH "EXAMPLES" +. +.nf + +wp option get siteurl + +wp option add my_option foobar + +wp option update my_option barfoo + +wp option delete my_option +. +.fi + diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 new file mode 100644 index 000000000..f78e01436 --- /dev/null +++ b/man/plugin-activate.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-ACTIVATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-activate\fR \- Activate an installed plugin\. +. +.SH "SYNOPSIS" +\fBwp plugin activate\fR \fIplugin\fR +. +.SH "OPTIONS" +. +.TP +\fB<plugin>\fR: +. +.IP +The plugin to activate\. + diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 new file mode 100644 index 000000000..25bd7b38f --- /dev/null +++ b/man/plugin-deactivate.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-deactivate\fR \- Deactivate an active plugin\. +. +.SH "SYNOPSIS" +\fBwp plugin deactivate\fR \fIplugin\fR +. +.SH "OPTIONS" +. +.TP +\fB<plugin>\fR: +. +.IP +The plugin to deactivate\. + diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 new file mode 100644 index 000000000..b6c3b2034 --- /dev/null +++ b/man/plugin-delete.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-DELETE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-delete\fR \- Delete a plugin\'s files, without removing it\'s data\. +. +.SH "SYNOPSIS" +\fBwp plugin delete\fR \fIplugin\fR +. +.SH "OPTIONS" +. +.TP +\fIplugin\fR: +. +.IP +The plugin to delete\. +. +.SH "EXAMPLES" +. +.nf + +wp plugin delete hello +. +.fi + diff --git a/man/plugin-install.1 b/man/plugin-install.1 new file mode 100644 index 000000000..a90117f76 --- /dev/null +++ b/man/plugin-install.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-INSTALL" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-install\fR \- Install a plugin from wordpress\.org or from a zip file\. +. +.SH "SYNOPSIS" +\fBwp plugin install\fR <plugin/zip> [\-\-version=\fIversion\fR] [\-\-activate] +. +.SH "OPTIONS" +. +.TP +\fIplugin\fR: +. +.IP +A plugin slug or the path to a zip file\. +. +.TP +\fB\-\-version\fR=\fIversion\fR: +. +.IP +If set, get that particular version from wordpress\.org, instead of the stable version\. +. +.TP +\fB\-\-activate\fR: +. +.IP +If set, the plugin will be activated immediately after install\. +. +.SH "EXAMPLES" +. +.nf + +wp plugin install bbpress \-\-version=2\.1 \-\-activate + +wp plugin install bbpress \-\-version=dev + +wp plugin install \.\./my\-plugin\.zip +. +.fi + diff --git a/man/plugin-path.1 b/man/plugin-path.1 new file mode 100644 index 000000000..cbf20513b --- /dev/null +++ b/man/plugin-path.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-PATH" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. +. +.SH "SYNOPSIS" +\fBwp plugin path\fR [\fIplugin\fR] [\-\-dir] +. +.SH "OPTIONS" +. +.TP +\fB<plugin>\fR: +. +.IP +The plugin to get the path to\. If not set, will return the path to the plugins directory\. +. +.TP +\fB\-\-dir\fR: +. +.IP +If set, get the path to the closest parent directory, instead of the plugin file\. + diff --git a/man/plugin-status.1 b/man/plugin-status.1 new file mode 100644 index 000000000..cbf0900fd --- /dev/null +++ b/man/plugin-status.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-STATUS" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-status\fR \- See the status of one or all plugins\. +. +.SH "SYNOPSIS" +\fBwp plugin status\fR [\fIplugin\fR] +. +.SH "OPTIONS" +. +.TP +\fB<plugin>\fR: +. +.IP +A particular plugin to show the status for\. + diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 new file mode 100644 index 000000000..36a4a599d --- /dev/null +++ b/man/plugin-toggle.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-deactivate\fR \- Activate/Deactivate an installed plugin\. +. +.SH "SYNOPSIS" +\fBwp plugin toggle\fR \fIplugin\fR +. +.SH "OPTIONS" +. +.TP +\fB<plugin>\fR: +. +.IP +The plugin to toggle\. + diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 new file mode 100644 index 000000000..de306138d --- /dev/null +++ b/man/plugin-uninstall.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-UNINSTALL" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-uninstall\fR \- Run the uninstallation procedure for a plugin\. +. +.SH "SYNOPSIS" +\fBwp plugin uninstall\fR \fIplugin\fR +. +.SH "OPTIONS" +. +.TP +\fIplugin\fR: +. +.IP +The plugin to uninstall\. +. +.SH "EXAMPLES" +. +.nf + +wp plugin uninstall hello +. +.fi + diff --git a/man/plugin-update.1 b/man/plugin-update.1 new file mode 100644 index 000000000..63d2c8161 --- /dev/null +++ b/man/plugin-update.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-UPDATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-update\fR \- Update an installed plugin\. +. +.SH "SYNOPSIS" +\fBwp plugin update\fR [\fIplugin\fR] [\-\-all] +. +.SH "OPTIONS" +. +.TP +\fIplugin\fR: +. +.IP +The plugin to update\. Can be omitted when \-\-all is passed\. +. +.TP +\fB\-\-all\fR: +. +.IP +If set, updates for all plugins will be performed\. Use \fBwp plugin status\fR to see which plugins have updates available\. +. +.SH "EXAMPLES" +. +.nf + +wp plugin update bbpress + +wp plugin update \-\-all +. +.fi + diff --git a/man/theme-activate.1 b/man/theme-activate.1 new file mode 100644 index 000000000..0d8c95f48 --- /dev/null +++ b/man/theme-activate.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-ACTIVATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-activate\fR \- Activate an installed theme\. +. +.SH "SYNOPSIS" +\fBwp theme activate\fR \fItheme\fR +. +.SH "OPTIONS" +. +.TP +\fB<theme>\fR: +. +.IP +The theme to activate\. + diff --git a/man/theme-delete.1 b/man/theme-delete.1 new file mode 100644 index 000000000..48f0c8357 --- /dev/null +++ b/man/theme-delete.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-DELETE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-delete\fR \- Delete a theme\. +. +.SH "SYNOPSIS" +\fBwp theme delete\fR \fItheme\fR +. +.SH "OPTIONS" +. +.TP +\fItheme\fR: +. +.IP +The theme to delete\. +. +.SH "EXAMPLES" +. +.nf + +wp theme delete twentyeleven +. +.fi + diff --git a/man/theme-install.1 b/man/theme-install.1 new file mode 100644 index 000000000..6b15db128 --- /dev/null +++ b/man/theme-install.1 @@ -0,0 +1,29 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-INSTALL" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-install\fR \- Install a theme from wordpress\.org or from a zip file\. +. +.SH "SYNOPSIS" +\fBwp theme install\fR <theme/zip> +. +.SH "OPTIONS" +. +.TP +\fItheme\fR: +. +.IP +A theme slug or the path to a zip file\. +. +.SH "EXAMPLES" +. +.nf + +wp theme install twentytwelve + +wp theme install \.\./my\-theme\.zip +. +.fi + diff --git a/man/theme-path.1 b/man/theme-path.1 new file mode 100644 index 000000000..3d806d057 --- /dev/null +++ b/man/theme-path.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-PATH" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. +. +.SH "SYNOPSIS" +\fBwp theme path\fR [\fItheme\fR] [\-\-dir] +. +.SH "OPTIONS" +. +.TP +\fB<theme>\fR: +. +.IP +The theme to get the path to\. If not set, will return the path to the themes directory\. +. +.TP +\fB\-\-dir\fR: +. +.IP +If set, get the path to the closest parent directory, instead of the theme file\. + diff --git a/man/theme-status.1 b/man/theme-status.1 new file mode 100644 index 000000000..2d68b088d --- /dev/null +++ b/man/theme-status.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-STATUS" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-status\fR \- See the status of one or all themes\. +. +.SH "SYNOPSIS" +\fBwp theme status\fR [\fItheme\fR] +. +.SH "OPTIONS" +. +.TP +\fB<theme>\fR: +. +.IP +A particular theme to show the status for\. + diff --git a/man/theme-update.1 b/man/theme-update.1 new file mode 100644 index 000000000..686ccb02a --- /dev/null +++ b/man/theme-update.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-UPDATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-update\fR \- Update an installed theme\. +. +.SH "SYNOPSIS" +\fBwp theme update\fR [\fItheme\fR] [\-\-all] +. +.SH "OPTIONS" +. +.TP +\fItheme\fR: +. +.IP +The theme to update\. Can be omitted when \-\-all is passed\. +. +.TP +\fB\-\-all\fR: +. +.IP +If set, updates for all themes will be performed\. Use \fBwp theme status\fR to see which themes have updates available\. +. +.SH "EXAMPLES" +. +.nf + +wp theme update twentytwelve + +wp theme update \-\-all +. +.fi + diff --git a/man/transient.1 b/man/transient.1 new file mode 100644 index 000000000..d2307b45b --- /dev/null +++ b/man/transient.1 @@ -0,0 +1,48 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TRANSIENT" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-transient\fR \- Manage WordPress transients\. +. +.SH "SYNOPSIS" +wp transient get \fIkey\fR +. +.P +wp transient set \fIkey\fR \fIvalue\fR [\fIexpiration\fR] +. +.P +wp transient delete \fIkey\fR +. +.P +wp transient type +. +.SH "SUBCOMMANDS" +. +.TP +\fBget\fR: +. +.IP +Get a transient value\. +. +.TP +\fBset\fR: +. +.IP +Set a transient value\. \fIexpiration\fR is the time until expiration, in seconds\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a transient value\. +. +.TP +\fBtype\fR: +. +.IP +See wether the transients API is using an object cache or the options table\. +. +.SH "EXAMPLES" +wp transient set my_key my_value 300 diff --git a/man/user-create.1 b/man/user-create.1 new file mode 100644 index 000000000..9f71326f3 --- /dev/null +++ b/man/user-create.1 @@ -0,0 +1,39 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-CREATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-create\fR \- Create a new WordPress user\. +. +.SH "SYNOPSIS" +\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] +. +.SH "OPTIONS" +. +.TP +\fB<user\-login>\fR: +. +.IP +The login of the user to create\. +. +.TP +\fB<user\-email>\fR: +. +.IP +The email address of the user to create\. +. +.TP +\fB\-\-role\fR=\fIrole\fR: +. +.IP +The role of the user to create\. +. +.SH "EXAMPLES" +. +.nf + +wp user create bob bob@example\.com \-\-role=author +. +.fi + diff --git a/man/user-delete.1 b/man/user-delete.1 new file mode 100644 index 000000000..dfab940b6 --- /dev/null +++ b/man/user-delete.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-DELETE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-delete\fR \- Delete a WordPress user\. +. +.SH "SYNOPSIS" +\fBwp user delete\fR \fIID\fR [\-\-reassign=\fIID\fR] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the user to delete\. +. +.TP +\fB\-\-reassign\fR=\fIID\fR: +. +.IP +User to reassign the posts to\. +. +.SH "EXAMPLES" +. +.nf + +wp user delete 123 \-\-reassign=567 +. +.fi + diff --git a/man/user-list.1 b/man/user-list.1 new file mode 100644 index 000000000..1ae1b93b5 --- /dev/null +++ b/man/user-list.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-LIST" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-list\fR \- List WordPress users\. +. +.SH "SYNOPSIS" +\fBwp user list\fR [\-\-role=\fIrole\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-role\fR=\fIrole\fR: +. +.IP +Only display users with a certain role\. + diff --git a/man/user-update.1 b/man/user-update.1 new file mode 100644 index 000000000..c5b8af7f2 --- /dev/null +++ b/man/user-update.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-UPDATE" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-update\fR \- Update a WordPress user\. +. +.SH "SYNOPSIS" +\fBwp user update\fR \fIID\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the user to update\. +. +.TP +\fB\-\-<field>\fR=\fIvalue\fR: +. +.IP +One or more fields to update\. For accepted fields, see wp_update_user()\. +. +.SH "EXAMPLES" +. +.nf + +wp user update 123 \-\-user_login=mary \-\-display_name=Mary +. +.fi + diff --git a/utils/build-doc b/utils/build-doc index 9b8866e41..eaa0b40e1 100755 --- a/utils/build-doc +++ b/utils/build-doc @@ -2,6 +2,7 @@ # generate man pages +rm -rf man mkdir -p man for file in $(ls src/doc/*.txt); do From a66fc1e6c5d561436d2b8421820e024936d4635e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 May 2012 17:20:44 +0300 Subject: [PATCH 0397/5359] use $this->upgrader in plugin install --- src/php/wp-cli/commands/internals/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 13963a78e..c9f119139 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -204,7 +204,7 @@ protected function install_from_repo( $slug, $assoc_args ) { switch ( $status['status'] ) { case 'update_available': case 'install': - $upgrader = WP_CLI::get_upgrader( 'Plugin_Upgrader' ); + $upgrader = WP_CLI::get_upgrader( $this->upgrader ); $result = $upgrader->install( $api->download_link ); if ( $result && isset( $assoc_args['activate'] ) ) { From 015d696b03029778069c69209ada5ad75a9144e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 16:26:17 +0300 Subject: [PATCH 0398/5359] bump version to 0.6.0-dev --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index b932b719f..d4d878ba0 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,7 +4,7 @@ die( 'Only cli access' ); } -define( 'WP_CLI_VERSION', '0.5.0' ); +define( 'WP_CLI_VERSION', '0.6.0-dev' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 9f15ead2d0e873106f3e7029a8ab4c5856019a19 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 17:49:59 +0300 Subject: [PATCH 0399/5359] make WP_CLI::launch() return the exit status --- src/php/wp-cli/class-wp-cli.php | 4 +++- src/php/wp-cli/commands/internals/db.php | 2 +- src/php/wp-cli/commands/internals/help.php | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 5387b4914..c078cbe69 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -152,9 +152,11 @@ static function legend( $legend ) { * Launch an external process, closing the current one * * @param string Command to call + * + * @return int The command exit status */ static function launch( $command ) { - proc_close( proc_open( $command, array( 0 => STDIN, 1 => STDOUT, 2 => STDERR ), $pipes ) ); + return proc_close( proc_open( $command, array( STDIN, STDOUT, STDERR ), $pipes ) ); } /** diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 9239e1811..893407501 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -33,7 +33,7 @@ function connect() { * Open a SQL command-line interface using WordPress's credentials. */ function cli() { - WP_CLI::launch( $this->connect_string() ); + exit( WP_CLI::launch( $this->connect_string() ) ); } /** diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index ae8dc1024..8ca0538e2 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -30,8 +30,7 @@ private function maybe_load_man_page( $args ) { $man_file = $man_dir . implode( '-', $args ) . '.1'; if ( is_readable( $man_file ) ) { - WP_CLI::launch( "man $man_file" ); - exit; + exit( WP_CLI::launch( "man $man_file" ) ); } } } From 86416ae9521689dea98f4a20bc7eb2d5176a5168 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 17:52:13 +0300 Subject: [PATCH 0400/5359] don't run uninstall procedure in wp plugin delete. fixes #109 --- src/php/wp-cli/commands/internals/plugin.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index c9f119139..84d8cd0f9 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -242,20 +242,18 @@ function uninstall( $args ) { } /** - * Delete a plugin + * Delete plugin files * * @param array $args */ function delete( $args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - if ( is_plugin_active( $file ) ) { - WP_CLI::error( 'The plugin is active.' ); - } + $plugin_dir = dirname( $file ); + if ( '.' == $plugin_dir ) + $plugin_dir = $file; - if ( !delete_plugins( array( $file ) ) ) { - WP_CLI::error( 'There was an error while deleting the plugin.' ); - } + exit( WP_CLI::launch( 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ) ) ); } /* PRIVATES */ From a5969570ae2e365d6bd82165f6eb33229bc8e973 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 18:27:08 +0300 Subject: [PATCH 0401/5359] make --admin_password optional. fixes #106 --- src/php/wp-cli/commands/internals/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index e1764c050..add41e059 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -69,11 +69,11 @@ public function install( $args, $assoc_args ) { 'site_title' => '', 'admin_name' => 'admin', 'admin_email' => '', - 'admin_password' => '' + 'admin_password' => wp_generate_password( 12, false ) ) ), EXTR_SKIP ); $missing = false; - foreach ( array( 'site_url', 'site_title', 'admin_email', 'admin_password' ) as $required_arg ) { + foreach ( array( 'site_url', 'site_title', 'admin_email' ) as $required_arg ) { if ( empty( $$required_arg ) ) { WP_CLI::warning( "missing --$required_arg parameter" ); $missing = true; From 7d32c526708ee7774b28c54b0603f8b3104f145a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 19:32:16 +0300 Subject: [PATCH 0402/5359] make WP_CLI_Command_With_Upgrade abstract --- .../wp-cli/class-wp-cli-command-with-upgrade.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index cad2fd1d8..5f4390077 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -1,9 +1,23 @@ <?php -class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { +abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { + + protected $item_type; + protected $upgrader; + protected $upgrade_refresh; + protected $upgrade_transient; protected $default_subcommand = 'status'; + abstract protected function parse_name( $args, $subcommand ); + + abstract protected function get_item_list(); + + abstract protected function status_all(); + abstract protected function status_single( $file, $name ); + + abstract protected function install_from_repo( $slug, $assoc_args ); + /** * Get the status of one or all items * From d4fa0c697849bbf46f2f095f968f400e3514cf9c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 19:51:44 +0300 Subject: [PATCH 0403/5359] add wp plugin update --version=dev. fixes #83 --- src/php/wp-cli/commands/internals/plugin.php | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 84d8cd0f9..3d3e30ee4 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -222,6 +222,21 @@ protected function install_from_repo( $slug, $assoc_args ) { } } + /** + * Update a plugin (to the latest dev version) + * + * @param array $args + * @param array $assoc_args + */ + function update( $args, $assoc_args ) { + if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { + $this->delete( $args, array(), false ); + $this->install( $args, $assoc_args ); + } else { + parent::update( $args, $assoc_args ); + } + } + protected function get_item_list() { return array_keys( get_plugins() ); } @@ -246,14 +261,17 @@ function uninstall( $args ) { * * @param array $args */ - function delete( $args ) { + function delete( $args, $assoc_args = array(), $exit_on_success = true ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $plugin_dir = dirname( $file ); if ( '.' == $plugin_dir ) $plugin_dir = $file; - exit( WP_CLI::launch( 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ) ) ); + $status = WP_CLI::launch( 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ) ); + + if ( $status || $exit_on_success ) + exit( $status ); } /* PRIVATES */ From 132830f305aa77ffa9b04343b7b299b12ae43111 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 20:04:15 +0300 Subject: [PATCH 0404/5359] update docs for wp plugin update. see #83 --- man/plugin-update.1 | 10 ++++++++-- src/doc/plugin-update.txt | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/man/plugin-update.1 b/man/plugin-update.1 index 63d2c8161..a5f21a8eb 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-update\fR \- Update an installed plugin\. . .SH "SYNOPSIS" -\fBwp plugin update\fR [\fIplugin\fR] [\-\-all] +\fBwp plugin update\fR [\fIplugin\fR] [\-\-all] [\-\-version=dev] . .SH "OPTIONS" . @@ -18,6 +18,12 @@ The plugin to update\. Can be omitted when \-\-all is passed\. . .TP +\fB\-\-version=dev\fR: +. +.IP +If set, the plugin will be updated to the latest development version, regardless of what version is currently installed\. Not compatible with \-\-all\. +. +.TP \fB\-\-all\fR: . .IP @@ -27,7 +33,7 @@ If set, updates for all plugins will be performed\. Use \fBwp plugin status\fR t . .nf -wp plugin update bbpress +wp plugin update bbpress \-\-version=dev wp plugin update \-\-all . diff --git a/src/doc/plugin-update.txt b/src/doc/plugin-update.txt index f909d53bf..4be28128b 100644 --- a/src/doc/plugin-update.txt +++ b/src/doc/plugin-update.txt @@ -3,7 +3,7 @@ wp-plugin-update(1) -- Update an installed plugin. ## SYNOPSIS -`wp plugin update` [<plugin>] [--all] +`wp plugin update` [<plugin>] [--all] [--version=dev] ## OPTIONS @@ -11,6 +11,11 @@ wp-plugin-update(1) -- Update an installed plugin. The plugin to update. Can be omitted when --all is passed. +* `--version=dev`: + + If set, the plugin will be updated to the latest development version, +regardless of what version is currently installed. Not compatible with --all. + * `--all`: If set, updates for all plugins will be performed. Use `wp plugin status` @@ -18,6 +23,6 @@ to see which plugins have updates available. ## EXAMPLES - wp plugin update bbpress + wp plugin update bbpress --version=dev wp plugin update --all From 474c2ff7ec35111b329b9f45bf3c02c30d62079e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 5 May 2012 20:05:50 +0300 Subject: [PATCH 0405/5359] rename build-* to *-build --- README.md | 2 +- utils/{build-dev => dev-build} | 0 utils/{build-doc => doc-build} | 0 utils/{build-local => local-build} | 0 utils/{build-pear => pear-build} | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename utils/{build-dev => dev-build} (100%) rename utils/{build-doc => doc-build} (100%) rename utils/{build-local => local-build} (100%) rename utils/{build-pear => pear-build} (100%) diff --git a/README.md b/README.md index e2578d61b..936fd7692 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ sudo pear install wp-cli.github.com/pear/wpcli ```sh git clone --recurse-submodules git://github.com/wp-cli/wp-cli.git ~/git/wp-cli cd ~/git/wp-cli -sudo utils/build-dev +sudo utils/dev-build ``` You can replace `~/git/wp-cli` with whatever you want. diff --git a/utils/build-dev b/utils/dev-build similarity index 100% rename from utils/build-dev rename to utils/dev-build diff --git a/utils/build-doc b/utils/doc-build similarity index 100% rename from utils/build-doc rename to utils/doc-build diff --git a/utils/build-local b/utils/local-build similarity index 100% rename from utils/build-local rename to utils/local-build diff --git a/utils/build-pear b/utils/pear-build similarity index 100% rename from utils/build-pear rename to utils/pear-build From 30ae0109b51c632e49c98e033cfc6a7260d3cab5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 00:38:10 +0300 Subject: [PATCH 0406/5359] let `wp core download` handle case when a WP instance already exists --- src/php/wp-cli/wp-cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index d4d878ba0..0ea4d4ec0 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -51,13 +51,13 @@ define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } +if ( array( 'core', 'download' ) == $arguments ) { + WP_CLI::run_command( $arguments, $assoc_args ); + exit; +} + if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { - if ( array( 'core', 'download' ) == $arguments ) { - WP_CLI::run_command( $arguments, $assoc_args ); - } else { - WP_CLI::error('This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.'); - exit; - } + WP_CLI::error( 'This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.' ); } if ( array( 'core', 'config' ) == $arguments ) { From 6089793c96fdae4c4556b2b0ecf322ff0df6280b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 00:45:46 +0300 Subject: [PATCH 0407/5359] suppress error message when generating autocomplete strings --- src/php/wp-cli/class-wp-cli.php | 5 ++++- src/php/wp-cli/wp-cli.php | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index c078cbe69..66bf874f2 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -46,7 +46,10 @@ static function line( $message = '' ) { * @param string $label */ static function error( $message, $label = 'Error' ) { - \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); + if ( !WP_CLI_AUTOCOMPLETE ) { + \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); + } + exit(1); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 0ea4d4ec0..43e87e472 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -26,7 +26,8 @@ // Get the cli arguments list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); -// Check --silent flag +// Set output levels +define( 'WP_CLI_AUTOCOMPLETE', isset( $assoc_args['completions'] ) ); define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); // Handle --version parameter @@ -112,8 +113,8 @@ unset( $assoc_args['require'] ); } -// Handle --completions parameter -if ( isset( $assoc_args['completions'] ) ) { +// Generate strings for autocomplete +if ( WP_CLI_AUTOCOMPLETE ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { $subcommands = implode( ' ', WP_CLI_Command::get_subcommands( $command ) ); WP_CLI::line( $name . ' ' . $subcommands ); From ae6b539265360303f06fee0be986836561ee56ef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 01:11:15 +0300 Subject: [PATCH 0408/5359] add check_required_args() method and use it for wp core config. see #65 --- src/php/wp-cli/class-wp-cli.php | 24 ++++++++++++++++++++++ src/php/wp-cli/commands/internals/core.php | 15 ++++---------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 66bf874f2..7853c2c88 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -136,6 +136,30 @@ static function compose_args( $args, $assoc_args = array() ) { return $str; } + /** + * Issue warnings for each missing associative argument. + * + * @param array List of required arg names + * @param array Passed args + */ + static function check_required_args( $required, $assoc_args ) { + $missing = false; + + foreach ( $required as $arg ) { + if ( !isset( $assoc_args[ $arg ] ) ) { + WP_CLI::warning( "--$arg parameter is missing" ); + $missing = true; + } elseif ( true === $assoc_args[ $arg ] ) { + // passed as a flag + WP_CLI::warning( "--$arg needs to have a value" ); + $missing = true; + } + } + + if ( $missing ) + exit(1); + } + /** * Display a legend * diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index add41e059..04c87d241 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -44,6 +44,8 @@ public function download( $args, $assoc_args ) { * Set up a wp-config.php file. */ public function config( $args, $assoc_args ) { + WP_CLI::check_required_args( array( 'dbname', 'dbuser', 'dbpass' ), $assoc_args ); + $_POST['dbname'] = $assoc_args['dbname']; $_POST['uname'] = $assoc_args['dbuser']; $_POST['pwd'] = $assoc_args['dbpass']; @@ -64,6 +66,8 @@ public function install( $args, $assoc_args ) { WP_CLI::error( 'WordPress is already installed.' ); } + WP_CLI::check_required_args( array( 'site_url', 'site_title', 'admin_email' ), $assoc_args ); + extract( wp_parse_args( $assoc_args, array( 'site_url' => defined( 'WP_SITEURL' ) ? WP_SITEURL : '', 'site_title' => '', @@ -72,20 +76,9 @@ public function install( $args, $assoc_args ) { 'admin_password' => wp_generate_password( 12, false ) ) ), EXTR_SKIP ); - $missing = false; - foreach ( array( 'site_url', 'site_title', 'admin_email' ) as $required_arg ) { - if ( empty( $$required_arg ) ) { - WP_CLI::warning( "missing --$required_arg parameter" ); - $missing = true; - } - } - if ( $site_url ) WP_CLI::set_url_params( $site_url ); - if ( $missing ) - exit(1); - $public = true; $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); From f07b87cf4cd1633aa0a8ab74345ac2a620a66965 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 02:38:01 +0300 Subject: [PATCH 0409/5359] make wp core config obey the silent flag. see #65 --- src/php/wp-cli/commands/internals/core.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 04c87d241..32a59542a 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -53,7 +53,10 @@ public function config( $args, $assoc_args ) { $_POST['prefix'] = isset( $assoc_args['dbprefix'] ) ? $assoc_args['dbprefix'] : 'wp_'; $_GET['step'] = 2; + + if ( WP_CLI_SILENT ) ob_start(); require WP_ROOT . '/wp-admin/setup-config.php'; + if ( WP_CLI_SILENT ) ob_end_clean(); } /** From 5f58f994489bc56feb3ebbedb8bb7154f06a9734 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 02:38:31 +0300 Subject: [PATCH 0410/5359] exit after executing 'core config' or 'db create' --- src/php/wp-cli/wp-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 43e87e472..96b457cfd 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -63,11 +63,13 @@ if ( array( 'core', 'config' ) == $arguments ) { WP_CLI::run_command( $arguments, $assoc_args ); + exit; } if ( array( 'db', 'create' ) == $arguments ) { WP_CLI::load_wp_config(); WP_CLI::run_command( $arguments, $assoc_args ); + exit; } // Handle --url and --blog parameters From acccc4336dcfd04eff964186c34b4036bd04174e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 02:59:54 +0300 Subject: [PATCH 0411/5359] `wp core install` improvements: * rename --site_url to --url and check for it before loading WP * rename --site_title to --title for consistency --- man/core-install.1 | 6 +++--- src/doc/core-install.txt | 6 +++--- src/php/wp-cli/commands/internals/core.php | 8 +------- src/php/wp-cli/wp-cli.php | 8 +++++--- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/man/core-install.1 b/man/core-install.1 index e8ab09478..b7376703e 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -7,18 +7,18 @@ \fBwp\-core\-install\fR \- Install the WordPress tables in the database\. . .SH "SYNOPSIS" -\fBwp core install\fR \-\-site_url=\fIurl\fR \-\-site_title=\fItitle> [\-\-admin_name=<username\fR] \-\-admin_password=\fIpassword\fR \-\-admin_email=\fIemail\fR +\fBwp core install\fR \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_password=\fIpassword\fR \-\-admin_email=\fIemail\fR . .SH "OPTIONS" . .TP -\fB\-\-site_url\fR=\fIurl\fR: +\fB\-\-url\fR=\fIurl\fR: . .IP The address of the new site\. . .TP -\fB\-\-site_title\fR=<title>: +\fB\-\-title\fR=\fIsite\-title\fR: . .IP The title of the new site\. diff --git a/src/doc/core-install.txt b/src/doc/core-install.txt index 20c14827d..19231e671 100644 --- a/src/doc/core-install.txt +++ b/src/doc/core-install.txt @@ -3,15 +3,15 @@ wp-core-install(1) -- Install the WordPress tables in the database. ## SYNOPSIS -`wp core install` --site_url=<url> --site_title=<title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email> +`wp core install` --url=<url> --title=<site-title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email> ## OPTIONS -* `--site_url`=<url>: +* `--url`=<url>: The address of the new site. -* `--site_title`=<title>: +* `--title`=<site-title>: The title of the new site. diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 32a59542a..fe2b02184 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -69,19 +69,13 @@ public function install( $args, $assoc_args ) { WP_CLI::error( 'WordPress is already installed.' ); } - WP_CLI::check_required_args( array( 'site_url', 'site_title', 'admin_email' ), $assoc_args ); - extract( wp_parse_args( $assoc_args, array( - 'site_url' => defined( 'WP_SITEURL' ) ? WP_SITEURL : '', - 'site_title' => '', + 'title' => '', 'admin_name' => 'admin', 'admin_email' => '', 'admin_password' => wp_generate_password( 12, false ) ) ), EXTR_SKIP ); - if ( $site_url ) - WP_CLI::set_url_params( $site_url ); - $public = true; $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 96b457cfd..fb7700c95 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -72,14 +72,16 @@ exit; } -// Handle --url and --blog parameters -WP_CLI::_set_url( $assoc_args ); - // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == $arguments ) { + WP_CLI::check_required_args( array( 'url', 'title', 'admin_email' ), $assoc_args ); + define( 'WP_INSTALLING', true ); } +// Handle --url and --blog parameters +WP_CLI::_set_url( $assoc_args ); + // Load WordPress require WP_ROOT . 'wp-load.php'; require ABSPATH . 'wp-admin/includes/admin.php'; From 889a5c83a1336493382af75e4e2e1f3fbc680f85 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 03:11:56 +0300 Subject: [PATCH 0412/5359] make wp db create pass along the return status from mysql. see #103 --- src/php/wp-cli/commands/internals/db.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 893407501..b36ad60e1 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -18,8 +18,10 @@ class DB_Command extends WP_CLI_Command { * Creates the database according to the wp-config.php file */ function create() { - exec( sprintf( 'mysql --host="%s" --user="%s" --password="%s" --execute="CREATE DATABASE %s"', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); + exit( WP_CLI::launch( sprintf( + 'mysql --host="%s" --user="%s" --password="%s" --execute="CREATE DATABASE %s"', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + ) ) ); } /** From 16d623a24afda60b09f4d41911866040a7c89957 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 03:15:54 +0300 Subject: [PATCH 0413/5359] use WP_CLI::launch in wp db query --- src/php/wp-cli/commands/internals/db.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index b36ad60e1..2a1f19ca1 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -49,11 +49,9 @@ function query( $args, $assoc_args ) { $query = $args[0]; - $exec = $this->connect_string(); - $exec .= sprintf(' --execute="%s"', $query); + $command = $this->connect_string() . sprintf( ' --execute="%s"', $query ); - $result = exec( $exec ); - WP_CLI::line( $result ); + exit( WP_CLI::launch( $command ) ); } /** From 1bfff0129fac87f6eb576cf8248dcdc022382ada Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 03:23:30 +0300 Subject: [PATCH 0414/5359] use WP_CLI::launch in db export/import --- src/php/wp-cli/commands/internals/db.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 2a1f19ca1..39342fe19 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -60,10 +60,11 @@ function query( $args, $assoc_args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $exec = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', + $command = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - exec( $exec ); + $r = WP_CLI::launch( $command ); + if ( $r ) exit($r); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } @@ -74,10 +75,11 @@ function export( $args, $assoc_args ) { function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $exec = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', + $command = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - exec( $exec ); + $r = WP_CLI::launch( $command ); + if ( $r ) exit($r); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } From 6434b1b7a585327902c250366204c138e94c94b5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 May 2012 03:30:45 +0300 Subject: [PATCH 0415/5359] add exit_on_error parameter to WP_CLI::launch() --- src/php/wp-cli/class-wp-cli.php | 10 ++++++++-- src/php/wp-cli/commands/internals/db.php | 14 ++++++-------- src/php/wp-cli/commands/internals/plugin.php | 7 +++---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 7853c2c88..ace1ed4ab 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -179,11 +179,17 @@ static function legend( $legend ) { * Launch an external process, closing the current one * * @param string Command to call + * @param bool Whether to exit if the command returns an error status * * @return int The command exit status */ - static function launch( $command ) { - return proc_close( proc_open( $command, array( STDIN, STDOUT, STDERR ), $pipes ) ); + static function launch( $command, $exit_on_error = true ) { + $r = proc_close( proc_open( $command, array( STDIN, STDOUT, STDERR ), $pipes ) ); + + if ( $r && $exit_on_error ) + exit($r); + + return $r; } /** diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 39342fe19..f27583370 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -18,10 +18,10 @@ class DB_Command extends WP_CLI_Command { * Creates the database according to the wp-config.php file */ function create() { - exit( WP_CLI::launch( sprintf( + WP_CLI::launch( sprintf( 'mysql --host="%s" --user="%s" --password="%s" --execute="CREATE DATABASE %s"', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME - ) ) ); + ) ); } /** @@ -35,7 +35,7 @@ function connect() { * Open a SQL command-line interface using WordPress's credentials. */ function cli() { - exit( WP_CLI::launch( $this->connect_string() ) ); + WP_CLI::launch( $this->connect_string() ); } /** @@ -51,7 +51,7 @@ function query( $args, $assoc_args ) { $command = $this->connect_string() . sprintf( ' --execute="%s"', $query ); - exit( WP_CLI::launch( $command ) ); + WP_CLI::launch( $command ); } /** @@ -63,8 +63,7 @@ function export( $args, $assoc_args ) { $command = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - $r = WP_CLI::launch( $command ); - if ( $r ) exit($r); + WP_CLI::launch( $command ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } @@ -78,8 +77,7 @@ function import( $args, $assoc_args ) { $command = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - $r = WP_CLI::launch( $command ); - if ( $r ) exit($r); + WP_CLI::launch( $command ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 3d3e30ee4..5c8b4e36e 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -261,17 +261,16 @@ function uninstall( $args ) { * * @param array $args */ - function delete( $args, $assoc_args = array(), $exit_on_success = true ) { + function delete( $args, $assoc_args = array(), $exit_on_error = true ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $plugin_dir = dirname( $file ); if ( '.' == $plugin_dir ) $plugin_dir = $file; - $status = WP_CLI::launch( 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ) ); + $command = 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ); - if ( $status || $exit_on_success ) - exit( $status ); + return WP_CLI::launch( $command, $exit_on_error ); } /* PRIVATES */ From 493437818224e89f39bbc80156169ec05683663b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 01:35:19 +0300 Subject: [PATCH 0416/5359] check --path before $_SERVER['PWD']. fixes #111 --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index fb7700c95..2dfc0620a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -43,11 +43,11 @@ } // Define the WordPress location -if ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { - define( 'WP_ROOT', $_SERVER['PWD'] . '/../' ); -} elseif ( !empty( $assoc_args['path'] ) ) { +if ( !empty( $assoc_args['path'] ) ) { // trailingslashit() isn't available yet define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); +} elseif ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { + define( 'WP_ROOT', $_SERVER['PWD'] . '/../' ); } else { define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } From cb769a1034944cc0e980cb38c74fb5182e0369af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 02:12:41 +0300 Subject: [PATCH 0417/5359] use escapeshellarg() in WP_CLI::compose_args() --- src/php/wp-cli/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index ace1ed4ab..d9e163ed0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -124,13 +124,13 @@ static function parse_args( $arguments ) { * @return string */ static function compose_args( $args, $assoc_args = array() ) { - $str = implode( ' ', $args ); + $str = implode( ' ', array_map( 'escapeshellarg', $args ) ); foreach ( $assoc_args as $key => $value ) { if ( true == $value ) $str .= " --$key"; else - $str .= " --$key=$value"; + $str .= " --$key=" . escapeshellarg( $value ); } return $str; From 0bb8d05decf2c50d69a6a4ac2046cdf267d616f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 02:31:07 +0300 Subject: [PATCH 0418/5359] strict bool check in compose_args() --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d9e163ed0..255f1e8a4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -127,7 +127,7 @@ static function compose_args( $args, $assoc_args = array() ) { $str = implode( ' ', array_map( 'escapeshellarg', $args ) ); foreach ( $assoc_args as $key => $value ) { - if ( true == $value ) + if ( true === $value ) $str .= " --$key"; else $str .= " --$key=" . escapeshellarg( $value ); From c5c132ad37e7603d4ffe3a3b8a59917783a8c127 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 02:34:47 +0300 Subject: [PATCH 0419/5359] add leading space to output of compose_args() --- src/php/wp-cli/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 255f1e8a4..f5d0f6f4e 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -118,13 +118,13 @@ static function parse_args( $arguments ) { } /** - * Composes positional and associative arguments into a string + * Composes positional and associative arguments into a string. * * @param array * @return string */ static function compose_args( $args, $assoc_args = array() ) { - $str = implode( ' ', array_map( 'escapeshellarg', $args ) ); + $str = ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); foreach ( $assoc_args as $key => $value ) { if ( true === $value ) From b002243dfca2da691ab4a3a9086d98344145a66e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 02:52:44 +0300 Subject: [PATCH 0420/5359] make wp plugin install return error status when it fails --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 5f4390077..fcd334658 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -63,6 +63,8 @@ function install( $args, $assoc_args ) { WP_CLI::line( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } + } else { + exit(1); } } else { $this->install_from_repo( $slug, $assoc_args ); From e59998d0c60b90c6c5779d290ce491b7103f577c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 03:31:24 +0300 Subject: [PATCH 0421/5359] pass correct title variable to wp_install() --- src/php/wp-cli/commands/internals/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index fe2b02184..6a61606e2 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -78,7 +78,7 @@ public function install( $args, $assoc_args ) { $public = true; - $result = wp_install( $site_title, $admin_name, $admin_email, $public, '', $admin_password ); + $result = wp_install( $title, $admin_name, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); From f1cce451689b3de19806b8b266c705499b3fad70 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 May 2012 03:34:33 +0300 Subject: [PATCH 0422/5359] introduce wp db drop --- src/php/wp-cli/commands/internals/db.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index f27583370..6cb1764b6 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -15,7 +15,7 @@ class DB_Command extends WP_CLI_Command { protected $aliases = array( 'dump' => 'export' ); /** - * Creates the database according to the wp-config.php file + * Creates the database specified in the wp-config.php file. */ function create() { WP_CLI::launch( sprintf( @@ -24,6 +24,16 @@ function create() { ) ); } + /** + * Deletes the database specified in the wp-config.php file. + */ + function drop() { + WP_CLI::launch( sprintf( + 'mysql --host="%s" --user="%s" --password="%s" --execute="DROP DATABASE %s"', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + ) ); + } + /** * Print a string for connecting to the DB. */ From 34f37ce18f403fc6efeea9adb96f466a71bfab64 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 14 May 2012 04:14:17 +0300 Subject: [PATCH 0423/5359] ask for confirmation before dropping the database --- src/php/wp-cli/commands/internals/db.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 6cb1764b6..30f9e9e52 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -27,11 +27,22 @@ function create() { /** * Deletes the database specified in the wp-config.php file. */ - function drop() { + function drop( $args, $assoc_args ) { + if ( !isset( $assoc_args['really'] ) ) { + WP_CLI::out( "Are you sure you want to drop the database? [y/n] " ); + + $answer = trim( fgets( STDIN ) ); + + if ( 'y' != $answer ) + return; + } + WP_CLI::launch( sprintf( 'mysql --host="%s" --user="%s" --password="%s" --execute="DROP DATABASE %s"', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); + + WP_CLI::success( "Database dropped." ); } /** From 25fb157943f966153c41399d353592066d2405c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 14 May 2012 04:17:18 +0300 Subject: [PATCH 0424/5359] add man page for db drop --- man/db-drop.1 | 19 +++++++++++++++++++ src/doc/db-drop.txt | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 man/db-drop.1 create mode 100644 src/doc/db-drop.txt diff --git a/man/db-drop.1 b/man/db-drop.1 new file mode 100644 index 000000000..3a370feb8 --- /dev/null +++ b/man/db-drop.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-DROP" "1" "May 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-drop\fR \- Drop the database specified in wp\-config\.php +. +.SH "SYNOPSIS" +\fBwp db drop\fR [\-\-really] +. +.SH "OPTIONS" +. +.TP +\fB\-\-really\fR: +. +.IP +Skip the confirmation messaje\. + diff --git a/src/doc/db-drop.txt b/src/doc/db-drop.txt new file mode 100644 index 000000000..074b14123 --- /dev/null +++ b/src/doc/db-drop.txt @@ -0,0 +1,12 @@ +wp-db-drop(1) -- Drop the database specified in wp-config.php +==== + +## SYNOPSIS + +`wp db drop` [--really] + +## OPTIONS + +* `--really`: + + Skip the confirmation messaje. From fc56284718a1a309cacf20b0cf5f4188c2ffc940 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 15 May 2012 21:09:55 +0300 Subject: [PATCH 0425/5359] warning() should write to STDERR, not STDOUT --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index f5d0f6f4e..e990f29a9 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -72,7 +72,7 @@ static function success( $message, $label = 'Success' ) { */ static function warning( $message, $label = 'Warning' ) { if ( WP_CLI_SILENT ) return; - \cli\line( '%C' . $label . ': %n' . self::error_to_string( $message ) ); + \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } /** From 859c7850ee7b5bae8c0794384a8bf8bbee35354f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 17 May 2012 03:39:04 +0300 Subject: [PATCH 0426/5359] make git clone command compatible with older versions of git. props jasonblewis --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 936fd7692..92835f7e7 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ sudo pear install wp-cli.github.com/pear/wpcli **Via GIT:** ```sh -git clone --recurse-submodules git://github.com/wp-cli/wp-cli.git ~/git/wp-cli +git clone --recursive git://github.com/wp-cli/wp-cli.git ~/git/wp-cli cd ~/git/wp-cli sudo utils/dev-build ``` From 7dcf532b802588fc0b015c66fd223a9579517593 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 18 May 2012 19:43:54 +0300 Subject: [PATCH 0427/5359] add locale parameter to wp core download. fixes #112 --- src/php/wp-cli/commands/internals/core.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 6a61606e2..5805fced2 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -22,10 +22,17 @@ public function download( $args, $assoc_args ) { else $docroot = './'; - if ( isset( $assoc_args['version'] ) ) { + if ( isset( $assoc_args['locale'] ) ) { + exec( 'curl -s ' . escapeshellarg( 'http://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); + if ($r) exit($r); + $download_url = $lines[2]; + WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $lines[3], $lines[4] ) ); + } elseif ( isset( $assoc_args['version'] ) ) { $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $download_url = 'http://wordpress.org/latest.zip'; + WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } $silent = ''; From e0654744f0e08aff8620c511a32d005f33ab8c16 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 18 May 2012 19:44:05 +0300 Subject: [PATCH 0428/5359] update docs. see #112 --- man/core-download.1 | 8 +++++++- src/doc/core-download.txt | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/man/core-download.1 b/man/core-download.1 index 95d38d781..8d4e9f8e6 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -7,11 +7,17 @@ \fBwp\-core\-download\fR \- Download core WordPress files\. . .SH "SYNOPSIS" -\fBwp core download\fR [\-\-version=\fIversion\fR] +\fBwp core download\fR [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] . .SH "OPTIONS" . .TP +\fB\-\-locale\fR=\fIlocale\fR: +. +.IP +Select which language you want to download\. The \-\-version parameter is ignored in this case\. +. +.TP \fB\-\-version\fR=\fIversion\fR: . .IP diff --git a/src/doc/core-download.txt b/src/doc/core-download.txt index fe858f152..7fbaee097 100644 --- a/src/doc/core-download.txt +++ b/src/doc/core-download.txt @@ -3,10 +3,15 @@ wp-core-download(1) -- Download core WordPress files. ## SYNOPSIS -`wp core download` [--version=<version>] +`wp core download` [--locale=<locale>] [--version=<version>] ## OPTIONS +* `--locale`=<locale>: + + Select which language you want to download. The --version parameter is +ignored in this case. + * `--version`=<version>: Select which version you want to download. From 2526aa89343cf30abf65c241898f38623d4c930a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 18 May 2012 19:48:04 +0300 Subject: [PATCH 0429/5359] use WP_CLI_SILENT constant instead of arg --- src/php/wp-cli/commands/internals/core.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 5805fced2..e24ac1745 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -35,9 +35,7 @@ public function download( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - $silent = ''; - if( !empty( $assoc_args['silent'] ) ) - $silent = '--silent '; + $silent = WP_CLI_SILENT ? '--silent ' : ''; WP_CLI::line('Downloading WordPress...'); exec("curl {$silent}http://wordpress.org/latest.zip > /tmp/wordpress.zip"); From 148bf8008047d8cffd1ba7ae5b7684311f425808 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 18 May 2012 20:04:25 +0300 Subject: [PATCH 0430/5359] wp core download fixes: * actually use $download_url instead of always downloading the latest * use WP_CLI::launch() to prevent an error from cascading * pass -f to curl so that it returns an error message on 404 see #112 --- src/php/wp-cli/commands/internals/core.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index e24ac1745..27deec66e 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -17,7 +17,7 @@ public function download( $args, $assoc_args ) { if ( is_readable( WP_ROOT . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); - if (isset($assoc_args['path'])) + if ( isset( $assoc_args['path'] ) ) $docroot = $assoc_args['path']; else $docroot = './'; @@ -35,14 +35,12 @@ public function download( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - $silent = WP_CLI_SILENT ? '--silent ' : ''; + WP_CLI::launch( 'curl -f' . (WP_CLI_SILENT ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' > /tmp/wordpress.zip' ); + WP_CLI::launch( 'unzip ' . (WP_CLI_SILENT ? '-qq ' : '-q ') . '/tmp/wordpress.zip' ); + WP_CLI::launch( 'mv wordpress/* ' . escapeshellarg( $docroot ) ); + WP_CLI::launch( 'rm -r wordpress' ); - WP_CLI::line('Downloading WordPress...'); - exec("curl {$silent}http://wordpress.org/latest.zip > /tmp/wordpress.zip"); - exec("unzip /tmp/wordpress.zip"); - exec("mv wordpress/* $docroot"); - exec("rm -r wordpress"); - WP_CLI::success('WordPress downloaded.'); + WP_CLI::success( 'WordPress downloaded.' ); } /** From e0bcd0fc70763db5ddea8fd2972819fe16aa3007 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 May 2012 21:30:21 +0300 Subject: [PATCH 0431/5359] don't ignore --url param when calling wp db create. see #103 --- src/php/wp-cli/wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 2dfc0620a..6fc69e506 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -52,6 +52,9 @@ define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } +// Handle --url and --blog parameters +WP_CLI::_set_url( $assoc_args ); + if ( array( 'core', 'download' ) == $arguments ) { WP_CLI::run_command( $arguments, $assoc_args ); exit; @@ -79,9 +82,6 @@ define( 'WP_INSTALLING', true ); } -// Handle --url and --blog parameters -WP_CLI::_set_url( $assoc_args ); - // Load WordPress require WP_ROOT . 'wp-load.php'; require ABSPATH . 'wp-admin/includes/admin.php'; From 8b81cb29634daaff82dbd949018e6a0f1f9a7980 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 May 2012 21:43:05 +0300 Subject: [PATCH 0432/5359] make wp db import work without loading WP. fixes #116 --- src/php/wp-cli/wp-cli.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 6fc69e506..ed2a2da56 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -75,6 +75,12 @@ exit; } +if ( array( 'db', 'import' ) == array_slice( $arguments, 0, 2 ) ) { + WP_CLI::load_wp_config(); + WP_CLI::run_command( $arguments, $assoc_args ); + exit; +} + // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == $arguments ) { WP_CLI::check_required_args( array( 'url', 'title', 'admin_email' ), $assoc_args ); From e989c8cf733d5bbea88ea429c2522c141280297c Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 10:29:58 +0100 Subject: [PATCH 0433/5359] Add command to update a meta field for a user --- src/php/wp-cli/commands/internals/user.php | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 7515979d4..34df9cc24 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -156,4 +156,32 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } + + /** + * Update meta field for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function update_meta( $args, $assoc_args ) { + $user_id = $args[0]; + $meta_key = $args[1]; + $meta_value = $args[2]; + + if ( ! is_numeric($user_id) ) { + WP_CLI::error( "User ID required (see 'wp user help')." ); + } + + if ( ! $meta_key || ! $meta_value ) { + WP_CLI:error( "meta_key and meta_value required (see 'wp user help')."); + } + + $success = update_user_meta( $user_id, $meta_key, $meta_value ); + + if ( $success ) { + WP_CLI::success( "Updated user $user_id." ); + } else { + WP_CLI::error( "Failed to update meta field" ); + } + } } From c3a8bbd5d7cdf95de9a3ae69c9ef7c02258d631c Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 10:33:48 +0100 Subject: [PATCH 0434/5359] Factor out duplicated error message string --- src/php/wp-cli/commands/internals/user.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 34df9cc24..2c70241dd 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -63,7 +63,7 @@ public function delete( $args, $assoc_args ) { $user_id = $args[0]; if ( ! is_numeric($user_id) ) { - WP_CLI::error("User ID required (see 'wp user help')"); + self::error_see_help( "User ID required" ); } $defaults = array( 'reassign' => NULL ); @@ -90,7 +90,7 @@ public function create( $args, $assoc_args ) { $user_email = $args[1]; if ( ! $user_login || ! $user_email ) { - WP_CLI::error("Login and email required (see 'wp user help')."); + self::error_see_help( "Login and email required" ); } $defaults = array( @@ -139,7 +139,7 @@ public function update( $args, $assoc_args ) { $user_id = $args[0]; if ( ! is_numeric($user_id) ) { - WP_CLI::error( "User ID required (see 'wp user help')." ); + self::error_see_help( "User ID required" ); } if ( empty( $assoc_args ) ) { @@ -169,11 +169,11 @@ public function update_meta( $args, $assoc_args ) { $meta_value = $args[2]; if ( ! is_numeric($user_id) ) { - WP_CLI::error( "User ID required (see 'wp user help')." ); + self::error_see_help( "User ID required" ); } if ( ! $meta_key || ! $meta_value ) { - WP_CLI:error( "meta_key and meta_value required (see 'wp user help')."); + self::error_see_help( "meta_key and meta_value required"); } $success = update_user_meta( $user_id, $meta_key, $meta_value ); @@ -184,4 +184,8 @@ public function update_meta( $args, $assoc_args ) { WP_CLI::error( "Failed to update meta field" ); } } + + private function error_see_help( $message ) { + WP_CLI::error( "$message (see 'wp user help')."); + } } From 534d7b922d6ec93aa5f442d1e3d2160ffd27b4d5 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 10:39:49 +0100 Subject: [PATCH 0435/5359] Factor out code to retrieve args in update_meta --- src/php/wp-cli/commands/internals/user.php | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 2c70241dd..2c124b0e6 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -164,17 +164,9 @@ public function update( $args, $assoc_args ) { * @param array $assoc_args **/ public function update_meta( $args, $assoc_args ) { - $user_id = $args[0]; - $meta_key = $args[1]; - $meta_value = $args[2]; - - if ( ! is_numeric($user_id) ) { - self::error_see_help( "User ID required" ); - } - - if ( ! $meta_key || ! $meta_value ) { - self::error_see_help( "meta_key and meta_value required"); - } + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $meta_key = self::get_arg_or_error($args, 1, "meta_key");; + $meta_value = self::get_arg_or_error($args, 2, "meta_value");; $success = update_user_meta( $user_id, $meta_key, $meta_value ); @@ -185,6 +177,22 @@ public function update_meta( $args, $assoc_args ) { } } + private function get_numeric_arg_or_error( $args, $index, $name ) { + $value = self::get_arg_or_error( $args, $index, $name ); + if ( ! is_numeric( $value ) ) { + self::error_see_help( "$name must be numeric" ); + } + return $value; + } + + private function get_arg_or_error( $args, $index, $name ) { + $value = $args[$index]; + if ( ! $value ) { + self::error_see_help( "$name required" ); + } + return $value; + } + private function error_see_help( $message ) { WP_CLI::error( "$message (see 'wp user help')."); } From 487f5c7ffcfb4d5313e42b1b63a4b29ff59e7bd4 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 10:41:20 +0100 Subject: [PATCH 0436/5359] Factor out fetching user ID from $args --- src/php/wp-cli/commands/internals/user.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 2c124b0e6..1b408dc36 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -59,12 +59,8 @@ public function _list( $args, $assoc_args ) { **/ public function delete( $args, $assoc_args ) { global $blog_id; - - $user_id = $args[0]; - - if ( ! is_numeric($user_id) ) { - self::error_see_help( "User ID required" ); - } + + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); $defaults = array( 'reassign' => NULL ); @@ -136,11 +132,7 @@ public function create( $args, $assoc_args ) { * @param array $assoc_args **/ public function update( $args, $assoc_args ) { - $user_id = $args[0]; - - if ( ! is_numeric($user_id) ) { - self::error_see_help( "User ID required" ); - } + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); if ( empty( $assoc_args ) ) { WP_CLI::error( "Need some fields to update." ); From 900f62515fc772a92f640b4bb64885d7af24db43 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 10:53:56 +0100 Subject: [PATCH 0437/5359] Add man page for user update_meta --- src/doc/user-update_meta.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/doc/user-update_meta.txt diff --git a/src/doc/user-update_meta.txt b/src/doc/user-update_meta.txt new file mode 100644 index 000000000..74616807d --- /dev/null +++ b/src/doc/user-update_meta.txt @@ -0,0 +1,24 @@ +wp-user-update_meta(1) -- Update a meta field for a WordPress user. +==== + +## SYNOPSIS + +`wp user update_meta` <ID> <meta_key> <meta_value> + +## OPTIONS + +* `<ID>`: + + The ID of the user to update. + +* meta_key: + + The meta_key to be updated + +* meta_value: + + The new desired value of the meta_key + +## EXAMPLES + + wp user update_meta 123 description "Mary is a WordPress developer" From cd96aabb2882d02bc6ddb9e876f0829aae96017b Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 11:37:28 +0100 Subject: [PATCH 0438/5359] Use isset to check if an argument exists --- src/php/wp-cli/commands/internals/user.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 1b408dc36..2b6739821 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -178,11 +178,10 @@ private function get_numeric_arg_or_error( $args, $index, $name ) { } private function get_arg_or_error( $args, $index, $name ) { - $value = $args[$index]; - if ( ! $value ) { + if ( ! isset( $args[$index] ) ) { self::error_see_help( "$name required" ); } - return $value; + return $args[$index]; } private function error_see_help( $message ) { From a06cb5dcb872d5bc3888bce47b09b533139a1167 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 31 May 2012 13:11:47 +0100 Subject: [PATCH 0439/5359] Change "wp user update_meta" to "wp user-meta set" --- src/doc/user-meta-set.txt | 24 +++++++++ src/doc/user-update_meta.txt | 24 --------- .../wp-cli/commands/internals/user-meta.php | 51 +++++++++++++++++++ src/php/wp-cli/commands/internals/user.php | 20 -------- 4 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 src/doc/user-meta-set.txt delete mode 100644 src/doc/user-update_meta.txt create mode 100644 src/php/wp-cli/commands/internals/user-meta.php diff --git a/src/doc/user-meta-set.txt b/src/doc/user-meta-set.txt new file mode 100644 index 000000000..b40cc0cc4 --- /dev/null +++ b/src/doc/user-meta-set.txt @@ -0,0 +1,24 @@ +wp-user-meta-set(1) -- Update a meta field for a WordPress user. +==== + +## SYNOPSIS + +`wp user-meta set` <ID> <meta_key> <meta_value> + +## OPTIONS + +* `<ID>`: + + The ID of the user to update. + +* meta_key: + + The meta_key to be updated + +* meta_value: + + The new desired value of the meta_key + +## EXAMPLES + + wp user-meta set 123 description "Mary is a WordPress developer" diff --git a/src/doc/user-update_meta.txt b/src/doc/user-update_meta.txt deleted file mode 100644 index 74616807d..000000000 --- a/src/doc/user-update_meta.txt +++ /dev/null @@ -1,24 +0,0 @@ -wp-user-update_meta(1) -- Update a meta field for a WordPress user. -==== - -## SYNOPSIS - -`wp user update_meta` <ID> <meta_key> <meta_value> - -## OPTIONS - -* `<ID>`: - - The ID of the user to update. - -* meta_key: - - The meta_key to be updated - -* meta_value: - - The new desired value of the meta_key - -## EXAMPLES - - wp user update_meta 123 description "Mary is a WordPress developer" diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php new file mode 100644 index 000000000..7636eff27 --- /dev/null +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -0,0 +1,51 @@ +<?php + +WP_CLI::add_command('user-meta', 'User_Meta_Command'); + +/** + * Implement user command + * + * @package wp-cli + * @subpackage commands/internals + */ +class User_Meta_Command extends WP_CLI_Command { + /** + * Update meta field for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function set( $args, $assoc_args ) { + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $meta_key = self::get_arg_or_error($args, 1, "meta_key");; + $meta_value = self::get_arg_or_error($args, 2, "meta_value");; + + $success = update_user_meta( $user_id, $meta_key, $meta_value ); + + if ( $success ) { + WP_CLI::success( "Updated user $user_id." ); + } else { + WP_CLI::error( "Failed to set meta field" ); + } + } + + private function get_numeric_arg_or_error( $args, $index, $name ) { + $value = self::get_arg_or_error( $args, $index, $name ); + if ( ! is_numeric( $value ) ) { + self::error_see_help( "$name must be numeric" ); + } + return $value; + } + + private function get_arg_or_error( $args, $index, $name ) { + if ( ! isset( $args[$index] ) ) { + self::error_see_help( "$name required" ); + } + return $args[$index]; + } + + private function error_see_help( $message ) { + WP_CLI::error( "$message (see 'wp user-meta help')."); + } +} + diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 2b6739821..2c9a6238b 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -148,26 +148,6 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } - - /** - * Update meta field for a user - * - * @param array $args - * @param array $assoc_args - **/ - public function update_meta( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key");; - $meta_value = self::get_arg_or_error($args, 2, "meta_value");; - - $success = update_user_meta( $user_id, $meta_key, $meta_value ); - - if ( $success ) { - WP_CLI::success( "Updated user $user_id." ); - } else { - WP_CLI::error( "Failed to update meta field" ); - } - } private function get_numeric_arg_or_error( $args, $index, $name ) { $value = self::get_arg_or_error( $args, $index, $name ); From 5a69b91b5458365858a8b716496c3734f9604414 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Jun 2012 11:59:22 +0300 Subject: [PATCH 0440/5359] generate man page. see #117 --- man/user-meta-set.1 | 33 +++++++++++++++++++ src/doc/user-meta-set.txt | 14 ++++---- .../wp-cli/commands/internals/user-meta.php | 6 ++-- 3 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 man/user-meta-set.1 diff --git a/man/user-meta-set.1 b/man/user-meta-set.1 new file mode 100644 index 000000000..8786c90b8 --- /dev/null +++ b/man/user-meta-set.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META\-SET" "1" "June 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\-set\fR \- Update a meta field for a WordPress user\. +. +.SH "SYNOPSIS" +\fBwp user\-meta set\fR \fIID\fR \fImeta_key\fR \fImeta_value\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the user to update\. +. +.TP +\fB<meta_key>\fR: +. +.IP +The meta_key to be updated\. +. +.TP +\fB<meta_value>\fR: +. +.IP +The new desired value of the meta_key\. +. +.SH "EXAMPLES" +wp user\-meta set 123 description "Mary is a WordPress developer\." diff --git a/src/doc/user-meta-set.txt b/src/doc/user-meta-set.txt index b40cc0cc4..3140f4a1b 100644 --- a/src/doc/user-meta-set.txt +++ b/src/doc/user-meta-set.txt @@ -11,14 +11,14 @@ wp-user-meta-set(1) -- Update a meta field for a WordPress user. The ID of the user to update. -* meta_key: +* `<meta_key>`: - The meta_key to be updated - -* meta_value: - - The new desired value of the meta_key + The meta_key to be updated. + +* `<meta_value>`: + + The new desired value of the meta_key. ## EXAMPLES - wp user-meta set 123 description "Mary is a WordPress developer" +wp user-meta set 123 description "Mary is a WordPress developer." diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index 7636eff27..ce602b537 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -28,7 +28,7 @@ public function set( $args, $assoc_args ) { WP_CLI::error( "Failed to set meta field" ); } } - + private function get_numeric_arg_or_error( $args, $index, $name ) { $value = self::get_arg_or_error( $args, $index, $name ); if ( ! is_numeric( $value ) ) { @@ -36,14 +36,14 @@ private function get_numeric_arg_or_error( $args, $index, $name ) { } return $value; } - + private function get_arg_or_error( $args, $index, $name ) { if ( ! isset( $args[$index] ) ) { self::error_see_help( "$name required" ); } return $args[$index]; } - + private function error_see_help( $message ) { WP_CLI::error( "$message (see 'wp user-meta help')."); } From 73a86f059842d2b2ed40637abab38ea4670f2455 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Jun 2012 12:05:49 +0300 Subject: [PATCH 0441/5359] introduce WP_CLI::print_value() --- src/php/wp-cli/class-wp-cli.php | 13 +++++++++++++ src/php/wp-cli/commands/internals/option.php | 6 +----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index e990f29a9..d16470d80 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -75,6 +75,19 @@ static function warning( $message, $label = 'Warning' ) { \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } + /** + * Display an easy to paste PHP value. + * + * @param string $message + */ + static function print_value( $value ) { + if ( is_array( $value ) || is_object( $value ) ) { + echo var_export( $value ) . "\n"; + } else { + echo $value . "\n"; + } + } + /** * Convert a wp_error into a string * diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 79825b4b2..53a3a3372 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -85,10 +85,6 @@ public function get( $args ) { if ( false === $value ) return; - if ( is_array( $value ) || is_object( $value ) ) { - echo var_export( $value ) . "\n"; - } else { - echo $value . "\n"; - } + WP_CLI::print_value( $value ); } } From 33fb1c6d9d39540e1a804201c6f2d7f58b9f5f0d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Jun 2012 12:10:04 +0300 Subject: [PATCH 0442/5359] add user-meta get. see #117 --- src/php/wp-cli/commands/internals/option.php | 2 +- .../wp-cli/commands/internals/user-meta.php | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 53a3a3372..955efb5f0 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -83,7 +83,7 @@ public function get( $args ) { $value = get_option( $key ); if ( false === $value ) - return; + die(1); WP_CLI::print_value( $value ); } diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index ce602b537..bf263bcce 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -9,6 +9,25 @@ * @subpackage commands/internals */ class User_Meta_Command extends WP_CLI_Command { + + /** + * Get meta field value for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function get( $args, $assoc_args ) { + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $meta_key = self::get_arg_or_error($args, 1, "meta_key"); + + $value = get_user_meta( $user_id, $meta_key, true ); + + if ( '' === $value ) + die(1); + + WP_CLI::print_value( $value ); + } + /** * Update meta field for a user * @@ -17,8 +36,8 @@ class User_Meta_Command extends WP_CLI_Command { **/ public function set( $args, $assoc_args ) { $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key");; - $meta_value = self::get_arg_or_error($args, 2, "meta_value");; + $meta_key = self::get_arg_or_error($args, 1, "meta_key"); + $meta_value = self::get_arg_or_error($args, 2, "meta_value"); $success = update_user_meta( $user_id, $meta_key, $meta_value ); From 94c2cdecac36a553c9573deecf28028cf8e67d97 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Jun 2012 12:19:27 +0300 Subject: [PATCH 0443/5359] Complete user-meta command: * rename 'user-meta set' to 'user-meta update' * add 'user-meta add' and 'user-meta delete' See #117 --- man/user-meta-set.1 | 33 ------------ man/user-meta.1 | 54 +++++++++++++++++++ src/doc/user-meta-set.txt | 24 --------- src/doc/user-meta.txt | 34 ++++++++++++ .../wp-cli/commands/internals/user-meta.php | 45 ++++++++++++++-- 5 files changed, 130 insertions(+), 60 deletions(-) delete mode 100644 man/user-meta-set.1 create mode 100644 man/user-meta.1 delete mode 100644 src/doc/user-meta-set.txt create mode 100644 src/doc/user-meta.txt diff --git a/man/user-meta-set.1 b/man/user-meta-set.1 deleted file mode 100644 index 8786c90b8..000000000 --- a/man/user-meta-set.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META\-SET" "1" "June 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\-set\fR \- Update a meta field for a WordPress user\. -. -.SH "SYNOPSIS" -\fBwp user\-meta set\fR \fIID\fR \fImeta_key\fR \fImeta_value\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the user to update\. -. -.TP -\fB<meta_key>\fR: -. -.IP -The meta_key to be updated\. -. -.TP -\fB<meta_value>\fR: -. -.IP -The new desired value of the meta_key\. -. -.SH "EXAMPLES" -wp user\-meta set 123 description "Mary is a WordPress developer\." diff --git a/man/user-meta.1 b/man/user-meta.1 new file mode 100644 index 000000000..a3429e987 --- /dev/null +++ b/man/user-meta.1 @@ -0,0 +1,54 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META" "1" "June 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\fR \- Manage user custom fields\. +. +.SH "SYNOPSIS" +wp user\-meta get \fIID\fR \fIkey\fR +. +.P +wp user\-meta add \fIID\fR \fIkey\fR \fIvalue\fR +. +.P +wp user\-meta update \fIID\fR \fIkey\fR \fIvalue\fR +. +.P +wp user\-meta delete \fIID\fR \fIkey\fR +. +.SH "SUBCOMMANDS" +. +.TP +\fBget\fR: +. +.IP +Get a custom field value\. +. +.TP +\fBadd\fR: +. +.IP +Add a new custom field\. +. +.TP +\fBupdate\fR: +. +.IP +Update an existing custom field\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a custom field\. +. +.SH "EXAMPLES" +. +.nf + +wp user\-meta set 123 description "Mary is a WordPress developer\." +. +.fi + diff --git a/src/doc/user-meta-set.txt b/src/doc/user-meta-set.txt deleted file mode 100644 index 3140f4a1b..000000000 --- a/src/doc/user-meta-set.txt +++ /dev/null @@ -1,24 +0,0 @@ -wp-user-meta-set(1) -- Update a meta field for a WordPress user. -==== - -## SYNOPSIS - -`wp user-meta set` <ID> <meta_key> <meta_value> - -## OPTIONS - -* `<ID>`: - - The ID of the user to update. - -* `<meta_key>`: - - The meta_key to be updated. - -* `<meta_value>`: - - The new desired value of the meta_key. - -## EXAMPLES - -wp user-meta set 123 description "Mary is a WordPress developer." diff --git a/src/doc/user-meta.txt b/src/doc/user-meta.txt new file mode 100644 index 000000000..1825c508c --- /dev/null +++ b/src/doc/user-meta.txt @@ -0,0 +1,34 @@ +wp-user-meta(1) -- Manage user custom fields. +==== + +## SYNOPSIS + +wp user-meta get <ID> <key> + +wp user-meta add <ID> <key> <value> + +wp user-meta update <ID> <key> <value> + +wp user-meta delete <ID> <key> + +## SUBCOMMANDS + +* `get`: + + Get a custom field value. + +* `add`: + + Add a new custom field. + +* `update`: + + Update an existing custom field. + +* `delete`: + + Delete a custom field. + +## EXAMPLES + + wp user-meta set 123 description "Mary is a WordPress developer." diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index bf263bcce..ebb32ce7c 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -28,13 +28,52 @@ public function get( $args, $assoc_args ) { WP_CLI::print_value( $value ); } + /** + * Get meta field value for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function delete( $args, $assoc_args ) { + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $meta_key = self::get_arg_or_error($args, 1, "meta_key"); + + $success = delete_user_meta( $user_id, $meta_key ); + + if ( $success ) { + WP_CLI::success( "Deleted custom field." ); + } else { + WP_CLI::error( "Failed to delete custom field." ); + } + } + + /** + * Update meta field for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function add( $args, $assoc_args ) { + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $meta_key = self::get_arg_or_error($args, 1, "meta_key"); + $meta_value = self::get_arg_or_error($args, 2, "meta_value"); + + $success = add_user_meta( $user_id, $meta_key, $meta_value ); + + if ( $success ) { + WP_CLI::success( "Added custom field." ); + } else { + WP_CLI::error( "Failed to add custom field." ); + } + } + /** * Update meta field for a user * * @param array $args * @param array $assoc_args **/ - public function set( $args, $assoc_args ) { + public function update( $args, $assoc_args ) { $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); $meta_key = self::get_arg_or_error($args, 1, "meta_key"); $meta_value = self::get_arg_or_error($args, 2, "meta_value"); @@ -42,9 +81,9 @@ public function set( $args, $assoc_args ) { $success = update_user_meta( $user_id, $meta_key, $meta_value ); if ( $success ) { - WP_CLI::success( "Updated user $user_id." ); + WP_CLI::success( "Updated custom field." ); } else { - WP_CLI::error( "Failed to set meta field" ); + WP_CLI::error( "Failed to update custom field." ); } } From a02a3f9633198141933d16175a59be6b457451e5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Jun 2012 15:08:24 +0300 Subject: [PATCH 0444/5359] don't unset the --url parameter; needed for other things. see #103 --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d16470d80..16f6fa4fb 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -235,7 +235,7 @@ static function get_upgrader( $class ) { static function _set_url( &$assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; - unset( $assoc_args['url'] ); + /* unset( $assoc_args['url'] ); */ } elseif ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); From 47c9559938a09302276362b97d817f88d541b5f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Jun 2012 23:12:48 +0300 Subject: [PATCH 0445/5359] move version check into PHP. fixes #119 --- src/bin/wp | 24 +++++------------------- src/php/wp-cli/wp-cli-boot.php | 9 +++++++++ src/php/wp-cli/wp-cli.php | 3 ++- 3 files changed, 16 insertions(+), 20 deletions(-) create mode 100644 src/php/wp-cli/wp-cli-boot.php diff --git a/src/bin/wp b/src/bin/wp index 20e984096..45da90e16 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -10,9 +10,6 @@ # php executable it can find on your system. # -# Set the required PHP version -CHECK_VERSION='5.3.0' - # Get the absolute path of this executable ORIGDIR=$(pwd) SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") @@ -29,12 +26,14 @@ while [ -h "$SELF_PATH" ]; do done cd "$ORIGDIR" -# Build the path to wp-cli.php. -SCRIPT_PATH='@@PHP_DIR@@/wp-cli/wp-cli.php' +# Build the path to the root PHP file +SCRIPT_PATH='@@PHP_DIR@@' if [ ! -f $SCRIPT_PATH ]; then - SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/wp-cli/wp-cli.php + SCRIPT_PATH=$(dirname "$SELF_PATH")/../php fi +SCRIPT_PATH=$SCRIPT_PATH/wp-cli/wp-cli-boot.php + case $(uname -a) in CYGWIN*) SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; @@ -95,19 +94,6 @@ if [ "x$wp_cli_php_override" != "x" ] ; then php="$php $wp_cli_override_vars" fi -# Get the php version -PHP_VERSION=$(php -v | awk '/^PHP / {print $2}' | cut -d '-' -f 1) - -# Format version numbers -CURRENT_NUMBER=$(echo "$PHP_VERSION" | tr -d '.') -NEW_NUMBER=$(echo "$CHECK_VERSION" | tr -d '.') - -# Compare version numbers and exit if needed -if [ "$CURRENT_NUMBER" -lt "$NEW_NUMBER" ] ; then - echo "Error: PHP version $CHECK_VERSION is required to run wp-cli. You are running version $PHP_VERSION."; - exit -fi - # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands exec $php "$SCRIPT_PATH" "$@" diff --git a/src/php/wp-cli/wp-cli-boot.php b/src/php/wp-cli/wp-cli-boot.php new file mode 100644 index 000000000..870cc6134 --- /dev/null +++ b/src/php/wp-cli/wp-cli-boot.php @@ -0,0 +1,9 @@ +<?php + +if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { + printf( "Error: PHP version %s is required to run wp-cli. You are running version %s.\n", '5.3.0', PHP_VERSION ); + die(-1); +} + +include dirname(__FILE__) . '/wp-cli.php'; + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index ed2a2da56..906eb2527 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -1,7 +1,8 @@ <?php if ( PHP_SAPI !== 'cli' ) { - die( 'Only cli access' ); + echo "Only CLI access.\n"; + die(-1); } define( 'WP_CLI_VERSION', '0.6.0-dev' ); From 4983355d6321c435f57e4816c62e4709dc55008c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Jun 2012 23:33:52 +0300 Subject: [PATCH 0446/5359] make error message clearer --- src/php/wp-cli/wp-cli-boot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli-boot.php b/src/php/wp-cli/wp-cli-boot.php index 870cc6134..972e60fd8 100644 --- a/src/php/wp-cli/wp-cli-boot.php +++ b/src/php/wp-cli/wp-cli-boot.php @@ -1,7 +1,7 @@ <?php if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { - printf( "Error: PHP version %s is required to run wp-cli. You are running version %s.\n", '5.3.0', PHP_VERSION ); + printf( "Error: wp-cli requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); die(-1); } From fda56659b382fca4ecd12ed36cd9b872ffba0938 Mon Sep 17 00:00:00 2001 From: Mike Burns <mgburns@bu.edu> Date: Tue, 22 May 2012 12:58:18 -0400 Subject: [PATCH 0447/5359] updated wp core generate posts command to allow for random hierarchical post generation --- .../wp-cli/commands/internals/generate.php | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index c4bddf222..8ef3bd9a7 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -21,6 +21,7 @@ public function posts( $args, $assoc_args ) { $defaults = array( 'count' => 100, + 'max_depth' => 1, 'type' => 'post', 'status' => 'publish', 'author' => false @@ -49,12 +50,30 @@ public function posts( $args, $assoc_args ) { $notify = new \cli\progress\Bar( 'Generating posts', $count ); + $post_ids = array(); + $current_depth = 1; + $current_parent = 0; + for ( $i = $total; $i < $limit; $i++ ) { - wp_insert_post( array( + + if( $this->maybe_make_child() && $current_depth < $max_depth ) { + + $current_parent = $post_ids[$i-1]; + $current_depth++; + + } else if( $this->maybe_reset_depth() ) { + + $current_depth = 1; + $current_parent = 0; + + } + + $post_ids[$i] = wp_insert_post( array( 'post_type' => $type, 'post_title' => "$label $i", 'post_status' => $status, - 'post_author' => $author + 'post_author' => $author, + 'post_parent' => $current_parent ) ); $notify->tick(); @@ -63,6 +82,16 @@ public function posts( $args, $assoc_args ) { $notify->finish(); } + private function maybe_make_child() { + // 50% chance of making child post + return ( mt_rand(1,2) == 1 ) ? true: false; + } + + private function maybe_reset_depth() { + // 10% chance of reseting to root depth + return ( mt_rand(1,10) == 7 ) ? true : false; + } + /** * Generate users * From f10f83ba1f902d23f7b5209a10afb7c9b9c234ac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 9 Jun 2012 02:07:23 +0300 Subject: [PATCH 0448/5359] add --max_depth parameter to docs --- man/generate-posts.1 | 10 ++++++++-- src/doc/generate-posts.txt | 7 ++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/man/generate-posts.1 b/man/generate-posts.1 index c014d4ff6..fcd00ede4 100644 --- a/man/generate-posts.1 +++ b/man/generate-posts.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-GENERATE\-POSTS" "1" "May 2012" "" "WP-CLI" +.TH "WP\-GENERATE\-POSTS" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-generate\-posts\fR \- Generate a bunch of posts\. . .SH "SYNOPSIS" -\fBwp generate posts\fR [\-\-count=100] [\-\-type=post] [\-\-status=publish] [\-\-author=\fIlogin\fR] +\fBwp generate posts\fR [\-\-count=100] [\-\-type=post] [\-\-status=publish] [\-\-author=\fIlogin\fR] [\-\-max_depth=1] . .SH "OPTIONS" . @@ -34,4 +34,10 @@ The status of the generated posts\. Default: \'publish\' . .IP The author of the generated posts\. Default: none +. +.TP +\fB\-\-max_depth\fR=\fInumber\fR: +. +.IP +For hierarchical post types, generate child posts down to a certain depth\. Default: 1 diff --git a/src/doc/generate-posts.txt b/src/doc/generate-posts.txt index 2f9b15606..129e4a1d0 100644 --- a/src/doc/generate-posts.txt +++ b/src/doc/generate-posts.txt @@ -3,7 +3,8 @@ wp-generate-posts(1) -- Generate a bunch of posts. ## SYNOPSIS -`wp generate posts` [--count=100] [--type=post] [--status=publish] [--author=<login>] +`wp generate posts` [--count=100] [--type=post] [--status=publish] +[--author=<login>] [--max_depth=1] ## OPTIONS @@ -22,3 +23,7 @@ wp-generate-posts(1) -- Generate a bunch of posts. * `--author`=<login>: The author of the generated posts. Default: none + +* `--max_depth`=<number>: + + For hierarchical post types, generate child posts down to a certain depth. Default: 1 From 9f91349a25c5f93b68610c96391951498a242fe9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 9 Jun 2012 02:22:01 +0300 Subject: [PATCH 0449/5359] make doc-build accept file names as parameters --- utils/doc-build | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/utils/doc-build b/utils/doc-build index eaa0b40e1..82ff06ae9 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -1,10 +1,20 @@ #!/bin/bash -# generate man pages +# regenerate everything: +# ./utils/doc-build -rm -rf man -mkdir -p man +# regenerate certain files: +# ./utils/doc-build src/doc/core-update.txt -for file in $(ls src/doc/*.txt); do +files="$@" + +if [ "$files" == "" ]; then + files=$(ls src/doc/*.txt) + + rm -rf man + mkdir -p man +fi + +for file in $files; do cat $file | ronn --roff --manual="WP-CLI" > man/$(basename $file .txt).1 done From 672e204b049362f55a2d58fa23cce7547e3e25e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 9 Jun 2012 02:32:10 +0300 Subject: [PATCH 0450/5359] allow easy wildcards --- utils/doc-build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/doc-build b/utils/doc-build index 82ff06ae9..588836d8a 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -4,9 +4,10 @@ # ./utils/doc-build # regenerate certain files: -# ./utils/doc-build src/doc/core-update.txt +# ./utils/doc-build src/doc/core-* -files="$@" +# eliminate *~ files +files=$(echo "$@" | tr ' ' "\n" | grep -v '~$') if [ "$files" == "" ]; then files=$(ls src/doc/*.txt) From 8263eea841dbb493335936a90fd55482a4212eff Mon Sep 17 00:00:00 2001 From: Mike Burns <mike@grady-etc.com> Date: Sat, 9 Jun 2012 21:42:46 -0400 Subject: [PATCH 0451/5359] Added check for hierarchical post type before respecting max_depth argument --- src/php/wp-cli/commands/internals/generate.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 8ef3bd9a7..c72f820df 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -46,6 +46,8 @@ public function posts( $args, $assoc_args ) { $label = get_post_type_object( $type )->labels->singular_name; + $hierarchical = get_post_type_object( $type )->hierarchical; + $limit = $count + $total; $notify = new \cli\progress\Bar( 'Generating posts', $count ); @@ -56,16 +58,19 @@ public function posts( $args, $assoc_args ) { for ( $i = $total; $i < $limit; $i++ ) { - if( $this->maybe_make_child() && $current_depth < $max_depth ) { + if( $hierarchical ) { + + if( $this->maybe_make_child() && $current_depth < $max_depth ) { - $current_parent = $post_ids[$i-1]; - $current_depth++; + $current_parent = $post_ids[$i-1]; + $current_depth++; - } else if( $this->maybe_reset_depth() ) { + } else if( $this->maybe_reset_depth() ) { - $current_depth = 1; - $current_parent = 0; + $current_depth = 1; + $current_parent = 0; + } } $post_ids[$i] = wp_insert_post( array( From 49ebf0660b58d307b5321aaad5d1e496ef21d12c Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Tue, 12 Jun 2012 10:12:01 +0100 Subject: [PATCH 0452/5359] Add wp core upgrade_database --- src/doc/core-upgrade_database.txt | 6 ++++++ src/php/wp-cli/commands/internals/core.php | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 src/doc/core-upgrade_database.txt diff --git a/src/doc/core-upgrade_database.txt b/src/doc/core-upgrade_database.txt new file mode 100644 index 000000000..b2d1d91e5 --- /dev/null +++ b/src/doc/core-upgrade_database.txt @@ -0,0 +1,6 @@ +wp-core-upgrade_database(1) -- Apply any outstanding database upgrades. +==== + +## SYNOPSIS + +`wp core database_upgrade` diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 27deec66e..74cd22862 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -155,5 +155,11 @@ function update( $args ) { WP_CLI::success('WordPress updated successfully.'); } } + + function database_upgrade( $args ) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + wp_upgrade(); + WP_CLI::success('WordPress database upgraded successfully.'); + } } From ffc6f72eb8a566212215b669877030327f52bc96 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Tue, 12 Jun 2012 10:15:19 +0100 Subject: [PATCH 0453/5359] Rename wp core database_upgrade to upgrade_database (to match docs) --- src/php/wp-cli/commands/internals/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 74cd22862..cde2e25a1 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -156,7 +156,7 @@ function update( $args ) { } } - function database_upgrade( $args ) { + function upgrade_database( $args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); wp_upgrade(); WP_CLI::success('WordPress database upgraded successfully.'); From 1ed0717156ac47076de524c350a04784c2e77627 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Jun 2012 22:12:33 +0300 Subject: [PATCH 0454/5359] merge `wp core upgrade_database` into wp core update. see #121 --- man/core-update.1 | 13 +++++++++++-- src/doc/core-update.txt | 9 ++++++++- src/doc/core-upgrade_database.txt | 6 ------ src/php/wp-cli/commands/internals/core.php | 20 ++++++++++---------- 4 files changed, 29 insertions(+), 19 deletions(-) delete mode 100644 src/doc/core-upgrade_database.txt diff --git a/man/core-update.1 b/man/core-update.1 index 24a01f15e..ee1aaebee 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,10 +1,19 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update\fR \- Update WordPress to the latest version\. . .SH "SYNOPSIS" -\fBwp core update\fR +\fBwp core update\fR [\-\-db] +. +.SH "OPTIONS" +. +.TP +\fB\-\-db\fR: +. +.IP +When passed, it applies any outstanding database upgrades, without touching the files\. + diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index 8a6d15bd8..64f3386ca 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -3,4 +3,11 @@ wp-core-update(1) -- Update WordPress to the latest version. ## SYNOPSIS -`wp core update` +`wp core update` [--db] + +## OPTIONS + +* `--db`: + + When passed, it applies any outstanding database upgrades, without +touching the files. diff --git a/src/doc/core-upgrade_database.txt b/src/doc/core-upgrade_database.txt deleted file mode 100644 index b2d1d91e5..000000000 --- a/src/doc/core-upgrade_database.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-core-upgrade_database(1) -- Apply any outstanding database upgrades. -==== - -## SYNOPSIS - -`wp core database_upgrade` diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index cde2e25a1..822253a51 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -130,7 +130,15 @@ public function version( $args = array(), $assoc_args = array() ) { * * @param array $args */ - function update( $args ) { + function update( $args, $assoc_args ) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + + if ( isset( $assoc_args['db'] ) ) { + wp_upgrade(); + WP_CLI::success( 'WordPress database upgraded successfully.' ); + return; + } + wp_version_check(); $from_api = get_site_transient( 'update_core' ); @@ -140,8 +148,6 @@ function update( $args ) { else list( $update ) = $from_api->updates; - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $result = WP_CLI::get_upgrader( 'Core_Upgrader' )->upgrade( $update ); if ( is_wp_error($result) ) { @@ -152,14 +158,8 @@ function update( $args ) { WP_CLI::success( $msg ); } } else { - WP_CLI::success('WordPress updated successfully.'); + WP_CLI::success( 'WordPress updated successfully.' ); } } - - function upgrade_database( $args ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - wp_upgrade(); - WP_CLI::success('WordPress database upgraded successfully.'); - } } From 451f13d06bfb3ed3ab2df809f19379d94320f9f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 20 Jun 2012 19:52:31 +0300 Subject: [PATCH 0455/5359] handle MAMP paths generically. see #66 --- src/bin/wp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index 45da90e16..20e3cb559 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -67,9 +67,10 @@ else fi # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php5/bin/php /Applications/MAMP/bin/php5.2/bin/php /Applications/MAMP/bin/php5.3/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + for amp_php in /Applications/MAMP/bin/php5*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do if [ -x $amp_php ]; then php=$amp_php + break fi done fi From 361d41d2f9188de7ca403d9f34734f6b1af78bb0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 20 Jun 2012 19:56:04 +0300 Subject: [PATCH 0456/5359] fix indenting in src/bin/wp --- src/bin/wp | 78 +++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/bin/wp b/src/bin/wp index 20e3cb559..f4e9ec769 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -16,13 +16,13 @@ SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(b # Resolve symlinks - this is the equivalent of "readlink -f", but also works with non-standard OS X readlink. while [ -h "$SELF_PATH" ]; do - # 1) cd to directory of the symlink - # 2) cd to the directory of where the symlink points - # 3) Get the pwd - # 4) Append the basename - DIR=$(dirname -- "$SELF_PATH") - SYM=$(readlink $SELF_PATH) - SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") + # 1) cd to directory of the symlink + # 2) cd to the directory of where the symlink points + # 3) Get the pwd + # 4) Append the basename + DIR=$(dirname -- "$SELF_PATH") + SYM=$(readlink $SELF_PATH) + SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") done cd "$ORIGDIR" @@ -35,8 +35,8 @@ fi SCRIPT_PATH=$SCRIPT_PATH/wp-cli/wp-cli-boot.php case $(uname -a) in - CYGWIN*) - SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; + CYGWIN*) + SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; esac # If not exported, try to determine and export the number of columns. @@ -46,53 +46,53 @@ esac # error message is suppressed, but tput cols becomes confused about the # terminal and prints out the default value (80). if [ -z $COLUMNS ] && [ -n "$TERM" ] && [ "$TERM" != dumb ] ; then - # Note to cygwin users: install the ncurses package to get tput command. - if COLUMNS=$(tput cols); then - export COLUMNS - fi + # Note to cygwin users: install the ncurses package to get tput command. + if COLUMNS=$(tput cols); then + export COLUMNS + fi fi if [ ! -z "$WP_CLI_PHP" ] ; then - # Use the WP_CLI_PHP environment variable if it is available. - php="$WP_CLI_PHP" + # Use the WP_CLI_PHP environment variable if it is available. + php="$WP_CLI_PHP" else - # Default to using the php that we find on the PATH. - # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 - php=`which php` + # Default to using the php that we find on the PATH. + # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 + php=`which php` - # We check for a command line (cli) version of php, and if found use that. - which php-cli >/dev/null 2>&1 - if [ "$?" = 0 ] ; then - php=`which php-cli` - fi + # We check for a command line (cli) version of php, and if found use that. + which php-cli >/dev/null 2>&1 + if [ "$?" = 0 ] ; then + php=`which php-cli` + fi - # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php5*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do - if [ -x $amp_php ]; then - php=$amp_php - break - fi - done + # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. + for amp_php in /Applications/MAMP/bin/php5*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + if [ -x $amp_php ]; then + php=$amp_php + break + fi + done fi # Check to see if the user has provided a php.ini file or wp-cli.ini file in any conf dir # Last found wins, so search in reverse priority order for conf_dir in $(dirname "$SELF_PATH") /etc/wp-cli $HOME/.wp-cli ; do - if [ -f $conf_dir/php.ini ] ; then - wp_cli_php_ini=$conf_dir/php.ini - fi - if [ -f $conf_dir/wp-cli.ini ] ; then - wp_cli_php_override=$conf_dir/wp-cli.ini - fi + if [ -f $conf_dir/php.ini ] ; then + wp_cli_php_ini=$conf_dir/php.ini + fi + if [ -f $conf_dir/wp-cli.ini ] ; then + wp_cli_php_override=$conf_dir/wp-cli.ini + fi done # Add in the php file location and/or the php override variables as appropriate if [ "x$wp_cli_php_ini" != "x" ] ; then - php="$php --php-ini $wp_cli_php_ini" + php="$php --php-ini $wp_cli_php_ini" fi if [ "x$wp_cli_php_override" != "x" ] ; then - wp_cli_override_vars=`grep '^[a-z_A-Z0-9]\+ *=' $wp_cli_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' ' '` - php="$php $wp_cli_override_vars" + wp_cli_override_vars=`grep '^[a-z_A-Z0-9]\+ *=' $wp_cli_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' ' '` + php="$php $wp_cli_override_vars" fi # Pass in the path to php so that wp-cli knows which one From d759983324a30f54716c9c4dc65520eb81b2aa31 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Jun 2012 06:16:19 +0300 Subject: [PATCH 0457/5359] add --network flag to wp plugin activate|deactivate|toggle. fixes #127 --- src/php/wp-cli/commands/internals/plugin.php | 44 +++++++++++++------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 5c8b4e36e..57b2719f6 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -108,15 +108,17 @@ private function get_status( $file, $long = false ) { * * @param array $args */ - function activate( $args ) { + function activate( $args, $assoc_args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - activate_plugin( $file ); + $network_wide = isset( $assoc_args['network'] ); - if ( !is_plugin_active( $file ) ) { - WP_CLI::error( 'Could not activate this plugin: ' . $name ); - } else { + activate_plugin( $file, '', $network_wide ); + + if ( $this->check_active( $file, $network_wide ) ) { WP_CLI::success( "Plugin '$name' activated." ); + } else { + WP_CLI::error( 'Could not activate plugin: ' . $name ); } } @@ -125,30 +127,44 @@ function activate( $args ) { * * @param array $args */ - function deactivate( $args ) { + function deactivate( $args, $assoc_args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - deactivate_plugins( $file ); + $network_wide = isset( $assoc_args['network'] ); - if ( !is_plugin_inactive( $file ) ) { - WP_CLI::error( 'Could not deactivate this plugin: '.$name ); - } else { + deactivate_plugins( $file, false, $network_wide ); + + if ( ! $this->check_active( $file, $network_wide ) ) { WP_CLI::success( "Plugin '$name' deactivated." ); + } else { + WP_CLI::error( 'Could not deactivate plugin: ' . $name ); } } + private function check_active( $file, $network_wide ) { + if ( $network_wide ) { + $check = is_plugin_active_for_network( $file ); + } else { + $check = is_plugin_active( $file ); + } + + return $check; + } + /** * Toggle a plugin's activation state * * @param array $args */ - function toggle( $args ) { + function toggle( $args, $assoc_args ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - if ( is_plugin_active( $file ) ) { - $this->deactivate( $args ); + $network_wide = isset( $assoc_args['network'] ); + + if ( $this->check_active( $file, $network_wide ) ) { + $this->deactivate( $args, $assoc_args ); } else { - $this->activate( $args ); + $this->activate( $args, $assoc_args ); } } From 22ab2343c930759075f7185b13eb5e8fa757d15b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Jun 2012 06:21:44 +0300 Subject: [PATCH 0458/5359] update docs. see #127 --- man/plugin-activate.1 | 10 ++++++++-- man/plugin-deactivate.1 | 10 ++++++++-- man/plugin-toggle.1 | 10 ++++++++-- src/doc/plugin-activate.txt | 6 +++++- src/doc/plugin-deactivate.txt | 6 +++++- src/doc/plugin-toggle.txt | 6 +++++- 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index f78e01436..4dfd3c780 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-ACTIVATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-ACTIVATE" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-activate\fR \- Activate an installed plugin\. . .SH "SYNOPSIS" -\fBwp plugin activate\fR \fIplugin\fR +\fBwp plugin activate\fR \fIplugin\fR [\-\-network] . .SH "OPTIONS" . @@ -16,4 +16,10 @@ . .IP The plugin to activate\. +. +.TP +\fB\-\-network\fR: +. +.IP +If set, the plugin will be deactivated for the entire multisite network\. diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 index 25bd7b38f..a9823535c 100644 --- a/man/plugin-deactivate.1 +++ b/man/plugin-deactivate.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-deactivate\fR \- Deactivate an active plugin\. . .SH "SYNOPSIS" -\fBwp plugin deactivate\fR \fIplugin\fR +\fBwp plugin deactivate\fR \fIplugin\fR [\-\-network] . .SH "OPTIONS" . @@ -16,4 +16,10 @@ . .IP The plugin to deactivate\. +. +.TP +\fB\-\-network\fR: +. +.IP +If set, the plugin will be deactivated for the entire multisite network\. diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index 36a4a599d..52dba0c00 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-deactivate\fR \- Activate/Deactivate an installed plugin\. . .SH "SYNOPSIS" -\fBwp plugin toggle\fR \fIplugin\fR +\fBwp plugin toggle\fR \fIplugin\fR [\-\-network] . .SH "OPTIONS" . @@ -16,4 +16,10 @@ . .IP The plugin to toggle\. +. +.TP +\fB\-\-network\fR: +. +.IP +If set, the plugin will be deactivated for the entire multisite network\. diff --git a/src/doc/plugin-activate.txt b/src/doc/plugin-activate.txt index 58760b709..906062541 100644 --- a/src/doc/plugin-activate.txt +++ b/src/doc/plugin-activate.txt @@ -3,10 +3,14 @@ wp-plugin-activate(1) -- Activate an installed plugin. ## SYNOPSIS -`wp plugin activate` <plugin> +`wp plugin activate` <plugin> [--network] ## OPTIONS * `<plugin>`: The plugin to activate. + +* `--network`: + + If set, the plugin will be deactivated for the entire multisite network. diff --git a/src/doc/plugin-deactivate.txt b/src/doc/plugin-deactivate.txt index e6093a838..d114fafed 100644 --- a/src/doc/plugin-deactivate.txt +++ b/src/doc/plugin-deactivate.txt @@ -3,10 +3,14 @@ wp-plugin-deactivate(1) -- Deactivate an active plugin. ## SYNOPSIS -`wp plugin deactivate` <plugin> +`wp plugin deactivate` <plugin> [--network] ## OPTIONS * `<plugin>`: The plugin to deactivate. + +* `--network`: + + If set, the plugin will be deactivated for the entire multisite network. diff --git a/src/doc/plugin-toggle.txt b/src/doc/plugin-toggle.txt index 5f90c0543..5dee2ee94 100644 --- a/src/doc/plugin-toggle.txt +++ b/src/doc/plugin-toggle.txt @@ -3,10 +3,14 @@ wp-plugin-deactivate(1) -- Activate/Deactivate an installed plugin. ## SYNOPSIS -`wp plugin toggle` <plugin> +`wp plugin toggle` <plugin> [--network] ## OPTIONS * `<plugin>`: The plugin to toggle. + +* `--network`: + + If set, the plugin will be deactivated for the entire multisite network. From 377793003548f9b3935bc1c9805beb5cfb9c5e42 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Jun 2012 06:28:03 +0300 Subject: [PATCH 0459/5359] make doc-build regenerate only the files that git says have changed --- utils/doc-build | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/utils/doc-build b/utils/doc-build index 588836d8a..048af6a36 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -1,21 +1,8 @@ #!/bin/bash -# regenerate everything: +# regenerate modified files: # ./utils/doc-build -# regenerate certain files: -# ./utils/doc-build src/doc/core-* - -# eliminate *~ files -files=$(echo "$@" | tr ' ' "\n" | grep -v '~$') - -if [ "$files" == "" ]; then - files=$(ls src/doc/*.txt) - - rm -rf man - mkdir -p man -fi - -for file in $files; do +for file in $(git st src/doc/ --porcelain | cut -d ' ' -f 3); do cat $file | ronn --roff --manual="WP-CLI" > man/$(basename $file .txt).1 done From c828c8f474187a393169c6589d3c626f01380fbf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Jun 2012 06:28:17 +0300 Subject: [PATCH 0460/5359] fix docs. see #127 --- man/plugin-activate.1 | 2 +- man/plugin-toggle.1 | 2 +- src/doc/plugin-activate.txt | 2 +- src/doc/plugin-toggle.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index 4dfd3c780..bcecd12c9 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -21,5 +21,5 @@ The plugin to activate\. \fB\-\-network\fR: . .IP -If set, the plugin will be deactivated for the entire multisite network\. +If set, the plugin will be activated for the entire multisite network\. diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index 52dba0c00..f86b819e5 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -21,5 +21,5 @@ The plugin to toggle\. \fB\-\-network\fR: . .IP -If set, the plugin will be deactivated for the entire multisite network\. +If set, the plugin will be toggled for the entire multisite network\. diff --git a/src/doc/plugin-activate.txt b/src/doc/plugin-activate.txt index 906062541..b7207bf81 100644 --- a/src/doc/plugin-activate.txt +++ b/src/doc/plugin-activate.txt @@ -13,4 +13,4 @@ wp-plugin-activate(1) -- Activate an installed plugin. * `--network`: - If set, the plugin will be deactivated for the entire multisite network. + If set, the plugin will be activated for the entire multisite network. diff --git a/src/doc/plugin-toggle.txt b/src/doc/plugin-toggle.txt index 5dee2ee94..07c243ea2 100644 --- a/src/doc/plugin-toggle.txt +++ b/src/doc/plugin-toggle.txt @@ -13,4 +13,4 @@ wp-plugin-deactivate(1) -- Activate/Deactivate an installed plugin. * `--network`: - If set, the plugin will be deactivated for the entire multisite network. + If set, the plugin will be toggled for the entire multisite network. From 5b7106a830851e313fce61c8eb1e8956f09a6a8c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Jun 2012 09:39:01 +0300 Subject: [PATCH 0461/5359] make --admin_password mandatory. fixes #128 --- man/core-install.1 | 4 ++-- src/doc/core-install.txt | 2 +- src/php/wp-cli/commands/internals/core.php | 2 +- src/php/wp-cli/wp-cli.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/man/core-install.1 b/man/core-install.1 index b7376703e..1c4213965 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL" "1" "May 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-install\fR \- Install the WordPress tables in the database\. . .SH "SYNOPSIS" -\fBwp core install\fR \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_password=\fIpassword\fR \-\-admin_email=\fIemail\fR +\fBwp core install\fR \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_email=\fIemail\fR \-\-admin_password=\fIpassword\fR . .SH "OPTIONS" . diff --git a/src/doc/core-install.txt b/src/doc/core-install.txt index 19231e671..8f65a9a00 100644 --- a/src/doc/core-install.txt +++ b/src/doc/core-install.txt @@ -3,7 +3,7 @@ wp-core-install(1) -- Install the WordPress tables in the database. ## SYNOPSIS -`wp core install` --url=<url> --title=<site-title> [--admin_name=<username>] --admin_password=<password> --admin_email=<email> +`wp core install` --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> ## OPTIONS diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 822253a51..4d45d4371 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -76,7 +76,7 @@ public function install( $args, $assoc_args ) { 'title' => '', 'admin_name' => 'admin', 'admin_email' => '', - 'admin_password' => wp_generate_password( 12, false ) + 'admin_password' => '' ) ), EXTR_SKIP ); $public = true; diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 906eb2527..c1be3a997 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -84,7 +84,7 @@ // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == $arguments ) { - WP_CLI::check_required_args( array( 'url', 'title', 'admin_email' ), $assoc_args ); + WP_CLI::check_required_args( array( 'url', 'title', 'admin_email', 'admin_password' ), $assoc_args ); define( 'WP_INSTALLING', true ); } From 919c1414345ce4598964e2824e1967a32d658954 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Jun 2012 22:24:09 +0300 Subject: [PATCH 0462/5359] always define WP_MEMORY_LIMIT. props larsemil. fixes #122 --- src/php/wp-cli/wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c1be3a997..c3ab62a5d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -89,6 +89,10 @@ define( 'WP_INSTALLING', true ); } +// Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 +if ( !defined('WP_MEMORY_LIMIT') ) + define('WP_MEMORY_LIMIT', '1024M'); + // Load WordPress require WP_ROOT . 'wp-load.php'; require ABSPATH . 'wp-admin/includes/admin.php'; From ada7f0fc5ab9a5e655f8b4ab1d4562f11b590f1a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Jun 2012 23:10:45 +0300 Subject: [PATCH 0463/5359] reset memory limit right before loading admin files. see #122 --- src/php/wp-cli/wp-cli.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c3ab62a5d..3db7c17c8 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -89,12 +89,12 @@ define( 'WP_INSTALLING', true ); } -// Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 -if ( !defined('WP_MEMORY_LIMIT') ) - define('WP_MEMORY_LIMIT', '1024M'); - // Load WordPress require WP_ROOT . 'wp-load.php'; + +// Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 +@ini_set( 'memory_limit', -1 ); + require ABSPATH . 'wp-admin/includes/admin.php'; // Load the right info into the global wp_query From 2af9287f99aa441cf3f450bcf6e73670548e3a17 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Jun 2012 14:50:31 +0300 Subject: [PATCH 0464/5359] fix notice from install --activate --- src/php/wp-cli/commands/internals/plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 57b2719f6..dfe6da512 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -108,7 +108,7 @@ private function get_status( $file, $long = false ) { * * @param array $args */ - function activate( $args, $assoc_args ) { + function activate( $args, $assoc_args = array() ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $network_wide = isset( $assoc_args['network'] ); @@ -127,7 +127,7 @@ function activate( $args, $assoc_args ) { * * @param array $args */ - function deactivate( $args, $assoc_args ) { + function deactivate( $args, $assoc_args = array() ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $network_wide = isset( $assoc_args['network'] ); @@ -156,7 +156,7 @@ private function check_active( $file, $network_wide ) { * * @param array $args */ - function toggle( $args, $assoc_args ) { + function toggle( $args, $assoc_args = array() ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); $network_wide = isset( $assoc_args['network'] ); From f197ff82a04af786c7356c2c82dc0169d6dbaf5c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Jun 2012 15:06:42 +0300 Subject: [PATCH 0465/5359] make `wp plugin uninstall` delete the plugin files; add -no-delete flag --- man/plugin-uninstall.1 | 10 ++++++++-- src/doc/plugin-uninstall.txt | 7 ++++++- src/php/wp-cli/commands/internals/plugin.php | 5 ++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 index de306138d..0d5430032 100644 --- a/man/plugin-uninstall.1 +++ b/man/plugin-uninstall.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UNINSTALL" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UNINSTALL" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-uninstall\fR \- Run the uninstallation procedure for a plugin\. . .SH "SYNOPSIS" -\fBwp plugin uninstall\fR \fIplugin\fR +\fBwp plugin uninstall\fR \fIplugin\fR [\-\-no\-delete] . .SH "OPTIONS" . @@ -17,6 +17,12 @@ .IP The plugin to uninstall\. . +.TP +\fB\-\-no\-delete\fR: +. +.IP +If set, the plugin files will not be deleted\. Only the uninstall procedure will be run\. +. .SH "EXAMPLES" . .nf diff --git a/src/doc/plugin-uninstall.txt b/src/doc/plugin-uninstall.txt index cc2fb5327..d0783f3dd 100644 --- a/src/doc/plugin-uninstall.txt +++ b/src/doc/plugin-uninstall.txt @@ -3,7 +3,7 @@ wp-plugin-uninstall(1) -- Run the uninstallation procedure for a plugin. ## SYNOPSIS -`wp plugin uninstall` <plugin> +`wp plugin uninstall` <plugin> [--no-delete] ## OPTIONS @@ -11,6 +11,11 @@ wp-plugin-uninstall(1) -- Run the uninstallation procedure for a plugin. The plugin to uninstall. +* `--no-delete`: + + If set, the plugin files will not be deleted. Only the uninstall procedure +will be run. + ## EXAMPLES wp plugin uninstall hello diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index dfe6da512..acf7ca5cf 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -262,7 +262,7 @@ protected function get_item_list() { * * @param array $args */ - function uninstall( $args ) { + function uninstall( $args, $assoc_args = array() ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); if ( is_plugin_active( $file ) ) { @@ -270,6 +270,9 @@ function uninstall( $args ) { } uninstall_plugin( $file ); + + if ( !isset( $assoc_args['no-delete'] ) ) + $this->delete( $args ); } /** From 0d8487b771afbaf1acd8c086e088f9d3601c3395 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Jun 2012 15:07:34 +0300 Subject: [PATCH 0466/5359] transform doc-build into a pre-commit hook --- utils/doc-build | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/utils/doc-build b/utils/doc-build index 048af6a36..8a4224449 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -1,8 +1,12 @@ #!/bin/bash -# regenerate modified files: -# ./utils/doc-build +# regenerates modified man pages +# +# run automatically before each commit: +# ln -s ../../utils/doc-build .git/hooks/pre-commit -for file in $(git st src/doc/ --porcelain | cut -d ' ' -f 3); do - cat $file | ronn --roff --manual="WP-CLI" > man/$(basename $file .txt).1 +for file in $(git diff --cached --name-only src/doc/); do + man_file=man/$(basename $file .txt).1 + cat $file | ronn --roff --manual="WP-CLI" > $man_file + git add $man_file done From 80bab547cac1ee34c406876f6f9c3477db6f5fdd Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 28 Jun 2012 09:14:15 +0100 Subject: [PATCH 0467/5359] Add --json argument to "wp option get" --- src/php/wp-cli/commands/internals/option.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 955efb5f0..388b98aec 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -72,7 +72,7 @@ public function delete( $args ) { * * @param array $args **/ - public function get( $args ) { + public function get( $args, $assoc_args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp option get <option-name>" ); exit; @@ -85,6 +85,10 @@ public function get( $args ) { if ( false === $value ) die(1); + if ( isset( $assoc_args['json'] ) ) { + $value = json_encode( $value ); + } + WP_CLI::print_value( $value ); } } From d34ceb0157aef7f35316dbda4dcd547808398216 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 28 Jun 2012 09:17:10 +0100 Subject: [PATCH 0468/5359] Add --json option to docs --- src/doc/option.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/option.txt b/src/doc/option.txt index 05f5e7da3..e1d75245c 100644 --- a/src/doc/option.txt +++ b/src/doc/option.txt @@ -3,7 +3,7 @@ wp-option(1) -- Manage WordPress options. ## SYNOPSIS -wp option get <key> +wp option get <key> [--json] wp option add <key> <value> @@ -15,7 +15,8 @@ wp option delete <key> * `get`: - Get an option value. + Get an option value. Passing --json causes the output to be formatted + as JSON. * `add`: From 5d7537a4213af49b34aec695f338cb1e248462c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 11:47:49 +0300 Subject: [PATCH 0469/5359] update man page --- man/option.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/man/option.1 b/man/option.1 index 30580ae81..6fd2f524c 100644 --- a/man/option.1 +++ b/man/option.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-OPTION" "1" "May 2012" "" "WP-CLI" +.TH "WP\-OPTION" "1" "June 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-option\fR \- Manage WordPress options\. . .SH "SYNOPSIS" -wp option get \fIkey\fR +wp option get \fIkey\fR [\-\-json] . .P wp option add \fIkey\fR \fIvalue\fR @@ -24,7 +24,7 @@ wp option delete \fIkey\fR \fBget\fR: . .IP -Get an option value\. +Get an option value\. Passing \-\-json causes the output to be formatted as JSON\. . .TP \fBadd\fR: From be136373aa241ba21f8463529046a5bdbbc27c79 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 11:49:14 +0300 Subject: [PATCH 0470/5359] allow passing man pages to doc-build again --- utils/doc-build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/doc-build b/utils/doc-build index 8a4224449..f19a97f5a 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -5,7 +5,13 @@ # run automatically before each commit: # ln -s ../../utils/doc-build .git/hooks/pre-commit -for file in $(git diff --cached --name-only src/doc/); do +if [ -n "$@" ]; then + files=$(git diff --cached --name-only src/doc/) +else + files=$@ +fi + +for file in $files; do man_file=man/$(basename $file .txt).1 cat $file | ronn --roff --manual="WP-CLI" > $man_file git add $man_file From 819c71df2d29ce51621569ed5c4cf254aeeb5a98 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 28 Jun 2012 09:54:52 +0100 Subject: [PATCH 0471/5359] Add --json option to "wp option update" --- src/php/wp-cli/commands/internals/option.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 388b98aec..30bb544fa 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -33,7 +33,7 @@ public function add( $args ) { * * @param array $args **/ - public function update( $args ) { + public function update( $args, $assoc_args ) { if ( count( $args ) < 2 ) { WP_CLI::line( "usage: wp option update <option-name> <option-value>" ); exit; @@ -41,6 +41,10 @@ public function update( $args ) { list( $key, $value ) = $args; + if ( isset( $assoc_args['json'] ) ) { + $value = json_decode( $value, true ); + } + if ( $value === get_option( $key ) ) return; From 45db34fff2885c419e5f043346cc36f844d59143 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 11:58:03 +0300 Subject: [PATCH 0472/5359] move --json handling to WP_CLI::print_value(). see #120 --- src/php/wp-cli/class-wp-cli.php | 10 ++++++---- src/php/wp-cli/commands/internals/option.php | 6 +----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 16f6fa4fb..b727dfe8f 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -80,12 +80,14 @@ static function warning( $message, $label = 'Warning' ) { * * @param string $message */ - static function print_value( $value ) { + static function print_value( $value, $assoc_args = array() ) { if ( is_array( $value ) || is_object( $value ) ) { - echo var_export( $value ) . "\n"; - } else { - echo $value . "\n"; + $formatter = isset( $assoc_args['json'] ) ? 'json_encode' : 'var_export'; + + $value = $formatter( $value ); } + + echo $value . "\n"; } /** diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 388b98aec..670fe72ef 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -85,10 +85,6 @@ public function get( $args, $assoc_args ) { if ( false === $value ) die(1); - if ( isset( $assoc_args['json'] ) ) { - $value = json_encode( $value ); - } - - WP_CLI::print_value( $value ); + WP_CLI::print_value( $value, $assoc_args ); } } From c10c9f375e2230e1f68e8866ddd85810f48d0604 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 12:01:36 +0300 Subject: [PATCH 0473/5359] add --json to wp user-meta get. see #120 --- man/user-meta.1 | 4 ++-- src/doc/user-meta.txt | 5 +++-- src/php/wp-cli/commands/internals/user-meta.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/man/user-meta.1 b/man/user-meta.1 index a3429e987..fa9b646d5 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -7,7 +7,7 @@ \fBwp\-user\-meta\fR \- Manage user custom fields\. . .SH "SYNOPSIS" -wp user\-meta get \fIID\fR \fIkey\fR +wp user\-meta get \fIID\fR \fIkey\fR [\-\-json] . .P wp user\-meta add \fIID\fR \fIkey\fR \fIvalue\fR @@ -24,7 +24,7 @@ wp user\-meta delete \fIID\fR \fIkey\fR \fBget\fR: . .IP -Get a custom field value\. +Get a custom field value\. Passing \-\-json causes the output to be formatted as JSON\. . .TP \fBadd\fR: diff --git a/src/doc/user-meta.txt b/src/doc/user-meta.txt index 1825c508c..8a7562f0f 100644 --- a/src/doc/user-meta.txt +++ b/src/doc/user-meta.txt @@ -3,7 +3,7 @@ wp-user-meta(1) -- Manage user custom fields. ## SYNOPSIS -wp user-meta get <ID> <key> +wp user-meta get <ID> <key> [--json] wp user-meta add <ID> <key> <value> @@ -15,7 +15,8 @@ wp user-meta delete <ID> <key> * `get`: - Get a custom field value. + Get a custom field value. Passing --json causes the output to be formatted + as JSON. * `add`: diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index ebb32ce7c..95450218d 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -25,7 +25,7 @@ public function get( $args, $assoc_args ) { if ( '' === $value ) die(1); - WP_CLI::print_value( $value ); + WP_CLI::print_value( $value, $assoc_args ); } /** From 243364d9a4a935cd6b2c3d2ba07b2d6ef25579b3 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 28 Jun 2012 10:02:58 +0100 Subject: [PATCH 0474/5359] Add --json option to "wp option add" --- src/php/wp-cli/commands/internals/option.php | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 30bb544fa..d20bc93aa 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -15,13 +15,13 @@ class Option_Command extends WP_CLI_Command { * * @param array $args **/ - public function add( $args ) { + public function add( $args, $assoc_args ) { if ( count( $args ) < 2 ) { WP_CLI::line( "usage: wp option add <option-name> <option-value>" ); exit; } - list( $key, $value ) = $args; + list( $key, $value ) = self::read_name_and_value( $args, $assoc_args ); if ( !add_option( $key, $value ) ) { WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); @@ -39,11 +39,7 @@ public function update( $args, $assoc_args ) { exit; } - list( $key, $value ) = $args; - - if ( isset( $assoc_args['json'] ) ) { - $value = json_decode( $value, true ); - } + list( $key, $value ) = self::read_name_and_value( $args, $assoc_args ); if ( $value === get_option( $key ) ) return; @@ -52,6 +48,16 @@ public function update( $args, $assoc_args ) { WP_CLI::error( "Could not update option '$key'." ); } } + + private function read_name_and_value( $args, $assoc_args) { + list( $key, $value ) = $args; + + if ( isset( $assoc_args['json'] ) ) { + $value = json_decode( $value, true ); + } + + return array( $key, $value ); + } /** * Delete an option From 7dd05600a779be6d00409a83f750bbabdb060a13 Mon Sep 17 00:00:00 2001 From: Michael Williamson <michael.williamson@red-gate.com> Date: Thu, 28 Jun 2012 10:04:28 +0100 Subject: [PATCH 0475/5359] Update documentation for --json option in "wp option {add|update}" --- src/doc/option.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/option.txt b/src/doc/option.txt index e1d75245c..cbb7b79c6 100644 --- a/src/doc/option.txt +++ b/src/doc/option.txt @@ -5,9 +5,9 @@ wp-option(1) -- Manage WordPress options. wp option get <key> [--json] -wp option add <key> <value> +wp option add <key> <value> [--json] -wp option update <key> <value> +wp option update <key> <value> [--json] wp option delete <key> @@ -20,11 +20,13 @@ wp option delete <key> * `add`: - Add a new option. + Add a new option. Pass --json to decode JSON values before adding + the option. * `update`: - Update an existing option. + Update an existing option. Pass --json to decode JSON values before + updating the option. * `delete`: From 8119f8eb22b92fb0117897b659ab8b1dd2a6ec1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 12:46:36 +0300 Subject: [PATCH 0476/5359] return JSON even for simple values --- src/php/wp-cli/class-wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index b727dfe8f..664d939a1 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -81,13 +81,13 @@ static function warning( $message, $label = 'Warning' ) { * @param string $message */ static function print_value( $value, $assoc_args = array() ) { - if ( is_array( $value ) || is_object( $value ) ) { - $formatter = isset( $assoc_args['json'] ) ? 'json_encode' : 'var_export'; - - $value = $formatter( $value ); + if ( isset( $assoc_args['json'] ) ) { + $value = json_encode( $value ); + } elseif ( is_array( $value ) || is_object( $value ) ) { + $value = var_export( $value ); } - echo $value . "\n"; + echo var_export( $value ) . "\n"; } /** From 57606f51aed69b634efcaf7cffc8521243b8016e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 14:04:57 +0300 Subject: [PATCH 0477/5359] remove double var_export() call --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 664d939a1..794af4fa4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -87,7 +87,7 @@ static function print_value( $value, $assoc_args = array() ) { $value = var_export( $value ); } - echo var_export( $value ) . "\n"; + echo $value . "\n"; } /** From 1934a06f0d3e80ed6488f68ee66d215312ce6500 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 14:05:25 +0300 Subject: [PATCH 0478/5359] replace read_name_and_value() with WP_CLI::read_value() --- src/php/wp-cli/class-wp-cli.php | 19 +++++++++++++++++-- src/php/wp-cli/commands/internals/option.php | 18 ++++++------------ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 794af4fa4..6eaaac3f4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -76,9 +76,24 @@ static function warning( $message, $label = 'Warning' ) { } /** - * Display an easy to paste PHP value. + * Read a value, from various formats * - * @param string $message + * @param mixed $value + * @param array $assoc_args + */ + static function read_value( $value, $assoc_args = array() ) { + if ( isset( $assoc_args['json'] ) ) { + $value = json_decode( $value, true ); + } + + return $value; + } + + /** + * Display a value, in various formats + * + * @param mixed $value + * @param array $assoc_args */ static function print_value( $value, $assoc_args = array() ) { if ( isset( $assoc_args['json'] ) ) { diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 954bae692..fcea4789d 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -21,7 +21,9 @@ public function add( $args, $assoc_args ) { exit; } - list( $key, $value ) = self::read_name_and_value( $args, $assoc_args ); + $key = $args[0]; + + $value = WP_CLI::read_value( $args[1], $assoc_args ); if ( !add_option( $key, $value ) ) { WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); @@ -39,7 +41,9 @@ public function update( $args, $assoc_args ) { exit; } - list( $key, $value ) = self::read_name_and_value( $args, $assoc_args ); + $key = $args[0]; + + $value = WP_CLI::read_value( $args[1], $assoc_args ); if ( $value === get_option( $key ) ) return; @@ -48,16 +52,6 @@ public function update( $args, $assoc_args ) { WP_CLI::error( "Could not update option '$key'." ); } } - - private function read_name_and_value( $args, $assoc_args) { - list( $key, $value ) = $args; - - if ( isset( $assoc_args['json'] ) ) { - $value = json_decode( $value, true ); - } - - return array( $key, $value ); - } /** * Delete an option From ffa76a177cec60f063c4956e3e5b5f95fe21e953 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 14:07:45 +0300 Subject: [PATCH 0479/5359] update man page --- man/option.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/man/option.1 b/man/option.1 index 6fd2f524c..660dc4d26 100644 --- a/man/option.1 +++ b/man/option.1 @@ -10,10 +10,10 @@ wp option get \fIkey\fR [\-\-json] . .P -wp option add \fIkey\fR \fIvalue\fR +wp option add \fIkey\fR \fIvalue\fR [\-\-json] . .P -wp option update \fIkey\fR \fIvalue\fR +wp option update \fIkey\fR \fIvalue\fR [\-\-json] . .P wp option delete \fIkey\fR @@ -30,13 +30,13 @@ Get an option value\. Passing \-\-json causes the output to be formatted as JSON \fBadd\fR: . .IP -Add a new option\. +Add a new option\. Pass \-\-json to decode JSON values before adding the option\. . .TP \fBupdate\fR: . .IP -Update an existing option\. +Update an existing option\. Pass \-\-json to decode JSON values before updating the option\. . .TP \fBdelete\fR: From ed2ac85c6aede26ae1ab8c6abb761191625280a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Jun 2012 14:08:06 +0300 Subject: [PATCH 0480/5359] use $# to check if there are no parameters passed --- utils/doc-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/doc-build b/utils/doc-build index f19a97f5a..9a71c69f9 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -5,7 +5,7 @@ # run automatically before each commit: # ln -s ../../utils/doc-build .git/hooks/pre-commit -if [ -n "$@" ]; then +if [ $# -eq 0 ]; then files=$(git diff --cached --name-only src/doc/) else files=$@ From dceaa271b0f3965b0aa0d60b6d1f9bebb8f9b96a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Jun 2012 20:49:13 +0300 Subject: [PATCH 0481/5359] don't look in parent dir for wp-load.php. fixes #134 --- src/php/wp-cli/wp-cli.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3db7c17c8..ca99bb703 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -47,8 +47,6 @@ if ( !empty( $assoc_args['path'] ) ) { // trailingslashit() isn't available yet define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); -} elseif ( is_readable( $_SERVER['PWD'] . '/../wp-load.php' ) ) { - define( 'WP_ROOT', $_SERVER['PWD'] . '/../' ); } else { define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } From 0e5e473f3ad3b76e37840090d56a3fce2315c7c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 1 Jul 2012 15:31:57 +0300 Subject: [PATCH 0482/5359] add `wp option set` and `wp user-meta set` aliases --- src/php/wp-cli/commands/internals/option.php | 4 ++++ src/php/wp-cli/commands/internals/user-meta.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index fcea4789d..861e05eae 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -10,6 +10,10 @@ */ class Option_Command extends WP_CLI_Command { + protected $aliases = array( + 'set' => 'update' + ); + /** * Add an option * diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index 95450218d..b12a8adde 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -10,6 +10,10 @@ */ class User_Meta_Command extends WP_CLI_Command { + protected $aliases = array( + 'set' => 'update' + ); + /** * Get meta field value for a user * From 8b01c257570bd9faec0cddda1bd92029f13970a8 Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Sun, 1 Jul 2012 23:24:30 -0700 Subject: [PATCH 0483/5359] Initial commit for core updates from local source --- man/core-update.1 | 20 +++++++++- src/doc/core-update.txt | 13 ++++++- src/php/wp-cli/commands/internals/core.php | 44 ++++++++++++++++++---- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/man/core-update.1 b/man/core-update.1 index ee1aaebee..bee1b2a11 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE" "1" "June 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE" "1" "July 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update\fR \- Update WordPress to the latest version\. . .SH "SYNOPSIS" -\fBwp core update\fR [\-\-db] +\fBwp core update\fR [\-\-db] [\-\-version=\fInew_version\fR <package/zip>] . .SH "OPTIONS" . @@ -16,4 +16,20 @@ . .IP When passed, it applies any outstanding database upgrades, without touching the files\. +. +.TP +\fB\-\-version=\fR\fInew_version\fR <package/zip>: +. +.IP +When passed, updates to new_version using package/zip as input\. NOTE: package removed by WordPress automatically upon completion\. +. +.SH "EXAMPLES" +. +.nf + +wp core update + +wp core update \-\-version=3\.4 \.\./latest\.zip +. +.fi diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index 64f3386ca..c8cb05917 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -3,7 +3,7 @@ wp-core-update(1) -- Update WordPress to the latest version. ## SYNOPSIS -`wp core update` [--db] +`wp core update` [--db] [--version=<new_version> <package/zip>] ## OPTIONS @@ -11,3 +11,14 @@ wp-core-update(1) -- Update WordPress to the latest version. When passed, it applies any outstanding database upgrades, without touching the files. + +* `--version=`<new_version> <package/zip>: + + When passed, updates to new_version using package/zip as input. + NOTE: package removed by WordPress automatically upon completion. + +## EXAMPLES + + wp core update + + wp core update --version=3.4 ../latest.zip diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 4d45d4371..62f552555 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -129,9 +129,11 @@ public function version( $args = array(), $assoc_args = array() ) { * Update the WordPress core * * @param array $args + * @param array $assoc_args */ function update( $args, $assoc_args ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + global $wp_version; + $update = $from_api = null; if ( isset( $assoc_args['db'] ) ) { wp_upgrade(); @@ -139,14 +141,42 @@ function update( $args, $assoc_args ) { return; } - wp_version_check(); + if ( empty( $assoc_args['version'] ) ) { + wp_version_check(); + $from_api = get_site_transient( 'update_core' ); - $from_api = get_site_transient( 'update_core' ); + if ( empty( $from_api->updates ) ) + $update = false; + else + list( $update ) = $from_api->updates; - if ( empty( $from_api->updates ) ) - $update = false; - else - list( $update ) = $from_api->updates; + } else { + if ( empty( $args[0] ) ) + WP_CLI::error( "Package not specified." ); + + $new_package = $args[0]; + $new_version = $assoc_args['version']; + + if ( version_compare( $wp_version, $new_version, '<' ) ) { + $update = (object) array( + 'response' => 'upgrade', + 'current' => $new_version, + 'download' => $new_package, + 'packages' => (object) array ( + 'partial' => null, + 'new_bundled' => null, + 'no_content' => null, + 'full' => $new_package, + ), + ); + + } else { + WP_CLI::success( 'WordPress is up to date.' ); + return; + } + } + + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); $result = WP_CLI::get_upgrader( 'Core_Upgrader' )->upgrade( $update ); From d034d193152dc2b8fdb55dc6795f6a2b0b45572a Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Tue, 3 Jul 2012 12:41:40 -0700 Subject: [PATCH 0484/5359] Avoid deleting specified package after Core Update. See #135 Introduces Non_Destructive_Core_Upgrader --- man/core-update.1 | 2 +- src/doc/core-update.txt | 1 - src/php/wp-cli/class-cli-upgrader-skin.php | 10 ++++++++++ src/php/wp-cli/commands/internals/core.php | 8 ++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/man/core-update.1 b/man/core-update.1 index bee1b2a11..4e8c61215 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -21,7 +21,7 @@ When passed, it applies any outstanding database upgrades, without touching the \fB\-\-version=\fR\fInew_version\fR <package/zip>: . .IP -When passed, updates to new_version using package/zip as input\. NOTE: package removed by WordPress automatically upon completion\. +When passed, updates to new_version using package/zip as input\. . .SH "EXAMPLES" . diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index c8cb05917..411ea0082 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -15,7 +15,6 @@ touching the files. * `--version=`<new_version> <package/zip>: When passed, updates to new_version using package/zip as input. - NOTE: package removed by WordPress automatically upon completion. ## EXAMPLES diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index 93488b8ca..45266bfd9 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -40,3 +40,13 @@ function feedback( $string ) { } } +/** + * A Core Upgrader class that leaves packages intact by default. + * + * @package wp-cli + */ +class Non_Destructive_Core_Upgrader extends Core_Upgrader { + function unpack_package($package, $delete_package = false) { + return parent::unpack_package( $package, $delete_package ); + } +} diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 62f552555..ee96d11cc 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -133,7 +133,7 @@ public function version( $args = array(), $assoc_args = array() ) { */ function update( $args, $assoc_args ) { global $wp_version; - $update = $from_api = null; + $update = $from_api = $upgrader = null; if ( isset( $assoc_args['db'] ) ) { wp_upgrade(); @@ -150,6 +150,8 @@ function update( $args, $assoc_args ) { else list( $update ) = $from_api->updates; + $upgrader = 'Core_Upgrader'; + } else { if ( empty( $args[0] ) ) WP_CLI::error( "Package not specified." ); @@ -170,6 +172,8 @@ function update( $args, $assoc_args ) { ), ); + $upgrader = 'Non_Destructive_Core_Upgrader'; + } else { WP_CLI::success( 'WordPress is up to date.' ); return; @@ -178,7 +182,7 @@ function update( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $result = WP_CLI::get_upgrader( 'Core_Upgrader' )->upgrade( $update ); + $result = WP_CLI::get_upgrader( $upgrader )->upgrade( $update ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); From 390e7dbbabee7398527c3a1552e849f5c87053aa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 14:07:13 +0300 Subject: [PATCH 0485/5359] set DOCUMENT_ROOT to the current working dir. fixes #137 --- src/php/wp-cli/wp-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index ca99bb703..7d42d32d9 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -43,6 +43,8 @@ unset( $assoc_args['help'] ); } +$_SERVER['DOCUMENT_ROOT'] = getcwd(); + // Define the WordPress location if ( !empty( $assoc_args['path'] ) ) { // trailingslashit() isn't available yet From 2e08bbd94949b5c845556d5432da5fe9760f5f44 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 20:38:49 +0300 Subject: [PATCH 0486/5359] don't attempt to populate wp_query when the blog is being installed --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 7d42d32d9..22485f1b5 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -98,7 +98,7 @@ require ABSPATH . 'wp-admin/includes/admin.php'; // Load the right info into the global wp_query -if ( isset( $assoc_args['url'] ) ) { +if ( !defined( 'WP_INSTALLING' ) && isset( $assoc_args['url'] ) ) { if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { $GLOBALS['wp']->parse_request(); $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); From 8d7504f8f51913779f3623acd07590ac0ea2cd03 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 22:55:55 +0300 Subject: [PATCH 0487/5359] introduce WP_CLI::locate_wp_config() --- src/php/wp-cli/class-wp-cli.php | 44 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 6eaaac3f4..f05684633 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -261,24 +261,23 @@ static function _set_url( &$assoc_args ) { } } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); - } else { + } elseif ( $wp_config_path = self::locate_wp_config() ) { // Try to find the blog parameter in the wp-config file - if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { - $wp_config_file = file_get_contents( WP_ROOT . '/wp-config.php' ); - $hit = array(); - if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { - foreach( $matches[2] as $def_key => $def_name ) { - if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[5][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[5][$def_key]; - } + $wp_config_file = file_get_contents( $wp_config_path ); + $hit = array(); + if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { + foreach ( $matches[2] as $def_key => $def_name ) { + if ( 'DOMAIN_CURRENT_SITE' == $def_name ) + $hit['domain'] = $matches[5][$def_key]; + if ( 'PATH_CURRENT_SITE' == $def_name ) + $hit['path'] = $matches[5][$def_key]; } - if ( !empty( $hit ) && isset( $hit['domain'] ) ) - $blog = $hit['domain']; - if ( !empty( $hit ) && isset( $hit['path'] ) ) - $blog .= $hit['path']; } + + if ( !empty( $hit ) && isset( $hit['domain'] ) ) + $blog = $hit['domain']; + if ( !empty( $hit ) && isset( $hit['path'] ) ) + $blog .= $hit['path']; } if ( isset( $blog ) ) { @@ -290,12 +289,19 @@ static function _set_url( &$assoc_args ) { static function load_wp_config() { define( 'ABSPATH', dirname(__FILE__) . '/' ); + if ( $wp_config_path = self::locate_wp_config() ) + require self::locate_wp_config(); + else + WP_CLI::error( 'No wp-config.php file.' ); + } + + static function locate_wp_config() { if ( file_exists( WP_ROOT . 'wp-config.php' ) ) { - require_once( WP_ROOT . 'wp-config.php' ); - } elseif ( file_exists( dirname(WP_ROOT) . '/wp-config.php' ) && ! file_exists( dirname(WP_ROOT) . '/wp-settings.php' ) ) { - require_once( dirname(WP_ROOT) . '/wp-config.php' ); + return WP_ROOT . 'wp-config.php'; + } elseif ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) { + return WP_ROOT . '/../wp-config.php'; } else { - WP_CLI::error( 'No wp-config.php file.' ); + return false; } } From 68541632a0e1f777187b81a15a7f03a4cc60f99e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 23:18:35 +0300 Subject: [PATCH 0488/5359] replace --really with --yes --- man/db-drop.1 | 19 ------------------- src/doc/db-drop.txt | 4 ++-- src/php/wp-cli/commands/internals/db.php | 2 +- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/man/db-drop.1 b/man/db-drop.1 index 3a370feb8..e69de29bb 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-DROP" "1" "May 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-drop\fR \- Drop the database specified in wp\-config\.php -. -.SH "SYNOPSIS" -\fBwp db drop\fR [\-\-really] -. -.SH "OPTIONS" -. -.TP -\fB\-\-really\fR: -. -.IP -Skip the confirmation messaje\. - diff --git a/src/doc/db-drop.txt b/src/doc/db-drop.txt index 074b14123..15a1bbd8f 100644 --- a/src/doc/db-drop.txt +++ b/src/doc/db-drop.txt @@ -7,6 +7,6 @@ wp-db-drop(1) -- Drop the database specified in wp-config.php ## OPTIONS -* `--really`: +* `--yes`: - Skip the confirmation messaje. + Answer yes to the confirmation message. diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 30f9e9e52..ec5780fad 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -28,7 +28,7 @@ function create() { * Deletes the database specified in the wp-config.php file. */ function drop( $args, $assoc_args ) { - if ( !isset( $assoc_args['really'] ) ) { + if ( !isset( $assoc_args['yes'] ) ) { WP_CLI::out( "Are you sure you want to drop the database? [y/n] " ); $answer = trim( fgets( STDIN ) ); From bc6a036f662c166a36e8eca83aebb52c8ba391f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 23:34:29 +0300 Subject: [PATCH 0489/5359] add install_network subcommand. fixes #139 --- man/core-install_network.1 | 0 src/doc/core-install_network.txt | 17 +++++++ src/php/wp-cli/commands/internals/core.php | 59 ++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 man/core-install_network.1 create mode 100644 src/doc/core-install_network.txt diff --git a/man/core-install_network.1 b/man/core-install_network.1 new file mode 100644 index 000000000..e69de29bb diff --git a/src/doc/core-install_network.txt b/src/doc/core-install_network.txt new file mode 100644 index 000000000..d40d94648 --- /dev/null +++ b/src/doc/core-install_network.txt @@ -0,0 +1,17 @@ +wp-core-install_network(1) -- Transform a single-site install into a +multi-site install. +==== + +## SYNOPSIS + +`wp core install_network` --title=<network-title> [--base_path=/] + +## OPTIONS + +* `--title`=<site-title>: + + The title of the new network. + +* `--base_path`=<path>: + + Base path after the domain name that each site url will start with. diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 4d45d4371..38d7fc88a 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -90,6 +90,65 @@ public function install( $args, $assoc_args ) { } } + public function install_network( $args, $assoc_args ) { + if ( is_multisite() ) + WP_CLI::error( 'This already is a multisite install.' ); + + global $wpdb; + + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + + // need to register the multisite tables manually for some reason + foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) + $wpdb->$table = $prefixed_table; + + WP_CLI::check_required_args( array( 'title' ), $assoc_args ); + + extract( wp_parse_args( $assoc_args, array( + 'base' => '/', + ) ) ); + + $hostname = self::get_clean_basedomain(); + $subdomain_install = isset( $assoc_args['subdomains'] ); + + install_network(); + + $result = populate_network( 1, $hostname, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); + + if ( is_wp_error( $result ) ) + WP_CLI::error( $result ); + + ob_start(); +?> +define('MULTISITE', true); +define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>); +$base = '<?php echo $base; ?>'; +define('DOMAIN_CURRENT_SITE', '<?php echo $hostname; ?>'); +define('PATH_CURRENT_SITE', '<?php echo $base; ?>'); +define('SITE_ID_CURRENT_SITE', 1); +define('BLOG_ID_CURRENT_SITE', 1); + +<?php + $ms_config = ob_get_clean(); + + $wp_config_path = WP_CLI::locate_wp_config(); + + $token = "/* That's all, stop editing!"; + + list( $before, $after ) = explode( $token, file_get_contents( $wp_config_path ) ); + + file_put_contents( $wp_config_path, $before . $ms_config . $token . $after ); + + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + } + + private static function get_clean_basedomain() { + $domain = preg_replace( '|https?://|', '', get_option( 'siteurl' ) ); + if ( $slash = strpos( $domain, '/' ) ) + $domain = substr( $domain, 0, $slash ); + return $domain; + } + /** * Display the WordPress version. */ From e03b3ba8b8baf2389428296a40807ba5e96a5624 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 23:48:14 +0300 Subject: [PATCH 0490/5359] fix man page. see #139 --- man/core-install_network.1 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/man/core-install_network.1 b/man/core-install_network.1 index e69de29bb..09fcc2890 100644 --- a/man/core-install_network.1 +++ b/man/core-install_network.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-INSTALL_NETWORK" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-install_network\fR \- Transform a single\-site install into a +. +.SH "SYNOPSIS" +\fBwp core install_network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=/] +. +.SH "OPTIONS" +. +.TP +\fB\-\-title\fR=\fIsite\-title\fR: +. +.IP +The title of the new network\. +. +.TP +\fB\-\-base_path\fR=\fIpath\fR: +. +.IP +Base path after the domain name that each site url will start with\. + From e92ea5210b9a05cf70616511e03748a3d9dc9e9d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Jul 2012 23:49:09 +0300 Subject: [PATCH 0491/5359] check if ronn is installed --- utils/doc-build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/doc-build b/utils/doc-build index 9a71c69f9..87ca6f64f 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -11,6 +11,11 @@ else files=$@ fi +if ! which ronn; then + echo "doc-build: ronn is not installed" + exit 1 +fi + for file in $files; do man_file=man/$(basename $file .txt).1 cat $file | ronn --roff --manual="WP-CLI" > $man_file From 0e85d0514993c83f9ccea0c8aa2f8e4d6818be7b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 00:15:43 +0300 Subject: [PATCH 0492/5359] create blogs.dir. see #139 --- src/php/wp-cli/commands/internals/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 38d7fc88a..8c8b1ceca 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -139,6 +139,8 @@ public function install_network( $args, $assoc_args ) { file_put_contents( $wp_config_path, $before . $ms_config . $token . $after ); + wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); } From db13ea5aeafcd9c736f8bae10f0a0e040d8522b2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 19:32:45 +0300 Subject: [PATCH 0493/5359] add --porcelain flag to `wp user create` --- man/user-create.1 | 10 ++++++++-- src/doc/user-create.txt | 6 +++++- src/php/wp-cli/commands/internals/user.php | 13 ++++++++----- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/man/user-create.1 b/man/user-create.1 index 9f71326f3..c96e19827 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-CREATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-USER\-CREATE" "1" "July 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-create\fR \- Create a new WordPress user\. . .SH "SYNOPSIS" -\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] +\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-porcelain] . .SH "OPTIONS" . @@ -29,6 +29,12 @@ The email address of the user to create\. .IP The role of the user to create\. . +.TP +\fB\-\-porcelain\fR: +. +.IP +Output just the new user id\. +. .SH "EXAMPLES" . .nf diff --git a/src/doc/user-create.txt b/src/doc/user-create.txt index 1173efcf4..0ed2e2214 100644 --- a/src/doc/user-create.txt +++ b/src/doc/user-create.txt @@ -3,7 +3,7 @@ wp-user-create(1) -- Create a new WordPress user. ## SYNOPSIS -`wp user create` <user-login> <user-email> [--role=<role>] +`wp user create` <user-login> <user-email> [--role=<role>] [--porcelain] ## OPTIONS @@ -19,6 +19,10 @@ wp-user-create(1) -- Create a new WordPress user. The role of the user to create. +* `--porcelain`: + + Output just the new user id. + ## EXAMPLES wp user create bob bob@example.com --role=author diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 2c9a6238b..2f601958e 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -59,7 +59,7 @@ public function _list( $args, $assoc_args ) { **/ public function delete( $args, $assoc_args ) { global $blog_id; - + $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); $defaults = array( 'reassign' => NULL ); @@ -122,7 +122,10 @@ public function create( $args, $assoc_args ) { } } - WP_CLI::success( "Created user $user_id." ); + if ( isset( $assoc_args['porcelain'] ) ) + WP_CLI::line( $user_id ); + else + WP_CLI::success( "Created user $user_id." ); } /** @@ -148,7 +151,7 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } - + private function get_numeric_arg_or_error( $args, $index, $name ) { $value = self::get_arg_or_error( $args, $index, $name ); if ( ! is_numeric( $value ) ) { @@ -156,14 +159,14 @@ private function get_numeric_arg_or_error( $args, $index, $name ) { } return $value; } - + private function get_arg_or_error( $args, $index, $name ) { if ( ! isset( $args[$index] ) ) { self::error_see_help( "$name required" ); } return $args[$index]; } - + private function error_see_help( $message ) { WP_CLI::error( "$message (see 'wp user help')."); } From b036a5fb197ae108129ffce1dd6fe19f7abe45df Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 19:32:57 +0300 Subject: [PATCH 0494/5359] silence output from which --- utils/doc-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/doc-build b/utils/doc-build index 87ca6f64f..a4bf43d08 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -11,7 +11,7 @@ else files=$@ fi -if ! which ronn; then +if ! which ronn > /dev/null; then echo "doc-build: ronn is not installed" exit 1 fi From 5258812e3019250d9e08fbbe6e423a815a3a0721 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 19:52:15 +0300 Subject: [PATCH 0495/5359] move User_Command::get_numeric_arg_or_error() to WP_CLI::get_numeric_arg() --- src/php/wp-cli/class-wp-cli.php | 12 ++++++++++ src/php/wp-cli/commands/internals/user.php | 28 ++++------------------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index f05684633..8b5864e3d 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -190,6 +190,18 @@ static function check_required_args( $required, $assoc_args ) { exit(1); } + static function get_numeric_arg( $args, $index, $name ) { + if ( ! isset( $args[$index] ) ) { + WP_CLI::error( "$name required" ); + } + + if ( ! is_numeric( $args[$index] ) ) { + WP_CLI::error( "$name must be numeric" ); + } + + return $args[$index]; + } + /** * Display a legend * diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 2f601958e..e5539639b 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -60,7 +60,7 @@ public function _list( $args, $assoc_args ) { public function delete( $args, $assoc_args ) { global $blog_id; - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); $defaults = array( 'reassign' => NULL ); @@ -82,11 +82,10 @@ public function delete( $args, $assoc_args ) { public function create( $args, $assoc_args ) { global $blog_id; - $user_login = $args[0]; - $user_email = $args[1]; + list( $user_login, $user_email ) = $args[0]; if ( ! $user_login || ! $user_email ) { - self::error_see_help( "Login and email required" ); + WP_CLI::error( "Login and email required." ); } $defaults = array( @@ -135,7 +134,7 @@ public function create( $args, $assoc_args ) { * @param array $assoc_args **/ public function update( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); + $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); if ( empty( $assoc_args ) ) { WP_CLI::error( "Need some fields to update." ); @@ -151,23 +150,4 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } - - private function get_numeric_arg_or_error( $args, $index, $name ) { - $value = self::get_arg_or_error( $args, $index, $name ); - if ( ! is_numeric( $value ) ) { - self::error_see_help( "$name must be numeric" ); - } - return $value; - } - - private function get_arg_or_error( $args, $index, $name ) { - if ( ! isset( $args[$index] ) ) { - self::error_see_help( "$name required" ); - } - return $args[$index]; - } - - private function error_see_help( $message ) { - WP_CLI::error( "$message (see 'wp user help')."); - } } From 5a538c7b983f8225b87744f100ccd754ac31abed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 20:26:48 +0300 Subject: [PATCH 0496/5359] add basic post commands. fixes #141 --- src/php/wp-cli/commands/internals/post.php | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/post.php diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php new file mode 100644 index 000000000..97687b56c --- /dev/null +++ b/src/php/wp-cli/commands/internals/post.php @@ -0,0 +1,69 @@ +<?php + +WP_CLI::add_command( 'post', 'Post_Command' ); + +/** + * Implement post command + * + * @package wp-cli + * @subpackage commands/internals + */ +class Post_Command extends WP_CLI_Command { + + /** + * Create a post + * + * @param array $args + * @param array $assoc_args + */ + public function create( $args, $assoc_args ) { + $post_id = wp_insert_post( $assoc_args, true ); + + if ( is_wp_error( $post_id ) ) { + WP_CLI::error( $post_id ); + } + + if ( isset( $assoc_args['porcelain'] ) ) + WP_CLI::line( $post_id ); + else + WP_CLI::success( "Created post $post_id." ); + } + + /** + * Update a user + * + * @param array $args + * @param array $assoc_args + */ + public function update( $args, $assoc_args ) { + $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); + + if ( empty( $assoc_args ) ) { + WP_CLI::error( "Need some fields to update." ); + } + + $params = array_merge( $assoc_args, array( 'ID' => $post_id ) ); + + if ( wp_update_post( $params ) ) { + WP_CLI::success( "Updated post $post_id." ); + } else { + WP_CLI::error( "Failed updating post $post_id" ); + } + } + + /** + * Delete a post + * + * @param array $args + * @param array $assoc_args + */ + public function delete( $args, $assoc_args ) { + $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); + + if ( wp_delete_post( $post_id, isset( $assoc_args['force'] ) ) ) { + WP_CLI::success( "Deleted post $post_id." ); + } else { + WP_CLI::error( "Failed deleting post $post_id." ); + } + } +} From 7101df24f14887e32534bb31cd742327d083677c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 20:35:21 +0300 Subject: [PATCH 0497/5359] add docs for post commands. see #141 --- man/post-create.1 | 35 +++++++++++++++++++++++++++++++++++ man/post-delete.1 | 33 +++++++++++++++++++++++++++++++++ man/post-update.1 | 33 +++++++++++++++++++++++++++++++++ src/doc/post-create.txt | 21 +++++++++++++++++++++ src/doc/post-delete.txt | 20 ++++++++++++++++++++ src/doc/post-update.txt | 20 ++++++++++++++++++++ 6 files changed, 162 insertions(+) create mode 100644 man/post-create.1 create mode 100644 man/post-delete.1 create mode 100644 man/post-update.1 create mode 100644 src/doc/post-create.txt create mode 100644 src/doc/post-delete.txt create mode 100644 src/doc/post-update.txt diff --git a/man/post-create.1 b/man/post-create.1 new file mode 100644 index 000000000..3ed689f81 --- /dev/null +++ b/man/post-create.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-CREATE" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-create\fR \- Create a new WordPress post\. +. +.SH "SYNOPSIS" +\fBwp post create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-porcelain] +. +.SH "OPTIONS" +. +.TP +\fB\-\-<field>\fR=\fIvalue\fR: +. +.IP +Field values for the new post\. See wp_insert_post()\. +. +.TP +\fB\-\-porcelain\fR: +. +.IP +Output just the new post id\. +. +.SH "EXAMPLES" +. +.nf + +wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A new +. +.fi +. +.P +page\' diff --git a/man/post-delete.1 b/man/post-delete.1 new file mode 100644 index 000000000..3bfd901a9 --- /dev/null +++ b/man/post-delete.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-DELETE" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-delete\fR \- Delete a WordPress post\. +. +.SH "SYNOPSIS" +\fBwp post delete\fR \fIID\fR [\-\-force] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the post to delete\. +. +.TP +\fB\-\-force\fR: +. +.IP +Skip the trash bin\. +. +.SH "EXAMPLES" +. +.nf + +wp post delete 123 \-\-force +. +.fi + diff --git a/man/post-update.1 b/man/post-update.1 new file mode 100644 index 000000000..7ef6418ed --- /dev/null +++ b/man/post-update.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-UPDATE" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-update\fR \- Update a WordPress post\. +. +.SH "SYNOPSIS" +\fBwp post update\fR \fIID\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the post to update\. +. +.TP +\fB\-\-<field>\fR=\fIvalue\fR: +. +.IP +One or more fields to update\. See wp_update_post()\. +. +.SH "EXAMPLES" +. +.nf + +wp post update 123 \-\-post_name=something \-\-post_status=draft +. +.fi + diff --git a/src/doc/post-create.txt b/src/doc/post-create.txt new file mode 100644 index 000000000..467f30501 --- /dev/null +++ b/src/doc/post-create.txt @@ -0,0 +1,21 @@ +wp-post-create(1) -- Create a new WordPress post. +==== + +## SYNOPSIS + +`wp post create` --<field>=<value> [--<field>=<value>...] [--porcelain] + +## OPTIONS + +* `--<field>`=<value>: + + Field values for the new post. See wp_insert_post(). + +* `--porcelain`: + + Output just the new post id. + +## EXAMPLES + + wp post create --post_type=page --post_status=publish --post_title='A new +page' diff --git a/src/doc/post-delete.txt b/src/doc/post-delete.txt new file mode 100644 index 000000000..97c07cc74 --- /dev/null +++ b/src/doc/post-delete.txt @@ -0,0 +1,20 @@ +wp-post-delete(1) -- Delete a WordPress post. +==== + +## SYNOPSIS + +`wp post delete` <ID> [--force] + +## OPTIONS + +* `<ID>`: + + The ID of the post to delete. + +* `--force`: + + Skip the trash bin. + +## EXAMPLES + + wp post delete 123 --force diff --git a/src/doc/post-update.txt b/src/doc/post-update.txt new file mode 100644 index 000000000..53a454859 --- /dev/null +++ b/src/doc/post-update.txt @@ -0,0 +1,20 @@ +wp-post-update(1) -- Update a WordPress post. +==== + +## SYNOPSIS + +`wp post update` <ID> --<field>=<value> [--<field>=<value>...] + +## OPTIONS + +* `<ID>`: + + The ID of the post to update. + +* `--<field>`=<value>: + + One or more fields to update. See wp_update_post(). + +## EXAMPLES + + wp post update 123 --post_name=something --post_status=draft From 35ec772f8b6c5432b77ef8f56d302f54c4be2a75 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 21:49:24 +0300 Subject: [PATCH 0498/5359] introduce WP_CLI_Command_With_Meta and implement wp post-meta with it. see #141 --- man/post-meta.1 | 54 +++++++++ src/doc/post-meta.txt | 35 ++++++ .../wp-cli/class-wp-cli-command-with-meta.php | 101 +++++++++++++++++ .../wp-cli/commands/internals/post-meta.php | 14 +++ .../wp-cli/commands/internals/user-meta.php | 107 +----------------- src/php/wp-cli/wp-cli.php | 1 + 6 files changed, 209 insertions(+), 103 deletions(-) create mode 100644 man/post-meta.1 create mode 100644 src/doc/post-meta.txt create mode 100644 src/php/wp-cli/class-wp-cli-command-with-meta.php create mode 100644 src/php/wp-cli/commands/internals/post-meta.php diff --git a/man/post-meta.1 b/man/post-meta.1 new file mode 100644 index 000000000..65bce7c9b --- /dev/null +++ b/man/post-meta.1 @@ -0,0 +1,54 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-META" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-meta\fR \- Manage post custom fields\. +. +.SH "SYNOPSIS" +wp post\-meta get \fIID\fR \fIkey\fR [\-\-json] +. +.P +wp post\-meta add \fIID\fR \fIkey\fR \fIvalue\fR +. +.P +wp post\-meta update \fIID\fR \fIkey\fR \fIvalue\fR +. +.P +wp post\-meta delete \fIID\fR \fIkey\fR +. +.SH "SUBCOMMANDS" +. +.TP +\fBget\fR: +. +.IP +Get a custom field value\. Passing \-\-json causes the output to be formatted as JSON\. +. +.TP +\fBadd\fR: +. +.IP +Add a new custom field\. +. +.TP +\fBupdate\fR: +. +.IP +Update an existing custom field\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a custom field\. +. +.SH "EXAMPLES" +. +.nf + +wp post\-meta set 123 _wp_page_template about\.php +. +.fi + diff --git a/src/doc/post-meta.txt b/src/doc/post-meta.txt new file mode 100644 index 000000000..55a0af328 --- /dev/null +++ b/src/doc/post-meta.txt @@ -0,0 +1,35 @@ +wp-post-meta(1) -- Manage post custom fields. +==== + +## SYNOPSIS + +wp post-meta get <ID> <key> [--json] + +wp post-meta add <ID> <key> <value> + +wp post-meta update <ID> <key> <value> + +wp post-meta delete <ID> <key> + +## SUBCOMMANDS + +* `get`: + + Get a custom field value. Passing --json causes the output to be formatted + as JSON. + +* `add`: + + Add a new custom field. + +* `update`: + + Update an existing custom field. + +* `delete`: + + Delete a custom field. + +## EXAMPLES + + wp post-meta set 123 _wp_page_template about.php diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/src/php/wp-cli/class-wp-cli-command-with-meta.php new file mode 100644 index 000000000..62934e48b --- /dev/null +++ b/src/php/wp-cli/class-wp-cli-command-with-meta.php @@ -0,0 +1,101 @@ +<?php + +/** + * Base class for WP-CLI commands that deal with metadata + * + * @package wp-cli + */ +abstract class WP_CLI_Command_With_Meta extends WP_CLI_Command { + + protected $meta_type; + + protected $aliases = array( + 'set' => 'update' + ); + + /** + * Get meta field value + * + * @param array $args + * @param array $assoc_args + **/ + public function get( $args, $assoc_args ) { + $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); + $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + + $value = get_metadata( $this->meta_type, $object_id, $meta_key, true ); + + if ( '' === $value ) + die(1); + + WP_CLI::print_value( $value, $assoc_args ); + } + + /** + * Get meta field value for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function delete( $args, $assoc_args ) { + $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); + $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + + $success = delete_metadata( $this->meta_type, $object_id, $meta_key ); + + if ( $success ) { + WP_CLI::success( "Deleted custom field." ); + } else { + WP_CLI::error( "Failed to delete custom field." ); + } + } + + /** + * Update meta field for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function add( $args, $assoc_args ) { + $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); + $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + $meta_value = self::get_arg_or_error( $args, 2, "meta_value" ); + + $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + + if ( $success ) { + WP_CLI::success( "Added custom field." ); + } else { + WP_CLI::error( "Failed to add custom field." ); + } + } + + /** + * Update meta field for a user + * + * @param array $args + * @param array $assoc_args + **/ + public function update( $args, $assoc_args ) { + $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); + $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + $meta_value = self::get_arg_or_error( $args, 2, "meta_value" ); + + $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + + if ( $success ) { + WP_CLI::success( "Updated custom field." ); + } else { + WP_CLI::error( "Failed to update custom field." ); + } + } + + protected function get_arg_or_error( $args, $index, $name ) { + if ( ! isset( $args[$index] ) ) { + WP_CLI::error( "$name required" ); + } + + return $args[$index]; + } +} + diff --git a/src/php/wp-cli/commands/internals/post-meta.php b/src/php/wp-cli/commands/internals/post-meta.php new file mode 100644 index 000000000..6e3b710f8 --- /dev/null +++ b/src/php/wp-cli/commands/internals/post-meta.php @@ -0,0 +1,14 @@ +<?php + +WP_CLI::add_command( 'post-meta', 'Post_Meta_Command' ); + +/** + * Implement post-meta command + * + * @package wp-cli + * @subpackage commands/internals + */ +class Post_Meta_Command extends WP_CLI_Command_With_Meta { + protected $meta_type = 'post'; +} + diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index b12a8adde..317420652 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -1,113 +1,14 @@ <?php -WP_CLI::add_command('user-meta', 'User_Meta_Command'); +WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); /** - * Implement user command + * Implement user-meta command * * @package wp-cli * @subpackage commands/internals */ -class User_Meta_Command extends WP_CLI_Command { - - protected $aliases = array( - 'set' => 'update' - ); - - /** - * Get meta field value for a user - * - * @param array $args - * @param array $assoc_args - **/ - public function get( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key"); - - $value = get_user_meta( $user_id, $meta_key, true ); - - if ( '' === $value ) - die(1); - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Get meta field value for a user - * - * @param array $args - * @param array $assoc_args - **/ - public function delete( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key"); - - $success = delete_user_meta( $user_id, $meta_key ); - - if ( $success ) { - WP_CLI::success( "Deleted custom field." ); - } else { - WP_CLI::error( "Failed to delete custom field." ); - } - } - - /** - * Update meta field for a user - * - * @param array $args - * @param array $assoc_args - **/ - public function add( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key"); - $meta_value = self::get_arg_or_error($args, 2, "meta_value"); - - $success = add_user_meta( $user_id, $meta_key, $meta_value ); - - if ( $success ) { - WP_CLI::success( "Added custom field." ); - } else { - WP_CLI::error( "Failed to add custom field." ); - } - } - - /** - * Update meta field for a user - * - * @param array $args - * @param array $assoc_args - **/ - public function update( $args, $assoc_args ) { - $user_id = self::get_numeric_arg_or_error($args, 0, "User ID"); - $meta_key = self::get_arg_or_error($args, 1, "meta_key"); - $meta_value = self::get_arg_or_error($args, 2, "meta_value"); - - $success = update_user_meta( $user_id, $meta_key, $meta_value ); - - if ( $success ) { - WP_CLI::success( "Updated custom field." ); - } else { - WP_CLI::error( "Failed to update custom field." ); - } - } - - private function get_numeric_arg_or_error( $args, $index, $name ) { - $value = self::get_arg_or_error( $args, $index, $name ); - if ( ! is_numeric( $value ) ) { - self::error_see_help( "$name must be numeric" ); - } - return $value; - } - - private function get_arg_or_error( $args, $index, $name ) { - if ( ! isset( $args[$index] ) ) { - self::error_see_help( "$name required" ); - } - return $args[$index]; - } - - private function error_see_help( $message ) { - WP_CLI::error( "$message (see 'wp user-meta help')."); - } +class User_Meta_Command extends WP_CLI_Command_With_Meta { + protected $meta_type = 'user'; } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 22485f1b5..5da128c23 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -16,6 +16,7 @@ // Include the wp-cli classes include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; +include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; // Include the command line tools From 170def0ccd3167d8eb33823582e76033ff45ae5d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 23:30:36 +0300 Subject: [PATCH 0499/5359] convert error message into string. see #140 --- src/php/wp-cli/class-cli-upgrader-skin.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index 93488b8ca..029811e88 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -16,8 +16,13 @@ function error( $error ) { if ( !$error ) return; + if ( isset( $this->upgrader->strings[$error] ) ) + $string = $this->upgrader->strings[$error]; + else + $string = $error; + // TODO: show all errors, not just the first one - WP_CLI::warning( $error ); + WP_CLI::warning( $string ); } function feedback( $string ) { From 9c6bf7d7207a9b5cd7b0236999e64eeee1a845b7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 5 Jul 2012 23:44:51 +0300 Subject: [PATCH 0500/5359] pass plugin file not plugin name to the upgrader. fixes #140 --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index fcd334658..ab13718dc 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -83,7 +83,7 @@ function update( $args, $assoc_args ) { if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); - WP_CLI::get_upgrader( $this->upgrader )->upgrade( $name ); + WP_CLI::get_upgrader( $this->upgrader )->upgrade( $file ); } else { $this->update_multiple( $args, $assoc_args ); } From c30a4bc5dfcf8f971f16d37b283557546e89e9b6 Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Thu, 5 Jul 2012 14:11:18 -0700 Subject: [PATCH 0501/5359] Core Update with specified `--version` from WP.org Can now update core with --version without specifying a local package. Also, `--force` added to allow downgrades. _Use With Caution_ --- man/core-update.1 | 6 ++- src/doc/core-update.txt | 7 ++- src/php/wp-cli/commands/internals/core.php | 51 +++++++++++----------- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/man/core-update.1 b/man/core-update.1 index 4e8c61215..665925fe3 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -18,10 +18,10 @@ When passed, it applies any outstanding database upgrades, without touching the files\. . .TP -\fB\-\-version=\fR\fInew_version\fR <package/zip>: +\fB\-\-version=\fR\fInew_version\fR [\-\-force] [package/zip]: . .IP -When passed, updates to new_version using package/zip as input\. +When passed, updates to new_version, optionally using package/zip as input\. Will update even when current WP version < new_version if \-\-force is specified\. Use with caution, since if you update to < 3\.0, you won\'t be able to revert using wp\-cli\. . .SH "EXAMPLES" . @@ -30,6 +30,8 @@ When passed, updates to new_version using package/zip as input\. wp core update wp core update \-\-version=3\.4 \.\./latest\.zip + +wp core update \-\-version=3\.1 \-\-force . .fi diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index 411ea0082..23da940ee 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -12,12 +12,15 @@ wp-core-update(1) -- Update WordPress to the latest version. When passed, it applies any outstanding database upgrades, without touching the files. -* `--version=`<new_version> <package/zip>: +* `--version=`<new_version> [--force] [package/zip]: - When passed, updates to new_version using package/zip as input. + When passed, updates to new_version, optionally using package/zip as input. + Will update even when current WP version < new_version if --force is specified. Use with caution, since if you update to < 3.0, you won't be able to revert using wp-cli. ## EXAMPLES wp core update wp core update --version=3.4 ../latest.zip + + wp core update --version=3.1 --force diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index ee96d11cc..73ec3028d 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -133,7 +133,8 @@ public function version( $args = array(), $assoc_args = array() ) { */ function update( $args, $assoc_args ) { global $wp_version; - $update = $from_api = $upgrader = null; + $update = $from_api = null; + $upgrader = 'Core_Upgrader'; if ( isset( $assoc_args['db'] ) ) { wp_upgrade(); @@ -150,34 +151,34 @@ function update( $args, $assoc_args ) { else list( $update ) = $from_api->updates; - $upgrader = 'Core_Upgrader'; + } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) + || isset( $assoc_args['force'] ) ) { - } else { - if ( empty( $args[0] ) ) - WP_CLI::error( "Package not specified." ); - - $new_package = $args[0]; - $new_version = $assoc_args['version']; - - if ( version_compare( $wp_version, $new_version, '<' ) ) { - $update = (object) array( - 'response' => 'upgrade', - 'current' => $new_version, - 'download' => $new_package, - 'packages' => (object) array ( - 'partial' => null, - 'new_bundled' => null, - 'no_content' => null, - 'full' => $new_package, - ), - ); - - $upgrader = 'Non_Destructive_Core_Upgrader'; + $new_package = null; + if ( empty( $args[0] ) ) { + $new_package = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { - WP_CLI::success( 'WordPress is up to date.' ); - return; + $new_package = $args[0]; + $upgrader = 'Non_Destructive_Core_Upgrader'; } + + $update = (object) array( + 'response' => 'upgrade', + 'current' => $assoc_args['version'], + 'download' => $new_package, + 'packages' => (object) array ( + 'partial' => null, + 'new_bundled' => null, + 'no_content' => null, + 'full' => $new_package, + ), + ); + + } else { + WP_CLI::success( 'WordPress is up to date.' ); + return; } require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); From 29e0407dc7f677a4d8dfc58ffea7082051428aaf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Jul 2012 01:22:53 +0300 Subject: [PATCH 0502/5359] update docs. see #136 --- man/core-update.1 | 2 +- src/doc/core-update.txt | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/man/core-update.1 b/man/core-update.1 index 665925fe3..9a667d392 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -7,7 +7,7 @@ \fBwp\-core\-update\fR \- Update WordPress to the latest version\. . .SH "SYNOPSIS" -\fBwp core update\fR [\-\-db] [\-\-version=\fInew_version\fR <package/zip>] +\fBwp core update\fR [\-\-db] [\-\-version=\fInew_version\fR] [\-\-force] [<package/zip>] . .SH "OPTIONS" . diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index 23da940ee..e3fb990eb 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -3,7 +3,7 @@ wp-core-update(1) -- Update WordPress to the latest version. ## SYNOPSIS -`wp core update` [--db] [--version=<new_version> <package/zip>] +`wp core update` [--db] [--version=<new_version>] [--force] [<package/zip>] ## OPTIONS @@ -14,8 +14,11 @@ touching the files. * `--version=`<new_version> [--force] [package/zip]: - When passed, updates to new_version, optionally using package/zip as input. - Will update even when current WP version < new_version if --force is specified. Use with caution, since if you update to < 3.0, you won't be able to revert using wp-cli. + When passed, updates to new_version, optionally using package/zip as +input. + Will update even when current WP version < new_version if --force is +specified. Use with caution, since if you update to < 3.0, you won't be able +to revert using wp-cli. ## EXAMPLES From 0e551345a568c61085be6e4f298c5ecf3232f4ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Jul 2012 01:26:48 +0300 Subject: [PATCH 0503/5359] move --force to it's own section. see #136 --- man/core-update.1 | 10 ++++++++-- src/doc/core-update.txt | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/man/core-update.1 b/man/core-update.1 index 9a667d392..687a18154 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -18,10 +18,16 @@ When passed, it applies any outstanding database upgrades, without touching the files\. . .TP -\fB\-\-version=\fR\fInew_version\fR [\-\-force] [package/zip]: +\fB\-\-version=\fR\fInew_version\fR [package/zip]: . .IP -When passed, updates to new_version, optionally using package/zip as input\. Will update even when current WP version < new_version if \-\-force is specified\. Use with caution, since if you update to < 3\.0, you won\'t be able to revert using wp\-cli\. +When passed, updates to new_version, optionally using package/zip as input\. +. +.TP +\fB\-\-force\fR: +. +.IP +Will update even when current WP version < passed version\. Use with caution\. . .SH "EXAMPLES" . diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index e3fb990eb..3bccb6ce7 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -12,13 +12,15 @@ wp-core-update(1) -- Update WordPress to the latest version. When passed, it applies any outstanding database upgrades, without touching the files. -* `--version=`<new_version> [--force] [package/zip]: +* `--version=`<new_version> [package/zip]: When passed, updates to new_version, optionally using package/zip as input. - Will update even when current WP version < new_version if --force is -specified. Use with caution, since if you update to < 3.0, you won't be able -to revert using wp-cli. + +* `--force`: + + Will update even when current WP version < passed version. Use with +caution. ## EXAMPLES From f06fbae9c33661bc82a04a6ea676468c461d1463 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Jul 2012 01:32:18 +0300 Subject: [PATCH 0504/5359] move database upgrade out of wp core update again. see #121 --- man/core-update.1 | 8 +------- man/core-update_db.1 | 10 ++++++++++ src/doc/core-update.txt | 7 +------ src/doc/core-update_db.txt | 6 ++++++ src/php/wp-cli/commands/internals/core.php | 18 +++++++++++------- 5 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 man/core-update_db.1 create mode 100644 src/doc/core-update_db.txt diff --git a/man/core-update.1 b/man/core-update.1 index 687a18154..af27373d7 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -7,17 +7,11 @@ \fBwp\-core\-update\fR \- Update WordPress to the latest version\. . .SH "SYNOPSIS" -\fBwp core update\fR [\-\-db] [\-\-version=\fInew_version\fR] [\-\-force] [<package/zip>] +\fBwp core update\fR [\-\-version=\fInew_version\fR] [\-\-force] [<package/zip>] . .SH "OPTIONS" . .TP -\fB\-\-db\fR: -. -.IP -When passed, it applies any outstanding database upgrades, without touching the files\. -. -.TP \fB\-\-version=\fR\fInew_version\fR [package/zip]: . .IP diff --git a/man/core-update_db.1 b/man/core-update_db.1 new file mode 100644 index 000000000..e9a570d92 --- /dev/null +++ b/man/core-update_db.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-UPDATE_DB" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-update_db\fR \- Update the WordPress database\. +. +.SH "SYNOPSIS" +\fBwp core update_db\fR diff --git a/src/doc/core-update.txt b/src/doc/core-update.txt index 3bccb6ce7..abdc56e07 100644 --- a/src/doc/core-update.txt +++ b/src/doc/core-update.txt @@ -3,15 +3,10 @@ wp-core-update(1) -- Update WordPress to the latest version. ## SYNOPSIS -`wp core update` [--db] [--version=<new_version>] [--force] [<package/zip>] +`wp core update` [--version=<new_version>] [--force] [<package/zip>] ## OPTIONS -* `--db`: - - When passed, it applies any outstanding database upgrades, without -touching the files. - * `--version=`<new_version> [package/zip]: When passed, updates to new_version, optionally using package/zip as diff --git a/src/doc/core-update_db.txt b/src/doc/core-update_db.txt new file mode 100644 index 000000000..746447513 --- /dev/null +++ b/src/doc/core-update_db.txt @@ -0,0 +1,6 @@ +wp-core-update_db(1) -- Update the WordPress database. +==== + +## SYNOPSIS + +`wp core update_db` diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 5962c29e8..f7419a979 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -197,12 +197,6 @@ function update( $args, $assoc_args ) { $update = $from_api = null; $upgrader = 'Core_Upgrader'; - if ( isset( $assoc_args['db'] ) ) { - wp_upgrade(); - WP_CLI::success( 'WordPress database upgraded successfully.' ); - return; - } - if ( empty( $assoc_args['version'] ) ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); @@ -257,5 +251,15 @@ function update( $args, $assoc_args ) { WP_CLI::success( 'WordPress updated successfully.' ); } } -} + /** + * Update the WordPress database + * + * @param array $args + * @param array $assoc_args + */ + function update_db() { + wp_upgrade(); + WP_CLI::success( 'WordPress database upgraded successfully.' ); + } +} From 49ddfb4f913a860ca7aad81271341e07388b9926 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Jul 2012 18:35:32 +0300 Subject: [PATCH 0505/5359] allow --no-delete flag to work --- src/php/wp-cli/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8b5864e3d..8dca01e32 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -135,9 +135,9 @@ static function parse_args( $arguments ) { $assoc_args = array(); foreach ( $arguments as $arg ) { - if ( preg_match( '|^--(\w+)$|', $arg, $matches ) ) { + if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { $assoc_args[ $matches[1] ] = true; - } elseif ( preg_match( '|^--(\w+)=(.+)|', $arg, $matches ) ) { + } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { $assoc_args[ $matches[1] ] = $matches[2]; } else { $regular_args[] = $arg; From 3e4a9e39ea102112ff8440d13b8c8f5f611bb145 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 10 Jul 2012 03:20:17 +0300 Subject: [PATCH 0506/5359] handle case where plugin is not found better --- src/php/wp-cli/commands/internals/plugin.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index acf7ca5cf..1da0d2e3a 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -192,7 +192,10 @@ protected function install_from_repo( $slug, $assoc_args ) { $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { - WP_CLI::error( $api ); + if ( null === maybe_unserialize( $api->get_error_data() ) ) + WP_CLI::error( 'Plugin not found.' ); + else + WP_CLI::error( $api ); } if ( isset( $assoc_args['version'] ) ) { From 8f24e29a9ac357cc38147307dbecf3ebda07a5ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 10 Jul 2012 16:19:24 +0300 Subject: [PATCH 0507/5359] harmonize error messages between themes and plugins --- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 1da0d2e3a..1fa343387 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -193,7 +193,7 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( is_wp_error( $api ) ) { if ( null === maybe_unserialize( $api->get_error_data() ) ) - WP_CLI::error( 'Plugin not found.' ); + WP_CLI::error( "Can't find the plugin in the WordPress.org repository." ); else WP_CLI::error( $api ); } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 8313d8d44..be09b205f 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -131,9 +131,12 @@ protected function install_from_repo( $slug, $assoc_args ) { $result = NULL; $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); + if ( is_wp_error( $api ) ) { - WP_CLI::error( "Can't find the theme in the WordPress.org theme repository." ); - exit(); + if ( null === maybe_unserialize( $api->get_error_data() ) ) + WP_CLI::error( "Can't find the theme in the WordPress.org repository." ); + else + WP_CLI::error( $api ); } // Check to see if we should update, rather than install. From 53f519d75bbca3e0172dffb01cdc90712cec550a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 10 Jul 2012 16:23:35 +0300 Subject: [PATCH 0508/5359] document the --activate flag for wp theme install --- man/theme-install.1 | 12 +++++++++--- src/doc/theme-install.txt | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/man/theme-install.1 b/man/theme-install.1 index 6b15db128..71f60fb0e 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-INSTALL" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-INSTALL" "1" "July 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-install\fR \- Install a theme from wordpress\.org or from a zip file\. . .SH "SYNOPSIS" -\fBwp theme install\fR <theme/zip> +\fBwp theme install\fR <theme/zip> [\-\-activate] . .SH "OPTIONS" . @@ -17,11 +17,17 @@ .IP A theme slug or the path to a zip file\. . +.TP +\fB\-\-activate\fR: +. +.IP +If set, the theme will be activated immediately after install\. +. .SH "EXAMPLES" . .nf -wp theme install twentytwelve +wp theme install twentytwelve \-\-activate wp theme install \.\./my\-theme\.zip . diff --git a/src/doc/theme-install.txt b/src/doc/theme-install.txt index 4f06c251b..df18a80e1 100644 --- a/src/doc/theme-install.txt +++ b/src/doc/theme-install.txt @@ -3,7 +3,7 @@ wp-theme-install(1) -- Install a theme from wordpress.org or from a zip file. ## SYNOPSIS -`wp theme install` <theme/zip> +`wp theme install` <theme/zip> [--activate] ## OPTIONS @@ -11,8 +11,12 @@ wp-theme-install(1) -- Install a theme from wordpress.org or from a zip file. A theme slug or the path to a zip file. +* `--activate`: + + If set, the theme will be activated immediately after install. + ## EXAMPLES - wp theme install twentytwelve + wp theme install twentytwelve --activate wp theme install ../my-theme.zip From a1475c791543fb91552a95caea3af0d77c35e357 Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Thu, 12 Jul 2012 14:18:14 -0700 Subject: [PATCH 0509/5359] Introduce `db optimize` and `db repair` --- man/db-optimize.1 | 10 ++++++++++ man/db-repair.1 | 10 ++++++++++ src/doc/db-optimize.txt | 6 ++++++ src/doc/db-repair.txt | 6 ++++++ src/php/wp-cli/commands/internals/db.php | 24 ++++++++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 man/db-optimize.1 create mode 100644 man/db-repair.1 create mode 100644 src/doc/db-optimize.txt create mode 100644 src/doc/db-repair.txt diff --git a/man/db-optimize.1 b/man/db-optimize.1 new file mode 100644 index 000000000..56b099bad --- /dev/null +++ b/man/db-optimize.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-OPTIMIZE" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-optimize\fR \- Optimize the database specified in the wp\-config\.php file\. +. +.SH "SYNOPSIS" +\fBwp db optimize\fR diff --git a/man/db-repair.1 b/man/db-repair.1 new file mode 100644 index 000000000..2f9089eb6 --- /dev/null +++ b/man/db-repair.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-REPAIR" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-repair\fR \- Optimize the database specified in the wp\-config\.php file\. +. +.SH "SYNOPSIS" +\fBwp db repair\fR diff --git a/src/doc/db-optimize.txt b/src/doc/db-optimize.txt new file mode 100644 index 000000000..bd640f7f6 --- /dev/null +++ b/src/doc/db-optimize.txt @@ -0,0 +1,6 @@ +wp-db-optimize(1) -- Optimize the database specified in the wp-config.php file. +==== + +## SYNOPSIS + +`wp db optimize` diff --git a/src/doc/db-repair.txt b/src/doc/db-repair.txt new file mode 100644 index 000000000..e882046c4 --- /dev/null +++ b/src/doc/db-repair.txt @@ -0,0 +1,6 @@ +wp-db-repair(1) -- Optimize the database specified in the wp-config.php file. +==== + +## SYNOPSIS + +`wp db repair` diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index ec5780fad..e27a93e36 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -45,6 +45,30 @@ function drop( $args, $assoc_args ) { WP_CLI::success( "Database dropped." ); } + /** + * Optimizes the database specified in the wp-config.php file. + */ + function optimize() { + WP_CLI::launch( sprintf( + 'mysqlcheck --optimize --host=%s --user=%s --password=%s %s', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + ) ); + + WP_CLI::success( "Database optimized." ); + } + + /** + * Repairs the database specified in the wp-config.php file. + */ + function repair() { + WP_CLI::launch( sprintf( + 'mysqlcheck --repair --host=%s --user=%s --password=%s %s', + DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + ) ); + + WP_CLI::success( "Database repaired." ); + } + /** * Print a string for connecting to the DB. */ From c0e3a240202373064944d905350a89f71ba285cd Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Thu, 12 Jul 2012 14:43:01 -0700 Subject: [PATCH 0510/5359] Correct `wp db drop` docs to properly reference `--yes` --- man/db-drop.1 | 19 +++++++++++++++++++ src/doc/db-drop.txt | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/man/db-drop.1 b/man/db-drop.1 index e69de29bb..f5c8f3b76 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-DROP" "1" "July 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-drop\fR \- Drop the database specified in wp\-config\.php +. +.SH "SYNOPSIS" +\fBwp db drop\fR [\-\-yes] +. +.SH "OPTIONS" +. +.TP +\fB\-\-yes\fR: +. +.IP +Answer yes to the confirmation message\. + diff --git a/src/doc/db-drop.txt b/src/doc/db-drop.txt index 15a1bbd8f..76f4266ca 100644 --- a/src/doc/db-drop.txt +++ b/src/doc/db-drop.txt @@ -3,7 +3,7 @@ wp-db-drop(1) -- Drop the database specified in wp-config.php ## SYNOPSIS -`wp db drop` [--really] +`wp db drop` [--yes] ## OPTIONS From fe2be3169b315fd0ffd5e65949aa29713f7329d9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 18 Jul 2012 14:17:47 +0300 Subject: [PATCH 0511/5359] make wp generate posts faster --- src/php/wp-cli/commands/internals/generate.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index c72f820df..a1cea714f 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -52,14 +52,13 @@ public function posts( $args, $assoc_args ) { $notify = new \cli\progress\Bar( 'Generating posts', $count ); - $post_ids = array(); $current_depth = 1; $current_parent = 0; for ( $i = $total; $i < $limit; $i++ ) { - if( $hierarchical ) { - + if ( $hierarchical ) { + if( $this->maybe_make_child() && $current_depth < $max_depth ) { $current_parent = $post_ids[$i-1]; @@ -73,13 +72,17 @@ public function posts( $args, $assoc_args ) { } } - $post_ids[$i] = wp_insert_post( array( + $args = array( 'post_type' => $type, 'post_title' => "$label $i", 'post_status' => $status, 'post_author' => $author, - 'post_parent' => $current_parent - ) ); + 'post_parent' => $current_parent, + 'post_name' => "post-$i" + ); + + // Not using wp_insert_post() because it's slow + $wpdb->insert( $wpdb->posts, $args ); $notify->tick(); } From 0723df10f0cdb9984cb455dd464b1e6b5d03d8ac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 21 Jul 2012 14:35:15 +0300 Subject: [PATCH 0512/5359] pipe curl directly to tar, avoiding temporary files. fixes #144 --- src/php/wp-cli/commands/internals/core.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index f7419a979..5ba7ff1b7 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -25,20 +25,18 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['locale'] ) ) { exec( 'curl -s ' . escapeshellarg( 'http://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); if ($r) exit($r); - $download_url = $lines[2]; + $download_url = str_replace( '.zip', '.tar.gz', $lines[2] ); WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $lines[3], $lines[4] ) ); } elseif ( isset( $assoc_args['version'] ) ) { - $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { - $download_url = 'http://wordpress.org/latest.zip'; + $download_url = 'http://wordpress.org/latest.tar.gz'; WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - WP_CLI::launch( 'curl -f' . (WP_CLI_SILENT ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' > /tmp/wordpress.zip' ); - WP_CLI::launch( 'unzip ' . (WP_CLI_SILENT ? '-qq ' : '-q ') . '/tmp/wordpress.zip' ); - WP_CLI::launch( 'mv wordpress/* ' . escapeshellarg( $docroot ) ); - WP_CLI::launch( 'rm -r wordpress' ); + WP_CLI::launch( 'curl -f' . (WP_CLI_SILENT ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' | tar xz' ); + WP_CLI::launch( 'mv wordpress/* . && rm -rf wordpress' ); WP_CLI::success( 'WordPress downloaded.' ); } From b4b73bcb14bd457a79590f2ef916ed2a7fd61cb2 Mon Sep 17 00:00:00 2001 From: joshstoik1 <joshstoik@gmail.com> Date: Sun, 22 Jul 2012 09:57:09 -0700 Subject: [PATCH 0513/5359] fixed missing requirement (wp-admin/includes/upgrade.php contains wp_upgrade() function), Core_Command->update_db() --- src/php/wp-cli/commands/internals/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 5ba7ff1b7..29843bb56 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -257,6 +257,7 @@ function update( $args, $assoc_args ) { * @param array $assoc_args */ function update_db() { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); wp_upgrade(); WP_CLI::success( 'WordPress database upgraded successfully.' ); } From 1d356a81fce98db53186235f45e72c608197d6d9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 23 Jul 2012 02:33:25 +0300 Subject: [PATCH 0514/5359] accept closures as command implementations. fixes #146 --- src/php/wp-cli/class-wp-cli.php | 9 ++-- .../wp-cli/commands/internals/eval-file.php | 40 +++++----------- src/php/wp-cli/commands/internals/eval.php | 30 +++--------- src/php/wp-cli/commands/internals/home.php | 48 +++++++------------ 4 files changed, 41 insertions(+), 86 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8dca01e32..db8424063 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -346,11 +346,14 @@ static function run_command( $arguments, $assoc_args ) { $command = $aliases[ $command ]; } - $class = self::load_command( $command ); - define( 'WP_CLI_COMMAND', $command ); - $instance = new $class( $arguments, $assoc_args ); + $implementation = self::load_command( $command ); + + if ( is_string( $implementation ) && class_exists( $implementation ) ) + $instance = new $implementation( $arguments, $assoc_args ); + else + call_user_func( $implementation, $arguments, $assoc_args ); } static function load_command( $command ) { diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/internals/eval-file.php index 006f5dc00..044ff7fac 100644 --- a/src/php/wp-cli/commands/internals/eval-file.php +++ b/src/php/wp-cli/commands/internals/eval-file.php @@ -1,33 +1,17 @@ <?php -WP_CLI::add_command('eval-file', 'Eval_File_Command'); - -/** - * Implement eval-file command - * - * @package wp-cli - * @subpackage commands/internals - */ -class Eval_File_Command extends WP_CLI_Command { - - /** - * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args - * @param array $assoc_args - */ - public function __construct( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp eval-file <path>" ); - exit; - } +WP_CLI::add_command( 'eval-file', function( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp eval-file <path>" ); + exit; + } - foreach ( $args as $file ) { - if ( !file_exists( $file ) ) { - WP_CLI::error( "'$file' does not exist." ); - } else { - include( $file ); - } + foreach ( $args as $file ) { + if ( !file_exists( $file ) ) { + WP_CLI::error( "'$file' does not exist." ); + } else { + include( $file ); } } -} +} ); + diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/internals/eval.php index 0915224bc..373cedfe2 100644 --- a/src/php/wp-cli/commands/internals/eval.php +++ b/src/php/wp-cli/commands/internals/eval.php @@ -1,27 +1,11 @@ <?php -WP_CLI::add_command('eval', 'Eval_Command'); - -/** - * Implement eval command - * - * @package wp-cli - * @subpackage commands/internals - */ -class Eval_Command extends WP_CLI_Command { +WP_CLI::add_command( 'eval', function( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( "usage: wp eval '<php-code>'" ); + exit; + } - /** - * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args - * @param array $assoc_args - */ - public function __construct( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp eval <php-code>" ); - exit; - } + eval( $args[0] ); +} ); - eval( $args[0] ); - } -} diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index ce8efce9f..75b006fa8 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -1,37 +1,21 @@ <?php -WP_CLI::add_command('home', 'Home_Command'); +WP_CLI::add_command( 'home', function() { + // The url for the wp-cli repository + $repository_url = 'http://github.com/wp-cli/wp-cli'; -/** - * Implement home command - * - * @package wp-cli - * @subpackage commands/internals - */ -class Home_Command extends WP_CLI_Command { - - /** - * Overwrite the constructor to have a command without sub-commands. - * - * @param array $args - * @param array $assoc_args - */ - public function __construct( $args, $assoc_args ) { - // The url for the wp-cli repository - $repository_url = 'http://github.com/wp-cli/wp-cli'; + // Open the wp-cli page in the browser + if ( exec( 'which x-www-browser' ) ) { + system( 'x-www-browser '.$repository_url ); + } + elseif ( exec( 'which open' ) ) { + system( 'open '.$repository_url ); + } + else { + WP_CLI::error( 'No command found to open the homepage in the browser. Please open it manually: '.$repository_url ); + return; + } - // Open the wp-cli page in the browser - if(exec('which x-www-browser')) { - system('x-www-browser '.$repository_url); - } - elseif(exec('which open')) { - system('open '.$repository_url); - } - else { - WP_CLI::error('No command found to open the homepage in the browser. Please open it manually: '.$repository_url); - return; - } + WP_CLI::success( 'The wp-cli homepage should be opening in your browser.' ); +} ); - WP_CLI::success('The wp-cli homepage should be opening in your browser.'); - } -} From cb300c73addfa2452b33469cc320b89f6b6954c4 Mon Sep 17 00:00:00 2001 From: Andreas Creten <andreas@madewithlove.be> Date: Fri, 3 Aug 2012 08:43:31 +0200 Subject: [PATCH 0515/5359] Support for new MAMP version --- src/bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index f4e9ec769..aaf8d1d6e 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -67,7 +67,7 @@ else fi # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php5*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + for amp_php in /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do if [ -x $amp_php ]; then php=$amp_php break From 3e44f9221bf23f3728a8ee2b672a2b2104c36a55 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 Aug 2012 16:53:59 +0300 Subject: [PATCH 0516/5359] properly escape db parameters. fixes #151 --- src/php/wp-cli/commands/internals/db.php | 33 +++++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index e27a93e36..0707f1fd3 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -18,8 +18,8 @@ class DB_Command extends WP_CLI_Command { * Creates the database specified in the wp-config.php file. */ function create() { - WP_CLI::launch( sprintf( - 'mysql --host="%s" --user="%s" --password="%s" --execute="CREATE DATABASE %s"', + WP_CLI::launch( self::create_cmd( + 'mysql --host=%s --user=%s --password=%s --execute=CREATE DATABASE %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); } @@ -37,8 +37,8 @@ function drop( $args, $assoc_args ) { return; } - WP_CLI::launch( sprintf( - 'mysql --host="%s" --user="%s" --password="%s" --execute="DROP DATABASE %s"', + WP_CLI::launch( self::create_cmd( + 'mysql --host=%s --user=%s --password=%s --execute=DROP DATABASE %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -49,7 +49,7 @@ function drop( $args, $assoc_args ) { * Optimizes the database specified in the wp-config.php file. */ function optimize() { - WP_CLI::launch( sprintf( + WP_CLI::launch( self::create_cmd( 'mysqlcheck --optimize --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -61,7 +61,7 @@ function optimize() { * Repairs the database specified in the wp-config.php file. */ function repair() { - WP_CLI::launch( sprintf( + WP_CLI::launch( self::create_cmd( 'mysqlcheck --repair --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -94,7 +94,7 @@ function query( $args, $assoc_args ) { $query = $args[0]; - $command = $this->connect_string() . sprintf( ' --execute="%s"', $query ); + $command = $this->connect_string() . self::create_cmd( ' --execute=%s', $query ); WP_CLI::launch( $command ); } @@ -105,7 +105,7 @@ function query( $args, $assoc_args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $command = sprintf( 'mysqldump "%s" --user="%s" --password="%s" --host="%s" --result-file "%s"', + $command = self::create_cmd( 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); WP_CLI::launch( $command ); @@ -119,7 +119,8 @@ function export( $args, $assoc_args ) { function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $command = sprintf( 'mysql "%s" --user="%s" --password="%s" --host="%s" < "%s"', + $command = self::create_cmd( + 'mysql %s --user=%s --password=%s --host=%s < %s', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); WP_CLI::launch( $command ); @@ -131,7 +132,7 @@ function import( $args, $assoc_args ) { * Return a string for connecting to the DB. */ private function connect_string() { - return sprintf( 'mysql --host="%s" --user="%s" --password="%s" --database="%s"', + return self::create_cmd( 'mysql --host=%s --user=%s --password=%s --database=%s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); } @@ -141,4 +142,16 @@ private function get_file_name( $args ) { return $args[0]; } + + /** + * Given a formatted string and an arbitrary number of arguments, + * returns the final command, with the parameters escaped + */ + private static function create_cmd( $cmd ) { + $args = func_get_args(); + + $cmd = array_shift( $args ); + + return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); + } } From 0de3fc551d784e4b75ed5c1f2820f642514f11a8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 21 Aug 2012 12:00:58 +0300 Subject: [PATCH 0517/5359] fix db create and db drop. see #151 --- src/php/wp-cli/commands/internals/db.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 0707f1fd3..939e86265 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -19,8 +19,8 @@ class DB_Command extends WP_CLI_Command { */ function create() { WP_CLI::launch( self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=CREATE DATABASE %s', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + 'mysql --host=%s --user=%s --password=%s --execute=%s', + DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME ) ); } @@ -38,8 +38,8 @@ function drop( $args, $assoc_args ) { } WP_CLI::launch( self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=DROP DATABASE %s', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + 'mysql --host=%s --user=%s --password=%s --execute=%s', + DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE ' . DB_NAME ) ); WP_CLI::success( "Database dropped." ); From 1fb105d1c03b540e03682209e2614d8ef8fccf4e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 21 Aug 2012 12:03:54 +0300 Subject: [PATCH 0518/5359] add success message to db create --- src/php/wp-cli/commands/internals/db.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 939e86265..23ab4e0d3 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -22,6 +22,8 @@ function create() { 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME ) ); + + WP_CLI::success( "Database created." ); } /** From 88817176740c8536ec6be3077a7f4e6be8b45e46 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 22 Aug 2012 00:34:11 +0300 Subject: [PATCH 0519/5359] fix user create --- src/php/wp-cli/commands/internals/user.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index e5539639b..c6fd1350f 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -82,12 +82,12 @@ public function delete( $args, $assoc_args ) { public function create( $args, $assoc_args ) { global $blog_id; - list( $user_login, $user_email ) = $args[0]; - - if ( ! $user_login || ! $user_email ) { + if ( count( $args ) < 2 ) { WP_CLI::error( "Login and email required." ); } + list( $user_login, $user_email ) = $args; + $defaults = array( 'role' => get_option('default_role'), 'user_pass' => wp_generate_password(), From 0fde04b43ac18ed6ce75164ec2eb8f6ea28bb155 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 22 Aug 2012 15:58:56 +0300 Subject: [PATCH 0520/5359] make db drop work without having wp installed --- src/php/wp-cli/wp-cli.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 5da128c23..3926bfae8 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -77,6 +77,12 @@ exit; } +if ( array( 'db', 'drop' ) == $arguments ) { + WP_CLI::load_wp_config(); + WP_CLI::run_command( $arguments, $assoc_args ); + exit; +} + if ( array( 'db', 'import' ) == array_slice( $arguments, 0, 2 ) ) { WP_CLI::load_wp_config(); WP_CLI::run_command( $arguments, $assoc_args ); From 9b1b39a977da8eb4d8e90a4eba856ab1fea19f0e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 23 Aug 2012 14:30:50 +0300 Subject: [PATCH 0521/5359] add --quiet to the help text --- src/php/wp-cli/class-wp-cli.php | 8 ++++---- src/php/wp-cli/commands/internals/core.php | 6 +++--- src/php/wp-cli/commands/internals/help.php | 1 + src/php/wp-cli/wp-cli.php | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index db8424063..7a1b2d4e4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -25,7 +25,7 @@ public function add_command( $name, $class ) { * @param string $message */ static function out( $message ) { - if ( WP_CLI_SILENT ) return; + if ( WP_CLI_QUIET ) return; \cli\out($message); } @@ -35,7 +35,7 @@ static function out( $message ) { * @param string $message */ static function line( $message = '' ) { - if ( WP_CLI_SILENT ) return; + if ( WP_CLI_QUIET ) return; \cli\line($message); } @@ -60,7 +60,7 @@ static function error( $message, $label = 'Error' ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - if ( WP_CLI_SILENT ) return; + if ( WP_CLI_QUIET ) return; \cli\line( '%G' . $label . ': %n' . $message ); } @@ -71,7 +71,7 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - if ( WP_CLI_SILENT ) return; + if ( WP_CLI_QUIET ) return; \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 29843bb56..41ad7a18a 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -35,7 +35,7 @@ public function download( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - WP_CLI::launch( 'curl -f' . (WP_CLI_SILENT ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' | tar xz' ); + WP_CLI::launch( 'curl -f' . (WP_CLI_QUIET ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' | tar xz' ); WP_CLI::launch( 'mv wordpress/* . && rm -rf wordpress' ); WP_CLI::success( 'WordPress downloaded.' ); @@ -55,9 +55,9 @@ public function config( $args, $assoc_args ) { $_GET['step'] = 2; - if ( WP_CLI_SILENT ) ob_start(); + if ( WP_CLI_QUIET ) ob_start(); require WP_ROOT . '/wp-admin/setup-config.php'; - if ( WP_CLI_SILENT ) ob_end_clean(); + if ( WP_CLI_QUIET ) ob_end_clean(); } /** diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 8ca0538e2..8ff24eb3e 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -66,6 +66,7 @@ private function general_help() { --url=<url> set the current URL --path=<path> set the current path to the WP install --require=<path> load a certain file before running the command + --quiet suppress informational messages --version print wp-cli version EOB ); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3926bfae8..3002a4435 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -30,7 +30,7 @@ // Set output levels define( 'WP_CLI_AUTOCOMPLETE', isset( $assoc_args['completions'] ) ); -define( 'WP_CLI_SILENT', isset( $assoc_args['silent'] ) ); +define( 'WP_CLI_QUIET', isset( $assoc_args['quiet'] ) || isset( $assoc_args['silent'] ) ); // Handle --version parameter if ( isset( $assoc_args['version'] ) && empty( $arguments ) ) { From 6775cd7d12de4a7c213a183ed6264e6f24996fb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 23 Aug 2012 23:26:52 +0300 Subject: [PATCH 0522/5359] introduce db reset --- man/db-reset.1 | 19 +++++++++++++++++ src/doc/db-reset.txt | 12 +++++++++++ src/php/wp-cli/commands/internals/db.php | 26 ++++++++++++++++++++++++ src/php/wp-cli/wp-cli.php | 15 ++------------ 4 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 man/db-reset.1 create mode 100644 src/doc/db-reset.txt diff --git a/man/db-reset.1 b/man/db-reset.1 new file mode 100644 index 000000000..4f40b8300 --- /dev/null +++ b/man/db-reset.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB\-RESET" "1" "August 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\-reset\fR \- Remove all data from the database specified in wp\-config\.php +. +.SH "SYNOPSIS" +\fBwp db reset\fR [\-\-yes] +. +.SH "OPTIONS" +. +.TP +\fB\-\-yes\fR: +. +.IP +Answer yes to the confirmation message\. + diff --git a/src/doc/db-reset.txt b/src/doc/db-reset.txt new file mode 100644 index 000000000..8ba5a5ed5 --- /dev/null +++ b/src/doc/db-reset.txt @@ -0,0 +1,12 @@ +wp-db-reset(1) -- Remove all data from the database specified in wp-config.php +==== + +## SYNOPSIS + +`wp db reset` [--yes] + +## OPTIONS + +* `--yes`: + + Answer yes to the confirmation message. diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 23ab4e0d3..f382651d3 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -47,6 +47,32 @@ function drop( $args, $assoc_args ) { WP_CLI::success( "Database dropped." ); } + /** + * Removes all tables from the database. + */ + function reset( $args, $assoc_args ) { + if ( !isset( $assoc_args['yes'] ) ) { + WP_CLI::out( "Are you sure you want to reset the database? [y/n] " ); + + $answer = trim( fgets( STDIN ) ); + + if ( 'y' != $answer ) + return; + } + + WP_CLI::launch( self::create_cmd( + 'mysql --host=%s --user=%s --password=%s --execute=%s', + DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE IF EXISTS ' . DB_NAME + ) ); + + WP_CLI::launch( self::create_cmd( + 'mysql --host=%s --user=%s --password=%s --execute=%s', + DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME + ) ); + + WP_CLI::success( "Database reset." ); + } + /** * Optimizes the database specified in the wp-config.php file. */ diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3002a4435..834e3b698 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -71,19 +71,8 @@ exit; } -if ( array( 'db', 'create' ) == $arguments ) { - WP_CLI::load_wp_config(); - WP_CLI::run_command( $arguments, $assoc_args ); - exit; -} - -if ( array( 'db', 'drop' ) == $arguments ) { - WP_CLI::load_wp_config(); - WP_CLI::run_command( $arguments, $assoc_args ); - exit; -} - -if ( array( 'db', 'import' ) == array_slice( $arguments, 0, 2 ) ) { +// The db commands don't need any WP files +if ( array( 'db' ) == array_slice( $arguments, 0, 1 ) ) { WP_CLI::load_wp_config(); WP_CLI::run_command( $arguments, $assoc_args ); exit; From a3fc9ea98c47f05d32471e034180eb72eb024bd2 Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 13:52:14 +0200 Subject: [PATCH 0523/5359] fix notice wording for total-cache flush --- src/php/wp-cli/commands/community/total-cache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index bc623bc4e..df18a647a 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -29,17 +29,17 @@ function flush( $args = array(), $vars = array() ) { case 'db': case 'database': if ( w3tc_dbcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); + WP_CLI::success( 'The database cache is flushed successfully.' ); } else { - WP_CLI::error( 'Flushing the object cache failed.' ); + WP_CLI::error( 'Flushing the database cache failed.' ); } break; case 'minify': if ( w3tc_minify_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); + WP_CLI::success( 'The minify cache is flushed successfully.' ); } else { - WP_CLI::error( 'Flushing the object cache failed.' ); + WP_CLI::error( 'Flushing the minify cache failed.' ); } break; From 9e9a81eee2dff3df20f6d962868857115936822b Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 13:54:24 +0200 Subject: [PATCH 0524/5359] add seperate handle for flushing whole page cache --- src/php/wp-cli/commands/community/total-cache.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index df18a647a..ed3d1af0e 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -51,6 +51,14 @@ function flush( $args = array(), $vars = array() ) { } break; + case 'page': + if ( w3tc_pgcache_flush() ) { + WP_CLI::success( 'The page cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the page cache failed.' ); + } + break; + case 'post': default: if ( isset($vars['post_id']) ) { @@ -70,12 +78,6 @@ function flush( $args = array(), $vars = array() ) { } else { WP_CLI::error('There is no post with this permalink.'); } - } else { - if ( isset( $flushed_page_cache ) && $flushed_page_cache ) - break; - - $flushed_page_cache = true; - w3tc_pgcache_flush(); } } } while ( !empty( $args ) ); From f8fe0813be807a934adbc4a1cf2f58c391f60c8f Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 14:06:07 +0200 Subject: [PATCH 0525/5359] add notices for post / permalink flushes --- src/php/wp-cli/commands/community/total-cache.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index ed3d1af0e..982bd80c2 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -63,18 +63,24 @@ function flush( $args = array(), $vars = array() ) { default: if ( isset($vars['post_id']) ) { if ( is_numeric( $vars['post_id'] ) ) { - w3tc_pgcache_flush_post( $vars['post_id'] ); + if ( w3tc_pgcache_flush_post( $vars['post_id'] ) ) { + WP_CLI::success( 'Post '.$vars['post_id'].' is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing '.$vars['post_id'].' from cache failed.' ); + } } else { WP_CLI::error('This is not a valid post id.'); } - - w3tc_pgcache_flush_post( $vars['post_id'] ); } elseif ( isset( $vars['permalink'] ) ) { $id = url_to_postid( $vars['permalink'] ); if ( is_numeric( $id ) ) { - w3tc_pgcache_flush_post( $id ); + if ( w3tc_pgcache_flush_post( $id ) ) { + WP_CLI::success( $id.' is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing '.$id.' from cache failed.' ); + } } else { WP_CLI::error('There is no post with this permalink.'); } From c1fbd93add53cbacd5af1e61f0f487476c0a849f Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 14:12:43 +0200 Subject: [PATCH 0526/5359] fail better on trying to flush a non-existent permalink --- src/php/wp-cli/commands/community/total-cache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index 982bd80c2..ca0259ee0 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -75,9 +75,9 @@ function flush( $args = array(), $vars = array() ) { elseif ( isset( $vars['permalink'] ) ) { $id = url_to_postid( $vars['permalink'] ); - if ( is_numeric( $id ) ) { + if ( is_numeric( $id ) && $id > 0 ) { if ( w3tc_pgcache_flush_post( $id ) ) { - WP_CLI::success( $id.' is flushed successfully.' ); + WP_CLI::success( $id.' is flushed successfully.' ); } else { WP_CLI::error( 'Flushing '.$id.' from cache failed.' ); } From afdfb50bc97e0c4d39f189fd2b2cc8ea15b041b6 Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 14:15:35 +0200 Subject: [PATCH 0527/5359] check if post id actually exists before flushing it from cache --- src/php/wp-cli/commands/community/total-cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index ca0259ee0..d63ae75b5 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -62,7 +62,7 @@ function flush( $args = array(), $vars = array() ) { case 'post': default: if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) ) { + if ( is_numeric( $vars['post_id'] ) && get_post( $vars['post_id'] ) ) { if ( w3tc_pgcache_flush_post( $vars['post_id'] ) ) { WP_CLI::success( 'Post '.$vars['post_id'].' is flushed successfully.' ); } else { From 1e8c2c102c5529b7dad98145cbbb1d214b0b194b Mon Sep 17 00:00:00 2001 From: Roel van der Ven <roel@soundcloud.com> Date: Sat, 25 Aug 2012 14:54:36 +0200 Subject: [PATCH 0528/5359] add page handle to command explanation --- src/php/wp-cli/commands/community/total-cache.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index d63ae75b5..8e1a35a4c 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -97,15 +97,16 @@ function flush( $args = array(), $vars = array() ) { */ public static function help() { WP_CLI::line( <<<EOB -usage: wp total-cache flush [post|database|minify|object] [--post_id=<post-id>] [--permalink=<post-permalink>] +usage: wp total-cache flush [post|database|minify|object|page] [--post_id=<post-id>] [--permalink=<post-permalink>] Available sub-commands: - flush flushes whole cache + flush --post_id=<id> flush specific ID --permalink=<post-permalink> flush specific permalink database flushes database cache object flush object cache minify flush minify cache + page flush page cache EOB ); } From 124f233436633058bb657fc9486e7dd4f0f44b0a Mon Sep 17 00:00:00 2001 From: Marco Ceppi <marco@ceppi.net> Date: Mon, 27 Aug 2012 16:06:08 -0400 Subject: [PATCH 0529/5359] Added HTTPS to all URLS which access WP for information. --- src/php/wp-cli/commands/internals/core.php | 8 ++++---- src/php/wp-cli/commands/internals/home.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 41ad7a18a..2da3efe8a 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -23,15 +23,15 @@ public function download( $args, $assoc_args ) { $docroot = './'; if ( isset( $assoc_args['locale'] ) ) { - exec( 'curl -s ' . escapeshellarg( 'http://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); + exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); if ($r) exit($r); $download_url = str_replace( '.zip', '.tar.gz', $lines[2] ); WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $lines[3], $lines[4] ) ); } elseif ( isset( $assoc_args['version'] ) ) { - $download_url = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; + $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { - $download_url = 'http://wordpress.org/latest.tar.gz'; + $download_url = 'https://wordpress.org/latest.tar.gz'; WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } @@ -210,7 +210,7 @@ function update( $args, $assoc_args ) { $new_package = null; if ( empty( $args[0] ) ) { - $new_package = 'http://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + $new_package = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $new_package = $args[0]; diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index 75b006fa8..c2efd8623 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -2,7 +2,7 @@ WP_CLI::add_command( 'home', function() { // The url for the wp-cli repository - $repository_url = 'http://github.com/wp-cli/wp-cli'; + $repository_url = 'https://github.com/wp-cli/wp-cli'; // Open the wp-cli page in the browser if ( exec( 'which x-www-browser' ) ) { From 445c4360a19fc8401d238f5f738557dcb42563cb Mon Sep 17 00:00:00 2001 From: tollmanz <tollmanz@gmail.com> Date: Mon, 3 Sep 2012 22:11:04 -0700 Subject: [PATCH 0530/5359] Added commands for the WordPress object cache. This commit adds commands for interacting with the WordPress object cache. For each public function in for the WordPress object cache, a corresponding command has been created. Additionally, a "which" command has been written that attempts to determine which 3rd party object cache the current installation is implementing. --- src/php/wp-cli/commands/internals/cache.php | 361 ++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/cache.php diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php new file mode 100644 index 000000000..8a7141b13 --- /dev/null +++ b/src/php/wp-cli/commands/internals/cache.php @@ -0,0 +1,361 @@ +<?php + +WP_CLI::add_command( 'cache', 'Cache_Command' ); + +/** + * Implement cache command + * + * @package wp-cli + * @subpackage commands/internals + */ +class Cache_Command extends WP_CLI_Command { + + /** + * Add a value to the object cache. + * + * @uses wp_cache_add + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function add( $args, $assoc_args ) { + if ( count( $assoc_args ) + count( $args ) < 2 ) { + WP_CLI::line( 'usage: wp cache add <key> <value> [group] [expiration]' ); + exit; + } + + list( $key, $value ) = $args; + + $group = ( isset( $args[2] ) ) ? $args[2] : ''; + + $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + + if ( ! wp_cache_add( $key, $value, $group, $expiration ) ) { + WP_CLI::error( "Could not add object '$key' in group '$group'. Does it already exist?" ); + exit; + } + + WP_CLI::success( "Added object '$key' in group '$group'." ); + } + + /** + * Add global cache groups. + * + * @uses wp_cache_add_global_groups + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function add_global_groups( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache add_global_groups <group>' ); + exit; + } + + $group = $args[0]; + + wp_cache_add_global_groups( $group ); + } + + /** + * Adds a non-persistent group to the list. + * + * @uses wp_cache_add_non_persistent_groups + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function add_non_persistent_groups( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache add_non_persistent_groups <group>' ); + exit; + } + + $group = $args[0]; + + wp_cache_add_non_persistent_groups( $group ); + } + + /** + * Decrement a value in the object cache. + * + * @uses wp_cache_decr + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function decr( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache decr <key> [offset] [group]' ); + exit; + } + + $key = $args[0]; + + $offset = ( isset( $args[1] ) ) ? $args[1] : 1; + + $group = ( isset( $args[2] ) ) ? $args[2] : ''; + + $value = wp_cache_decr( $key, $offset, $group ); + + if ( false === $value ) { + WP_CLI::error( 'The value was not decremented.' ); + exit; + } + + WP_CLI::print_value( $value, $assoc_args ); + } + + /** + * Remove a value from the object cache. + * + * @uses wp_cache_delete + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function delete( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache delete <key> [group]' ); + exit; + } + + $key = $args[0]; + + $group = ( isset( $args[1] ) ) ? $args[1] : ''; + + $result = wp_cache_delete( $key, $group ); + + if ( false === $result ) { + WP_CLI::error( 'The object was not deleted.' ); + exit; + } + + WP_CLI::success( 'Object deleted.' ); + } + + /** + * Flush the object cache. + * + * @uses wp_cache_flush + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function flush( $args, $assoc_args ) { + $value = wp_cache_flush(); + + if ( false === $value ) { + WP_CLI::error( 'The object cache could not be flushed.' ); + exit; + } + + WP_CLI::success( 'The cache was flushed.' ); + } + + /** + * Get a value from the object cache. + * + * @uses wp_cache_get + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function get( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache get <key> [group]' ); + exit; + } + + $key = $args[0]; + + $group = ( isset( $args[1] ) ) ? $args[1] : ''; + + $value = wp_cache_get( $key, $group ); + + if ( false === $value ) { + WP_CLI::error( "Object with key '$key' and group '$group' not found." ); + exit; + } + + WP_CLI::print_value( $value, $assoc_args ); + } + + /** + * Increment a value in the object cache. + * + * @uses wp_cache_incr + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function incr( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache incr <key> [offset] [group]' ); + exit; + } + + $key = $args[0]; + + $offset = ( isset( $args[1] ) ) ? $args[1] : 1; + + $group = ( isset( $args[2] ) ) ? $args[2] : ''; + + $value = wp_cache_incr( $key, $offset, $group ); + + if ( false === $value ) { + WP_CLI::error( 'The value was not incremented.' ); + exit; + } + + WP_CLI::print_value( $value, $assoc_args ); + } + + /** + * Replace an existing value in the object cache. + * + * @uses wp_cache_replace + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function replace( $args, $assoc_args ) { + if ( count( $assoc_args ) + count( $args ) < 2 ) { + WP_CLI::line( 'usage: wp cache replace <key> <value> [group] [expiration]' ); + exit; + } + + list( $key, $value ) = $args; + + $group = ( isset( $args[2] ) ) ? $args[2] : ''; + + $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + + $result = wp_cache_replace( $key, $value, $group, $expiration ); + + if ( false === $result ) { + WP_CLI::error( "Could not replace object '$key' in group '$group'. Does it already exist?" ); + exit; + } + + WP_CLI::success( "Replaced object '$key' in group '$group'." ); + } + + /** + * Set a value to the object cache. + * + * @uses wp_cache_set + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function set( $args, $assoc_args ) { + if ( count( $assoc_args ) + count( $args ) < 2 ) { + WP_CLI::line( 'usage: wp cache set <key> <value> [group] [expiration]' ); + exit; + } + + list( $key, $value ) = $args; + + $group = ( isset( $args[2] ) ) ? $args[2] : ''; + + $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + + $result = wp_cache_set( $key, $value, $group, $expiration ); + + if ( false === $result ) { + WP_CLI::error( "Could not add object '$key' in group '$group'." ); + exit; + } + + WP_CLI::success( "Set object '$key' in group '$group'." ); + } + + /** + * Switch the blog id, which switches the cache keys for all values. + * + * @uses wp_cache_switch_to_blog + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function switch_to_blog( $args, $assoc_args ) { + if ( empty( $args ) ) { + WP_CLI::line( 'usage: wp cache switch_to_blog <blog_id>' ); + exit; + } + + if ( ! function_exists( 'wp_cache_switch_to_blog' ) ) { + WP_CLI::warning( "Command cannot be executed because the 'wp_cache_switch_to_blog' function does not exist." ); + } + + $blog_id = $args[0]; + + wp_cache_switch_to_blog( $blog_id ); + } + + /** + * Attempts to determine which object cache is being used. + * + * Note that the guesses made by this function are based on the WP_Object_Cache classes + * that define the 3rd party object cache extension. Changes to those classes could render + * problems with this function's ability to determine which object cache is being used. + * + * @uses $_wp_using_ext_object_cache + * @uses $wp_object_cache + * + * @param array $args Function arguments. + * @param array $assoc_args Function arguments with parameter key. + * @return void + */ + public function which( $args, $assoc_args ) { + global $_wp_using_ext_object_cache, $wp_object_cache; + + $message = 'Using an unknown object cache'; + + if ( false !== $_wp_using_ext_object_cache ) { + // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) + if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) + $message = 'Using memcached with the memcached PECL extension'; + + // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) + if ( isset( $wp_object_cache->mc ) ) { + $is_memcache = true; + foreach ( $wp_object_cache->mc as $bucket ) { + if ( ! is_a( $bucket, 'Memcache' ) ) + $is_memcache = false; + } + + if ( $is_memcache ) + $message = 'Using memcached with the memcache PECL extension'; + } + + // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) + if ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) + $message = 'Using the xcache object cache'; + + // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) + if ( class_exists( 'WinCache_Object_Cache' ) ) + $message = 'Using the wincache object cache'; + + // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) + if ( class_exists( 'APC_Object_Cache' ) ) + $message = 'Using the APC object cache'; + } else { + $message = 'Using the default object cache'; + } + + WP_CLI::print_value( $message ); + } +} \ No newline at end of file From aa4d749da1508690731db1a178f6d313d1170895 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Sep 2012 23:19:07 +0300 Subject: [PATCH 0531/5359] abort at first error --- utils/pear-build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/pear-build b/utils/pear-build index 2172050ec..1a25b8df1 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -1,5 +1,7 @@ #!/bin/bash +set -ex + # generate package find -name '*~' -delete phing pear-package From f0d60294338a5a49cbccb05c9a310f8d5f05a626 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 01:48:12 +0300 Subject: [PATCH 0532/5359] add version 0.6.0 changelog --- README.md | 20 ++++++++++++++++++++ src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 92835f7e7..4806bac2e 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,26 @@ You can find more information about adding commands in the [Commands Cookbook](h Changelog --------------- +**0.6** + +- added `wp post` and `wp post-meta` +- added `wp user-meta` +- added `wp blog create` +- added `wp export` +- added `wp transient` +- added `wp db optimize` and `wp db repair` +- added `wp db create`, `wp db drop` and `wp db reset` +- added `wp db import` +- added `wp theme install` and `wp theme update` +- added `wp core install_network` +- added `--json` option to several subcommands +- added `--network` option to `wp plugin activate` +- added `--require` global parameter +- fixed `wp plugin update` +- fixed "out of memory" error +- misc bugfixes and optimizations +- man pages (not in PEAR package) + **0.5** - added `wp user` diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 834e3b698..7ad523325 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -5,7 +5,7 @@ die(-1); } -define( 'WP_CLI_VERSION', '0.6.0-dev' ); +define( 'WP_CLI_VERSION', '0.6.0' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 8578919ed7dc534109fd5cf02c22f3e369b9b523 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 01:50:28 +0300 Subject: [PATCH 0533/5359] mention wp core update_db --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4806bac2e..2e0590d15 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ Changelog - added `wp db import` - added `wp theme install` and `wp theme update` - added `wp core install_network` +- added `wp core update_db` - added `--json` option to several subcommands - added `--network` option to `wp plugin activate` - added `--require` global parameter From c84163073322e442fb7d2da2b7b71fd7b43fd57d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 02:30:11 +0300 Subject: [PATCH 0534/5359] pear-build: create missing directories --- utils/pear-build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/pear-build b/utils/pear-build index 1a25b8df1..1d9fadeda 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -2,6 +2,12 @@ set -ex +# create bunch of directories that phing complains about +mkdir -p src/data +mkdir -p src/tests/unit-tests/php +mkdir -p src/www +mkdir -p src/docs + # generate package find -name '*~' -delete phing pear-package From bbb4c81be2e19718948ee93a7f2db453993f31c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 02:30:25 +0300 Subject: [PATCH 0535/5359] update stable version and license --- build.properties | 2 +- package.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.properties b/build.properties index 2a40f3cd4..2bc7131b0 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=wp-cli.github.com/pear project.majorVersion=0 -project.minorVersion=5 +project.minorVersion=6 project.patchLevel=0 project.snapshot=false diff --git a/package.xml b/package.xml index aa11e65f2..852e8c4b1 100644 --- a/package.xml +++ b/package.xml @@ -31,7 +31,7 @@ <release>${project.stability}</release> <api>stable</api> </stability> - <license>GPL 2+</license> + <license>MIT</license> <notes> No notes. </notes> From c85b1b64f18953459147770b5281496fd9b7ca0d Mon Sep 17 00:00:00 2001 From: tollmanz <tollmanz@gmail.com> Date: Tue, 4 Sep 2012 20:57:10 -0700 Subject: [PATCH 0536/5359] Changed "which" command to "type" and simplified output --- src/php/wp-cli/commands/internals/cache.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index 8a7141b13..57a225b0b 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -319,15 +319,15 @@ public function switch_to_blog( $args, $assoc_args ) { * @param array $assoc_args Function arguments with parameter key. * @return void */ - public function which( $args, $assoc_args ) { + public function type( $args, $assoc_args ) { global $_wp_using_ext_object_cache, $wp_object_cache; - $message = 'Using an unknown object cache'; + $message = 'Unknown'; if ( false !== $_wp_using_ext_object_cache ) { // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) - $message = 'Using memcached with the memcached PECL extension'; + $message = 'Memcached (Memcached PECL extension)'; // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) if ( isset( $wp_object_cache->mc ) ) { @@ -338,22 +338,22 @@ public function which( $args, $assoc_args ) { } if ( $is_memcache ) - $message = 'Using memcached with the memcache PECL extension'; + $message = 'Memcached (Memcache PECL extension)'; } // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) if ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) - $message = 'Using the xcache object cache'; + $message = 'Xcache'; // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) if ( class_exists( 'WinCache_Object_Cache' ) ) - $message = 'Using the wincache object cache'; + $message = 'WinCache'; // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) if ( class_exists( 'APC_Object_Cache' ) ) - $message = 'Using the APC object cache'; + $message = 'APC'; } else { - $message = 'Using the default object cache'; + $message = 'Default object cache'; } WP_CLI::print_value( $message ); From a5d88bcb98a28537c3c3a952d372759aaa32eac1 Mon Sep 17 00:00:00 2001 From: tollmanz <tollmanz@gmail.com> Date: Tue, 4 Sep 2012 21:50:49 -0700 Subject: [PATCH 0537/5359] Added man page for cache command --- man/cache.1 | 123 ++++++++++++++++++++++++++++++++++++++++++++++ src/doc/cache.txt | 84 +++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 man/cache.1 create mode 100644 src/doc/cache.txt diff --git a/man/cache.1 b/man/cache.1 new file mode 100644 index 000000000..6024971c0 --- /dev/null +++ b/man/cache.1 @@ -0,0 +1,123 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\fR \- Manage WordPress the object cache\. +. +.SH "SYNOPSIS" +wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] +. +.P +wp cache add_global_groups \fIgroup\fR +. +.P +wp cache add_non_persistent_groups \fIgroup\fR +. +.P +wp cache decr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] +. +.P +wp cache delete \fIkey\fR \fIgroup\fR +. +.P +wp cache flush +. +.P +wp cache get \fIkey\fR [\fIgroup\fR] +. +.P +wp cache incr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] +. +.P +wp cache replace \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] +. +.P +wp cache set \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] +. +.P +wp cache switch_to_blog \fIblog_id\fR +. +.P +wp cache type +. +.SH "SUBCOMMANDS" +. +.TP +\fBadd\fR: +. +.IP +Add a value to cache where \fIkey\fR in \fIgroup\fR does not already exist\. +. +.TP +\fBadd_global_groups\fR: +. +.IP +Add a value to the global groups array\. +. +.TP +\fBadd_non_persistent_groups\fR: +. +.IP +Add a value to the non persistent groups array\. +. +.TP +\fBdecr\fR: +. +.IP +Decrement the value of a cached object by 1 or the value of the \fIoffset\fR parameter\. +. +.TP +\fBdelete\fR: +. +.IP +Remove an object from cache\. +. +.TP +\fBflush\fR: +. +.IP +Flush the cache\. +. +.TP +\fBget\fR: +. +.IP +Get a value from cache\. +. +.TP +\fBincr\fR: +. +.IP +Increment the value of a cached object by 1 or the value of the \fIoffset\fR parameter\. +. +.TP +\fBreplace\fR: +. +.IP +Replace a value in cache with a new value\. +. +.TP +\fBset\fR: +. +.IP +Set a value in cache\. +. +.TP +\fBswitch_to_blog\fR: +. +.IP +Interact with the cache for the specified \fIblog_id\fR\. +. +.TP +\fBtype\fR: +. +.IP +Report the type of object being used\. +. +.SH "EXAMPLES" +wp cache set my_key my_value my_group 300 +. +.P +wp cache get my_key my_group diff --git a/src/doc/cache.txt b/src/doc/cache.txt new file mode 100644 index 000000000..e28de79f6 --- /dev/null +++ b/src/doc/cache.txt @@ -0,0 +1,84 @@ +wp-cache(1) -- Manage WordPress the object cache. +==== + +## SYNOPSIS + +wp cache add <key> <value> [<group>] [<expiration>] + +wp cache add_global_groups <group> + +wp cache add_non_persistent_groups <group> + +wp cache decr <key> [<offset>] [<group>] + +wp cache delete <key> <group> + +wp cache flush + +wp cache get <key> [<group>] + +wp cache incr <key> [<offset>] [<group>] + +wp cache replace <key> <value> [<group>] [<expiration>] + +wp cache set <key> <value> [<group>] [<expiration>] + +wp cache switch_to_blog <blog_id> + +wp cache type + +## SUBCOMMANDS + +* `add`: + + Add a value to cache where <key> in <group> does not already exist. + +* `add_global_groups`: + + Add a value to the global groups array. + +* `add_non_persistent_groups`: + + Add a value to the non persistent groups array. + +* `decr`: + + Decrement the value of a cached object by 1 or the value of the <offset> parameter. + +* `delete`: + + Remove an object from cache. + +* `flush`: + + Flush the cache. + +* `get`: + + Get a value from cache. + +* `incr`: + + Increment the value of a cached object by 1 or the value of the <offset> parameter. + +* `replace`: + + Replace a value in cache with a new value. + +* `set`: + + Set a value in cache. + +* `switch_to_blog`: + + Interact with the cache for the specified <blog_id>. + +* `type`: + + Report the type of object being used. + +## EXAMPLES + +wp cache set my_key my_value my_group 300 + +wp cache get my_key my_group From 346213612013e618a5a54ee3c01511654ed71529 Mon Sep 17 00:00:00 2001 From: tollmanz <tollmanz@gmail.com> Date: Wed, 5 Sep 2012 20:31:48 -0700 Subject: [PATCH 0538/5359] Updated output and if/else struture in the type subcommand --- src/php/wp-cli/commands/internals/cache.php | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index 57a225b0b..546439036 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -322,15 +322,13 @@ public function switch_to_blog( $args, $assoc_args ) { public function type( $args, $assoc_args ) { global $_wp_using_ext_object_cache, $wp_object_cache; - $message = 'Unknown'; - if ( false !== $_wp_using_ext_object_cache ) { // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) - if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) - $message = 'Memcached (Memcached PECL extension)'; + if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) { + $message = 'Memcached'; // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) - if ( isset( $wp_object_cache->mc ) ) { + } elseif ( isset( $wp_object_cache->mc ) ) { $is_memcache = true; foreach ( $wp_object_cache->mc as $bucket ) { if ( ! is_a( $bucket, 'Memcache' ) ) @@ -338,22 +336,24 @@ public function type( $args, $assoc_args ) { } if ( $is_memcache ) - $message = 'Memcached (Memcache PECL extension)'; - } + $message = 'Memcache'; // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) - if ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) + } elseif ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) { $message = 'Xcache'; // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) - if ( class_exists( 'WinCache_Object_Cache' ) ) + } elseif ( class_exists( 'WinCache_Object_Cache' ) ) { $message = 'WinCache'; // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) - if ( class_exists( 'APC_Object_Cache' ) ) + } elseif ( class_exists( 'APC_Object_Cache' ) ) { $message = 'APC'; + } else { + $message = 'Unknown'; + } } else { - $message = 'Default object cache'; + $message = 'Default'; } WP_CLI::print_value( $message ); From c916695ee9c8c94ea31ee9ef1381837630778b31 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 02:33:44 +0300 Subject: [PATCH 0539/5359] need sudo for pear config-set too --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e0590d15..4b99c1d1c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Installing **Via PEAR:** ```sh -pear config-set auto_discover 1 +sudo pear config-set auto_discover 1 sudo pear install wp-cli.github.com/pear/wpcli ``` From 793b470327543481e4e230f6aaa6fc64bba597b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Sep 2012 02:49:45 +0300 Subject: [PATCH 0540/5359] make pear package work --- src/bin/wp | 2 +- utils/pear-build | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index aaf8d1d6e..1856f53e0 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -28,7 +28,7 @@ cd "$ORIGDIR" # Build the path to the root PHP file SCRIPT_PATH='@@PHP_DIR@@' -if [ ! -f $SCRIPT_PATH ]; then +if [ ! -d $SCRIPT_PATH ]; then SCRIPT_PATH=$(dirname "$SELF_PATH")/../php fi diff --git a/utils/pear-build b/utils/pear-build index 1d9fadeda..07530db9a 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -8,10 +8,20 @@ mkdir -p src/tests/unit-tests/php mkdir -p src/www mkdir -p src/docs +# temporarily move the .git dir, because phing is stupid +git_dir=src/php/php-cli-tools/.git +if [ -d $git_dir ]; then + mv $git_dir /tmp/php-cli-tools-git +fi + # generate package find -name '*~' -delete phing pear-package +if [ ! -d $git_dir ]; then + mv /tmp/php-cli-tools-git $git_dir +fi + version=$(cat dist/lastBuilt) version="${version/*wpcli-/}" version="${version/.tgz/}" From 7d4ff9198bf1935d83551c8896c84596d7823c98 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Sep 2012 14:28:51 +0300 Subject: [PATCH 0541/5359] mv src/doc src/docs --- man/blog-create.1 | 2 +- man/core-config.1 | 2 +- man/core-download.1 | 2 +- man/core-install.1 | 2 +- man/core-install_network.1 | 2 +- man/core-update.1 | 2 +- man/core-update_db.1 | 2 +- man/core-version.1 | 2 +- man/db-cli.1 | 2 +- man/db-connect.1 | 2 +- man/db-create.1 | 2 +- man/db-drop.1 | 2 +- man/db-export.1 | 2 +- man/db-import.1 | 2 +- man/db-optimize.1 | 2 +- man/db-query.1 | 2 +- man/db-repair.1 | 2 +- man/db-reset.1 | 2 +- man/eval-file.1 | 2 +- man/eval.1 | 2 +- man/export.1 | 2 +- man/generate-posts.1 | 2 +- man/generate-users.1 | 2 +- man/home.1 | 2 +- man/option.1 | 2 +- man/plugin-activate.1 | 2 +- man/plugin-deactivate.1 | 2 +- man/plugin-delete.1 | 2 +- man/plugin-install.1 | 2 +- man/plugin-path.1 | 2 +- man/plugin-status.1 | 2 +- man/plugin-toggle.1 | 2 +- man/plugin-uninstall.1 | 2 +- man/plugin-update.1 | 2 +- man/post-create.1 | 2 +- man/post-delete.1 | 2 +- man/post-meta.1 | 2 +- man/post-update.1 | 2 +- man/theme-activate.1 | 2 +- man/theme-delete.1 | 2 +- man/theme-install.1 | 2 +- man/theme-path.1 | 2 +- man/theme-status.1 | 2 +- man/theme-update.1 | 2 +- man/transient.1 | 2 +- man/user-create.1 | 2 +- man/user-delete.1 | 2 +- man/user-list.1 | 2 +- man/user-meta.1 | 2 +- man/user-update.1 | 2 +- src/{doc => docs}/blog-create.txt | 0 src/{doc => docs}/cache.txt | 0 src/{doc => docs}/core-config.txt | 0 src/{doc => docs}/core-download.txt | 0 src/{doc => docs}/core-install.txt | 0 src/{doc => docs}/core-install_network.txt | 0 src/{doc => docs}/core-update.txt | 0 src/{doc => docs}/core-update_db.txt | 0 src/{doc => docs}/core-version.txt | 0 src/{doc => docs}/db-cli.txt | 0 src/{doc => docs}/db-connect.txt | 0 src/{doc => docs}/db-create.txt | 0 src/{doc => docs}/db-drop.txt | 0 src/{doc => docs}/db-export.txt | 0 src/{doc => docs}/db-import.txt | 0 src/{doc => docs}/db-optimize.txt | 0 src/{doc => docs}/db-query.txt | 0 src/{doc => docs}/db-repair.txt | 0 src/{doc => docs}/db-reset.txt | 0 src/{doc => docs}/eval-file.txt | 0 src/{doc => docs}/eval.txt | 0 src/{doc => docs}/export.txt | 0 src/{doc => docs}/generate-posts.txt | 0 src/{doc => docs}/generate-users.txt | 0 src/{doc => docs}/home.txt | 0 src/{doc => docs}/option.txt | 0 src/{doc => docs}/plugin-activate.txt | 0 src/{doc => docs}/plugin-deactivate.txt | 0 src/{doc => docs}/plugin-delete.txt | 0 src/{doc => docs}/plugin-install.txt | 0 src/{doc => docs}/plugin-path.txt | 0 src/{doc => docs}/plugin-status.txt | 0 src/{doc => docs}/plugin-toggle.txt | 0 src/{doc => docs}/plugin-uninstall.txt | 0 src/{doc => docs}/plugin-update.txt | 0 src/{doc => docs}/post-create.txt | 0 src/{doc => docs}/post-delete.txt | 0 src/{doc => docs}/post-meta.txt | 0 src/{doc => docs}/post-update.txt | 0 src/{doc => docs}/theme-activate.txt | 0 src/{doc => docs}/theme-delete.txt | 0 src/{doc => docs}/theme-install.txt | 0 src/{doc => docs}/theme-path.txt | 0 src/{doc => docs}/theme-status.txt | 0 src/{doc => docs}/theme-update.txt | 0 src/{doc => docs}/transient.txt | 0 src/{doc => docs}/user-create.txt | 0 src/{doc => docs}/user-delete.txt | 0 src/{doc => docs}/user-list.txt | 0 src/{doc => docs}/user-meta.txt | 0 src/{doc => docs}/user-update.txt | 0 utils/doc-build | 2 +- utils/pear-build | 1 - 103 files changed, 51 insertions(+), 52 deletions(-) rename src/{doc => docs}/blog-create.txt (100%) rename src/{doc => docs}/cache.txt (100%) rename src/{doc => docs}/core-config.txt (100%) rename src/{doc => docs}/core-download.txt (100%) rename src/{doc => docs}/core-install.txt (100%) rename src/{doc => docs}/core-install_network.txt (100%) rename src/{doc => docs}/core-update.txt (100%) rename src/{doc => docs}/core-update_db.txt (100%) rename src/{doc => docs}/core-version.txt (100%) rename src/{doc => docs}/db-cli.txt (100%) rename src/{doc => docs}/db-connect.txt (100%) rename src/{doc => docs}/db-create.txt (100%) rename src/{doc => docs}/db-drop.txt (100%) rename src/{doc => docs}/db-export.txt (100%) rename src/{doc => docs}/db-import.txt (100%) rename src/{doc => docs}/db-optimize.txt (100%) rename src/{doc => docs}/db-query.txt (100%) rename src/{doc => docs}/db-repair.txt (100%) rename src/{doc => docs}/db-reset.txt (100%) rename src/{doc => docs}/eval-file.txt (100%) rename src/{doc => docs}/eval.txt (100%) rename src/{doc => docs}/export.txt (100%) rename src/{doc => docs}/generate-posts.txt (100%) rename src/{doc => docs}/generate-users.txt (100%) rename src/{doc => docs}/home.txt (100%) rename src/{doc => docs}/option.txt (100%) rename src/{doc => docs}/plugin-activate.txt (100%) rename src/{doc => docs}/plugin-deactivate.txt (100%) rename src/{doc => docs}/plugin-delete.txt (100%) rename src/{doc => docs}/plugin-install.txt (100%) rename src/{doc => docs}/plugin-path.txt (100%) rename src/{doc => docs}/plugin-status.txt (100%) rename src/{doc => docs}/plugin-toggle.txt (100%) rename src/{doc => docs}/plugin-uninstall.txt (100%) rename src/{doc => docs}/plugin-update.txt (100%) rename src/{doc => docs}/post-create.txt (100%) rename src/{doc => docs}/post-delete.txt (100%) rename src/{doc => docs}/post-meta.txt (100%) rename src/{doc => docs}/post-update.txt (100%) rename src/{doc => docs}/theme-activate.txt (100%) rename src/{doc => docs}/theme-delete.txt (100%) rename src/{doc => docs}/theme-install.txt (100%) rename src/{doc => docs}/theme-path.txt (100%) rename src/{doc => docs}/theme-status.txt (100%) rename src/{doc => docs}/theme-update.txt (100%) rename src/{doc => docs}/transient.txt (100%) rename src/{doc => docs}/user-create.txt (100%) rename src/{doc => docs}/user-delete.txt (100%) rename src/{doc => docs}/user-list.txt (100%) rename src/{doc => docs}/user-meta.txt (100%) rename src/{doc => docs}/user-update.txt (100%) diff --git a/man/blog-create.1 b/man/blog-create.1 index e75b5ee6c..338aff284 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-CREATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-BLOG\-CREATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-blog\-create\fR \- Create a new blog in a multisite install\. diff --git a/man/core-config.1 b/man/core-config.1 index 0235a39bc..cc545a665 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-CONFIG" "1" "May 2012" "" "WP-CLI" +.TH "WP\-CORE\-CONFIG" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-config\fR \- Create a wp\-config\.php file\. diff --git a/man/core-download.1 b/man/core-download.1 index 8d4e9f8e6..9dc988e6d 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-DOWNLOAD" "1" "May 2012" "" "WP-CLI" +.TH "WP\-CORE\-DOWNLOAD" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-download\fR \- Download core WordPress files\. diff --git a/man/core-install.1 b/man/core-install.1 index 1c4213965..9ba7e9e4a 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL" "1" "June 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-install\fR \- Install the WordPress tables in the database\. diff --git a/man/core-install_network.1 b/man/core-install_network.1 index 09fcc2890..6aad5aa0f 100644 --- a/man/core-install_network.1 +++ b/man/core-install_network.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL_NETWORK" "1" "July 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL_NETWORK" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-install_network\fR \- Transform a single\-site install into a diff --git a/man/core-update.1 b/man/core-update.1 index af27373d7..c0b4f8c61 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update\fR \- Update WordPress to the latest version\. diff --git a/man/core-update_db.1 b/man/core-update_db.1 index e9a570d92..dc5a11563 100644 --- a/man/core-update_db.1 +++ b/man/core-update_db.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE_DB" "1" "July 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE_DB" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update_db\fR \- Update the WordPress database\. diff --git a/man/core-version.1 b/man/core-version.1 index 160ccb376..8e910bab1 100644 --- a/man/core-version.1 +++ b/man/core-version.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-VERSION" "1" "May 2012" "" "WP-CLI" +.TH "WP\-CORE\-VERSION" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-version\fR \- Show the WordPress version\. diff --git a/man/db-cli.1 b/man/db-cli.1 index 22f397c05..c8ae69ee6 100644 --- a/man/db-cli.1 +++ b/man/db-cli.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CLI" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-CLI" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-cli\fR \- Open a SQL command\-line interface to the WordPress database\. diff --git a/man/db-connect.1 b/man/db-connect.1 index ea799644f..bb73c49b1 100644 --- a/man/db-connect.1 +++ b/man/db-connect.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CONNECT" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-CONNECT" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-connect\fR \- Print a string for connecting to the database\. diff --git a/man/db-create.1 b/man/db-create.1 index 93f929582..06d954353 100644 --- a/man/db-create.1 +++ b/man/db-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CREATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-CREATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-create\fR \- Create a database using the credentials from wp\-config\.php\. diff --git a/man/db-drop.1 b/man/db-drop.1 index f5c8f3b76..b3cf01108 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-DROP" "1" "July 2012" "" "WP-CLI" +.TH "WP\-DB\-DROP" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-drop\fR \- Drop the database specified in wp\-config\.php diff --git a/man/db-export.1 b/man/db-export.1 index 33648242f..06b28380c 100644 --- a/man/db-export.1 +++ b/man/db-export.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-EXPORT" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-EXPORT" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-export\fR \- Export the WordPress database using mysqldump\. diff --git a/man/db-import.1 b/man/db-import.1 index 987cade49..8941bbe14 100644 --- a/man/db-import.1 +++ b/man/db-import.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-IMPORT" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-IMPORT" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-import\fR \- Import a database from a text file\. diff --git a/man/db-optimize.1 b/man/db-optimize.1 index 56b099bad..3381c63ee 100644 --- a/man/db-optimize.1 +++ b/man/db-optimize.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-OPTIMIZE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-DB\-OPTIMIZE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-optimize\fR \- Optimize the database specified in the wp\-config\.php file\. diff --git a/man/db-query.1 b/man/db-query.1 index 0326bd394..9ba0d685b 100644 --- a/man/db-query.1 +++ b/man/db-query.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-QUERY" "1" "May 2012" "" "WP-CLI" +.TH "WP\-DB\-QUERY" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-query\fR \- Execute a query against the WordPress database\. diff --git a/man/db-repair.1 b/man/db-repair.1 index 2f9089eb6..9c96284d3 100644 --- a/man/db-repair.1 +++ b/man/db-repair.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-REPAIR" "1" "July 2012" "" "WP-CLI" +.TH "WP\-DB\-REPAIR" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-repair\fR \- Optimize the database specified in the wp\-config\.php file\. diff --git a/man/db-reset.1 b/man/db-reset.1 index 4f40b8300..de44c9539 100644 --- a/man/db-reset.1 +++ b/man/db-reset.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-RESET" "1" "August 2012" "" "WP-CLI" +.TH "WP\-DB\-RESET" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-reset\fR \- Remove all data from the database specified in wp\-config\.php diff --git a/man/eval-file.1 b/man/eval-file.1 index 5060788e1..b0a1694d4 100644 --- a/man/eval-file.1 +++ b/man/eval-file.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL\-FILE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-EVAL\-FILE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. diff --git a/man/eval.1 b/man/eval.1 index 473ec61df..2a8dbdb23 100644 --- a/man/eval.1 +++ b/man/eval.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL" "1" "May 2012" "" "WP-CLI" +.TH "WP\-EVAL" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. diff --git a/man/export.1 b/man/export.1 index d064d5db0..27afcfb5a 100644 --- a/man/export.1 +++ b/man/export.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EXPORT" "1" "May 2012" "" "WP-CLI" +.TH "WP\-EXPORT" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-export\fR \- Create a WXR file\. diff --git a/man/generate-posts.1 b/man/generate-posts.1 index fcd00ede4..9f0ef3a2e 100644 --- a/man/generate-posts.1 +++ b/man/generate-posts.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-GENERATE\-POSTS" "1" "June 2012" "" "WP-CLI" +.TH "WP\-GENERATE\-POSTS" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-generate\-posts\fR \- Generate a bunch of posts\. diff --git a/man/generate-users.1 b/man/generate-users.1 index 9fadb9950..347a6a5f0 100644 --- a/man/generate-users.1 +++ b/man/generate-users.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-GENERATE\-USERS" "1" "May 2012" "" "WP-CLI" +.TH "WP\-GENERATE\-USERS" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-generate\-users\fR \- Generate a bunch of users\. diff --git a/man/home.1 b/man/home.1 index 069590884..2dc74647e 100644 --- a/man/home.1 +++ b/man/home.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-HOME" "1" "May 2012" "" "WP-CLI" +.TH "WP\-HOME" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-home\fR \- Opens the wp\-cli homepage in your browser\. diff --git a/man/option.1 b/man/option.1 index 660dc4d26..678c77b48 100644 --- a/man/option.1 +++ b/man/option.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-OPTION" "1" "June 2012" "" "WP-CLI" +.TH "WP\-OPTION" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-option\fR \- Manage WordPress options\. diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index bcecd12c9..bff5b9bbe 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-ACTIVATE" "1" "June 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-ACTIVATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-activate\fR \- Activate an installed plugin\. diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 index a9823535c..3de02d969 100644 --- a/man/plugin-deactivate.1 +++ b/man/plugin-deactivate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "June 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-deactivate\fR \- Deactivate an active plugin\. diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 index b6c3b2034..8a8834c48 100644 --- a/man/plugin-delete.1 +++ b/man/plugin-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DELETE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DELETE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-delete\fR \- Delete a plugin\'s files, without removing it\'s data\. diff --git a/man/plugin-install.1 b/man/plugin-install.1 index a90117f76..af740f73b 100644 --- a/man/plugin-install.1 +++ b/man/plugin-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-INSTALL" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-INSTALL" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-install\fR \- Install a plugin from wordpress\.org or from a zip file\. diff --git a/man/plugin-path.1 b/man/plugin-path.1 index cbf20513b..87c1c8eb0 100644 --- a/man/plugin-path.1 +++ b/man/plugin-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-PATH" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-PATH" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. diff --git a/man/plugin-status.1 b/man/plugin-status.1 index cbf0900fd..98c1ea177 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-STATUS" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-STATUS" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index f86b819e5..9764eca03 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "June 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-deactivate\fR \- Activate/Deactivate an installed plugin\. diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 index 0d5430032..7e6bd9043 100644 --- a/man/plugin-uninstall.1 +++ b/man/plugin-uninstall.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UNINSTALL" "1" "June 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UNINSTALL" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-uninstall\fR \- Run the uninstallation procedure for a plugin\. diff --git a/man/plugin-update.1 b/man/plugin-update.1 index a5f21a8eb..3fcac90c5 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UPDATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UPDATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-update\fR \- Update an installed plugin\. diff --git a/man/post-create.1 b/man/post-create.1 index 3ed689f81..072011b4c 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-CREATE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-POST\-CREATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-create\fR \- Create a new WordPress post\. diff --git a/man/post-delete.1 b/man/post-delete.1 index 3bfd901a9..a46fb79bb 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-DELETE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-POST\-DELETE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-delete\fR \- Delete a WordPress post\. diff --git a/man/post-meta.1 b/man/post-meta.1 index 65bce7c9b..6107d180a 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-META" "1" "July 2012" "" "WP-CLI" +.TH "WP\-POST\-META" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-meta\fR \- Manage post custom fields\. diff --git a/man/post-update.1 b/man/post-update.1 index 7ef6418ed..60d85f15b 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-UPDATE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-POST\-UPDATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-update\fR \- Update a WordPress post\. diff --git a/man/theme-activate.1 b/man/theme-activate.1 index 0d8c95f48..55861bc3d 100644 --- a/man/theme-activate.1 +++ b/man/theme-activate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-ACTIVATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-ACTIVATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-activate\fR \- Activate an installed theme\. diff --git a/man/theme-delete.1 b/man/theme-delete.1 index 48f0c8357..0514d865d 100644 --- a/man/theme-delete.1 +++ b/man/theme-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-DELETE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-DELETE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-delete\fR \- Delete a theme\. diff --git a/man/theme-install.1 b/man/theme-install.1 index 71f60fb0e..3042b5bee 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-INSTALL" "1" "July 2012" "" "WP-CLI" +.TH "WP\-THEME\-INSTALL" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-install\fR \- Install a theme from wordpress\.org or from a zip file\. diff --git a/man/theme-path.1 b/man/theme-path.1 index 3d806d057..90bf49d82 100644 --- a/man/theme-path.1 +++ b/man/theme-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-PATH" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-PATH" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. diff --git a/man/theme-status.1 b/man/theme-status.1 index 2d68b088d..53b68274a 100644 --- a/man/theme-status.1 +++ b/man/theme-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-STATUS" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-STATUS" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-status\fR \- See the status of one or all themes\. diff --git a/man/theme-update.1 b/man/theme-update.1 index 686ccb02a..5ae00b078 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-UPDATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-THEME\-UPDATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-update\fR \- Update an installed theme\. diff --git a/man/transient.1 b/man/transient.1 index d2307b45b..0d10b8a23 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-TRANSIENT" "1" "May 2012" "" "WP-CLI" +.TH "WP\-TRANSIENT" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-transient\fR \- Manage WordPress transients\. diff --git a/man/user-create.1 b/man/user-create.1 index c96e19827..67537e0c7 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-CREATE" "1" "July 2012" "" "WP-CLI" +.TH "WP\-USER\-CREATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-create\fR \- Create a new WordPress user\. diff --git a/man/user-delete.1 b/man/user-delete.1 index dfab940b6..a33d6fdd3 100644 --- a/man/user-delete.1 +++ b/man/user-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-DELETE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-USER\-DELETE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-delete\fR \- Delete a WordPress user\. diff --git a/man/user-list.1 b/man/user-list.1 index 1ae1b93b5..0535f8674 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-LIST" "1" "May 2012" "" "WP-CLI" +.TH "WP\-USER\-LIST" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-list\fR \- List WordPress users\. diff --git a/man/user-meta.1 b/man/user-meta.1 index fa9b646d5..73130d87e 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-META" "1" "June 2012" "" "WP-CLI" +.TH "WP\-USER\-META" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-meta\fR \- Manage user custom fields\. diff --git a/man/user-update.1 b/man/user-update.1 index c5b8af7f2..cebdfef6b 100644 --- a/man/user-update.1 +++ b/man/user-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-UPDATE" "1" "May 2012" "" "WP-CLI" +.TH "WP\-USER\-UPDATE" "1" "September 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-update\fR \- Update a WordPress user\. diff --git a/src/doc/blog-create.txt b/src/docs/blog-create.txt similarity index 100% rename from src/doc/blog-create.txt rename to src/docs/blog-create.txt diff --git a/src/doc/cache.txt b/src/docs/cache.txt similarity index 100% rename from src/doc/cache.txt rename to src/docs/cache.txt diff --git a/src/doc/core-config.txt b/src/docs/core-config.txt similarity index 100% rename from src/doc/core-config.txt rename to src/docs/core-config.txt diff --git a/src/doc/core-download.txt b/src/docs/core-download.txt similarity index 100% rename from src/doc/core-download.txt rename to src/docs/core-download.txt diff --git a/src/doc/core-install.txt b/src/docs/core-install.txt similarity index 100% rename from src/doc/core-install.txt rename to src/docs/core-install.txt diff --git a/src/doc/core-install_network.txt b/src/docs/core-install_network.txt similarity index 100% rename from src/doc/core-install_network.txt rename to src/docs/core-install_network.txt diff --git a/src/doc/core-update.txt b/src/docs/core-update.txt similarity index 100% rename from src/doc/core-update.txt rename to src/docs/core-update.txt diff --git a/src/doc/core-update_db.txt b/src/docs/core-update_db.txt similarity index 100% rename from src/doc/core-update_db.txt rename to src/docs/core-update_db.txt diff --git a/src/doc/core-version.txt b/src/docs/core-version.txt similarity index 100% rename from src/doc/core-version.txt rename to src/docs/core-version.txt diff --git a/src/doc/db-cli.txt b/src/docs/db-cli.txt similarity index 100% rename from src/doc/db-cli.txt rename to src/docs/db-cli.txt diff --git a/src/doc/db-connect.txt b/src/docs/db-connect.txt similarity index 100% rename from src/doc/db-connect.txt rename to src/docs/db-connect.txt diff --git a/src/doc/db-create.txt b/src/docs/db-create.txt similarity index 100% rename from src/doc/db-create.txt rename to src/docs/db-create.txt diff --git a/src/doc/db-drop.txt b/src/docs/db-drop.txt similarity index 100% rename from src/doc/db-drop.txt rename to src/docs/db-drop.txt diff --git a/src/doc/db-export.txt b/src/docs/db-export.txt similarity index 100% rename from src/doc/db-export.txt rename to src/docs/db-export.txt diff --git a/src/doc/db-import.txt b/src/docs/db-import.txt similarity index 100% rename from src/doc/db-import.txt rename to src/docs/db-import.txt diff --git a/src/doc/db-optimize.txt b/src/docs/db-optimize.txt similarity index 100% rename from src/doc/db-optimize.txt rename to src/docs/db-optimize.txt diff --git a/src/doc/db-query.txt b/src/docs/db-query.txt similarity index 100% rename from src/doc/db-query.txt rename to src/docs/db-query.txt diff --git a/src/doc/db-repair.txt b/src/docs/db-repair.txt similarity index 100% rename from src/doc/db-repair.txt rename to src/docs/db-repair.txt diff --git a/src/doc/db-reset.txt b/src/docs/db-reset.txt similarity index 100% rename from src/doc/db-reset.txt rename to src/docs/db-reset.txt diff --git a/src/doc/eval-file.txt b/src/docs/eval-file.txt similarity index 100% rename from src/doc/eval-file.txt rename to src/docs/eval-file.txt diff --git a/src/doc/eval.txt b/src/docs/eval.txt similarity index 100% rename from src/doc/eval.txt rename to src/docs/eval.txt diff --git a/src/doc/export.txt b/src/docs/export.txt similarity index 100% rename from src/doc/export.txt rename to src/docs/export.txt diff --git a/src/doc/generate-posts.txt b/src/docs/generate-posts.txt similarity index 100% rename from src/doc/generate-posts.txt rename to src/docs/generate-posts.txt diff --git a/src/doc/generate-users.txt b/src/docs/generate-users.txt similarity index 100% rename from src/doc/generate-users.txt rename to src/docs/generate-users.txt diff --git a/src/doc/home.txt b/src/docs/home.txt similarity index 100% rename from src/doc/home.txt rename to src/docs/home.txt diff --git a/src/doc/option.txt b/src/docs/option.txt similarity index 100% rename from src/doc/option.txt rename to src/docs/option.txt diff --git a/src/doc/plugin-activate.txt b/src/docs/plugin-activate.txt similarity index 100% rename from src/doc/plugin-activate.txt rename to src/docs/plugin-activate.txt diff --git a/src/doc/plugin-deactivate.txt b/src/docs/plugin-deactivate.txt similarity index 100% rename from src/doc/plugin-deactivate.txt rename to src/docs/plugin-deactivate.txt diff --git a/src/doc/plugin-delete.txt b/src/docs/plugin-delete.txt similarity index 100% rename from src/doc/plugin-delete.txt rename to src/docs/plugin-delete.txt diff --git a/src/doc/plugin-install.txt b/src/docs/plugin-install.txt similarity index 100% rename from src/doc/plugin-install.txt rename to src/docs/plugin-install.txt diff --git a/src/doc/plugin-path.txt b/src/docs/plugin-path.txt similarity index 100% rename from src/doc/plugin-path.txt rename to src/docs/plugin-path.txt diff --git a/src/doc/plugin-status.txt b/src/docs/plugin-status.txt similarity index 100% rename from src/doc/plugin-status.txt rename to src/docs/plugin-status.txt diff --git a/src/doc/plugin-toggle.txt b/src/docs/plugin-toggle.txt similarity index 100% rename from src/doc/plugin-toggle.txt rename to src/docs/plugin-toggle.txt diff --git a/src/doc/plugin-uninstall.txt b/src/docs/plugin-uninstall.txt similarity index 100% rename from src/doc/plugin-uninstall.txt rename to src/docs/plugin-uninstall.txt diff --git a/src/doc/plugin-update.txt b/src/docs/plugin-update.txt similarity index 100% rename from src/doc/plugin-update.txt rename to src/docs/plugin-update.txt diff --git a/src/doc/post-create.txt b/src/docs/post-create.txt similarity index 100% rename from src/doc/post-create.txt rename to src/docs/post-create.txt diff --git a/src/doc/post-delete.txt b/src/docs/post-delete.txt similarity index 100% rename from src/doc/post-delete.txt rename to src/docs/post-delete.txt diff --git a/src/doc/post-meta.txt b/src/docs/post-meta.txt similarity index 100% rename from src/doc/post-meta.txt rename to src/docs/post-meta.txt diff --git a/src/doc/post-update.txt b/src/docs/post-update.txt similarity index 100% rename from src/doc/post-update.txt rename to src/docs/post-update.txt diff --git a/src/doc/theme-activate.txt b/src/docs/theme-activate.txt similarity index 100% rename from src/doc/theme-activate.txt rename to src/docs/theme-activate.txt diff --git a/src/doc/theme-delete.txt b/src/docs/theme-delete.txt similarity index 100% rename from src/doc/theme-delete.txt rename to src/docs/theme-delete.txt diff --git a/src/doc/theme-install.txt b/src/docs/theme-install.txt similarity index 100% rename from src/doc/theme-install.txt rename to src/docs/theme-install.txt diff --git a/src/doc/theme-path.txt b/src/docs/theme-path.txt similarity index 100% rename from src/doc/theme-path.txt rename to src/docs/theme-path.txt diff --git a/src/doc/theme-status.txt b/src/docs/theme-status.txt similarity index 100% rename from src/doc/theme-status.txt rename to src/docs/theme-status.txt diff --git a/src/doc/theme-update.txt b/src/docs/theme-update.txt similarity index 100% rename from src/doc/theme-update.txt rename to src/docs/theme-update.txt diff --git a/src/doc/transient.txt b/src/docs/transient.txt similarity index 100% rename from src/doc/transient.txt rename to src/docs/transient.txt diff --git a/src/doc/user-create.txt b/src/docs/user-create.txt similarity index 100% rename from src/doc/user-create.txt rename to src/docs/user-create.txt diff --git a/src/doc/user-delete.txt b/src/docs/user-delete.txt similarity index 100% rename from src/doc/user-delete.txt rename to src/docs/user-delete.txt diff --git a/src/doc/user-list.txt b/src/docs/user-list.txt similarity index 100% rename from src/doc/user-list.txt rename to src/docs/user-list.txt diff --git a/src/doc/user-meta.txt b/src/docs/user-meta.txt similarity index 100% rename from src/doc/user-meta.txt rename to src/docs/user-meta.txt diff --git a/src/doc/user-update.txt b/src/docs/user-update.txt similarity index 100% rename from src/doc/user-update.txt rename to src/docs/user-update.txt diff --git a/utils/doc-build b/utils/doc-build index a4bf43d08..8cb5c7c28 100755 --- a/utils/doc-build +++ b/utils/doc-build @@ -6,7 +6,7 @@ # ln -s ../../utils/doc-build .git/hooks/pre-commit if [ $# -eq 0 ]; then - files=$(git diff --cached --name-only src/doc/) + files=$(git diff --cached --name-only src/docs/) else files=$@ fi diff --git a/utils/pear-build b/utils/pear-build index 07530db9a..e044a8c4d 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -6,7 +6,6 @@ set -ex mkdir -p src/data mkdir -p src/tests/unit-tests/php mkdir -p src/www -mkdir -p src/docs # temporarily move the .git dir, because phing is stupid git_dir=src/php/php-cli-tools/.git From 15009ab451eefdf97ec345ae221904e40dad928f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Sep 2012 14:31:00 +0300 Subject: [PATCH 0542/5359] wp cache switch_to_blog does not make sense as a standalone subcommands. see #155 --- man/cache.1 | 6 ----- src/docs/cache.txt | 4 ---- src/php/wp-cli/commands/internals/cache.php | 26 +-------------------- 3 files changed, 1 insertion(+), 35 deletions(-) diff --git a/man/cache.1 b/man/cache.1 index 6024971c0..553960fad 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -105,12 +105,6 @@ Replace a value in cache with a new value\. Set a value in cache\. . .TP -\fBswitch_to_blog\fR: -. -.IP -Interact with the cache for the specified \fIblog_id\fR\. -. -.TP \fBtype\fR: . .IP diff --git a/src/docs/cache.txt b/src/docs/cache.txt index e28de79f6..069a875d3 100644 --- a/src/docs/cache.txt +++ b/src/docs/cache.txt @@ -69,10 +69,6 @@ wp cache type Set a value in cache. -* `switch_to_blog`: - - Interact with the cache for the specified <blog_id>. - * `type`: Report the type of object being used. diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index 546439036..5c1233994 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -281,30 +281,6 @@ public function set( $args, $assoc_args ) { WP_CLI::success( "Set object '$key' in group '$group'." ); } - /** - * Switch the blog id, which switches the cache keys for all values. - * - * @uses wp_cache_switch_to_blog - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void - */ - public function switch_to_blog( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache switch_to_blog <blog_id>' ); - exit; - } - - if ( ! function_exists( 'wp_cache_switch_to_blog' ) ) { - WP_CLI::warning( "Command cannot be executed because the 'wp_cache_switch_to_blog' function does not exist." ); - } - - $blog_id = $args[0]; - - wp_cache_switch_to_blog( $blog_id ); - } - /** * Attempts to determine which object cache is being used. * @@ -358,4 +334,4 @@ public function type( $args, $assoc_args ) { WP_CLI::print_value( $message ); } -} \ No newline at end of file +} From 9c30fe19f889da6f83c67f4af505c718d7a9efa0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Sep 2012 15:39:01 +0300 Subject: [PATCH 0543/5359] bump version to 0.7.0-alpha --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 7ad523325..1fbd96dd9 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -5,7 +5,7 @@ die(-1); } -define( 'WP_CLI_VERSION', '0.6.0' ); +define( 'WP_CLI_VERSION', '0.7.0-alpha' ); // Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 9509bf4148c1840aaedee70ffc6a37f7dad3323c Mon Sep 17 00:00:00 2001 From: ozh <ozh@ozh.org> Date: Fri, 7 Sep 2012 14:52:32 +0200 Subject: [PATCH 0544/5359] Implementation of the "comment" command Subcommands: create, delete, trash, untrash, spam, unspam, approve, unapprove, status, count, last --- src/php/wp-cli/commands/internals/comment.php | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/comment.php diff --git a/src/php/wp-cli/commands/internals/comment.php b/src/php/wp-cli/commands/internals/comment.php new file mode 100644 index 000000000..e64121295 --- /dev/null +++ b/src/php/wp-cli/commands/internals/comment.php @@ -0,0 +1,266 @@ +<?php +/** + * Implement 'comment' command + * + * @package wp-cli + * @subpackage commands/internals + */ + +// Register the 'comment' command handler +WP_CLI::add_command( 'comment', 'Comment_Command' ); + +class Comment_Command extends WP_CLI_Command { + + /** + * Basic help message + */ + static function help() { + WP_CLI::line( 'usage: wp comment [last|create|delete|trash|untrash|spam|unspam|approve|unapprove|count|status]' ); + } + + + /** + * Insert a comment. + * + * Example: wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" + * + * @param array $args} + * @param array $assoc_args + */ + public function create( $args, $assoc_args ) { + // Just one check: make sure the post actually exists + $comment_post_ID = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); + $post = get_post( $comment_post_ID ); + if ( empty( $post->comment_status ) ) { + WP_CLI::error( "Cannot find post $comment_post_ID" ); + } + + // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and avoid wp_die() formatted messages or notifications + $comment_id = wp_insert_comment( $assoc_args ); + + if ( 0 == $comment_id ) { + WP_CLI::error( "Could not create comment" ); + } + + if ( isset( $assoc_args['porcelain'] ) ) + WP_CLI::line( $comment_id ); + else + WP_CLI::success( "Inserted comment $comment_id." ); + } + + + /** + * Delete a comment + * + * Example: wp comment delete 15 --force + * + * @param array $args} + * @param array $assoc_args + */ + public function delete( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + // Boolean $force parameter to bypass trash and really delete + $force = ( isset( $assoc_args['force'] ) ? true : false ); + + if ( wp_delete_comment( $comment_id, $force ) ) { + WP_CLI::success( "Deleted comment $comment_id." ); + } else { + WP_CLI::error( "Failed deleting comment $comment_id" ); + } + } + + + /** + * Trash a comment + * + * Example: wp comment trash 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function trash( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + if ( wp_trash_comment( $comment_id ) ) { + WP_CLI::success( "Trashed comment $comment_id." ); + } else { + WP_CLI::error( "Failed trashing comment $comment_id" ); + } + } + + + /** + * Untrash a comment + * + * Example: wp comment untrash 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function untrash( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + if ( wp_untrash_comment( $comment_id ) ) { + WP_CLI::success( "Untrashed comment $comment_id." ); + } else { + WP_CLI::error( "Failed untrashing comment $comment_id" ); + } + } + + + /** + * Spam a comment + * + * Example: wp comment spam 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function spam( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + if ( wp_spam_comment( $comment_id ) ) { + WP_CLI::success( "Spammed comment $comment_id." ); + } else { + WP_CLI::error( "Failed spamming comment $comment_id" ); + } + } + + + /** + * Unspam a comment + * + * Example: wp comment unspam 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function unspam( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + if ( wp_unspam_comment( $comment_id ) ) { + WP_CLI::success( "Unspammed comment $comment_id." ); + } else { + WP_CLI::error( "Failed unspamming comment $comment_id" ); + } + } + + + /** + * Approve a comment + * + * Example: wp comment approve 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function approve( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + $comment = wp_set_comment_status( $comment_id, 'approve', true ); // last parameter 'true' to return a WP_Error object if there is a failure + + if ( is_wp_error( $comment ) ) { + WP_CLI::error( $comment ); + } else { + WP_CLI::success( "Approved comment $comment_id" ); + } + } + + + /** + * Unapprove a comment + * + * Example: wp comment unapprove 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function unapprove( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + $comment = wp_set_comment_status( $comment_id, 'hold', true ); + + if ( is_wp_error( $comment ) ) { + WP_CLI::error( $comment ); + } else { + WP_CLI::success( "Unapproved comment $comment_id" ); + } + } + + + /** + * Count comments, in whole blog or in a given post + * + * Example: "wp comment count 43" to count comments on post 43 + * Example: "wp comment count" to count comments on blog + * + * @param array $args} + * @param array $assoc_args + */ + public function count( $args, $assoc_args ) { + $post_id = ( isset( $args[0] ) && is_numeric( $args[0] ) ? $args[0] : 0 ); + + $comments = wp_count_comments( $post_id ); + // Move total_comments to the end of the object + $total = $comments->total_comments; + unset( $comments->total_comments ); + $comments->total_comments = $total; + + foreach( $comments as $status => $count ) { + WP_CLI::line( str_pad( "$status:", 17 ) . $count ); + } + } + + + /** + * Get status of a comment + * + * Example: wp comment status 15 + * + * @param array $args} + * @param array $assoc_args + */ + public function status( $args, $assoc_args ) { + $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + + $status = wp_get_comment_status( $comment_id ); + + if( false === $status ) { + WP_CLI::error( "Could not check status of comment $comment" ); + } else { + WP_CLI::line( $status ); + } + } + + + /** + * Get last approved comment. Options: --porcelain, --full|verbose + * + * @param array $args} + * @param array $assoc_args + */ + function last( $args = array(), $assoc_args = array() ) { + $last = get_comments( array( 'number' => 1, 'status' => 'approve' ) ); + extract( get_object_vars( $last[0] ) ); + // populates: comment_ID, comment_post_ID, comment_author, ... See http://codex.wordpress.org/Function_Reference/get_comments#Returns + + if ( isset( $assoc_args['porcelain'] ) ) { + WP_CLI::line( $comment_ID ); + exit( 1 ); + } + + WP_CLI::line( "%yLast approved comment :%n" ); + + if( isset( $assoc_args['verbose'] ) OR isset( $assoc_args['full'] ) ) { + $keys = array_keys( get_object_vars( $last[0] ) ); + } else { + $keys = array( 'comment_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' ); + } + foreach( $keys as $key ) { + WP_CLI::line( str_pad( "$key:", 23 ) . ${$key} ); + } + } + + +} From 384a2e435dae0769aef3fa01d201ec24996447b6 Mon Sep 17 00:00:00 2001 From: ozh <ozh@ozh.org> Date: Fri, 7 Sep 2012 15:39:51 +0200 Subject: [PATCH 0545/5359] Help files for the comment subcommands --- src/docs/comment-approve.txt | 16 ++++++++++++++ src/docs/comment-count.txt | 17 +++++++++++++++ src/docs/comment-create.txt | 21 +++++++++++++++++++ src/docs/comment-delete.txt | 20 ++++++++++++++++++ src/docs/comment-last.txt | 20 ++++++++++++++++++ src/docs/comment-spam.txt | 16 ++++++++++++++ src/docs/comment-status.txt | 16 ++++++++++++++ src/docs/comment-trash.txt | 16 ++++++++++++++ src/docs/comment-unapprove.txt | 16 ++++++++++++++ src/docs/comment-unspam.txt | 16 ++++++++++++++ src/docs/comment-untrash.txt | 16 ++++++++++++++ src/php/wp-cli/commands/internals/comment.php | 8 ------- 12 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 src/docs/comment-approve.txt create mode 100644 src/docs/comment-count.txt create mode 100644 src/docs/comment-create.txt create mode 100644 src/docs/comment-delete.txt create mode 100644 src/docs/comment-last.txt create mode 100644 src/docs/comment-spam.txt create mode 100644 src/docs/comment-status.txt create mode 100644 src/docs/comment-trash.txt create mode 100644 src/docs/comment-unapprove.txt create mode 100644 src/docs/comment-unspam.txt create mode 100644 src/docs/comment-untrash.txt diff --git a/src/docs/comment-approve.txt b/src/docs/comment-approve.txt new file mode 100644 index 000000000..7ed0ac4a1 --- /dev/null +++ b/src/docs/comment-approve.txt @@ -0,0 +1,16 @@ +wp-comment-approve(1) -- Approve a comment. +==== + +## SYNOPSIS + +`wp comment approve` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to approve. + +## EXAMPLES + + wp comment approve 1337 diff --git a/src/docs/comment-count.txt b/src/docs/comment-count.txt new file mode 100644 index 000000000..1c2abcf86 --- /dev/null +++ b/src/docs/comment-count.txt @@ -0,0 +1,17 @@ +wp-comment-count(1) -- Get total comments for blog or single post +==== + +## SYNOPSIS + +`wp comment count` [<ID>] + +## OPTIONS + +* `<ID>`: + + The ID of the post to count comments in + +## EXAMPLES + + wp comment count + wp comment count 42 diff --git a/src/docs/comment-create.txt b/src/docs/comment-create.txt new file mode 100644 index 000000000..b64ecb4e0 --- /dev/null +++ b/src/docs/comment-create.txt @@ -0,0 +1,21 @@ +wp-comment-create(1) -- Create a new comment. +==== + +## SYNOPSIS + +`wp comment create` --<field>=<value> [--<field>=<value>...] [--porcelain] + +## OPTIONS + +* `--<field>`=<value>: + + Field values for the new comment. See wp_insert_comment(). + +* `--porcelain`: + + Output just the new comment id. + +## EXAMPLES + + wp comment create --comment_post_ID=15 --comment_content="hello blog" +--comment_author="wp-cli" diff --git a/src/docs/comment-delete.txt b/src/docs/comment-delete.txt new file mode 100644 index 000000000..2cb016dcb --- /dev/null +++ b/src/docs/comment-delete.txt @@ -0,0 +1,20 @@ +wp-comment-delete(1) -- Delete a comment. +==== + +## SYNOPSIS + +`wp comment delete` <ID> [--force] + +## OPTIONS + +* `<ID>`: + + The ID of the comment to delete. + +* `--force`: + + Skip the trash bin. + +## EXAMPLES + + wp comment delete 1337 --force diff --git a/src/docs/comment-last.txt b/src/docs/comment-last.txt new file mode 100644 index 000000000..dec1e1308 --- /dev/null +++ b/src/docs/comment-last.txt @@ -0,0 +1,20 @@ +wp-comment-last(1) -- Retrieve last approved comment +==== + +## SYNOPSIS + +`wp comment last` [--porcelain] [--full|verbose] + +## OPTIONS + +* `--porcelain`: + + Output just the last comment id. + +* `--full` or `--verbose`: + + Output complete comment information + +## EXAMPLES + + wp comment last diff --git a/src/docs/comment-spam.txt b/src/docs/comment-spam.txt new file mode 100644 index 000000000..0fcdaf9a6 --- /dev/null +++ b/src/docs/comment-spam.txt @@ -0,0 +1,16 @@ +wp-comment-spam(1) -- Mark a comment as spam. +==== + +## SYNOPSIS + +`wp comment spam` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to mark as spam. + +## EXAMPLES + + wp comment spam 1337 diff --git a/src/docs/comment-status.txt b/src/docs/comment-status.txt new file mode 100644 index 000000000..ee51ec4fd --- /dev/null +++ b/src/docs/comment-status.txt @@ -0,0 +1,16 @@ +wp-comment-status(1) -- Get status of a comment +==== + +## SYNOPSIS + +`wp comment status` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to check + +## EXAMPLES + + wp comment status 1337 diff --git a/src/docs/comment-trash.txt b/src/docs/comment-trash.txt new file mode 100644 index 000000000..791968f52 --- /dev/null +++ b/src/docs/comment-trash.txt @@ -0,0 +1,16 @@ +wp-comment-trash(1) -- Trash a comment. +==== + +## SYNOPSIS + +`wp comment trash` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to trash. + +## EXAMPLES + + wp comment trash 1337 diff --git a/src/docs/comment-unapprove.txt b/src/docs/comment-unapprove.txt new file mode 100644 index 000000000..1fee7ac48 --- /dev/null +++ b/src/docs/comment-unapprove.txt @@ -0,0 +1,16 @@ +wp-comment-unapprove(1) -- Unapprove a comment. +==== + +## SYNOPSIS + +`wp comment unapprove` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to unapprove. + +## EXAMPLES + + wp comment unapprove 1337 diff --git a/src/docs/comment-unspam.txt b/src/docs/comment-unspam.txt new file mode 100644 index 000000000..59e9ff494 --- /dev/null +++ b/src/docs/comment-unspam.txt @@ -0,0 +1,16 @@ +wp-comment-unspam(1) -- Unmark a comment as spam. +==== + +## SYNOPSIS + +`wp comment unspam` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to unmark as spam. + +## EXAMPLES + + wp comment unspam 1337 diff --git a/src/docs/comment-untrash.txt b/src/docs/comment-untrash.txt new file mode 100644 index 000000000..d35967a3f --- /dev/null +++ b/src/docs/comment-untrash.txt @@ -0,0 +1,16 @@ +wp-comment-untrash(1) -- Untrash a comment. +==== + +## SYNOPSIS + +`wp comment untrash` <ID> + +## OPTIONS + +* `<ID>`: + + The ID of the comment to untrash. + +## EXAMPLES + + wp comment untrash 1337 diff --git a/src/php/wp-cli/commands/internals/comment.php b/src/php/wp-cli/commands/internals/comment.php index e64121295..b6b4abc93 100644 --- a/src/php/wp-cli/commands/internals/comment.php +++ b/src/php/wp-cli/commands/internals/comment.php @@ -11,14 +11,6 @@ class Comment_Command extends WP_CLI_Command { - /** - * Basic help message - */ - static function help() { - WP_CLI::line( 'usage: wp comment [last|create|delete|trash|untrash|spam|unspam|approve|unapprove|count|status]' ); - } - - /** * Insert a comment. * From 6ade0b17cb51c0fabc49332f335778b1655569fa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Sep 2012 17:03:46 +0300 Subject: [PATCH 0546/5359] add man pages. see #158 --- man/comment-approve.1 | 27 +++++++++++++++++++++++++++ man/comment-count.1 | 28 ++++++++++++++++++++++++++++ man/comment-create.1 | 35 +++++++++++++++++++++++++++++++++++ man/comment-delete.1 | 33 +++++++++++++++++++++++++++++++++ man/comment-last.1 | 33 +++++++++++++++++++++++++++++++++ man/comment-spam.1 | 27 +++++++++++++++++++++++++++ man/comment-status.1 | 27 +++++++++++++++++++++++++++ man/comment-trash.1 | 27 +++++++++++++++++++++++++++ man/comment-unapprove.1 | 27 +++++++++++++++++++++++++++ man/comment-unspam.1 | 27 +++++++++++++++++++++++++++ man/comment-untrash.1 | 27 +++++++++++++++++++++++++++ 11 files changed, 318 insertions(+) create mode 100644 man/comment-approve.1 create mode 100644 man/comment-count.1 create mode 100644 man/comment-create.1 create mode 100644 man/comment-delete.1 create mode 100644 man/comment-last.1 create mode 100644 man/comment-spam.1 create mode 100644 man/comment-status.1 create mode 100644 man/comment-trash.1 create mode 100644 man/comment-unapprove.1 create mode 100644 man/comment-unspam.1 create mode 100644 man/comment-untrash.1 diff --git a/man/comment-approve.1 b/man/comment-approve.1 new file mode 100644 index 000000000..5fbb4caa7 --- /dev/null +++ b/man/comment-approve.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-APPROVE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-approve\fR \- Approve a comment\. +. +.SH "SYNOPSIS" +\fBwp comment approve\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to approve\. +. +.SH "EXAMPLES" +. +.nf + +wp comment approve 1337 +. +.fi + diff --git a/man/comment-count.1 b/man/comment-count.1 new file mode 100644 index 000000000..733606c17 --- /dev/null +++ b/man/comment-count.1 @@ -0,0 +1,28 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-COUNT" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-count\fR \- Get total comments for blog or single post +. +.SH "SYNOPSIS" +\fBwp comment count\fR [\fIID\fR] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the post to count comments in +. +.SH "EXAMPLES" +. +.nf + +wp comment count +wp comment count 42 +. +.fi + diff --git a/man/comment-create.1 b/man/comment-create.1 new file mode 100644 index 000000000..b164b96e7 --- /dev/null +++ b/man/comment-create.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-CREATE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-create\fR \- Create a new comment\. +. +.SH "SYNOPSIS" +\fBwp comment create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-porcelain] +. +.SH "OPTIONS" +. +.TP +\fB\-\-<field>\fR=\fIvalue\fR: +. +.IP +Field values for the new comment\. See wp_insert_comment()\. +. +.TP +\fB\-\-porcelain\fR: +. +.IP +Output just the new comment id\. +. +.SH "EXAMPLES" +. +.nf + +wp comment create \-\-comment_post_ID=15 \-\-comment_content="hello blog" +. +.fi +. +.P +\-\-comment_author="wp\-cli" diff --git a/man/comment-delete.1 b/man/comment-delete.1 new file mode 100644 index 000000000..e7daaf6d6 --- /dev/null +++ b/man/comment-delete.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-DELETE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-delete\fR \- Delete a comment\. +. +.SH "SYNOPSIS" +\fBwp comment delete\fR \fIID\fR [\-\-force] +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to delete\. +. +.TP +\fB\-\-force\fR: +. +.IP +Skip the trash bin\. +. +.SH "EXAMPLES" +. +.nf + +wp comment delete 1337 \-\-force +. +.fi + diff --git a/man/comment-last.1 b/man/comment-last.1 new file mode 100644 index 000000000..ee29cdc9f --- /dev/null +++ b/man/comment-last.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-LAST" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-last\fR \- Retrieve last approved comment +. +.SH "SYNOPSIS" +\fBwp comment last\fR [\-\-porcelain] [\-\-full|verbose] +. +.SH "OPTIONS" +. +.TP +\fB\-\-porcelain\fR: +. +.IP +Output just the last comment id\. +. +.TP +\fB\-\-full\fR or \fB\-\-verbose\fR: +. +.IP +Output complete comment information +. +.SH "EXAMPLES" +. +.nf + +wp comment last +. +.fi + diff --git a/man/comment-spam.1 b/man/comment-spam.1 new file mode 100644 index 000000000..303d179e7 --- /dev/null +++ b/man/comment-spam.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-SPAM" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-spam\fR \- Mark a comment as spam\. +. +.SH "SYNOPSIS" +\fBwp comment spam\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to mark as spam\. +. +.SH "EXAMPLES" +. +.nf + +wp comment spam 1337 +. +.fi + diff --git a/man/comment-status.1 b/man/comment-status.1 new file mode 100644 index 000000000..6ca168f9d --- /dev/null +++ b/man/comment-status.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-STATUS" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-status\fR \- Get status of a comment +. +.SH "SYNOPSIS" +\fBwp comment status\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to check +. +.SH "EXAMPLES" +. +.nf + +wp comment status 1337 +. +.fi + diff --git a/man/comment-trash.1 b/man/comment-trash.1 new file mode 100644 index 000000000..cf451e98f --- /dev/null +++ b/man/comment-trash.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-TRASH" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-trash\fR \- Trash a comment\. +. +.SH "SYNOPSIS" +\fBwp comment trash\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to trash\. +. +.SH "EXAMPLES" +. +.nf + +wp comment trash 1337 +. +.fi + diff --git a/man/comment-unapprove.1 b/man/comment-unapprove.1 new file mode 100644 index 000000000..7df1204da --- /dev/null +++ b/man/comment-unapprove.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-UNAPPROVE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-unapprove\fR \- Unapprove a comment\. +. +.SH "SYNOPSIS" +\fBwp comment unapprove\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to unapprove\. +. +.SH "EXAMPLES" +. +.nf + +wp comment unapprove 1337 +. +.fi + diff --git a/man/comment-unspam.1 b/man/comment-unspam.1 new file mode 100644 index 000000000..4eb765e91 --- /dev/null +++ b/man/comment-unspam.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-UNSPAM" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-unspam\fR \- Unmark a comment as spam\. +. +.SH "SYNOPSIS" +\fBwp comment unspam\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to unmark as spam\. +. +.SH "EXAMPLES" +. +.nf + +wp comment unspam 1337 +. +.fi + diff --git a/man/comment-untrash.1 b/man/comment-untrash.1 new file mode 100644 index 000000000..223fd5cfc --- /dev/null +++ b/man/comment-untrash.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-COMMENT\-UNTRASH" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-comment\-untrash\fR \- Untrash a comment\. +. +.SH "SYNOPSIS" +\fBwp comment untrash\fR \fIID\fR +. +.SH "OPTIONS" +. +.TP +\fB<ID>\fR: +. +.IP +The ID of the comment to untrash\. +. +.SH "EXAMPLES" +. +.nf + +wp comment untrash 1337 +. +.fi + From 725a4b1a4172a2513fa9c3330cc5d3ecc08e19a3 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor <ntaintor@janrain.com> Date: Fri, 7 Sep 2012 16:20:46 -0700 Subject: [PATCH 0547/5359] Implement rewrite command Adds a command for wp rewrite, with three methods: - wp rewrite flush (--verbose) (--soft) - wp rewrite structure (structure) (--category-base=catstruct) (--tag-base=tagstruct) (--verbose) - wp rewrite dump --- src/php/wp-cli/commands/internals/rewrite.php | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/rewrite.php diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/internals/rewrite.php new file mode 100644 index 000000000..839b59591 --- /dev/null +++ b/src/php/wp-cli/commands/internals/rewrite.php @@ -0,0 +1,119 @@ +<?php + +WP_CLI:: add_command('rewrite', 'Rewrite_Command'); + +/** + * Implement rewrite command + * + * @package wp-cli + * @subpackage commands/internal + */ +class Rewrite_Command extends WP_CLI_Command { + + protected $aliases = array( + ); + + /** + * Flush rules + * + * @param array $args + * @param array $assoc_args + */ + public function flush( $args, $assoc_args ) { + + $verbose = ( isset( $assoc_args['verbose'] ) ); + $hard = ( isset( $assoc_args['soft'] ) ) ? false : true; + + if ( $verbose ) + WP_CLI::line( "Triggering ".( ( $hard ) ? 'hard' : 'soft' ). " permalink flush." ); + + flush_rewrite_rules( $hard ); + } + + /** + * Set permalink structure + * + * @param array $args + * @param array $assoc_args + */ + public function structure( $args, $assoc_args ) { + if ( !count( $args ) && !count( $assoc_args ) ) { + WP_CLI::line( "usage: wp rewrite structure <new-permalink-structure>" ); + exit; + } + global $wp_rewrite; + + // copypasta from /wp-admin/options-permalink.php + $home_path = get_home_path(); + $iis7_permalinks = iis7_supports_permalinks(); + + $prefix = $blog_prefix = ''; + if ( ! got_mod_rewrite() && ! $iis7_permalinks ) + $prefix = '/index.php'; + if ( is_multisite() && !is_subdomain_install() && is_main_site() ) + $blog_prefix = '/blog'; + + $verbose = ( isset( $assoc_args['verbose'] ) ); + + + // Update base permastruct if argument is provided + if ( isset( $args[0] ) ) { + + if ( $verbose ) + WP_CLI::line( "Setting permalink structure to ". $args[0] ); + + $permalink_structure = ( $args[0] == 'default' ) ? '' : $args[0]; + + if ( ! empty( $permalink_structure ) ) { + $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) ); + if ( $prefix && $blog_prefix ) + $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure ); + else + $permalink_structure = $blog_prefix . $permalink_structure; + } + $wp_rewrite->set_permalink_structure( $permalink_structure ); + } + + // Update category or tag bases + if ( isset( $assoc_args['category-base'] ) ) { + + if ( $verbose ) + WP_CLI::line( "Setting category base to ". $assoc_args['category-base'] ); + + $category_base = $assoc_args['category-base']; + if ( ! empty( $category_base ) ) + $category_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $category_base ) ); + $wp_rewrite->set_category_base( $category_base ); + } + + if ( isset( $assoc_args['tag-base'] ) ) { + + if ( $verbose ) + WP_CLI::line( "Setting tag base to ". $assoc_args['tag-base'] ); + + $tag_base = $assoc_args['tag-base']; + if ( ! empty( $tag_base ) ) + $tag_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $tag_base ) ); + $wp_rewrite->set_tag_base( $tag_base ); + } + + + flush_rewrite_rules( $hard ); + } + + /** + * Dump rewrite rules + * + * @param none + */ + public function dump() { + + $rules = get_option( 'rewrite_rules' ); + + foreach ( $rules as $route => $rule ) + WP_CLI::line( $route . "\t" . $rule ); + + } +} + +?> From cf595d5f987d946b6245134c3aa00e53d5763e5e Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor <ntaintor@janrain.com> Date: Sun, 9 Sep 2012 13:27:26 -0700 Subject: [PATCH 0548/5359] Remove useless '--verbose' arg option There's no useful information to provide here, so allowing people to choose verbose output is useless. --- src/php/wp-cli/commands/internals/rewrite.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/internals/rewrite.php index 839b59591..f57282aa0 100644 --- a/src/php/wp-cli/commands/internals/rewrite.php +++ b/src/php/wp-cli/commands/internals/rewrite.php @@ -20,13 +20,7 @@ class Rewrite_Command extends WP_CLI_Command { * @param array $assoc_args */ public function flush( $args, $assoc_args ) { - - $verbose = ( isset( $assoc_args['verbose'] ) ); $hard = ( isset( $assoc_args['soft'] ) ) ? false : true; - - if ( $verbose ) - WP_CLI::line( "Triggering ".( ( $hard ) ? 'hard' : 'soft' ). " permalink flush." ); - flush_rewrite_rules( $hard ); } @@ -53,15 +47,9 @@ public function structure( $args, $assoc_args ) { if ( is_multisite() && !is_subdomain_install() && is_main_site() ) $blog_prefix = '/blog'; - $verbose = ( isset( $assoc_args['verbose'] ) ); - - // Update base permastruct if argument is provided if ( isset( $args[0] ) ) { - if ( $verbose ) - WP_CLI::line( "Setting permalink structure to ". $args[0] ); - $permalink_structure = ( $args[0] == 'default' ) ? '' : $args[0]; if ( ! empty( $permalink_structure ) ) { @@ -77,9 +65,6 @@ public function structure( $args, $assoc_args ) { // Update category or tag bases if ( isset( $assoc_args['category-base'] ) ) { - if ( $verbose ) - WP_CLI::line( "Setting category base to ". $assoc_args['category-base'] ); - $category_base = $assoc_args['category-base']; if ( ! empty( $category_base ) ) $category_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $category_base ) ); @@ -88,9 +73,6 @@ public function structure( $args, $assoc_args ) { if ( isset( $assoc_args['tag-base'] ) ) { - if ( $verbose ) - WP_CLI::line( "Setting tag base to ". $assoc_args['tag-base'] ); - $tag_base = $assoc_args['tag-base']; if ( ! empty( $tag_base ) ) $tag_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $tag_base ) ); From 33638443602cec68d5d3f54802d9802b5b26ea7a Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor <ntaintor@janrain.com> Date: Sun, 9 Sep 2012 13:37:11 -0700 Subject: [PATCH 0549/5359] Add --json option to wp rewrite dump I'm not imagining any situations where you would actually want this data in json format, but it seems as though the option should be available to parallel the other subcommands where --json is available as a possible output format. --- src/php/wp-cli/commands/internals/rewrite.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/internals/rewrite.php index f57282aa0..feb28d45f 100644 --- a/src/php/wp-cli/commands/internals/rewrite.php +++ b/src/php/wp-cli/commands/internals/rewrite.php @@ -16,8 +16,8 @@ class Rewrite_Command extends WP_CLI_Command { /** * Flush rules * - * @param array $args - * @param array $assoc_args + * @param array $args not used + * @param array $assoc_args --soft or --hard (default) */ public function flush( $args, $assoc_args ) { $hard = ( isset( $assoc_args['soft'] ) ) ? false : true; @@ -86,16 +86,18 @@ public function structure( $args, $assoc_args ) { /** * Dump rewrite rules * - * @param none + * @param array $args + * @param array $assoc_args */ - public function dump() { + public function dump( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); - foreach ( $rules as $route => $rule ) - WP_CLI::line( $route . "\t" . $rule ); + if ( isset( $assoc_args['json'] ) ) + echo json_encode( $rules ); + else + foreach ( $rules as $route => $rule ) + WP_CLI::line( $route . "\t" . $rule ); } } - -?> From df849aa984f1667cd38b0934657bffe2e57343ba Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor <ntaintor@janrain.com> Date: Mon, 10 Sep 2012 09:19:14 -0700 Subject: [PATCH 0550/5359] Add man pages --- man/rewrite-dump.1 | 19 +++++++++++++++++++ man/rewrite-flush.1 | 19 +++++++++++++++++++ man/rewrite-structure.1 | 31 +++++++++++++++++++++++++++++++ src/docs/rewrite-dump.txt | 12 ++++++++++++ src/docs/rewrite-flush.txt | 14 ++++++++++++++ src/docs/rewrite-structure.txt | 21 +++++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 man/rewrite-dump.1 create mode 100644 man/rewrite-flush.1 create mode 100644 man/rewrite-structure.1 create mode 100644 src/docs/rewrite-dump.txt create mode 100644 src/docs/rewrite-flush.txt create mode 100644 src/docs/rewrite-structure.txt diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 new file mode 100644 index 000000000..fffedb924 --- /dev/null +++ b/man/rewrite-dump.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "REWRITE\-DUMP" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBrewrite\-dump\fR \- Print current rewrite rules to STDOUT\. +. +.SH "SYNOPSIS" +\fBwp rewrite dump\fR [\-\-json] +. +.SH "OPTIONS" +. +.TP +\fB\-\-json\fR: +. +.IP +Output rules in JSON format\. + diff --git a/man/rewrite-flush.1 b/man/rewrite-flush.1 new file mode 100644 index 000000000..02a631a4a --- /dev/null +++ b/man/rewrite-flush.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "REWRITE\-FLUSH" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBrewrite\-flush\fR \- Flush rewrite rules\. +. +.SH "SYNOPSIS" +\fBwp rewrite flush\fR [\-\-soft] +. +.SH "OPTIONS" +. +.TP +\fB\-\-soft\fR: +. +.IP +Perform a soft flush \- do not overwrite \fB\.htaccess\fR\. The default is to update \fB\.htaccess\fR rules as well as rewrite rules in database\. + diff --git a/man/rewrite-structure.1 b/man/rewrite-structure.1 new file mode 100644 index 000000000..833cd3e3a --- /dev/null +++ b/man/rewrite-structure.1 @@ -0,0 +1,31 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "REWRITE\-STRUCTURE" "1" "September 2012" "" "WP-CLI" +. +.SH "NAME" +\fBrewrite\-structure\fR \- Update the permalink structure +. +.SH "SYNOPSIS" +\fBwp rewrite structure\fR \fIpermastruct\fR [\-\-category\-base=\fIcategorybase\fR] [\-\-tag\-base=\fItagbase\fR] +. +.SH "OPTIONS" +. +.TP +\fIpermastruct\fR: +. +.IP +The new permalink structure to apply; like "/%year%/%monthnum%/%postname%"\. +. +.TP +\fB\-\-category\-base\fR=\fIcategorybase\fR: +. +.IP +Set the base for category permalinks, ie \'/category/\'\. +. +.TP +\fB\-\-tag\-base\fR=\fItagbase\fR: +. +.IP +Set the base for tag permalinks, ie \'/tag/\'\. + diff --git a/src/docs/rewrite-dump.txt b/src/docs/rewrite-dump.txt new file mode 100644 index 000000000..2a39b8527 --- /dev/null +++ b/src/docs/rewrite-dump.txt @@ -0,0 +1,12 @@ +rewrite-dump(1) -- Print current rewrite rules to STDOUT. +==== + +## SYNOPSIS + +`wp rewrite dump` [--json] + +## OPTIONS + +* `--json`: + + Output rules in JSON format. diff --git a/src/docs/rewrite-flush.txt b/src/docs/rewrite-flush.txt new file mode 100644 index 000000000..e7d11dd39 --- /dev/null +++ b/src/docs/rewrite-flush.txt @@ -0,0 +1,14 @@ +rewrite-flush(1) -- Flush rewrite rules. +==== + +## SYNOPSIS + +`wp rewrite flush` [--soft] + +## OPTIONS + +* `--soft`: + + Perform a soft flush - do not overwrite `.htaccess`. The default is to update + `.htaccess` rules as well as rewrite rules in database. + diff --git a/src/docs/rewrite-structure.txt b/src/docs/rewrite-structure.txt new file mode 100644 index 000000000..8e77ea39d --- /dev/null +++ b/src/docs/rewrite-structure.txt @@ -0,0 +1,21 @@ +rewrite-structure(1) -- Update the permalink structure +==== + +## SYNOPSIS + +`wp rewrite structure` <permastruct> [--category-base=<categorybase>] [--tag-base=<tagbase>] + +## OPTIONS + +* <permastruct>: + + The new permalink structure to apply; like "/%year%/%monthnum%/%postname%". + +* `--category-base`=<categorybase>: + + Set the base for category permalinks, ie '/category/'. + +* `--tag-base`=<tagbase>: + + Set the base for tag permalinks, ie '/tag/'. + From bafab795ffcbcc4799029b65cb09e41b09c87d63 Mon Sep 17 00:00:00 2001 From: Ben <benjamin.j.brooks@gmail.com> Date: Mon, 10 Sep 2012 12:03:13 -0700 Subject: [PATCH 0551/5359] Updated PHP path for MAMP 2.0.5 Updating the 'Special case for *AMP installers' to reflect that the current version of MAMP PRO stores the PHP executable in /Applications/MAMP/bin/php/php5.3*/bin/php --- src/bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index 1856f53e0..fa1037e4e 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -67,7 +67,7 @@ else fi # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do if [ -x $amp_php ]; then php=$amp_php break From 17f6c144c5507af3c70f4969e614f932b8ec835e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 15 Sep 2012 13:44:45 -0700 Subject: [PATCH 0552/5359] First pass at extending the 'delete' command to support deleting arbitrary sets of posts based on standard WP_Query arguments --- src/php/wp-cli/commands/internals/post.php | 50 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 97687b56c..490c07874 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -52,18 +52,58 @@ public function update( $args, $assoc_args ) { } /** - * Delete a post + * Delete a single post, or series of posts based on arguments * * @param array $args * @param array $assoc_args */ public function delete( $args, $assoc_args ) { - $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); - if ( wp_delete_post( $post_id, isset( $assoc_args['force'] ) ) ) { - WP_CLI::success( "Deleted post $post_id." ); + $defaults = array( + 'post_id' => null, + 'post_type' => null, + 'author' => null, + 'post_status' => 'any', + 'force' => false, + ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + + // Support for simply passing the post ID as the first argument + if ( isset( $args[0] ) && is_numeric( $args[0] ) ) + $post_id = $args[0]; + else if ( is_numeric( $assoc_args['post_id'] ) ) + $post_id = $assoc_args['post_id']; + else + $post_id = false; + + if ( $post_id ) { + $posts_to_delete = array( $post_id ); } else { - WP_CLI::error( "Failed deleting post $post_id." ); + $query_args = array( + 'fields' => 'ids', + 'posts_per_page' => -1, + 'post_type' => $assoc_args['post_type'], + 'author' => $assoc_args['author'], + 'post_status' => $assoc_args['post_status'], + ); + $maybe_posts = new WP_Query( $query_args ); + if ( ! is_wp_error( $maybe_posts ) ) + $posts_to_delete = $maybe_posts->posts; + else + $posts_to_delete = array(); + } + + if ( empty( $posts_to_delete ) ) { + WP_CLI::error( "No posts to delete." ); + } + + foreach( $posts_to_delete as $post_id ) { + if ( wp_delete_post( $post_id, (bool)$assoc_args['force'] ) ) { + $action = ( (bool) $assoc_args['force'] ) ? 'Deleted' : 'Trashed'; + WP_CLI::success( "{$action} post $post_id." ); + } else { + WP_CLI::error( "Failed deleting post $post_id." ); + } } } } From 7865cc0e98104932f5e0c85c8e882605a733b4e7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 15 Sep 2012 14:01:30 -0700 Subject: [PATCH 0553/5359] Use WP_Query's native 'p' parameter, instead of inventing our own. Props @scribu --- src/php/wp-cli/commands/internals/post.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 490c07874..ececdb6e8 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -60,7 +60,7 @@ public function update( $args, $assoc_args ) { public function delete( $args, $assoc_args ) { $defaults = array( - 'post_id' => null, + 'p' => null, 'post_type' => null, 'author' => null, 'post_status' => 'any', @@ -71,8 +71,8 @@ public function delete( $args, $assoc_args ) { // Support for simply passing the post ID as the first argument if ( isset( $args[0] ) && is_numeric( $args[0] ) ) $post_id = $args[0]; - else if ( is_numeric( $assoc_args['post_id'] ) ) - $post_id = $assoc_args['post_id']; + else if ( is_numeric( $assoc_args['p'] ) ) + $post_id = $assoc_args['p']; else $post_id = false; From ad025219f49b22cc9c7c96609b82193670e414f9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 15 Sep 2012 14:04:29 -0700 Subject: [PATCH 0554/5359] WP_Query shouldn't ever be a WP_Error object, so we don't need to check as such. Props @scribu --- src/php/wp-cli/commands/internals/post.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index ececdb6e8..7e0e1c9a5 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -87,10 +87,7 @@ public function delete( $args, $assoc_args ) { 'post_status' => $assoc_args['post_status'], ); $maybe_posts = new WP_Query( $query_args ); - if ( ! is_wp_error( $maybe_posts ) ) - $posts_to_delete = $maybe_posts->posts; - else - $posts_to_delete = array(); + $posts_to_delete = $maybe_posts->posts; } if ( empty( $posts_to_delete ) ) { From 682736c829ad0d87a8214931bd46cf5b8f625b5c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 15 Sep 2012 14:10:19 -0700 Subject: [PATCH 0555/5359] s/author/post_author/ --- src/php/wp-cli/commands/internals/post.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 7e0e1c9a5..06b80ded5 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -62,7 +62,7 @@ public function delete( $args, $assoc_args ) { $defaults = array( 'p' => null, 'post_type' => null, - 'author' => null, + 'post_author' => null, 'post_status' => 'any', 'force' => false, ); @@ -83,7 +83,7 @@ public function delete( $args, $assoc_args ) { 'fields' => 'ids', 'posts_per_page' => -1, 'post_type' => $assoc_args['post_type'], - 'author' => $assoc_args['author'], + 'post_author' => $assoc_args['post_author'], 'post_status' => $assoc_args['post_status'], ); $maybe_posts = new WP_Query( $query_args ); From 7640b7e47b72cebb332d495c392f5048273983d1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 15 Sep 2012 14:14:12 -0700 Subject: [PATCH 0556/5359] Update 'wp post delete' docs with information about new arguments --- src/doc/post-delete.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/doc/post-delete.txt b/src/doc/post-delete.txt index 97c07cc74..f2a017101 100644 --- a/src/doc/post-delete.txt +++ b/src/doc/post-delete.txt @@ -3,7 +3,7 @@ wp-post-delete(1) -- Delete a WordPress post. ## SYNOPSIS -`wp post delete` <ID> [--force] +`wp post delete` [<ID>] [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] ## OPTIONS @@ -11,6 +11,18 @@ wp-post-delete(1) -- Delete a WordPress post. The ID of the post to delete. +* `--post_type`: + + Trash or delete all posts of a given post type + +* `--post_author`: + + Trash or delete all posts written by a specific user + +* `--post_status`: + + Trash or delete all posts of a given post status + * `--force`: Skip the trash bin. @@ -18,3 +30,5 @@ wp-post-delete(1) -- Delete a WordPress post. ## EXAMPLES wp post delete 123 --force + + wp post delete --post_type=page --post_status=draft From 743e2616c7d3417564fe6e93b1276d3f49a2c8a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 15:58:47 +0300 Subject: [PATCH 0557/5359] split logic from presentation in plugin/theme get_status() --- src/php/wp-cli/commands/internals/plugin.php | 51 +++++++++++++++----- src/php/wp-cli/commands/internals/theme.php | 33 ++++++++++--- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 1fa343387..301ada39b 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -86,21 +86,46 @@ protected function status_all() { WP_CLI::legend( $legend ); } + private function _get_status( $file ) { + if ( isset( $this->mu_plugins[ $file ] ) ) + return 'must-use'; + + if ( is_plugin_active_for_network( $file ) ) + return 'active-network'; + + if ( is_plugin_active( $file ) ) + return 'active'; + + return 'inactive'; + } + private function get_status( $file, $long = false ) { - if ( isset( $this->mu_plugins[ $file ] ) ) { - $line = '%c'; - $line .= $long ? 'Must Use' : 'M'; - } elseif ( is_plugin_active_for_network( $file ) ) { - $line = '%b'; - $line .= $long ? 'Network Active' : 'N'; - } elseif ( is_plugin_active( $file ) ) { - $line = '%g'; - $line .= $long ? 'Active' : 'A'; - } else { - $line = $long ? 'Inactive' : 'I'; - } + $status = $this->_get_status( $file ); + + $colors = array( + 'inactive' => '', + 'active' => '%g', + 'active-network' => '%g', + 'must-use' => '%c', + ); + + $map_short = array( + 'inactive' => 'I', + 'active' => 'A', + 'active-network' => 'N', + 'must-use' => 'M', + ); + + $map_long = array( + 'inactive' => 'Inactive', + 'active' => 'Active', + 'active-network' => 'Must Use', + 'must-use' => 'Network Active', + ); + + $active_map = $long ? $map_long : $map_short; - return $line; + return $colors[ $status ] . $active_map[ $status ]; } /** diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index be09b205f..b57e00756 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -63,15 +63,34 @@ protected function status_all() { WP_CLI::legend( $legend ); } + private function _get_status( $stylesheet ) { + if ( $this->is_active_theme( $stylesheet ) ) + return 'active'; + + return 'inactive'; + } + private function get_status( $stylesheet, $long = false ) { - if ( $this->is_active_theme( $stylesheet ) ) { - $line = '%g'; - $line .= $long ? 'Active' : 'A'; - } else { - $line = $long ? 'Inactive' : 'I'; - } + $status = $this->_get_status( $stylesheet ); + + $colors = array( + 'inactive' => '', + 'active' => '%g', + ); + + $map_short = array( + 'inactive' => 'I', + 'active' => 'A', + ); + + $map_long = array( + 'inactive' => 'Inactive', + 'active' => 'Active', + ); + + $active_map = $long ? $map_long : $map_short; - return $line; + return $colors[ $status ] . $active_map[ $status ]; } /** From 419b587e2a035ef0686a0067820de9f6c0d99156 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 16:08:11 +0300 Subject: [PATCH 0558/5359] renamings: _get_status() -> get_status() -> format_status() --- src/php/wp-cli/commands/internals/plugin.php | 10 +++++----- src/php/wp-cli/commands/internals/theme.php | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 301ada39b..e2151a83c 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -28,7 +28,7 @@ function __construct( $args, $assoc_args ) { protected function status_single( $file, $name ) { $details = $this->get_details( $file ); - $status = $this->get_status( $file, true ); + $status = $this->format_status( $file, true ); $version = $details[ 'Version' ]; @@ -66,7 +66,7 @@ protected function status_all() { $line = ' '; } - $line .= $this->get_status( $file ) . " $name%n"; + $line .= $this->format_status( $file ) . " $name%n"; WP_CLI::line( $line ); } @@ -86,7 +86,7 @@ protected function status_all() { WP_CLI::legend( $legend ); } - private function _get_status( $file ) { + private function get_status( $file ) { if ( isset( $this->mu_plugins[ $file ] ) ) return 'must-use'; @@ -99,8 +99,8 @@ private function _get_status( $file ) { return 'inactive'; } - private function get_status( $file, $long = false ) { - $status = $this->_get_status( $file ); + private function format_status( $file, $long = false ) { + $status = $this->get_status( $file ); $colors = array( 'inactive' => '', diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index b57e00756..82564c9ee 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -19,7 +19,7 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { protected function status_single( $stylesheet, $name ) { $details = get_theme_data( $stylesheet ); - $status = $this->get_status( $stylesheet, true ); + $status = $this->format_status( $stylesheet, true ); $version = $details['Version']; @@ -47,7 +47,7 @@ protected function status_all() { $stylesheet = $this->get_stylesheet_path( $theme['Stylesheet'] ); - $line .= $this->get_status( $stylesheet ) . ' ' . $theme['Stylesheet'] . '%n'; + $line .= $this->format_status( $stylesheet ) . ' ' . $theme['Stylesheet'] . '%n'; WP_CLI::line( $line ); } @@ -63,15 +63,15 @@ protected function status_all() { WP_CLI::legend( $legend ); } - private function _get_status( $stylesheet ) { + private function get_status( $stylesheet ) { if ( $this->is_active_theme( $stylesheet ) ) return 'active'; return 'inactive'; } - private function get_status( $stylesheet, $long = false ) { - $status = $this->_get_status( $stylesheet ); + private function format_status( $stylesheet, $long = false ) { + $status = $this->get_status( $stylesheet ); $colors = array( 'inactive' => '', From 36fd51c70e62ab1cac6b8300a2e968dd7a0fdd90 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 16:11:27 +0300 Subject: [PATCH 0559/5359] move format_status() to parent class --- .../class-wp-cli-command-with-upgrade.php | 30 ++++++++++++++++++ src/php/wp-cli/commands/internals/plugin.php | 31 +------------------ src/php/wp-cli/commands/internals/theme.php | 25 +-------------- 3 files changed, 32 insertions(+), 54 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index ab13718dc..37ef1ed01 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -15,6 +15,7 @@ abstract protected function get_item_list(); abstract protected function status_all(); abstract protected function status_single( $file, $name ); + abstract protected function get_status( $file ); abstract protected function install_from_repo( $slug, $assoc_args ); @@ -150,4 +151,33 @@ protected function get_update_status( $slug ) { return isset( $update_list->response[ $slug ] ); } + + protected function format_status( $file, $long = false ) { + $status = $this->get_status( $file ); + + $colors = array( + 'inactive' => '', + 'active' => '%g', + 'active-network' => '%g', + 'must-use' => '%c', + ); + + $map_short = array( + 'inactive' => 'I', + 'active' => 'A', + 'active-network' => 'N', + 'must-use' => 'M', + ); + + $map_long = array( + 'inactive' => 'Inactive', + 'active' => 'Active', + 'active-network' => 'Must Use', + 'must-use' => 'Network Active', + ); + + $active_map = $long ? $map_long : $map_short; + + return $colors[ $status ] . $active_map[ $status ]; + } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index e2151a83c..ac7a40018 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -86,7 +86,7 @@ protected function status_all() { WP_CLI::legend( $legend ); } - private function get_status( $file ) { + protected function get_status( $file ) { if ( isset( $this->mu_plugins[ $file ] ) ) return 'must-use'; @@ -99,35 +99,6 @@ private function get_status( $file ) { return 'inactive'; } - private function format_status( $file, $long = false ) { - $status = $this->get_status( $file ); - - $colors = array( - 'inactive' => '', - 'active' => '%g', - 'active-network' => '%g', - 'must-use' => '%c', - ); - - $map_short = array( - 'inactive' => 'I', - 'active' => 'A', - 'active-network' => 'N', - 'must-use' => 'M', - ); - - $map_long = array( - 'inactive' => 'Inactive', - 'active' => 'Active', - 'active-network' => 'Must Use', - 'must-use' => 'Network Active', - ); - - $active_map = $long ? $map_long : $map_short; - - return $colors[ $status ] . $active_map[ $status ]; - } - /** * Activate a plugin * diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 82564c9ee..4565ee894 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -63,36 +63,13 @@ protected function status_all() { WP_CLI::legend( $legend ); } - private function get_status( $stylesheet ) { + protected function get_status( $stylesheet ) { if ( $this->is_active_theme( $stylesheet ) ) return 'active'; return 'inactive'; } - private function format_status( $stylesheet, $long = false ) { - $status = $this->get_status( $stylesheet ); - - $colors = array( - 'inactive' => '', - 'active' => '%g', - ); - - $map_short = array( - 'inactive' => 'I', - 'active' => 'A', - ); - - $map_long = array( - 'inactive' => 'Inactive', - 'active' => 'Active', - ); - - $active_map = $long ? $map_long : $map_short; - - return $colors[ $status ] . $active_map[ $status ]; - } - /** * Activate a theme * From 511489dc2d75bf0c1358f43f9eb6694cc862b4ce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 16:14:00 +0300 Subject: [PATCH 0560/5359] convert boolean $long parameter to $format --- .../class-wp-cli-command-with-upgrade.php | 35 +++++++++---------- src/php/wp-cli/commands/internals/plugin.php | 4 +-- src/php/wp-cli/commands/internals/theme.php | 4 +-- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 37ef1ed01..1b5a6ce8d 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -152,7 +152,22 @@ protected function get_update_status( $slug ) { return isset( $update_list->response[ $slug ] ); } - protected function format_status( $file, $long = false ) { + protected function format_status( $file, $format ) { + static $map = array( + 'short' => array( + 'inactive' => 'I', + 'active' => 'A', + 'active-network' => 'N', + 'must-use' => 'M', + ), + 'long' => array( + 'inactive' => 'Inactive', + 'active' => 'Active', + 'active-network' => 'Must Use', + 'must-use' => 'Network Active', + ) + ); + $status = $this->get_status( $file ); $colors = array( @@ -162,22 +177,6 @@ protected function format_status( $file, $long = false ) { 'must-use' => '%c', ); - $map_short = array( - 'inactive' => 'I', - 'active' => 'A', - 'active-network' => 'N', - 'must-use' => 'M', - ); - - $map_long = array( - 'inactive' => 'Inactive', - 'active' => 'Active', - 'active-network' => 'Must Use', - 'must-use' => 'Network Active', - ); - - $active_map = $long ? $map_long : $map_short; - - return $colors[ $status ] . $active_map[ $status ]; + return $colors[ $status ] . $map[ $format ][ $status ]; } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index ac7a40018..acb9d0cce 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -28,7 +28,7 @@ function __construct( $args, $assoc_args ) { protected function status_single( $file, $name ) { $details = $this->get_details( $file ); - $status = $this->format_status( $file, true ); + $status = $this->format_status( $file, 'long' ); $version = $details[ 'Version' ]; @@ -66,7 +66,7 @@ protected function status_all() { $line = ' '; } - $line .= $this->format_status( $file ) . " $name%n"; + $line .= $this->format_status( $file, 'short' ) . " $name%n"; WP_CLI::line( $line ); } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 4565ee894..ab2cc6592 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -19,7 +19,7 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { protected function status_single( $stylesheet, $name ) { $details = get_theme_data( $stylesheet ); - $status = $this->format_status( $stylesheet, true ); + $status = $this->format_status( $stylesheet, 'long' ); $version = $details['Version']; @@ -47,7 +47,7 @@ protected function status_all() { $stylesheet = $this->get_stylesheet_path( $theme['Stylesheet'] ); - $line .= $this->format_status( $stylesheet ) . ' ' . $theme['Stylesheet'] . '%n'; + $line .= $this->format_status( $stylesheet, 'short' ) . ' ' . $theme['Stylesheet'] . '%n'; WP_CLI::line( $line ); } From 3d1ee2a818df9e6c71593cf11c7e22d5478ee961 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 16:17:45 +0300 Subject: [PATCH 0561/5359] make get_details() method required --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 3 ++- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 1b5a6ce8d..6360f3660 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -12,10 +12,11 @@ abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { abstract protected function parse_name( $args, $subcommand ); abstract protected function get_item_list(); + abstract protected function get_status( $file ); + abstract protected function get_details( $file ); abstract protected function status_all(); abstract protected function status_single( $file, $name ); - abstract protected function get_status( $file ); abstract protected function install_from_repo( $slug, $assoc_args ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index acb9d0cce..6727ea8ea 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -299,7 +299,7 @@ function delete( $args, $assoc_args = array(), $exit_on_error = true ) { * @param string $file * @return array */ - private function get_details( $file ) { + protected function get_details( $file ) { $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); $plugin_file = basename( ( $file ) ); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index ab2cc6592..0b0d7e2be 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -17,7 +17,7 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { // Show details about a single theme protected function status_single( $stylesheet, $name ) { - $details = get_theme_data( $stylesheet ); + $details = $this->get_details( $stylesheet ); $status = $this->format_status( $stylesheet, 'long' ); @@ -33,6 +33,10 @@ protected function status_single( $stylesheet, $name ) { WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } + protected function get_details( $stylesheet ) { + return get_theme_data( $stylesheet ); + } + // Show details about all themes protected function status_all() { // Print the header From 1ec922f71fbe650703e398cb404ff89732078b8d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 17:42:58 +0300 Subject: [PATCH 0562/5359] move common code from status_single() into parent class --- .../wp-cli/class-wp-cli-command-with-upgrade.php | 15 ++++++++++++++- src/php/wp-cli/commands/internals/plugin.php | 12 +----------- src/php/wp-cli/commands/internals/theme.php | 12 +----------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 6360f3660..133731548 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -16,7 +16,7 @@ abstract protected function get_status( $file ); abstract protected function get_details( $file ); abstract protected function status_all(); - abstract protected function status_single( $file, $name ); + abstract protected function _status_single( $details, $name, $version, $status ); abstract protected function install_from_repo( $slug, $assoc_args ); @@ -38,6 +38,19 @@ function status( $args = array() ) { } } + protected function status_single( $file, $name ) { + $details = $this->get_details( $file ); + + $status = $this->format_status( $file, 'long' ); + + $version = $details[ 'Version' ]; + + if ( $this->get_update_status( $file ) ) + $version .= ' (%gUpdate available%n)'; + + $this->_status_single( $details, $name, $version, $status ); + } + /** * Install a new plugin/theme * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 6727ea8ea..98e59feb4 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -24,17 +24,7 @@ function __construct( $args, $assoc_args ) { parent::__construct( $args, $assoc_args ); } - // Show details about a single plugin - protected function status_single( $file, $name ) { - $details = $this->get_details( $file ); - - $status = $this->format_status( $file, 'long' ); - - $version = $details[ 'Version' ]; - - if ( $this->get_update_status( $file ) ) - $version .= ' (%gUpdate available%n)'; - + protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); WP_CLI::line( ' Status: ' . $status .'%n' ); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 0b0d7e2be..561217751 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -15,17 +15,7 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; - // Show details about a single theme - protected function status_single( $stylesheet, $name ) { - $details = $this->get_details( $stylesheet ); - - $status = $this->format_status( $stylesheet, 'long' ); - - $version = $details['Version']; - - if ( $this->get_update_status( $name ) ) - $version .= ' (%gUpdate available%n)'; - + protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( 'Theme %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); WP_CLI::line( ' Status: ' . $status .'%n' ); From b7ae1397d56b5a8fb57e335740e2ee77789d9e58 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 17:46:52 +0300 Subject: [PATCH 0563/5359] move legend() to WP_CLI_Command_With_Upgrade --- .../wp-cli/class-wp-cli-command-with-upgrade.php | 15 +++++++++++++++ src/php/wp-cli/class-wp-cli.php | 15 --------------- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 133731548..71e49d91c 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -51,6 +51,21 @@ protected function status_single( $file, $name ) { $this->_status_single( $details, $name, $version, $status ); } + /** + * Display a legend + * + * @param array( code => title ) $legend + */ + protected static function legend( $legend ) { + $legend[ '%yU' ] = 'Update Available'; + + $legend_line = array(); + foreach ( $legend as $key => $title ) + $legend_line[] = "$key = $title%n"; + + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + } + /** * Install a new plugin/theme * diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 7a1b2d4e4..967e3a143 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -202,21 +202,6 @@ static function get_numeric_arg( $args, $index, $name ) { return $args[$index]; } - /** - * Display a legend - * - * @param array( code => title ) $legend - */ - static function legend( $legend ) { - $legend[ '%yU' ] = 'Update Available'; - - $legend_line = array(); - foreach ( $legend as $key => $title ) - $legend_line[] = "$key = $title%n"; - - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); - } - /** * Launch an external process, closing the current one * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 98e59feb4..083a6200d 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -73,7 +73,7 @@ protected function status_all() { if ( is_multisite() ) $legend['%bN'] = 'Network Active'; - WP_CLI::legend( $legend ); + self::legend( $legend ); } protected function get_status( $file ) { diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 561217751..b456ad86a 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -54,7 +54,7 @@ protected function status_all() { '%gA' => 'Active', ); - WP_CLI::legend( $legend ); + self::legend( $legend ); } protected function get_status( $stylesheet ) { From 63e6d0fc84ee3448ffb4f41a0f69f16563984b48 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 17:50:52 +0300 Subject: [PATCH 0564/5359] move colors array to function --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 71e49d91c..8d12056fb 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -199,13 +199,17 @@ protected function format_status( $file, $format ) { $status = $this->get_status( $file ); - $colors = array( + return $this->get_color( $status ) . $map[ $format ][ $status ]; + } + + protected function get_color( $status ) { + static $colors = array( 'inactive' => '', 'active' => '%g', 'active-network' => '%g', 'must-use' => '%c', ); - return $colors[ $status ] . $map[ $format ][ $status ]; + return $colors[ $status ]; } } From 2341d80366ec8b172de26442c3d9fe33df450483 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:36:19 +0300 Subject: [PATCH 0565/5359] move get_status() call out of format_status() --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 6 ++---- src/php/wp-cli/commands/internals/plugin.php | 4 +++- src/php/wp-cli/commands/internals/theme.php | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 8d12056fb..c0f281d78 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -41,7 +41,7 @@ function status( $args = array() ) { protected function status_single( $file, $name ) { $details = $this->get_details( $file ); - $status = $this->format_status( $file, 'long' ); + $status = $this->format_status( $this->get_status( $file ), 'long' ); $version = $details[ 'Version' ]; @@ -181,7 +181,7 @@ protected function get_update_status( $slug ) { return isset( $update_list->response[ $slug ] ); } - protected function format_status( $file, $format ) { + protected function format_status( $status, $format ) { static $map = array( 'short' => array( 'inactive' => 'I', @@ -197,8 +197,6 @@ protected function format_status( $file, $format ) { ) ); - $status = $this->get_status( $file ); - return $this->get_color( $status ) . $map[ $format ][ $status ]; } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 083a6200d..59a69ab71 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -56,7 +56,9 @@ protected function status_all() { $line = ' '; } - $line .= $this->format_status( $file, 'short' ) . " $name%n"; + $status = $this->get_status( $file ); + + $line .= $this->format_status( $status, 'short' ) . " $name%n"; WP_CLI::line( $line ); } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index b456ad86a..35177be96 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -41,7 +41,9 @@ protected function status_all() { $stylesheet = $this->get_stylesheet_path( $theme['Stylesheet'] ); - $line .= $this->format_status( $stylesheet, 'short' ) . ' ' . $theme['Stylesheet'] . '%n'; + $status = $this->get_status( $stylesheet ); + + $line .= $this->format_status( $status, 'short' ) . ' ' . $theme['Stylesheet'] . '%n'; WP_CLI::line( $line ); } From 1fa143b9bc0a33c72b87ae3230ca7e68b6829ca7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:39:26 +0300 Subject: [PATCH 0566/5359] move some methods around --- src/php/wp-cli/commands/internals/plugin.php | 26 ++++++++++---------- src/php/wp-cli/commands/internals/theme.php | 8 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 59a69ab71..b043da055 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -78,19 +78,6 @@ protected function status_all() { self::legend( $legend ); } - protected function get_status( $file ) { - if ( isset( $this->mu_plugins[ $file ] ) ) - return 'must-use'; - - if ( is_plugin_active_for_network( $file ) ) - return 'active-network'; - - if ( is_plugin_active( $file ) ) - return 'active'; - - return 'inactive'; - } - /** * Activate a plugin * @@ -285,6 +272,19 @@ function delete( $args, $assoc_args = array(), $exit_on_error = true ) { /* PRIVATES */ + protected function get_status( $file ) { + if ( isset( $this->mu_plugins[ $file ] ) ) + return 'must-use'; + + if ( is_plugin_active_for_network( $file ) ) + return 'active-network'; + + if ( is_plugin_active( $file ) ) + return 'active'; + + return 'inactive'; + } + /** * Get the details of a plugin * diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 35177be96..03c8c2410 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -23,10 +23,6 @@ protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } - protected function get_details( $stylesheet ) { - return get_theme_data( $stylesheet ); - } - // Show details about all themes protected function status_all() { // Print the header @@ -66,6 +62,10 @@ protected function get_status( $stylesheet ) { return 'inactive'; } + protected function get_details( $stylesheet ) { + return get_theme_data( $stylesheet ); + } + /** * Activate a theme * From 218d104473de27003ab09f6105dbc8ee0e30db21 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:42:09 +0300 Subject: [PATCH 0567/5359] use get_status() in check_active() --- src/php/wp-cli/commands/internals/plugin.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index b043da055..4e9646d92 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -117,13 +117,9 @@ function deactivate( $args, $assoc_args = array() ) { } private function check_active( $file, $network_wide ) { - if ( $network_wide ) { - $check = is_plugin_active_for_network( $file ); - } else { - $check = is_plugin_active( $file ); - } + $required = $network_wide ? 'active-network' : 'active'; - return $check; + return $required == $this->get_status( $file ); } /** From ab70c913ab1583499dd184f7ceb3d43bdf11d1dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:44:02 +0300 Subject: [PATCH 0568/5359] move check_active lower --- src/php/wp-cli/commands/internals/plugin.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 4e9646d92..34723c0e5 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -116,12 +116,6 @@ function deactivate( $args, $assoc_args = array() ) { } } - private function check_active( $file, $network_wide ) { - $required = $network_wide ? 'active-network' : 'active'; - - return $required == $this->get_status( $file ); - } - /** * Toggle a plugin's activation state * @@ -268,6 +262,12 @@ function delete( $args, $assoc_args = array(), $exit_on_error = true ) { /* PRIVATES */ + private function check_active( $file, $network_wide ) { + $required = $network_wide ? 'active-network' : 'active'; + + return $required == $this->get_status( $file ); + } + protected function get_status( $file ) { if ( isset( $this->mu_plugins[ $file ] ) ) return 'must-use'; From 6f0526047c9a15a3ae041a4bea646b73c4a7c0dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:48:31 +0300 Subject: [PATCH 0569/5359] introduce get_name() helper for plugin status_all() --- src/php/wp-cli/commands/internals/plugin.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 34723c0e5..225ec55ce 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -44,12 +44,7 @@ protected function status_all() { // Print the header WP_CLI::line('Installed plugins:'); - foreach ($plugins as $file => $plugin) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace('.php', '', basename($file)); - else - $name = dirname($file); - + foreach ( $plugins as $file => $plugin ) { if ( $this->get_update_status( $file ) ) { $line = ' %yU%n'; } else { @@ -58,7 +53,8 @@ protected function status_all() { $status = $this->get_status( $file ); - $line .= $this->format_status( $status, 'short' ) . " $name%n"; + $line .= $this->format_status( $status, 'short' ); + $line .= " " . $this->get_name( $file ) . "%n"; WP_CLI::line( $line ); } @@ -78,6 +74,15 @@ protected function status_all() { self::legend( $legend ); } + private function get_name( $file ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace( '.php', '', basename( $file ) ); + else + $name = dirname( $file ); + + return $name; + } + /** * Activate a plugin * From 23d89cd1109e607c83577b7ab26b18508f1d9e55 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 18:50:24 +0300 Subject: [PATCH 0570/5359] rename get_update_status() to has_update() --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 6 +++--- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index c0f281d78..b18c7af1f 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -45,7 +45,7 @@ protected function status_single( $file, $name ) { $version = $details[ 'Version' ]; - if ( $this->get_update_status( $file ) ) + if ( $this->has_update( $file ) ) $version .= ' (%gUpdate available%n)'; $this->_status_single( $details, $name, $version, $status ); @@ -125,7 +125,7 @@ private function update_multiple( $args, $assoc_args ) { $item_list = "Available {$this->item_type} updates:"; $items_to_update = array(); foreach ( $this->get_item_list() as $file ) { - if ( $this->get_update_status( $file ) ) { + if ( $this->has_update( $file ) ) { $items_to_update[] = $file; if ( empty( $assoc_args ) ) { @@ -175,7 +175,7 @@ private function update_multiple( $args, $assoc_args ) { * * @return bool */ - protected function get_update_status( $slug ) { + protected function has_update( $slug ) { $update_list = get_site_transient( $this->upgrade_transient ); return isset( $update_list->response[ $slug ] ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 225ec55ce..700278612 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -45,7 +45,7 @@ protected function status_all() { WP_CLI::line('Installed plugins:'); foreach ( $plugins as $file => $plugin ) { - if ( $this->get_update_status( $file ) ) { + if ( $this->has_update( $file ) ) { $line = ' %yU%n'; } else { $line = ' '; diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 03c8c2410..5455ead13 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -29,7 +29,7 @@ protected function status_all() { WP_CLI::line( 'Installed themes:' ); foreach ( get_themes() as $key => $theme ) { - if ( $this->get_update_status( $theme['Stylesheet'] ) ) { + if ( $this->has_update( $theme['Stylesheet'] ) ) { $line = ' %yU%n'; } else { $line = ' '; @@ -132,7 +132,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } // Check to see if we should update, rather than install. - if ( $this->get_update_status( $slug ) ) { + if ( $this->has_update( $slug ) ) { WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $slug ); From 6701c6eb407155de71eefcc9f54ee744153361c5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 22:18:18 +0300 Subject: [PATCH 0571/5359] generate legend array from existing data --- .../class-wp-cli-command-with-upgrade.php | 63 ++++++++++--------- src/php/wp-cli/commands/internals/plugin.php | 11 +--- src/php/wp-cli/commands/internals/theme.php | 7 +-- 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index b18c7af1f..02998a5f4 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -51,21 +51,6 @@ protected function status_single( $file, $name ) { $this->_status_single( $details, $name, $version, $status ); } - /** - * Display a legend - * - * @param array( code => title ) $legend - */ - protected static function legend( $legend ) { - $legend[ '%yU' ] = 'Update Available'; - - $legend_line = array(); - foreach ( $legend as $key => $title ) - $legend_line[] = "$key = $title%n"; - - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); - } - /** * Install a new plugin/theme * @@ -181,23 +166,41 @@ protected function has_update( $slug ) { return isset( $update_list->response[ $slug ] ); } + protected $map = array( + 'short' => array( + 'inactive' => 'I', + 'active' => 'A', + 'active-network' => 'N', + 'must-use' => 'M', + ), + 'long' => array( + 'inactive' => 'Inactive', + 'active' => 'Active', + 'active-network' => 'Must Use', + 'must-use' => 'Network Active', + ) + ); + protected function format_status( $status, $format ) { - static $map = array( - 'short' => array( - 'inactive' => 'I', - 'active' => 'A', - 'active-network' => 'N', - 'must-use' => 'M', - ), - 'long' => array( - 'inactive' => 'Inactive', - 'active' => 'Active', - 'active-network' => 'Must Use', - 'must-use' => 'Network Active', - ) - ); + return $this->get_color( $status ) . $this->map[ $format ][ $status ]; + } + + protected function show_legend() { + $legend = array(); + + // TODO: show only the values that were used + foreach ( $this->map['short'] as $status => $short ) { + $key = $this->format_status( $status, 'short' ); + $legend[ $key ] = $this->map['long'][ $status ]; + } + + $legend[ '%yU' ] = 'Update Available'; + + $legend_line = array(); + foreach ( $legend as $key => $title ) + $legend_line[] = "$key = $title%n"; - return $this->get_color( $status ) . $map[ $format ][ $status ]; + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } protected function get_color( $status ) { diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 700278612..d07e0cb19 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -62,16 +62,7 @@ protected function status_all() { // Print the footer WP_CLI::line(); - $legend = array( - 'I' => 'Inactive', - '%gA' => 'Active', - '%cM' => 'Must Use', - ); - - if ( is_multisite() ) - $legend['%bN'] = 'Network Active'; - - self::legend( $legend ); + $this->show_legend(); } private function get_name( $file ) { diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 5455ead13..5a07908af 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -47,12 +47,7 @@ protected function status_all() { // Print the footer WP_CLI::line(); - $legend = array( - 'I' => 'Inactive', - '%gA' => 'Active', - ); - - self::legend( $legend ); + $this->show_legend(); } protected function get_status( $stylesheet ) { From 77d56fce308fa7bf19db7dfda980bb5de6a55bb6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 22:25:31 +0300 Subject: [PATCH 0572/5359] move get_name() to parent class --- .../wp-cli/class-wp-cli-command-with-upgrade.php | 16 ++++++++++------ src/php/wp-cli/commands/internals/plugin.php | 9 --------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 02998a5f4..a55d3a12d 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -114,12 +114,7 @@ private function update_multiple( $args, $assoc_args ) { $items_to_update[] = $file; if ( empty( $assoc_args ) ) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace('.php', '', basename($file)); - else - $name = dirname($file); - - $item_list .= "\n\t%y$name%n"; + $item_list .= "\n\t%y" . $this->get_name( $file ) . "%n"; } } } @@ -153,6 +148,15 @@ private function update_multiple( $args, $assoc_args ) { } } + protected function get_name( $file ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace( '.php', '', basename( $file ) ); + else + $name = dirname( $file ); + + return $name; + } + /** * Check whether an item has an update available or not. * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d07e0cb19..8e09d9989 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -65,15 +65,6 @@ protected function status_all() { $this->show_legend(); } - private function get_name( $file ) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace( '.php', '', basename( $file ) ); - else - $name = dirname( $file ); - - return $name; - } - /** * Activate a plugin * From 9aa9fffbc4d4ed008a245c10f923051d9994098c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 22:38:12 +0300 Subject: [PATCH 0573/5359] beef up get_item_list() and refactor update_multiple() --- .../class-wp-cli-command-with-upgrade.php | 22 ++++++++----------- src/php/wp-cli/commands/internals/plugin.php | 11 +++++++++- src/php/wp-cli/commands/internals/theme.php | 13 ++++++++++- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index a55d3a12d..9d66cf491 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -105,19 +105,9 @@ function update( $args, $assoc_args ) { } private function update_multiple( $args, $assoc_args ) { - // Grab all items that need updates - // If we have no sub-arguments, add them to the output list. - $item_list = "Available {$this->item_type} updates:"; - $items_to_update = array(); - foreach ( $this->get_item_list() as $file ) { - if ( $this->has_update( $file ) ) { - $items_to_update[] = $file; - - if ( empty( $assoc_args ) ) { - $item_list .= "\n\t%y" . $this->get_name( $file ) . "%n"; - } - } - } + $items_to_update = wp_list_filter( $this->get_item_list(), array( + 'update' => true + ) ); if ( empty( $items_to_update ) ) { WP_CLI::line( "No {$this->item_type} updates available." ); @@ -144,6 +134,12 @@ private function update_multiple( $args, $assoc_args ) { // Else list items that require updates } else { + $item_list = "Available {$this->item_type} updates:"; + + foreach ( $items_to_update as $file => $details ) { + $item_list .= "\n\t%y" . $this->get_name( $file ) . "%n"; + } + WP_CLI::line( $item_list ); } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 8e09d9989..0b84526e2 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -209,7 +209,16 @@ function update( $args, $assoc_args ) { } protected function get_item_list() { - return array_keys( get_plugins() ); + $items = array(); + + foreach ( get_plugins() as $file => $details ) { + $items[ $file ] = array( + 'status' => $this->get_status( $file ), + 'update' => $this->has_update( $file ), + ); + } + + return $items; } /** diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 5a07908af..ab17467a9 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -150,7 +150,18 @@ protected function install_from_repo( $slug, $assoc_args ) { } protected function get_item_list() { - return wp_list_pluck( get_themes(), 'Stylesheet' ); + $items = array(); + + foreach ( get_themes() as $title => $details ) { + $file = $details['Stylesheet']; + + $items[ $file ] = array( + 'status' => $this->get_status( $file ), + 'update' => $this->has_update( $file ), + ); + } + + return $items; } /** From 3f05a88a6382fed0b15fb270841c3e90b57f4359 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 22:49:18 +0300 Subject: [PATCH 0574/5359] use get_item_list() in status_all() --- src/php/wp-cli/commands/internals/plugin.php | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 0b84526e2..0430ad2ea 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -15,8 +15,6 @@ class Plugin_Command extends WP_CLI_Command_With_Upgrade { protected $upgrade_refresh = 'wp_update_plugins'; protected $upgrade_transient = 'update_plugins'; - private $mu_plugins; - function __construct( $args, $assoc_args ) { require_once ABSPATH.'wp-admin/includes/plugin.php'; require_once ABSPATH.'wp-admin/includes/plugin-install.php'; @@ -35,25 +33,26 @@ protected function _status_single( $details, $name, $version, $status ) { // Show details about all plugins protected function status_all() { - $this->mu_plugins = get_mu_plugins(); - - $plugins = get_plugins(); + $items = $this->get_item_list(); - $plugins = array_merge( $plugins, $this->mu_plugins ); + foreach ( get_mu_plugins() as $mu_plugin ) { + $items[ $mu_plugin ] = array( + 'status' => 'must-use', + 'update' => false + ); + } // Print the header WP_CLI::line('Installed plugins:'); - foreach ( $plugins as $file => $plugin ) { - if ( $this->has_update( $file ) ) { + foreach ( $items as $file => $details ) { + if ( $details['update'] ) { $line = ' %yU%n'; } else { $line = ' '; } - $status = $this->get_status( $file ); - - $line .= $this->format_status( $status, 'short' ); + $line .= $this->format_status( $details['status'], 'short' ); $line .= " " . $this->get_name( $file ) . "%n"; WP_CLI::line( $line ); @@ -265,9 +264,6 @@ private function check_active( $file, $network_wide ) { } protected function get_status( $file ) { - if ( isset( $this->mu_plugins[ $file ] ) ) - return 'must-use'; - if ( is_plugin_active_for_network( $file ) ) return 'active-network'; From c09b68070c367e6d0d62f1ba538e25eb9cb9c89d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 22:55:05 +0300 Subject: [PATCH 0575/5359] move get_name() back to plugin.php, where it belongs --- .../class-wp-cli-command-with-upgrade.php | 11 +---------- src/php/wp-cli/commands/internals/plugin.php | 17 ++++++++++++++--- src/php/wp-cli/commands/internals/theme.php | 1 + 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 9d66cf491..d3bd22ea7 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -137,22 +137,13 @@ private function update_multiple( $args, $assoc_args ) { $item_list = "Available {$this->item_type} updates:"; foreach ( $items_to_update as $file => $details ) { - $item_list .= "\n\t%y" . $this->get_name( $file ) . "%n"; + $item_list .= "\n\t%y" . $details['name'] . "%n"; } WP_CLI::line( $item_list ); } } - protected function get_name( $file ) { - if ( false === strpos( $file, '/' ) ) - $name = str_replace( '.php', '', basename( $file ) ); - else - $name = dirname( $file ); - - return $name; - } - /** * Check whether an item has an update available or not. * diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 0430ad2ea..a5c7135d3 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -35,8 +35,9 @@ protected function _status_single( $details, $name, $version, $status ) { protected function status_all() { $items = $this->get_item_list(); - foreach ( get_mu_plugins() as $mu_plugin ) { - $items[ $mu_plugin ] = array( + foreach ( get_mu_plugins() as $file => $mu_plugin ) { + $items[ $file ] = array( + 'name' => $this->get_name( $file ), 'status' => 'must-use', 'update' => false ); @@ -53,7 +54,7 @@ protected function status_all() { } $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . $this->get_name( $file ) . "%n"; + $line .= " " . $details['name'] . "%n"; WP_CLI::line( $line ); } @@ -212,6 +213,7 @@ protected function get_item_list() { foreach ( get_plugins() as $file => $details ) { $items[ $file ] = array( + 'name' => $this->get_name( $file ), 'status' => $this->get_status( $file ), 'update' => $this->has_update( $file ), ); @@ -320,4 +322,13 @@ protected function parse_name( $args, $subcommand ) { return array( $file, $name ); } + + private function get_name( $file ) { + if ( false === strpos( $file, '/' ) ) + $name = str_replace( '.php', '', basename( $file ) ); + else + $name = dirname( $file ); + + return $name; + } } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index ab17467a9..661d043c6 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -156,6 +156,7 @@ protected function get_item_list() { $file = $details['Stylesheet']; $items[ $file ] = array( + 'name' => $details['Stylesheet'], 'status' => $this->get_status( $file ), 'update' => $this->has_update( $file ), ); From d3d49c8cd407a4c748d7a94860d464c82bc878b1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 23:01:53 +0300 Subject: [PATCH 0576/5359] extract common print_status_all() method --- .../class-wp-cli-command-with-upgrade.php | 19 +++++++++++++ src/php/wp-cli/commands/internals/plugin.php | 22 ++------------- src/php/wp-cli/commands/internals/theme.php | 27 +++---------------- 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index d3bd22ea7..fa911d927 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -38,6 +38,25 @@ function status( $args = array() ) { } } + protected function print_status_all( $items ) { + foreach ( $items as $file => $details ) { + if ( $details['update'] ) { + $line = ' %yU%n'; + } else { + $line = ' '; + } + + $line .= $this->format_status( $details['status'], 'short' ); + $line .= " " . $details['name'] . "%n"; + + WP_CLI::line( $line ); + } + + WP_CLI::line(); + + $this->show_legend(); + } + protected function status_single( $file, $name ) { $details = $this->get_details( $file ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index a5c7135d3..8678312ad 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -31,7 +31,6 @@ protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); } - // Show details about all plugins protected function status_all() { $items = $this->get_item_list(); @@ -43,26 +42,9 @@ protected function status_all() { ); } - // Print the header - WP_CLI::line('Installed plugins:'); + WP_CLI::line( 'Installed plugins:' ); - foreach ( $items as $file => $details ) { - if ( $details['update'] ) { - $line = ' %yU%n'; - } else { - $line = ' '; - } - - $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . $details['name'] . "%n"; - - WP_CLI::line( $line ); - } - - // Print the footer - WP_CLI::line(); - - $this->show_legend(); + $this->print_status_all( $items ); } /** diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 661d043c6..faa724679 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -23,31 +23,10 @@ protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } - // Show details about all themes protected function status_all() { - // Print the header WP_CLI::line( 'Installed themes:' ); - foreach ( get_themes() as $key => $theme ) { - if ( $this->has_update( $theme['Stylesheet'] ) ) { - $line = ' %yU%n'; - } else { - $line = ' '; - } - - $stylesheet = $this->get_stylesheet_path( $theme['Stylesheet'] ); - - $status = $this->get_status( $stylesheet ); - - $line .= $this->format_status( $status, 'short' ) . ' ' . $theme['Stylesheet'] . '%n'; - - WP_CLI::line( $line ); - } - - // Print the footer - WP_CLI::line(); - - $this->show_legend(); + $this->print_status_all( $this->get_item_list() ); } protected function get_status( $stylesheet ) { @@ -153,12 +132,12 @@ protected function get_item_list() { $items = array(); foreach ( get_themes() as $title => $details ) { - $file = $details['Stylesheet']; + $file = $this->get_stylesheet_path( $details['Stylesheet'] ); $items[ $file ] = array( 'name' => $details['Stylesheet'], 'status' => $this->get_status( $file ), - 'update' => $this->has_update( $file ), + 'update' => $this->has_update( $details['Stylesheet'] ), ); } From e9b318df6baf7393b50038e44b3b2c4ae095af25 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 23:12:25 +0300 Subject: [PATCH 0577/5359] fix inverted descriptions --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index fa911d927..884573569 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -186,8 +186,8 @@ protected function has_update( $slug ) { 'long' => array( 'inactive' => 'Inactive', 'active' => 'Active', - 'active-network' => 'Must Use', - 'must-use' => 'Network Active', + 'active-network' => 'Network Active', + 'must-use' => 'Must Use', ) ); From 64dddc8cadebbbc10d41ad7aa4e59318eb4326e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 23:15:39 +0300 Subject: [PATCH 0578/5359] show only relevant legend items --- .../class-wp-cli-command-with-upgrade.php | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 884573569..4158907b6 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -54,7 +54,26 @@ protected function print_status_all( $items ) { WP_CLI::line(); - $this->show_legend(); + $this->show_legend( $items ); + } + + protected function show_legend( $items ) { + $statuses = array_unique( wp_list_pluck( $items, 'status' ) ); + + $legend_line = array(); + + foreach ( $statuses as $status ) { + $legend_line[] = sprintf( '%s%s = %s%%n', + $this->get_color( $status ), + $this->map['short'][ $status ], + $this->map['long'][ $status ] + ); + } + + if ( in_array( true, wp_list_pluck( $items, 'update' ) ) ) + $legend_line[] = '%yU = Update Available%n'; + + WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } protected function status_single( $file, $name ) { @@ -195,24 +214,6 @@ protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } - protected function show_legend() { - $legend = array(); - - // TODO: show only the values that were used - foreach ( $this->map['short'] as $status => $short ) { - $key = $this->format_status( $status, 'short' ); - $legend[ $key ] = $this->map['long'][ $status ]; - } - - $legend[ '%yU' ] = 'Update Available'; - - $legend_line = array(); - foreach ( $legend as $key => $title ) - $legend_line[] = "$key = $title%n"; - - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); - } - protected function get_color( $status ) { static $colors = array( 'inactive' => '', From 073ffdd848bdf9b7fb8337efd55562789c3cb9a6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 23:25:34 +0300 Subject: [PATCH 0579/5359] fix bulk upgrade --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 2 +- src/php/wp-cli/commands/internals/plugin.php | 1 + src/php/wp-cli/commands/internals/theme.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 4158907b6..6193a7577 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -155,7 +155,7 @@ private function update_multiple( $args, $assoc_args ) { // If --all, UPDATE ALL THE THINGS if ( isset( $assoc_args['all'] ) ) { $upgrader = WP_CLI::get_upgrader( $this->upgrader ); - $result = $upgrader->bulk_upgrade( $items_to_update ); + $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); // Let the user know the results. $num_to_update = count( $items_to_update ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 8678312ad..7c663bbd5 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -198,6 +198,7 @@ protected function get_item_list() { 'name' => $this->get_name( $file ), 'status' => $this->get_status( $file ), 'update' => $this->has_update( $file ), + 'update_id' => $file, ); } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index faa724679..4c90915e3 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -138,6 +138,7 @@ protected function get_item_list() { 'name' => $details['Stylesheet'], 'status' => $this->get_status( $file ), 'update' => $this->has_update( $details['Stylesheet'] ), + 'update_id' => $details['Stylesheet'], ); } From 5912c918d5f6d515e8b3e0a5b6d9bcf709b94c0f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Sep 2012 23:30:57 +0300 Subject: [PATCH 0580/5359] mark some things as private --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 6193a7577..d6fa809c9 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -57,7 +57,7 @@ protected function print_status_all( $items ) { $this->show_legend( $items ); } - protected function show_legend( $items ) { + private function show_legend( $items ) { $statuses = array_unique( wp_list_pluck( $items, 'status' ) ); $legend_line = array(); @@ -76,7 +76,7 @@ protected function show_legend( $items ) { WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } - protected function status_single( $file, $name ) { + private function status_single( $file, $name ) { $details = $this->get_details( $file ); $status = $this->format_status( $this->get_status( $file ), 'long' ); @@ -195,7 +195,7 @@ protected function has_update( $slug ) { return isset( $update_list->response[ $slug ] ); } - protected $map = array( + private $map = array( 'short' => array( 'inactive' => 'I', 'active' => 'A', @@ -210,11 +210,11 @@ protected function has_update( $slug ) { ) ); - protected function format_status( $status, $format ) { + private function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } - protected function get_color( $status ) { + private function get_color( $status ) { static $colors = array( 'inactive' => '', 'active' => '%g', From df0f50c3a012107bffd9a6f23c1c7b48d0c25de4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Sep 2012 00:00:44 +0300 Subject: [PATCH 0581/5359] separate item fetching logic from output --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 9 +++++++-- src/php/wp-cli/commands/internals/plugin.php | 6 ++---- src/php/wp-cli/commands/internals/theme.php | 6 ++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index d6fa809c9..550c148d9 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -12,10 +12,11 @@ abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { abstract protected function parse_name( $args, $subcommand ); abstract protected function get_item_list(); + abstract protected function get_all_items(); + abstract protected function get_status( $file ); abstract protected function get_details( $file ); - abstract protected function status_all(); abstract protected function _status_single( $details, $name, $version, $status ); abstract protected function install_from_repo( $slug, $assoc_args ); @@ -38,7 +39,11 @@ function status( $args = array() ) { } } - protected function print_status_all( $items ) { + private function status_all() { + $items = $this->get_all_items(); + + WP_CLI::line( "Installed {$this->item_type}s:" ); + foreach ( $items as $file => $details ) { if ( $details['update'] ) { $line = ' %yU%n'; diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 7c663bbd5..1082eb117 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -31,7 +31,7 @@ protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); } - protected function status_all() { + protected function get_all_items() { $items = $this->get_item_list(); foreach ( get_mu_plugins() as $file => $mu_plugin ) { @@ -42,9 +42,7 @@ protected function status_all() { ); } - WP_CLI::line( 'Installed plugins:' ); - - $this->print_status_all( $items ); + return $items; } /** diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 4c90915e3..bf0b34910 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -23,10 +23,8 @@ protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); } - protected function status_all() { - WP_CLI::line( 'Installed themes:' ); - - $this->print_status_all( $this->get_item_list() ); + protected function get_all_items() { + return $this->get_item_list(); } protected function get_status( $stylesheet ) { From cebef2c1f4516bd7ad38edb0ce8f4c491d5bfc1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Sep 2012 00:25:05 +0300 Subject: [PATCH 0582/5359] use suffix parameter from basename() instead of using str_replace() --- src/php/wp-cli/commands/internals/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 1082eb117..8154e15eb 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -306,7 +306,7 @@ protected function parse_name( $args, $subcommand ) { private function get_name( $file ) { if ( false === strpos( $file, '/' ) ) - $name = str_replace( '.php', '', basename( $file ) ); + $name = basename( $file, '.php' ); else $name = dirname( $file ); From 9dc12d53acd92af3f325d41645252951533b17ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Sep 2012 03:22:20 +0300 Subject: [PATCH 0583/5359] generate: issue error when passed an invalid post type --- src/php/wp-cli/commands/internals/generate.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index a1cea714f..965cdc16f 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -30,8 +30,7 @@ public function posts( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); if ( !post_type_exists( $type ) ) { - WP_CLI::warning( 'invalid post type.' ); - exit; + WP_CLI::error( sprintf( "'%s' is not a registered post type.", $type ) ); } if ( $author ) { From 022734127f81c9a0fc3e3ba4991274b0618b01d7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Sep 2012 13:41:55 +0300 Subject: [PATCH 0584/5359] update php-cli-tools revision; makes cli\Table output cleaner when piping to another command --- src/php/php-cli-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools index 1fd565ce6..7924a9dcc 160000 --- a/src/php/php-cli-tools +++ b/src/php/php-cli-tools @@ -1 +1 @@ -Subproject commit 1fd565ce6c989c1e1faf8571e2af6da7d88b8b32 +Subproject commit 7924a9dccc8dcd84bfeb7f9767104958caac3242 From 5f9982f6de454695bb52a119dccc910db93b62cd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Sep 2012 15:26:45 +0300 Subject: [PATCH 0585/5359] move $action out of loop. see #160 --- src/php/wp-cli/commands/internals/post.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 06b80ded5..97d788569 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -94,9 +94,12 @@ public function delete( $args, $assoc_args ) { WP_CLI::error( "No posts to delete." ); } - foreach( $posts_to_delete as $post_id ) { - if ( wp_delete_post( $post_id, (bool)$assoc_args['force'] ) ) { - $action = ( (bool) $assoc_args['force'] ) ? 'Deleted' : 'Trashed'; + $force = (bool) $assoc_args['force']; + + $action = $force ? 'Deleted' : 'Trashed'; + + foreach ( $posts_to_delete as $post_id ) { + if ( wp_delete_post( $post_id, $force ) ) { WP_CLI::success( "{$action} post $post_id." ); } else { WP_CLI::error( "Failed deleting post $post_id." ); From 003232a4f36f73847fec62c2adb99213367f7910 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Sep 2012 16:30:36 +0300 Subject: [PATCH 0586/5359] export: validate_arguments() is not a subcommand, so make it private --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 555a29d38..f884738ee 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -13,7 +13,7 @@ class Export_Command extends WP_CLI_Command { /** * Argument validation functions below */ - public function validate_arguments( $args, $assoc_args ) { + private function validate_arguments( $args, $assoc_args ) { $defaults = array( 'path' => NULL, 'start_date' => NULL, From 4da5c54ecea01094cf4488784a06ad508bce7e3d Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Thu, 27 Sep 2012 22:30:48 +0100 Subject: [PATCH 0587/5359] Use consistent names relating to post columns - Rename type to post_type - Rename status to post_status --- src/php/wp-cli/commands/internals/generate.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 965cdc16f..ab67433c7 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -23,14 +23,14 @@ public function posts( $args, $assoc_args ) { 'count' => 100, 'max_depth' => 1, 'type' => 'post', - 'status' => 'publish', - 'author' => false + 'post_status' => 'publish', + 'post_author' => false, ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - if ( !post_type_exists( $type ) ) { - WP_CLI::error( sprintf( "'%s' is not a registered post type.", $type ) ); + if ( !post_type_exists( $post_type ) ) { + WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); } if ( $author ) { @@ -41,11 +41,11 @@ public function posts( $args, $assoc_args ) { } // Get the total number of posts - $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $type ) ); + $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); - $label = get_post_type_object( $type )->labels->singular_name; + $label = get_post_type_object( $post_type )->labels->singular_name; - $hierarchical = get_post_type_object( $type )->hierarchical; + $hierarchical = get_post_type_object( $post_type )->hierarchical; $limit = $count + $total; @@ -72,9 +72,9 @@ public function posts( $args, $assoc_args ) { } $args = array( - 'post_type' => $type, + 'post_type' => $post_type, 'post_title' => "$label $i", - 'post_status' => $status, + 'post_status' => $post_status, 'post_author' => $author, 'post_parent' => $current_parent, 'post_name' => "post-$i" From 8dc741d55ba03820628ce5799a9f84fa1d44b66b Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Thu, 27 Sep 2012 22:33:42 +0100 Subject: [PATCH 0588/5359] Posts without a date cause 404s - Provide post_date argument - Set the default date to now --- src/php/wp-cli/commands/internals/generate.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index ab67433c7..0eb9a84ca 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -25,6 +25,7 @@ public function posts( $args, $assoc_args ) { 'type' => 'post', 'post_status' => 'publish', 'post_author' => false, + 'post_date' => date('Y-m-d H:i:s'), ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); @@ -77,7 +78,8 @@ public function posts( $args, $assoc_args ) { 'post_status' => $post_status, 'post_author' => $author, 'post_parent' => $current_parent, - 'post_name' => "post-$i" + 'post_name' => "post-$i", + 'post_date' => $post_date, ); // Not using wp_insert_post() because it's slow From cd740e92023472d6b6b4445a66d17f2a438ffdc2 Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Thu, 27 Sep 2012 22:46:16 +0100 Subject: [PATCH 0589/5359] Make Authors consisten with column names : post_author Fix error in previous commit regarding post_type --- src/php/wp-cli/commands/internals/generate.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 0eb9a84ca..6b39d6617 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -22,7 +22,7 @@ public function posts( $args, $assoc_args ) { $defaults = array( 'count' => 100, 'max_depth' => 1, - 'type' => 'post', + 'post_type' => 'post', 'post_status' => 'publish', 'post_author' => false, 'post_date' => date('Y-m-d H:i:s'), @@ -34,11 +34,11 @@ public function posts( $args, $assoc_args ) { WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); } - if ( $author ) { - $author = get_user_by( 'login', $author ); + if ( $post_author ) { + $post_author = get_user_by( 'login', $post_author ); - if ( $author ) - $author = $author->ID; + if ( $post_author ) + $post_author = $post_author->ID; } // Get the total number of posts @@ -76,7 +76,7 @@ public function posts( $args, $assoc_args ) { 'post_type' => $post_type, 'post_title' => "$label $i", 'post_status' => $post_status, - 'post_author' => $author, + 'post_author' => $post_author, 'post_parent' => $current_parent, 'post_name' => "post-$i", 'post_date' => $post_date, From 653ce4665dd5ab7ebe59ddcb746e994e34fc3bc2 Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Thu, 27 Sep 2012 22:58:44 +0100 Subject: [PATCH 0590/5359] Make the command post generate, not generate post --- src/php/wp-cli/commands/internals/generate.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php index 6b39d6617..ce0f0072d 100644 --- a/src/php/wp-cli/commands/internals/generate.php +++ b/src/php/wp-cli/commands/internals/generate.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command('generate', 'Generate_Command'); +WP_CLI::add_command('post', 'Post_Command'); /** * Implement generate command @@ -8,7 +8,7 @@ * @package wp-cli * @subpackage commands/internals */ -class Generate_Command extends WP_CLI_Command { +class Post_Command extends WP_CLI_Command { /** * Generate posts @@ -16,7 +16,7 @@ class Generate_Command extends WP_CLI_Command { * @param array $args * @param array $assoc_args **/ - public function posts( $args, $assoc_args ) { + public function generate( $args, $assoc_args ) { global $wpdb; $defaults = array( From 9997e41cc1bb133d38633b953e2febb4b6e0daf5 Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Fri, 28 Sep 2012 09:05:31 +0100 Subject: [PATCH 0591/5359] Move generate post and user into respective locations --- .../wp-cli/commands/internals/generate.php | 157 ------------------ src/php/wp-cli/commands/internals/post.php | 91 ++++++++++ src/php/wp-cli/commands/internals/user.php | 55 ++++++ 3 files changed, 146 insertions(+), 157 deletions(-) delete mode 100644 src/php/wp-cli/commands/internals/generate.php diff --git a/src/php/wp-cli/commands/internals/generate.php b/src/php/wp-cli/commands/internals/generate.php deleted file mode 100644 index ce0f0072d..000000000 --- a/src/php/wp-cli/commands/internals/generate.php +++ /dev/null @@ -1,157 +0,0 @@ -<?php - -WP_CLI::add_command('post', 'Post_Command'); - -/** - * Implement generate command - * - * @package wp-cli - * @subpackage commands/internals - */ -class Post_Command extends WP_CLI_Command { - - /** - * Generate posts - * - * @param array $args - * @param array $assoc_args - **/ - public function generate( $args, $assoc_args ) { - global $wpdb; - - $defaults = array( - 'count' => 100, - 'max_depth' => 1, - 'post_type' => 'post', - 'post_status' => 'publish', - 'post_author' => false, - 'post_date' => date('Y-m-d H:i:s'), - ); - - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - if ( !post_type_exists( $post_type ) ) { - WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); - } - - if ( $post_author ) { - $post_author = get_user_by( 'login', $post_author ); - - if ( $post_author ) - $post_author = $post_author->ID; - } - - // Get the total number of posts - $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); - - $label = get_post_type_object( $post_type )->labels->singular_name; - - $hierarchical = get_post_type_object( $post_type )->hierarchical; - - $limit = $count + $total; - - $notify = new \cli\progress\Bar( 'Generating posts', $count ); - - $current_depth = 1; - $current_parent = 0; - - for ( $i = $total; $i < $limit; $i++ ) { - - if ( $hierarchical ) { - - if( $this->maybe_make_child() && $current_depth < $max_depth ) { - - $current_parent = $post_ids[$i-1]; - $current_depth++; - - } else if( $this->maybe_reset_depth() ) { - - $current_depth = 1; - $current_parent = 0; - - } - } - - $args = array( - 'post_type' => $post_type, - 'post_title' => "$label $i", - 'post_status' => $post_status, - 'post_author' => $post_author, - 'post_parent' => $current_parent, - 'post_name' => "post-$i", - 'post_date' => $post_date, - ); - - // Not using wp_insert_post() because it's slow - $wpdb->insert( $wpdb->posts, $args ); - - $notify->tick(); - } - - $notify->finish(); - } - - private function maybe_make_child() { - // 50% chance of making child post - return ( mt_rand(1,2) == 1 ) ? true: false; - } - - private function maybe_reset_depth() { - // 10% chance of reseting to root depth - return ( mt_rand(1,10) == 7 ) ? true : false; - } - - /** - * Generate users - * - * @param array $args - * @param array $assoc_args - **/ - public function users( $args, $assoc_args ) { - global $blog_id; - - $defaults = array( - 'count' => 100, - 'role' => get_option('default_role'), - ); - - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - if ( 'none' == $role ) { - $role = false; - } elseif ( is_null( get_role( $role ) ) ) { - WP_CLI::warning( "invalid role." ); - exit; - } - - $user_count = count_users(); - - $total = $user_count['total_users']; - - $limit = $count + $total; - - $notify = new \cli\progress\Bar( 'Generating users', $count ); - - for ( $i = $total; $i < $limit; $i++ ) { - $login = sprintf( 'user_%d_%d', $blog_id, $i ); - $name = "User $i"; - - $user_id = wp_insert_user( array( - 'user_login' => $login, - 'user_pass' => $login, - 'nickname' => $name, - 'display_name' => $name, - 'role' => $role - ) ); - - if ( false === $role ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - - $notify->tick(); - } - - $notify->finish(); - } -} diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 97d788569..d6a614d6f 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -106,4 +106,95 @@ public function delete( $args, $assoc_args ) { } } } + + /** + * Generate posts + * + * @param array $args + * @param array $assoc_args + **/ + public function generate( $args, $assoc_args ) { + global $wpdb; + + $defaults = array( + 'count' => 100, + 'max_depth' => 1, + 'post_type' => 'post', + 'post_status' => 'publish', + 'post_author' => false, + 'post_date' => date('Y-m-d H:i:s'), + ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( !post_type_exists( $post_type ) ) { + WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); + } + + if ( $post_author ) { + $post_author = get_user_by( 'login', $post_author ); + + if ( $post_author ) + $post_author = $post_author->ID; + } + + // Get the total number of posts + $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); + + $label = get_post_type_object( $post_type )->labels->singular_name; + + $hierarchical = get_post_type_object( $post_type )->hierarchical; + + $limit = $count + $total; + + $notify = new \cli\progress\Bar( 'Generating posts', $count ); + + $current_depth = 1; + $current_parent = 0; + + for ( $i = $total; $i < $limit; $i++ ) { + + if ( $hierarchical ) { + + if( $this->maybe_make_child() && $current_depth < $max_depth ) { + + $current_parent = $post_ids[$i-1]; + $current_depth++; + + } else if( $this->maybe_reset_depth() ) { + + $current_depth = 1; + $current_parent = 0; + + } + } + + $args = array( + 'post_type' => $post_type, + 'post_title' => "$label $i", + 'post_status' => $post_status, + 'post_author' => $post_author, + 'post_parent' => $current_parent, + 'post_name' => "post-$i", + 'post_date' => $post_date, + ); + + // Not using wp_insert_post() because it's slow + $wpdb->insert( $wpdb->posts, $args ); + + $notify->tick(); + } + + $notify->finish(); + } + + private function maybe_make_child() { + // 50% chance of making child post + return ( mt_rand(1,2) == 1 ) ? true: false; + } + + private function maybe_reset_depth() { + // 10% chance of reseting to root depth + return ( mt_rand(1,10) == 7 ) ? true : false; + } } diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index c6fd1350f..4fbceb097 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -150,4 +150,59 @@ public function update( $args, $assoc_args ) { WP_CLI::success( "Updated user $updated_id." ); } } + + + /** + * Generate users + * + * @param array $args + * @param array $assoc_args + **/ + public function generate( $args, $assoc_args ) { + global $blog_id; + + $defaults = array( + 'count' => 100, + 'role' => get_option('default_role'), + ); + + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + if ( 'none' == $role ) { + $role = false; + } elseif ( is_null( get_role( $role ) ) ) { + WP_CLI::warning( "invalid role." ); + exit; + } + + $user_count = count_users(); + + $total = $user_count['total_users']; + + $limit = $count + $total; + + $notify = new \cli\progress\Bar( 'Generating users', $count ); + + for ( $i = $total; $i < $limit; $i++ ) { + $login = sprintf( 'user_%d_%d', $blog_id, $i ); + $name = "User $i"; + + $user_id = wp_insert_user( array( + 'user_login' => $login, + 'user_pass' => $login, + 'nickname' => $name, + 'display_name' => $name, + 'role' => $role + ) ); + + if ( false === $role ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } + + $notify->tick(); + } + + $notify->finish(); + } } From f6a939babe6308280912af8125acec3223bdc2fa Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jeff@bigfish.co.uk> Date: Fri, 28 Sep 2012 08:15:15 +0000 Subject: [PATCH 0592/5359] Fix typo in update post comment --- src/php/wp-cli/commands/internals/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index d6a614d6f..0d2124465 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -30,7 +30,7 @@ public function create( $args, $assoc_args ) { } /** - * Update a user + * Update a post * * @param array $args * @param array $assoc_args From 157bd7480a0dc9b426522f7a85fa5bb415429f81 Mon Sep 17 00:00:00 2001 From: Jeffry Ghazally <jghazally@gmail.com> Date: Sun, 30 Sep 2012 10:38:48 +0000 Subject: [PATCH 0593/5359] change post_date default to use current_time --- src/php/wp-cli/commands/internals/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 0d2124465..13d33c47a 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -122,7 +122,7 @@ public function generate( $args, $assoc_args ) { 'post_type' => 'post', 'post_status' => 'publish', 'post_author' => false, - 'post_date' => date('Y-m-d H:i:s'), + 'post_date' => current_time( 'mysql' ), ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); From 6bdc27fb36b603b76c9a645916b14b93ed6adc9d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Oct 2012 18:02:20 +0000 Subject: [PATCH 0594/5359] Basic commands for adding and removing users from blogs --- src/php/wp-cli/commands/internals/user.php | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 4fbceb097..e9fed335a 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -205,4 +205,60 @@ public function generate( $args, $assoc_args ) { $notify->finish(); } + + /** + * Add a user to a blog + * + * @param array $args + * @param array $assoc_args + **/ + public function add_to_blog( $args, $assoc_args ) { + + $defaults = array( + 'id_or_login' => $args[0], + 'role' => $args[1], + ); + $args = array_merge( $assoc_args, $defaults ); + + if ( is_numeric( $args['id_or_login'] ) ) + $user = get_user_by( 'id', $args['id_or_login'] ); + else + $user = get_user_by( 'login', $args['id_or_login'] ); + + if ( empty( $args['id_or_login'] ) || empty( $user ) ) + WP_CLI::error( "Please specify a valid user ID or user login to add to this blog" ); + + global $wp_roles; + if ( empty( $args['role'] ) || ! array_key_exists( $args['role'], $wp_roles->roles ) ) + $args['role'] = get_option( 'default_role' ); + + add_user_to_blog( get_current_blog_id(), $user->ID, $args['role'] ); + WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$args['role']}" ); + } + + /** + * Remove a user from a blog + * + * @param array $args + * @param array $assoc_args + **/ + public function remove_from_blog( $args, $assoc_args ) { + + $defaults = array( + 'id_or_login' => $args[0], + ); + $args = array_merge( $assoc_args, $defaults ); + + if ( is_numeric( $args['id_or_login'] ) ) + $user = get_user_by( 'id', $args['id_or_login'] ); + else + $user = get_user_by( 'login', $args['id_or_login'] ); + + if ( empty( $args['id_or_login'] ) || empty( $user ) ) + WP_CLI::error( "Please specify a valid user ID or user login to remove from this blog" ); + + remove_user_from_blog( $user->ID, get_current_blog_id() ); + WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); + } + } From cb0d619586eef3dc2fcd216517a92aea2cc85e65 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Oct 2012 18:07:23 +0000 Subject: [PATCH 0595/5359] Basic documentation for the add_to_blog and remove_from_blog subcommands --- src/docs/user-add_to_blog.txt | 20 ++++++++++++++++++++ src/docs/user-remove_from_blog.txt | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/docs/user-add_to_blog.txt create mode 100644 src/docs/user-remove_from_blog.txt diff --git a/src/docs/user-add_to_blog.txt b/src/docs/user-add_to_blog.txt new file mode 100644 index 000000000..76a3056c4 --- /dev/null +++ b/src/docs/user-add_to_blog.txt @@ -0,0 +1,20 @@ +wp-user-add_to_blog(1) -- Add an existing WordPress user to an existing blog +==== + +## SYNOPSIS + +`wp user add_to_blog` <user-login> [--role=<role>] + +## OPTIONS + +* `<user-login>`: + + The login of the user to add to the blog. + +* `--role`=<role>: + + Add the user with the specified role. Defaults to blog default. + +## EXAMPLES + + wp user add_to_blog bob --role=author diff --git a/src/docs/user-remove_from_blog.txt b/src/docs/user-remove_from_blog.txt new file mode 100644 index 000000000..619ab9840 --- /dev/null +++ b/src/docs/user-remove_from_blog.txt @@ -0,0 +1,16 @@ +wp-user-remove_from_blog(1) -- Remove a WordPress user from a blog +==== + +## SYNOPSIS + +`wp user remove_from_blog` <user-login> + +## OPTIONS + +* `<user-login>`: + + The login of the user to remove from the blog. + +## EXAMPLES + + wp user remove_from_blog bob From ff5772f650fe24a01df1cd61422dd2ac2f27c741 Mon Sep 17 00:00:00 2001 From: Andreas Creten <andreas@madewithlove.be> Date: Thu, 4 Oct 2012 14:26:32 +0200 Subject: [PATCH 0596/5359] Fixed broken wp export command. Fixes #175. --- man/export.1 | 6 +++--- src/docs/export.txt | 4 ++-- src/php/wp-cli/class-wp-cli-command.php | 2 +- src/php/wp-cli/commands/internals/export.php | 17 +++++++++-------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/man/export.1 b/man/export.1 index 27afcfb5a..a2e45d461 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,12 +7,12 @@ \fBwp\-export\fR \- Create a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR \-\-path=\fIdirname\fR [filters] [\-\-skip_comments] +\fBwp export\fR \-\-dir=\fIdirname\fR [filters] [\-\-skip_comments] . .SH "OPTIONS" . .TP -\fB\-\-path\fR=\fIdirname\fR: +\fB\-\-dir\fR=\fIdirname\fR: . .IP Full Path to directory where WXR export files should be stored\. @@ -65,7 +65,7 @@ Export only posts with this status\. . .nf -wp export \-\-path=/tmp/ \-\-user=admin \-\-post_type=post \-\-start_date=2011\-01\-01 \-\-end_date=2011\-12\-31 +wp export \-\-dir=/tmp/ \-\-user=admin \-\-post_type=post \-\-start_date=2011\-01\-01 \-\-end_date=2011\-12\-31 . .fi diff --git a/src/docs/export.txt b/src/docs/export.txt index 9a27e63ab..5e7d32e54 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -7,7 +7,7 @@ wp-export(1) -- Create a WXR file. ## OPTIONS -* `--path`=<dirname>: +* `--dir`=<dirname>: Full Path to directory where WXR export files should be stored. @@ -43,4 +43,4 @@ wp-export(1) -- Create a WXR file. ## EXAMPLES - wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 79eee88ac..e9701c26a 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -30,7 +30,7 @@ public function __construct( $args, $assoc_args ) { // This if for reserved keywords in php (like list, isset) $subcommand = '_' . $subcommand; } - + if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) ) { self::describe_command( get_class( $this ), WP_CLI_COMMAND ); } else { diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index f884738ee..275d93f73 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -9,13 +9,15 @@ * @subpackage commands/internals */ class Export_Command extends WP_CLI_Command { + + protected $default_subcommand = 'export'; /** * Argument validation functions below */ - private function validate_arguments( $args, $assoc_args ) { + protected function export( $args, $assoc_args ) { $defaults = array( - 'path' => NULL, + 'dir' => NULL, 'start_date' => NULL, 'end_date' => NULL, 'post_type' => NULL, @@ -41,21 +43,21 @@ private function validate_arguments( $args, $assoc_args ) { exit(1); } - $this->wxr_path = $assoc_args['path']; + $this->wxr_path = $assoc_args['dir']; WP_CLI::line( 'Starting export process...' ); WP_CLI::line(); $this->export_wp( $this->export_args ); } - private function check_path( $path ) { + private function check_dir( $path ) { if ( empty( $path ) ) { - WP_CLI::warning( 'missing --path parameter' ); + WP_CLI::warning( 'missing --dir parameter' ); return false; } if ( !is_dir( $path ) ) { - WP_CLI::error( sprintf( "The path %s does not exist", $path ) ); + WP_CLI::error( sprintf( "The directory %s does not exist", $path ) ); } return true; @@ -455,5 +457,4 @@ private function export_wp( $args = array() ) { file_put_contents( $full_path, $result ); } } -} - +} \ No newline at end of file From a4374f8608ab5bbfa6aac3bd3d4c16808b6fd50b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 19:27:18 +0300 Subject: [PATCH 0597/5359] move get_subcommands() and describe_command() to WP_CLI class --- src/php/wp-cli/class-wp-cli-command.php | 53 +--------------------- src/php/wp-cli/class-wp-cli.php | 49 ++++++++++++++++++++ src/php/wp-cli/commands/internals/help.php | 4 +- src/php/wp-cli/wp-cli.php | 2 +- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index e9701c26a..338f26c7c 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -30,61 +30,12 @@ public function __construct( $args, $assoc_args ) { // This if for reserved keywords in php (like list, isset) $subcommand = '_' . $subcommand; } - + if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) ) { - self::describe_command( get_class( $this ), WP_CLI_COMMAND ); + WP_CLI::describe_command( get_class( $this ), WP_CLI_COMMAND ); } else { $this->$subcommand( $args, $assoc_args ); } } - - static function describe_command( $class, $command ) { - if ( method_exists( $class, 'help' ) ) { - $class::help(); - return; - } - - $methods = self::get_subcommands( $class ); - - $out = "usage: wp $command"; - - if ( empty( $methods ) ) { - WP_CLI::line( $out ); - } else { - $out .= ' [' . implode( '|', $methods ) . ']'; - - WP_CLI::line( $out ); - - WP_CLI::line(); - WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); - } - } - - /** - * Get the list of subcommands for a class. - * - * @param string $class - * @return array The list of methods - */ - static function get_subcommands( $class ) { - $reflection = new ReflectionClass( $class ); - - $methods = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) - continue; - - $name = $method->name; - - if ( strpos( $name, '_' ) === 0 ) { - $name = substr( $name, 1 ); - } - - $methods[] = $name; - } - - return $methods; - } } diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 967e3a143..e00500129 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -361,6 +361,55 @@ static function load_command( $command ) { return WP_CLI::$commands[$command]; } + /** + * Get the list of subcommands for a class. + * + * @param string $class + * @return array The list of methods + */ + static function get_subcommands( $class ) { + $reflection = new ReflectionClass( $class ); + + $methods = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) + continue; + + $name = $method->name; + + if ( strpos( $name, '_' ) === 0 ) { + $name = substr( $name, 1 ); + } + + $methods[] = $name; + } + + return $methods; + } + + static function describe_command( $class, $command ) { + if ( method_exists( $class, 'help' ) ) { + $class::help(); + return; + } + + $methods = WP_CLI::get_subcommands( $class ); + + $out = "usage: wp $command"; + + if ( empty( $methods ) ) { + WP_CLI::line( $out ); + } else { + $out .= ' [' . implode( '|', $methods ) . ']'; + + WP_CLI::line( $out ); + + WP_CLI::line(); + WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); + } + } + // back-compat static function addCommand( $name, $class ) { self::add_command( $name, $class ); diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 8ff24eb3e..f5be9c222 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -37,7 +37,7 @@ private function maybe_load_man_page( $args ) { private function show_available_subcommands( $command ) { $class = WP_CLI::load_command( $command ); - WP_CLI_Command::describe_command( $class, $command ); + WP_CLI::describe_command( $class, $command ); } private function general_help() { @@ -48,7 +48,7 @@ private function general_help() { $out = " wp $command"; - $methods = WP_CLI_Command::get_subcommands( $class ); + $methods = WP_CLI::get_subcommands( $class ); if ( !empty( $methods ) ) { $out .= ' [' . implode( '|', $methods ) . ']'; diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 1fbd96dd9..c98991170 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -127,7 +127,7 @@ // Generate strings for autocomplete if ( WP_CLI_AUTOCOMPLETE ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { - $subcommands = implode( ' ', WP_CLI_Command::get_subcommands( $command ) ); + $subcommands = implode( ' ', WP_CLI::get_subcommands( $command ) ); WP_CLI::line( $name . ' ' . $subcommands ); } exit; From 95cf164614f17167b2f575502d6f99d7d062d68c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 20:15:53 +0300 Subject: [PATCH 0598/5359] introduce filter_methods() --- src/php/wp-cli/class-wp-cli.php | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index e00500129..697ae2a76 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -370,19 +370,25 @@ static function load_command( $command ) { static function get_subcommands( $class ) { $reflection = new ReflectionClass( $class ); - $methods = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) - continue; - + return self::filter_methods( $reflection, function( $method ) { $name = $method->name; if ( strpos( $name, '_' ) === 0 ) { $name = substr( $name, 1 ); } - $methods[] = $name; + return $name; + } ); + } + + private static function filter_methods( $reflection, $cb ) { + $methods = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) + continue; + + $methods[] = $cb( $method ); } return $methods; From 0844ec07a9905f3efa6b9af0d6f14b536ee79142 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 21:42:21 +0300 Subject: [PATCH 0599/5359] implement 'help' command as a closure in a namespace --- src/php/wp-cli/commands/internals/help.php | 95 ++++++++++------------ 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index f5be9c222..a8fe0f8e2 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -1,74 +1,65 @@ <?php +namespace WP_CLI\Help; -WP_CLI::add_command('help', 'Help_Command'); - -/** - * Implement help command - * - * @package wp-cli - * @subpackage commands/internals - */ -class Help_Command extends WP_CLI_Command { +\WP_CLI::add_command( 'help', function( $args ) { + if ( empty( $args ) ) { + general_help(); + return; + } - public function __construct( $args ) { - if ( empty( $args ) ) { - $this->general_help(); - return; - } + maybe_load_man_page( $args ); - $this->maybe_load_man_page( $args ); + show_available_subcommands( $args[0] ); +} ); - $this->show_available_subcommands( $args[0] ); - } +function maybe_load_man_page( $args ) { + $man_dir = WP_CLI_ROOT . "../../../man/"; - private function maybe_load_man_page( $args ) { - $man_dir = WP_CLI_ROOT . "../../../man/"; + if ( !is_dir( $man_dir ) ) { + \WP_CLI::warning( "man pages do not seem to be installed." ); + } else { + $man_file = $man_dir . implode( '-', $args ) . '.1'; - if ( !is_dir( $man_dir ) ) { - WP_CLI::warning( "man pages do not seem to be installed." ); - } else { - $man_file = $man_dir . implode( '-', $args ) . '.1'; - - if ( is_readable( $man_file ) ) { - exit( WP_CLI::launch( "man $man_file" ) ); - } + if ( is_readable( $man_file ) ) { + exit( \WP_CLI::launch( "man $man_file" ) ); } } +} - private function show_available_subcommands( $command ) { - $class = WP_CLI::load_command( $command ); - WP_CLI::describe_command( $class, $command ); - } - - private function general_help() { - WP_CLI::line( 'Available commands:' ); - foreach ( WP_CLI::load_all_commands() as $command => $class ) { - if ( 'help' == $command ) - continue; +function show_available_subcommands( $command ) { + $class = \WP_CLI::load_command( $command ); + \WP_CLI::describe_command( $class, $command ); +} - $out = " wp $command"; +function general_help() { + \WP_CLI::line( 'Available commands:' ); + foreach ( \WP_CLI::load_all_commands() as $command => $class ) { + if ( 'help' == $command ) + continue; - $methods = WP_CLI::get_subcommands( $class ); + $out = " wp $command"; - if ( !empty( $methods ) ) { - $out .= ' [' . implode( '|', $methods ) . ']'; - } + $methods = \WP_CLI::get_subcommands( $class ); - WP_CLI::line( $out ); + if ( !empty( $methods ) ) { + $out .= ' [' . implode( '|', $methods ) . ']'; } - WP_CLI::line(<<<EOB + \WP_CLI::line( $out ); + } + + \WP_CLI::line(<<<EOB See 'wp help <command>' for more information on a specific command. Global parameters: - --user=<id|login> set the current user - --url=<url> set the current URL - --path=<path> set the current path to the WP install - --require=<path> load a certain file before running the command - --quiet suppress informational messages - --version print wp-cli version +--user=<id|login> set the current user +--url=<url> set the current URL +--path=<path> set the current path to the WP install +--require=<path> load a certain file before running the command +--quiet suppress informational messages +--version print wp-cli version EOB - ); - } + ); } + From bdbeaacaad24554765be83444b62b29ed09de74b Mon Sep 17 00:00:00 2001 From: Lane Goldberg <lanegoldberg@gmail.com> Date: Mon, 8 Oct 2012 15:51:22 -0300 Subject: [PATCH 0600/5359] Added case for my fresh install of Mamp 2.1.1 ADDED: /Applications/MAMP/bin/php/php5.[34]*/bin/php --- src/bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index fa1037e4e..ec8e4a952 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -67,7 +67,7 @@ else fi # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php5.[34]*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do if [ -x $amp_php ]; then php=$amp_php break From 506797bb0fa78002e9080369e23f572ad7afcfcd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 22:04:35 +0300 Subject: [PATCH 0601/5359] implement 'export' command without relying on default subcommand or custom constructor --- src/php/wp-cli/commands/internals/export.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 275d93f73..02a42ddd4 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command('export', 'Export_Command'); +WP_CLI::add_command( 'export', array( new Export_Command, 'export' ) ); /** * Implement export command @@ -8,14 +8,12 @@ * @package wp-cli * @subpackage commands/internals */ -class Export_Command extends WP_CLI_Command { - - protected $default_subcommand = 'export'; +class Export_Command { /** * Argument validation functions below */ - protected function export( $args, $assoc_args ) { + public function export( $args, $assoc_args ) { $defaults = array( 'dir' => NULL, 'start_date' => NULL, @@ -457,4 +455,4 @@ private function export_wp( $args = array() ) { file_put_contents( $full_path, $result ); } } -} \ No newline at end of file +} From 53461fe532bd0fbec128003152f7822c56da024a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 22:12:56 +0300 Subject: [PATCH 0602/5359] move dispatch logic out of WP_CLI_Command constructor and into a separate namespace --- .../class-wp-cli-command-with-upgrade.php | 6 +- src/php/wp-cli/class-wp-cli-command.php | 35 ++---- src/php/wp-cli/class-wp-cli.php | 60 +--------- src/php/wp-cli/commands/internals/db.php | 4 +- src/php/wp-cli/commands/internals/help.php | 4 +- src/php/wp-cli/commands/internals/plugin.php | 4 +- src/php/wp-cli/dispatcher.php | 108 ++++++++++++++++++ src/php/wp-cli/wp-cli.php | 3 +- 8 files changed, 129 insertions(+), 95 deletions(-) create mode 100644 src/php/wp-cli/dispatcher.php diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 550c148d9..253724cb0 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -2,13 +2,15 @@ abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { + public static function get_default_subcommand() { + return 'status'; + } + protected $item_type; protected $upgrader; protected $upgrade_refresh; protected $upgrade_transient; - protected $default_subcommand = 'status'; - abstract protected function parse_name( $args, $subcommand ); abstract protected function get_item_list(); diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 338f26c7c..9bd137b85 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -7,35 +7,14 @@ */ abstract class WP_CLI_Command { - protected $default_subcommand; - - protected $aliases = array(); - - /** - * Transfers the handling to the appropriate method - * - * @param array $args - * @param array $assoc_args - */ - public function __construct( $args, $assoc_args ) { - if ( empty( $args ) ) - $subcommand = $this->default_subcommand; - else - $subcommand = array_shift( $args ); - - if ( isset( $this->aliases[ $subcommand ] ) ) - $subcommand = $this->aliases[ $subcommand ]; - - if ( !method_exists( $this, $subcommand ) ) { - // This if for reserved keywords in php (like list, isset) - $subcommand = '_' . $subcommand; - } + public static function get_default_subcommand() { + return false; + } - if ( __FUNCTION__ == $subcommand || !method_exists( $this, $subcommand ) ) { - WP_CLI::describe_command( get_class( $this ), WP_CLI_COMMAND ); - } else { - $this->$subcommand( $args, $assoc_args ); - } + static function get_aliases() { + return array(); } + + public function __construct() {} } diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 697ae2a76..17507abd0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -335,10 +335,7 @@ static function run_command( $arguments, $assoc_args ) { $implementation = self::load_command( $command ); - if ( is_string( $implementation ) && class_exists( $implementation ) ) - $instance = new $implementation( $arguments, $assoc_args ); - else - call_user_func( $implementation, $arguments, $assoc_args ); + \WP_CLI\Dispatcher\dispatch( $implementation, $arguments, $assoc_args ); } static function load_command( $command ) { @@ -361,61 +358,6 @@ static function load_command( $command ) { return WP_CLI::$commands[$command]; } - /** - * Get the list of subcommands for a class. - * - * @param string $class - * @return array The list of methods - */ - static function get_subcommands( $class ) { - $reflection = new ReflectionClass( $class ); - - return self::filter_methods( $reflection, function( $method ) { - $name = $method->name; - - if ( strpos( $name, '_' ) === 0 ) { - $name = substr( $name, 1 ); - } - - return $name; - } ); - } - - private static function filter_methods( $reflection, $cb ) { - $methods = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) - continue; - - $methods[] = $cb( $method ); - } - - return $methods; - } - - static function describe_command( $class, $command ) { - if ( method_exists( $class, 'help' ) ) { - $class::help(); - return; - } - - $methods = WP_CLI::get_subcommands( $class ); - - $out = "usage: wp $command"; - - if ( empty( $methods ) ) { - WP_CLI::line( $out ); - } else { - $out .= ' [' . implode( '|', $methods ) . ']'; - - WP_CLI::line( $out ); - - WP_CLI::line(); - WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); - } - } - // back-compat static function addCommand( $name, $class ) { self::add_command( $name, $class ); diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index f382651d3..b426d30a3 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -10,7 +10,9 @@ **/ class DB_Command extends WP_CLI_Command { - protected $default_subcommand = 'cli'; + public static function get_default_subcommand() { + return 'cli'; + } protected $aliases = array( 'dump' => 'export' ); diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index a8fe0f8e2..b4059ba1a 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -28,7 +28,7 @@ function maybe_load_man_page( $args ) { function show_available_subcommands( $command ) { $class = \WP_CLI::load_command( $command ); - \WP_CLI::describe_command( $class, $command ); + \WP_CLI\Dispatcher\describe_command( $class, $command ); } function general_help() { @@ -39,7 +39,7 @@ function general_help() { $out = " wp $command"; - $methods = \WP_CLI::get_subcommands( $class ); + $methods = \WP_CLI\Dispatcher\get_subcommands( $class ); if ( !empty( $methods ) ) { $out .= ' [' . implode( '|', $methods ) . ']'; diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 8154e15eb..dfc3a1272 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -15,11 +15,11 @@ class Plugin_Command extends WP_CLI_Command_With_Upgrade { protected $upgrade_refresh = 'wp_update_plugins'; protected $upgrade_transient = 'update_plugins'; - function __construct( $args, $assoc_args ) { + function __construct() { require_once ABSPATH.'wp-admin/includes/plugin.php'; require_once ABSPATH.'wp-admin/includes/plugin-install.php'; - parent::__construct( $args, $assoc_args ); + parent::__construct(); } protected function _status_single( $details, $name, $version, $status ) { diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php new file mode 100644 index 000000000..9a26071fb --- /dev/null +++ b/src/php/wp-cli/dispatcher.php @@ -0,0 +1,108 @@ +<?php + +namespace WP_CLI\Dispatcher; + +function dispatch( $implementation, $arguments, $assoc_args ) { + if ( is_string( $implementation ) && class_exists( $implementation ) ) + dispatch_subcommand( $implementation, $arguments, $assoc_args ); + else + call_user_func( $implementation, $arguments, $assoc_args ); +} + +/** + * Transfers the handling to the appropriate method + * + * @param array $args + * @param array $assoc_args + */ +function dispatch_subcommand( $class, $args, $assoc_args ) { + if ( empty( $args ) ) { + $subcommand = $class::get_default_subcommand(); + } else { + $subcommand = subcommand_to_method( $class, array_shift( $args ) ); + } + + if ( !$subcommand ) { + describe_command( $class, WP_CLI_COMMAND ); + return; + } + + $instance = new $class; + $instance->$subcommand( $args, $assoc_args ); +} + +function subcommand_to_method( $class, $command ) { + $aliases = $class::get_aliases(); + + if ( isset( $aliases[ $subcommand ] ) ) { + $method = $aliases[ $subcommand ]; + } + + if ( !method_exists( $class, $subcommand ) ) { + // This if for reserved keywords in php (like list, isset) + $subcommand = '_' . $subcommand; + } + + if ( !method_exists( $class, $method ) ) { + return false; + } +} + +function describe_command( $class, $command ) { + if ( method_exists( $class, 'help' ) ) { + $class::help(); + return; + } + + $methods = get_subcommands( $class ); + + $out = "usage: wp $command"; + + if ( empty( $methods ) ) { + \WP_CLI::line( $out ); + } else { + $out .= ' [' . implode( '|', $methods ) . ']'; + + \WP_CLI::line( $out ); + + \WP_CLI::line(); + \WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); + } +} + +/** + * Get the list of subcommands for a class (reverse-dispatch). + * + * @param string $class + * @return array The list of methods + */ +function get_subcommands( $class ) { + if ( !is_string( $class ) ) + return array(); + + $reflection = new \ReflectionClass( $class ); + + return _filter_methods( $reflection, function( $method ) { + $name = $method->name; + + if ( strpos( $name, '_' ) === 0 ) { + $name = substr( $name, 1 ); + } + + return $name; + } ); +} + +function _filter_methods( $reflection, $cb ) { + $methods = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) + continue; + + $methods[] = $cb( $method ); + } + + return $methods; +} + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c98991170..25199d918 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,6 +14,7 @@ define( 'WP_CLI', true ); // Include the wp-cli classes +include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; @@ -127,7 +128,7 @@ // Generate strings for autocomplete if ( WP_CLI_AUTOCOMPLETE ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { - $subcommands = implode( ' ', WP_CLI::get_subcommands( $command ) ); + $subcommands = implode( ' ', WP_CLI\Dispatcher\get_subcommands( $command ) ); WP_CLI::line( $name . ' ' . $subcommands ); } exit; From b56d1b7aac9dbb58b45336209ce8b801c1aa5b9c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 22:24:55 +0300 Subject: [PATCH 0603/5359] fix likely incorrect mamp path. see #179 --- src/bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wp b/src/bin/wp index ec8e4a952..9a7755d4a 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -67,7 +67,7 @@ else fi # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php5.[34]*/bin/php /Applications/MAMP/bin/php/php.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do + for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php5.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do if [ -x $amp_php ]; then php=$amp_php break From 39dd428a4881660227ec56f60d709798d9eb3e4c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 8 Oct 2012 23:36:58 +0300 Subject: [PATCH 0604/5359] move php detection to separate utility --- src/bin/wp | 18 ------------------ utils/amp-paths.txt | 5 +++++ utils/find-php | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 utils/amp-paths.txt create mode 100755 utils/find-php diff --git a/src/bin/wp b/src/bin/wp index 9a7755d4a..d0fbdb4ea 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -5,10 +5,6 @@ # http://drupal.org/project/drush # And 0.09% to the author of this project: # https://github.com/88mph/wpadmin/blob/master/wpadmin.php -# -# This is a wrapper script that will run wp-cli.php with the most appropriate -# php executable it can find on your system. -# # Get the absolute path of this executable ORIGDIR=$(pwd) @@ -59,20 +55,6 @@ else # Default to using the php that we find on the PATH. # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 php=`which php` - - # We check for a command line (cli) version of php, and if found use that. - which php-cli >/dev/null 2>&1 - if [ "$?" = 0 ] ; then - php=`which php-cli` - fi - - # Special case for *AMP installers, since they normally don't set themselves as the default cli php out of the box. - for amp_php in /Applications/MAMP/bin/php/php5.3*/bin/php /Applications/MAMP/bin/php5*/bin/php /Applications/MAMP/bin/php/php5.[34]*/bin/php /opt/lampp/bin/php /Applications/xampp/xamppfiles/bin/php; do - if [ -x $amp_php ]; then - php=$amp_php - break - fi - done fi # Check to see if the user has provided a php.ini file or wp-cli.ini file in any conf dir diff --git a/utils/amp-paths.txt b/utils/amp-paths.txt new file mode 100644 index 000000000..a6c891d3b --- /dev/null +++ b/utils/amp-paths.txt @@ -0,0 +1,5 @@ +/Applications/MAMP/bin/php/php5.3*/bin/php +/Applications/MAMP/bin/php5*/bin/php +/Applications/MAMP/bin/php/php5.[34]*/bin/php +/Applications/xampp/xamppfiles/bin/php; +/opt/lampp/bin/php diff --git a/utils/find-php b/utils/find-php new file mode 100755 index 000000000..6c4d115cf --- /dev/null +++ b/utils/find-php @@ -0,0 +1,19 @@ +#!/usr/bin/env sh + +which php || which php-cli + +if [ $? -eq 0 ]; then + exit +fi + +# Special case for *AMP installers, since they normally don't set themselves +# as the default cli php out of the box. +for amp_php in $(cat $(dirname $0)/amp-paths.txt); do + if [ -x $amp_php ]; then + echo $amp_php + exit + fi +done + +echo "no php binary found" +exit 1 From 17e22502bf7d95877e795952accfd205ab959c51 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Oct 2012 00:30:43 +0300 Subject: [PATCH 0605/5359] mention find-php in readme --- README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4b99c1d1c..7ac88e5df 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ What is wp-cli? A set of tools for controlling WordPress installations from the command line. Requirements ------------- +============ * PHP >= 5.3 * WP >= 3.3 Installing ----------- +========== **Via PEAR:** @@ -29,9 +29,25 @@ sudo utils/dev-build You can replace `~/git/wp-cli` with whatever you want. +MAMP, XAMP, etc. +----------- + +If the `php` command is not available, you can try finding an appropriate binary: + +```sh +./utils/find-php +``` + +Then, create an environment variable called `WP_CLI_PHP` with the path found by `find-php`. + +In a UNIX environment, you would do this by adding the following line to your `.bashrc` file: + +```sh +WP_CLI_PHP=/path/to/php-binary +``` Using ------ +===== Go into a WordPress root folder: @@ -100,7 +116,7 @@ wp theme status ``` Adding commands ---------------- +=============== Adding commands to wp-cli is very easy. You can even add them from within your own plugin. You can find more information about adding commands in the [Commands Cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook) on our Wiki. @@ -108,7 +124,7 @@ You can find more information about adding commands in the [Commands Cookbook](h **Please share the commands you make, issue a pull request to get them included in wp-cli by default.** Changelog ---------------- +========= **0.6** From 66bf7da8e5baeb42243122402eb78e05274dfb36 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Oct 2012 00:36:24 +0300 Subject: [PATCH 0606/5359] link to wiki from readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ac88e5df..7dc46db18 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ What is wp-cli? -------------- -A set of tools for controlling WordPress installations from the command line. +wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs, update posts and much more. + +Visit the [wiki](https://github.com/wp-cli/wp-cli/wiki) for more information. Requirements ============ From 655b26e9fde757bd3bec08c21df69879dadee0ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Oct 2012 00:52:50 +0300 Subject: [PATCH 0607/5359] update docs; see #166 --- man/generate-posts.1 | 40 --------------- man/generate-users.1 | 22 -------- man/post-generate.1 | 51 +++++++++++++++++++ man/user-generate.1 | 25 +++++++++ .../{generate-posts.txt => post-generate.txt} | 10 ++-- .../{generate-users.txt => user-generate.txt} | 4 +- 6 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 man/post-generate.1 create mode 100644 man/user-generate.1 rename src/docs/{generate-posts.txt => post-generate.txt} (62%) rename src/docs/{generate-users.txt => user-generate.txt} (64%) diff --git a/man/generate-posts.1 b/man/generate-posts.1 index 9f0ef3a2e..995c5436f 100644 --- a/man/generate-posts.1 +++ b/man/generate-posts.1 @@ -1,43 +1,3 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-GENERATE\-POSTS" "1" "September 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-generate\-posts\fR \- Generate a bunch of posts\. -. -.SH "SYNOPSIS" -\fBwp generate posts\fR [\-\-count=100] [\-\-type=post] [\-\-status=publish] [\-\-author=\fIlogin\fR] [\-\-max_depth=1] -. -.SH "OPTIONS" -. -.TP -\fB\-\-count\fR=\fInumber\fR: -. -.IP -How many posts to generate\. Default: 100 -. -.TP -\fB\-\-type\fR=\fIpost_type\fR: -. -.IP -The type of the generated posts\. Default: \'post\' -. -.TP -\fB\-\-status\fR=\fIpost_status\fR: -. -.IP -The status of the generated posts\. Default: \'publish\' -. -.TP -\fB\-\-author\fR=\fIlogin\fR: -. -.IP -The author of the generated posts\. Default: none -. -.TP -\fB\-\-max_depth\fR=\fInumber\fR: -. -.IP -For hierarchical post types, generate child posts down to a certain depth\. Default: 1 diff --git a/man/generate-users.1 b/man/generate-users.1 index 347a6a5f0..995c5436f 100644 --- a/man/generate-users.1 +++ b/man/generate-users.1 @@ -1,25 +1,3 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-GENERATE\-USERS" "1" "September 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-generate\-users\fR \- Generate a bunch of users\. -. -.SH "SYNOPSIS" -\fBwp generate users\fR [\-\-count=100] [\-\-role=\fIrole\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-count\fR=\fInumber\fR: -. -.IP -How many users to generate\. Default: 100 -. -.TP -\fB\-\-role\fR=\fIrole\fR: -. -.IP -The role of the generated users\. Default: default role from WP diff --git a/man/post-generate.1 b/man/post-generate.1 new file mode 100644 index 000000000..afb014a25 --- /dev/null +++ b/man/post-generate.1 @@ -0,0 +1,51 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-GENERATE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-generate\fR \- Generate a bunch of posts\. +. +.SH "SYNOPSIS" +\fBwp post generate\fR [\-\-count=100] [\-\-post_type=post] [\-\-post_status=publish] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIdate\fR] [\-\-max_depth=1] +. +.SH "OPTIONS" +. +.TP +\fB\-\-count\fR=\fInumber\fR: +. +.IP +How many posts to generate\. Default: 100 +. +.TP +\fB\-\-type\fR=\fIpost_type\fR: +. +.IP +The type of the generated posts\. Default: \'post\' +. +.TP +\fB\-\-status\fR=\fIpost_status\fR: +. +.IP +The status of the generated posts\. Default: \'publish\' +. +.TP +\fB\-\-author\fR=\fIlogin\fR: +. +.IP +The author of the generated posts\. Default: none +. +.TP +\fB\-\-max_depth\fR=\fInumber\fR: +. +.IP +For hierarchical post types, generate child posts down to a certain depth\. Default: 1 +. +.SH "EXAMPLES" +. +.nf + +wp post generate \-\-count=10 \-\-post_type=page \-\-post_date=1999\-01\-04 +. +.fi + diff --git a/man/user-generate.1 b/man/user-generate.1 new file mode 100644 index 000000000..a2331a216 --- /dev/null +++ b/man/user-generate.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-GENERATE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-generate\fR \- Generate a bunch of users\. +. +.SH "SYNOPSIS" +\fBwp user generate\fR [\-\-count=100] [\-\-role=\fIrole\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-count\fR=\fInumber\fR: +. +.IP +How many users to generate\. Default: 100 +. +.TP +\fB\-\-role\fR=\fIrole\fR: +. +.IP +The role of the generated users\. Default: default role from WP + diff --git a/src/docs/generate-posts.txt b/src/docs/post-generate.txt similarity index 62% rename from src/docs/generate-posts.txt rename to src/docs/post-generate.txt index 129e4a1d0..3b5e282b2 100644 --- a/src/docs/generate-posts.txt +++ b/src/docs/post-generate.txt @@ -1,10 +1,10 @@ -wp-generate-posts(1) -- Generate a bunch of posts. +wp-post-generate(1) -- Generate a bunch of posts. ==== ## SYNOPSIS -`wp generate posts` [--count=100] [--type=post] [--status=publish] -[--author=<login>] [--max_depth=1] +`wp post generate` [--count=100] [--post_type=post] [--post_status=publish] +[--post_author=<login>] [--post_date=<date>] [--max_depth=1] ## OPTIONS @@ -27,3 +27,7 @@ wp-generate-posts(1) -- Generate a bunch of posts. * `--max_depth`=<number>: For hierarchical post types, generate child posts down to a certain depth. Default: 1 + +## EXAMPLES + + wp post generate --count=10 --post_type=page --post_date=1999-01-04 diff --git a/src/docs/generate-users.txt b/src/docs/user-generate.txt similarity index 64% rename from src/docs/generate-users.txt rename to src/docs/user-generate.txt index 3b2da84a1..52885be9f 100644 --- a/src/docs/generate-users.txt +++ b/src/docs/user-generate.txt @@ -1,9 +1,9 @@ -wp-generate-users(1) -- Generate a bunch of users. +wp-user-generate(1) -- Generate a bunch of users. ==== ## SYNOPSIS -`wp generate users` [--count=100] [--role=<role>] +`wp user generate` [--count=100] [--role=<role>] ## OPTIONS From eb8dd1679f80a7c25fe2ccf24c4cb506dcb77075 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Oct 2012 01:31:17 +0300 Subject: [PATCH 0608/5359] introduce @subcommand and use same logic for describing and dispatching a command --- man/cache.1 | 10 ++-- man/core-install-network.1 | 25 +++++++++ man/core-install_network.1 | 22 -------- man/core-update-db.1 | 10 ++++ man/core-update_db.1 | 9 +-- src/docs/cache.txt | 8 +-- ...l_network.txt => core-install-network.txt} | 4 +- src/docs/core-update-db.txt | 6 ++ src/docs/core-update_db.txt | 6 -- src/php/wp-cli/commands/internals/cache.php | 12 +--- src/php/wp-cli/commands/internals/core.php | 3 +- src/php/wp-cli/commands/internals/help.php | 2 +- src/php/wp-cli/commands/internals/user.php | 3 +- src/php/wp-cli/dispatcher.php | 56 ++++++++++--------- src/php/wp-cli/wp-cli.php | 4 +- 15 files changed, 89 insertions(+), 91 deletions(-) create mode 100644 man/core-install-network.1 create mode 100644 man/core-update-db.1 rename src/docs/{core-install_network.txt => core-install-network.txt} (62%) create mode 100644 src/docs/core-update-db.txt delete mode 100644 src/docs/core-update_db.txt diff --git a/man/cache.1 b/man/cache.1 index 553960fad..8d4bfc487 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CACHE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CACHE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-cache\fR \- Manage WordPress the object cache\. @@ -10,10 +10,10 @@ wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] . .P -wp cache add_global_groups \fIgroup\fR +wp cache add\-global\-groups \fIgroup\fR . .P -wp cache add_non_persistent_groups \fIgroup\fR +wp cache add\-non\-persistent\-groups \fIgroup\fR . .P wp cache decr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] @@ -51,13 +51,13 @@ wp cache type Add a value to cache where \fIkey\fR in \fIgroup\fR does not already exist\. . .TP -\fBadd_global_groups\fR: +\fBadd\-global\-groups\fR: . .IP Add a value to the global groups array\. . .TP -\fBadd_non_persistent_groups\fR: +\fBadd\-non\-persistent\-groups\fR: . .IP Add a value to the non persistent groups array\. diff --git a/man/core-install-network.1 b/man/core-install-network.1 new file mode 100644 index 000000000..d849532c3 --- /dev/null +++ b/man/core-install-network.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-INSTALL\-NETWORK" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-install\-network\fR \- Transform a single\-site install into a +. +.SH "SYNOPSIS" +\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=/] +. +.SH "OPTIONS" +. +.TP +\fB\-\-title\fR=\fIsite\-title\fR: +. +.IP +The title of the new network\. +. +.TP +\fB\-\-base_path\fR=\fIpath\fR: +. +.IP +Base path after the domain name that each site url will start with\. + diff --git a/man/core-install_network.1 b/man/core-install_network.1 index 6aad5aa0f..995c5436f 100644 --- a/man/core-install_network.1 +++ b/man/core-install_network.1 @@ -1,25 +1,3 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-INSTALL_NETWORK" "1" "September 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-install_network\fR \- Transform a single\-site install into a -. -.SH "SYNOPSIS" -\fBwp core install_network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=/] -. -.SH "OPTIONS" -. -.TP -\fB\-\-title\fR=\fIsite\-title\fR: -. -.IP -The title of the new network\. -. -.TP -\fB\-\-base_path\fR=\fIpath\fR: -. -.IP -Base path after the domain name that each site url will start with\. diff --git a/man/core-update-db.1 b/man/core-update-db.1 new file mode 100644 index 000000000..87d2dbdb9 --- /dev/null +++ b/man/core-update-db.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-UPDATE\-DB" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-update\-db\fR \- Update the WordPress database\. +. +.SH "SYNOPSIS" +\fBwp core update\-db\fR diff --git a/man/core-update_db.1 b/man/core-update_db.1 index dc5a11563..995c5436f 100644 --- a/man/core-update_db.1 +++ b/man/core-update_db.1 @@ -1,10 +1,3 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-UPDATE_DB" "1" "September 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-update_db\fR \- Update the WordPress database\. -. -.SH "SYNOPSIS" -\fBwp core update_db\fR + diff --git a/src/docs/cache.txt b/src/docs/cache.txt index 069a875d3..c45986294 100644 --- a/src/docs/cache.txt +++ b/src/docs/cache.txt @@ -5,9 +5,9 @@ wp-cache(1) -- Manage WordPress the object cache. wp cache add <key> <value> [<group>] [<expiration>] -wp cache add_global_groups <group> +wp cache add-global-groups <group> -wp cache add_non_persistent_groups <group> +wp cache add-non-persistent-groups <group> wp cache decr <key> [<offset>] [<group>] @@ -33,11 +33,11 @@ wp cache type Add a value to cache where <key> in <group> does not already exist. -* `add_global_groups`: +* `add-global-groups`: Add a value to the global groups array. -* `add_non_persistent_groups`: +* `add-non-persistent-groups`: Add a value to the non persistent groups array. diff --git a/src/docs/core-install_network.txt b/src/docs/core-install-network.txt similarity index 62% rename from src/docs/core-install_network.txt rename to src/docs/core-install-network.txt index d40d94648..30c37441d 100644 --- a/src/docs/core-install_network.txt +++ b/src/docs/core-install-network.txt @@ -1,10 +1,10 @@ -wp-core-install_network(1) -- Transform a single-site install into a +wp-core-install-network(1) -- Transform a single-site install into a multi-site install. ==== ## SYNOPSIS -`wp core install_network` --title=<network-title> [--base_path=/] +`wp core install-network` --title=<network-title> [--base_path=/] ## OPTIONS diff --git a/src/docs/core-update-db.txt b/src/docs/core-update-db.txt new file mode 100644 index 000000000..b199312fd --- /dev/null +++ b/src/docs/core-update-db.txt @@ -0,0 +1,6 @@ +wp-core-update-db(1) -- Update the WordPress database. +==== + +## SYNOPSIS + +`wp core update-db` diff --git a/src/docs/core-update_db.txt b/src/docs/core-update_db.txt deleted file mode 100644 index 746447513..000000000 --- a/src/docs/core-update_db.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-core-update_db(1) -- Update the WordPress database. -==== - -## SYNOPSIS - -`wp core update_db` diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index 5c1233994..adf345403 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -42,11 +42,7 @@ public function add( $args, $assoc_args ) { /** * Add global cache groups. * - * @uses wp_cache_add_global_groups - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @subcommand add-global-groups */ public function add_global_groups( $args, $assoc_args ) { if ( empty( $args ) ) { @@ -62,11 +58,7 @@ public function add_global_groups( $args, $assoc_args ) { /** * Adds a non-persistent group to the list. * - * @uses wp_cache_add_non_persistent_groups - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @subcommand add-non-persistent-groups */ public function add_non_persistent_groups( $args, $assoc_args ) { if ( empty( $args ) ) { diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 2da3efe8a..8f177ff35 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -253,8 +253,7 @@ function update( $args, $assoc_args ) { /** * Update the WordPress database * - * @param array $args - * @param array $assoc_args + * @subcommand update-db */ function update_db() { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index b4059ba1a..e46bf1dcd 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -39,7 +39,7 @@ function general_help() { $out = " wp $command"; - $methods = \WP_CLI\Dispatcher\get_subcommands( $class ); + $methods = array_keys( \WP_CLI\Dispatcher\get_subcommands( $class ) ); if ( !empty( $methods ) ) { $out .= ' [' . implode( '|', $methods ) . ']'; diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 4fbceb097..50fbbb8e9 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -13,8 +13,7 @@ class User_Command extends WP_CLI_Command { /** * List users * - * @param array $args - * @param array $assoc_args + * @subcommand list **/ public function _list( $args, $assoc_args ) { global $blog_id; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 9a26071fb..1b1cd4837 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -19,33 +19,34 @@ function dispatch_subcommand( $class, $args, $assoc_args ) { if ( empty( $args ) ) { $subcommand = $class::get_default_subcommand(); } else { - $subcommand = subcommand_to_method( $class, array_shift( $args ) ); + $subcommand = array_shift( $args ); } - if ( !$subcommand ) { + $method = subcommand_to_method( $class, $subcommand ); + + if ( !$method ) { describe_command( $class, WP_CLI_COMMAND ); return; } $instance = new $class; - $instance->$subcommand( $args, $assoc_args ); + + $method->invoke( $instance, $args, $assoc_args ); } -function subcommand_to_method( $class, $command ) { +function subcommand_to_method( $class, $subcommand ) { $aliases = $class::get_aliases(); if ( isset( $aliases[ $subcommand ] ) ) { - $method = $aliases[ $subcommand ]; + $subcommand = $aliases[ $subcommand ]; } - if ( !method_exists( $class, $subcommand ) ) { - // This if for reserved keywords in php (like list, isset) - $subcommand = '_' . $subcommand; - } + $subcommands = get_subcommands( $class ); - if ( !method_exists( $class, $method ) ) { + if ( !isset( $subcommands[ $subcommand ] ) ) return false; - } + + return $subcommands[ $subcommand ]; } function describe_command( $class, $command ) { @@ -54,7 +55,7 @@ function describe_command( $class, $command ) { return; } - $methods = get_subcommands( $class ); + $methods = array_keys( get_subcommands( $class ) ); $out = "usage: wp $command"; @@ -74,7 +75,7 @@ function describe_command( $class, $command ) { * Get the list of subcommands for a class (reverse-dispatch). * * @param string $class - * @return array The list of methods + * @return array('subcommand' => $method) The list of methods */ function get_subcommands( $class ) { if ( !is_string( $class ) ) @@ -82,27 +83,28 @@ function get_subcommands( $class ) { $reflection = new \ReflectionClass( $class ); - return _filter_methods( $reflection, function( $method ) { - $name = $method->name; - - if ( strpos( $name, '_' ) === 0 ) { - $name = substr( $name, 1 ); - } - - return $name; - } ); -} - -function _filter_methods( $reflection, $cb ) { $methods = array(); foreach ( $reflection->getMethods() as $method ) { - if ( !$method->isPublic() || $method->isStatic() || $method->isConstructor() ) + if ( !_is_good_method( $method ) ) continue; - $methods[] = $cb( $method ); + $methods[ _get_subcommand_name( $method ) ] = $method; } return $methods; } +function _is_good_method( $method ) { + return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); +} + +function _get_subcommand_name( $method ) { + $comment = $method->getDocComment(); + + if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + return $matches[1]; + + return $method->name; +} + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 25199d918..3605093ec 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -128,8 +128,8 @@ // Generate strings for autocomplete if ( WP_CLI_AUTOCOMPLETE ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { - $subcommands = implode( ' ', WP_CLI\Dispatcher\get_subcommands( $command ) ); - WP_CLI::line( $name . ' ' . $subcommands ); + $subcommands = array_keys( WP_CLI\Dispatcher\get_subcommands( $command ) ); + WP_CLI::line( $name . ' ' . implode( ' ', $subcommands ) ); } exit; } From f01c0bcd5052b4f1c22e8200681c5f494edfa813 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Oct 2012 02:04:13 +0300 Subject: [PATCH 0609/5359] remove cache subcommands that have ephemeral side-effects --- man/cache.1 | 18 ------------ src/docs/cache.txt | 12 -------- src/php/wp-cli/commands/internals/cache.php | 32 --------------------- 3 files changed, 62 deletions(-) diff --git a/man/cache.1 b/man/cache.1 index 8d4bfc487..291f65dd1 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -10,12 +10,6 @@ wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] . .P -wp cache add\-global\-groups \fIgroup\fR -. -.P -wp cache add\-non\-persistent\-groups \fIgroup\fR -. -.P wp cache decr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] . .P @@ -51,18 +45,6 @@ wp cache type Add a value to cache where \fIkey\fR in \fIgroup\fR does not already exist\. . .TP -\fBadd\-global\-groups\fR: -. -.IP -Add a value to the global groups array\. -. -.TP -\fBadd\-non\-persistent\-groups\fR: -. -.IP -Add a value to the non persistent groups array\. -. -.TP \fBdecr\fR: . .IP diff --git a/src/docs/cache.txt b/src/docs/cache.txt index c45986294..d395a4d5f 100644 --- a/src/docs/cache.txt +++ b/src/docs/cache.txt @@ -5,10 +5,6 @@ wp-cache(1) -- Manage WordPress the object cache. wp cache add <key> <value> [<group>] [<expiration>] -wp cache add-global-groups <group> - -wp cache add-non-persistent-groups <group> - wp cache decr <key> [<offset>] [<group>] wp cache delete <key> <group> @@ -33,14 +29,6 @@ wp cache type Add a value to cache where <key> in <group> does not already exist. -* `add-global-groups`: - - Add a value to the global groups array. - -* `add-non-persistent-groups`: - - Add a value to the non persistent groups array. - * `decr`: Decrement the value of a cached object by 1 or the value of the <offset> parameter. diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index adf345403..d595ce986 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -39,38 +39,6 @@ public function add( $args, $assoc_args ) { WP_CLI::success( "Added object '$key' in group '$group'." ); } - /** - * Add global cache groups. - * - * @subcommand add-global-groups - */ - public function add_global_groups( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache add_global_groups <group>' ); - exit; - } - - $group = $args[0]; - - wp_cache_add_global_groups( $group ); - } - - /** - * Adds a non-persistent group to the list. - * - * @subcommand add-non-persistent-groups - */ - public function add_non_persistent_groups( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache add_non_persistent_groups <group>' ); - exit; - } - - $group = $args[0]; - - wp_cache_add_non_persistent_groups( $group ); - } - /** * Decrement a value in the object cache. * From 983b21e06ed04d6dd855b04b84b76c85e4fd37c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 15:26:46 +0300 Subject: [PATCH 0610/5359] remove nonexistant command from cache docs --- man/cache.1 | 3 --- man/core-install_network.1 | 3 --- man/core-update_db.1 | 3 --- src/docs/cache.txt | 2 -- 4 files changed, 11 deletions(-) delete mode 100644 man/core-install_network.1 delete mode 100644 man/core-update_db.1 diff --git a/man/cache.1 b/man/cache.1 index 291f65dd1..0788dfb51 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -31,9 +31,6 @@ wp cache replace \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] wp cache set \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] . .P -wp cache switch_to_blog \fIblog_id\fR -. -.P wp cache type . .SH "SUBCOMMANDS" diff --git a/man/core-install_network.1 b/man/core-install_network.1 deleted file mode 100644 index 995c5436f..000000000 --- a/man/core-install_network.1 +++ /dev/null @@ -1,3 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 - diff --git a/man/core-update_db.1 b/man/core-update_db.1 deleted file mode 100644 index 995c5436f..000000000 --- a/man/core-update_db.1 +++ /dev/null @@ -1,3 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 - diff --git a/src/docs/cache.txt b/src/docs/cache.txt index d395a4d5f..bd2d0f286 100644 --- a/src/docs/cache.txt +++ b/src/docs/cache.txt @@ -19,8 +19,6 @@ wp cache replace <key> <value> [<group>] [<expiration>] wp cache set <key> <value> [<group>] [<expiration>] -wp cache switch_to_blog <blog_id> - wp cache type ## SUBCOMMANDS From 82c89cdc3b49570855dfb550044b639552fd9f50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 15:28:25 +0300 Subject: [PATCH 0611/5359] rename install_network to install-network --- src/php/wp-cli/commands/internals/core.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 8f177ff35..e433658e5 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -88,6 +88,9 @@ public function install( $args, $assoc_args ) { } } + /** + * @subcommand install-network + */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) WP_CLI::error( 'This already is a multisite install.' ); From 1c788d8f92ef1839aec8e1b960c03a8a30ca5201 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 16:10:12 +0300 Subject: [PATCH 0612/5359] first pass at @synopsis tag --- src/php/wp-cli/commands/internals/blog.php | 10 ++----- src/php/wp-cli/dispatcher.php | 35 +++++++++++++++------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index b1efc2ce3..070e11885 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -12,10 +12,6 @@ */ class Blog_Command extends WP_CLI_Command { - private function _create_usage_string() { - return "usage: wp blog create --slug=<subdomain or directory name> --title=<blog title> [--email] [--site_id] [--private]"; - } - /** * Get site (network) data for a given id * @@ -35,11 +31,9 @@ private function _get_site( $site_id ) { } /** - * Create a blog via passed in arguments + * Create a blog in a multisite install. * - * @see BlogCommand::help() - * @param array $args - * @param array $assoc_args + * @synopsis --slug=<slug> --title=<Title> [--email=<email>] [--site_id=<site-id>] [--public] */ public function create( $args, $assoc_args ) { global $wpdb; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 1b1cd4837..3cb97d51d 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -55,24 +55,30 @@ function describe_command( $class, $command ) { return; } - $methods = array_keys( get_subcommands( $class ) ); - - $out = "usage: wp $command"; + $methods = get_subcommands( $class ); if ( empty( $methods ) ) { - \WP_CLI::line( $out ); - } else { - $out .= ' [' . implode( '|', $methods ) . ']'; + \WP_CLI::line( "usage: wp $command" ); + return; + } - \WP_CLI::line( $out ); + $i = 0; - \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); + foreach ( $methods as $subcommand => $method ) { + $synopsis = _get_subcommand_synopsis( $method ); + + $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; + + $desc = "wp $command $subcommand $synopsis"; + \WP_CLI::line( $prefix . $desc ); } + + \WP_CLI::line(); + \WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); } /** - * Get the list of subcommands for a class (reverse-dispatch). + * Get the list of subcommands for a class. * * @param string $class * @return array('subcommand' => $method) The list of methods @@ -108,3 +114,12 @@ function _get_subcommand_name( $method ) { return $method->name; } +function _get_subcommand_synopsis( $method ) { + $comment = $method->getDocComment(); + + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) + return false; + + return $matches[1]; +} + From f467e3cbd977197c4bfdc64f62435ae90339f7fb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 16:17:18 +0300 Subject: [PATCH 0613/5359] use get_aliases() in remaining places --- src/php/wp-cli/class-wp-cli-command-with-meta.php | 10 ++++++---- src/php/wp-cli/class-wp-cli-command.php | 2 +- src/php/wp-cli/commands/internals/db.php | 6 +++++- src/php/wp-cli/commands/internals/option.php | 8 +++++--- src/php/wp-cli/commands/internals/rewrite.php | 3 --- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/src/php/wp-cli/class-wp-cli-command-with-meta.php index 62934e48b..d636fd809 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-meta.php +++ b/src/php/wp-cli/class-wp-cli-command-with-meta.php @@ -7,11 +7,13 @@ */ abstract class WP_CLI_Command_With_Meta extends WP_CLI_Command { - protected $meta_type; + public static function get_aliases() { + return array( + 'set' => 'update' + ); + } - protected $aliases = array( - 'set' => 'update' - ); + protected $meta_type; /** * Get meta field value diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 9bd137b85..c8166549c 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -11,7 +11,7 @@ public static function get_default_subcommand() { return false; } - static function get_aliases() { + public static function get_aliases() { return array(); } diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index b426d30a3..2a2eb1be3 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -14,7 +14,11 @@ public static function get_default_subcommand() { return 'cli'; } - protected $aliases = array( 'dump' => 'export' ); + public static function get_aliases() { + return array( + 'dump' => 'export' + ); + } /** * Creates the database specified in the wp-config.php file. diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 861e05eae..ee3071e4b 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -10,9 +10,11 @@ */ class Option_Command extends WP_CLI_Command { - protected $aliases = array( - 'set' => 'update' - ); + public static function get_aliases() { + return array( + 'set' => 'update' + ); + } /** * Add an option diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/internals/rewrite.php index feb28d45f..87ea5da60 100644 --- a/src/php/wp-cli/commands/internals/rewrite.php +++ b/src/php/wp-cli/commands/internals/rewrite.php @@ -10,9 +10,6 @@ */ class Rewrite_Command extends WP_CLI_Command { - protected $aliases = array( - ); - /** * Flush rules * From b2bfff5560925dc44cfc739c03c5d4ca7057049f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 16:26:06 +0300 Subject: [PATCH 0614/5359] add synopsis for option subcommands --- src/php/wp-cli/commands/internals/option.php | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index ee3071e4b..d843083db 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -17,13 +17,13 @@ public static function get_aliases() { } /** - * Add an option + * Add an option. * - * @param array $args - **/ + * @synopsis <key> <value> [--json] + */ public function add( $args, $assoc_args ) { if ( count( $args ) < 2 ) { - WP_CLI::line( "usage: wp option add <option-name> <option-value>" ); + WP_CLI::line( "usage: wp option add <key> <value>" ); exit; } @@ -39,11 +39,11 @@ public function add( $args, $assoc_args ) { /** * Update an option * - * @param array $args + * @synopsis <key> <value> [--json] **/ public function update( $args, $assoc_args ) { if ( count( $args ) < 2 ) { - WP_CLI::line( "usage: wp option update <option-name> <option-value>" ); + WP_CLI::line( "usage: wp option update <key> <value>" ); exit; } @@ -62,11 +62,11 @@ public function update( $args, $assoc_args ) { /** * Delete an option * - * @param array $args - **/ + * @synopsis <key> + */ public function delete( $args ) { if ( empty( $args ) ) { - WP_CLI::line( "usage: wp option get <option-name>" ); + WP_CLI::line( "usage: wp option delete <key>" ); exit; } @@ -80,11 +80,11 @@ public function delete( $args ) { /** * Get an option * - * @param array $args - **/ + * @synopsis <key> [--json] + */ public function get( $args, $assoc_args ) { if ( empty( $args ) ) { - WP_CLI::line( "usage: wp option get <option-name>" ); + WP_CLI::line( "usage: wp option get <key>" ); exit; } From b26b755c59c9e059d5d436190fd4d6371d8ea718 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 16:41:44 +0300 Subject: [PATCH 0615/5359] introduce Subcommand class --- src/php/wp-cli/dispatcher.php | 81 ++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 3cb97d51d..a8c9221c7 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -16,37 +16,37 @@ function dispatch( $implementation, $arguments, $assoc_args ) { * @param array $assoc_args */ function dispatch_subcommand( $class, $args, $assoc_args ) { - if ( empty( $args ) ) { - $subcommand = $class::get_default_subcommand(); - } else { - $subcommand = array_shift( $args ); - } + $subcommand = find_subcommand( $class, $args ); - $method = subcommand_to_method( $class, $subcommand ); - - if ( !$method ) { + if ( !$subcommand ) { describe_command( $class, WP_CLI_COMMAND ); return; } $instance = new $class; - $method->invoke( $instance, $args, $assoc_args ); + $subcommand->invoke( $instance, $args, $assoc_args ); } -function subcommand_to_method( $class, $subcommand ) { +function find_subcommand( $class, $args ) { + if ( empty( $args ) ) { + $name = $class::get_default_subcommand(); + } else { + $name = array_shift( $args ); + } + $aliases = $class::get_aliases(); - if ( isset( $aliases[ $subcommand ] ) ) { - $subcommand = $aliases[ $subcommand ]; + if ( isset( $aliases[ $name ] ) ) { + $name = $aliases[ $name ]; } $subcommands = get_subcommands( $class ); - if ( !isset( $subcommands[ $subcommand ] ) ) + if ( !isset( $subcommands[ $name ] ) ) return false; - return $subcommands[ $subcommand ]; + return $subcommands[ $name ]; } function describe_command( $class, $command ) { @@ -64,13 +64,10 @@ function describe_command( $class, $command ) { $i = 0; - foreach ( $methods as $subcommand => $method ) { - $synopsis = _get_subcommand_synopsis( $method ); - - $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; + foreach ( $methods as $name => $subcommand ) { + $prefix = ( 0 == $i++ ) ? 'usage:' : ' or:'; - $desc = "wp $command $subcommand $synopsis"; - \WP_CLI::line( $prefix . $desc ); + \WP_CLI::line( "$prefix wp $command $name " . $subcommand->get_synopsis() ); } \WP_CLI::line(); @@ -81,7 +78,7 @@ function describe_command( $class, $command ) { * Get the list of subcommands for a class. * * @param string $class - * @return array('subcommand' => $method) The list of methods + * @return array('subcommand' => Subcommand) The list of subcommands */ function get_subcommands( $class ) { if ( !is_string( $class ) ) @@ -89,37 +86,51 @@ function get_subcommands( $class ) { $reflection = new \ReflectionClass( $class ); - $methods = array(); + $subcommands = array(); foreach ( $reflection->getMethods() as $method ) { if ( !_is_good_method( $method ) ) continue; - $methods[ _get_subcommand_name( $method ) ] = $method; + $subcommand = new Subcommand( $method ); + + $subcommands[ $subcommand->get_name() ] = $subcommand; } - return $methods; + return $subcommands; } function _is_good_method( $method ) { return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } -function _get_subcommand_name( $method ) { - $comment = $method->getDocComment(); - if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) - return $matches[1]; +class Subcommand { - return $method->name; -} + function __construct( $method ) { + $this->method = $method; + } -function _get_subcommand_synopsis( $method ) { - $comment = $method->getDocComment(); + function get_name() { + $comment = $this->method->getDocComment(); - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) - return false; + if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + return $matches[1]; + + return $this->method->name; + } + + function get_synopsis() { + $comment = $this->method->getDocComment(); - return $matches[1]; + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) + return false; + + return $matches[1]; + } + + function invoke() { + return call_user_func_array( array( $this->method, 'invoke' ), func_get_args() ); + } } From 89c3ab8b5d4ada6b340d76a5548d731e4b329f22 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 17:33:11 +0300 Subject: [PATCH 0616/5359] add validation for mandatory positional args --- src/php/wp-cli/dispatcher.php | 83 ++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index a8c9221c7..8e26eb296 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -65,9 +65,9 @@ function describe_command( $class, $command ) { $i = 0; foreach ( $methods as $name => $subcommand ) { - $prefix = ( 0 == $i++ ) ? 'usage:' : ' or:'; + $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - \WP_CLI::line( "$prefix wp $command $name " . $subcommand->get_synopsis() ); + $subcommand->show_usage( $prefix ); } \WP_CLI::line(); @@ -92,7 +92,7 @@ function get_subcommands( $class ) { if ( !_is_good_method( $method ) ) continue; - $subcommand = new Subcommand( $method ); + $subcommand = new Subcommand( $method, 'TODO' ); $subcommands[ $subcommand->get_name() ] = $subcommand; } @@ -107,8 +107,9 @@ function _is_good_method( $method ) { class Subcommand { - function __construct( $method ) { + function __construct( $method, $command ) { $this->method = $method; + $this->command = $command; } function get_name() { @@ -120,7 +121,19 @@ function get_name() { return $this->method->name; } - function get_synopsis() { + function show_usage( $prefix = 'usage: ' ) { + $name = $this->get_name(); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); + } + + function invoke( $instance, $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + return $this->method->invoke( $instance, $args, $assoc_args ); + } + + protected function get_synopsis() { $comment = $this->method->getDocComment(); if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) @@ -129,8 +142,64 @@ function get_synopsis() { return $matches[1]; } - function invoke() { - return call_user_func_array( array( $this->method, 'invoke' ), func_get_args() ); + protected function check_args( $args, $assoc_args ) { + $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); + + $mandatory_positinal = wp_list_filter( $accepted_params, array( + 'type' => 'positional', + 'optional' => false + ) ); + + if ( count( $args ) < count( $mandatory_positinal ) ) { + $this->show_usage(); + exit(1); + } + } + + protected function parse_synopsis( $synopsis ) { + $patterns = self::get_patterns(); + + $tokens = preg_split( '/[\s\t]+/', $synopsis ); + + $params = array(); + + foreach ( $tokens as $token ) { + foreach ( $patterns as $regex => $desc ) { + if ( preg_match( $regex, $token, $matches ) ) { + $params[] = array_merge( $matches, $desc ); + break; + } + } + } + + return $params; + } + + private static function get_patterns() { + $p_name = '(?P<name>[a-z-]+)'; + $p_value = '<(?P<value>[a-z-]+)>'; + + $param_types = array( + 'positional' => $p_value, + 'assoc' => "--$p_name=$p_value", + 'flag' => "--$p_name" + ); + + $patterns = array(); + + foreach ( $param_types as $type => $pattern ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } + + return $patterns; } } From 95e77c66963696d5a7aecca73f8d94c6664969a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 18:06:50 +0300 Subject: [PATCH 0617/5359] introduce SimpleCommand and CompositeCommand --- src/php/wp-cli/class-wp-cli.php | 13 +- src/php/wp-cli/commands/internals/help.php | 18 +-- src/php/wp-cli/dispatcher.php | 158 ++++++++++++--------- src/php/wp-cli/wp-cli.php | 3 +- 4 files changed, 106 insertions(+), 86 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 17507abd0..8e2a7292f 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -15,8 +15,13 @@ class WP_CLI { * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command */ - public function add_command( $name, $class ) { - self::$commands[$name] = $class; + public function add_command( $name, $implementation ) { + if ( is_string( $implementation ) && class_exists( $implementation ) ) + $class = '\WP_CLI\Dispatcher\CompositeCommand'; + else + $class = '\WP_CLI\Dispatcher\SimpleCommand'; + + self::$commands[ $name ] = new $class( $implementation, $name ); } /** @@ -333,9 +338,9 @@ static function run_command( $arguments, $assoc_args ) { define( 'WP_CLI_COMMAND', $command ); - $implementation = self::load_command( $command ); + $command = self::load_command( $command ); - \WP_CLI\Dispatcher\dispatch( $implementation, $arguments, $assoc_args ); + $command->invoke( $arguments, $assoc_args ); } static function load_command( $command ) { diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index e46bf1dcd..0aced7af8 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -27,25 +27,17 @@ function maybe_load_man_page( $args ) { } function show_available_subcommands( $command ) { - $class = \WP_CLI::load_command( $command ); - \WP_CLI\Dispatcher\describe_command( $class, $command ); + $command = \WP_CLI::load_command( $command ); + $command->show_usage(); } function general_help() { \WP_CLI::line( 'Available commands:' ); - foreach ( \WP_CLI::load_all_commands() as $command => $class ) { - if ( 'help' == $command ) + foreach ( \WP_CLI::load_all_commands() as $name => $command ) { + if ( 'help' == $name ) continue; - $out = " wp $command"; - - $methods = array_keys( \WP_CLI\Dispatcher\get_subcommands( $class ) ); - - if ( !empty( $methods ) ) { - $out .= ' [' . implode( '|', $methods ) . ']'; - } - - \WP_CLI::line( $out ); + \WP_CLI::line( " wp $name " . $command->shortdesc() ); } \WP_CLI::line(<<<EOB diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 8e26eb296..1567a6cb1 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -2,106 +2,130 @@ namespace WP_CLI\Dispatcher; -function dispatch( $implementation, $arguments, $assoc_args ) { - if ( is_string( $implementation ) && class_exists( $implementation ) ) - dispatch_subcommand( $implementation, $arguments, $assoc_args ); - else - call_user_func( $implementation, $arguments, $assoc_args ); +abstract class Command { + + function __construct( $implementation, $name ) { + $this->implementation = $implementation; + $this->name = $name; + } + + abstract function autocomplete(); + abstract function shortdesc(); + abstract function show_usage(); + abstract function invoke( $arguments, $assoc_args ); } -/** - * Transfers the handling to the appropriate method - * - * @param array $args - * @param array $assoc_args - */ -function dispatch_subcommand( $class, $args, $assoc_args ) { - $subcommand = find_subcommand( $class, $args ); - if ( !$subcommand ) { - describe_command( $class, WP_CLI_COMMAND ); - return; +class SimpleCommand extends Command { + + function autocomplete() { + return $this->name; } - $instance = new $class; + function shortdesc() { + return ''; + } + + function show_usage() { + \WP_CLI::line( "usage: wp $this->name" ); + } - $subcommand->invoke( $instance, $args, $assoc_args ); + function invoke( $arguments, $assoc_args ) { + call_user_func( $this->implementation, $arguments, $assoc_args ); + } } -function find_subcommand( $class, $args ) { - if ( empty( $args ) ) { - $name = $class::get_default_subcommand(); - } else { - $name = array_shift( $args ); + +class CompositeCommand extends Command { + + function autocomplete() { + $subcommands = array_keys( $this->get_subcommands() ); + return $this->name . ' ' . implode( ' ', $subcommands ); } - $aliases = $class::get_aliases(); + function shortdesc() { + $methods = array_keys( $this->get_subcommands() ); - if ( isset( $aliases[ $name ] ) ) { - $name = $aliases[ $name ]; + return implode( '|', $methods ); } - $subcommands = get_subcommands( $class ); + function show_usage() { + if ( method_exists( $this->implementation, 'help' ) ) { + $class::help(); + return; + } - if ( !isset( $subcommands[ $name ] ) ) - return false; + $methods = $this->get_subcommands(); - return $subcommands[ $name ]; -} + $i = 0; -function describe_command( $class, $command ) { - if ( method_exists( $class, 'help' ) ) { - $class::help(); - return; - } + foreach ( $methods as $name => $subcommand ) { + $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - $methods = get_subcommands( $class ); + $subcommand->show_usage( $prefix ); + } - if ( empty( $methods ) ) { - \WP_CLI::line( "usage: wp $command" ); - return; + \WP_CLI::line(); + \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); } - $i = 0; + function invoke( $args, $assoc_args ) { + $subcommand = $this->find_subcommand( $args ); + + if ( !$subcommand ) { + $this->show_usage(); + return; + } - foreach ( $methods as $name => $subcommand ) { - $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; + $class = $this->implementation; + $instance = new $class; - $subcommand->show_usage( $prefix ); + $subcommand->invoke( $instance, $args, $assoc_args ); } - \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $command <subcommand>' for more information on a specific subcommand." ); -} + protected function find_subcommand( $args ) { + $class = $this->implementation; -/** - * Get the list of subcommands for a class. - * - * @param string $class - * @return array('subcommand' => Subcommand) The list of subcommands - */ -function get_subcommands( $class ) { - if ( !is_string( $class ) ) - return array(); + if ( empty( $args ) ) { + $name = $class::get_default_subcommand(); + } else { + $name = array_shift( $args ); + } - $reflection = new \ReflectionClass( $class ); + $aliases = $class::get_aliases(); - $subcommands = array(); + if ( isset( $aliases[ $name ] ) ) { + $name = $aliases[ $name ]; + } - foreach ( $reflection->getMethods() as $method ) { - if ( !_is_good_method( $method ) ) - continue; + $subcommands = $this->get_subcommands(); - $subcommand = new Subcommand( $method, 'TODO' ); + if ( !isset( $subcommands[ $name ] ) ) + return false; - $subcommands[ $subcommand->get_name() ] = $subcommand; + return $subcommands[ $name ]; } - return $subcommands; -} + protected function get_subcommands() { + $reflection = new \ReflectionClass( $this->implementation ); + + $subcommands = array(); -function _is_good_method( $method ) { - return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); + foreach ( $reflection->getMethods() as $method ) { + if ( !self::_is_good_method( $method ) ) + continue; + + $subcommand = new Subcommand( $method, $this->name ); + + $subcommands[ $subcommand->get_name() ] = $subcommand; + } + + return $subcommands; + } + + private static function _is_good_method( $method ) { + return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); + } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 3605093ec..016fd3a5a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -128,8 +128,7 @@ // Generate strings for autocomplete if ( WP_CLI_AUTOCOMPLETE ) { foreach ( WP_CLI::load_all_commands() as $name => $command ) { - $subcommands = array_keys( WP_CLI\Dispatcher\get_subcommands( $command ) ); - WP_CLI::line( $name . ' ' . implode( ' ', $subcommands ) ); + WP_CLI::line( $command->autocomplete() ); } exit; } From 59d71ac8233e7a3c5f8322aa5efcf1f945593a6a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 18:52:57 +0300 Subject: [PATCH 0618/5359] remove first argument again, which represents the subcommand --- src/php/wp-cli/dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 1567a6cb1..92adbfb83 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -83,7 +83,7 @@ function invoke( $args, $assoc_args ) { $subcommand->invoke( $instance, $args, $assoc_args ); } - protected function find_subcommand( $args ) { + protected function find_subcommand( &$args ) { $class = $this->implementation; if ( empty( $args ) ) { From 3b7b50e8a1836f2536a6cecd775109177475145d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 18:54:59 +0300 Subject: [PATCH 0619/5359] remove redundant arg checking inside option subcommands --- src/php/wp-cli/commands/internals/option.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index d843083db..966055579 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -22,11 +22,6 @@ public static function get_aliases() { * @synopsis <key> <value> [--json] */ public function add( $args, $assoc_args ) { - if ( count( $args ) < 2 ) { - WP_CLI::line( "usage: wp option add <key> <value>" ); - exit; - } - $key = $args[0]; $value = WP_CLI::read_value( $args[1], $assoc_args ); @@ -42,11 +37,6 @@ public function add( $args, $assoc_args ) { * @synopsis <key> <value> [--json] **/ public function update( $args, $assoc_args ) { - if ( count( $args ) < 2 ) { - WP_CLI::line( "usage: wp option update <key> <value>" ); - exit; - } - $key = $args[0]; $value = WP_CLI::read_value( $args[1], $assoc_args ); @@ -65,11 +55,6 @@ public function update( $args, $assoc_args ) { * @synopsis <key> */ public function delete( $args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp option delete <key>" ); - exit; - } - list( $key ) = $args; if ( !delete_option( $key ) ) { @@ -83,11 +68,6 @@ public function delete( $args ) { * @synopsis <key> [--json] */ public function get( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp option get <key>" ); - exit; - } - list( $key ) = $args; $value = get_option( $key ); From fb988cf49521e96ad84cbf71621a30250646fd2f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 18:56:54 +0300 Subject: [PATCH 0620/5359] some reordering --- src/php/wp-cli/commands/internals/option.php | 32 ++++++++++---------- src/php/wp-cli/dispatcher.php | 18 +++++------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 966055579..0f3ddc0d3 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -16,6 +16,22 @@ public static function get_aliases() { ); } + /** + * Get an option + * + * @synopsis <key> [--json] + */ + public function get( $args, $assoc_args ) { + list( $key ) = $args; + + $value = get_option( $key ); + + if ( false === $value ) + die(1); + + WP_CLI::print_value( $value, $assoc_args ); + } + /** * Add an option. * @@ -61,20 +77,4 @@ public function delete( $args ) { WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); } } - - /** - * Get an option - * - * @synopsis <key> [--json] - */ - public function get( $args, $assoc_args ) { - list( $key ) = $args; - - $value = get_option( $key ); - - if ( false === $value ) - die(1); - - WP_CLI::print_value( $value, $assoc_args ); - } } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 92adbfb83..d6adacf20 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -157,15 +157,6 @@ function invoke( $instance, $args, $assoc_args ) { return $this->method->invoke( $instance, $args, $assoc_args ); } - protected function get_synopsis() { - $comment = $this->method->getDocComment(); - - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) - return false; - - return $matches[1]; - } - protected function check_args( $args, $assoc_args ) { $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); @@ -180,6 +171,15 @@ protected function check_args( $args, $assoc_args ) { } } + protected function get_synopsis() { + $comment = $this->method->getDocComment(); + + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) + return false; + + return $matches[1]; + } + protected function parse_synopsis( $synopsis ) { $patterns = self::get_patterns(); From 1ccdd2e6a34d5524f111cad1a1d2cd4eb47e5b63 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 19:07:02 +0300 Subject: [PATCH 0621/5359] check mandatory assoc args too --- src/php/wp-cli/commands/internals/blog.php | 14 +------------- src/php/wp-cli/dispatcher.php | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 070e11885..a9ebc6e62 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -33,23 +33,11 @@ private function _get_site( $site_id ) { /** * Create a blog in a multisite install. * - * @synopsis --slug=<slug> --title=<Title> [--email=<email>] [--site_id=<site-id>] [--public] + * @synopsis --slug=<slug> --title=<title> [--email=<email>] [--site_id=<site-id>] [--public] */ public function create( $args, $assoc_args ) { global $wpdb; - $has_errors = false; - - foreach ( array( 'slug', 'title' ) as $required ) { - if ( empty( $assoc_args[$required] ) ) { - WP_CLI::warning( "missing --$required parameter" ); - $has_errors = true; - } - } - - if ( $has_errors ) - exit(1); - $base = $assoc_args['slug']; $title = $assoc_args['title']; $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index d6adacf20..c368b7ce5 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -169,6 +169,28 @@ protected function check_args( $args, $assoc_args ) { $this->show_usage(); exit(1); } + + $mandatory_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( + 'type' => 'assoc', + 'optional' => false + ) ), 'name' ); + + $errors = array(); + + foreach ( $mandatory_assoc as $key ) { + if ( !isset( $assoc_args[ $key ] ) ) + $errors[] = "missing --$key parameter"; + elseif ( true === $assoc_args[ $key ] ) + $errors[] = "--$key parameter needs a value"; + } + + if ( empty( $errors ) ) + return; + + foreach ( $errors as $error ) + \WP_CLI::warning( $error ); + + exit(1); } protected function get_synopsis() { From 944ef1315ddff27f9f4905b63d63fbe32aee2c41 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 20:03:12 +0300 Subject: [PATCH 0622/5359] add @synopsis for plugin commands --- src/php/wp-cli/commands/internals/plugin.php | 51 ++++++++------------ 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index dfc3a1272..053d7bab8 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -46,12 +46,12 @@ protected function get_all_items() { } /** - * Activate a plugin + * Activate a plugin. * - * @param array $args + * @synopsis <plugin> [--network] */ function activate( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $network_wide = isset( $assoc_args['network'] ); @@ -65,12 +65,12 @@ function activate( $args, $assoc_args = array() ) { } /** - * Deactivate a plugin + * Deactivate a plugin. * - * @param array $args + * @synopsis <plugin> [--network] */ function deactivate( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $network_wide = isset( $assoc_args['network'] ); @@ -84,12 +84,12 @@ function deactivate( $args, $assoc_args = array() ) { } /** - * Toggle a plugin's activation state + * Toggle a plugin's activation state. * - * @param array $args + * @synopsis <plugin> [--network] */ function toggle( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $network_wide = isset( $assoc_args['network'] ); @@ -101,16 +101,15 @@ function toggle( $args, $assoc_args = array() ) { } /** - * Get a plugin path + * Get a plugin path. * - * @param array $args - * @param array $assoc_args + * @synopsis [<plugin>] [--dir] */ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $path .= '/' . $file; if ( isset( $assoc_args['dir'] ) ) @@ -174,10 +173,9 @@ protected function install_from_repo( $slug, $assoc_args ) { } /** - * Update a plugin (to the latest dev version) + * Update a plugin. * - * @param array $args - * @param array $assoc_args + * @synopsis [<plugin>] [--all] [--version=<version>] */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { @@ -204,12 +202,12 @@ protected function get_item_list() { } /** - * Uninstall a plugin + * Uninstall a plugin. * - * @param array $args + * @synopsis <plugin> [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); if ( is_plugin_active( $file ) ) { WP_CLI::error( 'The plugin is active.' ); @@ -222,12 +220,12 @@ function uninstall( $args, $assoc_args = array() ) { } /** - * Delete plugin files + * Delete plugin files. * - * @param array $args + * @synopsis <plugin> */ function delete( $args, $assoc_args = array(), $exit_on_error = true ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $plugin_dir = dirname( $file ); if ( '.' == $plugin_dir ) @@ -273,16 +271,9 @@ protected function get_details( $file ) { * Parse the name of a plugin to a filename, check if it exists * * @param array $args - * @param string $subcommand - * @param bool $exit * @return array */ - protected function parse_name( $args, $subcommand ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp plugin $subcommand <plugin-name>" ); - exit; - } - + protected function parse_name( $args ) { $name = $args[0]; $plugins = get_plugins( '/' . $name ); From 29e34dc3e73a28d3e1b7425da75bfa8c35accdce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 22:19:45 +0300 Subject: [PATCH 0623/5359] add synopsis for all theme subcommands --- .../class-wp-cli-command-with-upgrade.php | 25 ++-------- src/php/wp-cli/commands/internals/plugin.php | 18 +++++++ src/php/wp-cli/commands/internals/theme.php | 48 ++++++++++++++----- src/php/wp-cli/dispatcher.php | 2 +- 4 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 253724cb0..d11741b23 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -11,7 +11,7 @@ public static function get_default_subcommand() { protected $upgrade_refresh; protected $upgrade_transient; - abstract protected function parse_name( $args, $subcommand ); + abstract protected function parse_name( $args ); abstract protected function get_item_list(); abstract protected function get_all_items(); @@ -23,19 +23,14 @@ abstract protected function _status_single( $details, $name, $version, $status ) abstract protected function install_from_repo( $slug, $assoc_args ); - /** - * Get the status of one or all items - * - * @param array $args - */ - function status( $args = array() ) { + function status( $args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); if ( empty( $args ) ) { $this->status_all(); } else { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $this->status_single( $file, $name ); } @@ -96,12 +91,6 @@ private function status_single( $file, $name ) { $this->_status_single( $details, $name, $version, $status ); } - /** - * Install a new plugin/theme - * - * @param array $args - * @param array $assoc_args - */ function install( $args, $assoc_args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp $this->item_type install <slug>" ); @@ -131,17 +120,11 @@ function install( $args, $assoc_args ) { } } - /** - * Update a plugin/theme - * - * @param array $args - * @param array $assoc_args - */ function update( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); WP_CLI::get_upgrader( $this->upgrader )->upgrade( $file ); } else { diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 053d7bab8..7d93c962c 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -22,6 +22,15 @@ function __construct() { parent::__construct(); } + /** + * See the status of one or all plugins. + * + * @synopsis [<plugin>] + */ + function status( $args ) { + parent::status( $args ); + } + protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); @@ -201,6 +210,15 @@ protected function get_item_list() { return $items; } + /** + * Install a plugin from wordpress.org or from a zip file. + * + * @synopsis <plugin|zip> [--version=<version>] [--activate] + */ + function install( $args, $assoc_args ) { + parent::install( $args, $assoc_args ); + } + /** * Uninstall a plugin. * diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index bf0b34910..e86c5ede5 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -15,6 +15,15 @@ class Theme_Command extends WP_CLI_Command_With_Upgrade { protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; + /** + * See the status of one or all themes. + * + * @synopsis [<theme>] + */ + function status( $args ) { + parent::status( $args ); + } + protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( 'Theme %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); @@ -39,12 +48,12 @@ protected function get_details( $stylesheet ) { } /** - * Activate a theme + * Activate a theme. * - * @param array $args + * @synopsis <theme> **/ public function activate( $args = array() ) { - list( $stylesheet, $child ) = $this->parse_name( $args, __FUNCTION__ ); + list( $stylesheet, $child ) = $this->parse_name( $args ); $details = get_theme_data( $stylesheet ); @@ -72,16 +81,15 @@ private function is_active_theme( $stylesheet ) { } /** - * Get a theme path + * Get a theme path. * - * @param array $args - * @param array $assoc_args + * @synopsis [<theme>] [--dir] */ function path( $args, $assoc_args ) { if ( empty( $args ) ) { $path = WP_CONTENT_DIR . '/themes'; } else { - list( $stylesheet, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $stylesheet, $name ) = $this->parse_name( $args ); $path = $stylesheet; if ( isset( $assoc_args['dir'] ) ) @@ -144,12 +152,30 @@ protected function get_item_list() { } /** - * Delete a theme + * Install a theme from wordpress.org or from a zip file. + * + * @synopsis <theme|zip> [--version=<version>] [--activate] + */ + function install( $args, $assoc_args ) { + parent::install( $args, $assoc_args ); + } + + /** + * Update a theme. + * + * @synopsis [<theme>] [--all] + */ + function update( $args, $assoc_args ) { + parent::update( $args, $assoc_args ); + } + + /** + * Delete a theme. * - * @param array $args + * @synopsis <theme> */ function delete( $args ) { - list( $file, $name ) = $this->parse_name( $args, __FUNCTION__ ); + list( $file, $name ) = $this->parse_name( $args ); $r = delete_theme( $name ); @@ -158,7 +184,7 @@ function delete( $args ) { } } - protected function parse_name( $args, $subcommand ) { + protected function parse_name( $args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp theme $subcommand <theme-name>" ); exit; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index c368b7ce5..bbf2d8ba3 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -223,7 +223,7 @@ protected function parse_synopsis( $synopsis ) { private static function get_patterns() { $p_name = '(?P<name>[a-z-]+)'; - $p_value = '<(?P<value>[a-z-]+)>'; + $p_value = '<(?P<value>[a-z-|]+)>'; $param_types = array( 'positional' => $p_value, From 13493b223130f47324d8211f05c4527c918aa4e4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 22:27:39 +0300 Subject: [PATCH 0624/5359] replace closures with $method parameter in add_command() --- man/export.1 | 2 +- src/docs/export.txt | 2 +- src/php/wp-cli/class-wp-cli.php | 11 +-- src/php/wp-cli/commands/internals/export.php | 8 +- src/php/wp-cli/commands/internals/help.php | 72 ++++++++++-------- src/php/wp-cli/commands/internals/home.php | 43 +++++++---- src/php/wp-cli/dispatcher.php | 79 +++++++++++--------- 7 files changed, 126 insertions(+), 91 deletions(-) diff --git a/man/export.1 b/man/export.1 index a2e45d461..20f47f672 100644 --- a/man/export.1 +++ b/man/export.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EXPORT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-EXPORT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-export\fR \- Create a WXR file\. diff --git a/src/docs/export.txt b/src/docs/export.txt index 5e7d32e54..1aafbc5b1 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -3,7 +3,7 @@ wp-export(1) -- Create a WXR file. ## SYNOPSIS -`wp export` --path=<dirname> [filters] [--skip_comments] +`wp export` --dir=<dirname> [filters] [--skip_comments] ## OPTIONS diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8e2a7292f..553c07779 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -14,14 +14,15 @@ class WP_CLI { * * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command + * @param string $method The method to call, instead of subcommands */ - public function add_command( $name, $implementation ) { - if ( is_string( $implementation ) && class_exists( $implementation ) ) - $class = '\WP_CLI\Dispatcher\CompositeCommand'; + public function add_command( $name, $class, $method = false ) { + if ( !$method ) + $command = new \WP_CLI\Dispatcher\CompositeCommand( $name, $class ); else - $class = '\WP_CLI\Dispatcher\SimpleCommand'; + $command = new \WP_CLI\Dispatcher\SimpleCommand( $name, $class, $method ); - self::$commands[ $name ] = new $class( $implementation, $name ); + self::$commands[ $name ] = $command; } /** diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 02a42ddd4..350cbb5dd 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command( 'export', array( new Export_Command, 'export' ) ); +WP_CLI::add_command( 'export', 'Export_Command', 'export' ); /** * Implement export command @@ -8,10 +8,12 @@ * @package wp-cli * @subpackage commands/internals */ -class Export_Command { +class Export_Command extends WP_CLI_Command { /** - * Argument validation functions below + * Export posts to a WXR file. + * + * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] */ public function export( $args, $assoc_args ) { $defaults = array( diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 0aced7af8..7f852ba8b 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -1,46 +1,55 @@ <?php -namespace WP_CLI\Help; -\WP_CLI::add_command( 'help', function( $args ) { - if ( empty( $args ) ) { - general_help(); - return; - } +WP_CLI::add_command( 'help', 'Help_Command', 'help' ); + +/** + * Implement help command + * + * @package wp-cli + * @subpackage commands/internals + */ +class Help_Command extends WP_CLI_Command { + + function help( $args ) { + if ( empty( $args ) ) { + self::general_help(); + return; + } - maybe_load_man_page( $args ); + self::maybe_load_man_page( $args ); - show_available_subcommands( $args[0] ); -} ); + self::show_available_subcommands( $args[0] ); + } -function maybe_load_man_page( $args ) { - $man_dir = WP_CLI_ROOT . "../../../man/"; + private static function maybe_load_man_page( $args ) { + $man_dir = WP_CLI_ROOT . "../../../man/"; - if ( !is_dir( $man_dir ) ) { - \WP_CLI::warning( "man pages do not seem to be installed." ); - } else { - $man_file = $man_dir . implode( '-', $args ) . '.1'; + if ( !is_dir( $man_dir ) ) { + WP_CLI::warning( "man pages do not seem to be installed." ); + } else { + $man_file = $man_dir . implode( '-', $args ) . '.1'; - if ( is_readable( $man_file ) ) { - exit( \WP_CLI::launch( "man $man_file" ) ); + if ( is_readable( $man_file ) ) { + exit( WP_CLI::launch( "man $man_file" ) ); + } } } -} -function show_available_subcommands( $command ) { - $command = \WP_CLI::load_command( $command ); - $command->show_usage(); -} + private static function show_available_subcommands( $command ) { + $command = WP_CLI::load_command( $command ); + $command->show_usage(); + } -function general_help() { - \WP_CLI::line( 'Available commands:' ); - foreach ( \WP_CLI::load_all_commands() as $name => $command ) { - if ( 'help' == $name ) - continue; + private static function general_help() { + WP_CLI::line( 'Available commands:' ); + foreach ( WP_CLI::load_all_commands() as $name => $command ) { + if ( 'help' == $name ) + continue; - \WP_CLI::line( " wp $name " . $command->shortdesc() ); - } + WP_CLI::line( " wp $name " . $command->shortdesc() ); + } - \WP_CLI::line(<<<EOB + WP_CLI::line(<<<EOB See 'wp help <command>' for more information on a specific command. @@ -52,6 +61,7 @@ function general_help() { --quiet suppress informational messages --version print wp-cli version EOB - ); + ); + } } diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index c2efd8623..ca889c49d 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -1,21 +1,32 @@ <?php -WP_CLI::add_command( 'home', function() { - // The url for the wp-cli repository - $repository_url = 'https://github.com/wp-cli/wp-cli'; +WP_CLI::add_command( 'home', 'Home_Command', 'home' ); - // Open the wp-cli page in the browser - if ( exec( 'which x-www-browser' ) ) { - system( 'x-www-browser '.$repository_url ); - } - elseif ( exec( 'which open' ) ) { - system( 'open '.$repository_url ); - } - else { - WP_CLI::error( 'No command found to open the homepage in the browser. Please open it manually: '.$repository_url ); - return; - } +/** + * Implement home command + * + * @package wp-cli + * @subpackage commands/internals + */ +class Home_Command extends WP_CLI_Command { - WP_CLI::success( 'The wp-cli homepage should be opening in your browser.' ); -} ); + function home() { + // The url for the wp-cli repository + $repository_url = 'https://github.com/wp-cli/wp-cli'; + + // Open the wp-cli page in the browser + if ( exec( 'which x-www-browser' ) ) { + system( 'x-www-browser '.$repository_url ); + } + elseif ( exec( 'which open' ) ) { + system( 'open '.$repository_url ); + } + else { + WP_CLI::error( 'No command found to open the homepage in the browser. Please open it manually: '.$repository_url ); + return; + } + + WP_CLI::success( 'The wp-cli homepage should be opening in your browser.' ); + } +} diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index bbf2d8ba3..1b8f02d8f 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -2,41 +2,21 @@ namespace WP_CLI\Dispatcher; -abstract class Command { +interface Command { - function __construct( $implementation, $name ) { - $this->implementation = $implementation; - $this->name = $name; - } - - abstract function autocomplete(); - abstract function shortdesc(); - abstract function show_usage(); - abstract function invoke( $arguments, $assoc_args ); + function autocomplete(); + function shortdesc(); + function show_usage(); + function invoke( $arguments, $assoc_args ); } -class SimpleCommand extends Command { - - function autocomplete() { - return $this->name; - } - - function shortdesc() { - return ''; - } - - function show_usage() { - \WP_CLI::line( "usage: wp $this->name" ); - } +class CompositeCommand implements Command { - function invoke( $arguments, $assoc_args ) { - call_user_func( $this->implementation, $arguments, $assoc_args ); + function __construct( $name, $class ) { + $this->name = $name; + $this->class = $class; } -} - - -class CompositeCommand extends Command { function autocomplete() { $subcommands = array_keys( $this->get_subcommands() ); @@ -50,7 +30,7 @@ function shortdesc() { } function show_usage() { - if ( method_exists( $this->implementation, 'help' ) ) { + if ( method_exists( $this->class, 'help' ) ) { $class::help(); return; } @@ -77,14 +57,14 @@ function invoke( $args, $assoc_args ) { return; } - $class = $this->implementation; + $class = $this->class; $instance = new $class; $subcommand->invoke( $instance, $args, $assoc_args ); } protected function find_subcommand( &$args ) { - $class = $this->implementation; + $class = $this->class; if ( empty( $args ) ) { $name = $class::get_default_subcommand(); @@ -106,8 +86,8 @@ protected function find_subcommand( &$args ) { return $subcommands[ $name ]; } - protected function get_subcommands() { - $reflection = new \ReflectionClass( $this->implementation ); + private function get_subcommands() { + $reflection = new \ReflectionClass( $this->class ); $subcommands = array(); @@ -129,6 +109,36 @@ private static function _is_good_method( $method ) { } +class SimpleCommand extends CompositeCommand { + + function __construct( $name, $class, $method ) { + $this->name = $name; + $this->class = $class; + $this->method = $method; + } + + function autocomplete() { + return $this->name; + } + + function shortdesc() { + return ''; + } + + function show_usage() { + \WP_CLI::line( "usage: wp $this->name" ); + } + + protected function find_subcommand( &$args ) { + $class = $this->class; + + $method = new \ReflectionMethod( $this->class, $this->method ); + + return new Subcommand( $method, $this->name ); + } +} + + class Subcommand { function __construct( $method, $command ) { @@ -249,3 +259,4 @@ private static function get_patterns() { } } + From b297f1f918bae142b43df29fe11ce73af2da5321 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 23:11:35 +0300 Subject: [PATCH 0625/5359] introduce SimpleSubcommand class to avoid double name in show_usage() --- src/php/wp-cli/dispatcher.php | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 1b8f02d8f..e8e1fa821 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -134,7 +134,7 @@ protected function find_subcommand( &$args ) { $method = new \ReflectionMethod( $this->class, $this->method ); - return new Subcommand( $method, $this->name ); + return new SimpleSubcommand( $method, $this->name ); } } @@ -146,6 +146,13 @@ function __construct( $method, $command ) { $this->command = $command; } + function show_usage( $prefix = 'usage: ' ) { + $name = $this->get_name(); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); + } + function get_name() { $comment = $this->method->getDocComment(); @@ -155,13 +162,6 @@ function get_name() { return $this->method->name; } - function show_usage( $prefix = 'usage: ' ) { - $name = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); - } - function invoke( $instance, $args, $assoc_args ) { $this->check_args( $args, $assoc_args ); return $this->method->invoke( $instance, $args, $assoc_args ); @@ -197,9 +197,7 @@ protected function check_args( $args, $assoc_args ) { if ( empty( $errors ) ) return; - foreach ( $errors as $error ) - \WP_CLI::warning( $error ); - + $this->show_usage(); exit(1); } @@ -260,3 +258,12 @@ private static function get_patterns() { } +class SimpleSubcommand extends Subcommand { + + function show_usage( $prefix = 'usage: ' ) { + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $this->command $synopsis" ); + } +} + From f041df477cae392b96821a78279392bd2236c8d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 23:37:24 +0300 Subject: [PATCH 0626/5359] remove support for old static help() method --- src/php/wp-cli/dispatcher.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index e8e1fa821..a58eb13a7 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -30,11 +30,6 @@ function shortdesc() { } function show_usage() { - if ( method_exists( $this->class, 'help' ) ) { - $class::help(); - return; - } - $methods = $this->get_subcommands(); $i = 0; From 7de8cbc37848b10bde383d2690f61d0be251a20c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 23:42:33 +0300 Subject: [PATCH 0627/5359] replace $method parameter in add_command() with __invoke() magic method --- src/php/wp-cli/class-wp-cli.php | 7 +++---- src/php/wp-cli/commands/internals/export.php | 4 ++-- src/php/wp-cli/commands/internals/help.php | 4 ++-- src/php/wp-cli/commands/internals/home.php | 4 ++-- src/php/wp-cli/dispatcher.php | 15 +++++++++------ 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 553c07779..98faba63f 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -14,13 +14,12 @@ class WP_CLI { * * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command - * @param string $method The method to call, instead of subcommands */ - public function add_command( $name, $class, $method = false ) { - if ( !$method ) + public function add_command( $name, $class ) { + if ( is_string( $class ) ) $command = new \WP_CLI\Dispatcher\CompositeCommand( $name, $class ); else - $command = new \WP_CLI\Dispatcher\SimpleCommand( $name, $class, $method ); + $command = new \WP_CLI\Dispatcher\SimpleCommand( $name, $class ); self::$commands[ $name ] = $command; } diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 350cbb5dd..96527afac 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command( 'export', 'Export_Command', 'export' ); +WP_CLI::add_command( 'export', new Export_Command ); /** * Implement export command @@ -15,7 +15,7 @@ class Export_Command extends WP_CLI_Command { * * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] */ - public function export( $args, $assoc_args ) { + public function __invoke( $args, $assoc_args ) { $defaults = array( 'dir' => NULL, 'start_date' => NULL, diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 7f852ba8b..2f640280a 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command( 'help', 'Help_Command', 'help' ); +WP_CLI::add_command( 'help', new Help_Command ); /** * Implement help command @@ -10,7 +10,7 @@ */ class Help_Command extends WP_CLI_Command { - function help( $args ) { + function __invoke( $args ) { if ( empty( $args ) ) { self::general_help(); return; diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index ca889c49d..f20bcf03e 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -1,6 +1,6 @@ <?php -WP_CLI::add_command( 'home', 'Home_Command', 'home' ); +WP_CLI::add_command( 'home', new Home_Command ); /** * Implement home command @@ -10,7 +10,7 @@ */ class Home_Command extends WP_CLI_Command { - function home() { + function __invoke() { // The url for the wp-cli repository $repository_url = 'https://github.com/wp-cli/wp-cli'; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index a58eb13a7..4098cce02 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -106,10 +106,9 @@ private static function _is_good_method( $method ) { class SimpleCommand extends CompositeCommand { - function __construct( $name, $class, $method ) { + function __construct( $name, $callable ) { $this->name = $name; - $this->class = $class; - $this->method = $method; + $this->callable = $callable; } function autocomplete() { @@ -124,10 +123,14 @@ function show_usage() { \WP_CLI::line( "usage: wp $this->name" ); } - protected function find_subcommand( &$args ) { - $class = $this->class; + function invoke( $args, $assoc_args ) { + $subcommand = $this->find_subcommand( $args ); + + $subcommand->invoke( $this->callable, $args, $assoc_args ); + } - $method = new \ReflectionMethod( $this->class, $this->method ); + protected function find_subcommand( &$args ) { + $method = new \ReflectionMethod( $this->callable, '__invoke' ); return new SimpleSubcommand( $method, $this->name ); } From 3e53cec0779c432de6557d7dd8d442c10010ae5f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 23:49:36 +0300 Subject: [PATCH 0628/5359] rename Simple* to Single* --- src/php/wp-cli/class-wp-cli.php | 2 +- src/php/wp-cli/dispatcher.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 98faba63f..8be897c54 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -19,7 +19,7 @@ public function add_command( $name, $class ) { if ( is_string( $class ) ) $command = new \WP_CLI\Dispatcher\CompositeCommand( $name, $class ); else - $command = new \WP_CLI\Dispatcher\SimpleCommand( $name, $class ); + $command = new \WP_CLI\Dispatcher\SingleCommand( $name, $class ); self::$commands[ $name ] = $command; } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 4098cce02..5deb4674d 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -104,7 +104,7 @@ private static function _is_good_method( $method ) { } -class SimpleCommand extends CompositeCommand { +class SingleCommand extends CompositeCommand { function __construct( $name, $callable ) { $this->name = $name; @@ -132,7 +132,7 @@ function invoke( $args, $assoc_args ) { protected function find_subcommand( &$args ) { $method = new \ReflectionMethod( $this->callable, '__invoke' ); - return new SimpleSubcommand( $method, $this->name ); + return new SingleSubcommand( $method, $this->name ); } } @@ -256,7 +256,7 @@ private static function get_patterns() { } -class SimpleSubcommand extends Subcommand { +class SingleSubcommand extends Subcommand { function show_usage( $prefix = 'usage: ' ) { $synopsis = $this->get_synopsis(); From ca66de0c70f3caeb3017826a306de5845d713b5c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Oct 2012 23:57:52 +0300 Subject: [PATCH 0629/5359] move Subcommand classes to separate file --- src/php/wp-cli/dispatcher-subcommand.php | 132 +++++++++++++++++++++++ src/php/wp-cli/dispatcher.php | 129 ---------------------- src/php/wp-cli/wp-cli.php | 1 + 3 files changed, 133 insertions(+), 129 deletions(-) create mode 100644 src/php/wp-cli/dispatcher-subcommand.php diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php new file mode 100644 index 000000000..d798a8be8 --- /dev/null +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -0,0 +1,132 @@ +<?php + +namespace WP_CLI\Dispatcher; + +class Subcommand { + + function __construct( $method, $command ) { + $this->method = $method; + $this->command = $command; + } + + function show_usage( $prefix = 'usage: ' ) { + $name = $this->get_name(); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); + } + + function get_name() { + $comment = $this->method->getDocComment(); + + if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + return $matches[1]; + + return $this->method->name; + } + + function invoke( $instance, $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + return $this->method->invoke( $instance, $args, $assoc_args ); + } + + protected function check_args( $args, $assoc_args ) { + $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); + + $mandatory_positinal = wp_list_filter( $accepted_params, array( + 'type' => 'positional', + 'optional' => false + ) ); + + if ( count( $args ) < count( $mandatory_positinal ) ) { + $this->show_usage(); + exit(1); + } + + $mandatory_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( + 'type' => 'assoc', + 'optional' => false + ) ), 'name' ); + + $errors = array(); + + foreach ( $mandatory_assoc as $key ) { + if ( !isset( $assoc_args[ $key ] ) ) + $errors[] = "missing --$key parameter"; + elseif ( true === $assoc_args[ $key ] ) + $errors[] = "--$key parameter needs a value"; + } + + if ( empty( $errors ) ) + return; + + $this->show_usage(); + exit(1); + } + + protected function get_synopsis() { + $comment = $this->method->getDocComment(); + + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) + return false; + + return $matches[1]; + } + + protected function parse_synopsis( $synopsis ) { + $patterns = self::get_patterns(); + + $tokens = preg_split( '/[\s\t]+/', $synopsis ); + + $params = array(); + + foreach ( $tokens as $token ) { + foreach ( $patterns as $regex => $desc ) { + if ( preg_match( $regex, $token, $matches ) ) { + $params[] = array_merge( $matches, $desc ); + break; + } + } + } + + return $params; + } + + private static function get_patterns() { + $p_name = '(?P<name>[a-z-]+)'; + $p_value = '<(?P<value>[a-z-|]+)>'; + + $param_types = array( + 'positional' => $p_value, + 'assoc' => "--$p_name=$p_value", + 'flag' => "--$p_name" + ); + + $patterns = array(); + + foreach ( $param_types as $type => $pattern ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } + + return $patterns; + } +} + + +class SingleSubcommand extends Subcommand { + + function show_usage( $prefix = 'usage: ' ) { + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $this->command $synopsis" ); + } +} + diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 5deb4674d..1d30c7b0d 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -136,132 +136,3 @@ protected function find_subcommand( &$args ) { } } - -class Subcommand { - - function __construct( $method, $command ) { - $this->method = $method; - $this->command = $command; - } - - function show_usage( $prefix = 'usage: ' ) { - $name = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); - } - - function get_name() { - $comment = $this->method->getDocComment(); - - if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) - return $matches[1]; - - return $this->method->name; - } - - function invoke( $instance, $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - return $this->method->invoke( $instance, $args, $assoc_args ); - } - - protected function check_args( $args, $assoc_args ) { - $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); - - $mandatory_positinal = wp_list_filter( $accepted_params, array( - 'type' => 'positional', - 'optional' => false - ) ); - - if ( count( $args ) < count( $mandatory_positinal ) ) { - $this->show_usage(); - exit(1); - } - - $mandatory_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( - 'type' => 'assoc', - 'optional' => false - ) ), 'name' ); - - $errors = array(); - - foreach ( $mandatory_assoc as $key ) { - if ( !isset( $assoc_args[ $key ] ) ) - $errors[] = "missing --$key parameter"; - elseif ( true === $assoc_args[ $key ] ) - $errors[] = "--$key parameter needs a value"; - } - - if ( empty( $errors ) ) - return; - - $this->show_usage(); - exit(1); - } - - protected function get_synopsis() { - $comment = $this->method->getDocComment(); - - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) - return false; - - return $matches[1]; - } - - protected function parse_synopsis( $synopsis ) { - $patterns = self::get_patterns(); - - $tokens = preg_split( '/[\s\t]+/', $synopsis ); - - $params = array(); - - foreach ( $tokens as $token ) { - foreach ( $patterns as $regex => $desc ) { - if ( preg_match( $regex, $token, $matches ) ) { - $params[] = array_merge( $matches, $desc ); - break; - } - } - } - - return $params; - } - - private static function get_patterns() { - $p_name = '(?P<name>[a-z-]+)'; - $p_value = '<(?P<value>[a-z-|]+)>'; - - $param_types = array( - 'positional' => $p_value, - 'assoc' => "--$p_name=$p_value", - 'flag' => "--$p_name" - ); - - $patterns = array(); - - foreach ( $param_types as $type => $pattern ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); - - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); - } - - return $patterns; - } -} - - -class SingleSubcommand extends Subcommand { - - function show_usage( $prefix = 'usage: ' ) { - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $this->command $synopsis" ); - } -} - diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 016fd3a5a..37d95ba92 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -15,6 +15,7 @@ // Include the wp-cli classes include WP_CLI_ROOT . 'dispatcher.php'; +include WP_CLI_ROOT . 'dispatcher-subcommand.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; From 223a75400a31bf7079b2dcc61a8de9904295af55 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 00:10:39 +0300 Subject: [PATCH 0630/5359] make subcommand invoke() signature match command invoke() signature --- src/php/wp-cli/dispatcher-subcommand.php | 67 +++++++++++++++--------- src/php/wp-cli/dispatcher.php | 15 ++---- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index d798a8be8..2e855cba5 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -2,33 +2,15 @@ namespace WP_CLI\Dispatcher; -class Subcommand { +abstract class Subcommand { - function __construct( $method, $command ) { + function __construct( $method, $parent ) { $this->method = $method; - $this->command = $command; + $this->parent = $parent; } - function show_usage( $prefix = 'usage: ' ) { - $name = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $this->command $name $synopsis" ); - } - - function get_name() { - $comment = $this->method->getDocComment(); - - if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) - return $matches[1]; - - return $this->method->name; - } - - function invoke( $instance, $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - return $this->method->invoke( $instance, $args, $assoc_args ); - } + abstract function show_usage(); + abstract function invoke( $args, $assoc_args ); protected function check_args( $args, $assoc_args ) { $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); @@ -121,12 +103,49 @@ private static function get_patterns() { } +class MethodSubcommand extends Subcommand { + + function show_usage( $prefix = 'usage: ' ) { + $command = $this->parent->name; + $subcommand = $this->get_name(); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $command $subcommand $synopsis" ); + } + + function get_name() { + $comment = $this->method->getDocComment(); + + if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + return $matches[1]; + + return $this->method->name; + } + + function invoke( $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + + $class = $this->parent->class; + $instance = new $class; + + return $this->method->invoke( $instance, $args, $assoc_args ); + } +} + + class SingleSubcommand extends Subcommand { function show_usage( $prefix = 'usage: ' ) { + $command = $this->parent->name; $synopsis = $this->get_synopsis(); - \WP_CLI::line( $prefix . "wp $this->command $synopsis" ); + \WP_CLI::line( $prefix . "wp $command $synopsis" ); + } + + function invoke( $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + + return $this->method->invoke( $this->parent->callable, $args, $assoc_args ); } } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 1d30c7b0d..9673c61d8 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -52,10 +52,7 @@ function invoke( $args, $assoc_args ) { return; } - $class = $this->class; - $instance = new $class; - - $subcommand->invoke( $instance, $args, $assoc_args ); + $subcommand->invoke( $args, $assoc_args ); } protected function find_subcommand( &$args ) { @@ -90,7 +87,7 @@ private function get_subcommands() { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new Subcommand( $method, $this->name ); + $subcommand = new MethodSubcommand( $method, $this ); $subcommands[ $subcommand->get_name() ] = $subcommand; } @@ -123,16 +120,10 @@ function show_usage() { \WP_CLI::line( "usage: wp $this->name" ); } - function invoke( $args, $assoc_args ) { - $subcommand = $this->find_subcommand( $args ); - - $subcommand->invoke( $this->callable, $args, $assoc_args ); - } - protected function find_subcommand( &$args ) { $method = new \ReflectionMethod( $this->callable, '__invoke' ); - return new SingleSubcommand( $method, $this->name ); + return new SingleSubcommand( $method, $this ); } } From 2724e21b97cfd289bb960d0fc0dbe41b0792b14a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 00:50:44 +0300 Subject: [PATCH 0631/5359] SingleCommand doesn't need to inherit from CompositeCommand --- src/php/wp-cli/dispatcher.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 9673c61d8..81a4e395a 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -101,7 +101,7 @@ private static function _is_good_method( $method ) { } -class SingleCommand extends CompositeCommand { +class SingleCommand implements Command { function __construct( $name, $callable ) { $this->name = $name; @@ -120,10 +120,12 @@ function show_usage() { \WP_CLI::line( "usage: wp $this->name" ); } - protected function find_subcommand( &$args ) { + function invoke( $args, $assoc_args ) { $method = new \ReflectionMethod( $this->callable, '__invoke' ); - return new SingleSubcommand( $method, $this ); + $subcommand = new SingleSubcommand( $method, $this ); + + $subcommand->invoke( $args, $assoc_args ); } } From 250a10fcb0b6ef10c395b3355e0eb174443a03dd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 00:56:55 +0300 Subject: [PATCH 0632/5359] merge SingleSubcommand into SingleCommand --- src/php/wp-cli/dispatcher-subcommand.php | 28 +++++++----------------- src/php/wp-cli/dispatcher.php | 19 ++++++++++------ src/php/wp-cli/wp-cli.php | 2 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index 2e855cba5..dda879f76 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -4,9 +4,8 @@ abstract class Subcommand { - function __construct( $method, $parent ) { + function __construct( $method ) { $this->method = $method; - $this->parent = $parent; } abstract function show_usage(); @@ -105,6 +104,12 @@ private static function get_patterns() { class MethodSubcommand extends Subcommand { + function __construct( $method, $parent ) { + $this->parent = $parent; + + parent::__construct( $method ); + } + function show_usage( $prefix = 'usage: ' ) { $command = $this->parent->name; $subcommand = $this->get_name(); @@ -128,24 +133,7 @@ function invoke( $args, $assoc_args ) { $class = $this->parent->class; $instance = new $class; - return $this->method->invoke( $instance, $args, $assoc_args ); - } -} - - -class SingleSubcommand extends Subcommand { - - function show_usage( $prefix = 'usage: ' ) { - $command = $this->parent->name; - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $command $synopsis" ); - } - - function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - - return $this->method->invoke( $this->parent->callable, $args, $assoc_args ); + $this->method->invoke( $instance, $args, $assoc_args ); } } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 81a4e395a..b6d5e6398 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -101,11 +101,15 @@ private static function _is_good_method( $method ) { } -class SingleCommand implements Command { +class SingleCommand extends Subcommand implements Command { function __construct( $name, $callable ) { $this->name = $name; $this->callable = $callable; + + $method = new \ReflectionMethod( $this->callable, '__invoke' ); + + parent::__construct( $method ); } function autocomplete() { @@ -116,16 +120,17 @@ function shortdesc() { return ''; } - function show_usage() { - \WP_CLI::line( "usage: wp $this->name" ); + function show_usage( $prefix = 'usage: ' ) { + $command = $this->name; + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $command $synopsis" ); } function invoke( $args, $assoc_args ) { - $method = new \ReflectionMethod( $this->callable, '__invoke' ); + $this->check_args( $args, $assoc_args ); - $subcommand = new SingleSubcommand( $method, $this ); - - $subcommand->invoke( $args, $assoc_args ); + $this->method->invoke( $this->callable, $args, $assoc_args ); } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 37d95ba92..178c83cca 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,8 +14,8 @@ define( 'WP_CLI', true ); // Include the wp-cli classes -include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'dispatcher-subcommand.php'; +include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; From 8758fea612b985ead2da3ad78c88e07f5cef3f07 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 01:17:17 +0300 Subject: [PATCH 0633/5359] add @synopsis for eval and eval-file --- .../wp-cli/commands/internals/eval-file.php | 27 +++++++++++-------- src/php/wp-cli/commands/internals/eval.php | 19 ++++++++----- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/internals/eval-file.php index 044ff7fac..1887930d2 100644 --- a/src/php/wp-cli/commands/internals/eval-file.php +++ b/src/php/wp-cli/commands/internals/eval-file.php @@ -1,17 +1,22 @@ <?php -WP_CLI::add_command( 'eval-file', function( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp eval-file <path>" ); - exit; - } +WP_CLI::add_command( 'eval-file', new EvalFile_Command ); + +class EvalFile_Command extends WP_CLI_Command { - foreach ( $args as $file ) { - if ( !file_exists( $file ) ) { - WP_CLI::error( "'$file' does not exist." ); - } else { - include( $file ); + /** + * Loads and executes a PHP file after loading WordPress. + * + * @synopsis <path> + */ + public function __invoke( $args, $assoc_args ) { + foreach ( $args as $file ) { + if ( !file_exists( $file ) ) { + WP_CLI::error( "'$file' does not exist." ); + } else { + include( $file ); + } } } -} ); +} diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/internals/eval.php index 373cedfe2..fe8ae5f17 100644 --- a/src/php/wp-cli/commands/internals/eval.php +++ b/src/php/wp-cli/commands/internals/eval.php @@ -1,11 +1,16 @@ <?php -WP_CLI::add_command( 'eval', function( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp eval '<php-code>'" ); - exit; - } +WP_CLI::add_command( 'eval', new Eval_Command ); + +class Eval_Command extends WP_CLI_Command { - eval( $args[0] ); -} ); + /** + * Executes arbitrary PHP code after loading WordPress. + * + * @synopsis <php-code> + */ + public function __invoke( $args, $assoc_args ) { + eval( $args[0] ); + } +} From e6b5ac67fcc64695ac5699282ba91adc419f8ec4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 03:30:24 +0300 Subject: [PATCH 0634/5359] add warning when passing unknown assoc args --- src/php/wp-cli/dispatcher-subcommand.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index dda879f76..ad530cc33 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -38,11 +38,20 @@ protected function check_args( $args, $assoc_args ) { $errors[] = "--$key parameter needs a value"; } - if ( empty( $errors ) ) - return; + if ( !empty( $errors ) ) { + $this->show_usage(); + exit(1); + } - $this->show_usage(); - exit(1); + $known_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( + 'type' => 'positional', + ), 'NOT' ), 'name' ); + + $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); + + foreach ( $unknown_assoc as $key ) { + \WP_CLI::warning( "unkown --$key parameter" ); + } } protected function get_synopsis() { From 9f5bf59d2c3385ec033a49b146c828dec13340a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 03:42:26 +0300 Subject: [PATCH 0635/5359] add @synopsis for rewrite subcommands --- src/php/wp-cli/commands/internals/rewrite.php | 53 ++++++------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/internals/rewrite.php index 87ea5da60..67ca9313d 100644 --- a/src/php/wp-cli/commands/internals/rewrite.php +++ b/src/php/wp-cli/commands/internals/rewrite.php @@ -1,37 +1,24 @@ <?php -WP_CLI:: add_command('rewrite', 'Rewrite_Command'); - -/** - * Implement rewrite command - * - * @package wp-cli - * @subpackage commands/internal - */ +WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); + class Rewrite_Command extends WP_CLI_Command { /** - * Flush rules + * Flush rewrite rules. * - * @param array $args not used - * @param array $assoc_args --soft or --hard (default) + * @synopsis [--soft] */ public function flush( $args, $assoc_args ) { - $hard = ( isset( $assoc_args['soft'] ) ) ? false : true; - flush_rewrite_rules( $hard ); + flush_rewrite_rules( isset( $assoc_args['soft'] ) ); } /** - * Set permalink structure + * Update the permalink structure. * - * @param array $args - * @param array $assoc_args + * @synopsis <permastruct> [--category-base=<base>] [--tag-base=<base>] */ public function structure( $args, $assoc_args ) { - if ( !count( $args ) && !count( $assoc_args ) ) { - WP_CLI::line( "usage: wp rewrite structure <new-permalink-structure>" ); - exit; - } global $wp_rewrite; // copypasta from /wp-admin/options-permalink.php @@ -44,20 +31,16 @@ public function structure( $args, $assoc_args ) { if ( is_multisite() && !is_subdomain_install() && is_main_site() ) $blog_prefix = '/blog'; - // Update base permastruct if argument is provided - if ( isset( $args[0] ) ) { + $permalink_structure = ( $args[0] == 'default' ) ? '' : $args[0]; - $permalink_structure = ( $args[0] == 'default' ) ? '' : $args[0]; - - if ( ! empty( $permalink_structure ) ) { - $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) ); - if ( $prefix && $blog_prefix ) - $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure ); - else - $permalink_structure = $blog_prefix . $permalink_structure; - } - $wp_rewrite->set_permalink_structure( $permalink_structure ); + if ( ! empty( $permalink_structure ) ) { + $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) ); + if ( $prefix && $blog_prefix ) + $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure ); + else + $permalink_structure = $blog_prefix . $permalink_structure; } + $wp_rewrite->set_permalink_structure( $permalink_structure ); // Update category or tag bases if ( isset( $assoc_args['category-base'] ) ) { @@ -76,15 +59,13 @@ public function structure( $args, $assoc_args ) { $wp_rewrite->set_tag_base( $tag_base ); } - flush_rewrite_rules( $hard ); } /** - * Dump rewrite rules + * Print current rewrite rules. * - * @param array $args - * @param array $assoc_args + * @synopsis [--json] */ public function dump( $args, $assoc_args ) { From 314e9569932c18878317dbd5be332a63527297d8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 04:02:04 +0300 Subject: [PATCH 0636/5359] add @synopsis for cache subcommands --- src/php/wp-cli/commands/internals/cache.php | 92 ++------------------- 1 file changed, 8 insertions(+), 84 deletions(-) diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index d595ce986..32cf156a4 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -13,18 +13,9 @@ class Cache_Command extends WP_CLI_Command { /** * Add a value to the object cache. * - * @uses wp_cache_add - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> <value> [<group>] [<expiration>] */ public function add( $args, $assoc_args ) { - if ( count( $assoc_args ) + count( $args ) < 2 ) { - WP_CLI::line( 'usage: wp cache add <key> <value> [group] [expiration]' ); - exit; - } - list( $key, $value ) = $args; $group = ( isset( $args[2] ) ) ? $args[2] : ''; @@ -42,18 +33,9 @@ public function add( $args, $assoc_args ) { /** * Decrement a value in the object cache. * - * @uses wp_cache_decr - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> [<offset>] [<group>] */ public function decr( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache decr <key> [offset] [group]' ); - exit; - } - $key = $args[0]; $offset = ( isset( $args[1] ) ) ? $args[1] : 1; @@ -64,7 +46,6 @@ public function decr( $args, $assoc_args ) { if ( false === $value ) { WP_CLI::error( 'The value was not decremented.' ); - exit; } WP_CLI::print_value( $value, $assoc_args ); @@ -73,18 +54,9 @@ public function decr( $args, $assoc_args ) { /** * Remove a value from the object cache. * - * @uses wp_cache_delete - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> <group> */ public function delete( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache delete <key> [group]' ); - exit; - } - $key = $args[0]; $group = ( isset( $args[1] ) ) ? $args[1] : ''; @@ -101,12 +73,6 @@ public function delete( $args, $assoc_args ) { /** * Flush the object cache. - * - * @uses wp_cache_flush - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void */ public function flush( $args, $assoc_args ) { $value = wp_cache_flush(); @@ -122,18 +88,9 @@ public function flush( $args, $assoc_args ) { /** * Get a value from the object cache. * - * @uses wp_cache_get - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> [<group>] */ public function get( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache get <key> [group]' ); - exit; - } - $key = $args[0]; $group = ( isset( $args[1] ) ) ? $args[1] : ''; @@ -151,18 +108,9 @@ public function get( $args, $assoc_args ) { /** * Increment a value in the object cache. * - * @uses wp_cache_incr - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> [<offset>] [<group>] */ public function incr( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( 'usage: wp cache incr <key> [offset] [group]' ); - exit; - } - $key = $args[0]; $offset = ( isset( $args[1] ) ) ? $args[1] : 1; @@ -182,18 +130,9 @@ public function incr( $args, $assoc_args ) { /** * Replace an existing value in the object cache. * - * @uses wp_cache_replace - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> <value> [<group>] [<expiration>] */ public function replace( $args, $assoc_args ) { - if ( count( $assoc_args ) + count( $args ) < 2 ) { - WP_CLI::line( 'usage: wp cache replace <key> <value> [group] [expiration]' ); - exit; - } - list( $key, $value ) = $args; $group = ( isset( $args[2] ) ) ? $args[2] : ''; @@ -213,18 +152,9 @@ public function replace( $args, $assoc_args ) { /** * Set a value to the object cache. * - * @uses wp_cache_set - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void + * @synopsis <key> <value> [<group>] [<expiration>] */ public function set( $args, $assoc_args ) { - if ( count( $assoc_args ) + count( $args ) < 2 ) { - WP_CLI::line( 'usage: wp cache set <key> <value> [group] [expiration]' ); - exit; - } - list( $key, $value ) = $args; $group = ( isset( $args[2] ) ) ? $args[2] : ''; @@ -247,13 +177,6 @@ public function set( $args, $assoc_args ) { * Note that the guesses made by this function are based on the WP_Object_Cache classes * that define the 3rd party object cache extension. Changes to those classes could render * problems with this function's ability to determine which object cache is being used. - * - * @uses $_wp_using_ext_object_cache - * @uses $wp_object_cache - * - * @param array $args Function arguments. - * @param array $assoc_args Function arguments with parameter key. - * @return void */ public function type( $args, $assoc_args ) { global $_wp_using_ext_object_cache, $wp_object_cache; @@ -295,3 +218,4 @@ public function type( $args, $assoc_args ) { WP_CLI::print_value( $message ); } } + From 6dc7cc36a524e6c6ca84fac47c41ea010473a6f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 04:19:03 +0300 Subject: [PATCH 0637/5359] add @synopsis for core subcommands --- src/php/wp-cli/class-wp-cli.php | 24 --------------------- src/php/wp-cli/commands/internals/core.php | 25 +++++++++++++++------- src/php/wp-cli/wp-cli.php | 2 -- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8be897c54..eb084f6a3 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -171,30 +171,6 @@ static function compose_args( $args, $assoc_args = array() ) { return $str; } - /** - * Issue warnings for each missing associative argument. - * - * @param array List of required arg names - * @param array Passed args - */ - static function check_required_args( $required, $assoc_args ) { - $missing = false; - - foreach ( $required as $arg ) { - if ( !isset( $assoc_args[ $arg ] ) ) { - WP_CLI::warning( "--$arg parameter is missing" ); - $missing = true; - } elseif ( true === $assoc_args[ $arg ] ) { - // passed as a flag - WP_CLI::warning( "--$arg needs to have a value" ); - $missing = true; - } - } - - if ( $missing ) - exit(1); - } - static function get_numeric_arg( $args, $index, $name ) { if ( ! isset( $args[$index] ) ) { WP_CLI::error( "$name required" ); diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index e433658e5..326433072 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -12,6 +12,8 @@ class Core_Command extends WP_CLI_Command { /** * Download the core files from wordpress.org + * + * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] */ public function download( $args, $assoc_args ) { if ( is_readable( WP_ROOT . 'wp-load.php' ) ) @@ -43,10 +45,10 @@ public function download( $args, $assoc_args ) { /** * Set up a wp-config.php file. + * + * @synopsis --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=<host>] [--dbprefix=<prefix>] */ public function config( $args, $assoc_args ) { - WP_CLI::check_required_args( array( 'dbname', 'dbuser', 'dbpass' ), $assoc_args ); - $_POST['dbname'] = $assoc_args['dbname']; $_POST['uname'] = $assoc_args['dbuser']; $_POST['pwd'] = $assoc_args['dbpass']; @@ -62,6 +64,8 @@ public function config( $args, $assoc_args ) { /** * Run wp_install. Assumes that wp-config.php is already in place. + * + * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); @@ -89,7 +93,10 @@ public function install( $args, $assoc_args ) { } /** + * Transform a single-site install into a multi-site install. + * * @subcommand install-network + * @synopsis --title=<network-title> [--base_path=/] */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) @@ -103,8 +110,6 @@ public function install_network( $args, $assoc_args ) { foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) $wpdb->$table = $prefixed_table; - WP_CLI::check_required_args( array( 'title' ), $assoc_args ); - extract( wp_parse_args( $assoc_args, array( 'base' => '/', ) ) ); @@ -154,6 +159,8 @@ private static function get_clean_basedomain() { /** * Display the WordPress version. + * + * @synopsis [--extra] */ public function version( $args = array(), $assoc_args = array() ) { global $wp_version, $wp_db_version, $tinymce_version, $manifest_version; @@ -165,6 +172,7 @@ public function version( $args = array(), $assoc_args = array() ) { '-beta' => array( 'beta', '%B' ), '-' => array( 'in development', '%R' ), ); + foreach( $version_types as $needle => $type ) { if ( stristr( $wp_version, $needle ) ) { list( $version_text, $color ) = $type; @@ -172,6 +180,7 @@ public function version( $args = array(), $assoc_args = array() ) { break; } } + if ( isset( $assoc_args['extra'] ) ) { WP_CLI::line( "WordPress version:\t$version_text" ); @@ -188,13 +197,13 @@ public function version( $args = array(), $assoc_args = array() ) { } /** - * Update the WordPress core + * Update WordPress. * - * @param array $args - * @param array $assoc_args + * @synopsis [<zip>] [--version=<version>] [--force] */ function update( $args, $assoc_args ) { global $wp_version; + $update = $from_api = null; $upgrader = 'Core_Upgrader'; @@ -254,7 +263,7 @@ function update( $args, $assoc_args ) { } /** - * Update the WordPress database + * Update the WordPress database. * * @subcommand update-db */ diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 178c83cca..c16180459 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -82,8 +82,6 @@ // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == $arguments ) { - WP_CLI::check_required_args( array( 'url', 'title', 'admin_email', 'admin_password' ), $assoc_args ); - define( 'WP_INSTALLING', true ); } From ec86462816e288d4b14bf0243a92fb46c6f379e6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 04:40:54 +0300 Subject: [PATCH 0638/5359] don't assume WP functions exist when checking args --- src/php/wp-cli/dispatcher-subcommand.php | 43 +++++++++++++++++------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index ad530cc33..81d401509 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -14,20 +14,34 @@ abstract function invoke( $args, $assoc_args ); protected function check_args( $args, $assoc_args ) { $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); - $mandatory_positinal = wp_list_filter( $accepted_params, array( - 'type' => 'positional', - 'optional' => false - ) ); + $this->check_positional( $args, $accepted_params ); - if ( count( $args ) < count( $mandatory_positinal ) ) { + $this->check_assoc( $assoc_args, $accepted_params ); + + $this->check_unknown_assoc( $assoc_args, $accepted_params ); + } + + private function check_positional( $args, $accepted_params ) { + $count = 0; + + foreach ( $accepted_params as $param ) { + if ( 'positional' == $param['type'] && !$param['optional'] ) + $count++; + } + + if ( count( $args ) < $count ) { $this->show_usage(); exit(1); } + } + + private function check_assoc( $assoc_args, $accepted_params ) { + $mandatory_assoc = array(); - $mandatory_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( - 'type' => 'assoc', - 'optional' => false - ) ), 'name' ); + foreach ( $accepted_params as $param ) { + if ( 'assoc' == $param['type'] && !$param['optional'] ) + $mandatory_assoc[] = $param['name']; + } $errors = array(); @@ -42,10 +56,15 @@ protected function check_args( $args, $assoc_args ) { $this->show_usage(); exit(1); } + } + + private function check_unknown_assoc( $assoc_args, $accepted_params ) { + $known_assoc = array(); - $known_assoc = wp_list_pluck( wp_list_filter( $accepted_params, array( - 'type' => 'positional', - ), 'NOT' ), 'name' ); + foreach ( $accepted_params as $param ) { + if ( 'positional' != $param['type'] ) + $known_assoc[] = $param['name']; + } $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); From 98e77e116920e3fd195904d7ade8a5902bd70cb7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 04:44:01 +0300 Subject: [PATCH 0639/5359] fix indentation in core.php --- src/php/wp-cli/commands/internals/core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 326433072..8ea46d4c2 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -92,12 +92,12 @@ public function install( $args, $assoc_args ) { } } - /** + /** * Transform a single-site install into a multi-site install. * - * @subcommand install-network + * @subcommand install-network * @synopsis --title=<network-title> [--base_path=/] - */ + */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) WP_CLI::error( 'This already is a multisite install.' ); From d74129c66b4cc3c101471fcbe05b6249add07b93 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 04:57:55 +0300 Subject: [PATCH 0640/5359] add @synopsis for db subcommands --- src/php/wp-cli/commands/internals/db.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 2a2eb1be3..f84c9a40b 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -34,6 +34,8 @@ function create() { /** * Deletes the database specified in the wp-config.php file. + * + * @synopsis [--yes] */ function drop( $args, $assoc_args ) { if ( !isset( $assoc_args['yes'] ) ) { @@ -55,6 +57,8 @@ function drop( $args, $assoc_args ) { /** * Removes all tables from the database. + * + * @synopsis [--yes] */ function reset( $args, $assoc_args ) { if ( !isset( $assoc_args['yes'] ) ) { @@ -119,13 +123,10 @@ function cli() { /** * Execute a query against the site database. + * + * @synopsis <sql> */ function query( $args, $assoc_args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp db query <SQL>" ); - exit; - } - $query = $args[0]; $command = $this->connect_string() . self::create_cmd( ' --execute=%s', $query ); @@ -135,6 +136,8 @@ function query( $args, $assoc_args ) { /** * Exports the WordPress DB as SQL using mysqldump. + * + * @synopsis [<file>] */ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); @@ -149,6 +152,8 @@ function export( $args, $assoc_args ) { /** * Imports a database from a file. + * + * @synopsis [<file>] */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); From 1f95a84d1804a86ad4e315f79c26792d0442102f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 05:11:01 +0300 Subject: [PATCH 0641/5359] convert **/ to */ --- src/php/wp-cli/class-wp-cli-command-with-meta.php | 8 ++++---- src/php/wp-cli/commands/internals/db.php | 2 +- src/php/wp-cli/commands/internals/option.php | 2 +- src/php/wp-cli/commands/internals/post.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 2 +- src/php/wp-cli/commands/internals/user.php | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/src/php/wp-cli/class-wp-cli-command-with-meta.php index d636fd809..18521d486 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-meta.php +++ b/src/php/wp-cli/class-wp-cli-command-with-meta.php @@ -20,7 +20,7 @@ public static function get_aliases() { * * @param array $args * @param array $assoc_args - **/ + */ public function get( $args, $assoc_args ) { $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); @@ -38,7 +38,7 @@ public function get( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function delete( $args, $assoc_args ) { $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); @@ -57,7 +57,7 @@ public function delete( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function add( $args, $assoc_args ) { $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); @@ -77,7 +77,7 @@ public function add( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function update( $args, $assoc_args ) { $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index f84c9a40b..e5448e92f 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -7,7 +7,7 @@ * * @package wp-cli * @subpackage commands/internals - **/ + */ class DB_Command extends WP_CLI_Command { public static function get_default_subcommand() { diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 0f3ddc0d3..c7a1fb532 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -51,7 +51,7 @@ public function add( $args, $assoc_args ) { * Update an option * * @synopsis <key> <value> [--json] - **/ + */ public function update( $args, $assoc_args ) { $key = $args[0]; diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 13d33c47a..89ad3fccb 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -112,7 +112,7 @@ public function delete( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function generate( $args, $assoc_args ) { global $wpdb; diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index e86c5ede5..9bbe1050b 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -51,7 +51,7 @@ protected function get_details( $stylesheet ) { * Activate a theme. * * @synopsis <theme> - **/ + */ public function activate( $args = array() ) { list( $stylesheet, $child ) = $this->parse_name( $args ); diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 50fbbb8e9..a371ce35f 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -14,7 +14,7 @@ class User_Command extends WP_CLI_Command { * List users * * @subcommand list - **/ + */ public function _list( $args, $assoc_args ) { global $blog_id; @@ -55,7 +55,7 @@ public function _list( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function delete( $args, $assoc_args ) { global $blog_id; @@ -77,7 +77,7 @@ public function delete( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function create( $args, $assoc_args ) { global $blog_id; @@ -131,7 +131,7 @@ public function create( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function update( $args, $assoc_args ) { $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); @@ -156,7 +156,7 @@ public function update( $args, $assoc_args ) { * * @param array $args * @param array $assoc_args - **/ + */ public function generate( $args, $assoc_args ) { global $blog_id; From f989d598951cf65038887766a3eacfba7b05f5dd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 05:19:42 +0300 Subject: [PATCH 0642/5359] add @synopsis for user subcommands (except update) --- src/php/wp-cli/commands/internals/user.php | 25 +++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index a371ce35f..d0a695961 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -11,9 +11,10 @@ class User_Command extends WP_CLI_Command { /** - * List users + * List users. * * @subcommand list + * @synopsis [--role=<role>] */ public function _list( $args, $assoc_args ) { global $blog_id; @@ -51,10 +52,9 @@ public function _list( $args, $assoc_args ) { } /** - * Delete a user + * Delete a user. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> [--reassign=<id>] */ public function delete( $args, $assoc_args ) { global $blog_id; @@ -73,18 +73,13 @@ public function delete( $args, $assoc_args ) { } /** - * Create a user + * Create a user. * - * @param array $args - * @param array $assoc_args + * @synopsis <user-login> <user-email> [--role=<role>] [--porcelain] */ public function create( $args, $assoc_args ) { global $blog_id; - if ( count( $args ) < 2 ) { - WP_CLI::error( "Login and email required." ); - } - list( $user_login, $user_email ) = $args; $defaults = array( @@ -127,10 +122,7 @@ public function create( $args, $assoc_args ) { } /** - * Update a user - * - * @param array $args - * @param array $assoc_args + * Update a user. */ public function update( $args, $assoc_args ) { $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); @@ -154,8 +146,7 @@ public function update( $args, $assoc_args ) { /** * Generate users * - * @param array $args - * @param array $assoc_args + * @synopsis [--count=100] [--role=<role>] */ public function generate( $args, $assoc_args ) { global $blog_id; From f65823bdb0761a392b9da062b4680b52716f7a93 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 05:35:04 +0300 Subject: [PATCH 0643/5359] split --all flag into an update-all subcommand. fixes #180 --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 12 +++++------- src/php/wp-cli/commands/internals/plugin.php | 11 ++++++++++- src/php/wp-cli/commands/internals/theme.php | 9 +++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index d11741b23..d76eaf63d 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -123,16 +123,14 @@ function install( $args, $assoc_args ) { function update( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); - if ( !empty( $args ) && !isset( $assoc_args['all'] ) ) { - list( $file, $name ) = $this->parse_name( $args ); + list( $file, $name ) = $this->parse_name( $args ); - WP_CLI::get_upgrader( $this->upgrader )->upgrade( $file ); - } else { - $this->update_multiple( $args, $assoc_args ); - } + WP_CLI::get_upgrader( $this->upgrader )->upgrade( $file ); } - private function update_multiple( $args, $assoc_args ) { + function update_all( $args, $assoc_args ) { + call_user_func( $this->upgrade_refresh ); + $items_to_update = wp_list_filter( $this->get_item_list(), array( 'update' => true ) ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 7d93c962c..8a98361ea 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -184,7 +184,7 @@ protected function install_from_repo( $slug, $assoc_args ) { /** * Update a plugin. * - * @synopsis [<plugin>] [--all] [--version=<version>] + * @synopsis <plugin> [--version=<version>] */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { @@ -195,6 +195,15 @@ function update( $args, $assoc_args ) { } } + /** + * Update all plugins. + * + * @subcommand update-all + */ + function update_all( $args, $assoc_args ) { + parent::update_all( $args, $assoc_args ); + } + protected function get_item_list() { $items = array(); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 9bbe1050b..0316cf285 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -169,6 +169,15 @@ function update( $args, $assoc_args ) { parent::update( $args, $assoc_args ); } + /** + * Update all themes. + * + * @subcommand update-all + */ + function update_all( $args, $assoc_args ) { + parent::update_all( $args, $assoc_args ); + } + /** * Delete a theme. * From 9a72ba16e26dd5437259fee251b9a9ab9a2818ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Oct 2012 05:36:42 +0300 Subject: [PATCH 0644/5359] update synopsis for theme update. see #180 --- src/php/wp-cli/commands/internals/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 0316cf285..24559601d 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -163,7 +163,7 @@ function install( $args, $assoc_args ) { /** * Update a theme. * - * @synopsis [<theme>] [--all] + * @synopsis <theme> */ function update( $args, $assoc_args ) { parent::update( $args, $assoc_args ); From 8709268bf4282d042de09e188e1cd9b3ad755661 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 16:59:05 +0300 Subject: [PATCH 0645/5359] allow underscores in key names --- src/php/wp-cli/dispatcher-subcommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index 81d401509..afdb35b3e 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -102,7 +102,7 @@ protected function parse_synopsis( $synopsis ) { } private static function get_patterns() { - $p_name = '(?P<name>[a-z-]+)'; + $p_name = '(?P<name>[a-z-_]+)'; $p_value = '<(?P<value>[a-z-|]+)>'; $param_types = array( From ecbba6020f44ed66400876291d1d734211eff55b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 16:59:28 +0300 Subject: [PATCH 0646/5359] show missing parameters before showing usage --- src/php/wp-cli/dispatcher-subcommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index afdb35b3e..2bebf609d 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -53,6 +53,9 @@ private function check_assoc( $assoc_args, $accepted_params ) { } if ( !empty( $errors ) ) { + foreach ( $errors as $error ) { + \WP_CLI::warning( $error ); + } $this->show_usage(); exit(1); } From 88bd92e967efc49df7ca85d55616048382624e3e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 17:12:56 +0300 Subject: [PATCH 0647/5359] add synopsis for WP_CLI_Command_With_Meta --- .../wp-cli/class-wp-cli-command-with-meta.php | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/src/php/wp-cli/class-wp-cli-command-with-meta.php index 18521d486..968abf721 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-meta.php +++ b/src/php/wp-cli/class-wp-cli-command-with-meta.php @@ -16,14 +16,12 @@ public static function get_aliases() { protected $meta_type; /** - * Get meta field value + * Get meta field value. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> <key> [--json] */ public function get( $args, $assoc_args ) { - $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); - $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + list( $object_id, $meta_key ) = $args; $value = get_metadata( $this->meta_type, $object_id, $meta_key, true ); @@ -34,14 +32,12 @@ public function get( $args, $assoc_args ) { } /** - * Get meta field value for a user + * Delete a meta field. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> <key> */ public function delete( $args, $assoc_args ) { - $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); - $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); + list( $object_id, $meta_key ) = $args; $success = delete_metadata( $this->meta_type, $object_id, $meta_key ); @@ -53,15 +49,12 @@ public function delete( $args, $assoc_args ) { } /** - * Update meta field for a user + * Add a meta field. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> <key> <value> */ public function add( $args, $assoc_args ) { - $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); - $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); - $meta_value = self::get_arg_or_error( $args, 2, "meta_value" ); + list( $object_id, $meta_key, $meta_value ) = $args; $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); @@ -73,15 +66,12 @@ public function add( $args, $assoc_args ) { } /** - * Update meta field for a user + * Update a meta field. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> <key> <value> */ public function update( $args, $assoc_args ) { - $object_id = WP_CLI::get_numeric_arg( $args, 0, "$this->meta_type ID" ); - $meta_key = self::get_arg_or_error( $args, 1, "meta_key" ); - $meta_value = self::get_arg_or_error( $args, 2, "meta_value" ); + list( $object_id, $meta_key, $meta_value ) = $args; $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); @@ -91,13 +81,5 @@ public function update( $args, $assoc_args ) { WP_CLI::error( "Failed to update custom field." ); } } - - protected function get_arg_or_error( $args, $index, $name ) { - if ( ! isset( $args[$index] ) ) { - WP_CLI::error( "$name required" ); - } - - return $args[$index]; - } } From 70821fcc532f8e6deb4d39f5ed14af5aa150149f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 17:48:12 +0300 Subject: [PATCH 0648/5359] add @synopsis for transient subcommands --- .../wp-cli/commands/internals/transient.php | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php index 9d8236894..6c8a99824 100644 --- a/src/php/wp-cli/commands/internals/transient.php +++ b/src/php/wp-cli/commands/internals/transient.php @@ -11,16 +11,11 @@ class Transient_Command extends WP_CLI_Command { /** - * Gets a value using the "get_transient" function. + * Get a transient value. * - * @param array $args + * @synopsis <key> */ public function get( $args ) { - if ( empty( $args ) ) { - WP_CLI::error( 'Usage: wp transient get <key>' ); - exit; - } - list( $key ) = $args; $value = get_transient( $key ); @@ -37,19 +32,14 @@ public function get( $args ) { } /** - * Sets a value using the "set_transient" function. + * Set a transient value. <expiration> is the time until expiration, in seconds. * - * @param array $args + * @synopsis <key> <value> [<expiration>] */ public function set( $args ) { - if ( count( $args ) < 2 ) { - WP_CLI::error( 'usage: wp transient set <key> <value> [expiration]' ); - exit; - } + list( $key, $value ) = $args; - list( $key, $value, $expiration ) = $args; - - $expiration = isset( $expiration ) ? $expiration : 0; + $expiration = isset( $args[2] ) ? $args[2] : 0; if ( set_transient( $key, $value, $expiration ) ) WP_CLI::success( 'Transient added.' ); @@ -58,16 +48,11 @@ public function set( $args ) { } /** - * Deletes a value using the "delete_transient" function. + * Delete a transient value. * - * @param array $args + * @synopsis <key> */ public function delete( $args ) { - if ( empty( $args ) ) { - WP_CLI::warning( 'Usage: wp transient delete <key>' ); - exit; - } - list( $key ) = $args; if ( delete_transient( $key ) ) { @@ -81,7 +66,7 @@ public function delete( $args ) { } /** - * Indicates whether the transients API is using the object cache or options table in the current environment. + * See wether the transients API is using an object cache or the options table. */ public function type() { global $_wp_using_ext_object_cache, $wpdb; From 8f7414fef3733be33c72186a48bb043bce6f37e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 17:49:27 +0300 Subject: [PATCH 0649/5359] add --json flag for wp transient get --- src/php/wp-cli/commands/internals/transient.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php index 6c8a99824..4b6d24662 100644 --- a/src/php/wp-cli/commands/internals/transient.php +++ b/src/php/wp-cli/commands/internals/transient.php @@ -13,9 +13,9 @@ class Transient_Command extends WP_CLI_Command { /** * Get a transient value. * - * @synopsis <key> + * @synopsis <key> [--json] */ - public function get( $args ) { + public function get( $args, $assoc_args ) { list( $key ) = $args; $value = get_transient( $key ); @@ -25,10 +25,7 @@ public function get( $args ) { exit; } - if ( is_array( $value ) || is_object( $value ) ) - echo var_export( $value ) . "\n"; - else - echo $value . "\n"; + WP_CLI::print_value( $value, $assoc_args ); } /** From b55729eaeb6b46cf4d0b4357742f6eca7dc570e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 17:54:56 +0300 Subject: [PATCH 0650/5359] add synopsis for wp post generate --- src/php/wp-cli/commands/internals/post.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 89ad3fccb..0813e3dfb 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -108,10 +108,9 @@ public function delete( $args, $assoc_args ) { } /** - * Generate posts + * Generate some posts. * - * @param array $args - * @param array $assoc_args + * @synopsis [--count=100] [--post_type=post] [--post_status=publish] [--post_author=<login>] [--post_date=<date>] [--max_depth=1] */ public function generate( $args, $assoc_args ) { global $wpdb; From 35e77ff4710e32111a169a0116384037cf2a9944 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 18:03:30 +0300 Subject: [PATCH 0651/5359] add synopsis for wp post delete --- src/php/wp-cli/commands/internals/post.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 0813e3dfb..2708f718d 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -52,13 +52,11 @@ public function update( $args, $assoc_args ) { } /** - * Delete a single post, or series of posts based on arguments + * Delete a single post, or series of posts based on arguments. * - * @param array $args - * @param array $assoc_args + * @synopsis [<ID>] [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] */ public function delete( $args, $assoc_args ) { - $defaults = array( 'p' => null, 'post_type' => null, From fc588a3a4f15a3a41d93b5e379a9eb4f6ebda914 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 18:15:22 +0300 Subject: [PATCH 0652/5359] introduce wp post delete-many --- src/php/wp-cli/commands/internals/post.php | 58 ++++++++++------------ 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 2708f718d..4403efe5d 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -52,51 +52,45 @@ public function update( $args, $assoc_args ) { } /** - * Delete a single post, or series of posts based on arguments. + * Delete a post by ID. * - * @synopsis [<ID>] [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] + * @synopsis <id> */ public function delete( $args, $assoc_args ) { - $defaults = array( - 'p' => null, - 'post_type' => null, - 'post_author' => null, - 'post_status' => 'any', - 'force' => false, - ); - $assoc_args = wp_parse_args( $assoc_args, $defaults ); + $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); - // Support for simply passing the post ID as the first argument - if ( isset( $args[0] ) && is_numeric( $args[0] ) ) - $post_id = $args[0]; - else if ( is_numeric( $assoc_args['p'] ) ) - $post_id = $assoc_args['p']; - else - $post_id = false; + $this->_delete_posts( array( $post_id ), isset( $assoc_args['force'] ) ); + } - if ( $post_id ) { - $posts_to_delete = array( $post_id ); - } else { - $query_args = array( - 'fields' => 'ids', - 'posts_per_page' => -1, - 'post_type' => $assoc_args['post_type'], - 'post_author' => $assoc_args['post_author'], - 'post_status' => $assoc_args['post_status'], - ); - $maybe_posts = new WP_Query( $query_args ); - $posts_to_delete = $maybe_posts->posts; - } + /** + * Delete a series of posts based on arguments. + * + * @subcommand delete-many + * @synopsis [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] + */ + public function delete_many( $_, $assoc_args ) { + $query_args = array( + 'fields' => 'ids', + 'posts_per_page' => -1, + 'post_type' => $assoc_args['post_type'], + 'post_author' => $assoc_args['post_author'], + 'post_status' => $assoc_args['post_status'], + ); + + $query = new WP_Query( $query_args ); + $posts_to_delete = $query->posts; if ( empty( $posts_to_delete ) ) { WP_CLI::error( "No posts to delete." ); } - $force = (bool) $assoc_args['force']; + $this->_delete_posts( $posts_to_delete, isset( $assoc_args['force'] ) ); + } + protected function _delete_posts( $post_ids, $force ) { $action = $force ? 'Deleted' : 'Trashed'; - foreach ( $posts_to_delete as $post_id ) { + foreach ( $post_ids as $post_id ) { if ( wp_delete_post( $post_id, $force ) ) { WP_CLI::success( "{$action} post $post_id." ); } else { From d20d837428d35e9f8869b8d943a3bc737dcced74 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Oct 2012 18:26:27 +0300 Subject: [PATCH 0653/5359] allow wp post delete to accept more than one ID --- src/php/wp-cli/commands/internals/post.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 4403efe5d..027f0a184 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -54,12 +54,10 @@ public function update( $args, $assoc_args ) { /** * Delete a post by ID. * - * @synopsis <id> + * @synopsis <id>... [--force] */ public function delete( $args, $assoc_args ) { - $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); - - $this->_delete_posts( array( $post_id ), isset( $assoc_args['force'] ) ); + $this->_delete_posts( $args, isset( $assoc_args['force'] ) ); } /** From bdda3cb96c88523ed22b9e892d5aafd4469449b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 00:54:36 +0300 Subject: [PATCH 0654/5359] index synopsis parameters by type --- src/php/wp-cli/class-defaultdict.php | 44 ++++++++++++++++++++++++ src/php/wp-cli/dispatcher-subcommand.php | 18 +++++----- src/php/wp-cli/wp-cli.php | 1 + 3 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/php/wp-cli/class-defaultdict.php diff --git a/src/php/wp-cli/class-defaultdict.php b/src/php/wp-cli/class-defaultdict.php new file mode 100644 index 000000000..6dcbece2a --- /dev/null +++ b/src/php/wp-cli/class-defaultdict.php @@ -0,0 +1,44 @@ +<?php + +namespace WP_CLI\Utils; + +class Defaultdict implements \ArrayAccess { + + private $container = array(); + private $default; + + public function __construct( $default ) { + $this->default = $default; + } + + public function offsetSet( $offset, $value ) { + if ( is_null($offset) ) { + trigger_error( sprintf( "Trying to use %s as a list.", __CLASS__ ), E_USER_WARNING ); + return; + } + + $this->container[$offset] = $value; + } + + public function offsetExists( $offset ) { + return true; + } + + public function offsetUnset( $offset ) { + unset( $this->container[$offset] ); + } + + public function &offsetGet( $offset ) { + if ( !isset( $this->container[$offset] ) ) { + if ( is_callable($this->default) ) + $value = call_user_func( $this->default, $offset ); + else + $value = $this->default; + + $this->container[$offset] = $value; + } + + return $this->container[$offset]; + } +} + diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index 2bebf609d..1025a28b6 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -24,8 +24,8 @@ protected function check_args( $args, $assoc_args ) { private function check_positional( $args, $accepted_params ) { $count = 0; - foreach ( $accepted_params as $param ) { - if ( 'positional' == $param['type'] && !$param['optional'] ) + foreach ( $accepted_params['positional'] as $param ) { + if ( !$param['optional'] ) $count++; } @@ -38,8 +38,8 @@ private function check_positional( $args, $accepted_params ) { private function check_assoc( $assoc_args, $accepted_params ) { $mandatory_assoc = array(); - foreach ( $accepted_params as $param ) { - if ( 'assoc' == $param['type'] && !$param['optional'] ) + foreach ( $accepted_params['assoc'] as $param ) { + if ( !$param['optional'] ) $mandatory_assoc[] = $param['name']; } @@ -64,9 +64,10 @@ private function check_assoc( $assoc_args, $accepted_params ) { private function check_unknown_assoc( $assoc_args, $accepted_params ) { $known_assoc = array(); - foreach ( $accepted_params as $param ) { - if ( 'positional' != $param['type'] ) + foreach ( array( 'assoc', 'flag' ) as $type ) { + foreach ( $accepted_params[$type] as $param ) { $known_assoc[] = $param['name']; + } } $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); @@ -90,12 +91,13 @@ protected function parse_synopsis( $synopsis ) { $tokens = preg_split( '/[\s\t]+/', $synopsis ); - $params = array(); + $params = new \WP_CLI\Utils\Defaultdict( array() ); foreach ( $tokens as $token ) { foreach ( $patterns as $regex => $desc ) { if ( preg_match( $regex, $token, $matches ) ) { - $params[] = array_merge( $matches, $desc ); + $type = $desc['type']; + $params[$type][] = array_merge( $matches, $desc ); break; } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c16180459..42c006192 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,6 +14,7 @@ define( 'WP_CLI', true ); // Include the wp-cli classes +include WP_CLI_ROOT . 'class-defaultdict.php'; include WP_CLI_ROOT . 'dispatcher-subcommand.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; From 49f196e1ae8d85c07ce65d600598953edf8447ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 01:45:19 +0300 Subject: [PATCH 0655/5359] first pass at wp post list --- src/php/wp-cli/commands/internals/post.php | 64 ++++++++++++++-------- src/php/wp-cli/commands/internals/user.php | 3 +- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 027f0a184..19068f196 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -56,44 +56,60 @@ public function update( $args, $assoc_args ) { * * @synopsis <id>... [--force] */ - public function delete( $args, $assoc_args ) { - $this->_delete_posts( $args, isset( $assoc_args['force'] ) ); + public function delete( $post_ids, $assoc_args ) { + $action = isset( $assoc_args['force'] ) ? 'Deleted' : 'Trashed'; + + foreach ( $post_ids as $post_id ) { + if ( wp_delete_post( $post_id, $force ) ) { + WP_CLI::success( "{$action} post $post_id." ); + } else { + WP_CLI::error( "Failed deleting post $post_id." ); + } + } } /** - * Delete a series of posts based on arguments. + * Get a list of posts. * - * @subcommand delete-many - * @synopsis [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] + * @subcommand list */ - public function delete_many( $_, $assoc_args ) { + public function _list( $_, $assoc_args ) { $query_args = array( - 'fields' => 'ids', - 'posts_per_page' => -1, - 'post_type' => $assoc_args['post_type'], - 'post_author' => $assoc_args['post_author'], - 'post_status' => $assoc_args['post_status'], + 'posts_per_page' => -1 ); - $query = new WP_Query( $query_args ); - $posts_to_delete = $query->posts; + foreach ( $assoc_args as $key => $value ) { + if ( true === $value ) + continue; - if ( empty( $posts_to_delete ) ) { - WP_CLI::error( "No posts to delete." ); + $query_args[ $key ] = $value; } - $this->_delete_posts( $posts_to_delete, isset( $assoc_args['force'] ) ); - } + if ( isset( $assoc_args['ids'] ) ) + $query_args['fields'] = 'ids'; - protected function _delete_posts( $post_ids, $force ) { - $action = $force ? 'Deleted' : 'Trashed'; + $query = new WP_Query( $query_args ); - foreach ( $post_ids as $post_id ) { - if ( wp_delete_post( $post_id, $force ) ) { - WP_CLI::success( "{$action} post $post_id." ); - } else { - WP_CLI::error( "Failed deleting post $post_id." ); + if ( isset( $assoc_args['ids'] ) ) { + WP_CLI::out( implode( ' ', $query->posts ) ); + } else { + $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); + + $table = new \cli\Table(); + + $table->setHeaders( $fields ); + + foreach ( $query->posts as $post ) { + $line = array(); + + foreach ( $fields as $field ) { + $line[] = $post->$field; + } + + $table->addRow( $line ); } + + $table->display(); } } diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index d0a695961..7fe8ca529 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -28,11 +28,12 @@ public function _list( $args, $assoc_args ) { $params['role'] = $assoc_args['role']; } - $table = new \cli\Table(); $users = get_users( $params ); $fields = array('ID', 'user_login', 'display_name', 'user_email', 'user_registered'); + $table = new \cli\Table(); + $table->setHeaders( array_merge($fields, array('roles')) ); foreach ( $users as $user ) { From 52c0d43fde6a0ebb0435ebf4b08e62b5f4824456 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 01:48:31 +0300 Subject: [PATCH 0656/5359] update docs for wp post delete --- man/post-delete.1 | 26 ++++---------------------- src/docs/post-delete.txt | 18 +++--------------- 2 files changed, 7 insertions(+), 37 deletions(-) diff --git a/man/post-delete.1 b/man/post-delete.1 index 9ca88b26d..616087a1e 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-DELETE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-POST\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-delete\fR \- Delete a WordPress post\. +\fBwp\-post\-delete\fR \- Delete one or several posts by ID\. . .SH "SYNOPSIS" -\fBwp post delete\fR [\fIID\fR] [\-\-post_type=\fIvalue\fR] [\-\-post_author=\fIvalue\fR] [\-\-post_status=\fIvalue\fR] [\-\-force] +\fBwp post delete\fR \fIID\fR\.\.\. [\-\-force] . .SH "OPTIONS" . @@ -18,24 +18,6 @@ The ID of the post to delete\. . .TP -\fB\-\-post_type\fR: -. -.IP -Trash or delete all posts of a given post type -. -.TP -\fB\-\-post_author\fR: -. -.IP -Trash or delete all posts written by a specific user -. -.TP -\fB\-\-post_status\fR: -. -.IP -Trash or delete all posts of a given post status -. -.TP \fB\-\-force\fR: . .IP @@ -47,7 +29,7 @@ Skip the trash bin\. wp post delete 123 \-\-force -wp post delete \-\-post_type=page \-\-post_status=draft +wp post delete $(wp post list \-\-post_type=\'page\' \-\-ids) . .fi diff --git a/src/docs/post-delete.txt b/src/docs/post-delete.txt index f2a017101..21ce192f6 100644 --- a/src/docs/post-delete.txt +++ b/src/docs/post-delete.txt @@ -1,9 +1,9 @@ -wp-post-delete(1) -- Delete a WordPress post. +wp-post-delete(1) -- Delete one or several posts by ID. ==== ## SYNOPSIS -`wp post delete` [<ID>] [--post_type=<value>] [--post_author=<value>] [--post_status=<value>] [--force] +`wp post delete` <ID>... [--force] ## OPTIONS @@ -11,18 +11,6 @@ wp-post-delete(1) -- Delete a WordPress post. The ID of the post to delete. -* `--post_type`: - - Trash or delete all posts of a given post type - -* `--post_author`: - - Trash or delete all posts written by a specific user - -* `--post_status`: - - Trash or delete all posts of a given post status - * `--force`: Skip the trash bin. @@ -31,4 +19,4 @@ wp-post-delete(1) -- Delete a WordPress post. wp post delete 123 --force - wp post delete --post_type=page --post_status=draft + wp post delete $(wp post list --post_type='page' --ids) From bf8f34df9ba90102251f4d5177d2da83b92b7fba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 01:56:39 +0300 Subject: [PATCH 0657/5359] don't check args if synopsis isn't set --- src/php/wp-cli/dispatcher-subcommand.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index 1025a28b6..9b716b7fb 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -12,7 +12,11 @@ abstract function show_usage(); abstract function invoke( $args, $assoc_args ); protected function check_args( $args, $assoc_args ) { - $accepted_params = $this->parse_synopsis( $this->get_synopsis() ); + $synopsis = $this->get_synopsis(); + if ( !$synopsis ) + return; + + $accepted_params = $this->parse_synopsis( $synopsis ); $this->check_positional( $args, $accepted_params ); From 472f680e74077cb229725b4a6da11410814c4379 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 02:05:30 +0300 Subject: [PATCH 0658/5359] add docs for wp post list --- man/post-list.1 | 29 +++++++++++++++++++++++++++++ src/docs/post-list.txt | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 man/post-list.1 create mode 100644 src/docs/post-list.txt diff --git a/man/post-list.1 b/man/post-list.1 new file mode 100644 index 000000000..cb8d82da8 --- /dev/null +++ b/man/post-list.1 @@ -0,0 +1,29 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-LIST" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-list\fR \- Get a list of posts\. +. +.SH "SYNOPSIS" +\fBwp post list\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-ids] +. +.SH "OPTIONS" +. +.TP +\fB\-\-<field>\fR=\fIvalue\fR: +. +.IP +One or more args to pass to WP_Query\. +. +.SH "EXAMPLES" +. +.nf + +wp post list + +wp post list \-\-post_type=page \-\-post_status=draft \-\-ids +. +.fi + diff --git a/src/docs/post-list.txt b/src/docs/post-list.txt new file mode 100644 index 000000000..e2d9bd295 --- /dev/null +++ b/src/docs/post-list.txt @@ -0,0 +1,18 @@ +wp-post-list(1) -- Get a list of posts. +==== + +## SYNOPSIS + +`wp post list` --<field>=<value> [--<field>=<value>...] [--ids] + +## OPTIONS + +* `--<field>`=<value>: + + One or more args to pass to WP_Query. + +## EXAMPLES + + wp post list + + wp post list --post_type=page --post_status=draft --ids From c8ebd125c25f45b707b79b5b67cc437987e512b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 04:12:29 +0300 Subject: [PATCH 0659/5359] document the --ids flag. see #182 --- man/post-list.1 | 6 ++++++ src/docs/post-list.txt | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/man/post-list.1 b/man/post-list.1 index cb8d82da8..b66c8137a 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -17,6 +17,12 @@ .IP One or more args to pass to WP_Query\. . +.TP +\fB\-\-ids\fR: +. +.IP +Return only the IDs of the found posts, separated by spaces\. +. .SH "EXAMPLES" . .nf diff --git a/src/docs/post-list.txt b/src/docs/post-list.txt index e2d9bd295..de04f98ea 100644 --- a/src/docs/post-list.txt +++ b/src/docs/post-list.txt @@ -11,6 +11,10 @@ wp-post-list(1) -- Get a list of posts. One or more args to pass to WP_Query. +* `--ids`: + + Return only the IDs of the found posts, separated by spaces. + ## EXAMPLES wp post list From f0650e5b01b99f582542d3ebde4cc3dd8fc2ae1d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 16:45:17 +0300 Subject: [PATCH 0660/5359] manually initialize empty arrays instead of using Defaultdict. see #184 --- src/php/wp-cli/class-defaultdict.php | 44 ------------------------ src/php/wp-cli/dispatcher-subcommand.php | 10 +++--- src/php/wp-cli/wp-cli.php | 1 - 3 files changed, 6 insertions(+), 49 deletions(-) delete mode 100644 src/php/wp-cli/class-defaultdict.php diff --git a/src/php/wp-cli/class-defaultdict.php b/src/php/wp-cli/class-defaultdict.php deleted file mode 100644 index 6dcbece2a..000000000 --- a/src/php/wp-cli/class-defaultdict.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php - -namespace WP_CLI\Utils; - -class Defaultdict implements \ArrayAccess { - - private $container = array(); - private $default; - - public function __construct( $default ) { - $this->default = $default; - } - - public function offsetSet( $offset, $value ) { - if ( is_null($offset) ) { - trigger_error( sprintf( "Trying to use %s as a list.", __CLASS__ ), E_USER_WARNING ); - return; - } - - $this->container[$offset] = $value; - } - - public function offsetExists( $offset ) { - return true; - } - - public function offsetUnset( $offset ) { - unset( $this->container[$offset] ); - } - - public function &offsetGet( $offset ) { - if ( !isset( $this->container[$offset] ) ) { - if ( is_callable($this->default) ) - $value = call_user_func( $this->default, $offset ); - else - $value = $this->default; - - $this->container[$offset] = $value; - } - - return $this->container[$offset]; - } -} - diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index 9b716b7fb..a60ca8dc7 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -91,12 +91,10 @@ protected function get_synopsis() { } protected function parse_synopsis( $synopsis ) { - $patterns = self::get_patterns(); + list( $patterns, $params ) = self::get_patterns(); $tokens = preg_split( '/[\s\t]+/', $synopsis ); - $params = new \WP_CLI\Utils\Defaultdict( array() ); - foreach ( $tokens as $token ) { foreach ( $patterns as $regex => $desc ) { if ( preg_match( $regex, $token, $matches ) ) { @@ -134,7 +132,11 @@ private static function get_patterns() { ); } - return $patterns; + $params = array(); + foreach ( array_keys( $param_types ) as $type ) + $params[$type] = array(); + + return array( $patterns, $params ); } } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 42c006192..c16180459 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,7 +14,6 @@ define( 'WP_CLI', true ); // Include the wp-cli classes -include WP_CLI_ROOT . 'class-defaultdict.php'; include WP_CLI_ROOT . 'dispatcher-subcommand.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; From de3929e4222432a08044eda57ce651f04bfb39b8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 16:50:49 +0300 Subject: [PATCH 0661/5359] move concrete methods into a separate AbstractSubcommand class see #184 --- src/php/wp-cli/dispatcher-subcommand.php | 14 +++++++++----- src/php/wp-cli/dispatcher.php | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php index a60ca8dc7..a6e52c8a0 100644 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ b/src/php/wp-cli/dispatcher-subcommand.php @@ -2,15 +2,19 @@ namespace WP_CLI\Dispatcher; -abstract class Subcommand { +interface Subcommand { + + function show_usage(); + function invoke( $arguments, $assoc_args ); +} + + +abstract class AbstractSubcommand implements Subcommand { function __construct( $method ) { $this->method = $method; } - abstract function show_usage(); - abstract function invoke( $args, $assoc_args ); - protected function check_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); if ( !$synopsis ) @@ -141,7 +145,7 @@ private static function get_patterns() { } -class MethodSubcommand extends Subcommand { +class MethodSubcommand extends AbstractSubcommand { function __construct( $method, $parent ) { $this->parent = $parent; diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index b6d5e6398..2bbc3cffa 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -101,7 +101,7 @@ private static function _is_good_method( $method ) { } -class SingleCommand extends Subcommand implements Command { +class SingleCommand extends AbstractSubcommand implements Command { function __construct( $name, $callable ) { $this->name = $name; From 95459766384e1339333f3938b77e0660024abb6c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 16:59:58 +0300 Subject: [PATCH 0662/5359] use Command interface for all dispatcher classes --- src/php/wp-cli/dispatcher-subcommand.php | 182 ----------------------- src/php/wp-cli/dispatcher.php | 182 ++++++++++++++++++++++- src/php/wp-cli/wp-cli.php | 1 - 3 files changed, 181 insertions(+), 184 deletions(-) delete mode 100644 src/php/wp-cli/dispatcher-subcommand.php diff --git a/src/php/wp-cli/dispatcher-subcommand.php b/src/php/wp-cli/dispatcher-subcommand.php deleted file mode 100644 index a6e52c8a0..000000000 --- a/src/php/wp-cli/dispatcher-subcommand.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -interface Subcommand { - - function show_usage(); - function invoke( $arguments, $assoc_args ); -} - - -abstract class AbstractSubcommand implements Subcommand { - - function __construct( $method ) { - $this->method = $method; - } - - protected function check_args( $args, $assoc_args ) { - $synopsis = $this->get_synopsis(); - if ( !$synopsis ) - return; - - $accepted_params = $this->parse_synopsis( $synopsis ); - - $this->check_positional( $args, $accepted_params ); - - $this->check_assoc( $assoc_args, $accepted_params ); - - $this->check_unknown_assoc( $assoc_args, $accepted_params ); - } - - private function check_positional( $args, $accepted_params ) { - $count = 0; - - foreach ( $accepted_params['positional'] as $param ) { - if ( !$param['optional'] ) - $count++; - } - - if ( count( $args ) < $count ) { - $this->show_usage(); - exit(1); - } - } - - private function check_assoc( $assoc_args, $accepted_params ) { - $mandatory_assoc = array(); - - foreach ( $accepted_params['assoc'] as $param ) { - if ( !$param['optional'] ) - $mandatory_assoc[] = $param['name']; - } - - $errors = array(); - - foreach ( $mandatory_assoc as $key ) { - if ( !isset( $assoc_args[ $key ] ) ) - $errors[] = "missing --$key parameter"; - elseif ( true === $assoc_args[ $key ] ) - $errors[] = "--$key parameter needs a value"; - } - - if ( !empty( $errors ) ) { - foreach ( $errors as $error ) { - \WP_CLI::warning( $error ); - } - $this->show_usage(); - exit(1); - } - } - - private function check_unknown_assoc( $assoc_args, $accepted_params ) { - $known_assoc = array(); - - foreach ( array( 'assoc', 'flag' ) as $type ) { - foreach ( $accepted_params[$type] as $param ) { - $known_assoc[] = $param['name']; - } - } - - $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); - - foreach ( $unknown_assoc as $key ) { - \WP_CLI::warning( "unkown --$key parameter" ); - } - } - - protected function get_synopsis() { - $comment = $this->method->getDocComment(); - - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) - return false; - - return $matches[1]; - } - - protected function parse_synopsis( $synopsis ) { - list( $patterns, $params ) = self::get_patterns(); - - $tokens = preg_split( '/[\s\t]+/', $synopsis ); - - foreach ( $tokens as $token ) { - foreach ( $patterns as $regex => $desc ) { - if ( preg_match( $regex, $token, $matches ) ) { - $type = $desc['type']; - $params[$type][] = array_merge( $matches, $desc ); - break; - } - } - } - - return $params; - } - - private static function get_patterns() { - $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '<(?P<value>[a-z-|]+)>'; - - $param_types = array( - 'positional' => $p_value, - 'assoc' => "--$p_name=$p_value", - 'flag' => "--$p_name" - ); - - $patterns = array(); - - foreach ( $param_types as $type => $pattern ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); - - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); - } - - $params = array(); - foreach ( array_keys( $param_types ) as $type ) - $params[$type] = array(); - - return array( $patterns, $params ); - } -} - - -class MethodSubcommand extends AbstractSubcommand { - - function __construct( $method, $parent ) { - $this->parent = $parent; - - parent::__construct( $method ); - } - - function show_usage( $prefix = 'usage: ' ) { - $command = $this->parent->name; - $subcommand = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $command $subcommand $synopsis" ); - } - - function get_name() { - $comment = $this->method->getDocComment(); - - if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) - return $matches[1]; - - return $this->method->name; - } - - function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - - $class = $this->parent->class; - $instance = new $class; - - $this->method->invoke( $instance, $args, $assoc_args ); - } -} - diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 2bbc3cffa..4c5145622 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -101,7 +101,187 @@ private static function _is_good_method( $method ) { } -class SingleCommand extends AbstractSubcommand implements Command { +abstract class Subcommand implements Command { + + function __construct( $method ) { + $this->method = $method; + } + + protected function check_args( $args, $assoc_args ) { + $synopsis = $this->get_synopsis(); + if ( !$synopsis ) + return; + + $accepted_params = $this->parse_synopsis( $synopsis ); + + $this->check_positional( $args, $accepted_params ); + + $this->check_assoc( $assoc_args, $accepted_params ); + + $this->check_unknown_assoc( $assoc_args, $accepted_params ); + } + + private function check_positional( $args, $accepted_params ) { + $count = 0; + + foreach ( $accepted_params['positional'] as $param ) { + if ( !$param['optional'] ) + $count++; + } + + if ( count( $args ) < $count ) { + $this->show_usage(); + exit(1); + } + } + + private function check_assoc( $assoc_args, $accepted_params ) { + $mandatory_assoc = array(); + + foreach ( $accepted_params['assoc'] as $param ) { + if ( !$param['optional'] ) + $mandatory_assoc[] = $param['name']; + } + + $errors = array(); + + foreach ( $mandatory_assoc as $key ) { + if ( !isset( $assoc_args[ $key ] ) ) + $errors[] = "missing --$key parameter"; + elseif ( true === $assoc_args[ $key ] ) + $errors[] = "--$key parameter needs a value"; + } + + if ( !empty( $errors ) ) { + foreach ( $errors as $error ) { + \WP_CLI::warning( $error ); + } + $this->show_usage(); + exit(1); + } + } + + private function check_unknown_assoc( $assoc_args, $accepted_params ) { + $known_assoc = array(); + + foreach ( array( 'assoc', 'flag' ) as $type ) { + foreach ( $accepted_params[$type] as $param ) { + $known_assoc[] = $param['name']; + } + } + + $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); + + foreach ( $unknown_assoc as $key ) { + \WP_CLI::warning( "unkown --$key parameter" ); + } + } + + protected function get_synopsis() { + $comment = $this->method->getDocComment(); + + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) + return false; + + return $matches[1]; + } + + protected function parse_synopsis( $synopsis ) { + list( $patterns, $params ) = self::get_patterns(); + + $tokens = preg_split( '/[\s\t]+/', $synopsis ); + + foreach ( $tokens as $token ) { + foreach ( $patterns as $regex => $desc ) { + if ( preg_match( $regex, $token, $matches ) ) { + $type = $desc['type']; + $params[$type][] = array_merge( $matches, $desc ); + break; + } + } + } + + return $params; + } + + private static function get_patterns() { + $p_name = '(?P<name>[a-z-_]+)'; + $p_value = '<(?P<value>[a-z-|]+)>'; + + $param_types = array( + 'positional' => $p_value, + 'assoc' => "--$p_name=$p_value", + 'flag' => "--$p_name" + ); + + $patterns = array(); + + foreach ( $param_types as $type => $pattern ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } + + $params = array(); + foreach ( array_keys( $param_types ) as $type ) + $params[$type] = array(); + + return array( $patterns, $params ); + } +} + + +class MethodSubcommand extends Subcommand { + + function __construct( $method, $parent ) { + $this->parent = $parent; + + parent::__construct( $method ); + } + + function autocomplete() { + throw new Exception( "Not implemented." ); + } + + function shortdesc() { + throw new Exception( "Not implemented." ); + } + + function show_usage( $prefix = 'usage: ' ) { + $command = $this->parent->name; + $subcommand = $this->get_name(); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $command $subcommand $synopsis" ); + } + + function get_name() { + $comment = $this->method->getDocComment(); + + if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + return $matches[1]; + + return $this->method->name; + } + + function invoke( $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + + $class = $this->parent->class; + $instance = new $class; + + $this->method->invoke( $instance, $args, $assoc_args ); + } +} + + +class SingleCommand extends Subcommand { function __construct( $name, $callable ) { $this->name = $name; diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c16180459..0194beb6a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,7 +14,6 @@ define( 'WP_CLI', true ); // Include the wp-cli classes -include WP_CLI_ROOT . 'dispatcher-subcommand.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; From 7b50818bb586f6e8b92bac44ccd865d64d98f1c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 18:22:19 +0300 Subject: [PATCH 0663/5359] introduce get_subcommand_names() helper --- src/php/wp-cli/dispatcher.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 4c5145622..86ee6e14a 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -19,14 +19,11 @@ function __construct( $name, $class ) { } function autocomplete() { - $subcommands = array_keys( $this->get_subcommands() ); - return $this->name . ' ' . implode( ' ', $subcommands ); + return $this->name . ' ' . implode( ' ', $this->get_subcommand_names() ); } function shortdesc() { - $methods = array_keys( $this->get_subcommands() ); - - return implode( '|', $methods ); + return implode( '|', $this->get_subcommand_names() ); } function show_usage() { @@ -78,6 +75,10 @@ protected function find_subcommand( &$args ) { return $subcommands[ $name ]; } + private function get_subcommand_names() { + return array_keys( $this->get_subcommands() ); + } + private function get_subcommands() { $reflection = new \ReflectionClass( $this->class ); From 29f3357c42465996466dc1531b6fcf36a4e68a0f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 18:23:01 +0300 Subject: [PATCH 0664/5359] make find_subcommand() private --- src/php/wp-cli/dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 86ee6e14a..7e353b9d1 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -52,7 +52,7 @@ function invoke( $args, $assoc_args ) { $subcommand->invoke( $args, $assoc_args ); } - protected function find_subcommand( &$args ) { + private function find_subcommand( &$args ) { $class = $this->class; if ( empty( $args ) ) { From f26ff3383e13eccea23aa107f74be6108d81e5ef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 18:57:59 +0300 Subject: [PATCH 0665/5359] make get_name() mandatory for Subcommand classes --- src/php/wp-cli/dispatcher.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 7e353b9d1..fcbf9f938 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -108,6 +108,8 @@ function __construct( $method ) { $this->method = $method; } + abstract function get_name(); + protected function check_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); if ( !$synopsis ) @@ -293,6 +295,10 @@ function __construct( $name, $callable ) { parent::__construct( $method ); } + function get_name() { + return $this->name; + } + function autocomplete() { return $this->name; } @@ -302,7 +308,7 @@ function shortdesc() { } function show_usage( $prefix = 'usage: ' ) { - $command = $this->name; + $command = $this->get_name(); $synopsis = $this->get_synopsis(); \WP_CLI::line( $prefix . "wp $command $synopsis" ); From 10f26ae37b88c664b5957f01ec55cb7a20c6b2ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 19:04:45 +0300 Subject: [PATCH 0666/5359] introduce TopLevelCommand. see #184 --- src/php/wp-cli/dispatcher.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index fcbf9f938..a409c7035 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -4,14 +4,18 @@ interface Command { - function autocomplete(); - function shortdesc(); function show_usage(); function invoke( $arguments, $assoc_args ); } +interface TopLevelCommand { + + function autocomplete(); + function shortdesc(); +} + -class CompositeCommand implements Command { +class CompositeCommand implements Command, TopLevelCommand { function __construct( $name, $class ) { $this->name = $name; @@ -248,14 +252,6 @@ function __construct( $method, $parent ) { parent::__construct( $method ); } - function autocomplete() { - throw new Exception( "Not implemented." ); - } - - function shortdesc() { - throw new Exception( "Not implemented." ); - } - function show_usage( $prefix = 'usage: ' ) { $command = $this->parent->name; $subcommand = $this->get_name(); @@ -284,7 +280,7 @@ function invoke( $args, $assoc_args ) { } -class SingleCommand extends Subcommand { +class SingleCommand extends Subcommand implements TopLevelCommand { function __construct( $name, $callable ) { $this->name = $name; From be9f305ca7815b4569daa8cf84904ac7c0b77571 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 19:38:33 +0300 Subject: [PATCH 0667/5359] move WP_CLI::parse_args() to WP_CLI\Utils\parse_args() --- src/php/wp-cli/class-wp-cli.php | 23 ----------------------- src/php/wp-cli/utils.php | 27 +++++++++++++++++++++++++++ src/php/wp-cli/wp-cli.php | 3 ++- 3 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 src/php/wp-cli/utils.php diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index eb084f6a3..c961bb56f 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -129,29 +129,6 @@ static function error_to_string( $errors ) { } } - /** - * Splits a string into positional and associative arguments. - * - * @param string - * @return array - */ - static function parse_args( $arguments ) { - $regular_args = array(); - $assoc_args = array(); - - foreach ( $arguments as $arg ) { - if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = true; - } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = $matches[2]; - } else { - $regular_args[] = $arg; - } - } - - return array( $regular_args, $assoc_args ); - } - /** * Composes positional and associative arguments into a string. * diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php new file mode 100644 index 000000000..f9d667092 --- /dev/null +++ b/src/php/wp-cli/utils.php @@ -0,0 +1,27 @@ +<?php + +namespace WP_CLI\Utils; + +/** + * Splits $argv into positional and associative arguments. + * + * @param string + * @return array + */ +function parse_args() { + $regular_args = array(); + $assoc_args = array(); + + foreach ( array_slice( $GLOBALS['argv'], 1 ) as $arg ) { + if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = true; + } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = $matches[2]; + } else { + $regular_args[] = $arg; + } + } + + return array( $regular_args, $assoc_args ); +} + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 0194beb6a..6a0aa01ca 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -14,6 +14,7 @@ define( 'WP_CLI', true ); // Include the wp-cli classes +include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; @@ -27,7 +28,7 @@ \cli\register_autoload(); // Get the cli arguments -list( $arguments, $assoc_args ) = WP_CLI::parse_args( array_slice( $GLOBALS['argv'], 1 ) ); +list( $arguments, $assoc_args ) = WP_CLI\Utils\parse_args(); // Set output levels define( 'WP_CLI_AUTOCOMPLETE', isset( $assoc_args['completions'] ) ); From d0153c7ac20752ae57d333748bd78782fa285e5a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 19:53:26 +0300 Subject: [PATCH 0668/5359] move WP_CLI::_set_url() & co to WP_CLI\Utils\ --- src/php/wp-cli/class-wp-cli.php | 74 ---------------------- src/php/wp-cli/commands/internals/core.php | 2 +- src/php/wp-cli/utils.php | 74 ++++++++++++++++++++++ src/php/wp-cli/wp-cli.php | 4 +- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index c961bb56f..5a557ff1c 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -177,24 +177,6 @@ static function launch( $command, $exit_on_error = true ) { return $r; } - /** - * Sets the appropriate $_SERVER keys based on a given string - * - * @param string $url The URL - */ - static function set_url_params( $url ) { - $url_parts = parse_url( $url ); - - if ( !isset( $url_parts['scheme'] ) ) { - $url_parts = parse_url( 'http://' . $url ); - } - - $_SERVER['HTTP_HOST'] = isset($url_parts['host']) ? $url_parts['host'] : ''; - $_SERVER['REQUEST_URI'] = (isset($url_parts['path']) ? $url_parts['path'] : '') . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); - $_SERVER['REQUEST_URL'] = isset($url_parts['path']) ? $url_parts['path'] : ''; - $_SERVER['QUERY_STRING'] = isset($url_parts['query']) ? $url_parts['query'] : ''; - } - static function get_upgrader( $class ) { if ( !class_exists( 'WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; @@ -204,62 +186,6 @@ static function get_upgrader( $class ) { return new $class( new CLI_Upgrader_Skin ); } - static function _set_url( &$assoc_args ) { - if ( isset( $assoc_args['url'] ) ) { - $blog = $assoc_args['url']; - /* unset( $assoc_args['url'] ); */ - } elseif ( isset( $assoc_args['blog'] ) ) { - $blog = $assoc_args['blog']; - unset( $assoc_args['blog'] ); - if ( true === $blog ) { - WP_CLI::line( 'usage: wp --blog=example.com' ); - } - } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { - $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); - } elseif ( $wp_config_path = self::locate_wp_config() ) { - // Try to find the blog parameter in the wp-config file - $wp_config_file = file_get_contents( $wp_config_path ); - $hit = array(); - if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { - foreach ( $matches[2] as $def_key => $def_name ) { - if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[5][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[5][$def_key]; - } - } - - if ( !empty( $hit ) && isset( $hit['domain'] ) ) - $blog = $hit['domain']; - if ( !empty( $hit ) && isset( $hit['path'] ) ) - $blog .= $hit['path']; - } - - if ( isset( $blog ) ) { - WP_CLI::set_url_params( $blog ); - } - } - - // Loads wp-config.php without loading the rest of WP - static function load_wp_config() { - define( 'ABSPATH', dirname(__FILE__) . '/' ); - - if ( $wp_config_path = self::locate_wp_config() ) - require self::locate_wp_config(); - else - WP_CLI::error( 'No wp-config.php file.' ); - } - - static function locate_wp_config() { - if ( file_exists( WP_ROOT . 'wp-config.php' ) ) { - return WP_ROOT . 'wp-config.php'; - } elseif ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) { - return WP_ROOT . '/../wp-config.php'; - } else { - return false; - } - } - static function load_all_commands() { foreach ( array( 'internals', 'community' ) as $dir ) { foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 8ea46d4c2..cfef34390 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -137,7 +137,7 @@ public function install_network( $args, $assoc_args ) { <?php $ms_config = ob_get_clean(); - $wp_config_path = WP_CLI::locate_wp_config(); + $wp_config_path = WP_CLI\Utils\locate_wp_config(); $token = "/* That's all, stop editing!"; diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index f9d667092..cecec9b36 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -25,3 +25,77 @@ function parse_args() { return array( $regular_args, $assoc_args ); } +function set_url( &$assoc_args ) { + if ( isset( $assoc_args['url'] ) ) { + $blog = $assoc_args['url']; + /* unset( $assoc_args['url'] ); */ + } elseif ( isset( $assoc_args['blog'] ) ) { + $blog = $assoc_args['blog']; + unset( $assoc_args['blog'] ); + if ( true === $blog ) { + \WP_CLI::line( 'usage: wp --blog=example.com' ); + } + } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { + $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); + } elseif ( $wp_config_path = locate_wp_config() ) { + // Try to find the blog parameter in the wp-config file + $wp_config_file = file_get_contents( $wp_config_path ); + $hit = array(); + if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { + foreach ( $matches[2] as $def_key => $def_name ) { + if ( 'DOMAIN_CURRENT_SITE' == $def_name ) + $hit['domain'] = $matches[5][$def_key]; + if ( 'PATH_CURRENT_SITE' == $def_name ) + $hit['path'] = $matches[5][$def_key]; + } + } + + if ( !empty( $hit ) && isset( $hit['domain'] ) ) + $blog = $hit['domain']; + if ( !empty( $hit ) && isset( $hit['path'] ) ) + $blog .= $hit['path']; + } + + if ( isset( $blog ) ) { + set_url_params( $blog ); + } +} + +/** + * Sets the appropriate $_SERVER keys based on a given string + * + * @param string $url The URL + */ +function set_url_params( $url ) { + $url_parts = parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + + $_SERVER['HTTP_HOST'] = isset($url_parts['host']) ? $url_parts['host'] : ''; + $_SERVER['REQUEST_URI'] = (isset($url_parts['path']) ? $url_parts['path'] : '') . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); + $_SERVER['REQUEST_URL'] = isset($url_parts['path']) ? $url_parts['path'] : ''; + $_SERVER['QUERY_STRING'] = isset($url_parts['query']) ? $url_parts['query'] : ''; +} + +function locate_wp_config() { + if ( file_exists( WP_ROOT . 'wp-config.php' ) ) { + return WP_ROOT . 'wp-config.php'; + } elseif ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) { + return WP_ROOT . '/../wp-config.php'; + } else { + return false; + } +} + +// Loads wp-config.php without loading the rest of WP +function load_wp_config() { + define( 'ABSPATH', dirname(__FILE__) . '/' ); + + if ( $wp_config_path = locate_wp_config() ) + require locate_wp_config(); + else + WP_CLI::error( 'No wp-config.php file.' ); +} + diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 6a0aa01ca..938c8c99d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -57,7 +57,7 @@ } // Handle --url and --blog parameters -WP_CLI::_set_url( $assoc_args ); +WP_CLI\Utils\set_url( $assoc_args ); if ( array( 'core', 'download' ) == $arguments ) { WP_CLI::run_command( $arguments, $assoc_args ); @@ -75,7 +75,7 @@ // The db commands don't need any WP files if ( array( 'db' ) == array_slice( $arguments, 0, 1 ) ) { - WP_CLI::load_wp_config(); + WP_CLI\Utils\load_wp_config(); WP_CLI::run_command( $arguments, $assoc_args ); exit; } From c8be260a0f4acb17674a375b81a3fdfe0a3b8c54 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 20:00:03 +0300 Subject: [PATCH 0669/5359] introduce set_user() utility --- src/php/wp-cli/utils.php | 28 +++++++++++++++++++++++++++- src/php/wp-cli/wp-cli.php | 14 +------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index cecec9b36..bb6758f4d 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -96,6 +96,32 @@ function load_wp_config() { if ( $wp_config_path = locate_wp_config() ) require locate_wp_config(); else - WP_CLI::error( 'No wp-config.php file.' ); + \WP_CLI::error( 'No wp-config.php file.' ); +} + + + +// ---- AFTER WORDPRESS IS LOADED ---- // + + + +// Handle --user parameter +function set_user( &$assoc_args ) { + if ( !isset( $assoc_args['user'] ) ) + return; + + $user = $assoc_args['user']; + + if ( is_numeric( $user ) ) { + $user_id = (int) $user; + } else { + $user_id = (int) username_exists( $user ); + } + + if ( !$user_id || !wp_set_current_user( $user_id ) ) { + \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); + } + + unset( $assoc_args['user'] ); } diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 938c8c99d..e1bc29f1d 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -104,19 +104,7 @@ // Set filesystem method add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); -// Handle --user parameter -if ( isset( $assoc_args['user'] ) ) { - $user = $assoc_args['user']; - if ( is_numeric( $user ) ) { - $user_id = (int) $user; - } else { - $user_id = (int) username_exists( $user ); - } - if ( !$user_id || !wp_set_current_user( $user_id ) ) { - WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); - } - unset( $assoc_args['user'], $user ); -} +WP_CLI\Utils\set_user( $assoc_args ); // Handle --require parameter if ( isset( $assoc_args['require'] ) ) { From 083d8b27bc7b6cbeb90de9dc68e62736846b16cd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 20:15:41 +0300 Subject: [PATCH 0670/5359] move get_upgrader() to WP_CLI\Utils\ --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 6 +++--- src/php/wp-cli/class-wp-cli.php | 9 --------- src/php/wp-cli/commands/internals/core.php | 2 +- src/php/wp-cli/commands/internals/plugin.php | 2 +- src/php/wp-cli/commands/internals/theme.php | 4 ++-- src/php/wp-cli/utils.php | 9 +++++++++ 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index d76eaf63d..8357991a6 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -103,7 +103,7 @@ function install( $args, $assoc_args ) { $slug = stripslashes( $args[0] ); if ( '.zip' == substr( $slug, -4 ) ) { - $file_upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $file_upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); if ( $file_upgrader->install( $slug ) ) { $slug = $file_upgrader->result['destination_name']; @@ -125,7 +125,7 @@ function update( $args, $assoc_args ) { list( $file, $name ) = $this->parse_name( $args ); - WP_CLI::get_upgrader( $this->upgrader )->upgrade( $file ); + WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $file ); } function update_all( $args, $assoc_args ) { @@ -142,7 +142,7 @@ function update_all( $args, $assoc_args ) { // If --all, UPDATE ALL THE THINGS if ( isset( $assoc_args['all'] ) ) { - $upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); // Let the user know the results. diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 5a557ff1c..7bc6639d0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -177,15 +177,6 @@ static function launch( $command, $exit_on_error = true ) { return $r; } - static function get_upgrader( $class ) { - if ( !class_exists( 'WP_Upgrader' ) ) - require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - - require WP_CLI_ROOT . '/class-cli-upgrader-skin.php'; - - return new $class( new CLI_Upgrader_Skin ); - } - static function load_all_commands() { foreach ( array( 'internals', 'community' ) as $dir ) { foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index cfef34390..a652f3219 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -248,7 +248,7 @@ function update( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $result = WP_CLI::get_upgrader( $upgrader )->upgrade( $update ); + $result = WP_CLI\Utils\get_upgrader( $upgrader )->upgrade( $update ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 8a98361ea..2a57a486f 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -163,7 +163,7 @@ protected function install_from_repo( $slug, $assoc_args ) { switch ( $status['status'] ) { case 'update_available': case 'install': - $upgrader = WP_CLI::get_upgrader( $this->upgrader ); + $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); $result = $upgrader->install( $api->download_link ); if ( $result && isset( $assoc_args['activate'] ) ) { diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 24559601d..cceefb844 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -114,7 +114,7 @@ protected function install_from_repo( $slug, $assoc_args ) { // Check to see if we should update, rather than install. if ( $this->has_update( $slug ) ) { WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI::get_upgrader( $this->upgrader )->upgrade( $slug ); + $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $slug ); /** * Else, if there's no update, it's either not installed, @@ -122,7 +122,7 @@ protected function install_from_repo( $slug, $assoc_args ) { */ } else if ( !is_readable( $this->get_stylesheet_path( $slug ) ) ) { WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI::get_upgrader( $this->upgrader )->install( $api->download_link ); + $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); } else { WP_CLI::error( 'Theme already installed and up to date.' ); } diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index bb6758f4d..f91362645 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -125,3 +125,12 @@ function set_user( &$assoc_args ) { unset( $assoc_args['user'] ); } +function get_upgrader( $class ) { + if ( !class_exists( '\WP_Upgrader' ) ) + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + + require WP_CLI_ROOT . '/class-cli-upgrader-skin.php'; + + return new $class( new \CLI_Upgrader_Skin ); +} + From db2756351b388e8e1b73c213fb44b2a0471ae923 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 20:22:46 +0300 Subject: [PATCH 0671/5359] move SAPI check to wp-cli-boot.php --- src/php/wp-cli/wp-cli-boot.php | 5 +++++ src/php/wp-cli/wp-cli.php | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/wp-cli-boot.php b/src/php/wp-cli/wp-cli-boot.php index 972e60fd8..3effc22d4 100644 --- a/src/php/wp-cli/wp-cli-boot.php +++ b/src/php/wp-cli/wp-cli-boot.php @@ -1,5 +1,10 @@ <?php +if ( 'cli' !== PHP_SAPI ) { + echo "Only CLI access.\n"; + die(-1); +} + if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { printf( "Error: wp-cli requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); die(-1); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index e1bc29f1d..6a432666c 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -1,13 +1,7 @@ <?php -if ( PHP_SAPI !== 'cli' ) { - echo "Only CLI access.\n"; - die(-1); -} - define( 'WP_CLI_VERSION', '0.7.0-alpha' ); -// Define the wp-cli location define( 'WP_CLI_ROOT', __DIR__ . '/' ); // Set a constant that can be used to check if we are running wp-cli or not From e8b9231dea944bb723533e14a4eca7351cbf8b67 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 20:31:56 +0300 Subject: [PATCH 0672/5359] define WP_CLI_URL constant, instead of leaving 'url' in $assoc_args --- src/php/wp-cli/utils.php | 3 ++- src/php/wp-cli/wp-cli.php | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index f91362645..f6ee850ee 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -27,8 +27,9 @@ function parse_args() { function set_url( &$assoc_args ) { if ( isset( $assoc_args['url'] ) ) { + define( 'WP_CLI_URL', $assoc_args['url'] ); $blog = $assoc_args['url']; - /* unset( $assoc_args['url'] ); */ + unset( $assoc_args['url'] ); } elseif ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; unset( $assoc_args['blog'] ); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 6a432666c..04e3b4901 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -76,7 +76,7 @@ // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == $arguments ) { - define( 'WP_INSTALLING', true ); + define( 'WP_INSTALLING', true ); } // Load WordPress @@ -88,11 +88,11 @@ require ABSPATH . 'wp-admin/includes/admin.php'; // Load the right info into the global wp_query -if ( !defined( 'WP_INSTALLING' ) && isset( $assoc_args['url'] ) ) { - if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { - $GLOBALS['wp']->parse_request(); - $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); - } +if ( !defined( 'WP_INSTALLING' ) && defined( 'WP_CLI_URL' ) ) { + if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { + $GLOBALS['wp']->parse_request(); + $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); + } } // Set filesystem method From f1e358087ba9d16ac6ec7cbc5e0fb3ebe04d3867 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 21:34:37 +0300 Subject: [PATCH 0673/5359] Store arguments as properties on WP_CLI, instead of as global variables. This avoids having to define various constants. Also: - removes support for deprecated --help global parameter - removes support for deprecated --silent global parameter --- src/php/wp-cli/class-wp-cli.php | 111 ++++++++++++++++++++++++++++---- src/php/wp-cli/dispatcher.php | 2 + src/php/wp-cli/utils.php | 37 ++++++++--- src/php/wp-cli/wp-cli.php | 94 +-------------------------- 4 files changed, 132 insertions(+), 112 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 7bc6639d0..45ad48ca5 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -51,7 +51,7 @@ static function line( $message = '' ) { * @param string $label */ static function error( $message, $label = 'Error' ) { - if ( !WP_CLI_AUTOCOMPLETE ) { + if ( !isset( self::$assoc_special['completions'] ) ) { \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); } @@ -192,6 +192,26 @@ static function load_all_commands() { return self::$commands; } + static function load_command( $command ) { + if ( !isset( WP_CLI::$commands[$command] ) ) { + foreach ( array( 'internals', 'community' ) as $dir ) { + $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + + if ( is_readable( $path ) ) { + include $path; + break; + } + } + } + + if ( !isset( WP_CLI::$commands[$command] ) ) { + WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + exit; + } + + return WP_CLI::$commands[$command]; + } + static function run_command( $arguments, $assoc_args ) { if ( empty( $arguments ) ) { $command = 'help'; @@ -213,24 +233,89 @@ static function run_command( $arguments, $assoc_args ) { $command->invoke( $arguments, $assoc_args ); } - static function load_command( $command ) { - if ( !isset( WP_CLI::$commands[$command] ) ) { - foreach ( array( 'internals', 'community' ) as $dir ) { - $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + private static $arguments, $assoc_args, $assoc_special; - if ( is_readable( $path ) ) { - include $path; - break; - } - } + static function before_wp_load() { + $r = WP_CLI\Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + + list( self::$arguments, self::$assoc_args ) = $r; + + self::$assoc_special = WP_CLI\Utils\split_assoc( self::$assoc_args, array( + 'path', 'url', 'blog', 'user', 'require', + 'quiet', 'completions' + ) ); + + define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + + // Handle --version parameter + if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { + self::line( 'wp-cli ' . WP_CLI_VERSION ); + exit; } - if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + $_SERVER['DOCUMENT_ROOT'] = getcwd(); + + // Define the WordPress location + if ( !empty( self::$assoc_special['path'] ) ) { + // trailingslashit() isn't available yet + define( 'WP_ROOT', rtrim( self::$assoc_args['path'], '/' ) . '/' ); + } else { + define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); + } + + // Handle --url and --blog parameters + WP_CLI\Utils\set_url( self::$assoc_special ); + + if ( array( 'core', 'download' ) == self::$arguments ) { + WP_CLI::run_command( self::$arguments, self::$assoc_args ); exit; } - return WP_CLI::$commands[$command]; + if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { + WP_CLI::error( 'This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.' ); + } + + if ( array( 'core', 'config' ) == self::$arguments ) { + WP_CLI::run_command( self::$arguments, self::$assoc_args ); + exit; + } + + // The db commands don't need any WP files + if ( array( 'db' ) == array_slice( self::$arguments, 0, 1 ) ) { + WP_CLI\Utils\load_wp_config(); + WP_CLI::run_command( self::$arguments, self::$assoc_args ); + exit; + } + + // Set installer flag before loading any WP files + if ( array( 'core', 'install' ) == self::$arguments ) { + define( 'WP_INSTALLING', true ); + } + } + + static function get_assoc_special() { + return self::$assoc_special; + } + + static function after_wp_load() { + add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); + + WP_CLI\Utils\set_user( self::$assoc_special ); + + if ( !defined( 'WP_INSTALLING' ) && isset( self::$assoc_special['url'] ) ) + WP_CLI\Utils\set_wp_query(); + + if ( isset( self::$assoc_special['require'] ) ) + require self::$assoc_special['require']; + + if ( isset( self::$assoc_special['completions'] ) ) { + foreach ( self::load_all_commands() as $name => $command ) { + self::line( $command->autocomplete() ); + } + exit; + } + + self::run_command( self::$arguments, self::$assoc_args ); } // back-compat diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index a409c7035..0b2d19ba5 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -145,6 +145,8 @@ private function check_positional( $args, $accepted_params ) { private function check_assoc( $assoc_args, $accepted_params ) { $mandatory_assoc = array(); + $assoc_args += \WP_CLI::get_assoc_special(); + foreach ( $accepted_params['assoc'] as $param ) { if ( !$param['optional'] ) $mandatory_assoc[] = $param['name']; diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index f6ee850ee..1e49fcb89 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -8,11 +8,11 @@ * @param string * @return array */ -function parse_args() { +function parse_args( $arguments ) { $regular_args = array(); $assoc_args = array(); - foreach ( array_slice( $GLOBALS['argv'], 1 ) as $arg ) { + foreach ( $arguments as $arg ) { if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { $assoc_args[ $matches[1] ] = true; } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { @@ -25,14 +25,30 @@ function parse_args() { return array( $regular_args, $assoc_args ); } -function set_url( &$assoc_args ) { +/** + * Splits $argv into positional and associative arguments. + * + * @param string + * @return array + */ +function split_assoc( &$assoc_args, $special_keys ) { + $assoc_special = array(); + + foreach ( $special_keys as $key ) { + if ( isset( $assoc_args[ $key ] ) ) { + $assoc_special[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } + + return $assoc_special; +} + +function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { - define( 'WP_CLI_URL', $assoc_args['url'] ); $blog = $assoc_args['url']; - unset( $assoc_args['url'] ); } elseif ( isset( $assoc_args['blog'] ) ) { $blog = $assoc_args['blog']; - unset( $assoc_args['blog'] ); if ( true === $blog ) { \WP_CLI::line( 'usage: wp --blog=example.com' ); } @@ -107,7 +123,7 @@ function load_wp_config() { // Handle --user parameter -function set_user( &$assoc_args ) { +function set_user( $assoc_args ) { if ( !isset( $assoc_args['user'] ) ) return; @@ -122,8 +138,13 @@ function set_user( &$assoc_args ) { if ( !$user_id || !wp_set_current_user( $user_id ) ) { \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); } +} - unset( $assoc_args['user'] ); +function set_wp_query() { + if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { + $GLOBALS['wp']->parse_request(); + $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); + } } function get_upgrader( $class ) { diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 04e3b4901..94fe0e5fa 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -4,10 +4,9 @@ define( 'WP_CLI_ROOT', __DIR__ . '/' ); -// Set a constant that can be used to check if we are running wp-cli or not +// Can be used to check if we are running wp-cli or not define( 'WP_CLI', true ); -// Include the wp-cli classes include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; @@ -15,71 +14,11 @@ include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; -// Include the command line tools include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; - -// Register the cli tools autoload \cli\register_autoload(); -// Get the cli arguments -list( $arguments, $assoc_args ) = WP_CLI\Utils\parse_args(); - -// Set output levels -define( 'WP_CLI_AUTOCOMPLETE', isset( $assoc_args['completions'] ) ); -define( 'WP_CLI_QUIET', isset( $assoc_args['quiet'] ) || isset( $assoc_args['silent'] ) ); - -// Handle --version parameter -if ( isset( $assoc_args['version'] ) && empty( $arguments ) ) { - WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); - exit; -} - -// Handle --help parameter -if ( isset( $assoc_args['help'] ) ) { - array_unshift( $arguments, 'help' ); - unset( $assoc_args['help'] ); -} - -$_SERVER['DOCUMENT_ROOT'] = getcwd(); - -// Define the WordPress location -if ( !empty( $assoc_args['path'] ) ) { - // trailingslashit() isn't available yet - define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); -} else { - define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); -} - -// Handle --url and --blog parameters -WP_CLI\Utils\set_url( $assoc_args ); - -if ( array( 'core', 'download' ) == $arguments ) { - WP_CLI::run_command( $arguments, $assoc_args ); - exit; -} - -if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { - WP_CLI::error( 'This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.' ); -} +WP_CLI::before_wp_load(); -if ( array( 'core', 'config' ) == $arguments ) { - WP_CLI::run_command( $arguments, $assoc_args ); - exit; -} - -// The db commands don't need any WP files -if ( array( 'db' ) == array_slice( $arguments, 0, 1 ) ) { - WP_CLI\Utils\load_wp_config(); - WP_CLI::run_command( $arguments, $assoc_args ); - exit; -} - -// Set installer flag before loading any WP files -if ( array( 'core', 'install' ) == $arguments ) { - define( 'WP_INSTALLING', true ); -} - -// Load WordPress require WP_ROOT . 'wp-load.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @@ -87,32 +26,5 @@ require ABSPATH . 'wp-admin/includes/admin.php'; -// Load the right info into the global wp_query -if ( !defined( 'WP_INSTALLING' ) && defined( 'WP_CLI_URL' ) ) { - if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { - $GLOBALS['wp']->parse_request(); - $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); - } -} - -// Set filesystem method -add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - -WP_CLI\Utils\set_user( $assoc_args ); - -// Handle --require parameter -if ( isset( $assoc_args['require'] ) ) { - require $assoc_args['require']; - unset( $assoc_args['require'] ); -} - -// Generate strings for autocomplete -if ( WP_CLI_AUTOCOMPLETE ) { - foreach ( WP_CLI::load_all_commands() as $name => $command ) { - WP_CLI::line( $command->autocomplete() ); - } - exit; -} - -WP_CLI::run_command( $arguments, $assoc_args ); +WP_CLI::after_wp_load(); From 724a565a7c87014e5d9b58a9c9ea764fab79a883 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Oct 2012 23:23:39 +0300 Subject: [PATCH 0674/5359] add some comments to the init process --- src/php/wp-cli/wp-cli-boot.php | 2 ++ src/php/wp-cli/wp-cli.php | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/wp-cli-boot.php b/src/php/wp-cli/wp-cli-boot.php index 3effc22d4..b7c8de526 100644 --- a/src/php/wp-cli/wp-cli-boot.php +++ b/src/php/wp-cli/wp-cli-boot.php @@ -1,5 +1,7 @@ <?php +// This file needs to parse without error in PHP < 5.3 + if ( 'cli' !== PHP_SAPI ) { echo "Only CLI access.\n"; die(-1); diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 94fe0e5fa..61e7a1af9 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -1,12 +1,12 @@ <?php +// Can be used by plugins/themes to check if wp-cli is running or not +define( 'WP_CLI', true ); + define( 'WP_CLI_VERSION', '0.7.0-alpha' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); -// Can be used to check if we are running wp-cli or not -define( 'WP_CLI', true ); - include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; @@ -19,11 +19,13 @@ WP_CLI::before_wp_load(); +// Load WordPress, in the global scope require WP_ROOT . 'wp-load.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); +// Load all admin utilities require ABSPATH . 'wp-admin/includes/admin.php'; WP_CLI::after_wp_load(); From db8ab9d85425a6ed7783907be115b1ac1e5510b7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 00:22:06 +0300 Subject: [PATCH 0675/5359] implement alias tag --- .../wp-cli/class-wp-cli-command-with-meta.php | 7 +--- src/php/wp-cli/class-wp-cli-command.php | 4 -- src/php/wp-cli/commands/internals/db.php | 7 +--- src/php/wp-cli/commands/internals/option.php | 7 +--- src/php/wp-cli/dispatcher.php | 39 +++++++++++++++---- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/src/php/wp-cli/class-wp-cli-command-with-meta.php index 968abf721..7a18853b3 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-meta.php +++ b/src/php/wp-cli/class-wp-cli-command-with-meta.php @@ -7,12 +7,6 @@ */ abstract class WP_CLI_Command_With_Meta extends WP_CLI_Command { - public static function get_aliases() { - return array( - 'set' => 'update' - ); - } - protected $meta_type; /** @@ -68,6 +62,7 @@ public function add( $args, $assoc_args ) { /** * Update a meta field. * + * @alias set * @synopsis <id> <key> <value> */ public function update( $args, $assoc_args ) { diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index c8166549c..0bd4e1247 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -11,10 +11,6 @@ public static function get_default_subcommand() { return false; } - public static function get_aliases() { - return array(); - } - public function __construct() {} } diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index e5448e92f..ddd9c1611 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -14,12 +14,6 @@ public static function get_default_subcommand() { return 'cli'; } - public static function get_aliases() { - return array( - 'dump' => 'export' - ); - } - /** * Creates the database specified in the wp-config.php file. */ @@ -137,6 +131,7 @@ function query( $args, $assoc_args ) { /** * Exports the WordPress DB as SQL using mysqldump. * + * @alias dump * @synopsis [<file>] */ function export( $args, $assoc_args ) { diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index c7a1fb532..091677f0e 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -10,12 +10,6 @@ */ class Option_Command extends WP_CLI_Command { - public static function get_aliases() { - return array( - 'set' => 'update' - ); - } - /** * Get an option * @@ -50,6 +44,7 @@ public function add( $args, $assoc_args ) { /** * Update an option * + * @alias set * @synopsis <key> <value> [--json] */ public function update( $args, $assoc_args ) { diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 0b2d19ba5..5f038f8ff 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -65,13 +65,15 @@ private function find_subcommand( &$args ) { $name = array_shift( $args ); } - $aliases = $class::get_aliases(); + $subcommands = $this->get_subcommands(); - if ( isset( $aliases[ $name ] ) ) { - $name = $aliases[ $name ]; - } + if ( !isset( $subcommands[ $name ] ) ) { + $aliases = self::get_aliases( $subcommands ); - $subcommands = $this->get_subcommands(); + if ( isset( $aliases[ $name ] ) ) { + $name = $aliases[ $name ]; + } + } if ( !isset( $subcommands[ $name ] ) ) return false; @@ -79,6 +81,18 @@ private function find_subcommand( &$args ) { return $subcommands[ $name ]; } + private static function get_aliases( $subcommands ) { + $aliases = array(); + + foreach ( $subcommands as $name => $subcommand ) { + $alias = $subcommand->get_alias(); + if ( $alias ) + $aliases[ $alias ] = $name; + } + + return $aliases; + } + private function get_subcommand_names() { return array_keys( $this->get_subcommands() ); } @@ -262,15 +276,26 @@ function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . "wp $command $subcommand $synopsis" ); } - function get_name() { + private function get_tag( $name ) { $comment = $this->method->getDocComment(); - if ( preg_match( '/@subcommand\s+([a-z-]+)/', $comment, $matches ) ) + if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $comment, $matches ) ) return $matches[1]; + return false; + } + + function get_name() { + if ( $name = $this->get_tag( 'subcommand' ) ) + return $name; + return $this->method->name; } + function get_alias() { + return $this->get_tag( 'alias' ); + } + function invoke( $args, $assoc_args ) { $this->check_args( $args, $assoc_args ); From ebcf50d60d38a87a1934cd5ffbba1447a2f315d4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 01:08:05 +0300 Subject: [PATCH 0676/5359] flags can't be mandatory --- src/php/wp-cli/dispatcher.php | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 0b2d19ba5..9efbc8525 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -218,23 +218,29 @@ private static function get_patterns() { $p_value = '<(?P<value>[a-z-|]+)>'; $param_types = array( - 'positional' => $p_value, - 'assoc' => "--$p_name=$p_value", - 'flag' => "--$p_name" + array( 'positional', $p_value, 1, 1 ), + array( 'assoc', "--$p_name=$p_value", 1, 1 ), + array( 'flag', "--$p_name", 1, 0 ), ); $patterns = array(); - foreach ( $param_types as $type => $pattern ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); + foreach ( $param_types as $pt ) { + list( $type, $pattern, $optional, $mandatory ) = $pt; - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); + if ( $mandatory ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + } + + if ( $optional ) { + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } } $params = array(); From cfab0bc5b81070cfbd6d22a69830711d8a26baab Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 01:43:29 +0300 Subject: [PATCH 0677/5359] support generic assoc args in synopsis --- src/php/wp-cli/commands/internals/post.php | 13 ++++++------- src/php/wp-cli/commands/internals/user.php | 7 ++++--- src/php/wp-cli/dispatcher.php | 19 ++++++++++--------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 19068f196..1714b3ffd 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -11,10 +11,9 @@ class Post_Command extends WP_CLI_Command { /** - * Create a post + * Create a post. * - * @param array $args - * @param array $assoc_args + * @synopsis --<field>=<value> [--porcelain] */ public function create( $args, $assoc_args ) { $post_id = wp_insert_post( $assoc_args, true ); @@ -30,13 +29,12 @@ public function create( $args, $assoc_args ) { } /** - * Update a post + * Update a post. * - * @param array $args - * @param array $assoc_args + * @synopsis <id> --<field>=<value> */ public function update( $args, $assoc_args ) { - $post_id = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); + list( $post_id ) = $args; if ( empty( $assoc_args ) ) { WP_CLI::error( "Need some fields to update." ); @@ -72,6 +70,7 @@ public function delete( $post_ids, $assoc_args ) { * Get a list of posts. * * @subcommand list + * @synopsis [--<field>=<value>] */ public function _list( $_, $assoc_args ) { $query_args = array( diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 7fe8ca529..f9bd9c26c 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -60,7 +60,7 @@ public function _list( $args, $assoc_args ) { public function delete( $args, $assoc_args ) { global $blog_id; - $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); + list( $user_id ) = $args; $defaults = array( 'reassign' => NULL ); @@ -124,9 +124,11 @@ public function create( $args, $assoc_args ) { /** * Update a user. + * + * @synopsis <id> --<field>=<value> */ public function update( $args, $assoc_args ) { - $user_id = WP_CLI::get_numeric_arg( $args, 0, "User ID" ); + list( $user_id ) = $args; if ( empty( $assoc_args ) ) { WP_CLI::error( "Need some fields to update." ); @@ -143,7 +145,6 @@ public function update( $args, $assoc_args ) { } } - /** * Generate users * diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 9efbc8525..5fa2ec222 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -125,7 +125,8 @@ protected function check_args( $args, $assoc_args ) { $this->check_assoc( $assoc_args, $accepted_params ); - $this->check_unknown_assoc( $assoc_args, $accepted_params ); + if ( empty( $accepted_params['generic'] ) ) + $this->check_unknown_assoc( $assoc_args, $accepted_params ); } private function check_positional( $args, $accepted_params ) { @@ -215,15 +216,17 @@ protected function parse_synopsis( $synopsis ) { private static function get_patterns() { $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '<(?P<value>[a-z-|]+)>'; + $p_value = '(?P<value>[a-z-|]+)'; $param_types = array( - array( 'positional', $p_value, 1, 1 ), - array( 'assoc', "--$p_name=$p_value", 1, 1 ), - array( 'flag', "--$p_name", 1, 0 ), + array( 'positional', "<$p_value>", 1, 1 ), + array( 'generic', "--<field>=<value>", 1, 1 ), + array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), + array( 'flag', "--$p_name", 1, 0 ), ); $patterns = array(); + $params = array(); foreach ( $param_types as $pt ) { list( $type, $pattern, $optional, $mandatory ) = $pt; @@ -241,11 +244,9 @@ private static function get_patterns() { 'optional' => true ); } - } - $params = array(); - foreach ( array_keys( $param_types ) as $type ) - $params[$type] = array(); + $params[ $type ] = array(); + } return array( $patterns, $params ); } From 0be8cb2be07b0e91bdaa71bc525382b6dbb802f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 02:02:55 +0300 Subject: [PATCH 0678/5359] make get_subcommands() a required method and get rid of the TopLevelSubcommand interface --- src/php/wp-cli/class-wp-cli.php | 13 ++++++--- src/php/wp-cli/commands/internals/help.php | 3 +- src/php/wp-cli/dispatcher.php | 34 +++++----------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 45ad48ca5..8bc2f32bd 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -309,15 +309,20 @@ static function after_wp_load() { require self::$assoc_special['require']; if ( isset( self::$assoc_special['completions'] ) ) { - foreach ( self::load_all_commands() as $name => $command ) { - self::line( $command->autocomplete() ); - } - exit; + self::render_automcomplete(); } self::run_command( self::$arguments, self::$assoc_args ); } + private static function render_automcomplete() { + foreach ( self::load_all_commands() as $name => $command ) { + $subcommands = $command->get_subcommands(); + self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); + } + exit; + } + // back-compat static function addCommand( $name, $class ) { self::add_command( $name, $class ); diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 2f640280a..85e69ce79 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -46,7 +46,8 @@ private static function general_help() { if ( 'help' == $name ) continue; - WP_CLI::line( " wp $name " . $command->shortdesc() ); + $subcommands = $command->get_subcommands(); + WP_CLI::line( " wp $name " . implode( '|', array_keys( $subcommands ) ) ); } WP_CLI::line(<<<EOB diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 5fa2ec222..cf16967ca 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -6,28 +6,18 @@ interface Command { function show_usage(); function invoke( $arguments, $assoc_args ); + function get_subcommands(); } -interface TopLevelCommand { - - function autocomplete(); - function shortdesc(); -} - -class CompositeCommand implements Command, TopLevelCommand { +class CompositeCommand implements Command { function __construct( $name, $class ) { $this->name = $name; $this->class = $class; } - function autocomplete() { - return $this->name . ' ' . implode( ' ', $this->get_subcommand_names() ); - } - function shortdesc() { - return implode( '|', $this->get_subcommand_names() ); } function show_usage() { @@ -79,11 +69,7 @@ private function find_subcommand( &$args ) { return $subcommands[ $name ]; } - private function get_subcommand_names() { - return array_keys( $this->get_subcommands() ); - } - - private function get_subcommands() { + public function get_subcommands() { $reflection = new \ReflectionClass( $this->class ); $subcommands = array(); @@ -112,6 +98,10 @@ function __construct( $method ) { $this->method = $method; } + function get_subcommands() { + return array(); + } + abstract function get_name(); protected function check_args( $args, $assoc_args ) { @@ -289,7 +279,7 @@ function invoke( $args, $assoc_args ) { } -class SingleCommand extends Subcommand implements TopLevelCommand { +class SingleCommand extends Subcommand { function __construct( $name, $callable ) { $this->name = $name; @@ -304,14 +294,6 @@ function get_name() { return $this->name; } - function autocomplete() { - return $this->name; - } - - function shortdesc() { - return ''; - } - function show_usage( $prefix = 'usage: ' ) { $command = $this->get_name(); $synopsis = $this->get_synopsis(); From 17acfed52b4c9ba1efc70d3d71af30bd01475092 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 03:34:00 +0300 Subject: [PATCH 0679/5359] Introduce RootCommand class. It implements the Command interface, so it's easier to reason about it. --- src/php/wp-cli/class-wp-cli.php | 43 ++++++------------ src/php/wp-cli/commands/internals/help.php | 30 ------------- src/php/wp-cli/dispatcher.php | 52 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 59 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8bc2f32bd..a76093cf5 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -193,7 +193,7 @@ static function load_all_commands() { } static function load_command( $command ) { - if ( !isset( WP_CLI::$commands[$command] ) ) { + if ( !isset( self::$commands[$command] ) ) { foreach ( array( 'internals', 'community' ) as $dir ) { $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; @@ -204,33 +204,12 @@ static function load_command( $command ) { } } - if ( !isset( WP_CLI::$commands[$command] ) ) { - WP_CLI::error( "'$command' is not a registered wp command. See 'wp help'." ); + if ( !isset( self::$commands[$command] ) ) { + self::error( "'$command' is not a registered wp command. See 'wp help'." ); exit; } - return WP_CLI::$commands[$command]; - } - - static function run_command( $arguments, $assoc_args ) { - if ( empty( $arguments ) ) { - $command = 'help'; - } else { - $command = array_shift( $arguments ); - - $aliases = array( - 'sql' => 'db' - ); - - if ( isset( $aliases[ $command ] ) ) - $command = $aliases[ $command ]; - } - - define( 'WP_CLI_COMMAND', $command ); - - $command = self::load_command( $command ); - - $command->invoke( $arguments, $assoc_args ); + return self::$commands[$command]; } private static $arguments, $assoc_args, $assoc_special; @@ -267,7 +246,7 @@ static function before_wp_load() { WP_CLI\Utils\set_url( self::$assoc_special ); if ( array( 'core', 'download' ) == self::$arguments ) { - WP_CLI::run_command( self::$arguments, self::$assoc_args ); + self::run_command(); exit; } @@ -276,14 +255,14 @@ static function before_wp_load() { } if ( array( 'core', 'config' ) == self::$arguments ) { - WP_CLI::run_command( self::$arguments, self::$assoc_args ); + self::run_command(); exit; } // The db commands don't need any WP files if ( array( 'db' ) == array_slice( self::$arguments, 0, 1 ) ) { WP_CLI\Utils\load_wp_config(); - WP_CLI::run_command( self::$arguments, self::$assoc_args ); + self::run_command(); exit; } @@ -312,7 +291,13 @@ static function after_wp_load() { self::render_automcomplete(); } - self::run_command( self::$arguments, self::$assoc_args ); + self::run_command(); + } + + private static function run_command() { + $root = new \WP_CLI\Dispatcher\RootCommand; + + $root->invoke( self::$arguments, self::$assoc_args ); } private static function render_automcomplete() { diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 85e69ce79..5231a0dd2 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -11,11 +11,6 @@ class Help_Command extends WP_CLI_Command { function __invoke( $args ) { - if ( empty( $args ) ) { - self::general_help(); - return; - } - self::maybe_load_man_page( $args ); self::show_available_subcommands( $args[0] ); @@ -39,30 +34,5 @@ private static function show_available_subcommands( $command ) { $command = WP_CLI::load_command( $command ); $command->show_usage(); } - - private static function general_help() { - WP_CLI::line( 'Available commands:' ); - foreach ( WP_CLI::load_all_commands() as $name => $command ) { - if ( 'help' == $name ) - continue; - - $subcommands = $command->get_subcommands(); - WP_CLI::line( " wp $name " . implode( '|', array_keys( $subcommands ) ) ); - } - - WP_CLI::line(<<<EOB - -See 'wp help <command>' for more information on a specific command. - -Global parameters: ---user=<id|login> set the current user ---url=<url> set the current URL ---path=<path> set the current path to the WP install ---require=<path> load a certain file before running the command ---quiet suppress informational messages ---version print wp-cli version -EOB - ); - } } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index b1e1a64ce..fe70e3a15 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -10,6 +10,58 @@ function get_subcommands(); } +class RootCommand implements Command { + + function show_usage() { + \WP_CLI::line( 'Available commands:' ); + foreach ( \WP_CLI::load_all_commands() as $name => $command ) { + $subcommands = $command->get_subcommands(); + \WP_CLI::line( " wp $name " . implode( '|', array_keys( $subcommands ) ) ); + } + + \WP_CLI::line(<<<EOB + +See 'wp help <command>' for more information on a specific command. + +Global parameters: +--user=<id|login> set the current user +--url=<url> set the current URL +--path=<path> set the current path to the WP install +--require=<path> load a certain file before running the command +--quiet suppress informational messages +--version print wp-cli version +EOB + ); + } + + function invoke( $arguments, $assoc_args ) { + if ( empty( $arguments ) ) { + $this->show_usage(); + exit; + } + + $command = array_shift( $arguments ); + + $aliases = array( + 'sql' => 'db' + ); + + if ( isset( $aliases[ $command ] ) ) + $command = $aliases[ $command ]; + + define( 'WP_CLI_COMMAND', $command ); + + $command = \WP_CLI::load_command( $command ); + + $command->invoke( $arguments, $assoc_args ); + } + + function get_subcommands() { + return \WP_CLI::load_all_commands(); + } +} + + class CompositeCommand implements Command { function __construct( $name, $class ) { From ca0a81d7dd83d966196e6dd03751c5aa79a8f45b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 05:04:02 +0300 Subject: [PATCH 0680/5359] show general help when calling wp help --- src/php/wp-cli/dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index fe70e3a15..951b311d8 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -35,7 +35,7 @@ function show_usage() { } function invoke( $arguments, $assoc_args ) { - if ( empty( $arguments ) ) { + if ( empty( $arguments ) || array( 'help' ) == $arguments ) { $this->show_usage(); exit; } From 62567491cd89bb5915c9b9189eb6aa01c5789f27 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 05:09:51 +0300 Subject: [PATCH 0681/5359] add --ids flag to wp post list synopsis --- src/php/wp-cli/commands/internals/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 1714b3ffd..22335357c 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -70,7 +70,7 @@ public function delete( $post_ids, $assoc_args ) { * Get a list of posts. * * @subcommand list - * @synopsis [--<field>=<value>] + * @synopsis [--<field>=<value>] [--ids] */ public function _list( $_, $assoc_args ) { $query_args = array( From ff5d4b537e51b3de32686b563c9f46ba0087c45f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 05:41:59 +0300 Subject: [PATCH 0682/5359] clean up comment.php and add synopsis tags. see #158 --- man/comment-last.1 | 12 +- src/docs/comment-last.txt | 10 +- src/php/wp-cli/commands/internals/comment.php | 231 +++++++----------- 3 files changed, 95 insertions(+), 158 deletions(-) diff --git a/man/comment-last.1 b/man/comment-last.1 index ee29cdc9f..f1c4809d2 100644 --- a/man/comment-last.1 +++ b/man/comment-last.1 @@ -1,33 +1,33 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-LAST" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-LAST" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-last\fR \- Retrieve last approved comment . .SH "SYNOPSIS" -\fBwp comment last\fR [\-\-porcelain] [\-\-full|verbose] +\fBwp comment last\fR [\-\-id] [\-\-full] . .SH "OPTIONS" . .TP -\fB\-\-porcelain\fR: +\fB\-\-id\fR: . .IP Output just the last comment id\. . .TP -\fB\-\-full\fR or \fB\-\-verbose\fR: +\fB\-\-full\fR: . .IP -Output complete comment information +Output complete comment information\. . .SH "EXAMPLES" . .nf -wp comment last +wp comment last \-\-full . .fi diff --git a/src/docs/comment-last.txt b/src/docs/comment-last.txt index dec1e1308..358fcd79a 100644 --- a/src/docs/comment-last.txt +++ b/src/docs/comment-last.txt @@ -3,18 +3,18 @@ wp-comment-last(1) -- Retrieve last approved comment ## SYNOPSIS -`wp comment last` [--porcelain] [--full|verbose] +`wp comment last` [--id] [--full] ## OPTIONS -* `--porcelain`: +* `--id`: Output just the last comment id. -* `--full` or `--verbose`: +* `--full`: - Output complete comment information + Output complete comment information. ## EXAMPLES - wp comment last + wp comment last --full diff --git a/src/php/wp-cli/commands/internals/comment.php b/src/php/wp-cli/commands/internals/comment.php index b6b4abc93..77d2fecb8 100644 --- a/src/php/wp-cli/commands/internals/comment.php +++ b/src/php/wp-cli/commands/internals/comment.php @@ -1,258 +1,195 @@ <?php + +WP_CLI::add_command( 'comment', 'Comment_Command' ); + /** * Implement 'comment' command * * @package wp-cli * @subpackage commands/internals */ - -// Register the 'comment' command handler -WP_CLI::add_command( 'comment', 'Comment_Command' ); - class Comment_Command extends WP_CLI_Command { /** * Insert a comment. * - * Example: wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" - * - * @param array $args} - * @param array $assoc_args + * @synopsis --<field>=<value> [--porcelain] */ public function create( $args, $assoc_args ) { - // Just one check: make sure the post actually exists - $comment_post_ID = WP_CLI::get_numeric_arg( $args, 0, "Post ID" ); - $post = get_post( $comment_post_ID ); - if ( empty( $post->comment_status ) ) { + $post = get_post( $assoc_args['comment_post_ID'] ); + if ( !$post ) { WP_CLI::error( "Cannot find post $comment_post_ID" ); } - + // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and avoid wp_die() formatted messages or notifications $comment_id = wp_insert_comment( $assoc_args ); - if ( 0 == $comment_id ) { + if ( !$comment_id ) { WP_CLI::error( "Could not create comment" ); } - + if ( isset( $assoc_args['porcelain'] ) ) WP_CLI::line( $comment_id ); else WP_CLI::success( "Inserted comment $comment_id." ); } - /** - * Delete a comment - * - * Example: wp comment delete 15 --force + * Delete a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> [--force] */ public function delete( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); + list( $comment_id ) = $args; - // Boolean $force parameter to bypass trash and really delete - $force = ( isset( $assoc_args['force'] ) ? true : false ); - - if ( wp_delete_comment( $comment_id, $force ) ) { + if ( wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ) ) { WP_CLI::success( "Deleted comment $comment_id." ); } else { WP_CLI::error( "Failed deleting comment $comment_id" ); } } - + private function call( $args, $status, $success, $failure ) { + list( $comment_id ) = $args; + + $func = sprintf( 'wp_%s_comment', $status ); + + if ( $func( $comment_id ) ) { + WP_CLI::success( "$success comment $comment_id." ); + } else { + WP_CLI::error( "$failure comment $comment_id" ); + } + } + + private function set_status( $args, $status, $success ) { + list( $comment_id ) = $args; + + $r = wp_set_comment_status( $comment_id, 'approve', true ); + + if ( is_wp_error( $r ) ) { + WP_CLI::error( $r ); + } else { + WP_CLI::success( "$success comment $comment_id" ); + } + } + /** - * Trash a comment + * Trash a comment. * - * Example: wp comment trash 15 - * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function trash( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - if ( wp_trash_comment( $comment_id ) ) { - WP_CLI::success( "Trashed comment $comment_id." ); - } else { - WP_CLI::error( "Failed trashing comment $comment_id" ); - } + $this->call( $args, __FUNCTION__, 'Trashed', 'Failed trashing' ); } - /** - * Untrash a comment - * - * Example: wp comment untrash 15 + * Untrash a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function untrash( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - if ( wp_untrash_comment( $comment_id ) ) { - WP_CLI::success( "Untrashed comment $comment_id." ); - } else { - WP_CLI::error( "Failed untrashing comment $comment_id" ); - } + $this->call( $args, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); } - /** - * Spam a comment - * - * Example: wp comment spam 15 + * Spam a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function spam( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - if ( wp_spam_comment( $comment_id ) ) { - WP_CLI::success( "Spammed comment $comment_id." ); - } else { - WP_CLI::error( "Failed spamming comment $comment_id" ); - } + $this->call( $args, __FUNCTION__, 'Marked as spam', 'Failed marking as spam' ); } - /** - * Unspam a comment - * - * Example: wp comment unspam 15 + * Unspam a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function unspam( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - if ( wp_unspam_comment( $comment_id ) ) { - WP_CLI::success( "Unspammed comment $comment_id." ); - } else { - WP_CLI::error( "Failed unspamming comment $comment_id" ); - } + $this->call( $args, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); } - /** - * Approve a comment - * - * Example: wp comment approve 15 + * Approve a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function approve( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - $comment = wp_set_comment_status( $comment_id, 'approve', true ); // last parameter 'true' to return a WP_Error object if there is a failure - - if ( is_wp_error( $comment ) ) { - WP_CLI::error( $comment ); - } else { - WP_CLI::success( "Approved comment $comment_id" ); - } + $this->set_status( $args, 'approve', "Approved" ); } - /** * Unapprove a comment * - * Example: wp comment unapprove 15 - * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function unapprove( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - - $comment = wp_set_comment_status( $comment_id, 'hold', true ); - - if ( is_wp_error( $comment ) ) { - WP_CLI::error( $comment ); - } else { - WP_CLI::success( "Unapproved comment $comment_id" ); - } + $this->set_status( $args, 'hold', "Unapproved" ); } - /** - * Count comments, in whole blog or in a given post + * Count comments, on whole blog or on a given post. * - * Example: "wp comment count 43" to count comments on post 43 - * Example: "wp comment count" to count comments on blog - * - * @param array $args} - * @param array $assoc_args + * @synopsis [<post-id>] */ public function count( $args, $assoc_args ) { - $post_id = ( isset( $args[0] ) && is_numeric( $args[0] ) ? $args[0] : 0 ); - - $comments = wp_count_comments( $post_id ); + $post_id = isset( $args[0] ) ? $args[0] : 0; + + $count = wp_count_comments( $post_id ); + // Move total_comments to the end of the object - $total = $comments->total_comments; - unset( $comments->total_comments ); - $comments->total_comments = $total; + $total = $count->total_comments; + unset( $count->total_comments ); + $count->total_comments = $total; - foreach( $comments as $status => $count ) { + foreach ( $count as $status => $count ) { WP_CLI::line( str_pad( "$status:", 17 ) . $count ); } } - /** - * Get status of a comment - * - * Example: wp comment status 15 + * Get status of a comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis <id> */ public function status( $args, $assoc_args ) { - $comment_id = WP_CLI::get_numeric_arg( $args, 0, "Comment ID" ); - + list( $comment_id ) = $args; + $status = wp_get_comment_status( $comment_id ); - - if( false === $status ) { - WP_CLI::error( "Could not check status of comment $comment" ); + + if ( false === $status ) { + WP_CLI::error( "Could not check status of comment $comment_id." ); } else { WP_CLI::line( $status ); } } - /** - * Get last approved comment. Options: --porcelain, --full|verbose + * Get last approved comment. * - * @param array $args} - * @param array $assoc_args + * @synopsis [--id] [--full] */ function last( $args = array(), $assoc_args = array() ) { $last = get_comments( array( 'number' => 1, 'status' => 'approve' ) ); - extract( get_object_vars( $last[0] ) ); - // populates: comment_ID, comment_post_ID, comment_author, ... See http://codex.wordpress.org/Function_Reference/get_comments#Returns - if ( isset( $assoc_args['porcelain'] ) ) { - WP_CLI::line( $comment_ID ); + list( $comment ) = $last; + + if ( isset( $assoc_args['id'] ) ) { + WP_CLI::line( $comment->comment_ID ); exit( 1 ); } - WP_CLI::line( "%yLast approved comment :%n" ); + WP_CLI::line( "%yLast approved comment:%n " ); - if( isset( $assoc_args['verbose'] ) OR isset( $assoc_args['full'] ) ) { - $keys = array_keys( get_object_vars( $last[0] ) ); + if ( isset( $assoc_args['full'] ) ) { + $keys = array_keys( get_object_vars( $comment ) ); } else { $keys = array( 'comment_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' ); } - foreach( $keys as $key ) { - WP_CLI::line( str_pad( "$key:", 23 ) . ${$key} ); + + foreach ( $keys as $key ) { + WP_CLI::line( str_pad( "$key:", 23 ) . $comment->$key ); } } - - } + From 16df306fe7d3b83495a43954548c709d3b4ff6fb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 05:50:22 +0300 Subject: [PATCH 0683/5359] fix synopsis for wp core install-network --- man/core-install-network.1 | 6 +++--- src/docs/core-install-network.txt | 5 +++-- src/php/wp-cli/commands/internals/core.php | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/man/core-install-network.1 b/man/core-install-network.1 index d849532c3..d2bfef710 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -7,7 +7,7 @@ \fBwp\-core\-install\-network\fR \- Transform a single\-site install into a . .SH "SYNOPSIS" -\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=/] +\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=\fIurl\-path\fR] . .SH "OPTIONS" . @@ -18,8 +18,8 @@ The title of the new network\. . .TP -\fB\-\-base_path\fR=\fIpath\fR: +\fB\-\-base_path\fR=\fIurl\-path\fR: . .IP -Base path after the domain name that each site url will start with\. +Base path after the domain name that each site url will start with\. Default: \'/\' diff --git a/src/docs/core-install-network.txt b/src/docs/core-install-network.txt index 30c37441d..74fe22d98 100644 --- a/src/docs/core-install-network.txt +++ b/src/docs/core-install-network.txt @@ -4,7 +4,7 @@ multi-site install. ## SYNOPSIS -`wp core install-network` --title=<network-title> [--base_path=/] +`wp core install-network` --title=<network-title> [--base_path=<url-path>] ## OPTIONS @@ -12,6 +12,7 @@ multi-site install. The title of the new network. -* `--base_path`=<path>: +* `--base_path`=<url-path>: Base path after the domain name that each site url will start with. +Default: '/' diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index a652f3219..98a0db8fc 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -96,7 +96,7 @@ public function install( $args, $assoc_args ) { * Transform a single-site install into a multi-site install. * * @subcommand install-network - * @synopsis --title=<network-title> [--base_path=/] + * @synopsis --title=<network-title> [--base_path=<url-path>] */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) From e7486c77c7b0d6aabdb1573734bbfc93793273f5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 06:00:12 +0300 Subject: [PATCH 0684/5359] add confirm() helper method for db subcommands --- src/php/wp-cli/commands/internals/db.php | 29 +++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index ddd9c1611..542c67eba 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -14,6 +14,17 @@ public static function get_default_subcommand() { return 'cli'; } + private static function confirm( $question, $assoc_args ) { + if ( !isset( $assoc_args['yes'] ) ) { + WP_CLI::out( $question . " [y/n] " ); + + $answer = trim( fgets( STDIN ) ); + + if ( 'y' != $answer ) + exit; + } + } + /** * Creates the database specified in the wp-config.php file. */ @@ -32,14 +43,7 @@ function create() { * @synopsis [--yes] */ function drop( $args, $assoc_args ) { - if ( !isset( $assoc_args['yes'] ) ) { - WP_CLI::out( "Are you sure you want to drop the database? [y/n] " ); - - $answer = trim( fgets( STDIN ) ); - - if ( 'y' != $answer ) - return; - } + self::confirm( "Are you sure you want to drop the database?", $assoc_args ); WP_CLI::launch( self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', @@ -55,14 +59,7 @@ function drop( $args, $assoc_args ) { * @synopsis [--yes] */ function reset( $args, $assoc_args ) { - if ( !isset( $assoc_args['yes'] ) ) { - WP_CLI::out( "Are you sure you want to reset the database? [y/n] " ); - - $answer = trim( fgets( STDIN ) ); - - if ( 'y' != $answer ) - return; - } + self::confirm( "Are you sure you want to reset the database?", $assoc_args ); WP_CLI::launch( self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', From e354c59b7cb2a322871b15d488e445c23715631d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 18:32:32 +0300 Subject: [PATCH 0685/5359] update php-cli-tools --- src/php/php-cli-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools index 7924a9dcc..c23ffe979 160000 --- a/src/php/php-cli-tools +++ b/src/php/php-cli-tools @@ -1 +1 @@ -Subproject commit 7924a9dccc8dcd84bfeb7f9767104958caac3242 +Subproject commit c23ffe979c7956614fd8721c2e28e61a3cb6bad3 From 8bfdc91ddf2743f0e40d561e28a5c2241c1cd80e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 18:33:16 +0300 Subject: [PATCH 0686/5359] remove unused get_numeric_arg() --- src/php/wp-cli/class-wp-cli.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index a76093cf5..f5e8c18dd 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -148,18 +148,6 @@ static function compose_args( $args, $assoc_args = array() ) { return $str; } - static function get_numeric_arg( $args, $index, $name ) { - if ( ! isset( $args[$index] ) ) { - WP_CLI::error( "$name required" ); - } - - if ( ! is_numeric( $args[$index] ) ) { - WP_CLI::error( "$name must be numeric" ); - } - - return $args[$index]; - } - /** * Launch an external process, closing the current one * From 2d4c8b0f1f09f37158a9786022cd7739267cd21f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Oct 2012 19:02:37 +0300 Subject: [PATCH 0687/5359] introduce get_path() method to use in show_usage() --- src/php/wp-cli/dispatcher.php | 43 +++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 951b311d8..4700bdcc6 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -4,19 +4,28 @@ interface Command { + function get_path(); + function get_subcommands(); + function show_usage(); function invoke( $arguments, $assoc_args ); - function get_subcommands(); } class RootCommand implements Command { + function get_path() { + return array(); + } + function show_usage() { \WP_CLI::line( 'Available commands:' ); - foreach ( \WP_CLI::load_all_commands() as $name => $command ) { - $subcommands = $command->get_subcommands(); - \WP_CLI::line( " wp $name " . implode( '|', array_keys( $subcommands ) ) ); + + foreach ( \WP_CLI::load_all_commands() as $command ) { + \WP_CLI::line( sprintf( " wp %s %s", + implode( ' ', $command->get_path() ), + implode( '|', array_keys( $command->get_subcommands() ) ) + ) ); } \WP_CLI::line(<<<EOB @@ -69,6 +78,10 @@ function __construct( $name, $class ) { $this->class = $class; } + function get_path() { + return array( $this->name ); + } + function show_usage() { $methods = $this->get_subcommands(); @@ -161,6 +174,13 @@ function __construct( $method ) { $this->method = $method; } + function show_usage( $prefix = 'usage: ' ) { + $full_name = implode( ' ', $this->get_path() ); + $synopsis = $this->get_synopsis(); + + \WP_CLI::line( $prefix . "wp $full_name $synopsis" ); + } + function get_subcommands() { return array(); } @@ -314,12 +334,8 @@ function __construct( $method, $parent ) { parent::__construct( $method ); } - function show_usage( $prefix = 'usage: ' ) { - $command = $this->parent->name; - $subcommand = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $command $subcommand $synopsis" ); + function get_path() { + return array( $this->parent->name, $this->get_name() ); } private function get_tag( $name ) { @@ -368,11 +384,8 @@ function get_name() { return $this->name; } - function show_usage( $prefix = 'usage: ' ) { - $command = $this->get_name(); - $synopsis = $this->get_synopsis(); - - \WP_CLI::line( $prefix . "wp $command $synopsis" ); + function get_path() { + return array( $this->name ); } function invoke( $args, $assoc_args ) { From c8fd44b78f28c87196315b155083c7a0d969469d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Oct 2012 02:33:26 +0300 Subject: [PATCH 0688/5359] fix update-all and add --dry-run option closes #188. related #180. --- .../class-wp-cli-command-with-upgrade.php | 48 +++++++++---------- src/php/wp-cli/commands/internals/plugin.php | 1 + src/php/wp-cli/commands/internals/theme.php | 1 + 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 8357991a6..a8a9d9645 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -135,38 +135,36 @@ function update_all( $args, $assoc_args ) { 'update' => true ) ); - if ( empty( $items_to_update ) ) { - WP_CLI::line( "No {$this->item_type} updates available." ); + if ( isset( $assoc_args['dry-run'] ) ) { + $item_list = "Available {$this->item_type} updates:"; + + if ( empty( $items_to_update ) ) { + $item_list .= " none"; + } else { + foreach ( $items_to_update as $file => $details ) { + $item_list .= "\n\t%y" . $details['name'] . "%n"; + } + } + + WP_CLI::line( $item_list ); return; } - // If --all, UPDATE ALL THE THINGS - if ( isset( $assoc_args['all'] ) ) { - $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); + $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); + $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); - // Let the user know the results. - $num_to_update = count( $items_to_update ); - $num_updated = count( array_filter( $result ) ); + // Let the user know the results. + $num_to_update = count( $items_to_update ); + $num_updated = count( array_filter( $result ) ); - $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; - if ( $num_to_update == $num_updated ) { - WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - WP_CLI::warning( $line ); - } else { - WP_CLI::error( $line ); - } + $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; - // Else list items that require updates + if ( $num_to_update == $num_updated ) { + WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + WP_CLI::warning( $line ); } else { - $item_list = "Available {$this->item_type} updates:"; - - foreach ( $items_to_update as $file => $details ) { - $item_list .= "\n\t%y" . $details['name'] . "%n"; - } - - WP_CLI::line( $item_list ); + WP_CLI::error( $line ); } } diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 2a57a486f..4fd4a1672 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -199,6 +199,7 @@ function update( $args, $assoc_args ) { * Update all plugins. * * @subcommand update-all + * @synopsis [--dry-run] */ function update_all( $args, $assoc_args ) { parent::update_all( $args, $assoc_args ); diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index cceefb844..278b0ad40 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -173,6 +173,7 @@ function update( $args, $assoc_args ) { * Update all themes. * * @subcommand update-all + * @synopsis [--dry-run] */ function update_all( $args, $assoc_args ) { parent::update_all( $args, $assoc_args ); From 85fa00c75bad696f2926f8a1e8f23b376e92b4cf Mon Sep 17 00:00:00 2001 From: Ben Doherty <ben@thinkoomph.com> Date: Tue, 16 Oct 2012 20:05:24 -0400 Subject: [PATCH 0689/5359] Checks for existence of wp_get_themes to use instead of deprecated (as of 3.4) get_themes function --- src/php/wp-cli/commands/internals/theme.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 278b0ad40..8b16e4143 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -137,7 +137,12 @@ protected function install_from_repo( $slug, $assoc_args ) { protected function get_item_list() { $items = array(); - foreach ( get_themes() as $title => $details ) { + if( function_exists( 'wp_get_themes' ) ) + $themes = wp_get_themes(); + else + $themes = get_themes(); + + foreach ( $themes as $title => $details ) { $file = $this->get_stylesheet_path( $details['Stylesheet'] ); $items[ $file ] = array( From 13d588405f493d5142103f1bd0532185b4b7ee7e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 18 Oct 2012 02:15:46 +0300 Subject: [PATCH 0690/5359] get_themes() indexes themes differently than wp_get_themes(). see #189 --- src/php/wp-cli/commands/internals/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 8b16e4143..a10dadb99 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -142,7 +142,7 @@ protected function get_item_list() { else $themes = get_themes(); - foreach ( $themes as $title => $details ) { + foreach ( $themes as $details ) { $file = $this->get_stylesheet_path( $details['Stylesheet'] ); $items[ $file ] = array( From 78981e2279f477a28d6dfb7112d9fbbd7586f1fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 21 Oct 2012 00:36:03 +0300 Subject: [PATCH 0691/5359] first pass at blog delete command --- src/php/wp-cli/commands/internals/blog.php | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index a9ebc6e62..53402cc0d 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -123,4 +123,33 @@ public function create( $args, $assoc_args ) { } WP_CLI::success( "Blog $id created: $url" ); } + + /** + * Delete a blog in a multisite install. + * + * @synopsis --slug=<slug> + */ + function delete( $_, $assoc_args ) { + $slug = $assoc_args['slug']; + + $slug = '/' . trim( $slug, '/' ) . '/'; + + $blog_id = self::get_blog_id_by_slug( $slug ); + + if ( !$blog_id ) + WP_CLI::error( sprintf( "'%s' blog not found.", $slug ) ); + + wpmu_delete_blog( $blog_id, true ); + + WP_CLI::success( "Blog '%s' deleted." ); + } + + protected static function get_blog_id_by_slug( $slug ) { + global $wpdb, $current_site; + + return $wpdb->get_var( $wpdb->prepare( " + SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s" + , $current_site->domain, $slug ) ); + } } + From b7df777b597cb1ec5516ef0bb8743bd038376a24 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 21 Oct 2012 00:40:49 +0300 Subject: [PATCH 0692/5359] add confirmation --- src/php/wp-cli/class-wp-cli.php | 14 ++++++++++++++ src/php/wp-cli/commands/internals/blog.php | 8 ++++---- src/php/wp-cli/commands/internals/db.php | 15 ++------------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index f5e8c18dd..d533ffbe8 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -80,6 +80,20 @@ static function warning( $message, $label = 'Warning' ) { \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } + /** + * Ask for confirmation before running a destructive operation. + */ + static function confirm( $question, $assoc_args ) { + if ( !isset( $assoc_args['yes'] ) ) { + WP_CLI::out( $question . " [y/n] " ); + + $answer = trim( fgets( STDIN ) ); + + if ( 'y' != $answer ) + exit; + } + } + /** * Read a value, from various formats * diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 53402cc0d..e593960cc 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -127,18 +127,18 @@ public function create( $args, $assoc_args ) { /** * Delete a blog in a multisite install. * - * @synopsis --slug=<slug> + * @synopsis --slug=<slug> [--yes] */ function delete( $_, $assoc_args ) { - $slug = $assoc_args['slug']; - - $slug = '/' . trim( $slug, '/' ) . '/'; + $slug = '/' . trim( $assoc_args['slug'], '/' ) . '/'; $blog_id = self::get_blog_id_by_slug( $slug ); if ( !$blog_id ) WP_CLI::error( sprintf( "'%s' blog not found.", $slug ) ); + WP_CLI::confirm( "Are you sure you want to delete the '$slug' blog?", $assoc_args ); + wpmu_delete_blog( $blog_id, true ); WP_CLI::success( "Blog '%s' deleted." ); diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 542c67eba..ed9c8b2c1 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -14,17 +14,6 @@ public static function get_default_subcommand() { return 'cli'; } - private static function confirm( $question, $assoc_args ) { - if ( !isset( $assoc_args['yes'] ) ) { - WP_CLI::out( $question . " [y/n] " ); - - $answer = trim( fgets( STDIN ) ); - - if ( 'y' != $answer ) - exit; - } - } - /** * Creates the database specified in the wp-config.php file. */ @@ -43,7 +32,7 @@ function create() { * @synopsis [--yes] */ function drop( $args, $assoc_args ) { - self::confirm( "Are you sure you want to drop the database?", $assoc_args ); + WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); WP_CLI::launch( self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', @@ -59,7 +48,7 @@ function drop( $args, $assoc_args ) { * @synopsis [--yes] */ function reset( $args, $assoc_args ) { - self::confirm( "Are you sure you want to reset the database?", $assoc_args ); + WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); WP_CLI::launch( self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', From 7391296386645c0bebfc66278f21fe745e959d85 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 21 Oct 2012 00:42:50 +0300 Subject: [PATCH 0693/5359] add keep-tables flag --- src/php/wp-cli/commands/internals/blog.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index e593960cc..cc2649caa 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -127,7 +127,7 @@ public function create( $args, $assoc_args ) { /** * Delete a blog in a multisite install. * - * @synopsis --slug=<slug> [--yes] + * @synopsis --slug=<slug> [--yes] [--keep-tables] */ function delete( $_, $assoc_args ) { $slug = '/' . trim( $assoc_args['slug'], '/' ) . '/'; @@ -139,7 +139,7 @@ function delete( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to delete the '$slug' blog?", $assoc_args ); - wpmu_delete_blog( $blog_id, true ); + wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); WP_CLI::success( "Blog '%s' deleted." ); } From d2f31888c0d3ad134c716d004e3a33c5dbad852c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 21 Oct 2012 00:53:05 +0300 Subject: [PATCH 0694/5359] add man page --- man/blog-create.1 | 4 ++-- man/blog-delete.1 | 30 ++++++++++++++++++++++++++++++ src/docs/blog-create.txt | 2 +- src/docs/blog-delete.txt | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 man/blog-delete.1 create mode 100644 src/docs/blog-delete.txt diff --git a/man/blog-create.1 b/man/blog-create.1 index 338aff284..574670f93 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-CREATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-BLOG\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-blog\-create\fR \- Create a new blog in a multisite install\. @@ -15,7 +15,7 @@ \fB\-\-slug\fR=\fIslug\fR: . .IP -Base for the new domain\. Subdomain on subdomain installs, directory on subdirectory installs\. +Path for the new blog\. Subdomain on subdomain installs, directory on subdirectory installs\. . .TP \fB\-\-title\fR=<title>: diff --git a/man/blog-delete.1 b/man/blog-delete.1 new file mode 100644 index 000000000..b8f45e50b --- /dev/null +++ b/man/blog-delete.1 @@ -0,0 +1,30 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +wp\-blog\-delete(1) \-\- Delete a blog in a multisite install\. +. +.P +==== +. +.SH "SYNOPSIS" +\fBwp blog delete\fR \-\-slug=\fIslug\fR [\-\-yes] [\-\-keep\-tables] +. +.SH "OPTIONS" +. +.TP +\fB\-\-slug\fR=\fIslug\fR: +. +.IP +Path of the blog to be deleted\. Subdomain on subdomain installs, directory on subdirectory installs\. +. +.TP +\fB\-\-yes\fR: +. +.IP +Answer yes to the confirmation message\. +. +.TP +\fB\-\-keep\-tables\fR: +. +.IP +Delete the blog from the list, but don\'t drop it\'s tables\. + diff --git a/src/docs/blog-create.txt b/src/docs/blog-create.txt index 991e19caf..cfe7b2b39 100644 --- a/src/docs/blog-create.txt +++ b/src/docs/blog-create.txt @@ -9,7 +9,7 @@ wp-blog-create(1) -- Create a new blog in a multisite install. * `--slug`=<slug>: - Base for the new domain. Subdomain on subdomain installs, directory on subdirectory installs. + Path for the new blog. Subdomain on subdomain installs, directory on subdirectory installs. * `--title`=<title>: diff --git a/src/docs/blog-delete.txt b/src/docs/blog-delete.txt new file mode 100644 index 000000000..18b3ac87b --- /dev/null +++ b/src/docs/blog-delete.txt @@ -0,0 +1,21 @@ +wp-blog-delete(1) -- Delete a blog in a multisite install. + +==== + +## SYNOPSIS + +`wp blog delete` --slug=<slug> [--yes] [--keep-tables] + +## OPTIONS + +* `--slug`=<slug>: + + Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. + +* `--yes`: + + Answer yes to the confirmation message. + +* `--keep-tables`: + + Delete the blog from the list, but don't drop it's tables. From 6ebb2ab378d86d5369bb2ea6857406922279d4e5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 21 Oct 2012 01:02:44 +0300 Subject: [PATCH 0695/5359] fix message. see #191 --- src/php/wp-cli/commands/internals/blog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index cc2649caa..4c027ef2f 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -141,7 +141,7 @@ function delete( $_, $assoc_args ) { wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); - WP_CLI::success( "Blog '%s' deleted." ); + WP_CLI::success( "Blog '$slug' deleted." ); } protected static function get_blog_id_by_slug( $slug ) { From 966e6036df645b4565172610ca082d1ddfcc899c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Oct 2012 22:55:01 +0300 Subject: [PATCH 0696/5359] remove unnecessary WP_CLI_COMMAND constant --- src/php/wp-cli/dispatcher.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 4700bdcc6..dbbd4e654 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -58,8 +58,6 @@ function invoke( $arguments, $assoc_args ) { if ( isset( $aliases[ $command ] ) ) $command = $aliases[ $command ]; - define( 'WP_CLI_COMMAND', $command ); - $command = \WP_CLI::load_command( $command ); $command->invoke( $arguments, $assoc_args ); From 71ee445126991177d0fc3b01067468512d425926 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Oct 2012 22:22:10 +0300 Subject: [PATCH 0697/5359] add get_synopsis() method to Command interface --- src/php/wp-cli/dispatcher.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index dbbd4e654..80d8e947c 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -6,6 +6,7 @@ interface Command { function get_path(); function get_subcommands(); + function get_synopsis(); function show_usage(); function invoke( $arguments, $assoc_args ); @@ -18,6 +19,10 @@ function get_path() { return array(); } + function get_synopsis() { + return ''; + } + function show_usage() { \WP_CLI::line( 'Available commands:' ); @@ -80,6 +85,10 @@ function get_path() { return array( $this->name ); } + function get_synopsis() { + return ''; + } + function show_usage() { $methods = $this->get_subcommands(); @@ -258,7 +267,7 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { } } - protected function get_synopsis() { + public function get_synopsis() { $comment = $this->method->getDocComment(); if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) From 944f805969ff04e9063ce31905ca9be913948681 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Oct 2012 22:30:01 +0300 Subject: [PATCH 0698/5359] add get_shortdesc() method --- src/php/wp-cli/dispatcher.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 80d8e947c..ad3bb5641 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -6,6 +6,8 @@ interface Command { function get_path(); function get_subcommands(); + + function get_shortdesc(); function get_synopsis(); function show_usage(); @@ -19,6 +21,10 @@ function get_path() { return array(); } + function get_shortdesc() { + return ''; + } + function get_synopsis() { return ''; } @@ -85,6 +91,10 @@ function get_path() { return array( $this->name ); } + function get_shortdesc() { + return ''; + } + function get_synopsis() { return ''; } @@ -267,6 +277,15 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { } } + function get_shortdesc() { + $comment = $this->method->getDocComment(); + + if ( !preg_match( '/\* ([^@\.]+\.)\s*/', $comment, $matches ) ) + return false; + + return $matches[1]; + } + public function get_synopsis() { $comment = $this->method->getDocComment(); From 6b74860e2df23415092b9fb575713fbda600373a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Oct 2012 22:46:57 +0300 Subject: [PATCH 0699/5359] create separate Documentable interface --- src/php/wp-cli/dispatcher.php | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index ad3bb5641..f41c48a4b 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -7,28 +7,24 @@ interface Command { function get_path(); function get_subcommands(); - function get_shortdesc(); - function get_synopsis(); - function show_usage(); function invoke( $arguments, $assoc_args ); } +interface Documentable { + + function get_shortdesc(); + function get_synopsis(); +} + + class RootCommand implements Command { function get_path() { return array(); } - function get_shortdesc() { - return ''; - } - - function get_synopsis() { - return ''; - } - function show_usage() { \WP_CLI::line( 'Available commands:' ); @@ -91,14 +87,6 @@ function get_path() { return array( $this->name ); } - function get_shortdesc() { - return ''; - } - - function get_synopsis() { - return ''; - } - function show_usage() { $methods = $this->get_subcommands(); @@ -185,7 +173,7 @@ private static function _is_good_method( $method ) { } -abstract class Subcommand implements Command { +abstract class Subcommand implements Command, Documentable { function __construct( $method ) { $this->method = $method; From 763a1c6b448ae0ac52d982e663232fff10045a47 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Oct 2012 23:43:39 +0300 Subject: [PATCH 0700/5359] introduce Composite interface and traverse() function --- src/php/wp-cli/class-wp-cli.php | 3 +- src/php/wp-cli/commands/internals/help.php | 13 +++---- src/php/wp-cli/dispatcher.php | 41 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d533ffbe8..74be4e973 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -207,8 +207,7 @@ static function load_command( $command ) { } if ( !isset( self::$commands[$command] ) ) { - self::error( "'$command' is not a registered wp command. See 'wp help'." ); - exit; + return false; } return self::$commands[$command]; diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 5231a0dd2..410c1cf62 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -13,7 +13,13 @@ class Help_Command extends WP_CLI_Command { function __invoke( $args ) { self::maybe_load_man_page( $args ); - self::show_available_subcommands( $args[0] ); + $command = \WP_CLI\Dispatcher\traverse( $args ); + + if ( !$command ) { + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + } + + $command->show_usage(); } private static function maybe_load_man_page( $args ) { @@ -29,10 +35,5 @@ private static function maybe_load_man_page( $args ) { } } } - - private static function show_available_subcommands( $command ) { - $command = WP_CLI::load_command( $command ); - $command->show_usage(); - } } diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index f41c48a4b..9a12b6807 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -2,6 +2,22 @@ namespace WP_CLI\Dispatcher; +function traverse( &$args ) { + $args_copy = $args; + + $command = new RootCommand; + + while ( !empty( $args ) && $command && $command instanceof Composite ) { + $command = $command->find_subcommand( $args ); + } + + if ( !$command ) + $args = $args_copy; + + return $command; +} + + interface Command { function get_path(); @@ -12,6 +28,12 @@ function invoke( $arguments, $assoc_args ); } +interface Composite { + + function find_subcommand( &$arguments ); +} + + interface Documentable { function get_shortdesc(); @@ -19,7 +41,7 @@ function get_synopsis(); } -class RootCommand implements Command { +class RootCommand implements Command, Composite { function get_path() { return array(); @@ -56,6 +78,15 @@ function invoke( $arguments, $assoc_args ) { exit; } + $command = $this->find_subcommand( $arguments ); + + if ( !$command ) + \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $arguments[0] ) ); + + $command->invoke( $arguments, $assoc_args ); + } + + function find_subcommand( &$arguments ) { $command = array_shift( $arguments ); $aliases = array( @@ -65,9 +96,7 @@ function invoke( $arguments, $assoc_args ) { if ( isset( $aliases[ $command ] ) ) $command = $aliases[ $command ]; - $command = \WP_CLI::load_command( $command ); - - $command->invoke( $arguments, $assoc_args ); + return \WP_CLI::load_command( $command ); } function get_subcommands() { @@ -76,7 +105,7 @@ function get_subcommands() { } -class CompositeCommand implements Command { +class CompositeCommand implements Command, Composite { function __construct( $name, $class ) { $this->name = $name; @@ -113,7 +142,7 @@ function invoke( $args, $assoc_args ) { $subcommand->invoke( $args, $assoc_args ); } - private function find_subcommand( &$args ) { + function find_subcommand( &$args ) { $class = $this->class; if ( empty( $args ) ) { From c6e48a77017f566ee74213e9c489dbb69e4ed1ac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 00:44:13 +0300 Subject: [PATCH 0701/5359] add missing short descriptions --- src/php/wp-cli/commands/internals/comment.php | 2 +- src/php/wp-cli/commands/internals/help.php | 5 +++++ src/php/wp-cli/commands/internals/home.php | 3 +++ src/php/wp-cli/commands/internals/option.php | 6 +++--- src/php/wp-cli/commands/internals/user.php | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/comment.php b/src/php/wp-cli/commands/internals/comment.php index 77d2fecb8..0604b8e25 100644 --- a/src/php/wp-cli/commands/internals/comment.php +++ b/src/php/wp-cli/commands/internals/comment.php @@ -119,7 +119,7 @@ public function approve( $args, $assoc_args ) { } /** - * Unapprove a comment + * Unapprove a comment. * * @synopsis <id> */ diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 410c1cf62..3fc90c1d1 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -10,6 +10,11 @@ */ class Help_Command extends WP_CLI_Command { + /** + * Get help on a certain topic. + * + * @synopsis [<command>] + */ function __invoke( $args ) { self::maybe_load_man_page( $args ); diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/internals/home.php index f20bcf03e..730ce8d2c 100644 --- a/src/php/wp-cli/commands/internals/home.php +++ b/src/php/wp-cli/commands/internals/home.php @@ -10,6 +10,9 @@ */ class Home_Command extends WP_CLI_Command { + /** + * Opens the wp-cli homepage in your browser. + */ function __invoke() { // The url for the wp-cli repository $repository_url = 'https://github.com/wp-cli/wp-cli'; diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index 091677f0e..cf0147f6f 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -11,7 +11,7 @@ class Option_Command extends WP_CLI_Command { /** - * Get an option + * Get an option. * * @synopsis <key> [--json] */ @@ -42,7 +42,7 @@ public function add( $args, $assoc_args ) { } /** - * Update an option + * Update an option. * * @alias set * @synopsis <key> <value> [--json] @@ -61,7 +61,7 @@ public function update( $args, $assoc_args ) { } /** - * Delete an option + * Delete an option. * * @synopsis <key> */ diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index f9bd9c26c..6864fd124 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -146,7 +146,7 @@ public function update( $args, $assoc_args ) { } /** - * Generate users + * Generate users. * * @synopsis [--count=100] [--role=<role>] */ From 055b52384a5543b5b8ad372bc82eb8cc6e501b35 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 01:08:59 +0300 Subject: [PATCH 0702/5359] add special --doc flag --- src/php/wp-cli/class-wp-cli.php | 23 +++++++++++++++++++++-- src/php/wp-cli/utils.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 74be4e973..99952ce83 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -222,7 +222,7 @@ static function before_wp_load() { self::$assoc_special = WP_CLI\Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions' + 'quiet', 'completions', 'doc' ) ); define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); @@ -288,8 +288,14 @@ static function after_wp_load() { if ( isset( self::$assoc_special['require'] ) ) require self::$assoc_special['require']; + if ( isset( self::$assoc_special['doc'] ) ) { + self::render_doc(); + exit; + } + if ( isset( self::$assoc_special['completions'] ) ) { self::render_automcomplete(); + exit; } self::run_command(); @@ -301,12 +307,25 @@ private static function run_command() { $root->invoke( self::$arguments, self::$assoc_args ); } + private static function render_doc() { + foreach ( self::load_all_commands() as $command ) { + $subcommands = $command->get_subcommands(); + + if ( empty( $subcommands ) ) { + \WP_CLI\Utils\print_man_markdown( $command ); + } else { + foreach ( $subcommands as $subcommand ) { + \WP_CLI\Utils\print_man_markdown( $subcommand ); + } + } + } + } + private static function render_automcomplete() { foreach ( self::load_all_commands() as $name => $command ) { $subcommands = $command->get_subcommands(); self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); } - exit; } // back-compat diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 1e49fcb89..b9a5d996b 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -156,3 +156,31 @@ function get_upgrader( $class ) { return new $class( new \CLI_Upgrader_Skin ); } +function print_man_markdown( \WP_CLI\Dispatcher\Documentable $command ) { + $path = $command->get_path(); + $shortdesc = $command->get_shortdesc(); + $synopsis = $command->get_synopsis(); + + $name_m = implode( '-', $path ); + $name_s = implode( ' ', $path ); + + if ( !$shortdesc ) { + WP_CLI::warning( "No shortdesc for $name_s" ); + } + + echo <<<DOC +wp-$name_m(1) -- $shortdesc +==== + +## SYNOPSIS + +`wp $name_s` $synopsis + +DOC; + + $doc_path = WP_CLI_ROOT . "../../docs/$name_m.txt"; + + if ( file_exists( $doc_path ) ) + echo file_get_contents( $doc_path ); +} + From 838e35618aba02de7d1ca079e1dfb398bc3728b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 02:48:03 +0300 Subject: [PATCH 0703/5359] pass doc markdown to ronn from PHP --- src/php/wp-cli/class-wp-cli.php | 27 ++++----- src/php/wp-cli/commands/internals/help.php | 12 +--- src/php/wp-cli/man.php | 69 ++++++++++++++++++++++ src/php/wp-cli/utils.php | 28 --------- src/php/wp-cli/wp-cli.php | 1 + utils/doc-build | 23 -------- 6 files changed, 85 insertions(+), 75 deletions(-) create mode 100644 src/php/wp-cli/man.php delete mode 100755 utils/doc-build diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 99952ce83..8b259bb44 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -1,5 +1,7 @@ <?php +use \WP_CLI\Dispatcher; + /** * Wrapper class for WP-CLI * @@ -222,7 +224,7 @@ static function before_wp_load() { self::$assoc_special = WP_CLI\Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions', 'doc' + 'quiet', 'completions', 'man' ) ); define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); @@ -288,8 +290,8 @@ static function after_wp_load() { if ( isset( self::$assoc_special['require'] ) ) require self::$assoc_special['require']; - if ( isset( self::$assoc_special['doc'] ) ) { - self::render_doc(); + if ( isset( self::$assoc_special['man'] ) ) { + self::generate_man( self::$arguments ); exit; } @@ -302,28 +304,23 @@ static function after_wp_load() { } private static function run_command() { - $root = new \WP_CLI\Dispatcher\RootCommand; + $root = new Dispatcher\RootCommand; $root->invoke( self::$arguments, self::$assoc_args ); } - private static function render_doc() { - foreach ( self::load_all_commands() as $command ) { - $subcommands = $command->get_subcommands(); + private static function generate_man( $args ) { + $command = Dispatcher\traverse( $args ); + if ( !$command ) + WP_CLI::error( sprintf( "'%s' command not found." ) ); - if ( empty( $subcommands ) ) { - \WP_CLI\Utils\print_man_markdown( $command ); - } else { - foreach ( $subcommands as $subcommand ) { - \WP_CLI\Utils\print_man_markdown( $subcommand ); - } - } - } + \WP_CLI\Man\generate( $command ); } private static function render_automcomplete() { foreach ( self::load_all_commands() as $name => $command ) { $subcommands = $command->get_subcommands(); + self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); } } diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 3fc90c1d1..16a3a2c4d 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -28,16 +28,10 @@ function __invoke( $args ) { } private static function maybe_load_man_page( $args ) { - $man_dir = WP_CLI_ROOT . "../../../man/"; + $man_file = \WP_CLI\Man\get_path( $args ); - if ( !is_dir( $man_dir ) ) { - WP_CLI::warning( "man pages do not seem to be installed." ); - } else { - $man_file = $man_dir . implode( '-', $args ) . '.1'; - - if ( is_readable( $man_file ) ) { - exit( WP_CLI::launch( "man $man_file" ) ); - } + if ( is_readable( $man_file ) ) { + exit( WP_CLI::launch( "man $man_file" ) ); } } } diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php new file mode 100644 index 000000000..546956bb1 --- /dev/null +++ b/src/php/wp-cli/man.php @@ -0,0 +1,69 @@ +<?php + +namespace WP_CLI\Man; + +use \WP_CLI\Dispatcher; + +function get_path( $args ) { + return WP_CLI_ROOT . "../../../man/" . implode( '-', $args ) . '.1'; +} + +function get_doc_path() { + return WP_CLI_ROOT . "../../docs/"; +} + +function generate( $command ) { + if ( $command instanceof Dispatcher\Composite ) { + foreach ( $command->get_subcommands() as $subcommand ) { + generate( $subcommand ); + } + return; + } + + $descriptorspec = array( + 0 => get_markdown( $command ), + 1 => array( 'file', get_path( $command->get_path() ), 'w' ), + 2 => STDERR + ); + + $r = proc_close( proc_open( "ronn --roff --manual='WP-CLI'", $descriptorspec, $pipes ) ); + + \WP_CLI::line( "generated man page for " . implode( '-', $command->get_path() ) ); +} + +// returns a file descriptor containing markdown that will be passed to ronn +function get_markdown( Dispatcher\Documentable $command ) { + $path = $command->get_path(); + $shortdesc = $command->get_shortdesc(); + $synopsis = $command->get_synopsis(); + + $name_m = implode( '-', $path ); + $name_s = implode( ' ', $path ); + + if ( !$shortdesc ) { + \WP_CLI::warning( "No shortdesc for $name_s" ); + } + + $temp = fopen( "php://temp", "rw" ); + + fwrite( $temp, <<<DOC +wp-$name_m(1) -- $shortdesc +==== + +## SYNOPSIS + +`wp $name_s` $synopsis + +DOC + ); + + $doc_path = get_doc_path() . "$name_m.txt"; + + if ( file_exists( $doc_path ) ) + fwrite( $temp, file_get_contents( $doc_path ) ); + + fseek( $temp, 0 ); + + return $temp; +} + diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index b9a5d996b..1e49fcb89 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -156,31 +156,3 @@ function get_upgrader( $class ) { return new $class( new \CLI_Upgrader_Skin ); } -function print_man_markdown( \WP_CLI\Dispatcher\Documentable $command ) { - $path = $command->get_path(); - $shortdesc = $command->get_shortdesc(); - $synopsis = $command->get_synopsis(); - - $name_m = implode( '-', $path ); - $name_s = implode( ' ', $path ); - - if ( !$shortdesc ) { - WP_CLI::warning( "No shortdesc for $name_s" ); - } - - echo <<<DOC -wp-$name_m(1) -- $shortdesc -==== - -## SYNOPSIS - -`wp $name_s` $synopsis - -DOC; - - $doc_path = WP_CLI_ROOT . "../../docs/$name_m.txt"; - - if ( file_exists( $doc_path ) ) - echo file_get_contents( $doc_path ); -} - diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 61e7a1af9..295dadc4a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -13,6 +13,7 @@ include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; +include WP_CLI_ROOT . 'man.php'; include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); diff --git a/utils/doc-build b/utils/doc-build deleted file mode 100755 index 8cb5c7c28..000000000 --- a/utils/doc-build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# regenerates modified man pages -# -# run automatically before each commit: -# ln -s ../../utils/doc-build .git/hooks/pre-commit - -if [ $# -eq 0 ]; then - files=$(git diff --cached --name-only src/docs/) -else - files=$@ -fi - -if ! which ronn > /dev/null; then - echo "doc-build: ronn is not installed" - exit 1 -fi - -for file in $files; do - man_file=man/$(basename $file .txt).1 - cat $file | ronn --roff --manual="WP-CLI" > $man_file - git add $man_file -done From e17ad0f38c863948efc505807daeac342b0252ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 04:29:50 +0300 Subject: [PATCH 0704/5359] fix synopsis encoding bugs --- src/php/wp-cli/man.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 546956bb1..daee08c69 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -37,6 +37,8 @@ function get_markdown( Dispatcher\Documentable $command ) { $shortdesc = $command->get_shortdesc(); $synopsis = $command->get_synopsis(); + $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); + $name_m = implode( '-', $path ); $name_s = implode( ' ', $path ); From 1880307632f6c2fdb5cd3bb0a743a486ec55b2ec Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 04:54:37 +0300 Subject: [PATCH 0705/5359] fix some synopses --- src/php/wp-cli/commands/internals/core.php | 4 ++-- src/php/wp-cli/commands/internals/db.php | 21 +++++++++----------- src/php/wp-cli/commands/internals/plugin.php | 4 ++-- src/php/wp-cli/commands/internals/theme.php | 4 ++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 98a0db8fc..f16aa9f2f 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -11,7 +11,7 @@ class Core_Command extends WP_CLI_Command { /** - * Download the core files from wordpress.org + * Download core WordPress files. * * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] */ @@ -63,7 +63,7 @@ public function config( $args, $assoc_args ) { } /** - * Run wp_install. Assumes that wp-config.php is already in place. + * Create the WordPress tables in the database. * * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index ed9c8b2c1..12f6918a0 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -15,7 +15,7 @@ public static function get_default_subcommand() { } /** - * Creates the database specified in the wp-config.php file. + * Create the database. */ function create() { WP_CLI::launch( self::create_cmd( @@ -27,7 +27,7 @@ function create() { } /** - * Deletes the database specified in the wp-config.php file. + * Delete the database. * * @synopsis [--yes] */ @@ -43,7 +43,7 @@ function drop( $args, $assoc_args ) { } /** - * Removes all tables from the database. + * Remove all tables from the database. * * @synopsis [--yes] */ @@ -64,7 +64,7 @@ function reset( $args, $assoc_args ) { } /** - * Optimizes the database specified in the wp-config.php file. + * Optimize the database. */ function optimize() { WP_CLI::launch( self::create_cmd( @@ -76,7 +76,7 @@ function optimize() { } /** - * Repairs the database specified in the wp-config.php file. + * Repair the database. */ function repair() { WP_CLI::launch( self::create_cmd( @@ -95,14 +95,14 @@ function connect() { } /** - * Open a SQL command-line interface using WordPress's credentials. + * Open a mysql console using the WordPress credentials. */ function cli() { WP_CLI::launch( $this->connect_string() ); } /** - * Execute a query against the site database. + * Execute a query against the database. * * @synopsis <sql> */ @@ -115,7 +115,7 @@ function query( $args, $assoc_args ) { } /** - * Exports the WordPress DB as SQL using mysqldump. + * Exports the database using mysqldump. * * @alias dump * @synopsis [<file>] @@ -132,7 +132,7 @@ function export( $args, $assoc_args ) { } /** - * Imports a database from a file. + * Import database from a file. * * @synopsis [<file>] */ @@ -148,9 +148,6 @@ function import( $args, $assoc_args ) { WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } - /** - * Return a string for connecting to the DB. - */ private function connect_string() { return self::create_cmd( 'mysql --host=%s --user=%s --password=%s --database=%s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 4fd4a1672..d6f6d9840 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -110,7 +110,7 @@ function toggle( $args, $assoc_args = array() ) { } /** - * Get a plugin path. + * Get the path to a plugin or to the plugin directory. * * @synopsis [<plugin>] [--dir] */ @@ -221,7 +221,7 @@ protected function get_item_list() { } /** - * Install a plugin from wordpress.org or from a zip file. + * Install a plugin. * * @synopsis <plugin|zip> [--version=<version>] [--activate] */ diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index a10dadb99..733c6b2b8 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -81,7 +81,7 @@ private function is_active_theme( $stylesheet ) { } /** - * Get a theme path. + * Get the path to a theme or to the theme directory. * * @synopsis [<theme>] [--dir] */ @@ -157,7 +157,7 @@ protected function get_item_list() { } /** - * Install a theme from wordpress.org or from a zip file. + * Install a theme. * * @synopsis <theme|zip> [--version=<version>] [--activate] */ From a4d0f4e0901a471270a440fbb46664be5dedc664 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 04:55:58 +0300 Subject: [PATCH 0706/5359] remove duplicat info from doc files and generate man pages using new method --- man/blog-create.1 | 4 ++-- man/blog-delete.1 | 7 ++++--- man/cache-add.1 | 10 ++++++++++ man/cache-decr.1 | 10 ++++++++++ man/cache-delete.1 | 10 ++++++++++ man/cache-flush.1 | 10 ++++++++++ man/cache-get.1 | 10 ++++++++++ man/cache-incr.1 | 10 ++++++++++ man/cache-replace.1 | 10 ++++++++++ man/cache-set.1 | 10 ++++++++++ man/cache-type.1 | 10 ++++++++++ man/comment-approve.1 | 4 ++-- man/comment-count.1 | 6 +++--- man/comment-create.1 | 6 +++--- man/comment-delete.1 | 4 ++-- man/comment-last.1 | 2 +- man/comment-spam.1 | 6 +++--- man/comment-status.1 | 6 +++--- man/comment-trash.1 | 4 ++-- man/comment-unapprove.1 | 4 ++-- man/comment-unspam.1 | 6 +++--- man/comment-untrash.1 | 4 ++-- man/core-config.1 | 6 +++--- man/core-download.1 | 4 ++-- man/core-install-network.1 | 2 +- man/core-install.1 | 4 ++-- man/core-update.1 | 6 +++--- man/core-version.1 | 4 ++-- man/db-cli.1 | 4 ++-- man/db-connect.1 | 4 ++-- man/db-create.1 | 4 ++-- man/db-drop.1 | 4 ++-- man/db-export.1 | 4 ++-- man/db-import.1 | 4 ++-- man/db-optimize.1 | 4 ++-- man/db-query.1 | 6 +++--- man/db-repair.1 | 4 ++-- man/db-reset.1 | 4 ++-- man/eval-file.1 | 4 ++-- man/eval.1 | 4 ++-- man/export.1 | 4 ++-- man/help.1 | 10 ++++++++++ man/home.1 | 2 +- man/option-add.1 | 10 ++++++++++ man/option-delete.1 | 10 ++++++++++ man/option-get.1 | 10 ++++++++++ man/option-update.1 | 10 ++++++++++ man/plugin-activate.1 | 4 ++-- man/plugin-deactivate.1 | 4 ++-- man/plugin-delete.1 | 4 ++-- man/plugin-install.1 | 6 +++--- man/plugin-path.1 | 2 +- man/plugin-status.1 | 2 +- man/plugin-toggle.1 | 4 ++-- man/plugin-uninstall.1 | 4 ++-- man/plugin-update-all.1 | 10 ++++++++++ man/plugin-update.1 | 6 +++--- man/post-create.1 | 6 +++--- man/post-delete.1 | 4 ++-- man/post-generate.1 | 2 +- man/post-list.1 | 2 +- man/post-meta-add.1 | 10 ++++++++++ man/post-meta-delete.1 | 10 ++++++++++ man/post-meta-get.1 | 10 ++++++++++ man/post-meta-update.1 | 10 ++++++++++ man/post-update.1 | 6 +++--- man/rewrite-dump.1 | 4 ++-- man/rewrite-flush.1 | 4 ++-- man/rewrite-structure.1 | 6 +++--- man/theme-activate.1 | 4 ++-- man/theme-delete.1 | 2 +- man/theme-install.1 | 6 +++--- man/theme-path.1 | 2 +- man/theme-status.1 | 2 +- man/theme-update-all.1 | 10 ++++++++++ man/theme-update.1 | 6 +++--- man/transient-delete.1 | 10 ++++++++++ man/transient-get.1 | 10 ++++++++++ man/transient-set.1 | 10 ++++++++++ man/transient-type.1 | 10 ++++++++++ man/user-create.1 | 4 ++-- man/user-delete.1 | 6 +++--- man/user-generate.1 | 2 +- man/user-list.1 | 4 ++-- man/user-meta-add.1 | 10 ++++++++++ man/user-meta-delete.1 | 10 ++++++++++ man/user-meta-get.1 | 10 ++++++++++ man/user-meta-update.1 | 10 ++++++++++ man/user-update.1 | 6 +++--- src/docs/blog-create.txt | 7 ------- src/docs/blog-delete.txt | 8 -------- src/docs/comment-approve.txt | 7 ------- src/docs/comment-count.txt | 7 ------- src/docs/comment-create.txt | 7 ------- src/docs/comment-delete.txt | 7 ------- src/docs/comment-last.txt | 7 ------- src/docs/comment-spam.txt | 7 ------- src/docs/comment-status.txt | 7 ------- src/docs/comment-trash.txt | 7 ------- src/docs/comment-unapprove.txt | 7 ------- src/docs/comment-unspam.txt | 7 ------- src/docs/comment-untrash.txt | 7 ------- src/docs/core-config.txt | 7 ------- src/docs/core-download.txt | 7 ------- src/docs/core-install-network.txt | 8 -------- src/docs/core-install.txt | 7 ------- src/docs/core-update-db.txt | 6 ------ src/docs/core-update.txt | 7 ------- src/docs/core-version.txt | 7 ------- src/docs/db-cli.txt | 6 ------ src/docs/db-connect.txt | 6 ------ src/docs/db-create.txt | 6 ------ src/docs/db-drop.txt | 7 ------- src/docs/db-export.txt | 7 ------- src/docs/db-import.txt | 7 ------- src/docs/db-optimize.txt | 6 ------ src/docs/db-query.txt | 7 ------- src/docs/db-repair.txt | 6 ------ src/docs/db-reset.txt | 7 ------- src/docs/eval-file.txt | 7 ------- src/docs/eval.txt | 7 ------- src/docs/export.txt | 7 ------- src/docs/home.txt | 6 ------ src/docs/plugin-activate.txt | 7 ------- src/docs/plugin-deactivate.txt | 7 ------- src/docs/plugin-delete.txt | 7 ------- src/docs/plugin-install.txt | 7 ------- src/docs/plugin-path.txt | 7 ------- src/docs/plugin-status.txt | 7 ------- src/docs/plugin-toggle.txt | 7 ------- src/docs/plugin-uninstall.txt | 7 ------- src/docs/plugin-update.txt | 7 ------- src/docs/post-create.txt | 7 ------- src/docs/post-delete.txt | 7 ------- src/docs/post-generate.txt | 8 -------- src/docs/post-list.txt | 7 ------- src/docs/post-update.txt | 7 ------- src/docs/rewrite-dump.txt | 7 ------- src/docs/rewrite-flush.txt | 7 ------- src/docs/rewrite-structure.txt | 7 ------- src/docs/theme-activate.txt | 7 ------- src/docs/theme-delete.txt | 7 ------- src/docs/theme-install.txt | 7 ------- src/docs/theme-path.txt | 7 ------- src/docs/theme-status.txt | 7 ------- src/docs/theme-update.txt | 7 ------- src/docs/user-create.txt | 7 ------- src/docs/user-delete.txt | 7 ------- src/docs/user-generate.txt | 7 ------- src/docs/user-list.txt | 7 ------- src/docs/user-update.txt | 7 ------- 151 files changed, 410 insertions(+), 559 deletions(-) create mode 100644 man/cache-add.1 create mode 100644 man/cache-decr.1 create mode 100644 man/cache-delete.1 create mode 100644 man/cache-flush.1 create mode 100644 man/cache-get.1 create mode 100644 man/cache-incr.1 create mode 100644 man/cache-replace.1 create mode 100644 man/cache-set.1 create mode 100644 man/cache-type.1 create mode 100644 man/help.1 create mode 100644 man/option-add.1 create mode 100644 man/option-delete.1 create mode 100644 man/option-get.1 create mode 100644 man/option-update.1 create mode 100644 man/plugin-update-all.1 create mode 100644 man/post-meta-add.1 create mode 100644 man/post-meta-delete.1 create mode 100644 man/post-meta-get.1 create mode 100644 man/post-meta-update.1 create mode 100644 man/theme-update-all.1 create mode 100644 man/transient-delete.1 create mode 100644 man/transient-get.1 create mode 100644 man/transient-set.1 create mode 100644 man/transient-type.1 create mode 100644 man/user-meta-add.1 create mode 100644 man/user-meta-delete.1 create mode 100644 man/user-meta-get.1 create mode 100644 man/user-meta-update.1 delete mode 100644 src/docs/core-update-db.txt delete mode 100644 src/docs/db-cli.txt delete mode 100644 src/docs/db-connect.txt delete mode 100644 src/docs/db-create.txt delete mode 100644 src/docs/db-optimize.txt delete mode 100644 src/docs/db-repair.txt delete mode 100644 src/docs/home.txt diff --git a/man/blog-create.1 b/man/blog-create.1 index 574670f93..0245da7c1 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -4,10 +4,10 @@ .TH "WP\-BLOG\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-blog\-create\fR \- Create a new blog in a multisite install\. +\fBwp\-blog\-create\fR \- Create a blog in a multisite install\. . .SH "SYNOPSIS" -\fBwp blog create\fR \-\-slug=\fIslug\fR \-\-title=\fITitle\fR [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-public=true] +\fBwp blog create\fR \-\-slug=\fIslug\fR \-\-title=\fItitle\fR [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-public] . .SH "OPTIONS" . diff --git a/man/blog-delete.1 b/man/blog-delete.1 index b8f45e50b..556bb95c7 100644 --- a/man/blog-delete.1 +++ b/man/blog-delete.1 @@ -1,9 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 -wp\-blog\-delete(1) \-\- Delete a blog in a multisite install\. . -.P -==== +.TH "WP\-BLOG\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-blog\-delete\fR \- Delete a blog in a multisite install\. . .SH "SYNOPSIS" \fBwp blog delete\fR \-\-slug=\fIslug\fR [\-\-yes] [\-\-keep\-tables] diff --git a/man/cache-add.1 b/man/cache-add.1 new file mode 100644 index 000000000..1ba98a2b0 --- /dev/null +++ b/man/cache-add.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-ADD" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-add\fR \- Add a value to the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache add\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-decr.1 b/man/cache-decr.1 new file mode 100644 index 000000000..7b77e7111 --- /dev/null +++ b/man/cache-decr.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-DECR" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-decr\fR \- Decrement a value in the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache decr\fR \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] diff --git a/man/cache-delete.1 b/man/cache-delete.1 new file mode 100644 index 000000000..180dd95d4 --- /dev/null +++ b/man/cache-delete.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-delete\fR \- Remove a value from the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache delete\fR \fIkey\fR \fIgroup\fR diff --git a/man/cache-flush.1 b/man/cache-flush.1 new file mode 100644 index 000000000..68fa2e169 --- /dev/null +++ b/man/cache-flush.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-FLUSH" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-flush\fR \- Flush the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache flush\fR diff --git a/man/cache-get.1 b/man/cache-get.1 new file mode 100644 index 000000000..eb27a251c --- /dev/null +++ b/man/cache-get.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-GET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-get\fR \- Get a value from the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache get\fR \fIkey\fR [\fIgroup\fR] diff --git a/man/cache-incr.1 b/man/cache-incr.1 new file mode 100644 index 000000000..fc2e886a5 --- /dev/null +++ b/man/cache-incr.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-INCR" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-incr\fR \- Increment a value in the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache incr\fR \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] diff --git a/man/cache-replace.1 b/man/cache-replace.1 new file mode 100644 index 000000000..d33269501 --- /dev/null +++ b/man/cache-replace.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-REPLACE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-replace\fR \- Replace an existing value in the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache replace\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-set.1 b/man/cache-set.1 new file mode 100644 index 000000000..d40e0c0e6 --- /dev/null +++ b/man/cache-set.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-SET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-set\fR \- Set a value to the object cache\. +. +.SH "SYNOPSIS" +\fBwp cache set\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-type.1 b/man/cache-type.1 new file mode 100644 index 000000000..a6c7c2a47 --- /dev/null +++ b/man/cache-type.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CACHE\-TYPE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cache\-type\fR \- Attempts to determine which object cache is being used\. +. +.SH "SYNOPSIS" +\fBwp cache type\fR diff --git a/man/comment-approve.1 b/man/comment-approve.1 index 5fbb4caa7..06ecb02c8 100644 --- a/man/comment-approve.1 +++ b/man/comment-approve.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-APPROVE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-APPROVE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-approve\fR \- Approve a comment\. . .SH "SYNOPSIS" -\fBwp comment approve\fR \fIID\fR +\fBwp comment approve\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-count.1 b/man/comment-count.1 index 733606c17..eda8c40ae 100644 --- a/man/comment-count.1 +++ b/man/comment-count.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-COUNT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-COUNT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-count\fR \- Get total comments for blog or single post +\fBwp\-comment\-count\fR \- Count comments, on whole blog or on a given post\. . .SH "SYNOPSIS" -\fBwp comment count\fR [\fIID\fR] +\fBwp comment count\fR [\fIpost\-id\fR] . .SH "OPTIONS" . diff --git a/man/comment-create.1 b/man/comment-create.1 index b164b96e7..2d7510f36 100644 --- a/man/comment-create.1 +++ b/man/comment-create.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-CREATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-create\fR \- Create a new comment\. +\fBwp\-comment\-create\fR \- Insert a comment\. . .SH "SYNOPSIS" -\fBwp comment create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-porcelain] +\fBwp comment create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/comment-delete.1 b/man/comment-delete.1 index e7daaf6d6..14f31ffec 100644 --- a/man/comment-delete.1 +++ b/man/comment-delete.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-DELETE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-delete\fR \- Delete a comment\. . .SH "SYNOPSIS" -\fBwp comment delete\fR \fIID\fR [\-\-force] +\fBwp comment delete\fR \fIid\fR [\-\-force] . .SH "OPTIONS" . diff --git a/man/comment-last.1 b/man/comment-last.1 index f1c4809d2..298df1486 100644 --- a/man/comment-last.1 +++ b/man/comment-last.1 @@ -4,7 +4,7 @@ .TH "WP\-COMMENT\-LAST" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-last\fR \- Retrieve last approved comment +\fBwp\-comment\-last\fR \- Get last approved comment\. . .SH "SYNOPSIS" \fBwp comment last\fR [\-\-id] [\-\-full] diff --git a/man/comment-spam.1 b/man/comment-spam.1 index 303d179e7..ab667d8ca 100644 --- a/man/comment-spam.1 +++ b/man/comment-spam.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-SPAM" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-SPAM" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-spam\fR \- Mark a comment as spam\. +\fBwp\-comment\-spam\fR \- Spam a comment\. . .SH "SYNOPSIS" -\fBwp comment spam\fR \fIID\fR +\fBwp comment spam\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-status.1 b/man/comment-status.1 index 6ca168f9d..a9256af37 100644 --- a/man/comment-status.1 +++ b/man/comment-status.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-STATUS" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-STATUS" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-status\fR \- Get status of a comment +\fBwp\-comment\-status\fR \- Get status of a comment\. . .SH "SYNOPSIS" -\fBwp comment status\fR \fIID\fR +\fBwp comment status\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-trash.1 b/man/comment-trash.1 index cf451e98f..0b9cdbe2e 100644 --- a/man/comment-trash.1 +++ b/man/comment-trash.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-TRASH" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-TRASH" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-trash\fR \- Trash a comment\. . .SH "SYNOPSIS" -\fBwp comment trash\fR \fIID\fR +\fBwp comment trash\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-unapprove.1 b/man/comment-unapprove.1 index 7df1204da..01a7ae93c 100644 --- a/man/comment-unapprove.1 +++ b/man/comment-unapprove.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNAPPROVE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNAPPROVE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-unapprove\fR \- Unapprove a comment\. . .SH "SYNOPSIS" -\fBwp comment unapprove\fR \fIID\fR +\fBwp comment unapprove\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-unspam.1 b/man/comment-unspam.1 index 4eb765e91..6b64e907d 100644 --- a/man/comment-unspam.1 +++ b/man/comment-unspam.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNSPAM" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNSPAM" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-comment\-unspam\fR \- Unmark a comment as spam\. +\fBwp\-comment\-unspam\fR \- Unspam a comment\. . .SH "SYNOPSIS" -\fBwp comment unspam\fR \fIID\fR +\fBwp comment unspam\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-untrash.1 b/man/comment-untrash.1 index 223fd5cfc..7b62bfec3 100644 --- a/man/comment-untrash.1 +++ b/man/comment-untrash.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNTRASH" "1" "September 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNTRASH" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-untrash\fR \- Untrash a comment\. . .SH "SYNOPSIS" -\fBwp comment untrash\fR \fIID\fR +\fBwp comment untrash\fR \fIid\fR . .SH "OPTIONS" . diff --git a/man/core-config.1 b/man/core-config.1 index cc545a665..e1f2260b7 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-CONFIG" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CORE\-CONFIG" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-config\fR \- Create a wp\-config\.php file\. +\fBwp\-core\-config\fR \- Set up a wp\-config\. . .SH "SYNOPSIS" -\fBwp core config\fR \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=localhost] [\-\-dbprefix=wp_] +\fBwp core config\fR \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] . .SH "OPTIONS" . diff --git a/man/core-download.1 b/man/core-download.1 index 9dc988e6d..a654552f0 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-DOWNLOAD" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CORE\-DOWNLOAD" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-download\fR \- Download core WordPress files\. . .SH "SYNOPSIS" -\fBwp core download\fR [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] +\fBwp core download\fR [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] . .SH "OPTIONS" . diff --git a/man/core-install-network.1 b/man/core-install-network.1 index d2bfef710..f7bb75355 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -4,7 +4,7 @@ .TH "WP\-CORE\-INSTALL\-NETWORK" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-install\-network\fR \- Transform a single\-site install into a +\fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. . .SH "SYNOPSIS" \fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=\fIurl\-path\fR] diff --git a/man/core-install.1 b/man/core-install.1 index 9ba7e9e4a..6eda4897c 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-install\fR \- Install the WordPress tables in the database\. +\fBwp\-core\-install\fR \- Create the WordPress tables in the database\. . .SH "SYNOPSIS" \fBwp core install\fR \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_email=\fIemail\fR \-\-admin_password=\fIpassword\fR diff --git a/man/core-update.1 b/man/core-update.1 index c0b4f8c61..aa7cd22e4 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-update\fR \- Update WordPress to the latest version\. +\fBwp\-core\-update\fR \- Update WordPress\. . .SH "SYNOPSIS" -\fBwp core update\fR [\-\-version=\fInew_version\fR] [\-\-force] [<package/zip>] +\fBwp core update\fR [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] . .SH "OPTIONS" . diff --git a/man/core-version.1 b/man/core-version.1 index 8e910bab1..bb3bf3ca4 100644 --- a/man/core-version.1 +++ b/man/core-version.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-VERSION" "1" "September 2012" "" "WP-CLI" +.TH "WP\-CORE\-VERSION" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-version\fR \- Show the WordPress version\. +\fBwp\-core\-version\fR \- Display the WordPress version\. . .SH "SYNOPSIS" \fBwp core version\fR [\-\-extra] diff --git a/man/db-cli.1 b/man/db-cli.1 index c8ae69ee6..f5d2b88da 100644 --- a/man/db-cli.1 +++ b/man/db-cli.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CLI" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-CLI" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-cli\fR \- Open a SQL command\-line interface to the WordPress database\. +\fBwp\-db\-cli\fR \- Open a mysql console using the WordPress credentials\. . .SH "SYNOPSIS" \fBwp db cli\fR diff --git a/man/db-connect.1 b/man/db-connect.1 index bb73c49b1..9fea5148e 100644 --- a/man/db-connect.1 +++ b/man/db-connect.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CONNECT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-CONNECT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-connect\fR \- Print a string for connecting to the database\. +\fBwp\-db\-connect\fR \- Print a string for connecting to the DB\. . .SH "SYNOPSIS" \fBwp db connect\fR diff --git a/man/db-create.1 b/man/db-create.1 index 06d954353..eac9c4b54 100644 --- a/man/db-create.1 +++ b/man/db-create.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-CREATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-create\fR \- Create a database using the credentials from wp\-config\.php\. +\fBwp\-db\-create\fR \- Create the database\. . .SH "SYNOPSIS" \fBwp db create\fR diff --git a/man/db-drop.1 b/man/db-drop.1 index b3cf01108..d84934d27 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-DROP" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-DROP" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-drop\fR \- Drop the database specified in wp\-config\.php +\fBwp\-db\-drop\fR \- Delete the database\. . .SH "SYNOPSIS" \fBwp db drop\fR [\-\-yes] diff --git a/man/db-export.1 b/man/db-export.1 index 06b28380c..e4bbc6301 100644 --- a/man/db-export.1 +++ b/man/db-export.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-EXPORT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-EXPORT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-export\fR \- Export the WordPress database using mysqldump\. +\fBwp\-db\-export\fR \- Exports the database using mysqldump\. . .SH "SYNOPSIS" \fBwp db export\fR [\fIfile\fR] diff --git a/man/db-import.1 b/man/db-import.1 index 8941bbe14..456e821c4 100644 --- a/man/db-import.1 +++ b/man/db-import.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-IMPORT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-IMPORT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-import\fR \- Import a database from a text file\. +\fBwp\-db\-import\fR \- Import database from a file\. . .SH "SYNOPSIS" \fBwp db import\fR [\fIfile\fR] diff --git a/man/db-optimize.1 b/man/db-optimize.1 index 3381c63ee..50fad9af3 100644 --- a/man/db-optimize.1 +++ b/man/db-optimize.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-OPTIMIZE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-OPTIMIZE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-optimize\fR \- Optimize the database specified in the wp\-config\.php file\. +\fBwp\-db\-optimize\fR \- Optimize the database\. . .SH "SYNOPSIS" \fBwp db optimize\fR diff --git a/man/db-query.1 b/man/db-query.1 index 9ba0d685b..c8cd72887 100644 --- a/man/db-query.1 +++ b/man/db-query.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-QUERY" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-QUERY" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-query\fR \- Execute a query against the WordPress database\. +\fBwp\-db\-query\fR \- Execute a query against the database\. . .SH "SYNOPSIS" -\fBwp db query\fR \fISQL\fR +\fBwp db query\fR \fIsql\fR . .SH "OPTIONS" . diff --git a/man/db-repair.1 b/man/db-repair.1 index 9c96284d3..3e6539c8d 100644 --- a/man/db-repair.1 +++ b/man/db-repair.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-REPAIR" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-REPAIR" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-repair\fR \- Optimize the database specified in the wp\-config\.php file\. +\fBwp\-db\-repair\fR \- Repair the database\. . .SH "SYNOPSIS" \fBwp db repair\fR diff --git a/man/db-reset.1 b/man/db-reset.1 index de44c9539..d1c50d27c 100644 --- a/man/db-reset.1 +++ b/man/db-reset.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-RESET" "1" "September 2012" "" "WP-CLI" +.TH "WP\-DB\-RESET" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-reset\fR \- Remove all data from the database specified in wp\-config\.php +\fBwp\-db\-reset\fR \- Remove all tables from the database\. . .SH "SYNOPSIS" \fBwp db reset\fR [\-\-yes] diff --git a/man/eval-file.1 b/man/eval-file.1 index b0a1694d4..6ca9e6d26 100644 --- a/man/eval-file.1 +++ b/man/eval-file.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL\-FILE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-EVAL\-FILE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. . .SH "SYNOPSIS" -\fBwp eval\-file\fR \fIfile\fR +\fBwp eval\-file\fR \fIpath\fR . .SH "EXAMPLES" . diff --git a/man/eval.1 b/man/eval.1 index 2a8dbdb23..8889e5f51 100644 --- a/man/eval.1 +++ b/man/eval.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL" "1" "September 2012" "" "WP-CLI" +.TH "WP\-EVAL" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. . .SH "SYNOPSIS" -\fBwp eval\fR \fIPHP\fR +\fBwp eval\fR \fIphp\-code\fR . .SH "EXAMPLES" . diff --git a/man/export.1 b/man/export.1 index 20f47f672..77260f31f 100644 --- a/man/export.1 +++ b/man/export.1 @@ -4,10 +4,10 @@ .TH "WP\-EXPORT" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-export\fR \- Create a WXR file\. +\fBwp\-export\fR \- Export posts to a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR \-\-dir=\fIdirname\fR [filters] [\-\-skip_comments] +\fBwp export\fR \-\-dir=\fIdir\fR [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] . .SH "OPTIONS" . diff --git a/man/help.1 b/man/help.1 new file mode 100644 index 000000000..ec0050cb1 --- /dev/null +++ b/man/help.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-HELP" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-help\fR \- Get help on a certain topic\. +. +.SH "SYNOPSIS" +\fBwp help\fR [\fIcommand\fR] diff --git a/man/home.1 b/man/home.1 index 2dc74647e..235d563cb 100644 --- a/man/home.1 +++ b/man/home.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-HOME" "1" "September 2012" "" "WP-CLI" +.TH "WP\-HOME" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-home\fR \- Opens the wp\-cli homepage in your browser\. diff --git a/man/option-add.1 b/man/option-add.1 new file mode 100644 index 000000000..249bfa0b0 --- /dev/null +++ b/man/option-add.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-OPTION\-ADD" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-option\-add\fR \- Add an option\. +. +.SH "SYNOPSIS" +\fBwp option add\fR \fIkey\fR \fIvalue\fR [\-\-json] diff --git a/man/option-delete.1 b/man/option-delete.1 new file mode 100644 index 000000000..a625edcc9 --- /dev/null +++ b/man/option-delete.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-OPTION\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-option\-delete\fR \- Delete an option\. +. +.SH "SYNOPSIS" +\fBwp option delete\fR \fIkey\fR diff --git a/man/option-get.1 b/man/option-get.1 new file mode 100644 index 000000000..ad48edbd0 --- /dev/null +++ b/man/option-get.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-OPTION\-GET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-option\-get\fR \- Get an option\. +. +.SH "SYNOPSIS" +\fBwp option get\fR \fIkey\fR [\-\-json] diff --git a/man/option-update.1 b/man/option-update.1 new file mode 100644 index 000000000..f53e10c0a --- /dev/null +++ b/man/option-update.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-OPTION\-UPDATE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-option\-update\fR \- Update an option\. +. +.SH "SYNOPSIS" +\fBwp option update\fR \fIkey\fR \fIvalue\fR [\-\-json] diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index bff5b9bbe..b4e9fce6a 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-ACTIVATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-ACTIVATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-activate\fR \- Activate an installed plugin\. +\fBwp\-plugin\-activate\fR \- Activate a plugin\. . .SH "SYNOPSIS" \fBwp plugin activate\fR \fIplugin\fR [\-\-network] diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 index 3de02d969..17a87783e 100644 --- a/man/plugin-deactivate.1 +++ b/man/plugin-deactivate.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-deactivate\fR \- Deactivate an active plugin\. +\fBwp\-plugin\-deactivate\fR \- Deactivate a plugin\. . .SH "SYNOPSIS" \fBwp plugin deactivate\fR \fIplugin\fR [\-\-network] diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 index 8a8834c48..b89c7ab09 100644 --- a/man/plugin-delete.1 +++ b/man/plugin-delete.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DELETE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-delete\fR \- Delete a plugin\'s files, without removing it\'s data\. +\fBwp\-plugin\-delete\fR \- Delete plugin files\. . .SH "SYNOPSIS" \fBwp plugin delete\fR \fIplugin\fR diff --git a/man/plugin-install.1 b/man/plugin-install.1 index af740f73b..18a07e6d2 100644 --- a/man/plugin-install.1 +++ b/man/plugin-install.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-INSTALL" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-INSTALL" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-install\fR \- Install a plugin from wordpress\.org or from a zip file\. +\fBwp\-plugin\-install\fR \- Install a plugin\. . .SH "SYNOPSIS" -\fBwp plugin install\fR <plugin/zip> [\-\-version=\fIversion\fR] [\-\-activate] +\fBwp plugin install\fR \fIplugin|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] . .SH "OPTIONS" . diff --git a/man/plugin-path.1 b/man/plugin-path.1 index 87c1c8eb0..d8888628c 100644 --- a/man/plugin-path.1 +++ b/man/plugin-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-PATH" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-PATH" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. diff --git a/man/plugin-status.1 b/man/plugin-status.1 index 98c1ea177..305f7902b 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-STATUS" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-STATUS" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index 9764eca03..fdfd9bf61 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-TOGGLE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-deactivate\fR \- Activate/Deactivate an installed plugin\. +\fBwp\-plugin\-toggle\fR \- Toggle a plugin\'s activation state\. . .SH "SYNOPSIS" \fBwp plugin toggle\fR \fIplugin\fR [\-\-network] diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 index 7e6bd9043..0690bc46b 100644 --- a/man/plugin-uninstall.1 +++ b/man/plugin-uninstall.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UNINSTALL" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UNINSTALL" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-uninstall\fR \- Run the uninstallation procedure for a plugin\. +\fBwp\-plugin\-uninstall\fR \- Uninstall a plugin\. . .SH "SYNOPSIS" \fBwp plugin uninstall\fR \fIplugin\fR [\-\-no\-delete] diff --git a/man/plugin-update-all.1 b/man/plugin-update-all.1 new file mode 100644 index 000000000..0e0806909 --- /dev/null +++ b/man/plugin-update-all.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-UPDATE\-ALL" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-update\-all\fR \- Update all plugins\. +. +.SH "SYNOPSIS" +\fBwp plugin update\-all\fR [\-\-dry\-run] diff --git a/man/plugin-update.1 b/man/plugin-update.1 index 3fcac90c5..43d0d5705 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UPDATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UPDATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-plugin\-update\fR \- Update an installed plugin\. +\fBwp\-plugin\-update\fR \- Update a plugin\. . .SH "SYNOPSIS" -\fBwp plugin update\fR [\fIplugin\fR] [\-\-all] [\-\-version=dev] +\fBwp plugin update\fR \fIplugin\fR [\-\-version=\fIversion\fR] . .SH "OPTIONS" . diff --git a/man/post-create.1 b/man/post-create.1 index 072011b4c..4d7ca0460 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-CREATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-POST\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-create\fR \- Create a new WordPress post\. +\fBwp\-post\-create\fR \- Create a post\. . .SH "SYNOPSIS" -\fBwp post create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-porcelain] +\fBwp post create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/post-delete.1 b/man/post-delete.1 index 616087a1e..f2ef6523e 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -4,10 +4,10 @@ .TH "WP\-POST\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-delete\fR \- Delete one or several posts by ID\. +\fBwp\-post\-delete\fR \- Delete a post by ID\. . .SH "SYNOPSIS" -\fBwp post delete\fR \fIID\fR\.\.\. [\-\-force] +\fBwp post delete\fR \fIid\fR\.\.\. [\-\-force] . .SH "OPTIONS" . diff --git a/man/post-generate.1 b/man/post-generate.1 index afb014a25..93969834d 100644 --- a/man/post-generate.1 +++ b/man/post-generate.1 @@ -4,7 +4,7 @@ .TH "WP\-POST\-GENERATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-generate\fR \- Generate a bunch of posts\. +\fBwp\-post\-generate\fR \- Generate some posts\. . .SH "SYNOPSIS" \fBwp post generate\fR [\-\-count=100] [\-\-post_type=post] [\-\-post_status=publish] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIdate\fR] [\-\-max_depth=1] diff --git a/man/post-list.1 b/man/post-list.1 index b66c8137a..e35e8d6fa 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -\fBwp post list\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] [\-\-ids] +\fBwp post list\fR [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] . .SH "OPTIONS" . diff --git a/man/post-meta-add.1 b/man/post-meta-add.1 new file mode 100644 index 000000000..91ae02aa8 --- /dev/null +++ b/man/post-meta-add.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-META\-ADD" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-meta\-add\fR \- Add a meta field\. +. +.SH "SYNOPSIS" +\fBwp post\-meta add\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/post-meta-delete.1 b/man/post-meta-delete.1 new file mode 100644 index 000000000..ea28519d5 --- /dev/null +++ b/man/post-meta-delete.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-META\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-meta\-delete\fR \- Delete a meta field\. +. +.SH "SYNOPSIS" +\fBwp post\-meta delete\fR \fIid\fR \fIkey\fR diff --git a/man/post-meta-get.1 b/man/post-meta-get.1 new file mode 100644 index 000000000..330773f18 --- /dev/null +++ b/man/post-meta-get.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-META\-GET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-meta\-get\fR \- Get meta field value\. +. +.SH "SYNOPSIS" +\fBwp post\-meta get\fR \fIid\fR \fIkey\fR [\-\-json] diff --git a/man/post-meta-update.1 b/man/post-meta-update.1 new file mode 100644 index 000000000..a90f92c42 --- /dev/null +++ b/man/post-meta-update.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-META\-UPDATE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-meta\-update\fR \- Update a meta field\. +. +.SH "SYNOPSIS" +\fBwp post\-meta update\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/post-update.1 b/man/post-update.1 index 60d85f15b..abadef4a0 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-UPDATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-POST\-UPDATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-update\fR \- Update a WordPress post\. +\fBwp\-post\-update\fR \- Update a post\. . .SH "SYNOPSIS" -\fBwp post update\fR \fIID\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] +\fBwp post update\fR \fIid\fR \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 index fffedb924..8b7432011 100644 --- a/man/rewrite-dump.1 +++ b/man/rewrite-dump.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "REWRITE\-DUMP" "1" "September 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-DUMP" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBrewrite\-dump\fR \- Print current rewrite rules to STDOUT\. +\fBwp\-rewrite\-dump\fR \- Print current rewrite rules\. . .SH "SYNOPSIS" \fBwp rewrite dump\fR [\-\-json] diff --git a/man/rewrite-flush.1 b/man/rewrite-flush.1 index 02a631a4a..f7ba485be 100644 --- a/man/rewrite-flush.1 +++ b/man/rewrite-flush.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "REWRITE\-FLUSH" "1" "September 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-FLUSH" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBrewrite\-flush\fR \- Flush rewrite rules\. +\fBwp\-rewrite\-flush\fR \- Flush rewrite rules\. . .SH "SYNOPSIS" \fBwp rewrite flush\fR [\-\-soft] diff --git a/man/rewrite-structure.1 b/man/rewrite-structure.1 index 833cd3e3a..8589c5ca9 100644 --- a/man/rewrite-structure.1 +++ b/man/rewrite-structure.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "REWRITE\-STRUCTURE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-STRUCTURE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBrewrite\-structure\fR \- Update the permalink structure +\fBwp\-rewrite\-structure\fR \- Update the permalink structure\. . .SH "SYNOPSIS" -\fBwp rewrite structure\fR \fIpermastruct\fR [\-\-category\-base=\fIcategorybase\fR] [\-\-tag\-base=\fItagbase\fR] +\fBwp rewrite structure\fR \fIpermastruct\fR [\-\-category\-base=\fIbase\fR] [\-\-tag\-base=\fIbase\fR] . .SH "OPTIONS" . diff --git a/man/theme-activate.1 b/man/theme-activate.1 index 55861bc3d..cb545a291 100644 --- a/man/theme-activate.1 +++ b/man/theme-activate.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-ACTIVATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-ACTIVATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-theme\-activate\fR \- Activate an installed theme\. +\fBwp\-theme\-activate\fR \- Activate a theme\. . .SH "SYNOPSIS" \fBwp theme activate\fR \fItheme\fR diff --git a/man/theme-delete.1 b/man/theme-delete.1 index 0514d865d..7bf993510 100644 --- a/man/theme-delete.1 +++ b/man/theme-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-DELETE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-delete\fR \- Delete a theme\. diff --git a/man/theme-install.1 b/man/theme-install.1 index 3042b5bee..96ea741d4 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-INSTALL" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-INSTALL" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-theme\-install\fR \- Install a theme from wordpress\.org or from a zip file\. +\fBwp\-theme\-install\fR \- Install a theme\. . .SH "SYNOPSIS" -\fBwp theme install\fR <theme/zip> [\-\-activate] +\fBwp theme install\fR \fItheme|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] . .SH "OPTIONS" . diff --git a/man/theme-path.1 b/man/theme-path.1 index 90bf49d82..64275161f 100644 --- a/man/theme-path.1 +++ b/man/theme-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-PATH" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-PATH" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. diff --git a/man/theme-status.1 b/man/theme-status.1 index 53b68274a..e7b10fd12 100644 --- a/man/theme-status.1 +++ b/man/theme-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-STATUS" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-STATUS" "1" "October 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-status\fR \- See the status of one or all themes\. diff --git a/man/theme-update-all.1 b/man/theme-update-all.1 new file mode 100644 index 000000000..27a2beda1 --- /dev/null +++ b/man/theme-update-all.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-UPDATE\-ALL" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-update\-all\fR \- Update all themes\. +. +.SH "SYNOPSIS" +\fBwp theme update\-all\fR [\-\-dry\-run] diff --git a/man/theme-update.1 b/man/theme-update.1 index 5ae00b078..b186f1f81 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-UPDATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-THEME\-UPDATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-theme\-update\fR \- Update an installed theme\. +\fBwp\-theme\-update\fR \- Update a theme\. . .SH "SYNOPSIS" -\fBwp theme update\fR [\fItheme\fR] [\-\-all] +\fBwp theme update\fR \fItheme\fR . .SH "OPTIONS" . diff --git a/man/transient-delete.1 b/man/transient-delete.1 new file mode 100644 index 000000000..490196468 --- /dev/null +++ b/man/transient-delete.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TRANSIENT\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-transient\-delete\fR \- Delete a transient value\. +. +.SH "SYNOPSIS" +\fBwp transient delete\fR \fIkey\fR diff --git a/man/transient-get.1 b/man/transient-get.1 new file mode 100644 index 000000000..b6895c048 --- /dev/null +++ b/man/transient-get.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TRANSIENT\-GET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-transient\-get\fR \- Get a transient value\. +. +.SH "SYNOPSIS" +\fBwp transient get\fR \fIkey\fR [\-\-json] diff --git a/man/transient-set.1 b/man/transient-set.1 new file mode 100644 index 000000000..a3addcc59 --- /dev/null +++ b/man/transient-set.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TRANSIENT\-SET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-transient\-set\fR \- Set a transient value\. +. +.SH "SYNOPSIS" +\fBwp transient set\fR \fIkey\fR \fIvalue\fR [\fIexpiration\fR] diff --git a/man/transient-type.1 b/man/transient-type.1 new file mode 100644 index 000000000..bdd4b0677 --- /dev/null +++ b/man/transient-type.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TRANSIENT\-TYPE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-transient\-type\fR \- See wether the transients API is using an object cache or the options table\. +. +.SH "SYNOPSIS" +\fBwp transient type\fR diff --git a/man/user-create.1 b/man/user-create.1 index 67537e0c7..9f98d4296 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-CREATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-USER\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-create\fR \- Create a new WordPress user\. +\fBwp\-user\-create\fR \- Create a user\. . .SH "SYNOPSIS" \fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-porcelain] diff --git a/man/user-delete.1 b/man/user-delete.1 index a33d6fdd3..5f76a774a 100644 --- a/man/user-delete.1 +++ b/man/user-delete.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-DELETE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-USER\-DELETE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-delete\fR \- Delete a WordPress user\. +\fBwp\-user\-delete\fR \- Delete a user\. . .SH "SYNOPSIS" -\fBwp user delete\fR \fIID\fR [\-\-reassign=\fIID\fR] +\fBwp user delete\fR \fIid\fR [\-\-reassign=\fIid\fR] . .SH "OPTIONS" . diff --git a/man/user-generate.1 b/man/user-generate.1 index a2331a216..faa3c7bd1 100644 --- a/man/user-generate.1 +++ b/man/user-generate.1 @@ -4,7 +4,7 @@ .TH "WP\-USER\-GENERATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-generate\fR \- Generate a bunch of users\. +\fBwp\-user\-generate\fR \- Generate users\. . .SH "SYNOPSIS" \fBwp user generate\fR [\-\-count=100] [\-\-role=\fIrole\fR] diff --git a/man/user-list.1 b/man/user-list.1 index 0535f8674..c55e48fdd 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-LIST" "1" "September 2012" "" "WP-CLI" +.TH "WP\-USER\-LIST" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-list\fR \- List WordPress users\. +\fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" \fBwp user list\fR [\-\-role=\fIrole\fR] diff --git a/man/user-meta-add.1 b/man/user-meta-add.1 new file mode 100644 index 000000000..691c7b6dc --- /dev/null +++ b/man/user-meta-add.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META\-ADD" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\-add\fR \- Add a meta field\. +. +.SH "SYNOPSIS" +\fBwp user\-meta add\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/user-meta-delete.1 b/man/user-meta-delete.1 new file mode 100644 index 000000000..310893ccd --- /dev/null +++ b/man/user-meta-delete.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META\-DELETE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\-delete\fR \- Delete a meta field\. +. +.SH "SYNOPSIS" +\fBwp user\-meta delete\fR \fIid\fR \fIkey\fR diff --git a/man/user-meta-get.1 b/man/user-meta-get.1 new file mode 100644 index 000000000..1d9ee4b8c --- /dev/null +++ b/man/user-meta-get.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META\-GET" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\-get\fR \- Get meta field value\. +. +.SH "SYNOPSIS" +\fBwp user\-meta get\fR \fIid\fR \fIkey\fR [\-\-json] diff --git a/man/user-meta-update.1 b/man/user-meta-update.1 new file mode 100644 index 000000000..1e5e44f8f --- /dev/null +++ b/man/user-meta-update.1 @@ -0,0 +1,10 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-META\-UPDATE" "1" "October 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-meta\-update\fR \- Update a meta field\. +. +.SH "SYNOPSIS" +\fBwp user\-meta update\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/user-update.1 b/man/user-update.1 index cebdfef6b..2cf19a5ec 100644 --- a/man/user-update.1 +++ b/man/user-update.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-UPDATE" "1" "September 2012" "" "WP-CLI" +.TH "WP\-USER\-UPDATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-update\fR \- Update a WordPress user\. +\fBwp\-user\-update\fR \- Update a user\. . .SH "SYNOPSIS" -\fBwp user update\fR \fIID\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-\fIfield\fR=\fIvalue\fR\.\.\.] +\fBwp user update\fR \fIid\fR \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . diff --git a/src/docs/blog-create.txt b/src/docs/blog-create.txt index cfe7b2b39..3f660e3cb 100644 --- a/src/docs/blog-create.txt +++ b/src/docs/blog-create.txt @@ -1,10 +1,3 @@ -wp-blog-create(1) -- Create a new blog in a multisite install. -==== - -## SYNOPSIS - -`wp blog create` --slug=<slug> --title=<Title> [--email=<email>] [--site_id=<site-id>] [--public=true] - ## OPTIONS * `--slug`=<slug>: diff --git a/src/docs/blog-delete.txt b/src/docs/blog-delete.txt index 18b3ac87b..349836eb8 100644 --- a/src/docs/blog-delete.txt +++ b/src/docs/blog-delete.txt @@ -1,11 +1,3 @@ -wp-blog-delete(1) -- Delete a blog in a multisite install. - -==== - -## SYNOPSIS - -`wp blog delete` --slug=<slug> [--yes] [--keep-tables] - ## OPTIONS * `--slug`=<slug>: diff --git a/src/docs/comment-approve.txt b/src/docs/comment-approve.txt index 7ed0ac4a1..f703cd04b 100644 --- a/src/docs/comment-approve.txt +++ b/src/docs/comment-approve.txt @@ -1,10 +1,3 @@ -wp-comment-approve(1) -- Approve a comment. -==== - -## SYNOPSIS - -`wp comment approve` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-count.txt b/src/docs/comment-count.txt index 1c2abcf86..0c595e370 100644 --- a/src/docs/comment-count.txt +++ b/src/docs/comment-count.txt @@ -1,10 +1,3 @@ -wp-comment-count(1) -- Get total comments for blog or single post -==== - -## SYNOPSIS - -`wp comment count` [<ID>] - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-create.txt b/src/docs/comment-create.txt index b64ecb4e0..0b093d2f0 100644 --- a/src/docs/comment-create.txt +++ b/src/docs/comment-create.txt @@ -1,10 +1,3 @@ -wp-comment-create(1) -- Create a new comment. -==== - -## SYNOPSIS - -`wp comment create` --<field>=<value> [--<field>=<value>...] [--porcelain] - ## OPTIONS * `--<field>`=<value>: diff --git a/src/docs/comment-delete.txt b/src/docs/comment-delete.txt index 2cb016dcb..bd39300f7 100644 --- a/src/docs/comment-delete.txt +++ b/src/docs/comment-delete.txt @@ -1,10 +1,3 @@ -wp-comment-delete(1) -- Delete a comment. -==== - -## SYNOPSIS - -`wp comment delete` <ID> [--force] - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-last.txt b/src/docs/comment-last.txt index 358fcd79a..34504ec53 100644 --- a/src/docs/comment-last.txt +++ b/src/docs/comment-last.txt @@ -1,10 +1,3 @@ -wp-comment-last(1) -- Retrieve last approved comment -==== - -## SYNOPSIS - -`wp comment last` [--id] [--full] - ## OPTIONS * `--id`: diff --git a/src/docs/comment-spam.txt b/src/docs/comment-spam.txt index 0fcdaf9a6..b1a446cf1 100644 --- a/src/docs/comment-spam.txt +++ b/src/docs/comment-spam.txt @@ -1,10 +1,3 @@ -wp-comment-spam(1) -- Mark a comment as spam. -==== - -## SYNOPSIS - -`wp comment spam` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-status.txt b/src/docs/comment-status.txt index ee51ec4fd..a53c32765 100644 --- a/src/docs/comment-status.txt +++ b/src/docs/comment-status.txt @@ -1,10 +1,3 @@ -wp-comment-status(1) -- Get status of a comment -==== - -## SYNOPSIS - -`wp comment status` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-trash.txt b/src/docs/comment-trash.txt index 791968f52..3d1388178 100644 --- a/src/docs/comment-trash.txt +++ b/src/docs/comment-trash.txt @@ -1,10 +1,3 @@ -wp-comment-trash(1) -- Trash a comment. -==== - -## SYNOPSIS - -`wp comment trash` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-unapprove.txt b/src/docs/comment-unapprove.txt index 1fee7ac48..5569199c4 100644 --- a/src/docs/comment-unapprove.txt +++ b/src/docs/comment-unapprove.txt @@ -1,10 +1,3 @@ -wp-comment-unapprove(1) -- Unapprove a comment. -==== - -## SYNOPSIS - -`wp comment unapprove` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-unspam.txt b/src/docs/comment-unspam.txt index 59e9ff494..1a055d2ce 100644 --- a/src/docs/comment-unspam.txt +++ b/src/docs/comment-unspam.txt @@ -1,10 +1,3 @@ -wp-comment-unspam(1) -- Unmark a comment as spam. -==== - -## SYNOPSIS - -`wp comment unspam` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/comment-untrash.txt b/src/docs/comment-untrash.txt index d35967a3f..54fe15eb2 100644 --- a/src/docs/comment-untrash.txt +++ b/src/docs/comment-untrash.txt @@ -1,10 +1,3 @@ -wp-comment-untrash(1) -- Untrash a comment. -==== - -## SYNOPSIS - -`wp comment untrash` <ID> - ## OPTIONS * `<ID>`: diff --git a/src/docs/core-config.txt b/src/docs/core-config.txt index 01f71b1a0..5b3345010 100644 --- a/src/docs/core-config.txt +++ b/src/docs/core-config.txt @@ -1,10 +1,3 @@ -wp-core-config(1) -- Create a wp-config.php file. -==== - -## SYNOPSIS - -`wp core config` --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=localhost] [--dbprefix=wp_] - ## OPTIONS * `--dbname`=<dbname>: diff --git a/src/docs/core-download.txt b/src/docs/core-download.txt index 7fbaee097..6b85fc3af 100644 --- a/src/docs/core-download.txt +++ b/src/docs/core-download.txt @@ -1,10 +1,3 @@ -wp-core-download(1) -- Download core WordPress files. -==== - -## SYNOPSIS - -`wp core download` [--locale=<locale>] [--version=<version>] - ## OPTIONS * `--locale`=<locale>: diff --git a/src/docs/core-install-network.txt b/src/docs/core-install-network.txt index 74fe22d98..86db38741 100644 --- a/src/docs/core-install-network.txt +++ b/src/docs/core-install-network.txt @@ -1,11 +1,3 @@ -wp-core-install-network(1) -- Transform a single-site install into a -multi-site install. -==== - -## SYNOPSIS - -`wp core install-network` --title=<network-title> [--base_path=<url-path>] - ## OPTIONS * `--title`=<site-title>: diff --git a/src/docs/core-install.txt b/src/docs/core-install.txt index 8f65a9a00..711410e55 100644 --- a/src/docs/core-install.txt +++ b/src/docs/core-install.txt @@ -1,10 +1,3 @@ -wp-core-install(1) -- Install the WordPress tables in the database. -==== - -## SYNOPSIS - -`wp core install` --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> - ## OPTIONS * `--url`=<url>: diff --git a/src/docs/core-update-db.txt b/src/docs/core-update-db.txt deleted file mode 100644 index b199312fd..000000000 --- a/src/docs/core-update-db.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-core-update-db(1) -- Update the WordPress database. -==== - -## SYNOPSIS - -`wp core update-db` diff --git a/src/docs/core-update.txt b/src/docs/core-update.txt index abdc56e07..50caa5f2e 100644 --- a/src/docs/core-update.txt +++ b/src/docs/core-update.txt @@ -1,10 +1,3 @@ -wp-core-update(1) -- Update WordPress to the latest version. -==== - -## SYNOPSIS - -`wp core update` [--version=<new_version>] [--force] [<package/zip>] - ## OPTIONS * `--version=`<new_version> [package/zip]: diff --git a/src/docs/core-version.txt b/src/docs/core-version.txt index ecbdc4d48..d1c5d6a6d 100644 --- a/src/docs/core-version.txt +++ b/src/docs/core-version.txt @@ -1,10 +1,3 @@ -wp-core-version(1) -- Show the WordPress version. -==== - -## SYNOPSIS - -`wp core version` [--extra] - ## OPTIONS * `--extra`: diff --git a/src/docs/db-cli.txt b/src/docs/db-cli.txt deleted file mode 100644 index 10753c08b..000000000 --- a/src/docs/db-cli.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-db-cli(1) -- Open a SQL command-line interface to the WordPress database. -==== - -## SYNOPSIS - -`wp db cli` diff --git a/src/docs/db-connect.txt b/src/docs/db-connect.txt deleted file mode 100644 index b724452e1..000000000 --- a/src/docs/db-connect.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-db-connect(1) -- Print a string for connecting to the database. -==== - -## SYNOPSIS - -`wp db connect` diff --git a/src/docs/db-create.txt b/src/docs/db-create.txt deleted file mode 100644 index 27a6b7c74..000000000 --- a/src/docs/db-create.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-db-create(1) -- Create a database using the credentials from wp-config.php. -==== - -## SYNOPSIS - -`wp db create` diff --git a/src/docs/db-drop.txt b/src/docs/db-drop.txt index 76f4266ca..f626d62dd 100644 --- a/src/docs/db-drop.txt +++ b/src/docs/db-drop.txt @@ -1,10 +1,3 @@ -wp-db-drop(1) -- Drop the database specified in wp-config.php -==== - -## SYNOPSIS - -`wp db drop` [--yes] - ## OPTIONS * `--yes`: diff --git a/src/docs/db-export.txt b/src/docs/db-export.txt index c5019c2af..cce48dc75 100644 --- a/src/docs/db-export.txt +++ b/src/docs/db-export.txt @@ -1,10 +1,3 @@ -wp-db-export(1) -- Export the WordPress database using mysqldump. -==== - -## SYNOPSIS - -`wp db export` [<file>] - ## OPTIONS * `<file>`: diff --git a/src/docs/db-import.txt b/src/docs/db-import.txt index a0e65c2b9..5770c0b1c 100644 --- a/src/docs/db-import.txt +++ b/src/docs/db-import.txt @@ -1,10 +1,3 @@ -wp-db-import(1) -- Import a database from a text file. -==== - -## SYNOPSIS - -`wp db import` [<file>] - ## OPTIONS * `<file>`: diff --git a/src/docs/db-optimize.txt b/src/docs/db-optimize.txt deleted file mode 100644 index bd640f7f6..000000000 --- a/src/docs/db-optimize.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-db-optimize(1) -- Optimize the database specified in the wp-config.php file. -==== - -## SYNOPSIS - -`wp db optimize` diff --git a/src/docs/db-query.txt b/src/docs/db-query.txt index b4e986ba2..7d44ae675 100644 --- a/src/docs/db-query.txt +++ b/src/docs/db-query.txt @@ -1,10 +1,3 @@ -wp-db-query(1) -- Execute a query against the WordPress database. -==== - -## SYNOPSIS - -`wp db query` <SQL> - ## OPTIONS * `<SQL>`: diff --git a/src/docs/db-repair.txt b/src/docs/db-repair.txt deleted file mode 100644 index e882046c4..000000000 --- a/src/docs/db-repair.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-db-repair(1) -- Optimize the database specified in the wp-config.php file. -==== - -## SYNOPSIS - -`wp db repair` diff --git a/src/docs/db-reset.txt b/src/docs/db-reset.txt index 8ba5a5ed5..f626d62dd 100644 --- a/src/docs/db-reset.txt +++ b/src/docs/db-reset.txt @@ -1,10 +1,3 @@ -wp-db-reset(1) -- Remove all data from the database specified in wp-config.php -==== - -## SYNOPSIS - -`wp db reset` [--yes] - ## OPTIONS * `--yes`: diff --git a/src/docs/eval-file.txt b/src/docs/eval-file.txt index 47e6764bc..57a808c10 100644 --- a/src/docs/eval-file.txt +++ b/src/docs/eval-file.txt @@ -1,10 +1,3 @@ -wp-eval-file(1) -- Loads and executes a PHP file after loading WordPress. -==== - -## SYNOPSIS - -`wp eval-file` <file> - ## EXAMPLES wp eval-file my-code.php diff --git a/src/docs/eval.txt b/src/docs/eval.txt index 97db070a9..699b93f2e 100644 --- a/src/docs/eval.txt +++ b/src/docs/eval.txt @@ -1,10 +1,3 @@ -wp-eval(1) -- Executes arbitrary PHP code after loading WordPress. -==== - -## SYNOPSIS - -`wp eval` <PHP> - ## EXAMPLES wp eval 'echo WP_CONTENT_DIR;' diff --git a/src/docs/export.txt b/src/docs/export.txt index 1aafbc5b1..582a983cb 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -1,10 +1,3 @@ -wp-export(1) -- Create a WXR file. -==== - -## SYNOPSIS - -`wp export` --dir=<dirname> [filters] [--skip_comments] - ## OPTIONS * `--dir`=<dirname>: diff --git a/src/docs/home.txt b/src/docs/home.txt deleted file mode 100644 index 32d55a279..000000000 --- a/src/docs/home.txt +++ /dev/null @@ -1,6 +0,0 @@ -wp-home(1) -- Opens the wp-cli homepage in your browser. -==== - -## SYNOPSIS - -`wp home` diff --git a/src/docs/plugin-activate.txt b/src/docs/plugin-activate.txt index b7207bf81..555833891 100644 --- a/src/docs/plugin-activate.txt +++ b/src/docs/plugin-activate.txt @@ -1,10 +1,3 @@ -wp-plugin-activate(1) -- Activate an installed plugin. -==== - -## SYNOPSIS - -`wp plugin activate` <plugin> [--network] - ## OPTIONS * `<plugin>`: diff --git a/src/docs/plugin-deactivate.txt b/src/docs/plugin-deactivate.txt index d114fafed..12be8084c 100644 --- a/src/docs/plugin-deactivate.txt +++ b/src/docs/plugin-deactivate.txt @@ -1,10 +1,3 @@ -wp-plugin-deactivate(1) -- Deactivate an active plugin. -==== - -## SYNOPSIS - -`wp plugin deactivate` <plugin> [--network] - ## OPTIONS * `<plugin>`: diff --git a/src/docs/plugin-delete.txt b/src/docs/plugin-delete.txt index e36d303fe..111865f59 100644 --- a/src/docs/plugin-delete.txt +++ b/src/docs/plugin-delete.txt @@ -1,10 +1,3 @@ -wp-plugin-delete(1) -- Delete a plugin's files, without removing it's data. -==== - -## SYNOPSIS - -`wp plugin delete` <plugin> - ## OPTIONS * <plugin>: diff --git a/src/docs/plugin-install.txt b/src/docs/plugin-install.txt index e39aadedb..90f951721 100644 --- a/src/docs/plugin-install.txt +++ b/src/docs/plugin-install.txt @@ -1,10 +1,3 @@ -wp-plugin-install(1) -- Install a plugin from wordpress.org or from a zip file. -==== - -## SYNOPSIS - -`wp plugin install` <plugin/zip> [--version=<version>] [--activate] - ## OPTIONS * <plugin>: diff --git a/src/docs/plugin-path.txt b/src/docs/plugin-path.txt index 08e804aa1..6f05ac23b 100644 --- a/src/docs/plugin-path.txt +++ b/src/docs/plugin-path.txt @@ -1,10 +1,3 @@ -wp-plugin-path(1) -- Get the path to a plugin or to the plugin directory. -==== - -## SYNOPSIS - -`wp plugin path` [<plugin>] [--dir] - ## OPTIONS * `<plugin>`: diff --git a/src/docs/plugin-status.txt b/src/docs/plugin-status.txt index 5ee1022dc..daf14a99e 100644 --- a/src/docs/plugin-status.txt +++ b/src/docs/plugin-status.txt @@ -1,10 +1,3 @@ -wp-plugin-status(1) -- See the status of one or all plugins. -==== - -## SYNOPSIS - -`wp plugin status` [<plugin>] - ## OPTIONS * `<plugin>`: diff --git a/src/docs/plugin-toggle.txt b/src/docs/plugin-toggle.txt index 07c243ea2..97e284aed 100644 --- a/src/docs/plugin-toggle.txt +++ b/src/docs/plugin-toggle.txt @@ -1,10 +1,3 @@ -wp-plugin-deactivate(1) -- Activate/Deactivate an installed plugin. -==== - -## SYNOPSIS - -`wp plugin toggle` <plugin> [--network] - ## OPTIONS * `<plugin>`: diff --git a/src/docs/plugin-uninstall.txt b/src/docs/plugin-uninstall.txt index d0783f3dd..ea41bcbf1 100644 --- a/src/docs/plugin-uninstall.txt +++ b/src/docs/plugin-uninstall.txt @@ -1,10 +1,3 @@ -wp-plugin-uninstall(1) -- Run the uninstallation procedure for a plugin. -==== - -## SYNOPSIS - -`wp plugin uninstall` <plugin> [--no-delete] - ## OPTIONS * <plugin>: diff --git a/src/docs/plugin-update.txt b/src/docs/plugin-update.txt index 4be28128b..8bc68da0d 100644 --- a/src/docs/plugin-update.txt +++ b/src/docs/plugin-update.txt @@ -1,10 +1,3 @@ -wp-plugin-update(1) -- Update an installed plugin. -==== - -## SYNOPSIS - -`wp plugin update` [<plugin>] [--all] [--version=dev] - ## OPTIONS * <plugin>: diff --git a/src/docs/post-create.txt b/src/docs/post-create.txt index 467f30501..75c4de21f 100644 --- a/src/docs/post-create.txt +++ b/src/docs/post-create.txt @@ -1,10 +1,3 @@ -wp-post-create(1) -- Create a new WordPress post. -==== - -## SYNOPSIS - -`wp post create` --<field>=<value> [--<field>=<value>...] [--porcelain] - ## OPTIONS * `--<field>`=<value>: diff --git a/src/docs/post-delete.txt b/src/docs/post-delete.txt index 21ce192f6..7deed7050 100644 --- a/src/docs/post-delete.txt +++ b/src/docs/post-delete.txt @@ -1,10 +1,3 @@ -wp-post-delete(1) -- Delete one or several posts by ID. -==== - -## SYNOPSIS - -`wp post delete` <ID>... [--force] - ## OPTIONS * `<ID>`: diff --git a/src/docs/post-generate.txt b/src/docs/post-generate.txt index 3b5e282b2..cab9b591f 100644 --- a/src/docs/post-generate.txt +++ b/src/docs/post-generate.txt @@ -1,11 +1,3 @@ -wp-post-generate(1) -- Generate a bunch of posts. -==== - -## SYNOPSIS - -`wp post generate` [--count=100] [--post_type=post] [--post_status=publish] -[--post_author=<login>] [--post_date=<date>] [--max_depth=1] - ## OPTIONS * `--count`=<number>: diff --git a/src/docs/post-list.txt b/src/docs/post-list.txt index de04f98ea..295f102c0 100644 --- a/src/docs/post-list.txt +++ b/src/docs/post-list.txt @@ -1,10 +1,3 @@ -wp-post-list(1) -- Get a list of posts. -==== - -## SYNOPSIS - -`wp post list` --<field>=<value> [--<field>=<value>...] [--ids] - ## OPTIONS * `--<field>`=<value>: diff --git a/src/docs/post-update.txt b/src/docs/post-update.txt index 53a454859..0fd825e24 100644 --- a/src/docs/post-update.txt +++ b/src/docs/post-update.txt @@ -1,10 +1,3 @@ -wp-post-update(1) -- Update a WordPress post. -==== - -## SYNOPSIS - -`wp post update` <ID> --<field>=<value> [--<field>=<value>...] - ## OPTIONS * `<ID>`: diff --git a/src/docs/rewrite-dump.txt b/src/docs/rewrite-dump.txt index 2a39b8527..26498dbca 100644 --- a/src/docs/rewrite-dump.txt +++ b/src/docs/rewrite-dump.txt @@ -1,10 +1,3 @@ -rewrite-dump(1) -- Print current rewrite rules to STDOUT. -==== - -## SYNOPSIS - -`wp rewrite dump` [--json] - ## OPTIONS * `--json`: diff --git a/src/docs/rewrite-flush.txt b/src/docs/rewrite-flush.txt index e7d11dd39..60ae94af8 100644 --- a/src/docs/rewrite-flush.txt +++ b/src/docs/rewrite-flush.txt @@ -1,10 +1,3 @@ -rewrite-flush(1) -- Flush rewrite rules. -==== - -## SYNOPSIS - -`wp rewrite flush` [--soft] - ## OPTIONS * `--soft`: diff --git a/src/docs/rewrite-structure.txt b/src/docs/rewrite-structure.txt index 8e77ea39d..9dec9d860 100644 --- a/src/docs/rewrite-structure.txt +++ b/src/docs/rewrite-structure.txt @@ -1,10 +1,3 @@ -rewrite-structure(1) -- Update the permalink structure -==== - -## SYNOPSIS - -`wp rewrite structure` <permastruct> [--category-base=<categorybase>] [--tag-base=<tagbase>] - ## OPTIONS * <permastruct>: diff --git a/src/docs/theme-activate.txt b/src/docs/theme-activate.txt index 24a492d71..c74047240 100644 --- a/src/docs/theme-activate.txt +++ b/src/docs/theme-activate.txt @@ -1,10 +1,3 @@ -wp-theme-activate(1) -- Activate an installed theme. -==== - -## SYNOPSIS - -`wp theme activate` <theme> - ## OPTIONS * `<theme>`: diff --git a/src/docs/theme-delete.txt b/src/docs/theme-delete.txt index 94fa90cca..22506747b 100644 --- a/src/docs/theme-delete.txt +++ b/src/docs/theme-delete.txt @@ -1,10 +1,3 @@ -wp-theme-delete(1) -- Delete a theme. -==== - -## SYNOPSIS - -`wp theme delete` <theme> - ## OPTIONS * <theme>: diff --git a/src/docs/theme-install.txt b/src/docs/theme-install.txt index df18a80e1..28e26a342 100644 --- a/src/docs/theme-install.txt +++ b/src/docs/theme-install.txt @@ -1,10 +1,3 @@ -wp-theme-install(1) -- Install a theme from wordpress.org or from a zip file. -==== - -## SYNOPSIS - -`wp theme install` <theme/zip> [--activate] - ## OPTIONS * <theme>: diff --git a/src/docs/theme-path.txt b/src/docs/theme-path.txt index 32bb5c876..9b87d9699 100644 --- a/src/docs/theme-path.txt +++ b/src/docs/theme-path.txt @@ -1,10 +1,3 @@ -wp-theme-path(1) -- Get the path to a theme or to the theme directory. -==== - -## SYNOPSIS - -`wp theme path` [<theme>] [--dir] - ## OPTIONS * `<theme>`: diff --git a/src/docs/theme-status.txt b/src/docs/theme-status.txt index 48b5dfe14..f4aa71335 100644 --- a/src/docs/theme-status.txt +++ b/src/docs/theme-status.txt @@ -1,10 +1,3 @@ -wp-theme-status(1) -- See the status of one or all themes. -==== - -## SYNOPSIS - -`wp theme status` [<theme>] - ## OPTIONS * `<theme>`: diff --git a/src/docs/theme-update.txt b/src/docs/theme-update.txt index e6f5c5e01..9c37f8229 100644 --- a/src/docs/theme-update.txt +++ b/src/docs/theme-update.txt @@ -1,10 +1,3 @@ -wp-theme-update(1) -- Update an installed theme. -==== - -## SYNOPSIS - -`wp theme update` [<theme>] [--all] - ## OPTIONS * <theme>: diff --git a/src/docs/user-create.txt b/src/docs/user-create.txt index 0ed2e2214..6ba889ece 100644 --- a/src/docs/user-create.txt +++ b/src/docs/user-create.txt @@ -1,10 +1,3 @@ -wp-user-create(1) -- Create a new WordPress user. -==== - -## SYNOPSIS - -`wp user create` <user-login> <user-email> [--role=<role>] [--porcelain] - ## OPTIONS * `<user-login>`: diff --git a/src/docs/user-delete.txt b/src/docs/user-delete.txt index 6d8832c6c..920282f7e 100644 --- a/src/docs/user-delete.txt +++ b/src/docs/user-delete.txt @@ -1,10 +1,3 @@ -wp-user-delete(1) -- Delete a WordPress user. -==== - -## SYNOPSIS - -`wp user delete` <ID> [--reassign=<ID>] - ## OPTIONS * `<ID>`: diff --git a/src/docs/user-generate.txt b/src/docs/user-generate.txt index 52885be9f..a2467abf0 100644 --- a/src/docs/user-generate.txt +++ b/src/docs/user-generate.txt @@ -1,10 +1,3 @@ -wp-user-generate(1) -- Generate a bunch of users. -==== - -## SYNOPSIS - -`wp user generate` [--count=100] [--role=<role>] - ## OPTIONS * `--count`=<number>: diff --git a/src/docs/user-list.txt b/src/docs/user-list.txt index 32b88daad..631b84e28 100644 --- a/src/docs/user-list.txt +++ b/src/docs/user-list.txt @@ -1,10 +1,3 @@ -wp-user-list(1) -- List WordPress users. -==== - -## SYNOPSIS - -`wp user list` [--role=<role>] - ## OPTIONS * `--role`=<role>: diff --git a/src/docs/user-update.txt b/src/docs/user-update.txt index ca46b7e4e..9a93a9f81 100644 --- a/src/docs/user-update.txt +++ b/src/docs/user-update.txt @@ -1,10 +1,3 @@ -wp-user-update(1) -- Update a WordPress user. -==== - -## SYNOPSIS - -`wp user update` <ID> --<field>=<value> [--<field>=<value>...] - ## OPTIONS * `<ID>`: From 1823fc702b78e91c7ed9433028e5195bf4143208 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 05:04:44 +0300 Subject: [PATCH 0707/5359] extract add_initial_markdown() procedure --- src/php/wp-cli/man.php | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index daee08c69..4afc61321 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -8,8 +8,8 @@ function get_path( $args ) { return WP_CLI_ROOT . "../../../man/" . implode( '-', $args ) . '.1'; } -function get_doc_path() { - return WP_CLI_ROOT . "../../docs/"; +function get_doc_path( $args ) { + return WP_CLI_ROOT . "../../docs/" . implode( '-', $args ) . '.txt'; } function generate( $command ) { @@ -33,6 +33,21 @@ function generate( $command ) { // returns a file descriptor containing markdown that will be passed to ronn function get_markdown( Dispatcher\Documentable $command ) { + $fd = fopen( "php://temp", "rw" ); + + add_initial_markdown( $fd, $command ); + + $doc_path = get_doc_path( $command->get_path() ); + + if ( file_exists( $doc_path ) ) + fwrite( $fd, file_get_contents( $doc_path ) ); + + fseek( $fd, 0 ); + + return $fd; +} + +function add_initial_markdown( $fd, Dispatcher\Documentable $command ) { $path = $command->get_path(); $shortdesc = $command->get_shortdesc(); $synopsis = $command->get_synopsis(); @@ -46,9 +61,7 @@ function get_markdown( Dispatcher\Documentable $command ) { \WP_CLI::warning( "No shortdesc for $name_s" ); } - $temp = fopen( "php://temp", "rw" ); - - fwrite( $temp, <<<DOC + fwrite( $fd, <<<DOC wp-$name_m(1) -- $shortdesc ==== @@ -58,14 +71,5 @@ function get_markdown( Dispatcher\Documentable $command ) { DOC ); - - $doc_path = get_doc_path() . "$name_m.txt"; - - if ( file_exists( $doc_path ) ) - fwrite( $temp, file_get_contents( $doc_path ) ); - - fseek( $temp, 0 ); - - return $temp; } From 2718319374d01b7349129049257ef4aff9831a14 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 05:28:48 +0300 Subject: [PATCH 0708/5359] extract call_ronn() procedure --- src/php/wp-cli/man.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 4afc61321..6b310fab2 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -8,7 +8,7 @@ function get_path( $args ) { return WP_CLI_ROOT . "../../../man/" . implode( '-', $args ) . '.1'; } -function get_doc_path( $args ) { +function get_src_path( $args ) { return WP_CLI_ROOT . "../../docs/" . implode( '-', $args ) . '.txt'; } @@ -20,15 +20,19 @@ function generate( $command ) { return; } + call_ronn( get_markdown( $command ), get_path( $command->get_path() ) ); +} + +function call_ronn( $markdown, $dest ) { $descriptorspec = array( - 0 => get_markdown( $command ), - 1 => array( 'file', get_path( $command->get_path() ), 'w' ), + 0 => $markdown, + 1 => array( 'file', $dest, 'w' ), 2 => STDERR ); $r = proc_close( proc_open( "ronn --roff --manual='WP-CLI'", $descriptorspec, $pipes ) ); - \WP_CLI::line( "generated man page for " . implode( '-', $command->get_path() ) ); + \WP_CLI::line( "generated " . basename( $dest ) ); } // returns a file descriptor containing markdown that will be passed to ronn @@ -37,7 +41,7 @@ function get_markdown( Dispatcher\Documentable $command ) { add_initial_markdown( $fd, $command ); - $doc_path = get_doc_path( $command->get_path() ); + $doc_path = get_src_path( $command->get_path() ); if ( file_exists( $doc_path ) ) fwrite( $fd, file_get_contents( $doc_path ) ); From 71e67cfe7e02f351dd074b475d5ac9bf987367de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 05:35:05 +0300 Subject: [PATCH 0709/5359] call ronn for top level commands too --- src/php/wp-cli/man.php | 44 ++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 6b310fab2..379f09c6e 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -13,45 +13,36 @@ function get_src_path( $args ) { } function generate( $command ) { + call_ronn( get_markdown( $command ), get_path( $command->get_path() ) ); + if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) { generate( $subcommand ); } - return; } - - call_ronn( get_markdown( $command ), get_path( $command->get_path() ) ); -} - -function call_ronn( $markdown, $dest ) { - $descriptorspec = array( - 0 => $markdown, - 1 => array( 'file', $dest, 'w' ), - 2 => STDERR - ); - - $r = proc_close( proc_open( "ronn --roff --manual='WP-CLI'", $descriptorspec, $pipes ) ); - - \WP_CLI::line( "generated " . basename( $dest ) ); } -// returns a file descriptor containing markdown that will be passed to ronn -function get_markdown( Dispatcher\Documentable $command ) { +// returns a file descriptor or false +function get_markdown( $command ) { $fd = fopen( "php://temp", "rw" ); - add_initial_markdown( $fd, $command ); + if ( $command instanceof Dispatcher\Documentable ) + add_initial_markdown( $fd, $command ); $doc_path = get_src_path( $command->get_path() ); if ( file_exists( $doc_path ) ) fwrite( $fd, file_get_contents( $doc_path ) ); + if ( 0 === ftell( $fd ) ) + return false; + fseek( $fd, 0 ); return $fd; } -function add_initial_markdown( $fd, Dispatcher\Documentable $command ) { +function add_initial_markdown( $fd, $command ) { $path = $command->get_path(); $shortdesc = $command->get_shortdesc(); $synopsis = $command->get_synopsis(); @@ -77,3 +68,18 @@ function add_initial_markdown( $fd, Dispatcher\Documentable $command ) { ); } +function call_ronn( $markdown, $dest ) { + if ( !$markdown ) + return; + + $descriptorspec = array( + 0 => $markdown, + 1 => array( 'file', $dest, 'w' ), + 2 => STDERR + ); + + $r = proc_close( proc_open( "ronn --roff --manual='WP-CLI'", $descriptorspec, $pipes ) ); + + \WP_CLI::line( "generated " . basename( $dest ) ); +} + From 41895dae5e02d5936f01aa40e4969e58696bef9d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 06:40:34 +0300 Subject: [PATCH 0710/5359] remove \WP_CLI\ prefix --- src/php/wp-cli/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8b259bb44..31cff1fbb 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -19,9 +19,9 @@ class WP_CLI { */ public function add_command( $name, $class ) { if ( is_string( $class ) ) - $command = new \WP_CLI\Dispatcher\CompositeCommand( $name, $class ); + $command = new Dispatcher\CompositeCommand( $name, $class ); else - $command = new \WP_CLI\Dispatcher\SingleCommand( $name, $class ); + $command = new Dispatcher\SingleCommand( $name, $class ); self::$commands[ $name ] = $command; } From 7bb3ecacb860b05e1a6c8da7d71ab59332c2eb40 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 25 Oct 2012 07:00:33 +0300 Subject: [PATCH 0711/5359] finish shortdesc at newline, instead of dot. see #187 --- man/core-config.1 | 2 +- man/db-create.1 | 2 +- src/php/wp-cli/commands/internals/db.php | 2 +- src/php/wp-cli/dispatcher.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/core-config.1 b/man/core-config.1 index e1f2260b7..adb58494c 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -4,7 +4,7 @@ .TH "WP\-CORE\-CONFIG" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-core\-config\fR \- Set up a wp\-config\. +\fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. . .SH "SYNOPSIS" \fBwp core config\fR \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] diff --git a/man/db-create.1 b/man/db-create.1 index eac9c4b54..4c94095c8 100644 --- a/man/db-create.1 +++ b/man/db-create.1 @@ -4,7 +4,7 @@ .TH "WP\-DB\-CREATE" "1" "October 2012" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\-create\fR \- Create the database\. +\fBwp\-db\-create\fR \- Create the database, as specified in wp\-config\.php . .SH "SYNOPSIS" \fBwp db create\fR diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 12f6918a0..72c27d201 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -15,7 +15,7 @@ public static function get_default_subcommand() { } /** - * Create the database. + * Create the database, as specified in wp-config.php */ function create() { WP_CLI::launch( self::create_cmd( diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 9a12b6807..a825a6c7b 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -297,7 +297,7 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { function get_shortdesc() { $comment = $this->method->getDocComment(); - if ( !preg_match( '/\* ([^@\.]+\.)\s*/', $comment, $matches ) ) + if ( !preg_match( '/\* (\w.+)\n*/', $comment, $matches ) ) return false; return $matches[1]; From a431978318b73170f1d8c00c170fb3bfdada3a81 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Oct 2012 16:30:47 -0400 Subject: [PATCH 0712/5359] fix --path handling --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 31cff1fbb..a227cd7af 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -240,7 +240,7 @@ static function before_wp_load() { // Define the WordPress location if ( !empty( self::$assoc_special['path'] ) ) { // trailingslashit() isn't available yet - define( 'WP_ROOT', rtrim( self::$assoc_args['path'], '/' ) . '/' ); + define( 'WP_ROOT', rtrim( self::$assoc_special['path'], '/' ) . '/' ); } else { define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); } From c200b42a4f814a845dc8f132e1b5956be09d4e4d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 14:40:18 -0400 Subject: [PATCH 0713/5359] correctly mark add_command() as static. fixes #193 --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index a227cd7af..927803ed6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -17,7 +17,7 @@ class WP_CLI { * @param string $name The name of the command that will be used in the cli * @param string $class The class to manage the command */ - public function add_command( $name, $class ) { + static function add_command( $name, $class ) { if ( is_string( $class ) ) $command = new Dispatcher\CompositeCommand( $name, $class ); else From d0f5d8cae1b0c0e7fe403c3a96918edaf12e5bfc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 15:56:46 -0400 Subject: [PATCH 0714/5359] first pass at wp repl --- src/php/wp-cli/commands/internals/repl.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/repl.php diff --git a/src/php/wp-cli/commands/internals/repl.php b/src/php/wp-cli/commands/internals/repl.php new file mode 100644 index 000000000..49e3ce028 --- /dev/null +++ b/src/php/wp-cli/commands/internals/repl.php @@ -0,0 +1,20 @@ +<?php + +WP_CLI::add_command( 'repl', new Repl_Command ); + +class Repl_Command extends WP_CLI_Command { + + /** + * Open an interactive shell environment. + */ + public function __invoke() { + while ( true ) { + WP_CLI::out( 'wp> ' ); + + $in = \cli\input(); + + echo eval( $in ); + } + } +} + From 41fa520d1c0542067a84493b3ff04fba9f574d25 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 15:57:25 -0400 Subject: [PATCH 0715/5359] make 'exit' exit --- src/php/wp-cli/commands/internals/repl.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/commands/internals/repl.php b/src/php/wp-cli/commands/internals/repl.php index 49e3ce028..3571aa20d 100644 --- a/src/php/wp-cli/commands/internals/repl.php +++ b/src/php/wp-cli/commands/internals/repl.php @@ -13,6 +13,9 @@ public function __invoke() { $in = \cli\input(); + if ( 'exit' == $in ) + return; + echo eval( $in ); } } From 01719e33ecfd767a22c34a47351a12a8f0e51a51 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 16:12:32 -0400 Subject: [PATCH 0716/5359] fix "Object of class stdClass could not be converted to string" --- src/php/wp-cli/commands/internals/repl.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/repl.php b/src/php/wp-cli/commands/internals/repl.php index 3571aa20d..996d09aca 100644 --- a/src/php/wp-cli/commands/internals/repl.php +++ b/src/php/wp-cli/commands/internals/repl.php @@ -16,7 +16,12 @@ public function __invoke() { if ( 'exit' == $in ) return; - echo eval( $in ); + $r = eval( $in ); + + if ( null === $r ) + WP_CLI::line(); + else + var_export( $r ); } } } From d624c9a041db489029cb634f0f754ce39cf6f521 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 16:47:45 -0400 Subject: [PATCH 0717/5359] update version of php-cli-tools --- src/php/php-cli-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools index c23ffe979..7af88b487 160000 --- a/src/php/php-cli-tools +++ b/src/php/php-cli-tools @@ -1 +1 @@ -Subproject commit c23ffe979c7956614fd8721c2e28e61a3cb6bad3 +Subproject commit 7af88b48747da17d95db6af8d00c51af5c5e104c From f68db53615b2e49a0d21643e0a483e70a37b3bd7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 17:28:08 -0400 Subject: [PATCH 0718/5359] rename wp repl to wp interactive --- .../wp-cli/commands/internals/{repl.php => interactive.php} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/php/wp-cli/commands/internals/{repl.php => interactive.php} (72%) diff --git a/src/php/wp-cli/commands/internals/repl.php b/src/php/wp-cli/commands/internals/interactive.php similarity index 72% rename from src/php/wp-cli/commands/internals/repl.php rename to src/php/wp-cli/commands/internals/interactive.php index 996d09aca..5c9223491 100644 --- a/src/php/wp-cli/commands/internals/repl.php +++ b/src/php/wp-cli/commands/internals/interactive.php @@ -1,8 +1,8 @@ <?php -WP_CLI::add_command( 'repl', new Repl_Command ); +WP_CLI::add_command( 'interactive', new Interactive_Command ); -class Repl_Command extends WP_CLI_Command { +class Interactive_Command extends WP_CLI_Command { /** * Open an interactive shell environment. From d17da49bf7e8790de797e268369fc178c5b7d202 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 17:29:03 -0400 Subject: [PATCH 0719/5359] use readline(), if it's available --- .../wp-cli/commands/internals/interactive.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/interactive.php b/src/php/wp-cli/commands/internals/interactive.php index 5c9223491..61478e3d8 100644 --- a/src/php/wp-cli/commands/internals/interactive.php +++ b/src/php/wp-cli/commands/internals/interactive.php @@ -9,9 +9,7 @@ class Interactive_Command extends WP_CLI_Command { */ public function __invoke() { while ( true ) { - WP_CLI::out( 'wp> ' ); - - $in = \cli\input(); + $in = $this->read_input(); if ( 'exit' == $in ) return; @@ -24,5 +22,17 @@ public function __invoke() { var_export( $r ); } } + + private function read_input() { + if ( function_exists( 'readline' ) ) { + $line = readline( 'wp> ' ); + readline_add_history( $line ); + } else { + WP_CLI::out( 'wp> ' ); + $line = \cli\input(); + } + + return $line; + } } From 38be9492cb963f36c67309fefdb84cadc48d14c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 17:29:38 -0400 Subject: [PATCH 0720/5359] output nothing on fatal errors --- src/php/wp-cli/commands/internals/interactive.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/commands/internals/interactive.php b/src/php/wp-cli/commands/internals/interactive.php index 61478e3d8..d06e41579 100644 --- a/src/php/wp-cli/commands/internals/interactive.php +++ b/src/php/wp-cli/commands/internals/interactive.php @@ -16,6 +16,9 @@ public function __invoke() { $r = eval( $in ); + if ( false === $r ) + continue; + if ( null === $r ) WP_CLI::line(); else From ab02ad41259152fdda5e046f4c63ac4a7903aca9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 17:53:45 -0400 Subject: [PATCH 0721/5359] run function_exists( 'readline' ) only once --- .../wp-cli/commands/internals/interactive.php | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/commands/internals/interactive.php b/src/php/wp-cli/commands/internals/interactive.php index d06e41579..14cf35301 100644 --- a/src/php/wp-cli/commands/internals/interactive.php +++ b/src/php/wp-cli/commands/internals/interactive.php @@ -1,15 +1,23 @@ <?php -WP_CLI::add_command( 'interactive', new Interactive_Command ); +namespace WP_CLI\Commands; -class Interactive_Command extends WP_CLI_Command { +\WP_CLI::add_command( 'interactive', new Interactive_Command ); + +class Interactive_Command extends \WP_CLI_Command { /** * Open an interactive shell environment. */ public function __invoke() { + if ( function_exists( 'readline' ) ) { + $repl = new REPL_Readline; + } else { + $repl = new REPL_Basic; + } + while ( true ) { - $in = $this->read_input(); + $in = $repl->prompt( 'wp> ' ); if ( 'exit' == $in ) return; @@ -20,22 +28,29 @@ public function __invoke() { continue; if ( null === $r ) - WP_CLI::line(); + \WP_CLI::line(); else var_export( $r ); } } +} - private function read_input() { - if ( function_exists( 'readline' ) ) { - $line = readline( 'wp> ' ); - readline_add_history( $line ); - } else { - WP_CLI::out( 'wp> ' ); - $line = \cli\input(); - } +class REPL_Readline { + + function prompt( $str ) { + $line = readline( $str ); + readline_add_history( $line ); return $line; } } + +class REPL_Basic { + + function prompt( $str ) { + \WP_CLI::out( $str ); + return \cli\input(); + } +} + From 7acfb595a43d31f3353dd6911ce6423693ffe3db Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 21:53:50 -0400 Subject: [PATCH 0722/5359] don't really need separate classes for the REPLs yet --- .../wp-cli/commands/internals/interactive.php | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/interactive.php b/src/php/wp-cli/commands/internals/interactive.php index 14cf35301..2c8035d80 100644 --- a/src/php/wp-cli/commands/internals/interactive.php +++ b/src/php/wp-cli/commands/internals/interactive.php @@ -1,23 +1,21 @@ <?php -namespace WP_CLI\Commands; +WP_CLI::add_command( 'interactive', new Interactive_Command ); -\WP_CLI::add_command( 'interactive', new Interactive_Command ); - -class Interactive_Command extends \WP_CLI_Command { +class Interactive_Command extends WP_CLI_Command { /** * Open an interactive shell environment. */ public function __invoke() { if ( function_exists( 'readline' ) ) { - $repl = new REPL_Readline; + $repl = 'repl_readline'; } else { - $repl = new REPL_Basic; + $repl = 'repl_basic'; } while ( true ) { - $in = $repl->prompt( 'wp> ' ); + $in = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); if ( 'exit' == $in ) return; @@ -33,22 +31,14 @@ public function __invoke() { var_export( $r ); } } -} - - -class REPL_Readline { - function prompt( $str ) { + private static function repl_readline( $str ) { $line = readline( $str ); readline_add_history( $line ); return $line; } -} - - -class REPL_Basic { - function prompt( $str ) { + private static function repl_basic( $str ) { \WP_CLI::out( $str ); return \cli\input(); } From f86425ea4f4f05a469996d2e96c6e647238d081a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 23:26:05 -0400 Subject: [PATCH 0723/5359] rename to wp shell --- .../wp-cli/commands/internals/{interactive.php => shell.php} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/php/wp-cli/commands/internals/{interactive.php => shell.php} (85%) diff --git a/src/php/wp-cli/commands/internals/interactive.php b/src/php/wp-cli/commands/internals/shell.php similarity index 85% rename from src/php/wp-cli/commands/internals/interactive.php rename to src/php/wp-cli/commands/internals/shell.php index 2c8035d80..c4e7f92ce 100644 --- a/src/php/wp-cli/commands/internals/interactive.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -1,8 +1,8 @@ <?php -WP_CLI::add_command( 'interactive', new Interactive_Command ); +WP_CLI::add_command( 'shell', new Shell_Command ); -class Interactive_Command extends WP_CLI_Command { +class Shell_Command extends WP_CLI_Command { /** * Open an interactive shell environment. From 36c97a2d7824938dcbc27c48be6294475413f505 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 23:34:01 -0400 Subject: [PATCH 0724/5359] automatically return all expressions --- src/php/wp-cli/commands/internals/shell.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index c4e7f92ce..a17c34263 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -20,6 +20,9 @@ public function __invoke() { if ( 'exit' == $in ) return; + if ( !preg_match( '/^\s*(echo|return)\s+/', $in ) ) + $in = 'return ' . $in; + $r = eval( $in ); if ( false === $r ) @@ -28,7 +31,7 @@ public function __invoke() { if ( null === $r ) \WP_CLI::line(); else - var_export( $r ); + \WP_CLI::line( var_export( $r, false ) ); } } From cd47b7e02cc36e0bc48d59e403de272aeac2ba9a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 23:34:35 -0400 Subject: [PATCH 0725/5359] automatically append ; --- src/php/wp-cli/commands/internals/shell.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index a17c34263..47e45cdc9 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -23,6 +23,8 @@ public function __invoke() { if ( !preg_match( '/^\s*(echo|return)\s+/', $in ) ) $in = 'return ' . $in; + $in .= ';'; + $r = eval( $in ); if ( false === $r ) From d5bc11b61b06fab3e913d13d319f9dd2fc19b537 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 23:39:26 -0400 Subject: [PATCH 0726/5359] make $_ the implicit variable --- src/php/wp-cli/commands/internals/shell.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 47e45cdc9..72e5776a4 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -25,15 +25,12 @@ public function __invoke() { $in .= ';'; - $r = eval( $in ); + $_ = eval( $in ); - if ( false === $r ) + if ( false === $_ ) continue; - if ( null === $r ) - \WP_CLI::line(); - else - \WP_CLI::line( var_export( $r, false ) ); + \WP_CLI::line( var_export( $_, false ) ); } } From 62ab4321101e57e3d597b807e9b23bdd7bab116d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Oct 2012 23:57:11 -0400 Subject: [PATCH 0727/5359] allow bringing global variables into the scope --- src/php/wp-cli/commands/internals/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 72e5776a4..02c3202b1 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -20,7 +20,7 @@ public function __invoke() { if ( 'exit' == $in ) return; - if ( !preg_match( '/^\s*(echo|return)\s+/', $in ) ) + if ( !preg_match( '/^\s*(global|echo|return)\s+/', $in ) ) $in = 'return ' . $in; $in .= ';'; From aded6e12dcf8d98c4a952a90809b84478cac8b94 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Oct 2012 00:03:30 -0400 Subject: [PATCH 0728/5359] rename $in to $line --- src/php/wp-cli/commands/internals/shell.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 02c3202b1..8a0ee53a0 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -15,17 +15,17 @@ public function __invoke() { } while ( true ) { - $in = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); + $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); - if ( 'exit' == $in ) + if ( 'exit' == $line ) return; - if ( !preg_match( '/^\s*(global|echo|return)\s+/', $in ) ) - $in = 'return ' . $in; + if ( !preg_match( '/^\s*(global|echo|return)\s+/', $line ) ) + $line = 'return ' . $line; - $in .= ';'; + $line .= ';'; - $_ = eval( $in ); + $_ = eval( $line ); if ( false === $_ ) continue; From 568f2d0f0f1e28be780165057f4bdf9ebc61dcb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Oct 2012 00:50:46 -0400 Subject: [PATCH 0729/5359] don't need the special case for 'exit' anymore --- src/php/wp-cli/commands/internals/shell.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 8a0ee53a0..f8c6d0f21 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -17,9 +17,6 @@ public function __invoke() { while ( true ) { $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); - if ( 'exit' == $line ) - return; - if ( !preg_match( '/^\s*(global|echo|return)\s+/', $line ) ) $line = 'return ' . $line; From 1f4b4a8cc5459bbd93f936728dd4930733069faf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Oct 2012 01:15:17 -0400 Subject: [PATCH 0730/5359] add support for more non-expressions --- src/php/wp-cli/commands/internals/shell.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index f8c6d0f21..25b5cd1ab 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -14,10 +14,19 @@ public function __invoke() { $repl = 'repl_basic'; } + $non_expressions = array( + 'echo', 'return', 'global', + 'while', 'for', 'foreach', 'if', 'switch', + 'include', 'include\_once', 'require', 'require\_once' + ); + $non_expressions = implode( '|', $non_expressions ); + + $pattern = "/^\s*($non_expressions)\s+/"; + while ( true ) { $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); - if ( !preg_match( '/^\s*(global|echo|return)\s+/', $line ) ) + if ( !preg_match( $pattern, $line ) ) $line = 'return ' . $line; $line .= ';'; From 2b19970de99a810c18d9d0d8137e75e7b2119b82 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Oct 2012 01:16:13 -0400 Subject: [PATCH 0731/5359] allow echo('whatever') syntax too --- src/php/wp-cli/commands/internals/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 25b5cd1ab..1f51ba85f 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -21,7 +21,7 @@ public function __invoke() { ); $non_expressions = implode( '|', $non_expressions ); - $pattern = "/^\s*($non_expressions)\s+/"; + $pattern = "/^\s*($non_expressions)[\(\s]+/"; while ( true ) { $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); From 87f5a63afc2e224b0547018afa31ecc3986e1b48 Mon Sep 17 00:00:00 2001 From: Adrian Palmer <adrian@navitronic.co.uk> Date: Tue, 30 Oct 2012 14:57:17 +1100 Subject: [PATCH 0732/5359] Fixed typo in unknown warning --- src/php/wp-cli/dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index a825a6c7b..83700435f 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -290,7 +290,7 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); foreach ( $unknown_assoc as $key ) { - \WP_CLI::warning( "unkown --$key parameter" ); + \WP_CLI::warning( "unknown --$key parameter" ); } } From ac96cf43777a83c0784e34c02e4aca4499df7c9c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 10:33:55 -0400 Subject: [PATCH 0733/5359] update to upstream version of php-cli-tools --- src/php/php-cli-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools index 7af88b487..eeddb2bbf 160000 --- a/src/php/php-cli-tools +++ b/src/php/php-cli-tools @@ -1 +1 @@ -Subproject commit 7af88b48747da17d95db6af8d00c51af5c5e104c +Subproject commit eeddb2bbfab974fb8b7f188f08156eee6b533c7d From 05d8b5231056b3438d87b0cfbecd3559c81770d4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 12:28:51 -0400 Subject: [PATCH 0734/5359] use \cli\Streams directly --- src/php/wp-cli/class-wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 927803ed6..f9a8522ec 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -33,7 +33,7 @@ static function add_command( $name, $class ) { */ static function out( $message ) { if ( WP_CLI_QUIET ) return; - \cli\out($message); + \cli\Streams::out($message); } /** @@ -43,7 +43,7 @@ static function out( $message ) { */ static function line( $message = '' ) { if ( WP_CLI_QUIET ) return; - \cli\line($message); + \cli\Streams::line($message); } /** @@ -54,7 +54,7 @@ static function line( $message = '' ) { */ static function error( $message, $label = 'Error' ) { if ( !isset( self::$assoc_special['completions'] ) ) { - \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); + \cli\Streams::err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); } exit(1); @@ -68,7 +68,7 @@ static function error( $message, $label = 'Error' ) { */ static function success( $message, $label = 'Success' ) { if ( WP_CLI_QUIET ) return; - \cli\line( '%G' . $label . ': %n' . $message ); + \cli\Streams::line( '%G' . $label . ': %n' . $message ); } /** @@ -79,7 +79,7 @@ static function success( $message, $label = 'Success' ) { */ static function warning( $message, $label = 'Warning' ) { if ( WP_CLI_QUIET ) return; - \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); + \cli\Streams::err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } /** From 6aceb578d7ae86698cd9c1f12682078e3561df4a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 13:26:22 -0400 Subject: [PATCH 0735/5359] Revert "use \cli\Streams directly" This reverts commit 05d8b5231056b3438d87b0cfbecd3559c81770d4. --- src/php/wp-cli/class-wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index f9a8522ec..927803ed6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -33,7 +33,7 @@ static function add_command( $name, $class ) { */ static function out( $message ) { if ( WP_CLI_QUIET ) return; - \cli\Streams::out($message); + \cli\out($message); } /** @@ -43,7 +43,7 @@ static function out( $message ) { */ static function line( $message = '' ) { if ( WP_CLI_QUIET ) return; - \cli\Streams::line($message); + \cli\line($message); } /** @@ -54,7 +54,7 @@ static function line( $message = '' ) { */ static function error( $message, $label = 'Error' ) { if ( !isset( self::$assoc_special['completions'] ) ) { - \cli\Streams::err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); + \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); } exit(1); @@ -68,7 +68,7 @@ static function error( $message, $label = 'Error' ) { */ static function success( $message, $label = 'Success' ) { if ( WP_CLI_QUIET ) return; - \cli\Streams::line( '%G' . $label . ': %n' . $message ); + \cli\line( '%G' . $label . ': %n' . $message ); } /** @@ -79,7 +79,7 @@ static function success( $message, $label = 'Success' ) { */ static function warning( $message, $label = 'Warning' ) { if ( WP_CLI_QUIET ) return; - \cli\Streams::err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); + \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); } /** From ebe75d82c96aea478e7e429c1cd8b60b8064d8bf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 13:36:12 -0400 Subject: [PATCH 0736/5359] use fix from php-cli-tools. see #195 --- src/php/php-cli-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools index eeddb2bbf..f2abf5015 160000 --- a/src/php/php-cli-tools +++ b/src/php/php-cli-tools @@ -1 +1 @@ -Subproject commit eeddb2bbfab974fb8b7f188f08156eee6b533c7d +Subproject commit f2abf5015c769f9603fc63e7d0a0eff00006c61e From 29d9f34c1431ed1599dbf9c99c81876868fc2b22 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 13:36:59 -0400 Subject: [PATCH 0737/5359] set php-cli-tools remote to wp-cli fork --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 44afb303c..ec544e3d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/php/php-cli-tools"] path = src/php/php-cli-tools - url = git://github.com/jlogsdon/php-cli-tools.git + url = git://github.com/wp-cli/php-cli-tools.git From bd19d9bcdf9db12ca3ce548818f438b48c3bc5d7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 18:55:38 -0400 Subject: [PATCH 0738/5359] don't add empty lines to history. #89 --- src/php/wp-cli/commands/internals/shell.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 1f51ba85f..c655f9572 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -21,7 +21,7 @@ public function __invoke() { ); $non_expressions = implode( '|', $non_expressions ); - $pattern = "/^\s*($non_expressions)[\(\s]+/"; + $pattern = "/^($non_expressions)[\(\s]+/"; while ( true ) { $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); @@ -41,8 +41,9 @@ public function __invoke() { } private static function repl_readline( $str ) { - $line = readline( $str ); - readline_add_history( $line ); + $line = trim( readline( $str ) ); + if ( !empty( $line ) ) + readline_add_history( $line ); return $line; } From 8cad2c979b7faa1e877889660a9713eb3ad0099c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 19:41:53 -0400 Subject: [PATCH 0739/5359] first pass at preserving wp shell history between sessions --- src/php/wp-cli/commands/internals/shell.php | 41 ++++++++++++++++----- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index c655f9572..f8f6e0d5b 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -1,17 +1,19 @@ <?php -WP_CLI::add_command( 'shell', new Shell_Command ); +namespace WP_CLI\Commands; -class Shell_Command extends WP_CLI_Command { +\WP_CLI::add_command( 'shell', new Shell_Command ); + +class Shell_Command extends \WP_CLI_Command { /** * Open an interactive shell environment. */ public function __invoke() { if ( function_exists( 'readline' ) ) { - $repl = 'repl_readline'; + $repl = new REPL_Readline; } else { - $repl = 'repl_basic'; + $repl = new REPL_Basic; } $non_expressions = array( @@ -24,7 +26,7 @@ public function __invoke() { $pattern = "/^($non_expressions)[\(\s]+/"; while ( true ) { - $line = call_user_func( array( __CLASS__, $repl ), 'wp> ' ); + $line = $repl->read( 'wp> ' ); if ( !preg_match( $pattern, $line ) ) $line = 'return ' . $line; @@ -39,16 +41,37 @@ public function __invoke() { \WP_CLI::line( var_export( $_, false ) ); } } +} + + +class REPL_Readline { + + function __construct() { + $this->hist_path = getcwd() . '/.wp-cli-history'; + + readline_read_history( $this->hist_path ); + + register_shutdown_function( array( $this, 'save_history' ) ); + } - private static function repl_readline( $str ) { - $line = trim( readline( $str ) ); + function read( $prompt ) { + $line = trim( readline( $prompt ) ); if ( !empty( $line ) ) readline_add_history( $line ); + return $line; } - private static function repl_basic( $str ) { - \WP_CLI::out( $str ); + function save_history() { + readline_write_history( $this->hist_path ); + } +} + + +class REPL_Basic { + + function read( $prompt ) { + \WP_CLI::out( $prompt ); return \cli\input(); } } From b743dab38fa2ed6dc2a8ee3fcfff65c4414dcfef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Oct 2012 19:54:34 -0400 Subject: [PATCH 0740/5359] store different history files, based on current path and current user --- src/php/wp-cli/commands/internals/shell.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index f8f6e0d5b..12a04dfaf 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -47,13 +47,19 @@ public function __invoke() { class REPL_Readline { function __construct() { - $this->hist_path = getcwd() . '/.wp-cli-history'; + $this->hist_path = self::get_history_path(); readline_read_history( $this->hist_path ); register_shutdown_function( array( $this, 'save_history' ) ); } + private static function get_history_path() { + $data = getcwd() . get_current_user(); + + return sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); + } + function read( $prompt ) { $line = trim( readline( $prompt ) ); if ( !empty( $line ) ) From 775897b32ca947914d3f3e4352e2dd26f1bab410 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Oct 2012 11:25:17 -0400 Subject: [PATCH 0741/5359] attempt to catch termination signals BUGS: * Ctrl+D still isn't handled properly * Ctrl+C now requires a RETURN because readline blocks --- src/php/wp-cli/commands/internals/shell.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 12a04dfaf..57f27519a 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -52,6 +52,23 @@ function __construct() { readline_read_history( $this->hist_path ); register_shutdown_function( array( $this, 'save_history' ) ); + + declare( ticks = 1 ); + pcntl_signal( SIGINT, array( $this, 'catch_signal' ) ); + pcntl_signal( SIGTERM, array( $this, 'catch_signal' ) ); + pcntl_signal( SIGSEGV, array( $this, 'catch_signal' ) ); + pcntl_signal( SIGQUIT, array( $this, 'catch_signal' ) ); + } + + function catch_signal( $signo ) { + switch ( $signo ) { + case SIGTERM: + case SIGSEGV: + case SIGQUIT: + case SIGABRT: + case SIGINT: + exit; // ensures clean shutdown + } } private static function get_history_path() { From 2296c4c285fa264d997b03247538adacb993effc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Oct 2012 13:12:19 -0400 Subject: [PATCH 0742/5359] Revert "attempt to catch termination signals" This reverts commit 775897b32ca947914d3f3e4352e2dd26f1bab410. --- src/php/wp-cli/commands/internals/shell.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 57f27519a..12a04dfaf 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -52,23 +52,6 @@ function __construct() { readline_read_history( $this->hist_path ); register_shutdown_function( array( $this, 'save_history' ) ); - - declare( ticks = 1 ); - pcntl_signal( SIGINT, array( $this, 'catch_signal' ) ); - pcntl_signal( SIGTERM, array( $this, 'catch_signal' ) ); - pcntl_signal( SIGSEGV, array( $this, 'catch_signal' ) ); - pcntl_signal( SIGQUIT, array( $this, 'catch_signal' ) ); - } - - function catch_signal( $signo ) { - switch ( $signo ) { - case SIGTERM: - case SIGSEGV: - case SIGQUIT: - case SIGABRT: - case SIGINT: - exit; // ensures clean shutdown - } } private static function get_history_path() { From e916a66e513845212723ee6fb596b6fe9e0ca531 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Oct 2012 13:14:53 -0400 Subject: [PATCH 0743/5359] add notice about correct closing method --- src/php/wp-cli/commands/internals/shell.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 12a04dfaf..38592e44b 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -16,6 +16,8 @@ public function __invoke() { $repl = new REPL_Basic; } + \WP_CLI::line( 'Type "exit" to close session.' ); + $non_expressions = array( 'echo', 'return', 'global', 'while', 'for', 'foreach', 'if', 'switch', From 901414f92e9a2f88e4d5ae7026f10df936fbca57 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Oct 2012 14:31:38 -0400 Subject: [PATCH 0744/5359] ignore --ID parameter for wp post create, to avoid confusion --- src/php/wp-cli/commands/internals/post.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 22335357c..11065286b 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -15,7 +15,9 @@ class Post_Command extends WP_CLI_Command { * * @synopsis --<field>=<value> [--porcelain] */ - public function create( $args, $assoc_args ) { + public function create( $_, $assoc_args ) { + unset( $assoc_args['ID'] ); + $post_id = wp_insert_post( $assoc_args, true ); if ( is_wp_error( $post_id ) ) { From f7c61bd5dc92aa3073d2911b8276f677ea791494 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Oct 2012 14:37:31 -0400 Subject: [PATCH 0745/5359] fix wp post delete --force --- src/php/wp-cli/commands/internals/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index 11065286b..c05c3b8d4 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -60,7 +60,7 @@ public function delete( $post_ids, $assoc_args ) { $action = isset( $assoc_args['force'] ) ? 'Deleted' : 'Trashed'; foreach ( $post_ids as $post_id ) { - if ( wp_delete_post( $post_id, $force ) ) { + if ( wp_delete_post( $post_id, $assoc_args['force'] ) ) { WP_CLI::success( "{$action} post $post_id." ); } else { WP_CLI::error( "Failed deleting post $post_id." ); From 3ace64b97ac159ee713b5c4e024283b83f8aceee Mon Sep 17 00:00:00 2001 From: Taylor Dewey <td@tddewey.com> Date: Wed, 31 Oct 2012 22:07:10 -0700 Subject: [PATCH 0746/5359] WP Export: Add export arguments as a class variable Adds the export arguments that eventually get passed to export_wp() as a class variable. Fixes #197 --- src/php/wp-cli/commands/internals/export.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 96527afac..11439cb80 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -10,6 +10,12 @@ */ class Export_Command extends WP_CLI_Command { + /** + * Initialize the array of arguments that will be eventually be passed to export_wp + * @var array + */ + public $export_args = array(); + /** * Export posts to a WXR file. * From 06b5beeefa9176d132ac28c8fcab2919c26bf9ab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 11:54:49 -0700 Subject: [PATCH 0747/5359] A utility method for parsing a given CSV --- src/php/wp-cli/utils.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 1e49fcb89..3c912d7a7 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -156,3 +156,26 @@ function get_upgrader( $class ) { return new $class( new \CLI_Upgrader_Skin ); } +function parse_csv( $filepath, $has_headers = true ) { + + if ( false == ( $csv = fopen( $filepath, 'r' ) ) ) + \WP_CLI::error( sprintf( 'Could not open csv file: %s', $filepath ) ); + + $parsed_data = array(); + $headers = array(); + while ( ( $row = fgetcsv( $csv, 10000, "," ) ) !== FALSE ) { + if ( $has_headers ) { + $headers = array_values( $row ); + $has_headers = false; + continue; + } + $row_data = array(); + foreach( $row as $index => $cell_value ) { + if ( ! empty( $headers[$index] ) ) + $index = $headers[$index]; + $row_data[$index] = $cell_value; + } + $parsed_data[] = $row_data; + } + return $parsed_data; +} From 8f48e4e92df029bd599d300f21bdc14a325f58cc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 12:00:57 -0700 Subject: [PATCH 0748/5359] New user subcommand for importing users from a CSV The behavior of the subcommand is two-fold: create the users if they don't yet exist, or assign them to the blog if they do exist but aren't yet a member See #167 --- src/docs/user-import-csv.txt | 9 ++++ src/php/wp-cli/commands/internals/user.php | 59 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/docs/user-import-csv.txt diff --git a/src/docs/user-import-csv.txt b/src/docs/user-import-csv.txt new file mode 100644 index 000000000..ca39f28ef --- /dev/null +++ b/src/docs/user-import-csv.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `<file>`: + + The csv file of users to import + +## EXAMPLES + + wp user import_csv /path/to/csv.csv diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 6864fd124..5e7451042 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -197,4 +197,63 @@ public function generate( $args, $assoc_args ) { $notify->finish(); } + + /** + * Import users from a CSV + * + * @synopsis <file> + */ + public function import_csv( $args, $assoc_args ) { + + list( $csv ) = $args; + + $new_users = \WP_CLI\utils\parse_csv( $csv ); + + $blog_users = get_users(); + + foreach( $new_users as $new_user ) { + + $defaults = array( + 'role' => get_option('default_role'), + 'user_pass' => wp_generate_password(), + 'user_registered' => strftime( "%F %T", time() ), + 'display_name' => false, + ); + $new_user = array_merge( $new_user, $defaults ); + + if ( 'none' == $new_user['role'] ) { + $new_user['role'] = false; + } elseif ( is_null( get_role( $new_user['role'] ) ) ) { + WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + continue; + } + + // User already exists and we just need to add them to the site if they aren't already there + if ( $existing_user = get_user_by( 'login', $new_user['user_login'] ) ) { + if ( in_array( $new_user['user_login'], wp_list_pluck( $blog_users, 'user_login' ) ) ) + WP_CLI::warning( "{$new_user['user_login']} already is a member of blog" ); + else if ( $new_user['role'] ) { + add_user_to_blog( get_current_blog_id(), $new_user['user_login'], $new_user['role'] ); + WP_CLI::line( "{$new_user['user_login']} added to blog as {$new_user['role']}" ); + } else { + WP_CLI::line( "{$new_user['user_login']} exists, but won't be added to the blog" ); + } + continue; + } + + $user_id = wp_insert_user( $new_user ); + + if ( is_wp_error( $user_id ) ) { + WP_CLI::warning( $user_id ); + } else { + if ( false === $new_user['role'] ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); + } + } + + WP_CLI::line( "{$new_user['user_login']} created" ); + + } + } } From 7c2dbba1e93bd441c113c00549179cd71ac39fd2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 20:30:46 +0000 Subject: [PATCH 0749/5359] Merge in proper order so $new_user values aren't overwritten by $default --- src/php/wp-cli/commands/internals/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 5e7451042..cdcef1aa6 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -219,7 +219,7 @@ public function import_csv( $args, $assoc_args ) { 'user_registered' => strftime( "%F %T", time() ), 'display_name' => false, ); - $new_user = array_merge( $new_user, $defaults ); + $new_user = array_merge( $defaults, $new_user ); if ( 'none' == $new_user['role'] ) { $new_user['role'] = false; From d2adba913d0445d51cb38fc9170ffbb3892b4d02 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:12:10 +0000 Subject: [PATCH 0750/5359] check_end_date() validator should set the 'end_date' argument --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 11439cb80..15ff79217 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -91,7 +91,7 @@ private function check_end_date( $date ) { WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) ); return false; } - $this->export_args['start_date'] = date( 'Y-m-d', $time ); + $this->export_args['end_date'] = date( 'Y-m-d', $time ); return true; } From 3c669482002cc898ea083beea5710fa64c0c693f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:18:25 +0000 Subject: [PATCH 0751/5359] With 'end_date' properly set, we don't need add a month to the value --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 15ff79217..55482383a 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -266,7 +266,7 @@ private function export_wp( $args = array() ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); if ( $args['end_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( '+1 month', strtotime( $args['end_date'] ) ) ) ); + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); } // grab a snapshot of post IDs, just in case it changes during the export From 08013d6bdd4ee5d9c3e1d277fa21af133f3564c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:31:33 +0000 Subject: [PATCH 0752/5359] Rename the 'content' argument to 'post_type' for clarity --- src/php/wp-cli/commands/internals/export.php | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 55482383a..5d788d897 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -104,7 +104,7 @@ private function check_post_type( $post_type ) { WP_CLI::warning( sprintf( 'The post type %s does not exists. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); return false; } - $this->export_args['content'] = $post_type; + $this->export_args['post_type'] = $post_type; return true; } @@ -213,7 +213,7 @@ private function export_wp( $args = array() ) { /** * This is mostly the original code of export_wp defined in wp-admin/includes/export.php */ - $defaults = array( 'content' => 'all', 'author' => false, 'category' => false, + $defaults = array( 'post_type' => 'all', 'author' => false, 'category' => false, 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, ); $args = wp_parse_args( $args, $defaults ); @@ -233,32 +233,32 @@ private function export_wp( $args = array() ) { } $file_name_base = $sitename . 'wordpress.' . implode( ".", $append ); - if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) { - $ptype = get_post_type_object( $args['content'] ); + if ( 'all' != $args['post_type'] && post_type_exists( $args['post_type'] ) ) { + $ptype = get_post_type_object( $args['post_type'] ); if ( ! $ptype->can_export ) - $args['content'] = 'post'; + $args['post_type'] = 'post'; - $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] ); + $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['post_type'] ); } else { $post_types = get_post_types( array( 'can_export' => true ) ); $esses = array_fill( 0, count( $post_types ), '%s' ); $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); } - if ( $args['status'] && ( 'post' == $args['content'] || 'page' == $args['content'] ) ) + if ( $args['status'] && ( 'post' == $args['post_type'] || 'page' == $args['post_type'] ) ) $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] ); else $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; $join = ''; - if ( $args['category'] && 'post' == $args['content'] ) { + if ( $args['category'] && 'post' == $args['post_type'] ) { if ( $term = term_exists( $args['category'], 'category' ) ) { $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)"; $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] ); } } - if ( 'post' == $args['content'] || 'page' == $args['content'] ) { + if ( 'post' == $args['post_type'] || 'page' == $args['post_type'] ) { if ( $args['author'] ) $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); @@ -278,7 +278,7 @@ private function export_wp( $args = array() ) { $cat = get_term( $term['term_id'], 'category' ); $cats = array( $cat->term_id => $cat ); unset( $term, $cat ); - } else if ( 'all' == $args['content'] ) { + } else if ( 'all' == $args['post_type'] ) { $categories = (array) get_categories( array( 'get' => 'all' ) ); $tags = (array) get_tags( array( 'get' => 'all' ) ); @@ -364,7 +364,7 @@ private function export_wp( $args = array() ) { <?php foreach ( $terms as $t ) : ?> <wp:term><wp:term_id><?php echo $t->term_id ?></wp:term_id><wp:term_taxonomy><?php echo $t->taxonomy; ?></wp:term_taxonomy><wp:term_slug><?php echo $t->slug; ?></wp:term_slug><wp:term_parent><?php echo $t->parent ? $terms[$t->parent]->slug : ''; ?></wp:term_parent><?php wxr_term_name( $t ); ?><?php wxr_term_description( $t ); ?></wp:term> <?php endforeach; ?> -<?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?> +<?php if ( 'all' == $args['post_type'] ) wxr_nav_menu_terms(); ?> <?php do_action( 'rss2_head' ); ?> From edd4dea23e8b82926ee896474f895b73a73b8c08 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:35:14 +0000 Subject: [PATCH 0753/5359] ORDER BY post_date and post_parent to avoid getting attachments stacked up front when doing an 'all' post_type export https://github.com/Automattic/WordPress-CLI-Exporter/commit/b759208e8593ce504f9934804ee582bf00d68e35 --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 5d788d897..a90cd62af 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -270,7 +270,7 @@ private function export_wp( $args = array() ) { } // grab a snapshot of post IDs, just in case it changes during the export - $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); + $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); // get the requested terms ready, empty unless posts filtered by category or all content $cats = $tags = $terms = array(); From 0378bb9ba18a5da44069d029f3f719d7ab3c1bac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:41:31 +0000 Subject: [PATCH 0754/5359] When looking up a specific post type, ensure we grab their attachments too https://github.com/Automattic/WordPress-CLI-Exporter/commit/b7cfda1c052fe64088d55f21a580d061fb6d6b03 --- src/php/wp-cli/commands/internals/export.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index a90cd62af..e285de095 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -378,6 +378,12 @@ private function export_wp( $args = array() ) { $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); + if ( 'all' != $args['post_type'] ) { + $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" ); + if ( is_array( $attachment_ids ) ) + $posts = array_merge( $posts, array_map( 'get_post', $attachment_ids ) ); + } + // Begin Loop foreach ( $posts as $post ) { From 287a4e8ab7a9faa97308655e61f9829667dbd4bd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:51:16 +0000 Subject: [PATCH 0755/5359] All post types should be able to use the 'author' and date range flags --- src/php/wp-cli/commands/internals/export.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index e285de095..7bd66afd2 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -258,16 +258,15 @@ private function export_wp( $args = array() ) { } } - if ( 'post' == $args['post_type'] || 'page' == $args['post_type'] ) { - if ( $args['author'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); + + if ( $args['author'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); - if ( $args['start_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); + if ( $args['start_date'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); - if ( $args['end_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); - } + if ( $args['end_date'] ) + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); // grab a snapshot of post IDs, just in case it changes during the export $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); From 0029888e254bb92b7507fb9125e1df0f833fc778 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:53:24 +0000 Subject: [PATCH 0756/5359] Ensure the target directory is trailing slashed, because we expect it to be later --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 7bd66afd2..e060622b0 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -49,7 +49,7 @@ public function __invoke( $args, $assoc_args ) { exit(1); } - $this->wxr_path = $assoc_args['dir']; + $this->wxr_path = trailingslashit( $assoc_args['dir'] ); WP_CLI::line( 'Starting export process...' ); WP_CLI::line(); From b56cd2a3b1e21ff4d3dd45d7442bf28f8cc4b87b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 22:04:20 +0000 Subject: [PATCH 0757/5359] More explicit dates for the date range --- src/php/wp-cli/commands/internals/export.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index e060622b0..d58dceadf 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -263,10 +263,10 @@ private function export_wp( $args = array() ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); if ( $args['start_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s 00:00:00", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); if ( $args['end_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s 23:59:59", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); // grab a snapshot of post IDs, just in case it changes during the export $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); From 139737224a0582849ed30b066f31a91776942153 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 22:09:23 +0000 Subject: [PATCH 0758/5359] To significantly improve the performance on export, explicitly define the functions used to generate the WXR Although the previous approach passed a dummy content type, it still had to spend a lot of time getting all of the taxonomy terms, etc. --- src/php/wp-cli/commands/internals/export.php | 126 ++++++++++++++++++- 1 file changed, 120 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index d58dceadf..d59ae9956 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -203,12 +203,7 @@ private function stop_the_insanity() { private function export_wp( $args = array() ) { require_once ABSPATH . 'wp-admin/includes/export.php'; - global $wpdb, $post; - // call export_wp as we need the functions defined in it. - $dummy_args = array( 'content' => 'i-do-not-exist' ); - ob_start(); - export_wp( $dummy_args ); - ob_end_clean(); + global $wpdb; /** * This is mostly the original code of export_wp defined in wp-admin/includes/export.php @@ -303,6 +298,125 @@ private function export_wp( $args = array() ) { unset( $categories, $custom_taxonomies, $custom_terms ); } + /** + * Functions normally defined in wp-admin/includes/export.php + */ + function wxr_cdata( $str ) { + if ( seems_utf8( $str ) == false ) + $str = utf8_encode( $str ); + + // $str = ent2ncr(esc_html($str)); + $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>'; + + return $str; + } + + function wxr_site_url() { + // ms: the base url + if ( is_multisite() ) + return network_home_url(); + // wp: the blog url + else + return get_bloginfo_rss( 'url' ); + } + + function wxr_cat_name( $category ) { + if ( empty( $category->name ) ) + return; + + echo '<wp:cat_name>' . wxr_cdata( $category->name ) . '</wp:cat_name>'; + } + + function wxr_category_description( $category ) { + if ( empty( $category->description ) ) + return; + + echo '<wp:category_description>' . wxr_cdata( $category->description ) . '</wp:category_description>'; + } + + function wxr_tag_name( $tag ) { + if ( empty( $tag->name ) ) + return; + + echo '<wp:tag_name>' . wxr_cdata( $tag->name ) . '</wp:tag_name>'; + } + + + function wxr_tag_description( $tag ) { + if ( empty( $tag->description ) ) + return; + + echo '<wp:tag_description>' . wxr_cdata( $tag->description ) . '</wp:tag_description>'; + } + + function wxr_term_name( $term ) { + if ( empty( $term->name ) ) + return; + + echo '<wp:term_name>' . wxr_cdata( $term->name ) . '</wp:term_name>'; + } + + function wxr_term_description( $term ) { + if ( empty( $term->description ) ) + return; + + echo '<wp:term_description>' . wxr_cdata( $term->description ) . '</wp:term_description>'; + } + + function wxr_authors_list() { + global $wpdb; + + $authors = array(); + $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" ); + foreach ( (array) $results as $result ) + $authors[] = get_userdata( $result->post_author ); + + $authors = array_filter( $authors ); + + foreach ( $authors as $author ) { + echo "\t<wp:author>"; + echo '<wp:author_id>' . $author->ID . '</wp:author_id>'; + echo '<wp:author_login>' . $author->user_login . '</wp:author_login>'; + echo '<wp:author_email>' . $author->user_email . '</wp:author_email>'; + echo '<wp:author_display_name>' . wxr_cdata( $author->display_name ) . '</wp:author_display_name>'; + echo '<wp:author_first_name>' . wxr_cdata( $author->user_firstname ) . '</wp:author_first_name>'; + echo '<wp:author_last_name>' . wxr_cdata( $author->user_lastname ) . '</wp:author_last_name>'; + echo "</wp:author>\n"; + } + } + + function wxr_nav_menu_terms() { + $nav_menus = wp_get_nav_menus(); + if ( empty( $nav_menus ) || ! is_array( $nav_menus ) ) + return; + + foreach ( $nav_menus as $menu ) { + echo "\t<wp:term><wp:term_id>{$menu->term_id}</wp:term_id><wp:term_taxonomy>nav_menu</wp:term_taxonomy><wp:term_slug>{$menu->slug}</wp:term_slug>"; + wxr_term_name( $menu ); + echo "</wp:term>\n"; + } + } + + function wxr_post_taxonomy() { + $post = get_post(); + + $taxonomies = get_object_taxonomies( $post->post_type ); + if ( empty( $taxonomies ) ) + return; + $terms = wp_get_object_terms( $post->ID, $taxonomies ); + + foreach ( (array) $terms as $term ) { + echo "\t\t<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "</category>\n"; + } + } + + function wxr_filter_postmeta( $return_me, $meta_key ) { + if ( '_edit_lock' == $meta_key ) + $return_me = true; + return $return_me; + } + add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 ); + WP_CLI::line( 'Exporting ' . count( $post_ids ) . ' items' ); WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); From 4d1250d31bbd898a6037790f591037a1030d207e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 22:16:24 +0000 Subject: [PATCH 0759/5359] Fix SQL syntax issue --- src/php/wp-cli/commands/internals/export.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index d59ae9956..ba3f18740 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -258,10 +258,10 @@ private function export_wp( $args = array() ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); if ( $args['start_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s 00:00:00", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d 00:00:00', strtotime( $args['start_date'] ) ) ); if ( $args['end_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s 23:59:59", date( 'Y-m-d', strtotime( $args['end_date'] ) ) ); + $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s", date( 'Y-m-d 23:59:59', strtotime( $args['end_date'] ) ) ); // grab a snapshot of post IDs, just in case it changes during the export $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); From 3fcd2d7cb60ac7dd8db52d3c4010418dd77fc112 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 22:16:51 +0000 Subject: [PATCH 0760/5359] WXR is a XML derivative --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index ba3f18740..53dee8b7d 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -575,7 +575,7 @@ function wxr_filter_postmeta( $return_me, $meta_key ) { $result = ob_get_clean(); - $full_path = $this->wxr_path . $file_name_base . '.wxr'; + $full_path = $this->wxr_path . $file_name_base . '.xml'; if ( !file_exists( $full_path ) || is_writeable( $full_path ) ) { WP_CLI::line( 'Writing to ' . $full_path ); From e6d2d65357fc331042c2942bbca779a2dd50fa36 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 23:36:13 +0000 Subject: [PATCH 0761/5359] For increased performance with large datasets, automagically break the export files into sets of 1000 posts and dump the output buffer much more regularly --- src/php/wp-cli/commands/internals/export.php | 94 ++++++++++++++------ 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 53dee8b7d..bef0f3200 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -19,25 +19,26 @@ class Export_Command extends WP_CLI_Command { /** * Export posts to a WXR file. * - * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] + * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] */ public function __invoke( $args, $assoc_args ) { $defaults = array( - 'dir' => NULL, - 'start_date' => NULL, - 'end_date' => NULL, - 'post_type' => NULL, - 'author' => NULL, - 'category' => NULL, - 'post_status' => NULL, - 'skip_comments' => NULL, + 'dir' => NULL, + 'start_date' => NULL, + 'end_date' => NULL, + 'post_type' => NULL, + 'author' => NULL, + 'category' => NULL, + 'post_status' => NULL, + 'skip_comments' => NULL, + 'file_item_count' => 1000, ); $args = wp_parse_args( $assoc_args, $defaults ); $has_errors = false; - - foreach( $defaults as $argument => $default_value ) { + + foreach( $args as $argument => $default_value ) { if ( is_callable( array( &$this, 'check_' . $argument ) ) ) { $result = call_user_func( array( &$this, 'check_' . $argument ), $args[$argument] ); if ( false === $result && false === $has_errors ) @@ -179,6 +180,16 @@ private function check_skip_comments( $skip ) { return true; } + private function check_file_item_count( $file_item_count ) { + + if ( ! is_numeric( $file_item_count ) ) { + WP_CLI::warning( 'File item count needs to be numeric' ); + return false; + } + $this->export_args['file_item_count'] = $file_item_count; + return true; + } + /** * Workaround to prevent memory leaks from growing variables @@ -196,6 +207,22 @@ private function stop_the_insanity() { $wp_object_cache->__remoteset(); // important } + private function start_export() { + ob_start(); + } + + private function end_export() { + ob_end_clean(); + } + + private function flush_export( $file_path, $append = true ) { + $result = ob_get_clean(); + if ( $append ) + $append = FILE_APPEND; + file_put_contents( $file_path, $result, $append ); + $this->start_export(); + } + /** * Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php */ @@ -209,7 +236,7 @@ private function export_wp( $args = array() ) { * This is mostly the original code of export_wp defined in wp-admin/includes/export.php */ $defaults = array( 'post_type' => 'all', 'author' => false, 'category' => false, - 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, + 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, 'file_item_count' => 1000, ); $args = wp_parse_args( $args, $defaults ); @@ -264,7 +291,7 @@ private function export_wp( $args = array() ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s", date( 'Y-m-d 23:59:59', strtotime( $args['end_date'] ) ) ); // grab a snapshot of post IDs, just in case it changes during the export - $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); + $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); // get the requested terms ready, empty unless posts filtered by category or all content $cats = $tags = $terms = array(); @@ -418,15 +445,33 @@ function wxr_filter_postmeta( $return_me, $meta_key ) { add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 ); - WP_CLI::line( 'Exporting ' . count( $post_ids ) . ' items' ); + WP_CLI::line( 'Exporting ' . count( $all_the_post_ids ) . ' items to be broken into ' . ceil( count( $all_the_post_ids ) / $args['file_item_count'] ) . ' files' ); WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); WP_CLI::line(); - $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); + $file_count = 1; - ob_start(); + while ( $post_ids = array_splice( $all_the_post_ids, 0, $args['file_item_count'] ) ) { + + $full_path = $this->wxr_path . $file_name_base . '.' . str_pad( $file_count, 3, '0', STR_PAD_LEFT ) . '.xml'; + + // Create the file if it doesn't exist + if ( ! file_exists( $full_path ) ) { + touch( $full_path ); + } + + if ( ! file_exists( $full_path ) ) { + WP_CLI::error( "Failed to create file " . $full_path ); + exit; + } else { + WP_CLI::line( 'Writing to file ' . $full_path ); + } + + $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); + + $this->start_export(); echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; ?> @@ -480,6 +525,7 @@ function wxr_filter_postmeta( $return_me, $meta_key ) { <?php if ( 'all' == $args['post_type'] ) wxr_nav_menu_terms(); ?> <?php do_action( 'rss2_head' ); ?> + <?php $this->flush_export( $full_path, false ); ?> <?php if ( $post_ids ) { global $wp_query; @@ -565,21 +611,19 @@ function wxr_filter_postmeta( $return_me, $meta_key ) { <?php endif; ?> </item> <?php + $this->flush_export( $full_path ); } } } ?> </channel> </rss> <?php - $progress->finish(); - - $result = ob_get_clean(); - - $full_path = $this->wxr_path . $file_name_base . '.xml'; - - if ( !file_exists( $full_path ) || is_writeable( $full_path ) ) { - WP_CLI::line( 'Writing to ' . $full_path ); - file_put_contents( $full_path, $result ); + $this->flush_export( $full_path ); + $this->end_export(); + $this->stop_the_insanity(); + $progress->finish(); + $file_count++; } + WP_CLI::success( "All done with export" ); } } From 4f2098179d71a1aa61719fff8970eb99658bfca1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 23:40:11 +0000 Subject: [PATCH 0762/5359] Copy pasta fixes --- src/php/wp-cli/commands/internals/export.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index bef0f3200..ade057026 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -156,7 +156,7 @@ private function check_post_status( $status ) { $stati = get_post_statuses(); if ( empty( $stati ) || is_wp_error( $stati ) ) { - WP_CLI::warning( sprintf( 'Could not find any post stati', $category ) ); + WP_CLI::warning( 'Could not find any post stati' ); return false; } @@ -173,7 +173,7 @@ private function check_skip_comments( $skip ) { return true; if ( (int) $skip <> 0 && (int) $skip <> 1 ) { - WP_CLI::warning( sprintf( 'skip_comments needs to be 0 (no) or 1 (yes)', $category ) ); + WP_CLI::warning( 'skip_comments needs to be 0 (no) or 1 (yes)' ); return false; } $this->export_args['skip_comments'] = $skip; From 0a842848583c774279ad113d4b1335b7c825355d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Nov 2012 19:53:14 -0400 Subject: [PATCH 0763/5359] first pass at WP_CLI::add_man_dir() --- src/php/wp-cli/class-wp-cli.php | 15 ++++++++++++++- src/php/wp-cli/commands/internals/help.php | 11 +++++++---- src/php/wp-cli/man.php | 12 +++++++----- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 927803ed6..eb2992fec 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -10,6 +10,7 @@ class WP_CLI { private static $commands = array(); + private static $man_dirs = array(); /** * Add a command to the wp-cli list of commands @@ -26,6 +27,16 @@ static function add_command( $name, $class ) { self::$commands[ $name ] = $command; } + static function add_man_dir( $path ) { + $path = realpath( $path ) . '/'; + + self::$man_dirs[ $path ] = true; + } + + static function get_man_dirs() { + return array_keys( self::$man_dirs ); + } + /** * Display a message in the cli * @@ -218,6 +229,8 @@ static function load_command( $command ) { private static $arguments, $assoc_args, $assoc_special; static function before_wp_load() { + self::add_man_dir( WP_CLI_ROOT . "../../../man/" ); + $r = WP_CLI\Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( self::$arguments, self::$assoc_args ) = $r; @@ -314,7 +327,7 @@ private static function generate_man( $args ) { if ( !$command ) WP_CLI::error( sprintf( "'%s' command not found." ) ); - \WP_CLI\Man\generate( $command ); + \WP_CLI\Man\generate( key( self::$man_dirs ), $command ); } private static function render_automcomplete() { diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 16a3a2c4d..9b555263f 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -28,11 +28,14 @@ function __invoke( $args ) { } private static function maybe_load_man_page( $args ) { - $man_file = \WP_CLI\Man\get_path( $args ); + $man_file = \WP_CLI\Man\get_file_name( $args ); - if ( is_readable( $man_file ) ) { - exit( WP_CLI::launch( "man $man_file" ) ); + foreach ( \WP_CLI::get_man_dirs() as $dir ) { + $man_path = $dir . $man_file; + + if ( is_readable( $man_path ) ) { + exit( WP_CLI::launch( "man $man_path" ) ); + } } } } - diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 379f09c6e..44aafe724 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -4,20 +4,22 @@ use \WP_CLI\Dispatcher; -function get_path( $args ) { - return WP_CLI_ROOT . "../../../man/" . implode( '-', $args ) . '.1'; +function get_file_name( $args ) { + return implode( '-', $args ) . '.1'; } function get_src_path( $args ) { return WP_CLI_ROOT . "../../docs/" . implode( '-', $args ) . '.txt'; } -function generate( $command ) { - call_ronn( get_markdown( $command ), get_path( $command->get_path() ) ); +function generate( $dir, $command ) { + $man_path = $dir . get_file_name( $command->get_path() ); + + call_ronn( get_markdown( $command ), $man_path ); if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) { - generate( $subcommand ); + generate( $dir, $subcommand ); } } } From b77daaa3710ae2a84e993039bbcd8e8a1d526b33 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Nov 2012 19:59:14 -0400 Subject: [PATCH 0764/5359] move man source files to WP_CLI class --- src/php/wp-cli/class-wp-cli.php | 5 ++++- src/php/wp-cli/man.php | 16 ++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index eb2992fec..ce57caf02 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -327,7 +327,10 @@ private static function generate_man( $args ) { if ( !$command ) WP_CLI::error( sprintf( "'%s' command not found." ) ); - \WP_CLI\Man\generate( key( self::$man_dirs ), $command ); + $src_dir = WP_CLI_ROOT . "../../docs/"; + $dest_dir = key( self::$man_dirs ); + + \WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); } private static function render_automcomplete() { diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 44aafe724..a058ab305 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -8,30 +8,30 @@ function get_file_name( $args ) { return implode( '-', $args ) . '.1'; } -function get_src_path( $args ) { - return WP_CLI_ROOT . "../../docs/" . implode( '-', $args ) . '.txt'; +function get_src_file_name( $args ) { + return implode( '-', $args ) . '.txt'; } -function generate( $dir, $command ) { - $man_path = $dir . get_file_name( $command->get_path() ); +function generate( $src_dir, $dest_dir, $command ) { + $man_path = $dest_dir . get_file_name( $command->get_path() ); - call_ronn( get_markdown( $command ), $man_path ); + call_ronn( get_markdown( $src_dir, $command ), $man_path ); if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) { - generate( $dir, $subcommand ); + generate( $src_dir, $dest_dir, $subcommand ); } } } // returns a file descriptor or false -function get_markdown( $command ) { +function get_markdown( $src_dir, $command ) { $fd = fopen( "php://temp", "rw" ); if ( $command instanceof Dispatcher\Documentable ) add_initial_markdown( $fd, $command ); - $doc_path = get_src_path( $command->get_path() ); + $doc_path = $src_dir . get_src_file_name( $command->get_path() ); if ( file_exists( $doc_path ) ) fwrite( $fd, file_get_contents( $doc_path ) ); From 84f535b8686c442470d34fdb518964a90c4699e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Nov 2012 20:10:10 -0400 Subject: [PATCH 0765/5359] store man source file dir together with destination dir --- src/php/wp-cli/class-wp-cli.php | 23 +++++++++++++--------- src/php/wp-cli/commands/internals/help.php | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index ce57caf02..dcb4131f0 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -27,14 +27,17 @@ static function add_command( $name, $class ) { self::$commands[ $name ] = $command; } - static function add_man_dir( $path ) { - $path = realpath( $path ) . '/'; + static function add_man_dir( $dest_dir, $src_dir ) { + $dest_dir = realpath( $dest_dir ) . '/'; - self::$man_dirs[ $path ] = true; + if ( $src_dir ) + $src_dir = realpath( $src_dir ) . '/'; + + self::$man_dirs[ $dest_dir ] = $src_dir; } static function get_man_dirs() { - return array_keys( self::$man_dirs ); + return self::$man_dirs; } /** @@ -229,7 +232,10 @@ static function load_command( $command ) { private static $arguments, $assoc_args, $assoc_special; static function before_wp_load() { - self::add_man_dir( WP_CLI_ROOT . "../../../man/" ); + self::add_man_dir( + WP_CLI_ROOT . "../../../man/", + WP_CLI_ROOT . "../../docs/" + ); $r = WP_CLI\Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -327,10 +333,9 @@ private static function generate_man( $args ) { if ( !$command ) WP_CLI::error( sprintf( "'%s' command not found." ) ); - $src_dir = WP_CLI_ROOT . "../../docs/"; - $dest_dir = key( self::$man_dirs ); - - \WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + foreach ( self::$man_dirs as $dest_dir => $src_dir ) { + \WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + } } private static function render_automcomplete() { diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/internals/help.php index 9b555263f..11fa2aa6a 100644 --- a/src/php/wp-cli/commands/internals/help.php +++ b/src/php/wp-cli/commands/internals/help.php @@ -30,8 +30,8 @@ function __invoke( $args ) { private static function maybe_load_man_page( $args ) { $man_file = \WP_CLI\Man\get_file_name( $args ); - foreach ( \WP_CLI::get_man_dirs() as $dir ) { - $man_path = $dir . $man_file; + foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { + $man_path = $dest_dir . $man_file; if ( is_readable( $man_path ) ) { exit( WP_CLI::launch( "man $man_path" ) ); From cdd88d8175ca47ae16948647ca757aee6a692d25 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Nov 2012 20:15:47 -0400 Subject: [PATCH 0766/5359] generate man only if src file exists --- src/php/wp-cli/man.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index a058ab305..b2cc46710 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -13,9 +13,10 @@ function get_src_file_name( $args ) { } function generate( $src_dir, $dest_dir, $command ) { - $man_path = $dest_dir . get_file_name( $command->get_path() ); + $src_path = $src_dir . get_src_file_name( $command->get_path() ); + $dest_path = $dest_dir . get_file_name( $command->get_path() ); - call_ronn( get_markdown( $src_dir, $command ), $man_path ); + call_ronn( get_markdown( $src_path, $command ), $dest_path ); if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) { @@ -25,16 +26,16 @@ function generate( $src_dir, $dest_dir, $command ) { } // returns a file descriptor or false -function get_markdown( $src_dir, $command ) { +function get_markdown( $doc_path, $command ) { + if ( !file_exists( $doc_path ) ) + return false; + $fd = fopen( "php://temp", "rw" ); if ( $command instanceof Dispatcher\Documentable ) add_initial_markdown( $fd, $command ); - $doc_path = $src_dir . get_src_file_name( $command->get_path() ); - - if ( file_exists( $doc_path ) ) - fwrite( $fd, file_get_contents( $doc_path ) ); + fwrite( $fd, file_get_contents( $doc_path ) ); if ( 0 === ftell( $fd ) ) return false; From dfbd5a3cd2243526b18fe1d3dbe8cee6eb426acd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 01:59:13 +0200 Subject: [PATCH 0767/5359] rename $class to $implementation --- src/php/wp-cli/class-wp-cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index dcb4131f0..0129f41ce 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -16,13 +16,13 @@ class WP_CLI { * Add a command to the wp-cli list of commands * * @param string $name The name of the command that will be used in the cli - * @param string $class The class to manage the command + * @param string|object $implementation The command implementation */ - static function add_command( $name, $class ) { - if ( is_string( $class ) ) - $command = new Dispatcher\CompositeCommand( $name, $class ); + static function add_command( $name, $implementation ) { + if ( is_string( $implementation ) ) + $command = new Dispatcher\CompositeCommand( $name, $implementation ); else - $command = new Dispatcher\SingleCommand( $name, $class ); + $command = new Dispatcher\SingleCommand( $name, $implementation ); self::$commands[ $name ] = $command; } From 76746d73b321ad796d89c2368356275ff9ae0583 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 02:28:50 +0200 Subject: [PATCH 0768/5359] move static arguments to the top of the WP_CLI class --- src/php/wp-cli/class-wp-cli.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 0129f41ce..aba3d620b 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -11,6 +11,7 @@ class WP_CLI { private static $commands = array(); private static $man_dirs = array(); + private static $arguments, $assoc_args, $assoc_special; /** * Add a command to the wp-cli list of commands @@ -229,8 +230,6 @@ static function load_command( $command ) { return self::$commands[$command]; } - private static $arguments, $assoc_args, $assoc_special; - static function before_wp_load() { self::add_man_dir( WP_CLI_ROOT . "../../../man/", From f0e19991281eaf533b22efddd104e0e0e0846466 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 02:31:17 +0200 Subject: [PATCH 0769/5359] add 'use \WP_CLI\Utils;' directive --- src/php/wp-cli/class-wp-cli.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index aba3d620b..a9065bec4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -1,6 +1,7 @@ <?php use \WP_CLI\Dispatcher; +use \WP_CLI\Utils; /** * Wrapper class for WP-CLI @@ -236,11 +237,11 @@ static function before_wp_load() { WP_CLI_ROOT . "../../docs/" ); - $r = WP_CLI\Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( self::$arguments, self::$assoc_args ) = $r; - self::$assoc_special = WP_CLI\Utils\split_assoc( self::$assoc_args, array( + self::$assoc_special = Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', 'quiet', 'completions', 'man' ) ); @@ -264,7 +265,7 @@ static function before_wp_load() { } // Handle --url and --blog parameters - WP_CLI\Utils\set_url( self::$assoc_special ); + Utils\set_url( self::$assoc_special ); if ( array( 'core', 'download' ) == self::$arguments ) { self::run_command(); @@ -282,7 +283,7 @@ static function before_wp_load() { // The db commands don't need any WP files if ( array( 'db' ) == array_slice( self::$arguments, 0, 1 ) ) { - WP_CLI\Utils\load_wp_config(); + Utils\load_wp_config(); self::run_command(); exit; } @@ -300,10 +301,10 @@ static function get_assoc_special() { static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - WP_CLI\Utils\set_user( self::$assoc_special ); + Utils\set_user( self::$assoc_special ); if ( !defined( 'WP_INSTALLING' ) && isset( self::$assoc_special['url'] ) ) - WP_CLI\Utils\set_wp_query(); + Utils\set_wp_query(); if ( isset( self::$assoc_special['require'] ) ) require self::$assoc_special['require']; From 81b0ca27d51d7fcb53aeb1f23aaa01022f1ce5f7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 02:43:59 +0200 Subject: [PATCH 0770/5359] DRY set_url_params() --- src/php/wp-cli/utils.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 1e49fcb89..677aa98c4 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -90,10 +90,14 @@ function set_url_params( $url ) { $url_parts = parse_url( 'http://' . $url ); } - $_SERVER['HTTP_HOST'] = isset($url_parts['host']) ? $url_parts['host'] : ''; - $_SERVER['REQUEST_URI'] = (isset($url_parts['path']) ? $url_parts['path'] : '') . (isset($url_parts['query']) ? '?' . $url_parts['query'] : ''); - $_SERVER['REQUEST_URL'] = isset($url_parts['path']) ? $url_parts['path'] : ''; - $_SERVER['QUERY_STRING'] = isset($url_parts['query']) ? $url_parts['query'] : ''; + $f = function( $key ) use ( $url_parts ) { + return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; + }; + + $_SERVER['HTTP_HOST'] = $f('host'); + $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); + $_SERVER['REQUEST_URL'] = $f('path'); + $_SERVER['QUERY_STRING'] = $f('query'); } function locate_wp_config() { From c433dc667d868731f48d30bbc0447cbfc48347d5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 02:47:11 +0200 Subject: [PATCH 0771/5359] use getcwd() instead of $_SERVER['PWD'] --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index a9065bec4..9171e5250 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -261,7 +261,7 @@ static function before_wp_load() { // trailingslashit() isn't available yet define( 'WP_ROOT', rtrim( self::$assoc_special['path'], '/' ) . '/' ); } else { - define( 'WP_ROOT', $_SERVER['PWD'] . '/' ); + define( 'WP_ROOT', getcwd() . '/' ); } // Handle --url and --blog parameters From 53b1ed952e1cb4cfff80557d15c65fbb41e31282 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 02:59:58 +0200 Subject: [PATCH 0772/5359] introduce set_wp_root() helper --- src/php/wp-cli/class-wp-cli.php | 9 ++------- src/php/wp-cli/utils.php | 8 ++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 9171e5250..d2ef63f96 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -256,13 +256,8 @@ static function before_wp_load() { $_SERVER['DOCUMENT_ROOT'] = getcwd(); - // Define the WordPress location - if ( !empty( self::$assoc_special['path'] ) ) { - // trailingslashit() isn't available yet - define( 'WP_ROOT', rtrim( self::$assoc_special['path'], '/' ) . '/' ); - } else { - define( 'WP_ROOT', getcwd() . '/' ); - } + // Handle --path + Utils\set_wp_root( self::$assoc_special ); // Handle --url and --blog parameters Utils\set_url( self::$assoc_special ); diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 677aa98c4..077467702 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -44,6 +44,14 @@ function split_assoc( &$assoc_args, $special_keys ) { return $assoc_special; } +function set_wp_root( $assoc_args ) { + if ( !empty( $assoc_args['path'] ) ) { + define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); + } else { + define( 'WP_ROOT', getcwd() . '/' ); + } +} + function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; From 622000e9793cac40942f1f34d6f99ebf7ed416c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 3 Nov 2012 01:11:01 +0000 Subject: [PATCH 0773/5359] Rather than redeclaring all of the commands within the method, execute the export_wp command with params that are bound to be limited. The functions within export_wp will then be available within execution scope https://github.com/Automattic/wp-cli/commit/139737224a0582849ed30b066f31a91776942153#commitcomment-2092994 --- src/php/wp-cli/commands/internals/export.php | 123 +------------------ 1 file changed, 4 insertions(+), 119 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index ade057026..da299e8b5 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -325,125 +325,10 @@ private function export_wp( $args = array() ) { unset( $categories, $custom_taxonomies, $custom_terms ); } - /** - * Functions normally defined in wp-admin/includes/export.php - */ - function wxr_cdata( $str ) { - if ( seems_utf8( $str ) == false ) - $str = utf8_encode( $str ); - - // $str = ent2ncr(esc_html($str)); - $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>'; - - return $str; - } - - function wxr_site_url() { - // ms: the base url - if ( is_multisite() ) - return network_home_url(); - // wp: the blog url - else - return get_bloginfo_rss( 'url' ); - } - - function wxr_cat_name( $category ) { - if ( empty( $category->name ) ) - return; - - echo '<wp:cat_name>' . wxr_cdata( $category->name ) . '</wp:cat_name>'; - } - - function wxr_category_description( $category ) { - if ( empty( $category->description ) ) - return; - - echo '<wp:category_description>' . wxr_cdata( $category->description ) . '</wp:category_description>'; - } - - function wxr_tag_name( $tag ) { - if ( empty( $tag->name ) ) - return; - - echo '<wp:tag_name>' . wxr_cdata( $tag->name ) . '</wp:tag_name>'; - } - - - function wxr_tag_description( $tag ) { - if ( empty( $tag->description ) ) - return; - - echo '<wp:tag_description>' . wxr_cdata( $tag->description ) . '</wp:tag_description>'; - } - - function wxr_term_name( $term ) { - if ( empty( $term->name ) ) - return; - - echo '<wp:term_name>' . wxr_cdata( $term->name ) . '</wp:term_name>'; - } - - function wxr_term_description( $term ) { - if ( empty( $term->description ) ) - return; - - echo '<wp:term_description>' . wxr_cdata( $term->description ) . '</wp:term_description>'; - } - - function wxr_authors_list() { - global $wpdb; - - $authors = array(); - $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" ); - foreach ( (array) $results as $result ) - $authors[] = get_userdata( $result->post_author ); - - $authors = array_filter( $authors ); - - foreach ( $authors as $author ) { - echo "\t<wp:author>"; - echo '<wp:author_id>' . $author->ID . '</wp:author_id>'; - echo '<wp:author_login>' . $author->user_login . '</wp:author_login>'; - echo '<wp:author_email>' . $author->user_email . '</wp:author_email>'; - echo '<wp:author_display_name>' . wxr_cdata( $author->display_name ) . '</wp:author_display_name>'; - echo '<wp:author_first_name>' . wxr_cdata( $author->user_firstname ) . '</wp:author_first_name>'; - echo '<wp:author_last_name>' . wxr_cdata( $author->user_lastname ) . '</wp:author_last_name>'; - echo "</wp:author>\n"; - } - } - - function wxr_nav_menu_terms() { - $nav_menus = wp_get_nav_menus(); - if ( empty( $nav_menus ) || ! is_array( $nav_menus ) ) - return; - - foreach ( $nav_menus as $menu ) { - echo "\t<wp:term><wp:term_id>{$menu->term_id}</wp:term_id><wp:term_taxonomy>nav_menu</wp:term_taxonomy><wp:term_slug>{$menu->slug}</wp:term_slug>"; - wxr_term_name( $menu ); - echo "</wp:term>\n"; - } - } - - function wxr_post_taxonomy() { - $post = get_post(); - - $taxonomies = get_object_taxonomies( $post->post_type ); - if ( empty( $taxonomies ) ) - return; - $terms = wp_get_object_terms( $post->ID, $taxonomies ); - - foreach ( (array) $terms as $term ) { - echo "\t\t<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "</category>\n"; - } - } - - function wxr_filter_postmeta( $return_me, $meta_key ) { - if ( '_edit_lock' == $meta_key ) - $return_me = true; - return $return_me; - } - add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 ); - + // Load the functions available in wp-admin/includes/export.php + ob_start(); + export_wp( array( 'content' => 'page', 'start_date' => '1971-01-01', 'end_date' => '1971-01-02' ) ); + ob_end_clean(); WP_CLI::line( 'Exporting ' . count( $all_the_post_ids ) . ' items to be broken into ' . ceil( count( $all_the_post_ids ) / $args['file_item_count'] ) . ' files' ); WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); From 755261af2b44f51c1af2275a401afd71e383ce1f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 10:20:16 +0200 Subject: [PATCH 0774/5359] add wp core is-installed --- src/php/wp-cli/commands/internals/core.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index f16aa9f2f..a53be97c8 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -62,6 +62,19 @@ public function config( $args, $assoc_args ) { if ( WP_CLI_QUIET ) ob_end_clean(); } + /** + * Determine if the WordPress tables are installed. + * + * @subcommand is-installed + */ + public function is_installed() { + if ( is_blog_installed() ) { + exit( 0 ); + } else { + exit( 1 ); + } + } + /** * Create the WordPress tables in the database. * From 999e9709ed78bc1cae451e5a353f7c04c0aa05f5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 10:25:58 +0200 Subject: [PATCH 0775/5359] add example --- man/core-is-installed.1 | 26 ++++++++++++++++++++++++++ src/docs/core-is-installed.txt | 5 +++++ 2 files changed, 31 insertions(+) create mode 100644 man/core-is-installed.1 create mode 100644 src/docs/core-is-installed.txt diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 new file mode 100644 index 000000000..f2e27234a --- /dev/null +++ b/man/core-is-installed.1 @@ -0,0 +1,26 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-IS\-INSTALLED" "1" "November 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-is\-installed\fR \- Determine if the WordPress tables are installed\. +. +.SH "SYNOPSIS" +\fBwp core is\-installed\fR +. +.SH "EXAMPLES" +if [ ! $(wp core is\-installed) ]; then +. +.IP "" 4 +. +.nf + +wp core install +. +.fi +. +.IP "" 0 +. +.P +fi diff --git a/src/docs/core-is-installed.txt b/src/docs/core-is-installed.txt new file mode 100644 index 000000000..6432d0e66 --- /dev/null +++ b/src/docs/core-is-installed.txt @@ -0,0 +1,5 @@ +## EXAMPLES + +if [ ! $(wp core is-installed) ]; then + wp core install +fi From bf1362ebf5da5d65331c765a84beb22704a7eb50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 12:34:21 +0200 Subject: [PATCH 0776/5359] fix unregistered command name not showing up --- src/php/wp-cli/dispatcher.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 83700435f..a6e92b2a1 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -78,10 +78,11 @@ function invoke( $arguments, $assoc_args ) { exit; } + $cmd_name = $arguments[0]; $command = $this->find_subcommand( $arguments ); if ( !$command ) - \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $arguments[0] ) ); + \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $cmd_name ) ); $command->invoke( $arguments, $assoc_args ); } From c9e202a62085a01eb570460754cd6f9399154f7f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 12:34:37 +0200 Subject: [PATCH 0777/5359] add special --syn-list flag --- src/php/wp-cli/class-wp-cli.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index d2ef63f96..9a4eaf57d 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -243,7 +243,7 @@ static function before_wp_load() { self::$assoc_special = Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions', 'man' + 'quiet', 'completions', 'man', 'syn-list' ) ); define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); @@ -309,6 +309,19 @@ static function after_wp_load() { exit; } + // Handle --syn-list parameter + if ( isset( self::$assoc_special['syn-list'] ) ) { + foreach ( self::load_all_commands() as $command ) { + if ( $command instanceof \WP_CLI\Dispatcher\Composite ) { + foreach ( $command->get_subcommands() as $subcommand ) + $subcommand->show_usage( '' ); + } else { + $command->show_usage( '' ); + } + } + exit; + } + if ( isset( self::$assoc_special['completions'] ) ) { self::render_automcomplete(); exit; From a370086365ad4ed316c56db2197da9babef167a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 3 Nov 2012 12:44:34 +0200 Subject: [PATCH 0778/5359] add utils/compare-cmd --- utils/compare-cmd | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 utils/compare-cmd diff --git a/utils/compare-cmd b/utils/compare-cmd new file mode 100755 index 000000000..92a291b30 --- /dev/null +++ b/utils/compare-cmd @@ -0,0 +1,18 @@ +#!/bin/bash + +if [ $# -lt 3 ]; then + echo 'usage: <version-a> <version-b> <wp-path>' + exit 1 +fi + +ver_a=$1 +ver_b=$2 +wp_path=$3 + +git checkout $ver_a +wp --path=$wp_path --syn-list > /tmp/wp-cli-a + +git checkout $ver_b +wp --path=$wp_path --syn-list > /tmp/wp-cli-b + +diff /tmp/wp-cli-a /tmp/wp-cli-b From 5276d070bffe6bd3ba45a14c30fd96dc496856bc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 02:55:46 +0200 Subject: [PATCH 0779/5359] Assign expression result directly to $_, instead of relying on eval()'s return value, which returns false on error. see #89 --- src/php/wp-cli/commands/internals/shell.php | 26 ++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 38592e44b..ce33a6012 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -19,30 +19,34 @@ public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); $non_expressions = array( - 'echo', 'return', 'global', + 'echo', 'global', 'while', 'for', 'foreach', 'if', 'switch', 'include', 'include\_once', 'require', 'require\_once' ); $non_expressions = implode( '|', $non_expressions ); - $pattern = "/^($non_expressions)[\(\s]+/"; - while ( true ) { $line = $repl->read( 'wp> ' ); - - if ( !preg_match( $pattern, $line ) ) - $line = 'return ' . $line; - $line .= ';'; - $_ = eval( $line ); + if ( self::starts_with( $non_expressions, $line ) ) { + eval( $line ); + } else { + if ( self::starts_with( 'return', $line ) ) + $line = substr( $line, strlen( 'return' ) ); - if ( false === $_ ) - continue; + $line = '$_ = ' . $line; - \WP_CLI::line( var_export( $_, false ) ); + eval( $line ); + + \WP_CLI::line( var_export( $_, false ) ); + } } } + + private static function starts_with( $tokens, $line ) { + return preg_match( "/^($tokens)[\(\s]+/", $line ); + } } From a6bff727833a6da81a21844056233eeddeaf0a33 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 03:09:02 +0200 Subject: [PATCH 0780/5359] trim extra semicolons --- src/php/wp-cli/commands/internals/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index ce33a6012..4a10264dc 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -27,7 +27,7 @@ public function __invoke() { while ( true ) { $line = $repl->read( 'wp> ' ); - $line .= ';'; + $line = rtrim( $line, ';' ) . ';'; if ( self::starts_with( $non_expressions, $line ) ) { eval( $line ); From ef2655ee8092f6d4082eed37b0501afa738a8b81 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 04:15:34 +0200 Subject: [PATCH 0781/5359] move get_history_path() to Shell_Command class --- src/php/wp-cli/commands/internals/shell.php | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 4a10264dc..02ddfd784 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -10,10 +10,12 @@ class Shell_Command extends \WP_CLI_Command { * Open an interactive shell environment. */ public function __invoke() { + $history_path = self::get_history_path(); + if ( function_exists( 'readline' ) ) { - $repl = new REPL_Readline; + $repl = new REPL_Readline( $history_path ); } else { - $repl = new REPL_Basic; + $repl = new REPL_Basic( $history_path ); } \WP_CLI::line( 'Type "exit" to close session.' ); @@ -47,25 +49,25 @@ public function __invoke() { private static function starts_with( $tokens, $line ) { return preg_match( "/^($tokens)[\(\s]+/", $line ); } + + private static function get_history_path() { + $data = getcwd() . get_current_user(); + + return sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); + } } class REPL_Readline { - function __construct() { - $this->hist_path = self::get_history_path(); + function __construct( $history_path ) { + $this->hist_path = $history_path; readline_read_history( $this->hist_path ); register_shutdown_function( array( $this, 'save_history' ) ); } - private static function get_history_path() { - $data = getcwd() . get_current_user(); - - return sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); - } - function read( $prompt ) { $line = trim( readline( $prompt ) ); if ( !empty( $line ) ) From 962dd9bfde2c9de957e04a737479bea1779a450d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 04:26:58 +0200 Subject: [PATCH 0782/5359] introduce create_repl() helper --- src/php/wp-cli/commands/internals/shell.php | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 02ddfd784..949ea9d6e 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -6,20 +6,16 @@ class Shell_Command extends \WP_CLI_Command { + private $repl; + /** * Open an interactive shell environment. */ public function __invoke() { - $history_path = self::get_history_path(); - - if ( function_exists( 'readline' ) ) { - $repl = new REPL_Readline( $history_path ); - } else { - $repl = new REPL_Basic( $history_path ); - } - \WP_CLI::line( 'Type "exit" to close session.' ); + $this->repl = self::create_repl(); + $non_expressions = array( 'echo', 'global', 'while', 'for', 'foreach', 'if', 'switch', @@ -28,7 +24,7 @@ public function __invoke() { $non_expressions = implode( '|', $non_expressions ); while ( true ) { - $line = $repl->read( 'wp> ' ); + $line = $this->repl->read( 'wp> ' ); $line = rtrim( $line, ';' ) . ';'; if ( self::starts_with( $non_expressions, $line ) ) { @@ -46,6 +42,18 @@ public function __invoke() { } } + private static function create_repl() { + $class = __NAMESPACE__ . '\\'; + + if ( function_exists( 'readline' ) ) { + $class .= 'REPL_Readline'; + } else { + $class .= 'REPL_Basic'; + } + + return new $class( self::get_history_path() ); + } + private static function starts_with( $tokens, $line ) { return preg_match( "/^($tokens)[\(\s]+/", $line ); } From 4edf7e80ffb4096b0a68dfaba9356cfd9c9af955 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 04:52:24 +0200 Subject: [PATCH 0783/5359] add 'unset' to list of non-expression tokens --- src/php/wp-cli/commands/internals/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 949ea9d6e..738bf0b2a 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -17,7 +17,7 @@ public function __invoke() { $this->repl = self::create_repl(); $non_expressions = array( - 'echo', 'global', + 'echo', 'global', 'unset', 'while', 'for', 'foreach', 'if', 'switch', 'include', 'include\_once', 'require', 'require\_once' ); From 88b2f6fc170c0f6b536b4aad1a85cdd5f1427c60 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 04:43:43 +0200 Subject: [PATCH 0784/5359] Use bash builtins for reading user input. PHP's readline extension doesn't implement all the features from the native GNU readline library, such as Ctrl+u. Plus, a large percentage of PHP installs probably don't even have `--with-readline` enabled. The method used in this commit was inspired by wpshell. see #89 --- src/php/wp-cli/commands/internals/shell.php | 69 +++++++-------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 738bf0b2a..42fb10e2f 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -6,16 +6,12 @@ class Shell_Command extends \WP_CLI_Command { - private $repl; - /** * Open an interactive shell environment. */ public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); - $this->repl = self::create_repl(); - $non_expressions = array( 'echo', 'global', 'unset', 'while', 'for', 'foreach', 'if', 'switch', @@ -24,7 +20,11 @@ public function __invoke() { $non_expressions = implode( '|', $non_expressions ); while ( true ) { - $line = $this->repl->read( 'wp> ' ); + $line = self::prompt( 'wp> ', self::get_history_path() ); + + if ( '' === $line ) + continue; + $line = rtrim( $line, ';' ) . ';'; if ( self::starts_with( $non_expressions, $line ) ) { @@ -42,20 +42,24 @@ public function __invoke() { } } - private static function create_repl() { - $class = __NAMESPACE__ . '\\'; + private static function prompt( $prompt, $history_path ) { + $cmds = array( + 'set -f', + sprintf( 'history -r %s', escapeshellarg( $history_path ) ), + 'LINE=""', + sprintf( 'read -re -p %s LINE', escapeshellarg( $prompt ) ), + 'history -s "$LINE"', + sprintf( 'history -w %s', escapeshellarg( $history_path ) ), + 'echo $LINE' + ); - if ( function_exists( 'readline' ) ) { - $class .= 'REPL_Readline'; - } else { - $class .= 'REPL_Basic'; - } + $cmd = implode( '; ', $cmds ); - return new $class( self::get_history_path() ); - } + $fp = popen( '/bin/bash -c ' . escapeshellarg( $cmd ), 'r' ); - private static function starts_with( $tokens, $line ) { - return preg_match( "/^($tokens)[\(\s]+/", $line ); + $line = fgets( $fp ); + + return trim( $line ); } private static function get_history_path() { @@ -63,38 +67,9 @@ private static function get_history_path() { return sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); } -} - - -class REPL_Readline { - - function __construct( $history_path ) { - $this->hist_path = $history_path; - readline_read_history( $this->hist_path ); - - register_shutdown_function( array( $this, 'save_history' ) ); - } - - function read( $prompt ) { - $line = trim( readline( $prompt ) ); - if ( !empty( $line ) ) - readline_add_history( $line ); - - return $line; - } - - function save_history() { - readline_write_history( $this->hist_path ); - } -} - - -class REPL_Basic { - - function read( $prompt ) { - \WP_CLI::out( $prompt ); - return \cli\input(); + private static function starts_with( $tokens, $line ) { + return preg_match( "/^($tokens)[\(\s]+/", $line ); } } From 556218c2fcc1f3d504108d49fe7c6440c4a840dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 06:02:03 +0200 Subject: [PATCH 0785/5359] generate prompt command only once --- src/php/wp-cli/commands/internals/shell.php | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index 42fb10e2f..cc1e413b8 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -20,7 +20,7 @@ public function __invoke() { $non_expressions = implode( '|', $non_expressions ); while ( true ) { - $line = self::prompt( 'wp> ', self::get_history_path() ); + $line = self::prompt(); if ( '' === $line ) continue; @@ -42,8 +42,22 @@ public function __invoke() { } } - private static function prompt( $prompt, $history_path ) { - $cmds = array( + private static function prompt() { + static $cmd; + + if ( !$cmd ) { + $cmd = self::create_prompt_cmd( 'wp> ', self::get_history_path() ); + } + + $fp = popen( $cmd, 'r' ); + + $line = fgets( $fp ); + + return trim( $line ); + } + + private static function create_prompt_cmd( $prompt, $history_path ) { + $cmd = implode( '; ', array( 'set -f', sprintf( 'history -r %s', escapeshellarg( $history_path ) ), 'LINE=""', @@ -51,15 +65,9 @@ private static function prompt( $prompt, $history_path ) { 'history -s "$LINE"', sprintf( 'history -w %s', escapeshellarg( $history_path ) ), 'echo $LINE' - ); - - $cmd = implode( '; ', $cmds ); - - $fp = popen( '/bin/bash -c ' . escapeshellarg( $cmd ), 'r' ); + ) ); - $line = fgets( $fp ); - - return trim( $line ); + return '/bin/bash -c ' . escapeshellarg( $cmd ); } private static function get_history_path() { From f913727626bdfda0cc93f04b3c27935a57e85438 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Nov 2012 06:04:44 +0200 Subject: [PATCH 0786/5359] create non_expressions() helper --- src/php/wp-cli/commands/internals/shell.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/internals/shell.php index cc1e413b8..b3f75f262 100644 --- a/src/php/wp-cli/commands/internals/shell.php +++ b/src/php/wp-cli/commands/internals/shell.php @@ -12,13 +12,6 @@ class Shell_Command extends \WP_CLI_Command { public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); - $non_expressions = array( - 'echo', 'global', 'unset', - 'while', 'for', 'foreach', 'if', 'switch', - 'include', 'include\_once', 'require', 'require\_once' - ); - $non_expressions = implode( '|', $non_expressions ); - while ( true ) { $line = self::prompt(); @@ -27,7 +20,7 @@ public function __invoke() { $line = rtrim( $line, ';' ) . ';'; - if ( self::starts_with( $non_expressions, $line ) ) { + if ( self::starts_with( self::non_expressions(), $line ) ) { eval( $line ); } else { if ( self::starts_with( 'return', $line ) ) @@ -42,6 +35,14 @@ public function __invoke() { } } + private static function non_expressions() { + return implode( '|', array( + 'echo', 'global', 'unset', + 'while', 'for', 'foreach', 'if', 'switch', + 'include', 'include\_once', 'require', 'require\_once' + ) ); + } + private static function prompt() { static $cmd; From 7790c987267e95ceb501994a54a4ec3d8889d9f0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Nov 2012 02:02:45 +0200 Subject: [PATCH 0787/5359] leave documentation for wp-cli.org --- README.md | 200 ++---------------------------------------------------- 1 file changed, 7 insertions(+), 193 deletions(-) diff --git a/README.md b/README.md index 7dc46db18..b2888d0f7 100644 --- a/README.md +++ b/README.md @@ -1,196 +1,10 @@ -What is wp-cli? --------------- +wp-cli is a set of command-line tools for managing WordPress installations. -wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs, update posts and much more. +For documentation, usage, and examples, see: +http://wp-cli.org/ -Visit the [wiki](https://github.com/wp-cli/wp-cli/wiki) for more information. +To suggest a feature, report a bug, or general discussion: +https://github.com/wp-cli/wp-cli/issues -Requirements -============ - -* PHP >= 5.3 -* WP >= 3.3 - -Installing -========== - -**Via PEAR:** - -```sh -sudo pear config-set auto_discover 1 -sudo pear install wp-cli.github.com/pear/wpcli -``` - -**Via GIT:** - -```sh -git clone --recursive git://github.com/wp-cli/wp-cli.git ~/git/wp-cli -cd ~/git/wp-cli -sudo utils/dev-build -``` - -You can replace `~/git/wp-cli` with whatever you want. - -MAMP, XAMP, etc. ------------ - -If the `php` command is not available, you can try finding an appropriate binary: - -```sh -./utils/find-php -``` - -Then, create an environment variable called `WP_CLI_PHP` with the path found by `find-php`. - -In a UNIX environment, you would do this by adding the following line to your `.bashrc` file: - -```sh -WP_CLI_PHP=/path/to/php-binary -``` - -Using -===== - -Go into a WordPress root folder: - -``` -cd /var/www/wp/ -``` - -Typing `wp help` should show you an output similar to this: - -``` -Example usage: - wp google-sitemap [build|help] ... - wp core [update|help] ... - wp home [help] ... - wp option [add|update|delete|get|help] ... - wp plugin [status|activate|deactivate|install|delete|update|help] ... - wp theme [status|details|activate|help] ... -``` - -So this tells us which commands are installed: eg. google-sitemap, core, home, ... -Between brackets you can see their sub commands. - -Let's for example try to install the hello dolly plugin from wordpress.org: - -``` -wp plugin install hello-dolly -``` - -Output: - -``` -Installing Hello Dolly (1.5) - -Downloading install package from http://downloads.WordPress.org/plugin/hello-dolly.1.5.zip ... -Unpacking the package ... -Installing the plugin ... - -Success: The plugin is successfully installed -``` - -Multisite ---------- - -On a multisite installation, you need to pass a --blog parameter, so that WP knows which site it's supposed to be operating on: - -``` -wp theme status --blog=localhost/wp/test -``` - -If you have a subdomain installation, it would look like this: - -``` -wp theme status --blog=test.example.com -``` - -If you're usually working on the same site most of the time, you can put the url of that site in a file called 'wp-cli-blog' in your root WP dir: - -``` -echo 'test.example.com' > wp-cli-blog -``` - -Then, you can call `wp` without the --blog parameter again: - -``` -wp theme status -``` - -Adding commands -=============== - -Adding commands to wp-cli is very easy. You can even add them from within your own plugin. -You can find more information about adding commands in the [Commands Cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook) on our Wiki. - -**Please share the commands you make, issue a pull request to get them included in wp-cli by default.** - -Changelog -========= - -**0.6** - -- added `wp post` and `wp post-meta` -- added `wp user-meta` -- added `wp blog create` -- added `wp export` -- added `wp transient` -- added `wp db optimize` and `wp db repair` -- added `wp db create`, `wp db drop` and `wp db reset` -- added `wp db import` -- added `wp theme install` and `wp theme update` -- added `wp core install_network` -- added `wp core update_db` -- added `--json` option to several subcommands -- added `--network` option to `wp plugin activate` -- added `--require` global parameter -- fixed `wp plugin update` -- fixed "out of memory" error -- misc bugfixes and optimizations -- man pages (not in PEAR package) - -**0.5** - -- added `wp user` -- added `wp core download` -- added `wp core config` -- added `wp plugin update --all` -- added `wp theme update` -- added `wp db import` -- added `--url` `--path` and `--user` global parameters -- various bugfixes - -**0.4** - -- added `wp eval` and `wp eval-file` -- added `wp export` -- added `wp core install` -- fixed `wp core update` -- added `--dev` flag to `wp plugin install` -- added `wp plugin uninstall` -- fixed `wp plugin install` and `wp plugin update` - -**0.3** - -- added `wp sql` -- improved `wp option` -- pear installer - -**0.2** - -- added multisite support -- improved `wp plugin` and `wp theme` -- added `wp generate` -- added `wp core version` -- added `wp --version` -- added bash completion script - -**0.1** - -- initial release - -Contributors ------------- - -- [Contributor list](https://github.com/wp-cli/wp-cli/contributors) -- [Contributor guide](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook) +All contributors are listed here: +https://github.com/wp-cli/wp-cli/contributors From 7d12559e2b77b5c03057e7805e0033d2fba64df4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Nov 2012 19:02:40 +0200 Subject: [PATCH 0788/5359] update URL to pear channel --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 2bc7131b0..5c51b0ceb 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ project.name=wpcli -project.channel=wp-cli.github.com/pear +project.channel=wp-cli.org/pear project.majorVersion=0 project.minorVersion=6 project.patchLevel=0 From 9eb46fcf3f409e1feef2e897b6204021a6a89af0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Nov 2012 19:09:59 +0200 Subject: [PATCH 0789/5359] .git is a text file when checked out as a submodule --- utils/pear-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/pear-build b/utils/pear-build index e044a8c4d..300d83ef4 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -9,7 +9,7 @@ mkdir -p src/www # temporarily move the .git dir, because phing is stupid git_dir=src/php/php-cli-tools/.git -if [ -d $git_dir ]; then +if [ -f $git_dir ]; then mv $git_dir /tmp/php-cli-tools-git fi From d2ad080ce8c1e282c87faf8d310b4c9500dfccd4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Nov 2012 02:06:19 +0200 Subject: [PATCH 0790/5359] show plugin/theme count. fixes #205 --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index a8a9d9645..bfe6e4dc3 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -39,7 +39,7 @@ function status( $args ) { private function status_all() { $items = $this->get_all_items(); - WP_CLI::line( "Installed {$this->item_type}s:" ); + WP_CLI::line( count( $items ) . " installed {$this->item_type}s:" ); foreach ( $items as $file => $details ) { if ( $details['update'] ) { From b5e33de4de1299e444b6d66b298bdbf0c8fe7831 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Nov 2012 02:45:45 +0200 Subject: [PATCH 0791/5359] avoid '1 installed plugins:' situation. see #205 --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index bfe6e4dc3..b4953557e 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -39,7 +39,10 @@ function status( $args ) { private function status_all() { $items = $this->get_all_items(); - WP_CLI::line( count( $items ) . " installed {$this->item_type}s:" ); + $n = count( $items ); + + // Not interested in the translation, just the number logic + WP_CLI::line( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); foreach ( $items as $file => $details ) { if ( $details['update'] ) { From 228ff11365ce6853f20f090efa1451661030a04b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Nov 2012 20:37:44 +0000 Subject: [PATCH 0792/5359] Only call the remoteset method if it exists. Most of the time it doesn't --- src/php/wp-cli/commands/internals/export.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index da299e8b5..057433fbc 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -204,7 +204,8 @@ private function stop_the_insanity() { $wp_object_cache->stats = array(); $wp_object_cache->memcache_debug = array(); $wp_object_cache->cache = array(); - $wp_object_cache->__remoteset(); // important + if ( method_exists( $wp_object_cache, '__remoteset' ) ) + $wp_object_cache->__remoteset(); } private function start_export() { From 6611ca97efc3062537f8087db576c4181e1a5505 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Nov 2012 20:49:41 +0000 Subject: [PATCH 0793/5359] If there are attachments to export as well, pre-load them on the original set of post IDs so the cli progress bar is accurate https://github.com/wp-cli/wp-cli/pull/203#issuecomment-10035187 --- src/php/wp-cli/commands/internals/export.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 057433fbc..e76be99fb 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -294,6 +294,16 @@ private function export_wp( $args = array() ) { // grab a snapshot of post IDs, just in case it changes during the export $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); + // Make sure we're getting all of the attachments for these posts too + if ( 'all' != $args['post_type'] ) { + $all_post_ids_with_attachments = array(); + while ( $post_ids = array_splice( $all_the_post_ids, 0, 100 ) ) { + $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" ); + $all_post_ids_with_attachments = array_merge( $all_post_ids_with_attachments, $post_ids, (array)$attachment_ids ); + } + $all_the_post_ids = $all_post_ids_with_attachments; + } + // get the requested terms ready, empty unless posts filtered by category or all content $cats = $tags = $terms = array(); if ( isset( $term ) && $term ) { @@ -423,12 +433,6 @@ private function export_wp( $args = array() ) { $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); - if ( 'all' != $args['post_type'] ) { - $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" ); - if ( is_array( $attachment_ids ) ) - $posts = array_merge( $posts, array_map( 'get_post', $attachment_ids ) ); - } - // Begin Loop foreach ( $posts as $post ) { From d0536e93239184d0399460e8a4bcf517f32e90f1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Nov 2012 17:11:36 -0800 Subject: [PATCH 0794/5359] Globalize $post so the global $post variable is properly set. Fixes a PHP warning when calling wxr_post_taxonomy(): [08-Nov-2012 01:06:32 UTC] PHP Notice: Trying to get property of non-object in /Users/danielbachhuber/wp-cli/src/php/wp-cli/commands/internals/export.php on line 466 [08-Nov-2012 01:06:32 UTC] PHP Notice: Undefined variable: post in /Users/danielbachhuber/wp-cli/src/php/wp-cli/commands/internals/export.php on line 467 --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index e76be99fb..b0511d4c1 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -424,7 +424,7 @@ private function export_wp( $args = array() ) { <?php $this->flush_export( $full_path, false ); ?> <?php if ( $post_ids ) { - global $wp_query; + global $wp_query, $post; $wp_query->in_the_loop = true; // Fake being in the loop. // fetch 20 posts at a time rather than loading the entire table into memory From 9520cf00eb2f71e629913b459c22ab5da3eb50a2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 8 Nov 2012 22:24:08 +0000 Subject: [PATCH 0795/5359] Add missing reference to 'file_item_count' param --- src/docs/export.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/docs/export.txt b/src/docs/export.txt index 582a983cb..42542a3c1 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -8,6 +8,10 @@ Don't export comments. +* `--file_item_count`=<count> + + Break export into files with N posts + ## FILTERS * `--start_date`=<date>: From d06ec3da3933cb5d53a52b422cceb3fb99080bf0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 22:19:32 +0000 Subject: [PATCH 0796/5359] export: Default the export path to the current working directory Closes #206 --- src/docs/export.txt | 2 +- src/php/wp-cli/commands/internals/export.php | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/docs/export.txt b/src/docs/export.txt index 582a983cb..362ae699b 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -2,7 +2,7 @@ * `--dir`=<dirname>: - Full Path to directory where WXR export files should be stored. + Full Path to directory where WXR export files should be stored. Defaults to current working directory * `--skip_comments`: diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index b0511d4c1..4cd2eeb0f 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -19,7 +19,7 @@ class Export_Command extends WP_CLI_Command { /** * Export posts to a WXR file. * - * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] + * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] */ public function __invoke( $args, $assoc_args ) { $defaults = array( @@ -50,7 +50,8 @@ public function __invoke( $args, $assoc_args ) { exit(1); } - $this->wxr_path = trailingslashit( $assoc_args['dir'] ); + $this->wxr_path = trailingslashit( $this->export_args['dir'] ); + unset( $this->export_args['dir'] ); WP_CLI::line( 'Starting export process...' ); WP_CLI::line(); @@ -59,14 +60,15 @@ public function __invoke( $args, $assoc_args ) { private function check_dir( $path ) { if ( empty( $path ) ) { - WP_CLI::warning( 'missing --dir parameter' ); - return false; + $this->export_args['dir'] = getcwd(); + return true; } if ( !is_dir( $path ) ) { WP_CLI::error( sprintf( "The directory %s does not exist", $path ) ); } + $this->export_args['dir'] = $path; return true; } From 98dd8f60f410f2851f7e6bfc76f1426bf64dd170 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 00:23:37 +0200 Subject: [PATCH 0797/5359] add missing colon and generate man file. see #208 --- man/export.1 | 10 ++++++++-- src/docs/export.txt | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/man/export.1 b/man/export.1 index 77260f31f..07870c358 100644 --- a/man/export.1 +++ b/man/export.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EXPORT" "1" "October 2012" "" "WP-CLI" +.TH "WP\-EXPORT" "1" "November 2012" "" "WP-CLI" . .SH "NAME" \fBwp\-export\fR \- Export posts to a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR \-\-dir=\fIdir\fR [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] +\fBwp export\fR \-\-dir=\fIdir\fR [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] . .SH "OPTIONS" . @@ -23,6 +23,12 @@ Full Path to directory where WXR export files should be stored\. .IP Don\'t export comments\. . +.TP +\fB\-\-file_item_count\fR=\fIcount\fR: +. +.IP +Break export into files with N posts +. .SH "FILTERS" . .TP diff --git a/src/docs/export.txt b/src/docs/export.txt index 42542a3c1..ca5b1a65c 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -8,7 +8,7 @@ Don't export comments. -* `--file_item_count`=<count> +* `--file_item_count`=<count>: Break export into files with N posts From 71fa0ce88fba4881508fddcd00f988f0d48ee745 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 00:27:48 +0200 Subject: [PATCH 0798/5359] clean up arg handling in export.php --- src/php/wp-cli/commands/internals/export.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index b0511d4c1..340147d62 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -21,7 +21,7 @@ class Export_Command extends WP_CLI_Command { * * @synopsis --dir=<dir> [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] */ - public function __invoke( $args, $assoc_args ) { + public function __invoke( $_, $assoc_args ) { $defaults = array( 'dir' => NULL, 'start_date' => NULL, @@ -37,11 +37,11 @@ public function __invoke( $args, $assoc_args ) { $args = wp_parse_args( $assoc_args, $defaults ); $has_errors = false; - - foreach( $args as $argument => $default_value ) { - if ( is_callable( array( &$this, 'check_' . $argument ) ) ) { - $result = call_user_func( array( &$this, 'check_' . $argument ), $args[$argument] ); - if ( false === $result && false === $has_errors ) + + foreach ( $args as $key => $value ) { + if ( is_callable( array( $this, 'check_' . $key ) ) ) { + $result = call_user_func( array( &$this, 'check_' . $key ), $value ); + if ( false === $result ) $has_errors = true; } } @@ -281,7 +281,7 @@ private function export_wp( $args = array() ) { } } - + if ( $args['author'] ) $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); From 5eee5df2847de7510ea0a19aa26a5be1648075d8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 00:29:15 +0200 Subject: [PATCH 0799/5359] remove $this pass-by-reference --- src/php/wp-cli/commands/internals/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 340147d62..7495106e1 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -40,7 +40,7 @@ public function __invoke( $_, $assoc_args ) { foreach ( $args as $key => $value ) { if ( is_callable( array( $this, 'check_' . $key ) ) ) { - $result = call_user_func( array( &$this, 'check_' . $key ), $value ); + $result = call_user_func( array( $this, 'check_' . $key ), $value ); if ( false === $result ) $has_errors = true; } From 881c4f307dda8b9e2382f1a76a8c572960aa5151 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 00:35:24 +0200 Subject: [PATCH 0800/5359] dots and commands for export man file --- man/export.1 | 10 +++++----- src/docs/export.txt | 9 +++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/man/export.1 b/man/export.1 index 07870c358..b58032826 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,7 +7,7 @@ \fBwp\-export\fR \- Export posts to a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR \-\-dir=\fIdir\fR [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] +\fBwp export\fR [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] . .SH "OPTIONS" . @@ -15,7 +15,7 @@ \fB\-\-dir\fR=\fIdirname\fR: . .IP -Full Path to directory where WXR export files should be stored\. +Full path to directory where WXR export files should be stored\. Defaults to current working directory\. . .TP \fB\-\-skip_comments\fR: @@ -27,7 +27,7 @@ Don\'t export comments\. \fB\-\-file_item_count\fR=\fIcount\fR: . .IP -Break export into files with N posts +Break export into files with N posts\. . .SH "FILTERS" . @@ -35,13 +35,13 @@ Break export into files with N posts \fB\-\-start_date\fR=\fIdate\fR: . .IP -Export only posts newer than this date in format YYYY\-MM\-DD\. +Export only posts newer than this date, in format YYYY\-MM\-DD\. . .TP \fB\-\-end_date\fR=\fIdate\fR: . .IP -Export only posts older than this date in format YYYY\-MM\-DD\. +Export only posts older than this date, in format YYYY\-MM\-DD\. . .TP \fB\-\-post_type\fR=\fIpost_type\fR: diff --git a/src/docs/export.txt b/src/docs/export.txt index cd289bf10..ea92cb7f4 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -2,7 +2,8 @@ * `--dir`=<dirname>: - Full Path to directory where WXR export files should be stored. Defaults to current working directory + Full path to directory where WXR export files should be stored. Defaults +to current working directory. * `--skip_comments`: @@ -10,17 +11,17 @@ * `--file_item_count`=<count>: - Break export into files with N posts + Break export into files with N posts. ## FILTERS * `--start_date`=<date>: - Export only posts newer than this date in format YYYY-MM-DD. + Export only posts newer than this date, in format YYYY-MM-DD. * `--end_date`=<date>: - Export only posts older than this date in format YYYY-MM-DD. + Export only posts older than this date, in format YYYY-MM-DD. * `--post_type`=<post_type>: From 7f430ce2a457fb2c66523bf60309bd28ca3ca128 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 23:06:50 +0000 Subject: [PATCH 0801/5359] Subcommand should be named 'import-csv' --- src/php/wp-cli/commands/internals/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index cdcef1aa6..f6d6e643d 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -201,6 +201,7 @@ public function generate( $args, $assoc_args ) { /** * Import users from a CSV * + * @subcommand import-csv * @synopsis <file> */ public function import_csv( $args, $assoc_args ) { From 35ce814afd8e21c6e36d0333f34076f0ce01ac04 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 23:23:01 +0000 Subject: [PATCH 0802/5359] Include sample CSV --- src/docs/user-import-csv.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/docs/user-import-csv.txt b/src/docs/user-import-csv.txt index ca39f28ef..6601facf6 100644 --- a/src/docs/user-import-csv.txt +++ b/src/docs/user-import-csv.txt @@ -7,3 +7,8 @@ ## EXAMPLES wp user import_csv /path/to/csv.csv + + user_login, user_email, display_name, role + bobjones, bobjones@domain.com, Bob Jones, contributor + newuser1, newuser1@domain.com, New User, author + existinguser, existinguser@domain.com, Existing User, administrator \ No newline at end of file From 7020f4e063707cee6354fbbfb0c0f8054d9c737a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 23:28:51 +0000 Subject: [PATCH 0803/5359] Email address is a better check to see if this user already exists. Checking by email address instead of user_login will help avoid adding users to a site that aren't supposed to be on a site --- src/php/wp-cli/commands/internals/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index f6d6e643d..d4b56d9b5 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -230,7 +230,7 @@ public function import_csv( $args, $assoc_args ) { } // User already exists and we just need to add them to the site if they aren't already there - if ( $existing_user = get_user_by( 'login', $new_user['user_login'] ) ) { + if ( $existing_user = get_user_by( 'email', $new_user['user_email'] ) ) { if ( in_array( $new_user['user_login'], wp_list_pluck( $blog_users, 'user_login' ) ) ) WP_CLI::warning( "{$new_user['user_login']} already is a member of blog" ); else if ( $new_user['role'] ) { From 0a3a237d66fd05f5b3365f10b43f9865ece754e2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 16:22:20 -0800 Subject: [PATCH 0804/5359] Remove preceeding spaces in example CSV. The values end up being misinterpreted --- src/docs/user-import-csv.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/docs/user-import-csv.txt b/src/docs/user-import-csv.txt index 6601facf6..6c02912e7 100644 --- a/src/docs/user-import-csv.txt +++ b/src/docs/user-import-csv.txt @@ -8,7 +8,7 @@ wp user import_csv /path/to/csv.csv - user_login, user_email, display_name, role - bobjones, bobjones@domain.com, Bob Jones, contributor - newuser1, newuser1@domain.com, New User, author - existinguser, existinguser@domain.com, Existing User, administrator \ No newline at end of file + user_login,user_email,display_name,role + bobjones,bobjones@domain.com,Bob Jones,contributor + newuser1,newuser1@domain.com,New User,author + existinguser,existinguser@domain.com,Existing User,administrator \ No newline at end of file From bc285919285a2d149768a47ea634ec5f063a78fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 1 Nov 2012 21:08:03 -0700 Subject: [PATCH 0805/5359] Adding and removing users from a blog becomes set_role and remove_role. Also, support both multisite and single --- src/docs/user-add_to_blog.txt | 20 --------- src/docs/user-remove_from_blog.txt | 16 ------- src/docs/user-remove_role.txt | 16 +++++++ src/docs/user-set_role.txt | 20 +++++++++ src/php/wp-cli/commands/internals/user.php | 52 +++++++++++----------- 5 files changed, 63 insertions(+), 61 deletions(-) delete mode 100644 src/docs/user-add_to_blog.txt delete mode 100644 src/docs/user-remove_from_blog.txt create mode 100644 src/docs/user-remove_role.txt create mode 100644 src/docs/user-set_role.txt diff --git a/src/docs/user-add_to_blog.txt b/src/docs/user-add_to_blog.txt deleted file mode 100644 index 76a3056c4..000000000 --- a/src/docs/user-add_to_blog.txt +++ /dev/null @@ -1,20 +0,0 @@ -wp-user-add_to_blog(1) -- Add an existing WordPress user to an existing blog -==== - -## SYNOPSIS - -`wp user add_to_blog` <user-login> [--role=<role>] - -## OPTIONS - -* `<user-login>`: - - The login of the user to add to the blog. - -* `--role`=<role>: - - Add the user with the specified role. Defaults to blog default. - -## EXAMPLES - - wp user add_to_blog bob --role=author diff --git a/src/docs/user-remove_from_blog.txt b/src/docs/user-remove_from_blog.txt deleted file mode 100644 index 619ab9840..000000000 --- a/src/docs/user-remove_from_blog.txt +++ /dev/null @@ -1,16 +0,0 @@ -wp-user-remove_from_blog(1) -- Remove a WordPress user from a blog -==== - -## SYNOPSIS - -`wp user remove_from_blog` <user-login> - -## OPTIONS - -* `<user-login>`: - - The login of the user to remove from the blog. - -## EXAMPLES - - wp user remove_from_blog bob diff --git a/src/docs/user-remove_role.txt b/src/docs/user-remove_role.txt new file mode 100644 index 000000000..98e8cf045 --- /dev/null +++ b/src/docs/user-remove_role.txt @@ -0,0 +1,16 @@ +wp-user-remove_role(1) -- Remove a user's role on a blog +==== + +## SYNOPSIS + +`wp user remove_role` <user-login> + +## OPTIONS + +* `<user-login>`: + + The login of the user to remove from the blog. + +## EXAMPLES + + wp user remove_role bob diff --git a/src/docs/user-set_role.txt b/src/docs/user-set_role.txt new file mode 100644 index 000000000..c17611ffa --- /dev/null +++ b/src/docs/user-set_role.txt @@ -0,0 +1,20 @@ +wp-user-set_role(1) -- Set the user's role +==== + +## SYNOPSIS + +`wp user set_role` <user-login> [<role>] [--blog=<blog>] + +## OPTIONS + +* `<user-login>`: + + The login of the user to add to the blog. + +* `<role>`: + + Add the user with the specified role. Defaults to blog default. + +## EXAMPLES + + wp user set_role bob author diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index e9fed335a..92c0c07fb 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -212,28 +212,28 @@ public function generate( $args, $assoc_args ) { * @param array $args * @param array $assoc_args **/ - public function add_to_blog( $args, $assoc_args ) { + public function set_role( $args, $assoc_args ) { - $defaults = array( - 'id_or_login' => $args[0], - 'role' => $args[1], - ); - $args = array_merge( $assoc_args, $defaults ); + list( $id_or_login, $role ) = $args; - if ( is_numeric( $args['id_or_login'] ) ) - $user = get_user_by( 'id', $args['id_or_login'] ); + if ( is_numeric( $id_or_login ) ) + $user = get_user_by( 'id', $id_or_login ); else - $user = get_user_by( 'login', $args['id_or_login'] ); + $user = get_user_by( 'login', $id_or_login ); - if ( empty( $args['id_or_login'] ) || empty( $user ) ) + if ( ! $user ) WP_CLI::error( "Please specify a valid user ID or user login to add to this blog" ); - global $wp_roles; - if ( empty( $args['role'] ) || ! array_key_exists( $args['role'], $wp_roles->roles ) ) - $args['role'] = get_option( 'default_role' ); + if ( ! get_role( $role ) ) + $role = get_option( 'default_role' ); + + // Multisite + if ( function_exists( 'add_user_to_blog' ) ) + add_user_to_blog( get_current_blog_id(), $user->ID, $role ); + else + $user->set_role( $role ); - add_user_to_blog( get_current_blog_id(), $user->ID, $args['role'] ); - WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$args['role']}" ); + WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}" ); } /** @@ -242,22 +242,24 @@ public function add_to_blog( $args, $assoc_args ) { * @param array $args * @param array $assoc_args **/ - public function remove_from_blog( $args, $assoc_args ) { + public function remove_role( $args, $assoc_args ) { - $defaults = array( - 'id_or_login' => $args[0], - ); - $args = array_merge( $assoc_args, $defaults ); + list( $id_or_login ) = $args; - if ( is_numeric( $args['id_or_login'] ) ) - $user = get_user_by( 'id', $args['id_or_login'] ); + if ( is_numeric( $id_or_login ) ) + $user = get_user_by( 'id', $id_or_login ); else - $user = get_user_by( 'login', $args['id_or_login'] ); + $user = get_user_by( 'login', $id_or_login ); - if ( empty( $args['id_or_login'] ) || empty( $user ) ) + if ( ! $user ) WP_CLI::error( "Please specify a valid user ID or user login to remove from this blog" ); - remove_user_from_blog( $user->ID, get_current_blog_id() ); + // Multisite + if ( function_exists( 'remove_user_from_blog' ) ) + remove_user_from_blog( $user->ID, get_current_blog_id() ); + else + $user->remove_all_caps(); + WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); } From a34f62f0f9452e042d83bfba15c5086155fc76ca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 8 Nov 2012 19:24:04 -0800 Subject: [PATCH 0806/5359] Move synopsis for commants to PHPdoc https://github.com/wp-cli/wp-cli/pull/176#issuecomment-10035053 --- src/docs/user-remove_role.txt | 7 ------- src/docs/user-set_role.txt | 9 +-------- src/php/wp-cli/commands/internals/user.php | 6 ++---- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/docs/user-remove_role.txt b/src/docs/user-remove_role.txt index 98e8cf045..f0d6bb6bd 100644 --- a/src/docs/user-remove_role.txt +++ b/src/docs/user-remove_role.txt @@ -1,10 +1,3 @@ -wp-user-remove_role(1) -- Remove a user's role on a blog -==== - -## SYNOPSIS - -`wp user remove_role` <user-login> - ## OPTIONS * `<user-login>`: diff --git a/src/docs/user-set_role.txt b/src/docs/user-set_role.txt index c17611ffa..042162581 100644 --- a/src/docs/user-set_role.txt +++ b/src/docs/user-set_role.txt @@ -1,17 +1,10 @@ -wp-user-set_role(1) -- Set the user's role -==== - -## SYNOPSIS - -`wp user set_role` <user-login> [<role>] [--blog=<blog>] - ## OPTIONS * `<user-login>`: The login of the user to add to the blog. -* `<role>`: +* `[<role>]`: Add the user with the specified role. Defaults to blog default. diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 92c0c07fb..5475c9a79 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -209,8 +209,7 @@ public function generate( $args, $assoc_args ) { /** * Add a user to a blog * - * @param array $args - * @param array $assoc_args + * @synopsis <user-login> [<role>] [--blog=<blog>] **/ public function set_role( $args, $assoc_args ) { @@ -239,8 +238,7 @@ public function set_role( $args, $assoc_args ) { /** * Remove a user from a blog * - * @param array $args - * @param array $assoc_args + * @synopsis <user-login> **/ public function remove_role( $args, $assoc_args ) { From 5ef5798eb21e116eadcdff0e0b4a4c577dca66bd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Nov 2012 16:57:42 -0800 Subject: [PATCH 0807/5359] Rename to 'set-role' and 'remove-role' --- src/docs/{user-remove_role.txt => user-remove-role.txt} | 0 src/docs/{user-set_role.txt => user-set-role.txt} | 0 src/php/wp-cli/commands/internals/user.php | 2 ++ 3 files changed, 2 insertions(+) rename src/docs/{user-remove_role.txt => user-remove-role.txt} (100%) rename src/docs/{user-set_role.txt => user-set-role.txt} (100%) diff --git a/src/docs/user-remove_role.txt b/src/docs/user-remove-role.txt similarity index 100% rename from src/docs/user-remove_role.txt rename to src/docs/user-remove-role.txt diff --git a/src/docs/user-set_role.txt b/src/docs/user-set-role.txt similarity index 100% rename from src/docs/user-set_role.txt rename to src/docs/user-set-role.txt diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 5475c9a79..c38e5807c 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -209,6 +209,7 @@ public function generate( $args, $assoc_args ) { /** * Add a user to a blog * + * @subcommand set-role * @synopsis <user-login> [<role>] [--blog=<blog>] **/ public function set_role( $args, $assoc_args ) { @@ -238,6 +239,7 @@ public function set_role( $args, $assoc_args ) { /** * Remove a user from a blog * + * @subcommand remove-role * @synopsis <user-login> **/ public function remove_role( $args, $assoc_args ) { From cc7b0d1b5dc2e904a7d97b9181806a460a583646 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 10:02:25 +0200 Subject: [PATCH 0808/5359] formatting fixes. see #176 --- src/php/wp-cli/commands/internals/user.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 8ea13229b..d0994d54b 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -199,11 +199,11 @@ public function generate( $args, $assoc_args ) { } /** - * Add a user to a blog + * Add a user to a blog. * * @subcommand set-role * @synopsis <user-login> [<role>] [--blog=<blog>] - **/ + */ public function set_role( $args, $assoc_args ) { list( $id_or_login, $role ) = $args; @@ -229,13 +229,12 @@ public function set_role( $args, $assoc_args ) { } /** - * Remove a user from a blog + * Remove a user from a blog. * * @subcommand remove-role * @synopsis <user-login> - **/ + */ public function remove_role( $args, $assoc_args ) { - list( $id_or_login ) = $args; if ( is_numeric( $id_or_login ) ) From a1797019a7b7bddc18d51ade0df7b5d5c48d601c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 10:03:06 +0200 Subject: [PATCH 0809/5359] role is an optional parameter, so don't assume it's always there see #176 --- src/php/wp-cli/commands/internals/user.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index d0994d54b..95a5f7838 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -205,8 +205,7 @@ public function generate( $args, $assoc_args ) { * @synopsis <user-login> [<role>] [--blog=<blog>] */ public function set_role( $args, $assoc_args ) { - - list( $id_or_login, $role ) = $args; + list( $id_or_login ) = $args; if ( is_numeric( $id_or_login ) ) $user = get_user_by( 'id', $id_or_login ); @@ -216,8 +215,7 @@ public function set_role( $args, $assoc_args ) { if ( ! $user ) WP_CLI::error( "Please specify a valid user ID or user login to add to this blog" ); - if ( ! get_role( $role ) ) - $role = get_option( 'default_role' ); + $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); // Multisite if ( function_exists( 'add_user_to_blog' ) ) From b775da1b2d8a225aa6db52bb07119992370f4b1f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 10:05:51 +0200 Subject: [PATCH 0810/5359] add get_user_from_first_arg() helper. see #176 --- src/php/wp-cli/commands/internals/user.php | 32 ++++++++++------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 95a5f7838..6dc80d224 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -205,15 +205,7 @@ public function generate( $args, $assoc_args ) { * @synopsis <user-login> [<role>] [--blog=<blog>] */ public function set_role( $args, $assoc_args ) { - list( $id_or_login ) = $args; - - if ( is_numeric( $id_or_login ) ) - $user = get_user_by( 'id', $id_or_login ); - else - $user = get_user_by( 'login', $id_or_login ); - - if ( ! $user ) - WP_CLI::error( "Please specify a valid user ID or user login to add to this blog" ); + $user = self::get_user_from_first_arg( $args[0] ); $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); @@ -233,15 +225,7 @@ public function set_role( $args, $assoc_args ) { * @synopsis <user-login> */ public function remove_role( $args, $assoc_args ) { - list( $id_or_login ) = $args; - - if ( is_numeric( $id_or_login ) ) - $user = get_user_by( 'id', $id_or_login ); - else - $user = get_user_by( 'login', $id_or_login ); - - if ( ! $user ) - WP_CLI::error( "Please specify a valid user ID or user login to remove from this blog" ); + $user = self::get_user_from_first_arg( $args[0] ); // Multisite if ( function_exists( 'remove_user_from_blog' ) ) @@ -252,4 +236,16 @@ public function remove_role( $args, $assoc_args ) { WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); } + private static function get_user_from_first_arg( $id_or_login ) { + if ( is_numeric( $id_or_login ) ) + $user = get_user_by( 'id', $id_or_login ); + else + $user = get_user_by( 'login', $id_or_login ); + + if ( ! $user ) + WP_CLI::error( "Please specify a valid user ID or user login to remove from this blog" ); + + return $user; + } } + From 06ccc557935a77fea28584ccf643a836d84e8340 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 10:09:22 +0200 Subject: [PATCH 0811/5359] update docs and generate man files. see #176 --- man/user-remove-role.1 | 28 ++++++++++++++++++++++++++++ man/user-set-role.1 | 34 ++++++++++++++++++++++++++++++++++ src/docs/user-remove-role.txt | 5 +++-- src/docs/user-set-role.txt | 5 +++-- 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 man/user-remove-role.1 create mode 100644 man/user-set-role.1 diff --git a/man/user-remove-role.1 b/man/user-remove-role.1 new file mode 100644 index 000000000..ca9a77b0d --- /dev/null +++ b/man/user-remove-role.1 @@ -0,0 +1,28 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-REMOVE\-ROLE" "1" "November 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-remove\-role\fR \- Remove a user from a blog\. +. +.SH "SYNOPSIS" +\fBwp user remove\-role\fR \fIuser\-login\fR +. +.SH "OPTIONS" +. +.TP +\fB<user\-login>\fR: +. +.IP +User ID or user login\. +. +.SH "EXAMPLES" +. +.nf + +wp user remove\-role bob +wp user remove\-role 12 +. +.fi + diff --git a/man/user-set-role.1 b/man/user-set-role.1 new file mode 100644 index 000000000..b73d837c6 --- /dev/null +++ b/man/user-set-role.1 @@ -0,0 +1,34 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-SET\-ROLE" "1" "November 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-set\-role\fR \- Add a user to a blog\. +. +.SH "SYNOPSIS" +\fBwp user set\-role\fR \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] +. +.SH "OPTIONS" +. +.TP +\fB<user\-login>\fR: +. +.IP +User ID or user login\. +. +.TP +\fB[<role>]\fR: +. +.IP +Add the user with the specified role\. Defaults to blog default\. +. +.SH "EXAMPLES" +. +.nf + +wp user set\-role bob author +wp user set\-role 12 author +. +.fi + diff --git a/src/docs/user-remove-role.txt b/src/docs/user-remove-role.txt index f0d6bb6bd..c85990bd4 100644 --- a/src/docs/user-remove-role.txt +++ b/src/docs/user-remove-role.txt @@ -2,8 +2,9 @@ * `<user-login>`: - The login of the user to remove from the blog. + User ID or user login. ## EXAMPLES - wp user remove_role bob + wp user remove-role bob + wp user remove-role 12 diff --git a/src/docs/user-set-role.txt b/src/docs/user-set-role.txt index 042162581..3c5050f0e 100644 --- a/src/docs/user-set-role.txt +++ b/src/docs/user-set-role.txt @@ -2,7 +2,7 @@ * `<user-login>`: - The login of the user to add to the blog. + User ID or user login. * `[<role>]`: @@ -10,4 +10,5 @@ ## EXAMPLES - wp user set_role bob author + wp user set-role bob author + wp user set-role 12 author From 0f06d44f7770bcaf9ab1f3ba7f1c90dab8684fbc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 10 Nov 2012 11:18:24 -0800 Subject: [PATCH 0812/5359] If there was an issue creating the user, kick out of the loop instead of proceeding to the success message https://github.com/wp-cli/wp-cli/pull/201#issuecomment-10252908 --- src/php/wp-cli/commands/internals/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index d4b56d9b5..af4243235 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -246,6 +246,7 @@ public function import_csv( $args, $assoc_args ) { if ( is_wp_error( $user_id ) ) { WP_CLI::warning( $user_id ); + continue; } else { if ( false === $new_user['role'] ) { delete_user_option( $user_id, 'capabilities' ); From d3e65fd08f9aff98626faa59d882b8c9561be0fd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 22:37:35 +0200 Subject: [PATCH 0813/5359] clean up doc and generate man page. see #201 --- man/user-import-csv.1 | 34 ++++++++++++++++++++++ src/docs/user-import-csv.txt | 8 +++-- src/php/wp-cli/commands/internals/user.php | 5 ++-- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 man/user-import-csv.1 diff --git a/man/user-import-csv.1 b/man/user-import-csv.1 new file mode 100644 index 000000000..4c2f7d280 --- /dev/null +++ b/man/user-import-csv.1 @@ -0,0 +1,34 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-USER\-IMPORT\-CSV" "1" "November 2012" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-user\-import\-csv\fR \- Import users from a CSV file\. +. +.SH "SYNOPSIS" +\fBwp user import\-csv\fR \fIfile\fR +. +.SH "OPTIONS" +. +.TP +\fB<file>\fR: +. +.IP +The CSV file of users to import\. +. +.SH "EXAMPLES" +. +.nf + +wp user import\-csv /path/to/users\.csv + +Sample users\.csv file: + +user_login,user_email,display_name,role +bobjones,bobjones@domain\.com,Bob Jones,contributor +newuser1,newuser1@domain\.com,New User,author +existinguser,existinguser@domain\.com,Existing User,administrator +. +.fi + diff --git a/src/docs/user-import-csv.txt b/src/docs/user-import-csv.txt index 6c02912e7..e8963372a 100644 --- a/src/docs/user-import-csv.txt +++ b/src/docs/user-import-csv.txt @@ -2,13 +2,15 @@ * `<file>`: - The csv file of users to import + The CSV file of users to import. ## EXAMPLES - wp user import_csv /path/to/csv.csv + wp user import-csv /path/to/users.csv + + Sample users.csv file: user_login,user_email,display_name,role bobjones,bobjones@domain.com,Bob Jones,contributor newuser1,newuser1@domain.com,New User,author - existinguser,existinguser@domain.com,Existing User,administrator \ No newline at end of file + existinguser,existinguser@domain.com,Existing User,administrator diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 3241d81dd..aaa39ad29 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -249,7 +249,7 @@ private static function get_user_from_first_arg( $id_or_login ) { } /** - * Import users from a CSV + * Import users from a CSV file. * * @subcommand import-csv * @synopsis <file> @@ -304,8 +304,7 @@ public function import_csv( $args, $assoc_args ) { } } - WP_CLI::line( "{$new_user['user_login']} created" ); - + WP_CLI::line( $new_user['user_login'] . " created" ); } } } From c9f45e85b15e88ab6eb3fdcf5f1be9cd20d0ca5e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 23:18:58 +0200 Subject: [PATCH 0814/5359] extract WP_CLI::parse_args() helper --- src/php/wp-cli/class-wp-cli.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 9a4eaf57d..13930c0d6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -231,12 +231,7 @@ static function load_command( $command ) { return self::$commands[$command]; } - static function before_wp_load() { - self::add_man_dir( - WP_CLI_ROOT . "../../../man/", - WP_CLI_ROOT . "../../docs/" - ); - + private static function parse_args() { $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( self::$arguments, self::$assoc_args ) = $r; @@ -245,8 +240,19 @@ static function before_wp_load() { 'path', 'url', 'blog', 'user', 'require', 'quiet', 'completions', 'man', 'syn-list' ) ); + } - define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + static function get_assoc_special() { + return self::$assoc_special; + } + + static function before_wp_load() { + self::add_man_dir( + WP_CLI_ROOT . "../../../man/", + WP_CLI_ROOT . "../../docs/" + ); + + self::parse_args(); // Handle --version parameter if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { @@ -254,6 +260,8 @@ static function before_wp_load() { exit; } + define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + $_SERVER['DOCUMENT_ROOT'] = getcwd(); // Handle --path @@ -289,10 +297,6 @@ static function before_wp_load() { } } - static function get_assoc_special() { - return self::$assoc_special; - } - static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); From ab053e6f8601c3778c1b568bac686020f141ce86 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 23:22:16 +0200 Subject: [PATCH 0815/5359] add back --help flag --- src/php/wp-cli/class-wp-cli.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 13930c0d6..cbc59bcc4 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -236,6 +236,11 @@ private static function parse_args() { list( self::$arguments, self::$assoc_args ) = $r; + if ( isset( self::$assoc_args['help'] ) ) { + array_unshift( self::$arguments, 'help' ); + unset( self::$assoc_args['help'] ); + } + self::$assoc_special = Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', 'quiet', 'completions', 'man', 'syn-list' From 20625bd49f3009765628b41baa61b23bda756952 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 23:56:17 +0200 Subject: [PATCH 0816/5359] don't show date when the man page was last generated --- src/php/wp-cli/man.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index b2cc46710..515a88c6c 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -81,7 +81,13 @@ function call_ronn( $markdown, $dest ) { 2 => STDERR ); - $r = proc_close( proc_open( "ronn --roff --manual='WP-CLI'", $descriptorspec, $pipes ) ); + $cmd = "ronn --date=2012-01-01 --roff --manual='WP-CLI'"; + + $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); + + $roff = file_get_contents( $dest ); + $roff = str_replace( ' "January 2012"', '', $roff ); + file_put_contents( $dest, $roff ); \WP_CLI::line( "generated " . basename( $dest ) ); } From a9180270d4d1d7953de8b54bc5a18a1d2dd0d971 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Nov 2012 23:57:53 +0200 Subject: [PATCH 0817/5359] re-generate all man pages --- man/blog-create.1 | 2 +- man/blog-delete.1 | 2 +- man/cache.1 | 2 +- man/comment-approve.1 | 2 +- man/comment-count.1 | 2 +- man/comment-create.1 | 2 +- man/comment-delete.1 | 2 +- man/comment-last.1 | 2 +- man/comment-spam.1 | 2 +- man/comment-status.1 | 2 +- man/comment-trash.1 | 2 +- man/comment-unapprove.1 | 2 +- man/comment-unspam.1 | 2 +- man/comment-untrash.1 | 2 +- man/core-config.1 | 2 +- man/core-download.1 | 2 +- man/core-install-network.1 | 2 +- man/core-install.1 | 2 +- man/core-is-installed.1 | 2 +- man/core-update.1 | 2 +- man/core-version.1 | 2 +- man/db-drop.1 | 2 +- man/db-export.1 | 2 +- man/db-import.1 | 2 +- man/db-query.1 | 2 +- man/db-reset.1 | 2 +- man/eval-file.1 | 2 +- man/eval.1 | 2 +- man/export.1 | 2 +- man/option.1 | 2 +- man/plugin-activate.1 | 2 +- man/plugin-deactivate.1 | 2 +- man/plugin-delete.1 | 2 +- man/plugin-install.1 | 2 +- man/plugin-path.1 | 2 +- man/plugin-status.1 | 2 +- man/plugin-toggle.1 | 2 +- man/plugin-uninstall.1 | 2 +- man/plugin-update.1 | 2 +- man/post-create.1 | 2 +- man/post-delete.1 | 2 +- man/post-generate.1 | 2 +- man/post-list.1 | 2 +- man/post-meta.1 | 2 +- man/post-update.1 | 2 +- man/rewrite-dump.1 | 2 +- man/rewrite-flush.1 | 2 +- man/rewrite-structure.1 | 2 +- man/theme-activate.1 | 2 +- man/theme-delete.1 | 2 +- man/theme-install.1 | 2 +- man/theme-path.1 | 2 +- man/theme-status.1 | 2 +- man/theme-update.1 | 2 +- man/transient.1 | 2 +- man/user-create.1 | 2 +- man/user-delete.1 | 2 +- man/user-generate.1 | 2 +- man/user-import-csv.1 | 2 +- man/user-list.1 | 2 +- man/user-meta.1 | 2 +- man/user-remove-role.1 | 2 +- man/user-set-role.1 | 2 +- man/user-update.1 | 2 +- 64 files changed, 64 insertions(+), 64 deletions(-) diff --git a/man/blog-create.1 b/man/blog-create.1 index 0245da7c1..7e30d4d82 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-CREATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-BLOG\-CREATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-blog\-create\fR \- Create a blog in a multisite install\. diff --git a/man/blog-delete.1 b/man/blog-delete.1 index 556bb95c7..da5747d99 100644 --- a/man/blog-delete.1 +++ b/man/blog-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-BLOG\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-blog\-delete\fR \- Delete a blog in a multisite install\. diff --git a/man/cache.1 b/man/cache.1 index 0788dfb51..c0d6cde14 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CACHE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CACHE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-cache\fR \- Manage WordPress the object cache\. diff --git a/man/comment-approve.1 b/man/comment-approve.1 index 06ecb02c8..2f05beb71 100644 --- a/man/comment-approve.1 +++ b/man/comment-approve.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-APPROVE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-APPROVE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-approve\fR \- Approve a comment\. diff --git a/man/comment-count.1 b/man/comment-count.1 index eda8c40ae..499179b7d 100644 --- a/man/comment-count.1 +++ b/man/comment-count.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-COUNT" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-COUNT" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-count\fR \- Count comments, on whole blog or on a given post\. diff --git a/man/comment-create.1 b/man/comment-create.1 index 2d7510f36..72b010be5 100644 --- a/man/comment-create.1 +++ b/man/comment-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-CREATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-CREATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-create\fR \- Insert a comment\. diff --git a/man/comment-delete.1 b/man/comment-delete.1 index 14f31ffec..7a90702d1 100644 --- a/man/comment-delete.1 +++ b/man/comment-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-delete\fR \- Delete a comment\. diff --git a/man/comment-last.1 b/man/comment-last.1 index 298df1486..9f0ceb298 100644 --- a/man/comment-last.1 +++ b/man/comment-last.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-LAST" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-LAST" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-last\fR \- Get last approved comment\. diff --git a/man/comment-spam.1 b/man/comment-spam.1 index ab667d8ca..780872b1a 100644 --- a/man/comment-spam.1 +++ b/man/comment-spam.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-SPAM" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-SPAM" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-spam\fR \- Spam a comment\. diff --git a/man/comment-status.1 b/man/comment-status.1 index a9256af37..556f6ad27 100644 --- a/man/comment-status.1 +++ b/man/comment-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-STATUS" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-STATUS" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-status\fR \- Get status of a comment\. diff --git a/man/comment-trash.1 b/man/comment-trash.1 index 0b9cdbe2e..282d82341 100644 --- a/man/comment-trash.1 +++ b/man/comment-trash.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-TRASH" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-TRASH" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-trash\fR \- Trash a comment\. diff --git a/man/comment-unapprove.1 b/man/comment-unapprove.1 index 01a7ae93c..986377f42 100644 --- a/man/comment-unapprove.1 +++ b/man/comment-unapprove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNAPPROVE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNAPPROVE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-unapprove\fR \- Unapprove a comment\. diff --git a/man/comment-unspam.1 b/man/comment-unspam.1 index 6b64e907d..ce9c72b99 100644 --- a/man/comment-unspam.1 +++ b/man/comment-unspam.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNSPAM" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNSPAM" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-unspam\fR \- Unspam a comment\. diff --git a/man/comment-untrash.1 b/man/comment-untrash.1 index 7b62bfec3..ec9735a93 100644 --- a/man/comment-untrash.1 +++ b/man/comment-untrash.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-COMMENT\-UNTRASH" "1" "October 2012" "" "WP-CLI" +.TH "WP\-COMMENT\-UNTRASH" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-comment\-untrash\fR \- Untrash a comment\. diff --git a/man/core-config.1 b/man/core-config.1 index adb58494c..c950991e2 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-CONFIG" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-CONFIG" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. diff --git a/man/core-download.1 b/man/core-download.1 index a654552f0..02414cb40 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-DOWNLOAD" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-DOWNLOAD" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-download\fR \- Download core WordPress files\. diff --git a/man/core-install-network.1 b/man/core-install-network.1 index f7bb75355..d76fc582d 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL\-NETWORK" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL\-NETWORK" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. diff --git a/man/core-install.1 b/man/core-install.1 index 6eda4897c..7a5e0b9a9 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-INSTALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-INSTALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-install\fR \- Create the WordPress tables in the database\. diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 index f2e27234a..76a37ddda 100644 --- a/man/core-is-installed.1 +++ b/man/core-is-installed.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-IS\-INSTALLED" "1" "November 2012" "" "WP-CLI" +.TH "WP\-CORE\-IS\-INSTALLED" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-is\-installed\fR \- Determine if the WordPress tables are installed\. diff --git a/man/core-update.1 b/man/core-update.1 index aa7cd22e4..4d69900ae 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update\fR \- Update WordPress\. diff --git a/man/core-version.1 b/man/core-version.1 index bb3bf3ca4..4e9599f47 100644 --- a/man/core-version.1 +++ b/man/core-version.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-VERSION" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-VERSION" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-version\fR \- Display the WordPress version\. diff --git a/man/db-drop.1 b/man/db-drop.1 index d84934d27..3a0a06b65 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-DROP" "1" "October 2012" "" "WP-CLI" +.TH "WP\-DB\-DROP" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-drop\fR \- Delete the database\. diff --git a/man/db-export.1 b/man/db-export.1 index e4bbc6301..5dd630142 100644 --- a/man/db-export.1 +++ b/man/db-export.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-EXPORT" "1" "October 2012" "" "WP-CLI" +.TH "WP\-DB\-EXPORT" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-export\fR \- Exports the database using mysqldump\. diff --git a/man/db-import.1 b/man/db-import.1 index 456e821c4..c98ce4f70 100644 --- a/man/db-import.1 +++ b/man/db-import.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-IMPORT" "1" "October 2012" "" "WP-CLI" +.TH "WP\-DB\-IMPORT" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-import\fR \- Import database from a file\. diff --git a/man/db-query.1 b/man/db-query.1 index c8cd72887..db0962429 100644 --- a/man/db-query.1 +++ b/man/db-query.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-QUERY" "1" "October 2012" "" "WP-CLI" +.TH "WP\-DB\-QUERY" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-query\fR \- Execute a query against the database\. diff --git a/man/db-reset.1 b/man/db-reset.1 index d1c50d27c..f8ca22aa8 100644 --- a/man/db-reset.1 +++ b/man/db-reset.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-DB\-RESET" "1" "October 2012" "" "WP-CLI" +.TH "WP\-DB\-RESET" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-db\-reset\fR \- Remove all tables from the database\. diff --git a/man/eval-file.1 b/man/eval-file.1 index 6ca9e6d26..bfcb67454 100644 --- a/man/eval-file.1 +++ b/man/eval-file.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL\-FILE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-EVAL\-FILE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. diff --git a/man/eval.1 b/man/eval.1 index 8889e5f51..558bf38e7 100644 --- a/man/eval.1 +++ b/man/eval.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EVAL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-EVAL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. diff --git a/man/export.1 b/man/export.1 index b58032826..5a3d58584 100644 --- a/man/export.1 +++ b/man/export.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-EXPORT" "1" "November 2012" "" "WP-CLI" +.TH "WP\-EXPORT" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-export\fR \- Export posts to a WXR file\. diff --git a/man/option.1 b/man/option.1 index 678c77b48..b333c9119 100644 --- a/man/option.1 +++ b/man/option.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-OPTION" "1" "September 2012" "" "WP-CLI" +.TH "WP\-OPTION" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-option\fR \- Manage WordPress options\. diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index b4e9fce6a..489019db5 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-ACTIVATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-ACTIVATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-activate\fR \- Activate a plugin\. diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 index 17a87783e..6b435292c 100644 --- a/man/plugin-deactivate.1 +++ b/man/plugin-deactivate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DEACTIVATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-deactivate\fR \- Deactivate a plugin\. diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 index b89c7ab09..3c77f7e85 100644 --- a/man/plugin-delete.1 +++ b/man/plugin-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-delete\fR \- Delete plugin files\. diff --git a/man/plugin-install.1 b/man/plugin-install.1 index 18a07e6d2..af58aea05 100644 --- a/man/plugin-install.1 +++ b/man/plugin-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-INSTALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-INSTALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-install\fR \- Install a plugin\. diff --git a/man/plugin-path.1 b/man/plugin-path.1 index d8888628c..fe019d718 100644 --- a/man/plugin-path.1 +++ b/man/plugin-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-PATH" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-PATH" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. diff --git a/man/plugin-status.1 b/man/plugin-status.1 index 305f7902b..cb7f9b00d 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-STATUS" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-STATUS" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index fdfd9bf61..532fb87bd 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-TOGGLE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-TOGGLE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-toggle\fR \- Toggle a plugin\'s activation state\. diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 index 0690bc46b..b837b52ef 100644 --- a/man/plugin-uninstall.1 +++ b/man/plugin-uninstall.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UNINSTALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UNINSTALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-uninstall\fR \- Uninstall a plugin\. diff --git a/man/plugin-update.1 b/man/plugin-update.1 index 43d0d5705..13a769112 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UPDATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-update\fR \- Update a plugin\. diff --git a/man/post-create.1 b/man/post-create.1 index 4d7ca0460..76536d6e3 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-CREATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-POST\-CREATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-create\fR \- Create a post\. diff --git a/man/post-delete.1 b/man/post-delete.1 index f2ef6523e..45a8fa30a 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-POST\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-delete\fR \- Delete a post by ID\. diff --git a/man/post-generate.1 b/man/post-generate.1 index 93969834d..6fa88536d 100644 --- a/man/post-generate.1 +++ b/man/post-generate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-GENERATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-POST\-GENERATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-generate\fR \- Generate some posts\. diff --git a/man/post-list.1 b/man/post-list.1 index e35e8d6fa..c965fc51f 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-LIST" "1" "October 2012" "" "WP-CLI" +.TH "WP\-POST\-LIST" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-list\fR \- Get a list of posts\. diff --git a/man/post-meta.1 b/man/post-meta.1 index 6107d180a..97e825319 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-META" "1" "September 2012" "" "WP-CLI" +.TH "WP\-POST\-META" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-meta\fR \- Manage post custom fields\. diff --git a/man/post-update.1 b/man/post-update.1 index abadef4a0..fc8249fae 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-POST\-UPDATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-POST\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-post\-update\fR \- Update a post\. diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 index 8b7432011..80d34e073 100644 --- a/man/rewrite-dump.1 +++ b/man/rewrite-dump.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-REWRITE\-DUMP" "1" "October 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-DUMP" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-rewrite\-dump\fR \- Print current rewrite rules\. diff --git a/man/rewrite-flush.1 b/man/rewrite-flush.1 index f7ba485be..db0163863 100644 --- a/man/rewrite-flush.1 +++ b/man/rewrite-flush.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-REWRITE\-FLUSH" "1" "October 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-FLUSH" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-rewrite\-flush\fR \- Flush rewrite rules\. diff --git a/man/rewrite-structure.1 b/man/rewrite-structure.1 index 8589c5ca9..9775f55c3 100644 --- a/man/rewrite-structure.1 +++ b/man/rewrite-structure.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-REWRITE\-STRUCTURE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-REWRITE\-STRUCTURE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-rewrite\-structure\fR \- Update the permalink structure\. diff --git a/man/theme-activate.1 b/man/theme-activate.1 index cb545a291..b408317f0 100644 --- a/man/theme-activate.1 +++ b/man/theme-activate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-ACTIVATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-ACTIVATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-activate\fR \- Activate a theme\. diff --git a/man/theme-delete.1 b/man/theme-delete.1 index 7bf993510..6d82f601a 100644 --- a/man/theme-delete.1 +++ b/man/theme-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-delete\fR \- Delete a theme\. diff --git a/man/theme-install.1 b/man/theme-install.1 index 96ea741d4..2665ed671 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-INSTALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-INSTALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-install\fR \- Install a theme\. diff --git a/man/theme-path.1 b/man/theme-path.1 index 64275161f..87a2c0dc7 100644 --- a/man/theme-path.1 +++ b/man/theme-path.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-PATH" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-PATH" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. diff --git a/man/theme-status.1 b/man/theme-status.1 index e7b10fd12..576c274ae 100644 --- a/man/theme-status.1 +++ b/man/theme-status.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-STATUS" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-STATUS" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-status\fR \- See the status of one or all themes\. diff --git a/man/theme-update.1 b/man/theme-update.1 index b186f1f81..9f5ec07d8 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-UPDATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-update\fR \- Update a theme\. diff --git a/man/transient.1 b/man/transient.1 index 0d10b8a23..10077576e 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-TRANSIENT" "1" "September 2012" "" "WP-CLI" +.TH "WP\-TRANSIENT" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-transient\fR \- Manage WordPress transients\. diff --git a/man/user-create.1 b/man/user-create.1 index 9f98d4296..99e2fd964 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-CREATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-USER\-CREATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-create\fR \- Create a user\. diff --git a/man/user-delete.1 b/man/user-delete.1 index 5f76a774a..b9b44d191 100644 --- a/man/user-delete.1 +++ b/man/user-delete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-DELETE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-USER\-DELETE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-delete\fR \- Delete a user\. diff --git a/man/user-generate.1 b/man/user-generate.1 index faa3c7bd1..6e6bd5447 100644 --- a/man/user-generate.1 +++ b/man/user-generate.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-GENERATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-USER\-GENERATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-generate\fR \- Generate users\. diff --git a/man/user-import-csv.1 b/man/user-import-csv.1 index 4c2f7d280..7f8e09d26 100644 --- a/man/user-import-csv.1 +++ b/man/user-import-csv.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-IMPORT\-CSV" "1" "November 2012" "" "WP-CLI" +.TH "WP\-USER\-IMPORT\-CSV" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-import\-csv\fR \- Import users from a CSV file\. diff --git a/man/user-list.1 b/man/user-list.1 index c55e48fdd..b5bba57b7 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-LIST" "1" "October 2012" "" "WP-CLI" +.TH "WP\-USER\-LIST" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-list\fR \- List users\. diff --git a/man/user-meta.1 b/man/user-meta.1 index 73130d87e..4a2ab314e 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-META" "1" "September 2012" "" "WP-CLI" +.TH "WP\-USER\-META" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-meta\fR \- Manage user custom fields\. diff --git a/man/user-remove-role.1 b/man/user-remove-role.1 index ca9a77b0d..ffa374538 100644 --- a/man/user-remove-role.1 +++ b/man/user-remove-role.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-REMOVE\-ROLE" "1" "November 2012" "" "WP-CLI" +.TH "WP\-USER\-REMOVE\-ROLE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-remove\-role\fR \- Remove a user from a blog\. diff --git a/man/user-set-role.1 b/man/user-set-role.1 index b73d837c6..c4b99a980 100644 --- a/man/user-set-role.1 +++ b/man/user-set-role.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-SET\-ROLE" "1" "November 2012" "" "WP-CLI" +.TH "WP\-USER\-SET\-ROLE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-set\-role\fR \- Add a user to a blog\. diff --git a/man/user-update.1 b/man/user-update.1 index 2cf19a5ec..1e0a7ebc0 100644 --- a/man/user-update.1 +++ b/man/user-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-USER\-UPDATE" "1" "October 2012" "" "WP-CLI" +.TH "WP\-USER\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-user\-update\fR \- Update a user\. From 940a00e5d9070a10291ae4b2b1218e748c44e553 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Nov 2012 20:33:37 +0200 Subject: [PATCH 0818/5359] bump version to 0.7.0-beta --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 295dadc4a..5723b4046 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.7.0-alpha' ); +define( 'WP_CLI_VERSION', '0.7.0-beta' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 92ae99396edd454f2739e2f68b183cdb180eee12 Mon Sep 17 00:00:00 2001 From: Andreas Creten <andreas@madewithlove.be> Date: Tue, 13 Nov 2012 20:12:13 +0100 Subject: [PATCH 0819/5359] Updated README --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b2888d0f7..afd2cd42d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,23 @@ -wp-cli is a set of command-line tools for managing WordPress installations. +WP-CLI +======== +wp-cli is a set of command-line tools for managing WordPress installations. -For documentation, usage, and examples, see: -http://wp-cli.org/ +Where can I get more info? +-------------------------- +For documentation, usage, and examples, check out [wp-cli.org](http://wp-cli.org/). -To suggest a feature, report a bug, or general discussion: -https://github.com/wp-cli/wp-cli/issues +I'm running into troubles, what can I do? +----------------------------------------- -All contributors are listed here: -https://github.com/wp-cli/wp-cli/contributors +To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). + +Who's behind this thing? +------------------------ + +We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. + +A complete list of contibuters can be found [here](https://github.com/wp-cli/wp-cli/contributors). + +Need even more info? +-------------------- +Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). \ No newline at end of file From c100e6ec619873f94ff4c03531c84208904a4d1a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Nov 2012 21:14:08 +0200 Subject: [PATCH 0820/5359] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afd2cd42d..a2c308769 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Who's behind this thing? We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. -A complete list of contibuters can be found [here](https://github.com/wp-cli/wp-cli/contributors). +A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). Need even more info? -------------------- From 44a0db8b8ff1fb24ffdb17edb14bd57286ceb80f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Nov 2012 10:33:35 +0200 Subject: [PATCH 0821/5359] add link to wp-cli-commits mailing list --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a2c308769..1095531af 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,6 @@ A complete list of contributors can be found [here](https://github.com/wp-cli/wp Need even more info? -------------------- -Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). \ No newline at end of file +Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). + +If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. From 43106793fd366f7241fd687d03ba3a90f67487e0 Mon Sep 17 00:00:00 2001 From: Andreas Creten <andreas@madewithlove.be> Date: Wed, 14 Nov 2012 20:15:44 +0100 Subject: [PATCH 0822/5359] Changed order of php lookup in find-php, give priority to custom ones --- utils/find-php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/find-php b/utils/find-php index 6c4d115cf..e1a82c470 100755 --- a/utils/find-php +++ b/utils/find-php @@ -1,11 +1,5 @@ #!/usr/bin/env sh -which php || which php-cli - -if [ $? -eq 0 ]; then - exit -fi - # Special case for *AMP installers, since they normally don't set themselves # as the default cli php out of the box. for amp_php in $(cat $(dirname $0)/amp-paths.txt); do @@ -15,5 +9,11 @@ for amp_php in $(cat $(dirname $0)/amp-paths.txt); do fi done +which php || which php-cli + +if [ $? -eq 0 ]; then + exit +fi + echo "no php binary found" exit 1 From 9285bde6804d71d068f292d7a3c6a0c5a637c1b6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 14:05:43 +0200 Subject: [PATCH 0823/5359] remove support for default subcommands it had an inelegant implementation and it made for an inconsistent user experience --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 4 ---- src/php/wp-cli/class-wp-cli-command.php | 4 ---- src/php/wp-cli/commands/internals/db.php | 4 ---- src/php/wp-cli/dispatcher.php | 8 +------- 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index b4953557e..13c7d1105 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -2,10 +2,6 @@ abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { - public static function get_default_subcommand() { - return 'status'; - } - protected $item_type; protected $upgrader; protected $upgrade_refresh; diff --git a/src/php/wp-cli/class-wp-cli-command.php b/src/php/wp-cli/class-wp-cli-command.php index 0bd4e1247..0cccc51a4 100644 --- a/src/php/wp-cli/class-wp-cli-command.php +++ b/src/php/wp-cli/class-wp-cli-command.php @@ -7,10 +7,6 @@ */ abstract class WP_CLI_Command { - public static function get_default_subcommand() { - return false; - } - public function __construct() {} } diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 72c27d201..de4f35bc4 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -10,10 +10,6 @@ */ class DB_Command extends WP_CLI_Command { - public static function get_default_subcommand() { - return 'cli'; - } - /** * Create the database, as specified in wp-config.php */ diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index a6e92b2a1..4c4cde169 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -144,13 +144,7 @@ function invoke( $args, $assoc_args ) { } function find_subcommand( &$args ) { - $class = $this->class; - - if ( empty( $args ) ) { - $name = $class::get_default_subcommand(); - } else { - $name = array_shift( $args ); - } + $name = array_shift( $args ); $subcommands = $this->get_subcommands(); From f45e0065bda96770f81363a187f1ecdfde20143b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 14:16:49 +0200 Subject: [PATCH 0824/5359] use parent->get_path() instead of accessing parent->name directly --- src/php/wp-cli/dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 4c4cde169..0dba97862 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -373,7 +373,7 @@ function __construct( $method, $parent ) { } function get_path() { - return array( $this->parent->name, $this->get_name() ); + return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); } private function get_tag( $name ) { From ceb02ee7086d7b6fdc1e5a02a004f019f3dd643a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 14:28:16 +0200 Subject: [PATCH 0825/5359] hoist get_path() method up to Subcommand class --- src/php/wp-cli/class-wp-cli.php | 11 +++++++---- src/php/wp-cli/dispatcher.php | 28 ++++++++++------------------ 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index cbc59bcc4..bc9a550bd 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -10,7 +10,10 @@ */ class WP_CLI { + public static $root; + private static $commands = array(); + private static $man_dirs = array(); private static $arguments, $assoc_args, $assoc_special; @@ -24,7 +27,7 @@ static function add_command( $name, $implementation ) { if ( is_string( $implementation ) ) $command = new Dispatcher\CompositeCommand( $name, $implementation ); else - $command = new Dispatcher\SingleCommand( $name, $implementation ); + $command = new Dispatcher\SingleCommand( $name, $implementation, self::$root ); self::$commands[ $name ] = $command; } @@ -340,9 +343,7 @@ static function after_wp_load() { } private static function run_command() { - $root = new Dispatcher\RootCommand; - - $root->invoke( self::$arguments, self::$assoc_args ); + self::$root->invoke( self::$arguments, self::$assoc_args ); } private static function generate_man( $args ) { @@ -369,3 +370,5 @@ static function addCommand( $name, $class ) { } } +WP_CLI::$root = new Dispatcher\RootCommand; + diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 0dba97862..481a656cb 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -5,7 +5,7 @@ function traverse( &$args ) { $args_copy = $args; - $command = new RootCommand; + $command = \WP_CLI::$root; while ( !empty( $args ) && $command && $command instanceof Composite ) { $command = $command->find_subcommand( $args ); @@ -199,7 +199,9 @@ private static function _is_good_method( $method ) { abstract class Subcommand implements Command, Documentable { - function __construct( $method ) { + function __construct( $method, $parent ) { + $this->parent = $parent; + $this->method = $method; } @@ -214,6 +216,10 @@ function get_subcommands() { return array(); } + function get_path() { + return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); + } + abstract function get_name(); protected function check_args( $args, $assoc_args ) { @@ -366,16 +372,6 @@ private static function get_patterns() { class MethodSubcommand extends Subcommand { - function __construct( $method, $parent ) { - $this->parent = $parent; - - parent::__construct( $method ); - } - - function get_path() { - return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); - } - private function get_tag( $name ) { $comment = $this->method->getDocComment(); @@ -409,23 +405,19 @@ function invoke( $args, $assoc_args ) { class SingleCommand extends Subcommand { - function __construct( $name, $callable ) { + function __construct( $name, $callable, $parent ) { $this->name = $name; $this->callable = $callable; $method = new \ReflectionMethod( $this->callable, '__invoke' ); - parent::__construct( $method ); + parent::__construct( $method, $parent ); } function get_name() { return $this->name; } - function get_path() { - return array( $this->name ); - } - function invoke( $args, $assoc_args ) { $this->check_args( $args, $assoc_args ); From c4bd5ec5ed70521623c823f75801e4f694837cb7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 14:55:32 +0200 Subject: [PATCH 0826/5359] collect subcommands in the constructor, not in find_subcommand() --- src/php/wp-cli/dispatcher.php | 79 +++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 481a656cb..2f7343bf6 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -108,9 +108,31 @@ function get_subcommands() { class CompositeCommand implements Command, Composite { - function __construct( $name, $class ) { + protected $name; + + protected $subcommands; + + public function __construct( $name, $class ) { $this->name = $name; - $this->class = $class; + + $this->subcommands = $this->collect_subcommands( $class ); + } + + private function collect_subcommands( $class ) { + $reflection = new \ReflectionClass( $class ); + + $subcommands = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( !self::_is_good_method( $method ) ) + continue; + + $subcommand = new MethodSubcommand( $class, $method, $this ); + + $subcommands[ $subcommand->get_name() ] = $subcommand; + } + + return $subcommands; } function get_path() { @@ -175,20 +197,7 @@ private static function get_aliases( $subcommands ) { } public function get_subcommands() { - $reflection = new \ReflectionClass( $this->class ); - - $subcommands = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !self::_is_good_method( $method ) ) - continue; - - $subcommand = new MethodSubcommand( $method, $this ); - - $subcommands[ $subcommand->get_name() ] = $subcommand; - } - - return $subcommands; + return $this->subcommands; } private static function _is_good_method( $method ) { @@ -199,10 +208,10 @@ private static function _is_good_method( $method ) { abstract class Subcommand implements Command, Documentable { - function __construct( $method, $parent ) { - $this->parent = $parent; - + function __construct( $callable, $method, $parent ) { + $this->callable = $callable; $this->method = $method; + $this->parent = $parent; } function show_usage( $prefix = 'usage: ' ) { @@ -212,6 +221,12 @@ function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . "wp $full_name $synopsis" ); } + function invoke( $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + + call_user_func( $this->callable, $args, $assoc_args ); + } + function get_subcommands() { return array(); } @@ -372,6 +387,12 @@ private static function get_patterns() { class MethodSubcommand extends Subcommand { + function __construct( $class, $method, $parent ) { + $callable = array( new $class, $method->name ); + + parent::__construct( $callable, $method, $parent ); + } + private function get_tag( $name ) { $comment = $this->method->getDocComment(); @@ -391,15 +412,6 @@ function get_name() { function get_alias() { return $this->get_tag( 'alias' ); } - - function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - - $class = $this->parent->class; - $instance = new $class; - - $this->method->invoke( $instance, $args, $assoc_args ); - } } @@ -407,21 +419,14 @@ class SingleCommand extends Subcommand { function __construct( $name, $callable, $parent ) { $this->name = $name; - $this->callable = $callable; - $method = new \ReflectionMethod( $this->callable, '__invoke' ); + $method = new \ReflectionMethod( $callable, '__invoke' ); - parent::__construct( $method, $parent ); + parent::__construct( $callable, $method, $parent ); } function get_name() { return $this->name; } - - function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - - $this->method->invoke( $this->callable, $args, $assoc_args ); - } } From f434aafb9ddd348395f51787d330e5f739f695b8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 15:49:14 +0200 Subject: [PATCH 0827/5359] store commands in RootCommand instead of on WP_CLI --- src/php/wp-cli/class-wp-cli.php | 47 ++---------------------------- src/php/wp-cli/dispatcher.php | 51 +++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index bc9a550bd..7798ba50e 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -12,8 +12,6 @@ class WP_CLI { public static $root; - private static $commands = array(); - private static $man_dirs = array(); private static $arguments, $assoc_args, $assoc_special; @@ -24,12 +22,7 @@ class WP_CLI { * @param string|object $implementation The command implementation */ static function add_command( $name, $implementation ) { - if ( is_string( $implementation ) ) - $command = new Dispatcher\CompositeCommand( $name, $implementation ); - else - $command = new Dispatcher\SingleCommand( $name, $implementation, self::$root ); - - self::$commands[ $name ] = $command; + self::$root->add_command( $name, $implementation ); } static function add_man_dir( $dest_dir, $src_dir ) { @@ -200,40 +193,6 @@ static function launch( $command, $exit_on_error = true ) { return $r; } - static function load_all_commands() { - foreach ( array( 'internals', 'community' ) as $dir ) { - foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { - $command = substr( basename( $filename ), 0, -4 ); - - if ( isset( self::$commands[ $command ] ) ) - continue; - - include $filename; - } - } - - return self::$commands; - } - - static function load_command( $command ) { - if ( !isset( self::$commands[$command] ) ) { - foreach ( array( 'internals', 'community' ) as $dir ) { - $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; - - if ( is_readable( $path ) ) { - include $path; - break; - } - } - } - - if ( !isset( self::$commands[$command] ) ) { - return false; - } - - return self::$commands[$command]; - } - private static function parse_args() { $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -323,7 +282,7 @@ static function after_wp_load() { // Handle --syn-list parameter if ( isset( self::$assoc_special['syn-list'] ) ) { - foreach ( self::load_all_commands() as $command ) { + foreach ( self::$root->get_subcommands() as $command ) { if ( $command instanceof \WP_CLI\Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) $subcommand->show_usage( '' ); @@ -357,7 +316,7 @@ private static function generate_man( $args ) { } private static function render_automcomplete() { - foreach ( self::load_all_commands() as $name => $command ) { + foreach ( self::$root->get_subcommands() as $name => $command ) { $subcommands = $command->get_subcommands(); self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 2f7343bf6..135e2becc 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -43,6 +43,8 @@ function get_synopsis(); class RootCommand implements Command, Composite { + protected $subcommands = array(); + function get_path() { return array(); } @@ -50,7 +52,7 @@ function get_path() { function show_usage() { \WP_CLI::line( 'Available commands:' ); - foreach ( \WP_CLI::load_all_commands() as $command ) { + foreach ( $this->get_subcommands() as $command ) { \WP_CLI::line( sprintf( " wp %s %s", implode( ' ', $command->get_path() ), implode( '|', array_keys( $command->get_subcommands() ) ) @@ -97,11 +99,54 @@ function find_subcommand( &$arguments ) { if ( isset( $aliases[ $command ] ) ) $command = $aliases[ $command ]; - return \WP_CLI::load_command( $command ); + return $this->load_command( $command ); + } + + function add_command( $name, $implementation ) { + if ( is_string( $implementation ) ) + $command = new CompositeCommand( $name, $implementation ); + else + $command = new SingleCommand( $name, $implementation, $this ); + + $this->subcommands[ $name ] = $command; } function get_subcommands() { - return \WP_CLI::load_all_commands(); + $this->load_all_commands(); + + return $this->subcommands; + } + + protected function load_all_commands() { + foreach ( array( 'internals', 'community' ) as $dir ) { + foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { + $command = substr( basename( $filename ), 0, -4 ); + + if ( isset( $this->subcommands[ $command ] ) ) + continue; + + include $filename; + } + } + } + + function load_command( $command ) { + if ( !isset( $this->subcommands[$command] ) ) { + foreach ( array( 'internals', 'community' ) as $dir ) { + $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + + if ( is_readable( $path ) ) { + include $path; + break; + } + } + } + + if ( !isset( $this->subcommands[$command] ) ) { + return false; + } + + return $this->subcommands[$command]; } } From 3613d05b9cab75bf1b7b6c2f63834d504b9b3ecb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 16:05:51 +0200 Subject: [PATCH 0828/5359] shorten path to Composite --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 7798ba50e..5c7b551a9 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -283,7 +283,7 @@ static function after_wp_load() { // Handle --syn-list parameter if ( isset( self::$assoc_special['syn-list'] ) ) { foreach ( self::$root->get_subcommands() as $command ) { - if ( $command instanceof \WP_CLI\Dispatcher\Composite ) { + if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) $subcommand->show_usage( '' ); } else { From 61134ecae758adbc0bbbaefae6a7343054f117a8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 16:06:17 +0200 Subject: [PATCH 0829/5359] calculate method name only once --- src/php/wp-cli/dispatcher.php | 39 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 135e2becc..99358700a 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -253,7 +253,8 @@ private static function _is_good_method( $method ) { abstract class Subcommand implements Command, Documentable { - function __construct( $callable, $method, $parent ) { + function __construct( $name, $callable, $method, $parent ) { + $this->name = $name; $this->callable = $callable; $this->method = $method; $this->parent = $parent; @@ -276,12 +277,14 @@ function get_subcommands() { return array(); } + function get_name() { + return $this->name; + } + function get_path() { return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); } - abstract function get_name(); - protected function check_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); if ( !$synopsis ) @@ -435,11 +438,18 @@ class MethodSubcommand extends Subcommand { function __construct( $class, $method, $parent ) { $callable = array( new $class, $method->name ); - parent::__construct( $callable, $method, $parent ); + parent::__construct( self::_get_name( $method ), $callable, $method, $parent ); } - private function get_tag( $name ) { - $comment = $this->method->getDocComment(); + private static function _get_name( $method ) { + if ( $name = self::get_tag( $method, 'subcommand' ) ) + return $name; + + return $method->name; + } + + private static function get_tag( $method, $name ) { + $comment = $method->getDocComment(); if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $comment, $matches ) ) return $matches[1]; @@ -447,15 +457,8 @@ private function get_tag( $name ) { return false; } - function get_name() { - if ( $name = $this->get_tag( 'subcommand' ) ) - return $name; - - return $this->method->name; - } - function get_alias() { - return $this->get_tag( 'alias' ); + return self::get_tag( $this->method, 'alias' ); } } @@ -463,15 +466,9 @@ function get_alias() { class SingleCommand extends Subcommand { function __construct( $name, $callable, $parent ) { - $this->name = $name; - $method = new \ReflectionMethod( $callable, '__invoke' ); - parent::__construct( $callable, $method, $parent ); - } - - function get_name() { - return $this->name; + parent::__construct( $name, $callable, $method, $parent ); } } From 00f9b3db2bbde09091de11a7cc422b86c5211e11 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Nov 2012 16:09:29 +0200 Subject: [PATCH 0830/5359] dismantle SingleCommand class --- src/php/wp-cli/dispatcher.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 99358700a..810830d79 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -105,8 +105,11 @@ function find_subcommand( &$arguments ) { function add_command( $name, $implementation ) { if ( is_string( $implementation ) ) $command = new CompositeCommand( $name, $implementation ); - else - $command = new SingleCommand( $name, $implementation, $this ); + else { + $method = new \ReflectionMethod( $implementation, '__invoke' ); + + $command = new Subcommand( $name, $implementation, $method, $this ); + } $this->subcommands[ $name ] = $command; } @@ -251,7 +254,7 @@ private static function _is_good_method( $method ) { } -abstract class Subcommand implements Command, Documentable { +class Subcommand implements Command, Documentable { function __construct( $name, $callable, $method, $parent ) { $this->name = $name; @@ -462,13 +465,3 @@ function get_alias() { } } - -class SingleCommand extends Subcommand { - - function __construct( $name, $callable, $parent ) { - $method = new \ReflectionMethod( $callable, '__invoke' ); - - parent::__construct( $name, $callable, $method, $parent ); - } -} - From 91702b5a6d9eefc1cc4871408cc833418dd75a70 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Nov 2012 10:53:11 +0200 Subject: [PATCH 0831/5359] set version to 0.7.0 --- build.properties | 2 +- src/php/wp-cli/wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.properties b/build.properties index 5c51b0ceb..27ad66bce 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=wp-cli.org/pear project.majorVersion=0 -project.minorVersion=6 +project.minorVersion=7 project.patchLevel=0 project.snapshot=false diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 5723b4046..69d4d870a 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.7.0-beta' ); +define( 'WP_CLI_VERSION', '0.7.0' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 0ac2da0bc4518f80e5c37e71734370609c2a67d5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Nov 2012 14:13:40 +0200 Subject: [PATCH 0832/5359] define WP_CLI_QUIET before handling --version. fixes #213 --- src/php/wp-cli/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 5c7b551a9..6a9801ad6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -221,14 +221,14 @@ static function before_wp_load() { self::parse_args(); + define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + // Handle --version parameter if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { self::line( 'wp-cli ' . WP_CLI_VERSION ); exit; } - define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); - $_SERVER['DOCUMENT_ROOT'] = getcwd(); // Handle --path From f436dd1cc631c704e45d131ba5e04d1bcd887b72 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 16 Nov 2012 18:00:39 +0000 Subject: [PATCH 0833/5359] Apply the 'wxr_export_skip_postmeta' filter used in core for skipping post meta --- src/php/wp-cli/commands/internals/export.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index b2578cae2..32b4ff5b4 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -469,12 +469,15 @@ private function export_wp( $args = array() ) { <?php endif; ?> <?php wxr_post_taxonomy(); ?> <?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); - foreach ( $postmeta as $meta ) : if ( $meta->meta_key != '_edit_lock' ) : ?> + foreach ( $postmeta as $meta ) : + if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) + continue; + ?> <wp:postmeta> <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> </wp:postmeta> -<?php endif; endforeach; ?> +<?php endforeach; ?> <?php if ( false === $args['skip_comments'] ): ?> <?php $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); foreach ( $comments as $c ) : ?> From df0c1e7e705dc619d4cd26590b75605d0cee5b85 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Nov 2012 20:24:03 +0200 Subject: [PATCH 0834/5359] bump version to 0.8.0-alpha --- src/php/wp-cli/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index 69d4d870a..c7a3ea82e 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.7.0' ); +define( 'WP_CLI_VERSION', '0.8.0-alpha' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 75732ae6025432025dc942095ccf209eb50e16d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20Burc=C4=83?= <scribu@gmail.com> Date: Sat, 17 Nov 2012 17:27:27 +0200 Subject: [PATCH 0835/5359] uppercase WP-CLI in license text --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 745e84216..bd624ddd0 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ ======================================== -wp-cli is licensed under the MIT License +WP-CLI is licensed under the MIT License ======================================== Copyright (C) 2011-2012 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) From 7a391c2deae82d1e3678447975c14280f07849c1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 20 Nov 2012 05:55:40 +0200 Subject: [PATCH 0836/5359] introduce pre_invoke() method --- src/php/wp-cli/class-wp-cli.php | 3 ++- src/php/wp-cli/dispatcher.php | 37 +++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 6a9801ad6..062692b6d 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -302,7 +302,8 @@ static function after_wp_load() { } private static function run_command() { - self::$root->invoke( self::$arguments, self::$assoc_args ); + $command = Dispatcher\traverse( self::$arguments, 'pre_invoke' ); + $command->invoke( self::$arguments, self::$assoc_args ); } private static function generate_man( $args ) { diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 810830d79..0b97691f5 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -2,13 +2,13 @@ namespace WP_CLI\Dispatcher; -function traverse( &$args ) { +function traverse( &$args, $method = 'find_subcommand' ) { $args_copy = $args; $command = \WP_CLI::$root; while ( !empty( $args ) && $command && $command instanceof Composite ) { - $command = $command->find_subcommand( $args ); + $command = $command->$method( $args ); } if ( !$command ) @@ -24,13 +24,14 @@ function get_path(); function get_subcommands(); function show_usage(); - function invoke( $arguments, $assoc_args ); + function invoke( $args, $assoc_args ); } interface Composite { - function find_subcommand( &$arguments ); + function pre_invoke( &$args ); + function find_subcommand( &$args ); } @@ -74,23 +75,28 @@ function show_usage() { ); } - function invoke( $arguments, $assoc_args ) { - if ( empty( $arguments ) || array( 'help' ) == $arguments ) { + function invoke( $args, $assoc_args ) { + $subcommand = $this->pre_invoke( $args ); + $subcommand->invoke( $args, $assoc_args ); + } + + function pre_invoke( &$args ) { + if ( empty( $args ) || array( 'help' ) == $args ) { $this->show_usage(); exit; } - $cmd_name = $arguments[0]; - $command = $this->find_subcommand( $arguments ); + $cmd_name = $args[0]; + $command = $this->find_subcommand( $args ); if ( !$command ) \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $cmd_name ) ); - $command->invoke( $arguments, $assoc_args ); + return $command; } - function find_subcommand( &$arguments ) { - $command = array_shift( $arguments ); + function find_subcommand( &$args ) { + $command = array_shift( $args ); $aliases = array( 'sql' => 'db' @@ -203,14 +209,19 @@ function show_usage() { } function invoke( $args, $assoc_args ) { + $subcommand = $this->pre_invoke( $args ); + $subcommand->invoke( $args, $assoc_args ); + } + + function pre_invoke( &$args ) { $subcommand = $this->find_subcommand( $args ); if ( !$subcommand ) { $this->show_usage(); - return; + exit; } - $subcommand->invoke( $args, $assoc_args ); + return $subcommand; } function find_subcommand( &$args ) { From 32bcd448cba0859a68118e1c2492da22b2070d08 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 20 Nov 2012 06:23:12 +0200 Subject: [PATCH 0837/5359] replace --version global param with --info. fixes #219 --- src/bin/wp | 2 ++ src/php/wp-cli/class-wp-cli.php | 16 +++++++++++++--- src/php/wp-cli/dispatcher.php | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bin/wp b/src/bin/wp index d0fbdb4ea..fd25093a8 100755 --- a/src/bin/wp +++ b/src/bin/wp @@ -77,6 +77,8 @@ if [ "x$wp_cli_php_override" != "x" ] ; then php="$php $wp_cli_override_vars" fi +export WP_CLI_PHP_USED=$php + # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands exec $php "$SCRIPT_PATH" "$@" diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 062692b6d..513aaf2a6 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -223,9 +223,9 @@ static function before_wp_load() { define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); - // Handle --version parameter - if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { - self::line( 'wp-cli ' . WP_CLI_VERSION ); + // Handle --info parameter + if ( isset( self::$assoc_args['info'] ) && empty( self::$arguments ) ) { + self::show_info(); exit; } @@ -306,6 +306,16 @@ private static function run_command() { $command->invoke( self::$arguments, self::$assoc_args ); } + private static function show_info() { + $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + + WP_CLI::line( "PHP binary:\t" . $php_bin ); + WP_CLI::line( "PHP version:\t" . PHP_VERSION ); + WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); + WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); + } + private static function generate_man( $args ) { $command = Dispatcher\traverse( $args ); if ( !$command ) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 0b97691f5..7bb0b3b51 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -70,7 +70,7 @@ function show_usage() { --path=<path> set the current path to the WP install --require=<path> load a certain file before running the command --quiet suppress informational messages ---version print wp-cli version +--info print wp-cli information EOB ); } From 38580b810eb60107c8487695f020b13f945761d1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 20 Nov 2012 06:42:07 +0200 Subject: [PATCH 0838/5359] add back --version parameter. see #219 --- src/php/wp-cli/class-wp-cli.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 513aaf2a6..04c147352 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -223,6 +223,12 @@ static function before_wp_load() { define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + // Handle --version parameter + if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { + self::line( 'wp-cli ' . WP_CLI_VERSION ); + exit; + } + // Handle --info parameter if ( isset( self::$assoc_args['info'] ) && empty( self::$arguments ) ) { self::show_info(); From b68046b8b6923f0681e058bd7939617e8601f1d2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 Nov 2012 04:58:48 +0000 Subject: [PATCH 0839/5359] user import-csv: If the email address for a new user is already registered with an existing user, use the existing user's WP_User object instead. The prior code didn't work at all because: 1) The user_login in the CSV for the new user may not have been the same as the existing user 2) add_user_to_blog() accepts a user ID, not a user_login --- src/php/wp-cli/commands/internals/user.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index aaa39ad29..f686ad08e 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -281,13 +281,13 @@ public function import_csv( $args, $assoc_args ) { // User already exists and we just need to add them to the site if they aren't already there if ( $existing_user = get_user_by( 'email', $new_user['user_email'] ) ) { - if ( in_array( $new_user['user_login'], wp_list_pluck( $blog_users, 'user_login' ) ) ) - WP_CLI::warning( "{$new_user['user_login']} already is a member of blog" ); + if ( in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) ) + WP_CLI::warning( "{$existing_user->user_login} already is a member of blog" ); else if ( $new_user['role'] ) { - add_user_to_blog( get_current_blog_id(), $new_user['user_login'], $new_user['role'] ); - WP_CLI::line( "{$new_user['user_login']} added to blog as {$new_user['role']}" ); + add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); + WP_CLI::line( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); } else { - WP_CLI::line( "{$new_user['user_login']} exists, but won't be added to the blog" ); + WP_CLI::line( "{$existing_user->user_login} exists, but won't be added to the blog" ); } continue; } From 2cbdb22451c9368e9455271c98855ab6bd0be28b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 21 Nov 2012 15:09:53 +0200 Subject: [PATCH 0840/5359] rename `wp cli connect` to `wp cli connect-str` keep `connect` as alias, for backwards compatibility --- src/php/wp-cli/commands/internals/db.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index de4f35bc4..f61649480 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -85,6 +85,9 @@ function repair() { /** * Print a string for connecting to the DB. + * + * @subcommand connect-str + * @subcommand connect */ function connect() { WP_CLI::line( $this->connect_string() ); From 070b77da8e5af481f95a882374eb73882291afce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Nov 2012 03:03:21 +0200 Subject: [PATCH 0841/5359] add --ids flag to `wp user list`. fixes #223 --- man/user-list.1 | 8 +++++++- src/docs/user-list.txt | 5 +++++ src/php/wp-cli/commands/internals/user.php | 10 ++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/man/user-list.1 b/man/user-list.1 index b5bba57b7..265b30893 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -\fBwp user list\fR [\-\-role=\fIrole\fR] +\fBwp user list\fR [\-\-role=\fIrole\fR] [\-\-ids] . .SH "OPTIONS" . @@ -16,4 +16,10 @@ . .IP Only display users with a certain role\. +. +.TP +\fB\-\-ids\fR: +. +.IP +Return only the IDs of the found users, separated by spaces\. diff --git a/src/docs/user-list.txt b/src/docs/user-list.txt index 631b84e28..68c4eb6a7 100644 --- a/src/docs/user-list.txt +++ b/src/docs/user-list.txt @@ -3,3 +3,8 @@ * `--role`=<role>: Only display users with a certain role. + +* `--ids`: + + Return only the IDs of the found users, separated by spaces. + diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index f686ad08e..91651512f 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -14,14 +14,14 @@ class User_Command extends WP_CLI_Command { * List users. * * @subcommand list - * @synopsis [--role=<role>] + * @synopsis [--role=<role>] [--ids] */ public function _list( $args, $assoc_args ) { global $blog_id; $params = array( 'blog_id' => $blog_id, - 'fields' => 'all_with_meta', + 'fields' => isset( $assoc_args['ids'] ) ? 'ids' : 'all_with_meta', ); if ( array_key_exists('role', $assoc_args) ) { @@ -29,6 +29,12 @@ public function _list( $args, $assoc_args ) { } $users = get_users( $params ); + + if ( isset( $assoc_args['ids'] ) ) { + WP_CLI::out( implode( ' ', $users ) ); + return; + } + $fields = array('ID', 'user_login', 'display_name', 'user_email', 'user_registered'); From 65997186901dc849ecfcdf2c0521090c563eb30f Mon Sep 17 00:00:00 2001 From: Jaime Martinez <jmslbam@gmail.com> Date: Fri, 23 Nov 2012 17:00:25 +0100 Subject: [PATCH 0842/5359] Init commit into wp-cli --- .../wp-cli/commands/internals/scaffold.php | 160 ++++++++++++++++++ .../skeletons/post_type_skeleton.php | 79 +++++++++ .../internals/skeletons/taxonomy_skeleton.php | 47 +++++ 3 files changed, 286 insertions(+) create mode 100755 src/php/wp-cli/commands/internals/scaffold.php create mode 100755 src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php create mode 100755 src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php new file mode 100755 index 000000000..b7e556adb --- /dev/null +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -0,0 +1,160 @@ +<?php +/** + * Implement Scaffold Command + * + * @package wp-cli + * @subpackage commands/community + * @maintainer LinePress (http://www.linespress.org) + */ +WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); + +class Scaffold_Command extends WP_CLI_Command { + + /** + * Subcommand custom post type + * + * @param string $args Name of custom post type + * @param array $assoc_args + * + */ + + function custom_post_type( $args, $assoc_args ) { + if( !isset( $args[0] ) ) WP_CLI::error( "Please provide a cpt name" ); + + // set the args to variables with normal names to keep our sanity + $post_type = strtolower( $args[0] ); + // we use the machine name for function declarations + $machine_name = preg_replace('/-/', '_', $post_type ); + + // if no label is given use the slug and prettify it as good as possible + if( !isset($assoc_args['label'])){ + $label = preg_replace('/_|-/', ' ', ucfirst( strtolower( $post_type ) ) ); + } + + // set up defaults and merge theme with assoc_args + $defaults = array( + 'description' => "", + 'public' => 'true', + 'exclude_from_search' => 'false', + 'show_ui' => 'true', + 'show_in_nav_menus' => 'true', + 'show_in_menu' => 'true', + 'show_in_admin_bar' => 'true', + 'menu_position' => 'null', + 'menu_icon' => 'null', + 'capability_type' => 'post', + 'hierarchical' => 'false', + 'supports' => "'title', 'editor'", + 'has_archive' => 'true', + 'rewrite' => "array( 'slug' => '{$post_type}', 'feeds' => true, 'pages' => true )", + 'query_var' => 'true', + 'can_export' => 'true', + 'context' => strtolower( wp_get_theme()->template ), + ); + + // generate the variables from the defaults and associated arguments if they are set + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + $path = TEMPLATEPATH . '/custom-post-types/'; + if(! is_dir($path) ) + mkdir( $path ); + + $file = $path . $post_type .'.php'; + $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); + + include 'skeletons/post_type_skeleton.php'; + + fwrite( $handle, $output ); + fclose( $handle ); + } + + /** + * Subcommand cpt + * Alias for custom_post_type + * + * @param string $args Name of custom post type + * @param array $assoc_args + * + */ + function cpt ( $args, $assoc_args ) { + $this->custom_post_type( $args, $assoc_args ); + } + + /** + * Subcommand taxonomy + * + * @param string $args Name of taxonomy + * @param array $assoc_args + * + */ + function taxonomy( $args, $assoc_args ) { + + if( !isset($args[0])) WP_CLI::error( "Please provide a taxonomy" ); + + // set the args to variables with normal names to keep our sanity + $taxonomy = strtolower( $args[0] ); + + // we use the machine name for function declarations + $machine_name = preg_replace('/-/', '_', $taxonomy ); + + // if no label is given use the slug and prettify it as good as possible + if( !isset($assoc_args['label'])){ + $label = preg_replace('/_|-/', ' ', ucfirst( strtolower( $taxonomy ) ) ); + } + + // set up defaults and merge theme with assoc_args + $defaults = array( + 'public' => 'true', + 'show_in_nav_menus' => 'true', + 'show_ui' => 'true', + 'show_tagcloud' => 'true', + 'hierarchical' => 'false', + 'rewrite' => 'true', + 'query_var' => 'true', + 'slug' => $taxonomy, + 'hierarchical' => 'true', + 'context' => strtolower( wp_get_theme()->template ), + 'post_types' => 'post' + ); + + // generate the variables from the defaults and associated arguments if they are set + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + $path = TEMPLATEPATH . '/taxonomies/'; + if(! is_dir($path) ) + mkdir( $path ); + + $file = $path . $taxonomy .'.php'; + $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); + + include 'skeletons/taxonomy_skeleton.php'; + + fwrite( $handle, $output ); + fclose( $handle ); + } + + /** + * Subcommand tax + * Alias for taxonomy + * + * @param string $args Name of taxonomy + * @param array $assoc_args + * + */ + function tax ( $args, $assoc_args ) { + $this->taxonomy( $args, $assoc_args ); + } + + function status( $args, $assoc_args ) { + WP_CLI::success( "status command executed \n" ); + } + + static function help() { + WP_CLI::line( 'Welcome to wp-cli scaffold' ); + WP_CLI::line( 'Possible subcommando: cpt, tax' ); + WP_CLI::line( 'Example: cpt zombie' ); + WP_CLI::line( 'Example: tax zombie_speed --post_types=zombie' ); + + } + +} \ No newline at end of file diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php new file mode 100755 index 000000000..110f84325 --- /dev/null +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -0,0 +1,79 @@ +<?php + $output = "<?php + + if (!post_type_exists( '{$post_type}' ) ) : + register_post_type( '{$post_type}', + array( + 'label' => __( '{$label}s', '{$context}' ), + 'description' => __( '{$description}', '{$context}' ), + 'public' => {$public}, + 'exclude_from_search' => {$exclude_from_search}, + 'show_ui' => {$show_ui}, + 'show_in_nav_menus' => {$show_in_nav_menus}, + 'show_in_menu' => {$show_in_menu}, + 'show_in_admin_bar' => {$show_in_admin_bar}, + 'menu_position' => {$menu_position}, + 'menu_icon' => {$menu_icon}, + 'capability_type' => '{$capability_type}', + 'hierarchical' => {$hierarchical}, + 'supports' => {$supports}, + 'has_archive' => {$has_archive}, + 'rewrite' => array( 'slug' => '{$post_type}' ), + 'query_var' => {$query_var}, + 'can_export' => {$can_export}, + 'labels' => array( + 'name' => __( '{$label}s', '{$context}' ), + 'singular_name' => __( '{$label}', '{$context}' ), + 'add_new' => __( 'Add new {$label}', '{$context}' ), + 'all_items' => __( '{$label}s', '{$context}' ), + 'add_new_item' => __( 'Add new {$label}', '{$context}' ), + 'edit_item' => __( 'Edit {$label}', '{$context}' ), + 'new_item' => __( 'New {$label}', '{$context}' ), + 'view_item' => __( 'View {$label}', '{$context}' ), + 'search_items' => __( 'Search {$label}s', '{$context}' ), + 'not_found' => __( 'No {$label}s found', '{$context}' ), + 'not_found_in_trash' => __( 'No {$label}s found in trash', '{$context}' ), + 'parent_item_colon' => __( 'Parent {$label}', '{$context}' ), + 'menu_name' => __( '{$label}s', '{$context}' ), + ), + ) + ); + endif; + + function lp_{$machine_name}_updated_messages( \$messages ) { + global \$post, \$post_ID; + + \$messages['{$post_type}'] = array( + 0 => '', // Unused. Messages start at index 1. + 1 => sprintf( __('{$label} updated. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), + 2 => __('Custom field updated.', '{$context}'), + 3 => __('Custom field deleted.', '{$context}'), + 4 => __('{$label} updated.', '{$context}'), + /* translators: %s: date and time of the revision */ + 5 => isset(\$_GET['revision']) ? sprintf( __('{$label} restored to revision from %s', '{$context}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, + 6 => sprintf( __('{$label} published. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), + 7 => __('{$label} saved.', '{$context}'), + 8 => sprintf( __('{$label} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$context}'), + // translators: Publish box date format, see http://php.net/date + date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), + 10 => sprintf( __('{$label} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + ); + + return \$messages; + } + add_filter( 'post_updated_messages', 'lp_{$machine_name}_updated_messages' ); + + function lp_pre_single_{$machine_name}( \$query ) { + if ( get_post_type() == '{$post_type}' && \$query->is_main_query() ) { + + } + } + add_action( 'pre_get_posts', 'lp_pre_single_{$post_type}' ); + + function lp_pre_archive_{$machine_name}( \$query ) { + if ( is_post_type_archive( '{$post_type}' ) ) { + + } + } + add_action( 'pre_get_posts', 'lp_pre_archive_{$machine_name}' );"; \ No newline at end of file diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php new file mode 100755 index 000000000..482962782 --- /dev/null +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -0,0 +1,47 @@ +<?php + $output = "<?php + + if ( !taxonomy_exists( '{$taxonomy}' ) ) : + \$labels = array( + 'name' => __( '{$taxonomy}', '{$context}' ), + 'singular_name' => __( '{$taxonomy}', '{$context}' ), + 'search_items' => __( 'Search {$taxonomy}', '{$context}' ), + 'popular_items' => __( 'Popular {$taxonomy}', '{$context}' ), + 'all_items' => __( 'All {$taxonomy}', '{$context}' ), + 'parent_item' => __( 'Parent {$taxonomy}', '{$context}' ), + 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$context}' ), + 'edit_item' => __( 'Edit {$taxonomy}', '{$context}' ), + 'update_item' => __( 'Update {$taxonomy}', '{$context}' ), + 'add_new_item' => __( 'New {$taxonomy}', '{$context}' ), + 'new_item_name' => __( 'New {$taxonomy}', '{$context}' ), + 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$context}' ), + 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$context}' ), + 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$context}' ), + 'menu_name' => __( '{$taxonomy}s', '{$context}' ), + ); + + \$args = array( + 'labels' => \$labels, + 'public' => {$public}, + 'show_in_nav_menus' => {$show_in_nav_menus}, + 'show_ui' => {$show_ui}, + 'show_tagcloud' => {$show_tagcloud}, + 'hierarchical' => {$hierarchical}, + 'update_count_callback' => '_update_post_term_count', + 'rewrite' => {$rewrite}, + 'query_var' => {$query_var}, + 'capabilities' => array ( + 'manage_terms' => 'edit_posts', + 'edit_terms' => 'edit_posts', + 'delete_terms' => 'edit_posts', + 'assign_terms' => 'edit_posts' + ), + 'rewrite' => array( + 'slug' => '{$taxonomy}', + 'hierarchical' => {$hierarchical} + ), + ); + + register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args ); + + endif;"; \ No newline at end of file From 3bedbc86e31a54c575e65f563384caee79251e5f Mon Sep 17 00:00:00 2001 From: Jaime Martinez <jmslbam@gmail.com> Date: Fri, 23 Nov 2012 17:05:00 +0100 Subject: [PATCH 0843/5359] changed subpackes to internals --- src/php/wp-cli/commands/internals/scaffold.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index b7e556adb..915f6096e 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -1,11 +1,12 @@ <?php /** - * Implement Scaffold Command + * Implement scaffold command * * @package wp-cli - * @subpackage commands/community + * @subpackage commands/internals * @maintainer LinePress (http://www.linespress.org) */ + WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); class Scaffold_Command extends WP_CLI_Command { From 19cb1210c833c4f8e6d98d8b478af889fb4136ef Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 24 Nov 2012 00:25:49 +0100 Subject: [PATCH 0844/5359] Removed command aliasses and renamed custom post type to post type because everywhere in WP they use post type --- .../wp-cli/commands/internals/scaffold.php | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 915f6096e..16616d247 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -12,15 +12,15 @@ class Scaffold_Command extends WP_CLI_Command { /** - * Subcommand custom post type + * Subcommand post type * - * @param string $args Name of custom post type + * @param string $args Name of post type * @param array $assoc_args * */ - function custom_post_type( $args, $assoc_args ) { - if( !isset( $args[0] ) ) WP_CLI::error( "Please provide a cpt name" ); + function post_type( $args, $assoc_args ) { + if( !isset( $args[0] ) ) WP_CLI::error( "Please provide a post type name" ); // set the args to variables with normal names to keep our sanity $post_type = strtolower( $args[0] ); @@ -56,7 +56,7 @@ function custom_post_type( $args, $assoc_args ) { // generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - $path = TEMPLATEPATH . '/custom-post-types/'; + $path = TEMPLATEPATH . '/post-types/'; if(! is_dir($path) ) mkdir( $path ); @@ -69,18 +69,6 @@ function custom_post_type( $args, $assoc_args ) { fclose( $handle ); } - /** - * Subcommand cpt - * Alias for custom_post_type - * - * @param string $args Name of custom post type - * @param array $assoc_args - * - */ - function cpt ( $args, $assoc_args ) { - $this->custom_post_type( $args, $assoc_args ); - } - /** * Subcommand taxonomy * @@ -134,20 +122,8 @@ function taxonomy( $args, $assoc_args ) { fclose( $handle ); } - /** - * Subcommand tax - * Alias for taxonomy - * - * @param string $args Name of taxonomy - * @param array $assoc_args - * - */ - function tax ( $args, $assoc_args ) { - $this->taxonomy( $args, $assoc_args ); - } - function status( $args, $assoc_args ) { - WP_CLI::success( "status command executed \n" ); + WP_CLI::success( "Status command executed \n" ); } static function help() { From 8891c2d9c21f76824e30241b0253a77b72c306be Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 24 Nov 2012 00:29:45 +0100 Subject: [PATCH 0845/5359] Edited help text --- src/php/wp-cli/commands/internals/scaffold.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 16616d247..0ad862516 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -12,7 +12,7 @@ class Scaffold_Command extends WP_CLI_Command { /** - * Subcommand post type + * Subcommand posttype * * @param string $args Name of post type * @param array $assoc_args @@ -128,9 +128,9 @@ function status( $args, $assoc_args ) { static function help() { WP_CLI::line( 'Welcome to wp-cli scaffold' ); - WP_CLI::line( 'Possible subcommando: cpt, tax' ); - WP_CLI::line( 'Example: cpt zombie' ); - WP_CLI::line( 'Example: tax zombie_speed --post_types=zombie' ); + WP_CLI::line( 'Possible subcommando: post_type, taxonomy' ); + WP_CLI::line( 'Example: post_type zombie' ); + WP_CLI::line( 'Example: taxonomy zombie_speed --post_types=zombie' ); } From 39e2375982201d3a6418db3ef276910e1f83547d Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 24 Nov 2012 00:43:28 +0100 Subject: [PATCH 0846/5359] Remove status command --- src/php/wp-cli/commands/internals/scaffold.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 0ad862516..50805fa25 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -122,16 +122,11 @@ function taxonomy( $args, $assoc_args ) { fclose( $handle ); } - function status( $args, $assoc_args ) { - WP_CLI::success( "Status command executed \n" ); - } - static function help() { WP_CLI::line( 'Welcome to wp-cli scaffold' ); WP_CLI::line( 'Possible subcommando: post_type, taxonomy' ); WP_CLI::line( 'Example: post_type zombie' ); WP_CLI::line( 'Example: taxonomy zombie_speed --post_types=zombie' ); - } } \ No newline at end of file From 9fb37ae144b9e9aacacfab395595e8fa4dc4a00e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 24 Nov 2012 02:43:13 +0200 Subject: [PATCH 0847/5359] clean up post generate synopsis and man page --- man/post-generate.1 | 14 ++++++++++---- src/docs/post-generate.txt | 10 +++++++--- src/php/wp-cli/commands/internals/post.php | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/man/post-generate.1 b/man/post-generate.1 index 6fa88536d..a5a78c5e7 100644 --- a/man/post-generate.1 +++ b/man/post-generate.1 @@ -7,7 +7,7 @@ \fBwp\-post\-generate\fR \- Generate some posts\. . .SH "SYNOPSIS" -\fBwp post generate\fR [\-\-count=100] [\-\-post_type=post] [\-\-post_status=publish] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIdate\fR] [\-\-max_depth=1] +\fBwp post generate\fR [\-\-count=100] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=1] . .SH "OPTIONS" . @@ -18,24 +18,30 @@ How many posts to generate\. Default: 100 . .TP -\fB\-\-type\fR=\fIpost_type\fR: +\fB\-\-post_type\fR=\fItype\fR: . .IP The type of the generated posts\. Default: \'post\' . .TP -\fB\-\-status\fR=\fIpost_status\fR: +\fB\-\-post_status\fR=\fIstatus\fR: . .IP The status of the generated posts\. Default: \'publish\' . .TP -\fB\-\-author\fR=\fIlogin\fR: +\fB\-\-post_author\fR=\fIlogin\fR: . .IP The author of the generated posts\. Default: none . .TP +\fB\-\-post_date\fR=\fIyyyy\-mm\-dd\fR: +. +.IP +The date of the generated posts\. Default: current date +. +.TP \fB\-\-max_depth\fR=\fInumber\fR: . .IP diff --git a/src/docs/post-generate.txt b/src/docs/post-generate.txt index cab9b591f..7dba04a6f 100644 --- a/src/docs/post-generate.txt +++ b/src/docs/post-generate.txt @@ -4,18 +4,22 @@ How many posts to generate. Default: 100 -* `--type`=<post_type>: +* `--post_type`=<type>: The type of the generated posts. Default: 'post' -* `--status`=<post_status>: +* `--post_status`=<status>: The status of the generated posts. Default: 'publish' -* `--author`=<login>: +* `--post_author`=<login>: The author of the generated posts. Default: none +* `--post_date`=<yyyy-mm-dd>: + + The date of the generated posts. Default: current date + * `--max_depth`=<number>: For hierarchical post types, generate child posts down to a certain depth. Default: 1 diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index c05c3b8d4..dd84c51db 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -117,7 +117,7 @@ public function _list( $_, $assoc_args ) { /** * Generate some posts. * - * @synopsis [--count=100] [--post_type=post] [--post_status=publish] [--post_author=<login>] [--post_date=<date>] [--max_depth=1] + * @synopsis [--count=100] [--post_type=<type>] [--post_status=<status>] [--post_author=<login>] [--post_date=<yyyy-mm-dd>] [--max_depth=1] */ public function generate( $args, $assoc_args ) { global $wpdb; From c25ac12673898cdfe2cbba079a8b075dac70e7c2 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 24 Nov 2012 14:40:12 +0100 Subject: [PATCH 0848/5359] Use wp_cli launch instead of php to mkdir --- src/php/wp-cli/commands/internals/scaffold.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 50805fa25..6f908ea33 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -58,7 +58,7 @@ function post_type( $args, $assoc_args ) { $path = TEMPLATEPATH . '/post-types/'; if(! is_dir($path) ) - mkdir( $path ); + WP_CLI::launch('mkdir ' . $path); $file = $path . $post_type .'.php'; $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); @@ -111,7 +111,7 @@ function taxonomy( $args, $assoc_args ) { $path = TEMPLATEPATH . '/taxonomies/'; if(! is_dir($path) ) - mkdir( $path ); + WP_CLI::launch('mkdir ' . $path); $file = $path . $taxonomy .'.php'; $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); From 52b8ecb0e88ec9f2eaf136ff1fada6ddab5664c7 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 24 Nov 2012 14:52:26 +0100 Subject: [PATCH 0849/5359] Cleanup, spaces and Capitalize sentences --- .../wp-cli/commands/internals/scaffold.php | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 6f908ea33..a864e496c 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -1,4 +1,7 @@ <?php + +WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); + /** * Implement scaffold command * @@ -6,30 +9,29 @@ * @subpackage commands/internals * @maintainer LinePress (http://www.linespress.org) */ - -WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); - class Scaffold_Command extends WP_CLI_Command { /** * Subcommand posttype * * @param string $args Name of post type - * @param array $assoc_args + * @param array $assoc_args The ussual WordPress arguments * */ - function post_type( $args, $assoc_args ) { - if( !isset( $args[0] ) ) WP_CLI::error( "Please provide a post type name" ); + if( !isset( $args[0] ) ) { + WP_CLI::error( "Please provide a post type name" ); + } - // set the args to variables with normal names to keep our sanity + // Set the args to variables with normal names to keep our sanity $post_type = strtolower( $args[0] ); - // we use the machine name for function declarations - $machine_name = preg_replace('/-/', '_', $post_type ); - // if no label is given use the slug and prettify it as good as possible - if( !isset($assoc_args['label'])){ - $label = preg_replace('/_|-/', ' ', ucfirst( strtolower( $post_type ) ) ); + // We use the machine name for function declarations + $machine_name = preg_replace( '/-/', '_', $post_type ); + + // If no label is given use the slug and prettify it as good as possible + if( !isset( $assoc_args['label'] ) ) { + $label = preg_replace( '/_|-/', ' ', ucfirst( strtolower( $post_type ) ) ); } // set up defaults and merge theme with assoc_args @@ -53,12 +55,12 @@ function post_type( $args, $assoc_args ) { 'context' => strtolower( wp_get_theme()->template ), ); - // generate the variables from the defaults and associated arguments if they are set + // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); $path = TEMPLATEPATH . '/post-types/'; - if(! is_dir($path) ) - WP_CLI::launch('mkdir ' . $path); + if(! is_dir( $path ) ) + WP_CLI::launch( 'mkdir ' . $path ); $file = $path . $post_type .'.php'; $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); @@ -73,25 +75,27 @@ function post_type( $args, $assoc_args ) { * Subcommand taxonomy * * @param string $args Name of taxonomy - * @param array $assoc_args + * @param array $assoc_args The ussual WordPress arguments * */ function taxonomy( $args, $assoc_args ) { - if( !isset($args[0])) WP_CLI::error( "Please provide a taxonomy" ); + if( !isset( $args[0] ) ) { + WP_CLI::error( "Please provide a taxonomy" ); + } - // set the args to variables with normal names to keep our sanity + // Set the args to variables with normal names to keep our sanity $taxonomy = strtolower( $args[0] ); - // we use the machine name for function declarations - $machine_name = preg_replace('/-/', '_', $taxonomy ); + // We use the machine name for function declarations + $machine_name = preg_replace( '/-/', '_', $taxonomy ); - // if no label is given use the slug and prettify it as good as possible - if( !isset($assoc_args['label'])){ - $label = preg_replace('/_|-/', ' ', ucfirst( strtolower( $taxonomy ) ) ); + // If no label is given use the slug and prettify it as good as possible + if( !isset( $assoc_args['label'] ) ){ + $label = preg_replace( '/_|-/', ' ', ucfirst( strtolower( $taxonomy ) ) ); } - // set up defaults and merge theme with assoc_args + // Set up defaults and merge theme with assoc_args $defaults = array( 'public' => 'true', 'show_in_nav_menus' => 'true', @@ -106,20 +110,20 @@ function taxonomy( $args, $assoc_args ) { 'post_types' => 'post' ); - // generate the variables from the defaults and associated arguments if they are set + // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); $path = TEMPLATEPATH . '/taxonomies/'; - if(! is_dir($path) ) - WP_CLI::launch('mkdir ' . $path); + if(! is_dir( $path ) ) + WP_CLI::launch( 'mkdir ' . $path ); $file = $path . $taxonomy .'.php'; $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); include 'skeletons/taxonomy_skeleton.php'; - fwrite( $handle, $output ); - fclose( $handle ); + fwrite( $handle, $output ); + fclose( $handle ); } static function help() { @@ -128,5 +132,4 @@ static function help() { WP_CLI::line( 'Example: post_type zombie' ); WP_CLI::line( 'Example: taxonomy zombie_speed --post_types=zombie' ); } - } \ No newline at end of file From d126da362bcb9a78a6fb92ba5f5c8d33e7d7a9ac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 24 Nov 2012 16:51:28 +0200 Subject: [PATCH 0850/5359] update description of WP_CLI::launch() --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 04c147352..973dd0606 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -177,7 +177,7 @@ static function compose_args( $args, $assoc_args = array() ) { } /** - * Launch an external process, closing the current one + * Launch an external process that takes over I/O. * * @param string Command to call * @param bool Whether to exit if the command returns an error status From 324a200a50d83e2f23b7181edf6b8aa803466225 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 25 Nov 2012 16:07:21 +0100 Subject: [PATCH 0851/5359] Using WP_Filesystem to create dirs and write files --- .../wp-cli/commands/internals/scaffold.php | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index a864e496c..55ddbaa7f 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -11,6 +11,10 @@ */ class Scaffold_Command extends WP_CLI_Command { + function __construct() { + WP_Filesystem(); + } + /** * Subcommand posttype * @@ -19,6 +23,8 @@ class Scaffold_Command extends WP_CLI_Command { * */ function post_type( $args, $assoc_args ) { + global $wp_filesystem; + if( !isset( $args[0] ) ) { WP_CLI::error( "Please provide a post type name" ); } @@ -59,16 +65,17 @@ function post_type( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); $path = TEMPLATEPATH . '/post-types/'; - if(! is_dir( $path ) ) - WP_CLI::launch( 'mkdir ' . $path ); + if( !$wp_filesystem->is_dir( $path ) ) { + $wp_filesystem->mkdir( $path ); + } + + $filename = $path . $post_type .'.php'; - $file = $path . $post_type .'.php'; - $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); - include 'skeletons/post_type_skeleton.php'; - fwrite( $handle, $output ); - fclose( $handle ); + if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { + WP_CLI::error( 'Error while saving file' ); + } } /** @@ -79,6 +86,7 @@ function post_type( $args, $assoc_args ) { * */ function taxonomy( $args, $assoc_args ) { + global $wp_filesystem; if( !isset( $args[0] ) ) { WP_CLI::error( "Please provide a taxonomy" ); @@ -91,7 +99,7 @@ function taxonomy( $args, $assoc_args ) { $machine_name = preg_replace( '/-/', '_', $taxonomy ); // If no label is given use the slug and prettify it as good as possible - if( !isset( $assoc_args['label'] ) ){ + if( !isset( $assoc_args['label'] ) ) { $label = preg_replace( '/_|-/', ' ', ucfirst( strtolower( $taxonomy ) ) ); } @@ -114,16 +122,17 @@ function taxonomy( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); $path = TEMPLATEPATH . '/taxonomies/'; - if(! is_dir( $path ) ) - WP_CLI::launch( 'mkdir ' . $path ); - - $file = $path . $taxonomy .'.php'; - $handle = fopen( $file, 'wb' ) or die( 'Cannot open file: ' . $file ); - + if( !$wp_filesystem->is_dir( $path ) ) { + $wp_filesystem->mkdir( $path ); + } + + $filename = $path . $taxonomy .'.php'; + include 'skeletons/taxonomy_skeleton.php'; - fwrite( $handle, $output ); - fclose( $handle ); + if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { + WP_CLI::error( 'Error while saving file' ); + } } static function help() { From cb8030453c71a4b0aa460805bb93d9d7bb4503ad Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 25 Nov 2012 16:10:40 +0100 Subject: [PATCH 0852/5359] Added feedback on success when creating a post type or taxonomy --- src/php/wp-cli/commands/internals/scaffold.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 55ddbaa7f..ca20c0291 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -75,6 +75,8 @@ function post_type( $args, $assoc_args ) { if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { WP_CLI::error( 'Error while saving file' ); + } else { + WP_CLI::success( $post_type . ' created' ); } } @@ -132,6 +134,8 @@ function taxonomy( $args, $assoc_args ) { if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { WP_CLI::error( 'Error while saving file' ); + } else { + WP_CLI::success( $taxonomy . ' created' ); } } From 64cf0578fdb4168a8ca2ee6750444117c61fcfcb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 27 Nov 2012 02:17:38 +0200 Subject: [PATCH 0853/5359] user create: add user_pass, user_registered and display_name to list of accepted parameters --- man/user-create.1 | 22 ++++++++++++++++++++-- src/docs/user-create.txt | 14 +++++++++++++- src/php/wp-cli/commands/internals/user.php | 7 ++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/man/user-create.1 b/man/user-create.1 index 99e2fd964..dabdae714 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -7,7 +7,7 @@ \fBwp\-user\-create\fR \- Create a user\. . .SH "SYNOPSIS" -\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-porcelain] +\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-user_pass=\fIpassword\fR] [\-\-user_registered=\fIyyyy\-mm\-dd\fR] [\-\-display_name=\fIname\fR] [\-\-porcelain] . .SH "OPTIONS" . @@ -27,7 +27,25 @@ The email address of the user to create\. \fB\-\-role\fR=\fIrole\fR: . .IP -The role of the user to create\. +The role of the user to create\. Default: default role +. +.TP +\fB\-\-user_pass\fR=\fIpassword\fR: +. +.IP +The user password\. Default: randomly generated +. +.TP +\fB\-\-user_registered\fR=\fIyyyy\-mm\-dd\fR: +. +.IP +The date the user registered\. Default: current date +. +.TP +\fB\-\-display_name\fR=\fIname\fR: +. +.IP +The display name\. . .TP \fB\-\-porcelain\fR: diff --git a/src/docs/user-create.txt b/src/docs/user-create.txt index 6ba889ece..8b860096b 100644 --- a/src/docs/user-create.txt +++ b/src/docs/user-create.txt @@ -10,7 +10,19 @@ * `--role`=<role>: - The role of the user to create. + The role of the user to create. Default: default role + +* `--user_pass`=<password>: + + The user password. Default: randomly generated + +* `--user_registered`=<yyyy-mm-dd>: + + The date the user registered. Default: current date + +* `--display_name`=<name>: + + The display name. * `--porcelain`: diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 91651512f..0e48ee65d 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -82,7 +82,7 @@ public function delete( $args, $assoc_args ) { /** * Create a user. * - * @synopsis <user-login> <user-email> [--role=<role>] [--porcelain] + * @synopsis <user-login> <user-email> [--role=<role>] [--user_pass=<password>] [--user_registered=<yyyy-mm-dd>] [--display_name=<name>] [--porcelain] */ public function create( $args, $assoc_args ) { global $blog_id; @@ -122,10 +122,11 @@ public function create( $args, $assoc_args ) { } } - if ( isset( $assoc_args['porcelain'] ) ) + if ( isset( $assoc_args['porcelain'] ) ) { WP_CLI::line( $user_id ); - else + } else { WP_CLI::success( "Created user $user_id." ); + } } /** From b00255355b7528cf54020fd9e691bded378df674 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 27 Nov 2012 02:20:08 +0200 Subject: [PATCH 0854/5359] show generated password. fixes #227 --- src/php/wp-cli/commands/internals/user.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 0e48ee65d..3a186402f 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -91,7 +91,7 @@ public function create( $args, $assoc_args ) { $defaults = array( 'role' => get_option('default_role'), - 'user_pass' => wp_generate_password(), + 'user_pass' => false, 'user_registered' => strftime( "%F %T", time() ), 'display_name' => false, ); @@ -104,6 +104,11 @@ public function create( $args, $assoc_args ) { WP_CLI::error( "Invalid role." ); } + if ( !$user_pass ) { + $user_pass = wp_generate_password(); + $generated_pass = true; + } + $user_id = wp_insert_user( array( 'user_email' => $user_email, 'user_login' => $user_login, @@ -126,6 +131,8 @@ public function create( $args, $assoc_args ) { WP_CLI::line( $user_id ); } else { WP_CLI::success( "Created user $user_id." ); + if ( isset( $generated_pass ) ) + WP_CLI::line( "Password: $user_pass" ); } } From 1b9ca8b081f35d97a55896edb20b7358c214ec52 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Tue, 27 Nov 2012 18:38:24 +0100 Subject: [PATCH 0855/5359] added pluralize private function, updated the post_type_skeleton with pluralized labels and fixed the pre_get_posts hooks, fixed a bug with supports variable --- .../wp-cli/commands/internals/scaffold.php | 67 +++++++++++++++++-- .../skeletons/post_type_skeleton.php | 48 +++++++------ 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index ca20c0291..52553cf49 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -30,14 +30,19 @@ function post_type( $args, $assoc_args ) { } // Set the args to variables with normal names to keep our sanity - $post_type = strtolower( $args[0] ); + $post_type = strtolower( $args[0] ); // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $post_type ); + $machine_name = preg_replace( '/-/', '_', $post_type ); + $machine_name_plural = $this->pluralize( $post_type ); // If no label is given use the slug and prettify it as good as possible if( !isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', ucfirst( strtolower( $post_type ) ) ); + $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); + $label_ucfirst = ucfirst( $label ); + $label_plural = $this->pluralize( $label ); + + $label_plural_ucfirst = ucfirst( $label_plural ); } // set up defaults and merge theme with assoc_args @@ -55,7 +60,7 @@ function post_type( $args, $assoc_args ) { 'hierarchical' => 'false', 'supports' => "'title', 'editor'", 'has_archive' => 'true', - 'rewrite' => "array( 'slug' => '{$post_type}', 'feeds' => true, 'pages' => true )", + 'rewrite' => "array( 'slug' => '{$machine_name_plural}', 'feeds' => true, 'pages' => true )", 'query_var' => 'true', 'can_export' => 'true', 'context' => strtolower( wp_get_theme()->template ), @@ -145,4 +150,58 @@ static function help() { WP_CLI::line( 'Example: post_type zombie' ); WP_CLI::line( 'Example: taxonomy zombie_speed --post_types=zombie' ); } + + private function pluralize($word) { + $plural = array( + '/(quiz)$/i' => '\1zes', + '/^(ox)$/i' => '\1en', + '/([m|l])ouse$/i' => '\1ice', + '/(matr|vert|ind)ix|ex$/i' => '\1ices', + '/(x|ch|ss|sh)$/i' => '\1es', + '/([^aeiouy]|qu)ies$/i' => '\1y', + '/([^aeiouy]|qu)y$/i' => '\1ies', + '/(hive)$/i' => '\1s', + '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', + '/sis$/i' => 'ses', + '/([ti])um$/i' => '\1a', + '/(buffal|tomat)o$/i' => '\1oes', + '/(bu)s$/i' => '1ses', + '/(alias|status)/i' => '\1es', + '/(octop|vir)us$/i' => '1i', + '/(ax|test)is$/i' => '\1es', + '/s$/i' => 's', + '/$/' => 's'); + + $uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep'); + + $irregular = array( + 'person' => 'people', + 'man' => 'men', + 'woman' => 'women', + 'child' => 'children', + 'sex' => 'sexes', + 'move' => 'moves'); + + $lowercased_word = strtolower($word); + + foreach ($uncountable as $_uncountable){ + if(substr($lowercased_word,(-1*strlen($_uncountable))) == $_uncountable){ + return $word; + } + } + + foreach ($irregular as $_plural=> $_singular){ + if (preg_match('/('.$_plural.')$/i', $word, $arr)) { + return preg_replace('/('.$_plural.')$/i', substr($arr[0],0,1).substr($_singular,1), $word); + } + } + + foreach ($plural as $rule => $replacement) { + if (preg_match($rule, $word)) { + return preg_replace($rule, $replacement, $word); + } + } + return false; + + } } \ No newline at end of file diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 110f84325..fc3edc528 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -4,7 +4,7 @@ if (!post_type_exists( '{$post_type}' ) ) : register_post_type( '{$post_type}', array( - 'label' => __( '{$label}s', '{$context}' ), + 'label' => __( '{$label_plural_ucfirst}', '{$context}' ), 'description' => __( '{$description}', '{$context}' ), 'public' => {$public}, 'exclude_from_search' => {$exclude_from_search}, @@ -16,25 +16,25 @@ 'menu_icon' => {$menu_icon}, 'capability_type' => '{$capability_type}', 'hierarchical' => {$hierarchical}, - 'supports' => {$supports}, + 'supports' => array( {$supports} ), 'has_archive' => {$has_archive}, - 'rewrite' => array( 'slug' => '{$post_type}' ), + 'rewrite' => {$rewrite}, 'query_var' => {$query_var}, 'can_export' => {$can_export}, 'labels' => array( - 'name' => __( '{$label}s', '{$context}' ), - 'singular_name' => __( '{$label}', '{$context}' ), + 'name' => __( '{$label_plural_ucfirst}', '{$context}' ), + 'singular_name' => __( '{$label_ucfirst}', '{$context}' ), 'add_new' => __( 'Add new {$label}', '{$context}' ), - 'all_items' => __( '{$label}s', '{$context}' ), + 'all_items' => __( '{$label_plural_ucfirst}', '{$context}' ), 'add_new_item' => __( 'Add new {$label}', '{$context}' ), 'edit_item' => __( 'Edit {$label}', '{$context}' ), 'new_item' => __( 'New {$label}', '{$context}' ), 'view_item' => __( 'View {$label}', '{$context}' ), - 'search_items' => __( 'Search {$label}s', '{$context}' ), - 'not_found' => __( 'No {$label}s found', '{$context}' ), - 'not_found_in_trash' => __( 'No {$label}s found in trash', '{$context}' ), + 'search_items' => __( 'Search {$label_plural}', '{$context}' ), + 'not_found' => __( 'No {$label_plural} found', '{$context}' ), + 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$context}' ), 'parent_item_colon' => __( 'Parent {$label}', '{$context}' ), - 'menu_name' => __( '{$label}s', '{$context}' ), + 'menu_name' => __( '{$label_plural_ucfirst}', '{$context}' ), ), ) ); @@ -45,19 +45,19 @@ function lp_{$machine_name}_updated_messages( \$messages ) { \$messages['{$post_type}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label} updated. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), + 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), 2 => __('Custom field updated.', '{$context}'), 3 => __('Custom field deleted.', '{$context}'), - 4 => __('{$label} updated.', '{$context}'), + 4 => __('{$label_ucfirst} updated.', '{$context}'), /* translators: %s: date and time of the revision */ - 5 => isset(\$_GET['revision']) ? sprintf( __('{$label} restored to revision from %s', '{$context}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label} published. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), - 7 => __('{$label} saved.', '{$context}'), - 8 => sprintf( __('{$label} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$context}'), + 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$context}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), + 7 => __('{$label_ucfirst} saved.', '{$context}'), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$context}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), ); return \$messages; @@ -65,14 +65,18 @@ function lp_{$machine_name}_updated_messages( \$messages ) { add_filter( 'post_updated_messages', 'lp_{$machine_name}_updated_messages' ); function lp_pre_single_{$machine_name}( \$query ) { - if ( get_post_type() == '{$post_type}' && \$query->is_main_query() ) { - + if ( !is_admin() && get_post_type() == '{$post_type}' && is_main_query() ) { + // use \$query->set() to change the main query + // or use this function to hook in some other specific code + } } - add_action( 'pre_get_posts', 'lp_pre_single_{$post_type}' ); + add_action( 'pre_get_posts', 'lp_pre_single_{$machine_name}' ); function lp_pre_archive_{$machine_name}( \$query ) { - if ( is_post_type_archive( '{$post_type}' ) ) { + if ( !is_admin() && is_post_type_archive( '{$post_type}' ) ) { + // use \$query->set() to change the main query + // or use this function to hook in some other specific code } } From 33df6d7946887cd756cb510fb2676a5eb7fd6e5a Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Tue, 27 Nov 2012 19:04:30 +0100 Subject: [PATCH 0856/5359] Split up the rewrite argument into slug, feed and pages. Adjusted the skeleton to support this --- src/php/wp-cli/commands/internals/scaffold.php | 10 +++++----- .../internals/skeletons/post_type_skeleton.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 52553cf49..fd7f36e95 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -16,11 +16,9 @@ function __construct() { } /** - * Subcommand posttype - * - * @param string $args Name of post type - * @param array $assoc_args The ussual WordPress arguments + * @subcommand post-type * + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [context=<context>] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -60,7 +58,9 @@ function post_type( $args, $assoc_args ) { 'hierarchical' => 'false', 'supports' => "'title', 'editor'", 'has_archive' => 'true', - 'rewrite' => "array( 'slug' => '{$machine_name_plural}', 'feeds' => true, 'pages' => true )", + 'slug' => $machine_name_plural, + 'feeds' => 'true', + 'pages' => 'true', 'query_var' => 'true', 'can_export' => 'true', 'context' => strtolower( wp_get_theme()->template ), diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index fc3edc528..8e2adb121 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -18,7 +18,7 @@ 'hierarchical' => {$hierarchical}, 'supports' => array( {$supports} ), 'has_archive' => {$has_archive}, - 'rewrite' => {$rewrite}, + 'rewrite' => array( 'slug' => '{$slug}', 'feeds' => {$feeds}, 'pages' => {$pages} ), 'query_var' => {$query_var}, 'can_export' => {$can_export}, 'labels' => array( From b1d709c024f45b190b8ba5b4e1e28f9712477362 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Tue, 27 Nov 2012 19:07:12 +0100 Subject: [PATCH 0857/5359] removed static help function --- src/php/wp-cli/commands/internals/scaffold.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index fd7f36e95..7ddc207d4 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -144,13 +144,6 @@ function taxonomy( $args, $assoc_args ) { } } - static function help() { - WP_CLI::line( 'Welcome to wp-cli scaffold' ); - WP_CLI::line( 'Possible subcommando: post_type, taxonomy' ); - WP_CLI::line( 'Example: post_type zombie' ); - WP_CLI::line( 'Example: taxonomy zombie_speed --post_types=zombie' ); - } - private function pluralize($word) { $plural = array( '/(quiz)$/i' => '\1zes', From 1dadf2204677e4478eaa17182fb18afce76ade50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 28 Nov 2012 01:40:00 +0200 Subject: [PATCH 0858/5359] add examples for `plugin path` and `theme path` --- man/plugin-path.1 | 8 ++++++++ man/theme-path.1 | 8 ++++++++ src/docs/plugin-path.txt | 4 ++++ src/docs/theme-path.txt | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/man/plugin-path.1 b/man/plugin-path.1 index fe019d718..cadd730d9 100644 --- a/man/plugin-path.1 +++ b/man/plugin-path.1 @@ -22,4 +22,12 @@ The plugin to get the path to\. If not set, will return the path to the plugins . .IP If set, get the path to the closest parent directory, instead of the plugin file\. +. +.SH "EXAMPLES" +. +.nf + +cd $(wp theme path) +. +.fi diff --git a/man/theme-path.1 b/man/theme-path.1 index 87a2c0dc7..2243de192 100644 --- a/man/theme-path.1 +++ b/man/theme-path.1 @@ -22,4 +22,12 @@ The theme to get the path to\. If not set, will return the path to the themes di . .IP If set, get the path to the closest parent directory, instead of the theme file\. +. +.SH "EXAMPLES" +. +.nf + +cd $(wp theme path) +. +.fi diff --git a/src/docs/plugin-path.txt b/src/docs/plugin-path.txt index 6f05ac23b..a190a7702 100644 --- a/src/docs/plugin-path.txt +++ b/src/docs/plugin-path.txt @@ -9,3 +9,7 @@ plugins directory. If set, get the path to the closest parent directory, instead of the plugin file. + +## EXAMPLES + + cd $(wp theme path) diff --git a/src/docs/theme-path.txt b/src/docs/theme-path.txt index 9b87d9699..d54cec5b1 100644 --- a/src/docs/theme-path.txt +++ b/src/docs/theme-path.txt @@ -9,3 +9,7 @@ themes directory. If set, get the path to the closest parent directory, instead of the theme file. + +## EXAMPLES + + cd $(wp theme path) From 986d90bbe66bbec744f86505aeba7f41fec72e20 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 09:57:28 +0100 Subject: [PATCH 0859/5359] updated the synopsis for taxonomy, added an alias for taxonom, changed context to textdomain --- .../wp-cli/commands/internals/scaffold.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 7ddc207d4..5f93eb7f3 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -18,15 +18,13 @@ function __construct() { /** * @subcommand post-type * + * @alias pt + * * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [context=<context>] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; - if( !isset( $args[0] ) ) { - WP_CLI::error( "Please provide a post type name" ); - } - // Set the args to variables with normal names to keep our sanity $post_type = strtolower( $args[0] ); @@ -86,19 +84,15 @@ function post_type( $args, $assoc_args ) { } /** - * Subcommand taxonomy + * @subcommand taxonomy * - * @param string $args Name of taxonomy - * @param array $assoc_args The ussual WordPress arguments + * @alias tax * + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; - if( !isset( $args[0] ) ) { - WP_CLI::error( "Please provide a taxonomy" ); - } - // Set the args to variables with normal names to keep our sanity $taxonomy = strtolower( $args[0] ); @@ -120,8 +114,7 @@ function taxonomy( $args, $assoc_args ) { 'rewrite' => 'true', 'query_var' => 'true', 'slug' => $taxonomy, - 'hierarchical' => 'true', - 'context' => strtolower( wp_get_theme()->template ), + 'textdomain' => strtolower( wp_get_theme()->template ), 'post_types' => 'post' ); From e6a3e5275763898b2b26fb8f3fbaf59b0ed6fb50 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 09:58:22 +0100 Subject: [PATCH 0860/5359] updated the synopsis for taxonomy, added an alias for taxonom, changed context to textdomain --- src/php/wp-cli/commands/internals/scaffold.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 5f93eb7f3..11ebd2198 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -20,7 +20,7 @@ function __construct() { * * @alias pt * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [context=<context>] + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -61,7 +61,7 @@ function post_type( $args, $assoc_args ) { 'pages' => 'true', 'query_var' => 'true', 'can_export' => 'true', - 'context' => strtolower( wp_get_theme()->template ), + 'textdomain' => strtolower( wp_get_theme()->template ), ); // Generate the variables from the defaults and associated arguments if they are set From f4eb255e2aab8a7eea3aaf11a804891d88d6b4e5 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 10:06:35 +0100 Subject: [PATCH 0861/5359] Nothing really changed, just cleaned up the code formatting --- .../wp-cli/commands/internals/scaffold.php | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 11ebd2198..c61769001 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -37,7 +37,6 @@ function post_type( $args, $assoc_args ) { $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); $label_ucfirst = ucfirst( $label ); $label_plural = $this->pluralize( $label ); - $label_plural_ucfirst = ucfirst( $label_plural ); } @@ -61,7 +60,7 @@ function post_type( $args, $assoc_args ) { 'pages' => 'true', 'query_var' => 'true', 'can_export' => 'true', - 'textdomain' => strtolower( wp_get_theme()->template ), + 'textdomain' => strtolower( wp_get_theme()->template ), ); // Generate the variables from the defaults and associated arguments if they are set @@ -137,54 +136,56 @@ function taxonomy( $args, $assoc_args ) { } } - private function pluralize($word) { + private function pluralize( $word ) { $plural = array( - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)ix|ex$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(buffal|tomat)o$/i' => '\1oes', - '/(bu)s$/i' => '1ses', - '/(alias|status)/i' => '\1es', - '/(octop|vir)us$/i' => '1i', - '/(ax|test)is$/i' => '\1es', - '/s$/i' => 's', - '/$/' => 's'); - - $uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep'); + '/(quiz)$/i' => '\1zes', + '/^(ox)$/i' => '\1en', + '/([m|l])ouse$/i' => '\1ice', + '/(matr|vert|ind)ix|ex$/i' => '\1ices', + '/(x|ch|ss|sh)$/i' => '\1es', + '/([^aeiouy]|qu)ies$/i' => '\1y', + '/([^aeiouy]|qu)y$/i' => '\1ies', + '/(hive)$/i' => '\1s', + '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', + '/sis$/i' => 'ses', + '/([ti])um$/i' => '\1a', + '/(buffal|tomat)o$/i' => '\1oes', + '/(bu)s$/i' => '1ses', + '/(alias|status)/i' => '\1es', + '/(octop|vir)us$/i' => '1i', + '/(ax|test)is$/i' => '\1es', + '/s$/i' => 's', + '/$/' => 's' + ); + + $uncountable = array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep' ); $irregular = array( - 'person' => 'people', - 'man' => 'men', - 'woman' => 'women', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves'); + 'person' => 'people', + 'man' => 'men', + 'woman' => 'women', + 'child' => 'children', + 'sex' => 'sexes', + 'move' => 'moves' + ); - $lowercased_word = strtolower($word); + $lowercased_word = strtolower( $word ); - foreach ($uncountable as $_uncountable){ - if(substr($lowercased_word,(-1*strlen($_uncountable))) == $_uncountable){ + foreach ( $uncountable as $_uncountable ){ + if( substr( $lowercased_word, ( -1 * strlen( $_uncountable) ) ) == $_uncountable ){ return $word; } } - foreach ($irregular as $_plural=> $_singular){ - if (preg_match('/('.$_plural.')$/i', $word, $arr)) { - return preg_replace('/('.$_plural.')$/i', substr($arr[0],0,1).substr($_singular,1), $word); + foreach ( $irregular as $_plural=> $_singular ){ + if ( preg_match( '/('.$_plural.')$/i', $word, $arr ) ) { + return preg_replace( '/('.$_plural.')$/i', substr( $arr[0], 0, 1 ).substr( $_singular, 1 ), $word ); } } - foreach ($plural as $rule => $replacement) { - if (preg_match($rule, $word)) { - return preg_replace($rule, $replacement, $word); + foreach ( $plural as $rule => $replacement ) { + if ( preg_match( $rule, $word ) ) { + return preg_replace( $rule, $replacement, $word ); } } return false; From 792b33a7c1aadc9b67d51504d169721b6a20df3b Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 16:01:30 +0100 Subject: [PATCH 0862/5359] removed the lp_ prefixes --- .../internals/skeletons/post_type_skeleton.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 8e2adb121..1b9e0018a 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -40,7 +40,7 @@ ); endif; - function lp_{$machine_name}_updated_messages( \$messages ) { + function {$machine_name}_updated_messages( \$messages ) { global \$post, \$post_ID; \$messages['{$post_type}'] = array( @@ -62,22 +62,22 @@ function lp_{$machine_name}_updated_messages( \$messages ) { return \$messages; } - add_filter( 'post_updated_messages', 'lp_{$machine_name}_updated_messages' ); + add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' ); - function lp_pre_single_{$machine_name}( \$query ) { + function pre_single_{$machine_name}( \$query ) { if ( !is_admin() && get_post_type() == '{$post_type}' && is_main_query() ) { // use \$query->set() to change the main query // or use this function to hook in some other specific code } } - add_action( 'pre_get_posts', 'lp_pre_single_{$machine_name}' ); + add_action( 'pre_get_posts', 'pre_single_{$machine_name}' ); - function lp_pre_archive_{$machine_name}( \$query ) { + function pre_archive_{$machine_name}( \$query ) { if ( !is_admin() && is_post_type_archive( '{$post_type}' ) ) { // use \$query->set() to change the main query // or use this function to hook in some other specific code } } - add_action( 'pre_get_posts', 'lp_pre_archive_{$machine_name}' );"; \ No newline at end of file + add_action( 'pre_get_posts', 'pre_archive_{$machine_name}' );"; \ No newline at end of file From e3fabdaf87a565476270519cfe3ba2830f0132fe Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 16:08:04 +0100 Subject: [PATCH 0863/5359] changed the post type exists to a init hook --- .../commands/internals/skeletons/post_type_skeleton.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 1b9e0018a..5a5d04679 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -1,7 +1,7 @@ <?php $output = "<?php - if (!post_type_exists( '{$post_type}' ) ) : + function {$machine_name}_init() { register_post_type( '{$post_type}', array( 'label' => __( '{$label_plural_ucfirst}', '{$context}' ), @@ -38,7 +38,7 @@ ), ) ); - endif; + add_action( 'init', '{$machine_name}_init' ); function {$machine_name}_updated_messages( \$messages ) { global \$post, \$post_ID; From 1e19b444e969e24674f4695052ad5e0531d1849f Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 16:20:15 +0100 Subject: [PATCH 0864/5359] Revoved the templating related hooks so we get a more general scaffolding command --- .../skeletons/post_type_skeleton.php | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 5a5d04679..ac0a93e48 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -62,22 +62,4 @@ function {$machine_name}_updated_messages( \$messages ) { return \$messages; } - add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' ); - - function pre_single_{$machine_name}( \$query ) { - if ( !is_admin() && get_post_type() == '{$post_type}' && is_main_query() ) { - // use \$query->set() to change the main query - // or use this function to hook in some other specific code - - } - } - add_action( 'pre_get_posts', 'pre_single_{$machine_name}' ); - - function pre_archive_{$machine_name}( \$query ) { - if ( !is_admin() && is_post_type_archive( '{$post_type}' ) ) { - // use \$query->set() to change the main query - // or use this function to hook in some other specific code - - } - } - add_action( 'pre_get_posts', 'pre_archive_{$machine_name}' );"; \ No newline at end of file + add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' ); \ No newline at end of file From 008e4dcae5979f643db047e73903b337b04e893d Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Wed, 28 Nov 2012 16:22:57 +0100 Subject: [PATCH 0865/5359] changed context to textdomain in the post type template --- .../skeletons/post_type_skeleton.php | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index ac0a93e48..2efa3b671 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -4,8 +4,8 @@ function {$machine_name}_init() { register_post_type( '{$post_type}', array( - 'label' => __( '{$label_plural_ucfirst}', '{$context}' ), - 'description' => __( '{$description}', '{$context}' ), + 'label' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'description' => __( '{$description}', '{$textdomain}' ), 'public' => {$public}, 'exclude_from_search' => {$exclude_from_search}, 'show_ui' => {$show_ui}, @@ -22,19 +22,19 @@ function {$machine_name}_init() { 'query_var' => {$query_var}, 'can_export' => {$can_export}, 'labels' => array( - 'name' => __( '{$label_plural_ucfirst}', '{$context}' ), - 'singular_name' => __( '{$label_ucfirst}', '{$context}' ), - 'add_new' => __( 'Add new {$label}', '{$context}' ), - 'all_items' => __( '{$label_plural_ucfirst}', '{$context}' ), - 'add_new_item' => __( 'Add new {$label}', '{$context}' ), - 'edit_item' => __( 'Edit {$label}', '{$context}' ), - 'new_item' => __( 'New {$label}', '{$context}' ), - 'view_item' => __( 'View {$label}', '{$context}' ), - 'search_items' => __( 'Search {$label_plural}', '{$context}' ), - 'not_found' => __( 'No {$label_plural} found', '{$context}' ), - 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$context}' ), - 'parent_item_colon' => __( 'Parent {$label}', '{$context}' ), - 'menu_name' => __( '{$label_plural_ucfirst}', '{$context}' ), + 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), + 'add_new' => __( 'Add new {$label}', '{$textdomain}' ), + 'all_items' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'add_new_item' => __( 'Add new {$label}', '{$textdomain}' ), + 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), + 'new_item' => __( 'New {$label}', '{$textdomain}' ), + 'view_item' => __( 'View {$label}', '{$textdomain}' ), + 'search_items' => __( 'Search {$label_plural}', '{$textdomain}' ), + 'not_found' => __( 'No {$label_plural} found', '{$textdomain}' ), + 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$textdomain}' ), + 'parent_item_colon' => __( 'Parent {$label}', '{$textdomain}' ), + 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), ), ) ); @@ -45,19 +45,19 @@ function {$machine_name}_updated_messages( \$messages ) { \$messages['{$post_type}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), - 2 => __('Custom field updated.', '{$context}'), - 3 => __('Custom field deleted.', '{$context}'), - 4 => __('{$label_ucfirst} updated.', '{$context}'), + 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 2 => __('Custom field updated.', '{$textdomain}'), + 3 => __('Custom field deleted.', '{$textdomain}'), + 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), /* translators: %s: date and time of the revision */ - 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$context}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$context}'), esc_url( get_permalink(\$post_ID) ) ), - 7 => __('{$label_ucfirst} saved.', '{$context}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$context}'), + 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$textdomain}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$context}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), ); return \$messages; From 0a00a36196f2d98c1f18bb8da6fc81868dfc8c48 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 21:08:47 +0100 Subject: [PATCH 0866/5359] Correctly closed String at the end off the file --- .../wp-cli/commands/internals/skeletons/post_type_skeleton.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 2efa3b671..55802cd88 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -62,4 +62,4 @@ function {$machine_name}_updated_messages( \$messages ) { return \$messages; } - add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' ); \ No newline at end of file + add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file From 84e4949b89372fb1ec0080fdd25627a11916316a Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 21:30:10 +0100 Subject: [PATCH 0867/5359] Added closing curly bracket for post type init --- .../wp-cli/commands/internals/skeletons/post_type_skeleton.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 55802cd88..3f1be737e 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -38,6 +38,7 @@ function {$machine_name}_init() { ), ) ); + } add_action( 'init', '{$machine_name}_init' ); function {$machine_name}_updated_messages( \$messages ) { From db965366098421f28fafa914334fa42d5b7d01cc Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 21:33:50 +0100 Subject: [PATCH 0868/5359] Changed getext $context to $textdomain --- .../internals/skeletons/taxonomy_skeleton.php | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php index 482962782..841eb725d 100755 --- a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -3,21 +3,21 @@ if ( !taxonomy_exists( '{$taxonomy}' ) ) : \$labels = array( - 'name' => __( '{$taxonomy}', '{$context}' ), - 'singular_name' => __( '{$taxonomy}', '{$context}' ), - 'search_items' => __( 'Search {$taxonomy}', '{$context}' ), - 'popular_items' => __( 'Popular {$taxonomy}', '{$context}' ), - 'all_items' => __( 'All {$taxonomy}', '{$context}' ), - 'parent_item' => __( 'Parent {$taxonomy}', '{$context}' ), - 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$context}' ), - 'edit_item' => __( 'Edit {$taxonomy}', '{$context}' ), - 'update_item' => __( 'Update {$taxonomy}', '{$context}' ), - 'add_new_item' => __( 'New {$taxonomy}', '{$context}' ), - 'new_item_name' => __( 'New {$taxonomy}', '{$context}' ), - 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$context}' ), - 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$context}' ), - 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$context}' ), - 'menu_name' => __( '{$taxonomy}s', '{$context}' ), + 'name' => __( '{$taxonomy}', '{$textdomain}' ), + 'singular_name' => __( '{$taxonomy}', '{$textdomain}' ), + 'search_items' => __( 'Search {$taxonomy}', '{$textdomain}' ), + 'popular_items' => __( 'Popular {$taxonomy}', '{$textdomain}' ), + 'all_items' => __( 'All {$taxonomy}', '{$textdomain}' ), + 'parent_item' => __( 'Parent {$taxonomy}', '{$textdomain}' ), + 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$textdomain}' ), + 'edit_item' => __( 'Edit {$taxonomy}', '{$textdomain}' ), + 'update_item' => __( 'Update {$taxonomy}', '{$textdomain}' ), + 'add_new_item' => __( 'New {$taxonomy}', '{$textdomain}' ), + 'new_item_name' => __( 'New {$taxonomy}', '{$textdomain}' ), + 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$textdomain}' ), + 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$textdomain}' ), + 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$textdomain}' ), + 'menu_name' => __( '{$taxonomy}s', '{$textdomain}' ), ); \$args = array( From 0a5fa7bccf42a3022a247a5b58b8d97f96b8d0e4 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 21:35:26 +0100 Subject: [PATCH 0869/5359] Removed unneccesary indentation --- .../skeletons/post_type_skeleton.php | 122 +++++++++--------- .../internals/skeletons/taxonomy_skeleton.php | 88 ++++++------- 2 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 3f1be737e..613518b33 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -1,66 +1,66 @@ <?php - $output = "<?php +$output = "<?php - function {$machine_name}_init() { - register_post_type( '{$post_type}', - array( - 'label' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'description' => __( '{$description}', '{$textdomain}' ), - 'public' => {$public}, - 'exclude_from_search' => {$exclude_from_search}, - 'show_ui' => {$show_ui}, - 'show_in_nav_menus' => {$show_in_nav_menus}, - 'show_in_menu' => {$show_in_menu}, - 'show_in_admin_bar' => {$show_in_admin_bar}, - 'menu_position' => {$menu_position}, - 'menu_icon' => {$menu_icon}, - 'capability_type' => '{$capability_type}', - 'hierarchical' => {$hierarchical}, - 'supports' => array( {$supports} ), - 'has_archive' => {$has_archive}, - 'rewrite' => array( 'slug' => '{$slug}', 'feeds' => {$feeds}, 'pages' => {$pages} ), - 'query_var' => {$query_var}, - 'can_export' => {$can_export}, - 'labels' => array( - 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), - 'add_new' => __( 'Add new {$label}', '{$textdomain}' ), - 'all_items' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'add_new_item' => __( 'Add new {$label}', '{$textdomain}' ), - 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), - 'new_item' => __( 'New {$label}', '{$textdomain}' ), - 'view_item' => __( 'View {$label}', '{$textdomain}' ), - 'search_items' => __( 'Search {$label_plural}', '{$textdomain}' ), - 'not_found' => __( 'No {$label_plural} found', '{$textdomain}' ), - 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$textdomain}' ), - 'parent_item_colon' => __( 'Parent {$label}', '{$textdomain}' ), - 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - ), - ) - ); - } - add_action( 'init', '{$machine_name}_init' ); +function {$machine_name}_init() { + register_post_type( '{$post_type}', + array( + 'label' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'description' => __( '{$description}', '{$textdomain}' ), + 'public' => {$public}, + 'exclude_from_search' => {$exclude_from_search}, + 'show_ui' => {$show_ui}, + 'show_in_nav_menus' => {$show_in_nav_menus}, + 'show_in_menu' => {$show_in_menu}, + 'show_in_admin_bar' => {$show_in_admin_bar}, + 'menu_position' => {$menu_position}, + 'menu_icon' => {$menu_icon}, + 'capability_type' => '{$capability_type}', + 'hierarchical' => {$hierarchical}, + 'supports' => array( {$supports} ), + 'has_archive' => {$has_archive}, + 'rewrite' => array( 'slug' => '{$slug}', 'feeds' => {$feeds}, 'pages' => {$pages} ), + 'query_var' => {$query_var}, + 'can_export' => {$can_export}, + 'labels' => array( + 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), + 'add_new' => __( 'Add new {$label}', '{$textdomain}' ), + 'all_items' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'add_new_item' => __( 'Add new {$label}', '{$textdomain}' ), + 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), + 'new_item' => __( 'New {$label}', '{$textdomain}' ), + 'view_item' => __( 'View {$label}', '{$textdomain}' ), + 'search_items' => __( 'Search {$label_plural}', '{$textdomain}' ), + 'not_found' => __( 'No {$label_plural} found', '{$textdomain}' ), + 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$textdomain}' ), + 'parent_item_colon' => __( 'Parent {$label}', '{$textdomain}' ), + 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + ), + ) + ); +} +add_action( 'init', '{$machine_name}_init' ); - function {$machine_name}_updated_messages( \$messages ) { - global \$post, \$post_ID; +function {$machine_name}_updated_messages( \$messages ) { + global \$post, \$post_ID; - \$messages['{$post_type}'] = array( - 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 2 => __('Custom field updated.', '{$textdomain}'), - 3 => __('Custom field deleted.', '{$textdomain}'), - 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), - /* translators: %s: date and time of the revision */ - 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$textdomain}'), - // translators: Publish box date format, see http://php.net/date - date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), - ); + \$messages['{$post_type}'] = array( + 0 => '', // Unused. Messages start at index 1. + 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 2 => __('Custom field updated.', '{$textdomain}'), + 3 => __('Custom field deleted.', '{$textdomain}'), + 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), + /* translators: %s: date and time of the revision */ + 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$textdomain}'), + // translators: Publish box date format, see http://php.net/date + date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + ); - return \$messages; - } - add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file + return \$messages; +} +add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php index 841eb725d..992f4bb7d 100755 --- a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -1,47 +1,47 @@ <?php - $output = "<?php +$output = "<?php - if ( !taxonomy_exists( '{$taxonomy}' ) ) : - \$labels = array( - 'name' => __( '{$taxonomy}', '{$textdomain}' ), - 'singular_name' => __( '{$taxonomy}', '{$textdomain}' ), - 'search_items' => __( 'Search {$taxonomy}', '{$textdomain}' ), - 'popular_items' => __( 'Popular {$taxonomy}', '{$textdomain}' ), - 'all_items' => __( 'All {$taxonomy}', '{$textdomain}' ), - 'parent_item' => __( 'Parent {$taxonomy}', '{$textdomain}' ), - 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$textdomain}' ), - 'edit_item' => __( 'Edit {$taxonomy}', '{$textdomain}' ), - 'update_item' => __( 'Update {$taxonomy}', '{$textdomain}' ), - 'add_new_item' => __( 'New {$taxonomy}', '{$textdomain}' ), - 'new_item_name' => __( 'New {$taxonomy}', '{$textdomain}' ), - 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$textdomain}' ), - 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$textdomain}' ), - 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$textdomain}' ), - 'menu_name' => __( '{$taxonomy}s', '{$textdomain}' ), - ); - - \$args = array( - 'labels' => \$labels, - 'public' => {$public}, - 'show_in_nav_menus' => {$show_in_nav_menus}, - 'show_ui' => {$show_ui}, - 'show_tagcloud' => {$show_tagcloud}, - 'hierarchical' => {$hierarchical}, - 'update_count_callback' => '_update_post_term_count', - 'rewrite' => {$rewrite}, - 'query_var' => {$query_var}, - 'capabilities' => array ( - 'manage_terms' => 'edit_posts', - 'edit_terms' => 'edit_posts', - 'delete_terms' => 'edit_posts', - 'assign_terms' => 'edit_posts' - ), - 'rewrite' => array( - 'slug' => '{$taxonomy}', - 'hierarchical' => {$hierarchical} - ), - ); - - register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args ); +if ( !taxonomy_exists( '{$taxonomy}' ) ) : + \$labels = array( + 'name' => __( '{$taxonomy}', '{$textdomain}' ), + 'singular_name' => __( '{$taxonomy}', '{$textdomain}' ), + 'search_items' => __( 'Search {$taxonomy}', '{$textdomain}' ), + 'popular_items' => __( 'Popular {$taxonomy}', '{$textdomain}' ), + 'all_items' => __( 'All {$taxonomy}', '{$textdomain}' ), + 'parent_item' => __( 'Parent {$taxonomy}', '{$textdomain}' ), + 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$textdomain}' ), + 'edit_item' => __( 'Edit {$taxonomy}', '{$textdomain}' ), + 'update_item' => __( 'Update {$taxonomy}', '{$textdomain}' ), + 'add_new_item' => __( 'New {$taxonomy}', '{$textdomain}' ), + 'new_item_name' => __( 'New {$taxonomy}', '{$textdomain}' ), + 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$textdomain}' ), + 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$textdomain}' ), + 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$textdomain}' ), + 'menu_name' => __( '{$taxonomy}s', '{$textdomain}' ), + ); - endif;"; \ No newline at end of file + \$args = array( + 'labels' => \$labels, + 'public' => {$public}, + 'show_in_nav_menus' => {$show_in_nav_menus}, + 'show_ui' => {$show_ui}, + 'show_tagcloud' => {$show_tagcloud}, + 'hierarchical' => {$hierarchical}, + 'update_count_callback' => '_update_post_term_count', + 'rewrite' => {$rewrite}, + 'query_var' => {$query_var}, + 'capabilities' => array ( + 'manage_terms' => 'edit_posts', + 'edit_terms' => 'edit_posts', + 'delete_terms' => 'edit_posts', + 'assign_terms' => 'edit_posts' + ), + 'rewrite' => array( + 'slug' => '{$taxonomy}', + 'hierarchical' => {$hierarchical} + ), + ); + + register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args ); + +endif;"; \ No newline at end of file From 03f320b8212cd493e543ac455f17168ff109d981 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 21:49:21 +0100 Subject: [PATCH 0870/5359] Removed the hardcoded S for pluralizing taxonomy name --- .../commands/internals/skeletons/taxonomy_skeleton.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php index 992f4bb7d..75b41dfdc 100755 --- a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -14,10 +14,10 @@ 'update_item' => __( 'Update {$taxonomy}', '{$textdomain}' ), 'add_new_item' => __( 'New {$taxonomy}', '{$textdomain}' ), 'new_item_name' => __( 'New {$taxonomy}', '{$textdomain}' ), - 'separate_items_with_commas' => __( '{$taxonomy}s seperated by comma', '{$textdomain}' ), - 'add_or_remove_items' => __( 'Add or remove {$taxonomy}s', '{$textdomain}' ), + 'separate_items_with_commas' => __( '{$taxonomy} seperated by comma', '{$textdomain}' ), + 'add_or_remove_items' => __( 'Add or remove {$taxonomy}', '{$textdomain}' ), 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$textdomain}' ), - 'menu_name' => __( '{$taxonomy}s', '{$textdomain}' ), + 'menu_name' => __( '{$taxonomy}', '{$textdomain}' ), ); \$args = array( From 0b1bb6b9ec8a4fdc4bf5b54caa63a5e75603c7b1 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 28 Nov 2012 22:01:36 +0100 Subject: [PATCH 0871/5359] Using pluralize function and added beter labels to Taxonomy skeleton --- .../wp-cli/commands/internals/scaffold.php | 8 ++++-- .../internals/skeletons/taxonomy_skeleton.php | 26 +++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index c61769001..6c5883f5a 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -96,11 +96,15 @@ function taxonomy( $args, $assoc_args ) { $taxonomy = strtolower( $args[0] ); // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $taxonomy ); + $machine_name = preg_replace( '/-/', '_', $taxonomy ); + $machine_name_plural = $this->pluralize( $taxonomy ); // If no label is given use the slug and prettify it as good as possible if( !isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', ucfirst( strtolower( $taxonomy ) ) ); + $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); + $label_ucfirst = ucfirst( $label ); + $label_plural = $this->pluralize( $label ); + $label_plural_ucfirst = ucfirst( $label_plural ); } // Set up defaults and merge theme with assoc_args diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php index 75b41dfdc..de7c5e7ad 100755 --- a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -3,21 +3,21 @@ if ( !taxonomy_exists( '{$taxonomy}' ) ) : \$labels = array( - 'name' => __( '{$taxonomy}', '{$textdomain}' ), - 'singular_name' => __( '{$taxonomy}', '{$textdomain}' ), + 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), + 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), 'search_items' => __( 'Search {$taxonomy}', '{$textdomain}' ), 'popular_items' => __( 'Popular {$taxonomy}', '{$textdomain}' ), - 'all_items' => __( 'All {$taxonomy}', '{$textdomain}' ), - 'parent_item' => __( 'Parent {$taxonomy}', '{$textdomain}' ), - 'parent_item_colon' => __( 'Parent {$taxonomy}:', '{$textdomain}' ), - 'edit_item' => __( 'Edit {$taxonomy}', '{$textdomain}' ), - 'update_item' => __( 'Update {$taxonomy}', '{$textdomain}' ), - 'add_new_item' => __( 'New {$taxonomy}', '{$textdomain}' ), - 'new_item_name' => __( 'New {$taxonomy}', '{$textdomain}' ), - 'separate_items_with_commas' => __( '{$taxonomy} seperated by comma', '{$textdomain}' ), - 'add_or_remove_items' => __( 'Add or remove {$taxonomy}', '{$textdomain}' ), - 'choose_from_most_used' => __( 'Choose from the most used {$taxonomy}', '{$textdomain}' ), - 'menu_name' => __( '{$taxonomy}', '{$textdomain}' ), + 'all_items' => __( 'All {$label_plural}', '{$textdomain}' ), + 'parent_item' => __( 'Parent {$label}', '{$textdomain}' ), + 'parent_item_colon' => __( 'Parent {$label}:', '{$textdomain}' ), + 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), + 'update_item' => __( 'Update {$label}', '{$textdomain}' ), + 'add_new_item' => __( 'New {$label}', '{$textdomain}' ), + 'new_item_name' => __( 'New {$label}', '{$textdomain}' ), + 'separate_items_with_commas' => __( '{$label_plural_ucfirst} seperated by comma', '{$textdomain}' ), + 'add_or_remove_items' => __( 'Add or remove {$label}', '{$textdomain}' ), + 'choose_from_most_used' => __( 'Choose from the most used {$label_plural}', '{$textdomain}' ), + 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), ); \$args = array( From 9217c1f6b2ad5509ed76e9f1760683696ab1ab2f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 1 Dec 2012 22:07:05 +0200 Subject: [PATCH 0872/5359] update manpage for plugin/theme update; add manpage for update-all. fixes #228 --- man/plugin-update-all.1 | 19 ++++++++++++++++++- man/plugin-update.1 | 12 ++---------- man/theme-update-all.1 | 19 ++++++++++++++++++- man/theme-update.1 | 10 ++++------ src/docs/plugin-update-all.txt | 9 +++++++++ src/docs/plugin-update.txt | 11 ++--------- src/docs/theme-update-all.txt | 9 +++++++++ src/docs/theme-update.txt | 10 ++++------ src/php/wp-cli/commands/internals/theme.php | 2 +- 9 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 src/docs/plugin-update-all.txt create mode 100644 src/docs/theme-update-all.txt diff --git a/man/plugin-update-all.1 b/man/plugin-update-all.1 index 0e0806909..5198fd1e8 100644 --- a/man/plugin-update-all.1 +++ b/man/plugin-update-all.1 @@ -1,10 +1,27 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-PLUGIN\-UPDATE\-ALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-PLUGIN\-UPDATE\-ALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-plugin\-update\-all\fR \- Update all plugins\. . .SH "SYNOPSIS" \fBwp plugin update\-all\fR [\-\-dry\-run] +. +.SH "OPTIONS" +. +.TP +\fB\-\-dry\-run\fR: +. +.IP +Pretend to do the updates, to see what would happen\. +. +.SH "EXAMPLES" +. +.nf + +wp plugin update\-all +. +.fi + diff --git a/man/plugin-update.1 b/man/plugin-update.1 index 13a769112..5f38ffda6 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -15,27 +15,19 @@ \fIplugin\fR: . .IP -The plugin to update\. Can be omitted when \-\-all is passed\. +The plugin to update\. . .TP \fB\-\-version=dev\fR: . .IP -If set, the plugin will be updated to the latest development version, regardless of what version is currently installed\. Not compatible with \-\-all\. -. -.TP -\fB\-\-all\fR: -. -.IP -If set, updates for all plugins will be performed\. Use \fBwp plugin status\fR to see which plugins have updates available\. +If set, the plugin will be updated to the latest development version, regardless of what version is currently installed\. . .SH "EXAMPLES" . .nf wp plugin update bbpress \-\-version=dev - -wp plugin update \-\-all . .fi diff --git a/man/theme-update-all.1 b/man/theme-update-all.1 index 27a2beda1..057f3f4c9 100644 --- a/man/theme-update-all.1 +++ b/man/theme-update-all.1 @@ -1,10 +1,27 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-THEME\-UPDATE\-ALL" "1" "October 2012" "" "WP-CLI" +.TH "WP\-THEME\-UPDATE\-ALL" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-theme\-update\-all\fR \- Update all themes\. . .SH "SYNOPSIS" \fBwp theme update\-all\fR [\-\-dry\-run] +. +.SH "OPTIONS" +. +.TP +\fB\-\-dry\-run\fR: +. +.IP +Pretend to do the updates, to see what would happen\. +. +.SH "EXAMPLES" +. +.nf + +wp theme update\-all +. +.fi + diff --git a/man/theme-update.1 b/man/theme-update.1 index 9f5ec07d8..cb5f09b3b 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-update\fR \- Update a theme\. . .SH "SYNOPSIS" -\fBwp theme update\fR \fItheme\fR +\fBwp theme update\fR \fItheme\fR [\-\-version=\fIversion\fR] . .SH "OPTIONS" . @@ -15,21 +15,19 @@ \fItheme\fR: . .IP -The theme to update\. Can be omitted when \-\-all is passed\. +The theme to update\. . .TP -\fB\-\-all\fR: +\fB\-\-version=dev\fR: . .IP -If set, updates for all themes will be performed\. Use \fBwp theme status\fR to see which themes have updates available\. +If set, the theme will be updated to the latest development version, regardless of what version is currently installed\. . .SH "EXAMPLES" . .nf wp theme update twentytwelve - -wp theme update \-\-all . .fi diff --git a/src/docs/plugin-update-all.txt b/src/docs/plugin-update-all.txt new file mode 100644 index 000000000..8ba4aaa51 --- /dev/null +++ b/src/docs/plugin-update-all.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--dry-run`: + + Pretend to do the updates, to see what would happen. + +## EXAMPLES + + wp plugin update-all diff --git a/src/docs/plugin-update.txt b/src/docs/plugin-update.txt index 8bc68da0d..563c30373 100644 --- a/src/docs/plugin-update.txt +++ b/src/docs/plugin-update.txt @@ -2,20 +2,13 @@ * <plugin>: - The plugin to update. Can be omitted when --all is passed. + The plugin to update. * `--version=dev`: If set, the plugin will be updated to the latest development version, -regardless of what version is currently installed. Not compatible with --all. - -* `--all`: - - If set, updates for all plugins will be performed. Use `wp plugin status` -to see which plugins have updates available. +regardless of what version is currently installed. ## EXAMPLES wp plugin update bbpress --version=dev - - wp plugin update --all diff --git a/src/docs/theme-update-all.txt b/src/docs/theme-update-all.txt new file mode 100644 index 000000000..5d24e29a5 --- /dev/null +++ b/src/docs/theme-update-all.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--dry-run`: + + Pretend to do the updates, to see what would happen. + +## EXAMPLES + + wp theme update-all diff --git a/src/docs/theme-update.txt b/src/docs/theme-update.txt index 9c37f8229..d3439e48a 100644 --- a/src/docs/theme-update.txt +++ b/src/docs/theme-update.txt @@ -2,15 +2,13 @@ * <theme>: - The theme to update. Can be omitted when --all is passed. + The theme to update. -* `--all`: +* `--version=dev`: - If set, updates for all themes will be performed. Use `wp theme status` -to see which themes have updates available. + If set, the theme will be updated to the latest development version, +regardless of what version is currently installed. ## EXAMPLES wp theme update twentytwelve - - wp theme update --all diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index 733c6b2b8..d028937f8 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -168,7 +168,7 @@ function install( $args, $assoc_args ) { /** * Update a theme. * - * @synopsis <theme> + * @synopsis <theme> [--version=<version>] */ function update( $args, $assoc_args ) { parent::update( $args, $assoc_args ); From b444962c3bc99993328627950d8d832bb1e679d2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 15:53:22 +0200 Subject: [PATCH 0873/5359] total-cache: remove redundant check for w3tc_pgcache_flush() function --- .../wp-cli/commands/community/total-cache.php | 110 +++++++++--------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index 8e1a35a4c..80e5b49fa 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -20,76 +20,72 @@ class W3TotalCache_Command extends WP_CLI_Command { * @param array $vars */ function flush( $args = array(), $vars = array() ) { - if ( function_exists( 'w3tc_pgcache_flush' ) ) { - $args = array_unique( $args ); - do { - $cache_type = array_shift($args); + $args = array_unique( $args ); + do { + $cache_type = array_shift($args); - switch($cache_type) { - case 'db': - case 'database': - if ( w3tc_dbcache_flush() ) { - WP_CLI::success( 'The database cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the database cache failed.' ); - } - break; + switch($cache_type) { + case 'db': + case 'database': + if ( w3tc_dbcache_flush() ) { + WP_CLI::success( 'The database cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the database cache failed.' ); + } + break; - case 'minify': - if ( w3tc_minify_flush() ) { - WP_CLI::success( 'The minify cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the minify cache failed.' ); - } - break; + case 'minify': + if ( w3tc_minify_flush() ) { + WP_CLI::success( 'The minify cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the minify cache failed.' ); + } + break; - case 'object': - if ( w3tc_objectcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; + case 'object': + if ( w3tc_objectcache_flush() ) { + WP_CLI::success( 'The object cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the object cache failed.' ); + } + break; - case 'page': - if ( w3tc_pgcache_flush() ) { - WP_CLI::success( 'The page cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the page cache failed.' ); - } - break; + case 'page': + if ( w3tc_pgcache_flush() ) { + WP_CLI::success( 'The page cache is flushed successfully.' ); + } else { + WP_CLI::error( 'Flushing the page cache failed.' ); + } + break; - case 'post': - default: - if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) && get_post( $vars['post_id'] ) ) { - if ( w3tc_pgcache_flush_post( $vars['post_id'] ) ) { - WP_CLI::success( 'Post '.$vars['post_id'].' is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing '.$vars['post_id'].' from cache failed.' ); - } + case 'post': + default: + if ( isset($vars['post_id']) ) { + if ( is_numeric( $vars['post_id'] ) && get_post( $vars['post_id'] ) ) { + if ( w3tc_pgcache_flush_post( $vars['post_id'] ) ) { + WP_CLI::success( 'Post '.$vars['post_id'].' is flushed successfully.' ); } else { - WP_CLI::error('This is not a valid post id.'); + WP_CLI::error( 'Flushing '.$vars['post_id'].' from cache failed.' ); } + } else { + WP_CLI::error('This is not a valid post id.'); } - elseif ( isset( $vars['permalink'] ) ) { - $id = url_to_postid( $vars['permalink'] ); + } + elseif ( isset( $vars['permalink'] ) ) { + $id = url_to_postid( $vars['permalink'] ); - if ( is_numeric( $id ) && $id > 0 ) { - if ( w3tc_pgcache_flush_post( $id ) ) { - WP_CLI::success( $id.' is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing '.$id.' from cache failed.' ); - } + if ( is_numeric( $id ) && $id > 0 ) { + if ( w3tc_pgcache_flush_post( $id ) ) { + WP_CLI::success( $id.' is flushed successfully.' ); } else { - WP_CLI::error('There is no post with this permalink.'); + WP_CLI::error( 'Flushing '.$id.' from cache failed.' ); } + } else { + WP_CLI::error('There is no post with this permalink.'); } } - } while ( !empty( $args ) ); - } else { - WP_CLI::error('The W3 Total Cache could not be found, is it installed?'); - } + } + } while ( !empty( $args ) ); } /** From 7a91206f75cb0bc01c6c14ced3d29ec433a0ed37 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 15:58:22 +0200 Subject: [PATCH 0874/5359] total-cache: add `@synopsis` tag --- src/php/wp-cli/commands/community/total-cache.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index 80e5b49fa..6f565c198 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -5,19 +5,17 @@ } /** - * The WP Super Cache plugin + * The W3 Total Cache plugin * * @package wp-cli * @subpackage commands/community - * @maintainer Andreas Creten */ class W3TotalCache_Command extends WP_CLI_Command { /** - * Clear something from the cache + * Clear something from the cache. * - * @param array $args - * @param array $vars + * @synopsis <cache-type>... [--post_id=<post-id>] [--permalink=<permalink>] */ function flush( $args = array(), $vars = array() ) { $args = array_unique( $args ); From 63789aa3e95e976043da616b7f2a19208a1bf2e0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 16:06:51 +0200 Subject: [PATCH 0875/5359] total-cache: update static help() method --- src/php/wp-cli/commands/community/total-cache.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index 6f565c198..e8c934d8f 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -91,16 +91,11 @@ function flush( $args = array(), $vars = array() ) { */ public static function help() { WP_CLI::line( <<<EOB -usage: wp total-cache flush [post|database|minify|object|page] [--post_id=<post-id>] [--permalink=<post-permalink>] - Available sub-commands: flush - --post_id=<id> flush specific ID - --permalink=<post-permalink> flush specific permalink - database flushes database cache - object flush object cache - minify flush minify cache - page flush page cache + <cache-type> post|database|minify|object|page + --post_id=<id> flush post cache with specific ID + --permalink=<post-permalink> flush post cache with specific permalink EOB ); } From 641d5b03d031aa1f06129102c1e2a920ff27e065 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 16:10:05 +0200 Subject: [PATCH 0876/5359] total-cache: s/vars/assoc_args/g --- .../wp-cli/commands/community/total-cache.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php index e8c934d8f..5bfd11162 100644 --- a/src/php/wp-cli/commands/community/total-cache.php +++ b/src/php/wp-cli/commands/community/total-cache.php @@ -17,12 +17,12 @@ class W3TotalCache_Command extends WP_CLI_Command { * * @synopsis <cache-type>... [--post_id=<post-id>] [--permalink=<permalink>] */ - function flush( $args = array(), $vars = array() ) { + function flush( $args = array(), $assoc_args = array() ) { $args = array_unique( $args ); do { - $cache_type = array_shift($args); + $cache_type = array_shift( $args ); - switch($cache_type) { + switch( $cache_type ) { case 'db': case 'database': if ( w3tc_dbcache_flush() ) { @@ -58,19 +58,19 @@ function flush( $args = array(), $vars = array() ) { case 'post': default: - if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) && get_post( $vars['post_id'] ) ) { - if ( w3tc_pgcache_flush_post( $vars['post_id'] ) ) { - WP_CLI::success( 'Post '.$vars['post_id'].' is flushed successfully.' ); + if ( isset($assoc_args['post_id']) ) { + if ( is_numeric( $assoc_args['post_id'] ) && get_post( $assoc_args['post_id'] ) ) { + if ( w3tc_pgcache_flush_post( $assoc_args['post_id'] ) ) { + WP_CLI::success( 'Post '.$assoc_args['post_id'].' is flushed successfully.' ); } else { - WP_CLI::error( 'Flushing '.$vars['post_id'].' from cache failed.' ); + WP_CLI::error( 'Flushing '.$assoc_args['post_id'].' from cache failed.' ); } } else { WP_CLI::error('This is not a valid post id.'); } } - elseif ( isset( $vars['permalink'] ) ) { - $id = url_to_postid( $vars['permalink'] ); + elseif ( isset( $assoc_args['permalink'] ) ) { + $id = url_to_postid( $assoc_args['permalink'] ); if ( is_numeric( $id ) && $id > 0 ) { if ( w3tc_pgcache_flush_post( $id ) ) { From 7eb8abfbfb769c9c6507c3ec9c7078f0a801dd56 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 17:35:29 +0200 Subject: [PATCH 0877/5359] super-cache command cleanup: * removed redundant function checks * added @synopsis tags * s/$vars/$assoc_args/g --- .../wp-cli/commands/community/super-cache.php | 109 ++++++------------ 1 file changed, 37 insertions(+), 72 deletions(-) diff --git a/src/php/wp-cli/commands/community/super-cache.php b/src/php/wp-cli/commands/community/super-cache.php index a78d5918a..4902b12bf 100644 --- a/src/php/wp-cli/commands/community/super-cache.php +++ b/src/php/wp-cli/commands/community/super-cache.php @@ -9,50 +9,41 @@ * * @package wp-cli * @subpackage commands/community - * @maintainer Andreas Creten */ class WPSuperCache_Command extends WP_CLI_Command { /** - * Clear something from the cache + * Clear something from the cache. * - * @param array $args - * @param array $vars + * @synopsis [--post_id=<post-id>] [--permalink=<permalink>] */ - function flush( $args = array(), $vars = array() ) { - if ( function_exists( 'wp_cache_clear_cache' ) ) { - if ( isset($vars['post_id']) ) { - if ( is_numeric( $vars['post_id'] ) ) { - wp_cache_post_change( $vars['post_id'] ); - } else { - WP_CLI::error('This is not a valid post id.'); - } - - wp_cache_post_change( $vars['post_id'] ); + function flush( $args = array(), $assoc_args = array() ) { + if ( isset($assoc_args['post_id']) ) { + if ( is_numeric( $assoc_args['post_id'] ) ) { + wp_cache_post_change( $assoc_args['post_id'] ); + } else { + WP_CLI::error('This is not a valid post id.'); } - elseif ( isset( $vars['permalink'] ) ) { - $id = url_to_postid( $vars['permalink'] ); - if ( is_numeric( $id ) ) { - wp_cache_post_change( $id ); - } else { - WP_CLI::error('There is no post with this permalink.'); - } + wp_cache_post_change( $assoc_args['post_id'] ); + } + elseif ( isset( $assoc_args['permalink'] ) ) { + $id = url_to_postid( $assoc_args['permalink'] ); + + if ( is_numeric( $id ) ) { + wp_cache_post_change( $id ); } else { - wp_cache_clear_cache(); + WP_CLI::error('There is no post with this permalink.'); } } else { - WP_CLI::error('The WP Super Cache could not be found, is it installed?'); + wp_cache_clear_cache(); } } /** - * Get the status of the cache - * - * @param array $args - * @param array $vars + * Get the status of the cache. */ - function status( $args = array(), $vars = array() ) { + function status( $args = array(), $assoc_args = array() ) { $cache_stats = get_option( 'supercache_stats' ); if ( !empty( $cache_stats ) ) { @@ -77,58 +68,32 @@ function status( $args = array(), $vars = array() ) { } /** - * Enable the WP Super Cache - * - * @param array $args - * @param array $vars + * Enable the WP Super Cache. */ - function enable( $args = array(), $vars = array() ) { - if ( function_exists( 'wp_super_cache_enable' ) ) { - global $super_cache_enabled; - wp_super_cache_enable(); - if($super_cache_enabled) { - WP_CLI::success( 'The WP Super Cache is enabled.' ); - } else { - WP_CLI::error('The WP Super Cache is not enabled, check its settings page for more info.'); - } - } else { - WP_CLI::error('The WP Super Cache could not be found, is it installed?'); - } - } + function enable( $args = array(), $assoc_args = array() ) { + global $super_cache_enabled; - /** - * Disable the WP Super Cache - * - * @param array $args - * @param array $vars - */ - function disable( $args = array(), $vars = array() ) { - if ( function_exists( 'wp_super_cache_disable' ) ) { - global $super_cache_enabled; - wp_super_cache_disable(); - if(!$super_cache_enabled) { - WP_CLI::success( 'The WP Super Cache is disabled.' ); - } else { - WP_CLI::error('The WP Super Cache is still enabled, check its settings page for more info.'); - } + wp_super_cache_enable(); + + if($super_cache_enabled) { + WP_CLI::success( 'The WP Super Cache is enabled.' ); } else { - WP_CLI::error('The WP Super Cache could not be found, is it installed?'); + WP_CLI::error('The WP Super Cache is not enabled, check its settings page for more info.'); } } /** - * Help function for this command + * Disable the WP Super Cache. */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp super-cache [flush|status|enable|disable] --post_id=<id> --permalink=<post-permalink> + function disable( $args = array(), $assoc_args = array() ) { + global $super_cache_enabled; + + wp_super_cache_disable(); -Available sub-commands: - flush flushes whole cache, or post with given permalink or ID --post_id=<id> --permalink=<post-permalink> - status shows status of WP Super Cache - enable enables WP Super Cache - disable disables WP Super Cache -EOB - ); + if(!$super_cache_enabled) { + WP_CLI::success( 'The WP Super Cache is disabled.' ); + } else { + WP_CLI::error('The WP Super Cache is still enabled, check its settings page for more info.'); + } } } From 5d34ebb3649832f6ae75e91d8cbb48eb9bdef161 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 17:46:09 +0200 Subject: [PATCH 0878/5359] super-cache: use wp_cache_clean_cache() wp_cache_clear_cache() doesn't exist --- src/php/wp-cli/commands/community/super-cache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/community/super-cache.php b/src/php/wp-cli/commands/community/super-cache.php index 4902b12bf..5e54f3392 100644 --- a/src/php/wp-cli/commands/community/super-cache.php +++ b/src/php/wp-cli/commands/community/super-cache.php @@ -36,7 +36,11 @@ function flush( $args = array(), $assoc_args = array() ) { WP_CLI::error('There is no post with this permalink.'); } } else { - wp_cache_clear_cache(); + global $file_prefix; + + wp_cache_clean_cache( $file_prefix, true ); + + WP_CLI::success( 'Cache cleared.' ); } } From d3ea6f0a18902cfafc26802e56cf1a446dee3e0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Dec 2012 18:13:41 +0200 Subject: [PATCH 0879/5359] google-sitemap: cleanup --- .../commands/community/google-sitemap.php | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/community/google-sitemap.php b/src/php/wp-cli/commands/community/google-sitemap.php index 424837323..37bbe53c1 100644 --- a/src/php/wp-cli/commands/community/google-sitemap.php +++ b/src/php/wp-cli/commands/community/google-sitemap.php @@ -9,30 +9,15 @@ * * @package wp-cli * @subpackage commands/community - * @maintainer Andreas Creten */ class GoogleSitemapGenerator_Command extends WP_CLI_Command { /** * Re-generate the sitemap - * - * @param array $args - * @param array $vars */ - function rebuild( $args = array(), $vars = array() ) { + function rebuild() { do_action( 'sm_rebuild' ); - } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -usage: wp google-sitemap [rebuild] -Available sub-commands: - rebuild rebuild Google sitemap -EOB - ); + WP_CLI::success( 'Sitemap rebuilt.' ); } } From e9d3cda0a7db2bfcfd35ce4f48294998b665615c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Dec 2012 01:34:39 +0000 Subject: [PATCH 0880/5359] Export: a new 'post__in' param for exporting specific posts Also sanitizes the filename, which should've been happening previously, and excludes the post__in arg from the generated filename because this particular argument can be a long list --- src/docs/export.txt | 4 +++ src/php/wp-cli/commands/internals/export.php | 29 ++++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/docs/export.txt b/src/docs/export.txt index ea92cb7f4..473fc515a 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -27,6 +27,10 @@ to current working directory. Export only posts with this post_type. +* `--post__in`=<pid>: + + Export all posts specified with IDs + * `--author`=<login/id>: Export only posts by this author. diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/internals/export.php index 32b4ff5b4..3ed26350e 100644 --- a/src/php/wp-cli/commands/internals/export.php +++ b/src/php/wp-cli/commands/internals/export.php @@ -19,7 +19,7 @@ class Export_Command extends WP_CLI_Command { /** * Export posts to a WXR file. * - * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] + * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] */ public function __invoke( $_, $assoc_args ) { $defaults = array( @@ -30,6 +30,7 @@ public function __invoke( $_, $assoc_args ) { 'author' => NULL, 'category' => NULL, 'post_status' => NULL, + 'post__in' => NULL, 'skip_comments' => NULL, 'file_item_count' => 1000, ); @@ -111,6 +112,19 @@ private function check_post_type( $post_type ) { return true; } + private function check_post__in( $post__in ) { + if ( is_null( $post__in ) ) + return true; + + $post__in = array_unique( array_map( 'intval', explode( ',', $post__in ) ) ); + if ( empty( $post__in ) ) { + WP_CLI::warning( "post__in should be comma-separated post IDs" ); + return false; + } + $this->export_args['post__in'] = implode( ',', $post__in ); + return true; + } + private function check_author( $author ) { if ( is_null( $author ) ) return true; @@ -238,7 +252,7 @@ private function export_wp( $args = array() ) { /** * This is mostly the original code of export_wp defined in wp-admin/includes/export.php */ - $defaults = array( 'post_type' => 'all', 'author' => false, 'category' => false, + $defaults = array( 'post_type' => 'all', 'post__in' => false, 'author' => false, 'category' => false, 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, 'file_item_count' => 1000, ); $args = wp_parse_args( $args, $defaults ); @@ -253,10 +267,10 @@ private function export_wp( $args = array() ) { $append = array( date( 'Y-m-d' ) ); foreach( array_keys( $args ) as $arg_key ) { - if ( $defaults[$arg_key] <> $args[$arg_key] ) + if ( $defaults[$arg_key] <> $args[$arg_key] && 'post__in' != $arg_key ) $append[]= "$arg_key-" . (string) $args[$arg_key]; } - $file_name_base = $sitename . 'wordpress.' . implode( ".", $append ); + $file_name_base = sanitize_file_name( $sitename . 'wordpress.' . implode( ".", $append ) ); if ( 'all' != $args['post_type'] && post_type_exists( $args['post_type'] ) ) { $ptype = get_post_type_object( $args['post_type'] ); @@ -294,10 +308,13 @@ private function export_wp( $args = array() ) { $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s", date( 'Y-m-d 23:59:59', strtotime( $args['end_date'] ) ) ); // grab a snapshot of post IDs, just in case it changes during the export - $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); + if ( empty( $args['post__in'] ) ) + $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); + else + $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE ID IN ({$args['post__in']}) ORDER BY post_date ASC, post_parent ASC" ); // Make sure we're getting all of the attachments for these posts too - if ( 'all' != $args['post_type'] ) { + if ( 'all' != $args['post_type'] || ! empty( $args['post__in'] ) ) { $all_post_ids_with_attachments = array(); while ( $post_ids = array_splice( $all_the_post_ids, 0, 100 ) ) { $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" ); From f28cdcc78a2d7665abd0ec3922db644e99f51a0a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Dec 2012 14:42:35 +0200 Subject: [PATCH 0881/5359] pretend we're in /wp-admin/ --- src/php/wp-cli/class-wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 973dd0606..e92960893 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -268,6 +268,10 @@ static function before_wp_load() { if ( array( 'core', 'install' ) == self::$arguments ) { define( 'WP_INSTALLING', true ); } + + // Pretend we're in WP_ADMIN, to side-step full-page caching plugins + define( 'WP_ADMIN', true ); + $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } static function after_wp_load() { From 543dcde0f33229f80b075538a0f8557556c0947e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Dec 2012 15:00:18 +0200 Subject: [PATCH 0882/5359] add post__in usage example --- man/export.1 | 10 +++++++++- src/docs/export.txt | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/man/export.1 b/man/export.1 index 5a3d58584..c23fee7ab 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,7 +7,7 @@ \fBwp\-export\fR \- Export posts to a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] +\fBwp export\fR [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post\fI\fIin=\fRpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] . .SH "OPTIONS" . @@ -50,6 +50,12 @@ Export only posts older than this date, in format YYYY\-MM\-DD\. Export only posts with this post_type\. . .TP +\fB\-\-post__in\fR=\fIpid\fR: +. +.IP +Export all posts specified as a comma\-separated list of IDs\. +. +.TP \fB\-\-author\fR=<login/id>: . .IP @@ -72,6 +78,8 @@ Export only posts with this status\. .nf wp export \-\-dir=/tmp/ \-\-user=admin \-\-post_type=post \-\-start_date=2011\-01\-01 \-\-end_date=2011\-12\-31 + +wp export \-\-dir=/tmp/ \-\-post__in=123,124,125 . .fi diff --git a/src/docs/export.txt b/src/docs/export.txt index 473fc515a..94e5cab4b 100644 --- a/src/docs/export.txt +++ b/src/docs/export.txt @@ -29,7 +29,7 @@ to current working directory. * `--post__in`=<pid>: - Export all posts specified with IDs + Export all posts specified as a comma-separated list of IDs. * `--author`=<login/id>: @@ -46,3 +46,5 @@ to current working directory. ## EXAMPLES wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + + wp export --dir=/tmp/ --post__in=123,124,125 From 330d3ec0c5f852f12cd47d121d1db063b239d8af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Dec 2012 18:17:39 +0200 Subject: [PATCH 0883/5359] fix synopsis for blog create: the flag is --private, not --public --- src/php/wp-cli/commands/internals/blog.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index 4c027ef2f..d46a55a82 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -33,9 +33,9 @@ private function _get_site( $site_id ) { /** * Create a blog in a multisite install. * - * @synopsis --slug=<slug> --title=<title> [--email=<email>] [--site_id=<site-id>] [--public] + * @synopsis --slug=<slug> --title=<title> [--email=<email>] [--site_id=<site-id>] [--private] */ - public function create( $args, $assoc_args ) { + public function create( $_, $assoc_args ) { global $wpdb; $base = $assoc_args['slug']; @@ -52,7 +52,7 @@ public function create( $args, $assoc_args ) { $site = wpmu_current_site(); } - $public = isset( $assoc_args['private'] ) ? 0 : 1; + $public = !isset( $assoc_args['private'] ); // Sanitize if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { From 66fd2c1a318c5331cc8de110e3bbbc4f104f67a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Dec 2012 18:55:06 +0200 Subject: [PATCH 0884/5359] make --title arg optional in blog create --- man/blog-create.1 | 4 ++-- src/docs/blog-create.txt | 2 +- src/php/wp-cli/commands/internals/blog.php | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/man/blog-create.1 b/man/blog-create.1 index 7e30d4d82..34bc50c9a 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -7,7 +7,7 @@ \fBwp\-blog\-create\fR \- Create a blog in a multisite install\. . .SH "SYNOPSIS" -\fBwp blog create\fR \-\-slug=\fIslug\fR \-\-title=\fItitle\fR [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-public] +\fBwp blog create\fR \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] . .SH "OPTIONS" . @@ -21,7 +21,7 @@ Path for the new blog\. Subdomain on subdomain installs, directory on subdirecto \fB\-\-title\fR=<title>: . .IP -Title of the new blog\. +Title of the new blog\. Default: prettified slug\. . .TP \fB\-\-email\fR=\fIemail\fR: diff --git a/src/docs/blog-create.txt b/src/docs/blog-create.txt index 3f660e3cb..02814b8f3 100644 --- a/src/docs/blog-create.txt +++ b/src/docs/blog-create.txt @@ -6,7 +6,7 @@ * `--title`=<title>: - Title of the new blog. + Title of the new blog. Default: prettified slug. * `--email`=<email>: diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/internals/blog.php index d46a55a82..b73f1bd9b 100644 --- a/src/php/wp-cli/commands/internals/blog.php +++ b/src/php/wp-cli/commands/internals/blog.php @@ -33,13 +33,14 @@ private function _get_site( $site_id ) { /** * Create a blog in a multisite install. * - * @synopsis --slug=<slug> --title=<title> [--email=<email>] [--site_id=<site-id>] [--private] + * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] */ public function create( $_, $assoc_args ) { global $wpdb; $base = $assoc_args['slug']; - $title = $assoc_args['title']; + $title = isset( $assoc_args['title'] ) ? $assoc_args['title'] : ucfirst( $base ); + $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; // Site if ( !empty( $assoc_args['site_id'] ) ) { From 8fe5d452f388c3026cf529f8127f18c6efa07dd1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Dec 2012 23:13:11 +0200 Subject: [PATCH 0885/5359] fix synopsis for core `install-network` --- man/core-install-network.1 | 4 ++-- src/docs/core-install-network.txt | 2 +- src/php/wp-cli/commands/internals/core.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/core-install-network.1 b/man/core-install-network.1 index d76fc582d..78218ff9c 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -7,7 +7,7 @@ \fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. . .SH "SYNOPSIS" -\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base_path=\fIurl\-path\fR] +\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] . .SH "OPTIONS" . @@ -18,7 +18,7 @@ The title of the new network\. . .TP -\fB\-\-base_path\fR=\fIurl\-path\fR: +\fB\-\-base\fR=\fIurl\-path\fR: . .IP Base path after the domain name that each site url will start with\. Default: \'/\' diff --git a/src/docs/core-install-network.txt b/src/docs/core-install-network.txt index 86db38741..26e2c2a95 100644 --- a/src/docs/core-install-network.txt +++ b/src/docs/core-install-network.txt @@ -4,7 +4,7 @@ The title of the new network. -* `--base_path`=<url-path>: +* `--base`=<url-path>: Base path after the domain name that each site url will start with. Default: '/' diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index a53be97c8..40af5f6aa 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -109,7 +109,7 @@ public function install( $args, $assoc_args ) { * Transform a single-site install into a multi-site install. * * @subcommand install-network - * @synopsis --title=<network-title> [--base_path=<url-path>] + * @synopsis --title=<network-title> [--base=<url-path>] */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) From 56bfa6c4616d8421593b66e9ab5f0d279b6c6dc7 Mon Sep 17 00:00:00 2001 From: Miles Johnson <mileswjohnson@gmail.com> Date: Wed, 5 Dec 2012 15:53:51 -0800 Subject: [PATCH 0886/5359] Allow for updates during user import-csv --- src/php/wp-cli/commands/internals/user.php | 42 +++++++++++++++++----- src/php/wp-cli/utils.php | 1 + 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 3a186402f..1aedfbac4 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -268,7 +268,7 @@ private static function get_user_from_first_arg( $id_or_login ) { * @subcommand import-csv * @synopsis <file> */ - public function import_csv( $args, $assoc_args ) { + public function import_csv( $args, $assoc_args, $update = false ) { list( $csv ) = $args; @@ -295,31 +295,57 @@ public function import_csv( $args, $assoc_args ) { // User already exists and we just need to add them to the site if they aren't already there if ( $existing_user = get_user_by( 'email', $new_user['user_email'] ) ) { - if ( in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) ) + $new_user['ID'] = $existing_user->ID; + + if ( in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) ) { WP_CLI::warning( "{$existing_user->user_login} already is a member of blog" ); - else if ( $new_user['role'] ) { + + } else if ( $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); WP_CLI::line( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); + } else { WP_CLI::line( "{$existing_user->user_login} exists, but won't be added to the blog" ); } - continue; - } - $user_id = wp_insert_user( $new_user ); + if (!$update) { + continue; + } + + $user_id = wp_update_user( $new_user ); + + // Create the user + } else { + $user_id = wp_insert_user( $new_user ); + } if ( is_wp_error( $user_id ) ) { WP_CLI::warning( $user_id ); continue; } else { - if ( false === $new_user['role'] ) { + if ( $new_user['role'] === false ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } } - WP_CLI::line( $new_user['user_login'] . " created" ); + if (!empty($existing_user)) { + WP_CLI::line( $new_user['user_login'] . " updated" ); + } else { + WP_CLI::line( $new_user['user_login'] . " created" ); + } } } + + /** + * Import users from a CSV file and allow it to update the records instead of just create. + * + * @subcommand import-csv-upsert + * @synopsis <file> + */ + public function import_csv_upsert( $args, $assoc_args ) { + $this->import_csv( $args, $assoc_args, true ); + } + } diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 5221c12de..f6d404557 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -106,6 +106,7 @@ function set_url_params( $url ) { $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); $_SERVER['REQUEST_URL'] = $f('path'); $_SERVER['QUERY_STRING'] = $f('query'); + $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); } function locate_wp_config() { From 48a55d801c16f0e6c53d9f9ac5852f29b2f415c1 Mon Sep 17 00:00:00 2001 From: Miles Johnson <mileswjohnson@gmail.com> Date: Wed, 5 Dec 2012 16:03:05 -0800 Subject: [PATCH 0887/5359] Find user by email and login --- src/php/wp-cli/commands/internals/user.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 1aedfbac4..72cf84148 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -294,7 +294,13 @@ public function import_csv( $args, $assoc_args, $update = false ) { } // User already exists and we just need to add them to the site if they aren't already there - if ( $existing_user = get_user_by( 'email', $new_user['user_email'] ) ) { + $existing_user = get_user_by( 'email', $new_user['user_email'] ); + + if ( !$existing_user ) { + $existing_user = get_user_by( 'login', $new_user['user_login'] ); + } + + if ( $existing_user ) { $new_user['ID'] = $existing_user->ID; if ( in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) ) { @@ -330,9 +336,9 @@ public function import_csv( $args, $assoc_args, $update = false ) { } if (!empty($existing_user)) { - WP_CLI::line( $new_user['user_login'] . " updated" ); + WP_CLI::success( $new_user['user_login'] . " updated" ); } else { - WP_CLI::line( $new_user['user_login'] . " created" ); + WP_CLI::success( $new_user['user_login'] . " created" ); } } } From 00cc51a5e8d4219d778a3cb9c93b696fe617effb Mon Sep 17 00:00:00 2001 From: Miles Johnson <mileswjohnson@gmail.com> Date: Thu, 6 Dec 2012 16:33:00 -0800 Subject: [PATCH 0888/5359] Updated import-csv --- src/php/wp-cli/commands/internals/user.php | 37 +++++----------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 72cf84148..552b80289 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -268,7 +268,7 @@ private static function get_user_from_first_arg( $id_or_login ) { * @subcommand import-csv * @synopsis <file> */ - public function import_csv( $args, $assoc_args, $update = false ) { + public function import_csv( $args, $assoc_args ) { list( $csv ) = $args; @@ -288,6 +288,7 @@ public function import_csv( $args, $assoc_args, $update = false ) { if ( 'none' == $new_user['role'] ) { $new_user['role'] = false; + } elseif ( is_null( get_role( $new_user['role'] ) ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); continue; @@ -302,24 +303,13 @@ public function import_csv( $args, $assoc_args, $update = false ) { if ( $existing_user ) { $new_user['ID'] = $existing_user->ID; + $user_id = wp_update_user( $new_user ); - if ( in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) ) { - WP_CLI::warning( "{$existing_user->user_login} already is a member of blog" ); - - } else if ( $new_user['role'] ) { + if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); WP_CLI::line( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); - - } else { - WP_CLI::line( "{$existing_user->user_login} exists, but won't be added to the blog" ); - } - - if (!$update) { - continue; } - $user_id = wp_update_user( $new_user ); - // Create the user } else { $user_id = wp_insert_user( $new_user ); @@ -328,11 +318,10 @@ public function import_csv( $args, $assoc_args, $update = false ) { if ( is_wp_error( $user_id ) ) { WP_CLI::warning( $user_id ); continue; - } else { - if ( $new_user['role'] === false ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } + + } else if ( $new_user['role'] === false ) { + delete_user_option( $user_id, 'capabilities' ); + delete_user_option( $user_id, 'user_level' ); } if (!empty($existing_user)) { @@ -343,15 +332,5 @@ public function import_csv( $args, $assoc_args, $update = false ) { } } - /** - * Import users from a CSV file and allow it to update the records instead of just create. - * - * @subcommand import-csv-upsert - * @synopsis <file> - */ - public function import_csv_upsert( $args, $assoc_args ) { - $this->import_csv( $args, $assoc_args, true ); - } - } From f96d41326f41f66a14225b710fcaa0d759637ddb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 18:22:11 +0200 Subject: [PATCH 0889/5359] wp option docs: mention --json argument only once --- man/option.1 | 16 ++++++++++++---- src/docs/option.txt | 17 ++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/man/option.1 b/man/option.1 index b333c9119..5f88a911c 100644 --- a/man/option.1 +++ b/man/option.1 @@ -24,19 +24,19 @@ wp option delete \fIkey\fR \fBget\fR: . .IP -Get an option value\. Passing \-\-json causes the output to be formatted as JSON\. +Get an option value\. . .TP \fBadd\fR: . .IP -Add a new option\. Pass \-\-json to decode JSON values before adding the option\. +Add a new option\. . .TP \fBupdate\fR: . .IP -Update an existing option\. Pass \-\-json to decode JSON values before updating the option\. +Update an existing option\. . .TP \fBdelete\fR: @@ -44,6 +44,14 @@ Update an existing option\. Pass \-\-json to decode JSON values before updating .IP Delete an option\. . +.SH "OPTIONS" +. +.TP +\fBjson\fR: +. +.IP +Encode/decode values as JSON\. +. .SH "EXAMPLES" . .nf @@ -52,7 +60,7 @@ wp option get siteurl wp option add my_option foobar -wp option update my_option barfoo +wp option update my_option \'{"foo": "bar"}\' \-\-json wp option delete my_option . diff --git a/src/docs/option.txt b/src/docs/option.txt index cbb7b79c6..f8629478c 100644 --- a/src/docs/option.txt +++ b/src/docs/option.txt @@ -15,29 +15,32 @@ wp option delete <key> * `get`: - Get an option value. Passing --json causes the output to be formatted - as JSON. + Get an option value. * `add`: - Add a new option. Pass --json to decode JSON values before adding - the option. + Add a new option. * `update`: - Update an existing option. Pass --json to decode JSON values before - updating the option. + Update an existing option. * `delete`: Delete an option. +## OPTIONS + +* `json`: + + Encode/decode values as JSON. + ## EXAMPLES wp option get siteurl wp option add my_option foobar - wp option update my_option barfoo + wp option update my_option '{"foo": "bar"}' --json wp option delete my_option From 4cf34d52fc3c4773517b6c61ced88cc7a79e6963 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:16:58 +0200 Subject: [PATCH 0890/5359] introduce DocParser class --- src/php/wp-cli/dispatcher.php | 123 +++++++++++++++++++++------------- src/php/wp-cli/man.php | 4 +- 2 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index 7bb0b3b51..c56c490a4 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -18,6 +18,37 @@ function traverse( &$args, $method = 'find_subcommand' ) { } +class DocParser { + + protected $docComment; + + function __construct( $reflection ) { + $this->docComment = $reflection->getDocComment(); + } + + function get_shortdesc() { + if ( !preg_match( '/\* (\w.+)\n*/', $this->docComment, $matches ) ) + return false; + + return $matches[1]; + } + + function get_tag( $name ) { + if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $this->docComment, $matches ) ) + return $matches[1]; + + return false; + } + + function get_synopsis() { + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $this->docComment, $matches ) ) + return false; + + return $matches[1]; + } +} + + interface Command { function get_path(); @@ -38,7 +69,7 @@ function find_subcommand( &$args ); interface Documentable { function get_shortdesc(); - function get_synopsis(); + function get_full_synopsis(); } @@ -114,7 +145,9 @@ function add_command( $name, $implementation ) { else { $method = new \ReflectionMethod( $implementation, '__invoke' ); - $command = new Subcommand( $name, $implementation, $method, $this ); + $docparser = new DocParser( $method ); + + $command = new Subcommand( $name, $implementation, $docparser, $this ); } $this->subcommands[ $name ] = $command; @@ -160,21 +193,25 @@ function load_command( $command ) { } -class CompositeCommand implements Command, Composite { +class CompositeCommand implements Command, Composite, Documentable { protected $name; protected $subcommands; + protected $shortdesc; + public function __construct( $name, $class ) { $this->name = $name; - $this->subcommands = $this->collect_subcommands( $class ); - } - - private function collect_subcommands( $class ) { $reflection = new \ReflectionClass( $class ); + $this->subcommands = $this->collect_subcommands( $reflection, $class ); + + $this->docparser = new DocParser( $reflection ); + } + + private function collect_subcommands( $reflection, $class ) { $subcommands = array(); foreach ( $reflection->getMethods() as $method ) { @@ -259,6 +296,20 @@ public function get_subcommands() { return $this->subcommands; } + public function get_shortdesc() { + return $this->docparser->get_shortdesc(); + } + + public function get_full_synopsis() { + $str = array(); + + foreach ( $this->subcommands as $subcommand ) { + $str[] = $subcommand->get_full_synopsis(); + } + + return implode( "\n\n", $str ); + } + private static function _is_good_method( $method ) { return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } @@ -267,18 +318,26 @@ private static function _is_good_method( $method ) { class Subcommand implements Command, Documentable { - function __construct( $name, $callable, $method, $parent ) { + function __construct( $name, $callable, $docparser, $parent ) { $this->name = $name; $this->callable = $callable; - $this->method = $method; + $this->docparser = $docparser; $this->parent = $parent; } function show_usage( $prefix = 'usage: ' ) { + \WP_CLI::line( $prefix . $this->get_full_synopsis() ); + } + + function get_shortdesc() { + return $this->docparser->get_shortdesc(); + } + + function get_full_synopsis() { $full_name = implode( ' ', $this->get_path() ); - $synopsis = $this->get_synopsis(); + $synopsis = $this->docparser->get_synopsis(); - \WP_CLI::line( $prefix . "wp $full_name $synopsis" ); + return "wp $full_name $synopsis"; } function invoke( $args, $assoc_args ) { @@ -300,7 +359,7 @@ function get_path() { } protected function check_args( $args, $assoc_args ) { - $synopsis = $this->get_synopsis(); + $synopsis = $this->docparser->get_synopsis(); if ( !$synopsis ) return; @@ -372,24 +431,6 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { } } - function get_shortdesc() { - $comment = $this->method->getDocComment(); - - if ( !preg_match( '/\* (\w.+)\n*/', $comment, $matches ) ) - return false; - - return $matches[1]; - } - - public function get_synopsis() { - $comment = $this->method->getDocComment(); - - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $comment, $matches ) ) - return false; - - return $matches[1]; - } - protected function parse_synopsis( $synopsis ) { list( $patterns, $params ) = self::get_patterns(); @@ -452,27 +493,17 @@ class MethodSubcommand extends Subcommand { function __construct( $class, $method, $parent ) { $callable = array( new $class, $method->name ); - parent::__construct( self::_get_name( $method ), $callable, $method, $parent ); - } - - private static function _get_name( $method ) { - if ( $name = self::get_tag( $method, 'subcommand' ) ) - return $name; - - return $method->name; - } + $docparser = new DocParser( $method ); - private static function get_tag( $method, $name ) { - $comment = $method->getDocComment(); + $name = $docparser->get_tag( 'subcommand' ); + if ( !$name ) + $name = $method->name; - if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $comment, $matches ) ) - return $matches[1]; - - return false; + parent::__construct( $name, $callable, $docparser, $parent ); } function get_alias() { - return self::get_tag( $this->method, 'alias' ); + return $this->docparser->get_tag( 'alias' ); } } diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index 515a88c6c..bee9fcc6f 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -48,7 +48,7 @@ function get_markdown( $doc_path, $command ) { function add_initial_markdown( $fd, $command ) { $path = $command->get_path(); $shortdesc = $command->get_shortdesc(); - $synopsis = $command->get_synopsis(); + $synopsis = $command->get_full_synopsis(); $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); @@ -65,7 +65,7 @@ function add_initial_markdown( $fd, $command ) { ## SYNOPSIS -`wp $name_s` $synopsis +$synopsis DOC ); From 133c2dd2a2298e97131fe654a182c3feab51c10f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:23:11 +0200 Subject: [PATCH 0891/5359] add SUBCOMMANDS section automatically --- src/php/wp-cli/man.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/php/wp-cli/man.php b/src/php/wp-cli/man.php index bee9fcc6f..6a06c169e 100644 --- a/src/php/wp-cli/man.php +++ b/src/php/wp-cli/man.php @@ -69,6 +69,28 @@ function add_initial_markdown( $fd, $command ) { DOC ); + + if ( $command instanceof Dispatcher\Composite ) { + + fwrite( $fd, <<<DOC +## SUBCOMMANDS + +DOC + ); + + foreach ( $command->get_subcommands() as $subcommand ) { + $name = $subcommand->get_name(); + $desc = $subcommand->get_shortdesc(); + + fwrite( $fd, <<<DOC +* `$name`: + + $desc + +DOC + ); + } + } } function call_ronn( $markdown, $dest ) { From 4e7087209f87d9e5505adb1b7edafd18c71a0715 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:23:40 +0200 Subject: [PATCH 0892/5359] remove redundant data from composite command man pages --- man/option.1 | 7 ++-- man/post-meta.1 | 27 ++++++++++------ src/docs/option.txt | 31 ------------------ src/docs/post-meta.txt | 32 ++----------------- src/docs/user-meta.txt | 32 ++----------------- src/php/wp-cli/commands/internals/option.php | 2 +- .../wp-cli/commands/internals/post-meta.php | 2 +- .../wp-cli/commands/internals/user-meta.php | 2 +- 8 files changed, 31 insertions(+), 104 deletions(-) diff --git a/man/option.1 b/man/option.1 index 5f88a911c..12b38c6b7 100644 --- a/man/option.1 +++ b/man/option.1 @@ -24,19 +24,19 @@ wp option delete \fIkey\fR \fBget\fR: . .IP -Get an option value\. +Get an option\. . .TP \fBadd\fR: . .IP -Add a new option\. +Add an option\. . .TP \fBupdate\fR: . .IP -Update an existing option\. +Update an option\. . .TP \fBdelete\fR: @@ -45,6 +45,7 @@ Update an existing option\. Delete an option\. . .SH "OPTIONS" + . .TP \fBjson\fR: diff --git a/man/post-meta.1 b/man/post-meta.1 index 97e825319..3b3fc962f 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -7,16 +7,16 @@ \fBwp\-post\-meta\fR \- Manage post custom fields\. . .SH "SYNOPSIS" -wp post\-meta get \fIID\fR \fIkey\fR [\-\-json] +wp post\-meta get \fIid\fR \fIkey\fR [\-\-json] . .P -wp post\-meta add \fIID\fR \fIkey\fR \fIvalue\fR +wp post\-meta delete \fIid\fR \fIkey\fR . .P -wp post\-meta update \fIID\fR \fIkey\fR \fIvalue\fR +wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR . .P -wp post\-meta delete \fIID\fR \fIkey\fR +wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR . .SH "SUBCOMMANDS" . @@ -24,25 +24,34 @@ wp post\-meta delete \fIID\fR \fIkey\fR \fBget\fR: . .IP -Get a custom field value\. Passing \-\-json causes the output to be formatted as JSON\. +Get meta field value\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a meta field\. . .TP \fBadd\fR: . .IP -Add a new custom field\. +Add a meta field\. . .TP \fBupdate\fR: . .IP -Update an existing custom field\. +Update a meta field\. +. +.SH "OPTIONS" + . .TP -\fBdelete\fR: +\fBjson\fR: . .IP -Delete a custom field\. +Encode/decode values as JSON\. . .SH "EXAMPLES" . diff --git a/src/docs/option.txt b/src/docs/option.txt index f8629478c..238e5f66b 100644 --- a/src/docs/option.txt +++ b/src/docs/option.txt @@ -1,34 +1,3 @@ -wp-option(1) -- Manage WordPress options. -==== - -## SYNOPSIS - -wp option get <key> [--json] - -wp option add <key> <value> [--json] - -wp option update <key> <value> [--json] - -wp option delete <key> - -## SUBCOMMANDS - -* `get`: - - Get an option value. - -* `add`: - - Add a new option. - -* `update`: - - Update an existing option. - -* `delete`: - - Delete an option. - ## OPTIONS * `json`: diff --git a/src/docs/post-meta.txt b/src/docs/post-meta.txt index 55a0af328..e36dcb239 100644 --- a/src/docs/post-meta.txt +++ b/src/docs/post-meta.txt @@ -1,34 +1,8 @@ -wp-post-meta(1) -- Manage post custom fields. -==== +## OPTIONS -## SYNOPSIS +* `json`: -wp post-meta get <ID> <key> [--json] - -wp post-meta add <ID> <key> <value> - -wp post-meta update <ID> <key> <value> - -wp post-meta delete <ID> <key> - -## SUBCOMMANDS - -* `get`: - - Get a custom field value. Passing --json causes the output to be formatted - as JSON. - -* `add`: - - Add a new custom field. - -* `update`: - - Update an existing custom field. - -* `delete`: - - Delete a custom field. + Encode/decode values as JSON. ## EXAMPLES diff --git a/src/docs/user-meta.txt b/src/docs/user-meta.txt index 8a7562f0f..ad8d85bdb 100644 --- a/src/docs/user-meta.txt +++ b/src/docs/user-meta.txt @@ -1,34 +1,8 @@ -wp-user-meta(1) -- Manage user custom fields. -==== +## OPTIONS -## SYNOPSIS +* `json`: -wp user-meta get <ID> <key> [--json] - -wp user-meta add <ID> <key> <value> - -wp user-meta update <ID> <key> <value> - -wp user-meta delete <ID> <key> - -## SUBCOMMANDS - -* `get`: - - Get a custom field value. Passing --json causes the output to be formatted - as JSON. - -* `add`: - - Add a new custom field. - -* `update`: - - Update an existing custom field. - -* `delete`: - - Delete a custom field. + Encode/decode values as JSON. ## EXAMPLES diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/internals/option.php index cf0147f6f..d18f4a7b4 100644 --- a/src/php/wp-cli/commands/internals/option.php +++ b/src/php/wp-cli/commands/internals/option.php @@ -3,7 +3,7 @@ WP_CLI::add_command('option', 'Option_Command'); /** - * Implement option command + * Manage WordPress options. * * @package wp-cli * @subpackage commands/internals diff --git a/src/php/wp-cli/commands/internals/post-meta.php b/src/php/wp-cli/commands/internals/post-meta.php index 6e3b710f8..466468eab 100644 --- a/src/php/wp-cli/commands/internals/post-meta.php +++ b/src/php/wp-cli/commands/internals/post-meta.php @@ -3,7 +3,7 @@ WP_CLI::add_command( 'post-meta', 'Post_Meta_Command' ); /** - * Implement post-meta command + * Manage post custom fields. * * @package wp-cli * @subpackage commands/internals diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/internals/user-meta.php index 317420652..58fa75e8c 100644 --- a/src/php/wp-cli/commands/internals/user-meta.php +++ b/src/php/wp-cli/commands/internals/user-meta.php @@ -3,7 +3,7 @@ WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); /** - * Implement user-meta command + * Manage user custom fields. * * @package wp-cli * @subpackage commands/internals From 5fe949d6d58b2001170994f7840ad1351bb2c05d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:38:45 +0200 Subject: [PATCH 0893/5359] remove redundant data from `cache` and `transient` man pages see #236 --- man/cache.1 | 23 ++++--- man/transient.1 | 5 +- src/docs/cache.txt | 61 ------------------- src/docs/transient.txt | 33 ---------- src/php/wp-cli/commands/internals/cache.php | 2 +- .../wp-cli/commands/internals/transient.php | 2 +- 6 files changed, 19 insertions(+), 107 deletions(-) diff --git a/man/cache.1 b/man/cache.1 index c0d6cde14..a0031ba3b 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -4,7 +4,7 @@ .TH "WP\-CACHE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-cache\fR \- Manage WordPress the object cache\. +\fBwp\-cache\fR \- Manage the WordPress object cache\. . .SH "SYNOPSIS" wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] @@ -39,57 +39,60 @@ wp cache type \fBadd\fR: . .IP -Add a value to cache where \fIkey\fR in \fIgroup\fR does not already exist\. +Add a value to the object cache\. . .TP \fBdecr\fR: . .IP -Decrement the value of a cached object by 1 or the value of the \fIoffset\fR parameter\. +Decrement a value in the object cache\. . .TP \fBdelete\fR: . .IP -Remove an object from cache\. +Remove a value from the object cache\. . .TP \fBflush\fR: . .IP -Flush the cache\. +Flush the object cache\. . .TP \fBget\fR: . .IP -Get a value from cache\. +Get a value from the object cache\. . .TP \fBincr\fR: . .IP -Increment the value of a cached object by 1 or the value of the \fIoffset\fR parameter\. +Increment a value in the object cache\. . .TP \fBreplace\fR: . .IP -Replace a value in cache with a new value\. +Replace an existing value in the object cache\. . .TP \fBset\fR: . .IP -Set a value in cache\. +Set a value to the object cache\. . .TP \fBtype\fR: . .IP -Report the type of object being used\. +Attempts to determine which object cache is being used\. . .SH "EXAMPLES" + +. +.P wp cache set my_key my_value my_group 300 . .P diff --git a/man/transient.1 b/man/transient.1 index 10077576e..d169ff381 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -7,7 +7,7 @@ \fBwp\-transient\fR \- Manage WordPress transients\. . .SH "SYNOPSIS" -wp transient get \fIkey\fR +wp transient get \fIkey\fR [\-\-json] . .P wp transient set \fIkey\fR \fIvalue\fR [\fIexpiration\fR] @@ -45,4 +45,7 @@ Delete a transient value\. See wether the transients API is using an object cache or the options table\. . .SH "EXAMPLES" + +. +.P wp transient set my_key my_value 300 diff --git a/src/docs/cache.txt b/src/docs/cache.txt index bd2d0f286..7b25aa6d7 100644 --- a/src/docs/cache.txt +++ b/src/docs/cache.txt @@ -1,64 +1,3 @@ -wp-cache(1) -- Manage WordPress the object cache. -==== - -## SYNOPSIS - -wp cache add <key> <value> [<group>] [<expiration>] - -wp cache decr <key> [<offset>] [<group>] - -wp cache delete <key> <group> - -wp cache flush - -wp cache get <key> [<group>] - -wp cache incr <key> [<offset>] [<group>] - -wp cache replace <key> <value> [<group>] [<expiration>] - -wp cache set <key> <value> [<group>] [<expiration>] - -wp cache type - -## SUBCOMMANDS - -* `add`: - - Add a value to cache where <key> in <group> does not already exist. - -* `decr`: - - Decrement the value of a cached object by 1 or the value of the <offset> parameter. - -* `delete`: - - Remove an object from cache. - -* `flush`: - - Flush the cache. - -* `get`: - - Get a value from cache. - -* `incr`: - - Increment the value of a cached object by 1 or the value of the <offset> parameter. - -* `replace`: - - Replace a value in cache with a new value. - -* `set`: - - Set a value in cache. - -* `type`: - - Report the type of object being used. - ## EXAMPLES wp cache set my_key my_value my_group 300 diff --git a/src/docs/transient.txt b/src/docs/transient.txt index 50dece19d..175ca9c8d 100644 --- a/src/docs/transient.txt +++ b/src/docs/transient.txt @@ -1,36 +1,3 @@ -wp-transient(1) -- Manage WordPress transients. -==== - -## SYNOPSIS - -wp transient get <key> - -wp transient set <key> <value> [<expiration>] - -wp transient delete <key> - -wp transient type - -## SUBCOMMANDS - -* `get`: - - Get a transient value. - -* `set`: - - Set a transient value. <expiration> is the time until expiration, in -seconds. - -* `delete`: - - Delete a transient value. - -* `type`: - - See wether the transients API is using an object cache or the options -table. - ## EXAMPLES wp transient set my_key my_value 300 diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/internals/cache.php index 32cf156a4..142c23419 100644 --- a/src/php/wp-cli/commands/internals/cache.php +++ b/src/php/wp-cli/commands/internals/cache.php @@ -3,7 +3,7 @@ WP_CLI::add_command( 'cache', 'Cache_Command' ); /** - * Implement cache command + * Manage the WordPress object cache. * * @package wp-cli * @subpackage commands/internals diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/internals/transient.php index 4b6d24662..f21b93542 100644 --- a/src/php/wp-cli/commands/internals/transient.php +++ b/src/php/wp-cli/commands/internals/transient.php @@ -3,7 +3,7 @@ WP_CLI::add_command( 'transient', 'Transient_Command' ); /** - * Implement transient commands. + * Manage WordPress transients. * * @package wp-cli * @subpackage commands/internals From 2cc88d3dc9160c0e9a4ea22d6be96d8940043676 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:43:38 +0200 Subject: [PATCH 0894/5359] renegerate all man pages. see #236 --- man/blog-create.1 | 2 +- man/blog-delete.1 | 2 +- man/comment-approve.1 | 2 +- man/comment-count.1 | 2 +- man/comment-create.1 | 2 +- man/comment-delete.1 | 2 +- man/comment-last.1 | 2 +- man/comment-spam.1 | 2 +- man/comment-status.1 | 2 +- man/comment-trash.1 | 2 +- man/comment-unapprove.1 | 2 +- man/comment-unspam.1 | 2 +- man/comment-untrash.1 | 2 +- man/core-config.1 | 2 +- man/core-download.1 | 2 +- man/core-install-network.1 | 2 +- man/core-install.1 | 2 +- man/core-is-installed.1 | 2 +- man/core-update.1 | 2 +- man/core-version.1 | 2 +- man/db-drop.1 | 2 +- man/db-export.1 | 2 +- man/db-import.1 | 2 +- man/db-query.1 | 2 +- man/db-reset.1 | 2 +- man/eval-file.1 | 2 +- man/eval.1 | 2 +- man/export.1 | 2 +- man/plugin-activate.1 | 2 +- man/plugin-deactivate.1 | 2 +- man/plugin-delete.1 | 2 +- man/plugin-install.1 | 2 +- man/plugin-path.1 | 2 +- man/plugin-status.1 | 2 +- man/plugin-toggle.1 | 2 +- man/plugin-uninstall.1 | 2 +- man/plugin-update-all.1 | 2 +- man/plugin-update.1 | 2 +- man/post-create.1 | 2 +- man/post-delete.1 | 2 +- man/post-generate.1 | 2 +- man/post-list.1 | 2 +- man/post-update.1 | 2 +- man/rewrite-dump.1 | 2 +- man/rewrite-flush.1 | 2 +- man/rewrite-structure.1 | 2 +- man/theme-activate.1 | 2 +- man/theme-delete.1 | 2 +- man/theme-install.1 | 2 +- man/theme-path.1 | 2 +- man/theme-status.1 | 2 +- man/theme-update-all.1 | 2 +- man/theme-update.1 | 2 +- man/user-create.1 | 2 +- man/user-delete.1 | 2 +- man/user-generate.1 | 2 +- man/user-import-csv.1 | 2 +- man/user-list.1 | 2 +- man/user-meta.1 | 27 ++++++++++++++++++--------- man/user-remove-role.1 | 2 +- man/user-set-role.1 | 2 +- man/user-update.1 | 2 +- 62 files changed, 79 insertions(+), 70 deletions(-) diff --git a/man/blog-create.1 b/man/blog-create.1 index 34bc50c9a..c0b207a8b 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -7,7 +7,7 @@ \fBwp\-blog\-create\fR \- Create a blog in a multisite install\. . .SH "SYNOPSIS" -\fBwp blog create\fR \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] +wp blog create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] . .SH "OPTIONS" . diff --git a/man/blog-delete.1 b/man/blog-delete.1 index da5747d99..80e3c20c1 100644 --- a/man/blog-delete.1 +++ b/man/blog-delete.1 @@ -7,7 +7,7 @@ \fBwp\-blog\-delete\fR \- Delete a blog in a multisite install\. . .SH "SYNOPSIS" -\fBwp blog delete\fR \-\-slug=\fIslug\fR [\-\-yes] [\-\-keep\-tables] +wp blog delete \-\-slug=\fIslug\fR [\-\-yes] [\-\-keep\-tables] . .SH "OPTIONS" . diff --git a/man/comment-approve.1 b/man/comment-approve.1 index 2f05beb71..759498b75 100644 --- a/man/comment-approve.1 +++ b/man/comment-approve.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-approve\fR \- Approve a comment\. . .SH "SYNOPSIS" -\fBwp comment approve\fR \fIid\fR +wp comment approve \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-count.1 b/man/comment-count.1 index 499179b7d..4cb5c913b 100644 --- a/man/comment-count.1 +++ b/man/comment-count.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-count\fR \- Count comments, on whole blog or on a given post\. . .SH "SYNOPSIS" -\fBwp comment count\fR [\fIpost\-id\fR] +wp comment count [\fIpost\-id\fR] . .SH "OPTIONS" . diff --git a/man/comment-create.1 b/man/comment-create.1 index 72b010be5..8ca70f0ce 100644 --- a/man/comment-create.1 +++ b/man/comment-create.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-create\fR \- Insert a comment\. . .SH "SYNOPSIS" -\fBwp comment create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] +wp comment create \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/comment-delete.1 b/man/comment-delete.1 index 7a90702d1..fe9567b79 100644 --- a/man/comment-delete.1 +++ b/man/comment-delete.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-delete\fR \- Delete a comment\. . .SH "SYNOPSIS" -\fBwp comment delete\fR \fIid\fR [\-\-force] +wp comment delete \fIid\fR [\-\-force] . .SH "OPTIONS" . diff --git a/man/comment-last.1 b/man/comment-last.1 index 9f0ceb298..47b760f83 100644 --- a/man/comment-last.1 +++ b/man/comment-last.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-last\fR \- Get last approved comment\. . .SH "SYNOPSIS" -\fBwp comment last\fR [\-\-id] [\-\-full] +wp comment last [\-\-id] [\-\-full] . .SH "OPTIONS" . diff --git a/man/comment-spam.1 b/man/comment-spam.1 index 780872b1a..1f0732178 100644 --- a/man/comment-spam.1 +++ b/man/comment-spam.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-spam\fR \- Spam a comment\. . .SH "SYNOPSIS" -\fBwp comment spam\fR \fIid\fR +wp comment spam \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-status.1 b/man/comment-status.1 index 556f6ad27..70c4ddd4e 100644 --- a/man/comment-status.1 +++ b/man/comment-status.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-status\fR \- Get status of a comment\. . .SH "SYNOPSIS" -\fBwp comment status\fR \fIid\fR +wp comment status \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-trash.1 b/man/comment-trash.1 index 282d82341..2deba83ba 100644 --- a/man/comment-trash.1 +++ b/man/comment-trash.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-trash\fR \- Trash a comment\. . .SH "SYNOPSIS" -\fBwp comment trash\fR \fIid\fR +wp comment trash \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-unapprove.1 b/man/comment-unapprove.1 index 986377f42..e6d18d043 100644 --- a/man/comment-unapprove.1 +++ b/man/comment-unapprove.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-unapprove\fR \- Unapprove a comment\. . .SH "SYNOPSIS" -\fBwp comment unapprove\fR \fIid\fR +wp comment unapprove \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-unspam.1 b/man/comment-unspam.1 index ce9c72b99..41d7dd87f 100644 --- a/man/comment-unspam.1 +++ b/man/comment-unspam.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-unspam\fR \- Unspam a comment\. . .SH "SYNOPSIS" -\fBwp comment unspam\fR \fIid\fR +wp comment unspam \fIid\fR . .SH "OPTIONS" . diff --git a/man/comment-untrash.1 b/man/comment-untrash.1 index ec9735a93..ca2caa724 100644 --- a/man/comment-untrash.1 +++ b/man/comment-untrash.1 @@ -7,7 +7,7 @@ \fBwp\-comment\-untrash\fR \- Untrash a comment\. . .SH "SYNOPSIS" -\fBwp comment untrash\fR \fIid\fR +wp comment untrash \fIid\fR . .SH "OPTIONS" . diff --git a/man/core-config.1 b/man/core-config.1 index c950991e2..0e53dd338 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -7,7 +7,7 @@ \fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. . .SH "SYNOPSIS" -\fBwp core config\fR \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] +wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] . .SH "OPTIONS" . diff --git a/man/core-download.1 b/man/core-download.1 index 02414cb40..19b3e11eb 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -7,7 +7,7 @@ \fBwp\-core\-download\fR \- Download core WordPress files\. . .SH "SYNOPSIS" -\fBwp core download\fR [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] +wp core download [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] . .SH "OPTIONS" . diff --git a/man/core-install-network.1 b/man/core-install-network.1 index 78218ff9c..f7f4f84a8 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -7,7 +7,7 @@ \fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. . .SH "SYNOPSIS" -\fBwp core install\-network\fR \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] +wp core install\-network \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] . .SH "OPTIONS" . diff --git a/man/core-install.1 b/man/core-install.1 index 7a5e0b9a9..866788629 100644 --- a/man/core-install.1 +++ b/man/core-install.1 @@ -7,7 +7,7 @@ \fBwp\-core\-install\fR \- Create the WordPress tables in the database\. . .SH "SYNOPSIS" -\fBwp core install\fR \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_email=\fIemail\fR \-\-admin_password=\fIpassword\fR +wp core install \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_email=\fIemail\fR \-\-admin_password=\fIpassword\fR . .SH "OPTIONS" . diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 index 76a37ddda..ac423ae11 100644 --- a/man/core-is-installed.1 +++ b/man/core-is-installed.1 @@ -7,7 +7,7 @@ \fBwp\-core\-is\-installed\fR \- Determine if the WordPress tables are installed\. . .SH "SYNOPSIS" -\fBwp core is\-installed\fR +wp core is\-installed . .SH "EXAMPLES" if [ ! $(wp core is\-installed) ]; then diff --git a/man/core-update.1 b/man/core-update.1 index 4d69900ae..cb5848fb2 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -7,7 +7,7 @@ \fBwp\-core\-update\fR \- Update WordPress\. . .SH "SYNOPSIS" -\fBwp core update\fR [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] +wp core update [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] . .SH "OPTIONS" . diff --git a/man/core-version.1 b/man/core-version.1 index 4e9599f47..c3a37f1c1 100644 --- a/man/core-version.1 +++ b/man/core-version.1 @@ -7,7 +7,7 @@ \fBwp\-core\-version\fR \- Display the WordPress version\. . .SH "SYNOPSIS" -\fBwp core version\fR [\-\-extra] +wp core version [\-\-extra] . .SH "OPTIONS" . diff --git a/man/db-drop.1 b/man/db-drop.1 index 3a0a06b65..2f28197ff 100644 --- a/man/db-drop.1 +++ b/man/db-drop.1 @@ -7,7 +7,7 @@ \fBwp\-db\-drop\fR \- Delete the database\. . .SH "SYNOPSIS" -\fBwp db drop\fR [\-\-yes] +wp db drop [\-\-yes] . .SH "OPTIONS" . diff --git a/man/db-export.1 b/man/db-export.1 index 5dd630142..2f0a811fc 100644 --- a/man/db-export.1 +++ b/man/db-export.1 @@ -7,7 +7,7 @@ \fBwp\-db\-export\fR \- Exports the database using mysqldump\. . .SH "SYNOPSIS" -\fBwp db export\fR [\fIfile\fR] +wp db export [\fIfile\fR] . .SH "OPTIONS" . diff --git a/man/db-import.1 b/man/db-import.1 index c98ce4f70..eaa90697e 100644 --- a/man/db-import.1 +++ b/man/db-import.1 @@ -7,7 +7,7 @@ \fBwp\-db\-import\fR \- Import database from a file\. . .SH "SYNOPSIS" -\fBwp db import\fR [\fIfile\fR] +wp db import [\fIfile\fR] . .SH "OPTIONS" . diff --git a/man/db-query.1 b/man/db-query.1 index db0962429..0e0abdaf9 100644 --- a/man/db-query.1 +++ b/man/db-query.1 @@ -7,7 +7,7 @@ \fBwp\-db\-query\fR \- Execute a query against the database\. . .SH "SYNOPSIS" -\fBwp db query\fR \fIsql\fR +wp db query \fIsql\fR . .SH "OPTIONS" . diff --git a/man/db-reset.1 b/man/db-reset.1 index f8ca22aa8..b27e41cfc 100644 --- a/man/db-reset.1 +++ b/man/db-reset.1 @@ -7,7 +7,7 @@ \fBwp\-db\-reset\fR \- Remove all tables from the database\. . .SH "SYNOPSIS" -\fBwp db reset\fR [\-\-yes] +wp db reset [\-\-yes] . .SH "OPTIONS" . diff --git a/man/eval-file.1 b/man/eval-file.1 index bfcb67454..b6aecb6c4 100644 --- a/man/eval-file.1 +++ b/man/eval-file.1 @@ -7,7 +7,7 @@ \fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. . .SH "SYNOPSIS" -\fBwp eval\-file\fR \fIpath\fR +wp eval\-file \fIpath\fR . .SH "EXAMPLES" . diff --git a/man/eval.1 b/man/eval.1 index 558bf38e7..190f61c1d 100644 --- a/man/eval.1 +++ b/man/eval.1 @@ -7,7 +7,7 @@ \fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. . .SH "SYNOPSIS" -\fBwp eval\fR \fIphp\-code\fR +wp eval \fIphp\-code\fR . .SH "EXAMPLES" . diff --git a/man/export.1 b/man/export.1 index c23fee7ab..1e5e9b4fa 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,7 +7,7 @@ \fBwp\-export\fR \- Export posts to a WXR file\. . .SH "SYNOPSIS" -\fBwp export\fR [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post\fI\fIin=\fRpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] +wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post\fI\fIin=\fRpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] . .SH "OPTIONS" . diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 index 489019db5..a5355ada7 100644 --- a/man/plugin-activate.1 +++ b/man/plugin-activate.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-activate\fR \- Activate a plugin\. . .SH "SYNOPSIS" -\fBwp plugin activate\fR \fIplugin\fR [\-\-network] +wp plugin activate \fIplugin\fR [\-\-network] . .SH "OPTIONS" . diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 index 6b435292c..332b91a11 100644 --- a/man/plugin-deactivate.1 +++ b/man/plugin-deactivate.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-deactivate\fR \- Deactivate a plugin\. . .SH "SYNOPSIS" -\fBwp plugin deactivate\fR \fIplugin\fR [\-\-network] +wp plugin deactivate \fIplugin\fR [\-\-network] . .SH "OPTIONS" . diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 index 3c77f7e85..41b1927e0 100644 --- a/man/plugin-delete.1 +++ b/man/plugin-delete.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-delete\fR \- Delete plugin files\. . .SH "SYNOPSIS" -\fBwp plugin delete\fR \fIplugin\fR +wp plugin delete \fIplugin\fR . .SH "OPTIONS" . diff --git a/man/plugin-install.1 b/man/plugin-install.1 index af58aea05..557ec7db7 100644 --- a/man/plugin-install.1 +++ b/man/plugin-install.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-install\fR \- Install a plugin\. . .SH "SYNOPSIS" -\fBwp plugin install\fR \fIplugin|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] +wp plugin install \fIplugin|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] . .SH "OPTIONS" . diff --git a/man/plugin-path.1 b/man/plugin-path.1 index cadd730d9..7b4b33bb0 100644 --- a/man/plugin-path.1 +++ b/man/plugin-path.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. . .SH "SYNOPSIS" -\fBwp plugin path\fR [\fIplugin\fR] [\-\-dir] +wp plugin path [\fIplugin\fR] [\-\-dir] . .SH "OPTIONS" . diff --git a/man/plugin-status.1 b/man/plugin-status.1 index cb7f9b00d..797ffa320 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. . .SH "SYNOPSIS" -\fBwp plugin status\fR [\fIplugin\fR] +wp plugin status [\fIplugin\fR] . .SH "OPTIONS" . diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 index 532fb87bd..3c8e567c1 100644 --- a/man/plugin-toggle.1 +++ b/man/plugin-toggle.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-toggle\fR \- Toggle a plugin\'s activation state\. . .SH "SYNOPSIS" -\fBwp plugin toggle\fR \fIplugin\fR [\-\-network] +wp plugin toggle \fIplugin\fR [\-\-network] . .SH "OPTIONS" . diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 index b837b52ef..fa2fff495 100644 --- a/man/plugin-uninstall.1 +++ b/man/plugin-uninstall.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-uninstall\fR \- Uninstall a plugin\. . .SH "SYNOPSIS" -\fBwp plugin uninstall\fR \fIplugin\fR [\-\-no\-delete] +wp plugin uninstall \fIplugin\fR [\-\-no\-delete] . .SH "OPTIONS" . diff --git a/man/plugin-update-all.1 b/man/plugin-update-all.1 index 5198fd1e8..ae85d459a 100644 --- a/man/plugin-update-all.1 +++ b/man/plugin-update-all.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-update\-all\fR \- Update all plugins\. . .SH "SYNOPSIS" -\fBwp plugin update\-all\fR [\-\-dry\-run] +wp plugin update\-all [\-\-dry\-run] . .SH "OPTIONS" . diff --git a/man/plugin-update.1 b/man/plugin-update.1 index 5f38ffda6..cd26ed8e9 100644 --- a/man/plugin-update.1 +++ b/man/plugin-update.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-update\fR \- Update a plugin\. . .SH "SYNOPSIS" -\fBwp plugin update\fR \fIplugin\fR [\-\-version=\fIversion\fR] +wp plugin update \fIplugin\fR [\-\-version=\fIversion\fR] . .SH "OPTIONS" . diff --git a/man/post-create.1 b/man/post-create.1 index 76536d6e3..7aa1f5025 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -7,7 +7,7 @@ \fBwp\-post\-create\fR \- Create a post\. . .SH "SYNOPSIS" -\fBwp post create\fR \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] +wp post create \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/post-delete.1 b/man/post-delete.1 index 45a8fa30a..e301e7733 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -7,7 +7,7 @@ \fBwp\-post\-delete\fR \- Delete a post by ID\. . .SH "SYNOPSIS" -\fBwp post delete\fR \fIid\fR\.\.\. [\-\-force] +wp post delete \fIid\fR\.\.\. [\-\-force] . .SH "OPTIONS" . diff --git a/man/post-generate.1 b/man/post-generate.1 index a5a78c5e7..9aca68462 100644 --- a/man/post-generate.1 +++ b/man/post-generate.1 @@ -7,7 +7,7 @@ \fBwp\-post\-generate\fR \- Generate some posts\. . .SH "SYNOPSIS" -\fBwp post generate\fR [\-\-count=100] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=1] +wp post generate [\-\-count=100] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=1] . .SH "OPTIONS" . diff --git a/man/post-list.1 b/man/post-list.1 index c965fc51f..299c62aaa 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -\fBwp post list\fR [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] +wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] . .SH "OPTIONS" . diff --git a/man/post-update.1 b/man/post-update.1 index fc8249fae..4fd90c475 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -7,7 +7,7 @@ \fBwp\-post\-update\fR \- Update a post\. . .SH "SYNOPSIS" -\fBwp post update\fR \fIid\fR \-\-\fIfield\fR=\fIvalue\fR +wp post update \fIid\fR \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 index 80d34e073..932d8691a 100644 --- a/man/rewrite-dump.1 +++ b/man/rewrite-dump.1 @@ -7,7 +7,7 @@ \fBwp\-rewrite\-dump\fR \- Print current rewrite rules\. . .SH "SYNOPSIS" -\fBwp rewrite dump\fR [\-\-json] +wp rewrite dump [\-\-json] . .SH "OPTIONS" . diff --git a/man/rewrite-flush.1 b/man/rewrite-flush.1 index db0163863..622e11e12 100644 --- a/man/rewrite-flush.1 +++ b/man/rewrite-flush.1 @@ -7,7 +7,7 @@ \fBwp\-rewrite\-flush\fR \- Flush rewrite rules\. . .SH "SYNOPSIS" -\fBwp rewrite flush\fR [\-\-soft] +wp rewrite flush [\-\-soft] . .SH "OPTIONS" . diff --git a/man/rewrite-structure.1 b/man/rewrite-structure.1 index 9775f55c3..50272811d 100644 --- a/man/rewrite-structure.1 +++ b/man/rewrite-structure.1 @@ -7,7 +7,7 @@ \fBwp\-rewrite\-structure\fR \- Update the permalink structure\. . .SH "SYNOPSIS" -\fBwp rewrite structure\fR \fIpermastruct\fR [\-\-category\-base=\fIbase\fR] [\-\-tag\-base=\fIbase\fR] +wp rewrite structure \fIpermastruct\fR [\-\-category\-base=\fIbase\fR] [\-\-tag\-base=\fIbase\fR] . .SH "OPTIONS" . diff --git a/man/theme-activate.1 b/man/theme-activate.1 index b408317f0..52f33f8b4 100644 --- a/man/theme-activate.1 +++ b/man/theme-activate.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-activate\fR \- Activate a theme\. . .SH "SYNOPSIS" -\fBwp theme activate\fR \fItheme\fR +wp theme activate \fItheme\fR . .SH "OPTIONS" . diff --git a/man/theme-delete.1 b/man/theme-delete.1 index 6d82f601a..006662475 100644 --- a/man/theme-delete.1 +++ b/man/theme-delete.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-delete\fR \- Delete a theme\. . .SH "SYNOPSIS" -\fBwp theme delete\fR \fItheme\fR +wp theme delete \fItheme\fR . .SH "OPTIONS" . diff --git a/man/theme-install.1 b/man/theme-install.1 index 2665ed671..df8a8ef70 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-install\fR \- Install a theme\. . .SH "SYNOPSIS" -\fBwp theme install\fR \fItheme|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] +wp theme install \fItheme|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] . .SH "OPTIONS" . diff --git a/man/theme-path.1 b/man/theme-path.1 index 2243de192..b657808c8 100644 --- a/man/theme-path.1 +++ b/man/theme-path.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. . .SH "SYNOPSIS" -\fBwp theme path\fR [\fItheme\fR] [\-\-dir] +wp theme path [\fItheme\fR] [\-\-dir] . .SH "OPTIONS" . diff --git a/man/theme-status.1 b/man/theme-status.1 index 576c274ae..89fb262e6 100644 --- a/man/theme-status.1 +++ b/man/theme-status.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-status\fR \- See the status of one or all themes\. . .SH "SYNOPSIS" -\fBwp theme status\fR [\fItheme\fR] +wp theme status [\fItheme\fR] . .SH "OPTIONS" . diff --git a/man/theme-update-all.1 b/man/theme-update-all.1 index 057f3f4c9..82f580ff9 100644 --- a/man/theme-update-all.1 +++ b/man/theme-update-all.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-update\-all\fR \- Update all themes\. . .SH "SYNOPSIS" -\fBwp theme update\-all\fR [\-\-dry\-run] +wp theme update\-all [\-\-dry\-run] . .SH "OPTIONS" . diff --git a/man/theme-update.1 b/man/theme-update.1 index cb5f09b3b..86fd820bd 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -7,7 +7,7 @@ \fBwp\-theme\-update\fR \- Update a theme\. . .SH "SYNOPSIS" -\fBwp theme update\fR \fItheme\fR [\-\-version=\fIversion\fR] +wp theme update \fItheme\fR [\-\-version=\fIversion\fR] . .SH "OPTIONS" . diff --git a/man/user-create.1 b/man/user-create.1 index dabdae714..6eadf9ec9 100644 --- a/man/user-create.1 +++ b/man/user-create.1 @@ -7,7 +7,7 @@ \fBwp\-user\-create\fR \- Create a user\. . .SH "SYNOPSIS" -\fBwp user create\fR \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-user_pass=\fIpassword\fR] [\-\-user_registered=\fIyyyy\-mm\-dd\fR] [\-\-display_name=\fIname\fR] [\-\-porcelain] +wp user create \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-user_pass=\fIpassword\fR] [\-\-user_registered=\fIyyyy\-mm\-dd\fR] [\-\-display_name=\fIname\fR] [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/user-delete.1 b/man/user-delete.1 index b9b44d191..0666e0147 100644 --- a/man/user-delete.1 +++ b/man/user-delete.1 @@ -7,7 +7,7 @@ \fBwp\-user\-delete\fR \- Delete a user\. . .SH "SYNOPSIS" -\fBwp user delete\fR \fIid\fR [\-\-reassign=\fIid\fR] +wp user delete \fIid\fR [\-\-reassign=\fIid\fR] . .SH "OPTIONS" . diff --git a/man/user-generate.1 b/man/user-generate.1 index 6e6bd5447..2acca7912 100644 --- a/man/user-generate.1 +++ b/man/user-generate.1 @@ -7,7 +7,7 @@ \fBwp\-user\-generate\fR \- Generate users\. . .SH "SYNOPSIS" -\fBwp user generate\fR [\-\-count=100] [\-\-role=\fIrole\fR] +wp user generate [\-\-count=100] [\-\-role=\fIrole\fR] . .SH "OPTIONS" . diff --git a/man/user-import-csv.1 b/man/user-import-csv.1 index 7f8e09d26..0c3d07c7a 100644 --- a/man/user-import-csv.1 +++ b/man/user-import-csv.1 @@ -7,7 +7,7 @@ \fBwp\-user\-import\-csv\fR \- Import users from a CSV file\. . .SH "SYNOPSIS" -\fBwp user import\-csv\fR \fIfile\fR +wp user import\-csv \fIfile\fR . .SH "OPTIONS" . diff --git a/man/user-list.1 b/man/user-list.1 index 265b30893..2576b9acd 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -\fBwp user list\fR [\-\-role=\fIrole\fR] [\-\-ids] +wp user list [\-\-role=\fIrole\fR] [\-\-ids] . .SH "OPTIONS" . diff --git a/man/user-meta.1 b/man/user-meta.1 index 4a2ab314e..b304a99f9 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -7,16 +7,16 @@ \fBwp\-user\-meta\fR \- Manage user custom fields\. . .SH "SYNOPSIS" -wp user\-meta get \fIID\fR \fIkey\fR [\-\-json] +wp user\-meta get \fIid\fR \fIkey\fR [\-\-json] . .P -wp user\-meta add \fIID\fR \fIkey\fR \fIvalue\fR +wp user\-meta delete \fIid\fR \fIkey\fR . .P -wp user\-meta update \fIID\fR \fIkey\fR \fIvalue\fR +wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR . .P -wp user\-meta delete \fIID\fR \fIkey\fR +wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR . .SH "SUBCOMMANDS" . @@ -24,25 +24,34 @@ wp user\-meta delete \fIID\fR \fIkey\fR \fBget\fR: . .IP -Get a custom field value\. Passing \-\-json causes the output to be formatted as JSON\. +Get meta field value\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a meta field\. . .TP \fBadd\fR: . .IP -Add a new custom field\. +Add a meta field\. . .TP \fBupdate\fR: . .IP -Update an existing custom field\. +Update a meta field\. +. +.SH "OPTIONS" + . .TP -\fBdelete\fR: +\fBjson\fR: . .IP -Delete a custom field\. +Encode/decode values as JSON\. . .SH "EXAMPLES" . diff --git a/man/user-remove-role.1 b/man/user-remove-role.1 index ffa374538..232a68c91 100644 --- a/man/user-remove-role.1 +++ b/man/user-remove-role.1 @@ -7,7 +7,7 @@ \fBwp\-user\-remove\-role\fR \- Remove a user from a blog\. . .SH "SYNOPSIS" -\fBwp user remove\-role\fR \fIuser\-login\fR +wp user remove\-role \fIuser\-login\fR . .SH "OPTIONS" . diff --git a/man/user-set-role.1 b/man/user-set-role.1 index c4b99a980..bb8ca4670 100644 --- a/man/user-set-role.1 +++ b/man/user-set-role.1 @@ -7,7 +7,7 @@ \fBwp\-user\-set\-role\fR \- Add a user to a blog\. . .SH "SYNOPSIS" -\fBwp user set\-role\fR \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] +wp user set\-role \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] . .SH "OPTIONS" . diff --git a/man/user-update.1 b/man/user-update.1 index 1e0a7ebc0..4750f707e 100644 --- a/man/user-update.1 +++ b/man/user-update.1 @@ -7,7 +7,7 @@ \fBwp\-user\-update\fR \- Update a user\. . .SH "SYNOPSIS" -\fBwp user update\fR \fIid\fR \-\-\fIfield\fR=\fIvalue\fR +wp user update \fIid\fR \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . From 2ae2356ed0797cc2f3f5545faa65bd952db74f49 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 17:51:42 +0200 Subject: [PATCH 0895/5359] add --str flag to most `db` subcommands --- src/php/wp-cli/commands/internals/db.php | 80 +++++++++++++----------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index f61649480..778eb8590 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -12,9 +12,11 @@ class DB_Command extends WP_CLI_Command { /** * Create the database, as specified in wp-config.php + * + * @synopsis [--str] */ - function create() { - WP_CLI::launch( self::create_cmd( + function create( $_, $assoc_args ) { + self::run( $assoc_args, self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME ) ); @@ -25,12 +27,12 @@ function create() { /** * Delete the database. * - * @synopsis [--yes] + * @synopsis [--yes] [--str] */ - function drop( $args, $assoc_args ) { + function drop( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); - WP_CLI::launch( self::create_cmd( + self::run( $assoc_args, self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE ' . DB_NAME ) ); @@ -43,7 +45,7 @@ function drop( $args, $assoc_args ) { * * @synopsis [--yes] */ - function reset( $args, $assoc_args ) { + function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); WP_CLI::launch( self::create_cmd( @@ -61,9 +63,11 @@ function reset( $args, $assoc_args ) { /** * Optimize the database. + * + * @synopsis [--str] */ - function optimize() { - WP_CLI::launch( self::create_cmd( + function optimize( $_, $assoc_args ) { + self::run( $assoc_args, self::create_cmd( 'mysqlcheck --optimize --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -73,9 +77,11 @@ function optimize() { /** * Repair the database. + * + * @synopsis [--str] */ - function repair() { - WP_CLI::launch( self::create_cmd( + function repair( $_, $assoc_args ) { + self::run( $assoc_args, self::create_cmd( 'mysqlcheck --repair --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -83,49 +89,41 @@ function repair() { WP_CLI::success( "Database repaired." ); } - /** - * Print a string for connecting to the DB. - * - * @subcommand connect-str - * @subcommand connect - */ - function connect() { - WP_CLI::line( $this->connect_string() ); - } - /** * Open a mysql console using the WordPress credentials. + * + * @alias cli + * + * @synopsis [--str] */ - function cli() { - WP_CLI::launch( $this->connect_string() ); + function connect( $_, $assoc_args ) { + self::run( $assoc_args, $this->connect_string() ); } /** * Execute a query against the database. * - * @synopsis <sql> + * @synopsis <sql> [--str] */ function query( $args, $assoc_args ) { - $query = $args[0]; - - $command = $this->connect_string() . self::create_cmd( ' --execute=%s', $query ); + list( $query ) = $args; - WP_CLI::launch( $command ); + self::run( $assoc_args, $this->connect_string() . self::create_cmd( + ' --execute=%s', $query ) ); } /** * Exports the database using mysqldump. * * @alias dump - * @synopsis [<file>] + * @synopsis [<file>] [--str] */ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $command = self::create_cmd( 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', - DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - - WP_CLI::launch( $command ); + self::run( $assoc_args, self::create_cmd( + 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', + DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } @@ -133,16 +131,14 @@ function export( $args, $assoc_args ) { /** * Import database from a file. * - * @synopsis [<file>] + * @synopsis [<file>] [--str] */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $command = self::create_cmd( + self::run( $assoc_args, self::create_cmd( 'mysql %s --user=%s --password=%s --host=%s < %s', - DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ); - - WP_CLI::launch( $command ); + DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } @@ -170,4 +166,14 @@ private static function create_cmd( $cmd ) { return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); } + + private static function run( $assoc_args, $cmd ) { + if ( isset( $assoc_args['str'] ) ) { + WP_CLI::line( $cmd ); + exit; + } + + WP_CLI::launch( $cmd ); + } } + From 9b147f085407ed13ad094f1450c2e4bde1aa1bcd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 17:59:53 +0200 Subject: [PATCH 0896/5359] db drop: skip confirmation if --str is set --- src/php/wp-cli/commands/internals/db.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 778eb8590..28349178a 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -30,14 +30,18 @@ function create( $_, $assoc_args ) { * @synopsis [--yes] [--str] */ function drop( $_, $assoc_args ) { - WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); - - self::run( $assoc_args, self::create_cmd( + $command = self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE ' . DB_NAME - ) ); - - WP_CLI::success( "Database dropped." ); + ); + + if ( !isset( $assoc_args['str'] ) ) { + WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); + WP_CLI::launch( $command ); + WP_CLI::success( "Database dropped." ); + } else { + WP_CLI::line( $command ); + } } /** From 2a49bbe056f17ca9a7829205e0678f24617a5944 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 18:02:04 +0200 Subject: [PATCH 0897/5359] db reset: add --str flag --- src/php/wp-cli/commands/internals/db.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/internals/db.php index 28349178a..e9bccf921 100644 --- a/src/php/wp-cli/commands/internals/db.php +++ b/src/php/wp-cli/commands/internals/db.php @@ -47,22 +47,28 @@ function drop( $_, $assoc_args ) { /** * Remove all tables from the database. * - * @synopsis [--yes] + * @synopsis [--yes] [--str] */ function reset( $_, $assoc_args ) { - WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); - - WP_CLI::launch( self::create_cmd( + $drop_cmd = self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE IF EXISTS ' . DB_NAME - ) ); + ); - WP_CLI::launch( self::create_cmd( + $create_cmd = self::create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME - ) ); + ); - WP_CLI::success( "Database reset." ); + if ( !isset( $assoc_args['str'] ) ) { + WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); + WP_CLI::launch( $drop_cmd ); + WP_CLI::launch( $create_cmd ); + WP_CLI::success( "Database reset." ); + } else { + WP_CLI::line( $drop_cmd ); + WP_CLI::line( $create_cmd ); + } } /** From 84c92bf3970c2211b870515a2f776a2f0a5d1db2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:36:44 +0200 Subject: [PATCH 0898/5359] unify db man pages --- man/db.1 | 112 +++++++++++++++++++++++++++++ src/docs/db-drop.txt | 5 -- src/docs/db-import.txt | 5 -- src/docs/db-query.txt | 5 -- src/docs/db-reset.txt | 5 -- src/docs/{db-export.txt => db.txt} | 8 +++ 6 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 man/db.1 delete mode 100644 src/docs/db-drop.txt delete mode 100644 src/docs/db-import.txt delete mode 100644 src/docs/db-query.txt delete mode 100644 src/docs/db-reset.txt rename src/docs/{db-export.txt => db.txt} (53%) diff --git a/man/db.1 b/man/db.1 new file mode 100644 index 000000000..19b758990 --- /dev/null +++ b/man/db.1 @@ -0,0 +1,112 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-DB" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-db\fR \- Implement db command +. +.SH "SYNOPSIS" +wp db create [\-\-str] +. +.P +wp db drop [\-\-yes] [\-\-str] +. +.P +wp db reset [\-\-yes] [\-\-str] +. +.P +wp db optimize [\-\-str] +. +.P +wp db repair [\-\-str] +. +.P +wp db connect [\-\-str] +. +.P +wp db query \fIsql\fR [\-\-str] +. +.P +wp db export [\fIfile\fR] [\-\-str] +. +.P +wp db import [\fIfile\fR] [\-\-str] +. +.SH "SUBCOMMANDS" +. +.TP +\fBcreate\fR: +. +.IP +Create the database, as specified in wp\-config\.php +. +.TP +\fBdrop\fR: +. +.IP +Delete the database\. +. +.TP +\fBreset\fR: +. +.IP +Remove all tables from the database\. +. +.TP +\fBoptimize\fR: +. +.IP +Optimize the database\. +. +.TP +\fBrepair\fR: +. +.IP +Repair the database\. +. +.TP +\fBconnect\fR: +. +.IP +Open a mysql console using the WordPress credentials\. +. +.TP +\fBquery\fR: +. +.IP +Execute a query against the database\. +. +.TP +\fBexport\fR: +. +.IP +Exports the database using mysqldump\. +. +.TP +\fBimport\fR: +. +.IP +Import database from a file\. +. +.SH "OPTIONS" + +. +.TP +\fB\-\-yes\fR: +. +.IP +Answer yes to the confirmation message\. +. +.TP +\fB<file>\fR: +. +.IP +The name of the export file\. If omitted, it will be \'{dbname}\.sql\' +. +.TP +\fB<SQL>\fR: +. +.IP +A SQL query\. + diff --git a/src/docs/db-drop.txt b/src/docs/db-drop.txt deleted file mode 100644 index f626d62dd..000000000 --- a/src/docs/db-drop.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `--yes`: - - Answer yes to the confirmation message. diff --git a/src/docs/db-import.txt b/src/docs/db-import.txt deleted file mode 100644 index 5770c0b1c..000000000 --- a/src/docs/db-import.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `<file>`: - - The name of the import file. If omitted, it will be '{dbname}.sql' diff --git a/src/docs/db-query.txt b/src/docs/db-query.txt deleted file mode 100644 index 7d44ae675..000000000 --- a/src/docs/db-query.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `<SQL>`: - - A SQL query. diff --git a/src/docs/db-reset.txt b/src/docs/db-reset.txt deleted file mode 100644 index f626d62dd..000000000 --- a/src/docs/db-reset.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `--yes`: - - Answer yes to the confirmation message. diff --git a/src/docs/db-export.txt b/src/docs/db.txt similarity index 53% rename from src/docs/db-export.txt rename to src/docs/db.txt index cce48dc75..e60509350 100644 --- a/src/docs/db-export.txt +++ b/src/docs/db.txt @@ -1,5 +1,13 @@ ## OPTIONS +* `--yes`: + + Answer yes to the confirmation message. + * `<file>`: The name of the export file. If omitted, it will be '{dbname}.sql' + +* `<SQL>`: + + A SQL query. From 0e209078a2d04b3f0076d0fd3129fa68c6d33937 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Dec 2012 19:47:53 +0200 Subject: [PATCH 0899/5359] db docs: document --str option --- man/db.1 | 6 ++++++ src/docs/db.txt | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/man/db.1 b/man/db.1 index 19b758990..7c16d0827 100644 --- a/man/db.1 +++ b/man/db.1 @@ -91,6 +91,12 @@ Import database from a file\. . .SH "OPTIONS" +. +.TP +\fB\-\-str\fR: +. +.IP +Show the mysql command, instead of executing it\. . .TP \fB\-\-yes\fR: diff --git a/src/docs/db.txt b/src/docs/db.txt index e60509350..f160ad01a 100644 --- a/src/docs/db.txt +++ b/src/docs/db.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `--str`: + + Show the mysql command, instead of executing it. + * `--yes`: Answer yes to the confirmation message. From dec733ce8044b03b97640957c1fe23ee90ec04a0 Mon Sep 17 00:00:00 2001 From: Miles Johnson <mileswjohnson@gmail.com> Date: Fri, 7 Dec 2012 16:33:35 -0800 Subject: [PATCH 0900/5359] Add more server vars --- src/php/wp-cli/utils.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index f6d404557..4e6432f82 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -107,6 +107,9 @@ function set_url_params( $url ) { $_SERVER['REQUEST_URL'] = $f('path'); $_SERVER['QUERY_STRING'] = $f('query'); $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; + $_SERVER['HTTP_USER_AGENT'] = ''; + $_SERVER['REQUEST_METHOD'] = 'GET'; } function locate_wp_config() { From b75fcbadb092573284108fb7810e688ab9cda92e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Dec 2012 21:18:14 +0200 Subject: [PATCH 0901/5359] theme upgrader expects the theme name, while the plugin upgrader expects the basename. see #237 --- src/php/wp-cli/class-wp-cli-command-with-upgrade.php | 6 ++---- src/php/wp-cli/commands/internals/plugin.php | 4 +++- src/php/wp-cli/commands/internals/theme.php | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php index 13c7d1105..b84bcb7e1 100644 --- a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php +++ b/src/php/wp-cli/class-wp-cli-command-with-upgrade.php @@ -119,12 +119,10 @@ function install( $args, $assoc_args ) { } } - function update( $args, $assoc_args ) { + protected function _update( $item ) { call_user_func( $this->upgrade_refresh ); - list( $file, $name ) = $this->parse_name( $args ); - - WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $file ); + WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $item ); } function update_all( $args, $assoc_args ) { diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index d6f6d9840..4a474d5df 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -191,7 +191,9 @@ function update( $args, $assoc_args ) { $this->delete( $args, array(), false ); $this->install( $args, $assoc_args ); } else { - parent::update( $args, $assoc_args ); + list( $basename ) = $this->parse_name( $args ); + + parent::_update( $basename ); } } diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/internals/theme.php index d028937f8..5f64beb66 100644 --- a/src/php/wp-cli/commands/internals/theme.php +++ b/src/php/wp-cli/commands/internals/theme.php @@ -171,7 +171,9 @@ function install( $args, $assoc_args ) { * @synopsis <theme> [--version=<version>] */ function update( $args, $assoc_args ) { - parent::update( $args, $assoc_args ); + list( $_, $name ) = $this->parse_name( $args ); + + parent::_update( $name ); } /** From c6d5ef84c0b00aac9c522e1cc3444054699a4450 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Dec 2012 21:24:10 +0200 Subject: [PATCH 0902/5359] don't try to use WP_Error object as array key --- src/php/wp-cli/class-cli-upgrader-skin.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/src/php/wp-cli/class-cli-upgrader-skin.php index 580ab02d1..0b9871a90 100644 --- a/src/php/wp-cli/class-cli-upgrader-skin.php +++ b/src/php/wp-cli/class-cli-upgrader-skin.php @@ -16,13 +16,11 @@ function error( $error ) { if ( !$error ) return; - if ( isset( $this->upgrader->strings[$error] ) ) - $string = $this->upgrader->strings[$error]; - else - $string = $error; + if ( is_string( $error ) && isset( $this->upgrader->strings[ $error ] ) ) + $error = $this->upgrader->strings[ $error ]; // TODO: show all errors, not just the first one - WP_CLI::warning( $string ); + WP_CLI::warning( $error ); } function feedback( $string ) { From 54ad66e046f6755f55692072ab64aa8cff34ee39 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Dec 2012 21:35:44 +0200 Subject: [PATCH 0903/5359] silently convert {plugin|theme} update --all to {plugin|theme} update-all. closes #237 --- src/php/wp-cli/class-wp-cli.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index e92960893..94b8024fd 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -198,11 +198,21 @@ private static function parse_args() { list( self::$arguments, self::$assoc_args ) = $r; + // foo --help -> help foo if ( isset( self::$assoc_args['help'] ) ) { array_unshift( self::$arguments, 'help' ); unset( self::$assoc_args['help'] ); } + // {plugin|theme} update --all -> {plugin|theme} update-all + if ( in_array( self::$arguments[0], array( 'plugin', 'theme' ) ) + && self::$arguments[1] == 'update' + && isset( self::$assoc_args['all'] ) + ) { + self::$arguments[1] = 'update-all'; + unset( self::$assoc_args['all'] ); + } + self::$assoc_special = Utils\split_assoc( self::$assoc_args, array( 'path', 'url', 'blog', 'user', 'require', 'quiet', 'completions', 'man', 'syn-list' From 2a24cdf23c845b595c224c7c30f469291df579da Mon Sep 17 00:00:00 2001 From: Eric Mann <eric@eamann.com> Date: Tue, 11 Dec 2012 16:02:16 -0800 Subject: [PATCH 0904/5359] Fix Undefined Offset Message. If no arguments are passed aside from a -- flag (i.e. `wp --version`), the new plugin/theme logic triggers an undefined offset notice. This patch checks first that the arguments array has elements before trying to read them. see #237. closes #238 --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 94b8024fd..560c46f63 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -205,7 +205,7 @@ private static function parse_args() { } // {plugin|theme} update --all -> {plugin|theme} update-all - if ( in_array( self::$arguments[0], array( 'plugin', 'theme' ) ) + if ( count( self::$arguments ) > 1 && in_array( self::$arguments[0], array( 'plugin', 'theme' ) ) && self::$arguments[1] == 'update' && isset( self::$assoc_args['all'] ) ) { From 0c3b62f4dc5fe2f5b4bfcc0360c11f652a142e1c Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 10:30:31 +0000 Subject: [PATCH 0905/5359] Add dev dependency on phpunit --- .gitignore | 2 ++ composer.json | 5 +++++ 2 files changed, 7 insertions(+) create mode 100644 composer.json diff --git a/.gitignore b/.gitignore index d9cdde38e..851cd1140 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /.build /dist +/vendor +/composer.lock diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..90f5a3d05 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require-dev": { + "phpunit/phpunit": "3.7.x" + } +} From e3e922fc49ab6ed22286a978cc16136ec546c4bb Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 10:30:48 +0000 Subject: [PATCH 0906/5359] Add test for wp core is-installed when WordPress is not installed --- tests/core-Test.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/core-Test.php diff --git a/tests/core-Test.php b/tests/core-Test.php new file mode 100644 index 000000000..66e1ae6ad --- /dev/null +++ b/tests/core-Test.php @@ -0,0 +1,34 @@ +<?php +class CoreTest extends PHPUnit_Framework_TestCase { + public function testIsInstalledExitsWith1IfWordPressNotInstalled() { + $temp_dir = self::create_temporary_directory(); + $result = self::run_wp_cli("core is-installed --path=$temp_dir"); + $this->assertEquals(1, $result->return_code); + } + + private static function create_temporary_directory() { + return sys_get_temp_dir() . '/' . uniqid("wp-cli-test-", TRUE); + } + + private static function run_wp_cli( $wp_cli_command ) { + $wp_cli_path = self::find_wp_cli(); + return self::run_command("$wp_cli_path $wp_cli_command"); + } + + private static function find_wp_cli() { + return "src/bin/wp"; + } + + private static function run_command( $command ) { + $output = array(); + $return_code = 0; + exec( $command, $output, $return_code ); + return new ExecutionResult( $return_code ); + } +} + +class ExecutionResult { + public function __construct( $return_code ) { + $this->return_code = $return_code; + } +} From d5d95f216c3a84a9fdded6fbee2a5e47ad39ccaa Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:29:11 +0000 Subject: [PATCH 0907/5359] Add tests for installing WordPress --- tests/core-Test.php | 76 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index 66e1ae6ad..bc874c4ce 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -1,34 +1,90 @@ <?php class CoreTest extends PHPUnit_Framework_TestCase { + + public function testIsInstalledExitsWith1IfWordPressNotInstalled() { $temp_dir = self::create_temporary_directory(); - $result = self::run_wp_cli("core is-installed --path=$temp_dir"); + $command_runner = new CommandRunner( $temp_dir ); + $result = $command_runner->run_wp_cli("core is-installed"); $this->assertEquals(1, $result->return_code); } + public function testIsInstalledExitsWith0AfterRunningInstallCommand() { + $command_runner = $this->install_wp_cli(); + $result = $command_runner->run_wp_cli("core is-installed"); + $this->assertEquals(0, $result->return_code); + } + + public function testInstallCommandCreatesDefaultBlogPost() { + $command_runner = $this->install_wp_cli(); + $result = $command_runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } + + private function install_wp_cli() { + $temp_dir = self::create_temporary_directory(); + $command_runner = new CommandRunner( $temp_dir ); + self::download_wordpress_files( $temp_dir ); + $dbname = "wp_cli_test"; + $dbuser = "wp_cli_test"; + $dbpass = "password1"; + exec( "mysql -u$dbname -p$dbpass -e 'DROP DATABASE $dbname'" ); + exec( "mysql -u$dbname -p$dbpass -e 'CREATE DATABASE $dbname'" ); + $command_runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); + $command_runner->run_wp_cli( + "core install --url=http://example.com/ --title=WordPress " . + " --admin_email=admin@example.com --admin_password=password1" + ); + return $command_runner; + } + + private static function download_wordpress_files( $target_dir ) { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir($cache_dir); + $command_runner = new CommandRunner( $cache_dir ); + $command_runner->run_wp_cli( "core download" ); + } + exec( "cp -r '$cache_dir/'* '$target_dir/'" ); + } + private static function create_temporary_directory() { - return sys_get_temp_dir() . '/' . uniqid("wp-cli-test-", TRUE); + $dir = sys_get_temp_dir() . '/' . uniqid("wp-cli-test-", TRUE); + mkdir($dir); + return $dir; + } +} + +class CommandRunner { + private $cwd; + + public function __construct( $cwd ) { + $this->cwd = $cwd; } - private static function run_wp_cli( $wp_cli_command ) { + public function run_wp_cli( $wp_cli_command ) { $wp_cli_path = self::find_wp_cli(); - return self::run_command("$wp_cli_path $wp_cli_command"); + return self::run_command( "$wp_cli_path $wp_cli_command" ); } - private static function find_wp_cli() { - return "src/bin/wp"; + private function find_wp_cli() { + return getcwd() . "/src/bin/wp"; } - private static function run_command( $command ) { + private function run_command( $command ) { $output = array(); $return_code = 0; - exec( $command, $output, $return_code ); - return new ExecutionResult( $return_code ); + $cwd = $this->cwd; + exec( "sh -c 'cd $cwd; $command'", $output, $return_code ); + return new ExecutionResult( $return_code, implode( "\n", $output ) ); } } class ExecutionResult { - public function __construct( $return_code ) { + public function __construct( $return_code, $output ) { $this->return_code = $return_code; + $this->output = $output; } } From 3c43036af660ae03acf1b34d394c4eeafa62effe Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:31:51 +0000 Subject: [PATCH 0908/5359] Split command runner class into a separate file --- tests/class-command-runner.php | 33 ++++++++++++++++++++++++++++ tests/core-Test.php | 39 ++++------------------------------ 2 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 tests/class-command-runner.php diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php new file mode 100644 index 000000000..e4af39030 --- /dev/null +++ b/tests/class-command-runner.php @@ -0,0 +1,33 @@ +<?php + +class Command_Runner { + private $cwd; + + public function __construct( $cwd ) { + $this->cwd = $cwd; + } + + public function run_wp_cli( $wp_cli_command ) { + $wp_cli_path = self::find_wp_cli(); + return self::run_command( "$wp_cli_path $wp_cli_command" ); + } + + private function find_wp_cli() { + return getcwd() . "/src/bin/wp"; + } + + private function run_command( $command ) { + $output = array(); + $return_code = 0; + $cwd = $this->cwd; + exec( "sh -c 'cd $cwd; $command'", $output, $return_code ); + return new Execution_Result( $return_code, implode( "\n", $output ) ); + } +} + +class Execution_Result { + public function __construct( $return_code, $output ) { + $this->return_code = $return_code; + $this->output = $output; + } +} diff --git a/tests/core-Test.php b/tests/core-Test.php index bc874c4ce..94b1a9e26 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -1,7 +1,8 @@ <?php + +require __DIR__ . '/class-command-runner.php'; + class CoreTest extends PHPUnit_Framework_TestCase { - - public function testIsInstalledExitsWith1IfWordPressNotInstalled() { $temp_dir = self::create_temporary_directory(); $command_runner = new CommandRunner( $temp_dir ); @@ -23,7 +24,7 @@ public function testInstallCommandCreatesDefaultBlogPost() { private function install_wp_cli() { $temp_dir = self::create_temporary_directory(); - $command_runner = new CommandRunner( $temp_dir ); + $command_runner = new Command_Runner( $temp_dir ); self::download_wordpress_files( $temp_dir ); $dbname = "wp_cli_test"; $dbuser = "wp_cli_test"; @@ -56,35 +57,3 @@ private static function create_temporary_directory() { return $dir; } } - -class CommandRunner { - private $cwd; - - public function __construct( $cwd ) { - $this->cwd = $cwd; - } - - public function run_wp_cli( $wp_cli_command ) { - $wp_cli_path = self::find_wp_cli(); - return self::run_command( "$wp_cli_path $wp_cli_command" ); - } - - private function find_wp_cli() { - return getcwd() . "/src/bin/wp"; - } - - private function run_command( $command ) { - $output = array(); - $return_code = 0; - $cwd = $this->cwd; - exec( "sh -c 'cd $cwd; $command'", $output, $return_code ); - return new ExecutionResult( $return_code, implode( "\n", $output ) ); - } -} - -class ExecutionResult { - public function __construct( $return_code, $output ) { - $this->return_code = $return_code; - $this->output = $output; - } -} From 431127a4f10045ea86c330aa4103a66c2f02f862 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:37:30 +0000 Subject: [PATCH 0909/5359] Add instructions for running tests to README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 1095531af..312178020 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,24 @@ Need even more info? Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. + +Running tests +------------- + +The tests use PHPUnit, which can be installed using [composer](http://getcomposer.org/). +Once you've composer installed, run: + + composer.phar install --dev + +Before running the tests, you'll need a MySQL user called wp_cli_test with the password password1 that +has full privileges on the MySQL database wp_cli_test. Running the following +as root in MySQL should do the trick: + + GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" + IDENTIFIED BY "password1"; + +Finally, to run the tests: + + vendor/bin/phpunit tests + + From b9339bdc2bc2a0bd32ec64bfeb8cdf3b5d6163dd Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:38:19 +0000 Subject: [PATCH 0910/5359] Add missing word to test instructions in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 312178020..4ef7a34ea 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Running tests ------------- The tests use PHPUnit, which can be installed using [composer](http://getcomposer.org/). -Once you've composer installed, run: +Once you've got composer installed, run: composer.phar install --dev From 9296c4d57d98b423a02e415ca024796614d9ad10 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:39:05 +0000 Subject: [PATCH 0911/5359] Clarify README.md by marking database name/username/password using backticks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4ef7a34ea..4f30b007b 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ Once you've got composer installed, run: composer.phar install --dev -Before running the tests, you'll need a MySQL user called wp_cli_test with the password password1 that -has full privileges on the MySQL database wp_cli_test. Running the following -as root in MySQL should do the trick: +Before running the tests, you'll need a MySQL user called `wp_cli_test` with the +password `password1` that has full privileges on the MySQL database `wp_cli_test`. +Running the following as root in MySQL should do the trick: GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; From 759bf9b0aab8a0e95fef3ebee7b33cd2fe1074bd Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:40:54 +0000 Subject: [PATCH 0912/5359] Add spaces around function arguments --- tests/core-Test.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index 94b1a9e26..7a71ef12d 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -6,13 +6,13 @@ class CoreTest extends PHPUnit_Framework_TestCase { public function testIsInstalledExitsWith1IfWordPressNotInstalled() { $temp_dir = self::create_temporary_directory(); $command_runner = new CommandRunner( $temp_dir ); - $result = $command_runner->run_wp_cli("core is-installed"); + $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(1, $result->return_code); } public function testIsInstalledExitsWith0AfterRunningInstallCommand() { $command_runner = $this->install_wp_cli(); - $result = $command_runner->run_wp_cli("core is-installed"); + $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(0, $result->return_code); } @@ -44,7 +44,7 @@ private static function download_wordpress_files( $target_dir ) { // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { - mkdir($cache_dir); + mkdir( $cache_dir ); $command_runner = new CommandRunner( $cache_dir ); $command_runner->run_wp_cli( "core download" ); } @@ -52,8 +52,8 @@ private static function download_wordpress_files( $target_dir ) { } private static function create_temporary_directory() { - $dir = sys_get_temp_dir() . '/' . uniqid("wp-cli-test-", TRUE); - mkdir($dir); + $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $dir ); return $dir; } } From 89873085450fc3b3aebfb874c540a12f65ac1d11 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:41:44 +0000 Subject: [PATCH 0913/5359] Fix test due to rename of class --- tests/core-Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index 7a71ef12d..79de8a0d7 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -5,7 +5,7 @@ class CoreTest extends PHPUnit_Framework_TestCase { public function testIsInstalledExitsWith1IfWordPressNotInstalled() { $temp_dir = self::create_temporary_directory(); - $command_runner = new CommandRunner( $temp_dir ); + $command_runner = new Command_Runner( $temp_dir ); $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(1, $result->return_code); } From e40b85574ac763093abf017fa02d421ce318d9f4 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:43:20 +0000 Subject: [PATCH 0914/5359] Rename tests to use underscores instead of lowerCamelCase --- tests/core-Test.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index 79de8a0d7..c605c112e 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -3,20 +3,20 @@ require __DIR__ . '/class-command-runner.php'; class CoreTest extends PHPUnit_Framework_TestCase { - public function testIsInstalledExitsWith1IfWordPressNotInstalled() { + public function test_is_installed_exits_with_1_if_wordpress_not_installed() { $temp_dir = self::create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(1, $result->return_code); } - public function testIsInstalledExitsWith0AfterRunningInstallCommand() { + public function test_is_installed_exits_with_0_after_running_install_command() { $command_runner = $this->install_wp_cli(); $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(0, $result->return_code); } - public function testInstallCommandCreatesDefaultBlogPost() { + public function test_install_command_creates_default_blog_post() { $command_runner = $this->install_wp_cli(); $result = $command_runner->run_wp_cli( "post list --ids" ); $this->assertEquals( "1", $result->output ); From 64fa735b026106dbbd1c274e2d88bb5dc3b1761a Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:45:13 +0000 Subject: [PATCH 0915/5359] Add documentation for running specific test --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4f30b007b..22cda5bf8 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,7 @@ Finally, to run the tests: vendor/bin/phpunit tests +Each test installs WordPress from scratch. Since this is pretty slow, you can +use arguments to `phpunit` to only run the test that you're interested in: + vendor/bin/phpunit --filter test_function_you_want_to_run tests From 912703a777df8d426d70331824fd23ba1f2fef5a Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 11:46:34 +0000 Subject: [PATCH 0916/5359] Correct documentation -- most, but not all, tests install WordPress --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22cda5bf8..c6d3179f1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Finally, to run the tests: vendor/bin/phpunit tests -Each test installs WordPress from scratch. Since this is pretty slow, you can +Most tests install WordPress from scratch. Since this is pretty slow, you can use arguments to `phpunit` to only run the test that you're interested in: vendor/bin/phpunit --filter test_function_you_want_to_run tests From 1ea7c5f6f1e50a919078d69e6c23bab3bded5d6c Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 12:25:18 +0000 Subject: [PATCH 0917/5359] Display error in "wp core install" when wp-config.php is missing --- src/php/wp-cli/class-wp-cli.php | 5 +++++ tests/class-command-runner.php | 16 +++++++++++++--- tests/core-Test.php | 14 +++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 560c46f63..b07c1a899 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -277,6 +277,11 @@ static function before_wp_load() { // Set installer flag before loading any WP files if ( array( 'core', 'install' ) == self::$arguments ) { define( 'WP_INSTALLING', true ); + + if ( !file_exists( WP_ROOT . '/wp-config.php' ) ) { + WP_CLI::error( "wp-config.php not found\n" . + "Either create one manually or use wp core config" ); + } } // Pretend we're in WP_ADMIN, to side-step full-page caching plugins diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index e4af39030..f39b36007 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -17,11 +17,21 @@ private function find_wp_cli() { } private function run_command( $command ) { - $output = array(); + $output_dummy = array(); + $output_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); + $output_binary_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); $return_code = 0; $cwd = $this->cwd; - exec( "sh -c 'cd $cwd; $command'", $output, $return_code ); - return new Execution_Result( $return_code, implode( "\n", $output ) ); + $sh_command = "cd $cwd;" . + "$command > $output_binary_file 2>&1;" . + 'RETURN_CODE=$?;' . + "cat -v $output_binary_file > $output_file;" . + 'exit $RETURN_CODE'; + exec("sh -c '$sh_command'", $output_dummy, $return_code ); + $output = file_get_contents( $output_file); + unlink( $output_file ); + unlink( $output_binary_file ); + return new Execution_Result( $return_code, $output ); } } diff --git a/tests/core-Test.php b/tests/core-Test.php index c605c112e..816e4d9b0 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -22,6 +22,18 @@ public function test_install_command_creates_default_blog_post() { $this->assertEquals( "1", $result->output ); } + public function test_message_explains_that_config_must_be_present_before_install() { + $temp_dir = self::create_temporary_directory(); + $command_runner = new Command_Runner( $temp_dir ); + self::download_wordpress_files( $temp_dir ); + $result = $command_runner->run_wp_cli( "core install" ); + $this->assertEquals( + "^[[31;1mError: ^[[0mwp-config.php not found\n" . + "Either create one manually or use wp core config\n", + $result->output + ); + } + private function install_wp_cli() { $temp_dir = self::create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); @@ -45,7 +57,7 @@ private static function download_wordpress_files( $target_dir ) { $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { mkdir( $cache_dir ); - $command_runner = new CommandRunner( $cache_dir ); + $command_runner = new Command_Runner( $cache_dir ); $command_runner->run_wp_cli( "core download" ); } exec( "cp -r '$cache_dir/'* '$target_dir/'" ); From f7df0541588e3da3ff9829feb00eaef37a82ed64 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 12:34:52 +0000 Subject: [PATCH 0918/5359] Move general testing functionality into base class --- tests/class-wp-cli-test-case.php | 40 +++++++++++++++++++++++++++ tests/core-Test.php | 46 +++++--------------------------- 2 files changed, 46 insertions(+), 40 deletions(-) create mode 100644 tests/class-wp-cli-test-case.php diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php new file mode 100644 index 000000000..be7e99841 --- /dev/null +++ b/tests/class-wp-cli-test-case.php @@ -0,0 +1,40 @@ +<?php + +require_once __DIR__ . '/class-command-runner.php'; + +abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { + public function install_wp_cli() { + $temp_dir = $this->create_temporary_directory(); + $command_runner = new Command_Runner( $temp_dir ); + $this->download_wordpress_files( $temp_dir ); + $dbname = "wp_cli_test"; + $dbuser = "wp_cli_test"; + $dbpass = "password1"; + exec( "mysql -u$dbname -p$dbpass -e 'DROP DATABASE $dbname'" ); + exec( "mysql -u$dbname -p$dbpass -e 'CREATE DATABASE $dbname'" ); + $command_runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); + $command_runner->run_wp_cli( + "core install --url=http://example.com/ --title=WordPress " . + " --admin_email=admin@example.com --admin_password=password1" + ); + return $command_runner; + } + + public function download_wordpress_files( $target_dir ) { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir( $cache_dir ); + $command_runner = new Command_Runner( $cache_dir ); + $command_runner->run_wp_cli( "core download" ); + } + exec( "cp -r '$cache_dir/'* '$target_dir/'" ); + } + + public function create_temporary_directory() { + $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $dir ); + return $dir; + } +} diff --git a/tests/core-Test.php b/tests/core-Test.php index 816e4d9b0..3c79f9760 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -1,10 +1,11 @@ <?php -require __DIR__ . '/class-command-runner.php'; +require_once __DIR__ . '/class-command-runner.php'; +require_once __DIR__ . '/class-wp-cli-test-case.php'; -class CoreTest extends PHPUnit_Framework_TestCase { +class CoreTest extends Wp_Cli_Test_Case { public function test_is_installed_exits_with_1_if_wordpress_not_installed() { - $temp_dir = self::create_temporary_directory(); + $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); $result = $command_runner->run_wp_cli( "core is-installed" ); $this->assertEquals(1, $result->return_code); @@ -23,9 +24,9 @@ public function test_install_command_creates_default_blog_post() { } public function test_message_explains_that_config_must_be_present_before_install() { - $temp_dir = self::create_temporary_directory(); + $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); - self::download_wordpress_files( $temp_dir ); + $this->download_wordpress_files( $temp_dir ); $result = $command_runner->run_wp_cli( "core install" ); $this->assertEquals( "^[[31;1mError: ^[[0mwp-config.php not found\n" . @@ -33,39 +34,4 @@ public function test_message_explains_that_config_must_be_present_before_install $result->output ); } - - private function install_wp_cli() { - $temp_dir = self::create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - self::download_wordpress_files( $temp_dir ); - $dbname = "wp_cli_test"; - $dbuser = "wp_cli_test"; - $dbpass = "password1"; - exec( "mysql -u$dbname -p$dbpass -e 'DROP DATABASE $dbname'" ); - exec( "mysql -u$dbname -p$dbpass -e 'CREATE DATABASE $dbname'" ); - $command_runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); - $command_runner->run_wp_cli( - "core install --url=http://example.com/ --title=WordPress " . - " --admin_email=admin@example.com --admin_password=password1" - ); - return $command_runner; - } - - private static function download_wordpress_files( $target_dir ) { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $command_runner = new Command_Runner( $cache_dir ); - $command_runner->run_wp_cli( "core download" ); - } - exec( "cp -r '$cache_dir/'* '$target_dir/'" ); - } - - private static function create_temporary_directory() { - $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $dir ); - return $dir; - } } From 7a296f7628b3c403ebe6508a6f1f6028b237b3a2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 15:43:32 +0200 Subject: [PATCH 0919/5359] make `post update` accept multiple ids. see #229 --- src/php/wp-cli/commands/internals/post.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/internals/post.php index dd84c51db..12ca8e094 100644 --- a/src/php/wp-cli/commands/internals/post.php +++ b/src/php/wp-cli/commands/internals/post.php @@ -33,21 +33,23 @@ public function create( $_, $assoc_args ) { /** * Update a post. * - * @synopsis <id> --<field>=<value> + * @synopsis <id>... --<field>=<value> */ public function update( $args, $assoc_args ) { - list( $post_id ) = $args; + foreach ( $args as $post_id ) { + if ( empty( $assoc_args ) ) { + WP_CLI::error( "Need some fields to update." ); + } - if ( empty( $assoc_args ) ) { - WP_CLI::error( "Need some fields to update." ); - } + $params = array_merge( $assoc_args, array( 'ID' => $post_id ) ); - $params = array_merge( $assoc_args, array( 'ID' => $post_id ) ); + $r = wp_update_post( $params, true ); - if ( wp_update_post( $params ) ) { - WP_CLI::success( "Updated post $post_id." ); - } else { - WP_CLI::error( "Failed updating post $post_id" ); + if ( is_wp_error( $r ) ) { + WP_CLI::error( "Post $post_id: " . $r->get_error_message() ); + } else { + WP_CLI::success( "Updated post $post_id." ); + } } } From 9b482fd88d15413e5ce9239423e2d45373ec9d1d Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 16:06:31 +0000 Subject: [PATCH 0920/5359] Split off installation commands to dedicated class --- tests/class-wp-cli-test-case.php | 57 +++++++++++++++++++++++--------- tests/core-Test.php | 3 +- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index be7e99841..1c0cbe389 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -6,21 +6,51 @@ abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { public function install_wp_cli() { $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); - $this->download_wordpress_files( $temp_dir ); - $dbname = "wp_cli_test"; - $dbuser = "wp_cli_test"; - $dbpass = "password1"; - exec( "mysql -u$dbname -p$dbpass -e 'DROP DATABASE $dbname'" ); - exec( "mysql -u$dbname -p$dbpass -e 'CREATE DATABASE $dbname'" ); - $command_runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); - $command_runner->run_wp_cli( + $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $installer->download_wordpress_files( $temp_dir ); + $installer->reset_database(); + $installer->create_config(); + $installer->run_install(); + return $command_runner; + } + + public function create_temporary_directory() { + $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $dir ); + return $dir; + } +} + +class Wordpress_Installer { + private $dbname = "wp_cli_test"; + private $dbuser = "wp_cli_test"; + private $dbpass = "password1"; + private $install_dir; + private $command_runner; + + public function __construct( $install_dir, $command_runner ) { + $this->install_dir = $install_dir; + $this->command_runner = $command_runner; + } + + public function reset_database() { + exec( "mysql -u$this->dbname -p$this->dbpass -e 'DROP DATABASE $this->dbname'" ); + exec( "mysql -u$this->dbname -p$this->dbpass -e 'CREATE DATABASE $this->dbname'" ); + } + + public function create_config() { + $this->command_runner->run_wp_cli( + "core config --dbname=$this->dbname --dbuser=$this->dbuser --dbpass=$this->dbpass" ); + } + + public function run_install() { + $this->command_runner->run_wp_cli( "core install --url=http://example.com/ --title=WordPress " . " --admin_email=admin@example.com --admin_password=password1" ); - return $command_runner; } - public function download_wordpress_files( $target_dir ) { + public function download_wordpress_files() { // We cache the results of "wp core download" to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; @@ -29,12 +59,7 @@ public function download_wordpress_files( $target_dir ) { $command_runner = new Command_Runner( $cache_dir ); $command_runner->run_wp_cli( "core download" ); } - exec( "cp -r '$cache_dir/'* '$target_dir/'" ); + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } - public function create_temporary_directory() { - $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $dir ); - return $dir; - } } diff --git a/tests/core-Test.php b/tests/core-Test.php index 3c79f9760..5a6bd8a59 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -26,7 +26,8 @@ public function test_install_command_creates_default_blog_post() { public function test_message_explains_that_config_must_be_present_before_install() { $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); - $this->download_wordpress_files( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $installer->download_wordpress_files( $temp_dir ); $result = $command_runner->run_wp_cli( "core install" ); $this->assertEquals( "^[[31;1mError: ^[[0mwp-config.php not found\n" . From 9399daca3dcdbd96fcef445263bc9d059b899743 Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Thu, 13 Dec 2012 16:31:06 +0000 Subject: [PATCH 0921/5359] Update detection of wp-config.php to match WordPress itself --- src/php/wp-cli/class-wp-cli.php | 18 +++++++++--- tests/class-wp-cli-test-case.php | 49 +++++++++++++++++++++++--------- tests/core-Test.php | 14 +++++++++ 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index b07c1a899..078201193 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -278,16 +278,26 @@ static function before_wp_load() { if ( array( 'core', 'install' ) == self::$arguments ) { define( 'WP_INSTALLING', true ); - if ( !file_exists( WP_ROOT . '/wp-config.php' ) ) { - WP_CLI::error( "wp-config.php not found\n" . - "Either create one manually or use wp core config" ); - } + if ( !self::wp_config_is_present() ) { + WP_CLI::error( "wp-config.php not found\n" . + "Either create one manually or use wp core config" ); + } } // Pretend we're in WP_ADMIN, to side-step full-page caching plugins define( 'WP_ADMIN', true ); $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } + + private static function wp_config_is_present() { + if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { + return TRUE; + } + if ( file_exists( dirname(WP_ROOT) . '/wp-config.php' ) && ! file_exists( dirname(WP_ROOT) . '/wp-settings.php' ) ) { + return TRUE; + } + return FALSE; + } static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 1c0cbe389..702bb5fe6 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -3,13 +3,34 @@ require_once __DIR__ . '/class-command-runner.php'; abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { + protected $database_settings = array( + "dbname" => "wp_cli_test", + "dbuser" => "wp_cli_test", + "dbpass" => "password1" + ); + + protected function setUp() { + $this->reset_database(); + } + + private function reset_database() { + $dbname = $this->database_settings["dbname"]; + $this->run_sql( "DROP DATABASE $dbname" ); + $this->run_sql( "CREATE DATABASE $dbname" ); + } + + private function run_sql( $sql ) { + $dbuser = $this->database_settings["dbuser"]; + $dbpass = $this->database_settings["dbpass"]; + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + } + public function install_wp_cli() { $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); $installer = new Wordpress_Installer( $temp_dir, $command_runner ); $installer->download_wordpress_files( $temp_dir ); - $installer->reset_database(); - $installer->create_config(); + $installer->create_config( $this->database_settings ); $installer->run_install(); return $command_runner; } @@ -22,9 +43,6 @@ public function create_temporary_directory() { } class Wordpress_Installer { - private $dbname = "wp_cli_test"; - private $dbuser = "wp_cli_test"; - private $dbpass = "password1"; private $install_dir; private $command_runner; @@ -33,21 +51,20 @@ public function __construct( $install_dir, $command_runner ) { $this->command_runner = $command_runner; } - public function reset_database() { - exec( "mysql -u$this->dbname -p$this->dbpass -e 'DROP DATABASE $this->dbname'" ); - exec( "mysql -u$this->dbname -p$this->dbpass -e 'CREATE DATABASE $this->dbname'" ); - } - - public function create_config() { + public function create_config( $database_settings ) { + $dbname = $database_settings["dbname"]; + $dbuser = $database_settings["dbuser"]; + $dbpass = $database_settings["dbpass"]; $this->command_runner->run_wp_cli( - "core config --dbname=$this->dbname --dbuser=$this->dbuser --dbpass=$this->dbpass" ); + "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); } public function run_install() { - $this->command_runner->run_wp_cli( + $install_result = $this->command_runner->run_wp_cli( "core install --url=http://example.com/ --title=WordPress " . " --admin_email=admin@example.com --admin_password=password1" ); + $this->assert_process_exited_successfully( $install_result ); } public function download_wordpress_files() { @@ -62,4 +79,10 @@ public function download_wordpress_files() { exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } + private function assert_process_exited_successfully( $result ) { + if ( $result->return_code !== 0 ) { + $message = "return code was $result->return_code, output was: $result->output"; + throw new Exception( $message ); + } + } } diff --git a/tests/core-Test.php b/tests/core-Test.php index 5a6bd8a59..eb37feb0f 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -35,4 +35,18 @@ public function test_message_explains_that_config_must_be_present_before_install $result->output ); } + + public function test_wp_config_can_be_placed_in_parent_directory() { + $temp_dir = $this->create_temporary_directory(); + $install_dir = $temp_dir . '/www-root'; + mkdir( $install_dir ); + $command_runner = new Command_Runner( $install_dir ); + $installer = new Wordpress_Installer( $install_dir, $command_runner ); + $installer->download_wordpress_files( $install_dir ); + $installer->create_config( $this->database_settings ); + rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); + $installer->run_install(); + $result = $command_runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } } From 88f1faeed23e867f26cc87b630b4eccf2c1e665a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 22:59:16 +0200 Subject: [PATCH 0922/5359] use Utils\locate_wp_config(). see #241 --- src/php/wp-cli/class-wp-cli.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 078201193..8da8b9f36 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -278,9 +278,9 @@ static function before_wp_load() { if ( array( 'core', 'install' ) == self::$arguments ) { define( 'WP_INSTALLING', true ); - if ( !self::wp_config_is_present() ) { + if ( !Utils\locate_wp_config() ) { WP_CLI::error( "wp-config.php not found\n" . - "Either create one manually or use wp core config" ); + "Either create one manually or use `wp core config`." ); } } @@ -288,16 +288,6 @@ static function before_wp_load() { define( 'WP_ADMIN', true ); $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } - - private static function wp_config_is_present() { - if ( file_exists( WP_ROOT . '/wp-config.php' ) ) { - return TRUE; - } - if ( file_exists( dirname(WP_ROOT) . '/wp-config.php' ) && ! file_exists( dirname(WP_ROOT) . '/wp-settings.php' ) ) { - return TRUE; - } - return FALSE; - } static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); From 0809d64b8c28fc27188e6c946ed93e9fa63d5a58 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 23:20:12 +0200 Subject: [PATCH 0923/5359] make wp-cli a Composer library --- composer.json | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 90f5a3d05..85854aa80 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,10 @@ { - "require-dev": { - "phpunit/phpunit": "3.7.x" - } + "name": "wp-cli/wp-cli", + "description": "A command line interface for WordPress", + "keywords": [ "cli", "wordpress" ], + "homepage": "http://wp-cli.org", + "license": "MIT", + "require-dev": { + "phpunit/phpunit": "3.7.x" + } } From 0e3be8953aed546b75f64a6448431f48e3204bac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 23:23:29 +0200 Subject: [PATCH 0924/5359] specify required PHP version --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 85854aa80..da2185fe3 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,9 @@ "keywords": [ "cli", "wordpress" ], "homepage": "http://wp-cli.org", "license": "MIT", + "require": { + "php": ">=5.3" + }, "require-dev": { "phpunit/phpunit": "3.7.x" } From 533c9d804852cb1e83cc39496c6defe01b1fc294 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 23:32:56 +0200 Subject: [PATCH 0925/5359] register binary --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index da2185fe3..3ec42c39a 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,9 @@ "keywords": [ "cli", "wordpress" ], "homepage": "http://wp-cli.org", "license": "MIT", + "bin": [ + "src/bin/wp" + ], "require": { "php": ">=5.3" }, From d9154186df521bdf5bc72af8f4ac1248844cc7e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Dec 2012 23:44:00 +0200 Subject: [PATCH 0926/5359] add php-cli-tools dependency --- composer.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3ec42c39a..a3636d881 100644 --- a/composer.json +++ b/composer.json @@ -7,8 +7,15 @@ "bin": [ "src/bin/wp" ], + "repositories": [ + { + "type": "vcs", + "url": "http://github.com/wp-cli/php-cli-tools" + } + ], "require": { - "php": ">=5.3" + "php": ">=5.3", + "jlogsdon/cli": "v0.9.2-alpha" }, "require-dev": { "phpunit/phpunit": "3.7.x" From e8de957456d2e20b0ea52b63cff850cb66c18faf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Dec 2012 00:02:19 +0200 Subject: [PATCH 0927/5359] use php-cli-tools from Packagist --- composer.json | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index a3636d881..3092b1c42 100644 --- a/composer.json +++ b/composer.json @@ -7,17 +7,12 @@ "bin": [ "src/bin/wp" ], - "repositories": [ - { - "type": "vcs", - "url": "http://github.com/wp-cli/php-cli-tools" - } - ], "require": { "php": ">=5.3", - "jlogsdon/cli": "v0.9.2-alpha" + "wp-cli/php-cli-tools": "dev-master" }, "require-dev": { "phpunit/phpunit": "3.7.x" - } + }, + "minimum-stability": "dev" } From 21a3b981a7c45da56cf077b41a430af81f4989b6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Dec 2012 00:52:02 +0200 Subject: [PATCH 0928/5359] load php-cli-tools from vendor dir, when available --- src/php/wp-cli/utils.php | 12 ++++++++++++ src/php/wp-cli/wp-cli.php | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index 5221c12de..dae02d573 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -2,6 +2,18 @@ namespace WP_CLI\Utils; +function load_cli_tools() { + $vendor_path = WP_CLI_ROOT . '../../../vendor'; + + if ( file_exists( $vendor_path . '/autoload.php' ) ) { + require $vendor_path . '/autoload.php'; + include $vendor_path . '/wp-cli/php-cli-tools/lib/cli/cli.php'; + } else { + include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; + \cli\register_autoload(); + } +} + /** * Splits $argv into positional and associative arguments. * diff --git a/src/php/wp-cli/wp-cli.php b/src/php/wp-cli/wp-cli.php index c7a3ea82e..0f7fe5986 100755 --- a/src/php/wp-cli/wp-cli.php +++ b/src/php/wp-cli/wp-cli.php @@ -15,8 +15,7 @@ include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; include WP_CLI_ROOT . 'man.php'; -include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; -\cli\register_autoload(); +\WP_CLI\Utils\load_cli_tools(); WP_CLI::before_wp_load(); From 59c3806ec7cc20857dc9e25a7ba3b99bbfa35c28 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Dec 2012 02:32:55 +0200 Subject: [PATCH 0929/5359] handle both possible Composer scenarios --- src/php/wp-cli/utils.php | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index dae02d573..c78ebbe53 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -3,12 +3,23 @@ namespace WP_CLI\Utils; function load_cli_tools() { - $vendor_path = WP_CLI_ROOT . '../../../vendor'; + $vendor_paths = array( + WP_CLI_ROOT . '../../../../../../vendor', // part of a larger project + WP_CLI_ROOT . '../../../vendor', // top-level project + ); + + $found = true; + + foreach ( $vendor_paths as $vendor_path ) { + if ( file_exists( $vendor_path . '/autoload.php' ) ) { + require $vendor_path . '/autoload.php'; + include $vendor_path . '/wp-cli/php-cli-tools/lib/cli/cli.php'; + $found = true; + break; + } + } - if ( file_exists( $vendor_path . '/autoload.php' ) ) { - require $vendor_path . '/autoload.php'; - include $vendor_path . '/wp-cli/php-cli-tools/lib/cli/cli.php'; - } else { + if ( !$found ) { include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); } From c905c0320ec8afb3e52b8915e0926ccba9c150ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Dec 2012 22:14:24 +0200 Subject: [PATCH 0930/5359] assume the vendor directory doesn't exist. see #242 --- src/php/wp-cli/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/utils.php b/src/php/wp-cli/utils.php index c78ebbe53..4d1969575 100644 --- a/src/php/wp-cli/utils.php +++ b/src/php/wp-cli/utils.php @@ -8,7 +8,7 @@ function load_cli_tools() { WP_CLI_ROOT . '../../../vendor', // top-level project ); - $found = true; + $found = false; foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { From a3fca4689ab2f908013cc2d4020e0647c7b1e17e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 05:40:19 +0200 Subject: [PATCH 0931/5359] implement wp cap list --- src/php/wp-cli/commands/internals/cap.php | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/php/wp-cli/commands/internals/cap.php diff --git a/src/php/wp-cli/commands/internals/cap.php b/src/php/wp-cli/commands/internals/cap.php new file mode 100644 index 000000000..315b4ffe1 --- /dev/null +++ b/src/php/wp-cli/commands/internals/cap.php @@ -0,0 +1,33 @@ +<?php + +WP_CLI::add_command( 'cap', 'Capabilities_Command' ); + +/** + * Manage capabilities. + * + * @package wp-cli + * @subpackage commands/internals + */ +class Capabilities_Command extends WP_CLI_Command { + + /** + * List capabilities for a given role. + * + * @subcommand list + * @synopsis <role> + */ + public function _list( $args ) { + global $wp_roles; + + list( $role ) = $args; + + $role_obj = $wp_roles->get_role( $role ); + + if ( !$role_obj ) + WP_CLI::error( "$role does not exist" ); + + foreach ( array_keys( $role_obj->capabilities ) as $cap ) + WP_CLI::line( $cap ); + } +} + From e31cb1941eaf9eb33b5cf2d1024755ec73a0b5db Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 06:14:37 +0200 Subject: [PATCH 0932/5359] implement `wp cap add` and `wp cap remove` --- src/php/wp-cli/commands/internals/cap.php | 73 +++++++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/cap.php b/src/php/wp-cli/commands/internals/cap.php index 315b4ffe1..f496acc70 100644 --- a/src/php/wp-cli/commands/internals/cap.php +++ b/src/php/wp-cli/commands/internals/cap.php @@ -17,17 +17,80 @@ class Capabilities_Command extends WP_CLI_Command { * @synopsis <role> */ public function _list( $args ) { - global $wp_roles; + $role_obj = self::get_role( $args[0] ); + + foreach ( array_keys( $role_obj->capabilities ) as $cap ) + WP_CLI::line( $cap ); + } + + /** + * Add capabilities to a given role. + * + * @synopsis <role> <cap>... + */ + public function add( $args ) { + self::persistence_check(); + + $role = array_shift( $args ); + + $role_obj = self::get_role( $role ); + + $count = 0; + + foreach ( $args as $cap ) { + if ( $role_obj->has_cap( $cap ) ) + continue; + + $role_obj->add_cap( $cap ); + + $count++; + } + + WP_CLI::success( sprintf( "Added %d capabilities to '%s' role." , $count, $role ) ); + } + + /** + * Add capabilities to a given role. + * + * @synopsis <role> <cap>... + */ + public function remove( $args ) { + self::persistence_check(); + + $role = array_shift( $args ); + + $role_obj = self::get_role( $role ); + + $count = 0; + + foreach ( $args as $cap ) { + if ( !$role_obj->has_cap( $cap ) ) + continue; + + $role_obj->remove_cap( $cap ); + + $count++; + } - list( $role ) = $args; + WP_CLI::success( sprintf( "Removed %d capabilities from '%s' role." , $count, $role ) ); + } + + private static function get_role( $role ) { + global $wp_roles; $role_obj = $wp_roles->get_role( $role ); if ( !$role_obj ) - WP_CLI::error( "$role does not exist" ); + WP_CLI::error( "'$role' role not found." ); - foreach ( array_keys( $role_obj->capabilities ) as $cap ) - WP_CLI::line( $cap ); + return $role_obj; + } + + private static function persistence_check() { + global $wp_roles; + + if ( !$wp_roles->use_db ) + WP_CLI::error( "Role definitions are not persistent." ); } } From 55d86f3041836e4393c9762527e9cf19adae08f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 06:53:48 +0200 Subject: [PATCH 0933/5359] add a few examples --- man/cap.1 | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ src/docs/cap.txt | 10 +++++++++ 2 files changed, 67 insertions(+) create mode 100644 man/cap.1 create mode 100644 src/docs/cap.txt diff --git a/man/cap.1 b/man/cap.1 new file mode 100644 index 000000000..c12904046 --- /dev/null +++ b/man/cap.1 @@ -0,0 +1,57 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CAP" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-cap\fR \- Manage capabilities\. +. +.SH "SYNOPSIS" +wp cap list \fIrole\fR +. +.P +wp cap add \fIrole\fR \fIcap\fR\.\.\. +. +.P +wp cap remove \fIrole\fR \fIcap\fR\.\.\. +. +.SH "SUBCOMMANDS" +. +.TP +\fBlist\fR: +. +.IP +List capabilities for a given role\. +. +.TP +\fBadd\fR: +. +.IP +Add capabilities to a given role\. +. +.TP +\fBremove\fR: +. +.IP +Add capabilities to a given role\. +. +.SH "EXAMPLES" +. +.IP +# Add \'spectate\' capability to \'author\' role +. +.br +wp cap add \'author\' \'spectate\' +. +.IP +# Add all caps from \'editor\' role to \'author\' role +. +.br +wp cap list \'editor\' | xargs wp cap add \'author\' +. +.IP +# Remove all caps from \'editor\' role that also appear in \'author\' role +. +.br +wp cap list \'author\' | xargs wp cap remove \'editor\' + diff --git a/src/docs/cap.txt b/src/docs/cap.txt new file mode 100644 index 000000000..73b0921b1 --- /dev/null +++ b/src/docs/cap.txt @@ -0,0 +1,10 @@ +## EXAMPLES + + # Add 'spectate' capability to 'author' role + wp cap add 'author' 'spectate' + + # Add all caps from 'editor' role to 'author' role + wp cap list 'editor' | xargs wp cap add 'author' + + # Remove all caps from 'editor' role that also appear in 'author' role + wp cap list 'author' | xargs wp cap remove 'editor' From 3ce29907c6b2ba1913bfe4e980105d110f55cb3f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 08:22:52 +0200 Subject: [PATCH 0934/5359] implement `wp user add-role` --- src/php/wp-cli/commands/internals/user.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index 3a186402f..b35624b19 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -213,7 +213,7 @@ public function generate( $args, $assoc_args ) { } /** - * Add a user to a blog. + * Set the user role (for a particular blog). * * @subcommand set-role * @synopsis <user-login> [<role>] [--blog=<blog>] @@ -232,6 +232,22 @@ public function set_role( $args, $assoc_args ) { WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}" ); } + /** + * Add a role for a user. + * + * @subcommand add-role + * @synopsis <user-login> <role> [--blog=<blog>] + */ + public function add_role( $args, $assoc_args ) { + $user = self::get_user_from_first_arg( $args[0] ); + + $role = $args[1]; + + $user->add_role( $role ); + + WP_CLI::success( sprintf( "Added '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); + } + /** * Remove a user from a blog. * From 965573ee8bee8f2ff90863317517d748a028d87b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 08:29:37 +0200 Subject: [PATCH 0935/5359] add optional <role> arg to `wp user remove-role` --- src/php/wp-cli/commands/internals/user.php | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/internals/user.php index b35624b19..da0f1c167 100644 --- a/src/php/wp-cli/commands/internals/user.php +++ b/src/php/wp-cli/commands/internals/user.php @@ -249,21 +249,29 @@ public function add_role( $args, $assoc_args ) { } /** - * Remove a user from a blog. + * Remove a user's role. * * @subcommand remove-role - * @synopsis <user-login> + * @synopsis <user-login> [<role>] [--blog=<blog>] */ public function remove_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); - // Multisite - if ( function_exists( 'remove_user_from_blog' ) ) - remove_user_from_blog( $user->ID, get_current_blog_id() ); - else - $user->remove_all_caps(); + if ( isset( $args[1] ) ) { + $role = $args[1]; + + $user->remove_role( $role ); - WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); + WP_CLI::success( sprintf( "Removed '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); + } else { + // Multisite + if ( function_exists( 'remove_user_from_blog' ) ) + remove_user_from_blog( $user->ID, get_current_blog_id() ); + else + $user->remove_all_caps(); + + WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); + } } private static function get_user_from_first_arg( $id_or_login ) { From ed71807f4613183f5d990ff640cf68d4483eb9fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:03:06 +0200 Subject: [PATCH 0936/5359] first pass at reactivating a plugin after an update --- src/php/wp-cli/commands/internals/plugin.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/internals/plugin.php index 4a474d5df..06780e834 100644 --- a/src/php/wp-cli/commands/internals/plugin.php +++ b/src/php/wp-cli/commands/internals/plugin.php @@ -193,7 +193,20 @@ function update( $args, $assoc_args ) { } else { list( $basename ) = $this->parse_name( $args ); + $was_active = is_plugin_active( $basename ); + $was_network_active = is_plugin_active_for_network( $basename ); + parent::_update( $basename ); + + if ( $was_active ) { + $new_args = array( $args[0] ); + + $new_assoc_args = array(); + if ( $was_network_active ) + $new_assoc_args['network'] = true; + + $this->activate( $new_args, $new_assoc_args ); + } } } From 188e114abab1268d9afb8da154e297298e758e5d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:21:43 +0200 Subject: [PATCH 0937/5359] extract modify_wp_config() helper --- src/php/wp-cli/commands/internals/core.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/internals/core.php index 40af5f6aa..5b1d3b653 100644 --- a/src/php/wp-cli/commands/internals/core.php +++ b/src/php/wp-cli/commands/internals/core.php @@ -150,17 +150,21 @@ public function install_network( $args, $assoc_args ) { <?php $ms_config = ob_get_clean(); + self::modify_wp_config( $ms_config ); + + wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); + + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + } + + private static function modify_wp_config( $content ) { $wp_config_path = WP_CLI\Utils\locate_wp_config(); $token = "/* That's all, stop editing!"; list( $before, $after ) = explode( $token, file_get_contents( $wp_config_path ) ); - file_put_contents( $wp_config_path, $before . $ms_config . $token . $after ); - - wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); - - WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + file_put_contents( $wp_config_path, $before . $content . $token . $after ); } private static function get_clean_basedomain() { From b5f2607e4470c671391f9168543df49a4211ad19 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:25:05 +0200 Subject: [PATCH 0938/5359] tests: tabs, not spaces --- tests/class-command-runner.php | 72 +++++++------- tests/class-wp-cli-test-case.php | 158 +++++++++++++++---------------- tests/core-Test.php | 90 +++++++++--------- 3 files changed, 160 insertions(+), 160 deletions(-) diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index f39b36007..f8f87b511 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -1,43 +1,43 @@ <?php class Command_Runner { - private $cwd; - - public function __construct( $cwd ) { - $this->cwd = $cwd; - } - - public function run_wp_cli( $wp_cli_command ) { - $wp_cli_path = self::find_wp_cli(); - return self::run_command( "$wp_cli_path $wp_cli_command" ); - } - - private function find_wp_cli() { - return getcwd() . "/src/bin/wp"; - } - - private function run_command( $command ) { - $output_dummy = array(); - $output_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); - $output_binary_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); - $return_code = 0; - $cwd = $this->cwd; - $sh_command = "cd $cwd;" . - "$command > $output_binary_file 2>&1;" . - 'RETURN_CODE=$?;' . - "cat -v $output_binary_file > $output_file;" . - 'exit $RETURN_CODE'; - exec("sh -c '$sh_command'", $output_dummy, $return_code ); - $output = file_get_contents( $output_file); - unlink( $output_file ); - unlink( $output_binary_file ); - return new Execution_Result( $return_code, $output ); - } + private $cwd; + + public function __construct( $cwd ) { + $this->cwd = $cwd; + } + + public function run_wp_cli( $wp_cli_command ) { + $wp_cli_path = self::find_wp_cli(); + return self::run_command( "$wp_cli_path $wp_cli_command" ); + } + + private function find_wp_cli() { + return getcwd() . "/src/bin/wp"; + } + + private function run_command( $command ) { + $output_dummy = array(); + $output_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); + $output_binary_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); + $return_code = 0; + $cwd = $this->cwd; + $sh_command = "cd $cwd;" . + "$command > $output_binary_file 2>&1;" . + 'RETURN_CODE=$?;' . + "cat -v $output_binary_file > $output_file;" . + 'exit $RETURN_CODE'; + exec("sh -c '$sh_command'", $output_dummy, $return_code ); + $output = file_get_contents( $output_file); + unlink( $output_file ); + unlink( $output_binary_file ); + return new Execution_Result( $return_code, $output ); + } } class Execution_Result { - public function __construct( $return_code, $output ) { - $this->return_code = $return_code; - $this->output = $output; - } + public function __construct( $return_code, $output ) { + $this->return_code = $return_code; + $this->output = $output; + } } diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 702bb5fe6..047d174b8 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -3,86 +3,86 @@ require_once __DIR__ . '/class-command-runner.php'; abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { - protected $database_settings = array( - "dbname" => "wp_cli_test", - "dbuser" => "wp_cli_test", - "dbpass" => "password1" - ); - - protected function setUp() { - $this->reset_database(); - } - - private function reset_database() { - $dbname = $this->database_settings["dbname"]; - $this->run_sql( "DROP DATABASE $dbname" ); - $this->run_sql( "CREATE DATABASE $dbname" ); - } - - private function run_sql( $sql ) { - $dbuser = $this->database_settings["dbuser"]; - $dbpass = $this->database_settings["dbpass"]; - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); - } - - public function install_wp_cli() { - $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $command_runner ); - $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->database_settings ); - $installer->run_install(); - return $command_runner; - } - - public function create_temporary_directory() { - $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $dir ); - return $dir; - } + protected $database_settings = array( + "dbname" => "wp_cli_test", + "dbuser" => "wp_cli_test", + "dbpass" => "password1" + ); + + protected function setUp() { + $this->reset_database(); + } + + private function reset_database() { + $dbname = $this->database_settings["dbname"]; + $this->run_sql( "DROP DATABASE $dbname" ); + $this->run_sql( "CREATE DATABASE $dbname" ); + } + + private function run_sql( $sql ) { + $dbuser = $this->database_settings["dbuser"]; + $dbpass = $this->database_settings["dbpass"]; + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + } + + public function install_wp_cli() { + $temp_dir = $this->create_temporary_directory(); + $command_runner = new Command_Runner( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $installer->download_wordpress_files( $temp_dir ); + $installer->create_config( $this->database_settings ); + $installer->run_install(); + return $command_runner; + } + + public function create_temporary_directory() { + $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $dir ); + return $dir; + } } class Wordpress_Installer { - private $install_dir; - private $command_runner; - - public function __construct( $install_dir, $command_runner ) { - $this->install_dir = $install_dir; - $this->command_runner = $command_runner; - } - - public function create_config( $database_settings ) { - $dbname = $database_settings["dbname"]; - $dbuser = $database_settings["dbuser"]; - $dbpass = $database_settings["dbpass"]; - $this->command_runner->run_wp_cli( - "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); - } - - public function run_install() { - $install_result = $this->command_runner->run_wp_cli( - "core install --url=http://example.com/ --title=WordPress " . - " --admin_email=admin@example.com --admin_password=password1" - ); - $this->assert_process_exited_successfully( $install_result ); - } - - public function download_wordpress_files() { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $command_runner = new Command_Runner( $cache_dir ); - $command_runner->run_wp_cli( "core download" ); - } - exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); - } - - private function assert_process_exited_successfully( $result ) { - if ( $result->return_code !== 0 ) { - $message = "return code was $result->return_code, output was: $result->output"; - throw new Exception( $message ); - } - } + private $install_dir; + private $command_runner; + + public function __construct( $install_dir, $command_runner ) { + $this->install_dir = $install_dir; + $this->command_runner = $command_runner; + } + + public function create_config( $database_settings ) { + $dbname = $database_settings["dbname"]; + $dbuser = $database_settings["dbuser"]; + $dbpass = $database_settings["dbpass"]; + $this->command_runner->run_wp_cli( + "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); + } + + public function run_install() { + $install_result = $this->command_runner->run_wp_cli( + "core install --url=http://example.com/ --title=WordPress " . + " --admin_email=admin@example.com --admin_password=password1" + ); + $this->assert_process_exited_successfully( $install_result ); + } + + public function download_wordpress_files() { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir( $cache_dir ); + $command_runner = new Command_Runner( $cache_dir ); + $command_runner->run_wp_cli( "core download" ); + } + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); + } + + private function assert_process_exited_successfully( $result ) { + if ( $result->return_code !== 0 ) { + $message = "return code was $result->return_code, output was: $result->output"; + throw new Exception( $message ); + } + } } diff --git a/tests/core-Test.php b/tests/core-Test.php index eb37feb0f..80fc7d22d 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -4,49 +4,49 @@ require_once __DIR__ . '/class-wp-cli-test-case.php'; class CoreTest extends Wp_Cli_Test_Case { - public function test_is_installed_exits_with_1_if_wordpress_not_installed() { - $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $result = $command_runner->run_wp_cli( "core is-installed" ); - $this->assertEquals(1, $result->return_code); - } - - public function test_is_installed_exits_with_0_after_running_install_command() { - $command_runner = $this->install_wp_cli(); - $result = $command_runner->run_wp_cli( "core is-installed" ); - $this->assertEquals(0, $result->return_code); - } - - public function test_install_command_creates_default_blog_post() { - $command_runner = $this->install_wp_cli(); - $result = $command_runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } - - public function test_message_explains_that_config_must_be_present_before_install() { - $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $command_runner ); - $installer->download_wordpress_files( $temp_dir ); - $result = $command_runner->run_wp_cli( "core install" ); - $this->assertEquals( - "^[[31;1mError: ^[[0mwp-config.php not found\n" . - "Either create one manually or use wp core config\n", - $result->output - ); - } - - public function test_wp_config_can_be_placed_in_parent_directory() { - $temp_dir = $this->create_temporary_directory(); - $install_dir = $temp_dir . '/www-root'; - mkdir( $install_dir ); - $command_runner = new Command_Runner( $install_dir ); - $installer = new Wordpress_Installer( $install_dir, $command_runner ); - $installer->download_wordpress_files( $install_dir ); - $installer->create_config( $this->database_settings ); - rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); - $installer->run_install(); - $result = $command_runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } + public function test_is_installed_exits_with_1_if_wordpress_not_installed() { + $temp_dir = $this->create_temporary_directory(); + $command_runner = new Command_Runner( $temp_dir ); + $result = $command_runner->run_wp_cli( "core is-installed" ); + $this->assertEquals(1, $result->return_code); + } + + public function test_is_installed_exits_with_0_after_running_install_command() { + $command_runner = $this->install_wp_cli(); + $result = $command_runner->run_wp_cli( "core is-installed" ); + $this->assertEquals(0, $result->return_code); + } + + public function test_install_command_creates_default_blog_post() { + $command_runner = $this->install_wp_cli(); + $result = $command_runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } + + public function test_message_explains_that_config_must_be_present_before_install() { + $temp_dir = $this->create_temporary_directory(); + $command_runner = new Command_Runner( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $installer->download_wordpress_files( $temp_dir ); + $result = $command_runner->run_wp_cli( "core install" ); + $this->assertEquals( + "^[[31;1mError: ^[[0mwp-config.php not found\n" . + "Either create one manually or use wp core config\n", + $result->output + ); + } + + public function test_wp_config_can_be_placed_in_parent_directory() { + $temp_dir = $this->create_temporary_directory(); + $install_dir = $temp_dir . '/www-root'; + mkdir( $install_dir ); + $command_runner = new Command_Runner( $install_dir ); + $installer = new Wordpress_Installer( $install_dir, $command_runner ); + $installer->download_wordpress_files( $install_dir ); + $installer->create_config( $this->database_settings ); + rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); + $installer->run_install(); + $result = $command_runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } } From d71972b39f3e5bc74da3f3499ccf815d1753936b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:28:12 +0200 Subject: [PATCH 0939/5359] remove compare-cmd utility. using PHP's version_compare() now --- utils/compare-cmd | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100755 utils/compare-cmd diff --git a/utils/compare-cmd b/utils/compare-cmd deleted file mode 100755 index 92a291b30..000000000 --- a/utils/compare-cmd +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ $# -lt 3 ]; then - echo 'usage: <version-a> <version-b> <wp-path>' - exit 1 -fi - -ver_a=$1 -ver_b=$2 -wp_path=$3 - -git checkout $ver_a -wp --path=$wp_path --syn-list > /tmp/wp-cli-a - -git checkout $ver_b -wp --path=$wp_path --syn-list > /tmp/wp-cli-b - -diff /tmp/wp-cli-a /tmp/wp-cli-b From 8e5cb553c7997b7d4f7e7219bf60d09cfb062ce0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:32:59 +0200 Subject: [PATCH 0940/5359] tests: coding standards --- tests/class-command-runner.php | 5 +++-- tests/core-Test.php | 31 ++++++++++++++++--------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index f8f87b511..7b6e9b30d 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -27,8 +27,8 @@ private function run_command( $command ) { 'RETURN_CODE=$?;' . "cat -v $output_binary_file > $output_file;" . 'exit $RETURN_CODE'; - exec("sh -c '$sh_command'", $output_dummy, $return_code ); - $output = file_get_contents( $output_file); + exec( "sh -c '$sh_command'", $output_dummy, $return_code ); + $output = file_get_contents( $output_file ); unlink( $output_file ); unlink( $output_binary_file ); return new Execution_Result( $return_code, $output ); @@ -36,6 +36,7 @@ private function run_command( $command ) { } class Execution_Result { + public function __construct( $return_code, $output ) { $this->return_code = $return_code; $this->output = $output; diff --git a/tests/core-Test.php b/tests/core-Test.php index 80fc7d22d..d268d5866 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -4,31 +4,32 @@ require_once __DIR__ . '/class-wp-cli-test-case.php'; class CoreTest extends Wp_Cli_Test_Case { - public function test_is_installed_exits_with_1_if_wordpress_not_installed() { + + public function test_is_installed_exits_with_1_if_empty_dir() { $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $result = $command_runner->run_wp_cli( "core is-installed" ); - $this->assertEquals(1, $result->return_code); + $runner = new Command_Runner( $temp_dir ); + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); } public function test_is_installed_exits_with_0_after_running_install_command() { - $command_runner = $this->install_wp_cli(); - $result = $command_runner->run_wp_cli( "core is-installed" ); - $this->assertEquals(0, $result->return_code); + $runner = $this->install_wp_cli(); + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 0, $result->return_code ); } public function test_install_command_creates_default_blog_post() { - $command_runner = $this->install_wp_cli(); - $result = $command_runner->run_wp_cli( "post list --ids" ); + $runner = $this->install_wp_cli(); + $result = $runner->run_wp_cli( "post list --ids" ); $this->assertEquals( "1", $result->output ); } public function test_message_explains_that_config_must_be_present_before_install() { $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $runner = new Command_Runner( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $runner ); $installer->download_wordpress_files( $temp_dir ); - $result = $command_runner->run_wp_cli( "core install" ); + $result = $runner->run_wp_cli( "core install" ); $this->assertEquals( "^[[31;1mError: ^[[0mwp-config.php not found\n" . "Either create one manually or use wp core config\n", @@ -40,13 +41,13 @@ public function test_wp_config_can_be_placed_in_parent_directory() { $temp_dir = $this->create_temporary_directory(); $install_dir = $temp_dir . '/www-root'; mkdir( $install_dir ); - $command_runner = new Command_Runner( $install_dir ); - $installer = new Wordpress_Installer( $install_dir, $command_runner ); + $runner = new Command_Runner( $install_dir ); + $installer = new Wordpress_Installer( $install_dir, $runner ); $installer->download_wordpress_files( $install_dir ); $installer->create_config( $this->database_settings ); rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); $installer->run_install(); - $result = $command_runner->run_wp_cli( "post list --ids" ); + $result = $runner->run_wp_cli( "post list --ids" ); $this->assertEquals( "1", $result->output ); } } From 86ebfcbe8be7f970f142404fa2fe0341c5539f92 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:36:58 +0200 Subject: [PATCH 0941/5359] fix test_message_explains_that_config_must_be_present_before_install() --- tests/core-Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index d268d5866..948cc820b 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -32,7 +32,7 @@ public function test_message_explains_that_config_must_be_present_before_install $result = $runner->run_wp_cli( "core install" ); $this->assertEquals( "^[[31;1mError: ^[[0mwp-config.php not found\n" . - "Either create one manually or use wp core config\n", + "Either create one manually or use `wp core config`.\n", $result->output ); } From 439d825c720e4b090f0b71d8cfb5d8c27ab2329c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:39:56 +0200 Subject: [PATCH 0942/5359] tests: rename install_wp_cli() to full_wp_install() --- tests/class-wp-cli-test-case.php | 2 +- tests/core-Test.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 047d174b8..63a42ed78 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -25,7 +25,7 @@ private function run_sql( $sql ) { exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); } - public function install_wp_cli() { + public function full_wp_install() { $temp_dir = $this->create_temporary_directory(); $command_runner = new Command_Runner( $temp_dir ); $installer = new Wordpress_Installer( $temp_dir, $command_runner ); diff --git a/tests/core-Test.php b/tests/core-Test.php index 948cc820b..1cbab37e4 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -13,13 +13,13 @@ public function test_is_installed_exits_with_1_if_empty_dir() { } public function test_is_installed_exits_with_0_after_running_install_command() { - $runner = $this->install_wp_cli(); + $runner = $this->full_wp_install(); $result = $runner->run_wp_cli( "core is-installed" ); $this->assertEquals( 0, $result->return_code ); } public function test_install_command_creates_default_blog_post() { - $runner = $this->install_wp_cli(); + $runner = $this->full_wp_install(); $result = $runner->run_wp_cli( "post list --ids" ); $this->assertEquals( "1", $result->output ); } From 9cb3bb54ca54be54701874543eed7dfb82c43184 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:43:48 +0200 Subject: [PATCH 0943/5359] rename command_runner to runner --- tests/class-wp-cli-test-case.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 63a42ed78..54831a266 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -27,12 +27,12 @@ private function run_sql( $sql ) { public function full_wp_install() { $temp_dir = $this->create_temporary_directory(); - $command_runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $command_runner ); + $runner = new Command_Runner( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $runner ); $installer->download_wordpress_files( $temp_dir ); $installer->create_config( $this->database_settings ); $installer->run_install(); - return $command_runner; + return $runner; } public function create_temporary_directory() { @@ -44,23 +44,23 @@ public function create_temporary_directory() { class Wordpress_Installer { private $install_dir; - private $command_runner; + private $runner; - public function __construct( $install_dir, $command_runner ) { + public function __construct( $install_dir, $runner ) { $this->install_dir = $install_dir; - $this->command_runner = $command_runner; + $this->runner = $runner; } public function create_config( $database_settings ) { $dbname = $database_settings["dbname"]; $dbuser = $database_settings["dbuser"]; $dbpass = $database_settings["dbpass"]; - $this->command_runner->run_wp_cli( + $this->runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); } public function run_install() { - $install_result = $this->command_runner->run_wp_cli( + $install_result = $this->runner->run_wp_cli( "core install --url=http://example.com/ --title=WordPress " . " --admin_email=admin@example.com --admin_password=password1" ); @@ -73,8 +73,8 @@ public function download_wordpress_files() { $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { mkdir( $cache_dir ); - $command_runner = new Command_Runner( $cache_dir ); - $command_runner->run_wp_cli( "core download" ); + $runner = new Command_Runner( $cache_dir ); + $runner->run_wp_cli( "core download" ); } exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } From 2ae0589c0c823f3105ae077d23e2cb732611b350 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:46:10 +0200 Subject: [PATCH 0944/5359] add more tests for core is-installed. see #232 --- tests/core-Test.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/core-Test.php b/tests/core-Test.php index 1cbab37e4..55d1050e9 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -12,6 +12,31 @@ public function test_is_installed_exits_with_1_if_empty_dir() { $this->assertEquals( 1, $result->return_code ); } + public function test_is_installed_exits_with_1_if_missing_wp_config() { + $temp_dir = $this->create_temporary_directory(); + + $runner = new Command_Runner( $temp_dir ); + + $installer = new Wordpress_Installer( $temp_dir, $runner ); + $installer->download_wordpress_files( $temp_dir ); + + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); + } + + public function test_is_installed_exits_with_1_if_db_not_installed() { + $temp_dir = $this->create_temporary_directory(); + + $runner = new Command_Runner( $temp_dir ); + + $installer = new Wordpress_Installer( $temp_dir, $runner ); + $installer->download_wordpress_files( $temp_dir ); + $installer->create_config( $this->database_settings ); + + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); + } + public function test_is_installed_exits_with_0_after_running_install_command() { $runner = $this->full_wp_install(); $result = $runner->run_wp_cli( "core is-installed" ); From 58cfbfcbd5540e42daefd4a47a3036a774958798 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 22:58:26 +0200 Subject: [PATCH 0945/5359] special handling for core is-installed. fixes #232 --- src/php/wp-cli/class-wp-cli.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 8da8b9f36..09b3bb130 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -274,14 +274,17 @@ static function before_wp_load() { exit; } - // Set installer flag before loading any WP files - if ( array( 'core', 'install' ) == self::$arguments ) { - define( 'WP_INSTALLING', true ); - + if ( 'core' == self::$arguments[0] && in_array( self::$arguments[1], array( 'install', 'is-installed' ) ) ) { if ( !Utils\locate_wp_config() ) { WP_CLI::error( "wp-config.php not found\n" . "Either create one manually or use `wp core config`." ); } + + define( 'WP_INSTALLING', true ); + + if ( !isset( $_SERVER['HTTP_HOST'] ) ) { + define( 'WP_SITEURL', 'http://example.com' ); + } } // Pretend we're in WP_ADMIN, to side-step full-page caching plugins From 115ff24885be2875338ffcc71a825d6a47158f4d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 23:17:00 +0200 Subject: [PATCH 0946/5359] introduce cmd_starts_with() helper --- src/php/wp-cli/class-wp-cli.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 09b3bb130..f6af74174 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -267,14 +267,16 @@ static function before_wp_load() { exit; } - // The db commands don't need any WP files - if ( array( 'db' ) == array_slice( self::$arguments, 0, 1 ) ) { + if ( self::cmd_starts_with( array( 'db' ) ) ) { Utils\load_wp_config(); self::run_command(); exit; } - if ( 'core' == self::$arguments[0] && in_array( self::$arguments[1], array( 'install', 'is-installed' ) ) ) { + if ( + self::cmd_starts_with( array( 'core', 'install' ) ) || + self::cmd_starts_with( array( 'core', 'is-installed' ) ) + ) { if ( !Utils\locate_wp_config() ) { WP_CLI::error( "wp-config.php not found\n" . "Either create one manually or use `wp core config`." ); @@ -292,6 +294,10 @@ static function before_wp_load() { $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } + private static function cmd_starts_with( $prefix ) { + return $prefix == array_slice( self::$arguments, 0, count( $prefix ) ); + } + static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); From 182e7ae099329e270773176c4eb91cc54d2e228a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 23:20:14 +0200 Subject: [PATCH 0947/5359] use Utils\set_url_params() in case WP_SITEURL is already defined. see #232 --- src/php/wp-cli/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index f6af74174..b330cd8f7 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -285,7 +285,7 @@ static function before_wp_load() { define( 'WP_INSTALLING', true ); if ( !isset( $_SERVER['HTTP_HOST'] ) ) { - define( 'WP_SITEURL', 'http://example.com' ); + Utils\set_url_params( 'http://example.com' ); } } From e830377c431cd68643e108bcd7cf1878e9943d6f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 23:32:57 +0200 Subject: [PATCH 0948/5359] WP_CLI::error() - replace unused $label parameter with $exit boolean --- src/php/wp-cli/class-wp-cli.php | 17 +++++++++++------ tests/core-Test.php | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index b330cd8f7..05994f184 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -62,14 +62,16 @@ static function line( $message = '' ) { * Display an error in the CLI and end with a newline * * @param string $message - * @param string $label + * @param bool $exit */ - static function error( $message, $label = 'Error' ) { + static function error( $message, $exit = true ) { if ( !isset( self::$assoc_special['completions'] ) ) { + $label = 'Error'; \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); } - exit(1); + if ( $exit ) + exit(1); } /** @@ -259,7 +261,9 @@ static function before_wp_load() { } if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { - WP_CLI::error( 'This does not seem to be a WordPress install. Pass --path=`path/to/wordpress` or run `wp core download`.' ); + WP_CLI::error( "This does not seem to be a WordPress install.", false ); + WP_CLI::line( "Pass --path=`path/to/wordpress` or run `wp core download`." ); + exit(1); } if ( array( 'core', 'config' ) == self::$arguments ) { @@ -278,8 +282,9 @@ static function before_wp_load() { self::cmd_starts_with( array( 'core', 'is-installed' ) ) ) { if ( !Utils\locate_wp_config() ) { - WP_CLI::error( "wp-config.php not found\n" . - "Either create one manually or use `wp core config`." ); + WP_CLI::error( "wp-config.php not found.", false ); + WP_CLI::line( "Either create one manually or use `wp core config`." ); + exit(1); } define( 'WP_INSTALLING', true ); diff --git a/tests/core-Test.php b/tests/core-Test.php index 55d1050e9..73eb8efcf 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -56,7 +56,7 @@ public function test_message_explains_that_config_must_be_present_before_install $installer->download_wordpress_files( $temp_dir ); $result = $runner->run_wp_cli( "core install" ); $this->assertEquals( - "^[[31;1mError: ^[[0mwp-config.php not found\n" . + "^[[31;1mError: ^[[0mwp-config.php not found.\n" . "Either create one manually or use `wp core config`.\n", $result->output ); From 4705b6167754b43c2b776337d2aced9b6e1cbc16 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Dec 2012 23:33:14 +0200 Subject: [PATCH 0949/5359] tests: s/database_settings/db_settings/g --- tests/class-wp-cli-test-case.php | 18 +++++++++--------- tests/core-Test.php | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 54831a266..578b49345 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -3,7 +3,7 @@ require_once __DIR__ . '/class-command-runner.php'; abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { - protected $database_settings = array( + protected $db_settings = array( "dbname" => "wp_cli_test", "dbuser" => "wp_cli_test", "dbpass" => "password1" @@ -14,14 +14,14 @@ protected function setUp() { } private function reset_database() { - $dbname = $this->database_settings["dbname"]; + $dbname = $this->db_settings["dbname"]; $this->run_sql( "DROP DATABASE $dbname" ); $this->run_sql( "CREATE DATABASE $dbname" ); } private function run_sql( $sql ) { - $dbuser = $this->database_settings["dbuser"]; - $dbpass = $this->database_settings["dbpass"]; + $dbuser = $this->db_settings["dbuser"]; + $dbpass = $this->db_settings["dbpass"]; exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); } @@ -30,7 +30,7 @@ public function full_wp_install() { $runner = new Command_Runner( $temp_dir ); $installer = new Wordpress_Installer( $temp_dir, $runner ); $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->database_settings ); + $installer->create_config( $this->db_settings ); $installer->run_install(); return $runner; } @@ -51,10 +51,10 @@ public function __construct( $install_dir, $runner ) { $this->runner = $runner; } - public function create_config( $database_settings ) { - $dbname = $database_settings["dbname"]; - $dbuser = $database_settings["dbuser"]; - $dbpass = $database_settings["dbpass"]; + public function create_config( $db_settings ) { + $dbname = $db_settings["dbname"]; + $dbuser = $db_settings["dbuser"]; + $dbpass = $db_settings["dbpass"]; $this->runner->run_wp_cli( "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); } diff --git a/tests/core-Test.php b/tests/core-Test.php index 73eb8efcf..20ba5bc89 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -31,7 +31,7 @@ public function test_is_installed_exits_with_1_if_db_not_installed() { $installer = new Wordpress_Installer( $temp_dir, $runner ); $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->database_settings ); + $installer->create_config( $this->db_settings ); $result = $runner->run_wp_cli( "core is-installed" ); $this->assertEquals( 1, $result->return_code ); @@ -69,7 +69,7 @@ public function test_wp_config_can_be_placed_in_parent_directory() { $runner = new Command_Runner( $install_dir ); $installer = new Wordpress_Installer( $install_dir, $runner ); $installer->download_wordpress_files( $install_dir ); - $installer->create_config( $this->database_settings ); + $installer->create_config( $this->db_settings ); rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); $installer->run_install(); $result = $runner->run_wp_cli( "post list --ids" ); From 8415c828af419fed6411f84736c192dc9a359dd4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 17 Dec 2012 00:02:06 +0200 Subject: [PATCH 0950/5359] Re-add compare-cmd utility, with description. This reverts commit d71972b39f3e5bc74da3f3499ccf815d1753936b. --- utils/compare-cmd | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 utils/compare-cmd diff --git a/utils/compare-cmd b/utils/compare-cmd new file mode 100755 index 000000000..21f6bc9b5 --- /dev/null +++ b/utils/compare-cmd @@ -0,0 +1,22 @@ +#!/bin/bash + +# utility for comparing commands between two different wp-cli versions. + +if [ $# -lt 3 ]; then + echo 'usage: <version-a> <version-b> <wp-path>' + exit 1 +fi + +ver_a=$1 +ver_b=$2 +wp_path=$3 + +git checkout $ver_a +wp --path=$wp_path --syn-list > /tmp/wp-cli-a + +git checkout $ver_b +wp --path=$wp_path --syn-list > /tmp/wp-cli-b + +diff /tmp/wp-cli-a /tmp/wp-cli-b > cmd.diff + +echo 'Generated cmd.diff' From eb84c54ccf22b0f295bb825553d578d5d8e9ab10 Mon Sep 17 00:00:00 2001 From: Jaime Martinez <jmslbam@gmail.com> Date: Fri, 21 Dec 2012 17:54:16 +0100 Subject: [PATCH 0951/5359] Update src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php Added %1\$s to href attribute so the do open to the permalink. And a new window --- .../internals/skeletons/post_type_skeleton.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 613518b33..d3c5e7dfc 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -46,21 +46,21 @@ function {$machine_name}_updated_messages( \$messages ) { \$messages['{$post_type}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%1\$s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), 2 => __('Custom field updated.', '{$textdomain}'), 3 => __('Custom field deleted.', '{$textdomain}'), 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), /* translators: %s: date and time of the revision */ 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%1\$s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%1\$s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$textdomain}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%1\$s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), ); return \$messages; } -add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file +add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; From 6466bcadbf2e6050a897aa3758ab32b95e8a65f3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Dec 2012 10:09:19 +0200 Subject: [PATCH 0952/5359] check wp-config.php before running most commands. fixes #246 --- src/php/wp-cli/class-wp-cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 05994f184..314470aca 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -271,6 +271,12 @@ static function before_wp_load() { exit; } + if ( !Utils\locate_wp_config() ) { + WP_CLI::error( "wp-config.php not found.", false ); + WP_CLI::line( "Either create one manually or use `wp core config`." ); + exit(1); + } + if ( self::cmd_starts_with( array( 'db' ) ) ) { Utils\load_wp_config(); self::run_command(); @@ -281,12 +287,6 @@ static function before_wp_load() { self::cmd_starts_with( array( 'core', 'install' ) ) || self::cmd_starts_with( array( 'core', 'is-installed' ) ) ) { - if ( !Utils\locate_wp_config() ) { - WP_CLI::error( "wp-config.php not found.", false ); - WP_CLI::line( "Either create one manually or use `wp core config`." ); - exit(1); - } - define( 'WP_INSTALLING', true ); if ( !isset( $_SERVER['HTTP_HOST'] ) ) { From bb38c23f8a54d9df63fd1ab78ae4975c06f72ac7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Dec 2012 14:23:06 +0200 Subject: [PATCH 0953/5359] remove community commands --- .../commands/community/google-sitemap.php | 23 ---- .../wp-cli/commands/community/super-cache.php | 103 ------------------ .../wp-cli/commands/community/total-cache.php | 102 ----------------- 3 files changed, 228 deletions(-) delete mode 100644 src/php/wp-cli/commands/community/google-sitemap.php delete mode 100644 src/php/wp-cli/commands/community/super-cache.php delete mode 100644 src/php/wp-cli/commands/community/total-cache.php diff --git a/src/php/wp-cli/commands/community/google-sitemap.php b/src/php/wp-cli/commands/community/google-sitemap.php deleted file mode 100644 index 37bbe53c1..000000000 --- a/src/php/wp-cli/commands/community/google-sitemap.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -if( class_exists( 'GoogleSitemapGeneratorLoader' ) ) { - WP_CLI::add_command( 'google-sitemap', 'GoogleSitemapGenerator_Command' ); -} - -/** - * Manage the Google XML Sitemap plugin - * - * @package wp-cli - * @subpackage commands/community - */ -class GoogleSitemapGenerator_Command extends WP_CLI_Command { - - /** - * Re-generate the sitemap - */ - function rebuild() { - do_action( 'sm_rebuild' ); - - WP_CLI::success( 'Sitemap rebuilt.' ); - } -} diff --git a/src/php/wp-cli/commands/community/super-cache.php b/src/php/wp-cli/commands/community/super-cache.php deleted file mode 100644 index 5e54f3392..000000000 --- a/src/php/wp-cli/commands/community/super-cache.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php - -if ( function_exists( 'wp_super_cache_enable' ) ) { - WP_CLI::add_command( 'super-cache', 'WPSuperCache_Command' ); -} - -/** - * The WP Super Cache plugin - * - * @package wp-cli - * @subpackage commands/community - */ -class WPSuperCache_Command extends WP_CLI_Command { - - /** - * Clear something from the cache. - * - * @synopsis [--post_id=<post-id>] [--permalink=<permalink>] - */ - function flush( $args = array(), $assoc_args = array() ) { - if ( isset($assoc_args['post_id']) ) { - if ( is_numeric( $assoc_args['post_id'] ) ) { - wp_cache_post_change( $assoc_args['post_id'] ); - } else { - WP_CLI::error('This is not a valid post id.'); - } - - wp_cache_post_change( $assoc_args['post_id'] ); - } - elseif ( isset( $assoc_args['permalink'] ) ) { - $id = url_to_postid( $assoc_args['permalink'] ); - - if ( is_numeric( $id ) ) { - wp_cache_post_change( $id ); - } else { - WP_CLI::error('There is no post with this permalink.'); - } - } else { - global $file_prefix; - - wp_cache_clean_cache( $file_prefix, true ); - - WP_CLI::success( 'Cache cleared.' ); - } - } - - /** - * Get the status of the cache. - */ - function status( $args = array(), $assoc_args = array() ) { - $cache_stats = get_option( 'supercache_stats' ); - - if ( !empty( $cache_stats ) ) { - if ( $cache_stats['generated'] > time() - 3600 * 24 ) { - global $super_cache_enabled; - WP_CLI::line( 'Cache status: ' . ($super_cache_enabled ? '%gOn%n' : '%rOff%n') ); - WP_CLI::line( 'Cache content on ' . date('r', $cache_stats['generated'] ) . ': ' ); - WP_CLI::line(); - WP_CLI::line( ' WordPress cache:' ); - WP_CLI::line( ' Cached: ' . $cache_stats[ 'wpcache' ][ 'cached' ] ); - WP_CLI::line( ' Expired: ' . $cache_stats[ 'wpcache' ][ 'expired' ] ); - WP_CLI::line(); - WP_CLI::line( ' WP Super Cache:' ); - WP_CLI::line( ' Cached: ' . $cache_stats[ 'supercache' ][ 'cached' ] ); - WP_CLI::line( ' Expired: ' . $cache_stats[ 'supercache' ][ 'expired' ] ); - } else { - WP_CLI::error('The WP Super Cache stats are too old to work with (older than 24 hours).'); - } - } else { - WP_CLI::error('No WP Super Cache stats found.'); - } - } - - /** - * Enable the WP Super Cache. - */ - function enable( $args = array(), $assoc_args = array() ) { - global $super_cache_enabled; - - wp_super_cache_enable(); - - if($super_cache_enabled) { - WP_CLI::success( 'The WP Super Cache is enabled.' ); - } else { - WP_CLI::error('The WP Super Cache is not enabled, check its settings page for more info.'); - } - } - - /** - * Disable the WP Super Cache. - */ - function disable( $args = array(), $assoc_args = array() ) { - global $super_cache_enabled; - - wp_super_cache_disable(); - - if(!$super_cache_enabled) { - WP_CLI::success( 'The WP Super Cache is disabled.' ); - } else { - WP_CLI::error('The WP Super Cache is still enabled, check its settings page for more info.'); - } - } -} diff --git a/src/php/wp-cli/commands/community/total-cache.php b/src/php/wp-cli/commands/community/total-cache.php deleted file mode 100644 index 5bfd11162..000000000 --- a/src/php/wp-cli/commands/community/total-cache.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -if ( function_exists( 'w3tc_pgcache_flush' ) ) { - WP_CLI::add_command( 'total-cache', 'W3TotalCache_Command' ); -} - -/** - * The W3 Total Cache plugin - * - * @package wp-cli - * @subpackage commands/community - */ -class W3TotalCache_Command extends WP_CLI_Command { - - /** - * Clear something from the cache. - * - * @synopsis <cache-type>... [--post_id=<post-id>] [--permalink=<permalink>] - */ - function flush( $args = array(), $assoc_args = array() ) { - $args = array_unique( $args ); - do { - $cache_type = array_shift( $args ); - - switch( $cache_type ) { - case 'db': - case 'database': - if ( w3tc_dbcache_flush() ) { - WP_CLI::success( 'The database cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the database cache failed.' ); - } - break; - - case 'minify': - if ( w3tc_minify_flush() ) { - WP_CLI::success( 'The minify cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the minify cache failed.' ); - } - break; - - case 'object': - if ( w3tc_objectcache_flush() ) { - WP_CLI::success( 'The object cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the object cache failed.' ); - } - break; - - case 'page': - if ( w3tc_pgcache_flush() ) { - WP_CLI::success( 'The page cache is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing the page cache failed.' ); - } - break; - - case 'post': - default: - if ( isset($assoc_args['post_id']) ) { - if ( is_numeric( $assoc_args['post_id'] ) && get_post( $assoc_args['post_id'] ) ) { - if ( w3tc_pgcache_flush_post( $assoc_args['post_id'] ) ) { - WP_CLI::success( 'Post '.$assoc_args['post_id'].' is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing '.$assoc_args['post_id'].' from cache failed.' ); - } - } else { - WP_CLI::error('This is not a valid post id.'); - } - } - elseif ( isset( $assoc_args['permalink'] ) ) { - $id = url_to_postid( $assoc_args['permalink'] ); - - if ( is_numeric( $id ) && $id > 0 ) { - if ( w3tc_pgcache_flush_post( $id ) ) { - WP_CLI::success( $id.' is flushed successfully.' ); - } else { - WP_CLI::error( 'Flushing '.$id.' from cache failed.' ); - } - } else { - WP_CLI::error('There is no post with this permalink.'); - } - } - } - } while ( !empty( $args ) ); - } - - /** - * Help function for this command - */ - public static function help() { - WP_CLI::line( <<<EOB -Available sub-commands: - flush - <cache-type> post|database|minify|object|page - --post_id=<id> flush post cache with specific ID - --permalink=<post-permalink> flush post cache with specific permalink -EOB - ); - } -} From 7bf6a7c66a09cfd546fc6840b6596382d7f2ad80 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Dec 2012 14:21:47 +0200 Subject: [PATCH 0954/5359] make dispatcher look in /commands/ folder, instead of subfolders --- src/php/wp-cli/dispatcher.php | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/php/wp-cli/dispatcher.php b/src/php/wp-cli/dispatcher.php index c56c490a4..6077a49c8 100644 --- a/src/php/wp-cli/dispatcher.php +++ b/src/php/wp-cli/dispatcher.php @@ -160,27 +160,22 @@ function get_subcommands() { } protected function load_all_commands() { - foreach ( array( 'internals', 'community' ) as $dir ) { - foreach ( glob( WP_CLI_ROOT . "/commands/$dir/*.php" ) as $filename ) { - $command = substr( basename( $filename ), 0, -4 ); + foreach ( glob( WP_CLI_ROOT . "/commands/*.php" ) as $filename ) { + $command = substr( basename( $filename ), 0, -4 ); - if ( isset( $this->subcommands[ $command ] ) ) - continue; + if ( isset( $this->subcommands[ $command ] ) ) + continue; - include $filename; - } + include $filename; } } function load_command( $command ) { if ( !isset( $this->subcommands[$command] ) ) { - foreach ( array( 'internals', 'community' ) as $dir ) { - $path = WP_CLI_ROOT . "/commands/$dir/$command.php"; + $path = WP_CLI_ROOT . "/commands/$command.php"; - if ( is_readable( $path ) ) { - include $path; - break; - } + if ( is_readable( $path ) ) { + include $path; } } From e1c5de41ee5d78fb816f3716ed4d06aa74ce5ee7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Dec 2012 14:24:58 +0200 Subject: [PATCH 0955/5359] move internal commands to /commands/ folder --- src/php/wp-cli/commands/{internals => }/blog.php | 0 src/php/wp-cli/commands/{internals => }/cache.php | 0 src/php/wp-cli/commands/{internals => }/cap.php | 0 src/php/wp-cli/commands/{internals => }/comment.php | 0 src/php/wp-cli/commands/{internals => }/core.php | 0 src/php/wp-cli/commands/{internals => }/db.php | 0 src/php/wp-cli/commands/{internals => }/eval-file.php | 0 src/php/wp-cli/commands/{internals => }/eval.php | 0 src/php/wp-cli/commands/{internals => }/export.php | 0 src/php/wp-cli/commands/{internals => }/help.php | 0 src/php/wp-cli/commands/{internals => }/home.php | 0 src/php/wp-cli/commands/{internals => }/option.php | 0 src/php/wp-cli/commands/{internals => }/plugin.php | 0 src/php/wp-cli/commands/{internals => }/post-meta.php | 0 src/php/wp-cli/commands/{internals => }/post.php | 0 src/php/wp-cli/commands/{internals => }/rewrite.php | 0 src/php/wp-cli/commands/{internals => }/shell.php | 0 src/php/wp-cli/commands/{internals => }/theme.php | 0 src/php/wp-cli/commands/{internals => }/transient.php | 0 src/php/wp-cli/commands/{internals => }/user-meta.php | 0 src/php/wp-cli/commands/{internals => }/user.php | 0 21 files changed, 0 insertions(+), 0 deletions(-) rename src/php/wp-cli/commands/{internals => }/blog.php (100%) rename src/php/wp-cli/commands/{internals => }/cache.php (100%) rename src/php/wp-cli/commands/{internals => }/cap.php (100%) rename src/php/wp-cli/commands/{internals => }/comment.php (100%) rename src/php/wp-cli/commands/{internals => }/core.php (100%) rename src/php/wp-cli/commands/{internals => }/db.php (100%) rename src/php/wp-cli/commands/{internals => }/eval-file.php (100%) rename src/php/wp-cli/commands/{internals => }/eval.php (100%) rename src/php/wp-cli/commands/{internals => }/export.php (100%) rename src/php/wp-cli/commands/{internals => }/help.php (100%) rename src/php/wp-cli/commands/{internals => }/home.php (100%) rename src/php/wp-cli/commands/{internals => }/option.php (100%) rename src/php/wp-cli/commands/{internals => }/plugin.php (100%) rename src/php/wp-cli/commands/{internals => }/post-meta.php (100%) rename src/php/wp-cli/commands/{internals => }/post.php (100%) rename src/php/wp-cli/commands/{internals => }/rewrite.php (100%) rename src/php/wp-cli/commands/{internals => }/shell.php (100%) rename src/php/wp-cli/commands/{internals => }/theme.php (100%) rename src/php/wp-cli/commands/{internals => }/transient.php (100%) rename src/php/wp-cli/commands/{internals => }/user-meta.php (100%) rename src/php/wp-cli/commands/{internals => }/user.php (100%) diff --git a/src/php/wp-cli/commands/internals/blog.php b/src/php/wp-cli/commands/blog.php similarity index 100% rename from src/php/wp-cli/commands/internals/blog.php rename to src/php/wp-cli/commands/blog.php diff --git a/src/php/wp-cli/commands/internals/cache.php b/src/php/wp-cli/commands/cache.php similarity index 100% rename from src/php/wp-cli/commands/internals/cache.php rename to src/php/wp-cli/commands/cache.php diff --git a/src/php/wp-cli/commands/internals/cap.php b/src/php/wp-cli/commands/cap.php similarity index 100% rename from src/php/wp-cli/commands/internals/cap.php rename to src/php/wp-cli/commands/cap.php diff --git a/src/php/wp-cli/commands/internals/comment.php b/src/php/wp-cli/commands/comment.php similarity index 100% rename from src/php/wp-cli/commands/internals/comment.php rename to src/php/wp-cli/commands/comment.php diff --git a/src/php/wp-cli/commands/internals/core.php b/src/php/wp-cli/commands/core.php similarity index 100% rename from src/php/wp-cli/commands/internals/core.php rename to src/php/wp-cli/commands/core.php diff --git a/src/php/wp-cli/commands/internals/db.php b/src/php/wp-cli/commands/db.php similarity index 100% rename from src/php/wp-cli/commands/internals/db.php rename to src/php/wp-cli/commands/db.php diff --git a/src/php/wp-cli/commands/internals/eval-file.php b/src/php/wp-cli/commands/eval-file.php similarity index 100% rename from src/php/wp-cli/commands/internals/eval-file.php rename to src/php/wp-cli/commands/eval-file.php diff --git a/src/php/wp-cli/commands/internals/eval.php b/src/php/wp-cli/commands/eval.php similarity index 100% rename from src/php/wp-cli/commands/internals/eval.php rename to src/php/wp-cli/commands/eval.php diff --git a/src/php/wp-cli/commands/internals/export.php b/src/php/wp-cli/commands/export.php similarity index 100% rename from src/php/wp-cli/commands/internals/export.php rename to src/php/wp-cli/commands/export.php diff --git a/src/php/wp-cli/commands/internals/help.php b/src/php/wp-cli/commands/help.php similarity index 100% rename from src/php/wp-cli/commands/internals/help.php rename to src/php/wp-cli/commands/help.php diff --git a/src/php/wp-cli/commands/internals/home.php b/src/php/wp-cli/commands/home.php similarity index 100% rename from src/php/wp-cli/commands/internals/home.php rename to src/php/wp-cli/commands/home.php diff --git a/src/php/wp-cli/commands/internals/option.php b/src/php/wp-cli/commands/option.php similarity index 100% rename from src/php/wp-cli/commands/internals/option.php rename to src/php/wp-cli/commands/option.php diff --git a/src/php/wp-cli/commands/internals/plugin.php b/src/php/wp-cli/commands/plugin.php similarity index 100% rename from src/php/wp-cli/commands/internals/plugin.php rename to src/php/wp-cli/commands/plugin.php diff --git a/src/php/wp-cli/commands/internals/post-meta.php b/src/php/wp-cli/commands/post-meta.php similarity index 100% rename from src/php/wp-cli/commands/internals/post-meta.php rename to src/php/wp-cli/commands/post-meta.php diff --git a/src/php/wp-cli/commands/internals/post.php b/src/php/wp-cli/commands/post.php similarity index 100% rename from src/php/wp-cli/commands/internals/post.php rename to src/php/wp-cli/commands/post.php diff --git a/src/php/wp-cli/commands/internals/rewrite.php b/src/php/wp-cli/commands/rewrite.php similarity index 100% rename from src/php/wp-cli/commands/internals/rewrite.php rename to src/php/wp-cli/commands/rewrite.php diff --git a/src/php/wp-cli/commands/internals/shell.php b/src/php/wp-cli/commands/shell.php similarity index 100% rename from src/php/wp-cli/commands/internals/shell.php rename to src/php/wp-cli/commands/shell.php diff --git a/src/php/wp-cli/commands/internals/theme.php b/src/php/wp-cli/commands/theme.php similarity index 100% rename from src/php/wp-cli/commands/internals/theme.php rename to src/php/wp-cli/commands/theme.php diff --git a/src/php/wp-cli/commands/internals/transient.php b/src/php/wp-cli/commands/transient.php similarity index 100% rename from src/php/wp-cli/commands/internals/transient.php rename to src/php/wp-cli/commands/transient.php diff --git a/src/php/wp-cli/commands/internals/user-meta.php b/src/php/wp-cli/commands/user-meta.php similarity index 100% rename from src/php/wp-cli/commands/internals/user-meta.php rename to src/php/wp-cli/commands/user-meta.php diff --git a/src/php/wp-cli/commands/internals/user.php b/src/php/wp-cli/commands/user.php similarity index 100% rename from src/php/wp-cli/commands/internals/user.php rename to src/php/wp-cli/commands/user.php From a400beeaf550fd870c4b08aa2635b75195f566e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Dec 2012 14:51:03 +0200 Subject: [PATCH 0956/5359] disable colors if output is not a TTY --- src/php/wp-cli/class-wp-cli.php | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/php/wp-cli/class-wp-cli.php b/src/php/wp-cli/class-wp-cli.php index 314470aca..176066587 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/src/php/wp-cli/class-wp-cli.php @@ -43,9 +43,11 @@ static function get_man_dirs() { * * @param string $message */ - static function out( $message ) { - if ( WP_CLI_QUIET ) return; - \cli\out($message); + static function out( $message, $handle = STDOUT ) { + if ( WP_CLI_QUIET ) + return; + + fwrite( $handle, \cli\Colors::colorize( $message, ! \cli\Shell::isPiped() ) ); } /** @@ -54,8 +56,7 @@ static function out( $message ) { * @param string $message */ static function line( $message = '' ) { - if ( WP_CLI_QUIET ) return; - \cli\line($message); + self::out( $message . "\n" ); } /** @@ -67,7 +68,8 @@ static function line( $message = '' ) { static function error( $message, $exit = true ) { if ( !isset( self::$assoc_special['completions'] ) ) { $label = 'Error'; - \cli\err( '%R' . $label . ': %n' . self::error_to_string( $message ) ); + $msg = '%R' . $label . ': %n' . self::error_to_string( $message ); + self::out( $msg . "\n", STDERR ); } if ( $exit ) @@ -81,8 +83,10 @@ static function error( $message, $exit = true ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - if ( WP_CLI_QUIET ) return; - \cli\line( '%G' . $label . ': %n' . $message ); + if ( WP_CLI_QUIET ) + return; + + self::line( '%G' . $label . ': %n' . $message ); } /** @@ -92,8 +96,11 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - if ( WP_CLI_QUIET ) return; - \cli\err( '%C' . $label . ': %n' . self::error_to_string( $message ) ); + if ( WP_CLI_QUIET ) + return; + + $msg = '%C' . $label . ': %n' . self::error_to_string( $message ); + self::out( $msg . "\n", STDERR ); } /** @@ -101,7 +108,7 @@ static function warning( $message, $label = 'Warning' ) { */ static function confirm( $question, $assoc_args ) { if ( !isset( $assoc_args['yes'] ) ) { - WP_CLI::out( $question . " [y/n] " ); + self::out( $question . " [y/n] " ); $answer = trim( fgets( STDIN ) ); From 3c854d0d54c8d6d0cb1bd53ad40e729035cef5e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Dec 2012 10:56:00 +0200 Subject: [PATCH 0957/5359] move everything from src/ into the top level --- .gitmodules | 4 ++-- {src/bin => bin}/wp | 0 composer.json | 2 +- {src/docs => man-src}/blog-create.txt | 0 {src/docs => man-src}/blog-delete.txt | 0 {src/docs => man-src}/cache.txt | 0 {src/docs => man-src}/cap.txt | 0 {src/docs => man-src}/comment-approve.txt | 0 {src/docs => man-src}/comment-count.txt | 0 {src/docs => man-src}/comment-create.txt | 0 {src/docs => man-src}/comment-delete.txt | 0 {src/docs => man-src}/comment-last.txt | 0 {src/docs => man-src}/comment-spam.txt | 0 {src/docs => man-src}/comment-status.txt | 0 {src/docs => man-src}/comment-trash.txt | 0 {src/docs => man-src}/comment-unapprove.txt | 0 {src/docs => man-src}/comment-unspam.txt | 0 {src/docs => man-src}/comment-untrash.txt | 0 {src/docs => man-src}/core-config.txt | 0 {src/docs => man-src}/core-download.txt | 0 {src/docs => man-src}/core-install-network.txt | 0 {src/docs => man-src}/core-install.txt | 0 {src/docs => man-src}/core-is-installed.txt | 0 {src/docs => man-src}/core-update.txt | 0 {src/docs => man-src}/core-version.txt | 0 {src/docs => man-src}/db.txt | 0 {src/docs => man-src}/eval-file.txt | 0 {src/docs => man-src}/eval.txt | 0 {src/docs => man-src}/export.txt | 0 {src/docs => man-src}/option.txt | 0 {src/docs => man-src}/plugin-activate.txt | 0 {src/docs => man-src}/plugin-deactivate.txt | 0 {src/docs => man-src}/plugin-delete.txt | 0 {src/docs => man-src}/plugin-install.txt | 0 {src/docs => man-src}/plugin-path.txt | 0 {src/docs => man-src}/plugin-status.txt | 0 {src/docs => man-src}/plugin-toggle.txt | 0 {src/docs => man-src}/plugin-uninstall.txt | 0 {src/docs => man-src}/plugin-update-all.txt | 0 {src/docs => man-src}/plugin-update.txt | 0 {src/docs => man-src}/post-create.txt | 0 {src/docs => man-src}/post-delete.txt | 0 {src/docs => man-src}/post-generate.txt | 0 {src/docs => man-src}/post-list.txt | 0 {src/docs => man-src}/post-meta.txt | 0 {src/docs => man-src}/post-update.txt | 0 {src/docs => man-src}/rewrite-dump.txt | 0 {src/docs => man-src}/rewrite-flush.txt | 0 {src/docs => man-src}/rewrite-structure.txt | 0 {src/docs => man-src}/theme-activate.txt | 0 {src/docs => man-src}/theme-delete.txt | 0 {src/docs => man-src}/theme-install.txt | 0 {src/docs => man-src}/theme-path.txt | 0 {src/docs => man-src}/theme-status.txt | 0 {src/docs => man-src}/theme-update-all.txt | 0 {src/docs => man-src}/theme-update.txt | 0 {src/docs => man-src}/transient.txt | 0 {src/docs => man-src}/user-create.txt | 0 {src/docs => man-src}/user-delete.txt | 0 {src/docs => man-src}/user-generate.txt | 0 {src/docs => man-src}/user-import-csv.txt | 0 {src/docs => man-src}/user-list.txt | 0 {src/docs => man-src}/user-meta.txt | 0 {src/docs => man-src}/user-remove-role.txt | 0 {src/docs => man-src}/user-set-role.txt | 0 {src/docs => man-src}/user-update.txt | 0 php/php-cli-tools | 1 + {src/php => php}/wp-cli/class-cli-upgrader-skin.php | 0 {src/php => php}/wp-cli/class-wp-cli-command-with-meta.php | 0 .../wp-cli/class-wp-cli-command-with-upgrade.php | 0 {src/php => php}/wp-cli/class-wp-cli-command.php | 0 {src/php => php}/wp-cli/class-wp-cli.php | 4 ++-- {src/php => php}/wp-cli/commands/blog.php | 0 {src/php => php}/wp-cli/commands/cache.php | 0 {src/php => php}/wp-cli/commands/cap.php | 0 {src/php => php}/wp-cli/commands/comment.php | 0 {src/php => php}/wp-cli/commands/core.php | 0 {src/php => php}/wp-cli/commands/db.php | 0 {src/php => php}/wp-cli/commands/eval-file.php | 0 {src/php => php}/wp-cli/commands/eval.php | 0 {src/php => php}/wp-cli/commands/export.php | 0 {src/php => php}/wp-cli/commands/help.php | 0 {src/php => php}/wp-cli/commands/home.php | 0 {src/php => php}/wp-cli/commands/option.php | 0 {src/php => php}/wp-cli/commands/plugin.php | 0 {src/php => php}/wp-cli/commands/post-meta.php | 0 {src/php => php}/wp-cli/commands/post.php | 0 {src/php => php}/wp-cli/commands/rewrite.php | 0 {src/php => php}/wp-cli/commands/shell.php | 0 {src/php => php}/wp-cli/commands/theme.php | 0 {src/php => php}/wp-cli/commands/transient.php | 0 {src/php => php}/wp-cli/commands/user-meta.php | 0 {src/php => php}/wp-cli/commands/user.php | 0 {src/php => php}/wp-cli/dispatcher.php | 0 {src/php => php}/wp-cli/man.php | 0 {src/php => php}/wp-cli/utils.php | 4 ++-- {src/php => php}/wp-cli/wp-cli-boot.php | 0 {src/php => php}/wp-cli/wp-cli.php | 0 {src/php => php}/wp-cli/wp-settings.php | 0 src/php/php-cli-tools | 1 - tests/class-command-runner.php | 2 +- utils/dev-build | 2 +- utils/local-build | 2 +- utils/pear-build | 6 ++---- 104 files changed, 13 insertions(+), 15 deletions(-) rename {src/bin => bin}/wp (100%) rename {src/docs => man-src}/blog-create.txt (100%) rename {src/docs => man-src}/blog-delete.txt (100%) rename {src/docs => man-src}/cache.txt (100%) rename {src/docs => man-src}/cap.txt (100%) rename {src/docs => man-src}/comment-approve.txt (100%) rename {src/docs => man-src}/comment-count.txt (100%) rename {src/docs => man-src}/comment-create.txt (100%) rename {src/docs => man-src}/comment-delete.txt (100%) rename {src/docs => man-src}/comment-last.txt (100%) rename {src/docs => man-src}/comment-spam.txt (100%) rename {src/docs => man-src}/comment-status.txt (100%) rename {src/docs => man-src}/comment-trash.txt (100%) rename {src/docs => man-src}/comment-unapprove.txt (100%) rename {src/docs => man-src}/comment-unspam.txt (100%) rename {src/docs => man-src}/comment-untrash.txt (100%) rename {src/docs => man-src}/core-config.txt (100%) rename {src/docs => man-src}/core-download.txt (100%) rename {src/docs => man-src}/core-install-network.txt (100%) rename {src/docs => man-src}/core-install.txt (100%) rename {src/docs => man-src}/core-is-installed.txt (100%) rename {src/docs => man-src}/core-update.txt (100%) rename {src/docs => man-src}/core-version.txt (100%) rename {src/docs => man-src}/db.txt (100%) rename {src/docs => man-src}/eval-file.txt (100%) rename {src/docs => man-src}/eval.txt (100%) rename {src/docs => man-src}/export.txt (100%) rename {src/docs => man-src}/option.txt (100%) rename {src/docs => man-src}/plugin-activate.txt (100%) rename {src/docs => man-src}/plugin-deactivate.txt (100%) rename {src/docs => man-src}/plugin-delete.txt (100%) rename {src/docs => man-src}/plugin-install.txt (100%) rename {src/docs => man-src}/plugin-path.txt (100%) rename {src/docs => man-src}/plugin-status.txt (100%) rename {src/docs => man-src}/plugin-toggle.txt (100%) rename {src/docs => man-src}/plugin-uninstall.txt (100%) rename {src/docs => man-src}/plugin-update-all.txt (100%) rename {src/docs => man-src}/plugin-update.txt (100%) rename {src/docs => man-src}/post-create.txt (100%) rename {src/docs => man-src}/post-delete.txt (100%) rename {src/docs => man-src}/post-generate.txt (100%) rename {src/docs => man-src}/post-list.txt (100%) rename {src/docs => man-src}/post-meta.txt (100%) rename {src/docs => man-src}/post-update.txt (100%) rename {src/docs => man-src}/rewrite-dump.txt (100%) rename {src/docs => man-src}/rewrite-flush.txt (100%) rename {src/docs => man-src}/rewrite-structure.txt (100%) rename {src/docs => man-src}/theme-activate.txt (100%) rename {src/docs => man-src}/theme-delete.txt (100%) rename {src/docs => man-src}/theme-install.txt (100%) rename {src/docs => man-src}/theme-path.txt (100%) rename {src/docs => man-src}/theme-status.txt (100%) rename {src/docs => man-src}/theme-update-all.txt (100%) rename {src/docs => man-src}/theme-update.txt (100%) rename {src/docs => man-src}/transient.txt (100%) rename {src/docs => man-src}/user-create.txt (100%) rename {src/docs => man-src}/user-delete.txt (100%) rename {src/docs => man-src}/user-generate.txt (100%) rename {src/docs => man-src}/user-import-csv.txt (100%) rename {src/docs => man-src}/user-list.txt (100%) rename {src/docs => man-src}/user-meta.txt (100%) rename {src/docs => man-src}/user-remove-role.txt (100%) rename {src/docs => man-src}/user-set-role.txt (100%) rename {src/docs => man-src}/user-update.txt (100%) create mode 160000 php/php-cli-tools rename {src/php => php}/wp-cli/class-cli-upgrader-skin.php (100%) rename {src/php => php}/wp-cli/class-wp-cli-command-with-meta.php (100%) rename {src/php => php}/wp-cli/class-wp-cli-command-with-upgrade.php (100%) rename {src/php => php}/wp-cli/class-wp-cli-command.php (100%) rename {src/php => php}/wp-cli/class-wp-cli.php (99%) rename {src/php => php}/wp-cli/commands/blog.php (100%) rename {src/php => php}/wp-cli/commands/cache.php (100%) rename {src/php => php}/wp-cli/commands/cap.php (100%) rename {src/php => php}/wp-cli/commands/comment.php (100%) rename {src/php => php}/wp-cli/commands/core.php (100%) rename {src/php => php}/wp-cli/commands/db.php (100%) rename {src/php => php}/wp-cli/commands/eval-file.php (100%) rename {src/php => php}/wp-cli/commands/eval.php (100%) rename {src/php => php}/wp-cli/commands/export.php (100%) rename {src/php => php}/wp-cli/commands/help.php (100%) rename {src/php => php}/wp-cli/commands/home.php (100%) rename {src/php => php}/wp-cli/commands/option.php (100%) rename {src/php => php}/wp-cli/commands/plugin.php (100%) rename {src/php => php}/wp-cli/commands/post-meta.php (100%) rename {src/php => php}/wp-cli/commands/post.php (100%) rename {src/php => php}/wp-cli/commands/rewrite.php (100%) rename {src/php => php}/wp-cli/commands/shell.php (100%) rename {src/php => php}/wp-cli/commands/theme.php (100%) rename {src/php => php}/wp-cli/commands/transient.php (100%) rename {src/php => php}/wp-cli/commands/user-meta.php (100%) rename {src/php => php}/wp-cli/commands/user.php (100%) rename {src/php => php}/wp-cli/dispatcher.php (100%) rename {src/php => php}/wp-cli/man.php (100%) rename {src/php => php}/wp-cli/utils.php (97%) rename {src/php => php}/wp-cli/wp-cli-boot.php (100%) rename {src/php => php}/wp-cli/wp-cli.php (100%) rename {src/php => php}/wp-cli/wp-settings.php (100%) delete mode 160000 src/php/php-cli-tools diff --git a/.gitmodules b/.gitmodules index ec544e3d0..bf7ca3df3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "src/php/php-cli-tools"] - path = src/php/php-cli-tools +[submodule "php/php-cli-tools"] + path = php/php-cli-tools url = git://github.com/wp-cli/php-cli-tools.git diff --git a/src/bin/wp b/bin/wp similarity index 100% rename from src/bin/wp rename to bin/wp diff --git a/composer.json b/composer.json index 3092b1c42..2cb9f8c81 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "homepage": "http://wp-cli.org", "license": "MIT", "bin": [ - "src/bin/wp" + "bin/wp" ], "require": { "php": ">=5.3", diff --git a/src/docs/blog-create.txt b/man-src/blog-create.txt similarity index 100% rename from src/docs/blog-create.txt rename to man-src/blog-create.txt diff --git a/src/docs/blog-delete.txt b/man-src/blog-delete.txt similarity index 100% rename from src/docs/blog-delete.txt rename to man-src/blog-delete.txt diff --git a/src/docs/cache.txt b/man-src/cache.txt similarity index 100% rename from src/docs/cache.txt rename to man-src/cache.txt diff --git a/src/docs/cap.txt b/man-src/cap.txt similarity index 100% rename from src/docs/cap.txt rename to man-src/cap.txt diff --git a/src/docs/comment-approve.txt b/man-src/comment-approve.txt similarity index 100% rename from src/docs/comment-approve.txt rename to man-src/comment-approve.txt diff --git a/src/docs/comment-count.txt b/man-src/comment-count.txt similarity index 100% rename from src/docs/comment-count.txt rename to man-src/comment-count.txt diff --git a/src/docs/comment-create.txt b/man-src/comment-create.txt similarity index 100% rename from src/docs/comment-create.txt rename to man-src/comment-create.txt diff --git a/src/docs/comment-delete.txt b/man-src/comment-delete.txt similarity index 100% rename from src/docs/comment-delete.txt rename to man-src/comment-delete.txt diff --git a/src/docs/comment-last.txt b/man-src/comment-last.txt similarity index 100% rename from src/docs/comment-last.txt rename to man-src/comment-last.txt diff --git a/src/docs/comment-spam.txt b/man-src/comment-spam.txt similarity index 100% rename from src/docs/comment-spam.txt rename to man-src/comment-spam.txt diff --git a/src/docs/comment-status.txt b/man-src/comment-status.txt similarity index 100% rename from src/docs/comment-status.txt rename to man-src/comment-status.txt diff --git a/src/docs/comment-trash.txt b/man-src/comment-trash.txt similarity index 100% rename from src/docs/comment-trash.txt rename to man-src/comment-trash.txt diff --git a/src/docs/comment-unapprove.txt b/man-src/comment-unapprove.txt similarity index 100% rename from src/docs/comment-unapprove.txt rename to man-src/comment-unapprove.txt diff --git a/src/docs/comment-unspam.txt b/man-src/comment-unspam.txt similarity index 100% rename from src/docs/comment-unspam.txt rename to man-src/comment-unspam.txt diff --git a/src/docs/comment-untrash.txt b/man-src/comment-untrash.txt similarity index 100% rename from src/docs/comment-untrash.txt rename to man-src/comment-untrash.txt diff --git a/src/docs/core-config.txt b/man-src/core-config.txt similarity index 100% rename from src/docs/core-config.txt rename to man-src/core-config.txt diff --git a/src/docs/core-download.txt b/man-src/core-download.txt similarity index 100% rename from src/docs/core-download.txt rename to man-src/core-download.txt diff --git a/src/docs/core-install-network.txt b/man-src/core-install-network.txt similarity index 100% rename from src/docs/core-install-network.txt rename to man-src/core-install-network.txt diff --git a/src/docs/core-install.txt b/man-src/core-install.txt similarity index 100% rename from src/docs/core-install.txt rename to man-src/core-install.txt diff --git a/src/docs/core-is-installed.txt b/man-src/core-is-installed.txt similarity index 100% rename from src/docs/core-is-installed.txt rename to man-src/core-is-installed.txt diff --git a/src/docs/core-update.txt b/man-src/core-update.txt similarity index 100% rename from src/docs/core-update.txt rename to man-src/core-update.txt diff --git a/src/docs/core-version.txt b/man-src/core-version.txt similarity index 100% rename from src/docs/core-version.txt rename to man-src/core-version.txt diff --git a/src/docs/db.txt b/man-src/db.txt similarity index 100% rename from src/docs/db.txt rename to man-src/db.txt diff --git a/src/docs/eval-file.txt b/man-src/eval-file.txt similarity index 100% rename from src/docs/eval-file.txt rename to man-src/eval-file.txt diff --git a/src/docs/eval.txt b/man-src/eval.txt similarity index 100% rename from src/docs/eval.txt rename to man-src/eval.txt diff --git a/src/docs/export.txt b/man-src/export.txt similarity index 100% rename from src/docs/export.txt rename to man-src/export.txt diff --git a/src/docs/option.txt b/man-src/option.txt similarity index 100% rename from src/docs/option.txt rename to man-src/option.txt diff --git a/src/docs/plugin-activate.txt b/man-src/plugin-activate.txt similarity index 100% rename from src/docs/plugin-activate.txt rename to man-src/plugin-activate.txt diff --git a/src/docs/plugin-deactivate.txt b/man-src/plugin-deactivate.txt similarity index 100% rename from src/docs/plugin-deactivate.txt rename to man-src/plugin-deactivate.txt diff --git a/src/docs/plugin-delete.txt b/man-src/plugin-delete.txt similarity index 100% rename from src/docs/plugin-delete.txt rename to man-src/plugin-delete.txt diff --git a/src/docs/plugin-install.txt b/man-src/plugin-install.txt similarity index 100% rename from src/docs/plugin-install.txt rename to man-src/plugin-install.txt diff --git a/src/docs/plugin-path.txt b/man-src/plugin-path.txt similarity index 100% rename from src/docs/plugin-path.txt rename to man-src/plugin-path.txt diff --git a/src/docs/plugin-status.txt b/man-src/plugin-status.txt similarity index 100% rename from src/docs/plugin-status.txt rename to man-src/plugin-status.txt diff --git a/src/docs/plugin-toggle.txt b/man-src/plugin-toggle.txt similarity index 100% rename from src/docs/plugin-toggle.txt rename to man-src/plugin-toggle.txt diff --git a/src/docs/plugin-uninstall.txt b/man-src/plugin-uninstall.txt similarity index 100% rename from src/docs/plugin-uninstall.txt rename to man-src/plugin-uninstall.txt diff --git a/src/docs/plugin-update-all.txt b/man-src/plugin-update-all.txt similarity index 100% rename from src/docs/plugin-update-all.txt rename to man-src/plugin-update-all.txt diff --git a/src/docs/plugin-update.txt b/man-src/plugin-update.txt similarity index 100% rename from src/docs/plugin-update.txt rename to man-src/plugin-update.txt diff --git a/src/docs/post-create.txt b/man-src/post-create.txt similarity index 100% rename from src/docs/post-create.txt rename to man-src/post-create.txt diff --git a/src/docs/post-delete.txt b/man-src/post-delete.txt similarity index 100% rename from src/docs/post-delete.txt rename to man-src/post-delete.txt diff --git a/src/docs/post-generate.txt b/man-src/post-generate.txt similarity index 100% rename from src/docs/post-generate.txt rename to man-src/post-generate.txt diff --git a/src/docs/post-list.txt b/man-src/post-list.txt similarity index 100% rename from src/docs/post-list.txt rename to man-src/post-list.txt diff --git a/src/docs/post-meta.txt b/man-src/post-meta.txt similarity index 100% rename from src/docs/post-meta.txt rename to man-src/post-meta.txt diff --git a/src/docs/post-update.txt b/man-src/post-update.txt similarity index 100% rename from src/docs/post-update.txt rename to man-src/post-update.txt diff --git a/src/docs/rewrite-dump.txt b/man-src/rewrite-dump.txt similarity index 100% rename from src/docs/rewrite-dump.txt rename to man-src/rewrite-dump.txt diff --git a/src/docs/rewrite-flush.txt b/man-src/rewrite-flush.txt similarity index 100% rename from src/docs/rewrite-flush.txt rename to man-src/rewrite-flush.txt diff --git a/src/docs/rewrite-structure.txt b/man-src/rewrite-structure.txt similarity index 100% rename from src/docs/rewrite-structure.txt rename to man-src/rewrite-structure.txt diff --git a/src/docs/theme-activate.txt b/man-src/theme-activate.txt similarity index 100% rename from src/docs/theme-activate.txt rename to man-src/theme-activate.txt diff --git a/src/docs/theme-delete.txt b/man-src/theme-delete.txt similarity index 100% rename from src/docs/theme-delete.txt rename to man-src/theme-delete.txt diff --git a/src/docs/theme-install.txt b/man-src/theme-install.txt similarity index 100% rename from src/docs/theme-install.txt rename to man-src/theme-install.txt diff --git a/src/docs/theme-path.txt b/man-src/theme-path.txt similarity index 100% rename from src/docs/theme-path.txt rename to man-src/theme-path.txt diff --git a/src/docs/theme-status.txt b/man-src/theme-status.txt similarity index 100% rename from src/docs/theme-status.txt rename to man-src/theme-status.txt diff --git a/src/docs/theme-update-all.txt b/man-src/theme-update-all.txt similarity index 100% rename from src/docs/theme-update-all.txt rename to man-src/theme-update-all.txt diff --git a/src/docs/theme-update.txt b/man-src/theme-update.txt similarity index 100% rename from src/docs/theme-update.txt rename to man-src/theme-update.txt diff --git a/src/docs/transient.txt b/man-src/transient.txt similarity index 100% rename from src/docs/transient.txt rename to man-src/transient.txt diff --git a/src/docs/user-create.txt b/man-src/user-create.txt similarity index 100% rename from src/docs/user-create.txt rename to man-src/user-create.txt diff --git a/src/docs/user-delete.txt b/man-src/user-delete.txt similarity index 100% rename from src/docs/user-delete.txt rename to man-src/user-delete.txt diff --git a/src/docs/user-generate.txt b/man-src/user-generate.txt similarity index 100% rename from src/docs/user-generate.txt rename to man-src/user-generate.txt diff --git a/src/docs/user-import-csv.txt b/man-src/user-import-csv.txt similarity index 100% rename from src/docs/user-import-csv.txt rename to man-src/user-import-csv.txt diff --git a/src/docs/user-list.txt b/man-src/user-list.txt similarity index 100% rename from src/docs/user-list.txt rename to man-src/user-list.txt diff --git a/src/docs/user-meta.txt b/man-src/user-meta.txt similarity index 100% rename from src/docs/user-meta.txt rename to man-src/user-meta.txt diff --git a/src/docs/user-remove-role.txt b/man-src/user-remove-role.txt similarity index 100% rename from src/docs/user-remove-role.txt rename to man-src/user-remove-role.txt diff --git a/src/docs/user-set-role.txt b/man-src/user-set-role.txt similarity index 100% rename from src/docs/user-set-role.txt rename to man-src/user-set-role.txt diff --git a/src/docs/user-update.txt b/man-src/user-update.txt similarity index 100% rename from src/docs/user-update.txt rename to man-src/user-update.txt diff --git a/php/php-cli-tools b/php/php-cli-tools new file mode 160000 index 000000000..f3def25b8 --- /dev/null +++ b/php/php-cli-tools @@ -0,0 +1 @@ +Subproject commit f3def25b862bb0c5330a6347c6c04d62a99eb217 diff --git a/src/php/wp-cli/class-cli-upgrader-skin.php b/php/wp-cli/class-cli-upgrader-skin.php similarity index 100% rename from src/php/wp-cli/class-cli-upgrader-skin.php rename to php/wp-cli/class-cli-upgrader-skin.php diff --git a/src/php/wp-cli/class-wp-cli-command-with-meta.php b/php/wp-cli/class-wp-cli-command-with-meta.php similarity index 100% rename from src/php/wp-cli/class-wp-cli-command-with-meta.php rename to php/wp-cli/class-wp-cli-command-with-meta.php diff --git a/src/php/wp-cli/class-wp-cli-command-with-upgrade.php b/php/wp-cli/class-wp-cli-command-with-upgrade.php similarity index 100% rename from src/php/wp-cli/class-wp-cli-command-with-upgrade.php rename to php/wp-cli/class-wp-cli-command-with-upgrade.php diff --git a/src/php/wp-cli/class-wp-cli-command.php b/php/wp-cli/class-wp-cli-command.php similarity index 100% rename from src/php/wp-cli/class-wp-cli-command.php rename to php/wp-cli/class-wp-cli-command.php diff --git a/src/php/wp-cli/class-wp-cli.php b/php/wp-cli/class-wp-cli.php similarity index 99% rename from src/php/wp-cli/class-wp-cli.php rename to php/wp-cli/class-wp-cli.php index 176066587..0e5c2dd1b 100644 --- a/src/php/wp-cli/class-wp-cli.php +++ b/php/wp-cli/class-wp-cli.php @@ -234,8 +234,8 @@ static function get_assoc_special() { static function before_wp_load() { self::add_man_dir( - WP_CLI_ROOT . "../../../man/", - WP_CLI_ROOT . "../../docs/" + WP_CLI_ROOT . "../../man/", + WP_CLI_ROOT . "../../man-src/" ); self::parse_args(); diff --git a/src/php/wp-cli/commands/blog.php b/php/wp-cli/commands/blog.php similarity index 100% rename from src/php/wp-cli/commands/blog.php rename to php/wp-cli/commands/blog.php diff --git a/src/php/wp-cli/commands/cache.php b/php/wp-cli/commands/cache.php similarity index 100% rename from src/php/wp-cli/commands/cache.php rename to php/wp-cli/commands/cache.php diff --git a/src/php/wp-cli/commands/cap.php b/php/wp-cli/commands/cap.php similarity index 100% rename from src/php/wp-cli/commands/cap.php rename to php/wp-cli/commands/cap.php diff --git a/src/php/wp-cli/commands/comment.php b/php/wp-cli/commands/comment.php similarity index 100% rename from src/php/wp-cli/commands/comment.php rename to php/wp-cli/commands/comment.php diff --git a/src/php/wp-cli/commands/core.php b/php/wp-cli/commands/core.php similarity index 100% rename from src/php/wp-cli/commands/core.php rename to php/wp-cli/commands/core.php diff --git a/src/php/wp-cli/commands/db.php b/php/wp-cli/commands/db.php similarity index 100% rename from src/php/wp-cli/commands/db.php rename to php/wp-cli/commands/db.php diff --git a/src/php/wp-cli/commands/eval-file.php b/php/wp-cli/commands/eval-file.php similarity index 100% rename from src/php/wp-cli/commands/eval-file.php rename to php/wp-cli/commands/eval-file.php diff --git a/src/php/wp-cli/commands/eval.php b/php/wp-cli/commands/eval.php similarity index 100% rename from src/php/wp-cli/commands/eval.php rename to php/wp-cli/commands/eval.php diff --git a/src/php/wp-cli/commands/export.php b/php/wp-cli/commands/export.php similarity index 100% rename from src/php/wp-cli/commands/export.php rename to php/wp-cli/commands/export.php diff --git a/src/php/wp-cli/commands/help.php b/php/wp-cli/commands/help.php similarity index 100% rename from src/php/wp-cli/commands/help.php rename to php/wp-cli/commands/help.php diff --git a/src/php/wp-cli/commands/home.php b/php/wp-cli/commands/home.php similarity index 100% rename from src/php/wp-cli/commands/home.php rename to php/wp-cli/commands/home.php diff --git a/src/php/wp-cli/commands/option.php b/php/wp-cli/commands/option.php similarity index 100% rename from src/php/wp-cli/commands/option.php rename to php/wp-cli/commands/option.php diff --git a/src/php/wp-cli/commands/plugin.php b/php/wp-cli/commands/plugin.php similarity index 100% rename from src/php/wp-cli/commands/plugin.php rename to php/wp-cli/commands/plugin.php diff --git a/src/php/wp-cli/commands/post-meta.php b/php/wp-cli/commands/post-meta.php similarity index 100% rename from src/php/wp-cli/commands/post-meta.php rename to php/wp-cli/commands/post-meta.php diff --git a/src/php/wp-cli/commands/post.php b/php/wp-cli/commands/post.php similarity index 100% rename from src/php/wp-cli/commands/post.php rename to php/wp-cli/commands/post.php diff --git a/src/php/wp-cli/commands/rewrite.php b/php/wp-cli/commands/rewrite.php similarity index 100% rename from src/php/wp-cli/commands/rewrite.php rename to php/wp-cli/commands/rewrite.php diff --git a/src/php/wp-cli/commands/shell.php b/php/wp-cli/commands/shell.php similarity index 100% rename from src/php/wp-cli/commands/shell.php rename to php/wp-cli/commands/shell.php diff --git a/src/php/wp-cli/commands/theme.php b/php/wp-cli/commands/theme.php similarity index 100% rename from src/php/wp-cli/commands/theme.php rename to php/wp-cli/commands/theme.php diff --git a/src/php/wp-cli/commands/transient.php b/php/wp-cli/commands/transient.php similarity index 100% rename from src/php/wp-cli/commands/transient.php rename to php/wp-cli/commands/transient.php diff --git a/src/php/wp-cli/commands/user-meta.php b/php/wp-cli/commands/user-meta.php similarity index 100% rename from src/php/wp-cli/commands/user-meta.php rename to php/wp-cli/commands/user-meta.php diff --git a/src/php/wp-cli/commands/user.php b/php/wp-cli/commands/user.php similarity index 100% rename from src/php/wp-cli/commands/user.php rename to php/wp-cli/commands/user.php diff --git a/src/php/wp-cli/dispatcher.php b/php/wp-cli/dispatcher.php similarity index 100% rename from src/php/wp-cli/dispatcher.php rename to php/wp-cli/dispatcher.php diff --git a/src/php/wp-cli/man.php b/php/wp-cli/man.php similarity index 100% rename from src/php/wp-cli/man.php rename to php/wp-cli/man.php diff --git a/src/php/wp-cli/utils.php b/php/wp-cli/utils.php similarity index 97% rename from src/php/wp-cli/utils.php rename to php/wp-cli/utils.php index 518713928..070ade815 100644 --- a/src/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -4,8 +4,8 @@ function load_cli_tools() { $vendor_paths = array( - WP_CLI_ROOT . '../../../../../../vendor', // part of a larger project - WP_CLI_ROOT . '../../../vendor', // top-level project + WP_CLI_ROOT . '../../../../../vendor', // part of a larger project + WP_CLI_ROOT . '../../vendor', // top-level project ); $found = false; diff --git a/src/php/wp-cli/wp-cli-boot.php b/php/wp-cli/wp-cli-boot.php similarity index 100% rename from src/php/wp-cli/wp-cli-boot.php rename to php/wp-cli/wp-cli-boot.php diff --git a/src/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php similarity index 100% rename from src/php/wp-cli/wp-cli.php rename to php/wp-cli/wp-cli.php diff --git a/src/php/wp-cli/wp-settings.php b/php/wp-cli/wp-settings.php similarity index 100% rename from src/php/wp-cli/wp-settings.php rename to php/wp-cli/wp-settings.php diff --git a/src/php/php-cli-tools b/src/php/php-cli-tools deleted file mode 160000 index f2abf5015..000000000 --- a/src/php/php-cli-tools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f2abf5015c769f9603fc63e7d0a0eff00006c61e diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index 7b6e9b30d..7139cfb3b 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -13,7 +13,7 @@ public function run_wp_cli( $wp_cli_command ) { } private function find_wp_cli() { - return getcwd() . "/src/bin/wp"; + return getcwd() . "/bin/wp"; } private function run_command( $command ) { diff --git a/utils/dev-build b/utils/dev-build index ea70e6be6..b8ad05819 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -2,7 +2,7 @@ for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then - ln -sf $(pwd)/src/bin/wp $dir/wp + ln -sf $(pwd)/bin/wp $dir/wp break fi done diff --git a/utils/local-build b/utils/local-build index edf89736e..fab82fddf 100755 --- a/utils/local-build +++ b/utils/local-build @@ -12,6 +12,6 @@ fi DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd) -alias wp='$DIR/../src/bin/wp' +alias wp='$DIR/../bin/wp' . $DIR/wp-completion.bash diff --git a/utils/pear-build b/utils/pear-build index 300d83ef4..758cadd5c 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -3,12 +3,10 @@ set -ex # create bunch of directories that phing complains about -mkdir -p src/data -mkdir -p src/tests/unit-tests/php -mkdir -p src/www +mkdir -p data www tests/unit-tests/php # temporarily move the .git dir, because phing is stupid -git_dir=src/php/php-cli-tools/.git +git_dir=php/php-cli-tools/.git if [ -f $git_dir ]; then mv $git_dir /tmp/php-cli-tools-git fi From 3166e02d3de15a6d671a2a400688d65e73e6fc1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Dec 2012 16:43:02 +0200 Subject: [PATCH 0958/5359] fix pear-build --- .gitignore | 1 + utils/pear-build | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 851cd1140..8b2103e77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.build +/src /dist /vendor /composer.lock diff --git a/utils/pear-build b/utils/pear-build index 758cadd5c..1d0d66166 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -2,8 +2,16 @@ set -ex +# create src dir +rm -rf src +mkdir src +cp -r php src/ +cp -r bin src/ + # create bunch of directories that phing complains about -mkdir -p data www tests/unit-tests/php +cd src +mkdir -p docs data www tests/unit-tests/php +cd - # temporarily move the .git dir, because phing is stupid git_dir=php/php-cli-tools/.git From 5e8f2410b29a9201df6313d9eb82f1e74e709781 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Dec 2012 16:49:53 +0200 Subject: [PATCH 0959/5359] update path in build.xml instead of creating src dir. see #248 --- build.xml | 2 +- utils/pear-build | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/build.xml b/build.xml index a3b507921..932336fb4 100644 --- a/build.xml +++ b/build.xml @@ -22,7 +22,7 @@ <property name="project.apiversion" value="${project.majorVersion}.${project.minorVersion}" /> <!-- Paths to the directories that we work with --> - <property name="project.srcdir" value="${project.basedir}/src" override="true" /> + <property name="project.srcdir" value="${project.basedir}" override="true" /> <property name="project.src.phpdir" value="${project.srcdir}/php" override="true" /> <property name="project.src.bindir" value="${project.srcdir}/bin" override="true" /> <property name="project.src.datadir" value="${project.srcdir}/data" override="true" /> diff --git a/utils/pear-build b/utils/pear-build index 1d0d66166..c4e404784 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -2,16 +2,8 @@ set -ex -# create src dir -rm -rf src -mkdir src -cp -r php src/ -cp -r bin src/ - # create bunch of directories that phing complains about -cd src mkdir -p docs data www tests/unit-tests/php -cd - # temporarily move the .git dir, because phing is stupid git_dir=php/php-cli-tools/.git From 6c018aae76f7ae6adfdda24f2b724e651a061235 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 07:46:58 +0200 Subject: [PATCH 0960/5359] add query iterators as submodule --- .gitmodules | 3 +++ php/query-iterators | 1 + 2 files changed, 4 insertions(+) create mode 160000 php/query-iterators diff --git a/.gitmodules b/.gitmodules index bf7ca3df3..d70ec97df 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "php/php-cli-tools"] path = php/php-cli-tools url = git://github.com/wp-cli/php-cli-tools.git +[submodule "php/query-iterators"] + path = php/query-iterators + url = https://gist.github.com/4378217.git diff --git a/php/query-iterators b/php/query-iterators new file mode 160000 index 000000000..7cb209489 --- /dev/null +++ b/php/query-iterators @@ -0,0 +1 @@ +Subproject commit 7cb209489a356c6b18bb910a291df13a6c258b96 From b1bd56dd5e2bdc106603c1034affc6a953b5e6b1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 08:56:37 +0200 Subject: [PATCH 0961/5359] first pass at search-replace command --- php/wp-cli/commands/search-replace.php | 101 +++++++++++++++++++++++++ php/wp-cli/utils.php | 60 +++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 php/wp-cli/commands/search-replace.php diff --git a/php/wp-cli/commands/search-replace.php b/php/wp-cli/commands/search-replace.php new file mode 100644 index 000000000..cec0d29dd --- /dev/null +++ b/php/wp-cli/commands/search-replace.php @@ -0,0 +1,101 @@ +<?php + +WP_CLI::add_command( 'search-replace', new Search_Replace_Command ); + +/** + * Search/Replace strings in the database. + * + * @package wp-cli + */ +class Search_Replace_Command extends WP_CLI_Command { + + /** + * @synopsis <old> <new> + */ + public function __invoke( $args, $assoc_args ) { + require_once WP_CLI_ROOT . '../query-iterators/class-table-iterator.php'; + + global $wpdb; + + list( $old, $new ) = $args; + + $tables = $wpdb->tables( 'blog' ); + + $total = 0; + + foreach ( $tables as $table ) { + list( $primary_key, $columns ) = self::get_columns( $table ); + + foreach ( $columns as $col ) { + $count = self::handle_col( $col, $primary_key, $table, $old, $new ); + + WP_CLI::line( "$table.$col: $count" ); + + $total += $count; + } + } + + WP_CLI::success( "Made $total replacements." ); + } + + private static function handle_col( $col, $primary_key, $table, $old, $new ) { + global $wpdb; + + $args = array( + 'table' => $table, + 'fields' => array( $primary_key, $col ), + 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', + 'limit' => 1000 + ); + + $it = new TableIterator( $args ); + + $count = 0; + + foreach ( $it as $row ) { + if ( '' === $row->$col ) + continue; + + $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); + + $count += $wpdb->update( $table, + array( $col => $value ), + array( $primary_key => $row->$primary_key ) + ); + } + + return $count; + } + + private static function get_columns( $table ) { + global $wpdb; + + $primary_key = null; + + $columns = array(); + + foreach ( $wpdb->get_results( "DESCRIBE $table" ) as $col ) { + if ( 'PRI' === $col->Key ) { + $primary_key = $col->Field; + continue; + } + + if ( !self::is_text_col( $col->Type ) ) + continue; + + $columns[] = $col->Field; + } + + return array( $primary_key, $columns ); + } + + private static function is_text_col( $type ) { + foreach ( array( 'text', 'varchar' ) as $token ) { + if ( false !== strpos( $type, $token ) ) + return true; + } + + return false; + } +} + diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index 070ade815..344e14f52 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -218,3 +218,63 @@ function parse_csv( $filepath, $has_headers = true ) { } return $parsed_data; } + +/** + * Take a serialised array and unserialise it replacing elements as needed and + * unserialising any subordinate arrays and performing the replace on those too. + * + * @source https://github.com/interconnectit/Search-Replace-DB + * + * @param string $from String we're looking to replace. + * @param string $to What we want it to be replaced with + * @param array $data Used to pass any subordinate arrays back to in. + * @param bool $serialised Does the array passed via $data need serialising. + * + * @return array The original array with all elements replaced as needed. + */ +function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) { + + // some unseriliased data cannot be re-serialised eg. SimpleXMLElements + try { + + if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { + $data = recursive_unserialize_replace( $from, $to, $unserialized, true ); + } + + elseif ( is_array( $data ) ) { + $_tmp = array( ); + foreach ( $data as $key => $value ) { + $_tmp[ $key ] = recursive_unserialize_replace( $from, $to, $value, false ); + } + + $data = $_tmp; + unset( $_tmp ); + } + + // Submitted by Tina Matter + elseif ( is_object( $data ) ) { + $dataClass = get_class( $data ); + $_tmp = new $dataClass( ); + foreach ( $data as $key => $value ) { + $_tmp->$key = recursive_unserialize_replace( $from, $to, $value, false ); + } + + $data = $_tmp; + unset( $_tmp ); + } + + else { + if ( is_string( $data ) ) + $data = str_replace( $from, $to, $data ); + } + + if ( $serialised ) + return serialize( $data ); + + } catch( Exception $error ) { + + } + + return $data; +} + From ad7418703eba1890cb0e1cb1cd7f304b1550f318 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 09:02:04 +0200 Subject: [PATCH 0962/5359] use \cli\Table for displaying the report --- php/wp-cli/commands/search-replace.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/php/wp-cli/commands/search-replace.php b/php/wp-cli/commands/search-replace.php index cec0d29dd..e0f2f0e76 100644 --- a/php/wp-cli/commands/search-replace.php +++ b/php/wp-cli/commands/search-replace.php @@ -23,18 +23,25 @@ public function __invoke( $args, $assoc_args ) { $total = 0; + $report = array(); + foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { $count = self::handle_col( $col, $primary_key, $table, $old, $new ); - WP_CLI::line( "$table.$col: $count" ); + $report[] = array( $table, $col, $count ); $total += $count; } } + $table = new \cli\Table(); + $table->setHeaders( array( 'Table', 'Column', 'Replacements' ) ); + $table->setRows( $report ); + $table->display(); + WP_CLI::success( "Made $total replacements." ); } From d7015fa9acd4248da607506ce8484e2500194127 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 09:15:50 +0200 Subject: [PATCH 0963/5359] add --dry-run flag --- php/wp-cli/commands/search-replace.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/php/wp-cli/commands/search-replace.php b/php/wp-cli/commands/search-replace.php index e0f2f0e76..71bb7d524 100644 --- a/php/wp-cli/commands/search-replace.php +++ b/php/wp-cli/commands/search-replace.php @@ -10,7 +10,7 @@ class Search_Replace_Command extends WP_CLI_Command { /** - * @synopsis <old> <new> + * @synopsis <old> <new> [--dry-run] */ public function __invoke( $args, $assoc_args ) { require_once WP_CLI_ROOT . '../query-iterators/class-table-iterator.php'; @@ -25,11 +25,14 @@ public function __invoke( $args, $assoc_args ) { $report = array(); + $dry_run = isset( $assoc_args['dry-run'] ); + foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { - $count = self::handle_col( $col, $primary_key, $table, $old, $new ); + $count = self::handle_col( $col, $primary_key, $table, $old, $new, + $dry_run ); $report[] = array( $table, $col, $count ); @@ -42,10 +45,11 @@ public function __invoke( $args, $assoc_args ) { $table->setRows( $report ); $table->display(); - WP_CLI::success( "Made $total replacements." ); + if ( !$dry_run ) + WP_CLI::success( "Made $total replacements." ); } - private static function handle_col( $col, $primary_key, $table, $old, $new ) { + private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { global $wpdb; $args = array( @@ -65,10 +69,15 @@ private static function handle_col( $col, $primary_key, $table, $old, $new ) { $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); - $count += $wpdb->update( $table, - array( $col => $value ), - array( $primary_key => $row->$primary_key ) - ); + if ( $dry_run ) { + if ( $value != $row->$col ) + $count++; + } else { + $count += $wpdb->update( $table, + array( $col => $value ), + array( $primary_key => $row->$primary_key ) + ); + } } return $count; From ede01c951807b17cbcd640dab01bbb66e35f45ce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:06:14 +0200 Subject: [PATCH 0964/5359] move class-*.php to classes/*.php --- .../cli-upgrader-skin.php} | 0 .../wp-cli-command-with-meta.php} | 0 .../wp-cli-command-with-upgrade.php} | 0 .../wp-cli-command.php} | 0 php/wp-cli/{class-wp-cli.php => classes/wp-cli.php} | 0 php/wp-cli/wp-cli.php | 8 ++++---- 6 files changed, 4 insertions(+), 4 deletions(-) rename php/wp-cli/{class-cli-upgrader-skin.php => classes/cli-upgrader-skin.php} (100%) rename php/wp-cli/{class-wp-cli-command-with-meta.php => classes/wp-cli-command-with-meta.php} (100%) rename php/wp-cli/{class-wp-cli-command-with-upgrade.php => classes/wp-cli-command-with-upgrade.php} (100%) rename php/wp-cli/{class-wp-cli-command.php => classes/wp-cli-command.php} (100%) rename php/wp-cli/{class-wp-cli.php => classes/wp-cli.php} (100%) diff --git a/php/wp-cli/class-cli-upgrader-skin.php b/php/wp-cli/classes/cli-upgrader-skin.php similarity index 100% rename from php/wp-cli/class-cli-upgrader-skin.php rename to php/wp-cli/classes/cli-upgrader-skin.php diff --git a/php/wp-cli/class-wp-cli-command-with-meta.php b/php/wp-cli/classes/wp-cli-command-with-meta.php similarity index 100% rename from php/wp-cli/class-wp-cli-command-with-meta.php rename to php/wp-cli/classes/wp-cli-command-with-meta.php diff --git a/php/wp-cli/class-wp-cli-command-with-upgrade.php b/php/wp-cli/classes/wp-cli-command-with-upgrade.php similarity index 100% rename from php/wp-cli/class-wp-cli-command-with-upgrade.php rename to php/wp-cli/classes/wp-cli-command-with-upgrade.php diff --git a/php/wp-cli/class-wp-cli-command.php b/php/wp-cli/classes/wp-cli-command.php similarity index 100% rename from php/wp-cli/class-wp-cli-command.php rename to php/wp-cli/classes/wp-cli-command.php diff --git a/php/wp-cli/class-wp-cli.php b/php/wp-cli/classes/wp-cli.php similarity index 100% rename from php/wp-cli/class-wp-cli.php rename to php/wp-cli/classes/wp-cli.php diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index 0f7fe5986..a1975559b 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -9,10 +9,10 @@ include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; -include WP_CLI_ROOT . 'class-wp-cli.php'; -include WP_CLI_ROOT . 'class-wp-cli-command.php'; -include WP_CLI_ROOT . 'class-wp-cli-command-with-meta.php'; -include WP_CLI_ROOT . 'class-wp-cli-command-with-upgrade.php'; +include WP_CLI_ROOT . 'classes/wp-cli.php'; +include WP_CLI_ROOT . 'classes/wp-cli-command.php'; +include WP_CLI_ROOT . 'classes/wp-cli-command-with-meta.php'; +include WP_CLI_ROOT . 'classes/wp-cli-command-with-upgrade.php'; include WP_CLI_ROOT . 'man.php'; \WP_CLI\Utils\load_cli_tools(); From 05982206e7d5ee1d830716b86af3ef1773c3d4a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:37:28 +0200 Subject: [PATCH 0965/5359] add basic autoloader for WP_CLI namespace --- php/wp-cli/utils.php | 17 +++++++++++++++++ php/wp-cli/wp-cli.php | 1 + 2 files changed, 18 insertions(+) diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index 344e14f52..c6344d961 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -25,6 +25,23 @@ function load_cli_tools() { } } +function register_autoload() { + spl_autoload_register( function($class) { + // Only attempt to load classes in our namespace + if ( 0 !== strpos( $class, 'WP_CLI\\' ) ) { + return; + } + + $base = WP_CLI_ROOT . 'classes/'; + + $path = $base . str_replace( 'WP_CLI\\', '', $class ) . '.php'; + + if ( is_file( $path ) ) { + require_once $path; + } + } ); +} + /** * Splits $argv into positional and associative arguments. * diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index a1975559b..93f2fe033 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -15,6 +15,7 @@ include WP_CLI_ROOT . 'classes/wp-cli-command-with-upgrade.php'; include WP_CLI_ROOT . 'man.php'; +\WP_CLI\Utils\register_autoload(); \WP_CLI\Utils\load_cli_tools(); WP_CLI::before_wp_load(); From 20fb2432bb52e2354322bb0f41d5d47fe591af80 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:38:28 +0200 Subject: [PATCH 0966/5359] autoload upgrader classes CLI_Upgrader_Skin -> WP_CLI\UpgraderSkin Non_Destructive_Core_Upgrader -> WP_CLI\NonDestructiveCoreUpgrader --- .../classes/NonDestructiveCoreUpgrader.php | 15 +++++++++++++++ ...{cli-upgrader-skin.php => UpgraderSkin.php} | 18 +++++------------- php/wp-cli/commands/core.php | 2 +- php/wp-cli/utils.php | 4 +--- 4 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 php/wp-cli/classes/NonDestructiveCoreUpgrader.php rename php/wp-cli/classes/{cli-upgrader-skin.php => UpgraderSkin.php} (68%) diff --git a/php/wp-cli/classes/NonDestructiveCoreUpgrader.php b/php/wp-cli/classes/NonDestructiveCoreUpgrader.php new file mode 100644 index 000000000..41ba05949 --- /dev/null +++ b/php/wp-cli/classes/NonDestructiveCoreUpgrader.php @@ -0,0 +1,15 @@ +<?php + +namespace WP_CLI; + +/** + * A Core Upgrader class that leaves packages intact by default. + * + * @package wp-cli + */ +class NonDestructiveCoreUpgrader extends \Core_Upgrader { + function unpack_package($package, $delete_package = false) { + return parent::unpack_package( $package, $delete_package ); + } +} + diff --git a/php/wp-cli/classes/cli-upgrader-skin.php b/php/wp-cli/classes/UpgraderSkin.php similarity index 68% rename from php/wp-cli/classes/cli-upgrader-skin.php rename to php/wp-cli/classes/UpgraderSkin.php index 0b9871a90..aa56b4348 100644 --- a/php/wp-cli/classes/cli-upgrader-skin.php +++ b/php/wp-cli/classes/UpgraderSkin.php @@ -1,11 +1,13 @@ <?php +namespace WP_CLI; + /** * A Upgrader Skin for WordPress that only generates plain-text * * @package wp-cli */ -class CLI_Upgrader_Skin extends WP_Upgrader_Skin { +class UpgraderSkin extends \WP_Upgrader_Skin { function header() {} function footer() {} @@ -20,7 +22,7 @@ function error( $error ) { $error = $this->upgrader->strings[ $error ]; // TODO: show all errors, not just the first one - WP_CLI::warning( $error ); + \WP_CLI::warning( $error ); } function feedback( $string ) { @@ -39,17 +41,7 @@ function feedback( $string ) { $string = str_replace( '…', '...', strip_tags( $string ) ); - WP_CLI::line( $string ); + \WP_CLI::line( $string ); } } -/** - * A Core Upgrader class that leaves packages intact by default. - * - * @package wp-cli - */ -class Non_Destructive_Core_Upgrader extends Core_Upgrader { - function unpack_package($package, $delete_package = false) { - return parent::unpack_package( $package, $delete_package ); - } -} diff --git a/php/wp-cli/commands/core.php b/php/wp-cli/commands/core.php index 5b1d3b653..63894f4c0 100644 --- a/php/wp-cli/commands/core.php +++ b/php/wp-cli/commands/core.php @@ -243,7 +243,7 @@ function update( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $new_package = $args[0]; - $upgrader = 'Non_Destructive_Core_Upgrader'; + $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; } $update = (object) array( diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index c6344d961..1703ba4a0 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -207,9 +207,7 @@ function get_upgrader( $class ) { if ( !class_exists( '\WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - require WP_CLI_ROOT . '/class-cli-upgrader-skin.php'; - - return new $class( new \CLI_Upgrader_Skin ); + return new $class( new \WP_CLI\UpgraderSkin ); } function parse_csv( $filepath, $has_headers = true ) { From 053c40b66a53c9aeceffb2e0c7ed2c90eebdf01d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:48:11 +0200 Subject: [PATCH 0967/5359] WP_CLI_Command_With_Meta -> \WP_CLI\CommandWithMeta --- ...mand-with-meta.php => CommandWithMeta.php} | 26 ++++++++++--------- php/wp-cli/commands/post-meta.php | 6 ++--- php/wp-cli/commands/user-meta.php | 6 ++--- php/wp-cli/wp-cli.php | 1 - 4 files changed, 20 insertions(+), 19 deletions(-) rename php/wp-cli/classes/{wp-cli-command-with-meta.php => CommandWithMeta.php} (56%) diff --git a/php/wp-cli/classes/wp-cli-command-with-meta.php b/php/wp-cli/classes/CommandWithMeta.php similarity index 56% rename from php/wp-cli/classes/wp-cli-command-with-meta.php rename to php/wp-cli/classes/CommandWithMeta.php index 7a18853b3..3ec480e14 100644 --- a/php/wp-cli/classes/wp-cli-command-with-meta.php +++ b/php/wp-cli/classes/CommandWithMeta.php @@ -1,11 +1,13 @@ <?php +namespace WP_CLI; + /** * Base class for WP-CLI commands that deal with metadata * * @package wp-cli */ -abstract class WP_CLI_Command_With_Meta extends WP_CLI_Command { +abstract class CommandWithMeta extends \WP_CLI_Command { protected $meta_type; @@ -17,12 +19,12 @@ abstract class WP_CLI_Command_With_Meta extends WP_CLI_Command { public function get( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $value = get_metadata( $this->meta_type, $object_id, $meta_key, true ); + $value = \get_metadata( $this->meta_type, $object_id, $meta_key, true ); if ( '' === $value ) die(1); - WP_CLI::print_value( $value, $assoc_args ); + \WP_CLI::print_value( $value, $assoc_args ); } /** @@ -33,12 +35,12 @@ public function get( $args, $assoc_args ) { public function delete( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $success = delete_metadata( $this->meta_type, $object_id, $meta_key ); + $success = \delete_metadata( $this->meta_type, $object_id, $meta_key ); if ( $success ) { - WP_CLI::success( "Deleted custom field." ); + \WP_CLI::success( "Deleted custom field." ); } else { - WP_CLI::error( "Failed to delete custom field." ); + \WP_CLI::error( "Failed to delete custom field." ); } } @@ -50,12 +52,12 @@ public function delete( $args, $assoc_args ) { public function add( $args, $assoc_args ) { list( $object_id, $meta_key, $meta_value ) = $args; - $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $success = \add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { - WP_CLI::success( "Added custom field." ); + \WP_CLI::success( "Added custom field." ); } else { - WP_CLI::error( "Failed to add custom field." ); + \WP_CLI::error( "Failed to add custom field." ); } } @@ -68,12 +70,12 @@ public function add( $args, $assoc_args ) { public function update( $args, $assoc_args ) { list( $object_id, $meta_key, $meta_value ) = $args; - $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { - WP_CLI::success( "Updated custom field." ); + \WP_CLI::success( "Updated custom field." ); } else { - WP_CLI::error( "Failed to update custom field." ); + \WP_CLI::error( "Failed to update custom field." ); } } } diff --git a/php/wp-cli/commands/post-meta.php b/php/wp-cli/commands/post-meta.php index 466468eab..a987ac4b3 100644 --- a/php/wp-cli/commands/post-meta.php +++ b/php/wp-cli/commands/post-meta.php @@ -1,14 +1,14 @@ <?php -WP_CLI::add_command( 'post-meta', 'Post_Meta_Command' ); - /** * Manage post custom fields. * * @package wp-cli * @subpackage commands/internals */ -class Post_Meta_Command extends WP_CLI_Command_With_Meta { +class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; } +WP_CLI::add_command( 'post-meta', 'Post_Meta_Command' ); + diff --git a/php/wp-cli/commands/user-meta.php b/php/wp-cli/commands/user-meta.php index 58fa75e8c..6fe4ed794 100644 --- a/php/wp-cli/commands/user-meta.php +++ b/php/wp-cli/commands/user-meta.php @@ -1,14 +1,14 @@ <?php -WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); - /** * Manage user custom fields. * * @package wp-cli * @subpackage commands/internals */ -class User_Meta_Command extends WP_CLI_Command_With_Meta { +class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; } +WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); + diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index 93f2fe033..9d90a68e2 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -11,7 +11,6 @@ include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'classes/wp-cli.php'; include WP_CLI_ROOT . 'classes/wp-cli-command.php'; -include WP_CLI_ROOT . 'classes/wp-cli-command-with-meta.php'; include WP_CLI_ROOT . 'classes/wp-cli-command-with-upgrade.php'; include WP_CLI_ROOT . 'man.php'; From dfaa657a931eb54d4b9f817ad7e125a9735ddcd7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:52:47 +0200 Subject: [PATCH 0968/5359] WP_CLI_Command_With_Upgrade -> \WP_CLI\CommandWithUpgrade --- ...ith-upgrade.php => CommandWithUpgrade.php} | 30 ++++++++++--------- php/wp-cli/commands/plugin.php | 7 +++-- php/wp-cli/commands/theme.php | 7 +++-- php/wp-cli/wp-cli.php | 1 - 4 files changed, 24 insertions(+), 21 deletions(-) rename php/wp-cli/classes/{wp-cli-command-with-upgrade.php => CommandWithUpgrade.php} (85%) diff --git a/php/wp-cli/classes/wp-cli-command-with-upgrade.php b/php/wp-cli/classes/CommandWithUpgrade.php similarity index 85% rename from php/wp-cli/classes/wp-cli-command-with-upgrade.php rename to php/wp-cli/classes/CommandWithUpgrade.php index b84bcb7e1..1cf052645 100644 --- a/php/wp-cli/classes/wp-cli-command-with-upgrade.php +++ b/php/wp-cli/classes/CommandWithUpgrade.php @@ -1,6 +1,8 @@ <?php -abstract class WP_CLI_Command_With_Upgrade extends WP_CLI_Command { +namespace WP_CLI; + +abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $item_type; protected $upgrader; @@ -38,7 +40,7 @@ private function status_all() { $n = count( $items ); // Not interested in the translation, just the number logic - WP_CLI::line( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); + \WP_CLI::line( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); foreach ( $items as $file => $details ) { if ( $details['update'] ) { @@ -50,10 +52,10 @@ private function status_all() { $line .= $this->format_status( $details['status'], 'short' ); $line .= " " . $details['name'] . "%n"; - WP_CLI::line( $line ); + \WP_CLI::line( $line ); } - WP_CLI::line(); + \WP_CLI::line(); $this->show_legend( $items ); } @@ -74,7 +76,7 @@ private function show_legend( $items ) { if ( in_array( true, wp_list_pluck( $items, 'update' ) ) ) $legend_line[] = '%yU = Update Available%n'; - WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + \WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } private function status_single( $file, $name ) { @@ -92,7 +94,7 @@ private function status_single( $file, $name ) { function install( $args, $assoc_args ) { if ( empty( $args ) ) { - WP_CLI::line( "usage: wp $this->item_type install <slug>" ); + \WP_CLI::line( "usage: wp $this->item_type install <slug>" ); exit; } @@ -102,13 +104,13 @@ function install( $args, $assoc_args ) { $slug = stripslashes( $args[0] ); if ( '.zip' == substr( $slug, -4 ) ) { - $file_upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); + $file_upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); if ( $file_upgrader->install( $slug ) ) { $slug = $file_upgrader->result['destination_name']; if ( isset( $assoc_args['activate'] ) ) { - WP_CLI::line( "Activating '$slug'..." ); + \WP_CLI::line( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } } else { @@ -122,7 +124,7 @@ function install( $args, $assoc_args ) { protected function _update( $item ) { call_user_func( $this->upgrade_refresh ); - WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $item ); + \WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $item ); } function update_all( $args, $assoc_args ) { @@ -143,11 +145,11 @@ function update_all( $args, $assoc_args ) { } } - WP_CLI::line( $item_list ); + \WP_CLI::line( $item_list ); return; } - $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); + $upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); // Let the user know the results. @@ -157,11 +159,11 @@ function update_all( $args, $assoc_args ) { $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; if ( $num_to_update == $num_updated ) { - WP_CLI::success( $line ); + \WP_CLI::success( $line ); } else if ( $num_updated > 0 ) { - WP_CLI::warning( $line ); + \WP_CLI::warning( $line ); } else { - WP_CLI::error( $line ); + \WP_CLI::error( $line ); } } diff --git a/php/wp-cli/commands/plugin.php b/php/wp-cli/commands/plugin.php index 06780e834..047401d8f 100644 --- a/php/wp-cli/commands/plugin.php +++ b/php/wp-cli/commands/plugin.php @@ -1,14 +1,12 @@ <?php -WP_CLI::add_command('plugin', 'Plugin_Command'); - /** * Implement plugin command * * @package wp-cli * @subpackage commands/internals */ -class Plugin_Command extends WP_CLI_Command_With_Upgrade { +class Plugin_Command extends \WP_CLI\CommandWithUpgrade { protected $item_type = 'plugin'; protected $upgrader = 'Plugin_Upgrader'; @@ -347,3 +345,6 @@ private function get_name( $file ) { return $name; } } + +WP_CLI::add_command( 'plugin', 'Plugin_Command' ); + diff --git a/php/wp-cli/commands/theme.php b/php/wp-cli/commands/theme.php index 5f64beb66..8837f8c99 100644 --- a/php/wp-cli/commands/theme.php +++ b/php/wp-cli/commands/theme.php @@ -1,14 +1,12 @@ <?php -WP_CLI::add_command('theme', 'Theme_Command'); - /** * Implement theme command * * @package wp-cli * @subpackage commands/internals */ -class Theme_Command extends WP_CLI_Command_With_Upgrade { +class Theme_Command extends \WP_CLI\CommandWithUpgrade { protected $item_type = 'theme'; protected $upgrader = 'Theme_Upgrader'; @@ -223,3 +221,6 @@ protected function get_stylesheet_path( $theme ) { return WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; } } + +WP_CLI::add_command( 'theme', 'Theme_Command' ); + diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index 9d90a68e2..81056eb3b 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -11,7 +11,6 @@ include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'classes/wp-cli.php'; include WP_CLI_ROOT . 'classes/wp-cli-command.php'; -include WP_CLI_ROOT . 'classes/wp-cli-command-with-upgrade.php'; include WP_CLI_ROOT . 'man.php'; \WP_CLI\Utils\register_autoload(); From 5f3a5cec36acec6a0460084f0bf80c22450e9b72 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 10:56:17 +0200 Subject: [PATCH 0969/5359] move DocParser class to separate file --- php/wp-cli/classes/DocParser.php | 34 +++++++++++++++++++++++++++++ php/wp-cli/dispatcher.php | 37 +++----------------------------- 2 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 php/wp-cli/classes/DocParser.php diff --git a/php/wp-cli/classes/DocParser.php b/php/wp-cli/classes/DocParser.php new file mode 100644 index 000000000..cb891d19d --- /dev/null +++ b/php/wp-cli/classes/DocParser.php @@ -0,0 +1,34 @@ +<?php + +namespace WP_CLI; + +class DocParser { + + protected $docComment; + + function __construct( $reflection ) { + $this->docComment = $reflection->getDocComment(); + } + + function get_shortdesc() { + if ( !preg_match( '/\* (\w.+)\n*/', $this->docComment, $matches ) ) + return false; + + return $matches[1]; + } + + function get_tag( $name ) { + if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $this->docComment, $matches ) ) + return $matches[1]; + + return false; + } + + function get_synopsis() { + if ( !preg_match( '/@synopsis\s+([^\n]+)/', $this->docComment, $matches ) ) + return false; + + return $matches[1]; + } +} + diff --git a/php/wp-cli/dispatcher.php b/php/wp-cli/dispatcher.php index 6077a49c8..20b71a398 100644 --- a/php/wp-cli/dispatcher.php +++ b/php/wp-cli/dispatcher.php @@ -18,37 +18,6 @@ function traverse( &$args, $method = 'find_subcommand' ) { } -class DocParser { - - protected $docComment; - - function __construct( $reflection ) { - $this->docComment = $reflection->getDocComment(); - } - - function get_shortdesc() { - if ( !preg_match( '/\* (\w.+)\n*/', $this->docComment, $matches ) ) - return false; - - return $matches[1]; - } - - function get_tag( $name ) { - if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $this->docComment, $matches ) ) - return $matches[1]; - - return false; - } - - function get_synopsis() { - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $this->docComment, $matches ) ) - return false; - - return $matches[1]; - } -} - - interface Command { function get_path(); @@ -145,7 +114,7 @@ function add_command( $name, $implementation ) { else { $method = new \ReflectionMethod( $implementation, '__invoke' ); - $docparser = new DocParser( $method ); + $docparser = new \WP_CLI\DocParser( $method ); $command = new Subcommand( $name, $implementation, $docparser, $this ); } @@ -203,7 +172,7 @@ public function __construct( $name, $class ) { $this->subcommands = $this->collect_subcommands( $reflection, $class ); - $this->docparser = new DocParser( $reflection ); + $this->docparser = new \WP_CLI\DocParser( $reflection ); } private function collect_subcommands( $reflection, $class ) { @@ -488,7 +457,7 @@ class MethodSubcommand extends Subcommand { function __construct( $class, $method, $parent ) { $callable = array( new $class, $method->name ); - $docparser = new DocParser( $method ); + $docparser = new \WP_CLI\DocParser( $method ); $name = $docparser->get_tag( 'subcommand' ); if ( !$name ) From 4de395b07ff73066f8f36d21f21e32741b95e951 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:18:28 +0200 Subject: [PATCH 0970/5359] move Dispatcher classes to separate files --- .../classes/Dispatcher/CompositeCommand.php | 126 +++++ .../classes/Dispatcher/MethodSubcommand.php | 23 + php/wp-cli/classes/Dispatcher/RootCommand.php | 118 +++++ php/wp-cli/classes/Dispatcher/Subcommand.php | 175 +++++++ php/wp-cli/classes/wp-cli.php | 6 +- php/wp-cli/dispatcher.php | 430 ------------------ php/wp-cli/utils.php | 4 +- 7 files changed, 448 insertions(+), 434 deletions(-) create mode 100644 php/wp-cli/classes/Dispatcher/CompositeCommand.php create mode 100644 php/wp-cli/classes/Dispatcher/MethodSubcommand.php create mode 100644 php/wp-cli/classes/Dispatcher/RootCommand.php create mode 100644 php/wp-cli/classes/Dispatcher/Subcommand.php diff --git a/php/wp-cli/classes/Dispatcher/CompositeCommand.php b/php/wp-cli/classes/Dispatcher/CompositeCommand.php new file mode 100644 index 000000000..23ff3cf36 --- /dev/null +++ b/php/wp-cli/classes/Dispatcher/CompositeCommand.php @@ -0,0 +1,126 @@ +<?php + +namespace WP_CLI\Dispatcher; + +class CompositeCommand implements Command, Composite, Documentable { + + protected $name; + + protected $subcommands; + + protected $shortdesc; + + public function __construct( $name, $class ) { + $this->name = $name; + + $reflection = new \ReflectionClass( $class ); + + $this->subcommands = $this->collect_subcommands( $reflection, $class ); + + $this->docparser = new \WP_CLI\DocParser( $reflection ); + } + + private function collect_subcommands( $reflection, $class ) { + $subcommands = array(); + + foreach ( $reflection->getMethods() as $method ) { + if ( !self::_is_good_method( $method ) ) + continue; + + $subcommand = new MethodSubcommand( $class, $method, $this ); + + $subcommands[ $subcommand->get_name() ] = $subcommand; + } + + return $subcommands; + } + + function get_path() { + return array( $this->name ); + } + + function show_usage() { + $methods = $this->get_subcommands(); + + $i = 0; + + foreach ( $methods as $name => $subcommand ) { + $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; + + $subcommand->show_usage( $prefix ); + } + + \WP_CLI::line(); + \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); + } + + function invoke( $args, $assoc_args ) { + $subcommand = $this->pre_invoke( $args ); + $subcommand->invoke( $args, $assoc_args ); + } + + function pre_invoke( &$args ) { + $subcommand = $this->find_subcommand( $args ); + + if ( !$subcommand ) { + $this->show_usage(); + exit; + } + + return $subcommand; + } + + function find_subcommand( &$args ) { + $name = array_shift( $args ); + + $subcommands = $this->get_subcommands(); + + if ( !isset( $subcommands[ $name ] ) ) { + $aliases = self::get_aliases( $subcommands ); + + if ( isset( $aliases[ $name ] ) ) { + $name = $aliases[ $name ]; + } + } + + if ( !isset( $subcommands[ $name ] ) ) + return false; + + return $subcommands[ $name ]; + } + + private static function get_aliases( $subcommands ) { + $aliases = array(); + + foreach ( $subcommands as $name => $subcommand ) { + $alias = $subcommand->get_alias(); + if ( $alias ) + $aliases[ $alias ] = $name; + } + + return $aliases; + } + + public function get_subcommands() { + return $this->subcommands; + } + + public function get_shortdesc() { + return $this->docparser->get_shortdesc(); + } + + public function get_full_synopsis() { + $str = array(); + + foreach ( $this->subcommands as $subcommand ) { + $str[] = $subcommand->get_full_synopsis(); + } + + return implode( "\n\n", $str ); + } + + private static function _is_good_method( $method ) { + return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); + } +} + diff --git a/php/wp-cli/classes/Dispatcher/MethodSubcommand.php b/php/wp-cli/classes/Dispatcher/MethodSubcommand.php new file mode 100644 index 000000000..5ef500c56 --- /dev/null +++ b/php/wp-cli/classes/Dispatcher/MethodSubcommand.php @@ -0,0 +1,23 @@ +<?php + +namespace WP_CLI\Dispatcher; + +class MethodSubcommand extends Subcommand { + + function __construct( $class, $method, $parent ) { + $callable = array( new $class, $method->name ); + + $docparser = new \WP_CLI\DocParser( $method ); + + $name = $docparser->get_tag( 'subcommand' ); + if ( !$name ) + $name = $method->name; + + parent::__construct( $name, $callable, $docparser, $parent ); + } + + function get_alias() { + return $this->docparser->get_tag( 'alias' ); + } +} + diff --git a/php/wp-cli/classes/Dispatcher/RootCommand.php b/php/wp-cli/classes/Dispatcher/RootCommand.php new file mode 100644 index 000000000..ce8dd38d0 --- /dev/null +++ b/php/wp-cli/classes/Dispatcher/RootCommand.php @@ -0,0 +1,118 @@ +<?php + +namespace WP_CLI\Dispatcher; + +class RootCommand implements Command, Composite { + + protected $subcommands = array(); + + function get_path() { + return array(); + } + + function show_usage() { + \WP_CLI::line( 'Available commands:' ); + + foreach ( $this->get_subcommands() as $command ) { + \WP_CLI::line( sprintf( " wp %s %s", + implode( ' ', $command->get_path() ), + implode( '|', array_keys( $command->get_subcommands() ) ) + ) ); + } + + \WP_CLI::line(<<<EOB + +See 'wp help <command>' for more information on a specific command. + +Global parameters: +--user=<id|login> set the current user +--url=<url> set the current URL +--path=<path> set the current path to the WP install +--require=<path> load a certain file before running the command +--quiet suppress informational messages +--info print wp-cli information +EOB + ); + } + + function invoke( $args, $assoc_args ) { + $subcommand = $this->pre_invoke( $args ); + $subcommand->invoke( $args, $assoc_args ); + } + + function pre_invoke( &$args ) { + if ( empty( $args ) || array( 'help' ) == $args ) { + $this->show_usage(); + exit; + } + + $cmd_name = $args[0]; + $command = $this->find_subcommand( $args ); + + if ( !$command ) + \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $cmd_name ) ); + + return $command; + } + + function find_subcommand( &$args ) { + $command = array_shift( $args ); + + $aliases = array( + 'sql' => 'db' + ); + + if ( isset( $aliases[ $command ] ) ) + $command = $aliases[ $command ]; + + return $this->load_command( $command ); + } + + function add_command( $name, $implementation ) { + if ( is_string( $implementation ) ) + $command = new CompositeCommand( $name, $implementation ); + else { + $method = new \ReflectionMethod( $implementation, '__invoke' ); + + $docparser = new \WP_CLI\DocParser( $method ); + + $command = new Subcommand( $name, $implementation, $docparser, $this ); + } + + $this->subcommands[ $name ] = $command; + } + + function get_subcommands() { + $this->load_all_commands(); + + return $this->subcommands; + } + + protected function load_all_commands() { + foreach ( glob( WP_CLI_ROOT . "/commands/*.php" ) as $filename ) { + $command = substr( basename( $filename ), 0, -4 ); + + if ( isset( $this->subcommands[ $command ] ) ) + continue; + + include $filename; + } + } + + function load_command( $command ) { + if ( !isset( $this->subcommands[$command] ) ) { + $path = WP_CLI_ROOT . "/commands/$command.php"; + + if ( is_readable( $path ) ) { + include $path; + } + } + + if ( !isset( $this->subcommands[$command] ) ) { + return false; + } + + return $this->subcommands[$command]; + } +} + diff --git a/php/wp-cli/classes/Dispatcher/Subcommand.php b/php/wp-cli/classes/Dispatcher/Subcommand.php new file mode 100644 index 000000000..a6a3d1f97 --- /dev/null +++ b/php/wp-cli/classes/Dispatcher/Subcommand.php @@ -0,0 +1,175 @@ +<?php + +namespace WP_CLI\Dispatcher; + +class Subcommand implements Command, Documentable { + + function __construct( $name, $callable, $docparser, $parent ) { + $this->name = $name; + $this->callable = $callable; + $this->docparser = $docparser; + $this->parent = $parent; + } + + function show_usage( $prefix = 'usage: ' ) { + \WP_CLI::line( $prefix . $this->get_full_synopsis() ); + } + + function get_shortdesc() { + return $this->docparser->get_shortdesc(); + } + + function get_full_synopsis() { + $full_name = implode( ' ', $this->get_path() ); + $synopsis = $this->docparser->get_synopsis(); + + return "wp $full_name $synopsis"; + } + + function invoke( $args, $assoc_args ) { + $this->check_args( $args, $assoc_args ); + + call_user_func( $this->callable, $args, $assoc_args ); + } + + function get_subcommands() { + return array(); + } + + function get_name() { + return $this->name; + } + + function get_path() { + return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); + } + + protected function check_args( $args, $assoc_args ) { + $synopsis = $this->docparser->get_synopsis(); + if ( !$synopsis ) + return; + + $accepted_params = $this->parse_synopsis( $synopsis ); + + $this->check_positional( $args, $accepted_params ); + + $this->check_assoc( $assoc_args, $accepted_params ); + + if ( empty( $accepted_params['generic'] ) ) + $this->check_unknown_assoc( $assoc_args, $accepted_params ); + } + + private function check_positional( $args, $accepted_params ) { + $count = 0; + + foreach ( $accepted_params['positional'] as $param ) { + if ( !$param['optional'] ) + $count++; + } + + if ( count( $args ) < $count ) { + $this->show_usage(); + exit(1); + } + } + + private function check_assoc( $assoc_args, $accepted_params ) { + $mandatory_assoc = array(); + + $assoc_args += \WP_CLI::get_assoc_special(); + + foreach ( $accepted_params['assoc'] as $param ) { + if ( !$param['optional'] ) + $mandatory_assoc[] = $param['name']; + } + + $errors = array(); + + foreach ( $mandatory_assoc as $key ) { + if ( !isset( $assoc_args[ $key ] ) ) + $errors[] = "missing --$key parameter"; + elseif ( true === $assoc_args[ $key ] ) + $errors[] = "--$key parameter needs a value"; + } + + if ( !empty( $errors ) ) { + foreach ( $errors as $error ) { + \WP_CLI::warning( $error ); + } + $this->show_usage(); + exit(1); + } + } + + private function check_unknown_assoc( $assoc_args, $accepted_params ) { + $known_assoc = array(); + + foreach ( array( 'assoc', 'flag' ) as $type ) { + foreach ( $accepted_params[$type] as $param ) { + $known_assoc[] = $param['name']; + } + } + + $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); + + foreach ( $unknown_assoc as $key ) { + \WP_CLI::warning( "unknown --$key parameter" ); + } + } + + protected function parse_synopsis( $synopsis ) { + list( $patterns, $params ) = self::get_patterns(); + + $tokens = preg_split( '/[\s\t]+/', $synopsis ); + + foreach ( $tokens as $token ) { + foreach ( $patterns as $regex => $desc ) { + if ( preg_match( $regex, $token, $matches ) ) { + $type = $desc['type']; + $params[$type][] = array_merge( $matches, $desc ); + break; + } + } + } + + return $params; + } + + private static function get_patterns() { + $p_name = '(?P<name>[a-z-_]+)'; + $p_value = '(?P<value>[a-z-|]+)'; + + $param_types = array( + array( 'positional', "<$p_value>", 1, 1 ), + array( 'generic', "--<field>=<value>", 1, 1 ), + array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), + array( 'flag', "--$p_name", 1, 0 ), + ); + + $patterns = array(); + $params = array(); + + foreach ( $param_types as $pt ) { + list( $type, $pattern, $optional, $mandatory ) = $pt; + + if ( $mandatory ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + } + + if ( $optional ) { + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } + + $params[ $type ] = array(); + } + + return array( $patterns, $params ); + } +} + diff --git a/php/wp-cli/classes/wp-cli.php b/php/wp-cli/classes/wp-cli.php index 0e5c2dd1b..652d86a2f 100644 --- a/php/wp-cli/classes/wp-cli.php +++ b/php/wp-cli/classes/wp-cli.php @@ -1,7 +1,7 @@ <?php -use \WP_CLI\Dispatcher; use \WP_CLI\Utils; +use \WP_CLI\Dispatcher; /** * Wrapper class for WP-CLI @@ -233,6 +233,8 @@ static function get_assoc_special() { } static function before_wp_load() { + self::$root = new Dispatcher\RootCommand; + self::add_man_dir( WP_CLI_ROOT . "../../man/", WP_CLI_ROOT . "../../man-src/" @@ -386,5 +388,3 @@ static function addCommand( $name, $class ) { } } -WP_CLI::$root = new Dispatcher\RootCommand; - diff --git a/php/wp-cli/dispatcher.php b/php/wp-cli/dispatcher.php index 20b71a398..78e12d442 100644 --- a/php/wp-cli/dispatcher.php +++ b/php/wp-cli/dispatcher.php @@ -41,433 +41,3 @@ function get_shortdesc(); function get_full_synopsis(); } - -class RootCommand implements Command, Composite { - - protected $subcommands = array(); - - function get_path() { - return array(); - } - - function show_usage() { - \WP_CLI::line( 'Available commands:' ); - - foreach ( $this->get_subcommands() as $command ) { - \WP_CLI::line( sprintf( " wp %s %s", - implode( ' ', $command->get_path() ), - implode( '|', array_keys( $command->get_subcommands() ) ) - ) ); - } - - \WP_CLI::line(<<<EOB - -See 'wp help <command>' for more information on a specific command. - -Global parameters: ---user=<id|login> set the current user ---url=<url> set the current URL ---path=<path> set the current path to the WP install ---require=<path> load a certain file before running the command ---quiet suppress informational messages ---info print wp-cli information -EOB - ); - } - - function invoke( $args, $assoc_args ) { - $subcommand = $this->pre_invoke( $args ); - $subcommand->invoke( $args, $assoc_args ); - } - - function pre_invoke( &$args ) { - if ( empty( $args ) || array( 'help' ) == $args ) { - $this->show_usage(); - exit; - } - - $cmd_name = $args[0]; - $command = $this->find_subcommand( $args ); - - if ( !$command ) - \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $cmd_name ) ); - - return $command; - } - - function find_subcommand( &$args ) { - $command = array_shift( $args ); - - $aliases = array( - 'sql' => 'db' - ); - - if ( isset( $aliases[ $command ] ) ) - $command = $aliases[ $command ]; - - return $this->load_command( $command ); - } - - function add_command( $name, $implementation ) { - if ( is_string( $implementation ) ) - $command = new CompositeCommand( $name, $implementation ); - else { - $method = new \ReflectionMethod( $implementation, '__invoke' ); - - $docparser = new \WP_CLI\DocParser( $method ); - - $command = new Subcommand( $name, $implementation, $docparser, $this ); - } - - $this->subcommands[ $name ] = $command; - } - - function get_subcommands() { - $this->load_all_commands(); - - return $this->subcommands; - } - - protected function load_all_commands() { - foreach ( glob( WP_CLI_ROOT . "/commands/*.php" ) as $filename ) { - $command = substr( basename( $filename ), 0, -4 ); - - if ( isset( $this->subcommands[ $command ] ) ) - continue; - - include $filename; - } - } - - function load_command( $command ) { - if ( !isset( $this->subcommands[$command] ) ) { - $path = WP_CLI_ROOT . "/commands/$command.php"; - - if ( is_readable( $path ) ) { - include $path; - } - } - - if ( !isset( $this->subcommands[$command] ) ) { - return false; - } - - return $this->subcommands[$command]; - } -} - - -class CompositeCommand implements Command, Composite, Documentable { - - protected $name; - - protected $subcommands; - - protected $shortdesc; - - public function __construct( $name, $class ) { - $this->name = $name; - - $reflection = new \ReflectionClass( $class ); - - $this->subcommands = $this->collect_subcommands( $reflection, $class ); - - $this->docparser = new \WP_CLI\DocParser( $reflection ); - } - - private function collect_subcommands( $reflection, $class ) { - $subcommands = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !self::_is_good_method( $method ) ) - continue; - - $subcommand = new MethodSubcommand( $class, $method, $this ); - - $subcommands[ $subcommand->get_name() ] = $subcommand; - } - - return $subcommands; - } - - function get_path() { - return array( $this->name ); - } - - function show_usage() { - $methods = $this->get_subcommands(); - - $i = 0; - - foreach ( $methods as $name => $subcommand ) { - $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - - $subcommand->show_usage( $prefix ); - } - - \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); - } - - function invoke( $args, $assoc_args ) { - $subcommand = $this->pre_invoke( $args ); - $subcommand->invoke( $args, $assoc_args ); - } - - function pre_invoke( &$args ) { - $subcommand = $this->find_subcommand( $args ); - - if ( !$subcommand ) { - $this->show_usage(); - exit; - } - - return $subcommand; - } - - function find_subcommand( &$args ) { - $name = array_shift( $args ); - - $subcommands = $this->get_subcommands(); - - if ( !isset( $subcommands[ $name ] ) ) { - $aliases = self::get_aliases( $subcommands ); - - if ( isset( $aliases[ $name ] ) ) { - $name = $aliases[ $name ]; - } - } - - if ( !isset( $subcommands[ $name ] ) ) - return false; - - return $subcommands[ $name ]; - } - - private static function get_aliases( $subcommands ) { - $aliases = array(); - - foreach ( $subcommands as $name => $subcommand ) { - $alias = $subcommand->get_alias(); - if ( $alias ) - $aliases[ $alias ] = $name; - } - - return $aliases; - } - - public function get_subcommands() { - return $this->subcommands; - } - - public function get_shortdesc() { - return $this->docparser->get_shortdesc(); - } - - public function get_full_synopsis() { - $str = array(); - - foreach ( $this->subcommands as $subcommand ) { - $str[] = $subcommand->get_full_synopsis(); - } - - return implode( "\n\n", $str ); - } - - private static function _is_good_method( $method ) { - return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); - } -} - - -class Subcommand implements Command, Documentable { - - function __construct( $name, $callable, $docparser, $parent ) { - $this->name = $name; - $this->callable = $callable; - $this->docparser = $docparser; - $this->parent = $parent; - } - - function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $prefix . $this->get_full_synopsis() ); - } - - function get_shortdesc() { - return $this->docparser->get_shortdesc(); - } - - function get_full_synopsis() { - $full_name = implode( ' ', $this->get_path() ); - $synopsis = $this->docparser->get_synopsis(); - - return "wp $full_name $synopsis"; - } - - function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); - - call_user_func( $this->callable, $args, $assoc_args ); - } - - function get_subcommands() { - return array(); - } - - function get_name() { - return $this->name; - } - - function get_path() { - return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); - } - - protected function check_args( $args, $assoc_args ) { - $synopsis = $this->docparser->get_synopsis(); - if ( !$synopsis ) - return; - - $accepted_params = $this->parse_synopsis( $synopsis ); - - $this->check_positional( $args, $accepted_params ); - - $this->check_assoc( $assoc_args, $accepted_params ); - - if ( empty( $accepted_params['generic'] ) ) - $this->check_unknown_assoc( $assoc_args, $accepted_params ); - } - - private function check_positional( $args, $accepted_params ) { - $count = 0; - - foreach ( $accepted_params['positional'] as $param ) { - if ( !$param['optional'] ) - $count++; - } - - if ( count( $args ) < $count ) { - $this->show_usage(); - exit(1); - } - } - - private function check_assoc( $assoc_args, $accepted_params ) { - $mandatory_assoc = array(); - - $assoc_args += \WP_CLI::get_assoc_special(); - - foreach ( $accepted_params['assoc'] as $param ) { - if ( !$param['optional'] ) - $mandatory_assoc[] = $param['name']; - } - - $errors = array(); - - foreach ( $mandatory_assoc as $key ) { - if ( !isset( $assoc_args[ $key ] ) ) - $errors[] = "missing --$key parameter"; - elseif ( true === $assoc_args[ $key ] ) - $errors[] = "--$key parameter needs a value"; - } - - if ( !empty( $errors ) ) { - foreach ( $errors as $error ) { - \WP_CLI::warning( $error ); - } - $this->show_usage(); - exit(1); - } - } - - private function check_unknown_assoc( $assoc_args, $accepted_params ) { - $known_assoc = array(); - - foreach ( array( 'assoc', 'flag' ) as $type ) { - foreach ( $accepted_params[$type] as $param ) { - $known_assoc[] = $param['name']; - } - } - - $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); - - foreach ( $unknown_assoc as $key ) { - \WP_CLI::warning( "unknown --$key parameter" ); - } - } - - protected function parse_synopsis( $synopsis ) { - list( $patterns, $params ) = self::get_patterns(); - - $tokens = preg_split( '/[\s\t]+/', $synopsis ); - - foreach ( $tokens as $token ) { - foreach ( $patterns as $regex => $desc ) { - if ( preg_match( $regex, $token, $matches ) ) { - $type = $desc['type']; - $params[$type][] = array_merge( $matches, $desc ); - break; - } - } - } - - return $params; - } - - private static function get_patterns() { - $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '(?P<value>[a-z-|]+)'; - - $param_types = array( - array( 'positional', "<$p_value>", 1, 1 ), - array( 'generic', "--<field>=<value>", 1, 1 ), - array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), - array( 'flag', "--$p_name", 1, 0 ), - ); - - $patterns = array(); - $params = array(); - - foreach ( $param_types as $pt ) { - list( $type, $pattern, $optional, $mandatory ) = $pt; - - if ( $mandatory ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); - } - - if ( $optional ) { - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); - } - - $params[ $type ] = array(); - } - - return array( $patterns, $params ); - } -} - - -class MethodSubcommand extends Subcommand { - - function __construct( $class, $method, $parent ) { - $callable = array( new $class, $method->name ); - - $docparser = new \WP_CLI\DocParser( $method ); - - $name = $docparser->get_tag( 'subcommand' ); - if ( !$name ) - $name = $method->name; - - parent::__construct( $name, $callable, $docparser, $parent ); - } - - function get_alias() { - return $this->docparser->get_tag( 'alias' ); - } -} - diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index 1703ba4a0..1224db990 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -34,7 +34,9 @@ function register_autoload() { $base = WP_CLI_ROOT . 'classes/'; - $path = $base . str_replace( 'WP_CLI\\', '', $class ) . '.php'; + $class = str_replace( 'WP_CLI\\', '', $class ); + + $path = $base . str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php'; if ( is_file( $path ) ) { require_once $path; From 113a3760f185faef7924b9a2291c0848d6193571 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:20:19 +0200 Subject: [PATCH 0971/5359] move non-namespaceable classes out of /classes/ folder --- .../{classes/wp-cli-command.php => class-wp-cli-command.php} | 0 php/wp-cli/{classes/wp-cli.php => class-wp-cli.php} | 0 php/wp-cli/wp-cli.php | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename php/wp-cli/{classes/wp-cli-command.php => class-wp-cli-command.php} (100%) rename php/wp-cli/{classes/wp-cli.php => class-wp-cli.php} (100%) diff --git a/php/wp-cli/classes/wp-cli-command.php b/php/wp-cli/class-wp-cli-command.php similarity index 100% rename from php/wp-cli/classes/wp-cli-command.php rename to php/wp-cli/class-wp-cli-command.php diff --git a/php/wp-cli/classes/wp-cli.php b/php/wp-cli/class-wp-cli.php similarity index 100% rename from php/wp-cli/classes/wp-cli.php rename to php/wp-cli/class-wp-cli.php diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index 81056eb3b..ff4987d5b 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -9,8 +9,8 @@ include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; -include WP_CLI_ROOT . 'classes/wp-cli.php'; -include WP_CLI_ROOT . 'classes/wp-cli-command.php'; +include WP_CLI_ROOT . 'class-wp-cli.php'; +include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'man.php'; \WP_CLI\Utils\register_autoload(); From 4f7a23cf440c88c201a2655a849d854bf1f2ec10 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:24:10 +0200 Subject: [PATCH 0972/5359] make autoloader PSR-0 --- php/wp-cli/{classes => WP_CLI}/CommandWithMeta.php | 0 php/wp-cli/{classes => WP_CLI}/CommandWithUpgrade.php | 0 .../{classes => WP_CLI}/Dispatcher/CompositeCommand.php | 0 .../{classes => WP_CLI}/Dispatcher/MethodSubcommand.php | 0 php/wp-cli/{classes => WP_CLI}/Dispatcher/RootCommand.php | 0 php/wp-cli/{classes => WP_CLI}/Dispatcher/Subcommand.php | 0 php/wp-cli/{classes => WP_CLI}/DocParser.php | 0 .../{classes => WP_CLI}/NonDestructiveCoreUpgrader.php | 0 php/wp-cli/{classes => WP_CLI}/UpgraderSkin.php | 0 php/wp-cli/utils.php | 6 +----- 10 files changed, 1 insertion(+), 5 deletions(-) rename php/wp-cli/{classes => WP_CLI}/CommandWithMeta.php (100%) rename php/wp-cli/{classes => WP_CLI}/CommandWithUpgrade.php (100%) rename php/wp-cli/{classes => WP_CLI}/Dispatcher/CompositeCommand.php (100%) rename php/wp-cli/{classes => WP_CLI}/Dispatcher/MethodSubcommand.php (100%) rename php/wp-cli/{classes => WP_CLI}/Dispatcher/RootCommand.php (100%) rename php/wp-cli/{classes => WP_CLI}/Dispatcher/Subcommand.php (100%) rename php/wp-cli/{classes => WP_CLI}/DocParser.php (100%) rename php/wp-cli/{classes => WP_CLI}/NonDestructiveCoreUpgrader.php (100%) rename php/wp-cli/{classes => WP_CLI}/UpgraderSkin.php (100%) diff --git a/php/wp-cli/classes/CommandWithMeta.php b/php/wp-cli/WP_CLI/CommandWithMeta.php similarity index 100% rename from php/wp-cli/classes/CommandWithMeta.php rename to php/wp-cli/WP_CLI/CommandWithMeta.php diff --git a/php/wp-cli/classes/CommandWithUpgrade.php b/php/wp-cli/WP_CLI/CommandWithUpgrade.php similarity index 100% rename from php/wp-cli/classes/CommandWithUpgrade.php rename to php/wp-cli/WP_CLI/CommandWithUpgrade.php diff --git a/php/wp-cli/classes/Dispatcher/CompositeCommand.php b/php/wp-cli/WP_CLI/Dispatcher/CompositeCommand.php similarity index 100% rename from php/wp-cli/classes/Dispatcher/CompositeCommand.php rename to php/wp-cli/WP_CLI/Dispatcher/CompositeCommand.php diff --git a/php/wp-cli/classes/Dispatcher/MethodSubcommand.php b/php/wp-cli/WP_CLI/Dispatcher/MethodSubcommand.php similarity index 100% rename from php/wp-cli/classes/Dispatcher/MethodSubcommand.php rename to php/wp-cli/WP_CLI/Dispatcher/MethodSubcommand.php diff --git a/php/wp-cli/classes/Dispatcher/RootCommand.php b/php/wp-cli/WP_CLI/Dispatcher/RootCommand.php similarity index 100% rename from php/wp-cli/classes/Dispatcher/RootCommand.php rename to php/wp-cli/WP_CLI/Dispatcher/RootCommand.php diff --git a/php/wp-cli/classes/Dispatcher/Subcommand.php b/php/wp-cli/WP_CLI/Dispatcher/Subcommand.php similarity index 100% rename from php/wp-cli/classes/Dispatcher/Subcommand.php rename to php/wp-cli/WP_CLI/Dispatcher/Subcommand.php diff --git a/php/wp-cli/classes/DocParser.php b/php/wp-cli/WP_CLI/DocParser.php similarity index 100% rename from php/wp-cli/classes/DocParser.php rename to php/wp-cli/WP_CLI/DocParser.php diff --git a/php/wp-cli/classes/NonDestructiveCoreUpgrader.php b/php/wp-cli/WP_CLI/NonDestructiveCoreUpgrader.php similarity index 100% rename from php/wp-cli/classes/NonDestructiveCoreUpgrader.php rename to php/wp-cli/WP_CLI/NonDestructiveCoreUpgrader.php diff --git a/php/wp-cli/classes/UpgraderSkin.php b/php/wp-cli/WP_CLI/UpgraderSkin.php similarity index 100% rename from php/wp-cli/classes/UpgraderSkin.php rename to php/wp-cli/WP_CLI/UpgraderSkin.php diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index 1224db990..752758d3e 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -32,11 +32,7 @@ function register_autoload() { return; } - $base = WP_CLI_ROOT . 'classes/'; - - $class = str_replace( 'WP_CLI\\', '', $class ); - - $path = $base . str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php'; + $path = WP_CLI_ROOT . str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php'; if ( is_file( $path ) ) { require_once $path; From 9873b894b2844e46a3165d11904ec561a1eba9b4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:28:22 +0200 Subject: [PATCH 0973/5359] Use Composer's autoloader, when available --- composer.json | 3 +++ php/wp-cli/utils.php | 9 +++++---- php/wp-cli/wp-cli.php | 3 +-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 2cb9f8c81..62e97907d 100644 --- a/composer.json +++ b/composer.json @@ -14,5 +14,8 @@ "require-dev": { "phpunit/phpunit": "3.7.x" }, + "autoload": { + "psr-0": { "WP_CLI": "php/wp-cli" } + }, "minimum-stability": "dev" } diff --git a/php/wp-cli/utils.php b/php/wp-cli/utils.php index 752758d3e..a10ba516a 100644 --- a/php/wp-cli/utils.php +++ b/php/wp-cli/utils.php @@ -2,26 +2,27 @@ namespace WP_CLI\Utils; -function load_cli_tools() { +function bootstrap() { $vendor_paths = array( WP_CLI_ROOT . '../../../../../vendor', // part of a larger project WP_CLI_ROOT . '../../vendor', // top-level project ); - $found = false; + $has_autoload = false; foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; include $vendor_path . '/wp-cli/php-cli-tools/lib/cli/cli.php'; - $found = true; + $has_autoload = true; break; } } - if ( !$found ) { + if ( !$has_autoload ) { include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); + register_autoload(); } } diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli/wp-cli.php index ff4987d5b..a248bdb28 100755 --- a/php/wp-cli/wp-cli.php +++ b/php/wp-cli/wp-cli.php @@ -13,8 +13,7 @@ include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'man.php'; -\WP_CLI\Utils\register_autoload(); -\WP_CLI\Utils\load_cli_tools(); +\WP_CLI\Utils\bootstrap(); WP_CLI::before_wp_load(); From be8b90833e89dc8bb1ee16001fe4d616630f488d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:48:00 +0200 Subject: [PATCH 0974/5359] autoload query iterator classes --- .gitmodules | 3 - php/query-iterators | 1 - php/wp-cli/WP_CLI/QueryIterator.php | 100 +++++++++++++++++++++++++ php/wp-cli/WP_CLI/TableIterator.php | 81 ++++++++++++++++++++ php/wp-cli/commands/search-replace.php | 4 +- 5 files changed, 182 insertions(+), 7 deletions(-) delete mode 160000 php/query-iterators create mode 100644 php/wp-cli/WP_CLI/QueryIterator.php create mode 100644 php/wp-cli/WP_CLI/TableIterator.php diff --git a/.gitmodules b/.gitmodules index d70ec97df..bf7ca3df3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "php/php-cli-tools"] path = php/php-cli-tools url = git://github.com/wp-cli/php-cli-tools.git -[submodule "php/query-iterators"] - path = php/query-iterators - url = https://gist.github.com/4378217.git diff --git a/php/query-iterators b/php/query-iterators deleted file mode 160000 index 7cb209489..000000000 --- a/php/query-iterators +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7cb209489a356c6b18bb910a291df13a6c258b96 diff --git a/php/wp-cli/WP_CLI/QueryIterator.php b/php/wp-cli/WP_CLI/QueryIterator.php new file mode 100644 index 000000000..3962d1108 --- /dev/null +++ b/php/wp-cli/WP_CLI/QueryIterator.php @@ -0,0 +1,100 @@ +<?php + +namespace WP_CLI; + +/** + * Iterates over results of a query, split into many queries via LIMIT and OFFSET + * + * @source https://gist.github.com/4060005 + */ +class QueryIterator implements \Iterator { + + private $limit = 500; + private $query = ''; + + private $global_index = 0; + private $index_in_results = 0; + private $results = array(); + private $offset = 0; + private $db = null; + private $depleted = false; + + /** + * Creates a new query iterator + * + * This will loop over all users, but will retrieve them 100 by 100: + * <code> + * foreach( new QueryIterator( array( 'query' => 'SELECT * FROM users', 'limit' => 100 ) ) as $user ) { + * tickle( $user ); + * } + * </code> + * + * + * @param array $args Supported arguments: + * query – the query as a string. It shouldn't include any LIMIT clauses + * limit – (optional) how many rows to retrieve at once, default value is 500 + */ + function __construct( $args = array() ) { + $this->db = $GLOBALS['wpdb']; + foreach( $args as $key => $value ) { + $this->$key = $value; + } + if ( !$this->query ) { + throw new InvalidArgumentException( 'Missing query argument.' ); + } + } + + function load_items_from_db() { + $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->limit, $this->offset ); + $this->results = $this->db->get_results( $query ); + if ( !$this->results ) { + if ( $this->db->last_error ) { + throw new QueryIteratorException( 'Database error: '.$this->db->last_error ); + } else { + return false; + } + } + $this->offset += $this->limit; + return true; + } + + function current() { + return $this->results[$this->index_in_results]; + } + + function key() { + return $this->global_index; + } + + function next() { + $this->index_in_results++; + $this->global_index++; + } + + function rewind() { + $this->results = array(); + $this->global_index = 0; + $this->index_in_results = 0; + $this->offset = 0; + $this->depleted = false; + } + + function valid() { + if ( $this->depleted ) { + return false; + } + if ( !isset( $this->results[$this->index_in_results] ) ) { + $items_loaded = $this->load_items_from_db(); + if ( !$items_loaded ) { + $this->rewind(); + $this->depleted = true; + return false; + } + $this->index_in_results = 0; + } + return true; + } +} + +class QueryIteratorException extends \RuntimeException {} + diff --git a/php/wp-cli/WP_CLI/TableIterator.php b/php/wp-cli/WP_CLI/TableIterator.php new file mode 100644 index 000000000..ef8bf8905 --- /dev/null +++ b/php/wp-cli/WP_CLI/TableIterator.php @@ -0,0 +1,81 @@ +<?php + +namespace WP_CLI; + +/** + * @source https://gist.github.com/4060005 + */ +class TableIterator extends QueryIterator { + + /** + * Creates an iterator over a database table + * + * <code> + * foreach( new TableIterator( array( 'table' => $wpdb->posts, 'fields' => array( 'ID', 'post_content' ) ) ) as $post ) { + * count_words_for( $post->ID, $post->post_content ); + * } + * </code> + * + * <code> + * foreach( new TableIterator( array( 'table' => $wpdb->posts, 'where' => 'ID = 8 OR post_status = "publish"' ) ) as $post ) { + * … + * } + * </code> + * + * <code> + * foreach( new PostIterator( array( 'table' => $wpdb->posts, 'where' => array( 'post_status' => 'publish', 'post_date_gmt BETWEEN x AND y' ) ) ) as $post ) { + * … + * } + * </code> + * + * + * @param array $args Supported arguments: + * table – the name of the database table + * fields – an array of columns to get from the posst table, * is a valid value and the default + * where – conditions for filtering rows. Supports two formats: + * = string – this will be the where clause + * = array – each element is treated as a condition if it's positional, or as column => value if + * it's a key/value pair. In the latter case the value is automatically quoted and escaped + */ + function __construct( $args = array() ) { + global $wpdb; + + $defaults = array( + 'fields' => array( '*' ), + 'where' => array(), + 'table' => null, + ); + $table = $args['table']; + $args = array_merge( $defaults, $args ); + + $fields = self::build_fields( $args['fields'] ); + $conditions = self::build_where_conditions( $args['where'] ); + $where_sql = $conditions? " WHERE $conditions" : ''; + $query = "SELECT $fields FROM $table $where_sql"; + $parent_args = compact( 'query' ); + if ( isset( $args['limit'] ) ) { + $parent_args['limit'] = $args['limit']; + } + parent::__construct( $parent_args ); + } + + static function build_fields( $fields ) { + return implode( ', ', $fields ); + } + + static function build_where_conditions( $where ) { + global $wpdb; + if ( is_array( $where ) ) { + $conditions = array(); + foreach( $where as $key => $value ) { + if ( is_numeric( $key ) ) + $conditions[] = $value; + else + $conditions[] = $key . ' = "' . $wpdb->escape( $value ) .'"'; + } + $where = implode( ' AND ', $conditions ); + } + return $where; + } +} + diff --git a/php/wp-cli/commands/search-replace.php b/php/wp-cli/commands/search-replace.php index 71bb7d524..963b21124 100644 --- a/php/wp-cli/commands/search-replace.php +++ b/php/wp-cli/commands/search-replace.php @@ -13,8 +13,6 @@ class Search_Replace_Command extends WP_CLI_Command { * @synopsis <old> <new> [--dry-run] */ public function __invoke( $args, $assoc_args ) { - require_once WP_CLI_ROOT . '../query-iterators/class-table-iterator.php'; - global $wpdb; list( $old, $new ) = $args; @@ -59,7 +57,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'limit' => 1000 ); - $it = new TableIterator( $args ); + $it = new \WP_CLI\TableIterator( $args ); $count = 0; From 01dcff1ccad5e9656c67c14b5be05a45642b5414 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 11:56:09 +0200 Subject: [PATCH 0975/5359] move everything from /php/wp-cli/ to /php/ --- bin/wp | 2 +- composer.json | 2 +- php/{wp-cli => }/WP_CLI/CommandWithMeta.php | 0 php/{wp-cli => }/WP_CLI/CommandWithUpgrade.php | 0 php/{wp-cli => }/WP_CLI/Dispatcher/CompositeCommand.php | 0 php/{wp-cli => }/WP_CLI/Dispatcher/MethodSubcommand.php | 0 php/{wp-cli => }/WP_CLI/Dispatcher/RootCommand.php | 0 php/{wp-cli => }/WP_CLI/Dispatcher/Subcommand.php | 0 php/{wp-cli => }/WP_CLI/DocParser.php | 0 php/{wp-cli => }/WP_CLI/NonDestructiveCoreUpgrader.php | 0 php/{wp-cli => }/WP_CLI/QueryIterator.php | 0 php/{wp-cli => }/WP_CLI/TableIterator.php | 0 php/{wp-cli => }/WP_CLI/UpgraderSkin.php | 0 php/{wp-cli => }/class-wp-cli-command.php | 0 php/{wp-cli => }/class-wp-cli.php | 0 php/{wp-cli => }/commands/blog.php | 0 php/{wp-cli => }/commands/cache.php | 0 php/{wp-cli => }/commands/cap.php | 0 php/{wp-cli => }/commands/comment.php | 0 php/{wp-cli => }/commands/core.php | 0 php/{wp-cli => }/commands/db.php | 0 php/{wp-cli => }/commands/eval-file.php | 0 php/{wp-cli => }/commands/eval.php | 0 php/{wp-cli => }/commands/export.php | 0 php/{wp-cli => }/commands/help.php | 0 php/{wp-cli => }/commands/home.php | 0 php/{wp-cli => }/commands/option.php | 0 php/{wp-cli => }/commands/plugin.php | 0 php/{wp-cli => }/commands/post-meta.php | 0 php/{wp-cli => }/commands/post.php | 0 php/{wp-cli => }/commands/rewrite.php | 0 php/{wp-cli => }/commands/search-replace.php | 0 php/{wp-cli => }/commands/shell.php | 0 php/{wp-cli => }/commands/theme.php | 0 php/{wp-cli => }/commands/transient.php | 0 php/{wp-cli => }/commands/user-meta.php | 0 php/{wp-cli => }/commands/user.php | 0 php/{wp-cli => }/dispatcher.php | 0 php/{wp-cli => }/man.php | 0 php/{wp-cli => }/utils.php | 6 +++--- php/{wp-cli => }/wp-cli-boot.php | 0 php/{wp-cli => }/wp-cli.php | 0 php/{wp-cli => }/wp-settings.php | 0 43 files changed, 5 insertions(+), 5 deletions(-) rename php/{wp-cli => }/WP_CLI/CommandWithMeta.php (100%) rename php/{wp-cli => }/WP_CLI/CommandWithUpgrade.php (100%) rename php/{wp-cli => }/WP_CLI/Dispatcher/CompositeCommand.php (100%) rename php/{wp-cli => }/WP_CLI/Dispatcher/MethodSubcommand.php (100%) rename php/{wp-cli => }/WP_CLI/Dispatcher/RootCommand.php (100%) rename php/{wp-cli => }/WP_CLI/Dispatcher/Subcommand.php (100%) rename php/{wp-cli => }/WP_CLI/DocParser.php (100%) rename php/{wp-cli => }/WP_CLI/NonDestructiveCoreUpgrader.php (100%) rename php/{wp-cli => }/WP_CLI/QueryIterator.php (100%) rename php/{wp-cli => }/WP_CLI/TableIterator.php (100%) rename php/{wp-cli => }/WP_CLI/UpgraderSkin.php (100%) rename php/{wp-cli => }/class-wp-cli-command.php (100%) rename php/{wp-cli => }/class-wp-cli.php (100%) rename php/{wp-cli => }/commands/blog.php (100%) rename php/{wp-cli => }/commands/cache.php (100%) rename php/{wp-cli => }/commands/cap.php (100%) rename php/{wp-cli => }/commands/comment.php (100%) rename php/{wp-cli => }/commands/core.php (100%) rename php/{wp-cli => }/commands/db.php (100%) rename php/{wp-cli => }/commands/eval-file.php (100%) rename php/{wp-cli => }/commands/eval.php (100%) rename php/{wp-cli => }/commands/export.php (100%) rename php/{wp-cli => }/commands/help.php (100%) rename php/{wp-cli => }/commands/home.php (100%) rename php/{wp-cli => }/commands/option.php (100%) rename php/{wp-cli => }/commands/plugin.php (100%) rename php/{wp-cli => }/commands/post-meta.php (100%) rename php/{wp-cli => }/commands/post.php (100%) rename php/{wp-cli => }/commands/rewrite.php (100%) rename php/{wp-cli => }/commands/search-replace.php (100%) rename php/{wp-cli => }/commands/shell.php (100%) rename php/{wp-cli => }/commands/theme.php (100%) rename php/{wp-cli => }/commands/transient.php (100%) rename php/{wp-cli => }/commands/user-meta.php (100%) rename php/{wp-cli => }/commands/user.php (100%) rename php/{wp-cli => }/dispatcher.php (100%) rename php/{wp-cli => }/man.php (100%) rename php/{wp-cli => }/utils.php (97%) rename php/{wp-cli => }/wp-cli-boot.php (100%) rename php/{wp-cli => }/wp-cli.php (100%) rename php/{wp-cli => }/wp-settings.php (100%) diff --git a/bin/wp b/bin/wp index fd25093a8..aeebd4d50 100755 --- a/bin/wp +++ b/bin/wp @@ -28,7 +28,7 @@ if [ ! -d $SCRIPT_PATH ]; then SCRIPT_PATH=$(dirname "$SELF_PATH")/../php fi -SCRIPT_PATH=$SCRIPT_PATH/wp-cli/wp-cli-boot.php +SCRIPT_PATH=$SCRIPT_PATH/wp-cli-boot.php case $(uname -a) in CYGWIN*) diff --git a/composer.json b/composer.json index 62e97907d..c4d8fec42 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "phpunit/phpunit": "3.7.x" }, "autoload": { - "psr-0": { "WP_CLI": "php/wp-cli" } + "psr-0": { "WP_CLI": "php" } }, "minimum-stability": "dev" } diff --git a/php/wp-cli/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php similarity index 100% rename from php/wp-cli/WP_CLI/CommandWithMeta.php rename to php/WP_CLI/CommandWithMeta.php diff --git a/php/wp-cli/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php similarity index 100% rename from php/wp-cli/WP_CLI/CommandWithUpgrade.php rename to php/WP_CLI/CommandWithUpgrade.php diff --git a/php/wp-cli/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php similarity index 100% rename from php/wp-cli/WP_CLI/Dispatcher/CompositeCommand.php rename to php/WP_CLI/Dispatcher/CompositeCommand.php diff --git a/php/wp-cli/WP_CLI/Dispatcher/MethodSubcommand.php b/php/WP_CLI/Dispatcher/MethodSubcommand.php similarity index 100% rename from php/wp-cli/WP_CLI/Dispatcher/MethodSubcommand.php rename to php/WP_CLI/Dispatcher/MethodSubcommand.php diff --git a/php/wp-cli/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php similarity index 100% rename from php/wp-cli/WP_CLI/Dispatcher/RootCommand.php rename to php/WP_CLI/Dispatcher/RootCommand.php diff --git a/php/wp-cli/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php similarity index 100% rename from php/wp-cli/WP_CLI/Dispatcher/Subcommand.php rename to php/WP_CLI/Dispatcher/Subcommand.php diff --git a/php/wp-cli/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php similarity index 100% rename from php/wp-cli/WP_CLI/DocParser.php rename to php/WP_CLI/DocParser.php diff --git a/php/wp-cli/WP_CLI/NonDestructiveCoreUpgrader.php b/php/WP_CLI/NonDestructiveCoreUpgrader.php similarity index 100% rename from php/wp-cli/WP_CLI/NonDestructiveCoreUpgrader.php rename to php/WP_CLI/NonDestructiveCoreUpgrader.php diff --git a/php/wp-cli/WP_CLI/QueryIterator.php b/php/WP_CLI/QueryIterator.php similarity index 100% rename from php/wp-cli/WP_CLI/QueryIterator.php rename to php/WP_CLI/QueryIterator.php diff --git a/php/wp-cli/WP_CLI/TableIterator.php b/php/WP_CLI/TableIterator.php similarity index 100% rename from php/wp-cli/WP_CLI/TableIterator.php rename to php/WP_CLI/TableIterator.php diff --git a/php/wp-cli/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php similarity index 100% rename from php/wp-cli/WP_CLI/UpgraderSkin.php rename to php/WP_CLI/UpgraderSkin.php diff --git a/php/wp-cli/class-wp-cli-command.php b/php/class-wp-cli-command.php similarity index 100% rename from php/wp-cli/class-wp-cli-command.php rename to php/class-wp-cli-command.php diff --git a/php/wp-cli/class-wp-cli.php b/php/class-wp-cli.php similarity index 100% rename from php/wp-cli/class-wp-cli.php rename to php/class-wp-cli.php diff --git a/php/wp-cli/commands/blog.php b/php/commands/blog.php similarity index 100% rename from php/wp-cli/commands/blog.php rename to php/commands/blog.php diff --git a/php/wp-cli/commands/cache.php b/php/commands/cache.php similarity index 100% rename from php/wp-cli/commands/cache.php rename to php/commands/cache.php diff --git a/php/wp-cli/commands/cap.php b/php/commands/cap.php similarity index 100% rename from php/wp-cli/commands/cap.php rename to php/commands/cap.php diff --git a/php/wp-cli/commands/comment.php b/php/commands/comment.php similarity index 100% rename from php/wp-cli/commands/comment.php rename to php/commands/comment.php diff --git a/php/wp-cli/commands/core.php b/php/commands/core.php similarity index 100% rename from php/wp-cli/commands/core.php rename to php/commands/core.php diff --git a/php/wp-cli/commands/db.php b/php/commands/db.php similarity index 100% rename from php/wp-cli/commands/db.php rename to php/commands/db.php diff --git a/php/wp-cli/commands/eval-file.php b/php/commands/eval-file.php similarity index 100% rename from php/wp-cli/commands/eval-file.php rename to php/commands/eval-file.php diff --git a/php/wp-cli/commands/eval.php b/php/commands/eval.php similarity index 100% rename from php/wp-cli/commands/eval.php rename to php/commands/eval.php diff --git a/php/wp-cli/commands/export.php b/php/commands/export.php similarity index 100% rename from php/wp-cli/commands/export.php rename to php/commands/export.php diff --git a/php/wp-cli/commands/help.php b/php/commands/help.php similarity index 100% rename from php/wp-cli/commands/help.php rename to php/commands/help.php diff --git a/php/wp-cli/commands/home.php b/php/commands/home.php similarity index 100% rename from php/wp-cli/commands/home.php rename to php/commands/home.php diff --git a/php/wp-cli/commands/option.php b/php/commands/option.php similarity index 100% rename from php/wp-cli/commands/option.php rename to php/commands/option.php diff --git a/php/wp-cli/commands/plugin.php b/php/commands/plugin.php similarity index 100% rename from php/wp-cli/commands/plugin.php rename to php/commands/plugin.php diff --git a/php/wp-cli/commands/post-meta.php b/php/commands/post-meta.php similarity index 100% rename from php/wp-cli/commands/post-meta.php rename to php/commands/post-meta.php diff --git a/php/wp-cli/commands/post.php b/php/commands/post.php similarity index 100% rename from php/wp-cli/commands/post.php rename to php/commands/post.php diff --git a/php/wp-cli/commands/rewrite.php b/php/commands/rewrite.php similarity index 100% rename from php/wp-cli/commands/rewrite.php rename to php/commands/rewrite.php diff --git a/php/wp-cli/commands/search-replace.php b/php/commands/search-replace.php similarity index 100% rename from php/wp-cli/commands/search-replace.php rename to php/commands/search-replace.php diff --git a/php/wp-cli/commands/shell.php b/php/commands/shell.php similarity index 100% rename from php/wp-cli/commands/shell.php rename to php/commands/shell.php diff --git a/php/wp-cli/commands/theme.php b/php/commands/theme.php similarity index 100% rename from php/wp-cli/commands/theme.php rename to php/commands/theme.php diff --git a/php/wp-cli/commands/transient.php b/php/commands/transient.php similarity index 100% rename from php/wp-cli/commands/transient.php rename to php/commands/transient.php diff --git a/php/wp-cli/commands/user-meta.php b/php/commands/user-meta.php similarity index 100% rename from php/wp-cli/commands/user-meta.php rename to php/commands/user-meta.php diff --git a/php/wp-cli/commands/user.php b/php/commands/user.php similarity index 100% rename from php/wp-cli/commands/user.php rename to php/commands/user.php diff --git a/php/wp-cli/dispatcher.php b/php/dispatcher.php similarity index 100% rename from php/wp-cli/dispatcher.php rename to php/dispatcher.php diff --git a/php/wp-cli/man.php b/php/man.php similarity index 100% rename from php/wp-cli/man.php rename to php/man.php diff --git a/php/wp-cli/utils.php b/php/utils.php similarity index 97% rename from php/wp-cli/utils.php rename to php/utils.php index a10ba516a..a47469344 100644 --- a/php/wp-cli/utils.php +++ b/php/utils.php @@ -4,8 +4,8 @@ function bootstrap() { $vendor_paths = array( - WP_CLI_ROOT . '../../../../../vendor', // part of a larger project - WP_CLI_ROOT . '../../vendor', // top-level project + WP_CLI_ROOT . '../../../../vendor', // part of a larger project + WP_CLI_ROOT . '../vendor', // top-level project ); $has_autoload = false; @@ -20,7 +20,7 @@ function bootstrap() { } if ( !$has_autoload ) { - include WP_CLI_ROOT . '../php-cli-tools/lib/cli/cli.php'; + include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); register_autoload(); } diff --git a/php/wp-cli/wp-cli-boot.php b/php/wp-cli-boot.php similarity index 100% rename from php/wp-cli/wp-cli-boot.php rename to php/wp-cli-boot.php diff --git a/php/wp-cli/wp-cli.php b/php/wp-cli.php similarity index 100% rename from php/wp-cli/wp-cli.php rename to php/wp-cli.php diff --git a/php/wp-cli/wp-settings.php b/php/wp-settings.php similarity index 100% rename from php/wp-cli/wp-settings.php rename to php/wp-settings.php From f477b06701e0169fa6add54d0ee203754a553f5c Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 27 Dec 2012 22:28:59 +0100 Subject: [PATCH 0976/5359] Corrected the paramaters of the sprintf within post_update_messages --- .../internals/skeletons/post_type_skeleton.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index d3c5e7dfc..1b06f2c64 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -46,19 +46,19 @@ function {$machine_name}_updated_messages( \$messages ) { \$messages['{$post_type}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%1\$s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), 2 => __('Custom field updated.', '{$textdomain}'), 3 => __('Custom field deleted.', '{$textdomain}'), 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), /* translators: %s: date and time of the revision */ 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%1\$s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%1\$s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"\">Preview {$label}</a>', '{$textdomain}'), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"%2\$s\">Preview {$label}</a>', '{$textdomain}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%1\$s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), ); return \$messages; From b9a397ef94c6e1e9f3cce2ace7630f4929e600b3 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 01:16:35 +0100 Subject: [PATCH 0977/5359] Added a init for each taxonomy just like the post types have --- src/php/wp-cli/commands/internals/scaffold.php | 2 +- .../commands/internals/skeletons/taxonomy_skeleton.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 6c5883f5a..6764e409d 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -87,7 +87,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php index de7c5e7ad..1d299b7d1 100755 --- a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php @@ -1,7 +1,7 @@ <?php $output = "<?php -if ( !taxonomy_exists( '{$taxonomy}' ) ) : +function {$machine_name}_init() { \$labels = array( 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), @@ -44,4 +44,5 @@ register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args ); -endif;"; \ No newline at end of file +} +add_action( 'init', '{$machine_name}_init' );"; \ No newline at end of file From 64a876ea8c2c17ebfc6071a8cbb4492769007865 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 28 Dec 2012 01:47:48 +0000 Subject: [PATCH 0978/5359] Always return the list of subcommands as alphabetically sorted. This ensures commands added by plugins are added in their proper place. --- php/WP_CLI/Dispatcher/RootCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index ce8dd38d0..a98683e12 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -85,6 +85,8 @@ function add_command( $name, $implementation ) { function get_subcommands() { $this->load_all_commands(); + ksort( $this->subcommands ); + return $this->subcommands; } From c4edcfa1e737cfb29d40b91a70b239288f1d96eb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 12:16:35 +0200 Subject: [PATCH 0979/5359] fix path to man dirs; see #250 --- php/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 652d86a2f..04ea5cf68 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -236,8 +236,8 @@ static function before_wp_load() { self::$root = new Dispatcher\RootCommand; self::add_man_dir( - WP_CLI_ROOT . "../../man/", - WP_CLI_ROOT . "../../man-src/" + WP_CLI_ROOT . "../man/", + WP_CLI_ROOT . "../man-src/" ); self::parse_args(); From 78fdf15f2f5ec0ac1d7004506178b7ca77f5ca32 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 12:17:58 +0200 Subject: [PATCH 0980/5359] add search-replace man txt. see #249 --- man-src/search-replace.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 man-src/search-replace.txt diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt new file mode 100644 index 000000000..0e7f4cff1 --- /dev/null +++ b/man-src/search-replace.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--dry-run`: + + Show report, but don't perform the changes. + +## EXAMPLES + + wp search-replace 'http://example.dev' 'http://example.com' --dry-run From 0305a32720a8bf6fc5dcb0de4ffe79aae6e7236e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 26 Dec 2012 12:18:20 +0200 Subject: [PATCH 0981/5359] refresh man pages --- man-src/option.txt | 2 +- man-src/post-meta.txt | 2 +- man-src/user-meta.txt | 2 +- man/option.1 | 2 +- man/post-meta.1 | 2 +- man/post-update.1 | 2 +- man/search-replace.1 | 27 +++++++++++++++++++++++++++ man/user-meta.1 | 2 +- man/user-remove-role.1 | 4 ++-- man/user-set-role.1 | 2 +- php/commands/search-replace.php | 4 ++-- 11 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 man/search-replace.1 diff --git a/man-src/option.txt b/man-src/option.txt index 238e5f66b..423e81669 100644 --- a/man-src/option.txt +++ b/man-src/option.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `json`: +* `--json`: Encode/decode values as JSON. diff --git a/man-src/post-meta.txt b/man-src/post-meta.txt index e36dcb239..974a2bd7b 100644 --- a/man-src/post-meta.txt +++ b/man-src/post-meta.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `json`: +* `--json`: Encode/decode values as JSON. diff --git a/man-src/user-meta.txt b/man-src/user-meta.txt index ad8d85bdb..9db91bbf1 100644 --- a/man-src/user-meta.txt +++ b/man-src/user-meta.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `json`: +* `--json`: Encode/decode values as JSON. diff --git a/man/option.1 b/man/option.1 index 12b38c6b7..b22d66884 100644 --- a/man/option.1 +++ b/man/option.1 @@ -48,7 +48,7 @@ Delete an option\. . .TP -\fBjson\fR: +\fB\-\-json\fR: . .IP Encode/decode values as JSON\. diff --git a/man/post-meta.1 b/man/post-meta.1 index 3b3fc962f..c6cc6067e 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -48,7 +48,7 @@ Update a meta field\. . .TP -\fBjson\fR: +\fB\-\-json\fR: . .IP Encode/decode values as JSON\. diff --git a/man/post-update.1 b/man/post-update.1 index 4fd90c475..534a319d4 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -7,7 +7,7 @@ \fBwp\-post\-update\fR \- Update a post\. . .SH "SYNOPSIS" -wp post update \fIid\fR \-\-\fIfield\fR=\fIvalue\fR +wp post update \fIid\fR\.\.\. \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . diff --git a/man/search-replace.1 b/man/search-replace.1 new file mode 100644 index 000000000..b22472392 --- /dev/null +++ b/man/search-replace.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SEARCH\-REPLACE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-search\-replace\fR \- Search/replace strings in the database\. +. +.SH "SYNOPSIS" +wp search\-replace \fIold\fR \fInew\fR [\-\-dry\-run] +. +.SH "OPTIONS" +. +.TP +\fB\-\-dry\-run\fR: +. +.IP +Show report, but don\'t perform the changes\. +. +.SH "EXAMPLES" +. +.nf + +wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-dry\-run +. +.fi + diff --git a/man/user-meta.1 b/man/user-meta.1 index b304a99f9..25719cdbc 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -48,7 +48,7 @@ Update a meta field\. . .TP -\fBjson\fR: +\fB\-\-json\fR: . .IP Encode/decode values as JSON\. diff --git a/man/user-remove-role.1 b/man/user-remove-role.1 index 232a68c91..e6e0360a9 100644 --- a/man/user-remove-role.1 +++ b/man/user-remove-role.1 @@ -4,10 +4,10 @@ .TH "WP\-USER\-REMOVE\-ROLE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-remove\-role\fR \- Remove a user from a blog\. +\fBwp\-user\-remove\-role\fR \- Remove a user\'s role\. . .SH "SYNOPSIS" -wp user remove\-role \fIuser\-login\fR +wp user remove\-role \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] . .SH "OPTIONS" . diff --git a/man/user-set-role.1 b/man/user-set-role.1 index bb8ca4670..edd5ea550 100644 --- a/man/user-set-role.1 +++ b/man/user-set-role.1 @@ -4,7 +4,7 @@ .TH "WP\-USER\-SET\-ROLE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-set\-role\fR \- Add a user to a blog\. +\fBwp\-user\-set\-role\fR \- Set the user role (for a particular blog)\. . .SH "SYNOPSIS" wp user set\-role \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 963b21124..0b88b388f 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -3,13 +3,13 @@ WP_CLI::add_command( 'search-replace', new Search_Replace_Command ); /** - * Search/Replace strings in the database. - * * @package wp-cli */ class Search_Replace_Command extends WP_CLI_Command { /** + * Search/replace strings in the database. + * * @synopsis <old> <new> [--dry-run] */ public function __invoke( $args, $assoc_args ) { From e006bd60bcde54e64eeea1788748b8db22988d9c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 07:44:53 +0200 Subject: [PATCH 0982/5359] add optional <table>... param to search-replace. see #249 --- man-src/search-replace.txt | 2 ++ man/search-replace.1 | 2 +- php/commands/search-replace.php | 11 ++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index 0e7f4cff1..a106c1762 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -7,3 +7,5 @@ ## EXAMPLES wp search-replace 'http://example.dev' 'http://example.com' --dry-run + + wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms diff --git a/man/search-replace.1 b/man/search-replace.1 index b22472392..618339b31 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,7 +7,7 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\-\-dry\-run] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] . .SH "OPTIONS" . diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0b88b388f..722d48d63 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,14 +10,19 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [--dry-run] + * @synopsis <old> <new> [<table>...] [--dry-run] */ public function __invoke( $args, $assoc_args ) { global $wpdb; - list( $old, $new ) = $args; + $old = array_shift( $args ); + $new = array_shift( $args ); - $tables = $wpdb->tables( 'blog' ); + if ( !empty( $args ) ) { + $tables = $args; + } else { + $tables = $wpdb->tables( 'blog' ); + } $total = 0; From 2a6c356c1217bc4a6ae1ba6f21b28266cd8a9f9b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 07:45:28 +0200 Subject: [PATCH 0983/5359] regenerate search-replace manpage --- man/search-replace.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/man/search-replace.1 b/man/search-replace.1 index 618339b31..9ac08c7b6 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -22,6 +22,8 @@ Show report, but don\'t perform the changes\. .nf wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-dry\-run + +wp search\-replace \'foo\' \'bar\' wp_posts wp_postmeta wp_terms . .fi From 9df4cd9519f27c324f5b9788e0383088ae5b848e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 09:32:40 +0200 Subject: [PATCH 0984/5359] add Spyc YAML parser --- php/Spyc.php | 1033 +++++++++++++++++++++++++++++++++++++++++++++++++ php/utils.php | 2 + 2 files changed, 1035 insertions(+) create mode 100644 php/Spyc.php diff --git a/php/Spyc.php b/php/Spyc.php new file mode 100644 index 000000000..b6a42af67 --- /dev/null +++ b/php/Spyc.php @@ -0,0 +1,1033 @@ +<?php +/** + * Spyc -- A Simple PHP YAML Class + * @version 0.5 + * @author Vlad Andersen <vlad.andersen@gmail.com> + * @author Chris Wanstrath <chris@ozmm.org> + * @link http://code.google.com/p/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * <code> + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * </code> + * or: + * <code> + * $array = Spyc::YAMLLoad($file); + * </code> + * or: + * <code> + * $array = spyc_load_file($file); + * </code> + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->__loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->__load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * <code> + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * </code> + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + public static function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->__load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * <code> + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * </code> + * @access public + * @return array + * @param string $input String containing YAML + */ + public static function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->__loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public static function YAMLDump($array,$indent = false,$wordwrap = false) { + $spyc = new Spyc; + return $spyc->dump($array,$indent,$wordwrap); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) { + $value = $this->_doLiteralBlock($value,$indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = ($value) ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + } + + + return $value; + } + +// LOADING FUNCTIONS + + private function __load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function __loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ('', $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= $this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + + + if (strpos ($line, '#')) { + if (strpos ($line, '"') === false && strpos ($line, "'") === false) + $line = preg_replace('/\s+#(.+)$/','',$line); + } + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + return file($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return null; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if (!$is_quoted) $value = str_replace('\n', "\n", $value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if (in_array($value, + array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { + return true; + } + + if (in_array(strtolower($value), + array('false', 'off', '-', 'no', 'n'))) { + return false; + } + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(', ',$inline); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line) return false; + if ($line[0] != '-') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return ($line[0] == '-' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function returnMappedValue ($line) { + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ':')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(':',$line); + $key = trim($explode[0]); + array_shift($explode); + $value = trim(implode(':',$explode)); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} + diff --git a/php/utils.php b/php/utils.php index a47469344..41e622889 100644 --- a/php/utils.php +++ b/php/utils.php @@ -24,6 +24,8 @@ function bootstrap() { \cli\register_autoload(); register_autoload(); } + + include WP_CLI_ROOT . 'Spyc.php'; } function register_autoload() { From 29d47eb9b4d40485e46c6d85eacaf92162363c84 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 09:43:35 +0200 Subject: [PATCH 0985/5359] load wp-cli.yaml file --- php/class-wp-cli.php | 14 +++++++++++++- php/utils.php | 31 ++++++++++++------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 04ea5cf68..fee808755 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -13,6 +13,7 @@ class WP_CLI { public static $root; private static $man_dirs = array(); + private static $arguments, $assoc_args, $assoc_special; /** @@ -222,12 +223,21 @@ private static function parse_args() { unset( self::$assoc_args['all'] ); } - self::$assoc_special = Utils\split_assoc( self::$assoc_args, array( + self::split_special( array( 'path', 'url', 'blog', 'user', 'require', 'quiet', 'completions', 'man', 'syn-list' ) ); } + private static function split_special( $special_keys ) { + foreach ( $special_keys as $key ) { + if ( isset( self::$assoc_args[ $key ] ) ) { + self::$assoc_special[ $key ] = self::$assoc_args[ $key ]; + unset( self::$assoc_args[ $key ] ); + } + } + } + static function get_assoc_special() { return self::$assoc_special; } @@ -240,6 +250,8 @@ static function before_wp_load() { WP_CLI_ROOT . "../man-src/" ); + self::$assoc_special = Utils\load_config(); + self::parse_args(); define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); diff --git a/php/utils.php b/php/utils.php index 41e622889..ac3858aa4 100644 --- a/php/utils.php +++ b/php/utils.php @@ -43,6 +43,18 @@ function register_autoload() { } ); } +function load_config() { + foreach ( array( 'wp-cli.local.yaml', 'wp-cli.yaml' ) as $fname ) { + $path = getcwd() . '/' . $fname; + + if ( file_exists( $path ) ) { + return spyc_load_file( $path ); + } + } + + return array(); +} + /** * Splits $argv into positional and associative arguments. * @@ -66,25 +78,6 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args ); } -/** - * Splits $argv into positional and associative arguments. - * - * @param string - * @return array - */ -function split_assoc( &$assoc_args, $special_keys ) { - $assoc_special = array(); - - foreach ( $special_keys as $key ) { - if ( isset( $assoc_args[ $key ] ) ) { - $assoc_special[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } - - return $assoc_special; -} - function set_wp_root( $assoc_args ) { if ( !empty( $assoc_args['path'] ) ) { define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); From df80ca0ff7da6b590dda5c274ba35930fc93462c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 09:47:38 +0200 Subject: [PATCH 0986/5359] rename $assoc_special to $config --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/class-wp-cli.php | 34 +++++++++++++++------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index a6a3d1f97..9f4259f99 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -76,7 +76,7 @@ private function check_positional( $args, $accepted_params ) { private function check_assoc( $assoc_args, $accepted_params ) { $mandatory_assoc = array(); - $assoc_args += \WP_CLI::get_assoc_special(); + $assoc_args += \WP_CLI::get_config(); foreach ( $accepted_params['assoc'] as $param ) { if ( !$param['optional'] ) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index fee808755..792882781 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -14,7 +14,9 @@ class WP_CLI { private static $man_dirs = array(); - private static $arguments, $assoc_args, $assoc_special; + private static $config; + + private static $arguments, $assoc_args; /** * Add a command to the wp-cli list of commands @@ -67,7 +69,7 @@ static function line( $message = '' ) { * @param bool $exit */ static function error( $message, $exit = true ) { - if ( !isset( self::$assoc_special['completions'] ) ) { + if ( !isset( self::$config['completions'] ) ) { $label = 'Error'; $msg = '%R' . $label . ': %n' . self::error_to_string( $message ); self::out( $msg . "\n", STDERR ); @@ -232,14 +234,14 @@ private static function parse_args() { private static function split_special( $special_keys ) { foreach ( $special_keys as $key ) { if ( isset( self::$assoc_args[ $key ] ) ) { - self::$assoc_special[ $key ] = self::$assoc_args[ $key ]; + self::$config[ $key ] = self::$assoc_args[ $key ]; unset( self::$assoc_args[ $key ] ); } } } - static function get_assoc_special() { - return self::$assoc_special; + static function get_config() { + return self::$config; } static function before_wp_load() { @@ -250,11 +252,11 @@ static function before_wp_load() { WP_CLI_ROOT . "../man-src/" ); - self::$assoc_special = Utils\load_config(); + self::$config = Utils\load_config(); self::parse_args(); - define( 'WP_CLI_QUIET', isset( self::$assoc_special['quiet'] ) ); + define( 'WP_CLI_QUIET', isset( self::$config['quiet'] ) ); // Handle --version parameter if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { @@ -271,10 +273,10 @@ static function before_wp_load() { $_SERVER['DOCUMENT_ROOT'] = getcwd(); // Handle --path - Utils\set_wp_root( self::$assoc_special ); + Utils\set_wp_root( self::$config ); // Handle --url and --blog parameters - Utils\set_url( self::$assoc_special ); + Utils\set_url( self::$config ); if ( array( 'core', 'download' ) == self::$arguments ) { self::run_command(); @@ -327,21 +329,21 @@ private static function cmd_starts_with( $prefix ) { static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - Utils\set_user( self::$assoc_special ); + Utils\set_user( self::$config ); - if ( !defined( 'WP_INSTALLING' ) && isset( self::$assoc_special['url'] ) ) + if ( !defined( 'WP_INSTALLING' ) && isset( self::$config['url'] ) ) Utils\set_wp_query(); - if ( isset( self::$assoc_special['require'] ) ) - require self::$assoc_special['require']; + if ( isset( self::$config['require'] ) ) + require self::$config['require']; - if ( isset( self::$assoc_special['man'] ) ) { + if ( isset( self::$config['man'] ) ) { self::generate_man( self::$arguments ); exit; } // Handle --syn-list parameter - if ( isset( self::$assoc_special['syn-list'] ) ) { + if ( isset( self::$config['syn-list'] ) ) { foreach ( self::$root->get_subcommands() as $command ) { if ( $command instanceof Dispatcher\Composite ) { foreach ( $command->get_subcommands() as $subcommand ) @@ -353,7 +355,7 @@ static function after_wp_load() { exit; } - if ( isset( self::$assoc_special['completions'] ) ) { + if ( isset( self::$config['completions'] ) ) { self::render_automcomplete(); exit; } From cb92930237ab893aa906fa38cb64b286ea46ec24 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 10:06:37 +0200 Subject: [PATCH 0987/5359] correct extension is .yml, not .yaml --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index ac3858aa4..96e8b22f8 100644 --- a/php/utils.php +++ b/php/utils.php @@ -44,7 +44,7 @@ function register_autoload() { } function load_config() { - foreach ( array( 'wp-cli.local.yaml', 'wp-cli.yaml' ) as $fname ) { + foreach ( array( 'wp-cli.local.yml', 'wp-cli.yml' ) as $fname ) { $path = getcwd() . '/' . $fname; if ( file_exists( $path ) ) { From 7601ec85446507386a878b7ea518a57da7ca5ecf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 10:17:19 +0200 Subject: [PATCH 0988/5359] whitelist config keys --- php/class-wp-cli.php | 4 +++- php/utils.php | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 792882781..30f6fc89b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -252,7 +252,9 @@ static function before_wp_load() { WP_CLI_ROOT . "../man-src/" ); - self::$config = Utils\load_config(); + self::$config = Utils\load_config( array( + 'path', 'url', 'user' + ) ); self::parse_args(); diff --git a/php/utils.php b/php/utils.php index 96e8b22f8..c7f18b0a3 100644 --- a/php/utils.php +++ b/php/utils.php @@ -43,12 +43,21 @@ function register_autoload() { } ); } -function load_config() { +function load_config( $allowed_keys ) { foreach ( array( 'wp-cli.local.yml', 'wp-cli.yml' ) as $fname ) { $path = getcwd() . '/' . $fname; if ( file_exists( $path ) ) { - return spyc_load_file( $path ); + $config = spyc_load_file( $path ); + + $sanitized_config = array(); + + foreach ( $allowed_keys as $key ) { + if ( isset( $config[ $key ] ) ) + $sanitized_config[ $key ] = $config[ $key ]; + } + + return $sanitized_config; } } From 43f6097120bf27b5b1e749f3a7db115e49eb4260 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 13:46:06 +0200 Subject: [PATCH 0989/5359] separate wp-dependent utilities from independent ones --- php/class-wp-cli.php | 2 ++ php/utils-wp.php | 38 ++++++++++++++++++++++++++++++++++++++ php/utils.php | 40 ++-------------------------------------- 3 files changed, 42 insertions(+), 38 deletions(-) create mode 100644 php/utils-wp.php diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 30f6fc89b..b23be480e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -329,6 +329,8 @@ private static function cmd_starts_with( $prefix ) { } static function after_wp_load() { + require WP_CLI_ROOT . 'utils-wp.php'; + add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); Utils\set_user( self::$config ); diff --git a/php/utils-wp.php b/php/utils-wp.php new file mode 100644 index 000000000..3eafb3035 --- /dev/null +++ b/php/utils-wp.php @@ -0,0 +1,38 @@ +<?php + +// Utilities that depend on WordPress code. + +namespace WP_CLI\Utils; + +// Handle --user parameter +function set_user( $assoc_args ) { + if ( !isset( $assoc_args['user'] ) ) + return; + + $user = $assoc_args['user']; + + if ( is_numeric( $user ) ) { + $user_id = (int) $user; + } else { + $user_id = (int) username_exists( $user ); + } + + if ( !$user_id || !wp_set_current_user( $user_id ) ) { + \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); + } +} + +function set_wp_query() { + if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { + $GLOBALS['wp']->parse_request(); + $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); + } +} + +function get_upgrader( $class ) { + if ( !class_exists( '\WP_Upgrader' ) ) + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + + return new $class( new \WP_CLI\UpgraderSkin ); +} + diff --git a/php/utils.php b/php/utils.php index c7f18b0a3..12dc88172 100644 --- a/php/utils.php +++ b/php/utils.php @@ -1,5 +1,7 @@ <?php +// Utilities that do NOT depend on WordPress code. + namespace WP_CLI\Utils; function bootstrap() { @@ -175,44 +177,6 @@ function load_wp_config() { \WP_CLI::error( 'No wp-config.php file.' ); } - - -// ---- AFTER WORDPRESS IS LOADED ---- // - - - -// Handle --user parameter -function set_user( $assoc_args ) { - if ( !isset( $assoc_args['user'] ) ) - return; - - $user = $assoc_args['user']; - - if ( is_numeric( $user ) ) { - $user_id = (int) $user; - } else { - $user_id = (int) username_exists( $user ); - } - - if ( !$user_id || !wp_set_current_user( $user_id ) ) { - \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); - } -} - -function set_wp_query() { - if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { - $GLOBALS['wp']->parse_request(); - $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); - } -} - -function get_upgrader( $class ) { - if ( !class_exists( '\WP_Upgrader' ) ) - require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - - return new $class( new \WP_CLI\UpgraderSkin ); -} - function parse_csv( $filepath, $has_headers = true ) { if ( false == ( $csv = fopen( $filepath, 'r' ) ) ) From 50cbbdbeea5d154e5b793d37289b7137e2326988 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 13:51:28 +0200 Subject: [PATCH 0990/5359] move set_wp_root() closer to locate_wp_config() --- php/utils.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/php/utils.php b/php/utils.php index 12dc88172..88c83e187 100644 --- a/php/utils.php +++ b/php/utils.php @@ -89,14 +89,6 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args ); } -function set_wp_root( $assoc_args ) { - if ( !empty( $assoc_args['path'] ) ) { - define( 'WP_ROOT', rtrim( $assoc_args['path'], '/' ) . '/' ); - } else { - define( 'WP_ROOT', getcwd() . '/' ); - } -} - function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; @@ -157,14 +149,22 @@ function set_url_params( $url ) { $_SERVER['REQUEST_METHOD'] = 'GET'; } +function set_wp_root( $config ) { + if ( !empty( $config['path'] ) ) { + define( 'WP_ROOT', rtrim( $config['path'], '/' ) . '/' ); + } else { + define( 'WP_ROOT', getcwd() . '/' ); + } +} + function locate_wp_config() { - if ( file_exists( WP_ROOT . 'wp-config.php' ) ) { + if ( file_exists( WP_ROOT . 'wp-config.php' ) ) return WP_ROOT . 'wp-config.php'; - } elseif ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) { + + if ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) return WP_ROOT . '/../wp-config.php'; - } else { - return false; - } + + return false; } // Loads wp-config.php without loading the rest of WP From c0226e0e69384476157b30eef7d34786fa86a677 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 14:15:17 +0200 Subject: [PATCH 0991/5359] replace parse_csv() with CSVIterator class --- php/WP_CLI/CSVIterator.php | 58 ++++++++++++++++++++++++++++++++++++++ php/commands/user.php | 10 +++---- php/utils.php | 24 ---------------- 3 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 php/WP_CLI/CSVIterator.php diff --git a/php/WP_CLI/CSVIterator.php b/php/WP_CLI/CSVIterator.php new file mode 100644 index 000000000..339044b06 --- /dev/null +++ b/php/WP_CLI/CSVIterator.php @@ -0,0 +1,58 @@ +<?php + +namespace WP_CLI; + +class CSVIterator implements \Iterator { + + const ROW_SIZE = 4096; + + private $filePointer; + + private $delimiter; + private $columns; + + private $currentIndex; + private $currentElement; + + public function __construct( $file, $delimiter = ',' ) { + $this->filePointer = fopen( $file, 'r' ); + $this->delimiter = $delimiter; + } + + private function read_line() { + return fgetcsv( $this->filePointer, self::ROW_SIZE, $this->delimiter ); + } + + public function rewind() { + rewind( $this->filePointer ); + + $this->columns = $this->read_line(); + + $this->currentIndex = -1; + $this->next(); + } + + public function current() { + return $this->currentElement; + } + + public function key() { + return $this->currentIndex; + } + + public function next() { + $row = $this->read_line(); + + if ( !is_array( $row ) ) { + $this->currentElement = false; + } else { + $this->currentElement = array_combine( $this->columns, $row ); + $this->currentIndex++; + } + } + + public function valid() { + return is_array( $this->currentElement ); + } +} + diff --git a/php/commands/user.php b/php/commands/user.php index 7d998c592..11dc707c9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -294,14 +294,14 @@ private static function get_user_from_first_arg( $id_or_login ) { */ public function import_csv( $args, $assoc_args ) { - list( $csv ) = $args; - - $new_users = \WP_CLI\utils\parse_csv( $csv ); - $blog_users = get_users(); - foreach( $new_users as $new_user ) { + $filename = $args[0]; + + if ( !is_readable( $filename ) ) + \WP_CLI::error( sprintf( 'Could not open file: %s', $filename ) ); + foreach ( new \WP_CLI\CSVIterator( $filename ) as $i => $new_user ) { $defaults = array( 'role' => get_option('default_role'), 'user_pass' => wp_generate_password(), diff --git a/php/utils.php b/php/utils.php index 88c83e187..aac36c5b2 100644 --- a/php/utils.php +++ b/php/utils.php @@ -177,30 +177,6 @@ function load_wp_config() { \WP_CLI::error( 'No wp-config.php file.' ); } -function parse_csv( $filepath, $has_headers = true ) { - - if ( false == ( $csv = fopen( $filepath, 'r' ) ) ) - \WP_CLI::error( sprintf( 'Could not open csv file: %s', $filepath ) ); - - $parsed_data = array(); - $headers = array(); - while ( ( $row = fgetcsv( $csv, 10000, "," ) ) !== FALSE ) { - if ( $has_headers ) { - $headers = array_values( $row ); - $has_headers = false; - continue; - } - $row_data = array(); - foreach( $row as $index => $cell_value ) { - if ( ! empty( $headers[$index] ) ) - $index = $headers[$index]; - $row_data[$index] = $cell_value; - } - $parsed_data[] = $row_data; - } - return $parsed_data; -} - /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. From 2db8a6acabd555ffef1eaa97c80467bf3af9c755 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 16:13:39 +0200 Subject: [PATCH 0992/5359] make iterator more lenient * don't bail on empty lines * allow columns to be skipped --- php/WP_CLI/CSVIterator.php | 40 +++++++++++++++++++++++++------------- php/commands/user.php | 3 --- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/php/WP_CLI/CSVIterator.php b/php/WP_CLI/CSVIterator.php index 339044b06..46a3bf9c0 100644 --- a/php/WP_CLI/CSVIterator.php +++ b/php/WP_CLI/CSVIterator.php @@ -14,19 +14,18 @@ class CSVIterator implements \Iterator { private $currentIndex; private $currentElement; - public function __construct( $file, $delimiter = ',' ) { - $this->filePointer = fopen( $file, 'r' ); - $this->delimiter = $delimiter; - } + public function __construct( $filename, $delimiter = ',' ) { + $this->filePointer = fopen( $filename, 'r' ); + if ( !is_readable( $filename ) ) + \WP_CLI::error( sprintf( 'Could not open file: %s', $filename ) ); - private function read_line() { - return fgetcsv( $this->filePointer, self::ROW_SIZE, $this->delimiter ); + $this->delimiter = $delimiter; } public function rewind() { rewind( $this->filePointer ); - $this->columns = $this->read_line(); + $this->columns = fgetcsv( $this->filePointer, self::ROW_SIZE, $this->delimiter ); $this->currentIndex = -1; $this->next(); @@ -41,13 +40,28 @@ public function key() { } public function next() { - $row = $this->read_line(); + $this->currentElement = false; + + while ( true ) { + $str = fgets( $this->filePointer ); + + if ( false === $str ) + break; + + $row = str_getcsv( $str, $this->delimiter ); + + $element = array(); + foreach ( $this->columns as $i => $key ) { + if ( isset( $row[ $i ] ) ) + $element[ $key ] = $row[ $i ]; + } + + if ( !empty( $element ) ) { + $this->currentElement = $element; + $this->currentIndex++; - if ( !is_array( $row ) ) { - $this->currentElement = false; - } else { - $this->currentElement = array_combine( $this->columns, $row ); - $this->currentIndex++; + break; + } } } diff --git a/php/commands/user.php b/php/commands/user.php index 11dc707c9..a1a8c1d12 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -298,9 +298,6 @@ public function import_csv( $args, $assoc_args ) { $filename = $args[0]; - if ( !is_readable( $filename ) ) - \WP_CLI::error( sprintf( 'Could not open file: %s', $filename ) ); - foreach ( new \WP_CLI\CSVIterator( $filename ) as $i => $new_user ) { $defaults = array( 'role' => get_option('default_role'), From 2ff2cf8509d4d164c53c8e0a2bb48eaf06403c1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 16:33:11 +0200 Subject: [PATCH 0993/5359] make wp user delete accept multiple ids. see #229 --- php/commands/user.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index a1a8c1d12..8d0e77fb0 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -59,24 +59,28 @@ public function _list( $args, $assoc_args ) { } /** - * Delete a user. + * Delete one or more users. * - * @synopsis <id> [--reassign=<id>] + * @synopsis <id>... [--reassign=<id>] */ public function delete( $args, $assoc_args ) { - global $blog_id; - - list( $user_id ) = $args; - - $defaults = array( 'reassign' => NULL ); + $defaults = array( + 'reassign' => null + ); extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - if ( wp_delete_user( $user_id, $reassign ) ) { - WP_CLI::success( "Deleted user $user_id." ); - } else { - WP_CLI::error( "Failed deleting user $user_id." ); + foreach ( $args as $user_id ) { + if ( wp_delete_user( $user_id, $reassign ) ) { + WP_CLI::success( "Deleted user $user_id." ); + $status = 0; + } else { + WP_CLI::error( "Failed deleting user $user_id.", false ); + $status = 1; + } } + + exit( $status ); } /** From ce99707c049945f10f26bc513b2ac82fefae3721 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 28 Dec 2012 19:46:38 +0200 Subject: [PATCH 0994/5359] introduce CommandWithDBObject class - make `wp user update` accept multiple IDs. see #229 - use wpmu_user_delete() when on multisite - return correct error status --- php/WP_CLI/CommandWithDBObject.php | 82 +++++++++++++++++++++++++ php/commands/post.php | 70 ++++++++++------------ php/commands/user.php | 96 ++++++++++++++---------------- 3 files changed, 158 insertions(+), 90 deletions(-) create mode 100644 php/WP_CLI/CommandWithDBObject.php diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php new file mode 100644 index 000000000..8b252663a --- /dev/null +++ b/php/WP_CLI/CommandWithDBObject.php @@ -0,0 +1,82 @@ +<?php + +namespace WP_CLI; + +/** + * Base class for WP-CLI commands that deal with database objects. + * + * @package wp-cli + */ +abstract class CommandWithDBObject extends \WP_CLI_Command { + + abstract protected function _create( $params ); + abstract protected function _update( $params ); + abstract protected function _delete( $obj_id, $assoc_args ); + + public function create( $assoc_args ) { + unset( $assoc_args['ID'] ); + + $obj_id = $this->_create( $assoc_args ); + + if ( is_wp_error( $obj_id ) ) { + \WP_CLI::error( $obj_id ); + } + + if ( isset( $assoc_args['porcelain'] ) ) + \WP_CLI::line( $obj_id ); + else + \WP_CLI::success( "Created $this->obj_type $obj_id." ); + } + + public function update( $args, $assoc_args ) { + $status = 0; + + if ( empty( $assoc_args ) ) { + \WP_CLI::error( "Need some fields to update." ); + } + + foreach ( $args as $obj_id ) { + $params = array_merge( $assoc_args, array( 'ID' => $obj_id ) ); + + $status = $this->success_or_failure( $this->wp_error_to_resp( + $this->_update( $params ), + "Updated $this->obj_type $obj_id." + ) ); + } + + exit( $status ); + } + + protected function wp_error_to_resp( $r, $success_msg ) { + if ( is_wp_error( $r ) ) + return array( 'error', $r->get_error_message() ); + else + return array( 'success', $success_msg ); + } + + protected function success_or_failure( $r ) { + list( $type, $msg ) = $r; + + if ( 'success' == $type ) { + \WP_CLI::success( $msg ); + $status = 0; + } else { + \WP_CLI::error( $msg, false ); + $status = 1; + } + + return $status; + } + + public function delete( $args, $assoc_args ) { + $status = 0; + + foreach ( $args as $obj_id ) { + $r = $this->_delete( $obj_id, $assoc_args ); + $status = $this->success_or_failure( $r ); + } + + exit( $status ); + } +} + diff --git a/php/commands/post.php b/php/commands/post.php index 12ca8e094..b7652676b 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -1,14 +1,14 @@ <?php -WP_CLI::add_command( 'post', 'Post_Command' ); - /** * Implement post command * * @package wp-cli * @subpackage commands/internals */ -class Post_Command extends WP_CLI_Command { +class Post_Command extends \WP_CLI\CommandWithDBObject { + + protected $obj_type = 'post'; /** * Create a post. @@ -16,41 +16,24 @@ class Post_Command extends WP_CLI_Command { * @synopsis --<field>=<value> [--porcelain] */ public function create( $_, $assoc_args ) { - unset( $assoc_args['ID'] ); - - $post_id = wp_insert_post( $assoc_args, true ); - - if ( is_wp_error( $post_id ) ) { - WP_CLI::error( $post_id ); - } + parent::create( $assoc_args ); + } - if ( isset( $assoc_args['porcelain'] ) ) - WP_CLI::line( $post_id ); - else - WP_CLI::success( "Created post $post_id." ); + protected function _create( $params ) { + return wp_insert_post( $params, true ); } /** - * Update a post. + * Update one or more posts. * * @synopsis <id>... --<field>=<value> */ public function update( $args, $assoc_args ) { - foreach ( $args as $post_id ) { - if ( empty( $assoc_args ) ) { - WP_CLI::error( "Need some fields to update." ); - } - - $params = array_merge( $assoc_args, array( 'ID' => $post_id ) ); - - $r = wp_update_post( $params, true ); + parent::update( $args, $assoc_args ); + } - if ( is_wp_error( $r ) ) { - WP_CLI::error( "Post $post_id: " . $r->get_error_message() ); - } else { - WP_CLI::success( "Updated post $post_id." ); - } - } + protected function _update( $params ) { + return wp_update_post( $params, true ); } /** @@ -58,15 +41,23 @@ public function update( $args, $assoc_args ) { * * @synopsis <id>... [--force] */ - public function delete( $post_ids, $assoc_args ) { - $action = isset( $assoc_args['force'] ) ? 'Deleted' : 'Trashed'; - - foreach ( $post_ids as $post_id ) { - if ( wp_delete_post( $post_id, $assoc_args['force'] ) ) { - WP_CLI::success( "{$action} post $post_id." ); - } else { - WP_CLI::error( "Failed deleting post $post_id." ); - } + public function delete( $args, $assoc_args ) { + $assoc_args = wp_parse_args( $assoc_args, array( + 'force' => false + ) ); + + parent::delete( $args, $assoc_args ); + } + + protected function _delete( $post_id, $assoc_args ) { + $r = wp_delete_post( $post_id, $assoc_args['force'] ); + + if ( $r ) { + $action = $assoc_args['force'] ? 'Deleted' : 'Trashed'; + + return array( 'success', "$action post $post_id." ); + } else { + return array( 'error', "Failed deleting post $post_id." ); } } @@ -206,3 +197,6 @@ private function maybe_reset_depth() { return ( mt_rand(1,10) == 7 ) ? true : false; } } + +WP_CLI::add_command( 'post', 'Post_Command' ); + diff --git a/php/commands/user.php b/php/commands/user.php index 8d0e77fb0..fb69f14d4 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -1,14 +1,12 @@ <?php -WP_CLI::add_command('user', 'User_Command'); - /** * Implement user command * * @package wp-cli * @subpackage commands/internals */ -class User_Command extends WP_CLI_Command { +class User_Command extends \WP_CLI\CommandWithDBObject { /** * List users. @@ -24,7 +22,7 @@ public function _list( $args, $assoc_args ) { 'fields' => isset( $assoc_args['ids'] ) ? 'ids' : 'all_with_meta', ); - if ( array_key_exists('role', $assoc_args) ) { + if ( array_key_exists( 'role', $assoc_args ) ) { $params['role'] = $assoc_args['role']; } @@ -32,30 +30,29 @@ public function _list( $args, $assoc_args ) { if ( isset( $assoc_args['ids'] ) ) { WP_CLI::out( implode( ' ', $users ) ); - return; - } + } else { + $fields = array('ID', 'user_login', 'display_name', 'user_email', + 'user_registered'); - $fields = array('ID', 'user_login', 'display_name', 'user_email', - 'user_registered'); + $table = new \cli\Table(); - $table = new \cli\Table(); + $table->setHeaders( array_merge( $fields, array('roles') ) ); - $table->setHeaders( array_merge($fields, array('roles')) ); + foreach ( $users as $user ) { + $line = array(); - foreach ( $users as $user ) { - $line = array(); + foreach ( $fields as $field ) { + $line[] = $user->$field; + } + $line[] = implode( ',', $user->roles ); - foreach ( $fields as $field ) { - $line[] = $user->$field; + $table->addRow( $line ); } - $line[] = implode( ',', $user->roles ); - $table->addRow($line); - } - - $table->display(); + $table->display(); - WP_CLI::line( 'Total: ' . count($users) . ' users' ); + WP_CLI::line( 'Total: ' . count( $users ) . ' users' ); + } } /** @@ -64,23 +61,25 @@ public function _list( $args, $assoc_args ) { * @synopsis <id>... [--reassign=<id>] */ public function delete( $args, $assoc_args ) { - $defaults = array( + $assoc_args = wp_parse_args( $assoc_args, array( 'reassign' => null - ); + ) ); - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + parent::delete( $args, $assoc_args ); + } - foreach ( $args as $user_id ) { - if ( wp_delete_user( $user_id, $reassign ) ) { - WP_CLI::success( "Deleted user $user_id." ); - $status = 0; - } else { - WP_CLI::error( "Failed deleting user $user_id.", false ); - $status = 1; - } + protected function _delete( $user_id, $assoc_args ) { + if ( is_multisite() ) { + $r = wpmu_delete_user( $user_id ); + } else { + $r = wp_delete_user( $user_id, $assoc_args['reassign'] ); } - exit( $status ); + if ( $r ) { + return array( 'success', "Deleted user $user_id." ); + } else { + return array( 'error', "Failed deleting user $user_id." ); + } } /** @@ -89,8 +88,6 @@ public function delete( $args, $assoc_args ) { * @synopsis <user-login> <user-email> [--role=<role>] [--user_pass=<password>] [--user_registered=<yyyy-mm-dd>] [--display_name=<name>] [--porcelain] */ public function create( $args, $assoc_args ) { - global $blog_id; - list( $user_login, $user_email ) = $args; $defaults = array( @@ -113,7 +110,7 @@ public function create( $args, $assoc_args ) { $generated_pass = true; } - $user_id = wp_insert_user( array( + $user_id = $this->_create( array( 'user_email' => $user_email, 'user_login' => $user_login, 'user_pass' => $user_pass, @@ -122,7 +119,7 @@ public function create( $args, $assoc_args ) { 'role' => $role, ) ); - if ( is_wp_error($user_id) ) { + if ( is_wp_error( $user_id ) ) { WP_CLI::error( $user_id ); } else { if ( false === $role ) { @@ -140,27 +137,21 @@ public function create( $args, $assoc_args ) { } } + protected function _create( $params ) { + return wp_insert_user( $params ); + } + /** * Update a user. * - * @synopsis <id> --<field>=<value> + * @synopsis <id>... --<field>=<value> */ public function update( $args, $assoc_args ) { - list( $user_id ) = $args; - - if ( empty( $assoc_args ) ) { - WP_CLI::error( "Need some fields to update." ); - } - - $params = array_merge( array( 'ID' => $user_id ), $assoc_args ); - - $updated_id = wp_update_user( $params ); + parent::update( $args, $assoc_args, 'user' ); + } - if ( is_wp_error( $updated_id ) ) { - WP_CLI::error( $updated_id ); - } else { - WP_CLI::success( "Updated user $updated_id." ); - } + protected function _update( $params ) { + return wp_update_user( $params ); } /** @@ -356,6 +347,7 @@ public function import_csv( $args, $assoc_args ) { } } } - } +WP_CLI::add_command( 'user', 'User_Command' ); + From e47c6d526039ce75b0bcd9bf84ccb404de49905a Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 20:54:27 +0100 Subject: [PATCH 0995/5359] Implemented the STDOUT --theme flag and or --plugin="" for post_types --- .../wp-cli/commands/internals/scaffold.php | 86 +++++++++++++++---- .../skeletons/post_type_skeleton.php | 2 +- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 6764e409d..9c9d415c4 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -20,7 +20,7 @@ function __construct() { * * @alias pt * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin-name>] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -61,24 +61,23 @@ function post_type( $args, $assoc_args ) { 'query_var' => 'true', 'can_export' => 'true', 'textdomain' => strtolower( wp_get_theme()->template ), + 'theme' => false, + 'plugin' => false ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - $path = TEMPLATEPATH . '/post-types/'; - if( !$wp_filesystem->is_dir( $path ) ) { - $wp_filesystem->mkdir( $path ); - } - - $filename = $path . $post_type .'.php'; - - include 'skeletons/post_type_skeleton.php'; - - if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { - WP_CLI::error( 'Error while saving file' ); + + include "skeletons/post_type_skeleton.php"; + $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, 'path' => false ); + + if ( $theme || !empty( $plugin ) ) { + // Write file to theme or (given) plugin path + $assoc_args['path'] = $this->get_output_path( $assoc_args ); + $this->parse_skeleton( $assoc_args ); } else { - WP_CLI::success( $post_type . ' created' ); + // STDOUT + echo $this->parse_skeleton( $assoc_args ); } } @@ -129,7 +128,7 @@ function taxonomy( $args, $assoc_args ) { $wp_filesystem->mkdir( $path ); } - $filename = $path . $taxonomy .'.php'; + $filename = $path . $taxonomy . '.php'; include 'skeletons/taxonomy_skeleton.php'; @@ -140,6 +139,62 @@ function taxonomy( $args, $assoc_args ) { } } + private function get_output_path( $assoc_args ) { + global $wp_filesystem; + + extract( $assoc_args, EXTR_SKIP ); + + // Implements the --theme flag || --plugin=<plugin-name> + if( $theme ) { + //Here we assume you got a theme installed + $path = TEMPLATEPATH; + } elseif ( !empty( $plugin ) ){ + $path = WP_PLUGIN_DIR . '/' . $plugin; //Faking recursive mkdir for down the line + $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin ); //Faking recursive mkdir for down the line + } else { + // STDOUT + return false; + } + + if ( $type === "post_type") { + $path .= '/post-types/'; + } elseif ( $type === "taxonomy" ) { + $path .= '/taxonomies/'; + } + + // If it doesn't exists create it + if( !$wp_filesystem->is_dir( $path ) ) { + $wp_filesystem->mkdir( $path ); + WP_CLI::success( "Created dir: {$path}" ); + } elseif( $wp_filesystem->is_dir( $path ) ) { + WP_CLI::success( "Dir already exists: {$path}" ); + } else { + WP_CLI::error( "Couldn't create dir exists: {$path}" ); + } + + return $path; + } + + private function parse_skeleton( $assoc_args = array() ) { + global $wp_filesystem; + + extract( $assoc_args, EXTR_SKIP ); + + // Write to file + if( $path ) { + $filename = $path . $machine_name .'.php'; + + if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { + WP_CLI::error( "Error while saving file: {$filename}" ); + } else { + WP_CLI::success( $machine_name . ' created' ); + } + } else { + // Return for STDOUT + return $output; + } + } + private function pluralize( $word ) { $plural = array( '/(quiz)$/i' => '\1zes', @@ -193,6 +248,5 @@ private function pluralize( $word ) { } } return false; - } } \ No newline at end of file diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php index 1b06f2c64..e92355d2b 100755 --- a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php +++ b/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php @@ -63,4 +63,4 @@ function {$machine_name}_updated_messages( \$messages ) { return \$messages; } -add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; +add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file From 11de929dbf8014fdd9143d15f30c3a2575fb04f0 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 21:02:19 +0100 Subject: [PATCH 0996/5359] Implemented the STDOUT --theme flag and or --plugin="" for taxonomies --- .../wp-cli/commands/internals/scaffold.php | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 9c9d415c4..7047b4b44 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -86,7 +86,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin-name>] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; @@ -117,25 +117,24 @@ function taxonomy( $args, $assoc_args ) { 'query_var' => 'true', 'slug' => $taxonomy, 'textdomain' => strtolower( wp_get_theme()->template ), - 'post_types' => 'post' + 'post_types' => 'post', + 'theme' => false, + 'plugin' => false ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - $path = TEMPLATEPATH . '/taxonomies/'; - if( !$wp_filesystem->is_dir( $path ) ) { - $wp_filesystem->mkdir( $path ); - } - - $filename = $path . $taxonomy . '.php'; - include 'skeletons/taxonomy_skeleton.php'; - - if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { - WP_CLI::error( 'Error while saving file' ); + $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, 'path' => false ); + + if ( $theme || !empty( $plugin ) ) { + // Write file to theme or (given) plugin path + $assoc_args['path'] = $this->get_output_path( $assoc_args ); + $this->parse_skeleton( $assoc_args ); } else { - WP_CLI::success( $taxonomy . ' created' ); + // STDOUT + echo $this->parse_skeleton( $assoc_args ); } } @@ -187,7 +186,7 @@ private function parse_skeleton( $assoc_args = array() ) { if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { WP_CLI::error( "Error while saving file: {$filename}" ); } else { - WP_CLI::success( $machine_name . ' created' ); + WP_CLI::success( ucfirst($type) . " {$machine_name} created" ); } } else { // Return for STDOUT From 970ce971a396f4cdd7770baf26874cb904c56fad Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 21:21:45 +0100 Subject: [PATCH 0997/5359] Use theme, plugin name or YOUR-TEXTDOMAIN as textdomain, closes #5 --- src/php/wp-cli/commands/internals/scaffold.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 7047b4b44..31d869580 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -39,7 +39,7 @@ function post_type( $args, $assoc_args ) { $label_plural = $this->pluralize( $label ); $label_plural_ucfirst = ucfirst( $label_plural ); } - + // set up defaults and merge theme with assoc_args $defaults = array( 'description' => "", @@ -60,13 +60,23 @@ function post_type( $args, $assoc_args ) { 'pages' => 'true', 'query_var' => 'true', 'can_export' => 'true', - 'textdomain' => strtolower( wp_get_theme()->template ), + 'textdomain' => '', 'theme' => false, 'plugin' => false ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + // Because if you're writing your files to your theme directory your textdomain also needs to be the same + // Same goes for when plugin is being used + if( empty($textdomain) && $theme ) { + $textdomain = strtolower( wp_get_theme()->template ); + } elseif ( empty($textdomain) && $plugin) { + $textdomain = $plugin; + } else { + $textdomain = 'YOUR_TEXTDOMAIN'; + } include "skeletons/post_type_skeleton.php"; $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, 'path' => false ); From 56f3ac0124c6a6ce842434065c0618118c10c751 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 22:30:13 +0100 Subject: [PATCH 0998/5359] Renamed the --plugin to --plugin_name and also really fixed #5 so it always return the default --- .../wp-cli/commands/internals/scaffold.php | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 31d869580..760a9cde8 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -20,7 +20,7 @@ function __construct() { * * @alias pt * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin-name>] + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -62,27 +62,19 @@ function post_type( $args, $assoc_args ) { 'can_export' => 'true', 'textdomain' => '', 'theme' => false, - 'plugin' => false + 'plugin_name' => false ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - // Because if you're writing your files to your theme directory your textdomain also needs to be the same - // Same goes for when plugin is being used - if( empty($textdomain) && $theme ) { - $textdomain = strtolower( wp_get_theme()->template ); - } elseif ( empty($textdomain) && $plugin) { - $textdomain = $plugin; - } else { - $textdomain = 'YOUR_TEXTDOMAIN'; - } + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); include "skeletons/post_type_skeleton.php"; - $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, 'path' => false ); + $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name, 'path' => false ); - if ( $theme || !empty( $plugin ) ) { - // Write file to theme or (given) plugin path + if ( $theme || !empty( $plugin_name ) ) { + // Write file to theme or given plugin_name $assoc_args['path'] = $this->get_output_path( $assoc_args ); $this->parse_skeleton( $assoc_args ); } else { @@ -96,7 +88,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin-name>] + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; @@ -126,20 +118,22 @@ function taxonomy( $args, $assoc_args ) { 'rewrite' => 'true', 'query_var' => 'true', 'slug' => $taxonomy, - 'textdomain' => strtolower( wp_get_theme()->template ), 'post_types' => 'post', + 'textdomain' => '', 'theme' => false, - 'plugin' => false + 'plugin_name' => false ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); + include 'skeletons/taxonomy_skeleton.php'; - $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, 'path' => false ); + $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name, 'path' => false ); - if ( $theme || !empty( $plugin ) ) { - // Write file to theme or (given) plugin path + if ( $theme || !empty( $plugin_name ) ) { + // Write file to theme or given plugin_name $assoc_args['path'] = $this->get_output_path( $assoc_args ); $this->parse_skeleton( $assoc_args ); } else { @@ -153,13 +147,13 @@ private function get_output_path( $assoc_args ) { extract( $assoc_args, EXTR_SKIP ); - // Implements the --theme flag || --plugin=<plugin-name> + // Implements the --theme flag || --plugin_name=<plugin_name> if( $theme ) { //Here we assume you got a theme installed $path = TEMPLATEPATH; - } elseif ( !empty( $plugin ) ){ - $path = WP_PLUGIN_DIR . '/' . $plugin; //Faking recursive mkdir for down the line - $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin ); //Faking recursive mkdir for down the line + } elseif ( !empty( $plugin_name ) ){ + $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line + $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line } else { // STDOUT return false; @@ -204,6 +198,22 @@ private function parse_skeleton( $assoc_args = array() ) { } } + /** + * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. + * Same goes for when plugin_name is being used. + */ + private function get_textdomain( $textdomain, $theme, $plugin_name ) { + if( empty( $textdomain ) && $theme ) { + $textdomain = strtolower( wp_get_theme()->template ); + } elseif ( empty( $textdomain ) && $plugin_name) { + $textdomain = $plugin_name; + } elseif ( empty( $textdomain ) || gettype($textdomain) == 'boolean' ) { //This mean just a flag + $textdomain = 'YOUR-TEXTDOMAIN'; + } + + return $textdomain; + } + private function pluralize( $word ) { $plural = array( '/(quiz)$/i' => '\1zes', From 3cb8f4558e9a400b13ec945022c5a7bfa842339b Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 22:56:49 +0100 Subject: [PATCH 0999/5359] Cleaned up and kind of closes #2 --- .../wp-cli/commands/internals/scaffold.php | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/src/php/wp-cli/commands/internals/scaffold.php index 760a9cde8..9e39d2ad8 100755 --- a/src/php/wp-cli/commands/internals/scaffold.php +++ b/src/php/wp-cli/commands/internals/scaffold.php @@ -70,16 +70,16 @@ function post_type( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - include "skeletons/post_type_skeleton.php"; - $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name, 'path' => false ); - + include 'skeletons/post_type_skeleton.php'; + if ( $theme || !empty( $plugin_name ) ) { // Write file to theme or given plugin_name + $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->parse_skeleton( $assoc_args ); + $this->save_skeleton_output( $assoc_args ); } else { // STDOUT - echo $this->parse_skeleton( $assoc_args ); + echo $output; } } @@ -130,15 +130,15 @@ function taxonomy( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); include 'skeletons/taxonomy_skeleton.php'; - $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name, 'path' => false ); - + if ( $theme || !empty( $plugin_name ) ) { // Write file to theme or given plugin_name + $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->parse_skeleton( $assoc_args ); + $this->save_skeleton_output( $assoc_args ); } else { // STDOUT - echo $this->parse_skeleton( $assoc_args ); + echo $output; } } @@ -178,7 +178,7 @@ private function get_output_path( $assoc_args ) { return $path; } - private function parse_skeleton( $assoc_args = array() ) { + private function save_skeleton_output( $assoc_args ) { global $wp_filesystem; extract( $assoc_args, EXTR_SKIP ); @@ -190,11 +190,8 @@ private function parse_skeleton( $assoc_args = array() ) { if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { WP_CLI::error( "Error while saving file: {$filename}" ); } else { - WP_CLI::success( ucfirst($type) . " {$machine_name} created" ); + WP_CLI::success( "{$type} {$machine_name} created" ); } - } else { - // Return for STDOUT - return $output; } } From e6764f260e9a177f9d8544dbd75129c36f38d8d2 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 23:30:11 +0100 Subject: [PATCH 1000/5359] Moved scaffold from src/php/wp-cli/commands/internals to php/commands --- {src/php/wp-cli/commands/internals => php/commands}/scaffold.php | 0 .../internals => php/commands}/skeletons/post_type_skeleton.php | 0 .../internals => php/commands}/skeletons/taxonomy_skeleton.php | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {src/php/wp-cli/commands/internals => php/commands}/scaffold.php (100%) rename {src/php/wp-cli/commands/internals => php/commands}/skeletons/post_type_skeleton.php (100%) rename {src/php/wp-cli/commands/internals => php/commands}/skeletons/taxonomy_skeleton.php (100%) diff --git a/src/php/wp-cli/commands/internals/scaffold.php b/php/commands/scaffold.php similarity index 100% rename from src/php/wp-cli/commands/internals/scaffold.php rename to php/commands/scaffold.php diff --git a/src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php b/php/commands/skeletons/post_type_skeleton.php similarity index 100% rename from src/php/wp-cli/commands/internals/skeletons/post_type_skeleton.php rename to php/commands/skeletons/post_type_skeleton.php diff --git a/src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php b/php/commands/skeletons/taxonomy_skeleton.php similarity index 100% rename from src/php/wp-cli/commands/internals/skeletons/taxonomy_skeleton.php rename to php/commands/skeletons/taxonomy_skeleton.php From c3b5195983e4ced20dfeabf9e00f5a6e45a4e14e Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 28 Dec 2012 23:59:18 +0100 Subject: [PATCH 1001/5359] A little bit of WordPress Conding Standards --- php/commands/scaffold.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 9e39d2ad8..c1b832d09 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -72,9 +72,15 @@ function post_type( $args, $assoc_args ) { include 'skeletons/post_type_skeleton.php'; - if ( $theme || !empty( $plugin_name ) ) { + if ( $theme || ! empty( $plugin_name ) ) { // Write file to theme or given plugin_name - $assoc_args = array('type' => 'post_type', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name ); + $assoc_args = array( + 'type' => 'post_type', + 'output' => $output, + 'theme' => $theme, + 'plugin_name' => $plugin_name, + 'machine_name' => $machine_name, + ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); $this->save_skeleton_output( $assoc_args ); } else { @@ -133,7 +139,13 @@ function taxonomy( $args, $assoc_args ) { if ( $theme || !empty( $plugin_name ) ) { // Write file to theme or given plugin_name - $assoc_args = array('type' => 'taxonomy', 'output' => $output, 'theme' => $theme, 'plugin_name' => $plugin_name, 'machine_name' => $machine_name ); + $assoc_args = array( + 'type' => 'taxonomy', + 'output' => $output, + 'theme' => $theme, + 'plugin_name' => $plugin_name, + 'machine_name' => $machine_name, + ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); $this->save_skeleton_output( $assoc_args ); } else { @@ -151,7 +163,7 @@ private function get_output_path( $assoc_args ) { if( $theme ) { //Here we assume you got a theme installed $path = TEMPLATEPATH; - } elseif ( !empty( $plugin_name ) ){ + } elseif ( ! empty( $plugin_name ) ){ $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line } else { @@ -166,7 +178,7 @@ private function get_output_path( $assoc_args ) { } // If it doesn't exists create it - if( !$wp_filesystem->is_dir( $path ) ) { + if( ! $wp_filesystem->is_dir( $path ) ) { $wp_filesystem->mkdir( $path ); WP_CLI::success( "Created dir: {$path}" ); } elseif( $wp_filesystem->is_dir( $path ) ) { From 9454028630f93c9614441509a439b4558be3708c Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sat, 29 Dec 2012 01:25:46 +0100 Subject: [PATCH 1002/5359] Implemented --raw flag so that one only gets the registration of a taxonomy or post type WITH labels. Without these you will also get a init and update messages. But I think update messages also need to be a part of the --raw flag --- php/commands/scaffold.php | 32 +++++++++++++------ php/commands/skeletons/post_type_skeleton.php | 30 +---------------- .../skeletons/post_type_skeleton_extended.php | 32 +++++++++++++++++++ php/commands/skeletons/taxonomy_skeleton.php | 11 ++----- .../skeletons/taxonomy_skeleton_extended.php | 8 +++++ 5 files changed, 67 insertions(+), 46 deletions(-) mode change 100755 => 100644 php/commands/skeletons/post_type_skeleton.php create mode 100755 php/commands/skeletons/post_type_skeleton_extended.php mode change 100755 => 100644 php/commands/skeletons/taxonomy_skeleton.php create mode 100755 php/commands/skeletons/taxonomy_skeleton_extended.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c1b832d09..ee11f0c8f 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -20,7 +20,7 @@ function __construct() { * * @alias pt * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -33,7 +33,7 @@ function post_type( $args, $assoc_args ) { $machine_name_plural = $this->pluralize( $post_type ); // If no label is given use the slug and prettify it as good as possible - if( !isset( $assoc_args['label'] ) ) { + if( ! isset( $assoc_args['label'] ) ) { $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); $label_ucfirst = ucfirst( $label ); $label_plural = $this->pluralize( $label ); @@ -62,7 +62,8 @@ function post_type( $args, $assoc_args ) { 'can_export' => 'true', 'textdomain' => '', 'theme' => false, - 'plugin_name' => false + 'plugin_name' => false, + 'raw' => false, ); // Generate the variables from the defaults and associated arguments if they are set @@ -70,7 +71,13 @@ function post_type( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - include 'skeletons/post_type_skeleton.php'; + if( ! $raw ) { + include 'skeletons/post_type_skeleton.php'; + $output = str_replace( "<?php", "", $output); + include 'skeletons/post_type_skeleton_extended.php'; + } else { + include 'skeletons/post_type_skeleton.php'; + } if ( $theme || ! empty( $plugin_name ) ) { // Write file to theme or given plugin_name @@ -94,7 +101,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; @@ -107,7 +114,7 @@ function taxonomy( $args, $assoc_args ) { $machine_name_plural = $this->pluralize( $taxonomy ); // If no label is given use the slug and prettify it as good as possible - if( !isset( $assoc_args['label'] ) ) { + if( ! isset( $assoc_args['label'] ) ) { $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); $label_ucfirst = ucfirst( $label ); $label_plural = $this->pluralize( $label ); @@ -127,7 +134,8 @@ function taxonomy( $args, $assoc_args ) { 'post_types' => 'post', 'textdomain' => '', 'theme' => false, - 'plugin_name' => false + 'plugin_name' => false, + 'raw' => false, ); // Generate the variables from the defaults and associated arguments if they are set @@ -135,9 +143,15 @@ function taxonomy( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - include 'skeletons/taxonomy_skeleton.php'; + if( ! $raw ) { + include 'skeletons/taxonomy_skeleton.php'; + $output = str_replace( "<?php", "", $output); + include 'skeletons/taxonomy_skeleton_extended.php'; + } else { + include 'skeletons/taxonomy_skeleton.php'; + } - if ( $theme || !empty( $plugin_name ) ) { + if ( $theme || ! empty( $plugin_name ) ) { // Write file to theme or given plugin_name $assoc_args = array( 'type' => 'taxonomy', diff --git a/php/commands/skeletons/post_type_skeleton.php b/php/commands/skeletons/post_type_skeleton.php old mode 100755 new mode 100644 index e92355d2b..21253f939 --- a/php/commands/skeletons/post_type_skeleton.php +++ b/php/commands/skeletons/post_type_skeleton.php @@ -1,7 +1,5 @@ <?php $output = "<?php - -function {$machine_name}_init() { register_post_type( '{$post_type}', array( 'label' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), @@ -37,30 +35,4 @@ function {$machine_name}_init() { 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), ), ) - ); -} -add_action( 'init', '{$machine_name}_init' ); - -function {$machine_name}_updated_messages( \$messages ) { - global \$post, \$post_ID; - - \$messages['{$post_type}'] = array( - 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 2 => __('Custom field updated.', '{$textdomain}'), - 3 => __('Custom field deleted.', '{$textdomain}'), - 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), - /* translators: %s: date and time of the revision */ - 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"%2\$s\">Preview {$label}</a>', '{$textdomain}'), - // translators: Publish box date format, see http://php.net/date - date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), - ); - - return \$messages; -} -add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; \ No newline at end of file + );"; \ No newline at end of file diff --git a/php/commands/skeletons/post_type_skeleton_extended.php b/php/commands/skeletons/post_type_skeleton_extended.php new file mode 100755 index 000000000..3d541d8d9 --- /dev/null +++ b/php/commands/skeletons/post_type_skeleton_extended.php @@ -0,0 +1,32 @@ +<?php +$output = "<?php + +function {$machine_name}_init() { + {$output} +} +add_action( 'init', '{$machine_name}_init' ); + +function {$machine_name}_updated_messages( \$messages ) { + global \$post, \$post_ID; + + \$messages['{$post_type}'] = array( + 0 => '', // Unused. Messages start at index 1. + 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 2 => __('Custom field updated.', '{$textdomain}'), + 3 => __('Custom field deleted.', '{$textdomain}'), + 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), + /* translators: %s: date and time of the revision */ + 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, + 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), + 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), + 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), + 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"%2\$s\">Preview {$label}</a>', '{$textdomain}'), + // translators: Publish box date format, see http://php.net/date + date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), + 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), + ); + + return \$messages; +} +add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; +?> \ No newline at end of file diff --git a/php/commands/skeletons/taxonomy_skeleton.php b/php/commands/skeletons/taxonomy_skeleton.php old mode 100755 new mode 100644 index 1d299b7d1..e098f77f5 --- a/php/commands/skeletons/taxonomy_skeleton.php +++ b/php/commands/skeletons/taxonomy_skeleton.php @@ -1,7 +1,5 @@ <?php $output = "<?php - -function {$machine_name}_init() { \$labels = array( 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), @@ -20,8 +18,8 @@ function {$machine_name}_init() { 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), ); - \$args = array( - 'labels' => \$labels, + \$args = array( + 'labels' => \$labels, 'public' => {$public}, 'show_in_nav_menus' => {$show_in_nav_menus}, 'show_ui' => {$show_ui}, @@ -42,7 +40,4 @@ function {$machine_name}_init() { ), ); - register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args ); - -} -add_action( 'init', '{$machine_name}_init' );"; \ No newline at end of file + register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args );"; \ No newline at end of file diff --git a/php/commands/skeletons/taxonomy_skeleton_extended.php b/php/commands/skeletons/taxonomy_skeleton_extended.php new file mode 100755 index 000000000..d4015c73e --- /dev/null +++ b/php/commands/skeletons/taxonomy_skeleton_extended.php @@ -0,0 +1,8 @@ +<?php +$output = "<?php + +function {$machine_name}_init() { + {$output} + +} +add_action( 'init', '{$machine_name}_init' );"; \ No newline at end of file From b0a5a21a9224f6fd30d23a5a31479186bb472c38 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 12:48:54 +0200 Subject: [PATCH 1003/5359] rename Composite interface to CommandContainer Command containers don't need to have an invoke() method, since they don't have any implementation of their own. --- php/WP_CLI/Dispatcher/CompositeCommand.php | 16 ++-------------- php/WP_CLI/Dispatcher/RootCommand.php | 10 +++------- php/class-wp-cli.php | 8 ++++++-- php/dispatcher.php | 9 ++++++--- php/man.php | 4 ++-- 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 23ff3cf36..05f973ec9 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class CompositeCommand implements Command, Composite, Documentable { +class CompositeCommand implements CommandContainer, Documentable { protected $name; @@ -54,20 +54,8 @@ function show_usage() { \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); } - function invoke( $args, $assoc_args ) { - $subcommand = $this->pre_invoke( $args ); - $subcommand->invoke( $args, $assoc_args ); - } - function pre_invoke( &$args ) { - $subcommand = $this->find_subcommand( $args ); - - if ( !$subcommand ) { - $this->show_usage(); - exit; - } - - return $subcommand; + return $this->find_subcommand( $args ); } function find_subcommand( &$args ) { diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index a98683e12..9b19204b1 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class RootCommand implements Command, Composite { +class RootCommand implements CommandContainer { protected $subcommands = array(); @@ -35,18 +35,14 @@ function show_usage() { ); } - function invoke( $args, $assoc_args ) { - $subcommand = $this->pre_invoke( $args ); - $subcommand->invoke( $args, $assoc_args ); - } - function pre_invoke( &$args ) { - if ( empty( $args ) || array( 'help' ) == $args ) { + if ( array( 'help' ) == $args ) { $this->show_usage(); exit; } $cmd_name = $args[0]; + $command = $this->find_subcommand( $args ); if ( !$command ) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b23be480e..653429add 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -349,7 +349,7 @@ static function after_wp_load() { // Handle --syn-list parameter if ( isset( self::$config['syn-list'] ) ) { foreach ( self::$root->get_subcommands() as $command ) { - if ( $command instanceof Dispatcher\Composite ) { + if ( $command instanceof Dispatcher\CommandContainer ) { foreach ( $command->get_subcommands() as $subcommand ) $subcommand->show_usage( '' ); } else { @@ -369,7 +369,11 @@ static function after_wp_load() { private static function run_command() { $command = Dispatcher\traverse( self::$arguments, 'pre_invoke' ); - $command->invoke( self::$arguments, self::$assoc_args ); + + if ( $command instanceof Dispatcher\CommandContainer ) + $command->show_usage(); + else + $command->invoke( self::$arguments, self::$assoc_args ); } private static function show_info() { diff --git a/php/dispatcher.php b/php/dispatcher.php index 78e12d442..95bcd0891 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -7,7 +7,7 @@ function traverse( &$args, $method = 'find_subcommand' ) { $command = \WP_CLI::$root; - while ( !empty( $args ) && $command && $command instanceof Composite ) { + while ( !empty( $args ) && $command && $command instanceof CommandContainer ) { $command = $command->$method( $args ); } @@ -28,10 +28,13 @@ function invoke( $args, $assoc_args ); } -interface Composite { +interface CommandContainer { + + function show_usage(); - function pre_invoke( &$args ); function find_subcommand( &$args ); + + function pre_invoke( &$args ); } diff --git a/php/man.php b/php/man.php index 6a06c169e..2e40ec4b7 100644 --- a/php/man.php +++ b/php/man.php @@ -18,7 +18,7 @@ function generate( $src_dir, $dest_dir, $command ) { call_ronn( get_markdown( $src_path, $command ), $dest_path ); - if ( $command instanceof Dispatcher\Composite ) { + if ( $command instanceof Dispatcher\CommandContainer ) { foreach ( $command->get_subcommands() as $subcommand ) { generate( $src_dir, $dest_dir, $subcommand ); } @@ -70,7 +70,7 @@ function add_initial_markdown( $fd, $command ) { DOC ); - if ( $command instanceof Dispatcher\Composite ) { + if ( $command instanceof Dispatcher\CommandContainer ) { fwrite( $fd, <<<DOC ## SUBCOMMANDS From f249ee30601133e90f4440dc9df2e83f5352919b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 12:52:25 +0200 Subject: [PATCH 1004/5359] regenerate man pages. see #229 --- man/post-update.1 | 2 +- man/user-delete.1 | 4 ++-- man/user-update.1 | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/post-update.1 b/man/post-update.1 index 534a319d4..91b69b6b5 100644 --- a/man/post-update.1 +++ b/man/post-update.1 @@ -4,7 +4,7 @@ .TH "WP\-POST\-UPDATE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-post\-update\fR \- Update a post\. +\fBwp\-post\-update\fR \- Update one or more posts\. . .SH "SYNOPSIS" wp post update \fIid\fR\.\.\. \-\-\fIfield\fR=\fIvalue\fR diff --git a/man/user-delete.1 b/man/user-delete.1 index 0666e0147..d498eb415 100644 --- a/man/user-delete.1 +++ b/man/user-delete.1 @@ -4,10 +4,10 @@ .TH "WP\-USER\-DELETE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-user\-delete\fR \- Delete a user\. +\fBwp\-user\-delete\fR \- Delete one or more users\. . .SH "SYNOPSIS" -wp user delete \fIid\fR [\-\-reassign=\fIid\fR] +wp user delete \fIid\fR\.\.\. [\-\-reassign=\fIid\fR] . .SH "OPTIONS" . diff --git a/man/user-update.1 b/man/user-update.1 index 4750f707e..965501ff5 100644 --- a/man/user-update.1 +++ b/man/user-update.1 @@ -7,7 +7,7 @@ \fBwp\-user\-update\fR \- Update a user\. . .SH "SYNOPSIS" -wp user update \fIid\fR \-\-\fIfield\fR=\fIvalue\fR +wp user update \fIid\fR\.\.\. \-\-\fIfield\fR=\fIvalue\fR . .SH "OPTIONS" . From d19f323ec005d85864c7c409e1f7bdf67c7398d3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 12:59:09 +0200 Subject: [PATCH 1005/5359] only command containers can have subcommands --- php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/WP_CLI/Dispatcher/Subcommand.php | 4 ---- php/class-wp-cli.php | 2 +- php/dispatcher.php | 13 ++++++++++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 9b19204b1..4df759aed 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -16,7 +16,7 @@ function show_usage() { foreach ( $this->get_subcommands() as $command ) { \WP_CLI::line( sprintf( " wp %s %s", implode( ' ', $command->get_path() ), - implode( '|', array_keys( $command->get_subcommands() ) ) + implode( '|', array_keys( get_subcommands( $command ) ) ) ) ); } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 9f4259f99..88be1f595 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -32,10 +32,6 @@ function invoke( $args, $assoc_args ) { call_user_func( $this->callable, $args, $assoc_args ); } - function get_subcommands() { - return array(); - } - function get_name() { return $this->name; } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 653429add..c91297eeb 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -398,7 +398,7 @@ private static function generate_man( $args ) { private static function render_automcomplete() { foreach ( self::$root->get_subcommands() as $name => $command ) { - $subcommands = $command->get_subcommands(); + $subcommands = Dispatcher\get_subcommands( $command ); self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); } diff --git a/php/dispatcher.php b/php/dispatcher.php index 95bcd0891..8c94d6505 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -17,23 +17,30 @@ function traverse( &$args, $method = 'find_subcommand' ) { return $command; } +function get_subcommands( $command ) { + if ( $command instanceof CommandContainer ) + return $command->get_subcommands(); + + return array(); +} + interface Command { function get_path(); - function get_subcommands(); - function show_usage(); + function invoke( $args, $assoc_args ); } interface CommandContainer { + function get_subcommands(); + function show_usage(); function find_subcommand( &$args ); - function pre_invoke( &$args ); } From 3de7e636a40118ed47e428821f1012a9439b92ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 13:51:44 +0200 Subject: [PATCH 1006/5359] transform get_path() method into a standalone function also introduce AtomicCommand interface --- php/WP_CLI/Dispatcher/CompositeCommand.php | 10 +++++++--- php/WP_CLI/Dispatcher/RootCommand.php | 14 +++++++++----- php/WP_CLI/Dispatcher/Subcommand.php | 10 +++++----- php/dispatcher.php | 20 +++++++++++++++++--- php/man.php | 12 ++++++++---- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 05f973ec9..2f3ccafb9 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class CompositeCommand implements CommandContainer, Documentable { +class CompositeCommand implements Command, CommandContainer, Documentable { protected $name; @@ -35,8 +35,12 @@ private function collect_subcommands( $reflection, $class ) { return $subcommands; } - function get_path() { - return array( $this->name ); + function get_name() { + return $this->name; + } + + function get_parent() { + return \WP_CLI::$root; } function show_usage() { diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 4df759aed..40a6ad8d6 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -2,20 +2,24 @@ namespace WP_CLI\Dispatcher; -class RootCommand implements CommandContainer { +class RootCommand implements Command, CommandContainer { protected $subcommands = array(); - function get_path() { - return array(); + function get_name() { + return 'wp'; + } + + function get_parent() { + return false; } function show_usage() { \WP_CLI::line( 'Available commands:' ); foreach ( $this->get_subcommands() as $command ) { - \WP_CLI::line( sprintf( " wp %s %s", - implode( ' ', $command->get_path() ), + \WP_CLI::line( sprintf( " %s %s", + implode( ' ', get_path( $command ) ), implode( '|', array_keys( get_subcommands( $command ) ) ) ) ); } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 88be1f595..21238a1ff 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class Subcommand implements Command, Documentable { +class Subcommand implements Command, AtomicCommand, Documentable { function __construct( $name, $callable, $docparser, $parent ) { $this->name = $name; @@ -20,10 +20,10 @@ function get_shortdesc() { } function get_full_synopsis() { - $full_name = implode( ' ', $this->get_path() ); + $full_name = implode( ' ', get_path( $this ) ); $synopsis = $this->docparser->get_synopsis(); - return "wp $full_name $synopsis"; + return "$full_name $synopsis"; } function invoke( $args, $assoc_args ) { @@ -36,8 +36,8 @@ function get_name() { return $this->name; } - function get_path() { - return array_merge( $this->parent->get_path(), array( $this->get_name() ) ); + function get_parent() { + return $this->parent; } protected function check_args( $args, $assoc_args ) { diff --git a/php/dispatcher.php b/php/dispatcher.php index 8c94d6505..48aa9b22a 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -24,11 +24,27 @@ function get_subcommands( $command ) { return array(); } +function get_path( Command $command ) { + $path = array(); + + do { + array_unshift( $path, $command->get_name() ); + } while ( $command = $command->get_parent() ); + + return $path; +} + interface Command { - function get_path(); + function get_name(); + function get_parent(); + function show_usage(); +} + + +interface AtomicCommand { function invoke( $args, $assoc_args ); } @@ -38,8 +54,6 @@ interface CommandContainer { function get_subcommands(); - function show_usage(); - function find_subcommand( &$args ); function pre_invoke( &$args ); } diff --git a/php/man.php b/php/man.php index 2e40ec4b7..64f9fd69b 100644 --- a/php/man.php +++ b/php/man.php @@ -13,8 +13,11 @@ function get_src_file_name( $args ) { } function generate( $src_dir, $dest_dir, $command ) { - $src_path = $src_dir . get_src_file_name( $command->get_path() ); - $dest_path = $dest_dir . get_file_name( $command->get_path() ); + $cmd_path = Dispatcher\get_path( $command ); + array_shift( $cmd_path ); // discard 'wp' + + $src_path = $src_dir . get_src_file_name( $cmd_path ); + $dest_path = $dest_dir . get_file_name( $cmd_path ); call_ronn( get_markdown( $src_path, $command ), $dest_path ); @@ -46,7 +49,8 @@ function get_markdown( $doc_path, $command ) { } function add_initial_markdown( $fd, $command ) { - $path = $command->get_path(); + $path = Dispatcher\get_path( $command ); + $shortdesc = $command->get_shortdesc(); $synopsis = $command->get_full_synopsis(); @@ -60,7 +64,7 @@ function add_initial_markdown( $fd, $command ) { } fwrite( $fd, <<<DOC -wp-$name_m(1) -- $shortdesc +$name_m(1) -- $shortdesc ==== ## SYNOPSIS From ec34284e2c848e483b7fc87a52527ea37a71b452 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 14:32:08 +0200 Subject: [PATCH 1007/5359] make load_command() protected --- php/WP_CLI/Dispatcher/RootCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 40a6ad8d6..47b5b2417 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -69,9 +69,9 @@ function find_subcommand( &$args ) { } function add_command( $name, $implementation ) { - if ( is_string( $implementation ) ) + if ( is_string( $implementation ) ) { $command = new CompositeCommand( $name, $implementation ); - else { + } else { $method = new \ReflectionMethod( $implementation, '__invoke' ); $docparser = new \WP_CLI\DocParser( $method ); @@ -92,7 +92,7 @@ function get_subcommands() { protected function load_all_commands() { foreach ( glob( WP_CLI_ROOT . "/commands/*.php" ) as $filename ) { - $command = substr( basename( $filename ), 0, -4 ); + $command = str_replace( '.php', '', $filename ); if ( isset( $this->subcommands[ $command ] ) ) continue; @@ -101,7 +101,7 @@ protected function load_all_commands() { } } - function load_command( $command ) { + protected function load_command( $command ) { if ( !isset( $this->subcommands[$command] ) ) { $path = WP_CLI_ROOT . "/commands/$command.php"; From 9c6231c331c5951066207b9c6b17660006ba0da4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 14:39:27 +0200 Subject: [PATCH 1008/5359] add_command(): move logic back to WP_CLI class --- php/WP_CLI/Dispatcher/RootCommand.php | 12 +----------- php/class-wp-cli.php | 12 +++++++++++- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 47b5b2417..e1319b230 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -68,17 +68,7 @@ function find_subcommand( &$args ) { return $this->load_command( $command ); } - function add_command( $name, $implementation ) { - if ( is_string( $implementation ) ) { - $command = new CompositeCommand( $name, $implementation ); - } else { - $method = new \ReflectionMethod( $implementation, '__invoke' ); - - $docparser = new \WP_CLI\DocParser( $method ); - - $command = new Subcommand( $name, $implementation, $docparser, $this ); - } - + function add_command( $name, Command $command ) { $this->subcommands[ $name ] = $command; } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index c91297eeb..74072460d 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -25,7 +25,17 @@ class WP_CLI { * @param string|object $implementation The command implementation */ static function add_command( $name, $implementation ) { - self::$root->add_command( $name, $implementation ); + if ( is_string( $implementation ) ) { + $command = new Dispatcher\CompositeCommand( $name, $implementation ); + } else { + $method = new \ReflectionMethod( $implementation, '__invoke' ); + + $docparser = new \WP_CLI\DocParser( $method ); + + $command = new Dispatcher\Subcommand( $name, $implementation, $docparser, self::$root ); + } + + self::$root->add_command( $name, $command ); } static function add_man_dir( $dest_dir, $src_dir ) { From 0371ceebbed83a41e059d028149140a4c8a189ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 14:45:50 +0200 Subject: [PATCH 1009/5359] introduce AbstractCommandContainer class --- .../Dispatcher/AbstractCommandContainer.php | 19 +++++++++++++++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 8 +------- php/WP_CLI/Dispatcher/RootCommand.php | 12 ++---------- php/class-wp-cli.php | 2 +- php/dispatcher.php | 1 + 5 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 php/WP_CLI/Dispatcher/AbstractCommandContainer.php diff --git a/php/WP_CLI/Dispatcher/AbstractCommandContainer.php b/php/WP_CLI/Dispatcher/AbstractCommandContainer.php new file mode 100644 index 000000000..29136f920 --- /dev/null +++ b/php/WP_CLI/Dispatcher/AbstractCommandContainer.php @@ -0,0 +1,19 @@ +<?php + +namespace WP_CLI\Dispatcher; + +abstract class AbstractCommandContainer implements Command, CommandContainer { + + protected $subcommands = array(); + + function add_subcommand( $name, Command $command ) { + $this->subcommands[ $name ] = $command; + } + + function get_subcommands() { + ksort( $this->subcommands ); + + return $this->subcommands; + } +} + diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 2f3ccafb9..40ed2ea72 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,12 +2,10 @@ namespace WP_CLI\Dispatcher; -class CompositeCommand implements Command, CommandContainer, Documentable { +class CompositeCommand extends AbstractCommandContainer implements Documentable { protected $name; - protected $subcommands; - protected $shortdesc; public function __construct( $name, $class ) { @@ -93,10 +91,6 @@ private static function get_aliases( $subcommands ) { return $aliases; } - public function get_subcommands() { - return $this->subcommands; - } - public function get_shortdesc() { return $this->docparser->get_shortdesc(); } diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index e1319b230..080ad4cbc 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -2,9 +2,7 @@ namespace WP_CLI\Dispatcher; -class RootCommand implements Command, CommandContainer { - - protected $subcommands = array(); +class RootCommand extends AbstractCommandContainer { function get_name() { return 'wp'; @@ -68,16 +66,10 @@ function find_subcommand( &$args ) { return $this->load_command( $command ); } - function add_command( $name, Command $command ) { - $this->subcommands[ $name ] = $command; - } - function get_subcommands() { $this->load_all_commands(); - ksort( $this->subcommands ); - - return $this->subcommands; + return parent::get_subcommands(); } protected function load_all_commands() { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 74072460d..217addfe0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -35,7 +35,7 @@ static function add_command( $name, $implementation ) { $command = new Dispatcher\Subcommand( $name, $implementation, $docparser, self::$root ); } - self::$root->add_command( $name, $command ); + self::$root->add_subcommand( $name, $command ); } static function add_man_dir( $dest_dir, $src_dir ) { diff --git a/php/dispatcher.php b/php/dispatcher.php index 48aa9b22a..f59914489 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -52,6 +52,7 @@ function invoke( $args, $assoc_args ); interface CommandContainer { + function add_subcommand( $name, Command $command ); function get_subcommands(); function find_subcommand( &$args ); From 37a3b95f0b345cadec1df40de063cbc104c7d069 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 15:23:34 +0200 Subject: [PATCH 1010/5359] introduce 'disabled_commands' config key --- php/class-wp-cli.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 217addfe0..d708dc6cf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -263,7 +263,7 @@ static function before_wp_load() { ); self::$config = Utils\load_config( array( - 'path', 'url', 'user' + 'path', 'url', 'user', 'disabled_commands' ) ); self::parse_args(); @@ -380,10 +380,25 @@ static function after_wp_load() { private static function run_command() { $command = Dispatcher\traverse( self::$arguments, 'pre_invoke' ); - if ( $command instanceof Dispatcher\CommandContainer ) + self::check_disabled_commands( $command ); + + if ( $command instanceof Dispatcher\CommandContainer ) { $command->show_usage(); - else + } else { $command->invoke( self::$arguments, self::$assoc_args ); + } + } + + private static function check_disabled_commands( Dispatcher\Command $command ) { + if ( !isset( self::$config['disabled_commands'] ) ) + return; + + $path = Dispatcher\get_path( $command ); + array_shift( $path ); + $cmd_str = implode( ' ', $path ); + + if ( in_array( $cmd_str, self::$config['disabled_commands'] ) ) + WP_CLI::error( "The '$cmd_str' command is disabled." ); } private static function show_info() { From 01c53757549105c19fb63cc06c134c3ff5d10947 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 16:22:00 +0200 Subject: [PATCH 1011/5359] create new command instance on each invocation. fixes #257 --- php/WP_CLI/Dispatcher/CompositeCommand.php | 2 +- php/WP_CLI/Dispatcher/MethodSubcommand.php | 8 ++++---- php/WP_CLI/Dispatcher/Subcommand.php | 6 ++++-- php/class-wp-cli.php | 20 ++++++++++++++------ php/dispatcher.php | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 40ed2ea72..52b6dfa8b 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -25,7 +25,7 @@ private function collect_subcommands( $reflection, $class ) { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new MethodSubcommand( $class, $method, $this ); + $subcommand = new MethodSubcommand( $this, $class, $method ); $subcommands[ $subcommand->get_name() ] = $subcommand; } diff --git a/php/WP_CLI/Dispatcher/MethodSubcommand.php b/php/WP_CLI/Dispatcher/MethodSubcommand.php index 5ef500c56..f66329bc2 100644 --- a/php/WP_CLI/Dispatcher/MethodSubcommand.php +++ b/php/WP_CLI/Dispatcher/MethodSubcommand.php @@ -4,16 +4,16 @@ class MethodSubcommand extends Subcommand { - function __construct( $class, $method, $parent ) { - $callable = array( new $class, $method->name ); - + function __construct( CommandContainer $parent, $class, \ReflectionMethod $method ) { $docparser = new \WP_CLI\DocParser( $method ); $name = $docparser->get_tag( 'subcommand' ); if ( !$name ) $name = $method->name; - parent::__construct( $name, $callable, $docparser, $parent ); + $callable = new CallableMethod( $class, $method->name ); + + parent::__construct( $parent, $name, $callable, $docparser ); } function get_alias() { diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 21238a1ff..0432e7a83 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -4,11 +4,13 @@ class Subcommand implements Command, AtomicCommand, Documentable { - function __construct( $name, $callable, $docparser, $parent ) { + function __construct( CommandContainer $parent, $name, $callable, $docparser ) { + $this->parent = $parent; $this->name = $name; + $this->callable = $callable; + $this->docparser = $docparser; - $this->parent = $parent; } function show_usage( $prefix = 'usage: ' ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d708dc6cf..cfcf815c8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -26,18 +26,26 @@ class WP_CLI { */ static function add_command( $name, $implementation ) { if ( is_string( $implementation ) ) { - $command = new Dispatcher\CompositeCommand( $name, $implementation ); + $command = self::create_composite_command( $name, $implementation ); } else { - $method = new \ReflectionMethod( $implementation, '__invoke' ); - - $docparser = new \WP_CLI\DocParser( $method ); - - $command = new Dispatcher\Subcommand( $name, $implementation, $docparser, self::$root ); + $command = self::create_atomic_command( $name, $implementation ); } self::$root->add_subcommand( $name, $command ); } + private static function create_composite_command( $name, $class ) { + return new Dispatcher\CompositeCommand( $name, $class ); + } + + private static function create_atomic_command( $name, $implementation ) { + $method = new \ReflectionMethod( $implementation, '__invoke' ); + + $docparser = new \WP_CLI\DocParser( $method ); + + return new Dispatcher\Subcommand( self::$root, $name, $implementation, $docparser ); + } + static function add_man_dir( $dest_dir, $src_dir ) { $dest_dir = realpath( $dest_dir ) . '/'; diff --git a/php/dispatcher.php b/php/dispatcher.php index f59914489..148704fb4 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -66,3 +66,18 @@ function get_shortdesc(); function get_full_synopsis(); } + +class CallableMethod { + + function __construct( $class, $method ) { + $this->class = $class; + $this->method = $method; + } + + function __invoke( $args, $assoc_args ) { + $instance = new $this->class; + + call_user_func( array( $instance, $this->method ), $args, $assoc_args ); + } +} + From 25eb311bf1df96de37301661aec2dea36f1edb7a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 16:54:09 +0200 Subject: [PATCH 1012/5359] move logic from CompositeCommand constructor to WP_CLI class --- php/WP_CLI/Dispatcher/CompositeCommand.php | 31 +++------------------- php/class-wp-cli.php | 21 ++++++++++++++- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 52b6dfa8b..e0ff1f670 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -5,32 +5,11 @@ class CompositeCommand extends AbstractCommandContainer implements Documentable { protected $name; - protected $shortdesc; - public function __construct( $name, $class ) { + public function __construct( $name, $shortdesc ) { $this->name = $name; - - $reflection = new \ReflectionClass( $class ); - - $this->subcommands = $this->collect_subcommands( $reflection, $class ); - - $this->docparser = new \WP_CLI\DocParser( $reflection ); - } - - private function collect_subcommands( $reflection, $class ) { - $subcommands = array(); - - foreach ( $reflection->getMethods() as $method ) { - if ( !self::_is_good_method( $method ) ) - continue; - - $subcommand = new MethodSubcommand( $this, $class, $method ); - - $subcommands[ $subcommand->get_name() ] = $subcommand; - } - - return $subcommands; + $this->shortdesc = $shortdesc; } function get_name() { @@ -92,7 +71,7 @@ private static function get_aliases( $subcommands ) { } public function get_shortdesc() { - return $this->docparser->get_shortdesc(); + return $this->shortdesc; } public function get_full_synopsis() { @@ -104,9 +83,5 @@ public function get_full_synopsis() { return implode( "\n\n", $str ); } - - private static function _is_good_method( $method ) { - return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); - } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cfcf815c8..283032238 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -35,7 +35,26 @@ static function add_command( $name, $implementation ) { } private static function create_composite_command( $name, $class ) { - return new Dispatcher\CompositeCommand( $name, $class ); + $reflection = new \ReflectionClass( $class ); + + $docparser = new \WP_CLI\DocParser( $reflection ); + + $container = new Dispatcher\CompositeCommand( $name, $docparser->get_shortdesc() ); + + foreach ( $reflection->getMethods() as $method ) { + if ( !self::_is_good_method( $method ) ) + continue; + + $subcommand = new Dispatcher\MethodSubcommand( $container, $class, $method ); + + $container->add_subcommand( $subcommand->get_name(), $subcommand ); + } + + return $container; + } + + private static function _is_good_method( $method ) { + return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } private static function create_atomic_command( $name, $implementation ) { From 275867dbb876b30a8c274687dafd2f213440bb69 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 17:07:23 +0200 Subject: [PATCH 1013/5359] check disabled commands during registration, instead of during invocation --- php/class-wp-cli.php | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 283032238..2ea75d2e2 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -25,6 +25,9 @@ class WP_CLI { * @param string|object $implementation The command implementation */ static function add_command( $name, $implementation ) { + if ( in_array( $name, self::$config['disabled_commands'] ) ) + return; + if ( is_string( $implementation ) ) { $command = self::create_composite_command( $name, $implementation ); } else { @@ -47,12 +50,25 @@ private static function create_composite_command( $name, $class ) { $subcommand = new Dispatcher\MethodSubcommand( $container, $class, $method ); - $container->add_subcommand( $subcommand->get_name(), $subcommand ); + $subcommand_name = $subcommand->get_name(); + $full_name = self::get_full_name( $subcommand ); + + if ( in_array( $full_name, self::$config['disabled_commands'] ) ) + continue; + + $container->add_subcommand( $subcommand_name, $subcommand ); } return $container; } + private static function get_full_name( Dispatcher\Command $command ) { + $path = Dispatcher\get_path( $command ); + array_shift( $path ); + + return implode( ' ', $path ); + } + private static function _is_good_method( $method ) { return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } @@ -293,6 +309,9 @@ static function before_wp_load() { 'path', 'url', 'user', 'disabled_commands' ) ); + if ( !isset( self::$config['disabled_commands'] ) ) + self::$config['disabled_commands'] = array(); + self::parse_args(); define( 'WP_CLI_QUIET', isset( self::$config['quiet'] ) ); @@ -407,8 +426,6 @@ static function after_wp_load() { private static function run_command() { $command = Dispatcher\traverse( self::$arguments, 'pre_invoke' ); - self::check_disabled_commands( $command ); - if ( $command instanceof Dispatcher\CommandContainer ) { $command->show_usage(); } else { @@ -416,18 +433,6 @@ private static function run_command() { } } - private static function check_disabled_commands( Dispatcher\Command $command ) { - if ( !isset( self::$config['disabled_commands'] ) ) - return; - - $path = Dispatcher\get_path( $command ); - array_shift( $path ); - $cmd_str = implode( ' ', $path ); - - if ( in_array( $cmd_str, self::$config['disabled_commands'] ) ) - WP_CLI::error( "The '$cmd_str' command is disabled." ); - } - private static function show_info() { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); From 882c629fbdb294fdb226a5678c1b7fb92227df7a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 17:32:32 +0200 Subject: [PATCH 1014/5359] fix test_message_explains_that_config_must_be_present_before_install(). see #170 --- tests/core-Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core-Test.php b/tests/core-Test.php index 20ba5bc89..af2f07112 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -56,7 +56,7 @@ public function test_message_explains_that_config_must_be_present_before_install $installer->download_wordpress_files( $temp_dir ); $result = $runner->run_wp_cli( "core install" ); $this->assertEquals( - "^[[31;1mError: ^[[0mwp-config.php not found.\n" . + "Error: wp-config.php not found.\n" . "Either create one manually or use `wp core config`.\n", $result->output ); From 8d1214be042131e0f319c454c6058042244731c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 17:38:09 +0200 Subject: [PATCH 1015/5359] add phpunit.xml file --- README.md | 6 ++-- tests/bootstrap.php | 5 +++ tests/core-Test.php | 3 -- tests/phpunit.xml | 13 ++++++++ tests/test_core.php | 78 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 tests/bootstrap.php create mode 100644 tests/phpunit.xml create mode 100644 tests/test_core.php diff --git a/README.md b/README.md index c6d3179f1..10c52eeee 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ Running the following as root in MySQL should do the trick: GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; - + Finally, to run the tests: - vendor/bin/phpunit tests + vendor/bin/phpunit -c tests/phpunit.xml Most tests install WordPress from scratch. Since this is pretty slow, you can use arguments to `phpunit` to only run the test that you're interested in: - vendor/bin/phpunit --filter test_function_you_want_to_run tests + vendor/bin/phpunit -c tests/phpunit.xml --filter test_function_you_want_to_run tests diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 000000000..ac6ee7195 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,5 @@ +<?php + +require __DIR__ . '/class-command-runner.php'; +require __DIR__ . '/class-wp-cli-test-case.php'; + diff --git a/tests/core-Test.php b/tests/core-Test.php index af2f07112..ded886a6e 100644 --- a/tests/core-Test.php +++ b/tests/core-Test.php @@ -1,8 +1,5 @@ <?php -require_once __DIR__ . '/class-command-runner.php'; -require_once __DIR__ . '/class-wp-cli-test-case.php'; - class CoreTest extends Wp_Cli_Test_Case { public function test_is_installed_exits_with_1_if_empty_dir() { diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 000000000..4ea00f4df --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,13 @@ +<phpunit + bootstrap="bootstrap.php" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + > + <testsuites> + <testsuite> + <directory prefix="test_" suffix=".php">./</directory> + </testsuite> + </testsuites> +</phpunit> diff --git a/tests/test_core.php b/tests/test_core.php new file mode 100644 index 000000000..af2f07112 --- /dev/null +++ b/tests/test_core.php @@ -0,0 +1,78 @@ +<?php + +require_once __DIR__ . '/class-command-runner.php'; +require_once __DIR__ . '/class-wp-cli-test-case.php'; + +class CoreTest extends Wp_Cli_Test_Case { + + public function test_is_installed_exits_with_1_if_empty_dir() { + $temp_dir = $this->create_temporary_directory(); + $runner = new Command_Runner( $temp_dir ); + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); + } + + public function test_is_installed_exits_with_1_if_missing_wp_config() { + $temp_dir = $this->create_temporary_directory(); + + $runner = new Command_Runner( $temp_dir ); + + $installer = new Wordpress_Installer( $temp_dir, $runner ); + $installer->download_wordpress_files( $temp_dir ); + + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); + } + + public function test_is_installed_exits_with_1_if_db_not_installed() { + $temp_dir = $this->create_temporary_directory(); + + $runner = new Command_Runner( $temp_dir ); + + $installer = new Wordpress_Installer( $temp_dir, $runner ); + $installer->download_wordpress_files( $temp_dir ); + $installer->create_config( $this->db_settings ); + + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 1, $result->return_code ); + } + + public function test_is_installed_exits_with_0_after_running_install_command() { + $runner = $this->full_wp_install(); + $result = $runner->run_wp_cli( "core is-installed" ); + $this->assertEquals( 0, $result->return_code ); + } + + public function test_install_command_creates_default_blog_post() { + $runner = $this->full_wp_install(); + $result = $runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } + + public function test_message_explains_that_config_must_be_present_before_install() { + $temp_dir = $this->create_temporary_directory(); + $runner = new Command_Runner( $temp_dir ); + $installer = new Wordpress_Installer( $temp_dir, $runner ); + $installer->download_wordpress_files( $temp_dir ); + $result = $runner->run_wp_cli( "core install" ); + $this->assertEquals( + "Error: wp-config.php not found.\n" . + "Either create one manually or use `wp core config`.\n", + $result->output + ); + } + + public function test_wp_config_can_be_placed_in_parent_directory() { + $temp_dir = $this->create_temporary_directory(); + $install_dir = $temp_dir . '/www-root'; + mkdir( $install_dir ); + $runner = new Command_Runner( $install_dir ); + $installer = new Wordpress_Installer( $install_dir, $runner ); + $installer->download_wordpress_files( $install_dir ); + $installer->create_config( $this->db_settings ); + rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); + $installer->run_install(); + $result = $runner->run_wp_cli( "post list --ids" ); + $this->assertEquals( "1", $result->output ); + } +} From 0857778911cff25a82c8e1ea323bacca4a8598d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 17:41:13 +0200 Subject: [PATCH 1016/5359] move phpunit.xml to the root dir --- .gitignore | 1 + README.md | 4 ++-- tests/phpunit.xml => phpunit.xml.dist | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) rename tests/phpunit.xml => phpunit.xml.dist (67%) diff --git a/.gitignore b/.gitignore index 8b2103e77..8e2a67431 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /dist /vendor /composer.lock +/phpunit.xml diff --git a/README.md b/README.md index 10c52eeee..2f9ec0ff2 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ Running the following as root in MySQL should do the trick: Finally, to run the tests: - vendor/bin/phpunit -c tests/phpunit.xml + vendor/bin/phpunit Most tests install WordPress from scratch. Since this is pretty slow, you can use arguments to `phpunit` to only run the test that you're interested in: - vendor/bin/phpunit -c tests/phpunit.xml --filter test_function_you_want_to_run tests + vendor/bin/phpunit --filter test_function_you_want_to_run diff --git a/tests/phpunit.xml b/phpunit.xml.dist similarity index 67% rename from tests/phpunit.xml rename to phpunit.xml.dist index 4ea00f4df..77cb7d28d 100644 --- a/tests/phpunit.xml +++ b/phpunit.xml.dist @@ -1,5 +1,5 @@ <phpunit - bootstrap="bootstrap.php" + bootstrap="tests/bootstrap.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" @@ -7,7 +7,7 @@ > <testsuites> <testsuite> - <directory prefix="test_" suffix=".php">./</directory> + <directory prefix="test_" suffix=".php">tests/</directory> </testsuite> </testsuites> </phpunit> From ca0dcbed5c983e65a8c5e93054a1734a5031b18f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 17:59:41 +0200 Subject: [PATCH 1017/5359] dismantle Dispatcher\traverse() --- php/class-wp-cli.php | 26 ++++++++++++++++++++++---- php/commands/help.php | 12 ++++++++++-- php/dispatcher.php | 15 --------------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 2ea75d2e2..426c8afff 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -424,12 +424,22 @@ static function after_wp_load() { } private static function run_command() { - $command = Dispatcher\traverse( self::$arguments, 'pre_invoke' ); + $command = \WP_CLI::$root; + + $args = self::$arguments; + + while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { + $subcommand = $command->pre_invoke( $args ); + if ( !$subcommand ) + break; + + $command = $subcommand; + } if ( $command instanceof Dispatcher\CommandContainer ) { $command->show_usage(); } else { - $command->invoke( self::$arguments, self::$assoc_args ); + $command->invoke( $args, self::$assoc_args ); } } @@ -444,9 +454,17 @@ private static function show_info() { } private static function generate_man( $args ) { - $command = Dispatcher\traverse( $args ); + $arg_copy = $args; + + $command = \WP_CLI::$root; + + while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { + $command = $command->find_subcommand( $args ); + } + if ( !$command ) - WP_CLI::error( sprintf( "'%s' command not found." ) ); + WP_CLI::error( sprintf( "'%s' command not found.", + implode( ' ', $arg_copy ) ) ); foreach ( self::$man_dirs as $dest_dir => $src_dir ) { \WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); diff --git a/php/commands/help.php b/php/commands/help.php index 11fa2aa6a..1d83ba159 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -2,6 +2,8 @@ WP_CLI::add_command( 'help', new Help_Command ); +use \WP_CLI\Dispatcher\CommandContainer; + /** * Implement help command * @@ -18,10 +20,16 @@ class Help_Command extends WP_CLI_Command { function __invoke( $args ) { self::maybe_load_man_page( $args ); - $command = \WP_CLI\Dispatcher\traverse( $args ); + $arg_copy = $args; + + $command = \WP_CLI::$root; + + while ( !empty( $args ) && $command && $command instanceof CommandContainer ) { + $command = $command->find_subcommand( $args ); + } if ( !$command ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $arg_copy[0] ) ); } $command->show_usage(); diff --git a/php/dispatcher.php b/php/dispatcher.php index 148704fb4..7b7907675 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -2,21 +2,6 @@ namespace WP_CLI\Dispatcher; -function traverse( &$args, $method = 'find_subcommand' ) { - $args_copy = $args; - - $command = \WP_CLI::$root; - - while ( !empty( $args ) && $command && $command instanceof CommandContainer ) { - $command = $command->$method( $args ); - } - - if ( !$command ) - $args = $args_copy; - - return $command; -} - function get_subcommands( $command ) { if ( $command instanceof CommandContainer ) return $command->get_subcommands(); From 0a59b5b43a2bd82e9add5aae28865f67e3854500 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 18:28:56 +0200 Subject: [PATCH 1018/5359] tests: use system(), instead of futzing with sh and temp files --- tests/class-command-runner.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index 7139cfb3b..9b72beba9 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -17,20 +17,13 @@ private function find_wp_cli() { } private function run_command( $command ) { - $output_dummy = array(); - $output_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); - $output_binary_file = tempnam( sys_get_temp_dir(), "wp-cli-test" ); - $return_code = 0; $cwd = $this->cwd; - $sh_command = "cd $cwd;" . - "$command > $output_binary_file 2>&1;" . - 'RETURN_CODE=$?;' . - "cat -v $output_binary_file > $output_file;" . - 'exit $RETURN_CODE'; - exec( "sh -c '$sh_command'", $output_dummy, $return_code ); - $output = file_get_contents( $output_file ); - unlink( $output_file ); - unlink( $output_binary_file ); + $sh_command = "cd $cwd; $command 2>&1;"; + + ob_start(); + system( $sh_command, $return_code ); + $output = ob_get_clean(); + return new Execution_Result( $return_code, $output ); } } From b60e6c17b10291a5565304c88c9cd1e149135079 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 18:31:37 +0200 Subject: [PATCH 1019/5359] don't really need an Execution_Result class --- tests/class-command-runner.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php index 9b72beba9..241f16aa3 100644 --- a/tests/class-command-runner.php +++ b/tests/class-command-runner.php @@ -24,14 +24,7 @@ private function run_command( $command ) { system( $sh_command, $return_code ); $output = ob_get_clean(); - return new Execution_Result( $return_code, $output ); + return (object) compact( 'return_code', 'output' ); } } -class Execution_Result { - - public function __construct( $return_code, $output ) { - $this->return_code = $return_code; - $this->output = $output; - } -} From 0ed20196e6acd91d164aa7807de8712dbc6972c0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 18:39:39 +0200 Subject: [PATCH 1020/5359] use wp_insert_post() in `wp post generate` again. fixes #217 --- php/commands/post.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index b7652676b..be907ed8a 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -178,8 +178,7 @@ public function generate( $args, $assoc_args ) { 'post_date' => $post_date, ); - // Not using wp_insert_post() because it's slow - $wpdb->insert( $wpdb->posts, $args ); + wp_insert_post( $args, true ); $notify->tick(); } From a57e88f6b9ed23d1b60cb08c51deca30a2aa3c8d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:14:53 +0200 Subject: [PATCH 1021/5359] minor cleanup in `wp post generate` --- php/commands/post.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index be907ed8a..49bc35e3d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -188,12 +188,12 @@ public function generate( $args, $assoc_args ) { private function maybe_make_child() { // 50% chance of making child post - return ( mt_rand(1,2) == 1 ) ? true: false; + return ( mt_rand(1, 2) == 1 ); } private function maybe_reset_depth() { // 10% chance of reseting to root depth - return ( mt_rand(1,10) == 7 ) ? true : false; + return ( mt_rand(1, 10) == 7 ); } } From 6da13d0cf6d311191817f4e5d6c0db3586ee0196 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:20:15 +0200 Subject: [PATCH 1022/5359] remove old core-Test.php file --- tests/core-Test.php | 75 --------------------------------------------- tests/test_core.php | 3 -- 2 files changed, 78 deletions(-) delete mode 100644 tests/core-Test.php diff --git a/tests/core-Test.php b/tests/core-Test.php deleted file mode 100644 index ded886a6e..000000000 --- a/tests/core-Test.php +++ /dev/null @@ -1,75 +0,0 @@ -<?php - -class CoreTest extends Wp_Cli_Test_Case { - - public function test_is_installed_exits_with_1_if_empty_dir() { - $temp_dir = $this->create_temporary_directory(); - $runner = new Command_Runner( $temp_dir ); - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_1_if_missing_wp_config() { - $temp_dir = $this->create_temporary_directory(); - - $runner = new Command_Runner( $temp_dir ); - - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_1_if_db_not_installed() { - $temp_dir = $this->create_temporary_directory(); - - $runner = new Command_Runner( $temp_dir ); - - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->db_settings ); - - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_0_after_running_install_command() { - $runner = $this->full_wp_install(); - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 0, $result->return_code ); - } - - public function test_install_command_creates_default_blog_post() { - $runner = $this->full_wp_install(); - $result = $runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } - - public function test_message_explains_that_config_must_be_present_before_install() { - $temp_dir = $this->create_temporary_directory(); - $runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - $result = $runner->run_wp_cli( "core install" ); - $this->assertEquals( - "Error: wp-config.php not found.\n" . - "Either create one manually or use `wp core config`.\n", - $result->output - ); - } - - public function test_wp_config_can_be_placed_in_parent_directory() { - $temp_dir = $this->create_temporary_directory(); - $install_dir = $temp_dir . '/www-root'; - mkdir( $install_dir ); - $runner = new Command_Runner( $install_dir ); - $installer = new Wordpress_Installer( $install_dir, $runner ); - $installer->download_wordpress_files( $install_dir ); - $installer->create_config( $this->db_settings ); - rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); - $installer->run_install(); - $result = $runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } -} diff --git a/tests/test_core.php b/tests/test_core.php index af2f07112..ded886a6e 100644 --- a/tests/test_core.php +++ b/tests/test_core.php @@ -1,8 +1,5 @@ <?php -require_once __DIR__ . '/class-command-runner.php'; -require_once __DIR__ . '/class-wp-cli-test-case.php'; - class CoreTest extends Wp_Cli_Test_Case { public function test_is_installed_exits_with_1_if_empty_dir() { From 87fab1a5c1494b359234cb568a816e64bffe2285 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:43:08 +0200 Subject: [PATCH 1023/5359] don't require passing a runner to Wordpress_Installer --- tests/class-wp-cli-test-case.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 578b49345..1a4302ab7 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -43,12 +43,13 @@ public function create_temporary_directory() { } class Wordpress_Installer { + private $install_dir; private $runner; - public function __construct( $install_dir, $runner ) { + public function __construct( $install_dir ) { $this->install_dir = $install_dir; - $this->runner = $runner; + $this->runner = new Command_Runner( $install_dir ); } public function create_config( $db_settings ) { From ec279ecdf01317f466337d3c4a7dd0e4f373c109 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:17:43 +0200 Subject: [PATCH 1024/5359] add phpunit-story as a dev dependency --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c4d8fec42..abdda1a44 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "wp-cli/php-cli-tools": "dev-master" }, "require-dev": { - "phpunit/phpunit": "3.7.x" + "phpunit/phpunit": "3.7.x", + "phpunit/phpunit-story": "1.0.x" }, "autoload": { "psr-0": { "WP_CLI": "php" } From 7340ce31f953c90efaec1b89aaa8a4f825d0212b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:30:07 +0200 Subject: [PATCH 1025/5359] update phpunit.xml to run the spec tests --- phpunit.xml.dist | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 77cb7d28d..49615945a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,11 @@ <phpunit bootstrap="tests/bootstrap.php" colors="true" - convertErrorsToExceptions="true" - convertNoticesToExceptions="true" - convertWarningsToExceptions="true" + printerClass="PHPUnit_Extensions_Story_ResultPrinter_Text" > <testsuites> <testsuite> - <directory prefix="test_" suffix=".php">tests/</directory> + <directory prefix="spec-" suffix=".php">tests/</directory> </testsuite> </testsuites> </phpunit> From acafdc6ffba8e05b5535a10dfc28bc8b520caad9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 19:31:30 +0200 Subject: [PATCH 1026/5359] add first scenario --- tests/spec-core.php | 88 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/spec-core.php diff --git a/tests/spec-core.php b/tests/spec-core.php new file mode 100644 index 000000000..40dc2993d --- /dev/null +++ b/tests/spec-core.php @@ -0,0 +1,88 @@ +<?php + +class CoreCommandSpec extends PHPUnit_Extensions_Story_TestCase { + + /** + * @scenario + */ + public function emptyDir() { + $this + ->given( 'empty dir' ) + ->when( 'invoking core is-installed' ) + ->then( 'return code should be', 1 ); + } + + /** + * @scenario + */ + public function noWpConfig() { + $this + ->given( 'empty dir' ) + ->and( 'wp files' ) + ->when( 'invoking core is-installed' ) + ->then( 'return code should be', 1 ); + } + + /** + * @scenario + */ + public function notInstalled() { + $this + ->given( 'empty dir' ) + ->and( 'wp files' ) + ->and( 'wp config' ) + ->when( 'invoking core is-installed' ) + ->then( 'return code should be', 1 ); + } + + public function runGiven( &$world, $action, $arguments ) { + switch ( $action ) { + case 'empty dir': { + $world['temp_dir'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $world['temp_dir'] ); + } + break; + + case 'wp files': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->download_wordpress_files(); + } + break; + + case 'wp config': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->create_config( array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1' + ) ); + } + break; + + default: { + return $this->notImplemented( $action ); + } + } + } + + public function runWhen( &$world, $action, $arguments ) { + $cmd = str_replace( 'invoking ', '', $action ); + + $runner = new Command_Runner( $world['temp_dir'] ); + $world['result'] = $runner->run_wp_cli( $cmd ); + } + + public function runThen( &$world, $action, $arguments ) { + switch ( $action ) { + case 'return code should be': { + $this->assertEquals( $arguments[0], $world['result']->return_code ); + } + break; + + default: { + return $this->notImplemented( $action ); + } + } + } +} + From 8bf23eeeb66efa6ba8fc16ace29c5ca4cf11b405 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 20:10:53 +0200 Subject: [PATCH 1027/5359] reset database between scenarios --- tests/spec-core.php | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/spec-core.php b/tests/spec-core.php index 40dc2993d..832c76c98 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -35,6 +35,25 @@ public function notInstalled() { ->then( 'return code should be', 1 ); } + protected static $db_settings = array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1' + ); + + private static function run_sql( $sql ) { + $dbuser = self::$db_settings['dbuser']; + $dbpass = self::$db_settings['dbpass']; + + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + } + + protected function setUp() { + $dbname = self::$db_settings['dbname']; + $this->run_sql( "DROP DATABASE $dbname" ); + $this->run_sql( "CREATE DATABASE $dbname" ); + } + public function runGiven( &$world, $action, $arguments ) { switch ( $action ) { case 'empty dir': { @@ -51,11 +70,7 @@ public function runGiven( &$world, $action, $arguments ) { case 'wp config': { $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->create_config( array( - 'dbname' => 'wp_cli_test', - 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1' - ) ); + $installer->create_config( self::$db_settings ); } break; From c750bf3e5da9553bf02f9f3ab3510525c271081f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 20:29:13 +0200 Subject: [PATCH 1028/5359] add full_install() method to WordPress_Installer --- tests/class-wp-cli-test-case.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php index 1a4302ab7..7215c9ed3 100644 --- a/tests/class-wp-cli-test-case.php +++ b/tests/class-wp-cli-test-case.php @@ -27,12 +27,9 @@ private function run_sql( $sql ) { public function full_wp_install() { $temp_dir = $this->create_temporary_directory(); - $runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->db_settings ); - $installer->run_install(); - return $runner; + $installer = new Wordpress_Installer( $temp_dir ); + $installer->full_install( $this->db_settings ); + return new Command_Runner( $temp_dir ); } public function create_temporary_directory() { @@ -80,6 +77,12 @@ public function download_wordpress_files() { exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } + public function full_install( $db_settings ) { + $this->download_wordpress_files(); + $this->create_config( $db_settings ); + $this->run_install(); + } + private function assert_process_exited_successfully( $result ) { if ( $result->return_code !== 0 ) { $message = "return code was $result->return_code, output was: $result->output"; From caf32c9a0fcc033114bb0e76a10b994deab03880 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 20:29:46 +0200 Subject: [PATCH 1029/5359] more scenarios --- tests/spec-core.php | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/tests/spec-core.php b/tests/spec-core.php index 832c76c98..593389e8b 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -8,6 +8,7 @@ class CoreCommandSpec extends PHPUnit_Extensions_Story_TestCase { public function emptyDir() { $this ->given( 'empty dir' ) + ->when( 'invoking core is-installed' ) ->then( 'return code should be', 1 ); } @@ -19,22 +20,45 @@ public function noWpConfig() { $this ->given( 'empty dir' ) ->and( 'wp files' ) + ->when( 'invoking core is-installed' ) - ->then( 'return code should be', 1 ); + ->then( 'return code should be', 1 ) + + ->when( 'invoking core install' ) + ->then( 'output should be', + "Error: wp-config.php not found.\n" . + "Either create one manually or use `wp core config`.\n" + ); } /** * @scenario */ - public function notInstalled() { + public function dbTablesNotInstalled() { $this ->given( 'empty dir' ) ->and( 'wp files' ) ->and( 'wp config' ) + ->when( 'invoking core is-installed' ) ->then( 'return code should be', 1 ); } + /** + * @scenario + */ + public function fullInstall() { + $this + ->given( 'empty dir' ) + ->and( 'wp install' ) + + ->when( 'invoking core is-installed' ) + ->then( 'return code should be', 0 ) + + ->when( 'invoking post list --ids' ) + ->then( 'output should be', 1 ); + } + protected static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', @@ -74,6 +98,12 @@ public function runGiven( &$world, $action, $arguments ) { } break; + case 'wp install': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->full_install( self::$db_settings ); + } + break; + default: { return $this->notImplemented( $action ); } @@ -94,6 +124,11 @@ public function runThen( &$world, $action, $arguments ) { } break; + case 'output should be': { + $this->assertEquals( $arguments[0], $world['result']->output ); + } + break; + default: { return $this->notImplemented( $action ); } From 7e842fc564afe137d2537b7da73964ea384c3cf8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 20:50:52 +0200 Subject: [PATCH 1030/5359] remove old test cases and move all supporting code to bootstrap.php --- tests/bootstrap.php | 80 ++++++++++++++++++++++++++- tests/class-command-runner.php | 30 ----------- tests/class-wp-cli-test-case.php | 92 -------------------------------- tests/test_core.php | 75 -------------------------- 4 files changed, 78 insertions(+), 199 deletions(-) delete mode 100644 tests/class-command-runner.php delete mode 100644 tests/class-wp-cli-test-case.php delete mode 100644 tests/test_core.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index ac6ee7195..c7ce8ec8c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,81 @@ <?php -require __DIR__ . '/class-command-runner.php'; -require __DIR__ . '/class-wp-cli-test-case.php'; +class Command_Runner { + private $cwd; + public function __construct( $cwd ) { + $this->cwd = $cwd; + } + + public function run_wp_cli( $wp_cli_command ) { + $wp_cli_path = self::find_wp_cli(); + return self::run_command( "$wp_cli_path $wp_cli_command" ); + } + + private function find_wp_cli() { + return getcwd() . "/bin/wp"; + } + + private function run_command( $command ) { + $cwd = $this->cwd; + $sh_command = "cd $cwd; $command 2>&1;"; + + ob_start(); + system( $sh_command, $return_code ); + $output = ob_get_clean(); + + return (object) compact( 'return_code', 'output' ); + } +} + +class Wordpress_Installer { + + private $install_dir; + private $runner; + + public function __construct( $install_dir ) { + $this->install_dir = $install_dir; + $this->runner = new Command_Runner( $install_dir ); + } + + public function create_config( $db_settings ) { + $dbname = $db_settings["dbname"]; + $dbuser = $db_settings["dbuser"]; + $dbpass = $db_settings["dbpass"]; + $this->runner->run_wp_cli( + "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); + } + + public function run_install() { + $install_result = $this->runner->run_wp_cli( + "core install --url=http://example.com/ --title=WordPress " . + " --admin_email=admin@example.com --admin_password=password1" + ); + $this->assert_process_exited_successfully( $install_result ); + } + + public function download_wordpress_files() { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir( $cache_dir ); + $runner = new Command_Runner( $cache_dir ); + $runner->run_wp_cli( "core download" ); + } + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); + } + + public function full_install( $db_settings ) { + $this->download_wordpress_files(); + $this->create_config( $db_settings ); + $this->run_install(); + } + + private function assert_process_exited_successfully( $result ) { + if ( $result->return_code !== 0 ) { + $message = "return code was $result->return_code, output was: $result->output"; + throw new Exception( $message ); + } + } +} diff --git a/tests/class-command-runner.php b/tests/class-command-runner.php deleted file mode 100644 index 241f16aa3..000000000 --- a/tests/class-command-runner.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -class Command_Runner { - private $cwd; - - public function __construct( $cwd ) { - $this->cwd = $cwd; - } - - public function run_wp_cli( $wp_cli_command ) { - $wp_cli_path = self::find_wp_cli(); - return self::run_command( "$wp_cli_path $wp_cli_command" ); - } - - private function find_wp_cli() { - return getcwd() . "/bin/wp"; - } - - private function run_command( $command ) { - $cwd = $this->cwd; - $sh_command = "cd $cwd; $command 2>&1;"; - - ob_start(); - system( $sh_command, $return_code ); - $output = ob_get_clean(); - - return (object) compact( 'return_code', 'output' ); - } -} - diff --git a/tests/class-wp-cli-test-case.php b/tests/class-wp-cli-test-case.php deleted file mode 100644 index 7215c9ed3..000000000 --- a/tests/class-wp-cli-test-case.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php - -require_once __DIR__ . '/class-command-runner.php'; - -abstract class Wp_Cli_Test_Case extends PHPUnit_Framework_TestCase { - protected $db_settings = array( - "dbname" => "wp_cli_test", - "dbuser" => "wp_cli_test", - "dbpass" => "password1" - ); - - protected function setUp() { - $this->reset_database(); - } - - private function reset_database() { - $dbname = $this->db_settings["dbname"]; - $this->run_sql( "DROP DATABASE $dbname" ); - $this->run_sql( "CREATE DATABASE $dbname" ); - } - - private function run_sql( $sql ) { - $dbuser = $this->db_settings["dbuser"]; - $dbpass = $this->db_settings["dbpass"]; - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); - } - - public function full_wp_install() { - $temp_dir = $this->create_temporary_directory(); - $installer = new Wordpress_Installer( $temp_dir ); - $installer->full_install( $this->db_settings ); - return new Command_Runner( $temp_dir ); - } - - public function create_temporary_directory() { - $dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $dir ); - return $dir; - } -} - -class Wordpress_Installer { - - private $install_dir; - private $runner; - - public function __construct( $install_dir ) { - $this->install_dir = $install_dir; - $this->runner = new Command_Runner( $install_dir ); - } - - public function create_config( $db_settings ) { - $dbname = $db_settings["dbname"]; - $dbuser = $db_settings["dbuser"]; - $dbpass = $db_settings["dbpass"]; - $this->runner->run_wp_cli( - "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); - } - - public function run_install() { - $install_result = $this->runner->run_wp_cli( - "core install --url=http://example.com/ --title=WordPress " . - " --admin_email=admin@example.com --admin_password=password1" - ); - $this->assert_process_exited_successfully( $install_result ); - } - - public function download_wordpress_files() { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $runner = new Command_Runner( $cache_dir ); - $runner->run_wp_cli( "core download" ); - } - exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); - } - - public function full_install( $db_settings ) { - $this->download_wordpress_files(); - $this->create_config( $db_settings ); - $this->run_install(); - } - - private function assert_process_exited_successfully( $result ) { - if ( $result->return_code !== 0 ) { - $message = "return code was $result->return_code, output was: $result->output"; - throw new Exception( $message ); - } - } -} diff --git a/tests/test_core.php b/tests/test_core.php deleted file mode 100644 index ded886a6e..000000000 --- a/tests/test_core.php +++ /dev/null @@ -1,75 +0,0 @@ -<?php - -class CoreTest extends Wp_Cli_Test_Case { - - public function test_is_installed_exits_with_1_if_empty_dir() { - $temp_dir = $this->create_temporary_directory(); - $runner = new Command_Runner( $temp_dir ); - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_1_if_missing_wp_config() { - $temp_dir = $this->create_temporary_directory(); - - $runner = new Command_Runner( $temp_dir ); - - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_1_if_db_not_installed() { - $temp_dir = $this->create_temporary_directory(); - - $runner = new Command_Runner( $temp_dir ); - - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - $installer->create_config( $this->db_settings ); - - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 1, $result->return_code ); - } - - public function test_is_installed_exits_with_0_after_running_install_command() { - $runner = $this->full_wp_install(); - $result = $runner->run_wp_cli( "core is-installed" ); - $this->assertEquals( 0, $result->return_code ); - } - - public function test_install_command_creates_default_blog_post() { - $runner = $this->full_wp_install(); - $result = $runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } - - public function test_message_explains_that_config_must_be_present_before_install() { - $temp_dir = $this->create_temporary_directory(); - $runner = new Command_Runner( $temp_dir ); - $installer = new Wordpress_Installer( $temp_dir, $runner ); - $installer->download_wordpress_files( $temp_dir ); - $result = $runner->run_wp_cli( "core install" ); - $this->assertEquals( - "Error: wp-config.php not found.\n" . - "Either create one manually or use `wp core config`.\n", - $result->output - ); - } - - public function test_wp_config_can_be_placed_in_parent_directory() { - $temp_dir = $this->create_temporary_directory(); - $install_dir = $temp_dir . '/www-root'; - mkdir( $install_dir ); - $runner = new Command_Runner( $install_dir ); - $installer = new Wordpress_Installer( $install_dir, $runner ); - $installer->download_wordpress_files( $install_dir ); - $installer->create_config( $this->db_settings ); - rename( $install_dir . '/wp-config.php', $temp_dir . '/wp-config.php' ); - $installer->run_install(); - $result = $runner->run_wp_cli( "post list --ids" ); - $this->assertEquals( "1", $result->output ); - } -} From 653fe6bd5618ca3055bf8c82f9611a01d35a6154 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 21:01:24 +0200 Subject: [PATCH 1031/5359] move supporting code to a WP_CLI_Spec class --- tests/bootstrap.php | 2 + tests/class-wp-cli-spec.php | 81 +++++++++++++++++++++++++++++++++++++ tests/spec-core.php | 78 +---------------------------------- 3 files changed, 84 insertions(+), 77 deletions(-) create mode 100644 tests/class-wp-cli-spec.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c7ce8ec8c..bac8b968c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,7 @@ <?php +require_once __DIR__ . '/class-wp-cli-spec.php'; + class Command_Runner { private $cwd; diff --git a/tests/class-wp-cli-spec.php b/tests/class-wp-cli-spec.php new file mode 100644 index 000000000..76e8ab45a --- /dev/null +++ b/tests/class-wp-cli-spec.php @@ -0,0 +1,81 @@ +<?php + +abstract class WP_CLI_Spec extends PHPUnit_Extensions_Story_TestCase { + + protected static $db_settings = array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1' + ); + + private static function run_sql( $sql ) { + $dbuser = self::$db_settings['dbuser']; + $dbpass = self::$db_settings['dbpass']; + + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + } + + protected function setUp() { + $dbname = self::$db_settings['dbname']; + $this->run_sql( "DROP DATABASE $dbname" ); + $this->run_sql( "CREATE DATABASE $dbname" ); + } + + public function runGiven( &$world, $action, $arguments ) { + switch ( $action ) { + case 'empty dir': { + $world['temp_dir'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $world['temp_dir'] ); + } + break; + + case 'wp files': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->download_wordpress_files(); + } + break; + + case 'wp config': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->create_config( self::$db_settings ); + } + break; + + case 'wp install': { + $installer = new Wordpress_Installer( $world['temp_dir'] ); + $installer->full_install( self::$db_settings ); + } + break; + + default: { + return $this->notImplemented( $action ); + } + } + } + + public function runWhen( &$world, $action, $arguments ) { + $cmd = str_replace( 'invoking ', '', $action ); + + $runner = new Command_Runner( $world['temp_dir'] ); + $world['result'] = $runner->run_wp_cli( $cmd ); + } + + public function runThen( &$world, $action, $arguments ) { + switch ( $action ) { + case 'return code should be': { + $this->assertEquals( $arguments[0], $world['result']->return_code ); + } + break; + + case 'output should be': { + $this->assertEquals( $arguments[0], $world['result']->output ); + } + break; + + default: { + return $this->notImplemented( $action ); + } + } + } +} + diff --git a/tests/spec-core.php b/tests/spec-core.php index 593389e8b..250fb9bc2 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -1,6 +1,6 @@ <?php -class CoreCommandSpec extends PHPUnit_Extensions_Story_TestCase { +class CoreCommandSpec extends WP_CLI_Spec { /** * @scenario @@ -58,81 +58,5 @@ public function fullInstall() { ->when( 'invoking post list --ids' ) ->then( 'output should be', 1 ); } - - protected static $db_settings = array( - 'dbname' => 'wp_cli_test', - 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1' - ); - - private static function run_sql( $sql ) { - $dbuser = self::$db_settings['dbuser']; - $dbpass = self::$db_settings['dbpass']; - - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); - } - - protected function setUp() { - $dbname = self::$db_settings['dbname']; - $this->run_sql( "DROP DATABASE $dbname" ); - $this->run_sql( "CREATE DATABASE $dbname" ); - } - - public function runGiven( &$world, $action, $arguments ) { - switch ( $action ) { - case 'empty dir': { - $world['temp_dir'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $world['temp_dir'] ); - } - break; - - case 'wp files': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->download_wordpress_files(); - } - break; - - case 'wp config': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->create_config( self::$db_settings ); - } - break; - - case 'wp install': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->full_install( self::$db_settings ); - } - break; - - default: { - return $this->notImplemented( $action ); - } - } - } - - public function runWhen( &$world, $action, $arguments ) { - $cmd = str_replace( 'invoking ', '', $action ); - - $runner = new Command_Runner( $world['temp_dir'] ); - $world['result'] = $runner->run_wp_cli( $cmd ); - } - - public function runThen( &$world, $action, $arguments ) { - switch ( $action ) { - case 'return code should be': { - $this->assertEquals( $arguments[0], $world['result']->return_code ); - } - break; - - case 'output should be': { - $this->assertEquals( $arguments[0], $world['result']->output ); - } - break; - - default: { - return $this->notImplemented( $action ); - } - } - } } From cae01a899a86d5ea6d3e9e2d5b507306cd669332 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 21:06:11 +0200 Subject: [PATCH 1032/5359] dismantle full_install() method --- tests/bootstrap.php | 6 ------ tests/class-wp-cli-spec.php | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index bac8b968c..9a794706f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -68,12 +68,6 @@ public function download_wordpress_files() { exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } - public function full_install( $db_settings ) { - $this->download_wordpress_files(); - $this->create_config( $db_settings ); - $this->run_install(); - } - private function assert_process_exited_successfully( $result ) { if ( $result->return_code !== 0 ) { $message = "return code was $result->return_code, output was: $result->output"; diff --git a/tests/class-wp-cli-spec.php b/tests/class-wp-cli-spec.php index 76e8ab45a..56dcf170c 100644 --- a/tests/class-wp-cli-spec.php +++ b/tests/class-wp-cli-spec.php @@ -43,7 +43,9 @@ public function runGiven( &$world, $action, $arguments ) { case 'wp install': { $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->full_install( self::$db_settings ); + $installer->download_wordpress_files(); + $installer->create_config( self::$db_settings ); + $installer->run_install(); } break; From 7321cf63a7aa69643ee8d4eca684fd4aaec15d93 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 21:19:55 +0200 Subject: [PATCH 1033/5359] PHPUnit_Extensions_Story_ResultPrinter_Text is not that great --- phpunit.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 49615945a..917a7d50a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,6 @@ <phpunit bootstrap="tests/bootstrap.php" colors="true" - printerClass="PHPUnit_Extensions_Story_ResultPrinter_Text" > <testsuites> <testsuite> From 6960f7a3d01c116a48406576b3a262a56535e6b8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 21:28:57 +0200 Subject: [PATCH 1034/5359] set @scenarion annotation on a single line --- tests/spec-core.php | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/spec-core.php b/tests/spec-core.php index 250fb9bc2..5cfdb6d49 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -2,9 +2,7 @@ class CoreCommandSpec extends WP_CLI_Spec { - /** - * @scenario - */ + /** @scenario */ public function emptyDir() { $this ->given( 'empty dir' ) @@ -13,9 +11,7 @@ public function emptyDir() { ->then( 'return code should be', 1 ); } - /** - * @scenario - */ + /** @scenario */ public function noWpConfig() { $this ->given( 'empty dir' ) @@ -31,9 +27,7 @@ public function noWpConfig() { ); } - /** - * @scenario - */ + /** @scenario */ public function dbTablesNotInstalled() { $this ->given( 'empty dir' ) @@ -44,9 +38,7 @@ public function dbTablesNotInstalled() { ->then( 'return code should be', 1 ); } - /** - * @scenario - */ + /** @scenario */ public function fullInstall() { $this ->given( 'empty dir' ) From 2e50648b8cedbf25f12f7983c295252b2edd3ca1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 21:54:52 +0200 Subject: [PATCH 1035/5359] transform Command_Runner class into run_wp_cli() method --- tests/bootstrap.php | 49 +++++++++++++------------------------ tests/class-wp-cli-spec.php | 3 +-- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9a794706f..35f6b28a6 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,57 +2,43 @@ require_once __DIR__ . '/class-wp-cli-spec.php'; -class Command_Runner { - private $cwd; +function run_wp_cli( $command, $cwd ) { + $wp_cli_path = getcwd() . "/bin/wp"; - public function __construct( $cwd ) { - $this->cwd = $cwd; - } - - public function run_wp_cli( $wp_cli_command ) { - $wp_cli_path = self::find_wp_cli(); - return self::run_command( "$wp_cli_path $wp_cli_command" ); - } - - private function find_wp_cli() { - return getcwd() . "/bin/wp"; - } - - private function run_command( $command ) { - $cwd = $this->cwd; - $sh_command = "cd $cwd; $command 2>&1;"; + $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; - ob_start(); - system( $sh_command, $return_code ); - $output = ob_get_clean(); + ob_start(); + system( $sh_command, $return_code ); + $output = ob_get_clean(); - return (object) compact( 'return_code', 'output' ); - } + return (object) compact( 'return_code', 'output' ); } class Wordpress_Installer { private $install_dir; - private $runner; public function __construct( $install_dir ) { $this->install_dir = $install_dir; - $this->runner = new Command_Runner( $install_dir ); } public function create_config( $db_settings ) { $dbname = $db_settings["dbname"]; $dbuser = $db_settings["dbuser"]; $dbpass = $db_settings["dbpass"]; - $this->runner->run_wp_cli( - "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass" ); + + $cmd = "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass"; + + run_wp_cli( $cmd, $this->install_dir ); } public function run_install() { - $install_result = $this->runner->run_wp_cli( + $cmd = "core install --url=http://example.com/ --title=WordPress " . - " --admin_email=admin@example.com --admin_password=password1" - ); + " --admin_email=admin@example.com --admin_password=password1"; + + $install_result = run_wp_cli( $cmd, $this->install_dir ); + $this->assert_process_exited_successfully( $install_result ); } @@ -62,8 +48,7 @@ public function download_wordpress_files() { $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { mkdir( $cache_dir ); - $runner = new Command_Runner( $cache_dir ); - $runner->run_wp_cli( "core download" ); + run_wp_cli( "core download", $cache_dir ); } exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } diff --git a/tests/class-wp-cli-spec.php b/tests/class-wp-cli-spec.php index 56dcf170c..e12ba9277 100644 --- a/tests/class-wp-cli-spec.php +++ b/tests/class-wp-cli-spec.php @@ -58,8 +58,7 @@ public function runGiven( &$world, $action, $arguments ) { public function runWhen( &$world, $action, $arguments ) { $cmd = str_replace( 'invoking ', '', $action ); - $runner = new Command_Runner( $world['temp_dir'] ); - $world['result'] = $runner->run_wp_cli( $cmd ); + $world['result'] = run_wp_cli( $cmd, $world['temp_dir'] ); } public function runThen( &$world, $action, $arguments ) { From afe4348d121a16f6ddf309fea661cc6eeae3c595 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 22:04:38 +0200 Subject: [PATCH 1036/5359] WP_CLI::compose_args() -> Utils\compose_args() --- php/class-wp-cli.php | 19 ------------------- php/utils.php | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 426c8afff..232f6dc4b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -222,25 +222,6 @@ static function error_to_string( $errors ) { } } - /** - * Composes positional and associative arguments into a string. - * - * @param array - * @return string - */ - static function compose_args( $args, $assoc_args = array() ) { - $str = ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); - - foreach ( $assoc_args as $key => $value ) { - if ( true === $value ) - $str .= " --$key"; - else - $str .= " --$key=" . escapeshellarg( $value ); - } - - return $str; - } - /** * Launch an external process that takes over I/O. * diff --git a/php/utils.php b/php/utils.php index aac36c5b2..b0d8f0894 100644 --- a/php/utils.php +++ b/php/utils.php @@ -89,6 +89,26 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args ); } +/** + * Composes positional and associative arguments into a string. + * + * @param array Positional args + * @param array Associative args + * @return string + */ +function compose_args( $args, $assoc_args = array() ) { + $str = ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); + + foreach ( $assoc_args as $key => $value ) { + if ( true === $value ) + $str .= " --$key"; + else + $str .= " --$key=" . escapeshellarg( $value ); + } + + return $str; +} + function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; From d88192f8b4eeda2911a2c5fcb7f483339d488b75 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 22:16:23 +0200 Subject: [PATCH 1037/5359] break out compose_assoc_args() utility and use in test runner --- php/utils.php | 19 ++++++++++++++----- tests/bootstrap.php | 18 ++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/php/utils.php b/php/utils.php index b0d8f0894..0ade39ee7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -90,14 +90,23 @@ function parse_args( $arguments ) { } /** - * Composes positional and associative arguments into a string. + * Composes positional arguments into a command string. * - * @param array Positional args - * @param array Associative args + * @param array * @return string */ -function compose_args( $args, $assoc_args = array() ) { - $str = ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); +function compose_args( $args ) { + return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); +} + +/** + * Composes associative arguments into a command string. + * + * @param array + * @return string + */ +function compose_assoc_args( $assoc_args ) { + $str = ''; foreach ( $assoc_args as $key => $value ) { if ( true === $value ) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 35f6b28a6..c9393cd59 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,7 @@ <?php +require_once getcwd() . '/php/utils.php'; + require_once __DIR__ . '/class-wp-cli-spec.php'; function run_wp_cli( $command, $cwd ) { @@ -23,19 +25,18 @@ public function __construct( $install_dir ) { } public function create_config( $db_settings ) { - $dbname = $db_settings["dbname"]; - $dbuser = $db_settings["dbuser"]; - $dbpass = $db_settings["dbpass"]; - - $cmd = "core config --dbname=$dbname --dbuser=$dbuser --dbpass=$dbpass"; + $cmd = 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ); run_wp_cli( $cmd, $this->install_dir ); } public function run_install() { - $cmd = - "core install --url=http://example.com/ --title=WordPress " . - " --admin_email=admin@example.com --admin_password=password1"; + $cmd = 'core install' . \WP_CLI\Utils\compose_assoc_args( array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Tests', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ) ); $install_result = run_wp_cli( $cmd, $this->install_dir ); @@ -50,6 +51,7 @@ public function download_wordpress_files() { mkdir( $cache_dir ); run_wp_cli( "core download", $cache_dir ); } + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } From d222caa169ed9a80c7169d1dcb95830d4656ab5f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 22:50:28 +0200 Subject: [PATCH 1038/5359] Wordpress_Installer + run_wp_cli() = WP_CLI_Command_Runner --- tests/bootstrap.php | 36 +++++++++++++++++++----------------- tests/class-wp-cli-spec.php | 18 +++++++----------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c9393cd59..936875e7b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -4,30 +4,32 @@ require_once __DIR__ . '/class-wp-cli-spec.php'; -function run_wp_cli( $command, $cwd ) { - $wp_cli_path = getcwd() . "/bin/wp"; +class WP_CLI_Command_Runner { - $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; + private $install_dir; - ob_start(); - system( $sh_command, $return_code ); - $output = ob_get_clean(); + public function __construct() { + $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $this->install_dir ); + } - return (object) compact( 'return_code', 'output' ); -} + public function run( $command, $cwd = false ) { + if ( !$cwd ) + $cwd = $this->install_dir; -class Wordpress_Installer { + $wp_cli_path = getcwd() . "/bin/wp"; - private $install_dir; + $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; + + ob_start(); + system( $sh_command, $return_code ); + $output = ob_get_clean(); - public function __construct( $install_dir ) { - $this->install_dir = $install_dir; + return (object) compact( 'return_code', 'output' ); } public function create_config( $db_settings ) { - $cmd = 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ); - - run_wp_cli( $cmd, $this->install_dir ); + $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); } public function run_install() { @@ -38,7 +40,7 @@ public function run_install() { 'admin_password' => 'password1' ) ); - $install_result = run_wp_cli( $cmd, $this->install_dir ); + $install_result = $this->run( $cmd ); $this->assert_process_exited_successfully( $install_result ); } @@ -49,7 +51,7 @@ public function download_wordpress_files() { $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { mkdir( $cache_dir ); - run_wp_cli( "core download", $cache_dir ); + $this->run( "core download", $cache_dir ); } exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); diff --git a/tests/class-wp-cli-spec.php b/tests/class-wp-cli-spec.php index e12ba9277..de7e79839 100644 --- a/tests/class-wp-cli-spec.php +++ b/tests/class-wp-cli-spec.php @@ -24,28 +24,24 @@ protected function setUp() { public function runGiven( &$world, $action, $arguments ) { switch ( $action ) { case 'empty dir': { - $world['temp_dir'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $world['temp_dir'] ); + $world['runner'] = new WP_CLI_Command_Runner; } break; case 'wp files': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->download_wordpress_files(); + $world['runner']->download_wordpress_files(); } break; case 'wp config': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->create_config( self::$db_settings ); + $world['runner']->create_config( self::$db_settings ); } break; case 'wp install': { - $installer = new Wordpress_Installer( $world['temp_dir'] ); - $installer->download_wordpress_files(); - $installer->create_config( self::$db_settings ); - $installer->run_install(); + $world['runner']->download_wordpress_files(); + $world['runner']->create_config( self::$db_settings ); + $world['runner']->run_install(); } break; @@ -58,7 +54,7 @@ public function runGiven( &$world, $action, $arguments ) { public function runWhen( &$world, $action, $arguments ) { $cmd = str_replace( 'invoking ', '', $action ); - $world['result'] = run_wp_cli( $cmd, $world['temp_dir'] ); + $world['result'] = $world['runner']->run( $cmd ); } public function runThen( &$world, $action, $arguments ) { From da73c0167a886022d679d285497fd3a4101fb058 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 23:03:14 +0200 Subject: [PATCH 1039/5359] explicitly test creating config file and running install --- tests/bootstrap.php | 13 ++----------- tests/class-wp-cli-spec.php | 18 ++++++++++++++++-- tests/spec-core.php | 18 ++++++++++++------ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 936875e7b..8a095f88c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -29,7 +29,7 @@ public function run( $command, $cwd = false ) { } public function create_config( $db_settings ) { - $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); + return $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); } public function run_install() { @@ -40,9 +40,7 @@ public function run_install() { 'admin_password' => 'password1' ) ); - $install_result = $this->run( $cmd ); - - $this->assert_process_exited_successfully( $install_result ); + return $this->run( $cmd ); } public function download_wordpress_files() { @@ -56,11 +54,4 @@ public function download_wordpress_files() { exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); } - - private function assert_process_exited_successfully( $result ) { - if ( $result->return_code !== 0 ) { - $message = "return code was $result->return_code, output was: $result->output"; - throw new Exception( $message ); - } - } } diff --git a/tests/class-wp-cli-spec.php b/tests/class-wp-cli-spec.php index de7e79839..6c4c6ca95 100644 --- a/tests/class-wp-cli-spec.php +++ b/tests/class-wp-cli-spec.php @@ -52,9 +52,23 @@ public function runGiven( &$world, $action, $arguments ) { } public function runWhen( &$world, $action, $arguments ) { - $cmd = str_replace( 'invoking ', '', $action ); + switch ( $action ) { + case 'invoking core install': { + $world['result'] = $world['runner']->run_install(); + } + break; + + case 'invoking core config': { + $world['result'] = $world['runner']->create_config( self::$db_settings ); + } + break; + + default: { + $cmd = str_replace( 'invoking ', '', $action ); - $world['result'] = $world['runner']->run( $cmd ); + $world['result'] = $world['runner']->run( $cmd ); + } + } } public function runThen( &$world, $action, $arguments ) { diff --git a/tests/spec-core.php b/tests/spec-core.php index 5cfdb6d49..199361300 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -24,7 +24,10 @@ public function noWpConfig() { ->then( 'output should be', "Error: wp-config.php not found.\n" . "Either create one manually or use `wp core config`.\n" - ); + ) + + ->when( 'invoking core config' ) + ->then( 'return code should be', 0 ); } /** @scenario */ @@ -35,7 +38,13 @@ public function dbTablesNotInstalled() { ->and( 'wp config' ) ->when( 'invoking core is-installed' ) - ->then( 'return code should be', 1 ); + ->then( 'return code should be', 1 ) + + ->when( 'invoking core install' ) + ->then( 'return code should be', 0 ) + + ->when( 'invoking post list --ids' ) + ->then( 'output should be', 1 ); } /** @scenario */ @@ -45,10 +54,7 @@ public function fullInstall() { ->and( 'wp install' ) ->when( 'invoking core is-installed' ) - ->then( 'return code should be', 0 ) - - ->when( 'invoking post list --ids' ) - ->then( 'output should be', 1 ); + ->then( 'return code should be', 0 ); } } From e40e5f4a5c586559efc9df701c61d3ecff437b7d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 29 Dec 2012 23:06:12 +0200 Subject: [PATCH 1040/5359] move WP_CLI_Command_Runner class out of bootstrap.php --- ...lass-wp-cli-spec.php => abstract-spec.php} | 0 tests/bootstrap.php | 54 +------------------ tests/command-runner.php | 53 ++++++++++++++++++ 3 files changed, 55 insertions(+), 52 deletions(-) rename tests/{class-wp-cli-spec.php => abstract-spec.php} (100%) create mode 100644 tests/command-runner.php diff --git a/tests/class-wp-cli-spec.php b/tests/abstract-spec.php similarity index 100% rename from tests/class-wp-cli-spec.php rename to tests/abstract-spec.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8a095f88c..4e82b7fa5 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,56 +2,6 @@ require_once getcwd() . '/php/utils.php'; -require_once __DIR__ . '/class-wp-cli-spec.php'; +require_once __DIR__ . '/abstract-spec.php'; +require_once __DIR__ . '/command-runner.php'; -class WP_CLI_Command_Runner { - - private $install_dir; - - public function __construct() { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $this->install_dir ); - } - - public function run( $command, $cwd = false ) { - if ( !$cwd ) - $cwd = $this->install_dir; - - $wp_cli_path = getcwd() . "/bin/wp"; - - $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; - - ob_start(); - system( $sh_command, $return_code ); - $output = ob_get_clean(); - - return (object) compact( 'return_code', 'output' ); - } - - public function create_config( $db_settings ) { - return $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); - } - - public function run_install() { - $cmd = 'core install' . \WP_CLI\Utils\compose_assoc_args( array( - 'url' => 'http://example.com', - 'title' => 'WP CLI Tests', - 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' - ) ); - - return $this->run( $cmd ); - } - - public function download_wordpress_files() { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $this->run( "core download", $cache_dir ); - } - - exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); - } -} diff --git a/tests/command-runner.php b/tests/command-runner.php new file mode 100644 index 000000000..d232c9111 --- /dev/null +++ b/tests/command-runner.php @@ -0,0 +1,53 @@ +<?php + +class WP_CLI_Command_Runner { + + private $install_dir; + + public function __construct() { + $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $this->install_dir ); + } + + public function run( $command, $cwd = false ) { + if ( !$cwd ) + $cwd = $this->install_dir; + + $wp_cli_path = getcwd() . "/bin/wp"; + + $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; + + ob_start(); + system( $sh_command, $return_code ); + $output = ob_get_clean(); + + return (object) compact( 'return_code', 'output' ); + } + + public function create_config( $db_settings ) { + return $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); + } + + public function run_install() { + $cmd = 'core install' . \WP_CLI\Utils\compose_assoc_args( array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Tests', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ) ); + + return $this->run( $cmd ); + } + + public function download_wordpress_files() { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir( $cache_dir ); + $this->run( "core download", $cache_dir ); + } + + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); + } +} From f85b7693c0ae8b39a73089604a7856f08016ef7f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 10:09:45 +0200 Subject: [PATCH 1041/5359] add test for when db tables aren't installed --- tests/abstract-spec.php | 5 +++++ tests/spec-core.php | 3 +++ 2 files changed, 8 insertions(+) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 6c4c6ca95..746a647be 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -83,6 +83,11 @@ public function runThen( &$world, $action, $arguments ) { } break; + case 'should have output': { + $this->assertNotEmpty( $world['result']->output ); + } + break; + default: { return $this->notImplemented( $action ); } diff --git a/tests/spec-core.php b/tests/spec-core.php index 199361300..dbbcfbf68 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -40,6 +40,9 @@ public function dbTablesNotInstalled() { ->when( 'invoking core is-installed' ) ->then( 'return code should be', 1 ) + ->when( 'invoking help' ) + ->then( 'should have output' ) + ->when( 'invoking core install' ) ->then( 'return code should be', 0 ) From 15f1eb937686a4e12770418e87959f74076bc54f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 10:15:05 +0200 Subject: [PATCH 1042/5359] pass action as message for assertions --- tests/abstract-spec.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 746a647be..8b8323569 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -74,17 +74,17 @@ public function runWhen( &$world, $action, $arguments ) { public function runThen( &$world, $action, $arguments ) { switch ( $action ) { case 'return code should be': { - $this->assertEquals( $arguments[0], $world['result']->return_code ); + $this->assertEquals( $arguments[0], $world['result']->return_code, $action ); } break; case 'output should be': { - $this->assertEquals( $arguments[0], $world['result']->output ); + $this->assertEquals( $arguments[0], $world['result']->output, $action ); } break; case 'should have output': { - $this->assertNotEmpty( $world['result']->output ); + $this->assertNotEmpty( $world['result']->output, $action ); } break; From c8ea8cad0ed32cf9c298958de98ecd024be92b11 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 11:12:37 +0200 Subject: [PATCH 1043/5359] Tame wp-config.php Frustratingly, wp-config.php insists on defining ABSPATH and on require()ing wp-settings.php. So, we comb through each line of code from wp-config.php, skipping what we don't like, and then we explicitly eval() the result. Afterwards, we're free to require() our own version of wp-settings.php etc. --- php/class-wp-cli.php | 2 +- php/utils.php | 29 +++++++++++++++++++++-------- php/wp-cli.php | 6 +++++- php/wp-settings.php | 4 ---- 4 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 php/wp-settings.php diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 232f6dc4b..1e5e023e5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -340,7 +340,7 @@ static function before_wp_load() { } if ( self::cmd_starts_with( array( 'db' ) ) ) { - Utils\load_wp_config(); + eval( Utils\get_wp_config_code() ); self::run_command(); exit; } diff --git a/php/utils.php b/php/utils.php index 0ade39ee7..70079b0cf 100644 --- a/php/utils.php +++ b/php/utils.php @@ -196,14 +196,27 @@ function locate_wp_config() { return false; } -// Loads wp-config.php without loading the rest of WP -function load_wp_config() { - define( 'ABSPATH', dirname(__FILE__) . '/' ); - - if ( $wp_config_path = locate_wp_config() ) - require locate_wp_config(); - else - \WP_CLI::error( 'No wp-config.php file.' ); +/** + * Returns wp-config.php code, skipping the loading of wp-settings.php + * + * @return string + */ +function get_wp_config_code() { + $wp_config_code = file_get_contents( locate_wp_config() ); + + $lines_to_run = array(); + + foreach ( explode( "\n", $wp_config_code ) as $line ) { + if ( 0 === strpos( $line, '<?php' ) ) + continue; + + if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) + continue; + + $lines_to_run[] = $line; + } + + return implode( "\n", $lines_to_run ); } /** diff --git a/php/wp-cli.php b/php/wp-cli.php index a248bdb28..0528fc67e 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -18,7 +18,11 @@ WP_CLI::before_wp_load(); // Load WordPress, in the global scope -require WP_ROOT . 'wp-load.php'; +define( 'ABSPATH', WP_ROOT ); + +eval( \WP_CLI\Utils\get_wp_config_code() ); + +require ABSPATH . 'wp-settings.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); diff --git a/php/wp-settings.php b/php/wp-settings.php deleted file mode 100644 index 648622d87..000000000 --- a/php/wp-settings.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php - -// This is a dummy file necessary for loading wp-config.php without going through wp-load.php - From ec6eaa1467612381c70b76b60abb228866f2b735 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 12:18:35 +0200 Subject: [PATCH 1044/5359] copy wp-settings.php from WP 3.5 --- php/wp-cli.php | 2 +- php/wp-settings-cli.php | 327 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 php/wp-settings-cli.php diff --git a/php/wp-cli.php b/php/wp-cli.php index 0528fc67e..57df1df42 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -22,7 +22,7 @@ eval( \WP_CLI\Utils\get_wp_config_code() ); -require ABSPATH . 'wp-settings.php'; +require WP_CLI_ROOT . 'wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php new file mode 100644 index 000000000..65485a841 --- /dev/null +++ b/php/wp-settings-cli.php @@ -0,0 +1,327 @@ +<?php +/** + * Used to set up and fix common variables and include + * the WordPress procedural and class library. + * + * Allows for some configuration in wp-config.php (see default-constants.php) + * + * @internal This file must be parsable by PHP4. + * + * @package WordPress + */ + +/** + * Stores the location of the WordPress directory of functions, classes, and core content. + * + * @since 1.0.0 + */ +define( 'WPINC', 'wp-includes' ); + +// Include files required for initialization. +require( ABSPATH . WPINC . '/load.php' ); +require( ABSPATH . WPINC . '/default-constants.php' ); +require( ABSPATH . WPINC . '/version.php' ); + +// Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE. +wp_initial_constants( ); + +// Check for the required PHP version and for the MySQL extension or a database drop-in. +wp_check_php_mysql_versions(); + +// Disable magic quotes at runtime. Magic quotes are added using wpdb later in wp-settings.php. +@ini_set( 'magic_quotes_runtime', 0 ); +@ini_set( 'magic_quotes_sybase', 0 ); + +// WordPress calculates offsets from UTC. +date_default_timezone_set( 'UTC' ); + +// Turn register_globals off. +wp_unregister_GLOBALS(); + +// Standardize $_SERVER variables across setups. +wp_fix_server_vars(); + +// Check if we have received a request due to missing favicon.ico +wp_favicon_request(); + +// Check if we're in maintenance mode. +wp_maintenance(); + +// Start loading timer. +timer_start(); + +// Check if we're in WP_DEBUG mode. +wp_debug_mode(); + +// For an advanced caching plugin to use. Uses a static drop-in because you would only want one. +if ( WP_CACHE ) + WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); + +// Define WP_LANG_DIR if not set. +wp_set_lang_dir(); + +// Load early WordPress files. +require( ABSPATH . WPINC . '/compat.php' ); +require( ABSPATH . WPINC . '/functions.php' ); +require( ABSPATH . WPINC . '/class-wp.php' ); +require( ABSPATH . WPINC . '/class-wp-error.php' ); +require( ABSPATH . WPINC . '/plugin.php' ); +require( ABSPATH . WPINC . '/pomo/mo.php' ); + +// Include the wpdb class and, if present, a db.php database drop-in. +require_wp_db(); + +// Set the database table prefix and the format specifiers for database table columns. +$GLOBALS['table_prefix'] = $table_prefix; +wp_set_wpdb_vars(); + +// Start the WordPress object cache, or an external object cache if the drop-in is present. +wp_start_object_cache(); + +// Attach the default filters. +require( ABSPATH . WPINC . '/default-filters.php' ); + +// Initialize multisite if enabled. +if ( is_multisite() ) { + require( ABSPATH . WPINC . '/ms-blogs.php' ); + require( ABSPATH . WPINC . '/ms-settings.php' ); +} elseif ( ! defined( 'MULTISITE' ) ) { + define( 'MULTISITE', false ); +} + +register_shutdown_function( 'shutdown_action_hook' ); + +// Stop most of WordPress from being loaded if we just want the basics. +if ( SHORTINIT ) + return false; + +// Load the L10n library. +require_once( ABSPATH . WPINC . '/l10n.php' ); + +// Run the installer if WordPress is not installed. +wp_not_installed(); + +// Load most of WordPress. +require( ABSPATH . WPINC . '/class-wp-walker.php' ); +require( ABSPATH . WPINC . '/class-wp-ajax-response.php' ); +require( ABSPATH . WPINC . '/formatting.php' ); +require( ABSPATH . WPINC . '/capabilities.php' ); +require( ABSPATH . WPINC . '/query.php' ); +require( ABSPATH . WPINC . '/theme.php' ); +require( ABSPATH . WPINC . '/class-wp-theme.php' ); +require( ABSPATH . WPINC . '/template.php' ); +require( ABSPATH . WPINC . '/user.php' ); +require( ABSPATH . WPINC . '/meta.php' ); +require( ABSPATH . WPINC . '/general-template.php' ); +require( ABSPATH . WPINC . '/link-template.php' ); +require( ABSPATH . WPINC . '/author-template.php' ); +require( ABSPATH . WPINC . '/post.php' ); +require( ABSPATH . WPINC . '/post-template.php' ); +require( ABSPATH . WPINC . '/post-thumbnail-template.php' ); +require( ABSPATH . WPINC . '/category.php' ); +require( ABSPATH . WPINC . '/category-template.php' ); +require( ABSPATH . WPINC . '/comment.php' ); +require( ABSPATH . WPINC . '/comment-template.php' ); +require( ABSPATH . WPINC . '/rewrite.php' ); +require( ABSPATH . WPINC . '/feed.php' ); +require( ABSPATH . WPINC . '/bookmark.php' ); +require( ABSPATH . WPINC . '/bookmark-template.php' ); +require( ABSPATH . WPINC . '/kses.php' ); +require( ABSPATH . WPINC . '/cron.php' ); +require( ABSPATH . WPINC . '/deprecated.php' ); +require( ABSPATH . WPINC . '/script-loader.php' ); +require( ABSPATH . WPINC . '/taxonomy.php' ); +require( ABSPATH . WPINC . '/update.php' ); +require( ABSPATH . WPINC . '/canonical.php' ); +require( ABSPATH . WPINC . '/shortcodes.php' ); +require( ABSPATH . WPINC . '/class-wp-embed.php' ); +require( ABSPATH . WPINC . '/media.php' ); +require( ABSPATH . WPINC . '/http.php' ); +require( ABSPATH . WPINC . '/class-http.php' ); +require( ABSPATH . WPINC . '/widgets.php' ); +require( ABSPATH . WPINC . '/nav-menu.php' ); +require( ABSPATH . WPINC . '/nav-menu-template.php' ); +require( ABSPATH . WPINC . '/admin-bar.php' ); + +// Load multisite-specific files. +if ( is_multisite() ) { + require( ABSPATH . WPINC . '/ms-functions.php' ); + require( ABSPATH . WPINC . '/ms-default-filters.php' ); + require( ABSPATH . WPINC . '/ms-deprecated.php' ); +} + +// Define constants that rely on the API to obtain the default value. +// Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. +wp_plugin_directory_constants( ); + +// Load must-use plugins. +foreach ( wp_get_mu_plugins() as $mu_plugin ) { + include_once( $mu_plugin ); +} +unset( $mu_plugin ); + +// Load network activated plugins. +if ( is_multisite() ) { + foreach( wp_get_active_network_plugins() as $network_plugin ) { + include_once( $network_plugin ); + } + unset( $network_plugin ); +} + +do_action( 'muplugins_loaded' ); + +if ( is_multisite() ) + ms_cookie_constants( ); + +// Define constants after multisite is loaded. Cookie-related constants may be overridden in ms_network_cookies(). +wp_cookie_constants( ); + +// Define and enforce our SSL constants +wp_ssl_constants( ); + +// Create common globals. +require( ABSPATH . WPINC . '/vars.php' ); + +// Make taxonomies and posts available to plugins and themes. +// @plugin authors: warning: these get registered again on the init hook. +create_initial_taxonomies(); +create_initial_post_types(); + +// Register the default theme directory root +register_theme_directory( get_theme_root() ); + +// Load active plugins. +foreach ( wp_get_active_and_valid_plugins() as $plugin ) + include_once( $plugin ); +unset( $plugin ); + +// Load pluggable functions. +require( ABSPATH . WPINC . '/pluggable.php' ); +require( ABSPATH . WPINC . '/pluggable-deprecated.php' ); + +// Set internal encoding. +wp_set_internal_encoding(); + +// Run wp_cache_postload() if object cache is enabled and the function exists. +if ( WP_CACHE && function_exists( 'wp_cache_postload' ) ) + wp_cache_postload(); + +do_action( 'plugins_loaded' ); + +// Define constants which affect functionality if not already defined. +wp_functionality_constants( ); + +// Add magic quotes and set up $_REQUEST ( $_GET + $_POST ) +wp_magic_quotes(); + +do_action( 'sanitize_comment_cookies' ); + +/** + * WordPress Query object + * @global object $wp_the_query + * @since 2.0.0 + */ +$wp_the_query = new WP_Query(); + +/** + * Holds the reference to @see $wp_the_query + * Use this global for WordPress queries + * @global object $wp_query + * @since 1.5.0 + */ +$wp_query = $wp_the_query; + +/** + * Holds the WordPress Rewrite object for creating pretty URLs + * @global object $wp_rewrite + * @since 1.5.0 + */ +$GLOBALS['wp_rewrite'] = new WP_Rewrite(); + +/** + * WordPress Object + * @global object $wp + * @since 2.0.0 + */ +$wp = new WP(); + +/** + * WordPress Widget Factory Object + * @global object $wp_widget_factory + * @since 2.8.0 + */ +$GLOBALS['wp_widget_factory'] = new WP_Widget_Factory(); + +/** + * WordPress User Roles + * @global object $wp_roles + * @since 2.0.0 + */ +$GLOBALS['wp_roles'] = new WP_Roles(); + +do_action( 'setup_theme' ); + +// Define the template related constants. +wp_templating_constants( ); + +// Load the default text localization domain. +load_default_textdomain(); + +$locale = get_locale(); +$locale_file = WP_LANG_DIR . "/$locale.php"; +if ( ( 0 === validate_file( $locale ) ) && is_readable( $locale_file ) ) + require( $locale_file ); +unset( $locale_file ); + +// Pull in locale data after loading text domain. +require_once( ABSPATH . WPINC . '/locale.php' ); + +/** + * WordPress Locale object for loading locale domain date and various strings. + * @global object $wp_locale + * @since 2.1.0 + */ +$GLOBALS['wp_locale'] = new WP_Locale(); + +// Load the functions for the active theme, for both parent and child theme if applicable. +if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { + if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) + include( STYLESHEETPATH . '/functions.php' ); + if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) + include( TEMPLATEPATH . '/functions.php' ); +} + +do_action( 'after_setup_theme' ); + +// Set up current user. +$wp->init(); + +/** + * Most of WP is loaded at this stage, and the user is authenticated. WP continues + * to load on the init hook that follows (e.g. widgets), and many plugins instantiate + * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.). + * + * If you wish to plug an action once WP is loaded, use the wp_loaded hook below. + */ +do_action( 'init' ); + +// Check site status +if ( is_multisite() ) { + if ( true !== ( $file = ms_site_check() ) ) { + require( $file ); + die(); + } + unset($file); +} + +/** + * This hook is fired once WP, all plugins, and the theme are fully loaded and instantiated. + * + * AJAX requests should use wp-admin/admin-ajax.php. admin-ajax.php can handle requests for + * users not logged in. + * + * @link http://codex.wordpress.org/AJAX_in_Plugins + * + * @since 3.0.0 + */ +do_action('wp_loaded'); From cb89a50a33306e5173b320e8f0f34491ea0138c3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 12:20:46 +0200 Subject: [PATCH 1045/5359] change header for wp-settings-cli.php --- php/wp-settings-cli.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 65485a841..11ef5bb32 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -1,13 +1,6 @@ <?php /** - * Used to set up and fix common variables and include - * the WordPress procedural and class library. - * - * Allows for some configuration in wp-config.php (see default-constants.php) - * - * @internal This file must be parsable by PHP4. - * - * @package WordPress + * A modified version of wp-settings.php, tailored for CLI use. */ /** @@ -23,7 +16,7 @@ require( ABSPATH . WPINC . '/version.php' ); // Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE. -wp_initial_constants( ); +wp_initial_constants(); // Check for the required PHP version and for the MySQL extension or a database drop-in. wp_check_php_mysql_versions(); From 2d5ccb249f10d6da642a248d790accb64cae46ea Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 12:34:41 +0200 Subject: [PATCH 1046/5359] remove irrelevant checks: wp_favicon_request() and wp_maintenance() --- php/wp-settings-cli.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 11ef5bb32..aa051802c 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -34,12 +34,6 @@ // Standardize $_SERVER variables across setups. wp_fix_server_vars(); -// Check if we have received a request due to missing favicon.ico -wp_favicon_request(); - -// Check if we're in maintenance mode. -wp_maintenance(); - // Start loading timer. timer_start(); From 8f3b6601377f4e7230a1275833ada39bfa182c50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 12:41:25 +0200 Subject: [PATCH 1047/5359] never load advanced-cache.php. see #164 --- php/class-wp-cli.php | 2 +- php/wp-settings-cli.php | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1e5e023e5..b6b5e2d2d 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -356,7 +356,7 @@ static function before_wp_load() { } } - // Pretend we're in WP_ADMIN, to side-step full-page caching plugins + // Pretend we're in WP_ADMIN define( 'WP_ADMIN', true ); $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index aa051802c..aa079547e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -40,10 +40,6 @@ // Check if we're in WP_DEBUG mode. wp_debug_mode(); -// For an advanced caching plugin to use. Uses a static drop-in because you would only want one. -if ( WP_CACHE ) - WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); - // Define WP_LANG_DIR if not set. wp_set_lang_dir(); From 29cd328ca7b9be7f716e573f2525c4f53060c84a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 13:06:02 +0200 Subject: [PATCH 1048/5359] use our own version of wp_not_installed(). see #93 --- php/class-wp-cli.php | 2 -- php/utils-wp.php | 8 ++++++++ php/wp-settings-cli.php | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b6b5e2d2d..0c17283ac 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -366,8 +366,6 @@ private static function cmd_starts_with( $prefix ) { } static function after_wp_load() { - require WP_CLI_ROOT . 'utils-wp.php'; - add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); Utils\set_user( self::$config ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 3eafb3035..0dd4bf62a 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -4,6 +4,14 @@ namespace WP_CLI\Utils; +function wp_not_installed() { + if ( !is_blog_installed() && !defined( 'WP_INSTALLING' ) ) { + \WP_CLI::error( 'The site you have requested is not installed.', false ); + \WP_CLI::line( 'Run `wp core install`.' ); + exit( 1 ); + } +} + // Handle --user parameter function set_user( $assoc_args ) { if ( !isset( $assoc_args['user'] ) ) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index aa079547e..a001e293c 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -78,11 +78,14 @@ if ( SHORTINIT ) return false; +// Load WP-CLI utilities +require WP_CLI_ROOT . 'utils-wp.php'; + // Load the L10n library. require_once( ABSPATH . WPINC . '/l10n.php' ); // Run the installer if WordPress is not installed. -wp_not_installed(); +\WP_CLI\Utils\wp_not_installed(); // Load most of WordPress. require( ABSPATH . WPINC . '/class-wp-walker.php' ); From ec9198202d0f5dc6700ee3e8339f1a2b9fe4595d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 13:13:50 +0200 Subject: [PATCH 1049/5359] make wp-settings-cli.php compatible with WP 3.4 --- php/utils.php | 5 +++++ php/wp-settings-cli.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 70079b0cf..4ebaec288 100644 --- a/php/utils.php +++ b/php/utils.php @@ -219,6 +219,11 @@ function get_wp_config_code() { return implode( "\n", $lines_to_run ); } +function maybe_require( $path ) { + if ( file_exists( $path ) ) + require $path; +} + /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index a001e293c..4e8fe3e3a 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -120,7 +120,7 @@ require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); -require( ABSPATH . WPINC . '/class-wp-embed.php' ); +\WP_CLI\Utils\maybe_require( ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); require( ABSPATH . WPINC . '/class-http.php' ); From 74215cb623b76ff76328266d01cbeca6d80d0576 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 13:14:48 +0200 Subject: [PATCH 1050/5359] add use \WP_CLI\Utils to wp-settings-cli.php --- php/wp-settings-cli.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 4e8fe3e3a..3b074bab0 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -3,6 +3,8 @@ * A modified version of wp-settings.php, tailored for CLI use. */ +use \WP_CLI\Utils; + /** * Stores the location of the WordPress directory of functions, classes, and core content. * @@ -85,7 +87,7 @@ require_once( ABSPATH . WPINC . '/l10n.php' ); // Run the installer if WordPress is not installed. -\WP_CLI\Utils\wp_not_installed(); +Utils\wp_not_installed(); // Load most of WordPress. require( ABSPATH . WPINC . '/class-wp-walker.php' ); @@ -120,7 +122,7 @@ require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); -\WP_CLI\Utils\maybe_require( ABSPATH . WPINC . '/class-wp-embed.php' ); +Utils\maybe_require( ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); require( ABSPATH . WPINC . '/class-http.php' ); From fa92f5f8a29db3de3a81af433825fa40e841708b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 13:22:27 +0200 Subject: [PATCH 1051/5359] make wp-settings-cli.php compatible with WP 3.3 --- php/wp-settings-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 3b074bab0..2dc0f0711 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -96,8 +96,8 @@ require( ABSPATH . WPINC . '/capabilities.php' ); require( ABSPATH . WPINC . '/query.php' ); require( ABSPATH . WPINC . '/theme.php' ); -require( ABSPATH . WPINC . '/class-wp-theme.php' ); -require( ABSPATH . WPINC . '/template.php' ); +Utils\maybe_require( ABSPATH . WPINC . '/class-wp-theme.php' ); +Utils\maybe_require( ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); require( ABSPATH . WPINC . '/meta.php' ); require( ABSPATH . WPINC . '/general-template.php' ); From 6ba6689a548f0f411143ccde0a59713fc5b72021 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 13:25:33 +0200 Subject: [PATCH 1052/5359] pass WP version to maybe_require() --- php/utils-wp.php | 7 +++++++ php/utils.php | 5 ----- php/wp-settings-cli.php | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index 0dd4bf62a..01777c211 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -12,6 +12,13 @@ function wp_not_installed() { } } +function maybe_require( $since, $path ) { + global $wp_version; + + if ( version_compare( $wp_version, $since, '>=' ) ) + require $path; +} + // Handle --user parameter function set_user( $assoc_args ) { if ( !isset( $assoc_args['user'] ) ) diff --git a/php/utils.php b/php/utils.php index 4ebaec288..70079b0cf 100644 --- a/php/utils.php +++ b/php/utils.php @@ -219,11 +219,6 @@ function get_wp_config_code() { return implode( "\n", $lines_to_run ); } -function maybe_require( $path ) { - if ( file_exists( $path ) ) - require $path; -} - /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 2dc0f0711..30769553d 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -96,8 +96,8 @@ require( ABSPATH . WPINC . '/capabilities.php' ); require( ABSPATH . WPINC . '/query.php' ); require( ABSPATH . WPINC . '/theme.php' ); -Utils\maybe_require( ABSPATH . WPINC . '/class-wp-theme.php' ); -Utils\maybe_require( ABSPATH . WPINC . '/template.php' ); +Utils\maybe_require( '3.4', ABSPATH . WPINC . '/class-wp-theme.php' ); +Utils\maybe_require( '3.4', ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); require( ABSPATH . WPINC . '/meta.php' ); require( ABSPATH . WPINC . '/general-template.php' ); @@ -122,7 +122,7 @@ require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); -Utils\maybe_require( ABSPATH . WPINC . '/class-wp-embed.php' ); +Utils\maybe_require( '3.5', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); require( ABSPATH . WPINC . '/class-http.php' ); From 136d4911b1ebae5047499cdee6880c6eb60281af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 14:20:58 +0200 Subject: [PATCH 1053/5359] tests: pass wp-cli command as a parameter --- tests/abstract-spec.php | 29 +++++++++++++++++++---------- tests/spec-core.php | 18 +++++++++--------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 8b8323569..11effab3c 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -53,20 +53,29 @@ public function runGiven( &$world, $action, $arguments ) { public function runWhen( &$world, $action, $arguments ) { switch ( $action ) { - case 'invoking core install': { - $world['result'] = $world['runner']->run_install(); - } - break; - - case 'invoking core config': { - $world['result'] = $world['runner']->create_config( self::$db_settings ); + case 'invoking': { + $cmd = $arguments[0]; + + switch ( $cmd ) { + case 'core install': { + $world['result'] = $world['runner']->run_install(); + } + break; + + case 'core config': { + $world['result'] = $world['runner']->create_config( self::$db_settings ); + } + break; + + default: { + $world['result'] = $world['runner']->run( $cmd ); + } + } } break; default: { - $cmd = str_replace( 'invoking ', '', $action ); - - $world['result'] = $world['runner']->run( $cmd ); + return $this->notImplemented( $action ); } } } diff --git a/tests/spec-core.php b/tests/spec-core.php index dbbcfbf68..4221919d9 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -7,7 +7,7 @@ public function emptyDir() { $this ->given( 'empty dir' ) - ->when( 'invoking core is-installed' ) + ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 1 ); } @@ -17,16 +17,16 @@ public function noWpConfig() { ->given( 'empty dir' ) ->and( 'wp files' ) - ->when( 'invoking core is-installed' ) + ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 1 ) - ->when( 'invoking core install' ) + ->when( 'invoking', 'core install' ) ->then( 'output should be', "Error: wp-config.php not found.\n" . "Either create one manually or use `wp core config`.\n" ) - ->when( 'invoking core config' ) + ->when( 'invoking', 'core config' ) ->then( 'return code should be', 0 ); } @@ -37,16 +37,16 @@ public function dbTablesNotInstalled() { ->and( 'wp files' ) ->and( 'wp config' ) - ->when( 'invoking core is-installed' ) + ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 1 ) - ->when( 'invoking help' ) + ->when( 'invoking', 'help' ) ->then( 'should have output' ) - ->when( 'invoking core install' ) + ->when( 'invoking', 'core install' ) ->then( 'return code should be', 0 ) - ->when( 'invoking post list --ids' ) + ->when( 'invoking', 'post list --ids' ) ->then( 'output should be', 1 ); } @@ -56,7 +56,7 @@ public function fullInstall() { ->given( 'empty dir' ) ->and( 'wp install' ) - ->when( 'invoking core is-installed' ) + ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 0 ); } } From 398af1ceea87bf96396e9825792c0c30ff0cf2cd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 14:57:36 +0200 Subject: [PATCH 1054/5359] add test case for custom WP_CONTENT dirs --- tests/abstract-spec.php | 5 +++++ tests/command-runner.php | 31 +++++++++++++++++++++++++++++++ tests/spec-core.php | 14 ++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 11effab3c..e49239ddb 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -45,6 +45,11 @@ public function runGiven( &$world, $action, $arguments ) { } break; + case 'custom wp-content dir': { + $world['runner']->define_custom_wp_content_dir(); + } + break; + default: { return $this->notImplemented( $action ); } diff --git a/tests/command-runner.php b/tests/command-runner.php index d232c9111..26133fd91 100644 --- a/tests/command-runner.php +++ b/tests/command-runner.php @@ -28,6 +28,37 @@ public function create_config( $db_settings ) { return $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); } + public function define_custom_wp_content_dir() { + $wp_config_path = $this->install_dir . '/wp-config.php'; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $this->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); + + $this->move_files( 'wp-content', 'my-content' ); + + $this->add_line_to_wp_config( $wp_config_code, + "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); + + $this->move_files( 'my-content/plugins', 'my-plugins' ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } + + private function move_files( $src, $dest ) { + rename( + $this->install_dir . '/' . $src, + $this->install_dir . '/' . $dest + ); + } + + private function add_line_to_wp_config( &$wp_config_code, $line ) { + $token = "/* That's all, stop editing!"; + + $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); + } + public function run_install() { $cmd = 'core install' . \WP_CLI\Utils\compose_assoc_args( array( 'url' => 'http://example.com', diff --git a/tests/spec-core.php b/tests/spec-core.php index 4221919d9..adb4c574d 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -59,5 +59,19 @@ public function fullInstall() { ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 0 ); } + + /** @scenario */ + public function customWpContentDir() { + $this + ->given( 'empty dir' ) + ->and( 'wp install' ) + ->and( 'custom wp-content dir' ) + + ->when( 'invoking', 'theme status twentytwelve' ) + ->then( 'return code should be', 0 ) + + ->when( 'invoking', 'plugin status hello' ) + ->then( 'return code should be', 0 ); + } } From d167367ccaf8b4f3ec7406d907d3d83cfa02522c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 30 Dec 2012 15:06:25 +0200 Subject: [PATCH 1055/5359] replace __FILE__ and __DIR__ before calling eval() --- php/utils.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 70079b0cf..6e4368954 100644 --- a/php/utils.php +++ b/php/utils.php @@ -202,18 +202,28 @@ function locate_wp_config() { * @return string */ function get_wp_config_code() { - $wp_config_code = file_get_contents( locate_wp_config() ); + $wp_config_path = locate_wp_config(); + + $replacements = array( + '__FILE__' => "'$wp_config_path'", + '__DIR__' => "'" . dirname( $wp_config_path ) . "'" + ); + + $old = array_keys( $replacements ); + $new = array_values( $replacements ); + + $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); $lines_to_run = array(); - foreach ( explode( "\n", $wp_config_code ) as $line ) { + foreach ( $wp_config_code as $line ) { if ( 0 === strpos( $line, '<?php' ) ) continue; if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) continue; - $lines_to_run[] = $line; + $lines_to_run[] = str_replace( $old, $new, $line ); } return implode( "\n", $lines_to_run ); From 0a8c543e3468cf22e0b772526bd3ef9da8a5937d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 14:40:41 +0200 Subject: [PATCH 1056/5359] move dispatching logic to a standalone utility function --- php/class-wp-cli.php | 18 +----------------- php/utils.php | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0c17283ac..34848dbc1 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -403,23 +403,7 @@ static function after_wp_load() { } private static function run_command() { - $command = \WP_CLI::$root; - - $args = self::$arguments; - - while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { - $subcommand = $command->pre_invoke( $args ); - if ( !$subcommand ) - break; - - $command = $subcommand; - } - - if ( $command instanceof Dispatcher\CommandContainer ) { - $command->show_usage(); - } else { - $command->invoke( $args, self::$assoc_args ); - } + Utils\run_command( self::$arguments, self::$assoc_args ); } private static function show_info() { diff --git a/php/utils.php b/php/utils.php index 6e4368954..bf0b6d050 100644 --- a/php/utils.php +++ b/php/utils.php @@ -4,6 +4,8 @@ namespace WP_CLI\Utils; +use \WP_CLI\Dispatcher; + function bootstrap() { $vendor_paths = array( WP_CLI_ROOT . '../../../../vendor', // part of a larger project @@ -118,6 +120,30 @@ function compose_assoc_args( $assoc_args ) { return $str; } +/** + * Run a given command. + * + * @param array + * @param array + */ +function run_command( $args, $assoc_args ) { + $command = \WP_CLI::$root; + + while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { + $subcommand = $command->pre_invoke( $args ); + if ( !$subcommand ) + break; + + $command = $subcommand; + } + + if ( $command instanceof Dispatcher\CommandContainer ) { + $command->show_usage(); + } else { + $command->invoke( $args, $assoc_args ); + } +} + function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $blog = $assoc_args['url']; From d71537e0bcc91042787d84a80b5315424b2985fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 14:46:17 +0200 Subject: [PATCH 1057/5359] compose_args() -> args_to_str() --- php/utils.php | 4 ++-- tests/command-runner.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index bf0b6d050..799dca696 100644 --- a/php/utils.php +++ b/php/utils.php @@ -97,7 +97,7 @@ function parse_args( $arguments ) { * @param array * @return string */ -function compose_args( $args ) { +function args_to_str( $args ) { return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); } @@ -107,7 +107,7 @@ function compose_args( $args ) { * @param array * @return string */ -function compose_assoc_args( $assoc_args ) { +function assoc_args_to_str( $assoc_args ) { $str = ''; foreach ( $assoc_args as $key => $value ) { diff --git a/tests/command-runner.php b/tests/command-runner.php index 26133fd91..a54cd7f19 100644 --- a/tests/command-runner.php +++ b/tests/command-runner.php @@ -25,7 +25,7 @@ public function run( $command, $cwd = false ) { } public function create_config( $db_settings ) { - return $this->run( 'core config' . \WP_CLI\Utils\compose_assoc_args( $db_settings ) ); + return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( $db_settings ) ); } public function define_custom_wp_content_dir() { @@ -60,7 +60,7 @@ private function add_line_to_wp_config( &$wp_config_code, $line ) { } public function run_install() { - $cmd = 'core install' . \WP_CLI\Utils\compose_assoc_args( array( + $cmd = 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( 'url' => 'http://example.com', 'title' => 'WP CLI Tests', 'admin_email' => 'admin@example.com', From 6377865c83d8fedd0dcf66ae541425206cec38c5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 14:51:42 +0200 Subject: [PATCH 1058/5359] run_command(): make $assoc_args parameter optional --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 799dca696..5e3d8f8a8 100644 --- a/php/utils.php +++ b/php/utils.php @@ -126,7 +126,7 @@ function assoc_args_to_str( $assoc_args ) { * @param array * @param array */ -function run_command( $args, $assoc_args ) { +function run_command( $args, $assoc_args = array() ) { $command = \WP_CLI::$root; while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { From e192796d3d5e00315457532709a5e57d0b93fdb9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 15:05:48 +0200 Subject: [PATCH 1059/5359] s/$blog/$url/ --- php/utils.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/php/utils.php b/php/utils.php index 5e3d8f8a8..5a012498e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -146,14 +146,14 @@ function run_command( $args, $assoc_args = array() ) { function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { - $blog = $assoc_args['url']; + $url = $assoc_args['url']; } elseif ( isset( $assoc_args['blog'] ) ) { - $blog = $assoc_args['blog']; - if ( true === $blog ) { + $url = $assoc_args['blog']; + if ( true === $url ) { \WP_CLI::line( 'usage: wp --blog=example.com' ); } } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { - $blog = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); + $url = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); } elseif ( $wp_config_path = locate_wp_config() ) { // Try to find the blog parameter in the wp-config file $wp_config_file = file_get_contents( $wp_config_path ); @@ -168,13 +168,13 @@ function set_url( $assoc_args ) { } if ( !empty( $hit ) && isset( $hit['domain'] ) ) - $blog = $hit['domain']; + $url = $hit['domain']; if ( !empty( $hit ) && isset( $hit['path'] ) ) - $blog .= $hit['path']; + $url .= $hit['path']; } - if ( isset( $blog ) ) { - set_url_params( $blog ); + if ( isset( $url ) ) { + set_url_params( $url ); } } From 1f8a43c8796ee60c45cbb2264e5587f3ce8b3990 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 15:08:33 +0200 Subject: [PATCH 1060/5359] add deprecation warnings for --blog and wp-cli-blog. see #254 --- php/utils.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/utils.php b/php/utils.php index 5a012498e..e23bdda90 100644 --- a/php/utils.php +++ b/php/utils.php @@ -148,11 +148,15 @@ function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $url = $assoc_args['url']; } elseif ( isset( $assoc_args['blog'] ) ) { + \WP_CLI::warning( 'The --blog parameter is deprecated. use --url instead' ); + $url = $assoc_args['blog']; if ( true === $url ) { \WP_CLI::line( 'usage: wp --blog=example.com' ); } } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { + \WP_CLI::warning( 'The wp-cli-blog file is deprecated. use wp-cli.yml instead' ); + $url = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); } elseif ( $wp_config_path = locate_wp_config() ) { // Try to find the blog parameter in the wp-config file From ea80ac02b1268b9962804ce6fa94a83a8fc9c57e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 15:10:01 +0200 Subject: [PATCH 1061/5359] fix punctuation for deprecation messages --- php/utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index e23bdda90..c69406165 100644 --- a/php/utils.php +++ b/php/utils.php @@ -148,14 +148,14 @@ function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $url = $assoc_args['url']; } elseif ( isset( $assoc_args['blog'] ) ) { - \WP_CLI::warning( 'The --blog parameter is deprecated. use --url instead' ); + \WP_CLI::warning( 'The --blog parameter is deprecated. Use --url instead.' ); $url = $assoc_args['blog']; if ( true === $url ) { \WP_CLI::line( 'usage: wp --blog=example.com' ); } } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { - \WP_CLI::warning( 'The wp-cli-blog file is deprecated. use wp-cli.yml instead' ); + \WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); $url = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); } elseif ( $wp_config_path = locate_wp_config() ) { From 2e6b1f83c62a1da309c150cac9e98e7e8e83d593 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:08:37 +0200 Subject: [PATCH 1062/5359] change alias from 'pt' to 'cpt', which is more familiar --- php/commands/scaffold.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ee11f0c8f..7dac8f402 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -10,7 +10,7 @@ * @maintainer LinePress (http://www.linespress.org) */ class Scaffold_Command extends WP_CLI_Command { - + function __construct() { WP_Filesystem(); } @@ -18,7 +18,7 @@ function __construct() { /** * @subcommand post-type * - * @alias pt + * @alias cpt * * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] */ @@ -28,7 +28,7 @@ function post_type( $args, $assoc_args ) { // Set the args to variables with normal names to keep our sanity $post_type = strtolower( $args[0] ); - // We use the machine name for function declarations + // We use the machine name for function declarations $machine_name = preg_replace( '/-/', '_', $post_type ); $machine_name_plural = $this->pluralize( $post_type ); @@ -39,7 +39,7 @@ function post_type( $args, $assoc_args ) { $label_plural = $this->pluralize( $label ); $label_plural_ucfirst = ucfirst( $label_plural ); } - + // set up defaults and merge theme with assoc_args $defaults = array( 'description' => "", @@ -70,7 +70,7 @@ function post_type( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - + if( ! $raw ) { include 'skeletons/post_type_skeleton.php'; $output = str_replace( "<?php", "", $output); @@ -109,7 +109,7 @@ function taxonomy( $args, $assoc_args ) { // Set the args to variables with normal names to keep our sanity $taxonomy = strtolower( $args[0] ); - // We use the machine name for function declarations + // We use the machine name for function declarations $machine_name = preg_replace( '/-/', '_', $taxonomy ); $machine_name_plural = $this->pluralize( $taxonomy ); @@ -137,7 +137,7 @@ function taxonomy( $args, $assoc_args ) { 'plugin_name' => false, 'raw' => false, ); - + // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); @@ -176,7 +176,7 @@ private function get_output_path( $assoc_args ) { // Implements the --theme flag || --plugin_name=<plugin_name> if( $theme ) { //Here we assume you got a theme installed - $path = TEMPLATEPATH; + $path = TEMPLATEPATH; } elseif ( ! empty( $plugin_name ) ){ $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line @@ -227,7 +227,7 @@ private function save_skeleton_output( $assoc_args ) { */ private function get_textdomain( $textdomain, $theme, $plugin_name ) { if( empty( $textdomain ) && $theme ) { - $textdomain = strtolower( wp_get_theme()->template ); + $textdomain = strtolower( wp_get_theme()->template ); } elseif ( empty( $textdomain ) && $plugin_name) { $textdomain = $plugin_name; } elseif ( empty( $textdomain ) || gettype($textdomain) == 'boolean' ) { //This mean just a flag @@ -291,4 +291,4 @@ private function pluralize( $word ) { } return false; } -} \ No newline at end of file +} From 74abf21f6071a36da9bfd9560e687f08add3ccac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:10:36 +0200 Subject: [PATCH 1063/5359] scaffold.php: tabs, not spaces --- php/commands/scaffold.php | 561 +++++++++++++++++++------------------- 1 file changed, 281 insertions(+), 280 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 7dac8f402..26157b158 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -11,284 +11,285 @@ */ class Scaffold_Command extends WP_CLI_Command { - function __construct() { - WP_Filesystem(); - } - - /** - * @subcommand post-type - * - * @alias cpt - * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] - */ - function post_type( $args, $assoc_args ) { - global $wp_filesystem; - - // Set the args to variables with normal names to keep our sanity - $post_type = strtolower( $args[0] ); - - // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $post_type ); - $machine_name_plural = $this->pluralize( $post_type ); - - // If no label is given use the slug and prettify it as good as possible - if( ! isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); - $label_ucfirst = ucfirst( $label ); - $label_plural = $this->pluralize( $label ); - $label_plural_ucfirst = ucfirst( $label_plural ); - } - - // set up defaults and merge theme with assoc_args - $defaults = array( - 'description' => "", - 'public' => 'true', - 'exclude_from_search' => 'false', - 'show_ui' => 'true', - 'show_in_nav_menus' => 'true', - 'show_in_menu' => 'true', - 'show_in_admin_bar' => 'true', - 'menu_position' => 'null', - 'menu_icon' => 'null', - 'capability_type' => 'post', - 'hierarchical' => 'false', - 'supports' => "'title', 'editor'", - 'has_archive' => 'true', - 'slug' => $machine_name_plural, - 'feeds' => 'true', - 'pages' => 'true', - 'query_var' => 'true', - 'can_export' => 'true', - 'textdomain' => '', - 'theme' => false, - 'plugin_name' => false, - 'raw' => false, - ); - - // Generate the variables from the defaults and associated arguments if they are set - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - - if( ! $raw ) { - include 'skeletons/post_type_skeleton.php'; - $output = str_replace( "<?php", "", $output); - include 'skeletons/post_type_skeleton_extended.php'; - } else { - include 'skeletons/post_type_skeleton.php'; - } - - if ( $theme || ! empty( $plugin_name ) ) { - // Write file to theme or given plugin_name - $assoc_args = array( - 'type' => 'post_type', - 'output' => $output, - 'theme' => $theme, - 'plugin_name' => $plugin_name, - 'machine_name' => $machine_name, - ); - $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->save_skeleton_output( $assoc_args ); - } else { - // STDOUT - echo $output; - } - } - - /** - * @subcommand taxonomy - * - * @alias tax - * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] - */ - function taxonomy( $args, $assoc_args ) { - global $wp_filesystem; - - // Set the args to variables with normal names to keep our sanity - $taxonomy = strtolower( $args[0] ); - - // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $taxonomy ); - $machine_name_plural = $this->pluralize( $taxonomy ); - - // If no label is given use the slug and prettify it as good as possible - if( ! isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); - $label_ucfirst = ucfirst( $label ); - $label_plural = $this->pluralize( $label ); - $label_plural_ucfirst = ucfirst( $label_plural ); - } - - // Set up defaults and merge theme with assoc_args - $defaults = array( - 'public' => 'true', - 'show_in_nav_menus' => 'true', - 'show_ui' => 'true', - 'show_tagcloud' => 'true', - 'hierarchical' => 'false', - 'rewrite' => 'true', - 'query_var' => 'true', - 'slug' => $taxonomy, - 'post_types' => 'post', - 'textdomain' => '', - 'theme' => false, - 'plugin_name' => false, - 'raw' => false, - ); - - // Generate the variables from the defaults and associated arguments if they are set - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - - if( ! $raw ) { - include 'skeletons/taxonomy_skeleton.php'; - $output = str_replace( "<?php", "", $output); - include 'skeletons/taxonomy_skeleton_extended.php'; - } else { - include 'skeletons/taxonomy_skeleton.php'; - } - - if ( $theme || ! empty( $plugin_name ) ) { - // Write file to theme or given plugin_name - $assoc_args = array( - 'type' => 'taxonomy', - 'output' => $output, - 'theme' => $theme, - 'plugin_name' => $plugin_name, - 'machine_name' => $machine_name, - ); - $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->save_skeleton_output( $assoc_args ); - } else { - // STDOUT - echo $output; - } - } - - private function get_output_path( $assoc_args ) { - global $wp_filesystem; - - extract( $assoc_args, EXTR_SKIP ); - - // Implements the --theme flag || --plugin_name=<plugin_name> - if( $theme ) { - //Here we assume you got a theme installed - $path = TEMPLATEPATH; - } elseif ( ! empty( $plugin_name ) ){ - $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line - $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line - } else { - // STDOUT - return false; - } - - if ( $type === "post_type") { - $path .= '/post-types/'; - } elseif ( $type === "taxonomy" ) { - $path .= '/taxonomies/'; - } - - // If it doesn't exists create it - if( ! $wp_filesystem->is_dir( $path ) ) { - $wp_filesystem->mkdir( $path ); - WP_CLI::success( "Created dir: {$path}" ); - } elseif( $wp_filesystem->is_dir( $path ) ) { - WP_CLI::success( "Dir already exists: {$path}" ); - } else { - WP_CLI::error( "Couldn't create dir exists: {$path}" ); - } - - return $path; - } - - private function save_skeleton_output( $assoc_args ) { - global $wp_filesystem; - - extract( $assoc_args, EXTR_SKIP ); - - // Write to file - if( $path ) { - $filename = $path . $machine_name .'.php'; - - if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { - WP_CLI::error( "Error while saving file: {$filename}" ); - } else { - WP_CLI::success( "{$type} {$machine_name} created" ); - } - } - } - - /** - * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. - * Same goes for when plugin_name is being used. - */ - private function get_textdomain( $textdomain, $theme, $plugin_name ) { - if( empty( $textdomain ) && $theme ) { - $textdomain = strtolower( wp_get_theme()->template ); - } elseif ( empty( $textdomain ) && $plugin_name) { - $textdomain = $plugin_name; - } elseif ( empty( $textdomain ) || gettype($textdomain) == 'boolean' ) { //This mean just a flag - $textdomain = 'YOUR-TEXTDOMAIN'; - } - - return $textdomain; - } - - private function pluralize( $word ) { - $plural = array( - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)ix|ex$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(buffal|tomat)o$/i' => '\1oes', - '/(bu)s$/i' => '1ses', - '/(alias|status)/i' => '\1es', - '/(octop|vir)us$/i' => '1i', - '/(ax|test)is$/i' => '\1es', - '/s$/i' => 's', - '/$/' => 's' - ); - - $uncountable = array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep' ); - - $irregular = array( - 'person' => 'people', - 'man' => 'men', - 'woman' => 'women', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves' - ); - - $lowercased_word = strtolower( $word ); - - foreach ( $uncountable as $_uncountable ){ - if( substr( $lowercased_word, ( -1 * strlen( $_uncountable) ) ) == $_uncountable ){ - return $word; - } - } - - foreach ( $irregular as $_plural=> $_singular ){ - if ( preg_match( '/('.$_plural.')$/i', $word, $arr ) ) { - return preg_replace( '/('.$_plural.')$/i', substr( $arr[0], 0, 1 ).substr( $_singular, 1 ), $word ); - } - } - - foreach ( $plural as $rule => $replacement ) { - if ( preg_match( $rule, $word ) ) { - return preg_replace( $rule, $replacement, $word ); - } - } - return false; - } + function __construct() { + WP_Filesystem(); + } + + /** + * @subcommand post-type + * + * @alias cpt + * + * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] + */ + function post_type( $args, $assoc_args ) { + global $wp_filesystem; + + // Set the args to variables with normal names to keep our sanity + $post_type = strtolower( $args[0] ); + + // We use the machine name for function declarations + $machine_name = preg_replace( '/-/', '_', $post_type ); + $machine_name_plural = $this->pluralize( $post_type ); + + // If no label is given use the slug and prettify it as good as possible + if( ! isset( $assoc_args['label'] ) ) { + $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); + $label_ucfirst = ucfirst( $label ); + $label_plural = $this->pluralize( $label ); + $label_plural_ucfirst = ucfirst( $label_plural ); + } + + // set up defaults and merge theme with assoc_args + $defaults = array( + 'description' => "", + 'public' => 'true', + 'exclude_from_search' => 'false', + 'show_ui' => 'true', + 'show_in_nav_menus' => 'true', + 'show_in_menu' => 'true', + 'show_in_admin_bar' => 'true', + 'menu_position' => 'null', + 'menu_icon' => 'null', + 'capability_type' => 'post', + 'hierarchical' => 'false', + 'supports' => "'title', 'editor'", + 'has_archive' => 'true', + 'slug' => $machine_name_plural, + 'feeds' => 'true', + 'pages' => 'true', + 'query_var' => 'true', + 'can_export' => 'true', + 'textdomain' => '', + 'theme' => false, + 'plugin_name' => false, + 'raw' => false, + ); + + // Generate the variables from the defaults and associated arguments if they are set + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); + + if( ! $raw ) { + include 'skeletons/post_type_skeleton.php'; + $output = str_replace( "<?php", "", $output); + include 'skeletons/post_type_skeleton_extended.php'; + } else { + include 'skeletons/post_type_skeleton.php'; + } + + if ( $theme || ! empty( $plugin_name ) ) { + // Write file to theme or given plugin_name + $assoc_args = array( + 'type' => 'post_type', + 'output' => $output, + 'theme' => $theme, + 'plugin_name' => $plugin_name, + 'machine_name' => $machine_name, + ); + $assoc_args['path'] = $this->get_output_path( $assoc_args ); + $this->save_skeleton_output( $assoc_args ); + } else { + // STDOUT + echo $output; + } + } + + /** + * @subcommand taxonomy + * + * @alias tax + * + * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] + */ + function taxonomy( $args, $assoc_args ) { + global $wp_filesystem; + + // Set the args to variables with normal names to keep our sanity + $taxonomy = strtolower( $args[0] ); + + // We use the machine name for function declarations + $machine_name = preg_replace( '/-/', '_', $taxonomy ); + $machine_name_plural = $this->pluralize( $taxonomy ); + + // If no label is given use the slug and prettify it as good as possible + if( ! isset( $assoc_args['label'] ) ) { + $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); + $label_ucfirst = ucfirst( $label ); + $label_plural = $this->pluralize( $label ); + $label_plural_ucfirst = ucfirst( $label_plural ); + } + + // Set up defaults and merge theme with assoc_args + $defaults = array( + 'public' => 'true', + 'show_in_nav_menus' => 'true', + 'show_ui' => 'true', + 'show_tagcloud' => 'true', + 'hierarchical' => 'false', + 'rewrite' => 'true', + 'query_var' => 'true', + 'slug' => $taxonomy, + 'post_types' => 'post', + 'textdomain' => '', + 'theme' => false, + 'plugin_name' => false, + 'raw' => false, + ); + + // Generate the variables from the defaults and associated arguments if they are set + extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); + + if( ! $raw ) { + include 'skeletons/taxonomy_skeleton.php'; + $output = str_replace( "<?php", "", $output); + include 'skeletons/taxonomy_skeleton_extended.php'; + } else { + include 'skeletons/taxonomy_skeleton.php'; + } + + if ( $theme || ! empty( $plugin_name ) ) { + // Write file to theme or given plugin_name + $assoc_args = array( + 'type' => 'taxonomy', + 'output' => $output, + 'theme' => $theme, + 'plugin_name' => $plugin_name, + 'machine_name' => $machine_name, + ); + $assoc_args['path'] = $this->get_output_path( $assoc_args ); + $this->save_skeleton_output( $assoc_args ); + } else { + // STDOUT + echo $output; + } + } + + private function get_output_path( $assoc_args ) { + global $wp_filesystem; + + extract( $assoc_args, EXTR_SKIP ); + + // Implements the --theme flag || --plugin_name=<plugin_name> + if( $theme ) { + //Here we assume you got a theme installed + $path = TEMPLATEPATH; + } elseif ( ! empty( $plugin_name ) ){ + $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line + $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line + } else { + // STDOUT + return false; + } + + if ( $type === "post_type") { + $path .= '/post-types/'; + } elseif ( $type === "taxonomy" ) { + $path .= '/taxonomies/'; + } + + // If it doesn't exists create it + if( ! $wp_filesystem->is_dir( $path ) ) { + $wp_filesystem->mkdir( $path ); + WP_CLI::success( "Created dir: {$path}" ); + } elseif( $wp_filesystem->is_dir( $path ) ) { + WP_CLI::success( "Dir already exists: {$path}" ); + } else { + WP_CLI::error( "Couldn't create dir exists: {$path}" ); + } + + return $path; + } + + private function save_skeleton_output( $assoc_args ) { + global $wp_filesystem; + + extract( $assoc_args, EXTR_SKIP ); + + // Write to file + if( $path ) { + $filename = $path . $machine_name .'.php'; + + if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { + WP_CLI::error( "Error while saving file: {$filename}" ); + } else { + WP_CLI::success( "{$type} {$machine_name} created" ); + } + } + } + + /** + * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. + * Same goes for when plugin_name is being used. + */ + private function get_textdomain( $textdomain, $theme, $plugin_name ) { + if( empty( $textdomain ) && $theme ) { + $textdomain = strtolower( wp_get_theme()->template ); + } elseif ( empty( $textdomain ) && $plugin_name) { + $textdomain = $plugin_name; + } elseif ( empty( $textdomain ) || gettype($textdomain) == 'boolean' ) { //This mean just a flag + $textdomain = 'YOUR-TEXTDOMAIN'; + } + + return $textdomain; + } + + private function pluralize( $word ) { + $plural = array( + '/(quiz)$/i' => '\1zes', + '/^(ox)$/i' => '\1en', + '/([m|l])ouse$/i' => '\1ice', + '/(matr|vert|ind)ix|ex$/i' => '\1ices', + '/(x|ch|ss|sh)$/i' => '\1es', + '/([^aeiouy]|qu)ies$/i' => '\1y', + '/([^aeiouy]|qu)y$/i' => '\1ies', + '/(hive)$/i' => '\1s', + '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', + '/sis$/i' => 'ses', + '/([ti])um$/i' => '\1a', + '/(buffal|tomat)o$/i' => '\1oes', + '/(bu)s$/i' => '1ses', + '/(alias|status)/i' => '\1es', + '/(octop|vir)us$/i' => '1i', + '/(ax|test)is$/i' => '\1es', + '/s$/i' => 's', + '/$/' => 's' + ); + + $uncountable = array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep' ); + + $irregular = array( + 'person' => 'people', + 'man' => 'men', + 'woman' => 'women', + 'child' => 'children', + 'sex' => 'sexes', + 'move' => 'moves' + ); + + $lowercased_word = strtolower( $word ); + + foreach ( $uncountable as $_uncountable ){ + if( substr( $lowercased_word, ( -1 * strlen( $_uncountable) ) ) == $_uncountable ){ + return $word; + } + } + + foreach ( $irregular as $_plural=> $_singular ){ + if ( preg_match( '/('.$_plural.')$/i', $word, $arr ) ) { + return preg_replace( '/('.$_plural.')$/i', substr( $arr[0], 0, 1 ).substr( $_singular, 1 ), $word ); + } + } + + foreach ( $plural as $rule => $replacement ) { + if ( preg_match( $rule, $word ) ) { + return preg_replace( $rule, $replacement, $word ); + } + } + return false; + } } + From ac6a92bf3e02c265cb05cf658320c22309966b1d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:12:17 +0200 Subject: [PATCH 1064/5359] spacing fixes --- php/commands/scaffold.php | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 26157b158..078353cc5 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -16,6 +16,8 @@ function __construct() { } /** + * + * * @subcommand post-type * * @alias cpt @@ -33,7 +35,7 @@ function post_type( $args, $assoc_args ) { $machine_name_plural = $this->pluralize( $post_type ); // If no label is given use the slug and prettify it as good as possible - if( ! isset( $assoc_args['label'] ) ) { + if ( ! isset( $assoc_args['label'] ) ) { $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); $label_ucfirst = ucfirst( $label ); $label_plural = $this->pluralize( $label ); @@ -71,9 +73,9 @@ function post_type( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - if( ! $raw ) { + if ( ! $raw ) { include 'skeletons/post_type_skeleton.php'; - $output = str_replace( "<?php", "", $output); + $output = str_replace( "<?php", "", $output ); include 'skeletons/post_type_skeleton_extended.php'; } else { include 'skeletons/post_type_skeleton.php'; @@ -97,6 +99,8 @@ function post_type( $args, $assoc_args ) { } /** + * + * * @subcommand taxonomy * * @alias tax @@ -114,7 +118,7 @@ function taxonomy( $args, $assoc_args ) { $machine_name_plural = $this->pluralize( $taxonomy ); // If no label is given use the slug and prettify it as good as possible - if( ! isset( $assoc_args['label'] ) ) { + if ( ! isset( $assoc_args['label'] ) ) { $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); $label_ucfirst = ucfirst( $label ); $label_plural = $this->pluralize( $label ); @@ -143,9 +147,9 @@ function taxonomy( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); - if( ! $raw ) { + if ( ! $raw ) { include 'skeletons/taxonomy_skeleton.php'; - $output = str_replace( "<?php", "", $output); + $output = str_replace( "<?php", "", $output ); include 'skeletons/taxonomy_skeleton_extended.php'; } else { include 'skeletons/taxonomy_skeleton.php'; @@ -174,10 +178,10 @@ private function get_output_path( $assoc_args ) { extract( $assoc_args, EXTR_SKIP ); // Implements the --theme flag || --plugin_name=<plugin_name> - if( $theme ) { + if ( $theme ) { //Here we assume you got a theme installed $path = TEMPLATEPATH; - } elseif ( ! empty( $plugin_name ) ){ + } elseif ( ! empty( $plugin_name ) ) { $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line } else { @@ -185,17 +189,17 @@ private function get_output_path( $assoc_args ) { return false; } - if ( $type === "post_type") { + if ( $type === "post_type" ) { $path .= '/post-types/'; } elseif ( $type === "taxonomy" ) { $path .= '/taxonomies/'; } // If it doesn't exists create it - if( ! $wp_filesystem->is_dir( $path ) ) { + if ( ! $wp_filesystem->is_dir( $path ) ) { $wp_filesystem->mkdir( $path ); WP_CLI::success( "Created dir: {$path}" ); - } elseif( $wp_filesystem->is_dir( $path ) ) { + } elseif ( $wp_filesystem->is_dir( $path ) ) { WP_CLI::success( "Dir already exists: {$path}" ); } else { WP_CLI::error( "Couldn't create dir exists: {$path}" ); @@ -210,7 +214,7 @@ private function save_skeleton_output( $assoc_args ) { extract( $assoc_args, EXTR_SKIP ); // Write to file - if( $path ) { + if ( $path ) { $filename = $path . $machine_name .'.php'; if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { @@ -226,11 +230,11 @@ private function save_skeleton_output( $assoc_args ) { * Same goes for when plugin_name is being used. */ private function get_textdomain( $textdomain, $theme, $plugin_name ) { - if( empty( $textdomain ) && $theme ) { + if ( empty( $textdomain ) && $theme ) { $textdomain = strtolower( wp_get_theme()->template ); - } elseif ( empty( $textdomain ) && $plugin_name) { + } elseif ( empty( $textdomain ) && $plugin_name ) { $textdomain = $plugin_name; - } elseif ( empty( $textdomain ) || gettype($textdomain) == 'boolean' ) { //This mean just a flag + } elseif ( empty( $textdomain ) || gettype( $textdomain ) == 'boolean' ) { //This mean just a flag $textdomain = 'YOUR-TEXTDOMAIN'; } @@ -272,13 +276,13 @@ private function pluralize( $word ) { $lowercased_word = strtolower( $word ); - foreach ( $uncountable as $_uncountable ){ - if( substr( $lowercased_word, ( -1 * strlen( $_uncountable) ) ) == $_uncountable ){ + foreach ( $uncountable as $_uncountable ) { + if ( substr( $lowercased_word, ( -1 * strlen( $_uncountable ) ) ) == $_uncountable ) { return $word; } } - foreach ( $irregular as $_plural=> $_singular ){ + foreach ( $irregular as $_plural=> $_singular ) { if ( preg_match( '/('.$_plural.')$/i', $word, $arr ) ) { return preg_replace( '/('.$_plural.')$/i', substr( $arr[0], 0, 1 ).substr( $_singular, 1 ), $word ); } @@ -292,4 +296,3 @@ private function pluralize( $word ) { return false; } } - From 98cdec7d6e56a1f99131ef1944be61714c39200a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:14:00 +0200 Subject: [PATCH 1065/5359] add shortdesc and mention <slug> in synopsis --- php/commands/scaffold.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 078353cc5..d25896d62 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -16,13 +16,13 @@ function __construct() { } /** - * + * Generate PHP code for registering a custom post type. * * @subcommand post-type * * @alias cpt * - * @synopsis [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] + * @synopsis <slug> [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -99,13 +99,13 @@ function post_type( $args, $assoc_args ) { } /** - * + * Generate PHP code for registering a custom taxonomy. * * @subcommand taxonomy * * @alias tax * - * @synopsis [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] + * @synopsis <slug> [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; From 487f728009f19a94e42a2e03b593b23f41b72080 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:26:58 +0200 Subject: [PATCH 1066/5359] rename --plugin_name arg to --plugin --- php/commands/scaffold.php | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d25896d62..42f1790fa 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -22,7 +22,7 @@ function __construct() { * * @alias cpt * - * @synopsis <slug> [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin_name=<plugin_name>] [--raw] + * @synopsis <slug> [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function post_type( $args, $assoc_args ) { global $wp_filesystem; @@ -64,14 +64,14 @@ function post_type( $args, $assoc_args ) { 'can_export' => 'true', 'textdomain' => '', 'theme' => false, - 'plugin_name' => false, + 'plugin' => false, 'raw' => false, ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); if ( ! $raw ) { include 'skeletons/post_type_skeleton.php'; @@ -81,13 +81,13 @@ function post_type( $args, $assoc_args ) { include 'skeletons/post_type_skeleton.php'; } - if ( $theme || ! empty( $plugin_name ) ) { - // Write file to theme or given plugin_name + if ( $theme || ! empty( $plugin ) ) { + // Write file to theme or given plugin $assoc_args = array( 'type' => 'post_type', 'output' => $output, 'theme' => $theme, - 'plugin_name' => $plugin_name, + 'plugin' => $plugin, 'machine_name' => $machine_name, ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); @@ -105,7 +105,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis <slug> [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin_name=<plugin_name>] [--raw] + * @synopsis <slug> [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin>] [--raw] */ function taxonomy( $args, $assoc_args ) { global $wp_filesystem; @@ -138,14 +138,14 @@ function taxonomy( $args, $assoc_args ) { 'post_types' => 'post', 'textdomain' => '', 'theme' => false, - 'plugin_name' => false, + 'plugin' => false, 'raw' => false, ); // Generate the variables from the defaults and associated arguments if they are set extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin_name ); + $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); if ( ! $raw ) { include 'skeletons/taxonomy_skeleton.php'; @@ -155,13 +155,13 @@ function taxonomy( $args, $assoc_args ) { include 'skeletons/taxonomy_skeleton.php'; } - if ( $theme || ! empty( $plugin_name ) ) { - // Write file to theme or given plugin_name + if ( $theme || ! empty( $plugin ) ) { + // Write file to theme or given plugin $assoc_args = array( 'type' => 'taxonomy', 'output' => $output, 'theme' => $theme, - 'plugin_name' => $plugin_name, + 'plugin' => $plugin, 'machine_name' => $machine_name, ); $assoc_args['path'] = $this->get_output_path( $assoc_args ); @@ -177,13 +177,13 @@ private function get_output_path( $assoc_args ) { extract( $assoc_args, EXTR_SKIP ); - // Implements the --theme flag || --plugin_name=<plugin_name> + // Implements the --theme flag || --plugin=<plugin> if ( $theme ) { //Here we assume you got a theme installed $path = TEMPLATEPATH; - } elseif ( ! empty( $plugin_name ) ) { - $path = WP_PLUGIN_DIR . '/' . $plugin_name; //Faking recursive mkdir for down the line - $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin_name ); //Faking recursive mkdir for down the line + } elseif ( ! empty( $plugin ) ) { + $path = WP_PLUGIN_DIR . '/' . $plugin; //Faking recursive mkdir for down the line + $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin ); //Faking recursive mkdir for down the line } else { // STDOUT return false; @@ -227,13 +227,13 @@ private function save_skeleton_output( $assoc_args ) { /** * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. - * Same goes for when plugin_name is being used. + * Same goes for when plugin is being used. */ - private function get_textdomain( $textdomain, $theme, $plugin_name ) { + private function get_textdomain( $textdomain, $theme, $plugin ) { if ( empty( $textdomain ) && $theme ) { $textdomain = strtolower( wp_get_theme()->template ); - } elseif ( empty( $textdomain ) && $plugin_name ) { - $textdomain = $plugin_name; + } elseif ( empty( $textdomain ) && $plugin ) { + $textdomain = $plugin; } elseif ( empty( $textdomain ) || gettype( $textdomain ) == 'boolean' ) { //This mean just a flag $textdomain = 'YOUR-TEXTDOMAIN'; } From 0058ae757d882a9748d2428a45053ce91f8072fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:32:35 +0200 Subject: [PATCH 1067/5359] add man pages --- man-src/scaffold-post-type.txt | 19 +++++++++++++++++ man-src/scaffold-taxonomy.txt | 19 +++++++++++++++++ man/scaffold-post-type.1 | 37 ++++++++++++++++++++++++++++++++++ man/scaffold-taxonomy.1 | 37 ++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 man-src/scaffold-post-type.txt create mode 100644 man-src/scaffold-taxonomy.txt create mode 100644 man/scaffold-post-type.1 create mode 100644 man/scaffold-taxonomy.1 diff --git a/man-src/scaffold-post-type.txt b/man-src/scaffold-post-type.txt new file mode 100644 index 000000000..e78108cde --- /dev/null +++ b/man-src/scaffold-post-type.txt @@ -0,0 +1,19 @@ +## OPTIONS + +* `--textdomain=<textdomain>`: + + The textdomain to use for the labels. + +* `--theme`: + + Create a file in the current theme directory, instead of sending to +STDOUT. + +* `--plugin=<plugin>`: + + Create a file in the given plugin's directory, instead of sending to +STDOUT. + +* `--raw`: + + Just generate the `register_post_type()` call and nothing else. diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt new file mode 100644 index 000000000..5eac94157 --- /dev/null +++ b/man-src/scaffold-taxonomy.txt @@ -0,0 +1,19 @@ +## OPTIONS + +* `--textdomain=<textdomain>`: + + The textdomain to use for the labels. + +* `--theme`: + + Create a file in the current theme directory, instead of sending to +STDOUT. + +* `--plugin=<plugin>`: + + Create a file in the given plugin's directory, instead of sending to +STDOUT. + +* `--raw`: + + Just generate the `register_taxonomy()` call and nothing else. diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 new file mode 100644 index 000000000..0ecd3f15d --- /dev/null +++ b/man/scaffold-post-type.1 @@ -0,0 +1,37 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-POST\-TYPE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. +. +.SH "SYNOPSIS" +wp scaffold post\-type \fIslug\fR [\-\-description=\fIdescription\fR] [\-\-public=\fIpublic\fR] [\-\-exclude_from_search=\fIexclude_from_search\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_in_menu=\fIshow_in_menu\fR] [\-\-show_in_admin_bar=\fIshow_in_admin_bar\fR] [\-\-menu_position=\fImenu_position\fR] [\-\-menu_icon=\fImenu_icon\fR] [\-\-capability_type=\fIcapability_type\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-supports=\fIsupports\fR] [\-\-has_archive=\fIhas_archive\fR] [\-\-slug=\fIslug\fR] [\-\-feed=\fIfeed\fR] [\-\-pages=\fIpages\fR] [\-\-query_var=\fIquery_var\fR] [\-\-can_export=\fIcan_export\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +. +.SH "OPTIONS" +. +.TP +\fB\-\-textdomain=<textdomain>\fR: +. +.IP +The textdomain to use for the labels\. +. +.TP +\fB\-\-theme\fR: +. +.IP +Create a file in the current theme directory, instead of sending to STDOUT\. +. +.TP +\fB\-\-plugin=<plugin>\fR: +. +.IP +Create a file in the given plugin\'s directory, instead of sending to STDOUT\. +. +.TP +\fB\-\-raw\fR: +. +.IP +Just generate the \fBregister_post_type()\fR call and nothing else\. + diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 new file mode 100644 index 000000000..0b8290186 --- /dev/null +++ b/man/scaffold-taxonomy.1 @@ -0,0 +1,37 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-TAXONOMY" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. +. +.SH "SYNOPSIS" +wp scaffold taxonomy \fIslug\fR [\-\-public=\fIpublic\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_tagcloud=\fIshow_tagcloud\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-rewrite=\fIrewrite\fR] [\-\-query_var=\fIquery_var\fR] [\-\-slug=\fIslug\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-post_types=\fIpost_types\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +. +.SH "OPTIONS" +. +.TP +\fB\-\-textdomain=<textdomain>\fR: +. +.IP +The textdomain to use for the labels\. +. +.TP +\fB\-\-theme\fR: +. +.IP +Create a file in the current theme directory, instead of sending to STDOUT\. +. +.TP +\fB\-\-plugin=<plugin>\fR: +. +.IP +Create a file in the given plugin\'s directory, instead of sending to STDOUT\. +. +.TP +\fB\-\-raw\fR: +. +.IP +Just generate the \fBregister_taxonomy()\fR call and nothing else\. + From 6b2080185a2eaff83e53c0af8c18d9726be4300c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 16:42:45 +0200 Subject: [PATCH 1068/5359] php/commands/skeletons -> php/templates --- php/commands/scaffold.php | 12 ++++++------ .../post_type.php} | 0 .../post_type_extended.php} | 0 .../taxonomy_skeleton.php => templates/taxonomy.php} | 0 .../taxonomy_extended.php} | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename php/{commands/skeletons/post_type_skeleton.php => templates/post_type.php} (100%) rename php/{commands/skeletons/post_type_skeleton_extended.php => templates/post_type_extended.php} (100%) rename php/{commands/skeletons/taxonomy_skeleton.php => templates/taxonomy.php} (100%) rename php/{commands/skeletons/taxonomy_skeleton_extended.php => templates/taxonomy_extended.php} (100%) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 42f1790fa..209351abe 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -74,11 +74,11 @@ function post_type( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); if ( ! $raw ) { - include 'skeletons/post_type_skeleton.php'; + include WP_CLI_ROOT . '/templates/post_type.php'; $output = str_replace( "<?php", "", $output ); - include 'skeletons/post_type_skeleton_extended.php'; + include WP_CLI_ROOT . '/templates/post_type_extended.php'; } else { - include 'skeletons/post_type_skeleton.php'; + include WP_CLI_ROOT . '/templates/post_type.php'; } if ( $theme || ! empty( $plugin ) ) { @@ -148,11 +148,11 @@ function taxonomy( $args, $assoc_args ) { $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); if ( ! $raw ) { - include 'skeletons/taxonomy_skeleton.php'; + include WP_CLI_ROOT . '/templates/taxonomy.php'; $output = str_replace( "<?php", "", $output ); - include 'skeletons/taxonomy_skeleton_extended.php'; + include WP_CLI_ROOT . '/templates/taxonomy_extended.php'; } else { - include 'skeletons/taxonomy_skeleton.php'; + include WP_CLI_ROOT . '/templates/taxonomy.php'; } if ( $theme || ! empty( $plugin ) ) { diff --git a/php/commands/skeletons/post_type_skeleton.php b/php/templates/post_type.php similarity index 100% rename from php/commands/skeletons/post_type_skeleton.php rename to php/templates/post_type.php diff --git a/php/commands/skeletons/post_type_skeleton_extended.php b/php/templates/post_type_extended.php similarity index 100% rename from php/commands/skeletons/post_type_skeleton_extended.php rename to php/templates/post_type_extended.php diff --git a/php/commands/skeletons/taxonomy_skeleton.php b/php/templates/taxonomy.php similarity index 100% rename from php/commands/skeletons/taxonomy_skeleton.php rename to php/templates/taxonomy.php diff --git a/php/commands/skeletons/taxonomy_skeleton_extended.php b/php/templates/taxonomy_extended.php similarity index 100% rename from php/commands/skeletons/taxonomy_skeleton_extended.php rename to php/templates/taxonomy_extended.php From ac0e100424b904a5a827e6276f2d04221ea7935d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 13:30:43 +0200 Subject: [PATCH 1069/5359] add Mustache dependency --- .gitmodules | 3 +++ composer.json | 3 ++- php/mustache | 1 + php/utils.php | 4 ++++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 160000 php/mustache diff --git a/.gitmodules b/.gitmodules index bf7ca3df3..05f4715b9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "php/php-cli-tools"] path = php/php-cli-tools url = git://github.com/wp-cli/php-cli-tools.git +[submodule "php/mustache"] + path = php/mustache + url = git://github.com/bobthecow/mustache.php.git diff --git a/composer.json b/composer.json index abdda1a44..dbb99f17b 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,8 @@ ], "require": { "php": ">=5.3", - "wp-cli/php-cli-tools": "dev-master" + "wp-cli/php-cli-tools": "dev-master", + "mustache/mustache": "2.0.x" }, "require-dev": { "phpunit/phpunit": "3.7.x", diff --git a/php/mustache b/php/mustache new file mode 160000 index 000000000..d99be3444 --- /dev/null +++ b/php/mustache @@ -0,0 +1 @@ +Subproject commit d99be3444e5b2f0fb605941d7e692d3b5159360c diff --git a/php/utils.php b/php/utils.php index c69406165..8e27e5cbd 100644 --- a/php/utils.php +++ b/php/utils.php @@ -26,6 +26,10 @@ function bootstrap() { if ( !$has_autoload ) { include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; \cli\register_autoload(); + + include WP_CLI_ROOT . 'mustache/src/Mustache/Autoloader.php'; + \Mustache_Autoloader::register(); + register_autoload(); } From 69f62d17013d9e54f904c3e95a10bee980b48cf9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 19:51:28 +0200 Subject: [PATCH 1070/5359] transform scaffold raw php templates into mustache templates * move common code into helper method * make taxonomy template more consistent with cpt template * rename --label to --singular --- php/commands/scaffold.php | 186 +++++++++++++-------------- php/templates/post_type.php | 70 +++++----- php/templates/post_type_extended.php | 48 ++++--- php/templates/taxonomy.php | 75 +++++------ php/templates/taxonomy_extended.php | 8 +- 5 files changed, 184 insertions(+), 203 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 209351abe..ee23397d2 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -22,29 +22,11 @@ function __construct() { * * @alias cpt * - * @synopsis <slug> [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--slug=<slug>] [--feed=<feed>] [--pages=<pages>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--singular=<label>] [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function post_type( $args, $assoc_args ) { - global $wp_filesystem; - - // Set the args to variables with normal names to keep our sanity - $post_type = strtolower( $args[0] ); - - // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $post_type ); - $machine_name_plural = $this->pluralize( $post_type ); - - // If no label is given use the slug and prettify it as good as possible - if ( ! isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', strtolower( $post_type ) ); - $label_ucfirst = ucfirst( $label ); - $label_plural = $this->pluralize( $label ); - $label_plural_ucfirst = ucfirst( $label_plural ); - } - - // set up defaults and merge theme with assoc_args $defaults = array( - 'description' => "", + 'description' => '', 'public' => 'true', 'exclude_from_search' => 'false', 'show_ui' => 'true', @@ -57,45 +39,16 @@ function post_type( $args, $assoc_args ) { 'hierarchical' => 'false', 'supports' => "'title', 'editor'", 'has_archive' => 'true', - 'slug' => $machine_name_plural, - 'feeds' => 'true', - 'pages' => 'true', + 'rewrite' => 'true', 'query_var' => 'true', 'can_export' => 'true', 'textdomain' => '', - 'theme' => false, - 'plugin' => false, - 'raw' => false, ); - // Generate the variables from the defaults and associated arguments if they are set - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); - - if ( ! $raw ) { - include WP_CLI_ROOT . '/templates/post_type.php'; - $output = str_replace( "<?php", "", $output ); - include WP_CLI_ROOT . '/templates/post_type_extended.php'; - } else { - include WP_CLI_ROOT . '/templates/post_type.php'; - } - - if ( $theme || ! empty( $plugin ) ) { - // Write file to theme or given plugin - $assoc_args = array( - 'type' => 'post_type', - 'output' => $output, - 'theme' => $theme, - 'plugin' => $plugin, - 'machine_name' => $machine_name, - ); - $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->save_skeleton_output( $assoc_args ); - } else { - // STDOUT - echo $output; - } + $this->_scaffold( $args[0], $assoc_args, $defaults, array( + 'post_type.php', + 'post_type_extended.php' + ) ); } /** @@ -105,27 +58,9 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis <slug> [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--slug=<slug>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--singular=<label>] [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin>] [--raw] */ function taxonomy( $args, $assoc_args ) { - global $wp_filesystem; - - // Set the args to variables with normal names to keep our sanity - $taxonomy = strtolower( $args[0] ); - - // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $taxonomy ); - $machine_name_plural = $this->pluralize( $taxonomy ); - - // If no label is given use the slug and prettify it as good as possible - if ( ! isset( $assoc_args['label'] ) ) { - $label = preg_replace( '/_|-/', ' ', strtolower( $taxonomy ) ); - $label_ucfirst = ucfirst( $label ); - $label_plural = $this->pluralize( $label ); - $label_plural_ucfirst = ucfirst( $label_plural ); - } - - // Set up defaults and merge theme with assoc_args $defaults = array( 'public' => 'true', 'show_in_nav_menus' => 'true', @@ -134,7 +69,6 @@ function taxonomy( $args, $assoc_args ) { 'hierarchical' => 'false', 'rewrite' => 'true', 'query_var' => 'true', - 'slug' => $taxonomy, 'post_types' => 'post', 'textdomain' => '', 'theme' => false, @@ -142,24 +76,65 @@ function taxonomy( $args, $assoc_args ) { 'raw' => false, ); - // Generate the variables from the defaults and associated arguments if they are set - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + $this->_scaffold( $args[0], $assoc_args, $defaults, array( + 'taxonomy.php', + 'taxonomy_extended.php' + ) ); + } + + private function _scaffold( $slug, $assoc_args, $defaults, $templates ) { + global $wp_filesystem; + + $control_args = $this->extract_args( $assoc_args, array( + 'theme' => false, + 'plugin' => false, + 'raw' => false, + ) ); + + $vars = $this->extract_args( $assoc_args, $defaults ); + + $vars['slug'] = $slug; + + $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); + + // If no label is given use the slug and prettify it as good as possible + if ( isset( $assoc_args['singular'] ) ) { + $vars['label'] = $assoc_args['singular']; + } else { + $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $slug ) ); + } + + $vars['label_ucfirst'] = ucfirst( $vars['label'] ); + $vars['label_plural'] = $this->pluralize( $vars['label'] ); + $vars['label_plural_ucfirst'] = ucfirst( $vars['label_plural'] ); + + // We use the machine name for function declarations + $machine_name = preg_replace( '/-/', '_', $slug ); + $machine_name_plural = $this->pluralize( $slug ); + + list( $raw_template, $extended_template ) = $templates; - $textdomain = $this->get_textdomain( $textdomain, $theme, $plugin ); + $raw_output = $this->render( $raw_template, $vars ); + $raw_output = str_replace( "<?php", '', $raw_output ); + + extract( $control_args ); if ( ! $raw ) { - include WP_CLI_ROOT . '/templates/taxonomy.php'; - $output = str_replace( "<?php", "", $output ); - include WP_CLI_ROOT . '/templates/taxonomy_extended.php'; + $vars = array_merge( $vars, array( + 'machine_name' => $machine_name, + 'output' => $raw_output + ) ); + + $final_output = $this->render( $extended_template, $vars ); } else { - include WP_CLI_ROOT . '/templates/taxonomy.php'; + $final_output = $raw_output; } if ( $theme || ! empty( $plugin ) ) { - // Write file to theme or given plugin + // Write file to theme or plugin dir $assoc_args = array( - 'type' => 'taxonomy', - 'output' => $output, + 'type' => 'post_type', + 'output' => $final_output, 'theme' => $theme, 'plugin' => $plugin, 'machine_name' => $machine_name, @@ -168,7 +143,7 @@ function taxonomy( $args, $assoc_args ) { $this->save_skeleton_output( $assoc_args ); } else { // STDOUT - echo $output; + echo $final_output; } } @@ -229,16 +204,17 @@ private function save_skeleton_output( $assoc_args ) { * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. * Same goes for when plugin is being used. */ - private function get_textdomain( $textdomain, $theme, $plugin ) { - if ( empty( $textdomain ) && $theme ) { - $textdomain = strtolower( wp_get_theme()->template ); - } elseif ( empty( $textdomain ) && $plugin ) { - $textdomain = $plugin; - } elseif ( empty( $textdomain ) || gettype( $textdomain ) == 'boolean' ) { //This mean just a flag - $textdomain = 'YOUR-TEXTDOMAIN'; - } + private function get_textdomain( $textdomain, $args ) { + if ( strlen( $textdomain ) ) + return $textdomain; - return $textdomain; + if ( $args['theme'] ) + return strtolower( wp_get_theme()->template ); + + if ( $args['plugin'] && true !== $args['plugin'] ) + return $args['plugin']; + + return 'YOUR-TEXTDOMAIN'; } private function pluralize( $word ) { @@ -295,4 +271,26 @@ private function pluralize( $word ) { } return false; } + + protected function extract_args( $assoc_args, $defaults ) { + $out = array(); + + foreach ( $defaults as $key => $value ) { + $out[ $key ] = isset( $assoc_args[ $key ] ) + ? $assoc_args[ $key ] + : $value; + } + + return $out; + } + + private function render( $template, $data ) { + $scaffolds_dir = WP_CLI_ROOT . 'templates'; + + $template = file_get_contents( $scaffolds_dir . '/' . $template ); + + $m = new Mustache_Engine; + + return $m->render( $template, $data ); + } } diff --git a/php/templates/post_type.php b/php/templates/post_type.php index 21253f939..323460d4f 100644 --- a/php/templates/post_type.php +++ b/php/templates/post_type.php @@ -1,38 +1,34 @@ <?php -$output = "<?php - register_post_type( '{$post_type}', - array( - 'label' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'description' => __( '{$description}', '{$textdomain}' ), - 'public' => {$public}, - 'exclude_from_search' => {$exclude_from_search}, - 'show_ui' => {$show_ui}, - 'show_in_nav_menus' => {$show_in_nav_menus}, - 'show_in_menu' => {$show_in_menu}, - 'show_in_admin_bar' => {$show_in_admin_bar}, - 'menu_position' => {$menu_position}, - 'menu_icon' => {$menu_icon}, - 'capability_type' => '{$capability_type}', - 'hierarchical' => {$hierarchical}, - 'supports' => array( {$supports} ), - 'has_archive' => {$has_archive}, - 'rewrite' => array( 'slug' => '{$slug}', 'feeds' => {$feeds}, 'pages' => {$pages} ), - 'query_var' => {$query_var}, - 'can_export' => {$can_export}, - 'labels' => array( - 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), - 'add_new' => __( 'Add new {$label}', '{$textdomain}' ), - 'all_items' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'add_new_item' => __( 'Add new {$label}', '{$textdomain}' ), - 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), - 'new_item' => __( 'New {$label}', '{$textdomain}' ), - 'view_item' => __( 'View {$label}', '{$textdomain}' ), - 'search_items' => __( 'Search {$label_plural}', '{$textdomain}' ), - 'not_found' => __( 'No {$label_plural} found', '{$textdomain}' ), - 'not_found_in_trash' => __( 'No {$label_plural} found in trash', '{$textdomain}' ), - 'parent_item_colon' => __( 'Parent {$label}', '{$textdomain}' ), - 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - ), - ) - );"; \ No newline at end of file + register_post_type( '{{slug}}', array( + 'description' => __( '{{description}}', '{{textdomain}}' ), + 'public' => {{public}}, + 'exclude_from_search' => {{exclude_from_search}}, + 'show_ui' => {{show_ui}}, + 'show_in_nav_menus' => {{show_in_nav_menus}}, + 'show_in_menu' => {{show_in_menu}}, + 'show_in_admin_bar' => {{show_in_admin_bar}}, + 'menu_position' => {{menu_position}}, + 'menu_icon' => {{menu_icon}}, + 'capability_type' => '{{capability_type}}', + 'hierarchical' => {{hierarchical}}, + 'supports' => array( {{supports}} ), + 'has_archive' => {{has_archive}}, + 'rewrite' => {{rewrite}}, + 'query_var' => {{query_var}}, + 'can_export' => {{can_export}}, + 'labels' => array( + 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), + 'add_new' => __( 'Add new {{label}}', '{{textdomain}}' ), + 'all_items' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'add_new_item' => __( 'Add new {{label}}', '{{textdomain}}' ), + 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), + 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), + 'view_item' => __( 'View {{label}}', '{{textdomain}}' ), + 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), + 'not_found' => __( 'No {{label_plural}} found', '{{textdomain}}' ), + 'not_found_in_trash' => __( 'No {{label_plural}} found in trash', '{{textdomain}}' ), + 'parent_item_colon' => __( 'Parent {{label}}', '{{textdomain}}' ), + 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + ), + ) ); diff --git a/php/templates/post_type_extended.php b/php/templates/post_type_extended.php index 3d541d8d9..e4503f996 100755 --- a/php/templates/post_type_extended.php +++ b/php/templates/post_type_extended.php @@ -1,32 +1,30 @@ <?php -$output = "<?php -function {$machine_name}_init() { - {$output} +function {{machine_name}}_init() { + {{{output}}} } -add_action( 'init', '{$machine_name}_init' ); +add_action( 'init', '{{machine_name}}_init' ); -function {$machine_name}_updated_messages( \$messages ) { - global \$post, \$post_ID; +function {{machine_name}}_updated_messages( $messages ) { + global $post, $post_ID; - \$messages['{$post_type}'] = array( - 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{$label_ucfirst} updated. <a target=\"_blank\" href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 2 => __('Custom field updated.', '{$textdomain}'), - 3 => __('Custom field deleted.', '{$textdomain}'), - 4 => __('{$label_ucfirst} updated.', '{$textdomain}'), - /* translators: %s: date and time of the revision */ - 5 => isset(\$_GET['revision']) ? sprintf( __('{$label_ucfirst} restored to revision from %s', '{$textdomain}'), wp_post_revision_title( (int) \$_GET['revision'], false ) ) : false, - 6 => sprintf( __('{$label_ucfirst} published. <a href=\"%s\">View {$label}</a>', '{$textdomain}'), esc_url( get_permalink(\$post_ID) ) ), - 7 => __('{$label_ucfirst} saved.', '{$textdomain}'), - 8 => sprintf( __('{$label_ucfirst} submitted. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink(\$post_ID) ) ) ), - 9 => sprintf( __('{$label_ucfirst} scheduled for: <strong>%1\$s</strong>. <a target=\"_blank\" href=\"%2\$s\">Preview {$label}</a>', '{$textdomain}'), - // translators: Publish box date format, see http://php.net/date - date_i18n( __( 'M j, Y @ G:i' ), strtotime( \$post->post_date ) ), esc_url( get_permalink( \$post_ID ) ) ), - 10 => sprintf( __('{$label_ucfirst} draft updated. <a target=\"_blank\" href=\"%s\">Preview {$post_type}</a>', '{$textdomain}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( \$post_ID ) ) ) ), - ); + $messages['{{post_type}}'] = array( + 0 => '', // Unused. Messages start at index 1. + 1 => sprintf( __('{{label_ucfirst}} updated. <a target=\"_blank\" href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), + 2 => __('Custom field updated.', '{{textdomain}}'), + 3 => __('Custom field deleted.', '{{textdomain}}'), + 4 => __('{{label_ucfirst}} updated.', '{{textdomain}}'), + /* translators: %s: date and time of the revision */ + 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, + 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), + 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), + 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{post_type}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), + 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s\">Preview {{label}}</a>', '{{textdomain}}'), + // translators: Publish box date format, see http://php.net/date + date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ), + 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{post_type}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), + ); - return \$messages; + return $messages; } -add_filter( 'post_updated_messages', '{$machine_name}_updated_messages' );"; -?> \ No newline at end of file +add_filter( 'post_updated_messages', '{{machine_name}}_updated_messages' ); diff --git a/php/templates/taxonomy.php b/php/templates/taxonomy.php index e098f77f5..7c1003a51 100644 --- a/php/templates/taxonomy.php +++ b/php/templates/taxonomy.php @@ -1,43 +1,34 @@ <?php -$output = "<?php - \$labels = array( - 'name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - 'singular_name' => __( '{$label_ucfirst}', '{$textdomain}' ), - 'search_items' => __( 'Search {$taxonomy}', '{$textdomain}' ), - 'popular_items' => __( 'Popular {$taxonomy}', '{$textdomain}' ), - 'all_items' => __( 'All {$label_plural}', '{$textdomain}' ), - 'parent_item' => __( 'Parent {$label}', '{$textdomain}' ), - 'parent_item_colon' => __( 'Parent {$label}:', '{$textdomain}' ), - 'edit_item' => __( 'Edit {$label}', '{$textdomain}' ), - 'update_item' => __( 'Update {$label}', '{$textdomain}' ), - 'add_new_item' => __( 'New {$label}', '{$textdomain}' ), - 'new_item_name' => __( 'New {$label}', '{$textdomain}' ), - 'separate_items_with_commas' => __( '{$label_plural_ucfirst} seperated by comma', '{$textdomain}' ), - 'add_or_remove_items' => __( 'Add or remove {$label}', '{$textdomain}' ), - 'choose_from_most_used' => __( 'Choose from the most used {$label_plural}', '{$textdomain}' ), - 'menu_name' => __( '{$label_plural_ucfirst}', '{$textdomain}' ), - ); - - \$args = array( - 'labels' => \$labels, - 'public' => {$public}, - 'show_in_nav_menus' => {$show_in_nav_menus}, - 'show_ui' => {$show_ui}, - 'show_tagcloud' => {$show_tagcloud}, - 'hierarchical' => {$hierarchical}, - 'update_count_callback' => '_update_post_term_count', - 'rewrite' => {$rewrite}, - 'query_var' => {$query_var}, - 'capabilities' => array ( - 'manage_terms' => 'edit_posts', - 'edit_terms' => 'edit_posts', - 'delete_terms' => 'edit_posts', - 'assign_terms' => 'edit_posts' - ), - 'rewrite' => array( - 'slug' => '{$taxonomy}', - 'hierarchical' => {$hierarchical} - ), - ); - - register_taxonomy( '{$taxonomy}', array( '{$post_types}' ), \$args );"; \ No newline at end of file + register_taxonomy( '{{slug}}', array( '{{post_types}}' ), array( + 'public' => {{public}}, + 'show_in_nav_menus' => {{show_in_nav_menus}}, + 'show_ui' => {{show_ui}}, + 'show_tagcloud' => {{show_tagcloud}}, + 'hierarchical' => {{hierarchical}}, + 'update_count_callback' => '_update_post_term_count', + 'query_var' => {{query_var}}, + 'rewrite' => {{rewrite}}, + 'capabilities' => array ( + 'manage_terms' => 'edit_posts', + 'edit_terms' => 'edit_posts', + 'delete_terms' => 'edit_posts', + 'assign_terms' => 'edit_posts' + ), + 'labels' => array( + 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), + 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), + 'popular_items' => __( 'Popular {{label_plural}}', '{{textdomain}}' ), + 'all_items' => __( 'All {{label_plural}}', '{{textdomain}}' ), + 'parent_item' => __( 'Parent {{label}}', '{{textdomain}}' ), + 'parent_item_colon' => __( 'Parent {{label}}:', '{{textdomain}}' ), + 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), + 'update_item' => __( 'Update {{label}}', '{{textdomain}}' ), + 'add_new_item' => __( 'New {{label}}', '{{textdomain}}' ), + 'new_item_name' => __( 'New {{label}}', '{{textdomain}}' ), + 'separate_items_with_commas' => __( '{{label_plural_ucfirst}} separated by comma', '{{textdomain}}' ), + 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), + 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), + 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + ), + ) ); diff --git a/php/templates/taxonomy_extended.php b/php/templates/taxonomy_extended.php index d4015c73e..080556351 100755 --- a/php/templates/taxonomy_extended.php +++ b/php/templates/taxonomy_extended.php @@ -1,8 +1,6 @@ <?php -$output = "<?php - -function {$machine_name}_init() { - {$output} +function {{machine_name}}_init() { + {{{output}}} } -add_action( 'init', '{$machine_name}_init' );"; \ No newline at end of file +add_action( 'init', '{{machine_name}}_init' ); From f6136555c5b3824992e1c58a04b3ab2bc16c5af0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 21:06:34 +0200 Subject: [PATCH 1071/5359] replace {{post_type}} with {{slug}} --- php/templates/post_type_extended.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/templates/post_type_extended.php b/php/templates/post_type_extended.php index e4503f996..b7be67ec7 100755 --- a/php/templates/post_type_extended.php +++ b/php/templates/post_type_extended.php @@ -8,7 +8,7 @@ function {{machine_name}}_init() { function {{machine_name}}_updated_messages( $messages ) { global $post, $post_ID; - $messages['{{post_type}}'] = array( + $messages['{{slug}}'] = array( 0 => '', // Unused. Messages start at index 1. 1 => sprintf( __('{{label_ucfirst}} updated. <a target=\"_blank\" href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), 2 => __('Custom field updated.', '{{textdomain}}'), @@ -18,11 +18,11 @@ function {{machine_name}}_updated_messages( $messages ) { 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), - 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{post_type}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), + 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{slug}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s\">Preview {{label}}</a>', '{{textdomain}}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ), - 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{post_type}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), + 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{slug}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), ); return $messages; From ab0e03b0e7e9c21bfaa8af74a9b99cc58dcfe52f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 21:08:39 +0200 Subject: [PATCH 1072/5359] use {{label}} instead of {{slug}}, where appropriate --- php/templates/post_type_extended.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/templates/post_type_extended.php b/php/templates/post_type_extended.php index b7be67ec7..bb2c2bfc8 100755 --- a/php/templates/post_type_extended.php +++ b/php/templates/post_type_extended.php @@ -18,11 +18,11 @@ function {{machine_name}}_updated_messages( $messages ) { 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), - 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{slug}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), + 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s\">Preview {{label}}</a>', '{{textdomain}}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ), - 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{slug}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), + 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), ); return $messages; From a880c4e4e1aa06b60c0a09efeeca54ba98987010 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 31 Dec 2012 21:13:18 +0200 Subject: [PATCH 1073/5359] pass whole post to get_permalink() and cache the result --- php/templates/post_type_extended.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/php/templates/post_type_extended.php b/php/templates/post_type_extended.php index bb2c2bfc8..48cef1b3e 100755 --- a/php/templates/post_type_extended.php +++ b/php/templates/post_type_extended.php @@ -6,23 +6,25 @@ function {{machine_name}}_init() { add_action( 'init', '{{machine_name}}_init' ); function {{machine_name}}_updated_messages( $messages ) { - global $post, $post_ID; + global $post; + + $permalink = get_permalink( $post ); $messages['{{slug}}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{{label_ucfirst}} updated. <a target=\"_blank\" href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), + 1 => sprintf( __('{{label_ucfirst}} updated. <a target=\"_blank\" href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), 2 => __('Custom field updated.', '{{textdomain}}'), 3 => __('Custom field deleted.', '{{textdomain}}'), 4 => __('{{label_ucfirst}} updated.', '{{textdomain}}'), /* translators: %s: date and time of the revision */ 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, - 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( get_permalink($post_ID) ) ), + 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), - 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), + 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s\">Preview {{label}}</a>', '{{textdomain}}'), // translators: Publish box date format, see http://php.net/date - date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ), - 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), + date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( $permalink ) ), + 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), ); return $messages; From 5a7727f0a1600c2a630a6ff665f406e92d4d1945 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Jan 2013 00:12:56 +0000 Subject: [PATCH 1074/5359] Require the file based on when the file was actually committed to core. --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 30769553d..04b784a89 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -122,7 +122,7 @@ require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); -Utils\maybe_require( '3.5', ABSPATH . WPINC . '/class-wp-embed.php' ); +Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); require( ABSPATH . WPINC . '/class-http.php' ); From 6a7b36c640bc00713c9a3df8f5d9f6d88294d7e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 14:18:30 +0200 Subject: [PATCH 1075/5359] remove @maintainer and @subpackage tags --- php/commands/scaffold.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ee23397d2..e6d640fd1 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -1,13 +1,9 @@ <?php -WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); - /** - * Implement scaffold command + * Generate code for post types, taxonomies, etc. * * @package wp-cli - * @subpackage commands/internals - * @maintainer LinePress (http://www.linespress.org) */ class Scaffold_Command extends WP_CLI_Command { @@ -294,3 +290,6 @@ private function render( $template, $data ) { return $m->render( $template, $data ); } } + +WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); + From a8abbefb27b4496873f0b0c2147abfc7b7c09b1c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 14:28:32 +0200 Subject: [PATCH 1076/5359] first pass at `wp scaffold plugin` --- php/commands/scaffold.php | 35 +++++++++++++++++++++++++++++++++++ php/templates/plugin.php | 12 ++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 php/templates/plugin.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index e6d640fd1..52cb985c0 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -179,6 +179,33 @@ private function get_output_path( $assoc_args ) { return $path; } + /** + * Generate starter code for a plugin. + * + * @synopsis <slug> [--plugin_name=<title>] [--activate] + */ + function plugin( $args, $assoc_args ) { + $plugin_slug = $args[0]; + + $data = wp_parse_args( $assoc_args, array( + 'plugin_name' => ucfirst( $plugin_slug ), + 'textdomain' => $plugin_slug + ) ); + + $plugin_contents = $this->render( 'plugin.php', $data ); + + $plugin_path = WP_PLUGIN_DIR . "/$plugin_slug/$plugin_slug.php"; + + if ( ! $this->create_file( $plugin_path, $plugin_contents ) ) { + WP_CLI::error( "Error creating file: $plugin_path" ); + } + + WP_CLI::success( "Plugin scaffold created: $plugin_path" ); + + if ( isset( $assoc_args['activate'] ) ) + \WP_CLI\Utils\run_command( array( 'plugin', 'activate', $plugin_slug ) ); + } + private function save_skeleton_output( $assoc_args ) { global $wp_filesystem; @@ -196,6 +223,14 @@ private function save_skeleton_output( $assoc_args ) { } } + private function create_file( $filename, $contents ) { + global $wp_filesystem; + + $wp_filesystem->mkdir( dirname( $filename ) ); + + return $wp_filesystem->put_contents( $filename, $contents ); + } + /** * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. * Same goes for when plugin is being used. diff --git a/php/templates/plugin.php b/php/templates/plugin.php new file mode 100644 index 000000000..d992cd094 --- /dev/null +++ b/php/templates/plugin.php @@ -0,0 +1,12 @@ +<?php +/* +Plugin Name: {{plugin_name}} +Version: 0.1-alpha +Description: PLUGIN DESCRIPTION HERE +Author: YOUR NAME HERE +Author URI: YOUR SITE HERE +Plugin URI: PLUGIN SITE HERE +Text Domain: {{textdomain}} +Domain Path: /languages +*/ + From 16d7ed340381fb4e6bdc70ad708d2cbbd512bb12 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 14:46:05 +0200 Subject: [PATCH 1077/5359] use create_file() for cpt and tax scaffolds --- php/commands/scaffold.php | 78 +++++++++------------------------------ 1 file changed, 17 insertions(+), 61 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 52cb985c0..d5a9f6ed0 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -41,7 +41,7 @@ function post_type( $args, $assoc_args ) { 'textdomain' => '', ); - $this->_scaffold( $args[0], $assoc_args, $defaults, array( + $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( 'post_type.php', 'post_type_extended.php' ) ); @@ -72,13 +72,13 @@ function taxonomy( $args, $assoc_args ) { 'raw' => false, ); - $this->_scaffold( $args[0], $assoc_args, $defaults, array( + $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( 'taxonomy.php', 'taxonomy_extended.php' ) ); } - private function _scaffold( $slug, $assoc_args, $defaults, $templates ) { + private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) { global $wp_filesystem; $control_args = $this->extract_args( $assoc_args, array( @@ -113,9 +113,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $templates ) { $raw_output = $this->render( $raw_template, $vars ); $raw_output = str_replace( "<?php", '', $raw_output ); - extract( $control_args ); - - if ( ! $raw ) { + if ( ! $control_args['raw'] ) { $vars = array_merge( $vars, array( 'machine_name' => $machine_name, 'output' => $raw_output @@ -126,55 +124,30 @@ private function _scaffold( $slug, $assoc_args, $defaults, $templates ) { $final_output = $raw_output; } - if ( $theme || ! empty( $plugin ) ) { - // Write file to theme or plugin dir - $assoc_args = array( - 'type' => 'post_type', - 'output' => $final_output, - 'theme' => $theme, - 'plugin' => $plugin, - 'machine_name' => $machine_name, - ); - $assoc_args['path'] = $this->get_output_path( $assoc_args ); - $this->save_skeleton_output( $assoc_args ); + if ( $path = $this->get_output_path( $control_args, $subdir ) ) { + $filename = $path . $machine_name .'.php'; + + $this->create_file( $filename, $final_output ); + + WP_CLI::success( "Created $filename" ); } else { // STDOUT echo $final_output; } } - private function get_output_path( $assoc_args ) { - global $wp_filesystem; - + private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); - // Implements the --theme flag || --plugin=<plugin> if ( $theme ) { - //Here we assume you got a theme installed $path = TEMPLATEPATH; } elseif ( ! empty( $plugin ) ) { - $path = WP_PLUGIN_DIR . '/' . $plugin; //Faking recursive mkdir for down the line - $wp_filesystem->mkdir( WP_PLUGIN_DIR . '/' . $plugin ); //Faking recursive mkdir for down the line + $path = WP_PLUGIN_DIR . '/' . $plugin; } else { - // STDOUT return false; } - if ( $type === "post_type" ) { - $path .= '/post-types/'; - } elseif ( $type === "taxonomy" ) { - $path .= '/taxonomies/'; - } - - // If it doesn't exists create it - if ( ! $wp_filesystem->is_dir( $path ) ) { - $wp_filesystem->mkdir( $path ); - WP_CLI::success( "Created dir: {$path}" ); - } elseif ( $wp_filesystem->is_dir( $path ) ) { - WP_CLI::success( "Dir already exists: {$path}" ); - } else { - WP_CLI::error( "Couldn't create dir exists: {$path}" ); - } + $path .= $subdir; return $path; } @@ -196,9 +169,7 @@ function plugin( $args, $assoc_args ) { $plugin_path = WP_PLUGIN_DIR . "/$plugin_slug/$plugin_slug.php"; - if ( ! $this->create_file( $plugin_path, $plugin_contents ) ) { - WP_CLI::error( "Error creating file: $plugin_path" ); - } + $this->create_file( $plugin_path, $plugin_contents ); WP_CLI::success( "Plugin scaffold created: $plugin_path" ); @@ -206,29 +177,14 @@ function plugin( $args, $assoc_args ) { \WP_CLI\Utils\run_command( array( 'plugin', 'activate', $plugin_slug ) ); } - private function save_skeleton_output( $assoc_args ) { - global $wp_filesystem; - - extract( $assoc_args, EXTR_SKIP ); - - // Write to file - if ( $path ) { - $filename = $path . $machine_name .'.php'; - - if ( ! $wp_filesystem->put_contents( $filename, $output ) ) { - WP_CLI::error( "Error while saving file: {$filename}" ); - } else { - WP_CLI::success( "{$type} {$machine_name} created" ); - } - } - } - private function create_file( $filename, $contents ) { global $wp_filesystem; $wp_filesystem->mkdir( dirname( $filename ) ); - return $wp_filesystem->put_contents( $filename, $contents ); + if ( !$wp_filesystem->put_contents( $filename, $contents ) ) { + WP_CLI::error( "Error creating file: $filename" ); + } } /** From 11c74b7e8898265fb2fd8e2bcec146e280030005 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 14:52:31 +0200 Subject: [PATCH 1078/5359] add man page for `wp scaffold plugin` --- man-src/scaffold-plugin.txt | 9 +++++++++ man/scaffold-plugin.1 | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 man-src/scaffold-plugin.txt create mode 100644 man/scaffold-plugin.1 diff --git a/man-src/scaffold-plugin.txt b/man-src/scaffold-plugin.txt new file mode 100644 index 000000000..bea18ef97 --- /dev/null +++ b/man-src/scaffold-plugin.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--activate`: + + Activate the newly generated plugin. + +* `--plugin_name=<title>`: + + What to put in the 'Plugin Name:' header diff --git a/man/scaffold-plugin.1 b/man/scaffold-plugin.1 new file mode 100644 index 000000000..f91ec221e --- /dev/null +++ b/man/scaffold-plugin.1 @@ -0,0 +1,25 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-PLUGIN" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-plugin\fR \- Generate starter code for a plugin\. +. +.SH "SYNOPSIS" +wp scaffold plugin \fIslug\fR [\-\-plugin_name=\fItitle\fR] [\-\-activate] +. +.SH "OPTIONS" +. +.TP +\fB\-\-activate\fR: +. +.IP +Activate the newly generated plugin\. +. +.TP +\fB\-\-plugin_name=<title>\fR: +. +.IP +What to put in the \'Plugin Name:\' header + From 5fc65beb331c025024459cac31fb3723e5dcb06a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 14:55:03 +0200 Subject: [PATCH 1079/5359] always use the plugin slug for the textdomain --- php/commands/scaffold.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d5a9f6ed0..401c1a97c 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,9 +162,10 @@ function plugin( $args, $assoc_args ) { $data = wp_parse_args( $assoc_args, array( 'plugin_name' => ucfirst( $plugin_slug ), - 'textdomain' => $plugin_slug ) ); + $data['textdomain'] = $plugin_slug; + $plugin_contents = $this->render( 'plugin.php', $data ); $plugin_path = WP_PLUGIN_DIR . "/$plugin_slug/$plugin_slug.php"; From cd187c2278a09256be430b135dcac7484dde9da1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 22:31:20 +0200 Subject: [PATCH 1080/5359] update top-level command descriptions and move add_command() below the class definitions --- php/commands/blog.php | 10 +++++----- php/commands/cache.php | 6 +++--- php/commands/cap.php | 6 +++--- php/commands/comment.php | 6 +++--- php/commands/core.php | 7 ++++--- php/commands/db.php | 6 +++--- php/commands/eval-file.php | 4 ++-- php/commands/eval.php | 4 ++-- php/commands/export.php | 13 ++++--------- php/commands/help.php | 11 +++-------- php/commands/home.php | 10 ++-------- php/commands/option.php | 5 +++-- php/commands/plugin.php | 2 +- php/commands/post.php | 2 +- php/commands/rewrite.php | 10 ++++++++-- php/commands/search-replace.php | 6 ++++-- php/commands/shell.php | 6 +++--- php/commands/theme.php | 2 +- php/commands/transient.php | 5 +++-- php/commands/user.php | 2 +- 20 files changed, 59 insertions(+), 64 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index b73f1bd9b..7e3291435 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -1,11 +1,7 @@ <?php -if ( is_multisite() ) { - WP_CLI::add_command( 'blog', 'Blog_Command' ); -} - /** - * Implement core command + * Manage blogs in a multisite install. * * @package wp-cli * @subpackage commands/internals @@ -154,3 +150,7 @@ protected static function get_blog_id_by_slug( $slug ) { } } +if ( is_multisite() ) { + WP_CLI::add_command( 'blog', 'Blog_Command' ); +} + diff --git a/php/commands/cache.php b/php/commands/cache.php index 142c23419..314229596 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -1,9 +1,7 @@ <?php -WP_CLI::add_command( 'cache', 'Cache_Command' ); - /** - * Manage the WordPress object cache. + * Manage the object cache. * * @package wp-cli * @subpackage commands/internals @@ -219,3 +217,5 @@ public function type( $args, $assoc_args ) { } } +WP_CLI::add_command( 'cache', 'Cache_Command' ); + diff --git a/php/commands/cap.php b/php/commands/cap.php index f496acc70..29fe26462 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -1,9 +1,7 @@ <?php -WP_CLI::add_command( 'cap', 'Capabilities_Command' ); - /** - * Manage capabilities. + * Manage user capabilities. * * @package wp-cli * @subpackage commands/internals @@ -94,3 +92,5 @@ private static function persistence_check() { } } +WP_CLI::add_command( 'cap', 'Capabilities_Command' ); + diff --git a/php/commands/comment.php b/php/commands/comment.php index 0604b8e25..2db3c0a0e 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -1,9 +1,7 @@ <?php -WP_CLI::add_command( 'comment', 'Comment_Command' ); - /** - * Implement 'comment' command + * Manage comments. * * @package wp-cli * @subpackage commands/internals @@ -193,3 +191,5 @@ function last( $args = array(), $assoc_args = array() ) { } } +WP_CLI::add_command( 'comment', 'Comment_Command' ); + diff --git a/php/commands/core.php b/php/commands/core.php index 63894f4c0..86daef297 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1,9 +1,7 @@ <?php -WP_CLI::add_command('core', 'Core_Command'); - /** - * Implement core command + * Download, install, update and otherwise manage WordPress proper. * * @package wp-cli * @subpackage commands/internals @@ -290,3 +288,6 @@ function update_db() { WP_CLI::success( 'WordPress database upgraded successfully.' ); } } + +WP_CLI::add_command( 'core', 'Core_Command' ); + diff --git a/php/commands/db.php b/php/commands/db.php index e9bccf921..2d204d44d 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -1,9 +1,7 @@ <?php -WP_CLI::add_command( 'db', 'DB_Command' ); - /** - * Implement db command + * Perform basic database operations. * * @package wp-cli * @subpackage commands/internals @@ -187,3 +185,5 @@ private static function run( $assoc_args, $cmd ) { } } +WP_CLI::add_command( 'db', 'DB_Command' ); + diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 1887930d2..d5d2a4204 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -1,7 +1,5 @@ <?php -WP_CLI::add_command( 'eval-file', new EvalFile_Command ); - class EvalFile_Command extends WP_CLI_Command { /** @@ -20,3 +18,5 @@ public function __invoke( $args, $assoc_args ) { } } +WP_CLI::add_command( 'eval-file', new EvalFile_Command ); + diff --git a/php/commands/eval.php b/php/commands/eval.php index fe8ae5f17..131ca8455 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -1,7 +1,5 @@ <?php -WP_CLI::add_command( 'eval', new Eval_Command ); - class Eval_Command extends WP_CLI_Command { /** @@ -14,3 +12,5 @@ public function __invoke( $args, $assoc_args ) { } } +WP_CLI::add_command( 'eval', new Eval_Command ); + diff --git a/php/commands/export.php b/php/commands/export.php index 3ed26350e..8a08f3bf7 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -1,13 +1,5 @@ <?php -WP_CLI::add_command( 'export', new Export_Command ); - -/** - * Implement export command - * - * @package wp-cli - * @subpackage commands/internals - */ class Export_Command extends WP_CLI_Command { /** @@ -17,7 +9,7 @@ class Export_Command extends WP_CLI_Command { public $export_args = array(); /** - * Export posts to a WXR file. + * Export content to a WXR file. * * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] */ @@ -539,3 +531,6 @@ private function export_wp( $args = array() ) { WP_CLI::success( "All done with export" ); } } + +WP_CLI::add_command( 'export', new Export_Command ); + diff --git a/php/commands/help.php b/php/commands/help.php index 1d83ba159..bd1234a19 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -1,15 +1,7 @@ <?php -WP_CLI::add_command( 'help', new Help_Command ); - use \WP_CLI\Dispatcher\CommandContainer; -/** - * Implement help command - * - * @package wp-cli - * @subpackage commands/internals - */ class Help_Command extends WP_CLI_Command { /** @@ -47,3 +39,6 @@ private static function maybe_load_man_page( $args ) { } } } + +WP_CLI::add_command( 'help', new Help_Command ); + diff --git a/php/commands/home.php b/php/commands/home.php index 730ce8d2c..a5ca3e6d3 100644 --- a/php/commands/home.php +++ b/php/commands/home.php @@ -1,13 +1,5 @@ <?php -WP_CLI::add_command( 'home', new Home_Command ); - -/** - * Implement home command - * - * @package wp-cli - * @subpackage commands/internals - */ class Home_Command extends WP_CLI_Command { /** @@ -33,3 +25,5 @@ function __invoke() { } } +WP_CLI::add_command( 'home', new Home_Command ); + diff --git a/php/commands/option.php b/php/commands/option.php index d18f4a7b4..b5f63da42 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -1,7 +1,5 @@ <?php -WP_CLI::add_command('option', 'Option_Command'); - /** * Manage WordPress options. * @@ -73,3 +71,6 @@ public function delete( $args ) { } } } + +WP_CLI::add_command( 'option', 'Option_Command' ); + diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 047401d8f..b13366594 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -1,7 +1,7 @@ <?php /** - * Implement plugin command + * Manage plugins. * * @package wp-cli * @subpackage commands/internals diff --git a/php/commands/post.php b/php/commands/post.php index 49bc35e3d..e0a082e6c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -1,7 +1,7 @@ <?php /** - * Implement post command + * Manage posts. * * @package wp-cli * @subpackage commands/internals diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 67ca9313d..0709e9f0f 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -1,7 +1,10 @@ <?php -WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); - +/** + * Manage rewrite rules. + * + * @package wp-cli + */ class Rewrite_Command extends WP_CLI_Command { /** @@ -79,3 +82,6 @@ public function dump( $args, $assoc_args ) { } } + +WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); + diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 722d48d63..f46cc2790 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -1,8 +1,8 @@ <?php -WP_CLI::add_command( 'search-replace', new Search_Replace_Command ); - /** + * Search and replace strings in the database. + * * @package wp-cli */ class Search_Replace_Command extends WP_CLI_Command { @@ -118,3 +118,5 @@ private static function is_text_col( $type ) { } } +WP_CLI::add_command( 'search-replace', new Search_Replace_Command ); + diff --git a/php/commands/shell.php b/php/commands/shell.php index b3f75f262..c0e73760f 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -2,12 +2,10 @@ namespace WP_CLI\Commands; -\WP_CLI::add_command( 'shell', new Shell_Command ); - class Shell_Command extends \WP_CLI_Command { /** - * Open an interactive shell environment. + * Interactive PHP console. */ public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); @@ -82,3 +80,5 @@ private static function starts_with( $tokens, $line ) { } } +\WP_CLI::add_command( 'shell', new Shell_Command ); + diff --git a/php/commands/theme.php b/php/commands/theme.php index 8837f8c99..ca016ddcb 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -1,7 +1,7 @@ <?php /** - * Implement theme command + * Manage themes. * * @package wp-cli * @subpackage commands/internals diff --git a/php/commands/transient.php b/php/commands/transient.php index f21b93542..8c2ee6a5f 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -1,7 +1,5 @@ <?php -WP_CLI::add_command( 'transient', 'Transient_Command' ); - /** * Manage WordPress transients. * @@ -76,3 +74,6 @@ public function type() { WP_CLI::line( $message ); } } + +WP_CLI::add_command( 'transient', 'Transient_Command' ); + diff --git a/php/commands/user.php b/php/commands/user.php index fb69f14d4..fe878a65e 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -1,7 +1,7 @@ <?php /** - * Implement user command + * Manage users. * * @package wp-cli * @subpackage commands/internals From 42ff9afcbb3f30fdd23e2e0e9105c307edc95406 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 22:35:58 +0200 Subject: [PATCH 1081/5359] remove @subpackage commands/internals --- php/commands/blog.php | 1 - php/commands/cache.php | 1 - php/commands/cap.php | 1 - php/commands/comment.php | 1 - php/commands/core.php | 1 - php/commands/db.php | 1 - php/commands/option.php | 1 - php/commands/plugin.php | 1 - php/commands/post-meta.php | 1 - php/commands/post.php | 1 - php/commands/theme.php | 1 - php/commands/transient.php | 1 - php/commands/user-meta.php | 1 - php/commands/user.php | 1 - 14 files changed, 14 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 7e3291435..52b868538 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -4,7 +4,6 @@ * Manage blogs in a multisite install. * * @package wp-cli - * @subpackage commands/internals */ class Blog_Command extends WP_CLI_Command { diff --git a/php/commands/cache.php b/php/commands/cache.php index 314229596..00b93b254 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -4,7 +4,6 @@ * Manage the object cache. * * @package wp-cli - * @subpackage commands/internals */ class Cache_Command extends WP_CLI_Command { diff --git a/php/commands/cap.php b/php/commands/cap.php index 29fe26462..aea5a2f73 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -4,7 +4,6 @@ * Manage user capabilities. * * @package wp-cli - * @subpackage commands/internals */ class Capabilities_Command extends WP_CLI_Command { diff --git a/php/commands/comment.php b/php/commands/comment.php index 2db3c0a0e..dd5442cda 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -4,7 +4,6 @@ * Manage comments. * * @package wp-cli - * @subpackage commands/internals */ class Comment_Command extends WP_CLI_Command { diff --git a/php/commands/core.php b/php/commands/core.php index 86daef297..f3d70f48d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -4,7 +4,6 @@ * Download, install, update and otherwise manage WordPress proper. * * @package wp-cli - * @subpackage commands/internals */ class Core_Command extends WP_CLI_Command { diff --git a/php/commands/db.php b/php/commands/db.php index 2d204d44d..104516728 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -4,7 +4,6 @@ * Perform basic database operations. * * @package wp-cli - * @subpackage commands/internals */ class DB_Command extends WP_CLI_Command { diff --git a/php/commands/option.php b/php/commands/option.php index b5f63da42..525a89a36 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -4,7 +4,6 @@ * Manage WordPress options. * * @package wp-cli - * @subpackage commands/internals */ class Option_Command extends WP_CLI_Command { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b13366594..189dad344 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -4,7 +4,6 @@ * Manage plugins. * * @package wp-cli - * @subpackage commands/internals */ class Plugin_Command extends \WP_CLI\CommandWithUpgrade { diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php index a987ac4b3..08a1052f0 100644 --- a/php/commands/post-meta.php +++ b/php/commands/post-meta.php @@ -4,7 +4,6 @@ * Manage post custom fields. * * @package wp-cli - * @subpackage commands/internals */ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; diff --git a/php/commands/post.php b/php/commands/post.php index e0a082e6c..1e69d24b7 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -4,7 +4,6 @@ * Manage posts. * * @package wp-cli - * @subpackage commands/internals */ class Post_Command extends \WP_CLI\CommandWithDBObject { diff --git a/php/commands/theme.php b/php/commands/theme.php index ca016ddcb..236765801 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -4,7 +4,6 @@ * Manage themes. * * @package wp-cli - * @subpackage commands/internals */ class Theme_Command extends \WP_CLI\CommandWithUpgrade { diff --git a/php/commands/transient.php b/php/commands/transient.php index 8c2ee6a5f..c7dae5961 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -4,7 +4,6 @@ * Manage WordPress transients. * * @package wp-cli - * @subpackage commands/internals */ class Transient_Command extends WP_CLI_Command { diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 6fe4ed794..59b4b739f 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -4,7 +4,6 @@ * Manage user custom fields. * * @package wp-cli - * @subpackage commands/internals */ class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; diff --git a/php/commands/user.php b/php/commands/user.php index fe878a65e..c3cff0cd9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -4,7 +4,6 @@ * Manage users. * * @package wp-cli - * @subpackage commands/internals */ class User_Command extends \WP_CLI\CommandWithDBObject { From 10b35f3d34b8bf060f3b5267c90802e587ae9cfa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 18:56:53 +0200 Subject: [PATCH 1082/5359] replace --syn-list with --cmd-dump --- php/WP_CLI/Dispatcher/RootCommand.php | 10 +++++++- php/WP_CLI/Dispatcher/Subcommand.php | 8 ++++-- php/class-wp-cli.php | 37 +++++++++++++++++++-------- php/dispatcher.php | 1 + 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 080ad4cbc..0e721678c 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class RootCommand extends AbstractCommandContainer { +class RootCommand extends AbstractCommandContainer implements Documentable { function get_name() { return 'wp'; @@ -12,6 +12,14 @@ function get_parent() { return false; } + function get_shortdesc() { + return ''; + } + + function get_full_synopsis() { + return ''; + } + function show_usage() { \WP_CLI::line( 'Available commands:' ); diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 0432e7a83..e725199dd 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -23,11 +23,15 @@ function get_shortdesc() { function get_full_synopsis() { $full_name = implode( ' ', get_path( $this ) ); - $synopsis = $this->docparser->get_synopsis(); + $synopsis = $this->get_synopsis(); return "$full_name $synopsis"; } + function get_synopsis() { + return $this->docparser->get_synopsis(); + } + function invoke( $args, $assoc_args ) { $this->check_args( $args, $assoc_args ); @@ -43,7 +47,7 @@ function get_parent() { } protected function check_args( $args, $assoc_args ) { - $synopsis = $this->docparser->get_synopsis(); + $synopsis = $this->get_synopsis(); if ( !$synopsis ) return; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 34848dbc1..407d25557 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -261,7 +261,7 @@ private static function parse_args() { self::split_special( array( 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions', 'man', 'syn-list' + 'quiet', 'completions', 'man', 'cmd-dump' ) ); } @@ -381,16 +381,8 @@ static function after_wp_load() { exit; } - // Handle --syn-list parameter - if ( isset( self::$config['syn-list'] ) ) { - foreach ( self::$root->get_subcommands() as $command ) { - if ( $command instanceof Dispatcher\CommandContainer ) { - foreach ( $command->get_subcommands() as $subcommand ) - $subcommand->show_usage( '' ); - } else { - $command->show_usage( '' ); - } - } + if ( isset( self::$config['cmd-dump'] ) ) { + self::cmd_dump(); exit; } @@ -402,6 +394,29 @@ static function after_wp_load() { self::run_command(); } + private static function cmd_dump() { + $dump = self::command_to_array( self::$root ); + + echo json_encode( $dump['subcommands'] ); + } + + private static function command_to_array( $command ) { + $dump = array( + 'name' => $command->get_name(), + 'description' => $command->get_shortdesc(), + ); + + if ( $command instanceof Dispatcher\AtomicCommand ) { + $dump['synopsis'] = $command->get_synopsis(); + } else { + foreach ( Dispatcher\get_subcommands( $command ) as $subcommand ) { + $dump['subcommands'][] = self::command_to_array( $subcommand ); + } + } + + return $dump; + } + private static function run_command() { Utils\run_command( self::$arguments, self::$assoc_args ); } diff --git a/php/dispatcher.php b/php/dispatcher.php index 7b7907675..da4e1b0ff 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -31,6 +31,7 @@ function show_usage(); interface AtomicCommand { + function get_synopsis(); function invoke( $args, $assoc_args ); } From 853783999fd0ed66f925fac4f894b84554faa65e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 19:37:44 +0200 Subject: [PATCH 1083/5359] add external syn-list.php utility --- utils/syn-list.php | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 utils/syn-list.php diff --git a/utils/syn-list.php b/utils/syn-list.php new file mode 100644 index 000000000..5f7cf5cdc --- /dev/null +++ b/utils/syn-list.php @@ -0,0 +1,41 @@ +<?php +# Given a list of commands as JSON on STDIN, generates a list of synopses. +# +# Example usage: +# +# wp --cmd-dump | php /path/to/wp-cli/utils/syn-list.php + +function read_json() { + $input = ''; + + while ( false !== ( $line = fgets( STDIN ) ) ) { + $input .= $line; + } + + $json = json_decode( $input, true ); + if ( !$json ) { + echo "Invalid JSON."; + exit(1); + } + + return $json; +} + +function generate_synopsis( $command, $path ) { + $full_path = $path . ' ' . $command['name']; + + if ( !isset( $command['subcommands'] ) ) { + echo $full_path . ' ' . $command['synopsis'] . "\n"; + } else { + foreach ( $command['subcommands'] as $subcommand ) { + generate_synopsis( $subcommand, $full_path ); + } + } +} + +$commands = read_json(); + +foreach ( $commands as $command ) { + generate_synopsis( $command, 'wp' ); +} + From 4b1273a5ed695731ae84023e1a11b2b68ea7d7b7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 20:18:42 +0200 Subject: [PATCH 1084/5359] synopsis should always be a string --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 407d25557..a3097a153 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -407,7 +407,7 @@ private static function command_to_array( $command ) { ); if ( $command instanceof Dispatcher\AtomicCommand ) { - $dump['synopsis'] = $command->get_synopsis(); + $dump['synopsis'] = (string) $command->get_synopsis(); } else { foreach ( Dispatcher\get_subcommands( $command ) as $subcommand ) { $dump['subcommands'][] = self::command_to_array( $subcommand ); From b63b1638d20bf63b1aea117a902fefede50d8b1b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 21:44:57 +0200 Subject: [PATCH 1085/5359] it's actually easier if we pass the whole 'wp' command --- php/class-wp-cli.php | 2 +- utils/syn-list.php | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index a3097a153..085cb8fd1 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -397,7 +397,7 @@ static function after_wp_load() { private static function cmd_dump() { $dump = self::command_to_array( self::$root ); - echo json_encode( $dump['subcommands'] ); + echo json_encode( $dump ); } private static function command_to_array( $command ) { diff --git a/utils/syn-list.php b/utils/syn-list.php index 5f7cf5cdc..02e69b0a1 100644 --- a/utils/syn-list.php +++ b/utils/syn-list.php @@ -21,7 +21,7 @@ function read_json() { return $json; } -function generate_synopsis( $command, $path ) { +function generate_synopsis( $command, $path = '' ) { $full_path = $path . ' ' . $command['name']; if ( !isset( $command['subcommands'] ) ) { @@ -33,9 +33,5 @@ function generate_synopsis( $command, $path ) { } } -$commands = read_json(); - -foreach ( $commands as $command ) { - generate_synopsis( $command, 'wp' ); -} +generate_synopsis( read_json() ); From b8f9cf653c717832703cab025d7c476f6dcac7ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 21:49:30 +0200 Subject: [PATCH 1086/5359] move read_json() to separate file --- utils/syn-list.php | 16 +--------------- utils/utils.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 utils/utils.php diff --git a/utils/syn-list.php b/utils/syn-list.php index 02e69b0a1..4534d69c1 100644 --- a/utils/syn-list.php +++ b/utils/syn-list.php @@ -5,21 +5,7 @@ # # wp --cmd-dump | php /path/to/wp-cli/utils/syn-list.php -function read_json() { - $input = ''; - - while ( false !== ( $line = fgets( STDIN ) ) ) { - $input .= $line; - } - - $json = json_decode( $input, true ); - if ( !$json ) { - echo "Invalid JSON."; - exit(1); - } - - return $json; -} +include __DIR__ . '/utils.php'; function generate_synopsis( $command, $path = '' ) { $full_path = $path . ' ' . $command['name']; diff --git a/utils/utils.php b/utils/utils.php new file mode 100644 index 000000000..eda9c6e19 --- /dev/null +++ b/utils/utils.php @@ -0,0 +1,18 @@ +<?php + +function read_json() { + $input = ''; + + while ( false !== ( $line = fgets( STDIN ) ) ) { + $input .= $line; + } + + $json = json_decode( $input, true ); + if ( !$json ) { + echo "Invalid JSON."; + exit(1); + } + + return $json; +} + From e95d0a0c149a940c824db5d8b99e04098f6c730f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 22:00:28 +0200 Subject: [PATCH 1087/5359] add cmd-list.php utility --- utils/cmd-list.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 utils/cmd-list.php diff --git a/utils/cmd-list.php b/utils/cmd-list.php new file mode 100644 index 000000000..fe4b9e072 --- /dev/null +++ b/utils/cmd-list.php @@ -0,0 +1,23 @@ +<?php + +# Given a list of commands as JSON on STDIN, generates an HTML table with the +# top-level commands. +# +# Example usage: +# +# wp --cmd-dump | php /path/to/wp-cli/utils/cmd-list.php + +include __DIR__ . '/utils.php'; + +$wp = read_json(); + +foreach ( $wp['subcommands'] as $command ) { + echo <<<EOB + <tr> + <td><a href="https://github.com/wp-cli/wp-cli/blob/master/php/commands/{$command['name']}.php">{$command['name']}</a></td> + <td>{$command['description']}</td> + </tr> + +EOB; +} + From da3099096f14c9c13de5e9e0a928d0366d7e8d03 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 22:46:00 +0200 Subject: [PATCH 1088/5359] convert all top-level command descriptions to the imperative mood --- php/commands/eval-file.php | 2 +- php/commands/eval.php | 2 +- php/commands/home.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index d5d2a4204..8ee5b6e33 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -3,7 +3,7 @@ class EvalFile_Command extends WP_CLI_Command { /** - * Loads and executes a PHP file after loading WordPress. + * Load and execute a PHP file after loading WordPress. * * @synopsis <path> */ diff --git a/php/commands/eval.php b/php/commands/eval.php index 131ca8455..b8cd803cf 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -3,7 +3,7 @@ class Eval_Command extends WP_CLI_Command { /** - * Executes arbitrary PHP code after loading WordPress. + * Execute arbitrary PHP code after loading WordPress. * * @synopsis <php-code> */ diff --git a/php/commands/home.php b/php/commands/home.php index a5ca3e6d3..fbb3b2fdc 100644 --- a/php/commands/home.php +++ b/php/commands/home.php @@ -3,7 +3,7 @@ class Home_Command extends WP_CLI_Command { /** - * Opens the wp-cli homepage in your browser. + * Open the wp-cli homepage in your browser. */ function __invoke() { // The url for the wp-cli repository From 4996b66949204717ef889a9fb78574fef2c23f7c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 23:02:42 +0200 Subject: [PATCH 1089/5359] add 'internal' key and put it to use --- php/WP_CLI/Dispatcher/RootCommand.php | 11 ++++------- php/class-wp-cli.php | 1 + php/utils.php | 10 ++++++++++ utils/cmd-list.php | 3 +++ utils/syn-list.php | 3 +++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 0e721678c..e8ac4e532 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -92,19 +92,16 @@ protected function load_all_commands() { } protected function load_command( $command ) { - if ( !isset( $this->subcommands[$command] ) ) { - $path = WP_CLI_ROOT . "/commands/$command.php"; - - if ( is_readable( $path ) ) { + if ( !isset( $this->subcommands[ $command ] ) ) { + if ( $path = \WP_CLI\Utils\get_command_file( $command ) ) include $path; - } } - if ( !isset( $this->subcommands[$command] ) ) { + if ( !isset( $this->subcommands[ $command ] ) ) { return false; } - return $this->subcommands[$command]; + return $this->subcommands[ $command ]; } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 085cb8fd1..432eb9003 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -404,6 +404,7 @@ private static function command_to_array( $command ) { $dump = array( 'name' => $command->get_name(), 'description' => $command->get_shortdesc(), + 'internal' => (bool) Utils\get_command_file( $command->get_name() ) ); if ( $command instanceof Dispatcher\AtomicCommand ) { diff --git a/php/utils.php b/php/utils.php index 8e27e5cbd..bacf01020 100644 --- a/php/utils.php +++ b/php/utils.php @@ -124,6 +124,16 @@ function assoc_args_to_str( $assoc_args ) { return $str; } +function get_command_file( $command ) { + $path = WP_CLI_ROOT . "/commands/$command.php"; + + if ( !is_readable( $path ) ) { + return false; + } + + return $path; +} + /** * Run a given command. * diff --git a/utils/cmd-list.php b/utils/cmd-list.php index fe4b9e072..a24a65788 100644 --- a/utils/cmd-list.php +++ b/utils/cmd-list.php @@ -12,6 +12,9 @@ $wp = read_json(); foreach ( $wp['subcommands'] as $command ) { + if ( !$command['internal'] ) + continue; + echo <<<EOB <tr> <td><a href="https://github.com/wp-cli/wp-cli/blob/master/php/commands/{$command['name']}.php">{$command['name']}</a></td> diff --git a/utils/syn-list.php b/utils/syn-list.php index 4534d69c1..218511cc0 100644 --- a/utils/syn-list.php +++ b/utils/syn-list.php @@ -8,6 +8,9 @@ include __DIR__ . '/utils.php'; function generate_synopsis( $command, $path = '' ) { + if ( isset( $command['internal'] ) && !$command['internal'] ) + continue; + $full_path = $path . ' ' . $command['name']; if ( !isset( $command['subcommands'] ) ) { From 54aecec3da553741aeeeef5a1c04ebba02439797 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 23:03:41 +0200 Subject: [PATCH 1090/5359] remove intermediate value in cmd_dump() --- php/class-wp-cli.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 432eb9003..7ab423d2c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -395,9 +395,7 @@ static function after_wp_load() { } private static function cmd_dump() { - $dump = self::command_to_array( self::$root ); - - echo json_encode( $dump ); + echo json_encode( self::command_to_array( self::$root ) ); } private static function command_to_array( $command ) { From 4c8326bfc65d5dc796d08b9fc5b64f132aad5da9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Jan 2013 23:17:23 +0200 Subject: [PATCH 1091/5359] move non-wp-related code out of after_wp_load() --- php/class-wp-cli.php | 2 ++ php/wp-cli.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7ab423d2c..60a79659f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -372,7 +372,9 @@ static function after_wp_load() { if ( !defined( 'WP_INSTALLING' ) && isset( self::$config['url'] ) ) Utils\set_wp_query(); + } + static function run() { if ( isset( self::$config['require'] ) ) require self::$config['require']; diff --git a/php/wp-cli.php b/php/wp-cli.php index 57df1df42..0e28698e3 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -32,3 +32,5 @@ WP_CLI::after_wp_load(); +WP_CLI::run(); + From b1506d51b8dddfe397a3aea967e67385bd23fb6b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 00:04:37 +0200 Subject: [PATCH 1092/5359] re-generate man pages --- man/cache.1 | 2 +- man/cap.1 | 10 +++++----- man/db.1 | 34 +++++++++++++++++----------------- man/export.1 | 2 +- man/option.1 | 16 ++++++++-------- man/post-meta.1 | 8 ++++---- man/scaffold-post-type.1 | 2 +- man/scaffold-taxonomy.1 | 2 +- man/transient.1 | 12 ++++++------ man/user-meta.1 | 8 ++++---- 10 files changed, 48 insertions(+), 48 deletions(-) diff --git a/man/cache.1 b/man/cache.1 index a0031ba3b..19d4886d6 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -4,7 +4,7 @@ .TH "WP\-CACHE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-cache\fR \- Manage the WordPress object cache\. +\fBwp\-cache\fR \- Manage the object cache\. . .SH "SYNOPSIS" wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cap.1 b/man/cap.1 index c12904046..5dfefa654 100644 --- a/man/cap.1 +++ b/man/cap.1 @@ -4,7 +4,7 @@ .TH "WP\-CAP" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-cap\fR \- Manage capabilities\. +\fBwp\-cap\fR \- Manage user capabilities\. . .SH "SYNOPSIS" wp cap list \fIrole\fR @@ -18,16 +18,16 @@ wp cap remove \fIrole\fR \fIcap\fR\.\.\. .SH "SUBCOMMANDS" . .TP -\fBlist\fR: +\fBadd\fR: . .IP -List capabilities for a given role\. +Add capabilities to a given role\. . .TP -\fBadd\fR: +\fBlist\fR: . .IP -Add capabilities to a given role\. +List capabilities for a given role\. . .TP \fBremove\fR: diff --git a/man/db.1 b/man/db.1 index 7c16d0827..319076f6e 100644 --- a/man/db.1 +++ b/man/db.1 @@ -4,7 +4,7 @@ .TH "WP\-DB" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-db\fR \- Implement db command +\fBwp\-db\fR \- Perform basic database operations\. . .SH "SYNOPSIS" wp db create [\-\-str] @@ -36,40 +36,40 @@ wp db import [\fIfile\fR] [\-\-str] .SH "SUBCOMMANDS" . .TP -\fBcreate\fR: +\fBconnect\fR: . .IP -Create the database, as specified in wp\-config\.php +Open a mysql console using the WordPress credentials\. . .TP -\fBdrop\fR: +\fBcreate\fR: . .IP -Delete the database\. +Create the database, as specified in wp\-config\.php . .TP -\fBreset\fR: +\fBdrop\fR: . .IP -Remove all tables from the database\. +Delete the database\. . .TP -\fBoptimize\fR: +\fBexport\fR: . .IP -Optimize the database\. +Exports the database using mysqldump\. . .TP -\fBrepair\fR: +\fBimport\fR: . .IP -Repair the database\. +Import database from a file\. . .TP -\fBconnect\fR: +\fBoptimize\fR: . .IP -Open a mysql console using the WordPress credentials\. +Optimize the database\. . .TP \fBquery\fR: @@ -78,16 +78,16 @@ Open a mysql console using the WordPress credentials\. Execute a query against the database\. . .TP -\fBexport\fR: +\fBrepair\fR: . .IP -Exports the database using mysqldump\. +Repair the database\. . .TP -\fBimport\fR: +\fBreset\fR: . .IP -Import database from a file\. +Remove all tables from the database\. . .SH "OPTIONS" diff --git a/man/export.1 b/man/export.1 index 1e5e9b4fa..17d770ab3 100644 --- a/man/export.1 +++ b/man/export.1 @@ -4,7 +4,7 @@ .TH "WP\-EXPORT" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-export\fR \- Export posts to a WXR file\. +\fBwp\-export\fR \- Export content to a WXR file\. . .SH "SYNOPSIS" wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post\fI\fIin=\fRpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] diff --git a/man/option.1 b/man/option.1 index b22d66884..531d1c2c8 100644 --- a/man/option.1 +++ b/man/option.1 @@ -21,28 +21,28 @@ wp option delete \fIkey\fR .SH "SUBCOMMANDS" . .TP -\fBget\fR: +\fBadd\fR: . .IP -Get an option\. +Add an option\. . .TP -\fBadd\fR: +\fBdelete\fR: . .IP -Add an option\. +Delete an option\. . .TP -\fBupdate\fR: +\fBget\fR: . .IP -Update an option\. +Get an option\. . .TP -\fBdelete\fR: +\fBupdate\fR: . .IP -Delete an option\. +Update an option\. . .SH "OPTIONS" diff --git a/man/post-meta.1 b/man/post-meta.1 index c6cc6067e..3a2cd2040 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -21,10 +21,10 @@ wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR .SH "SUBCOMMANDS" . .TP -\fBget\fR: +\fBadd\fR: . .IP -Get meta field value\. +Add a meta field\. . .TP \fBdelete\fR: @@ -33,10 +33,10 @@ Get meta field value\. Delete a meta field\. . .TP -\fBadd\fR: +\fBget\fR: . .IP -Add a meta field\. +Get meta field value\. . .TP \fBupdate\fR: diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 index 0ecd3f15d..208d21cda 100644 --- a/man/scaffold-post-type.1 +++ b/man/scaffold-post-type.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. . .SH "SYNOPSIS" -wp scaffold post\-type \fIslug\fR [\-\-description=\fIdescription\fR] [\-\-public=\fIpublic\fR] [\-\-exclude_from_search=\fIexclude_from_search\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_in_menu=\fIshow_in_menu\fR] [\-\-show_in_admin_bar=\fIshow_in_admin_bar\fR] [\-\-menu_position=\fImenu_position\fR] [\-\-menu_icon=\fImenu_icon\fR] [\-\-capability_type=\fIcapability_type\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-supports=\fIsupports\fR] [\-\-has_archive=\fIhas_archive\fR] [\-\-slug=\fIslug\fR] [\-\-feed=\fIfeed\fR] [\-\-pages=\fIpages\fR] [\-\-query_var=\fIquery_var\fR] [\-\-can_export=\fIcan_export\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold post\-type \fIslug\fR [\-\-singular=\fIlabel\fR] [\-\-description=\fIdescription\fR] [\-\-public=\fIpublic\fR] [\-\-exclude_from_search=\fIexclude_from_search\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_in_menu=\fIshow_in_menu\fR] [\-\-show_in_admin_bar=\fIshow_in_admin_bar\fR] [\-\-menu_position=\fImenu_position\fR] [\-\-menu_icon=\fImenu_icon\fR] [\-\-capability_type=\fIcapability_type\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-supports=\fIsupports\fR] [\-\-has_archive=\fIhas_archive\fR] [\-\-query_var=\fIquery_var\fR] [\-\-can_export=\fIcan_export\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index 0b8290186..d6f65ef62 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. . .SH "SYNOPSIS" -wp scaffold taxonomy \fIslug\fR [\-\-public=\fIpublic\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_tagcloud=\fIshow_tagcloud\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-rewrite=\fIrewrite\fR] [\-\-query_var=\fIquery_var\fR] [\-\-slug=\fIslug\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-post_types=\fIpost_types\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold taxonomy \fIslug\fR [\-\-singular=\fIlabel\fR] [\-\-public=\fIpublic\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_tagcloud=\fIshow_tagcloud\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-rewrite=\fIrewrite\fR] [\-\-query_var=\fIquery_var\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-post_types=\fIpost_types\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . diff --git a/man/transient.1 b/man/transient.1 index d169ff381..6c267b439 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -21,22 +21,22 @@ wp transient type .SH "SUBCOMMANDS" . .TP -\fBget\fR: +\fBdelete\fR: . .IP -Get a transient value\. +Delete a transient value\. . .TP -\fBset\fR: +\fBget\fR: . .IP -Set a transient value\. \fIexpiration\fR is the time until expiration, in seconds\. +Get a transient value\. . .TP -\fBdelete\fR: +\fBset\fR: . .IP -Delete a transient value\. +Set a transient value\. \fIexpiration\fR is the time until expiration, in seconds\. . .TP \fBtype\fR: diff --git a/man/user-meta.1 b/man/user-meta.1 index 25719cdbc..b88a027f4 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -21,10 +21,10 @@ wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR .SH "SUBCOMMANDS" . .TP -\fBget\fR: +\fBadd\fR: . .IP -Get meta field value\. +Add a meta field\. . .TP \fBdelete\fR: @@ -33,10 +33,10 @@ Get meta field value\. Delete a meta field\. . .TP -\fBadd\fR: +\fBget\fR: . .IP -Add a meta field\. +Get meta field value\. . .TP \fBupdate\fR: From c53616eb2d7baee028e0c3eeeb178bff9322a474 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 00:16:23 +0200 Subject: [PATCH 1093/5359] use --cmd-dump in compare-cmd --- utils/compare-cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/compare-cmd b/utils/compare-cmd index 21f6bc9b5..744d512b8 100755 --- a/utils/compare-cmd +++ b/utils/compare-cmd @@ -7,15 +7,15 @@ if [ $# -lt 3 ]; then exit 1 fi -ver_a=$1 -ver_b=$2 wp_path=$3 -git checkout $ver_a -wp --path=$wp_path --syn-list > /tmp/wp-cli-a +get_syn_list() { + git checkout $1 + wp --path=$wp_path --cmd-dump | php $(dirname $0)/syn-list.php +} -git checkout $ver_b -wp --path=$wp_path --syn-list > /tmp/wp-cli-b +get_syn_list $1 > /tmp/wp-cli-a +get_syn_list $2 > /tmp/wp-cli-b diff /tmp/wp-cli-a /tmp/wp-cli-b > cmd.diff From 285d651dd2d3dec1a779cdec7e3c5b7d68c41939 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 10:15:32 +0200 Subject: [PATCH 1094/5359] remove site-related utilities (moved to site repo) --- utils/cmd-list.php | 26 -------------------------- utils/compare-cmd | 22 ---------------------- utils/syn-list.php | 26 -------------------------- utils/utils.php | 18 ------------------ 4 files changed, 92 deletions(-) delete mode 100644 utils/cmd-list.php delete mode 100755 utils/compare-cmd delete mode 100644 utils/syn-list.php delete mode 100644 utils/utils.php diff --git a/utils/cmd-list.php b/utils/cmd-list.php deleted file mode 100644 index a24a65788..000000000 --- a/utils/cmd-list.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -# Given a list of commands as JSON on STDIN, generates an HTML table with the -# top-level commands. -# -# Example usage: -# -# wp --cmd-dump | php /path/to/wp-cli/utils/cmd-list.php - -include __DIR__ . '/utils.php'; - -$wp = read_json(); - -foreach ( $wp['subcommands'] as $command ) { - if ( !$command['internal'] ) - continue; - - echo <<<EOB - <tr> - <td><a href="https://github.com/wp-cli/wp-cli/blob/master/php/commands/{$command['name']}.php">{$command['name']}</a></td> - <td>{$command['description']}</td> - </tr> - -EOB; -} - diff --git a/utils/compare-cmd b/utils/compare-cmd deleted file mode 100755 index 744d512b8..000000000 --- a/utils/compare-cmd +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# utility for comparing commands between two different wp-cli versions. - -if [ $# -lt 3 ]; then - echo 'usage: <version-a> <version-b> <wp-path>' - exit 1 -fi - -wp_path=$3 - -get_syn_list() { - git checkout $1 - wp --path=$wp_path --cmd-dump | php $(dirname $0)/syn-list.php -} - -get_syn_list $1 > /tmp/wp-cli-a -get_syn_list $2 > /tmp/wp-cli-b - -diff /tmp/wp-cli-a /tmp/wp-cli-b > cmd.diff - -echo 'Generated cmd.diff' diff --git a/utils/syn-list.php b/utils/syn-list.php deleted file mode 100644 index 218511cc0..000000000 --- a/utils/syn-list.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php -# Given a list of commands as JSON on STDIN, generates a list of synopses. -# -# Example usage: -# -# wp --cmd-dump | php /path/to/wp-cli/utils/syn-list.php - -include __DIR__ . '/utils.php'; - -function generate_synopsis( $command, $path = '' ) { - if ( isset( $command['internal'] ) && !$command['internal'] ) - continue; - - $full_path = $path . ' ' . $command['name']; - - if ( !isset( $command['subcommands'] ) ) { - echo $full_path . ' ' . $command['synopsis'] . "\n"; - } else { - foreach ( $command['subcommands'] as $subcommand ) { - generate_synopsis( $subcommand, $full_path ); - } - } -} - -generate_synopsis( read_json() ); - diff --git a/utils/utils.php b/utils/utils.php deleted file mode 100644 index eda9c6e19..000000000 --- a/utils/utils.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -function read_json() { - $input = ''; - - while ( false !== ( $line = fgets( STDIN ) ) ) { - $input .= $line; - } - - $json = json_decode( $input, true ); - if ( !$json ) { - echo "Invalid JSON."; - exit(1); - } - - return $json; -} - From ead705851091c7c2b576f94f24659d065fd8d9f3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 10:33:18 +0200 Subject: [PATCH 1095/5359] run --cmd-dump without needing WP files --- php/class-wp-cli.php | 12 ++++++------ php/commands/blog.php | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 60a79659f..930f837bf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -309,6 +309,12 @@ static function before_wp_load() { exit; } + // Handle --cmd-dump parameter + if ( isset( self::$config['cmd-dump'] ) ) { + self::cmd_dump(); + exit; + } + $_SERVER['DOCUMENT_ROOT'] = getcwd(); // Handle --path @@ -383,11 +389,6 @@ static function run() { exit; } - if ( isset( self::$config['cmd-dump'] ) ) { - self::cmd_dump(); - exit; - } - if ( isset( self::$config['completions'] ) ) { self::render_automcomplete(); exit; @@ -404,7 +405,6 @@ private static function command_to_array( $command ) { $dump = array( 'name' => $command->get_name(), 'description' => $command->get_shortdesc(), - 'internal' => (bool) Utils\get_command_file( $command->get_name() ) ); if ( $command instanceof Dispatcher\AtomicCommand ) { diff --git a/php/commands/blog.php b/php/commands/blog.php index 52b868538..92be6de20 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -149,7 +149,8 @@ protected static function get_blog_id_by_slug( $slug ) { } } -if ( is_multisite() ) { - WP_CLI::add_command( 'blog', 'Blog_Command' ); -} +if ( function_exists( 'is_multisite' ) && !is_multisite() ) + return; + +WP_CLI::add_command( 'blog', 'Blog_Command' ); From 1d06e0bd2cec69c3538eb0cded56ce02247dbeb8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 10:48:12 +0200 Subject: [PATCH 1096/5359] replace just '<?php', instead of ignoring the whole line. fixes #271 --- php/utils.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index bacf01020..f1f19de2a 100644 --- a/php/utils.php +++ b/php/utils.php @@ -261,12 +261,11 @@ function get_wp_config_code() { $lines_to_run = array(); foreach ( $wp_config_code as $line ) { - if ( 0 === strpos( $line, '<?php' ) ) - continue; - if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) continue; + $line = preg_replace( '|^\s*\<\?php\s*|', '', $line ); + $lines_to_run[] = str_replace( $old, $new, $line ); } From 16ee34bc3619fea769b4318209006296e326d009 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 2 Jan 2013 10:50:34 +0200 Subject: [PATCH 1097/5359] run preg_replace() only once, on the whole string. see #271 --- php/utils.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index f1f19de2a..2405f394b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -264,12 +264,10 @@ function get_wp_config_code() { if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) continue; - $line = preg_replace( '|^\s*\<\?php\s*|', '', $line ); - $lines_to_run[] = str_replace( $old, $new, $line ); } - return implode( "\n", $lines_to_run ); + return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); } /** From eb813fae9911eebbdce3ec0ca3a40d5f6c10a0e6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 Jan 2013 01:44:58 +0200 Subject: [PATCH 1098/5359] change template extensions from .php to .mustache, to avoid compatibility issues with pre-commit linters etc. --- php/commands/scaffold.php | 10 +++++----- php/templates/{plugin.php => plugin.mustache} | 0 php/templates/{post_type.php => post_type.mustache} | 0 ...t_type_extended.php => post_type_extended.mustache} | 0 php/templates/{taxonomy.php => taxonomy.mustache} | 0 ...axonomy_extended.php => taxonomy_extended.mustache} | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename php/templates/{plugin.php => plugin.mustache} (100%) rename php/templates/{post_type.php => post_type.mustache} (100%) rename php/templates/{post_type_extended.php => post_type_extended.mustache} (100%) rename php/templates/{taxonomy.php => taxonomy.mustache} (100%) rename php/templates/{taxonomy_extended.php => taxonomy_extended.mustache} (100%) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 401c1a97c..73584b000 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -42,8 +42,8 @@ function post_type( $args, $assoc_args ) { ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( - 'post_type.php', - 'post_type_extended.php' + 'post_type.mustache', + 'post_type_extended.mustache' ) ); } @@ -73,8 +73,8 @@ function taxonomy( $args, $assoc_args ) { ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( - 'taxonomy.php', - 'taxonomy_extended.php' + 'taxonomy.mustache', + 'taxonomy_extended.mustache' ) ); } @@ -166,7 +166,7 @@ function plugin( $args, $assoc_args ) { $data['textdomain'] = $plugin_slug; - $plugin_contents = $this->render( 'plugin.php', $data ); + $plugin_contents = $this->render( 'plugin.mustache', $data ); $plugin_path = WP_PLUGIN_DIR . "/$plugin_slug/$plugin_slug.php"; diff --git a/php/templates/plugin.php b/php/templates/plugin.mustache similarity index 100% rename from php/templates/plugin.php rename to php/templates/plugin.mustache diff --git a/php/templates/post_type.php b/php/templates/post_type.mustache similarity index 100% rename from php/templates/post_type.php rename to php/templates/post_type.mustache diff --git a/php/templates/post_type_extended.php b/php/templates/post_type_extended.mustache similarity index 100% rename from php/templates/post_type_extended.php rename to php/templates/post_type_extended.mustache diff --git a/php/templates/taxonomy.php b/php/templates/taxonomy.mustache similarity index 100% rename from php/templates/taxonomy.php rename to php/templates/taxonomy.mustache diff --git a/php/templates/taxonomy_extended.php b/php/templates/taxonomy_extended.mustache similarity index 100% rename from php/templates/taxonomy_extended.php rename to php/templates/taxonomy_extended.mustache From 546dd84c34062ba4b7b1296a5dae4266900087e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 Jan 2013 01:49:32 +0200 Subject: [PATCH 1099/5359] remove unused '<?php' from templates was only used to get syntax highlighting, when the templates ended in .php --- php/commands/scaffold.php | 1 - php/templates/post_type.mustache | 1 - php/templates/taxonomy.mustache | 1 - 3 files changed, 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 73584b000..d14567cdb 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -111,7 +111,6 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) list( $raw_template, $extended_template ) = $templates; $raw_output = $this->render( $raw_template, $vars ); - $raw_output = str_replace( "<?php", '', $raw_output ); if ( ! $control_args['raw'] ) { $vars = array_merge( $vars, array( diff --git a/php/templates/post_type.mustache b/php/templates/post_type.mustache index 323460d4f..00e9d652d 100644 --- a/php/templates/post_type.mustache +++ b/php/templates/post_type.mustache @@ -1,4 +1,3 @@ -<?php register_post_type( '{{slug}}', array( 'description' => __( '{{description}}', '{{textdomain}}' ), 'public' => {{public}}, diff --git a/php/templates/taxonomy.mustache b/php/templates/taxonomy.mustache index 7c1003a51..db2ba2e37 100644 --- a/php/templates/taxonomy.mustache +++ b/php/templates/taxonomy.mustache @@ -1,4 +1,3 @@ -<?php register_taxonomy( '{{slug}}', array( '{{post_types}}' ), array( 'public' => {{public}}, 'show_in_nav_menus' => {{show_in_nav_menus}}, From c479691ed04311a4d641ab0bdbb39d79ac5172f3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 3 Jan 2013 01:50:43 +0200 Subject: [PATCH 1100/5359] scaffold taxonomy: remove control args from defaults --- php/commands/scaffold.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d14567cdb..939ed05bc 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -67,9 +67,6 @@ function taxonomy( $args, $assoc_args ) { 'query_var' => 'true', 'post_types' => 'post', 'textdomain' => '', - 'theme' => false, - 'plugin' => false, - 'raw' => false, ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( From 2eba6a2107edb698db2d8a9ed32949d8121ef7ba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 15 Jan 2013 15:29:49 +0200 Subject: [PATCH 1101/5359] move run_command() back into the WP_CLI class --- php/class-wp-cli.php | 36 ++++++++++++++++++++++++++++++------ php/commands/scaffold.php | 2 +- php/utils.php | 24 ------------------------ 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 930f837bf..0ff541dbc 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -324,7 +324,7 @@ static function before_wp_load() { Utils\set_url( self::$config ); if ( array( 'core', 'download' ) == self::$arguments ) { - self::run_command(); + self::_run_command(); exit; } @@ -335,7 +335,7 @@ static function before_wp_load() { } if ( array( 'core', 'config' ) == self::$arguments ) { - self::run_command(); + self::_run_command(); exit; } @@ -347,7 +347,7 @@ static function before_wp_load() { if ( self::cmd_starts_with( array( 'db' ) ) ) { eval( Utils\get_wp_config_code() ); - self::run_command(); + self::_run_command(); exit; } @@ -394,7 +394,7 @@ static function run() { exit; } - self::run_command(); + self::_run_command(); } private static function cmd_dump() { @@ -418,8 +418,32 @@ private static function command_to_array( $command ) { return $dump; } - private static function run_command() { - Utils\run_command( self::$arguments, self::$assoc_args ); + private static function _run_command() { + self::run_command( self::$arguments, self::$assoc_args ); + } + + /** + * Run a given command. + * + * @param array + * @param array + */ + public static function run_command( $args, $assoc_args = array() ) { + $command = self::$root; + + while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { + $subcommand = $command->pre_invoke( $args ); + if ( !$subcommand ) + break; + + $command = $subcommand; + } + + if ( $command instanceof Dispatcher\CommandContainer ) { + $command->show_usage(); + } else { + $command->invoke( $args, $assoc_args ); + } } private static function show_info() { diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 939ed05bc..b5511feb2 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -171,7 +171,7 @@ function plugin( $args, $assoc_args ) { WP_CLI::success( "Plugin scaffold created: $plugin_path" ); if ( isset( $assoc_args['activate'] ) ) - \WP_CLI\Utils\run_command( array( 'plugin', 'activate', $plugin_slug ) ); + WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); } private function create_file( $filename, $contents ) { diff --git a/php/utils.php b/php/utils.php index 2405f394b..4c87eb908 100644 --- a/php/utils.php +++ b/php/utils.php @@ -134,30 +134,6 @@ function get_command_file( $command ) { return $path; } -/** - * Run a given command. - * - * @param array - * @param array - */ -function run_command( $args, $assoc_args = array() ) { - $command = \WP_CLI::$root; - - while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { - $subcommand = $command->pre_invoke( $args ); - if ( !$subcommand ) - break; - - $command = $subcommand; - } - - if ( $command instanceof Dispatcher\CommandContainer ) { - $command->show_usage(); - } else { - $command->invoke( $args, $assoc_args ); - } -} - function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $url = $assoc_args['url']; From 4db02be698fb47c4cd4eb10fe1d24b0fdab30257 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 19 Jan 2013 15:14:16 +0200 Subject: [PATCH 1102/5359] add 'color' config option. fixes #267 --- php/class-wp-cli.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0ff541dbc..d3729e97e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -103,7 +103,7 @@ static function out( $message, $handle = STDOUT ) { if ( WP_CLI_QUIET ) return; - fwrite( $handle, \cli\Colors::colorize( $message, ! \cli\Shell::isPiped() ) ); + fwrite( $handle, \cli\Colors::colorize( $message, self::$config['color'] ) ); } /** @@ -287,12 +287,15 @@ static function before_wp_load() { ); self::$config = Utils\load_config( array( - 'path', 'url', 'user', 'disabled_commands' + 'path', 'url', 'user', 'disabled_commands', 'color' ) ); if ( !isset( self::$config['disabled_commands'] ) ) self::$config['disabled_commands'] = array(); + if ( !isset( self::$config['colors'] ) ) + self::$config['colors'] = ! \cli\Shell::isPiped(); + self::parse_args(); define( 'WP_CLI_QUIET', isset( self::$config['quiet'] ) ); From 64f26b484c6fd14aaf8c6c2f92f7bac0d0738fd3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 19 Jan 2013 15:19:56 +0200 Subject: [PATCH 1103/5359] 'color', not 'colors'. see #267 --- php/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d3729e97e..4b07b295c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -293,8 +293,8 @@ static function before_wp_load() { if ( !isset( self::$config['disabled_commands'] ) ) self::$config['disabled_commands'] = array(); - if ( !isset( self::$config['colors'] ) ) - self::$config['colors'] = ! \cli\Shell::isPiped(); + if ( !isset( self::$config['color'] ) ) + self::$config['color'] = ! \cli\Shell::isPiped(); self::parse_args(); From 945a57c764969fdbe0d53e930ecec10e263f170a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 19 Jan 2013 15:45:52 +0200 Subject: [PATCH 1104/5359] add --config global parameter. fixes #272 --- php/WP_CLI/Dispatcher/RootCommand.php | 9 +++--- php/class-wp-cli.php | 21 ++++++++------ php/utils.php | 40 ++++++++++++++++++--------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index e8ac4e532..84c5a19db 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -35,10 +35,11 @@ function show_usage() { See 'wp help <command>' for more information on a specific command. Global parameters: ---user=<id|login> set the current user ---url=<url> set the current URL ---path=<path> set the current path to the WP install ---require=<path> load a certain file before running the command +--user=<id|login> set the WordPress user +--url=<url> set the URL +--path=<path> set the path to the WP install +--config=<path> set the path to the wp-cli config file +--require=<path> load a certain PHP file before running the command --quiet suppress informational messages --info print wp-cli information EOB diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4b07b295c..d4ae0b404 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -14,7 +14,7 @@ class WP_CLI { private static $man_dirs = array(); - private static $config; + private static $config_path, $config; private static $arguments, $assoc_args; @@ -258,11 +258,6 @@ private static function parse_args() { self::$arguments[1] = 'update-all'; unset( self::$assoc_args['all'] ); } - - self::split_special( array( - 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions', 'man', 'cmd-dump' - ) ); } private static function split_special( $special_keys ) { @@ -286,18 +281,25 @@ static function before_wp_load() { WP_CLI_ROOT . "../man-src/" ); - self::$config = Utils\load_config( array( + self::parse_args(); + + self::$config_path = Utils\get_config_path( self::$assoc_args ); + + self::$config = Utils\load_config( self::$config_path, array( 'path', 'url', 'user', 'disabled_commands', 'color' ) ); + self::split_special( array( + 'path', 'url', 'blog', 'user', 'require', + 'quiet', 'completions', 'man', 'cmd-dump' + ) ); + if ( !isset( self::$config['disabled_commands'] ) ) self::$config['disabled_commands'] = array(); if ( !isset( self::$config['color'] ) ) self::$config['color'] = ! \cli\Shell::isPiped(); - self::parse_args(); - define( 'WP_CLI_QUIET', isset( self::$config['quiet'] ) ); // Handle --version parameter @@ -456,6 +458,7 @@ private static function show_info() { WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "wp-cli config:\t" . self::$config_path ); WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); } diff --git a/php/utils.php b/php/utils.php index 4c87eb908..d6e3449a6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -51,25 +51,39 @@ function register_autoload() { } ); } -function load_config( $allowed_keys ) { - foreach ( array( 'wp-cli.local.yml', 'wp-cli.yml' ) as $fname ) { - $path = getcwd() . '/' . $fname; +function load_config( $path, $allowed_keys ) { + if ( !$path ) + return array(); - if ( file_exists( $path ) ) { - $config = spyc_load_file( $path ); + $config = spyc_load_file( $path ); - $sanitized_config = array(); + $sanitized_config = array(); - foreach ( $allowed_keys as $key ) { - if ( isset( $config[ $key ] ) ) - $sanitized_config[ $key ] = $config[ $key ]; - } + foreach ( $allowed_keys as $key ) { + if ( isset( $config[ $key ] ) ) + $sanitized_config[ $key ] = $config[ $key ]; + } - return $sanitized_config; - } + return $sanitized_config; +} + +function get_config_path( $assoc_args ) { + if ( isset( $assoc_args['config'] ) ) { + $paths = array( $assoc_args['config'] ); + unset( $assoc_args['config'] ); + } else { + $paths = array( + getcwd() . '/wp-cli.local.yml', + getcwd() . 'wp-cli.yml' + ); + } + + foreach ( $paths as $path ) { + if ( file_exists( $path ) ) + return $path; } - return array(); + return false; } /** From 27c17f3e3aabe7af53ecc6271bf07e3d0ecec496 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 19 Jan 2013 21:34:51 +0200 Subject: [PATCH 1105/5359] fix path to wp-cli.yml. see #267 --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index d6e3449a6..92a6062f3 100644 --- a/php/utils.php +++ b/php/utils.php @@ -74,7 +74,7 @@ function get_config_path( $assoc_args ) { } else { $paths = array( getcwd() . '/wp-cli.local.yml', - getcwd() . 'wp-cli.yml' + getcwd() . '/wp-cli.yml' ); } From 372c8f15f40664f41e5e6870c5cb6f4b71c78a24 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 19 Jan 2013 21:36:05 +0200 Subject: [PATCH 1106/5359] add --debug global param. fixes #177 --- php/WP_CLI/Dispatcher/RootCommand.php | 1 + php/class-wp-cli.php | 22 ++++++++++++++++++---- php/utils-wp.php | 9 +++++++++ php/wp-cli.php | 2 ++ php/wp-settings-cli.php | 8 ++++---- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 84c5a19db..a0712ca80 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -41,6 +41,7 @@ function show_usage() { --config=<path> set the path to the wp-cli config file --require=<path> load a certain PHP file before running the command --quiet suppress informational messages +--debug show all PHP errors --info print wp-cli information EOB ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d4ae0b404..d8e2c9dde 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -269,8 +269,14 @@ private static function split_special( $special_keys ) { } } - static function get_config() { - return self::$config; + static function get_config( $key = null ) { + if ( null === $key ) + return self::$config; + + if ( !isset( self::$config[ $key ] ) ) + return null; + + return self::$config[ $key ]; } static function before_wp_load() { @@ -286,12 +292,13 @@ static function before_wp_load() { self::$config_path = Utils\get_config_path( self::$assoc_args ); self::$config = Utils\load_config( self::$config_path, array( - 'path', 'url', 'user', 'disabled_commands', 'color' + 'path', 'url', 'user', 'debug', 'disabled_commands', 'color' ) ); self::split_special( array( 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'completions', 'man', 'cmd-dump' + 'quiet', 'debug', + 'completions', 'man', 'cmd-dump' ) ); if ( !isset( self::$config['disabled_commands'] ) ) @@ -376,6 +383,13 @@ private static function cmd_starts_with( $prefix ) { return $prefix == array_slice( self::$arguments, 0, count( $prefix ) ); } + static function after_wp_config_load() { + if ( isset( self::$config['debug'] ) ) { + if ( !defined( 'WP_DEBUG' ) ) + define( 'WP_DEBUG', true ); + } + } + static function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 01777c211..0fb19ff06 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -12,6 +12,15 @@ function wp_not_installed() { } } +function wp_debug_mode() { + if ( \WP_CLI::get_config( 'debug' ) ) { + error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT ); + ini_set( 'display_errors', true ); + } else { + \wp_debug_mode(); + } +} + function maybe_require( $since, $path ) { global $wp_version; diff --git a/php/wp-cli.php b/php/wp-cli.php index 0e28698e3..995c549f6 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -22,6 +22,8 @@ eval( \WP_CLI\Utils\get_wp_config_code() ); +WP_CLI::after_wp_config_load(); + require WP_CLI_ROOT . 'wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 04b784a89..7855768a5 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -39,8 +39,11 @@ // Start loading timer. timer_start(); +// Load WP-CLI utilities +require WP_CLI_ROOT . 'utils-wp.php'; + // Check if we're in WP_DEBUG mode. -wp_debug_mode(); +Utils\wp_debug_mode(); // Define WP_LANG_DIR if not set. wp_set_lang_dir(); @@ -80,9 +83,6 @@ if ( SHORTINIT ) return false; -// Load WP-CLI utilities -require WP_CLI_ROOT . 'utils-wp.php'; - // Load the L10n library. require_once( ABSPATH . WPINC . '/l10n.php' ); From c1e9a983c443e2d73285ce0fe6d74af2437878b1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 06:05:39 +0200 Subject: [PATCH 1107/5359] merge back run() method into after_wp_load() not needed and avoids confusion with run_command() --- php/class-wp-cli.php | 2 -- php/wp-cli.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d8e2c9dde..a4b8c266a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -397,9 +397,7 @@ static function after_wp_load() { if ( !defined( 'WP_INSTALLING' ) && isset( self::$config['url'] ) ) Utils\set_wp_query(); - } - static function run() { if ( isset( self::$config['require'] ) ) require self::$config['require']; diff --git a/php/wp-cli.php b/php/wp-cli.php index 995c549f6..5799cf04a 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -34,5 +34,3 @@ WP_CLI::after_wp_load(); -WP_CLI::run(); - From d3be4048c2871717e887383ae5ffbd4fdc7070b4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 18:53:28 +0200 Subject: [PATCH 1108/5359] replace WP_ROOT with ABSPATH --- php/class-wp-cli.php | 2 +- php/commands/core.php | 4 ++-- php/utils.php | 16 ++++++++-------- php/wp-cli.php | 2 -- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index a4b8c266a..e8e97001a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -340,7 +340,7 @@ static function before_wp_load() { exit; } - if ( !is_readable( WP_ROOT . 'wp-load.php' ) ) { + if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { WP_CLI::error( "This does not seem to be a WordPress install.", false ); WP_CLI::line( "Pass --path=`path/to/wordpress` or run `wp core download`." ); exit(1); diff --git a/php/commands/core.php b/php/commands/core.php index f3d70f48d..3b442f5df 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -13,7 +13,7 @@ class Core_Command extends WP_CLI_Command { * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] */ public function download( $args, $assoc_args ) { - if ( is_readable( WP_ROOT . 'wp-load.php' ) ) + if ( is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( isset( $assoc_args['path'] ) ) @@ -55,7 +55,7 @@ public function config( $args, $assoc_args ) { $_GET['step'] = 2; if ( WP_CLI_QUIET ) ob_start(); - require WP_ROOT . '/wp-admin/setup-config.php'; + require ABSPATH . '/wp-admin/setup-config.php'; if ( WP_CLI_QUIET ) ob_end_clean(); } diff --git a/php/utils.php b/php/utils.php index 92a6062f3..974b81c2b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -158,10 +158,10 @@ function set_url( $assoc_args ) { if ( true === $url ) { \WP_CLI::line( 'usage: wp --blog=example.com' ); } - } elseif ( is_readable( WP_ROOT . 'wp-cli-blog' ) ) { + } elseif ( is_readable( ABSPATH . 'wp-cli-blog' ) ) { \WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); - $url = trim( file_get_contents( WP_ROOT . 'wp-cli-blog' ) ); + $url = trim( file_get_contents( ABSPATH . 'wp-cli-blog' ) ); } elseif ( $wp_config_path = locate_wp_config() ) { // Try to find the blog parameter in the wp-config file $wp_config_file = file_get_contents( $wp_config_path ); @@ -214,18 +214,18 @@ function set_url_params( $url ) { function set_wp_root( $config ) { if ( !empty( $config['path'] ) ) { - define( 'WP_ROOT', rtrim( $config['path'], '/' ) . '/' ); + define( 'ABSPATH', rtrim( $config['path'], '/' ) . '/' ); } else { - define( 'WP_ROOT', getcwd() . '/' ); + define( 'ABSPATH', getcwd() . '/' ); } } function locate_wp_config() { - if ( file_exists( WP_ROOT . 'wp-config.php' ) ) - return WP_ROOT . 'wp-config.php'; + if ( file_exists( ABSPATH . 'wp-config.php' ) ) + return ABSPATH . 'wp-config.php'; - if ( file_exists( WP_ROOT . '/../wp-config.php' ) && ! file_exists( WP_ROOT . '/../wp-settings.php' ) ) - return WP_ROOT . '/../wp-config.php'; + if ( file_exists( ABSPATH . '/../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) + return ABSPATH . '/../wp-config.php'; return false; } diff --git a/php/wp-cli.php b/php/wp-cli.php index 5799cf04a..d9b16b3bd 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -18,8 +18,6 @@ WP_CLI::before_wp_load(); // Load WordPress, in the global scope -define( 'ABSPATH', WP_ROOT ); - eval( \WP_CLI\Utils\get_wp_config_code() ); WP_CLI::after_wp_config_load(); From d921490e71c185965d61e9911d802fc71fb9acc1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 06:03:34 +0200 Subject: [PATCH 1109/5359] add config spec --- php/class-wp-cli.php | 27 +++++----------- php/config-spec.php | 74 ++++++++++++++++++++++++++++++++++++++++++++ php/utils.php | 48 ++++++++++++++++++++++------ 3 files changed, 120 insertions(+), 29 deletions(-) create mode 100644 php/config-spec.php diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e8e97001a..6bc586414 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -260,15 +260,6 @@ private static function parse_args() { } } - private static function split_special( $special_keys ) { - foreach ( $special_keys as $key ) { - if ( isset( self::$assoc_args[ $key ] ) ) { - self::$config[ $key ] = self::$assoc_args[ $key ]; - unset( self::$assoc_args[ $key ] ); - } - } - } - static function get_config( $key = null ) { if ( null === $key ) return self::$config; @@ -289,17 +280,13 @@ static function before_wp_load() { self::parse_args(); + $config_spec = Utils\get_config_spec(); + self::$config_path = Utils\get_config_path( self::$assoc_args ); - self::$config = Utils\load_config( self::$config_path, array( - 'path', 'url', 'user', 'debug', 'disabled_commands', 'color' - ) ); + self::$config = Utils\load_config( self::$config_path, $config_spec ); - self::split_special( array( - 'path', 'url', 'blog', 'user', 'require', - 'quiet', 'debug', - 'completions', 'man', 'cmd-dump' - ) ); + Utils\split_special( self::$assoc_args, self::$config, $config_spec ); if ( !isset( self::$config['disabled_commands'] ) ) self::$config['disabled_commands'] = array(); @@ -322,7 +309,7 @@ static function before_wp_load() { } // Handle --cmd-dump parameter - if ( isset( self::$config['cmd-dump'] ) ) { + if ( isset( self::$assoc_args['cmd-dump'] ) ) { self::cmd_dump(); exit; } @@ -401,12 +388,12 @@ static function after_wp_load() { if ( isset( self::$config['require'] ) ) require self::$config['require']; - if ( isset( self::$config['man'] ) ) { + if ( isset( self::$assoc_args['man'] ) ) { self::generate_man( self::$arguments ); exit; } - if ( isset( self::$config['completions'] ) ) { + if ( isset( self::$assoc_args['completions'] ) ) { self::render_automcomplete(); exit; } diff --git a/php/config-spec.php b/php/config-spec.php new file mode 100644 index 000000000..885ffeee0 --- /dev/null +++ b/php/config-spec.php @@ -0,0 +1,74 @@ +<?php + +return array( + 'path' => array( + 'runtime' => true, + 'file' => true, + 'default' => null, + 'desc' => 'Path to the WordPress files', + 'synopsis' => '<path>' + ), + + 'url' => array( + 'runtime' => true, + 'file' => true, + 'default' => null, + 'desc' => 'Pretend request came from given URL', + 'synopsis' => '<url>' + ), + 'blog' => array( + 'deprecated' => 'Use --url instead', + 'runtime' => true, + 'file' => false, + 'default' => null, + 'synopsis' => '<url>', + ), + + 'user' => array( + 'runtime' => true, + 'file' => true, + 'default' => null, + 'desc' => 'Set the WordPress user', + 'synopsis' => '<id|login>' + ), + + 'require' => array( + 'runtime' => true, + 'file' => true, + 'default' => null, + 'desc' => 'Load given PHP file before running the command', + 'synopsis' => '<path>' + ), + + 'disabled_commands' => array( + 'runtime' => false, + 'file' => true, + 'default' => array(), + 'desc' => '(Sub)commands to disable', + ), + + 'color' => array( + 'runtime' => true, + 'file' => true, + 'default' => false, + 'desc' => 'Show all PHP errors.', + 'synopsis' => '<bool>', + ), + + 'debug' => array( + 'runtime' => true, + 'file' => true, + 'default' => false, + 'desc' => 'Show all PHP errors.', + 'synopsis' => '', + ), + + 'quiet' => array( + 'runtime' => true, + 'file' => true, + 'default' => false, + 'desc' => 'Show all PHP errors.', + 'synopsis' => '<bool>', + ), +); + diff --git a/php/utils.php b/php/utils.php index 974b81c2b..88a49f4c9 100644 --- a/php/utils.php +++ b/php/utils.php @@ -51,20 +51,25 @@ function register_autoload() { } ); } -function load_config( $path, $allowed_keys ) { - if ( !$path ) - return array(); +function get_config_spec() { + static $spec; - $config = spyc_load_file( $path ); + if ( !$spec ) { + $spec = include __DIR__ . '/config-spec.php'; - $sanitized_config = array(); + $defaults = array( + 'runtime' => false, + 'file' => false, + 'synopsis' => '', + 'default' => null, + ); - foreach ( $allowed_keys as $key ) { - if ( isset( $config[ $key ] ) ) - $sanitized_config[ $key ] = $config[ $key ]; + foreach ( $spec as &$option ) { + $option = array_merge( $defaults, $option ); + } } - return $sanitized_config; + return $spec; } function get_config_path( $assoc_args ) { @@ -86,6 +91,31 @@ function get_config_path( $assoc_args ) { return false; } +function load_config( $path, $spec ) { + if ( !$path ) + return array(); + + $config = spyc_load_file( $path ); + + $sanitized_config = array(); + + foreach ( $spec as $key => $details ) { + if ( $details['file'] && isset( $config[ $key ] ) ) + $sanitized_config[ $key ] = $config[ $key ]; + } + + return $sanitized_config; +} + +function split_special( &$assoc_args, &$config, $spec ) { + foreach ( $spec as $key => $details ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } +} + /** * Splits $argv into positional and associative arguments. * From 3bac46f3e48fc793fc9e8bfdd16683691f9bdecf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 18:30:50 +0200 Subject: [PATCH 1110/5359] add tests for --quiet flag and don't suppress output on fatal error --- php/class-wp-cli.php | 10 ++-------- tests/spec-flags.php | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 tests/spec-flags.php diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 6bc586414..91405b4a8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -124,8 +124,8 @@ static function line( $message = '' ) { static function error( $message, $exit = true ) { if ( !isset( self::$config['completions'] ) ) { $label = 'Error'; - $msg = '%R' . $label . ': %n' . self::error_to_string( $message ); - self::out( $msg . "\n", STDERR ); + $msg = '%R' . $label . ': %n' . self::error_to_string( $message ) . "\n"; + fwrite( STDERR, \cli\Colors::colorize( $msg, self::$config['color'] ) ); } if ( $exit ) @@ -139,9 +139,6 @@ static function error( $message, $exit = true ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - if ( WP_CLI_QUIET ) - return; - self::line( '%G' . $label . ': %n' . $message ); } @@ -152,9 +149,6 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - if ( WP_CLI_QUIET ) - return; - $msg = '%C' . $label . ': %n' . self::error_to_string( $message ); self::out( $msg . "\n", STDERR ); } diff --git a/tests/spec-flags.php b/tests/spec-flags.php new file mode 100644 index 000000000..6ca84276b --- /dev/null +++ b/tests/spec-flags.php @@ -0,0 +1,24 @@ +<?php + +class FlagsSpec extends WP_CLI_Spec { + + /** @scenario */ + public function quietRun() { + $this + ->given( 'empty dir' ) + ->and( 'wp install' ) + + ->when( 'invoking', '' ) + ->then( 'return code should be', 0 ) + ->and( 'should have output' ) + + ->when( 'invoking', '--quiet' ) + ->then( 'return code should be', 0 ) + ->and( 'output should be', '' ) + + ->when( 'invoking', 'wp non-existing-command --quiet' ) + ->then( 'return code should be', 1 ) + ->and( 'should have output' ); + } +} + From e95fae9d35193bbaffcc3d3d6617744cd1e70c99 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 18:35:44 +0200 Subject: [PATCH 1111/5359] replace WP_CLI_QUIET with WP_CLI::get_config('quiet') --- php/class-wp-cli.php | 4 +--- php/commands/core.php | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 91405b4a8..61f1cb6c7 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -100,7 +100,7 @@ static function get_man_dirs() { * @param string $message */ static function out( $message, $handle = STDOUT ) { - if ( WP_CLI_QUIET ) + if ( self::get_config('quiet') ) return; fwrite( $handle, \cli\Colors::colorize( $message, self::$config['color'] ) ); @@ -288,8 +288,6 @@ static function before_wp_load() { if ( !isset( self::$config['color'] ) ) self::$config['color'] = ! \cli\Shell::isPiped(); - define( 'WP_CLI_QUIET', isset( self::$config['quiet'] ) ); - // Handle --version parameter if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { self::line( 'wp-cli ' . WP_CLI_VERSION ); diff --git a/php/commands/core.php b/php/commands/core.php index 3b442f5df..ac9600ebf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -34,7 +34,9 @@ public function download( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - WP_CLI::launch( 'curl -f' . (WP_CLI_QUIET ? ' --silent ' : ' ') . escapeshellarg( $download_url ) . ' | tar xz' ); + $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; + + WP_CLI::launch( 'curl -f' . $silent . escapeshellarg( $download_url ) . ' | tar xz' ); WP_CLI::launch( 'mv wordpress/* . && rm -rf wordpress' ); WP_CLI::success( 'WordPress downloaded.' ); @@ -54,9 +56,9 @@ public function config( $args, $assoc_args ) { $_GET['step'] = 2; - if ( WP_CLI_QUIET ) ob_start(); + if ( WP_CLI::get_config('quiet') ) ob_start(); require ABSPATH . '/wp-admin/setup-config.php'; - if ( WP_CLI_QUIET ) ob_end_clean(); + if ( WP_CLI::get_config('quiet') ) ob_end_clean(); } /** From 7db452324528def6086473b9587e33dc5209153a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 20 Jan 2013 19:08:39 +0200 Subject: [PATCH 1112/5359] make use of defaults --- php/class-wp-cli.php | 9 ++++----- php/config-spec.php | 2 +- php/utils.php | 10 ++++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 61f1cb6c7..4b0f68a9a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -258,8 +258,10 @@ static function get_config( $key = null ) { if ( null === $key ) return self::$config; - if ( !isset( self::$config[ $key ] ) ) + if ( !isset( self::$config[ $key ] ) ) { + self::warning( "Unknown config option '$key'." ); return null; + } return self::$config[ $key ]; } @@ -282,10 +284,7 @@ static function before_wp_load() { Utils\split_special( self::$assoc_args, self::$config, $config_spec ); - if ( !isset( self::$config['disabled_commands'] ) ) - self::$config['disabled_commands'] = array(); - - if ( !isset( self::$config['color'] ) ) + if ( 'auto' == self::$config['color'] ) self::$config['color'] = ! \cli\Shell::isPiped(); // Handle --version parameter diff --git a/php/config-spec.php b/php/config-spec.php index 885ffeee0..07c3aa130 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -50,7 +50,7 @@ 'color' => array( 'runtime' => true, 'file' => true, - 'default' => false, + 'default' => 'auto', 'desc' => 'Show all PHP errors.', 'synopsis' => '<bool>', ), diff --git a/php/utils.php b/php/utils.php index 88a49f4c9..3145e405d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -92,16 +92,18 @@ function get_config_path( $assoc_args ) { } function load_config( $path, $spec ) { - if ( !$path ) - return array(); - - $config = spyc_load_file( $path ); + if ( $path ) + $config = spyc_load_file( $path ); + else + $config = array(); $sanitized_config = array(); foreach ( $spec as $key => $details ) { if ( $details['file'] && isset( $config[ $key ] ) ) $sanitized_config[ $key ] = $config[ $key ]; + else + $sanitized_config[ $key ] = $details['default']; } return $sanitized_config; From 1505e0d97eaa969e79748b441fff45efffcb8dda Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Jan 2013 22:47:19 +0200 Subject: [PATCH 1113/5359] move special args handling to separate class --- php/WP_CLI/InternalAssoc.php | 73 ++++++++++++++++++++++++++++++++++++ php/class-wp-cli.php | 72 +++++------------------------------ 2 files changed, 82 insertions(+), 63 deletions(-) create mode 100644 php/WP_CLI/InternalAssoc.php diff --git a/php/WP_CLI/InternalAssoc.php b/php/WP_CLI/InternalAssoc.php new file mode 100644 index 000000000..2652ed774 --- /dev/null +++ b/php/WP_CLI/InternalAssoc.php @@ -0,0 +1,73 @@ +<?php + +namespace WP_CLI; +use \WP_CLI; + +/** + * Class that handles special assoc parameters + */ +class InternalAssoc { + + static function version() { + WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); + } + + static function info() { + $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + + WP_CLI::line( "PHP binary:\t" . $php_bin ); + WP_CLI::line( "PHP version:\t" . PHP_VERSION ); + WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); + WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "wp-cli config:\t" . WP_CLI::get_config_path() ); + WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); + } + + static function cmd_dump() { + echo json_encode( self::command_to_array( WP_CLI::$root ) ); + } + + private static function command_to_array( $command ) { + $dump = array( + 'name' => $command->get_name(), + 'description' => $command->get_shortdesc(), + ); + + if ( $command instanceof Dispatcher\AtomicCommand ) { + $dump['synopsis'] = (string) $command->get_synopsis(); + } else { + foreach ( Dispatcher\get_subcommands( $command ) as $subcommand ) { + $dump['subcommands'][] = self::command_to_array( $subcommand ); + } + } + + return $dump; + } + + static function completions() { + foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { + $subcommands = Dispatcher\get_subcommands( $command ); + + WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); + } + } + + static function man( $args ) { + $arg_copy = $args; + + $command = WP_CLI::$root; + + while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { + $command = $command->find_subcommand( $args ); + } + + if ( !$command ) + WP_CLI::error( sprintf( "'%s' command not found.", + implode( ' ', $arg_copy ) ) ); + + foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { + WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + } + } +} + diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4b0f68a9a..6167cd1d9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -254,6 +254,10 @@ private static function parse_args() { } } + static function get_config_path() { + return self::$config_path; + } + static function get_config( $key = null ) { if ( null === $key ) return self::$config; @@ -289,19 +293,19 @@ static function before_wp_load() { // Handle --version parameter if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { - self::line( 'wp-cli ' . WP_CLI_VERSION ); + \WP_CLI\InternalAssoc::version(); exit; } // Handle --info parameter if ( isset( self::$assoc_args['info'] ) && empty( self::$arguments ) ) { - self::show_info(); + \WP_CLI\InternalAssoc::info(); exit; } // Handle --cmd-dump parameter if ( isset( self::$assoc_args['cmd-dump'] ) ) { - self::cmd_dump(); + \WP_CLI\InternalAssoc::cmd_dump(); exit; } @@ -380,39 +384,18 @@ static function after_wp_load() { require self::$config['require']; if ( isset( self::$assoc_args['man'] ) ) { - self::generate_man( self::$arguments ); + \WP_CLI\InternalAssoc::man( self::$arguments ); exit; } if ( isset( self::$assoc_args['completions'] ) ) { - self::render_automcomplete(); + \WP_CLI\InternalAssoc::completions(); exit; } self::_run_command(); } - private static function cmd_dump() { - echo json_encode( self::command_to_array( self::$root ) ); - } - - private static function command_to_array( $command ) { - $dump = array( - 'name' => $command->get_name(), - 'description' => $command->get_shortdesc(), - ); - - if ( $command instanceof Dispatcher\AtomicCommand ) { - $dump['synopsis'] = (string) $command->get_synopsis(); - } else { - foreach ( Dispatcher\get_subcommands( $command ) as $subcommand ) { - $dump['subcommands'][] = self::command_to_array( $subcommand ); - } - } - - return $dump; - } - private static function _run_command() { self::run_command( self::$arguments, self::$assoc_args ); } @@ -441,43 +424,6 @@ public static function run_command( $args, $assoc_args = array() ) { } } - private static function show_info() { - $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); - - WP_CLI::line( "PHP binary:\t" . $php_bin ); - WP_CLI::line( "PHP version:\t" . PHP_VERSION ); - WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); - WP_CLI::line( "wp-cli config:\t" . self::$config_path ); - WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); - } - - private static function generate_man( $args ) { - $arg_copy = $args; - - $command = \WP_CLI::$root; - - while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { - $command = $command->find_subcommand( $args ); - } - - if ( !$command ) - WP_CLI::error( sprintf( "'%s' command not found.", - implode( ' ', $arg_copy ) ) ); - - foreach ( self::$man_dirs as $dest_dir => $src_dir ) { - \WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); - } - } - - private static function render_automcomplete() { - foreach ( self::$root->get_subcommands() as $name => $command ) { - $subcommands = Dispatcher\get_subcommands( $command ); - - self::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); - } - } - // back-compat static function addCommand( $name, $class ) { self::add_command( $name, $class ); From 88e446e906beef2325e116a2969deda72186b562 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Jan 2013 22:48:52 +0200 Subject: [PATCH 1114/5359] rename bootstrap() to load_depdencies() --- php/utils.php | 2 +- php/wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 3145e405d..124e7494e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -6,7 +6,7 @@ use \WP_CLI\Dispatcher; -function bootstrap() { +function load_dependencies() { $vendor_paths = array( WP_CLI_ROOT . '../../../../vendor', // part of a larger project WP_CLI_ROOT . '../vendor', // top-level project diff --git a/php/wp-cli.php b/php/wp-cli.php index d9b16b3bd..41fef873d 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -13,7 +13,7 @@ include WP_CLI_ROOT . 'class-wp-cli-command.php'; include WP_CLI_ROOT . 'man.php'; -\WP_CLI\Utils\bootstrap(); +\WP_CLI\Utils\load_dependencies(); WP_CLI::before_wp_load(); From 6d300b5ab42e6c88441986a0b0bbd37e3b92440c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Jan 2013 23:23:06 +0200 Subject: [PATCH 1115/5359] introduce WP_CLI\Runner class It contains all the logic related to argument handling and WP loading. --- php/WP_CLI/Runner.php | 205 ++++++++++++++++++++++++++++++++++++++++++ php/class-wp-cli.php | 188 +++++--------------------------------- php/utils.php | 46 ---------- php/wp-cli.php | 8 +- 4 files changed, 233 insertions(+), 214 deletions(-) create mode 100644 php/WP_CLI/Runner.php diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php new file mode 100644 index 000000000..86cf92ba9 --- /dev/null +++ b/php/WP_CLI/Runner.php @@ -0,0 +1,205 @@ +<?php + +namespace WP_CLI; + +use WP_CLI; +use WP_CLI\Utils; + + +class Runner { + + private $config_path, $config; + + private $arguments, $assoc_args; + + public function __get( $key ) { + return $this->$key; + } + + private static function get_config_path( &$assoc_args ) { + if ( isset( $assoc_args['config'] ) ) { + $paths = array( $assoc_args['config'] ); + unset( $assoc_args['config'] ); + } else { + $paths = array( + getcwd() . '/wp-cli.local.yml', + getcwd() . '/wp-cli.yml' + ); + } + + foreach ( $paths as $path ) { + if ( file_exists( $path ) ) + return $path; + } + + return false; + } + + private static function load_config( $path, $spec ) { + if ( $path ) + $config = spyc_load_file( $path ); + else + $config = array(); + + $sanitized_config = array(); + + foreach ( $spec as $key => $details ) { + if ( $details['file'] && isset( $config[ $key ] ) ) + $sanitized_config[ $key ] = $config[ $key ]; + else + $sanitized_config[ $key ] = $details['default']; + } + + return $sanitized_config; + } + + private static function split_special( &$assoc_args, &$config, $spec ) { + foreach ( $spec as $key => $details ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } + } + + public function before_wp_load() { + $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + + list( $this->arguments, $this->assoc_args ) = $r; + + // foo --help -> help foo + if ( isset( $this->assoc_args['help'] ) ) { + array_unshift( $this->arguments, 'help' ); + unset( $this->assoc_args['help'] ); + } + + // {plugin|theme} update --all -> {plugin|theme} update-all + if ( count( $this->arguments ) > 1 && in_array( $this->arguments[0], array( 'plugin', 'theme' ) ) + && $this->arguments[1] == 'update' + && isset( $this->assoc_args['all'] ) + ) { + $this->arguments[1] = 'update-all'; + unset( $this->assoc_args['all'] ); + } + + $config_spec = Utils\get_config_spec(); + + $this->config_path = self::get_config_path( $this->assoc_args ); + + $this->config = self::load_config( $this->config_path, $config_spec ); + + self::split_special( $this->assoc_args, $this->config, $config_spec ); + + if ( 'auto' == $this->config['color'] ) + $this->config['color'] = ! \cli\Shell::isPiped(); + + // Handle --version parameter + if ( isset( $this->assoc_args['version'] ) && empty( $this->arguments ) ) { + \WP_CLI\InternalAssoc::version(); + exit; + } + + // Handle --info parameter + if ( isset( $this->assoc_args['info'] ) && empty( $this->arguments ) ) { + \WP_CLI\InternalAssoc::info(); + exit; + } + + // Handle --cmd-dump parameter + if ( isset( $this->assoc_args['cmd-dump'] ) ) { + \WP_CLI\InternalAssoc::cmd_dump(); + exit; + } + + $_SERVER['DOCUMENT_ROOT'] = getcwd(); + + // Handle --path + Utils\set_wp_root( $this->config ); + + // Handle --url and --blog parameters + Utils\set_url( $this->config ); + + if ( array( 'core', 'download' ) == $this->arguments ) { + $this->_run_command(); + exit; + } + + if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { + WP_CLI::error( "This does not seem to be a WordPress install.", false ); + WP_CLI::line( "Pass --path=`path/to/wordpress` or run `wp core download`." ); + exit(1); + } + + if ( array( 'core', 'config' ) == $this->arguments ) { + $this->_run_command(); + exit; + } + + if ( !Utils\locate_wp_config() ) { + WP_CLI::error( "wp-config.php not found.", false ); + WP_CLI::line( "Either create one manually or use `wp core config`." ); + exit(1); + } + + if ( $this->cmd_starts_with( array( 'db' ) ) ) { + eval( Utils\get_wp_config_code() ); + $this->_run_command(); + exit; + } + + if ( + $this->cmd_starts_with( array( 'core', 'install' ) ) || + $this->cmd_starts_with( array( 'core', 'is-installed' ) ) + ) { + define( 'WP_INSTALLING', true ); + + if ( !isset( $_SERVER['HTTP_HOST'] ) ) { + Utils\set_url_params( 'http://example.com' ); + } + } + + // Pretend we're in WP_ADMIN + define( 'WP_ADMIN', true ); + $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; + } + + private function cmd_starts_with( $prefix ) { + return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); + } + + function after_wp_config_load() { + if ( isset( $this->config['debug'] ) ) { + if ( !defined( 'WP_DEBUG' ) ) + define( 'WP_DEBUG', true ); + } + } + + function after_wp_load() { + add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); + + Utils\set_user( $this->config ); + + if ( !defined( 'WP_INSTALLING' ) && isset( $this->config['url'] ) ) + Utils\set_wp_query(); + + if ( isset( $this->config['require'] ) ) + require $this->config['require']; + + if ( isset( $this->assoc_args['man'] ) ) { + \WP_CLI\InternalAssoc::man( $this->arguments ); + exit; + } + + if ( isset( $this->assoc_args['completions'] ) ) { + \WP_CLI\InternalAssoc::completions(); + exit; + } + + $this->_run_command(); + } + + private function _run_command() { + WP_CLI::run_command( $this->arguments, $this->assoc_args ); + } +} + diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 6167cd1d9..64069ab1d 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -4,19 +4,28 @@ use \WP_CLI\Dispatcher; /** - * Wrapper class for WP-CLI - * - * @package wp-cli + * Various utilities for WP-CLI commands. */ class WP_CLI { public static $root; + public static $runner; + private static $man_dirs = array(); - private static $config_path, $config; + /** + * Initialize WP_CLI static variables. + */ + static function init() { + self::add_man_dir( + WP_CLI_ROOT . "../man/", + WP_CLI_ROOT . "../man-src/" + ); - private static $arguments, $assoc_args; + self::$root = new Dispatcher\RootCommand; + self::$runner = new WP_CLI\Runner; + } /** * Add a command to the wp-cli list of commands @@ -25,7 +34,7 @@ class WP_CLI { * @param string|object $implementation The command implementation */ static function add_command( $name, $implementation ) { - if ( in_array( $name, self::$config['disabled_commands'] ) ) + if ( in_array( $name, self::get_config('disabled_commands') ) ) return; if ( is_string( $implementation ) ) { @@ -53,7 +62,7 @@ private static function create_composite_command( $name, $class ) { $subcommand_name = $subcommand->get_name(); $full_name = self::get_full_name( $subcommand ); - if ( in_array( $full_name, self::$config['disabled_commands'] ) ) + if ( in_array( $full_name, self::get_config('disabled_commands') ) ) continue; $container->add_subcommand( $subcommand_name, $subcommand ); @@ -103,7 +112,7 @@ static function out( $message, $handle = STDOUT ) { if ( self::get_config('quiet') ) return; - fwrite( $handle, \cli\Colors::colorize( $message, self::$config['color'] ) ); + fwrite( $handle, \cli\Colors::colorize( $message, self::get_config('color') ) ); } /** @@ -122,10 +131,10 @@ static function line( $message = '' ) { * @param bool $exit */ static function error( $message, $exit = true ) { - if ( !isset( self::$config['completions'] ) ) { + if ( ! self::get_config('completions') ) { $label = 'Error'; $msg = '%R' . $label . ': %n' . self::error_to_string( $message ) . "\n"; - fwrite( STDERR, \cli\Colors::colorize( $msg, self::$config['color'] ) ); + fwrite( STDERR, \cli\Colors::colorize( $msg, self::get_config('color') ) ); } if ( $exit ) @@ -233,171 +242,20 @@ static function launch( $command, $exit_on_error = true ) { return $r; } - private static function parse_args() { - $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); - - list( self::$arguments, self::$assoc_args ) = $r; - - // foo --help -> help foo - if ( isset( self::$assoc_args['help'] ) ) { - array_unshift( self::$arguments, 'help' ); - unset( self::$assoc_args['help'] ); - } - - // {plugin|theme} update --all -> {plugin|theme} update-all - if ( count( self::$arguments ) > 1 && in_array( self::$arguments[0], array( 'plugin', 'theme' ) ) - && self::$arguments[1] == 'update' - && isset( self::$assoc_args['all'] ) - ) { - self::$arguments[1] = 'update-all'; - unset( self::$assoc_args['all'] ); - } - } - static function get_config_path() { - return self::$config_path; + return self::$runner->config_path; } static function get_config( $key = null ) { if ( null === $key ) - return self::$config; + return self::$runner->config; - if ( !isset( self::$config[ $key ] ) ) { + if ( !isset( self::$runner->config[ $key ] ) ) { self::warning( "Unknown config option '$key'." ); return null; } - return self::$config[ $key ]; - } - - static function before_wp_load() { - self::$root = new Dispatcher\RootCommand; - - self::add_man_dir( - WP_CLI_ROOT . "../man/", - WP_CLI_ROOT . "../man-src/" - ); - - self::parse_args(); - - $config_spec = Utils\get_config_spec(); - - self::$config_path = Utils\get_config_path( self::$assoc_args ); - - self::$config = Utils\load_config( self::$config_path, $config_spec ); - - Utils\split_special( self::$assoc_args, self::$config, $config_spec ); - - if ( 'auto' == self::$config['color'] ) - self::$config['color'] = ! \cli\Shell::isPiped(); - - // Handle --version parameter - if ( isset( self::$assoc_args['version'] ) && empty( self::$arguments ) ) { - \WP_CLI\InternalAssoc::version(); - exit; - } - - // Handle --info parameter - if ( isset( self::$assoc_args['info'] ) && empty( self::$arguments ) ) { - \WP_CLI\InternalAssoc::info(); - exit; - } - - // Handle --cmd-dump parameter - if ( isset( self::$assoc_args['cmd-dump'] ) ) { - \WP_CLI\InternalAssoc::cmd_dump(); - exit; - } - - $_SERVER['DOCUMENT_ROOT'] = getcwd(); - - // Handle --path - Utils\set_wp_root( self::$config ); - - // Handle --url and --blog parameters - Utils\set_url( self::$config ); - - if ( array( 'core', 'download' ) == self::$arguments ) { - self::_run_command(); - exit; - } - - if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { - WP_CLI::error( "This does not seem to be a WordPress install.", false ); - WP_CLI::line( "Pass --path=`path/to/wordpress` or run `wp core download`." ); - exit(1); - } - - if ( array( 'core', 'config' ) == self::$arguments ) { - self::_run_command(); - exit; - } - - if ( !Utils\locate_wp_config() ) { - WP_CLI::error( "wp-config.php not found.", false ); - WP_CLI::line( "Either create one manually or use `wp core config`." ); - exit(1); - } - - if ( self::cmd_starts_with( array( 'db' ) ) ) { - eval( Utils\get_wp_config_code() ); - self::_run_command(); - exit; - } - - if ( - self::cmd_starts_with( array( 'core', 'install' ) ) || - self::cmd_starts_with( array( 'core', 'is-installed' ) ) - ) { - define( 'WP_INSTALLING', true ); - - if ( !isset( $_SERVER['HTTP_HOST'] ) ) { - Utils\set_url_params( 'http://example.com' ); - } - } - - // Pretend we're in WP_ADMIN - define( 'WP_ADMIN', true ); - $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; - } - - private static function cmd_starts_with( $prefix ) { - return $prefix == array_slice( self::$arguments, 0, count( $prefix ) ); - } - - static function after_wp_config_load() { - if ( isset( self::$config['debug'] ) ) { - if ( !defined( 'WP_DEBUG' ) ) - define( 'WP_DEBUG', true ); - } - } - - static function after_wp_load() { - add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - - Utils\set_user( self::$config ); - - if ( !defined( 'WP_INSTALLING' ) && isset( self::$config['url'] ) ) - Utils\set_wp_query(); - - if ( isset( self::$config['require'] ) ) - require self::$config['require']; - - if ( isset( self::$assoc_args['man'] ) ) { - \WP_CLI\InternalAssoc::man( self::$arguments ); - exit; - } - - if ( isset( self::$assoc_args['completions'] ) ) { - \WP_CLI\InternalAssoc::completions(); - exit; - } - - self::_run_command(); - } - - private static function _run_command() { - self::run_command( self::$arguments, self::$assoc_args ); + return self::$runner->config[ $key ]; } /** diff --git a/php/utils.php b/php/utils.php index 124e7494e..49121da12 100644 --- a/php/utils.php +++ b/php/utils.php @@ -72,52 +72,6 @@ function get_config_spec() { return $spec; } -function get_config_path( $assoc_args ) { - if ( isset( $assoc_args['config'] ) ) { - $paths = array( $assoc_args['config'] ); - unset( $assoc_args['config'] ); - } else { - $paths = array( - getcwd() . '/wp-cli.local.yml', - getcwd() . '/wp-cli.yml' - ); - } - - foreach ( $paths as $path ) { - if ( file_exists( $path ) ) - return $path; - } - - return false; -} - -function load_config( $path, $spec ) { - if ( $path ) - $config = spyc_load_file( $path ); - else - $config = array(); - - $sanitized_config = array(); - - foreach ( $spec as $key => $details ) { - if ( $details['file'] && isset( $config[ $key ] ) ) - $sanitized_config[ $key ] = $config[ $key ]; - else - $sanitized_config[ $key ] = $details['default']; - } - - return $sanitized_config; -} - -function split_special( &$assoc_args, &$config, $spec ) { - foreach ( $spec as $key => $details ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } -} - /** * Splits $argv into positional and associative arguments. * diff --git a/php/wp-cli.php b/php/wp-cli.php index 41fef873d..75413548b 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -15,12 +15,14 @@ \WP_CLI\Utils\load_dependencies(); -WP_CLI::before_wp_load(); +WP_CLI::init(); + +WP_CLI::$runner->before_wp_load(); // Load WordPress, in the global scope eval( \WP_CLI\Utils\get_wp_config_code() ); -WP_CLI::after_wp_config_load(); +WP_CLI::$runner->after_wp_config_load(); require WP_CLI_ROOT . 'wp-settings-cli.php'; @@ -30,5 +32,5 @@ // Load all admin utilities require ABSPATH . 'wp-admin/includes/admin.php'; -WP_CLI::after_wp_load(); +WP_CLI::$runner->after_wp_load(); From 25c6f36bc388523db7b60bd1c237a40a6a01c5da Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Jan 2013 23:51:49 +0200 Subject: [PATCH 1116/5359] move even more code from utils.php into WP_CLI\Runner --- php/WP_CLI/Runner.php | 85 +++++++++++++++++++++++++++++++++++++++++-- php/utils.php | 76 -------------------------------------- php/wp-cli.php | 2 +- 3 files changed, 83 insertions(+), 80 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 86cf92ba9..dd68d6ecb 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -62,6 +62,85 @@ private static function split_special( &$assoc_args, &$config, $spec ) { } } + private static function set_wp_root( $config ) { + if ( !empty( $config['path'] ) ) { + define( 'ABSPATH', rtrim( $config['path'], '/' ) . '/' ); + } else { + define( 'ABSPATH', getcwd() . '/' ); + } + } + + private static function set_url( $assoc_args ) { + if ( isset( $assoc_args['url'] ) ) { + $url = $assoc_args['url']; + } elseif ( isset( $assoc_args['blog'] ) ) { + WP_CLI::warning( 'The --blog parameter is deprecated. Use --url instead.' ); + + $url = $assoc_args['blog']; + if ( true === $url ) { + WP_CLI::line( 'usage: wp --blog=example.com' ); + } + } elseif ( is_readable( ABSPATH . 'wp-cli-blog' ) ) { + WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); + + $url = trim( file_get_contents( ABSPATH . 'wp-cli-blog' ) ); + } elseif ( $wp_config_path = Utils\locate_wp_config() ) { + // Try to find the blog parameter in the wp-config file + $wp_config_file = file_get_contents( $wp_config_path ); + $hit = array(); + + $re_define = "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU"; + + if ( preg_match_all( $re_define, $wp_config_file, $matches ) ) { + foreach ( $matches[2] as $def_key => $def_name ) { + if ( 'DOMAIN_CURRENT_SITE' == $def_name ) + $hit['domain'] = $matches[5][$def_key]; + if ( 'PATH_CURRENT_SITE' == $def_name ) + $hit['path'] = $matches[5][$def_key]; + } + } + + if ( !empty( $hit ) && isset( $hit['domain'] ) ) + $url = $hit['domain']; + if ( !empty( $hit ) && isset( $hit['path'] ) ) + $url .= $hit['path']; + } + + if ( isset( $url ) ) { + Utils\set_url_params( $url ); + } + } + + /** + * Returns wp-config.php code, skipping the loading of wp-settings.php + * + * @return string + */ + function get_wp_config_code() { + $wp_config_path = Utils\locate_wp_config(); + + $replacements = array( + '__FILE__' => "'$wp_config_path'", + '__DIR__' => "'" . dirname( $wp_config_path ) . "'" + ); + + $old = array_keys( $replacements ); + $new = array_values( $replacements ); + + $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); + + $lines_to_run = array(); + + foreach ( $wp_config_code as $line ) { + if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) + continue; + + $lines_to_run[] = str_replace( $old, $new, $line ); + } + + return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); + } + public function before_wp_load() { $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -114,10 +193,10 @@ public function before_wp_load() { $_SERVER['DOCUMENT_ROOT'] = getcwd(); // Handle --path - Utils\set_wp_root( $this->config ); + self::set_wp_root( $this->config ); // Handle --url and --blog parameters - Utils\set_url( $this->config ); + self::set_url( $this->config ); if ( array( 'core', 'download' ) == $this->arguments ) { $this->_run_command(); @@ -142,7 +221,7 @@ public function before_wp_load() { } if ( $this->cmd_starts_with( array( 'db' ) ) ) { - eval( Utils\get_wp_config_code() ); + eval( $this->get_wp_config_code() ); $this->_run_command(); exit; } diff --git a/php/utils.php b/php/utils.php index 49121da12..2119bb05d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -134,44 +134,6 @@ function get_command_file( $command ) { return $path; } -function set_url( $assoc_args ) { - if ( isset( $assoc_args['url'] ) ) { - $url = $assoc_args['url']; - } elseif ( isset( $assoc_args['blog'] ) ) { - \WP_CLI::warning( 'The --blog parameter is deprecated. Use --url instead.' ); - - $url = $assoc_args['blog']; - if ( true === $url ) { - \WP_CLI::line( 'usage: wp --blog=example.com' ); - } - } elseif ( is_readable( ABSPATH . 'wp-cli-blog' ) ) { - \WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); - - $url = trim( file_get_contents( ABSPATH . 'wp-cli-blog' ) ); - } elseif ( $wp_config_path = locate_wp_config() ) { - // Try to find the blog parameter in the wp-config file - $wp_config_file = file_get_contents( $wp_config_path ); - $hit = array(); - if ( preg_match_all( "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU", $wp_config_file, $matches ) ) { - foreach ( $matches[2] as $def_key => $def_name ) { - if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[5][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[5][$def_key]; - } - } - - if ( !empty( $hit ) && isset( $hit['domain'] ) ) - $url = $hit['domain']; - if ( !empty( $hit ) && isset( $hit['path'] ) ) - $url .= $hit['path']; - } - - if ( isset( $url ) ) { - set_url_params( $url ); - } -} - /** * Sets the appropriate $_SERVER keys based on a given string * @@ -198,14 +160,6 @@ function set_url_params( $url ) { $_SERVER['REQUEST_METHOD'] = 'GET'; } -function set_wp_root( $config ) { - if ( !empty( $config['path'] ) ) { - define( 'ABSPATH', rtrim( $config['path'], '/' ) . '/' ); - } else { - define( 'ABSPATH', getcwd() . '/' ); - } -} - function locate_wp_config() { if ( file_exists( ABSPATH . 'wp-config.php' ) ) return ABSPATH . 'wp-config.php'; @@ -216,36 +170,6 @@ function locate_wp_config() { return false; } -/** - * Returns wp-config.php code, skipping the loading of wp-settings.php - * - * @return string - */ -function get_wp_config_code() { - $wp_config_path = locate_wp_config(); - - $replacements = array( - '__FILE__' => "'$wp_config_path'", - '__DIR__' => "'" . dirname( $wp_config_path ) . "'" - ); - - $old = array_keys( $replacements ); - $new = array_values( $replacements ); - - $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); - - $lines_to_run = array(); - - foreach ( $wp_config_code as $line ) { - if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) - continue; - - $lines_to_run[] = str_replace( $old, $new, $line ); - } - - return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); -} - /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. diff --git a/php/wp-cli.php b/php/wp-cli.php index 75413548b..b3eeae39a 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -20,7 +20,7 @@ WP_CLI::$runner->before_wp_load(); // Load WordPress, in the global scope -eval( \WP_CLI\Utils\get_wp_config_code() ); +eval( WP_CLI::$runner->get_wp_config_code() ); WP_CLI::$runner->after_wp_config_load(); From ea2f548367f66f9f355d044375f423351f7af9a3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 01:30:39 +0200 Subject: [PATCH 1117/5359] storing the config spec in a static variable is not needed get_config_spec() is only called once per instantiation, or at most 2 times. --- php/utils.php | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/php/utils.php b/php/utils.php index 2119bb05d..93065817d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -52,21 +52,17 @@ function register_autoload() { } function get_config_spec() { - static $spec; + $spec = include __DIR__ . '/config-spec.php'; - if ( !$spec ) { - $spec = include __DIR__ . '/config-spec.php'; - - $defaults = array( - 'runtime' => false, - 'file' => false, - 'synopsis' => '', - 'default' => null, - ); + $defaults = array( + 'runtime' => false, + 'file' => false, + 'synopsis' => '', + 'default' => null, + ); - foreach ( $spec as &$option ) { - $option = array_merge( $defaults, $option ); - } + foreach ( $spec as &$option ) { + $option = array_merge( $defaults, $option ); } return $spec; From 60aa13881acef0a4f85227b966de8237c205f8c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 01:33:01 +0200 Subject: [PATCH 1118/5359] add --param-dump --- php/WP_CLI/InternalAssoc.php | 4 ++++ php/WP_CLI/Runner.php | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/php/WP_CLI/InternalAssoc.php b/php/WP_CLI/InternalAssoc.php index 2652ed774..6ceae0b09 100644 --- a/php/WP_CLI/InternalAssoc.php +++ b/php/WP_CLI/InternalAssoc.php @@ -23,6 +23,10 @@ static function info() { WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); } + static function param_dump() { + echo json_encode( Utils\get_config_spec() ); + } + static function cmd_dump() { echo json_encode( self::command_to_array( WP_CLI::$root ) ); } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index dd68d6ecb..e4e94d7b8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -184,6 +184,12 @@ public function before_wp_load() { exit; } + // Handle --cmd-dump parameter + if ( isset( $this->assoc_args['param-dump'] ) ) { + \WP_CLI\InternalAssoc::param_dump(); + exit; + } + // Handle --cmd-dump parameter if ( isset( $this->assoc_args['cmd-dump'] ) ) { \WP_CLI\InternalAssoc::cmd_dump(); From 05c57d481982046f8b533234b67701182e46684f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 04:44:34 +0200 Subject: [PATCH 1119/5359] support --color and --no-color special args. closes #267 --- php/WP_CLI/Runner.php | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e4e94d7b8..9876d3179 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -53,11 +53,30 @@ private static function load_config( $path, $spec ) { return $sanitized_config; } + private static function handle_boolean_param( &$assoc_args, &$config, $param ) { + $subkeys = array( + "$param" => true, + "no-$param" => false + ); + + foreach ( $subkeys as $key => $value ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $param ] = $value; + } + + unset( $assoc_args[ $key ] ); + } + } + private static function split_special( &$assoc_args, &$config, $spec ) { foreach ( $spec as $key => $details ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); + if ( true == $details['runtime'] ) { + self::handle_boolean_param( $assoc_args, $config, $key ); + } elseif ( false !== $details['runtime'] ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } } } } @@ -169,8 +188,12 @@ public function before_wp_load() { self::split_special( $this->assoc_args, $this->config, $config_spec ); - if ( 'auto' == $this->config['color'] ) + if ( isset( $this->assoc_args['no-color'] ) ) { + $this->config['color'] = false; + unset( $this->assoc_args['no-color'] ); + } elseif ( 'auto' == $this->config['color'] ) { $this->config['color'] = ! \cli\Shell::isPiped(); + } // Handle --version parameter if ( isset( $this->assoc_args['version'] ) && empty( $this->arguments ) ) { From cc517b06e3a7ca487c46d1b82446567faf7c67c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 04:46:53 +0200 Subject: [PATCH 1120/5359] update config-spec.php. see #267 --- php/config-spec.php | 51 ++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 07c3aa130..2a8652e0c 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -2,73 +2,58 @@ return array( 'path' => array( - 'runtime' => true, - 'file' => true, - 'default' => null, + 'runtime' => '=<path>', + 'file' => '<path>', 'desc' => 'Path to the WordPress files', - 'synopsis' => '<path>' ), 'url' => array( - 'runtime' => true, - 'file' => true, - 'default' => null, + 'runtime' => '=<url>', + 'file' => '<url>', 'desc' => 'Pretend request came from given URL', - 'synopsis' => '<url>' ), 'blog' => array( 'deprecated' => 'Use --url instead', - 'runtime' => true, - 'file' => false, - 'default' => null, - 'synopsis' => '<url>', + 'runtime' => '', ), 'user' => array( - 'runtime' => true, - 'file' => true, - 'default' => null, + 'runtime' => '=<id|login>', + 'file' => '<id|login>', 'desc' => 'Set the WordPress user', - 'synopsis' => '<id|login>' ), 'require' => array( - 'runtime' => true, - 'file' => true, - 'default' => null, + 'runtime' => '=<path>', + 'file' => '<path>', 'desc' => 'Load given PHP file before running the command', - 'synopsis' => '<path>' ), 'disabled_commands' => array( - 'runtime' => false, - 'file' => true, + 'file' => '<list>', 'default' => array(), 'desc' => '(Sub)commands to disable', ), 'color' => array( 'runtime' => true, - 'file' => true, + 'file' => '<bool>', 'default' => 'auto', - 'desc' => 'Show all PHP errors.', - 'synopsis' => '<bool>', + 'desc' => 'Whether to colozire the output', ), 'debug' => array( - 'runtime' => true, - 'file' => true, + 'runtime' => '', + 'file' => '<bool>', 'default' => false, - 'desc' => 'Show all PHP errors.', - 'synopsis' => '', + 'desc' => 'Show all PHP errors', ), 'quiet' => array( - 'runtime' => true, - 'file' => true, + 'runtime' => '', + 'file' => '<bool>', 'default' => false, - 'desc' => 'Show all PHP errors.', - 'synopsis' => '<bool>', + 'desc' => 'Suppress informational messages', ), ); From 3c598b476f60f7f52577f63a8f2ea0388f54f30f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 05:14:15 +0200 Subject: [PATCH 1121/5359] generate synopsis for global command from config-spec --- php/WP_CLI/Dispatcher/RootCommand.php | 43 +++++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index a0712ca80..989faa2cf 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -35,16 +35,41 @@ function show_usage() { See 'wp help <command>' for more information on a specific command. Global parameters: ---user=<id|login> set the WordPress user ---url=<url> set the URL ---path=<path> set the path to the WP install ---config=<path> set the path to the wp-cli config file ---require=<path> load a certain PHP file before running the command ---quiet suppress informational messages ---debug show all PHP errors ---info print wp-cli information EOB - ); + ); + + \WP_CLI::line( self::generate_synopsis() ); + } + + private static function generate_synopsis() { + $max_len = 0; + + $lines = array(); + + foreach ( \WP_CLI\Utils\get_config_spec() as $key => $details ) { + if ( false === $details['runtime'] ) + continue; + + if ( isset( $details['deprecated'] ) ) + continue; + + $synopsis = ( true === $details['runtime'] ) + ? "--$key/--no-$key" + : "--$key" . $details['runtime']; + + $cur_len = strlen( $synopsis ); + + if ( $max_len < $cur_len ) + $max_len = $cur_len; + + $lines[] = array( $synopsis, $details['desc'] ); + } + + foreach ( $lines as $line ) { + list( $synopsis, $desc ) = $line; + + \WP_CLI::line( ' ' . str_pad( $synopsis, $max_len ) . ' ' . $desc ); + } } function pre_invoke( &$args ) { From 309b2d6aacf66cf70e5e22c8672690ac95c2c98b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 05:15:27 +0200 Subject: [PATCH 1122/5359] add --config global param --- php/config-spec.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/config-spec.php b/php/config-spec.php index 2a8652e0c..8879434b2 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -1,6 +1,12 @@ <?php return array( + 'config' => array( + 'runtime' => '=<path>', + 'file' => false, + 'desc' => 'Path to the wp-cli config file', + ), + 'path' => array( 'runtime' => '=<path>', 'file' => '<path>', From ba13113ffdc43e34c0193f9f68c33eefe94cd389 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 05:23:46 +0200 Subject: [PATCH 1123/5359] fix check for completions in WP_CLI::error() --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 64069ab1d..884327447 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -131,7 +131,7 @@ static function line( $message = '' ) { * @param bool $exit */ static function error( $message, $exit = true ) { - if ( ! self::get_config('completions') ) { + if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { $label = 'Error'; $msg = '%R' . $label . ': %n' . self::error_to_string( $message ) . "\n"; fwrite( STDERR, \cli\Colors::colorize( $msg, self::get_config('color') ) ); From c7da7bceef309c547de62021d825016df5c8eb2d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 05:37:39 +0200 Subject: [PATCH 1124/5359] strict comparison for 'runtime' key. see #277 --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9876d3179..ce1287e7e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -70,7 +70,7 @@ private static function handle_boolean_param( &$assoc_args, &$config, $param ) { private static function split_special( &$assoc_args, &$config, $spec ) { foreach ( $spec as $key => $details ) { - if ( true == $details['runtime'] ) { + if ( true === $details['runtime'] ) { self::handle_boolean_param( $assoc_args, $config, $key ); } elseif ( false !== $details['runtime'] ) { if ( isset( $assoc_args[ $key ] ) ) { From b96ad80a5e85ac3c8eb7ba75ab48886f9fc2af62 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Jan 2013 05:44:00 +0200 Subject: [PATCH 1125/5359] bump version to 0.8.0-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index b3eeae39a..3fd88af13 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.8.0-alpha' ); +define( 'WP_CLI_VERSION', '0.8.0-beta' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From b15b8042427b85e7e9a8a91851cbf7484351d107 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 03:49:14 +0100 Subject: [PATCH 1126/5359] remove unnecessary leading slash in locate_wp_config() --- php/utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 93065817d..6fb20fdc7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -160,8 +160,8 @@ function locate_wp_config() { if ( file_exists( ABSPATH . 'wp-config.php' ) ) return ABSPATH . 'wp-config.php'; - if ( file_exists( ABSPATH . '/../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) - return ABSPATH . '/../wp-config.php'; + if ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) + return ABSPATH . '../wp-config.php'; return false; } From 0c6850417f67e416873b40f8e31cf70178436267 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 03:57:06 +0100 Subject: [PATCH 1127/5359] normalize and cache path returned by locate_wp_config() --- php/utils.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/php/utils.php b/php/utils.php index 6fb20fdc7..663c4254d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -157,13 +157,21 @@ function set_url_params( $url ) { } function locate_wp_config() { - if ( file_exists( ABSPATH . 'wp-config.php' ) ) - return ABSPATH . 'wp-config.php'; + static $path; - if ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) - return ABSPATH . '../wp-config.php'; + if ( null === $path ) { + if ( file_exists( ABSPATH . 'wp-config.php' ) ) + $path = ABSPATH . 'wp-config.php'; + elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) + $path = ABSPATH . '../wp-config.php'; + else + $path = false; + + if ( $path ) + $path = realpath( $path ); + } - return false; + return $path; } /** From 0be188895f742af6dfae0520e45511b65cefceb8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 04:03:24 +0100 Subject: [PATCH 1128/5359] scaffold plugin: made success msg consistent with other scaffolds --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b5511feb2..45ee281fc 100755 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -168,7 +168,7 @@ function plugin( $args, $assoc_args ) { $this->create_file( $plugin_path, $plugin_contents ); - WP_CLI::success( "Plugin scaffold created: $plugin_path" ); + WP_CLI::success( "Created $plugin_path" ); if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); From 8fccb8649d104576947bc343352225a7da0c33c1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 04:06:05 +0100 Subject: [PATCH 1129/5359] remove extra tab from extended scaffolds --- php/templates/post_type_extended.mustache | 2 +- php/templates/taxonomy_extended.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/templates/post_type_extended.mustache b/php/templates/post_type_extended.mustache index 48cef1b3e..240746970 100755 --- a/php/templates/post_type_extended.mustache +++ b/php/templates/post_type_extended.mustache @@ -1,7 +1,7 @@ <?php function {{machine_name}}_init() { - {{{output}}} +{{{output}}} } add_action( 'init', '{{machine_name}}_init' ); diff --git a/php/templates/taxonomy_extended.mustache b/php/templates/taxonomy_extended.mustache index 080556351..8e0e1a5c7 100755 --- a/php/templates/taxonomy_extended.mustache +++ b/php/templates/taxonomy_extended.mustache @@ -1,6 +1,6 @@ <?php function {{machine_name}}_init() { - {{{output}}} +{{{output}}} } add_action( 'init', '{{machine_name}}_init' ); From 8acc57dcb3ec545b948f3f39b79f577e548a32fb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 15:22:14 +0100 Subject: [PATCH 1130/5359] set version to 0.8.0 --- build.properties | 2 +- php/wp-cli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.properties b/build.properties index 27ad66bce..dcab1de8e 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ project.name=wpcli project.channel=wp-cli.org/pear project.majorVersion=0 -project.minorVersion=7 +project.minorVersion=8 project.patchLevel=0 project.snapshot=false diff --git a/php/wp-cli.php b/php/wp-cli.php index 3fd88af13..343184614 100755 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.8.0-beta' ); +define( 'WP_CLI_VERSION', '0.8.0' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From 27e5f83b00fc1d3f9fd72f08a147184a54f946d6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 17:07:55 +0100 Subject: [PATCH 1131/5359] exclude .git files via build.xml --- build.xml | 12 ++++++------ utils/pear-build | 10 ---------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/build.xml b/build.xml index 932336fb4..96905b8ca 100644 --- a/build.xml +++ b/build.xml @@ -75,37 +75,37 @@ <include name="**/**"/> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.datadir}" id="datafiles"> <include name="**/**"/> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.phpdir}" id="phpfiles"> <include name="**/**"/> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.testunitdir}/php" id="testfiles"> <include name="**/**"/> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.wwwdir}" id="wwwfiles"> <include name="**/**" /> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.docdir}" id="docfiles"> <include name="**/**" /> <exclude name="**/.DS_Store"/> <exclude name="**/.empty"/> - <exclude name="**/.svn"/> + <exclude name="**/.git*"/> </fileset> <fileset dir="${project.basedir}" id="topleveldocfiles"> <include name="*.txt" /> diff --git a/utils/pear-build b/utils/pear-build index c4e404784..d7ce29dc5 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -5,20 +5,10 @@ set -ex # create bunch of directories that phing complains about mkdir -p docs data www tests/unit-tests/php -# temporarily move the .git dir, because phing is stupid -git_dir=php/php-cli-tools/.git -if [ -f $git_dir ]; then - mv $git_dir /tmp/php-cli-tools-git -fi - # generate package find -name '*~' -delete phing pear-package -if [ ! -d $git_dir ]; then - mv /tmp/php-cli-tools-git $git_dir -fi - version=$(cat dist/lastBuilt) version="${version/*wpcli-/}" version="${version/.tgz/}" From 46ff75de61ac8906b0fd2e441f2694a7e27d5268 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Jan 2013 19:43:50 +0100 Subject: [PATCH 1132/5359] include only php files in build.xml --- build.xml | 5 +---- utils/pear-build | 10 ++++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build.xml b/build.xml index 96905b8ca..4264119d3 100644 --- a/build.xml +++ b/build.xml @@ -84,10 +84,7 @@ <exclude name="**/.git*"/> </fileset> <fileset dir="${project.src.phpdir}" id="phpfiles"> - <include name="**/**"/> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> + <include name="**/*.php"/> </fileset> <fileset dir="${project.src.testunitdir}/php" id="testfiles"> <include name="**/**"/> diff --git a/utils/pear-build b/utils/pear-build index d7ce29dc5..f2be1b3fd 100755 --- a/utils/pear-build +++ b/utils/pear-build @@ -6,7 +6,6 @@ set -ex mkdir -p docs data www tests/unit-tests/php # generate package -find -name '*~' -delete phing pear-package version=$(cat dist/lastBuilt) @@ -16,11 +15,14 @@ version="${version/.tgz/}" #sudo phing install-system # update channel files -cd ../wp-cli-pear -pirum add . ../wp-cli/dist/wpcli-$version.tgz -pirum build . +pear_repo=../wp-cli-pear + +pirum add $pear_repo ../wp-cli/dist/wpcli-$version.tgz +pirum build $pear_repo # push changes +cd $pear_repo + git add -A git ci -m "release $version" git push origin gh-pages From 9f514b6d5dc1601a162908074518682df3e57169 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Jan 2013 17:19:12 +0100 Subject: [PATCH 1133/5359] PHP files don't need to be executable --- php/commands/scaffold.php | 0 php/wp-cli.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 php/commands/scaffold.php mode change 100755 => 100644 php/wp-cli.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php old mode 100755 new mode 100644 diff --git a/php/wp-cli.php b/php/wp-cli.php old mode 100755 new mode 100644 From 0bd67df80b8c07d993f5fb5a4c4c1527ce29c2bc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Jan 2013 17:25:30 +0100 Subject: [PATCH 1134/5359] check that the plugin directory exists. fixes #281 --- php/commands/scaffold.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 45ee281fc..0061ac571 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -139,6 +139,9 @@ private function get_output_path( $assoc_args, $subdir ) { $path = TEMPLATEPATH; } elseif ( ! empty( $plugin ) ) { $path = WP_PLUGIN_DIR . '/' . $plugin; + if ( !is_dir( $path ) ) { + WP_CLI::error( "Can't find '$plugin' plugin." ); + } } else { return false; } From a9a98991565973a4b5f6d9d1c801d5f63a1b526a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Jan 2013 17:26:21 +0100 Subject: [PATCH 1135/5359] bump version to 0.9.0-dev --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 343184614..c1443fd6a 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.8.0' ); +define( 'WP_CLI_VERSION', '0.9.0-dev' ); define( 'WP_CLI_ROOT', __DIR__ . '/' ); From b5dcdfdaa6f9c53a0c1c6ff1dea06de750b53313 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 31 Jan 2013 22:36:18 +0100 Subject: [PATCH 1136/5359] Added command file and skeleton for methods --- php/commands/media.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 php/commands/media.php diff --git a/php/commands/media.php b/php/commands/media.php new file mode 100644 index 000000000..f1468cc8b --- /dev/null +++ b/php/commands/media.php @@ -0,0 +1,32 @@ +<?php + +/** + * Functionality to control the media library and its attachments + * + * @package wp-cli + */ +class Media_Command extends WP_CLI_Command { + + function __construct() { + WP_Filesystem(); + } + + /** + * Import a file into the media library. + * + * @synopsis <filename> [--blog] + */ + function import( $args, $assoc_args = array() ) { + } + /** + * Regenerate thumbnail(s) + * + * @synopsis [--all] [--file=<file>] [--id=<id>] + */ + function regenerate( $args, $assoc_args = array() ) { + + } + +} + +WP_CLI::add_command( 'media', 'Media_Command' ); \ No newline at end of file From 4da5e6199399b4d3f793a2250b430cf2fd57be7d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Feb 2013 11:42:39 -0800 Subject: [PATCH 1137/5359] Output a list of users as CSV or JSON with a new CSV helper utility --- php/commands/user.php | 75 ++++++++++++++++++++++++++++++++----------- php/utils.php | 24 ++++++++++++++ 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index c3cff0cd9..bea3a5c55 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -11,15 +11,16 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * List users. * * @subcommand list - * @synopsis [--role=<role>] [--ids] + * @synopsis [--role=<role>] [--ids] [--format=<format>] */ public function _list( $args, $assoc_args ) { - global $blog_id; - $params = array( - 'blog_id' => $blog_id, - 'fields' => isset( $assoc_args['ids'] ) ? 'ids' : 'all_with_meta', + $defaults = array( + 'blog_id' => get_current_blog_id(), + 'fields' => isset( $assoc_args['ids'] ) ? 'ids' : 'all_with_meta', + 'format' => 'table', ); + $params = array_merge( $defaults, $assoc_args ); if ( array_key_exists( 'role', $assoc_args ) ) { $params['role'] = $assoc_args['role']; @@ -29,29 +30,65 @@ public function _list( $args, $assoc_args ) { if ( isset( $assoc_args['ids'] ) ) { WP_CLI::out( implode( ' ', $users ) ); - } else { - $fields = array('ID', 'user_login', 'display_name', 'user_email', - 'user_registered'); + } + + $fields = array( + 'ID', + 'user_login', + 'display_name', + 'user_email', + 'user_registered' + ); + + switch( $params['format'] ) { + case 'table': + $table = new \cli\Table(); - $table = new \cli\Table(); + $table->setHeaders( array_merge( $fields, array('roles') ) ); - $table->setHeaders( array_merge( $fields, array('roles') ) ); + foreach ( $users as $user ) { + $line = array(); - foreach ( $users as $user ) { - $line = array(); + foreach ( $fields as $field ) { + $line[] = $user->$field; + } + $line[] = implode( ',', $user->roles ); - foreach ( $fields as $field ) { - $line[] = $user->$field; + $table->addRow( $line ); } - $line[] = implode( ',', $user->roles ); - $table->addRow( $line ); - } + $table->display(); + + WP_CLI::line( 'Total: ' . count( $users ) . ' users' ); + break; + case 'json': + $json_users = array(); + + foreach( $users as $user ) { + $json_user = new stdClass; + foreach( $fields as $field ) { + $json_user->$field = $user->$field; + } + $json_users[] = $json_user; + } - $table->display(); + echo json_encode( $json_users ); + break; + case 'csv': + $csv_users = array(); + + foreach( $users as $user ) { + $csv_user = array(); + foreach( $fields as $field ) { + $csv_user[$field] = $user->$field; + } + $csv_users[] = $csv_user; + } - WP_CLI::line( 'Total: ' . count( $users ) . ' users' ); + WP_CLI\Utils\output_csv( $fields, $csv_users ); + break; } + } /** diff --git a/php/utils.php b/php/utils.php index 663c4254d..ad4f16a1b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -233,3 +233,27 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria return $data; } +/** + * Output data as CSV + * + * @param array $headers Headers for the CSV (optional) + * @param array $data Data for each row + */ +function output_csv( $headers = array(), $data = array() ) { + + // Prepare the headers if they were specified + if ( ! empty( $headers ) ) { + echo '"' . implode( '","', $headers ) . '"' . PHP_EOL; + } + + foreach( $data as $row ) { + + if ( ! empty( $headers ) ) { + $build_row = array(); + foreach( $headers as $key ) { + $build_row[] = $row[$key]; + } + } + echo '"' . implode( '","', $row ) . '"' . PHP_EOL; + } +} From 6f46c74196e53cf9923559b0b8a79c574bf658f6 Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Sat, 2 Feb 2013 16:04:16 -0800 Subject: [PATCH 1138/5359] Added initial version of wp scaffold _s --- php/commands/scaffold.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 0061ac571..8a64ab07d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -132,6 +132,40 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) } } + /** + * Generate starter code for a theme. + * + * @synopsis <slug> [--theme_name=<title>] [--author=<full name>] [--author_uri=<http url>] [--activate] + */ + function _s( $args, $assoc_args ) { + + $theme_slug = $args[0]; + $theme_path = WP_CONTENT_DIR . "/themes"; + $data = wp_parse_args( $assoc_args, array( + 'theme_name' => ucfirst( $theme_slug ), + 'author' => "Me", + 'author_uri' => "", + ) ); + $theme_description = "Custom theme ".$data['theme_name']."developed by: ".$data['author']; + $prepare = 'curl -d underscoresme_name="'.$data['theme_name'].'"'; + $prepare .= ' -d underscoresme_slug="'.$theme_slug.'"'; + $prepare .= ' -d underscoresme_author="'.$data['author'].'"'; + $prepare .= ' -d underscoresme_author_uri="'.$data['author_uri'].'"'; + $prepare .= ' -d underscoresme_description="'.$theme_description.'"'; + $prepare .= ' -d underscoresme_generate_submit="Generate"'; + $prepare .= ' -d underscoresme_generate="1"'; + $prepare .= ' http://underscores.me > '.$theme_path.'/underscores.zip'; + $prepare .= ' && unzip -d '.$theme_path.' '.$theme_path.'/underscores.zip && rm '.$theme_path.'/underscores.zip'; + + shell_exec($prepare); // Don't know the WordPress way of doing this. + + WP_CLI::success( "Created Theme: ".$data['theme_name'] ); + + + if ( isset( $assoc_args['activate'] ) ) + WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + } + private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); From cba6678cf88ed0dd3389e3e7ba8dd50f78d972d8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 10:14:18 -0800 Subject: [PATCH 1139/5359] If only --ids are requested, we don't need to do anything else --- php/commands/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/user.php b/php/commands/user.php index bea3a5c55..407b27a71 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -30,6 +30,7 @@ public function _list( $args, $assoc_args ) { if ( isset( $assoc_args['ids'] ) ) { WP_CLI::out( implode( ' ', $users ) ); + exit; } $fields = array( From 4495f7838624c2693b5046ac38d8d445ac2a03ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 10:20:55 -0800 Subject: [PATCH 1140/5359] Simplify the code to generate CSV and JSON output by typecasting. Feels a little dirty, but no harm no fowl. --- php/commands/user.php | 25 ++++++++----------------- php/utils.php | 1 + 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 407b27a71..21f39165c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -63,30 +63,21 @@ public function _list( $args, $assoc_args ) { WP_CLI::line( 'Total: ' . count( $users ) . ' users' ); break; case 'json': - $json_users = array(); - - foreach( $users as $user ) { - $json_user = new stdClass; - foreach( $fields as $field ) { - $json_user->$field = $user->$field; - } - $json_users[] = $json_user; - } - - echo json_encode( $json_users ); - break; case 'csv': - $csv_users = array(); + $output_users = array(); foreach( $users as $user ) { - $csv_user = array(); + $output_user = new stdClass; foreach( $fields as $field ) { - $csv_user[$field] = $user->$field; + $output_user->$field = $user->$field; } - $csv_users[] = $csv_user; + $output_users[] = $output_user; } - WP_CLI\Utils\output_csv( $fields, $csv_users ); + if ( 'json' == $params['format'] ) + echo json_encode( $output_users ); + else + WP_CLI\Utils\output_csv( $fields, $output_users ); break; } diff --git a/php/utils.php b/php/utils.php index ad4f16a1b..63f124715 100644 --- a/php/utils.php +++ b/php/utils.php @@ -247,6 +247,7 @@ function output_csv( $headers = array(), $data = array() ) { } foreach( $data as $row ) { + $row = (array)$row; if ( ! empty( $headers ) ) { $build_row = array(); From 319cfab8f9769fd0843d98a07bd885de24c0d89c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 10:25:17 -0800 Subject: [PATCH 1141/5359] Update man doc --- man-src/user-list.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/man-src/user-list.txt b/man-src/user-list.txt index 68c4eb6a7..90e4ddb20 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -8,3 +8,6 @@ Return only the IDs of the found users, separated by spaces. +* `--format`=<format>: + + Output list as table, CSV or JSON From 4d213b1f493f9e740072ef6d0e1fd16b1fea40d8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 10:51:15 -0800 Subject: [PATCH 1142/5359] Mention default output --- man-src/user-list.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man-src/user-list.txt b/man-src/user-list.txt index 90e4ddb20..f725025c3 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -10,4 +10,4 @@ * `--format`=<format>: - Output list as table, CSV or JSON + Output list as table, CSV or JSON. Defaults to table. From ad58fc9411dbe9e96811d6ff93c42321bdc5c3fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 10:52:02 -0800 Subject: [PATCH 1143/5359] Use the row we built to make sure we're only presenting data that correlates to headers --- php/utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/utils.php b/php/utils.php index 63f124715..f800312f3 100644 --- a/php/utils.php +++ b/php/utils.php @@ -254,6 +254,7 @@ function output_csv( $headers = array(), $data = array() ) { foreach( $headers as $key ) { $build_row[] = $row[$key]; } + $row = $build_row; } echo '"' . implode( '","', $row ) . '"' . PHP_EOL; } From b24c271aadd1d6e1ac279dcfa88bdec35b209730 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 12:23:14 -0800 Subject: [PATCH 1144/5359] Use fputcsv with STDOUT instead of building our own CSV. Props @scribu --- php/utils.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index f800312f3..fa878df3a 100644 --- a/php/utils.php +++ b/php/utils.php @@ -242,9 +242,8 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria function output_csv( $headers = array(), $data = array() ) { // Prepare the headers if they were specified - if ( ! empty( $headers ) ) { - echo '"' . implode( '","', $headers ) . '"' . PHP_EOL; - } + if ( ! empty( $headers ) ) + fputcsv( STDOUT, $headers ); foreach( $data as $row ) { $row = (array)$row; @@ -256,6 +255,6 @@ function output_csv( $headers = array(), $data = array() ) { } $row = $build_row; } - echo '"' . implode( '","', $row ) . '"' . PHP_EOL; + fputcsv( STDOUT, $row ); } } From a0727cb643077f5bba7695321b79208f8c0cfd9c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Feb 2013 22:31:50 +0200 Subject: [PATCH 1145/5359] add some examples for user list and regenerate manpage --- man-src/user-list.txt | 6 ++++++ man/user-list.1 | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/man-src/user-list.txt b/man-src/user-list.txt index f725025c3..8fc98a013 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -11,3 +11,9 @@ * `--format`=<format>: Output list as table, CSV or JSON. Defaults to table. + +## EXAMPLES + + wp user list + + wp user list --role=administrator --format=csv diff --git a/man/user-list.1 b/man/user-list.1 index 2576b9acd..251e9f254 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -wp user list [\-\-role=\fIrole\fR] [\-\-ids] +wp user list [\-\-role=\fIrole\fR] [\-\-ids] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -22,4 +22,20 @@ Only display users with a certain role\. . .IP Return only the IDs of the found users, separated by spaces\. +. +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. +. +.SH "EXAMPLES" +. +.nf + +wp user list + +wp user list \-\-role=administrator \-\-format=csv +. +.fi From 8d2b26235a000b7136b328e9e76185f4d7b0c820 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Feb 2013 22:37:16 +0200 Subject: [PATCH 1146/5359] Reverse parameter order in output_csv() utility ... so that $headers can actually be optional. Also fix coding standards violations. --- php/commands/user.php | 15 +++++++-------- php/utils.php | 15 ++++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 21f39165c..7ded9497d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -34,12 +34,12 @@ public function _list( $args, $assoc_args ) { } $fields = array( - 'ID', - 'user_login', - 'display_name', - 'user_email', - 'user_registered' - ); + 'ID', + 'user_login', + 'display_name', + 'user_email', + 'user_registered' + ); switch( $params['format'] ) { case 'table': @@ -77,10 +77,9 @@ public function _list( $args, $assoc_args ) { if ( 'json' == $params['format'] ) echo json_encode( $output_users ); else - WP_CLI\Utils\output_csv( $fields, $output_users ); + WP_CLI\Utils\output_csv( $output_users, $fields ); break; } - } /** diff --git a/php/utils.php b/php/utils.php index fa878df3a..4e06615c7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -236,25 +236,26 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria /** * Output data as CSV * - * @param array $headers Headers for the CSV (optional) - * @param array $data Data for each row + * @param array $rows Array of rows to output + * @param array $headers List of CSV columns (optional) */ -function output_csv( $headers = array(), $data = array() ) { +function output_csv( $rows, $headers = array() ) { // Prepare the headers if they were specified if ( ! empty( $headers ) ) fputcsv( STDOUT, $headers ); - foreach( $data as $row ) { - $row = (array)$row; + foreach ( $rows as $row ) { + $row = (array) $row; if ( ! empty( $headers ) ) { $build_row = array(); - foreach( $headers as $key ) { - $build_row[] = $row[$key]; + foreach ( $headers as $key ) { + $build_row[] = $row[ $key ]; } $row = $build_row; } fputcsv( STDOUT, $row ); } } + From ef47ed38f5abea346987c59caa26c341a1efd539 Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Mon, 4 Feb 2013 19:40:41 -0800 Subject: [PATCH 1147/5359] Instead of using bash unzip, using WP_CLI native theme install, with optional activate --- php/commands/scaffold.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 8a64ab07d..5e5f466e4 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -141,6 +141,9 @@ function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; + $zip_path = $theme_path.'/underscores.zip'; + $activate = ( isset( $assoc_args['activate'] ) ) ? 1 : 0; + $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", @@ -154,18 +157,15 @@ function _s( $args, $assoc_args ) { $prepare .= ' -d underscoresme_description="'.$theme_description.'"'; $prepare .= ' -d underscoresme_generate_submit="Generate"'; $prepare .= ' -d underscoresme_generate="1"'; - $prepare .= ' http://underscores.me > '.$theme_path.'/underscores.zip'; - $prepare .= ' && unzip -d '.$theme_path.' '.$theme_path.'/underscores.zip && rm '.$theme_path.'/underscores.zip'; - - shell_exec($prepare); // Don't know the WordPress way of doing this. - - WP_CLI::success( "Created Theme: ".$data['theme_name'] ); + $prepare .= ' http://underscores.me > '.$zip_path; + shell_exec($prepare); + + WP_CLI::run_command( array( 'theme', 'install', $zip_path ), array( 'activate' => $activate ) ); - if ( isset( $assoc_args['activate'] ) ) - WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); } + private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); From 99982e5597ead78ed21004773f8fbcc6bee36868 Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Tue, 5 Feb 2013 12:06:43 -0800 Subject: [PATCH 1148/5359] changed shell_exec to properly use wp_remote_post, unzip, and unlink the temp file --- php/commands/scaffold.php | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5e5f466e4..dd8b288e3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -141,27 +141,38 @@ function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; - $zip_path = $theme_path.'/underscores.zip'; - $activate = ( isset( $assoc_args['activate'] ) ) ? 1 : 0; + $url = "http://underscores.me"; $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", 'author_uri' => "", ) ); - $theme_description = "Custom theme ".$data['theme_name']."developed by: ".$data['author']; - $prepare = 'curl -d underscoresme_name="'.$data['theme_name'].'"'; - $prepare .= ' -d underscoresme_slug="'.$theme_slug.'"'; - $prepare .= ' -d underscoresme_author="'.$data['author'].'"'; - $prepare .= ' -d underscoresme_author_uri="'.$data['author_uri'].'"'; - $prepare .= ' -d underscoresme_description="'.$theme_description.'"'; - $prepare .= ' -d underscoresme_generate_submit="Generate"'; - $prepare .= ' -d underscoresme_generate="1"'; - $prepare .= ' http://underscores.me > '.$zip_path; - shell_exec($prepare); + $body['underscoresme_name'] = $data['theme_name']; + $body['underscoresme_slug'] = $theme_slug; + $body['underscoresme_author'] = $data['author']; + $body['underscoresme_author_uri'] = $data['author_uri']; + $body['underscoresme_description'] = $theme_description; + $body['underscoresme_generate_submit'] = "Generate"; + $body['underscoresme_generate'] = "1"; + + // Request Array + $request = array( + 'method' => 'POST', + 'stream' => true, + 'body' => $body, + 'sslverify' => false + ); + + $tmpfname = wp_tempnam($url); + $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); + + unzip_file( $tmpfname, $theme_path ); + unlink($tmpfname); - WP_CLI::run_command( array( 'theme', 'install', $zip_path ), array( 'activate' => $activate ) ); + if ( isset( $assoc_args['activate'] ) ) + WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); } From 59d4752c04ed0e0769d9c8fc0787aaa6cf0f797e Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Tue, 5 Feb 2013 14:17:35 -0800 Subject: [PATCH 1149/5359] added man-src page for scaffold _s, tidied up formatting. --- man-src/scaffold-_s.txt | 21 +++++++++++++++++++++ php/commands/scaffold.php | 12 ++---------- 2 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 man-src/scaffold-_s.txt diff --git a/man-src/scaffold-_s.txt b/man-src/scaffold-_s.txt new file mode 100644 index 000000000..82c57a8ab --- /dev/null +++ b/man-src/scaffold-_s.txt @@ -0,0 +1,21 @@ +## OPTIONS + +* <slug>: + + The slug for the new theme, used for prefixing functions. + +* `--activate`: + + Activate the newly downloaded theme. + +* `--theme_name=<title>`: + + What to put in the 'Theme Name:' header in style.css + +* `--author=<full name>`: + + What to put in the 'Author:' header in style.css + +* `--author_uri=<http url>`: + + What to put in the 'Author URI:' header in style.css \ No newline at end of file diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index dd8b288e3..4597a7c75 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -157,22 +157,14 @@ function _s( $args, $assoc_args ) { $body['underscoresme_generate_submit'] = "Generate"; $body['underscoresme_generate'] = "1"; - // Request Array - $request = array( - 'method' => 'POST', - 'stream' => true, - 'body' => $body, - 'sslverify' => false - ); - $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); unzip_file( $tmpfname, $theme_path ); - unlink($tmpfname); + unlink( $tmpfname ); if ( isset( $assoc_args['activate'] ) ) - WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); } From 89b46de270d7e08f399b2b8638cbe47cd8ec9109 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Feb 2013 23:29:32 +0100 Subject: [PATCH 1150/5359] Merged code from @benmay, would have liked to merge his commit but time aint on my side --- php/commands/media.php | 131 +++++++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 18 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index f1468cc8b..da73d0acf 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -6,27 +6,122 @@ * @package wp-cli */ class Media_Command extends WP_CLI_Command { + var $errors = false; + function __construct() { + WP_Filesystem(); + } - function __construct() { - WP_Filesystem(); - } + /** + * Import a file into the media library. + * + * @synopsis <filename> [--blog] [--zip=<zip>] + */ + function import( $args, $assoc_args = array() ) { + } - /** - * Import a file into the media library. - * - * @synopsis <filename> [--blog] - */ - function import( $args, $assoc_args = array() ) { - } - /** - * Regenerate thumbnail(s) - * - * @synopsis [--all] [--file=<file>] [--id=<id>] - */ - function regenerate( $args, $assoc_args = array() ) { + /** + * Regenerate thumbnail(s) + * + * @synopsis [--all] + * @todo [--file=<file>] [--id=<id>] + */ + function regenerate( $args, $assoc_args = array() ) { + global $wpdb; + + if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { + WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); + return; + } + + WP_CLI::line( 'Found ' . count( $images ) . ' pictures to regenerate!' ); + + foreach ( $images as $image ) + $this->_process_regeneration( $image->ID ); + + if ( $this->errors ) + WP_CLI::error( 'Finished regenerating images - however, there were some errors throughout.' ); + else + WP_CLI::success( 'Finished - without any errors either!' ); + } - } - + private function _process_regeneration( $id ) { + // Don't break the JSON result + @error_reporting( 0 ); + + $image = get_post( $id ); + + if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { + $this->errors = true; + WP_CLI::line( "FAILED: {$image->post_title} - invalid image ID" ); + return; + } + + $fullsizepath = get_attached_file( $image->ID ); + + if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { + $this->errors = true; + WP_CLI::line( "FAILED: {$image->post_title} - Can't find it $fullsizepath" ); + return; + } + + // 5 minutes per image should be PLENTY + @set_time_limit( 900 ); + + $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); + $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); + + $imageFormat = $array_file[ count( $array_file ) - 1 ]; + + unset( $array_path[ count( $array_path ) - 1 ] ); + unset( $array_file[ count( $array_file ) - 1 ] ); + + $imagePath = implode( DIRECTORY_SEPARATOR, $array_path ) . DIRECTORY_SEPARATOR . implode( '.', $array_file ); + + + /** + * Continue + */ + $dirPath = explode( DIRECTORY_SEPARATOR, $imagePath ); + $imageName = sprintf( "%s-", $dirPath[ count( $dirPath ) - 1 ] ); + unset( $dirPath[ count( $dirPath ) - 1 ] ); + $dirPath = sprintf( "%s%s", implode( DIRECTORY_SEPARATOR, $dirPath ), DIRECTORY_SEPARATOR ); + + // Read and delete files + $dir = opendir( $dirPath ); + $files = array(); + while ( $file = readdir( $dir ) ) { + if ( !( strrpos( $file, $imageName ) === false ) ) { + $thumbnail = explode( $imageName, $file ); + if ( $thumbnail[ 0 ] == "" ) { + $thumbnailFormat = substr( $thumbnail[ 1 ], -4 ); + $thumbnail = substr( $thumbnail[ 1 ], 0, strlen( $thumbnail[ 1 ] ) - 4 ); + $thumbnail = explode( 'x', $thumbnail ); + if ( count( $thumbnail ) == 2 ) { + if ( is_numeric( $thumbnail[ 0 ] ) && is_numeric( $thumbnail[ 1 ] ) ) { + WP_CLI::line( "Thumbnail: {$thumbnail[0]} x {$thumbnail[1]} was deleted." ); + @unlink( $dirPath . $imageName . $thumbnail[ 0 ] . 'x' . $thumbnail[ 1 ] . $thumbnailFormat ); + } + } + } + } + } + + $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); + + if ( is_wp_error( $metadata ) ) { + WP_CLI::line( $metadata->get_error_message() ); + return; + } + + if ( empty( $metadata ) ) { + $this->errors = true; + WP_CLI::line( 'Unknown failure reason.' ); + return; + } + wp_update_attachment_metadata( $image->ID, $metadata ); + WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds " ); + } + } WP_CLI::add_command( 'media', 'Media_Command' ); \ No newline at end of file From 5244e2a29b3009aa165a9507ff79bb168cf16e23 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Feb 2013 23:30:22 +0100 Subject: [PATCH 1151/5359] Cleaned up error --- php/commands/media.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index da73d0acf..0ded0a2b4 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -22,12 +22,13 @@ function import( $args, $assoc_args = array() ) { /** * Regenerate thumbnail(s) * - * @synopsis [--all] + * @synopsis [--all] * @todo [--file=<file>] [--id=<id>] + * props @benmay */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - + if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); return; From eefef9d7b001031c34c8ed8a2b8208cfe4fe81ef Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 6 Feb 2013 00:35:28 +0100 Subject: [PATCH 1152/5359] Added the regenerate --id= --- php/commands/media.php | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 0ded0a2b4..f80ac4f66 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -22,15 +22,28 @@ function import( $args, $assoc_args = array() ) { /** * Regenerate thumbnail(s) * - * @synopsis [--all] - * @todo [--file=<file>] [--id=<id>] + * @synopsis [--id=<id>] + * @todo [--file=<file>] * props @benmay */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { - WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); + $vars = wp_parse_args( $assoc_args, array( + 'id' => false, + ) ); + + extract($vars, EXTR_SKIP); + + $where_clause = ( $id ) ? "AND ID = $id" : 'bla'; + + if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { + if ( $id ) { + WP_CLI::error( "Unable to find the image. Are you sure some it exists?" ); + } else { + WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); + } + return; } @@ -122,6 +135,18 @@ private function _process_regeneration( $id ) { wp_update_attachment_metadata( $image->ID, $metadata ); WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds " ); } + + protected function extract_args( $assoc_args, $defaults ) { + $out = array(); + + foreach ( $defaults as $key => $value ) { + $out[ $key ] = isset( $assoc_args[ $key ] ) + ? $assoc_args[ $key ] + : $value; + } + + return $out; + } } From a98c6bbc9aa98e82bf7ac7ce76a5e615a04101ae Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 6 Feb 2013 00:38:37 +0100 Subject: [PATCH 1153/5359] Removed unused coded and the bla --- php/commands/media.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index f80ac4f66..f612cf80f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -35,7 +35,7 @@ function regenerate( $args, $assoc_args = array() ) { extract($vars, EXTR_SKIP); - $where_clause = ( $id ) ? "AND ID = $id" : 'bla'; + $where_clause = ( $id ) ? "AND ID = $id" : ''; if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { if ( $id ) { @@ -135,19 +135,6 @@ private function _process_regeneration( $id ) { wp_update_attachment_metadata( $image->ID, $metadata ); WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds " ); } - - protected function extract_args( $assoc_args, $defaults ) { - $out = array(); - - foreach ( $defaults as $key => $value ) { - $out[ $key ] = isset( $assoc_args[ $key ] ) - ? $assoc_args[ $key ] - : $value; - } - - return $out; - } - } WP_CLI::add_command( 'media', 'Media_Command' ); \ No newline at end of file From c292153e47b17f57576728979ea7ac5cc7e5c59a Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Tue, 5 Feb 2013 16:45:44 -0800 Subject: [PATCH 1154/5359] added default timeout and generic theme description from author and theme name. --- php/commands/scaffold.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4597a7c75..bb7f473ab 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -142,13 +142,15 @@ function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; $url = "http://underscores.me"; + $theme_description = "Custom theme: ".$data['theme_name']." developed by, ".$data['author']; + $timeout = 30; $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", 'author_uri' => "", ) ); - + $body['underscoresme_name'] = $data['theme_name']; $body['underscoresme_slug'] = $theme_slug; $body['underscoresme_author'] = $data['author']; From fa2229fe06ad7bebbf71ef21824bc615728e5e7e Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Tue, 5 Feb 2013 18:06:18 -0800 Subject: [PATCH 1155/5359] removed spaces in the synopsis --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index bb7f473ab..23067d53c 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -135,7 +135,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) /** * Generate starter code for a theme. * - * @synopsis <slug> [--theme_name=<title>] [--author=<full name>] [--author_uri=<http url>] [--activate] + * @synopsis <slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--activate] */ function _s( $args, $assoc_args ) { From f8ebaf6f92d97a3e16d38ba6d06662ca3602418e Mon Sep 17 00:00:00 2001 From: Jaime Martinez <jmslbam@gmail.com> Date: Wed, 6 Feb 2013 18:16:42 +0100 Subject: [PATCH 1156/5359] Changed filename from machinename to slug Because `wp scaffold post-type jm-foo` scaffolds a file name jm_foo.php bacause the machinename hyphens get replaced by underscores. Same behaviour as the plugin scaffold. Hyphens should separate words. --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 0061ac571..06378544d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -121,7 +121,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) } if ( $path = $this->get_output_path( $control_args, $subdir ) ) { - $filename = $path . $machine_name .'.php'; + $filename = $path . $slug .'.php'; $this->create_file( $filename, $final_output ); From 6451d4af9d9e1b3eb2178135fe85c222f70049ce Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Wed, 6 Feb 2013 09:20:46 -0800 Subject: [PATCH 1157/5359] fixed undefined variables --- php/commands/scaffold.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 23067d53c..baf9e8bed 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -142,7 +142,6 @@ function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; $url = "http://underscores.me"; - $theme_description = "Custom theme: ".$data['theme_name']." developed by, ".$data['author']; $timeout = 30; $data = wp_parse_args( $assoc_args, array( @@ -151,6 +150,8 @@ function _s( $args, $assoc_args ) { 'author_uri' => "", ) ); + $theme_description = "Custom theme: ".$data['theme_name']." developed by, ".$data['author']; + $body['underscoresme_name'] = $data['theme_name']; $body['underscoresme_slug'] = $theme_slug; $body['underscoresme_author'] = $data['author']; From ecf4f74cfc9be7aa61a66cecff1c41f98ca33a80 Mon Sep 17 00:00:00 2001 From: Brandon Lavigne <B@Brandons-Mac-Pro-4.local> Date: Wed, 6 Feb 2013 09:51:21 -0800 Subject: [PATCH 1158/5359] added success message if remote request code is 200 --- php/commands/scaffold.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index baf9e8bed..662fedeed 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -163,6 +163,9 @@ function _s( $args, $assoc_args ) { $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); + if ( $response['response']['code'] == 200 ) + WP_CLI::success( "Created theme '".$data['theme_name']."'." ); + unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); From 4a71b8cadd0b03ce84dfe3606b7b49758fa69d2d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Feb 2013 20:04:00 +0200 Subject: [PATCH 1159/5359] generate manpage for scaffold _s. see #285 --- man/scaffold-_s.1 | 43 +++++++++++++++++++++++++++++++++++++++++++ php/man.php | 1 + 2 files changed, 44 insertions(+) create mode 100644 man/scaffold-_s.1 diff --git a/man/scaffold-_s.1 b/man/scaffold-_s.1 new file mode 100644 index 000000000..d6ee0407c --- /dev/null +++ b/man/scaffold-_s.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-_S" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-_s\fR \- Generate starter code for a theme\. +. +.SH "SYNOPSIS" +wp scaffold _s \fIslug\fR [\-\-theme_name=\fItitle\fR] [\-\-author=\fIfull\-name\fR] [\-\-author_uri=\fIhttp\-url\fR] [\-\-activate] +. +.SH "OPTIONS" +. +.TP +\fIslug\fR: +. +.IP +The slug for the new theme, used for prefixing functions\. +. +.TP +\fB\-\-activate\fR: +. +.IP +Activate the newly downloaded theme\. +. +.TP +\fB\-\-theme_name=<title>\fR: +. +.IP +What to put in the \'Theme Name:\' header in style\.css +. +.TP +\fB\-\-author=<full name>\fR: +. +.IP +What to put in the \'Author:\' header in style\.css +. +.TP +\fB\-\-author_uri=<http url>\fR: +. +.IP +What to put in the \'Author URI:\' header in style\.css + diff --git a/php/man.php b/php/man.php index 64f9fd69b..e2578fc8f 100644 --- a/php/man.php +++ b/php/man.php @@ -54,6 +54,7 @@ function add_initial_markdown( $fd, $command ) { $shortdesc = $command->get_shortdesc(); $synopsis = $command->get_full_synopsis(); + $synopsis = str_replace( '_', '\_', $synopsis ); $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); $name_m = implode( '-', $path ); From cd8fd14b185b9c283085b35fdfbeb41b93cdb824 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Feb 2013 20:08:38 +0200 Subject: [PATCH 1160/5359] regenerate some manpages --- man/eval-file.1 | 2 +- man/eval.1 | 2 +- man/export.1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/eval-file.1 b/man/eval-file.1 index b6aecb6c4..fc8fb2caf 100644 --- a/man/eval-file.1 +++ b/man/eval-file.1 @@ -4,7 +4,7 @@ .TH "WP\-EVAL\-FILE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-eval\-file\fR \- Loads and executes a PHP file after loading WordPress\. +\fBwp\-eval\-file\fR \- Load and execute a PHP file after loading WordPress\. . .SH "SYNOPSIS" wp eval\-file \fIpath\fR diff --git a/man/eval.1 b/man/eval.1 index 190f61c1d..644451e32 100644 --- a/man/eval.1 +++ b/man/eval.1 @@ -4,7 +4,7 @@ .TH "WP\-EVAL" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-eval\fR \- Executes arbitrary PHP code after loading WordPress\. +\fBwp\-eval\fR \- Execute arbitrary PHP code after loading WordPress\. . .SH "SYNOPSIS" wp eval \fIphp\-code\fR diff --git a/man/export.1 b/man/export.1 index 17d770ab3..a11fc78cb 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,7 +7,7 @@ \fBwp\-export\fR \- Export content to a WXR file\. . .SH "SYNOPSIS" -wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post\fI\fIin=\fRpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] +wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post__in=\fIpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] . .SH "OPTIONS" . From f93b73ca35350e48c727fc5a6862d3f7e2c31b33 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 7 Feb 2013 03:14:50 +0200 Subject: [PATCH 1161/5359] move /templates/ out of /php/ since it doesn't contain PHP files --- php/commands/scaffold.php | 4 ++-- {php/templates => templates}/plugin.mustache | 0 {php/templates => templates}/post_type.mustache | 0 {php/templates => templates}/post_type_extended.mustache | 0 {php/templates => templates}/taxonomy.mustache | 0 {php/templates => templates}/taxonomy_extended.mustache | 0 6 files changed, 2 insertions(+), 2 deletions(-) rename {php/templates => templates}/plugin.mustache (100%) rename {php/templates => templates}/post_type.mustache (100%) rename {php/templates => templates}/post_type_extended.mustache (100%) rename {php/templates => templates}/taxonomy.mustache (100%) rename {php/templates => templates}/taxonomy_extended.mustache (100%) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 0b5c13771..08996cdec 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,7 +162,7 @@ function _s( $args, $assoc_args ) { $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); - + if ( $response['response']['code'] == 200 ) WP_CLI::success( "Created theme '".$data['theme_name']."'." ); @@ -315,7 +315,7 @@ protected function extract_args( $assoc_args, $defaults ) { } private function render( $template, $data ) { - $scaffolds_dir = WP_CLI_ROOT . 'templates'; + $scaffolds_dir = WP_CLI_ROOT . '../templates'; $template = file_get_contents( $scaffolds_dir . '/' . $template ); diff --git a/php/templates/plugin.mustache b/templates/plugin.mustache similarity index 100% rename from php/templates/plugin.mustache rename to templates/plugin.mustache diff --git a/php/templates/post_type.mustache b/templates/post_type.mustache similarity index 100% rename from php/templates/post_type.mustache rename to templates/post_type.mustache diff --git a/php/templates/post_type_extended.mustache b/templates/post_type_extended.mustache similarity index 100% rename from php/templates/post_type_extended.mustache rename to templates/post_type_extended.mustache diff --git a/php/templates/taxonomy.mustache b/templates/taxonomy.mustache similarity index 100% rename from php/templates/taxonomy.mustache rename to templates/taxonomy.mustache diff --git a/php/templates/taxonomy_extended.mustache b/templates/taxonomy_extended.mustache similarity index 100% rename from php/templates/taxonomy_extended.mustache rename to templates/taxonomy_extended.mustache From b590c7eceae68e2e788a97bc0644cf259414e55c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Feb 2013 00:19:34 +0200 Subject: [PATCH 1162/5359] add test case --- tests/abstract-spec.php | 14 ++++++++++++-- tests/spec-core.php | 18 +++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index e49239ddb..6a40f9b74 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -15,9 +15,13 @@ private static function run_sql( $sql ) { exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); } - protected function setUp() { + protected function tearDown() { + $dbname = self::$db_settings['dbname']; + $this->run_sql( "DROP DATABASE IF EXISTS $dbname" ); + } + + private function create_db() { $dbname = self::$db_settings['dbname']; - $this->run_sql( "DROP DATABASE $dbname" ); $this->run_sql( "CREATE DATABASE $dbname" ); } @@ -28,6 +32,11 @@ public function runGiven( &$world, $action, $arguments ) { } break; + case 'database': { + $this->create_db(); + } + break; + case 'wp files': { $world['runner']->download_wordpress_files(); } @@ -39,6 +48,7 @@ public function runGiven( &$world, $action, $arguments ) { break; case 'wp install': { + $this->create_db(); $world['runner']->download_wordpress_files(); $world['runner']->create_config( self::$db_settings ); $world['runner']->run_install(); diff --git a/tests/spec-core.php b/tests/spec-core.php index adb4c574d..0824a401e 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -30,12 +30,28 @@ public function noWpConfig() { ->then( 'return code should be', 0 ); } + /** @scenario */ + public function dbDoesntExist() { + $this + ->given( 'empty dir' ) + ->and( 'wp files' ) + ->and( 'wp config' ) + + ->when( 'invoking', 'wp' ) + ->then( 'return code should be', 1 ) + ->and( 'output should be', "Error: Can't connect to the database." ) + + ->when( 'invoking', 'db create' ) + ->then( 'return code should be', 0 ); + } + /** @scenario */ public function dbTablesNotInstalled() { $this ->given( 'empty dir' ) ->and( 'wp files' ) ->and( 'wp config' ) + ->and( 'database' ) ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 1 ) @@ -47,7 +63,7 @@ public function dbTablesNotInstalled() { ->then( 'return code should be', 0 ) ->when( 'invoking', 'post list --ids' ) - ->then( 'output should be', 1 ); + ->then( 'output should be', "1" ); } /** @scenario */ From cd542d30d3580131a9619e76b0f11b849794e8fd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Feb 2013 00:21:55 +0200 Subject: [PATCH 1163/5359] make 'wp install' imply 'empty dir' --- tests/abstract-spec.php | 1 + tests/spec-core.php | 6 ++---- tests/spec-flags.php | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 6a40f9b74..1e438b945 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -49,6 +49,7 @@ public function runGiven( &$world, $action, $arguments ) { case 'wp install': { $this->create_db(); + $world['runner'] = new WP_CLI_Command_Runner; $world['runner']->download_wordpress_files(); $world['runner']->create_config( self::$db_settings ); $world['runner']->run_install(); diff --git a/tests/spec-core.php b/tests/spec-core.php index 0824a401e..8913a448e 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -69,8 +69,7 @@ public function dbTablesNotInstalled() { /** @scenario */ public function fullInstall() { $this - ->given( 'empty dir' ) - ->and( 'wp install' ) + ->given( 'wp install' ) ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 0 ); @@ -79,8 +78,7 @@ public function fullInstall() { /** @scenario */ public function customWpContentDir() { $this - ->given( 'empty dir' ) - ->and( 'wp install' ) + ->given( 'wp install' ) ->and( 'custom wp-content dir' ) ->when( 'invoking', 'theme status twentytwelve' ) diff --git a/tests/spec-flags.php b/tests/spec-flags.php index 6ca84276b..79bd5fc41 100644 --- a/tests/spec-flags.php +++ b/tests/spec-flags.php @@ -5,8 +5,7 @@ class FlagsSpec extends WP_CLI_Spec { /** @scenario */ public function quietRun() { $this - ->given( 'empty dir' ) - ->and( 'wp install' ) + ->given( 'wp install' ) ->when( 'invoking', '' ) ->then( 'return code should be', 0 ) From 14f7085497670ce74008fd4cb08f34d9daf7540a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Feb 2013 02:28:07 +0200 Subject: [PATCH 1164/5359] add our own wp_die() handler --- php/utils-wp.php | 19 +++++++++++++++++++ php/wp-settings-cli.php | 2 ++ tests/spec-core.php | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index 0fb19ff06..4609617a5 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -21,6 +21,25 @@ function wp_debug_mode() { } } +function replace_wp_die_handler() { + \remove_filter( 'wp_die_handler', '_default_wp_die_handler' ); + \add_filter( 'wp_die_handler', function() { return __NAMESPACE__ . '\\' . 'wp_die_handler'; } ); +} + +function wp_die_handler( $message ) { + if ( is_wp_error( $message ) ) { + $message = $message->get_error_message(); + } + + if ( preg_match( '|^\<h1>(.+?)</h1>|', $message, $matches ) ) { + $message = $matches[1]; + } + + $message = html_entity_decode( $message ); + + \WP_CLI::error( $message ); +} + function maybe_require( $since, $path ) { global $wp_version; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 7855768a5..e58ea0d83 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -56,6 +56,8 @@ require( ABSPATH . WPINC . '/plugin.php' ); require( ABSPATH . WPINC . '/pomo/mo.php' ); +Utils\replace_wp_die_handler(); + // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); diff --git a/tests/spec-core.php b/tests/spec-core.php index 8913a448e..95b3fce5f 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -39,7 +39,7 @@ public function dbDoesntExist() { ->when( 'invoking', 'wp' ) ->then( 'return code should be', 1 ) - ->and( 'output should be', "Error: Can't connect to the database." ) + ->and( 'output should be', "Error: Can’t select database\n" ) ->when( 'invoking', 'db create' ) ->then( 'return code should be', 0 ); From 44cfc2a99514fce23179375322cbccb9f8d3e78b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Feb 2013 03:12:09 +0200 Subject: [PATCH 1165/5359] tests: separate stdout from stderr The more precise assertions expose several buggy tests. Also reverts WP_CLI::error() second parameter to $label, since sending the first line to STDERR and subsequent ones to STDOUT is confusing. If you want to have a multiline error message, just insert \n characters. --- php/WP_CLI/Runner.php | 6 +++--- php/class-wp-cli.php | 5 ++--- php/utils-wp.php | 6 +++--- tests/abstract-spec.php | 13 ++++++++++--- tests/command-runner.php | 20 +++++++++++++++----- tests/spec-core.php | 15 +++++++++------ tests/spec-flags.php | 8 +++++--- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ce1287e7e..7dbd8637d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -244,9 +244,9 @@ public function before_wp_load() { } if ( !Utils\locate_wp_config() ) { - WP_CLI::error( "wp-config.php not found.", false ); - WP_CLI::line( "Either create one manually or use `wp core config`." ); - exit(1); + WP_CLI::error( + "wp-config.php not found.\n" . + "Either create one manually or use `wp core config`." ); } if ( $this->cmd_starts_with( array( 'db' ) ) ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 884327447..02f65c21b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -128,11 +128,10 @@ static function line( $message = '' ) { * Display an error in the CLI and end with a newline * * @param string $message - * @param bool $exit + * @param string $label */ - static function error( $message, $exit = true ) { + static function error( $message, $label = 'Error' ) { if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { - $label = 'Error'; $msg = '%R' . $label . ': %n' . self::error_to_string( $message ) . "\n"; fwrite( STDERR, \cli\Colors::colorize( $msg, self::get_config('color') ) ); } diff --git a/php/utils-wp.php b/php/utils-wp.php index 4609617a5..2153d3fee 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -6,9 +6,9 @@ function wp_not_installed() { if ( !is_blog_installed() && !defined( 'WP_INSTALLING' ) ) { - \WP_CLI::error( 'The site you have requested is not installed.', false ); - \WP_CLI::line( 'Run `wp core install`.' ); - exit( 1 ); + \WP_CLI::error( + "The site you have requested is not installed.\n" . + 'Run `wp core install`.' ); } } diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 1e438b945..08a1e27ad 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -103,13 +103,20 @@ public function runThen( &$world, $action, $arguments ) { } break; - case 'output should be': { - $this->assertEquals( $arguments[0], $world['result']->output, $action ); + case 'stdout': { + $this->assertEquals( $arguments[0], $world['result']->stdout, $action ); + } + break; + + case 'stderr': { + $this->assertEquals( $arguments[0], $world['result']->stderr, $action ); } break; case 'should have output': { - $this->assertNotEmpty( $world['result']->output, $action ); + if ( empty( $world['result']->stdout ) ) + var_dump($world['result']); + $this->assertNotEmpty( $world['result']->stdout, $action ); } break; diff --git a/tests/command-runner.php b/tests/command-runner.php index a54cd7f19..3901991ac 100644 --- a/tests/command-runner.php +++ b/tests/command-runner.php @@ -15,13 +15,23 @@ public function run( $command, $cwd = false ) { $wp_cli_path = getcwd() . "/bin/wp"; - $sh_command = "cd $cwd; $wp_cli_path $command 2>&1;"; + $sh_command = "cd $cwd; $wp_cli_path $command"; - ob_start(); - system( $sh_command, $return_code ); - $output = ob_get_clean(); + $process = proc_open( $sh_command, array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ), $pipes ); - return (object) compact( 'return_code', 'output' ); + $stdout = stream_get_contents( $pipes[1] ); + fclose( $pipes[1] ); + + $stderr = stream_get_contents( $pipes[2] ); + fclose( $pipes[2] ); + + $return_code = proc_close( $process ); + + return (object) compact( 'return_code', 'stdout', 'stderr' ); } public function create_config( $db_settings ) { diff --git a/tests/spec-core.php b/tests/spec-core.php index 95b3fce5f..90a83bdaf 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -21,7 +21,7 @@ public function noWpConfig() { ->then( 'return code should be', 1 ) ->when( 'invoking', 'core install' ) - ->then( 'output should be', + ->then( 'stderr', "Error: wp-config.php not found.\n" . "Either create one manually or use `wp core config`.\n" ) @@ -37,9 +37,9 @@ public function dbDoesntExist() { ->and( 'wp files' ) ->and( 'wp config' ) - ->when( 'invoking', 'wp' ) + ->when( 'invoking', '' ) ->then( 'return code should be', 1 ) - ->and( 'output should be', "Error: Can’t select database\n" ) + ->and( 'stderr', "Error: Can’t select database\n" ) ->when( 'invoking', 'db create' ) ->then( 'return code should be', 0 ); @@ -56,14 +56,17 @@ public function dbTablesNotInstalled() { ->when( 'invoking', 'core is-installed' ) ->then( 'return code should be', 1 ) - ->when( 'invoking', 'help' ) - ->then( 'should have output' ) + ->when( 'invoking', '' ) + ->then( 'stderr', + "Error: The site you have requested is not installed.\n" . + "Run `wp core install`.\n" + ) ->when( 'invoking', 'core install' ) ->then( 'return code should be', 0 ) ->when( 'invoking', 'post list --ids' ) - ->then( 'output should be', "1" ); + ->then( 'stdout', "1" ); } /** @scenario */ diff --git a/tests/spec-flags.php b/tests/spec-flags.php index 79bd5fc41..c720fda61 100644 --- a/tests/spec-flags.php +++ b/tests/spec-flags.php @@ -13,11 +13,13 @@ public function quietRun() { ->when( 'invoking', '--quiet' ) ->then( 'return code should be', 0 ) - ->and( 'output should be', '' ) + ->and( 'stdout', '' ) - ->when( 'invoking', 'wp non-existing-command --quiet' ) + ->when( 'invoking', 'non-existing-command --quiet' ) ->then( 'return code should be', 1 ) - ->and( 'should have output' ); + ->and( 'stderr', + "Error: 'non-existing-command' is not a registered wp command. See 'wp help'.\n" + ); } } From 9782a3490126dbb2a0a756b00772a8443e8b1a4c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Feb 2013 04:14:44 +0200 Subject: [PATCH 1166/5359] fix WP_CLI::error() not exiting --- php/class-wp-cli.php | 3 +-- tests/spec-core.php | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 02f65c21b..ad70c61c1 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -136,8 +136,7 @@ static function error( $message, $label = 'Error' ) { fwrite( STDERR, \cli\Colors::colorize( $msg, self::get_config('color') ) ); } - if ( $exit ) - exit(1); + exit(1); } /** diff --git a/tests/spec-core.php b/tests/spec-core.php index 90a83bdaf..d7dab9ed4 100644 --- a/tests/spec-core.php +++ b/tests/spec-core.php @@ -40,6 +40,7 @@ public function dbDoesntExist() { ->when( 'invoking', '' ) ->then( 'return code should be', 1 ) ->and( 'stderr', "Error: Can’t select database\n" ) + ->and( 'stdout', '' ) ->when( 'invoking', 'db create' ) ->then( 'return code should be', 0 ); From 131943b36753e001f1c555df055b4f183d63d09d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 15:00:30 -0800 Subject: [PATCH 1167/5359] A term command with subcommands for creating, updating, deleting and listing taxonomy terms --- php/commands/term.php | 153 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 php/commands/term.php diff --git a/php/commands/term.php b/php/commands/term.php new file mode 100644 index 000000000..c52db45be --- /dev/null +++ b/php/commands/term.php @@ -0,0 +1,153 @@ +<?php +/** + * Manage terms. + * + * @package wp-cli + */ +class Term_Command extends WP_CLI_Command { + + /** + * List terms in a taxonomy. + * + * @subcommand list + * @synopsis <taxonomy> [--format=<format>] + */ + public function _list( $args, $assoc_args ) { + + list( $taxonomy ) = $args; + + $defaults = array( + 'format' => 'table', + 'hide_empty' => false, + ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + + $terms = get_terms( array( $taxonomy ), $assoc_args ); + + $fields = array( + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', + ); + + switch ( $assoc_args['format'] ) { + case 'table': + $table = new \cli\Table(); + + $table->setHeaders( $fields ); + + foreach ( $terms as $term ) { + $line = array(); + + foreach ( $fields as $field ) { + $line[] = $term->$field; + } + + $table->addRow( $line ); + } + + $table->display(); + + WP_CLI::line( 'Total: ' . count( $terms ) . ' terms.' ); + break; + case 'csv': + case 'json': + $output_terms = array(); + + foreach( $terms as $term ) { + $output_term = new stdClass; + foreach( $fields as $field ) { + $output_term->$field = $term->$field; + } + $output_terms[] = $output_term; + } + + if ( 'json' == $assoc_args['format'] ) + echo json_encode( $output_terms ); + else + WP_CLI\Utils\output_csv( $output_terms, $fields ); + break; + } + + } + + /** + * Create a term. + * + * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] + */ + public function create( $args, $assoc_args ) { + + list( $term, $taxonomy ) = $args; + + $defaults = array( + 'slug' => sanitize_title( $term ), + 'description' => '', + ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + + $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); + + if ( is_wp_error( $ret ) ) + WP_CLI::error( $ret->get_error_message() ); + else + WP_CLI::success( "Term created." ); + } + + /** + * Update a term. + * + * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<parent>] + */ + public function update( $args, $assoc_args ) { + + list( $term_id, $taxonomy ) = $args; + + $defaults = array( + 'name' => null, + 'slug' => null, + 'description' => null, + 'parent' => null, + ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + + foreach( $assoc_args as $key => $value ) { + if ( is_null( $value ) ) + unset( $assoc_args[$key] ); + } + + $ret = wp_update_term( $term_id, $taxonomy, $assoc_args ); + + if ( is_wp_error( $ret ) ) + WP_CLI::error( $ret->get_error_message() ); + else + WP_CLI::success( "Term updated." ); + + } + + /** + * Delete a term. + * + * @synopsis <term-id> <taxonomy> + */ + public function delete( $args ) { + + list( $term_id, $taxonomy ) = $args; + + $ret = wp_delete_term( $term_id, $taxonomy ); + + if ( is_wp_error( $ret ) ) + WP_CLI::error( $ret->get_error_message() ); + else if ( $ret ) + WP_CLI::success( "Term deleted." ); + else + WP_CLI::error( "Error deleting term." ); + } + +} + +WP_CLI::add_command( 'term', 'Term_Command' ); \ No newline at end of file From fc211aeba0840796b1320a99cc3ee0a85a338edf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 15:31:14 -0800 Subject: [PATCH 1168/5359] Abstract output of data to a format_items() utility function --- php/commands/term.php | 40 +----------------------------------- php/utils.php | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c52db45be..d6c9ffb34 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -34,45 +34,7 @@ public function _list( $args, $assoc_args ) { 'count', ); - switch ( $assoc_args['format'] ) { - case 'table': - $table = new \cli\Table(); - - $table->setHeaders( $fields ); - - foreach ( $terms as $term ) { - $line = array(); - - foreach ( $fields as $field ) { - $line[] = $term->$field; - } - - $table->addRow( $line ); - } - - $table->display(); - - WP_CLI::line( 'Total: ' . count( $terms ) . ' terms.' ); - break; - case 'csv': - case 'json': - $output_terms = array(); - - foreach( $terms as $term ) { - $output_term = new stdClass; - foreach( $fields as $field ) { - $output_term->$field = $term->$field; - } - $output_terms[] = $output_term; - } - - if ( 'json' == $assoc_args['format'] ) - echo json_encode( $output_terms ); - else - WP_CLI\Utils\output_csv( $output_terms, $fields ); - break; - } - + WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); } /** diff --git a/php/utils.php b/php/utils.php index 4e06615c7..10b7604c3 100644 --- a/php/utils.php +++ b/php/utils.php @@ -233,6 +233,53 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria return $data; } +/** + * Output items in a table, JSON, or CSV + * + * @param string $format Format to use: 'table', 'json', 'csv' + * @param array $fields Named fields for each item of data + * @param array $items Data to output + */ +function format_items( $format, $fields, $items ) { + + switch ( $format ) { + case 'table': + $table = new \cli\Table(); + + $table->setHeaders( $fields ); + + foreach ( $items as $item ) { + $line = array(); + + foreach ( $fields as $field ) { + $line[] = $item->$field; + } + + $table->addRow( $line ); + } + + $table->display(); + break; + case 'csv': + case 'json': + $output_items = array(); + + foreach( $items as $item ) { + $output_item = new \stdClass; + foreach( $fields as $field ) { + $output_item->$field = $item->$field; + } + $output_items[] = $output_item; + } + + if ( 'json' == $format ) + echo json_encode( $output_items ); + else + output_csv( $output_items, $fields ); + break; + } +} + /** * Output data as CSV * From 8ace75225c7868deec378e0cf51e20f0add23964 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 16:34:57 -0800 Subject: [PATCH 1169/5359] Man pages --- man-src/term-create.txt | 21 +++++++++++++++++++++ man-src/term-delete.txt | 13 +++++++++++++ man-src/term-list.txt | 13 +++++++++++++ man-src/term-update.txt | 29 +++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 man-src/term-create.txt create mode 100644 man-src/term-delete.txt create mode 100644 man-src/term-list.txt create mode 100644 man-src/term-update.txt diff --git a/man-src/term-create.txt b/man-src/term-create.txt new file mode 100644 index 000000000..19fe84d8e --- /dev/null +++ b/man-src/term-create.txt @@ -0,0 +1,21 @@ +## OPTIONS + +* `<term>`: + + A name for the new term. + +* `<taxonomy>`: + + Taxonomy for the new term. + +* `--slug`=<slug>: + + A unique slug for the new term. Defaults to sanitized version of name. + +* `--description`=<description>: + + A description for the new term. + +## EXAMPLES + + wp term create Apple category --description="A type of fruit" \ No newline at end of file diff --git a/man-src/term-delete.txt b/man-src/term-delete.txt new file mode 100644 index 000000000..03f23097d --- /dev/null +++ b/man-src/term-delete.txt @@ -0,0 +1,13 @@ +## OPTIONS + +* `<term-id>`: + + ID for the term to delete. + +* `<taxonomy>`: + + Taxonomy of the term to delete. + +## EXAMPLES + + wp term delete 15 category \ No newline at end of file diff --git a/man-src/term-list.txt b/man-src/term-list.txt new file mode 100644 index 000000000..f991f2558 --- /dev/null +++ b/man-src/term-list.txt @@ -0,0 +1,13 @@ +## OPTIONS + +* `<taxonomy>`: + + List terms of a given taxonomy. + +* `--format`=<format>: + + Output list as table, CSV or JSON. Defaults to table. + +## EXAMPLES + + wp term list category --format=csv \ No newline at end of file diff --git a/man-src/term-update.txt b/man-src/term-update.txt new file mode 100644 index 000000000..82ae9a113 --- /dev/null +++ b/man-src/term-update.txt @@ -0,0 +1,29 @@ +## OPTIONS + +* `<term-id>`: + + ID for the term to update. + +* `<taxonomy>`: + + Taxonomy of the term to update. + +* `--name`=<name>: + + A new name for the term. + +* `--slug`=<slug>: + + A new slug for the term. + +* `--description`=<description>: + + A new description for the term. + +* `--parent`=<parent>: + + A new parent for the term. + +## EXAMPLES + + wp term update 15 category --name=Apple \ No newline at end of file From 669849fdd3fadd8510edcb409635ea8373dc5568 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Feb 2013 18:40:19 -0800 Subject: [PATCH 1170/5359] Accept a parent when creating a new term --- man-src/term-create.txt | 4 ++++ php/commands/term.php | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/man-src/term-create.txt b/man-src/term-create.txt index 19fe84d8e..31ca3a4ee 100644 --- a/man-src/term-create.txt +++ b/man-src/term-create.txt @@ -16,6 +16,10 @@ A description for the new term. +* `--parent`=<parent>: + + A parent for the new term. + ## EXAMPLES wp term create Apple category --description="A type of fruit" \ No newline at end of file diff --git a/php/commands/term.php b/php/commands/term.php index d6c9ffb34..888ef2da5 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -40,7 +40,7 @@ public function _list( $args, $assoc_args ) { /** * Create a term. * - * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] + * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<parent>] */ public function create( $args, $assoc_args ) { @@ -49,6 +49,7 @@ public function create( $args, $assoc_args ) { $defaults = array( 'slug' => sanitize_title( $term ), 'description' => '', + 'parent' => '', ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); From f5f1ff1f38990c8d34f4a6736c585272972a2b1c Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Sun, 10 Feb 2013 11:53:33 +0100 Subject: [PATCH 1171/5359] Fix error output if no WordPress install exists --- php/WP_CLI/Runner.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7dbd8637d..1daa7ef48 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -233,9 +233,9 @@ public function before_wp_load() { } if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { - WP_CLI::error( "This does not seem to be a WordPress install.", false ); - WP_CLI::line( "Pass --path=`path/to/wordpress` or run `wp core download`." ); - exit(1); + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); } if ( array( 'core', 'config' ) == $this->arguments ) { @@ -310,4 +310,3 @@ private function _run_command() { WP_CLI::run_command( $this->arguments, $this->assoc_args ); } } - From 78e00cb423e556712aa012b30893cf3dd76cfcc3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Feb 2013 17:35:17 +0200 Subject: [PATCH 1172/5359] Use `cp -r` instead of `mv` for moving WP files into the current dir This allows installing WP into a directory that already has a wp-content dir. Props @carlalexander. Closes #293 --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index ac9600ebf..dc1f2dbb7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -37,7 +37,7 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; WP_CLI::launch( 'curl -f' . $silent . escapeshellarg( $download_url ) . ' | tar xz' ); - WP_CLI::launch( 'mv wordpress/* . && rm -rf wordpress' ); + WP_CLI::launch( 'cp -r wordpress/* . && rm -rf wordpress' ); WP_CLI::success( 'WordPress downloaded.' ); } From 2fdc22ba73cc8ba3fe3c854a4ab25ccab17e6ffb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Feb 2013 18:31:33 +0200 Subject: [PATCH 1173/5359] add --force flag to wp core download. fixes #221 --- man/core-download.1 | 2 +- php/commands/core.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/core-download.1 b/man/core-download.1 index 19b3e11eb..956e22cdc 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -7,7 +7,7 @@ \fBwp\-core\-download\fR \- Download core WordPress files\. . .SH "SYNOPSIS" -wp core download [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] +wp core download [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] [\-\-force] . .SH "OPTIONS" . diff --git a/php/commands/core.php b/php/commands/core.php index dc1f2dbb7..20502c90a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -10,10 +10,10 @@ class Core_Command extends WP_CLI_Command { /** * Download core WordPress files. * - * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] + * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] [--force] */ public function download( $args, $assoc_args ) { - if ( is_readable( ABSPATH . 'wp-load.php' ) ) + if ( !isset( $assoc_args['force'] ) && is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( isset( $assoc_args['path'] ) ) From d7f29cbec8dae69f1e75310d3395d89f1757abf6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 20:10:31 +0200 Subject: [PATCH 1174/5359] make cmd runner return command string, for easy debugging --- tests/command-runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/command-runner.php b/tests/command-runner.php index 3901991ac..d35e4d1a6 100644 --- a/tests/command-runner.php +++ b/tests/command-runner.php @@ -31,7 +31,7 @@ public function run( $command, $cwd = false ) { $return_code = proc_close( $process ); - return (object) compact( 'return_code', 'stdout', 'stderr' ); + return (object) compact( 'command', 'return_code', 'stdout', 'stderr' ); } public function create_config( $db_settings ) { From 4a4f3805bdff96b63ecc769948fd31699768bdda Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 20:53:55 +0200 Subject: [PATCH 1175/5359] introduce SynopsisParser class --- php/WP_CLI/Dispatcher/Subcommand.php | 56 +---------------------- php/WP_CLI/SynopsisParser.php | 66 ++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 php/WP_CLI/SynopsisParser.php diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index e725199dd..47ebb6f21 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -51,7 +51,7 @@ protected function check_args( $args, $assoc_args ) { if ( !$synopsis ) return; - $accepted_params = $this->parse_synopsis( $synopsis ); + $accepted_params = \WP_CLI\SynopsisParser::parse( $synopsis ); $this->check_positional( $args, $accepted_params ); @@ -119,59 +119,5 @@ private function check_unknown_assoc( $assoc_args, $accepted_params ) { } } - protected function parse_synopsis( $synopsis ) { - list( $patterns, $params ) = self::get_patterns(); - - $tokens = preg_split( '/[\s\t]+/', $synopsis ); - - foreach ( $tokens as $token ) { - foreach ( $patterns as $regex => $desc ) { - if ( preg_match( $regex, $token, $matches ) ) { - $type = $desc['type']; - $params[$type][] = array_merge( $matches, $desc ); - break; - } - } - } - - return $params; - } - - private static function get_patterns() { - $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '(?P<value>[a-z-|]+)'; - - $param_types = array( - array( 'positional', "<$p_value>", 1, 1 ), - array( 'generic', "--<field>=<value>", 1, 1 ), - array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), - array( 'flag', "--$p_name", 1, 0 ), - ); - - $patterns = array(); - $params = array(); - - foreach ( $param_types as $pt ) { - list( $type, $pattern, $optional, $mandatory ) = $pt; - - if ( $mandatory ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); - } - - if ( $optional ) { - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); - } - - $params[ $type ] = array(); - } - - return array( $patterns, $params ); - } } diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php new file mode 100644 index 000000000..bc594df3d --- /dev/null +++ b/php/WP_CLI/SynopsisParser.php @@ -0,0 +1,66 @@ +<?php + +namespace WP_CLI; + +class SynopsisParser { + + /** + * @param string + * @return array List of parameters + */ + static function parse( $synopsis ) { + list( $patterns, $params ) = self::get_patterns(); + + $tokens = preg_split( '/[\s\t]+/', $synopsis ); + + foreach ( $tokens as $token ) { + foreach ( $patterns as $regex => $desc ) { + if ( preg_match( $regex, $token, $matches ) ) { + $type = $desc['type']; + $params[$type][] = array_merge( $matches, $desc ); + break; + } + } + } + + return $params; + } + + private static function get_patterns() { + $p_name = '(?P<name>[a-z-_]+)'; + $p_value = '(?P<value>[a-z-|]+)'; + + $param_types = array( + array( 'positional', "<$p_value>", 1, 1 ), + array( 'generic', "--<field>=<value>", 1, 1 ), + array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), + array( 'flag', "--$p_name", 1, 0 ), + ); + + $patterns = array(); + $params = array(); + + foreach ( $param_types as $pt ) { + list( $type, $pattern, $optional, $mandatory ) = $pt; + + if ( $mandatory ) { + $patterns[ "/^$pattern$/" ] = array( + 'type' => $type, + 'optional' => false + ); + } + + if ( $optional ) { + $patterns[ "/^\[$pattern\]$/" ] = array( + 'type' => $type, + 'optional' => true + ); + } + + $params[ $type ] = array(); + } + + return array( $patterns, $params ); + } +} + From 68a33aeccff175d412cccbc256e4cd5549420870 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 19:14:07 +0200 Subject: [PATCH 1176/5359] add tests for SynopsisParser --- phpunit.xml.dist | 1 + tests/bootstrap.php | 1 + tests/test-synopsis.php | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/test-synopsis.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 917a7d50a..529dae0ef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,6 +5,7 @@ <testsuites> <testsuite> <directory prefix="spec-" suffix=".php">tests/</directory> + <directory prefix="test-" suffix=".php">tests/</directory> </testsuite> </testsuites> </phpunit> diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 4e82b7fa5..c24b94614 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,6 @@ <?php +require_once getcwd() . '/vendor/autoload.php'; require_once getcwd() . '/php/utils.php'; require_once __DIR__ . '/abstract-spec.php'; diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php new file mode 100644 index 000000000..59f477120 --- /dev/null +++ b/tests/test-synopsis.php @@ -0,0 +1,37 @@ +<?php + +use WP_CLI\SynopsisParser; + +class SynopsisParserTest extends PHPUnit_Framework_TestCase { + + function testPositional() { + $r = SynopsisParser::parse( '<foo> [<bar>]' ); + + $this->assertEquals( 2, count( $r['positional'] ) ); + $this->assertFalse( $r['positional'][0]['optional'] ); + $this->assertTrue( $r['positional'][1]['optional'] ); + } + + function testFlag() { + $r = SynopsisParser::parse( '--foo' ); + $this->assertEquals( 0, count( $r['flag'] ) ); // flags can't be mandatory + + $r = SynopsisParser::parse( '[--foo]' ); + $this->assertEquals( 1, count( $r['flag'] ) ); + } + + function testGeneric() { + $r = SynopsisParser::parse( '--<field>=<value>' ); + + $this->assertEquals( 1, count( $r['generic'] ) ); + } + + function testAssoc() { + $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>]' ); + + $this->assertEquals( 2, count( $r['assoc'] ) ); + $this->assertFalse( $r['assoc'][0]['optional'] ); + $this->assertTrue( $r['assoc'][1]['optional'] ); + } +} + From 535d85d4e6386d58f44453e6d17ebef0b5995260 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 21:41:05 +0200 Subject: [PATCH 1177/5359] check that other parameter types are 0 --- tests/test-synopsis.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 59f477120..5649d80ab 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -7,31 +7,39 @@ class SynopsisParserTest extends PHPUnit_Framework_TestCase { function testPositional() { $r = SynopsisParser::parse( '<foo> [<bar>]' ); - $this->assertEquals( 2, count( $r['positional'] ) ); + $this->assertFoundParameters( 2, 'positional', $r ); $this->assertFalse( $r['positional'][0]['optional'] ); $this->assertTrue( $r['positional'][1]['optional'] ); } function testFlag() { $r = SynopsisParser::parse( '--foo' ); - $this->assertEquals( 0, count( $r['flag'] ) ); // flags can't be mandatory + $this->assertFoundParameters( 0, 'flag', $r ); // flags can't be mandatory $r = SynopsisParser::parse( '[--foo]' ); - $this->assertEquals( 1, count( $r['flag'] ) ); + $this->assertFoundParameters( 1, 'flag', $r ); } function testGeneric() { $r = SynopsisParser::parse( '--<field>=<value>' ); - $this->assertEquals( 1, count( $r['generic'] ) ); + $this->assertFoundParameters( 1, 'generic', $r ); } function testAssoc() { $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>]' ); - $this->assertEquals( 2, count( $r['assoc'] ) ); + $this->assertFoundParameters( 2, 'assoc', $r ); $this->assertFalse( $r['assoc'][0]['optional'] ); $this->assertTrue( $r['assoc'][1]['optional'] ); } + + protected function assertFoundParameters( $count, $type, $r ) { + foreach ( $r as $key => $params ) { + $expected = ( $key == $type ) ? $count : 0; + + $this->assertEquals( $expected, count( $params ) ); + } + } } From 6d339aa93cf491f281d549998cc00d0d115d6fb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 21:51:12 +0200 Subject: [PATCH 1178/5359] add test for combined param types --- tests/test-synopsis.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 5649d80ab..01322b007 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -21,9 +21,11 @@ function testFlag() { } function testGeneric() { - $r = SynopsisParser::parse( '--<field>=<value>' ); + $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>]' ); - $this->assertFoundParameters( 1, 'generic', $r ); + $this->assertFoundParameters( 2, 'generic', $r ); + $this->assertFalse( $r['generic'][0]['optional'] ); + $this->assertTrue( $r['generic'][1]['optional'] ); } function testAssoc() { @@ -34,6 +36,15 @@ function testAssoc() { $this->assertTrue( $r['assoc'][1]['optional'] ); } + function testCombined() { + $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); + + $this->assertEquals( 1, count( $r['positional'] ) ); + $this->assertEquals( 1, count( $r['assoc'] ) ); + $this->assertEquals( 1, count( $r['generic'] ) ); + $this->assertEquals( 1, count( $r['flag'] ) ); + } + protected function assertFoundParameters( $count, $type, $r ) { foreach ( $r as $key => $params ) { $expected = ( $key == $type ) ? $count : 0; From 13e64ddee6bef85c3421d7a0e4353573f12ca085 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 21:53:28 +0200 Subject: [PATCH 1179/5359] use assertCount() instead of assertEquals() --- tests/test-synopsis.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 01322b007..624cc45cf 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -39,17 +39,17 @@ function testAssoc() { function testCombined() { $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); - $this->assertEquals( 1, count( $r['positional'] ) ); - $this->assertEquals( 1, count( $r['assoc'] ) ); - $this->assertEquals( 1, count( $r['generic'] ) ); - $this->assertEquals( 1, count( $r['flag'] ) ); + $this->assertCount( 1, $r['positional'] ); + $this->assertCount( 1, $r['assoc'] ); + $this->assertCount( 1, $r['generic'] ); + $this->assertCount( 1, $r['flag'] ); } protected function assertFoundParameters( $count, $type, $r ) { foreach ( $r as $key => $params ) { $expected = ( $key == $type ) ? $count : 0; - $this->assertEquals( $expected, count( $params ) ); + $this->assertCount( $expected, $params ); } } } From f0d3d349d6faa9c62263bcea33e15a03248ec0c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 22:17:43 +0200 Subject: [PATCH 1180/5359] make synopsis parser return unknown tokens --- php/WP_CLI/SynopsisParser.php | 6 ++++++ tests/test-synopsis.php | 11 ++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index bc594df3d..94cb05440 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -14,6 +14,8 @@ static function parse( $synopsis ) { $tokens = preg_split( '/[\s\t]+/', $synopsis ); foreach ( $tokens as $token ) { + $type = false; + foreach ( $patterns as $regex => $desc ) { if ( preg_match( $regex, $token, $matches ) ) { $type = $desc['type']; @@ -21,6 +23,10 @@ static function parse( $synopsis ) { break; } } + + if ( !$type ) { + $params['unknown'][] = $token; + } } return $params; diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 624cc45cf..a92c7c350 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -13,11 +13,12 @@ function testPositional() { } function testFlag() { - $r = SynopsisParser::parse( '--foo' ); - $this->assertFoundParameters( 0, 'flag', $r ); // flags can't be mandatory - $r = SynopsisParser::parse( '[--foo]' ); $this->assertFoundParameters( 1, 'flag', $r ); + + // flags can't be mandatory + $r = SynopsisParser::parse( '--foo' ); + $this->assertFoundParameters( 1, 'unknown', $r ); } function testGeneric() { @@ -34,6 +35,10 @@ function testAssoc() { $this->assertFoundParameters( 2, 'assoc', $r ); $this->assertFalse( $r['assoc'][0]['optional'] ); $this->assertTrue( $r['assoc'][1]['optional'] ); + + // shouldn't pass defaults to assoc parameters + $r = SynopsisParser::parse( '--count=100' ); + $this->assertFoundParameters( 1, 'unknown', $r ); } function testCombined() { From 9e4ee5864299da3b661b325aef868b250e01e9c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 23:14:28 +0200 Subject: [PATCH 1181/5359] show warnings for invalid tokens when generating man pages --- php/WP_CLI/Dispatcher/Subcommand.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 47ebb6f21..b8b758bc2 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -14,17 +14,25 @@ function __construct( CommandContainer $parent, $name, $callable, $docparser ) { } function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $prefix . $this->get_full_synopsis() ); + \WP_CLI::line( $prefix . $this->get_full_synopsis( false ) ); } function get_shortdesc() { return $this->docparser->get_shortdesc(); } - function get_full_synopsis() { + function get_full_synopsis( $validate = true ) { $full_name = implode( ' ', get_path( $this ) ); $synopsis = $this->get_synopsis(); + $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); + if ( isset( $tokens['unknown'] ) ) { + foreach ( $tokens['unknown'] as $token ) { + \WP_CLI::warning( sprintf( "Invalid token '%s' in synopsis for '%s'", + $token, $full_name ) ); + } + } + return "$full_name $synopsis"; } From 40a1e8b9a9048137c392ba9643d5ae27b72f560a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Feb 2013 23:24:34 +0200 Subject: [PATCH 1182/5359] ignore empty synopsis tokens --- php/WP_CLI/SynopsisParser.php | 2 +- tests/test-synopsis.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 94cb05440..5ae4a162d 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -11,7 +11,7 @@ class SynopsisParser { static function parse( $synopsis ) { list( $patterns, $params ) = self::get_patterns(); - $tokens = preg_split( '/[\s\t]+/', $synopsis ); + $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); foreach ( $tokens as $token ) { $type = false; diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index a92c7c350..33d2a1dae 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -4,6 +4,12 @@ class SynopsisParserTest extends PHPUnit_Framework_TestCase { + function testEmpty() { + $r = SynopsisParser::parse( ' ' ); + + $this->assertFoundParameters( 0, 'positional', $r ); + } + function testPositional() { $r = SynopsisParser::parse( '<foo> [<bar>]' ); From 831b8b0d581235e24c8e967d62265900a1a8446d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 00:12:57 +0200 Subject: [PATCH 1183/5359] refactor pattern generation --- php/WP_CLI/SynopsisParser.php | 46 ++++++++++++++++------------------- tests/test-synopsis.php | 6 ++--- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 5ae4a162d..a8f4cfaeb 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -32,41 +32,37 @@ static function parse( $synopsis ) { return $params; } + private static $patterns = array(); + private static $params = array(); + private static function get_patterns() { $p_name = '(?P<name>[a-z-_]+)'; $p_value = '(?P<value>[a-z-|]+)'; - $param_types = array( - array( 'positional', "<$p_value>", 1, 1 ), - array( 'generic', "--<field>=<value>", 1, 1 ), - array( 'assoc', "--$p_name=<$p_value>", 1, 1 ), - array( 'flag', "--$p_name", 1, 0 ), - ); - - $patterns = array(); - $params = array(); + self::gen_patterns( 'positional', "<$p_value>", array( 'mandatory', 'optional' ) ); + self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional' ) ); + self::gen_patterns( 'assoc', "--$p_name=<$p_value>", array( 'mandatory', 'optional' ) ); + self::gen_patterns( 'flag', "--$p_name", array( 'optional' ) ); - foreach ( $param_types as $pt ) { - list( $type, $pattern, $optional, $mandatory ) = $pt; + return array( self::$patterns, self::$params ); + } - if ( $mandatory ) { - $patterns[ "/^$pattern$/" ] = array( - 'type' => $type, - 'optional' => false - ); - } + private function gen_patterns( $type, $pattern, $flavour_types ) { + static $flavours = array( + 'mandatory' => "/^:pattern:$/", + 'optional' => "/^\[:pattern:\]$/", + ); - if ( $optional ) { - $patterns[ "/^\[$pattern\]$/" ] = array( - 'type' => $type, - 'optional' => true - ); - } + foreach ( $flavour_types as $flavour_type ) { + $flavour = $flavours[ $flavour_type ]; - $params[ $type ] = array(); + self::$patterns[ str_replace( ':pattern:', $pattern, $flavour ) ] = array( + 'type' => $type, + $flavour_type => true + ); } - return array( $patterns, $params ); + self::$params[ $type ] = array(); } } diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 33d2a1dae..040876936 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -14,7 +14,7 @@ function testPositional() { $r = SynopsisParser::parse( '<foo> [<bar>]' ); $this->assertFoundParameters( 2, 'positional', $r ); - $this->assertFalse( $r['positional'][0]['optional'] ); + $this->assertTrue( $r['positional'][0]['mandatory'] ); $this->assertTrue( $r['positional'][1]['optional'] ); } @@ -31,7 +31,7 @@ function testGeneric() { $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>]' ); $this->assertFoundParameters( 2, 'generic', $r ); - $this->assertFalse( $r['generic'][0]['optional'] ); + $this->assertTrue( $r['generic'][0]['mandatory'] ); $this->assertTrue( $r['generic'][1]['optional'] ); } @@ -39,7 +39,7 @@ function testAssoc() { $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>]' ); $this->assertFoundParameters( 2, 'assoc', $r ); - $this->assertFalse( $r['assoc'][0]['optional'] ); + $this->assertTrue( $r['assoc'][0]['mandatory'] ); $this->assertTrue( $r['assoc'][1]['optional'] ); // shouldn't pass defaults to assoc parameters From 4c38ebe4652a2ede387b926aa9bd999c6ec8ebcd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 02:41:06 +0200 Subject: [PATCH 1184/5359] first pass at moving arg checking into SynopsisParser Also, doesn't nest accepted parameters by type --- php/WP_CLI/Dispatcher/Subcommand.php | 92 +++---------------- php/WP_CLI/SynopsisParser.php | 131 ++++++++++++++++++++++++--- tests/test-synopsis.php | 60 +++++++----- 3 files changed, 167 insertions(+), 116 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index b8b758bc2..db17c4dfb 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -26,10 +26,13 @@ function get_full_synopsis( $validate = true ) { $synopsis = $this->get_synopsis(); $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); - if ( isset( $tokens['unknown'] ) ) { - foreach ( $tokens['unknown'] as $token ) { - \WP_CLI::warning( sprintf( "Invalid token '%s' in synopsis for '%s'", - $token, $full_name ) ); + + foreach ( $tokens as $token ) { + if ( 'unknown' == $token['type'] ) { + \WP_CLI::warning( sprintf( + "Invalid token '%s' in synopsis for '%s'", + $token['token'], $full_name + ) ); } } @@ -41,7 +44,12 @@ function get_synopsis() { } function invoke( $args, $assoc_args ) { - $this->check_args( $args, $assoc_args ); + $synopsis = $this->get_synopsis(); + + if ( $synopsis ) { + \WP_CLI\SynopsisParser::validate_args( $synopsis, $args, $assoc_args, + array( $this, 'show_usage' ) ); + } call_user_func( $this->callable, $args, $assoc_args ); } @@ -53,79 +61,5 @@ function get_name() { function get_parent() { return $this->parent; } - - protected function check_args( $args, $assoc_args ) { - $synopsis = $this->get_synopsis(); - if ( !$synopsis ) - return; - - $accepted_params = \WP_CLI\SynopsisParser::parse( $synopsis ); - - $this->check_positional( $args, $accepted_params ); - - $this->check_assoc( $assoc_args, $accepted_params ); - - if ( empty( $accepted_params['generic'] ) ) - $this->check_unknown_assoc( $assoc_args, $accepted_params ); - } - - private function check_positional( $args, $accepted_params ) { - $count = 0; - - foreach ( $accepted_params['positional'] as $param ) { - if ( !$param['optional'] ) - $count++; - } - - if ( count( $args ) < $count ) { - $this->show_usage(); - exit(1); - } - } - - private function check_assoc( $assoc_args, $accepted_params ) { - $mandatory_assoc = array(); - - $assoc_args += \WP_CLI::get_config(); - - foreach ( $accepted_params['assoc'] as $param ) { - if ( !$param['optional'] ) - $mandatory_assoc[] = $param['name']; - } - - $errors = array(); - - foreach ( $mandatory_assoc as $key ) { - if ( !isset( $assoc_args[ $key ] ) ) - $errors[] = "missing --$key parameter"; - elseif ( true === $assoc_args[ $key ] ) - $errors[] = "--$key parameter needs a value"; - } - - if ( !empty( $errors ) ) { - foreach ( $errors as $error ) { - \WP_CLI::warning( $error ); - } - $this->show_usage(); - exit(1); - } - } - - private function check_unknown_assoc( $assoc_args, $accepted_params ) { - $known_assoc = array(); - - foreach ( array( 'assoc', 'flag' ) as $type ) { - foreach ( $accepted_params[$type] as $param ) { - $known_assoc[] = $param['name']; - } - } - - $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); - - foreach ( $unknown_assoc as $key ) { - \WP_CLI::warning( "unknown --$key parameter" ); - } - } - } diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index a8f4cfaeb..248f7c72d 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -4,38 +4,120 @@ class SynopsisParser { + private static $patterns = array(); + + private $params = array(); + + /** + * @param string Synopsis + * @param array Positional args + * @param array Associative args + * @param callback What to do on a critical failure + */ + static function validate_args( $synopsis, $args, $assoc_args, $callback ) { + $instance = new self( $synopsis ); + + $instance->check_positional( $args, $callback ); + + $instance->check_assoc( $assoc_args, $callback ); + + $instance->check_unknown_assoc( $assoc_args ); + } + + private function __construct( $synopsis ) { + $this->params = $this->parse( $synopsis ); + } + + private function check_positional( $args, $callback ) { + $positional = $this->query_params( array( + 'type' => 'positional', + 'flavour' => 'mandatory' + ) ); + + if ( count( $args ) < count( $positional ) ) { + call_user_func( $callback ); + exit(1); + } + } + + private function check_assoc( $assoc_args, $callback ) { + $assoc_args += \WP_CLI::get_config(); + + $errors = array(); + + $mandatory_assoc = $this->query_params( array( + 'type' => 'assoc', + 'flavour' => 'mandatory' + ) ); + + foreach ( $mandatory_assoc as $param ) { + $key = $param['name']; + + if ( !isset( $assoc_args[ $key ] ) ) + $errors[] = "missing --$key parameter"; + elseif ( true === $assoc_args[ $key ] ) + $errors[] = "--$key parameter needs a value"; + } + + if ( !empty( $errors ) ) { + foreach ( $errors as $error ) { + \WP_CLI::warning( $error ); + } + call_user_func( $callback ); + exit(1); + } + } + + private function check_unknown_assoc( $assoc_args ) { + $known_assoc = array(); + + foreach ( $this->params as $param ) { + if ( in_array( $param['type'], array( 'assoc', 'flag' ) ) ) + $known_assoc[] = $param['name']; + } + + $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); + + foreach ( $unknown_assoc as $key ) { + \WP_CLI::warning( "unknown --$key parameter" ); + } + } + /** * @param string * @return array List of parameters */ static function parse( $synopsis ) { - list( $patterns, $params ) = self::get_patterns(); + if ( empty( self::$patterns ) ) + self::init_patterns(); $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); + $params = array(); + foreach ( $tokens as $token ) { $type = false; - foreach ( $patterns as $regex => $desc ) { + foreach ( self::$patterns as $regex => $desc ) { if ( preg_match( $regex, $token, $matches ) ) { $type = $desc['type']; - $params[$type][] = array_merge( $matches, $desc ); + $params[] = array_merge( $matches, $desc ); break; } } if ( !$type ) { - $params['unknown'][] = $token; + $params[] = array( + 'type' => 'unknown', + 'token' => $token + ); } } return $params; } - private static $patterns = array(); - private static $params = array(); - - private static function get_patterns() { + private static function init_patterns() { $p_name = '(?P<name>[a-z-_]+)'; $p_value = '(?P<value>[a-z-|]+)'; @@ -43,8 +125,6 @@ private static function get_patterns() { self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional' ) ); self::gen_patterns( 'assoc', "--$p_name=<$p_value>", array( 'mandatory', 'optional' ) ); self::gen_patterns( 'flag', "--$p_name", array( 'optional' ) ); - - return array( self::$patterns, self::$params ); } private function gen_patterns( $type, $pattern, $flavour_types ) { @@ -58,11 +138,38 @@ private function gen_patterns( $type, $pattern, $flavour_types ) { self::$patterns[ str_replace( ':pattern:', $pattern, $flavour ) ] = array( 'type' => $type, - $flavour_type => true + 'flavour' => $flavour_type ); } + } + + /** + * Filters a list of associatve arrays, based on a set of key => value arguments. + * + * @param array $args An array of key => value arguments to match against + * @param string $operator + * @return array + */ + private function query_params( $args, $operator = 'AND' ) { + $operator = strtoupper( $operator ); + $count = count( $args ); + $filtered = array(); + + foreach ( $this->params as $key => $to_match ) { + $matched = 0; + foreach ( $args as $m_key => $m_value ) { + if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) + $matched++; + } + + if ( ( 'AND' == $operator && $matched == $count ) + || ( 'OR' == $operator && $matched > 0 ) + || ( 'NOT' == $operator && 0 == $matched ) ) { + $filtered[$key] = $to_match; + } + } - self::$params[ $type ] = array(); + return $filtered; } } diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 040876936..80bef8c2c 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -7,61 +7,71 @@ class SynopsisParserTest extends PHPUnit_Framework_TestCase { function testEmpty() { $r = SynopsisParser::parse( ' ' ); - $this->assertFoundParameters( 0, 'positional', $r ); + $this->assertEmpty( $r ); } function testPositional() { $r = SynopsisParser::parse( '<foo> [<bar>]' ); - $this->assertFoundParameters( 2, 'positional', $r ); - $this->assertTrue( $r['positional'][0]['mandatory'] ); - $this->assertTrue( $r['positional'][1]['optional'] ); + $this->assertCount( 2, $r ); + + $this->assertEquals( 'positional', $r[0]['type'] ); + $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + + $this->assertEquals( 'positional', $r[1]['type'] ); + $this->assertEquals( 'optional', $r[1]['flavour'] ); } function testFlag() { $r = SynopsisParser::parse( '[--foo]' ); - $this->assertFoundParameters( 1, 'flag', $r ); + + $this->assertCount( 1, $r ); + $this->assertEquals( 'flag', $r[0]['type'] ); + $this->assertEquals( 'optional', $r[0]['flavour'] ); // flags can't be mandatory $r = SynopsisParser::parse( '--foo' ); - $this->assertFoundParameters( 1, 'unknown', $r ); + + $this->assertCount( 1, $r ); + $this->assertEquals( 'unknown', $r[0]['type'] ); } function testGeneric() { $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>]' ); - $this->assertFoundParameters( 2, 'generic', $r ); - $this->assertTrue( $r['generic'][0]['mandatory'] ); - $this->assertTrue( $r['generic'][1]['optional'] ); + $this->assertCount( 2, $r ); + + $this->assertEquals( 'generic', $r[0]['type'] ); + $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + + $this->assertEquals( 'generic', $r[1]['type'] ); + $this->assertEquals( 'optional', $r[1]['flavour'] ); } function testAssoc() { $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>]' ); - $this->assertFoundParameters( 2, 'assoc', $r ); - $this->assertTrue( $r['assoc'][0]['mandatory'] ); - $this->assertTrue( $r['assoc'][1]['optional'] ); + $this->assertCount( 2, $r ); + + $this->assertEquals( 'assoc', $r[0]['type'] ); + $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + + $this->assertEquals( 'assoc', $r[1]['type'] ); + $this->assertEquals( 'optional', $r[1]['flavour'] ); // shouldn't pass defaults to assoc parameters $r = SynopsisParser::parse( '--count=100' ); - $this->assertFoundParameters( 1, 'unknown', $r ); + $this->assertCount( 1, $r ); + $this->assertEquals( 'unknown', $r[0]['type'] ); } function testCombined() { $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); - $this->assertCount( 1, $r['positional'] ); - $this->assertCount( 1, $r['assoc'] ); - $this->assertCount( 1, $r['generic'] ); - $this->assertCount( 1, $r['flag'] ); - } - - protected function assertFoundParameters( $count, $type, $r ) { - foreach ( $r as $key => $params ) { - $expected = ( $key == $type ) ? $count : 0; - - $this->assertCount( $expected, $params ); - } + $this->assertEquals( 'positional', $r[0]['type'] ); + $this->assertEquals( 'assoc', $r[1]['type'] ); + $this->assertEquals( 'generic', $r[2]['type'] ); + $this->assertEquals( 'flag', $r[3]['type'] ); } } From b18652ba586a086082b69a7c4dc8fdf5935a045e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 03:40:20 +0200 Subject: [PATCH 1185/5359] add 'repeating' flavour --- php/WP_CLI/SynopsisParser.php | 13 ++++++++----- tests/test-synopsis.php | 8 ++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 248f7c72d..66552ec02 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -121,22 +121,25 @@ private static function init_patterns() { $p_name = '(?P<name>[a-z-_]+)'; $p_value = '(?P<value>[a-z-|]+)'; - self::gen_patterns( 'positional', "<$p_value>", array( 'mandatory', 'optional' ) ); - self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional' ) ); + self::gen_patterns( 'positional', "<$p_value>", array( 'mandatory', 'optional', 'repeating' ) ); + self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional', 'repeating' ) ); self::gen_patterns( 'assoc', "--$p_name=<$p_value>", array( 'mandatory', 'optional' ) ); self::gen_patterns( 'flag', "--$p_name", array( 'optional' ) ); } private function gen_patterns( $type, $pattern, $flavour_types ) { static $flavours = array( - 'mandatory' => "/^:pattern:$/", - 'optional' => "/^\[:pattern:\]$/", + 'mandatory' => ":pattern:", + 'optional' => "\[:pattern:\]", + 'repeating' => ":pattern:...", ); foreach ( $flavour_types as $flavour_type ) { $flavour = $flavours[ $flavour_type ]; - self::$patterns[ str_replace( ':pattern:', $pattern, $flavour ) ] = array( + $final_pattern = str_replace( ':pattern:', $pattern, $flavour ); + + self::$patterns[ '/^' . $final_pattern . '$/' ] = array( 'type' => $type, 'flavour' => $flavour_type ); diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 80bef8c2c..f27bcd72c 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -65,6 +65,14 @@ function testAssoc() { $this->assertEquals( 'unknown', $r[0]['type'] ); } + function testRepeating() { + $r = SynopsisParser::parse( '<positional>...' ); + + $this->assertCount( 1, $r ); + $this->assertEquals( 'positional', $r[0]['type'] ); + $this->assertEquals( 'repeating', $r[0]['flavour'] ); + } + function testCombined() { $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); From 8f91cc17cefcf516cd78ad680ecaa357ac0f1562 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 03:59:19 +0200 Subject: [PATCH 1186/5359] the 'repeating' flavour can also be optional --- php/WP_CLI/SynopsisParser.php | 20 ++++++++++---------- tests/test-synopsis.php | 8 ++++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 66552ec02..7512ce112 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -129,20 +129,20 @@ private static function init_patterns() { private function gen_patterns( $type, $pattern, $flavour_types ) { static $flavours = array( - 'mandatory' => ":pattern:", - 'optional' => "\[:pattern:\]", - 'repeating' => ":pattern:...", + 'mandatory' => ':pattern:', + 'optional' => '\[:pattern:\]', + 'repeating' => array( ':pattern:...', '\[:pattern:...\]' ) ); foreach ( $flavour_types as $flavour_type ) { - $flavour = $flavours[ $flavour_type ]; + foreach ( (array) $flavours[ $flavour_type ] as $flavour ) { + $final_pattern = str_replace( ':pattern:', $pattern, $flavour ); - $final_pattern = str_replace( ':pattern:', $pattern, $flavour ); - - self::$patterns[ '/^' . $final_pattern . '$/' ] = array( - 'type' => $type, - 'flavour' => $flavour_type - ); + self::$patterns[ '/^' . $final_pattern . '$/' ] = array( + 'type' => $type, + 'flavour' => $flavour_type + ); + } } } diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index f27bcd72c..d54f9df2a 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -66,11 +66,15 @@ function testAssoc() { } function testRepeating() { - $r = SynopsisParser::parse( '<positional>...' ); + $r = SynopsisParser::parse( '<positional>... [--<field>=<value>...]' ); + + $this->assertCount( 2, $r ); - $this->assertCount( 1, $r ); $this->assertEquals( 'positional', $r[0]['type'] ); $this->assertEquals( 'repeating', $r[0]['flavour'] ); + + $this->assertEquals( 'generic', $r[1]['type'] ); + $this->assertEquals( 'repeating', $r[1]['flavour'] ); } function testCombined() { From a8bcee0998f12eb00104d04cbec6f70c4798e3c5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 04:17:01 +0200 Subject: [PATCH 1187/5359] fix post generate and user generate synopses closes #296 --- man/post-generate.1 | 2 +- man/user-generate.1 | 2 +- php/commands/post.php | 2 +- php/commands/user.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/post-generate.1 b/man/post-generate.1 index 9aca68462..d89efebe9 100644 --- a/man/post-generate.1 +++ b/man/post-generate.1 @@ -7,7 +7,7 @@ \fBwp\-post\-generate\fR \- Generate some posts\. . .SH "SYNOPSIS" -wp post generate [\-\-count=100] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=1] +wp post generate [\-\-count=\fInumber\fR] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=\fInumber\fR] . .SH "OPTIONS" . diff --git a/man/user-generate.1 b/man/user-generate.1 index 2acca7912..3c87b5c76 100644 --- a/man/user-generate.1 +++ b/man/user-generate.1 @@ -7,7 +7,7 @@ \fBwp\-user\-generate\fR \- Generate users\. . .SH "SYNOPSIS" -wp user generate [\-\-count=100] [\-\-role=\fIrole\fR] +wp user generate [\-\-count=\fInumber\fR] [\-\-role=\fIrole\fR] . .SH "OPTIONS" . diff --git a/php/commands/post.php b/php/commands/post.php index 1e69d24b7..00809403f 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -109,7 +109,7 @@ public function _list( $_, $assoc_args ) { /** * Generate some posts. * - * @synopsis [--count=100] [--post_type=<type>] [--post_status=<status>] [--post_author=<login>] [--post_date=<yyyy-mm-dd>] [--max_depth=1] + * @synopsis [--count=<number>] [--post_type=<type>] [--post_status=<status>] [--post_author=<login>] [--post_date=<yyyy-mm-dd>] [--max_depth=<number>] */ public function generate( $args, $assoc_args ) { global $wpdb; diff --git a/php/commands/user.php b/php/commands/user.php index 7ded9497d..fd4aac632 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -184,7 +184,7 @@ protected function _update( $params ) { /** * Generate users. * - * @synopsis [--count=100] [--role=<role>] + * @synopsis [--count=<number>] [--role=<role>] */ public function generate( $args, $assoc_args ) { global $blog_id; From ca7e87d56a4ed8c5d00fdacd6be43823d9185aa8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 04:27:01 +0200 Subject: [PATCH 1188/5359] show validation warnings only when generating man pages. see #298 --- php/WP_CLI/Dispatcher/CompositeCommand.php | 2 +- php/WP_CLI/Dispatcher/Subcommand.php | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index e0ff1f670..897992bbe 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -78,7 +78,7 @@ public function get_full_synopsis() { $str = array(); foreach ( $this->subcommands as $subcommand ) { - $str[] = $subcommand->get_full_synopsis(); + $str[] = $subcommand->get_full_synopsis( true ); } return implode( "\n\n", $str ); diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index db17c4dfb..80d43f620 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -14,25 +14,27 @@ function __construct( CommandContainer $parent, $name, $callable, $docparser ) { } function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $prefix . $this->get_full_synopsis( false ) ); + \WP_CLI::line( $prefix . $this->get_full_synopsis() ); } function get_shortdesc() { return $this->docparser->get_shortdesc(); } - function get_full_synopsis( $validate = true ) { + function get_full_synopsis( $validate = false ) { $full_name = implode( ' ', get_path( $this ) ); $synopsis = $this->get_synopsis(); - $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); + if ( $validate ) { + $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); - foreach ( $tokens as $token ) { - if ( 'unknown' == $token['type'] ) { - \WP_CLI::warning( sprintf( - "Invalid token '%s' in synopsis for '%s'", - $token['token'], $full_name - ) ); + foreach ( $tokens as $token ) { + if ( 'unknown' == $token['type'] ) { + \WP_CLI::warning( sprintf( + "Invalid token '%s' in synopsis for '%s'", + $token['token'], $full_name + ) ); + } } } From 678855fc62b7e58262a26297d264e1306858f4be Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 00:07:53 +0200 Subject: [PATCH 1189/5359] first pass at creating a Phar archive --- .gitignore | 1 + bin/wp | 2 +- php/{wp-cli-boot.php => boot-fs.php} | 2 ++ php/boot-phar.php | 6 +++++ php/wp-cli.php | 2 -- utils/make-phar.php | 36 ++++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) rename php/{wp-cli-boot.php => boot-fs.php} (89%) create mode 100644 php/boot-phar.php create mode 100644 utils/make-phar.php diff --git a/.gitignore b/.gitignore index 8e2a67431..31c4b786e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /vendor /composer.lock /phpunit.xml +/wp-cli.phar diff --git a/bin/wp b/bin/wp index aeebd4d50..d2cfa79f8 100755 --- a/bin/wp +++ b/bin/wp @@ -28,7 +28,7 @@ if [ ! -d $SCRIPT_PATH ]; then SCRIPT_PATH=$(dirname "$SELF_PATH")/../php fi -SCRIPT_PATH=$SCRIPT_PATH/wp-cli-boot.php +SCRIPT_PATH=$SCRIPT_PATH/boot-fs.php case $(uname -a) in CYGWIN*) diff --git a/php/wp-cli-boot.php b/php/boot-fs.php similarity index 89% rename from php/wp-cli-boot.php rename to php/boot-fs.php index b7c8de526..a3311c887 100644 --- a/php/wp-cli-boot.php +++ b/php/boot-fs.php @@ -12,5 +12,7 @@ die(-1); } +define( 'WP_CLI_ROOT', __DIR__ . '/' ); + include dirname(__FILE__) . '/wp-cli.php'; diff --git a/php/boot-phar.php b/php/boot-phar.php new file mode 100644 index 000000000..be8cfdcb2 --- /dev/null +++ b/php/boot-phar.php @@ -0,0 +1,6 @@ +<?php + +define( 'WP_CLI_ROOT', 'phar://wp-cli.phar/php/' ); + +include WP_CLI_ROOT . 'wp-cli.php'; + diff --git a/php/wp-cli.php b/php/wp-cli.php index c1443fd6a..c0000d100 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -5,8 +5,6 @@ define( 'WP_CLI_VERSION', '0.9.0-dev' ); -define( 'WP_CLI_ROOT', __DIR__ . '/' ); - include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; diff --git a/utils/make-phar.php b/utils/make-phar.php new file mode 100644 index 000000000..e6cd3f667 --- /dev/null +++ b/utils/make-phar.php @@ -0,0 +1,36 @@ +<?php + +// php -dphar.readonly=0 utils/make-phar.php + +$iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator( './php', FilesystemIterator::SKIP_DOTS ) +); + +$phar = new Phar( 'wp-cli.phar', 0, 'wp-cli.phar' ); + +$phar->startBuffering(); + +foreach ( $iterator as $path ) { + if ( !preg_match( '/\.php$/', $path ) ) + continue; + + $key = str_replace( './', '', $path ); + + echo "$key - $path\n"; + + $phar[ $key ] = file_get_contents( $path ); +} + +$phar->setStub( <<<EOB +<?php +Phar::mapPhar(); +include 'phar://wp-cli.phar/php/boot-phar.php'; +__HALT_COMPILER(); +?> +EOB +); + +$phar->stopBuffering(); + +echo "Generated wp-cli.phar.\n"; + From 669c72026f8d3176cb7b7e0e7c9cdd9407a610db Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 00:20:53 +0200 Subject: [PATCH 1190/5359] add ignored paths --- utils/make-phar.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index e6cd3f667..8fc8746d0 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -10,7 +10,19 @@ $phar->startBuffering(); +$ignored_paths = array( + '/mustache/bin/', + '/mustache/test/', + '/mustache/vendor/', + '/php-cli-tools/examples/' +); + foreach ( $iterator as $path ) { + foreach ( $ignored_paths as $ignore ) { + if ( strpos( $path, $ignore ) ) + continue 2; + } + if ( !preg_match( '/\.php$/', $path ) ) continue; From 5c0bea0f970ce3c9e8da7655db281fb503a08317 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 00:26:14 +0200 Subject: [PATCH 1191/5359] handle --quiet parameter --- utils/make-phar.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index 8fc8746d0..7de3b17eb 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -1,6 +1,8 @@ <?php -// php -dphar.readonly=0 utils/make-phar.php +// php -dphar.readonly=0 utils/make-phar.php [--quiet] + +define( 'BE_QUIET', isset( $argv[1] ) && '--quiet' == $argv[1] ); $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( './php', FilesystemIterator::SKIP_DOTS ) @@ -28,7 +30,8 @@ $key = str_replace( './', '', $path ); - echo "$key - $path\n"; + if ( !BE_QUIET ) + echo "$key - $path\n"; $phar[ $key ] = file_get_contents( $path ); } From d824eeda952e79a7d4f49ad924f7072b8f01bf48 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 00:43:56 +0200 Subject: [PATCH 1192/5359] use DirectoryIterator, since glob() doesn't work on Phar archives --- php/WP_CLI/Dispatcher/RootCommand.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 989faa2cf..654d4fca5 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -108,13 +108,20 @@ function get_subcommands() { } protected function load_all_commands() { - foreach ( glob( WP_CLI_ROOT . "/commands/*.php" ) as $filename ) { - $command = str_replace( '.php', '', $filename ); + $cmd_dir = WP_CLI_ROOT . "commands"; + + $iterator = new \DirectoryIterator( $cmd_dir ); + + foreach ( $iterator as $filename ) { + if ( '.php' != substr( $filename, -4 ) ) + continue; + + $command = substr( $filename, 0, -4 ); if ( isset( $this->subcommands[ $command ] ) ) continue; - include $filename; + include "$cmd_dir/$filename"; } } From 6c5a05897445c778ae3fb4c16e7340fac478affe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 01:32:18 +0200 Subject: [PATCH 1193/5359] add shebang to Phar stub --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 7de3b17eb..ece45d38f 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -37,6 +37,7 @@ } $phar->setStub( <<<EOB +#!/usr/bin/env php <?php Phar::mapPhar(); include 'phar://wp-cli.phar/php/boot-phar.php'; From a464817eb27c9c44aa20b92a56f0fb0235187edf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 01:33:50 +0200 Subject: [PATCH 1194/5359] make manpages work from a Phar archive --- php/class-wp-cli.php | 5 ----- php/commands/help.php | 21 ++++++++++++++++++++- utils/make-phar.php | 28 +++++++++++++++++++--------- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ad70c61c1..1f453e1c7 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -91,11 +91,6 @@ private static function create_atomic_command( $name, $implementation ) { } static function add_man_dir( $dest_dir, $src_dir ) { - $dest_dir = realpath( $dest_dir ) . '/'; - - if ( $src_dir ) - $src_dir = realpath( $src_dir ) . '/'; - self::$man_dirs[ $dest_dir ] = $src_dir; } diff --git a/php/commands/help.php b/php/commands/help.php index bd1234a19..7b3490abc 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -34,10 +34,29 @@ private static function maybe_load_man_page( $args ) { $man_path = $dest_dir . $man_file; if ( is_readable( $man_path ) ) { - exit( WP_CLI::launch( "man $man_path" ) ); + self::show_manpage( $man_path ); } } } + + private static function show_manpage( $path ) { + // to make compatible with Phar archives, need to write to a temporary file + $fd = fopen( 'php://temp', 'rw' ); + fwrite( $fd, file_get_contents( $path ) ); + fseek( $fd, 0 ); + + $descriptorspec = array( + 0 => $fd, + 1 => STDOUT, + 2 => STDERR + ); + + $cmd = 'man -l -'; + + $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); + + exit( $r ); + } } WP_CLI::add_command( 'help', new Help_Command ); diff --git a/utils/make-phar.php b/utils/make-phar.php index ece45d38f..8f61ee0d5 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -4,9 +4,20 @@ define( 'BE_QUIET', isset( $argv[1] ) && '--quiet' == $argv[1] ); -$iterator = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( './php', FilesystemIterator::SKIP_DOTS ) -); +function get_iterator( $dir ) { + return new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) + ); +} + +function add_file( $phar, $path ) { + $key = str_replace( './', '', $path ); + + if ( !BE_QUIET ) + echo "$key - $path\n"; + + $phar[ $key ] = file_get_contents( $path ); +} $phar = new Phar( 'wp-cli.phar', 0, 'wp-cli.phar' ); @@ -19,7 +30,7 @@ '/php-cli-tools/examples/' ); -foreach ( $iterator as $path ) { +foreach ( get_iterator( './php' ) as $path ) { foreach ( $ignored_paths as $ignore ) { if ( strpos( $path, $ignore ) ) continue 2; @@ -28,12 +39,11 @@ if ( !preg_match( '/\.php$/', $path ) ) continue; - $key = str_replace( './', '', $path ); - - if ( !BE_QUIET ) - echo "$key - $path\n"; + add_file( $phar, $path ); +} - $phar[ $key ] = file_get_contents( $path ); +foreach ( get_iterator( './man' ) as $path ) { + add_file( $phar, $path ); } $phar->setStub( <<<EOB From dea703e54245560a26458b05de8e6a8b84c7c1f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 01:57:58 +0200 Subject: [PATCH 1195/5359] add templates to phar archive --- utils/make-phar.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 8f61ee0d5..bb5a8feaa 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -42,6 +42,10 @@ function add_file( $phar, $path ) { add_file( $phar, $path ); } +foreach ( get_iterator( './templates' ) as $path ) { + add_file( $phar, $path ); +} + foreach ( get_iterator( './man' ) as $path ) { add_file( $phar, $path ); } From a402e7c994fbcfb6fc689ad866b9d00cb113aa7e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 02:07:32 +0200 Subject: [PATCH 1196/5359] allow specifying where to create the phar archive --- .gitignore | 1 - utils/make-phar.php | 13 +++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 31c4b786e..8e2a67431 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ /vendor /composer.lock /phpunit.xml -/wp-cli.phar diff --git a/utils/make-phar.php b/utils/make-phar.php index bb5a8feaa..b928bd108 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -1,8 +1,13 @@ <?php -// php -dphar.readonly=0 utils/make-phar.php [--quiet] +if ( !isset( $argv[1] ) ) { + echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet]\n"; + exit(1); +} + +define( 'DEST_PATH', $argv[1] ); -define( 'BE_QUIET', isset( $argv[1] ) && '--quiet' == $argv[1] ); +define( 'BE_QUIET', in_array( '--quiet', $argv ) ); function get_iterator( $dir ) { return new \RecursiveIteratorIterator( @@ -19,7 +24,7 @@ function add_file( $phar, $path ) { $phar[ $key ] = file_get_contents( $path ); } -$phar = new Phar( 'wp-cli.phar', 0, 'wp-cli.phar' ); +$phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); $phar->startBuffering(); @@ -62,5 +67,5 @@ function add_file( $phar, $path ) { $phar->stopBuffering(); -echo "Generated wp-cli.phar.\n"; +echo "\nGenerated " . DEST_PATH . "\n"; From 0de47afc45ff0b42b496bb23d602293ef9967482 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 02:20:42 +0200 Subject: [PATCH 1197/5359] set version to 0.9.0-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index c0000d100..9c28fbe35 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.0-dev' ); +define( 'WP_CLI_VERSION', '0.9.0-alpha' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From c097bd27dcf879213288096dcfafbdac1d85a0f7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Feb 2013 06:37:07 +0200 Subject: [PATCH 1198/5359] delete files used for generating pear packages. see #301. closes #39 --- .gitignore | 3 - build.local.xml | 6 - build.properties | 13 -- build.xml | 437 ----------------------------------------------- package.xml | 71 -------- utils/pear-build | 28 --- 6 files changed, 558 deletions(-) delete mode 100644 build.local.xml delete mode 100644 build.properties delete mode 100644 build.xml delete mode 100644 package.xml delete mode 100755 utils/pear-build diff --git a/.gitignore b/.gitignore index 8e2a67431..abb9c75a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -/.build -/src -/dist /vendor /composer.lock /phpunit.xml diff --git a/build.local.xml b/build.local.xml deleted file mode 100644 index 90aa3bc92..000000000 --- a/build.local.xml +++ /dev/null @@ -1,6 +0,0 @@ -<project name="local" default="help"> - <target name="help"> - <echo message="This component has no local build targets." /> - </target> -</project> -<!-- vim: set tabstop=2 shiftwidth=2 expandtab: --> diff --git a/build.properties b/build.properties deleted file mode 100644 index dcab1de8e..000000000 --- a/build.properties +++ /dev/null @@ -1,13 +0,0 @@ -project.name=wpcli -project.channel=wp-cli.org/pear -project.majorVersion=0 -project.minorVersion=8 -project.patchLevel=0 -project.snapshot=false - -checkstyle.standard=Zend - -component.type=php-library -component.version=10 - -pear.local=/var/www/${project.channel} diff --git a/build.xml b/build.xml deleted file mode 100644 index 4264119d3..000000000 --- a/build.xml +++ /dev/null @@ -1,437 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- build file for phing --> -<project default="help" basedir="."> - <!-- Human-readable info about our component --> - <property file="build.properties" /> - <taskdef name="now" classname="Phix_Project.ComponentManager.Phing.NowTask" /> - <now name="date.now"/> - <if> - <and> - <isset property="project.snapshot"/> - <istrue value="${project.snapshot}"/> - </and> - <then> - <property name="project.version" value="${project.majorVersion}.${project.minorVersion}.${project.patchLevel}snapshot${date.now}" /> - <property name="project.stability" value="snapshot" /> - </then> - <else> - <property name="project.version" value="${project.majorVersion}.${project.minorVersion}.${project.patchLevel}" /> - <property name="project.stability" value="stable" /> - </else> - </if> - <property name="project.apiversion" value="${project.majorVersion}.${project.minorVersion}" /> - - <!-- Paths to the directories that we work with --> - <property name="project.srcdir" value="${project.basedir}" override="true" /> - <property name="project.src.phpdir" value="${project.srcdir}/php" override="true" /> - <property name="project.src.bindir" value="${project.srcdir}/bin" override="true" /> - <property name="project.src.datadir" value="${project.srcdir}/data" override="true" /> - <property name="project.src.docdir" value="${project.srcdir}/docs" override="true" /> - <property name="project.src.testdir" value="${project.srcdir}/tests" override="true" /> - <property name="project.src.wwwdir" value="${project.srcdir}/www" override="true" /> - <property name="project.src.testunitdir" value="${project.src.testdir}/unit-tests" override="true" /> - <property name="project.src.testintdir" value="${project.src.testdir}/integration-tests" override="true" /> - <property name="project.src.testfuncdir" value="${project.src.testdir}/functional-tests" override="true" /> - - <property name="project.reviewdir" value="${project.basedir}/review" override="true" /> - <property name="project.review.logsdir" value="${project.basedir}/review/logs" override="true" /> - <property name="project.review.docsdir" value="${project.reviewdir}/docs" override="true" /> - <property name="project.review.codebrowserdir" value="${project.reviewdir}/code-browser" override="true" /> - <property name="project.review.codecoveragedir" value="${project.reviewdir}/code-coverage" override="true" /> - - <property name="project.builddir" value="${project.basedir}/.build" override="true" /> - <property name="project.pkgdir" value="${project.builddir}/${project.name}-${project.version}" override="true" /> - <property name="project.tmpdir" value="${project.basedir}/.tmp" override="true" /> - - <property name="project.vendordir" value="${project.basedir}/vendor" override="true" /> - <property name="project.vendor.bindir" value="${project.vendordir}/bin" override="true" /> - <property name="project.vendor.datadir" value="${project.vendordir}/data" override="true" /> - <property name="project.vendor.phpdir" value="${project.vendordir}/php" override="true" /> - <property name="project.vendor.testdir" value="${project.vendordir}/tests" override="true" /> - <property name="project.vendor.docdir" value="${project.vendordir}/docs" override="true" /> - <property name="project.vendor.wwwdir" value="${project.vendordir}/www" override="true" /> - - <property name="project.distdir" value="${project.basedir}/dist" /> - <property name="project.distdir.lastBuilt" value="${project.basedir}/dist/lastBuilt" /> - <property name="project.tarfilename" value="${project.name}-${project.version}.tgz" /> - <property name="project.tarfile" value="${project.distdir}/${project.tarfilename}" /> - - <!-- what was the last PEAR package we created, if any? --> - <if> - <available file="${project.distdir.lastBuilt}"/> - <then> - <property file="${project.distdir.lastBuilt}"/> - </then> - <else> - <property name="project.lastBuiltTarfile" value="false"/> - </else> - </if> - - <!-- override this if you want to run additional PEAR commands --> - <property name="pear.cmd" value="" override="true" /> - - <!-- lists of the files that make up our package --> - <fileset dir="${project.src.bindir}" id="binfiles"> - <include name="**/**"/> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> - </fileset> - <fileset dir="${project.src.datadir}" id="datafiles"> - <include name="**/**"/> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> - </fileset> - <fileset dir="${project.src.phpdir}" id="phpfiles"> - <include name="**/*.php"/> - </fileset> - <fileset dir="${project.src.testunitdir}/php" id="testfiles"> - <include name="**/**"/> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> - </fileset> - <fileset dir="${project.src.wwwdir}" id="wwwfiles"> - <include name="**/**" /> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> - </fileset> - <fileset dir="${project.src.docdir}" id="docfiles"> - <include name="**/**" /> - <exclude name="**/.DS_Store"/> - <exclude name="**/.empty"/> - <exclude name="**/.git*"/> - </fileset> - <fileset dir="${project.basedir}" id="topleveldocfiles"> - <include name="*.txt" /> - <include name="*.md" /> - </fileset> - - <taskdef name="phingcallifexists" classname="Phix_Project.ComponentManager.Phing.PhingCallIfExistsTask" /> - <import file="build.local.xml"/> - - <!-- Tell the user what this build file supports --> - <target name="help"> - <echo message="${project.name} ${project.version}: build.xml targets:" /> - <echo message="" /> - <echo message="Setup your dev environment:" /> - <echo message="" /> - <echo message=" build-vendor" /> - <echo message=" Populate vendor/ with this package's dependencies" /> - <echo message=" vendor-pear" /> - <echo message=" Run additional PEAR commands inside the vendor folder" /> - <echo message="" /> - <echo message="Develop your code:" /> - <echo message="" /> - <echo message=" lint" /> - <echo message=" Check the PHP files for syntax errors" /> - <echo message=" test" /> - <echo message=" Run the component's PHPUnit tests" /> - <echo message=" code-review" /> - <echo message=" Run all of the code quality targets:" /> - <echo message="" /> - <echo message=" code-browser" /> - <echo message=" Run code quality tests for PHP_CodeBrowser" /> - <echo message=" phpcpd" /> - <echo message=" Check for cut and paste problems" /> - <echo message=" phpdoc" /> - <echo message=" Create the PHP docs from source code" /> - <echo message="" /> - <echo message="Publish your component:" /> - <echo message="" /> - <echo message=" pear-package" /> - <echo message=" Create a PEAR-compatible package" /> - <echo message=" publish-local" /> - <echo message=" Publish your PEAR-compatible package into a local copy" /> - <echo message=" of your PEAR channel" /> - <echo message=" install-vendor" /> - <echo message=" Install this component from source into vendor/" /> - <echo message=" install-system" /> - <echo message=" Install this component from source for all local users" /> - <echo message=" You must be root to run this target on Linux!!" /> - <echo message=""/> - <echo message="Maintain your component:"/> - <echo message=""/> - <echo message=" upgrade-skeleton"/> - <echo message=" Upgrade the skeleton files for this component"/> - <echo message=""/> - <echo message="Additional targets:" /> - <echo message=""/> - <echo message=" clean" /> - <echo message=" Remove all temporary folders created by this build file" /> - <echo message=" version" /> - <echo message=" Show this component's version from build.properties" /> - <echo message="" /> - <phingcallifexists target="local.help" /> - </target> - - <!-- Show the current version, as set in build.properties --> - <!-- This is just to be a time-saver --> - <target name="version"> - <echo message="${project.version}" /> - </target> - - <!-- Run PHP lint on all of the source code --> - <target name="lint"> - <phplint> - <fileset dir="${project.src.phpdir}"> - <include name="**/*.php" /> - </fileset> - </phplint> - <phingcallifexists target="local.lint" /> - </target> - - <!-- Run the unit tests for this module --> - <target name="run-unittests" depends="lint"> - <!-- Make sure vendor/ folder exists --> - <if> - <not> - <available file="${project.vendordir}" type="dir"/> - </not> - <then> - <phingcall target="build-vendor"/> - </then> - </if> - - <!-- do we have any tests? --> - <!-- currently cannot think of a reliable way to test this in phing --> - - <!-- run the tests --> - <delete dir="${project.review.codecoveragedir}" /> - <mkdir dir="${project.review.codecoveragedir}" /> - <mkdir dir="${project.review.logsdir}" /> - <exec command="phpunit --configuration=phpunit.xml ${project.src.testunitdir}" checkreturn="true" logoutput="true"/> - <echo/> - <echo>The code coverage report is in file://${project.review.codecoveragedir}</echo> - <echo/> - </target> - - <!-- Run all the tests for this module --> - <target name="test" depends="run-unittests"> - <phingcallifexists target="local.test"/> - </target> - - <!-- Run the code review quality tests --> - <target name="code-review" depends="run-unittests, code-browser, phpcpd, pdepend"> - <phingcallifexists target="local.code-review"/> - </target> - - <!-- Run all of the targets for setting up the code browser --> - <target name="code-browser" depends="phpmd, phpcs, phpcb"> - <phingcallifexists target="local.code-browser"/> - </target> - - <target name="pdepend"> - <mkdir dir="${project.review.logsdir}" /> - <exec command="pdepend --phpunit-xml=${project.review.logsdir}/pdepend.xml --jdepend-xml=${project.review.logsdir}/jdepend.xml --jdepend-chart=${project.review.logsdir}/dependencies.svg --overview-pyramid=${project.review.logsdir}/overview-pyramid.svg ${project.src.phpdir}" logoutput="true"/> - </target> - - <!-- Generate package docs --> - <target name="phpdoc"> - <mkdir dir="${project.review.logsdir}" /> - <exec command="phpdoc -d ${project.src.phpdir} -t ${project.review.docsdir}" logoutput="true"/> - <echo message="You will find the PHPDoc for your project at: ${project.review.docsdir}/index.html"/> - <phingcallifexists target="local.phpdoc"/> - </target> - - <!-- Check code for code smells --> - <target name="phpmd"> - <mkdir dir="${project.review.logsdir}" /> - <exec command="phpmd ${project.src.phpdir} xml codesize,design,naming,unusedcode --reportfile ${project.review.logsdir}/phpmd.xml" logoutput="true" /> - </target> - - <target name="phpcpd"> - <mkdir dir="${project.review.logsdir}"/> - <exec command="phpcpd --log-pmd ${project.review.logsdir}/pmd-cpd.xml ${project.src.phpdir}" logoutput="true" /> - </target> - - <!-- Check the code for style violations --> - <target name="phpcs"> - <mkdir dir="${project.review.logsdir}" /> - <exec command="phpcs --report=xml --report-file=${project.review.logsdir}/checkstyle.xml --standard=${checkstyle.standard} --extensions=php ${project.src.phpdir}" logoutput="true"/> - </target> - - <!-- Build the code-browser files --> - <target name="phpcb" depends="phpmd"> - <delete dir="${project.review.codebrowserdir}" /> - <mkdir dir="${project.review.codebrowserdir}" /> - <exec command="phpcb --log ${project.review.logsdir} --source ${project.src.phpdir} --output ${project.review.codebrowserdir}" logoutput="true" /> - </target> - - <!-- Populate vendor with the dependencies for this component --> - <target name="build-vendor" depends="pear-package,setup-vendor"> - <echo>Populating vendor/ with dependencies</echo> - <exec command="phix pear:register-channels" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config install --alldeps ${project.tarfile}" logoutput="true" checkreturn="true"/> - <echo/> - <echo>Your vendor/ folder has been built.</echo> - <echo>You only need to run 'phing build-vendor' again if you change the</echo> - <echo>dependencies listed in your package.xml file.</echo> - <echo/> - <phingcallifexists target="local.buildvendor"/> - </target> - - <!-- Setup the vendor folder --> - <target name="setup-vendor"> - <echo>Creating vendor/ as a sandboxed PEAR install folder</echo> - <delete dir="${project.vendordir}" /> - <mkdir dir="${project.vendordir}" /> - <delete dir="${project.tmpdir}" /> - <mkdir dir="${project.tmpdir}" /> - <exec command="pear config-create ${project.tmpdir} ${project.tmpdir}/pear-config" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set preferred_state alpha" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set php_dir ${project.vendor.phpdir}" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set bin_dir ${project.vendor.bindir}" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set data_dir ${project.vendor.datadir}" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set doc_dir ${project.vendor.docdir}" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set test_dir ${project.vendor.testdir}" checkreturn="true" logoutput="true" /> - <exec command="pear -c ${project.tmpdir}/pear-config config-set www_dir ${project.vendor.wwwdir}" checkreturn="true" logoutput="true" /> - </target> - - <!-- Create the PEAR package, ready for release --> - <target name="pear-package"> - <echo>Building release directory</echo> - <delete dir="${project.builddir}" /> - <mkdir dir="${project.pkgdir}" /> - <copy todir="${project.pkgdir}"> - <fileset refid="binfiles"/> - <fileset refid="datafiles"/> - <fileset refid="phpfiles"/> - <fileset refid="testfiles"/> - <fileset refid="wwwfiles"/> - <fileset refid="docfiles"/> - <fileset refid="topleveldocfiles"/> - </copy> - <copy todir="${project.builddir}"> - <fileset dir="."> - <include name="package.xml" /> - </fileset> - </copy> - - <exec command="phix pear:expand-package-xml" checkreturn="yes" logoutput="yes"/> - - <echo>Creating ${project.tarfile} PEAR package</echo> - - <mkdir dir="${project.distdir}" /> - <delete file="${project.tarfile}" /> - <tar destfile="${project.tarfile}" compression="gzip"> - <fileset dir="${project.builddir}"> - <include name="**/**" /> - </fileset> - </tar> - - <!-- remember the tarball we have just build --> - <property name="project.lastBuiltTarfile" value="${project.tarfile}" override="true"/> - <echo file="${project.distdir.lastBuilt}" append="false">project.lastBuiltTarfile=${project.tarfile}</echo> - - <!-- write a message to say which file we built last --> - <echo>Your PEAR package is in ${project.tarfile}</echo> - <phingcallifexists target="local.pear-package"/> - </target> - - <!-- Install the code --> - <target name="install-vendor"> - <if> - <not> - <contains string="${project.lastBuiltTarfile}" substring="${project.name}"/> - </not> - <then> - <echo>Please run 'phing pear-package' first, then try again.</echo> - </then> - <elseif> - <available file="${project.lastBuiltTarfile}"/> - <then> - <exec command="pear -c ${project.tmpdir}/pear-config install --alldeps -f ${project.lastBuiltTarfile}" logoutput="true" checkreturn="true"/> - <phingcallifexists target="local.install-vendor"/> - </then> - </elseif> - <else> - <echo>Cannot find PEAR package file ${project.lastBuiltTarfile}</echo> - <echo>Run 'phing pear-package' to create a new PEAR package, then try again</echo> - </else> - </if> - </target> - - <!-- install a package system-wide --> - <target name="install-system"> - <if> - <not> - <contains string="${project.lastBuiltTarfile}" substring="${project.name}"/> - </not> - <then> - <echo>Please run 'phing pear-package' first, then try again.</echo> - </then> - <elseif> - <available file="${project.lastBuiltTarfile}"/> - <then> - <exec command="pear install -f -a ${project.lastBuiltTarfile}" checkreturn="true" logoutput="true" /> - <phingcallifexists target="local.install-system"/> - </then> - </elseif> - <else> - <echo>Cannot find PEAR package file ${project.lastBuiltTarfile}</echo> - <echo>Run 'phing pear-package' to create a new PEAR package, then try again</echo> - </else> - </if> - </target> - - <!-- Publish to local copy of PEAR channel --> - <target name="publish-local" depends="pear-package"> - <if> - <not> - <contains string="${project.lastBuiltTarfile}" substring="${project.name}"/> - </not> - <then> - <echo>Please run 'phing pear-package' first, then try again.</echo> - </then> - <elseif> - <available file="${project.lastBuiltTarfile}"/> - <then> - <!-- get rid of any existing snapshots we may have published --> - <foreach param="packagefile" absparam="abspackagefile" target="pirum-remove-package"> - <fileset dir="${pear.local}/get"> - <include name="${project.name}*snapshot*.tgz" /> - </fileset> - </foreach> - - <!-- publish the new PEAR package --> - <exec command="pirum add ${pear.local} ${project.lastBuiltTarfile}" checkreturn="true" logoutput="true" /> - <phingcallifexists target="local.publish-local"/> - </then> - </elseif> - <else> - <echo>Cannot find PEAR package file ${project.lastBuiltTarfile}</echo> - <echo>Run 'phing pear-package' to create a new PEAR package, then try again</echo> - </else> - </if> - </target> - - <target name="pirum-remove-package"> - <exec command="pirum remove ${pear.local} ${packagefile}" logoutput="true" checkreturn="true" /> - </target> - - <!-- Run additional PEAR commands in the vendor folder --> - <target name="vendor-pear"> - <exec command="pear -c ${project.tmpdir}/pear-config ${pear.cmd}" logoutput="true" checkreturn="true" /> - </target> - - <!-- Upgrade the skeleton files here and now --> - <target name="upgrade-skeleton"> - <exec command="phix ${component.type}:upgrade ." logoutput="true" checkreturn="true" /> - <phingcallifexists target="local.upgrade-skeleton"/> - </target> - - <!-- Clean up the mess --> - <target name="clean"> - <delete dir="${project.builddir}" /> - <delete dir="${project.distdir}" /> - <delete dir="${project.reviewdir}" /> - <delete dir="${project.pkgdir}" /> - <delete dir="${project.distdir}" /> - <delete dir="${project.tmpdir}" /> - <phingcallifexists target="local.clean"/> - </target> -</project> -<!-- vim: set tabstop=2 shiftwidth=2 expandtab: --> diff --git a/package.xml b/package.xml deleted file mode 100644 index 852e8c4b1..000000000 --- a/package.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<package packagerversion="1.9.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 - http://pear.php.net/dtd/tasks-1.0.xsd - http://pear.php.net/dtd/package-2.0 - http://pear.php.net/dtd/package-2.0.xsd"> - <name>${project.name}</name> - <channel>${project.channel}</channel> - <summary>WordPress CLI interface</summary> - <description> - A tool for controlling WordPress through the command line. - </description> - <lead> - <name>Andreas Creten</name> - <user>andreascreten</user> - <email></email> - <active>yes</active> - </lead> - <lead> - <name>scribu</name> - <user>scribu</user> - <email>mail@scribu.net</email> - <active>yes</active> - </lead> - <date>${build.date}</date> - <time>${build.time}</time> - <version> - <release>${project.version}</release> - <api>${project.majorVersion}.${project.minorVersion}</api> - </version> - <stability> - <release>${project.stability}</release> - <api>stable</api> - </stability> - <license>MIT</license> - <notes> - No notes. - </notes> - <contents> - <dir baseinstalldir="/" name="/"> -${contents} - </dir> - </contents> - <dependencies> - <required> - <php> - <min>5.3.0</min> - </php> - <pearinstaller> - <min>1.9.4</min> - </pearinstaller> - </required> - </dependencies> - <phprelease /> - <changelog> - <release> - <version> - <release>X.Y.Z</release> - <api>X.Y</api> - </version> - <stability> - <release>stable</release> - <api>stable</api> - </stability> - <date>Your release date</date> - <license>All rights reserved</license> - <notes> - </notes> - </release> - </changelog> -</package> -<!-- vim: set tabstop=2 shiftwidth=2 expandtab: --> diff --git a/utils/pear-build b/utils/pear-build deleted file mode 100755 index f2be1b3fd..000000000 --- a/utils/pear-build +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -set -ex - -# create bunch of directories that phing complains about -mkdir -p docs data www tests/unit-tests/php - -# generate package -phing pear-package - -version=$(cat dist/lastBuilt) -version="${version/*wpcli-/}" -version="${version/.tgz/}" - -#sudo phing install-system - -# update channel files -pear_repo=../wp-cli-pear - -pirum add $pear_repo ../wp-cli/dist/wpcli-$version.tgz -pirum build $pear_repo - -# push changes -cd $pear_repo - -git add -A -git ci -m "release $version" -git push origin gh-pages From bd0ad30c018b3f33ed9b7bb1f4eece7536a511ce Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 8 Feb 2013 15:33:54 -0800 Subject: [PATCH 1199/5359] Introduce system editor function in \WP_CLI\Utils Adds a function called `launch_editor_for_input()` which launches the system's editor to allow file editing of post content, etc. Should account for system line-endings properly, but probably needs testing on Windows to be sure. Function returns false if no change (ie user :q!'s out of vim), or updated content if any change is made. Also adds two new subcommands to `wp post`: - `wp post create --edit` Launches the editor to build the post content before creating post. - `wp post edit <id>` Edits post <id>'s content in system editor. --- php/commands/post.php | 37 ++++++++++++++++++++++++++++++++++++- php/utils.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 1e69d24b7..d741b885d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -12,9 +12,21 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { /** * Create a post. * - * @synopsis --<field>=<value> [--porcelain] + * @synopsis --<field>=<value> [--edit] [--porcelain] */ public function create( $_, $assoc_args ) { + if ( isset( $assoc_args['edit'] ) ) { + + $input = ( isset( $assoc_args['post_content'] ) ) ? + $assoc_args['post_content'] : ''; + + if ( $output = \WP_CLI\Utils\launch_editor_for_input( $input ) ) + $assoc_args['post_content'] = $output; + else + $assoc_args['post_content'] = $input; + + } + parent::create( $assoc_args ); } @@ -35,6 +47,29 @@ protected function _update( $params ) { return wp_update_post( $params, true ); } + /** + * Launch system editor to edit post content + * + * @synopsis <id>... + */ + public function edit( $args, $assoc_args ) { + $post_id = $args[0]; + if ( !$post_id || !$post = get_post( $post_id ) ) { + \WP_CLI::error( "Failed opening post $post_id to edit.", false ); + return; + } + + $r = \WP_CLI\Utils\launch_editor_for_input( $post->post_content ); + + if ( !$r ) { + \WP_CLI::error( "Aborting. No change made to post.", false ); + return; + } + + $assoc_args['post_content'] = $r; + parent::update( $args, $assoc_args ); + } + /** * Delete a post by ID. * diff --git a/php/utils.php b/php/utils.php index 4e06615c7..c68545a16 100644 --- a/php/utils.php +++ b/php/utils.php @@ -257,5 +257,35 @@ function output_csv( $rows, $headers = array() ) { } fputcsv( STDOUT, $row ); } + } +/** + * Launch system's $EDITOR to edit text + * + * @param str $content Text to edit (eg post content) + * @return str|bool Edited text, if file is saved from editor + */ +function launch_editor_for_input( $input ) { + + $tmpfile = tempnam( '/tmp', 'wp-cli' ); + + if ( !$tmpfile ) + die( 'Error creating temporary file.' ); + + $handle = fopen( $tmpfile, 'w+t' ); + fwrite( $handle, $input ); + fclose( $handle ); + + $out = `\${EDITOR:-vi} "$tmpfile" 3>&1 1>&2 2>&3 || exit $?`; + + $handle = fopen( $tmpfile, 'r' ); + $output = fread( $handle, filesize( $tmpfile ) ); + fclose( $handle ); + unlink( $tmpfile ); + + if ( $output === $input ) + return false; + + return $output; +} From 32b851e3cc405c067d2eee59c716c90b229d5523 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 17:07:24 +0200 Subject: [PATCH 1200/5359] replace <parent> with <term-id> --- man-src/term-create.txt | 4 ++-- php/commands/term.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/man-src/term-create.txt b/man-src/term-create.txt index 31ca3a4ee..e34cd3842 100644 --- a/man-src/term-create.txt +++ b/man-src/term-create.txt @@ -16,10 +16,10 @@ A description for the new term. -* `--parent`=<parent>: +* `--parent`=<term-id>: A parent for the new term. ## EXAMPLES - wp term create Apple category --description="A type of fruit" \ No newline at end of file + wp term create Apple category --description="A type of fruit" diff --git a/php/commands/term.php b/php/commands/term.php index 888ef2da5..148559e1a 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -40,7 +40,7 @@ public function _list( $args, $assoc_args ) { /** * Create a term. * - * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<parent>] + * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<term-id>] */ public function create( $args, $assoc_args ) { @@ -63,7 +63,7 @@ public function create( $args, $assoc_args ) { /** * Update a term. - * + * * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<parent>] */ public function update( $args, $assoc_args ) { @@ -113,4 +113,4 @@ public function delete( $args ) { } -WP_CLI::add_command( 'term', 'Term_Command' ); \ No newline at end of file +WP_CLI::add_command( 'term', 'Term_Command' ); From 5599b00beffb1bf21cd4e5cc1837536bac7cc8c0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 17:18:28 +0200 Subject: [PATCH 1201/5359] use format_items() utility in wp user list --- php/commands/user.php | 44 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 7ded9497d..7c71e42ad 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -41,45 +41,23 @@ public function _list( $args, $assoc_args ) { 'user_registered' ); - switch( $params['format'] ) { - case 'table': - $table = new \cli\Table(); + $output_users = array(); - $table->setHeaders( array_merge( $fields, array('roles') ) ); + foreach ( $users as $user ) { + $output_user = new stdClass; - foreach ( $users as $user ) { - $line = array(); - - foreach ( $fields as $field ) { - $line[] = $user->$field; - } - $line[] = implode( ',', $user->roles ); - - $table->addRow( $line ); - } + foreach ( $fields as $field ) { + $output_user->$field = $user->$field; + } - $table->display(); + $output_user->roles = implode( ',', $user->roles ); - WP_CLI::line( 'Total: ' . count( $users ) . ' users' ); - break; - case 'json': - case 'csv': - $output_users = array(); + $output_users[] = $output_user; + } - foreach( $users as $user ) { - $output_user = new stdClass; - foreach( $fields as $field ) { - $output_user->$field = $user->$field; - } - $output_users[] = $output_user; - } + $fields[] = 'roles'; - if ( 'json' == $params['format'] ) - echo json_encode( $output_users ); - else - WP_CLI\Utils\output_csv( $output_users, $fields ); - break; - } + WP_CLI\Utils\format_items( $params['format'], $fields, $output_users ); } /** From e2fcc550e5bc8822f1ed8955c7814dc15c5280bb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 17:23:14 +0200 Subject: [PATCH 1202/5359] replace <parent> with <term-id> for wp term update --- man-src/term-update.txt | 4 ++-- php/commands/term.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man-src/term-update.txt b/man-src/term-update.txt index 82ae9a113..cc6bc6cf9 100644 --- a/man-src/term-update.txt +++ b/man-src/term-update.txt @@ -20,10 +20,10 @@ A new description for the term. -* `--parent`=<parent>: +* `--parent`=<term-id>: A new parent for the term. ## EXAMPLES - wp term update 15 category --name=Apple \ No newline at end of file + wp term update 15 category --name=Apple diff --git a/php/commands/term.php b/php/commands/term.php index 148559e1a..f8c999c59 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -64,7 +64,7 @@ public function create( $args, $assoc_args ) { /** * Update a term. * - * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<parent>] + * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<term-id>] */ public function update( $args, $assoc_args ) { From 30ded5cb06b1638527efab4ab2096b15f3aa3b4c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 17:23:46 +0200 Subject: [PATCH 1203/5359] add generated man pages --- man/term-create.1 | 51 ++++++++++++++++++++++++++++++++++++++++++ man/term-delete.1 | 33 +++++++++++++++++++++++++++ man/term-list.1 | 33 +++++++++++++++++++++++++++ man/term-update.1 | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 man/term-create.1 create mode 100644 man/term-delete.1 create mode 100644 man/term-list.1 create mode 100644 man/term-update.1 diff --git a/man/term-create.1 b/man/term-create.1 new file mode 100644 index 000000000..a5cf4ad56 --- /dev/null +++ b/man/term-create.1 @@ -0,0 +1,51 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TERM\-CREATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-term\-create\fR \- Create a term\. +. +.SH "SYNOPSIS" +wp term create \fIterm\fR \fItaxonomy\fR [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] +. +.SH "OPTIONS" +. +.TP +\fB<term>\fR: +. +.IP +A name for the new term\. +. +.TP +\fB<taxonomy>\fR: +. +.IP +Taxonomy for the new term\. +. +.TP +\fB\-\-slug\fR=\fIslug\fR: +. +.IP +A unique slug for the new term\. Defaults to sanitized version of name\. +. +.TP +\fB\-\-description\fR=\fIdescription\fR: +. +.IP +A description for the new term\. +. +.TP +\fB\-\-parent\fR=\fIterm\-id\fR: +. +.IP +A parent for the new term\. +. +.SH "EXAMPLES" +. +.nf + +wp term create Apple category \-\-description="A type of fruit" +. +.fi + diff --git a/man/term-delete.1 b/man/term-delete.1 new file mode 100644 index 000000000..1a9700510 --- /dev/null +++ b/man/term-delete.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TERM\-DELETE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-term\-delete\fR \- Delete a term\. +. +.SH "SYNOPSIS" +wp term delete \fIterm\-id\fR \fItaxonomy\fR +. +.SH "OPTIONS" +. +.TP +\fB<term\-id>\fR: +. +.IP +ID for the term to delete\. +. +.TP +\fB<taxonomy>\fR: +. +.IP +Taxonomy of the term to delete\. +. +.SH "EXAMPLES" +. +.nf + +wp term delete 15 category +. +.fi + diff --git a/man/term-list.1 b/man/term-list.1 new file mode 100644 index 000000000..060772fdd --- /dev/null +++ b/man/term-list.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TERM\-LIST" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-term\-list\fR \- List terms in a taxonomy\. +. +.SH "SYNOPSIS" +wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] +. +.SH "OPTIONS" +. +.TP +\fB<taxonomy>\fR: +. +.IP +List terms of a given taxonomy\. +. +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. +. +.SH "EXAMPLES" +. +.nf + +wp term list category \-\-format=csv +. +.fi + diff --git a/man/term-update.1 b/man/term-update.1 new file mode 100644 index 000000000..34bf099de --- /dev/null +++ b/man/term-update.1 @@ -0,0 +1,57 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-TERM\-UPDATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-term\-update\fR \- Update a term\. +. +.SH "SYNOPSIS" +wp term update \fIterm\-id\fR \fItaxonomy\fR [\-\-name=\fIname\fR] [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] +. +.SH "OPTIONS" +. +.TP +\fB<term\-id>\fR: +. +.IP +ID for the term to update\. +. +.TP +\fB<taxonomy>\fR: +. +.IP +Taxonomy of the term to update\. +. +.TP +\fB\-\-name\fR=\fIname\fR: +. +.IP +A new name for the term\. +. +.TP +\fB\-\-slug\fR=\fIslug\fR: +. +.IP +A new slug for the term\. +. +.TP +\fB\-\-description\fR=\fIdescription\fR: +. +.IP +A new description for the term\. +. +.TP +\fB\-\-parent\fR=\fIterm\-id\fR: +. +.IP +A new parent for the term\. +. +.SH "EXAMPLES" +. +.nf + +wp term update 15 category \-\-name=Apple +. +.fi + From 30f83685104b1a3c07026c004fba22519444a2a9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 17:47:05 +0200 Subject: [PATCH 1204/5359] fix indenting for term command. see #286 --- php/commands/term.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index f8c999c59..9c4e82a1e 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -17,22 +17,22 @@ public function _list( $args, $assoc_args ) { list( $taxonomy ) = $args; $defaults = array( - 'format' => 'table', - 'hide_empty' => false, - ); + 'format' => 'table', + 'hide_empty' => false, + ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); $terms = get_terms( array( $taxonomy ), $assoc_args ); $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', - ); + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', + ); WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); } @@ -47,10 +47,10 @@ public function create( $args, $assoc_args ) { list( $term, $taxonomy ) = $args; $defaults = array( - 'slug' => sanitize_title( $term ), - 'description' => '', - 'parent' => '', - ); + 'slug' => sanitize_title( $term ), + 'description' => '', + 'parent' => '', + ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); @@ -71,11 +71,11 @@ public function update( $args, $assoc_args ) { list( $term_id, $taxonomy ) = $args; $defaults = array( - 'name' => null, - 'slug' => null, - 'description' => null, - 'parent' => null, - ); + 'name' => null, + 'slug' => null, + 'description' => null, + 'parent' => null, + ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); foreach( $assoc_args as $key => $value ) { @@ -89,7 +89,6 @@ public function update( $args, $assoc_args ) { WP_CLI::error( $ret->get_error_message() ); else WP_CLI::success( "Term updated." ); - } /** @@ -114,3 +113,4 @@ public function delete( $args ) { } WP_CLI::add_command( 'term', 'Term_Command' ); + From d74537e2e5df5dab9fb02f62165e08cd9c194793 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 18:17:39 +0200 Subject: [PATCH 1205/5359] remove superfluous parameters from post and taxonomy scaffolds --- php/commands/scaffold.php | 40 ++++++------------------------------ templates/post_type.mustache | 24 ++++++++-------------- templates/taxonomy.mustache | 16 +++++++-------- 3 files changed, 21 insertions(+), 59 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 08996cdec..36be7ab54 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -18,27 +18,11 @@ function __construct() { * * @alias cpt * - * @synopsis <slug> [--singular=<label>] [--description=<description>] [--public=<public>] [--exclude_from_search=<exclude_from_search>] [--show_ui=<show_ui>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_in_menu=<show_in_menu>] [--show_in_admin_bar=<show_in_admin_bar>] [--menu_position=<menu_position>] [--menu_icon=<menu_icon>] [--capability_type=<capability_type>] [--hierarchical=<hierarchical>] [--supports=<supports>] [--has_archive=<has_archive>] [--query_var=<query_var>] [--can_export=<can_export>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function post_type( $args, $assoc_args ) { $defaults = array( - 'description' => '', - 'public' => 'true', - 'exclude_from_search' => 'false', - 'show_ui' => 'true', - 'show_in_nav_menus' => 'true', - 'show_in_menu' => 'true', - 'show_in_admin_bar' => 'true', - 'menu_position' => 'null', - 'menu_icon' => 'null', - 'capability_type' => 'post', - 'hierarchical' => 'false', - 'supports' => "'title', 'editor'", - 'has_archive' => 'true', - 'rewrite' => 'true', - 'query_var' => 'true', - 'can_export' => 'true', - 'textdomain' => '', + 'textdomain' => '', ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( @@ -54,19 +38,12 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis <slug> [--singular=<label>] [--public=<public>] [--show_in_nav_menus=<show_in_nav_menus>] [--show_ui=<show_ui>] [--show_tagcloud=<show_tagcloud>] [--hierarchical=<hierarchical>] [--rewrite=<rewrite>] [--query_var=<query_var>] [--textdomain=<textdomain>] [--post_types=<post_types>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--post_types=<post-types>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function taxonomy( $args, $assoc_args ) { $defaults = array( - 'public' => 'true', - 'show_in_nav_menus' => 'true', - 'show_ui' => 'true', - 'show_tagcloud' => 'true', - 'hierarchical' => 'false', - 'rewrite' => 'true', - 'query_var' => 'true', - 'post_types' => 'post', - 'textdomain' => '', + 'textdomain' => '', + 'post_types' => 'post' ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( @@ -90,12 +67,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); - // If no label is given use the slug and prettify it as good as possible - if ( isset( $assoc_args['singular'] ) ) { - $vars['label'] = $assoc_args['singular']; - } else { - $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $slug ) ); - } + $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $slug ) ); $vars['label_ucfirst'] = ucfirst( $vars['label'] ); $vars['label_plural'] = $this->pluralize( $vars['label'] ); diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 00e9d652d..44ebb048e 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -1,20 +1,12 @@ register_post_type( '{{slug}}', array( - 'description' => __( '{{description}}', '{{textdomain}}' ), - 'public' => {{public}}, - 'exclude_from_search' => {{exclude_from_search}}, - 'show_ui' => {{show_ui}}, - 'show_in_nav_menus' => {{show_in_nav_menus}}, - 'show_in_menu' => {{show_in_menu}}, - 'show_in_admin_bar' => {{show_in_admin_bar}}, - 'menu_position' => {{menu_position}}, - 'menu_icon' => {{menu_icon}}, - 'capability_type' => '{{capability_type}}', - 'hierarchical' => {{hierarchical}}, - 'supports' => array( {{supports}} ), - 'has_archive' => {{has_archive}}, - 'rewrite' => {{rewrite}}, - 'query_var' => {{query_var}}, - 'can_export' => {{can_export}}, + 'hierarchical' => false, + 'public' => true, + 'show_in_nav_menus' => true, + 'show_ui' => true, + 'supports' => array( 'title', 'editor' ), + 'has_archive' => true, + 'query_var' => {{slug}}, + 'rewrite' => true, 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index db2ba2e37..20747a722 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -1,13 +1,11 @@ register_taxonomy( '{{slug}}', array( '{{post_types}}' ), array( - 'public' => {{public}}, - 'show_in_nav_menus' => {{show_in_nav_menus}}, - 'show_ui' => {{show_ui}}, - 'show_tagcloud' => {{show_tagcloud}}, - 'hierarchical' => {{hierarchical}}, - 'update_count_callback' => '_update_post_term_count', - 'query_var' => {{query_var}}, - 'rewrite' => {{rewrite}}, - 'capabilities' => array ( + 'hierarchical' => false, + 'public' => true, + 'show_in_nav_menus' => true, + 'show_ui' => true, + 'query_var' => {{slug}}, + 'rewrite' => true, + 'capabilities' => array( 'manage_terms' => 'edit_posts', 'edit_terms' => 'edit_posts', 'delete_terms' => 'edit_posts', From 79efd4e08a88cf8aa012cfff99564fca0440d4d8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 18:19:46 +0200 Subject: [PATCH 1206/5359] regenerate manpages --- man/scaffold-post-type.1 | 2 +- man/scaffold-taxonomy.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 index 208d21cda..5e9223561 100644 --- a/man/scaffold-post-type.1 +++ b/man/scaffold-post-type.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. . .SH "SYNOPSIS" -wp scaffold post\-type \fIslug\fR [\-\-singular=\fIlabel\fR] [\-\-description=\fIdescription\fR] [\-\-public=\fIpublic\fR] [\-\-exclude_from_search=\fIexclude_from_search\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_in_menu=\fIshow_in_menu\fR] [\-\-show_in_admin_bar=\fIshow_in_admin_bar\fR] [\-\-menu_position=\fImenu_position\fR] [\-\-menu_icon=\fImenu_icon\fR] [\-\-capability_type=\fIcapability_type\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-supports=\fIsupports\fR] [\-\-has_archive=\fIhas_archive\fR] [\-\-query_var=\fIquery_var\fR] [\-\-can_export=\fIcan_export\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold post\-type \fIslug\fR [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index d6f65ef62..6af8faf4f 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. . .SH "SYNOPSIS" -wp scaffold taxonomy \fIslug\fR [\-\-singular=\fIlabel\fR] [\-\-public=\fIpublic\fR] [\-\-show_in_nav_menus=\fIshow_in_nav_menus\fR] [\-\-show_ui=\fIshow_ui\fR] [\-\-show_tagcloud=\fIshow_tagcloud\fR] [\-\-hierarchical=\fIhierarchical\fR] [\-\-rewrite=\fIrewrite\fR] [\-\-query_var=\fIquery_var\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-post_types=\fIpost_types\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . From 478d21235b0deeda574f5666e0bf2903ce6f2b7b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Feb 2013 18:43:11 +0200 Subject: [PATCH 1207/5359] remove @@PHP_DIR@@ reference. see #301 --- bin/wp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bin/wp b/bin/wp index d2cfa79f8..0ae1dabd5 100755 --- a/bin/wp +++ b/bin/wp @@ -23,12 +23,7 @@ done cd "$ORIGDIR" # Build the path to the root PHP file -SCRIPT_PATH='@@PHP_DIR@@' -if [ ! -d $SCRIPT_PATH ]; then - SCRIPT_PATH=$(dirname "$SELF_PATH")/../php -fi - -SCRIPT_PATH=$SCRIPT_PATH/boot-fs.php +SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/boot-fs.php case $(uname -a) in CYGWIN*) From 4d3fcccebc36a20115ad927dd83aef0b6ef5cbdd Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 13 Feb 2013 11:21:20 -0800 Subject: [PATCH 1208/5359] Use WP_CLI::launch to open editor Also use wp_tempnam to create file, and give the created file a meaningful name rather than just using system or php's tempfile name. --- php/commands/post.php | 4 ++-- php/utils.php | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index d741b885d..f4b8f0b2d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -20,7 +20,7 @@ public function create( $_, $assoc_args ) { $input = ( isset( $assoc_args['post_content'] ) ) ? $assoc_args['post_content'] : ''; - if ( $output = \WP_CLI\Utils\launch_editor_for_input( $input ) ) + if ( $output = \WP_CLI\Utils\launch_editor_for_input( $input, 'WP-CLI: New Post' ) ) $assoc_args['post_content'] = $output; else $assoc_args['post_content'] = $input; @@ -59,7 +59,7 @@ public function edit( $args, $assoc_args ) { return; } - $r = \WP_CLI\Utils\launch_editor_for_input( $post->post_content ); + $r = \WP_CLI\Utils\launch_editor_for_input( $post->post_content, "WP-CLI post $post_id" ); if ( !$r ) { \WP_CLI::error( "Aborting. No change made to post.", false ); diff --git a/php/utils.php b/php/utils.php index c68545a16..68cc356ef 100644 --- a/php/utils.php +++ b/php/utils.php @@ -265,10 +265,11 @@ function output_csv( $rows, $headers = array() ) { * * @param str $content Text to edit (eg post content) * @return str|bool Edited text, if file is saved from editor + * False, if no change to file */ -function launch_editor_for_input( $input ) { +function launch_editor_for_input( $input, $title = 'WP-CLI' ) { - $tmpfile = tempnam( '/tmp', 'wp-cli' ); + $tmpfile = wp_tempnam( $title ); if ( !$tmpfile ) die( 'Error creating temporary file.' ); @@ -277,7 +278,7 @@ function launch_editor_for_input( $input ) { fwrite( $handle, $input ); fclose( $handle ); - $out = `\${EDITOR:-vi} "$tmpfile" 3>&1 1>&2 2>&3 || exit $?`; + \WP_CLI::launch( "\${EDITOR:-vi} '$tmpfile'" ); $handle = fopen( $tmpfile, 'r' ); $output = fread( $handle, filesize( $tmpfile ) ); From b295e89e57fce49d04e83a4d559fa51abd3f43e8 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 13 Feb 2013 11:23:45 -0800 Subject: [PATCH 1209/5359] Handle error caused by reading empty file `fread()` will throw an error if trying to read an empty file (ie if user deleted all post content or quit the editor on `wp post create`. Detect that and fail gracefully. --- php/utils.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 68cc356ef..bb0ee3de8 100644 --- a/php/utils.php +++ b/php/utils.php @@ -280,8 +280,13 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { \WP_CLI::launch( "\${EDITOR:-vi} '$tmpfile'" ); + $filesize = filesize( $tmpfile ); + + if ( $filesize === 0 ) + return false; + $handle = fopen( $tmpfile, 'r' ); - $output = fread( $handle, filesize( $tmpfile ) ); + $output = fread( $handle, $filesize ); fclose( $handle ); unlink( $tmpfile ); From 479a1788d09783b9b8817b172b03f3c9cc85001d Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 13 Feb 2013 15:59:24 -0800 Subject: [PATCH 1210/5359] Use file_put_contents/file_get_contents instead of fwrite/fread Much simpler this way. Also does away with the need to check for empty output, although now we have to check the return value of `launch_editor_for_input` strictly against false, since its possible for it to return an empty string now (editing a post and deleting all the content). --- php/commands/post.php | 2 +- php/utils.php | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index f4b8f0b2d..8714b7cba 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -61,7 +61,7 @@ public function edit( $args, $assoc_args ) { $r = \WP_CLI\Utils\launch_editor_for_input( $post->post_content, "WP-CLI post $post_id" ); - if ( !$r ) { + if ( $r === false ) { \WP_CLI::error( "Aborting. No change made to post.", false ); return; } diff --git a/php/utils.php b/php/utils.php index bb0ee3de8..2f3f5e6de 100644 --- a/php/utils.php +++ b/php/utils.php @@ -274,20 +274,12 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { if ( !$tmpfile ) die( 'Error creating temporary file.' ); - $handle = fopen( $tmpfile, 'w+t' ); - fwrite( $handle, $input ); - fclose( $handle ); + file_put_contents( $tmpfile, $input ); \WP_CLI::launch( "\${EDITOR:-vi} '$tmpfile'" ); - $filesize = filesize( $tmpfile ); + $output = file_get_contents( $tmpfile ); - if ( $filesize === 0 ) - return false; - - $handle = fopen( $tmpfile, 'r' ); - $output = fread( $handle, $filesize ); - fclose( $handle ); unlink( $tmpfile ); if ( $output === $input ) From e5433ecaf4b838a589560c25cb960de4a89333c8 Mon Sep 17 00:00:00 2001 From: Nikolay Bachiyski <nb@nikolay.bg> Date: Thu, 14 Feb 2013 16:28:40 +0200 Subject: [PATCH 1211/5359] Exit on end-of-file It's a common practice shells to exit on end-of-file. WP-CLI doesn't do this. I traced the reason to the fact we're not checking the exit code from the `read` builtin. If it timeouts or receives end-of-file, it's non-zero. In both these cases it makes sense to exit. --- php/commands/shell.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/shell.php b/php/commands/shell.php index c0e73760f..75a90151d 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -52,6 +52,10 @@ private static function prompt() { $line = fgets( $fp ); + if ( !$line ) { + $line = 'exit'; + } + return trim( $line ); } @@ -61,6 +65,7 @@ private static function create_prompt_cmd( $prompt, $history_path ) { sprintf( 'history -r %s', escapeshellarg( $history_path ) ), 'LINE=""', sprintf( 'read -re -p %s LINE', escapeshellarg( $prompt ) ), + '[ $? -eq 0 ] || exit', 'history -s "$LINE"', sprintf( 'history -w %s', escapeshellarg( $history_path ) ), 'echo $LINE' From eeba0afaf5005101a92cc9b60ec3adf882561c1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 14 Feb 2013 17:09:01 +0200 Subject: [PATCH 1212/5359] allow whitespace before the 'require' statement in wp-config.php. see #288 --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 1daa7ef48..1683393fd 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -151,7 +151,7 @@ function get_wp_config_code() { $lines_to_run = array(); foreach ( $wp_config_code as $line ) { - if ( preg_match( '/^require.+wp-settings\.php/', $line ) ) + if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) continue; $lines_to_run[] = str_replace( $old, $new, $line ); From e9f17aa732cdd393ede0400316bb97b2b697ebcb Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 14 Feb 2013 15:29:16 -0800 Subject: [PATCH 1213/5359] Make error messages and output codes more logical Use `WP_CLI::error` for any fatal errors. Output a warning rather than an error if user aborts the editor (At this point it exits without performing any action just like an error would, but it shouldn't be considered an error. Also, its possible that commands using the editor function will go on to perform other actions.) Also, whitespace cleanup and minor refactoring... making a helper method `_edit()` in post.php to make editor functions more reusable. --- php/commands/post.php | 27 +++++++++++++-------------- php/utils.php | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 8714b7cba..5a27d54ef 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -20,7 +20,7 @@ public function create( $_, $assoc_args ) { $input = ( isset( $assoc_args['post_content'] ) ) ? $assoc_args['post_content'] : ''; - if ( $output = \WP_CLI\Utils\launch_editor_for_input( $input, 'WP-CLI: New Post' ) ) + if ( $output = $this->_edit( $input, 'WP-CLI: New Post' ) ) $assoc_args['post_content'] = $output; else $assoc_args['post_content'] = $input; @@ -50,24 +50,23 @@ protected function _update( $params ) { /** * Launch system editor to edit post content * - * @synopsis <id>... + * @synopsis <id> */ - public function edit( $args, $assoc_args ) { + public function edit( $args, $_ ) { $post_id = $args[0]; - if ( !$post_id || !$post = get_post( $post_id ) ) { - \WP_CLI::error( "Failed opening post $post_id to edit.", false ); - return; - } + if ( !$post_id || !$post = get_post( $post_id ) ) + \WP_CLI::error( "Failed opening post $post_id to edit." ); - $r = \WP_CLI\Utils\launch_editor_for_input( $post->post_content, "WP-CLI post $post_id" ); + $r = $this->_edit( $post->post_content, "WP-CLI post $post_id" ); - if ( $r === false ) { - \WP_CLI::error( "Aborting. No change made to post.", false ); - return; - } + if ( $r === false ) + \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); + else + parent::update( $args, array( 'post_content' => $r ) ); + } - $assoc_args['post_content'] = $r; - parent::update( $args, $assoc_args ); + protected function _edit( $content, $title ) { + return \WP_CLI\Utils\launch_editor_for_input( $content, $title ); } /** diff --git a/php/utils.php b/php/utils.php index 2f3f5e6de..26be917ca 100644 --- a/php/utils.php +++ b/php/utils.php @@ -272,7 +272,7 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { $tmpfile = wp_tempnam( $title ); if ( !$tmpfile ) - die( 'Error creating temporary file.' ); + \WP_CLI::error( 'Error creating temporary file.' ); file_put_contents( $tmpfile, $input ); From 270f75222e4b00c95628cfcaad7a1daf29ea1bbf Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 14 Feb 2013 15:34:22 -0800 Subject: [PATCH 1214/5359] Whitespace cleanup Use spaces for inner-line spacing --- php/utils.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 26be917ca..30d09dc3a 100644 --- a/php/utils.php +++ b/php/utils.php @@ -263,9 +263,9 @@ function output_csv( $rows, $headers = array() ) { /** * Launch system's $EDITOR to edit text * - * @param str $content Text to edit (eg post content) - * @return str|bool Edited text, if file is saved from editor - * False, if no change to file + * @param str $content Text to edit (eg post content) + * @return str|bool Edited text, if file is saved from editor + * False, if no change to file */ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { From a57f4496a8e83d45d521cdbc6fd98c3fa2024758 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Feb 2013 02:00:54 +0200 Subject: [PATCH 1215/5359] add man page for wp post edit. see #302 --- man-src/post-edit.txt | 9 +++++++++ man/post-create.1 | 2 +- man/post-edit.1 | 27 +++++++++++++++++++++++++++ php/commands/post.php | 2 +- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 man-src/post-edit.txt create mode 100644 man/post-edit.1 diff --git a/man-src/post-edit.txt b/man-src/post-edit.txt new file mode 100644 index 000000000..6e3607984 --- /dev/null +++ b/man-src/post-edit.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `<id>`: + + The ID of the post to edit. + +## EXAMPLES + + wp post edit 123 diff --git a/man/post-create.1 b/man/post-create.1 index 7aa1f5025..88d81eae3 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -7,7 +7,7 @@ \fBwp\-post\-create\fR \- Create a post\. . .SH "SYNOPSIS" -wp post create \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] +wp post create \-\-\fIfield\fR=\fIvalue\fR [\-\-edit] [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/post-edit.1 b/man/post-edit.1 new file mode 100644 index 000000000..9ce962902 --- /dev/null +++ b/man/post-edit.1 @@ -0,0 +1,27 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-EDIT" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-edit\fR \- Launch system editor to edit post content\. +. +.SH "SYNOPSIS" +wp post edit \fIid\fR +. +.SH "OPTIONS" +. +.TP +\fB<id>\fR: +. +.IP +The ID of the post to edit\. +. +.SH "EXAMPLES" +. +.nf + +wp post edit 123 +. +.fi + diff --git a/php/commands/post.php b/php/commands/post.php index bba7dfca3..625f3306c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -48,7 +48,7 @@ protected function _update( $params ) { } /** - * Launch system editor to edit post content + * Launch system editor to edit post content. * * @synopsis <id> */ From c47fafe50b83d555f1cb257b2bc91393b2642d37 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 14 Feb 2013 16:18:59 -0800 Subject: [PATCH 1216/5359] Allow `wp post create` to read from file or STDIN If a filename is passed as the first argument to `wp post create`, that file will be read for the post's content. If the first argument is '-', then post content will be read from STDIN. If an unreadable filename is given, `wp post create` exits with an error. --- php/commands/post.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 625f3306c..fe7950729 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -12,9 +12,17 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { /** * Create a post. * - * @synopsis --<field>=<value> [--edit] [--porcelain] + * @synopsis [<file>] --<field>=<value> [--porcelain] */ - public function create( $_, $assoc_args ) { + public function create( $args, $assoc_args ) { + if ( ! empty( $args[0] ) ) { + $readfile = ( $args[0] === '-' ) ? 'php://stdin' : $args[0]; + + if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) + \WP_CLI::error( "Unable to read content from $readfile." ); + + $assoc_args['post_content'] = file_get_contents( $readfile ); + } if ( isset( $assoc_args['edit'] ) ) { $input = ( isset( $assoc_args['post_content'] ) ) ? @@ -26,7 +34,6 @@ public function create( $_, $assoc_args ) { $assoc_args['post_content'] = $input; } - parent::create( $assoc_args ); } From 99016736ce9e97d7eed6ae3e69be07d20cb1806e Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 15 Feb 2013 10:29:04 -0800 Subject: [PATCH 1217/5359] Update man page for `wp post create` Still can't get synopsis to render correctly though. After adding optional positional argument to synopsis, all calls generate an 'unknown parameter' warning. --- man-src/post-create.txt | 21 +++++++++++++++++++-- man/post-create.1 | 28 +++++++++++++++++++++++----- php/commands/post.php | 2 +- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/man-src/post-create.txt b/man-src/post-create.txt index 75c4de21f..0a2bb1e06 100644 --- a/man-src/post-create.txt +++ b/man-src/post-create.txt @@ -1,14 +1,31 @@ ## OPTIONS +* `<filename>`: + + Read post content from <filename>. If this value is present, the + `--post_content` argument will be ignored. + + Passing `-` as the filename will cause post content to + be read from STDIN. + * `--<field>`=<value>: Field values for the new post. See wp_insert_post(). +* `--edit`: + + Immediately open system's editor to write or edit post content. + + (If content is read from a file, from STDIN, or from the `--post_content` + argument, that text will be loaded into the editor; otherwise, an empty + file will be opened.) + * `--porcelain`: Output just the new post id. ## EXAMPLES - wp post create --post_type=page --post_status=publish --post_title='A new -page' + wp post create --post_type=page --post_status=publish --post_title='A new page' + + wp post create file.txt --post_type=post --post_title='Post from file' diff --git a/man/post-create.1 b/man/post-create.1 index 88d81eae3..12e7be408 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -7,17 +7,35 @@ \fBwp\-post\-create\fR \- Create a post\. . .SH "SYNOPSIS" -wp post create \-\-\fIfield\fR=\fIvalue\fR [\-\-edit] [\-\-porcelain] +wp post create [\fIfilename\fR] \-\-\fIfield\fR=\fIvalue\fR [\-\-edit] [\-\-porcelain] . .SH "OPTIONS" . .TP +\fB<filename>\fR: +. +.IP +Read post content from \fIfilename\fR\. If this value is present, the \fB\-\-post_content\fR argument will be ignored\. +. +.IP +Passing \fB\-\fR as the filename will cause post content to be read from STDIN\. +. +.TP \fB\-\-<field>\fR=\fIvalue\fR: . .IP Field values for the new post\. See wp_insert_post()\. . .TP +\fB\-\-edit\fR: +. +.IP +Immediately open system\'s editor to write or edit post content\. +. +.IP +(If content is read from a file, from STDIN, or from the \fB\-\-post_content\fR argument, that text will be loaded into the editor; otherwise, an empty file will be opened\.) +. +.TP \fB\-\-porcelain\fR: . .IP @@ -27,9 +45,9 @@ Output just the new post id\. . .nf -wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A new +wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A new page\' + +wp post create file\.txt \-\-post_type=post \-\-post_title=\'Post from file\' . .fi -. -.P -page\' + diff --git a/php/commands/post.php b/php/commands/post.php index fe7950729..7be856bcb 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -12,7 +12,7 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { /** * Create a post. * - * @synopsis [<file>] --<field>=<value> [--porcelain] + * @synopsis [<filename>] --<field>=<value> [--edit] [--porcelain] */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { From d11071ab41b8dd72e1579fbe0cf5c9c780b02561 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 14 Feb 2013 17:28:08 -0800 Subject: [PATCH 1218/5359] Add filename completion for `wp post create` command Uses bash default filename completion for `wp post create` --- utils/wp-completion.bash | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) mode change 100644 => 100755 utils/wp-completion.bash diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash old mode 100644 new mode 100755 index 2e7e42025..f3822d350 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -12,6 +12,10 @@ _wp() { opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2- | tr '\n' ' ') fi - COMPREPLY=( $(compgen -W "$opts" -- $cur) ) + if [[ 'create' = $prev ]]; then + COMPREPLY=( $(compgen -f "$cur") ) + else + COMPREPLY=( $(compgen -W "$opts" -- $cur) ) + fi } complete -F _wp wp From 4958e7494a5c8ee5fac465ab2441b233ef0387b9 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 15 Feb 2013 12:59:13 -0800 Subject: [PATCH 1219/5359] Don't check if php://stdin is_file It'll let you down every time. --- php/commands/post.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 7be856bcb..9073c4ed5 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -16,10 +16,13 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { - $readfile = ( $args[0] === '-' ) ? 'php://stdin' : $args[0]; - if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) - \WP_CLI::error( "Unable to read content from $readfile." ); + if ( $args[0] !== '-' ) { + $readfile = $args[0]; + if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) + \WP_CLI::error( "Unable to read content from $readfile." ); + } else + $readfile = 'php://stdin'; $assoc_args['post_content'] = file_get_contents( $readfile ); } From 4a9c02f0847842d6379b7253523b889d8a9ff2ec Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 16 Feb 2013 22:55:48 +0200 Subject: [PATCH 1220/5359] move db commands to Command_Runner --- tests/abstract-spec.php | 33 +++++---------------------------- tests/command-runner.php | 29 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php index 08a1e27ad..2183b4083 100644 --- a/tests/abstract-spec.php +++ b/tests/abstract-spec.php @@ -2,29 +2,6 @@ abstract class WP_CLI_Spec extends PHPUnit_Extensions_Story_TestCase { - protected static $db_settings = array( - 'dbname' => 'wp_cli_test', - 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1' - ); - - private static function run_sql( $sql ) { - $dbuser = self::$db_settings['dbuser']; - $dbpass = self::$db_settings['dbpass']; - - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); - } - - protected function tearDown() { - $dbname = self::$db_settings['dbname']; - $this->run_sql( "DROP DATABASE IF EXISTS $dbname" ); - } - - private function create_db() { - $dbname = self::$db_settings['dbname']; - $this->run_sql( "CREATE DATABASE $dbname" ); - } - public function runGiven( &$world, $action, $arguments ) { switch ( $action ) { case 'empty dir': { @@ -33,7 +10,7 @@ public function runGiven( &$world, $action, $arguments ) { break; case 'database': { - $this->create_db(); + $world['runner']->create_db(); } break; @@ -43,15 +20,15 @@ public function runGiven( &$world, $action, $arguments ) { break; case 'wp config': { - $world['runner']->create_config( self::$db_settings ); + $world['runner']->create_config(); } break; case 'wp install': { - $this->create_db(); $world['runner'] = new WP_CLI_Command_Runner; + $world['runner']->create_db(); $world['runner']->download_wordpress_files(); - $world['runner']->create_config( self::$db_settings ); + $world['runner']->create_config(); $world['runner']->run_install(); } break; @@ -79,7 +56,7 @@ public function runWhen( &$world, $action, $arguments ) { break; case 'core config': { - $world['result'] = $world['runner']->create_config( self::$db_settings ); + $world['result'] = $world['runner']->create_config(); } break; diff --git a/tests/command-runner.php b/tests/command-runner.php index d35e4d1a6..98d695571 100644 --- a/tests/command-runner.php +++ b/tests/command-runner.php @@ -2,11 +2,36 @@ class WP_CLI_Command_Runner { + protected static $db_settings = array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1' + ); + private $install_dir; public function __construct() { $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); mkdir( $this->install_dir ); + + $this->drop_db(); + } + + public function create_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "CREATE DATABASE $dbname" ); + } + + public function drop_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); + } + + private static function run_sql( $sql ) { + $dbuser = self::$db_settings['dbuser']; + $dbpass = self::$db_settings['dbpass']; + + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); } public function run( $command, $cwd = false ) { @@ -34,8 +59,8 @@ public function run( $command, $cwd = false ) { return (object) compact( 'command', 'return_code', 'stdout', 'stderr' ); } - public function create_config( $db_settings ) { - return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( $db_settings ) ); + public function create_config() { + return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( self::$db_settings ) ); } public function define_custom_wp_content_dir() { From 0b2923849bcda6ef1a7958da9b135801072c7f35 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 16 Feb 2013 23:23:23 +0200 Subject: [PATCH 1221/5359] dependencies: replace phpunit-story with behat --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dbb99f17b..2acd3fad1 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ }, "require-dev": { "phpunit/phpunit": "3.7.x", - "phpunit/phpunit-story": "1.0.x" + "behat/behat": "2.4.*@stable" }, "autoload": { "psr-0": { "WP_CLI": "php" } From 106d894effba7c2d1d3ecc6cf1f68389f636140d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 16 Feb 2013 23:44:56 +0200 Subject: [PATCH 1222/5359] convert PHPUnit Story specs to Behat features --- .../bootstrap/CommandRunner.php | 14 +- features/bootstrap/FeatureContext.php | 144 ++++++++++++++++++ features/core.feature | 84 ++++++++++ features/flags.feature | 24 +++ tests/abstract-spec.php | 106 ------------- tests/bootstrap.php | 3 - tests/spec-core.php | 95 ------------ tests/spec-flags.php | 25 --- 8 files changed, 262 insertions(+), 233 deletions(-) rename tests/command-runner.php => features/bootstrap/CommandRunner.php (91%) create mode 100644 features/bootstrap/FeatureContext.php create mode 100644 features/core.feature create mode 100644 features/flags.feature delete mode 100644 tests/abstract-spec.php delete mode 100644 tests/spec-core.php delete mode 100644 tests/spec-flags.php diff --git a/tests/command-runner.php b/features/bootstrap/CommandRunner.php similarity index 91% rename from tests/command-runner.php rename to features/bootstrap/CommandRunner.php index 98d695571..15da72f70 100644 --- a/tests/command-runner.php +++ b/features/bootstrap/CommandRunner.php @@ -11,10 +11,16 @@ class WP_CLI_Command_Runner { private $install_dir; public function __construct() { + $this->drop_db(); + } + + public function create_empty_dir() { $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); mkdir( $this->install_dir ); + } - $this->drop_db(); + public function get_path( $file ) { + return $this->install_dir . '/' . $file; } public function create_db() { @@ -48,15 +54,15 @@ public function run( $command, $cwd = false ) { 2 => array( 'pipe', 'w' ), ), $pipes ); - $stdout = stream_get_contents( $pipes[1] ); + $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); - $stderr = stream_get_contents( $pipes[2] ); + $STDERR = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); $return_code = proc_close( $process ); - return (object) compact( 'command', 'return_code', 'stdout', 'stderr' ); + return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); } public function create_config() { diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php new file mode 100644 index 000000000..dda8354d2 --- /dev/null +++ b/features/bootstrap/FeatureContext.php @@ -0,0 +1,144 @@ +<?php + +use Behat\Behat\Context\ClosuredContextInterface, + Behat\Behat\Context\TranslatedContextInterface, + Behat\Behat\Context\BehatContext, + Behat\Behat\Exception\PendingException; +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode; + +require_once 'PHPUnit/Autoload.php'; +require_once 'PHPUnit/Framework/Assert/Functions.php'; + +require_once __DIR__ . '/../../php/utils.php'; + +/** + * Features context. + */ +class FeatureContext extends BehatContext +{ + /** + * Initializes context. + * Every scenario gets it's own context object. + * + * @param array $parameters context parameters (set them up through behat.yml) + */ + public function __construct(array $parameters) + { + $this->runner = new WP_CLI_Command_Runner; + } + + /** + * @Given /^an empty directory$/ + */ + public function anEmptyDirectory() + { + $this->runner->create_empty_dir(); + } + + /** + * @Given /^WP files$/ + */ + public function wordpressFiles() + { + $this->runner->download_wordpress_files(); + } + + /** + * @Given /^wp-config\.php$/ + */ + public function wpConfigPhp() + { + $this->runner->create_config(); + } + + /** + * @Given /^a database$/ + */ + public function aDatabase() + { + $this->runner->create_db(); + } + + /** + * @Given /^WP install$/ + */ + public function wpInstall() + { + $this->runner->create_db(); + $this->runner->create_empty_dir(); + $this->runner->download_wordpress_files(); + $this->runner->create_config(); + $this->runner->run_install(); + } + + /** + * @Given /^custom wp-content directory$/ + */ + public function customWpContentDirectory() + { + $this->runner->define_custom_wp_content_dir(); + } + + /** + * @When /^I run `(.+)`$/ + */ + public function iRun( $cmd ) + { + $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); + + switch ( $cmd ) + { + case 'core install': + $this->result = $this->runner->run_install(); + break; + + case 'core config': + $this->result = $this->runner->create_config(); + break; + + default: + $this->result = $this->runner->run( $cmd ); + } + } + + /** + * @Then /^the return code should be (\d+)$/ + */ + public function theReturnCodeShouldBe( $return_code ) + { + assertEquals( $return_code, $this->result->return_code ); + } + + /** + * @Then /^(STDOUT|STDERR) should be:$/ + */ + public function outputShouldBe( $stream, PyStringNode $output ) + { + assertEquals( (string) $output, rtrim( $this->result->$stream, "\n" ) ); + } + + /** + * @Then /^(STDOUT|STDERR) should not be empty$/ + */ + public function outputShouldNotBeEmpty( $stream ) + { + assertNotEmpty( rtrim( $this->result->$stream, "\n" ) ); + } + + /** + * @Then /^the (.+) file should exist$/ + */ + public function fileShouldExist( $path ) + { + assertFileExists( $this->runner->get_path( $path ) ); + } + + /** + * @Then /^database exists$/ + */ + public function databaseExists() + { + throw new PendingException(); + } +} diff --git a/features/core.feature b/features/core.feature new file mode 100644 index 000000000..37b40a091 --- /dev/null +++ b/features/core.feature @@ -0,0 +1,84 @@ +Feature: core + In order to manage WordPress + As a UNIX user + I need to be able to install it + + Scenario: Empty dir + Given an empty directory + When I run `wp core is-installed` + Then the return code should be 1 + + Scenario: No wp-config.php + Given an empty directory + And WP files + + When I run `wp core is-installed` + Then the return code should be 1 + + When I run `wp core install` + Then STDERR should be: + """ + Error: wp-config.php not found. + Either create one manually or use `wp core config`. + """ + + When I run `wp core config` + Then the return code should be 0 + And the wp-config.php file should exist + + Scenario: Database doesn't exist + Given an empty directory + And WP files + And wp-config.php + + When I run `wp` + Then the return code should be 1 + And STDERR should be: + """ + Error: Can’t select database + """ + + When I run `wp db create` + Then the return code should be 0 + + Scenario: Database tables not installed + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core is-installed` + Then the return code should be 1 + + When I run `wp` + Then the return code should be 1 + And STDERR should be: + """ + Error: The site you have requested is not installed. + Run `wp core install`. + """ + + When I run `wp core install` + Then the return code should be 0 + + When I run `wp post list --ids` + Then STDOUT should be: + """ + 1 + """ + + Scenario: Full install + Given WP install + + When I run `wp core is-installed` + Then the return code should be 0 + + Scenario: Custom wp-content directory + Given WP install + And custom wp-content directory + + When I run `wp theme status twentytwelve` + Then the return code should be 0 + + When I run `wp plugin status hello` + Then the return code should be 0 diff --git a/features/flags.feature b/features/flags.feature new file mode 100644 index 000000000..f5643f9ee --- /dev/null +++ b/features/flags.feature @@ -0,0 +1,24 @@ +Feature: flags + In order to manage WordPress + As a UNIX user + I need to be able to use various flags + + Scenario: Quiet run + Given WP install + + When I run `wp` + Then the return code should be 0 + And STDOUT should not be empty + + When I run `wp --quiet` + Then the return code should be 0 + And STDOUT should be: + """ + """ + + When I run `wp non-existing-command --quiet` + Then the return code should be 1 + And STDERR should be: + """ + Error: 'non-existing-command' is not a registered wp command. See 'wp help'. + """ diff --git a/tests/abstract-spec.php b/tests/abstract-spec.php deleted file mode 100644 index 2183b4083..000000000 --- a/tests/abstract-spec.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -abstract class WP_CLI_Spec extends PHPUnit_Extensions_Story_TestCase { - - public function runGiven( &$world, $action, $arguments ) { - switch ( $action ) { - case 'empty dir': { - $world['runner'] = new WP_CLI_Command_Runner; - } - break; - - case 'database': { - $world['runner']->create_db(); - } - break; - - case 'wp files': { - $world['runner']->download_wordpress_files(); - } - break; - - case 'wp config': { - $world['runner']->create_config(); - } - break; - - case 'wp install': { - $world['runner'] = new WP_CLI_Command_Runner; - $world['runner']->create_db(); - $world['runner']->download_wordpress_files(); - $world['runner']->create_config(); - $world['runner']->run_install(); - } - break; - - case 'custom wp-content dir': { - $world['runner']->define_custom_wp_content_dir(); - } - break; - - default: { - return $this->notImplemented( $action ); - } - } - } - - public function runWhen( &$world, $action, $arguments ) { - switch ( $action ) { - case 'invoking': { - $cmd = $arguments[0]; - - switch ( $cmd ) { - case 'core install': { - $world['result'] = $world['runner']->run_install(); - } - break; - - case 'core config': { - $world['result'] = $world['runner']->create_config(); - } - break; - - default: { - $world['result'] = $world['runner']->run( $cmd ); - } - } - } - break; - - default: { - return $this->notImplemented( $action ); - } - } - } - - public function runThen( &$world, $action, $arguments ) { - switch ( $action ) { - case 'return code should be': { - $this->assertEquals( $arguments[0], $world['result']->return_code, $action ); - } - break; - - case 'stdout': { - $this->assertEquals( $arguments[0], $world['result']->stdout, $action ); - } - break; - - case 'stderr': { - $this->assertEquals( $arguments[0], $world['result']->stderr, $action ); - } - break; - - case 'should have output': { - if ( empty( $world['result']->stdout ) ) - var_dump($world['result']); - $this->assertNotEmpty( $world['result']->stdout, $action ); - } - break; - - default: { - return $this->notImplemented( $action ); - } - } - } -} - diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c24b94614..cea88d887 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,6 +3,3 @@ require_once getcwd() . '/vendor/autoload.php'; require_once getcwd() . '/php/utils.php'; -require_once __DIR__ . '/abstract-spec.php'; -require_once __DIR__ . '/command-runner.php'; - diff --git a/tests/spec-core.php b/tests/spec-core.php deleted file mode 100644 index d7dab9ed4..000000000 --- a/tests/spec-core.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php - -class CoreCommandSpec extends WP_CLI_Spec { - - /** @scenario */ - public function emptyDir() { - $this - ->given( 'empty dir' ) - - ->when( 'invoking', 'core is-installed' ) - ->then( 'return code should be', 1 ); - } - - /** @scenario */ - public function noWpConfig() { - $this - ->given( 'empty dir' ) - ->and( 'wp files' ) - - ->when( 'invoking', 'core is-installed' ) - ->then( 'return code should be', 1 ) - - ->when( 'invoking', 'core install' ) - ->then( 'stderr', - "Error: wp-config.php not found.\n" . - "Either create one manually or use `wp core config`.\n" - ) - - ->when( 'invoking', 'core config' ) - ->then( 'return code should be', 0 ); - } - - /** @scenario */ - public function dbDoesntExist() { - $this - ->given( 'empty dir' ) - ->and( 'wp files' ) - ->and( 'wp config' ) - - ->when( 'invoking', '' ) - ->then( 'return code should be', 1 ) - ->and( 'stderr', "Error: Can’t select database\n" ) - ->and( 'stdout', '' ) - - ->when( 'invoking', 'db create' ) - ->then( 'return code should be', 0 ); - } - - /** @scenario */ - public function dbTablesNotInstalled() { - $this - ->given( 'empty dir' ) - ->and( 'wp files' ) - ->and( 'wp config' ) - ->and( 'database' ) - - ->when( 'invoking', 'core is-installed' ) - ->then( 'return code should be', 1 ) - - ->when( 'invoking', '' ) - ->then( 'stderr', - "Error: The site you have requested is not installed.\n" . - "Run `wp core install`.\n" - ) - - ->when( 'invoking', 'core install' ) - ->then( 'return code should be', 0 ) - - ->when( 'invoking', 'post list --ids' ) - ->then( 'stdout', "1" ); - } - - /** @scenario */ - public function fullInstall() { - $this - ->given( 'wp install' ) - - ->when( 'invoking', 'core is-installed' ) - ->then( 'return code should be', 0 ); - } - - /** @scenario */ - public function customWpContentDir() { - $this - ->given( 'wp install' ) - ->and( 'custom wp-content dir' ) - - ->when( 'invoking', 'theme status twentytwelve' ) - ->then( 'return code should be', 0 ) - - ->when( 'invoking', 'plugin status hello' ) - ->then( 'return code should be', 0 ); - } -} - diff --git a/tests/spec-flags.php b/tests/spec-flags.php deleted file mode 100644 index c720fda61..000000000 --- a/tests/spec-flags.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -class FlagsSpec extends WP_CLI_Spec { - - /** @scenario */ - public function quietRun() { - $this - ->given( 'wp install' ) - - ->when( 'invoking', '' ) - ->then( 'return code should be', 0 ) - ->and( 'should have output' ) - - ->when( 'invoking', '--quiet' ) - ->then( 'return code should be', 0 ) - ->and( 'stdout', '' ) - - ->when( 'invoking', 'non-existing-command --quiet' ) - ->then( 'return code should be', 1 ) - ->and( 'stderr', - "Error: 'non-existing-command' is not a registered wp command. See 'wp help'.\n" - ); - } -} - From 9f2126c05ddd88441411780322bed0894a746f0d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 00:58:19 +0200 Subject: [PATCH 1223/5359] update readme --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2f9ec0ff2..a607afe72 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,12 @@ If you want to receive an email for every single commit, you can subscribe to th Running tests ------------- -The tests use PHPUnit, which can be installed using [composer](http://getcomposer.org/). -Once you've got composer installed, run: +There are two types of tests: + +* unit tests, implemented using [PHPUnit](http://phpunit.de/) +* functional tests, implemented using [Behat](http://behat.org) + +All the test dependencies can be installed using [composer](http://getcomposer.org/): composer.phar install --dev @@ -39,11 +43,10 @@ Running the following as root in MySQL should do the trick: GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; -Finally, to run the tests: +Finally, to run the unit tests: vendor/bin/phpunit -Most tests install WordPress from scratch. Since this is pretty slow, you can -use arguments to `phpunit` to only run the test that you're interested in: +And to run the functional tests: - vendor/bin/phpunit --filter test_function_you_want_to_run + vendor/bin/behat From 4c5b7e9d9569fd9f9bb4888c92136c486df23f2e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 01:38:45 +0200 Subject: [PATCH 1224/5359] add function test for wp user create --- features/bootstrap/CommandRunner.php | 15 ++++++++++++ features/bootstrap/FeatureContext.php | 33 ++++++++++++++++----------- features/user.feature | 11 +++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 features/user.feature diff --git a/features/bootstrap/CommandRunner.php b/features/bootstrap/CommandRunner.php index 15da72f70..b81d5e54a 100644 --- a/features/bootstrap/CommandRunner.php +++ b/features/bootstrap/CommandRunner.php @@ -41,6 +41,21 @@ private static function run_sql( $sql ) { } public function run( $command, $cwd = false ) { + switch ( $command ) { + case 'core install': + return $this->run_install(); + break; + + case 'core config': + return $this->create_config(); + break; + + default: + return $this->_run( $command, $cwd ); + } + } + + private function _run( $command, $cwd ) { if ( !$cwd ) $cwd = $this->install_dir; diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index dda8354d2..4a077a2af 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -87,19 +87,18 @@ public function iRun( $cmd ) { $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); - switch ( $cmd ) - { - case 'core install': - $this->result = $this->runner->run_install(); - break; - - case 'core config': - $this->result = $this->runner->create_config(); - break; - - default: - $this->result = $this->runner->run( $cmd ); - } + $this->result = $this->runner->run( $cmd ); + } + + /** + * @When /^I run the previous command again$/ + */ + public function iRunThePreviousCommandAgain() + { + if ( !isset( $this->result ) ) + throw new \Exception( 'No previous command.' ); + + $this->result = $this->runner->run( $this->result->command ); } /** @@ -118,6 +117,14 @@ public function outputShouldBe( $stream, PyStringNode $output ) assertEquals( (string) $output, rtrim( $this->result->$stream, "\n" ) ); } + /** + * @Then /^(STDOUT|STDERR) should match \'([^\']+)\'$/ + */ + public function outputShouldMatch( $stream, $format ) + { + assertStringMatchesFormat( $format, $this->result->$stream ); + } + /** * @Then /^(STDOUT|STDERR) should not be empty$/ */ diff --git a/features/user.feature b/features/user.feature new file mode 100644 index 000000000..2523ef557 --- /dev/null +++ b/features/user.feature @@ -0,0 +1,11 @@ +Feature: Manage WordPress users + + Scenario: Creating/deleting users + Given WP install + + When I run `wp user create testuser testuser@example.com --porcelain` + Then the return code should be 0 + And STDOUT should match '%d' + + When I run the previous command again + Then the return code should be 1 From 683fdf77382d706ae40385b0054219e119325d60 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 01:58:49 +0200 Subject: [PATCH 1225/5359] test deleting the previously created user --- features/bootstrap/FeatureContext.php | 7 +++++++ features/user.feature | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4a077a2af..0fde4e565 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -85,6 +85,13 @@ public function customWpContentDirectory() */ public function iRun( $cmd ) { + if ( false !== strpos( $cmd, '<STDOUT>' ) ) { + if ( !isset( $this->result ) ) + throw new \Exception( 'No previous command.' ); + + $cmd = str_replace( '<STDOUT>', trim( $this->result->STDOUT ), $cmd ); + } + $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); $this->result = $this->runner->run( $cmd ); diff --git a/features/user.feature b/features/user.feature index 2523ef557..4f2530b0d 100644 --- a/features/user.feature +++ b/features/user.feature @@ -7,5 +7,6 @@ Feature: Manage WordPress users Then the return code should be 0 And STDOUT should match '%d' - When I run the previous command again - Then the return code should be 1 + When I run `wp user delete <STDOUT>` + Then the return code should be 0 + And STDOUT should not be empty From 5448727c231d81b82258954364f7a9e3e8fa1b06 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 01:59:09 +0200 Subject: [PATCH 1226/5359] use WP_CLI::warning() instead of passing false to WP_CLI::error() --- php/WP_CLI/CommandWithDBObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 8b252663a..773f81d44 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -61,7 +61,7 @@ protected function success_or_failure( $r ) { \WP_CLI::success( $msg ); $status = 0; } else { - \WP_CLI::error( $msg, false ); + \WP_CLI::warning( $msg ); $status = 1; } From 5a90ea64a9d89c8eadfb1d8ccdd2c3380ef63e6d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 02:00:07 +0200 Subject: [PATCH 1227/5359] remove boilerplate feature description --- features/core.feature | 5 +---- features/flags.feature | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/features/core.feature b/features/core.feature index 37b40a091..8f65bd441 100644 --- a/features/core.feature +++ b/features/core.feature @@ -1,7 +1,4 @@ -Feature: core - In order to manage WordPress - As a UNIX user - I need to be able to install it +Feature: Manage WordPress installation Scenario: Empty dir Given an empty directory diff --git a/features/flags.feature b/features/flags.feature index f5643f9ee..b3b8484b5 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -1,7 +1,4 @@ -Feature: flags - In order to manage WordPress - As a UNIX user - I need to be able to use various flags +Feature: Global flags Scenario: Quiet run Given WP install From 2f67346e29380023635b342cba7f57ead9068e4a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 02:09:53 +0200 Subject: [PATCH 1228/5359] add test for wp user generate --- features/user.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/user.feature b/features/user.feature index 4f2530b0d..45a3dac1a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -10,3 +10,24 @@ Feature: Manage WordPress users When I run `wp user delete <STDOUT>` Then the return code should be 0 And STDOUT should not be empty + + Scenario: Generating users + Given WP install + + # Delete all users + When I run `wp user list --ids` + And I run `wp user delete <STDOUT>` + When I run `wp user list --ids` + Then the return code should be 0 + And STDOUT should be: + """ + """ + + When I run `wp user generate --count=10` + Then the return code should be 0 + + When I run `wp user list | wc -l` + Then STDOUT should be: + """ + 11 + """ From 2ac359a8cd7ded1e090ab40199ba006afcdc471b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 02:34:46 +0200 Subject: [PATCH 1229/5359] add ability to save result from previous command --- features/bootstrap/FeatureContext.php | 29 ++++++++++++++++++++------- features/user.feature | 9 +++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 0fde4e565..8f18c417f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -17,6 +17,8 @@ */ class FeatureContext extends BehatContext { + private $variables = array(); + /** * Initializes context. * Every scenario gets it's own context object. @@ -85,18 +87,23 @@ public function customWpContentDirectory() */ public function iRun( $cmd ) { - if ( false !== strpos( $cmd, '<STDOUT>' ) ) { - if ( !isset( $this->result ) ) - throw new \Exception( 'No previous command.' ); - - $cmd = str_replace( '<STDOUT>', trim( $this->result->STDOUT ), $cmd ); - } - $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); + $cmd = preg_replace_callback( '/\{(\w+)\}/', array( $this, 'replace_var' ), $cmd ); + $this->result = $this->runner->run( $cmd ); } + private function replace_var( $matches ) { + $cmd = $matches[0]; + + foreach ( array_slice( $matches, 1 ) as $key ) { + $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); + } + + return $cmd; + } + /** * @When /^I run the previous command again$/ */ @@ -108,6 +115,14 @@ public function iRunThePreviousCommandAgain() $this->result = $this->runner->run( $this->result->command ); } + /** + * @Given /^save (STDOUT|STDERR) as \{(\w+)\}$/ + */ + public function saveStreamAsVariable( $stream, $key ) + { + $this->variables[ $key ] = rtrim( $this->result->$stream, "\n" ); + } + /** * @Then /^the return code should be (\d+)$/ */ diff --git a/features/user.feature b/features/user.feature index 45a3dac1a..62ad8dbe1 100644 --- a/features/user.feature +++ b/features/user.feature @@ -6,8 +6,12 @@ Feature: Manage WordPress users When I run `wp user create testuser testuser@example.com --porcelain` Then the return code should be 0 And STDOUT should match '%d' + And save STDOUT as {USER_ID} - When I run `wp user delete <STDOUT>` + When I run the previous command again + Then the return code should be 1 + + When I run `wp user delete {USER_ID}` Then the return code should be 0 And STDOUT should not be empty @@ -16,7 +20,8 @@ Feature: Manage WordPress users # Delete all users When I run `wp user list --ids` - And I run `wp user delete <STDOUT>` + And save STDOUT as {USER_IDS} + And I run `wp user delete {USER_IDS}` When I run `wp user list --ids` Then the return code should be 0 And STDOUT should be: From 6317e87b610d49dea64b8240ce2256a8cc325f88 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 03:11:01 +0200 Subject: [PATCH 1230/5359] replace 'return code should be 0' with 'it should run without errors' --- features/bootstrap/FeatureContext.php | 9 +++++++++ features/core.feature | 12 ++++++------ features/flags.feature | 4 ++-- features/user.feature | 9 ++++----- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 8f18c417f..93f9593d9 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -131,6 +131,15 @@ public function theReturnCodeShouldBe( $return_code ) assertEquals( $return_code, $this->result->return_code ); } + /** + * @Then /^it should run without errors$/ + */ + public function itShouldRunWithoutErrors() + { + assertEquals( 0, $this->result->return_code ); + assertEmpty( $this->result->STDERR ); + } + /** * @Then /^(STDOUT|STDERR) should be:$/ */ diff --git a/features/core.feature b/features/core.feature index 8f65bd441..02ad41f6e 100644 --- a/features/core.feature +++ b/features/core.feature @@ -20,7 +20,7 @@ Feature: Manage WordPress installation """ When I run `wp core config` - Then the return code should be 0 + Then it should run without errors And the wp-config.php file should exist Scenario: Database doesn't exist @@ -36,7 +36,7 @@ Feature: Manage WordPress installation """ When I run `wp db create` - Then the return code should be 0 + Then it should run without errors Scenario: Database tables not installed Given an empty directory @@ -56,7 +56,7 @@ Feature: Manage WordPress installation """ When I run `wp core install` - Then the return code should be 0 + Then it should run without errors When I run `wp post list --ids` Then STDOUT should be: @@ -68,14 +68,14 @@ Feature: Manage WordPress installation Given WP install When I run `wp core is-installed` - Then the return code should be 0 + Then it should run without errors Scenario: Custom wp-content directory Given WP install And custom wp-content directory When I run `wp theme status twentytwelve` - Then the return code should be 0 + Then it should run without errors When I run `wp plugin status hello` - Then the return code should be 0 + Then it should run without errors diff --git a/features/flags.feature b/features/flags.feature index b3b8484b5..63362b5d1 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -4,11 +4,11 @@ Feature: Global flags Given WP install When I run `wp` - Then the return code should be 0 + Then it should run without errors And STDOUT should not be empty When I run `wp --quiet` - Then the return code should be 0 + Then it should run without errors And STDOUT should be: """ """ diff --git a/features/user.feature b/features/user.feature index 62ad8dbe1..73d42122f 100644 --- a/features/user.feature +++ b/features/user.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress users Given WP install When I run `wp user create testuser testuser@example.com --porcelain` - Then the return code should be 0 + Then it should run without errors And STDOUT should match '%d' And save STDOUT as {USER_ID} @@ -12,8 +12,7 @@ Feature: Manage WordPress users Then the return code should be 1 When I run `wp user delete {USER_ID}` - Then the return code should be 0 - And STDOUT should not be empty + Then it should run without errors Scenario: Generating users Given WP install @@ -23,13 +22,13 @@ Feature: Manage WordPress users And save STDOUT as {USER_IDS} And I run `wp user delete {USER_IDS}` When I run `wp user list --ids` - Then the return code should be 0 + Then it should run without errors And STDOUT should be: """ """ When I run `wp user generate --count=10` - Then the return code should be 0 + Then it should run without errors When I run `wp user list | wc -l` Then STDOUT should be: From 02e91fbd96eda9b8acffacbd6241c7b2e1149296 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 03:49:53 +0200 Subject: [PATCH 1231/5359] make 'should run without errors' failure more descriptive --- features/bootstrap/FeatureContext.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 93f9593d9..daaa5ab3f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -136,8 +136,11 @@ public function theReturnCodeShouldBe( $return_code ) */ public function itShouldRunWithoutErrors() { - assertEquals( 0, $this->result->return_code ); - assertEmpty( $this->result->STDERR ); + if ( !empty( $this->result->STDERR ) ) + throw new \Exception( $this->result->STDERR ); + + if ( 0 != $this->result->return_code ) + throw new \Exception( "Return code was $this->result->return_code" ); } /** From 417e1379ba53ee13a0a4380e0ef40c40bda3f7cc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 03:58:18 +0200 Subject: [PATCH 1232/5359] add missing $obj_type property to User_Command --- php/commands/user.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index d3f21b449..f867204e1 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -7,6 +7,8 @@ */ class User_Command extends \WP_CLI\CommandWithDBObject { + protected $obj_type = 'user'; + /** * List users. * From 07b1dba826e1259a5c7be5327969039c27877f4d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 04:08:24 +0200 Subject: [PATCH 1233/5359] disable unkown assoc warnings when a generic assoc specifier is present in the synopsis --- php/WP_CLI/SynopsisParser.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 7512ce112..e96d2d05d 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -69,6 +69,13 @@ private function check_assoc( $assoc_args, $callback ) { } private function check_unknown_assoc( $assoc_args ) { + $generic = $this->query_params( array( + 'type' => 'generic', + ) ); + + if ( count( $generic ) ) + return; + $known_assoc = array(); foreach ( $this->params as $param ) { From b3683376126a24a7bde0e354cf1bdcfba79dbc50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 04:14:02 +0200 Subject: [PATCH 1234/5359] throw stream output instead of using assertEquals() --- features/bootstrap/FeatureContext.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index daaa5ab3f..87661bfa3 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -148,7 +148,11 @@ public function itShouldRunWithoutErrors() */ public function outputShouldBe( $stream, PyStringNode $output ) { - assertEquals( (string) $output, rtrim( $this->result->$stream, "\n" ) ); + $result = rtrim( $this->result->$stream, "\n" ); + + if ( (string) $output != $result ) { + throw new \Exception( $this->result->$stream ); + } } /** From ed5860748ca67973779a8a6a879eb16b325f03ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 04:17:58 +0200 Subject: [PATCH 1235/5359] test wp user update --- features/bootstrap/FeatureContext.php | 32 +++++++++++++++++---------- features/user.feature | 9 +++++++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 87661bfa3..4d4e85b0a 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -25,11 +25,27 @@ class FeatureContext extends BehatContext * * @param array $parameters context parameters (set them up through behat.yml) */ - public function __construct(array $parameters) + public function __construct( array $parameters ) { $this->runner = new WP_CLI_Command_Runner; } + private function replace_variables( &$str ) + { + $str = preg_replace_callback( '/\{(\w+)\}/', array( $this, '_replace_var' ), $str ); + } + + private function _replace_var( $matches ) + { + $cmd = $matches[0]; + + foreach ( array_slice( $matches, 1 ) as $key ) { + $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); + } + + return $cmd; + } + /** * @Given /^an empty directory$/ */ @@ -89,21 +105,11 @@ public function iRun( $cmd ) { $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); - $cmd = preg_replace_callback( '/\{(\w+)\}/', array( $this, 'replace_var' ), $cmd ); + $this->replace_variables( $cmd ); $this->result = $this->runner->run( $cmd ); } - private function replace_var( $matches ) { - $cmd = $matches[0]; - - foreach ( array_slice( $matches, 1 ) as $key ) { - $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); - } - - return $cmd; - } - /** * @When /^I run the previous command again$/ */ @@ -148,6 +154,8 @@ public function itShouldRunWithoutErrors() */ public function outputShouldBe( $stream, PyStringNode $output ) { + $this->replace_variables( $output ); + $result = rtrim( $this->result->$stream, "\n" ); if ( (string) $output != $result ) { diff --git a/features/user.feature b/features/user.feature index 73d42122f..ec16aa430 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,6 +1,6 @@ Feature: Manage WordPress users - Scenario: Creating/deleting users + Scenario: Creating/updating/deleting users Given WP install When I run `wp user create testuser testuser@example.com --porcelain` @@ -11,6 +11,13 @@ Feature: Manage WordPress users When I run the previous command again Then the return code should be 1 + When I run `wp user update {USER_ID} --displayname=Foo` + Then it should run without errors + And STDOUT should be: + """ + Success: Updated user {USER_ID}. + """ + When I run `wp user delete {USER_ID}` Then it should run without errors From 846bb295eb67cbe5514c8f1353db9ed24f98bf40 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 04:46:18 +0200 Subject: [PATCH 1236/5359] add 'should be empty' step definition --- features/bootstrap/FeatureContext.php | 10 ++++++++++ features/flags.feature | 4 +--- features/user.feature | 4 +--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4d4e85b0a..7eefe89b0 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -171,6 +171,16 @@ public function outputShouldMatch( $stream, $format ) assertStringMatchesFormat( $format, $this->result->$stream ); } + /** + * @Then /^(STDOUT|STDERR) should be empty$/ + */ + public function outputShouldBeEmpty( $stream ) + { + if ( !empty( $this->result->$stream ) ) { + throw new \Exception( $this->result->$stream ); + } + } + /** * @Then /^(STDOUT|STDERR) should not be empty$/ */ diff --git a/features/flags.feature b/features/flags.feature index 63362b5d1..684b370fb 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -9,9 +9,7 @@ Feature: Global flags When I run `wp --quiet` Then it should run without errors - And STDOUT should be: - """ - """ + And STDOUT should be empty When I run `wp non-existing-command --quiet` Then the return code should be 1 diff --git a/features/user.feature b/features/user.feature index ec16aa430..0c68fd9cb 100644 --- a/features/user.feature +++ b/features/user.feature @@ -30,9 +30,7 @@ Feature: Manage WordPress users And I run `wp user delete {USER_IDS}` When I run `wp user list --ids` Then it should run without errors - And STDOUT should be: - """ - """ + And STDOUT should be empty When I run `wp user generate --count=10` Then it should run without errors From a077fee11c22ec893d05734e39ec6c9113d37683 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 04:59:50 +0200 Subject: [PATCH 1237/5359] add test for --debug flag --- features/bootstrap/FeatureContext.php | 10 ++++++++++ features/flags.feature | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 7eefe89b0..31bff785d 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -163,6 +163,16 @@ public function outputShouldBe( $stream, PyStringNode $output ) } } + /** + * @Then /^(STDOUT|STDERR) should contain:$/ + */ + public function outputShouldContain( $stream, PyStringNode $output ) + { + if ( false === strpos( $this->result->$stream, (string) $output ) ) { + throw new \Exception( $this->result->$stream ); + } + } + /** * @Then /^(STDOUT|STDERR) should match \'([^\']+)\'$/ */ diff --git a/features/flags.feature b/features/flags.feature index 684b370fb..82ec10aee 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -17,3 +17,20 @@ Feature: Global flags """ Error: 'non-existing-command' is not a registered wp command. See 'wp help'. """ + + Scenario: Debug run + Given WP install + + When I run `wp eval 'echo CONST_WITHOUT_QUOTES;'` + Then it should run without errors + And STDOUT should be: + """ + CONST_WITHOUT_QUOTES + """ + + When I run `wp --debug eval 'echo CONST_WITHOUT_QUOTES;'` + Then the return code should be 0 + And STDOUT should contain: + """ + Notice: Use of undefined constant CONST_WITHOUT_QUOTES + """ From 5e555d3185d3b34b2053e3955ce2a189e39289a3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 05:11:02 +0200 Subject: [PATCH 1238/5359] add tests for creating/updating/deleting a post --- features/post.feature | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 features/post.feature diff --git a/features/post.feature b/features/post.feature new file mode 100644 index 000000000..2ecfe9b8d --- /dev/null +++ b/features/post.feature @@ -0,0 +1,29 @@ +Feature: Manage WordPress posts + + Scenario: Creating/updating/deleting posts + Given WP install + + When I run `wp post create --post_title='Test post' --porcelain` + Then it should run without errors + And STDOUT should match '%d' + And save STDOUT as {POST_ID} + + When I run `wp post update {POST_ID} --post_title='Updated post'` + Then it should run without errors + And STDOUT should be: + """ + Success: Updated post {POST_ID}. + """ + + When I run `wp post delete {POST_ID}` + Then it should run without errors + And STDOUT should be: + """ + Success: Trashed post {POST_ID}. + """ + + When I run the previous command again + Then it should run without errors + + When I run the previous command again + Then the return code should be 1 From 056c226073868a6f85baf4bacbb743762c2d73e0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 05:59:26 +0200 Subject: [PATCH 1239/5359] define steps using closures --- features/bootstrap/FeatureContext.php | 191 ++------------------------ features/steps/basic_steps.php | 99 +++++++++++++ 2 files changed, 114 insertions(+), 176 deletions(-) create mode 100644 features/steps/basic_steps.php diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 31bff785d..7b9be635d 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -2,10 +2,7 @@ use Behat\Behat\Context\ClosuredContextInterface, Behat\Behat\Context\TranslatedContextInterface, - Behat\Behat\Context\BehatContext, - Behat\Behat\Exception\PendingException; -use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode; + Behat\Behat\Context\BehatContext; require_once 'PHPUnit/Autoload.php'; require_once 'PHPUnit/Framework/Assert/Functions.php'; @@ -15,9 +12,9 @@ /** * Features context. */ -class FeatureContext extends BehatContext +class FeatureContext extends BehatContext implements ClosuredContextInterface { - private $variables = array(); + public $variables = array(); /** * Initializes context. @@ -30,188 +27,30 @@ public function __construct( array $parameters ) $this->runner = new WP_CLI_Command_Runner; } - private function replace_variables( &$str ) + public function getStepDefinitionResources() { - $str = preg_replace_callback( '/\{(\w+)\}/', array( $this, '_replace_var' ), $str ); - } - - private function _replace_var( $matches ) - { - $cmd = $matches[0]; - - foreach ( array_slice( $matches, 1 ) as $key ) { - $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); - } - - return $cmd; - } - - /** - * @Given /^an empty directory$/ - */ - public function anEmptyDirectory() - { - $this->runner->create_empty_dir(); - } - - /** - * @Given /^WP files$/ - */ - public function wordpressFiles() - { - $this->runner->download_wordpress_files(); - } - - /** - * @Given /^wp-config\.php$/ - */ - public function wpConfigPhp() - { - $this->runner->create_config(); - } - - /** - * @Given /^a database$/ - */ - public function aDatabase() - { - $this->runner->create_db(); - } - - /** - * @Given /^WP install$/ - */ - public function wpInstall() - { - $this->runner->create_db(); - $this->runner->create_empty_dir(); - $this->runner->download_wordpress_files(); - $this->runner->create_config(); - $this->runner->run_install(); - } - - /** - * @Given /^custom wp-content directory$/ - */ - public function customWpContentDirectory() - { - $this->runner->define_custom_wp_content_dir(); - } - - /** - * @When /^I run `(.+)`$/ - */ - public function iRun( $cmd ) - { - $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); - - $this->replace_variables( $cmd ); - - $this->result = $this->runner->run( $cmd ); - } - - /** - * @When /^I run the previous command again$/ - */ - public function iRunThePreviousCommandAgain() - { - if ( !isset( $this->result ) ) - throw new \Exception( 'No previous command.' ); - - $this->result = $this->runner->run( $this->result->command ); - } - - /** - * @Given /^save (STDOUT|STDERR) as \{(\w+)\}$/ - */ - public function saveStreamAsVariable( $stream, $key ) - { - $this->variables[ $key ] = rtrim( $this->result->$stream, "\n" ); + return array( __DIR__ . '/../steps/basic_steps.php' ); } - /** - * @Then /^the return code should be (\d+)$/ - */ - public function theReturnCodeShouldBe( $return_code ) + public function getHookDefinitionResources() { - assertEquals( $return_code, $this->result->return_code ); + return array(); } - /** - * @Then /^it should run without errors$/ - */ - public function itShouldRunWithoutErrors() + public function replace_variables( &$str ) { - if ( !empty( $this->result->STDERR ) ) - throw new \Exception( $this->result->STDERR ); - - if ( 0 != $this->result->return_code ) - throw new \Exception( "Return code was $this->result->return_code" ); - } - - /** - * @Then /^(STDOUT|STDERR) should be:$/ - */ - public function outputShouldBe( $stream, PyStringNode $output ) - { - $this->replace_variables( $output ); - - $result = rtrim( $this->result->$stream, "\n" ); - - if ( (string) $output != $result ) { - throw new \Exception( $this->result->$stream ); - } - } - - /** - * @Then /^(STDOUT|STDERR) should contain:$/ - */ - public function outputShouldContain( $stream, PyStringNode $output ) - { - if ( false === strpos( $this->result->$stream, (string) $output ) ) { - throw new \Exception( $this->result->$stream ); - } + $str = preg_replace_callback( '/\{(\w+)\}/', array( $this, '_replace_var' ), $str ); } - /** - * @Then /^(STDOUT|STDERR) should match \'([^\']+)\'$/ - */ - public function outputShouldMatch( $stream, $format ) + private function _replace_var( $matches ) { - assertStringMatchesFormat( $format, $this->result->$stream ); - } + $cmd = $matches[0]; - /** - * @Then /^(STDOUT|STDERR) should be empty$/ - */ - public function outputShouldBeEmpty( $stream ) - { - if ( !empty( $this->result->$stream ) ) { - throw new \Exception( $this->result->$stream ); + foreach ( array_slice( $matches, 1 ) as $key ) { + $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); } - } - - /** - * @Then /^(STDOUT|STDERR) should not be empty$/ - */ - public function outputShouldNotBeEmpty( $stream ) - { - assertNotEmpty( rtrim( $this->result->$stream, "\n" ) ); - } - /** - * @Then /^the (.+) file should exist$/ - */ - public function fileShouldExist( $path ) - { - assertFileExists( $this->runner->get_path( $path ) ); - } - - /** - * @Then /^database exists$/ - */ - public function databaseExists() - { - throw new PendingException(); + return $cmd; } } + diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php new file mode 100644 index 000000000..cd1651ef0 --- /dev/null +++ b/features/steps/basic_steps.php @@ -0,0 +1,99 @@ +<?php + +use Behat\Behat\Exception\PendingException, + Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode; + +$steps->Given( '/^an empty directory$/', function( $world ) { + $world->runner->create_empty_dir(); +} ); + +$steps->Given( '/^WP files$/', function ( $world ) { + $world->runner->download_wordpress_files(); +} ); + +$steps->Given( '/^wp-config\.php$/', function ( $world ) { + $world->runner->create_config(); +} ); + +$steps->Given( '/^a database$/', function( $world ) { + $world->runner->create_db(); +} ); + +$steps->Given( '/^WP install$/', function( $world ) { + $world->runner->create_db(); + $world->runner->create_empty_dir(); + $world->runner->download_wordpress_files(); + $world->runner->create_config(); + $world->runner->run_install(); +} ); + +$steps->Given( '/^custom wp-content directory$/', function( $world ) { + $world->runner->define_custom_wp_content_dir(); +} ); + +$steps->When( '/^I run `(.+)`$/', function( $world, $cmd ) { + $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); + + $world->replace_variables( $cmd ); + + $world->result = $world->runner->run( $cmd ); +} ); + +$steps->When( '/^I run the previous command again$/', function( $world ) { + if ( !isset( $world->result ) ) + throw new \Exception( 'No previous command.' ); + + $world->result = $world->runner->run( $world->result->command ); +} ); + +$steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', function( $world, $stream, $key ) { + $world->variables[ $key ] = rtrim( $world->result->$stream, "\n" ); +} ); + +$steps->Then( '/^the return code should be (\d+)$/', function( $world, $return_code ) { + assertEquals( $return_code, $world->result->return_code ); +} ); + +$steps->Then( '/^it should run without errors$/', function( $world ) { + if ( !empty( $world->result->STDERR ) ) + throw new \Exception( $world->result->STDERR ); + + if ( 0 != $world->result->return_code ) + throw new \Exception( "Return code was $world->result->return_code" ); +} ); + +$steps->Then( '/^(STDOUT|STDERR) should be:$/', function( $world, $stream, PyStringNode $output ) { + $world->replace_variables( $output ); + + $result = rtrim( $world->result->$stream, "\n" ); + + if ( (string) $output != $result ) { + throw new \Exception( $world->result->$stream ); + } +} ); + +$steps->Then( '/^(STDOUT|STDERR) should contain:$/', +function( $world, $stream, PyStringNode $output ) { + if ( false === strpos( $world->result->$stream, (string) $output ) ) { + throw new \Exception( $world->result->$stream ); + } +} ); + +$steps->Then( '/^(STDOUT|STDERR) should match \'([^\']+)\'$/', function( $world, $stream, $format ) { + assertStringMatchesFormat( $format, $world->result->$stream ); +} ); + +$steps->Then( '/^(STDOUT|STDERR) should be empty$/', function( $world, $stream ) { + if ( !empty( $world->result->$stream ) ) { + throw new \Exception( $world->result->$stream ); + } +} ); + +$steps->Then( '/^(STDOUT|STDERR) should not be empty$/', function( $world, $stream ) { + assertNotEmpty( rtrim( $world->result->$stream, "\n" ) ); +} ); + +$steps->Then( '/^the (.+) file should exist$/', function( $world, $path ) { + assertFileExists( $world->runner->get_path( $path ) ); +} ); From b007bd8c7b6d49f559d176c399ff64bbcdeb7681 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 06:07:45 +0200 Subject: [PATCH 1240/5359] merge WP_CLI_Command_Runner into FeatureContext --- features/bootstrap/CommandRunner.php | 140 -------------------------- features/bootstrap/FeatureContext.php | 134 +++++++++++++++++++++++- features/steps/basic_steps.php | 26 ++--- 3 files changed, 146 insertions(+), 154 deletions(-) delete mode 100644 features/bootstrap/CommandRunner.php diff --git a/features/bootstrap/CommandRunner.php b/features/bootstrap/CommandRunner.php deleted file mode 100644 index b81d5e54a..000000000 --- a/features/bootstrap/CommandRunner.php +++ /dev/null @@ -1,140 +0,0 @@ -<?php - -class WP_CLI_Command_Runner { - - protected static $db_settings = array( - 'dbname' => 'wp_cli_test', - 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1' - ); - - private $install_dir; - - public function __construct() { - $this->drop_db(); - } - - public function create_empty_dir() { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $this->install_dir ); - } - - public function get_path( $file ) { - return $this->install_dir . '/' . $file; - } - - public function create_db() { - $dbname = self::$db_settings['dbname']; - self::run_sql( "CREATE DATABASE $dbname" ); - } - - public function drop_db() { - $dbname = self::$db_settings['dbname']; - self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); - } - - private static function run_sql( $sql ) { - $dbuser = self::$db_settings['dbuser']; - $dbpass = self::$db_settings['dbpass']; - - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); - } - - public function run( $command, $cwd = false ) { - switch ( $command ) { - case 'core install': - return $this->run_install(); - break; - - case 'core config': - return $this->create_config(); - break; - - default: - return $this->_run( $command, $cwd ); - } - } - - private function _run( $command, $cwd ) { - if ( !$cwd ) - $cwd = $this->install_dir; - - $wp_cli_path = getcwd() . "/bin/wp"; - - $sh_command = "cd $cwd; $wp_cli_path $command"; - - $process = proc_open( $sh_command, array( - 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ), $pipes ); - - $STDOUT = stream_get_contents( $pipes[1] ); - fclose( $pipes[1] ); - - $STDERR = stream_get_contents( $pipes[2] ); - fclose( $pipes[2] ); - - $return_code = proc_close( $process ); - - return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); - } - - public function create_config() { - return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( self::$db_settings ) ); - } - - public function define_custom_wp_content_dir() { - $wp_config_path = $this->install_dir . '/wp-config.php'; - - $wp_config_code = file_get_contents( $wp_config_path ); - - $this->add_line_to_wp_config( $wp_config_code, - "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); - - $this->move_files( 'wp-content', 'my-content' ); - - $this->add_line_to_wp_config( $wp_config_code, - "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); - - $this->move_files( 'my-content/plugins', 'my-plugins' ); - - file_put_contents( $wp_config_path, $wp_config_code ); - } - - private function move_files( $src, $dest ) { - rename( - $this->install_dir . '/' . $src, - $this->install_dir . '/' . $dest - ); - } - - private function add_line_to_wp_config( &$wp_config_code, $line ) { - $token = "/* That's all, stop editing!"; - - $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); - } - - public function run_install() { - $cmd = 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( - 'url' => 'http://example.com', - 'title' => 'WP CLI Tests', - 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' - ) ); - - return $this->run( $cmd ); - } - - public function download_wordpress_files() { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $this->run( "core download", $cache_dir ); - } - - exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); - } -} diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 7b9be635d..9250c312f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -14,6 +14,14 @@ */ class FeatureContext extends BehatContext implements ClosuredContextInterface { + protected static $db_settings = array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1' + ); + + private $install_dir; + public $variables = array(); /** @@ -24,7 +32,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface */ public function __construct( array $parameters ) { - $this->runner = new WP_CLI_Command_Runner; + $this->drop_db(); } public function getStepDefinitionResources() @@ -52,5 +60,129 @@ private function _replace_var( $matches ) return $cmd; } + + public function create_empty_dir() { + $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $this->install_dir ); + } + + public function get_path( $file ) { + return $this->install_dir . '/' . $file; + } + + private static function run_sql( $sql ) { + $dbuser = self::$db_settings['dbuser']; + $dbpass = self::$db_settings['dbpass']; + + exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + } + + public function create_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "CREATE DATABASE $dbname" ); + } + + public function drop_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); + } + + private function _run( $command, $cwd ) { + if ( !$cwd ) + $cwd = $this->install_dir; + + $wp_cli_path = getcwd() . "/bin/wp"; + + $sh_command = "cd $cwd; $wp_cli_path $command"; + + $process = proc_open( $sh_command, array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ), $pipes ); + + $STDOUT = stream_get_contents( $pipes[1] ); + fclose( $pipes[1] ); + + $STDERR = stream_get_contents( $pipes[2] ); + fclose( $pipes[2] ); + + $return_code = proc_close( $process ); + + return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); + } + + public function run( $command, $cwd = false ) { + switch ( $command ) { + case 'core install': + return $this->run_install(); + break; + + case 'core config': + return $this->create_config(); + break; + + default: + return $this->_run( $command, $cwd ); + } + } + + public function create_config() { + return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( self::$db_settings ) ); + } + + public function define_custom_wp_content_dir() { + $wp_config_path = $this->install_dir . '/wp-config.php'; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $this->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); + + $this->move_files( 'wp-content', 'my-content' ); + + $this->add_line_to_wp_config( $wp_config_code, + "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); + + $this->move_files( 'my-content/plugins', 'my-plugins' ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } + + private function move_files( $src, $dest ) { + rename( + $this->install_dir . '/' . $src, + $this->install_dir . '/' . $dest + ); + } + + private function add_line_to_wp_config( &$wp_config_code, $line ) { + $token = "/* That's all, stop editing!"; + + $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); + } + + public function run_install() { + $cmd = 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Tests', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ) ); + + return $this->run( $cmd ); + } + + public function download_wordpress_files() { + // We cache the results of "wp core download" to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + if ( !file_exists( $cache_dir ) ) { + mkdir( $cache_dir ); + $this->run( "core download", $cache_dir ); + } + + exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); + } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index cd1651ef0..97cb6cd75 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -5,31 +5,31 @@ Behat\Gherkin\Node\TableNode; $steps->Given( '/^an empty directory$/', function( $world ) { - $world->runner->create_empty_dir(); + $world->create_empty_dir(); } ); $steps->Given( '/^WP files$/', function ( $world ) { - $world->runner->download_wordpress_files(); + $world->download_wordpress_files(); } ); $steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->runner->create_config(); + $world->create_config(); } ); $steps->Given( '/^a database$/', function( $world ) { - $world->runner->create_db(); + $world->create_db(); } ); $steps->Given( '/^WP install$/', function( $world ) { - $world->runner->create_db(); - $world->runner->create_empty_dir(); - $world->runner->download_wordpress_files(); - $world->runner->create_config(); - $world->runner->run_install(); + $world->create_db(); + $world->create_empty_dir(); + $world->download_wordpress_files(); + $world->create_config(); + $world->run_install(); } ); $steps->Given( '/^custom wp-content directory$/', function( $world ) { - $world->runner->define_custom_wp_content_dir(); + $world->define_custom_wp_content_dir(); } ); $steps->When( '/^I run `(.+)`$/', function( $world, $cmd ) { @@ -37,14 +37,14 @@ $world->replace_variables( $cmd ); - $world->result = $world->runner->run( $cmd ); + $world->result = $world->run( $cmd ); } ); $steps->When( '/^I run the previous command again$/', function( $world ) { if ( !isset( $world->result ) ) throw new \Exception( 'No previous command.' ); - $world->result = $world->runner->run( $world->result->command ); + $world->result = $world->run( $world->result->command ); } ); $steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', function( $world, $stream, $key ) { @@ -95,5 +95,5 @@ function( $world, $stream, PyStringNode $output ) { } ); $steps->Then( '/^the (.+) file should exist$/', function( $world, $path ) { - assertFileExists( $world->runner->get_path( $path ) ); + assertFileExists( $world->get_path( $path ) ); } ); From d4913f26ed46ef4889879a08bb5ed4f4e11e30ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 06:25:46 +0200 Subject: [PATCH 1241/5359] improve indentation for step definitions --- features/steps/basic_steps.php | 169 ++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 68 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 97cb6cd75..436667ddf 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -4,96 +4,129 @@ Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; -$steps->Given( '/^an empty directory$/', function( $world ) { - $world->create_empty_dir(); -} ); - -$steps->Given( '/^WP files$/', function ( $world ) { - $world->download_wordpress_files(); -} ); +$steps->Given( '/^an empty directory$/', + function ( $world ) { + $world->create_empty_dir(); + } +); -$steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->create_config(); -} ); +$steps->Given( '/^WP files$/', + function ( $world ) { + $world->download_wordpress_files(); + } +); -$steps->Given( '/^a database$/', function( $world ) { - $world->create_db(); -} ); +$steps->Given( '/^wp-config\.php$/', + function ( $world ) { + $world->create_config(); + } +); -$steps->Given( '/^WP install$/', function( $world ) { - $world->create_db(); - $world->create_empty_dir(); - $world->download_wordpress_files(); - $world->create_config(); - $world->run_install(); -} ); +$steps->Given( '/^a database$/', + function ( $world ) { + $world->create_db(); + } +); + +$steps->Given( '/^WP install$/', + function ( $world ) { + $world->create_db(); + $world->create_empty_dir(); + $world->download_wordpress_files(); + $world->create_config(); + $world->run_install(); + } +); -$steps->Given( '/^custom wp-content directory$/', function( $world ) { - $world->define_custom_wp_content_dir(); -} ); +$steps->Given( '/^custom wp-content directory$/', + function ( $world ) { + $world->define_custom_wp_content_dir(); + } +); -$steps->When( '/^I run `(.+)`$/', function( $world, $cmd ) { - $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); +$steps->When( '/^I run `(.+)`$/', + function ( $world, $cmd ) { + $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); - $world->replace_variables( $cmd ); + $world->replace_variables( $cmd ); - $world->result = $world->run( $cmd ); -} ); + $world->result = $world->run( $cmd ); + } +); -$steps->When( '/^I run the previous command again$/', function( $world ) { - if ( !isset( $world->result ) ) - throw new \Exception( 'No previous command.' ); +$steps->When( '/^I run the previous command again$/', + function ( $world ) { + if ( !isset( $world->result ) ) + throw new \Exception( 'No previous command.' ); - $world->result = $world->run( $world->result->command ); -} ); + $world->result = $world->run( $world->result->command ); + } +); -$steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', function( $world, $stream, $key ) { - $world->variables[ $key ] = rtrim( $world->result->$stream, "\n" ); -} ); +$steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', + function ( $world, $stream, $key ) { + $world->variables[ $key ] = rtrim( $world->result->$stream, "\n" ); + } +); -$steps->Then( '/^the return code should be (\d+)$/', function( $world, $return_code ) { - assertEquals( $return_code, $world->result->return_code ); -} ); +$steps->Then( '/^the return code should be (\d+)$/', + function ( $world, $return_code ) { + assertEquals( $return_code, $world->result->return_code ); + } +); -$steps->Then( '/^it should run without errors$/', function( $world ) { - if ( !empty( $world->result->STDERR ) ) - throw new \Exception( $world->result->STDERR ); +$steps->Then( '/^it should run without errors$/', + function ( $world ) { + if ( !empty( $world->result->STDERR ) ) + throw new \Exception( $world->result->STDERR ); - if ( 0 != $world->result->return_code ) - throw new \Exception( "Return code was $world->result->return_code" ); -} ); + if ( 0 != $world->result->return_code ) + throw new \Exception( "Return code was $world->result->return_code" ); + } +); -$steps->Then( '/^(STDOUT|STDERR) should be:$/', function( $world, $stream, PyStringNode $output ) { - $world->replace_variables( $output ); +$steps->Then( '/^(STDOUT|STDERR) should be:$/', + function ( $world, $stream, PyStringNode $output ) { + $world->replace_variables( $output ); - $result = rtrim( $world->result->$stream, "\n" ); + $result = rtrim( $world->result->$stream, "\n" ); - if ( (string) $output != $result ) { - throw new \Exception( $world->result->$stream ); + if ( (string) $output != $result ) { + throw new \Exception( $world->result->$stream ); + } } -} ); +); $steps->Then( '/^(STDOUT|STDERR) should contain:$/', -function( $world, $stream, PyStringNode $output ) { - if ( false === strpos( $world->result->$stream, (string) $output ) ) { - throw new \Exception( $world->result->$stream ); + function ( $world, $stream, PyStringNode $output ) { + if ( false === strpos( $world->result->$stream, (string) $output ) ) { + throw new \Exception( $world->result->$stream ); + } } -} ); +); -$steps->Then( '/^(STDOUT|STDERR) should match \'([^\']+)\'$/', function( $world, $stream, $format ) { - assertStringMatchesFormat( $format, $world->result->$stream ); -} ); +$steps->Then( '/^(STDOUT|STDERR) should match \'([^\']+)\'$/', + function ( $world, $stream, $format ) { + assertStringMatchesFormat( $format, $world->result->$stream ); + } +); -$steps->Then( '/^(STDOUT|STDERR) should be empty$/', function( $world, $stream ) { - if ( !empty( $world->result->$stream ) ) { - throw new \Exception( $world->result->$stream ); +$steps->Then( '/^(STDOUT|STDERR) should be empty$/', + function ( $world, $stream ) { + if ( !empty( $world->result->$stream ) ) { + throw new \Exception( $world->result->$stream ); + } } -} ); +); -$steps->Then( '/^(STDOUT|STDERR) should not be empty$/', function( $world, $stream ) { - assertNotEmpty( rtrim( $world->result->$stream, "\n" ) ); -} ); +$steps->Then( '/^(STDOUT|STDERR) should not be empty$/', + function ( $world, $stream ) { + assertNotEmpty( rtrim( $world->result->$stream, "\n" ) ); + } +); -$steps->Then( '/^the (.+) file should exist$/', function( $world, $path ) { - assertFileExists( $world->get_path( $path ) ); -} ); +$steps->Then( '/^the (.+) file should exist$/', + function ( $world, $path ) { + assertFileExists( $world->get_path( $path ) ); + } +); From c87c69638e4c0d46eee48b48a9d5a6a7ae41036c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 06:36:44 +0200 Subject: [PATCH 1242/5359] add test for --user global parameter --- features/flags.feature | 24 ++++++++++++++++++++++++ features/steps/basic_steps.php | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index 82ec10aee..47c9d0014 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -34,3 +34,27 @@ Feature: Global flags """ Notice: Use of undefined constant CONST_WITHOUT_QUOTES """ + + Scenario: Setting the WP user + Given WP install + + When I run `wp eval 'echo (int) is_user_logged_in();'` + Then it should run without errors + And STDOUT should be: + """ + 0 + """ + + When I run `wp --user=admin eval 'echo wp_get_current_user()->user_login;'` + Then it should run without errors + And STDOUT should be: + """ + admin + """ + + When I run `wp --user=non-existing-user` + Then the return code should be 1 + And STDERR should be: + """ + Error: Could not get a user_id for this user: 'non-existing-user' + """ diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 436667ddf..9e19360ab 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -46,7 +46,9 @@ function ( $world ) { $steps->When( '/^I run `(.+)`$/', function ( $world, $cmd ) { - $cmd = ltrim( str_replace( 'wp', '', $cmd ) ); + if ( 0 === strpos( $cmd, 'wp' ) ) { + $cmd = ltrim( substr( $cmd, 2 ) ); + } $world->replace_variables( $cmd ); From 3bdc1cb43ddebd3bf890dc6dd8e11dd711e6354e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 07:37:23 +0200 Subject: [PATCH 1243/5359] add tests for --color/--no-color --- features/flags.feature | 15 +++++++++++++++ php/WP_CLI/Runner.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index 47c9d0014..9ef0db43f 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -58,3 +58,18 @@ Feature: Global flags """ Error: Could not get a user_id for this user: 'non-existing-user' """ + + Scenario: Enabling/disabling color + Given WP install + + When I run `wp --no-color non-existant-command` + Then STDERR should be: + """ + Error: 'non-existant-command' is not a registered wp command. See 'wp help'. + """ + + When I run `wp --color non-existant-command` + Then STDERR should contain: + """ + [31;1mError: + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 1683393fd..433507c31 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -191,7 +191,7 @@ public function before_wp_load() { if ( isset( $this->assoc_args['no-color'] ) ) { $this->config['color'] = false; unset( $this->assoc_args['no-color'] ); - } elseif ( 'auto' == $this->config['color'] ) { + } elseif ( 'auto' === $this->config['color'] ) { $this->config['color'] = ! \cli\Shell::isPiped(); } From ff0dff7224d9390e0d0deff8883d4d988b983e30 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 7 Feb 2013 03:46:14 +0200 Subject: [PATCH 1244/5359] add files for plugin unit testing --- php/commands/scaffold.php | 35 +++++++++++++++++++++++++++++------ templates/.travis.yml | 33 +++++++++++++++++++++++++++++++++ templates/bootstrap.mustache | 8 ++++++++ templates/phpunit.xml | 20 ++++++++++++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 templates/.travis.yml create mode 100644 templates/bootstrap.mustache create mode 100644 templates/phpunit.xml diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 36be7ab54..300d37ba9 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -180,11 +180,12 @@ function plugin( $args, $assoc_args ) { $data['textdomain'] = $plugin_slug; - $plugin_contents = $this->render( 'plugin.mustache', $data ); + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + $plugin_path = "$plugin_dir/$plugin_slug.php"; - $plugin_path = WP_PLUGIN_DIR . "/$plugin_slug/$plugin_slug.php"; + $this->create_file( $plugin_path, $this->render( 'plugin.mustache', $data ) ); - $this->create_file( $plugin_path, $plugin_contents ); + $this->add_testing_files( $plugin_dir, $plugin_slug ); WP_CLI::success( "Created $plugin_path" ); @@ -192,6 +193,26 @@ function plugin( $args, $assoc_args ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); } + private function add_testing_files( $plugin_dir, $plugin_slug ) { + global $wp_filesystem; + + $tests_dir = "$plugin_dir/tests"; + + $wp_filesystem->mkdir( $tests_dir ); + + $this->create_file( "$tests_dir/bootstrap.php", + $this->render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ); + + $to_copy = array( + 'phpunit.xml' => $plugin_dir, + '.travis.yml' => $plugin_dir, + ); + + foreach ( $to_copy as $file => $dir ) { + $wp_filesystem->copy( $this->get_template_path( $file ), "$dir/$file" ); + } + } + private function create_file( $filename, $contents ) { global $wp_filesystem; @@ -287,14 +308,16 @@ protected function extract_args( $assoc_args, $defaults ) { } private function render( $template, $data ) { - $scaffolds_dir = WP_CLI_ROOT . '../templates'; - - $template = file_get_contents( $scaffolds_dir . '/' . $template ); + $template = file_get_contents( $this->get_template_path( $template ) ); $m = new Mustache_Engine; return $m->render( $template, $data ); } + + private function get_template_path( $template ) { + return WP_CLI_ROOT . "../templates/$template"; + } } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); diff --git a/templates/.travis.yml b/templates/.travis.yml new file mode 100644 index 000000000..e5c59aee3 --- /dev/null +++ b/templates/.travis.yml @@ -0,0 +1,33 @@ +language: php + +php: + - 5.3 + - 5.4 + +env: + - WP_VERSION=master WP_MULTISITE=0 + - WP_VERSION=3.4.2 WP_MULTISITE=0 + - WP_VERSION=master WP_MULTISITE=1 + - WP_VERSION=3.4.2 WP_MULTISITE=1 + +before_install: + - git submodule update --init --recursive + +before_script: + - WP_CORE_DIR=/tmp/wordpress/ + - plugin_slug=$(basename $(pwd)) + - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug + - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION + - mkdir -p $WP_CORE_DIR + - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + - cd .. + - mv $plugin_slug $plugin_dir + - wget -nv -O $plugin_dir/tests/wp-tests-config.php http://unit-test.svn.wordpress.org/trunk/wp-tests-config-sample.php + - cd $plugin_dir + - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" tests/wp-tests-config.php + - sed -i "s/yourdbnamehere/wordpress_test/" tests/wp-tests-config.php + - sed -i "s/yourusernamehere/root/" tests/wp-tests-config.php + - sed -i "s/yourpasswordhere//" tests/wp-tests-config.php + - mysql -e 'CREATE DATABASE wordpress_test;' -uroot + +script: phpunit diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache new file mode 100644 index 000000000..9c9405abc --- /dev/null +++ b/templates/bootstrap.mustache @@ -0,0 +1,8 @@ +<?php + +$GLOBALS['wp_tests_options'] = array( + 'active_plugins' => array( basename( dirname( dirname( __FILE__ ) ) ) . '/{{plugin_slug}}.php' ), +); + +require dirname( __FILE__ ) . '/lib/bootstrap.php'; + diff --git a/templates/phpunit.xml b/templates/phpunit.xml new file mode 100644 index 000000000..8b8c4f085 --- /dev/null +++ b/templates/phpunit.xml @@ -0,0 +1,20 @@ +<phpunit + bootstrap="tests/bootstrap.php" + backupGlobals="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + > + <testsuites> + <testsuite> + <directory prefix="test-" suffix=".php">./tests/</directory> + </testsuite> + </testsuites> + <filter> + <whitelist> + <directory suffix=".php">./core</directory> + <directory suffix=".php">./admin</directory> + </whitelist> + </filter> +</phpunit> From 63ab03262c46e09eb793b197ab5c45ed2216541a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 7 Feb 2013 04:01:14 +0200 Subject: [PATCH 1245/5359] show plugin dir, instead of path on success message, since there's more than one generated file now --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 300d37ba9..f21135c13 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -187,7 +187,7 @@ function plugin( $args, $assoc_args ) { $this->add_testing_files( $plugin_dir, $plugin_slug ); - WP_CLI::success( "Created $plugin_path" ); + WP_CLI::success( "Created $plugin_dir" ); if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); From 82d76de77b07f36c6a0b5c4d5a0c10cecbd6b848 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Feb 2013 22:21:46 +0200 Subject: [PATCH 1246/5359] transform add_testing_files() method into a proper subcommand --- php/commands/scaffold.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f21135c13..baff9f30e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -185,17 +185,28 @@ function plugin( $args, $assoc_args ) { $this->create_file( $plugin_path, $this->render( 'plugin.mustache', $data ) ); - $this->add_testing_files( $plugin_dir, $plugin_slug ); - WP_CLI::success( "Created $plugin_dir" ); + WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); + if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); } - private function add_testing_files( $plugin_dir, $plugin_slug ) { + /** + * Generate files needed for running PHPUnit tests. + * + * @subcommand plugin-tests + * + * @synopsis <plugin> + */ + function plugin_tests( $args, $assoc_args ) { global $wp_filesystem; + $plugin_slug = $args[0]; + + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + $tests_dir = "$plugin_dir/tests"; $wp_filesystem->mkdir( $tests_dir ); @@ -211,6 +222,8 @@ private function add_testing_files( $plugin_dir, $plugin_slug ) { foreach ( $to_copy as $file => $dir ) { $wp_filesystem->copy( $this->get_template_path( $file ), "$dir/$file" ); } + + WP_CLI::success( "Created test files in $plugin_dir" ); } private function create_file( $filename, $contents ) { From c58c439382de8cfb883a5272b8d1bc04d7e7e2e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 18 Feb 2013 12:50:35 +0200 Subject: [PATCH 1247/5359] add test-sample.php file --- php/commands/scaffold.php | 1 + templates/test-sample.php | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 templates/test-sample.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index baff9f30e..75b7a2251 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -217,6 +217,7 @@ function plugin_tests( $args, $assoc_args ) { $to_copy = array( 'phpunit.xml' => $plugin_dir, '.travis.yml' => $plugin_dir, + 'test-sample.php' => $tests_dir, ); foreach ( $to_copy as $file => $dir ) { diff --git a/templates/test-sample.php b/templates/test-sample.php new file mode 100644 index 000000000..1a23460d3 --- /dev/null +++ b/templates/test-sample.php @@ -0,0 +1,10 @@ +<?php + +class SampleTest extends WP_UnitTestCase { + + function testSample() { + // replace this with some actual testing code + $this->assertTrue( true ); + } +} + From b7693e07ab9d29618b3d43890276ed1f03e86b31 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 18 Feb 2013 15:03:13 +0200 Subject: [PATCH 1248/5359] revert to using the official unit testing suite --- templates/.travis.yml | 23 +++++++++++++++-------- templates/bootstrap.mustache | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index e5c59aee3..0f2425e31 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -14,20 +14,27 @@ before_install: - git submodule update --init --recursive before_script: + # set up WP install - WP_CORE_DIR=/tmp/wordpress/ - - plugin_slug=$(basename $(pwd)) - - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION - mkdir -p $WP_CORE_DIR - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + - plugin_slug=$(basename $(pwd)) + - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug - cd .. - mv $plugin_slug $plugin_dir - - wget -nv -O $plugin_dir/tests/wp-tests-config.php http://unit-test.svn.wordpress.org/trunk/wp-tests-config-sample.php - - cd $plugin_dir - - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" tests/wp-tests-config.php - - sed -i "s/yourdbnamehere/wordpress_test/" tests/wp-tests-config.php - - sed -i "s/yourusernamehere/root/" tests/wp-tests-config.php - - sed -i "s/yourpasswordhere//" tests/wp-tests-config.php + # set up testing suite + - export WP_TESTS_DIR=/tmp/wordpress-tests/ + - svn co --ignore-externals http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR + - cd $WP_TESTS_DIR + - cp wp-tests-config-sample.php wp-tests-config.php + - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php + - sed -i "s/yourdbnamehere/wordpress_test/" wp-tests-config.php + - sed -i "s/yourusernamehere/root/" wp-tests-config.php + - sed -i "s/yourpasswordhere//" wp-tests-config.php + # set up database - mysql -e 'CREATE DATABASE wordpress_test;' -uroot + # prepare for running the tests + - cd $plugin_dir script: phpunit diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index 9c9405abc..382f74013 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -4,5 +4,5 @@ $GLOBALS['wp_tests_options'] = array( 'active_plugins' => array( basename( dirname( dirname( __FILE__ ) ) ) . '/{{plugin_slug}}.php' ), ); -require dirname( __FILE__ ) . '/lib/bootstrap.php'; +require getenv( 'WP_TESTS_DIR' ) . '/includes/bootstrap.php'; From c51eecdca8587b31249251ccbb0bc81aa7310d60 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 01:10:11 +0200 Subject: [PATCH 1249/5359] add manpage for `wp scaffold plugin-tests` --- man-src/scaffold-plugin-tests.txt | 17 ++++++++++++++++ man/scaffold-plugin-tests.1 | 33 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 man-src/scaffold-plugin-tests.txt create mode 100644 man/scaffold-plugin-tests.1 diff --git a/man-src/scaffold-plugin-tests.txt b/man-src/scaffold-plugin-tests.txt new file mode 100644 index 000000000..927c7fea4 --- /dev/null +++ b/man-src/scaffold-plugin-tests.txt @@ -0,0 +1,17 @@ +## DESCRIPTION + +These are the files that are generated: + +* `phpunit.xml` is the configuration file for PHPUnit +* `.travis.yml` is the configuration file for Travis CI +* `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite +* `tests/test-sample.php` is a sample file containing the actual tests + +## ENVIRONMENT + +The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment +variable. + +## EXAMPLE + +wp scaffold plugin-tests hello diff --git a/man/scaffold-plugin-tests.1 b/man/scaffold-plugin-tests.1 new file mode 100644 index 000000000..1e1e7cd26 --- /dev/null +++ b/man/scaffold-plugin-tests.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-PLUGIN\-TESTS" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-plugin\-tests\fR \- Generate files needed for running PHPUnit tests\. +. +.SH "SYNOPSIS" +wp scaffold plugin\-tests \fIplugin\fR +. +.SH "DESCRIPTION" +These are the files that are generated: +. +.IP "\(bu" 4 +\fBphpunit\.xml\fR is the configuration file for PHPUnit +. +.IP "\(bu" 4 +\fB\.travis\.yml\fR is the configuration file for Travis CI +. +.IP "\(bu" 4 +\fBtests/bootstrap\.php\fR is the file that makes the current plugin active when running the test suite +. +.IP "\(bu" 4 +\fBtests/test\-sample\.php\fR is a sample file containing the actual tests +. +.IP "" 0 +. +.SH "ENVIRONMENT" +The \fBtests/bootstrap\.php\fR file looks for the WP_TESTS_DIR environment variable\. +. +.SH "EXAMPLE" +wp scaffold plugin\-tests hello From f2a7bec206a9ea40c0ff4315df45cbf73c2eaa4c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 18 Feb 2013 13:52:23 +0200 Subject: [PATCH 1250/5359] add `wp core init-tests` --- php/commands/core.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 20502c90a..85c78f376 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -288,6 +288,36 @@ function update_db() { wp_upgrade(); WP_CLI::success( 'WordPress database upgraded successfully.' ); } + + /** + * Set up the test suite using the current WP instance. + * + * @subcommand init-tests + * + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] + */ + function init_tests( $args, $assoc_args ) { + $tests_dir = ABSPATH . 'unit-tests/'; + + WP_CLI::launch( 'svn co https://unit-test.svn.wordpress.org/trunk/ ' . escapeshellarg( $tests_dir ) ); + + $config_file = file_get_contents( $tests_dir . 'wp-tests-config-sample.php' ); + + $replacements = array( + "dirname( __FILE__ ) . '/wordpress/'" => "'" . ABSPATH . "'", + "yourdbnamehere" => $assoc_args['dbname'], + "yourusernamehere" => $assoc_args['dbuser'], + "yourpasswordhere" => isset( $assoc_args['dbpass'] ) ? $assoc_args['dbpass'] : '' + ); + + $config_file = str_replace( array_keys( $replacements ), array_values( $replacements ), $config_file ); + + $config_file_path = $tests_dir . 'wp-tests-config.php'; + + file_put_contents( $config_file_path, $config_file ); + + WP_CLI::success( "Created $config_file_path" ); + } } WP_CLI::add_command( 'core', 'Core_Command' ); From 013ef39184ac08476df19d2b83731aa606f68cc0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 01:45:45 +0200 Subject: [PATCH 1251/5359] add optional path parameter --- php/commands/core.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 85c78f376..4845bbf0a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -294,10 +294,13 @@ function update_db() { * * @subcommand init-tests * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] + * @synopsis [<path>] --dbname=<name> --dbuser=<user> [--dbpass=<password>] */ function init_tests( $args, $assoc_args ) { - $tests_dir = ABSPATH . 'unit-tests/'; + if ( isset( $args[0] ) ) + $tests_dir = trailingslashit( $args[0] ); + else + $tests_dir = ABSPATH . 'unit-tests/'; WP_CLI::launch( 'svn co https://unit-test.svn.wordpress.org/trunk/ ' . escapeshellarg( $tests_dir ) ); From 9a59ab682f47f364b22a6489243f69195d283b43 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 01:50:26 +0200 Subject: [PATCH 1252/5359] add manpage --- man-src/core-init-tests.txt | 14 ++++++++++++++ man/core-init-tests.1 | 31 +++++++++++++++++++++++++++++++ php/commands/core.php | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 man-src/core-init-tests.txt create mode 100644 man/core-init-tests.1 diff --git a/man-src/core-init-tests.txt b/man-src/core-init-tests.txt new file mode 100644 index 000000000..e06ef024f --- /dev/null +++ b/man-src/core-init-tests.txt @@ -0,0 +1,14 @@ +## OPTIONS + +* `--dbname`=<dbname>: + + Set the database name. **WARNING**: The database will be whipped every time +you run the tests. + +* `--dbuser`=<dbuser>: + + Set the database user. + +* `--dbpass`=<dbpass>: + + Set the database user password. diff --git a/man/core-init-tests.1 b/man/core-init-tests.1 new file mode 100644 index 000000000..66ac80a3d --- /dev/null +++ b/man/core-init-tests.1 @@ -0,0 +1,31 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-INIT\-TESTS" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-init\-tests\fR \- Set up the official test suite using the current WordPress instance\. +. +.SH "SYNOPSIS" +wp core init\-tests [\fIpath\fR] \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-dbname\fR=\fIdbname\fR: +. +.IP +Set the database name\. \fBWARNING\fR: The database will be whipped every time you run the tests\. +. +.TP +\fB\-\-dbuser\fR=\fIdbuser\fR: +. +.IP +Set the database user\. +. +.TP +\fB\-\-dbpass\fR=\fIdbpass\fR: +. +.IP +Set the database user password\. + diff --git a/php/commands/core.php b/php/commands/core.php index 4845bbf0a..38bd29040 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -290,7 +290,7 @@ function update_db() { } /** - * Set up the test suite using the current WP instance. + * Set up the official test suite using the current WordPress instance. * * @subcommand init-tests * From e8a4bcda74999cc1651cbbd7ba7236dd68f46ec2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 01:58:44 +0200 Subject: [PATCH 1253/5359] document path parameter and add example --- man-src/core-init-tests.txt | 8 ++++++++ man/core-init-tests.1 | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/man-src/core-init-tests.txt b/man-src/core-init-tests.txt index e06ef024f..9f55ec5cc 100644 --- a/man-src/core-init-tests.txt +++ b/man-src/core-init-tests.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `<path>`: + + The directory in which to download the testing suite files. (Optional) + * `--dbname`=<dbname>: Set the database name. **WARNING**: The database will be whipped every time @@ -12,3 +16,7 @@ you run the tests. * `--dbpass`=<dbpass>: Set the database user password. + +## EXAMPLE + +wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test diff --git a/man/core-init-tests.1 b/man/core-init-tests.1 index 66ac80a3d..7e5c48195 100644 --- a/man/core-init-tests.1 +++ b/man/core-init-tests.1 @@ -12,6 +12,12 @@ wp core init\-tests [\fIpath\fR] \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\- .SH "OPTIONS" . .TP +\fB<path>\fR: +. +.IP +The directory in which to download the testing suite files\. (Optional) +. +.TP \fB\-\-dbname\fR=\fIdbname\fR: . .IP @@ -28,4 +34,6 @@ Set the database user\. . .IP Set the database user password\. - +. +.SH "EXAMPLE" +wp core init\-tests ~/svn/wp\-tests \-\-dbname=wp_test \-\-dbuser=wp_test From 076ffbae41aca91e34cf3623ad3144726bbf20cf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 02:49:55 +0200 Subject: [PATCH 1254/5359] bump version to 0.9.0-alpha2 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 9c28fbe35..7e040cbec 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.0-alpha' ); +define( 'WP_CLI_VERSION', '0.9.0-alpha2' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 6e0c833c9eb6dbf3584f3e4f558a0ad80786c7c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Feb 2013 22:43:39 +0200 Subject: [PATCH 1255/5359] avoid using the -l option for man, which doesn't exist on OSX fixes #311 --- php/commands/help.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 7b3490abc..a875f7a28 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -40,22 +40,14 @@ private static function maybe_load_man_page( $args ) { } private static function show_manpage( $path ) { - // to make compatible with Phar archives, need to write to a temporary file - $fd = fopen( 'php://temp', 'rw' ); - fwrite( $fd, file_get_contents( $path ) ); - fseek( $fd, 0 ); + // man can't read phar://, so need to copy to a temporary file + $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); - $descriptorspec = array( - 0 => $fd, - 1 => STDOUT, - 2 => STDERR - ); + copy( $path, $tmp_path ); - $cmd = 'man -l -'; + WP_CLI::launch( "man $tmp_path" ); - $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); - - exit( $r ); + unlink( $tmp_path ); } } From ebada77fca3583308fbe8a01999708f73e5914d5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Feb 2013 08:43:01 +0200 Subject: [PATCH 1256/5359] remove P2P specific <filter> from phpunit.xml see #270 --- templates/phpunit.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/templates/phpunit.xml b/templates/phpunit.xml index 8b8c4f085..44f0fdb69 100644 --- a/templates/phpunit.xml +++ b/templates/phpunit.xml @@ -11,10 +11,4 @@ <directory prefix="test-" suffix=".php">./tests/</directory> </testsuite> </testsuites> - <filter> - <whitelist> - <directory suffix=".php">./core</directory> - <directory suffix=".php">./admin</directory> - </whitelist> - </filter> </phpunit> From 245fa1f5f6c2335a1c91bb7782f7b4d4d303ae3c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Feb 2013 09:44:20 +0200 Subject: [PATCH 1257/5359] add utils/update-phar --- utils/update-phar | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 utils/update-phar diff --git a/utils/update-phar b/utils/update-phar new file mode 100755 index 000000000..8105be91d --- /dev/null +++ b/utils/update-phar @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -ex + +current_rev=$(git rev-parse HEAD) +current_rev=${current_rev:0:10} + +php -dphar.readonly=0 ./utils/make-phar.php ../wp-cli-packages/phar/wp-cli.phar --quiet + +cd ../wp-cli-packages + +new_commit_subj="update wp-cli.phar to $current_rev" + +current_commit_subj=$(git show -s --pretty=format:%s HEAD) + +if [ "$new_commit_subj" = "$current_commit_subj" ]; then + echo "already at latest revision" + exit 1 +fi + +git add phar/wp-cli.phar + +git commit -m "$new_commit_subj" + +git push From 50012843429d92da36b95746c53161dcadcb5dd9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Feb 2013 14:12:24 +0200 Subject: [PATCH 1258/5359] quiet down svn checkout in travis script. see #270 --- templates/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 0f2425e31..89d1fe964 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -25,7 +25,7 @@ before_script: - mv $plugin_slug $plugin_dir # set up testing suite - export WP_TESTS_DIR=/tmp/wordpress-tests/ - - svn co --ignore-externals http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR + - svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR - cd $WP_TESTS_DIR - cp wp-tests-config-sample.php wp-tests-config.php - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php From c4e9bc870ca2e03adca6f9b0542ee82f9e3a7844 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Feb 2013 09:57:54 +0200 Subject: [PATCH 1259/5359] make shell readline script more readable, using a heredoc --- php/commands/shell.php | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 75a90151d..2cdcecbed 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -60,16 +60,21 @@ private static function prompt() { } private static function create_prompt_cmd( $prompt, $history_path ) { - $cmd = implode( '; ', array( - 'set -f', - sprintf( 'history -r %s', escapeshellarg( $history_path ) ), - 'LINE=""', - sprintf( 'read -re -p %s LINE', escapeshellarg( $prompt ) ), - '[ $? -eq 0 ] || exit', - 'history -s "$LINE"', - sprintf( 'history -w %s', escapeshellarg( $history_path ) ), - 'echo $LINE' - ) ); + $prompt = escapeshellarg( $prompt ); + $history_path = escapeshellarg( $history_path ); + + $cmd = <<<BASH +set -f +history -r $history_path +LINE="" +read -re -p $prompt LINE +[ $? -eq 0 ] || exit +history -s "\$LINE" +history -w $history_path +echo \$LINE +BASH; + + $cmd = str_replace( "\n", '; ', $cmd ); return '/bin/bash -c ' . escapeshellarg( $cmd ); } From d562b974a667adad0422970c268dbea89fdfc3e6 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Sun, 24 Feb 2013 15:05:23 +0100 Subject: [PATCH 1260/5359] Fix fatal error, because of new files, see https://core.trac.wordpress.org/changeset/23466 --- php/wp-settings-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index e58ea0d83..ac988a49d 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -107,6 +107,8 @@ require( ABSPATH . WPINC . '/author-template.php' ); require( ABSPATH . WPINC . '/post.php' ); require( ABSPATH . WPINC . '/post-template.php' ); +Utils\maybe_require( '3.5-alpha-23466', ABSPATH . WPINC . '/revision.php' ); +Utils\maybe_require( '3.5-alpha-23466', ABSPATH . WPINC . '/post-formats.php' ); require( ABSPATH . WPINC . '/post-thumbnail-template.php' ); require( ABSPATH . WPINC . '/category.php' ); require( ABSPATH . WPINC . '/category-template.php' ); From 943149031f2d4d0a07ddcaa02a49c38fd2913cc2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 18:22:49 +0200 Subject: [PATCH 1261/5359] fix version check for revision.php and post-formats.php * 3.6-alpha, not 3.5-alpha * 23451, because $wp_version wasn't updated with r23466 fixes #322. see #318 --- php/wp-settings-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index ac988a49d..dd64be7d3 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -107,8 +107,8 @@ require( ABSPATH . WPINC . '/author-template.php' ); require( ABSPATH . WPINC . '/post.php' ); require( ABSPATH . WPINC . '/post-template.php' ); -Utils\maybe_require( '3.5-alpha-23466', ABSPATH . WPINC . '/revision.php' ); -Utils\maybe_require( '3.5-alpha-23466', ABSPATH . WPINC . '/post-formats.php' ); +Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/revision.php' ); +Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/post-formats.php' ); require( ABSPATH . WPINC . '/post-thumbnail-template.php' ); require( ABSPATH . WPINC . '/category.php' ); require( ABSPATH . WPINC . '/category-template.php' ); From b21d0efeb6840d76868e307608ccbf645782166c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 18:52:28 +0200 Subject: [PATCH 1262/5359] re-order lines in .travis.yml template to make them more readable --- templates/.travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 89d1fe964..a34cedf75 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -6,9 +6,9 @@ php: env: - WP_VERSION=master WP_MULTISITE=0 - - WP_VERSION=3.4.2 WP_MULTISITE=0 - WP_VERSION=master WP_MULTISITE=1 - - WP_VERSION=3.4.2 WP_MULTISITE=1 + - WP_VERSION=3.5.1 WP_MULTISITE=0 + - WP_VERSION=3.5.1 WP_MULTISITE=1 before_install: - git submodule update --init --recursive @@ -16,8 +16,8 @@ before_install: before_script: # set up WP install - WP_CORE_DIR=/tmp/wordpress/ - - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION - mkdir -p $WP_CORE_DIR + - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - plugin_slug=$(basename $(pwd)) - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug From 65e1bbf3ab1dff99c28bb0a3fb0b0e0b52c23cb5 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 25 Feb 2013 17:52:33 +0100 Subject: [PATCH 1263/5359] Cleanup before pull request and add props to Viperbond007 --- php/commands/media.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index f612cf80f..5b11fb50e 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -6,25 +6,18 @@ * @package wp-cli */ class Media_Command extends WP_CLI_Command { + var $errors = false; + function __construct() { WP_Filesystem(); } - /** - * Import a file into the media library. - * - * @synopsis <filename> [--blog] [--zip=<zip>] - */ - function import( $args, $assoc_args = array() ) { - } - /** * Regenerate thumbnail(s) * - * @synopsis [--id=<id>] - * @todo [--file=<file>] - * props @benmay + * @synopsis [--id=<id>] + * props @benmay & @Viper007Bond */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; From 69ebc70a3ae21cff734797436258589c55e704b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 18:55:16 +0200 Subject: [PATCH 1264/5359] running the tests: fix example mysql command --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index a607afe72..8285acd30 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,7 @@ Before running the tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: - GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" - IDENTIFIED BY "password1"; + GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; Finally, to run the unit tests: From 7eb90a2a7c804416a8a9a50eba69032916fd8007 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 18:57:48 +0200 Subject: [PATCH 1265/5359] first pass at .travis.yml file --- .travis.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..c47713fe7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +language: php + +php: + - 5.3 + - 5.4 + +env: + - WP_VERSION=master WP_MULTISITE=0 + - WP_VERSION=master WP_MULTISITE=1 + - WP_VERSION=3.5.1 WP_MULTISITE=0 + - WP_VERSION=3.5.1 WP_MULTISITE=1 + - WP_VERSION=3.4.2 WP_MULTISITE=0 + - WP_VERSION=3.4.2 WP_MULTISITE=1 + +before_install: + - git submodule update --init --recursive + +before_script: + # install dependencies + - curl -sS https://getcomposer.org/installer | php + - php composer.phar install --dev + # set up WP install + - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ + - mkdir -p $WP_CORE_DIR + - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION + - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + # set up database + - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot + - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot + +script: + - vendor/bin/phpunit + - vendor/bin/behat From 6a9776f9dd442742e8d0183b227e917f21dcb1ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 19:02:48 +0200 Subject: [PATCH 1266/5359] don't run Behat tests if unit tests fail --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c47713fe7..b2bab1cbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,4 @@ before_script: - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot -script: - - vendor/bin/phpunit - - vendor/bin/behat +script: vendor/bin/phpunit && vendor/bin/behat From 2c14f9f5e18cbc43afc7efe553466b013b14b7d2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 19:13:03 +0200 Subject: [PATCH 1267/5359] mark SynopsisParser::gen_patterns() as static --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index e96d2d05d..b488c7195 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -134,7 +134,7 @@ private static function init_patterns() { self::gen_patterns( 'flag', "--$p_name", array( 'optional' ) ); } - private function gen_patterns( $type, $pattern, $flavour_types ) { + private static function gen_patterns( $type, $pattern, $flavour_types ) { static $flavours = array( 'mandatory' => ':pattern:', 'optional' => '\[:pattern:\]', From bd57b99fa70d50def2971fab2f51808378e7aa6a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 19:32:30 +0200 Subject: [PATCH 1268/5359] make wp core install check less strict, to avoid error from sendmail --- features/core.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 02ad41f6e..2c41160e4 100644 --- a/features/core.feature +++ b/features/core.feature @@ -56,7 +56,7 @@ Feature: Manage WordPress installation """ When I run `wp core install` - Then it should run without errors + Then the return code should be 0 When I run `wp post list --ids` Then STDOUT should be: From f238f48dc75e22d1443288218478fe18b5fd157a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 20:01:28 +0200 Subject: [PATCH 1269/5359] remove `wp theme status twentytwelve` check Twentytwelve is not available in WP 3.4. --- features/core.feature | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index 2c41160e4..22d59e908 100644 --- a/features/core.feature +++ b/features/core.feature @@ -74,8 +74,5 @@ Feature: Manage WordPress installation Given WP install And custom wp-content directory - When I run `wp theme status twentytwelve` - Then it should run without errors - When I run `wp plugin status hello` Then it should run without errors From b7e2111dbf7f3b7f05b57ac27273032893b5e51f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 20:05:41 +0200 Subject: [PATCH 1270/5359] 'Db doesn't exist scenarion: make check less strict, to avoid issues with encodings --- features/core.feature | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index 22d59e908..7c27c5f14 100644 --- a/features/core.feature +++ b/features/core.feature @@ -30,10 +30,7 @@ Feature: Manage WordPress installation When I run `wp` Then the return code should be 1 - And STDERR should be: - """ - Error: Can’t select database - """ + And STDERR should not be empty When I run `wp db create` Then it should run without errors From 4993db4b5642371086c7cd9d96340f732ed241c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Feb 2013 20:30:59 +0200 Subject: [PATCH 1271/5359] add Build Status image to readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8285acd30..f72337f64 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ WP-CLI ======== + +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) + wp-cli is a set of command-line tools for managing WordPress installations. Where can I get more info? From 7f905b465f0d3146784fd5756cf2e056f3709026 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 25 Feb 2013 23:42:51 +0100 Subject: [PATCH 1272/5359] Added confirmation check before regenerating all images --- php/commands/media.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 5b11fb50e..28cb8b42c 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -16,18 +16,20 @@ function __construct() { /** * Regenerate thumbnail(s) * - * @synopsis [--id=<id>] + * @synopsis [--id=<id>] [--yes] * props @benmay & @Viper007Bond */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; $vars = wp_parse_args( $assoc_args, array( - 'id' => false, + 'id' => false ) ); extract($vars, EXTR_SKIP); + WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); + $where_clause = ( $id ) ? "AND ID = $id" : ''; if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { From 222eacbc1a6dfd64abe4efa597338668238ce31e Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 25 Feb 2013 23:59:27 +0100 Subject: [PATCH 1273/5359] Skip confirmation if `id` arg is given --- php/commands/media.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 28cb8b42c..31003ba2f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -23,11 +23,16 @@ function regenerate( $args, $assoc_args = array() ) { global $wpdb; $vars = wp_parse_args( $assoc_args, array( - 'id' => false + 'id' => false ) ); extract($vars, EXTR_SKIP); + // If id is given, skip confirm because it is only one file + if( !empty( $id ) ) { + $assoc_args['yes'] = true; + } + WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); $where_clause = ( $id ) ? "AND ID = $id" : ''; From 41df238f39248414f93bdc1c47d9fe3a35052cf7 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 26 Feb 2013 01:07:36 +0100 Subject: [PATCH 1274/5359] First start better naming --- php/commands/media.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 31003ba2f..fafdf11b5 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -106,14 +106,20 @@ private function _process_regeneration( $id ) { while ( $file = readdir( $dir ) ) { if ( !( strrpos( $file, $imageName ) === false ) ) { $thumbnail = explode( $imageName, $file ); - if ( $thumbnail[ 0 ] == "" ) { - $thumbnailFormat = substr( $thumbnail[ 1 ], -4 ); - $thumbnail = substr( $thumbnail[ 1 ], 0, strlen( $thumbnail[ 1 ] ) - 4 ); - $thumbnail = explode( 'x', $thumbnail ); - if ( count( $thumbnail ) == 2 ) { - if ( is_numeric( $thumbnail[ 0 ] ) && is_numeric( $thumbnail[ 1 ] ) ) { - WP_CLI::line( "Thumbnail: {$thumbnail[0]} x {$thumbnail[1]} was deleted." ); - @unlink( $dirPath . $imageName . $thumbnail[ 0 ] . 'x' . $thumbnail[ 1 ] . $thumbnailFormat ); + $filename = $thumbnail[ 1 ]; + + if ( "" == $thumbnail[ 0 ] ) { + $thumbnailFormat = substr( $filename, -4 ); + $thumbnail = substr( $filename, 0, strlen( $filename ) - 4 ); + + $sizes = explode( 'x', $thumbnail ); + $width = $sizes[0]; + $height = $sizes[1]; + + if ( 2 == count( $sizes ) ) { + if ( is_numeric( $width ) && is_numeric( $height ) ) { + WP_CLI::line( "Thumbnail: {$width} x {$height} was deleted." ); + @unlink( $dirPath . $imageName . $width . 'x' . $thumbnail[ 1 ] . $thumbnailFormat ); } } } From f46a6a5f1eefdab8ed8fd0737c9c2387efffacd8 Mon Sep 17 00:00:00 2001 From: Tracy Rotton <tracy@taupecat.com> Date: Mon, 25 Feb 2013 21:53:46 -0500 Subject: [PATCH 1275/5359] Update php/config-spec.php Fixed the spelling of "colorize." --- php/config-spec.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/config-spec.php b/php/config-spec.php index 8879434b2..41332d9a3 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -45,7 +45,7 @@ 'runtime' => true, 'file' => '<bool>', 'default' => 'auto', - 'desc' => 'Whether to colozire the output', + 'desc' => 'Whether to colorize the output', ), 'debug' => array( From 547a3e4379df5087fcd2507fd116b71c14d34874 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Feb 2013 23:03:16 +0200 Subject: [PATCH 1276/5359] rely on --path, instead of using chdir() --- features/bootstrap/FeatureContext.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 9250c312f..006fd08e8 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -87,13 +87,16 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - private function _run( $command, $cwd ) { - if ( !$cwd ) - $cwd = $this->install_dir; - + private function _run( $command ) { $wp_cli_path = getcwd() . "/bin/wp"; - $sh_command = "cd $cwd; $wp_cli_path $command"; + if ( false === strpos( $command, '--path' ) ) { + $command .= \WP_CLI\Utils\assoc_args_to_str( array( + 'path' => $this->install_dir + ) ); + } + + $sh_command = "$wp_cli_path $command"; $process = proc_open( $sh_command, array( 0 => STDIN, @@ -112,7 +115,7 @@ private function _run( $command, $cwd ) { return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); } - public function run( $command, $cwd = false ) { + public function run( $command ) { switch ( $command ) { case 'core install': return $this->run_install(); @@ -123,7 +126,7 @@ public function run( $command, $cwd = false ) { break; default: - return $this->_run( $command, $cwd ); + return $this->_run( $command ); } } @@ -179,10 +182,12 @@ public function download_wordpress_files() { $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( !file_exists( $cache_dir ) ) { mkdir( $cache_dir ); - $this->run( "core download", $cache_dir ); + $this->run( 'core download' . \WP_CLI\Utils\assoc_args_to_str( array( + 'path' => $cache_dir + ) ) ); } - exec( "cp -r '$cache_dir/'* '$this->install_dir/'" ); + exec( sprintf( "cp -r '%s/'* '%s/'", $cache_dir, $this->install_dir ) ); } } From ef46d1129ae3e836ad56ed88b5e61c592006d6ec Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Feb 2013 23:03:34 +0200 Subject: [PATCH 1277/5359] add core download check in 'Empty dir' scenario --- features/core.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/core.feature b/features/core.feature index 7c27c5f14..ea5910fa0 100644 --- a/features/core.feature +++ b/features/core.feature @@ -5,6 +5,10 @@ Feature: Manage WordPress installation When I run `wp core is-installed` Then the return code should be 1 + When I run `wp core download --quiet` + Then it should run without errors + And the wp-settings.php file should exist + Scenario: No wp-config.php Given an empty directory And WP files From 0aa3e59d2b80d17c4aff227a03b5b90c833233d3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Feb 2013 23:06:37 +0200 Subject: [PATCH 1278/5359] use ABSPATH in `core download`, instead of '.' --- php/commands/core.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 38bd29040..21e963340 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -16,11 +16,6 @@ public function download( $args, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); - if ( isset( $assoc_args['path'] ) ) - $docroot = $assoc_args['path']; - else - $docroot = './'; - if ( isset( $assoc_args['locale'] ) ) { exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); if ($r) exit($r); @@ -37,7 +32,7 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; WP_CLI::launch( 'curl -f' . $silent . escapeshellarg( $download_url ) . ' | tar xz' ); - WP_CLI::launch( 'cp -r wordpress/* . && rm -rf wordpress' ); + WP_CLI::launch( sprintf( 'cp -r wordpress/* %s && rm -rf wordpress', escapeshellarg( ABSPATH ) ) ); WP_CLI::success( 'WordPress downloaded.' ); } From fe7683f6f535b4610315bc665734a7a9c5f3e616 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Feb 2013 23:38:53 +0200 Subject: [PATCH 1279/5359] create ABSPATH if it doesn't exist. props @erwanlr --- php/commands/core.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 21e963340..6176571e8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -16,6 +16,11 @@ public function download( $args, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); + if ( !is_dir( ABSPATH ) ) { + WP_CLI::line( sprintf( 'Creating directory %s', ABSPATH ) ); + WP_CLI::launch( 'mkdir -p ' . escapeshellarg( ABSPATH ) ); + } + if ( isset( $assoc_args['locale'] ) ) { exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); if ($r) exit($r); From f4260a522c9573163e744b622c199c614899e032 Mon Sep 17 00:00:00 2001 From: erwanlr <erwan.lr@gmail.com> Date: Tue, 26 Feb 2013 22:55:40 +0100 Subject: [PATCH 1280/5359] Fixes Runner::set_wp_root to handle absolute & relative path --- php/WP_CLI/Runner.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 433507c31..ff9ecb276 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -82,11 +82,20 @@ private static function split_special( &$assoc_args, &$config, $spec ) { } private static function set_wp_root( $config ) { - if ( !empty( $config['path'] ) ) { - define( 'ABSPATH', rtrim( $config['path'], '/' ) . '/' ); - } else { - define( 'ABSPATH', getcwd() . '/' ); + $path = getcwd(); + + if ( !empty( $config['path'] ) ) + { + if ( self::is_absolute_path( $config['path'] ) ) + $path = $config['path']; + else + $path .= $config['path']; } + define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); + } + + private static function is_absolute_path( $path ) { + return $path[0] === '/' ? true : false; } private static function set_url( $assoc_args ) { From d7d15c53bb3f5d983fcad0b8acbe0420d809a538 Mon Sep 17 00:00:00 2001 From: erwanlr <erwan.lr@gmail.com> Date: Wed, 27 Feb 2013 10:15:22 +0100 Subject: [PATCH 1281/5359] '/' missing --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ff9ecb276..621e9577e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -89,7 +89,7 @@ private static function set_wp_root( $config ) { if ( self::is_absolute_path( $config['path'] ) ) $path = $config['path']; else - $path .= $config['path']; + $path .= '/' . $config['path']; } define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); } From 2c9dae3d43b76d0e5e8a5fc5e6a02084a332897f Mon Sep 17 00:00:00 2001 From: erwanlr <erwan.lr@gmail.com> Date: Wed, 27 Feb 2013 10:22:52 +0100 Subject: [PATCH 1282/5359] Fixes #321 db create / drop / reset syntax error with some dbnames (like wordpress-3.5.1) --- php/commands/db.php | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 104516728..bed80acbf 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -13,9 +13,8 @@ class DB_Command extends WP_CLI_Command { * @synopsis [--str] */ function create( $_, $assoc_args ) { - self::run( $assoc_args, self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=%s', - DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME + self::run( $assoc_args, self::create_execute_cmd( + sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ) ); WP_CLI::success( "Database created." ); @@ -27,10 +26,7 @@ function create( $_, $assoc_args ) { * @synopsis [--yes] [--str] */ function drop( $_, $assoc_args ) { - $command = self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=%s', - DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE ' . DB_NAME - ); + $command = self::create_execute_cmd( sprintf( 'DROP DATABASE `%s`', DB_NAME ) ); if ( !isset( $assoc_args['str'] ) ) { WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); @@ -47,15 +43,9 @@ function drop( $_, $assoc_args ) { * @synopsis [--yes] [--str] */ function reset( $_, $assoc_args ) { - $drop_cmd = self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=%s', - DB_HOST, DB_USER, DB_PASSWORD, 'DROP DATABASE IF EXISTS ' . DB_NAME - ); + $drop_cmd = self::create_execute_cmd( sprintf( 'DROP DATABASE IF EXISTS `%s`', DB_NAME ) ); - $create_cmd = self::create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=%s', - DB_HOST, DB_USER, DB_PASSWORD, 'CREATE DATABASE ' . DB_NAME - ); + $create_cmd = self::create_execute_cmd( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); if ( !isset( $assoc_args['str'] ) ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); @@ -162,6 +152,13 @@ private function get_file_name( $args ) { return $args[0]; } + private static function create_execute_cmd( $execute_statement ) { + return self::create_cmd( + 'mysql --host=%s --user=%s --password=%s --execute=%s', + DB_HOST, DB_USER, DB_PASSWORD, $execute_statement + ); + } + /** * Given a formatted string and an arbitrary number of arguments, * returns the final command, with the parameters escaped @@ -185,4 +182,3 @@ private static function run( $assoc_args, $cmd ) { } WP_CLI::add_command( 'db', 'DB_Command' ); - From 8863f0052173ab01a31bd6ab2f5eb8a2dc26477b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 11:45:26 +0200 Subject: [PATCH 1283/5359] fix coding standards. see #329 --- php/WP_CLI/Runner.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 621e9577e..e4d04c266 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -84,18 +84,18 @@ private static function split_special( &$assoc_args, &$config, $spec ) { private static function set_wp_root( $config ) { $path = getcwd(); - if ( !empty( $config['path'] ) ) - { + if ( !empty( $config['path'] ) ) { if ( self::is_absolute_path( $config['path'] ) ) $path = $config['path']; else $path .= '/' . $config['path']; } + define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); } private static function is_absolute_path( $path ) { - return $path[0] === '/' ? true : false; + return $path[0] === '/'; } private static function set_url( $assoc_args ) { From fdac555f5a951f9a620e585cfa98c25d431bb4ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 12:09:39 +0200 Subject: [PATCH 1284/5359] Ignore `wp ` prefix straigth from step definition. This makes it clearer that running arbitrary commands is not supported. --- features/steps/basic_steps.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 9e19360ab..2dbbdf160 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -44,12 +44,14 @@ function ( $world ) { } ); -$steps->When( '/^I run `(.+)`$/', - function ( $world, $cmd ) { - if ( 0 === strpos( $cmd, 'wp' ) ) { - $cmd = ltrim( substr( $cmd, 2 ) ); - } +$steps->When( '/^I run `wp`$/', + function ( $world ) { + $world->result = $world->run( '' ); + } +); +$steps->When( '/^I run `wp (.+)`$/', + function ( $world, $cmd ) { $world->replace_variables( $cmd ); $world->result = $world->run( $cmd ); From 232407508086aee09b8a3033e8124d406b8dc1ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 12:15:22 +0200 Subject: [PATCH 1285/5359] Prepend `--path`, instead of appending it, so that piping works. --- features/bootstrap/FeatureContext.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 006fd08e8..57c05cda1 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -91,9 +91,9 @@ private function _run( $command ) { $wp_cli_path = getcwd() . "/bin/wp"; if ( false === strpos( $command, '--path' ) ) { - $command .= \WP_CLI\Utils\assoc_args_to_str( array( + $command = \WP_CLI\Utils\assoc_args_to_str( array( 'path' => $this->install_dir - ) ); + ) ) . ' ' . $command; } $sh_command = "$wp_cli_path $command"; From b76c44f4b05d540a0ead7ba9cd0af192a2125597 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 12:52:27 +0200 Subject: [PATCH 1286/5359] travis: add --no-interaction flag to Composer call Should at least make stalled builds fail faster. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b2bab1cbc..dfe12aa7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ before_install: before_script: # install dependencies - curl -sS https://getcomposer.org/installer | php - - php composer.phar install --dev + - php composer.phar install --dev --no-interaction # set up WP install - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ - mkdir -p $WP_CORE_DIR From 2d905eaf2d99279120476ad33f44b911f1769e87 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 13:00:35 +0200 Subject: [PATCH 1287/5359] shorten synopsis for boolean parameters --- php/WP_CLI/Dispatcher/RootCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 654d4fca5..e1db3ce16 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -54,7 +54,7 @@ private static function generate_synopsis() { continue; $synopsis = ( true === $details['runtime'] ) - ? "--$key/--no-$key" + ? "--[no-]$key" : "--$key" . $details['runtime']; $cur_len = strlen( $synopsis ); From 2a162669c958675b3163b61f609edb6a33fd32e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Feb 2013 20:39:24 +0200 Subject: [PATCH 1288/5359] use `wp core version` instead of `wp post list` to check if the install was successful. --- features/core.feature | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index ea5910fa0..fe5dbd395 100644 --- a/features/core.feature +++ b/features/core.feature @@ -59,11 +59,9 @@ Feature: Manage WordPress installation When I run `wp core install` Then the return code should be 0 - When I run `wp post list --ids` - Then STDOUT should be: - """ - 1 - """ + When I run `wp core version` + Then it should run without errors + And STDOUT should not be empty Scenario: Full install Given WP install From 5775f17c98ba825a5829a798cee9969bd927f02d Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Thu, 28 Feb 2013 10:42:31 +0100 Subject: [PATCH 1289/5359] made dbpass parameter optional for core config command --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 6176571e8..66aa42144 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -45,12 +45,12 @@ public function download( $args, $assoc_args ) { /** * Set up a wp-config.php file. * - * @synopsis --dbname=<name> --dbuser=<user> --dbpass=<password> [--dbhost=<host>] [--dbprefix=<prefix>] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] */ public function config( $args, $assoc_args ) { $_POST['dbname'] = $assoc_args['dbname']; $_POST['uname'] = $assoc_args['dbuser']; - $_POST['pwd'] = $assoc_args['dbpass']; + $_POST['pwd'] = isset( $assoc_args['dbpass'] ) ? $assoc_args['dbpass'] : ''; $_POST['dbhost'] = isset( $assoc_args['dbhost'] ) ? $assoc_args['dbhost'] : 'localhost'; $_POST['prefix'] = isset( $assoc_args['dbprefix'] ) ? $assoc_args['dbprefix'] : 'wp_'; From a0dff2f22a28b26767e43229f544106e0f972683 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Thu, 28 Feb 2013 10:44:43 +0100 Subject: [PATCH 1290/5359] regenerated the man page for core config command --- man/core-config.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/core-config.1 b/man/core-config.1 index 0e53dd338..47e893b7b 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -7,7 +7,7 @@ \fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. . .SH "SYNOPSIS" -wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR \-\-dbpass=\fIpassword\fR [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] +wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] . .SH "OPTIONS" . From 85e10be065a462d44df0a58c934675abb46bd0c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 20:34:21 +0200 Subject: [PATCH 1291/5359] delete submodules --- .gitmodules | 6 ------ php/mustache | 1 - php/php-cli-tools | 1 - 3 files changed, 8 deletions(-) delete mode 100644 .gitmodules delete mode 160000 php/mustache delete mode 160000 php/php-cli-tools diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 05f4715b9..000000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "php/php-cli-tools"] - path = php/php-cli-tools - url = git://github.com/wp-cli/php-cli-tools.git -[submodule "php/mustache"] - path = php/mustache - url = git://github.com/bobthecow/mustache.php.git diff --git a/php/mustache b/php/mustache deleted file mode 160000 index d99be3444..000000000 --- a/php/mustache +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d99be3444e5b2f0fb605941d7e692d3b5159360c diff --git a/php/php-cli-tools b/php/php-cli-tools deleted file mode 160000 index f3def25b8..000000000 --- a/php/php-cli-tools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f3def25b862bb0c5330a6347c6c04d62a99eb217 From 41cd47f4053e3fbf51c05a15ab6810d4aef1a923 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 20:38:01 +0200 Subject: [PATCH 1292/5359] add composer.lock --- .gitignore | 1 - composer.lock | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index abb9c75a1..0e7aef903 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /vendor -/composer.lock /phpunit.xml diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..c395f5b8e --- /dev/null +++ b/composer.lock @@ -0,0 +1,98 @@ +{ + "hash": "dd697246fcbfe8ce5e5654c9898ae115", + "packages": [ + { + "name": "mustache/mustache", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/mustache.php", + "reference": "v2.0.2" + }, + "dist": { + "type": "zip", + "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", + "reference": "v2.0.2", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "type": "library", + "autoload": { + "psr-0": { + "Mustache": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", + "keywords": [ + "mustache", + "templating" + ], + "time": "2012-09-12 09:13:06" + }, + { + "name": "wp-cli/php-cli-tools", + "version": "dev-master", + "source": { + "type": "git", + "url": "http://github.com/wp-cli/php-cli-tools", + "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217" + }, + "dist": { + "type": "zip", + "url": "https://github.com/wp-cli/php-cli-tools/archive/f3def25b862bb0c5330a6347c6c04d62a99eb217.zip", + "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217", + "shasum": "" + }, + "require": { + "php": ">= 5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "cli": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "James Logsdon", + "email": "jlogsdon@php.net", + "role": "Developer" + } + ], + "description": "Console utilities for PHP", + "homepage": "http://github.com/jlogsdon/php-cli-tools", + "keywords": [ + "cli", + "console" + ], + "time": "2012-12-13 22:18:34" + } + ], + "packages-dev": null, + "aliases": [ + + ], + "minimum-stability": "dev", + "stability-flags": { + "wp-cli/php-cli-tools": 20, + "behat/behat": 0 + } +} From ec82ee6abc981084ac95b691873efdbfd160b0e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 20:58:24 +0200 Subject: [PATCH 1293/5359] travis: no more submodules to initialize --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dfe12aa7a..bb6c74de7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,6 @@ env: - WP_VERSION=3.4.2 WP_MULTISITE=0 - WP_VERSION=3.4.2 WP_MULTISITE=1 -before_install: - - git submodule update --init --recursive - before_script: # install dependencies - curl -sS https://getcomposer.org/installer | php From 853323672ea45a425363cde82d0ade6e83e09177 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 21:25:07 +0200 Subject: [PATCH 1294/5359] install and use Composer in utils/dev-build --- utils/dev-build | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utils/dev-build b/utils/dev-build index b8ad05819..bffbaf168 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -1,5 +1,15 @@ #!/usr/bin/env bash +# install Composer +command -v composer > /dev/null || { + curl -sS https://getcomposer.org/installer | php + mv composer.phar /usr/local/bin/composer +} + +# install dependencies +composer install + +# add symlink to wp binary for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then ln -sf $(pwd)/bin/wp $dir/wp @@ -7,6 +17,7 @@ for dir in /usr/bin /usr/local/bin; do fi done +# install bash completion file for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do if [ -d $dir ]; then ln -sf $(pwd)/utils/wp-completion.bash $dir/wp From 1317f6b81d8464022a49aae7c96f097cb3da37fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 21:38:57 +0200 Subject: [PATCH 1295/5359] remove loading from submodules --- php/utils.php | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/php/utils.php b/php/utils.php index ba2882aa7..49834755c 100644 --- a/php/utils.php +++ b/php/utils.php @@ -23,34 +23,9 @@ function load_dependencies() { } } - if ( !$has_autoload ) { - include WP_CLI_ROOT . 'php-cli-tools/lib/cli/cli.php'; - \cli\register_autoload(); - - include WP_CLI_ROOT . 'mustache/src/Mustache/Autoloader.php'; - \Mustache_Autoloader::register(); - - register_autoload(); - } - include WP_CLI_ROOT . 'Spyc.php'; } -function register_autoload() { - spl_autoload_register( function($class) { - // Only attempt to load classes in our namespace - if ( 0 !== strpos( $class, 'WP_CLI\\' ) ) { - return; - } - - $path = WP_CLI_ROOT . str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php'; - - if ( is_file( $path ) ) { - require_once $path; - } - } ); -} - function get_config_spec() { $spec = include __DIR__ . '/config-spec.php'; From 07c32925eaba785e179fdcf5c787a8f4580b4c3f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Feb 2013 21:54:55 +0200 Subject: [PATCH 1296/5359] update make-phar.php to use vendor dir --- utils/make-phar.php | 48 +++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index b928bd108..96c66abb8 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -28,31 +28,45 @@ function add_file( $phar, $path ) { $phar->startBuffering(); -$ignored_paths = array( - '/mustache/bin/', - '/mustache/test/', - '/mustache/vendor/', - '/php-cli-tools/examples/' -); - +// php files foreach ( get_iterator( './php' ) as $path ) { - foreach ( $ignored_paths as $ignore ) { - if ( strpos( $path, $ignore ) ) - continue 2; - } - if ( !preg_match( '/\.php$/', $path ) ) continue; add_file( $phar, $path ); } -foreach ( get_iterator( './templates' ) as $path ) { - add_file( $phar, $path ); +// non-php files +$additional_dirs = array( + './templates', + './man' +); + +foreach ( $additional_dirs as $dir ) { + foreach ( get_iterator( $dir ) as $path ) { + add_file( $phar, $path ); + } } -foreach ( get_iterator( './man' ) as $path ) { - add_file( $phar, $path ); +// dependencies +$ignored_paths = array( + '/.git', +); + +$vendor_dirs = array( + './vendor/mustache', + './vendor/wp-cli', +); + +foreach ( $vendor_dirs as $vendor_dir ) { + foreach ( get_iterator( $vendor_dir ) as $path ) { + foreach ( $ignored_paths as $ignore ) { + if ( strpos( $path, $ignore ) ) + continue 2; + } + + add_file( $phar, $path ); + } } $phar->setStub( <<<EOB @@ -67,5 +81,5 @@ function add_file( $phar, $path ) { $phar->stopBuffering(); -echo "\nGenerated " . DEST_PATH . "\n"; +echo "Generated " . DEST_PATH . "\n"; From 4cbc752a12e02ed33deda4801237a5377aad1683 Mon Sep 17 00:00:00 2001 From: Gleb Kalinin <glebis@gmail.com> Date: Sat, 2 Mar 2013 00:17:57 +0400 Subject: [PATCH 1297/5359] Adds scaffolding for child theme (based on Twenty Twelve by default) Apart from creating an empty underscore theme, it would be cool to be able to create an empty child theme. I've implemented a very basic command for this. It created a theme folder and style.css which imports parent theme's styles --- php/commands/scaffold.php | 33 +++++++++++++++++++++++++++++++++ templates/child_theme.mustache | 11 +++++++++++ 2 files changed, 44 insertions(+) create mode 100644 templates/child_theme.mustache diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 75b7a2251..b63720148 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -146,6 +146,39 @@ function _s( $args, $assoc_args ) { } + /** + * Generate empty child theme (twentytwelve by default). + * + * @synopsis <slug> [--theme_name=<title>] [--parent_theme=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] + */ + function child_theme( $args, $assoc_args ) { + + $theme_slug = $args[0]; + $theme_path = WP_CONTENT_DIR . "/themes"; + + $data = wp_parse_args( $assoc_args, array( + 'theme_name' => ucfirst( $theme_slug ), + 'parent_theme' => 'twentytwelve', + 'author' => "Me", + 'author_uri' => "", + 'theme_uri' => "" + ) ); + + $data['theme_description'] = ucfirst($data['parent_theme']) . " child theme. "; + + + $theme_dir = $theme_path . "/$theme_slug"; + $theme_style_path = "$theme_dir/style.css"; + + $this->create_file( $theme_style_path, $this->render( 'child_theme.mustache', $data ) ); + + WP_CLI::success( "Created $theme_dir" ); + + + if ( isset( $assoc_args['activate'] ) ) + WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + + } private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); diff --git a/templates/child_theme.mustache b/templates/child_theme.mustache new file mode 100644 index 000000000..a6b182b82 --- /dev/null +++ b/templates/child_theme.mustache @@ -0,0 +1,11 @@ +/* +Theme Name: {{theme_name}} +Theme URI: {{theme_uri}} +Description: {{theme_description}} +Author: {{author}} +Author URI: {{author_uri}} +Template: {{parent_theme}} +Version: 0.1.0 +*/ + +@import '../{{parent_theme}}/style.css'; \ No newline at end of file From 047e890a29f69964c15e3ceb112ae434598f44b2 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 1 Mar 2013 22:07:58 +0100 Subject: [PATCH 1298/5359] Optimizing looping and unlinking of the resized images --- php/commands/media.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index fafdf11b5..0862cc8bd 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -99,27 +99,32 @@ private function _process_regeneration( $id ) { $imageName = sprintf( "%s-", $dirPath[ count( $dirPath ) - 1 ] ); unset( $dirPath[ count( $dirPath ) - 1 ] ); $dirPath = sprintf( "%s%s", implode( DIRECTORY_SEPARATOR, $dirPath ), DIRECTORY_SEPARATOR ); - + // Read and delete files $dir = opendir( $dirPath ); $files = array(); while ( $file = readdir( $dir ) ) { + if ( !( strrpos( $file, $imageName ) === false ) ) { + $thumbnail = explode( $imageName, $file ); $filename = $thumbnail[ 1 ]; + //If we got the original / full image if ( "" == $thumbnail[ 0 ] ) { - $thumbnailFormat = substr( $filename, -4 ); - $thumbnail = substr( $filename, 0, strlen( $filename ) - 4 ); + preg_match('/\.[^\.]+$/i', $file, $ext); + $thumbnailFormat = $ext[0]; + $thumbnail = basename( $file, $thumbnailFormat ); - $sizes = explode( 'x', $thumbnail ); - $width = $sizes[0]; - $height = $sizes[1]; + $sizes = explode( 'x', $thumbnail ); + // If not cropped by WP if ( 2 == count( $sizes ) ) { + $width = $sizes[0]; + $height = $sizes[1]; if ( is_numeric( $width ) && is_numeric( $height ) ) { WP_CLI::line( "Thumbnail: {$width} x {$height} was deleted." ); - @unlink( $dirPath . $imageName . $width . 'x' . $thumbnail[ 1 ] . $thumbnailFormat ); + @unlink( $dirPath . $imageName . $width . 'x' . $thumbnail . $thumbnailFormat ); } } } From db585a5fb0344bc1b27269ada86dc4294053fb71 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Mar 2013 13:21:39 +0200 Subject: [PATCH 1299/5359] show error message when vendor directory is missing see #336 --- php/utils.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/utils.php b/php/utils.php index 49834755c..efd1411cb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -23,6 +23,11 @@ function load_dependencies() { } } + if ( !$has_autoload ) { + fputs( STDERR, "Internal error: Can't find Composer autoloader.\n" ); + exit(2); + } + include WP_CLI_ROOT . 'Spyc.php'; } From c69b7a45cff56923079cd2d6610ab2dceb256037 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Mar 2013 01:04:03 +0200 Subject: [PATCH 1300/5359] leave minimum stability to stable --- composer.json | 3 +- composer.lock | 842 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 838 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 2acd3fad1..46ed15725 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,5 @@ }, "autoload": { "psr-0": { "WP_CLI": "php" } - }, - "minimum-stability": "dev" + } } diff --git a/composer.lock b/composer.lock index c395f5b8e..bdbb23f0b 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "dd697246fcbfe8ce5e5654c9898ae115", + "hash": "f2b06fd19e26795775358b054c6fb09d", "packages": [ { "name": "mustache/mustache", @@ -48,12 +48,12 @@ "version": "dev-master", "source": { "type": "git", - "url": "http://github.com/wp-cli/php-cli-tools", + "url": "https://github.com/wp-cli/php-cli-tools.git", "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217" }, "dist": { "type": "zip", - "url": "https://github.com/wp-cli/php-cli-tools/archive/f3def25b862bb0c5330a6347c6c04d62a99eb217.zip", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/f3def25b862bb0c5330a6347c6c04d62a99eb217", "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217", "shasum": "" }, @@ -86,11 +86,843 @@ "time": "2012-12-13 22:18:34" } ], - "packages-dev": null, + "packages-dev": [ + { + "name": "behat/behat", + "version": "v2.4.5", + "source": { + "type": "git", + "url": "git://github.com/Behat/Behat.git", + "reference": "v2.4.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/Behat/Behat/archive/v2.4.5.zip", + "reference": "v2.4.5", + "shasum": "" + }, + "require": { + "behat/gherkin": ">=2.2.4,<2.3-dev", + "php": ">=5.3.1", + "symfony/config": ">=2.0,<2.3-dev", + "symfony/console": ">=2.0,<2.3-dev", + "symfony/dependency-injection": ">=2.0,<2.3-dev", + "symfony/event-dispatcher": ">=2.0,<2.3-dev", + "symfony/finder": ">=2.0,<2.3-dev", + "symfony/translation": ">=2.0,<2.3-dev", + "symfony/yaml": ">=2.0,<2.3-dev" + }, + "suggest": { + "behat/mink-extension": "for integration with Mink testing framework", + "behat/symfony2-extension": "for integration with Symfony2 web framework", + "behat/yii-extension": "for integration with Yii web framework" + }, + "bin": [ + "bin/behat" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "2.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Behat": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Scenario-oriented BDD framework for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Symfony2" + ], + "time": "2013-01-27 14:45:41" + }, + { + "name": "behat/gherkin", + "version": "v2.2.9", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "v2.2.9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/v2.2.9", + "reference": "v2.2.9", + "shasum": "" + }, + "require": { + "php": ">=5.3.1", + "symfony/finder": ">=2.0,<2.4-dev" + }, + "require-dev": { + "symfony/config": ">=2.0,<2.4-dev", + "symfony/translation": ">=2.0,<2.4-dev", + "symfony/yaml": ">=2.0,<2.4-dev" + }, + "suggest": { + "symfony/config": "If you want to use Config component to manage resources", + "symfony/translation": "If you want to use Symfony2 translations adapter", + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "DSL", + "Symfony2", + "parser" + ], + "time": "2013-03-02 10:38:40" + }, + { + "name": "phpunit/php-code-coverage", + "version": "1.2.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1.2.9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9", + "reference": "1.2.9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.1.1@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2013-02-26 18:55:56" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "1.3.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", + "reference": "1.3.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2012-10-11 04:44:38" + }, + { + "name": "phpunit/php-text-template", + "version": "1.1.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-text-template.git", + "reference": "1.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", + "reference": "1.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2012-10-31 11:15:28" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-timer.git", + "reference": "1.0.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", + "reference": "1.0.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "timer" + ], + "time": "2012-10-11 04:45:58" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.1.5", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1.1.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", + "reference": "1.1.5", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "tokenizer" + ], + "time": "2012-10-11 04:47:14" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3.7.15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.15", + "reference": "3.7.15", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-timer": ">=1.0.2,<1.1.0", + "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", + "symfony/yaml": ">=2.2.0" + }, + "require-dev": { + "pear-pear/pear": "1.9.4" + }, + "suggest": { + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "phpunit/php-invoker": ">=1.1.0,<1.2.0" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2013-03-01 11:55:06" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1.2.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", + "reference": "1.2.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "symfony/config", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Config", + "source": { + "type": "git", + "url": "https://github.com/symfony/Config.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Config\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "http://symfony.com", + "time": "2013-02-17 12:27:42" + }, + { + "name": "symfony/console", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "v2.2.0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.0", + "reference": "v2.2.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2013-03-01 06:43:14" + }, + { + "name": "symfony/dependency-injection", + "version": "v2.2.0", + "target-dir": "Symfony/Component/DependencyInjection", + "source": { + "type": "git", + "url": "https://github.com/symfony/DependencyInjection.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/config": ">=2.2,<2.3-dev", + "symfony/yaml": ">=2.0,<3.0" + }, + "suggest": { + "symfony/config": "2.2.*", + "symfony/yaml": "2.2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\DependencyInjection\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "http://symfony.com", + "time": "2013-02-11 11:43:49" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.2.0", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/dependency-injection": ">=2.0,<3.0" + }, + "suggest": { + "symfony/dependency-injection": "2.2.*", + "symfony/http-kernel": "2.2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com", + "time": "2013-02-11 11:26:43" + }, + { + "name": "symfony/finder", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "v2.2.0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.0", + "reference": "v2.2.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com", + "time": "2013-02-28 14:06:36" + }, + { + "name": "symfony/translation", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Translation", + "source": { + "type": "git", + "url": "https://github.com/symfony/Translation.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/config": ">=2.0,<2.3-dev", + "symfony/yaml": ">=2.2,<3.0" + }, + "suggest": { + "symfony/config": "2.2.*", + "symfony/yaml": "2.2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "http://symfony.com", + "time": "2013-02-08 16:10:57" + }, + { + "name": "symfony/yaml", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2013-01-27 16:49:19" + } + ], "aliases": [ ], - "minimum-stability": "dev", + "minimum-stability": "stable", "stability-flags": { "wp-cli/php-cli-tools": 20, "behat/behat": 0 From 61a81205df1accf69d3d5d0979fa5f389070438f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Mar 2013 02:28:38 +0200 Subject: [PATCH 1301/5359] remove unnecessary loading of PHPUnit/Autoload.php --- features/bootstrap/FeatureContext.php | 1 - 1 file changed, 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 57c05cda1..80bcba82f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -4,7 +4,6 @@ Behat\Behat\Context\TranslatedContextInterface, Behat\Behat\Context\BehatContext; -require_once 'PHPUnit/Autoload.php'; require_once 'PHPUnit/Framework/Assert/Functions.php'; require_once __DIR__ . '/../../php/utils.php'; From 2fcb19477aa5839814fb3a6f67a0582ca25b20ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Mar 2013 02:39:22 +0200 Subject: [PATCH 1302/5359] don't check if the cache directory exists `core download` takes care of it --- features/bootstrap/FeatureContext.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 80bcba82f..bbdb33691 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -179,12 +179,10 @@ public function download_wordpress_files() { // We cache the results of "wp core download" to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - if ( !file_exists( $cache_dir ) ) { - mkdir( $cache_dir ); - $this->run( 'core download' . \WP_CLI\Utils\assoc_args_to_str( array( - 'path' => $cache_dir - ) ) ); - } + + $r = $this->run( 'core download' . \WP_CLI\Utils\assoc_args_to_str( array( + 'path' => $cache_dir + ) ) ); exec( sprintf( "cp -r '%s/'* '%s/'", $cache_dir, $this->install_dir ) ); } From ea8b72394eaf08eb6ac25dcb2f68c122fa4323fa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 2 Mar 2013 20:00:41 +0200 Subject: [PATCH 1303/5359] make update-phar generate a checksum [ci skip] --- utils/update-phar | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/utils/update-phar b/utils/update-phar index 8105be91d..0f208844c 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -5,10 +5,12 @@ set -ex current_rev=$(git rev-parse HEAD) current_rev=${current_rev:0:10} +# generate archive php -dphar.readonly=0 ./utils/make-phar.php ../wp-cli-packages/phar/wp-cli.phar --quiet cd ../wp-cli-packages +# check which wp-cli commit the previous Phar archive was based on new_commit_subj="update wp-cli.phar to $current_rev" current_commit_subj=$(git show -s --pretty=format:%s HEAD) @@ -18,7 +20,12 @@ if [ "$new_commit_subj" = "$current_commit_subj" ]; then exit 1 fi -git add phar/wp-cli.phar +fname="phar/wp-cli.phar" + +# generate md5 checksum +md5sum $fname | cut -d ' ' -f 1 > $fname.md5 + +git add $fname $fname.md5 git commit -m "$new_commit_subj" From f4ef6a0c2c9a081dbc22f1d938602f32d7326a51 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:10:00 +0100 Subject: [PATCH 1304/5359] Removed use of $error --- php/commands/media.php | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 0862cc8bd..e25cd4d61 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -6,9 +6,7 @@ * @package wp-cli */ class Media_Command extends WP_CLI_Command { - - var $errors = false; - + function __construct() { WP_Filesystem(); } @@ -49,23 +47,18 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::line( 'Found ' . count( $images ) . ' pictures to regenerate!' ); - foreach ( $images as $image ) + foreach ( $images as $image ) { $this->_process_regeneration( $image->ID ); + } - if ( $this->errors ) - WP_CLI::error( 'Finished regenerating images - however, there were some errors throughout.' ); - else - WP_CLI::success( 'Finished - without any errors either!' ); + WP_CLI::success( 'Finished regenerating images' ); } private function _process_regeneration( $id ) { - // Don't break the JSON result - @error_reporting( 0 ); $image = get_post( $id ); if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { - $this->errors = true; WP_CLI::line( "FAILED: {$image->post_title} - invalid image ID" ); return; } @@ -73,7 +66,6 @@ private function _process_regeneration( $id ) { $fullsizepath = get_attached_file( $image->ID ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - $this->errors = true; WP_CLI::line( "FAILED: {$image->post_title} - Can't find it $fullsizepath" ); return; } @@ -139,7 +131,6 @@ private function _process_regeneration( $id ) { } if ( empty( $metadata ) ) { - $this->errors = true; WP_CLI::line( 'Unknown failure reason.' ); return; } From 6e173a8c06436564464d7c4fc8e17c60eecd7aa9 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:10:23 +0100 Subject: [PATCH 1305/5359] Removed settings timeout --- php/commands/media.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index e25cd4d61..b1bd073ff 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -70,9 +70,6 @@ private function _process_regeneration( $id ) { return; } - // 5 minutes per image should be PLENTY - @set_time_limit( 900 ); - $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); From 03979a48356c4061d412aa038009c4e93d3f10cc Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:16:34 +0100 Subject: [PATCH 1306/5359] Use concate instead of sprintf --- php/commands/media.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index b1bd073ff..a9b6c9a3e 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -79,15 +79,10 @@ private function _process_regeneration( $id ) { unset( $array_file[ count( $array_file ) - 1 ] ); $imagePath = implode( DIRECTORY_SEPARATOR, $array_path ) . DIRECTORY_SEPARATOR . implode( '.', $array_file ); - - - /** - * Continue - */ $dirPath = explode( DIRECTORY_SEPARATOR, $imagePath ); - $imageName = sprintf( "%s-", $dirPath[ count( $dirPath ) - 1 ] ); + $imageName = $dirPath[ count( $dirPath ) - 1 ] . "-"; unset( $dirPath[ count( $dirPath ) - 1 ] ); - $dirPath = sprintf( "%s%s", implode( DIRECTORY_SEPARATOR, $dirPath ), DIRECTORY_SEPARATOR ); + $dirPath = implode( DIRECTORY_SEPARATOR, $dirPath ) . DIRECTORY_SEPARATOR; // Read and delete files $dir = opendir( $dirPath ); From 4cdfc0e061c30fa9423ac2535fc4330c3c600a88 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:17:45 +0100 Subject: [PATCH 1307/5359] Using WP_CLI::warning --- php/commands/media.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index a9b6c9a3e..67ac71d58 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -59,14 +59,14 @@ private function _process_regeneration( $id ) { $image = get_post( $id ); if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { - WP_CLI::line( "FAILED: {$image->post_title} - invalid image ID" ); + WP_CLI::warning( "FAILED: {$image->post_title} - invalid image ID" ); return; } $fullsizepath = get_attached_file( $image->ID ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::line( "FAILED: {$image->post_title} - Can't find it $fullsizepath" ); + WP_CLI::warning( "FAILED: {$image->post_title} - Can't find it $fullsizepath" ); return; } From 798aeac310e0a4d175e1265f656e3c587a83956f Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:20:12 +0100 Subject: [PATCH 1308/5359] Using WP_CLI::warning --- php/commands/media.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 67ac71d58..038084982 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -59,14 +59,14 @@ private function _process_regeneration( $id ) { $image = get_post( $id ); if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { - WP_CLI::warning( "FAILED: {$image->post_title} - invalid image ID" ); + WP_CLI::warning( "{$image->post_title} - invalid image ID" ); return; } $fullsizepath = get_attached_file( $image->ID ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "FAILED: {$image->post_title} - Can't find it $fullsizepath" ); + WP_CLI::warning( "{$image->post_title} - Can't find it $fullsizepath" ); return; } @@ -118,12 +118,12 @@ private function _process_regeneration( $id ) { $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); if ( is_wp_error( $metadata ) ) { - WP_CLI::line( $metadata->get_error_message() ); + WP_CLI::warning( $metadata->get_error_message() ); return; } if ( empty( $metadata ) ) { - WP_CLI::line( 'Unknown failure reason.' ); + WP_CLI::warning( 'Unknown failure reason.' ); return; } wp_update_attachment_metadata( $image->ID, $metadata ); From eb904e498318025e65cf3e6f830ac03f543cdabe Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 17:36:14 +0100 Subject: [PATCH 1309/5359] Polished some feedback messages --- php/commands/media.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 038084982..ffe9f5323 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -59,14 +59,14 @@ private function _process_regeneration( $id ) { $image = get_post( $id ); if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { - WP_CLI::warning( "{$image->post_title} - invalid image ID" ); + WP_CLI::warning( "{$image->post_title} - invalid image ID." ); return; } $fullsizepath = get_attached_file( $image->ID ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "{$image->post_title} - Can't find it $fullsizepath" ); + WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); return; } @@ -123,11 +123,11 @@ private function _process_regeneration( $id ) { } if ( empty( $metadata ) ) { - WP_CLI::warning( 'Unknown failure reason.' ); + WP_CLI::warning( "Couldn't regenerate image." ); return; } wp_update_attachment_metadata( $image->ID, $metadata ); - WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds " ); + WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); } } From 9ff48b6f2259151b2c0f493e93889ccc0a374003 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 18:10:00 +0100 Subject: [PATCH 1310/5359] Cleaned up unused code --- php/commands/media.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index ffe9f5323..8bfb5f345 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -69,12 +69,10 @@ private function _process_regeneration( $id ) { WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); return; } - + //wp_upload_dir() $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); - - $imageFormat = $array_file[ count( $array_file ) - 1 ]; - + unset( $array_path[ count( $array_path ) - 1 ] ); unset( $array_file[ count( $array_file ) - 1 ] ); From 8dba6eb248e367502012c5ab19ba2419fa131947 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 18:40:23 +0100 Subject: [PATCH 1311/5359] Better grammar --- php/commands/media.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 8bfb5f345..77e6f7e89 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -37,7 +37,7 @@ function regenerate( $args, $assoc_args = array() ) { if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { if ( $id ) { - WP_CLI::error( "Unable to find the image. Are you sure some it exists?" ); + WP_CLI::error( "Unable to find the image. Are you sure it exists?" ); } else { WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); } @@ -45,7 +45,7 @@ function regenerate( $args, $assoc_args = array() ) { return; } - WP_CLI::line( 'Found ' . count( $images ) . ' pictures to regenerate!' ); + WP_CLI::line( 'Found ' . count( $images ) . ' images to regenerate.' ); foreach ( $images as $image ) { $this->_process_regeneration( $image->ID ); @@ -72,7 +72,7 @@ private function _process_regeneration( $id ) { //wp_upload_dir() $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); - + unset( $array_path[ count( $array_path ) - 1 ] ); unset( $array_file[ count( $array_file ) - 1 ] ); From cd49ab9aa939a1ca028133255103cf9842074842 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 19:26:03 +0100 Subject: [PATCH 1312/5359] Fixed variable name so thumbnails get unlinked again --- php/commands/media.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 77e6f7e89..05ad83a9d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -69,7 +69,7 @@ private function _process_regeneration( $id ) { WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); return; } - //wp_upload_dir() + $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); @@ -96,7 +96,7 @@ private function _process_regeneration( $id ) { if ( "" == $thumbnail[ 0 ] ) { preg_match('/\.[^\.]+$/i', $file, $ext); $thumbnailFormat = $ext[0]; - $thumbnail = basename( $file, $thumbnailFormat ); + $thumbnail = basename( $filename, $thumbnailFormat ); $sizes = explode( 'x', $thumbnail ); From 7b9033d8f6c819bb1b4a17288da5898fe27c7ec3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Mar 2013 23:26:24 +0200 Subject: [PATCH 1313/5359] install composer dependencies in local-build too see #342 --- utils/local-build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/local-build b/utils/local-build index fab82fddf..4fd798d20 100755 --- a/utils/local-build +++ b/utils/local-build @@ -10,6 +10,10 @@ if [ "$BASH_SOURCE" = "$0" ]; then exit 1 fi +[ -f composer.phar ] || curl -sS https://getcomposer.org/installer | php + +php composer.phar install + DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd) alias wp='$DIR/../bin/wp' From 2124bedecfaa9a069404ebdee99001c4b8b328f9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 3 Mar 2013 23:44:16 +0200 Subject: [PATCH 1314/5359] make local-build embedable into .bashrc again see #342 --- utils/local-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/local-build b/utils/local-build index 4fd798d20..9d92ea875 100755 --- a/utils/local-build +++ b/utils/local-build @@ -12,7 +12,7 @@ fi [ -f composer.phar ] || curl -sS https://getcomposer.org/installer | php -php composer.phar install +[ -d vendor/ ] || php composer.phar install DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd) From 11d8a246b5b40e8e6b14c56abe823e0725931656 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 22:59:18 +0100 Subject: [PATCH 1315/5359] Added position paramater `wp media regenerate 21 45 56` and better messages --- php/commands/media.php | 49 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 05ad83a9d..eff128ef7 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -14,44 +14,38 @@ function __construct() { /** * Regenerate thumbnail(s) * - * @synopsis [--id=<id>] [--yes] + * @synopsis <id>... [--yes] * props @benmay & @Viper007Bond */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - - $vars = wp_parse_args( $assoc_args, array( - 'id' => false - ) ); - - extract($vars, EXTR_SKIP); - + $count = 0; + // If id is given, skip confirm because it is only one file - if( !empty( $id ) ) { + if( !empty( $args ) ) { $assoc_args['yes'] = true; } WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); - $where_clause = ( $id ) ? "AND ID = $id" : ''; + $where_clause = ( !empty( $args ) ) ? "AND ID = " . implode(" OR ID = ", $args) . " " : ''; - if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC" ) ) { - if ( $id ) { - WP_CLI::error( "Unable to find the image. Are you sure it exists?" ); - } else { - WP_CLI::error( "Unable to find any images. Are you sure some exist?" ); - } - - return; + if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A ) ) { + //No images, so all keys in $args are not found within WP + WP_CLI::error( $this->_not_found_message( $args ) ); } - - WP_CLI::line( 'Found ' . count( $images ) . ' images to regenerate.' ); + $count = count($images); + + WP_CLI::line( "Found {$count} " . ngettext('image', 'images', $count) . " to regenerate." ); + + $not_found = array_diff( $args, wp_list_pluck( $images, 'ID' ) ); + WP_CLI::warning( $this->_not_found_message( $not_found ) ); foreach ( $images as $image ) { - $this->_process_regeneration( $image->ID ); + $this->_process_regeneration( $image['ID'] ); } - WP_CLI::success( 'Finished regenerating images' ); + WP_CLI::success( "Finished regenerating " . ngettext('the image', 'all images', $count) . "."); } private function _process_regeneration( $id ) { @@ -69,7 +63,9 @@ private function _process_regeneration( $id ) { WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); return; } - + + WP_CLI::line( "Start processing of \"" . get_the_title( $image->ID ) . " (ID: {$image->ID})\"" ); + $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); @@ -125,7 +121,12 @@ private function _process_regeneration( $id ) { return; } wp_update_attachment_metadata( $image->ID, $metadata ); - WP_CLI::success( esc_html( get_the_title( $image->ID ) ) . " (ID {$image->ID}): All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); + WP_CLI::success( "{$image->ID} All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); + } + + private function _not_found_message( $not_found_ids ){ + $count = count($not_found_ids); + return "Unable to find the " . ngettext('image', 'images', $count) . " (" . implode(", ", $not_found_ids) . "). Are you sure " . ngettext('it', 'they', $count) . " " . ngettext('exist', 'exists', $count) . "?"; } } From 7adeca7ecc3741870818cac2627bc3a2953ff3d8 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 23:00:57 +0100 Subject: [PATCH 1316/5359] Polished message --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index eff128ef7..4f9cd9d90 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -121,7 +121,7 @@ private function _process_regeneration( $id ) { return; } wp_update_attachment_metadata( $image->ID, $metadata ); - WP_CLI::success( "{$image->ID} All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); + WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); } private function _not_found_message( $not_found_ids ){ From 91d80ecc28ea648eef6c7ec4355d34faab757225 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 3 Mar 2013 23:16:44 +0100 Subject: [PATCH 1317/5359] renamed parameter --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 4f9cd9d90..e2de098e0 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -14,7 +14,7 @@ function __construct() { /** * Regenerate thumbnail(s) * - * @synopsis <id>... [--yes] + * @synopsis <attachment-id>... [--yes] * props @benmay & @Viper007Bond */ function regenerate( $args, $assoc_args = array() ) { From d63290d8b2357aafe6779d799acf27e9e9e1c212 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 4 Mar 2013 01:24:30 +0100 Subject: [PATCH 1318/5359] Use WP_Query instead of custom select --- php/commands/media.php | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index e2de098e0..96e46a952 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -19,7 +19,6 @@ function __construct() { */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - $count = 0; // If id is given, skip confirm because it is only one file if( !empty( $args ) ) { @@ -28,23 +27,35 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); - $where_clause = ( !empty( $args ) ) ? "AND ID = " . implode(" OR ID = ", $args) . " " : ''; + $query_args = array( + 'post_type' => 'attachment', + 'post__in' => $args, + 'post_mime_type' => 'image', + 'post_status' => 'any', + 'posts_per_page' => -1, + 'fields' => 'ids' + ); - if ( !$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' $where_clause AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A ) ) { + $images = new WP_Query( $query_args ); + + if ( $images->post_count == 0 ) { //No images, so all keys in $args are not found within WP WP_CLI::error( $this->_not_found_message( $args ) ); } - $count = count($images); + $count = $images->post_count; WP_CLI::line( "Found {$count} " . ngettext('image', 'images', $count) . " to regenerate." ); + + $not_found = array_diff( $args, $images->posts ); + if( !empty($not_found) ) { + WP_CLI::warning( $this->_not_found_message( $not_found ) ); + } - $not_found = array_diff( $args, wp_list_pluck( $images, 'ID' ) ); - WP_CLI::warning( $this->_not_found_message( $not_found ) ); - - foreach ( $images as $image ) { - $this->_process_regeneration( $image['ID'] ); + foreach ( $images->posts as $id ) { + $this->_process_regeneration( $id ); } - + + wp_reset_postdata(); WP_CLI::success( "Finished regenerating " . ngettext('the image', 'all images', $count) . "."); } From b8c3f86e7af8bbea12a995ea6c38345187bd0151 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Mon, 4 Mar 2013 15:06:33 +0100 Subject: [PATCH 1319/5359] set default value for query_var to true, same as the codex --- templates/post_type.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 44ebb048e..429e00226 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -5,7 +5,7 @@ 'show_ui' => true, 'supports' => array( 'title', 'editor' ), 'has_archive' => true, - 'query_var' => {{slug}}, + 'query_var' => true, 'rewrite' => true, 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), From e539d6f3399ad9e39ca6ccd05f886de0e8e07306 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Mon, 4 Mar 2013 15:16:51 +0100 Subject: [PATCH 1320/5359] fixed escaped quotes that caused wrong urls on output --- templates/post_type_extended.mustache | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/post_type_extended.mustache b/templates/post_type_extended.mustache index 240746970..9acbbb5d2 100755 --- a/templates/post_type_extended.mustache +++ b/templates/post_type_extended.mustache @@ -12,19 +12,19 @@ function {{machine_name}}_updated_messages( $messages ) { $messages['{{slug}}'] = array( 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{{label_ucfirst}} updated. <a target=\"_blank\" href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), + 1 => sprintf( __('{{label_ucfirst}} updated. <a target="_blank" href="%s">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), 2 => __('Custom field updated.', '{{textdomain}}'), 3 => __('Custom field deleted.', '{{textdomain}}'), 4 => __('{{label_ucfirst}} updated.', '{{textdomain}}'), /* translators: %s: date and time of the revision */ 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, - 6 => sprintf( __('{{label_ucfirst}} published. <a href=\"%s\">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), + 6 => sprintf( __('{{label_ucfirst}} published. <a href="%s">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), - 8 => sprintf( __('{{label_ucfirst}} submitted. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), - 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s\">Preview {{label}}</a>', '{{textdomain}}'), + 8 => sprintf( __('{{label_ucfirst}} submitted. <a target="_blank" href="%s">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), + 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview {{label}}</a>', '{{textdomain}}'), // translators: Publish box date format, see http://php.net/date date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( $permalink ) ), - 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target=\"_blank\" href=\"%s\">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), + 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target="_blank" href="%s">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), ); return $messages; From fb0cfe745cbedecc20a60f394ca4d288b254921f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 4 Mar 2013 17:35:35 +0200 Subject: [PATCH 1321/5359] add smoke test to utils/update-phar --- utils/update-phar | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/utils/update-phar b/utils/update-phar index 0f208844c..1d910bd1a 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -5,12 +5,21 @@ set -ex current_rev=$(git rev-parse HEAD) current_rev=${current_rev:0:10} +packages_repo=../wp-cli-packages + +fname="phar/wp-cli.phar" + # generate archive -php -dphar.readonly=0 ./utils/make-phar.php ../wp-cli-packages/phar/wp-cli.phar --quiet +php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet -cd ../wp-cli-packages +cd $packages_repo + +# smoke test +php $fname --version # check which wp-cli commit the previous Phar archive was based on +# can't use the md5 hash, since it will be different each time the +# archive is generated new_commit_subj="update wp-cli.phar to $current_rev" current_commit_subj=$(git show -s --pretty=format:%s HEAD) @@ -20,8 +29,6 @@ if [ "$new_commit_subj" = "$current_commit_subj" ]; then exit 1 fi -fname="phar/wp-cli.phar" - # generate md5 checksum md5sum $fname | cut -d ' ' -f 1 > $fname.md5 From 0c6c0bb90ddf738632004e15e2fb6226cc360b4a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 4 Mar 2013 17:38:01 +0200 Subject: [PATCH 1322/5359] add missing Composer files to phar archive --- utils/make-phar.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 96c66abb8..1911b8f36 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -56,6 +56,7 @@ function add_file( $phar, $path ) { $vendor_dirs = array( './vendor/mustache', './vendor/wp-cli', + './vendor/composer', ); foreach ( $vendor_dirs as $vendor_dir ) { @@ -69,6 +70,8 @@ function add_file( $phar, $path ) { } } +add_file( $phar, './vendor/autoload.php' ); + $phar->setStub( <<<EOB #!/usr/bin/env php <?php From 2cacbdc3a0153c41ed4d67f829c8252203daa047 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 4 Mar 2013 17:57:06 +0200 Subject: [PATCH 1323/5359] add utils/test-phar-download. see #340 --- utils/test-phar-download | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 utils/test-phar-download diff --git a/utils/test-phar-download b/utils/test-phar-download new file mode 100755 index 000000000..f1a47e519 --- /dev/null +++ b/utils/test-phar-download @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | md5sum | cut -d ' ' -f 1) + +echo "expected:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.md5) +echo "actual: " $actual_checksum From a815e13dd4d3c35f0e3c53992e3f4c0db7b6162d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 4 Mar 2013 20:48:19 +0200 Subject: [PATCH 1324/5359] use tests_add_filter() in bootstrap.mustache see https://core.trac.wordpress.org/ticket/23690 --- templates/bootstrap.mustache | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index 382f74013..18f87a91a 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -1,8 +1,11 @@ <?php -$GLOBALS['wp_tests_options'] = array( - 'active_plugins' => array( basename( dirname( dirname( __FILE__ ) ) ) . '/{{plugin_slug}}.php' ), -); +require_once getenv( 'WP_TESTS_DIR' ) . '/includes/functions.php'; + +function _manually_load_plugin() { + require dirname( __FILE__ ) . '/../{{plugin_slug}}.php'; +} +tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); require getenv( 'WP_TESTS_DIR' ) . '/includes/bootstrap.php'; From 18d6a32abf4a00518e6361dc843bebea4619bc1e Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 4 Mar 2013 21:19:47 +0100 Subject: [PATCH 1325/5359] Removed query reset --- php/commands/media.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 96e46a952..9942c9b53 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -55,7 +55,6 @@ function regenerate( $args, $assoc_args = array() ) { $this->_process_regeneration( $id ); } - wp_reset_postdata(); WP_CLI::success( "Finished regenerating " . ngettext('the image', 'all images', $count) . "."); } From 2d6853bb030d94f77ab3e54ca0a3e5528b6251be Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 4 Mar 2013 22:08:59 +0100 Subject: [PATCH 1326/5359] Cleanup regenerating thumbnails and use more WP function --- php/commands/media.php | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 9942c9b53..2b0fa663d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -76,35 +76,33 @@ private function _process_regeneration( $id ) { WP_CLI::line( "Start processing of \"" . get_the_title( $image->ID ) . " (ID: {$image->ID})\"" ); - $array_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); - $array_file = explode( '.', $array_path[ count( $array_path ) - 1 ] ); + $a_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); + $a_file = explode( '.', $a_path[ count( $a_path ) - 1 ] ); - unset( $array_path[ count( $array_path ) - 1 ] ); - unset( $array_file[ count( $array_file ) - 1 ] ); - - $imagePath = implode( DIRECTORY_SEPARATOR, $array_path ) . DIRECTORY_SEPARATOR . implode( '.', $array_file ); - $dirPath = explode( DIRECTORY_SEPARATOR, $imagePath ); - $imageName = $dirPath[ count( $dirPath ) - 1 ] . "-"; - unset( $dirPath[ count( $dirPath ) - 1 ] ); - $dirPath = implode( DIRECTORY_SEPARATOR, $dirPath ) . DIRECTORY_SEPARATOR; + unset( $a_path ); + unset( $a_file[ count( $a_file ) - 1 ] ); + + $image_name = $a_file[ count( $a_file ) - 1 ] . '-'; + $dir_path = wp_upload_dir(); // Read and delete files - $dir = opendir( $dirPath ); + $dir = opendir( $dir_path['basedir'] ); $files = array(); + while ( $file = readdir( $dir ) ) { - - if ( !( strrpos( $file, $imageName ) === false ) ) { + + if ( !( strrpos( $file, $image_name ) === false ) ) { - $thumbnail = explode( $imageName, $file ); - $filename = $thumbnail[ 1 ]; + $thumbnail = explode( $image_name, $file ); + $filename = $thumbnail[ 1 ]; //If we got the original / full image if ( "" == $thumbnail[ 0 ] ) { - preg_match('/\.[^\.]+$/i', $file, $ext); - $thumbnailFormat = $ext[0]; - $thumbnail = basename( $filename, $thumbnailFormat ); - - $sizes = explode( 'x', $thumbnail ); + $filetype = wp_check_filetype($file); + $thumbnail_ext = ".{$filetype['ext']}"; + $thumbnail_name = basename( $filename, $thumbnail_ext ); + + $sizes = explode( 'x', $thumbnail_name ); // If not cropped by WP if ( 2 == count( $sizes ) ) { @@ -112,7 +110,7 @@ private function _process_regeneration( $id ) { $height = $sizes[1]; if ( is_numeric( $width ) && is_numeric( $height ) ) { WP_CLI::line( "Thumbnail: {$width} x {$height} was deleted." ); - @unlink( $dirPath . $imageName . $width . 'x' . $thumbnail . $thumbnailFormat ); + @unlink( $dir_path['basedir'] . DIRECTORY_SEPARATOR . $image_name . $thumbnail_name . $thumbnail_ext ); } } } From 2517635d5b7a6440008c2bba6085afffd02926e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 5 Mar 2013 00:33:08 +0200 Subject: [PATCH 1327/5359] don't need to place the plugin directory inside the plugins folder anymore see http://core.trac.wordpress.org/ticket/23690 --- templates/.travis.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index a34cedf75..a2020ad18 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -19,10 +19,6 @@ before_script: - mkdir -p $WP_CORE_DIR - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - - plugin_slug=$(basename $(pwd)) - - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug - - cd .. - - mv $plugin_slug $plugin_dir # set up testing suite - export WP_TESTS_DIR=/tmp/wordpress-tests/ - svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR @@ -32,9 +28,8 @@ before_script: - sed -i "s/yourdbnamehere/wordpress_test/" wp-tests-config.php - sed -i "s/yourusernamehere/root/" wp-tests-config.php - sed -i "s/yourpasswordhere//" wp-tests-config.php + - cd - # set up database - mysql -e 'CREATE DATABASE wordpress_test;' -uroot - # prepare for running the tests - - cd $plugin_dir script: phpunit From 991a2e53181a5c388fdb8df600e9071c1aeeb8a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 5 Mar 2013 00:43:21 +0200 Subject: [PATCH 1328/5359] plugin init-tests: always overwrite existing files the assumption is that the plugin will already be under version control --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 75b7a2251..4697c47fb 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -221,7 +221,7 @@ function plugin_tests( $args, $assoc_args ) { ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( $this->get_template_path( $file ), "$dir/$file" ); + $wp_filesystem->copy( $this->get_template_path( $file ), "$dir/$file", true ); } WP_CLI::success( "Created test files in $plugin_dir" ); From d1e6faa7ce99e134cbc834f887ed1b7de9100835 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Mar 2013 20:26:36 +0100 Subject: [PATCH 1329/5359] Added @unlink and merged from upstream master --- php/commands/media.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 2b0fa663d..b6b247c3d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -90,12 +90,12 @@ private function _process_regeneration( $id ) { $files = array(); while ( $file = readdir( $dir ) ) { - + WP_CLI::print_value( $dir_path ); if ( !( strrpos( $file, $image_name ) === false ) ) { $thumbnail = explode( $image_name, $file ); $filename = $thumbnail[ 1 ]; - +//WP_CLI::print_value( $dir ); //If we got the original / full image if ( "" == $thumbnail[ 0 ] ) { $filetype = wp_check_filetype($file); @@ -110,7 +110,7 @@ private function _process_regeneration( $id ) { $height = $sizes[1]; if ( is_numeric( $width ) && is_numeric( $height ) ) { WP_CLI::line( "Thumbnail: {$width} x {$height} was deleted." ); - @unlink( $dir_path['basedir'] . DIRECTORY_SEPARATOR . $image_name . $thumbnail_name . $thumbnail_ext ); + unlink( $dir_path['basedir'] . DIRECTORY_SEPARATOR . $image_name . $thumbnail_name . $thumbnail_ext ); } } } From 812afd6627b8b7e9ceb90878a726841f6022e293 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Mar 2013 20:31:37 +0100 Subject: [PATCH 1330/5359] Removed print_r and finalized to generate man page --- php/commands/media.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index b6b247c3d..b61a28dd3 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -74,7 +74,7 @@ private function _process_regeneration( $id ) { return; } - WP_CLI::line( "Start processing of \"" . get_the_title( $image->ID ) . " (ID: {$image->ID})\"" ); + WP_CLI::line( "Start processing of \"" . get_the_title( $image->ID ) . "\" (ID: {$image->ID})" ); $a_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $a_file = explode( '.', $a_path[ count( $a_path ) - 1 ] ); @@ -90,12 +90,12 @@ private function _process_regeneration( $id ) { $files = array(); while ( $file = readdir( $dir ) ) { - WP_CLI::print_value( $dir_path ); + if ( !( strrpos( $file, $image_name ) === false ) ) { $thumbnail = explode( $image_name, $file ); $filename = $thumbnail[ 1 ]; -//WP_CLI::print_value( $dir ); + //If we got the original / full image if ( "" == $thumbnail[ 0 ] ) { $filetype = wp_check_filetype($file); From 2e95438b01d4bc7dc6c02445152d19f86a700716 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Mar 2013 21:07:18 +0100 Subject: [PATCH 1331/5359] Added man pages --- man-src/media-regenerate.txt | 15 +++++++++++++++ man/media-regenerate.1 | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 man-src/media-regenerate.txt create mode 100644 man/media-regenerate.1 diff --git a/man-src/media-regenerate.txt b/man-src/media-regenerate.txt new file mode 100644 index 000000000..92ba35b32 --- /dev/null +++ b/man-src/media-regenerate.txt @@ -0,0 +1,15 @@ +## OPTIONS + +* `--yes`: + + Answer yes to the confirmation message. + +* `<attachment-id>`: + + One or more IDs of the attachment to regenerate. + +## EXAMPLES + + wp media regenerate 123 1337 + + wp media regenerate --yes \ No newline at end of file diff --git a/man/media-regenerate.1 b/man/media-regenerate.1 new file mode 100644 index 000000000..082157a6a --- /dev/null +++ b/man/media-regenerate.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-MEDIA\-REGENERATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-media\-regenerate\fR \- Regenerate thumbnail(s) +. +.SH "SYNOPSIS" +wp media regenerate \fIattachment\-id\fR\.\.\. [\-\-yes] +. +.SH "OPTIONS" +. +.TP +\fB\-\-yes\fR: +. +.IP +Answer yes to the confirmation message\. +. +.TP +\fB<attachment\-id>\fR: +. +.IP +One or more IDs of the attachment to regenerate\. +. +.SH "EXAMPLES" +. +.nf + +wp media regenerate 123 1337 + +wp media regenerate \-\-yes +. +.fi + From 941959b1d4e08dc76dc183c6da19c055ff92b5f3 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 5 Mar 2013 21:08:42 +0100 Subject: [PATCH 1332/5359] Typo --- man-src/media-regenerate.txt | 2 +- man/media-regenerate.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/media-regenerate.txt b/man-src/media-regenerate.txt index 92ba35b32..f873f5349 100644 --- a/man-src/media-regenerate.txt +++ b/man-src/media-regenerate.txt @@ -6,7 +6,7 @@ * `<attachment-id>`: - One or more IDs of the attachment to regenerate. + One or more IDs of the attachments to regenerate. ## EXAMPLES diff --git a/man/media-regenerate.1 b/man/media-regenerate.1 index 082157a6a..8591e809a 100644 --- a/man/media-regenerate.1 +++ b/man/media-regenerate.1 @@ -21,7 +21,7 @@ Answer yes to the confirmation message\. \fB<attachment\-id>\fR: . .IP -One or more IDs of the attachment to regenerate\. +One or more IDs of the attachments to regenerate\. . .SH "EXAMPLES" . From a18cbccbaabbcdd1f1ec10db6551c8da3688ebca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Mar 2013 15:21:46 +0200 Subject: [PATCH 1333/5359] update-phar: make wp-cli revision linkable --- utils/update-phar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update-phar b/utils/update-phar index 1d910bd1a..e7cf98c22 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -20,7 +20,7 @@ php $fname --version # check which wp-cli commit the previous Phar archive was based on # can't use the md5 hash, since it will be different each time the # archive is generated -new_commit_subj="update wp-cli.phar to $current_rev" +new_commit_subj="update wp-cli.phar to wp-cli/wp-cli@$current_rev" current_commit_subj=$(git show -s --pretty=format:%s HEAD) From 84e575251177efae8ac3b3af41fae9e5235be597 Mon Sep 17 00:00:00 2001 From: Andrew Nacin <andrewnacin@gmail.com> Date: Thu, 7 Mar 2013 10:30:45 -0500 Subject: [PATCH 1334/5359] When populate_network() returns a wildcard DNS error, treat it as a warning, not an error. See http://core.trac.wordpress.org/ticket/23709. --- php/commands/core.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 66aa42144..19f7774dd 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -133,8 +133,12 @@ public function install_network( $args, $assoc_args ) { $result = populate_network( 1, $hostname, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); - if ( is_wp_error( $result ) ) - WP_CLI::error( $result ); + if ( is_wp_error( $result ) ) { + if ( $result->get_error_codes() === array( 'no_wildcard_dns' ) ) + WP_CLI::warning( __( 'Wildcard DNS may not be configured correctly.' ) ); + else + WP_CLI::error( $result ); + } ob_start(); ?> From feb50436e1423f7fbd2d2d35c6b7b0f9de0b8656 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 15:14:28 +0200 Subject: [PATCH 1335/5359] make `core upgrade` an alias of `core update` --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 19f7774dd..85a4bcf5e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -219,6 +219,8 @@ public function version( $args = array(), $assoc_args = array() ) { /** * Update WordPress. * + * @alias upgrade + * * @synopsis [<zip>] [--version=<version>] [--force] */ function update( $args, $assoc_args ) { From c759b00c148001be500d18e9176357b794038361 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Fri, 8 Mar 2013 11:15:08 +0000 Subject: [PATCH 1336/5359] Avoid warning if no rewrite rules exist --- php/commands/rewrite.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 0709e9f0f..d04344dd2 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -74,12 +74,20 @@ public function dump( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); - if ( isset( $assoc_args['json'] ) ) - echo json_encode( $rules ); - else - foreach ( $rules as $route => $rule ) - WP_CLI::line( $route . "\t" . $rule ); - + if ( isset( $assoc_args['json'] ) ) { + if ( ! $rules ) { + echo json_encode( "No rules" ); + } else { + echo json_encode( $rules ); + } + } else { + if ( ! $rules ) { + WP_CLI::line( "No rules" ); + } else { + foreach ( $rules as $route => $rule ) + WP_CLI::line( $route . "\t" . $rule ); + } + } } } From 315e68b14d7a366548756e56aeac547acce2ac3b Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Fri, 8 Mar 2013 15:02:52 +0000 Subject: [PATCH 1337/5359] Show messages as warnings, and change JSON output to empty array, not string --- php/commands/rewrite.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d04344dd2..0b24f8bd0 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -76,13 +76,14 @@ public function dump( $args, $assoc_args ) { if ( isset( $assoc_args['json'] ) ) { if ( ! $rules ) { - echo json_encode( "No rules" ); + WP_CLI::warning( 'No rewrite rules' ); + echo json_encode( array() ); } else { echo json_encode( $rules ); } } else { if ( ! $rules ) { - WP_CLI::line( "No rules" ); + WP_CLI::warning( 'No rewrite rules' ); } else { foreach ( $rules as $route => $rule ) WP_CLI::line( $route . "\t" . $rule ); From 88bb9ecb1f4dae89697e6f964f274ca741138aa8 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Fri, 8 Mar 2013 15:17:30 +0000 Subject: [PATCH 1338/5359] Clean up logic --- php/commands/rewrite.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 0b24f8bd0..41ae7d61b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -73,22 +73,18 @@ public function structure( $args, $assoc_args ) { public function dump( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); + if ( ! $rules ) { + $rules = array(); + WP_CLI::warning( 'No rewrite rules' ); + } if ( isset( $assoc_args['json'] ) ) { - if ( ! $rules ) { - WP_CLI::warning( 'No rewrite rules' ); - echo json_encode( array() ); - } else { - echo json_encode( $rules ); - } + echo json_encode( $rules ); } else { - if ( ! $rules ) { - WP_CLI::warning( 'No rewrite rules' ); - } else { - foreach ( $rules as $route => $rule ) - WP_CLI::line( $route . "\t" . $rule ); - } + foreach ( $rules as $route => $rule ) + WP_CLI::line( $route . "\t" . $rule ); } + } } From 1bf64de634f2918374b1c4106d4e39bffcbc5572 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Fri, 8 Mar 2013 15:28:00 +0000 Subject: [PATCH 1339/5359] . --- php/commands/rewrite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 41ae7d61b..7f464ae0a 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -75,7 +75,7 @@ public function dump( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); if ( ! $rules ) { $rules = array(); - WP_CLI::warning( 'No rewrite rules' ); + WP_CLI::warning( 'No rewrite rules.' ); } if ( isset( $assoc_args['json'] ) ) { From ac0d89c38b55f772f0016ebbcb7e70b8cb1bde17 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 17:55:36 +0200 Subject: [PATCH 1340/5359] move create_cmd() utility out of DB_Command --- php/commands/db.php | 26 +++++++------------------- php/utils.php | 12 ++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index bed80acbf..f304902d4 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -64,7 +64,7 @@ function reset( $_, $assoc_args ) { * @synopsis [--str] */ function optimize( $_, $assoc_args ) { - self::run( $assoc_args, self::create_cmd( + self::run( $assoc_args, \WP_CLI\Utils\create_cmd( 'mysqlcheck --optimize --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -78,7 +78,7 @@ function optimize( $_, $assoc_args ) { * @synopsis [--str] */ function repair( $_, $assoc_args ) { - self::run( $assoc_args, self::create_cmd( + self::run( $assoc_args, \WP_CLI\Utils\create_cmd( 'mysqlcheck --repair --host=%s --user=%s --password=%s %s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ) ); @@ -105,7 +105,7 @@ function connect( $_, $assoc_args ) { function query( $args, $assoc_args ) { list( $query ) = $args; - self::run( $assoc_args, $this->connect_string() . self::create_cmd( + self::run( $assoc_args, $this->connect_string() . \WP_CLI\Utils\create_cmd( ' --execute=%s', $query ) ); } @@ -118,7 +118,7 @@ function query( $args, $assoc_args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( $assoc_args, self::create_cmd( + self::run( $assoc_args, \WP_CLI\Utils\create_cmd( 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); @@ -133,7 +133,7 @@ function export( $args, $assoc_args ) { function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( $assoc_args, self::create_cmd( + self::run( $assoc_args, \WP_CLI\Utils\create_cmd( 'mysql %s --user=%s --password=%s --host=%s < %s', DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); @@ -141,7 +141,7 @@ function import( $args, $assoc_args ) { } private function connect_string() { - return self::create_cmd( 'mysql --host=%s --user=%s --password=%s --database=%s', + return \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --password=%s --database=%s', DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); } @@ -153,24 +153,12 @@ private function get_file_name( $args ) { } private static function create_execute_cmd( $execute_statement ) { - return self::create_cmd( + return \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --password=%s --execute=%s', DB_HOST, DB_USER, DB_PASSWORD, $execute_statement ); } - /** - * Given a formatted string and an arbitrary number of arguments, - * returns the final command, with the parameters escaped - */ - private static function create_cmd( $cmd ) { - $args = func_get_args(); - - $cmd = array_shift( $args ); - - return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); - } - private static function run( $assoc_args, $cmd ) { if ( isset( $assoc_args['str'] ) ) { WP_CLI::line( $cmd ); diff --git a/php/utils.php b/php/utils.php index efd1411cb..451085e7e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -100,6 +100,18 @@ function assoc_args_to_str( $assoc_args ) { return $str; } +/** + * Given a template string and an arbitrary number of arguments, + * returns the final command, with the parameters escaped. + */ +function create_cmd( $cmd ) { + $args = func_get_args(); + + $cmd = array_shift( $args ); + + return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); +} + function get_command_file( $command ) { $path = WP_CLI_ROOT . "/commands/$command.php"; From 3b33c81cc3a3dcdc8d2c47ed6494b15949637f08 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 21:07:42 +0200 Subject: [PATCH 1341/5359] behat: unify and standardize output testing steps: * always run replace_variables() and restrict variable names * add 'not contain' option --- features/bootstrap/FeatureContext.php | 4 +-- features/steps/basic_steps.php | 38 ++++++++++++++++----------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index bbdb33691..d45f89555 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -44,9 +44,9 @@ public function getHookDefinitionResources() return array(); } - public function replace_variables( &$str ) + public function replace_variables( $str ) { - $str = preg_replace_callback( '/\{(\w+)\}/', array( $this, '_replace_var' ), $str ); + return preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); } private function _replace_var( $matches ) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 2dbbdf160..28551fb89 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -52,9 +52,7 @@ function ( $world ) { $steps->When( '/^I run `wp (.+)`$/', function ( $world, $cmd ) { - $world->replace_variables( $cmd ); - - $world->result = $world->run( $cmd ); + $world->result = $world->run( $world->replace_variables( $cmd ) ); } ); @@ -89,22 +87,32 @@ function ( $world ) { } ); -$steps->Then( '/^(STDOUT|STDERR) should be:$/', - function ( $world, $stream, PyStringNode $output ) { - $world->replace_variables( $output ); +$steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', + function ( $world, $stream, $action, PyStringNode $expected ) { + $output = $world->replace_variables( $world->result->$stream ); - $result = rtrim( $world->result->$stream, "\n" ); + $expected = (string) $expected; - if ( (string) $output != $result ) { - throw new \Exception( $world->result->$stream ); + switch ( $action ) { + + case 'be': + $r = $expected === rtrim( $output, "\n" ); + break; + + case 'contain': + $r = false !== strpos( $output, $expected ); + break; + + case 'not contain': + $r = false === strpos( $output, $expected ); + break; + + default: + throw new PendingException(); } - } -); -$steps->Then( '/^(STDOUT|STDERR) should contain:$/', - function ( $world, $stream, PyStringNode $output ) { - if ( false === strpos( $world->result->$stream, (string) $output ) ) { - throw new \Exception( $world->result->$stream ); + if ( !$r ) { + throw new \Exception( $output ); } } ); From 2ece4d5699b3d1ac1399bd0f1a8ae526b879f1e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 16:48:47 +0200 Subject: [PATCH 1342/5359] first pass at theme tests --- features/theme.feature | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 features/theme.feature diff --git a/features/theme.feature b/features/theme.feature new file mode 100644 index 000000000..6552e04ed --- /dev/null +++ b/features/theme.feature @@ -0,0 +1,49 @@ +Feature: Manage WordPress themes + + Scenario: Checking the theme list + Given WP install + + When I run `wp theme status` + Then it should run without errors + And STDOUT should not be empty + + Scenario: Installing a theme + Given WP install + + When I run `wp theme install p2` + Then it should run without errors + + When I run the previous command again + Then the return code should be 1 + + When I run `wp theme status p2` + Then it should run without errors + And STDOUT should contain: + """ + Theme p2 details: + Name: P2 + """ + + When I run `wp theme path p2` + Then it should run without errors + And STDOUT should contain: + """ + /themes/p2/style.css + """ + + When I run `wp theme activate p2` + Then it should run without errors + And STDOUT should contain: + """ + Success: Switched to 'P2' theme. + """ + + When I run `wp theme delete p2` + Then it should run without errors + + When I run the previous command again + Then the return code should be 1 + And STDERR should contain: + """ + Error: The theme 'p2' could not be found. + """ From a718da781ef0d33aa93b7b42bbc1e7be12b033e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 15:22:25 +0200 Subject: [PATCH 1343/5359] always use wp_get_themes() --- php/commands/theme.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 236765801..9ba7c79b3 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -134,12 +134,7 @@ protected function install_from_repo( $slug, $assoc_args ) { protected function get_item_list() { $items = array(); - if( function_exists( 'wp_get_themes' ) ) - $themes = wp_get_themes(); - else - $themes = get_themes(); - - foreach ( $themes as $details ) { + foreach ( wp_get_themes() as $details ) { $file = $this->get_stylesheet_path( $details['Stylesheet'] ); $items[ $file ] = array( From 520f991342854b58f61525c6d74887e233d8ce37 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 15:45:41 +0200 Subject: [PATCH 1344/5359] use wp_get_theme() instead of get_theme_data() --- php/commands/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 9ba7c79b3..ee087bb2b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -41,7 +41,7 @@ protected function get_status( $stylesheet ) { } protected function get_details( $stylesheet ) { - return get_theme_data( $stylesheet ); + return wp_get_theme( $stylesheet ); } /** @@ -52,7 +52,7 @@ protected function get_details( $stylesheet ) { public function activate( $args = array() ) { list( $stylesheet, $child ) = $this->parse_name( $args ); - $details = get_theme_data( $stylesheet ); + $details = wp_get_theme( $stylesheet ); $parent = $details['Template']; From ec69fe9066b6c2f870f76dbc4718d58dc5a5e3ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 15:53:49 +0200 Subject: [PATCH 1345/5359] switch_theme() doesn't even accept a second parameter --- php/commands/theme.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index ee087bb2b..f1faed149 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -54,15 +54,7 @@ public function activate( $args = array() ) { $details = wp_get_theme( $stylesheet ); - $parent = $details['Template']; - - if ( empty( $parent ) ) { - $parent = $child; - } elseif ( !is_readable( $this->get_stylesheet_path( $parent ) ) ) { - WP_CLI::error( 'Parent theme not found.' ); - } - - switch_theme( $parent, $child ); + switch_theme( $child ); $name = $details['Title']; From 4c01e5675f4ccc377ffccb1bf817bc8eee8c3a1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 16:48:58 +0200 Subject: [PATCH 1346/5359] add tests for `plugin status` --- features/plugin.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 features/plugin.feature diff --git a/features/plugin.feature b/features/plugin.feature new file mode 100644 index 000000000..0300fb252 --- /dev/null +++ b/features/plugin.feature @@ -0,0 +1,23 @@ +Feature: Manage WordPress plugins + + Scenario: Checking the plugin status + Given WP install + + When I run `wp plugin status` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp plugin status hello` + Then it should run without errors + And STDOUT should contain: + """ + Plugin hello details: + Name: Hello Dolly + """ + + When I run `wp plugin status non-existent-plugin` + Then the return code should be 1 + And STDERR should contain: + """ + Error: The plugin 'non-existent-plugin' could not be found. + """ From 5b188048ab71d0fab90530a586c7da3fbcfcc9a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 16:47:50 +0200 Subject: [PATCH 1347/5359] use WP_Theme objects, instead of messing with paths --- php/WP_CLI/CommandWithUpgrade.php | 22 ++------- php/commands/plugin.php | 15 ++++++ php/commands/theme.php | 82 +++++++++++++++---------------- 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 1cf052645..08b87ccfb 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -15,9 +15,8 @@ abstract protected function get_item_list(); abstract protected function get_all_items(); abstract protected function get_status( $file ); - abstract protected function get_details( $file ); - abstract protected function _status_single( $details, $name, $version, $status ); + abstract protected function status_single( $args ); abstract protected function install_from_repo( $slug, $assoc_args ); @@ -28,9 +27,7 @@ function status( $args ) { if ( empty( $args ) ) { $this->status_all(); } else { - list( $file, $name ) = $this->parse_name( $args ); - - $this->status_single( $file, $name ); + $this->status_single( $args ); } } @@ -79,19 +76,6 @@ private function show_legend( $items ) { \WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); } - private function status_single( $file, $name ) { - $details = $this->get_details( $file ); - - $status = $this->format_status( $this->get_status( $file ), 'long' ); - - $version = $details[ 'Version' ]; - - if ( $this->has_update( $file ) ) - $version .= ' (%gUpdate available%n)'; - - $this->_status_single( $details, $name, $version, $status ); - } - function install( $args, $assoc_args ) { if ( empty( $args ) ) { \WP_CLI::line( "usage: wp $this->item_type install <slug>" ); @@ -195,7 +179,7 @@ protected function has_update( $slug ) { ) ); - private function format_status( $status, $format ) { + protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 189dad344..ea01f2a9a 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -28,6 +28,21 @@ function status( $args ) { parent::status( $args ); } + protected function status_single( $args ) { + list( $file, $name ) = $this->parse_name( $args ); + + $details = $this->get_details( $file ); + + $status = $this->format_status( $this->get_status( $file ), 'long' ); + + $version = $details[ 'Version' ]; + + if ( $this->has_update( $file ) ) + $version .= ' (%gUpdate available%n)'; + + $this->_status_single( $details, $name, $version, $status ); + } + protected function _status_single( $details, $name, $version, $status ) { WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); diff --git a/php/commands/theme.php b/php/commands/theme.php index f1faed149..26dbdad77 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -21,27 +21,28 @@ function status( $args ) { parent::status( $args ); } - protected function _status_single( $details, $name, $version, $status ) { - WP_CLI::line( 'Theme %9' . $name . '%n details:' ); - WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); + protected function status_single( $args ) { + $theme = $this->parse_name( $args ); + + $status = $this->format_status( $this->get_status( $theme ), 'long' ); + + $version = $theme->get('Version'); + if ( $this->has_update( $theme->get_stylesheet() ) ) + $version .= ' (%gUpdate available%n)'; + + WP_CLI::line( 'Theme %9' . $theme->get_stylesheet() . '%n details:' ); + WP_CLI::line( ' Name: ' . $theme->get('Name') ); WP_CLI::line( ' Status: ' . $status .'%n' ); WP_CLI::line( ' Version: ' . $version ); - WP_CLI::line( ' Author: ' . strip_tags( $details[ 'Author' ] ) ); + WP_CLI::line( ' Author: ' . $theme->get('Author') ); } protected function get_all_items() { return $this->get_item_list(); } - protected function get_status( $stylesheet ) { - if ( $this->is_active_theme( $stylesheet ) ) - return 'active'; - - return 'inactive'; - } - - protected function get_details( $stylesheet ) { - return wp_get_theme( $stylesheet ); + protected function get_status( $theme ) { + return ( $this->is_active_theme( $theme ) ) ? 'active' : 'inactive'; } /** @@ -50,23 +51,21 @@ protected function get_details( $stylesheet ) { * @synopsis <theme> */ public function activate( $args = array() ) { - list( $stylesheet, $child ) = $this->parse_name( $args ); - - $details = wp_get_theme( $stylesheet ); + $theme = $this->parse_name( $args ); - switch_theme( $child ); + switch_theme( $theme->get_stylesheet() ); - $name = $details['Title']; + $name = $theme->get('Name'); - if ( $this->is_active_theme( $stylesheet ) ) { + if ( $this->is_active_theme( $theme ) ) { WP_CLI::success( "Switched to '$name' theme." ); } else { WP_CLI::error( "Could not switch to '$name' theme." ); } } - private function is_active_theme( $stylesheet ) { - return dirname( $stylesheet ) == get_stylesheet_directory(); + private function is_active_theme( $theme ) { + return $theme->get_stylesheet_directory() == get_stylesheet_directory(); } /** @@ -78,11 +77,12 @@ function path( $args, $assoc_args ) { if ( empty( $args ) ) { $path = WP_CONTENT_DIR . '/themes'; } else { - list( $stylesheet, $name ) = $this->parse_name( $args ); - $path = $stylesheet; + $theme = $this->parse_name( $args ); + + $path = $theme->get_stylesheet_directory(); - if ( isset( $assoc_args['dir'] ) ) - $path = dirname( $path ); + if ( !isset( $assoc_args['dir'] ) ) + $path .= '/style.css'; } WP_CLI::line( $path ); @@ -109,7 +109,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * Else, if there's no update, it's either not installed, * or it's newer than what we've got. */ - } else if ( !is_readable( $this->get_stylesheet_path( $slug ) ) ) { + } else if ( !wp_get_theme( $slug )->exists() ) { WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); } else { @@ -126,14 +126,14 @@ protected function install_from_repo( $slug, $assoc_args ) { protected function get_item_list() { $items = array(); - foreach ( wp_get_themes() as $details ) { - $file = $this->get_stylesheet_path( $details['Stylesheet'] ); + foreach ( wp_get_themes() as $theme ) { + $file = $theme->get_stylesheet_directory(); $items[ $file ] = array( - 'name' => $details['Stylesheet'], - 'status' => $this->get_status( $file ), - 'update' => $this->has_update( $details['Stylesheet'] ), - 'update_id' => $details['Stylesheet'], + 'name' => $theme->get('Name'), + 'status' => $this->get_status( $theme ), + 'update' => $this->has_update( $theme->get_stylesheet() ), + 'update_id' => $theme->get_stylesheet(), ); } @@ -155,9 +155,9 @@ function install( $args, $assoc_args ) { * @synopsis <theme> [--version=<version>] */ function update( $args, $assoc_args ) { - list( $_, $name ) = $this->parse_name( $args ); + $theme = $this->parse_name( $args ); - parent::_update( $name ); + parent::_update( $theme->get_stylesheet() ); } /** @@ -176,9 +176,9 @@ function update_all( $args, $assoc_args ) { * @synopsis <theme> */ function delete( $args ) { - list( $file, $name ) = $this->parse_name( $args ); + $theme = $this->parse_name( $args ); - $r = delete_theme( $name ); + $r = delete_theme( $theme->get_stylesheet() ); if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); @@ -193,18 +193,14 @@ protected function parse_name( $args ) { $name = $args[0]; - $stylesheet = $this->get_stylesheet_path( $name ); + $theme = wp_get_theme( $name ); - if ( !is_readable( $stylesheet ) ) { + if ( !$theme->exists() ) { WP_CLI::error( "The theme '$name' could not be found." ); exit; } - return array( $stylesheet, $name ); - } - - protected function get_stylesheet_path( $theme ) { - return WP_CONTENT_DIR . '/themes/' . $theme . '/style.css'; + return $theme; } } From c902a180b5a199e13fdb0719b0ce818158c6c749 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 21:13:01 +0200 Subject: [PATCH 1348/5359] add theme updating scenario --- features/steps/basic_steps.php | 16 ++++++++++++++ features/theme.feature | 40 +++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 28551fb89..1691794a5 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -44,6 +44,22 @@ function ( $world ) { } ); +$steps->Given('/^a P2 theme zip$/', + function ( $world ) { + $zip_name = 'p2.1.0.1.zip'; + + $cache_dir = sys_get_temp_dir() . '/wp-cli-test-cache'; + $world->variables['THEME_ZIP'] = $cache_dir . '/' . $zip_name; + + $zip_url = 'http://wordpress.org/extend/themes/download/' . $zip_name; + + system( \WP_CLI\Utils\create_cmd( 'mkdir -p %s', $cache_dir ) ); + + system( \WP_CLI\Utils\create_cmd( 'curl -s %s > %s', $zip_url, + $world->variables['THEME_ZIP'] ) ); + } +); + $steps->When( '/^I run `wp`$/', function ( $world ) { $world->result = $world->run( '' ); diff --git a/features/theme.feature b/features/theme.feature index 6552e04ed..6b5ef6984 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -1,12 +1,5 @@ Feature: Manage WordPress themes - Scenario: Checking the theme list - Given WP install - - When I run `wp theme status` - Then it should run without errors - And STDOUT should not be empty - Scenario: Installing a theme Given WP install @@ -20,7 +13,7 @@ Feature: Manage WordPress themes Then it should run without errors And STDOUT should contain: """ - Theme p2 details: + Theme p2 details: Name: P2 """ @@ -47,3 +40,34 @@ Feature: Manage WordPress themes """ Error: The theme 'p2' could not be found. """ + + Scenario: Upgrading a theme + Given WP install + And a P2 theme zip + + When I run `wp theme install {THEME_ZIP}` + Then it should run without errors + + When I run `wp theme status` + Then it should run without errors + And STDOUT should contain: + """ + U = Update Available + """ + + When I run `wp theme status p2` + Then it should run without errors + And STDOUT should contain: + """ + Version: 1.0.1 (Update available) + """ + + When I run `wp theme update p2` + Then it should run without errors + + When I run `wp theme status p2` + Then it should run without errors + And STDOUT should not contain: + """ + (Update available) + """ From ba857d212c6e8a497e3abc4ae64f06908598a3dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 21:39:17 +0200 Subject: [PATCH 1349/5359] fix indentation for feature files --- features/plugin.feature | 18 +++++++++--------- features/theme.feature | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 0300fb252..dcd4034da 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -9,15 +9,15 @@ Feature: Manage WordPress plugins When I run `wp plugin status hello` Then it should run without errors - And STDOUT should contain: - """ - Plugin hello details: - Name: Hello Dolly - """ + And STDOUT should contain: + """ + Plugin hello details: + Name: Hello Dolly + """ When I run `wp plugin status non-existent-plugin` Then the return code should be 1 - And STDERR should contain: - """ - Error: The plugin 'non-existent-plugin' could not be found. - """ + And STDERR should contain: + """ + Error: The plugin 'non-existent-plugin' could not be found. + """ diff --git a/features/theme.feature b/features/theme.feature index 6b5ef6984..a60d22ed1 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -52,14 +52,14 @@ Feature: Manage WordPress themes Then it should run without errors And STDOUT should contain: """ - U = Update Available + U = Update Available """ When I run `wp theme status p2` Then it should run without errors And STDOUT should contain: """ - Version: 1.0.1 (Update available) + Version: 1.0.1 (Update available) """ When I run `wp theme update p2` @@ -69,5 +69,5 @@ Feature: Manage WordPress themes Then it should run without errors And STDOUT should not contain: """ - (Update available) + (Update available) """ From 83ec424ff3dae2e4994ae51f7c56f56f690b0cdd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 21:50:12 +0200 Subject: [PATCH 1350/5359] replace variables in expected output, not in current output --- features/steps/basic_steps.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 1691794a5..218326b12 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -105,9 +105,9 @@ function ( $world ) { $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { - $output = $world->replace_variables( $world->result->$stream ); + $output = $world->result->$stream; - $expected = (string) $expected; + $expected = $world->replace_variables( (string) $expected ); switch ( $action ) { From d862ebd563493bcf8610aa8400c860eb33a1c71e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 21:50:39 +0200 Subject: [PATCH 1351/5359] replace 'Given WP install' with 'Given a WP install' --- features/core.feature | 4 ++-- features/flags.feature | 8 ++++---- features/plugin.feature | 2 +- features/post.feature | 2 +- features/steps/basic_steps.php | 2 +- features/theme.feature | 4 ++-- features/user.feature | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/features/core.feature b/features/core.feature index fe5dbd395..d333fbaab 100644 --- a/features/core.feature +++ b/features/core.feature @@ -64,13 +64,13 @@ Feature: Manage WordPress installation And STDOUT should not be empty Scenario: Full install - Given WP install + Given a WP install When I run `wp core is-installed` Then it should run without errors Scenario: Custom wp-content directory - Given WP install + Given a WP install And custom wp-content directory When I run `wp plugin status hello` diff --git a/features/flags.feature b/features/flags.feature index 9ef0db43f..676729004 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -1,7 +1,7 @@ Feature: Global flags Scenario: Quiet run - Given WP install + Given a WP install When I run `wp` Then it should run without errors @@ -19,7 +19,7 @@ Feature: Global flags """ Scenario: Debug run - Given WP install + Given a WP install When I run `wp eval 'echo CONST_WITHOUT_QUOTES;'` Then it should run without errors @@ -36,7 +36,7 @@ Feature: Global flags """ Scenario: Setting the WP user - Given WP install + Given a WP install When I run `wp eval 'echo (int) is_user_logged_in();'` Then it should run without errors @@ -60,7 +60,7 @@ Feature: Global flags """ Scenario: Enabling/disabling color - Given WP install + Given a WP install When I run `wp --no-color non-existant-command` Then STDERR should be: diff --git a/features/plugin.feature b/features/plugin.feature index dcd4034da..88dbf0548 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -1,7 +1,7 @@ Feature: Manage WordPress plugins Scenario: Checking the plugin status - Given WP install + Given a WP install When I run `wp plugin status` Then it should run without errors diff --git a/features/post.feature b/features/post.feature index 2ecfe9b8d..af7999f42 100644 --- a/features/post.feature +++ b/features/post.feature @@ -1,7 +1,7 @@ Feature: Manage WordPress posts Scenario: Creating/updating/deleting posts - Given WP install + Given a WP install When I run `wp post create --post_title='Test post' --porcelain` Then it should run without errors diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 218326b12..6e48c3bb8 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -28,7 +28,7 @@ function ( $world ) { } ); -$steps->Given( '/^WP install$/', +$steps->Given( '/^a WP install$/', function ( $world ) { $world->create_db(); $world->create_empty_dir(); diff --git a/features/theme.feature b/features/theme.feature index a60d22ed1..086659d66 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -1,7 +1,7 @@ Feature: Manage WordPress themes Scenario: Installing a theme - Given WP install + Given a WP install When I run `wp theme install p2` Then it should run without errors @@ -42,7 +42,7 @@ Feature: Manage WordPress themes """ Scenario: Upgrading a theme - Given WP install + Given a WP install And a P2 theme zip When I run `wp theme install {THEME_ZIP}` diff --git a/features/user.feature b/features/user.feature index 0c68fd9cb..d1d034a9e 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,7 +1,7 @@ Feature: Manage WordPress users Scenario: Creating/updating/deleting users - Given WP install + Given a WP install When I run `wp user create testuser testuser@example.com --porcelain` Then it should run without errors @@ -22,7 +22,7 @@ Feature: Manage WordPress users Then it should run without errors Scenario: Generating users - Given WP install + Given a WP install # Delete all users When I run `wp user list --ids` From ed565f301c1112ba8e604e4843583c1c33195b3e Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 8 Mar 2013 21:44:14 +0100 Subject: [PATCH 1352/5359] Removed future wp filesystem --- php/commands/media.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index b61a28dd3..c8e74e00c 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -6,10 +6,6 @@ * @package wp-cli */ class Media_Command extends WP_CLI_Command { - - function __construct() { - WP_Filesystem(); - } /** * Regenerate thumbnail(s) From 285e6a2ff8a7568aea5878372a7722ed5d5b5f8c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 Mar 2013 22:44:29 +0200 Subject: [PATCH 1353/5359] don't allow deletion of the current theme WSODs are bad, mkay. --- php/commands/theme.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 26dbdad77..4f5a8dee9 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -178,6 +178,10 @@ function update_all( $args, $assoc_args ) { function delete( $args ) { $theme = $this->parse_name( $args ); + if ( $this->is_active_theme( $theme ) ) { + WP_CLI::error( "Can't delete the currently active theme." ); + } + $r = delete_theme( $theme->get_stylesheet() ); if ( is_wp_error( $r ) ) { From c7978365ccebaad852ac36627f386860acbb761d Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 8 Mar 2013 22:22:24 +0100 Subject: [PATCH 1354/5359] Put back the sprintf --- php/commands/media.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index c8e74e00c..383377948 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -40,7 +40,7 @@ function regenerate( $args, $assoc_args = array() ) { } $count = $images->post_count; - WP_CLI::line( "Found {$count} " . ngettext('image', 'images', $count) . " to regenerate." ); + WP_CLI::line( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); $not_found = array_diff( $args, $images->posts ); if( !empty($not_found) ) { @@ -51,7 +51,7 @@ function regenerate( $args, $assoc_args = array() ) { $this->_process_regeneration( $id ); } - WP_CLI::success( "Finished regenerating " . ngettext('the image', 'all images', $count) . "."); + WP_CLI::success( sprintf( 'Finished regenerating %1$s.', ngettext('the image', 'all images', $count) ) ); } private function _process_regeneration( $id ) { @@ -70,7 +70,7 @@ private function _process_regeneration( $id ) { return; } - WP_CLI::line( "Start processing of \"" . get_the_title( $image->ID ) . "\" (ID: {$image->ID})" ); + WP_CLI::line( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); $a_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); $a_file = explode( '.', $a_path[ count( $a_path ) - 1 ] ); @@ -130,7 +130,12 @@ private function _process_regeneration( $id ) { private function _not_found_message( $not_found_ids ){ $count = count($not_found_ids); - return "Unable to find the " . ngettext('image', 'images', $count) . " (" . implode(", ", $not_found_ids) . "). Are you sure " . ngettext('it', 'they', $count) . " " . ngettext('exist', 'exists', $count) . "?"; + return vsprintf( 'Unable to find the %1$s (%2$s). Are you sure %3$s %4$s?', array( + ngettext('image', 'images', $count), + implode(", ", $not_found_ids), + ngettext('it', 'they', $count), + ngettext('exists', 'exist', $count), + )); } } From da28c063a2150c0ecee0fcb045ddf489c9b14d4c Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 8 Mar 2013 22:25:26 +0100 Subject: [PATCH 1355/5359] Removed obsolete check --- php/commands/media.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 383377948..77c6a1075 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -57,12 +57,7 @@ function regenerate( $args, $assoc_args = array() ) { private function _process_regeneration( $id ) { $image = get_post( $id ); - - if ( !$image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) ) { - WP_CLI::warning( "{$image->post_title} - invalid image ID." ); - return; - } - + $fullsizepath = get_attached_file( $image->ID ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { From e2d0534e2abc0fd49269e0ddaded2e3fa8a579ff Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 15:31:08 +0000 Subject: [PATCH 1356/5359] Correct documentation for capability removal function --- php/commands/cap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index aea5a2f73..31004285c 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -47,7 +47,7 @@ public function add( $args ) { } /** - * Add capabilities to a given role. + * Remove capabilities from a given role. * * @synopsis <role> <cap>... */ From 8ac5bbfb4cd2a9c32d394c01da91cf578de3afb6 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 16:18:01 +0000 Subject: [PATCH 1357/5359] Add new roles command. Implements list, create, delete --- php/commands/roles.php | 88 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 php/commands/roles.php diff --git a/php/commands/roles.php b/php/commands/roles.php new file mode 100644 index 000000000..c7123d8a2 --- /dev/null +++ b/php/commands/roles.php @@ -0,0 +1,88 @@ +<?php + +/** + * Manage user roles. + * + * @package wp-cli + */ +class Roles_Command extends WP_CLI_Command { + + /** + * List one or all roles. + * + * @subcommand list + * @synopsis [<role-key>] + */ + public function _list( $args ) { + global $wp_roles; + + if ( isset ( $args[0] ) ) + $target_role = $args[0]; + else + $target_role = ''; + + foreach ( $wp_roles->roles as $key => $role ) { + if ( empty ( $target_role ) || $key == $target_role ) + WP_CLI::line( $role['name'] . " ($key)"); + } + } + + /** + * Create a new role. + * + * @subcommand create + * @synopsis <role-key> <role-name> + */ + public function _create( $args ) { + self::persistence_check(); + + $role_key = array_shift( $args ); + $role_name = array_shift( $args ); + + if ( empty ( $role_key ) || empty ( $role_name ) ) + WP_CLI::error( "Can't create role, insufficient information provided."); + + if ( ! add_role ( $role_key, $role_name ) ) + WP_CLI::error( "Role couldn't be created." ); + else + WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + + } + + /** + * Delete an existing role + * + * @subcommand delete + * @synopsis <role-key> + */ + public function _delete( $args ) { + + global $wp_roles; + + self::persistence_check(); + + $role_key = array_shift( $args ); + + if ( empty ( $role_key ) || ! isset ( $wp_roles->roles[$role_key] ) ) + WP_CLI::error( "Role key not provided, or is invalid." ); + + remove_role ( $role_key ); + + // Note: remove_role() doesn't indicate success or otherwise, so we have to + // check ourselves + if ( ! isset ( $wp_roles->roles[$role_key] ) ) + WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); + else + WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); + + } + + private static function persistence_check() { + global $wp_roles; + + if ( !$wp_roles->use_db ) + WP_CLI::error( "Role definitions are not persistent." ); + } +} + +WP_CLI::add_command( 'roles', 'Roles_Command' ); \ No newline at end of file From 70de7f4b857a4ee17422dc9e016a8ebb0c8fe035 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 20:25:58 +0000 Subject: [PATCH 1358/5359] Remove spaces before function calls --- php/commands/roles.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/php/commands/roles.php b/php/commands/roles.php index c7123d8a2..8372e3c99 100644 --- a/php/commands/roles.php +++ b/php/commands/roles.php @@ -16,13 +16,13 @@ class Roles_Command extends WP_CLI_Command { public function _list( $args ) { global $wp_roles; - if ( isset ( $args[0] ) ) + if ( isset( $args[0] ) ) $target_role = $args[0]; else $target_role = ''; foreach ( $wp_roles->roles as $key => $role ) { - if ( empty ( $target_role ) || $key == $target_role ) + if ( empty( $target_role ) || $key == $target_role ) WP_CLI::line( $role['name'] . " ($key)"); } } @@ -39,10 +39,10 @@ public function _create( $args ) { $role_key = array_shift( $args ); $role_name = array_shift( $args ); - if ( empty ( $role_key ) || empty ( $role_name ) ) + if ( empty( $role_key ) || empty( $role_name ) ) WP_CLI::error( "Can't create role, insufficient information provided."); - if ( ! add_role ( $role_key, $role_name ) ) + if ( ! add_role( $role_key, $role_name ) ) WP_CLI::error( "Role couldn't be created." ); else WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); @@ -63,14 +63,14 @@ public function _delete( $args ) { $role_key = array_shift( $args ); - if ( empty ( $role_key ) || ! isset ( $wp_roles->roles[$role_key] ) ) + if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) WP_CLI::error( "Role key not provided, or is invalid." ); - remove_role ( $role_key ); + remove_role( $role_key ); // Note: remove_role() doesn't indicate success or otherwise, so we have to // check ourselves - if ( ! isset ( $wp_roles->roles[$role_key] ) ) + if ( ! isset( $wp_roles->roles[$role_key] ) ) WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); else WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); From f8f388c291011a24941e850299079df9cc791138 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 20:33:55 +0000 Subject: [PATCH 1359/5359] Add man src files --- man-src/roles-create.txt | 16 ++++++++++++++++ man-src/roles-delete.txt | 12 ++++++++++++ man-src/roles-list.txt | 12 ++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 man-src/roles-create.txt create mode 100644 man-src/roles-delete.txt create mode 100644 man-src/roles-list.txt diff --git a/man-src/roles-create.txt b/man-src/roles-create.txt new file mode 100644 index 000000000..912f829ff --- /dev/null +++ b/man-src/roles-create.txt @@ -0,0 +1,16 @@ +## OPTIONS + +* <role-key>: + + The internal name of the role, e.g. editor + +* <role-name>: + + The publically visible name of the rule, e.g. Editor + +## EXAMPLES + + wp roles create approver Approver + + wp roles create productadmin "Product Administrator" + diff --git a/man-src/roles-delete.txt b/man-src/roles-delete.txt new file mode 100644 index 000000000..676e290fe --- /dev/null +++ b/man-src/roles-delete.txt @@ -0,0 +1,12 @@ +## OPTIONS + +* <role-key>: + + The internal name of the role, e.g. editor + +## EXAMPLES + + wp roles delete approver + + wp roles create productadmin + diff --git a/man-src/roles-list.txt b/man-src/roles-list.txt new file mode 100644 index 000000000..364c1fea9 --- /dev/null +++ b/man-src/roles-list.txt @@ -0,0 +1,12 @@ +## OPTIONS + +* [<role-key>]: + + Optional. A role to return. + +## EXAMPLES + + wp roles list + + wp roles list editor + From 70583a50febec04f415369634fbfd2ae00ce5dbd Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 20:34:40 +0000 Subject: [PATCH 1360/5359] Generated man files --- man/roles-create.1 | 35 +++++++++++++++++++++++++++++++++++ man/roles-delete.1 | 29 +++++++++++++++++++++++++++++ man/roles-list.1 | 29 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 man/roles-create.1 create mode 100644 man/roles-delete.1 create mode 100644 man/roles-list.1 diff --git a/man/roles-create.1 b/man/roles-create.1 new file mode 100644 index 000000000..19f92fe76 --- /dev/null +++ b/man/roles-create.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLES\-CREATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-roles\-create\fR \- Create a new role\. +. +.SH "SYNOPSIS" +wp roles create \fIrole\-key\fR \fIrole\-name\fR +. +.SH "OPTIONS" +. +.TP +\fIrole\-key\fR: +. +.IP +The internal name of the role, e\.g\. editor +. +.TP +\fIrole\-name\fR: +. +.IP +The publically visible name of the rule, e\.g\. Editor +. +.SH "EXAMPLES" +. +.nf + +wp roles create approver Approver + +wp roles create productadmin "Product Administrator" +. +.fi + diff --git a/man/roles-delete.1 b/man/roles-delete.1 new file mode 100644 index 000000000..5ed0e3444 --- /dev/null +++ b/man/roles-delete.1 @@ -0,0 +1,29 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLES\-DELETE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-roles\-delete\fR \- Delete an existing role +. +.SH "SYNOPSIS" +wp roles delete \fIrole\-key\fR +. +.SH "OPTIONS" +. +.TP +\fIrole\-key\fR: +. +.IP +The internal name of the role, e\.g\. editor +. +.SH "EXAMPLES" +. +.nf + +wp roles delete approver + +wp roles create productadmin +. +.fi + diff --git a/man/roles-list.1 b/man/roles-list.1 new file mode 100644 index 000000000..4a7f5a371 --- /dev/null +++ b/man/roles-list.1 @@ -0,0 +1,29 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLES\-LIST" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-roles\-list\fR \- List one or all roles\. +. +.SH "SYNOPSIS" +wp roles list [\fIrole\-key\fR] +. +.SH "OPTIONS" +. +.TP +[\fIrole\-key\fR]: +. +.IP +Optional\. A role to return\. +. +.SH "EXAMPLES" +. +.nf + +wp roles list + +wp roles list editor +. +.fi + From 15720e64ba83d1460eaf84bbb3a48056e5bb6ddf Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sat, 9 Mar 2013 20:37:40 +0000 Subject: [PATCH 1361/5359] Regenerated man page --- man/cap.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/cap.1 b/man/cap.1 index 5dfefa654..5e8c620f8 100644 --- a/man/cap.1 +++ b/man/cap.1 @@ -33,7 +33,7 @@ List capabilities for a given role\. \fBremove\fR: . .IP -Add capabilities to a given role\. +Remove capabilities from a given role\. . .SH "EXAMPLES" . From 39ee2d5e4e7c7a8b0907a6e8327a01730aaa7eac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Mar 2013 22:49:56 +0200 Subject: [PATCH 1362/5359] tests: switch to previous theme before deleting the current theme --- features/theme.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 086659d66..a6a57c252 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -24,6 +24,10 @@ Feature: Manage WordPress themes /themes/p2/style.css """ + When I run `wp option get stylesheet` + Then it should run without errors + And save STDOUT as {PREVIOUS_THEME} + When I run `wp theme activate p2` Then it should run without errors And STDOUT should contain: @@ -31,6 +35,10 @@ Feature: Manage WordPress themes Success: Switched to 'P2' theme. """ + When I run `wp theme activate {PREVIOUS_THEME}` + Then it should run without errors + And STDOUT should not be empty + When I run `wp theme delete p2` Then it should run without errors From 70e6ab3bbe7df257d035d63876de1b5cd3a75750 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Mar 2013 23:17:58 +0200 Subject: [PATCH 1363/5359] travis: add --prefer-source, in the hope of not reaching the Github API limit --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bb6c74de7..e72bb6c45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: before_script: # install dependencies - curl -sS https://getcomposer.org/installer | php - - php composer.phar install --dev --no-interaction + - php composer.phar install --dev --no-interaction --prefer-source # set up WP install - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ - mkdir -p $WP_CORE_DIR From e99b22dce52bf70187cf3755fd80ec69375bf3ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Mar 2013 23:21:20 +0200 Subject: [PATCH 1364/5359] travis: use pre-installed Composer binary --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e72bb6c45..294495c75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,7 @@ env: before_script: # install dependencies - - curl -sS https://getcomposer.org/installer | php - - php composer.phar install --dev --no-interaction --prefer-source + - composer install --dev --no-interaction --prefer-source # set up WP install - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ - mkdir -p $WP_CORE_DIR From 8e4b6b70c5826f89a91dc6ba2f178a24593f6285 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 21:55:52 +0000 Subject: [PATCH 1365/5359] s/roles/role/ --- man-src/{roles-create.txt => role-create.txt} | 4 ++-- man-src/{roles-delete.txt => role-delete.txt} | 4 ++-- man-src/{roles-list.txt => role-list.txt} | 4 ++-- php/commands/{roles.php => role.php} | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename man-src/{roles-create.txt => role-create.txt} (63%) rename man-src/{roles-delete.txt => role-delete.txt} (59%) rename man-src/{roles-list.txt => role-list.txt} (66%) rename php/commands/{roles.php => role.php} (95%) diff --git a/man-src/roles-create.txt b/man-src/role-create.txt similarity index 63% rename from man-src/roles-create.txt rename to man-src/role-create.txt index 912f829ff..6c7d2e523 100644 --- a/man-src/roles-create.txt +++ b/man-src/role-create.txt @@ -10,7 +10,7 @@ ## EXAMPLES - wp roles create approver Approver + wp role create approver Approver - wp roles create productadmin "Product Administrator" + wp role create productadmin "Product Administrator" diff --git a/man-src/roles-delete.txt b/man-src/role-delete.txt similarity index 59% rename from man-src/roles-delete.txt rename to man-src/role-delete.txt index 676e290fe..fafd2ac02 100644 --- a/man-src/roles-delete.txt +++ b/man-src/role-delete.txt @@ -6,7 +6,7 @@ ## EXAMPLES - wp roles delete approver + wp role delete approver - wp roles create productadmin + wp role delete productadmin diff --git a/man-src/roles-list.txt b/man-src/role-list.txt similarity index 66% rename from man-src/roles-list.txt rename to man-src/role-list.txt index 364c1fea9..563dd3a9c 100644 --- a/man-src/roles-list.txt +++ b/man-src/role-list.txt @@ -6,7 +6,7 @@ ## EXAMPLES - wp roles list + wp role list - wp roles list editor + wp role list editor diff --git a/php/commands/roles.php b/php/commands/role.php similarity index 95% rename from php/commands/roles.php rename to php/commands/role.php index 8372e3c99..785544ca6 100644 --- a/php/commands/roles.php +++ b/php/commands/role.php @@ -5,7 +5,7 @@ * * @package wp-cli */ -class Roles_Command extends WP_CLI_Command { +class Role_Command extends WP_CLI_Command { /** * List one or all roles. @@ -85,4 +85,4 @@ private static function persistence_check() { } } -WP_CLI::add_command( 'roles', 'Roles_Command' ); \ No newline at end of file +WP_CLI::add_command( 'role', 'Role_Command' ); \ No newline at end of file From 6db8d851944b690f5e93eee4d5f4ab2e8212f097 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 21:56:38 +0000 Subject: [PATCH 1366/5359] function rename, and remove unneeded @subcommand declarations --- php/commands/role.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 785544ca6..0846352d7 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -30,10 +30,9 @@ public function _list( $args ) { /** * Create a new role. * - * @subcommand create * @synopsis <role-key> <role-name> */ - public function _create( $args ) { + public function create( $args ) { self::persistence_check(); $role_key = array_shift( $args ); @@ -52,10 +51,9 @@ public function _create( $args ) { /** * Delete an existing role * - * @subcommand delete * @synopsis <role-key> */ - public function _delete( $args ) { + public function delete( $args ) { global $wp_roles; From c817971bbe17b381ad4362e7fafc31fe0cbbc1ce Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 21:57:13 +0000 Subject: [PATCH 1367/5359] Doc fix --- php/commands/role.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 0846352d7..e70f11fff 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -49,7 +49,7 @@ public function create( $args ) { } /** - * Delete an existing role + * Delete an existing role. * * @synopsis <role-key> */ From 6ab3a58e9fd9fe1e4661f82e59bbf12ea5f3ce9f Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 22:07:43 +0000 Subject: [PATCH 1368/5359] Correct typo in docs --- man-src/role-create.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man-src/role-create.txt b/man-src/role-create.txt index 6c7d2e523..d041b245a 100644 --- a/man-src/role-create.txt +++ b/man-src/role-create.txt @@ -6,7 +6,7 @@ * <role-name>: - The publically visible name of the rule, e.g. Editor + The publically visible name of the role, e.g. Editor ## EXAMPLES From dc11141b56e93a1dfa94bad6c00090721878cb1c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 00:11:02 +0200 Subject: [PATCH 1369/5359] WP_Theme was introduced in WP 3.4, but switch_theme() still requires two parameters until WP 3.5 --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 4f5a8dee9..70d8dad2e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -53,7 +53,7 @@ protected function get_status( $theme ) { public function activate( $args = array() ) { $theme = $this->parse_name( $args ); - switch_theme( $theme->get_stylesheet() ); + switch_theme( $theme->get_template(), $theme->get_stylesheet() ); $name = $theme->get('Name'); From 0d0febabe50144fb001a9f00ed771d2c5d7484b4 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 22:37:27 +0000 Subject: [PATCH 1370/5359] Remove old versions of generated man files --- man/roles-create.1 | 35 ----------------------------------- man/roles-delete.1 | 29 ----------------------------- man/roles-list.1 | 29 ----------------------------- 3 files changed, 93 deletions(-) delete mode 100644 man/roles-create.1 delete mode 100644 man/roles-delete.1 delete mode 100644 man/roles-list.1 diff --git a/man/roles-create.1 b/man/roles-create.1 deleted file mode 100644 index 19f92fe76..000000000 --- a/man/roles-create.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLES\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-roles\-create\fR \- Create a new role\. -. -.SH "SYNOPSIS" -wp roles create \fIrole\-key\fR \fIrole\-name\fR -. -.SH "OPTIONS" -. -.TP -\fIrole\-key\fR: -. -.IP -The internal name of the role, e\.g\. editor -. -.TP -\fIrole\-name\fR: -. -.IP -The publically visible name of the rule, e\.g\. Editor -. -.SH "EXAMPLES" -. -.nf - -wp roles create approver Approver - -wp roles create productadmin "Product Administrator" -. -.fi - diff --git a/man/roles-delete.1 b/man/roles-delete.1 deleted file mode 100644 index 5ed0e3444..000000000 --- a/man/roles-delete.1 +++ /dev/null @@ -1,29 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLES\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-roles\-delete\fR \- Delete an existing role -. -.SH "SYNOPSIS" -wp roles delete \fIrole\-key\fR -. -.SH "OPTIONS" -. -.TP -\fIrole\-key\fR: -. -.IP -The internal name of the role, e\.g\. editor -. -.SH "EXAMPLES" -. -.nf - -wp roles delete approver - -wp roles create productadmin -. -.fi - diff --git a/man/roles-list.1 b/man/roles-list.1 deleted file mode 100644 index 4a7f5a371..000000000 --- a/man/roles-list.1 +++ /dev/null @@ -1,29 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLES\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-roles\-list\fR \- List one or all roles\. -. -.SH "SYNOPSIS" -wp roles list [\fIrole\-key\fR] -. -.SH "OPTIONS" -. -.TP -[\fIrole\-key\fR]: -. -.IP -Optional\. A role to return\. -. -.SH "EXAMPLES" -. -.nf - -wp roles list - -wp roles list editor -. -.fi - From efe9af065e7bc31ceb3833add248849d71e5784e Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 22:38:37 +0000 Subject: [PATCH 1371/5359] role list just lists all roles, no args --- man-src/role-list.txt | 9 --------- php/commands/role.php | 9 +-------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/man-src/role-list.txt b/man-src/role-list.txt index 563dd3a9c..dd144391f 100644 --- a/man-src/role-list.txt +++ b/man-src/role-list.txt @@ -1,12 +1,3 @@ -## OPTIONS - -* [<role-key>]: - - Optional. A role to return. - ## EXAMPLES wp role list - - wp role list editor - diff --git a/php/commands/role.php b/php/commands/role.php index e70f11fff..b9419d27a 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -8,21 +8,14 @@ class Role_Command extends WP_CLI_Command { /** - * List one or all roles. + * List all roles. * * @subcommand list - * @synopsis [<role-key>] */ public function _list( $args ) { global $wp_roles; - if ( isset( $args[0] ) ) - $target_role = $args[0]; - else - $target_role = ''; - foreach ( $wp_roles->roles as $key => $role ) { - if ( empty( $target_role ) || $key == $target_role ) WP_CLI::line( $role['name'] . " ($key)"); } } From 9352f057e8e15b7b1627976b909567faff712785 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 22:39:07 +0000 Subject: [PATCH 1372/5359] Add role exists comand --- man-src/role-exists.txt | 16 ++++++++++++++++ php/commands/role.php | 15 +++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 man-src/role-exists.txt diff --git a/man-src/role-exists.txt b/man-src/role-exists.txt new file mode 100644 index 000000000..aac999737 --- /dev/null +++ b/man-src/role-exists.txt @@ -0,0 +1,16 @@ +## OPTIONS + +* <role-key>: + + The internal name of the role, e.g. editor + + +##DESCRIPTION + +Will return 0 if the role exists, 1 if it does not. + + +## EXAMPLES + + wp role exists editor + diff --git a/php/commands/role.php b/php/commands/role.php index b9419d27a..11754e607 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -20,6 +20,21 @@ public function _list( $args ) { } } + /** + * Check if a role exists. + * Will return 0 if the role exists, 1 if it does not. + * + * @subcommand exists + * @synopsis <role-key> + */ + public function _exists( $args ) { + global $wp_roles; + + if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { + WP_CLI::error( "Role not found." ); + } + } + /** * Create a new role. * From 94088d4e3c4ca8a226ef1562ed66d46df6deff4f Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Sun, 10 Mar 2013 22:40:04 +0000 Subject: [PATCH 1373/5359] Regenerate man files --- man/role-create.1 | 35 +++++++++++++++++++++++++++++++++++ man/role-delete.1 | 29 +++++++++++++++++++++++++++++ man/role-exists.1 | 30 ++++++++++++++++++++++++++++++ man/role-list.1 | 19 +++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 man/role-create.1 create mode 100644 man/role-delete.1 create mode 100644 man/role-exists.1 create mode 100644 man/role-list.1 diff --git a/man/role-create.1 b/man/role-create.1 new file mode 100644 index 000000000..4737ed2b0 --- /dev/null +++ b/man/role-create.1 @@ -0,0 +1,35 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLE\-CREATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-role\-create\fR \- Create a new role\. +. +.SH "SYNOPSIS" +wp role create \fIrole\-key\fR \fIrole\-name\fR +. +.SH "OPTIONS" +. +.TP +\fIrole\-key\fR: +. +.IP +The internal name of the role, e\.g\. editor +. +.TP +\fIrole\-name\fR: +. +.IP +The publically visible name of the role, e\.g\. Editor +. +.SH "EXAMPLES" +. +.nf + +wp role create approver Approver + +wp role create productadmin "Product Administrator" +. +.fi + diff --git a/man/role-delete.1 b/man/role-delete.1 new file mode 100644 index 000000000..02375d369 --- /dev/null +++ b/man/role-delete.1 @@ -0,0 +1,29 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLE\-DELETE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-role\-delete\fR \- Delete an existing role\. +. +.SH "SYNOPSIS" +wp role delete \fIrole\-key\fR +. +.SH "OPTIONS" +. +.TP +\fIrole\-key\fR: +. +.IP +The internal name of the role, e\.g\. editor +. +.SH "EXAMPLES" +. +.nf + +wp role delete approver + +wp role delete productadmin +. +.fi + diff --git a/man/role-exists.1 b/man/role-exists.1 new file mode 100644 index 000000000..8478a971f --- /dev/null +++ b/man/role-exists.1 @@ -0,0 +1,30 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLE\-EXISTS" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-role\-exists\fR \- Check if a role exists\. +. +.SH "SYNOPSIS" +wp role exists \fIrole\-key\fR +. +.SH "OPTIONS" +. +.TP +\fIrole\-key\fR: +. +.IP +The internal name of the role, e\.g\. editor +. +.SH "DESCRIPTION" +Will return 0 if the role exists, 1 if it does not\. +. +.SH "EXAMPLES" +. +.nf + +wp role exists editor +. +.fi + diff --git a/man/role-list.1 b/man/role-list.1 new file mode 100644 index 000000000..7998c7010 --- /dev/null +++ b/man/role-list.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-ROLE\-LIST" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-role\-list\fR \- List all roles\. +. +.SH "SYNOPSIS" +wp role list +. +.SH "EXAMPLES" +. +.nf + +wp role list +. +.fi + From 7f20dc1ca645817351901abd595574b06369a0e3 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Mon, 11 Mar 2013 07:32:40 +0000 Subject: [PATCH 1374/5359] Convert indents to be spaces consistently --- man-src/role-create.txt | 5 +- man-src/role-delete.txt | 4 +- man-src/role-exists.txt | 2 +- man-src/role-list.txt | 2 +- php/commands/role.php | 164 ++++++++++++++++++++-------------------- 5 files changed, 88 insertions(+), 89 deletions(-) diff --git a/man-src/role-create.txt b/man-src/role-create.txt index d041b245a..dde7db553 100644 --- a/man-src/role-create.txt +++ b/man-src/role-create.txt @@ -2,7 +2,7 @@ * <role-key>: - The internal name of the role, e.g. editor + The internal name of the role, e.g. editor * <role-name>: @@ -12,5 +12,4 @@ wp role create approver Approver - wp role create productadmin "Product Administrator" - + wp role create productadmin "Product Administrator" diff --git a/man-src/role-delete.txt b/man-src/role-delete.txt index fafd2ac02..f8519240d 100644 --- a/man-src/role-delete.txt +++ b/man-src/role-delete.txt @@ -2,11 +2,11 @@ * <role-key>: - The internal name of the role, e.g. editor + The internal name of the role, e.g. editor ## EXAMPLES wp role delete approver - wp role delete productadmin + wp role delete productadmin diff --git a/man-src/role-exists.txt b/man-src/role-exists.txt index aac999737..afd32a5a0 100644 --- a/man-src/role-exists.txt +++ b/man-src/role-exists.txt @@ -2,7 +2,7 @@ * <role-key>: - The internal name of the role, e.g. editor + The internal name of the role, e.g. editor ##DESCRIPTION diff --git a/man-src/role-list.txt b/man-src/role-list.txt index dd144391f..6bc9ed2a3 100644 --- a/man-src/role-list.txt +++ b/man-src/role-list.txt @@ -1,3 +1,3 @@ ## EXAMPLES - wp role list + wp role list diff --git a/php/commands/role.php b/php/commands/role.php index 11754e607..20c3833a4 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -7,88 +7,88 @@ */ class Role_Command extends WP_CLI_Command { - /** - * List all roles. - * - * @subcommand list - */ - public function _list( $args ) { - global $wp_roles; - - foreach ( $wp_roles->roles as $key => $role ) { - WP_CLI::line( $role['name'] . " ($key)"); - } - } - - /** - * Check if a role exists. - * Will return 0 if the role exists, 1 if it does not. - * - * @subcommand exists - * @synopsis <role-key> - */ - public function _exists( $args ) { - global $wp_roles; - - if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - WP_CLI::error( "Role not found." ); - } - } - - /** - * Create a new role. - * - * @synopsis <role-key> <role-name> - */ - public function create( $args ) { - self::persistence_check(); - - $role_key = array_shift( $args ); - $role_name = array_shift( $args ); - - if ( empty( $role_key ) || empty( $role_name ) ) - WP_CLI::error( "Can't create role, insufficient information provided."); - - if ( ! add_role( $role_key, $role_name ) ) - WP_CLI::error( "Role couldn't be created." ); - else - WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); - - } - - /** - * Delete an existing role. - * - * @synopsis <role-key> - */ - public function delete( $args ) { - - global $wp_roles; - - self::persistence_check(); - - $role_key = array_shift( $args ); - - if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::error( "Role key not provided, or is invalid." ); - - remove_role( $role_key ); - - // Note: remove_role() doesn't indicate success or otherwise, so we have to - // check ourselves - if ( ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); - else - WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); - - } - - private static function persistence_check() { - global $wp_roles; - - if ( !$wp_roles->use_db ) - WP_CLI::error( "Role definitions are not persistent." ); - } + /** + * List all roles. + * + * @subcommand list + */ + public function _list( $args ) { + global $wp_roles; + + foreach ( $wp_roles->roles as $key => $role ) { + WP_CLI::line( $role['name'] . " ($key)"); + } + } + + /** + * Check if a role exists. + * Will return 0 if the role exists, 1 if it does not. + * + * @subcommand exists + * @synopsis <role-key> + */ + public function _exists( $args ) { + global $wp_roles; + + if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { + WP_CLI::error( "Role not found." ); + } + } + + /** + * Create a new role. + * + * @synopsis <role-key> <role-name> + */ + public function create( $args ) { + self::persistence_check(); + + $role_key = array_shift( $args ); + $role_name = array_shift( $args ); + + if ( empty( $role_key ) || empty( $role_name ) ) + WP_CLI::error( "Can't create role, insufficient information provided."); + + if ( ! add_role( $role_key, $role_name ) ) + WP_CLI::error( "Role couldn't be created." ); + else + WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + + } + + /** + * Delete an existing role. + * + * @synopsis <role-key> + */ + public function delete( $args ) { + + global $wp_roles; + + self::persistence_check(); + + $role_key = array_shift( $args ); + + if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) + WP_CLI::error( "Role key not provided, or is invalid." ); + + remove_role( $role_key ); + + // Note: remove_role() doesn't indicate success or otherwise, so we have to + // check ourselves + if ( ! isset( $wp_roles->roles[$role_key] ) ) + WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); + else + WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); + + } + + private static function persistence_check() { + global $wp_roles; + + if ( !$wp_roles->use_db ) + WP_CLI::error( "Role definitions are not persistent." ); + } } WP_CLI::add_command( 'role', 'Role_Command' ); \ No newline at end of file From 895327aacffb28cb16f40c134e5f5202e69a418f Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Mon, 11 Mar 2013 07:36:31 +0000 Subject: [PATCH 1375/5359] Make role exists produce no output --- php/commands/role.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 20c3833a4..7d2046eab 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -31,7 +31,7 @@ public function _exists( $args ) { global $wp_roles; if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - WP_CLI::error( "Role not found." ); + exit(1); } } From 9bbec43bf39507846e01dd1dc1a933576d0aff02 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Mon, 11 Mar 2013 07:36:57 +0000 Subject: [PATCH 1376/5359] s/_exists/exists --- php/commands/role.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 7d2046eab..2e1237586 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -24,10 +24,9 @@ public function _list( $args ) { * Check if a role exists. * Will return 0 if the role exists, 1 if it does not. * - * @subcommand exists * @synopsis <role-key> */ - public function _exists( $args ) { + public function exists( $args ) { global $wp_roles; if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { From bd357e02a8bec1ebf76d0a88e973159f093648bd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 09:51:26 +0200 Subject: [PATCH 1377/5359] clarify documentation for `role exists`. see #350 --- man-src/role-exists.txt | 2 +- man/role-exists.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/role-exists.txt b/man-src/role-exists.txt index afd32a5a0..28a8ee0a5 100644 --- a/man-src/role-exists.txt +++ b/man-src/role-exists.txt @@ -7,7 +7,7 @@ ##DESCRIPTION -Will return 0 if the role exists, 1 if it does not. +Will exit with status 0 if the role exists, 1 if it does not. ## EXAMPLES diff --git a/man/role-exists.1 b/man/role-exists.1 index 8478a971f..7db3baa31 100644 --- a/man/role-exists.1 +++ b/man/role-exists.1 @@ -18,7 +18,7 @@ wp role exists \fIrole\-key\fR The internal name of the role, e\.g\. editor . .SH "DESCRIPTION" -Will return 0 if the role exists, 1 if it does not\. +Will exit with status 0 if the role exists, 1 if it does not\. . .SH "EXAMPLES" . From c444a0709dbe71c6607cab3da2106d2b7e576cf0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 10:16:33 +0200 Subject: [PATCH 1378/5359] download WP from wordpress.org Hopefully, it's more reliable than Github's tarball service. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 294495c75..eaf97a25e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ php: - 5.4 env: - - WP_VERSION=master WP_MULTISITE=0 - - WP_VERSION=master WP_MULTISITE=1 + - WP_VERSION=latest WP_MULTISITE=0 + - WP_VERSION=latest WP_MULTISITE=1 - WP_VERSION=3.5.1 WP_MULTISITE=0 - WP_VERSION=3.5.1 WP_MULTISITE=1 - WP_VERSION=3.4.2 WP_MULTISITE=0 @@ -18,7 +18,7 @@ before_script: # set up WP install - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ - mkdir -p $WP_CORE_DIR - - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION + - wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/wordpress-$WP_VERSION.tar.gz - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR # set up database - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot From 12918e6b3543bb85e9ad36c991b56e7b063c8e16 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 10:19:16 +0200 Subject: [PATCH 1379/5359] travis: latest = 3.5.1 at the moment --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index eaf97a25e..5ccd5656b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ php: env: - WP_VERSION=latest WP_MULTISITE=0 - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.5.1 WP_MULTISITE=0 - - WP_VERSION=3.5.1 WP_MULTISITE=1 - WP_VERSION=3.4.2 WP_MULTISITE=0 - WP_VERSION=3.4.2 WP_MULTISITE=1 From 5b6efb9d2cb3416a51ef8efe79bdfcfe3258218a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Mar 2013 22:53:16 +0200 Subject: [PATCH 1380/5359] don't pretend we're in WP_ADMIN anymore --- php/WP_CLI/Runner.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e4d04c266..b7da8954c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -274,10 +274,6 @@ public function before_wp_load() { Utils\set_url_params( 'http://example.com' ); } } - - // Pretend we're in WP_ADMIN - define( 'WP_ADMIN', true ); - $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; } private function cmd_starts_with( $prefix ) { From bc40251e8bbdf2019acce104d9ab7c9193d001e0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 13:44:07 +0200 Subject: [PATCH 1381/5359] remove utils/local-build. closes #353 --- utils/local-build | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100755 utils/local-build diff --git a/utils/local-build b/utils/local-build deleted file mode 100755 index 9d92ea875..000000000 --- a/utils/local-build +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -if [ "$BASH_SOURCE" = "$0" ]; then - echo "This file should not be executed. It should be sourced into your current shell like this:" - echo - echo "source $BASH_SOURCE" - echo - echo "Add the above line to your .bashrc or .bash_profile to have this environment set up" - echo "automatically when you log in." - exit 1 -fi - -[ -f composer.phar ] || curl -sS https://getcomposer.org/installer | php - -[ -d vendor/ ] || php composer.phar install - -DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd) - -alias wp='$DIR/../bin/wp' - -. $DIR/wp-completion.bash From d19d31871f10f9b768e7f161f0fd7eb623085199 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 18:32:38 +0200 Subject: [PATCH 1382/5359] handle wpdb error ourselves, instead of waiting for dead_db() --- php/wp-settings-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index dd64be7d3..12321c11a 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -61,6 +61,10 @@ // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); +// WP-CLI: Handle db error ourselves, instead of waiting for dead_db() +if ( !empty( $wpdb->error ) ) + wp_die( $wpdb->error ); + // Set the database table prefix and the format specifiers for database table columns. $GLOBALS['table_prefix'] = $table_prefix; wp_set_wpdb_vars(); From c9cf0ff29072ce5f463f2329631f287c80cfaa58 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 19:36:42 +0200 Subject: [PATCH 1383/5359] minor cleanup in Runner.php --- php/WP_CLI/Runner.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b7da8954c..93ffbae1b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -139,12 +139,20 @@ private static function set_url( $assoc_args ) { } } + private function cmd_starts_with( $prefix ) { + return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); + } + + private function _run_command() { + WP_CLI::run_command( $this->arguments, $this->assoc_args ); + } + /** * Returns wp-config.php code, skipping the loading of wp-settings.php * * @return string */ - function get_wp_config_code() { + public function get_wp_config_code() { $wp_config_path = Utils\locate_wp_config(); $replacements = array( @@ -276,18 +284,14 @@ public function before_wp_load() { } } - private function cmd_starts_with( $prefix ) { - return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); - } - - function after_wp_config_load() { + public function after_wp_config_load() { if ( isset( $this->config['debug'] ) ) { if ( !defined( 'WP_DEBUG' ) ) define( 'WP_DEBUG', true ); } } - function after_wp_load() { + public function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); Utils\set_user( $this->config ); @@ -310,8 +314,4 @@ function after_wp_load() { $this->_run_command(); } - - private function _run_command() { - WP_CLI::run_command( $this->arguments, $this->assoc_args ); - } } From 5264d7c30b81dcf9dfc300d1229969183fa78a0d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 20:20:38 +0200 Subject: [PATCH 1384/5359] add initial test case --- features/help.feature | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 features/help.feature diff --git a/features/help.feature b/features/help.feature new file mode 100644 index 000000000..4c8077e16 --- /dev/null +++ b/features/help.feature @@ -0,0 +1,6 @@ +Feature: Get help about WP-CLI commands + + Scenario: Empty dir + Given an empty directory + When I run `wp help core` + Then it should run without errors From d6c10fc4fbe91a0c2c90bfdf44ae312255d3ed7a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 23:25:25 +0200 Subject: [PATCH 1385/5359] make get_command_file() a method of RootCommand It's only used there and it's very unlikely to be needed elsewhere. --- php/WP_CLI/Dispatcher/RootCommand.php | 12 +++++++++++- php/utils.php | 10 ---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index e1db3ce16..0da342d74 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -125,9 +125,19 @@ protected function load_all_commands() { } } + protected static function get_command_file( $command ) { + $path = WP_CLI_ROOT . "/commands/$command.php"; + + if ( !is_readable( $path ) ) { + return false; + } + + return $path; + } + protected function load_command( $command ) { if ( !isset( $this->subcommands[ $command ] ) ) { - if ( $path = \WP_CLI\Utils\get_command_file( $command ) ) + if ( $path = self::get_command_file( $command ) ) include $path; } diff --git a/php/utils.php b/php/utils.php index 451085e7e..26ed76c23 100644 --- a/php/utils.php +++ b/php/utils.php @@ -112,16 +112,6 @@ function create_cmd( $cmd ) { return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); } -function get_command_file( $command ) { - $path = WP_CLI_ROOT . "/commands/$command.php"; - - if ( !is_readable( $path ) ) { - return false; - } - - return $path; -} - /** * Sets the appropriate $_SERVER keys based on a given string * From 6324b4219e1d29f24f8ae2d44aeb0db8b15f2f75 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 11 Mar 2013 23:59:03 +0200 Subject: [PATCH 1386/5359] add show_help_early() --- php/WP_CLI/Runner.php | 23 ++++++++++++++++++++++- php/commands/help.php | 35 +++-------------------------------- php/man.php | 26 ++++++++++++++++++++++++++ php/utils.php | 11 +++++++++++ 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 93ffbae1b..b18600a25 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -140,7 +140,7 @@ private static function set_url( $assoc_args ) { } private function cmd_starts_with( $prefix ) { - return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); + return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } private function _run_command() { @@ -177,6 +177,20 @@ public function get_wp_config_code() { return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); } + private static function show_help_early( $args ) { + if ( \WP_CLI\Man\maybe_show_manpage( $args ) ) + return true; + + $command = WP_CLI\Utils\find_subcommand( $args ); + + if ( $command ) { + $command->show_usage(); + return true; + } + + return false; + } + public function before_wp_load() { $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -238,6 +252,13 @@ public function before_wp_load() { $_SERVER['DOCUMENT_ROOT'] = getcwd(); + // First try at showing man page + if ( $this->cmd_starts_with( array( 'help' ) ) ) { + if ( self::show_help_early( array_slice( $this->arguments, 1 ) ) ) { + exit; + } + } + // Handle --path self::set_wp_root( $this->config ); diff --git a/php/commands/help.php b/php/commands/help.php index a875f7a28..ef1eded1a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -10,45 +10,16 @@ class Help_Command extends WP_CLI_Command { * @synopsis [<command>] */ function __invoke( $args ) { - self::maybe_load_man_page( $args ); + \WP_CLI\Man\maybe_show_manpage( $args ); - $arg_copy = $args; - - $command = \WP_CLI::$root; - - while ( !empty( $args ) && $command && $command instanceof CommandContainer ) { - $command = $command->find_subcommand( $args ); - } + $command = WP_CLI\Utils\find_subcommand( $args ); if ( !$command ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $arg_copy[0] ) ); + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); } $command->show_usage(); } - - private static function maybe_load_man_page( $args ) { - $man_file = \WP_CLI\Man\get_file_name( $args ); - - foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { - $man_path = $dest_dir . $man_file; - - if ( is_readable( $man_path ) ) { - self::show_manpage( $man_path ); - } - } - } - - private static function show_manpage( $path ) { - // man can't read phar://, so need to copy to a temporary file - $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); - - copy( $path, $tmp_path ); - - WP_CLI::launch( "man $tmp_path" ); - - unlink( $tmp_path ); - } } WP_CLI::add_command( 'help', new Help_Command ); diff --git a/php/man.php b/php/man.php index e2578fc8f..0d42cbfd0 100644 --- a/php/man.php +++ b/php/man.php @@ -119,3 +119,29 @@ function call_ronn( $markdown, $dest ) { \WP_CLI::line( "generated " . basename( $dest ) ); } +function show_manpage( $path ) { + // man can't read phar://, so need to copy to a temporary file + $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); + + copy( $path, $tmp_path ); + + \WP_CLI::launch( "man $tmp_path" ); + + unlink( $tmp_path ); +} + +function maybe_show_manpage( $args ) { + $man_file = get_file_name( $args ); + + foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { + $man_path = $dest_dir . $man_file; + + if ( is_readable( $man_path ) ) { + show_manpage( $man_path ); + return true; + } + } + + return false; +} + diff --git a/php/utils.php b/php/utils.php index 26ed76c23..5a2718636 100644 --- a/php/utils.php +++ b/php/utils.php @@ -316,3 +316,14 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { return $output; } + +function find_subcommand( $args ) { + $command = \WP_CLI::$root; + + while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { + $command = $command->find_subcommand( $args ); + } + + return $command; +} + From 98431fbd44f09bb75fe4de6b927b4acd369d8e30 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 00:07:35 +0200 Subject: [PATCH 1387/5359] add more usages to help.feature --- features/help.feature | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/features/help.feature b/features/help.feature index 4c8077e16..e5b216c58 100644 --- a/features/help.feature +++ b/features/help.feature @@ -2,5 +2,24 @@ Feature: Get help about WP-CLI commands Scenario: Empty dir Given an empty directory + + When I run `wp help` + Then it should run without errors + And STDOUT should contain: + """ + Available commands: + """ + When I run `wp help core` Then it should run without errors + And STDOUT should contain: + """ + usage: + """ + + When I run `wp help core download` + Then it should run without errors + And STDOUT should contain: + """ + WP-CORE-DOWNLOAD(1) + """ From 73c306dd251748828e3114d6c1c2f443b698281e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 01:12:27 +0200 Subject: [PATCH 1388/5359] fix E_STRICT error in CommandWithDBObject::create() signature --- php/WP_CLI/CommandWithDBObject.php | 2 +- php/commands/post.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 773f81d44..fa735be9e 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -13,7 +13,7 @@ abstract protected function _create( $params ); abstract protected function _update( $params ); abstract protected function _delete( $obj_id, $assoc_args ); - public function create( $assoc_args ) { + public function create( $args, $assoc_args ) { unset( $assoc_args['ID'] ); $obj_id = $this->_create( $assoc_args ); diff --git a/php/commands/post.php b/php/commands/post.php index 9073c4ed5..028afbce0 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -26,8 +26,8 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = file_get_contents( $readfile ); } - if ( isset( $assoc_args['edit'] ) ) { + if ( isset( $assoc_args['edit'] ) ) { $input = ( isset( $assoc_args['post_content'] ) ) ? $assoc_args['post_content'] : ''; @@ -35,9 +35,9 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = $output; else $assoc_args['post_content'] = $input; - } - parent::create( $assoc_args ); + + parent::create( $args, $assoc_args ); } protected function _create( $params ) { From 4fbdd4c0b285c6584f350bc469105d04784c3cef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 01:52:22 +0200 Subject: [PATCH 1389/5359] s/existant/existent/ --- features/flags.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 676729004..f2020b901 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -62,13 +62,13 @@ Feature: Global flags Scenario: Enabling/disabling color Given a WP install - When I run `wp --no-color non-existant-command` + When I run `wp --no-color non-existent-command` Then STDERR should be: """ - Error: 'non-existant-command' is not a registered wp command. See 'wp help'. + Error: 'non-existent-command' is not a registered wp command. See 'wp help'. """ - When I run `wp --color non-existant-command` + When I run `wp --color non-existent-command` Then STDERR should contain: """ [31;1mError: From d6a26bf156cafb3b5cce986c2134f8c87e65c699 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 01:53:49 +0200 Subject: [PATCH 1390/5359] add test for unknown command --- features/help.feature | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/help.feature b/features/help.feature index e5b216c58..53dfbb896 100644 --- a/features/help.feature +++ b/features/help.feature @@ -23,3 +23,6 @@ Feature: Get help about WP-CLI commands """ WP-CORE-DOWNLOAD(1) """ + + When I run `wp help non-existent-command` + Then the return code should be 1 From 46e2c301de2c0091be1957ed5f0bb9178c15b69e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 02:26:29 +0200 Subject: [PATCH 1391/5359] test getting help for a third-party command --- features/bootstrap/FeatureContext.php | 15 +++++++++++++++ features/help.feature | 15 ++++++++++++++- features/steps/basic_steps.php | 18 ++++++++++++------ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d45f89555..8fb9912b2 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -69,6 +69,21 @@ public function get_path( $file ) { return $this->install_dir . '/' . $file; } + public function get_cache_path( $file ) { + static $path; + + if ( !$path ) { + $path = sys_get_temp_dir() . '/wp-cli-test-cache'; + system( \WP_CLI\Utils\create_cmd( 'mkdir -p %s', $path ) ); + } + + return $path . '/' . $file; + } + + public function download_file( $url, $path ) { + system( \WP_CLI\Utils\create_cmd( 'curl -sSL %s > %s', $url, $path ) ); + } + private static function run_sql( $sql ) { $dbuser = self::$db_settings['dbuser']; $dbpass = self::$db_settings['dbpass']; diff --git a/features/help.feature b/features/help.feature index 53dfbb896..432eadf00 100644 --- a/features/help.feature +++ b/features/help.feature @@ -14,7 +14,7 @@ Feature: Get help about WP-CLI commands Then it should run without errors And STDOUT should contain: """ - usage: + usage: wp core """ When I run `wp help core download` @@ -26,3 +26,16 @@ Feature: Get help about WP-CLI commands When I run `wp help non-existent-command` Then the return code should be 1 + + Scenario: Getting help for a third-party command + Given a WP install + And a google-sitemap-generator-cli plugin zip + And I run `wp plugin install --activate {PLUGIN_ZIP}` + And I run `wp plugin install --activate google-sitemap-generator` + + When I run `wp help google-sitemap` + Then it should run without errors + And STDOUT should contain: + """ + usage: wp google-sitemap + """ diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 6e48c3bb8..f16959b4c 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -44,19 +44,25 @@ function ( $world ) { } ); -$steps->Given('/^a P2 theme zip$/', +$steps->Given( '/^a P2 theme zip$/', function ( $world ) { $zip_name = 'p2.1.0.1.zip'; - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-cache'; - $world->variables['THEME_ZIP'] = $cache_dir . '/' . $zip_name; + $world->variables['THEME_ZIP'] = $world->get_cache_path( $zip_name ); $zip_url = 'http://wordpress.org/extend/themes/download/' . $zip_name; - system( \WP_CLI\Utils\create_cmd( 'mkdir -p %s', $cache_dir ) ); + $world->download_file( $zip_url, $world->variables['THEME_ZIP'] ); + } +); + +$steps->Given( '/^a google-sitemap-generator-cli plugin zip$/', + function ( $world ) { + $zip_url = 'https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip'; + + $world->variables['PLUGIN_ZIP'] = $world->get_cache_path( 'google-sitemap-generator-cli.zip' ); - system( \WP_CLI\Utils\create_cmd( 'curl -s %s > %s', $zip_url, - $world->variables['THEME_ZIP'] ) ); + $world->download_file( $zip_url, $world->variables['PLUGIN_ZIP'] ); } ); From 589e51debb21d2dc741518ea88398cecced6c1de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 04:04:19 +0200 Subject: [PATCH 1392/5359] create CONTRIBUTING.md file --- CONTRIBUTING.md | 37 +++++++++++++++++++++++++++++++++++++ README.md | 26 -------------------------- 2 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..eea981316 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +Contribute +========== + +So you've got an awesome idea to throw into WP-CLI. Great! Please keep the +following in mind: + +* If you're adding a new command or subcommand, please consider adding a functional test for it in the `features` directory. Also, please create the appropriate `.txt` file in the `man-src` directory. +* Please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). + +Test Dependencies +----------------- + +There are two types of tests: + +* unit tests, implemented using [PHPUnit](http://phpunit.de/) +* functional tests, implemented using [Behat](http://behat.org) + +All the test dependencies can be installed using [Composer](http://getcomposer.org/): + + php composer.phar install --dev + +Before running the tests, you'll need a MySQL user called `wp_cli_test` with the +password `password1` that has full privileges on the MySQL database `wp_cli_test`. +Running the following as root in MySQL should do the trick: + + GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; + +Finally, to run the tests: + + vendor/bin/phpunit + vendor/bin/behat + +Finally... +---------- + +Thanks! Hacking on WP-CLI should be fun. If you find any of this hard to figure +out, let us know so we can improve our process or documentation! diff --git a/README.md b/README.md index f72337f64..7a3335d10 100644 --- a/README.md +++ b/README.md @@ -26,29 +26,3 @@ Need even more info? Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. - -Running tests -------------- - -There are two types of tests: - -* unit tests, implemented using [PHPUnit](http://phpunit.de/) -* functional tests, implemented using [Behat](http://behat.org) - -All the test dependencies can be installed using [composer](http://getcomposer.org/): - - composer.phar install --dev - -Before running the tests, you'll need a MySQL user called `wp_cli_test` with the -password `password1` that has full privileges on the MySQL database `wp_cli_test`. -Running the following as root in MySQL should do the trick: - - GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; - -Finally, to run the unit tests: - - vendor/bin/phpunit - -And to run the functional tests: - - vendor/bin/behat From 00b06c7ff622ce0784d55780ed547e0a71813718 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 11 Mar 2013 19:41:53 -0700 Subject: [PATCH 1393/5359] role: Correct indentation style --- php/commands/role.php | 162 +++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 2e1237586..4c1104ee8 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -7,87 +7,87 @@ */ class Role_Command extends WP_CLI_Command { - /** - * List all roles. - * - * @subcommand list - */ - public function _list( $args ) { - global $wp_roles; - - foreach ( $wp_roles->roles as $key => $role ) { - WP_CLI::line( $role['name'] . " ($key)"); - } - } - - /** - * Check if a role exists. - * Will return 0 if the role exists, 1 if it does not. - * - * @synopsis <role-key> - */ - public function exists( $args ) { - global $wp_roles; - - if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - exit(1); - } - } - - /** - * Create a new role. - * - * @synopsis <role-key> <role-name> - */ - public function create( $args ) { - self::persistence_check(); - - $role_key = array_shift( $args ); - $role_name = array_shift( $args ); - - if ( empty( $role_key ) || empty( $role_name ) ) - WP_CLI::error( "Can't create role, insufficient information provided."); - - if ( ! add_role( $role_key, $role_name ) ) - WP_CLI::error( "Role couldn't be created." ); - else - WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); - - } - - /** - * Delete an existing role. - * - * @synopsis <role-key> - */ - public function delete( $args ) { - - global $wp_roles; - - self::persistence_check(); - - $role_key = array_shift( $args ); - - if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::error( "Role key not provided, or is invalid." ); - - remove_role( $role_key ); - - // Note: remove_role() doesn't indicate success or otherwise, so we have to - // check ourselves - if ( ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); - else - WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); - - } - - private static function persistence_check() { - global $wp_roles; - - if ( !$wp_roles->use_db ) - WP_CLI::error( "Role definitions are not persistent." ); - } + /** + * List all roles. + * + * @subcommand list + */ + public function _list( $args ) { + global $wp_roles; + + foreach ( $wp_roles->roles as $key => $role ) { + WP_CLI::line( $role['name'] . " ($key)"); + } + } + + /** + * Check if a role exists. + * Will return 0 if the role exists, 1 if it does not. + * + * @synopsis <role-key> + */ + public function exists( $args ) { + global $wp_roles; + + if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { + exit(1); + } + } + + /** + * Create a new role. + * + * @synopsis <role-key> <role-name> + */ + public function create( $args ) { + self::persistence_check(); + + $role_key = array_shift( $args ); + $role_name = array_shift( $args ); + + if ( empty( $role_key ) || empty( $role_name ) ) + WP_CLI::error( "Can't create role, insufficient information provided."); + + if ( ! add_role( $role_key, $role_name ) ) + WP_CLI::error( "Role couldn't be created." ); + else + WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + + } + + /** + * Delete an existing role. + * + * @synopsis <role-key> + */ + public function delete( $args ) { + + global $wp_roles; + + self::persistence_check(); + + $role_key = array_shift( $args ); + + if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) + WP_CLI::error( "Role key not provided, or is invalid." ); + + remove_role( $role_key ); + + // Note: remove_role() doesn't indicate success or otherwise, so we have to + // check ourselves + if ( ! isset( $wp_roles->roles[$role_key] ) ) + WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); + else + WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); + + } + + private static function persistence_check() { + global $wp_roles; + + if ( !$wp_roles->use_db ) + WP_CLI::error( "Role definitions are not persistent." ); + } } WP_CLI::add_command( 'role', 'Role_Command' ); \ No newline at end of file From 0d4cf1488e76fc87421e8bd8004bf74482d097f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 11 Mar 2013 19:50:52 -0700 Subject: [PATCH 1394/5359] role: Update role list to properly format roles in a table --- man-src/role-list.txt | 6 ++++++ php/commands/role.php | 23 +++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/man-src/role-list.txt b/man-src/role-list.txt index 6bc9ed2a3..a2dcd0cc0 100644 --- a/man-src/role-list.txt +++ b/man-src/role-list.txt @@ -1,3 +1,9 @@ +## OPTIONS + +* `--format`=<format>: + + Output list as table, CSV or JSON. Defaults to table. + ## EXAMPLES wp role list diff --git a/php/commands/role.php b/php/commands/role.php index 4c1104ee8..8f2e0765c 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -11,13 +11,32 @@ class Role_Command extends WP_CLI_Command { * List all roles. * * @subcommand list + * @synopsis [--format=<format>] */ - public function _list( $args ) { + public function _list( $args, $assoc_args ) { global $wp_roles; + $defaults = array( + 'format' => 'table', + ); + $params = array_merge( $defaults, $assoc_args ); + + $fields = array( + 'name', + 'role', + ); + + $output_roles = array(); foreach ( $wp_roles->roles as $key => $role ) { - WP_CLI::line( $role['name'] . " ($key)"); + $output_role = new stdClass; + + $output_role->name = $role['name']; + $output_role->role = $key; + + $output_roles[] = $output_role; } + + WP_CLI\Utils\format_items( $params['format'], $fields, $output_roles ); } /** From d00b499bab77abdf257b1238dbb8a79349705a0d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 12:41:22 +0200 Subject: [PATCH 1395/5359] describe how to generate a man page --- CONTRIBUTING.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eea981316..5ae6bc952 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,27 @@ Contribute ========== -So you've got an awesome idea to throw into WP-CLI. Great! Please keep the -following in mind: +So you've got an awesome idea to throw into WP-CLI. Great! Please keep the following in mind: * If you're adding a new command or subcommand, please consider adding a functional test for it in the `features` directory. Also, please create the appropriate `.txt` file in the `man-src` directory. * Please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). -Test Dependencies +Generating man pages +-------------------- + +To generate a man page, WP-CLI looks for `.txt` files in the `man-src` directory. It also gather information from the inline comments and the `@synopsis` annotations. + +The compiled man page is placed in the `man` directory. + +To (re)generate one or more man pages, you first need to have the [ronn](https://rubygems.org/gems/ronn) ruby gem installed. + +Then, you can run one of the following: + +* `wp --man` - regenerates all man pages +* `wp core --man` - regenerates man pages for the `core` command +* `wp core download --man` - regenerates man page only for the `core download` subcommand + +Running the tests ----------------- There are two types of tests: From 7324cccb1c05c45f68eb70fb71ce9b28342a828b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 12:44:41 +0200 Subject: [PATCH 1396/5359] s/gather/gathers/ --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ae6bc952..04fea3104 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ So you've got an awesome idea to throw into WP-CLI. Great! Please keep the follo Generating man pages -------------------- -To generate a man page, WP-CLI looks for `.txt` files in the `man-src` directory. It also gather information from the inline comments and the `@synopsis` annotations. +To generate a man page, WP-CLI looks for `.txt` files in the `man-src` directory. It also gathers information from the inline comments and the `@synopsis` annotations. The compiled man page is placed in the `man` directory. From a97d232eb34d8888abc5b39d31ca1e8ff1923297 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 14:44:47 +0200 Subject: [PATCH 1397/5359] add checks for plugin installs --- features/help.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/help.feature b/features/help.feature index 432eadf00..af077c730 100644 --- a/features/help.feature +++ b/features/help.feature @@ -31,7 +31,9 @@ Feature: Get help about WP-CLI commands Given a WP install And a google-sitemap-generator-cli plugin zip And I run `wp plugin install --activate {PLUGIN_ZIP}` + And it should run without errors And I run `wp plugin install --activate google-sitemap-generator` + And it should run without errors When I run `wp help google-sitemap` Then it should run without errors From f1762dddebe7d27bd8e2609903569af55ea913d6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 15:19:53 +0200 Subject: [PATCH 1398/5359] run core install-network when WP_MULTISITE=1 --- features/bootstrap/FeatureContext.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 8fb9912b2..91dd59fb5 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -180,14 +180,24 @@ private function add_line_to_wp_config( &$wp_config_code, $line ) { } public function run_install() { - $cmd = 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( + $install_r = $this->run( 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( 'url' => 'http://example.com', - 'title' => 'WP CLI Tests', + 'title' => 'WP CLI Site', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' - ) ); + ) ) ); + + if ( 0 !== $install_r->return_code ) { + return $install_r; + } + + if ( getenv( 'WP_MULTISITE' ) === '1' ) { + $install_r = $this->run( 'core install-network' . \WP_CLI\Utils\assoc_args_to_str( array( + 'title' => 'WP CLI Network' + ) ) ); + } - return $this->run( $cmd ); + return $install_r; } public function download_wordpress_files() { From 0d25ebf6411baeccee106cb9a418ee3ef3767ce0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 19:24:09 +0200 Subject: [PATCH 1399/5359] Add note about serialized values in search-replace man page [ci skip] --- man-src/search-replace.txt | 6 ++++++ man/search-replace.1 | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index a106c1762..2db4c96cf 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -1,3 +1,9 @@ +## DESCRIPTION + +This command will go through all rows in all tables and will replace all appearances of the old string with the new one. + +It will correctly handle serialized values. + ## OPTIONS * `--dry-run`: diff --git a/man/search-replace.1 b/man/search-replace.1 index 9ac08c7b6..0a5e34236 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -9,6 +9,12 @@ .SH "SYNOPSIS" wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] . +.SH "DESCRIPTION" +This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. +. +.P +It will correctly handle serialized values\. +. .SH "OPTIONS" . .TP From 89052b58006ebfad921bcd290f176b6f77592849 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 19:55:45 +0200 Subject: [PATCH 1400/5359] Replace WP_MULTISITE env variable with a 'Given a WP multisite install' step --- .travis.yml | 6 ++---- features/bootstrap/FeatureContext.php | 18 ++++++------------ features/steps/basic_steps.php | 8 ++++++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5ccd5656b..a0581df5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,8 @@ php: - 5.4 env: - - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.4.2 WP_MULTISITE=0 - - WP_VERSION=3.4.2 WP_MULTISITE=1 + - WP_VERSION=latest + - WP_VERSION=3.4.2 before_script: # install dependencies diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 91dd59fb5..fdd111d0b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -180,24 +180,18 @@ private function add_line_to_wp_config( &$wp_config_code, $line ) { } public function run_install() { - $install_r = $this->run( 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( + return $this->run( 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( 'url' => 'http://example.com', 'title' => 'WP CLI Site', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' ) ) ); + } - if ( 0 !== $install_r->return_code ) { - return $install_r; - } - - if ( getenv( 'WP_MULTISITE' ) === '1' ) { - $install_r = $this->run( 'core install-network' . \WP_CLI\Utils\assoc_args_to_str( array( - 'title' => 'WP CLI Network' - ) ) ); - } - - return $install_r; + public function run_install_network() { + return $this->run( 'core install-network' . \WP_CLI\Utils\assoc_args_to_str( array( + 'title' => 'WP CLI Network' + ) ) ); } public function download_wordpress_files() { diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index f16959b4c..c9c407027 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -28,13 +28,17 @@ function ( $world ) { } ); -$steps->Given( '/^a WP install$/', - function ( $world ) { +$steps->Given( '/^a WP (install|multisite install)$/', + function ( $world, $type ) { $world->create_db(); $world->create_empty_dir(); $world->download_wordpress_files(); $world->create_config(); $world->run_install(); + + if ( 'multisite install' == $type ) { + $world->run_install_network(); + } } ); From 2c32a5cc187d4bfdc5c1ceecdd492d10bf898cdc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 12 Mar 2013 16:11:02 -0700 Subject: [PATCH 1401/5359] Update man file --- man/role-list.1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/man/role-list.1 b/man/role-list.1 index 7998c7010..a962ccae4 100644 --- a/man/role-list.1 +++ b/man/role-list.1 @@ -7,7 +7,15 @@ \fBwp\-role\-list\fR \- List all roles\. . .SH "SYNOPSIS" -wp role list +wp role list [\-\-format=\fIformat\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. . .SH "EXAMPLES" . From 3f23bd0b197bb22f070e62945565da3306e3dd93 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 20:26:00 +0200 Subject: [PATCH 1402/5359] tests: escape arguments passed in run_sql() --- features/bootstrap/FeatureContext.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index fdd111d0b..f8841c84f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -85,10 +85,8 @@ public function download_file( $url, $path ) { } private static function run_sql( $sql ) { - $dbuser = self::$db_settings['dbuser']; - $dbpass = self::$db_settings['dbpass']; - - exec( "mysql -u$dbuser -p$dbpass -e '$sql'" ); + system( \WP_CLI\Utils\create_cmd( 'mysql -u%s -p%s -e %s', + self::$db_settings['dbuser'], self::$db_settings['dbpass'], $sql ) ); } public function create_db() { From e39d52f6cb4480d82dbb1820e72725ab5e66bdbf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Mar 2013 20:39:35 +0200 Subject: [PATCH 1403/5359] add $assoc_args parameter to _run(), for convenience --- features/bootstrap/FeatureContext.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index f8841c84f..af3e7c46f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -99,8 +99,9 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - private function _run( $command ) { - $wp_cli_path = getcwd() . "/bin/wp"; + private function _run( $command, $assoc_args ) { + if ( !empty( $assoc_args ) ) + $command .= \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); if ( false === strpos( $command, '--path' ) ) { $command = \WP_CLI\Utils\assoc_args_to_str( array( @@ -108,7 +109,7 @@ private function _run( $command ) { ) ) . ' ' . $command; } - $sh_command = "$wp_cli_path $command"; + $sh_command = getcwd() . "/bin/wp $command"; $process = proc_open( $sh_command, array( 0 => STDIN, @@ -127,7 +128,7 @@ private function _run( $command ) { return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); } - public function run( $command ) { + public function run( $command, $assoc_args = array() ) { switch ( $command ) { case 'core install': return $this->run_install(); @@ -138,12 +139,12 @@ public function run( $command ) { break; default: - return $this->_run( $command ); + return $this->_run( $command, $assoc_args ); } } public function create_config() { - return $this->run( 'core config' . \WP_CLI\Utils\assoc_args_to_str( self::$db_settings ) ); + return $this->_run( 'core config', self::$db_settings ); } public function define_custom_wp_content_dir() { @@ -178,18 +179,18 @@ private function add_line_to_wp_config( &$wp_config_code, $line ) { } public function run_install() { - return $this->run( 'core install' . \WP_CLI\Utils\assoc_args_to_str( array( + return $this->_run( 'core install', array( 'url' => 'http://example.com', 'title' => 'WP CLI Site', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' - ) ) ); + ) ); } public function run_install_network() { - return $this->run( 'core install-network' . \WP_CLI\Utils\assoc_args_to_str( array( + return $this->_run( 'core install-network', array( 'title' => 'WP CLI Network' - ) ) ); + ) ); } public function download_wordpress_files() { @@ -197,9 +198,9 @@ public function download_wordpress_files() { // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - $r = $this->run( 'core download' . \WP_CLI\Utils\assoc_args_to_str( array( + $r = $this->_run( 'core download', array( 'path' => $cache_dir - ) ) ); + ) ); exec( sprintf( "cp -r '%s/'* '%s/'", $cache_dir, $this->install_dir ) ); } From dc0f1c0c1a97cfad83656c0160d388644ef9cb54 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 17:41:35 +0200 Subject: [PATCH 1404/5359] transparently add additional assoc params to special commands, instead of having dedicated methods --- features/bootstrap/FeatureContext.php | 49 +++++++++++---------------- features/steps/basic_steps.php | 8 ++--- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index af3e7c46f..4a9e9526c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -20,6 +20,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface ); private $install_dir; + private $additional_args; public $variables = array(); @@ -32,6 +33,21 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface public function __construct( array $parameters ) { $this->drop_db(); + + $this->additional_args = array( + 'core config' => self::$db_settings, + + 'core install' => array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Site', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ), + + 'core install-network', array( + 'title' => 'WP CLI Network' + ) + ); } public function getStepDefinitionResources() @@ -129,22 +145,12 @@ private function _run( $command, $assoc_args ) { } public function run( $command, $assoc_args = array() ) { - switch ( $command ) { - case 'core install': - return $this->run_install(); - break; - - case 'core config': - return $this->create_config(); - break; - - default: - return $this->_run( $command, $assoc_args ); + if ( isset( $this->additional_args[ $command ] ) ) { + $assoc_args = array_merge( $this->additional_args[ $command ], + $assoc_args ); } - } - public function create_config() { - return $this->_run( 'core config', self::$db_settings ); + return $this->_run( $command, $assoc_args ); } public function define_custom_wp_content_dir() { @@ -178,21 +184,6 @@ private function add_line_to_wp_config( &$wp_config_code, $line ) { $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); } - public function run_install() { - return $this->_run( 'core install', array( - 'url' => 'http://example.com', - 'title' => 'WP CLI Site', - 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' - ) ); - } - - public function run_install_network() { - return $this->_run( 'core install-network', array( - 'title' => 'WP CLI Network' - ) ); - } - public function download_wordpress_files() { // We cache the results of "wp core download" to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index c9c407027..270e9fa4d 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -18,7 +18,7 @@ function ( $world ) { $steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->create_config(); + $world->run( 'core config' ); } ); @@ -33,11 +33,11 @@ function ( $world, $type ) { $world->create_db(); $world->create_empty_dir(); $world->download_wordpress_files(); - $world->create_config(); - $world->run_install(); + $world->run( 'core config' ); + $world->run( 'core install' ); if ( 'multisite install' == $type ) { - $world->run_install_network(); + $world->run( 'core install-network' ); } } ); From cf2769fd1a8fa7d07f467e968b76261d8ce0249b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 17:50:06 +0200 Subject: [PATCH 1405/5359] use create_cmd() utility in download_wordpress_files() --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4a9e9526c..f4d1a9388 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -193,7 +193,7 @@ public function download_wordpress_files() { 'path' => $cache_dir ) ); - exec( sprintf( "cp -r '%s/'* '%s/'", $cache_dir, $this->install_dir ) ); + system( \WP_CLI\Utils\create_cmd( "cp -r %s/* %s/", $cache_dir, $this->install_dir ) ); } } From ecfe4360f11a387d5eb6d39cb257d148fda41e2a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 18:36:04 +0200 Subject: [PATCH 1406/5359] first pass at multisite.feature --- features/bootstrap/FeatureContext.php | 2 +- features/multisite.feature | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 features/multisite.feature diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index f4d1a9388..071bba1cc 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -44,7 +44,7 @@ public function __construct( array $parameters ) 'admin_password' => 'password1' ), - 'core install-network', array( + 'core install-network' => array( 'title' => 'WP CLI Network' ) ); diff --git a/features/multisite.feature b/features/multisite.feature new file mode 100644 index 000000000..a370e3d32 --- /dev/null +++ b/features/multisite.feature @@ -0,0 +1,17 @@ +Feature: Manage a WordPress multisite installation + + Scenario: Install multisite + Given a WP install + + When I run `wp core install-network` + Then it should run without errors + + When I run the previous command again + Then the return code should be 1 + + Scenario: Create some blogs + Given a WP multisite install + + When I run `wp blog create --slug=first --title=First` + Then it should run without errors + And STDOUT should not be empty From c118a907ada57d18ef2e71727c9d863bbc83376f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 18:51:23 +0200 Subject: [PATCH 1407/5359] don't test against WP 3.4.2 using PHP 5.4 It avoids this warning: Creating default object from empty value in /wp-admin/includes/schema.php on line 922 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index a0581df5b..e470d86ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,11 @@ env: - WP_VERSION=latest - WP_VERSION=3.4.2 +matrix: + exclude: + - php: 5.4 + env: WP_VERSION=3.4.2 + before_script: # install dependencies - composer install --dev --no-interaction --prefer-source From 80181f8dc9a1762555185e757ad9ccc1c00d5250 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 19:40:45 +0200 Subject: [PATCH 1408/5359] test deleting a blog --- features/multisite.feature | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/features/multisite.feature b/features/multisite.feature index a370e3d32..67d0e7908 100644 --- a/features/multisite.feature +++ b/features/multisite.feature @@ -12,6 +12,13 @@ Feature: Manage a WordPress multisite installation Scenario: Create some blogs Given a WP multisite install - When I run `wp blog create --slug=first --title=First` + When I run `wp blog create --slug=first --porcelain` Then it should run without errors - And STDOUT should not be empty + And STDOUT should match '%d' + And save STDOUT as {BLOG_ID} + + When I run `wp blog delete {BLOG_ID} --yes` + Then it should run without errors + + When I run the previous command again + Then the return code should be 1 From 5a0793959746cb0752630f3e8c126789910f4a54 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 19:41:48 +0200 Subject: [PATCH 1409/5359] add --porcelain flag to `blog create` --- man-src/blog-create.txt | 4 ++++ man/blog-create.1 | 8 +++++++- php/commands/blog.php | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/man-src/blog-create.txt b/man-src/blog-create.txt index 02814b8f3..1c7e6aea5 100644 --- a/man-src/blog-create.txt +++ b/man-src/blog-create.txt @@ -19,3 +19,7 @@ * `--private`: If set, the new blog will be non-public (not indexed) + +* `--porcelain`: + + If set, only the blog id will be output on success. diff --git a/man/blog-create.1 b/man/blog-create.1 index c0b207a8b..022c1c88a 100644 --- a/man/blog-create.1 +++ b/man/blog-create.1 @@ -7,7 +7,7 @@ \fBwp\-blog\-create\fR \- Create a blog in a multisite install\. . .SH "SYNOPSIS" -wp blog create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] +wp blog create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] [\-\-porcelain] . .SH "OPTIONS" . @@ -40,4 +40,10 @@ Site (network) to associate new blog with\. Defaults to current site (typically . .IP If set, the new blog will be non\-public (not indexed) +. +.TP +\fB\-\-porcelain\fR: +. +.IP +If set, only the blog id will be output on success\. diff --git a/php/commands/blog.php b/php/commands/blog.php index 92be6de20..6ba51a729 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -28,7 +28,7 @@ private function _get_site( $site_id ) { /** * Create a blog in a multisite install. * - * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] + * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] [--porcelain] */ public function create( $_, $assoc_args ) { global $wpdb; From eb961c546057f04f32bb2bd325db3d7e4263c128 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 19:47:37 +0200 Subject: [PATCH 1410/5359] make `blog delete` accept a blog id as well --- php/commands/blog.php | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 6ba51a729..9af9fa2e4 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -117,35 +117,40 @@ public function create( $_, $assoc_args ) { else { WP_CLI::error( $id->get_error_message() ); } - WP_CLI::success( "Blog $id created: $url" ); + + if ( isset( $assoc_args['porcelain'] ) ) + WP_CLI::line( $id ); + else + WP_CLI::success( "Blog $id created: $url" ); } /** * Delete a blog in a multisite install. * - * @synopsis --slug=<slug> [--yes] [--keep-tables] + * @synopsis [<blog-id>] [--slug=<slug>] [--yes] [--keep-tables] */ - function delete( $_, $assoc_args ) { - $slug = '/' . trim( $assoc_args['slug'], '/' ) . '/'; - - $blog_id = self::get_blog_id_by_slug( $slug ); + function delete( $args, $assoc_args ) { + if ( isset( $assoc_args['slug'] ) ) { + $blog = get_blog_details( trim( $assoc_args['slug'], '/' ) ); + } else { + if ( empty( $args ) ) { + WP_CLI::error( "Need to specify a blog id." ); + } - if ( !$blog_id ) - WP_CLI::error( sprintf( "'%s' blog not found.", $slug ) ); + $blog_id = $args[0]; - WP_CLI::confirm( "Are you sure you want to delete the '$slug' blog?", $assoc_args ); + $blog = get_blog_details( $blog_id ); + } - wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); + if ( !$blog ) { + WP_CLI::error( "Blog not found." ); + } - WP_CLI::success( "Blog '$slug' deleted." ); - } + WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl blog?", $assoc_args ); - protected static function get_blog_id_by_slug( $slug ) { - global $wpdb, $current_site; + wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); - return $wpdb->get_var( $wpdb->prepare( " - SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s" - , $current_site->domain, $slug ) ); + WP_CLI::success( "Blog 3 deleted." ); } } From 06567d64faeac03b1da70914a8f2b5f2935f5aed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 19:50:15 +0200 Subject: [PATCH 1411/5359] update man page for blog delete [ci skip] --- man-src/blog-delete.txt | 4 ++++ man/blog-delete.1 | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/man-src/blog-delete.txt b/man-src/blog-delete.txt index 349836eb8..f119826b9 100644 --- a/man-src/blog-delete.txt +++ b/man-src/blog-delete.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `<blog-id>`: + + The id of the blog to delete. If not provided, you must set the --slug parameter. + * `--slug`=<slug>: Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. diff --git a/man/blog-delete.1 b/man/blog-delete.1 index 80e3c20c1..d90ec3e16 100644 --- a/man/blog-delete.1 +++ b/man/blog-delete.1 @@ -7,11 +7,17 @@ \fBwp\-blog\-delete\fR \- Delete a blog in a multisite install\. . .SH "SYNOPSIS" -wp blog delete \-\-slug=\fIslug\fR [\-\-yes] [\-\-keep\-tables] +wp blog delete [\fIblog\-id\fR] [\-\-slug=\fIslug\fR] [\-\-yes] [\-\-keep\-tables] . .SH "OPTIONS" . .TP +\fB<blog\-id>\fR: +. +.IP +The id of the blog to delete\. If not provided, you must set the \-\-slug parameter\. +. +.TP \fB\-\-slug\fR=\fIslug\fR: . .IP From f16b19aac20b5a3628ab5957fa47fc247f8461fd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 19:52:40 +0200 Subject: [PATCH 1412/5359] fix success message for `blog delete` --- features/multisite.feature | 4 ++++ php/commands/blog.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/features/multisite.feature b/features/multisite.feature index 67d0e7908..058d2456d 100644 --- a/features/multisite.feature +++ b/features/multisite.feature @@ -19,6 +19,10 @@ Feature: Manage a WordPress multisite installation When I run `wp blog delete {BLOG_ID} --yes` Then it should run without errors + And STDOUT should contain: + """ + Blog {BLOG_ID} deleted. + """ When I run the previous command again Then the return code should be 1 diff --git a/php/commands/blog.php b/php/commands/blog.php index 9af9fa2e4..7bf2cf509 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -150,7 +150,7 @@ function delete( $args, $assoc_args ) { wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); - WP_CLI::success( "Blog 3 deleted." ); + WP_CLI::success( "Blog $blog_id deleted." ); } } From 783a98a590088becc283eca5a7511daf65c5a976 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 20:07:50 +0200 Subject: [PATCH 1413/5359] add 'Delete a blog by slug' scenario --- features/multisite.feature | 21 ++++++++++++++++----- php/commands/blog.php | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/features/multisite.feature b/features/multisite.feature index 058d2456d..536fed7f5 100644 --- a/features/multisite.feature +++ b/features/multisite.feature @@ -9,7 +9,7 @@ Feature: Manage a WordPress multisite installation When I run the previous command again Then the return code should be 1 - Scenario: Create some blogs + Scenario: Delete a blog by id Given a WP multisite install When I run `wp blog create --slug=first --porcelain` @@ -19,10 +19,21 @@ Feature: Manage a WordPress multisite installation When I run `wp blog delete {BLOG_ID} --yes` Then it should run without errors - And STDOUT should contain: - """ - Blog {BLOG_ID} deleted. - """ + And STDOUT should not be empty + + When I run the previous command again + Then the return code should be 1 + + Scenario: Delete a blog by slug + Given a WP multisite install + + When I run `wp blog create --slug=first` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp blog delete --slug=first --yes` + Then it should run without errors + And STDOUT should not be empty When I run the previous command again Then the return code should be 1 diff --git a/php/commands/blog.php b/php/commands/blog.php index 7bf2cf509..b7af96103 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -148,9 +148,9 @@ function delete( $args, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl blog?", $assoc_args ); - wpmu_delete_blog( $blog_id, !isset( $assoc_args['keep-tables'] ) ); + wpmu_delete_blog( $blog->blog_id, !isset( $assoc_args['keep-tables'] ) ); - WP_CLI::success( "Blog $blog_id deleted." ); + WP_CLI::success( "The blog at $blog->siteurl was deleted." ); } } From 682b0761bb51957e75df329effcfa1b25187dba4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 13 Mar 2013 20:56:35 +0200 Subject: [PATCH 1414/5359] bump version 0.9.0-beta [ci skip] --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 7e040cbec..7fb1aa66f 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.0-alpha2' ); +define( 'WP_CLI_VERSION', '0.9.0-beta' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 5a8e4bcf9a1a22576b9ba535c838dddf71a0b1d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 03:16:57 +0200 Subject: [PATCH 1415/5359] 'debug' option is always set, but might be false --- features/flags.feature | 2 +- php/WP_CLI/Runner.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index f2020b901..223fda99b 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -28,7 +28,7 @@ Feature: Global flags CONST_WITHOUT_QUOTES """ - When I run `wp --debug eval 'echo CONST_WITHOUT_QUOTES;'` + When I run `wp eval 'echo CONST_WITHOUT_QUOTES;' --debug` Then the return code should be 0 And STDOUT should contain: """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b18600a25..ff3fbae7e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -306,7 +306,7 @@ public function before_wp_load() { } public function after_wp_config_load() { - if ( isset( $this->config['debug'] ) ) { + if ( $this->config['debug'] ) { if ( !defined( 'WP_DEBUG' ) ) define( 'WP_DEBUG', true ); } From fda118d320d57de4a71eeb08645d118fd5685c19 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 03:27:02 +0200 Subject: [PATCH 1416/5359] fix whitespace in media.php [ci skip] --- php/commands/media.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 77c6a1075..802c11971 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -15,7 +15,7 @@ class Media_Command extends WP_CLI_Command { */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - + // If id is given, skip confirm because it is only one file if( !empty( $args ) ) { $assoc_args['yes'] = true; @@ -41,7 +41,7 @@ function regenerate( $args, $assoc_args = array() ) { $count = $images->post_count; WP_CLI::line( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); - + $not_found = array_diff( $args, $images->posts ); if( !empty($not_found) ) { WP_CLI::warning( $this->_not_found_message( $not_found ) ); @@ -55,11 +55,10 @@ function regenerate( $args, $assoc_args = array() ) { } private function _process_regeneration( $id ) { - $image = get_post( $id ); $fullsizepath = get_attached_file( $image->ID ); - + if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); return; @@ -83,7 +82,7 @@ private function _process_regeneration( $id ) { while ( $file = readdir( $dir ) ) { if ( !( strrpos( $file, $image_name ) === false ) ) { - + $thumbnail = explode( $image_name, $file ); $filename = $thumbnail[ 1 ]; @@ -94,7 +93,7 @@ private function _process_regeneration( $id ) { $thumbnail_name = basename( $filename, $thumbnail_ext ); $sizes = explode( 'x', $thumbnail_name ); - + // If not cropped by WP if ( 2 == count( $sizes ) ) { $width = $sizes[0]; @@ -107,19 +106,21 @@ private function _process_regeneration( $id ) { } } } - + $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); - + if ( is_wp_error( $metadata ) ) { WP_CLI::warning( $metadata->get_error_message() ); return; } - + if ( empty( $metadata ) ) { WP_CLI::warning( "Couldn't regenerate image." ); return; } + wp_update_attachment_metadata( $image->ID, $metadata ); + WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); } @@ -134,4 +135,4 @@ private function _not_found_message( $not_found_ids ){ } } -WP_CLI::add_command( 'media', 'Media_Command' ); \ No newline at end of file +WP_CLI::add_command( 'media', 'Media_Command' ); From 83cb617e87ed7b7dbef720206f413f8a44062ece Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 05:06:00 +0200 Subject: [PATCH 1417/5359] media regenerate: remove inline props code has been significantly altered. will give credit in release post. --- php/commands/media.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 802c11971..44007eec9 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -10,8 +10,7 @@ class Media_Command extends WP_CLI_Command { /** * Regenerate thumbnail(s) * - * @synopsis <attachment-id>... [--yes] - * props @benmay & @Viper007Bond + * @synopsis <attachment-id>... [--yes] */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; From f7127b540ca184d6e5549c402ab2f2fcc42a87ac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 05:23:18 +0200 Subject: [PATCH 1418/5359] use attachment metadata for deleting old images, instead of reading through the existing files --- php/commands/media.php | 62 +++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 44007eec9..199b1067d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -65,46 +65,7 @@ private function _process_regeneration( $id ) { WP_CLI::line( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); - $a_path = explode( DIRECTORY_SEPARATOR, $fullsizepath ); - $a_file = explode( '.', $a_path[ count( $a_path ) - 1 ] ); - - unset( $a_path ); - unset( $a_file[ count( $a_file ) - 1 ] ); - - $image_name = $a_file[ count( $a_file ) - 1 ] . '-'; - $dir_path = wp_upload_dir(); - - // Read and delete files - $dir = opendir( $dir_path['basedir'] ); - $files = array(); - - while ( $file = readdir( $dir ) ) { - - if ( !( strrpos( $file, $image_name ) === false ) ) { - - $thumbnail = explode( $image_name, $file ); - $filename = $thumbnail[ 1 ]; - - //If we got the original / full image - if ( "" == $thumbnail[ 0 ] ) { - $filetype = wp_check_filetype($file); - $thumbnail_ext = ".{$filetype['ext']}"; - $thumbnail_name = basename( $filename, $thumbnail_ext ); - - $sizes = explode( 'x', $thumbnail_name ); - - // If not cropped by WP - if ( 2 == count( $sizes ) ) { - $width = $sizes[0]; - $height = $sizes[1]; - if ( is_numeric( $width ) && is_numeric( $height ) ) { - WP_CLI::line( "Thumbnail: {$width} x {$height} was deleted." ); - unlink( $dir_path['basedir'] . DIRECTORY_SEPARATOR . $image_name . $thumbnail_name . $thumbnail_ext ); - } - } - } - } - } + $this->remove_old_images( $image->ID ); $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); @@ -123,6 +84,27 @@ private function _process_regeneration( $id ) { WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); } + private function remove_old_images( $att_id ) { + $wud = wp_upload_dir(); + + $metadata = wp_get_attachment_metadata( $att_id ); + + $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; + $original_path = $dir_path . basename( $metadata['file'] ); + + foreach ( $metadata['sizes'] as $size => $size_info ) { + $intermediate_path = $dir_path . $size_info['file']; + + if ( $intermediate_path == $original_path ) + continue; + + if ( unlink( $intermediate_path ) ) { + WP_CLI::line( sprintf( "Thumbnail %s x %s was deleted.", + $size_info['width'], $size_info['height'] ) ); + } + } + } + private function _not_found_message( $not_found_ids ){ $count = count($not_found_ids); return vsprintf( 'Unable to find the %1$s (%2$s). Are you sure %3$s %4$s?', array( From 4cdfe8cc63def17d630be532819e33a925484275 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 05:25:04 +0200 Subject: [PATCH 1419/5359] fix indentation for commands/media.php --- php/commands/media.php | 134 +++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 66 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 199b1067d..c053cbca0 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -7,82 +7,82 @@ */ class Media_Command extends WP_CLI_Command { - /** - * Regenerate thumbnail(s) - * - * @synopsis <attachment-id>... [--yes] - */ - function regenerate( $args, $assoc_args = array() ) { - global $wpdb; - - // If id is given, skip confirm because it is only one file - if( !empty( $args ) ) { - $assoc_args['yes'] = true; - } + /** + * Regenerate thumbnail(s) + * + * @synopsis <attachment-id>... [--yes] + */ + function regenerate( $args, $assoc_args = array() ) { + global $wpdb; + + // If id is given, skip confirm because it is only one file + if( !empty( $args ) ) { + $assoc_args['yes'] = true; + } - WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); + WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); - $query_args = array( - 'post_type' => 'attachment', - 'post__in' => $args, - 'post_mime_type' => 'image', - 'post_status' => 'any', - 'posts_per_page' => -1, - 'fields' => 'ids' - ); + $query_args = array( + 'post_type' => 'attachment', + 'post__in' => $args, + 'post_mime_type' => 'image', + 'post_status' => 'any', + 'posts_per_page' => -1, + 'fields' => 'ids' + ); - $images = new WP_Query( $query_args ); + $images = new WP_Query( $query_args ); - if ( $images->post_count == 0 ) { - //No images, so all keys in $args are not found within WP - WP_CLI::error( $this->_not_found_message( $args ) ); - } - $count = $images->post_count; + if ( $images->post_count == 0 ) { + //No images, so all keys in $args are not found within WP + WP_CLI::error( $this->_not_found_message( $args ) ); + } + $count = $images->post_count; - WP_CLI::line( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); + WP_CLI::line( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); - $not_found = array_diff( $args, $images->posts ); - if( !empty($not_found) ) { - WP_CLI::warning( $this->_not_found_message( $not_found ) ); - } + $not_found = array_diff( $args, $images->posts ); + if( !empty($not_found) ) { + WP_CLI::warning( $this->_not_found_message( $not_found ) ); + } - foreach ( $images->posts as $id ) { - $this->_process_regeneration( $id ); - } + foreach ( $images->posts as $id ) { + $this->_process_regeneration( $id ); + } - WP_CLI::success( sprintf( 'Finished regenerating %1$s.', ngettext('the image', 'all images', $count) ) ); - } + WP_CLI::success( sprintf( 'Finished regenerating %1$s.', ngettext('the image', 'all images', $count) ) ); + } - private function _process_regeneration( $id ) { - $image = get_post( $id ); + private function _process_regeneration( $id ) { + $image = get_post( $id ); - $fullsizepath = get_attached_file( $image->ID ); + $fullsizepath = get_attached_file( $image->ID ); - if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); - return; - } + if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { + WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); + return; + } - WP_CLI::line( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); + WP_CLI::line( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); $this->remove_old_images( $image->ID ); - $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); + $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); - if ( is_wp_error( $metadata ) ) { - WP_CLI::warning( $metadata->get_error_message() ); - return; - } + if ( is_wp_error( $metadata ) ) { + WP_CLI::warning( $metadata->get_error_message() ); + return; + } - if ( empty( $metadata ) ) { - WP_CLI::warning( "Couldn't regenerate image." ); - return; - } + if ( empty( $metadata ) ) { + WP_CLI::warning( "Couldn't regenerate image." ); + return; + } - wp_update_attachment_metadata( $image->ID, $metadata ); + wp_update_attachment_metadata( $image->ID, $metadata ); - WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); - } + WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); + } private function remove_old_images( $att_id ) { $wud = wp_upload_dir(); @@ -105,15 +105,17 @@ private function remove_old_images( $att_id ) { } } - private function _not_found_message( $not_found_ids ){ - $count = count($not_found_ids); - return vsprintf( 'Unable to find the %1$s (%2$s). Are you sure %3$s %4$s?', array( - ngettext('image', 'images', $count), - implode(", ", $not_found_ids), - ngettext('it', 'they', $count), - ngettext('exists', 'exist', $count), - )); - } + private function _not_found_message( $not_found_ids ){ + $count = count( $not_found_ids ); + + return vsprintf( 'Unable to find the %1$s (%2$s). Are you sure %3$s %4$s?', array( + ngettext('image', 'images', $count), + implode(", ", $not_found_ids), + ngettext('it', 'they', $count), + ngettext('exists', 'exist', $count), + ) ); + } } WP_CLI::add_command( 'media', 'Media_Command' ); + From cf3d53bdfc0ee5213914165f0cc894a4a403f674 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 15 Mar 2013 22:40:24 +0200 Subject: [PATCH 1420/5359] add utility for generating the list of contributors [ci skip] --- .mailmap | 42 ++++++++++++++++++++++++++++++++++++++++++ utils/contrib-list | 16 ++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .mailmap create mode 100755 utils/contrib-list diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..cb5c30bb2 --- /dev/null +++ b/.mailmap @@ -0,0 +1,42 @@ +andreascreten <andreas@madewithlove.be> +bendoh <ben@thinkoomph.com> +builtbylane <lanegoldberg@gmail.com> +conatus <alex@recordsonribs.com> +danielbachhuber <d@danielbachhuber.com> +drrobotnik <B@Brandons-Mac-Pro-4.local> +dwightjack <marco.solazzi@gmail.com> +ericandrewlewis <eric.andrew.lewis@gmail.com> +ericmann <eric@eamann.com> +getsource <mike.schroder@dreamhost.com> +goldenapples <ntaintor@janrain.com> +jghazally <jeff@bigfish.co.uk> +jghazally <jghazally@gmail.com> +jmslbam <jmslbam@gmail.com> +johnpbloch <jbloch@John-Blochs-iMac.local> +johnpbloch <johnpbloch@gmail.com> +kidfiction <ejdanderson@gmail.com> +lackingpenguin <benjamin.j.brooks@gmail.com> +leewillis77 <leewillis77@gmail.com> +marcoceppi <marco@ceppi.net> +matiskay <matiskay@gmail.com> +mgburns <mgburns@bu.edu> +mgburns <mike@grady-etc.com> +milesj <mileswjohnson@gmail.com> +mwilliamson <michael.williamson@red-gate.com> +mwilliamson <mike@zwobble.org> +nacin <andrewnacin@gmail.com> +navitronic <adrian@navitronic.co.uk> +nb <nb@nikolay.bg> +ocean90 <dominikschilling+git@gmail.com> +roelven <roel@soundcloud.com> +scribu <scribu@gmail.com> +sebastiaandegeus <sebastiaan@hoppinger.com> +soulou <leo@soulou.fr> +spuriousdata <spuriousdata@gmail.com> +svaj <chris@chrisbot.(none)> +taupecat <tracy@taupecat.com> +tddewey <td@tddewey.com> +tollmanz <zack@zackdev.com> +toszcze <toszcze@gmail.com> +tott <tott@automattic.com> +wopr42 <john@zippykid.com> diff --git a/utils/contrib-list b/utils/contrib-list new file mode 100755 index 000000000..76f5a1531 --- /dev/null +++ b/utils/contrib-list @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +if [ $# -lt 1 ]; then + echo "usage: $(basename $0) v0.8.0..v0.9.0 [-l]" + exit 1 +fi + +prev_version=$1 +linked=$2 + +if [ '-l' == "$linked" ] +then + git log --format="%aN" $prev_version -- | sort | uniq | sed 's#\(.*\)# [\1](http://github.com/\1)#' | tr '\n' ',' +else + git log --format="%aN <%aE>" $prev_version -- | sort | uniq +fi From 59111392b25c882af297b8fc93c12d03e3aa31ed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 18 Mar 2013 19:21:04 +0200 Subject: [PATCH 1421/5359] add link to Governance page --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 7a3335d10..2c49bc83d 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,11 @@ For documentation, usage, and examples, check out [wp-cli.org](http://wp-cli.org I'm running into troubles, what can I do? ----------------------------------------- - To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). Who's behind this thing? ------------------------ - -We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. +We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). From 0a3a932c3d13cf9d4d4f9a6e1b9c3152c583c4d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Mar 2013 17:28:37 +0200 Subject: [PATCH 1422/5359] remote obsolete manual pages --- man/cache-add.1 | 10 ---------- man/cache-decr.1 | 10 ---------- man/cache-delete.1 | 10 ---------- man/cache-flush.1 | 10 ---------- man/cache-get.1 | 10 ---------- man/cache-incr.1 | 10 ---------- man/cache-replace.1 | 10 ---------- man/cache-set.1 | 10 ---------- man/cache-type.1 | 10 ---------- man/generate-posts.1 | 3 --- man/generate-users.1 | 3 --- man/option-add.1 | 10 ---------- man/option-delete.1 | 10 ---------- man/option-get.1 | 10 ---------- man/option-update.1 | 10 ---------- man/post-meta-add.1 | 10 ---------- man/post-meta-delete.1 | 10 ---------- man/post-meta-get.1 | 10 ---------- man/post-meta-update.1 | 10 ---------- man/transient-delete.1 | 10 ---------- man/transient-get.1 | 10 ---------- man/transient-set.1 | 10 ---------- man/transient-type.1 | 10 ---------- man/user-meta-add.1 | 10 ---------- man/user-meta-delete.1 | 10 ---------- man/user-meta-get.1 | 10 ---------- man/user-meta-update.1 | 10 ---------- 27 files changed, 256 deletions(-) delete mode 100644 man/cache-add.1 delete mode 100644 man/cache-decr.1 delete mode 100644 man/cache-delete.1 delete mode 100644 man/cache-flush.1 delete mode 100644 man/cache-get.1 delete mode 100644 man/cache-incr.1 delete mode 100644 man/cache-replace.1 delete mode 100644 man/cache-set.1 delete mode 100644 man/cache-type.1 delete mode 100644 man/generate-posts.1 delete mode 100644 man/generate-users.1 delete mode 100644 man/option-add.1 delete mode 100644 man/option-delete.1 delete mode 100644 man/option-get.1 delete mode 100644 man/option-update.1 delete mode 100644 man/post-meta-add.1 delete mode 100644 man/post-meta-delete.1 delete mode 100644 man/post-meta-get.1 delete mode 100644 man/post-meta-update.1 delete mode 100644 man/transient-delete.1 delete mode 100644 man/transient-get.1 delete mode 100644 man/transient-set.1 delete mode 100644 man/transient-type.1 delete mode 100644 man/user-meta-add.1 delete mode 100644 man/user-meta-delete.1 delete mode 100644 man/user-meta-get.1 delete mode 100644 man/user-meta-update.1 diff --git a/man/cache-add.1 b/man/cache-add.1 deleted file mode 100644 index 1ba98a2b0..000000000 --- a/man/cache-add.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-ADD" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-add\fR \- Add a value to the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache add\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-decr.1 b/man/cache-decr.1 deleted file mode 100644 index 7b77e7111..000000000 --- a/man/cache-decr.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-DECR" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-decr\fR \- Decrement a value in the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache decr\fR \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] diff --git a/man/cache-delete.1 b/man/cache-delete.1 deleted file mode 100644 index 180dd95d4..000000000 --- a/man/cache-delete.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-DELETE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-delete\fR \- Remove a value from the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache delete\fR \fIkey\fR \fIgroup\fR diff --git a/man/cache-flush.1 b/man/cache-flush.1 deleted file mode 100644 index 68fa2e169..000000000 --- a/man/cache-flush.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-FLUSH" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-flush\fR \- Flush the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache flush\fR diff --git a/man/cache-get.1 b/man/cache-get.1 deleted file mode 100644 index eb27a251c..000000000 --- a/man/cache-get.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-GET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-get\fR \- Get a value from the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache get\fR \fIkey\fR [\fIgroup\fR] diff --git a/man/cache-incr.1 b/man/cache-incr.1 deleted file mode 100644 index fc2e886a5..000000000 --- a/man/cache-incr.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-INCR" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-incr\fR \- Increment a value in the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache incr\fR \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] diff --git a/man/cache-replace.1 b/man/cache-replace.1 deleted file mode 100644 index d33269501..000000000 --- a/man/cache-replace.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-REPLACE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-replace\fR \- Replace an existing value in the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache replace\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-set.1 b/man/cache-set.1 deleted file mode 100644 index d40e0c0e6..000000000 --- a/man/cache-set.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-SET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-set\fR \- Set a value to the object cache\. -. -.SH "SYNOPSIS" -\fBwp cache set\fR \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] diff --git a/man/cache-type.1 b/man/cache-type.1 deleted file mode 100644 index a6c7c2a47..000000000 --- a/man/cache-type.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE\-TYPE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\-type\fR \- Attempts to determine which object cache is being used\. -. -.SH "SYNOPSIS" -\fBwp cache type\fR diff --git a/man/generate-posts.1 b/man/generate-posts.1 deleted file mode 100644 index 995c5436f..000000000 --- a/man/generate-posts.1 +++ /dev/null @@ -1,3 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 - diff --git a/man/generate-users.1 b/man/generate-users.1 deleted file mode 100644 index 995c5436f..000000000 --- a/man/generate-users.1 +++ /dev/null @@ -1,3 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 - diff --git a/man/option-add.1 b/man/option-add.1 deleted file mode 100644 index 249bfa0b0..000000000 --- a/man/option-add.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-OPTION\-ADD" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-option\-add\fR \- Add an option\. -. -.SH "SYNOPSIS" -\fBwp option add\fR \fIkey\fR \fIvalue\fR [\-\-json] diff --git a/man/option-delete.1 b/man/option-delete.1 deleted file mode 100644 index a625edcc9..000000000 --- a/man/option-delete.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-OPTION\-DELETE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-option\-delete\fR \- Delete an option\. -. -.SH "SYNOPSIS" -\fBwp option delete\fR \fIkey\fR diff --git a/man/option-get.1 b/man/option-get.1 deleted file mode 100644 index ad48edbd0..000000000 --- a/man/option-get.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-OPTION\-GET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-option\-get\fR \- Get an option\. -. -.SH "SYNOPSIS" -\fBwp option get\fR \fIkey\fR [\-\-json] diff --git a/man/option-update.1 b/man/option-update.1 deleted file mode 100644 index f53e10c0a..000000000 --- a/man/option-update.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-OPTION\-UPDATE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-option\-update\fR \- Update an option\. -. -.SH "SYNOPSIS" -\fBwp option update\fR \fIkey\fR \fIvalue\fR [\-\-json] diff --git a/man/post-meta-add.1 b/man/post-meta-add.1 deleted file mode 100644 index 91ae02aa8..000000000 --- a/man/post-meta-add.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-META\-ADD" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-meta\-add\fR \- Add a meta field\. -. -.SH "SYNOPSIS" -\fBwp post\-meta add\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/post-meta-delete.1 b/man/post-meta-delete.1 deleted file mode 100644 index ea28519d5..000000000 --- a/man/post-meta-delete.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-META\-DELETE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-meta\-delete\fR \- Delete a meta field\. -. -.SH "SYNOPSIS" -\fBwp post\-meta delete\fR \fIid\fR \fIkey\fR diff --git a/man/post-meta-get.1 b/man/post-meta-get.1 deleted file mode 100644 index 330773f18..000000000 --- a/man/post-meta-get.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-META\-GET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-meta\-get\fR \- Get meta field value\. -. -.SH "SYNOPSIS" -\fBwp post\-meta get\fR \fIid\fR \fIkey\fR [\-\-json] diff --git a/man/post-meta-update.1 b/man/post-meta-update.1 deleted file mode 100644 index a90f92c42..000000000 --- a/man/post-meta-update.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-META\-UPDATE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-meta\-update\fR \- Update a meta field\. -. -.SH "SYNOPSIS" -\fBwp post\-meta update\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/transient-delete.1 b/man/transient-delete.1 deleted file mode 100644 index 490196468..000000000 --- a/man/transient-delete.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TRANSIENT\-DELETE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-transient\-delete\fR \- Delete a transient value\. -. -.SH "SYNOPSIS" -\fBwp transient delete\fR \fIkey\fR diff --git a/man/transient-get.1 b/man/transient-get.1 deleted file mode 100644 index b6895c048..000000000 --- a/man/transient-get.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TRANSIENT\-GET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-transient\-get\fR \- Get a transient value\. -. -.SH "SYNOPSIS" -\fBwp transient get\fR \fIkey\fR [\-\-json] diff --git a/man/transient-set.1 b/man/transient-set.1 deleted file mode 100644 index a3addcc59..000000000 --- a/man/transient-set.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TRANSIENT\-SET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-transient\-set\fR \- Set a transient value\. -. -.SH "SYNOPSIS" -\fBwp transient set\fR \fIkey\fR \fIvalue\fR [\fIexpiration\fR] diff --git a/man/transient-type.1 b/man/transient-type.1 deleted file mode 100644 index bdd4b0677..000000000 --- a/man/transient-type.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TRANSIENT\-TYPE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-transient\-type\fR \- See wether the transients API is using an object cache or the options table\. -. -.SH "SYNOPSIS" -\fBwp transient type\fR diff --git a/man/user-meta-add.1 b/man/user-meta-add.1 deleted file mode 100644 index 691c7b6dc..000000000 --- a/man/user-meta-add.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META\-ADD" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\-add\fR \- Add a meta field\. -. -.SH "SYNOPSIS" -\fBwp user\-meta add\fR \fIid\fR \fIkey\fR \fIvalue\fR diff --git a/man/user-meta-delete.1 b/man/user-meta-delete.1 deleted file mode 100644 index 310893ccd..000000000 --- a/man/user-meta-delete.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META\-DELETE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\-delete\fR \- Delete a meta field\. -. -.SH "SYNOPSIS" -\fBwp user\-meta delete\fR \fIid\fR \fIkey\fR diff --git a/man/user-meta-get.1 b/man/user-meta-get.1 deleted file mode 100644 index 1d9ee4b8c..000000000 --- a/man/user-meta-get.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META\-GET" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\-get\fR \- Get meta field value\. -. -.SH "SYNOPSIS" -\fBwp user\-meta get\fR \fIid\fR \fIkey\fR [\-\-json] diff --git a/man/user-meta-update.1 b/man/user-meta-update.1 deleted file mode 100644 index 1e5e44f8f..000000000 --- a/man/user-meta-update.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META\-UPDATE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\-update\fR \- Update a meta field\. -. -.SH "SYNOPSIS" -\fBwp user\-meta update\fR \fIid\fR \fIkey\fR \fIvalue\fR From 566810649598a87785a9c2ae28b9685343016b1d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 19 Mar 2013 17:33:58 +0200 Subject: [PATCH 1423/5359] add missing man src for core update-db --- man-src/core-update-db.txt | 0 man/core-update-db.1 | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 man-src/core-update-db.txt diff --git a/man-src/core-update-db.txt b/man-src/core-update-db.txt new file mode 100644 index 000000000..e69de29bb diff --git a/man/core-update-db.1 b/man/core-update-db.1 index 87d2dbdb9..1dd86294f 100644 --- a/man/core-update-db.1 +++ b/man/core-update-db.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-CORE\-UPDATE\-DB" "1" "October 2012" "" "WP-CLI" +.TH "WP\-CORE\-UPDATE\-DB" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-core\-update\-db\fR \- Update the WordPress database\. . .SH "SYNOPSIS" -\fBwp core update\-db\fR +wp core update\-db From 270b0f6497cb011cac7504fd7d52eae68738eb6f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 20 Mar 2013 18:28:27 +0200 Subject: [PATCH 1424/5359] set version to 0.9.0 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 7fb1aa66f..e7afedfca 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.0-beta' ); +define( 'WP_CLI_VERSION', '0.9.0' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 420605ceb444e90fdef8c30b918fa6ca0ab7443c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 20 Mar 2013 18:33:09 +0200 Subject: [PATCH 1425/5359] update description for media command --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index c053cbca0..36c37ac91 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -1,7 +1,7 @@ <?php /** - * Functionality to control the media library and its attachments + * Control the media library and its attachments. * * @package wp-cli */ From 4a5f0c9d783eda0acb2c570065982b7231b05a9b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Mar 2013 07:28:39 +0200 Subject: [PATCH 1426/5359] convert output_csv() to write_csv() and make it require a file parameter --- php/utils.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/php/utils.php b/php/utils.php index 5a2718636..3997a1547 100644 --- a/php/utils.php +++ b/php/utils.php @@ -257,22 +257,23 @@ function format_items( $format, $fields, $items ) { if ( 'json' == $format ) echo json_encode( $output_items ); else - output_csv( $output_items, $fields ); + write_csv( STDOUT, $output_items, $fields ); break; } } /** - * Output data as CSV + * Write data as CSV to a given file. * - * @param array $rows Array of rows to output - * @param array $headers List of CSV columns (optional) + * @param resource $fd File descriptor + * @param array $rows Array of rows to output + * @param array $headers List of CSV columns (optional) */ -function output_csv( $rows, $headers = array() ) { +function write_csv( $fd, $rows, $headers = array() ) { // Prepare the headers if they were specified if ( ! empty( $headers ) ) - fputcsv( STDOUT, $headers ); + fputcsv( $fd, $headers ); foreach ( $rows as $row ) { $row = (array) $row; @@ -284,7 +285,7 @@ function output_csv( $rows, $headers = array() ) { } $row = $build_row; } - fputcsv( STDOUT, $row ); + fputcsv( $fd, $row ); } } From 46e97a5dfc1d2bc1e66332b7875f32f5057e973a Mon Sep 17 00:00:00 2001 From: Weston Ruter <westonruter@gmail.com> Date: Thu, 21 Mar 2013 17:12:00 -0700 Subject: [PATCH 1427/5359] walk up directory tree to find config file Allows WP-CLI to be invoked from anywhere within a project. You are not limited to being in the directory where the wp-cli*.yml file is. The DOCUMENT_ROOT is then set to the supplied path relative to the config file. --- php/WP_CLI/Runner.php | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ff3fbae7e..945861423 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -17,19 +17,29 @@ public function __get( $key ) { } private static function get_config_path( &$assoc_args ) { - if ( isset( $assoc_args['config'] ) ) { - $paths = array( $assoc_args['config'] ); + if ( isset( $assoc_args['config'] ) && file_exists( $assoc_args['config'] ) ) { + $path = $assoc_args['config']; unset( $assoc_args['config'] ); - } else { - $paths = array( - getcwd() . '/wp-cli.local.yml', - getcwd() . '/wp-cli.yml' - ); + return $path; } - foreach ( $paths as $path ) { - if ( file_exists( $path ) ) - return $path; + $dir = getcwd(); + $config_files = array( + 'wp-cli.local.yml', + 'wp-cli.yml' + ); + while ( is_readable( $dir ) ) { + foreach ( $config_files as $config_file ) { + $path = $dir . DIRECTORY_SEPARATOR . $config_file; + if ( file_exists( $path ) ) { + return $path; + } + } + $parent_dir = dirname( $dir ); + if ( empty($parent_dir) || $parent_dir === $dir ) { + break; + } + $dir = $parent_dir; } return false; @@ -50,6 +60,12 @@ private static function load_config( $path, $spec ) { $sanitized_config[ $key ] = $details['default']; } + // When invoking from a subdirectory in the project, + // make sure a config-relative 'path' is made absolute + if ( ! self::is_absolute_path( $sanitized_config['path'] ) ) { + $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; + } + return $sanitized_config; } @@ -250,7 +266,7 @@ public function before_wp_load() { exit; } - $_SERVER['DOCUMENT_ROOT'] = getcwd(); + $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); // First try at showing man page if ( $this->cmd_starts_with( array( 'help' ) ) ) { From 3c1059fa64af83071f974f709aab86679c4c1758 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Mar 2013 02:38:50 +0200 Subject: [PATCH 1428/5359] contributing: add line about getting feedback --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04fea3104..c90ed7c39 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,7 @@ Contribute So you've got an awesome idea to throw into WP-CLI. Great! Please keep the following in mind: +* The best way to get feedback is by opening an issue or a pull request; if you think the code shouldn't be merged yet, just say so. * If you're adding a new command or subcommand, please consider adding a functional test for it in the `features` directory. Also, please create the appropriate `.txt` file in the `man-src` directory. * Please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). From 7fdf7ab4de049648f3aa8012bae1f4c2a1f1bdd5 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Fri, 22 Mar 2013 01:14:46 -0700 Subject: [PATCH 1429/5359] supply a default to the path config based on an upward search for wp-load.php Add a Utils function for find_file_upward --- php/WP_CLI/Runner.php | 22 +++++++++------------- php/utils.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 945861423..aa506acb2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -23,23 +23,13 @@ private static function get_config_path( &$assoc_args ) { return $path; } - $dir = getcwd(); $config_files = array( 'wp-cli.local.yml', 'wp-cli.yml' ); - while ( is_readable( $dir ) ) { - foreach ( $config_files as $config_file ) { - $path = $dir . DIRECTORY_SEPARATOR . $config_file; - if ( file_exists( $path ) ) { - return $path; - } - } - $parent_dir = dirname( $dir ); - if ( empty($parent_dir) || $parent_dir === $dir ) { - break; - } - $dir = $parent_dir; + $path = Utils\find_file_upward( $config_files, getcwd() ); + if ( $path ) { + return $path; } return false; @@ -229,6 +219,12 @@ public function before_wp_load() { $config_spec = Utils\get_config_spec(); + // Set the path default to the ABSPATH + $wp_abspath = dirname( Utils\find_file_upward( 'wp-load.php' ) ); + if ( ! empty( $wp_abspath ) ) { + $config_spec['path']['default'] = $wp_abspath; + } + $this->config_path = self::get_config_path( $this->assoc_args ); $this->config = self::load_config( $this->config_path, $config_spec ); diff --git a/php/utils.php b/php/utils.php index 3997a1547..6898e7176 100644 --- a/php/utils.php +++ b/php/utils.php @@ -48,6 +48,34 @@ function get_config_spec() { return $spec; } +/** + * Search for file by walking up the directory tree until the first file is found + * @param string|array The files (or file) to search for + * @param string|null The directory to start searching from; defaults to CWD + * @return null|string Null if the file was not found + */ +function find_file_upward($files, $dir = null) { + $files = (array) $files; + if ( is_null( $dir ) ) { + $dir = getcwd(); + } + while ( is_readable( $dir ) ) { + foreach ( $files as $file ) { + $path = $dir . DIRECTORY_SEPARATOR . $file; + if ( file_exists( $path ) ) { + return $path; + } + } + + $parent_dir = dirname( $dir ); + if ( empty($parent_dir) || $parent_dir === $dir ) { + break; + } + $dir = $parent_dir; + } + return null; +} + /** * Splits $argv into positional and associative arguments. * From ef6d541614ded739ba51e74d693c9f852464e8f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Mar 2013 18:34:45 +0200 Subject: [PATCH 1430/5359] fix brace style in Feature Context --- features/bootstrap/FeatureContext.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 071bba1cc..9b20e4d60 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -11,8 +11,8 @@ /** * Features context. */ -class FeatureContext extends BehatContext implements ClosuredContextInterface -{ +class FeatureContext extends BehatContext implements ClosuredContextInterface { + protected static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', @@ -30,8 +30,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface * * @param array $parameters context parameters (set them up through behat.yml) */ - public function __construct( array $parameters ) - { + public function __construct( array $parameters ) { $this->drop_db(); $this->additional_args = array( @@ -50,23 +49,19 @@ public function __construct( array $parameters ) ); } - public function getStepDefinitionResources() - { + public function getStepDefinitionResources() { return array( __DIR__ . '/../steps/basic_steps.php' ); } - public function getHookDefinitionResources() - { + public function getHookDefinitionResources() { return array(); } - public function replace_variables( $str ) - { + public function replace_variables( $str ) { return preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); } - private function _replace_var( $matches ) - { + private function _replace_var( $matches ) { $cmd = $matches[0]; foreach ( array_slice( $matches, 1 ) as $key ) { From bb76c470f09a66b776908d0800a4c4bebf4970b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Mar 2013 18:36:40 +0200 Subject: [PATCH 1431/5359] move define_custom_wp_content_dir() into step definition, since it's only used once --- features/bootstrap/FeatureContext.php | 27 +++------------------------ features/steps/basic_steps.php | 14 +++++++++++++- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 9b20e4d60..1977603a3 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -148,32 +148,11 @@ public function run( $command, $assoc_args = array() ) { return $this->_run( $command, $assoc_args ); } - public function define_custom_wp_content_dir() { - $wp_config_path = $this->install_dir . '/wp-config.php'; - - $wp_config_code = file_get_contents( $wp_config_path ); - - $this->add_line_to_wp_config( $wp_config_code, - "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); - - $this->move_files( 'wp-content', 'my-content' ); - - $this->add_line_to_wp_config( $wp_config_code, - "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); - - $this->move_files( 'my-content/plugins', 'my-plugins' ); - - file_put_contents( $wp_config_path, $wp_config_code ); - } - - private function move_files( $src, $dest ) { - rename( - $this->install_dir . '/' . $src, - $this->install_dir . '/' . $dest - ); + public function move_files( $src, $dest ) { + rename( $this->get_path( $src ), $this->get_path( $dest ) ); } - private function add_line_to_wp_config( &$wp_config_code, $line ) { + public function add_line_to_wp_config( &$wp_config_code, $line ) { $token = "/* That's all, stop editing!"; $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 270e9fa4d..83e4399be 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -44,7 +44,19 @@ function ( $world, $type ) { $steps->Given( '/^custom wp-content directory$/', function ( $world ) { - $world->define_custom_wp_content_dir(); + $wp_config_path = $world->get_path( 'wp-config.php' ); + + $wp_config_code = file_get_contents( $wp_config_path ); + + $world->move_files( 'wp-content', 'my-content' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); + + $world->move_files( 'my-content/plugins', 'my-plugins' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); + + file_put_contents( $wp_config_path, $wp_config_code ); } ); From 1486d9d596d1207584e0781b11df9634e441be66 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 04:45:04 +0200 Subject: [PATCH 1432/5359] use @BeforeSuite hook to initialize $additional_args --- features/bootstrap/FeatureContext.php | 33 ++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 1977603a3..58d300ce5 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -2,7 +2,8 @@ use Behat\Behat\Context\ClosuredContextInterface, Behat\Behat\Context\TranslatedContextInterface, - Behat\Behat\Context\BehatContext; + Behat\Behat\Context\BehatContext, + Behat\Behat\Event\SuiteEvent; require_once 'PHPUnit/Framework/Assert/Functions.php'; @@ -13,27 +14,23 @@ */ class FeatureContext extends BehatContext implements ClosuredContextInterface { - protected static $db_settings = array( + private static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', 'dbpass' => 'password1' ); + private static $additional_args; + private $install_dir; - private $additional_args; public $variables = array(); /** - * Initializes context. - * Every scenario gets it's own context object. - * - * @param array $parameters context parameters (set them up through behat.yml) + * @BeforeSuite */ - public function __construct( array $parameters ) { - $this->drop_db(); - - $this->additional_args = array( + public static function prepare( SuiteEvent $event ) { + self::$additional_args = array( 'core config' => self::$db_settings, 'core install' => array( @@ -49,6 +46,16 @@ public function __construct( array $parameters ) { ); } + /** + * Initializes context. + * Every scenario gets it's own context object. + * + * @param array $parameters context parameters (set them up through behat.yml) + */ + public function __construct( array $parameters ) { + $this->drop_db(); + } + public function getStepDefinitionResources() { return array( __DIR__ . '/../steps/basic_steps.php' ); } @@ -140,8 +147,8 @@ private function _run( $command, $assoc_args ) { } public function run( $command, $assoc_args = array() ) { - if ( isset( $this->additional_args[ $command ] ) ) { - $assoc_args = array_merge( $this->additional_args[ $command ], + if ( isset( self::$additional_args[ $command ] ) ) { + $assoc_args = array_merge( self::$additional_args[ $command ], $assoc_args ); } From 79ff4f68053dbbc80d33d30ccfbefb6adc7e2e61 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 04:52:13 +0200 Subject: [PATCH 1433/5359] change directory, instead of prepending --path --- features/bootstrap/FeatureContext.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 58d300ce5..d37532213 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -81,6 +81,7 @@ private function _replace_var( $matches ) { public function create_empty_dir() { $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); mkdir( $this->install_dir ); + chdir( $this->install_dir ); } public function get_path( $file ) { @@ -121,13 +122,7 @@ private function _run( $command, $assoc_args ) { if ( !empty( $assoc_args ) ) $command .= \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); - if ( false === strpos( $command, '--path' ) ) { - $command = \WP_CLI\Utils\assoc_args_to_str( array( - 'path' => $this->install_dir - ) ) . ' ' . $command; - } - - $sh_command = getcwd() . "/bin/wp $command"; + $sh_command = __DIR__ . "/../../bin/wp $command"; $process = proc_open( $sh_command, array( 0 => STDIN, From 42120584acfdce3e2ea984f0737acfdb300cf314 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 05:01:36 +0200 Subject: [PATCH 1434/5359] make FeatureContext->get_path() return the path unmodified --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d37532213..dfd7fc388 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -85,7 +85,7 @@ public function create_empty_dir() { } public function get_path( $file ) { - return $this->install_dir . '/' . $file; + return $file; } public function get_cache_path( $file ) { From cc29364d4dc1682ab0c9e10d83e37c44a894a057 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 05:14:28 +0200 Subject: [PATCH 1435/5359] prepend './' to relative paths --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index dfd7fc388..dbee25765 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -85,7 +85,7 @@ public function create_empty_dir() { } public function get_path( $file ) { - return $file; + return './' . $file; } public function get_cache_path( $file ) { From 319d7429393bc43ad168dd9b8ddb33e1d8855e28 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 05:41:55 +0200 Subject: [PATCH 1436/5359] pass cwd directly to proc_open() and revert changes to get_path() --- features/bootstrap/FeatureContext.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index dbee25765..2dd41e187 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -81,11 +81,10 @@ private function _replace_var( $matches ) { public function create_empty_dir() { $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); mkdir( $this->install_dir ); - chdir( $this->install_dir ); } public function get_path( $file ) { - return './' . $file; + return $this->install_dir . '/' . $file; } public function get_cache_path( $file ) { @@ -122,13 +121,15 @@ private function _run( $command, $assoc_args ) { if ( !empty( $assoc_args ) ) $command .= \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); - $sh_command = __DIR__ . "/../../bin/wp $command"; + $cmd = __DIR__ . "/../../bin/wp $command"; - $process = proc_open( $sh_command, array( + $descriptors = array( 0 => STDIN, 1 => array( 'pipe', 'w' ), 2 => array( 'pipe', 'w' ), - ), $pipes ); + ); + + $proc = proc_open( $cmd, $descriptors, $pipes, $this->install_dir ); $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); @@ -136,9 +137,11 @@ private function _run( $command, $assoc_args ) { $STDERR = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); - $return_code = proc_close( $process ); + $return_code = proc_close( $proc ); + + $r = (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); - return (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); + return $r; } public function run( $command, $assoc_args = array() ) { From 22599b5271e340920a2869bed2e32b142cf5da08 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 05:53:33 +0200 Subject: [PATCH 1437/5359] split single site from multisite install steps --- features/bootstrap/FeatureContext.php | 8 ++++++++ features/steps/basic_steps.php | 19 +++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 2dd41e187..d7b8740da 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -174,5 +174,13 @@ public function download_wordpress_files() { system( \WP_CLI\Utils\create_cmd( "cp -r %s/* %s/", $cache_dir, $this->install_dir ) ); } + + public function wp_install() { + $this->create_db(); + $this->create_empty_dir(); + $this->download_wordpress_files(); + $this->run( 'core config' ); + $this->run( 'core install' ); + } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 83e4399be..0473c39f8 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -28,17 +28,16 @@ function ( $world ) { } ); -$steps->Given( '/^a WP (install|multisite install)$/', - function ( $world, $type ) { - $world->create_db(); - $world->create_empty_dir(); - $world->download_wordpress_files(); - $world->run( 'core config' ); - $world->run( 'core install' ); +$steps->Given( '/^a WP install$/', + function ( $world ) { + $world->wp_install(); + } +); - if ( 'multisite install' == $type ) { - $world->run( 'core install-network' ); - } +$steps->Given( '/^a WP multisite install$/', + function ( $world ) { + $world->wp_install(); + $world->run( 'core install-network' ); } ); From d6228d520b2b084f804531762f75e9470aeeebc3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 06:43:32 +0200 Subject: [PATCH 1438/5359] add 'cwd' key to FeatureContext->_run() result --- features/bootstrap/FeatureContext.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d7b8740da..61545f42a 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -137,9 +137,13 @@ private function _run( $command, $assoc_args ) { $STDERR = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); - $return_code = proc_close( $proc ); - - $r = (object) compact( 'command', 'return_code', 'STDOUT', 'STDERR' ); + $r = (object) array( + 'command' => $command, + 'STDOUT' => $STDOUT, + 'STDERR' => $STDERR, + 'return_code' => proc_close( $proc ), + 'cwd' => $this->install_dir + ); return $r; } From dd553c2e7e7d8eb0881f784a55ec280d17236b48 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Mar 2013 06:52:52 +0200 Subject: [PATCH 1439/5359] add basic scenarios for wp-cli.yml --- features/config.feature | 26 ++++++++++++++++++++++++++ features/steps/basic_steps.php | 6 ++++++ 2 files changed, 32 insertions(+) create mode 100644 features/config.feature diff --git a/features/config.feature b/features/config.feature new file mode 100644 index 000000000..c61251984 --- /dev/null +++ b/features/config.feature @@ -0,0 +1,26 @@ +Feature: Have a config file + + Scenario: No config file + Given a WP install + """ + """ + + When I run `wp --info` + Then it should run without errors + And STDOUT should not contain: + """ + wp-cli.yml + """ + + Scenario: Config file in WP Root + Given a WP install + And a wp-cli.yml file: + """ + """ + + When I run `wp --info` + Then it should run without errors + And STDOUT should contain: + """ + wp-cli.yml + """ diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 0473c39f8..119b8a90f 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -10,6 +10,12 @@ function ( $world ) { } ); +$steps->Given( '/^a ([^\s]+) file:$/', + function ( $world, $path, PyStringNode $content ) { + file_put_contents( $world->get_path( $path ), (string) $content ); + } +); + $steps->Given( '/^WP files$/', function ( $world ) { $world->download_wordpress_files(); From 8b8721a180439f40795b6838b2308e30d4fd1ea5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Mar 2013 17:18:33 +0200 Subject: [PATCH 1440/5359] add scenario for WP in a subdir --- features/bootstrap/FeatureContext.php | 18 ++++++++++++------ features/config.feature | 11 +++++++++++ features/steps/basic_steps.php | 6 ++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 61545f42a..9776e56d1 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -167,7 +167,7 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); } - public function download_wordpress_files() { + public function download_wordpress_files( $subdir = '' ) { // We cache the results of "wp core download" to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; @@ -176,15 +176,21 @@ public function download_wordpress_files() { 'path' => $cache_dir ) ); - system( \WP_CLI\Utils\create_cmd( "cp -r %s/* %s/", $cache_dir, $this->install_dir ) ); + $dest_dir = $this->get_path( $subdir ); + + if ( $subdir ) mkdir( $dest_dir ); + + $cmd = \WP_CLI\Utils\create_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); + + system( $cmd ); } - public function wp_install() { + public function wp_install( $subdir = '' ) { $this->create_db(); $this->create_empty_dir(); - $this->download_wordpress_files(); - $this->run( 'core config' ); - $this->run( 'core install' ); + $this->download_wordpress_files( $subdir ); + $this->run( 'core config', array( 'path' => $subdir ) ); + $this->run( 'core install', array( 'path' => $subdir ) ); } } diff --git a/features/config.feature b/features/config.feature index c61251984..7d3f51b29 100644 --- a/features/config.feature +++ b/features/config.feature @@ -24,3 +24,14 @@ Feature: Have a config file """ wp-cli.yml """ + + Scenario: WP in a subdirectory + Given a WP install in 'core' + And a wp-cli.yml file: + """ + path: core + """ + + When I run `wp core version` + Then it should run without errors + And STDOUT should not be empty diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 119b8a90f..4a962777e 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -40,6 +40,12 @@ function ( $world ) { } ); +$steps->Given( "/^a WP install in '([^\s]+)'$/", + function ( $world, $subdir ) { + $world->wp_install( $subdir ); + } +); + $steps->Given( '/^a WP multisite install$/', function ( $world ) { $world->wp_install(); From f021f0421f55f6bceb68a93415447bf0086cd09a Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 25 Mar 2013 19:28:56 +0100 Subject: [PATCH 1441/5359] Added behat feature for media regenerate --- features/media.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 features/media.feature diff --git a/features/media.feature b/features/media.feature new file mode 100644 index 000000000..6afe09198 --- /dev/null +++ b/features/media.feature @@ -0,0 +1,11 @@ +Feature: Manage WordPress attachments + + @images + Scenario: Regenerate all images while none exists + Given a WP install + + When I run `wp media regenerate --yes` + Then STDERR should contain: + """ + Error: Unable to find the images + """ From 6ee929c0578ce218a13fb0dbd8b371d9d5fbd68e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Mar 2013 19:42:57 +0200 Subject: [PATCH 1442/5359] 'a custom wp-content directory' --- features/core.feature | 2 +- features/steps/basic_steps.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index d333fbaab..87d06872d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -71,7 +71,7 @@ Feature: Manage WordPress installation Scenario: Custom wp-content directory Given a WP install - And custom wp-content directory + And a custom wp-content directory When I run `wp plugin status hello` Then it should run without errors diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 4a962777e..7e9509e8d 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -53,7 +53,7 @@ function ( $world ) { } ); -$steps->Given( '/^custom wp-content directory$/', +$steps->Given( '/^a custom wp-content directory$/', function ( $world ) { $wp_config_path = $world->get_path( 'wp-config.php' ); From 576b6b60ae9c88ad46245af932fdf0b17c64d1a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Mar 2013 19:48:21 +0200 Subject: [PATCH 1443/5359] add run cmd from subdir step definition --- features/bootstrap/FeatureContext.php | 14 ++++++++------ features/steps/basic_steps.php | 6 ++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 9776e56d1..bf493384d 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -117,10 +117,12 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - private function _run( $command, $assoc_args ) { + private function _run( $command, $assoc_args, $subdir = '' ) { if ( !empty( $assoc_args ) ) $command .= \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); + $subdir = $this->get_path( $subdir ); + $cmd = __DIR__ . "/../../bin/wp $command"; $descriptors = array( @@ -129,7 +131,7 @@ private function _run( $command, $assoc_args ) { 2 => array( 'pipe', 'w' ), ); - $proc = proc_open( $cmd, $descriptors, $pipes, $this->install_dir ); + $proc = proc_open( $cmd, $descriptors, $pipes, $subdir ); $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); @@ -148,13 +150,13 @@ private function _run( $command, $assoc_args ) { return $r; } - public function run( $command, $assoc_args = array() ) { + public function run( $command, $assoc_args = array(), $subdir = '' ) { if ( isset( self::$additional_args[ $command ] ) ) { $assoc_args = array_merge( self::$additional_args[ $command ], $assoc_args ); } - return $this->_run( $command, $assoc_args ); + return $this->_run( $command, $assoc_args, $subdir ); } public function move_files( $src, $dest ) { @@ -189,8 +191,8 @@ public function wp_install( $subdir = '' ) { $this->create_db(); $this->create_empty_dir(); $this->download_wordpress_files( $subdir ); - $this->run( 'core config', array( 'path' => $subdir ) ); - $this->run( 'core install', array( 'path' => $subdir ) ); + $this->run( 'core config', array(), $subdir ); + $this->run( 'core install', array(), $subdir ); } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 7e9509e8d..352bdb77a 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -105,6 +105,12 @@ function ( $world, $cmd ) { } ); +$steps->When( "/^I run `wp (.+)` from '([^\s]+)'$/", + function ( $world, $cmd, $subdir ) { + $world->result = $world->run( $world->replace_variables( $cmd ), array(), $subdir ); + } +); + $steps->When( '/^I run the previous command again$/', function ( $world ) { if ( !isset( $world->result ) ) From 4a0e69568bef2fa148bc3f51d78a81f81c7ae99c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 27 Mar 2013 07:15:03 +0200 Subject: [PATCH 1444/5359] fix comment about param-dump [ci skip] --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ff3fbae7e..78f142344 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -238,7 +238,7 @@ public function before_wp_load() { exit; } - // Handle --cmd-dump parameter + // Handle --param-dump parameter if ( isset( $this->assoc_args['param-dump'] ) ) { \WP_CLI\InternalAssoc::param_dump(); exit; From 9a7e58bed838133254a0b94e897e901d20077b46 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 27 Mar 2013 09:19:54 +0100 Subject: [PATCH 1445/5359] Regenerate Man --- man-src/scaffold-post-type.txt | 4 ++++ man-src/scaffold-taxonomy.txt | 4 ++++ man/scaffold-post-type.1 | 8 +++++++- man/scaffold-taxonomy.1 | 8 +++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/man-src/scaffold-post-type.txt b/man-src/scaffold-post-type.txt index e78108cde..e45952d06 100644 --- a/man-src/scaffold-post-type.txt +++ b/man-src/scaffold-post-type.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `--label=<label>`: + + The text used to translate the update messages + * `--textdomain=<textdomain>`: The textdomain to use for the labels. diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt index 5eac94157..41c7ab375 100644 --- a/man-src/scaffold-taxonomy.txt +++ b/man-src/scaffold-taxonomy.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `--label=<label>`: + + The text used to translate the update messages + * `--textdomain=<textdomain>`: The textdomain to use for the labels. diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 index 5e9223561..1fc921d04 100644 --- a/man/scaffold-post-type.1 +++ b/man/scaffold-post-type.1 @@ -7,11 +7,17 @@ \fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. . .SH "SYNOPSIS" -wp scaffold post\-type \fIslug\fR [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold post\-type \fIslug\fR [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-label=\fIlabel\fR] [\-\-raw] . .SH "OPTIONS" . .TP +\fB\-\-label=<label>\fR: +. +.IP +The text used to translate the update messages +. +.TP \fB\-\-textdomain=<textdomain>\fR: . .IP diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index 6af8faf4f..10f5b5e64 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -7,11 +7,17 @@ \fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. . .SH "SYNOPSIS" -wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] +wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-label=\fIlabel\fR] [\-\-raw] . .SH "OPTIONS" . .TP +\fB\-\-label=<label>\fR: +. +.IP +The text used to translate the update messages +. +.TP \fB\-\-textdomain=<textdomain>\fR: . .IP From 1cf73da8914b9cd1a1a1c4586bd60f633d434d9e Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 27 Mar 2013 09:20:09 +0100 Subject: [PATCH 1446/5359] Added label to tax and cpt --- php/commands/scaffold.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4697c47fb..87a88fbec 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -18,7 +18,7 @@ function __construct() { * * @alias cpt * - * @synopsis <slug> [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--label=<label>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function post_type( $args, $assoc_args ) { $defaults = array( @@ -38,7 +38,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax * - * @synopsis <slug> [--post_types=<post-types>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] + * @synopsis <slug> [--post_types=<post-types>] [--label=<label>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function taxonomy( $args, $assoc_args ) { $defaults = array( @@ -56,6 +56,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) global $wp_filesystem; $control_args = $this->extract_args( $assoc_args, array( + 'label' => $slug, 'theme' => false, 'plugin' => false, 'raw' => false, @@ -67,7 +68,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); - $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $slug ) ); + $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $control_args['label'] ) ); $vars['label_ucfirst'] = ucfirst( $vars['label'] ); $vars['label_plural'] = $this->pluralize( $vars['label'] ); From 245278e94262f32234cf4bb552874a92e15ffc85 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 27 Mar 2013 21:01:38 +0100 Subject: [PATCH 1447/5359] Only preg_replace default $slug --- php/commands/scaffold.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 87a88fbec..5b3fc7919 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -56,7 +56,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) global $wp_filesystem; $control_args = $this->extract_args( $assoc_args, array( - 'label' => $slug, + 'label' => preg_replace( '/_|-/', ' ', strtolower( $slug ) ), 'theme' => false, 'plugin' => false, 'raw' => false, @@ -68,7 +68,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); - $vars['label'] = preg_replace( '/_|-/', ' ', strtolower( $control_args['label'] ) ); + $vars['label'] = $control_args['label']; $vars['label_ucfirst'] = ucfirst( $vars['label'] ); $vars['label_plural'] = $this->pluralize( $vars['label'] ); From d0e20dff194d775ea9f838abec0dfb24322fc534 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Wed, 27 Mar 2013 18:06:17 -0700 Subject: [PATCH 1448/5359] prevent absolutizing a relative config path when it is empty The result was that the config path was erroneously being set to the root / This specifically happened when downloading WordPress via `wp core download` See comment by @scribu: https://github.com/wp-cli/wp-cli/pull/362#issuecomment-15480546 --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index aa506acb2..2bbd33732 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -52,7 +52,7 @@ private static function load_config( $path, $spec ) { // When invoking from a subdirectory in the project, // make sure a config-relative 'path' is made absolute - if ( ! self::is_absolute_path( $sanitized_config['path'] ) ) { + if ( ! empty( $sanitized_config['path'] ) && ! self::is_absolute_path( $sanitized_config['path'] ) ) { $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; } From e302d26feb78e43f013af89111bddfb7bb4eafc2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Mar 2013 04:24:31 +0200 Subject: [PATCH 1449/5359] deb-build: add sudo where appropriate see #368 --- utils/dev-build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/dev-build b/utils/dev-build index bffbaf168..6583a472c 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -3,7 +3,7 @@ # install Composer command -v composer > /dev/null || { curl -sS https://getcomposer.org/installer | php - mv composer.phar /usr/local/bin/composer + sudo mv composer.phar /usr/local/bin/composer } # install dependencies @@ -12,7 +12,7 @@ composer install # add symlink to wp binary for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then - ln -sf $(pwd)/bin/wp $dir/wp + sudo ln -sf $(pwd)/bin/wp $dir/wp break fi done @@ -20,7 +20,7 @@ done # install bash completion file for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do if [ -d $dir ]; then - ln -sf $(pwd)/utils/wp-completion.bash $dir/wp + sudo ln -sf $(pwd)/utils/wp-completion.bash $dir/wp break fi done From 17b2315be9e9bf1d6e269bab23f81ec1f984dcde Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Mar 2013 04:54:23 +0200 Subject: [PATCH 1450/5359] use MYSQL_PWD env variable in FeatureContext->run_sql() --- features/bootstrap/FeatureContext.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index bf493384d..d70fd2be5 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -103,8 +103,10 @@ public function download_file( $url, $path ) { } private static function run_sql( $sql ) { - system( \WP_CLI\Utils\create_cmd( 'mysql -u%s -p%s -e %s', - self::$db_settings['dbuser'], self::$db_settings['dbpass'], $sql ) ); + putenv( 'MYSQL_PWD=' . self::$db_settings['dbpass'] ); + + system( \WP_CLI\Utils\create_cmd( 'mysql -u%s -e %s', + self::$db_settings['dbuser'], $sql ) ); } public function create_db() { From 92957d18f966d6f0e14d0b314019d8a5b59bae3b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Mar 2013 07:22:19 +0200 Subject: [PATCH 1451/5359] add some functional tests for `wp db` --- features/db.feature | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 features/db.feature diff --git a/features/db.feature b/features/db.feature new file mode 100644 index 000000000..1d440234e --- /dev/null +++ b/features/db.feature @@ -0,0 +1,32 @@ +Feature: Perform database operations + + Scenario: DB CRUD + Given an empty directory + And WP files + And wp-config.php + + When I run `wp db create` + Then it should run without errors + And STDOUT should not be empty + + When I run the previous command again + Then the return code should be 1 + + When I run `wp db reset --yes` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp db optimize` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp db repair` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp db query 'SELECT 42 FROM dual'` + Then it should run without errors + And STDOUT should contain: + """ + 42 + """ From f4efbe8e29e7d1413ea65ba9549b9f12a888da4b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Mar 2013 07:22:53 +0200 Subject: [PATCH 1452/5359] use MYSQL_PWD env variable, instead of passing the password as a CLI arg --- php/commands/db.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index f304902d4..5f8d53123 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -65,8 +65,8 @@ function reset( $_, $assoc_args ) { */ function optimize( $_, $assoc_args ) { self::run( $assoc_args, \WP_CLI\Utils\create_cmd( - 'mysqlcheck --optimize --host=%s --user=%s --password=%s %s', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + 'mysqlcheck --optimize --host=%s --user=%s %s', + DB_HOST, DB_USER, DB_NAME ) ); WP_CLI::success( "Database optimized." ); @@ -79,8 +79,8 @@ function optimize( $_, $assoc_args ) { */ function repair( $_, $assoc_args ) { self::run( $assoc_args, \WP_CLI\Utils\create_cmd( - 'mysqlcheck --repair --host=%s --user=%s --password=%s %s', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME + 'mysqlcheck --repair --host=%s --user=%s %s', + DB_HOST, DB_USER, DB_NAME ) ); WP_CLI::success( "Database repaired." ); @@ -119,8 +119,8 @@ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); self::run( $assoc_args, \WP_CLI\Utils\create_cmd( - 'mysqldump %s --user=%s --password=%s --host=%s --result-file %s', - DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); + 'mysqldump %s --user=%s --host=%s --result-file %s', + DB_NAME, DB_USER, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } @@ -134,15 +134,15 @@ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); self::run( $assoc_args, \WP_CLI\Utils\create_cmd( - 'mysql %s --user=%s --password=%s --host=%s < %s', - DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, $result_file ) ); + 'mysql %s --user=%s --host=%s < %s', + DB_NAME, DB_USER, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } private function connect_string() { - return \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --password=%s --database=%s', - DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); + return \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --database=%s', + DB_HOST, DB_USER, DB_NAME ); } private function get_file_name( $args ) { @@ -154,8 +154,8 @@ private function get_file_name( $args ) { private static function create_execute_cmd( $execute_statement ) { return \WP_CLI\Utils\create_cmd( - 'mysql --host=%s --user=%s --password=%s --execute=%s', - DB_HOST, DB_USER, DB_PASSWORD, $execute_statement + 'mysql --host=%s --user=%s --execute=%s', + DB_HOST, DB_USER, $execute_statement ); } @@ -165,7 +165,11 @@ private static function run( $assoc_args, $cmd ) { exit; } + $old_val = getenv( 'MYSQL_PWD' ); + + putenv( 'MYSQL_PWD=' . DB_PASSWORD ); WP_CLI::launch( $cmd ); + putenv( 'MYSQL_PWD=' . $old_val ); } } From 7287e1603f34317e276fecbd76e476f2f381af4d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Mar 2013 07:39:04 +0200 Subject: [PATCH 1453/5359] bump version to 0.9.1-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index e7afedfca..0582ca428 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.0' ); +define( 'WP_CLI_VERSION', '0.9.1-alpha' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 6aefeaaa84a47f7eaabd396ec93239d6f140dc04 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sat, 30 Mar 2013 00:53:28 -0700 Subject: [PATCH 1454/5359] handle edge case finding wp-cli.yml in nested subdirectory installs See comment by @scribu: https://github.com/wp-cli/wp-cli/pull/362#issuecomment-15506011 --- php/WP_CLI/Runner.php | 11 ++++++++++- php/utils.php | 10 ++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2bbd33732..4c58871ad 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -27,7 +27,16 @@ private static function get_config_path( &$assoc_args ) { 'wp-cli.local.yml', 'wp-cli.yml' ); - $path = Utils\find_file_upward( $config_files, getcwd() ); + // Stop looking upward when we find we have emerged from a subdirectory install into a parent install + $stop_check = function ( $dir ) { + static $wp_load_count = 0; + $wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php'; + if ( file_exists( $wp_load_path ) ) { + $wp_load_count += 1; + } + return $wp_load_count > 1; + }; + $path = Utils\find_file_upward( $config_files, getcwd(), $stop_check ); if ( $path ) { return $path; } diff --git a/php/utils.php b/php/utils.php index 6898e7176..eeb6f000b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -49,17 +49,23 @@ function get_config_spec() { } /** - * Search for file by walking up the directory tree until the first file is found + * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true * @param string|array The files (or file) to search for * @param string|null The directory to start searching from; defaults to CWD + * @param callable Function which is passed the current dir each time a directory level is traversed * @return null|string Null if the file was not found */ -function find_file_upward($files, $dir = null) { +function find_file_upward( $files, $dir = null, $stop_check = null ) { $files = (array) $files; if ( is_null( $dir ) ) { $dir = getcwd(); } while ( is_readable( $dir ) ) { + // Stop walking up when the supplied callable returns true being passed the $dir + if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { + return null; + } + foreach ( $files as $file ) { $path = $dir . DIRECTORY_SEPARATOR . $file; if ( file_exists( $path ) ) { From f908a276889830cf2dd001b5a79002aa045d977b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 16:05:26 +0200 Subject: [PATCH 1455/5359] use slug as theme name. closes #372 --- php/commands/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 70d8dad2e..9e8ad5aff 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -126,11 +126,11 @@ protected function install_from_repo( $slug, $assoc_args ) { protected function get_item_list() { $items = array(); - foreach ( wp_get_themes() as $theme ) { + foreach ( wp_get_themes() as $key => $theme ) { $file = $theme->get_stylesheet_directory(); $items[ $file ] = array( - 'name' => $theme->get('Name'), + 'name' => $key, 'status' => $this->get_status( $theme ), 'update' => $this->has_update( $theme->get_stylesheet() ), 'update_id' => $theme->get_stylesheet(), From 8f4a74d0ef21898a38912e6601fa024866bbd4df Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 16:34:19 +0200 Subject: [PATCH 1456/5359] set version to 0.9.1 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 0582ca428..1a15556f6 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.1-alpha' ); +define( 'WP_CLI_VERSION', '0.9.1' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From a7906691d4089013202f2332706de3e31e24add9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 16:59:09 +0200 Subject: [PATCH 1457/5359] update-phar: OSX doesn't ship with md5sum, so use md5 -r --- utils/update-phar | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/utils/update-phar b/utils/update-phar index e7cf98c22..ea79bf112 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -30,7 +30,14 @@ if [ "$new_commit_subj" = "$current_commit_subj" ]; then fi # generate md5 checksum -md5sum $fname | cut -d ' ' -f 1 > $fname.md5 +if [ command -v md5sum > /dev/null ] +then + md5hash=$(md5sum $fname) +else + md5hash=$(md5 -r $fname) +fi + +echo $md5hash | cut -d ' ' -f 1 > $fname.md5 git add $fname $fname.md5 From ff9db7e61b5d78dd8a19659ec6b1aca00e71d0b7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 17:07:01 +0200 Subject: [PATCH 1458/5359] manpages: check for ronn executable before doing anything --- php/WP_CLI/InternalAssoc.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/InternalAssoc.php b/php/WP_CLI/InternalAssoc.php index 6ceae0b09..661d282f4 100644 --- a/php/WP_CLI/InternalAssoc.php +++ b/php/WP_CLI/InternalAssoc.php @@ -57,6 +57,10 @@ static function completions() { } static function man( $args ) { + if ( '' === exec( 'which ronn' ) ) { + WP_CLI::error( '`ronn` executable not found.' ); + } + $arg_copy = $args; $command = WP_CLI::$root; From 9492829660e320b7c80c3391713711da24d81fef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 17:12:19 +0200 Subject: [PATCH 1459/5359] document --force parameter for wp core download --- man-src/core-download.txt | 4 ++++ man/core-download.1 | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/man-src/core-download.txt b/man-src/core-download.txt index 6b85fc3af..74448c986 100644 --- a/man-src/core-download.txt +++ b/man-src/core-download.txt @@ -9,6 +9,10 @@ ignored in this case. Select which version you want to download. +* `--force`: + + Overwrites existing files, if present. + ## EXAMPLES Download version 3.3: wp core download --version=3.3 diff --git a/man/core-download.1 b/man/core-download.1 index 956e22cdc..7f2725d56 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -23,6 +23,12 @@ Select which language you want to download\. The \-\-version parameter is ignore .IP Select which version you want to download\. . +.TP +\fB\-\-force\fR: +. +.IP +Overwrites existing files, if present\. +. .SH "EXAMPLES" . .nf From 82af1db8fb3b81c1f31b892f1a8b1eb6fc4b41c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Mar 2013 20:17:06 +0200 Subject: [PATCH 1460/5359] add tests for running commands from a subdirectory see #362 --- features/config.feature | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/features/config.feature b/features/config.feature index 7d3f51b29..9bb174d7d 100644 --- a/features/config.feature +++ b/features/config.feature @@ -2,8 +2,6 @@ Feature: Have a config file Scenario: No config file Given a WP install - """ - """ When I run `wp --info` Then it should run without errors @@ -12,6 +10,10 @@ Feature: Have a config file wp-cli.yml """ + When I run `wp core is-installed` from 'wp-content' + Then it should run without errors + And STDOUT should be empty + Scenario: Config file in WP Root Given a WP install And a wp-cli.yml file: @@ -25,6 +27,10 @@ Feature: Have a config file wp-cli.yml """ + When I run `wp core is-installed` + Then it should run without errors + And STDOUT should be empty + Scenario: WP in a subdirectory Given a WP install in 'core' And a wp-cli.yml file: @@ -32,6 +38,31 @@ Feature: Have a config file path: core """ - When I run `wp core version` + When I run `wp --info` + Then it should run without errors + And STDOUT should contain: + """ + wp-cli.yml + """ + + When I run `wp core is-installed` Then it should run without errors - And STDOUT should not be empty + And STDOUT should be empty + + When I run `wp core is-installed` from 'core/wp-content' + Then it should run without errors + And STDOUT should be empty + + Scenario: Nested installs + Given a WP install + And a WP install in 'subsite' + And a wp-cli.yml file: + """ + """ + + When I run `wp info` from 'subsite' + And STDOUT should not contain: + """ + wp-cli.yml + """ + From 4b7060d85970761ef519d70f2dc63fafab8e8036 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Mar 2013 19:38:19 +0200 Subject: [PATCH 1461/5359] bump version to 0.10.0-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 1a15556f6..a3bc6cd67 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.9.1' ); +define( 'WP_CLI_VERSION', '0.10.0-alpha' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 655cb3334b367f5090a05f0dbebeac27f1abf5f9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 00:10:14 +0300 Subject: [PATCH 1462/5359] add 'history' command --- php/commands/shell.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 2cdcecbed..3f0eac005 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -13,8 +13,16 @@ public function __invoke() { while ( true ) { $line = self::prompt(); - if ( '' === $line ) - continue; + switch ( $line ) { + case '': { + continue 2; + } + + case 'history': { + self::print_history(); + continue 2; + } + } $line = rtrim( $line, ';' ) . ';'; @@ -79,6 +87,24 @@ private static function create_prompt_cmd( $prompt, $history_path ) { return '/bin/bash -c ' . escapeshellarg( $cmd ); } + private static function print_history() { + $history_file = self::get_history_path(); + + if ( !is_readable( $history_file ) ) + return; + + $lines = array_filter( explode( "\n", file_get_contents( $history_file ) ) ); + + foreach ( $lines as $line ) { + if ( 'history' == $line ) + continue; + + $line = rtrim( $line, ';' ) . ';'; + + echo "$line\n"; + } + } + private static function get_history_path() { $data = getcwd() . get_current_user(); From 1528767a367c1fc12b4934b779243eec457b3a55 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 01:41:23 +0300 Subject: [PATCH 1463/5359] add man page for `wp shell` --- man-src/shell.txt | 5 +++++ man/shell.1 | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 man-src/shell.txt create mode 100644 man/shell.1 diff --git a/man-src/shell.txt b/man-src/shell.txt new file mode 100644 index 000000000..ccd56f493 --- /dev/null +++ b/man-src/shell.txt @@ -0,0 +1,5 @@ +## DESCRIPTION + +`wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. + +If you type `history` and hit Return, WP-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file. diff --git a/man/shell.1 b/man/shell.1 new file mode 100644 index 000000000..de0e717e1 --- /dev/null +++ b/man/shell.1 @@ -0,0 +1,16 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SHELL" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-shell\fR \- Interactive PHP console\. +. +.SH "SYNOPSIS" +wp shell +. +.SH "DESCRIPTION" +\fBwp shell\fR allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment\. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example\. +. +.P +If you type \fBhistory\fR and hit Return, WP\-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file\. From 274f1e26e1d4b9b62ddf7bec4094ba642d5284a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 01:54:56 +0300 Subject: [PATCH 1464/5359] compute the history file path at the beginning this avoids problems if the user calls chdir() --- php/commands/shell.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 3f0eac005..fd32cb6ec 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -10,8 +10,10 @@ class Shell_Command extends \WP_CLI_Command { public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); + $this->set_history_file(); + while ( true ) { - $line = self::prompt(); + $line = $this->prompt(); switch ( $line ) { case '': { @@ -49,11 +51,11 @@ private static function non_expressions() { ) ); } - private static function prompt() { + private function prompt() { static $cmd; if ( !$cmd ) { - $cmd = self::create_prompt_cmd( 'wp> ', self::get_history_path() ); + $cmd = self::create_prompt_cmd( 'wp> ', $this->history_file ); } $fp = popen( $cmd, 'r' ); @@ -87,13 +89,11 @@ private static function create_prompt_cmd( $prompt, $history_path ) { return '/bin/bash -c ' . escapeshellarg( $cmd ); } - private static function print_history() { - $history_file = self::get_history_path(); - - if ( !is_readable( $history_file ) ) + private function print_history() { + if ( !is_readable( $this->history_file ) ) return; - $lines = array_filter( explode( "\n", file_get_contents( $history_file ) ) ); + $lines = array_filter( explode( "\n", file_get_contents( $this->history_file ) ) ); foreach ( $lines as $line ) { if ( 'history' == $line ) @@ -105,10 +105,10 @@ private static function print_history() { } } - private static function get_history_path() { + private function set_history_file() { $data = getcwd() . get_current_user(); - return sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); + $this->history_file = sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); } private static function starts_with( $tokens, $line ) { From 24e45edc6d33385a08ae75349b5050c20d5ef19b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 04:29:14 +0300 Subject: [PATCH 1465/5359] remove --str flag from db subcommands The --str flag assumes that all the information will be passed as CLI arguments, but that's no longer the case since we started using the MYSQL_PWD env variable. And we might want to start using the PDO extension in the future, instead of the `mysql` binary. Also introduce run_mysql_query() utility. --- php/commands/db.php | 104 +++++++++++++++++--------------------------- php/utils.php | 14 ++++++ 2 files changed, 55 insertions(+), 63 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 5f8d53123..ad5be78be 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -10,12 +10,10 @@ class DB_Command extends WP_CLI_Command { /** * Create the database, as specified in wp-config.php * - * @synopsis [--str] + * @synopsis */ function create( $_, $assoc_args ) { - self::run( $assoc_args, self::create_execute_cmd( - sprintf( 'CREATE DATABASE `%s`', DB_NAME ) - ) ); + self::run_query( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); WP_CLI::success( "Database created." ); } @@ -23,48 +21,37 @@ function create( $_, $assoc_args ) { /** * Delete the database. * - * @synopsis [--yes] [--str] + * @synopsis [--yes] */ function drop( $_, $assoc_args ) { - $command = self::create_execute_cmd( sprintf( 'DROP DATABASE `%s`', DB_NAME ) ); - - if ( !isset( $assoc_args['str'] ) ) { - WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); - WP_CLI::launch( $command ); - WP_CLI::success( "Database dropped." ); - } else { - WP_CLI::line( $command ); - } + WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); + + self::run_query( sprintf( 'DROP DATABASE `%s`', DB_NAME ) ); + + WP_CLI::success( "Database dropped." ); } /** * Remove all tables from the database. * - * @synopsis [--yes] [--str] + * @synopsis [--yes] */ function reset( $_, $assoc_args ) { - $drop_cmd = self::create_execute_cmd( sprintf( 'DROP DATABASE IF EXISTS `%s`', DB_NAME ) ); - - $create_cmd = self::create_execute_cmd( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); - - if ( !isset( $assoc_args['str'] ) ) { - WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); - WP_CLI::launch( $drop_cmd ); - WP_CLI::launch( $create_cmd ); - WP_CLI::success( "Database reset." ); - } else { - WP_CLI::line( $drop_cmd ); - WP_CLI::line( $create_cmd ); - } + WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); + + self::run_query( sprintf( 'DROP DATABASE IF EXISTS `%s`', DB_NAME ) ); + self::run_query( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); + + WP_CLI::success( "Database reset." ); } /** * Optimize the database. * - * @synopsis [--str] + * @synopsis */ - function optimize( $_, $assoc_args ) { - self::run( $assoc_args, \WP_CLI\Utils\create_cmd( + function optimize() { + self::run( \WP_CLI\Utils\create_cmd( 'mysqlcheck --optimize --host=%s --user=%s %s', DB_HOST, DB_USER, DB_NAME ) ); @@ -75,13 +62,12 @@ function optimize( $_, $assoc_args ) { /** * Repair the database. * - * @synopsis [--str] + * @synopsis */ - function repair( $_, $assoc_args ) { - self::run( $assoc_args, \WP_CLI\Utils\create_cmd( + function repair() { + self::run( \WP_CLI\Utils\create_cmd( 'mysqlcheck --repair --host=%s --user=%s %s', - DB_HOST, DB_USER, DB_NAME - ) ); + DB_HOST, DB_USER, DB_NAME ) ); WP_CLI::success( "Database repaired." ); } @@ -91,34 +77,35 @@ function repair( $_, $assoc_args ) { * * @alias cli * - * @synopsis [--str] + * @synopsis */ - function connect( $_, $assoc_args ) { - self::run( $assoc_args, $this->connect_string() ); + function connect() { + self::run( \WP_CLI\Utils\create_cmd( + 'mysql --host=%s --user=%s --database=%s', + DB_HOST, DB_USER, DB_NAME ) ); } /** * Execute a query against the database. * - * @synopsis <sql> [--str] + * @synopsis <sql> */ - function query( $args, $assoc_args ) { + function query( $args ) { list( $query ) = $args; - self::run( $assoc_args, $this->connect_string() . \WP_CLI\Utils\create_cmd( - ' --execute=%s', $query ) ); + self::run_query( $query ); } /** * Exports the database using mysqldump. * * @alias dump - * @synopsis [<file>] [--str] + * @synopsis [<file>] */ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( $assoc_args, \WP_CLI\Utils\create_cmd( + self::run( \WP_CLI\Utils\create_cmd( 'mysqldump %s --user=%s --host=%s --result-file %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); @@ -128,23 +115,18 @@ function export( $args, $assoc_args ) { /** * Import database from a file. * - * @synopsis [<file>] [--str] + * @synopsis [<file>] */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( $assoc_args, \WP_CLI\Utils\create_cmd( + self::run( \WP_CLI\Utils\create_cmd( 'mysql %s --user=%s --host=%s < %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } - private function connect_string() { - return \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --database=%s', - DB_HOST, DB_USER, DB_NAME ); - } - private function get_file_name( $args ) { if ( empty( $args ) ) return sprintf( '%s.sql', DB_NAME ); @@ -152,19 +134,15 @@ private function get_file_name( $args ) { return $args[0]; } - private static function create_execute_cmd( $execute_statement ) { - return \WP_CLI\Utils\create_cmd( - 'mysql --host=%s --user=%s --execute=%s', - DB_HOST, DB_USER, $execute_statement - ); + private static function run_query( $query ) { + return \WP_CLI\Utils\run_mysql_query( $query, array( + 'host' => DB_HOST, + 'user' => DB_USER, + 'pass' => DB_PASSWORD, + ) ); } - private static function run( $assoc_args, $cmd ) { - if ( isset( $assoc_args['str'] ) ) { - WP_CLI::line( $cmd ); - exit; - } - + private static function run( $cmd ) { $old_val = getenv( 'MYSQL_PWD' ); putenv( 'MYSQL_PWD=' . DB_PASSWORD ); diff --git a/php/utils.php b/php/utils.php index eeb6f000b..c54e15e6d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -362,3 +362,17 @@ function find_subcommand( $args ) { return $command; } +function run_mysql_query( $query, $args, $dry_run = false ) { + // TODO: use PDO? + + $cmd = \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --execute=%s', + $args['host'], $args['user'], $query + ); + + $old_val = getenv( 'MYSQL_PWD' ); + + putenv( 'MYSQL_PWD=' . $args['pass'] ); + \WP_CLI::launch( $cmd ); + putenv( 'MYSQL_PWD=' . $old_val ); +} + From 624510a6c0774a26f659ee0e28d2f300025256ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 04:38:22 +0300 Subject: [PATCH 1466/5359] create tests database if it doesn't exist --- php/commands/core.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 85a4bcf5e..3e65fccf8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -308,15 +308,30 @@ function init_tests( $args, $assoc_args ) { else $tests_dir = ABSPATH . 'unit-tests/'; + $assoc_args = wp_parse_args( $assoc_args, array( + 'dbpass' => '', + ) ); + + // Download the test suite WP_CLI::launch( 'svn co https://unit-test.svn.wordpress.org/trunk/ ' . escapeshellarg( $tests_dir ) ); + // Create the database + $query = sprintf( 'CREATE DATABASE IF NOT EXISTS `%s`', $assoc_args['dbname'] ); + + \WP_CLI\Utils\run_mysql_query( $query, array( + 'host' => 'localhost', + 'user' => $assoc_args['dbuser'], + 'pass' => $assoc_args['dbpass'], + ) ); + + // Create the wp-tests-config.php file $config_file = file_get_contents( $tests_dir . 'wp-tests-config-sample.php' ); $replacements = array( "dirname( __FILE__ ) . '/wordpress/'" => "'" . ABSPATH . "'", "yourdbnamehere" => $assoc_args['dbname'], "yourusernamehere" => $assoc_args['dbuser'], - "yourpasswordhere" => isset( $assoc_args['dbpass'] ) ? $assoc_args['dbpass'] : '' + "yourpasswordhere" => $assoc_args['dbpass'], ); $config_file = str_replace( array_keys( $replacements ), array_values( $replacements ), $config_file ); From 8dab261b415f928ac5e631d03e36f7dad646d87e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 4 Apr 2013 05:13:56 +0300 Subject: [PATCH 1467/5359] update db man page --- man-src/db.txt | 4 ---- man/db.1 | 18 +++++++++--------- php/commands/db.php | 9 +-------- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/man-src/db.txt b/man-src/db.txt index f160ad01a..e60509350 100644 --- a/man-src/db.txt +++ b/man-src/db.txt @@ -1,9 +1,5 @@ ## OPTIONS -* `--str`: - - Show the mysql command, instead of executing it. - * `--yes`: Answer yes to the confirmation message. diff --git a/man/db.1 b/man/db.1 index 319076f6e..99983e2d3 100644 --- a/man/db.1 +++ b/man/db.1 @@ -7,31 +7,31 @@ \fBwp\-db\fR \- Perform basic database operations\. . .SH "SYNOPSIS" -wp db create [\-\-str] +wp db create . .P -wp db drop [\-\-yes] [\-\-str] +wp db drop [\-\-yes] . .P -wp db reset [\-\-yes] [\-\-str] +wp db reset [\-\-yes] . .P -wp db optimize [\-\-str] +wp db optimize . .P -wp db repair [\-\-str] +wp db repair . .P -wp db connect [\-\-str] +wp db connect . .P -wp db query \fIsql\fR [\-\-str] +wp db query \fIsql\fR . .P -wp db export [\fIfile\fR] [\-\-str] +wp db export [\fIfile\fR] . .P -wp db import [\fIfile\fR] [\-\-str] +wp db import [\fIfile\fR] . .SH "SUBCOMMANDS" . diff --git a/php/commands/db.php b/php/commands/db.php index ad5be78be..fbcf636aa 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -9,8 +9,6 @@ class DB_Command extends WP_CLI_Command { /** * Create the database, as specified in wp-config.php - * - * @synopsis */ function create( $_, $assoc_args ) { self::run_query( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); @@ -47,8 +45,6 @@ function reset( $_, $assoc_args ) { /** * Optimize the database. - * - * @synopsis */ function optimize() { self::run( \WP_CLI\Utils\create_cmd( @@ -61,8 +57,6 @@ function optimize() { /** * Repair the database. - * - * @synopsis */ function repair() { self::run( \WP_CLI\Utils\create_cmd( @@ -76,8 +70,6 @@ function repair() { * Open a mysql console using the WordPress credentials. * * @alias cli - * - * @synopsis */ function connect() { self::run( \WP_CLI\Utils\create_cmd( @@ -100,6 +92,7 @@ function query( $args ) { * Exports the database using mysqldump. * * @alias dump + * * @synopsis [<file>] */ function export( $args, $assoc_args ) { From 5f6db53478f7e462dd189e349e99a6f4b4d95828 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 4 Apr 2013 23:51:02 +0200 Subject: [PATCH 1468/5359] Added label scaffold behat test --- features/scaffold.feature | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 features/scaffold.feature diff --git a/features/scaffold.feature b/features/scaffold.feature new file mode 100644 index 000000000..4a041b95c --- /dev/null +++ b/features/scaffold.feature @@ -0,0 +1,22 @@ +Feature: Wordpress code scaffolding + + @Custom Post Types + Scenario: Scaffold a Custom Post Type with label + Given a WP install + + When I run `wp scaffold post-type zombie --label="Brain eater"` + Then it should run without errors + And STDOUT should contain: + """ + __( 'Brain eaters' + """ + + Scenario: Scaffold a Custom Post Type without the label flag + Given a WP install + + When I run `wp scaffold post-type zombie` + Then it should run without errors + And STDOUT should contain: + """ + __( 'Zombies' + """ \ No newline at end of file From a8ea75807ab01e01a558eedd2e0771f45fc91ecc Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 4 Apr 2013 23:54:12 +0200 Subject: [PATCH 1469/5359] Reorder tests --- features/scaffold.feature | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 4a041b95c..0ced7c3ea 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,6 +1,16 @@ Feature: Wordpress code scaffolding @Custom Post Types + Scenario: Scaffold a Custom Post Type + Given a WP install + + When I run `wp scaffold post-type zombie` + Then it should run without errors + And STDOUT should contain: + """ + __( 'Zombies' + """ + Scenario: Scaffold a Custom Post Type with label Given a WP install @@ -9,14 +19,4 @@ Feature: Wordpress code scaffolding And STDOUT should contain: """ __( 'Brain eaters' - """ - - Scenario: Scaffold a Custom Post Type without the label flag - Given a WP install - - When I run `wp scaffold post-type zombie` - Then it should run without errors - And STDOUT should contain: - """ - __( 'Zombies' - """ \ No newline at end of file + """ \ No newline at end of file From b35b4ef5540e86f53c9590dd3fe7e04e3364e60e Mon Sep 17 00:00:00 2001 From: John Lamp <j3lamp@gmail.com> Date: Thu, 4 Apr 2013 22:26:36 -0400 Subject: [PATCH 1470/5359] Added `post get` command. --- features/post.feature | 15 +++++++++++++++ man-src/post-get.txt | 18 ++++++++++++++++++ man/post-get.1 | 38 ++++++++++++++++++++++++++++++++++++++ php/commands/post.php | 23 ++++++++++++++++++++++- 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 man-src/post-get.txt create mode 100644 man/post-get.1 diff --git a/features/post.feature b/features/post.feature index af7999f42..5fb6dd22d 100644 --- a/features/post.feature +++ b/features/post.feature @@ -27,3 +27,18 @@ Feature: Manage WordPress posts When I run the previous command again Then the return code should be 1 + + Scenario: Creating/geting posts + Given a WP install + + When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` + Then it should run without errors + And STDOUT should match '%d' + And save STDOUT as {POST_ID} + + When I run `wp post get {POST_ID} -` + Then it should run without errors + And STDOUT should be: + """ + Test content. + """ diff --git a/man-src/post-get.txt b/man-src/post-get.txt new file mode 100644 index 000000000..0df8d8952 --- /dev/null +++ b/man-src/post-get.txt @@ -0,0 +1,18 @@ +## OPTIONS + +* `<id>`: + + The ID of the post to get. + +* `<filename>`: + + Write post content to <filename>. + + Passing `-` as the filename will cause post content to + be written to STDOUT. + +## EXAMPLES + + wp post get 12 - + + wp post get 12 file.txt diff --git a/man/post-get.1 b/man/post-get.1 new file mode 100644 index 000000000..0261db57a --- /dev/null +++ b/man/post-get.1 @@ -0,0 +1,38 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-POST\-GET" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-post\-get\fR \- Get a post\'s content by ID\. +. +.SH "SYNOPSIS" +wp post get \fIid\fR \fIfilename\fR +. +.SH "OPTIONS" +. +.TP +\fB<id>\fR: +. +.IP +The ID of the post to get\. +. +.TP +\fB<filename>\fR: +. +.IP +Write post content to \fIfilename\fR\. +. +.IP +Passing \fB\-\fR as the filename will cause post content to be written to STDOUT\. +. +.SH "EXAMPLES" +. +.nf + +wp post get 12 \- + +wp post get 12 file\.txt +. +.fi + diff --git a/php/commands/post.php b/php/commands/post.php index 028afbce0..ff25bce90 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -79,6 +79,28 @@ protected function _edit( $content, $title ) { return \WP_CLI\Utils\launch_editor_for_input( $content, $title ); } + /** + * Get a post's content by ID. + * + * @synopsis <id> <filename> + */ + public function get( $args, $_ ) { + $post_id = $args[0]; + if ( !$post_id || !$post = get_post( $post_id ) ) + \WP_CLI::error( "Failed opening post $post_id to get." ); + + if ( $args[1] !== '-' ) { + $writefile = $args[1]; + if ( ! file_exists( $writefile ) || ! is_file( $writefile ) ) + \WP_CLI::error( "Unable to write content to $writefile." ); + } else + $writefile = 'php://stdout'; + + $r = file_put_contents( $writefile, $post->post_content ); + if ( $r === false ) + \WP_CLI::error( "Failed to write content to $writefile." ); + } + /** * Delete a post by ID. * @@ -241,4 +263,3 @@ private function maybe_reset_depth() { } WP_CLI::add_command( 'post', 'Post_Command' ); - From df325ba4790eff06d727b23510e3ae2ca3af9512 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Fri, 5 Apr 2013 12:27:45 +0200 Subject: [PATCH 1471/5359] Removed feature tag --- features/scaffold.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 0ced7c3ea..5c966f080 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,6 +1,5 @@ Feature: Wordpress code scaffolding - @Custom Post Types Scenario: Scaffold a Custom Post Type Given a WP install From 0bcaa756c60e55dc04ff42e09461ad3540325952 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 5 Apr 2013 21:21:20 +0300 Subject: [PATCH 1472/5359] add --defaults-file=/dev/null to mysql commands --- php/commands/db.php | 33 ++++++++++++++++----------------- php/utils.php | 17 +++++++++++------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index fbcf636aa..300b82740 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -1,5 +1,7 @@ <?php +use \WP_CLI\Utils; + /** * Perform basic database operations. * @@ -47,8 +49,8 @@ function reset( $_, $assoc_args ) { * Optimize the database. */ function optimize() { - self::run( \WP_CLI\Utils\create_cmd( - 'mysqlcheck --optimize --host=%s --user=%s %s', + self::run( 'mysqlcheck', Utils\create_cmd( + '--optimize --host=%s --user=%s %s', DB_HOST, DB_USER, DB_NAME ) ); @@ -59,8 +61,8 @@ function optimize() { * Repair the database. */ function repair() { - self::run( \WP_CLI\Utils\create_cmd( - 'mysqlcheck --repair --host=%s --user=%s %s', + self::run( 'mysqlcheck', Utils\create_cmd( + '--repair --host=%s --user=%s %s', DB_HOST, DB_USER, DB_NAME ) ); WP_CLI::success( "Database repaired." ); @@ -72,8 +74,8 @@ function repair() { * @alias cli */ function connect() { - self::run( \WP_CLI\Utils\create_cmd( - 'mysql --host=%s --user=%s --database=%s', + self::run( 'mysql', Utils\create_cmd( + '--host=%s --user=%s --database=%s', DB_HOST, DB_USER, DB_NAME ) ); } @@ -98,8 +100,8 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( \WP_CLI\Utils\create_cmd( - 'mysqldump %s --user=%s --host=%s --result-file %s', + self::run( 'mysqldump', Utils\create_cmd( + '%s --user=%s --host=%s --result-file %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); @@ -113,8 +115,8 @@ function export( $args, $assoc_args ) { function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( \WP_CLI\Utils\create_cmd( - 'mysql %s --user=%s --host=%s < %s', + self::run( 'mysql', Utils\create_cmd( + '%s --user=%s --host=%s < %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); @@ -128,20 +130,17 @@ private function get_file_name( $args ) { } private static function run_query( $query ) { - return \WP_CLI\Utils\run_mysql_query( $query, array( + Utils\run_mysql_query( $query, array( 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASSWORD, ) ); } - private static function run( $cmd ) { - $old_val = getenv( 'MYSQL_PWD' ); - - putenv( 'MYSQL_PWD=' . DB_PASSWORD ); - WP_CLI::launch( $cmd ); - putenv( 'MYSQL_PWD=' . $old_val ); + private static function run( $cmd, $args ) { + Utils\run_mysql_command( $cmd, $args, DB_PASSWORD ); } } WP_CLI::add_command( 'db', 'DB_Command' ); + diff --git a/php/utils.php b/php/utils.php index c54e15e6d..73e89b9ef 100644 --- a/php/utils.php +++ b/php/utils.php @@ -362,17 +362,22 @@ function find_subcommand( $args ) { return $command; } -function run_mysql_query( $query, $args, $dry_run = false ) { +function run_mysql_query( $query, $args ) { // TODO: use PDO? - $cmd = \WP_CLI\Utils\create_cmd( 'mysql --host=%s --user=%s --execute=%s', - $args['host'], $args['user'], $query - ); + $arg_str = create_cmd( '--host=%s --user=%s --execute=%s', + $args['host'], $args['user'], $query ); + + run_mysql_command( 'mysql', $arg_str, $args['pass'] ); +} +function run_mysql_command( $cmd, $arg_str, $pass ) { $old_val = getenv( 'MYSQL_PWD' ); - putenv( 'MYSQL_PWD=' . $args['pass'] ); - \WP_CLI::launch( $cmd ); + $final_cmd = "$cmd --defaults-file=/dev/null $arg_str"; + + putenv( 'MYSQL_PWD=' . $pass ); + \WP_CLI::launch( $final_cmd ); putenv( 'MYSQL_PWD=' . $old_val ); } From 981542f3d8ca0f18fa8431252c7b1976487a13ce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 5 Apr 2013 22:05:15 +0300 Subject: [PATCH 1473/5359] use run_mysql_query() in functional tests too --- features/bootstrap/FeatureContext.php | 19 +++++++++++-------- php/utils.php | 4 +++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d70fd2be5..07038d3e8 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -5,6 +5,8 @@ Behat\Behat\Context\BehatContext, Behat\Behat\Event\SuiteEvent; +use \WP_CLI\Utils; + require_once 'PHPUnit/Framework/Assert/Functions.php'; require_once __DIR__ . '/../../php/utils.php'; @@ -92,21 +94,22 @@ public function get_cache_path( $file ) { if ( !$path ) { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - system( \WP_CLI\Utils\create_cmd( 'mkdir -p %s', $path ) ); + system( Utils\create_cmd( 'mkdir -p %s', $path ) ); } return $path . '/' . $file; } public function download_file( $url, $path ) { - system( \WP_CLI\Utils\create_cmd( 'curl -sSL %s > %s', $url, $path ) ); + system( Utils\create_cmd( 'curl -sSL %s > %s', $url, $path ) ); } private static function run_sql( $sql ) { - putenv( 'MYSQL_PWD=' . self::$db_settings['dbpass'] ); - - system( \WP_CLI\Utils\create_cmd( 'mysql -u%s -e %s', - self::$db_settings['dbuser'], $sql ) ); + Utils\run_mysql_query( $sql, array( + 'host' => 'localhost', + 'user' => self::$db_settings['dbuser'], + 'pass' => self::$db_settings['dbpass'], + ) ); } public function create_db() { @@ -121,7 +124,7 @@ public function drop_db() { private function _run( $command, $assoc_args, $subdir = '' ) { if ( !empty( $assoc_args ) ) - $command .= \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); + $command .= Utils\assoc_args_to_str( $assoc_args ); $subdir = $this->get_path( $subdir ); @@ -184,7 +187,7 @@ public function download_wordpress_files( $subdir = '' ) { if ( $subdir ) mkdir( $dest_dir ); - $cmd = \WP_CLI\Utils\create_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); + $cmd = Utils\create_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); system( $cmd ); } diff --git a/php/utils.php b/php/utils.php index 73e89b9ef..51f25b541 100644 --- a/php/utils.php +++ b/php/utils.php @@ -377,7 +377,9 @@ function run_mysql_command( $cmd, $arg_str, $pass ) { $final_cmd = "$cmd --defaults-file=/dev/null $arg_str"; putenv( 'MYSQL_PWD=' . $pass ); - \WP_CLI::launch( $final_cmd ); + $r = proc_close( proc_open( $final_cmd, array( STDIN, STDOUT, STDERR ), $pipes ) ); putenv( 'MYSQL_PWD=' . $old_val ); + + if ( $r ) exit( $r ); } From d92d3bdf653aa2d128d1ce3a639fabda84b248eb Mon Sep 17 00:00:00 2001 From: John Lamp <j3lamp@gmail.com> Date: Fri, 5 Apr 2013 17:23:23 -0400 Subject: [PATCH 1474/5359] Removed the <filename> argument from `post get`. --- features/post.feature | 8 ++++---- man-src/post-get.txt | 11 ++--------- man/post-get.1 | 15 +++------------ php/commands/post.php | 13 ++----------- 4 files changed, 11 insertions(+), 36 deletions(-) diff --git a/features/post.feature b/features/post.feature index 5fb6dd22d..874609063 100644 --- a/features/post.feature +++ b/features/post.feature @@ -36,9 +36,9 @@ Feature: Manage WordPress posts And STDOUT should match '%d' And save STDOUT as {POST_ID} - When I run `wp post get {POST_ID} -` + When I run `wp post get {POST_ID}` Then it should run without errors And STDOUT should be: - """ - Test content. - """ + """ + Test content. + """ diff --git a/man-src/post-get.txt b/man-src/post-get.txt index 0df8d8952..38d10df7c 100644 --- a/man-src/post-get.txt +++ b/man-src/post-get.txt @@ -4,15 +4,8 @@ The ID of the post to get. -* `<filename>`: - - Write post content to <filename>. - - Passing `-` as the filename will cause post content to - be written to STDOUT. - ## EXAMPLES - wp post get 12 - + wp post get 12 - wp post get 12 file.txt + wp post get 12 > file.txt diff --git a/man/post-get.1 b/man/post-get.1 index 0261db57a..766655143 100644 --- a/man/post-get.1 +++ b/man/post-get.1 @@ -7,7 +7,7 @@ \fBwp\-post\-get\fR \- Get a post\'s content by ID\. . .SH "SYNOPSIS" -wp post get \fIid\fR \fIfilename\fR +wp post get \fIid\fR . .SH "OPTIONS" . @@ -17,22 +17,13 @@ wp post get \fIid\fR \fIfilename\fR .IP The ID of the post to get\. . -.TP -\fB<filename>\fR: -. -.IP -Write post content to \fIfilename\fR\. -. -.IP -Passing \fB\-\fR as the filename will cause post content to be written to STDOUT\. -. .SH "EXAMPLES" . .nf -wp post get 12 \- +wp post get 12 -wp post get 12 file\.txt +wp post get 12 > file\.txt . .fi diff --git a/php/commands/post.php b/php/commands/post.php index ff25bce90..e2bd93436 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -82,23 +82,14 @@ protected function _edit( $content, $title ) { /** * Get a post's content by ID. * - * @synopsis <id> <filename> + * @synopsis <id> */ public function get( $args, $_ ) { $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) \WP_CLI::error( "Failed opening post $post_id to get." ); - if ( $args[1] !== '-' ) { - $writefile = $args[1]; - if ( ! file_exists( $writefile ) || ! is_file( $writefile ) ) - \WP_CLI::error( "Unable to write content to $writefile." ); - } else - $writefile = 'php://stdout'; - - $r = file_put_contents( $writefile, $post->post_content ); - if ( $r === false ) - \WP_CLI::error( "Failed to write content to $writefile." ); + echo($post->post_content); } /** From e57c9ea38f243eefc1e17168f113bf960c63b17e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 9 Apr 2013 20:39:44 +0300 Subject: [PATCH 1475/5359] tests: add IF NOT EXISTS to create_db() --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 07038d3e8..fd2fdf2d9 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -114,7 +114,7 @@ private static function run_sql( $sql ) { public function create_db() { $dbname = self::$db_settings['dbname']; - self::run_sql( "CREATE DATABASE $dbname" ); + self::run_sql( "CREATE DATABASE IF NOT EXISTS $dbname" ); } public function drop_db() { From fbf53ad262f50f27cc55762d55e2c6bf8d630617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20Burc=C4=83?= <scribu@gmail.com> Date: Fri, 12 Apr 2013 17:24:02 +0300 Subject: [PATCH 1476/5359] be more explicit about which code is covered by the MIT license --- LICENSE.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index bd624ddd0..1b2b49c65 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,8 +1,8 @@ -======================================== -WP-CLI is licensed under the MIT License -======================================== +========================================================================================================= +All code in this repository, unless otherwise specified, is hereby licensed under the MIT Public License: +========================================================================================================= -Copyright (C) 2011-2012 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) +Copyright (C) 2011-2013 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From a134ce6e46561e9f36ee5efeb33e69ad97b97141 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 12 Apr 2013 08:59:13 -0700 Subject: [PATCH 1477/5359] Correct file permissions to 755 --- php/commands/scaffold.php | 0 php/wp-cli.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 php/commands/scaffold.php mode change 100644 => 100755 php/wp-cli.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php old mode 100644 new mode 100755 diff --git a/php/wp-cli.php b/php/wp-cli.php old mode 100644 new mode 100755 From ea6b75fa6fb7268e4abc1fa657837abc916c3a59 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 12 Apr 2013 09:47:39 -0700 Subject: [PATCH 1478/5359] Revert a134ce6e46561e9f36ee5efeb33e69ad97b97141 See https://github.com/wp-cli/wp-cli/commit/a134ce6e46561e9f36ee5efeb33e69ad97b97141#commitcomment-3001898 --- php/commands/scaffold.php | 0 php/wp-cli.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 php/commands/scaffold.php mode change 100755 => 100644 php/wp-cli.php diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php old mode 100755 new mode 100644 diff --git a/php/wp-cli.php b/php/wp-cli.php old mode 100755 new mode 100644 From 5aaaa1ab8dd6cf678514e38c8bf8f6234cf0b691 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 12 Apr 2013 10:06:16 -0700 Subject: [PATCH 1479/5359] Support for `--format` when using `wp post list` --- man-src/post-list.txt | 6 ++++++ man/post-list.1 | 10 +++++++++- php/commands/post.php | 26 +++++++++++++++----------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/man-src/post-list.txt b/man-src/post-list.txt index 295f102c0..ad6786367 100644 --- a/man-src/post-list.txt +++ b/man-src/post-list.txt @@ -8,8 +8,14 @@ Return only the IDs of the found posts, separated by spaces. +* `--format`=<format>: + + Output list as table, CSV or JSON. Defaults to table. + ## EXAMPLES wp post list wp post list --post_type=page --post_status=draft --ids + + wp post list --post_type=post --posts_per_page=5 --format=json diff --git a/man/post-list.1 b/man/post-list.1 index 299c62aaa..85a82be0e 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] +wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -23,6 +23,12 @@ One or more args to pass to WP_Query\. .IP Return only the IDs of the found posts, separated by spaces\. . +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. +. .SH "EXAMPLES" . .nf @@ -30,6 +36,8 @@ Return only the IDs of the found posts, separated by spaces\. wp post list wp post list \-\-post_type=page \-\-post_status=draft \-\-ids + +wp post list \-\-post_type=post \-\-posts_per_page=5 \-\-format=json . .fi diff --git a/php/commands/post.php b/php/commands/post.php index 028afbce0..645df962e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -108,13 +108,20 @@ protected function _delete( $post_id, $assoc_args ) { * Get a list of posts. * * @subcommand list - * @synopsis [--<field>=<value>] [--ids] + * @synopsis [--<field>=<value>] [--ids] [--format=<format>] */ public function _list( $_, $assoc_args ) { $query_args = array( 'posts_per_page' => -1 ); + if ( ! empty( $assoc_args['format'] ) ) { + $format = $assoc_args['format']; + unset( $assoc_args['format'] ); + } else { + $format = 'table'; + } + foreach ( $assoc_args as $key => $value ) { if ( true === $value ) continue; @@ -130,24 +137,21 @@ public function _list( $_, $assoc_args ) { if ( isset( $assoc_args['ids'] ) ) { WP_CLI::out( implode( ' ', $query->posts ) ); } else { - $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); - - $table = new \cli\Table(); - $table->setHeaders( $fields ); + $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); + $output_posts = array(); foreach ( $query->posts as $post ) { - $line = array(); + $output_post = new stdClass; foreach ( $fields as $field ) { - $line[] = $post->$field; + $output_post->$field = $post->$field; } - - $table->addRow( $line ); + $output_posts[] = $output_post; } - - $table->display(); + WP_CLI\Utils\format_items( $format, $fields, $output_posts ); } + } /** From b0c0f6f36f36fda11c13f68bfe364e2b5278833d Mon Sep 17 00:00:00 2001 From: Tim Brayshaw <tim@brayshaw.com> Date: Sat, 13 Apr 2013 00:10:15 +0100 Subject: [PATCH 1480/5359] Fix example for 'core is-installed' --- man-src/core-is-installed.txt | 2 +- man/core-is-installed.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/core-is-installed.txt b/man-src/core-is-installed.txt index 6432d0e66..e4901fe31 100644 --- a/man-src/core-is-installed.txt +++ b/man-src/core-is-installed.txt @@ -1,5 +1,5 @@ ## EXAMPLES -if [ ! $(wp core is-installed) ]; then +if ! $(wp core is-installed); then wp core install fi diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 index ac423ae11..0aab8f72c 100644 --- a/man/core-is-installed.1 +++ b/man/core-is-installed.1 @@ -10,7 +10,7 @@ wp core is\-installed . .SH "EXAMPLES" -if [ ! $(wp core is\-installed) ]; then +if ! $(wp core is\-installed); then . .IP "" 4 . From cfae9d7894891947492a4a9c61f8ee933d54c6b4 Mon Sep 17 00:00:00 2001 From: John Lamp <j3lamp@gmail.com> Date: Fri, 12 Apr 2013 21:21:33 -0400 Subject: [PATCH 1481/5359] Added the `--feature` option for `post get`. --- features/post.feature | 34 +++++++++++++++++++ features/steps/basic_steps.php | 60 ++++++++++++++++++++++++++++++++++ man-src/post-get.txt | 13 ++++++++ man/post-get.1 | 20 +++++++++++- php/commands/post.php | 57 ++++++++++++++++++++++++++------ 5 files changed, 173 insertions(+), 11 deletions(-) diff --git a/features/post.feature b/features/post.feature index 874609063..74f6cd842 100644 --- a/features/post.feature +++ b/features/post.feature @@ -42,3 +42,37 @@ Feature: Manage WordPress posts """ Test content. """ + + When I run `wp post get --format=content {POST_ID}` + Then it should run without errors + And STDOUT should be: + """ + Test content. + """ + + When I run `wp post get --format=table {POST_ID}` + Then it should run without errors + And STDOUT should be a table containing rows: + """ + Field Value + ID {POST_ID} + post_title Test post + post_content Test content. + """ + + When I run `wp post get --format=csv {POST_ID}` + Then it should run without errors + And STDOUT should be a table containing rows: + """ + Field,Value + ID,{POST_ID} + post_title,"Test post" + post_content,"Test content." + """ + + When I run `wp post get --format=json {POST_ID}` + Then it should run without errors + And STDOUT should be JSON containing: + """ + {"ID":{POST_ID},"post_title":"Test post","post_content":"Test content."} + """ diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 352bdb77a..d6eb182e0 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -178,6 +178,41 @@ function ( $world, $stream, $format ) { } ); +$steps->Then( '/^STDOUT should be a table containing rows:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->STDOUT; + $outputRows = explode( "\n", rtrim( $output, "\n" ) ); + + $expected = $world->replace_variables( (string) $expected ); + $expectedRows = explode( "\n", rtrim( $expected, "\n" ) ); + + // the first row is the header and must be present + if ( $expectedRows[0] != $outputRows[0] ) { + throw new \Exception( $output ); + } + + unset($outputRows[0]); + unset($expectedRows[0]); + $matches = array_intersect( $expectedRows, $outputRows ); + if ( count( $expectedRows ) != count( $matches ) ) { + throw new \Exception( $output ); + } + } +); + +$steps->Then( '/^STDOUT should be JSON containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->STDOUT; + $outputJson = json_decode( $output ); + + $expected = $world->replace_variables( (string) $expected ); + $expectedJson = json_decode( $expected ); + + if ( !compareJson( $expectedJson, $outputJson ) ) { + throw new \Exception( $output ); + } +}); + $steps->Then( '/^(STDOUT|STDERR) should be empty$/', function ( $world, $stream ) { if ( !empty( $world->result->$stream ) ) { @@ -197,3 +232,28 @@ function ( $world, $path ) { assertFileExists( $world->get_path( $path ) ); } ); + + +function compareJson( $expected, $actual ) { + if ( gettype( $expected ) != gettype( $actual ) ) { + return false; + } + + if ( is_object( $expected ) ) { + foreach ( get_object_vars( $expected ) as $name => $value ) { + if ( !compareJson( $value, $actual->$name ) ) { + return false; + } + } + } else if ( is_array( $expected ) ) { + foreach ( $expected as $key => $value ) { + if ( !compareJson( $value, $actual[$key] ) ) { + return false; + } + } + } else { + return $expected === $actual; + } + + return true; +} diff --git a/man-src/post-get.txt b/man-src/post-get.txt index 38d10df7c..ff20d1df9 100644 --- a/man-src/post-get.txt +++ b/man-src/post-get.txt @@ -1,5 +1,18 @@ ## OPTIONS +* `[--format=<format>]`: + + The format to use when printing the post, acceptable values: + + content: outputs only the post's content (default) + + table: output all fields of the post as a table, note that the + post_content field is output last to simplify parsing + + csv: output all fields in Comma Separated Value format + + json: output all fields in JavaScript Object Notation format + * `<id>`: The ID of the post to get. diff --git a/man/post-get.1 b/man/post-get.1 index 766655143..1a44a8296 100644 --- a/man/post-get.1 +++ b/man/post-get.1 @@ -7,11 +7,29 @@ \fBwp\-post\-get\fR \- Get a post\'s content by ID\. . .SH "SYNOPSIS" -wp post get \fIid\fR +wp post get [\-\-format=\fIformat\fR] \fIid\fR . .SH "OPTIONS" . .TP +\fB[\-\-format=<format>]\fR: +. +.IP +The format to use when printing the post, acceptable values: +. +.IP +content: outputs only the post\'s content (default) +. +.IP +table: output all fields of the post as a table, note that the post_content field is output last to simplify parsing +. +.IP +csv: output all fields in Comma Separated Value format +. +.IP +json: output all fields in JavaScript Object Notation format +. +.TP \fB<id>\fR: . .IP diff --git a/php/commands/post.php b/php/commands/post.php index e2bd93436..b84d19349 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -65,14 +65,14 @@ protected function _update( $params ) { public function edit( $args, $_ ) { $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) - \WP_CLI::error( "Failed opening post $post_id to edit." ); + \WP_CLI::error( "Failed opening post $post_id to edit." ); $r = $this->_edit( $post->post_content, "WP-CLI post $post_id" ); if ( $r === false ) - \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); + \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); else - parent::update( $args, array( 'post_content' => $r ) ); + parent::update( $args, array( 'post_content' => $r ) ); } protected function _edit( $content, $title ) { @@ -80,16 +80,53 @@ protected function _edit( $content, $title ) { } /** - * Get a post's content by ID. - * - * @synopsis <id> - */ - public function get( $args, $_ ) { + * Get a post's content by ID. + * + * @synopsis [--format=<format>] <id> + */ + public function get( $args, $assoc_args ) { + $assoc_args = wp_parse_args( $assoc_args, array( + 'format' => 'content' + ) ); + $format = $assoc_args['format']; + $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) - \WP_CLI::error( "Failed opening post $post_id to get." ); + \WP_CLI::error( "Failed opening post $post_id to get." ); + + switch ( $assoc_args['format'] ) { + + case 'content': + echo($post->post_content); + break; - echo($post->post_content); + case 'table': + case 'csv': + $items = array(); + foreach ( get_object_vars( $post ) as $field => $value ) { + if ( 'post_content' === $field ) + continue; + + $item = new \stdClass; + $item->Field = $field; + $item->Value = $value; + $items[] = $item; + } + $content = new \stdClass; + $content->Field = 'post_content'; + $content->Value = $post->post_content; + $items[] = $content; + + \WP_CLI\Utils\format_items( $format, array( 'Field', 'Value' ), $items ); + break; + + case 'json': + echo( json_encode( $post ) ); + break; + + default: + \WP_CLI::error( "Invalid value for format: " . $format ); + } } /** From b98df06b1562c3aa7c0f2128661d015c27b524f5 Mon Sep 17 00:00:00 2001 From: John Lamp <j3lamp@gmail.com> Date: Sat, 13 Apr 2013 20:46:32 -0400 Subject: [PATCH 1482/5359] Removed CSV format from `post get`, with JSON format it is redundent, etc. Removed the `post_content` field from the table format output as the table becomes unweildy and the extremely long value of the content or the content itself causes problems with the table processing. Besides, chances are if one wanted the contents and the other fields JSON would be easier anyway. --- features/post.feature | 11 ----------- man-src/post-get.txt | 4 +--- man/post-get.1 | 5 +---- php/commands/post.php | 14 ++++++++------ 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/features/post.feature b/features/post.feature index 74f6cd842..ee5efed9d 100644 --- a/features/post.feature +++ b/features/post.feature @@ -57,17 +57,6 @@ Feature: Manage WordPress posts Field Value ID {POST_ID} post_title Test post - post_content Test content. - """ - - When I run `wp post get --format=csv {POST_ID}` - Then it should run without errors - And STDOUT should be a table containing rows: - """ - Field,Value - ID,{POST_ID} - post_title,"Test post" - post_content,"Test content." """ When I run `wp post get --format=json {POST_ID}` diff --git a/man-src/post-get.txt b/man-src/post-get.txt index ff20d1df9..fab4fdeb3 100644 --- a/man-src/post-get.txt +++ b/man-src/post-get.txt @@ -7,9 +7,7 @@ content: outputs only the post's content (default) table: output all fields of the post as a table, note that the - post_content field is output last to simplify parsing - - csv: output all fields in Comma Separated Value format + post_content field is omitted so that the table is readable json: output all fields in JavaScript Object Notation format diff --git a/man/post-get.1 b/man/post-get.1 index 1a44a8296..67511f013 100644 --- a/man/post-get.1 +++ b/man/post-get.1 @@ -21,10 +21,7 @@ The format to use when printing the post, acceptable values: content: outputs only the post\'s content (default) . .IP -table: output all fields of the post as a table, note that the post_content field is output last to simplify parsing -. -.IP -csv: output all fields in Comma Separated Value format +table: output all fields of the post as a table, note that the post_content field is omitted so that the table is readable . .IP json: output all fields in JavaScript Object Notation format diff --git a/php/commands/post.php b/php/commands/post.php index b84d19349..d87f903a8 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -20,7 +20,7 @@ public function create( $args, $assoc_args ) { if ( $args[0] !== '-' ) { $readfile = $args[0]; if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) - \WP_CLI::error( "Unable to read content from $readfile." ); + \WP_CLI::error( "Unable to read content from $readfile." ); } else $readfile = 'php://stdin'; @@ -101,31 +101,33 @@ public function get( $args, $assoc_args ) { break; case 'table': - case 'csv': $items = array(); foreach ( get_object_vars( $post ) as $field => $value ) { if ( 'post_content' === $field ) continue; + if ( !is_string($value) ) { + $value = json_encode($value); + } + $item = new \stdClass; $item->Field = $field; $item->Value = $value; $items[] = $item; } - $content = new \stdClass; - $content->Field = 'post_content'; - $content->Value = $post->post_content; - $items[] = $content; \WP_CLI\Utils\format_items( $format, array( 'Field', 'Value' ), $items ); break; case 'json': echo( json_encode( $post ) ); + echo( "\n" ); break; default: \WP_CLI::error( "Invalid value for format: " . $format ); + break; + } } From 0b52bebd0c6c1a3a4bcd4ed3846e4c03e9aed67c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Apr 2013 22:11:05 +0300 Subject: [PATCH 1483/5359] move iterators to separate namespace --- php/WP_CLI/{CSVIterator.php => Iterators/CSV.php} | 4 ++-- php/WP_CLI/Iterators/Exception.php | 6 ++++++ php/WP_CLI/{QueryIterator.php => Iterators/Query.php} | 10 ++++------ php/WP_CLI/{TableIterator.php => Iterators/Table.php} | 8 ++++---- php/commands/role.php | 2 +- php/commands/search-replace.php | 2 +- php/commands/user.php | 2 +- 7 files changed, 19 insertions(+), 15 deletions(-) rename php/WP_CLI/{CSVIterator.php => Iterators/CSV.php} (95%) create mode 100644 php/WP_CLI/Iterators/Exception.php rename php/WP_CLI/{QueryIterator.php => Iterators/Query.php} (86%) rename php/WP_CLI/{TableIterator.php => Iterators/Table.php} (86%) diff --git a/php/WP_CLI/CSVIterator.php b/php/WP_CLI/Iterators/CSV.php similarity index 95% rename from php/WP_CLI/CSVIterator.php rename to php/WP_CLI/Iterators/CSV.php index 46a3bf9c0..dde3fb51c 100644 --- a/php/WP_CLI/CSVIterator.php +++ b/php/WP_CLI/Iterators/CSV.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Iterators; -class CSVIterator implements \Iterator { +class CSV implements \Iterator { const ROW_SIZE = 4096; diff --git a/php/WP_CLI/Iterators/Exception.php b/php/WP_CLI/Iterators/Exception.php new file mode 100644 index 000000000..e7320e077 --- /dev/null +++ b/php/WP_CLI/Iterators/Exception.php @@ -0,0 +1,6 @@ +<?php + +namespace WP_CLI\Iterators; + +class Exception extends \RuntimeException {} + diff --git a/php/WP_CLI/QueryIterator.php b/php/WP_CLI/Iterators/Query.php similarity index 86% rename from php/WP_CLI/QueryIterator.php rename to php/WP_CLI/Iterators/Query.php index 3962d1108..195458624 100644 --- a/php/WP_CLI/QueryIterator.php +++ b/php/WP_CLI/Iterators/Query.php @@ -1,13 +1,13 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Iterators; /** * Iterates over results of a query, split into many queries via LIMIT and OFFSET * * @source https://gist.github.com/4060005 */ -class QueryIterator implements \Iterator { +class Query implements \Iterator { private $limit = 500; private $query = ''; @@ -24,7 +24,7 @@ class QueryIterator implements \Iterator { * * This will loop over all users, but will retrieve them 100 by 100: * <code> - * foreach( new QueryIterator( array( 'query' => 'SELECT * FROM users', 'limit' => 100 ) ) as $user ) { + * foreach( new Iterators\Query( array( 'query' => 'SELECT * FROM users', 'limit' => 100 ) ) as $user ) { * tickle( $user ); * } * </code> @@ -49,7 +49,7 @@ function load_items_from_db() { $this->results = $this->db->get_results( $query ); if ( !$this->results ) { if ( $this->db->last_error ) { - throw new QueryIteratorException( 'Database error: '.$this->db->last_error ); + throw new Iterators\Exception( 'Database error: '.$this->db->last_error ); } else { return false; } @@ -96,5 +96,3 @@ function valid() { } } -class QueryIteratorException extends \RuntimeException {} - diff --git a/php/WP_CLI/TableIterator.php b/php/WP_CLI/Iterators/Table.php similarity index 86% rename from php/WP_CLI/TableIterator.php rename to php/WP_CLI/Iterators/Table.php index ef8bf8905..fb807d0a1 100644 --- a/php/WP_CLI/TableIterator.php +++ b/php/WP_CLI/Iterators/Table.php @@ -1,23 +1,23 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Iterators; /** * @source https://gist.github.com/4060005 */ -class TableIterator extends QueryIterator { +class Table extends Iterators\Query { /** * Creates an iterator over a database table * * <code> - * foreach( new TableIterator( array( 'table' => $wpdb->posts, 'fields' => array( 'ID', 'post_content' ) ) ) as $post ) { + * foreach( new Iterators\Table( array( 'table' => $wpdb->posts, 'fields' => array( 'ID', 'post_content' ) ) ) as $post ) { * count_words_for( $post->ID, $post->post_content ); * } * </code> * * <code> - * foreach( new TableIterator( array( 'table' => $wpdb->posts, 'where' => 'ID = 8 OR post_status = "publish"' ) ) as $post ) { + * foreach( new Iterators\Table( array( 'table' => $wpdb->posts, 'where' => 'ID = 8 OR post_status = "publish"' ) ) as $post ) { * … * } * </code> diff --git a/php/commands/role.php b/php/commands/role.php index 8f2e0765c..88c43b0de 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -109,4 +109,4 @@ private static function persistence_check() { } } -WP_CLI::add_command( 'role', 'Role_Command' ); \ No newline at end of file +WP_CLI::add_command( 'role', 'Role_Command' ); diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f46cc2790..607ccd28d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -62,7 +62,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'limit' => 1000 ); - $it = new \WP_CLI\TableIterator( $args ); + $it = new \WP_CLI\Iterators\Table( $args ); $count = 0; diff --git a/php/commands/user.php b/php/commands/user.php index f867204e1..b2fdc7911 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -300,7 +300,7 @@ public function import_csv( $args, $assoc_args ) { $filename = $args[0]; - foreach ( new \WP_CLI\CSVIterator( $filename ) as $i => $new_user ) { + foreach ( new \WP_CLI\Iterators\CSV( $filename ) as $i => $new_user ) { $defaults = array( 'role' => get_option('default_role'), 'user_pass' => wp_generate_password(), From 72e10a40a2d9f8a33832d08f73a35cd23c468d2e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Apr 2013 22:18:42 +0300 Subject: [PATCH 1484/5359] on OS X, wc -l inexplicably outputs whitespace before the result --- features/user.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index d1d034a9e..e725dcedc 100644 --- a/features/user.feature +++ b/features/user.feature @@ -35,7 +35,7 @@ Feature: Manage WordPress users When I run `wp user generate --count=10` Then it should run without errors - When I run `wp user list | wc -l` + When I run `wp user list | wc -l | tr -d ' '` Then STDOUT should be: """ 11 From a4460e3cfdb313ca8051fb1b00dfb7042ba1ea22 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Apr 2013 23:13:56 +0300 Subject: [PATCH 1485/5359] add smoke test for search-replace --- features/search-replace.feature | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 features/search-replace.feature diff --git a/features/search-replace.feature b/features/search-replace.feature new file mode 100644 index 000000000..34241c880 --- /dev/null +++ b/features/search-replace.feature @@ -0,0 +1,8 @@ +Feature: Do global search/replace + + Scenario: Basic search/replace + Given a WP install + + When I run `wp search-replace foo bar` + Then it should run without errors + And STDOUT should not be empty From e960694560527f26f801c7bb5a37f9e293fb2aba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Apr 2013 23:17:07 +0300 Subject: [PATCH 1486/5359] fix class reference in Iterators/Table.php --- php/WP_CLI/Iterators/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index fb807d0a1..eade2ca1d 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -5,7 +5,7 @@ /** * @source https://gist.github.com/4060005 */ -class Table extends Iterators\Query { +class Table extends Query { /** * Creates an iterator over a database table From 6f0870761e644bf4e47ffb7e6a012b974c61d913 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Apr 2013 00:57:16 +0300 Subject: [PATCH 1487/5359] add smoke test for wp user import-csv --- features/user.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/features/user.feature b/features/user.feature index e725dcedc..316b534d5 100644 --- a/features/user.feature +++ b/features/user.feature @@ -40,3 +40,23 @@ Feature: Manage WordPress users """ 11 """ + + Scenario: Importing users from a CSV file + Given a WP install + And a users.csv file: + """ + user_login, user_email, display_name, role + bobjones, bobjones@domain.com, Bob Jones, contributor + newuser1, newuser1@domain.com, New User, author + admin, admin@domain.com, Existing User, administrator + """ + + When I run `wp user import-csv users.csv` + Then it should run without errors + + When I run `wp user list | wc -l | tr -d ' '` + Then STDOUT should be: + """ + 4 + """ + From 3ab5140e621dba66defc878a9cbdc1f92cfd57d9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Apr 2013 02:37:32 +0300 Subject: [PATCH 1488/5359] make query string mandatory first parameter in Iterators\Query constructor see #390 --- php/WP_CLI/Iterators/Query.php | 19 +++++++------------ php/WP_CLI/Iterators/Table.php | 9 ++++----- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 195458624..523e300d2 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -24,24 +24,19 @@ class Query implements \Iterator { * * This will loop over all users, but will retrieve them 100 by 100: * <code> - * foreach( new Iterators\Query( array( 'query' => 'SELECT * FROM users', 'limit' => 100 ) ) as $user ) { + * foreach( new Iterators\Query( 'SELECT * FROM users', 100 ) as $user ) { * tickle( $user ); * } * </code> * - * - * @param array $args Supported arguments: - * query – the query as a string. It shouldn't include any LIMIT clauses - * limit – (optional) how many rows to retrieve at once, default value is 500 + * @param string $query The query as a string. It shouldn't include any LIMIT clauses + * @param number $limit How many rows to retrieve at once; default value is 500 (optional) */ - function __construct( $args = array() ) { + public function __construct( $query, $limit = 500 ) { + $this->query = $query; + $this->limit = $limit; + $this->db = $GLOBALS['wpdb']; - foreach( $args as $key => $value ) { - $this->$key = $value; - } - if ( !$this->query ) { - throw new InvalidArgumentException( 'Missing query argument.' ); - } } function load_items_from_db() { diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index eade2ca1d..825bf265e 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -52,11 +52,10 @@ function __construct( $args = array() ) { $conditions = self::build_where_conditions( $args['where'] ); $where_sql = $conditions? " WHERE $conditions" : ''; $query = "SELECT $fields FROM $table $where_sql"; - $parent_args = compact( 'query' ); - if ( isset( $args['limit'] ) ) { - $parent_args['limit'] = $args['limit']; - } - parent::__construct( $parent_args ); + + $limit = isset( $args['limit'] ) ? $args['limit'] : 500; + + parent::__construct( $query, $limit ); } static function build_fields( $fields ) { From bf9e77f409199d947147bfa880ad6e06cd7eace4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Apr 2013 02:38:23 +0300 Subject: [PATCH 1489/5359] mark some iterator methods as private see #390 --- php/WP_CLI/Iterators/Query.php | 14 ++++++++++---- php/WP_CLI/Iterators/Table.php | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 523e300d2..1577e99ab 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -39,22 +39,24 @@ public function __construct( $query, $limit = 500 ) { $this->db = $GLOBALS['wpdb']; } - function load_items_from_db() { + private function load_items_from_db() { $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->limit, $this->offset ); $this->results = $this->db->get_results( $query ); + if ( !$this->results ) { if ( $this->db->last_error ) { - throw new Iterators\Exception( 'Database error: '.$this->db->last_error ); + throw new Iterators\Exception( 'Database error: ' . $this->db->last_error ); } else { return false; } } + $this->offset += $this->limit; return true; } function current() { - return $this->results[$this->index_in_results]; + return $this->results[ $this->index_in_results ]; } function key() { @@ -78,15 +80,19 @@ function valid() { if ( $this->depleted ) { return false; } - if ( !isset( $this->results[$this->index_in_results] ) ) { + + if ( !isset( $this->results[ $this->index_in_results ] ) ) { $items_loaded = $this->load_items_from_db(); + if ( !$items_loaded ) { $this->rewind(); $this->depleted = true; return false; } + $this->index_in_results = 0; } + return true; } } diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 825bf265e..450301ae2 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -58,11 +58,11 @@ function __construct( $args = array() ) { parent::__construct( $query, $limit ); } - static function build_fields( $fields ) { + private static function build_fields( $fields ) { return implode( ', ', $fields ); } - static function build_where_conditions( $where ) { + private static function build_where_conditions( $where ) { global $wpdb; if ( is_array( $where ) ) { $conditions = array(); From 3aae56760cf6e7e3eb0df0efc2cf6d7234a291a8 Mon Sep 17 00:00:00 2001 From: John Lamp <j3lamp@gmail.com> Date: Sun, 14 Apr 2013 22:29:30 -0400 Subject: [PATCH 1490/5359] Refactored the poorly named `compareJson()` function into the more accurate `checkThatJsonStringContainsJsonString()` function which encapsulates the calls to `json_decode()`. --- features/steps/basic_steps.php | 77 ++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index d6eb182e0..5f03ada13 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -203,12 +203,11 @@ function ( $world, PyStringNode $expected ) { $steps->Then( '/^STDOUT should be JSON containing:$/', function ( $world, PyStringNode $expected ) { $output = $world->result->STDOUT; - $outputJson = json_decode( $output ); $expected = $world->replace_variables( (string) $expected ); - $expectedJson = json_decode( $expected ); - if ( !compareJson( $expectedJson, $outputJson ) ) { + if ( !checkThatJsonStringContainsJsonString( $output, + $expected ) ) { throw new \Exception( $output ); } }); @@ -234,26 +233,70 @@ function ( $world, $path ) { ); -function compareJson( $expected, $actual ) { - if ( gettype( $expected ) != gettype( $actual ) ) { +/** + * Compare two strings containing JSON to ensure that @a $actualJson contains at + * least what the JSON string @a $expectedJson contains. + * + * @return whether or not @a $actualJson contains @a $expectedJson + * @retval true @a $actualJson contains @a $expectedJson + * @retval false @a $actualJson does not contain @a $expectedJson + * + * @param[in] $actualJson the JSON string to be tested + * @param[in] $expectedJson the expected JSON string + * + * Examples: + * expected: {'a':1,'array':[1,3,5]} + * + * 1) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: true + * + * 2) + * actual: {'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * element 'a' is missing from the root object + * + * 3) + * actual: {'a':0,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * the value of element 'a' is not 1 + * + * 4) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,4,5]} + * return: false + * the contents of 'array' does not include 3 + */ +function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { + $actualValue = json_decode( $actualJson ); + $expectedValue = json_decode( $expectedJson ); + + if ( !$actualValue ) { return false; } - if ( is_object( $expected ) ) { - foreach ( get_object_vars( $expected ) as $name => $value ) { - if ( !compareJson( $value, $actual->$name ) ) { - return false; - } + function compareContents( $expected, $actual ) { + if ( gettype( $expected ) != gettype( $actual ) ) { + return false; } - } else if ( is_array( $expected ) ) { - foreach ( $expected as $key => $value ) { - if ( !compareJson( $value, $actual[$key] ) ) { - return false; + + if ( is_object( $expected ) ) { + foreach ( get_object_vars( $expected ) as $name => $value ) { + if ( !compareContents( $value, $actual->$name ) ) { + return false; + } } + } else if ( is_array( $expected ) ) { + foreach ( $expected as $key => $value ) { + if ( !compareContents( $value, $actual[$key] ) ) { + return false; + } + } + } else { + return $expected === $actual; } - } else { - return $expected === $actual; + + return true; } - return true; + return compareContents( $expectedValue, $actualValue ); } From 9bf27efa2a2c7fa9000ea88200611f9a2ee61033 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Wed, 17 Apr 2013 01:12:09 +0200 Subject: [PATCH 1491/5359] Fixed query_var using slug instead of boolean TRUE --- templates/taxonomy.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 20747a722..5d82234e3 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -3,7 +3,7 @@ 'public' => true, 'show_in_nav_menus' => true, 'show_ui' => true, - 'query_var' => {{slug}}, + 'query_var' => true, 'rewrite' => true, 'capabilities' => array( 'manage_terms' => 'edit_posts', From f917293010981a6240b66ed23049ca07ef696417 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Apr 2013 18:24:58 -0700 Subject: [PATCH 1492/5359] Ignore composer.phar, as it's installed separately from the project --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0e7aef903..325d475d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +composer.phar /vendor /phpunit.xml From f739e5388307ff02d7241fc04893e8fa49179950 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Apr 2013 19:03:11 -0700 Subject: [PATCH 1493/5359] Functional test for creating / listing a term --- features/steps/basic_steps.php | 7 +++++++ features/term.feature | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 features/term.feature diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 5f03ada13..64ab158cb 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -142,6 +142,13 @@ function ( $world ) { } ); +$steps->Then( '/^it should run with errors$/' , + function ( $world ) { + if ( empty( $world->result->STDERR ) ) + throw new \Exception( "No error produced" ); + } +); + $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { $output = $world->result->$stream; diff --git a/features/term.feature b/features/term.feature new file mode 100644 index 000000000..268fba52a --- /dev/null +++ b/features/term.feature @@ -0,0 +1,25 @@ +Feature: Manage WordPress terms + + Scenario: Creating/listing a term + Given a WP install + + When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` + Then it should run without errors + And STDOUT should be: + """ + Success: Term created. + """ + + When I run the previous command again + Then it should run with errors + And STDERR should be: + """ + Error: A term with the name provided already exists. + """ + + When I run `wp term list post_tag --format=json` + Then it should run without errors + And STDOUT should be JSON containing: + """ + [{"term_id":"2","term_taxonomy_id":"2","name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] + """ \ No newline at end of file From 4076050a8342e64a197ec24a1dbfe0516b8d6029 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Apr 2013 19:14:15 -0700 Subject: [PATCH 1494/5359] Newline fix for failed test --- features/term.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 268fba52a..9698050bc 100644 --- a/features/term.feature +++ b/features/term.feature @@ -22,4 +22,4 @@ Feature: Manage WordPress terms And STDOUT should be JSON containing: """ [{"term_id":"2","term_taxonomy_id":"2","name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] - """ \ No newline at end of file + """ From 8f0ce253fb203c0486be185741f438b8716296f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Apr 2013 20:35:29 -0700 Subject: [PATCH 1495/5359] Actually fix failing tests. Functions defined inside of functions cause everything to fatal when the parent function is called twice. --- features/steps/basic_steps.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 64ab158cb..0414f2a5f 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -281,6 +281,7 @@ function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { return false; } + if ( ! function_exists( 'compareContents' ) ) : function compareContents( $expected, $actual ) { if ( gettype( $expected ) != gettype( $actual ) ) { return false; @@ -304,6 +305,7 @@ function compareContents( $expected, $actual ) { return true; } + endif; return compareContents( $expectedValue, $actualValue ); } From b908f81bc637027cd166c6b7658e9ddf51832d50 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 13:28:03 -0700 Subject: [PATCH 1496/5359] Move declaration of compareContents() outside of a function, to avoid fatals when the function is declared twice See https://github.com/wp-cli/wp-cli/pull/398/files#r3869537 --- features/steps/basic_steps.php | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 0414f2a5f..9de39f064 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -281,31 +281,29 @@ function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { return false; } - if ( ! function_exists( 'compareContents' ) ) : - function compareContents( $expected, $actual ) { - if ( gettype( $expected ) != gettype( $actual ) ) { - return false; - } + return compareContents( $expectedValue, $actualValue ); +} + +function compareContents( $expected, $actual ) { + if ( gettype( $expected ) != gettype( $actual ) ) { + return false; + } - if ( is_object( $expected ) ) { - foreach ( get_object_vars( $expected ) as $name => $value ) { - if ( !compareContents( $value, $actual->$name ) ) { - return false; - } + if ( is_object( $expected ) ) { + foreach ( get_object_vars( $expected ) as $name => $value ) { + if ( !compareContents( $value, $actual->$name ) ) { + return false; } - } else if ( is_array( $expected ) ) { - foreach ( $expected as $key => $value ) { - if ( !compareContents( $value, $actual[$key] ) ) { - return false; - } + } + } else if ( is_array( $expected ) ) { + foreach ( $expected as $key => $value ) { + if ( !compareContents( $value, $actual[$key] ) ) { + return false; } - } else { - return $expected === $actual; } - - return true; + } else { + return $expected === $actual; } - endif; - return compareContents( $expectedValue, $actualValue ); -} + return true; +} \ No newline at end of file From 395a9c8097fbfa4a46ee36b9c7303351538d2e9a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 13:30:55 -0700 Subject: [PATCH 1497/5359] Skip checking these numeric fields, as they might change during the tests See https://github.com/wp-cli/wp-cli/pull/398/files#r3869915 --- features/term.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 9698050bc..8c29b0021 100644 --- a/features/term.feature +++ b/features/term.feature @@ -21,5 +21,5 @@ Feature: Manage WordPress terms Then it should run without errors And STDOUT should be JSON containing: """ - [{"term_id":"2","term_taxonomy_id":"2","name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] + [{"name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] """ From dbd057a968c2d04d0119a1f1a5df9b5e5b934b76 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 13:33:52 -0700 Subject: [PATCH 1498/5359] Simplify expression of the run with errors condition See https://github.com/wp-cli/wp-cli/pull/398/files#r3869578 --- features/steps/basic_steps.php | 7 ------- features/term.feature | 6 +----- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 9de39f064..4e1d8c2bf 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -142,13 +142,6 @@ function ( $world ) { } ); -$steps->Then( '/^it should run with errors$/' , - function ( $world ) { - if ( empty( $world->result->STDERR ) ) - throw new \Exception( "No error produced" ); - } -); - $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { $output = $world->result->$stream; diff --git a/features/term.feature b/features/term.feature index 8c29b0021..e8be1655b 100644 --- a/features/term.feature +++ b/features/term.feature @@ -11,11 +11,7 @@ Feature: Manage WordPress terms """ When I run the previous command again - Then it should run with errors - And STDERR should be: - """ - Error: A term with the name provided already exists. - """ + Then STDERR should not be empty When I run `wp term list post_tag --format=json` Then it should run without errors From b62bd52fa7d1706376ed1c8609b0ae43e6d55c14 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 00:10:28 +0300 Subject: [PATCH 1499/5359] rename `scaffold child_theme` to `scaffold child-theme` --- php/commands/scaffold.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b63720148..4b76b6ce5 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -149,6 +149,8 @@ function _s( $args, $assoc_args ) { /** * Generate empty child theme (twentytwelve by default). * + * @subcommand child-theme + * * @synopsis <slug> [--theme_name=<title>] [--parent_theme=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] */ function child_theme( $args, $assoc_args ) { @@ -166,14 +168,14 @@ function child_theme( $args, $assoc_args ) { $data['theme_description'] = ucfirst($data['parent_theme']) . " child theme. "; - + $theme_dir = $theme_path . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; $this->create_file( $theme_style_path, $this->render( 'child_theme.mustache', $data ) ); WP_CLI::success( "Created $theme_dir" ); - + if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); From 1b1be354eee3ad35bbac32d87005479fe7955e3a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 00:14:37 +0300 Subject: [PATCH 1500/5359] make --parent_theme mandatory --- php/commands/scaffold.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4b76b6ce5..281f97e4d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -151,7 +151,7 @@ function _s( $args, $assoc_args ) { * * @subcommand child-theme * - * @synopsis <slug> [--theme_name=<title>] [--parent_theme=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] + * @synopsis <slug> --parent_theme=<title> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] */ function child_theme( $args, $assoc_args ) { @@ -160,7 +160,6 @@ function child_theme( $args, $assoc_args ) { $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), - 'parent_theme' => 'twentytwelve', 'author' => "Me", 'author_uri' => "", 'theme_uri' => "" From 8cb137677286fe31b56b51b4f9c24ad805db8695 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 00:19:08 +0300 Subject: [PATCH 1501/5359] style fixes for scaffold child-theme --- php/commands/scaffold.php | 9 ++------- templates/child_theme.mustache | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 281f97e4d..b7a5f9e30 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -154,9 +154,7 @@ function _s( $args, $assoc_args ) { * @synopsis <slug> --parent_theme=<title> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] */ function child_theme( $args, $assoc_args ) { - $theme_slug = $args[0]; - $theme_path = WP_CONTENT_DIR . "/themes"; $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), @@ -165,20 +163,17 @@ function child_theme( $args, $assoc_args ) { 'theme_uri' => "" ) ); - $data['theme_description'] = ucfirst($data['parent_theme']) . " child theme. "; - + $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; - $theme_dir = $theme_path . "/$theme_slug"; + $theme_dir = WP_CONTENT_DIR . "themes" . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; $this->create_file( $theme_style_path, $this->render( 'child_theme.mustache', $data ) ); WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } private function get_output_path( $assoc_args, $subdir ) { diff --git a/templates/child_theme.mustache b/templates/child_theme.mustache index a6b182b82..6e96440f1 100644 --- a/templates/child_theme.mustache +++ b/templates/child_theme.mustache @@ -1,11 +1,11 @@ /* Theme Name: {{theme_name}} Theme URI: {{theme_uri}} -Description: {{theme_description}} +Description: {{description}} Author: {{author}} Author URI: {{author_uri}} Template: {{parent_theme}} Version: 0.1.0 */ -@import '../{{parent_theme}}/style.css'; \ No newline at end of file +@import '../{{parent_theme}}/style.css'; From 8443a96168bcea0b13c9dad5db5446752ec3929d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 00:26:38 +0300 Subject: [PATCH 1502/5359] add man page for scaffold child-theme. see #339 --- man-src/scaffold-child-theme.txt | 29 +++++++++++++++++ man/scaffold-child-theme.1 | 55 ++++++++++++++++++++++++++++++++ php/commands/scaffold.php | 4 +-- 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 man-src/scaffold-child-theme.txt create mode 100644 man/scaffold-child-theme.1 diff --git a/man-src/scaffold-child-theme.txt b/man-src/scaffold-child-theme.txt new file mode 100644 index 000000000..2f05ab25f --- /dev/null +++ b/man-src/scaffold-child-theme.txt @@ -0,0 +1,29 @@ +## OPTIONS + +* <slug>: + + The slug for the new child theme. + +* `--parent_theme=<slug>`: + + What to put in the 'Template:' header in style.css + +* `--theme_name=<title>`: + + What to put in the 'Theme Name:' header in style.css + +* `--author=<full name>`: + + What to put in the 'Author:' header in style.css + +* `--author_uri=<http url>`: + + What to put in the 'Author URI:' header in style.css + +* `--theme_uri=<http url>`: + + What to put in the 'Theme URI:' header in style.css + +* `--activate`: + + Activate the newly created child theme. diff --git a/man/scaffold-child-theme.1 b/man/scaffold-child-theme.1 new file mode 100644 index 000000000..67fa5bcd3 --- /dev/null +++ b/man/scaffold-child-theme.1 @@ -0,0 +1,55 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SCAFFOLD\-CHILD\-THEME" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-scaffold\-child\-theme\fR \- Generate empty child theme\. +. +.SH "SYNOPSIS" +wp scaffold child\-theme \fIslug\fR \-\-parent_theme=\fIslug\fR [\-\-theme_name=\fItitle\fR] [\-\-author=\fIfull\-name\fR] [\-\-author_uri=\fIhttp\-url\fR] [\-\-theme_uri=\fIhttp\-url\fR] [\-\-activate] +. +.SH "OPTIONS" +. +.TP +\fIslug\fR: +. +.IP +The slug for the new child theme\. +. +.TP +\fB\-\-parent_theme=<slug>\fR: +. +.IP +What to put in the \'Template:\' header in style\.css +. +.TP +\fB\-\-theme_name=<title>\fR: +. +.IP +What to put in the \'Theme Name:\' header in style\.css +. +.TP +\fB\-\-author=<full name>\fR: +. +.IP +What to put in the \'Author:\' header in style\.css +. +.TP +\fB\-\-author_uri=<http url>\fR: +. +.IP +What to put in the \'Author URI:\' header in style\.css +. +.TP +\fB\-\-theme_uri=<http url>\fR: +. +.IP +What to put in the \'Theme URI:\' header in style\.css +. +.TP +\fB\-\-activate\fR: +. +.IP +Activate the newly created child theme\. + diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 69a72d89a..b43e87a13 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -148,11 +148,11 @@ function _s( $args, $assoc_args ) { } /** - * Generate empty child theme (twentytwelve by default). + * Generate empty child theme. * * @subcommand child-theme * - * @synopsis <slug> --parent_theme=<title> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] + * @synopsis <slug> --parent_theme=<slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] */ function child_theme( $args, $assoc_args ) { $theme_slug = $args[0]; From ae1d943ec09c6ef4bc67c725a7cc4e7e89c663ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Apr 2013 21:04:17 -0700 Subject: [PATCH 1503/5359] wp term list: Support for `--ids` argument --- man-src/term-list.txt | 4 ++++ man/term-list.1 | 8 +++++++- php/commands/term.php | 29 +++++++++++++++++------------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/man-src/term-list.txt b/man-src/term-list.txt index f991f2558..32e01215d 100644 --- a/man-src/term-list.txt +++ b/man-src/term-list.txt @@ -4,6 +4,10 @@ List terms of a given taxonomy. +* `--ids`: + + Return only the term ids of the found terms, separated by spaces. + * `--format`=<format>: Output list as table, CSV or JSON. Defaults to table. diff --git a/man/term-list.1 b/man/term-list.1 index 060772fdd..88d47ab96 100644 --- a/man/term-list.1 +++ b/man/term-list.1 @@ -7,7 +7,7 @@ \fBwp\-term\-list\fR \- List terms in a taxonomy\. . .SH "SYNOPSIS" -wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] +wp term list \fItaxonomy\fR [\-\-ids] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -18,6 +18,12 @@ wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] List terms of a given taxonomy\. . .TP +\fB\-\-ids\fR: +. +.IP +Return only the term ids of the found terms, separated by spaces\. +. +.TP \fB\-\-format\fR=\fIformat\fR: . .IP diff --git a/php/commands/term.php b/php/commands/term.php index 9c4e82a1e..4679a3312 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -10,7 +10,7 @@ class Term_Command extends WP_CLI_Command { * List terms in a taxonomy. * * @subcommand list - * @synopsis <taxonomy> [--format=<format>] + * @synopsis <taxonomy> [--ids] [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -24,17 +24,22 @@ public function _list( $args, $assoc_args ) { $terms = get_terms( array( $taxonomy ), $assoc_args ); - $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', - ); - - WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); + if ( isset( $assoc_args['ids'] ) ) { + WP_CLI::out( implode( ' ', wp_list_pluck( $terms, 'term_id' ) ) ); + } else { + + $fields = array( + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', + ); + + WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); + } } /** From ef46664602e1fce1d4e48491901faea7cc75fbf1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 14:08:31 -0700 Subject: [PATCH 1504/5359] Refactor to allow 'ids' be passed to `format_items()` as a formatting argument --- man-src/term-list.txt | 6 +----- man/term-list.1 | 10 ++-------- php/commands/term.php | 28 +++++++++++++--------------- php/utils.php | 3 +++ 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/man-src/term-list.txt b/man-src/term-list.txt index 32e01215d..f782b7e59 100644 --- a/man-src/term-list.txt +++ b/man-src/term-list.txt @@ -4,13 +4,9 @@ List terms of a given taxonomy. -* `--ids`: - - Return only the term ids of the found terms, separated by spaces. - * `--format`=<format>: - Output list as table, CSV or JSON. Defaults to table. + Output list as table, CSV, JSON, or simply IDs. Defaults to table. ## EXAMPLES diff --git a/man/term-list.1 b/man/term-list.1 index 88d47ab96..9990d2ff0 100644 --- a/man/term-list.1 +++ b/man/term-list.1 @@ -7,7 +7,7 @@ \fBwp\-term\-list\fR \- List terms in a taxonomy\. . .SH "SYNOPSIS" -wp term list \fItaxonomy\fR [\-\-ids] [\-\-format=\fIformat\fR] +wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -18,16 +18,10 @@ wp term list \fItaxonomy\fR [\-\-ids] [\-\-format=\fIformat\fR] List terms of a given taxonomy\. . .TP -\fB\-\-ids\fR: -. -.IP -Return only the term ids of the found terms, separated by spaces\. -. -.TP \fB\-\-format\fR=\fIformat\fR: . .IP -Output list as table, CSV or JSON\. Defaults to table\. +Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. . .SH "EXAMPLES" . diff --git a/php/commands/term.php b/php/commands/term.php index 4679a3312..c55b58508 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -10,7 +10,7 @@ class Term_Command extends WP_CLI_Command { * List terms in a taxonomy. * * @subcommand list - * @synopsis <taxonomy> [--ids] [--format=<format>] + * @synopsis <taxonomy> [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -24,22 +24,20 @@ public function _list( $args, $assoc_args ) { $terms = get_terms( array( $taxonomy ), $assoc_args ); - if ( isset( $assoc_args['ids'] ) ) { - WP_CLI::out( implode( ' ', wp_list_pluck( $terms, 'term_id' ) ) ); - } else { - - $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', + if ( 'ids' == $assoc_args['format'] ) + $terms = wp_list_pluck( $terms, 'term_id' ); + + $fields = array( + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', ); - WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); - } + WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); } /** diff --git a/php/utils.php b/php/utils.php index 51f25b541..3489393d7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -293,6 +293,9 @@ function format_items( $format, $fields, $items ) { else write_csv( STDOUT, $output_items, $fields ); break; + case 'ids': + \WP_CLI::out( implode( ' ', $items ) ); + break; } } From aec54c690ef9bc8184bebe5ce34fa20a1df3ba14 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 14:27:20 -0700 Subject: [PATCH 1505/5359] Convert `wp user list --ids` to `wp user list --format=ids` Also, dropped the formatting of the `$output_items`, as a user is already a WP_User object and the formatting is handled within our `format_items()` util --- man-src/user-list.txt | 6 +----- man/user-list.1 | 10 ++-------- php/commands/user.php | 38 ++++++++++++++++---------------------- 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/man-src/user-list.txt b/man-src/user-list.txt index 8fc98a013..f675f25a0 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -4,13 +4,9 @@ Only display users with a certain role. -* `--ids`: - - Return only the IDs of the found users, separated by spaces. - * `--format`=<format>: - Output list as table, CSV or JSON. Defaults to table. + Output list as table, CSV, JSON, or simply IDs. Defaults to table. ## EXAMPLES diff --git a/man/user-list.1 b/man/user-list.1 index 251e9f254..73c72ba33 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -wp user list [\-\-role=\fIrole\fR] [\-\-ids] [\-\-format=\fIformat\fR] +wp user list [\-\-role=\fIrole\fR] [\-\-format=\fIformat\fR] [\-\-ids] . .SH "OPTIONS" . @@ -18,16 +18,10 @@ wp user list [\-\-role=\fIrole\fR] [\-\-ids] [\-\-format=\fIformat\fR] Only display users with a certain role\. . .TP -\fB\-\-ids\fR: -. -.IP -Return only the IDs of the found users, separated by spaces\. -. -.TP \fB\-\-format\fR=\fIformat\fR: . .IP -Output list as table, CSV or JSON\. Defaults to table\. +Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. . .SH "EXAMPLES" . diff --git a/php/commands/user.php b/php/commands/user.php index b2fdc7911..f59583ffc 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -13,7 +13,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * List users. * * @subcommand list - * @synopsis [--role=<role>] [--ids] [--format=<format>] + * @synopsis [--role=<role>] [--format=<format>] [--ids] */ public function _list( $args, $assoc_args ) { @@ -28,38 +28,32 @@ public function _list( $args, $assoc_args ) { $params['role'] = $assoc_args['role']; } - $users = get_users( $params ); - - if ( isset( $assoc_args['ids'] ) ) { - WP_CLI::out( implode( ' ', $users ) ); - exit; + // --ids is deprecated + if ( isset( $params['ids'] ) ) { + $params['format'] = 'ids'; + unset( $params['ids'] ); } + if ( 'ids' == $params['format'] ) + $params['fields'] = 'ids'; + + $users = get_users( $params ); + $fields = array( 'ID', 'user_login', 'display_name', 'user_email', - 'user_registered' + 'user_registered', + 'roles' ); - - $output_users = array(); - - foreach ( $users as $user ) { - $output_user = new stdClass; - - foreach ( $fields as $field ) { - $output_user->$field = $user->$field; + if ( 'ids' != $params['format'] ) { + foreach ( $users as $user ) { + $user->roles = implode( ',', $user->roles ); } - - $output_user->roles = implode( ',', $user->roles ); - - $output_users[] = $output_user; } - $fields[] = 'roles'; - - WP_CLI\Utils\format_items( $params['format'], $fields, $output_users ); + WP_CLI\Utils\format_items( $params['format'], $fields, $users ); } /** From fff9d064a6df71e25fc631fd720c2af2546ed4a0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 14:43:17 -0700 Subject: [PATCH 1506/5359] JSON format test for `wp user list` Also, fix the CSV used in the setup of the scenario as it originally caused the test to fail --- features/user.feature | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/features/user.feature b/features/user.feature index 316b534d5..183986f8d 100644 --- a/features/user.feature +++ b/features/user.feature @@ -45,10 +45,10 @@ Feature: Manage WordPress users Given a WP install And a users.csv file: """ - user_login, user_email, display_name, role - bobjones, bobjones@domain.com, Bob Jones, contributor - newuser1, newuser1@domain.com, New User, author - admin, admin@domain.com, Existing User, administrator + user_login,user_email,display_name,role + bobjones,bobjones@domain.com,Bob Jones,contributor + newuser1,newuser1@domain.com,New User,author + admin,admin@domain.com,Existing User,administrator """ When I run `wp user import-csv users.csv` @@ -60,3 +60,9 @@ Feature: Manage WordPress users 4 """ + When I run `wp user list --format=json` + Then it should run without errors + And STDOUT should be JSON containing: + """ + [{"user_login":"admin","display_name":"Existing User","user_email":"admin@domain.com","roles":"administrator"}] + """ From ee5da67d2188663536b43801354431606a558545 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 15:27:20 -0700 Subject: [PATCH 1507/5359] Convert `wp post list --ids` to `wp post list --format=ids` --- php/commands/post.php | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index bcd2e71ee..88e5c8517 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -160,13 +160,19 @@ protected function _delete( $post_id, $assoc_args ) { * Get a list of posts. * * @subcommand list - * @synopsis [--<field>=<value>] [--ids] [--format=<format>] + * @synopsis [--<field>=<value>] [--format=<format>] [--ids] */ public function _list( $_, $assoc_args ) { $query_args = array( 'posts_per_page' => -1 ); + // --ids is deprecated + if ( isset( $assoc_args['ids'] ) ) { + $assoc_args['format'] = 'ids'; + unset( $assoc_args['ids'] ); + } + if ( ! empty( $assoc_args['format'] ) ) { $format = $assoc_args['format']; unset( $assoc_args['format'] ); @@ -181,29 +187,16 @@ public function _list( $_, $assoc_args ) { $query_args[ $key ] = $value; } - if ( isset( $assoc_args['ids'] ) ) + if ( 'ids' == $format ) $query_args['fields'] = 'ids'; $query = new WP_Query( $query_args ); - if ( isset( $assoc_args['ids'] ) ) { - WP_CLI::out( implode( ' ', $query->posts ) ); - } else { - - $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); - - $output_posts = array(); - foreach ( $query->posts as $post ) { + $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); - $output_post = new stdClass; - foreach ( $fields as $field ) { - $output_post->$field = $post->$field; - } - $output_posts[] = $output_post; - } - WP_CLI\Utils\format_items( $format, $fields, $output_posts ); - } + $output_posts = $query->posts; + WP_CLI\Utils\format_items( $format, $fields, $output_posts ); } /** From 2037ae14567f85a115bd6a513e7b8184b2421373 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Apr 2013 15:32:16 -0700 Subject: [PATCH 1508/5359] Update man for `wp post list` --- man-src/post-list.txt | 8 +------- man/post-list.1 | 12 ++---------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/man-src/post-list.txt b/man-src/post-list.txt index ad6786367..400e712cc 100644 --- a/man-src/post-list.txt +++ b/man-src/post-list.txt @@ -4,18 +4,12 @@ One or more args to pass to WP_Query. -* `--ids`: - - Return only the IDs of the found posts, separated by spaces. - * `--format`=<format>: - Output list as table, CSV or JSON. Defaults to table. + Output list as table, CSV, JSON, or simply IDs. Defaults to table. ## EXAMPLES wp post list - wp post list --post_type=page --post_status=draft --ids - wp post list --post_type=post --posts_per_page=5 --format=json diff --git a/man/post-list.1 b/man/post-list.1 index 85a82be0e..8da81f7a4 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] [\-\-format=\fIformat\fR] +wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-format=\fIformat\fR] [\-\-ids] . .SH "OPTIONS" . @@ -18,16 +18,10 @@ wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-ids] [\-\-format=\fIformat\fR] One or more args to pass to WP_Query\. . .TP -\fB\-\-ids\fR: -. -.IP -Return only the IDs of the found posts, separated by spaces\. -. -.TP \fB\-\-format\fR=\fIformat\fR: . .IP -Output list as table, CSV or JSON\. Defaults to table\. +Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. . .SH "EXAMPLES" . @@ -35,8 +29,6 @@ Output list as table, CSV or JSON\. Defaults to table\. wp post list -wp post list \-\-post_type=page \-\-post_status=draft \-\-ids - wp post list \-\-post_type=post \-\-posts_per_page=5 \-\-format=json . .fi From 17757fea7519464c6772af3a6f1957f608179e8a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 01:57:24 +0300 Subject: [PATCH 1509/5359] transparently convert --ids to --format=ids this keeps the back-compat code separate from the command implementation --- man-src/post-list.txt | 2 +- man-src/user-list.txt | 2 +- man/post-list.1 | 4 ++-- man/user-list.1 | 4 ++-- php/WP_CLI/Runner.php | 9 +++++++++ php/commands/post.php | 8 +------- php/commands/user.php | 9 ++------- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/man-src/post-list.txt b/man-src/post-list.txt index 400e712cc..47849ced9 100644 --- a/man-src/post-list.txt +++ b/man-src/post-list.txt @@ -10,6 +10,6 @@ ## EXAMPLES - wp post list + wp post list --format=ids wp post list --post_type=post --posts_per_page=5 --format=json diff --git a/man-src/user-list.txt b/man-src/user-list.txt index f675f25a0..d30757b45 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -10,6 +10,6 @@ ## EXAMPLES - wp user list + wp user list --format=ids wp user list --role=administrator --format=csv diff --git a/man/post-list.1 b/man/post-list.1 index 8da81f7a4..b20875028 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-format=\fIformat\fR] [\-\-ids] +wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -27,7 +27,7 @@ Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. . .nf -wp post list +wp post list \-\-format=ids wp post list \-\-post_type=post \-\-posts_per_page=5 \-\-format=json . diff --git a/man/user-list.1 b/man/user-list.1 index 73c72ba33..8d66afa59 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -wp user list [\-\-role=\fIrole\fR] [\-\-format=\fIformat\fR] [\-\-ids] +wp user list [\-\-role=\fIrole\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -27,7 +27,7 @@ Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. . .nf -wp user list +wp user list \-\-format=ids wp user list \-\-role=administrator \-\-format=csv . diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 835aba90d..a41f34b67 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -226,6 +226,15 @@ public function before_wp_load() { unset( $this->assoc_args['all'] ); } + // {post|user} list --ids -> {post|user} list --format=ids + if ( count( $this->arguments ) > 1 && in_array( $this->arguments[0], array( 'post', 'user' ) ) + && $this->arguments[1] == 'list' + && isset( $this->assoc_args['ids'] ) + ) { + $this->assoc_args['format'] = 'ids'; + unset( $this->assoc_args['ids'] ); + } + $config_spec = Utils\get_config_spec(); // Set the path default to the ABSPATH diff --git a/php/commands/post.php b/php/commands/post.php index 88e5c8517..7dec70541 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -160,19 +160,13 @@ protected function _delete( $post_id, $assoc_args ) { * Get a list of posts. * * @subcommand list - * @synopsis [--<field>=<value>] [--format=<format>] [--ids] + * @synopsis [--<field>=<value>] [--format=<format>] */ public function _list( $_, $assoc_args ) { $query_args = array( 'posts_per_page' => -1 ); - // --ids is deprecated - if ( isset( $assoc_args['ids'] ) ) { - $assoc_args['format'] = 'ids'; - unset( $assoc_args['ids'] ); - } - if ( ! empty( $assoc_args['format'] ) ) { $format = $assoc_args['format']; unset( $assoc_args['format'] ); diff --git a/php/commands/user.php b/php/commands/user.php index f59583ffc..e96e39843 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -13,7 +13,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * List users. * * @subcommand list - * @synopsis [--role=<role>] [--format=<format>] [--ids] + * @synopsis [--role=<role>] [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -28,12 +28,6 @@ public function _list( $args, $assoc_args ) { $params['role'] = $assoc_args['role']; } - // --ids is deprecated - if ( isset( $params['ids'] ) ) { - $params['format'] = 'ids'; - unset( $params['ids'] ); - } - if ( 'ids' == $params['format'] ) $params['fields'] = 'ids'; @@ -47,6 +41,7 @@ public function _list( $args, $assoc_args ) { 'user_registered', 'roles' ); + if ( 'ids' != $params['format'] ) { foreach ( $users as $user ) { $user->roles = implode( ',', $user->roles ); From f22aa8e21293fb53c5bec284b4fddfbbc79d6831 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 02:01:10 +0300 Subject: [PATCH 1510/5359] update `wp post delete` example --- man-src/post-delete.txt | 2 +- man/post-delete.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/post-delete.txt b/man-src/post-delete.txt index 7deed7050..d2a614bd8 100644 --- a/man-src/post-delete.txt +++ b/man-src/post-delete.txt @@ -12,4 +12,4 @@ wp post delete 123 --force - wp post delete $(wp post list --post_type='page' --ids) + wp post delete $(wp post list --post_type='page' --format=ids) diff --git a/man/post-delete.1 b/man/post-delete.1 index e301e7733..f163575f2 100644 --- a/man/post-delete.1 +++ b/man/post-delete.1 @@ -29,7 +29,7 @@ Skip the trash bin\. wp post delete 123 \-\-force -wp post delete $(wp post list \-\-post_type=\'page\' \-\-ids) +wp post delete $(wp post list \-\-post_type=\'page\' \-\-format=ids) . .fi From 8895f824acc0b5ce1e53a781c8cd0295ff0973ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Apr 2013 02:01:41 +0300 Subject: [PATCH 1511/5359] use --format=ids in user.feature --- features/user.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index 183986f8d..627a684a2 100644 --- a/features/user.feature +++ b/features/user.feature @@ -25,10 +25,10 @@ Feature: Manage WordPress users Given a WP install # Delete all users - When I run `wp user list --ids` + When I run `wp user list --format=ids` And save STDOUT as {USER_IDS} And I run `wp user delete {USER_IDS}` - When I run `wp user list --ids` + When I run `wp user list --format=ids` Then it should run without errors And STDOUT should be empty From bed5cb0b47e650000a69232b81e45c01b433dc2b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 21:27:00 -0700 Subject: [PATCH 1512/5359] Improvements to `wp term` output * Add `--porcelain` argument to `wp term create` * `wp term create` should include term ID in success message * `wp term delete` includes the term ID of the deleted term * Updated tests / doc See https://github.com/wp-cli/wp-cli/issues/399#issuecomment-16685216 --- features/term.feature | 25 ++++++++++++++++++++----- man-src/term-create.txt | 4 ++++ man/term-create.1 | 8 +++++++- php/commands/term.php | 20 +++++++++++++++----- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/features/term.feature b/features/term.feature index e8be1655b..47a4219dc 100644 --- a/features/term.feature +++ b/features/term.feature @@ -3,12 +3,9 @@ Feature: Manage WordPress terms Scenario: Creating/listing a term Given a WP install - When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` + When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` Then it should run without errors - And STDOUT should be: - """ - Success: Term created. - """ + And STDOUT should match '%d' When I run the previous command again Then STDERR should not be empty @@ -19,3 +16,21 @@ Feature: Manage WordPress terms """ [{"name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] """ + + Scenario: Creating/deleting a term + Given a WP install + + When I run `wp term create 'Test delete term' post_tag --slug=test-delete --description='This is a test term to be deleted' --porcelain` + Then it should run without errors + And STDOUT should match '%d' + And save STDOUT as {TERM_ID} + + When I run `wp term delete {TERM_ID} post_tag` + Then it should run without errors + And STDOUT should contain: + """ + Deleted post_tag {TERM_ID}. + """ + + When I run the previous command again + Then STDERR should not be empty diff --git a/man-src/term-create.txt b/man-src/term-create.txt index e34cd3842..46b85b9f0 100644 --- a/man-src/term-create.txt +++ b/man-src/term-create.txt @@ -20,6 +20,10 @@ A parent for the new term. +* `--porcelain`: + + Output just the new term id. + ## EXAMPLES wp term create Apple category --description="A type of fruit" diff --git a/man/term-create.1 b/man/term-create.1 index a5cf4ad56..366ee1a88 100644 --- a/man/term-create.1 +++ b/man/term-create.1 @@ -7,7 +7,7 @@ \fBwp\-term\-create\fR \- Create a term\. . .SH "SYNOPSIS" -wp term create \fIterm\fR \fItaxonomy\fR [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] +wp term create \fIterm\fR \fItaxonomy\fR [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] [\-\-porcelain] . .SH "OPTIONS" . @@ -41,6 +41,12 @@ A description for the new term\. .IP A parent for the new term\. . +.TP +\fB\-\-porcelain\fR: +. +.IP +Output just the new term id\. +. .SH "EXAMPLES" . .nf diff --git a/php/commands/term.php b/php/commands/term.php index c55b58508..12e56bda5 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -43,7 +43,7 @@ public function _list( $args, $assoc_args ) { /** * Create a term. * - * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<term-id>] + * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<term-id>] [--porcelain] */ public function create( $args, $assoc_args ) { @@ -56,12 +56,22 @@ public function create( $args, $assoc_args ) { ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); + if ( isset( $assoc_args['porcelain'] ) ) { + $porcelain = true; + unset( $assoc_args['porcelain'] ); + } else + $porcelain = false; + $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); if ( is_wp_error( $ret ) ) WP_CLI::error( $ret->get_error_message() ); - else - WP_CLI::success( "Term created." ); + else { + if ( $porcelain ) + WP_CLI::line( $ret['term_id'] ); + else + WP_CLI::success( sprintf( "Created %s %d.", $taxonomy, $ret['term_id'] ) ); + } } /** @@ -108,9 +118,9 @@ public function delete( $args ) { if ( is_wp_error( $ret ) ) WP_CLI::error( $ret->get_error_message() ); else if ( $ret ) - WP_CLI::success( "Term deleted." ); + WP_CLI::success( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); else - WP_CLI::error( "Error deleting term." ); + WP_CLI::error( "Term doesn't exist." ); } } From 34522269e92b3a818735c457d8a1d1b05bb84e7e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 21:52:57 -0700 Subject: [PATCH 1513/5359] For ease of use, allow a CSV of fields to be passed into `format_items()` --- php/utils.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 3489393d7..1aaa9a91d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -252,12 +252,15 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria /** * Output items in a table, JSON, or CSV * - * @param string $format Format to use: 'table', 'json', 'csv' - * @param array $fields Named fields for each item of data - * @param array $items Data to output + * @param string $format Format to use: 'table', 'json', 'csv' + * @param array|string $fields Named fields for each item of data. Can be array or CSV + * @param array $items Data to output */ function format_items( $format, $fields, $items ) { + if ( ! is_array( $fields ) ) + $fields = explode( ',', $fields ); + switch ( $format ) { case 'table': $table = new \cli\Table(); From 298d84ef800d5d11797bb3579a7403d02ab4bb62 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 22:07:20 -0700 Subject: [PATCH 1514/5359] Refactor `format_items()` such that it prepares output items in advance, and validates `$fields` based on the fields avaialble on the object. --- php/utils.php | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/php/utils.php b/php/utils.php index 1aaa9a91d..d6a0ff5ba 100644 --- a/php/utils.php +++ b/php/utils.php @@ -261,35 +261,37 @@ function format_items( $format, $fields, $items ) { if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); + $output_items = array(); + foreach ( $items as $item ) { + + $output_item = new \stdClass; + foreach ( $fields as $key => $field ) { + + if ( ! isset( $item->$field ) ) { + unset( $fields[$key] ); + continue; + } + + $output_item->$field = $item->$field; + } + + $output_items[] = $output_item; + } + switch ( $format ) { case 'table': $table = new \cli\Table(); $table->setHeaders( $fields ); - foreach ( $items as $item ) { - $line = array(); - - foreach ( $fields as $field ) { - $line[] = $item->$field; - } - - $table->addRow( $line ); + foreach ( $output_items as $item ) { + $table->addRow( array_values( (array)$item ) ); } $table->display(); break; case 'csv': case 'json': - $output_items = array(); - - foreach( $items as $item ) { - $output_item = new \stdClass; - foreach( $fields as $field ) { - $output_item->$field = $item->$field; - } - $output_items[] = $output_item; - } if ( 'json' == $format ) echo json_encode( $output_items ); From 62be7cb17287676e6afd4d75bf122ba7fc2768e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 22:09:54 -0700 Subject: [PATCH 1515/5359] Add `--fields` support to `wp term list`. Needs updated tests and doc. --- php/commands/term.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c55b58508..2a64f1b44 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -6,37 +6,41 @@ */ class Term_Command extends WP_CLI_Command { + public $fields = array( + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', + ); + /** * List terms in a taxonomy. * * @subcommand list - * @synopsis <taxonomy> [--format=<format>] + * @synopsis <taxonomy> [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { list( $taxonomy ) = $args; $defaults = array( + 'fields' => implode( ',', $this->fields ), 'format' => 'table', 'hide_empty' => false, ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); + $fields = $assoc_args['fields']; + unset( $assoc_args['fields'] ); + $terms = get_terms( array( $taxonomy ), $assoc_args ); if ( 'ids' == $assoc_args['format'] ) $terms = wp_list_pluck( $terms, 'term_id' ); - $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', - ); - WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); } From 61151e7f2e7ffcc282c511992911a4468ca0309b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 22:23:19 -0700 Subject: [PATCH 1516/5359] `--fields` support for `wp role list` --- php/commands/role.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 88c43b0de..a397dc6ad 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -7,24 +7,28 @@ */ class Role_Command extends WP_CLI_Command { + public $fields = array( + 'name', + 'role' + ); + /** * List all roles. * * @subcommand list - * @synopsis [--format=<format>] + * @synopsis [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { global $wp_roles; $defaults = array( + 'fields' => implode( ',', $this->fields ), 'format' => 'table', ); $params = array_merge( $defaults, $assoc_args ); - $fields = array( - 'name', - 'role', - ); + $fields = $params['fields']; + unset( $params['fields'] ); $output_roles = array(); foreach ( $wp_roles->roles as $key => $role ) { From 2e38aa503a4a82326111c0f8cc1dac00a07497e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 22:37:18 -0700 Subject: [PATCH 1517/5359] Implement `--fields` support for `wp post list` --- php/commands/post.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 7dec70541..7d966c3bb 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -9,6 +9,13 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'post'; + public $fields = array( + 'ID', + 'post_title', + 'post_name', + 'post_date' + ); + /** * Create a post. * @@ -160,7 +167,7 @@ protected function _delete( $post_id, $assoc_args ) { * Get a list of posts. * * @subcommand list - * @synopsis [--<field>=<value>] [--format=<format>] + * @synopsis [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $_, $assoc_args ) { $query_args = array( @@ -174,6 +181,13 @@ public function _list( $_, $assoc_args ) { $format = 'table'; } + if ( isset( $assoc_args['fields'] ) ) { + $fields = $assoc_args['fields']; + unset( $assoc_args['fields'] ); + } else { + $fields = $this->fields; + } + foreach ( $assoc_args as $key => $value ) { if ( true === $value ) continue; @@ -186,8 +200,6 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); - $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); - $output_posts = $query->posts; WP_CLI\Utils\format_items( $format, $fields, $output_posts ); From 30fa02622992cdf1554df8cb152f72ebcbfb27e4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Apr 2013 22:48:25 -0700 Subject: [PATCH 1518/5359] Implement `--fields` support for `wp user list` --- php/commands/user.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index e96e39843..de3245f99 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -9,39 +9,44 @@ class User_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'user'; + public $fields = array( + 'ID', + 'user_login', + 'display_name', + 'user_email', + 'user_registered', + 'roles' + ); + /** * List users. * * @subcommand list - * @synopsis [--role=<role>] [--format=<format>] + * @synopsis [--role=<role>] [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { $defaults = array( 'blog_id' => get_current_blog_id(), - 'fields' => isset( $assoc_args['ids'] ) ? 'ids' : 'all_with_meta', + 'fields' => implode( ',', $this->fields ), 'format' => 'table', ); $params = array_merge( $defaults, $assoc_args ); + $fields = $params['fields']; + unset( $params['fields'] ); + if ( array_key_exists( 'role', $assoc_args ) ) { $params['role'] = $assoc_args['role']; } if ( 'ids' == $params['format'] ) $params['fields'] = 'ids'; + else + $params['fields'] = 'all_with_meta'; $users = get_users( $params ); - $fields = array( - 'ID', - 'user_login', - 'display_name', - 'user_email', - 'user_registered', - 'roles' - ); - if ( 'ids' != $params['format'] ) { foreach ( $users as $user ) { $user->roles = implode( ',', $user->roles ); From 210ad2f63f09cc940325078b99a1b2c0992572dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 21 Apr 2013 07:32:11 -0700 Subject: [PATCH 1519/5359] Balance ze curly braces to meet WP standards https://github.com/wp-cli/wp-cli/pull/407/files#r3886566 --- php/commands/term.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 12e56bda5..8adba26cd 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -59,14 +59,15 @@ public function create( $args, $assoc_args ) { if ( isset( $assoc_args['porcelain'] ) ) { $porcelain = true; unset( $assoc_args['porcelain'] ); - } else + } else { $porcelain = false; + } $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); - if ( is_wp_error( $ret ) ) + if ( is_wp_error( $ret ) ) { WP_CLI::error( $ret->get_error_message() ); - else { + } else { if ( $porcelain ) WP_CLI::line( $ret['term_id'] ); else From 40f6681065b79bbefd734c03747b83e5ee830d9b Mon Sep 17 00:00:00 2001 From: Michael Williamson <mike@zwobble.org> Date: Sun, 21 Apr 2013 22:36:04 +0100 Subject: [PATCH 1520/5359] Don't create temporary wordpress directory during "wp core download" --- php/commands/core.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3e65fccf8..8f29005a8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -35,9 +35,11 @@ public function download( $args, $assoc_args ) { } $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; - - WP_CLI::launch( 'curl -f' . $silent . escapeshellarg( $download_url ) . ' | tar xz' ); - WP_CLI::launch( sprintf( 'cp -r wordpress/* %s && rm -rf wordpress', escapeshellarg( ABSPATH ) ) ); + + WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); + $curl_command = 'curl -f' . $silent . escapeshellarg( $download_url ); + $tar_command = sprintf( 'tar xz --directory=%s --strip-components=1', escapeshellarg( ABSPATH ) ); + WP_CLI::launch( $curl_command . ' | ' . $tar_command ); WP_CLI::success( 'WordPress downloaded.' ); } From fef40acd10fc722257ddc323d7fb19ed422a0ab2 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Sun, 21 Apr 2013 23:53:29 +0000 Subject: [PATCH 1521/5359] Add empty_blog subcommand to core --- php/commands/core.php | 78 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 3e65fccf8..d1df7cb99 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -61,6 +61,84 @@ public function config( $args, $assoc_args ) { if ( WP_CLI::get_config('quiet') ) ob_end_clean(); } + /** + * Empty a blog + * + * @synopsis [--post_type] [--empty_terms] [--empty_comments] [--empty_options] + */ + public function empty_blog( $args, $assoc_args ) { + + $assoc_args = wp_parse_args( $assoc_args, array( + 'post_type' => 'all', + 'empty_terms' => 1, + 'empty_comments' => 1, + 'empty_options' => 1, + ) ); + + WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); + + global $wpdb; + + // Empty posts and post cache + $posts_query = "SELECT ID FROM $wpdb->posts"; + if ( 'all' != $assoc_args['post_type'] ) + $posts_query .= " WHERE post_type='$assoc_args[post_type]'"; + + $taxonomies = get_taxonomies(); + $posts = $wpdb->get_col( $posts_query ); + $max = count( $posts ); + foreach ( $posts as $postid ) { + wp_cache_delete( $postid, 'posts' ); + wp_cache_delete( $postid, 'post_meta' ); + foreach ( $taxonomies as $taxonomy ) + wp_cache_delete( $postid, "{$taxonomy}_relationships" ); + wp_cache_delete( $wpdb->blogid . '-' . $postid, 'global-posts' ); + } + $wpdb->query( "TRUNCATE $wpdb->posts" ); + + if ( 'all' == $assoc_args['post_type'] ) + $wpdb->query( "TRUNCATE $wpdb->postmeta" ); + + + // Empty comments and comment cache + if ( 1 == $assoc_args['empty_comments'] ) { + $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); + foreach ( $comment_ids as $comment_id ) { + wp_cache_delete( $comment_id, 'comment' ); + wp_cache_delete( $comment_id, 'comment_meta' ); + } + $wpdb->query( "TRUNCATE $wpdb->comments" ); + $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); + } + + // Empty taxonomies and terms + if ( 1 == $assoc_args['empty_terms'] ) { + $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); + $ids = array(); + foreach ( (array) $terms as $term ) { + $taxonomies[] = $term->taxonomy; + $ids[] = $term->term_id; + wp_cache_delete( $term->term_id, $term->taxonomy ); + } + + $taxonomies = array_unique( $taxonomies ); + foreach ( $taxonomies as $taxonomy ) { + if ( isset( $cleaned[$taxonomy] ) ) + continue; + $cleaned[$taxonomy] = true; + + wp_cache_delete( 'all_ids', $taxonomy ); + wp_cache_delete( 'get', $taxonomy ); + delete_option( "{$taxonomy}_children" ); + } + $wpdb->query( "TRUNCATE $wpdb->terms" ); + $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); + $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); + } + + WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); + } + /** * Determine if the WordPress tables are installed. * From 779bb624355c5639e6bba897b62fd925deb31011 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Mon, 22 Apr 2013 00:00:13 +0000 Subject: [PATCH 1522/5359] Remove some old code [closes #406] --- php/commands/core.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d1df7cb99..f14cee587 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -86,7 +86,6 @@ public function empty_blog( $args, $assoc_args ) { $taxonomies = get_taxonomies(); $posts = $wpdb->get_col( $posts_query ); - $max = count( $posts ); foreach ( $posts as $postid ) { wp_cache_delete( $postid, 'posts' ); wp_cache_delete( $postid, 'post_meta' ); From d77c50ee2a3496b28119b26d54a66392c6b53769 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Mon, 22 Apr 2013 00:19:58 +0000 Subject: [PATCH 1523/5359] Remove empty_options flag --- php/commands/core.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index f14cee587..840431b44 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -64,7 +64,7 @@ public function config( $args, $assoc_args ) { /** * Empty a blog * - * @synopsis [--post_type] [--empty_terms] [--empty_comments] [--empty_options] + * @synopsis [--post_type] [--empty_terms] [--empty_comments] */ public function empty_blog( $args, $assoc_args ) { @@ -72,7 +72,6 @@ public function empty_blog( $args, $assoc_args ) { 'post_type' => 'all', 'empty_terms' => 1, 'empty_comments' => 1, - 'empty_options' => 1, ) ); WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); From 4b2bf491bee726bf241625faed1f595e1181647a Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Mon, 22 Apr 2013 13:58:28 +0000 Subject: [PATCH 1524/5359] Use WP_CLI\Iterators\Query instead of ->get_col --- php/commands/core.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 840431b44..2ce416096 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -84,13 +84,18 @@ public function empty_blog( $args, $assoc_args ) { $posts_query .= " WHERE post_type='$assoc_args[post_type]'"; $taxonomies = get_taxonomies(); - $posts = $wpdb->get_col( $posts_query ); - foreach ( $posts as $postid ) { - wp_cache_delete( $postid, 'posts' ); - wp_cache_delete( $postid, 'post_meta' ); + $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); + + while ( $posts->valid() ) { + $post_id = $posts->current()->ID; + + wp_cache_delete( $post_id, 'posts' ); + wp_cache_delete( $post_id, 'post_meta' ); foreach ( $taxonomies as $taxonomy ) - wp_cache_delete( $postid, "{$taxonomy}_relationships" ); - wp_cache_delete( $wpdb->blogid . '-' . $postid, 'global-posts' ); + wp_cache_delete( $post_id, "{$taxonomy}_relationships" ); + wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' ); + + $posts->next(); } $wpdb->query( "TRUNCATE $wpdb->posts" ); From 1e2f7a84b3b1732596c639b19202743cead23c3c Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Mon, 22 Apr 2013 13:59:42 +0000 Subject: [PATCH 1525/5359] Fix post type argument in comments --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2ce416096..0d1721ef4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -64,7 +64,7 @@ public function config( $args, $assoc_args ) { /** * Empty a blog * - * @synopsis [--post_type] [--empty_terms] [--empty_comments] + * @synopsis [--post_type=<post-type>] [--empty_terms] [--empty_comments] */ public function empty_blog( $args, $assoc_args ) { From a4e4d4ec5515f9e51bf4c22ad84a8472c6fc7a92 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Mon, 22 Apr 2013 14:04:28 +0000 Subject: [PATCH 1526/5359] Change empty_terms and empty_comments to keep_terms and keep_comments --- php/commands/core.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 0d1721ef4..9feeaa9e3 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -64,14 +64,14 @@ public function config( $args, $assoc_args ) { /** * Empty a blog * - * @synopsis [--post_type=<post-type>] [--empty_terms] [--empty_comments] + * @synopsis [--post_type=<post-type>] [--keep_terms] [--keep_comments] */ public function empty_blog( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( 'post_type' => 'all', - 'empty_terms' => 1, - 'empty_comments' => 1, + 'keep_terms' => 0, + 'keep_comments' => 0, ) ); WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); @@ -104,7 +104,7 @@ public function empty_blog( $args, $assoc_args ) { // Empty comments and comment cache - if ( 1 == $assoc_args['empty_comments'] ) { + if ( 0 == $assoc_args['keep_comments'] ) { $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); foreach ( $comment_ids as $comment_id ) { wp_cache_delete( $comment_id, 'comment' ); @@ -115,7 +115,7 @@ public function empty_blog( $args, $assoc_args ) { } // Empty taxonomies and terms - if ( 1 == $assoc_args['empty_terms'] ) { + if ( 0 == $assoc_args['keep_terms'] ) { $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); $ids = array(); foreach ( (array) $terms as $term ) { From b42005e1c3d4ca505a0e507313a4e9f5443df4f7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Apr 2013 16:42:50 +0300 Subject: [PATCH 1527/5359] Simulate and announce a /wp-admin/ page load Most of the built-in commands need access to code from wp-admin/includes/ so it makes sense to load it upfront. Since we're already doing that, it seems like a good idea to also announce this fact to plugins, by setting WP_ADMIN to true. And since we're setting WP_ADMIN to true, we don't need to set up the global $wp_query instance anymore, because the only admin screen where it's set is the post list screen (wp-admin/edit.php). See #385 --- features/core.feature | 14 ++++++++++++++ php/WP_CLI/Runner.php | 3 --- php/utils-wp.php | 7 ------- php/wp-cli.php | 8 ++++++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/features/core.feature b/features/core.feature index 87d06872d..60923299c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -69,6 +69,20 @@ Feature: Manage WordPress installation When I run `wp core is-installed` Then it should run without errors + When I run `wp eval 'var_export( is_admin() );'` + Then it should run without errors + And STDOUT should be: + """ + true + """ + + When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` + Then it should run without errors + And STDOUT should be: + """ + true + """ + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a41f34b67..4af9554ea 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -347,9 +347,6 @@ public function after_wp_load() { Utils\set_user( $this->config ); - if ( !defined( 'WP_INSTALLING' ) && isset( $this->config['url'] ) ) - Utils\set_wp_query(); - if ( isset( $this->config['require'] ) ) require $this->config['require']; diff --git a/php/utils-wp.php b/php/utils-wp.php index 2153d3fee..1821f7f8c 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -65,13 +65,6 @@ function set_user( $assoc_args ) { } } -function set_wp_query() { - if ( isset( $GLOBALS['wp_query'] ) && isset( $GLOBALS['wp'] ) ) { - $GLOBALS['wp']->parse_request(); - $GLOBALS['wp_query']->query($GLOBALS['wp']->query_vars); - } -} - function get_upgrader( $class ) { if ( !class_exists( '\WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; diff --git a/php/wp-cli.php b/php/wp-cli.php index a3bc6cd67..449a19e9f 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -17,18 +17,22 @@ WP_CLI::$runner->before_wp_load(); -// Load WordPress, in the global scope +// Load wp-config.php code, in the global scope eval( WP_CLI::$runner->get_wp_config_code() ); WP_CLI::$runner->after_wp_config_load(); +// Load main WordPress code, in the global scope require WP_CLI_ROOT . 'wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); -// Load all admin utilities +// Simulate a /wp-admin/ page load +$_SERVER['PHP_SELF'] = '/wp-admin/index.php'; +define( 'WP_ADMIN', true ); require ABSPATH . 'wp-admin/includes/admin.php'; +do_action( 'admin_init' ); WP_CLI::$runner->after_wp_load(); From 65eb98d6e7b192118e69773c7f1775e4b2530949 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Apr 2013 19:39:21 +0300 Subject: [PATCH 1528/5359] Define WP_ADMIN before loading WordPress ... where "loading WordPress" also includes loading plugins and themes. Also, define WP_NETWORK_ADMIN and WP_USER_ADMIN, for completeness. see #385 --- php/wp-cli.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 449a19e9f..f002341c3 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -22,15 +22,18 @@ WP_CLI::$runner->after_wp_config_load(); -// Load main WordPress code, in the global scope +// Simulate a /wp-admin/ page load +$_SERVER['PHP_SELF'] = '/wp-admin/index.php'; +define( 'WP_ADMIN', true ); +define( 'WP_NETWORK_ADMIN', false ); +define( 'WP_USER_ADMIN', false ); + +// Load Core, mu-plugins, plugins, themes etc. require WP_CLI_ROOT . 'wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); -// Simulate a /wp-admin/ page load -$_SERVER['PHP_SELF'] = '/wp-admin/index.php'; -define( 'WP_ADMIN', true ); require ABSPATH . 'wp-admin/includes/admin.php'; do_action( 'admin_init' ); From 53a823ab4b9fb90ad0db0d762db2c0ed02d21bad Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Wed, 24 Apr 2013 04:46:17 +0000 Subject: [PATCH 1529/5359] Moving empty blog subcommand to blog command --- php/commands/core.php | 81 ------------------------------------------- 1 file changed, 81 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9feeaa9e3..3e65fccf8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -61,87 +61,6 @@ public function config( $args, $assoc_args ) { if ( WP_CLI::get_config('quiet') ) ob_end_clean(); } - /** - * Empty a blog - * - * @synopsis [--post_type=<post-type>] [--keep_terms] [--keep_comments] - */ - public function empty_blog( $args, $assoc_args ) { - - $assoc_args = wp_parse_args( $assoc_args, array( - 'post_type' => 'all', - 'keep_terms' => 0, - 'keep_comments' => 0, - ) ); - - WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); - - global $wpdb; - - // Empty posts and post cache - $posts_query = "SELECT ID FROM $wpdb->posts"; - if ( 'all' != $assoc_args['post_type'] ) - $posts_query .= " WHERE post_type='$assoc_args[post_type]'"; - - $taxonomies = get_taxonomies(); - $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); - - while ( $posts->valid() ) { - $post_id = $posts->current()->ID; - - wp_cache_delete( $post_id, 'posts' ); - wp_cache_delete( $post_id, 'post_meta' ); - foreach ( $taxonomies as $taxonomy ) - wp_cache_delete( $post_id, "{$taxonomy}_relationships" ); - wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' ); - - $posts->next(); - } - $wpdb->query( "TRUNCATE $wpdb->posts" ); - - if ( 'all' == $assoc_args['post_type'] ) - $wpdb->query( "TRUNCATE $wpdb->postmeta" ); - - - // Empty comments and comment cache - if ( 0 == $assoc_args['keep_comments'] ) { - $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); - foreach ( $comment_ids as $comment_id ) { - wp_cache_delete( $comment_id, 'comment' ); - wp_cache_delete( $comment_id, 'comment_meta' ); - } - $wpdb->query( "TRUNCATE $wpdb->comments" ); - $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); - } - - // Empty taxonomies and terms - if ( 0 == $assoc_args['keep_terms'] ) { - $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); - $ids = array(); - foreach ( (array) $terms as $term ) { - $taxonomies[] = $term->taxonomy; - $ids[] = $term->term_id; - wp_cache_delete( $term->term_id, $term->taxonomy ); - } - - $taxonomies = array_unique( $taxonomies ); - foreach ( $taxonomies as $taxonomy ) { - if ( isset( $cleaned[$taxonomy] ) ) - continue; - $cleaned[$taxonomy] = true; - - wp_cache_delete( 'all_ids', $taxonomy ); - wp_cache_delete( 'get', $taxonomy ); - delete_option( "{$taxonomy}_children" ); - } - $wpdb->query( "TRUNCATE $wpdb->terms" ); - $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); - $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); - } - - WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); - } - /** * Determine if the WordPress tables are installed. * From 5e8ea533730160b883898c734ba67039b499ca90 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Wed, 24 Apr 2013 04:47:15 +0000 Subject: [PATCH 1530/5359] Move empty blog subcommand to blog command; create separate class for multi-site commands so that we can make blog available to single site installations --- php/commands/blog.php | 156 +++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 33 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index b7af96103..0eef48b7f 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -1,12 +1,130 @@ <?php /** - * Manage blogs in a multisite install. + * Manage blog(s) * * @package wp-cli */ class Blog_Command extends WP_CLI_Command { + /** + * Empty a blog + * + * @synopsis [--post_type=<post-type>] [--keep_terms] [--keep_comments] + */ + public function truncate( $args, $assoc_args ) { + + $assoc_args = wp_parse_args( $assoc_args, array( + 'post_type' => 'all', + 'keep_terms' => 0, + 'keep_comments' => 0, + ) ); + + WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); + + global $wpdb; + + // Empty posts and post cache + $posts_query = "SELECT ID FROM $wpdb->posts"; + if ( 'all' != $assoc_args['post_type'] ) + $posts_query .= " WHERE post_type='$assoc_args[post_type]'"; + + $taxonomies = get_taxonomies(); + $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); + + while ( $posts->valid() ) { + $post_id = $posts->current()->ID; + + wp_cache_delete( $post_id, 'posts' ); + wp_cache_delete( $post_id, 'post_meta' ); + foreach ( $taxonomies as $taxonomy ) + wp_cache_delete( $post_id, "{$taxonomy}_relationships" ); + wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' ); + + $posts->next(); + } + $wpdb->query( "TRUNCATE $wpdb->posts" ); + + if ( 'all' == $assoc_args['post_type'] ) + $wpdb->query( "TRUNCATE $wpdb->postmeta" ); + + + // Empty comments and comment cache + if ( 0 == $assoc_args['keep_comments'] ) { + $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); + foreach ( $comment_ids as $comment_id ) { + wp_cache_delete( $comment_id, 'comment' ); + wp_cache_delete( $comment_id, 'comment_meta' ); + } + $wpdb->query( "TRUNCATE $wpdb->comments" ); + $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); + } + + // Empty taxonomies and terms + if ( 0 == $assoc_args['keep_terms'] ) { + $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); + $ids = array(); + foreach ( (array) $terms as $term ) { + $taxonomies[] = $term->taxonomy; + $ids[] = $term->term_id; + wp_cache_delete( $term->term_id, $term->taxonomy ); + } + + $taxonomies = array_unique( $taxonomies ); + foreach ( $taxonomies as $taxonomy ) { + if ( isset( $cleaned[$taxonomy] ) ) + continue; + $cleaned[$taxonomy] = true; + + wp_cache_delete( 'all_ids', $taxonomy ); + wp_cache_delete( 'get', $taxonomy ); + delete_option( "{$taxonomy}_children" ); + } + $wpdb->query( "TRUNCATE $wpdb->terms" ); + $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); + $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); + } + + WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); + } +} + +/** + * Manage blogs in a multisite install + */ +class MS_Blog_Command extends Blog_Command { + + public function __construct() { } + + /** + * Delete a blog in a multisite install. + * + * @synopsis [<blog-id>] [--slug=<slug>] [--yes] [--keep-tables] + */ + function delete( $args, $assoc_args ) { + if ( isset( $assoc_args['slug'] ) ) { + $blog = get_blog_details( trim( $assoc_args['slug'], '/' ) ); + } else { + if ( empty( $args ) ) { + WP_CLI::error( "Need to specify a blog id." ); + } + + $blog_id = $args[0]; + + $blog = get_blog_details( $blog_id ); + } + + if ( !$blog ) { + WP_CLI::error( "Blog not found." ); + } + + WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl blog?", $assoc_args ); + + wpmu_delete_blog( $blog->blog_id, !isset( $assoc_args['keep-tables'] ) ); + + WP_CLI::success( "The blog at $blog->siteurl was deleted." ); + } + /** * Get site (network) data for a given id * @@ -123,39 +241,11 @@ public function create( $_, $assoc_args ) { else WP_CLI::success( "Blog $id created: $url" ); } - - /** - * Delete a blog in a multisite install. - * - * @synopsis [<blog-id>] [--slug=<slug>] [--yes] [--keep-tables] - */ - function delete( $args, $assoc_args ) { - if ( isset( $assoc_args['slug'] ) ) { - $blog = get_blog_details( trim( $assoc_args['slug'], '/' ) ); - } else { - if ( empty( $args ) ) { - WP_CLI::error( "Need to specify a blog id." ); - } - - $blog_id = $args[0]; - - $blog = get_blog_details( $blog_id ); - } - - if ( !$blog ) { - WP_CLI::error( "Blog not found." ); - } - - WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl blog?", $assoc_args ); - - wpmu_delete_blog( $blog->blog_id, !isset( $assoc_args['keep-tables'] ) ); - - WP_CLI::success( "The blog at $blog->siteurl was deleted." ); - } } -if ( function_exists( 'is_multisite' ) && !is_multisite() ) - return; +$command_class = 'Blog_Command'; +if ( function_exists( 'is_multisite' ) && is_multisite() ) + $command_class = 'MS_Blog_Command'; -WP_CLI::add_command( 'blog', 'Blog_Command' ); +WP_CLI::add_command( 'blog', $command_class ); From 99b65aa57af98e21113b1f5e382144a1d3543822 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Wed, 24 Apr 2013 13:39:56 +0000 Subject: [PATCH 1531/5359] Rename wp blog truncate to wp blog empty --- php/commands/blog.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 0eef48b7f..7b046fb8a 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -10,9 +10,10 @@ class Blog_Command extends WP_CLI_Command { /** * Empty a blog * + * @subcommand empty * @synopsis [--post_type=<post-type>] [--keep_terms] [--keep_comments] */ - public function truncate( $args, $assoc_args ) { + public function _empty( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( 'post_type' => 'all', From 108b485fb68e1bfc2ccafcafce7750aa54637a11 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Thu, 25 Apr 2013 02:57:17 +0000 Subject: [PATCH 1532/5359] Remove empty subcommands args; move empty terms/taxes, posts, and comments; insert default terms/taxes --- php/commands/blog.php | 133 ++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 49 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 7b046fb8a..32229c684 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -8,30 +8,32 @@ class Blog_Command extends WP_CLI_Command { /** - * Empty a blog - * - * @subcommand empty - * @synopsis [--post_type=<post-type>] [--keep_terms] [--keep_comments] + * Delete comments */ - public function _empty( $args, $assoc_args ) { - - $assoc_args = wp_parse_args( $assoc_args, array( - 'post_type' => 'all', - 'keep_terms' => 0, - 'keep_comments' => 0, - ) ); + private function _empty_comments() { + global $wpdb; - WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); + // Empty comments and comment cache + $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); + foreach ( $comment_ids as $comment_id ) { + wp_cache_delete( $comment_id, 'comment' ); + wp_cache_delete( $comment_id, 'comment_meta' ); + } + $wpdb->query( "TRUNCATE $wpdb->comments" ); + $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); + } + /** + * Delete all posts + */ + private function _empty_posts() { global $wpdb; // Empty posts and post cache $posts_query = "SELECT ID FROM $wpdb->posts"; - if ( 'all' != $assoc_args['post_type'] ) - $posts_query .= " WHERE post_type='$assoc_args[post_type]'"; + $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); $taxonomies = get_taxonomies(); - $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); while ( $posts->valid() ) { $post_id = $posts->current()->ID; @@ -45,47 +47,80 @@ public function _empty( $args, $assoc_args ) { $posts->next(); } $wpdb->query( "TRUNCATE $wpdb->posts" ); + $wpdb->query( "TRUNCATE $wpdb->postmeta" ); + } - if ( 'all' == $assoc_args['post_type'] ) - $wpdb->query( "TRUNCATE $wpdb->postmeta" ); - + /** + * Delete terms, taxonomies, and tax relationships + */ + private function _empty_taxonomies() { + global $wpdb; - // Empty comments and comment cache - if ( 0 == $assoc_args['keep_comments'] ) { - $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); - foreach ( $comment_ids as $comment_id ) { - wp_cache_delete( $comment_id, 'comment' ); - wp_cache_delete( $comment_id, 'comment_meta' ); - } - $wpdb->query( "TRUNCATE $wpdb->comments" ); - $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); + // Empty taxonomies and terms + $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); + $ids = array(); + foreach ( (array) $terms as $term ) { + $taxonomies[] = $term->taxonomy; + $ids[] = $term->term_id; + wp_cache_delete( $term->term_id, $term->taxonomy ); + } + + $taxonomies = array_unique( $taxonomies ); + foreach ( $taxonomies as $taxonomy ) { + if ( isset( $cleaned[$taxonomy] ) ) + continue; + $cleaned[$taxonomy] = true; + + wp_cache_delete( 'all_ids', $taxonomy ); + wp_cache_delete( 'get', $taxonomy ); + delete_option( "{$taxonomy}_children" ); } + $wpdb->query( "TRUNCATE $wpdb->terms" ); + $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); + $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); + } - // Empty taxonomies and terms - if ( 0 == $assoc_args['keep_terms'] ) { - $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); - $ids = array(); - foreach ( (array) $terms as $term ) { - $taxonomies[] = $term->taxonomy; - $ids[] = $term->term_id; - wp_cache_delete( $term->term_id, $term->taxonomy ); - } - - $taxonomies = array_unique( $taxonomies ); - foreach ( $taxonomies as $taxonomy ) { - if ( isset( $cleaned[$taxonomy] ) ) - continue; - $cleaned[$taxonomy] = true; - - wp_cache_delete( 'all_ids', $taxonomy ); - wp_cache_delete( 'get', $taxonomy ); - delete_option( "{$taxonomy}_children" ); + /** + * Insert default terms + */ + private function _insert_default_terms() { + global $wpdb; + + // Default category + $cat_name = __( 'Uncategorized' ); + + /* translators: Default category slug */ + $cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug' ) ); + + if ( global_terms_enabled() ) { + $cat_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM {$wpdb->sitecategories} WHERE category_nicename = %s", $cat_slug ) ); + if ( $cat_id == null ) { + $wpdb->insert( $wpdb->sitecategories, array('cat_ID' => 0, 'cat_name' => $cat_name, 'category_nicename' => $cat_slug, 'last_updated' => current_time('mysql', true)) ); + $cat_id = $wpdb->insert_id; } - $wpdb->query( "TRUNCATE $wpdb->terms" ); - $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); - $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); + update_option('default_category', $cat_id); + } else { + $cat_id = 1; } + $wpdb->insert( $wpdb->terms, array('term_id' => $cat_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0) ); + $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $cat_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 1)); + } + + /** + * Empty a blog + * + * @subcommand empty + */ + public function _empty( $args, $assoc_args ) { + + WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); + + $this->_empty_posts(); + $this->_empty_comments(); + $this->_empty_taxonomies(); + $this->_insert_default_terms(); + WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); } } From 6bccb80d7619f47391a44df3f5d884e5986f68d7 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 27 Mar 2013 15:03:45 -0700 Subject: [PATCH 1533/5359] Initial implementation of wp media import Introduces `wp media import` command to sideload images and import them as attachments. Needs tests, second opinion, etc. --- man-src/media-import.txt | 20 +++++++++++++++++++ man/media-import.1 | 43 ++++++++++++++++++++++++++++++++++++++++ php/commands/media.php | 39 ++++++++++++++++++++++++++++++++++++ utils/wp-completion.bash | 7 +++++-- 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 man-src/media-import.txt create mode 100644 man/media-import.1 diff --git a/man-src/media-import.txt b/man-src/media-import.txt new file mode 100644 index 000000000..ed910ff5d --- /dev/null +++ b/man-src/media-import.txt @@ -0,0 +1,20 @@ +## OPTIONS + +* `<file>`: + + Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. + +* `--post-id=<post_id>` + + ID of the post to attach the imported files to. + +* `--desc=<description>` + + "Description" field (post title) of attachment post + + +## EXAMPLES + + wp media import ~/Pictures/**/*.jpg + + wp media import ~/Downloads/image.png --post_id=123 --desc="A downloaded picture" diff --git a/man/media-import.1 b/man/media-import.1 new file mode 100644 index 000000000..304529c6b --- /dev/null +++ b/man/media-import.1 @@ -0,0 +1,43 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-MEDIA\-IMPORT" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-media\-import\fR \- Sideload images from file(s) and import as attachments, optionally attached to a post +. +.SH "SYNOPSIS" +wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-desc=\fIdescription\fR] +. +.SH "OPTIONS" +. +.IP "\(bu" 4 +\fB<file>\fR: +. +.IP +Path to file or files to be imported\. Supports the glob(3) capabilities of the current shell\. +. +.IP "\(bu" 4 +\fB\-\-post\-id=<post_id>\fR +. +.IP +ID of the post to attach the imported files to\. +. +.IP "\(bu" 4 +\fB\-\-desc=<description>\fR +. +.IP +"Description" field (post title) of attachment post +. +.IP "" 0 +. +.SH "EXAMPLES" +. +.nf + +wp media import ~/Pictures/**/*\.jpg + +wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-desc="A downloaded picture" +. +.fi + diff --git a/php/commands/media.php b/php/commands/media.php index 36c37ac91..2ac40ad8b 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -53,6 +53,45 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::success( sprintf( 'Finished regenerating %1$s.', ngettext('the image', 'all images', $count) ) ); } + /** + * Sideload images from file(s) and import as attachments, optionally attached to a post + * + * @synopsis <file>... [--post_id=<post_id>] [--desc=<description>] + */ + function import( $args, $assoc_args = array() ) { + + $assoc_args = wp_parse_args( + $assoc_args, + array( + 'post_id' => 0, + ) + ); + + foreach( $args as $file ) { + $file_array = array( + 'tmp_name' => $file, + 'name' => basename( $file ) + ); + $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['desc'] ); + if ( is_wp_error( $success ) ) + WP_CLI::error( + sprintf( + 'Unable to import file %s. Reason: %s', + $file_array['tmp_name'], implode( ', ', $success->get_error_messages() ) + ) + ); + else + WP_CLI::success( + sprintf( + 'Successfully imported file %s as attachment ID %d.', + $file_array['tmp_name'], $success + ) + ); + } + + } + + private function _process_regeneration( $id ) { $image = get_post( $id ); diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index f3822d350..d78f1001a 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -1,7 +1,7 @@ # bash completion for the wp command _wp() { - local cur prev opts + local cur prev opts file_ops cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} @@ -12,7 +12,10 @@ _wp() { opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2- | tr '\n' ' ') fi - if [[ 'create' = $prev ]]; then + # An array of prev keywords that should get file completion + declare -A file_ops=([create]=1 [import]=1) + + if [[ ${file_ops[$prev]} ]]; then COMPREPLY=( $(compgen -f "$cur") ) else COMPREPLY=( $(compgen -W "$opts" -- $cur) ) From dd70a96efc41870cebcd3c54dd24ec4d3805bc54 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 27 Mar 2013 17:24:51 -0700 Subject: [PATCH 1534/5359] Add capability to download files from URL If a recognizable scheme is passed in the <file> argument, `wp media import` will attempt to download the file to a temp directory before importing it. --- man-src/media-import.txt | 2 ++ man/media-import.1 | 2 +- php/commands/media.php | 18 +++++++++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/man-src/media-import.txt b/man-src/media-import.txt index ed910ff5d..d61929848 100644 --- a/man-src/media-import.txt +++ b/man-src/media-import.txt @@ -3,6 +3,8 @@ * `<file>`: Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. + If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be + downloaded to a temp file before being sideloaded. * `--post-id=<post_id>` diff --git a/man/media-import.1 b/man/media-import.1 index 304529c6b..9bce04bc9 100644 --- a/man/media-import.1 +++ b/man/media-import.1 @@ -15,7 +15,7 @@ wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-desc=\fIdescri \fB<file>\fR: . .IP -Path to file or files to be imported\. Supports the glob(3) capabilities of the current shell\. +Path to file or files to be imported\. Supports the glob(3) capabilities of the current shell\. If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be downloaded to a temp file before being sideloaded\. . .IP "\(bu" 4 \fB\-\-post\-id=<post_id>\fR diff --git a/php/commands/media.php b/php/commands/media.php index 2ac40ad8b..475972e4d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -54,7 +54,7 @@ function regenerate( $args, $assoc_args = array() ) { } /** - * Sideload images from file(s) and import as attachments, optionally attached to a post + * Sideload images from local file(s) or URL and import as attachments, optionally attached to a post * * @synopsis <file>... [--post_id=<post_id>] [--desc=<description>] */ @@ -64,10 +64,26 @@ function import( $args, $assoc_args = array() ) { $assoc_args, array( 'post_id' => 0, + 'desc' => null ) ); foreach( $args as $file ) { + + $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); + + if ( !empty( $is_file_remote ) ) { + $extension = pathinfo( $file, PATHINFO_EXTENSION ); + $tempfile = download_url( $file ); + + // Necessary because temp filename will probably have an extension like + // .tmp, which is not in the list of permitted upload extensions + // and won't be recognized with the correct mime type + $tempfile_extension = pathinfo( $tempfile, PATHINFO_EXTENSION ); + $file = preg_replace( "/$tempfile_extension$/", $extension, $tempfile ); + rename( $tempfile, $file ); + } + $file_array = array( 'tmp_name' => $file, 'name' => basename( $file ) From 51be561678556db85d2afbcdeff4eaa945a5188d Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 28 Mar 2013 10:19:28 -0700 Subject: [PATCH 1535/5359] Remove filename completion for wp media import Filtering bash completions breaks bash's default filename globbing, which is a more useful feature here. --- utils/wp-completion.bash | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index d78f1001a..f3822d350 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -1,7 +1,7 @@ # bash completion for the wp command _wp() { - local cur prev opts file_ops + local cur prev opts cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} @@ -12,10 +12,7 @@ _wp() { opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2- | tr '\n' ' ') fi - # An array of prev keywords that should get file completion - declare -A file_ops=([create]=1 [import]=1) - - if [[ ${file_ops[$prev]} ]]; then + if [[ 'create' = $prev ]]; then COMPREPLY=( $(compgen -f "$cur") ) else COMPREPLY=( $(compgen -W "$opts" -- $cur) ) From f25992520584fc05f1af589ac608aa04a9f8780f Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 28 Mar 2013 10:21:07 -0700 Subject: [PATCH 1536/5359] Rename arguments to make more logical sense Use the same field labels as are used by the admin media uploader, to avoid confusion: title / caption / alt / description; rather than the variable names used internally, where 'description' is really title and so on. --- man-src/media-import.txt | 24 ++++++++++++++++++++---- man/media-import.1 | 32 ++++++++++++++++++++++++++------ php/commands/media.php | 18 ++++++++++++++++-- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/man-src/media-import.txt b/man-src/media-import.txt index d61929848..e937ada5d 100644 --- a/man-src/media-import.txt +++ b/man-src/media-import.txt @@ -6,17 +6,33 @@ If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be downloaded to a temp file before being sideloaded. -* `--post-id=<post_id>` +* `--post_id=<post_id>` - ID of the post to attach the imported files to. + ID of the post to attach the imported files to + +* `--title=<title>` + + Attachment title (post title field) + +* `--caption=<caption>` + + Caption for attachent (post excerpt field) + +* `--alt=<alt_text>` + + Alt text for image (saved as post meta) * `--desc=<description>` - "Description" field (post title) of attachment post + "Description" field (post content) of attachment post ## EXAMPLES wp media import ~/Pictures/**/*.jpg - wp media import ~/Downloads/image.png --post_id=123 --desc="A downloaded picture" + wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" + + wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" + + diff --git a/man/media-import.1 b/man/media-import.1 index 9bce04bc9..0af6e249a 100644 --- a/man/media-import.1 +++ b/man/media-import.1 @@ -4,10 +4,10 @@ .TH "WP\-MEDIA\-IMPORT" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-media\-import\fR \- Sideload images from file(s) and import as attachments, optionally attached to a post +\fBwp\-media\-import\fR \- Sideload images from local file(s) or URL and import as attachments, optionally attached to a post . .SH "SYNOPSIS" -wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-desc=\fIdescription\fR] +wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fIalt_text\fR] [\-\-desc=\fIdescription\fR] . .SH "OPTIONS" . @@ -18,16 +18,34 @@ wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-desc=\fIdescri Path to file or files to be imported\. Supports the glob(3) capabilities of the current shell\. If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be downloaded to a temp file before being sideloaded\. . .IP "\(bu" 4 -\fB\-\-post\-id=<post_id>\fR +\fB\-\-post_id=<post_id>\fR . .IP -ID of the post to attach the imported files to\. +ID of the post to attach the imported files to +. +.IP "\(bu" 4 +\fB\-\-title=<title>\fR +. +.IP +Attachment title (post title field) +. +.IP "\(bu" 4 +\fB\-\-caption=<caption>\fR +. +.IP +Caption for attachent (post excerpt field) +. +.IP "\(bu" 4 +\fB\-\-alt=<alt_text>\fR +. +.IP +Alt text for image (saved as post meta) . .IP "\(bu" 4 \fB\-\-desc=<description>\fR . .IP -"Description" field (post title) of attachment post +"Description" field (post content) of attachment post . .IP "" 0 . @@ -37,7 +55,9 @@ ID of the post to attach the imported files to\. wp media import ~/Pictures/**/*\.jpg -wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-desc="A downloaded picture" +wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-title="A downloaded picture" + +wp media import http://s\.wordpress\.org/style/images/wp\-header\-logo\.png \-\-title=\'The WordPress logo\' \-\-alt="Semantic personal publishing" . .fi diff --git a/php/commands/media.php b/php/commands/media.php index 475972e4d..be4eebf82 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -56,7 +56,7 @@ function regenerate( $args, $assoc_args = array() ) { /** * Sideload images from local file(s) or URL and import as attachments, optionally attached to a post * - * @synopsis <file>... [--post_id=<post_id>] [--desc=<description>] + * @synopsis <file>... [--post_id=<post_id>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] */ function import( $args, $assoc_args = array() ) { @@ -64,6 +64,9 @@ function import( $args, $assoc_args = array() ) { $assoc_args, array( 'post_id' => 0, + 'title' => null, + 'caption' => null, + 'alt' => null, 'desc' => null ) ); @@ -88,7 +91,18 @@ function import( $args, $assoc_args = array() ) { 'tmp_name' => $file, 'name' => basename( $file ) ); - $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['desc'] ); + + $post_array= array( + 'post_title' => $assoc_args['title'], + 'post_excerpt' => $assoc_args['caption'], + 'post_content' => $assoc_args['desc'] + ); + + $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); + + if ( !is_wp_error( $success ) && $assoc_args['alt'] ) + update_post_meta( $success, '_wp_attachment_image_alt', $assoc_args['alt'] ); + if ( is_wp_error( $success ) ) WP_CLI::error( sprintf( From bc620eb45cf2920a9110f659ed3ad46744aff403 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Wed, 17 Apr 2013 17:01:53 -0700 Subject: [PATCH 1537/5359] Add Behat feature for `wp media import` --- features/media.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/media.feature b/features/media.feature index 6afe09198..7521376b2 100644 --- a/features/media.feature +++ b/features/media.feature @@ -9,3 +9,12 @@ Feature: Manage WordPress attachments """ Error: Unable to find the images """ + + Scenario: Import image from remote URL + Given a WP install + + When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` + Then STDOUT should contain: + """ + Success: Successfully imported file /tmp/codeispoetry.png + """ From d170024c17febf975b8c3bd5a10e5e45a614e925 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 25 Apr 2013 12:40:29 -0700 Subject: [PATCH 1538/5359] Add `--featured_image` associative arg This flag will set the uploaded image to be the post thumbnail of the post its attached to. Also, fix the success message and the Behat feature, so that tests don't fail on environments that use a different tmp path. --- features/media.feature | 2 +- php/commands/media.php | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/features/media.feature b/features/media.feature index 7521376b2..c247d6860 100644 --- a/features/media.feature +++ b/features/media.feature @@ -16,5 +16,5 @@ Feature: Manage WordPress attachments When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ - Success: Successfully imported file /tmp/codeispoetry.png + Success: Imported file http://s.wordpress.org/style/images/codeispoetry.png """ diff --git a/php/commands/media.php b/php/commands/media.php index be4eebf82..1e946f400 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -56,7 +56,7 @@ function regenerate( $args, $assoc_args = array() ) { /** * Sideload images from local file(s) or URL and import as attachments, optionally attached to a post * - * @synopsis <file>... [--post_id=<post_id>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] + * @synopsis <file>... [--post_id=<post_id>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { @@ -74,6 +74,7 @@ function import( $args, $assoc_args = array() ) { foreach( $args as $file ) { $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); + $orig_filename = $file; if ( !empty( $is_file_remote ) ) { $extension = pathinfo( $file, PATHINFO_EXTENSION ); @@ -100,21 +101,31 @@ function import( $args, $assoc_args = array() ) { $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); + // Set alt text if ( !is_wp_error( $success ) && $assoc_args['alt'] ) update_post_meta( $success, '_wp_attachment_image_alt', $assoc_args['alt'] ); + // Set as featured image, if --post_id and --featured_image are set + if ( !is_wp_error( $success ) && $assoc_args['post_id'] && $assoc_args['featured_image'] ) + update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); + + $attachment_success_text = ( $assoc_args['post_id'] && get_post( $assoc_args['post_id'] ) ) ? + " and attached to post {$assoc_args['post_id']}" . + ( ( $assoc_args['featured_image'] ) ? ' as featured image' : '' ) + : ''; + if ( is_wp_error( $success ) ) WP_CLI::error( sprintf( 'Unable to import file %s. Reason: %s', - $file_array['tmp_name'], implode( ', ', $success->get_error_messages() ) + $orig_filename, implode( ', ', $success->get_error_messages() ) ) ); else WP_CLI::success( sprintf( - 'Successfully imported file %s as attachment ID %d.', - $file_array['tmp_name'], $success + 'Imported file %s as attachment ID %d%s.', + $orig_filename, $success, $attachment_success_text ) ); } From 661169fd55ee5124cf0003665cede7c37e8e1f6e Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Thu, 25 Apr 2013 13:22:03 -0700 Subject: [PATCH 1539/5359] Update man page for `wp media import` Add option description for `--featured_image`, and briefly explain examples --- man-src/media-import.txt | 9 ++++++++- man/media-import.1 | 13 +++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/man-src/media-import.txt b/man-src/media-import.txt index e937ada5d..5f7e7d1dc 100644 --- a/man-src/media-import.txt +++ b/man-src/media-import.txt @@ -26,13 +26,20 @@ "Description" field (post content) of attachment post +* `--featured_image` + + If set, set the imported image as the Featured Image of the post its attached to. + ## EXAMPLES + # Import all jpgs in the current user's "Pictures" directory, not attached to any post wp media import ~/Pictures/**/*.jpg - wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" + # Import a local image and set it to be the post thumbnail for a post + wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image + # Import an image from the web wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" diff --git a/man/media-import.1 b/man/media-import.1 index 0af6e249a..03bb00ae0 100644 --- a/man/media-import.1 +++ b/man/media-import.1 @@ -7,7 +7,7 @@ \fBwp\-media\-import\fR \- Sideload images from local file(s) or URL and import as attachments, optionally attached to a post . .SH "SYNOPSIS" -wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fIalt_text\fR] [\-\-desc=\fIdescription\fR] +wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fIalt_text\fR] [\-\-desc=\fIdescription\fR] [\-\-featured_image] . .SH "OPTIONS" . @@ -47,16 +47,25 @@ Alt text for image (saved as post meta) .IP "Description" field (post content) of attachment post . +.IP "\(bu" 4 +\fB\-\-featured_image\fR +. +.IP +If set, set the imported image as the Featured Image of the post its attached to\. +. .IP "" 0 . .SH "EXAMPLES" . .nf +# Import all jpgs in the current user\'s "Pictures" directory, not attached to any post wp media import ~/Pictures/**/*\.jpg -wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-title="A downloaded picture" +# Import a local image and set it to be the post thumbnail for a post +wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-title="A downloaded picture" \-\-featured_image +# Import an image from the web wp media import http://s\.wordpress\.org/style/images/wp\-header\-logo\.png \-\-title=\'The WordPress logo\' \-\-alt="Semantic personal publishing" . .fi From e3858df53cd0748bbc5fcaa7e956f8b1e9929911 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Apr 2013 20:43:10 +0300 Subject: [PATCH 1540/5359] check for __invoke() method instead of parameter type --- php/class-wp-cli.php | 32 ++++++++++++++++---------------- php/commands/eval-file.php | 2 +- php/commands/eval.php | 2 +- php/commands/export.php | 2 +- php/commands/help.php | 2 +- php/commands/home.php | 3 +-- php/commands/search-replace.php | 2 +- php/commands/shell.php | 2 +- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1f453e1c7..3b579bef1 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -31,24 +31,32 @@ static function init() { * Add a command to the wp-cli list of commands * * @param string $name The name of the command that will be used in the cli - * @param string|object $implementation The command implementation + * @param string $class The command implementation */ - static function add_command( $name, $implementation ) { + static function add_command( $name, $class ) { if ( in_array( $name, self::get_config('disabled_commands') ) ) return; - if ( is_string( $implementation ) ) { - $command = self::create_composite_command( $name, $implementation ); + $reflection = new \ReflectionClass( $class ); + + if ( $reflection->hasMethod( '__invoke' ) ) { + $command = self::create_atomic_command( $name, $reflection ); } else { - $command = self::create_atomic_command( $name, $implementation ); + $command = self::create_composite_command( $name, $reflection ); } self::$root->add_subcommand( $name, $command ); } - private static function create_composite_command( $name, $class ) { - $reflection = new \ReflectionClass( $class ); + private static function create_atomic_command( $name, $reflection ) { + $method = $reflection->getMethod( '__invoke' ); + + $docparser = new \WP_CLI\DocParser( $method ); + + return new Dispatcher\Subcommand( self::$root, $name, $reflection->name, $docparser ); + } + private static function create_composite_command( $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection ); $container = new Dispatcher\CompositeCommand( $name, $docparser->get_shortdesc() ); @@ -57,7 +65,7 @@ private static function create_composite_command( $name, $class ) { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new Dispatcher\MethodSubcommand( $container, $class, $method ); + $subcommand = new Dispatcher\MethodSubcommand( $container, $reflection->name, $method ); $subcommand_name = $subcommand->get_name(); $full_name = self::get_full_name( $subcommand ); @@ -82,14 +90,6 @@ private static function _is_good_method( $method ) { return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } - private static function create_atomic_command( $name, $implementation ) { - $method = new \ReflectionMethod( $implementation, '__invoke' ); - - $docparser = new \WP_CLI\DocParser( $method ); - - return new Dispatcher\Subcommand( self::$root, $name, $implementation, $docparser ); - } - static function add_man_dir( $dest_dir, $src_dir ) { self::$man_dirs[ $dest_dir ] = $src_dir; } diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 8ee5b6e33..e1c60b9ef 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -18,5 +18,5 @@ public function __invoke( $args, $assoc_args ) { } } -WP_CLI::add_command( 'eval-file', new EvalFile_Command ); +WP_CLI::add_command( 'eval-file', 'EvalFile_Command' ); diff --git a/php/commands/eval.php b/php/commands/eval.php index b8cd803cf..02b97c6a9 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -12,5 +12,5 @@ public function __invoke( $args, $assoc_args ) { } } -WP_CLI::add_command( 'eval', new Eval_Command ); +WP_CLI::add_command( 'eval', 'Eval_Command' ); diff --git a/php/commands/export.php b/php/commands/export.php index 8a08f3bf7..0f85c92c3 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -532,5 +532,5 @@ private function export_wp( $args = array() ) { } } -WP_CLI::add_command( 'export', new Export_Command ); +WP_CLI::add_command( 'export', 'Export_Command' ); diff --git a/php/commands/help.php b/php/commands/help.php index ef1eded1a..55050bb99 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -22,5 +22,5 @@ function __invoke( $args ) { } } -WP_CLI::add_command( 'help', new Help_Command ); +WP_CLI::add_command( 'help', 'Help_Command' ); diff --git a/php/commands/home.php b/php/commands/home.php index fbb3b2fdc..eed233f66 100644 --- a/php/commands/home.php +++ b/php/commands/home.php @@ -25,5 +25,4 @@ function __invoke() { } } -WP_CLI::add_command( 'home', new Home_Command ); - +WP_CLI::add_command( 'home', 'Home_Command' ); diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 607ccd28d..89f76d55c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -118,5 +118,5 @@ private static function is_text_col( $type ) { } } -WP_CLI::add_command( 'search-replace', new Search_Replace_Command ); +WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); diff --git a/php/commands/shell.php b/php/commands/shell.php index fd32cb6ec..0f63833a7 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -116,5 +116,5 @@ private static function starts_with( $tokens, $line ) { } } -\WP_CLI::add_command( 'shell', new Shell_Command ); +\WP_CLI::add_command( 'shell', 'Shell_Command' ); From 79180d315f130fdb4700b2bfa52808414546b48e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Apr 2013 21:27:09 +0300 Subject: [PATCH 1541/5359] remove unnecessary WP_CLI\Commands namespace --- php/commands/shell.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 0f63833a7..02daaed99 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -1,7 +1,5 @@ <?php -namespace WP_CLI\Commands; - class Shell_Command extends \WP_CLI_Command { /** From 68d4b4d458f4c8f685f7942087eca5b8fd2a3197 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Apr 2013 21:32:28 +0300 Subject: [PATCH 1542/5359] instantiate MethodSubcommand instead of Subcommand --- php/class-wp-cli.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3b579bef1..befc5092e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -40,7 +40,7 @@ static function add_command( $name, $class ) { $reflection = new \ReflectionClass( $class ); if ( $reflection->hasMethod( '__invoke' ) ) { - $command = self::create_atomic_command( $name, $reflection ); + $command = new Dispatcher\MethodSubcommand( self::$root, $reflection->name, $reflection->getMethod( '__invoke' ) ); } else { $command = self::create_composite_command( $name, $reflection ); } @@ -48,14 +48,6 @@ static function add_command( $name, $class ) { self::$root->add_subcommand( $name, $command ); } - private static function create_atomic_command( $name, $reflection ) { - $method = $reflection->getMethod( '__invoke' ); - - $docparser = new \WP_CLI\DocParser( $method ); - - return new Dispatcher\Subcommand( self::$root, $name, $reflection->name, $docparser ); - } - private static function create_composite_command( $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection ); From ab598d4ef7f95ad3494e5f04dfa673f21ae55e5d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Apr 2013 21:50:59 +0300 Subject: [PATCH 1543/5359] merge MethodSubcommand into Subcommand --- php/WP_CLI/Dispatcher/MethodSubcommand.php | 23 ---------------------- php/WP_CLI/Dispatcher/Subcommand.php | 23 ++++++++++++++++++---- php/class-wp-cli.php | 5 +++-- php/dispatcher.php | 15 -------------- 4 files changed, 22 insertions(+), 44 deletions(-) delete mode 100644 php/WP_CLI/Dispatcher/MethodSubcommand.php diff --git a/php/WP_CLI/Dispatcher/MethodSubcommand.php b/php/WP_CLI/Dispatcher/MethodSubcommand.php deleted file mode 100644 index f66329bc2..000000000 --- a/php/WP_CLI/Dispatcher/MethodSubcommand.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -class MethodSubcommand extends Subcommand { - - function __construct( CommandContainer $parent, $class, \ReflectionMethod $method ) { - $docparser = new \WP_CLI\DocParser( $method ); - - $name = $docparser->get_tag( 'subcommand' ); - if ( !$name ) - $name = $method->name; - - $callable = new CallableMethod( $class, $method->name ); - - parent::__construct( $parent, $name, $callable, $docparser ); - } - - function get_alias() { - return $this->docparser->get_tag( 'alias' ); - } -} - diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 80d43f620..8b3bae245 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -4,15 +4,28 @@ class Subcommand implements Command, AtomicCommand, Documentable { - function __construct( CommandContainer $parent, $name, $callable, $docparser ) { + private $parent, $name, $method, $docparser; + + function __construct( CommandContainer $parent, \ReflectionMethod $method, $name = false ) { + $docparser = new \WP_CLI\DocParser( $method ); + + if ( !$name ) + $name = $docparser->get_tag( 'subcommand' ); + + if ( !$name ) + $name = $method->name; + $this->parent = $parent; $this->name = $name; - $this->callable = $callable; - + $this->method = $method; $this->docparser = $docparser; } + function get_alias() { + return $this->docparser->get_tag( 'alias' ); + } + function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . $this->get_full_synopsis() ); } @@ -53,7 +66,9 @@ function invoke( $args, $assoc_args ) { array( $this, 'show_usage' ) ); } - call_user_func( $this->callable, $args, $assoc_args ); + $instance = new $this->method->class; + + call_user_func( array( $instance, $this->method->name ), $args, $assoc_args ); } function get_name() { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index befc5092e..b8abeccef 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -40,7 +40,8 @@ static function add_command( $name, $class ) { $reflection = new \ReflectionClass( $class ); if ( $reflection->hasMethod( '__invoke' ) ) { - $command = new Dispatcher\MethodSubcommand( self::$root, $reflection->name, $reflection->getMethod( '__invoke' ) ); + $command = new Dispatcher\Subcommand( self::$root, + $reflection->getMethod( '__invoke' ), $name ); } else { $command = self::create_composite_command( $name, $reflection ); } @@ -57,7 +58,7 @@ private static function create_composite_command( $name, $reflection ) { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new Dispatcher\MethodSubcommand( $container, $reflection->name, $method ); + $subcommand = new Dispatcher\Subcommand( $container, $method ); $subcommand_name = $subcommand->get_name(); $full_name = self::get_full_name( $subcommand ); diff --git a/php/dispatcher.php b/php/dispatcher.php index da4e1b0ff..168ced1eb 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -52,18 +52,3 @@ function get_shortdesc(); function get_full_synopsis(); } - -class CallableMethod { - - function __construct( $class, $method ) { - $this->class = $class; - $this->method = $method; - } - - function __invoke( $args, $assoc_args ) { - $instance = new $this->class; - - call_user_func( array( $instance, $this->method ), $args, $assoc_args ); - } -} - From f42948036e1ff75d0fa024a31d03b8ac152a2fae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 26 Apr 2013 22:29:00 +0300 Subject: [PATCH 1544/5359] dev-build: check that 'php' is available before doing anything else see #419 --- utils/dev-build | 6 ++++++ utils/find-php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/dev-build b/utils/dev-build index 6583a472c..2f0a97dad 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -1,5 +1,11 @@ #!/usr/bin/env bash +# check that PHP is available +command -v php > /dev/null || { + echo "can't find PHP binary" >&2 + exit 1 +} + # install Composer command -v composer > /dev/null || { curl -sS https://getcomposer.org/installer | php diff --git a/utils/find-php b/utils/find-php index e1a82c470..f8d19f4a2 100755 --- a/utils/find-php +++ b/utils/find-php @@ -15,5 +15,5 @@ if [ $? -eq 0 ]; then exit fi -echo "no php binary found" +echo "no PHP binary found" >&2 exit 1 From cd784fd2c51f72a18cc81e53e8b72a79d6debe8d Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 26 Apr 2013 14:39:04 -0700 Subject: [PATCH 1545/5359] For local media imports, copy to tempfile before importing Apparently `wp_handle_sideload` performs a`rename()` operation on the file it's sideloading. In this case thats an unexpected side effect - you don't want the original image to go away when importing it to WordPress. --- php/commands/media.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 1e946f400..6fdf2b069 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -76,18 +76,30 @@ function import( $args, $assoc_args = array() ) { $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); $orig_filename = $file; - if ( !empty( $is_file_remote ) ) { - $extension = pathinfo( $file, PATHINFO_EXTENSION ); + if ( empty( $is_file_remote ) ) { + // File appears to be a local file; make a copy first to work with + + $tempfile = wp_tempnam( $file ); + if ( ! $tempfile ) + WP_CLI::error( 'Could not create temporary file.' ); + + copy( $file, $tempfile ); + + } else { + // File appear to be a remote file; download as temp file + $tempfile = download_url( $file ); - // Necessary because temp filename will probably have an extension like - // .tmp, which is not in the list of permitted upload extensions - // and won't be recognized with the correct mime type - $tempfile_extension = pathinfo( $tempfile, PATHINFO_EXTENSION ); - $file = preg_replace( "/$tempfile_extension$/", $extension, $tempfile ); - rename( $tempfile, $file ); } + // Necessary because temp filename will probably have an extension like + // .tmp, which is not in the list of permitted upload extensions + // and won't be recognized with the correct mime type + $extension = pathinfo( $file, PATHINFO_EXTENSION ); + $tempfile_extension = pathinfo( $tempfile, PATHINFO_EXTENSION ); + $file = preg_replace( "/$tempfile_extension$/", $extension, $tempfile ); + rename( $tempfile, $file ); + $file_array = array( 'tmp_name' => $file, 'name' => basename( $file ) From 10f253ebff870015142594d43c33d432645d5b41 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 26 Apr 2013 15:32:50 -0700 Subject: [PATCH 1546/5359] Add behat features to test against local files One test for failure on trying to import non-existant image, and one to make sure that local images are not removed on import --- features/media.feature | 26 +++++++++++++++++++++++++- features/steps/basic_steps.php | 26 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/features/media.feature b/features/media.feature index c247d6860..09cf8db32 100644 --- a/features/media.feature +++ b/features/media.feature @@ -13,8 +13,32 @@ Feature: Manage WordPress attachments Scenario: Import image from remote URL Given a WP install - When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` + When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ Success: Imported file http://s.wordpress.org/style/images/codeispoetry.png """ + + Scenario: Fail to import missing image + Given a WP install + + When I run `wp media import gobbledygook.png` + Then STDERR should contain: + """ + Error: Unable to import file gobbledygook.png. Reason: File is empty. + """ + + Scenario: Import a file as attachment from a local image + Given a WP install + And a large image file + + When I try to import it + Then STDOUT should contain: + """ + Success: Imported file + """ + And STDOUT should contain: + """ + and attached to post 1 as featured image + """ + And the image should not be deleted diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 4e1d8c2bf..3e4fd0a0a 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -93,6 +93,16 @@ function ( $world ) { } ); +$steps->Given( '/^a large image file$/', + function ( $world ) { + $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; + + $world->variables['DOWNLOADED_IMAGE'] = $world->get_cache_path( 'wallpaper.jpg' ); + + $world->download_file( $image_file, $world->variables['DOWNLOADED_IMAGE'] ); + } +); + $steps->When( '/^I run `wp`$/', function ( $world ) { $world->result = $world->run( '' ); @@ -120,6 +130,15 @@ function ( $world ) { } ); +$steps->When( '/^I try to import it$/', + function ( $world ) { + if ( !isset( $world->variables['DOWNLOADED_IMAGE'] ) ) + throw new \Exception( 'Cached image not available.' ); + + $world->result = $world->run( 'media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' ); + } +); + $steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', function ( $world, $stream, $key ) { $world->variables[ $key ] = rtrim( $world->result->$stream, "\n" ); @@ -232,6 +251,11 @@ function ( $world, $path ) { } ); +$steps->Then( '/^the image should not be deleted$/', + function ( $world ) { + assertFileExists( $world->variables['DOWNLOADED_IMAGE'] ); + } +); /** * Compare two strings containing JSON to ensure that @a $actualJson contains at @@ -299,4 +323,4 @@ function compareContents( $expected, $actual ) { } return true; -} \ No newline at end of file +} From 4ae855aa32147cec1db5d6a6bab1cad0550223a6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 27 Apr 2013 01:38:49 +0300 Subject: [PATCH 1547/5359] add functional test for --require flag --- features/flags.feature | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index 223fda99b..7053443bb 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -59,6 +59,28 @@ Feature: Global flags Error: Could not get a user_id for this user: 'non-existing-user' """ + Scenario: Using --require + Given a WP install + And a custom-cmd.php file: + """ + <?php + class Test_Command extends WP_CLI_Command { + + function req( $args, $assoc_args ) { + WP_CLI::line( $args[0] ); + } + } + + WP_CLI::add_command( 'test', 'Test_Command' ); + """ + + When I run `wp --require=custom-cmd.php test req 'This is a custom command.'` + Then it should run without errors + And STDOUT should be: + """ + This is a custom command. + """ + Scenario: Enabling/disabling color Given a WP install From 8652b9adbf6b50582076cf3f65dccfb82ed7a111 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 26 Apr 2013 16:55:36 -0700 Subject: [PATCH 1548/5359] Use variables in feature steps for readability Rewrote the feature step so that it displays the actual command being run, and uses variable substitution. * I had to modify the definition of the "file should exist" step to allow variable substitution. All of the existing tests still pass, but I'm not sure if this is best practice. I can write a new step instead, if that makes more sense. --- features/media.feature | 9 ++++++--- features/steps/basic_steps.php | 15 +++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/features/media.feature b/features/media.feature index 09cf8db32..e7a607cf3 100644 --- a/features/media.feature +++ b/features/media.feature @@ -10,6 +10,7 @@ Feature: Manage WordPress attachments Error: Unable to find the images """ + @images Scenario: Import image from remote URL Given a WP install @@ -19,6 +20,7 @@ Feature: Manage WordPress attachments Success: Imported file http://s.wordpress.org/style/images/codeispoetry.png """ + @images Scenario: Fail to import missing image Given a WP install @@ -28,17 +30,18 @@ Feature: Manage WordPress attachments Error: Unable to import file gobbledygook.png. Reason: File is empty. """ + @images Scenario: Import a file as attachment from a local image Given a WP install And a large image file - When I try to import it + When I run `wp media import {DOWNLOADED_IMAGE} --post_id=1 --featured_image` Then STDOUT should contain: """ - Success: Imported file + Success: Imported file """ And STDOUT should contain: """ and attached to post 1 as featured image """ - And the image should not be deleted + And the {DOWNLOADED_IMAGE} file should exist diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 3e4fd0a0a..04f299ba2 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -247,13 +247,16 @@ function ( $world, $stream ) { $steps->Then( '/^the (.+) file should exist$/', function ( $world, $path ) { - assertFileExists( $world->get_path( $path ) ); - } -); + $path = $world->replace_variables( $path ); -$steps->Then( '/^the image should not be deleted$/', - function ( $world ) { - assertFileExists( $world->variables['DOWNLOADED_IMAGE'] ); + // If $path refers to a complete cache path, use it; + // otherwise, get the real path using $world->get_path() + if ( strpos( $path, $world->get_cache_path('') ) === 0 ) + $realpath = $path; + else + $realpath = $world->get_path( $path ); + + assertFileExists( $realpath ); } ); From 49cceec63db619f89f828d00d8c67f30e9837c99 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 27 Apr 2013 13:32:13 +0300 Subject: [PATCH 1549/5359] Shorten description for `wp media import` see #367 --- man/media-import.1 | 2 +- man/media-regenerate.1 | 2 +- php/commands/media.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/media-import.1 b/man/media-import.1 index 03bb00ae0..8dca82091 100644 --- a/man/media-import.1 +++ b/man/media-import.1 @@ -4,7 +4,7 @@ .TH "WP\-MEDIA\-IMPORT" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-media\-import\fR \- Sideload images from local file(s) or URL and import as attachments, optionally attached to a post +\fBwp\-media\-import\fR \- Create attachments from local files or from URLs\. . .SH "SYNOPSIS" wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fIalt_text\fR] [\-\-desc=\fIdescription\fR] [\-\-featured_image] diff --git a/man/media-regenerate.1 b/man/media-regenerate.1 index 8591e809a..c829722ac 100644 --- a/man/media-regenerate.1 +++ b/man/media-regenerate.1 @@ -4,7 +4,7 @@ .TH "WP\-MEDIA\-REGENERATE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-media\-regenerate\fR \- Regenerate thumbnail(s) +\fBwp\-media\-regenerate\fR \- Regenerate thumbnail(s)\. . .SH "SYNOPSIS" wp media regenerate \fIattachment\-id\fR\.\.\. [\-\-yes] diff --git a/php/commands/media.php b/php/commands/media.php index 6fdf2b069..0ee75de29 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -8,7 +8,7 @@ class Media_Command extends WP_CLI_Command { /** - * Regenerate thumbnail(s) + * Regenerate thumbnail(s). * * @synopsis <attachment-id>... [--yes] */ @@ -54,7 +54,7 @@ function regenerate( $args, $assoc_args = array() ) { } /** - * Sideload images from local file(s) or URL and import as attachments, optionally attached to a post + * Create attachments from local files or from URLs. * * @synopsis <file>... [--post_id=<post_id>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] [--featured_image] */ From c4d4adb0059a68832ad471336a254cd005cb62c3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 27 Apr 2013 13:33:55 +0300 Subject: [PATCH 1550/5359] nested ternary operators are bad, mkay... see #367 --- php/commands/media.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 0ee75de29..e8c668ba9 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -121,10 +121,12 @@ function import( $args, $assoc_args = array() ) { if ( !is_wp_error( $success ) && $assoc_args['post_id'] && $assoc_args['featured_image'] ) update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); - $attachment_success_text = ( $assoc_args['post_id'] && get_post( $assoc_args['post_id'] ) ) ? - " and attached to post {$assoc_args['post_id']}" . - ( ( $assoc_args['featured_image'] ) ? ' as featured image' : '' ) - : ''; + $attachment_success_text = ''; + if ( $assoc_args['post_id'] && get_post( $assoc_args['post_id'] ) ) { + $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; + if ( $assoc_args['featured_image'] ) + $attachment_success_text .= ' as featured image'; + } if ( is_wp_error( $success ) ) WP_CLI::error( From 93aab78fd284e62f395b36a4779f0318d8732fca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 27 Apr 2013 13:38:17 +0300 Subject: [PATCH 1551/5359] validate --post_id only once and issue warning see #367 --- php/commands/media.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index e8c668ba9..64e954018 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -63,7 +63,7 @@ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( - 'post_id' => 0, + 'post_id' => false, 'title' => null, 'caption' => null, 'alt' => null, @@ -71,7 +71,12 @@ function import( $args, $assoc_args = array() ) { ) ); - foreach( $args as $file ) { + if ( !get_post( $assoc_args['post_id'] ) ) { + WP_CLI::warning( "Invalid --post_id" ); + $assoc_args['post_id'] = false; + } + + foreach ( $args as $file ) { $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); $orig_filename = $file; @@ -122,7 +127,7 @@ function import( $args, $assoc_args = array() ) { update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); $attachment_success_text = ''; - if ( $assoc_args['post_id'] && get_post( $assoc_args['post_id'] ) ) { + if ( $assoc_args['post_id'] ) { $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; if ( $assoc_args['featured_image'] ) $attachment_success_text .= ' as featured image'; From 15ba7e0618a9d5e762a9159a8c19f90cedb837f7 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Sat, 27 Apr 2013 17:36:50 +0000 Subject: [PATCH 1552/5359] Update man pages --- man-src/blog-empty.txt | 3 +++ man/blog-empty.1 | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 man-src/blog-empty.txt create mode 100644 man/blog-empty.1 diff --git a/man-src/blog-empty.txt b/man-src/blog-empty.txt new file mode 100644 index 000000000..80db5732c --- /dev/null +++ b/man-src/blog-empty.txt @@ -0,0 +1,3 @@ +## EXAMPLES + + wp blog empty \ No newline at end of file diff --git a/man/blog-empty.1 b/man/blog-empty.1 new file mode 100644 index 000000000..137b9c69c --- /dev/null +++ b/man/blog-empty.1 @@ -0,0 +1,19 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-BLOG\-EMPTY" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-blog\-empty\fR \- Empty a blog +. +.SH "SYNOPSIS" +wp blog empty +. +.SH "EXAMPLES" +. +.nf + +wp blog empty +. +.fi + From 670a00d4b35e5b290f8f6fc10ece54a79dc04d81 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 27 Apr 2013 16:57:55 -0700 Subject: [PATCH 1553/5359] Ensure `wp post list` returns posts of all statuses by default, as WP_Query behaves differently in the WP_ADMIN context. See #412 --- php/commands/post.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 7dec70541..d58f90b80 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -164,7 +164,8 @@ protected function _delete( $post_id, $assoc_args ) { */ public function _list( $_, $assoc_args ) { $query_args = array( - 'posts_per_page' => -1 + 'posts_per_page' => -1, + 'post_status' => 'any', ); if ( ! empty( $assoc_args['format'] ) ) { From e07da7ad0de88a8f214914b6e4c49f25f6a7ca14 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 27 Apr 2013 17:17:31 -0700 Subject: [PATCH 1554/5359] Update composer.lock to latest --- composer.lock | 92 ++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/composer.lock b/composer.lock index bdbb23f0b..9bd1adfaa 100644 --- a/composer.lock +++ b/composer.lock @@ -1,4 +1,8 @@ { + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], "hash": "f2b06fd19e26795775358b054c6fb09d", "packages": [ { @@ -445,16 +449,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.15", + "version": "3.7.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.15" + "reference": "3.7.19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.15", - "reference": "3.7.15", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.19", + "reference": "3.7.19", "shasum": "" }, "require": { @@ -468,7 +472,7 @@ "phpunit/php-text-template": ">=1.1.1", "phpunit/php-timer": ">=1.0.2,<1.1.0", "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.2.0" + "symfony/yaml": ">=2.0.0,<2.3.0" }, "require-dev": { "pear-pear/pear": "1.9.4" @@ -515,7 +519,7 @@ "testing", "xunit" ], - "time": "2013-03-01 11:55:06" + "time": "2013-03-25 11:45:06" }, { "name": "phpunit/phpunit-mock-objects", @@ -568,17 +572,17 @@ }, { "name": "symfony/config", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/Config", "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -611,21 +615,21 @@ ], "description": "Symfony Config Component", "homepage": "http://symfony.com", - "time": "2013-02-17 12:27:42" + "time": "2013-03-01 10:42:10" }, { "name": "symfony/console", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "v2.2.0" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.0", - "reference": "v2.2.0", + "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -658,21 +662,21 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2013-03-01 06:43:14" + "time": "2013-03-19 20:48:08" }, { "name": "symfony/dependency-injection", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/DependencyInjection", "source": { "type": "git", "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -713,21 +717,21 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "http://symfony.com", - "time": "2013-02-11 11:43:49" + "time": "2013-03-23 07:49:54" }, { "name": "symfony/event-dispatcher", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -771,17 +775,17 @@ }, { "name": "symfony/finder", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "v2.2.0" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.0", - "reference": "v2.2.0", + "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -814,21 +818,21 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2013-02-28 14:06:36" + "time": "2013-04-01 07:51:50" }, { "name": "symfony/translation", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -869,21 +873,21 @@ ], "description": "Symfony Translation Component", "homepage": "http://symfony.com", - "time": "2013-02-08 16:10:57" + "time": "2013-04-01 08:06:05" }, { "name": "symfony/yaml", - "version": "v2.2.0", + "version": "v2.2.1", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.2.0-RC3" + "reference": "v2.2.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.1", + "reference": "v2.2.1", "shasum": "" }, "require": { @@ -916,7 +920,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2013-01-27 16:49:19" + "time": "2013-03-23 07:49:54" } ], "aliases": [ @@ -926,5 +930,11 @@ "stability-flags": { "wp-cli/php-cli-tools": 20, "behat/behat": 0 - } + }, + "platform": { + "php": ">=5.3" + }, + "platform-dev": [ + + ] } From 8e57994640c506071159b263bcb7a0958ca8c71b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 28 Apr 2013 18:07:39 -0700 Subject: [PATCH 1555/5359] Fix typo --- features/post.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index ee5efed9d..d2677bb68 100644 --- a/features/post.feature +++ b/features/post.feature @@ -28,7 +28,7 @@ Feature: Manage WordPress posts When I run the previous command again Then the return code should be 1 - Scenario: Creating/geting posts + Scenario: Creating/getting posts Given a WP install When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` From d74921231b6634447cd6c4445674c1c745082dd6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 28 Apr 2013 18:44:39 -0700 Subject: [PATCH 1556/5359] Behat step for checking a CSV contains string --- features/steps/basic_steps.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 04f299ba2..d5821906f 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -231,6 +231,17 @@ function ( $world, PyStringNode $expected ) { } }); +$steps->Then( '/^STDOUT should be CSV containing:$/', + function( $world, PyStringNode $expected ) { + + $output = $world->result->STDOUT; + $expected = $world->replace_variables( (string) $expected ); + + if ( ! checkThatCsvStringContainsCsvString( $output, $expected ) ) + throw new \Exception( $output ); + } +); + $steps->Then( '/^(STDOUT|STDERR) should be empty$/', function ( $world, $stream ) { if ( !empty( $world->result->$stream ) ) { @@ -327,3 +338,20 @@ function compareContents( $expected, $actual ) { return true; } + +/** + * Compare two strings to confirm $actualCSV contains $expectedCSV + * + * @return bool Whether $actualCSV contacts $expectedCSV + */ +function checkThatCsvStringContainsCsvString( $actualCSV, $expectedCSV ) { + + $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); + $expectedCSV = array_map( 'str_getcsv', explode( PHP_EOL, $expectedCSV ) ); + + if ( ! $actualCSV ) { + return false; + } + + return compareContents( $expectedCSV, $actualCSV ); +} From 2dfa40109d828e2ed92cffadd5c2043a00ebd5a9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 28 Apr 2013 19:34:06 -0700 Subject: [PATCH 1557/5359] Refactor checkThatCsvStringContainsCsvString() such that: * expected CSV can be in any row of the actual CSV * actual CSV must contain all expected CSV data rows --- features/steps/basic_steps.php | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index d5821906f..1d10594dc 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -322,15 +322,13 @@ function compareContents( $expected, $actual ) { if ( is_object( $expected ) ) { foreach ( get_object_vars( $expected ) as $name => $value ) { - if ( !compareContents( $value, $actual->$name ) ) { + if ( ! compareContents( $value, $actual->$name ) ) return false; - } } } else if ( is_array( $expected ) ) { foreach ( $expected as $key => $value ) { - if ( !compareContents( $value, $actual[$key] ) ) { + if ( ! compareContents( $value, $actual[$key] ) ) return false; - } } } else { return $expected === $actual; @@ -341,6 +339,8 @@ function compareContents( $expected, $actual ) { /** * Compare two strings to confirm $actualCSV contains $expectedCSV + * Both strings are expected to have headers for their CSVs. + * $actualCSV must match all data rows in $expectedCSV * * @return bool Whether $actualCSV contacts $expectedCSV */ @@ -349,9 +349,27 @@ function checkThatCsvStringContainsCsvString( $actualCSV, $expectedCSV ) { $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); $expectedCSV = array_map( 'str_getcsv', explode( PHP_EOL, $expectedCSV ) ); - if ( ! $actualCSV ) { + if ( empty( $actualCSV ) ) return false; + + // Each sample must have headers + $actualHeaders = array_values( array_shift( $actualCSV ) ); + $expectedHeaders = array_values( array_shift( $expectedCSV ) ); + + // Each expectedCSV must exist somewhere in actualCSV in the proper column + $expectedResult = 0; + foreach( $expectedCSV as $expected_row ) { + $expected_row = array_combine( $expectedHeaders, $expected_row ); + foreach( $actualCSV as $actual_row ) { + + if ( count( $actualHeaders ) != count( $actual_row ) ) + continue; + + $actual_row = array_intersect_key( array_combine( $actualHeaders, $actual_row ), $expected_row ); + if ( $actual_row == $expected_row ) + $expectedResult++; + } } - return compareContents( $expectedCSV, $actualCSV ); + return $expectedResult >= count( $expectedCSV ); } From ad1b293b279e2c60facdd0693436daae76d3fb9a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 28 Apr 2013 19:38:22 -0700 Subject: [PATCH 1558/5359] Test: `wp post list` should contain both 'draft' and 'publish' posts --- features/post.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/features/post.feature b/features/post.feature index d2677bb68..3fa02b1d6 100644 --- a/features/post.feature +++ b/features/post.feature @@ -65,3 +65,23 @@ Feature: Manage WordPress posts """ {"ID":{POST_ID},"post_title":"Test post","post_content":"Test content."} """ + + Scenario: Creating/listing posts + Given a WP install + + When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` + Then it should run without errors + And STDOUT should match '%d' + + When I run `wp post create --post_title='Draft post' --post_content='Draft post content' --post_status='draft' --porcelain` + Then it should run without errors + And STDOUT should match '%d' + + When I run `wp post list --post_type='post' --format=csv` + Then it should run without errors + And STDOUT should be CSV containing: + """ + post_title,post_name + "Publish post",publish-post + "Draft post", + """ From 9105cbba89dd3d78b4e5f2c7077e5d8ba06f4db8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 14:45:00 +0300 Subject: [PATCH 1559/5359] add post_status to `wp post list` output --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index d58f90b80..a1b3aa65c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -187,7 +187,7 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); - $fields = array( 'ID', 'post_title', 'post_name', 'post_date' ); + $fields = array( 'ID', 'post_title', 'post_name', 'post_date', 'post_status' ); $output_posts = $query->posts; From 54a65ecd35f227b2969e8401b1648dd512d84666 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 18:16:26 +0300 Subject: [PATCH 1560/5359] Rename `wp db connect` back to `wp db cli` `db connect` is rather ambigous: you connect to the database, and then what?! `db cli` is more explicit: connect to the database and open a MySQL command-line session --- man/db.1 | 10 ++-------- php/commands/db.php | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/man/db.1 b/man/db.1 index 99983e2d3..80c7f34ce 100644 --- a/man/db.1 +++ b/man/db.1 @@ -22,7 +22,7 @@ wp db optimize wp db repair . .P -wp db connect +wp db cli . .P wp db query \fIsql\fR @@ -36,7 +36,7 @@ wp db import [\fIfile\fR] .SH "SUBCOMMANDS" . .TP -\fBconnect\fR: +\fBcli\fR: . .IP Open a mysql console using the WordPress credentials\. @@ -91,12 +91,6 @@ Remove all tables from the database\. . .SH "OPTIONS" -. -.TP -\fB\-\-str\fR: -. -.IP -Show the mysql command, instead of executing it\. . .TP \fB\-\-yes\fR: diff --git a/php/commands/db.php b/php/commands/db.php index 300b82740..c411413a4 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -71,9 +71,9 @@ function repair() { /** * Open a mysql console using the WordPress credentials. * - * @alias cli + * @alias connect */ - function connect() { + function cli() { self::run( 'mysql', Utils\create_cmd( '--host=%s --user=%s --database=%s', DB_HOST, DB_USER, DB_NAME ) ); From b52917e1ad7f11b61c76951b7fa4f988825f54b7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 18:58:33 +0300 Subject: [PATCH 1561/5359] Use `wp core download` in Travis tests too. --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e470d86ce..48687d040 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,10 +17,7 @@ before_script: # install dependencies - composer install --dev --no-interaction --prefer-source # set up WP install - - WP_CORE_DIR=/tmp/wp-cli-test-core-download-cache/ - - mkdir -p $WP_CORE_DIR - - wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/wordpress-$WP_VERSION.tar.gz - - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + - bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ # set up database - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot From abc3facc04401f03d68f9d496df90ebbd06fb758 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 19:22:31 +0300 Subject: [PATCH 1562/5359] core download: remove duplicate code for creating the directory --- php/commands/core.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8f29005a8..391ba1402 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -18,7 +18,7 @@ public function download( $args, $assoc_args ) { if ( !is_dir( ABSPATH ) ) { WP_CLI::line( sprintf( 'Creating directory %s', ABSPATH ) ); - WP_CLI::launch( 'mkdir -p ' . escapeshellarg( ABSPATH ) ); + WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); } if ( isset( $assoc_args['locale'] ) ) { @@ -35,8 +35,7 @@ public function download( $args, $assoc_args ) { } $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; - - WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); + $curl_command = 'curl -f' . $silent . escapeshellarg( $download_url ); $tar_command = sprintf( 'tar xz --directory=%s --strip-components=1', escapeshellarg( ABSPATH ) ); WP_CLI::launch( $curl_command . ' | ' . $tar_command ); From 86d713c9ceae21c4d4cb77cc3a31201c324162cb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 19:29:55 +0300 Subject: [PATCH 1563/5359] core download: refactor curl + tar into a single command string --- php/commands/core.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 391ba1402..d3f13b743 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -34,11 +34,10 @@ public function download( $args, $assoc_args ) { WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - $silent = WP_CLI::get_config('quiet') ? ' --silent ' : ' '; + $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; - $curl_command = 'curl -f' . $silent . escapeshellarg( $download_url ); - $tar_command = sprintf( 'tar xz --directory=%s --strip-components=1', escapeshellarg( ABSPATH ) ); - WP_CLI::launch( $curl_command . ' | ' . $tar_command ); + $cmd = "curl -f $silent %s | tar xz --strip-components=1 --directory=%s"; + WP_CLI::launch( \WP_CLI\Utils\create_cmd( $cmd, $download_url, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); } From 46813ade0679ba8c15cc04f1c127a2e454ec5b58 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 19:31:45 +0300 Subject: [PATCH 1564/5359] core command: "use WP_CLI\Utils;" --- php/commands/core.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d3f13b743..e62a2ea69 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1,5 +1,7 @@ <?php +use \WP_CLI\Utils; + /** * Download, install, update and otherwise manage WordPress proper. * @@ -37,7 +39,7 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; $cmd = "curl -f $silent %s | tar xz --strip-components=1 --directory=%s"; - WP_CLI::launch( \WP_CLI\Utils\create_cmd( $cmd, $download_url, ABSPATH ) ); + WP_CLI::launch( Utils\create_cmd( $cmd, $download_url, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); } @@ -161,7 +163,7 @@ public function install_network( $args, $assoc_args ) { } private static function modify_wp_config( $content ) { - $wp_config_path = WP_CLI\Utils\locate_wp_config(); + $wp_config_path = Utils\locate_wp_config(); $token = "/* That's all, stop editing!"; @@ -270,7 +272,7 @@ function update( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $result = WP_CLI\Utils\get_upgrader( $upgrader )->upgrade( $update ); + $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); @@ -318,7 +320,7 @@ function init_tests( $args, $assoc_args ) { // Create the database $query = sprintf( 'CREATE DATABASE IF NOT EXISTS `%s`', $assoc_args['dbname'] ); - \WP_CLI\Utils\run_mysql_query( $query, array( + Utils\run_mysql_query( $query, array( 'host' => 'localhost', 'user' => $assoc_args['dbuser'], 'pass' => $assoc_args['dbpass'], From 62b97c9b048d450e1066cecec67dfe51d9febc7c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 19:38:51 +0300 Subject: [PATCH 1565/5359] rename create_cmd() to esc_cmd() Matches WP escaping functions: esc_sql(), esc_html() etc. --- features/bootstrap/FeatureContext.php | 6 +++--- php/commands/core.php | 2 +- php/commands/db.php | 10 +++++----- php/utils.php | 7 +++++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index fd2fdf2d9..19b7025c2 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -94,14 +94,14 @@ public function get_cache_path( $file ) { if ( !$path ) { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - system( Utils\create_cmd( 'mkdir -p %s', $path ) ); + system( Utils\esc_cmd( 'mkdir -p %s', $path ) ); } return $path . '/' . $file; } public function download_file( $url, $path ) { - system( Utils\create_cmd( 'curl -sSL %s > %s', $url, $path ) ); + system( Utils\esc_cmd( 'curl -sSL %s > %s', $url, $path ) ); } private static function run_sql( $sql ) { @@ -187,7 +187,7 @@ public function download_wordpress_files( $subdir = '' ) { if ( $subdir ) mkdir( $dest_dir ); - $cmd = Utils\create_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); + $cmd = Utils\esc_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); system( $cmd ); } diff --git a/php/commands/core.php b/php/commands/core.php index e62a2ea69..3c3724abb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -39,7 +39,7 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; $cmd = "curl -f $silent %s | tar xz --strip-components=1 --directory=%s"; - WP_CLI::launch( Utils\create_cmd( $cmd, $download_url, ABSPATH ) ); + WP_CLI::launch( Utils\esc_cmd( $cmd, $download_url, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); } diff --git a/php/commands/db.php b/php/commands/db.php index c411413a4..a14c286f1 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -49,7 +49,7 @@ function reset( $_, $assoc_args ) { * Optimize the database. */ function optimize() { - self::run( 'mysqlcheck', Utils\create_cmd( + self::run( 'mysqlcheck', Utils\esc_cmd( '--optimize --host=%s --user=%s %s', DB_HOST, DB_USER, DB_NAME ) ); @@ -61,7 +61,7 @@ function optimize() { * Repair the database. */ function repair() { - self::run( 'mysqlcheck', Utils\create_cmd( + self::run( 'mysqlcheck', Utils\esc_cmd( '--repair --host=%s --user=%s %s', DB_HOST, DB_USER, DB_NAME ) ); @@ -74,7 +74,7 @@ function repair() { * @alias connect */ function cli() { - self::run( 'mysql', Utils\create_cmd( + self::run( 'mysql', Utils\esc_cmd( '--host=%s --user=%s --database=%s', DB_HOST, DB_USER, DB_NAME ) ); } @@ -100,7 +100,7 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( 'mysqldump', Utils\create_cmd( + self::run( 'mysqldump', Utils\esc_cmd( '%s --user=%s --host=%s --result-file %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); @@ -115,7 +115,7 @@ function export( $args, $assoc_args ) { function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( 'mysql', Utils\create_cmd( + self::run( 'mysql', Utils\esc_cmd( '%s --user=%s --host=%s < %s', DB_NAME, DB_USER, DB_HOST, $result_file ) ); diff --git a/php/utils.php b/php/utils.php index 3489393d7..3521a2a62 100644 --- a/php/utils.php +++ b/php/utils.php @@ -138,7 +138,10 @@ function assoc_args_to_str( $assoc_args ) { * Given a template string and an arbitrary number of arguments, * returns the final command, with the parameters escaped. */ -function create_cmd( $cmd ) { +function esc_cmd( $cmd ) { + if ( func_num_args() < 2 ) + trigger_error( 'esc_cmd() requires at least two arguments.', E_USER_WARNING ); + $args = func_get_args(); $cmd = array_shift( $args ); @@ -368,7 +371,7 @@ function find_subcommand( $args ) { function run_mysql_query( $query, $args ) { // TODO: use PDO? - $arg_str = create_cmd( '--host=%s --user=%s --execute=%s', + $arg_str = esc_cmd( '--host=%s --user=%s --execute=%s', $args['host'], $args['user'], $query ); run_mysql_command( 'mysql', $arg_str, $args['pass'] ); From 6fea8a4e49497b5c2642dd979b1594dc6d4390fb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 20:41:03 +0300 Subject: [PATCH 1566/5359] since it's called dev-build, install the development dependencies --- utils/dev-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/dev-build b/utils/dev-build index 2f0a97dad..299460360 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -13,7 +13,7 @@ command -v composer > /dev/null || { } # install dependencies -composer install +composer install --dev # add symlink to wp binary for dir in /usr/bin /usr/local/bin; do From d966e0bda697e358ebd5641dc572d8b6e0be1fa6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 18:36:25 +0300 Subject: [PATCH 1567/5359] make `wp db query` optionally read from STDIN --- php/commands/db.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index a14c286f1..e19cc1428 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -82,10 +82,14 @@ function cli() { /** * Execute a query against the database. * - * @synopsis <sql> + * @synopsis [<sql>] */ function query( $args ) { - list( $query ) = $args; + if ( empty( $args ) ) { + $query = file_get_contents( 'php://stdin' ); + } else { + list( $query ) = $args; + } self::run_query( $query ); } From bf8d5bb929f3de1baa66798b0b012da9ab42afff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 20:46:52 +0300 Subject: [PATCH 1568/5359] test that database is selected --- features/db.feature | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/features/db.feature b/features/db.feature index 1d440234e..30630fa6c 100644 --- a/features/db.feature +++ b/features/db.feature @@ -24,9 +24,6 @@ Feature: Perform database operations Then it should run without errors And STDOUT should not be empty - When I run `wp db query 'SELECT 42 FROM dual'` + When I run `wp db query 'SELECT COUNT(*) FROM wp_posts'` Then it should run without errors - And STDOUT should contain: - """ - 42 - """ + And STDOUT should match '%d' From 67b2c3d4890e5865ad9100a0b320bbc8f1017249 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 21:08:34 +0300 Subject: [PATCH 1569/5359] db query: select database Also, let WP_CLI::launch() proxy STDIN, instead of reading it explicitly. --- features/db.feature | 22 ++++++++++++++++++++-- php/commands/db.php | 11 ++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/features/db.feature b/features/db.feature index 30630fa6c..ca3241111 100644 --- a/features/db.feature +++ b/features/db.feature @@ -24,6 +24,24 @@ Feature: Perform database operations Then it should run without errors And STDOUT should not be empty - When I run `wp db query 'SELECT COUNT(*) FROM wp_posts'` + Scenario: DB Query + Given a WP install + + When I run `wp db query 'SELECT COUNT(*) as total FROM wp_posts'` + Then it should run without errors + And STDOUT should contain: + """ + total + """ + + Given a debug.sql file: + """ + SELECT COUNT(*) as total FROM wp_posts + """ + + When I run `wp db query < debug.sql` Then it should run without errors - And STDOUT should match '%d' + And STDOUT should contain: + """ + total + """ diff --git a/php/commands/db.php b/php/commands/db.php index e19cc1428..662306d5f 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -85,13 +85,14 @@ function cli() { * @synopsis [<sql>] */ function query( $args ) { - if ( empty( $args ) ) { - $query = file_get_contents( 'php://stdin' ); - } else { - list( $query ) = $args; + $cmd = '--host=%s --user=%s --database=%s'; + $cmd = Utils\esc_cmd( $cmd, DB_HOST, DB_USER, DB_NAME ); + + if ( !empty( $args ) ) { + $cmd .= Utils\esc_cmd( ' --execute=%s', $args[0] ); } - self::run_query( $query ); + self::run( 'mysql', $cmd ); } /** From 172ff6d65c0ed4ef586550c38cd311a5136eb5ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 29 Apr 2013 21:13:37 +0300 Subject: [PATCH 1570/5359] man: add `wp db query` example --- man-src/db.txt | 4 ++++ man/db.1 | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/man-src/db.txt b/man-src/db.txt index e60509350..a9fb12bfd 100644 --- a/man-src/db.txt +++ b/man-src/db.txt @@ -11,3 +11,7 @@ * `<SQL>`: A SQL query. + +## EXAMPLES + +wp db query < debug.sql diff --git a/man/db.1 b/man/db.1 index 80c7f34ce..98c8a6b8e 100644 --- a/man/db.1 +++ b/man/db.1 @@ -25,7 +25,7 @@ wp db repair wp db cli . .P -wp db query \fIsql\fR +wp db query [\fIsql\fR] . .P wp db export [\fIfile\fR] @@ -109,4 +109,6 @@ The name of the export file\. If omitted, it will be \'{dbname}\.sql\' . .IP A SQL query\. - +. +.SH "EXAMPLES" +wp db query < debug\.sql From 37fc45c7c706f42d6574b3ff5436b57f5fadf5d2 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Mon, 29 Apr 2013 23:12:32 +0200 Subject: [PATCH 1571/5359] Fixed issue #428. Ability to display version for plugin status --- man-src/plugin-status.txt | 4 ++++ man/plugin-status.1 | 8 +++++++- php/WP_CLI/CommandWithUpgrade.php | 20 ++++++++++++++++---- php/commands/plugin.php | 7 ++++--- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/man-src/plugin-status.txt b/man-src/plugin-status.txt index daf14a99e..33135209b 100644 --- a/man-src/plugin-status.txt +++ b/man-src/plugin-status.txt @@ -3,3 +3,7 @@ * `<plugin>`: A particular plugin to show the status for. + +* `--with-version`: + + If set, the plugin version will also be shown. \ No newline at end of file diff --git a/man/plugin-status.1 b/man/plugin-status.1 index 797ffa320..126cac072 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. . .SH "SYNOPSIS" -wp plugin status [\fIplugin\fR] +wp plugin status [\fIplugin\fR] [\-\-with\-version] . .SH "OPTIONS" . @@ -16,4 +16,10 @@ wp plugin status [\fIplugin\fR] . .IP A particular plugin to show the status for\. +. +.TP +\fB\-\-with\-version\fR: +. +.IP +If set, the plugin version will also be shown\. diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 08b87ccfb..f7ba9e55f 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -20,18 +20,23 @@ abstract protected function status_single( $args ); abstract protected function install_from_repo( $slug, $assoc_args ); - function status( $args ) { + function status( $args, $assoc_args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); if ( empty( $args ) ) { - $this->status_all(); + $with_version = false; + if( in_array( 'with-version', $assoc_args ) ) { + $with_version = true; + } + + $this->status_all( $with_version ); } else { $this->status_single( $args ); } } - private function status_all() { + private function status_all( $with_version = false ) { $items = $this->get_all_items(); $n = count( $items ); @@ -47,7 +52,10 @@ private function status_all() { } $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . $details['name'] . "%n"; + $line .= " " . $details['name']; + if ( $with_version ) { + $line .= " " . $this->format_version( $details['version'] ) . "%n"; + } \WP_CLI::line( $line ); } @@ -183,6 +191,10 @@ protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } + protected function format_version( $version ) { + return '%c' . $version; + } + private function get_color( $status ) { static $colors = array( 'inactive' => '', diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ea01f2a9a..4c01e3d59 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -22,10 +22,10 @@ function __construct() { /** * See the status of one or all plugins. * - * @synopsis [<plugin>] + * @synopsis [<plugin>] [--with-version] */ - function status( $args ) { - parent::status( $args ); + function status( $args, $assoc_args ) { + parent::status( $args, $assoc_args ); } protected function status_single( $args ) { @@ -240,6 +240,7 @@ protected function get_item_list() { 'name' => $this->get_name( $file ), 'status' => $this->get_status( $file ), 'update' => $this->has_update( $file ), + 'version' => $details['Version'], 'update_id' => $file, ); } From c5f438b1657ff3fbbb0a2b55174ea887b6dc5a7d Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Tue, 30 Apr 2013 01:05:19 +0200 Subject: [PATCH 1572/5359] show version default, remove color from version and align left --- man-src/plugin-status.txt | 6 +----- man/plugin-status.1 | 8 +------ php/WP_CLI/CommandWithUpgrade.php | 36 +++++++++++++++++++------------ php/commands/plugin.php | 6 +++--- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/man-src/plugin-status.txt b/man-src/plugin-status.txt index 33135209b..6902ac270 100644 --- a/man-src/plugin-status.txt +++ b/man-src/plugin-status.txt @@ -2,8 +2,4 @@ * `<plugin>`: - A particular plugin to show the status for. - -* `--with-version`: - - If set, the plugin version will also be shown. \ No newline at end of file + A particular plugin to show the status for. \ No newline at end of file diff --git a/man/plugin-status.1 b/man/plugin-status.1 index 126cac072..797ffa320 100644 --- a/man/plugin-status.1 +++ b/man/plugin-status.1 @@ -7,7 +7,7 @@ \fBwp\-plugin\-status\fR \- See the status of one or all plugins\. . .SH "SYNOPSIS" -wp plugin status [\fIplugin\fR] [\-\-with\-version] +wp plugin status [\fIplugin\fR] . .SH "OPTIONS" . @@ -16,10 +16,4 @@ wp plugin status [\fIplugin\fR] [\-\-with\-version] . .IP A particular plugin to show the status for\. -. -.TP -\fB\-\-with\-version\fR: -. -.IP -If set, the plugin version will also be shown\. diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index f7ba9e55f..a994eb22d 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -20,23 +20,18 @@ abstract protected function status_single( $args ); abstract protected function install_from_repo( $slug, $assoc_args ); - function status( $args, $assoc_args ) { + function status( $args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); if ( empty( $args ) ) { - $with_version = false; - if( in_array( 'with-version', $assoc_args ) ) { - $with_version = true; - } - - $this->status_all( $with_version ); + $this->status_all(); } else { $this->status_single( $args ); } } - private function status_all( $with_version = false ) { + private function status_all() { $items = $this->get_all_items(); $n = count( $items ); @@ -44,18 +39,17 @@ private function status_all( $with_version = false ) { // Not interested in the translation, just the number logic \WP_CLI::line( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); + $padding = $this->get_padding($items); + foreach ( $items as $file => $details ) { if ( $details['update'] ) { $line = ' %yU%n'; } else { $line = ' '; } - $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . $details['name']; - if ( $with_version ) { - $line .= " " . $this->format_version( $details['version'] ) . "%n"; - } + $line .= " " . str_pad( $details['name'], $padding ); + $line .= "%n " . $this->format_version( $details['version'] ) . "%n"; \WP_CLI::line( $line ); } @@ -65,6 +59,20 @@ private function status_all( $with_version = false ) { $this->show_legend( $items ); } + private function get_padding( $items ) { + $max_len = 0; + + foreach ( $items as $details ) { + $len = strlen( $details['name'] ); + + if ( $len > $max_len ) { + $max_len = $len; + } + } + + return $max_len; + } + private function show_legend( $items ) { $statuses = array_unique( wp_list_pluck( $items, 'status' ) ); @@ -192,7 +200,7 @@ protected function format_status( $status, $format ) { } protected function format_version( $version ) { - return '%c' . $version; + return '' . $version; } private function get_color( $status ) { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 4c01e3d59..f761afb19 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -22,10 +22,10 @@ function __construct() { /** * See the status of one or all plugins. * - * @synopsis [<plugin>] [--with-version] + * @synopsis [<plugin>] */ - function status( $args, $assoc_args ) { - parent::status( $args, $assoc_args ); + function status( $args ) { + parent::status( $args ); } protected function status_single( $args ) { From 0021a7363bce5dae043c8f0512b7f1c467126930 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Tue, 30 Apr 2013 11:39:58 +0200 Subject: [PATCH 1573/5359] Check empty version for mu-plugins, remove unnecessary formatting --- php/WP_CLI/CommandWithUpgrade.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index a994eb22d..01d1c06a3 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -48,8 +48,10 @@ private function status_all() { $line = ' '; } $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . str_pad( $details['name'], $padding ); - $line .= "%n " . $this->format_version( $details['version'] ) . "%n"; + $line .= " " . str_pad( $details['name'], $padding ). "%n"; + if ( !empty( $details['version'] ) ) { + $line .= " " . $details['version']; + } \WP_CLI::line( $line ); } @@ -199,10 +201,6 @@ protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } - protected function format_version( $version ) { - return '' . $version; - } - private function get_color( $status ) { static $colors = array( 'inactive' => '', From af75f064de177106040541897a23ee8bc1702c2d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 16:55:01 +0300 Subject: [PATCH 1574/5359] add basic shell smoke test --- features/shell.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 features/shell.feature diff --git a/features/shell.feature b/features/shell.feature new file mode 100644 index 000000000..924f84fa0 --- /dev/null +++ b/features/shell.feature @@ -0,0 +1,11 @@ +Feature: WordPress REPL + + Scenario: Blank session + Given a WP install + + When I run `wp shell < /dev/null` + Then it should run without errors + And STDOUT should be: + """ + Type "exit" to close session. + """ From 55f887dc50c66626f9cb187132d36f886904bdb1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 17:21:48 +0300 Subject: [PATCH 1575/5359] shell: use WP_CLI::print_value(), since we don't want to colorize the output --- php/commands/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 02daaed99..d379d93a6 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -36,7 +36,7 @@ public function __invoke() { eval( $line ); - \WP_CLI::line( var_export( $_, false ) ); + \WP_CLI::print_value( var_export( $_, false ) ); } } } From 938d2ba47491ea86a965f125f224ba3536ee9ce9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 17:26:51 +0300 Subject: [PATCH 1576/5359] behat: add newline to generated files `wp shell` expects it --- features/shell.feature | 20 ++++++++++++++++++++ features/steps/basic_steps.php | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/features/shell.feature b/features/shell.feature index 924f84fa0..213177204 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -9,3 +9,23 @@ Feature: WordPress REPL """ Type "exit" to close session. """ + + Scenario: Basic session + Given a WP install + And a session file: + """ + WP_ADMIN + $_ + get_current_user_id() + $_ + """ + + When I run `wp shell --quiet < session` + Then it should run without errors + And STDOUT should be: + """ + true + true + 0 + 0 + """ diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 1d10594dc..0002a6c54 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -12,7 +12,8 @@ function ( $world ) { $steps->Given( '/^a ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { - file_put_contents( $world->get_path( $path ), (string) $content ); + $content = (string) $content . "\n"; + file_put_contents( $world->get_path( $path ), $content ); } ); From b5b6abcc10b4ee6196d0abbd48d7639d1c2f3b1c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 18:02:02 +0300 Subject: [PATCH 1577/5359] travis: don't send email notifications on success Branches always go through pull requests, which give plenty of feedback about the build status. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 48687d040..f6bfe635b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,3 +23,7 @@ before_script: - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot script: vendor/bin/phpunit && vendor/bin/behat + +notifications: + email: + on_success: never From e7dd57240e6f958f6357985b2a35629a69fa6028 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 18:17:22 +0300 Subject: [PATCH 1578/5359] test declaring functions and variables in a shell session --- features/shell.feature | 19 ++++++++++++++++++- php/commands/shell.php | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index 213177204..8c29ca78d 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -10,7 +10,7 @@ Feature: WordPress REPL Type "exit" to close session. """ - Scenario: Basic session + Scenario: $_ special variable Given a WP install And a session file: """ @@ -29,3 +29,20 @@ Feature: WordPress REPL 0 0 """ + + Scenario: Persistent environment + Given a WP install + And a session file: + """ + function is_empty_string( $str ) { return strlen( $str ) == 0; } + 1; $a = get_option('home') + is_empty_string( $a ) + """ + + When I run `wp shell --quiet < session` + Then it should run without errors + And STDOUT should be: + """ + 1 + false + """ diff --git a/php/commands/shell.php b/php/commands/shell.php index d379d93a6..32e0808a2 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -43,7 +43,7 @@ public function __invoke() { private static function non_expressions() { return implode( '|', array( - 'echo', 'global', 'unset', + 'echo', 'global', 'unset', 'function', 'while', 'for', 'foreach', 'if', 'switch', 'include', 'include\_once', 'require', 'require\_once' ) ); From 5ca08111848514241bb2cdb1d0d956660fd0dbda Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 18:26:28 +0300 Subject: [PATCH 1579/5359] add test for 'history' builtin; see #373 --- features/shell.feature | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/features/shell.feature b/features/shell.feature index 8c29ca78d..9015f678d 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -46,3 +46,22 @@ Feature: WordPress REPL 1 false """ + + Scenario: History builtin + Given a WP install + And a session file: + """ + defined('WP_CLI') + function foo() {} + history + """ + + When I run `wp shell --quiet < session` + Then it should run without errors + And STDOUT should be: + """ + true + defined('WP_CLI'); + function foo() {}; + """ + From 8fa99e9b589dc80a69bff2bcf19f0f7aff7a1b9b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 19:37:47 +0300 Subject: [PATCH 1580/5359] Add multiline support to `wp shell` via backslash We could remove the -r flag from the `read` builtin, but that would have several drawbacks: * couldn't dynamically change the prompt * would add another layer of escaping, on top of PHP's eval() --- features/shell.feature | 18 ++++++++++++++++++ php/commands/shell.php | 34 +++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index 9015f678d..2cc9c47f8 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -65,3 +65,21 @@ Feature: WordPress REPL function foo() {}; """ + Scenario: Multiline support + Given a WP install + And a session file: + """ + function is_empty_string( $str ) { \ + return strlen( $str ) == 0; \ + } + + function_exists( 'is_empty_string' ) + """ + + When I run `wp shell --quiet < session` + Then it should run without errors + And STDOUT should be: + """ + true + """ + diff --git a/php/commands/shell.php b/php/commands/shell.php index 32e0808a2..0c586ccc4 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -50,21 +50,37 @@ private static function non_expressions() { } private function prompt() { - static $cmd; + $full_line = false; - if ( !$cmd ) { - $cmd = self::create_prompt_cmd( 'wp> ', $this->history_file ); - } + $done = false; + do { + $prompt = ( !$done && $full_line !== false ) ? '--> ' : 'wp> '; + + $fp = popen( self::create_prompt_cmd( $prompt, $this->history_file ), 'r' ); + + $line = fgets( $fp ); + + if ( !$line ) { + break; + } + + $line = rtrim( $line, "\n" ); + + if ( $line && '\\' == $line[ strlen( $line ) - 1 ] ) { + $line = substr( $line, 0, -1 ); + } else { + $done = true; + } - $fp = popen( $cmd, 'r' ); + $full_line .= $line; - $line = fgets( $fp ); + } while ( !$done ); - if ( !$line ) { - $line = 'exit'; + if ( $full_line === false ) { + return 'exit'; } - return trim( $line ); + return $full_line; } private static function create_prompt_cmd( $prompt, $history_path ) { From c7739f0822ea64c71fe15f673d9932680ec07940 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Apr 2013 19:53:22 +0300 Subject: [PATCH 1581/5359] update shell man page [ci skip] --- man-src/shell.txt | 4 ++++ man/shell.1 | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/man-src/shell.txt b/man-src/shell.txt index ccd56f493..1759cffb5 100644 --- a/man-src/shell.txt +++ b/man-src/shell.txt @@ -2,4 +2,8 @@ `wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. +`$_` is a special variable that contains the result from the last evaluated statement. + +You can split a statement over multiple lines by adding a `\` (backslash) before hitting Return. + If you type `history` and hit Return, WP-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file. diff --git a/man/shell.1 b/man/shell.1 index de0e717e1..d145d4a61 100644 --- a/man/shell.1 +++ b/man/shell.1 @@ -13,4 +13,10 @@ wp shell \fBwp shell\fR allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment\. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example\. . .P +\fB$_\fR is a special variable that contains the result from the last evaluated statement\. +. +.P +You can split a statement over multiple lines by adding a \fB\e\fR (backslash) before hitting Return\. +. +.P If you type \fBhistory\fR and hit Return, WP\-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file\. From a6265228f7695b265877022f0c9acc6b35ed432a Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Wed, 1 May 2013 09:17:23 +0200 Subject: [PATCH 1582/5359] Show version on wp theme status by default --- php/commands/theme.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 9e8ad5aff..f7670c8cb 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -133,6 +133,7 @@ protected function get_item_list() { 'name' => $key, 'status' => $this->get_status( $theme ), 'update' => $this->has_update( $theme->get_stylesheet() ), + 'version' => $theme->get('Version'), 'update_id' => $theme->get_stylesheet(), ); } From 2065b139b5a17ca73e7d15f5a217d2eaf6fc3adb Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Wed, 1 May 2013 17:07:09 +0000 Subject: [PATCH 1583/5359] Rename multisite.feature to blog.feature; add feature tests for wp blog empty --- features/{multisite.feature => blog.feature} | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) rename features/{multisite.feature => blog.feature} (56%) diff --git a/features/multisite.feature b/features/blog.feature similarity index 56% rename from features/multisite.feature rename to features/blog.feature index 536fed7f5..264dd66d4 100644 --- a/features/multisite.feature +++ b/features/blog.feature @@ -1,4 +1,4 @@ -Feature: Manage a WordPress multisite installation +Feature: Manage a WordPress installation Scenario: Install multisite Given a WP install @@ -37,3 +37,26 @@ Feature: Manage a WordPress multisite installation When I run the previous command again Then the return code should be 1 + + Scenario: Empty a blog + Given a WP install + + When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp blog empty --yes` + Then it should run without errors + And STDOUT should not be empty + + When I run `wp post list --format=ids` + Then it should run without errors + And STDOUT should be empty + + When I run `wp term list post_tag --format=ids` + Then it should run without errors + And STDOUT should be empty \ No newline at end of file From 5b203f5594b8a095518a37af7cf5e43a80a7506c Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Wed, 1 May 2013 17:14:06 +0000 Subject: [PATCH 1584/5359] Add docblock mention for --yes flag --- php/commands/blog.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/blog.php b/php/commands/blog.php index 32229c684..15686aa80 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -111,6 +111,7 @@ private function _insert_default_terms() { * Empty a blog * * @subcommand empty + * @synopsis [--yes] */ public function _empty( $args, $assoc_args ) { From c7b4d0691a5f14799e9bbc531c70a1ef49c4351b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 3 May 2013 18:50:51 +0300 Subject: [PATCH 1585/5359] remove empty constructor from MS_Blog_Command see #416 and #410 --- php/commands/blog.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 15686aa80..ae91486ae 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -131,8 +131,6 @@ public function _empty( $args, $assoc_args ) { */ class MS_Blog_Command extends Blog_Command { - public function __construct() { } - /** * Delete a blog in a multisite install. * From eb7584f30ec4872703fce07c5260b371c245bc6c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 3 May 2013 19:55:38 +0300 Subject: [PATCH 1586/5359] add missing dots to blog subcommand descriptions see #410 --- man/blog-empty.1 | 4 ++-- php/commands/blog.php | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/man/blog-empty.1 b/man/blog-empty.1 index 137b9c69c..34cf749fc 100644 --- a/man/blog-empty.1 +++ b/man/blog-empty.1 @@ -4,10 +4,10 @@ .TH "WP\-BLOG\-EMPTY" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-blog\-empty\fR \- Empty a blog +\fBwp\-blog\-empty\fR \- Empty a blog of its content\. . .SH "SYNOPSIS" -wp blog empty +wp blog empty [\-\-yes] . .SH "EXAMPLES" . diff --git a/php/commands/blog.php b/php/commands/blog.php index ae91486ae..3c38438d3 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -1,14 +1,14 @@ <?php /** - * Manage blog(s) + * Manage blog. * * @package wp-cli */ class Blog_Command extends WP_CLI_Command { /** - * Delete comments + * Delete comments. */ private function _empty_comments() { global $wpdb; @@ -24,7 +24,7 @@ private function _empty_comments() { } /** - * Delete all posts + * Delete all posts. */ private function _empty_posts() { global $wpdb; @@ -51,7 +51,7 @@ private function _empty_posts() { } /** - * Delete terms, taxonomies, and tax relationships + * Delete terms, taxonomies, and tax relationships. */ private function _empty_taxonomies() { global $wpdb; @@ -64,13 +64,13 @@ private function _empty_taxonomies() { $ids[] = $term->term_id; wp_cache_delete( $term->term_id, $term->taxonomy ); } - + $taxonomies = array_unique( $taxonomies ); foreach ( $taxonomies as $taxonomy ) { if ( isset( $cleaned[$taxonomy] ) ) continue; $cleaned[$taxonomy] = true; - + wp_cache_delete( 'all_ids', $taxonomy ); wp_cache_delete( 'get', $taxonomy ); delete_option( "{$taxonomy}_children" ); @@ -81,7 +81,7 @@ private function _empty_taxonomies() { } /** - * Insert default terms + * Insert default terms. */ private function _insert_default_terms() { global $wpdb; @@ -108,7 +108,7 @@ private function _insert_default_terms() { } /** - * Empty a blog + * Empty a blog of its content. * * @subcommand empty * @synopsis [--yes] @@ -127,7 +127,7 @@ public function _empty( $args, $assoc_args ) { } /** - * Manage blogs in a multisite install + * Manage blogs in a multisite install. */ class MS_Blog_Command extends Blog_Command { @@ -161,7 +161,7 @@ function delete( $args, $assoc_args ) { } /** - * Get site (network) data for a given id + * Get site (network) data for a given id. * * @param int $site_id * @return bool|array False if no network found with given id, array otherwise From 57d66645ee7f313dc9fe73674a1d7642ea1ee4b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 3 May 2013 21:02:53 +0300 Subject: [PATCH 1587/5359] behat: merge _run() and run() methods --- features/bootstrap/FeatureContext.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 19b7025c2..040401788 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -122,7 +122,12 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - private function _run( $command, $assoc_args, $subdir = '' ) { + public function run( $command, $assoc_args = array(), $subdir = '' ) { + if ( isset( self::$additional_args[ $command ] ) ) { + $assoc_args = array_merge( self::$additional_args[ $command ], + $assoc_args ); + } + if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); @@ -155,15 +160,6 @@ private function _run( $command, $assoc_args, $subdir = '' ) { return $r; } - public function run( $command, $assoc_args = array(), $subdir = '' ) { - if ( isset( self::$additional_args[ $command ] ) ) { - $assoc_args = array_merge( self::$additional_args[ $command ], - $assoc_args ); - } - - return $this->_run( $command, $assoc_args, $subdir ); - } - public function move_files( $src, $dest ) { rename( $this->get_path( $src ), $this->get_path( $dest ) ); } @@ -179,7 +175,7 @@ public function download_wordpress_files( $subdir = '' ) { // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - $r = $this->_run( 'core download', array( + $r = $this->run( 'core download', array( 'path' => $cache_dir ) ); From ac5b70ce6199cccfa631f48a1d6ba285918ec88f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 3 May 2013 21:45:09 +0300 Subject: [PATCH 1588/5359] behat: introduce Process class The run_check() method is a shortcut for implicitly checking that a command runs succesfully. --- features/bootstrap/FeatureContext.php | 46 +++++---------------- features/bootstrap/Process.php | 58 +++++++++++++++++++++++++++ features/steps/basic_steps.php | 22 +++++----- 3 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 features/bootstrap/Process.php diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 040401788..ab61ffe59 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -94,14 +94,14 @@ public function get_cache_path( $file ) { if ( !$path ) { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - system( Utils\esc_cmd( 'mkdir -p %s', $path ) ); + Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); } return $path . '/' . $file; } public function download_file( $url, $path ) { - system( Utils\esc_cmd( 'curl -sSL %s > %s', $url, $path ) ); + Process::create( Utils\esc_cmd( 'curl -sSL %s > %s', $url, $path ) )->run_check(); } private static function run_sql( $sql ) { @@ -122,7 +122,7 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - public function run( $command, $assoc_args = array(), $subdir = '' ) { + public function proc( $command, $assoc_args = array() ) { if ( isset( self::$additional_args[ $command ] ) ) { $assoc_args = array_merge( self::$additional_args[ $command ], $assoc_args ); @@ -131,33 +131,7 @@ public function run( $command, $assoc_args = array(), $subdir = '' ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - $subdir = $this->get_path( $subdir ); - - $cmd = __DIR__ . "/../../bin/wp $command"; - - $descriptors = array( - 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); - - $proc = proc_open( $cmd, $descriptors, $pipes, $subdir ); - - $STDOUT = stream_get_contents( $pipes[1] ); - fclose( $pipes[1] ); - - $STDERR = stream_get_contents( $pipes[2] ); - fclose( $pipes[2] ); - - $r = (object) array( - 'command' => $command, - 'STDOUT' => $STDOUT, - 'STDERR' => $STDERR, - 'return_code' => proc_close( $proc ), - 'cwd' => $this->install_dir - ); - - return $r; + return Process::create( __DIR__ . "/../../bin/wp $command", $this->install_dir ); } public function move_files( $src, $dest ) { @@ -175,25 +149,23 @@ public function download_wordpress_files( $subdir = '' ) { // Ideally, we'd cache at the HTTP layer for more reliable tests $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - $r = $this->run( 'core download', array( + $r = $this->proc( 'core download', array( 'path' => $cache_dir - ) ); + ) )->run(); $dest_dir = $this->get_path( $subdir ); if ( $subdir ) mkdir( $dest_dir ); - $cmd = Utils\esc_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ); - - system( $cmd ); + Process::create( Utils\esc_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ) )->run_check(); } public function wp_install( $subdir = '' ) { $this->create_db(); $this->create_empty_dir(); $this->download_wordpress_files( $subdir ); - $this->run( 'core config', array(), $subdir ); - $this->run( 'core install', array(), $subdir ); + $this->proc( 'core config' )->run_check( $subdir ); + $this->proc( 'core install' )->run_check( $subdir ); } } diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php new file mode 100644 index 000000000..0776a2865 --- /dev/null +++ b/features/bootstrap/Process.php @@ -0,0 +1,58 @@ +<?php + +class Process { + + public static function create( $command, $cwd = null ) { + $proc = new self; + + $proc->command = $command; + $proc->cwd = $cwd; + + return $proc; + } + + private $command, $cwd; + + private function __construct() {} + + public function run( $subdir = '' ) { + $cwd = $this->cwd; + if ( $subdir ) { + $cwd .= '/' . $subdir; + } + + $descriptors = array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd ); + + $STDOUT = stream_get_contents( $pipes[1] ); + fclose( $pipes[1] ); + + $STDERR = stream_get_contents( $pipes[2] ); + fclose( $pipes[2] ); + + return (object) array( + 'STDOUT' => $STDOUT, + 'STDERR' => $STDERR, + 'return_code' => proc_close( $proc ), + 'command' => $this->command, + 'cwd' => $cwd + ); + } + + public function run_check( $subdir = '' ) { + $r = $this->run( $subdir ); + + if ( $r->return_code ) { + throw new \RuntimeException( sprintf( "%s: %s\ncwd: %s", + $r->command, $r->STDERR, $r->cwd ) ); + } + + return $r; + } +} + diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 0002a6c54..3b6905e10 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -25,7 +25,7 @@ function ( $world ) { $steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->run( 'core config' ); + $world->proc( 'core config' )->run_check(); } ); @@ -50,7 +50,7 @@ function ( $world, $subdir ) { $steps->Given( '/^a WP multisite install$/', function ( $world ) { $world->wp_install(); - $world->run( 'core install-network' ); + $world->proc( 'core install-network' )->run_check(); } ); @@ -96,29 +96,29 @@ function ( $world ) { $steps->Given( '/^a large image file$/', function ( $world ) { - $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; + $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; - $world->variables['DOWNLOADED_IMAGE'] = $world->get_cache_path( 'wallpaper.jpg' ); + $world->variables['DOWNLOADED_IMAGE'] = $world->get_cache_path( 'wallpaper.jpg' ); - $world->download_file( $image_file, $world->variables['DOWNLOADED_IMAGE'] ); + $world->download_file( $image_file, $world->variables['DOWNLOADED_IMAGE'] ); } ); $steps->When( '/^I run `wp`$/', function ( $world ) { - $world->result = $world->run( '' ); + $world->result = $world->proc( '' )->run(); } ); $steps->When( '/^I run `wp (.+)`$/', function ( $world, $cmd ) { - $world->result = $world->run( $world->replace_variables( $cmd ) ); + $world->result = $world->proc( $world->replace_variables( $cmd ) )->run(); } ); $steps->When( "/^I run `wp (.+)` from '([^\s]+)'$/", function ( $world, $cmd, $subdir ) { - $world->result = $world->run( $world->replace_variables( $cmd ), array(), $subdir ); + $world->result = $world->proc( $world->replace_variables( $cmd ) )->run( $subdir ); } ); @@ -127,7 +127,7 @@ function ( $world ) { if ( !isset( $world->result ) ) throw new \Exception( 'No previous command.' ); - $world->result = $world->run( $world->result->command ); + $world->result = Process::create( $world->result->command, $world->result->cwd )->run(); } ); @@ -136,7 +136,7 @@ function ( $world ) { if ( !isset( $world->variables['DOWNLOADED_IMAGE'] ) ) throw new \Exception( 'Cached image not available.' ); - $world->result = $world->run( 'media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' ); + $world->result = $world->proc( 'media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' )->run(); } ); @@ -234,7 +234,7 @@ function ( $world, PyStringNode $expected ) { $steps->Then( '/^STDOUT should be CSV containing:$/', function( $world, PyStringNode $expected ) { - + $output = $world->result->STDOUT; $expected = $world->replace_variables( (string) $expected ); From 40deddeba9d8a572b4e51673e605674933860852 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 3 May 2013 23:57:40 +0300 Subject: [PATCH 1589/5359] behat: set different db prefix for subdir install --- features/bootstrap/FeatureContext.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index ab61ffe59..1245620f2 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -164,7 +164,9 @@ public function wp_install( $subdir = '' ) { $this->create_db(); $this->create_empty_dir(); $this->download_wordpress_files( $subdir ); - $this->proc( 'core config' )->run_check( $subdir ); + + $this->proc( 'core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); + $this->proc( 'core install' )->run_check( $subdir ); } } From 4f4ba1a1c6b37622c791be3041f6df0b06f106c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 4 May 2013 01:00:07 +0300 Subject: [PATCH 1590/5359] behat: be more verbose when a command fails --- features/steps/basic_steps.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 3b6905e10..f0591acfe 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -154,8 +154,11 @@ function ( $world, $return_code ) { $steps->Then( '/^it should run without errors$/', function ( $world ) { - if ( !empty( $world->result->STDERR ) ) - throw new \Exception( $world->result->STDERR ); + if ( !empty( $world->result->STDERR ) ) { + $r = $world->result; + throw new \Exception( sprintf( "%s: %s\ncwd: %s", + $r->command, $r->STDERR, $r->cwd ) ); + } if ( 0 != $world->result->return_code ) throw new \Exception( "Return code was $world->result->return_code" ); From e66e78bb8bc486287e8dd8792d37d73ec2c4f285 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 4 May 2013 01:01:32 +0300 Subject: [PATCH 1591/5359] generate test plugin on the fly, instead of downloading one from github --- features/help.feature | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/features/help.feature b/features/help.feature index af077c730..5a410db41 100644 --- a/features/help.feature +++ b/features/help.feature @@ -29,15 +29,23 @@ Feature: Get help about WP-CLI commands Scenario: Getting help for a third-party command Given a WP install - And a google-sitemap-generator-cli plugin zip - And I run `wp plugin install --activate {PLUGIN_ZIP}` - And it should run without errors - And I run `wp plugin install --activate google-sitemap-generator` + And a wp-content/plugins/test-cli-help.php file: + """ + <?php + // Plugin Name: Test CLI Help + + class Test_Help extends WP_CLI_Command { + function __invoke() {} + } + + WP_CLI::add_command( 'test-help', 'Test_Help' ); + """ + And I run `wp plugin activate test-cli-help` And it should run without errors - When I run `wp help google-sitemap` + When I run `wp help test-help` Then it should run without errors And STDOUT should contain: """ - usage: wp google-sitemap + usage: wp test-help """ From f7bc7c39554b195a96ec37c3624a395dfe6756ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 4 May 2013 01:14:50 +0300 Subject: [PATCH 1592/5359] behat: remove unused step definition. see #434 --- features/steps/basic_steps.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index f0591acfe..89368ceb7 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -84,16 +84,6 @@ function ( $world ) { } ); -$steps->Given( '/^a google-sitemap-generator-cli plugin zip$/', - function ( $world ) { - $zip_url = 'https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip'; - - $world->variables['PLUGIN_ZIP'] = $world->get_cache_path( 'google-sitemap-generator-cli.zip' ); - - $world->download_file( $zip_url, $world->variables['PLUGIN_ZIP'] ); - } -); - $steps->Given( '/^a large image file$/', function ( $world ) { $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; From c5126c4f15dc2f8cea49561c9a61d6355328ffca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 4 May 2013 01:30:14 +0300 Subject: [PATCH 1593/5359] outut a single error message, instead of multiple warnings fixes #114 --- php/WP_CLI/SynopsisParser.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index b488c7195..0cc8a49a7 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -60,11 +60,12 @@ private function check_assoc( $assoc_args, $callback ) { } if ( !empty( $errors ) ) { + $out = ''; foreach ( $errors as $error ) { - \WP_CLI::warning( $error ); + $out .= "\n " . $error; } - call_user_func( $callback ); - exit(1); + + \WP_CLI::error( $out, "Parameter errors" ); } } From 2f84fe816ebf1b2d2efda20fb44b79a493e599aa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 May 2013 22:26:17 +0300 Subject: [PATCH 1594/5359] argument validation: separate logic from presentation also, show warning when an optional assoc param doesn't have a value see #436 --- php/WP_CLI/Dispatcher/Subcommand.php | 47 ++++++++++++++----- php/WP_CLI/SynopsisParser.php | 67 +++++++++------------------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 8b3bae245..23afd66ff 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -26,6 +26,14 @@ function get_alias() { return $this->docparser->get_tag( 'alias' ); } + function get_name() { + return $this->name; + } + + function get_parent() { + return $this->parent; + } + function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . $this->get_full_synopsis() ); } @@ -58,25 +66,42 @@ function get_synopsis() { return $this->docparser->get_synopsis(); } - function invoke( $args, $assoc_args ) { + private function validate_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); - if ( $synopsis ) { - \WP_CLI\SynopsisParser::validate_args( $synopsis, $args, $assoc_args, - array( $this, 'show_usage' ) ); + if ( !$synopsis ) + return; + + $parser = new \WP_CLI\SynopsisParser( $synopsis ); + if ( !$parser->enough_positionals( $args ) ) { + $this->show_usage(); + exit(1); } - $instance = new $this->method->class; + $errors = $parser->validate_assoc( $assoc_args ); - call_user_func( array( $instance, $this->method->name ), $args, $assoc_args ); - } + if ( !empty( $errors['fatal'] ) ) { + $out = ''; + foreach ( $errors['fatal'] as $error ) { + $out .= "\n " . $error; + } - function get_name() { - return $this->name; + \WP_CLI::error( $out, "Parameter errors" ); + } + + array_map( '\\WP_CLI::warning', $errors['warnings'] ); + + foreach ( $parser->unknown_assoc( $assoc_args ) as $key ) { + \WP_CLI::warning( "unknown --$key parameter" ); + } } - function get_parent() { - return $this->parent; + function invoke( $args, $assoc_args ) { + $this->validate_args( $args, $assoc_args ); + + $instance = new $this->method->class; + + call_user_func( array( $instance, $this->method->name ), $args, $assoc_args ); } } diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 0cc8a49a7..c0eba6f55 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -8,68 +8,47 @@ class SynopsisParser { private $params = array(); - /** - * @param string Synopsis - * @param array Positional args - * @param array Associative args - * @param callback What to do on a critical failure - */ - static function validate_args( $synopsis, $args, $assoc_args, $callback ) { - $instance = new self( $synopsis ); - - $instance->check_positional( $args, $callback ); - - $instance->check_assoc( $assoc_args, $callback ); - - $instance->check_unknown_assoc( $assoc_args ); - } - - private function __construct( $synopsis ) { + public function __construct( $synopsis ) { $this->params = $this->parse( $synopsis ); } - private function check_positional( $args, $callback ) { + public function enough_positionals( $args ) { $positional = $this->query_params( array( 'type' => 'positional', 'flavour' => 'mandatory' ) ); - if ( count( $args ) < count( $positional ) ) { - call_user_func( $callback ); - exit(1); - } + return count( $args ) >= count( $positional ); } - private function check_assoc( $assoc_args, $callback ) { + public function validate_assoc( $assoc_args ) { $assoc_args += \WP_CLI::get_config(); - $errors = array(); - - $mandatory_assoc = $this->query_params( array( + $assoc = $this->query_params( array( 'type' => 'assoc', - 'flavour' => 'mandatory' ) ); - foreach ( $mandatory_assoc as $param ) { - $key = $param['name']; + $errors = array(); - if ( !isset( $assoc_args[ $key ] ) ) - $errors[] = "missing --$key parameter"; - elseif ( true === $assoc_args[ $key ] ) - $errors[] = "--$key parameter needs a value"; - } + foreach ( $assoc as $param ) { + $key = $param['name']; - if ( !empty( $errors ) ) { - $out = ''; - foreach ( $errors as $error ) { - $out .= "\n " . $error; + if ( !isset( $assoc_args[ $key ] ) ) { + if ( 'mandatory' == $param['flavour'] ) { + $errors['fatal'][] = "missing --$key parameter"; + } + } else { + if ( true === $assoc_args[ $key ] ) { + $error_type = ( 'mandatory' == $param['flavour'] ) ? 'fatal' : 'warning'; + $errors[ $error_type ][] = "--$key parameter needs a value"; + } } - - \WP_CLI::error( $out, "Parameter errors" ); } + + return $errors; } - private function check_unknown_assoc( $assoc_args ) { + public function unknown_assoc( $assoc_args ) { $generic = $this->query_params( array( 'type' => 'generic', ) ); @@ -84,11 +63,7 @@ private function check_unknown_assoc( $assoc_args ) { $known_assoc[] = $param['name']; } - $unknown_assoc = array_diff( array_keys( $assoc_args ), $known_assoc ); - - foreach ( $unknown_assoc as $key ) { - \WP_CLI::warning( "unknown --$key parameter" ); - } + return array_diff( array_keys( $assoc_args ), $known_assoc ); } /** From 2f621fc9ee0dbb9feb0e2b37972dff92bd950738 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 May 2013 22:53:26 +0300 Subject: [PATCH 1595/5359] add empty arrays, to avoid notices --- php/WP_CLI/SynopsisParser.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index c0eba6f55..06b1e4950 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -28,7 +28,10 @@ public function validate_assoc( $assoc_args ) { 'type' => 'assoc', ) ); - $errors = array(); + $errors = array( + 'fatal' => array(), + 'warnings' => array() + ); foreach ( $assoc as $param ) { $key = $param['name']; @@ -54,7 +57,7 @@ public function unknown_assoc( $assoc_args ) { ) ); if ( count( $generic ) ) - return; + return array(); $known_assoc = array(); From 81f0c26472a8f8983c675a8a7772d0567e9bec0b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 May 2013 23:14:04 +0300 Subject: [PATCH 1596/5359] add some unit tests for argument validation methods --- php/WP_CLI/Dispatcher/Subcommand.php | 4 +-- php/WP_CLI/SynopsisParser.php | 4 +-- tests/test-arg-validation.php | 50 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/test-arg-validation.php diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 23afd66ff..8845b2a41 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -78,7 +78,7 @@ private function validate_args( $args, $assoc_args ) { exit(1); } - $errors = $parser->validate_assoc( $assoc_args ); + $errors = $parser->validate_assoc( array_merge( WP_CLI::get_config(), $assoc_args ) ); if ( !empty( $errors['fatal'] ) ) { $out = ''; @@ -89,7 +89,7 @@ private function validate_args( $args, $assoc_args ) { \WP_CLI::error( $out, "Parameter errors" ); } - array_map( '\\WP_CLI::warning', $errors['warnings'] ); + array_map( '\\WP_CLI::warning', $errors['warning'] ); foreach ( $parser->unknown_assoc( $assoc_args ) as $key ) { \WP_CLI::warning( "unknown --$key parameter" ); diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 06b1e4950..e0b316c22 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -22,15 +22,13 @@ public function enough_positionals( $args ) { } public function validate_assoc( $assoc_args ) { - $assoc_args += \WP_CLI::get_config(); - $assoc = $this->query_params( array( 'type' => 'assoc', ) ); $errors = array( 'fatal' => array(), - 'warnings' => array() + 'warning' => array() ); foreach ( $assoc as $param ) { diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php new file mode 100644 index 000000000..887589119 --- /dev/null +++ b/tests/test-arg-validation.php @@ -0,0 +1,50 @@ +<?php + +use WP_CLI\SynopsisParser; + +class ArgValidationTests extends PHPUnit_Framework_TestCase { + + function testMissingPositional() { + $parser = new SynopsisParser( '<foo> <bar> [<baz>]' ); + + $this->assertFalse( $parser->enough_positionals( array() ) ); + $this->assertTrue( $parser->enough_positionals( array( 1, 2 ) ) ); + $this->assertTrue( $parser->enough_positionals( array( 1, 2, 3, 4 ) ) ); + } + + function testRepeatingPositional() { + $parser = new SynopsisParser( '<foo> [<bar>...]' ); + + $this->assertFalse( $parser->enough_positionals( array() ) ); + $this->assertTrue( $parser->enough_positionals( array( 1 ) ) ); + $this->assertTrue( $parser->enough_positionals( array( 1, 2, 3 ) ) ); + } + + function testUnknownAssocEmpty() { + $parser = new SynopsisParser( '' ); + + $assoc_args = array( 'foo' => true, 'bar' => false ); + $this->assertEquals( array_keys( $assoc_args ), $parser->unknown_assoc( $assoc_args ) ); + } + + function testUnknownAssoc() { + $parser = new SynopsisParser( '--type=<type> [--brand=<brand>] [--flag]' ); + + $assoc_args = array( 'type' => 'analog', 'brand' => true, 'flag' => true ); + $this->assertEmpty( $parser->unknown_assoc( $assoc_args ) ); + + $assoc_args['another'] = true; + $this->assertContains( 'another', $parser->unknown_assoc( $assoc_args ) ); + } + + function testMissingAssoc() { + $parser = new SynopsisParser( '--type=<type> [--brand=<brand>] [--flag]' ); + + $assoc_args = array( 'brand' => true, 'flag' => true ); + $errors = $parser->validate_assoc( $assoc_args ); + + $this->assertCount( 1, $errors['fatal'] ); + $this->assertCount( 1, $errors['warning'] ); + } +} + From 33b48341977f7eee71041f0e8e5c382a0f2be0f9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 May 2013 23:28:26 +0300 Subject: [PATCH 1597/5359] fix SynopsisParser::validate_args() not finding the WP_CLI class --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 8845b2a41..4ac02a7df 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -78,7 +78,7 @@ private function validate_args( $args, $assoc_args ) { exit(1); } - $errors = $parser->validate_assoc( array_merge( WP_CLI::get_config(), $assoc_args ) ); + $errors = $parser->validate_assoc( array_merge( \WP_CLI::get_config(), $assoc_args ) ); if ( !empty( $errors['fatal'] ) ) { $out = ''; From 6f0789b4e62c9baee02f7d8c0b80e6d78da9c571 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 May 2013 23:52:38 +0300 Subject: [PATCH 1598/5359] remove invalid assoc args before. fixes #436 --- php/WP_CLI/Dispatcher/Subcommand.php | 4 ++-- php/WP_CLI/SynopsisParser.php | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 4ac02a7df..8c6191419 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -66,7 +66,7 @@ function get_synopsis() { return $this->docparser->get_synopsis(); } - private function validate_args( $args, $assoc_args ) { + private function validate_args( $args, &$assoc_args ) { $synopsis = $this->get_synopsis(); if ( !$synopsis ) @@ -78,7 +78,7 @@ private function validate_args( $args, $assoc_args ) { exit(1); } - $errors = $parser->validate_assoc( array_merge( \WP_CLI::get_config(), $assoc_args ) ); + $errors = $parser->validate_assoc( $assoc_args, array_keys( \WP_CLI::get_config() ) ); if ( !empty( $errors['fatal'] ) ) { $out = ''; diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index e0b316c22..2021c486c 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -21,7 +21,7 @@ public function enough_positionals( $args ) { return count( $args ) >= count( $positional ); } - public function validate_assoc( $assoc_args ) { + public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { $assoc = $this->query_params( array( 'type' => 'assoc', ) ); @@ -34,6 +34,9 @@ public function validate_assoc( $assoc_args ) { foreach ( $assoc as $param ) { $key = $param['name']; + if ( in_array( $key, $ignored_keys ) ) + continue; + if ( !isset( $assoc_args[ $key ] ) ) { if ( 'mandatory' == $param['flavour'] ) { $errors['fatal'][] = "missing --$key parameter"; @@ -42,6 +45,8 @@ public function validate_assoc( $assoc_args ) { if ( true === $assoc_args[ $key ] ) { $error_type = ( 'mandatory' == $param['flavour'] ) ? 'fatal' : 'warning'; $errors[ $error_type ][] = "--$key parameter needs a value"; + + unset( $assoc_args[ $key ] ); } } } From 3500a184e5ca652370fdaa7e2c2217290fadf69c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 7 May 2013 00:27:29 +0300 Subject: [PATCH 1599/5359] make $items the first parameter in format_items() The idea is that $items is in fact the most important value, guaranteed to be mandatory, whereas $format and $fields could be optional. --- php/commands/post.php | 6 ++---- php/commands/role.php | 2 +- php/commands/term.php | 2 +- php/commands/user.php | 2 +- php/utils.php | 11 +++++------ 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 7d966c3bb..7228e4a1a 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -123,7 +123,7 @@ public function get( $args, $assoc_args ) { $items[] = $item; } - \WP_CLI\Utils\format_items( $format, array( 'Field', 'Value' ), $items ); + \WP_CLI\Utils\format_items( $items, $format, array( 'Field', 'Value' ) ); break; case 'json': @@ -200,9 +200,7 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); - $output_posts = $query->posts; - - WP_CLI\Utils\format_items( $format, $fields, $output_posts ); + WP_CLI\Utils\format_items( $query->posts, $format, $fields ); } /** diff --git a/php/commands/role.php b/php/commands/role.php index a397dc6ad..cadfb9658 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -40,7 +40,7 @@ public function _list( $args, $assoc_args ) { $output_roles[] = $output_role; } - WP_CLI\Utils\format_items( $params['format'], $fields, $output_roles ); + WP_CLI\Utils\format_items( $output_roles, $params['format'], $fields ); } /** diff --git a/php/commands/term.php b/php/commands/term.php index 2a64f1b44..e72b209e4 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -41,7 +41,7 @@ public function _list( $args, $assoc_args ) { if ( 'ids' == $assoc_args['format'] ) $terms = wp_list_pluck( $terms, 'term_id' ); - WP_CLI\Utils\format_items( $assoc_args['format'], $fields, $terms ); + WP_CLI\Utils\format_items( $terms, $assoc_args['format'], $fields, $terms ); } /** diff --git a/php/commands/user.php b/php/commands/user.php index de3245f99..09de1e64c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -53,7 +53,7 @@ public function _list( $args, $assoc_args ) { } } - WP_CLI\Utils\format_items( $params['format'], $fields, $users ); + WP_CLI\Utils\format_items( $users, $params['format'], $fields ); } /** diff --git a/php/utils.php b/php/utils.php index d6a0ff5ba..99272dc7f 100644 --- a/php/utils.php +++ b/php/utils.php @@ -252,11 +252,13 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria /** * Output items in a table, JSON, or CSV * - * @param string $format Format to use: 'table', 'json', 'csv' - * @param array|string $fields Named fields for each item of data. Can be array or CSV * @param array $items Data to output + * @param string $format Format to use: 'table', 'json', 'csv' + * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ -function format_items( $format, $fields, $items ) { +function format_items( $items, $format, $fields ) { + if ( 'ids' == $format ) + \WP_CLI::out( implode( ' ', $items ) ); if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); @@ -298,9 +300,6 @@ function format_items( $format, $fields, $items ) { else write_csv( STDOUT, $output_items, $fields ); break; - case 'ids': - \WP_CLI::out( implode( ' ', $items ) ); - break; } } From e94b5c2057ddeaade5fa33451188c1eb6b3bbfdd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 7 May 2013 00:38:07 +0300 Subject: [PATCH 1600/5359] refactor Post_Command::_list() --- php/commands/post.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 7228e4a1a..47ed019bc 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -174,19 +174,18 @@ public function _list( $_, $assoc_args ) { 'posts_per_page' => -1 ); - if ( ! empty( $assoc_args['format'] ) ) { - $format = $assoc_args['format']; - unset( $assoc_args['format'] ); - } else { - $format = 'table'; - } + $values = array( + 'format' => 'table', + 'fields' => $this->fields + ); - if ( isset( $assoc_args['fields'] ) ) { - $fields = $assoc_args['fields']; - unset( $assoc_args['fields'] ); - } else { - $fields = $this->fields; + foreach ( $values as $key => &$value ) { + if ( isset( $assoc_args[ $key ] ) ) { + $value = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } } + unset( $value ); foreach ( $assoc_args as $key => $value ) { if ( true === $value ) @@ -195,12 +194,12 @@ public function _list( $_, $assoc_args ) { $query_args[ $key ] = $value; } - if ( 'ids' == $format ) + if ( 'ids' == $values['format'] ) $query_args['fields'] = 'ids'; $query = new WP_Query( $query_args ); - WP_CLI\Utils\format_items( $query->posts, $format, $fields ); + WP_CLI\Utils\format_items( $query->posts, $values['format'], $values['fields'] ); } /** From f6e50633c89afd534691bd79694ca7c2723c07a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 7 May 2013 00:41:33 +0300 Subject: [PATCH 1601/5359] make the $fields property private there really isn't any use for it outside of its own class --- php/commands/post.php | 2 +- php/commands/role.php | 8 ++++---- php/commands/term.php | 18 +++++++++--------- php/commands/user.php | 16 ++++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 47ed019bc..e9a7aa7bb 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -9,7 +9,7 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'post'; - public $fields = array( + private $fields = array( 'ID', 'post_title', 'post_name', diff --git a/php/commands/role.php b/php/commands/role.php index cadfb9658..2f88e4d02 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -7,10 +7,10 @@ */ class Role_Command extends WP_CLI_Command { - public $fields = array( - 'name', - 'role' - ); + private $fields = array( + 'name', + 'role' + ); /** * List all roles. diff --git a/php/commands/term.php b/php/commands/term.php index e72b209e4..c891e9e4c 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -6,15 +6,15 @@ */ class Term_Command extends WP_CLI_Command { - public $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', - ); + private $fields = array( + 'term_id', + 'term_taxonomy_id', + 'name', + 'slug', + 'description', + 'parent', + 'count', + ); /** * List terms in a taxonomy. diff --git a/php/commands/user.php b/php/commands/user.php index 09de1e64c..1880a2960 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -9,14 +9,14 @@ class User_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'user'; - public $fields = array( - 'ID', - 'user_login', - 'display_name', - 'user_email', - 'user_registered', - 'roles' - ); + private $fields = array( + 'ID', + 'user_login', + 'display_name', + 'user_email', + 'user_registered', + 'roles' + ); /** * List users. From 7580187615790e68ea443e41f0ec7f86c8e1abbd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 14:09:55 +0300 Subject: [PATCH 1602/5359] move REPL implementation to separate class --- php/WP_CLI/REPL.php | 135 +++++++++++++++++++++++++++++++++++++++++ php/commands/shell.php | 121 +----------------------------------- 2 files changed, 137 insertions(+), 119 deletions(-) create mode 100644 php/WP_CLI/REPL.php diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php new file mode 100644 index 000000000..93e43774b --- /dev/null +++ b/php/WP_CLI/REPL.php @@ -0,0 +1,135 @@ +<?php + +namespace WP_CLI; + +class REPL { + + private $promt; + + public function __construct( $prompt ) { + $this->prompt = $prompt; + + $this->set_history_file(); + } + + public function start() { + while ( true ) { + $line = $this->prompt(); + + switch ( $line ) { + case '': { + continue 2; + } + + case 'history': { + self::print_history(); + continue 2; + } + } + + $line = rtrim( $line, ';' ) . ';'; + + if ( self::starts_with( self::non_expressions(), $line ) ) { + eval( $line ); + } else { + if ( self::starts_with( 'return', $line ) ) + $line = substr( $line, strlen( 'return' ) ); + + $line = '$_ = ' . $line; + + eval( $line ); + + \WP_CLI::print_value( var_export( $_, false ) ); + } + } + } + + private static function non_expressions() { + return implode( '|', array( + 'echo', 'global', 'unset', 'function', + 'while', 'for', 'foreach', 'if', 'switch', + 'include', 'include\_once', 'require', 'require\_once' + ) ); + } + + private function prompt() { + $full_line = false; + + $done = false; + do { + $prompt = ( !$done && $full_line !== false ) ? '--> ' : $this->prompt; + + $fp = popen( self::create_prompt_cmd( $prompt, $this->history_file ), 'r' ); + + $line = fgets( $fp ); + + if ( !$line ) { + break; + } + + $line = rtrim( $line, "\n" ); + + if ( $line && '\\' == $line[ strlen( $line ) - 1 ] ) { + $line = substr( $line, 0, -1 ); + } else { + $done = true; + } + + $full_line .= $line; + + } while ( !$done ); + + if ( $full_line === false ) { + return 'exit'; + } + + return $full_line; + } + + private static function create_prompt_cmd( $prompt, $history_path ) { + $prompt = escapeshellarg( $prompt ); + $history_path = escapeshellarg( $history_path ); + + $cmd = <<<BASH +set -f +history -r $history_path +LINE="" +read -re -p $prompt LINE +[ $? -eq 0 ] || exit +history -s "\$LINE" +history -w $history_path +echo \$LINE +BASH; + + $cmd = str_replace( "\n", '; ', $cmd ); + + return '/bin/bash -c ' . escapeshellarg( $cmd ); + } + + private function print_history() { + if ( !is_readable( $this->history_file ) ) + return; + + $lines = array_filter( explode( "\n", file_get_contents( $this->history_file ) ) ); + + foreach ( $lines as $line ) { + if ( 'history' == $line ) + continue; + + $line = rtrim( $line, ';' ) . ';'; + + echo "$line\n"; + } + } + + private function set_history_file() { + $data = getcwd() . get_current_user(); + + $this->history_file = sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); + } + + private static function starts_with( $tokens, $line ) { + return preg_match( "/^($tokens)[\(\s]+/", $line ); + } +} + diff --git a/php/commands/shell.php b/php/commands/shell.php index 0c586ccc4..2bc41fd21 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -8,125 +8,8 @@ class Shell_Command extends \WP_CLI_Command { public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); - $this->set_history_file(); - - while ( true ) { - $line = $this->prompt(); - - switch ( $line ) { - case '': { - continue 2; - } - - case 'history': { - self::print_history(); - continue 2; - } - } - - $line = rtrim( $line, ';' ) . ';'; - - if ( self::starts_with( self::non_expressions(), $line ) ) { - eval( $line ); - } else { - if ( self::starts_with( 'return', $line ) ) - $line = substr( $line, strlen( 'return' ) ); - - $line = '$_ = ' . $line; - - eval( $line ); - - \WP_CLI::print_value( var_export( $_, false ) ); - } - } - } - - private static function non_expressions() { - return implode( '|', array( - 'echo', 'global', 'unset', 'function', - 'while', 'for', 'foreach', 'if', 'switch', - 'include', 'include\_once', 'require', 'require\_once' - ) ); - } - - private function prompt() { - $full_line = false; - - $done = false; - do { - $prompt = ( !$done && $full_line !== false ) ? '--> ' : 'wp> '; - - $fp = popen( self::create_prompt_cmd( $prompt, $this->history_file ), 'r' ); - - $line = fgets( $fp ); - - if ( !$line ) { - break; - } - - $line = rtrim( $line, "\n" ); - - if ( $line && '\\' == $line[ strlen( $line ) - 1 ] ) { - $line = substr( $line, 0, -1 ); - } else { - $done = true; - } - - $full_line .= $line; - - } while ( !$done ); - - if ( $full_line === false ) { - return 'exit'; - } - - return $full_line; - } - - private static function create_prompt_cmd( $prompt, $history_path ) { - $prompt = escapeshellarg( $prompt ); - $history_path = escapeshellarg( $history_path ); - - $cmd = <<<BASH -set -f -history -r $history_path -LINE="" -read -re -p $prompt LINE -[ $? -eq 0 ] || exit -history -s "\$LINE" -history -w $history_path -echo \$LINE -BASH; - - $cmd = str_replace( "\n", '; ', $cmd ); - - return '/bin/bash -c ' . escapeshellarg( $cmd ); - } - - private function print_history() { - if ( !is_readable( $this->history_file ) ) - return; - - $lines = array_filter( explode( "\n", file_get_contents( $this->history_file ) ) ); - - foreach ( $lines as $line ) { - if ( 'history' == $line ) - continue; - - $line = rtrim( $line, ';' ) . ';'; - - echo "$line\n"; - } - } - - private function set_history_file() { - $data = getcwd() . get_current_user(); - - $this->history_file = sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); - } - - private static function starts_with( $tokens, $line ) { - return preg_match( "/^($tokens)[\(\s]+/", $line ); + $repl = new \WP_CLI\REPL( 'wp> ' ); + $repl->start(); } } From 61939d5677dc02556daf45de7982fc3b22fde1f1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 14:17:39 +0300 Subject: [PATCH 1603/5359] add Boris as a dependency and use it instead of homegrown REPL --- composer.json | 3 ++- composer.lock | 35 ++++++++++++++++++++++++++++++++++- php/commands/shell.php | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 46ed15725..5817208cb 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "require": { "php": ">=5.3", "wp-cli/php-cli-tools": "dev-master", - "mustache/mustache": "2.0.x" + "mustache/mustache": "2.0.x", + "d11wtq/boris": "dev-master" }, "require-dev": { "phpunit/phpunit": "3.7.x", diff --git a/composer.lock b/composer.lock index 9bd1adfaa..e804126ba 100644 --- a/composer.lock +++ b/composer.lock @@ -3,8 +3,40 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "f2b06fd19e26795775358b054c6fb09d", + "hash": "1d1cf2cc2d559d96f2e3397353a4be3e", "packages": [ + { + "name": "d11wtq/boris", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/d11wtq/boris.git", + "reference": "09c211ab3a79154f39efce542f737ad08596e63f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/d11wtq/boris/zipball/09c211ab3a79154f39efce542f737ad08596e63f", + "reference": "09c211ab3a79154f39efce542f737ad08596e63f", + "shasum": "" + }, + "require": { + "ext-pcntl": "*", + "ext-posix": "*", + "ext-readline": "*", + "php": ">=5.3.0" + }, + "bin": [ + "bin/boris" + ], + "type": "library", + "autoload": { + "psr-0": { + "Boris": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "time": "2013-04-23 13:31:51" + }, { "name": "mustache/mustache", "version": "v2.0.2", @@ -929,6 +961,7 @@ "minimum-stability": "stable", "stability-flags": { "wp-cli/php-cli-tools": 20, + "d11wtq/boris": 20, "behat/behat": 0 }, "platform": { diff --git a/php/commands/shell.php b/php/commands/shell.php index 2bc41fd21..077e22ef3 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -8,7 +8,7 @@ class Shell_Command extends \WP_CLI_Command { public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); - $repl = new \WP_CLI\REPL( 'wp> ' ); + $repl = new \Boris\Boris( 'wp> ' ); $repl->start(); } } From cf2753e12fffe89fd762147bdc580a69125a71de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 14:48:02 +0300 Subject: [PATCH 1604/5359] fall back to old REPL implementation if Boris is not available --- php/commands/shell.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 077e22ef3..8ab60c013 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -8,8 +8,18 @@ class Shell_Command extends \WP_CLI_Command { public function __invoke() { \WP_CLI::line( 'Type "exit" to close session.' ); - $repl = new \Boris\Boris( 'wp> ' ); - $repl->start(); + $implementations = array( + '\\Boris\\Boris', + '\\WP_CLI\\REPL', + ); + + foreach ( $implementations as $class ) { + if ( class_exists( $class ) ) { + $repl = new $class( 'wp> ' ); + $repl->start(); + break; + } + } } } From 883411c7d1d84ec8392aded2ae345ab080aa7d0f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 15:06:46 +0300 Subject: [PATCH 1605/5359] add --basic flag to `wp shell` command --- man-src/shell.txt | 6 ++++++ php/commands/shell.php | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/man-src/shell.txt b/man-src/shell.txt index 1759cffb5..da5393cf2 100644 --- a/man-src/shell.txt +++ b/man-src/shell.txt @@ -7,3 +7,9 @@ You can split a statement over multiple lines by adding a `\` (backslash) before hitting Return. If you type `history` and hit Return, WP-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file. + +## OPTIONS + +* `--basic`: + + Start in fail-safe mode, even if Boris is available. diff --git a/php/commands/shell.php b/php/commands/shell.php index 8ab60c013..4ff4215ab 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -4,8 +4,10 @@ class Shell_Command extends \WP_CLI_Command { /** * Interactive PHP console. + * + * @synopsis [--basic] */ - public function __invoke() { + public function __invoke( $_, $assoc_args ) { \WP_CLI::line( 'Type "exit" to close session.' ); $implementations = array( @@ -13,6 +15,10 @@ public function __invoke() { '\\WP_CLI\\REPL', ); + if ( isset( $assoc_args['basic'] ) ) { + unset( $implementations[0] ); + } + foreach ( $implementations as $class ) { if ( class_exists( $class ) ) { $repl = new $class( 'wp> ' ); From 1ead253ab0731414ac14dead11ee58d84eb33da3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 15:10:12 +0300 Subject: [PATCH 1606/5359] remove support for $_ special variable, since Boris doesn't support it. --- features/shell.feature | 20 -------------------- man-src/shell.txt | 2 -- php/WP_CLI/REPL.php | 10 +++------- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index 2cc9c47f8..a880b91a6 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -10,26 +10,6 @@ Feature: WordPress REPL Type "exit" to close session. """ - Scenario: $_ special variable - Given a WP install - And a session file: - """ - WP_ADMIN - $_ - get_current_user_id() - $_ - """ - - When I run `wp shell --quiet < session` - Then it should run without errors - And STDOUT should be: - """ - true - true - 0 - 0 - """ - Scenario: Persistent environment Given a WP install And a session file: diff --git a/man-src/shell.txt b/man-src/shell.txt index da5393cf2..02f84c977 100644 --- a/man-src/shell.txt +++ b/man-src/shell.txt @@ -2,8 +2,6 @@ `wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. -`$_` is a special variable that contains the result from the last evaluated statement. - You can split a statement over multiple lines by adding a `\` (backslash) before hitting Return. If you type `history` and hit Return, WP-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file. diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 93e43774b..830404d0a 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -32,14 +32,10 @@ public function start() { if ( self::starts_with( self::non_expressions(), $line ) ) { eval( $line ); } else { - if ( self::starts_with( 'return', $line ) ) - $line = substr( $line, strlen( 'return' ) ); + if ( !self::starts_with( 'return', $line ) ) + $line = 'return ' . $line; - $line = '$_ = ' . $line; - - eval( $line ); - - \WP_CLI::print_value( var_export( $_, false ) ); + \WP_CLI::print_value( var_export( eval( $line ), false ) ); } } } From d7e43e5cf2af2413c9b3831911ff708901d79bea Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 15:49:33 +0300 Subject: [PATCH 1607/5359] fix shell tests --- features/shell.feature | 43 ++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index a880b91a6..8cb9f59e7 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -5,25 +5,25 @@ Feature: WordPress REPL When I run `wp shell < /dev/null` Then it should run without errors - And STDOUT should be: - """ - Type "exit" to close session. - """ + And STDOUT should not be empty + + When I run `wp shell --basic < /dev/null` + Then it should run without errors + And STDOUT should not be empty Scenario: Persistent environment Given a WP install And a session file: """ function is_empty_string( $str ) { return strlen( $str ) == 0; } - 1; $a = get_option('home') - is_empty_string( $a ) + $a = get_option('home'); + is_empty_string( $a ); """ - When I run `wp shell --quiet < session` + When I run `wp shell --basic --quiet < session` Then it should run without errors - And STDOUT should be: + And STDOUT should contain: """ - 1 false """ @@ -36,7 +36,7 @@ Feature: WordPress REPL history """ - When I run `wp shell --quiet < session` + When I run `wp shell --basic --quiet < session` Then it should run without errors And STDOUT should be: """ @@ -46,6 +46,25 @@ Feature: WordPress REPL """ Scenario: Multiline support + Given a WP install + And a session file: + """ + function is_empty_string( $str ) { + return strlen( $str ) == 0; + } + + function_exists( 'is_empty_string' ); + """ + + When I run `wp shell --quiet < session` + Then it should run without errors + And STDOUT should be: + """ + → NULL + → bool(true) + """ + + Scenario: Multiline support (basic) Given a WP install And a session file: """ @@ -53,10 +72,10 @@ Feature: WordPress REPL return strlen( $str ) == 0; \ } - function_exists( 'is_empty_string' ) + function_exists( 'is_empty_string' ); """ - When I run `wp shell --quiet < session` + When I run `wp shell --basic --quiet < session` Then it should run without errors And STDOUT should be: """ From 4a7f30a36482d4ef2b034ab14bc4eda61b905974 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 15:57:13 +0300 Subject: [PATCH 1608/5359] shell: use var_dump(), to better match Boris output --- features/shell.feature | 6 +++--- php/WP_CLI/REPL.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index 8cb9f59e7..fd774963b 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -24,7 +24,7 @@ Feature: WordPress REPL Then it should run without errors And STDOUT should contain: """ - false + bool(false) """ Scenario: History builtin @@ -40,7 +40,7 @@ Feature: WordPress REPL Then it should run without errors And STDOUT should be: """ - true + bool(true) defined('WP_CLI'); function foo() {}; """ @@ -79,6 +79,6 @@ Feature: WordPress REPL Then it should run without errors And STDOUT should be: """ - true + bool(true) """ diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 830404d0a..73232b747 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -35,7 +35,7 @@ public function start() { if ( !self::starts_with( 'return', $line ) ) $line = 'return ' . $line; - \WP_CLI::print_value( var_export( eval( $line ), false ) ); + var_dump( eval( $line ) ); } } } From a9dd5dcc36a744b163a7f94bde5ab93bde7977f9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 16:03:04 +0300 Subject: [PATCH 1609/5359] shell: remove support for 'history' builtin 1. The syntax felt kind of inconsistent. 2. Boris doesn't support it. 3. It didn't ship with a stable release, so not many people know about it. see #373 --- features/shell.feature | 18 ------------------ man-src/shell.txt | 2 -- php/WP_CLI/REPL.php | 27 +-------------------------- 3 files changed, 1 insertion(+), 46 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index fd774963b..ed1bd3503 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -27,24 +27,6 @@ Feature: WordPress REPL bool(false) """ - Scenario: History builtin - Given a WP install - And a session file: - """ - defined('WP_CLI') - function foo() {} - history - """ - - When I run `wp shell --basic --quiet < session` - Then it should run without errors - And STDOUT should be: - """ - bool(true) - defined('WP_CLI'); - function foo() {}; - """ - Scenario: Multiline support Given a WP install And a session file: diff --git a/man-src/shell.txt b/man-src/shell.txt index 02f84c977..a895f32c4 100644 --- a/man-src/shell.txt +++ b/man-src/shell.txt @@ -4,8 +4,6 @@ You can split a statement over multiple lines by adding a `\` (backslash) before hitting Return. -If you type `history` and hit Return, WP-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file. - ## OPTIONS * `--basic`: diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 73232b747..c065091a2 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -16,16 +16,7 @@ public function start() { while ( true ) { $line = $this->prompt(); - switch ( $line ) { - case '': { - continue 2; - } - - case 'history': { - self::print_history(); - continue 2; - } - } + if ( '' === $line ) continue; $line = rtrim( $line, ';' ) . ';'; @@ -102,22 +93,6 @@ private static function create_prompt_cmd( $prompt, $history_path ) { return '/bin/bash -c ' . escapeshellarg( $cmd ); } - private function print_history() { - if ( !is_readable( $this->history_file ) ) - return; - - $lines = array_filter( explode( "\n", file_get_contents( $this->history_file ) ) ); - - foreach ( $lines as $line ) { - if ( 'history' == $line ) - continue; - - $line = rtrim( $line, ';' ) . ';'; - - echo "$line\n"; - } - } - private function set_history_file() { $data = getcwd() . get_current_user(); From abf1240e2cb11ea56ff29c16cf3fcbf958c6037f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 16:06:39 +0300 Subject: [PATCH 1610/5359] shell man: remove note about backslashes Backslashes are needed only in basic mode. --- man-src/shell.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/man-src/shell.txt b/man-src/shell.txt index a895f32c4..7dd583a28 100644 --- a/man-src/shell.txt +++ b/man-src/shell.txt @@ -2,8 +2,6 @@ `wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. -You can split a statement over multiple lines by adding a `\` (backslash) before hitting Return. - ## OPTIONS * `--basic`: From 86493d25e89562a78c9e8caf2d6f1b38951331b3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 16:17:42 +0300 Subject: [PATCH 1611/5359] shell: remove Boris tests they belong in the Boris repo --- features/shell.feature | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index ed1bd3503..e328ac171 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -27,25 +27,6 @@ Feature: WordPress REPL bool(false) """ - Scenario: Multiline support - Given a WP install - And a session file: - """ - function is_empty_string( $str ) { - return strlen( $str ) == 0; - } - - function_exists( 'is_empty_string' ); - """ - - When I run `wp shell --quiet < session` - Then it should run without errors - And STDOUT should be: - """ - → NULL - → bool(true) - """ - Scenario: Multiline support (basic) Given a WP install And a session file: From 29e1b0547f1bbb22249b3e0cdd2a4d9fd96c9b4c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 16:45:12 +0300 Subject: [PATCH 1612/5359] make Boris a suggested package --- composer.json | 6 ++++-- composer.lock | 35 +---------------------------------- utils/dev-build | 3 +++ 3 files changed, 8 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index 5817208cb..64773ce14 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,10 @@ "require": { "php": ">=5.3", "wp-cli/php-cli-tools": "dev-master", - "mustache/mustache": "2.0.x", - "d11wtq/boris": "dev-master" + "mustache/mustache": "2.0.x" + }, + "suggest": { + "d11wtq/boris": "Enhanced `wp shell` functionality" }, "require-dev": { "phpunit/phpunit": "3.7.x", diff --git a/composer.lock b/composer.lock index e804126ba..26c0f6bdf 100644 --- a/composer.lock +++ b/composer.lock @@ -3,40 +3,8 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "1d1cf2cc2d559d96f2e3397353a4be3e", + "hash": "b0b7111ec0133fedf911454fef153d87", "packages": [ - { - "name": "d11wtq/boris", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/d11wtq/boris.git", - "reference": "09c211ab3a79154f39efce542f737ad08596e63f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/d11wtq/boris/zipball/09c211ab3a79154f39efce542f737ad08596e63f", - "reference": "09c211ab3a79154f39efce542f737ad08596e63f", - "shasum": "" - }, - "require": { - "ext-pcntl": "*", - "ext-posix": "*", - "ext-readline": "*", - "php": ">=5.3.0" - }, - "bin": [ - "bin/boris" - ], - "type": "library", - "autoload": { - "psr-0": { - "Boris": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "time": "2013-04-23 13:31:51" - }, { "name": "mustache/mustache", "version": "v2.0.2", @@ -961,7 +929,6 @@ "minimum-stability": "stable", "stability-flags": { "wp-cli/php-cli-tools": 20, - "d11wtq/boris": 20, "behat/behat": 0 }, "platform": { diff --git a/utils/dev-build b/utils/dev-build index 299460360..c97b95fa8 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -15,6 +15,9 @@ command -v composer > /dev/null || { # install dependencies composer install --dev +# try installing Boris +composer require d11wtq/boris=dev-master + # add symlink to wp binary for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then From e9ef2cb186147ff953b42e040b3acb8dcf0a9868 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 21:08:36 +0300 Subject: [PATCH 1613/5359] shell: remove superfluous exit instructions --- features/shell.feature | 6 ++---- php/commands/shell.php | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index e328ac171..0ca5aa9a9 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -5,11 +5,9 @@ Feature: WordPress REPL When I run `wp shell < /dev/null` Then it should run without errors - And STDOUT should not be empty When I run `wp shell --basic < /dev/null` Then it should run without errors - And STDOUT should not be empty Scenario: Persistent environment Given a WP install @@ -20,7 +18,7 @@ Feature: WordPress REPL is_empty_string( $a ); """ - When I run `wp shell --basic --quiet < session` + When I run `wp shell --basic < session` Then it should run without errors And STDOUT should contain: """ @@ -38,7 +36,7 @@ Feature: WordPress REPL function_exists( 'is_empty_string' ); """ - When I run `wp shell --basic --quiet < session` + When I run `wp shell --basic < session` Then it should run without errors And STDOUT should be: """ diff --git a/php/commands/shell.php b/php/commands/shell.php index 4ff4215ab..4fbf4bbcc 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -8,8 +8,6 @@ class Shell_Command extends \WP_CLI_Command { * @synopsis [--basic] */ public function __invoke( $_, $assoc_args ) { - \WP_CLI::line( 'Type "exit" to close session.' ); - $implementations = array( '\\Boris\\Boris', '\\WP_CLI\\REPL', From 4190db66edb86dc6a498aa49b3ea4770b3a24e2c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 21:12:56 +0300 Subject: [PATCH 1614/5359] travis: force-install Boris, for smoke testing --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f6bfe635b..7225c6eaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ matrix: before_script: # install dependencies - composer install --dev --no-interaction --prefer-source + - composer require d11wtq/boris=dev-master --no-interaction --prefer-source # set up WP install - bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ # set up database From 3c2fd0be6ece9976073066ea3d90c97263083c67 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 23:03:18 +0300 Subject: [PATCH 1615/5359] shell: re-generate man page [ci skip] --- man/shell.1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/man/shell.1 b/man/shell.1 index d145d4a61..6aa5f9e1f 100644 --- a/man/shell.1 +++ b/man/shell.1 @@ -7,16 +7,16 @@ \fBwp\-shell\fR \- Interactive PHP console\. . .SH "SYNOPSIS" -wp shell +wp shell [\-\-basic] . .SH "DESCRIPTION" \fBwp shell\fR allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment\. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example\. . -.P -\fB$_\fR is a special variable that contains the result from the last evaluated statement\. +.SH "OPTIONS" . -.P -You can split a statement over multiple lines by adding a \fB\e\fR (backslash) before hitting Return\. +.TP +\fB\-\-basic\fR: . -.P -If you type \fBhistory\fR and hit Return, WP\-CLI will print the list of previously evaluated statements, which you can copy+paste into a PHP file\. +.IP +Start in fail\-safe mode, even if Boris is available\. + From 096a4944004c533435ce0ef498e840bb6b6e4c68 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 23:05:26 +0300 Subject: [PATCH 1616/5359] don't install Boris in dev-build, since it alters the git repo --- utils/dev-build | 3 --- 1 file changed, 3 deletions(-) diff --git a/utils/dev-build b/utils/dev-build index c97b95fa8..299460360 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -15,9 +15,6 @@ command -v composer > /dev/null || { # install dependencies composer install --dev -# try installing Boris -composer require d11wtq/boris=dev-master - # add symlink to wp binary for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then From 4c73c449255fb209d612510810948ffd85badb84 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 23:43:09 +0300 Subject: [PATCH 1617/5359] Bump required PHP version to 5.3.2 We depend on Composer and Composer doesn't work wit anything below that. This also allows us to move back to the upstream php-cli-tools package. --- composer.json | 4 +-- composer.lock | 69 +++++++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/composer.json b/composer.json index 64773ce14..dc3cc5aaa 100644 --- a/composer.json +++ b/composer.json @@ -8,8 +8,8 @@ "bin/wp" ], "require": { - "php": ">=5.3", - "wp-cli/php-cli-tools": "dev-master", + "php": ">=5.3.2", + "jlogsdon/cli": "~0.9.1", "mustache/mustache": "2.0.x" }, "suggest": { diff --git a/composer.lock b/composer.lock index 26c0f6bdf..726e2b26b 100644 --- a/composer.lock +++ b/composer.lock @@ -3,29 +3,29 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "b0b7111ec0133fedf911454fef153d87", + "hash": "2f907ef4729a8057cba8d5310e72ed9f", "packages": [ { - "name": "mustache/mustache", - "version": "v2.0.2", + "name": "jlogsdon/cli", + "version": "v0.9.1", "source": { "type": "git", - "url": "https://github.com/bobthecow/mustache.php", - "reference": "v2.0.2" + "url": "git://github.com/jlogsdon/php-cli-tools.git", + "reference": "v0.9.1" }, "dist": { "type": "zip", - "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", - "reference": "v2.0.2", + "url": "https://github.com/jlogsdon/php-cli-tools/zipball/v0.9.1", + "reference": "v0.9.1", "shasum": "" }, "require": { - "php": ">=5.2.4" + "php": ">= 5.3.0" }, "type": "library", "autoload": { "psr-0": { - "Mustache": "src/" + "cli": "lib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -34,40 +34,40 @@ ], "authors": [ { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "name": "James Logsdon", + "email": "jlogsdon@php.net", + "role": "Developer" } ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", + "description": "Console utilities for PHP", + "homepage": "http://github.com/jlogsdon/php-cli-tools", "keywords": [ - "mustache", - "templating" + "cli", + "console" ], - "time": "2012-09-12 09:13:06" + "time": "2012-09-15 14:09:00" }, { - "name": "wp-cli/php-cli-tools", - "version": "dev-master", + "name": "mustache/mustache", + "version": "v2.0.2", "source": { "type": "git", - "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217" + "url": "https://github.com/bobthecow/mustache.php", + "reference": "v2.0.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/f3def25b862bb0c5330a6347c6c04d62a99eb217", - "reference": "f3def25b862bb0c5330a6347c6c04d62a99eb217", + "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", + "reference": "v2.0.2", "shasum": "" }, "require": { - "php": ">= 5.3.0" + "php": ">=5.2.4" }, "type": "library", "autoload": { "psr-0": { - "cli": "lib/" + "Mustache": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -76,18 +76,18 @@ ], "authors": [ { - "name": "James Logsdon", - "email": "jlogsdon@php.net", - "role": "Developer" + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" } ], - "description": "Console utilities for PHP", - "homepage": "http://github.com/jlogsdon/php-cli-tools", + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", "keywords": [ - "cli", - "console" + "mustache", + "templating" ], - "time": "2012-12-13 22:18:34" + "time": "2012-09-12 09:13:06" } ], "packages-dev": [ @@ -928,11 +928,10 @@ ], "minimum-stability": "stable", "stability-flags": { - "wp-cli/php-cli-tools": 20, "behat/behat": 0 }, "platform": { - "php": ">=5.3" + "php": ">=5.3.2" }, "platform-dev": [ From a524e2ff71b06d76c2f2ceda9e2af055b12d959d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 23:52:02 +0300 Subject: [PATCH 1618/5359] fix path to cli-tools package --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 3521a2a62..a0a6fb188 100644 --- a/php/utils.php +++ b/php/utils.php @@ -17,7 +17,7 @@ function load_dependencies() { foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; - include $vendor_path . '/wp-cli/php-cli-tools/lib/cli/cli.php'; + include $vendor_path . '/jlogsdon/cli/lib/cli/cli.php'; $has_autoload = true; break; } From bae50f56e0da11b228edca69772475bc6dcaa307 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 8 May 2013 23:55:34 +0300 Subject: [PATCH 1619/5359] change exit code when Composer packages aren't installed 2 is a reserved exit code: http://tldp.org/LDP/abs/html/exitcodes.html --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index a0a6fb188..12e8595ca 100644 --- a/php/utils.php +++ b/php/utils.php @@ -25,7 +25,7 @@ function load_dependencies() { if ( !$has_autoload ) { fputs( STDERR, "Internal error: Can't find Composer autoloader.\n" ); - exit(2); + exit(3); } include WP_CLI_ROOT . 'Spyc.php'; From 7ce4dec8ed2c606199bf50c185b1e90856ae8237 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 8 May 2013 16:01:19 -0700 Subject: [PATCH 1620/5359] Revert parts of 3500a184e5ca652370fdaa7e2c2217290fadf69c. Changing the order in which arguments are passed will break community use of this helper function. See https://github.com/wp-cli/wp-cli/commit/3500a184e5ca652370fdaa7e2c2217290fadf69c#commitcomment-3174323 --- php/commands/post.php | 4 ++-- php/commands/role.php | 2 +- php/commands/term.php | 2 +- php/commands/user.php | 2 +- php/utils.php | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index d9d182fd3..7952a8b73 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -123,7 +123,7 @@ public function get( $args, $assoc_args ) { $items[] = $item; } - \WP_CLI\Utils\format_items( $items, $format, array( 'Field', 'Value' ) ); + \WP_CLI\Utils\format_items( $format, $items, array( 'Field', 'Value' ) ); break; case 'json': @@ -200,7 +200,7 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); - WP_CLI\Utils\format_items( $query->posts, $values['format'], $values['fields'] ); + WP_CLI\Utils\format_items( $values['format'], $query->posts, $values['fields'] ); } /** diff --git a/php/commands/role.php b/php/commands/role.php index 2f88e4d02..bfd974b63 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -40,7 +40,7 @@ public function _list( $args, $assoc_args ) { $output_roles[] = $output_role; } - WP_CLI\Utils\format_items( $output_roles, $params['format'], $fields ); + WP_CLI\Utils\format_items( $params['format'], $output_roles, $fields ); } /** diff --git a/php/commands/term.php b/php/commands/term.php index 5c9c72468..5cbaf0a5a 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -41,7 +41,7 @@ public function _list( $args, $assoc_args ) { if ( 'ids' == $assoc_args['format'] ) $terms = wp_list_pluck( $terms, 'term_id' ); - WP_CLI\Utils\format_items( $terms, $assoc_args['format'], $fields, $terms ); + WP_CLI\Utils\format_items( $assoc_args['format'], $terms, $fields ); } /** diff --git a/php/commands/user.php b/php/commands/user.php index 1880a2960..23b68f373 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -53,7 +53,7 @@ public function _list( $args, $assoc_args ) { } } - WP_CLI\Utils\format_items( $users, $params['format'], $fields ); + WP_CLI\Utils\format_items( $params['format'], $users, $fields ); } /** diff --git a/php/utils.php b/php/utils.php index acb259d5f..39ff8e7ad 100644 --- a/php/utils.php +++ b/php/utils.php @@ -255,11 +255,11 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria /** * Output items in a table, JSON, or CSV * + * @param string $format Format to use: 'table', 'json', 'csv', 'ids' * @param array $items Data to output - * @param string $format Format to use: 'table', 'json', 'csv' * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ -function format_items( $items, $format, $fields ) { +function format_items( $format, $items, $fields ) { if ( 'ids' == $format ) \WP_CLI::out( implode( ' ', $items ) ); From c2594aa16e1199296d2f7c4b4eed284d958eab4e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 8 May 2013 16:06:19 -0700 Subject: [PATCH 1621/5359] Update post.feature to test new `--fields` argument --- features/post.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/post.feature b/features/post.feature index 3fa02b1d6..731184f93 100644 --- a/features/post.feature +++ b/features/post.feature @@ -77,11 +77,11 @@ Feature: Manage WordPress posts Then it should run without errors And STDOUT should match '%d' - When I run `wp post list --post_type='post' --format=csv` + When I run `wp post list --post_type='post' --fields=post_title,post_name,post_status --format=csv` Then it should run without errors And STDOUT should be CSV containing: """ - post_title,post_name - "Publish post",publish-post - "Draft post", + post_title,post_name,post_status + "Publish post",publish-post,publish + "Draft post",,draft """ From 78a461720ec98134a6bb300698b6590cee1aed96 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 8 May 2013 16:23:08 -0700 Subject: [PATCH 1622/5359] Update term.feature to make use of `--fields` argument --- features/term.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/term.feature b/features/term.feature index 47a4219dc..0c6af7e53 100644 --- a/features/term.feature +++ b/features/term.feature @@ -17,6 +17,14 @@ Feature: Manage WordPress terms [{"name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] """ + When I run `wp term list post_tag --fields=name,slug --format=csv` + Then it should run without errors + And STDOUT should be CSV containing: + """ + name,slug + "Test term",test + """ + Scenario: Creating/deleting a term Given a WP install From 3a54547a13c9853858f2c2b58c7151c9a26d4825 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 8 May 2013 16:42:37 -0700 Subject: [PATCH 1623/5359] Update man docs to mention `--fields` --- man-src/post-list.txt | 6 ++++++ man-src/role-list.txt | 6 +++++- man-src/term-list.txt | 8 +++++++- man-src/user-list.txt | 6 ++++++ man/post-list.1 | 10 +++++++++- man/role-list.1 | 10 ++++++++-- man/term-list.1 | 10 +++++++++- man/user-list.1 | 10 +++++++++- 8 files changed, 59 insertions(+), 7 deletions(-) diff --git a/man-src/post-list.txt b/man-src/post-list.txt index 47849ced9..67637487a 100644 --- a/man-src/post-list.txt +++ b/man-src/post-list.txt @@ -4,6 +4,10 @@ One or more args to pass to WP_Query. +* `--fields`=<fields>: + + Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date. + * `--format`=<format>: Output list as table, CSV, JSON, or simply IDs. Defaults to table. @@ -13,3 +17,5 @@ wp post list --format=ids wp post list --post_type=post --posts_per_page=5 --format=json + + wp post list --post_type=page --fields=post_title,post_status diff --git a/man-src/role-list.txt b/man-src/role-list.txt index a2dcd0cc0..2b7940161 100644 --- a/man-src/role-list.txt +++ b/man-src/role-list.txt @@ -1,9 +1,13 @@ ## OPTIONS +* `--fields`=<fields>: + + Limit the output to specific object fields. Defaults to name,role. + * `--format`=<format>: Output list as table, CSV or JSON. Defaults to table. ## EXAMPLES - wp role list + wp role list --fields=role --format=csv diff --git a/man-src/term-list.txt b/man-src/term-list.txt index f782b7e59..18cd0a4ed 100644 --- a/man-src/term-list.txt +++ b/man-src/term-list.txt @@ -4,10 +4,16 @@ List terms of a given taxonomy. +* `--fields`=<fields>: + + Limit the output to specific object fields. Defaults to all of the term object fields. + * `--format`=<format>: Output list as table, CSV, JSON, or simply IDs. Defaults to table. ## EXAMPLES - wp term list category --format=csv \ No newline at end of file + wp term list category --format=csv + + wp term list post_tag --fields=name,slug diff --git a/man-src/user-list.txt b/man-src/user-list.txt index d30757b45..0aa7951da 100644 --- a/man-src/user-list.txt +++ b/man-src/user-list.txt @@ -4,6 +4,10 @@ Only display users with a certain role. +* `--fields`=<fields>: + + Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles + * `--format`=<format>: Output list as table, CSV, JSON, or simply IDs. Defaults to table. @@ -13,3 +17,5 @@ wp user list --format=ids wp user list --role=administrator --format=csv + + wp user list --fields=display_name,user_email diff --git a/man/post-list.1 b/man/post-list.1 index b20875028..83d3c3991 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -7,7 +7,7 @@ \fBwp\-post\-list\fR \- Get a list of posts\. . .SH "SYNOPSIS" -wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-format=\fIformat\fR] +wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -18,6 +18,12 @@ wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-format=\fIformat\fR] One or more args to pass to WP_Query\. . .TP +\fB\-\-fields\fR=\fIfields\fR: +. +.IP +Limit the output to specific object fields\. Defaults to ID,post_title,post_name,post_date\. +. +.TP \fB\-\-format\fR=\fIformat\fR: . .IP @@ -30,6 +36,8 @@ Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. wp post list \-\-format=ids wp post list \-\-post_type=post \-\-posts_per_page=5 \-\-format=json + +wp post list \-\-post_type=page \-\-fields=post_title,post_status . .fi diff --git a/man/role-list.1 b/man/role-list.1 index a962ccae4..14d58a8b8 100644 --- a/man/role-list.1 +++ b/man/role-list.1 @@ -7,11 +7,17 @@ \fBwp\-role\-list\fR \- List all roles\. . .SH "SYNOPSIS" -wp role list [\-\-format=\fIformat\fR] +wp role list [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . .TP +\fB\-\-fields\fR=\fIfields\fR: +. +.IP +Limit the output to specific object fields\. Defaults to name,role\. +. +.TP \fB\-\-format\fR=\fIformat\fR: . .IP @@ -21,7 +27,7 @@ Output list as table, CSV or JSON\. Defaults to table\. . .nf -wp role list +wp role list \-\-fields=role \-\-format=csv . .fi diff --git a/man/term-list.1 b/man/term-list.1 index 9990d2ff0..ef1530191 100644 --- a/man/term-list.1 +++ b/man/term-list.1 @@ -7,7 +7,7 @@ \fBwp\-term\-list\fR \- List terms in a taxonomy\. . .SH "SYNOPSIS" -wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] +wp term list \fItaxonomy\fR [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -18,6 +18,12 @@ wp term list \fItaxonomy\fR [\-\-format=\fIformat\fR] List terms of a given taxonomy\. . .TP +\fB\-\-fields\fR=\fIfields\fR: +. +.IP +Limit the output to specific object fields\. Defaults to all of the term object fields\. +. +.TP \fB\-\-format\fR=\fIformat\fR: . .IP @@ -28,6 +34,8 @@ Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. .nf wp term list category \-\-format=csv + +wp term list post_tag \-\-fields=name,slug . .fi diff --git a/man/user-list.1 b/man/user-list.1 index 8d66afa59..f5dac94ed 100644 --- a/man/user-list.1 +++ b/man/user-list.1 @@ -7,7 +7,7 @@ \fBwp\-user\-list\fR \- List users\. . .SH "SYNOPSIS" -wp user list [\-\-role=\fIrole\fR] [\-\-format=\fIformat\fR] +wp user list [\-\-role=\fIrole\fR] [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] . .SH "OPTIONS" . @@ -18,6 +18,12 @@ wp user list [\-\-role=\fIrole\fR] [\-\-format=\fIformat\fR] Only display users with a certain role\. . .TP +\fB\-\-fields\fR=\fIfields\fR: +. +.IP +Limit the output to specific object fields\. Defaults to ID,user_login,display_name,user_email,user_registered,roles +. +.TP \fB\-\-format\fR=\fIformat\fR: . .IP @@ -30,6 +36,8 @@ Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. wp user list \-\-format=ids wp user list \-\-role=administrator \-\-format=csv + +wp user list \-\-fields=display_name,user_email . .fi From e46e6ec9d7af558580f77091316079f4c534c74a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 13:04:02 +0300 Subject: [PATCH 1624/5359] don't load cli/cli.php utilities (unused) --- php/utils.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 39ff8e7ad..7ef915431 100644 --- a/php/utils.php +++ b/php/utils.php @@ -17,7 +17,6 @@ function load_dependencies() { foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; - include $vendor_path . '/jlogsdon/cli/lib/cli/cli.php'; $has_autoload = true; break; } From d7cf3340f8988eefe16ee371b61938ef772f7850 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 13:11:55 +0300 Subject: [PATCH 1625/5359] Revert "don't load cli/cli.php utilities (unused)" It's used internally by cli\Table. This reverts commit e46e6ec9d7af558580f77091316079f4c534c74a. --- php/utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/utils.php b/php/utils.php index 7ef915431..39ff8e7ad 100644 --- a/php/utils.php +++ b/php/utils.php @@ -17,6 +17,7 @@ function load_dependencies() { foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; + include $vendor_path . '/jlogsdon/cli/lib/cli/cli.php'; $has_autoload = true; break; } From 2612b40ea2dcbc1c2633e2f28088eabddb833882 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Thu, 9 May 2013 13:32:16 +0200 Subject: [PATCH 1626/5359] Implemented 'list' command for theme and plugin command, issue #440 --- php/WP_CLI/CommandWithUpgrade.php | 44 +++++++++++++++++++++++++++++++ php/commands/plugin.php | 17 ++++++++++++ php/commands/theme.php | 17 ++++++++++++ 3 files changed, 78 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 01d1c06a3..88687f2b3 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -169,6 +169,26 @@ function update_all( $args, $assoc_args ) { } } + protected function _list( $format ) { + $values = array( + 'format' => 'table', + 'fields' => $this->fields + ); + + foreach ( $values as $key => &$value ) { + if ( isset( $format[ $key ] ) ) { + $value = $format[ $key ]; + unset( $format[ $key ] ); + } + } + unset( $value ); + + $all_items = $this->get_all_items(); + $items = $this->create_objects( $all_items ); + + \WP_CLI\Utils\format_items( $values['format'], $items, $values['fields'] ); + } + /** * Check whether an item has an update available or not. * @@ -197,6 +217,30 @@ protected function has_update( $slug ) { ) ); + private function create_objects( $items ) { + if ( !is_array( $items ) && !empty( $items ) ) + \WP_CLI::error( sprintf( "No '$this->item_type's found." ) ); + + $objects = array(); + + foreach ( $items as $item ) { + $object = new \stdClass; + + foreach ( $item as $field => $value ) { + if ( $value === true ) { + $value = "available"; + } else if ( $value === false) { + $value = "none"; + } + + $object->{$field} = $value; + } + $objects[] = $object; + } + + return $objects; + } + protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index f761afb19..162b2539d 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -12,6 +12,13 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade { protected $upgrade_refresh = 'wp_update_plugins'; protected $upgrade_transient = 'update_plugins'; + protected $fields = array( + 'name', + 'status', + 'update', + 'version' + ); + function __construct() { require_once ABSPATH.'wp-admin/includes/plugin.php'; require_once ABSPATH.'wp-admin/includes/plugin-install.php'; @@ -292,6 +299,16 @@ function delete( $args, $assoc_args = array(), $exit_on_error = true ) { return WP_CLI::launch( $command, $exit_on_error ); } + /** + * Get a list of plugins. + * + * @subcommand list + * @synopsis [--format=<format>] + */ + function _list( $_, $assoc_args ) { + parent::_list( $_, $assoc_args ); + } + /* PRIVATES */ private function check_active( $file, $network_wide ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index f7670c8cb..2970eb65f 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -12,6 +12,13 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; + protected $fields = array( + 'name', + 'status', + 'update', + 'version' + ); + /** * See the status of one or all themes. * @@ -190,6 +197,16 @@ function delete( $args ) { } } + /** + * Get a list of themes. + * + * @subcommand list + * @synopsis [--format=<format>] + */ + function _list( $_, $assoc_args ) { + parent::_list( $assoc_args ); + } + protected function parse_name( $args ) { if ( empty( $args ) ) { WP_CLI::line( "usage: wp theme $subcommand <theme-name>" ); From a1a28bb9ff4bdaebb5a6d84a55ee42b20467c945 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Thu, 9 May 2013 16:26:24 +0200 Subject: [PATCH 1627/5359] Match arguments of parent function --- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/commands/theme.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 88687f2b3..f8b349a1f 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -169,7 +169,7 @@ function update_all( $args, $assoc_args ) { } } - protected function _list( $format ) { + protected function _list( $_, $format ) { $values = array( 'format' => 'table', 'fields' => $this->fields diff --git a/php/commands/theme.php b/php/commands/theme.php index 2970eb65f..441b2a3a2 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -204,7 +204,7 @@ function delete( $args ) { * @synopsis [--format=<format>] */ function _list( $_, $assoc_args ) { - parent::_list( $assoc_args ); + parent::_list( $_, $assoc_args ); } protected function parse_name( $args ) { From 77c971350d8cf14098f85ca23a6da2ffed4b32e8 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Thu, 9 May 2013 16:30:28 +0200 Subject: [PATCH 1628/5359] Generated man pages for the list commands --- man-src/plugin-list.txt | 9 +++++++++ man-src/theme-list.txt | 9 +++++++++ man/plugin-list.1 | 21 +++++++++++++++++++++ man/theme-list.1 | 21 +++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 man-src/plugin-list.txt create mode 100644 man-src/theme-list.txt create mode 100644 man/plugin-list.1 create mode 100644 man/theme-list.1 diff --git a/man-src/plugin-list.txt b/man-src/plugin-list.txt new file mode 100644 index 000000000..8d2344d88 --- /dev/null +++ b/man-src/plugin-list.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--format`=<format>: + + Output list as table, CSV or JSON. Defaults to table. + +## EXAMPLES + + wp plugin list --format=json diff --git a/man-src/theme-list.txt b/man-src/theme-list.txt new file mode 100644 index 000000000..b875caeed --- /dev/null +++ b/man-src/theme-list.txt @@ -0,0 +1,9 @@ +## OPTIONS + +* `--format`=<format>: + + Output list as table, CSV or JSON. Defaults to table. + +## EXAMPLES + + wp theme list --format=csv diff --git a/man/plugin-list.1 b/man/plugin-list.1 new file mode 100644 index 000000000..fd23e19af --- /dev/null +++ b/man/plugin-list.1 @@ -0,0 +1,21 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-PLUGIN\-LIST" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-plugin\-list\fR \- Get a list of plugins\. +. +.SH "SYNOPSIS" +wp plugin list [\-\-format=\fIformat\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. +. +.SH "EXAMPLES" +wp plugin list \-\-format=json diff --git a/man/theme-list.1 b/man/theme-list.1 new file mode 100644 index 000000000..96436899f --- /dev/null +++ b/man/theme-list.1 @@ -0,0 +1,21 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-THEME\-LIST" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-theme\-list\fR \- Get a list of themes\. +. +.SH "SYNOPSIS" +wp theme list [\-\-format=\fIformat\fR] +. +.SH "OPTIONS" +. +.TP +\fB\-\-format\fR=\fIformat\fR: +. +.IP +Output list as table, CSV or JSON\. Defaults to table\. +. +.SH "EXAMPLES" +wp theme list \-\-format=csv From 4fb95a3e4f994677b1b23fbaefd5a0841ec23c93 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Thu, 9 May 2013 16:41:08 +0200 Subject: [PATCH 1629/5359] Added functional tests for the plugin and theme list command --- features/plugin.feature | 4 ++++ features/theme.feature | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 88dbf0548..66bdb0530 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -21,3 +21,7 @@ Feature: Manage WordPress plugins """ Error: The plugin 'non-existent-plugin' could not be found. """ + + When I run `wp plugin list --format=json` + Then it should run without errors + And STDOUT should not be empty diff --git a/features/theme.feature b/features/theme.feature index a6a57c252..4424b4404 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -49,6 +49,10 @@ Feature: Manage WordPress themes Error: The theme 'p2' could not be found. """ + When I run `wp theme list` + Then it should run without errors + And STDOUT should not be empty + Scenario: Upgrading a theme Given a WP install And a P2 theme zip From 32402827d8e738c7c4e6025b7b3bbc6d7a1a45d2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 20:53:47 +0300 Subject: [PATCH 1630/5359] first pass at --verbose flag for `wp export` --- php/commands/export.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 0f85c92c3..2983053d3 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -11,7 +11,7 @@ class Export_Command extends WP_CLI_Command { /** * Export content to a WXR file. * - * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] + * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] [--verbose] */ public function __invoke( $_, $assoc_args ) { $defaults = array( @@ -25,6 +25,7 @@ public function __invoke( $_, $assoc_args ) { 'post__in' => NULL, 'skip_comments' => NULL, 'file_item_count' => 1000, + 'verbose' => false, ); $args = wp_parse_args( $assoc_args, $defaults ); @@ -51,6 +52,12 @@ public function __invoke( $_, $assoc_args ) { $this->export_wp( $this->export_args ); } + private function check_verbose( $verbose ) { + $this->verbose = $verbose; + + return true; + } + private function check_dir( $path ) { if ( empty( $path ) ) { $this->export_args['dir'] = getcwd(); @@ -376,7 +383,8 @@ private function export_wp( $args = array() ) { WP_CLI::line( 'Writing to file ' . $full_path ); } - $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); + if ( !$this->verbose ) + $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); $this->start_export(); echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; @@ -447,7 +455,11 @@ private function export_wp( $args = array() ) { // Begin Loop foreach ( $posts as $post ) { - $progress->tick(); + if ( !$this->verbose ) { + $progress->tick(); + } else { + WP_CLI::line( "Exporting post $post->ID" ); + } setup_postdata( $post ); $is_sticky = is_sticky( $post->ID ) ? 1 : 0; @@ -525,7 +537,11 @@ private function export_wp( $args = array() ) { $this->flush_export( $full_path ); $this->end_export(); $this->stop_the_insanity(); - $progress->finish(); + + if ( !$this->verbose ) { + $progress->finish(); + } + $file_count++; } WP_CLI::success( "All done with export" ); From 067c9ed741efad4ddd38d9b1fefd284d50d7d501 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 21:02:00 +0300 Subject: [PATCH 1631/5359] export: minor whitespace fixes --- php/commands/export.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 2983053d3..e28d778e0 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -15,16 +15,16 @@ class Export_Command extends WP_CLI_Command { */ public function __invoke( $_, $assoc_args ) { $defaults = array( - 'dir' => NULL, - 'start_date' => NULL, - 'end_date' => NULL, - 'post_type' => NULL, - 'author' => NULL, - 'category' => NULL, - 'post_status' => NULL, - 'post__in' => NULL, - 'skip_comments' => NULL, - 'file_item_count' => 1000, + 'dir' => NULL, + 'start_date' => NULL, + 'end_date' => NULL, + 'post_type' => NULL, + 'author' => NULL, + 'category' => NULL, + 'post_status' => NULL, + 'post__in' => NULL, + 'skip_comments' => NULL, + 'file_item_count' => 1000, 'verbose' => false, ); @@ -386,8 +386,8 @@ private function export_wp( $args = array() ) { if ( !$this->verbose ) $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); - $this->start_export(); - echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; + $this->start_export(); + echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; ?> <!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. --> From a8180e70bcf4a30909f7c06e8cc39ddf3d66f058 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 23:54:58 +0300 Subject: [PATCH 1632/5359] behat: set up WP file cache only once, before suite Also, use run_check() to catch download errors. see #441 --- features/bootstrap/FeatureContext.php | 32 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 1245620f2..699f6c56b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -16,6 +16,8 @@ */ class FeatureContext extends BehatContext implements ClosuredContextInterface { + private static $cache_dir; + private static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', @@ -28,10 +30,28 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { public $variables = array(); + private static function wp_cli( $command ) { + return __DIR__ . "/../../bin/wp $command"; + } + + // We cache the results of `wp core download` to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + private static function cache_wp_files() { + self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + + if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) + return; + + $cmd = Utils\esc_cmd( 'core download --force --path=%s', self::$cache_dir ); + Process::create( self::wp_cli( $cmd ) )->run_check(); + } + /** * @BeforeSuite */ public static function prepare( SuiteEvent $event ) { + self::cache_wp_files(); + self::$additional_args = array( 'core config' => self::$db_settings, @@ -131,7 +151,7 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( __DIR__ . "/../../bin/wp $command", $this->install_dir ); + return Process::create( self::wp_cli( $command ), $this->install_dir ); } public function move_files( $src, $dest ) { @@ -145,19 +165,11 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { } public function download_wordpress_files( $subdir = '' ) { - // We cache the results of "wp core download" to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - $cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; - - $r = $this->proc( 'core download', array( - 'path' => $cache_dir - ) )->run(); - $dest_dir = $this->get_path( $subdir ); if ( $subdir ) mkdir( $dest_dir ); - Process::create( Utils\esc_cmd( "cp -r %s/* %s", $cache_dir, $dest_dir ) )->run_check(); + Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); } public function wp_install( $subdir = '' ) { From 8e03de3d4f968d73daa7f3419adac937620e52bc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 23:23:58 +0300 Subject: [PATCH 1633/5359] define WP_DEBUG in Utils\wp_debug_mode() --- php/WP_CLI/Runner.php | 7 ------- php/utils-wp.php | 3 +++ php/wp-cli.php | 2 -- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4af9554ea..fba607aec 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -335,13 +335,6 @@ public function before_wp_load() { } } - public function after_wp_config_load() { - if ( $this->config['debug'] ) { - if ( !defined( 'WP_DEBUG' ) ) - define( 'WP_DEBUG', true ); - } - } - public function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 1821f7f8c..a50be4713 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -14,6 +14,9 @@ function wp_not_installed() { function wp_debug_mode() { if ( \WP_CLI::get_config( 'debug' ) ) { + if ( !defined( 'WP_DEBUG' ) ) + define( 'WP_DEBUG', true ); + error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT ); ini_set( 'display_errors', true ); } else { diff --git a/php/wp-cli.php b/php/wp-cli.php index f002341c3..74db4137d 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -20,8 +20,6 @@ // Load wp-config.php code, in the global scope eval( WP_CLI::$runner->get_wp_config_code() ); -WP_CLI::$runner->after_wp_config_load(); - // Simulate a /wp-admin/ page load $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; define( 'WP_ADMIN', true ); From 6aa4fa36f8701e3148ba44e7a0ee33b7fc71a54a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 10 May 2013 00:39:15 +0300 Subject: [PATCH 1634/5359] never display PHP errors on STDOUT --- features/flags.feature | 8 ++++++-- php/utils-wp.php | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 7053443bb..39592c33a 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -30,9 +30,13 @@ Feature: Global flags When I run `wp eval 'echo CONST_WITHOUT_QUOTES;' --debug` Then the return code should be 0 - And STDOUT should contain: + And STDOUT should be: + """ + CONST_WITHOUT_QUOTES + """ + And STDERR should contain: """ - Notice: Use of undefined constant CONST_WITHOUT_QUOTES + PHP Notice: Use of undefined constant CONST_WITHOUT_QUOTES """ Scenario: Setting the WP user diff --git a/php/utils-wp.php b/php/utils-wp.php index a50be4713..f5c2afe85 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -18,10 +18,12 @@ function wp_debug_mode() { define( 'WP_DEBUG', true ); error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT ); - ini_set( 'display_errors', true ); } else { \wp_debug_mode(); } + + // Never show errors on STDOUT; only on STDERR + ini_set( 'display_errors', false ); } function replace_wp_die_handler() { From d3e4016a84d1173f5587937d1734c1e137413db5 Mon Sep 17 00:00:00 2001 From: tolgap <tolga@hoppinger.com> Date: Fri, 10 May 2013 15:16:31 +0200 Subject: [PATCH 1635/5359] Force the version field if not exist so it shows up in the table --- php/WP_CLI/CommandWithUpgrade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index f8b349a1f..4ffe02386 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -226,6 +226,9 @@ private function create_objects( $items ) { foreach ( $items as $item ) { $object = new \stdClass; + if ( empty( $item['version'] ) ) + $item['version'] = ""; + foreach ( $item as $field => $value ) { if ( $value === true ) { $value = "available"; From 5ad115079538d63bb17c9d6f248821265df61bd9 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 23 Apr 2013 00:50:10 +0200 Subject: [PATCH 1636/5359] Added CPT and TAX --flags test and TAX --theme test --- features/scaffold.feature | 65 ++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 5c966f080..616ebfad4 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,15 +1,64 @@ Feature: Wordpress code scaffolding - - Scenario: Scaffold a Custom Post Type - Given a WP install - When I run `wp scaffold post-type zombie` - Then it should run without errors - And STDOUT should contain: + Scenario: Scaffold a Custom Taxonomy and write it to active theme + Given a WP install + + When I run `wp scaffold taxonomy zombie-speed --theme` + Then it should run without errors + + When I run `wp option get stylesheet` + Then it should run without errors + And save STDOUT as {ACTIVE_THEME} + + #And the wp-content/{ACTIVE_THEME}/taxonomy/zombie-speed.php file should exist + And the wp-content/themes/twentytwelve/taxonomies/zombie-speed.php file should exist + + # Test for all flags but --label, --theme, --plugin and --raw + Scenario: Scaffold a Custom Taxonomy and attach it to a CPT zombie that is prefixed and has a text domain + Given a WP install + + When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie" --textdomain=zombieland` + Then it should run without errors + And STDOUT should contain: + """ + __( 'Zombie speeds' + """ + And STDOUT should contain: + """ + array( 'prefix-zombie' ) + """ + And STDOUT should contain: + """ + __( 'Zombie speeds', 'zombieland' + """ + + Scenario: Scaffold a Custom Taxonomy with label "Speed" + Given a WP install + + When I run `wp scaffold taxonomy zombie-speed --label="Speed"` + Then it should run without errors + And STDOUT should contain: """ - __( 'Zombies' + __( 'Speed' """ - + + + + # Test for all flags but --label, --theme, --plugin and --raw + Scenario: Scaffold a Custom Post Type + Given a WP install + + When I run `wp scaffold post-type zombie --textdomain=zombieland` + Then it should run without errors + And STDOUT should contain: + """ + __( 'Zombies' + """ + And STDOUT should contain: + """ + __( 'Zombies', 'zombieland' + """ + Scenario: Scaffold a Custom Post Type with label Given a WP install From 61dd38e0d9b35681d953d9460966b56d90a7f728 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 9 May 2013 02:39:02 +0200 Subject: [PATCH 1637/5359] Using stylesheetpath because it gets them path and active theme at once --- features/scaffold.feature | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 616ebfad4..423d373c5 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -6,12 +6,10 @@ Feature: Wordpress code scaffolding When I run `wp scaffold taxonomy zombie-speed --theme` Then it should run without errors - When I run `wp option get stylesheet` + When I run `wp eval 'echo STYLESHEETPATH;'` Then it should run without errors - And save STDOUT as {ACTIVE_THEME} - - #And the wp-content/{ACTIVE_THEME}/taxonomy/zombie-speed.php file should exist - And the wp-content/themes/twentytwelve/taxonomies/zombie-speed.php file should exist + And save STDOUT as {STYLESHEETPATH} + And the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist # Test for all flags but --label, --theme, --plugin and --raw Scenario: Scaffold a Custom Taxonomy and attach it to a CPT zombie that is prefixed and has a text domain From d55d5599861bcb69e318927be2c86dca98abc4d5 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 9 May 2013 18:20:27 +0200 Subject: [PATCH 1638/5359] Added CPT creation --- features/scaffold.feature | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 423d373c5..7f018db3d 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -11,6 +11,17 @@ Feature: Wordpress code scaffolding And save STDOUT as {STYLESHEETPATH} And the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist + Scenario: Scaffold a Custom Post Type and write it to active theme + Given a WP install + + When I run `wp scaffold post-type zombie --theme` + Then it should run without errors + + When I run `wp eval 'echo STYLESHEETPATH;'` + Then it should run without errors + And save STDOUT as {STYLESHEETPATH} + And the {STYLESHEETPATH}/post-types/zombie.php file should exist + # Test for all flags but --label, --theme, --plugin and --raw Scenario: Scaffold a Custom Taxonomy and attach it to a CPT zombie that is prefixed and has a text domain Given a WP install @@ -40,8 +51,6 @@ Feature: Wordpress code scaffolding __( 'Speed' """ - - # Test for all flags but --label, --theme, --plugin and --raw Scenario: Scaffold a Custom Post Type Given a WP install From 0d1771575235eb4cfa26729dc4ebb19283f20b1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 May 2013 01:03:35 +0300 Subject: [PATCH 1639/5359] simplify 'file should exist' step definition --- features/steps/basic_steps.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 89368ceb7..59cf646b7 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -252,16 +252,13 @@ function ( $world, $stream ) { $steps->Then( '/^the (.+) file should exist$/', function ( $world, $path ) { - $path = $world->replace_variables( $path ); + $path = $world->replace_variables( $path ); - // If $path refers to a complete cache path, use it; - // otherwise, get the real path using $world->get_path() - if ( strpos( $path, $world->get_cache_path('') ) === 0 ) - $realpath = $path; - else - $realpath = $world->get_path( $path ); + // If it's a relative path, make it relative to the current test dir + if ( '/' !== $path[0] ) + $path = $world->get_path( $path ); - assertFileExists( $realpath ); + assertFileExists( $path ); } ); From 2d2fc66c30af12e24b3609a950393cd24aeae41e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 May 2013 23:27:19 +0300 Subject: [PATCH 1640/5359] switch back to our fork of php-cli-tools --- composer.json | 2 +- composer.lock | 72 +++++++++++++++++++++++++++------------------------ php/utils.php | 1 - 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index dc3cc5aaa..ff0d20c9d 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "jlogsdon/cli": "~0.9.1", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "2.0.x" }, "suggest": { diff --git a/composer.lock b/composer.lock index 726e2b26b..a16ee74ea 100644 --- a/composer.lock +++ b/composer.lock @@ -3,29 +3,29 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "2f907ef4729a8057cba8d5310e72ed9f", + "hash": "e83d4615b33cb717939303cba9848c94", "packages": [ { - "name": "jlogsdon/cli", - "version": "v0.9.1", + "name": "mustache/mustache", + "version": "v2.0.2", "source": { "type": "git", - "url": "git://github.com/jlogsdon/php-cli-tools.git", - "reference": "v0.9.1" + "url": "https://github.com/bobthecow/mustache.php", + "reference": "v2.0.2" }, "dist": { "type": "zip", - "url": "https://github.com/jlogsdon/php-cli-tools/zipball/v0.9.1", - "reference": "v0.9.1", + "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", + "reference": "v2.0.2", "shasum": "" }, "require": { - "php": ">= 5.3.0" + "php": ">=5.2.4" }, "type": "library", "autoload": { "psr-0": { - "cli": "lib/" + "Mustache": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -34,41 +34,44 @@ ], "authors": [ { - "name": "James Logsdon", - "email": "jlogsdon@php.net", - "role": "Developer" + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" } ], - "description": "Console utilities for PHP", - "homepage": "http://github.com/jlogsdon/php-cli-tools", + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", "keywords": [ - "cli", - "console" + "mustache", + "templating" ], - "time": "2012-09-15 14:09:00" + "time": "2012-09-12 09:13:06" }, { - "name": "mustache/mustache", - "version": "v2.0.2", + "name": "wp-cli/php-cli-tools", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/bobthecow/mustache.php", - "reference": "v2.0.2" + "url": "https://github.com/wp-cli/php-cli-tools.git", + "reference": "d44e1a9bd32d564a1c77dda0e96b66a199993e5c" }, "dist": { "type": "zip", - "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", - "reference": "v2.0.2", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d44e1a9bd32d564a1c77dda0e96b66a199993e5c", + "reference": "d44e1a9bd32d564a1c77dda0e96b66a199993e5c", "shasum": "" }, "require": { - "php": ">=5.2.4" + "php": ">= 5.3.0" }, "type": "library", "autoload": { "psr-0": { - "Mustache": "src/" - } + "cli": "lib/" + }, + "files": [ + "lib/cli/cli.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -76,18 +79,18 @@ ], "authors": [ { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "name": "James Logsdon", + "email": "jlogsdon@php.net", + "role": "Developer" } ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", + "description": "Console utilities for PHP", + "homepage": "http://github.com/jlogsdon/php-cli-tools", "keywords": [ - "mustache", - "templating" + "cli", + "console" ], - "time": "2012-09-12 09:13:06" + "time": "2013-05-11 20:20:03" } ], "packages-dev": [ @@ -928,6 +931,7 @@ ], "minimum-stability": "stable", "stability-flags": { + "wp-cli/php-cli-tools": 20, "behat/behat": 0 }, "platform": { diff --git a/php/utils.php b/php/utils.php index 39ff8e7ad..7ef915431 100644 --- a/php/utils.php +++ b/php/utils.php @@ -17,7 +17,6 @@ function load_dependencies() { foreach ( $vendor_paths as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; - include $vendor_path . '/jlogsdon/cli/lib/cli/cli.php'; $has_autoload = true; break; } From 4365b16811300622ef17c079e010c776bf9eb793 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 May 2013 23:28:24 +0300 Subject: [PATCH 1641/5359] autoload from local vendor dir, then from global This allows running `composer update` on the spot and without switching the wp-cli repo back to the master branch. This also allows using suggested packages from a super-project (most common being ~/.composer). --- php/utils.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 7ef915431..07aa0a083 100644 --- a/php/utils.php +++ b/php/utils.php @@ -8,8 +8,8 @@ function load_dependencies() { $vendor_paths = array( - WP_CLI_ROOT . '../../../../vendor', // part of a larger project WP_CLI_ROOT . '../vendor', // top-level project + WP_CLI_ROOT . '../../../../vendor', // part of a larger project ); $has_autoload = false; @@ -18,7 +18,6 @@ function load_dependencies() { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; $has_autoload = true; - break; } } From d233ebbdc56320497e07357ed7eb966ae4bd4e64 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 00:11:04 +0300 Subject: [PATCH 1642/5359] stop after finding the first Composer autoloader. Otherwise, could get fatal errors, such as "Cannot redeclare cli\register_autoload()". Unfortunately, this also means that suggested packages will be ignored, if there's a local vendor dir present. --- php/utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/utils.php b/php/utils.php index 07aa0a083..880136c86 100644 --- a/php/utils.php +++ b/php/utils.php @@ -18,6 +18,7 @@ function load_dependencies() { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; $has_autoload = true; + break; } } From 0c047f6f2fc65b1b677e7dd8a61e60abb444f7eb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 16:22:29 +0300 Subject: [PATCH 1643/5359] add deprecation message for WP_CLI::addCommand() closes #448 --- php/class-wp-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b8abeccef..e3855a7ce 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -270,6 +270,8 @@ public static function run_command( $args, $assoc_args = array() ) { // back-compat static function addCommand( $name, $class ) { + trigger_error( sprintf( 'wp %s: %s is deprecated. use WP_CLI::add_command() instead.', + $name, __FUNCTION__ ), E_USER_WARNING ); self::add_command( $name, $class ); } } From c8a5b120904579f3e3e7debbd63e8788ad37a12a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 16:37:13 +0300 Subject: [PATCH 1644/5359] make is_absolute_path() work on Windows paths fixes #447 --- php/WP_CLI/Runner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index fba607aec..981716dc1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -110,6 +110,10 @@ private static function set_wp_root( $config ) { } private static function is_absolute_path( $path ) { + // Windows + if ( ':' === $path[1] ) + return true; + return $path[0] === '/'; } From 9fe97c833a367d0d42e8c691b1dcb9f7a21de5a3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 19:25:31 +0300 Subject: [PATCH 1645/5359] export: more indentation fixes --- php/commands/export.php | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index e28d778e0..9b6b1d6d5 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -329,31 +329,31 @@ private function export_wp( $args = array() ) { $cats = array( $cat->term_id => $cat ); unset( $term, $cat ); } else if ( 'all' == $args['post_type'] ) { - $categories = (array) get_categories( array( 'get' => 'all' ) ); - $tags = (array) get_tags( array( 'get' => 'all' ) ); - - $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); - $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); - - // put categories in order with no child going before its parent - while ( $cat = array_shift( $categories ) ) { - if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) - $cats[$cat->term_id] = $cat; - else - $categories[] = $cat; - } - - // put terms in order with no child going before its parent - while ( $t = array_shift( $custom_terms ) ) { - if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) - $terms[$t->term_id] = $t; - else - $custom_terms[] = $t; - } + $categories = (array) get_categories( array( 'get' => 'all' ) ); + $tags = (array) get_tags( array( 'get' => 'all' ) ); + + $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); + $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); + + // put categories in order with no child going before its parent + while ( $cat = array_shift( $categories ) ) { + if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) + $cats[$cat->term_id] = $cat; + else + $categories[] = $cat; + } - unset( $categories, $custom_taxonomies, $custom_terms ); + // put terms in order with no child going before its parent + while ( $t = array_shift( $custom_terms ) ) { + if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) + $terms[$t->term_id] = $t; + else + $custom_terms[] = $t; } + unset( $categories, $custom_taxonomies, $custom_terms ); + } + // Load the functions available in wp-admin/includes/export.php ob_start(); export_wp( array( 'content' => 'page', 'start_date' => '1971-01-01', 'end_date' => '1971-01-02' ) ); From e057464acc250f16330da40c6f80941de7adc249 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 19:26:55 +0300 Subject: [PATCH 1646/5359] export: show parameters sent to export_wp() only if --verbose is set --- php/commands/export.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 9b6b1d6d5..3bde8c314 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -256,7 +256,9 @@ private function export_wp( $args = array() ) { ); $args = wp_parse_args( $args, $defaults ); - WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); + if ( $this->verbose ) { + WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); + } do_action( 'export_wp' ); From 0781be0fd832627fef85ef3e8d783654fc012a12 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 19:29:34 +0300 Subject: [PATCH 1647/5359] export: document --verbose parameter [ci skip] --- man-src/export.txt | 4 ++++ man/export.1 | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/man-src/export.txt b/man-src/export.txt index 94e5cab4b..dcb8ea478 100644 --- a/man-src/export.txt +++ b/man-src/export.txt @@ -13,6 +13,10 @@ to current working directory. Break export into files with N posts. +* `--verbose`: + + Show more information about the process on STDOUT. + ## FILTERS * `--start_date`=<date>: diff --git a/man/export.1 b/man/export.1 index a11fc78cb..e4aaf633b 100644 --- a/man/export.1 +++ b/man/export.1 @@ -7,7 +7,7 @@ \fBwp\-export\fR \- Export content to a WXR file\. . .SH "SYNOPSIS" -wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post__in=\fIpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] +wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post__in=\fIpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] [\-\-verbose] . .SH "OPTIONS" . @@ -29,6 +29,12 @@ Don\'t export comments\. .IP Break export into files with N posts\. . +.TP +\fB\-\-verbose\fR: +. +.IP +Show more information about the process on STDOUT\. +. .SH "FILTERS" . .TP From 7066757ee12a27c17a629507fbeda0d799cbb08a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 19:37:31 +0300 Subject: [PATCH 1648/5359] export: add smoke test --- features/export.feature | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 features/export.feature diff --git a/features/export.feature b/features/export.feature new file mode 100644 index 000000000..096429833 --- /dev/null +++ b/features/export.feature @@ -0,0 +1,8 @@ +Feature: Export content. + + Scenario: Basic export + Given a WP install + + When I run `wp export` + Then it should run without errors + And STDOUT should not be empty From e3fbb0525f241e3a3e9d3a4e244a53cb26fa0a81 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 12 May 2013 23:02:20 +0200 Subject: [PATCH 1649/5359] Merged CPT and Tax test --- features/scaffold.feature | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 7f018db3d..acd875f5f 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,6 +1,6 @@ Feature: Wordpress code scaffolding - Scenario: Scaffold a Custom Taxonomy and write it to active theme + Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install When I run `wp scaffold taxonomy zombie-speed --theme` @@ -11,15 +11,8 @@ Feature: Wordpress code scaffolding And save STDOUT as {STYLESHEETPATH} And the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist - Scenario: Scaffold a Custom Post Type and write it to active theme - Given a WP install - When I run `wp scaffold post-type zombie --theme` Then it should run without errors - - When I run `wp eval 'echo STYLESHEETPATH;'` - Then it should run without errors - And save STDOUT as {STYLESHEETPATH} And the {STYLESHEETPATH}/post-types/zombie.php file should exist # Test for all flags but --label, --theme, --plugin and --raw From 0d4e5357ca7b6c0638185e3fe09d10b6391665c1 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 12 May 2013 23:05:21 +0200 Subject: [PATCH 1650/5359] Added trailing slash to WP_CONTENT_DIR Fixes #446 --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b43e87a13..1cdcac396 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -166,7 +166,7 @@ function child_theme( $args, $assoc_args ) { $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; - $theme_dir = WP_CONTENT_DIR . "themes" . "/$theme_slug"; + $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; $this->create_file( $theme_style_path, $this->render( 'child_theme.mustache', $data ) ); From 29ee3d3227437b4c3f4d287ea1e878ff4a0c5200 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 00:29:45 +0200 Subject: [PATCH 1651/5359] Added child-theme behat test --- features/scaffold.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index acd875f5f..10b876324 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,5 +1,18 @@ Feature: Wordpress code scaffolding + @theme + Scenario: Scaffold a child theme + Given a WP install + + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella` + Then it should run without errors + + When I run `wp theme path` + Then it should run without errors + And save STDOUT as {THEME_PATH} + And the {THEME_PATH}/zombieland/style.css file should exist + + Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install From b07830876addfa08b5804f32925ed3e4f1fbcf02 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 00:52:13 +0200 Subject: [PATCH 1652/5359] Added tags --- features/scaffold.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 10b876324..4fa80f743 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -12,7 +12,7 @@ Feature: Wordpress code scaffolding And save STDOUT as {THEME_PATH} And the {THEME_PATH}/zombieland/style.css file should exist - + @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install @@ -29,6 +29,7 @@ Feature: Wordpress code scaffolding And the {STYLESHEETPATH}/post-types/zombie.php file should exist # Test for all flags but --label, --theme, --plugin and --raw + @tax Scenario: Scaffold a Custom Taxonomy and attach it to a CPT zombie that is prefixed and has a text domain Given a WP install @@ -47,6 +48,7 @@ Feature: Wordpress code scaffolding __( 'Zombie speeds', 'zombieland' """ + @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" Given a WP install @@ -58,6 +60,7 @@ Feature: Wordpress code scaffolding """ # Test for all flags but --label, --theme, --plugin and --raw + @cpt Scenario: Scaffold a Custom Post Type Given a WP install @@ -72,6 +75,7 @@ Feature: Wordpress code scaffolding __( 'Zombies', 'zombieland' """ + @cpt Scenario: Scaffold a Custom Post Type with label Given a WP install From b56b58f778913cb2c63fbd7eecc9077c6e354e4a Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 00:58:12 +0200 Subject: [PATCH 1653/5359] Added behat test for plugin scaffolding --- features/scaffold.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 4fa80f743..1285ddb05 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -11,6 +11,18 @@ Feature: Wordpress code scaffolding Then it should run without errors And save STDOUT as {THEME_PATH} And the {THEME_PATH}/zombieland/style.css file should exist + + @plugin + Scenario: Scaffold a plugin + Given a WP install + + When I run `wp scaffold plugin zombieland` + Then it should run without errors + + When I run `wp path path` + Then it should run without errors + And save STDOUT as {PLUGIN_PATH} + And the {PLUGIN_PATH}/zombieland/zombieland.php file should exist @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme From 37b3d8bfac6793862d0a0fe6497ed7a597fe23be Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 01:11:11 +0200 Subject: [PATCH 1654/5359] Added scaffold plugin activation test --- features/scaffold.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 1285ddb05..ba516bfb2 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -4,7 +4,7 @@ Feature: Wordpress code scaffolding Scenario: Scaffold a child theme Given a WP install - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella` + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` Then it should run without errors When I run `wp theme path` @@ -16,7 +16,7 @@ Feature: Wordpress code scaffolding Scenario: Scaffold a plugin Given a WP install - When I run `wp scaffold plugin zombieland` + When I run `wp scaffold plugin zombieland --activate` Then it should run without errors When I run `wp path path` From 5a985b4bfc72fe70bcbb93884442511f5adeff86 Mon Sep 17 00:00:00 2001 From: Jaime Martinez <jmslbam@gmail.com> Date: Mon, 13 May 2013 09:26:51 +0200 Subject: [PATCH 1655/5359] Plugin scaffold typo fix for Behat test --- features/scaffold.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index ba516bfb2..2d27a889b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -19,7 +19,7 @@ Feature: Wordpress code scaffolding When I run `wp scaffold plugin zombieland --activate` Then it should run without errors - When I run `wp path path` + When I run `wp plugin path` Then it should run without errors And save STDOUT as {PLUGIN_PATH} And the {PLUGIN_PATH}/zombieland/zombieland.php file should exist @@ -96,4 +96,4 @@ Feature: Wordpress code scaffolding And STDOUT should contain: """ __( 'Brain eaters' - """ \ No newline at end of file + """ From a00f6056b5f5d995d254be7e5ac83e8448243418 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 22:45:36 +0200 Subject: [PATCH 1656/5359] Split up plugin activation --- features/scaffold.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 2d27a889b..02bf15727 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -12,17 +12,21 @@ Feature: Wordpress code scaffolding And save STDOUT as {THEME_PATH} And the {THEME_PATH}/zombieland/style.css file should exist + # Adding --activate to the test crashes the tests @plugin Scenario: Scaffold a plugin Given a WP install - When I run `wp scaffold plugin zombieland --activate` + When I run `wp scaffold plugin zombieland` Then it should run without errors When I run `wp plugin path` Then it should run without errors And save STDOUT as {PLUGIN_PATH} And the {PLUGIN_PATH}/zombieland/zombieland.php file should exist + + When I run `wp plugin activate zombieland` + Then it should run without errors @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme From ac2272bc83379d5f8a7d3b79fc2f947933b2d576 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 13 May 2013 22:54:23 +0200 Subject: [PATCH 1657/5359] Added plugin_name arg --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 02bf15727..6a1e96d17 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -17,7 +17,7 @@ Feature: Wordpress code scaffolding Scenario: Scaffold a plugin Given a WP install - When I run `wp scaffold plugin zombieland` + When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland"` Then it should run without errors When I run `wp plugin path` From c813d88c11cb89d8a5ecc684403e54e0bf6f83a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 14:08:41 +0300 Subject: [PATCH 1658/5359] behat: reorganize common cpt and tax setup --- features/scaffold.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 6a1e96d17..ed94dc4ec 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -32,12 +32,12 @@ Feature: Wordpress code scaffolding Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install - When I run `wp scaffold taxonomy zombie-speed --theme` - Then it should run without errors - When I run `wp eval 'echo STYLESHEETPATH;'` Then it should run without errors And save STDOUT as {STYLESHEETPATH} + + When I run `wp scaffold taxonomy zombie-speed --theme` + Then it should run without errors And the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist When I run `wp scaffold post-type zombie --theme` From 7d80a1237413cdacb51b65c17e84d8df4f931eac Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 16:14:22 +0300 Subject: [PATCH 1659/5359] behat: remove "it should run without errors" step introduce "try `cmd`" steps. --- features/blog.feature | 35 +++++++++-------------- features/config.feature | 25 ++++++----------- features/core.feature | 35 ++++++++++------------- features/db.feature | 21 +++++--------- features/export.feature | 3 +- features/flags.feature | 26 +++++++---------- features/help.feature | 14 ++++----- features/media.feature | 4 +-- features/plugin.feature | 9 ++---- features/post.feature | 37 +++++++++--------------- features/scaffold.feature | 33 ++++++++-------------- features/search-replace.feature | 3 +- features/shell.feature | 7 ++--- features/steps/basic_steps.php | 50 ++++++++++++++++----------------- features/term.feature | 19 +++++-------- features/theme.feature | 36 +++++++++--------------- features/user.feature | 18 ++++-------- 17 files changed, 143 insertions(+), 232 deletions(-) diff --git a/features/blog.feature b/features/blog.feature index 264dd66d4..14712c444 100644 --- a/features/blog.feature +++ b/features/blog.feature @@ -4,59 +4,50 @@ Feature: Manage a WordPress installation Given a WP install When I run `wp core install-network` - Then it should run without errors + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 Scenario: Delete a blog by id Given a WP multisite install When I run `wp blog create --slug=first --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' And save STDOUT as {BLOG_ID} When I run `wp blog delete {BLOG_ID} --yes` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 Scenario: Delete a blog by slug Given a WP multisite install When I run `wp blog create --slug=first` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp blog delete --slug=first --yes` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 Scenario: Empty a blog Given a WP install When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp blog empty --yes` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp post list --format=ids` - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty When I run `wp term list post_tag --format=ids` - Then it should run without errors - And STDOUT should be empty \ No newline at end of file + Then STDOUT should be empty diff --git a/features/config.feature b/features/config.feature index 9bb174d7d..339319c95 100644 --- a/features/config.feature +++ b/features/config.feature @@ -4,15 +4,13 @@ Feature: Have a config file Given a WP install When I run `wp --info` - Then it should run without errors - And STDOUT should not contain: + Then STDOUT should not contain: """ wp-cli.yml """ When I run `wp core is-installed` from 'wp-content' - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty Scenario: Config file in WP Root Given a WP install @@ -21,15 +19,13 @@ Feature: Have a config file """ When I run `wp --info` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ wp-cli.yml """ When I run `wp core is-installed` - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty Scenario: WP in a subdirectory Given a WP install in 'core' @@ -39,19 +35,16 @@ Feature: Have a config file """ When I run `wp --info` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ wp-cli.yml """ When I run `wp core is-installed` - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty When I run `wp core is-installed` from 'core/wp-content' - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty Scenario: Nested installs Given a WP install @@ -60,8 +53,8 @@ Feature: Have a config file """ """ - When I run `wp info` from 'subsite' - And STDOUT should not contain: + When I run `wp --info` from 'subsite' + Then STDOUT should not contain: """ wp-cli.yml """ diff --git a/features/core.feature b/features/core.feature index 60923299c..7de94acec 100644 --- a/features/core.feature +++ b/features/core.feature @@ -2,21 +2,22 @@ Feature: Manage WordPress installation Scenario: Empty dir Given an empty directory - When I run `wp core is-installed` + + When I try `wp core is-installed` Then the return code should be 1 When I run `wp core download --quiet` - Then it should run without errors - And the wp-settings.php file should exist + Then the wp-settings.php file should exist Scenario: No wp-config.php Given an empty directory And WP files - When I run `wp core is-installed` + When I try `wp core is-installed` Then the return code should be 1 - When I run `wp core install` + When I try `wp core install` + Then the return code should be 1 Then STDERR should be: """ Error: wp-config.php not found. @@ -24,20 +25,19 @@ Feature: Manage WordPress installation """ When I run `wp core config` - Then it should run without errors - And the wp-config.php file should exist + Then the wp-config.php file should exist Scenario: Database doesn't exist Given an empty directory And WP files And wp-config.php - When I run `wp` + When I try `wp` Then the return code should be 1 And STDERR should not be empty When I run `wp db create` - Then it should run without errors + Then STDOUT should not be empty Scenario: Database tables not installed Given an empty directory @@ -45,10 +45,10 @@ Feature: Manage WordPress installation And wp-config.php And a database - When I run `wp core is-installed` + When I try `wp core is-installed` Then the return code should be 1 - When I run `wp` + When I try `wp` Then the return code should be 1 And STDERR should be: """ @@ -57,28 +57,24 @@ Feature: Manage WordPress installation """ When I run `wp core install` - Then the return code should be 0 + Then STDOUT should not be empty When I run `wp core version` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty Scenario: Full install Given a WP install When I run `wp core is-installed` - Then it should run without errors When I run `wp eval 'var_export( is_admin() );'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ true """ When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ true """ @@ -88,4 +84,3 @@ Feature: Manage WordPress installation And a custom wp-content directory When I run `wp plugin status hello` - Then it should run without errors diff --git a/features/db.feature b/features/db.feature index ca3241111..6bef95986 100644 --- a/features/db.feature +++ b/features/db.feature @@ -6,30 +6,25 @@ Feature: Perform database operations And wp-config.php When I run `wp db create` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 When I run `wp db reset --yes` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp db optimize` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp db repair` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty Scenario: DB Query Given a WP install When I run `wp db query 'SELECT COUNT(*) as total FROM wp_posts'` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ total """ @@ -38,10 +33,8 @@ Feature: Perform database operations """ SELECT COUNT(*) as total FROM wp_posts """ - When I run `wp db query < debug.sql` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ total """ diff --git a/features/export.feature b/features/export.feature index 096429833..1194696f9 100644 --- a/features/export.feature +++ b/features/export.feature @@ -4,5 +4,4 @@ Feature: Export content. Given a WP install When I run `wp export` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty diff --git a/features/flags.feature b/features/flags.feature index 39592c33a..95a201a73 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -4,14 +4,12 @@ Feature: Global flags Given a WP install When I run `wp` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp --quiet` - Then it should run without errors - And STDOUT should be empty + Then STDOUT should be empty - When I run `wp non-existing-command --quiet` + When I try `wp non-existing-command --quiet` Then the return code should be 1 And STDERR should be: """ @@ -22,8 +20,7 @@ Feature: Global flags Given a WP install When I run `wp eval 'echo CONST_WITHOUT_QUOTES;'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ CONST_WITHOUT_QUOTES """ @@ -43,20 +40,18 @@ Feature: Global flags Given a WP install When I run `wp eval 'echo (int) is_user_logged_in();'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ 0 """ When I run `wp --user=admin eval 'echo wp_get_current_user()->user_login;'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ admin """ - When I run `wp --user=non-existing-user` + When I try `wp --user=non-existing-user` Then the return code should be 1 And STDERR should be: """ @@ -79,8 +74,7 @@ Feature: Global flags """ When I run `wp --require=custom-cmd.php test req 'This is a custom command.'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ This is a custom command. """ @@ -88,13 +82,13 @@ Feature: Global flags Scenario: Enabling/disabling color Given a WP install - When I run `wp --no-color non-existent-command` + When I try `wp --no-color non-existent-command` Then STDERR should be: """ Error: 'non-existent-command' is not a registered wp command. See 'wp help'. """ - When I run `wp --color non-existent-command` + When I try `wp --color non-existent-command` Then STDERR should contain: """ [31;1mError: diff --git a/features/help.feature b/features/help.feature index 5a410db41..81599f589 100644 --- a/features/help.feature +++ b/features/help.feature @@ -4,28 +4,26 @@ Feature: Get help about WP-CLI commands Given an empty directory When I run `wp help` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Available commands: """ When I run `wp help core` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ usage: wp core """ When I run `wp help core download` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ WP-CORE-DOWNLOAD(1) """ - When I run `wp help non-existent-command` + When I try `wp help non-existent-command` Then the return code should be 1 + And STDERR should not be empty Scenario: Getting help for a third-party command Given a WP install @@ -41,10 +39,8 @@ Feature: Get help about WP-CLI commands WP_CLI::add_command( 'test-help', 'Test_Help' ); """ And I run `wp plugin activate test-cli-help` - And it should run without errors When I run `wp help test-help` - Then it should run without errors And STDOUT should contain: """ usage: wp test-help diff --git a/features/media.feature b/features/media.feature index e7a607cf3..ddb721c48 100644 --- a/features/media.feature +++ b/features/media.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress attachments Scenario: Regenerate all images while none exists Given a WP install - When I run `wp media regenerate --yes` + When I try `wp media regenerate --yes` Then STDERR should contain: """ Error: Unable to find the images @@ -24,7 +24,7 @@ Feature: Manage WordPress attachments Scenario: Fail to import missing image Given a WP install - When I run `wp media import gobbledygook.png` + When I try `wp media import gobbledygook.png` Then STDERR should contain: """ Error: Unable to import file gobbledygook.png. Reason: File is empty. diff --git a/features/plugin.feature b/features/plugin.feature index 66bdb0530..ad9a88520 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -4,18 +4,16 @@ Feature: Manage WordPress plugins Given a WP install When I run `wp plugin status` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp plugin status hello` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Plugin hello details: Name: Hello Dolly """ - When I run `wp plugin status non-existent-plugin` + When I try `wp plugin status non-existent-plugin` Then the return code should be 1 And STDERR should contain: """ @@ -23,5 +21,4 @@ Feature: Manage WordPress plugins """ When I run `wp plugin list --format=json` - Then it should run without errors And STDOUT should not be empty diff --git a/features/post.feature b/features/post.feature index 731184f93..c9e93d630 100644 --- a/features/post.feature +++ b/features/post.feature @@ -4,55 +4,48 @@ Feature: Manage WordPress posts Given a WP install When I run `wp post create --post_title='Test post' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' And save STDOUT as {POST_ID} When I run `wp post update {POST_ID} --post_title='Updated post'` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ Success: Updated post {POST_ID}. """ When I run `wp post delete {POST_ID}` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ Success: Trashed post {POST_ID}. """ When I run the previous command again - Then it should run without errors + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 Scenario: Creating/getting posts Given a WP install When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' And save STDOUT as {POST_ID} When I run `wp post get {POST_ID}` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ Test content. """ When I run `wp post get --format=content {POST_ID}` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ Test content. """ When I run `wp post get --format=table {POST_ID}` - Then it should run without errors - And STDOUT should be a table containing rows: + Then STDOUT should be a table containing rows: """ Field Value ID {POST_ID} @@ -60,8 +53,7 @@ Feature: Manage WordPress posts """ When I run `wp post get --format=json {POST_ID}` - Then it should run without errors - And STDOUT should be JSON containing: + Then STDOUT should be JSON containing: """ {"ID":{POST_ID},"post_title":"Test post","post_content":"Test content."} """ @@ -70,16 +62,13 @@ Feature: Manage WordPress posts Given a WP install When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' When I run `wp post create --post_title='Draft post' --post_content='Draft post content' --post_status='draft' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' When I run `wp post list --post_type='post' --fields=post_title,post_name,post_status --format=csv` - Then it should run without errors - And STDOUT should be CSV containing: + Then STDOUT should be CSV containing: """ post_title,post_name,post_status "Publish post",publish-post,publish diff --git a/features/scaffold.feature b/features/scaffold.feature index ed94dc4ec..c12a3cfee 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -5,11 +5,9 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` - Then it should run without errors When I run `wp theme path` - Then it should run without errors - And save STDOUT as {THEME_PATH} + Then save STDOUT as {THEME_PATH} And the {THEME_PATH}/zombieland/style.css file should exist # Adding --activate to the test crashes the tests @@ -18,31 +16,26 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland"` - Then it should run without errors + Then STDOUT should not be empty When I run `wp plugin path` - Then it should run without errors And save STDOUT as {PLUGIN_PATH} - And the {PLUGIN_PATH}/zombieland/zombieland.php file should exist + Then the {PLUGIN_PATH}/zombieland/zombieland.php file should exist When I run `wp plugin activate zombieland` - Then it should run without errors + Then STDOUT should not be empty @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install - - When I run `wp eval 'echo STYLESHEETPATH;'` - Then it should run without errors + And I run `wp eval 'echo STYLESHEETPATH;'` And save STDOUT as {STYLESHEETPATH} When I run `wp scaffold taxonomy zombie-speed --theme` - Then it should run without errors - And the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist + Then the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist When I run `wp scaffold post-type zombie --theme` - Then it should run without errors - And the {STYLESHEETPATH}/post-types/zombie.php file should exist + Then the {STYLESHEETPATH}/post-types/zombie.php file should exist # Test for all flags but --label, --theme, --plugin and --raw @tax @@ -50,8 +43,7 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie" --textdomain=zombieland` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ __( 'Zombie speeds' """ @@ -69,8 +61,7 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold taxonomy zombie-speed --label="Speed"` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ __( 'Speed' """ @@ -81,8 +72,7 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold post-type zombie --textdomain=zombieland` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ __( 'Zombies' """ @@ -96,8 +86,7 @@ Feature: Wordpress code scaffolding Given a WP install When I run `wp scaffold post-type zombie --label="Brain eater"` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ __( 'Brain eaters' """ diff --git a/features/search-replace.feature b/features/search-replace.feature index 34241c880..30d9ecb78 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -4,5 +4,4 @@ Feature: Do global search/replace Given a WP install When I run `wp search-replace foo bar` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty diff --git a/features/shell.feature b/features/shell.feature index 0ca5aa9a9..ad0f5c52c 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -4,10 +4,9 @@ Feature: WordPress REPL Given a WP install When I run `wp shell < /dev/null` - Then it should run without errors When I run `wp shell --basic < /dev/null` - Then it should run without errors + Then STDOUT should be empty Scenario: Persistent environment Given a WP install @@ -19,8 +18,7 @@ Feature: WordPress REPL """ When I run `wp shell --basic < session` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ bool(false) """ @@ -37,7 +35,6 @@ Feature: WordPress REPL """ When I run `wp shell --basic < session` - Then it should run without errors And STDOUT should be: """ bool(true) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 59cf646b7..c4d373aa3 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -4,6 +4,16 @@ Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; +function invoke_proc( $proc, $mode, $subdir = null ) { + $map = array( + 'run' => 'run_check', + 'try' => 'run' + ); + $method = $map[ $mode ]; + + return $proc->$method( $subdir ); +} + $steps->Given( '/^an empty directory$/', function ( $world ) { $world->create_empty_dir(); @@ -94,30 +104,33 @@ function ( $world ) { } ); -$steps->When( '/^I run `wp`$/', - function ( $world ) { - $world->result = $world->proc( '' )->run(); +$steps->When( '/^I (run|try) `wp`$/', + function ( $world, $mode ) { + $world->result = invoke_proc( $world->proc( '' ), $mode ); } ); -$steps->When( '/^I run `wp (.+)`$/', - function ( $world, $cmd ) { - $world->result = $world->proc( $world->replace_variables( $cmd ) )->run(); +$steps->When( '/^I (run|try) `wp (.+)`$/', + function ( $world, $mode, $cmd ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd ), $mode ); } ); -$steps->When( "/^I run `wp (.+)` from '([^\s]+)'$/", - function ( $world, $cmd, $subdir ) { - $world->result = $world->proc( $world->replace_variables( $cmd ) )->run( $subdir ); +$steps->When( "/^I (run|try) `wp (.+)` from '([^\s]+)'$/", + function ( $world, $mode, $cmd, $subdir ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd ), $mode, $subdir ); } ); -$steps->When( '/^I run the previous command again$/', - function ( $world ) { +$steps->When( '/^I (run|try) the previous command again$/', + function ( $world, $mode ) { if ( !isset( $world->result ) ) throw new \Exception( 'No previous command.' ); - $world->result = Process::create( $world->result->command, $world->result->cwd )->run(); + $proc = Process::create( $world->result->command, $world->result->cwd ); + $world->result = invoke_proc( $proc, $mode ); } ); @@ -142,19 +155,6 @@ function ( $world, $return_code ) { } ); -$steps->Then( '/^it should run without errors$/', - function ( $world ) { - if ( !empty( $world->result->STDERR ) ) { - $r = $world->result; - throw new \Exception( sprintf( "%s: %s\ncwd: %s", - $r->command, $r->STDERR, $r->cwd ) ); - } - - if ( 0 != $world->result->return_code ) - throw new \Exception( "Return code was $world->result->return_code" ); - } -); - $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { $output = $world->result->$stream; diff --git a/features/term.feature b/features/term.feature index 0c6af7e53..7a6442d45 100644 --- a/features/term.feature +++ b/features/term.feature @@ -4,22 +4,19 @@ Feature: Manage WordPress terms Given a WP install When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' - When I run the previous command again + When I try the previous command again Then STDERR should not be empty When I run `wp term list post_tag --format=json` - Then it should run without errors - And STDOUT should be JSON containing: + Then STDOUT should be JSON containing: """ [{"name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] """ When I run `wp term list post_tag --fields=name,slug --format=csv` - Then it should run without errors - And STDOUT should be CSV containing: + Then STDOUT should be CSV containing: """ name,slug "Test term",test @@ -29,16 +26,14 @@ Feature: Manage WordPress terms Given a WP install When I run `wp term create 'Test delete term' post_tag --slug=test-delete --description='This is a test term to be deleted' --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' And save STDOUT as {TERM_ID} When I run `wp term delete {TERM_ID} post_tag` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Deleted post_tag {TERM_ID}. """ - When I run the previous command again + When I try the previous command again Then STDERR should not be empty diff --git a/features/theme.feature b/features/theme.feature index 4424b4404..2991173f8 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -4,43 +4,38 @@ Feature: Manage WordPress themes Given a WP install When I run `wp theme install p2` - Then it should run without errors + Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 When I run `wp theme status p2` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Theme p2 details: Name: P2 """ When I run `wp theme path p2` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ /themes/p2/style.css """ When I run `wp option get stylesheet` - Then it should run without errors - And save STDOUT as {PREVIOUS_THEME} + Then save STDOUT as {PREVIOUS_THEME} When I run `wp theme activate p2` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Success: Switched to 'P2' theme. """ When I run `wp theme activate {PREVIOUS_THEME}` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty When I run `wp theme delete p2` - Then it should run without errors + Then STDOUT should not be empty When I run the previous command again Then the return code should be 1 @@ -50,36 +45,31 @@ Feature: Manage WordPress themes """ When I run `wp theme list` - Then it should run without errors - And STDOUT should not be empty + Then STDOUT should not be empty Scenario: Upgrading a theme Given a WP install And a P2 theme zip When I run `wp theme install {THEME_ZIP}` - Then it should run without errors + Then STDOUT should not be empty When I run `wp theme status` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ U = Update Available """ When I run `wp theme status p2` - Then it should run without errors - And STDOUT should contain: + Then STDOUT should contain: """ Version: 1.0.1 (Update available) """ When I run `wp theme update p2` - Then it should run without errors When I run `wp theme status p2` - Then it should run without errors - And STDOUT should not contain: + Then STDOUT should not contain: """ (Update available) """ diff --git a/features/user.feature b/features/user.feature index 627a684a2..5370006d9 100644 --- a/features/user.feature +++ b/features/user.feature @@ -4,22 +4,19 @@ Feature: Manage WordPress users Given a WP install When I run `wp user create testuser testuser@example.com --porcelain` - Then it should run without errors - And STDOUT should match '%d' + Then STDOUT should match '%d' And save STDOUT as {USER_ID} - When I run the previous command again + When I try the previous command again Then the return code should be 1 When I run `wp user update {USER_ID} --displayname=Foo` - Then it should run without errors - And STDOUT should be: + Then STDOUT should be: """ Success: Updated user {USER_ID}. """ When I run `wp user delete {USER_ID}` - Then it should run without errors Scenario: Generating users Given a WP install @@ -28,12 +25,10 @@ Feature: Manage WordPress users When I run `wp user list --format=ids` And save STDOUT as {USER_IDS} And I run `wp user delete {USER_IDS}` - When I run `wp user list --format=ids` - Then it should run without errors - And STDOUT should be empty + And I run `wp user list --format=ids` + Then STDOUT should be empty When I run `wp user generate --count=10` - Then it should run without errors When I run `wp user list | wc -l | tr -d ' '` Then STDOUT should be: @@ -52,7 +47,7 @@ Feature: Manage WordPress users """ When I run `wp user import-csv users.csv` - Then it should run without errors + Then STDOUT should not be empty When I run `wp user list | wc -l | tr -d ' '` Then STDOUT should be: @@ -61,7 +56,6 @@ Feature: Manage WordPress users """ When I run `wp user list --format=json` - Then it should run without errors And STDOUT should be JSON containing: """ [{"user_login":"admin","display_name":"Existing User","user_email":"admin@domain.com","roles":"administrator"}] From 54753392104e6114a2f3d9babbfe34b0de00d480 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 16:28:41 +0300 Subject: [PATCH 1660/5359] add success message for `wp theme delete` --- php/commands/theme.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 441b2a3a2..3b0a5c6f7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -195,6 +195,8 @@ function delete( $args ) { if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); } + + WP_CLI::success( "$theme->name theme deleted." ); } /** @@ -204,7 +206,7 @@ function delete( $args ) { * @synopsis [--format=<format>] */ function _list( $_, $assoc_args ) { - parent::_list( $_, $assoc_args ); + parent::_list( $_, $assoc_args ); } protected function parse_name( $args ) { From 1611e1885f38ff7715f86fa664268b5acfa5e743 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 21:55:03 +0300 Subject: [PATCH 1661/5359] don't create a new test dir if one already exists this allows having nested WP installs --- features/bootstrap/FeatureContext.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 699f6c56b..b48d8f7ff 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -101,8 +101,10 @@ private function _replace_var( $matches ) { } public function create_empty_dir() { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); - mkdir( $this->install_dir ); + if ( !$this->install_dir ) { + $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + mkdir( $this->install_dir ); + } } public function get_path( $file ) { From 93afe56e211958f70e52712e3c09840b4f145814 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 22:14:42 +0300 Subject: [PATCH 1662/5359] behat: fix theme test --- features/theme.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index 2991173f8..3870379d1 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -37,7 +37,7 @@ Feature: Manage WordPress themes When I run `wp theme delete p2` Then STDOUT should not be empty - When I run the previous command again + When I try the previous command again Then the return code should be 1 And STDERR should contain: """ From 687f52b7dddf9dcab0c52f25100ace46bea99736 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 23:35:46 +0300 Subject: [PATCH 1663/5359] behat: misc fixes --- features/help.feature | 2 +- features/shell.feature | 2 +- features/theme.feature | 1 + features/user.feature | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/help.feature b/features/help.feature index 81599f589..f82b0c7cf 100644 --- a/features/help.feature +++ b/features/help.feature @@ -41,7 +41,7 @@ Feature: Get help about WP-CLI commands And I run `wp plugin activate test-cli-help` When I run `wp help test-help` - And STDOUT should contain: + Then STDOUT should contain: """ usage: wp test-help """ diff --git a/features/shell.feature b/features/shell.feature index ad0f5c52c..1e855ae7f 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -35,7 +35,7 @@ Feature: WordPress REPL """ When I run `wp shell --basic < session` - And STDOUT should be: + Then STDOUT should be: """ bool(true) """ diff --git a/features/theme.feature b/features/theme.feature index 3870379d1..db3804ebb 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -67,6 +67,7 @@ Feature: Manage WordPress themes """ When I run `wp theme update p2` + Then STDOUT should not be empty When I run `wp theme status p2` Then STDOUT should not contain: diff --git a/features/user.feature b/features/user.feature index 5370006d9..1e8131e58 100644 --- a/features/user.feature +++ b/features/user.feature @@ -17,6 +17,7 @@ Feature: Manage WordPress users """ When I run `wp user delete {USER_ID}` + Then STDOUT should not be empty Scenario: Generating users Given a WP install @@ -29,6 +30,7 @@ Feature: Manage WordPress users Then STDOUT should be empty When I run `wp user generate --count=10` + Then STDOUT should not be empty When I run `wp user list | wc -l | tr -d ' '` Then STDOUT should be: @@ -56,7 +58,7 @@ Feature: Manage WordPress users """ When I run `wp user list --format=json` - And STDOUT should be JSON containing: + Then STDOUT should be JSON containing: """ [{"user_login":"admin","display_name":"Existing User","user_email":"admin@domain.com","roles":"administrator"}] """ From 7253f7fcb3e7540f754125e225e5129aacabde91 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 23:44:07 +0300 Subject: [PATCH 1664/5359] behat: move theme dir acquiring to the 'Given' block --- features/scaffold.feature | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index c12a3cfee..6b51ae80a 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -3,12 +3,12 @@ Feature: Wordpress code scaffolding @theme Scenario: Scaffold a child theme Given a WP install + And I run `wp theme path` + And save STDOUT as {THEME_DIR} - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` - - When I run `wp theme path` - Then save STDOUT as {THEME_PATH} - And the {THEME_PATH}/zombieland/style.css file should exist + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` + Then STDOUT should not be empty + And the {THEME_DIR}/zombieland/style.css file should exist # Adding --activate to the test crashes the tests @plugin @@ -17,14 +17,14 @@ Feature: Wordpress code scaffolding When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland"` Then STDOUT should not be empty - + When I run `wp plugin path` And save STDOUT as {PLUGIN_PATH} Then the {PLUGIN_PATH}/zombieland/zombieland.php file should exist When I run `wp plugin activate zombieland` Then STDOUT should not be empty - + @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install From 00e0bd2034fdce799899509a6dd83097fd38c5ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 23:46:09 +0300 Subject: [PATCH 1665/5359] behat: more misc fixes --- features/core.feature | 1 + features/plugin.feature | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 7de94acec..4accc60b3 100644 --- a/features/core.feature +++ b/features/core.feature @@ -84,3 +84,4 @@ Feature: Manage WordPress installation And a custom wp-content directory When I run `wp plugin status hello` + Then STDOUT should not be empty diff --git a/features/plugin.feature b/features/plugin.feature index ad9a88520..b1093e2f8 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -21,4 +21,4 @@ Feature: Manage WordPress plugins """ When I run `wp plugin list --format=json` - And STDOUT should not be empty + Then STDOUT should not be empty From 147d5b37b23ded49020694ffc5004368166e7291 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 May 2013 23:59:55 +0300 Subject: [PATCH 1666/5359] behat: move plugin dir acquiring to the 'Given' block --- features/scaffold.feature | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 6b51ae80a..e2cc2b4e8 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -14,13 +14,12 @@ Feature: Wordpress code scaffolding @plugin Scenario: Scaffold a plugin Given a WP install + And I run `wp plugin path` + And save STDOUT as {PLUGIN_DIR} When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland"` Then STDOUT should not be empty - - When I run `wp plugin path` - And save STDOUT as {PLUGIN_PATH} - Then the {PLUGIN_PATH}/zombieland/zombieland.php file should exist + And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist When I run `wp plugin activate zombieland` Then STDOUT should not be empty From 4e436222a11efc1b492fa0c56791aa55e687f4c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 15 May 2013 00:11:50 +0300 Subject: [PATCH 1667/5359] try the --activate flag for `wp scaffold plugin` one more time --- features/scaffold.feature | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index e2cc2b4e8..c638f6c14 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -10,14 +10,13 @@ Feature: Wordpress code scaffolding Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist - # Adding --activate to the test crashes the tests @plugin Scenario: Scaffold a plugin Given a WP install And I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} - When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland"` + When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland" --activate` Then STDOUT should not be empty And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist From e74d250da7412669a2c4dcf6b9837ab3229cbdd9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 16:38:13 +0300 Subject: [PATCH 1668/5359] travis: make Behat output less verbose --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7225c6eaa..622e25b65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_script: - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot -script: vendor/bin/phpunit && vendor/bin/behat +script: vendor/bin/phpunit && vendor/bin/behat --format progress notifications: email: From 3c10db3147990c4ea9e81446693481799040a7ef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 16:31:23 +0300 Subject: [PATCH 1669/5359] test wp core download --locale --- features/core.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/core.feature b/features/core.feature index 4accc60b3..b9497e37e 100644 --- a/features/core.feature +++ b/features/core.feature @@ -1,5 +1,6 @@ Feature: Manage WordPress installation + @download Scenario: Empty dir Given an empty directory @@ -9,6 +10,12 @@ Feature: Manage WordPress installation When I run `wp core download --quiet` Then the wp-settings.php file should exist + @download + Scenario: Localized install + Given an empty directory + When I run `wp core download --locale=de_DE` + Then the wp-settings.php file should exist + Scenario: No wp-config.php Given an empty directory And WP files From 3fbef8ba71eb62a8e37b8b5d874e1cc351c57c6f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 17:13:40 +0300 Subject: [PATCH 1670/5359] core download: update to /version-check/1.6/ --- php/commands/core.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3c3724abb..24ce49d44 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -24,10 +24,10 @@ public function download( $args, $assoc_args ) { } if ( isset( $assoc_args['locale'] ) ) { - exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.5/?locale=' . $assoc_args['locale'] ), $lines, $r ); - if ($r) exit($r); - $download_url = str_replace( '.zip', '.tar.gz', $lines[2] ); - WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $lines[3], $lines[4] ) ); + $offer = $this->get_download_offer( $assoc_args['locale'] ); + $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); + WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', + $offer['current'], $offer['locale'] ) ); } elseif ( isset( $assoc_args['version'] ) ) { $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); @@ -44,6 +44,14 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } + private function get_download_offer( $locale ) { + $out = exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ), $lines, $r ); + if ($r) exit($r); + + $out = unserialize( $out ); + return $out['offers'][0]; + } + /** * Set up a wp-config.php file. * From 670d641fd0cbdf92f97b13d7ac62abafb377912b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 18:28:56 +0300 Subject: [PATCH 1671/5359] post get: default to table format. see #399 --- features/post.feature | 6 ------ php/commands/post.php | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/features/post.feature b/features/post.feature index c9e93d630..499224754 100644 --- a/features/post.feature +++ b/features/post.feature @@ -32,12 +32,6 @@ Feature: Manage WordPress posts Then STDOUT should match '%d' And save STDOUT as {POST_ID} - When I run `wp post get {POST_ID}` - Then STDOUT should be: - """ - Test content. - """ - When I run `wp post get --format=content {POST_ID}` Then STDOUT should be: """ diff --git a/php/commands/post.php b/php/commands/post.php index 7952a8b73..b2b5199a2 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -93,7 +93,7 @@ protected function _edit( $content, $title ) { */ public function get( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( - 'format' => 'content' + 'format' => 'table' ) ); $format = $assoc_args['format']; From e79a132eed734a4d63adbd807ed910c291a8183b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 18:35:43 +0300 Subject: [PATCH 1672/5359] transparently convert from --json to --format=json --- man-src/option.txt | 4 ++-- man-src/post-meta.txt | 2 +- man-src/rewrite-dump.txt | 2 +- man-src/user-meta.txt | 2 +- php/WP_CLI/Runner.php | 21 ++++++++++++++++----- php/class-wp-cli.php | 4 ++-- php/commands/post.php | 5 ++--- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/man-src/option.txt b/man-src/option.txt index 423e81669..99c8aab05 100644 --- a/man-src/option.txt +++ b/man-src/option.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `--json`: +* `--format=json`: Encode/decode values as JSON. @@ -10,6 +10,6 @@ wp option add my_option foobar - wp option update my_option '{"foo": "bar"}' --json + wp option update my_option '{"foo": "bar"}' --format=json wp option delete my_option diff --git a/man-src/post-meta.txt b/man-src/post-meta.txt index 974a2bd7b..eeadc606f 100644 --- a/man-src/post-meta.txt +++ b/man-src/post-meta.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `--json`: +* `--format=json`: Encode/decode values as JSON. diff --git a/man-src/rewrite-dump.txt b/man-src/rewrite-dump.txt index 26498dbca..f15473d02 100644 --- a/man-src/rewrite-dump.txt +++ b/man-src/rewrite-dump.txt @@ -1,5 +1,5 @@ ## OPTIONS -* `--json`: +* `--format=json`: Output rules in JSON format. diff --git a/man-src/user-meta.txt b/man-src/user-meta.txt index 9db91bbf1..94d507cc5 100644 --- a/man-src/user-meta.txt +++ b/man-src/user-meta.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `--json`: +* `--format=json`: Encode/decode values as JSON. diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 981716dc1..4c5cabe3b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -210,11 +210,8 @@ private static function show_help_early( $args ) { return false; } - public function before_wp_load() { - $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); - - list( $this->arguments, $this->assoc_args ) = $r; - + // Transparently convert old syntaxes + private function back_compat_conversions() { // foo --help -> help foo if ( isset( $this->assoc_args['help'] ) ) { array_unshift( $this->arguments, 'help' ); @@ -239,6 +236,20 @@ public function before_wp_load() { unset( $this->assoc_args['ids'] ); } + // --json -> --format=json + if ( isset( $this->assoc_args['json'] ) ) { + $this->assoc_args['format'] = 'json'; + unset( $this->assoc_args['ids'] ); + } + } + + public function before_wp_load() { + $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); + + list( $this->arguments, $this->assoc_args ) = $r; + + $this->back_compat_conversions(); + $config_spec = Utils\get_config_spec(); // Set the path default to the ABSPATH diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e3855a7ce..320cb5031 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -169,7 +169,7 @@ static function confirm( $question, $assoc_args ) { * @param array $assoc_args */ static function read_value( $value, $assoc_args = array() ) { - if ( isset( $assoc_args['json'] ) ) { + if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { $value = json_decode( $value, true ); } @@ -183,7 +183,7 @@ static function read_value( $value, $assoc_args = array() ) { * @param array $assoc_args */ static function print_value( $value, $assoc_args = array() ) { - if ( isset( $assoc_args['json'] ) ) { + if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { $value = json_encode( $value ); } elseif ( is_array( $value ) || is_object( $value ) ) { $value = var_export( $value ); diff --git a/php/commands/post.php b/php/commands/post.php index b2b5199a2..b895a78d9 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -104,7 +104,7 @@ public function get( $args, $assoc_args ) { switch ( $assoc_args['format'] ) { case 'content': - echo($post->post_content); + WP_CLI::print_value( $post->post_content ); break; case 'table': @@ -127,8 +127,7 @@ public function get( $args, $assoc_args ) { break; case 'json': - echo( json_encode( $post ) ); - echo( "\n" ); + WP_CLI::print_value( $post, $assoc_args ); break; default: From 51186ddd9c75347b452e2be176866bbbaf80263d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 19:04:42 +0300 Subject: [PATCH 1673/5359] option: add tests --- features/option.feature | 28 ++++++++++++++++++++++++++++ php/commands/option.php | 6 +++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 features/option.feature diff --git a/features/option.feature b/features/option.feature new file mode 100644 index 000000000..0ab33e815 --- /dev/null +++ b/features/option.feature @@ -0,0 +1,28 @@ +Feature: Manage WordPress options + + Scenario: Option CRUD + Given a WP install + + When I run `wp option add foo 'bar'` + Then STDOUT should be empty + + When I run `wp option get foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp option set foo '[ 1, 2 ]' --format=json` + Then STDOUT should be empty + + When I run `wp option get foo --format=json` + Then STDOUT should be: + """ + [1,2] + """ + + When I run `wp option delete foo` + Then STDOUT should be empty + + When I try `wp option get foo` + Then the return code should be 1 diff --git a/php/commands/option.php b/php/commands/option.php index 525a89a36..361a1f73b 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -10,7 +10,7 @@ class Option_Command extends WP_CLI_Command { /** * Get an option. * - * @synopsis <key> [--json] + * @synopsis <key> [--format=<format>] */ public function get( $args, $assoc_args ) { list( $key ) = $args; @@ -26,7 +26,7 @@ public function get( $args, $assoc_args ) { /** * Add an option. * - * @synopsis <key> <value> [--json] + * @synopsis <key> [--format=<format>] */ public function add( $args, $assoc_args ) { $key = $args[0]; @@ -42,7 +42,7 @@ public function add( $args, $assoc_args ) { * Update an option. * * @alias set - * @synopsis <key> <value> [--json] + * @synopsis <key> [--format=<format>] */ public function update( $args, $assoc_args ) { $key = $args[0]; From 49997f835585e04d44282961bb273cd9cfed6539 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 May 2013 19:16:57 +0300 Subject: [PATCH 1674/5359] post-meta: add tests --- features/post-meta.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 features/post-meta.feature diff --git a/features/post-meta.feature b/features/post-meta.feature new file mode 100644 index 000000000..0b7ac02d5 --- /dev/null +++ b/features/post-meta.feature @@ -0,0 +1,28 @@ +Feature: Manage post custom fields + + Scenario: Postmeta CRUD + Given a WP install + + When I run `wp post-meta add 1 foo 'bar'` + Then STDOUT should be empty + + When I run `wp post-meta get 1 foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp post-meta set 1 foo '[ 1, 2 ]' --format=json` + Then STDOUT should be empty + + When I run `wp post-meta get 1 foo --format=json` + Then STDOUT should be: + """ + [1,2] + """ + + When I run `wp post-meta delete 1 foo` + Then STDOUT should be empty + + When I try `wp post-meta get 1 foo` + Then the return code should be 1 From 60822fedc670e70337f33825009a90d0fc418250 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 19:40:31 +0300 Subject: [PATCH 1675/5359] add --format parameter to meta get and update --- php/WP_CLI/CommandWithMeta.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 3ec480e14..6695d1e51 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -14,7 +14,7 @@ abstract class CommandWithMeta extends \WP_CLI_Command { /** * Get meta field value. * - * @synopsis <id> <key> [--json] + * @synopsis <id> <key> [--format=<format>] */ public function get( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; @@ -47,10 +47,12 @@ public function delete( $args, $assoc_args ) { /** * Add a meta field. * - * @synopsis <id> <key> <value> + * @synopsis <id> <key> <value> [--format=<format>] */ public function add( $args, $assoc_args ) { - list( $object_id, $meta_key, $meta_value ) = $args; + list( $object_id, $meta_key ) = $args; + + $meta_value = \WP_CLI::read_value( $args[2], $assoc_args ); $success = \add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); @@ -65,10 +67,12 @@ public function add( $args, $assoc_args ) { * Update a meta field. * * @alias set - * @synopsis <id> <key> <value> + * @synopsis <id> <key> <value> [--format=<format>] */ public function update( $args, $assoc_args ) { - list( $object_id, $meta_key, $meta_value ) = $args; + list( $object_id, $meta_key ) = $args; + + $meta_value = \WP_CLI::read_value( $args[2], $assoc_args ); $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); From dea3de8c207b82f831e2a97724323e0f15122ecb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 19:52:23 +0300 Subject: [PATCH 1676/5359] save parent class in Subcommand ReflectionMethod only stores the name of the original class, which might be abstract. --- php/WP_CLI/Dispatcher/Subcommand.php | 7 ++++--- php/class-wp-cli.php | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 8c6191419..91dfcbf54 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -4,9 +4,10 @@ class Subcommand implements Command, AtomicCommand, Documentable { - private $parent, $name, $method, $docparser; + private $parent, $name, $class, $method, $docparser; - function __construct( CommandContainer $parent, \ReflectionMethod $method, $name = false ) { + function __construct( CommandContainer $parent, $class, \ReflectionMethod $method, $name = false ) { + $this->class = $class; $docparser = new \WP_CLI\DocParser( $method ); if ( !$name ) @@ -99,7 +100,7 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { $this->validate_args( $args, $assoc_args ); - $instance = new $this->method->class; + $instance = new $this->class; call_user_func( array( $instance, $this->method->name ), $args, $assoc_args ); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 320cb5031..a711d4d0a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -40,7 +40,7 @@ static function add_command( $name, $class ) { $reflection = new \ReflectionClass( $class ); if ( $reflection->hasMethod( '__invoke' ) ) { - $command = new Dispatcher\Subcommand( self::$root, + $command = new Dispatcher\Subcommand( self::$root, $reflection->name, $reflection->getMethod( '__invoke' ), $name ); } else { $command = self::create_composite_command( $name, $reflection ); @@ -58,7 +58,7 @@ private static function create_composite_command( $name, $reflection ) { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new Dispatcher\Subcommand( $container, $method ); + $subcommand = new Dispatcher\Subcommand( $container, $reflection->name, $method ); $subcommand_name = $subcommand->get_name(); $full_name = self::get_full_name( $subcommand ); From c92524ffc5300ddc92b7cea9aca2ca933be743bf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 19:57:52 +0300 Subject: [PATCH 1677/5359] unlike `wp option`, `wp post-meta` outputs confirmation messages --- features/post-meta.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 0b7ac02d5..664417b4f 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -4,7 +4,7 @@ Feature: Manage post custom fields Given a WP install When I run `wp post-meta add 1 foo 'bar'` - Then STDOUT should be empty + Then STDOUT should not be empty When I run `wp post-meta get 1 foo` Then STDOUT should be: @@ -13,7 +13,7 @@ Feature: Manage post custom fields """ When I run `wp post-meta set 1 foo '[ 1, 2 ]' --format=json` - Then STDOUT should be empty + Then STDOUT should not be empty When I run `wp post-meta get 1 foo --format=json` Then STDOUT should be: @@ -22,7 +22,7 @@ Feature: Manage post custom fields """ When I run `wp post-meta delete 1 foo` - Then STDOUT should be empty + Then STDOUT should not be empty When I try `wp post-meta get 1 foo` Then the return code should be 1 From 8e176d75358f9f2907390ae136d49708adfacab8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 21:06:55 +0300 Subject: [PATCH 1678/5359] behat: work around bug in WP 3.4.2 related to serializing custom fields --- features/post-meta.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 664417b4f..5c3ecd116 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -12,13 +12,13 @@ Feature: Manage post custom fields bar """ - When I run `wp post-meta set 1 foo '[ 1, 2 ]' --format=json` + When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty When I run `wp post-meta get 1 foo --format=json` Then STDOUT should be: """ - [1,2] + ["1","2"] """ When I run `wp post-meta delete 1 foo` From 7046dcc76a1135eb79e01cf1b430362337a993c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 21:07:11 +0300 Subject: [PATCH 1679/5359] behat: formatting fixes --- features/steps/basic_steps.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index c4d373aa3..d5432db90 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -215,21 +215,18 @@ function ( $world, PyStringNode $expected ) { $steps->Then( '/^STDOUT should be JSON containing:$/', function ( $world, PyStringNode $expected ) { - $output = $world->result->STDOUT; - - $expected = $world->replace_variables( (string) $expected ); + $output = $world->result->STDOUT; + $expected = $world->replace_variables( (string) $expected ); - if ( !checkThatJsonStringContainsJsonString( $output, - $expected ) ) { + if ( !checkThatJsonStringContainsJsonString( $output, $expected ) ) { throw new \Exception( $output ); } }); $steps->Then( '/^STDOUT should be CSV containing:$/', function( $world, PyStringNode $expected ) { - - $output = $world->result->STDOUT; - $expected = $world->replace_variables( (string) $expected ); + $output = $world->result->STDOUT; + $expected = $world->replace_variables( (string) $expected ); if ( ! checkThatCsvStringContainsCsvString( $output, $expected ) ) throw new \Exception( $output ); From b8f624737690f0ea97b25867c10903a49747b846 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 21:08:39 +0300 Subject: [PATCH 1680/5359] user-meta: add tests --- features/user-meta.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 features/user-meta.feature diff --git a/features/user-meta.feature b/features/user-meta.feature new file mode 100644 index 000000000..945237153 --- /dev/null +++ b/features/user-meta.feature @@ -0,0 +1,28 @@ +Feature: Manage user custom fields + + Scenario: Usermeta CRUD + Given a WP install + + When I run `wp user-meta add 1 foo 'bar'` + Then STDOUT should not be empty + + When I run `wp user-meta get 1 foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` + Then STDOUT should not be empty + + When I run `wp user-meta get 1 foo --format=json` + Then STDOUT should be: + """ + ["1","2"] + """ + + When I run `wp user-meta delete 1 foo` + Then STDOUT should not be empty + + When I try `wp user-meta get 1 foo` + Then the return code should be 1 From a38cf376dc4fa1912e3146d27dc91903dd143f81 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 21:21:09 +0300 Subject: [PATCH 1681/5359] re-generate man pages [ci skip] --- man/option.1 | 10 +++++----- man/post-meta.1 | 8 ++++---- man/rewrite-dump.1 | 2 +- man/scaffold-post-type.1 | 2 +- man/scaffold-taxonomy.1 | 2 +- man/user-meta.1 | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/man/option.1 b/man/option.1 index 531d1c2c8..bfb8105b8 100644 --- a/man/option.1 +++ b/man/option.1 @@ -7,13 +7,13 @@ \fBwp\-option\fR \- Manage WordPress options\. . .SH "SYNOPSIS" -wp option get \fIkey\fR [\-\-json] +wp option get \fIkey\fR [\-\-format=\fIformat\fR] . .P -wp option add \fIkey\fR \fIvalue\fR [\-\-json] +wp option add \fIkey\fR [\-\-format=\fIformat\fR] . .P -wp option update \fIkey\fR \fIvalue\fR [\-\-json] +wp option update \fIkey\fR [\-\-format=\fIformat\fR] . .P wp option delete \fIkey\fR @@ -48,7 +48,7 @@ Update an option\. . .TP -\fB\-\-json\fR: +\fB\-\-format=json\fR: . .IP Encode/decode values as JSON\. @@ -61,7 +61,7 @@ wp option get siteurl wp option add my_option foobar -wp option update my_option \'{"foo": "bar"}\' \-\-json +wp option update my_option \'{"foo": "bar"}\' \-\-format=json wp option delete my_option . diff --git a/man/post-meta.1 b/man/post-meta.1 index 3a2cd2040..b806b334d 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -7,16 +7,16 @@ \fBwp\-post\-meta\fR \- Manage post custom fields\. . .SH "SYNOPSIS" -wp post\-meta get \fIid\fR \fIkey\fR [\-\-json] +wp post\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] . .P wp post\-meta delete \fIid\fR \fIkey\fR . .P -wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR +wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .P -wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR +wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .SH "SUBCOMMANDS" . @@ -48,7 +48,7 @@ Update a meta field\. . .TP -\fB\-\-json\fR: +\fB\-\-format=json\fR: . .IP Encode/decode values as JSON\. diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 index 932d8691a..a5e9c33d3 100644 --- a/man/rewrite-dump.1 +++ b/man/rewrite-dump.1 @@ -12,7 +12,7 @@ wp rewrite dump [\-\-json] .SH "OPTIONS" . .TP -\fB\-\-json\fR: +\fB\-\-format=json\fR: . .IP Output rules in JSON format\. diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 index 1fc921d04..5d07b487b 100644 --- a/man/scaffold-post-type.1 +++ b/man/scaffold-post-type.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. . .SH "SYNOPSIS" -wp scaffold post\-type \fIslug\fR [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-label=\fIlabel\fR] [\-\-raw] +wp scaffold post\-type \fIslug\fR [\-\-label=\fIlabel\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index 10f5b5e64..a61470a2d 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -7,7 +7,7 @@ \fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. . .SH "SYNOPSIS" -wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-label=\fIlabel\fR] [\-\-raw] +wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-label=\fIlabel\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] . .SH "OPTIONS" . diff --git a/man/user-meta.1 b/man/user-meta.1 index b88a027f4..883b2923b 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -7,16 +7,16 @@ \fBwp\-user\-meta\fR \- Manage user custom fields\. . .SH "SYNOPSIS" -wp user\-meta get \fIid\fR \fIkey\fR [\-\-json] +wp user\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] . .P wp user\-meta delete \fIid\fR \fIkey\fR . .P -wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR +wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .P -wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR +wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .SH "SUBCOMMANDS" . @@ -48,7 +48,7 @@ Update a meta field\. . .TP -\fB\-\-json\fR: +\fB\-\-format=json\fR: . .IP Encode/decode values as JSON\. From 6b3b6ca8bbe9961915f6b5e56405fdab5d864d9e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 21:23:25 +0300 Subject: [PATCH 1682/5359] unset 'json' key, not 'ids' --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4c5cabe3b..2de3bb6f6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -239,7 +239,7 @@ private function back_compat_conversions() { // --json -> --format=json if ( isset( $this->assoc_args['json'] ) ) { $this->assoc_args['format'] = 'json'; - unset( $this->assoc_args['ids'] ); + unset( $this->assoc_args['json'] ); } } From 8448a661073f8091888b99a4e429bdfdd2960f8e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 22:06:20 +0300 Subject: [PATCH 1683/5359] behat: remove temp files for scenarios that don't have failing steps --- features/bootstrap/FeatureContext.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b48d8f7ff..76d2343db 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -68,6 +68,18 @@ public static function prepare( SuiteEvent $event ) { ); } + /** + * @AfterScenario + */ + public function afterScenario( $event ) { + if ( !$this->install_dir ) + return; + + if ( $event->getResult() < 4 ) { + Process::create( Utils\esc_cmd( 'rm -r %s', $this->install_dir ) )->run(); + } + } + /** * Initializes context. * Every scenario gets it's own context object. From 097c6383095a253122dd696d0cfe9532ec3b1d71 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 22:22:10 +0300 Subject: [PATCH 1684/5359] rename InternalAssoc to InternalFlags 'flags' is more descriptive than 'assoc' --- .../{InternalAssoc.php => InternalFlags.php} | 2 +- php/WP_CLI/Runner.php | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) rename php/WP_CLI/{InternalAssoc.php => InternalFlags.php} (98%) diff --git a/php/WP_CLI/InternalAssoc.php b/php/WP_CLI/InternalFlags.php similarity index 98% rename from php/WP_CLI/InternalAssoc.php rename to php/WP_CLI/InternalFlags.php index 661d282f4..87cabf372 100644 --- a/php/WP_CLI/InternalAssoc.php +++ b/php/WP_CLI/InternalFlags.php @@ -6,7 +6,7 @@ /** * Class that handles special assoc parameters */ -class InternalAssoc { +class InternalFlags { static function version() { WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2de3bb6f6..ff428c38d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -273,25 +273,25 @@ public function before_wp_load() { // Handle --version parameter if ( isset( $this->assoc_args['version'] ) && empty( $this->arguments ) ) { - \WP_CLI\InternalAssoc::version(); + \WP_CLI\InternalFlags::version(); exit; } // Handle --info parameter if ( isset( $this->assoc_args['info'] ) && empty( $this->arguments ) ) { - \WP_CLI\InternalAssoc::info(); + \WP_CLI\InternalFlags::info(); exit; } // Handle --param-dump parameter if ( isset( $this->assoc_args['param-dump'] ) ) { - \WP_CLI\InternalAssoc::param_dump(); + \WP_CLI\InternalFlags::param_dump(); exit; } // Handle --cmd-dump parameter if ( isset( $this->assoc_args['cmd-dump'] ) ) { - \WP_CLI\InternalAssoc::cmd_dump(); + \WP_CLI\InternalFlags::cmd_dump(); exit; } @@ -304,7 +304,7 @@ public function before_wp_load() { } } - // Handle --path + // Handle --path parameter self::set_wp_root( $this->config ); // Handle --url and --blog parameters @@ -358,13 +358,15 @@ public function after_wp_load() { if ( isset( $this->config['require'] ) ) require $this->config['require']; + // Handle --man parameter if ( isset( $this->assoc_args['man'] ) ) { - \WP_CLI\InternalAssoc::man( $this->arguments ); + \WP_CLI\InternalFlags::man( $this->arguments ); exit; } + // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { - \WP_CLI\InternalAssoc::completions(); + \WP_CLI\InternalFlags::completions(); exit; } From f266205b63a4378fedc0af65a8a54dffd4987486 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 22:29:07 +0300 Subject: [PATCH 1685/5359] move --man handling to _run_command() so that `wp db --man` works --- php/WP_CLI/Runner.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ff428c38d..3ae1b5ed3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -163,6 +163,12 @@ private function cmd_starts_with( $prefix ) { } private function _run_command() { + // Handle --man parameter + if ( isset( $this->assoc_args['man'] ) ) { + \WP_CLI\InternalFlags::man( $this->arguments ); + exit; + } + WP_CLI::run_command( $this->arguments, $this->assoc_args ); } @@ -358,12 +364,6 @@ public function after_wp_load() { if ( isset( $this->config['require'] ) ) require $this->config['require']; - // Handle --man parameter - if ( isset( $this->assoc_args['man'] ) ) { - \WP_CLI\InternalFlags::man( $this->arguments ); - exit; - } - // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { \WP_CLI\InternalFlags::completions(); From a07b8e17cfc2e89f55f1d06d5e93b47228155754 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 22:51:30 +0300 Subject: [PATCH 1686/5359] reduce code duplication by merging show_help_early() into Help_Command --- php/WP_CLI/Runner.php | 18 +----------------- php/commands/help.php | 14 ++++++++++---- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3ae1b5ed3..106fc6479 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -202,20 +202,6 @@ public function get_wp_config_code() { return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); } - private static function show_help_early( $args ) { - if ( \WP_CLI\Man\maybe_show_manpage( $args ) ) - return true; - - $command = WP_CLI\Utils\find_subcommand( $args ); - - if ( $command ) { - $command->show_usage(); - return true; - } - - return false; - } - // Transparently convert old syntaxes private function back_compat_conversions() { // foo --help -> help foo @@ -305,9 +291,7 @@ public function before_wp_load() { // First try at showing man page if ( $this->cmd_starts_with( array( 'help' ) ) ) { - if ( self::show_help_early( array_slice( $this->arguments, 1 ) ) ) { - exit; - } + $this->_run_command(); } // Handle --path parameter diff --git a/php/commands/help.php b/php/commands/help.php index 55050bb99..0afaea742 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -10,15 +10,21 @@ class Help_Command extends WP_CLI_Command { * @synopsis [<command>] */ function __invoke( $args ) { - \WP_CLI\Man\maybe_show_manpage( $args ); + if ( \WP_CLI\Man\maybe_show_manpage( $args ) ) { + exit; + } $command = WP_CLI\Utils\find_subcommand( $args ); - if ( !$command ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + if ( $command ) { + $command->show_usage(); + exit; } - $command->show_usage(); + // WordPress is already loaded, so there's no chance we'll find the command + if ( function_exists( 'add_filter' ) ) { + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + } } } From 13f90966a7c2e3ca7c533267fe31286cf5852c7b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 22:59:07 +0300 Subject: [PATCH 1687/5359] create empty help.txt file, so that `wp help --man` works --- man-src/help.txt | 0 man/help.1 | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 man-src/help.txt diff --git a/man-src/help.txt b/man-src/help.txt new file mode 100644 index 000000000..e69de29bb diff --git a/man/help.1 b/man/help.1 index ec0050cb1..707ebcc97 100644 --- a/man/help.1 +++ b/man/help.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-HELP" "1" "October 2012" "" "WP-CLI" +.TH "WP\-HELP" "1" "" "WP-CLI" . .SH "NAME" \fBwp\-help\fR \- Get help on a certain topic\. . .SH "SYNOPSIS" -\fBwp help\fR [\fIcommand\fR] +wp help [\fIcommand\fR] From 6ce07e6c875a438644b376a6fa7f21c5102d222d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 23:03:13 +0300 Subject: [PATCH 1688/5359] create empty home.txt file, so that `wp home --man` works --- man-src/home.txt | 0 man/home.1 | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 man-src/home.txt diff --git a/man-src/home.txt b/man-src/home.txt new file mode 100644 index 000000000..e69de29bb diff --git a/man/home.1 b/man/home.1 index 235d563cb..184b18290 100644 --- a/man/home.1 +++ b/man/home.1 @@ -1,10 +1,10 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-HOME" "1" "October 2012" "" "WP-CLI" +.TH "WP\-HOME" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-home\fR \- Opens the wp\-cli homepage in your browser\. +\fBwp\-home\fR \- Open the wp\-cli homepage in your browser\. . .SH "SYNOPSIS" -\fBwp home\fR +wp home From 53ecf149fc7cd136b980f820e293dd006979b810 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 23:04:46 +0300 Subject: [PATCH 1689/5359] remove old db man pages --- man/db-cli.1 | 10 ---------- man/db-connect.1 | 10 ---------- man/db-create.1 | 10 ---------- man/db-drop.1 | 19 ------------------- man/db-export.1 | 19 ------------------- man/db-import.1 | 19 ------------------- man/db-optimize.1 | 10 ---------- man/db-query.1 | 19 ------------------- man/db-repair.1 | 10 ---------- man/db-reset.1 | 19 ------------------- 10 files changed, 145 deletions(-) delete mode 100644 man/db-cli.1 delete mode 100644 man/db-connect.1 delete mode 100644 man/db-create.1 delete mode 100644 man/db-drop.1 delete mode 100644 man/db-export.1 delete mode 100644 man/db-import.1 delete mode 100644 man/db-optimize.1 delete mode 100644 man/db-query.1 delete mode 100644 man/db-repair.1 delete mode 100644 man/db-reset.1 diff --git a/man/db-cli.1 b/man/db-cli.1 deleted file mode 100644 index f5d2b88da..000000000 --- a/man/db-cli.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-CLI" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-cli\fR \- Open a mysql console using the WordPress credentials\. -. -.SH "SYNOPSIS" -\fBwp db cli\fR diff --git a/man/db-connect.1 b/man/db-connect.1 deleted file mode 100644 index 9fea5148e..000000000 --- a/man/db-connect.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-CONNECT" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-connect\fR \- Print a string for connecting to the DB\. -. -.SH "SYNOPSIS" -\fBwp db connect\fR diff --git a/man/db-create.1 b/man/db-create.1 deleted file mode 100644 index 4c94095c8..000000000 --- a/man/db-create.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-CREATE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-create\fR \- Create the database, as specified in wp\-config\.php -. -.SH "SYNOPSIS" -\fBwp db create\fR diff --git a/man/db-drop.1 b/man/db-drop.1 deleted file mode 100644 index 2f28197ff..000000000 --- a/man/db-drop.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-DROP" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-drop\fR \- Delete the database\. -. -.SH "SYNOPSIS" -wp db drop [\-\-yes] -. -.SH "OPTIONS" -. -.TP -\fB\-\-yes\fR: -. -.IP -Answer yes to the confirmation message\. - diff --git a/man/db-export.1 b/man/db-export.1 deleted file mode 100644 index 2f0a811fc..000000000 --- a/man/db-export.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-EXPORT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-export\fR \- Exports the database using mysqldump\. -. -.SH "SYNOPSIS" -wp db export [\fIfile\fR] -. -.SH "OPTIONS" -. -.TP -\fB<file>\fR: -. -.IP -The name of the export file\. If omitted, it will be \'{dbname}\.sql\' - diff --git a/man/db-import.1 b/man/db-import.1 deleted file mode 100644 index eaa90697e..000000000 --- a/man/db-import.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-IMPORT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-import\fR \- Import database from a file\. -. -.SH "SYNOPSIS" -wp db import [\fIfile\fR] -. -.SH "OPTIONS" -. -.TP -\fB<file>\fR: -. -.IP -The name of the import file\. If omitted, it will be \'{dbname}\.sql\' - diff --git a/man/db-optimize.1 b/man/db-optimize.1 deleted file mode 100644 index 50fad9af3..000000000 --- a/man/db-optimize.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-OPTIMIZE" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-optimize\fR \- Optimize the database\. -. -.SH "SYNOPSIS" -\fBwp db optimize\fR diff --git a/man/db-query.1 b/man/db-query.1 deleted file mode 100644 index 0e0abdaf9..000000000 --- a/man/db-query.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-QUERY" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-query\fR \- Execute a query against the database\. -. -.SH "SYNOPSIS" -wp db query \fIsql\fR -. -.SH "OPTIONS" -. -.TP -\fB<SQL>\fR: -. -.IP -A SQL query\. - diff --git a/man/db-repair.1 b/man/db-repair.1 deleted file mode 100644 index 3e6539c8d..000000000 --- a/man/db-repair.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-REPAIR" "1" "October 2012" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-repair\fR \- Repair the database\. -. -.SH "SYNOPSIS" -\fBwp db repair\fR diff --git a/man/db-reset.1 b/man/db-reset.1 deleted file mode 100644 index b27e41cfc..000000000 --- a/man/db-reset.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB\-RESET" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\-reset\fR \- Remove all tables from the database\. -. -.SH "SYNOPSIS" -wp db reset [\-\-yes] -. -.SH "OPTIONS" -. -.TP -\fB\-\-yes\fR: -. -.IP -Answer yes to the confirmation message\. - From 7e93170380b98ed51a41bc876905172f7a838767 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 May 2013 23:12:01 +0300 Subject: [PATCH 1690/5359] help: add test for --help --- features/help.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/help.feature b/features/help.feature index f82b0c7cf..84207355d 100644 --- a/features/help.feature +++ b/features/help.feature @@ -21,6 +21,12 @@ Feature: Get help about WP-CLI commands WP-CORE-DOWNLOAD(1) """ + When I run `wp help --help` + Then STDOUT should contain: + """ + WP-HELP(1) + """ + When I try `wp help non-existent-command` Then the return code should be 1 And STDERR should not be empty From 262781e7215717be05dcd42cd313d38e4aafe0a4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 00:09:59 +0300 Subject: [PATCH 1691/5359] post list: show post status by default Yes, we have --fields, but useful defaults matter. The post status helps to remind users that they might want to filter the list further. see #422 --- php/commands/post.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index b895a78d9..e1e2da842 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -13,7 +13,8 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { 'ID', 'post_title', 'post_name', - 'post_date' + 'post_date', + 'post_status' ); /** From ca9c9715429d94c911d48cb1be73495df49f9ddc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 00:20:48 +0300 Subject: [PATCH 1692/5359] post list: update man page --- man-src/post-list.txt | 2 +- man/post-list.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/post-list.txt b/man-src/post-list.txt index 67637487a..098d41c74 100644 --- a/man-src/post-list.txt +++ b/man-src/post-list.txt @@ -6,7 +6,7 @@ * `--fields`=<fields>: - Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date. + Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. * `--format`=<format>: diff --git a/man/post-list.1 b/man/post-list.1 index 83d3c3991..921245423 100644 --- a/man/post-list.1 +++ b/man/post-list.1 @@ -21,7 +21,7 @@ One or more args to pass to WP_Query\. \fB\-\-fields\fR=\fIfields\fR: . .IP -Limit the output to specific object fields\. Defaults to ID,post_title,post_name,post_date\. +Limit the output to specific object fields\. Defaults to ID,post_title,post_name,post_date,post_status\. . .TP \fB\-\-format\fR=\fIformat\fR: From 9b983ff044fc02843662287fbac7299d906f6213 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 00:34:04 +0300 Subject: [PATCH 1693/5359] post create: include --post_date in example closes #282 --- man-src/post-create.txt | 4 ++-- man/post-create.1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man-src/post-create.txt b/man-src/post-create.txt index 0a2bb1e06..770713c9c 100644 --- a/man-src/post-create.txt +++ b/man-src/post-create.txt @@ -26,6 +26,6 @@ ## EXAMPLES - wp post create --post_type=page --post_status=publish --post_title='A new page' + wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' - wp post create file.txt --post_type=post --post_title='Post from file' + wp post create page.txt --post_type=page --post_title='Page from file' diff --git a/man/post-create.1 b/man/post-create.1 index 12e7be408..7dbc24844 100644 --- a/man/post-create.1 +++ b/man/post-create.1 @@ -45,9 +45,9 @@ Output just the new post id\. . .nf -wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A new page\' +wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A future post\' \-\-post\-status=future \-\-post_date=\'2020\-12\-01 07:00:00\' -wp post create file\.txt \-\-post_type=post \-\-post_title=\'Post from file\' +wp post create page\.txt \-\-post_type=page \-\-post_title=\'Page from file\' . .fi From c74fa93214b28b3d5577219ca84630737c4cf716 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 12 May 2013 00:01:10 +0300 Subject: [PATCH 1694/5359] don't attempt to export $COLUMNS First of all, it's not used by wp-cli (php-cli-tools calls tput directly). Second of all, $COLUMNS is a shell variable, so it wouldn't be available via PHP's getenv() normally. In other words, calling tput directly is the correct solution. --- bin/wp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/bin/wp b/bin/wp index 0ae1dabd5..0120a18de 100755 --- a/bin/wp +++ b/bin/wp @@ -30,19 +30,6 @@ case $(uname -a) in SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; esac -# If not exported, try to determine and export the number of columns. -# We do not want to run $(tput cols) if $TERM is empty or "dumb", because -# if we do, tput will output an undesirable error message to stderr. If -# we redirect stderr in any way, e.g. $(tput cols 2>/dev/null), then the -# error message is suppressed, but tput cols becomes confused about the -# terminal and prints out the default value (80). -if [ -z $COLUMNS ] && [ -n "$TERM" ] && [ "$TERM" != dumb ] ; then - # Note to cygwin users: install the ncurses package to get tput command. - if COLUMNS=$(tput cols); then - export COLUMNS - fi -fi - if [ ! -z "$WP_CLI_PHP" ] ; then # Use the WP_CLI_PHP environment variable if it is available. php="$WP_CLI_PHP" From c12b24d6201cc09dd4e9c22a04dbed904b6e3225 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 15:20:07 +0300 Subject: [PATCH 1695/5359] convert `wp --man` to `wp help --gen` --- php/WP_CLI/Dispatcher/RootCommand.php | 5 ---- php/WP_CLI/InternalFlags.php | 22 ----------------- php/WP_CLI/Runner.php | 6 ----- php/commands/help.php | 34 +++++++++++++++++++++++---- 4 files changed, 30 insertions(+), 37 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 0da342d74..4c74f82cb 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -73,11 +73,6 @@ private static function generate_synopsis() { } function pre_invoke( &$args ) { - if ( array( 'help' ) == $args ) { - $this->show_usage(); - exit; - } - $cmd_name = $args[0]; $command = $this->find_subcommand( $args ); diff --git a/php/WP_CLI/InternalFlags.php b/php/WP_CLI/InternalFlags.php index 87cabf372..1f5bf7089 100644 --- a/php/WP_CLI/InternalFlags.php +++ b/php/WP_CLI/InternalFlags.php @@ -55,27 +55,5 @@ static function completions() { WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); } } - - static function man( $args ) { - if ( '' === exec( 'which ronn' ) ) { - WP_CLI::error( '`ronn` executable not found.' ); - } - - $arg_copy = $args; - - $command = WP_CLI::$root; - - while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { - $command = $command->find_subcommand( $args ); - } - - if ( !$command ) - WP_CLI::error( sprintf( "'%s' command not found.", - implode( ' ', $arg_copy ) ) ); - - foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { - WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); - } - } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 106fc6479..107963716 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -163,12 +163,6 @@ private function cmd_starts_with( $prefix ) { } private function _run_command() { - // Handle --man parameter - if ( isset( $this->assoc_args['man'] ) ) { - \WP_CLI\InternalFlags::man( $this->arguments ); - exit; - } - WP_CLI::run_command( $this->arguments, $this->assoc_args ); } diff --git a/php/commands/help.php b/php/commands/help.php index 0afaea742..c66e4a99b 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -1,15 +1,20 @@ <?php -use \WP_CLI\Dispatcher\CommandContainer; - class Help_Command extends WP_CLI_Command { /** * Get help on a certain topic. * - * @synopsis [<command>] + * @synopsis [<command>] [--gen] */ - function __invoke( $args ) { + function __invoke( $args, $assoc_args ) { + if ( isset( $assoc_args['gen'] ) ) + $this->generate( $args ); + else + $this->show( $args ); + } + + private function show( $args ) { if ( \WP_CLI\Man\maybe_show_manpage( $args ) ) { exit; } @@ -26,6 +31,27 @@ function __invoke( $args ) { \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); } } + + private function generate( $args ) { + if ( '' === exec( 'which ronn' ) ) { + WP_CLI::error( '`ronn` executable not found.' ); + } + + $arg_copy = $args; + + $command = WP_CLI\Utils\find_subcommand( $args ); + + if ( !$command ) { + WP_CLI::error( sprintf( "'%s' command not found.", + implode( ' ', $arg_copy ) ) ); + } + + foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { + WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + } + + exit; + } } WP_CLI::add_command( 'help', 'Help_Command' ); From d8b2af174b36308a10e7448ce43c5aa88f6cdc15 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 15:20:49 +0300 Subject: [PATCH 1696/5359] wp help: update man page --- CONTRIBUTING.md | 6 +----- man-src/help.txt | 10 ++++++++++ man/help.1 | 18 +++++++++++++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c90ed7c39..7389047ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,11 +16,7 @@ The compiled man page is placed in the `man` directory. To (re)generate one or more man pages, you first need to have the [ronn](https://rubygems.org/gems/ronn) ruby gem installed. -Then, you can run one of the following: - -* `wp --man` - regenerates all man pages -* `wp core --man` - regenerates man pages for the `core` command -* `wp core download --man` - regenerates man page only for the `core download` subcommand +Then, you can use the `wp help --gen` command. Running the tests ----------------- diff --git a/man-src/help.txt b/man-src/help.txt index e69de29bb..69ac8e699 100644 --- a/man-src/help.txt +++ b/man-src/help.txt @@ -0,0 +1,10 @@ +## EXAMPLES + + # (re)generates all man pages + wp help --gen + + # (re)generate man pages for the `core` command + wp help --gen core + + # (re)generate man page only for the `core download` subcommand + wp help --gen core download diff --git a/man/help.1 b/man/help.1 index 707ebcc97..9b707455e 100644 --- a/man/help.1 +++ b/man/help.1 @@ -7,4 +7,20 @@ \fBwp\-help\fR \- Get help on a certain topic\. . .SH "SYNOPSIS" -wp help [\fIcommand\fR] +wp help [\fIcommand\fR] [\-\-gen] +. +.SH "EXAMPLES" +. +.nf + +# (re)generates all man pages +wp help \-\-gen + +# (re)generate man pages for the `core` command +wp help \-\-gen core + +# (re)generate man page only for the `core download` subcommand +wp help \-\-gen core download +. +.fi + From ad73dea652a38f826aaa45173afd4ab00a4b3125 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 15:56:44 +0300 Subject: [PATCH 1697/5359] help --gen: add test for multisite-only subcommands --- features/help.feature | 8 ++++++++ php/commands/blog.php | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index 84207355d..205cd8b36 100644 --- a/features/help.feature +++ b/features/help.feature @@ -51,3 +51,11 @@ Feature: Get help about WP-CLI commands """ usage: wp test-help """ + + Scenario: Generating help + Given an empty directory + When I run `wp help --gen blog create` + Then STDOUT should be: + """ + generated blog-create.1 + """ diff --git a/php/commands/blog.php b/php/commands/blog.php index 3c38438d3..548981e5e 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -279,7 +279,7 @@ public function create( $_, $assoc_args ) { } $command_class = 'Blog_Command'; -if ( function_exists( 'is_multisite' ) && is_multisite() ) +if ( !function_exists( 'is_multisite' ) || is_multisite() ) $command_class = 'MS_Blog_Command'; WP_CLI::add_command( 'blog', $command_class ); From 64d4085f60f8ff0d3b61fb3f8bbf373e28b42992 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 16:53:44 +0300 Subject: [PATCH 1698/5359] help --gen: add test for third-party commands --- .travis.yml | 1 + features/help.feature | 26 +++++++++++++++++++++++--- features/steps/basic_steps.php | 4 +++- php/class-wp-cli.php | 4 ++-- php/commands/help.php | 15 ++++++++------- php/man.php | 6 +++--- 6 files changed, 40 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 622e25b65..d0a9cebc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ before_script: # install dependencies - composer install --dev --no-interaction --prefer-source - composer require d11wtq/boris=dev-master --no-interaction --prefer-source + - gem install ronn # set up WP install - bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ # set up database diff --git a/features/help.feature b/features/help.feature index 205cd8b36..7ee24d6a4 100644 --- a/features/help.feature +++ b/features/help.feature @@ -33,7 +33,13 @@ Feature: Get help about WP-CLI commands Scenario: Getting help for a third-party command Given a WP install - And a wp-content/plugins/test-cli-help.php file: + And a wp-content/plugins/test-cli/test-help.txt file: + """ + ## EXAMPLES + + wp test-help + """ + And a wp-content/plugins/test-cli/command.php file: """ <?php // Plugin Name: Test CLI Help @@ -43,8 +49,10 @@ Feature: Get help about WP-CLI commands } WP_CLI::add_command( 'test-help', 'Test_Help' ); + + WP_CLI::add_man_dir( __DIR__, __DIR__ ); """ - And I run `wp plugin activate test-cli-help` + And I run `wp plugin activate test-cli` When I run `wp help test-help` Then STDOUT should contain: @@ -52,7 +60,19 @@ Feature: Get help about WP-CLI commands usage: wp test-help """ - Scenario: Generating help + When I run `wp help --gen test-help` + Then STDOUT should contain: + """ + generated test-help.1 + """ + + When I run `wp help test-help` + Then STDOUT should contain: + """ + WP-TEST-HELP(1) + """ + + Scenario: Generating help for multisite-only subcommands Given an empty directory When I run `wp help --gen blog create` Then STDOUT should be: diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index d5432db90..f838df65c 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -23,7 +23,9 @@ function ( $world ) { $steps->Given( '/^a ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; - file_put_contents( $world->get_path( $path ), $content ); + $full_path = $world->get_path( $path ); + Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); + file_put_contents( $full_path, $content ); } ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index a711d4d0a..1a47614f1 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -19,8 +19,8 @@ class WP_CLI { */ static function init() { self::add_man_dir( - WP_CLI_ROOT . "../man/", - WP_CLI_ROOT . "../man-src/" + WP_CLI_ROOT . "../man", + WP_CLI_ROOT . "../man-src" ); self::$root = new Dispatcher\RootCommand; diff --git a/php/commands/help.php b/php/commands/help.php index c66e4a99b..9043a7e84 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -41,16 +41,17 @@ private function generate( $args ) { $command = WP_CLI\Utils\find_subcommand( $args ); - if ( !$command ) { - WP_CLI::error( sprintf( "'%s' command not found.", - implode( ' ', $arg_copy ) ) ); + if ( $command ) { + foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { + WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + } + exit; } - foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { - WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + // WordPress is already loaded, so there's no chance we'll find the command + if ( function_exists( 'add_filter' ) ) { + WP_CLI::error( sprintf( "'%s' command not found.", implode( ' ', $arg_copy ) ) ); } - - exit; } } diff --git a/php/man.php b/php/man.php index 0d42cbfd0..38abf2d90 100644 --- a/php/man.php +++ b/php/man.php @@ -16,8 +16,8 @@ function generate( $src_dir, $dest_dir, $command ) { $cmd_path = Dispatcher\get_path( $command ); array_shift( $cmd_path ); // discard 'wp' - $src_path = $src_dir . get_src_file_name( $cmd_path ); - $dest_path = $dest_dir . get_file_name( $cmd_path ); + $src_path = "$src_dir/" . get_src_file_name( $cmd_path ); + $dest_path = "$dest_dir/" . get_file_name( $cmd_path ); call_ronn( get_markdown( $src_path, $command ), $dest_path ); @@ -134,7 +134,7 @@ function maybe_show_manpage( $args ) { $man_file = get_file_name( $args ); foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { - $man_path = $dest_dir . $man_file; + $man_path = "$dest_dir/" . $man_file; if ( is_readable( $man_path ) ) { show_manpage( $man_path ); From 780c5f4fc2571b92a2f141fa483b203be6366bc9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 17:21:17 +0300 Subject: [PATCH 1699/5359] merge man.php into commands/help.php --- php/commands/help.php | 147 +++++++++++++++++++++++++++++++++++++++++- php/man.php | 147 ------------------------------------------ php/wp-cli.php | 1 - 3 files changed, 145 insertions(+), 150 deletions(-) delete mode 100644 php/man.php diff --git a/php/commands/help.php b/php/commands/help.php index 9043a7e84..3fa8de9c0 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -1,5 +1,7 @@ <?php +use \WP_CLI\Dispatcher; + class Help_Command extends WP_CLI_Command { /** @@ -15,7 +17,7 @@ function __invoke( $args, $assoc_args ) { } private function show( $args ) { - if ( \WP_CLI\Man\maybe_show_manpage( $args ) ) { + if ( self::maybe_show_manpage( $args ) ) { exit; } @@ -43,7 +45,7 @@ private function generate( $args ) { if ( $command ) { foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { - WP_CLI\Man\generate( $src_dir, $dest_dir, $command ); + self::_generate( $src_dir, $dest_dir, $command ); } exit; } @@ -53,6 +55,147 @@ private function generate( $args ) { WP_CLI::error( sprintf( "'%s' command not found.", implode( ' ', $arg_copy ) ) ); } } + + private static function maybe_show_manpage( $args ) { + $man_file = self::get_file_name( $args ); + + foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { + $man_path = "$dest_dir/" . $man_file; + + if ( is_readable( $man_path ) ) { + self::show_manpage( $man_path ); + return true; + } + } + + return false; + } + + private static function show_manpage( $path ) { + // man can't read phar://, so need to copy to a temporary file + $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); + + copy( $path, $tmp_path ); + + \WP_CLI::launch( "man $tmp_path" ); + + unlink( $tmp_path ); + } + + private static function _generate( $src_dir, $dest_dir, $command ) { + $cmd_path = Dispatcher\get_path( $command ); + array_shift( $cmd_path ); // discard 'wp' + + $src_path = "$src_dir/" . self::get_src_file_name( $cmd_path ); + $dest_path = "$dest_dir/" . self::get_file_name( $cmd_path ); + + self::call_ronn( self::get_markdown( $src_path, $command ), $dest_path ); + + if ( $command instanceof Dispatcher\CommandContainer ) { + foreach ( $command->get_subcommands() as $subcommand ) { + self::_generate( $src_dir, $dest_dir, $subcommand ); + } + } + } + + // returns a file descriptor or false + private static function get_markdown( $doc_path, $command ) { + if ( !file_exists( $doc_path ) ) + return false; + + $fd = fopen( "php://temp", "rw" ); + + if ( $command instanceof Dispatcher\Documentable ) + self::add_initial_markdown( $fd, $command ); + + fwrite( $fd, file_get_contents( $doc_path ) ); + + if ( 0 === ftell( $fd ) ) + return false; + + fseek( $fd, 0 ); + + return $fd; + } + + private static function add_initial_markdown( $fd, $command ) { + $path = Dispatcher\get_path( $command ); + + $shortdesc = $command->get_shortdesc(); + $synopsis = $command->get_full_synopsis(); + + $synopsis = str_replace( '_', '\_', $synopsis ); + $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); + + $name_m = implode( '-', $path ); + $name_s = implode( ' ', $path ); + + if ( !$shortdesc ) { + \WP_CLI::warning( "No shortdesc for $name_s" ); + } + + fwrite( $fd, <<<DOC +$name_m(1) -- $shortdesc +==== + +## SYNOPSIS + +$synopsis + +DOC + ); + + if ( $command instanceof Dispatcher\CommandContainer ) { + + fwrite( $fd, <<<DOC +## SUBCOMMANDS + +DOC + ); + + foreach ( $command->get_subcommands() as $subcommand ) { + $name = $subcommand->get_name(); + $desc = $subcommand->get_shortdesc(); + + fwrite( $fd, <<<DOC +* `$name`: + + $desc + +DOC + ); + } + } + } + + private static function call_ronn( $markdown, $dest ) { + if ( !$markdown ) + return; + + $descriptorspec = array( + 0 => $markdown, + 1 => array( 'file', $dest, 'w' ), + 2 => STDERR + ); + + $cmd = "ronn --date=2012-01-01 --roff --manual='WP-CLI'"; + + $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); + + $roff = file_get_contents( $dest ); + $roff = str_replace( ' "January 2012"', '', $roff ); + file_put_contents( $dest, $roff ); + + \WP_CLI::line( "generated " . basename( $dest ) ); + } + + private static function get_file_name( $args ) { + return implode( '-', $args ) . '.1'; + } + + private static function get_src_file_name( $args ) { + return implode( '-', $args ) . '.txt'; + } } WP_CLI::add_command( 'help', 'Help_Command' ); diff --git a/php/man.php b/php/man.php deleted file mode 100644 index 38abf2d90..000000000 --- a/php/man.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php - -namespace WP_CLI\Man; - -use \WP_CLI\Dispatcher; - -function get_file_name( $args ) { - return implode( '-', $args ) . '.1'; -} - -function get_src_file_name( $args ) { - return implode( '-', $args ) . '.txt'; -} - -function generate( $src_dir, $dest_dir, $command ) { - $cmd_path = Dispatcher\get_path( $command ); - array_shift( $cmd_path ); // discard 'wp' - - $src_path = "$src_dir/" . get_src_file_name( $cmd_path ); - $dest_path = "$dest_dir/" . get_file_name( $cmd_path ); - - call_ronn( get_markdown( $src_path, $command ), $dest_path ); - - if ( $command instanceof Dispatcher\CommandContainer ) { - foreach ( $command->get_subcommands() as $subcommand ) { - generate( $src_dir, $dest_dir, $subcommand ); - } - } -} - -// returns a file descriptor or false -function get_markdown( $doc_path, $command ) { - if ( !file_exists( $doc_path ) ) - return false; - - $fd = fopen( "php://temp", "rw" ); - - if ( $command instanceof Dispatcher\Documentable ) - add_initial_markdown( $fd, $command ); - - fwrite( $fd, file_get_contents( $doc_path ) ); - - if ( 0 === ftell( $fd ) ) - return false; - - fseek( $fd, 0 ); - - return $fd; -} - -function add_initial_markdown( $fd, $command ) { - $path = Dispatcher\get_path( $command ); - - $shortdesc = $command->get_shortdesc(); - $synopsis = $command->get_full_synopsis(); - - $synopsis = str_replace( '_', '\_', $synopsis ); - $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); - - $name_m = implode( '-', $path ); - $name_s = implode( ' ', $path ); - - if ( !$shortdesc ) { - \WP_CLI::warning( "No shortdesc for $name_s" ); - } - - fwrite( $fd, <<<DOC -$name_m(1) -- $shortdesc -==== - -## SYNOPSIS - -$synopsis - -DOC - ); - - if ( $command instanceof Dispatcher\CommandContainer ) { - - fwrite( $fd, <<<DOC -## SUBCOMMANDS - -DOC - ); - - foreach ( $command->get_subcommands() as $subcommand ) { - $name = $subcommand->get_name(); - $desc = $subcommand->get_shortdesc(); - - fwrite( $fd, <<<DOC -* `$name`: - - $desc - -DOC - ); - } - } -} - -function call_ronn( $markdown, $dest ) { - if ( !$markdown ) - return; - - $descriptorspec = array( - 0 => $markdown, - 1 => array( 'file', $dest, 'w' ), - 2 => STDERR - ); - - $cmd = "ronn --date=2012-01-01 --roff --manual='WP-CLI'"; - - $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); - - $roff = file_get_contents( $dest ); - $roff = str_replace( ' "January 2012"', '', $roff ); - file_put_contents( $dest, $roff ); - - \WP_CLI::line( "generated " . basename( $dest ) ); -} - -function show_manpage( $path ) { - // man can't read phar://, so need to copy to a temporary file - $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); - - copy( $path, $tmp_path ); - - \WP_CLI::launch( "man $tmp_path" ); - - unlink( $tmp_path ); -} - -function maybe_show_manpage( $args ) { - $man_file = get_file_name( $args ); - - foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { - $man_path = "$dest_dir/" . $man_file; - - if ( is_readable( $man_path ) ) { - show_manpage( $man_path ); - return true; - } - } - - return false; -} - diff --git a/php/wp-cli.php b/php/wp-cli.php index 74db4137d..8ca2bcf13 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -9,7 +9,6 @@ include WP_CLI_ROOT . 'dispatcher.php'; include WP_CLI_ROOT . 'class-wp-cli.php'; include WP_CLI_ROOT . 'class-wp-cli-command.php'; -include WP_CLI_ROOT . 'man.php'; \WP_CLI\Utils\load_dependencies(); From 77cb9de295aef1c1f625b335f2ce2c227639553e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 17:31:42 +0300 Subject: [PATCH 1700/5359] convert Scaffold_Command->render() to Utils\mustache_render() --- php/commands/scaffold.php | 26 ++++++++------------------ php/utils.php | 8 ++++++++ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 1cdcac396..9ba3d923d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Generate code for post types, taxonomies, etc. * @@ -80,7 +82,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) list( $raw_template, $extended_template ) = $templates; - $raw_output = $this->render( $raw_template, $vars ); + $raw_output = Utils\mustache_render( $raw_template, $vars ); if ( ! $control_args['raw'] ) { $vars = array_merge( $vars, array( @@ -88,7 +90,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) 'output' => $raw_output ) ); - $final_output = $this->render( $extended_template, $vars ); + $final_output = Utils\mustache_render( $extended_template, $vars ); } else { $final_output = $raw_output; } @@ -169,7 +171,7 @@ function child_theme( $args, $assoc_args ) { $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; - $this->create_file( $theme_style_path, $this->render( 'child_theme.mustache', $data ) ); + $this->create_file( $theme_style_path, Utils\mustache_render( 'child_theme.mustache', $data ) ); WP_CLI::success( "Created $theme_dir" ); @@ -213,7 +215,7 @@ function plugin( $args, $assoc_args ) { $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; $plugin_path = "$plugin_dir/$plugin_slug.php"; - $this->create_file( $plugin_path, $this->render( 'plugin.mustache', $data ) ); + $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); WP_CLI::success( "Created $plugin_dir" ); @@ -242,7 +244,7 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->mkdir( $tests_dir ); $this->create_file( "$tests_dir/bootstrap.php", - $this->render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ); + Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ); $to_copy = array( 'phpunit.xml' => $plugin_dir, @@ -251,7 +253,7 @@ function plugin_tests( $args, $assoc_args ) { ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( $this->get_template_path( $file ), "$dir/$file", true ); + $wp_filesystem->copy( WP_CLI_ROOT . "../templates/$file", "$dir/$file", true ); } WP_CLI::success( "Created test files in $plugin_dir" ); @@ -350,18 +352,6 @@ protected function extract_args( $assoc_args, $defaults ) { return $out; } - - private function render( $template, $data ) { - $template = file_get_contents( $this->get_template_path( $template ) ); - - $m = new Mustache_Engine; - - return $m->render( $template, $data ); - } - - private function get_template_path( $template ) { - return WP_CLI_ROOT . "../templates/$template"; - } } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); diff --git a/php/utils.php b/php/utils.php index 880136c86..65614d327 100644 --- a/php/utils.php +++ b/php/utils.php @@ -392,3 +392,11 @@ function run_mysql_command( $cmd, $arg_str, $pass ) { if ( $r ) exit( $r ); } +function mustache_render( $template_name, $data ) { + $template = file_get_contents( WP_CLI_ROOT . "../templates/$template_name" ); + + $m = new \Mustache_Engine; + + return $m->render( $template, $data ); +} + From d21f33adb4513b1d006f23b71ab8639f143e6757 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 17:47:40 +0300 Subject: [PATCH 1701/5359] help --gen: add test for combined man pages --- features/help.feature | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/features/help.feature b/features/help.feature index 7ee24d6a4..39ca944d8 100644 --- a/features/help.feature +++ b/features/help.feature @@ -1,6 +1,6 @@ Feature: Get help about WP-CLI commands - Scenario: Empty dir + Scenario: Help for internal commands Given an empty directory When I run `wp help` @@ -31,7 +31,23 @@ Feature: Get help about WP-CLI commands Then the return code should be 1 And STDERR should not be empty - Scenario: Getting help for a third-party command + Scenario: Generating help for subcommands + Given an empty directory + When I run `wp help --gen option` + Then STDOUT should be: + """ + generated option.1 + """ + + Scenario: Generating help for multisite-only subcommands + Given an empty directory + When I run `wp help --gen blog create` + Then STDOUT should be: + """ + generated blog-create.1 + """ + + Scenario: Help for third-party commands Given a WP install And a wp-content/plugins/test-cli/test-help.txt file: """ @@ -71,11 +87,3 @@ Feature: Get help about WP-CLI commands """ WP-TEST-HELP(1) """ - - Scenario: Generating help for multisite-only subcommands - Given an empty directory - When I run `wp help --gen blog create` - Then STDOUT should be: - """ - generated blog-create.1 - """ From 770f53c3a38723ffa3f16f1e1f165b5b4ff65d03 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 17:59:38 +0300 Subject: [PATCH 1702/5359] introduce man.mustache --- php/commands/help.php | 45 +++++++++++++----------------------------- templates/man.mustache | 17 ++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) create mode 100644 templates/man.mustache diff --git a/php/commands/help.php b/php/commands/help.php index 3fa8de9c0..12a31397d 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -1,5 +1,6 @@ <?php +use \WP_CLI\Utils; use \WP_CLI\Dispatcher; class Help_Command extends WP_CLI_Command { @@ -121,51 +122,33 @@ private static function get_markdown( $doc_path, $command ) { private static function add_initial_markdown( $fd, $command ) { $path = Dispatcher\get_path( $command ); - $shortdesc = $command->get_shortdesc(); + $binding = array( + 'name_m' => implode( '-', $path ), + 'shortdesc' => $command->get_shortdesc(), + ); + $synopsis = $command->get_full_synopsis(); $synopsis = str_replace( '_', '\_', $synopsis ); $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); - $name_m = implode( '-', $path ); - $name_s = implode( ' ', $path ); + $binding['synopsis'] = $synopsis; - if ( !$shortdesc ) { + if ( !$binding['shortdesc'] ) { + $name_s = implode( ' ', $path ); \WP_CLI::warning( "No shortdesc for $name_s" ); } - fwrite( $fd, <<<DOC -$name_m(1) -- $shortdesc -==== - -## SYNOPSIS - -$synopsis - -DOC - ); - if ( $command instanceof Dispatcher\CommandContainer ) { - - fwrite( $fd, <<<DOC -## SUBCOMMANDS - -DOC - ); - foreach ( $command->get_subcommands() as $subcommand ) { - $name = $subcommand->get_name(); - $desc = $subcommand->get_shortdesc(); - - fwrite( $fd, <<<DOC -* `$name`: - - $desc - -DOC + $binding['has-subcommands']['subcommands'][] = array( + 'name' => $subcommand->get_name(), + 'desc' => $subcommand->get_shortdesc(), ); } } + + fwrite( $fd, Utils\mustache_render( 'man.mustache', $binding ) ); } private static function call_ronn( $markdown, $dest ) { diff --git a/templates/man.mustache b/templates/man.mustache new file mode 100644 index 000000000..61a99bcfc --- /dev/null +++ b/templates/man.mustache @@ -0,0 +1,17 @@ +{{name_m}}(1) -- {{shortdesc}} +==== + +## SYNOPSIS + +{{synopsis}} + +{{#has-subcommands}} +## SUBCOMMANDS + +{{#subcommands}} +* `{{name}}`: + + {{desc}} + +{{/subcommands}} +{{/has-subcommands}} From d7d3939e889309292a8a6457182935a1289fd0cc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 18:13:31 +0300 Subject: [PATCH 1703/5359] re-generate man pages --- man/cache.1 | 3 --- man/cap.1 | 17 ++++++----------- man/db.1 | 1 - man/option.1 | 1 - man/post-meta.1 | 1 - man/transient.1 | 5 +---- man/user-meta.1 | 1 - 7 files changed, 7 insertions(+), 22 deletions(-) diff --git a/man/cache.1 b/man/cache.1 index 19d4886d6..82f66dc5b 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -90,9 +90,6 @@ Set a value to the object cache\. Attempts to determine which object cache is being used\. . .SH "EXAMPLES" - -. -.P wp cache set my_key my_value my_group 300 . .P diff --git a/man/cap.1 b/man/cap.1 index 5e8c620f8..fdee7e6b6 100644 --- a/man/cap.1 +++ b/man/cap.1 @@ -37,21 +37,16 @@ Remove capabilities from a given role\. . .SH "EXAMPLES" . -.IP +.nf + # Add \'spectate\' capability to \'author\' role -. -.br wp cap add \'author\' \'spectate\' -. -.IP + # Add all caps from \'editor\' role to \'author\' role -. -.br wp cap list \'editor\' | xargs wp cap add \'author\' -. -.IP + # Remove all caps from \'editor\' role that also appear in \'author\' role -. -.br wp cap list \'author\' | xargs wp cap remove \'editor\' +. +.fi diff --git a/man/db.1 b/man/db.1 index 98c8a6b8e..5dd468995 100644 --- a/man/db.1 +++ b/man/db.1 @@ -90,7 +90,6 @@ Repair the database\. Remove all tables from the database\. . .SH "OPTIONS" - . .TP \fB\-\-yes\fR: diff --git a/man/option.1 b/man/option.1 index bfb8105b8..904b88a2a 100644 --- a/man/option.1 +++ b/man/option.1 @@ -45,7 +45,6 @@ Get an option\. Update an option\. . .SH "OPTIONS" - . .TP \fB\-\-format=json\fR: diff --git a/man/post-meta.1 b/man/post-meta.1 index b806b334d..ac1203efe 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -45,7 +45,6 @@ Get meta field value\. Update a meta field\. . .SH "OPTIONS" - . .TP \fB\-\-format=json\fR: diff --git a/man/transient.1 b/man/transient.1 index 6c267b439..1edd72a00 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -36,7 +36,7 @@ Get a transient value\. \fBset\fR: . .IP -Set a transient value\. \fIexpiration\fR is the time until expiration, in seconds\. +Set a transient value\. <expiration> is the time until expiration, in seconds\. . .TP \fBtype\fR: @@ -45,7 +45,4 @@ Set a transient value\. \fIexpiration\fR is the time until expiration, in second See wether the transients API is using an object cache or the options table\. . .SH "EXAMPLES" - -. -.P wp transient set my_key my_value 300 diff --git a/man/user-meta.1 b/man/user-meta.1 index 883b2923b..b09bb8db9 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -45,7 +45,6 @@ Get meta field value\. Update a meta field\. . .SH "OPTIONS" - . .TP \fB\-\-format=json\fR: From 1ba4c6c9676f3c93f71bba397b3aa9449e6aa2af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 18:49:40 +0300 Subject: [PATCH 1704/5359] CommandWithUpgrade: remove unnecessary args check; indentation fixes --- php/WP_CLI/CommandWithUpgrade.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 4ffe02386..d2b8529c0 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -47,6 +47,7 @@ private function status_all() { } else { $line = ' '; } + $line .= $this->format_status( $details['status'], 'short' ); $line .= " " . str_pad( $details['name'], $padding ). "%n"; if ( !empty( $details['version'] ) ) { @@ -65,11 +66,11 @@ private function get_padding( $items ) { $max_len = 0; foreach ( $items as $details ) { - $len = strlen( $details['name'] ); + $len = strlen( $details['name'] ); - if ( $len > $max_len ) { - $max_len = $len; - } + if ( $len > $max_len ) { + $max_len = $len; + } } return $max_len; @@ -95,11 +96,6 @@ private function show_legend( $items ) { } function install( $args, $assoc_args ) { - if ( empty( $args ) ) { - \WP_CLI::line( "usage: wp $this->item_type install <slug>" ); - exit; - } - // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); @@ -235,7 +231,7 @@ private function create_objects( $items ) { } else if ( $value === false) { $value = "none"; } - + $object->{$field} = $value; } $objects[] = $object; From 3a70d152dceec529e21a70629106ff068015d9c9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 18:52:51 +0300 Subject: [PATCH 1705/5359] behat: replace 'a P2 theme zip' step with 'wp theme install' call --- features/steps/basic_steps.php | 12 ------------ features/theme.feature | 5 +---- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index f838df65c..dfec88c93 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -84,18 +84,6 @@ function ( $world ) { } ); -$steps->Given( '/^a P2 theme zip$/', - function ( $world ) { - $zip_name = 'p2.1.0.1.zip'; - - $world->variables['THEME_ZIP'] = $world->get_cache_path( $zip_name ); - - $zip_url = 'http://wordpress.org/extend/themes/download/' . $zip_name; - - $world->download_file( $zip_url, $world->variables['THEME_ZIP'] ); - } -); - $steps->Given( '/^a large image file$/', function ( $world ) { $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; diff --git a/features/theme.feature b/features/theme.feature index db3804ebb..fd65ec665 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -49,10 +49,7 @@ Feature: Manage WordPress themes Scenario: Upgrading a theme Given a WP install - And a P2 theme zip - - When I run `wp theme install {THEME_ZIP}` - Then STDOUT should not be empty + And I run `wp theme install p2 --version=1.0.1` When I run `wp theme status` Then STDOUT should contain: From 09d12e552cefba13cc8bd66574a1c60b73dd6538 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 20 May 2013 18:59:06 +0300 Subject: [PATCH 1706/5359] blog: explain logic behind multisite condition The `function_exists( 'add_filter' )` part tests that WordPress is loaded. --- php/commands/blog.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index 548981e5e..d92e3ac39 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -278,9 +278,11 @@ public function create( $_, $assoc_args ) { } } -$command_class = 'Blog_Command'; -if ( !function_exists( 'is_multisite' ) || is_multisite() ) +// We want multisite subcommands to be available when doing `wp help --gen blog` +if ( !function_exists( 'add_filter' ) || is_multisite() ) $command_class = 'MS_Blog_Command'; +else + $command_class = 'Blog_Command'; WP_CLI::add_command( 'blog', $command_class ); From 4a72e73d34c6574734d6b385722f50cea9e75d16 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 20 May 2013 16:29:22 -0700 Subject: [PATCH 1707/5359] Add a search-replace option to skip guids. --- man-src/search-replace.txt | 4 ++++ man/search-replace.1 | 8 +++++++- php/commands/search-replace.php | 7 ++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index 2db4c96cf..f4ed828d5 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -10,6 +10,10 @@ It will correctly handle serialized values. Show report, but don't perform the changes. +* `--skip-guids`: + + Do not perform the replacement in columns named 'guid'. Use to preserve existing GUID values when changing domain names. + ## EXAMPLES wp search-replace 'http://example.dev' 'http://example.com' --dry-run diff --git a/man/search-replace.1 b/man/search-replace.1 index 0a5e34236..edd227a8d 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,7 +7,7 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] [\-\-skip\-guids] . .SH "DESCRIPTION" This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. @@ -23,6 +23,12 @@ It will correctly handle serialized values\. .IP Show report, but don\'t perform the changes\. . +.TP +\fB\-\-skip\-guids\fR: +. +.IP +Do not perform the replacement in columns named \'guid\'\. Use to preserve existing GUID values when changing domain names\. +. .SH "EXAMPLES" . .nf diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 89f76d55c..752b2d50d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,7 +10,7 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [<table>...] [--dry-run] + * @synopsis <old> <new> [<table>...] [--dry-run] [--skip-guids] */ public function __invoke( $args, $assoc_args ) { global $wpdb; @@ -30,10 +30,15 @@ public function __invoke( $args, $assoc_args ) { $dry_run = isset( $assoc_args['dry-run'] ); + $skip_guids = isset( $assoc_args['skip-guids'] ); + foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { + if ( $skip_guids && 'guid' === $col ) + continue; + $count = self::handle_col( $col, $primary_key, $table, $old, $new, $dry_run ); From d261d7011e30f67870eb96aa06f1908223f88b49 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 20 May 2013 20:57:40 -0700 Subject: [PATCH 1708/5359] Specify any columns to be skipped. --- man-src/search-replace.txt | 8 ++++---- man/search-replace.1 | 10 +++++----- php/commands/search-replace.php | 9 ++++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index f4ed828d5..0168065d3 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -2,7 +2,7 @@ This command will go through all rows in all tables and will replace all appearances of the old string with the new one. -It will correctly handle serialized values. +It will correctly handle serialized values, and will not change primary key values. ## OPTIONS @@ -10,12 +10,12 @@ It will correctly handle serialized values. Show report, but don't perform the changes. -* `--skip-guids`: +* `--skip-columns=<columns>`: - Do not perform the replacement in columns named 'guid'. Use to preserve existing GUID values when changing domain names. + Do not perform the replacement in the comma-separated columns. Useful to preserve existing guid column values when changing domain names. ## EXAMPLES - wp search-replace 'http://example.dev' 'http://example.com' --dry-run + wp search-replace 'http://example.dev' 'http://example.com' --dry-run --skip-columns=guid wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms diff --git a/man/search-replace.1 b/man/search-replace.1 index edd227a8d..c532ce291 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,13 +7,13 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] [\-\-skip\-guids] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] [\-\-skip\-columns=\fIcolumns\fR] . .SH "DESCRIPTION" This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. . .P -It will correctly handle serialized values\. +It will correctly handle serialized values, and will not change primary key values\. . .SH "OPTIONS" . @@ -24,16 +24,16 @@ It will correctly handle serialized values\. Show report, but don\'t perform the changes\. . .TP -\fB\-\-skip\-guids\fR: +\fB\-\-skip\-columns=<columns>\fR: . .IP -Do not perform the replacement in columns named \'guid\'\. Use to preserve existing GUID values when changing domain names\. +Do not perform the replacement in the comma\-separated columns\. Useful to preserve existing guid column values when changing domain names\. . .SH "EXAMPLES" . .nf -wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-dry\-run +wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-dry\-run \-\-skip\-columns=guid wp search\-replace \'foo\' \'bar\' wp_posts wp_postmeta wp_terms . diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 752b2d50d..c5ffbe95d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,7 +10,7 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [<table>...] [--dry-run] [--skip-guids] + * @synopsis <old> <new> [<table>...] [--dry-run] [--skip-columns=<columns>] */ public function __invoke( $args, $assoc_args ) { global $wpdb; @@ -30,13 +30,16 @@ public function __invoke( $args, $assoc_args ) { $dry_run = isset( $assoc_args['dry-run'] ); - $skip_guids = isset( $assoc_args['skip-guids'] ); + if ( isset( $assoc_args['skip-columns'] ) ) + $skip_columns = explode( ',', $assoc_args['skip-columns'] ); + else + $skip_columns = array(); foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { - if ( $skip_guids && 'guid' === $col ) + if ( in_array( $col, $skip_columns ) ) continue; $count = self::handle_col( $col, $primary_key, $table, $old, $new, From a0f456c4a707fbf16c4fa8cdee69592b3804bbc6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 22 May 2013 15:59:50 +0300 Subject: [PATCH 1709/5359] search-replace: the --dry-run flag should be last --- man-src/search-replace.txt | 12 ++++++------ man/search-replace.1 | 14 +++++++------- php/commands/search-replace.php | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index 0168065d3..f6ead0c89 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -6,16 +6,16 @@ It will correctly handle serialized values, and will not change primary key valu ## OPTIONS -* `--dry-run`: +* `--skip-columns=<columns>`: - Show report, but don't perform the changes. + Do not perform the replacement in the comma-separated columns. -* `--skip-columns=<columns>`: +* `--dry-run`: - Do not perform the replacement in the comma-separated columns. Useful to preserve existing guid column values when changing domain names. + Show report, but don't perform the changes. ## EXAMPLES - wp search-replace 'http://example.dev' 'http://example.com' --dry-run --skip-columns=guid + wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid - wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms + wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run diff --git a/man/search-replace.1 b/man/search-replace.1 index c532ce291..7ee007f60 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,7 +7,7 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-dry\-run] [\-\-skip\-columns=\fIcolumns\fR] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] . .SH "DESCRIPTION" This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. @@ -18,24 +18,24 @@ It will correctly handle serialized values, and will not change primary key valu .SH "OPTIONS" . .TP -\fB\-\-dry\-run\fR: +\fB\-\-skip\-columns=<columns>\fR: . .IP -Show report, but don\'t perform the changes\. +Do not perform the replacement in the comma\-separated columns\. . .TP -\fB\-\-skip\-columns=<columns>\fR: +\fB\-\-dry\-run\fR: . .IP -Do not perform the replacement in the comma\-separated columns\. Useful to preserve existing guid column values when changing domain names\. +Show report, but don\'t perform the changes\. . .SH "EXAMPLES" . .nf -wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-dry\-run \-\-skip\-columns=guid +wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-skip\-columns=guid -wp search\-replace \'foo\' \'bar\' wp_posts wp_postmeta wp_terms +wp search\-replace \'foo\' \'bar\' wp_posts wp_postmeta wp_terms \-\-dry\-run . .fi diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c5ffbe95d..a08af875c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,7 +10,7 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [<table>...] [--dry-run] [--skip-columns=<columns>] + * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] */ public function __invoke( $args, $assoc_args ) { global $wpdb; From 1cf29c4fdd30d68105e10985b06cf3f69c70f504 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 22 May 2013 16:04:19 +0300 Subject: [PATCH 1710/5359] search-replace: add test for --skip-columns see #464 --- features/search-replace.feature | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 30d9ecb78..d5bf8ff4a 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -4,4 +4,13 @@ Feature: Do global search/replace Given a WP install When I run `wp search-replace foo bar` - Then STDOUT should not be empty + Then STDOUT should contain: + """ + guid + """ + + When I run `wp search-replace foo bar --skip-columns=guid` + Then STDOUT should not contain: + """ + guid + """ From fd465cea7ff0695d28f8dd30bd5605a0968c9921 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Thu, 23 May 2013 10:19:30 -0700 Subject: [PATCH 1711/5359] Correct taxonomy scaffold code for multiple post types. --- features/scaffold.feature | 11 +++++++++++ man-src/scaffold-taxonomy.txt | 4 ++++ man/core-update.1 | 37 ----------------------------------- man/scaffold-taxonomy.1 | 6 ++++++ php/commands/scaffold.php | 6 ++++++ templates/taxonomy.mustache | 2 +- 6 files changed, 28 insertions(+), 38 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index c638f6c14..e4d4fe3a8 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -53,6 +53,17 @@ Feature: Wordpress code scaffolding """ __( 'Zombie speeds', 'zombieland' """ + + # Test for multiple post types + @tax + Scenario: Scaffold a Custom Taxonomy and attach it to multiple post types + Given a WP install + + When I run `wp scaffold taxonomy perambulation-speed --post_types="zombie,wraith" --textdomain=zombieland` + Then STDOUT should contain: + """ + array( 'zombie', 'wraith' ) + """ @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt index 41c7ab375..f3e9a892b 100644 --- a/man-src/scaffold-taxonomy.txt +++ b/man-src/scaffold-taxonomy.txt @@ -1,5 +1,9 @@ ## OPTIONS +* `--post_types=<post_types>`: + + Post types to register for use with the taxonomy. + * `--label=<label>`: The text used to translate the update messages diff --git a/man/core-update.1 b/man/core-update.1 index cb5848fb2..e69de29bb 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -1,37 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-update\fR \- Update WordPress\. -. -.SH "SYNOPSIS" -wp core update [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] -. -.SH "OPTIONS" -. -.TP -\fB\-\-version=\fR\fInew_version\fR [package/zip]: -. -.IP -When passed, updates to new_version, optionally using package/zip as input\. -. -.TP -\fB\-\-force\fR: -. -.IP -Will update even when current WP version < passed version\. Use with caution\. -. -.SH "EXAMPLES" -. -.nf - -wp core update - -wp core update \-\-version=3\.4 \.\./latest\.zip - -wp core update \-\-version=3\.1 \-\-force -. -.fi - diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index a61470a2d..ec4586af2 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -12,6 +12,12 @@ wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-label=\f .SH "OPTIONS" . .TP +\fB\-\-post_types=<post_types>\fR: +. +.IP +Post types to register for use with the taxonomy\. +. +.TP \fB\-\-label=<label>\fR: . .IP diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 9ba3d923d..6b3b1bf05 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -68,6 +68,8 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $vars['slug'] = $slug; + $vars['post_types'] = $this->quote_comma_list_elements( $vars['post_types'] ); + $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); $vars['label'] = $control_args['label']; @@ -352,6 +354,10 @@ protected function extract_args( $assoc_args, $defaults ) { return $out; } + + protected function quote_comma_list_elements( $comma_list ) { + return "'" . implode( "', '", explode( ',', $comma_list ) ) . "'"; + } } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 5d82234e3..96e18b586 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -1,4 +1,4 @@ - register_taxonomy( '{{slug}}', array( '{{post_types}}' ), array( + register_taxonomy( '{{slug}}', array( {{post_types}} ), array( 'hierarchical' => false, 'public' => true, 'show_in_nav_menus' => true, From fcf449dd9b4c0c740843f5a7a7b711cec52f179e Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Thu, 23 May 2013 10:49:18 -0700 Subject: [PATCH 1712/5359] Restore accidentally deleted man page. --- man/core-update.1 | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/man/core-update.1 b/man/core-update.1 index e69de29bb..cb5848fb2 100644 --- a/man/core-update.1 +++ b/man/core-update.1 @@ -0,0 +1,37 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-CORE\-UPDATE" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-core\-update\fR \- Update WordPress\. +. +.SH "SYNOPSIS" +wp core update [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] +. +.SH "OPTIONS" +. +.TP +\fB\-\-version=\fR\fInew_version\fR [package/zip]: +. +.IP +When passed, updates to new_version, optionally using package/zip as input\. +. +.TP +\fB\-\-force\fR: +. +.IP +Will update even when current WP version < passed version\. Use with caution\. +. +.SH "EXAMPLES" +. +.nf + +wp core update + +wp core update \-\-version=3\.4 \.\./latest\.zip + +wp core update \-\-version=3\.1 \-\-force +. +.fi + From fbdb6c5792b363bada7d57b4fe3c26bb23c833d8 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Thu, 23 May 2013 10:49:43 -0700 Subject: [PATCH 1713/5359] Remove unnecessary comment. --- features/scaffold.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index e4d4fe3a8..cebd1ff7d 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -54,7 +54,6 @@ Feature: Wordpress code scaffolding __( 'Zombie speeds', 'zombieland' """ - # Test for multiple post types @tax Scenario: Scaffold a Custom Taxonomy and attach it to multiple post types Given a WP install From 12b9be1b0a31dba18db5f8400f080710718e8b27 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 24 May 2013 15:43:11 +0300 Subject: [PATCH 1714/5359] introduce WP_CLI\Loggers namespace --- php/WP_CLI/Loggers/Quiet.php | 30 +++++++++++++++++++++++++++++ php/WP_CLI/Loggers/Regular.php | 31 ++++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 25 ++++++++++++++++++------ php/class-wp-cli.php | 35 ++++++++++++++++------------------ php/utils.php | 2 +- 5 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 php/WP_CLI/Loggers/Quiet.php create mode 100644 php/WP_CLI/Loggers/Regular.php diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php new file mode 100644 index 000000000..d080815c5 --- /dev/null +++ b/php/WP_CLI/Loggers/Quiet.php @@ -0,0 +1,30 @@ +<?php + +namespace WP_CLI\Loggers; + +class Quiet { + + private $colorize; + + function __construct( $colorize ) { + $this->colorize = $colorize; + } + + function line( $message ) { + // nothing + } + + function success( $message, $label ) { + // nothing + } + + function warning( $message, $label ) { + // nothing + } + + function error( $message, $label ) { + $msg = '%R' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + fwrite( STDERR, \cli\Colors::colorize( $msg . "\n", $this->colorize ) ); + } +} + diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php new file mode 100644 index 000000000..bca7f10e7 --- /dev/null +++ b/php/WP_CLI/Loggers/Regular.php @@ -0,0 +1,31 @@ +<?php + +namespace WP_CLI\Loggers; + +class Regular { + + private $colorize; + + function __construct( $colorize ) { + $this->colorize = $colorize; + } + + function line( $message, $handle = STDOUT ) { + fwrite( $handle, \cli\Colors::colorize( $message . "\n", $this->colorize ) ); + } + + function success( $message, $label ) { + $this->line( '%G' . $label . ': %n' . $message ); + } + + function warning( $message, $label ) { + $msg = '%C' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + $this->line( $msg, STDERR ); + } + + function error( $message, $label ) { + $msg = '%R' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + $this->line( $msg, STDERR ); + } +} + diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 107963716..e312e14d2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -229,6 +229,24 @@ private function back_compat_conversions() { } } + private function init_logger() { + if ( isset( $this->assoc_args['no-color'] ) ) { + $color = false; + unset( $this->assoc_args['no-color'] ); + } elseif ( 'auto' === $this->config['color'] ) { + $color = ! \cli\Shell::isPiped(); + } else { + $color = $this->config['color']; + } + + if ( $this->config['quiet'] ) + $logger = new \WP_CLI\Loggers\Quiet( $color ); + else + $logger = new \WP_CLI\Loggers\Regular( $color ); + + WP_CLI::set_logger( $logger ); + } + public function before_wp_load() { $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -250,12 +268,7 @@ public function before_wp_load() { self::split_special( $this->assoc_args, $this->config, $config_spec ); - if ( isset( $this->assoc_args['no-color'] ) ) { - $this->config['color'] = false; - unset( $this->assoc_args['no-color'] ); - } elseif ( 'auto' === $this->config['color'] ) { - $this->config['color'] = ! \cli\Shell::isPiped(); - } + $this->init_logger(); // Handle --version parameter if ( isset( $this->assoc_args['version'] ) && empty( $this->arguments ) ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1a47614f1..0cc024c88 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -12,6 +12,8 @@ class WP_CLI { public static $runner; + private static $logger; + private static $man_dirs = array(); /** @@ -27,6 +29,15 @@ static function init() { self::$runner = new WP_CLI\Runner; } + /** + * Set the logger instance. + * + * @param object $logger + */ + static function set_logger( $logger ) { + self::$logger = $logger; + } + /** * Add a command to the wp-cli list of commands * @@ -91,25 +102,13 @@ static function get_man_dirs() { return self::$man_dirs; } - /** - * Display a message in the cli - * - * @param string $message - */ - static function out( $message, $handle = STDOUT ) { - if ( self::get_config('quiet') ) - return; - - fwrite( $handle, \cli\Colors::colorize( $message, self::get_config('color') ) ); - } - /** * Display a message in the CLI and end with a newline * * @param string $message */ static function line( $message = '' ) { - self::out( $message . "\n" ); + self::$logger->line( $message ); } /** @@ -120,8 +119,7 @@ static function line( $message = '' ) { */ static function error( $message, $label = 'Error' ) { if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { - $msg = '%R' . $label . ': %n' . self::error_to_string( $message ) . "\n"; - fwrite( STDERR, \cli\Colors::colorize( $msg, self::get_config('color') ) ); + self::$logger->error( $message, $label ); } exit(1); @@ -134,7 +132,7 @@ static function error( $message, $label = 'Error' ) { * @param string $label */ static function success( $message, $label = 'Success' ) { - self::line( '%G' . $label . ': %n' . $message ); + self::$logger->success( $message, $label ); } /** @@ -144,8 +142,7 @@ static function success( $message, $label = 'Success' ) { * @param string $label */ static function warning( $message, $label = 'Warning' ) { - $msg = '%C' . $label . ': %n' . self::error_to_string( $message ); - self::out( $msg . "\n", STDERR ); + self::$logger->warning( $message, $label ); } /** @@ -153,7 +150,7 @@ static function warning( $message, $label = 'Warning' ) { */ static function confirm( $question, $assoc_args ) { if ( !isset( $assoc_args['yes'] ) ) { - self::out( $question . " [y/n] " ); + echo $question . " [y/n] "; $answer = trim( fgets( STDIN ) ); diff --git a/php/utils.php b/php/utils.php index 65614d327..e9cad0bd7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -260,7 +260,7 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria */ function format_items( $format, $items, $fields ) { if ( 'ids' == $format ) - \WP_CLI::out( implode( ' ', $items ) ); + echo implode( ' ', $items ); if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); From e085ceb25a0d621ec80f14e64c2f4dc3b268927a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 24 May 2013 16:29:23 +0300 Subject: [PATCH 1715/5359] add back WP_CLI::out(), just to prevent fatal errors --- php/class-wp-cli.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0cc024c88..d30f56ae3 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -265,6 +265,11 @@ public static function run_command( $args, $assoc_args = array() ) { } } + // back-compat + static function out( $str ) { + echo $str; + } + // back-compat static function addCommand( $name, $class ) { trigger_error( sprintf( 'wp %s: %s is deprecated. use WP_CLI::add_command() instead.', From 77e4a4ed91dfdc772474d8be590034e2803ddbde Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Fri, 24 May 2013 08:46:13 -0700 Subject: [PATCH 1716/5359] add an EXAMPLES section that features the --post_types parameter --- man-src/scaffold-taxonomy.txt | 4 ++++ man/scaffold-taxonomy.1 | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt index f3e9a892b..f739fb1f6 100644 --- a/man-src/scaffold-taxonomy.txt +++ b/man-src/scaffold-taxonomy.txt @@ -25,3 +25,7 @@ STDOUT. * `--raw`: Just generate the `register_taxonomy()` call and nothing else. + +## EXAMPLES + + wp scaffold taxonomy venue --post_types=event,presentation diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index ec4586af2..84a1a7900 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -46,4 +46,12 @@ Create a file in the given plugin\'s directory, instead of sending to STDOUT\. . .IP Just generate the \fBregister_taxonomy()\fR call and nothing else\. +. +.SH "EXAMPLES" +. +.nf + +wp scaffold taxonomy venue \-\-post_types=event,presentation +. +.fi From 443ef23fed256098f7719524e8a47755e5307eb9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 May 2013 01:36:07 +0300 Subject: [PATCH 1717/5359] Loggers\Regular: don't expose $handle parameter --- php/WP_CLI/Loggers/Regular.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index bca7f10e7..aa18dd082 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -10,22 +10,26 @@ function __construct( $colorize ) { $this->colorize = $colorize; } - function line( $message, $handle = STDOUT ) { + private function _line( $message, $handle = STDOUT ) { fwrite( $handle, \cli\Colors::colorize( $message . "\n", $this->colorize ) ); } + function line( $message ) { + $this->_line( $message ); + } + function success( $message, $label ) { $this->line( '%G' . $label . ': %n' . $message ); } function warning( $message, $label ) { $msg = '%C' . $label . ': %n' . \WP_CLI::error_to_string( $message ); - $this->line( $msg, STDERR ); + $this->_line( $msg, STDERR ); } function error( $message, $label ) { $msg = '%R' . $label . ': %n' . \WP_CLI::error_to_string( $message ); - $this->line( $msg, STDERR ); + $this->_line( $msg, STDERR ); } } From 71d60af8c7603f84038049e7fa400921903f5de9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 May 2013 01:42:56 +0300 Subject: [PATCH 1718/5359] keep error_to_string() calls inside WP_CLI They assume WP is loaded, by calling is_wp_error(). --- php/WP_CLI/Loggers/Quiet.php | 2 +- php/WP_CLI/Loggers/Regular.php | 4 ++-- php/class-wp-cli.php | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index d080815c5..06a404bb5 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -23,7 +23,7 @@ function warning( $message, $label ) { } function error( $message, $label ) { - $msg = '%R' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + $msg = '%R' . $label . ': %n' . $message; fwrite( STDERR, \cli\Colors::colorize( $msg . "\n", $this->colorize ) ); } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index aa18dd082..65104db23 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -23,12 +23,12 @@ function success( $message, $label ) { } function warning( $message, $label ) { - $msg = '%C' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + $msg = '%C' . $label . ': %n' . $message; $this->_line( $msg, STDERR ); } function error( $message, $label ) { - $msg = '%R' . $label . ': %n' . \WP_CLI::error_to_string( $message ); + $msg = '%R' . $label . ': %n' . $message; $this->_line( $msg, STDERR ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d30f56ae3..c07c602f8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -112,37 +112,37 @@ static function line( $message = '' ) { } /** - * Display an error in the CLI and end with a newline + * Display a success in the CLI and end with a newline * * @param string $message * @param string $label */ - static function error( $message, $label = 'Error' ) { - if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { - self::$logger->error( $message, $label ); - } - - exit(1); + static function success( $message, $label = 'Success' ) { + self::$logger->success( $message, $label ); } /** - * Display a success in the CLI and end with a newline + * Display a warning in the CLI and end with a newline * * @param string $message * @param string $label */ - static function success( $message, $label = 'Success' ) { - self::$logger->success( $message, $label ); + static function warning( $message, $label = 'Warning' ) { + self::$logger->warning( self::error_to_string( $message ), $label ); } /** - * Display a warning in the CLI and end with a newline + * Display an error in the CLI and end with a newline * * @param string $message * @param string $label */ - static function warning( $message, $label = 'Warning' ) { - self::$logger->warning( $message, $label ); + static function error( $message, $label = 'Error' ) { + if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { + self::$logger->error( self::error_to_string( $message ), $label ); + } + + exit(1); } /** From 4b15043008fa053ea33e68ff1e1c70ba7733cc98 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 May 2013 02:11:12 +0300 Subject: [PATCH 1719/5359] don't use is_wp_error() in error_to_string() We want to be able to use it without WP being installed. --- php/class-wp-cli.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index c07c602f8..69199003d 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -196,11 +196,13 @@ static function print_value( $value, $assoc_args = array() ) { * @return string */ static function error_to_string( $errors ) { - if( is_string( $errors ) ) { + if ( is_string( $errors ) ) { return $errors; - } elseif( is_wp_error( $errors ) && $errors->get_error_code() ) { - foreach( $errors->get_error_messages() as $message ) { - if( $errors->get_error_data() ) + } + + if ( is_object( $errors ) && is_a( $errors, 'WP_Error' ) ) { + foreach ( $errors->get_error_messages() as $message ) { + if ( $errors->get_error_data() ) return $message . ' ' . $errors->get_error_data(); else return $message; From 5cacbcfd2c3bf580a00612111945c6b870e59d38 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Fri, 24 May 2013 18:22:52 -0700 Subject: [PATCH 1720/5359] combine similar custom taxonomy tests --- features/scaffold.feature | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index cebd1ff7d..8449990c1 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -37,33 +37,23 @@ Feature: Wordpress code scaffolding # Test for all flags but --label, --theme, --plugin and --raw @tax - Scenario: Scaffold a Custom Taxonomy and attach it to a CPT zombie that is prefixed and has a text domain + Scenario: Scaffold a Custom Taxonomy and attach it to CPTs including one that is prefixed and has a text domain Given a WP install - When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie" --textdomain=zombieland` + When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie,wraith" --textdomain=zombieland` Then STDOUT should contain: """ __( 'Zombie speeds' """ And STDOUT should contain: """ - array( 'prefix-zombie' ) + array( 'prefix-zombie', 'wraith' ) """ And STDOUT should contain: """ __( 'Zombie speeds', 'zombieland' """ - @tax - Scenario: Scaffold a Custom Taxonomy and attach it to multiple post types - Given a WP install - - When I run `wp scaffold taxonomy perambulation-speed --post_types="zombie,wraith" --textdomain=zombieland` - Then STDOUT should contain: - """ - array( 'zombie', 'wraith' ) - """ - @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" Given a WP install From daff963bddae0d2e485790f9882e975a95eb18f7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 26 May 2013 19:57:09 +0300 Subject: [PATCH 1721/5359] clarify that only the bash code was copied from drush --- bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wp b/bin/wp index 0120a18de..f53faf413 100755 --- a/bin/wp +++ b/bin/wp @@ -1,6 +1,6 @@ #!/usr/bin/env sh # -# This script has been adapted from the drush wrapper script +# This wrapper script has been adapted from the equivalent drush wrapper # and 99.9% of all credit should go to the authors of that project: # http://drupal.org/project/drush # And 0.09% to the author of this project: From 85d4d0c8362997ebe6f552408f82f108921c91f8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 27 May 2013 23:37:22 +0300 Subject: [PATCH 1722/5359] TableIterator: rename 'limit' parameter to 'chunk_size', so that it's not confused with SQL LIMIT see https://github.com/wp-cli/wp-cli/commit/b1bd56dd5e2bdc106603c1034affc6a953b5e6b1#commitcomment-3296894 --- php/WP_CLI/Iterators/Query.php | 12 ++++++------ php/WP_CLI/Iterators/Table.php | 5 ++--- php/commands/search-replace.php | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 1577e99ab..016961a0a 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -9,7 +9,7 @@ */ class Query implements \Iterator { - private $limit = 500; + private $chunk_size; private $query = ''; private $global_index = 0; @@ -30,17 +30,17 @@ class Query implements \Iterator { * </code> * * @param string $query The query as a string. It shouldn't include any LIMIT clauses - * @param number $limit How many rows to retrieve at once; default value is 500 (optional) + * @param number $chunk_size How many rows to retrieve at once; default value is 500 (optional) */ - public function __construct( $query, $limit = 500 ) { + public function __construct( $query, $chunk_size = 500 ) { $this->query = $query; - $this->limit = $limit; + $this->chunk_size = $chunk_size; $this->db = $GLOBALS['wpdb']; } private function load_items_from_db() { - $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->limit, $this->offset ); + $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->chunk_size, $this->offset ); $this->results = $this->db->get_results( $query ); if ( !$this->results ) { @@ -51,7 +51,7 @@ private function load_items_from_db() { } } - $this->offset += $this->limit; + $this->offset += $this->chunk_size; return true; } diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 450301ae2..6e05cf9ed 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -44,6 +44,7 @@ function __construct( $args = array() ) { 'fields' => array( '*' ), 'where' => array(), 'table' => null, + 'chunk_size' => 500 ); $table = $args['table']; $args = array_merge( $defaults, $args ); @@ -53,9 +54,7 @@ function __construct( $args = array() ) { $where_sql = $conditions? " WHERE $conditions" : ''; $query = "SELECT $fields FROM $table $where_sql"; - $limit = isset( $args['limit'] ) ? $args['limit'] : 500; - - parent::__construct( $query, $limit ); + parent::__construct( $query, $args['chunk_size'] ); } private static function build_fields( $fields ) { diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index a08af875c..e6bcd5f94 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -67,7 +67,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'table' => $table, 'fields' => array( $primary_key, $col ), 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', - 'limit' => 1000 + 'chunk_size' => 1000 ); $it = new \WP_CLI\Iterators\Table( $args ); From d3515347c2ed7d96746b151196761084117d8e46 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 27 May 2013 15:18:21 -0700 Subject: [PATCH 1723/5359] Add a test for large search/replace failure. --- features/search-replace.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index d5bf8ff4a..f18dd3635 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -14,3 +14,15 @@ Feature: Do global search/replace """ guid """ + + Scenario: Large search/replace + Given a WP install + + And I run `wp post generate --count=1200` + + And I run `wp search-replace $( wp option get siteurl ) testreplacement` + Then STDOUT should be a table containing rows: + """ + Table Column Replacements + wp_posts guid 1202 + """ From 27697bc455cf95472d9b456aaf5706cda8fb908e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 28 May 2013 01:40:57 +0300 Subject: [PATCH 1724/5359] make back_compat_conversion() method static --- php/WP_CLI/Runner.php | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e312e14d2..cd60aefba 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -197,36 +197,39 @@ public function get_wp_config_code() { } // Transparently convert old syntaxes - private function back_compat_conversions() { + private static function back_compat_conversions( $r ) { + list( $args, $assoc_args ) = $r; + // foo --help -> help foo - if ( isset( $this->assoc_args['help'] ) ) { - array_unshift( $this->arguments, 'help' ); - unset( $this->assoc_args['help'] ); + if ( isset( $assoc_args['help'] ) ) { + array_unshift( $args, 'help' ); + unset( $assoc_args['help'] ); } // {plugin|theme} update --all -> {plugin|theme} update-all - if ( count( $this->arguments ) > 1 && in_array( $this->arguments[0], array( 'plugin', 'theme' ) ) - && $this->arguments[1] == 'update' - && isset( $this->assoc_args['all'] ) + if ( count( $args ) > 1 && in_array( $args[0], array( 'plugin', 'theme' ) ) + && $args[1] == 'update' && isset( $assoc_args['all'] ) ) { - $this->arguments[1] = 'update-all'; - unset( $this->assoc_args['all'] ); + $args[1] = 'update-all'; + unset( $assoc_args['all'] ); } // {post|user} list --ids -> {post|user} list --format=ids - if ( count( $this->arguments ) > 1 && in_array( $this->arguments[0], array( 'post', 'user' ) ) - && $this->arguments[1] == 'list' - && isset( $this->assoc_args['ids'] ) + if ( count( $args ) > 1 && in_array( $args[0], array( 'post', 'user' ) ) + && $args[1] == 'list' + && isset( $assoc_args['ids'] ) ) { - $this->assoc_args['format'] = 'ids'; - unset( $this->assoc_args['ids'] ); + $assoc_args['format'] = 'ids'; + unset( $assoc_args['ids'] ); } // --json -> --format=json - if ( isset( $this->assoc_args['json'] ) ) { - $this->assoc_args['format'] = 'json'; - unset( $this->assoc_args['json'] ); + if ( isset( $assoc_args['json'] ) ) { + $assoc_args['format'] = 'json'; + unset( $assoc_args['json'] ); } + + return array( $args, $assoc_args ); } private function init_logger() { @@ -248,11 +251,8 @@ private function init_logger() { } public function before_wp_load() { - $r = Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ); - - list( $this->arguments, $this->assoc_args ) = $r; - - $this->back_compat_conversions(); + list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( + Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ) ); $config_spec = Utils\get_config_spec(); From 41f8ffe5cdbd1f9e44fb09391a1a89e5eacc04ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 28 May 2013 02:03:55 +0300 Subject: [PATCH 1725/5359] alias `wp plugin scaffold` to `wp scaffold plugin` --- features/scaffold.feature | 2 +- php/WP_CLI/Runner.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 8449990c1..6143dd8de 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -16,7 +16,7 @@ Feature: Wordpress code scaffolding And I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} - When I run `wp scaffold plugin zombieland --plugin_name="Welcome to Zombieland" --activate` + When I run `wp plugin scaffold zombieland --plugin_name="Welcome to Zombieland" --activate` Then STDOUT should not be empty And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cd60aefba..245711cb7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -214,6 +214,11 @@ private static function back_compat_conversions( $r ) { unset( $assoc_args['all'] ); } + // plugin scaffold -> scaffold plugin + if ( array( 'plugin', 'scaffold' ) == array_slice( $args, 0, 2 ) ) { + list( $args[0], $args[1] ) = array( $args[1], $args[0] ); + } + // {post|user} list --ids -> {post|user} list --format=ids if ( count( $args ) > 1 && in_array( $args[0], array( 'post', 'user' ) ) && $args[1] == 'list' From fba2f4ee98b2f635ec630430c33bb797fdff64e0 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 27 May 2013 18:56:14 -0700 Subject: [PATCH 1726/5359] Use the STDOUT saving technique so tests can pass. The wp aliases in my PATH made me oblivious before... --- features/search-replace.feature | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index f18dd3635..fa11307e7 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,12 +15,31 @@ Feature: Do global search/replace guid """ - Scenario: Large search/replace + Scenario: Small guid search/replace Given a WP install + When I run `wp option get siteurl` + + And save STDOUT as {SITEURL} + + And I run `wp post generate --count=100` + + And I run `wp search-replace {SITEURL} testreplacement` + Then STDOUT should be a table containing rows: + """ + Table Column Replacements + wp_posts guid 102 + """ + Scenario: Large guid search/replace + Given a WP install + + When I run `wp option get siteurl` + + And save STDOUT as {SITEURL} + And I run `wp post generate --count=1200` - And I run `wp search-replace $( wp option get siteurl ) testreplacement` + And I run `wp search-replace {SITEURL} testreplacement` Then STDOUT should be a table containing rows: """ Table Column Replacements From 132bf3799569db79a2f6ffb5d78cbec8345eaf7c Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 27 May 2013 20:17:02 -0700 Subject: [PATCH 1727/5359] Add a test for the case when the replacement contains the search string. In this case the current code works, but alternatives I was considering might not. Also removed the small test - that case is already covered. --- features/search-replace.feature | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index fa11307e7..2d946ae21 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,22 +15,22 @@ Feature: Do global search/replace guid """ - Scenario: Small guid search/replace + Scenario: Large guid search/replace where replacement contains search Given a WP install When I run `wp option get siteurl` And save STDOUT as {SITEURL} - And I run `wp post generate --count=100` + And I run `wp post generate --count=1200` - And I run `wp search-replace {SITEURL} testreplacement` + And I run `wp search-replace {SITEURL} {SITEURL}/subdir` Then STDOUT should be a table containing rows: """ Table Column Replacements - wp_posts guid 102 + wp_posts guid 1202 """ - Scenario: Large guid search/replace + Scenario: Large guid search/replace where replacement does not contain search Given a WP install When I run `wp option get siteurl` @@ -39,7 +39,7 @@ Feature: Do global search/replace And I run `wp post generate --count=1200` - And I run `wp search-replace {SITEURL} testreplacement` + And I run `wp search-replace {SITEURL} http://newdomain.com` Then STDOUT should be a table containing rows: """ Table Column Replacements From 45770c2d2fef4da9021ef458e4ef55504a7b5872 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Mon, 27 May 2013 20:41:44 -0700 Subject: [PATCH 1728/5359] Adjust chunking based on whether the replacement contains the search string. --- php/commands/search-replace.php | 48 ++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e6bcd5f94..b32b9798a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -63,31 +63,41 @@ public function __invoke( $args, $assoc_args ) { private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { global $wpdb; - $args = array( - 'table' => $table, - 'fields' => array( $primary_key, $col ), - 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', - 'chunk_size' => 1000 - ); + if ( strpos( $new, $old ) !== false ) + $new_contains_old = true; + else + $new_contains_old = false; - $it = new \WP_CLI\Iterators\Table( $args ); + $fields = $primary_key . ', ' . $col; + $conditions = $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"'; + $chunk_size = 1000; + $offset = 0; + + $chunk_query = "SELECT $fields FROM $table WHERE $conditions LIMIT $chunk_size OFFSET $offset"; $count = 0; - foreach ( $it as $row ) { - if ( '' === $row->$col ) - continue; + while ( $chunk = $wpdb->get_results( $chunk_query ) ) { + foreach ( $chunk as $row ) { + if ( '' === $row->$col ) + continue; - $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); + $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); + + if ( $dry_run ) { + if ( $value != $row->$col ) + $count++; + } else { + $count += $wpdb->update( $table, + array( $col => $value ), + array( $primary_key => $row->$primary_key ) + ); + } + } - if ( $dry_run ) { - if ( $value != $row->$col ) - $count++; - } else { - $count += $wpdb->update( $table, - array( $col => $value ), - array( $primary_key => $row->$primary_key ) - ); + if ( $new_contains_old ) { + $offset += $chunk_size; + $chunk_query = "SELECT $fields FROM $table WHERE $conditions LIMIT $chunk_size OFFSET $offset"; } } From ac13794f742ede999054a6a74ae15b5f48b15967 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 28 May 2013 03:03:41 +0300 Subject: [PATCH 1729/5359] behat: use bash function to allow inner calls to `wp` (bash aliases seem to be available only in interactive mode) --- features/bootstrap/FeatureContext.php | 2 +- features/bootstrap/Process.php | 8 +++++++- features/user.feature | 4 +--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 76d2343db..e0478d210 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -31,7 +31,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { public $variables = array(); private static function wp_cli( $command ) { - return __DIR__ . "/../../bin/wp $command"; + return "wp $command"; } // We cache the results of `wp core download` to improve test performance diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 0776a2865..4dddf4225 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -27,7 +27,13 @@ public function run( $subdir = '' ) { 2 => array( 'pipe', 'w' ), ); - $proc = proc_open( $this->command, $descriptors, $pipes, $cwd ); + // Ensure we're using the expected `wp` binary + $env = sprintf( 'function wp() { %s "$@"; }; %s', + realpath( __DIR__ . "/../../bin/wp" ), $this->command ); + + $wrapper = sprintf( 'bash -c %s', escapeshellarg( $env ) ); + + $proc = proc_open( $wrapper, $descriptors, $pipes, $cwd ); $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); diff --git a/features/user.feature b/features/user.feature index 1e8131e58..8743d1273 100644 --- a/features/user.feature +++ b/features/user.feature @@ -23,9 +23,7 @@ Feature: Manage WordPress users Given a WP install # Delete all users - When I run `wp user list --format=ids` - And save STDOUT as {USER_IDS} - And I run `wp user delete {USER_IDS}` + When I run `wp user delete $(wp user list --format=ids)` And I run `wp user list --format=ids` Then STDOUT should be empty From 72f6a58cfaf415abef6b601ee05fc8a155697a1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 28 May 2013 03:38:41 +0300 Subject: [PATCH 1730/5359] behat: don't hardcode `wp ` in the step definitions --- features/bootstrap/FeatureContext.php | 20 ++++++++------------ features/steps/basic_steps.php | 16 +++++----------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index e0478d210..20114ddef 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -30,10 +30,6 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { public $variables = array(); - private static function wp_cli( $command ) { - return "wp $command"; - } - // We cache the results of `wp core download` to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests private static function cache_wp_files() { @@ -42,8 +38,8 @@ private static function cache_wp_files() { if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) return; - $cmd = Utils\esc_cmd( 'core download --force --path=%s', self::$cache_dir ); - Process::create( self::wp_cli( $cmd ) )->run_check(); + $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); + Process::create( $cmd )->run_check(); } /** @@ -53,16 +49,16 @@ public static function prepare( SuiteEvent $event ) { self::cache_wp_files(); self::$additional_args = array( - 'core config' => self::$db_settings, + 'wp core config' => self::$db_settings, - 'core install' => array( + 'wp core install' => array( 'url' => 'http://example.com', 'title' => 'WP CLI Site', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' ), - 'core install-network' => array( + 'wp core install-network' => array( 'title' => 'WP CLI Network' ) ); @@ -165,7 +161,7 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( self::wp_cli( $command ), $this->install_dir ); + return Process::create( $command, $this->install_dir ); } public function move_files( $src, $dest ) { @@ -191,9 +187,9 @@ public function wp_install( $subdir = '' ) { $this->create_empty_dir(); $this->download_wordpress_files( $subdir ); - $this->proc( 'core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); + $this->proc( 'wp core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); - $this->proc( 'core install' )->run_check( $subdir ); + $this->proc( 'wp core install' )->run_check( $subdir ); } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index f838df65c..b2cab9d3b 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -37,7 +37,7 @@ function ( $world ) { $steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->proc( 'core config' )->run_check(); + $world->proc( 'wp core config' )->run_check(); } ); @@ -62,7 +62,7 @@ function ( $world, $subdir ) { $steps->Given( '/^a WP multisite install$/', function ( $world ) { $world->wp_install(); - $world->proc( 'core install-network' )->run_check(); + $world->proc( 'wp core install-network' )->run_check(); } ); @@ -106,20 +106,14 @@ function ( $world ) { } ); -$steps->When( '/^I (run|try) `wp`$/', - function ( $world, $mode ) { - $world->result = invoke_proc( $world->proc( '' ), $mode ); - } -); - -$steps->When( '/^I (run|try) `wp (.+)`$/', +$steps->When( '/^I (run|try) `([^`]+)`$/', function ( $world, $mode, $cmd ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd ), $mode ); } ); -$steps->When( "/^I (run|try) `wp (.+)` from '([^\s]+)'$/", +$steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", function ( $world, $mode, $cmd, $subdir ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd ), $mode, $subdir ); @@ -141,7 +135,7 @@ function ( $world ) { if ( !isset( $world->variables['DOWNLOADED_IMAGE'] ) ) throw new \Exception( 'Cached image not available.' ); - $world->result = $world->proc( 'media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' )->run(); + $world->result = $world->proc( 'wp media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' )->run(); } ); From 611afd7e6fe46d7fe507278e73b411681ac5afae Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Tue, 28 May 2013 06:56:53 -0700 Subject: [PATCH 1731/5359] Generate only as many posts as needed to test chunking. --- features/search-replace.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 2d946ae21..3c3b2ce7c 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -22,13 +22,13 @@ Feature: Do global search/replace And save STDOUT as {SITEURL} - And I run `wp post generate --count=1200` + And I run `wp post generate --count=1000` And I run `wp search-replace {SITEURL} {SITEURL}/subdir` Then STDOUT should be a table containing rows: """ Table Column Replacements - wp_posts guid 1202 + wp_posts guid 1002 """ Scenario: Large guid search/replace where replacement does not contain search Given a WP install @@ -37,11 +37,11 @@ Feature: Do global search/replace And save STDOUT as {SITEURL} - And I run `wp post generate --count=1200` + And I run `wp post generate --count=1000` And I run `wp search-replace {SITEURL} http://newdomain.com` Then STDOUT should be a table containing rows: """ Table Column Replacements - wp_posts guid 1202 + wp_posts guid 1002 """ From 05a89293a491ac9a476863b6b972d28a03b93735 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Tue, 28 May 2013 21:09:44 -0700 Subject: [PATCH 1732/5359] Revert "Adjust chunking based on whether the replacement contains the search string." This reverts commit 45770c2d2fef4da9021ef458e4ef55504a7b5872. --- php/commands/search-replace.php | 48 +++++++++++++-------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b32b9798a..e6bcd5f94 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -63,41 +63,31 @@ public function __invoke( $args, $assoc_args ) { private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { global $wpdb; - if ( strpos( $new, $old ) !== false ) - $new_contains_old = true; - else - $new_contains_old = false; + $args = array( + 'table' => $table, + 'fields' => array( $primary_key, $col ), + 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', + 'chunk_size' => 1000 + ); - $fields = $primary_key . ', ' . $col; - $conditions = $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"'; - $chunk_size = 1000; - $offset = 0; - - $chunk_query = "SELECT $fields FROM $table WHERE $conditions LIMIT $chunk_size OFFSET $offset"; + $it = new \WP_CLI\Iterators\Table( $args ); $count = 0; - while ( $chunk = $wpdb->get_results( $chunk_query ) ) { - foreach ( $chunk as $row ) { - if ( '' === $row->$col ) - continue; + foreach ( $it as $row ) { + if ( '' === $row->$col ) + continue; - $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); - - if ( $dry_run ) { - if ( $value != $row->$col ) - $count++; - } else { - $count += $wpdb->update( $table, - array( $col => $value ), - array( $primary_key => $row->$primary_key ) - ); - } - } + $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); - if ( $new_contains_old ) { - $offset += $chunk_size; - $chunk_query = "SELECT $fields FROM $table WHERE $conditions LIMIT $chunk_size OFFSET $offset"; + if ( $dry_run ) { + if ( $value != $row->$col ) + $count++; + } else { + $count += $wpdb->update( $table, + array( $col => $value ), + array( $primary_key => $row->$primary_key ) + ); } } From 6196545ff8bd58f5b722f189acabbfe7c8820ceb Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Tue, 28 May 2013 21:46:44 -0700 Subject: [PATCH 1733/5359] Add a dry run test to make sure the iterator doesn't depend on updates. --- features/search-replace.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 3c3b2ce7c..3cf524dbd 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -45,3 +45,19 @@ Feature: Do global search/replace Table Column Replacements wp_posts guid 1002 """ + + Scenario: Large guid search/replace dry run where replacement does not contain search + Given a WP install + + When I run `wp option get siteurl` + + And save STDOUT as {SITEURL} + + And I run `wp post generate --count=1000` + + And I run `wp search-replace --dry-run {SITEURL} http://newdomain.com` + Then STDOUT should be a table containing rows: + """ + Table Column Replacements + wp_posts guid 1002 + """ From b58290cde490548479e46bb41ad84c4d969dd673 Mon Sep 17 00:00:00 2001 From: Dylan Kuhn <dylan.k.kuhn@gmail.com> Date: Tue, 28 May 2013 21:47:55 -0700 Subject: [PATCH 1734/5359] Reduce chunk offset to account for updated rows. --- php/WP_CLI/Iterators/Query.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 016961a0a..4fea0301e 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -11,10 +11,12 @@ class Query implements \Iterator { private $chunk_size; private $query = ''; + private $count_query = ''; private $global_index = 0; private $index_in_results = 0; private $results = array(); + private $row_count = 0; private $offset = 0; private $db = null; private $depleted = false; @@ -34,12 +36,38 @@ class Query implements \Iterator { */ public function __construct( $query, $chunk_size = 500 ) { $this->query = $query; + + $this->count_query = preg_replace( '/^.*? FROM /', 'SELECT COUNT(*) FROM ', $query, 1, $replacements ); + if ( $replacements != 1 ) + $this->count_query = ''; + $this->chunk_size = $chunk_size; $this->db = $GLOBALS['wpdb']; } + /** + * Reduces the offset when the query row count shrinks + * + * In cases where the iterated rows are being updated such that they will no + * longer be returned by the original query, the offset must be reduced to + * iterate over all remaining rows. + */ + private function adjust_offset_for_shrinking_result_set() { + if ( empty( $this->count_query ) ) + return; + + $row_count = $this->db->get_var( $this->count_query ); + + if ( $row_count < $this->row_count ) + $this->offset -= $this->row_count - $row_count; + + $this->row_count = $row_count; + } + private function load_items_from_db() { + $this->adjust_offset_for_shrinking_result_set(); + $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->chunk_size, $this->offset ); $this->results = $this->db->get_results( $query ); From f2c94a4e329c3bd25892597fd8783850225aedeb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 29 May 2013 19:41:29 +0300 Subject: [PATCH 1735/5359] behat: change subprocess PATH, instead of creating a function see #475 --- features/bootstrap/Process.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 4dddf4225..36ad7bcfd 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -28,12 +28,9 @@ public function run( $subdir = '' ) { ); // Ensure we're using the expected `wp` binary - $env = sprintf( 'function wp() { %s "$@"; }; %s', - realpath( __DIR__ . "/../../bin/wp" ), $this->command ); - - $wrapper = sprintf( 'bash -c %s', escapeshellarg( $env ) ); - - $proc = proc_open( $wrapper, $descriptors, $pipes, $cwd ); + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, array( + 'PATH' => realpath( __DIR__ . "/../../bin" ) . ':' . getenv( 'PATH' ) + ) ); $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); From f121dfac28e9268f55a03f911e8c2f366441ec46 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 29 May 2013 20:00:24 +0300 Subject: [PATCH 1736/5359] travis: move init script to separate file --- .travis.yml | 11 +---------- bin/ci/install_dependencies.sh | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) create mode 100755 bin/ci/install_dependencies.sh diff --git a/.travis.yml b/.travis.yml index d0a9cebc4..a2fc11f22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,16 +13,7 @@ matrix: - php: 5.4 env: WP_VERSION=3.4.2 -before_script: - # install dependencies - - composer install --dev --no-interaction --prefer-source - - composer require d11wtq/boris=dev-master --no-interaction --prefer-source - - gem install ronn - # set up WP install - - bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ - # set up database - - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot - - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot +before_script: ./bin/ci/install_dependencies.sh script: vendor/bin/phpunit && vendor/bin/behat --format progress diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh new file mode 100755 index 000000000..38049100d --- /dev/null +++ b/bin/ci/install_dependencies.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# called by Travis CI + +set -ex + +# install dependencies +composer install --dev --no-interaction --prefer-source +composer require d11wtq/boris=dev-master --no-interaction --prefer-source +gem install ronn + +# set up WP install +./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ + +# set up database +mysql -e 'CREATE DATABASE wp_cli_test;' -uroot +mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot From a675de3f72d107bc1c4d5304fa295b30df14ecc8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 29 May 2013 20:12:54 +0300 Subject: [PATCH 1737/5359] travis: move main script to separate file --- .travis.yml | 4 ++-- bin/ci/run_build.sh | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100755 bin/ci/run_build.sh diff --git a/.travis.yml b/.travis.yml index a2fc11f22..81e74cf68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,8 @@ matrix: before_script: ./bin/ci/install_dependencies.sh -script: vendor/bin/phpunit && vendor/bin/behat --format progress - +script: ./bin/ci/run_build.sh + notifications: email: on_success: never diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh new file mode 100755 index 000000000..3ed2e35cd --- /dev/null +++ b/bin/ci/run_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -ex + +vendor/bin/phpunit + +vendor/bin/behat --format progress From 7f7a9faab825bdeb2f8295e44b9c0cd0c8492894 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 29 May 2013 20:20:08 +0300 Subject: [PATCH 1738/5359] travis: set WITH_RONN env variable Also, tag behat tests that depend on the ronn gem. We don't care too much about which WP version is installed, so run the ronn tests only once. --- .travis.yml | 6 +++--- bin/ci/install_dependencies.sh | 5 ++++- bin/ci/run_build.sh | 6 +++++- features/help.feature | 3 +++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 81e74cf68..138b44b66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,13 @@ php: - 5.4 env: - - WP_VERSION=latest - - WP_VERSION=3.4.2 + - WP_VERSION=latest + - WP_VERSION=3.4.2 WITH_RONN=1 matrix: exclude: - php: 5.4 - env: WP_VERSION=3.4.2 + env: WP_VERSION=3.4.2 WITH_RONN=1 before_script: ./bin/ci/install_dependencies.sh diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh index 38049100d..02b33c11b 100755 --- a/bin/ci/install_dependencies.sh +++ b/bin/ci/install_dependencies.sh @@ -7,7 +7,10 @@ set -ex # install dependencies composer install --dev --no-interaction --prefer-source composer require d11wtq/boris=dev-master --no-interaction --prefer-source -gem install ronn + +if [ -n "$WITH_RONN" ]; then + gem install ronn +fi # set up WP install ./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh index 3ed2e35cd..aed4ad0bf 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/run_build.sh @@ -4,4 +4,8 @@ set -ex vendor/bin/phpunit -vendor/bin/behat --format progress +if [ -z "$WITH_RONN" ]; then + BEHAT_OPTS="--tags ~@ronn" +fi + +vendor/bin/behat --format progress $BEHAT_OPTS diff --git a/features/help.feature b/features/help.feature index 39ca944d8..b23b898da 100644 --- a/features/help.feature +++ b/features/help.feature @@ -31,6 +31,7 @@ Feature: Get help about WP-CLI commands Then the return code should be 1 And STDERR should not be empty + @ronn Scenario: Generating help for subcommands Given an empty directory When I run `wp help --gen option` @@ -39,6 +40,7 @@ Feature: Get help about WP-CLI commands generated option.1 """ + @ronn Scenario: Generating help for multisite-only subcommands Given an empty directory When I run `wp help --gen blog create` @@ -47,6 +49,7 @@ Feature: Get help about WP-CLI commands generated blog-create.1 """ + @ronn Scenario: Help for third-party commands Given a WP install And a wp-content/plugins/test-cli/test-help.txt file: From e594b0aadf3a5418e22c786d1b52ffab095ff20a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 29 May 2013 22:42:03 +0300 Subject: [PATCH 1739/5359] contributing: clarify workflow --- CONTRIBUTING.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7389047ef..e4b8ec7e9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,19 @@ Contribute ========== -So you've got an awesome idea to throw into WP-CLI. Great! Please keep the following in mind: +So you've got an awesome idea to throw into WP-CLI. Great! Here's the process, in a nutshell: -* The best way to get feedback is by opening an issue or a pull request; if you think the code shouldn't be merged yet, just say so. -* If you're adding a new command or subcommand, please consider adding a functional test for it in the `features` directory. Also, please create the appropriate `.txt` file in the `man-src` directory. -* Please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). +1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. +2. Make the code changes in your fork. +3. Open a pull request. + +It doesn't matter if the code isn't perfect. The idea is to get feedback early and iterate. + +If you're adding a new feature, please add one or more functional tests for it in the `features` directory. See below. + +Also, please create or update the appropriate `.txt` file in the `man-src` directory. See below. + +Lastly, please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). Generating man pages -------------------- From fbd1a9f35c06017999118f5056c2a4ad8080b701 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 01:20:35 +0300 Subject: [PATCH 1740/5359] behat: move utility functions to separate file --- features/bootstrap/support.php | 106 +++++++++++++++++++++++++++++++++ features/steps/basic_steps.php | 102 ------------------------------- 2 files changed, 106 insertions(+), 102 deletions(-) create mode 100644 features/bootstrap/support.php diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php new file mode 100644 index 000000000..64a52bcad --- /dev/null +++ b/features/bootstrap/support.php @@ -0,0 +1,106 @@ +<?php + +// Utility functions used by Behat steps + +function compareContents( $expected, $actual ) { + if ( gettype( $expected ) != gettype( $actual ) ) { + return false; + } + + if ( is_object( $expected ) ) { + foreach ( get_object_vars( $expected ) as $name => $value ) { + if ( ! compareContents( $value, $actual->$name ) ) + return false; + } + } else if ( is_array( $expected ) ) { + foreach ( $expected as $key => $value ) { + if ( ! compareContents( $value, $actual[$key] ) ) + return false; + } + } else { + return $expected === $actual; + } + + return true; +} + +/** + * Compare two strings containing JSON to ensure that @a $actualJson contains at + * least what the JSON string @a $expectedJson contains. + * + * @return whether or not @a $actualJson contains @a $expectedJson + * @retval true @a $actualJson contains @a $expectedJson + * @retval false @a $actualJson does not contain @a $expectedJson + * + * @param[in] $actualJson the JSON string to be tested + * @param[in] $expectedJson the expected JSON string + * + * Examples: + * expected: {'a':1,'array':[1,3,5]} + * + * 1 ) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: true + * + * 2 ) + * actual: {'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * element 'a' is missing from the root object + * + * 3 ) + * actual: {'a':0,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * the value of element 'a' is not 1 + * + * 4 ) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,4,5]} + * return: false + * the contents of 'array' does not include 3 + */ +function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { + $actualValue = json_decode( $actualJson ); + $expectedValue = json_decode( $expectedJson ); + + if ( !$actualValue ) { + return false; + } + + return compareContents( $expectedValue, $actualValue ); +} + +/** + * Compare two strings to confirm $actualCSV contains $expectedCSV + * Both strings are expected to have headers for their CSVs. + * $actualCSV must match all data rows in $expectedCSV + * + * @return bool Whether $actualCSV contacts $expectedCSV + */ +function checkThatCsvStringContainsCsvString( $actualCSV, $expectedCSV ) { + $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); + $expectedCSV = array_map( 'str_getcsv', explode( PHP_EOL, $expectedCSV ) ); + + if ( empty( $actualCSV ) ) + return false; + + // Each sample must have headers + $actualHeaders = array_values( array_shift( $actualCSV ) ); + $expectedHeaders = array_values( array_shift( $expectedCSV ) ); + + // Each expectedCSV must exist somewhere in actualCSV in the proper column + $expectedResult = 0; + foreach ( $expectedCSV as $expected_row ) { + $expected_row = array_combine( $expectedHeaders, $expected_row ); + foreach ( $actualCSV as $actual_row ) { + + if ( count( $actualHeaders ) != count( $actual_row ) ) + continue; + + $actual_row = array_intersect_key( array_combine( $actualHeaders, $actual_row ), $expected_row ); + if ( $actual_row == $expected_row ) + $expectedResult++; + } + } + + return $expectedResult >= count( $expectedCSV ); +} + diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index b2cab9d3b..c020b4873 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -255,105 +255,3 @@ function ( $world, $path ) { } ); -/** - * Compare two strings containing JSON to ensure that @a $actualJson contains at - * least what the JSON string @a $expectedJson contains. - * - * @return whether or not @a $actualJson contains @a $expectedJson - * @retval true @a $actualJson contains @a $expectedJson - * @retval false @a $actualJson does not contain @a $expectedJson - * - * @param[in] $actualJson the JSON string to be tested - * @param[in] $expectedJson the expected JSON string - * - * Examples: - * expected: {'a':1,'array':[1,3,5]} - * - * 1) - * actual: {'a':1,'b':2,'c':3,'array':[1,2,3,4,5]} - * return: true - * - * 2) - * actual: {'b':2,'c':3,'array':[1,2,3,4,5]} - * return: false - * element 'a' is missing from the root object - * - * 3) - * actual: {'a':0,'b':2,'c':3,'array':[1,2,3,4,5]} - * return: false - * the value of element 'a' is not 1 - * - * 4) - * actual: {'a':1,'b':2,'c':3,'array':[1,2,4,5]} - * return: false - * the contents of 'array' does not include 3 - */ -function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { - $actualValue = json_decode( $actualJson ); - $expectedValue = json_decode( $expectedJson ); - - if ( !$actualValue ) { - return false; - } - - return compareContents( $expectedValue, $actualValue ); -} - -function compareContents( $expected, $actual ) { - if ( gettype( $expected ) != gettype( $actual ) ) { - return false; - } - - if ( is_object( $expected ) ) { - foreach ( get_object_vars( $expected ) as $name => $value ) { - if ( ! compareContents( $value, $actual->$name ) ) - return false; - } - } else if ( is_array( $expected ) ) { - foreach ( $expected as $key => $value ) { - if ( ! compareContents( $value, $actual[$key] ) ) - return false; - } - } else { - return $expected === $actual; - } - - return true; -} - -/** - * Compare two strings to confirm $actualCSV contains $expectedCSV - * Both strings are expected to have headers for their CSVs. - * $actualCSV must match all data rows in $expectedCSV - * - * @return bool Whether $actualCSV contacts $expectedCSV - */ -function checkThatCsvStringContainsCsvString( $actualCSV, $expectedCSV ) { - - $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); - $expectedCSV = array_map( 'str_getcsv', explode( PHP_EOL, $expectedCSV ) ); - - if ( empty( $actualCSV ) ) - return false; - - // Each sample must have headers - $actualHeaders = array_values( array_shift( $actualCSV ) ); - $expectedHeaders = array_values( array_shift( $expectedCSV ) ); - - // Each expectedCSV must exist somewhere in actualCSV in the proper column - $expectedResult = 0; - foreach( $expectedCSV as $expected_row ) { - $expected_row = array_combine( $expectedHeaders, $expected_row ); - foreach( $actualCSV as $actual_row ) { - - if ( count( $actualHeaders ) != count( $actual_row ) ) - continue; - - $actual_row = array_intersect_key( array_combine( $actualHeaders, $actual_row ), $expected_row ); - if ( $actual_row == $expected_row ) - $expectedResult++; - } - } - - return $expectedResult >= count( $expectedCSV ); -} From 2a10fb74af51e7c8449c0b52f5831a4f6a7c5205 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 02:04:50 +0300 Subject: [PATCH 1741/5359] behat: add aditional args if command merely starts with a given string --- features/bootstrap/FeatureContext.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 20114ddef..66b3bfb3e 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -153,9 +153,11 @@ public function drop_db() { } public function proc( $command, $assoc_args = array() ) { - if ( isset( self::$additional_args[ $command ] ) ) { - $assoc_args = array_merge( self::$additional_args[ $command ], - $assoc_args ); + foreach ( self::$additional_args as $start => $additional_args ) { + if ( 0 === strpos( $command, $start ) ) { + $assoc_args = array_merge( $additional_args, $assoc_args ); + break; + } } if ( !empty( $assoc_args ) ) From e27c5d6c66003a8f1ec8a7337eed8d1e03cb8c7d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 02:12:14 +0300 Subject: [PATCH 1742/5359] behat: extend 'the file should' step --- features/bootstrap/support.php | 24 ++++++++++++++++++++++ features/steps/basic_steps.php | 37 +++++++++------------------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 64a52bcad..178df3ad2 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -2,6 +2,30 @@ // Utility functions used by Behat steps +function checkString( $output, $expected, $action ) { + switch ( $action ) { + + case 'be': + $r = $expected === rtrim( $output, "\n" ); + break; + + case 'contain': + $r = false !== strpos( $output, $expected ); + break; + + case 'not contain': + $r = false === strpos( $output, $expected ); + break; + + default: + throw new Behat\Behat\Exception\PendingException(); + } + + if ( !$r ) { + throw new Exception( $output ); + } +} + function compareContents( $expected, $actual ) { if ( gettype( $expected ) != gettype( $actual ) ) { return false; diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index c020b4873..3367484f9 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -1,7 +1,6 @@ <?php -use Behat\Behat\Exception\PendingException, - Behat\Gherkin\Node\PyStringNode, +use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; function invoke_proc( $proc, $mode, $subdir = null ) { @@ -153,31 +152,9 @@ function ( $world, $return_code ) { $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { - $output = $world->result->$stream; - $expected = $world->replace_variables( (string) $expected ); - switch ( $action ) { - - case 'be': - $r = $expected === rtrim( $output, "\n" ); - break; - - case 'contain': - $r = false !== strpos( $output, $expected ); - break; - - case 'not contain': - $r = false === strpos( $output, $expected ); - break; - - default: - throw new PendingException(); - } - - if ( !$r ) { - throw new \Exception( $output ); - } + checkString( $world->result->$stream, $expected, $action ); } ); @@ -243,8 +220,8 @@ function ( $world, $stream ) { } ); -$steps->Then( '/^the (.+) file should exist$/', - function ( $world, $path ) { +$steps->Then( '/^the (.+) file should (exist|be:|contain:|not contain:)$/', + function ( $world, $path, $action, $expected = null ) { $path = $world->replace_variables( $path ); // If it's a relative path, make it relative to the current test dir @@ -252,6 +229,12 @@ function ( $world, $path ) { $path = $world->get_path( $path ); assertFileExists( $path ); + + if ( 'exist' !== $action ) { + $action = substr( $action, 0, -1 ); + $expected = $world->replace_variables( (string) $expected ); + checkString( file_get_contents( $path ), $expected, $action ); + } } ); From 4057bd0b251c0b8efa655d0cc911890c2cc067e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 03:34:24 +0300 Subject: [PATCH 1743/5359] behat: pass BEHAT_RUN env variable see #473 --- features/bootstrap/Process.php | 3 ++- php/commands/search-replace.php | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 36ad7bcfd..792277d9c 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -29,7 +29,8 @@ public function run( $subdir = '' ) { // Ensure we're using the expected `wp` binary $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, array( - 'PATH' => realpath( __DIR__ . "/../../bin" ) . ':' . getenv( 'PATH' ) + 'PATH' => realpath( __DIR__ . "/../../bin" ) . ':' . getenv( 'PATH' ), + 'BEHAT_RUN' => 1 ) ); $STDOUT = stream_get_contents( $pipes[1] ); diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e6bcd5f94..3a2af0889 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -63,11 +63,14 @@ public function __invoke( $args, $assoc_args ) { private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { global $wpdb; + // We don't want to have to generate thousands of rows when running the test suite + $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; + $args = array( 'table' => $table, 'fields' => array( $primary_key, $col ), 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', - 'chunk_size' => 1000 + 'chunk_size' => $chunk_size ); $it = new \WP_CLI\Iterators\Table( $args ); From 8e6c8c4e5d1a32f45c0d5d06bf42cef3052ff077 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 02:46:58 +0300 Subject: [PATCH 1744/5359] behat: use table in 'should be a table containing rows' step --- features/post.feature | 8 +++----- features/search-replace.feature | 19 +++++++------------ features/steps/basic_steps.php | 8 +++++--- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/features/post.feature b/features/post.feature index 499224754..0e0c3c166 100644 --- a/features/post.feature +++ b/features/post.feature @@ -40,11 +40,9 @@ Feature: Manage WordPress posts When I run `wp post get --format=table {POST_ID}` Then STDOUT should be a table containing rows: - """ - Field Value - ID {POST_ID} - post_title Test post - """ + | Field | Value | + | ID | {POST_ID} | + | post_title | Test post | When I run `wp post get --format=json {POST_ID}` Then STDOUT should be JSON containing: diff --git a/features/search-replace.feature b/features/search-replace.feature index 3cf524dbd..1dd40fcba 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -26,10 +26,9 @@ Feature: Do global search/replace And I run `wp search-replace {SITEURL} {SITEURL}/subdir` Then STDOUT should be a table containing rows: - """ - Table Column Replacements - wp_posts guid 1002 - """ + | Table | Column | Replacements | + | wp_posts | guid | 1002 | + Scenario: Large guid search/replace where replacement does not contain search Given a WP install @@ -41,10 +40,8 @@ Feature: Do global search/replace And I run `wp search-replace {SITEURL} http://newdomain.com` Then STDOUT should be a table containing rows: - """ - Table Column Replacements - wp_posts guid 1002 - """ + | Table | Column | Replacements | + | wp_posts | guid | 1002 | Scenario: Large guid search/replace dry run where replacement does not contain search Given a WP install @@ -57,7 +54,5 @@ Feature: Do global search/replace And I run `wp search-replace --dry-run {SITEURL} http://newdomain.com` Then STDOUT should be a table containing rows: - """ - Table Column Replacements - wp_posts guid 1002 - """ + | Table | Column | Replacements | + | wp_posts | guid | 1002 | diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 3367484f9..747de6472 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -165,12 +165,14 @@ function ( $world, $stream, $format ) { ); $steps->Then( '/^STDOUT should be a table containing rows:$/', - function ( $world, PyStringNode $expected ) { + function ( $world, TableNode $expected ) { $output = $world->result->STDOUT; $outputRows = explode( "\n", rtrim( $output, "\n" ) ); - $expected = $world->replace_variables( (string) $expected ); - $expectedRows = explode( "\n", rtrim( $expected, "\n" ) ); + $expectedRows = array(); + foreach ( $expected->getRows() as $row ) { + $expectedRows[] = $world->replace_variables( implode( "\t", $row ) ); + } // the first row is the header and must be present if ( $expectedRows[0] != $outputRows[0] ) { From 8192d51d6741001ac4bd1f6662d9455117ba052d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 03:36:47 +0300 Subject: [PATCH 1745/5359] behat: refactor search-replace tests by using a scenario outline --- features/search-replace.feature | 45 ++++++++------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 1dd40fcba..978959bab 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,44 +15,19 @@ Feature: Do global search/replace guid """ - Scenario: Large guid search/replace where replacement contains search + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install - - When I run `wp option get siteurl` - + And I run `wp option get siteurl` And save STDOUT as {SITEURL} + And I run `wp post generate --count=20` - And I run `wp post generate --count=1000` - - And I run `wp search-replace {SITEURL} {SITEURL}/subdir` + When I run `wp search-replace <flags> {SITEURL} <replacement>` Then STDOUT should be a table containing rows: | Table | Column | Replacements | - | wp_posts | guid | 1002 | - - Scenario: Large guid search/replace where replacement does not contain search - Given a WP install - - When I run `wp option get siteurl` + | wp_posts | guid | 22 | - And save STDOUT as {SITEURL} - - And I run `wp post generate --count=1000` - - And I run `wp search-replace {SITEURL} http://newdomain.com` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_posts | guid | 1002 | - - Scenario: Large guid search/replace dry run where replacement does not contain search - Given a WP install - - When I run `wp option get siteurl` - - And save STDOUT as {SITEURL} - - And I run `wp post generate --count=1000` - - And I run `wp search-replace --dry-run {SITEURL} http://newdomain.com` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_posts | guid | 1002 | + Examples: + | replacement | flags | + | {SITEURL}/subdir | | + | http://newdomain.com | | + | http://newdomain.com | --dry-run | From 0de17883f863c26a0d4b00dde171ce920a8dbe7e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 03:56:16 +0300 Subject: [PATCH 1746/5359] behat: use table in 'should be CSV containing' step --- features/bootstrap/support.php | 7 ++++--- features/post.feature | 8 +++----- features/steps/basic_steps.php | 12 +++++++++--- features/term.feature | 6 ++---- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 178df3ad2..d213ea3de 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -97,11 +97,12 @@ function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { * Both strings are expected to have headers for their CSVs. * $actualCSV must match all data rows in $expectedCSV * - * @return bool Whether $actualCSV contacts $expectedCSV + * @param string A CSV string + * @param array A nested array of values + * @return bool Whether $actualCSV contains $expectedCSV */ -function checkThatCsvStringContainsCsvString( $actualCSV, $expectedCSV ) { +function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); - $expectedCSV = array_map( 'str_getcsv', explode( PHP_EOL, $expectedCSV ) ); if ( empty( $actualCSV ) ) return false; diff --git a/features/post.feature b/features/post.feature index 0e0c3c166..035be2982 100644 --- a/features/post.feature +++ b/features/post.feature @@ -61,8 +61,6 @@ Feature: Manage WordPress posts When I run `wp post list --post_type='post' --fields=post_title,post_name,post_status --format=csv` Then STDOUT should be CSV containing: - """ - post_title,post_name,post_status - "Publish post",publish-post,publish - "Draft post",,draft - """ + | post_title | post_name | post_status | + | Publish post | publish-post | publish | + | Draft post | | draft | diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 747de6472..ec5a0fe8f 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -199,11 +199,17 @@ function ( $world, PyStringNode $expected ) { }); $steps->Then( '/^STDOUT should be CSV containing:$/', - function( $world, PyStringNode $expected ) { + function( $world, TableNode $expected ) { $output = $world->result->STDOUT; - $expected = $world->replace_variables( (string) $expected ); - if ( ! checkThatCsvStringContainsCsvString( $output, $expected ) ) + $expectedRows = $expected->getRows(); + foreach ( $expected as &$row ) { + foreach ( $row as &$value ) { + $value = $world->replace_variables( $value ); + } + } + + if ( ! checkThatCsvStringContainsValues( $output, $expectedRows ) ) throw new \Exception( $output ); } ); diff --git a/features/term.feature b/features/term.feature index 7a6442d45..df7dea76c 100644 --- a/features/term.feature +++ b/features/term.feature @@ -17,10 +17,8 @@ Feature: Manage WordPress terms When I run `wp term list post_tag --fields=name,slug --format=csv` Then STDOUT should be CSV containing: - """ - name,slug - "Test term",test - """ + | name | slug | + | Test term | test | Scenario: Creating/deleting a term Given a WP install From 9f561881756524df46b3366c4b0d65f760120358 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 03:02:09 +0300 Subject: [PATCH 1747/5359] first pass at ditching wp-admin/setup-config.php --- features/core.feature | 17 +++++++-- man-src/core-config.txt | 15 ++++++++ php/commands/core.php | 44 ++++++++++++++++------- templates/wp-config.mustache | 68 ++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 templates/wp-config.mustache diff --git a/features/core.feature b/features/core.feature index b9497e37e..a61b01b70 100644 --- a/features/core.feature +++ b/features/core.feature @@ -25,14 +25,25 @@ Feature: Manage WordPress installation When I try `wp core install` Then the return code should be 1 - Then STDERR should be: + And STDERR should be: """ Error: wp-config.php not found. Either create one manually or use `wp core config`. """ - When I run `wp core config` - Then the wp-config.php file should exist + Given a wp-config-extra.php file: + """ + define( 'WP_DEBUG_LOG', true ); + """ + When I run `wp core config --extra-php < wp-config-extra.php` + Then the wp-config.php file should contain: + """ + define('AUTH_SALT', + """ + And the wp-config.php file should contain: + """ + define( 'WP_DEBUG_LOG', true ); + """ Scenario: Database doesn't exist Given an empty directory diff --git a/man-src/core-config.txt b/man-src/core-config.txt index 5b3345010..203927aad 100644 --- a/man-src/core-config.txt +++ b/man-src/core-config.txt @@ -19,3 +19,18 @@ * `--dbprefix`=<dbprefix>: Set the database table prefix. Default: 'wp_' + +* `--extra-php`: + + If set, the command reads additional PHP code from STDIN. + +## EXAMPLES + +# Standard wp-config.php file: +wp core config --dbname=testing --dbuser=wp --dbpass=securepswd + +# Enable WP_DEBUG and WP_DEBUG_LOG +wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP +define( 'WP_DEBUG', true ); +define( 'WP_DEBUG_LOG', true ); +PHP diff --git a/php/commands/core.php b/php/commands/core.php index 24ce49d44..2e0de6aee 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -44,31 +44,49 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } + private static function _download( $url ) { + exec( 'curl -s ' . escapeshellarg( $url ), $lines, $r ); + if ( $r ) exit( $r ); + return implode( "\n", $lines ); + } + private function get_download_offer( $locale ) { - $out = exec( 'curl -s ' . escapeshellarg( 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ), $lines, $r ); - if ($r) exit($r); + $out = unserialize( self::_download( + 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ) ); - $out = unserialize( $out ); return $out['offers'][0]; } /** * Set up a wp-config.php file. * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--extra-php] */ public function config( $args, $assoc_args ) { - $_POST['dbname'] = $assoc_args['dbname']; - $_POST['uname'] = $assoc_args['dbuser']; - $_POST['pwd'] = isset( $assoc_args['dbpass'] ) ? $assoc_args['dbpass'] : ''; - $_POST['dbhost'] = isset( $assoc_args['dbhost'] ) ? $assoc_args['dbhost'] : 'localhost'; - $_POST['prefix'] = isset( $assoc_args['dbprefix'] ) ? $assoc_args['dbprefix'] : 'wp_'; + // TODO: check if wp-config.php already exists + + if ( isset( $assoc_args['extra-php'] ) ) { + $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); + } + + if ( isset( $assoc_args['dbprefix'] ) ) { + if ( preg_match( '|[^a-z0-9_]|i', $assoc_args['dbprefix'] ) ) + WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); + } else { + $assoc_args['dbprefix'] = 'wp_'; + } + + // TODO: check db connection + + // TODO: adapt more resilient code from wp-admin/setup-config.php + $assoc_args['keys-and-salts'] = self::_download( + 'https://api.wordpress.org/secret-key/1.1/salt/' ); + + $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); - $_GET['step'] = 2; + file_put_contents( ABSPATH . 'wp-config.php', $out ); - if ( WP_CLI::get_config('quiet') ) ob_start(); - require ABSPATH . '/wp-admin/setup-config.php'; - if ( WP_CLI::get_config('quiet') ) ob_end_clean(); + WP_CLI::success( 'Generated wp-config.php file.' ); } /** diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache new file mode 100644 index 000000000..9c1442a03 --- /dev/null +++ b/templates/wp-config.mustache @@ -0,0 +1,68 @@ +<?php +/** + * The base configurations of the WordPress. + * + * This file has the following configurations: MySQL settings, Table Prefix, + * Secret Keys, WordPress Language, and ABSPATH. You can find more information + * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing + * wp-config.php} Codex page. You can get the MySQL settings from your web host. + * @package WordPress + */ + +// ** MySQL settings - You can get this info from your web host ** // +/** The name of the database for WordPress */ +define('DB_NAME', '{{dbname}}'); + +/** MySQL database username */ +define('DB_USER', '{{dbuser}}'); + +/** MySQL database password */ +define('DB_PASSWORD', '{{dbpass}}'); + +/** MySQL hostname */ +define('DB_HOST', '{{dbhost}}'); + +/** Database Charset to use in creating database tables. */ +define('DB_CHARSET', 'utf8'); + +/** The Database Collate type. Don't change this if in doubt. */ +define('DB_COLLATE', ''); + +/**#@+ + * Authentication Unique Keys and Salts. + * + * Change these to different unique phrases! + * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} + * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. + */ +{{{keys-and-salts}}} +/**#@-*/ + +/** + * WordPress Database Table prefix. + * + * You can have multiple installations in one database if you give each a unique + * prefix. Only numbers, letters, and underscores please! + */ +$table_prefix = '{{dbprefix}}'; + +/** + * WordPress Localized Language, defaults to English. + * + * Change this to localize WordPress. A corresponding MO file for the chosen + * language must be installed to wp-content/languages. For example, install + * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German + * language support. + */ +define('WPLANG', ''); + +{{{extra-php}}} + +/* That's all, stop editing! Happy blogging. */ + +/** Absolute path to the WordPress directory. */ +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + +/** Sets up WordPress vars and included files. */ +require_once(ABSPATH . 'wp-settings.php'); From e13bc3c0c241aa32764fa15fe9894f4db1dd089b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 15:17:21 +0300 Subject: [PATCH 1748/5359] core config: abort if wp-config.php already exists --- features/core.feature | 4 ++++ php/commands/core.php | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index a61b01b70..eb9d7339d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -45,6 +45,10 @@ Feature: Manage WordPress installation define( 'WP_DEBUG_LOG', true ); """ + When I try the previous command again + Then the return code should be 1 + And STDERR should not be empty + Scenario: Database doesn't exist Given an empty directory And WP files diff --git a/php/commands/core.php b/php/commands/core.php index 2e0de6aee..824c2fad0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -63,7 +63,9 @@ private function get_download_offer( $locale ) { * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--extra-php] */ public function config( $args, $assoc_args ) { - // TODO: check if wp-config.php already exists + if ( Utils\locate_wp_config() ) { + WP_CLI::error( "The 'wp-config.php' file already exists." ); + } if ( isset( $assoc_args['extra-php'] ) ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); From f5b5f04ab49dd64c133141e6a36008868356fb0e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 15:32:00 +0300 Subject: [PATCH 1749/5359] core config: check DB credentials --- php/commands/core.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 824c2fad0..37d6a6d20 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -62,24 +62,31 @@ private function get_download_offer( $locale ) { * * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--extra-php] */ - public function config( $args, $assoc_args ) { + public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { WP_CLI::error( "The 'wp-config.php' file already exists." ); } + $defaults = array( + 'dbhost' => 'localhost', + 'dbprefix' => 'wp_' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + if ( preg_match( '|[^a-z0-9_]|i', $assoc_args['dbprefix'] ) ) + WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); + + // Check DB connection + Utils\run_mysql_query( ';', array( + 'host' => $assoc_args['dbhost'], + 'user' => $assoc_args['dbuser'], + 'pass' => $assoc_args['dbpass'], + ) ); + if ( isset( $assoc_args['extra-php'] ) ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); } - if ( isset( $assoc_args['dbprefix'] ) ) { - if ( preg_match( '|[^a-z0-9_]|i', $assoc_args['dbprefix'] ) ) - WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); - } else { - $assoc_args['dbprefix'] = 'wp_'; - } - - // TODO: check db connection - // TODO: adapt more resilient code from wp-admin/setup-config.php $assoc_args['keys-and-salts'] = self::_download( 'https://api.wordpress.org/secret-key/1.1/salt/' ); From 7bd54f449685f1f4e270b01b1b6edd59ee756597 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 15:50:57 +0300 Subject: [PATCH 1750/5359] core config: update man page [ci skip] --- man-src/core-config.txt | 16 ++++++++-------- man/core-config.1 | 23 ++++++++++++++++++++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/man-src/core-config.txt b/man-src/core-config.txt index 203927aad..2f5920998 100644 --- a/man-src/core-config.txt +++ b/man-src/core-config.txt @@ -26,11 +26,11 @@ ## EXAMPLES -# Standard wp-config.php file: -wp core config --dbname=testing --dbuser=wp --dbpass=securepswd - -# Enable WP_DEBUG and WP_DEBUG_LOG -wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP -define( 'WP_DEBUG', true ); -define( 'WP_DEBUG_LOG', true ); -PHP + # Standard wp-config.php file + wp core config --dbname=testing --dbuser=wp --dbpass=securepswd + + # Enable WP_DEBUG and WP_DEBUG_LOG + wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP + define( 'WP_DEBUG', true ); + define( 'WP_DEBUG_LOG', true ); + PHP diff --git a/man/core-config.1 b/man/core-config.1 index 47e893b7b..4a8d6e8d9 100644 --- a/man/core-config.1 +++ b/man/core-config.1 @@ -7,7 +7,7 @@ \fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. . .SH "SYNOPSIS" -wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] +wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] [\-\-extra\-php] . .SH "OPTIONS" . @@ -40,4 +40,25 @@ Set the database host\. Default: \'localhost\' . .IP Set the database table prefix\. Default: \'wp_\' +. +.TP +\fB\-\-extra\-php\fR: +. +.IP +If set, the command reads additional PHP code from STDIN\. +. +.SH "EXAMPLES" +. +.nf + +# Standard wp\-config\.php file +wp core config \-\-dbname=testing \-\-dbuser=wp \-\-dbpass=securepswd + +# Enable WP_DEBUG and WP_DEBUG_LOG +wp core config \-\-dbname=testing \-\-dbuser=wp \-\-dbpass=securepswd \-\-extra\-php <<PHP +define( \'WP_DEBUG\', true ); +define( \'WP_DEBUG_LOG\', true ); +PHP +. +.fi From a834ef1e5fae0da5319731a561653d08efea19d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 May 2013 21:28:11 +0300 Subject: [PATCH 1751/5359] move Utils\set_user() to Runner::set_user() it's not a general-purpose utility and it shouldn't be public --- php/WP_CLI/Runner.php | 20 +++++++++++++++++++- php/utils-wp.php | 18 ------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 245711cb7..b0f9b9c91 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -109,6 +109,23 @@ private static function set_wp_root( $config ) { define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); } + private static function set_user( $assoc_args ) { + if ( !isset( $assoc_args['user'] ) ) + return; + + $user = $assoc_args['user']; + + if ( is_numeric( $user ) ) { + $user_id = (int) $user; + } else { + $user_id = (int) username_exists( $user ); + } + + if ( !$user_id || !wp_set_current_user( $user_id ) ) { + \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); + } + } + private static function is_absolute_path( $path ) { // Windows if ( ':' === $path[1] ) @@ -355,7 +372,8 @@ public function before_wp_load() { public function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - Utils\set_user( $this->config ); + // Handle --user parameter + self::set_user( $this->config ); if ( isset( $this->config['require'] ) ) require $this->config['require']; diff --git a/php/utils-wp.php b/php/utils-wp.php index f5c2afe85..5d42c52c8 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -52,24 +52,6 @@ function maybe_require( $since, $path ) { require $path; } -// Handle --user parameter -function set_user( $assoc_args ) { - if ( !isset( $assoc_args['user'] ) ) - return; - - $user = $assoc_args['user']; - - if ( is_numeric( $user ) ) { - $user_id = (int) $user; - } else { - $user_id = (int) username_exists( $user ); - } - - if ( !$user_id || !wp_set_current_user( $user_id ) ) { - \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); - } -} - function get_upgrader( $class ) { if ( !class_exists( '\WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; From ca7b4f1319f48f34a51a8bce4c4c1d5598d1f252 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 26 May 2013 05:28:53 +0300 Subject: [PATCH 1752/5359] extract find_command_to_run() method --- php/class-wp-cli.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 69199003d..1daf81559 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -243,14 +243,8 @@ static function get_config( $key = null ) { return self::$runner->config[ $key ]; } - /** - * Run a given command. - * - * @param array - * @param array - */ - public static function run_command( $args, $assoc_args = array() ) { - $command = self::$root; + private static function find_command_to_run( $args ) { + $command = \WP_CLI::$root; while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { $subcommand = $command->pre_invoke( $args ); @@ -260,10 +254,22 @@ public static function run_command( $args, $assoc_args = array() ) { $command = $subcommand; } + return array( $command, $args ); + } + + /** + * Run a given command. + * + * @param array + * @param array + */ + public static function run_command( $args, $assoc_args = array() ) { + list( $command, $final_args ) = self::find_command_to_run( $args ); + if ( $command instanceof Dispatcher\CommandContainer ) { $command->show_usage(); } else { - $command->invoke( $args, $assoc_args ); + $command->invoke( $final_args, $assoc_args ); } } From 3d046d1a1ec22000c521f507adf4a75d983be59e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 26 May 2013 05:22:23 +0300 Subject: [PATCH 1753/5359] make load_command() and load_all_commands() standalone utilities --- php/WP_CLI/Dispatcher/RootCommand.php | 49 +++++---------------------- php/utils.php | 21 ++++++++++++ 2 files changed, 29 insertions(+), 41 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 4c74f82cb..e47721aef 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -2,6 +2,8 @@ namespace WP_CLI\Dispatcher; +use \WP_CLI\Utils; + class RootCommand extends AbstractCommandContainer implements Documentable { function get_name() { @@ -93,54 +95,19 @@ function find_subcommand( &$args ) { if ( isset( $aliases[ $command ] ) ) $command = $aliases[ $command ]; - return $this->load_command( $command ); - } - - function get_subcommands() { - $this->load_all_commands(); - - return parent::get_subcommands(); - } - - protected function load_all_commands() { - $cmd_dir = WP_CLI_ROOT . "commands"; + Utils\load_command( $command ); - $iterator = new \DirectoryIterator( $cmd_dir ); - - foreach ( $iterator as $filename ) { - if ( '.php' != substr( $filename, -4 ) ) - continue; - - $command = substr( $filename, 0, -4 ); - - if ( isset( $this->subcommands[ $command ] ) ) - continue; - - include "$cmd_dir/$filename"; - } - } - - protected static function get_command_file( $command ) { - $path = WP_CLI_ROOT . "/commands/$command.php"; - - if ( !is_readable( $path ) ) { + if ( !isset( $this->subcommands[ $command ] ) ) { return false; } - return $path; + return $this->subcommands[ $command ]; } - protected function load_command( $command ) { - if ( !isset( $this->subcommands[ $command ] ) ) { - if ( $path = self::get_command_file( $command ) ) - include $path; - } - - if ( !isset( $this->subcommands[ $command ] ) ) { - return false; - } + function get_subcommands() { + Utils\load_all_commands(); - return $this->subcommands[ $command ]; + return parent::get_subcommands(); } } diff --git a/php/utils.php b/php/utils.php index e9cad0bd7..5c4da7752 100644 --- a/php/utils.php +++ b/php/utils.php @@ -30,6 +30,27 @@ function load_dependencies() { include WP_CLI_ROOT . 'Spyc.php'; } +function load_command( $name ) { + $path = WP_CLI_ROOT . "/commands/$name.php"; + + if ( is_readable( $path ) ) { + include_once $path; + } +} + +function load_all_commands() { + $cmd_dir = WP_CLI_ROOT . "commands"; + + $iterator = new \DirectoryIterator( $cmd_dir ); + + foreach ( $iterator as $filename ) { + if ( '.php' != substr( $filename, -4 ) ) + continue; + + include_once "$cmd_dir/$filename"; + } +} + function get_config_spec() { $spec = include __DIR__ . '/config-spec.php'; From a4fb83f3952751e7eef1074e0e48d5205954d424 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 31 May 2013 22:07:53 +0000 Subject: [PATCH 1754/5359] `$group` is optional for the function, so let it be optional for the command too --- php/commands/cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index 00b93b254..4516e7e16 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -51,7 +51,7 @@ public function decr( $args, $assoc_args ) { /** * Remove a value from the object cache. * - * @synopsis <key> <group> + * @synopsis <key> [<group>] */ public function delete( $args, $assoc_args ) { $key = $args[0]; From a8c9d64508bc4228ee1af9111dfbcc71d79604d5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 1 Jun 2013 00:21:56 +0000 Subject: [PATCH 1755/5359] Regenerate cache man --- man/cache.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/cache.1 b/man/cache.1 index 82f66dc5b..2f724253c 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -13,7 +13,7 @@ wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] wp cache decr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] . .P -wp cache delete \fIkey\fR \fIgroup\fR +wp cache delete \fIkey\fR [\fIgroup\fR] . .P wp cache flush From 9fb3dc1ba38a15d1c7b5919427d5c15f6ec753f0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 1 Jun 2013 20:10:46 +0000 Subject: [PATCH 1756/5359] Use `get_stylesheet_directory()` instead of `TEMPLATEPATH` when determining where to place a scaffold. In parent-child theme relationships, `TEMPLATEPATH` will always be the parent theme. We'd like to instead place our CPT/taxonomy in the child theme, as child themes are where the customizations occur. --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 6b3b1bf05..a9354de18 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -185,7 +185,7 @@ private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); if ( $theme ) { - $path = TEMPLATEPATH; + $path = get_stylesheet_directory(); } elseif ( ! empty( $plugin ) ) { $path = WP_PLUGIN_DIR . '/' . $plugin; if ( !is_dir( $path ) ) { From c4d503b01b4bce364dc67e1bc6f42fd7ceddb1e4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Jun 2013 13:47:15 +0300 Subject: [PATCH 1757/5359] scaffold: clarify --theme description in docs --- man-src/scaffold-post-type.txt | 2 +- man-src/scaffold-taxonomy.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/scaffold-post-type.txt b/man-src/scaffold-post-type.txt index e45952d06..9e50ebaf5 100644 --- a/man-src/scaffold-post-type.txt +++ b/man-src/scaffold-post-type.txt @@ -10,7 +10,7 @@ * `--theme`: - Create a file in the current theme directory, instead of sending to + Create a file in the current theme's directory, instead of sending to STDOUT. * `--plugin=<plugin>`: diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt index f739fb1f6..4156dfd65 100644 --- a/man-src/scaffold-taxonomy.txt +++ b/man-src/scaffold-taxonomy.txt @@ -14,7 +14,7 @@ * `--theme`: - Create a file in the current theme directory, instead of sending to + Create a file in the current theme's directory, instead of sending to STDOUT. * `--plugin=<plugin>`: From 59f7dc5be40e6b490beff2fbd3456bd780624fb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Jun 2013 17:32:13 +0300 Subject: [PATCH 1758/5359] core config: fix notice when not passing --dbpass --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 37d6a6d20..b088af51e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -69,7 +69,8 @@ public function config( $_, $assoc_args ) { $defaults = array( 'dbhost' => 'localhost', - 'dbprefix' => 'wp_' + 'dbpass' => '', + 'dbprefix' => 'wp_', ); $assoc_args = array_merge( $defaults, $assoc_args ); From 1df18344b8852ed8a5663b30c0a9c5b47eeb36fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Jun 2013 17:41:41 +0300 Subject: [PATCH 1759/5359] core config: set WPLANG based on downloaded locale fixes #488 --- php/commands/core.php | 10 ++++++++++ templates/wp-config.mustache | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index b088af51e..3009dde8f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -57,6 +57,15 @@ private function get_download_offer( $locale ) { return $out['offers'][0]; } + private static function get_initial_locale() { + include ABSPATH . '/wp-includes/version.php'; + + if ( isset( $wp_local_package ) ) + return $wp_local_package; + + return ''; + } + /** * Set up a wp-config.php file. * @@ -71,6 +80,7 @@ public function config( $_, $assoc_args ) { 'dbhost' => 'localhost', 'dbpass' => '', 'dbprefix' => 'wp_', + 'locale' => self::get_initial_locale() ); $assoc_args = array_merge( $defaults, $assoc_args ); diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 9c1442a03..78cca7488 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -54,7 +54,7 @@ $table_prefix = '{{dbprefix}}'; * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German * language support. */ -define('WPLANG', ''); +define('WPLANG', '{{locale}}'); {{{extra-php}}} From c01406fbf03565ae46daa6de98e2d993a292bfcb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 2 Jun 2013 08:44:32 -0700 Subject: [PATCH 1760/5359] Update post type and taxonomy scaffold to support a named theme target --- php/commands/scaffold.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a9354de18..65f0e9688 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -185,7 +185,10 @@ private function get_output_path( $assoc_args, $subdir ) { extract( $assoc_args, EXTR_SKIP ); if ( $theme ) { - $path = get_stylesheet_directory(); + if ( is_string( $theme ) ) + $path = get_theme_root( $theme ) . '/' . $theme; + else + $path = get_stylesheet_directory(); } elseif ( ! empty( $plugin ) ) { $path = WP_PLUGIN_DIR . '/' . $plugin; if ( !is_dir( $path ) ) { From 08fbddac696473977e0140c781e05b2f8ccf13d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 2 Jun 2013 08:47:13 -0700 Subject: [PATCH 1761/5359] Update man docs --- man-src/scaffold-post-type.txt | 4 ++-- man-src/scaffold-taxonomy.txt | 4 ++-- man/scaffold-post-type.1 | 2 +- man/scaffold-taxonomy.1 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/man-src/scaffold-post-type.txt b/man-src/scaffold-post-type.txt index 9e50ebaf5..e164c1f3b 100644 --- a/man-src/scaffold-post-type.txt +++ b/man-src/scaffold-post-type.txt @@ -10,8 +10,8 @@ * `--theme`: - Create a file in the current theme's directory, instead of sending to -STDOUT. + Create a file in the active theme directory, instead of sending to +STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. * `--plugin=<plugin>`: diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt index 4156dfd65..1015bf54c 100644 --- a/man-src/scaffold-taxonomy.txt +++ b/man-src/scaffold-taxonomy.txt @@ -14,8 +14,8 @@ * `--theme`: - Create a file in the current theme's directory, instead of sending to -STDOUT. + Create a file in the active theme directory, instead of sending to +STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. * `--plugin=<plugin>`: diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 index 5d07b487b..6db8bf44c 100644 --- a/man/scaffold-post-type.1 +++ b/man/scaffold-post-type.1 @@ -27,7 +27,7 @@ The textdomain to use for the labels\. \fB\-\-theme\fR: . .IP -Create a file in the current theme directory, instead of sending to STDOUT\. +Create a file in the active theme directory, instead of sending to STDOUT\. Specify a theme with \fB\-\-theme=<theme>\fR to have the file placed in that theme\. . .TP \fB\-\-plugin=<plugin>\fR: diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 index 84a1a7900..3d7986f2e 100644 --- a/man/scaffold-taxonomy.1 +++ b/man/scaffold-taxonomy.1 @@ -33,7 +33,7 @@ The textdomain to use for the labels\. \fB\-\-theme\fR: . .IP -Create a file in the current theme directory, instead of sending to STDOUT\. +Create a file in the active theme directory, instead of sending to STDOUT\. Specify a theme with \fB\-\-theme=<theme>\fR to have the file placed in that theme\. . .TP \fB\-\-plugin=<plugin>\fR: From c5d8f7073caff031e3d5988d654551fa85f0b583 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Jun 2013 22:10:18 +0300 Subject: [PATCH 1762/5359] bump version to 0.10.0-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 8ca2bcf13..1b40a05d3 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0-alpha' ); +define( 'WP_CLI_VERSION', '0.10.0-beta' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 4fb859972901bef44a03c491316fa721b65b624e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 30 May 2013 17:26:45 +0300 Subject: [PATCH 1763/5359] run_mysql_command: use --no-defaults instead of --defaults-file --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 5c4da7752..7d3fe7afc 100644 --- a/php/utils.php +++ b/php/utils.php @@ -404,7 +404,7 @@ function run_mysql_query( $query, $args ) { function run_mysql_command( $cmd, $arg_str, $pass ) { $old_val = getenv( 'MYSQL_PWD' ); - $final_cmd = "$cmd --defaults-file=/dev/null $arg_str"; + $final_cmd = "$cmd --no-defaults $arg_str"; putenv( 'MYSQL_PWD=' . $pass ); $r = proc_close( proc_open( $final_cmd, array( STDIN, STDOUT, STDERR ), $pipes ) ); From dae17e1496f6994824ec3345de449dd3ef8dac90 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 May 2013 22:00:00 +0300 Subject: [PATCH 1764/5359] standardize special flags handling --- php/WP_CLI/Runner.php | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b0f9b9c91..22e1a60a0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -292,28 +292,15 @@ public function before_wp_load() { $this->init_logger(); - // Handle --version parameter - if ( isset( $this->assoc_args['version'] ) && empty( $this->arguments ) ) { - \WP_CLI\InternalFlags::version(); - exit; - } - - // Handle --info parameter - if ( isset( $this->assoc_args['info'] ) && empty( $this->arguments ) ) { - \WP_CLI\InternalFlags::info(); - exit; - } - - // Handle --param-dump parameter - if ( isset( $this->assoc_args['param-dump'] ) ) { - \WP_CLI\InternalFlags::param_dump(); - exit; - } - - // Handle --cmd-dump parameter - if ( isset( $this->assoc_args['cmd-dump'] ) ) { - \WP_CLI\InternalFlags::cmd_dump(); - exit; + // Handle a bunch of special-purpose flags + if ( empty( $this->arguments ) ) { + foreach ( array( 'version', 'info', 'param-dump', 'cmd-dump' ) as $key ) { + if ( isset( $this->assoc_args[ $key ] ) ) { + call_user_func( array( '\\WP_CLI\\InternalFlags', + str_replace( '-', '_', $key ) ) ); + exit; + } + } } $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); From 4cea180531a2e2318ff5b4e03673a161938a481e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Jun 2013 23:08:50 +0300 Subject: [PATCH 1765/5359] convert InternalFlags class to Sys_Command --- php/WP_CLI/Dispatcher/RootCommand.php | 3 + php/WP_CLI/Runner.php | 32 +++++---- .../InternalFlags.php => commands/_sys.php} | 67 +++++++++---------- 3 files changed, 55 insertions(+), 47 deletions(-) rename php/{WP_CLI/InternalFlags.php => commands/_sys.php} (65%) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index e47721aef..9fc159aee 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -26,6 +26,9 @@ function show_usage() { \WP_CLI::line( 'Available commands:' ); foreach ( $this->get_subcommands() as $command ) { + if ( '_sys' == $command->get_name() ) + continue; + \WP_CLI::line( sprintf( " %s %s", implode( ' ', get_path( $command ) ), implode( '|', array_keys( get_subcommands( $command ) ) ) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 22e1a60a0..dcfe5fffe 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -251,6 +251,16 @@ private static function back_compat_conversions( $r ) { unset( $assoc_args['json'] ); } + // --{version|info} -> _sys {version|info} + if ( empty( $args ) ) { + foreach ( array( 'version', 'info' ) as $key ) { + if ( isset( $assoc_args[ $key ] ) ) { + $args = array( '_sys', $key ); + break; + } + } + } + return array( $args, $assoc_args ); } @@ -292,19 +302,13 @@ public function before_wp_load() { $this->init_logger(); - // Handle a bunch of special-purpose flags - if ( empty( $this->arguments ) ) { - foreach ( array( 'version', 'info', 'param-dump', 'cmd-dump' ) as $key ) { - if ( isset( $this->assoc_args[ $key ] ) ) { - call_user_func( array( '\\WP_CLI\\InternalFlags', - str_replace( '-', '_', $key ) ) ); - exit; - } - } - } - $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); + if ( $this->cmd_starts_with( array( '_sys' ) ) ) { + $this->_run_command(); + exit; + } + // First try at showing man page if ( $this->cmd_starts_with( array( 'help' ) ) ) { $this->_run_command(); @@ -367,7 +371,11 @@ public function after_wp_load() { // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { - \WP_CLI\InternalFlags::completions(); + foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { + $subcommands = Dispatcher\get_subcommands( $command ); + + WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); + } exit; } diff --git a/php/WP_CLI/InternalFlags.php b/php/commands/_sys.php similarity index 65% rename from php/WP_CLI/InternalFlags.php rename to php/commands/_sys.php index 1f5bf7089..af2b1b714 100644 --- a/php/WP_CLI/InternalFlags.php +++ b/php/commands/_sys.php @@ -1,37 +1,11 @@ <?php -namespace WP_CLI; -use \WP_CLI; +use \WP_CLI\Dispatcher, + \WP_CLI\Utils; -/** - * Class that handles special assoc parameters - */ -class InternalFlags { +class Sys_Command extends WP_CLI_Command { - static function version() { - WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); - } - - static function info() { - $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); - - WP_CLI::line( "PHP binary:\t" . $php_bin ); - WP_CLI::line( "PHP version:\t" . PHP_VERSION ); - WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); - WP_CLI::line( "wp-cli config:\t" . WP_CLI::get_config_path() ); - WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); - } - - static function param_dump() { - echo json_encode( Utils\get_config_spec() ); - } - - static function cmd_dump() { - echo json_encode( self::command_to_array( WP_CLI::$root ) ); - } - - private static function command_to_array( $command ) { + private function command_to_array( $command ) { $dump = array( 'name' => $command->get_name(), 'description' => $command->get_shortdesc(), @@ -48,12 +22,35 @@ private static function command_to_array( $command ) { return $dump; } - static function completions() { - foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { - $subcommands = Dispatcher\get_subcommands( $command ); + function version() { + WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); + } - WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); - } + function info() { + $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + + WP_CLI::line( "PHP binary:\t" . $php_bin ); + WP_CLI::line( "PHP version:\t" . PHP_VERSION ); + WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); + WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "wp-cli config:\t" . WP_CLI::get_config_path() ); + WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); + } + + /** + * @subcommand param-dump + */ + function param_dump() { + echo json_encode( Utils\get_config_spec() ); + } + + /** + * @subcommand cmd-dump + */ + function cmd_dump() { + echo json_encode( self::command_to_array( WP_CLI::$root ) ); } } +WP_CLI::add_command( '_sys', 'Sys_Command' ); + From 3f08d5f7eefeb678fb36e380205d343bebd2dfe1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 3 Jun 2013 10:34:22 -0700 Subject: [PATCH 1766/5359] Create `get_api_for_version()`, which will give us the proper download link for a given version --- php/WP_CLI/CommandWithUpgrade.php | 26 ++++++++++++++++++++++++++ php/commands/theme.php | 3 +++ 2 files changed, 29 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index d2b8529c0..bed5291ff 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -119,6 +119,32 @@ function install( $args, $assoc_args ) { } } + protected function get_api_for_version( $api, $version ) { + + list( $link ) = explode( $api->slug, $api->download_link ); + + if ( stripos( $api->download_link, 'theme' ) ) + $download_type = 'theme'; + else + $download_type = 'plugin'; + + + if ( 'dev' == $version ) { + $api->download_link = $link . $api->slug . '.zip'; + $api->version = 'Development Version'; + } else { + $api->download_link = $link . $api->slug . '.' . $version .'.zip'; + $api->version = $version; + + // check if the requested version exists + $response = wp_remote_head( $api->download_link ); + if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { + \WP_CLI::error( sprintf( "Can't find the requested %s's version %s in the WordPress.org %s repository.", $download_type, $version, $download_type ) ); + } + } + return $api; + } + protected function _update( $item ) { call_user_func( $this->upgrade_refresh ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 3b0a5c6f7..4c5414737 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -107,6 +107,9 @@ protected function install_from_repo( $slug, $assoc_args ) { WP_CLI::error( $api ); } + if ( ! empty( $assoc_args['version'] ) ) + $api = $this->get_api_for_version( $api, $assoc_args['version'] ); + // Check to see if we should update, rather than install. if ( $this->has_update( $slug ) ) { WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); From f8f5742962b498e7c97cf0c8f9b6870250058d22 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Jun 2013 22:12:28 +0300 Subject: [PATCH 1767/5359] rename get_api_for_version() to alter_api_response() and use in plugin command --- features/theme.feature | 24 ------------------------ features/upgradables.feature | 31 +++++++++++++++++++++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 31 ++++++++++++++++++------------- php/commands/plugin.php | 16 +--------------- php/commands/theme.php | 5 +++-- 5 files changed, 53 insertions(+), 54 deletions(-) create mode 100644 features/upgradables.feature diff --git a/features/theme.feature b/features/theme.feature index fd65ec665..f7a57b5b9 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -47,27 +47,3 @@ Feature: Manage WordPress themes When I run `wp theme list` Then STDOUT should not be empty - Scenario: Upgrading a theme - Given a WP install - And I run `wp theme install p2 --version=1.0.1` - - When I run `wp theme status` - Then STDOUT should contain: - """ - U = Update Available - """ - - When I run `wp theme status p2` - Then STDOUT should contain: - """ - Version: 1.0.1 (Update available) - """ - - When I run `wp theme update p2` - Then STDOUT should not be empty - - When I run `wp theme status p2` - Then STDOUT should not contain: - """ - (Update available) - """ diff --git a/features/upgradables.feature b/features/upgradables.feature new file mode 100644 index 000000000..0dd81ef2d --- /dev/null +++ b/features/upgradables.feature @@ -0,0 +1,31 @@ +Feature: Manage WordPress themes and plugins + + Scenario Outline: Upgrading a theme or plugin + Given a WP install + And I run `wp <type> install <item> --version=<version>` + + When I run `wp <type> status` + Then STDOUT should contain: + """ + U = Update Available + """ + + When I run `wp <type> status <item>` + Then STDOUT should contain: + """ + Version: <version> (Update available) + """ + + When I run `wp <type> update <item>` + Then STDOUT should not be empty + + When I run `wp <type> status <item>` + Then STDOUT should not contain: + """ + (Update available) + """ + + Examples: + | type | item | version | + | theme | p2 | 1.0.1 | + | plugin | category-checklist-tree | 1.2 | diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index bed5291ff..50c4bc1c5 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -119,30 +119,35 @@ function install( $args, $assoc_args ) { } } - protected function get_api_for_version( $api, $version ) { - - list( $link ) = explode( $api->slug, $api->download_link ); + /** + * Prepare an API response for downloading a particular version of an item. + * + * @param object $response wordpress.org API response + * @param string $version The desired version of the package + */ + protected static function alter_api_response( $response, $version ) { + list( $link ) = explode( $response->slug, $response->download_link ); - if ( stripos( $api->download_link, 'theme' ) ) + if ( false !== strpos( $response->download_link, 'theme' ) ) $download_type = 'theme'; else $download_type = 'plugin'; - if ( 'dev' == $version ) { - $api->download_link = $link . $api->slug . '.zip'; - $api->version = 'Development Version'; + $response->download_link = $link . $response->slug . '.zip'; + $response->version = 'Development Version'; } else { - $api->download_link = $link . $api->slug . '.' . $version .'.zip'; - $api->version = $version; + $response->download_link = $link . $response->slug . '.' . $version .'.zip'; + $response->version = $version; // check if the requested version exists - $response = wp_remote_head( $api->download_link ); + $response = wp_remote_head( $response->download_link ); if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { - \WP_CLI::error( sprintf( "Can't find the requested %s's version %s in the WordPress.org %s repository.", $download_type, $version, $download_type ) ); - } + \WP_CLI::error( sprintf( + "Can't find the requested %s's version %s in the WordPress.org %s repository.", + $download_type, $version, $download_type ) ); + } } - return $api; } protected function _update( $item ) { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 162b2539d..6d6f1200e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -158,21 +158,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } if ( isset( $assoc_args['version'] ) ) { - list( $link ) = explode( $slug, $api->download_link ); - - if ( 'dev' == $assoc_args['version'] ) { - $api->download_link = $link . $slug . '.zip'; - $api->version = 'Development Version'; - } else { - $api->download_link = $link . $slug . '.' . $assoc_args['version'] .'.zip'; - $api->version = $assoc_args['version']; - - // check if the requested version exists - $response = wp_remote_head( $api->download_link ); - if ( !$response || $response['headers']['content-type'] != 'application/octet-stream' ) { - WP_CLI::error( "Can't find the requested plugin's version " . $assoc_args['version'] . " in the WordPress.org plugins repository." ); - } - } + self::alter_api_response( $api, $assoc_args['version'] ); } $status = install_plugin_install_status( $api ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 4c5414737..4aceba925 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -107,8 +107,9 @@ protected function install_from_repo( $slug, $assoc_args ) { WP_CLI::error( $api ); } - if ( ! empty( $assoc_args['version'] ) ) - $api = $this->get_api_for_version( $api, $assoc_args['version'] ); + if ( isset( $assoc_args['version'] ) ) { + self::alter_api_response( $api, $assoc_args['version'] ); + } // Check to see if we should update, rather than install. if ( $this->has_update( $slug ) ) { From 42d3ab15fbf10fbf1380a9ac64573f886d8b1c43 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Jun 2013 16:35:15 +0300 Subject: [PATCH 1768/5359] contributing: use `behat --expand` Without --expand, it's hard to debug failures in scenarion outlines. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4b8ec7e9..52ce37fda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ Running the following as root in MySQL should do the trick: Finally, to run the tests: vendor/bin/phpunit - vendor/bin/behat + vendor/bin/behat --expand Finally... ---------- From f4169830d213245488c464c2c4fe4d6afdba3153 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Jun 2013 16:11:59 +0300 Subject: [PATCH 1769/5359] behat: generate new plugin instead of relying on Hello Dolly This allows us to check more things, since all the plugin data is frozen. --- features/plugin.feature | 43 +++++++++++++++++++++++++++------- features/scaffold.feature | 13 ---------- features/steps/basic_steps.php | 14 +++++++---- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index b1093e2f8..5ab78736d 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -1,24 +1,49 @@ Feature: Manage WordPress plugins - Scenario: Checking the plugin status + Scenario: Create, activate and check plugin status Given a WP install + And I run `wp plugin path` + And save STDOUT as {PLUGIN_DIR} - When I run `wp plugin status` + When I run `wp plugin scaffold zombieland --plugin_name="Zombieland"` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist + + When I run `wp plugin status zombieland` + Then STDOUT should contain: + """ + Plugin zombieland details: + Name: Zombieland + Status: Inactive + Version: 0.1-alpha + Author: YOUR NAME HERE + Description: PLUGIN DESCRIPTION HERE + """ + + When I run `wp plugin activate zombieland` Then STDOUT should not be empty - When I run `wp plugin status hello` + When I run `wp plugin status zombieland` Then STDOUT should contain: """ - Plugin hello details: - Name: Hello Dolly + Status: Active """ - When I try `wp plugin status non-existent-plugin` + When I run `wp plugin status` + Then STDOUT should not be empty + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | zombieland | active | none | 0.1-alpha | + + When I run `wp plugin delete zombieland` + Then the {PLUGIN_DIR}/zombieland file should not exist + + When I try `wp plugin status zombieland` Then the return code should be 1 And STDERR should contain: """ - Error: The plugin 'non-existent-plugin' could not be found. + Error: The plugin 'zombieland' could not be found. """ - When I run `wp plugin list --format=json` - Then STDOUT should not be empty diff --git a/features/scaffold.feature b/features/scaffold.feature index 6143dd8de..5e2601964 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -10,19 +10,6 @@ Feature: Wordpress code scaffolding Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist - @plugin - Scenario: Scaffold a plugin - Given a WP install - And I run `wp plugin path` - And save STDOUT as {PLUGIN_DIR} - - When I run `wp plugin scaffold zombieland --plugin_name="Welcome to Zombieland" --activate` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist - - When I run `wp plugin activate zombieland` - Then STDOUT should not be empty - @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 700cf4736..c90c4a736 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -216,7 +216,7 @@ function ( $world, $stream ) { } ); -$steps->Then( '/^the (.+) file should (exist|be:|contain:|not contain:)$/', +$steps->Then( '/^the (.+) file should (exist|not exist|be:|contain:|not contain:)$/', function ( $world, $path, $action, $expected = null ) { $path = $world->replace_variables( $path ); @@ -224,9 +224,15 @@ function ( $world, $path, $action, $expected = null ) { if ( '/' !== $path[0] ) $path = $world->get_path( $path ); - assertFileExists( $path ); - - if ( 'exist' !== $action ) { + switch ( $action ) { + case 'exist': + assertFileExists( $path ); + break; + case 'not exist': + assertFileNotExists( $path ); + break; + default: + assertFileExists( $path ); $action = substr( $action, 0, -1 ); $expected = $world->replace_variables( (string) $expected ); checkString( file_get_contents( $path ), $expected, $action ); From f2df95dad28ef7fc0540ad528f534ee9c5487360 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Jun 2013 17:26:33 +0300 Subject: [PATCH 1770/5359] Ensure `wp plugin delete` and `wp theme delete` output consistent messages. --- features/plugin.feature | 23 ++++++++++++++++++----- features/upgradables.feature | 15 +++++++++++++-- php/commands/plugin.php | 36 +++++++++++++++++++++++------------- php/commands/theme.php | 5 +++-- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 5ab78736d..174ab4abe 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -37,13 +37,26 @@ Feature: Manage WordPress plugins | name | status | update | version | | zombieland | active | none | 0.1-alpha | - When I run `wp plugin delete zombieland` - Then the {PLUGIN_DIR}/zombieland file should not exist - - When I try `wp plugin status zombieland` + When I try `wp plugin uninstall zombieland` Then the return code should be 1 And STDERR should contain: """ - Error: The plugin 'zombieland' could not be found. + The plugin is active. """ + When I run `wp plugin deactivate zombieland` + Then STDOUT should not be empty + + When I run `wp plugin uninstall zombieland` + Then STDOUT should contain: + """ + Success: Uninstalled 'zombieland' plugin. + """ + And the {PLUGIN_DIR}/zombieland file should not exist + + When I try the previous command again + Then the return code should be 1 + And STDERR should contain: + """ + The plugin 'zombieland' could not be found. + """ diff --git a/features/upgradables.feature b/features/upgradables.feature index 0dd81ef2d..e44428617 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -1,6 +1,6 @@ Feature: Manage WordPress themes and plugins - Scenario Outline: Upgrading a theme or plugin + Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install And I run `wp <type> install <item> --version=<version>` @@ -13,7 +13,8 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> status <item>` Then STDOUT should contain: """ - Version: <version> (Update available) + Status: Inactive + Version: <version> (Update available) """ When I run `wp <type> update <item>` @@ -25,6 +26,16 @@ Feature: Manage WordPress themes and plugins (Update available) """ + When I run `wp <type> delete <item>` + Then STDOUT should contain: + """ + Success: Deleted '<item>' <type>. + """ + + When I try `wp <type> status <item>` + Then the return code should be 1 + And STDERR should not be empty + Examples: | type | item | version | | theme | p2 | 1.0.1 | diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 6d6f1200e..4b860a081 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -192,12 +192,12 @@ protected function install_from_repo( $slug, $assoc_args ) { * @synopsis <plugin> [--version=<version>] */ function update( $args, $assoc_args ) { + list( $basename ) = $this->parse_name( $args ); + if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { - $this->delete( $args, array(), false ); + $this->_delete( $basename, false ); $this->install( $args, $assoc_args ); } else { - list( $basename ) = $this->parse_name( $args ); - $was_active = is_plugin_active( $basename ); $was_network_active = is_plugin_active_for_network( $basename ); @@ -264,8 +264,12 @@ function uninstall( $args, $assoc_args = array() ) { uninstall_plugin( $file ); - if ( !isset( $assoc_args['no-delete'] ) ) - $this->delete( $args ); + if ( isset( $assoc_args['no-delete'] ) ) + return; + + if ( $this->_delete( $file ) ) { + WP_CLI::success( sprintf( "Uninstalled '%s' plugin.", $name ) ); + } } /** @@ -273,16 +277,12 @@ function uninstall( $args, $assoc_args = array() ) { * * @synopsis <plugin> */ - function delete( $args, $assoc_args = array(), $exit_on_error = true ) { + function delete( $args, $assoc_args = array() ) { list( $file, $name ) = $this->parse_name( $args ); - $plugin_dir = dirname( $file ); - if ( '.' == $plugin_dir ) - $plugin_dir = $file; - - $command = 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ); - - return WP_CLI::launch( $command, $exit_on_error ); + if ( $this->_delete( $file ) ) { + WP_CLI::success( sprintf( "Deleted '%s' plugin.", $name ) ); + } } /** @@ -362,6 +362,16 @@ private function get_name( $file ) { return $name; } + + private function _delete( $file ) { + $plugin_dir = dirname( $file ); + if ( '.' == $plugin_dir ) + $plugin_dir = $file; + + $command = 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ); + + return ! WP_CLI::launch( $command ); + } } WP_CLI::add_command( 'plugin', 'Plugin_Command' ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 4aceba925..50245e714 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -189,18 +189,19 @@ function update_all( $args, $assoc_args ) { */ function delete( $args ) { $theme = $this->parse_name( $args ); + $theme_slug = $theme->get_stylesheet(); if ( $this->is_active_theme( $theme ) ) { WP_CLI::error( "Can't delete the currently active theme." ); } - $r = delete_theme( $theme->get_stylesheet() ); + $r = delete_theme( $theme_slug ); if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); } - WP_CLI::success( "$theme->name theme deleted." ); + WP_CLI::success( sprintf( "Deleted '%s' theme.", $theme_slug ) ); } /** From 15bf1fe4259c291562410e169ac675f7dbe8b41d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 4 Jun 2013 18:04:18 +0300 Subject: [PATCH 1771/5359] option: add success messages see #472 --- features/option.feature | 6 +++--- php/commands/option.php | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/features/option.feature b/features/option.feature index 0ab33e815..707c4fe82 100644 --- a/features/option.feature +++ b/features/option.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress options Given a WP install When I run `wp option add foo 'bar'` - Then STDOUT should be empty + Then STDOUT should not be empty When I run `wp option get foo` Then STDOUT should be: @@ -13,7 +13,7 @@ Feature: Manage WordPress options """ When I run `wp option set foo '[ 1, 2 ]' --format=json` - Then STDOUT should be empty + Then STDOUT should not be empty When I run `wp option get foo --format=json` Then STDOUT should be: @@ -22,7 +22,7 @@ Feature: Manage WordPress options """ When I run `wp option delete foo` - Then STDOUT should be empty + Then STDOUT should not be empty When I try `wp option get foo` Then the return code should be 1 diff --git a/php/commands/option.php b/php/commands/option.php index 361a1f73b..fb39ce7b5 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -35,6 +35,8 @@ public function add( $args, $assoc_args ) { if ( !add_option( $key, $value ) ) { WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); + } else { + WP_CLI::success( "Added '$key' option." ); } } @@ -54,6 +56,8 @@ public function update( $args, $assoc_args ) { if ( !update_option( $key, $value ) ) { WP_CLI::error( "Could not update option '$key'." ); + } else { + WP_CLI::success( "Updated '$key' option." ); } } @@ -67,6 +71,8 @@ public function delete( $args ) { if ( !delete_option( $key ) ) { WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); + } else { + WP_CLI::success( "Deleted '$key' option." ); } } } From 682b0d51afc68f776fa907e0f308c3b03c5b2346 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Apr 2013 21:50:34 +0300 Subject: [PATCH 1772/5359] core is-installed: let the bootstrap process show the error message. --- features/core.feature | 4 ++++ php/WP_CLI/Runner.php | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index eb9d7339d..29478558d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -6,6 +6,7 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 + And STDERR should not be empty When I run `wp core download --quiet` Then the wp-settings.php file should exist @@ -22,6 +23,7 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 + And STDERR should not be empty When I try `wp core install` Then the return code should be 1 @@ -69,6 +71,7 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 + And STDERR should not be empty When I try `wp` Then the return code should be 1 @@ -88,6 +91,7 @@ Feature: Manage WordPress installation Given a WP install When I run `wp core is-installed` + Then STDOUT should be empty When I run `wp eval 'var_export( is_admin() );'` Then STDOUT should be: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b0f9b9c91..6a02c39d0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -358,8 +358,7 @@ public function before_wp_load() { } if ( - $this->cmd_starts_with( array( 'core', 'install' ) ) || - $this->cmd_starts_with( array( 'core', 'is-installed' ) ) + $this->cmd_starts_with( array( 'core', 'install' ) ) ) { define( 'WP_INSTALLING', true ); From 7ed975a42fe06f9adc0f20700dc764ad7dcdeb7d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Jun 2013 04:04:07 +0300 Subject: [PATCH 1773/5359] composer: update mustache to 2.3.x; update composer.lock --- composer.json | 2 +- composer.lock | 107 ++++++++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/composer.json b/composer.json index ff0d20c9d..895c4e2f9 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "require": { "php": ">=5.3.2", "wp-cli/php-cli-tools": "dev-master", - "mustache/mustache": "2.0.x" + "mustache/mustache": "2.3.x" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" diff --git a/composer.lock b/composer.lock index a16ee74ea..6e824d1cf 100644 --- a/composer.lock +++ b/composer.lock @@ -3,20 +3,20 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "e83d4615b33cb717939303cba9848c94", + "hash": "9cb0bdfbcfa8b3b505b9241ca38f19f7", "packages": [ { "name": "mustache/mustache", - "version": "v2.0.2", + "version": "v2.3.1", "source": { "type": "git", - "url": "https://github.com/bobthecow/mustache.php", - "reference": "v2.0.2" + "url": "https://github.com/bobthecow/mustache.php.git", + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://github.com/bobthecow/mustache.php/zipball/v2.0.2", - "reference": "v2.0.2", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { @@ -45,7 +45,7 @@ "mustache", "templating" ], - "time": "2012-09-12 09:13:06" + "time": "2013-04-25 15:23:30" }, { "name": "wp-cli/php-cli-tools", @@ -221,16 +221,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "1.2.9", + "version": "1.2.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.9" + "reference": "1.2.11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9", - "reference": "1.2.9", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.11", + "reference": "1.2.11", "shasum": "" }, "require": { @@ -239,6 +239,9 @@ "phpunit/php-text-template": ">=1.1.1@stable", "phpunit/php-token-stream": ">=1.1.3@stable" }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, "suggest": { "ext-dom": "*", "ext-xdebug": ">=2.0.5" @@ -270,7 +273,7 @@ "testing", "xunit" ], - "time": "2013-02-26 18:55:56" + "time": "2013-05-23 18:23:24" }, { "name": "phpunit/php-file-iterator", @@ -452,16 +455,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.19", + "version": "3.7.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.19" + "reference": "3.7.21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.19", - "reference": "3.7.19", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.21", + "reference": "3.7.21", "shasum": "" }, "require": { @@ -475,7 +478,7 @@ "phpunit/php-text-template": ">=1.1.1", "phpunit/php-timer": ">=1.0.2,<1.1.0", "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.0.0,<2.3.0" + "symfony/yaml": ">=2.0,<3.0" }, "require-dev": { "pear-pear/pear": "1.9.4" @@ -522,7 +525,7 @@ "testing", "xunit" ], - "time": "2013-03-25 11:45:06" + "time": "2013-05-23 18:54:29" }, { "name": "phpunit/phpunit-mock-objects", @@ -575,17 +578,17 @@ }, { "name": "symfony/config", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/Config", "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -618,21 +621,21 @@ ], "description": "Symfony Config Component", "homepage": "http://symfony.com", - "time": "2013-03-01 10:42:10" + "time": "2013-05-10 18:08:31" }, { "name": "symfony/console", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -665,21 +668,21 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2013-03-19 20:48:08" + "time": "2013-05-27 14:47:40" }, { "name": "symfony/dependency-injection", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/DependencyInjection", "source": { "type": "git", "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -720,21 +723,21 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "http://symfony.com", - "time": "2013-03-23 07:49:54" + "time": "2013-05-06 08:37:50" }, { "name": "symfony/event-dispatcher", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -778,17 +781,17 @@ }, { "name": "symfony/finder", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -821,21 +824,21 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2013-04-01 07:51:50" + "time": "2013-05-27 20:26:32" }, { "name": "symfony/translation", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -876,21 +879,21 @@ ], "description": "Symfony Translation Component", "homepage": "http://symfony.com", - "time": "2013-04-01 08:06:05" + "time": "2013-05-10 16:49:00" }, { "name": "symfony/yaml", - "version": "v2.2.1", + "version": "v2.2.2", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.2.1" + "reference": "v2.2.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.1", - "reference": "v2.2.1", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.2", + "reference": "v2.2.2", "shasum": "" }, "require": { @@ -923,7 +926,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2013-03-23 07:49:54" + "time": "2013-05-10 18:08:31" } ], "aliases": [ From 03fb31d13fc2359b0347bd39a81087126a6d007a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 5 Jun 2013 04:14:58 +0300 Subject: [PATCH 1774/5359] bump version to 0.10.0-beta2 [ci skip] --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 1b40a05d3..cae0c4c28 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0-beta' ); +define( 'WP_CLI_VERSION', '0.10.0-beta2' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 8491cfbcb4d7c2e6fa093e2fd9c47632eb1648bc Mon Sep 17 00:00:00 2001 From: James Collins <james@jamesc.id.au> Date: Wed, 5 Jun 2013 22:42:10 +1000 Subject: [PATCH 1775/5359] Only use maintenance mode if a plugin or theme needs updating When updating plugins (wp plugin update-all) or themes (wp theme update-all) on a WordPress multisite installation, maintenance activated and deactivated even if there are no updates to install. The Plugin_Upgrader::bulk_upgrade() and Theme_Upgrader::bulk_upgrade() WordPress functions currently don't check that the array passed to it isn't empty, causing maintenance mode to be enabled even if no updates are required. This bug doesn't affect non multisite installs, because for non multisite installs the code in Plugin_Upgrader::bulk_upgrade() and Theme_Upgrader::bulk_upgrade() only uses maintenance mode if the plugin/theme being updated is activated. Fixes #491 --- php/WP_CLI/CommandWithUpgrade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 50c4bc1c5..f02f3c6f5 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -179,7 +179,8 @@ function update_all( $args, $assoc_args ) { } $upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); + + $result = count($items_to_update) ? $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ) : array(); // Let the user know the results. $num_to_update = count( $items_to_update ); From 186b0480e3b9940afdad73921abfe56842803642 Mon Sep 17 00:00:00 2001 From: James Collins <james@jamesc.id.au> Date: Wed, 5 Jun 2013 22:59:11 +1000 Subject: [PATCH 1776/5359] Change ternary operator to simple if statement --- php/WP_CLI/CommandWithUpgrade.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index f02f3c6f5..ad18dbe83 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -180,7 +180,11 @@ function update_all( $args, $assoc_args ) { $upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = count($items_to_update) ? $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ) : array(); + $result = array(); + + // Only attempt to update if there is something to update + if ( count($items_to_update) > 0 ) + $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); // Let the user know the results. $num_to_update = count( $items_to_update ); From 2e220527ac4ad325a357c1d7ccedcc8d8b96c66c Mon Sep 17 00:00:00 2001 From: James Collins <james@jamesc.id.au> Date: Wed, 5 Jun 2013 23:41:29 +1000 Subject: [PATCH 1777/5359] Use empty() check instead of count() Requested in https://github.com/wp-cli/wp-cli/pull/492#discussion_r4545088. --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index ad18dbe83..cf771d6f5 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -183,7 +183,7 @@ function update_all( $args, $assoc_args ) { $result = array(); // Only attempt to update if there is something to update - if ( count($items_to_update) > 0 ) + if ( !empty( $items_to_update ) ) $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); // Let the user know the results. From 485dd3f64d8f973f012ca5d232eb9f3175fe6142 Mon Sep 17 00:00:00 2001 From: Ramon de la Fuente <ramon@future500.nl> Date: Thu, 6 Jun 2013 16:16:21 +0200 Subject: [PATCH 1778/5359] Allow capital letters in <value> tokens in @synopsis Values in @synopsis tags are not matched if they contain capital letters. This allows for capital letters i.e. --name=<myPropertyValue> fixes #493 --- php/WP_CLI/SynopsisParser.php | 2 +- tests/test-synopsis.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 2021c486c..eb5dc8e0e 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -108,7 +108,7 @@ static function parse( $synopsis ) { private static function init_patterns() { $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '(?P<value>[a-z-|]+)'; + $p_value = '(?P<value>[a-zA-Z-|]+)'; self::gen_patterns( 'positional', "<$p_value>", array( 'mandatory', 'optional', 'repeating' ) ); self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional', 'repeating' ) ); diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index d54f9df2a..9262b593e 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -85,5 +85,23 @@ function testCombined() { $this->assertEquals( 'generic', $r[2]['type'] ); $this->assertEquals( 'flag', $r[3]['type'] ); } + + function testAllowedValueCharacters() { + $r = SynopsisParser::parse( '--capitals=<VALUE> --hyphen=<val-ue> --combined=<VAL-ue> --disallowed=<wrong:char>' ); + + $this->assertCount( 4, $r ); + + $this->assertEquals( 'assoc', $r[0]['type'] ); + $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + + $this->assertEquals( 'assoc', $r[1]['type'] ); + $this->assertEquals( 'mandatory', $r[1]['flavour'] ); + + $this->assertEquals( 'assoc', $r[2]['type'] ); + $this->assertEquals( 'mandatory', $r[2]['flavour'] ); + + $this->assertEquals( 'unknown', $r[3]['type'] ); + } + } From 1e1561d69f6a4bfe343d593a85851b0eceaf30ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Jun 2013 17:37:08 +0300 Subject: [PATCH 1779/5359] remove `wp home` command --- man-src/home.txt | 0 man/home.1 | 10 ---------- php/commands/home.php | 28 ---------------------------- 3 files changed, 38 deletions(-) delete mode 100644 man-src/home.txt delete mode 100644 man/home.1 delete mode 100644 php/commands/home.php diff --git a/man-src/home.txt b/man-src/home.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/man/home.1 b/man/home.1 deleted file mode 100644 index 184b18290..000000000 --- a/man/home.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-HOME" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-home\fR \- Open the wp\-cli homepage in your browser\. -. -.SH "SYNOPSIS" -wp home diff --git a/php/commands/home.php b/php/commands/home.php deleted file mode 100644 index eed233f66..000000000 --- a/php/commands/home.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -class Home_Command extends WP_CLI_Command { - - /** - * Open the wp-cli homepage in your browser. - */ - function __invoke() { - // The url for the wp-cli repository - $repository_url = 'https://github.com/wp-cli/wp-cli'; - - // Open the wp-cli page in the browser - if ( exec( 'which x-www-browser' ) ) { - system( 'x-www-browser '.$repository_url ); - } - elseif ( exec( 'which open' ) ) { - system( 'open '.$repository_url ); - } - else { - WP_CLI::error( 'No command found to open the homepage in the browser. Please open it manually: '.$repository_url ); - return; - } - - WP_CLI::success( 'The wp-cli homepage should be opening in your browser.' ); - } -} - -WP_CLI::add_command( 'home', 'Home_Command' ); From 3c3f624c4cc413fbbdbe7d26ce112a5160dde0db Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 12:55:22 +0300 Subject: [PATCH 1780/5359] bump version to 0.10.0-RC --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index cae0c4c28..63ea79668 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0-beta2' ); +define( 'WP_CLI_VERSION', '0.10.0-RC' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From c06ba098837720f18f0aa1caa45bf2789fab415d Mon Sep 17 00:00:00 2001 From: daithi-coombes <webeire@gmail.com> Date: Sat, 8 Jun 2013 13:54:39 +0100 Subject: [PATCH 1781/5359] search-replace function modified to perform a search and replace through multisite specific tables --- features/search-replace.feature | 9 ++++++ php/commands/search-replace.php | 51 ++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 978959bab..df3884df3 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,6 +15,15 @@ Feature: Do global search/replace guid """ + Scenario: Multisite search/replace + Given a WP multisite install + And I run `wp blog create --slug="foo" --title="foo" --email="foo@example.com"` + And I run `wp search-replace foo bar --multisite` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | + | wp_2_posts | guid | 2 | + | wp_blogs | path | 1 | + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 3a2af0889..478f29683 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,25 +10,54 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] + * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--multisite] */ public function __invoke( $args, $assoc_args ) { - global $wpdb; + //vars + global $wpdb; $old = array_shift( $args ); $new = array_shift( $args ); + $total = 0; + $report = array(); + $dry_run = isset( $assoc_args['dry-run'] ); + $multisite = isset( $assoc_args['multisite'] ); + /** + * build list of tables to find/replace + */ if ( !empty( $args ) ) { $tables = $args; } else { - $tables = $wpdb->tables( 'blog' ); - } - - $total = 0; - $report = array(); + $tables = $wpdb->tables( 'blog' ); - $dry_run = isset( $assoc_args['dry-run'] ); + if( $multisite ) { + $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}blogs ORDER BY blog_id" ) ); + $mu_tables = $wpdb->tables( 'global' ); + + if( ! $wpdb->query("SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) + unset( $mu_tables['sitecategories'] ); //table $prefix_sitecategories not found + + foreach( $blogs as $blog ){ + if( $blog->blog_id == 1 ) + continue; + + foreach( $tables as $table_ref => $table ){ + $tbl = "{$wpdb->prefix}{$blog->blog_id}_{$table_ref}"; + $mu_tables[$tbl] = $tbl; + } + } + + //set multisite vars + $tables = array_merge( $mu_tables, $tables ); + if ( isset( $assoc_args['skip-columns'] ) ) + $assoc_args['skip-columns'] .= ",user_pass"; + else + $assoc_args['skip-columns'] .= "user_pass"; + } + } + //end build list of tables to find/replace if ( isset( $assoc_args['skip-columns'] ) ) $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -37,7 +66,6 @@ public function __invoke( $args, $assoc_args ) { foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); - foreach ( $columns as $col ) { if ( in_array( $col, $skip_columns ) ) continue; @@ -73,6 +101,9 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'chunk_size' => $chunk_size ); + if($primary_key===null) + return "skipped"; + $it = new \WP_CLI\Iterators\Table( $args ); $count = 0; @@ -93,7 +124,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry ); } } - + return $count; } From 415695ee5e56efb2e17512147dfdbc7fccd39912 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:08:10 +0300 Subject: [PATCH 1782/5359] search-replace: whitespace fixes --- php/commands/search-replace.php | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 478f29683..77c47a909 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -13,8 +13,6 @@ class Search_Replace_Command extends WP_CLI_Command { * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--multisite] */ public function __invoke( $args, $assoc_args ) { - - //vars global $wpdb; $old = array_shift( $args ); $new = array_shift( $args ); @@ -23,33 +21,29 @@ public function __invoke( $args, $assoc_args ) { $dry_run = isset( $assoc_args['dry-run'] ); $multisite = isset( $assoc_args['multisite'] ); - /** - * build list of tables to find/replace - */ + // build list of tables to find/replace if ( !empty( $args ) ) { $tables = $args; } else { - $tables = $wpdb->tables( 'blog' ); - if( $multisite ) { + if ( $multisite ) { $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}blogs ORDER BY blog_id" ) ); $mu_tables = $wpdb->tables( 'global' ); - - if( ! $wpdb->query("SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) + + if ( ! $wpdb->query( "SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) unset( $mu_tables['sitecategories'] ); //table $prefix_sitecategories not found - - foreach( $blogs as $blog ){ - if( $blog->blog_id == 1 ) + + foreach ( $blogs as $blog ) { + if ( $blog->blog_id == 1 ) continue; - foreach( $tables as $table_ref => $table ){ + foreach ( $tables as $table_ref => $table ) { $tbl = "{$wpdb->prefix}{$blog->blog_id}_{$table_ref}"; $mu_tables[$tbl] = $tbl; } } - //set multisite vars $tables = array_merge( $mu_tables, $tables ); if ( isset( $assoc_args['skip-columns'] ) ) $assoc_args['skip-columns'] .= ",user_pass"; @@ -57,7 +51,7 @@ public function __invoke( $args, $assoc_args ) { $assoc_args['skip-columns'] .= "user_pass"; } } - //end build list of tables to find/replace + // end build list of tables to find/replace if ( isset( $assoc_args['skip-columns'] ) ) $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -101,9 +95,9 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'chunk_size' => $chunk_size ); - if($primary_key===null) + if ( $primary_key===null ) return "skipped"; - + $it = new \WP_CLI\Iterators\Table( $args ); $count = 0; @@ -124,7 +118,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry ); } } - + return $count; } From 91fa8f55eb4a6820755142c22e2bc0bd2e0c2833 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:09:37 +0300 Subject: [PATCH 1783/5359] search-replace: blacklist user_pass column later --- php/commands/search-replace.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 77c47a909..2d20e251a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -45,10 +45,6 @@ public function __invoke( $args, $assoc_args ) { } $tables = array_merge( $mu_tables, $tables ); - if ( isset( $assoc_args['skip-columns'] ) ) - $assoc_args['skip-columns'] .= ",user_pass"; - else - $assoc_args['skip-columns'] .= "user_pass"; } } // end build list of tables to find/replace @@ -58,6 +54,9 @@ public function __invoke( $args, $assoc_args ) { else $skip_columns = array(); + // never mess with hashed passwords + $skip_columns[] = 'user_pass'; + foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { From 8352de2bafaf2f07f2c6e6520c3ad46a70b93f61 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:17:32 +0300 Subject: [PATCH 1784/5359] search-replace: extract get_table_list() method --- php/commands/search-replace.php | 63 +++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 2d20e251a..600302cc1 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -13,41 +13,11 @@ class Search_Replace_Command extends WP_CLI_Command { * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--multisite] */ public function __invoke( $args, $assoc_args ) { - global $wpdb; $old = array_shift( $args ); $new = array_shift( $args ); $total = 0; $report = array(); $dry_run = isset( $assoc_args['dry-run'] ); - $multisite = isset( $assoc_args['multisite'] ); - - // build list of tables to find/replace - if ( !empty( $args ) ) { - $tables = $args; - } else { - $tables = $wpdb->tables( 'blog' ); - - if ( $multisite ) { - $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}blogs ORDER BY blog_id" ) ); - $mu_tables = $wpdb->tables( 'global' ); - - if ( ! $wpdb->query( "SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) - unset( $mu_tables['sitecategories'] ); //table $prefix_sitecategories not found - - foreach ( $blogs as $blog ) { - if ( $blog->blog_id == 1 ) - continue; - - foreach ( $tables as $table_ref => $table ) { - $tbl = "{$wpdb->prefix}{$blog->blog_id}_{$table_ref}"; - $mu_tables[$tbl] = $tbl; - } - } - - $tables = array_merge( $mu_tables, $tables ); - } - } - // end build list of tables to find/replace if ( isset( $assoc_args['skip-columns'] ) ) $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -57,6 +27,8 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; + $tables = self::get_table_list( $args, isset( $assoc_args['multisite'] ) ); + foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); foreach ( $columns as $col ) { @@ -81,6 +53,37 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::success( "Made $total replacements." ); } + private static function get_table_list( $args, $multisite ) { + global $wpdb; + + if ( !empty( $args ) ) + return $args; + + $tables = $wpdb->tables( 'blog' ); + + if ( $multisite ) { + $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}blogs ORDER BY blog_id" ) ); + $mu_tables = $wpdb->tables( 'global' ); + + if ( ! $wpdb->query( "SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) + unset( $mu_tables['sitecategories'] ); //table $prefix_sitecategories not found + + foreach ( $blogs as $blog ) { + if ( $blog->blog_id == 1 ) + continue; + + foreach ( $tables as $table_ref => $table ) { + $tbl = "{$wpdb->prefix}{$blog->blog_id}_{$table_ref}"; + $mu_tables[$tbl] = $tbl; + } + } + + $tables = array_merge( $mu_tables, $tables ); + } + + return $tables; + } + private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { global $wpdb; From 5eb3aff846f3e7af054590b360c497dec2c6fa3f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:22:21 +0300 Subject: [PATCH 1785/5359] search-replace: fix warning from using wpdb->prepare() with only 1 parameter --- php/commands/search-replace.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 600302cc1..998cacb26 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -62,11 +62,15 @@ private static function get_table_list( $args, $multisite ) { $tables = $wpdb->tables( 'blog' ); if ( $multisite ) { - $blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}blogs ORDER BY blog_id" ) ); $mu_tables = $wpdb->tables( 'global' ); - if ( ! $wpdb->query( "SHOW TABLES LIKE '{$mu_tables['sitecategories']}' " ) ) - unset( $mu_tables['sitecategories'] ); //table $prefix_sitecategories not found + // The $prefix_sitecategories table isn't always present + if ( ! $wpdb->query( $wpdb->prepare( "SHOW TABLES LIKE %s", + $mu_tables['sitecategories'] ) ) ) { + unset( $mu_tables['sitecategories'] ); + } + + $blogs = $wpdb->get_results( "SELECT * FROM $wpdb->blogs ORDER BY blog_id" ); foreach ( $blogs as $blog ) { if ( $blog->blog_id == 1 ) From 7ccbc9d77766d5ffa98ab22ab73629794b6bca70 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:36:18 +0300 Subject: [PATCH 1786/5359] search-replace: use a single SHOW TABLES query to get list of multisite tables Besides simplicity, it avoids warnings for non-existant tables. For example, the Posts 2 Posts plugin creates 2 custom, per-blog tables. But it might not be activated on all blogs. --- php/commands/search-replace.php | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 998cacb26..56e740f6b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -59,30 +59,10 @@ private static function get_table_list( $args, $multisite ) { if ( !empty( $args ) ) return $args; - $tables = $wpdb->tables( 'blog' ); - - if ( $multisite ) { - $mu_tables = $wpdb->tables( 'global' ); - - // The $prefix_sitecategories table isn't always present - if ( ! $wpdb->query( $wpdb->prepare( "SHOW TABLES LIKE %s", - $mu_tables['sitecategories'] ) ) ) { - unset( $mu_tables['sitecategories'] ); - } - - $blogs = $wpdb->get_results( "SELECT * FROM $wpdb->blogs ORDER BY blog_id" ); - - foreach ( $blogs as $blog ) { - if ( $blog->blog_id == 1 ) - continue; - - foreach ( $tables as $table_ref => $table ) { - $tbl = "{$wpdb->prefix}{$blog->blog_id}_{$table_ref}"; - $mu_tables[$tbl] = $tbl; - } - } - - $tables = array_merge( $mu_tables, $tables ); + if ( !$multisite ) { + $tables = $wpdb->tables( 'blog' ); + } else { + $tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->base_prefix}%'" ); } return $tables; From 9234c0804d97e596c2b0168282d55cdf955f0618 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 16:49:38 +0300 Subject: [PATCH 1787/5359] search-replace: move primary key check --- php/commands/search-replace.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 56e740f6b..e7d3faede 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -31,6 +31,14 @@ public function __invoke( $args, $assoc_args ) { foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); + + // since we'll be updating one row at a time, + // we need a primary key to identify the row + if ( null === $primary_key ) { + $report[] = array( $table, '', 'skipped' ); + continue; + } + foreach ( $columns as $col ) { if ( in_array( $col, $skip_columns ) ) continue; @@ -81,9 +89,6 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry 'chunk_size' => $chunk_size ); - if ( $primary_key===null ) - return "skipped"; - $it = new \WP_CLI\Iterators\Table( $args ); $count = 0; From bad9f6d0f2cbaed4819096050a85eefe3a7229ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 8 Jun 2013 17:01:01 +0300 Subject: [PATCH 1788/5359] search-replace: update man page --- man-src/search-replace.txt | 4 ++++ man/search-replace.1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index f6ead0c89..de5fdca91 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -6,6 +6,10 @@ It will correctly handle serialized values, and will not change primary key valu ## OPTIONS +* `--multisite`: + + Search/replace through all the tables in a multisite install. + * `--skip-columns=<columns>`: Do not perform the replacement in the comma-separated columns. diff --git a/man/search-replace.1 b/man/search-replace.1 index 7ee007f60..963900f39 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,7 +7,7 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] [\-\-multisite] . .SH "DESCRIPTION" This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. From ea497952deb1dc6f04fa9b96763bf92436adaf0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 00:06:59 +0300 Subject: [PATCH 1789/5359] bump version to 0.10.0 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 63ea79668..b4c7d5221 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0-RC' ); +define( 'WP_CLI_VERSION', '0.10.0' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 348e6125caf26f9bdcba918a33476d0a15d2f21a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 00:36:50 +0300 Subject: [PATCH 1790/5359] contrib-list: validate github URLs --- utils/contrib-list | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/utils/contrib-list b/utils/contrib-list index 76f5a1531..43d8f1542 100755 --- a/utils/contrib-list +++ b/utils/contrib-list @@ -8,9 +8,22 @@ fi prev_version=$1 linked=$2 +githubify() { + local url="https://github.com/$name" + local response_code=$(curl -o /dev/null --silent --head --write-out '%{http_code}\n' $url) + + if [ "200" != "$response_code" ]; then + echo "$response_code: $url" 1>&2; + fi + + while read name; do + echo " [$name]($url)" + done +} + if [ '-l' == "$linked" ] then - git log --format="%aN" $prev_version -- | sort | uniq | sed 's#\(.*\)# [\1](http://github.com/\1)#' | tr '\n' ',' + git log --format="%aN" $prev_version -- | sort | uniq | githubify | tr '\n' ',' else git log --format="%aN <%aE>" $prev_version -- | sort | uniq fi From 4f6dbb8d53ec5904dd722dfdcdd23b7003fe4812 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 00:51:09 +0300 Subject: [PATCH 1791/5359] mailmap: add new contributors from 0.10 release --- .mailmap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.mailmap b/.mailmap index cb5c30bb2..682554bd4 100644 --- a/.mailmap +++ b/.mailmap @@ -2,13 +2,17 @@ andreascreten <andreas@madewithlove.be> bendoh <ben@thinkoomph.com> builtbylane <lanegoldberg@gmail.com> conatus <alex@recordsonribs.com> +cyberhobo <dylan.k.kuhn@gmail.com> danielbachhuber <d@danielbachhuber.com> drrobotnik <B@Brandons-Mac-Pro-4.local> dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> +future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> +glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> +j3lamp <j3lamp@gmail.com> jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> jmslbam <jmslbam@gmail.com> @@ -28,6 +32,7 @@ nacin <andrewnacin@gmail.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> ocean90 <dominikschilling+git@gmail.com> +om4james <james@jamesc.id.au> roelven <roel@soundcloud.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> @@ -36,7 +41,11 @@ spuriousdata <spuriousdata@gmail.com> svaj <chris@chrisbot.(none)> taupecat <tracy@taupecat.com> tddewey <td@tddewey.com> +tlovett1 <admin@taylorlovett.com> tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> tott <tott@automattic.com> +twisty <tim@brayshaw.com> +westonruter <weston@x-team.com> +westonruter <westonruter@gmail.com> wopr42 <john@zippykid.com> From 61dc7086e497eda0bf5209033601a7c41077af8f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 01:33:58 +0300 Subject: [PATCH 1792/5359] search-replace: rename --multisite flag to --network it's more consistent with other commands fixes #504; see #501 --- features/search-replace.feature | 2 +- man-src/search-replace.txt | 2 +- man/search-replace.1 | 8 +++++++- php/commands/search-replace.php | 8 ++++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index df3884df3..07fa919f1 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -18,7 +18,7 @@ Feature: Do global search/replace Scenario: Multisite search/replace Given a WP multisite install And I run `wp blog create --slug="foo" --title="foo" --email="foo@example.com"` - And I run `wp search-replace foo bar --multisite` + And I run `wp search-replace foo bar --network` Then STDOUT should be a table containing rows: | Table | Column | Replacements | | wp_2_posts | guid | 2 | diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt index de5fdca91..812dfcc97 100644 --- a/man-src/search-replace.txt +++ b/man-src/search-replace.txt @@ -6,7 +6,7 @@ It will correctly handle serialized values, and will not change primary key valu ## OPTIONS -* `--multisite`: +* `--network`: Search/replace through all the tables in a multisite install. diff --git a/man/search-replace.1 b/man/search-replace.1 index 963900f39..6af388a6e 100644 --- a/man/search-replace.1 +++ b/man/search-replace.1 @@ -7,7 +7,7 @@ \fBwp\-search\-replace\fR \- Search/replace strings in the database\. . .SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] [\-\-multisite] +wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] [\-\-network] . .SH "DESCRIPTION" This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. @@ -18,6 +18,12 @@ It will correctly handle serialized values, and will not change primary key valu .SH "OPTIONS" . .TP +\fB\-\-network\fR: +. +.IP +Search/replace through all the tables in a multisite install\. +. +.TP \fB\-\-skip\-columns=<columns>\fR: . .IP diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e7d3faede..2a0f3309e 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,7 +10,7 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--multisite] + * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--network] */ public function __invoke( $args, $assoc_args ) { $old = array_shift( $args ); @@ -27,7 +27,7 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - $tables = self::get_table_list( $args, isset( $assoc_args['multisite'] ) ); + $tables = self::get_table_list( $args, isset( $assoc_args['network'] ) ); foreach ( $tables as $table ) { list( $primary_key, $columns ) = self::get_columns( $table ); @@ -61,13 +61,13 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::success( "Made $total replacements." ); } - private static function get_table_list( $args, $multisite ) { + private static function get_table_list( $args, $network ) { global $wpdb; if ( !empty( $args ) ) return $args; - if ( !$multisite ) { + if ( !$network ) { $tables = $wpdb->tables( 'blog' ); } else { $tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->base_prefix}%'" ); From 0066dac71fc85acc4f9da2a56824cafdb99fcd1c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 13:57:54 +0300 Subject: [PATCH 1793/5359] link to contributor guide from readme --- CONTRIBUTING.md | 1 + README.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ce37fda..a2053192d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ Contribute So you've got an awesome idea to throw into WP-CLI. Great! Here's the process, in a nutshell: 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. +2. Clone the repo and run `./utils/dev-build`. 2. Make the code changes in your fork. 3. Open a pull request. diff --git a/README.md b/README.md index 2c49bc83d..51151a18a 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,7 @@ Need even more info? Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. + +Contributing +------------ +See [CONTRIBUTING.md](CONTRIBUTING.md). From 6ebf0b4f6a3ac81659530f1764fca32b049458f9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 15:02:15 +0300 Subject: [PATCH 1794/5359] bump version to 0.11.0-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index b4c7d5221..59cee2480 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0' ); +define( 'WP_CLI_VERSION', '0.11.0-alpha' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 653c6c7f9d014d6136945faa78e23908a18e382c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 15:37:23 +0300 Subject: [PATCH 1795/5359] contributing: remove confusing ./utils/dev-build step --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2053192d..52ce37fda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,6 @@ Contribute So you've got an awesome idea to throw into WP-CLI. Great! Here's the process, in a nutshell: 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. -2. Clone the repo and run `./utils/dev-build`. 2. Make the code changes in your fork. 3. Open a pull request. From e5d5c09c0ad444831b8297f554ffa56673c4624f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 15:23:53 +0300 Subject: [PATCH 1796/5359] blog: don't hide multisite-only subcommands; just throw an error This is good for `wp help --gen`, which doesn't have a WP install. It's also good for users, since they have a clear indication of why the subcommand doesn't work. --- php/commands/blog.php | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/php/commands/blog.php b/php/commands/blog.php index d92e3ac39..dfc91e1db 100644 --- a/php/commands/blog.php +++ b/php/commands/blog.php @@ -1,7 +1,7 @@ <?php /** - * Manage blog. + * Perform blog-wide operations. * * @package wp-cli */ @@ -124,12 +124,6 @@ public function _empty( $args, $assoc_args ) { WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); } -} - -/** - * Manage blogs in a multisite install. - */ -class MS_Blog_Command extends Blog_Command { /** * Delete a blog in a multisite install. @@ -137,6 +131,10 @@ class MS_Blog_Command extends Blog_Command { * @synopsis [<blog-id>] [--slug=<slug>] [--yes] [--keep-tables] */ function delete( $args, $assoc_args ) { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + if ( isset( $assoc_args['slug'] ) ) { $blog = get_blog_details( trim( $assoc_args['slug'], '/' ) ); } else { @@ -184,6 +182,10 @@ private function _get_site( $site_id ) { * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] [--porcelain] */ public function create( $_, $assoc_args ) { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + global $wpdb; $base = $assoc_args['slug']; @@ -278,11 +280,5 @@ public function create( $_, $assoc_args ) { } } -// We want multisite subcommands to be available when doing `wp help --gen blog` -if ( !function_exists( 'add_filter' ) || is_multisite() ) - $command_class = 'MS_Blog_Command'; -else - $command_class = 'Blog_Command'; - -WP_CLI::add_command( 'blog', $command_class ); +WP_CLI::add_command( 'blog', 'Blog_Command' ); From c88cfc815e65ff16519118426eb5419ed4e5a8a9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 16:40:22 +0300 Subject: [PATCH 1797/5359] move 'sql' aliasing to Runner --- php/WP_CLI/Dispatcher/RootCommand.php | 7 ------- php/WP_CLI/Runner.php | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 9fc159aee..fb9b05de4 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -91,13 +91,6 @@ function pre_invoke( &$args ) { function find_subcommand( &$args ) { $command = array_shift( $args ); - $aliases = array( - 'sql' => 'db' - ); - - if ( isset( $aliases[ $command ] ) ) - $command = $aliases[ $command ]; - Utils\load_command( $command ); if ( !isset( $this->subcommands[ $command ] ) ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 621097b0d..6b17b49c8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -223,6 +223,11 @@ private static function back_compat_conversions( $r ) { unset( $assoc_args['help'] ); } + // sql -> db + if ( count( $args ) > 0 && 'sql' == $args[0] ) { + $args[0] = 'db'; + } + // {plugin|theme} update --all -> {plugin|theme} update-all if ( count( $args ) > 1 && in_array( $args[0], array( 'plugin', 'theme' ) ) && $args[1] == 'update' && isset( $assoc_args['all'] ) From a8132f2db549185c732b04a38e1867d7b46e8c8d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 21:41:20 +0300 Subject: [PATCH 1798/5359] branding: the project name is 'WP-CLI', not 'wp-cli' It's an abbreviation for 'WordPress Command-Line Interface' --- README.md | 2 +- php/boot-fs.php | 2 +- php/class-wp-cli.php | 2 +- php/commands/_sys.php | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 51151a18a..a85012c68 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ WP-CLI [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) -wp-cli is a set of command-line tools for managing WordPress installations. +WP-CLI is a set of command-line tools for managing WordPress installations. Where can I get more info? -------------------------- diff --git a/php/boot-fs.php b/php/boot-fs.php index a3311c887..a227bfede 100644 --- a/php/boot-fs.php +++ b/php/boot-fs.php @@ -8,7 +8,7 @@ } if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { - printf( "Error: wp-cli requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); + printf( "Error: WP-CLI requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); die(-1); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1daf81559..71d87d80b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -39,7 +39,7 @@ static function set_logger( $logger ) { } /** - * Add a command to the wp-cli list of commands + * Add a command to the WP-CLI list of commands * * @param string $name The name of the command that will be used in the cli * @param string $class The command implementation diff --git a/php/commands/_sys.php b/php/commands/_sys.php index af2b1b714..95aabdde2 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -23,7 +23,7 @@ private function command_to_array( $command ) { } function version() { - WP_CLI::line( 'wp-cli ' . WP_CLI_VERSION ); + WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); } function info() { @@ -32,9 +32,9 @@ function info() { WP_CLI::line( "PHP binary:\t" . $php_bin ); WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "wp-cli root:\t" . WP_CLI_ROOT ); - WP_CLI::line( "wp-cli config:\t" . WP_CLI::get_config_path() ); - WP_CLI::line( "wp-cli version:\t" . WP_CLI_VERSION ); + WP_CLI::line( "WP-CLI root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "WP-CLI config:\t" . WP_CLI::get_config_path() ); + WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); } /** From 268515f2ecb9da6ff2c1c54433ff3a441a805964 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 22:19:19 +0300 Subject: [PATCH 1799/5359] get rid of AtomicCommand interface --- .../Dispatcher/AbstractCommandContainer.php | 8 ++++++++ php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/WP_CLI/Dispatcher/Subcommand.php | 6 +++++- php/WP_CLI/Runner.php | 2 +- php/commands/_sys.php | 10 +++++----- php/dispatcher.php | 17 +++-------------- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/php/WP_CLI/Dispatcher/AbstractCommandContainer.php b/php/WP_CLI/Dispatcher/AbstractCommandContainer.php index 29136f920..7724a9b48 100644 --- a/php/WP_CLI/Dispatcher/AbstractCommandContainer.php +++ b/php/WP_CLI/Dispatcher/AbstractCommandContainer.php @@ -6,6 +6,14 @@ abstract class AbstractCommandContainer implements Command, CommandContainer { protected $subcommands = array(); + function get_synopsis() { + return ''; + } + + function invoke( $args, $assoc_args ) { + $this->show_usage(); + } + function add_subcommand( $name, Command $command ) { $this->subcommands[ $name ] = $command; } diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index fb9b05de4..99f4c2534 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -31,7 +31,7 @@ function show_usage() { \WP_CLI::line( sprintf( " %s %s", implode( ' ', get_path( $command ) ), - implode( '|', array_keys( get_subcommands( $command ) ) ) + implode( '|', array_keys( $command->get_subcommands() ) ) ) ); } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 91dfcbf54..c775ece89 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class Subcommand implements Command, AtomicCommand, Documentable { +class Subcommand implements Command, Documentable { private $parent, $name, $class, $method, $docparser; @@ -35,6 +35,10 @@ function get_parent() { return $this->parent; } + function get_subcommands() { + return array(); + } + function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . $this->get_full_synopsis() ); } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6b17b49c8..5332f7516 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -376,7 +376,7 @@ public function after_wp_load() { // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { - $subcommands = Dispatcher\get_subcommands( $command ); + $subcommands = $command->get_subcommands(); WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); } diff --git a/php/commands/_sys.php b/php/commands/_sys.php index 95aabdde2..963d48af6 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -11,12 +11,12 @@ private function command_to_array( $command ) { 'description' => $command->get_shortdesc(), ); - if ( $command instanceof Dispatcher\AtomicCommand ) { + foreach ( $command->get_subcommands() as $subcommand ) { + $dump['subcommands'][] = self::command_to_array( $subcommand ); + } + + if ( empty( $dump['subcommands'] ) ) { $dump['synopsis'] = (string) $command->get_synopsis(); - } else { - foreach ( Dispatcher\get_subcommands( $command ) as $subcommand ) { - $dump['subcommands'][] = self::command_to_array( $subcommand ); - } } return $dump; diff --git a/php/dispatcher.php b/php/dispatcher.php index 168ced1eb..b9921cb53 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -2,13 +2,6 @@ namespace WP_CLI\Dispatcher; -function get_subcommands( $command ) { - if ( $command instanceof CommandContainer ) - return $command->get_subcommands(); - - return array(); -} - function get_path( Command $command ) { $path = array(); @@ -24,22 +17,18 @@ interface Command { function get_name(); function get_parent(); + function get_synopsis(); - function show_usage(); -} - - -interface AtomicCommand { + function get_subcommands(); - function get_synopsis(); function invoke( $args, $assoc_args ); + function show_usage(); } interface CommandContainer { function add_subcommand( $name, Command $command ); - function get_subcommands(); function find_subcommand( &$args ); function pre_invoke( &$args ); From cd092fd19732e640cd171f57406af3bf2870302d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 22:23:00 +0300 Subject: [PATCH 1800/5359] everything is documentable, so get rid of the Documentable interface --- php/WP_CLI/Dispatcher/CompositeCommand.php | 2 +- php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/commands/help.php | 3 +-- php/dispatcher.php | 10 +++------- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 897992bbe..f39b9b826 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class CompositeCommand extends AbstractCommandContainer implements Documentable { +class CompositeCommand extends AbstractCommandContainer { protected $name; protected $shortdesc; diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 99f4c2534..88da4a363 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -4,7 +4,7 @@ use \WP_CLI\Utils; -class RootCommand extends AbstractCommandContainer implements Documentable { +class RootCommand extends AbstractCommandContainer { function get_name() { return 'wp'; diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c775ece89..1e0fcd341 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -class Subcommand implements Command, Documentable { +class Subcommand implements Command { private $parent, $name, $class, $method, $docparser; diff --git a/php/commands/help.php b/php/commands/help.php index 12a31397d..d23675de0 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -106,8 +106,7 @@ private static function get_markdown( $doc_path, $command ) { $fd = fopen( "php://temp", "rw" ); - if ( $command instanceof Dispatcher\Documentable ) - self::add_initial_markdown( $fd, $command ); + self::add_initial_markdown( $fd, $command ); fwrite( $fd, file_get_contents( $doc_path ) ); diff --git a/php/dispatcher.php b/php/dispatcher.php index b9921cb53..25d7ee327 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -17,7 +17,10 @@ interface Command { function get_name(); function get_parent(); + function get_synopsis(); + function get_shortdesc(); + function get_full_synopsis(); function get_subcommands(); @@ -34,10 +37,3 @@ function find_subcommand( &$args ); function pre_invoke( &$args ); } - -interface Documentable { - - function get_shortdesc(); - function get_full_synopsis(); -} - From b34ede5128979309744048fcb7e979f1c63efd45 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 22:48:13 +0300 Subject: [PATCH 1801/5359] convert get_full_synopsis() method to a standalone function --- php/WP_CLI/Dispatcher/CompositeCommand.php | 10 -------- php/WP_CLI/Dispatcher/RootCommand.php | 4 --- php/WP_CLI/Dispatcher/Subcommand.php | 22 +--------------- php/commands/help.php | 2 +- php/dispatcher.php | 29 +++++++++++++++++++++- 5 files changed, 30 insertions(+), 37 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index f39b9b826..4febf465e 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -73,15 +73,5 @@ private static function get_aliases( $subcommands ) { public function get_shortdesc() { return $this->shortdesc; } - - public function get_full_synopsis() { - $str = array(); - - foreach ( $this->subcommands as $subcommand ) { - $str[] = $subcommand->get_full_synopsis( true ); - } - - return implode( "\n\n", $str ); - } } diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 88da4a363..f50213487 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -18,10 +18,6 @@ function get_shortdesc() { return ''; } - function get_full_synopsis() { - return ''; - } - function show_usage() { \WP_CLI::line( 'Available commands:' ); diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1e0fcd341..5af76a1ef 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -40,33 +40,13 @@ function get_subcommands() { } function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $prefix . $this->get_full_synopsis() ); + \WP_CLI::line( $prefix . get_full_synopsis( $this ) ); } function get_shortdesc() { return $this->docparser->get_shortdesc(); } - function get_full_synopsis( $validate = false ) { - $full_name = implode( ' ', get_path( $this ) ); - $synopsis = $this->get_synopsis(); - - if ( $validate ) { - $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); - - foreach ( $tokens as $token ) { - if ( 'unknown' == $token['type'] ) { - \WP_CLI::warning( sprintf( - "Invalid token '%s' in synopsis for '%s'", - $token['token'], $full_name - ) ); - } - } - } - - return "$full_name $synopsis"; - } - function get_synopsis() { return $this->docparser->get_synopsis(); } diff --git a/php/commands/help.php b/php/commands/help.php index d23675de0..b56281a63 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -126,7 +126,7 @@ private static function add_initial_markdown( $fd, $command ) { 'shortdesc' => $command->get_shortdesc(), ); - $synopsis = $command->get_full_synopsis(); + $synopsis = Dispatcher\get_full_synopsis( $command, true ); $synopsis = str_replace( '_', '\_', $synopsis ); $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); diff --git a/php/dispatcher.php b/php/dispatcher.php index 25d7ee327..689acba45 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -12,6 +12,34 @@ function get_path( Command $command ) { return $path; } +function get_full_synopsis( $command, $validate = false ) { + $subcommands = $command->get_subcommands(); + + if ( empty( $subcommands ) ) { + $synopsis = $command->get_synopsis(); + + if ( $validate ) { + $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); + + foreach ( $tokens as $token ) { + if ( 'unknown' == $token['type'] ) { + \WP_CLI::warning( sprintf( + "Invalid token '%s' in synopsis for '%s'", + $token['token'], $full_name + ) ); + } + } + } + + $full_name = implode( ' ', get_path( $command ) ); + + return "$full_name $synopsis"; + } else { + return implode( "\n\n", array_map( __FUNCTION__, + $subcommands ) ); + } +} + interface Command { @@ -20,7 +48,6 @@ function get_parent(); function get_synopsis(); function get_shortdesc(); - function get_full_synopsis(); function get_subcommands(); From 7bc411cbea62a85caa7bcfb61945a5dc79379890 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 22:52:56 +0300 Subject: [PATCH 1802/5359] Simplify dispatch class hierarchy: * merge AbstractCommandContainer into CompositeCommand * make RootCommand inherit from CompositeCommand * get rid of redundant Command and CommandContainer interfaces --- .../Dispatcher/AbstractCommandContainer.php | 27 ------------------- php/WP_CLI/Dispatcher/CompositeCommand.php | 24 ++++++++++++++++- php/WP_CLI/Dispatcher/RootCommand.php | 13 +++++---- php/WP_CLI/Dispatcher/Subcommand.php | 7 +++-- php/class-wp-cli.php | 6 ++--- php/commands/help.php | 4 +-- php/dispatcher.php | 26 +----------------- php/utils.php | 2 +- 8 files changed, 41 insertions(+), 68 deletions(-) delete mode 100644 php/WP_CLI/Dispatcher/AbstractCommandContainer.php diff --git a/php/WP_CLI/Dispatcher/AbstractCommandContainer.php b/php/WP_CLI/Dispatcher/AbstractCommandContainer.php deleted file mode 100644 index 7724a9b48..000000000 --- a/php/WP_CLI/Dispatcher/AbstractCommandContainer.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -abstract class AbstractCommandContainer implements Command, CommandContainer { - - protected $subcommands = array(); - - function get_synopsis() { - return ''; - } - - function invoke( $args, $assoc_args ) { - $this->show_usage(); - } - - function add_subcommand( $name, Command $command ) { - $this->subcommands[ $name ] = $command; - } - - function get_subcommands() { - ksort( $this->subcommands ); - - return $this->subcommands; - } -} - diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 4febf465e..159fcfb73 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,16 +2,30 @@ namespace WP_CLI\Dispatcher; -class CompositeCommand extends AbstractCommandContainer { +/** + * A non-leaf node in the command tree. + */ +class CompositeCommand { protected $name; protected $shortdesc; + protected $subcommands = array(); public function __construct( $name, $shortdesc ) { $this->name = $name; $this->shortdesc = $shortdesc; } + function add_subcommand( $name, $command ) { + $this->subcommands[ $name ] = $command; + } + + function get_subcommands() { + ksort( $this->subcommands ); + + return $this->subcommands; + } + function get_name() { return $this->name; } @@ -20,6 +34,14 @@ function get_parent() { return \WP_CLI::$root; } + function get_synopsis() { + return ''; + } + + function invoke( $args, $assoc_args ) { + $this->show_usage(); + } + function show_usage() { $methods = $this->get_subcommands(); diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index f50213487..98be09d49 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -4,20 +4,19 @@ use \WP_CLI\Utils; -class RootCommand extends AbstractCommandContainer { +/** + * The root node in the command tree. + */ +class RootCommand extends CompositeCommand { - function get_name() { - return 'wp'; + function __construct() { + parent::__construct( 'wp', '' ); } function get_parent() { return false; } - function get_shortdesc() { - return ''; - } - function show_usage() { \WP_CLI::line( 'Available commands:' ); diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 5af76a1ef..1742f1c38 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -2,11 +2,14 @@ namespace WP_CLI\Dispatcher; -class Subcommand implements Command { +/** + * A leaf node in the command tree. + */ +class Subcommand { private $parent, $name, $class, $method, $docparser; - function __construct( CommandContainer $parent, $class, \ReflectionMethod $method, $name = false ) { + function __construct( CompositeCommand $parent, $class, \ReflectionMethod $method, $name = false ) { $this->class = $class; $docparser = new \WP_CLI\DocParser( $method ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 71d87d80b..3b1e7c230 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -83,7 +83,7 @@ private static function create_composite_command( $name, $reflection ) { return $container; } - private static function get_full_name( Dispatcher\Command $command ) { + private static function get_full_name( $command ) { $path = Dispatcher\get_path( $command ); array_shift( $path ); @@ -246,7 +246,7 @@ static function get_config( $key = null ) { private static function find_command_to_run( $args ) { $command = \WP_CLI::$root; - while ( !empty( $args ) && $command instanceof Dispatcher\CommandContainer ) { + while ( !empty( $args ) && $command instanceof Dispatcher\CompositeCommand ) { $subcommand = $command->pre_invoke( $args ); if ( !$subcommand ) break; @@ -266,7 +266,7 @@ private static function find_command_to_run( $args ) { public static function run_command( $args, $assoc_args = array() ) { list( $command, $final_args ) = self::find_command_to_run( $args ); - if ( $command instanceof Dispatcher\CommandContainer ) { + if ( $command instanceof Dispatcher\CompositeCommand ) { $command->show_usage(); } else { $command->invoke( $final_args, $assoc_args ); diff --git a/php/commands/help.php b/php/commands/help.php index b56281a63..934de6929 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -92,7 +92,7 @@ private static function _generate( $src_dir, $dest_dir, $command ) { self::call_ronn( self::get_markdown( $src_path, $command ), $dest_path ); - if ( $command instanceof Dispatcher\CommandContainer ) { + if ( $command instanceof Dispatcher\CompositeCommand ) { foreach ( $command->get_subcommands() as $subcommand ) { self::_generate( $src_dir, $dest_dir, $subcommand ); } @@ -138,7 +138,7 @@ private static function add_initial_markdown( $fd, $command ) { \WP_CLI::warning( "No shortdesc for $name_s" ); } - if ( $command instanceof Dispatcher\CommandContainer ) { + if ( $command instanceof Dispatcher\CompositeCommand ) { foreach ( $command->get_subcommands() as $subcommand ) { $binding['has-subcommands']['subcommands'][] = array( 'name' => $subcommand->get_name(), diff --git a/php/dispatcher.php b/php/dispatcher.php index 689acba45..45903834f 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -2,7 +2,7 @@ namespace WP_CLI\Dispatcher; -function get_path( Command $command ) { +function get_path( $command ) { $path = array(); do { @@ -40,27 +40,3 @@ function get_full_synopsis( $command, $validate = false ) { } } - -interface Command { - - function get_name(); - function get_parent(); - - function get_synopsis(); - function get_shortdesc(); - - function get_subcommands(); - - function invoke( $args, $assoc_args ); - function show_usage(); -} - - -interface CommandContainer { - - function add_subcommand( $name, Command $command ); - - function find_subcommand( &$args ); - function pre_invoke( &$args ); -} - diff --git a/php/utils.php b/php/utils.php index 7d3fe7afc..49a87f609 100644 --- a/php/utils.php +++ b/php/utils.php @@ -385,7 +385,7 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { function find_subcommand( $args ) { $command = \WP_CLI::$root; - while ( !empty( $args ) && $command && $command instanceof Dispatcher\CommandContainer ) { + while ( !empty( $args ) && $command && $command instanceof Dispatcher\CompositeCommand ) { $command = $command->find_subcommand( $args ); } From 8526f9e4a0dbcde27f3f99e6b7cc1baa25ac7f54 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 23:38:12 +0300 Subject: [PATCH 1803/5359] make Subcommand inherit from CompositeCommand --- php/WP_CLI/Dispatcher/CompositeCommand.php | 29 ++++++++++------- php/WP_CLI/Dispatcher/RootCommand.php | 11 ++++--- php/WP_CLI/Dispatcher/Subcommand.php | 37 ++++++---------------- php/class-wp-cli.php | 11 +++---- php/commands/help.php | 4 +-- php/utils.php | 2 +- 6 files changed, 40 insertions(+), 54 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 159fcfb73..446bfbac3 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -7,19 +7,30 @@ */ class CompositeCommand { - protected $name; - protected $shortdesc; - protected $subcommands = array(); + protected $name, $shortdesc, $synopsis; + + protected $parent, $subcommands = array(); + + public function __construct( $parent, $name, $shortdesc, $synopsis = '' ) { + $this->parent = $parent; - public function __construct( $name, $shortdesc ) { $this->name = $name; $this->shortdesc = $shortdesc; + $this->synopsis = $synopsis; + } + + function get_parent() { + return $this->parent; } function add_subcommand( $name, $command ) { $this->subcommands[ $name ] = $command; } + function has_subcommands() { + return !empty( $this->subcommands ); + } + function get_subcommands() { ksort( $this->subcommands ); @@ -30,12 +41,12 @@ function get_name() { return $this->name; } - function get_parent() { - return \WP_CLI::$root; + function get_shortdesc() { + return $this->shortdesc; } function get_synopsis() { - return ''; + return $this->synopsis; } function invoke( $args, $assoc_args ) { @@ -91,9 +102,5 @@ private static function get_aliases( $subcommands ) { return $aliases; } - - public function get_shortdesc() { - return $this->shortdesc; - } } diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 98be09d49..800ff89aa 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -10,11 +10,7 @@ class RootCommand extends CompositeCommand { function __construct() { - parent::__construct( 'wp', '' ); - } - - function get_parent() { - return false; + parent::__construct( false, 'wp', '' ); } function show_usage() { @@ -100,5 +96,10 @@ function get_subcommands() { return parent::get_subcommands(); } + + function has_subcommands() { + // Commands are lazy-loaded, so we need to assume there will be some + return true; + } } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1742f1c38..69249d97a 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -5,55 +5,36 @@ /** * A leaf node in the command tree. */ -class Subcommand { +class Subcommand extends CompositeCommand { - private $parent, $name, $class, $method, $docparser; + private $class, $method; function __construct( CompositeCommand $parent, $class, \ReflectionMethod $method, $name = false ) { $this->class = $class; + $this->method = $method; + $docparser = new \WP_CLI\DocParser( $method ); + $this->alias = $docparser->get_tag( 'alias' ); + if ( !$name ) $name = $docparser->get_tag( 'subcommand' ); if ( !$name ) $name = $method->name; - $this->parent = $parent; - $this->name = $name; - - $this->method = $method; - $this->docparser = $docparser; + parent::__construct( $parent, $name, + $docparser->get_shortdesc(), $docparser->get_synopsis() ); } function get_alias() { - return $this->docparser->get_tag( 'alias' ); - } - - function get_name() { - return $this->name; - } - - function get_parent() { - return $this->parent; - } - - function get_subcommands() { - return array(); + return $this->alias; } function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $prefix . get_full_synopsis( $this ) ); } - function get_shortdesc() { - return $this->docparser->get_shortdesc(); - } - - function get_synopsis() { - return $this->docparser->get_synopsis(); - } - private function validate_args( $args, &$assoc_args ) { $synopsis = $this->get_synopsis(); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3b1e7c230..cbf7f1f22 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -63,7 +63,8 @@ static function add_command( $name, $class ) { private static function create_composite_command( $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection ); - $container = new Dispatcher\CompositeCommand( $name, $docparser->get_shortdesc() ); + $container = new Dispatcher\CompositeCommand( self::$root, $name, + $docparser->get_shortdesc() ); foreach ( $reflection->getMethods() as $method ) { if ( !self::_is_good_method( $method ) ) @@ -246,7 +247,7 @@ static function get_config( $key = null ) { private static function find_command_to_run( $args ) { $command = \WP_CLI::$root; - while ( !empty( $args ) && $command instanceof Dispatcher\CompositeCommand ) { + while ( !empty( $args ) && $command->has_subcommands() ) { $subcommand = $command->pre_invoke( $args ); if ( !$subcommand ) break; @@ -266,11 +267,7 @@ private static function find_command_to_run( $args ) { public static function run_command( $args, $assoc_args = array() ) { list( $command, $final_args ) = self::find_command_to_run( $args ); - if ( $command instanceof Dispatcher\CompositeCommand ) { - $command->show_usage(); - } else { - $command->invoke( $final_args, $assoc_args ); - } + $command->invoke( $final_args, $assoc_args ); } // back-compat diff --git a/php/commands/help.php b/php/commands/help.php index 934de6929..39e5da307 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -92,7 +92,7 @@ private static function _generate( $src_dir, $dest_dir, $command ) { self::call_ronn( self::get_markdown( $src_path, $command ), $dest_path ); - if ( $command instanceof Dispatcher\CompositeCommand ) { + if ( $command->has_subcommands() ) { foreach ( $command->get_subcommands() as $subcommand ) { self::_generate( $src_dir, $dest_dir, $subcommand ); } @@ -138,7 +138,7 @@ private static function add_initial_markdown( $fd, $command ) { \WP_CLI::warning( "No shortdesc for $name_s" ); } - if ( $command instanceof Dispatcher\CompositeCommand ) { + if ( $command->has_subcommands() ) { foreach ( $command->get_subcommands() as $subcommand ) { $binding['has-subcommands']['subcommands'][] = array( 'name' => $subcommand->get_name(), diff --git a/php/utils.php b/php/utils.php index 49a87f609..93ffad35f 100644 --- a/php/utils.php +++ b/php/utils.php @@ -385,7 +385,7 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { function find_subcommand( $args ) { $command = \WP_CLI::$root; - while ( !empty( $args ) && $command && $command instanceof Dispatcher\CompositeCommand ) { + while ( !empty( $args ) && $command && $command->has_subcommands() ) { $command = $command->find_subcommand( $args ); } From 810689dff7e870d79decf744d0830caef0ff825d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 00:30:10 +0300 Subject: [PATCH 1804/5359] get rid of pre_invoke() method --- php/WP_CLI/Dispatcher/CompositeCommand.php | 4 ---- php/WP_CLI/Dispatcher/RootCommand.php | 11 ----------- php/class-wp-cli.php | 13 ++++++++++--- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 446bfbac3..42adc9635 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -68,10 +68,6 @@ function show_usage() { \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); } - function pre_invoke( &$args ) { - return $this->find_subcommand( $args ); - } - function find_subcommand( &$args ) { $name = array_shift( $args ); diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 800ff89aa..0f8654ef0 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -68,17 +68,6 @@ private static function generate_synopsis() { } } - function pre_invoke( &$args ) { - $cmd_name = $args[0]; - - $command = $this->find_subcommand( $args ); - - if ( !$command ) - \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $cmd_name ) ); - - return $command; - } - function find_subcommand( &$args ) { $command = array_shift( $args ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cbf7f1f22..06708d0ea 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -247,10 +247,17 @@ static function get_config( $key = null ) { private static function find_command_to_run( $args ) { $command = \WP_CLI::$root; + $cmd_path = array(); + while ( !empty( $args ) && $command->has_subcommands() ) { - $subcommand = $command->pre_invoke( $args ); - if ( !$subcommand ) - break; + $cmd_path[] = $args[0]; + + $subcommand = $command->find_subcommand( $args ); + + if ( !$subcommand ) { + \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", + implode( ' ', $cmd_path ) ) ); + } $command = $subcommand; } From 89058ba5296b9e2c0af619dcca431691fd996cd5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 00:35:48 +0300 Subject: [PATCH 1805/5359] move find_command() utility to Help_Command class it's not used anywhere else, nor should it be --- php/commands/help.php | 14 ++++++++++++-- php/utils.php | 10 ---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 39e5da307..d2b8691e3 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -17,12 +17,22 @@ function __invoke( $args, $assoc_args ) { $this->show( $args ); } + private static function find_subcommand( $args ) { + $command = \WP_CLI::$root; + + while ( !empty( $args ) && $command && $command->has_subcommands() ) { + $command = $command->find_subcommand( $args ); + } + + return $command; + } + private function show( $args ) { if ( self::maybe_show_manpage( $args ) ) { exit; } - $command = WP_CLI\Utils\find_subcommand( $args ); + $command = self::find_subcommand( $args ); if ( $command ) { $command->show_usage(); @@ -42,7 +52,7 @@ private function generate( $args ) { $arg_copy = $args; - $command = WP_CLI\Utils\find_subcommand( $args ); + $command = self::find_subcommand( $args ); if ( $command ) { foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { diff --git a/php/utils.php b/php/utils.php index 93ffad35f..bd5cada51 100644 --- a/php/utils.php +++ b/php/utils.php @@ -382,16 +382,6 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { return $output; } -function find_subcommand( $args ) { - $command = \WP_CLI::$root; - - while ( !empty( $args ) && $command && $command->has_subcommands() ) { - $command = $command->find_subcommand( $args ); - } - - return $command; -} - function run_mysql_query( $query, $args ) { // TODO: use PDO? From 65e4d75d3423f3d89b60a34038a51a50798423f1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 02:30:38 +0300 Subject: [PATCH 1806/5359] extract create_subcommand() method --- php/WP_CLI/Dispatcher/Subcommand.php | 15 ++++----------- php/class-wp-cli.php | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 69249d97a..00152d1d8 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -7,24 +7,17 @@ */ class Subcommand extends CompositeCommand { + private $alias; + private $class, $method; - function __construct( CompositeCommand $parent, $class, \ReflectionMethod $method, $name = false ) { + function __construct( $parent, $name, $class, \ReflectionMethod $method, $docparser ) { $this->class = $class; $this->method = $method; - $docparser = new \WP_CLI\DocParser( $method ); - $this->alias = $docparser->get_tag( 'alias' ); - if ( !$name ) - $name = $docparser->get_tag( 'subcommand' ); - - if ( !$name ) - $name = $method->name; - - parent::__construct( $parent, $name, - $docparser->get_shortdesc(), $docparser->get_synopsis() ); + parent::__construct( $parent, $name, $docparser->get_shortdesc(), $docparser->get_synopsis() ); } function get_alias() { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 06708d0ea..1a036d49c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -51,8 +51,8 @@ static function add_command( $name, $class ) { $reflection = new \ReflectionClass( $class ); if ( $reflection->hasMethod( '__invoke' ) ) { - $command = new Dispatcher\Subcommand( self::$root, $reflection->name, - $reflection->getMethod( '__invoke' ), $name ); + $command = self::create_subcommand( self::$root, $name, $reflection->name, + $reflection->getMethod( '__invoke' ) ); } else { $command = self::create_composite_command( $name, $reflection ); } @@ -60,6 +60,18 @@ static function add_command( $name, $class ) { self::$root->add_subcommand( $name, $command ); } + private static function create_subcommand( $parent, $name, $class_name, $method ) { + $docparser = new \WP_CLI\DocParser( $method ); + + if ( !$name ) + $name = $docparser->get_tag( 'subcommand' ); + + if ( !$name ) + $name = $method->name; + + return new Dispatcher\Subcommand( $parent, $name, $class_name, $method, $docparser ); + } + private static function create_composite_command( $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection ); @@ -70,7 +82,7 @@ private static function create_composite_command( $name, $reflection ) { if ( !self::_is_good_method( $method ) ) continue; - $subcommand = new Dispatcher\Subcommand( $container, $reflection->name, $method ); + $subcommand = self::create_subcommand( $container, false, $reflection->name, $method ); $subcommand_name = $subcommand->get_name(); $full_name = self::get_full_name( $subcommand ); From 00b154962caf3dc2336376fe4cc3c9a2f5379ad4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 02:50:01 +0300 Subject: [PATCH 1807/5359] make the Subcommand constructor accept a callback the idea is to have fewer parameters, with a clearer purpose --- php/WP_CLI/Dispatcher/Subcommand.php | 11 ++++------- php/class-wp-cli.php | 8 +++++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 00152d1d8..c86b096e6 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -9,11 +9,10 @@ class Subcommand extends CompositeCommand { private $alias; - private $class, $method; + private $when_invoked; - function __construct( $parent, $name, $class, \ReflectionMethod $method, $docparser ) { - $this->class = $class; - $this->method = $method; + function __construct( $parent, $name, $when_invoked, $docparser ) { + $this->when_invoked = $when_invoked; $this->alias = $docparser->get_tag( 'alias' ); @@ -61,9 +60,7 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { $this->validate_args( $args, $assoc_args ); - $instance = new $this->class; - - call_user_func( array( $instance, $this->method->name ), $args, $assoc_args ); + call_user_func( $this->when_invoked, $args, $assoc_args ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1a036d49c..cb9a0a9e0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -69,7 +69,13 @@ private static function create_subcommand( $parent, $name, $class_name, $method if ( !$name ) $name = $method->name; - return new Dispatcher\Subcommand( $parent, $name, $class_name, $method, $docparser ); + $method_name = $method->name; + + $when_invoked = function ( $args, $assoc_args ) use ( $class_name, $method_name ) { + call_user_func( array( new $class_name, $method_name ), $args, $assoc_args ); + }; + + return new Dispatcher\Subcommand( $parent, $name, $when_invoked, $docparser ); } private static function create_composite_command( $name, $reflection ) { From 7b4546fa021f0a9544d83f4b85635cb93329f4e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 03:15:47 +0300 Subject: [PATCH 1808/5359] pass docparser directly to CompositeCommand constructor --- php/WP_CLI/Dispatcher/CompositeCommand.php | 7 ++++--- php/WP_CLI/Dispatcher/RootCommand.php | 7 ++++++- php/WP_CLI/Dispatcher/Subcommand.php | 4 ++-- php/class-wp-cli.php | 5 ++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 42adc9635..4b4ad4e0b 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -11,12 +11,13 @@ class CompositeCommand { protected $parent, $subcommands = array(); - public function __construct( $parent, $name, $shortdesc, $synopsis = '' ) { + public function __construct( $parent, $name, $docparser ) { $this->parent = $parent; $this->name = $name; - $this->shortdesc = $shortdesc; - $this->synopsis = $synopsis; + + $this->shortdesc = $docparser->get_shortdesc(); + $this->synopsis = $docparser->get_synopsis(); } function get_parent() { diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 0f8654ef0..25ddc558a 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -10,7 +10,12 @@ class RootCommand extends CompositeCommand { function __construct() { - parent::__construct( false, 'wp', '' ); + $this->parent = false; + + $this->name = 'wp'; + + $this->shortdesc = ''; + $this->synopsis = ''; } function show_usage() { diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c86b096e6..7a71e282d 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -11,12 +11,12 @@ class Subcommand extends CompositeCommand { private $when_invoked; - function __construct( $parent, $name, $when_invoked, $docparser ) { + function __construct( $parent, $name, $docparser, $when_invoked ) { $this->when_invoked = $when_invoked; $this->alias = $docparser->get_tag( 'alias' ); - parent::__construct( $parent, $name, $docparser->get_shortdesc(), $docparser->get_synopsis() ); + parent::__construct( $parent, $name, $docparser ); } function get_alias() { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cb9a0a9e0..564965df2 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -75,14 +75,13 @@ private static function create_subcommand( $parent, $name, $class_name, $method call_user_func( array( new $class_name, $method_name ), $args, $assoc_args ); }; - return new Dispatcher\Subcommand( $parent, $name, $when_invoked, $docparser ); + return new Dispatcher\Subcommand( $parent, $name, $docparser, $when_invoked ); } private static function create_composite_command( $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection ); - $container = new Dispatcher\CompositeCommand( self::$root, $name, - $docparser->get_shortdesc() ); + $container = new Dispatcher\CompositeCommand( self::$root, $name, $docparser ); foreach ( $reflection->getMethods() as $method ) { if ( !self::_is_good_method( $method ) ) From eb48065e296adaabd2d57e2f38a7019d7d56e015 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 15:28:15 +0300 Subject: [PATCH 1809/5359] post get: update man page fixes #509 --- man-src/post-get.txt | 10 +++++----- man/post-get.1 | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/man-src/post-get.txt b/man-src/post-get.txt index fab4fdeb3..9b79b9ce9 100644 --- a/man-src/post-get.txt +++ b/man-src/post-get.txt @@ -4,12 +4,12 @@ The format to use when printing the post, acceptable values: - content: outputs only the post's content (default) + **content**: Outputs only the post's content. - table: output all fields of the post as a table, note that the - post_content field is omitted so that the table is readable + **table**: Outputs all fields of the post as a table. Note that the + post_content field is omitted so that the table is readable. - json: output all fields in JavaScript Object Notation format + **json**: Outputs all fields in JSON format. * `<id>`: @@ -17,6 +17,6 @@ ## EXAMPLES - wp post get 12 + wp post get 12 --format=content wp post get 12 > file.txt diff --git a/man/post-get.1 b/man/post-get.1 index 67511f013..94df8e63b 100644 --- a/man/post-get.1 +++ b/man/post-get.1 @@ -18,13 +18,13 @@ wp post get [\-\-format=\fIformat\fR] \fIid\fR The format to use when printing the post, acceptable values: . .IP -content: outputs only the post\'s content (default) +\fBcontent\fR: Outputs only the post\'s content\. . .IP -table: output all fields of the post as a table, note that the post_content field is omitted so that the table is readable +\fBtable\fR: Outputs all fields of the post as a table\. Note that the post_content field is omitted so that the table is readable\. . .IP -json: output all fields in JavaScript Object Notation format +\fBjson\fR: Outputs all fields in JSON format\. . .TP \fB<id>\fR: @@ -36,7 +36,7 @@ The ID of the post to get\. . .nf -wp post get 12 +wp post get 12 \-\-format=content wp post get 12 > file\.txt . From d44992ee47537085701cba12a2f9f1ff22bc1cb2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 19:08:59 +0300 Subject: [PATCH 1810/5359] mention `wp --info` in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2c49bc83d..3d4a0eb0a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ I'm running into troubles, what can I do? ----------------------------------------- To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). +If you're reporting a bug, please also post the output from `wp --info`. + Who's behind this thing? ------------------------ We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). From 32aa314db1037128b21e14368e5ebd53ef0735c6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 19:59:41 +0300 Subject: [PATCH 1811/5359] don't alter API response if the returned version happens to be the one we want see #511 --- php/WP_CLI/CommandWithUpgrade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index cf771d6f5..28bc23731 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -126,6 +126,9 @@ function install( $args, $assoc_args ) { * @param string $version The desired version of the package */ protected static function alter_api_response( $response, $version ) { + if ( $response->version == $version ) + return; + list( $link ) = explode( $response->slug, $response->download_link ); if ( false !== strpos( $response->download_link, 'theme' ) ) From 6ca5bae8d2879468021a5feea20f2bcc0e9fe2c8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Jun 2013 20:10:55 +0300 Subject: [PATCH 1812/5359] bump version to 0.10.1-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index b4c7d5221..7fa1276aa 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.0' ); +define( 'WP_CLI_VERSION', '0.10.1-alpha' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 89cc55159d94431c2c268d2b388c242fecbd1551 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Jun 2013 15:49:38 +0300 Subject: [PATCH 1813/5359] remove executable bit from mustache templates --- templates/post_type_extended.mustache | 0 templates/taxonomy_extended.mustache | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 templates/post_type_extended.mustache mode change 100755 => 100644 templates/taxonomy_extended.mustache diff --git a/templates/post_type_extended.mustache b/templates/post_type_extended.mustache old mode 100755 new mode 100644 diff --git a/templates/taxonomy_extended.mustache b/templates/taxonomy_extended.mustache old mode 100755 new mode 100644 From 42366d044de5b5cb9c164576d4473692ff46cd4e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Jun 2013 15:59:31 +0300 Subject: [PATCH 1814/5359] scaffold plugin-tests: create install-wp-tests.sh script This makes it easier to run unit tests locally. --- php/commands/scaffold.php | 8 +++++--- templates/.travis.yml | 20 +------------------- templates/install-wp-tests.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 22 deletions(-) create mode 100644 templates/install-wp-tests.sh diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 6b3b1bf05..ef0eb2b28 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -240,17 +240,19 @@ function plugin_tests( $args, $assoc_args ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - $tests_dir = "$plugin_dir/tests"; + $bin_dir = "$plugin_dir/bin"; $wp_filesystem->mkdir( $tests_dir ); + $wp_filesystem->mkdir( $bin_dir ); $this->create_file( "$tests_dir/bootstrap.php", Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ); $to_copy = array( - 'phpunit.xml' => $plugin_dir, + 'install-wp-tests.sh' => $bin_dir, '.travis.yml' => $plugin_dir, + 'phpunit.xml' => $plugin_dir, 'test-sample.php' => $tests_dir, ); @@ -258,7 +260,7 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->copy( WP_CLI_ROOT . "../templates/$file", "$dir/$file", true ); } - WP_CLI::success( "Created test files in $plugin_dir" ); + WP_CLI::success( "Created test files." ); } private function create_file( $filename, $contents ) { diff --git a/templates/.travis.yml b/templates/.travis.yml index a2020ad18..a91b121be 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -10,26 +10,8 @@ env: - WP_VERSION=3.5.1 WP_MULTISITE=0 - WP_VERSION=3.5.1 WP_MULTISITE=1 -before_install: - - git submodule update --init --recursive - before_script: - # set up WP install - - WP_CORE_DIR=/tmp/wordpress/ - - mkdir -p $WP_CORE_DIR - - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION - - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - # set up testing suite - export WP_TESTS_DIR=/tmp/wordpress-tests/ - - svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR - - cd $WP_TESTS_DIR - - cp wp-tests-config-sample.php wp-tests-config.php - - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php - - sed -i "s/yourdbnamehere/wordpress_test/" wp-tests-config.php - - sed -i "s/yourusernamehere/root/" wp-tests-config.php - - sed -i "s/yourpasswordhere//" wp-tests-config.php - - cd - - # set up database - - mysql -e 'CREATE DATABASE wordpress_test;' -uroot + - bash bin/install-wp-tests.sh wordpress_test root '' $WP_VERSION script: phpunit diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh new file mode 100644 index 000000000..a93a900d6 --- /dev/null +++ b/templates/install-wp-tests.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +if [ $# -lt 3 ]; then + echo "usage: $0 <db-name> <db-user> <db-pass> [wp-version]" + exit 1 +fi + +DB_NAME=$1 +DB_USER=$2 +DB_PASS=$3 +WP_VERSION=${4-master} + +set -ex + +# set up a WP install +WP_CORE_DIR=/tmp/wordpress/ +mkdir -p $WP_CORE_DIR +wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION +tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + +# set up testing suite +svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR + +cd $WP_TESTS_DIR +cp wp-tests-config-sample.php wp-tests-config.php +sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php +sed -i "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php +sed -i "s/yourusernamehere/$DB_USER/" wp-tests-config.php +sed -i "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php + +# create database +mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS" From 03f9539f83d50478b4eca0c245b5561821df9dcd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 04:12:11 +0300 Subject: [PATCH 1815/5359] move all config logic to a new class --- php/WP_CLI/Configurator.php | 100 ++++++++++++++++++++++++++ php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/WP_CLI/Runner.php | 70 ++---------------- php/class-wp-cli.php | 3 +- php/commands/_sys.php | 2 +- php/utils.php | 25 +++---- 6 files changed, 116 insertions(+), 86 deletions(-) create mode 100644 php/WP_CLI/Configurator.php diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php new file mode 100644 index 000000000..fc3c5caef --- /dev/null +++ b/php/WP_CLI/Configurator.php @@ -0,0 +1,100 @@ +<?php + +namespace WP_CLI; + +class Configurator { + + private $spec; + + function __construct( $path ) { + $this->spec = include $path; + + $defaults = array( + 'runtime' => false, + 'file' => false, + 'synopsis' => '', + 'default' => null, + ); + + foreach ( $this->spec as &$option ) { + $option = array_merge( $defaults, $option ); + } + } + + /** + * Get configuration specification, i.e. list of accepted keys. + * + * @return array + */ + function get_spec() { + return $this->spec; + } + + /** + * Set default value for a particular configuration key. + */ + function set_default( $key, $value ) { + $this->spec[ $key ]['default'] = $value; + } + + /** + * Load values from a YML file and sanitize them according to the spec. + * + * @return array + */ + function load_config( $path ) { + if ( $path ) + $config = spyc_load_file( $path ); + else + $config = array(); + + $sanitized_config = array(); + + foreach ( $this->spec as $key => $details ) { + if ( $details['file'] && isset( $config[ $key ] ) ) + $sanitized_config[ $key ] = $config[ $key ]; + else + $sanitized_config[ $key ] = $details['default']; + } + + // When invoking from a subdirectory in the project, + // make sure a config-relative 'path' is made absolute + if ( ! empty( $sanitized_config['path'] ) && ! \WP_CLI\Utils\is_absolute_path( $sanitized_config['path'] ) ) { + $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; + } + + return $sanitized_config; + } + + /** + * Extract values from an associative array, according to the spec. + */ + function split_special( &$assoc_args, &$config ) { + foreach ( $this->spec as $key => $details ) { + if ( true === $details['runtime'] ) { + self::handle_boolean_param( $assoc_args, $config, $key ); + } elseif ( false !== $details['runtime'] ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } + } + } + + private static function handle_boolean_param( &$assoc_args, &$config, $param ) { + $subkeys = array( + "$param" => true, + "no-$param" => false + ); + + foreach ( $subkeys as $key => $value ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $param ] = $value; + } + + unset( $assoc_args[ $key ] ); + } + } +} + diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 25ddc558a..ffebadb15 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -47,7 +47,7 @@ private static function generate_synopsis() { $lines = array(); - foreach ( \WP_CLI\Utils\get_config_spec() as $key => $details ) { + foreach ( \WP_CLI::$configurator->get_spec() as $key => $details ) { if ( false === $details['runtime'] ) continue; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 5332f7516..fd33cd0c8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -44,63 +44,11 @@ private static function get_config_path( &$assoc_args ) { return false; } - private static function load_config( $path, $spec ) { - if ( $path ) - $config = spyc_load_file( $path ); - else - $config = array(); - - $sanitized_config = array(); - - foreach ( $spec as $key => $details ) { - if ( $details['file'] && isset( $config[ $key ] ) ) - $sanitized_config[ $key ] = $config[ $key ]; - else - $sanitized_config[ $key ] = $details['default']; - } - - // When invoking from a subdirectory in the project, - // make sure a config-relative 'path' is made absolute - if ( ! empty( $sanitized_config['path'] ) && ! self::is_absolute_path( $sanitized_config['path'] ) ) { - $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; - } - - return $sanitized_config; - } - - private static function handle_boolean_param( &$assoc_args, &$config, $param ) { - $subkeys = array( - "$param" => true, - "no-$param" => false - ); - - foreach ( $subkeys as $key => $value ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $param ] = $value; - } - - unset( $assoc_args[ $key ] ); - } - } - - private static function split_special( &$assoc_args, &$config, $spec ) { - foreach ( $spec as $key => $details ) { - if ( true === $details['runtime'] ) { - self::handle_boolean_param( $assoc_args, $config, $key ); - } elseif ( false !== $details['runtime'] ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } - } - } - private static function set_wp_root( $config ) { $path = getcwd(); if ( !empty( $config['path'] ) ) { - if ( self::is_absolute_path( $config['path'] ) ) + if ( Utils\is_absolute_path( $config['path'] ) ) $path = $config['path']; else $path .= '/' . $config['path']; @@ -126,14 +74,6 @@ private static function set_user( $assoc_args ) { } } - private static function is_absolute_path( $path ) { - // Windows - if ( ':' === $path[1] ) - return true; - - return $path[0] === '/'; - } - private static function set_url( $assoc_args ) { if ( isset( $assoc_args['url'] ) ) { $url = $assoc_args['url']; @@ -291,19 +231,17 @@ public function before_wp_load() { list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ) ); - $config_spec = Utils\get_config_spec(); - // Set the path default to the ABSPATH $wp_abspath = dirname( Utils\find_file_upward( 'wp-load.php' ) ); if ( ! empty( $wp_abspath ) ) { - $config_spec['path']['default'] = $wp_abspath; + \WP_CLI::$configurator->set_default( 'path', $wp_abspath ); } $this->config_path = self::get_config_path( $this->assoc_args ); - $this->config = self::load_config( $this->config_path, $config_spec ); + $this->config = \WP_CLI::$configurator->load_config( $this->config_path ); - self::split_special( $this->assoc_args, $this->config, $config_spec ); + \WP_CLI::$configurator->split_special( $this->assoc_args, $this->config ); $this->init_logger(); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 564965df2..bdee64d14 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -8,8 +8,8 @@ */ class WP_CLI { + public static $configurator; public static $root; - public static $runner; private static $logger; @@ -25,6 +25,7 @@ static function init() { WP_CLI_ROOT . "../man-src" ); + self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/config-spec.php' ); self::$root = new Dispatcher\RootCommand; self::$runner = new WP_CLI\Runner; } diff --git a/php/commands/_sys.php b/php/commands/_sys.php index 963d48af6..82a7107aa 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -41,7 +41,7 @@ function info() { * @subcommand param-dump */ function param_dump() { - echo json_encode( Utils\get_config_spec() ); + echo json_encode( \WP_CLI::$configurator->get_spec() ); } /** diff --git a/php/utils.php b/php/utils.php index bd5cada51..e0cef0c1f 100644 --- a/php/utils.php +++ b/php/utils.php @@ -51,23 +51,6 @@ function load_all_commands() { } } -function get_config_spec() { - $spec = include __DIR__ . '/config-spec.php'; - - $defaults = array( - 'runtime' => false, - 'file' => false, - 'synopsis' => '', - 'default' => null, - ); - - foreach ( $spec as &$option ) { - $option = array_merge( $defaults, $option ); - } - - return $spec; -} - /** * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true * @param string|array The files (or file) to search for @@ -102,6 +85,14 @@ function find_file_upward( $files, $dir = null, $stop_check = null ) { return null; } +function is_absolute_path( $path ) { + // Windows + if ( ':' === $path[1] ) + return true; + + return $path[0] === '/'; +} + /** * Splits $argv into positional and associative arguments. * From 02fdfacec78e92c6613f59ba05f9f2a6b086b45d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 05:26:32 +0300 Subject: [PATCH 1816/5359] rename is_absolute_path() to is_path_absolute() it emphasises the assumption that the parameter is a path and not some random string --- php/WP_CLI/Configurator.php | 2 +- php/WP_CLI/Runner.php | 2 +- php/utils.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index fc3c5caef..a677d1f3e 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -59,7 +59,7 @@ function load_config( $path ) { // When invoking from a subdirectory in the project, // make sure a config-relative 'path' is made absolute - if ( ! empty( $sanitized_config['path'] ) && ! \WP_CLI\Utils\is_absolute_path( $sanitized_config['path'] ) ) { + if ( ! empty( $sanitized_config['path'] ) && ! \WP_CLI\Utils\is_path_absolute( $sanitized_config['path'] ) ) { $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index fd33cd0c8..5003f70a6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -48,7 +48,7 @@ private static function set_wp_root( $config ) { $path = getcwd(); if ( !empty( $config['path'] ) ) { - if ( Utils\is_absolute_path( $config['path'] ) ) + if ( Utils\is_path_absolute( $config['path'] ) ) $path = $config['path']; else $path .= '/' . $config['path']; diff --git a/php/utils.php b/php/utils.php index e0cef0c1f..240bce8e6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -85,7 +85,7 @@ function find_file_upward( $files, $dir = null, $stop_check = null ) { return null; } -function is_absolute_path( $path ) { +function is_path_absolute( $path ) { // Windows if ( ':' === $path[1] ) return true; From 4129614a80e647ebf0e431a699e69beb743c4a95 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 05:32:37 +0300 Subject: [PATCH 1817/5359] move parse_args() to Configurator and set WP path only if it's not explicitly set --- php/WP_CLI/Configurator.php | 22 +++++++++++++++++++--- php/WP_CLI/Runner.php | 12 +++++------- php/utils.php | 23 ----------------------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index a677d1f3e..a7078c5d9 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -31,10 +31,26 @@ function get_spec() { } /** - * Set default value for a particular configuration key. + * Splits a list of arguments into positional and associative. + * + * @param string + * @return array */ - function set_default( $key, $value ) { - $this->spec[ $key ]['default'] = $value; + function parse_args( $arguments ) { + $regular_args = array(); + $assoc_args = array(); + + foreach ( $arguments as $arg ) { + if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = true; + } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = $matches[2]; + } else { + $regular_args[] = $arg; + } + } + + return array( $regular_args, $assoc_args ); } /** diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 5003f70a6..93510c915 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -229,13 +229,7 @@ private function init_logger() { public function before_wp_load() { list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( - Utils\parse_args( array_slice( $GLOBALS['argv'], 1 ) ) ); - - // Set the path default to the ABSPATH - $wp_abspath = dirname( Utils\find_file_upward( 'wp-load.php' ) ); - if ( ! empty( $wp_abspath ) ) { - \WP_CLI::$configurator->set_default( 'path', $wp_abspath ); - } + \WP_CLI::$configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ) ); $this->config_path = self::get_config_path( $this->assoc_args ); @@ -243,6 +237,10 @@ public function before_wp_load() { \WP_CLI::$configurator->split_special( $this->assoc_args, $this->config ); + if ( !isset( $this->config['path'] ) ) { + $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); + } + $this->init_logger(); $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); diff --git a/php/utils.php b/php/utils.php index 240bce8e6..a5a2bad76 100644 --- a/php/utils.php +++ b/php/utils.php @@ -93,29 +93,6 @@ function is_path_absolute( $path ) { return $path[0] === '/'; } -/** - * Splits $argv into positional and associative arguments. - * - * @param string - * @return array - */ -function parse_args( $arguments ) { - $regular_args = array(); - $assoc_args = array(); - - foreach ( $arguments as $arg ) { - if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = true; - } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = $matches[2]; - } else { - $regular_args[] = $arg; - } - } - - return array( $regular_args, $assoc_args ); -} - /** * Composes positional arguments into a command string. * From 82b5d8520f3392e0a459d78589fb83b00731ec44 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 05:50:43 +0300 Subject: [PATCH 1818/5359] merge split_special() into parse_args() this gives us two clear variables to work with: $runtime_config and $local_config --- php/WP_CLI/Configurator.php | 63 ++++++++++++++++++------------------- php/WP_CLI/Runner.php | 33 +++++++++---------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index a7078c5d9..47e919f69 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -31,7 +31,7 @@ function get_spec() { } /** - * Splits a list of arguments into positional and associative. + * Splits a list of arguments into positional, associative and config. * * @param string * @return array @@ -50,7 +50,35 @@ function parse_args( $arguments ) { } } - return array( $regular_args, $assoc_args ); + $runtime_config = array(); + + foreach ( $this->spec as $key => $details ) { + if ( true === $details['runtime'] ) { + self::handle_boolean_param( $assoc_args, $runtime_config, $key ); + } elseif ( false !== $details['runtime'] ) { + if ( isset( $assoc_args[ $key ] ) ) { + $runtime_config[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } + } + + return array( $regular_args, $assoc_args, $runtime_config ); + } + + private static function handle_boolean_param( &$assoc_args, &$config, $param ) { + $subkeys = array( + "$param" => true, + "no-$param" => false + ); + + foreach ( $subkeys as $key => $value ) { + if ( isset( $assoc_args[ $key ] ) ) { + $config[ $param ] = $value; + } + + unset( $assoc_args[ $key ] ); + } } /** @@ -81,36 +109,5 @@ function load_config( $path ) { return $sanitized_config; } - - /** - * Extract values from an associative array, according to the spec. - */ - function split_special( &$assoc_args, &$config ) { - foreach ( $this->spec as $key => $details ) { - if ( true === $details['runtime'] ) { - self::handle_boolean_param( $assoc_args, $config, $key ); - } elseif ( false !== $details['runtime'] ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } - } - } - - private static function handle_boolean_param( &$assoc_args, &$config, $param ) { - $subkeys = array( - "$param" => true, - "no-$param" => false - ); - - foreach ( $subkeys as $key => $value ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $param ] = $value; - } - - unset( $assoc_args[ $key ] ); - } - } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 93510c915..c33edc729 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -16,27 +16,27 @@ public function __get( $key ) { return $this->$key; } - private static function get_config_path( &$assoc_args ) { - if ( isset( $assoc_args['config'] ) && file_exists( $assoc_args['config'] ) ) { - $path = $assoc_args['config']; - unset( $assoc_args['config'] ); - return $path; + private static function get_config_path( $runtime_config ) { + if ( isset( $runtime_config['config'] ) && file_exists( $runtime_config['config'] ) ) { + return $runtime_config['config']; } $config_files = array( 'wp-cli.local.yml', 'wp-cli.yml' ); - // Stop looking upward when we find we have emerged from a subdirectory install into a parent install - $stop_check = function ( $dir ) { + + // Stop looking upward when we find we have emerged from a subdirectory + // install into a parent install + $path = Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { static $wp_load_count = 0; $wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php'; if ( file_exists( $wp_load_path ) ) { $wp_load_count += 1; } return $wp_load_count > 1; - }; - $path = Utils\find_file_upward( $config_files, getcwd(), $stop_check ); + } ); + if ( $path ) { return $path; } @@ -154,9 +154,7 @@ public function get_wp_config_code() { } // Transparently convert old syntaxes - private static function back_compat_conversions( $r ) { - list( $args, $assoc_args ) = $r; - + private static function back_compat_conversions( $args, $assoc_args ) { // foo --help -> help foo if ( isset( $assoc_args['help'] ) ) { array_unshift( $args, 'help' ); @@ -228,14 +226,17 @@ private function init_logger() { } public function before_wp_load() { + list( $args, $assoc_args, $runtime_config ) = \WP_CLI::$configurator->parse_args( + array_slice( $GLOBALS['argv'], 1 ) ); + list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( - \WP_CLI::$configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ) ); + $args, $assoc_args ); - $this->config_path = self::get_config_path( $this->assoc_args ); + $this->config_path = self::get_config_path( $runtime_config ); - $this->config = \WP_CLI::$configurator->load_config( $this->config_path ); + $local_config = \WP_CLI::$configurator->load_config( $this->config_path ); - \WP_CLI::$configurator->split_special( $this->assoc_args, $this->config ); + $this->config = array_merge( $local_config, $runtime_config ); if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); From b56969e7d3755b1e651b327958fedc5bc59c7474 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 06:51:18 +0300 Subject: [PATCH 1819/5359] behat: add -run- to temporary directory names this makes it easy to delete them, without deleting wp-cli-test-download-cache --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 66b3bfb3e..eb699c29b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -110,7 +110,7 @@ private function _replace_var( $matches ) { public function create_empty_dir() { if ( !$this->install_dir ) { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-", TRUE ); + $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); mkdir( $this->install_dir ); } } From a1c78df3df41d6a01e6598b4e8e09a05c677c7ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 06:39:01 +0300 Subject: [PATCH 1820/5359] support passing --require multiple times --- features/flags.feature | 52 +++++++++++++++++++++++++++++-------- php/WP_CLI/Configurator.php | 49 +++++++++++++++++++--------------- php/WP_CLI/Runner.php | 23 +++++++++++++--- php/config-spec.php | 2 ++ 4 files changed, 91 insertions(+), 35 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 95a201a73..e99f95996 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -61,23 +61,53 @@ Feature: Global flags Scenario: Using --require Given a WP install And a custom-cmd.php file: - """ - <?php - class Test_Command extends WP_CLI_Command { + """ + <?php + class Test_Command extends WP_CLI_Command { - function req( $args, $assoc_args ) { - WP_CLI::line( $args[0] ); + function req( $args, $assoc_args ) { + WP_CLI::line( $args[0] ); + } } - } - WP_CLI::add_command( 'test', 'Test_Command' ); - """ + WP_CLI::add_command( 'test', 'Test_Command' ); + """ + + And a foo.php file: + """ + <?php echo basename(__FILE__) . "\n"; + """ + + And a bar.php file: + """ + <?php echo basename(__FILE__) . "\n"; + """ + + And a wp-cli.yml file: + """ + require: + - foo.php + - bar.php + """ + + And a wp-cli2.yml file: + """ + require: custom-cmd.php + """ When I run `wp --require=custom-cmd.php test req 'This is a custom command.'` Then STDOUT should be: - """ - This is a custom command. - """ + """ + foo.php + bar.php + This is a custom command. + """ + + When I run `wp --config=wp-cli2.yml test req 'This is a custom command.'` + Then STDOUT should contain: + """ + This is a custom command. + """ Scenario: Enabling/disabling color Given a WP install diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 47e919f69..fba6f7502 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -14,6 +14,7 @@ function __construct( $path ) { 'file' => false, 'synopsis' => '', 'default' => null, + 'multiple' => false, ); foreach ( $this->spec as &$option ) { @@ -37,28 +38,34 @@ function get_spec() { * @return array */ function parse_args( $arguments ) { - $regular_args = array(); - $assoc_args = array(); + $regular_args = $mixed_args = array(); foreach ( $arguments as $arg ) { if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = true; + $mixed_args[] = array( $matches[1], true ); } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = $matches[2]; + $mixed_args[] = array( $matches[1], $matches[2] ); } else { $regular_args[] = $arg; } } - $runtime_config = array(); + $assoc_args = $runtime_config = array(); - foreach ( $this->spec as $key => $details ) { - if ( true === $details['runtime'] ) { - self::handle_boolean_param( $assoc_args, $runtime_config, $key ); - } elseif ( false !== $details['runtime'] ) { - if ( isset( $assoc_args[ $key ] ) ) { - $runtime_config[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); + foreach ( $mixed_args as $tmp ) { + list( $key, $value ) = $tmp; + + $enabled = isset( $this->spec[ $key ] ) ? $this->spec[ $key ]['runtime'] : false; + + if ( false === $enabled ) { + $assoc_args[ $key ] = $value; + } elseif ( true === $enabled ) { + self::handle_boolean_param( $mixed_args, $runtime_config, $key ); + } else { + if ( $this->spec[ $key ]['multiple'] ) { + $runtime_config[ $key ][] = $value; + } else { + $runtime_config[ $key ] = $value; } } } @@ -95,16 +102,16 @@ function load_config( $path ) { $sanitized_config = array(); foreach ( $this->spec as $key => $details ) { - if ( $details['file'] && isset( $config[ $key ] ) ) - $sanitized_config[ $key ] = $config[ $key ]; - else - $sanitized_config[ $key ] = $details['default']; - } + if ( $details['file'] && isset( $config[ $key ] ) ) { + $value = $config[ $key ]; + if ( $details['multiple'] && !is_array( $value ) ) { + $value = array( $value ); + } + } else { + $value = $details['default']; + } - // When invoking from a subdirectory in the project, - // make sure a config-relative 'path' is made absolute - if ( ! empty( $sanitized_config['path'] ) && ! \WP_CLI\Utils\is_path_absolute( $sanitized_config['path'] ) ) { - $sanitized_config['path'] = dirname( $path ) . DIRECTORY_SEPARATOR . $sanitized_config['path']; + $sanitized_config[ $key ] = $value; } return $sanitized_config; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c33edc729..13def081c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -236,7 +236,21 @@ public function before_wp_load() { $local_config = \WP_CLI::$configurator->load_config( $this->config_path ); - $this->config = array_merge( $local_config, $runtime_config ); + // When invoking from a subdirectory in the project, + // make sure a config-relative 'path' is made absolute + if ( !empty( $local_config['path'] ) && !\WP_CLI\Utils\is_path_absolute( $local_config['path'] ) ) { + $local_config['path'] = dirname( $this->config_path ) . DIRECTORY_SEPARATOR . $local_config['path']; + } + + $this->config = $local_config; + + foreach ( $runtime_config as $key => $value ) { + if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { + $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); + } else { + $this->config[ $key ] = $value; + } + } if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); @@ -307,8 +321,11 @@ public function after_wp_load() { // Handle --user parameter self::set_user( $this->config ); - if ( isset( $this->config['require'] ) ) - require $this->config['require']; + if ( isset( $this->config['require'] ) ) { + foreach ( $this->config['require'] as $path ) { + require $path; + } + } // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { diff --git a/php/config-spec.php b/php/config-spec.php index 41332d9a3..a711db49b 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -33,6 +33,8 @@ 'runtime' => '=<path>', 'file' => '<path>', 'desc' => 'Load given PHP file before running the command', + 'multiple' => true, + 'default' => array(), ), 'disabled_commands' => array( From 034f1e634cbf47f3d458bd5346fb260e4ef562af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 18:09:28 +0300 Subject: [PATCH 1821/5359] fix boolean flag handling --- php/WP_CLI/Configurator.php | 21 +++------------------ php/WP_CLI/Runner.php | 5 +---- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index fba6f7502..70b72522b 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -41,7 +41,9 @@ function parse_args( $arguments ) { $regular_args = $mixed_args = array(); foreach ( $arguments as $arg ) { - if ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { + if ( preg_match( '|^--no-([^=]+)$|', $arg, $matches ) ) { + $mixed_args[] = array( $matches[1], false ); + } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { $mixed_args[] = array( $matches[1], true ); } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { $mixed_args[] = array( $matches[1], $matches[2] ); @@ -59,8 +61,6 @@ function parse_args( $arguments ) { if ( false === $enabled ) { $assoc_args[ $key ] = $value; - } elseif ( true === $enabled ) { - self::handle_boolean_param( $mixed_args, $runtime_config, $key ); } else { if ( $this->spec[ $key ]['multiple'] ) { $runtime_config[ $key ][] = $value; @@ -73,21 +73,6 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args, $runtime_config ); } - private static function handle_boolean_param( &$assoc_args, &$config, $param ) { - $subkeys = array( - "$param" => true, - "no-$param" => false - ); - - foreach ( $subkeys as $key => $value ) { - if ( isset( $assoc_args[ $key ] ) ) { - $config[ $param ] = $value; - } - - unset( $assoc_args[ $key ] ); - } - } - /** * Load values from a YML file and sanitize them according to the spec. * diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 13def081c..6e735b047 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -208,10 +208,7 @@ private static function back_compat_conversions( $args, $assoc_args ) { } private function init_logger() { - if ( isset( $this->assoc_args['no-color'] ) ) { - $color = false; - unset( $this->assoc_args['no-color'] ); - } elseif ( 'auto' === $this->config['color'] ) { + if ( 'auto' === $this->config['color'] ) { $color = ! \cli\Shell::isPiped(); } else { $color = $this->config['color']; From e91a480df19e806598cedaed5ff06df4f3dc974f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 18:41:55 +0300 Subject: [PATCH 1822/5359] mention that --require can be used more than once --- php/WP_CLI/Dispatcher/RootCommand.php | 4 ++-- php/config-spec.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index ffebadb15..c9e9abddc 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -25,7 +25,7 @@ function show_usage() { if ( '_sys' == $command->get_name() ) continue; - \WP_CLI::line( sprintf( " %s %s", + \WP_CLI::line( sprintf( ' %s %s', implode( ' ', get_path( $command ) ), implode( '|', array_keys( $command->get_subcommands() ) ) ) ); @@ -69,7 +69,7 @@ private static function generate_synopsis() { foreach ( $lines as $line ) { list( $synopsis, $desc ) = $line; - \WP_CLI::line( ' ' . str_pad( $synopsis, $max_len ) . ' ' . $desc ); + \WP_CLI::line( sprintf( ' %s %s', str_pad( $synopsis, $max_len ), $desc ) ); } } diff --git a/php/config-spec.php b/php/config-spec.php index a711db49b..61aaf46ba 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -32,7 +32,7 @@ 'require' => array( 'runtime' => '=<path>', 'file' => '<path>', - 'desc' => 'Load given PHP file before running the command', + 'desc' => 'Load PHP file before running the command (may be used more than once)', 'multiple' => true, 'default' => array(), ), From 5d9ce1fbd8668b8e04ded941aae83b893e056d51 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 23 May 2013 14:25:45 +0300 Subject: [PATCH 1823/5359] load path from --require before WP is loaded --- php/WP_CLI/Runner.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6e735b047..a8474e4b8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -255,6 +255,12 @@ public function before_wp_load() { $this->init_logger(); + if ( isset( $this->config['require'] ) ) { + foreach ( $this->config['require'] as $path ) { + require $path; + } + } + $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); if ( $this->cmd_starts_with( array( '_sys' ) ) ) { @@ -318,12 +324,6 @@ public function after_wp_load() { // Handle --user parameter self::set_user( $this->config ); - if ( isset( $this->config['require'] ) ) { - foreach ( $this->config['require'] as $path ) { - require $path; - } - } - // Handle --completions parameter if ( isset( $this->assoc_args['completions'] ) ) { foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { From 782a6b71f2382ebb29614bfb8f441bd8e0f3ff5a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 16:44:51 +0300 Subject: [PATCH 1824/5359] attempt to load built-in command early --- php/WP_CLI/Runner.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a8474e4b8..93613ad9a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -255,6 +255,9 @@ public function before_wp_load() { $this->init_logger(); + if ( !empty( $this->arguments ) ) + Utils\load_command( $this->arguments[0] ); + if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { require $path; From 10c987faf2b6b08edd32987b4334b82ad92af35e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 17:09:26 +0300 Subject: [PATCH 1825/5359] behat: test that --require works without a WP install --- features/flags.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index e99f95996..20a2e436f 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -58,6 +58,27 @@ Feature: Global flags Error: Could not get a user_id for this user: 'non-existing-user' """ + Scenario: Using a custom logger + Given an empty directory + And a custom-logger.php file: + """ + <?php + class Dummy_Logger { + + function __call( $method, $args ) { + echo "log: called '$method' method"; + } + } + + WP_CLI::set_logger( new Dummy_Logger ); + """ + + When I try `wp --require=custom-logger.php` + Then STDOUT should be: + """ + log: called 'error' method + """ + Scenario: Using --require Given a WP install And a custom-cmd.php file: From 56476488709e462e5c738ac6f1129f3ffa44bbd5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Jun 2013 19:41:48 +0300 Subject: [PATCH 1826/5359] update Composer dependencies make version requirements less strict --- composer.json | 6 +- composer.lock | 193 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 71 deletions(-) diff --git a/composer.json b/composer.json index 895c4e2f9..c9a8e7b55 100644 --- a/composer.json +++ b/composer.json @@ -10,14 +10,14 @@ "require": { "php": ">=5.3.2", "wp-cli/php-cli-tools": "dev-master", - "mustache/mustache": "2.3.x" + "mustache/mustache": "~2.3" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" }, "require-dev": { - "phpunit/phpunit": "3.7.x", - "behat/behat": "2.4.*@stable" + "phpunit/phpunit": "~3.7", + "behat/behat": "~2.4" }, "autoload": { "psr-0": { "WP_CLI": "php" } diff --git a/composer.lock b/composer.lock index 6e824d1cf..8764fbff5 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "9cb0bdfbcfa8b3b505b9241ca38f19f7", + "hash": "6cae44632851e1e1cee580631b2d784a", "packages": [ { "name": "mustache/mustache", @@ -96,28 +96,31 @@ "packages-dev": [ { "name": "behat/behat", - "version": "v2.4.5", + "version": "v2.4.6", "source": { "type": "git", - "url": "git://github.com/Behat/Behat.git", - "reference": "v2.4.5" + "url": "https://github.com/Behat/Behat.git", + "reference": "v2.4.6" }, "dist": { "type": "zip", - "url": "https://github.com/Behat/Behat/archive/v2.4.5.zip", - "reference": "v2.4.5", + "url": "https://api.github.com/repos/Behat/Behat/zipball/v2.4.6", + "reference": "v2.4.6", "shasum": "" }, "require": { - "behat/gherkin": ">=2.2.4,<2.3-dev", + "behat/gherkin": ">=2.2.9,<2.3", "php": ">=5.3.1", - "symfony/config": ">=2.0,<2.3-dev", - "symfony/console": ">=2.0,<2.3-dev", - "symfony/dependency-injection": ">=2.0,<2.3-dev", - "symfony/event-dispatcher": ">=2.0,<2.3-dev", - "symfony/finder": ">=2.0,<2.3-dev", - "symfony/translation": ">=2.0,<2.3-dev", - "symfony/yaml": ">=2.0,<2.3-dev" + "symfony/config": ">=2.0,<3.0", + "symfony/console": ">=2.0,<3.0", + "symfony/dependency-injection": ">=2.0,<3.0", + "symfony/event-dispatcher": ">=2.0,<3.0", + "symfony/finder": ">=2.0,<3.0", + "symfony/translation": ">=2.0,<3.0", + "symfony/yaml": ">=2.0,<3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7.19.0,<3.8" }, "suggest": { "behat/mink-extension": "for integration with Mink testing framework", @@ -156,7 +159,7 @@ "Behat", "Symfony2" ], - "time": "2013-01-27 14:45:41" + "time": "2013-06-06 10:46:48" }, { "name": "behat/gherkin", @@ -578,26 +581,27 @@ }, { "name": "symfony/config", - "version": "v2.2.2", + "version": "v2.3.1", "target-dir": "Symfony/Component/Config", "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "v2.2.2" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/Config/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/filesystem": ">=2.3,<3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -621,30 +625,36 @@ ], "description": "Symfony Config Component", "homepage": "http://symfony.com", - "time": "2013-05-10 18:08:31" + "time": "2013-06-03 00:18:25" }, { "name": "symfony/console", - "version": "v2.2.2", + "version": "v2.3.1", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "v2.2.2" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/Console/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/event-dispatcher": ">=2.1,<3.0" + }, + "suggest": { + "symfony/event-dispatcher": "" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -668,38 +678,39 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2013-05-27 14:47:40" + "time": "2013-06-11 07:15:14" }, { "name": "symfony/dependency-injection", - "version": "v2.2.2", + "version": "v2.3.1", "target-dir": "Symfony/Component/DependencyInjection", "source": { "type": "git", "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "v2.2.2" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "symfony/config": ">=2.2,<2.3-dev", + "symfony/config": ">=2.2,<3.0", "symfony/yaml": ">=2.0,<3.0" }, "suggest": { - "symfony/config": "2.2.*", - "symfony/yaml": "2.2.*" + "symfony/config": "", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -723,21 +734,21 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "http://symfony.com", - "time": "2013-05-06 08:37:50" + "time": "2013-06-05 09:51:05" }, { "name": "symfony/event-dispatcher", - "version": "v2.2.2", + "version": "v2.3.0", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.2.2" + "reference": "v2.3.0-RC1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1", + "reference": "v2.3.0-RC1", "shasum": "" }, "require": { @@ -747,13 +758,13 @@ "symfony/dependency-injection": ">=2.0,<3.0" }, "suggest": { - "symfony/dependency-injection": "2.2.*", - "symfony/http-kernel": "2.2.*" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -777,21 +788,68 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "http://symfony.com", - "time": "2013-02-11 11:26:43" + "time": "2013-05-13 14:36:40" + }, + { + "name": "symfony/filesystem", + "version": "v2.3.1", + "target-dir": "Symfony/Component/Filesystem", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "v2.3.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.1", + "reference": "v2.3.1", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "http://symfony.com", + "time": "2013-06-04 15:02:05" }, { "name": "symfony/finder", - "version": "v2.2.2", + "version": "v2.3.1", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "v2.2.2" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { @@ -800,7 +858,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -824,38 +882,38 @@ ], "description": "Symfony Finder Component", "homepage": "http://symfony.com", - "time": "2013-05-27 20:26:32" + "time": "2013-06-02 12:05:51" }, { "name": "symfony/translation", - "version": "v2.2.2", + "version": "v2.3.0", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "v2.2.2" + "reference": "v2.3.0-RC1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.0-RC1", + "reference": "v2.3.0-RC1", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "symfony/config": ">=2.0,<2.3-dev", + "symfony/config": ">=2.0,<3.0", "symfony/yaml": ">=2.2,<3.0" }, "suggest": { - "symfony/config": "2.2.*", - "symfony/yaml": "2.2.*" + "symfony/config": "", + "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -879,21 +937,21 @@ ], "description": "Symfony Translation Component", "homepage": "http://symfony.com", - "time": "2013-05-10 16:49:00" + "time": "2013-05-13 14:36:40" }, { "name": "symfony/yaml", - "version": "v2.2.2", + "version": "v2.3.0", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.2.2" + "reference": "v2.3.0-RC1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.2", - "reference": "v2.2.2", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.0-RC1", + "reference": "v2.3.0-RC1", "shasum": "" }, "require": { @@ -902,7 +960,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -926,7 +984,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2013-05-10 18:08:31" + "time": "2013-05-10 18:12:13" } ], "aliases": [ @@ -934,8 +992,7 @@ ], "minimum-stability": "stable", "stability-flags": { - "wp-cli/php-cli-tools": 20, - "behat/behat": 0 + "wp-cli/php-cli-tools": 20 }, "platform": { "php": ">=5.3.2" From c8d5e0d567db81fee1f6f89ef8429eb07ba292eb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 05:22:55 +0300 Subject: [PATCH 1827/5359] introduce WP_CLI::colorize() utility --- php/WP_CLI/Loggers/Quiet.php | 8 +------- php/WP_CLI/Loggers/Regular.php | 8 +------- php/WP_CLI/Runner.php | 17 ++++++++++++----- php/class-wp-cli.php | 4 ++++ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 06a404bb5..e2fd0c6b5 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -4,12 +4,6 @@ class Quiet { - private $colorize; - - function __construct( $colorize ) { - $this->colorize = $colorize; - } - function line( $message ) { // nothing } @@ -24,7 +18,7 @@ function warning( $message, $label ) { function error( $message, $label ) { $msg = '%R' . $label . ': %n' . $message; - fwrite( STDERR, \cli\Colors::colorize( $msg . "\n", $this->colorize ) ); + fwrite( STDERR, \WP_CLI::colorize( $msg . "\n" ) ); } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 65104db23..cb2809ffd 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -4,14 +4,8 @@ class Regular { - private $colorize; - - function __construct( $colorize ) { - $this->colorize = $colorize; - } - private function _line( $message, $handle = STDOUT ) { - fwrite( $handle, \cli\Colors::colorize( $message . "\n", $this->colorize ) ); + fwrite( $handle, \WP_CLI::colorize( $message . "\n" ) ); } function line( $message ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 93613ad9a..f1100d4d2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -207,17 +207,23 @@ private static function back_compat_conversions( $args, $assoc_args ) { return array( $args, $assoc_args ); } - private function init_logger() { + public function in_color() { + return $this->colorize; + } + + private function init_colorization() { if ( 'auto' === $this->config['color'] ) { - $color = ! \cli\Shell::isPiped(); + $this->colorize = !\cli\Shell::isPiped(); } else { - $color = $this->config['color']; + $this->colorize = $this->config['color']; } + } + private function init_logger() { if ( $this->config['quiet'] ) - $logger = new \WP_CLI\Loggers\Quiet( $color ); + $logger = new \WP_CLI\Loggers\Quiet; else - $logger = new \WP_CLI\Loggers\Regular( $color ); + $logger = new \WP_CLI\Loggers\Regular; WP_CLI::set_logger( $logger ); } @@ -253,6 +259,7 @@ public function before_wp_load() { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); } + $this->init_colorization(); $this->init_logger(); if ( !empty( $this->arguments ) ) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index bdee64d14..ea33cd04a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -39,6 +39,10 @@ static function set_logger( $logger ) { self::$logger = $logger; } + static function colorize( $string ) { + return \cli\Colors::colorize( $string, self::$runner->in_color() ); + } + /** * Add a command to the WP-CLI list of commands * From 71d81899acfa7d1ccce2674b9669b30250494f34 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 05:30:44 +0300 Subject: [PATCH 1828/5359] use Mustache templates to display plugin/theme details --- php/commands/plugin.php | 18 ++++++++---------- php/commands/theme.php | 12 +++++++----- templates/plugin-status.mustache | 6 ++++++ templates/theme-status.mustache | 5 +++++ 4 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 templates/plugin-status.mustache create mode 100644 templates/theme-status.mustache diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 4b860a081..1aee7a29c 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -47,16 +47,14 @@ protected function status_single( $args ) { if ( $this->has_update( $file ) ) $version .= ' (%gUpdate available%n)'; - $this->_status_single( $details, $name, $version, $status ); - } - - protected function _status_single( $details, $name, $version, $status ) { - WP_CLI::line( 'Plugin %9' . $name . '%n details:' ); - WP_CLI::line( ' Name: ' . $details[ 'Name' ] ); - WP_CLI::line( ' Status: ' . $status .'%n' ); - WP_CLI::line( ' Version: ' . $version ); - WP_CLI::line( ' Author: ' . $details[ 'Author' ] ); - WP_CLI::line( ' Description: ' . $details[ 'Description' ] ); + echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'plugin-status.mustache', array( + 'slug' => $name, + 'status' => $status, + 'version' => $version, + 'name' => $details['Name'], + 'author' => $details['Author'], + 'description' => $details['Description'] + ) ) ); } protected function get_all_items() { diff --git a/php/commands/theme.php b/php/commands/theme.php index 50245e714..0a9602b82 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -37,11 +37,13 @@ protected function status_single( $args ) { if ( $this->has_update( $theme->get_stylesheet() ) ) $version .= ' (%gUpdate available%n)'; - WP_CLI::line( 'Theme %9' . $theme->get_stylesheet() . '%n details:' ); - WP_CLI::line( ' Name: ' . $theme->get('Name') ); - WP_CLI::line( ' Status: ' . $status .'%n' ); - WP_CLI::line( ' Version: ' . $version ); - WP_CLI::line( ' Author: ' . $theme->get('Author') ); + echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'theme-status.mustache', array( + 'slug' => $theme->get_stylesheet(), + 'status' => $status, + 'version' => $version, + 'name' => $theme->get('Name'), + 'author' => $theme->get('Author'), + ) ) ); } protected function get_all_items() { diff --git a/templates/plugin-status.mustache b/templates/plugin-status.mustache new file mode 100644 index 000000000..375862690 --- /dev/null +++ b/templates/plugin-status.mustache @@ -0,0 +1,6 @@ +Plugin %9{{slug}}%n details: + Name: {{name}} + Status: {{status}}%n + Version: {{version}} + Author: {{author}} + Description: {{description}} diff --git a/templates/theme-status.mustache b/templates/theme-status.mustache new file mode 100644 index 000000000..c53be6338 --- /dev/null +++ b/templates/theme-status.mustache @@ -0,0 +1,5 @@ +Theme %9{{slug}}%n details: + Name: {{name}} + Status: {{status}}%n + Version: {{version}} + Author: {{author}} From 7066d87f7b383836f4c64f4adad9158a86570fad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 05:50:08 +0300 Subject: [PATCH 1829/5359] refresh `core version` output * remove manifest version (absent from recent WP releases) * remove redundant stability label for core versions * use Mustache template and replace tabs with spaces --- php/commands/core.php | 38 ++++++++++++------------------------- templates/versions.mustache | 3 +++ 2 files changed, 15 insertions(+), 26 deletions(-) create mode 100644 templates/versions.mustache diff --git a/php/commands/core.php b/php/commands/core.php index 3009dde8f..99c52fec1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -231,36 +231,22 @@ private static function get_clean_basedomain() { * @synopsis [--extra] */ public function version( $args = array(), $assoc_args = array() ) { - global $wp_version, $wp_db_version, $tinymce_version, $manifest_version; - - $color = '%G'; - $version_text = $wp_version; - $version_types = array( - '-RC' => array( 'release candidate', '%y' ), - '-beta' => array( 'beta', '%B' ), - '-' => array( 'in development', '%R' ), - ); - - foreach( $version_types as $needle => $type ) { - if ( stristr( $wp_version, $needle ) ) { - list( $version_text, $color ) = $type; - $version_text = "$color$wp_version%n (stability: $version_text)"; - break; - } - } + global $wp_version, $wp_db_version, $tinymce_version; if ( isset( $assoc_args['extra'] ) ) { - WP_CLI::line( "WordPress version:\t$version_text" ); - - WP_CLI::line( "Database revision:\t$wp_db_version" ); - preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); - $human_readable_tiny_mce = $match? $match[1] . '.' . $match[2] : ''; - WP_CLI::line( "TinyMCE version:\t" . ( $human_readable_tiny_mce? "$human_readable_tiny_mce ($tinymce_version)" : $tinymce_version ) ); - - WP_CLI::line( "Manifest revision:\t$manifest_version" ); + $human_readable_tiny_mce = $match ? $match[1] . '.' . $match[2] : ''; + + echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( + 'wp-version' => $wp_version, + 'db-version' => $wp_db_version, + 'mce-version' => ( $human_readable_tiny_mce ? + "$human_readable_tiny_mce ($tinymce_version)" + : $tinymce_version + ) + ) ); } else { - WP_CLI::line( $version_text ); + WP_CLI::line( $wp_version ); } } diff --git a/templates/versions.mustache b/templates/versions.mustache new file mode 100644 index 000000000..06c0e8ea9 --- /dev/null +++ b/templates/versions.mustache @@ -0,0 +1,3 @@ +WordPress version: {{wp-version}} +Database revision: {{db-version}} +TinyMCE version: {{mce-version}} From b9ae3fdb1f0eee329f019227df67a44af18e76a5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 06:03:02 +0300 Subject: [PATCH 1830/5359] use WP_CLI::colorize() in CommandWithUpgrade --- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/WP_CLI/Loggers/Regular.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index cf771d6f5..8f99841aa 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -54,7 +54,7 @@ private function status_all() { $line .= " " . $details['version']; } - \WP_CLI::line( $line ); + \WP_CLI::line( \WP_CLI::colorize( $line ) ); } \WP_CLI::line(); diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index cb2809ffd..08d0670df 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -9,7 +9,7 @@ private function _line( $message, $handle = STDOUT ) { } function line( $message ) { - $this->_line( $message ); + echo $message . "\n"; } function success( $message, $label ) { From 174ef01d9ec5e9ca6dd4546fbfec441e76a7ee78 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 06:13:35 +0300 Subject: [PATCH 1831/5359] move line() method from loggers back to the WP_CLI class --- php/WP_CLI/Loggers/Quiet.php | 7 +------ php/WP_CLI/Loggers/Regular.php | 9 ++------- php/class-wp-cli.php | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index e2fd0c6b5..14b929566 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -4,10 +4,6 @@ class Quiet { - function line( $message ) { - // nothing - } - function success( $message, $label ) { // nothing } @@ -17,8 +13,7 @@ function warning( $message, $label ) { } function error( $message, $label ) { - $msg = '%R' . $label . ': %n' . $message; - fwrite( STDERR, \WP_CLI::colorize( $msg . "\n" ) ); + fwrite( STDERR, \WP_CLI::colorize( "%R$label:%n $message\n" ) ); } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 08d0670df..6cd2db0ba 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -8,17 +8,12 @@ private function _line( $message, $handle = STDOUT ) { fwrite( $handle, \WP_CLI::colorize( $message . "\n" ) ); } - function line( $message ) { - echo $message . "\n"; - } - function success( $message, $label ) { - $this->line( '%G' . $label . ': %n' . $message ); + $this->_line( "%G$label:%n $message" ); } function warning( $message, $label ) { - $msg = '%C' . $label . ': %n' . $message; - $this->_line( $msg, STDERR ); + $this->_line( "%C$label:%n $message", STDERR ); } function error( $message, $label ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ea33cd04a..cfcf3ac4a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -131,7 +131,7 @@ static function get_man_dirs() { * @param string $message */ static function line( $message = '' ) { - self::$logger->line( $message ); + echo $message . "\n"; } /** From 14a0d4f83a121e7ea0fef62802f275a4aa1f09ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Jun 2013 06:30:37 +0300 Subject: [PATCH 1832/5359] behat: partially delete quiet run test output from WP_CLI::line() is no longer suppressed, since we can't be sure it's not the essential output (think `wp core version`) --- features/flags.feature | 6 ------ 1 file changed, 6 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 20a2e436f..dc73efbf4 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -3,12 +3,6 @@ Feature: Global flags Scenario: Quiet run Given a WP install - When I run `wp` - Then STDOUT should not be empty - - When I run `wp --quiet` - Then STDOUT should be empty - When I try `wp non-existing-command --quiet` Then the return code should be 1 And STDERR should be: From 37829cb231523dd2aefb3d9ce5bb512afa594226 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Jun 2013 21:55:02 +0300 Subject: [PATCH 1833/5359] add URL redirect warning --- php/utils-wp.php | 10 ++++++++++ php/wp-settings-cli.php | 2 ++ 2 files changed, 12 insertions(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index 5d42c52c8..4a307e753 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -45,6 +45,16 @@ function wp_die_handler( $message ) { \WP_CLI::error( $message ); } +function wp_redirect_handler( $url ) { + \WP_CLI::warning( 'Some code is trying to do a URL redirect. Backtrace:' ); + + ob_start(); + debug_print_backtrace(); + fwrite( STDERR, ob_get_clean() ); + + return $url; +} + function maybe_require( $since, $path ) { global $wp_version; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 12321c11a..f892f57eb 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -56,7 +56,9 @@ require( ABSPATH . WPINC . '/plugin.php' ); require( ABSPATH . WPINC . '/pomo/mo.php' ); +// WP_CLI: Early hooks Utils\replace_wp_die_handler(); +add_filter( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From 4ccd65904c363cc4b67ca15aa07e8ec7e5d0578e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Jun 2013 21:55:02 +0300 Subject: [PATCH 1834/5359] add URL redirect warning (for 0.10.1 branch) see #521 --- php/utils-wp.php | 10 ++++++++++ php/wp-settings-cli.php | 2 ++ 2 files changed, 12 insertions(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index 5d42c52c8..4a307e753 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -45,6 +45,16 @@ function wp_die_handler( $message ) { \WP_CLI::error( $message ); } +function wp_redirect_handler( $url ) { + \WP_CLI::warning( 'Some code is trying to do a URL redirect. Backtrace:' ); + + ob_start(); + debug_print_backtrace(); + fwrite( STDERR, ob_get_clean() ); + + return $url; +} + function maybe_require( $since, $path ) { global $wp_version; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 12321c11a..f892f57eb 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -56,7 +56,9 @@ require( ABSPATH . WPINC . '/plugin.php' ); require( ABSPATH . WPINC . '/pomo/mo.php' ); +// WP_CLI: Early hooks Utils\replace_wp_die_handler(); +add_filter( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From 65a2dabc95193c5026f3dd8707fff4eb21846400 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 11:46:01 +0300 Subject: [PATCH 1835/5359] set version to 0.10.1 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 7fa1276aa..c54a7a4ac 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.10.1-alpha' ); +define( 'WP_CLI_VERSION', '0.10.1' ); include WP_CLI_ROOT . 'utils.php'; include WP_CLI_ROOT . 'dispatcher.php'; From 973a5ec67bb088ac56c06b75b8c39ff89ab13e4d Mon Sep 17 00:00:00 2001 From: Tomasz Ratajczak <tomasz.ratajczak@espeo.pl> Date: Fri, 7 Jun 2013 16:26:54 +0200 Subject: [PATCH 1836/5359] add site meta commands --- php/commands/site-meta.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 php/commands/site-meta.php diff --git a/php/commands/site-meta.php b/php/commands/site-meta.php new file mode 100644 index 000000000..3642167de --- /dev/null +++ b/php/commands/site-meta.php @@ -0,0 +1,13 @@ +<?php + +/** + * Manage site custom fields. + * + * @package wp-cli + */ +class Site_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'site'; +} + +WP_CLI::add_command( 'site-meta', 'Site_Meta_Command' ); + From 6ae19150fe3263b5b19e1237c58b92f73d9eab15 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 May 2013 17:35:38 +0300 Subject: [PATCH 1837/5359] introduce 'before_invoke:{cmd}' hook and use it for site-meta command --- features/site-meta.feature | 17 +++++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 2 ++ php/class-wp-cli.php | 26 +++++++++++++++++++++++++- php/commands/site-meta.php | 6 ++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 features/site-meta.feature diff --git a/features/site-meta.feature b/features/site-meta.feature new file mode 100644 index 000000000..8b1fa2035 --- /dev/null +++ b/features/site-meta.feature @@ -0,0 +1,17 @@ +Feature: Manage WordPress installation + + Scenario: Non-multisite + Given a WP install + + When I try `wp site-meta` + Then STDOUT should contain: + """ + usage: wp site-meta + """ + + When I try `wp site-meta get 1 site_admins` + Then STDOUT should be empty + And STDERR should contain: + """ + This is not a multisite install. + """ diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 7a71e282d..5ce7058c8 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -60,6 +60,8 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { $this->validate_args( $args, $assoc_args ); + \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); + call_user_func( $this->when_invoked, $args, $assoc_args ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cfcf3ac4a..4bccc2101 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -14,6 +14,8 @@ class WP_CLI { private static $logger; + private static $hooks = array(), $hooks_passed = array(); + private static $man_dirs = array(); /** @@ -44,7 +46,29 @@ static function colorize( $string ) { } /** - * Add a command to the WP-CLI list of commands + * Schedule a callback to be executed at a certain point (before WP is loaded). + */ + static function add_hook( $when, $callback ) { + if ( in_array( $when, self::$hooks_passed ) ) + call_user_func( $callback ); + + self::$hooks[ $when ][] = $callback; + } + + /** + * Execute registered callbacks. + */ + static function do_hook( $when ) { + self::$hooks_passed[] = $when; + + if ( !isset( self::$hooks[ $when ] ) ) + return; + + array_map( 'call_user_func', self::$hooks[ $when ] ); + } + + /** + * Add a command to the wp-cli list of commands * * @param string $name The name of the command that will be used in the cli * @param string $class The command implementation diff --git a/php/commands/site-meta.php b/php/commands/site-meta.php index 3642167de..9ca5c61bb 100644 --- a/php/commands/site-meta.php +++ b/php/commands/site-meta.php @@ -11,3 +11,9 @@ class Site_Meta_Command extends \WP_CLI\CommandWithMeta { WP_CLI::add_command( 'site-meta', 'Site_Meta_Command' ); +WP_CLI::add_hook( 'before_invoke:site-meta', function () { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } +} ); + From 567f7f57efac5a0abd45934c2b6e7f8a1590e007 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 12:52:41 +0300 Subject: [PATCH 1838/5359] add man page for site-meta [ci skip] --- man-src/site-meta.txt | 14 ++++++++ man/site-meta.1 | 69 ++++++++++++++++++++++++++++++++++++++ php/commands/site-meta.php | 2 +- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 man-src/site-meta.txt create mode 100644 man/site-meta.1 diff --git a/man-src/site-meta.txt b/man-src/site-meta.txt new file mode 100644 index 000000000..e921abce7 --- /dev/null +++ b/man-src/site-meta.txt @@ -0,0 +1,14 @@ +## OPTIONS + +* `<id>`: + + The network id (usually 1). + +* `--format=json`: + + Encode/decode values as JSON. + +## EXAMPLES + + # get a list of super-admins + wp site-meta get 1 site_admins diff --git a/man/site-meta.1 b/man/site-meta.1 new file mode 100644 index 000000000..eaa72b0de --- /dev/null +++ b/man/site-meta.1 @@ -0,0 +1,69 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "WP\-SITE\-META" "1" "" "WP-CLI" +. +.SH "NAME" +\fBwp\-site\-meta\fR \- Manage network custom fields\. +. +.SH "SYNOPSIS" +wp site\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +. +.P +wp site\-meta delete \fIid\fR \fIkey\fR +. +.P +wp site\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] +. +.P +wp site\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +. +.SH "SUBCOMMANDS" +. +.TP +\fBadd\fR: +. +.IP +Add a meta field\. +. +.TP +\fBdelete\fR: +. +.IP +Delete a meta field\. +. +.TP +\fBget\fR: +. +.IP +Get meta field value\. +. +.TP +\fBupdate\fR: +. +.IP +Update a meta field\. +. +.SH "OPTIONS" +. +.TP +\fB<id>\fR: +. +.IP +The network id (usually 1)\. +. +.TP +\fB\-\-format=json\fR: +. +.IP +Encode/decode values as JSON\. +. +.SH "EXAMPLES" +. +.nf + +# get a list of super\-admins +wp site\-meta get 1 site_admins +. +.fi + diff --git a/php/commands/site-meta.php b/php/commands/site-meta.php index 9ca5c61bb..b31ba358b 100644 --- a/php/commands/site-meta.php +++ b/php/commands/site-meta.php @@ -1,7 +1,7 @@ <?php /** - * Manage site custom fields. + * Manage network custom fields. * * @package wp-cli */ From b672bc767c8439790910957a67bfdb95f6921437 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 13:02:50 +0300 Subject: [PATCH 1839/5359] rename `wp site-meta` to `wp network-meta` --- features/{site-meta.feature => network-meta.feature} | 8 ++++---- man-src/{site-meta.txt => network-meta.txt} | 0 man/{site-meta.1 => network-meta.1} | 12 ++++++------ php/commands/{site-meta.php => network-meta.php} | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) rename features/{site-meta.feature => network-meta.feature} (59%) rename man-src/{site-meta.txt => network-meta.txt} (100%) rename man/{site-meta.1 => network-meta.1} (61%) rename php/commands/{site-meta.php => network-meta.php} (51%) diff --git a/features/site-meta.feature b/features/network-meta.feature similarity index 59% rename from features/site-meta.feature rename to features/network-meta.feature index 8b1fa2035..dd6bf9c88 100644 --- a/features/site-meta.feature +++ b/features/network-meta.feature @@ -1,15 +1,15 @@ -Feature: Manage WordPress installation +Feature: Manage network-wide custom fields. Scenario: Non-multisite Given a WP install - When I try `wp site-meta` + When I try `wp network-meta` Then STDOUT should contain: """ - usage: wp site-meta + usage: wp network-meta """ - When I try `wp site-meta get 1 site_admins` + When I try `wp network-meta get 1 site_admins` Then STDOUT should be empty And STDERR should contain: """ diff --git a/man-src/site-meta.txt b/man-src/network-meta.txt similarity index 100% rename from man-src/site-meta.txt rename to man-src/network-meta.txt diff --git a/man/site-meta.1 b/man/network-meta.1 similarity index 61% rename from man/site-meta.1 rename to man/network-meta.1 index eaa72b0de..fad87547d 100644 --- a/man/site-meta.1 +++ b/man/network-meta.1 @@ -1,22 +1,22 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-SITE\-META" "1" "" "WP-CLI" +.TH "WP\-NETWORK\-META" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-site\-meta\fR \- Manage network custom fields\. +\fBwp\-network\-meta\fR \- Manage network custom fields\. . .SH "SYNOPSIS" -wp site\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +wp network\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .P -wp site\-meta delete \fIid\fR \fIkey\fR +wp network\-meta delete \fIid\fR \fIkey\fR . .P -wp site\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] +wp network\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] . .P -wp site\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +wp network\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .SH "SUBCOMMANDS" . diff --git a/php/commands/site-meta.php b/php/commands/network-meta.php similarity index 51% rename from php/commands/site-meta.php rename to php/commands/network-meta.php index b31ba358b..1d39a6e0c 100644 --- a/php/commands/site-meta.php +++ b/php/commands/network-meta.php @@ -5,13 +5,13 @@ * * @package wp-cli */ -class Site_Meta_Command extends \WP_CLI\CommandWithMeta { +class Network_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'site'; } -WP_CLI::add_command( 'site-meta', 'Site_Meta_Command' ); +WP_CLI::add_command( 'network-meta', 'Network_Meta_Command' ); -WP_CLI::add_hook( 'before_invoke:site-meta', function () { +WP_CLI::add_hook( 'before_invoke:network-meta', function () { if ( !is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } From 9fc38aa32737987e59e0eca1757ab0ab3d7c798a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 13:11:14 +0300 Subject: [PATCH 1840/5359] rename `wp blog` to `wp site` --- features/search-replace.feature | 2 +- features/{blog.feature => site.feature} | 29 +++++++------------- man-src/{blog-create.txt => site-create.txt} | 0 man-src/{blog-delete.txt => site-delete.txt} | 0 man-src/{blog-empty.txt => site-empty.txt} | 0 man/{blog-create.1 => site-create.1} | 6 ++-- man/{blog-delete.1 => site-delete.1} | 6 ++-- man/{blog-empty.1 => site-empty.1} | 6 ++-- php/commands/{blog.php => site.php} | 24 ++++++++-------- 9 files changed, 32 insertions(+), 41 deletions(-) rename features/{blog.feature => site.feature} (58%) rename man-src/{blog-create.txt => site-create.txt} (100%) rename man-src/{blog-delete.txt => site-delete.txt} (100%) rename man-src/{blog-empty.txt => site-empty.txt} (100%) rename man/{blog-create.1 => site-create.1} (84%) rename man/{blog-delete.1 => site-delete.1} (77%) rename man/{blog-empty.1 => site-empty.1} (56%) rename php/commands/{blog.php => site.php} (93%) diff --git a/features/search-replace.feature b/features/search-replace.feature index 07fa919f1..2031ceb14 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -17,7 +17,7 @@ Feature: Do global search/replace Scenario: Multisite search/replace Given a WP multisite install - And I run `wp blog create --slug="foo" --title="foo" --email="foo@example.com"` + And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` And I run `wp search-replace foo bar --network` Then STDOUT should be a table containing rows: | Table | Column | Replacements | diff --git a/features/blog.feature b/features/site.feature similarity index 58% rename from features/blog.feature rename to features/site.feature index 14712c444..80a6c94ff 100644 --- a/features/blog.feature +++ b/features/site.feature @@ -1,40 +1,31 @@ -Feature: Manage a WordPress installation +Feature: Manage sites in a multisite installation - Scenario: Install multisite - Given a WP install - - When I run `wp core install-network` - Then STDOUT should not be empty - - When I try the previous command again - Then the return code should be 1 - - Scenario: Delete a blog by id + Scenario: Delete a site by id Given a WP multisite install - When I run `wp blog create --slug=first --porcelain` + When I run `wp site create --slug=first --porcelain` Then STDOUT should match '%d' - And save STDOUT as {BLOG_ID} + And save STDOUT as {SITE_ID} - When I run `wp blog delete {BLOG_ID} --yes` + When I run `wp site delete {SITE_ID} --yes` Then STDOUT should not be empty When I try the previous command again Then the return code should be 1 - Scenario: Delete a blog by slug + Scenario: Delete a site by slug Given a WP multisite install - When I run `wp blog create --slug=first` + When I run `wp site create --slug=first` Then STDOUT should not be empty - When I run `wp blog delete --slug=first --yes` + When I run `wp site delete --slug=first --yes` Then STDOUT should not be empty When I try the previous command again Then the return code should be 1 - Scenario: Empty a blog + Scenario: Empty a site Given a WP install When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` @@ -43,7 +34,7 @@ Feature: Manage a WordPress installation When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` Then STDOUT should not be empty - When I run `wp blog empty --yes` + When I run `wp site empty --yes` Then STDOUT should not be empty When I run `wp post list --format=ids` diff --git a/man-src/blog-create.txt b/man-src/site-create.txt similarity index 100% rename from man-src/blog-create.txt rename to man-src/site-create.txt diff --git a/man-src/blog-delete.txt b/man-src/site-delete.txt similarity index 100% rename from man-src/blog-delete.txt rename to man-src/site-delete.txt diff --git a/man-src/blog-empty.txt b/man-src/site-empty.txt similarity index 100% rename from man-src/blog-empty.txt rename to man-src/site-empty.txt diff --git a/man/blog-create.1 b/man/site-create.1 similarity index 84% rename from man/blog-create.1 rename to man/site-create.1 index 022c1c88a..a30664396 100644 --- a/man/blog-create.1 +++ b/man/site-create.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-CREATE" "1" "" "WP-CLI" +.TH "WP\-SITE\-CREATE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-blog\-create\fR \- Create a blog in a multisite install\. +\fBwp\-site\-create\fR \- Create a site in a multisite install\. . .SH "SYNOPSIS" -wp blog create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] [\-\-porcelain] +wp site create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] [\-\-porcelain] . .SH "OPTIONS" . diff --git a/man/blog-delete.1 b/man/site-delete.1 similarity index 77% rename from man/blog-delete.1 rename to man/site-delete.1 index d90ec3e16..d8f7f3bc3 100644 --- a/man/blog-delete.1 +++ b/man/site-delete.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-DELETE" "1" "" "WP-CLI" +.TH "WP\-SITE\-DELETE" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-blog\-delete\fR \- Delete a blog in a multisite install\. +\fBwp\-site\-delete\fR \- Delete a site in a multisite install\. . .SH "SYNOPSIS" -wp blog delete [\fIblog\-id\fR] [\-\-slug=\fIslug\fR] [\-\-yes] [\-\-keep\-tables] +wp site delete [\fIsite\-id\fR] [\-\-slug=\fIslug\fR] [\-\-yes] [\-\-keep\-tables] . .SH "OPTIONS" . diff --git a/man/blog-empty.1 b/man/site-empty.1 similarity index 56% rename from man/blog-empty.1 rename to man/site-empty.1 index 34cf749fc..144391fba 100644 --- a/man/blog-empty.1 +++ b/man/site-empty.1 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WP\-BLOG\-EMPTY" "1" "" "WP-CLI" +.TH "WP\-SITE\-EMPTY" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-blog\-empty\fR \- Empty a blog of its content\. +\fBwp\-site\-empty\fR \- Empty a site of its content\. . .SH "SYNOPSIS" -wp blog empty [\-\-yes] +wp site empty [\-\-yes] . .SH "EXAMPLES" . diff --git a/php/commands/blog.php b/php/commands/site.php similarity index 93% rename from php/commands/blog.php rename to php/commands/site.php index dfc91e1db..fbe438c01 100644 --- a/php/commands/blog.php +++ b/php/commands/site.php @@ -5,7 +5,7 @@ * * @package wp-cli */ -class Blog_Command extends WP_CLI_Command { +class Site_Command extends WP_CLI_Command { /** * Delete comments. @@ -108,27 +108,27 @@ private function _insert_default_terms() { } /** - * Empty a blog of its content. + * Empty a site of its content. * * @subcommand empty * @synopsis [--yes] */ public function _empty( $args, $assoc_args ) { - WP_CLI::confirm( 'Are you sure you want to empty the blog at ' . site_url() . '?', $assoc_args ); + WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . '?', $assoc_args ); $this->_empty_posts(); $this->_empty_comments(); $this->_empty_taxonomies(); $this->_insert_default_terms(); - WP_CLI::success( 'The blog at ' . site_url() . ' was emptied.' ); + WP_CLI::success( 'The site at ' . site_url() . ' was emptied.' ); } /** - * Delete a blog in a multisite install. + * Delete a site in a multisite install. * - * @synopsis [<blog-id>] [--slug=<slug>] [--yes] [--keep-tables] + * @synopsis [<site-id>] [--slug=<slug>] [--yes] [--keep-tables] */ function delete( $args, $assoc_args ) { if ( !is_multisite() ) { @@ -148,14 +148,14 @@ function delete( $args, $assoc_args ) { } if ( !$blog ) { - WP_CLI::error( "Blog not found." ); + WP_CLI::error( "Site not found." ); } - WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl blog?", $assoc_args ); + WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl site?", $assoc_args ); wpmu_delete_blog( $blog->blog_id, !isset( $assoc_args['keep-tables'] ) ); - WP_CLI::success( "The blog at $blog->siteurl was deleted." ); + WP_CLI::success( "The site at $blog->siteurl was deleted." ); } /** @@ -177,7 +177,7 @@ private function _get_site( $site_id ) { } /** - * Create a blog in a multisite install. + * Create a site in a multisite install. * * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] [--porcelain] */ @@ -276,9 +276,9 @@ public function create( $_, $assoc_args ) { if ( isset( $assoc_args['porcelain'] ) ) WP_CLI::line( $id ); else - WP_CLI::success( "Blog $id created: $url" ); + WP_CLI::success( "Site $id created: $url" ); } } -WP_CLI::add_command( 'blog', 'Blog_Command' ); +WP_CLI::add_command( 'site', 'Site_Command' ); From 8791bbef53fc83d05cf4e0038824939f1cdf3087 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 13:28:49 +0300 Subject: [PATCH 1841/5359] alias `wp blog` to `wp site` --- php/WP_CLI/Runner.php | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index f1100d4d2..76eef2062 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -155,15 +155,17 @@ public function get_wp_config_code() { // Transparently convert old syntaxes private static function back_compat_conversions( $args, $assoc_args ) { - // foo --help -> help foo - if ( isset( $assoc_args['help'] ) ) { - array_unshift( $args, 'help' ); - unset( $assoc_args['help'] ); - } - - // sql -> db - if ( count( $args ) > 0 && 'sql' == $args[0] ) { - $args[0] = 'db'; + $top_level_aliases = array( + 'sql' => 'db', + 'blog' => 'site' + ); + if ( count( $args ) > 0 ) { + foreach ( $top_level_aliases as $old => $new ) { + if ( $old == $args[0] ) { + $args[0] = $new; + break; + } + } } // {plugin|theme} update --all -> {plugin|theme} update-all @@ -179,6 +181,12 @@ private static function back_compat_conversions( $args, $assoc_args ) { list( $args[0], $args[1] ) = array( $args[1], $args[0] ); } + // foo --help -> help foo + if ( isset( $assoc_args['help'] ) ) { + array_unshift( $args, 'help' ); + unset( $assoc_args['help'] ); + } + // {post|user} list --ids -> {post|user} list --format=ids if ( count( $args ) > 1 && in_array( $args[0], array( 'post', 'user' ) ) && $args[1] == 'list' From 8a631204a88c6dfe2b88b9b62641fa78d622e4f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 13:47:15 +0300 Subject: [PATCH 1842/5359] behat: fix help --gen test --- features/help.feature | 4 ++-- man/option.1 | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/help.feature b/features/help.feature index b23b898da..5b8b421fe 100644 --- a/features/help.feature +++ b/features/help.feature @@ -43,10 +43,10 @@ Feature: Get help about WP-CLI commands @ronn Scenario: Generating help for multisite-only subcommands Given an empty directory - When I run `wp help --gen blog create` + When I run `wp help --gen site create` Then STDOUT should be: """ - generated blog-create.1 + generated site-create.1 """ @ronn diff --git a/man/option.1 b/man/option.1 index 904b88a2a..69a8fb23b 100644 --- a/man/option.1 +++ b/man/option.1 @@ -7,16 +7,16 @@ \fBwp\-option\fR \- Manage WordPress options\. . .SH "SYNOPSIS" -wp option get \fIkey\fR [\-\-format=\fIformat\fR] +wp option add \fIkey\fR [\-\-format=\fIformat\fR] . .P -wp option add \fIkey\fR [\-\-format=\fIformat\fR] +wp option delete \fIkey\fR . .P -wp option update \fIkey\fR [\-\-format=\fIformat\fR] +wp option get \fIkey\fR [\-\-format=\fIformat\fR] . .P -wp option delete \fIkey\fR +wp option update \fIkey\fR [\-\-format=\fIformat\fR] . .SH "SUBCOMMANDS" . From 093e6aeb6a864a9744519059d0a9511c540fa529 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 14:11:43 +0300 Subject: [PATCH 1843/5359] site create: rename --site_id= to --network_id= --- man-src/site-create.txt | 12 ++++++------ man/site-create.1 | 14 +++++++------- php/commands/site.php | 9 +++++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/man-src/site-create.txt b/man-src/site-create.txt index 1c7e6aea5..84c3df985 100644 --- a/man-src/site-create.txt +++ b/man-src/site-create.txt @@ -2,24 +2,24 @@ * `--slug`=<slug>: - Path for the new blog. Subdomain on subdomain installs, directory on subdirectory installs. + Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. * `--title`=<title>: - Title of the new blog. Default: prettified slug. + Title of the new site. Default: prettified slug. * `--email`=<email>: Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. -* `--site_id`=<site-id>: +* `--network_id`=<network-id>: - Site (network) to associate new blog with. Defaults to current site (typically 1). + Network to associate new site with. Defaults to current network (typically 1). * `--private`: - If set, the new blog will be non-public (not indexed) + If set, the new site will be non-public (not indexed) * `--porcelain`: - If set, only the blog id will be output on success. + If set, only the site id will be output on success. diff --git a/man/site-create.1 b/man/site-create.1 index a30664396..20675a3e6 100644 --- a/man/site-create.1 +++ b/man/site-create.1 @@ -7,7 +7,7 @@ \fBwp\-site\-create\fR \- Create a site in a multisite install\. . .SH "SYNOPSIS" -wp site create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-site_id=\fIsite\-id\fR] [\-\-private] [\-\-porcelain] +wp site create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-network_id=\fInetwork\-id\fR] [\-\-private] [\-\-porcelain] . .SH "OPTIONS" . @@ -15,13 +15,13 @@ wp site create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\f \fB\-\-slug\fR=\fIslug\fR: . .IP -Path for the new blog\. Subdomain on subdomain installs, directory on subdirectory installs\. +Path for the new site\. Subdomain on subdomain installs, directory on subdirectory installs\. . .TP \fB\-\-title\fR=<title>: . .IP -Title of the new blog\. Default: prettified slug\. +Title of the new site\. Default: prettified slug\. . .TP \fB\-\-email\fR=\fIemail\fR: @@ -30,20 +30,20 @@ Title of the new blog\. Default: prettified slug\. Email for Admin user\. User will be created if none exists\. Assignement to Super Admin if not included\. . .TP -\fB\-\-site_id\fR=\fIsite\-id\fR: +\fB\-\-network_id\fR=\fInetwork\-id\fR: . .IP -Site (network) to associate new blog with\. Defaults to current site (typically 1)\. +Network to associate new site with\. Defaults to current network (typically 1)\. . .TP \fB\-\-private\fR: . .IP -If set, the new blog will be non\-public (not indexed) +If set, the new site will be non\-public (not indexed) . .TP \fB\-\-porcelain\fR: . .IP -If set, only the blog id will be output on success\. +If set, only the site id will be output on success\. diff --git a/php/commands/site.php b/php/commands/site.php index fbe438c01..5f548284c 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -179,7 +179,7 @@ private function _get_site( $site_id ) { /** * Create a site in a multisite install. * - * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--site_id=<site-id>] [--private] [--porcelain] + * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--network_id=<network-id>] [--private] [--porcelain] */ public function create( $_, $assoc_args ) { if ( !is_multisite() ) { @@ -192,11 +192,12 @@ public function create( $_, $assoc_args ) { $title = isset( $assoc_args['title'] ) ? $assoc_args['title'] : ucfirst( $base ); $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; + // Site - if ( !empty( $assoc_args['site_id'] ) ) { - $site = $this->_get_site( $assoc_args['site_id'] ); + if ( !empty( $assoc_args['network_id'] ) ) { + $site = $this->_get_site( $assoc_args['network_id'] ); if ( $site === false ) { - WP_CLI::error( 'Site with id '.$assoc_args['site_id'].' does not exist' ); + WP_CLI::error( sprintf( 'Network with id %d does not exist.', $assoc_args['network_id'] ) ); } } else { From 639d9d97f488d85598e216d7b882a9e7b8e11560 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 14:24:06 +0300 Subject: [PATCH 1844/5359] site create: alias --site_id= to --network_id= --- php/WP_CLI/Runner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 76eef2062..b72f47706 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -168,6 +168,12 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } + // site --site_id= -> site --network_id= + if ( count( $args ) > 0 && 'site' == $args[0] && isset( $assoc_args['site_id'] ) ) { + $assoc_args['network_id'] = $assoc_args['site_id']; + unset( $assoc_args['site_id'] ); + } + // {plugin|theme} update --all -> {plugin|theme} update-all if ( count( $args ) > 1 && in_array( $args[0], array( 'plugin', 'theme' ) ) && $args[1] == 'update' && isset( $assoc_args['all'] ) From fd3bdfd4ee23c866779aa4f4a4cd24851acc97b0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 8 Jun 2013 15:19:13 -0700 Subject: [PATCH 1845/5359] A basic test for converting an install to multisite. --- features/core.feature | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/features/core.feature b/features/core.feature index 29478558d..0390c7db0 100644 --- a/features/core.feature +++ b/features/core.feature @@ -100,6 +100,24 @@ Feature: Manage WordPress installation """ When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` + Then STDOUT should be: + """ + true + """ + + Scenario: Convert install to multisite + Given a WP install + + When I run `wp eval 'var_export( is_multisite() );'` + Then STDOUT should be: + """ + false + """ + + When I run `wp core install-network --title='test network'` + Then STDOUT should not be empty + + When I run `wp eval 'var_export( is_multisite() );'` Then STDOUT should be: """ true From 757b9eea6d395c482bc4eb772f7a6654a0aec296 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Jun 2013 18:36:15 +0300 Subject: [PATCH 1846/5359] behat: try running the install-network command again --- features/core.feature | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/core.feature b/features/core.feature index 0390c7db0..592ba4915 100644 --- a/features/core.feature +++ b/features/core.feature @@ -123,6 +123,9 @@ Feature: Manage WordPress installation true """ + When I try `wp core install-network --title='test network'` + Then the return code should be 1 + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory From 421766b557eda056f7d243f47ba6df7308d5524f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 18:26:09 +0300 Subject: [PATCH 1847/5359] rename _hook() to _action() --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/class-wp-cli.php | 4 ++-- php/commands/network-meta.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 5ce7058c8..55d27f925 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -60,7 +60,7 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { $this->validate_args( $args, $assoc_args ); - \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); + \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); call_user_func( $this->when_invoked, $args, $assoc_args ); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4bccc2101..8c73a401b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -48,7 +48,7 @@ static function colorize( $string ) { /** * Schedule a callback to be executed at a certain point (before WP is loaded). */ - static function add_hook( $when, $callback ) { + static function add_action( $when, $callback ) { if ( in_array( $when, self::$hooks_passed ) ) call_user_func( $callback ); @@ -58,7 +58,7 @@ static function add_hook( $when, $callback ) { /** * Execute registered callbacks. */ - static function do_hook( $when ) { + static function do_action( $when ) { self::$hooks_passed[] = $when; if ( !isset( self::$hooks[ $when ] ) ) diff --git a/php/commands/network-meta.php b/php/commands/network-meta.php index 1d39a6e0c..88b43759a 100644 --- a/php/commands/network-meta.php +++ b/php/commands/network-meta.php @@ -11,7 +11,7 @@ class Network_Meta_Command extends \WP_CLI\CommandWithMeta { WP_CLI::add_command( 'network-meta', 'Network_Meta_Command' ); -WP_CLI::add_hook( 'before_invoke:network-meta', function () { +WP_CLI::add_action( 'before_invoke:network-meta', function () { if ( !is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } From 6c73830c0b21a35ae3c154484338a27bdda8c4e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 15 Jun 2013 18:50:14 +0300 Subject: [PATCH 1848/5359] help: move duplicated function_exists() check to __invoke() --- php/commands/help.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index d2b8691e3..b85f07023 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -15,6 +15,11 @@ function __invoke( $args, $assoc_args ) { $this->generate( $args ); else $this->show( $args ); + + // WordPress is already loaded, so there's no chance we'll find the command + if ( function_exists( 'add_filter' ) ) { + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + } } private static function find_subcommand( $args ) { @@ -38,11 +43,6 @@ private function show( $args ) { $command->show_usage(); exit; } - - // WordPress is already loaded, so there's no chance we'll find the command - if ( function_exists( 'add_filter' ) ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); - } } private function generate( $args ) { @@ -50,8 +50,6 @@ private function generate( $args ) { WP_CLI::error( '`ronn` executable not found.' ); } - $arg_copy = $args; - $command = self::find_subcommand( $args ); if ( $command ) { @@ -60,11 +58,6 @@ private function generate( $args ) { } exit; } - - // WordPress is already loaded, so there's no chance we'll find the command - if ( function_exists( 'add_filter' ) ) { - WP_CLI::error( sprintf( "'%s' command not found.", implode( ' ', $arg_copy ) ) ); - } } private static function maybe_show_manpage( $args ) { From 4bfb75fd8adb864b2a329fff024987b98631e3dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 19:54:42 +0300 Subject: [PATCH 1849/5359] introduce WP_CLI::log() WP_CLI::line() is for spitting something to STDOUT. WP_CLI::log() is for sending a message to the logger, which could do various things with it. closes #465 --- php/WP_CLI/Loggers/Quiet.php | 4 ++++ php/WP_CLI/Loggers/Regular.php | 4 ++++ php/class-wp-cli.php | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 14b929566..926986c5e 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -4,6 +4,10 @@ class Quiet { + function info( $message ) { + // nothing + } + function success( $message, $label ) { // nothing } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 6cd2db0ba..b33a7f84b 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -8,6 +8,10 @@ private function _line( $message, $handle = STDOUT ) { fwrite( $handle, \WP_CLI::colorize( $message . "\n" ) ); } + function info( $message ) { + fwrite( STDOUT, $message . "\n" ); + } + function success( $message, $label ) { $this->_line( "%G$label:%n $message" ); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 8c73a401b..e78de8c14 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -158,6 +158,15 @@ static function line( $message = '' ) { echo $message . "\n"; } + /** + * Log an informational message. + * + * @param string $message + */ + static function log( $message ) { + self::$logger->info( $message ); + } + /** * Display a success in the CLI and end with a newline * From 52943dfa68d7661505fbe9207f6b83ca9bb8ad4e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 20:22:00 +0300 Subject: [PATCH 1850/5359] convert from WP_CLI::line() to WP_CLI::log() where appropriate --- php/WP_CLI/CommandWithUpgrade.php | 4 ++-- php/commands/core.php | 10 +++++----- php/commands/help.php | 2 +- php/commands/media.php | 6 +++--- php/commands/plugin.php | 4 ++-- php/commands/theme.php | 6 +++--- php/commands/user.php | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 52c261cd4..c8da9c3a4 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -37,7 +37,7 @@ private function status_all() { $n = count( $items ); // Not interested in the translation, just the number logic - \WP_CLI::line( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); + \WP_CLI::log( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); $padding = $this->get_padding($items); @@ -108,7 +108,7 @@ function install( $args, $assoc_args ) { $slug = $file_upgrader->result['destination_name']; if ( isset( $assoc_args['activate'] ) ) { - \WP_CLI::line( "Activating '$slug'..." ); + \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } } else { diff --git a/php/commands/core.php b/php/commands/core.php index 99c52fec1..125e3db2e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -19,21 +19,21 @@ public function download( $args, $assoc_args ) { WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( !is_dir( ABSPATH ) ) { - WP_CLI::line( sprintf( 'Creating directory %s', ABSPATH ) ); + WP_CLI::log( sprintf( 'Creating directory %s', ABSPATH ) ); WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); } if ( isset( $assoc_args['locale'] ) ) { $offer = $this->get_download_offer( $assoc_args['locale'] ); $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); - WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $offer['current'], $offer['locale'] ) ); } elseif ( isset( $assoc_args['version'] ) ) { $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; - WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $download_url = 'https://wordpress.org/latest.tar.gz'; - WP_CLI::line( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); + WP_CLI::log( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; @@ -279,7 +279,7 @@ function update( $args, $assoc_args ) { if ( empty( $args[0] ) ) { $new_package = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; - WP_CLI::line( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $new_package = $args[0]; $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; diff --git a/php/commands/help.php b/php/commands/help.php index b85f07023..ef8b24bef 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -171,7 +171,7 @@ private static function call_ronn( $markdown, $dest ) { $roff = str_replace( ' "January 2012"', '', $roff ); file_put_contents( $dest, $roff ); - \WP_CLI::line( "generated " . basename( $dest ) ); + \WP_CLI::log( "generated " . basename( $dest ) ); } private static function get_file_name( $args ) { diff --git a/php/commands/media.php b/php/commands/media.php index 64e954018..b35db1ef8 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -39,7 +39,7 @@ function regenerate( $args, $assoc_args = array() ) { } $count = $images->post_count; - WP_CLI::line( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); + WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); $not_found = array_diff( $args, $images->posts ); if( !empty($not_found) ) { @@ -162,7 +162,7 @@ private function _process_regeneration( $id ) { return; } - WP_CLI::line( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); + WP_CLI::log( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); $this->remove_old_images( $image->ID ); @@ -198,7 +198,7 @@ private function remove_old_images( $att_id ) { continue; if ( unlink( $intermediate_path ) ) { - WP_CLI::line( sprintf( "Thumbnail %s x %s was deleted.", + WP_CLI::log( sprintf( "Thumbnail %s x %s was deleted.", $size_info['width'], $size_info['height'] ) ); } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1aee7a29c..c96d85465 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -161,7 +161,7 @@ protected function install_from_repo( $slug, $assoc_args ) { $status = install_plugin_install_status( $api ); - WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); switch ( $status['status'] ) { case 'update_available': @@ -170,7 +170,7 @@ protected function install_from_repo( $slug, $assoc_args ) { $result = $upgrader->install( $api->download_link ); if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::line( "Activating '$slug'..." ); + WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 0a9602b82..c2047cd99 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -115,7 +115,7 @@ protected function install_from_repo( $slug, $assoc_args ) { // Check to see if we should update, rather than install. if ( $this->has_update( $slug ) ) { - WP_CLI::line( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); + WP_CLI::log( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $slug ); /** @@ -123,7 +123,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * or it's newer than what we've got. */ } else if ( !wp_get_theme( $slug )->exists() ) { - WP_CLI::line( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); } else { WP_CLI::error( 'Theme already installed and up to date.' ); @@ -131,7 +131,7 @@ protected function install_from_repo( $slug, $assoc_args ) { // Finally, activate theme if requested. if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::line( "Activating '$slug'..." ); + WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } } diff --git a/php/commands/user.php b/php/commands/user.php index 23b68f373..4c1a85795 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -324,7 +324,7 @@ public function import_csv( $args, $assoc_args ) { if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); - WP_CLI::line( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); + WP_CLI::log( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); } // Create the user From 614da25404ce45a77e12c4d8897239fc25c69556 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 20:28:29 +0300 Subject: [PATCH 1851/5359] remove redundant arg check in Theme_Command::parse_name() it's already handled by the synopsis parser --- php/commands/theme.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index c2047cd99..681d273be 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -217,11 +217,6 @@ function _list( $_, $assoc_args ) { } protected function parse_name( $args ) { - if ( empty( $args ) ) { - WP_CLI::line( "usage: wp theme $subcommand <theme-name>" ); - exit; - } - $name = $args[0]; $theme = wp_get_theme( $name ); From 21fb2961e224f56a83689e674a0a96ca24d01c7c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 17 Jun 2013 03:17:02 +0300 Subject: [PATCH 1852/5359] move command instance creation to a separate class Keep the disabled_commands logic inside the WP_CLI class; show an explicit error, instead of pretending the command doesn't exist. --- features/config.feature | 13 ++++ php/WP_CLI/Dispatcher/CommandFactory.php | 64 +++++++++++++++++++ php/class-wp-cli.php | 80 +++++------------------- 3 files changed, 92 insertions(+), 65 deletions(-) create mode 100644 php/WP_CLI/Dispatcher/CommandFactory.php diff --git a/features/config.feature b/features/config.feature index 339319c95..83813588b 100644 --- a/features/config.feature +++ b/features/config.feature @@ -59,3 +59,16 @@ Feature: Have a config file wp-cli.yml """ + Scenario: Disabled subcommands + Given a WP install + And a wp-cli.yml file: + """ + disabled_commands: + - db drop + """ + + When I try `wp db drop --yes` + Then STDERR should contain: + """ + command has been disabled + """ diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php new file mode 100644 index 000000000..72eb104f3 --- /dev/null +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -0,0 +1,64 @@ +<?php + +namespace WP_CLI\Dispatcher; + +/** + * Creates CompositeCommand or Subcommand instances. + */ +class CommandFactory { + + public static function create( $name, $class, $parent ) { + $reflection = new \ReflectionClass( $class ); + + if ( $reflection->hasMethod( '__invoke' ) ) { + $command = self::create_subcommand( $parent, $name, $reflection->name, + $reflection->getMethod( '__invoke' ) ); + } else { + $command = self::create_composite_command( $parent, $name, $reflection ); + } + + return $command; + } + + private static function create_subcommand( $parent, $name, $class_name, $method ) { + $docparser = new \WP_CLI\DocParser( $method ); + + if ( !$name ) + $name = $docparser->get_tag( 'subcommand' ); + + if ( !$name ) + $name = $method->name; + + $method_name = $method->name; + + $when_invoked = function ( $args, $assoc_args ) use ( $class_name, $method_name ) { + call_user_func( array( new $class_name, $method_name ), $args, $assoc_args ); + }; + + return new Subcommand( $parent, $name, $docparser, $when_invoked ); + } + + private static function create_composite_command( $parent, $name, $reflection ) { + $docparser = new \WP_CLI\DocParser( $reflection ); + + $container = new CompositeCommand( $parent, $name, $docparser ); + + foreach ( $reflection->getMethods() as $method ) { + if ( !self::is_good_method( $method ) ) + continue; + + $subcommand = self::create_subcommand( $container, false, $reflection->name, $method ); + + $subcommand_name = $subcommand->get_name(); + + $container->add_subcommand( $subcommand_name, $subcommand ); + } + + return $container; + } + + private static function is_good_method( $method ) { + return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); + } +} + diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e78de8c14..47d5db6bf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -74,73 +74,11 @@ static function do_action( $when ) { * @param string $class The command implementation */ static function add_command( $name, $class ) { - if ( in_array( $name, self::get_config('disabled_commands') ) ) - return; - - $reflection = new \ReflectionClass( $class ); - - if ( $reflection->hasMethod( '__invoke' ) ) { - $command = self::create_subcommand( self::$root, $name, $reflection->name, - $reflection->getMethod( '__invoke' ) ); - } else { - $command = self::create_composite_command( $name, $reflection ); - } + $command = Dispatcher\CommandFactory::create( $name, $class, self::$root ); self::$root->add_subcommand( $name, $command ); } - private static function create_subcommand( $parent, $name, $class_name, $method ) { - $docparser = new \WP_CLI\DocParser( $method ); - - if ( !$name ) - $name = $docparser->get_tag( 'subcommand' ); - - if ( !$name ) - $name = $method->name; - - $method_name = $method->name; - - $when_invoked = function ( $args, $assoc_args ) use ( $class_name, $method_name ) { - call_user_func( array( new $class_name, $method_name ), $args, $assoc_args ); - }; - - return new Dispatcher\Subcommand( $parent, $name, $docparser, $when_invoked ); - } - - private static function create_composite_command( $name, $reflection ) { - $docparser = new \WP_CLI\DocParser( $reflection ); - - $container = new Dispatcher\CompositeCommand( self::$root, $name, $docparser ); - - foreach ( $reflection->getMethods() as $method ) { - if ( !self::_is_good_method( $method ) ) - continue; - - $subcommand = self::create_subcommand( $container, false, $reflection->name, $method ); - - $subcommand_name = $subcommand->get_name(); - $full_name = self::get_full_name( $subcommand ); - - if ( in_array( $full_name, self::get_config('disabled_commands') ) ) - continue; - - $container->add_subcommand( $subcommand_name, $subcommand ); - } - - return $container; - } - - private static function get_full_name( $command ) { - $path = Dispatcher\get_path( $command ); - array_shift( $path ); - - return implode( ' ', $path ); - } - - private static function _is_good_method( $method ) { - return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); - } - static function add_man_dir( $dest_dir, $src_dir ) { self::$man_dirs[ $dest_dir ] = $src_dir; } @@ -304,14 +242,26 @@ private static function find_command_to_run( $args ) { $cmd_path = array(); + $disabled_commands = self::get_config('disabled_commands'); + while ( !empty( $args ) && $command->has_subcommands() ) { $cmd_path[] = $args[0]; + $full_name = implode( ' ', $cmd_path ); $subcommand = $command->find_subcommand( $args ); if ( !$subcommand ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", - implode( ' ', $cmd_path ) ) ); + \WP_CLI::error( sprintf( + "'%s' is not a registered wp command. See 'wp help'.", + $full_name + ) ); + } + + if ( in_array( $full_name, $disabled_commands ) ) { + \WP_CLI::error( sprintf( + "The '%s' command has been disabled from the config file.", + $full_name + ) ); } $command = $subcommand; From 3f9c545e40367ee7d5afb3a86ff4171547b1fb37 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 17 Jun 2013 04:37:53 +0300 Subject: [PATCH 1853/5359] move setting $_SERVER['DOCUMENT_ROOT'] to set_wp_root() method It was first defined in 390e7dbbabee7398527c3a1552e849f5c87053aa and then sort of drifted away from where paths are handled. --- php/WP_CLI/Runner.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b72f47706..596176f24 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -55,6 +55,8 @@ private static function set_wp_root( $config ) { } define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); + + $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); } private static function set_user( $assoc_args ) { @@ -285,8 +287,6 @@ public function before_wp_load() { } } - $_SERVER['DOCUMENT_ROOT'] = realpath( $this->config['path'] ); - if ( $this->cmd_starts_with( array( '_sys' ) ) ) { $this->_run_command(); exit; From a88bf1c8ea6100d6c02f23f9d1769747455b7ce0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 17 Jun 2013 04:21:58 +0300 Subject: [PATCH 1854/5359] implement '@when' docblock tag Works on both commands and subcommands. --- php/WP_CLI/Dispatcher/CompositeCommand.php | 5 ++++ php/WP_CLI/DocParser.php | 2 +- php/WP_CLI/Runner.php | 32 ++++++++++++++++------ php/commands/_sys.php | 3 ++ php/commands/core.php | 2 ++ 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 4b4ad4e0b..14179199c 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -18,6 +18,11 @@ public function __construct( $parent, $name, $docparser ) { $this->shortdesc = $docparser->get_shortdesc(); $this->synopsis = $docparser->get_synopsis(); + + $when_to_invoke = $docparser->get_tag( 'when' ); + if ( $when_to_invoke ) { + \WP_CLI::$runner->register_early_invoke( $when_to_invoke, $this ); + } } function get_parent() { diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index cb891d19d..4d597a631 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -18,7 +18,7 @@ function get_shortdesc() { } function get_tag( $name ) { - if ( preg_match( '/@' . $name . '\s+([a-z-]+)/', $this->docComment, $matches ) ) + if ( preg_match( '/@' . $name . '\s+([a-z-_]+)/', $this->docComment, $matches ) ) return $matches[1]; return false; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 596176f24..f4dc78b2f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -12,10 +12,32 @@ class Runner { private $arguments, $assoc_args; + private $_early_invoke = array(); + public function __get( $key ) { + if ( '_' === $key[0] ) + return null; + return $this->$key; } + public function register_early_invoke( $when, $command ) { + $this->_early_invoke[ $when ][] = $command; + } + + private function do_early_invoke( $when ) { + if ( !isset( $this->_early_invoke[ $when ] ) ) + return; + + foreach ( $this->_early_invoke[ $when ] as $command ) { + $path = array_slice( Dispatcher\get_path( $command ), 1 ); + if ( $this->cmd_starts_with( $path ) ) { + $this->_run_command(); + exit; + } + } + } + private static function get_config_path( $runtime_config ) { if ( isset( $runtime_config['config'] ) && file_exists( $runtime_config['config'] ) ) { return $runtime_config['config']; @@ -287,11 +309,6 @@ public function before_wp_load() { } } - if ( $this->cmd_starts_with( array( '_sys' ) ) ) { - $this->_run_command(); - exit; - } - // First try at showing man page if ( $this->cmd_starts_with( array( 'help' ) ) ) { $this->_run_command(); @@ -303,10 +320,7 @@ public function before_wp_load() { // Handle --url and --blog parameters self::set_url( $this->config ); - if ( array( 'core', 'download' ) == $this->arguments ) { - $this->_run_command(); - exit; - } + $this->do_early_invoke( 'before_wp_load' ); if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { WP_CLI::error( diff --git a/php/commands/_sys.php b/php/commands/_sys.php index 82a7107aa..fefbc2231 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -3,6 +3,9 @@ use \WP_CLI\Dispatcher, \WP_CLI\Utils; +/** + * @when before_wp_load + */ class Sys_Command extends WP_CLI_Command { private function command_to_array( $command ) { diff --git a/php/commands/core.php b/php/commands/core.php index 125e3db2e..6feb6bc5c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -13,6 +13,8 @@ class Core_Command extends WP_CLI_Command { * Download core WordPress files. * * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] [--force] + * + * @when before_wp_load */ public function download( $args, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && is_readable( ABSPATH . 'wp-load.php' ) ) From 73374561c1e09750690a2e22f771cfd7f6badd8b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 17 Jun 2013 05:04:38 +0300 Subject: [PATCH 1855/5359] calculate path for early commands only once --- php/WP_CLI/Runner.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index f4dc78b2f..d48455865 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -22,15 +22,14 @@ public function __get( $key ) { } public function register_early_invoke( $when, $command ) { - $this->_early_invoke[ $when ][] = $command; + $this->_early_invoke[ $when ][] = array_slice( Dispatcher\get_path( $command ), 1 ); } private function do_early_invoke( $when ) { if ( !isset( $this->_early_invoke[ $when ] ) ) return; - foreach ( $this->_early_invoke[ $when ] as $command ) { - $path = array_slice( Dispatcher\get_path( $command ), 1 ); + foreach ( $this->_early_invoke[ $when ] as $path ) { if ( $this->cmd_starts_with( $path ) ) { $this->_run_command(); exit; From 16fd5dd8a739eba58a54b6ac8d13ea24b64a44de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 18 Jun 2013 01:28:56 +0300 Subject: [PATCH 1856/5359] fix network-meta man page. see #529 --- man-src/network-meta.txt | 2 +- man/network-meta.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/network-meta.txt b/man-src/network-meta.txt index e921abce7..c1899f2d4 100644 --- a/man-src/network-meta.txt +++ b/man-src/network-meta.txt @@ -11,4 +11,4 @@ ## EXAMPLES # get a list of super-admins - wp site-meta get 1 site_admins + wp network-meta get 1 site_admins diff --git a/man/network-meta.1 b/man/network-meta.1 index fad87547d..0beb7eb4a 100644 --- a/man/network-meta.1 +++ b/man/network-meta.1 @@ -63,7 +63,7 @@ Encode/decode values as JSON\. .nf # get a list of super\-admins -wp site\-meta get 1 site_admins +wp network\-meta get 1 site_admins . .fi From 56bc7ce75e335ac63fb1da484cccd6a35a4e8189 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 19 Jun 2013 20:47:33 +0300 Subject: [PATCH 1857/5359] show error on invalid json. closes #531 --- php/class-wp-cli.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 47d5db6bf..3cb5133c4 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -159,9 +159,14 @@ static function confirm( $question, $assoc_args ) { * @param mixed $value * @param array $assoc_args */ - static function read_value( $value, $assoc_args = array() ) { + static function read_value( $raw_value, $assoc_args = array() ) { if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { - $value = json_decode( $value, true ); + $value = json_decode( $raw_value, true ); + if ( null === $value ) { + WP_CLI::error( sprintf( 'Invalid JSON: %s', $raw_value ) ); + } + } else { + $value = $raw_value; } return $value; From 6f3b77c7938044fc491d318608e17ad431fc3056 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 04:27:56 +0300 Subject: [PATCH 1858/5359] add optional 'before_invoke' parameter to WP_CLI::add_command() this avoids repeating the command name and makes it clearer when the callback is fired --- php/class-wp-cli.php | 8 +++++++- php/commands/network-meta.php | 12 ++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3cb5133c4..bac6d3468 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -72,10 +72,16 @@ static function do_action( $when ) { * * @param string $name The name of the command that will be used in the cli * @param string $class The command implementation + * @param array $args An associative array with additional parameters: + * 'before_invoke' => callback to execute before invoking the command */ - static function add_command( $name, $class ) { + static function add_command( $name, $class, $args = array() ) { $command = Dispatcher\CommandFactory::create( $name, $class, self::$root ); + if ( isset( $args['before_invoke'] ) ) { + self::add_action( "before_invoke:$name", $args['before_invoke'] ); + } + self::$root->add_subcommand( $name, $command ); } diff --git a/php/commands/network-meta.php b/php/commands/network-meta.php index 88b43759a..c7a603a90 100644 --- a/php/commands/network-meta.php +++ b/php/commands/network-meta.php @@ -9,11 +9,11 @@ class Network_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'site'; } -WP_CLI::add_command( 'network-meta', 'Network_Meta_Command' ); - -WP_CLI::add_action( 'before_invoke:network-meta', function () { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); +WP_CLI::add_command( 'network-meta', 'Network_Meta_Command', array( + 'before_invoke' => function () { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } } -} ); +) ); From 195ad148e753ce2e856ed1b4aeae2c601a1405a9 Mon Sep 17 00:00:00 2001 From: Mitesh Shah <Mitesh.Shah@rtCamp.com> Date: Thu, 20 Jun 2013 15:05:30 +0530 Subject: [PATCH 1859/5359] Support Subdomains --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 6feb6bc5c..ea82af3ba 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -158,7 +158,7 @@ public function install( $args, $assoc_args ) { * Transform a single-site install into a multi-site install. * * @subcommand install-network - * @synopsis --title=<network-title> [--base=<url-path>] + * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains=<TRUE>] */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) From ec59bac9036b2182c5a2f7e05c98da9843dbc40b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 12:44:28 +0300 Subject: [PATCH 1860/5359] core install-network: flags don't need a value; update man page see #532 --- man-src/core-install-network.txt | 4 ++++ man/core-install-network.1 | 8 +++++++- php/commands/core.php | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/man-src/core-install-network.txt b/man-src/core-install-network.txt index 26e2c2a95..24494f117 100644 --- a/man-src/core-install-network.txt +++ b/man-src/core-install-network.txt @@ -8,3 +8,7 @@ Base path after the domain name that each site url will start with. Default: '/' + +* `--subdomains`: + + If passed, the network will use subdomains, instead of subdirectories. diff --git a/man/core-install-network.1 b/man/core-install-network.1 index f7f4f84a8..60fdbfc0e 100644 --- a/man/core-install-network.1 +++ b/man/core-install-network.1 @@ -7,7 +7,7 @@ \fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. . .SH "SYNOPSIS" -wp core install\-network \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] +wp core install\-network \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] [\-\-subdomains] . .SH "OPTIONS" . @@ -22,4 +22,10 @@ The title of the new network\. . .IP Base path after the domain name that each site url will start with\. Default: \'/\' +. +.TP +\fB\-\-subdomains\fR: +. +.IP +If passed, the network will use subdomains, instead of subdirectories\. diff --git a/php/commands/core.php b/php/commands/core.php index ea82af3ba..9f450ce5b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -158,7 +158,7 @@ public function install( $args, $assoc_args ) { * Transform a single-site install into a multi-site install. * * @subcommand install-network - * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains=<TRUE>] + * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains] */ public function install_network( $args, $assoc_args ) { if ( is_multisite() ) From 404a035fb0cb834337bc08f691afd530cf6cf0a5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 19:04:20 +0300 Subject: [PATCH 1861/5359] search-replace: always do a SHOW TABLES query --- php/commands/search-replace.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 2a0f3309e..1eee97656 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -67,13 +67,9 @@ private static function get_table_list( $args, $network ) { if ( !empty( $args ) ) return $args; - if ( !$network ) { - $tables = $wpdb->tables( 'blog' ); - } else { - $tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->base_prefix}%'" ); - } + $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; - return $tables; + return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { From 3931aea9fc6ff3c5189c629c9e085555a7a38b98 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 21:30:07 +0300 Subject: [PATCH 1862/5359] option update: show success message even if the value has not changed see #531 --- features/option.feature | 3 +++ php/commands/option.php | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/option.feature b/features/option.feature index 707c4fe82..66c8d78e2 100644 --- a/features/option.feature +++ b/features/option.feature @@ -15,6 +15,9 @@ Feature: Manage WordPress options When I run `wp option set foo '[ 1, 2 ]' --format=json` Then STDOUT should not be empty + When I run the previous command again + Then STDOUT should not be empty + When I run `wp option get foo --format=json` Then STDOUT should be: """ diff --git a/php/commands/option.php b/php/commands/option.php index fb39ce7b5..f3f83404c 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -51,10 +51,10 @@ public function update( $args, $assoc_args ) { $value = WP_CLI::read_value( $args[1], $assoc_args ); - if ( $value === get_option( $key ) ) - return; + $result = update_option( $key, $value ); - if ( !update_option( $key, $value ) ) { + // update_option() returns false if the value is the same + if ( !$result && $value !== get_option( $key ) ) { WP_CLI::error( "Could not update option '$key'." ); } else { WP_CLI::success( "Updated '$key' option." ); From 80cc692d2ab8576233e675ed1e049f39f3c0a871 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 22:38:06 +0300 Subject: [PATCH 1863/5359] post create: balance brackets --- php/commands/post.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index e1e2da842..438f86ac1 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -24,13 +24,14 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { - if ( $args[0] !== '-' ) { $readfile = $args[0]; - if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) + if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) { \WP_CLI::error( "Unable to read content from $readfile." ); - } else + } + } else { $readfile = 'php://stdin'; + } $assoc_args['post_content'] = file_get_contents( $readfile ); } From b28a4a47ee94813f3a8816ee866f285cbad17604 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 20 Jun 2013 22:44:34 +0300 Subject: [PATCH 1864/5359] behat: add test for `post create` reading content from STDIN --- features/post.feature | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/features/post.feature b/features/post.feature index 035be2982..f8de28f0c 100644 --- a/features/post.feature +++ b/features/post.feature @@ -27,15 +27,23 @@ Feature: Manage WordPress posts Scenario: Creating/getting posts Given a WP install + And a content.html file: + """ + This is some content. + + It will be inserted in a post. + """ - When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` + When I run `wp post create --post_title='Test post' --porcelain - < content.html` Then STDOUT should match '%d' And save STDOUT as {POST_ID} When I run `wp post get --format=content {POST_ID}` Then STDOUT should be: """ - Test content. + This is some content. + + It will be inserted in a post. """ When I run `wp post get --format=table {POST_ID}` @@ -47,7 +55,7 @@ Feature: Manage WordPress posts When I run `wp post get --format=json {POST_ID}` Then STDOUT should be JSON containing: """ - {"ID":{POST_ID},"post_title":"Test post","post_content":"Test content."} + {"ID":{POST_ID},"post_title":"Test post"} """ Scenario: Creating/listing posts From 3ca6c14ab22042ce3a1be78a5ac057ec0c735358 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Jun 2013 00:22:49 +0300 Subject: [PATCH 1865/5359] --info: make WP-CLI root be the root folder, not php/ --- php/commands/_sys.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/_sys.php b/php/commands/_sys.php index fefbc2231..e5510c563 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -35,7 +35,7 @@ function info() { WP_CLI::line( "PHP binary:\t" . $php_bin ); WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "WP-CLI root:\t" . WP_CLI_ROOT ); + WP_CLI::line( "WP-CLI root:\t" . dirname( WP_CLI_ROOT ) ); WP_CLI::line( "WP-CLI config:\t" . WP_CLI::get_config_path() ); WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); } From 8483fb709b2285a033515f59b4ad818468a0372a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 9 May 2013 00:08:37 +0300 Subject: [PATCH 1866/5359] remove support for Phar archive --- php/boot-phar.php | 6 --- php/commands/help.php | 13 +----- utils/make-phar.php | 88 ---------------------------------------- utils/test-phar-download | 6 --- utils/update-phar | 46 --------------------- 5 files changed, 1 insertion(+), 158 deletions(-) delete mode 100644 php/boot-phar.php delete mode 100644 utils/make-phar.php delete mode 100755 utils/test-phar-download delete mode 100755 utils/update-phar diff --git a/php/boot-phar.php b/php/boot-phar.php deleted file mode 100644 index be8cfdcb2..000000000 --- a/php/boot-phar.php +++ /dev/null @@ -1,6 +0,0 @@ -<?php - -define( 'WP_CLI_ROOT', 'phar://wp-cli.phar/php/' ); - -include WP_CLI_ROOT . 'wp-cli.php'; - diff --git a/php/commands/help.php b/php/commands/help.php index ef8b24bef..a15ecc223 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -67,7 +67,7 @@ private static function maybe_show_manpage( $args ) { $man_path = "$dest_dir/" . $man_file; if ( is_readable( $man_path ) ) { - self::show_manpage( $man_path ); + \WP_CLI::launch( "man $man_path" ); return true; } } @@ -75,17 +75,6 @@ private static function maybe_show_manpage( $args ) { return false; } - private static function show_manpage( $path ) { - // man can't read phar://, so need to copy to a temporary file - $tmp_path = tempnam( sys_get_temp_dir(), 'wp-cli-man-' ); - - copy( $path, $tmp_path ); - - \WP_CLI::launch( "man $tmp_path" ); - - unlink( $tmp_path ); - } - private static function _generate( $src_dir, $dest_dir, $command ) { $cmd_path = Dispatcher\get_path( $command ); array_shift( $cmd_path ); // discard 'wp' diff --git a/utils/make-phar.php b/utils/make-phar.php deleted file mode 100644 index 1911b8f36..000000000 --- a/utils/make-phar.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php - -if ( !isset( $argv[1] ) ) { - echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet]\n"; - exit(1); -} - -define( 'DEST_PATH', $argv[1] ); - -define( 'BE_QUIET', in_array( '--quiet', $argv ) ); - -function get_iterator( $dir ) { - return new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) - ); -} - -function add_file( $phar, $path ) { - $key = str_replace( './', '', $path ); - - if ( !BE_QUIET ) - echo "$key - $path\n"; - - $phar[ $key ] = file_get_contents( $path ); -} - -$phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); - -$phar->startBuffering(); - -// php files -foreach ( get_iterator( './php' ) as $path ) { - if ( !preg_match( '/\.php$/', $path ) ) - continue; - - add_file( $phar, $path ); -} - -// non-php files -$additional_dirs = array( - './templates', - './man' -); - -foreach ( $additional_dirs as $dir ) { - foreach ( get_iterator( $dir ) as $path ) { - add_file( $phar, $path ); - } -} - -// dependencies -$ignored_paths = array( - '/.git', -); - -$vendor_dirs = array( - './vendor/mustache', - './vendor/wp-cli', - './vendor/composer', -); - -foreach ( $vendor_dirs as $vendor_dir ) { - foreach ( get_iterator( $vendor_dir ) as $path ) { - foreach ( $ignored_paths as $ignore ) { - if ( strpos( $path, $ignore ) ) - continue 2; - } - - add_file( $phar, $path ); - } -} - -add_file( $phar, './vendor/autoload.php' ); - -$phar->setStub( <<<EOB -#!/usr/bin/env php -<?php -Phar::mapPhar(); -include 'phar://wp-cli.phar/php/boot-phar.php'; -__HALT_COMPILER(); -?> -EOB -); - -$phar->stopBuffering(); - -echo "Generated " . DEST_PATH . "\n"; - diff --git a/utils/test-phar-download b/utils/test-phar-download deleted file mode 100755 index f1a47e519..000000000 --- a/utils/test-phar-download +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | md5sum | cut -d ' ' -f 1) - -echo "expected:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.md5) -echo "actual: " $actual_checksum diff --git a/utils/update-phar b/utils/update-phar deleted file mode 100755 index ea79bf112..000000000 --- a/utils/update-phar +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -current_rev=$(git rev-parse HEAD) -current_rev=${current_rev:0:10} - -packages_repo=../wp-cli-packages - -fname="phar/wp-cli.phar" - -# generate archive -php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet - -cd $packages_repo - -# smoke test -php $fname --version - -# check which wp-cli commit the previous Phar archive was based on -# can't use the md5 hash, since it will be different each time the -# archive is generated -new_commit_subj="update wp-cli.phar to wp-cli/wp-cli@$current_rev" - -current_commit_subj=$(git show -s --pretty=format:%s HEAD) - -if [ "$new_commit_subj" = "$current_commit_subj" ]; then - echo "already at latest revision" - exit 1 -fi - -# generate md5 checksum -if [ command -v md5sum > /dev/null ] -then - md5hash=$(md5sum $fname) -else - md5hash=$(md5 -r $fname) -fi - -echo $md5hash | cut -d ' ' -f 1 > $fname.md5 - -git add $fname $fname.md5 - -git commit -m "$new_commit_subj" - -git push From ec88e63f36841cbac5b6fb88eefbc181c6b1c06c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Jun 2013 12:34:38 +0300 Subject: [PATCH 1867/5359] define WP_CLI_ROOT to be the root directory, with no trailing slash --- php/boot-fs.php | 4 ++-- php/class-wp-cli.php | 6 +++--- php/commands/_sys.php | 2 +- php/commands/scaffold.php | 2 +- php/utils.php | 12 ++++++------ php/wp-cli.php | 10 +++++----- php/wp-settings-cli.php | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/php/boot-fs.php b/php/boot-fs.php index a227bfede..7a13744db 100644 --- a/php/boot-fs.php +++ b/php/boot-fs.php @@ -12,7 +12,7 @@ die(-1); } -define( 'WP_CLI_ROOT', __DIR__ . '/' ); +define( 'WP_CLI_ROOT', dirname( __DIR__ ) ); -include dirname(__FILE__) . '/wp-cli.php'; +include WP_CLI_ROOT . '/php/wp-cli.php'; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3cb5133c4..9f928a481 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -23,11 +23,11 @@ class WP_CLI { */ static function init() { self::add_man_dir( - WP_CLI_ROOT . "../man", - WP_CLI_ROOT . "../man-src" + WP_CLI_ROOT . "/man", + WP_CLI_ROOT . "/man-src" ); - self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/config-spec.php' ); + self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); self::$root = new Dispatcher\RootCommand; self::$runner = new WP_CLI\Runner; } diff --git a/php/commands/_sys.php b/php/commands/_sys.php index e5510c563..fefbc2231 100644 --- a/php/commands/_sys.php +++ b/php/commands/_sys.php @@ -35,7 +35,7 @@ function info() { WP_CLI::line( "PHP binary:\t" . $php_bin ); WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "WP-CLI root:\t" . dirname( WP_CLI_ROOT ) ); + WP_CLI::line( "WP-CLI root:\t" . WP_CLI_ROOT ); WP_CLI::line( "WP-CLI config:\t" . WP_CLI::get_config_path() ); WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); } diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 7997e23da..242833973 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -260,7 +260,7 @@ function plugin_tests( $args, $assoc_args ) { ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( WP_CLI_ROOT . "../templates/$file", "$dir/$file", true ); + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); } WP_CLI::success( "Created test files." ); diff --git a/php/utils.php b/php/utils.php index a5a2bad76..dab686c87 100644 --- a/php/utils.php +++ b/php/utils.php @@ -8,8 +8,8 @@ function load_dependencies() { $vendor_paths = array( - WP_CLI_ROOT . '../vendor', // top-level project - WP_CLI_ROOT . '../../../../vendor', // part of a larger project + WP_CLI_ROOT . '/vendor', // top-level project + WP_CLI_ROOT . '/../../../vendor', // part of a larger project ); $has_autoload = false; @@ -27,11 +27,11 @@ function load_dependencies() { exit(3); } - include WP_CLI_ROOT . 'Spyc.php'; + include WP_CLI_ROOT . '/php/Spyc.php'; } function load_command( $name ) { - $path = WP_CLI_ROOT . "/commands/$name.php"; + $path = WP_CLI_ROOT . "/php/commands/$name.php"; if ( is_readable( $path ) ) { include_once $path; @@ -39,7 +39,7 @@ function load_command( $name ) { } function load_all_commands() { - $cmd_dir = WP_CLI_ROOT . "commands"; + $cmd_dir = WP_CLI_ROOT . "/php/commands"; $iterator = new \DirectoryIterator( $cmd_dir ); @@ -372,7 +372,7 @@ function run_mysql_command( $cmd, $arg_str, $pass ) { } function mustache_render( $template_name, $data ) { - $template = file_get_contents( WP_CLI_ROOT . "../templates/$template_name" ); + $template = file_get_contents( WP_CLI_ROOT . "/templates/$template_name" ); $m = new \Mustache_Engine; diff --git a/php/wp-cli.php b/php/wp-cli.php index 59cee2480..5970c361f 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -5,10 +5,10 @@ define( 'WP_CLI_VERSION', '0.11.0-alpha' ); -include WP_CLI_ROOT . 'utils.php'; -include WP_CLI_ROOT . 'dispatcher.php'; -include WP_CLI_ROOT . 'class-wp-cli.php'; -include WP_CLI_ROOT . 'class-wp-cli-command.php'; +include WP_CLI_ROOT . '/php/utils.php'; +include WP_CLI_ROOT . '/php/dispatcher.php'; +include WP_CLI_ROOT . '/php/class-wp-cli.php'; +include WP_CLI_ROOT . '/php/class-wp-cli-command.php'; \WP_CLI\Utils\load_dependencies(); @@ -26,7 +26,7 @@ define( 'WP_USER_ADMIN', false ); // Load Core, mu-plugins, plugins, themes etc. -require WP_CLI_ROOT . 'wp-settings-cli.php'; +require WP_CLI_ROOT . '/php/wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index f892f57eb..34cba9323 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -40,7 +40,7 @@ timer_start(); // Load WP-CLI utilities -require WP_CLI_ROOT . 'utils-wp.php'; +require WP_CLI_ROOT . '/php/utils-wp.php'; // Check if we're in WP_DEBUG mode. Utils\wp_debug_mode(); From 34b370439109a9d28c6339071e4f4cc947a5839a Mon Sep 17 00:00:00 2001 From: Andrey Savchenko <contact@rarst.net> Date: Sat, 22 Jun 2013 01:42:33 +0300 Subject: [PATCH 1868/5359] Added basic wp.bat launcher for Windows environment. --- bin/wp.bat | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 bin/wp.bat diff --git a/bin/wp.bat b/bin/wp.bat new file mode 100644 index 000000000..59f953440 --- /dev/null +++ b/bin/wp.bat @@ -0,0 +1,2 @@ +@ECHO OFF +php "%~dp0../php/boot-fs.php" %* \ No newline at end of file From 4b5786bc16905cf0c3f2cc95a4afd9d51390f2d4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 02:24:31 +0300 Subject: [PATCH 1869/5359] colorize plugin/theme status legend. see #517 --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index c8da9c3a4..65ede4f56 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -92,7 +92,7 @@ private function show_legend( $items ) { if ( in_array( true, wp_list_pluck( $items, 'update' ) ) ) $legend_line[] = '%yU = Update Available%n'; - \WP_CLI::line( 'Legend: ' . implode( ', ', $legend_line ) ); + \WP_CLI::line( 'Legend: ' . implode( ', ', \WP_CLI::colorize( $legend_line ) ) ); } function install( $args, $assoc_args ) { From 9304d773ab2f993bc820fc41e7b0e218f4724c07 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 21:08:28 +0300 Subject: [PATCH 1870/5359] fix man page for `wp core is-installed` --- man-src/core-is-installed.txt | 6 +++--- man/core-is-installed.1 | 13 ++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/man-src/core-is-installed.txt b/man-src/core-is-installed.txt index e4901fe31..afccd6c95 100644 --- a/man-src/core-is-installed.txt +++ b/man-src/core-is-installed.txt @@ -1,5 +1,5 @@ ## EXAMPLES -if ! $(wp core is-installed); then - wp core install -fi + if ! $(wp core is-installed); then + wp core install + fi diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 index 0aab8f72c..56f61768b 100644 --- a/man/core-is-installed.1 +++ b/man/core-is-installed.1 @@ -10,17 +10,12 @@ wp core is\-installed . .SH "EXAMPLES" -if ! $(wp core is\-installed); then -. -.IP "" 4 . .nf -wp core install +if ! $(wp core is\-installed); then + wp core install +fi . .fi -. -.IP "" 0 -. -.P -fi + From 625081abb79fd9ce7ce0427c72619821244c7e4a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 21:52:52 +0300 Subject: [PATCH 1871/5359] fix synopsis for `wp media import` --- man/media-import.1 | 2 +- php/commands/media.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/media-import.1 b/man/media-import.1 index 8dca82091..8ef92207d 100644 --- a/man/media-import.1 +++ b/man/media-import.1 @@ -7,7 +7,7 @@ \fBwp\-media\-import\fR \- Create attachments from local files or from URLs\. . .SH "SYNOPSIS" -wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIpost_id\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fIalt_text\fR] [\-\-desc=\fIdescription\fR] [\-\-featured_image] +wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIid\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fItext\fR] [\-\-desc=\fIdescription\fR] [\-\-featured_image] . .SH "OPTIONS" . diff --git a/php/commands/media.php b/php/commands/media.php index b35db1ef8..0b73113fd 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -56,7 +56,7 @@ function regenerate( $args, $assoc_args = array() ) { /** * Create attachments from local files or from URLs. * - * @synopsis <file>... [--post_id=<post_id>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] [--featured_image] + * @synopsis <file>... [--post_id=<id>] [--title=<title>] [--caption=<caption>] [--alt=<text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { From 31a30e5015fb098811c1f5b0ce6225abd7d1b7dd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 21:53:13 +0300 Subject: [PATCH 1872/5359] various man page updates --- man/cap.1 | 4 ++-- man/db.1 | 16 ++++++++-------- man/post-meta.1 | 4 ++-- man/transient.1 | 6 +++--- man/user-meta.1 | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/man/cap.1 b/man/cap.1 index fdee7e6b6..fd4b8f669 100644 --- a/man/cap.1 +++ b/man/cap.1 @@ -7,10 +7,10 @@ \fBwp\-cap\fR \- Manage user capabilities\. . .SH "SYNOPSIS" -wp cap list \fIrole\fR +wp cap add \fIrole\fR \fIcap\fR\.\.\. . .P -wp cap add \fIrole\fR \fIcap\fR\.\.\. +wp cap list \fIrole\fR . .P wp cap remove \fIrole\fR \fIcap\fR\.\.\. diff --git a/man/db.1 b/man/db.1 index 5dd468995..eaca52f2c 100644 --- a/man/db.1 +++ b/man/db.1 @@ -7,31 +7,31 @@ \fBwp\-db\fR \- Perform basic database operations\. . .SH "SYNOPSIS" -wp db create +wp db cli . .P -wp db drop [\-\-yes] +wp db create . .P -wp db reset [\-\-yes] +wp db drop [\-\-yes] . .P -wp db optimize +wp db export [\fIfile\fR] . .P -wp db repair +wp db import [\fIfile\fR] . .P -wp db cli +wp db optimize . .P wp db query [\fIsql\fR] . .P -wp db export [\fIfile\fR] +wp db repair . .P -wp db import [\fIfile\fR] +wp db reset [\-\-yes] . .SH "SUBCOMMANDS" . diff --git a/man/post-meta.1 b/man/post-meta.1 index ac1203efe..90398260a 100644 --- a/man/post-meta.1 +++ b/man/post-meta.1 @@ -7,13 +7,13 @@ \fBwp\-post\-meta\fR \- Manage post custom fields\. . .SH "SYNOPSIS" -wp post\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] +wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .P wp post\-meta delete \fIid\fR \fIkey\fR . .P -wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +wp post\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] . .P wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] diff --git a/man/transient.1 b/man/transient.1 index 1edd72a00..695644fc7 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -7,13 +7,13 @@ \fBwp\-transient\fR \- Manage WordPress transients\. . .SH "SYNOPSIS" -wp transient get \fIkey\fR [\-\-json] +wp transient delete \fIkey\fR . .P -wp transient set \fIkey\fR \fIvalue\fR [\fIexpiration\fR] +wp transient get \fIkey\fR [\-\-json] . .P -wp transient delete \fIkey\fR +wp transient set \fIkey\fR \fIvalue\fR [\fIexpiration\fR] . .P wp transient type diff --git a/man/user-meta.1 b/man/user-meta.1 index b09bb8db9..817491f42 100644 --- a/man/user-meta.1 +++ b/man/user-meta.1 @@ -7,13 +7,13 @@ \fBwp\-user\-meta\fR \- Manage user custom fields\. . .SH "SYNOPSIS" -wp user\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] +wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] . .P wp user\-meta delete \fIid\fR \fIkey\fR . .P -wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] +wp user\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] . .P wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] From 22dadc77575cae1b15e08bac93a86f299b270aa4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 22:28:49 +0300 Subject: [PATCH 1873/5359] misc man fixes [ci skip] --- man-src/cache.txt | 4 ++-- man-src/core-download.txt | 2 +- man-src/core-init-tests.txt | 2 +- man-src/db.txt | 3 ++- man-src/scaffold-plugin-tests.txt | 2 +- man-src/theme-delete.txt | 2 +- man-src/theme-install.txt | 2 +- man-src/theme-update.txt | 2 +- man-src/transient.txt | 2 +- man/cache.1 | 9 +++++++-- man/core-download.1 | 2 +- man/core-init-tests.1 | 6 ++++++ man/db.1 | 7 +++++++ man/scaffold-plugin-tests.1 | 6 ++++++ man/theme-delete.1 | 2 +- man/theme-install.1 | 2 +- man/theme-update.1 | 2 +- man/transient.1 | 6 ++++++ 18 files changed, 47 insertions(+), 16 deletions(-) diff --git a/man-src/cache.txt b/man-src/cache.txt index 7b25aa6d7..70856ff26 100644 --- a/man-src/cache.txt +++ b/man-src/cache.txt @@ -1,5 +1,5 @@ ## EXAMPLES -wp cache set my_key my_value my_group 300 + wp cache set my_key my_value my_group 300 -wp cache get my_key my_group + wp cache get my_key my_group diff --git a/man-src/core-download.txt b/man-src/core-download.txt index 74448c986..a72ecc610 100644 --- a/man-src/core-download.txt +++ b/man-src/core-download.txt @@ -15,4 +15,4 @@ ignored in this case. ## EXAMPLES - Download version 3.3: wp core download --version=3.3 + wp core download --version=3.3 diff --git a/man-src/core-init-tests.txt b/man-src/core-init-tests.txt index 9f55ec5cc..55d72eafc 100644 --- a/man-src/core-init-tests.txt +++ b/man-src/core-init-tests.txt @@ -19,4 +19,4 @@ you run the tests. ## EXAMPLE -wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test + wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test diff --git a/man-src/db.txt b/man-src/db.txt index a9fb12bfd..d7ccfb703 100644 --- a/man-src/db.txt +++ b/man-src/db.txt @@ -14,4 +14,5 @@ ## EXAMPLES -wp db query < debug.sql + # execute a query stored in a file + wp db query < debug.sql diff --git a/man-src/scaffold-plugin-tests.txt b/man-src/scaffold-plugin-tests.txt index 927c7fea4..7224977bd 100644 --- a/man-src/scaffold-plugin-tests.txt +++ b/man-src/scaffold-plugin-tests.txt @@ -14,4 +14,4 @@ variable. ## EXAMPLE -wp scaffold plugin-tests hello + wp scaffold plugin-tests hello diff --git a/man-src/theme-delete.txt b/man-src/theme-delete.txt index 22506747b..030f781e4 100644 --- a/man-src/theme-delete.txt +++ b/man-src/theme-delete.txt @@ -1,6 +1,6 @@ ## OPTIONS -* <theme>: +* `<theme>`: The theme to delete. diff --git a/man-src/theme-install.txt b/man-src/theme-install.txt index 28e26a342..a7377e628 100644 --- a/man-src/theme-install.txt +++ b/man-src/theme-install.txt @@ -1,6 +1,6 @@ ## OPTIONS -* <theme>: +* `<theme>`: A theme slug or the path to a zip file. diff --git a/man-src/theme-update.txt b/man-src/theme-update.txt index d3439e48a..b7e610940 100644 --- a/man-src/theme-update.txt +++ b/man-src/theme-update.txt @@ -1,6 +1,6 @@ ## OPTIONS -* <theme>: +* `<theme>`: The theme to update. diff --git a/man-src/transient.txt b/man-src/transient.txt index 175ca9c8d..64dcebe0f 100644 --- a/man-src/transient.txt +++ b/man-src/transient.txt @@ -1,3 +1,3 @@ ## EXAMPLES -wp transient set my_key my_value 300 + wp transient set my_key my_value 300 diff --git a/man/cache.1 b/man/cache.1 index 2f724253c..7587a2a94 100644 --- a/man/cache.1 +++ b/man/cache.1 @@ -90,7 +90,12 @@ Set a value to the object cache\. Attempts to determine which object cache is being used\. . .SH "EXAMPLES" -wp cache set my_key my_value my_group 300 . -.P +.nf + +wp cache set my_key my_value my_group 300 + wp cache get my_key my_group +. +.fi + diff --git a/man/core-download.1 b/man/core-download.1 index 7f2725d56..7f607ca28 100644 --- a/man/core-download.1 +++ b/man/core-download.1 @@ -33,7 +33,7 @@ Overwrites existing files, if present\. . .nf -Download version 3\.3: wp core download \-\-version=3\.3 +wp core download \-\-version=3\.3 . .fi diff --git a/man/core-init-tests.1 b/man/core-init-tests.1 index 7e5c48195..e5001c331 100644 --- a/man/core-init-tests.1 +++ b/man/core-init-tests.1 @@ -36,4 +36,10 @@ Set the database user\. Set the database user password\. . .SH "EXAMPLE" +. +.nf + wp core init\-tests ~/svn/wp\-tests \-\-dbname=wp_test \-\-dbuser=wp_test +. +.fi + diff --git a/man/db.1 b/man/db.1 index eaca52f2c..7524abedd 100644 --- a/man/db.1 +++ b/man/db.1 @@ -110,4 +110,11 @@ The name of the export file\. If omitted, it will be \'{dbname}\.sql\' A SQL query\. . .SH "EXAMPLES" +. +.nf + +# execute a query stored in a file wp db query < debug\.sql +. +.fi + diff --git a/man/scaffold-plugin-tests.1 b/man/scaffold-plugin-tests.1 index 1e1e7cd26..5c0a07ee5 100644 --- a/man/scaffold-plugin-tests.1 +++ b/man/scaffold-plugin-tests.1 @@ -30,4 +30,10 @@ These are the files that are generated: The \fBtests/bootstrap\.php\fR file looks for the WP_TESTS_DIR environment variable\. . .SH "EXAMPLE" +. +.nf + wp scaffold plugin\-tests hello +. +.fi + diff --git a/man/theme-delete.1 b/man/theme-delete.1 index 006662475..3bfae3759 100644 --- a/man/theme-delete.1 +++ b/man/theme-delete.1 @@ -12,7 +12,7 @@ wp theme delete \fItheme\fR .SH "OPTIONS" . .TP -\fItheme\fR: +\fB<theme>\fR: . .IP The theme to delete\. diff --git a/man/theme-install.1 b/man/theme-install.1 index df8a8ef70..5e74e7c30 100644 --- a/man/theme-install.1 +++ b/man/theme-install.1 @@ -12,7 +12,7 @@ wp theme install \fItheme|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] .SH "OPTIONS" . .TP -\fItheme\fR: +\fB<theme>\fR: . .IP A theme slug or the path to a zip file\. diff --git a/man/theme-update.1 b/man/theme-update.1 index 86fd820bd..7e877c817 100644 --- a/man/theme-update.1 +++ b/man/theme-update.1 @@ -12,7 +12,7 @@ wp theme update \fItheme\fR [\-\-version=\fIversion\fR] .SH "OPTIONS" . .TP -\fItheme\fR: +\fB<theme>\fR: . .IP The theme to update\. diff --git a/man/transient.1 b/man/transient.1 index 695644fc7..e3fd1ddd1 100644 --- a/man/transient.1 +++ b/man/transient.1 @@ -45,4 +45,10 @@ Set a transient value\. <expiration> is the time until expiration, in seconds\. See wether the transients API is using an object cache or the options table\. . .SH "EXAMPLES" +. +.nf + wp transient set my_key my_value 300 +. +.fi + From 7fe10d4c70387e093351270aea6c3e982548bc02 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 12:46:34 +0300 Subject: [PATCH 1874/5359] remove empty line --- php/WP_CLI/Dispatcher/RootCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index c9e9abddc..03bc8196d 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -39,10 +39,10 @@ function show_usage() { EOB ); - \WP_CLI::line( self::generate_synopsis() ); + self::show_synopsis(); } - private static function generate_synopsis() { + private static function show_synopsis() { $max_len = 0; $lines = array(); From e2dc746ac6dd025f3422bbbb6d46978427f44021 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 14:44:11 +0300 Subject: [PATCH 1875/5359] update Composer dependencies --- composer.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/composer.lock b/composer.lock index 8764fbff5..4eb19204e 100644 --- a/composer.lock +++ b/composer.lock @@ -53,12 +53,12 @@ "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "d44e1a9bd32d564a1c77dda0e96b66a199993e5c" + "reference": "9c34cb24ddbdec5ae0a56297561acda708890b5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d44e1a9bd32d564a1c77dda0e96b66a199993e5c", - "reference": "d44e1a9bd32d564a1c77dda0e96b66a199993e5c", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/9c34cb24ddbdec5ae0a56297561acda708890b5c", + "reference": "9c34cb24ddbdec5ae0a56297561acda708890b5c", "shasum": "" }, "require": { @@ -90,7 +90,7 @@ "cli", "console" ], - "time": "2013-05-11 20:20:03" + "time": "2013-06-23 11:32:36" } ], "packages-dev": [ @@ -738,17 +738,17 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.3.0", + "version": "v2.3.1", "target-dir": "Symfony/Component/EventDispatcher", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.3.0-RC1" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.0-RC1", - "reference": "v2.3.0-RC1", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { @@ -886,17 +886,17 @@ }, { "name": "symfony/translation", - "version": "v2.3.0", + "version": "v2.3.1", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "v2.3.0-RC1" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.0-RC1", - "reference": "v2.3.0-RC1", + "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { @@ -941,17 +941,17 @@ }, { "name": "symfony/yaml", - "version": "v2.3.0", + "version": "v2.3.1", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.3.0-RC1" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.0-RC1", - "reference": "v2.3.0-RC1", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { From 7cc4c8669674ee1a7485efe7e1ef4f1d02876187 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 14:45:44 +0300 Subject: [PATCH 1876/5359] ignore composer.lock Facts: 1. When WP-CLI isn't installed as the root package, composer.lock is ignored. 2. The wp-cli.org installer doesn't install WP-CLI as the root package, but as a dependency. 1. + 2. => Having composer.lock under version control gives a false sense of security. Instead, we should take more care with how we define dependencies in composer.json --- .gitignore | 1 + composer.lock | 1003 ------------------------------------------------- 2 files changed, 1 insertion(+), 1003 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 325d475d8..03f9ead5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +composer.lock composer.phar /vendor /phpunit.xml diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 4eb19204e..000000000 --- a/composer.lock +++ /dev/null @@ -1,1003 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" - ], - "hash": "6cae44632851e1e1cee580631b2d784a", - "packages": [ - { - "name": "mustache/mustache", - "version": "v2.3.1", - "source": { - "type": "git", - "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "type": "library", - "autoload": { - "psr-0": { - "Mustache": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" - } - ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", - "keywords": [ - "mustache", - "templating" - ], - "time": "2013-04-25 15:23:30" - }, - { - "name": "wp-cli/php-cli-tools", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "9c34cb24ddbdec5ae0a56297561acda708890b5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/9c34cb24ddbdec5ae0a56297561acda708890b5c", - "reference": "9c34cb24ddbdec5ae0a56297561acda708890b5c", - "shasum": "" - }, - "require": { - "php": ">= 5.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "cli": "lib/" - }, - "files": [ - "lib/cli/cli.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "James Logsdon", - "email": "jlogsdon@php.net", - "role": "Developer" - } - ], - "description": "Console utilities for PHP", - "homepage": "http://github.com/jlogsdon/php-cli-tools", - "keywords": [ - "cli", - "console" - ], - "time": "2013-06-23 11:32:36" - } - ], - "packages-dev": [ - { - "name": "behat/behat", - "version": "v2.4.6", - "source": { - "type": "git", - "url": "https://github.com/Behat/Behat.git", - "reference": "v2.4.6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/v2.4.6", - "reference": "v2.4.6", - "shasum": "" - }, - "require": { - "behat/gherkin": ">=2.2.9,<2.3", - "php": ">=5.3.1", - "symfony/config": ">=2.0,<3.0", - "symfony/console": ">=2.0,<3.0", - "symfony/dependency-injection": ">=2.0,<3.0", - "symfony/event-dispatcher": ">=2.0,<3.0", - "symfony/finder": ">=2.0,<3.0", - "symfony/translation": ">=2.0,<3.0", - "symfony/yaml": ">=2.0,<3.0" - }, - "require-dev": { - "phpunit/phpunit": ">=3.7.19.0,<3.8" - }, - "suggest": { - "behat/mink-extension": "for integration with Mink testing framework", - "behat/symfony2-extension": "for integration with Symfony2 web framework", - "behat/yii-extension": "for integration with Yii web framework" - }, - "bin": [ - "bin/behat" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Behat": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Scenario-oriented BDD framework for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "Symfony2" - ], - "time": "2013-06-06 10:46:48" - }, - { - "name": "behat/gherkin", - "version": "v2.2.9", - "source": { - "type": "git", - "url": "https://github.com/Behat/Gherkin.git", - "reference": "v2.2.9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/v2.2.9", - "reference": "v2.2.9", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/finder": ">=2.0,<2.4-dev" - }, - "require-dev": { - "symfony/config": ">=2.0,<2.4-dev", - "symfony/translation": ">=2.0,<2.4-dev", - "symfony/yaml": ">=2.0,<2.4-dev" - }, - "suggest": { - "symfony/config": "If you want to use Config component to manage resources", - "symfony/translation": "If you want to use Symfony2 translations adapter", - "symfony/yaml": "If you want to parse features, represented in YAML files" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "2.2-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Gherkin": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Gherkin DSL parser for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "DSL", - "Symfony2", - "parser" - ], - "time": "2013-03-02 10:38:40" - }, - { - "name": "phpunit/php-code-coverage", - "version": "1.2.11", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.11", - "reference": "1.2.11", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.1.1@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2013-05-23 18:23:24" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.3.3", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "1.3.3" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", - "reference": "1.3.3", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "File/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2012-10-11 04:44:38" - }, - { - "name": "phpunit/php-text-template", - "version": "1.1.4", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-text-template.git", - "reference": "1.1.4" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", - "reference": "1.1.4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "Text/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2012-10-31 11:15:28" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.4", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-timer.git", - "reference": "1.0.4" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", - "reference": "1.0.4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "timer" - ], - "time": "2012-10-11 04:45:58" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.1.5", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1.1.5" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", - "reference": "1.1.5", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "tokenizer" - ], - "time": "2012-10-11 04:47:14" - }, - { - "name": "phpunit/phpunit", - "version": "3.7.21", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.21" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.21", - "reference": "3.7.21", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-timer": ">=1.0.2,<1.1.0", - "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.0,<3.0" - }, - "require-dev": { - "pear-pear/pear": "1.9.4" - }, - "suggest": { - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "phpunit/php-invoker": ">=1.1.0,<1.2.0" - }, - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2013-05-23 18:54:29" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "1.2.3" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", - "reference": "1.2.3", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2013-01-13 10:24:48" - }, - { - "name": "symfony/config", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Config", - "source": { - "type": "git", - "url": "https://github.com/symfony/Config.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/filesystem": ">=2.3,<3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Config\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Config Component", - "homepage": "http://symfony.com", - "time": "2013-06-03 00:18:25" - }, - { - "name": "symfony/console", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Console", - "source": { - "type": "git", - "url": "https://github.com/symfony/Console.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/event-dispatcher": ">=2.1,<3.0" - }, - "suggest": { - "symfony/event-dispatcher": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Console\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "http://symfony.com", - "time": "2013-06-11 07:15:14" - }, - { - "name": "symfony/dependency-injection", - "version": "v2.3.1", - "target-dir": "Symfony/Component/DependencyInjection", - "source": { - "type": "git", - "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/config": ">=2.2,<3.0", - "symfony/yaml": ">=2.0,<3.0" - }, - "suggest": { - "symfony/config": "", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\DependencyInjection\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony DependencyInjection Component", - "homepage": "http://symfony.com", - "time": "2013-06-05 09:51:05" - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.3.1", - "target-dir": "Symfony/Component/EventDispatcher", - "source": { - "type": "git", - "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/dependency-injection": ">=2.0,<3.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com", - "time": "2013-05-13 14:36:40" - }, - { - "name": "symfony/filesystem", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Filesystem", - "source": { - "type": "git", - "url": "https://github.com/symfony/Filesystem.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Filesystem\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "http://symfony.com", - "time": "2013-06-04 15:02:05" - }, - { - "name": "symfony/finder", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Finder", - "source": { - "type": "git", - "url": "https://github.com/symfony/Finder.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Finder\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Finder Component", - "homepage": "http://symfony.com", - "time": "2013-06-02 12:05:51" - }, - { - "name": "symfony/translation", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Translation", - "source": { - "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/config": ">=2.0,<3.0", - "symfony/yaml": ">=2.2,<3.0" - }, - "suggest": { - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Translation\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Translation Component", - "homepage": "http://symfony.com", - "time": "2013-05-13 14:36:40" - }, - { - "name": "symfony/yaml", - "version": "v2.3.1", - "target-dir": "Symfony/Component/Yaml", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.3.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.1", - "reference": "v2.3.1", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com", - "time": "2013-05-10 18:12:13" - } - ], - "aliases": [ - - ], - "minimum-stability": "stable", - "stability-flags": { - "wp-cli/php-cli-tools": 20 - }, - "platform": { - "php": ">=5.3.2" - }, - "platform-dev": [ - - ] -} From 7742a7003428aa22a764feb957a9e2cb22c59418 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Jun 2013 23:31:14 +0300 Subject: [PATCH 1877/5359] output help markdown directly, instead of going through man --- .travis.yml | 4 +- CONTRIBUTING.md | 11 -- bin/ci/install_dependencies.sh | 4 - bin/ci/run_build.sh | 6 +- features/help.feature | 55 +------- man-src/help.txt | 11 +- php/WP_CLI/Dispatcher/CompositeCommand.php | 3 +- php/WP_CLI/Dispatcher/Subcommand.php | 11 +- php/commands/help.php | 145 ++++----------------- php/dispatcher.php | 28 ---- templates/man.mustache | 15 ++- 11 files changed, 58 insertions(+), 235 deletions(-) diff --git a/.travis.yml b/.travis.yml index 138b44b66..cff1fea32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,12 +6,12 @@ php: env: - WP_VERSION=latest - - WP_VERSION=3.4.2 WITH_RONN=1 + - WP_VERSION=3.4.2 matrix: exclude: - php: 5.4 - env: WP_VERSION=3.4.2 WITH_RONN=1 + env: WP_VERSION=3.4.2 before_script: ./bin/ci/install_dependencies.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ce37fda..3580119b9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,17 +15,6 @@ Also, please create or update the appropriate `.txt` file in the `man-src` direc Lastly, please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). -Generating man pages --------------------- - -To generate a man page, WP-CLI looks for `.txt` files in the `man-src` directory. It also gathers information from the inline comments and the `@synopsis` annotations. - -The compiled man page is placed in the `man` directory. - -To (re)generate one or more man pages, you first need to have the [ronn](https://rubygems.org/gems/ronn) ruby gem installed. - -Then, you can use the `wp help --gen` command. - Running the tests ----------------- diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh index 02b33c11b..c75651098 100755 --- a/bin/ci/install_dependencies.sh +++ b/bin/ci/install_dependencies.sh @@ -8,10 +8,6 @@ set -ex composer install --dev --no-interaction --prefer-source composer require d11wtq/boris=dev-master --no-interaction --prefer-source -if [ -n "$WITH_RONN" ]; then - gem install ronn -fi - # set up WP install ./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh index aed4ad0bf..3ed2e35cd 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/run_build.sh @@ -4,8 +4,4 @@ set -ex vendor/bin/phpunit -if [ -z "$WITH_RONN" ]; then - BEHAT_OPTS="--tags ~@ronn" -fi - -vendor/bin/behat --format progress $BEHAT_OPTS +vendor/bin/behat --format progress diff --git a/features/help.feature b/features/help.feature index 5b8b421fe..2f2193548 100644 --- a/features/help.feature +++ b/features/help.feature @@ -4,52 +4,21 @@ Feature: Get help about WP-CLI commands Given an empty directory When I run `wp help` - Then STDOUT should contain: - """ - Available commands: - """ + Then STDOUT should not be empty When I run `wp help core` - Then STDOUT should contain: - """ - usage: wp core - """ + Then STDOUT should not be empty When I run `wp help core download` - Then STDOUT should contain: - """ - WP-CORE-DOWNLOAD(1) - """ + Then STDOUT should not be empty - When I run `wp help --help` - Then STDOUT should contain: - """ - WP-HELP(1) - """ + When I run `wp help help` + Then STDOUT should not be empty When I try `wp help non-existent-command` Then the return code should be 1 And STDERR should not be empty - @ronn - Scenario: Generating help for subcommands - Given an empty directory - When I run `wp help --gen option` - Then STDOUT should be: - """ - generated option.1 - """ - - @ronn - Scenario: Generating help for multisite-only subcommands - Given an empty directory - When I run `wp help --gen site create` - Then STDOUT should be: - """ - generated site-create.1 - """ - - @ronn Scenario: Help for third-party commands Given a WP install And a wp-content/plugins/test-cli/test-help.txt file: @@ -76,17 +45,5 @@ Feature: Get help about WP-CLI commands When I run `wp help test-help` Then STDOUT should contain: """ - usage: wp test-help - """ - - When I run `wp help --gen test-help` - Then STDOUT should contain: - """ - generated test-help.1 - """ - - When I run `wp help test-help` - Then STDOUT should contain: - """ - WP-TEST-HELP(1) + wp test-help """ diff --git a/man-src/help.txt b/man-src/help.txt index 69ac8e699..19e660f7c 100644 --- a/man-src/help.txt +++ b/man-src/help.txt @@ -1,10 +1,7 @@ ## EXAMPLES - # (re)generates all man pages - wp help --gen + # get help for `core` command + wp help core - # (re)generate man pages for the `core` command - wp help --gen core - - # (re)generate man page only for the `core download` subcommand - wp help --gen core download + # get help for `core download` subcommand + wp help core download diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 14179199c..8a527fa09 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -17,7 +17,6 @@ public function __construct( $parent, $name, $docparser ) { $this->name = $name; $this->shortdesc = $docparser->get_shortdesc(); - $this->synopsis = $docparser->get_synopsis(); $when_to_invoke = $docparser->get_tag( 'when' ); if ( $when_to_invoke ) { @@ -52,7 +51,7 @@ function get_shortdesc() { } function get_synopsis() { - return $this->synopsis; + return '<subcommand>'; } function invoke( $args, $assoc_args ) { diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 55d27f925..3203ef9d4 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -14,17 +14,26 @@ class Subcommand extends CompositeCommand { function __construct( $parent, $name, $docparser, $when_invoked ) { $this->when_invoked = $when_invoked; + $this->synopsis = $docparser->get_synopsis(); $this->alias = $docparser->get_tag( 'alias' ); parent::__construct( $parent, $name, $docparser ); } + function get_synopsis() { + return $this->synopsis; + } + function get_alias() { return $this->alias; } function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $prefix . get_full_synopsis( $this ) ); + \WP_CLI::line( sprintf( "%s%s %s", + $prefix, + implode( ' ', get_path( $this ) ), + $this->get_synopsis() + ) ); } private function validate_args( $args, &$assoc_args ) { diff --git a/php/commands/help.php b/php/commands/help.php index a15ecc223..03ac39082 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -8,13 +8,21 @@ class Help_Command extends WP_CLI_Command { /** * Get help on a certain topic. * - * @synopsis [<command>] [--gen] + * @synopsis [<command>] */ function __invoke( $args, $assoc_args ) { - if ( isset( $assoc_args['gen'] ) ) - $this->generate( $args ); - else - $this->show( $args ); + $command = self::find_subcommand( $args ); + + if ( $command ) { + self::add_initial_markdown( $command ); + + $extra_markdown_path = self::find_extra_markdown( $command ); + if ( $extra_markdown_path ) { + echo file_get_contents( $extra_markdown_path ); + } + + exit; + } // WordPress is already loaded, so there's no chance we'll find the command if ( function_exists( 'add_filter' ) ) { @@ -32,103 +40,29 @@ private static function find_subcommand( $args ) { return $command; } - private function show( $args ) { - if ( self::maybe_show_manpage( $args ) ) { - exit; - } - - $command = self::find_subcommand( $args ); - - if ( $command ) { - $command->show_usage(); - exit; - } - } - - private function generate( $args ) { - if ( '' === exec( 'which ronn' ) ) { - WP_CLI::error( '`ronn` executable not found.' ); - } - - $command = self::find_subcommand( $args ); - - if ( $command ) { - foreach ( WP_CLI::get_man_dirs() as $dest_dir => $src_dir ) { - self::_generate( $src_dir, $dest_dir, $command ); - } - exit; - } - } - - private static function maybe_show_manpage( $args ) { - $man_file = self::get_file_name( $args ); - - foreach ( \WP_CLI::get_man_dirs() as $dest_dir => $_ ) { - $man_path = "$dest_dir/" . $man_file; - - if ( is_readable( $man_path ) ) { - \WP_CLI::launch( "man $man_path" ); - return true; - } - } - - return false; - } - - private static function _generate( $src_dir, $dest_dir, $command ) { + private static function find_extra_markdown( $command ) { $cmd_path = Dispatcher\get_path( $command ); array_shift( $cmd_path ); // discard 'wp' + $cmd_path = implode( '-', $cmd_path ); - $src_path = "$src_dir/" . self::get_src_file_name( $cmd_path ); - $dest_path = "$dest_dir/" . self::get_file_name( $cmd_path ); - - self::call_ronn( self::get_markdown( $src_path, $command ), $dest_path ); - - if ( $command->has_subcommands() ) { - foreach ( $command->get_subcommands() as $subcommand ) { - self::_generate( $src_dir, $dest_dir, $subcommand ); - } + foreach ( WP_CLI::get_man_dirs() as $src_dir ) { + $src_path = "$src_dir/$cmd_path.txt"; + if ( is_readable( $src_path ) ) + return $src_path; } - } - - // returns a file descriptor or false - private static function get_markdown( $doc_path, $command ) { - if ( !file_exists( $doc_path ) ) - return false; - - $fd = fopen( "php://temp", "rw" ); - - self::add_initial_markdown( $fd, $command ); - fwrite( $fd, file_get_contents( $doc_path ) ); - - if ( 0 === ftell( $fd ) ) - return false; - - fseek( $fd, 0 ); - - return $fd; + return false; } - private static function add_initial_markdown( $fd, $command ) { - $path = Dispatcher\get_path( $command ); + private static function add_initial_markdown( $command ) { + $name = implode( ' ', Dispatcher\get_path( $command ) ); $binding = array( - 'name_m' => implode( '-', $path ), + 'name' => $name, 'shortdesc' => $command->get_shortdesc(), ); - $synopsis = Dispatcher\get_full_synopsis( $command, true ); - - $synopsis = str_replace( '_', '\_', $synopsis ); - $synopsis = str_replace( array( '<', '>' ), '_', $synopsis ); - - $binding['synopsis'] = $synopsis; - - if ( !$binding['shortdesc'] ) { - $name_s = implode( ' ', $path ); - \WP_CLI::warning( "No shortdesc for $name_s" ); - } + $binding['synopsis'] = "$name " . $command->get_synopsis(); if ( $command->has_subcommands() ) { foreach ( $command->get_subcommands() as $subcommand ) { @@ -139,36 +73,7 @@ private static function add_initial_markdown( $fd, $command ) { } } - fwrite( $fd, Utils\mustache_render( 'man.mustache', $binding ) ); - } - - private static function call_ronn( $markdown, $dest ) { - if ( !$markdown ) - return; - - $descriptorspec = array( - 0 => $markdown, - 1 => array( 'file', $dest, 'w' ), - 2 => STDERR - ); - - $cmd = "ronn --date=2012-01-01 --roff --manual='WP-CLI'"; - - $r = proc_close( proc_open( $cmd, $descriptorspec, $pipes ) ); - - $roff = file_get_contents( $dest ); - $roff = str_replace( ' "January 2012"', '', $roff ); - file_put_contents( $dest, $roff ); - - \WP_CLI::log( "generated " . basename( $dest ) ); - } - - private static function get_file_name( $args ) { - return implode( '-', $args ) . '.1'; - } - - private static function get_src_file_name( $args ) { - return implode( '-', $args ) . '.txt'; + echo Utils\mustache_render( 'man.mustache', $binding ); } } diff --git a/php/dispatcher.php b/php/dispatcher.php index 45903834f..8157d21b6 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -12,31 +12,3 @@ function get_path( $command ) { return $path; } -function get_full_synopsis( $command, $validate = false ) { - $subcommands = $command->get_subcommands(); - - if ( empty( $subcommands ) ) { - $synopsis = $command->get_synopsis(); - - if ( $validate ) { - $tokens = \WP_CLI\SynopsisParser::parse( $synopsis ); - - foreach ( $tokens as $token ) { - if ( 'unknown' == $token['type'] ) { - \WP_CLI::warning( sprintf( - "Invalid token '%s' in synopsis for '%s'", - $token['token'], $full_name - ) ); - } - } - } - - $full_name = implode( ' ', get_path( $command ) ); - - return "$full_name $synopsis"; - } else { - return implode( "\n\n", array_map( __FUNCTION__, - $subcommands ) ); - } -} - diff --git a/templates/man.mustache b/templates/man.mustache index 61a99bcfc..0c9aafb1e 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -1,17 +1,20 @@ -{{name_m}}(1) -- {{shortdesc}} -==== +## NAME + + {{{name}}} + +## DESCRIPTION + + {{{shortdesc}}} ## SYNOPSIS -{{synopsis}} + {{{synopsis}}} {{#has-subcommands}} ## SUBCOMMANDS {{#subcommands}} -* `{{name}}`: - - {{desc}} + * `{{name}}`: {{desc}} {{/subcommands}} {{/has-subcommands}} From d7a46f010ba954c11be3373c27808fc7c853abeb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 13:53:53 +0300 Subject: [PATCH 1878/5359] make help headings bright --- php/commands/help.php | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 03ac39082..00881a0fb 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -14,13 +14,7 @@ function __invoke( $args, $assoc_args ) { $command = self::find_subcommand( $args ); if ( $command ) { - self::add_initial_markdown( $command ); - - $extra_markdown_path = self::find_extra_markdown( $command ); - if ( $extra_markdown_path ) { - echo file_get_contents( $extra_markdown_path ); - } - + self::show_help( $command ); exit; } @@ -40,6 +34,20 @@ private static function find_subcommand( $args ) { return $command; } + private static function show_help( $command ) { + $out = self::get_initial_markdown( $command ); + + $extra_markdown_path = self::find_extra_markdown( $command ); + if ( $extra_markdown_path ) { + $out .= file_get_contents( $extra_markdown_path ); + } + + $out = str_replace( "\t", ' ', $out ); + $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); + + echo WP_CLI::colorize( $out ); + } + private static function find_extra_markdown( $command ) { $cmd_path = Dispatcher\get_path( $command ); array_shift( $cmd_path ); // discard 'wp' @@ -54,7 +62,7 @@ private static function find_extra_markdown( $command ) { return false; } - private static function add_initial_markdown( $command ) { + private static function get_initial_markdown( $command ) { $name = implode( ' ', Dispatcher\get_path( $command ) ); $binding = array( @@ -73,7 +81,7 @@ private static function add_initial_markdown( $command ) { } } - echo Utils\mustache_render( 'man.mustache', $binding ); + return Utils\mustache_render( 'man.mustache', $binding ); } } From b57796b31115895f5711bf1a2e554cb2ee056ff3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 14:10:25 +0300 Subject: [PATCH 1879/5359] prettify subcommand listing --- php/commands/help.php | 34 ++++++++++++++++++++++++++++------ templates/man.mustache | 4 ++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 00881a0fb..af9941c29 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -73,16 +73,38 @@ private static function get_initial_markdown( $command ) { $binding['synopsis'] = "$name " . $command->get_synopsis(); if ( $command->has_subcommands() ) { - foreach ( $command->get_subcommands() as $subcommand ) { - $binding['has-subcommands']['subcommands'][] = array( - 'name' => $subcommand->get_name(), - 'desc' => $subcommand->get_shortdesc(), - ); - } + $binding['has-subcommands']['subcommands'] = self::render_subcommands( $command ); } return Utils\mustache_render( 'man.mustache', $binding ); } + + private static function render_subcommands( $command ) { + $subcommands = array(); + foreach ( $command->get_subcommands() as $subcommand ) { + $subcommands[ $subcommand->get_name() ] = $subcommand->get_shortdesc(); + } + + $max_len = self::get_max_len( array_keys( $subcommands ) ); + + $lines = array(); + foreach ( $subcommands as $name => $desc ) { + $lines[] = str_pad( $name, $max_len ) . "\t\t\t" . $desc; + } + + return $lines; + } + + private static function get_max_len( $strings ) { + $max_len = 0; + foreach ( $strings as $str ) { + $len = strlen( $str ); + if ( $len > $max_len ) + $max_len = $len; + } + + return $max_len; + } } WP_CLI::add_command( 'help', 'Help_Command' ); diff --git a/templates/man.mustache b/templates/man.mustache index 0c9aafb1e..6767c83d8 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -14,7 +14,7 @@ ## SUBCOMMANDS {{#subcommands}} - * `{{name}}`: {{desc}} - + {{{.}}} {{/subcommands}} + {{/has-subcommands}} From 7ca41b2f12b8c83f3f826ad394062a84f935e5c6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 23 Jun 2013 14:39:51 +0300 Subject: [PATCH 1880/5359] partial cleanup of option listing --- php/commands/help.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index af9941c29..c1cf96b2a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -42,8 +42,9 @@ private static function show_help( $command ) { $out .= file_get_contents( $extra_markdown_path ); } + $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); // section headers + $out = preg_replace( '/^\* `([^`]+)`/m', '\1', $out ); // options $out = str_replace( "\t", ' ', $out ); - $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); echo WP_CLI::colorize( $out ); } From 3b4efe3a967bc2f1f6f2d63b01c128736d583b50 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Mon, 24 Jun 2013 11:02:49 +0000 Subject: [PATCH 1881/5359] Clarity the `site empty` command doesn't do anything to the options table or users. --- man/site-empty.1 | 2 +- php/commands/site.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/site-empty.1 b/man/site-empty.1 index 144391fba..1c0b067d0 100644 --- a/man/site-empty.1 +++ b/man/site-empty.1 @@ -4,7 +4,7 @@ .TH "WP\-SITE\-EMPTY" "1" "" "WP-CLI" . .SH "NAME" -\fBwp\-site\-empty\fR \- Empty a site of its content\. +\fBwp\-site\-empty\fR \- Empty a site of its content (posts, comments, and terms)\. . .SH "SYNOPSIS" wp site empty [\-\-yes] diff --git a/php/commands/site.php b/php/commands/site.php index 5f548284c..c027cf495 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -108,14 +108,14 @@ private function _insert_default_terms() { } /** - * Empty a site of its content. + * Empty a site of its content (posts, comments, and terms). * * @subcommand empty * @synopsis [--yes] */ public function _empty( $args, $assoc_args ) { - WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . '?', $assoc_args ); + WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . ' of all posts, comments, and terms?', $assoc_args ); $this->_empty_posts(); $this->_empty_comments(); From 2d6344c1ab0095d6cfbe00a2cee5debd481a6fa0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Mon, 24 Jun 2013 11:06:09 +0000 Subject: [PATCH 1882/5359] Manual for the `--yes` prompt --- man-src/site-empty.txt | 8 +++++++- man/site-empty.1 | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/man-src/site-empty.txt b/man-src/site-empty.txt index 80db5732c..b97477a0f 100644 --- a/man-src/site-empty.txt +++ b/man-src/site-empty.txt @@ -1,3 +1,9 @@ ## EXAMPLES - wp blog empty \ No newline at end of file + wp blog empty + +## OPTIONS + +* `--yes`: + + Proceed to empty the site without a confirmation prompt. \ No newline at end of file diff --git a/man/site-empty.1 b/man/site-empty.1 index 1c0b067d0..f1de33d86 100644 --- a/man/site-empty.1 +++ b/man/site-empty.1 @@ -16,4 +16,12 @@ wp site empty [\-\-yes] wp blog empty . .fi +. +.SH "OPTIONS" +. +.TP +\fB\-\-yes\fR: +. +.IP +Proceed to empty the site without a confirmation prompt\. From 8c649489ad68f889068e471bbe961b0703a62424 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Mon, 24 Jun 2013 11:07:04 +0000 Subject: [PATCH 1883/5359] Fix reference to command --- man-src/site-empty.txt | 2 +- man/site-empty.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man-src/site-empty.txt b/man-src/site-empty.txt index b97477a0f..0d9581531 100644 --- a/man-src/site-empty.txt +++ b/man-src/site-empty.txt @@ -1,6 +1,6 @@ ## EXAMPLES - wp blog empty + wp site empty ## OPTIONS diff --git a/man/site-empty.1 b/man/site-empty.1 index f1de33d86..6ce47ca00 100644 --- a/man/site-empty.1 +++ b/man/site-empty.1 @@ -13,7 +13,7 @@ wp site empty [\-\-yes] . .nf -wp blog empty +wp site empty . .fi . From 2ab4b4fae31a7874d62f5dd418467760e6f7f574 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Mon, 24 Jun 2013 11:16:58 +0000 Subject: [PATCH 1884/5359] Drop the example entirely. Basic usage is covered in the synopsis --- man-src/site-empty.txt | 4 ---- man/site-empty.1 | 8 -------- 2 files changed, 12 deletions(-) diff --git a/man-src/site-empty.txt b/man-src/site-empty.txt index 0d9581531..bbb41c593 100644 --- a/man-src/site-empty.txt +++ b/man-src/site-empty.txt @@ -1,7 +1,3 @@ -## EXAMPLES - - wp site empty - ## OPTIONS * `--yes`: diff --git a/man/site-empty.1 b/man/site-empty.1 index 6ce47ca00..0a15512db 100644 --- a/man/site-empty.1 +++ b/man/site-empty.1 @@ -9,14 +9,6 @@ .SH "SYNOPSIS" wp site empty [\-\-yes] . -.SH "EXAMPLES" -. -.nf - -wp site empty -. -.fi -. .SH "OPTIONS" . .TP From 1a486b2412705e30195bdf3da3e1a190638c327b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 15:00:25 +0300 Subject: [PATCH 1885/5359] more cleanup of option listing --- php/commands/help.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index c1cf96b2a..5e0b1b669 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -37,19 +37,28 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); - $extra_markdown_path = self::find_extra_markdown( $command ); - if ( $extra_markdown_path ) { - $out .= file_get_contents( $extra_markdown_path ); - } + $out .= self::get_extra_markdown( $command ); + + // section headers + $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); + + // old-style options + $out = preg_replace( '/\* `(.+)`([^\n]*):\n\n/', "\\1\\2\n\t", $out ); - $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); // section headers - $out = preg_replace( '/^\* `([^`]+)`/m', '\1', $out ); // options $out = str_replace( "\t", ' ', $out ); echo WP_CLI::colorize( $out ); } - private static function find_extra_markdown( $command ) { + private static function get_extra_markdown( $command ) { + $md_file = self::find_extra_markdown_file( $command ); + if ( !$md_file ) + return ''; + + return file_get_contents( $md_file ); + } + + private static function find_extra_markdown_file( $command ) { $cmd_path = Dispatcher\get_path( $command ); array_shift( $cmd_path ); // discard 'wp' $cmd_path = implode( '-', $cmd_path ); From 2c6be8fc7e99af415061e37108d6b0a7f8bdffed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 15:23:42 +0300 Subject: [PATCH 1886/5359] fix indentation for options --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 5e0b1b669..af94415ca 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -43,7 +43,7 @@ private static function show_help( $command ) { $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); // old-style options - $out = preg_replace( '/\* `(.+)`([^\n]*):\n\n/', "\\1\\2\n\t", $out ); + $out = preg_replace( '/\n\* `(.+)`([^\n]*):\n\n/', "\n\t\\1\\2\n\t\t", $out ); $out = str_replace( "\t", ' ', $out ); From ac7a6df4bfe25cdec3cdc55a7c8c5a73786f0488 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 16:20:34 +0300 Subject: [PATCH 1887/5359] Make `wp` show the same output as `wp help`. --- php/WP_CLI/Dispatcher/CompositeCommand.php | 22 +++++++++ php/WP_CLI/Dispatcher/RootCommand.php | 56 +++++----------------- php/WP_CLI/Runner.php | 6 ++- php/commands/help.php | 26 +--------- templates/man-params.mustache | 8 ++++ 5 files changed, 48 insertions(+), 70 deletions(-) create mode 100644 templates/man-params.mustache diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 8a527fa09..90dc7fe1b 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -73,6 +73,28 @@ function show_usage() { \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); } + function get_extra_markdown() { + $md_file = self::find_extra_markdown_file( $this ); + if ( !$md_file ) + return ''; + + return file_get_contents( $md_file ); + } + + private static function find_extra_markdown_file( $command ) { + $cmd_path = get_path( $command ); + array_shift( $cmd_path ); // discard 'wp' + $cmd_path = implode( '-', $cmd_path ); + + foreach ( \WP_CLI::get_man_dirs() as $src_dir ) { + $src_path = "$src_dir/$cmd_path.txt"; + if ( is_readable( $src_path ) ) + return $src_path; + } + + return false; + } + function find_subcommand( &$args ) { $name = array_shift( $args ); diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 03bc8196d..afae68221 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -14,38 +14,11 @@ function __construct() { $this->name = 'wp'; - $this->shortdesc = ''; - $this->synopsis = ''; + $this->shortdesc = 'Manage WordPress installations through the command-line.'; } - function show_usage() { - \WP_CLI::line( 'Available commands:' ); - - foreach ( $this->get_subcommands() as $command ) { - if ( '_sys' == $command->get_name() ) - continue; - - \WP_CLI::line( sprintf( ' %s %s', - implode( ' ', get_path( $command ) ), - implode( '|', array_keys( $command->get_subcommands() ) ) - ) ); - } - - \WP_CLI::line(<<<EOB - -See 'wp help <command>' for more information on a specific command. - -Global parameters: -EOB - ); - - self::show_synopsis(); - } - - private static function show_synopsis() { - $max_len = 0; - - $lines = array(); + function get_extra_markdown() { + $binding = array(); foreach ( \WP_CLI::$configurator->get_spec() as $key => $details ) { if ( false === $details['runtime'] ) @@ -54,23 +27,18 @@ private static function show_synopsis() { if ( isset( $details['deprecated'] ) ) continue; - $synopsis = ( true === $details['runtime'] ) - ? "--[no-]$key" - : "--$key" . $details['runtime']; - - $cur_len = strlen( $synopsis ); + if ( true === $details['runtime'] ) + $synopsis = "--[no-]$key"; + else + $synopsis = "--$key" . $details['runtime']; - if ( $max_len < $cur_len ) - $max_len = $cur_len; - - $lines[] = array( $synopsis, $details['desc'] ); + $binding['parameters'][] = array( + 'synopsis' => $synopsis, + 'desc' => $details['desc'] + ); } - foreach ( $lines as $line ) { - list( $synopsis, $desc ) = $line; - - \WP_CLI::line( sprintf( ' %s %s', str_pad( $synopsis, $max_len ), $desc ) ); - } + return Utils\mustache_render( 'man-params.mustache', $binding ); } function find_subcommand( &$args ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index d48455865..17426a035 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -299,8 +299,10 @@ public function before_wp_load() { $this->init_colorization(); $this->init_logger(); - if ( !empty( $this->arguments ) ) - Utils\load_command( $this->arguments[0] ); + if ( empty( $this->arguments ) ) + $this->arguments[] = 'help'; + + Utils\load_command( $this->arguments[0] ); if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { diff --git a/php/commands/help.php b/php/commands/help.php index af94415ca..d1b2cc945 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -37,10 +37,10 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); - $out .= self::get_extra_markdown( $command ); + $out .= $command->get_extra_markdown(); // section headers - $out = preg_replace( '/^## ([A-Z]+)/m', '%9\1%n', $out ); + $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); // old-style options $out = preg_replace( '/\n\* `(.+)`([^\n]*):\n\n/', "\n\t\\1\\2\n\t\t", $out ); @@ -50,28 +50,6 @@ private static function show_help( $command ) { echo WP_CLI::colorize( $out ); } - private static function get_extra_markdown( $command ) { - $md_file = self::find_extra_markdown_file( $command ); - if ( !$md_file ) - return ''; - - return file_get_contents( $md_file ); - } - - private static function find_extra_markdown_file( $command ) { - $cmd_path = Dispatcher\get_path( $command ); - array_shift( $cmd_path ); // discard 'wp' - $cmd_path = implode( '-', $cmd_path ); - - foreach ( WP_CLI::get_man_dirs() as $src_dir ) { - $src_path = "$src_dir/$cmd_path.txt"; - if ( is_readable( $src_path ) ) - return $src_path; - } - - return false; - } - private static function get_initial_markdown( $command ) { $name = implode( ' ', Dispatcher\get_path( $command ) ); diff --git a/templates/man-params.mustache b/templates/man-params.mustache new file mode 100644 index 000000000..2d3383f57 --- /dev/null +++ b/templates/man-params.mustache @@ -0,0 +1,8 @@ +## GLOBAL PARAMETERS + +{{#parameters}} + {{{synopsis}}} + {{desc}} + +{{/parameters}} +Run 'wp help <subcommand>' to get more information on a specific command. From 1c08d00c41b4ca3952079566d764fb0d78c1445c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 16:40:27 +0300 Subject: [PATCH 1888/5359] rename '_sys' to 'cli' --- php/WP_CLI/Runner.php | 4 ++-- php/commands/{_sys.php => cli.php} | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) rename php/commands/{_sys.php => cli.php} (90%) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 17426a035..87fee0012 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -231,11 +231,11 @@ private static function back_compat_conversions( $args, $assoc_args ) { unset( $assoc_args['json'] ); } - // --{version|info} -> _sys {version|info} + // --{version|info} -> cli {version|info} if ( empty( $args ) ) { foreach ( array( 'version', 'info' ) as $key ) { if ( isset( $assoc_args[ $key ] ) ) { - $args = array( '_sys', $key ); + $args = array( 'cli', $key ); break; } } diff --git a/php/commands/_sys.php b/php/commands/cli.php similarity index 90% rename from php/commands/_sys.php rename to php/commands/cli.php index fefbc2231..b371c2314 100644 --- a/php/commands/_sys.php +++ b/php/commands/cli.php @@ -4,9 +4,11 @@ \WP_CLI\Utils; /** + * Get information about WP-CLI itself. + * * @when before_wp_load */ -class Sys_Command extends WP_CLI_Command { +class CLI_Command extends WP_CLI_Command { private function command_to_array( $command ) { $dump = array( @@ -55,5 +57,5 @@ function cmd_dump() { } } -WP_CLI::add_command( '_sys', 'Sys_Command' ); +WP_CLI::add_command( 'cli', 'CLI_Command' ); From 02a5a2db84488adbf177e9faf9b15396b8de5b53 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 16:50:54 +0300 Subject: [PATCH 1889/5359] ignore first parameter to WP_CLI::add_man_dir() --- php/class-wp-cli.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9f928a481..1c94a5872 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -22,10 +22,7 @@ class WP_CLI { * Initialize WP_CLI static variables. */ static function init() { - self::add_man_dir( - WP_CLI_ROOT . "/man", - WP_CLI_ROOT . "/man-src" - ); + self::add_man_dir( null, WP_CLI_ROOT . "/man-src" ); self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); self::$root = new Dispatcher\RootCommand; @@ -79,8 +76,8 @@ static function add_command( $name, $class ) { self::$root->add_subcommand( $name, $command ); } - static function add_man_dir( $dest_dir, $src_dir ) { - self::$man_dirs[ $dest_dir ] = $src_dir; + static function add_man_dir( $deprecated = null, $src_dir ) { + self::$man_dirs[] = $src_dir; } static function get_man_dirs() { From d5c3d652e8b3b6f608c6c61af872f0906381495a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 17:12:55 +0300 Subject: [PATCH 1890/5359] remove man/ dir --- man/cache.1 | 101 ------------------------------ man/cap.1 | 52 ---------------- man/comment-approve.1 | 27 -------- man/comment-count.1 | 28 --------- man/comment-create.1 | 35 ----------- man/comment-delete.1 | 33 ---------- man/comment-last.1 | 33 ---------- man/comment-spam.1 | 27 -------- man/comment-status.1 | 27 -------- man/comment-trash.1 | 27 -------- man/comment-unapprove.1 | 27 -------- man/comment-unspam.1 | 27 -------- man/comment-untrash.1 | 27 -------- man/core-config.1 | 64 ------------------- man/core-download.1 | 39 ------------ man/core-init-tests.1 | 45 -------------- man/core-install-network.1 | 31 ---------- man/core-install.1 | 43 ------------- man/core-is-installed.1 | 21 ------- man/core-update-db.1 | 10 --- man/core-update.1 | 37 ----------- man/core-version.1 | 19 ------ man/db.1 | 120 ------------------------------------ man/eval-file.1 | 19 ------ man/eval.1 | 19 ------ man/export.1 | 91 --------------------------- man/help.1 | 26 -------- man/media-import.1 | 72 ---------------------- man/media-regenerate.1 | 35 ----------- man/network-meta.1 | 69 --------------------- man/option.1 | 68 -------------------- man/plugin-activate.1 | 25 -------- man/plugin-deactivate.1 | 25 -------- man/plugin-delete.1 | 27 -------- man/plugin-install.1 | 43 ------------- man/plugin-list.1 | 21 ------- man/plugin-path.1 | 33 ---------- man/plugin-status.1 | 19 ------ man/plugin-toggle.1 | 25 -------- man/plugin-uninstall.1 | 33 ---------- man/plugin-update-all.1 | 27 -------- man/plugin-update.1 | 33 ---------- man/post-create.1 | 53 ---------------- man/post-delete.1 | 35 ----------- man/post-edit.1 | 27 -------- man/post-generate.1 | 57 ----------------- man/post-get.1 | 44 ------------- man/post-list.1 | 43 ------------- man/post-meta.1 | 62 ------------------- man/post-update.1 | 33 ---------- man/rewrite-dump.1 | 19 ------ man/rewrite-flush.1 | 19 ------ man/rewrite-structure.1 | 31 ---------- man/role-create.1 | 35 ----------- man/role-delete.1 | 29 --------- man/role-exists.1 | 30 --------- man/role-list.1 | 33 ---------- man/scaffold-_s.1 | 43 ------------- man/scaffold-child-theme.1 | 55 ----------------- man/scaffold-plugin-tests.1 | 39 ------------ man/scaffold-plugin.1 | 25 -------- man/scaffold-post-type.1 | 43 ------------- man/scaffold-taxonomy.1 | 57 ----------------- man/search-replace.1 | 47 -------------- man/shell.1 | 22 ------- man/site-create.1 | 49 --------------- man/site-delete.1 | 37 ----------- man/site-empty.1 | 19 ------ man/term-create.1 | 57 ----------------- man/term-delete.1 | 33 ---------- man/term-list.1 | 41 ------------ man/term-update.1 | 57 ----------------- man/theme-activate.1 | 19 ------ man/theme-delete.1 | 27 -------- man/theme-install.1 | 35 ----------- man/theme-list.1 | 21 ------- man/theme-path.1 | 33 ---------- man/theme-status.1 | 19 ------ man/theme-update-all.1 | 27 -------- man/theme-update.1 | 33 ---------- man/transient.1 | 54 ---------------- man/user-create.1 | 63 ------------------- man/user-delete.1 | 33 ---------- man/user-generate.1 | 25 -------- man/user-import-csv.1 | 34 ---------- man/user-list.1 | 43 ------------- man/user-meta.1 | 62 ------------------- man/user-remove-role.1 | 28 --------- man/user-set-role.1 | 34 ---------- man/user-update.1 | 33 ---------- 90 files changed, 3407 deletions(-) delete mode 100644 man/cache.1 delete mode 100644 man/cap.1 delete mode 100644 man/comment-approve.1 delete mode 100644 man/comment-count.1 delete mode 100644 man/comment-create.1 delete mode 100644 man/comment-delete.1 delete mode 100644 man/comment-last.1 delete mode 100644 man/comment-spam.1 delete mode 100644 man/comment-status.1 delete mode 100644 man/comment-trash.1 delete mode 100644 man/comment-unapprove.1 delete mode 100644 man/comment-unspam.1 delete mode 100644 man/comment-untrash.1 delete mode 100644 man/core-config.1 delete mode 100644 man/core-download.1 delete mode 100644 man/core-init-tests.1 delete mode 100644 man/core-install-network.1 delete mode 100644 man/core-install.1 delete mode 100644 man/core-is-installed.1 delete mode 100644 man/core-update-db.1 delete mode 100644 man/core-update.1 delete mode 100644 man/core-version.1 delete mode 100644 man/db.1 delete mode 100644 man/eval-file.1 delete mode 100644 man/eval.1 delete mode 100644 man/export.1 delete mode 100644 man/help.1 delete mode 100644 man/media-import.1 delete mode 100644 man/media-regenerate.1 delete mode 100644 man/network-meta.1 delete mode 100644 man/option.1 delete mode 100644 man/plugin-activate.1 delete mode 100644 man/plugin-deactivate.1 delete mode 100644 man/plugin-delete.1 delete mode 100644 man/plugin-install.1 delete mode 100644 man/plugin-list.1 delete mode 100644 man/plugin-path.1 delete mode 100644 man/plugin-status.1 delete mode 100644 man/plugin-toggle.1 delete mode 100644 man/plugin-uninstall.1 delete mode 100644 man/plugin-update-all.1 delete mode 100644 man/plugin-update.1 delete mode 100644 man/post-create.1 delete mode 100644 man/post-delete.1 delete mode 100644 man/post-edit.1 delete mode 100644 man/post-generate.1 delete mode 100644 man/post-get.1 delete mode 100644 man/post-list.1 delete mode 100644 man/post-meta.1 delete mode 100644 man/post-update.1 delete mode 100644 man/rewrite-dump.1 delete mode 100644 man/rewrite-flush.1 delete mode 100644 man/rewrite-structure.1 delete mode 100644 man/role-create.1 delete mode 100644 man/role-delete.1 delete mode 100644 man/role-exists.1 delete mode 100644 man/role-list.1 delete mode 100644 man/scaffold-_s.1 delete mode 100644 man/scaffold-child-theme.1 delete mode 100644 man/scaffold-plugin-tests.1 delete mode 100644 man/scaffold-plugin.1 delete mode 100644 man/scaffold-post-type.1 delete mode 100644 man/scaffold-taxonomy.1 delete mode 100644 man/search-replace.1 delete mode 100644 man/shell.1 delete mode 100644 man/site-create.1 delete mode 100644 man/site-delete.1 delete mode 100644 man/site-empty.1 delete mode 100644 man/term-create.1 delete mode 100644 man/term-delete.1 delete mode 100644 man/term-list.1 delete mode 100644 man/term-update.1 delete mode 100644 man/theme-activate.1 delete mode 100644 man/theme-delete.1 delete mode 100644 man/theme-install.1 delete mode 100644 man/theme-list.1 delete mode 100644 man/theme-path.1 delete mode 100644 man/theme-status.1 delete mode 100644 man/theme-update-all.1 delete mode 100644 man/theme-update.1 delete mode 100644 man/transient.1 delete mode 100644 man/user-create.1 delete mode 100644 man/user-delete.1 delete mode 100644 man/user-generate.1 delete mode 100644 man/user-import-csv.1 delete mode 100644 man/user-list.1 delete mode 100644 man/user-meta.1 delete mode 100644 man/user-remove-role.1 delete mode 100644 man/user-set-role.1 delete mode 100644 man/user-update.1 diff --git a/man/cache.1 b/man/cache.1 deleted file mode 100644 index 7587a2a94..000000000 --- a/man/cache.1 +++ /dev/null @@ -1,101 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CACHE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cache\fR \- Manage the object cache\. -. -.SH "SYNOPSIS" -wp cache add \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] -. -.P -wp cache decr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] -. -.P -wp cache delete \fIkey\fR [\fIgroup\fR] -. -.P -wp cache flush -. -.P -wp cache get \fIkey\fR [\fIgroup\fR] -. -.P -wp cache incr \fIkey\fR [\fIoffset\fR] [\fIgroup\fR] -. -.P -wp cache replace \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] -. -.P -wp cache set \fIkey\fR \fIvalue\fR [\fIgroup\fR] [\fIexpiration\fR] -. -.P -wp cache type -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add a value to the object cache\. -. -.TP -\fBdecr\fR: -. -.IP -Decrement a value in the object cache\. -. -.TP -\fBdelete\fR: -. -.IP -Remove a value from the object cache\. -. -.TP -\fBflush\fR: -. -.IP -Flush the object cache\. -. -.TP -\fBget\fR: -. -.IP -Get a value from the object cache\. -. -.TP -\fBincr\fR: -. -.IP -Increment a value in the object cache\. -. -.TP -\fBreplace\fR: -. -.IP -Replace an existing value in the object cache\. -. -.TP -\fBset\fR: -. -.IP -Set a value to the object cache\. -. -.TP -\fBtype\fR: -. -.IP -Attempts to determine which object cache is being used\. -. -.SH "EXAMPLES" -. -.nf - -wp cache set my_key my_value my_group 300 - -wp cache get my_key my_group -. -.fi - diff --git a/man/cap.1 b/man/cap.1 deleted file mode 100644 index fd4b8f669..000000000 --- a/man/cap.1 +++ /dev/null @@ -1,52 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CAP" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-cap\fR \- Manage user capabilities\. -. -.SH "SYNOPSIS" -wp cap add \fIrole\fR \fIcap\fR\.\.\. -. -.P -wp cap list \fIrole\fR -. -.P -wp cap remove \fIrole\fR \fIcap\fR\.\.\. -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add capabilities to a given role\. -. -.TP -\fBlist\fR: -. -.IP -List capabilities for a given role\. -. -.TP -\fBremove\fR: -. -.IP -Remove capabilities from a given role\. -. -.SH "EXAMPLES" -. -.nf - -# Add \'spectate\' capability to \'author\' role -wp cap add \'author\' \'spectate\' - -# Add all caps from \'editor\' role to \'author\' role -wp cap list \'editor\' | xargs wp cap add \'author\' - -# Remove all caps from \'editor\' role that also appear in \'author\' role -wp cap list \'author\' | xargs wp cap remove \'editor\' -. -.fi - diff --git a/man/comment-approve.1 b/man/comment-approve.1 deleted file mode 100644 index 759498b75..000000000 --- a/man/comment-approve.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-APPROVE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-approve\fR \- Approve a comment\. -. -.SH "SYNOPSIS" -wp comment approve \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to approve\. -. -.SH "EXAMPLES" -. -.nf - -wp comment approve 1337 -. -.fi - diff --git a/man/comment-count.1 b/man/comment-count.1 deleted file mode 100644 index 4cb5c913b..000000000 --- a/man/comment-count.1 +++ /dev/null @@ -1,28 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-COUNT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-count\fR \- Count comments, on whole blog or on a given post\. -. -.SH "SYNOPSIS" -wp comment count [\fIpost\-id\fR] -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the post to count comments in -. -.SH "EXAMPLES" -. -.nf - -wp comment count -wp comment count 42 -. -.fi - diff --git a/man/comment-create.1 b/man/comment-create.1 deleted file mode 100644 index 8ca70f0ce..000000000 --- a/man/comment-create.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-create\fR \- Insert a comment\. -. -.SH "SYNOPSIS" -wp comment create \-\-\fIfield\fR=\fIvalue\fR [\-\-porcelain] -. -.SH "OPTIONS" -. -.TP -\fB\-\-<field>\fR=\fIvalue\fR: -. -.IP -Field values for the new comment\. See wp_insert_comment()\. -. -.TP -\fB\-\-porcelain\fR: -. -.IP -Output just the new comment id\. -. -.SH "EXAMPLES" -. -.nf - -wp comment create \-\-comment_post_ID=15 \-\-comment_content="hello blog" -. -.fi -. -.P -\-\-comment_author="wp\-cli" diff --git a/man/comment-delete.1 b/man/comment-delete.1 deleted file mode 100644 index fe9567b79..000000000 --- a/man/comment-delete.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-delete\fR \- Delete a comment\. -. -.SH "SYNOPSIS" -wp comment delete \fIid\fR [\-\-force] -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to delete\. -. -.TP -\fB\-\-force\fR: -. -.IP -Skip the trash bin\. -. -.SH "EXAMPLES" -. -.nf - -wp comment delete 1337 \-\-force -. -.fi - diff --git a/man/comment-last.1 b/man/comment-last.1 deleted file mode 100644 index 47b760f83..000000000 --- a/man/comment-last.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-LAST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-last\fR \- Get last approved comment\. -. -.SH "SYNOPSIS" -wp comment last [\-\-id] [\-\-full] -. -.SH "OPTIONS" -. -.TP -\fB\-\-id\fR: -. -.IP -Output just the last comment id\. -. -.TP -\fB\-\-full\fR: -. -.IP -Output complete comment information\. -. -.SH "EXAMPLES" -. -.nf - -wp comment last \-\-full -. -.fi - diff --git a/man/comment-spam.1 b/man/comment-spam.1 deleted file mode 100644 index 1f0732178..000000000 --- a/man/comment-spam.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-SPAM" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-spam\fR \- Spam a comment\. -. -.SH "SYNOPSIS" -wp comment spam \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to mark as spam\. -. -.SH "EXAMPLES" -. -.nf - -wp comment spam 1337 -. -.fi - diff --git a/man/comment-status.1 b/man/comment-status.1 deleted file mode 100644 index 70c4ddd4e..000000000 --- a/man/comment-status.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-STATUS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-status\fR \- Get status of a comment\. -. -.SH "SYNOPSIS" -wp comment status \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to check -. -.SH "EXAMPLES" -. -.nf - -wp comment status 1337 -. -.fi - diff --git a/man/comment-trash.1 b/man/comment-trash.1 deleted file mode 100644 index 2deba83ba..000000000 --- a/man/comment-trash.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-TRASH" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-trash\fR \- Trash a comment\. -. -.SH "SYNOPSIS" -wp comment trash \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to trash\. -. -.SH "EXAMPLES" -. -.nf - -wp comment trash 1337 -. -.fi - diff --git a/man/comment-unapprove.1 b/man/comment-unapprove.1 deleted file mode 100644 index e6d18d043..000000000 --- a/man/comment-unapprove.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-UNAPPROVE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-unapprove\fR \- Unapprove a comment\. -. -.SH "SYNOPSIS" -wp comment unapprove \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to unapprove\. -. -.SH "EXAMPLES" -. -.nf - -wp comment unapprove 1337 -. -.fi - diff --git a/man/comment-unspam.1 b/man/comment-unspam.1 deleted file mode 100644 index 41d7dd87f..000000000 --- a/man/comment-unspam.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-UNSPAM" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-unspam\fR \- Unspam a comment\. -. -.SH "SYNOPSIS" -wp comment unspam \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to unmark as spam\. -. -.SH "EXAMPLES" -. -.nf - -wp comment unspam 1337 -. -.fi - diff --git a/man/comment-untrash.1 b/man/comment-untrash.1 deleted file mode 100644 index ca2caa724..000000000 --- a/man/comment-untrash.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-COMMENT\-UNTRASH" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-comment\-untrash\fR \- Untrash a comment\. -. -.SH "SYNOPSIS" -wp comment untrash \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the comment to untrash\. -. -.SH "EXAMPLES" -. -.nf - -wp comment untrash 1337 -. -.fi - diff --git a/man/core-config.1 b/man/core-config.1 deleted file mode 100644 index 4a8d6e8d9..000000000 --- a/man/core-config.1 +++ /dev/null @@ -1,64 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-CONFIG" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-config\fR \- Set up a wp\-config\.php file\. -. -.SH "SYNOPSIS" -wp core config \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] [\-\-dbhost=\fIhost\fR] [\-\-dbprefix=\fIprefix\fR] [\-\-extra\-php] -. -.SH "OPTIONS" -. -.TP -\fB\-\-dbname\fR=\fIdbname\fR: -. -.IP -Set the database name\. -. -.TP -\fB\-\-dbuser\fR=\fIdbuser\fR: -. -.IP -Set the database user\. -. -.TP -\fB\-\-dbpass\fR=\fIdbpass\fR: -. -.IP -Set the database user password\. -. -.TP -\fB\-\-dbhost\fR=\fIdbhost\fR: -. -.IP -Set the database host\. Default: \'localhost\' -. -.TP -\fB\-\-dbprefix\fR=\fIdbprefix\fR: -. -.IP -Set the database table prefix\. Default: \'wp_\' -. -.TP -\fB\-\-extra\-php\fR: -. -.IP -If set, the command reads additional PHP code from STDIN\. -. -.SH "EXAMPLES" -. -.nf - -# Standard wp\-config\.php file -wp core config \-\-dbname=testing \-\-dbuser=wp \-\-dbpass=securepswd - -# Enable WP_DEBUG and WP_DEBUG_LOG -wp core config \-\-dbname=testing \-\-dbuser=wp \-\-dbpass=securepswd \-\-extra\-php <<PHP -define( \'WP_DEBUG\', true ); -define( \'WP_DEBUG_LOG\', true ); -PHP -. -.fi - diff --git a/man/core-download.1 b/man/core-download.1 deleted file mode 100644 index 7f607ca28..000000000 --- a/man/core-download.1 +++ /dev/null @@ -1,39 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-DOWNLOAD" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-download\fR \- Download core WordPress files\. -. -.SH "SYNOPSIS" -wp core download [\-\-locale=\fIlocale\fR] [\-\-version=\fIversion\fR] [\-\-path=\fIpath\fR] [\-\-force] -. -.SH "OPTIONS" -. -.TP -\fB\-\-locale\fR=\fIlocale\fR: -. -.IP -Select which language you want to download\. The \-\-version parameter is ignored in this case\. -. -.TP -\fB\-\-version\fR=\fIversion\fR: -. -.IP -Select which version you want to download\. -. -.TP -\fB\-\-force\fR: -. -.IP -Overwrites existing files, if present\. -. -.SH "EXAMPLES" -. -.nf - -wp core download \-\-version=3\.3 -. -.fi - diff --git a/man/core-init-tests.1 b/man/core-init-tests.1 deleted file mode 100644 index e5001c331..000000000 --- a/man/core-init-tests.1 +++ /dev/null @@ -1,45 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-INIT\-TESTS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-init\-tests\fR \- Set up the official test suite using the current WordPress instance\. -. -.SH "SYNOPSIS" -wp core init\-tests [\fIpath\fR] \-\-dbname=\fIname\fR \-\-dbuser=\fIuser\fR [\-\-dbpass=\fIpassword\fR] -. -.SH "OPTIONS" -. -.TP -\fB<path>\fR: -. -.IP -The directory in which to download the testing suite files\. (Optional) -. -.TP -\fB\-\-dbname\fR=\fIdbname\fR: -. -.IP -Set the database name\. \fBWARNING\fR: The database will be whipped every time you run the tests\. -. -.TP -\fB\-\-dbuser\fR=\fIdbuser\fR: -. -.IP -Set the database user\. -. -.TP -\fB\-\-dbpass\fR=\fIdbpass\fR: -. -.IP -Set the database user password\. -. -.SH "EXAMPLE" -. -.nf - -wp core init\-tests ~/svn/wp\-tests \-\-dbname=wp_test \-\-dbuser=wp_test -. -.fi - diff --git a/man/core-install-network.1 b/man/core-install-network.1 deleted file mode 100644 index 60fdbfc0e..000000000 --- a/man/core-install-network.1 +++ /dev/null @@ -1,31 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-INSTALL\-NETWORK" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-install\-network\fR \- Transform a single\-site install into a multi\-site install\. -. -.SH "SYNOPSIS" -wp core install\-network \-\-title=\fInetwork\-title\fR [\-\-base=\fIurl\-path\fR] [\-\-subdomains] -. -.SH "OPTIONS" -. -.TP -\fB\-\-title\fR=\fIsite\-title\fR: -. -.IP -The title of the new network\. -. -.TP -\fB\-\-base\fR=\fIurl\-path\fR: -. -.IP -Base path after the domain name that each site url will start with\. Default: \'/\' -. -.TP -\fB\-\-subdomains\fR: -. -.IP -If passed, the network will use subdomains, instead of subdirectories\. - diff --git a/man/core-install.1 b/man/core-install.1 deleted file mode 100644 index 866788629..000000000 --- a/man/core-install.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-INSTALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-install\fR \- Create the WordPress tables in the database\. -. -.SH "SYNOPSIS" -wp core install \-\-url=\fIurl\fR \-\-title=\fIsite\-title\fR [\-\-admin_name=\fIusername\fR] \-\-admin_email=\fIemail\fR \-\-admin_password=\fIpassword\fR -. -.SH "OPTIONS" -. -.TP -\fB\-\-url\fR=\fIurl\fR: -. -.IP -The address of the new site\. -. -.TP -\fB\-\-title\fR=\fIsite\-title\fR: -. -.IP -The title of the new site\. -. -.TP -\fB\-\-admin_name\fR=\fIusername\fR: -. -.IP -The name of the admin user\. Default: \'admin\' -. -.TP -\fB\-\-admin_password\fR=\fIpassword\fR: -. -.IP -The password for the admin user\. -. -.TP -\fB\-\-admin_email\fR=\fIemail\fR: -. -.IP -The email address for the admin user\. - diff --git a/man/core-is-installed.1 b/man/core-is-installed.1 deleted file mode 100644 index 56f61768b..000000000 --- a/man/core-is-installed.1 +++ /dev/null @@ -1,21 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-IS\-INSTALLED" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-is\-installed\fR \- Determine if the WordPress tables are installed\. -. -.SH "SYNOPSIS" -wp core is\-installed -. -.SH "EXAMPLES" -. -.nf - -if ! $(wp core is\-installed); then - wp core install -fi -. -.fi - diff --git a/man/core-update-db.1 b/man/core-update-db.1 deleted file mode 100644 index 1dd86294f..000000000 --- a/man/core-update-db.1 +++ /dev/null @@ -1,10 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-UPDATE\-DB" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-update\-db\fR \- Update the WordPress database\. -. -.SH "SYNOPSIS" -wp core update\-db diff --git a/man/core-update.1 b/man/core-update.1 deleted file mode 100644 index cb5848fb2..000000000 --- a/man/core-update.1 +++ /dev/null @@ -1,37 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-update\fR \- Update WordPress\. -. -.SH "SYNOPSIS" -wp core update [\fIzip\fR] [\-\-version=\fIversion\fR] [\-\-force] -. -.SH "OPTIONS" -. -.TP -\fB\-\-version=\fR\fInew_version\fR [package/zip]: -. -.IP -When passed, updates to new_version, optionally using package/zip as input\. -. -.TP -\fB\-\-force\fR: -. -.IP -Will update even when current WP version < passed version\. Use with caution\. -. -.SH "EXAMPLES" -. -.nf - -wp core update - -wp core update \-\-version=3\.4 \.\./latest\.zip - -wp core update \-\-version=3\.1 \-\-force -. -.fi - diff --git a/man/core-version.1 b/man/core-version.1 deleted file mode 100644 index c3a37f1c1..000000000 --- a/man/core-version.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-CORE\-VERSION" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-core\-version\fR \- Display the WordPress version\. -. -.SH "SYNOPSIS" -wp core version [\-\-extra] -. -.SH "OPTIONS" -. -.TP -\fB\-\-extra\fR: -. -.IP -Show extended version information\. - diff --git a/man/db.1 b/man/db.1 deleted file mode 100644 index 7524abedd..000000000 --- a/man/db.1 +++ /dev/null @@ -1,120 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-DB" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-db\fR \- Perform basic database operations\. -. -.SH "SYNOPSIS" -wp db cli -. -.P -wp db create -. -.P -wp db drop [\-\-yes] -. -.P -wp db export [\fIfile\fR] -. -.P -wp db import [\fIfile\fR] -. -.P -wp db optimize -. -.P -wp db query [\fIsql\fR] -. -.P -wp db repair -. -.P -wp db reset [\-\-yes] -. -.SH "SUBCOMMANDS" -. -.TP -\fBcli\fR: -. -.IP -Open a mysql console using the WordPress credentials\. -. -.TP -\fBcreate\fR: -. -.IP -Create the database, as specified in wp\-config\.php -. -.TP -\fBdrop\fR: -. -.IP -Delete the database\. -. -.TP -\fBexport\fR: -. -.IP -Exports the database using mysqldump\. -. -.TP -\fBimport\fR: -. -.IP -Import database from a file\. -. -.TP -\fBoptimize\fR: -. -.IP -Optimize the database\. -. -.TP -\fBquery\fR: -. -.IP -Execute a query against the database\. -. -.TP -\fBrepair\fR: -. -.IP -Repair the database\. -. -.TP -\fBreset\fR: -. -.IP -Remove all tables from the database\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-yes\fR: -. -.IP -Answer yes to the confirmation message\. -. -.TP -\fB<file>\fR: -. -.IP -The name of the export file\. If omitted, it will be \'{dbname}\.sql\' -. -.TP -\fB<SQL>\fR: -. -.IP -A SQL query\. -. -.SH "EXAMPLES" -. -.nf - -# execute a query stored in a file -wp db query < debug\.sql -. -.fi - diff --git a/man/eval-file.1 b/man/eval-file.1 deleted file mode 100644 index fc8fb2caf..000000000 --- a/man/eval-file.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-EVAL\-FILE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-eval\-file\fR \- Load and execute a PHP file after loading WordPress\. -. -.SH "SYNOPSIS" -wp eval\-file \fIpath\fR -. -.SH "EXAMPLES" -. -.nf - -wp eval\-file my\-code\.php -. -.fi - diff --git a/man/eval.1 b/man/eval.1 deleted file mode 100644 index 644451e32..000000000 --- a/man/eval.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-EVAL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-eval\fR \- Execute arbitrary PHP code after loading WordPress\. -. -.SH "SYNOPSIS" -wp eval \fIphp\-code\fR -. -.SH "EXAMPLES" -. -.nf - -wp eval \'echo WP_CONTENT_DIR;\' -. -.fi - diff --git a/man/export.1 b/man/export.1 deleted file mode 100644 index e4aaf633b..000000000 --- a/man/export.1 +++ /dev/null @@ -1,91 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-EXPORT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-export\fR \- Export content to a WXR file\. -. -.SH "SYNOPSIS" -wp export [\-\-dir=\fIdir\fR] [\-\-start_date=\fIdate\fR] [\-\-end_date=\fIdate\fR] [\-\-post_type=\fIptype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post__in=\fIpids\fR] [\-\-author=\fIlogin\fR] [\-\-category=\fIcat\fR] [\-\-skip_comments] [\-\-file_item_count=\fIcount\fR] [\-\-verbose] -. -.SH "OPTIONS" -. -.TP -\fB\-\-dir\fR=\fIdirname\fR: -. -.IP -Full path to directory where WXR export files should be stored\. Defaults to current working directory\. -. -.TP -\fB\-\-skip_comments\fR: -. -.IP -Don\'t export comments\. -. -.TP -\fB\-\-file_item_count\fR=\fIcount\fR: -. -.IP -Break export into files with N posts\. -. -.TP -\fB\-\-verbose\fR: -. -.IP -Show more information about the process on STDOUT\. -. -.SH "FILTERS" -. -.TP -\fB\-\-start_date\fR=\fIdate\fR: -. -.IP -Export only posts newer than this date, in format YYYY\-MM\-DD\. -. -.TP -\fB\-\-end_date\fR=\fIdate\fR: -. -.IP -Export only posts older than this date, in format YYYY\-MM\-DD\. -. -.TP -\fB\-\-post_type\fR=\fIpost_type\fR: -. -.IP -Export only posts with this post_type\. -. -.TP -\fB\-\-post__in\fR=\fIpid\fR: -. -.IP -Export all posts specified as a comma\-separated list of IDs\. -. -.TP -\fB\-\-author\fR=<login/id>: -. -.IP -Export only posts by this author\. -. -.TP -\fB\-\-category\fR=\fIcategory\-id\fR: -. -.IP -Export only posts in this category\. -. -.TP -\fB\-\-post_status\fR=\fIstatus\fR: -. -.IP -Export only posts with this status\. -. -.SH "EXAMPLES" -. -.nf - -wp export \-\-dir=/tmp/ \-\-user=admin \-\-post_type=post \-\-start_date=2011\-01\-01 \-\-end_date=2011\-12\-31 - -wp export \-\-dir=/tmp/ \-\-post__in=123,124,125 -. -.fi - diff --git a/man/help.1 b/man/help.1 deleted file mode 100644 index 9b707455e..000000000 --- a/man/help.1 +++ /dev/null @@ -1,26 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-HELP" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-help\fR \- Get help on a certain topic\. -. -.SH "SYNOPSIS" -wp help [\fIcommand\fR] [\-\-gen] -. -.SH "EXAMPLES" -. -.nf - -# (re)generates all man pages -wp help \-\-gen - -# (re)generate man pages for the `core` command -wp help \-\-gen core - -# (re)generate man page only for the `core download` subcommand -wp help \-\-gen core download -. -.fi - diff --git a/man/media-import.1 b/man/media-import.1 deleted file mode 100644 index 8ef92207d..000000000 --- a/man/media-import.1 +++ /dev/null @@ -1,72 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-MEDIA\-IMPORT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-media\-import\fR \- Create attachments from local files or from URLs\. -. -.SH "SYNOPSIS" -wp media import \fIfile\fR\.\.\. [\-\-post_id=\fIid\fR] [\-\-title=\fItitle\fR] [\-\-caption=\fIcaption\fR] [\-\-alt=\fItext\fR] [\-\-desc=\fIdescription\fR] [\-\-featured_image] -. -.SH "OPTIONS" -. -.IP "\(bu" 4 -\fB<file>\fR: -. -.IP -Path to file or files to be imported\. Supports the glob(3) capabilities of the current shell\. If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be downloaded to a temp file before being sideloaded\. -. -.IP "\(bu" 4 -\fB\-\-post_id=<post_id>\fR -. -.IP -ID of the post to attach the imported files to -. -.IP "\(bu" 4 -\fB\-\-title=<title>\fR -. -.IP -Attachment title (post title field) -. -.IP "\(bu" 4 -\fB\-\-caption=<caption>\fR -. -.IP -Caption for attachent (post excerpt field) -. -.IP "\(bu" 4 -\fB\-\-alt=<alt_text>\fR -. -.IP -Alt text for image (saved as post meta) -. -.IP "\(bu" 4 -\fB\-\-desc=<description>\fR -. -.IP -"Description" field (post content) of attachment post -. -.IP "\(bu" 4 -\fB\-\-featured_image\fR -. -.IP -If set, set the imported image as the Featured Image of the post its attached to\. -. -.IP "" 0 -. -.SH "EXAMPLES" -. -.nf - -# Import all jpgs in the current user\'s "Pictures" directory, not attached to any post -wp media import ~/Pictures/**/*\.jpg - -# Import a local image and set it to be the post thumbnail for a post -wp media import ~/Downloads/image\.png \-\-post_id=123 \-\-title="A downloaded picture" \-\-featured_image - -# Import an image from the web -wp media import http://s\.wordpress\.org/style/images/wp\-header\-logo\.png \-\-title=\'The WordPress logo\' \-\-alt="Semantic personal publishing" -. -.fi - diff --git a/man/media-regenerate.1 b/man/media-regenerate.1 deleted file mode 100644 index c829722ac..000000000 --- a/man/media-regenerate.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-MEDIA\-REGENERATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-media\-regenerate\fR \- Regenerate thumbnail(s)\. -. -.SH "SYNOPSIS" -wp media regenerate \fIattachment\-id\fR\.\.\. [\-\-yes] -. -.SH "OPTIONS" -. -.TP -\fB\-\-yes\fR: -. -.IP -Answer yes to the confirmation message\. -. -.TP -\fB<attachment\-id>\fR: -. -.IP -One or more IDs of the attachments to regenerate\. -. -.SH "EXAMPLES" -. -.nf - -wp media regenerate 123 1337 - -wp media regenerate \-\-yes -. -.fi - diff --git a/man/network-meta.1 b/man/network-meta.1 deleted file mode 100644 index 0beb7eb4a..000000000 --- a/man/network-meta.1 +++ /dev/null @@ -1,69 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-NETWORK\-META" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-network\-meta\fR \- Manage network custom fields\. -. -.SH "SYNOPSIS" -wp network\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.P -wp network\-meta delete \fIid\fR \fIkey\fR -. -.P -wp network\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] -. -.P -wp network\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add a meta field\. -. -.TP -\fBdelete\fR: -. -.IP -Delete a meta field\. -. -.TP -\fBget\fR: -. -.IP -Get meta field value\. -. -.TP -\fBupdate\fR: -. -.IP -Update a meta field\. -. -.SH "OPTIONS" -. -.TP -\fB<id>\fR: -. -.IP -The network id (usually 1)\. -. -.TP -\fB\-\-format=json\fR: -. -.IP -Encode/decode values as JSON\. -. -.SH "EXAMPLES" -. -.nf - -# get a list of super\-admins -wp network\-meta get 1 site_admins -. -.fi - diff --git a/man/option.1 b/man/option.1 deleted file mode 100644 index 69a8fb23b..000000000 --- a/man/option.1 +++ /dev/null @@ -1,68 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-OPTION" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-option\fR \- Manage WordPress options\. -. -.SH "SYNOPSIS" -wp option add \fIkey\fR [\-\-format=\fIformat\fR] -. -.P -wp option delete \fIkey\fR -. -.P -wp option get \fIkey\fR [\-\-format=\fIformat\fR] -. -.P -wp option update \fIkey\fR [\-\-format=\fIformat\fR] -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add an option\. -. -.TP -\fBdelete\fR: -. -.IP -Delete an option\. -. -.TP -\fBget\fR: -. -.IP -Get an option\. -. -.TP -\fBupdate\fR: -. -.IP -Update an option\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-format=json\fR: -. -.IP -Encode/decode values as JSON\. -. -.SH "EXAMPLES" -. -.nf - -wp option get siteurl - -wp option add my_option foobar - -wp option update my_option \'{"foo": "bar"}\' \-\-format=json - -wp option delete my_option -. -.fi - diff --git a/man/plugin-activate.1 b/man/plugin-activate.1 deleted file mode 100644 index a5355ada7..000000000 --- a/man/plugin-activate.1 +++ /dev/null @@ -1,25 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-ACTIVATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-activate\fR \- Activate a plugin\. -. -.SH "SYNOPSIS" -wp plugin activate \fIplugin\fR [\-\-network] -. -.SH "OPTIONS" -. -.TP -\fB<plugin>\fR: -. -.IP -The plugin to activate\. -. -.TP -\fB\-\-network\fR: -. -.IP -If set, the plugin will be activated for the entire multisite network\. - diff --git a/man/plugin-deactivate.1 b/man/plugin-deactivate.1 deleted file mode 100644 index 332b91a11..000000000 --- a/man/plugin-deactivate.1 +++ /dev/null @@ -1,25 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-DEACTIVATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-deactivate\fR \- Deactivate a plugin\. -. -.SH "SYNOPSIS" -wp plugin deactivate \fIplugin\fR [\-\-network] -. -.SH "OPTIONS" -. -.TP -\fB<plugin>\fR: -. -.IP -The plugin to deactivate\. -. -.TP -\fB\-\-network\fR: -. -.IP -If set, the plugin will be deactivated for the entire multisite network\. - diff --git a/man/plugin-delete.1 b/man/plugin-delete.1 deleted file mode 100644 index 41b1927e0..000000000 --- a/man/plugin-delete.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-delete\fR \- Delete plugin files\. -. -.SH "SYNOPSIS" -wp plugin delete \fIplugin\fR -. -.SH "OPTIONS" -. -.TP -\fIplugin\fR: -. -.IP -The plugin to delete\. -. -.SH "EXAMPLES" -. -.nf - -wp plugin delete hello -. -.fi - diff --git a/man/plugin-install.1 b/man/plugin-install.1 deleted file mode 100644 index 557ec7db7..000000000 --- a/man/plugin-install.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-INSTALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-install\fR \- Install a plugin\. -. -.SH "SYNOPSIS" -wp plugin install \fIplugin|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] -. -.SH "OPTIONS" -. -.TP -\fIplugin\fR: -. -.IP -A plugin slug or the path to a zip file\. -. -.TP -\fB\-\-version\fR=\fIversion\fR: -. -.IP -If set, get that particular version from wordpress\.org, instead of the stable version\. -. -.TP -\fB\-\-activate\fR: -. -.IP -If set, the plugin will be activated immediately after install\. -. -.SH "EXAMPLES" -. -.nf - -wp plugin install bbpress \-\-version=2\.1 \-\-activate - -wp plugin install bbpress \-\-version=dev - -wp plugin install \.\./my\-plugin\.zip -. -.fi - diff --git a/man/plugin-list.1 b/man/plugin-list.1 deleted file mode 100644 index fd23e19af..000000000 --- a/man/plugin-list.1 +++ /dev/null @@ -1,21 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-list\fR \- Get a list of plugins\. -. -.SH "SYNOPSIS" -wp plugin list [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV or JSON\. Defaults to table\. -. -.SH "EXAMPLES" -wp plugin list \-\-format=json diff --git a/man/plugin-path.1 b/man/plugin-path.1 deleted file mode 100644 index 7b4b33bb0..000000000 --- a/man/plugin-path.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-PATH" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-path\fR \- Get the path to a plugin or to the plugin directory\. -. -.SH "SYNOPSIS" -wp plugin path [\fIplugin\fR] [\-\-dir] -. -.SH "OPTIONS" -. -.TP -\fB<plugin>\fR: -. -.IP -The plugin to get the path to\. If not set, will return the path to the plugins directory\. -. -.TP -\fB\-\-dir\fR: -. -.IP -If set, get the path to the closest parent directory, instead of the plugin file\. -. -.SH "EXAMPLES" -. -.nf - -cd $(wp theme path) -. -.fi - diff --git a/man/plugin-status.1 b/man/plugin-status.1 deleted file mode 100644 index 797ffa320..000000000 --- a/man/plugin-status.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-STATUS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-status\fR \- See the status of one or all plugins\. -. -.SH "SYNOPSIS" -wp plugin status [\fIplugin\fR] -. -.SH "OPTIONS" -. -.TP -\fB<plugin>\fR: -. -.IP -A particular plugin to show the status for\. - diff --git a/man/plugin-toggle.1 b/man/plugin-toggle.1 deleted file mode 100644 index 3c8e567c1..000000000 --- a/man/plugin-toggle.1 +++ /dev/null @@ -1,25 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-TOGGLE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-toggle\fR \- Toggle a plugin\'s activation state\. -. -.SH "SYNOPSIS" -wp plugin toggle \fIplugin\fR [\-\-network] -. -.SH "OPTIONS" -. -.TP -\fB<plugin>\fR: -. -.IP -The plugin to toggle\. -. -.TP -\fB\-\-network\fR: -. -.IP -If set, the plugin will be toggled for the entire multisite network\. - diff --git a/man/plugin-uninstall.1 b/man/plugin-uninstall.1 deleted file mode 100644 index fa2fff495..000000000 --- a/man/plugin-uninstall.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-UNINSTALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-uninstall\fR \- Uninstall a plugin\. -. -.SH "SYNOPSIS" -wp plugin uninstall \fIplugin\fR [\-\-no\-delete] -. -.SH "OPTIONS" -. -.TP -\fIplugin\fR: -. -.IP -The plugin to uninstall\. -. -.TP -\fB\-\-no\-delete\fR: -. -.IP -If set, the plugin files will not be deleted\. Only the uninstall procedure will be run\. -. -.SH "EXAMPLES" -. -.nf - -wp plugin uninstall hello -. -.fi - diff --git a/man/plugin-update-all.1 b/man/plugin-update-all.1 deleted file mode 100644 index ae85d459a..000000000 --- a/man/plugin-update-all.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-UPDATE\-ALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-update\-all\fR \- Update all plugins\. -. -.SH "SYNOPSIS" -wp plugin update\-all [\-\-dry\-run] -. -.SH "OPTIONS" -. -.TP -\fB\-\-dry\-run\fR: -. -.IP -Pretend to do the updates, to see what would happen\. -. -.SH "EXAMPLES" -. -.nf - -wp plugin update\-all -. -.fi - diff --git a/man/plugin-update.1 b/man/plugin-update.1 deleted file mode 100644 index cd26ed8e9..000000000 --- a/man/plugin-update.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-PLUGIN\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-plugin\-update\fR \- Update a plugin\. -. -.SH "SYNOPSIS" -wp plugin update \fIplugin\fR [\-\-version=\fIversion\fR] -. -.SH "OPTIONS" -. -.TP -\fIplugin\fR: -. -.IP -The plugin to update\. -. -.TP -\fB\-\-version=dev\fR: -. -.IP -If set, the plugin will be updated to the latest development version, regardless of what version is currently installed\. -. -.SH "EXAMPLES" -. -.nf - -wp plugin update bbpress \-\-version=dev -. -.fi - diff --git a/man/post-create.1 b/man/post-create.1 deleted file mode 100644 index 7dbc24844..000000000 --- a/man/post-create.1 +++ /dev/null @@ -1,53 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-create\fR \- Create a post\. -. -.SH "SYNOPSIS" -wp post create [\fIfilename\fR] \-\-\fIfield\fR=\fIvalue\fR [\-\-edit] [\-\-porcelain] -. -.SH "OPTIONS" -. -.TP -\fB<filename>\fR: -. -.IP -Read post content from \fIfilename\fR\. If this value is present, the \fB\-\-post_content\fR argument will be ignored\. -. -.IP -Passing \fB\-\fR as the filename will cause post content to be read from STDIN\. -. -.TP -\fB\-\-<field>\fR=\fIvalue\fR: -. -.IP -Field values for the new post\. See wp_insert_post()\. -. -.TP -\fB\-\-edit\fR: -. -.IP -Immediately open system\'s editor to write or edit post content\. -. -.IP -(If content is read from a file, from STDIN, or from the \fB\-\-post_content\fR argument, that text will be loaded into the editor; otherwise, an empty file will be opened\.) -. -.TP -\fB\-\-porcelain\fR: -. -.IP -Output just the new post id\. -. -.SH "EXAMPLES" -. -.nf - -wp post create \-\-post_type=page \-\-post_status=publish \-\-post_title=\'A future post\' \-\-post\-status=future \-\-post_date=\'2020\-12\-01 07:00:00\' - -wp post create page\.txt \-\-post_type=page \-\-post_title=\'Page from file\' -. -.fi - diff --git a/man/post-delete.1 b/man/post-delete.1 deleted file mode 100644 index f163575f2..000000000 --- a/man/post-delete.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-delete\fR \- Delete a post by ID\. -. -.SH "SYNOPSIS" -wp post delete \fIid\fR\.\.\. [\-\-force] -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the post to delete\. -. -.TP -\fB\-\-force\fR: -. -.IP -Skip the trash bin\. -. -.SH "EXAMPLES" -. -.nf - -wp post delete 123 \-\-force - -wp post delete $(wp post list \-\-post_type=\'page\' \-\-format=ids) -. -.fi - diff --git a/man/post-edit.1 b/man/post-edit.1 deleted file mode 100644 index 9ce962902..000000000 --- a/man/post-edit.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-EDIT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-edit\fR \- Launch system editor to edit post content\. -. -.SH "SYNOPSIS" -wp post edit \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB<id>\fR: -. -.IP -The ID of the post to edit\. -. -.SH "EXAMPLES" -. -.nf - -wp post edit 123 -. -.fi - diff --git a/man/post-generate.1 b/man/post-generate.1 deleted file mode 100644 index d89efebe9..000000000 --- a/man/post-generate.1 +++ /dev/null @@ -1,57 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-GENERATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-generate\fR \- Generate some posts\. -. -.SH "SYNOPSIS" -wp post generate [\-\-count=\fInumber\fR] [\-\-post_type=\fItype\fR] [\-\-post_status=\fIstatus\fR] [\-\-post_author=\fIlogin\fR] [\-\-post_date=\fIyyyy\-mm\-dd\fR] [\-\-max_depth=\fInumber\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-count\fR=\fInumber\fR: -. -.IP -How many posts to generate\. Default: 100 -. -.TP -\fB\-\-post_type\fR=\fItype\fR: -. -.IP -The type of the generated posts\. Default: \'post\' -. -.TP -\fB\-\-post_status\fR=\fIstatus\fR: -. -.IP -The status of the generated posts\. Default: \'publish\' -. -.TP -\fB\-\-post_author\fR=\fIlogin\fR: -. -.IP -The author of the generated posts\. Default: none -. -.TP -\fB\-\-post_date\fR=\fIyyyy\-mm\-dd\fR: -. -.IP -The date of the generated posts\. Default: current date -. -.TP -\fB\-\-max_depth\fR=\fInumber\fR: -. -.IP -For hierarchical post types, generate child posts down to a certain depth\. Default: 1 -. -.SH "EXAMPLES" -. -.nf - -wp post generate \-\-count=10 \-\-post_type=page \-\-post_date=1999\-01\-04 -. -.fi - diff --git a/man/post-get.1 b/man/post-get.1 deleted file mode 100644 index 94df8e63b..000000000 --- a/man/post-get.1 +++ /dev/null @@ -1,44 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-GET" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-get\fR \- Get a post\'s content by ID\. -. -.SH "SYNOPSIS" -wp post get [\-\-format=\fIformat\fR] \fIid\fR -. -.SH "OPTIONS" -. -.TP -\fB[\-\-format=<format>]\fR: -. -.IP -The format to use when printing the post, acceptable values: -. -.IP -\fBcontent\fR: Outputs only the post\'s content\. -. -.IP -\fBtable\fR: Outputs all fields of the post as a table\. Note that the post_content field is omitted so that the table is readable\. -. -.IP -\fBjson\fR: Outputs all fields in JSON format\. -. -.TP -\fB<id>\fR: -. -.IP -The ID of the post to get\. -. -.SH "EXAMPLES" -. -.nf - -wp post get 12 \-\-format=content - -wp post get 12 > file\.txt -. -.fi - diff --git a/man/post-list.1 b/man/post-list.1 deleted file mode 100644 index 921245423..000000000 --- a/man/post-list.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-list\fR \- Get a list of posts\. -. -.SH "SYNOPSIS" -wp post list [\-\-\fIfield\fR=\fIvalue\fR] [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-<field>\fR=\fIvalue\fR: -. -.IP -One or more args to pass to WP_Query\. -. -.TP -\fB\-\-fields\fR=\fIfields\fR: -. -.IP -Limit the output to specific object fields\. Defaults to ID,post_title,post_name,post_date,post_status\. -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. -. -.SH "EXAMPLES" -. -.nf - -wp post list \-\-format=ids - -wp post list \-\-post_type=post \-\-posts_per_page=5 \-\-format=json - -wp post list \-\-post_type=page \-\-fields=post_title,post_status -. -.fi - diff --git a/man/post-meta.1 b/man/post-meta.1 deleted file mode 100644 index 90398260a..000000000 --- a/man/post-meta.1 +++ /dev/null @@ -1,62 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-META" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-meta\fR \- Manage post custom fields\. -. -.SH "SYNOPSIS" -wp post\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.P -wp post\-meta delete \fIid\fR \fIkey\fR -. -.P -wp post\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] -. -.P -wp post\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add a meta field\. -. -.TP -\fBdelete\fR: -. -.IP -Delete a meta field\. -. -.TP -\fBget\fR: -. -.IP -Get meta field value\. -. -.TP -\fBupdate\fR: -. -.IP -Update a meta field\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-format=json\fR: -. -.IP -Encode/decode values as JSON\. -. -.SH "EXAMPLES" -. -.nf - -wp post\-meta set 123 _wp_page_template about\.php -. -.fi - diff --git a/man/post-update.1 b/man/post-update.1 deleted file mode 100644 index 91b69b6b5..000000000 --- a/man/post-update.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-POST\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-post\-update\fR \- Update one or more posts\. -. -.SH "SYNOPSIS" -wp post update \fIid\fR\.\.\. \-\-\fIfield\fR=\fIvalue\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the post to update\. -. -.TP -\fB\-\-<field>\fR=\fIvalue\fR: -. -.IP -One or more fields to update\. See wp_update_post()\. -. -.SH "EXAMPLES" -. -.nf - -wp post update 123 \-\-post_name=something \-\-post_status=draft -. -.fi - diff --git a/man/rewrite-dump.1 b/man/rewrite-dump.1 deleted file mode 100644 index a5e9c33d3..000000000 --- a/man/rewrite-dump.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-REWRITE\-DUMP" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-rewrite\-dump\fR \- Print current rewrite rules\. -. -.SH "SYNOPSIS" -wp rewrite dump [\-\-json] -. -.SH "OPTIONS" -. -.TP -\fB\-\-format=json\fR: -. -.IP -Output rules in JSON format\. - diff --git a/man/rewrite-flush.1 b/man/rewrite-flush.1 deleted file mode 100644 index 622e11e12..000000000 --- a/man/rewrite-flush.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-REWRITE\-FLUSH" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-rewrite\-flush\fR \- Flush rewrite rules\. -. -.SH "SYNOPSIS" -wp rewrite flush [\-\-soft] -. -.SH "OPTIONS" -. -.TP -\fB\-\-soft\fR: -. -.IP -Perform a soft flush \- do not overwrite \fB\.htaccess\fR\. The default is to update \fB\.htaccess\fR rules as well as rewrite rules in database\. - diff --git a/man/rewrite-structure.1 b/man/rewrite-structure.1 deleted file mode 100644 index 50272811d..000000000 --- a/man/rewrite-structure.1 +++ /dev/null @@ -1,31 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-REWRITE\-STRUCTURE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-rewrite\-structure\fR \- Update the permalink structure\. -. -.SH "SYNOPSIS" -wp rewrite structure \fIpermastruct\fR [\-\-category\-base=\fIbase\fR] [\-\-tag\-base=\fIbase\fR] -. -.SH "OPTIONS" -. -.TP -\fIpermastruct\fR: -. -.IP -The new permalink structure to apply; like "/%year%/%monthnum%/%postname%"\. -. -.TP -\fB\-\-category\-base\fR=\fIcategorybase\fR: -. -.IP -Set the base for category permalinks, ie \'/category/\'\. -. -.TP -\fB\-\-tag\-base\fR=\fItagbase\fR: -. -.IP -Set the base for tag permalinks, ie \'/tag/\'\. - diff --git a/man/role-create.1 b/man/role-create.1 deleted file mode 100644 index 4737ed2b0..000000000 --- a/man/role-create.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLE\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-role\-create\fR \- Create a new role\. -. -.SH "SYNOPSIS" -wp role create \fIrole\-key\fR \fIrole\-name\fR -. -.SH "OPTIONS" -. -.TP -\fIrole\-key\fR: -. -.IP -The internal name of the role, e\.g\. editor -. -.TP -\fIrole\-name\fR: -. -.IP -The publically visible name of the role, e\.g\. Editor -. -.SH "EXAMPLES" -. -.nf - -wp role create approver Approver - -wp role create productadmin "Product Administrator" -. -.fi - diff --git a/man/role-delete.1 b/man/role-delete.1 deleted file mode 100644 index 02375d369..000000000 --- a/man/role-delete.1 +++ /dev/null @@ -1,29 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLE\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-role\-delete\fR \- Delete an existing role\. -. -.SH "SYNOPSIS" -wp role delete \fIrole\-key\fR -. -.SH "OPTIONS" -. -.TP -\fIrole\-key\fR: -. -.IP -The internal name of the role, e\.g\. editor -. -.SH "EXAMPLES" -. -.nf - -wp role delete approver - -wp role delete productadmin -. -.fi - diff --git a/man/role-exists.1 b/man/role-exists.1 deleted file mode 100644 index 7db3baa31..000000000 --- a/man/role-exists.1 +++ /dev/null @@ -1,30 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLE\-EXISTS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-role\-exists\fR \- Check if a role exists\. -. -.SH "SYNOPSIS" -wp role exists \fIrole\-key\fR -. -.SH "OPTIONS" -. -.TP -\fIrole\-key\fR: -. -.IP -The internal name of the role, e\.g\. editor -. -.SH "DESCRIPTION" -Will exit with status 0 if the role exists, 1 if it does not\. -. -.SH "EXAMPLES" -. -.nf - -wp role exists editor -. -.fi - diff --git a/man/role-list.1 b/man/role-list.1 deleted file mode 100644 index 14d58a8b8..000000000 --- a/man/role-list.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-ROLE\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-role\-list\fR \- List all roles\. -. -.SH "SYNOPSIS" -wp role list [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-fields\fR=\fIfields\fR: -. -.IP -Limit the output to specific object fields\. Defaults to name,role\. -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV or JSON\. Defaults to table\. -. -.SH "EXAMPLES" -. -.nf - -wp role list \-\-fields=role \-\-format=csv -. -.fi - diff --git a/man/scaffold-_s.1 b/man/scaffold-_s.1 deleted file mode 100644 index d6ee0407c..000000000 --- a/man/scaffold-_s.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-_S" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-_s\fR \- Generate starter code for a theme\. -. -.SH "SYNOPSIS" -wp scaffold _s \fIslug\fR [\-\-theme_name=\fItitle\fR] [\-\-author=\fIfull\-name\fR] [\-\-author_uri=\fIhttp\-url\fR] [\-\-activate] -. -.SH "OPTIONS" -. -.TP -\fIslug\fR: -. -.IP -The slug for the new theme, used for prefixing functions\. -. -.TP -\fB\-\-activate\fR: -. -.IP -Activate the newly downloaded theme\. -. -.TP -\fB\-\-theme_name=<title>\fR: -. -.IP -What to put in the \'Theme Name:\' header in style\.css -. -.TP -\fB\-\-author=<full name>\fR: -. -.IP -What to put in the \'Author:\' header in style\.css -. -.TP -\fB\-\-author_uri=<http url>\fR: -. -.IP -What to put in the \'Author URI:\' header in style\.css - diff --git a/man/scaffold-child-theme.1 b/man/scaffold-child-theme.1 deleted file mode 100644 index 67fa5bcd3..000000000 --- a/man/scaffold-child-theme.1 +++ /dev/null @@ -1,55 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-CHILD\-THEME" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-child\-theme\fR \- Generate empty child theme\. -. -.SH "SYNOPSIS" -wp scaffold child\-theme \fIslug\fR \-\-parent_theme=\fIslug\fR [\-\-theme_name=\fItitle\fR] [\-\-author=\fIfull\-name\fR] [\-\-author_uri=\fIhttp\-url\fR] [\-\-theme_uri=\fIhttp\-url\fR] [\-\-activate] -. -.SH "OPTIONS" -. -.TP -\fIslug\fR: -. -.IP -The slug for the new child theme\. -. -.TP -\fB\-\-parent_theme=<slug>\fR: -. -.IP -What to put in the \'Template:\' header in style\.css -. -.TP -\fB\-\-theme_name=<title>\fR: -. -.IP -What to put in the \'Theme Name:\' header in style\.css -. -.TP -\fB\-\-author=<full name>\fR: -. -.IP -What to put in the \'Author:\' header in style\.css -. -.TP -\fB\-\-author_uri=<http url>\fR: -. -.IP -What to put in the \'Author URI:\' header in style\.css -. -.TP -\fB\-\-theme_uri=<http url>\fR: -. -.IP -What to put in the \'Theme URI:\' header in style\.css -. -.TP -\fB\-\-activate\fR: -. -.IP -Activate the newly created child theme\. - diff --git a/man/scaffold-plugin-tests.1 b/man/scaffold-plugin-tests.1 deleted file mode 100644 index 5c0a07ee5..000000000 --- a/man/scaffold-plugin-tests.1 +++ /dev/null @@ -1,39 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-PLUGIN\-TESTS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-plugin\-tests\fR \- Generate files needed for running PHPUnit tests\. -. -.SH "SYNOPSIS" -wp scaffold plugin\-tests \fIplugin\fR -. -.SH "DESCRIPTION" -These are the files that are generated: -. -.IP "\(bu" 4 -\fBphpunit\.xml\fR is the configuration file for PHPUnit -. -.IP "\(bu" 4 -\fB\.travis\.yml\fR is the configuration file for Travis CI -. -.IP "\(bu" 4 -\fBtests/bootstrap\.php\fR is the file that makes the current plugin active when running the test suite -. -.IP "\(bu" 4 -\fBtests/test\-sample\.php\fR is a sample file containing the actual tests -. -.IP "" 0 -. -.SH "ENVIRONMENT" -The \fBtests/bootstrap\.php\fR file looks for the WP_TESTS_DIR environment variable\. -. -.SH "EXAMPLE" -. -.nf - -wp scaffold plugin\-tests hello -. -.fi - diff --git a/man/scaffold-plugin.1 b/man/scaffold-plugin.1 deleted file mode 100644 index f91ec221e..000000000 --- a/man/scaffold-plugin.1 +++ /dev/null @@ -1,25 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-PLUGIN" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-plugin\fR \- Generate starter code for a plugin\. -. -.SH "SYNOPSIS" -wp scaffold plugin \fIslug\fR [\-\-plugin_name=\fItitle\fR] [\-\-activate] -. -.SH "OPTIONS" -. -.TP -\fB\-\-activate\fR: -. -.IP -Activate the newly generated plugin\. -. -.TP -\fB\-\-plugin_name=<title>\fR: -. -.IP -What to put in the \'Plugin Name:\' header - diff --git a/man/scaffold-post-type.1 b/man/scaffold-post-type.1 deleted file mode 100644 index 6db8bf44c..000000000 --- a/man/scaffold-post-type.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-POST\-TYPE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-post\-type\fR \- Generate PHP code for registering a custom post type\. -. -.SH "SYNOPSIS" -wp scaffold post\-type \fIslug\fR [\-\-label=\fIlabel\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] -. -.SH "OPTIONS" -. -.TP -\fB\-\-label=<label>\fR: -. -.IP -The text used to translate the update messages -. -.TP -\fB\-\-textdomain=<textdomain>\fR: -. -.IP -The textdomain to use for the labels\. -. -.TP -\fB\-\-theme\fR: -. -.IP -Create a file in the active theme directory, instead of sending to STDOUT\. Specify a theme with \fB\-\-theme=<theme>\fR to have the file placed in that theme\. -. -.TP -\fB\-\-plugin=<plugin>\fR: -. -.IP -Create a file in the given plugin\'s directory, instead of sending to STDOUT\. -. -.TP -\fB\-\-raw\fR: -. -.IP -Just generate the \fBregister_post_type()\fR call and nothing else\. - diff --git a/man/scaffold-taxonomy.1 b/man/scaffold-taxonomy.1 deleted file mode 100644 index 3d7986f2e..000000000 --- a/man/scaffold-taxonomy.1 +++ /dev/null @@ -1,57 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SCAFFOLD\-TAXONOMY" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-scaffold\-taxonomy\fR \- Generate PHP code for registering a custom taxonomy\. -. -.SH "SYNOPSIS" -wp scaffold taxonomy \fIslug\fR [\-\-post_types=\fIpost\-types\fR] [\-\-label=\fIlabel\fR] [\-\-textdomain=\fItextdomain\fR] [\-\-theme] [\-\-plugin=\fIplugin\fR] [\-\-raw] -. -.SH "OPTIONS" -. -.TP -\fB\-\-post_types=<post_types>\fR: -. -.IP -Post types to register for use with the taxonomy\. -. -.TP -\fB\-\-label=<label>\fR: -. -.IP -The text used to translate the update messages -. -.TP -\fB\-\-textdomain=<textdomain>\fR: -. -.IP -The textdomain to use for the labels\. -. -.TP -\fB\-\-theme\fR: -. -.IP -Create a file in the active theme directory, instead of sending to STDOUT\. Specify a theme with \fB\-\-theme=<theme>\fR to have the file placed in that theme\. -. -.TP -\fB\-\-plugin=<plugin>\fR: -. -.IP -Create a file in the given plugin\'s directory, instead of sending to STDOUT\. -. -.TP -\fB\-\-raw\fR: -. -.IP -Just generate the \fBregister_taxonomy()\fR call and nothing else\. -. -.SH "EXAMPLES" -. -.nf - -wp scaffold taxonomy venue \-\-post_types=event,presentation -. -.fi - diff --git a/man/search-replace.1 b/man/search-replace.1 deleted file mode 100644 index 6af388a6e..000000000 --- a/man/search-replace.1 +++ /dev/null @@ -1,47 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SEARCH\-REPLACE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-search\-replace\fR \- Search/replace strings in the database\. -. -.SH "SYNOPSIS" -wp search\-replace \fIold\fR \fInew\fR [\fItable\fR\.\.\.] [\-\-skip\-columns=\fIcolumns\fR] [\-\-dry\-run] [\-\-network] -. -.SH "DESCRIPTION" -This command will go through all rows in all tables and will replace all appearances of the old string with the new one\. -. -.P -It will correctly handle serialized values, and will not change primary key values\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-network\fR: -. -.IP -Search/replace through all the tables in a multisite install\. -. -.TP -\fB\-\-skip\-columns=<columns>\fR: -. -.IP -Do not perform the replacement in the comma\-separated columns\. -. -.TP -\fB\-\-dry\-run\fR: -. -.IP -Show report, but don\'t perform the changes\. -. -.SH "EXAMPLES" -. -.nf - -wp search\-replace \'http://example\.dev\' \'http://example\.com\' \-\-skip\-columns=guid - -wp search\-replace \'foo\' \'bar\' wp_posts wp_postmeta wp_terms \-\-dry\-run -. -.fi - diff --git a/man/shell.1 b/man/shell.1 deleted file mode 100644 index 6aa5f9e1f..000000000 --- a/man/shell.1 +++ /dev/null @@ -1,22 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SHELL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-shell\fR \- Interactive PHP console\. -. -.SH "SYNOPSIS" -wp shell [\-\-basic] -. -.SH "DESCRIPTION" -\fBwp shell\fR allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment\. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-basic\fR: -. -.IP -Start in fail\-safe mode, even if Boris is available\. - diff --git a/man/site-create.1 b/man/site-create.1 deleted file mode 100644 index 20675a3e6..000000000 --- a/man/site-create.1 +++ /dev/null @@ -1,49 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SITE\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-site\-create\fR \- Create a site in a multisite install\. -. -.SH "SYNOPSIS" -wp site create \-\-slug=\fIslug\fR [\-\-title=\fItitle\fR] [\-\-email=\fIemail\fR] [\-\-network_id=\fInetwork\-id\fR] [\-\-private] [\-\-porcelain] -. -.SH "OPTIONS" -. -.TP -\fB\-\-slug\fR=\fIslug\fR: -. -.IP -Path for the new site\. Subdomain on subdomain installs, directory on subdirectory installs\. -. -.TP -\fB\-\-title\fR=<title>: -. -.IP -Title of the new site\. Default: prettified slug\. -. -.TP -\fB\-\-email\fR=\fIemail\fR: -. -.IP -Email for Admin user\. User will be created if none exists\. Assignement to Super Admin if not included\. -. -.TP -\fB\-\-network_id\fR=\fInetwork\-id\fR: -. -.IP -Network to associate new site with\. Defaults to current network (typically 1)\. -. -.TP -\fB\-\-private\fR: -. -.IP -If set, the new site will be non\-public (not indexed) -. -.TP -\fB\-\-porcelain\fR: -. -.IP -If set, only the site id will be output on success\. - diff --git a/man/site-delete.1 b/man/site-delete.1 deleted file mode 100644 index d8f7f3bc3..000000000 --- a/man/site-delete.1 +++ /dev/null @@ -1,37 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SITE\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-site\-delete\fR \- Delete a site in a multisite install\. -. -.SH "SYNOPSIS" -wp site delete [\fIsite\-id\fR] [\-\-slug=\fIslug\fR] [\-\-yes] [\-\-keep\-tables] -. -.SH "OPTIONS" -. -.TP -\fB<blog\-id>\fR: -. -.IP -The id of the blog to delete\. If not provided, you must set the \-\-slug parameter\. -. -.TP -\fB\-\-slug\fR=\fIslug\fR: -. -.IP -Path of the blog to be deleted\. Subdomain on subdomain installs, directory on subdirectory installs\. -. -.TP -\fB\-\-yes\fR: -. -.IP -Answer yes to the confirmation message\. -. -.TP -\fB\-\-keep\-tables\fR: -. -.IP -Delete the blog from the list, but don\'t drop it\'s tables\. - diff --git a/man/site-empty.1 b/man/site-empty.1 deleted file mode 100644 index 144391fba..000000000 --- a/man/site-empty.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-SITE\-EMPTY" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-site\-empty\fR \- Empty a site of its content\. -. -.SH "SYNOPSIS" -wp site empty [\-\-yes] -. -.SH "EXAMPLES" -. -.nf - -wp blog empty -. -.fi - diff --git a/man/term-create.1 b/man/term-create.1 deleted file mode 100644 index 366ee1a88..000000000 --- a/man/term-create.1 +++ /dev/null @@ -1,57 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TERM\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-term\-create\fR \- Create a term\. -. -.SH "SYNOPSIS" -wp term create \fIterm\fR \fItaxonomy\fR [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] [\-\-porcelain] -. -.SH "OPTIONS" -. -.TP -\fB<term>\fR: -. -.IP -A name for the new term\. -. -.TP -\fB<taxonomy>\fR: -. -.IP -Taxonomy for the new term\. -. -.TP -\fB\-\-slug\fR=\fIslug\fR: -. -.IP -A unique slug for the new term\. Defaults to sanitized version of name\. -. -.TP -\fB\-\-description\fR=\fIdescription\fR: -. -.IP -A description for the new term\. -. -.TP -\fB\-\-parent\fR=\fIterm\-id\fR: -. -.IP -A parent for the new term\. -. -.TP -\fB\-\-porcelain\fR: -. -.IP -Output just the new term id\. -. -.SH "EXAMPLES" -. -.nf - -wp term create Apple category \-\-description="A type of fruit" -. -.fi - diff --git a/man/term-delete.1 b/man/term-delete.1 deleted file mode 100644 index 1a9700510..000000000 --- a/man/term-delete.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TERM\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-term\-delete\fR \- Delete a term\. -. -.SH "SYNOPSIS" -wp term delete \fIterm\-id\fR \fItaxonomy\fR -. -.SH "OPTIONS" -. -.TP -\fB<term\-id>\fR: -. -.IP -ID for the term to delete\. -. -.TP -\fB<taxonomy>\fR: -. -.IP -Taxonomy of the term to delete\. -. -.SH "EXAMPLES" -. -.nf - -wp term delete 15 category -. -.fi - diff --git a/man/term-list.1 b/man/term-list.1 deleted file mode 100644 index ef1530191..000000000 --- a/man/term-list.1 +++ /dev/null @@ -1,41 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TERM\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-term\-list\fR \- List terms in a taxonomy\. -. -.SH "SYNOPSIS" -wp term list \fItaxonomy\fR [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB<taxonomy>\fR: -. -.IP -List terms of a given taxonomy\. -. -.TP -\fB\-\-fields\fR=\fIfields\fR: -. -.IP -Limit the output to specific object fields\. Defaults to all of the term object fields\. -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. -. -.SH "EXAMPLES" -. -.nf - -wp term list category \-\-format=csv - -wp term list post_tag \-\-fields=name,slug -. -.fi - diff --git a/man/term-update.1 b/man/term-update.1 deleted file mode 100644 index 34bf099de..000000000 --- a/man/term-update.1 +++ /dev/null @@ -1,57 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TERM\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-term\-update\fR \- Update a term\. -. -.SH "SYNOPSIS" -wp term update \fIterm\-id\fR \fItaxonomy\fR [\-\-name=\fIname\fR] [\-\-slug=\fIslug\fR] [\-\-description=\fIdescription\fR] [\-\-parent=\fIterm\-id\fR] -. -.SH "OPTIONS" -. -.TP -\fB<term\-id>\fR: -. -.IP -ID for the term to update\. -. -.TP -\fB<taxonomy>\fR: -. -.IP -Taxonomy of the term to update\. -. -.TP -\fB\-\-name\fR=\fIname\fR: -. -.IP -A new name for the term\. -. -.TP -\fB\-\-slug\fR=\fIslug\fR: -. -.IP -A new slug for the term\. -. -.TP -\fB\-\-description\fR=\fIdescription\fR: -. -.IP -A new description for the term\. -. -.TP -\fB\-\-parent\fR=\fIterm\-id\fR: -. -.IP -A new parent for the term\. -. -.SH "EXAMPLES" -. -.nf - -wp term update 15 category \-\-name=Apple -. -.fi - diff --git a/man/theme-activate.1 b/man/theme-activate.1 deleted file mode 100644 index 52f33f8b4..000000000 --- a/man/theme-activate.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-ACTIVATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-activate\fR \- Activate a theme\. -. -.SH "SYNOPSIS" -wp theme activate \fItheme\fR -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -The theme to activate\. - diff --git a/man/theme-delete.1 b/man/theme-delete.1 deleted file mode 100644 index 3bfae3759..000000000 --- a/man/theme-delete.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-delete\fR \- Delete a theme\. -. -.SH "SYNOPSIS" -wp theme delete \fItheme\fR -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -The theme to delete\. -. -.SH "EXAMPLES" -. -.nf - -wp theme delete twentyeleven -. -.fi - diff --git a/man/theme-install.1 b/man/theme-install.1 deleted file mode 100644 index 5e74e7c30..000000000 --- a/man/theme-install.1 +++ /dev/null @@ -1,35 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-INSTALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-install\fR \- Install a theme\. -. -.SH "SYNOPSIS" -wp theme install \fItheme|zip\fR [\-\-version=\fIversion\fR] [\-\-activate] -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -A theme slug or the path to a zip file\. -. -.TP -\fB\-\-activate\fR: -. -.IP -If set, the theme will be activated immediately after install\. -. -.SH "EXAMPLES" -. -.nf - -wp theme install twentytwelve \-\-activate - -wp theme install \.\./my\-theme\.zip -. -.fi - diff --git a/man/theme-list.1 b/man/theme-list.1 deleted file mode 100644 index 96436899f..000000000 --- a/man/theme-list.1 +++ /dev/null @@ -1,21 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-list\fR \- Get a list of themes\. -. -.SH "SYNOPSIS" -wp theme list [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV or JSON\. Defaults to table\. -. -.SH "EXAMPLES" -wp theme list \-\-format=csv diff --git a/man/theme-path.1 b/man/theme-path.1 deleted file mode 100644 index b657808c8..000000000 --- a/man/theme-path.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-PATH" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-path\fR \- Get the path to a theme or to the theme directory\. -. -.SH "SYNOPSIS" -wp theme path [\fItheme\fR] [\-\-dir] -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -The theme to get the path to\. If not set, will return the path to the themes directory\. -. -.TP -\fB\-\-dir\fR: -. -.IP -If set, get the path to the closest parent directory, instead of the theme file\. -. -.SH "EXAMPLES" -. -.nf - -cd $(wp theme path) -. -.fi - diff --git a/man/theme-status.1 b/man/theme-status.1 deleted file mode 100644 index 89fb262e6..000000000 --- a/man/theme-status.1 +++ /dev/null @@ -1,19 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-STATUS" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-status\fR \- See the status of one or all themes\. -. -.SH "SYNOPSIS" -wp theme status [\fItheme\fR] -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -A particular theme to show the status for\. - diff --git a/man/theme-update-all.1 b/man/theme-update-all.1 deleted file mode 100644 index 82f580ff9..000000000 --- a/man/theme-update-all.1 +++ /dev/null @@ -1,27 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-UPDATE\-ALL" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-update\-all\fR \- Update all themes\. -. -.SH "SYNOPSIS" -wp theme update\-all [\-\-dry\-run] -. -.SH "OPTIONS" -. -.TP -\fB\-\-dry\-run\fR: -. -.IP -Pretend to do the updates, to see what would happen\. -. -.SH "EXAMPLES" -. -.nf - -wp theme update\-all -. -.fi - diff --git a/man/theme-update.1 b/man/theme-update.1 deleted file mode 100644 index 7e877c817..000000000 --- a/man/theme-update.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-THEME\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-theme\-update\fR \- Update a theme\. -. -.SH "SYNOPSIS" -wp theme update \fItheme\fR [\-\-version=\fIversion\fR] -. -.SH "OPTIONS" -. -.TP -\fB<theme>\fR: -. -.IP -The theme to update\. -. -.TP -\fB\-\-version=dev\fR: -. -.IP -If set, the theme will be updated to the latest development version, regardless of what version is currently installed\. -. -.SH "EXAMPLES" -. -.nf - -wp theme update twentytwelve -. -.fi - diff --git a/man/transient.1 b/man/transient.1 deleted file mode 100644 index e3fd1ddd1..000000000 --- a/man/transient.1 +++ /dev/null @@ -1,54 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-TRANSIENT" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-transient\fR \- Manage WordPress transients\. -. -.SH "SYNOPSIS" -wp transient delete \fIkey\fR -. -.P -wp transient get \fIkey\fR [\-\-json] -. -.P -wp transient set \fIkey\fR \fIvalue\fR [\fIexpiration\fR] -. -.P -wp transient type -. -.SH "SUBCOMMANDS" -. -.TP -\fBdelete\fR: -. -.IP -Delete a transient value\. -. -.TP -\fBget\fR: -. -.IP -Get a transient value\. -. -.TP -\fBset\fR: -. -.IP -Set a transient value\. <expiration> is the time until expiration, in seconds\. -. -.TP -\fBtype\fR: -. -.IP -See wether the transients API is using an object cache or the options table\. -. -.SH "EXAMPLES" -. -.nf - -wp transient set my_key my_value 300 -. -.fi - diff --git a/man/user-create.1 b/man/user-create.1 deleted file mode 100644 index 6eadf9ec9..000000000 --- a/man/user-create.1 +++ /dev/null @@ -1,63 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-CREATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-create\fR \- Create a user\. -. -.SH "SYNOPSIS" -wp user create \fIuser\-login\fR \fIuser\-email\fR [\-\-role=\fIrole\fR] [\-\-user_pass=\fIpassword\fR] [\-\-user_registered=\fIyyyy\-mm\-dd\fR] [\-\-display_name=\fIname\fR] [\-\-porcelain] -. -.SH "OPTIONS" -. -.TP -\fB<user\-login>\fR: -. -.IP -The login of the user to create\. -. -.TP -\fB<user\-email>\fR: -. -.IP -The email address of the user to create\. -. -.TP -\fB\-\-role\fR=\fIrole\fR: -. -.IP -The role of the user to create\. Default: default role -. -.TP -\fB\-\-user_pass\fR=\fIpassword\fR: -. -.IP -The user password\. Default: randomly generated -. -.TP -\fB\-\-user_registered\fR=\fIyyyy\-mm\-dd\fR: -. -.IP -The date the user registered\. Default: current date -. -.TP -\fB\-\-display_name\fR=\fIname\fR: -. -.IP -The display name\. -. -.TP -\fB\-\-porcelain\fR: -. -.IP -Output just the new user id\. -. -.SH "EXAMPLES" -. -.nf - -wp user create bob bob@example\.com \-\-role=author -. -.fi - diff --git a/man/user-delete.1 b/man/user-delete.1 deleted file mode 100644 index d498eb415..000000000 --- a/man/user-delete.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-DELETE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-delete\fR \- Delete one or more users\. -. -.SH "SYNOPSIS" -wp user delete \fIid\fR\.\.\. [\-\-reassign=\fIid\fR] -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the user to delete\. -. -.TP -\fB\-\-reassign\fR=\fIID\fR: -. -.IP -User to reassign the posts to\. -. -.SH "EXAMPLES" -. -.nf - -wp user delete 123 \-\-reassign=567 -. -.fi - diff --git a/man/user-generate.1 b/man/user-generate.1 deleted file mode 100644 index 3c87b5c76..000000000 --- a/man/user-generate.1 +++ /dev/null @@ -1,25 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-GENERATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-generate\fR \- Generate users\. -. -.SH "SYNOPSIS" -wp user generate [\-\-count=\fInumber\fR] [\-\-role=\fIrole\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-count\fR=\fInumber\fR: -. -.IP -How many users to generate\. Default: 100 -. -.TP -\fB\-\-role\fR=\fIrole\fR: -. -.IP -The role of the generated users\. Default: default role from WP - diff --git a/man/user-import-csv.1 b/man/user-import-csv.1 deleted file mode 100644 index 0c3d07c7a..000000000 --- a/man/user-import-csv.1 +++ /dev/null @@ -1,34 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-IMPORT\-CSV" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-import\-csv\fR \- Import users from a CSV file\. -. -.SH "SYNOPSIS" -wp user import\-csv \fIfile\fR -. -.SH "OPTIONS" -. -.TP -\fB<file>\fR: -. -.IP -The CSV file of users to import\. -. -.SH "EXAMPLES" -. -.nf - -wp user import\-csv /path/to/users\.csv - -Sample users\.csv file: - -user_login,user_email,display_name,role -bobjones,bobjones@domain\.com,Bob Jones,contributor -newuser1,newuser1@domain\.com,New User,author -existinguser,existinguser@domain\.com,Existing User,administrator -. -.fi - diff --git a/man/user-list.1 b/man/user-list.1 deleted file mode 100644 index f5dac94ed..000000000 --- a/man/user-list.1 +++ /dev/null @@ -1,43 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-LIST" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-list\fR \- List users\. -. -.SH "SYNOPSIS" -wp user list [\-\-role=\fIrole\fR] [\-\-fields=\fIfields\fR] [\-\-format=\fIformat\fR] -. -.SH "OPTIONS" -. -.TP -\fB\-\-role\fR=\fIrole\fR: -. -.IP -Only display users with a certain role\. -. -.TP -\fB\-\-fields\fR=\fIfields\fR: -. -.IP -Limit the output to specific object fields\. Defaults to ID,user_login,display_name,user_email,user_registered,roles -. -.TP -\fB\-\-format\fR=\fIformat\fR: -. -.IP -Output list as table, CSV, JSON, or simply IDs\. Defaults to table\. -. -.SH "EXAMPLES" -. -.nf - -wp user list \-\-format=ids - -wp user list \-\-role=administrator \-\-format=csv - -wp user list \-\-fields=display_name,user_email -. -.fi - diff --git a/man/user-meta.1 b/man/user-meta.1 deleted file mode 100644 index 817491f42..000000000 --- a/man/user-meta.1 +++ /dev/null @@ -1,62 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-META" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-meta\fR \- Manage user custom fields\. -. -.SH "SYNOPSIS" -wp user\-meta add \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.P -wp user\-meta delete \fIid\fR \fIkey\fR -. -.P -wp user\-meta get \fIid\fR \fIkey\fR [\-\-format=\fIformat\fR] -. -.P -wp user\-meta update \fIid\fR \fIkey\fR \fIvalue\fR [\-\-format=\fIformat\fR] -. -.SH "SUBCOMMANDS" -. -.TP -\fBadd\fR: -. -.IP -Add a meta field\. -. -.TP -\fBdelete\fR: -. -.IP -Delete a meta field\. -. -.TP -\fBget\fR: -. -.IP -Get meta field value\. -. -.TP -\fBupdate\fR: -. -.IP -Update a meta field\. -. -.SH "OPTIONS" -. -.TP -\fB\-\-format=json\fR: -. -.IP -Encode/decode values as JSON\. -. -.SH "EXAMPLES" -. -.nf - -wp user\-meta set 123 description "Mary is a WordPress developer\." -. -.fi - diff --git a/man/user-remove-role.1 b/man/user-remove-role.1 deleted file mode 100644 index e6e0360a9..000000000 --- a/man/user-remove-role.1 +++ /dev/null @@ -1,28 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-REMOVE\-ROLE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-remove\-role\fR \- Remove a user\'s role\. -. -.SH "SYNOPSIS" -wp user remove\-role \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] -. -.SH "OPTIONS" -. -.TP -\fB<user\-login>\fR: -. -.IP -User ID or user login\. -. -.SH "EXAMPLES" -. -.nf - -wp user remove\-role bob -wp user remove\-role 12 -. -.fi - diff --git a/man/user-set-role.1 b/man/user-set-role.1 deleted file mode 100644 index edd5ea550..000000000 --- a/man/user-set-role.1 +++ /dev/null @@ -1,34 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-SET\-ROLE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-set\-role\fR \- Set the user role (for a particular blog)\. -. -.SH "SYNOPSIS" -wp user set\-role \fIuser\-login\fR [\fIrole\fR] [\-\-blog=\fIblog\fR] -. -.SH "OPTIONS" -. -.TP -\fB<user\-login>\fR: -. -.IP -User ID or user login\. -. -.TP -\fB[<role>]\fR: -. -.IP -Add the user with the specified role\. Defaults to blog default\. -. -.SH "EXAMPLES" -. -.nf - -wp user set\-role bob author -wp user set\-role 12 author -. -.fi - diff --git a/man/user-update.1 b/man/user-update.1 deleted file mode 100644 index 965501ff5..000000000 --- a/man/user-update.1 +++ /dev/null @@ -1,33 +0,0 @@ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "WP\-USER\-UPDATE" "1" "" "WP-CLI" -. -.SH "NAME" -\fBwp\-user\-update\fR \- Update a user\. -. -.SH "SYNOPSIS" -wp user update \fIid\fR\.\.\. \-\-\fIfield\fR=\fIvalue\fR -. -.SH "OPTIONS" -. -.TP -\fB<ID>\fR: -. -.IP -The ID of the user to update\. -. -.TP -\fB\-\-<field>\fR=\fIvalue\fR: -. -.IP -One or more fields to update\. For accepted fields, see wp_update_user()\. -. -.SH "EXAMPLES" -. -.nf - -wp user update 123 \-\-user_login=mary \-\-display_name=Mary -. -.fi - From d1cb39fa5c2fb82f2753777f4b73666a8c073f7c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 18:08:11 +0300 Subject: [PATCH 1891/5359] attempt to pass doc through a pager --- php/commands/help.php | 49 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index d1b2cc945..bd681c31a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -47,7 +47,54 @@ private static function show_help( $command ) { $out = str_replace( "\t", ' ', $out ); - echo WP_CLI::colorize( $out ); + self::pass_through_pager( WP_CLI::colorize( $out ) ); + } + + private static function launch_pager( $pager, $fd ) { + // launch pager + $descriptorspec = array( + 0 => $fd, + 1 => STDOUT, + 2 => array( 'pipe', 'w' ) + ); + + $r = proc_close( proc_open( $pager, $descriptorspec, $pipes ) ); + + if ( 127 == $r ) { + return false; + } + + if ( $r ) { + fwrite( STDERR, stream_get_contents( $pipes[1] ) ); + exit( $r ); + } + + return true; + } + + private static function pass_through_pager( $out ) { + // convert string to file handle + $fd = fopen( "php://temp", "r+" ); + fputs( $fd, $out ); + rewind( $fd ); + + $pagers = array( 'less -r', 'more -r' ); + foreach ( $pagers as $pager ) { + if ( self::launch_pager( $pager, $fd ) ) + return; + } + + // no pager found + echo $out; + } + + private static function find( $candidates, $callback ) { + foreach ( $candidates as $candidate ) { + if ( call_user_func( $callback, $candidate ) ) + return $candidate; + } + + return false; } private static function get_initial_markdown( $command ) { From c60ed18bd0fecfdf5c12cae74a02f8a2d5c9f26f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 19:40:22 +0300 Subject: [PATCH 1892/5359] behat: use `@when` flag for testing --require see #453 --- features/flags.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index dc73efbf4..003311672 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -74,10 +74,13 @@ Feature: Global flags """ Scenario: Using --require - Given a WP install + Given an empty directory And a custom-cmd.php file: """ <?php + /** + * @when before_wp_load + */ class Test_Command extends WP_CLI_Command { function req( $args, $assoc_args ) { From 1b80fdffc015f9624e431d073a3377b68481b3fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Jun 2013 19:54:46 -0700 Subject: [PATCH 1893/5359] When specifying a `--version` for a plugin, always install that version. Previous behavior was to quit if the plugin was already installed. --- php/commands/plugin.php | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c96d85465..54639bc3f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -164,23 +164,29 @@ protected function install_from_repo( $slug, $assoc_args ) { WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); switch ( $status['status'] ) { - case 'update_available': - case 'install': - $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = $upgrader->install( $api->download_link ); - - if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } - break; - case 'newer_installed': - WP_CLI::error( sprintf( 'Newer version (%s) installed.', $status['version'] ) ); - break; - case 'latest_installed': - WP_CLI::error( 'Latest version already installed.' ); - break; + case 'latest_installed': + WP_CLI::error( 'Latest version already installed.' ); + break; + + // Newer installed plugin, but we might want the older version + case 'newer_installed': + case 'update_available': + if ( isset( $assoc_args['version'] ) + && version_compare( $status['version'], $assoc_args['version'], '>=' ) ) { + list( $file, $name ) = $this->parse_name( array( $api->slug ) ); + $this->_delete( $file ); + } + + case 'install': + $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); + $result = $upgrader->install( $api->download_link ); + + if ( $result && isset( $assoc_args['activate'] ) ) { + WP_CLI::log( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } + break; } } From 608fd04d8ab5a2acbde5c7cf7741e6c8365fb6e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 11:20:20 +0300 Subject: [PATCH 1894/5359] behat: always invoke `wp` with a command --- features/core.feature | 9 ++++++--- features/flags.feature | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index 592ba4915..fef65dca1 100644 --- a/features/core.feature +++ b/features/core.feature @@ -56,9 +56,12 @@ Feature: Manage WordPress installation And WP files And wp-config.php - When I try `wp` + When I try `wp core is-installed` Then the return code should be 1 - And STDERR should not be empty + And STDERR should contain: + """ + Can’t select database + """ When I run `wp db create` Then STDOUT should not be empty @@ -73,7 +76,7 @@ Feature: Manage WordPress installation Then the return code should be 1 And STDERR should not be empty - When I try `wp` + When I try `wp core is-installed` Then the return code should be 1 And STDERR should be: """ diff --git a/features/flags.feature b/features/flags.feature index 003311672..3c59cd236 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -45,7 +45,7 @@ Feature: Global flags admin """ - When I try `wp --user=non-existing-user` + When I try `wp --user=non-existing-user eval 'echo wp_get_current_user()->user_login;'` Then the return code should be 1 And STDERR should be: """ @@ -67,7 +67,7 @@ Feature: Global flags WP_CLI::set_logger( new Dummy_Logger ); """ - When I try `wp --require=custom-logger.php` + When I try `wp --require=custom-logger.php is-installed` Then STDOUT should be: """ log: called 'error' method From 6f432fa1e8a39ea1b3c8a3a3777777c4085d1d79 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 11:30:01 +0300 Subject: [PATCH 1895/5359] behat: don't check DB error message, since it's sometimes encoded and sometimes not. --- features/core.feature | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index fef65dca1..d0004d571 100644 --- a/features/core.feature +++ b/features/core.feature @@ -58,10 +58,7 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 - And STDERR should contain: - """ - Can’t select database - """ + And STDERR should not be empty When I run `wp db create` Then STDOUT should not be empty From e838b0beef8f28a8d12b0897325a1b463ec6864e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 14:24:03 +0300 Subject: [PATCH 1896/5359] s/blog-wide/site-wide/g --- php/commands/site.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index c027cf495..f1208a129 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -1,7 +1,7 @@ <?php /** - * Perform blog-wide operations. + * Perform site-wide operations. * * @package wp-cli */ From 8d1311c70d2a9feea181ee6c6f856b974fde415b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 14:25:22 +0300 Subject: [PATCH 1897/5359] don't mention deprecated --blog option in synopsis --- php/commands/user.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 4c1a85795..3533ec800 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -212,7 +212,7 @@ public function generate( $args, $assoc_args ) { * Set the user role (for a particular blog). * * @subcommand set-role - * @synopsis <user-login> [<role>] [--blog=<blog>] + * @synopsis <user-login> [<role>] */ public function set_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); @@ -232,7 +232,7 @@ public function set_role( $args, $assoc_args ) { * Add a role for a user. * * @subcommand add-role - * @synopsis <user-login> <role> [--blog=<blog>] + * @synopsis <user-login> <role> */ public function add_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); @@ -248,7 +248,7 @@ public function add_role( $args, $assoc_args ) { * Remove a user's role. * * @subcommand remove-role - * @synopsis <user-login> [<role>] [--blog=<blog>] + * @synopsis <user-login> [<role>] */ public function remove_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); @@ -277,7 +277,7 @@ private static function get_user_from_first_arg( $id_or_login ) { $user = get_user_by( 'login', $id_or_login ); if ( ! $user ) - WP_CLI::error( "Please specify a valid user ID or user login to remove from this blog" ); + WP_CLI::error( "Invalid user ID or login: $id_or_login" ); return $user; } @@ -324,7 +324,7 @@ public function import_csv( $args, $assoc_args ) { if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); - WP_CLI::log( "{$existing_user->user_login} added to blog as {$new_user['role']}" ); + WP_CLI::log( "{$existing_user->user_login} added as {$new_user['role']}." ); } // Create the user From 6e664d8bfc779921acbbe4c06f092cbc3e92006a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Jun 2013 14:26:38 +0300 Subject: [PATCH 1898/5359] show warning if --url doesn't receive a value --- php/WP_CLI/Runner.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 87fee0012..b383cd5f3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -98,14 +98,16 @@ private static function set_user( $assoc_args ) { } private static function set_url( $assoc_args ) { - if ( isset( $assoc_args['url'] ) ) { - $url = $assoc_args['url']; - } elseif ( isset( $assoc_args['blog'] ) ) { + if ( isset( $assoc_args['blog'] ) ) { + $assoc_args['url'] = $assoc_args['blog']; + unset( $assoc_args['blog'] ); WP_CLI::warning( 'The --blog parameter is deprecated. Use --url instead.' ); + } - $url = $assoc_args['blog']; + if ( isset( $assoc_args['url'] ) ) { + $url = $assoc_args['url']; if ( true === $url ) { - WP_CLI::line( 'usage: wp --blog=example.com' ); + WP_CLI::warning( 'The --url parameter expects a value.' ); } } elseif ( is_readable( ABSPATH . 'wp-cli-blog' ) ) { WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); From f08a43a02624a447d8728db0f5ddd558cd849812 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 13:20:44 +0300 Subject: [PATCH 1899/5359] behat: add test for relative 'require:' path in wp-cli.yml --- features/config.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/config.feature b/features/config.feature index 83813588b..a51d366c0 100644 --- a/features/config.feature +++ b/features/config.feature @@ -14,8 +14,13 @@ Feature: Have a config file Scenario: Config file in WP Root Given a WP install + And a sample.php file: + """ + <?php + """ And a wp-cli.yml file: """ + require: sample.php """ When I run `wp --info` @@ -27,6 +32,9 @@ Feature: Have a config file When I run `wp core is-installed` Then STDOUT should be empty + When I run `wp` from 'wp-content' + Then STDOUT should not be empty + Scenario: WP in a subdirectory Given a WP install in 'core' And a wp-cli.yml file: From d8aac013918d2e161772fffe9b9daccb3123a7c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 13:21:28 +0300 Subject: [PATCH 1900/5359] move 'path:' absolutization logic to Configurator --- php/WP_CLI/Configurator.php | 15 ++++++++++++--- php/WP_CLI/Runner.php | 6 ------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 70b72522b..0bbcca804 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -78,9 +78,9 @@ function parse_args( $arguments ) { * * @return array */ - function load_config( $path ) { - if ( $path ) - $config = spyc_load_file( $path ); + function load_config( $yml_file ) { + if ( $yml_file ) + $config = spyc_load_file( $yml_file ); else $config = array(); @@ -99,7 +99,16 @@ function load_config( $path ) { $sanitized_config[ $key ] = $value; } + // Make sure a config-relative 'path' is made absolute + self::absolutize( $sanitized_config['path'], dirname( $yml_file ) ); + return $sanitized_config; } + + private static function absolutize( &$path, $base ) { + if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { + $path = $base . DIRECTORY_SEPARATOR . $path; + } + } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b383cd5f3..0ce51fb0c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -278,12 +278,6 @@ public function before_wp_load() { $local_config = \WP_CLI::$configurator->load_config( $this->config_path ); - // When invoking from a subdirectory in the project, - // make sure a config-relative 'path' is made absolute - if ( !empty( $local_config['path'] ) && !\WP_CLI\Utils\is_path_absolute( $local_config['path'] ) ) { - $local_config['path'] = dirname( $this->config_path ) . DIRECTORY_SEPARATOR . $local_config['path']; - } - $this->config = $local_config; foreach ( $runtime_config as $key => $value ) { From 723e0f2004e4215a302d1d41359e8d8f53f40e28 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 13:38:54 +0300 Subject: [PATCH 1901/5359] absolutize 'require:' --- php/WP_CLI/Configurator.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 0bbcca804..e28c90f1f 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -99,8 +99,17 @@ function load_config( $yml_file ) { $sanitized_config[ $key ] = $value; } - // Make sure a config-relative 'path' is made absolute - self::absolutize( $sanitized_config['path'], dirname( $yml_file ) ); + // Make sure config-file-relative paths are made absolute. + $yml_file_dir = dirname( $yml_file ); + + if ( isset( $sanitized_config['path'] ) ) + self::absolutize( $sanitized_config['path'], $yml_file_dir ); + + if ( isset( $sanitized_config['require'] ) ) { + foreach ( $sanitized_config['require'] as &$path ) { + self::absolutize( $path, $yml_file_dir ); + } + } return $sanitized_config; } From 3673a7d2762809f8a0a6ed96ad5cd3b204fbc67f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 15:34:18 +0300 Subject: [PATCH 1902/5359] harmonize command descriptions --- php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/commands/help.php | 2 +- php/commands/media.php | 2 +- php/commands/option.php | 2 +- php/commands/transient.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index afae68221..67282fd6a 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -14,7 +14,7 @@ function __construct() { $this->name = 'wp'; - $this->shortdesc = 'Manage WordPress installations through the command-line.'; + $this->shortdesc = 'Manage WordPress through the command-line.'; } function get_extra_markdown() { diff --git a/php/commands/help.php b/php/commands/help.php index d1b2cc945..c339c6fbf 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -6,7 +6,7 @@ class Help_Command extends WP_CLI_Command { /** - * Get help on a certain topic. + * Get help on a certain command. * * @synopsis [<command>] */ diff --git a/php/commands/media.php b/php/commands/media.php index 0b73113fd..3657d3191 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -1,7 +1,7 @@ <?php /** - * Control the media library and its attachments. + * Manage attachments. * * @package wp-cli */ diff --git a/php/commands/option.php b/php/commands/option.php index f3f83404c..da3f3ceaf 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -1,7 +1,7 @@ <?php /** - * Manage WordPress options. + * Manage options. * * @package wp-cli */ diff --git a/php/commands/transient.php b/php/commands/transient.php index c7dae5961..6294a7976 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -1,7 +1,7 @@ <?php /** - * Manage WordPress transients. + * Manage transients. * * @package wp-cli */ From 16c7dd9c79bc6225fe962f887e9875842e479297 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 21:51:28 +0300 Subject: [PATCH 1903/5359] behat: add test for --url global parameter --- features/flags.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index 3c59cd236..f33e92864 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -1,5 +1,14 @@ Feature: Global flags + Scenario: Setting the URL + Given a WP install + + When I run `wp --url=localhost:8001 eval 'echo $_SERVER["SERVER_PORT"];'` + Then STDOUT should be: + """ + 8001 + """ + Scenario: Quiet run Given a WP install From f32919f56fac18c5cde937d07f455dd1130a3c45 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 21:52:39 +0300 Subject: [PATCH 1904/5359] set $_SERVER['SERVER_PORT'] --- php/utils.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/utils.php b/php/utils.php index dab686c87..de0f66bf5 100644 --- a/php/utils.php +++ b/php/utils.php @@ -156,6 +156,7 @@ function set_url_params( $url ) { $_SERVER['HTTP_HOST'] = $f('host'); $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); $_SERVER['REQUEST_URL'] = $f('path'); + $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; $_SERVER['QUERY_STRING'] = $f('query'); $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 649df2db99b25813f211e7af2f1ecc1da0fc7bd6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 22:10:13 +0300 Subject: [PATCH 1905/5359] behat: remove duplicate check in core.feature --- features/core.feature | 4 ---- 1 file changed, 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index d0004d571..27d87889f 100644 --- a/features/core.feature +++ b/features/core.feature @@ -69,10 +69,6 @@ Feature: Manage WordPress installation And wp-config.php And a database - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - When I try `wp core is-installed` Then the return code should be 1 And STDERR should be: From e1136931194e065f014ef3369fb7ceb822e41b4b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 22:55:22 +0300 Subject: [PATCH 1906/5359] behat: install WP with custom URL --- features/bootstrap/FeatureContext.php | 2 +- features/core.feature | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index eb699c29b..40928fc35 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -52,7 +52,7 @@ public static function prepare( SuiteEvent $event ) { 'wp core config' => self::$db_settings, 'wp core install' => array( - 'url' => 'http://example.com', + 'url' => 'http://localhost:8001', 'title' => 'WP CLI Site', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' diff --git a/features/core.feature b/features/core.feature index d0004d571..cbbf65701 100644 --- a/features/core.feature +++ b/features/core.feature @@ -84,8 +84,11 @@ Feature: Manage WordPress installation When I run `wp core install` Then STDOUT should not be empty - When I run `wp core version` - Then STDOUT should not be empty + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + http://localhost:8001 + """ Scenario: Full install Given a WP install From b01bbc3cc28bd042d2bc8afb8712758d2ae7d9a8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 22:55:53 +0300 Subject: [PATCH 1907/5359] append port to $_SERVER['HTTP_HOST'] --- php/utils.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index de0f66bf5..9f3f5abb9 100644 --- a/php/utils.php +++ b/php/utils.php @@ -153,12 +153,19 @@ function set_url_params( $url ) { return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; }; - $_SERVER['HTTP_HOST'] = $f('host'); + if ( isset( $url_parts['host'] ) ) { + $_SERVER['HTTP_HOST'] = $url_parts['host']; + if ( isset( $url_parts['port'] ) ) { + $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; + } + + $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); + } + $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); $_SERVER['REQUEST_URL'] = $f('path'); $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; $_SERVER['QUERY_STRING'] = $f('query'); - $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; $_SERVER['HTTP_USER_AGENT'] = ''; $_SERVER['REQUEST_METHOD'] = 'GET'; From fadef7811bc3c97ed9cf1833764df03a7779cc8b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 22:56:16 +0300 Subject: [PATCH 1908/5359] don't set $_SERVER['REQUEST_URL'] not used by WordPress and probably bogus --- php/utils.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 9f3f5abb9..72ab48445 100644 --- a/php/utils.php +++ b/php/utils.php @@ -163,7 +163,6 @@ function set_url_params( $url ) { } $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); - $_SERVER['REQUEST_URL'] = $f('path'); $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; $_SERVER['QUERY_STRING'] = $f('query'); $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 8962f408c1388b5c95582c8451a0358e7b0d797c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 23:18:28 +0300 Subject: [PATCH 1909/5359] behat: set custom port only in that specific test, since multisite installs don't like it --- features/bootstrap/FeatureContext.php | 16 ++++++++-------- features/core.feature | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 40928fc35..25836cc02 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -51,13 +51,6 @@ public static function prepare( SuiteEvent $event ) { self::$additional_args = array( 'wp core config' => self::$db_settings, - 'wp core install' => array( - 'url' => 'http://localhost:8001', - 'title' => 'WP CLI Site', - 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' - ), - 'wp core install-network' => array( 'title' => 'WP CLI Network' ) @@ -191,7 +184,14 @@ public function wp_install( $subdir = '' ) { $this->proc( 'wp core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); - $this->proc( 'wp core install' )->run_check( $subdir ); + $install_args = array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Site', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ); + + $this->proc( 'wp core install', $install_args )->run_check( $subdir ); } } diff --git a/features/core.feature b/features/core.feature index cbbf65701..c0477048a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -81,7 +81,7 @@ Feature: Manage WordPress installation Run `wp core install`. """ - When I run `wp core install` + When I run `wp core install --url='localhost:8001' --title='Test' --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty When I run `wp eval 'echo home_url();'` From 33fedb7ada301508d5059b112b3672f88e53c912 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 23:45:05 +0300 Subject: [PATCH 1910/5359] add test for --completions flag --- features/flags.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index f33e92864..8cb7107fc 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -150,3 +150,11 @@ Feature: Global flags """ [31;1mError: """ + + Scenario: Generate completions + Given an empty directory + When I run `wp --completions` + Then STDOUT should contain: + """ + transient delete get set type + """ From e35483b4656913415dbe2dc88deea4ae11936c2d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Jun 2013 23:45:52 +0300 Subject: [PATCH 1911/5359] move completions flag to 'cli' command --- php/WP_CLI/Runner.php | 15 +++------------ php/commands/cli.php | 8 ++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0ce51fb0c..5740b0de4 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -233,9 +233,10 @@ private static function back_compat_conversions( $args, $assoc_args ) { unset( $assoc_args['json'] ); } - // --{version|info} -> cli {version|info} + // --{version|info|completions} -> cli {version|info|completions} if ( empty( $args ) ) { - foreach ( array( 'version', 'info' ) as $key ) { + $special_flags = array( 'version', 'info', 'completions' ); + foreach ( $special_flags as $key ) { if ( isset( $assoc_args[ $key ] ) ) { $args = array( 'cli', $key ); break; @@ -359,16 +360,6 @@ public function after_wp_load() { // Handle --user parameter self::set_user( $this->config ); - // Handle --completions parameter - if ( isset( $this->assoc_args['completions'] ) ) { - foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { - $subcommands = $command->get_subcommands(); - - WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); - } - exit; - } - $this->_run_command(); } } diff --git a/php/commands/cli.php b/php/commands/cli.php index b371c2314..b537b1028 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -55,6 +55,14 @@ function param_dump() { function cmd_dump() { echo json_encode( self::command_to_array( WP_CLI::$root ) ); } + + function completions() { + foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { + $subcommands = $command->get_subcommands(); + + WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); + } + } } WP_CLI::add_command( 'cli', 'CLI_Command' ); From a568f674640b534481d4bab5e5a2b7c62a880129 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 12 Feb 2013 14:07:21 +1300 Subject: [PATCH 1912/5359] A wee bit of work on an import command --- php/WP_CLI/Runner.php | 4 ++++ php/commands/import.php | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 php/commands/import.php diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0ce51fb0c..7a469c788 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -351,6 +351,10 @@ public function before_wp_load() { Utils\set_url_params( 'http://example.com' ); } } + + if ( $this->cmd_starts_with( array( 'import') ) ) + define( 'WP_LOAD_IMPORTERS', true ); + } public function after_wp_load() { diff --git a/php/commands/import.php b/php/commands/import.php new file mode 100644 index 000000000..92bcfe1f4 --- /dev/null +++ b/php/commands/import.php @@ -0,0 +1,43 @@ +<?php + +class Import_Command extends WP_CLI_Command { + + /** + * Import content from a WXR file + * + * @synopsis <file> [--author_mapping=<file>] [--skip_attachments=<bool>] + */ + public function __invoke( $args, $assoc_args ) { + + list( $file ) = $args; + + $defaults = array( + 'skip_attachments' => false, + 'author_mapping' => null, + ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + + $wp_import = new WP_Import; + $wp_import->fetch_attachments = ( $assoc_args['skip_attachments'] ) ? false : true; + + $_GET = array( 'import' => 'wordpress', 'step' => 2 ); + $author_in = $user_select = array(); + // @todo properly handle mapping + foreach( array() as $in => $out ) { + $author_in[] = sanitize_user( $in, true ); + $user_select[] = $out; + } + $_POST = array( + 'imported_authors' => $author_in, + 'user_map' => $user_select, + 'fetch_attachments' => $wp_import->fetch_attachments, + ); + $wp_import->import( $file ); + + WP_CLI::success( "Import complete." ); + } + + +} + +WP_CLI::add_command( 'import', new Import_Command ); \ No newline at end of file From ffa3037f63b528439966dc2b5b8601353a80a21a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 21 Apr 2013 08:19:16 -0700 Subject: [PATCH 1913/5359] Also define `WP_IMPORTING`, as this constant can be used to determine whether a number of supplemental actions are run (or not) --- php/WP_CLI/Runner.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7a469c788..65baffdec 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -352,8 +352,10 @@ public function before_wp_load() { } } - if ( $this->cmd_starts_with( array( 'import') ) ) + if ( $this->cmd_starts_with( array( 'import') ) ) { define( 'WP_LOAD_IMPORTERS', true ); + define( 'WP_IMPORTING', true ); + } } From 6b131265c6d332d5234bfe1ae2dcb2e4ee32cbb2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 21 Apr 2013 09:04:52 -0700 Subject: [PATCH 1914/5359] First pass at a refactor to make `wp import` more abstracted, and potentially support multiple importers. --- php/commands/import.php | 95 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index 92bcfe1f4..cf766875c 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -3,23 +3,67 @@ class Import_Command extends WP_CLI_Command { /** - * Import content from a WXR file + * Import content. * - * @synopsis <file> [--author_mapping=<file>] [--skip_attachments=<bool>] + * @synopsis <file> [--authors=<authors>] [--skip=<data-type>] */ public function __invoke( $args, $assoc_args ) { list( $file ) = $args; + if ( ! file_exists( $file ) ) + WP_CLI::error( "File to import doesn't exist." ); + $defaults = array( - 'skip_attachments' => false, - 'author_mapping' => null, + 'type' => 'wxr', + 'authors' => null, + 'skip' => array(), ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); + $assoc_args['file'] = $file; + + if ( ! empty( $assoc_args['skip'] ) ) + $assoc_args['skip'] = explode( ',', $assoc_args['skip'] ); + + $importer = $this->is_importer_available( $assoc_args['type'] ); + if ( is_wp_error( $importer ) ) + WP_CLI::error( $importer->get_error_message() ); + + $ret = $this->import( $assoc_args ); + + if ( is_wp_error( $ret ) ) + WP_CLI::error( $ret->get_error_message() ); + else + WP_CLI::success( "Import complete." ); + } + + /** + * Import a file into WordPress. + */ + private function import( $args ) { + + switch( $args['type'] ) { + case 'wxr': + case 'wordpress': + $ret = $this->import_wxr( $args ); + break; + default: + $ret = new WP_Error( 'missing-import-type', "Import type doesn't exist." ); + break; + } + return $ret; + } + + /** + * Import a WXR file + */ + private function import_wxr( $args ) { + $wp_import = new WP_Import; - $wp_import->fetch_attachments = ( $assoc_args['skip_attachments'] ) ? false : true; + $wp_import->fetch_attachments = ( in_array( 'attachment', $args['skip'] ) ) ? false : true; + $_GET = array( 'import' => 'wordpress', 'step' => 2 ); $author_in = $user_select = array(); // @todo properly handle mapping @@ -28,13 +72,42 @@ public function __invoke( $args, $assoc_args ) { $user_select[] = $out; } $_POST = array( - 'imported_authors' => $author_in, - 'user_map' => $user_select, - 'fetch_attachments' => $wp_import->fetch_attachments, - ); - $wp_import->import( $file ); + 'imported_authors' => $author_in, + 'user_map' => $user_select, + 'fetch_attachments' => $wp_import->fetch_attachments, + ); + $wp_import->import( $args['file'] ); + + return true; + } + + /** + * Is the requested importer available? + */ + private function is_importer_available( $importer ) { + + require_once ABSPATH . 'wp-admin/includes/plugin.php'; - WP_CLI::success( "Import complete." ); + switch ( $importer ) { + case 'wxr': + case 'wordpress': + if ( class_exists( 'WP_Import' ) ) { + $ret = true; + } else { + $plugins = get_plugins(); + $wordpress_importer = 'wordpress-importer/wordpress-importer.php'; + if ( array_key_exists( $wordpress_importer, $plugins ) ) + $error_msg = "WordPress Importer needs to be activated. Try 'wp plugin activate wordpress-importer'."; + else + $error_msg = "WordPress Importer needs to be installed. Try 'wp plugin install wordpress-importer --activate'."; + $ret = new WP_Error( 'importer-missing', $error_msg ); + } + break; + default: + $ret = new WP_Error( 'missing-import-type', "Import type doesn't exist." ); + break; + } + return $ret; } From 630086271cc0151de45e6b7078ee96036ff36bd0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 21 Apr 2013 11:20:02 -0700 Subject: [PATCH 1915/5359] Incorporate author mapping support into the WordPress importer. * If a .csv filename is specified, it will look for an author mapping file. * If the .csv author mapping file doesn't exist, it will create one for you and wait for you to edit. * `--authors=create` will create any missing users, and expect that either user_email or user_logins map up directly. * `--authors=skip` will ignore any byline mapping. --- php/commands/import.php | 119 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 7 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index cf766875c..40e1c510c 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -61,16 +61,80 @@ private function import( $args ) { private function import_wxr( $args ) { $wp_import = new WP_Import; + $import_data = $wp_import->parse( $args['file'] ); + if ( is_wp_error( $import_data ) ) + return $import_data; - $wp_import->fetch_attachments = ( in_array( 'attachment', $args['skip'] ) ) ? false : true; - - $_GET = array( 'import' => 'wordpress', 'step' => 2 ); $author_in = $user_select = array(); - // @todo properly handle mapping - foreach( array() as $in => $out ) { - $author_in[] = sanitize_user( $in, true ); - $user_select[] = $out; + if ( file_exists( $args['authors'] ) ) { + foreach ( new \WP_CLI\Iterators\CSV( $args['authors'] ) as $i => $author ) { + if ( ! array_key_exists( 'old_user_login', $author ) || ! array_key_exists( 'new_user_login', $author ) ) + return new WP_Error( 'invalid-author-mapping', "Author mapping file isn't properly formatted." ); + + $author_in[] = $author['old_user_login']; + $user_select[] = $author['new_user_login']; + } + } else if ( false !== stripos( $args['authors'], '.csv' ) ) { + if ( touch( $args['authors'] ) ) { + $author_mapping = array(); + foreach( $import_data['authors'] as $wxr_author ) { + $author_mapping[] = array( + 'old_user_login' => $wxr_author['author_login'], + 'new_user_login' => $this->suggest_user( $wxr_author['author_login'], $wxr_author['author_email'] ), + ); + } + $file = fopen( $args['authors'], 'w' ); + \WP_CLI\utils\write_csv( $file, $author_mapping, array( 'old_user_login', 'new_user_login' ) ); + WP_CLI::success( sprintf( "Please update author mapping file before continuing: %s", $args['authors'] ) ); + exit; + } else { + return new WP_Error( 'author-mapping-error', "Couldn't create author mapping file." ); + } + } else { + switch( $args['authors'] ) { + // Create authors if they don't yet exist; maybe match on email or user_login + case 'create': + foreach( $import_data['authors'] as $author ) { + + if ( $user = get_user_by( 'email', $author['author_email'] ) ) { + $author_in[] = $author['author_login']; + $user_select[] = $user->user_login; + continue; + } + + if ( $user = get_user_by( 'login', $author['author_login'] ) ) { + $author_in[] = $author['author_login']; + $user_select[] = $user->user_login; + continue; + } + + $user = array( + 'user_login' => $author['author_login'], + 'user_email' => $author['author_email'], + 'display_name' => $author['author_display_name'], + 'first_name' => $author['author_first_name'], + 'last_name' => $author['author_last_name'], + 'user_pass' => wp_generate_password(), + ); + $user_id = wp_insert_user( $user ); + if ( is_wp_error( $user_id ) ) + return $user_id; + + $user = get_user_by( 'id', $user_id ); + $author_in[] = $author['author_login']; + $user_select[] = $user->user_login; + } + break; + // Skip any sort of author mapping + case 'skip': + break; + default: + return new WP_Error( 'invalid-argument', "'authors' argument is invalid." ); + } } + + $wp_import->fetch_attachments = ( in_array( 'attachment', $args['skip'] ) ) ? false : true; + $_GET = array( 'import' => 'wordpress', 'step' => 2 ); $_POST = array( 'imported_authors' => $author_in, 'user_map' => $user_select, @@ -110,6 +174,47 @@ private function is_importer_available( $importer ) { return $ret; } + /** + * Suggest a blog user based on the levenshtein distance + */ + private function suggest_user( $author_user_login, $author_user_email = '' ) { + + if ( ! isset( $this->blog_users ) ) + $this->blog_users = get_users(); + + $shortest = -1; + $shortestavg = array(); + + $threshold = floor( ( strlen( $author_user_login ) / 100 ) * 10 ); // 10 % of the strlen are valid + $closest = ''; + foreach ( $this->blog_users as $user ) { + // Before we resort to an algorithm, let's try for an exact match + if ( $author_user_email && $user->user_email == $author_user_email ) + return $user->user_login; + + $levs[] = levenshtein( $author_user_login, $user->display_name ); + $levs[] = levenshtein( $author_user_login, $user->user_login ); + $levs[] = levenshtein( $author_user_login, $user->user_email ); + $levs[] = levenshtein( $author_user_login, array_shift( explode( "@", $user->user_email ) ) ); + arsort( $levs ); + $lev = array_pop( $levs ); + if ( 0 == $lev ) { + $closest = $user->user_login; + $shortest = 0; + break; + } + + if ( ( $lev <= $shortest || $shortest < 0 ) && $lev <= $threshold ) { + $closest = $user->user_login; + $shortest = $lev; + } + $shortestavg[] = $lev; + } + // in case all usernames have a common pattern + if ( $shortest > ( array_sum( $shortestavg ) / count( $shortestavg ) ) ) + return ''; + return $closest; + } } From dcec61f962e00fb8d502fbf0bd263aa2c5be2aeb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 21 Apr 2013 12:29:45 -0700 Subject: [PATCH 1916/5359] Refactor author mapping code so it can be used with other importers --- php/commands/import.php | 220 ++++++++++++++++++++++++++++------------ 1 file changed, 154 insertions(+), 66 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index 40e1c510c..954567dd1 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -65,74 +65,47 @@ private function import_wxr( $args ) { if ( is_wp_error( $import_data ) ) return $import_data; - $author_in = $user_select = array(); - if ( file_exists( $args['authors'] ) ) { - foreach ( new \WP_CLI\Iterators\CSV( $args['authors'] ) as $i => $author ) { - if ( ! array_key_exists( 'old_user_login', $author ) || ! array_key_exists( 'new_user_login', $author ) ) - return new WP_Error( 'invalid-author-mapping', "Author mapping file isn't properly formatted." ); - - $author_in[] = $author['old_user_login']; - $user_select[] = $author['new_user_login']; - } - } else if ( false !== stripos( $args['authors'], '.csv' ) ) { - if ( touch( $args['authors'] ) ) { - $author_mapping = array(); - foreach( $import_data['authors'] as $wxr_author ) { - $author_mapping[] = array( - 'old_user_login' => $wxr_author['author_login'], - 'new_user_login' => $this->suggest_user( $wxr_author['author_login'], $wxr_author['author_email'] ), - ); - } - $file = fopen( $args['authors'], 'w' ); - \WP_CLI\utils\write_csv( $file, $author_mapping, array( 'old_user_login', 'new_user_login' ) ); - WP_CLI::success( sprintf( "Please update author mapping file before continuing: %s", $args['authors'] ) ); - exit; - } else { - return new WP_Error( 'author-mapping-error', "Couldn't create author mapping file." ); - } - } else { - switch( $args['authors'] ) { - // Create authors if they don't yet exist; maybe match on email or user_login - case 'create': - foreach( $import_data['authors'] as $author ) { - - if ( $user = get_user_by( 'email', $author['author_email'] ) ) { - $author_in[] = $author['author_login']; - $user_select[] = $user->user_login; - continue; - } - - if ( $user = get_user_by( 'login', $author['author_login'] ) ) { - $author_in[] = $author['author_login']; - $user_select[] = $user->user_login; - continue; - } - - $user = array( - 'user_login' => $author['author_login'], - 'user_email' => $author['author_email'], - 'display_name' => $author['author_display_name'], - 'first_name' => $author['author_first_name'], - 'last_name' => $author['author_last_name'], - 'user_pass' => wp_generate_password(), - ); - $user_id = wp_insert_user( $user ); - if ( is_wp_error( $user_id ) ) - return $user_id; - - $user = get_user_by( 'id', $user_id ); - $author_in[] = $author['author_login']; - $user_select[] = $user->user_login; - } - break; - // Skip any sort of author mapping - case 'skip': - break; - default: - return new WP_Error( 'invalid-argument', "'authors' argument is invalid." ); - } + // Prepare the data to be used in process_author_mapping(); + $wp_import->get_authors_from_import( $import_data ); + $author_data = array(); + foreach( $wp_import->authors as $wxr_author ) { + $author = new \stdClass; + // Always in the WXR + $author->user_login = $wxr_author['author_login']; + $author->user_email = $wxr_author['author_email']; + + // Should be in the WXR; no guarantees + if ( isset( $wxr_author['author_display_name'] ) ) + $author->display_name = $wxr_author['author_display_name']; + if ( isset( $wxr_author['author_first_name'] ) ) + $author->first_name = $wxr_author['author_first_name']; + if ( isset( $wxr_author['author_last_name'] ) ) + $author->last_name = $wxr_author['author_last_name']; + + $author_data[] = $author; } + // Build the author mapping + $author_mapping = $this->process_author_mapping( $args['authors'], $author_data ); + if ( is_wp_error( $author_mapping ) ) + return $author_mapping; + + $author_in = wp_list_pluck( $author_mapping, 'old_user_login' ); + $author_out = wp_list_pluck( $author_mapping, 'new_user_login' ); + // $user_select needs to be an array of user IDs + $user_select = array(); + $invalid_user_select = array(); + foreach( $author_out as $author_login ) { + $user = get_user_by( 'login', $author_login ); + if ( $user ) + $user_select[] = $user->ID; + else + $invalid_user_select[] = $author_login; + } + if ( ! empty( $invalid_user_select ) ) + return new WP_Error( 'invalid-author-mapping', sprintf( "These user_logins are invalid: %s", implode( ',', $invalid_user_select ) ) ); + + // Drive the import $wp_import->fetch_attachments = ( in_array( 'attachment', $args['skip'] ) ) ? false : true; $_GET = array( 'import' => 'wordpress', 'step' => 2 ); $_POST = array( @@ -174,6 +147,121 @@ private function is_importer_available( $importer ) { return $ret; } + /** + * Process how the authors should be mapped + * + * @param string $authors_arg The `--author` argument originally passed to command + * @param array $author_data An array of WP_User-esque author objects + * @return array|WP_Error $author_mapping Author mapping array if successful, WP_Error if something bad happened + */ + private function process_author_mapping( $authors_arg, $author_data ) { + + // Provided an author mapping file (method checks validity) + if ( file_exists( $authors_arg ) ) + return $this->read_author_mapping_file( $authors_arg ); + + // Provided a file reference, but the file doesn't yet exist + if ( false !== stripos( $authors_arg, '.csv' ) ) + return $this->create_author_mapping_file( $authors_arg, $author_data ); + + switch( $authors_arg ) { + // Create authors if they don't yet exist; maybe match on email or user_login + case 'create': + return $this->create_authors_for_mapping( $author_data ); + break; + // Skip any sort of author mapping + case 'skip': + return array(); + break; + default: + return new WP_Error( 'invalid-argument', "'authors' argument is invalid." ); + } + } + + /** + * Read an author mapping file + */ + private function read_author_mapping_file( $file ) { + + $author_mapping = array(); + foreach ( new \WP_CLI\Iterators\CSV( $file ) as $i => $author ) { + if ( ! array_key_exists( 'old_user_login', $author ) || ! array_key_exists( 'new_user_login', $author ) ) + return new WP_Error( 'invalid-author-mapping', "Author mapping file isn't properly formatted." ); + + $author_mapping[] = $author; + } + return $author_mapping; + } + + /** + * Create an author mapping file, based on provided author data + * + * @return WP_Error The file was just now created, so some action needs to be taken + */ + private function create_author_mapping_file( $file, $author_data ) { + + if ( touch( $file ) ) { + $author_mapping = array(); + foreach( $author_data as $author ) { + $author_mapping[] = array( + 'old_user_login' => $author->user_login, + 'new_user_login' => $this->suggest_user( $author->user_login, $author->user_email ), + ); + } + $file_resource = fopen( $file, 'w' ); + \WP_CLI\utils\write_csv( $file_resource, $author_mapping, array( 'old_user_login', 'new_user_login' ) ); + return new WP_Error( 'author-mapping-error', sprintf( "Please update author mapping file before continuing: %s", $file ) ); + } else { + return new WP_Error( 'author-mapping-error', "Couldn't create author mapping file." ); + } + } + + /** + * Create users if they don't exist, and build an author mapping file + */ + private function create_authors_for_mapping( $author_data ) { + + $author_mapping = array(); + foreach( $author_data as $author ) { + + if ( isset( $author->user_email ) ) { + if ( $user = get_user_by( 'email', $author->user_email ) ) { + $author_mapping[] = array( + 'old_user_login' => $author->user_login, + 'new_user_login' => $user->user_login, + ); + continue; + } + } + + if ( $user = get_user_by( 'login', $author->user_login ) ) { + $author_mapping[] = array( + 'old_user_login' => $author->user_login, + 'new_user_login' => $user->user_login, + ); + continue; + } + + $user = array( + 'user_login' => '', + 'user_email' => '', + 'user_pass' => wp_generate_password(), + ); + $user = array_merge( $user, (array)$author ); + $user_id = wp_insert_user( $user ); + if ( is_wp_error( $user_id ) ) + return $user_id; + + $user = get_user_by( 'id', $user_id ); + $author_mapping[] = array( + 'old_user_login' => $author->user_login, + 'new_user_login' => $user->user_login, + ); + } + return $author_mapping; + + } + /** * Suggest a blog user based on the levenshtein distance */ From 19d06afd92ac4ae9cf13633f42efe06a79bf655b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Thu, 25 Apr 2013 17:29:34 +0000 Subject: [PATCH 1917/5359] Make the `--authors` argument required. It's a very necessary step, even if just to have the user confirm they're skipping mappings. --- php/commands/import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index 954567dd1..f682287cd 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -5,7 +5,7 @@ class Import_Command extends WP_CLI_Command { /** * Import content. * - * @synopsis <file> [--authors=<authors>] [--skip=<data-type>] + * @synopsis <file> --authors=<authors> [--skip=<data-type>] */ public function __invoke( $args, $assoc_args ) { From 52da29f162ea314bead853554d1ba92c99531a78 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <danielbachhuber@gmail.com> Date: Mon, 24 Jun 2013 12:41:30 +0000 Subject: [PATCH 1918/5359] Incorporate @mjangda's helpful verbosity filters --- php/commands/import.php | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/php/commands/import.php b/php/commands/import.php index f682287cd..80240fac5 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -46,6 +46,7 @@ private function import( $args ) { switch( $args['type'] ) { case 'wxr': case 'wordpress': + $this->add_wxr_filters(); $ret = $this->import_wxr( $args ); break; default: @@ -118,6 +119,65 @@ private function import_wxr( $args ) { return true; } + /** + * Useful verbosity filters for the WXR importer + */ + private function add_wxr_filters() { + + add_filter( 'wp_import_posts', function( $posts ) { + global $wpcli_import_counts; + $wpcli_import_counts['current_post'] = 0; + $wpcli_import_counts['total_posts'] = count( $posts ); + return $posts; + }, 10 ); + + add_filter( 'wp_import_post_comments', function( $comments, $post_id, $post ) { + global $wpcli_import_counts; + $wpcli_import_counts['current_comment'] = 0; + $wpcli_import_counts['total_comments'] = count( $comments ); + return $comments; + }, 10, 3 ); + + add_filter( 'wp_import_post_data_raw', function( $post ) { + global $wpcli_import_counts; + + $wpcli_import_counts['current_post']++; + WP_CLI::line(); + WP_CLI::line(); + WP_CLI::line( sprintf( 'Processing post #%d ("%s") (post_type: %s)', $post['post_id'], $post['post_title'], $post['post_type'] ) ); + WP_CLI::line( sprintf( '-- %s of %s', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ) ) ); + WP_CLI::line( '-- ' . date( 'r' ) ); + + return $post; + } ); + + add_action( 'wp_import_insert_post', function( $post_id, $original_post_ID, $post, $postdata ) { + if ( is_wp_error( $post_id ) ) + WP_CLI::warning( "-- Error importing post: " . $post_id->get_error_code() ); + else + WP_CLI::line( "-- Imported post as post_id #{$post_id}" ); + }, 10, 4 ); + + add_action( 'wp_import_insert_term', function( $t, $import_term, $post_id, $post ) { + WP_CLI::line( "-- Created term \"{$import_term['name']}\"" ); + }, 10, 4 ); + + add_action( 'wp_import_set_post_terms', function( $tt_ids, $term_ids, $taxonomy, $post_id, $post ) { + WP_CLI::line( "-- Added terms (" . implode( ',', $term_ids ) .") for taxonomy \"{$taxonomy}\"" ); + }, 10, 5 ); + + add_action( 'wp_import_insert_comment', function( $comment_id, $comment, $comment_post_ID, $post ) { + global $wpcli_import_counts; + $wpcli_import_counts['current_comment']++; + WP_CLI::line( sprintf( '-- Added comment #%d (%s of %s)', $comment_id, number_format( $wpcli_import_counts['current_comment'] ), number_format( $wpcli_import_counts['total_comments'] ) ) ); + }, 10, 4 ); + + add_action( 'import_post_meta', function( $post_id, $key, $value ) { + WP_CLI::line( "-- Added post_meta $key" ); + }, 10, 3 ); + + } + /** * Is the requested importer available? */ From b48cf5d059364ab2ae383731b3e0eb8dba1bf0fe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Jun 2013 10:48:58 -0700 Subject: [PATCH 1919/5359] Allow a subset of STDOUT and STDERR to be used with a syntax like: `'Writing to file %s'` --- features/steps/basic_steps.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index c90c4a736..8198bf7b7 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -126,9 +126,19 @@ function ( $world ) { } ); -$steps->Given( '/^save (STDOUT|STDERR) as \{(\w+)\}$/', - function ( $world, $stream, $key ) { - $world->variables[ $key ] = rtrim( $world->result->$stream, "\n" ); +$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', + function ( $world, $stream, $output_filter, $key ) { + + if ( $output_filter ) { + $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; + if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) + $output = array_pop( $matches ); + else + $output = ''; + } else { + $output = $world->result->$stream; + } + $world->variables[ $key ] = trim( $output, "\n" ); } ); From 9b757f990326f36a95b80285cba0606668bedd00 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Jun 2013 10:50:47 -0700 Subject: [PATCH 1920/5359] Basic feature test for import command --- features/import.feature | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 features/import.feature diff --git a/features/import.feature b/features/import.feature new file mode 100644 index 000000000..ffab45b5e --- /dev/null +++ b/features/import.feature @@ -0,0 +1,44 @@ +Feature: Import content. + +Scenario: Basic export then import + Given a WP install + + When I run `wp post generate --post_type=post --count=3` + Then STDOUT should not be empty + + When I run `wp post generate --post_type=page --count=2` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=csv | wc -l` + Then STDOUT should be: + """ + 8 + """ + + When I run `wp export` + Then STDOUT should contain: + """ + All done with export + """ + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=csv | wc -l` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should not be empty + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=csv | wc -l` + Then STDOUT should be: + """ + 8 + """ \ No newline at end of file From 11f18c8ec3cfa891f22439a7f04ab67a7d9da738 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Jun 2013 11:04:31 -0700 Subject: [PATCH 1921/5359] Update docs --- man-src/import.txt | 13 +++++++++++++ php/commands/import.php | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 man-src/import.txt diff --git a/man-src/import.txt b/man-src/import.txt new file mode 100644 index 000000000..8a26f302e --- /dev/null +++ b/man-src/import.txt @@ -0,0 +1,13 @@ +## OPTIONS + +* `<file>`: + + Path to a valid WXR file for importing. + +* `--authors=<authors>`: + + How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. + +* `--skip=<data-type>`: + + Skip importing specific data. Supported option is 'attachment'. \ No newline at end of file diff --git a/php/commands/import.php b/php/commands/import.php index 80240fac5..b9f41b8af 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -3,7 +3,7 @@ class Import_Command extends WP_CLI_Command { /** - * Import content. + * Import content from a WXR file. * * @synopsis <file> --authors=<authors> [--skip=<data-type>] */ From c5e1f4212b99610386deb5d97b198aad7959a8ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Jun 2013 14:10:49 -0700 Subject: [PATCH 1922/5359] For most `wp user` subcommands, the first argument can be user ID or login --- php/commands/user.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 3533ec800..d4b23b3f9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -59,13 +59,14 @@ public function _list( $args, $assoc_args ) { /** * Delete one or more users. * - * @synopsis <id>... [--reassign=<id>] + * @synopsis <user>... [--reassign=<id>] */ public function delete( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( 'reassign' => null ) ); + $args[0] = self::get_user_from_first_arg( $args[0] )->ID; parent::delete( $args, $assoc_args ); } @@ -145,9 +146,11 @@ protected function _create( $params ) { /** * Update a user. * - * @synopsis <id>... --<field>=<value> + * @synopsis <user>... --<field>=<value> */ public function update( $args, $assoc_args ) { + + $args[0] = self::get_user_from_first_arg( $args[0] )->ID; parent::update( $args, $assoc_args, 'user' ); } @@ -212,7 +215,7 @@ public function generate( $args, $assoc_args ) { * Set the user role (for a particular blog). * * @subcommand set-role - * @synopsis <user-login> [<role>] + * @synopsis <user> [<role>] */ public function set_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); @@ -232,7 +235,7 @@ public function set_role( $args, $assoc_args ) { * Add a role for a user. * * @subcommand add-role - * @synopsis <user-login> <role> + * @synopsis <user> <role> */ public function add_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); @@ -248,7 +251,7 @@ public function add_role( $args, $assoc_args ) { * Remove a user's role. * * @subcommand remove-role - * @synopsis <user-login> [<role>] + * @synopsis <user> [<role>] */ public function remove_role( $args, $assoc_args ) { $user = self::get_user_from_first_arg( $args[0] ); From 2e144908c25126c26f43c27c2b0c6393da177947 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Jun 2013 14:14:18 -0700 Subject: [PATCH 1923/5359] Update documentation --- man-src/user-delete.txt | 4 ++-- man-src/user-remove-role.txt | 2 +- man-src/user-set-role.txt | 2 +- man-src/user-update.txt | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/man-src/user-delete.txt b/man-src/user-delete.txt index 920282f7e..88d8966a1 100644 --- a/man-src/user-delete.txt +++ b/man-src/user-delete.txt @@ -1,8 +1,8 @@ ## OPTIONS -* `<ID>`: +* `<user>`: - The ID of the user to delete. + The user login or ID of the user to delete. * `--reassign`=<ID>: diff --git a/man-src/user-remove-role.txt b/man-src/user-remove-role.txt index c85990bd4..b4a77e47d 100644 --- a/man-src/user-remove-role.txt +++ b/man-src/user-remove-role.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `<user-login>`: +* `<user>`: User ID or user login. diff --git a/man-src/user-set-role.txt b/man-src/user-set-role.txt index 3c5050f0e..84190293b 100644 --- a/man-src/user-set-role.txt +++ b/man-src/user-set-role.txt @@ -1,6 +1,6 @@ ## OPTIONS -* `<user-login>`: +* `<user>`: User ID or user login. diff --git a/man-src/user-update.txt b/man-src/user-update.txt index 9a93a9f81..092ab8b59 100644 --- a/man-src/user-update.txt +++ b/man-src/user-update.txt @@ -1,8 +1,8 @@ ## OPTIONS -* `<ID>`: +* `<user>`: - The ID of the user to update. + The user login or ID of the user to update. * `--<field>`=<value>: @@ -11,3 +11,5 @@ ## EXAMPLES wp user update 123 --user_login=mary --display_name=Mary + + wp user update mary --user_pass=marypass From f7c0354a8f9bf8e93811824000631aa435bb7cf3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Jun 2013 14:25:20 -0700 Subject: [PATCH 1924/5359] Have the success message appear on its own line https://github.com/wp-cli/wp-cli/pull/299#issuecomment-20008252 --- php/commands/import.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index b9f41b8af..c904e53c0 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -32,10 +32,12 @@ public function __invoke( $args, $assoc_args ) { $ret = $this->import( $assoc_args ); - if ( is_wp_error( $ret ) ) + if ( is_wp_error( $ret ) ) { WP_CLI::error( $ret->get_error_message() ); - else + } else { + WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line WP_CLI::success( "Import complete." ); + } } /** From 8329d4b0e4f2217a48c96c12a81584fa70a70854 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 15:39:31 +0300 Subject: [PATCH 1925/5359] copy files from wp-includes/export verbatim --- php/export/class-wp-export-oxymel.php | 27 ++ php/export/class-wp-export-query.php | 311 +++++++++++++++++++ php/export/class-wp-export-wxr-formatter.php | 262 ++++++++++++++++ php/export/functions.export.php | 30 ++ php/export/writers.php | 145 +++++++++ 5 files changed, 775 insertions(+) create mode 100644 php/export/class-wp-export-oxymel.php create mode 100644 php/export/class-wp-export-query.php create mode 100644 php/export/class-wp-export-wxr-formatter.php create mode 100644 php/export/functions.export.php create mode 100644 php/export/writers.php diff --git a/php/export/class-wp-export-oxymel.php b/php/export/class-wp-export-oxymel.php new file mode 100644 index 000000000..6c2bc9674 --- /dev/null +++ b/php/export/class-wp-export-oxymel.php @@ -0,0 +1,27 @@ +<?php + +require_once ABSPATH . WPINC . '/Oxymel.php'; + +class WP_Export_Oxymel extends Oxymel { + public function optional( $tag_name, $contents ) { + if ( $contents ) { + $this->$tag_name( $contents ); + } + return $this; + } + + public function optional_cdata( $tag_name, $contents ) { + if ( $contents ) { + $this->$tag_name->contains->cdata( $contents )->end; + } + return $this; + } + + public function cdata( $text ) { + if ( !seems_utf8( $text ) ) { + $text = utf8_encode( $text ); + } + return parent::cdata( $text ); + } +} + diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php new file mode 100644 index 000000000..5522cc06a --- /dev/null +++ b/php/export/class-wp-export-query.php @@ -0,0 +1,311 @@ +<?php +/** + * Represents a set of posts and other site data to be exported. + * + * An immutable object, which gathers all data needed for the export. + */ +class WP_Export_Query { + const QUERY_CHUNK = 100; + + private static $defaults = array( + 'post_ids' => null, + 'post_type' => null, + 'status' => null, + 'author' => null, + 'start_date' => null, + 'end_date' => null, + 'category' => null, + ); + + private $post_ids; + private $filters; + private $xml_gen; + + private $wheres = array(); + private $joins = array(); + + private $author; + private $category; + + public function __construct( $filters = array() ) { + $this->filters = wp_parse_args( $filters, self::$defaults ); + $this->post_ids = $this->calculate_post_ids(); + } + + public function post_ids() { + return $this->post_ids; + } + + public function charset() { + return get_bloginfo( 'charset' ); + } + + public function site_metadata() { + $metadata = array( + 'name' => $this->bloginfo_rss( 'name' ), + 'url' => $this->bloginfo_rss( 'url' ), + 'language' => $this->bloginfo_rss( 'language' ), + 'description' => $this->bloginfo_rss( 'description' ), + 'pubDate' => date( 'D, d M Y H:i:s +0000' ), + 'site_url' => is_multisite()? network_home_url() : $this->bloginfo_rss( 'url' ), + 'blog_url' => $this->bloginfo_rss( 'url' ), + ); + return $metadata; + } + + public function wp_generator_tag() { + return apply_filters( 'the_generator', get_the_generator( 'export' ), 'export' ); + } + + public function authors() { + global $wpdb; + $authors = array(); + $author_ids = $wpdb->get_col( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" ); + foreach ( (array) $author_ids as $author_id ) { + $authors[] = get_userdata( $author_id ); + } + $authors = array_filter( $authors ); + return $authors; + } + + public function categories() { + if ( $this->category ) { + return array( $this->category ); + } + if ( $this->filters['post_type'] ) { + return array(); + } + $categories = (array) get_categories( array( 'get' => 'all' ) ); + $categories = self::topologically_sort_terms( $categories ); + return $categories; + } + + public function tags() { + if ( $this->filters['post_type'] ) { + return array(); + } + $tags = (array) get_tags( array( 'get' => 'all' ) ); + return $tags; + } + + public function custom_taxonomies_terms() { + if ( $this->filters['post_type'] ) { + return array(); + } + $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); + $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); + $custom_terms = self::topologically_sort_terms( $custom_terms ); + return $custom_terms; + } + + public function nav_menu_terms() { + $nav_menus = wp_get_nav_menus(); + foreach( $nav_menus as &$term ) { + $term->description = ''; + } + return $nav_menus; + } + + public function exportify_post( $post ) { + $GLOBALS['wp_query']->in_the_loop = true; + $previous_global_post = isset( $GLOBALS['post'] )? $GLOBALS['post'] : null; + $GLOBALS['post'] = $post; + setup_postdata( $post ); + $post->post_content = apply_filters( 'the_content_export', $post->post_content ); + $post->post_excerpt = apply_filters( 'the_excerpt_export', $post->post_excerpt ); + $post->is_sticky = is_sticky( $post->ID ) ? 1 : 0; + $post->terms = self::get_terms_for_post( $post ); + $post->meta = self::get_meta_for_post( $post ); + $post->comments = self::get_comments_for_post( $post ); + $GLOBALS['post'] = $previous_global_post; + return $post; + } + + public function posts() { + $posts_iterator = new WP_Post_IDs_Iterator( $this->post_ids, self::QUERY_CHUNK ); + return new WP_Map_Iterator( $posts_iterator, array( $this, 'exportify_post' ) ); + } + + private function calculate_post_ids() { + global $wpdb; + if ( is_array( $this->filters['post_ids'] ) ) { + return $this->filters['post_ids']; + } + $this->post_type_where(); + $this->status_where(); + $this->author_where(); + $this->start_date_where(); + $this->end_date_where(); + $this->category_where(); + + $where = implode( ' AND ', array_filter( $this->wheres ) ); + if ( $where ) $where = "WHERE $where"; + $join = implode( ' ', array_filter( $this->joins ) ); + + $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where" ); + $post_ids = array_merge( $post_ids, $this->attachments_for_specific_post_types( $post_ids ) ); + return $post_ids; + } + + private function post_type_where() { + global $wpdb; + $post_types_filters = array( 'can_export' => true ); + if ( $this->filters['post_type'] ) { + $post_types_filters = array_merge( $post_types_filters, array( 'name' => $this->filters['post_type'] ) ); + } + $post_types = get_post_types( $post_types_filters ); + if ( !$post_types ) { + $this->wheres[] = 'p.post_type IS NULL'; + return; + } + $this->wheres[] = $wpdb->build_IN_condition( 'p.post_type', $post_types ); + } + + private function status_where() { + global $wpdb; + if ( !$this->filters['status'] ) { + $this->wheres[] = "p.post_status != 'auto-draft'"; + return; + } + $this->wheres[] = $wpdb->prepare( 'p.post_status = %s', $this->filters['status'] ); + } + + private function author_where() { + global $wpdb; + $user = $this->find_user_from_any_object( $this->filters['author'] ); + if ( !$user || is_wp_error( $user ) ) { + return; + } + $this->author = $user; + $this->wheres[] = $wpdb->prepare( 'p.post_author = %d', $user->ID ); + } + + private function start_date_where() { + global $wpdb; + $timestamp = strtotime( $this->filters['start_date'] ); + if ( !$timestamp ) { + return; + } + $this->wheres[] = $wpdb->prepare( 'p.post_date >= %s', date( 'Y-m-d 00:00:00', $timestamp ) ); + } + + private function end_date_where() { + global $wpdb; + if ( preg_match( '/^\d{4}-\d{2}$/', $this->filters['end_date'] ) ) { + $timestamp = $this->get_timestamp_for_the_last_day_of_a_month( $this->filters['end_date'] ); + } else { + $timestamp = strtotime( $this->filters['end_date'] ); + } + if ( !$timestamp ) { + return; + } + $this->wheres[] = $wpdb->prepare( 'p.post_date <= %s', date( 'Y-m-d 23:59:59', $timestamp ) ); + } + + private function get_timestamp_for_the_last_day_of_a_month( $yyyy_mm ) { + return strtotime( "$yyyy_mm +1month -1day" ); + } + + private function category_where() { + global $wpdb; + if ( 'post' != $this->filters['post_type'] ) { + return; + } + $category = $this->find_category_from_any_object( $this->filters['category'] ); + if ( !$category ) { + return; + } + $this->category = $category; + $this->joins[] = "INNER JOIN {$wpdb->term_relationships} AS tr ON (p.ID = tr.object_id)"; + $this->wheres[] = $wpdb->prepare( 'tr.term_taxonomy_id = %d', $category->term_taxonomy_id ); + } + + private function attachments_for_specific_post_types( $post_ids ) { + global $wpdb; + if ( !$this->filters['post_type'] ) { + return array(); + } + $attachment_ids = array(); + while ( $batch_of_post_ids = array_splice( $post_ids, 0, self::QUERY_CHUNK ) ) { + $post_parent_condition = $wpdb->build_IN_condition( 'post_parent', $batch_of_post_ids ); + $attachment_ids = array_merge( $attachment_ids, (array)$wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND $post_parent_condition" ) ); + } + return array_map( 'intval', $attachment_ids ); + } + + private function bloginfo_rss( $section ) { + return apply_filters( 'bloginfo_rss', get_bloginfo_rss( $section ), $section ); + } + + private function find_user_from_any_object( $user ) { + if ( is_numeric( $user ) ) { + return get_user_by( 'id', $user ); + } elseif ( is_string( $user ) ) { + return get_user_by( 'login', $user ); + } elseif ( isset( $user->ID ) ) { + return get_user_by( 'id', $user->ID ); + } + return false; + } + + private function find_category_from_any_object( $category ) { + if ( is_numeric( $category ) ) { + return get_term( $category, 'category' ); + } elseif ( is_string( $category ) ) { + $term = term_exists( $category, 'category' ); + return isset( $term['term_id'] )? get_term( $term['term_id'], 'category' ) : false; + } elseif ( isset( $category->term_id ) ) { + return get_term( $category->term_id, 'category' ); + } + return false; + } + + private static function topologically_sort_terms( $terms ) { + $sorted = array(); + while ( $term = array_shift( $terms ) ) { + if ( $term->parent == 0 || isset( $sorted[$term->parent] ) ) + $sorted[$term->term_id] = $term; + else + $terms[] = $term; + } + return $sorted; + } + + private static function get_terms_for_post( $post ) { + $taxonomies = get_object_taxonomies( $post->post_type ); + if ( empty( $taxonomies ) ) + return array(); + $terms = wp_get_object_terms( $post->ID, $taxonomies ); + $terms = $terms? $terms : array(); + return $terms; + } + + private static function get_meta_for_post( $post ) { + global $wpdb; + $meta_for_export = array(); + $meta_from_db = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); + foreach ( $meta_from_db as $meta ) { + if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) + continue; + if ( in_array( $meta->meta_key, array( '_edit_lock', '_wp_attachment_metadata', '_wp_attached_file' ) ) ) { + continue; + } + $meta_for_export[] = $meta; + } + return $meta_for_export; + } + + private static function get_comments_for_post( $post ) { + global $wpdb; + $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); + foreach( $comments as $comment ) { + $meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) ); + $meta = $meta? $meta : array(); + $comment->meta = $meta; + } + return $comments; + } +} + +class WP_Export_Exception extends RuntimeException { +} diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php new file mode 100644 index 000000000..f4850ac32 --- /dev/null +++ b/php/export/class-wp-export-wxr-formatter.php @@ -0,0 +1,262 @@ +<?php +/** + * Version number for the export format. + * + * Bump this when something changes that might affect compatibility. + * + * @since 2.5.0 + */ +define( 'WXR_VERSION', '1.2' ); + +require_once ABSPATH . WPINC . '/export/class-wp-export-oxymel.php'; + +/** + * Responsible for formatting the data in WP_Export_Query to WXR + */ +class WP_Export_WXR_Formatter { + public function __construct( $export ) { + $this->export = $export; + $this->wxr_version = WXR_VERSION; + } + + public function before_posts() { + $before_posts_xml = ''; + $before_posts_xml .= $this->header(); + $before_posts_xml .= $this->site_metadata(); + $before_posts_xml .= $this->authors(); + $before_posts_xml .= $this->categories(); + $before_posts_xml .= $this->tags(); + $before_posts_xml .= $this->nav_menu_terms(); + $before_posts_xml .= $this->custom_taxonomies_terms(); + $before_posts_xml .= $this->rss2_head_action(); + return $before_posts_xml; + } + + public function posts() { + return new WP_Map_Iterator( $this->export->posts(), array( $this, 'post' ) ); + } + + public function after_posts() { + return $this->footer(); + } + + public function header() { + $oxymel = new Oxymel; + $charset = $this->export->charset(); + $wp_generator_tag = $this->export->wp_generator_tag(); + $comment = <<<COMMENT + + This is a WordPress eXtended RSS file generated by WordPress as an export of your site. + It contains information about your site's posts, pages, comments, categories, and other content. + You may use this file to transfer that content from one site to another. + This file is not intended to serve as a complete backup of your site. + + To import this information into a WordPress site follow these steps: + 1. Log in to that site as an administrator. + 2. Go to Tools: Import in the WordPress admin panel. + 3. Install the "WordPress" importer from the list. + 4. Activate & Run Importer. + 5. Upload this file using the form provided on that page. + 6. You will first be asked to map the authors in this export file to users + on the site. For each author, you may choose to map to an + existing user on the site or to create a new user. + 7. WordPress will then import each of the posts, pages, comments, categories, etc. + contained in this file into your site. + +COMMENT; + return $oxymel + ->xml + ->comment( $comment ) + ->raw( $wp_generator_tag ) + ->open_rss( array( + 'version' => '2.0', + 'xmlns:excerpt' => "http://wordpress.org/export/{$this->wxr_version}/excerpt/", + 'xmlns:content' => "http://purl.org/rss/1.0/modules/content/", + 'xmlns:wfw' => "http://wellformedweb.org/CommentAPI/", + 'xmlns:dc' => "http://purl.org/dc/elements/1.1/", + 'xmlns:wp' => "http://wordpress.org/export/{$this->wxr_version}/", + ) ) + ->open_channel + ->to_string(); + + } + + public function site_metadata() { + $oxymel = new Oxymel; + $metadata = $this->export->site_metadata(); + return $oxymel + ->title( $metadata['name'] ) + ->link( $metadata['url'] ) + ->description( $metadata['description'] ) + ->pubDate( $metadata['pubDate'] ) + ->language( $metadata['language'] ) + ->tag( 'wp:wxr_version', $this->wxr_version ) + ->tag( 'wp:base_site_url', $metadata['site_url'] ) + ->tag( 'wp:base_blog_url', $metadata['blog_url'] ) + ->to_string(); + } + + public function authors() { + $oxymel = new Oxymel; + $authors = $this->export->authors(); + foreach ( $authors as $author ) { + $oxymel + ->tag( 'wp:wp_author' )->contains + ->tag( 'wp:author_login', $author->user_login ) + ->tag( 'wp:author_email', $author->user_email ) + ->tag( 'wp:author_display_name' )->contains->cdata( $author->display_name )->end + ->tag( 'wp:author_first_name' )->contains->cdata( $author->user_first_name )->end + ->tag( 'wp:author_last_name' )->contains->cdata( $author->user_last_name )->end + ->end; + } + return $oxymel->to_string(); + } + + public function categories() { + $oxymel = new WP_Export_Oxymel; + $categories = $this->export->categories(); + foreach( $categories as $term_id => $category ) { + $category->parent_slug = $category->parent? $categories[$category->parent]->slug : ''; + $oxymel->tag( 'wp:category' )->contains + ->tag( 'wp:term_id', $category->term_id ) + ->tag( 'wp:category_nicename', $category->slug ) + ->tag( 'wp:category_parent', $category->parent_slug ) + ->optional_cdata( 'wp:cat_name', $category->name ) + ->optional_cdata( 'wp:category_description', $category->description ) + ->end; + } + return $oxymel->to_string(); + } + + public function tags() { + $oxymel = new WP_Export_Oxymel; + $tags = $this->export->tags(); + foreach( $tags as $tag ) { + $oxymel->tag( 'wp:tag' )->contains + ->tag( 'wp:term_id', $tag->term_id ) + ->tag( 'wp:tag_slug', $tag->slug ) + ->optional_cdata( 'wp:tag_name', $tag->name ) + ->optional_cdata( 'wp:tag_description', $tag->description ) + ->end; + } + return $oxymel->to_string(); + } + + public function nav_menu_terms() { + return $this->terms( $this->export->nav_menu_terms() ); + } + + public function custom_taxonomies_terms() { + return $this->terms( $this->export->custom_taxonomies_terms() ); + } + + public function rss2_head_action() { + ob_start(); + do_action( 'rss2_head' ); + $action_output = ob_get_clean(); + return $action_output; + } + + public function post( $post ) { + $oxymel = new WP_Export_Oxymel; + $GLOBALS['wp_query']->in_the_loop = true; + $GLOBALS['post'] = $post; + setup_postdata( $post ); + + $oxymel->item->contains + ->title( apply_filters( 'the_title_rss', $post->post_title ) ) + ->link( esc_url( apply_filters('the_permalink_rss', get_permalink() ) ) ) + ->pubDate( mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ) ) + ->tag( 'dc:creator', get_the_author_meta( 'login' ) ) + ->guid( get_the_guid(), array( 'isPermaLink' => 'false' ) ) + ->description( '' ) + ->tag( 'content:encoded' )->contains->cdata( $post->post_content )->end + ->tag( 'excerpt:encoded' )->contains->cdata( $post->post_excerpt )->end + ->tag( 'wp:post_id', $post->ID ) + ->tag( 'wp:post_date', $post->post_date ) + ->tag( 'wp:post_date_gmt', $post->post_date_gmt ) + ->tag( 'wp:comment_status', $post->comment_status ) + ->tag( 'wp:ping_status', $post->ping_status ) + ->tag( 'wp:post_name', $post->post_name ) + ->tag( 'wp:status', $post->post_status ) + ->tag( 'wp:post_parent', $post->post_parent ) + ->tag( 'wp:menu_order', $post->menu_order ) + ->tag( 'wp:post_type', $post->post_type ) + ->tag( 'wp:post_password', $post->post_password ) + ->tag( 'wp:is_sticky', $post->is_sticky ) + ->optional( 'wp:attachment_url', wp_get_attachment_url( $post->ID ) ); + foreach( $post->terms as $term ) { + $oxymel + ->category( array( 'domain' => $term->taxonomy, 'nicename' => $term->slug ) )->contains->cdata( $term->name )->end; + } + foreach( $post->meta as $meta ) { + $oxymel + ->tag( 'wp:postmeta' )->contains + ->tag( 'wp:meta_key', $meta->meta_key ) + ->tag( 'wp:meta_value' )->contains->cdata( $meta->meta_value )->end + ->end; + } + foreach( $post->comments as $comment ) { + $oxymel + ->tag( 'wp:comment' )->contains + ->tag( 'wp:comment_id', $comment->comment_ID ) + ->tag( 'wp:comment_author' )->contains->cdata( $comment->comment_author )->end + ->tag( 'wp:comment_author_email', $comment->comment_author_email ) + ->tag( 'wp:comment_author_url', esc_url( $comment->comment_author_url ) ) + ->tag( 'wp:comment_author_IP', $comment->comment_author_IP ) + ->tag( 'wp:comment_date', $comment->comment_date ) + ->tag( 'wp:comment_date_gmt', $comment->comment_date_gmt ) + ->tag( 'wp:comment_content' )->contains->cdata( $comment->comment_content )->end + ->tag( 'wp:comment_approved', $comment->comment_approved ) + ->tag( 'wp:comment_type', $comment->comment_type ) + ->tag( 'wp:comment_parent', $comment->comment_parent ) + ->tag( 'wp:comment_user_id', $comment->user_id ) + ->oxymel( $this->comment_meta( $comment ) ) + ->end; + } + $oxymel + ->end; + return $oxymel->to_string(); + } + + public function footer() { + $oxymel = new Oxymel; + return $oxymel->close_channel->close_rss->to_string(); + } + + protected function terms( $terms ) { + $oxymel = new WP_Export_Oxymel; + foreach( $terms as $term ) { + $term->parent_slug = $term->parent? $terms[$term->parent]->slug : ''; + $oxymel->tag( 'wp:term' )->contains + ->tag( 'wp:term_id', $term->term_id ) + ->tag( 'wp:term_taxonomy', $term->taxonomy ) + ->tag( 'wp:term_slug', $term->slug ); + if ( 'nav_menu' != $term->taxonomy ) { + $oxymel + ->tag( 'wp:term_parent', $term->parent_slug ); + } + $oxymel + ->optional_cdata( 'wp:term_name', $term->name ) + ->optional_cdata( 'wp:term_description', $term->description ) + ->end; + } + return $oxymel->to_string(); + } + + protected function comment_meta( $comment ) { + global $wpdb; + $metas = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) ); + if ( !$metas ) { + return new Oxymel; + } + $oxymel = new WP_Export_Oxymel; + foreach( $metas as $meta ) { + $oxymel->tag( 'wp:commentmeta' )->contains + ->tag( 'wp:meta_key', $meta->meta_key ) + ->tag( 'wp:meta_value', $meta->meta_value ) + ->end; + } + return $oxymel; + } +} diff --git a/php/export/functions.export.php b/php/export/functions.export.php new file mode 100644 index 000000000..441736ef8 --- /dev/null +++ b/php/export/functions.export.php @@ -0,0 +1,30 @@ +<?php + +function wp_export( $args = array() ) { + $defaults = array( + 'filters' => array(), + 'format' => 'WP_Export_WXR_Formatter', + 'writer' => 'WP_Export_Returner', + 'writer_args' => null, + ); + $args = wp_parse_args( $args, $defaults ); + $export_query = new WP_Export_Query( $args['filters'] ); + $formatter = new $args['format']( $export_query ); + $writer = new $args['writer']( $formatter, $args['writer_args'] ); + try { + return $writer->export(); + } catch ( WP_Export_Exception $e ) { + return new WP_Error( 'wp-export-error', $e->getMessage() ); + } +} + +function wp_export_new_style_args_from_old_style_args( $args ) { + if ( isset( $args['content'] ) ) { + if ( 'all' == $args['content'] ) { + unset( $args['content'] ); + } else { + $args['post_type'] = $args['content']; + } + } + return $args; +} diff --git a/php/export/writers.php b/php/export/writers.php new file mode 100644 index 000000000..52a68d702 --- /dev/null +++ b/php/export/writers.php @@ -0,0 +1,145 @@ +<?php +abstract class WP_Export_Base_Writer { + protected $formatter; + + function __construct( $formatter ) { + $this->formatter = $formatter; + } + + public function export() { + $this->write( $this->formatter->before_posts() ); + foreach( $this->formatter->posts() as $post_in_wxr ) { + $this->write( $post_in_wxr ); + } + $this->write( $this->formatter->after_posts() ); + } + + abstract protected function write( $xml ); +} + +class WP_Export_XML_Over_HTTP extends WP_Export_Base_Writer { + private $file_name; + + function __construct( $formatter, $file_name ) { + parent::__construct( $formatter ); + $this->file_name = $file_name; + } + + public function export() { + header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: attachment; filename=' . $this->file_name ); + header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); + parent::export(); + } + + protected function write( $xml ) { + echo $xml; + } +} + +class WP_Export_Returner extends WP_Export_Base_Writer { + private $result = ''; + + public function export() { + $this->private = ''; + parent::export(); + return $this->result; + } + protected function write( $xml ) { + $this->result .= $xml; + } +} + +class WP_Export_File_Writer extends WP_Export_Base_Writer { + private $f; + private $file_name; + + public function __construct( $formatter, $file_name ) { + parent::__construct( $formatter ); + $this->file_name = $file_name; + } + + public function export() { + $this->f = fopen( $this->file_name, 'w' ); + if ( !$this->f ) { + throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) ); + } + parent::export(); + fclose( $this->f ); + } + + protected function write( $xml ) { + $res = fwrite( $this->f, $xml); + if ( false === $res ) { + throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); + } + } +} + +class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer { + private $result = ''; + private $f; + private $next_file_number = 0; + private $current_file_size = 0; + + function __construct( $formatter, $writer_args = array() ) { + parent::__construct( $formatter ); + //TODO: check if args are not missing + $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; + $this->destination_directory = $writer_args['destination_directory']; + $this->filename_template = $writer_args['filename_template']; + $this->before_posts_xml = $this->formatter->before_posts(); + $this->after_posts_xml = $this->formatter->after_posts(); + } + + public function export() { + $this->start_new_file(); + foreach( $this->formatter->posts() as $post_xml ) { + if ( ( $this->current_file_size + strlen( $post_xml ) ) > $this->max_file_size ) { + $this->start_new_file(); + } + $this->write( $post_xml ); + } + $this->close_current_file(); + } + + protected function write( $xml ) { + $res = fwrite( $this->f, $xml); + if ( false === $res ) { + throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); + } + $this->current_file_size += strlen( $xml ); + } + + private function start_new_file() { + if ( $this->f ) { + $this->close_current_file(); + } + $file_path = $this->next_file_path(); + $this->f = fopen( $file_path, 'w' ); + if ( !$this->f ) { + throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); + } + $this->current_file_size = 0; + $this->write( $this->before_posts_xml ); + } + + private function close_current_file() { + if ( !$this->f ) { + return; + } + $this->write( $this->after_posts_xml ); + fclose( $this->f ); + } + + private function next_file_name() { + $next_file_name = sprintf( $this->filename_template, $this->next_file_number ); + $this->next_file_number++; + return $next_file_name; + } + + private function next_file_path() { + return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name(); + } + +} From c3480588ffe4b1676be9e0d675cf0f20cde100d3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 17:04:13 +0300 Subject: [PATCH 1926/5359] copy wp-includes/iterators.php to export/iterators.php --- php/export/iterators.php | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 php/export/iterators.php diff --git a/php/export/iterators.php b/php/export/iterators.php new file mode 100644 index 000000000..6a4613cbb --- /dev/null +++ b/php/export/iterators.php @@ -0,0 +1,80 @@ +<?php +class WP_Map_Iterator extends IteratorIterator { + function __construct( $iterator, $callback ) { + $this->callback = $callback; + parent::__construct( $iterator ); + } + + function current() { + $original_current = parent::current(); + return call_user_func( $this->callback, $original_current ); + } +} + +class WP_Post_IDs_Iterator implements Iterator { + private $limit = 100; + private $post_ids; + private $ids_left; + private $results = array(); + + public function __construct( $post_ids, $limit = null ) { + $this->db = $GLOBALS['wpdb']; + $this->post_ids = $post_ids; + $this->ids_left = $post_ids; + if ( !is_null( $limit ) ) { + $this->limit = $limit; + } + } + + public function current() { + return $this->results[$this->index_in_results]; + } + + public function key() { + return $this->global_index; + } + + public function next() { + $this->index_in_results++; + $this->global_index++; + } + + public function rewind() { + $this->results = array(); + $this->global_index = 0; + $this->index_in_results = 0; + $this->ids_left = $this->post_ids; + } + + public function valid() { + if ( isset( $this->results[$this->index_in_results] ) ) { + return true; + } + if ( empty( $this->ids_left ) ) { + return false; + } + $has_posts = $this->load_next_posts_from_db(); + if ( !$has_posts ) { + return false; + } + $this->index_in_results = 0; + return true; + } + + private function load_next_posts_from_db() { + $next_batch_post_ids = array_splice( $this->ids_left, 0, $this->limit ); + $in_post_ids_sql = $this->db->build_IN_condition( 'ID', $next_batch_post_ids ); + $this->results = $this->db->get_results( "SELECT * FROM {$this->db->posts} WHERE $in_post_ids_sql" ); + if ( !$this->results ) { + if ( $this->db->last_error ) { + throw new WP_Iterator_Exception( 'Database error: ' . $this->db->last_error ); + } else { + return false; + } + } + return true; + } +} + +class WP_Iterator_Exception extends Exception { +} From adfdc881a5a9ac4885a336954ef22ea81c869587 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 15:07:06 +0300 Subject: [PATCH 1927/5359] load Oxymel via Composer --- composer.json | 3 ++- php/export/class-wp-export-oxymel.php | 2 -- php/export/class-wp-export-wxr-formatter.php | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index c9a8e7b55..19183596d 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "require": { "php": ">=5.3.2", "wp-cli/php-cli-tools": "dev-master", - "mustache/mustache": "~2.3" + "mustache/mustache": "~2.3", + "nb/oxymel": "dev-master" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" diff --git a/php/export/class-wp-export-oxymel.php b/php/export/class-wp-export-oxymel.php index 6c2bc9674..74c1a7cf1 100644 --- a/php/export/class-wp-export-oxymel.php +++ b/php/export/class-wp-export-oxymel.php @@ -1,7 +1,5 @@ <?php -require_once ABSPATH . WPINC . '/Oxymel.php'; - class WP_Export_Oxymel extends Oxymel { public function optional( $tag_name, $contents ) { if ( $contents ) { diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index f4850ac32..c169029fe 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -8,8 +8,6 @@ */ define( 'WXR_VERSION', '1.2' ); -require_once ABSPATH . WPINC . '/export/class-wp-export-oxymel.php'; - /** * Responsible for formatting the data in WP_Export_Query to WXR */ From 9ae66fa07c312531004bf4640b86fbc795bcec39 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 18:33:24 +0300 Subject: [PATCH 1928/5359] load export classes via Composer --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 19183596d..4a9d9cb3f 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "behat/behat": "~2.4" }, "autoload": { - "psr-0": { "WP_CLI": "php" } + "psr-0": { "WP_CLI": "php" }, + "classmap": [ "php/export" ] } } From 1e50229f93d348454fd69f4d671f6099db7cc49f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 16 Jun 2013 18:54:03 +0300 Subject: [PATCH 1929/5359] first pass at loading and using the export API * replace --file_item_count with --max_file_size * --verbose is ignored, for now --- man-src/export.txt | 4 +- php/commands/export.php | 420 ++++++---------------------------------- 2 files changed, 58 insertions(+), 366 deletions(-) diff --git a/man-src/export.txt b/man-src/export.txt index dcb8ea478..d58e6de7c 100644 --- a/man-src/export.txt +++ b/man-src/export.txt @@ -9,9 +9,9 @@ to current working directory. Don't export comments. -* `--file_item_count`=<count>: +* `--max_file_size`=<MB>: - Break export into files with N posts. + Set maximum size (in MB) each export file should have. Default: 15. * `--verbose`: diff --git a/php/commands/export.php b/php/commands/export.php index 3bde8c314..ee2ca87db 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -11,7 +11,7 @@ class Export_Command extends WP_CLI_Command { /** * Export content to a WXR file. * - * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] [--verbose] + * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--max_file_size=<MB>] [--verbose] */ public function __invoke( $_, $assoc_args ) { $defaults = array( @@ -24,12 +24,55 @@ public function __invoke( $_, $assoc_args ) { 'post_status' => NULL, 'post__in' => NULL, 'skip_comments' => NULL, - 'file_item_count' => 1000, + 'max_file_size' => 15, 'verbose' => false, ); - $args = wp_parse_args( $assoc_args, $defaults ); + $this->validate_args( wp_parse_args( $assoc_args, $defaults ) ); + if ( !function_exists( 'wp_export' ) ) { + self::load_export_api(); + } + + WP_CLI::line( 'Starting export process...' ); + + wp_export( array( + 'filters' => $this->export_args, + 'writer' => 'WP_Export_Split_Files_Writer', + 'writer_args' => array( + 'max_file_size' => $this->max_file_size * MB_IN_BYTES, + 'destination_directory' => $this->wxr_path, + 'filename_template' => self::get_filename_template() + ) + ) ); + + WP_CLI::success( 'All done with export.' ); + } + + private static function get_filename_template() { + $sitename = sanitize_key( get_bloginfo( 'name' ) ); + if ( ! empty($sitename) ) $sitename .= '.'; + return $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.%d.xml'; + } + + private static function load_export_api() { + if ( !defined( 'KB_IN_BYTES' ) ) { + // Constants for expressing human-readable data sizes + // in their respective number of bytes. + define( 'KB_IN_BYTES', 1024 ); + define( 'MB_IN_BYTES', 1024 * KB_IN_BYTES ); + define( 'GB_IN_BYTES', 1024 * MB_IN_BYTES ); + define( 'TB_IN_BYTES', 1024 * GB_IN_BYTES ); + define( 'PB_IN_BYTES', 1024 * TB_IN_BYTES ); + define( 'EB_IN_BYTES', 1024 * PB_IN_BYTES ); + define( 'ZB_IN_BYTES', 1024 * EB_IN_BYTES ); + define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES ); + } + + require WP_CLI_ROOT . '/export/functions.export.php'; + } + + private function validate_args( $args ) { $has_errors = false; foreach ( $args as $key => $value ) { @@ -43,13 +86,6 @@ public function __invoke( $_, $assoc_args ) { if ( $has_errors ) { exit(1); } - - $this->wxr_path = trailingslashit( $this->export_args['dir'] ); - unset( $this->export_args['dir'] ); - - WP_CLI::line( 'Starting export process...' ); - WP_CLI::line(); - $this->export_wp( $this->export_args ); } private function check_verbose( $verbose ) { @@ -60,15 +96,14 @@ private function check_verbose( $verbose ) { private function check_dir( $path ) { if ( empty( $path ) ) { - $this->export_args['dir'] = getcwd(); - return true; - } - - if ( !is_dir( $path ) ) { + $path = getcwd(); + } elseif ( !is_dir( $path ) ) { WP_CLI::error( sprintf( "The directory %s does not exist", $path ) ); + return false; } - $this->export_args['dir'] = $path; + $this->wxr_path = trailingslashit( $path ); + return true; } @@ -195,358 +230,15 @@ private function check_skip_comments( $skip ) { return true; } - private function check_file_item_count( $file_item_count ) { - - if ( ! is_numeric( $file_item_count ) ) { - WP_CLI::warning( 'File item count needs to be numeric' ); + private function check_max_file_size( $size ) { + if ( !is_numeric( $size ) ) { + WP_CLI::warning( sprintf( "max_file_size should be numeric", $size ) ); return false; } - $this->export_args['file_item_count'] = $file_item_count; - return true; - } - - - /** - * Workaround to prevent memory leaks from growing variables - */ - - private function stop_the_insanity() { - global $wpdb, $wp_object_cache; - $wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); - if ( !is_object( $wp_object_cache ) ) - return; - $wp_object_cache->group_ops = array(); - $wp_object_cache->stats = array(); - $wp_object_cache->memcache_debug = array(); - $wp_object_cache->cache = array(); - if ( method_exists( $wp_object_cache, '__remoteset' ) ) - $wp_object_cache->__remoteset(); - } - - private function start_export() { - ob_start(); - } - - private function end_export() { - ob_end_clean(); - } - - private function flush_export( $file_path, $append = true ) { - $result = ob_get_clean(); - if ( $append ) - $append = FILE_APPEND; - file_put_contents( $file_path, $result, $append ); - $this->start_export(); - } - - /** - * Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php - */ - - private function export_wp( $args = array() ) { - require_once ABSPATH . 'wp-admin/includes/export.php'; - - global $wpdb; - - /** - * This is mostly the original code of export_wp defined in wp-admin/includes/export.php - */ - $defaults = array( 'post_type' => 'all', 'post__in' => false, 'author' => false, 'category' => false, - 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, 'file_item_count' => 1000, - ); - $args = wp_parse_args( $args, $defaults ); - - if ( $this->verbose ) { - WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); - } - - do_action( 'export_wp' ); - - $sitename = sanitize_key( get_bloginfo( 'name' ) ); - if ( ! empty( $sitename ) ) - $sitename .= '.'; - - $append = array( date( 'Y-m-d' ) ); - foreach( array_keys( $args ) as $arg_key ) { - if ( $defaults[$arg_key] <> $args[$arg_key] && 'post__in' != $arg_key ) - $append[]= "$arg_key-" . (string) $args[$arg_key]; - } - $file_name_base = sanitize_file_name( $sitename . 'wordpress.' . implode( ".", $append ) ); - - if ( 'all' != $args['post_type'] && post_type_exists( $args['post_type'] ) ) { - $ptype = get_post_type_object( $args['post_type'] ); - if ( ! $ptype->can_export ) - $args['post_type'] = 'post'; - - $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['post_type'] ); - } else { - $post_types = get_post_types( array( 'can_export' => true ) ); - $esses = array_fill( 0, count( $post_types ), '%s' ); - $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); - } - - if ( $args['status'] && ( 'post' == $args['post_type'] || 'page' == $args['post_type'] ) ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] ); - else - $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; - - $join = ''; - if ( $args['category'] && 'post' == $args['post_type'] ) { - if ( $term = term_exists( $args['category'], 'category' ) ) { - $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)"; - $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] ); - } - } - - - if ( $args['author'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); - - if ( $args['start_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d 00:00:00', strtotime( $args['start_date'] ) ) ); - - if ( $args['end_date'] ) - $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s", date( 'Y-m-d 23:59:59', strtotime( $args['end_date'] ) ) ); - // grab a snapshot of post IDs, just in case it changes during the export - if ( empty( $args['post__in'] ) ) - $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" ); - else - $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE ID IN ({$args['post__in']}) ORDER BY post_date ASC, post_parent ASC" ); - - // Make sure we're getting all of the attachments for these posts too - if ( 'all' != $args['post_type'] || ! empty( $args['post__in'] ) ) { - $all_post_ids_with_attachments = array(); - while ( $post_ids = array_splice( $all_the_post_ids, 0, 100 ) ) { - $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" ); - $all_post_ids_with_attachments = array_merge( $all_post_ids_with_attachments, $post_ids, (array)$attachment_ids ); - } - $all_the_post_ids = $all_post_ids_with_attachments; - } - - // get the requested terms ready, empty unless posts filtered by category or all content - $cats = $tags = $terms = array(); - if ( isset( $term ) && $term ) { - $cat = get_term( $term['term_id'], 'category' ); - $cats = array( $cat->term_id => $cat ); - unset( $term, $cat ); - } else if ( 'all' == $args['post_type'] ) { - $categories = (array) get_categories( array( 'get' => 'all' ) ); - $tags = (array) get_tags( array( 'get' => 'all' ) ); - - $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); - $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); - - // put categories in order with no child going before its parent - while ( $cat = array_shift( $categories ) ) { - if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) - $cats[$cat->term_id] = $cat; - else - $categories[] = $cat; - } + $this->max_file_size = $size; - // put terms in order with no child going before its parent - while ( $t = array_shift( $custom_terms ) ) { - if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) - $terms[$t->term_id] = $t; - else - $custom_terms[] = $t; - } - - unset( $categories, $custom_taxonomies, $custom_terms ); - } - - // Load the functions available in wp-admin/includes/export.php - ob_start(); - export_wp( array( 'content' => 'page', 'start_date' => '1971-01-01', 'end_date' => '1971-01-02' ) ); - ob_end_clean(); - - WP_CLI::line( 'Exporting ' . count( $all_the_post_ids ) . ' items to be broken into ' . ceil( count( $all_the_post_ids ) / $args['file_item_count'] ) . ' files' ); - WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); - WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); - WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); - WP_CLI::line(); - - $file_count = 1; - - while ( $post_ids = array_splice( $all_the_post_ids, 0, $args['file_item_count'] ) ) { - - $full_path = $this->wxr_path . $file_name_base . '.' . str_pad( $file_count, 3, '0', STR_PAD_LEFT ) . '.xml'; - - // Create the file if it doesn't exist - if ( ! file_exists( $full_path ) ) { - touch( $full_path ); - } - - if ( ! file_exists( $full_path ) ) { - WP_CLI::error( "Failed to create file " . $full_path ); - exit; - } else { - WP_CLI::line( 'Writing to file ' . $full_path ); - } - - if ( !$this->verbose ) - $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) ); - - $this->start_export(); - echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; - -?> -<!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. --> -<!-- It contains information about your site's posts, pages, comments, categories, and other content. --> -<!-- You may use this file to transfer that content from one site to another. --> -<!-- This file is not intended to serve as a complete backup of your site. --> - -<!-- To import this information into a WordPress site follow these steps: --> -<!-- 1. Log in to that site as an administrator. --> -<!-- 2. Go to Tools: Import in the WordPress admin panel. --> -<!-- 3. Install the "WordPress" importer from the list. --> -<!-- 4. Activate & Run Importer. --> -<!-- 5. Upload this file using the form provided on that page. --> -<!-- 6. You will first be asked to map the authors in this export file to users --> -<!-- on the site. For each author, you may choose to map to an --> -<!-- existing user on the site or to create a new user. --> -<!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. --> -<!-- contained in this file into your site. --> - -<?php the_generator( 'export' ); ?> -<rss version="2.0" - xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/" - xmlns:content="http://purl.org/rss/1.0/modules/content/" - xmlns:wfw="http://wellformedweb.org/CommentAPI/" - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/" -> - -<channel> - <title><?php bloginfo_rss( 'name' ); ?> - - - - - - - - - - - - term_id ?>slug; ?>parent ? $cats[$c->parent]->slug : ''; ?> - - - term_id ?>slug; ?> - - - term_id ?>taxonomy; ?>slug; ?>parent ? $terms[$t->parent]->slug : ''; ?> - - - - - flush_export( $full_path, false ); ?> - -in_the_loop = true; // Fake being in the loop. - - // fetch 20 posts at a time rather than loading the entire table into memory - while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { - - $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; - $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); - - // Begin Loop - foreach ( $posts as $post ) { - - if ( !$this->verbose ) { - $progress->tick(); - } else { - WP_CLI::line( "Exporting post $post->ID" ); - } - - setup_postdata( $post ); - $is_sticky = is_sticky( $post->ID ) ? 1 : 0; -?> - - <?php echo apply_filters( 'the_title_rss', $post->post_title ); ?> - - - - - - post_content ) ); ?> - post_excerpt ) ); ?> - ID; ?> - post_date; ?> - post_date_gmt; ?> - comment_status; ?> - ping_status; ?> - post_name; ?> - post_status; ?> - post_parent; ?> - menu_order; ?> - post_type; ?> - post_password; ?> - -post_type == 'attachment' ) : ?> - ID ); ?> - - -get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); - foreach ( $postmeta as $meta ) : - if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) - continue; - ?> - - meta_key; ?> - meta_value ); ?> - - - -get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); - foreach ( $comments as $c ) : ?> - - comment_ID; ?> - comment_author ); ?> - comment_author_email; ?> - comment_author_url ); ?> - comment_author_IP; ?> - comment_date; ?> - comment_date_gmt; ?> - comment_content ) ?> - comment_approved; ?> - comment_type; ?> - comment_parent; ?> - user_id; ?> -get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); - foreach ( $c_meta as $meta ) : ?> - - meta_key; ?> - meta_value ); ?> - - - - - - -flush_export( $full_path ); - } - } - } ?> - - -flush_export( $full_path ); - $this->end_export(); - $this->stop_the_insanity(); - - if ( !$this->verbose ) { - $progress->finish(); - } - - $file_count++; - } - WP_CLI::success( "All done with export" ); + return true; } } From 128b9c0674dcecb5f24a1c370c0a4ed16f5e25ea Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 16 Jun 2013 19:09:52 +0300 Subject: [PATCH 1930/5359] add _wp_export_build_IN_condition() helper --- php/export/class-wp-export-query.php | 4 ++-- php/export/functions.export.php | 11 +++++++++++ php/export/iterators.php | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 5522cc06a..b99636e04 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -158,7 +158,7 @@ private function post_type_where() { $this->wheres[] = 'p.post_type IS NULL'; return; } - $this->wheres[] = $wpdb->build_IN_condition( 'p.post_type', $post_types ); + $this->wheres[] = _wp_export_build_IN_condition( 'p.post_type', $post_types ); } private function status_where() { @@ -227,7 +227,7 @@ private function attachments_for_specific_post_types( $post_ids ) { } $attachment_ids = array(); while ( $batch_of_post_ids = array_splice( $post_ids, 0, self::QUERY_CHUNK ) ) { - $post_parent_condition = $wpdb->build_IN_condition( 'post_parent', $batch_of_post_ids ); + $post_parent_condition = _wp_export_build_IN_condition( 'post_parent', $batch_of_post_ids ); $attachment_ids = array_merge( $attachment_ids, (array)$wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND $post_parent_condition" ) ); } return array_map( 'intval', $attachment_ids ); diff --git a/php/export/functions.export.php b/php/export/functions.export.php index 441736ef8..492e97e9b 100644 --- a/php/export/functions.export.php +++ b/php/export/functions.export.php @@ -28,3 +28,14 @@ function wp_export_new_style_args_from_old_style_args( $args ) { } return $args; } + +// TEMPORARY +function _wp_export_build_IN_condition( $column_name, $values, $format = '%s' ) { + global $wpdb; + + if ( !is_array( $values ) || empty( $values ) ) { + return ''; + } + $formats = implode( ', ', array_fill( 0, count( $values ), $format ) ); + return $wpdb->prepare( "$column_name IN ($formats)", $values ); +} diff --git a/php/export/iterators.php b/php/export/iterators.php index 6a4613cbb..86572f56c 100644 --- a/php/export/iterators.php +++ b/php/export/iterators.php @@ -63,7 +63,7 @@ public function valid() { private function load_next_posts_from_db() { $next_batch_post_ids = array_splice( $this->ids_left, 0, $this->limit ); - $in_post_ids_sql = $this->db->build_IN_condition( 'ID', $next_batch_post_ids ); + $in_post_ids_sql = _wp_export_build_IN_condition( 'ID', $next_batch_post_ids ); $this->results = $this->db->get_results( "SELECT * FROM {$this->db->posts} WHERE $in_post_ids_sql" ); if ( !$this->results ) { if ( $this->db->last_error ) { From 4bfc6be67d22983b2566e9c8a336c4922156f906 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 16 Jun 2013 20:15:53 +0300 Subject: [PATCH 1931/5359] log each exported file path had to copy over the whole WP_Export_Split_Files_Writer class. --- php/WP_CLI/VerboseExportWriter.php | 73 ++++++++++++++++++++++++++++++ php/commands/export.php | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 php/WP_CLI/VerboseExportWriter.php diff --git a/php/WP_CLI/VerboseExportWriter.php b/php/WP_CLI/VerboseExportWriter.php new file mode 100644 index 000000000..5facc3f90 --- /dev/null +++ b/php/WP_CLI/VerboseExportWriter.php @@ -0,0 +1,73 @@ +max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; + $this->destination_directory = $writer_args['destination_directory']; + $this->filename_template = $writer_args['filename_template']; + $this->before_posts_xml = $this->formatter->before_posts(); + $this->after_posts_xml = $this->formatter->after_posts(); + } + + public function export() { + $this->start_new_file(); + foreach( $this->formatter->posts() as $post_xml ) { + if ( ( $this->current_file_size + strlen( $post_xml ) ) > $this->max_file_size ) { + $this->start_new_file(); + } + $this->write( $post_xml ); + } + $this->close_current_file(); + } + + protected function write( $xml ) { + $res = fwrite( $this->f, $xml); + if ( false === $res ) { + throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); + } + $this->current_file_size += strlen( $xml ); + } + + private function start_new_file() { + if ( $this->f ) { + $this->close_current_file(); + } + $file_path = $this->next_file_path(); + $this->f = fopen( $file_path, 'w' ); + if ( !$this->f ) { + throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); + } + \WP_CLI::log( sprintf( "Started writing to %s", $file_path ) ); + $this->current_file_size = 0; + $this->write( $this->before_posts_xml ); + } + + private function close_current_file() { + if ( !$this->f ) { + return; + } + $this->write( $this->after_posts_xml ); + fclose( $this->f ); + } + + private function next_file_name() { + $next_file_name = sprintf( $this->filename_template, $this->next_file_number ); + $this->next_file_number++; + return $next_file_name; + } + + private function next_file_path() { + return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name(); + } +} + diff --git a/php/commands/export.php b/php/commands/export.php index ee2ca87db..c777f5464 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -38,7 +38,7 @@ public function __invoke( $_, $assoc_args ) { wp_export( array( 'filters' => $this->export_args, - 'writer' => 'WP_Export_Split_Files_Writer', + 'writer' => '\\WP_CLI\\VerboseExportWriter', 'writer_args' => array( 'max_file_size' => $this->max_file_size * MB_IN_BYTES, 'destination_directory' => $this->wxr_path, From aa542585aeeef589b1ce1e18edf3d4aa30a06786 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 16 Jun 2013 20:16:28 +0300 Subject: [PATCH 1932/5359] remove --verbose parameter The idea is to be reasonably verbose by default and completely silent when --quiet is passed. --- man-src/export.txt | 4 ---- php/commands/export.php | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/man-src/export.txt b/man-src/export.txt index d58e6de7c..58326c5f6 100644 --- a/man-src/export.txt +++ b/man-src/export.txt @@ -13,10 +13,6 @@ to current working directory. Set maximum size (in MB) each export file should have. Default: 15. -* `--verbose`: - - Show more information about the process on STDOUT. - ## FILTERS * `--start_date`=: diff --git a/php/commands/export.php b/php/commands/export.php index c777f5464..d7fc59da4 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -11,7 +11,7 @@ class Export_Command extends WP_CLI_Command { /** * Export content to a WXR file. * - * @synopsis [--dir=] [--start_date=] [--end_date=] [--post_type=] [--post_status=] [--post__in=] [--author=] [--category=] [--skip_comments] [--max_file_size=] [--verbose] + * @synopsis [--dir=] [--start_date=] [--end_date=] [--post_type=] [--post_status=] [--post__in=] [--author=] [--category=] [--skip_comments] [--max_file_size=] */ public function __invoke( $_, $assoc_args ) { $defaults = array( @@ -25,7 +25,6 @@ public function __invoke( $_, $assoc_args ) { 'post__in' => NULL, 'skip_comments' => NULL, 'max_file_size' => 15, - 'verbose' => false, ); $this->validate_args( wp_parse_args( $assoc_args, $defaults ) ); @@ -34,7 +33,7 @@ public function __invoke( $_, $assoc_args ) { self::load_export_api(); } - WP_CLI::line( 'Starting export process...' ); + WP_CLI::log( 'Starting export process...' ); wp_export( array( 'filters' => $this->export_args, From fb5da0ab2b1f1034c7f4f12796d22af534f9e255 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 25 Jun 2013 14:32:18 -0700 Subject: [PATCH 1933/5359] Restore af65fe41c8d3b9df3c1fb1461fddf92ac165fde5, which I accidentally overwrote :( --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index d7fc59da4..97a319b9f 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -68,7 +68,7 @@ private static function load_export_api() { define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES ); } - require WP_CLI_ROOT . '/export/functions.export.php'; + require WP_CLI_ROOT . '/php/export/functions.export.php'; } private function validate_args( $args ) { From 4923fefdb4d2cb512c9f35fa0e1316312b35647a Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 01:16:44 +0300 Subject: [PATCH 1934/5359] minor whitespace fixes --- php/commands/import.php | 53 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index c904e53c0..1f2dc0892 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -15,10 +15,10 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( "File to import doesn't exist." ); $defaults = array( - 'type' => 'wxr', - 'authors' => null, - 'skip' => array(), - ); + 'type' => 'wxr', + 'authors' => null, + 'skip' => array(), + ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); $assoc_args['file'] = $file; @@ -71,7 +71,7 @@ private function import_wxr( $args ) { // Prepare the data to be used in process_author_mapping(); $wp_import->get_authors_from_import( $import_data ); $author_data = array(); - foreach( $wp_import->authors as $wxr_author ) { + foreach ( $wp_import->authors as $wxr_author ) { $author = new \stdClass; // Always in the WXR $author->user_login = $wxr_author['author_login']; @@ -98,7 +98,7 @@ private function import_wxr( $args ) { // $user_select needs to be an array of user IDs $user_select = array(); $invalid_user_select = array(); - foreach( $author_out as $author_login ) { + foreach ( $author_out as $author_login ) { $user = get_user_by( 'login', $author_login ); if ( $user ) $user_select[] = $user->ID; @@ -109,7 +109,7 @@ private function import_wxr( $args ) { return new WP_Error( 'invalid-author-mapping', sprintf( "These user_logins are invalid: %s", implode( ',', $invalid_user_select ) ) ); // Drive the import - $wp_import->fetch_attachments = ( in_array( 'attachment', $args['skip'] ) ) ? false : true; + $wp_import->fetch_attachments = !in_array( 'attachment', $args['skip'] ); $_GET = array( 'import' => 'wordpress', 'step' => 2 ); $_POST = array( 'imported_authors' => $author_in, @@ -264,11 +264,11 @@ private function create_author_mapping_file( $file, $author_data ) { if ( touch( $file ) ) { $author_mapping = array(); - foreach( $author_data as $author ) { + foreach ( $author_data as $author ) { $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $this->suggest_user( $author->user_login, $author->user_email ), - ); + 'old_user_login' => $author->user_login, + 'new_user_login' => $this->suggest_user( $author->user_login, $author->user_email ), + ); } $file_resource = fopen( $file, 'w' ); \WP_CLI\utils\write_csv( $file_resource, $author_mapping, array( 'old_user_login', 'new_user_login' ) ); @@ -284,14 +284,14 @@ private function create_author_mapping_file( $file, $author_data ) { private function create_authors_for_mapping( $author_data ) { $author_mapping = array(); - foreach( $author_data as $author ) { + foreach ( $author_data as $author ) { if ( isset( $author->user_email ) ) { if ( $user = get_user_by( 'email', $author->user_email ) ) { $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $user->user_login, - ); + 'old_user_login' => $author->user_login, + 'new_user_login' => $user->user_login, + ); continue; } } @@ -305,10 +305,10 @@ private function create_authors_for_mapping( $author_data ) { } $user = array( - 'user_login' => '', - 'user_email' => '', - 'user_pass' => wp_generate_password(), - ); + 'user_login' => '', + 'user_email' => '', + 'user_pass' => wp_generate_password(), + ); $user = array_merge( $user, (array)$author ); $user_id = wp_insert_user( $user ); if ( is_wp_error( $user_id ) ) @@ -316,9 +316,9 @@ private function create_authors_for_mapping( $author_data ) { $user = get_user_by( 'id', $user_id ); $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $user->user_login, - ); + 'old_user_login' => $author->user_login, + 'new_user_login' => $user->user_login, + ); } return $author_mapping; @@ -334,7 +334,7 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { $shortest = -1; $shortestavg = array(); - + $threshold = floor( ( strlen( $author_user_login ) / 100 ) * 10 ); // 10 % of the strlen are valid $closest = ''; foreach ( $this->blog_users as $user ) { @@ -353,13 +353,13 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { $shortest = 0; break; } - + if ( ( $lev <= $shortest || $shortest < 0 ) && $lev <= $threshold ) { $closest = $user->user_login; $shortest = $lev; } $shortestavg[] = $lev; - } + } // in case all usernames have a common pattern if ( $shortest > ( array_sum( $shortestavg ) / count( $shortestavg ) ) ) return ''; @@ -368,4 +368,5 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { } -WP_CLI::add_command( 'import', new Import_Command ); \ No newline at end of file +WP_CLI::add_command( 'import', new Import_Command ); + From e50c87f52bd89558d4dd367ca1be266d14a00b40 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 01:24:26 +0300 Subject: [PATCH 1935/5359] add newline at end of man-src/import.txt [ci skip] --- man-src/import.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man-src/import.txt b/man-src/import.txt index 8a26f302e..5f4e3dedf 100644 --- a/man-src/import.txt +++ b/man-src/import.txt @@ -10,4 +10,4 @@ * `--skip=`: - Skip importing specific data. Supported option is 'attachment'. \ No newline at end of file + Skip importing specific data. Supported option is 'attachment'. From 6e42fae31f03f4af200e0a3373b1011047565aeb Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 01:26:13 +0300 Subject: [PATCH 1936/5359] fix indentation in import.feature [ci skip] --- features/import.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/import.feature b/features/import.feature index ffab45b5e..dc9f201a1 100644 --- a/features/import.feature +++ b/features/import.feature @@ -1,6 +1,6 @@ Feature: Import content. -Scenario: Basic export then import + Scenario: Basic export then import Given a WP install When I run `wp post generate --post_type=post --count=3` @@ -25,7 +25,7 @@ Scenario: Basic export then import When I run `wp site empty --yes` Then STDOUT should not be empty - When I run `wp post list --post_type=any --format=csv | wc -l` + When I run `wp post list --post_type=any --format=csv | wc -l` Then STDOUT should be: """ 1 @@ -41,4 +41,4 @@ Scenario: Basic export then import Then STDOUT should be: """ 8 - """ \ No newline at end of file + """ From 3ca418c83ea26b92c5670a11348d547ad0230558 Mon Sep 17 00:00:00 2001 From: Andrey Savchenko Date: Wed, 26 Jun 2013 02:52:56 +0300 Subject: [PATCH 1937/5359] Added wp.bat to bin section of composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c9a8e7b55..318de31b6 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "homepage": "http://wp-cli.org", "license": "MIT", "bin": [ - "bin/wp" + "bin/wp.bat", "bin/wp" ], "require": { "php": ">=5.3.2", From dbd220902cb6370a9089f38d1feed6280c09c344 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 26 Jun 2013 11:52:51 +1000 Subject: [PATCH 1938/5359] support for port and socket configurations with wp core config --- php/utils.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index dab686c87..f75525710 100644 --- a/php/utils.php +++ b/php/utils.php @@ -353,8 +353,25 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { function run_mysql_query( $query, $args ) { // TODO: use PDO? + $host_parts = explode( ':', $args['host'] ); + if ( count( $host_parts ) == 2 ) { + list( $host, $extra ) = $host_parts; + } else { + $host = $args['host']; + } + $arg_str = esc_cmd( '--host=%s --user=%s --execute=%s', - $args['host'], $args['user'], $query ); + $host, $args['user'], $query ); + + if ( isset( $extra ) ) { + if ( is_numeric($extra) ) { + $arg_str .= esc_cmd( ' --port=%s --protocol=%s', intval( $extra ), 'tcp' ); + } else if ( trim($extra) !== '' ) { + $arg_str .= esc_cmd( ' --socket=%s', trim( $extra ) ); + } + } + + echo $arg_str . "\n"; run_mysql_command( 'mysql', $arg_str, $args['pass'] ); } From 91d4521d62723bccac68901bdc7968b5429ed25f Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 26 Jun 2013 16:37:16 +1000 Subject: [PATCH 1939/5359] Make wp rewrite (flush|structure) generate .htaccess files properly for apache. --- php/commands/rewrite.php | 28 ++++++++++++++++++++++++---- php/config-spec.php | 7 +++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 7f464ae0a..3453496e1 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -10,16 +10,18 @@ class Rewrite_Command extends WP_CLI_Command { /** * Flush rewrite rules. * - * @synopsis [--soft] + * @synopsis [--hard] */ public function flush( $args, $assoc_args ) { - flush_rewrite_rules( isset( $assoc_args['soft'] ) ); + // make sure we detect mod_rewrite if configured in apache_modules in config + self::apache_modules(); + flush_rewrite_rules( isset( $assoc_args['hard'] ) ); } /** * Update the permalink structure. * - * @synopsis [--category-base=] [--tag-base=] + * @synopsis [--category-base=] [--tag-base=] [--hard] */ public function structure( $args, $assoc_args ) { global $wp_rewrite; @@ -62,7 +64,9 @@ public function structure( $args, $assoc_args ) { $wp_rewrite->set_tag_base( $tag_base ); } - flush_rewrite_rules( $hard ); + // make sure we detect mod_rewrite if configured in apache_modules in config + self::apache_modules(); + flush_rewrite_rules( isset( $assoc_args['hard'] ) ); } /** @@ -86,6 +90,22 @@ public function dump( $args, $assoc_args ) { } } + + /** + * Expose apache modules if present in config + */ + public static function apache_modules() { + $mods = WP_CLI::get_config('apache_modules'); + if ( count($mods) > 0 && !function_exists( 'apache_get_modules') ) { + global $is_apache; + $is_apache = true; + + function apache_get_modules() { + return WP_CLI::get_config('apache_modules'); + } + } + } + } WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); diff --git a/php/config-spec.php b/php/config-spec.php index 61aaf46ba..1ec7556f8 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -63,5 +63,12 @@ 'default' => false, 'desc' => 'Suppress informational messages', ), + + 'apache_modules' => array( + 'file' => '', + 'desc' => 'List of Apache Modules that are to be reported as loaded', + 'multiple' => true, + 'default' => array(), + ), ); From e97184ef6856a1ae4db8a7803c36f1a6985e19f7 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 12:27:09 +0300 Subject: [PATCH 1940/5359] lock php-cli-tools version to 0.9.3 fixes #560; see #561 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c9a8e7b55..832b311da 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.3" }, "suggest": { From f2300d56d231aa6bddfb8a9e2fa692c1e3b30eba Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 17:52:37 +0300 Subject: [PATCH 1941/5359] set Oxymel to version 0.1.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4a9d9cb3f..fd5211d41 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.3", - "nb/oxymel": "dev-master" + "nb/oxymel": "0.1.0" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" From 949b40770010f90579d93db797ec1da40879bac8 Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 26 Jun 2013 18:53:20 +0300 Subject: [PATCH 1942/5359] ensure CRLF are always normalized to LF in the git database --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..0fdf7ac9b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform EOL normalization +* text=auto From 198e8a3afbd96151633e197055f159aab58a7cd3 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 28 Jun 2013 20:42:04 +0300 Subject: [PATCH 1943/5359] check wp-includes/version.php before loading WP --- php/WP_CLI/Runner.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b3de186ff..4c57380d1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -268,6 +268,26 @@ private function init_logger() { WP_CLI::set_logger( $logger ); } + private function check_wp_version() { + if ( !is_readable( ABSPATH . 'wp-includes/version.php' ) ) { + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); + } + + include ABSPATH . 'wp-includes/version.php'; + + $minimum_version = '3.4'; + + if ( version_compare( $wp_version, $minimum_version, '<' ) ) { + WP_CLI::error( + "WP-CLI needs WordPress $minimum_version or later to work properly. " . + "The version currently installed is $wp_version.\n" . + "Try running `wp core download --force`." + ); + } + } + public function before_wp_load() { list( $args, $assoc_args, $runtime_config ) = \WP_CLI::$configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -320,11 +340,7 @@ public function before_wp_load() { $this->do_early_invoke( 'before_wp_load' ); - if ( !is_readable( ABSPATH . 'wp-load.php' ) ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } + $this->check_wp_version(); if ( array( 'core', 'config' ) == $this->arguments ) { $this->_run_command(); From 1c304a996b466c6d17aaf48d2fbc8bf0fbeb91a5 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 22:53:41 +0200 Subject: [PATCH 1944/5359] make WP_CLI::add_command() work when called from a Composer package's autoloaded file --- php/class-wp-cli.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9a7ac59f7..f8d1f3631 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -15,6 +15,7 @@ class WP_CLI { private static $logger; private static $hooks = array(), $hooks_passed = array(); + private static $commands_in_packages = array(); private static $man_dirs = array(); @@ -27,6 +28,10 @@ static function init() { self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); self::$root = new Dispatcher\RootCommand; self::$runner = new WP_CLI\Runner; + + foreach ( self::$commands_in_packages as $args ) { + call_user_func_array( array( __CLASS__, 'add_command' ), $args ); + } } /** @@ -73,6 +78,14 @@ static function do_action( $when ) { * 'before_invoke' => callback to execute before invoking the command */ static function add_command( $name, $class, $args = array() ) { + if ( !self::$root ) { // Still loading Composer autoloader + self::$commands_in_packages[] = func_get_args(); + } else { + self::_add_command( $name, $class, $args ); + } + } + + private static function _add_command( $name, $class, $args ) { $command = Dispatcher\CommandFactory::create( $name, $class, self::$root ); if ( isset( $args['before_invoke'] ) ) { From 5c4fcc3cf083d4dd67a31c4a231e7ac3ec0f88f9 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:14:33 +0200 Subject: [PATCH 1945/5359] instantiate WP_CLI::$root on-demand --- php/class-wp-cli.php | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f8d1f3631..347a3d4d0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -15,7 +15,6 @@ class WP_CLI { private static $logger; private static $hooks = array(), $hooks_passed = array(); - private static $commands_in_packages = array(); private static $man_dirs = array(); @@ -26,12 +25,7 @@ static function init() { self::add_man_dir( null, WP_CLI_ROOT . "/man-src" ); self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); - self::$root = new Dispatcher\RootCommand; self::$runner = new WP_CLI\Runner; - - foreach ( self::$commands_in_packages as $args ) { - call_user_func_array( array( __CLASS__, 'add_command' ), $args ); - } } /** @@ -78,20 +72,16 @@ static function do_action( $when ) { * 'before_invoke' => callback to execute before invoking the command */ static function add_command( $name, $class, $args = array() ) { - if ( !self::$root ) { // Still loading Composer autoloader - self::$commands_in_packages[] = func_get_args(); - } else { - self::_add_command( $name, $class, $args ); - } - } - - private static function _add_command( $name, $class, $args ) { $command = Dispatcher\CommandFactory::create( $name, $class, self::$root ); if ( isset( $args['before_invoke'] ) ) { self::add_action( "before_invoke:$name", $args['before_invoke'] ); } + if ( !self::$root ) { + self::$root = new Dispatcher\RootCommand; + } + self::$root->add_subcommand( $name, $command ); } From 75504265afd5e36f654e9bf1ac3d469c9739a64e Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:19:55 +0200 Subject: [PATCH 1946/5359] introduce get_root_command() getter --- php/class-wp-cli.php | 12 ++++++++---- php/commands/cli.php | 4 ++-- php/commands/help.php | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 347a3d4d0..068acd31a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -9,9 +9,9 @@ class WP_CLI { public static $configurator; - public static $root; public static $runner; + private static $root; private static $logger; private static $hooks = array(), $hooks_passed = array(); @@ -72,17 +72,21 @@ static function do_action( $when ) { * 'before_invoke' => callback to execute before invoking the command */ static function add_command( $name, $class, $args = array() ) { - $command = Dispatcher\CommandFactory::create( $name, $class, self::$root ); + $command = Dispatcher\CommandFactory::create( $name, $class, self::get_root_command() ); if ( isset( $args['before_invoke'] ) ) { self::add_action( "before_invoke:$name", $args['before_invoke'] ); } + self::get_root_command()->add_subcommand( $name, $command ); + } + + static function get_root_command() { if ( !self::$root ) { self::$root = new Dispatcher\RootCommand; } - self::$root->add_subcommand( $name, $command ); + return self::$root; } static function add_man_dir( $deprecated = null, $src_dir ) { @@ -249,7 +253,7 @@ static function get_config( $key = null ) { } private static function find_command_to_run( $args ) { - $command = \WP_CLI::$root; + $command = \WP_CLI::get_root_command(); $cmd_path = array(); diff --git a/php/commands/cli.php b/php/commands/cli.php index b537b1028..110fcb098 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -53,11 +53,11 @@ function param_dump() { * @subcommand cmd-dump */ function cmd_dump() { - echo json_encode( self::command_to_array( WP_CLI::$root ) ); + echo json_encode( self::command_to_array( WP_CLI::get_root_command() ) ); } function completions() { - foreach ( WP_CLI::$root->get_subcommands() as $name => $command ) { + foreach ( WP_CLI::get_root_command()->get_subcommands() as $name => $command ) { $subcommands = $command->get_subcommands(); WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); diff --git a/php/commands/help.php b/php/commands/help.php index c339c6fbf..7b6599dc7 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -25,7 +25,7 @@ function __invoke( $args, $assoc_args ) { } private static function find_subcommand( $args ) { - $command = \WP_CLI::$root; + $command = \WP_CLI::get_root_command(); while ( !empty( $args ) && $command && $command->has_subcommands() ) { $command = $command->find_subcommand( $args ); From 8148411fa9fbc171fa562ddaa1f026255cdc9e63 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:24:07 +0200 Subject: [PATCH 1947/5359] convert $root from class static to method static This avoids accidental direct access from other class methods. --- php/class-wp-cli.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 068acd31a..964533a20 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -11,7 +11,6 @@ class WP_CLI { public static $configurator; public static $runner; - private static $root; private static $logger; private static $hooks = array(), $hooks_passed = array(); @@ -82,11 +81,13 @@ static function add_command( $name, $class, $args = array() ) { } static function get_root_command() { - if ( !self::$root ) { - self::$root = new Dispatcher\RootCommand; + static $root; + + if ( !$root ) { + $root = new Dispatcher\RootCommand; } - return self::$root; + return $root; } static function add_man_dir( $deprecated = null, $src_dir ) { From 4709fa695e8eece3177a826ba09d81898dcbd82d Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:37:08 +0200 Subject: [PATCH 1948/5359] convert from WP_CLI:: to self:: --- php/class-wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 964533a20..2df1376a9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -254,7 +254,7 @@ static function get_config( $key = null ) { } private static function find_command_to_run( $args ) { - $command = \WP_CLI::get_root_command(); + $command = self::get_root_command(); $cmd_path = array(); @@ -267,14 +267,14 @@ private static function find_command_to_run( $args ) { $subcommand = $command->find_subcommand( $args ); if ( !$subcommand ) { - \WP_CLI::error( sprintf( + self::error( sprintf( "'%s' is not a registered wp command. See 'wp help'.", $full_name ) ); } if ( in_array( $full_name, $disabled_commands ) ) { - \WP_CLI::error( sprintf( + self::error( sprintf( "The '%s' command has been disabled from the config file.", $full_name ) ); From ac041c617a386a39cd627f19fee70737ef564ec6 Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:41:33 +0200 Subject: [PATCH 1949/5359] introduce get_configurator() getter We don't want to allow people to change the configurator instance just yet. --- php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/WP_CLI/Runner.php | 4 ++-- php/class-wp-cli.php | 6 +++++- php/commands/cli.php | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 67282fd6a..311d295bb 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -20,7 +20,7 @@ function __construct() { function get_extra_markdown() { $binding = array(); - foreach ( \WP_CLI::$configurator->get_spec() as $key => $details ) { + foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { if ( false === $details['runtime'] ) continue; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b3de186ff..dacbd3028 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -269,7 +269,7 @@ private function init_logger() { } public function before_wp_load() { - list( $args, $assoc_args, $runtime_config ) = \WP_CLI::$configurator->parse_args( + list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( @@ -277,7 +277,7 @@ public function before_wp_load() { $this->config_path = self::get_config_path( $runtime_config ); - $local_config = \WP_CLI::$configurator->load_config( $this->config_path ); + $local_config = \WP_CLI::get_configurator()->load_config( $this->config_path ); $this->config = $local_config; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 2df1376a9..dc3462f21 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -8,7 +8,7 @@ */ class WP_CLI { - public static $configurator; + private static $configurator; public static $runner; private static $logger; @@ -36,6 +36,10 @@ static function set_logger( $logger ) { self::$logger = $logger; } + static function get_configurator() { + return self::$configurator; + } + static function colorize( $string ) { return \cli\Colors::colorize( $string, self::$runner->in_color() ); } diff --git a/php/commands/cli.php b/php/commands/cli.php index 110fcb098..a31493b87 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -46,7 +46,7 @@ function info() { * @subcommand param-dump */ function param_dump() { - echo json_encode( \WP_CLI::$configurator->get_spec() ); + echo json_encode( \WP_CLI::get_configurator()->get_spec() ); } /** From 20ee2ae3817354285970cc107d2700cbc8f77e1b Mon Sep 17 00:00:00 2001 From: scribu Date: Sun, 30 Jun 2013 23:44:49 +0200 Subject: [PATCH 1950/5359] introduce WP_CLI::get_runner() getter We don't want to allow people to change the runner instance either. --- php/WP_CLI/Dispatcher/CompositeCommand.php | 2 +- php/class-wp-cli.php | 4 ++++ php/wp-cli.php | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 90dc7fe1b..1aa21b5d3 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -20,7 +20,7 @@ public function __construct( $parent, $name, $docparser ) { $when_to_invoke = $docparser->get_tag( 'when' ); if ( $when_to_invoke ) { - \WP_CLI::$runner->register_early_invoke( $when_to_invoke, $this ); + \WP_CLI::get_runner()->register_early_invoke( $when_to_invoke, $this ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index dc3462f21..9b91d35fc 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -40,6 +40,10 @@ static function get_configurator() { return self::$configurator; } + static function get_runner() { + return self::$runner; + } + static function colorize( $string ) { return \cli\Colors::colorize( $string, self::$runner->in_color() ); } diff --git a/php/wp-cli.php b/php/wp-cli.php index 5970c361f..1064b77e6 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -14,10 +14,10 @@ WP_CLI::init(); -WP_CLI::$runner->before_wp_load(); +WP_CLI::get_runner()->before_wp_load(); // Load wp-config.php code, in the global scope -eval( WP_CLI::$runner->get_wp_config_code() ); +eval( WP_CLI::get_runner()->get_wp_config_code() ); // Simulate a /wp-admin/ page load $_SERVER['PHP_SELF'] = '/wp-admin/index.php'; @@ -34,5 +34,5 @@ require ABSPATH . 'wp-admin/includes/admin.php'; do_action( 'admin_init' ); -WP_CLI::$runner->after_wp_load(); +WP_CLI::get_runner()->after_wp_load(); From 36aac2e3f69d16bc431b58ad840b2d13fa40436f Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 1 Jul 2013 01:52:19 +0200 Subject: [PATCH 1951/5359] travis: test against PHP 5.5 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cff1fea32..7ed5e423f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: php php: - 5.3 - - 5.4 + - 5.5 env: - WP_VERSION=latest @@ -10,7 +10,7 @@ env: matrix: exclude: - - php: 5.4 + - php: 5.5 env: WP_VERSION=3.4.2 before_script: ./bin/ci/install_dependencies.sh From 5cfe3c1d83df156887b1db740d1a617c5d67d299 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Tue, 2 Jul 2013 12:26:09 +1000 Subject: [PATCH 1952/5359] bool -> list --- php/config-spec.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/config-spec.php b/php/config-spec.php index 1ec7556f8..a2f174769 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -65,7 +65,7 @@ ), 'apache_modules' => array( - 'file' => '', + 'file' => '', 'desc' => 'List of Apache Modules that are to be reported as loaded', 'multiple' => true, 'default' => array(), From d48fee13b22bdbf9fdd5bd285ef80e1c483247da Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Tue, 2 Jul 2013 12:28:01 +1000 Subject: [PATCH 1953/5359] remove debug line --- php/utils.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index f75525710..e2523f296 100644 --- a/php/utils.php +++ b/php/utils.php @@ -371,8 +371,6 @@ function run_mysql_query( $query, $args ) { } } - echo $arg_str . "\n"; - run_mysql_command( 'mysql', $arg_str, $args['pass'] ); } From a7c9fd9ca8dd5e4214b0674eeeedc59aa27d4d13 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 20:18:54 -0700 Subject: [PATCH 1954/5359] Improve `theme install` logic to support force-installing a specific version. Previous `theme install` logic: * Updates the theme if there's an update available. * Installs if the theme isn't installed. * Otherwise, assume the theme is installed. New `theme install` logic: * Don't do anything if theme is already installed and no `--version` specified. * If `--version` is set and is different than what's installed, force install. * Install if the theme isn't installed. --- php/commands/theme.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 681d273be..e6824309f 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -113,20 +113,20 @@ protected function install_from_repo( $slug, $assoc_args ) { self::alter_api_response( $api, $assoc_args['version'] ); } - // Check to see if we should update, rather than install. - if ( $this->has_update( $slug ) ) { - WP_CLI::log( sprintf( 'Updating %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $slug ); - - /** - * Else, if there's no update, it's either not installed, - * or it's newer than what we've got. - */ - } else if ( !wp_get_theme( $slug )->exists() ) { + $theme_obj = wp_get_theme( $slug ); + if ( $theme_obj->exists() + && empty( $assoc_args['version'] ) ) { + // Theme is already installed to the correct version. + WP_CLI::error( 'Theme already installed.' ); + } else if ( $theme_obj->exists() + && version_compare( $assoc_args['version'], $theme_obj->version, '!=' ) ) { + // Theme is installed, but we want a different version + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + delete_theme( $theme_obj->stylesheet ); + $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); + } else if ( ! $theme_obj->exists() ) { WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); - } else { - WP_CLI::error( 'Theme already installed and up to date.' ); } // Finally, activate theme if requested. From 8565c6fb9212dd850019a9ab0ed8bbe7cf5365e2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 20:30:56 -0700 Subject: [PATCH 1955/5359] A Behat test for force-installing a plugin --- features/plugin.feature | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 174ab4abe..349559f51 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -60,3 +60,25 @@ Feature: Manage WordPress plugins """ The plugin 'zombieland' could not be found. """ + + Scenario: Install a plugin, activate, then force install an older version of the plugin + Given a WP install + + When I run `wp plugin install akismet --version=2.5.7` + Then STDOUT should not be empty + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | inactive | available | 2.5.7 | + + When I run `wp plugin activate akismet` + Then STDOUT should not be empty + + When I run `wp plugin install akismet --version=2.5.6` + Then STDOUT should not be empty + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | active | available | 2.5.6 | From 7979a5bd1866cb3438d679a16fcc2f7cfdc1ae12 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 20:35:24 -0700 Subject: [PATCH 1956/5359] Behat test for force-installing a specific version of a theme. --- features/theme.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index f7a57b5b9..b599957bd 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -47,3 +47,24 @@ Feature: Manage WordPress themes When I run `wp theme list` Then STDOUT should not be empty + Scenario: Install a theme, activate, then force install an older version of the theme + Given a WP install + + When I run `wp theme install p2 --version=1.4.2` + Then STDOUT should not be empty + + When I run `wp theme list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | p2 | inactive | available | 1.4.2 | + + When I run `wp theme activate p2` + Then STDOUT should not be empty + + When I run `wp theme install p2 --version=1.4.1` + Then STDOUT should not be empty + + When I run `wp theme list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | p2 | active | available | 1.4.1 | From da576a63037aeb77fd5e4288f9e8feabeddace48 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 20:58:29 -0700 Subject: [PATCH 1957/5359] Support for `count` as a format type; update PHPdoc --- php/utils.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 72ab48445..810f3fb1e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -248,15 +248,21 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria } /** - * Output items in a table, JSON, or CSV + * Output items in a table, JSON, CSV, ids, or the total count * - * @param string $format Format to use: 'table', 'json', 'csv', 'ids' + * @param string $format Format to use: 'table', 'json', 'csv', 'ids', 'count' * @param array $items Data to output * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ function format_items( $format, $items, $fields ) { - if ( 'ids' == $format ) + + if ( 'ids' == $format ) { echo implode( ' ', $items ); + return; + } else if ( 'count' == $format ) { + echo count( $items ); + return; + } if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); From fbc4792d159adbe3c4e593b1ad7c3d84a11b0820 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 20:59:04 -0700 Subject: [PATCH 1958/5359] Fix maths error --- features/import.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/import.feature b/features/import.feature index dc9f201a1..feca82c72 100644 --- a/features/import.feature +++ b/features/import.feature @@ -12,7 +12,7 @@ Feature: Import content. When I run `wp post list --post_type=any --format=csv | wc -l` Then STDOUT should be: """ - 8 + 7 """ When I run `wp export` From c4ee20dac02564643f27b06fb8354860ddc2c50c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 21:00:32 -0700 Subject: [PATCH 1959/5359] Scratch, fbc4792 was because I dropped the CSV heading. Update the rest of the scenarios --- features/import.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/import.feature b/features/import.feature index feca82c72..a10af3184 100644 --- a/features/import.feature +++ b/features/import.feature @@ -9,7 +9,7 @@ Feature: Import content. When I run `wp post generate --post_type=page --count=2` Then STDOUT should not be empty - When I run `wp post list --post_type=any --format=csv | wc -l` + When I run `wp post list --post_type=any --format=count` Then STDOUT should be: """ 7 @@ -25,10 +25,10 @@ Feature: Import content. When I run `wp site empty --yes` Then STDOUT should not be empty - When I run `wp post list --post_type=any --format=csv | wc -l` + When I run `wp post list --post_type=any --format=count` Then STDOUT should be: """ - 1 + 0 """ When I run `wp plugin install wordpress-importer --activate` @@ -37,8 +37,8 @@ Feature: Import content. When I run `wp import {EXPORT_FILE} --authors=skip` Then STDOUT should not be empty - When I run `wp post list --post_type=any --format=csv | wc -l` + When I run `wp post list --post_type=any --format=count` Then STDOUT should be: """ - 8 + 7 """ From 97d266b23478c5efb164c679891f73d75316b832 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 1 Jul 2013 21:01:59 -0700 Subject: [PATCH 1960/5359] Update user behat tests to use `--format=count` --- features/user.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/user.feature b/features/user.feature index 8743d1273..137ee8936 100644 --- a/features/user.feature +++ b/features/user.feature @@ -30,10 +30,10 @@ Feature: Manage WordPress users When I run `wp user generate --count=10` Then STDOUT should not be empty - When I run `wp user list | wc -l | tr -d ' '` + When I run `wp user list --format=count` Then STDOUT should be: """ - 11 + 10 """ Scenario: Importing users from a CSV file @@ -49,10 +49,10 @@ Feature: Manage WordPress users When I run `wp user import-csv users.csv` Then STDOUT should not be empty - When I run `wp user list | wc -l | tr -d ' '` + When I run `wp user list --format=count` Then STDOUT should be: """ - 4 + 3 """ When I run `wp user list --format=json` From 50010c4c30ed2a270c3d776626c520e083873798 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 2 Jul 2013 06:39:46 -0700 Subject: [PATCH 1961/5359] Mention why there's no break See https://github.com/wp-cli/wp-cli/pull/476/files#r4981709 [ci-skip] --- php/commands/plugin.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 54639bc3f..8ebb2ed7a 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -177,6 +177,7 @@ protected function install_from_repo( $slug, $assoc_args ) { list( $file, $name ) = $this->parse_name( array( $api->slug ) ); $this->_delete( $file ); } + // fallthrough - need to install the plugin nows case 'install': $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); From eaac711c6f3e204c5a59da09ab97e60497c99204 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 2 Jul 2013 17:22:41 +0200 Subject: [PATCH 1962/5359] instantiate WP_CLI\Runner on demand; see #571 This allows early commands to be defined in third-party packages. --- php/class-wp-cli.php | 45 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9b91d35fc..784a29622 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -9,7 +9,6 @@ class WP_CLI { private static $configurator; - public static $runner; private static $logger; @@ -24,7 +23,6 @@ static function init() { self::add_man_dir( null, WP_CLI_ROOT . "/man-src" ); self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); - self::$runner = new WP_CLI\Runner; } /** @@ -40,12 +38,28 @@ static function get_configurator() { return self::$configurator; } + static function get_root_command() { + static $root; + + if ( !$root ) { + $root = new Dispatcher\RootCommand; + } + + return $root; + } + static function get_runner() { - return self::$runner; + static $runner; + + if ( !$runner ) { + $runner = new WP_CLI\Runner; + } + + return $runner; } static function colorize( $string ) { - return \cli\Colors::colorize( $string, self::$runner->in_color() ); + return \cli\Colors::colorize( $string, self::get_runner()->in_color() ); } /** @@ -88,16 +102,6 @@ static function add_command( $name, $class, $args = array() ) { self::get_root_command()->add_subcommand( $name, $command ); } - static function get_root_command() { - static $root; - - if ( !$root ) { - $root = new Dispatcher\RootCommand; - } - - return $root; - } - static function add_man_dir( $deprecated = null, $src_dir ) { self::$man_dirs[] = $src_dir; } @@ -151,7 +155,7 @@ static function warning( $message, $label = 'Warning' ) { * @param string $label */ static function error( $message, $label = 'Error' ) { - if ( ! isset( self::$runner->assoc_args[ 'completions' ] ) ) { + if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { self::$logger->error( self::error_to_string( $message ), $label ); } @@ -246,19 +250,20 @@ static function launch( $command, $exit_on_error = true ) { } static function get_config_path() { - return self::$runner->config_path; + return self::get_runner()->config_path; } static function get_config( $key = null ) { - if ( null === $key ) - return self::$runner->config; + if ( null === $key ) { + return self::get_runner()->config; + } - if ( !isset( self::$runner->config[ $key ] ) ) { + if ( !isset( self::get_runner()->config[ $key ] ) ) { self::warning( "Unknown config option '$key'." ); return null; } - return self::$runner->config[ $key ]; + return self::get_runner()->config[ $key ]; } private static function find_command_to_run( $args ) { From 7efff3015a7d615169a01764799fd7a316694812 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 09:44:11 +1000 Subject: [PATCH 1963/5359] add comment explaining need for apache_modules() function --- php/commands/rewrite.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 3453496e1..297caba79 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -93,6 +93,26 @@ public function dump( $args, $assoc_args ) { /** * Expose apache modules if present in config + * + * Implementation Notes: This function exposes a global function + * apache_get_modules and also sets the $is_apache global variable. + * + * This is so that flush_rewrite_rules will actually write out the + * .htaccess file for apache wordpress installations. There is a check + * to see: + * + * 1. if the $is_apache variable is set. + * 2. if the mod_rewrite module is returned from the apche_get_modules + * function. + * + * To get this to work with wp-cli you'll need to add the mod_rewrite module + * to your config.yml. For example + * + * apache_modules: + * - mod_rewrite + * + * If this isn't done then the .htaccess rewrite rules won't be flushed out + * to disk. */ public static function apache_modules() { $mods = WP_CLI::get_config('apache_modules'); From 070ad89cbba10dce8cbdbe379bdc5caaf239335b Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 11:42:37 +1000 Subject: [PATCH 1964/5359] don\'t hard code localhost --- php/commands/core.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9f450ce5b..c14344c4b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -336,7 +336,7 @@ function update_db() { * * @subcommand init-tests * - * @synopsis [] --dbname= --dbuser= [--dbpass=] + * @synopsis [] --dbname= --dbuser= [--dbpass=] [--dbhost=] */ function init_tests( $args, $assoc_args ) { if ( isset( $args[0] ) ) @@ -346,6 +346,7 @@ function init_tests( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( 'dbpass' => '', + 'dbhost' => 'localhost' ) ); // Download the test suite @@ -355,7 +356,7 @@ function init_tests( $args, $assoc_args ) { $query = sprintf( 'CREATE DATABASE IF NOT EXISTS `%s`', $assoc_args['dbname'] ); Utils\run_mysql_query( $query, array( - 'host' => 'localhost', + 'host' => $assoc_args['dbhost'], 'user' => $assoc_args['dbuser'], 'pass' => $assoc_args['dbpass'], ) ); From f75d5a1f41ecc3af14ca721a9a0ea931a6327b38 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 12:26:57 +1000 Subject: [PATCH 1965/5359] replace host in config file --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index c14344c4b..59964c082 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -369,6 +369,7 @@ function init_tests( $args, $assoc_args ) { "yourdbnamehere" => $assoc_args['dbname'], "yourusernamehere" => $assoc_args['dbuser'], "yourpasswordhere" => $assoc_args['dbpass'], + "localhost" => $assoc_args['dbhost'], ); $config_file = str_replace( array_keys( $replacements ), array_values( $replacements ), $config_file ); From e3f0c5b59cafb81165ea356c6491e6120b1b0542 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 15:46:38 +1000 Subject: [PATCH 1966/5359] inline sed replace that is portable across GNU linux and Mac OSX --- templates/install-wp-tests.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index a93a900d6..616bfb99b 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -21,12 +21,16 @@ tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR # set up testing suite svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR +# portable in-place argument for both GNU sed and Mac OSX sed +[[ $(uname -s) == 'Darwin' ]] && ioption=(-i "") || ioption=(-i) + +# generate testing config file cd $WP_TESTS_DIR cp wp-tests-config-sample.php wp-tests-config.php -sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php -sed -i "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php -sed -i "s/yourusernamehere/$DB_USER/" wp-tests-config.php -sed -i "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php +sed "${ioption[@]}" "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php +sed "${ioption[@]}" "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php +sed "${ioption[@]}" "s/yourusernamehere/$DB_USER/" wp-tests-config.php +sed "${ioption[@]}" "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php # create database mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS" From 0004bbc4689249b96dbd4438f685c692e24a41f7 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 15:48:16 +1000 Subject: [PATCH 1967/5359] enable passing through a db hostname with port, socket, etc --- templates/install-wp-tests.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 616bfb99b..7d2572214 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -1,14 +1,15 @@ #!/usr/bin/env bash if [ $# -lt 3 ]; then - echo "usage: $0 [wp-version]" + echo "usage: $0 [db-host] [wp-version]" exit 1 fi DB_NAME=$1 DB_USER=$2 DB_PASS=$3 -WP_VERSION=${4-master} +DB_HOST=$4 +WP_VERSION=${5-master} set -ex @@ -31,6 +32,23 @@ sed "${ioption[@]}" "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-t sed "${ioption[@]}" "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php sed "${ioption[@]}" "s/yourusernamehere/$DB_USER/" wp-tests-config.php sed "${ioption[@]}" "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php +sed "${ioption[@]}" "s/localhost/${DB_HOST//\//\\/}/" wp-tests-config.php + +# parse DB_HOST for port or socket references +PARTS=(${DB_HOST//\:/ }) +DB_HOSTNAME=${PARTS[0]}; +DB_SOCK_OR_PORT=${PARTS[1]}; +EXTRA="" + +if ! [ -z $DB_HOSTNAME ] ; then + if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi +fi # create database -mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS" +mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA From 047fdc7f67d8ecc02cd7f48cfc18d79ec86c7078 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 16:42:59 +1000 Subject: [PATCH 1968/5359] default host to localhost --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 7d2572214..2357d1a82 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -8,7 +8,7 @@ fi DB_NAME=$1 DB_USER=$2 DB_PASS=$3 -DB_HOST=$4 +DB_HOST=${4:-localhost} WP_VERSION=${5-master} set -ex From 97da95413727b3c0b3affa68c5038b246d90bd56 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 21:46:59 +1000 Subject: [PATCH 1969/5359] use | as sed separator --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 2357d1a82..151c10b3d 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -32,7 +32,7 @@ sed "${ioption[@]}" "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-t sed "${ioption[@]}" "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php sed "${ioption[@]}" "s/yourusernamehere/$DB_USER/" wp-tests-config.php sed "${ioption[@]}" "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php -sed "${ioption[@]}" "s/localhost/${DB_HOST//\//\\/}/" wp-tests-config.php +sed "${ioption[@]}" "s|localhost|${DB_HOST}|" wp-tests-config.php # parse DB_HOST for port or socket references PARTS=(${DB_HOST//\:/ }) From 9a148445ce4b8f081034ca0aff1161bbdb418445 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 3 Jul 2013 21:51:37 +1000 Subject: [PATCH 1970/5359] fix whitespace and count -> empty --- php/commands/rewrite.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 297caba79..71538d25b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -116,12 +116,12 @@ public function dump( $args, $assoc_args ) { */ public static function apache_modules() { $mods = WP_CLI::get_config('apache_modules'); - if ( count($mods) > 0 && !function_exists( 'apache_get_modules') ) { + if ( !empty( $mods ) && !function_exists( 'apache_get_modules' ) ) { global $is_apache; $is_apache = true; function apache_get_modules() { - return WP_CLI::get_config('apache_modules'); + return WP_CLI::get_config( 'apache_modules' ); } } } From a12965c749c8e10f76246990de799c1c8608cdea Mon Sep 17 00:00:00 2001 From: James Collins Date: Fri, 5 Jul 2013 14:16:45 +1000 Subject: [PATCH 1971/5359] Bug fix: allow plugins and themes to be installed from zip file URLs that contain GET parameters Without this bug fix, doing something like: wp plugin install http://downloads.wordpress.org/plugin/buddypress.1.7.2.zip?test would fail, because wp-cli wouldn't recognise that the URL contains a zip file. This is because the wp-cli code assumes that ".zip" are the last 4 characters in the URL. With this bug fix, the .zip file detection in URLs has been improved, so the above command works as expected. This allows (for example), plugins/themes to be installed directly from private Amazon S3 URLs (which have GET parameters in the URLs). For example: wp plugin install 'http://s3.amazonaws.com/bucketname/plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef' Note: for complex URLs that contain ampersands, it is usually necessary to enclose the URL in single quotes. --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 65ede4f56..efc6b316f 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -101,7 +101,7 @@ function install( $args, $assoc_args ) { $slug = stripslashes( $args[0] ); - if ( '.zip' == substr( $slug, -4 ) ) { + if ( '.zip' == substr( $slug, strrpos($slug, '.'), 4 ) ) { $file_upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); if ( $file_upgrader->install( $slug ) ) { From 743092d08e4ef2c8b754ece8e2f17e9474b8b515 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 5 Jul 2013 19:52:12 +0200 Subject: [PATCH 1972/5359] replace VerboseExportWriter class with 'wp_export_new_file' hook --- php/WP_CLI/VerboseExportWriter.php | 73 ------------------------------ php/commands/export.php | 6 ++- php/export/writers.php | 1 + 3 files changed, 6 insertions(+), 74 deletions(-) delete mode 100644 php/WP_CLI/VerboseExportWriter.php diff --git a/php/WP_CLI/VerboseExportWriter.php b/php/WP_CLI/VerboseExportWriter.php deleted file mode 100644 index 5facc3f90..000000000 --- a/php/WP_CLI/VerboseExportWriter.php +++ /dev/null @@ -1,73 +0,0 @@ -max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; - $this->destination_directory = $writer_args['destination_directory']; - $this->filename_template = $writer_args['filename_template']; - $this->before_posts_xml = $this->formatter->before_posts(); - $this->after_posts_xml = $this->formatter->after_posts(); - } - - public function export() { - $this->start_new_file(); - foreach( $this->formatter->posts() as $post_xml ) { - if ( ( $this->current_file_size + strlen( $post_xml ) ) > $this->max_file_size ) { - $this->start_new_file(); - } - $this->write( $post_xml ); - } - $this->close_current_file(); - } - - protected function write( $xml ) { - $res = fwrite( $this->f, $xml); - if ( false === $res ) { - throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); - } - $this->current_file_size += strlen( $xml ); - } - - private function start_new_file() { - if ( $this->f ) { - $this->close_current_file(); - } - $file_path = $this->next_file_path(); - $this->f = fopen( $file_path, 'w' ); - if ( !$this->f ) { - throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); - } - \WP_CLI::log( sprintf( "Started writing to %s", $file_path ) ); - $this->current_file_size = 0; - $this->write( $this->before_posts_xml ); - } - - private function close_current_file() { - if ( !$this->f ) { - return; - } - $this->write( $this->after_posts_xml ); - fclose( $this->f ); - } - - private function next_file_name() { - $next_file_name = sprintf( $this->filename_template, $this->next_file_number ); - $this->next_file_number++; - return $next_file_name; - } - - private function next_file_path() { - return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name(); - } -} - diff --git a/php/commands/export.php b/php/commands/export.php index 97a319b9f..3d4130b5c 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -35,9 +35,13 @@ public function __invoke( $_, $assoc_args ) { WP_CLI::log( 'Starting export process...' ); + add_action( 'wp_export_new_file', function( $file_path ) { + WP_CLI::log( sprintf( "Started writing to %s", $file_path ) ); + } ); + wp_export( array( 'filters' => $this->export_args, - 'writer' => '\\WP_CLI\\VerboseExportWriter', + 'writer' => 'WP_Export_Split_Files_Writer', 'writer_args' => array( 'max_file_size' => $this->max_file_size * MB_IN_BYTES, 'destination_directory' => $this->wxr_path, diff --git a/php/export/writers.php b/php/export/writers.php index 52a68d702..751d356a1 100644 --- a/php/export/writers.php +++ b/php/export/writers.php @@ -120,6 +120,7 @@ private function start_new_file() { if ( !$this->f ) { throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); } + do_action( 'wp_export_new_file', $file_path ); $this->current_file_size = 0; $this->write( $this->before_posts_xml ); } From 0f58857c7e7bc2b019e982e545250d5edbec99f1 Mon Sep 17 00:00:00 2001 From: scribu Date: Fri, 5 Jul 2013 20:03:20 +0200 Subject: [PATCH 1973/5359] behat: fix import by making the export message match the expected format again --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 3d4130b5c..f7d722807 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -36,7 +36,7 @@ public function __invoke( $_, $assoc_args ) { WP_CLI::log( 'Starting export process...' ); add_action( 'wp_export_new_file', function( $file_path ) { - WP_CLI::log( sprintf( "Started writing to %s", $file_path ) ); + WP_CLI::log( sprintf( "Writing to file %s", $file_path ) ); } ); wp_export( array( From e749f71cb00d2f905bf794677250818e05df58a5 Mon Sep 17 00:00:00 2001 From: James Collins Date: Sat, 6 Jul 2013 11:34:07 +1000 Subject: [PATCH 1974/5359] behat: Tests to demonstraten the plugin/theme install bug in #581 * Install plugins from WordPress.org repository, a local zip file, and remote zip files. * Install themes from WordPress.org repository, a local zip file, and remote zip files. --- features/plugin.feature | 81 ++++++++++++++++++++++++++++++++++ features/steps/basic_steps.php | 20 +++++++++ features/theme.feature | 74 +++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 174ab4abe..ad517cad3 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -60,3 +60,84 @@ Feature: Manage WordPress plugins """ The plugin 'zombieland' could not be found. """ + + Scenario: Install plugins from WordPress.org repository, a local zip file, and remote zip files + Given a WP install + And I run `wp plugin path` + And save STDOUT as {PLUGIN_DIR} + And a local mp6 plugin zip file + + When I run `wp plugin delete akismet` + Then STDOUT should contain: + """ + Success: Deleted 'akismet' plugin. + """ + And the {PLUGIN_DIR}/akismet file should not exist + + # Install plugin from WordPress.org repository + When I run `wp plugin install akismet` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And the {PLUGIN_DIR}/akismet/akismet.php file should exist + + When I try the previous command again + Then the return code should be 1 + And STDERR should contain: + """ + Error: Latest version already installed. + """ + + When I run `wp plugin delete akismet` + Then STDOUT should contain: + """ + Success: Deleted 'akismet' plugin. + """ + And the {PLUGIN_DIR}/akismet file should not exist + + # Install plugin from a local zip file + When I run `wp plugin install {DOWNLOADED_PLUGIN_FILE}` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And the {PLUGIN_DIR}/mp6/mp6.php file should exist + And the {DOWNLOADED_PLUGIN_FILE} file should exist + + When I run `wp plugin delete mp6` + Then STDOUT should contain: + """ + Success: Deleted 'mp6' plugin. + """ + And the {PLUGIN_DIR}/mp6 file should not exist + + # Install plugin from remote ZIP file (standard URL with no GET parameters) + When I run `wp plugin install http://downloads.wordpress.org/plugin/akismet.zip` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And the {PLUGIN_DIR}/akismet/akismet.php file should exist + + When I run `wp plugin delete akismet` + Then STDOUT should contain: + """ + Success: Deleted 'akismet' plugin. + """ + And the {PLUGIN_DIR}/akismet file should not exist + + # Install plugin from remote ZIP file (complex URL with GET parameters) + When I run `wp plugin install 'http://downloads.wordpress.org/plugin/akismet.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And the {PLUGIN_DIR}/akismet/akismet.php file should exist + + When I run `wp plugin delete akismet` + Then STDOUT should contain: + """ + Success: Deleted 'akismet' plugin. + """ + And the {PLUGIN_DIR}/akismet file should not exist \ No newline at end of file diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 8198bf7b7..f8400046d 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -93,6 +93,26 @@ function ( $world ) { } ); +$steps->Given( '/^a local mp6 plugin zip file/', + function ( $world ) { + $image_file = 'http://downloads.wordpress.org/plugin/mp6.zip'; + + $world->variables['DOWNLOADED_PLUGIN_FILE'] = $world->get_cache_path( 'mp6.zip' ); + + $world->download_file( $image_file, $world->variables['DOWNLOADED_PLUGIN_FILE'] ); + } +); + +$steps->Given( '/^a local classic theme zip file/', + function ( $world ) { + $image_file = 'http://wordpress.org/themes/download/classic.1.6.zip'; + + $world->variables['DOWNLOADED_THEME_FILE'] = $world->get_cache_path( 'classic.zip' ); + + $world->download_file( $image_file, $world->variables['DOWNLOADED_THEME_FILE'] ); + } +); + $steps->When( '/^I (run|try) `([^`]+)`$/', function ( $world, $mode, $cmd ) { $cmd = $world->replace_variables( $cmd ); diff --git a/features/theme.feature b/features/theme.feature index f7a57b5b9..17195ef79 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -47,3 +47,77 @@ Feature: Manage WordPress themes When I run `wp theme list` Then STDOUT should not be empty + + Scenario: Install themes from WordPress.org repository, a local zip file, and remote zip files + Given a WP install + And I run `wp theme path` + And save STDOUT as {THEME_DIR} + And a local classic theme zip file + + # Install theme from WordPress.org repository + When I run `wp theme install classic` + Then STDOUT should contain: + """ + Theme installed successfully. + """ + And the {THEME_DIR}/classic/style.css file should exist + + When I try the previous command again + Then the return code should be 1 + And STDERR should contain: + """ + Error: Theme already installed and up to date. + """ + + When I run `wp theme delete classic` + Then STDOUT should contain: + """ + Success: Deleted 'classic' theme. + """ + And the {THEME_DIR}/classic file should not exist + + # Install Theme from a local zip file + When I run `wp theme install {DOWNLOADED_THEME_FILE}` + Then STDOUT should contain: + """ + Theme installed successfully. + """ + And the {THEME_DIR}/classic/style.css file should exist + And the {DOWNLOADED_THEME_FILE} file should exist + + When I run `wp theme delete classic` + Then STDOUT should contain: + """ + Success: Deleted 'classic' theme. + """ + And the {THEME_DIR}/classic file should not exist + + # Install Theme from remote ZIP file (standard URL with no GET parameters) + When I run `wp theme install http://wordpress.org/themes/download/classic.1.6.zip` + Then STDOUT should contain: + """ + Theme installed successfully. + """ + And the {THEME_DIR}/classic/style.css file should exist + + When I run `wp theme delete classic` + Then STDOUT should contain: + """ + Success: Deleted 'classic' theme. + """ + And the {THEME_DIR}/classic file should not exist + + # Install Theme from remote ZIP file (complex URL with GET parameters) + When I run `wp theme install 'http://wordpress.org/themes/download/classic.1.6.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` + Then STDOUT should contain: + """ + Theme installed successfully. + """ + And the {THEME_DIR}/classic/style.css file should exist + + When I run `wp theme delete classic` + Then STDOUT should contain: + """ + Success: Deleted 'classic' theme. + """ + And the {THEME_DIR}/classic file should not exist \ No newline at end of file From b26cade8e5c0131762f65abe2135f3a36f2a71a9 Mon Sep 17 00:00:00 2001 From: James Collins Date: Sat, 6 Jul 2013 11:39:59 +1000 Subject: [PATCH 1975/5359] Bug Fix for #581: allow plugins/themes to be installed from complex zip file URLs This should be more reliable than the attempted fix in a12965c. --- php/WP_CLI/CommandWithUpgrade.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index efc6b316f..1b3434842 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -101,10 +101,25 @@ function install( $args, $assoc_args ) { $slug = stripslashes( $args[0] ); - if ( '.zip' == substr( $slug, strrpos($slug, '.'), 4 ) ) { + $local_or_remote_zip_file = ''; + + // Check if a URL to a remote zip file has been specified + $url_path = parse_url( $slug, PHP_URL_PATH ); + if ( ! empty( $url_path ) && '.zip' === substr( $url_path, - 4 ) ) { + $local_or_remote_zip_file = $slug; + } else { + // Check if a local zip file has been specified + if ( 'zip' === pathinfo( $slug, PATHINFO_EXTENSION ) && file_exists( $slug ) ) { + $local_or_remote_zip_file = $slug; + } + } + + if ( ! empty( $local_or_remote_zip_file ) ) { + + // Install from local or remote zip file $file_upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); - if ( $file_upgrader->install( $slug ) ) { + if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { $slug = $file_upgrader->result['destination_name']; if ( isset( $assoc_args['activate'] ) ) { @@ -114,7 +129,9 @@ function install( $args, $assoc_args ) { } else { exit(1); } + } else { + // Assume a plugin/theme slug from the WordPress.org repository has been specified $this->install_from_repo( $slug, $assoc_args ); } } From be69d7669d061fb8844492ad8838dd64d0de1490 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 6 Jul 2013 22:34:41 +0200 Subject: [PATCH 1976/5359] behat: replace 'a large image file' step with a more generic and explicit 'download' step --- features/bootstrap/FeatureContext.php | 18 +++++------------- features/media.feature | 8 +++++--- features/steps/basic_steps.php | 19 ++++++++++++------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 25836cc02..a4e6b45e5 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -77,6 +77,7 @@ public function afterScenario( $event ) { */ public function __construct( array $parameters ) { $this->drop_db(); + $this->set_cache_dir(); } public function getStepDefinitionResources() { @@ -112,19 +113,10 @@ public function get_path( $file ) { return $this->install_dir . '/' . $file; } - public function get_cache_path( $file ) { - static $path; - - if ( !$path ) { - $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); - } - - return $path . '/' . $file; - } - - public function download_file( $url, $path ) { - Process::create( Utils\esc_cmd( 'curl -sSL %s > %s', $url, $path ) )->run_check(); + private function set_cache_dir() { + $path = sys_get_temp_dir() . '/wp-cli-test-cache'; + Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + $this->variables['CACHE_DIR'] = $path; } private static function run_sql( $sql ) { diff --git a/features/media.feature b/features/media.feature index ddb721c48..e09e2b173 100644 --- a/features/media.feature +++ b/features/media.feature @@ -33,9 +33,11 @@ Feature: Manage WordPress attachments @images Scenario: Import a file as attachment from a local image Given a WP install - And a large image file + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg | - When I run `wp media import {DOWNLOADED_IMAGE} --post_id=1 --featured_image` + When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` Then STDOUT should contain: """ Success: Imported file @@ -44,4 +46,4 @@ Feature: Manage WordPress attachments """ and attached to post 1 as featured image """ - And the {DOWNLOADED_IMAGE} file should exist + And the {CACHE_DIR}/large-image.jpg file should exist diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 8198bf7b7..874c34209 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -83,13 +83,18 @@ function ( $world ) { } ); -$steps->Given( '/^a large image file$/', - function ( $world ) { - $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; - - $world->variables['DOWNLOADED_IMAGE'] = $world->get_cache_path( 'wallpaper.jpg' ); +$steps->Given( '/^download:$/', + function ( $world, TableNode $table ) { + foreach ( $table->getHash() as $row ) { + $path = $world->replace_variables( $row['path'] ); + if ( file_exists( $path ) ) { + var_dump($path); + // assume it's the same file and skip re-download + continue; + } - $world->download_file( $image_file, $world->variables['DOWNLOADED_IMAGE'] ); + \Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); + } } ); @@ -128,7 +133,7 @@ function ( $world ) { $steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { - + if ( $output_filter ) { $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) From a2798f96a29cde367f88b1d7093d0866501ef6f5 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 6 Jul 2013 22:45:14 +0200 Subject: [PATCH 1977/5359] behat: convert install_dir private property to RUN_DIR variable --- features/bootstrap/FeatureContext.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index a4e6b45e5..83f8b2ccb 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -26,8 +26,6 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { private static $additional_args; - private $install_dir; - public $variables = array(); // We cache the results of `wp core download` to improve test performance @@ -61,11 +59,12 @@ public static function prepare( SuiteEvent $event ) { * @AfterScenario */ public function afterScenario( $event ) { - if ( !$this->install_dir ) + if ( !isset( $this->variables['RUN_DIR'] ) ) return; + // remove altered WP install, unless there's an error if ( $event->getResult() < 4 ) { - Process::create( Utils\esc_cmd( 'rm -r %s', $this->install_dir ) )->run(); + Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); } } @@ -103,14 +102,14 @@ private function _replace_var( $matches ) { } public function create_empty_dir() { - if ( !$this->install_dir ) { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); - mkdir( $this->install_dir ); + if ( !isset( $this->variables['RUN_DIR'] ) ) { + $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); + mkdir( $this->variables['RUN_DIR'] ); } } public function get_path( $file ) { - return $this->install_dir . '/' . $file; + return $this->variables['RUN_DIR'] . '/' . $file; } private function set_cache_dir() { @@ -148,7 +147,7 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( $command, $this->install_dir ); + return Process::create( $command, $this->variables['RUN_DIR'] ); } public function move_files( $src, $dest ) { From 59369baf41a2c33b9b069af97998f63e6c24645d Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 6 Jul 2013 22:56:10 +0200 Subject: [PATCH 1978/5359] behat: remove get_path() helper method --- features/bootstrap/FeatureContext.php | 8 ++------ features/steps/basic_steps.php | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 83f8b2ccb..31e10fd1b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -108,10 +108,6 @@ public function create_empty_dir() { } } - public function get_path( $file ) { - return $this->variables['RUN_DIR'] . '/' . $file; - } - private function set_cache_dir() { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); @@ -151,7 +147,7 @@ public function proc( $command, $assoc_args = array() ) { } public function move_files( $src, $dest ) { - rename( $this->get_path( $src ), $this->get_path( $dest ) ); + rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); } public function add_line_to_wp_config( &$wp_config_code, $line ) { @@ -161,7 +157,7 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { } public function download_wordpress_files( $subdir = '' ) { - $dest_dir = $this->get_path( $subdir ); + $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; if ( $subdir ) mkdir( $dest_dir ); diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 874c34209..481b4cc34 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -22,7 +22,7 @@ function ( $world ) { $steps->Given( '/^a ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; - $full_path = $world->get_path( $path ); + $full_path = $world->variables['RUN_DIR'] . "/$path"; Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); file_put_contents( $full_path, $content ); } @@ -67,7 +67,7 @@ function ( $world ) { $steps->Given( '/^a custom wp-content directory$/', function ( $world ) { - $wp_config_path = $world->get_path( 'wp-config.php' ); + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; $wp_config_code = file_get_contents( $wp_config_path ); @@ -237,7 +237,7 @@ function ( $world, $path, $action, $expected = null ) { // If it's a relative path, make it relative to the current test dir if ( '/' !== $path[0] ) - $path = $world->get_path( $path ); + $path = $world->variables['RUN_DIR'] . "/$path"; switch ( $action ) { case 'exist': From 6671b38302248631b6c78d091c6193ddba650285 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 6 Jul 2013 22:58:07 +0200 Subject: [PATCH 1979/5359] behat: rename some helper methods --- features/bootstrap/FeatureContext.php | 13 +++++++------ features/steps/basic_steps.php | 10 +++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 31e10fd1b..8c4dc9fad 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -101,7 +101,7 @@ private function _replace_var( $matches ) { return $cmd; } - public function create_empty_dir() { + public function create_run_dir() { if ( !isset( $this->variables['RUN_DIR'] ) ) { $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); mkdir( $this->variables['RUN_DIR'] ); @@ -156,7 +156,7 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); } - public function download_wordpress_files( $subdir = '' ) { + public function download_wp( $subdir = '' ) { $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; if ( $subdir ) mkdir( $dest_dir ); @@ -164,12 +164,13 @@ public function download_wordpress_files( $subdir = '' ) { Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); } - public function wp_install( $subdir = '' ) { + public function install_wp( $subdir = '' ) { $this->create_db(); - $this->create_empty_dir(); - $this->download_wordpress_files( $subdir ); + $this->create_run_dir(); + $this->download_wp( $subdir ); - $this->proc( 'wp core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); + $dbprefix = $subdir ?: 'wp_'; + $this->proc( 'wp core config', compact( 'dbprefix' ) )->run_check( $subdir ); $install_args = array( 'url' => 'http://example.com', diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 481b4cc34..ce1d956a6 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -15,7 +15,7 @@ function invoke_proc( $proc, $mode, $subdir = null ) { $steps->Given( '/^an empty directory$/', function ( $world ) { - $world->create_empty_dir(); + $world->create_run_dir(); } ); @@ -30,7 +30,7 @@ function ( $world, $path, PyStringNode $content ) { $steps->Given( '/^WP files$/', function ( $world ) { - $world->download_wordpress_files(); + $world->download_wp(); } ); @@ -48,19 +48,19 @@ function ( $world ) { $steps->Given( '/^a WP install$/', function ( $world ) { - $world->wp_install(); + $world->install_wp(); } ); $steps->Given( "/^a WP install in '([^\s]+)'$/", function ( $world, $subdir ) { - $world->wp_install( $subdir ); + $world->install_wp( $subdir ); } ); $steps->Given( '/^a WP multisite install$/', function ( $world ) { - $world->wp_install(); + $world->install_wp(); $world->proc( 'wp core install-network' )->run_check(); } ); From 498fb6a001e2a9dbb6ccc8220356a8485f1fd533 Mon Sep 17 00:00:00 2001 From: scribu Date: Sat, 6 Jul 2013 23:10:58 +0200 Subject: [PATCH 1980/5359] behat: remove var_dump() --- features/steps/basic_steps.php | 1 - 1 file changed, 1 deletion(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index ce1d956a6..6d84fdc60 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -88,7 +88,6 @@ function ( $world, TableNode $table ) { foreach ( $table->getHash() as $row ) { $path = $world->replace_variables( $row['path'] ); if ( file_exists( $path ) ) { - var_dump($path); // assume it's the same file and skip re-download continue; } From b07154ed976b937aa9875cf55573722e38308ef6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Sun, 7 Jul 2013 18:58:02 +0100 Subject: [PATCH 1981/5359] If a plugin or theme is already installed and the `--version` parameter is used, prompt the user to confirm they'd like it installed. See https://github.com/wp-cli/wp-cli/pull/476#issuecomment-20354895 --- php/commands/plugin.php | 7 +++++-- php/commands/theme.php | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 8ebb2ed7a..73e11eace 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -173,7 +173,10 @@ protected function install_from_repo( $slug, $assoc_args ) { case 'newer_installed': case 'update_available': if ( isset( $assoc_args['version'] ) - && version_compare( $status['version'], $assoc_args['version'], '>=' ) ) { + && version_compare( $status['version'], $assoc_args['version'], '!=' ) ) { + + WP_CLI::confirm( "A different version is installed. Overwrite it?", $assoc_args ); + list( $file, $name ) = $this->parse_name( array( $api->slug ) ); $this->_delete( $file ); } @@ -249,7 +252,7 @@ protected function get_item_list() { /** * Install a plugin. * - * @synopsis [--version=] [--activate] + * @synopsis [--version=] [--activate] [--yes] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); diff --git a/php/commands/theme.php b/php/commands/theme.php index e6824309f..df2da7f67 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -121,6 +121,8 @@ protected function install_from_repo( $slug, $assoc_args ) { } else if ( $theme_obj->exists() && version_compare( $assoc_args['version'], $theme_obj->version, '!=' ) ) { // Theme is installed, but we want a different version + WP_CLI::confirm( "A different version is installed. Overwrite it?", $assoc_args ); + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); delete_theme( $theme_obj->stylesheet ); $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); @@ -157,7 +159,7 @@ protected function get_item_list() { /** * Install a theme. * - * @synopsis [--version=] [--activate] + * @synopsis [--version=] [--activate] [--yes] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); From 396adfcc339b3e3dc9cde4dcaebb962b2bb61265 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Sun, 7 Jul 2013 20:08:12 +0100 Subject: [PATCH 1982/5359] Update stories to support b07154e. Behat isn't working properly on my local machine bcause of my shoddy connection, so let's see if this passes in Travis --- features/plugin.feature | 2 +- features/theme.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 349559f51..5c3e9fb26 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -75,7 +75,7 @@ Feature: Manage WordPress plugins When I run `wp plugin activate akismet` Then STDOUT should not be empty - When I run `wp plugin install akismet --version=2.5.6` + When I run `wp plugin install akismet --version=2.5.6 --yes` Then STDOUT should not be empty When I run `wp plugin list` diff --git a/features/theme.feature b/features/theme.feature index b599957bd..afc96a97d 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -61,7 +61,7 @@ Feature: Manage WordPress themes When I run `wp theme activate p2` Then STDOUT should not be empty - When I run `wp theme install p2 --version=1.4.1` + When I run `wp theme install p2 --version=1.4.1 --yes` Then STDOUT should not be empty When I run `wp theme list` From fb760886206e76681746ce6322796380ee5aa6ff Mon Sep 17 00:00:00 2001 From: James Collins Date: Mon, 8 Jul 2013 09:10:08 +1000 Subject: [PATCH 1983/5359] Merge remote-tracking branch 'upstream/master' into zipfiles Changes: https://github.com/wp-cli/wp-cli/compare/fbaab715...498fb6 behat: replace 'a large image file' step with a more generic and explicit 'download' step --- features/bootstrap/FeatureContext.php | 54 +++++++++++---------------- features/media.feature | 8 ++-- features/steps/basic_steps.php | 34 +++++++++-------- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 25836cc02..8c4dc9fad 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -26,8 +26,6 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { private static $additional_args; - private $install_dir; - public $variables = array(); // We cache the results of `wp core download` to improve test performance @@ -61,11 +59,12 @@ public static function prepare( SuiteEvent $event ) { * @AfterScenario */ public function afterScenario( $event ) { - if ( !$this->install_dir ) + if ( !isset( $this->variables['RUN_DIR'] ) ) return; + // remove altered WP install, unless there's an error if ( $event->getResult() < 4 ) { - Process::create( Utils\esc_cmd( 'rm -r %s', $this->install_dir ) )->run(); + Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); } } @@ -77,6 +76,7 @@ public function afterScenario( $event ) { */ public function __construct( array $parameters ) { $this->drop_db(); + $this->set_cache_dir(); } public function getStepDefinitionResources() { @@ -101,30 +101,17 @@ private function _replace_var( $matches ) { return $cmd; } - public function create_empty_dir() { - if ( !$this->install_dir ) { - $this->install_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); - mkdir( $this->install_dir ); - } - } - - public function get_path( $file ) { - return $this->install_dir . '/' . $file; - } - - public function get_cache_path( $file ) { - static $path; - - if ( !$path ) { - $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + public function create_run_dir() { + if ( !isset( $this->variables['RUN_DIR'] ) ) { + $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); + mkdir( $this->variables['RUN_DIR'] ); } - - return $path . '/' . $file; } - public function download_file( $url, $path ) { - Process::create( Utils\esc_cmd( 'curl -sSL %s > %s', $url, $path ) )->run_check(); + private function set_cache_dir() { + $path = sys_get_temp_dir() . '/wp-cli-test-cache'; + Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + $this->variables['CACHE_DIR'] = $path; } private static function run_sql( $sql ) { @@ -156,11 +143,11 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( $command, $this->install_dir ); + return Process::create( $command, $this->variables['RUN_DIR'] ); } public function move_files( $src, $dest ) { - rename( $this->get_path( $src ), $this->get_path( $dest ) ); + rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); } public function add_line_to_wp_config( &$wp_config_code, $line ) { @@ -169,20 +156,21 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); } - public function download_wordpress_files( $subdir = '' ) { - $dest_dir = $this->get_path( $subdir ); + public function download_wp( $subdir = '' ) { + $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; if ( $subdir ) mkdir( $dest_dir ); Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); } - public function wp_install( $subdir = '' ) { + public function install_wp( $subdir = '' ) { $this->create_db(); - $this->create_empty_dir(); - $this->download_wordpress_files( $subdir ); + $this->create_run_dir(); + $this->download_wp( $subdir ); - $this->proc( 'wp core config', array( 'dbprefix' => $subdir ? $subdir : 'wp_' ) )->run_check( $subdir ); + $dbprefix = $subdir ?: 'wp_'; + $this->proc( 'wp core config', compact( 'dbprefix' ) )->run_check( $subdir ); $install_args = array( 'url' => 'http://example.com', diff --git a/features/media.feature b/features/media.feature index ddb721c48..e09e2b173 100644 --- a/features/media.feature +++ b/features/media.feature @@ -33,9 +33,11 @@ Feature: Manage WordPress attachments @images Scenario: Import a file as attachment from a local image Given a WP install - And a large image file + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg | - When I run `wp media import {DOWNLOADED_IMAGE} --post_id=1 --featured_image` + When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` Then STDOUT should contain: """ Success: Imported file @@ -44,4 +46,4 @@ Feature: Manage WordPress attachments """ and attached to post 1 as featured image """ - And the {DOWNLOADED_IMAGE} file should exist + And the {CACHE_DIR}/large-image.jpg file should exist diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index f8400046d..8fe4d431e 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -15,14 +15,14 @@ function invoke_proc( $proc, $mode, $subdir = null ) { $steps->Given( '/^an empty directory$/', function ( $world ) { - $world->create_empty_dir(); + $world->create_run_dir(); } ); $steps->Given( '/^a ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; - $full_path = $world->get_path( $path ); + $full_path = $world->variables['RUN_DIR'] . "/$path"; Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); file_put_contents( $full_path, $content ); } @@ -30,7 +30,7 @@ function ( $world, $path, PyStringNode $content ) { $steps->Given( '/^WP files$/', function ( $world ) { - $world->download_wordpress_files(); + $world->download_wp(); } ); @@ -48,26 +48,26 @@ function ( $world ) { $steps->Given( '/^a WP install$/', function ( $world ) { - $world->wp_install(); + $world->install_wp(); } ); $steps->Given( "/^a WP install in '([^\s]+)'$/", function ( $world, $subdir ) { - $world->wp_install( $subdir ); + $world->install_wp( $subdir ); } ); $steps->Given( '/^a WP multisite install$/', function ( $world ) { - $world->wp_install(); + $world->install_wp(); $world->proc( 'wp core install-network' )->run_check(); } ); $steps->Given( '/^a custom wp-content directory$/', function ( $world ) { - $wp_config_path = $world->get_path( 'wp-config.php' ); + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; $wp_config_code = file_get_contents( $wp_config_path ); @@ -83,13 +83,17 @@ function ( $world ) { } ); -$steps->Given( '/^a large image file$/', - function ( $world ) { - $image_file = 'http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg'; - - $world->variables['DOWNLOADED_IMAGE'] = $world->get_cache_path( 'wallpaper.jpg' ); +$steps->Given( '/^download:$/', + function ( $world, TableNode $table ) { + foreach ( $table->getHash() as $row ) { + $path = $world->replace_variables( $row['path'] ); + if ( file_exists( $path ) ) { + // assume it's the same file and skip re-download + continue; + } - $world->download_file( $image_file, $world->variables['DOWNLOADED_IMAGE'] ); + \Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); + } } ); @@ -148,7 +152,7 @@ function ( $world ) { $steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { - + if ( $output_filter ) { $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) @@ -252,7 +256,7 @@ function ( $world, $path, $action, $expected = null ) { // If it's a relative path, make it relative to the current test dir if ( '/' !== $path[0] ) - $path = $world->get_path( $path ); + $path = $world->variables['RUN_DIR'] . "/$path"; switch ( $action ) { case 'exist': From 05f6beed91ad2a5339c274dec060dc241a477f4d Mon Sep 17 00:00:00 2001 From: James Collins Date: Mon, 8 Jul 2013 09:54:53 +1000 Subject: [PATCH 1984/5359] behat: Convert duplicate plugin/theme tests to scenario outlines Converts the plugin/theme tests added in e749f71 to Behat's scenario outlines (http://docs.behat.org/guides/1.gherkin.html#scenario-outlines), which removes test duplication. vendor/bin/behat features/upgradables.feature --expand --- features/plugin.feature | 81 ------------------------------------ features/theme.feature | 75 --------------------------------- features/upgradables.feature | 66 +++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 160 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index ad517cad3..174ab4abe 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -60,84 +60,3 @@ Feature: Manage WordPress plugins """ The plugin 'zombieland' could not be found. """ - - Scenario: Install plugins from WordPress.org repository, a local zip file, and remote zip files - Given a WP install - And I run `wp plugin path` - And save STDOUT as {PLUGIN_DIR} - And a local mp6 plugin zip file - - When I run `wp plugin delete akismet` - Then STDOUT should contain: - """ - Success: Deleted 'akismet' plugin. - """ - And the {PLUGIN_DIR}/akismet file should not exist - - # Install plugin from WordPress.org repository - When I run `wp plugin install akismet` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And the {PLUGIN_DIR}/akismet/akismet.php file should exist - - When I try the previous command again - Then the return code should be 1 - And STDERR should contain: - """ - Error: Latest version already installed. - """ - - When I run `wp plugin delete akismet` - Then STDOUT should contain: - """ - Success: Deleted 'akismet' plugin. - """ - And the {PLUGIN_DIR}/akismet file should not exist - - # Install plugin from a local zip file - When I run `wp plugin install {DOWNLOADED_PLUGIN_FILE}` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And the {PLUGIN_DIR}/mp6/mp6.php file should exist - And the {DOWNLOADED_PLUGIN_FILE} file should exist - - When I run `wp plugin delete mp6` - Then STDOUT should contain: - """ - Success: Deleted 'mp6' plugin. - """ - And the {PLUGIN_DIR}/mp6 file should not exist - - # Install plugin from remote ZIP file (standard URL with no GET parameters) - When I run `wp plugin install http://downloads.wordpress.org/plugin/akismet.zip` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And the {PLUGIN_DIR}/akismet/akismet.php file should exist - - When I run `wp plugin delete akismet` - Then STDOUT should contain: - """ - Success: Deleted 'akismet' plugin. - """ - And the {PLUGIN_DIR}/akismet file should not exist - - # Install plugin from remote ZIP file (complex URL with GET parameters) - When I run `wp plugin install 'http://downloads.wordpress.org/plugin/akismet.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And the {PLUGIN_DIR}/akismet/akismet.php file should exist - - When I run `wp plugin delete akismet` - Then STDOUT should contain: - """ - Success: Deleted 'akismet' plugin. - """ - And the {PLUGIN_DIR}/akismet file should not exist \ No newline at end of file diff --git a/features/theme.feature b/features/theme.feature index 17195ef79..d4a073c52 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -46,78 +46,3 @@ Feature: Manage WordPress themes When I run `wp theme list` Then STDOUT should not be empty - - - Scenario: Install themes from WordPress.org repository, a local zip file, and remote zip files - Given a WP install - And I run `wp theme path` - And save STDOUT as {THEME_DIR} - And a local classic theme zip file - - # Install theme from WordPress.org repository - When I run `wp theme install classic` - Then STDOUT should contain: - """ - Theme installed successfully. - """ - And the {THEME_DIR}/classic/style.css file should exist - - When I try the previous command again - Then the return code should be 1 - And STDERR should contain: - """ - Error: Theme already installed and up to date. - """ - - When I run `wp theme delete classic` - Then STDOUT should contain: - """ - Success: Deleted 'classic' theme. - """ - And the {THEME_DIR}/classic file should not exist - - # Install Theme from a local zip file - When I run `wp theme install {DOWNLOADED_THEME_FILE}` - Then STDOUT should contain: - """ - Theme installed successfully. - """ - And the {THEME_DIR}/classic/style.css file should exist - And the {DOWNLOADED_THEME_FILE} file should exist - - When I run `wp theme delete classic` - Then STDOUT should contain: - """ - Success: Deleted 'classic' theme. - """ - And the {THEME_DIR}/classic file should not exist - - # Install Theme from remote ZIP file (standard URL with no GET parameters) - When I run `wp theme install http://wordpress.org/themes/download/classic.1.6.zip` - Then STDOUT should contain: - """ - Theme installed successfully. - """ - And the {THEME_DIR}/classic/style.css file should exist - - When I run `wp theme delete classic` - Then STDOUT should contain: - """ - Success: Deleted 'classic' theme. - """ - And the {THEME_DIR}/classic file should not exist - - # Install Theme from remote ZIP file (complex URL with GET parameters) - When I run `wp theme install 'http://wordpress.org/themes/download/classic.1.6.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` - Then STDOUT should contain: - """ - Theme installed successfully. - """ - And the {THEME_DIR}/classic/style.css file should exist - - When I run `wp theme delete classic` - Then STDOUT should contain: - """ - Success: Deleted 'classic' theme. - """ - And the {THEME_DIR}/classic file should not exist \ No newline at end of file diff --git a/features/upgradables.feature b/features/upgradables.feature index e44428617..fbda07e2d 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -2,7 +2,18 @@ Feature: Manage WordPress themes and plugins Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install - And I run `wp install --version=` + And download: + | path | url | + | {CACHE_DIR}/.zip | | + And I run `wp path` + And save STDOUT as {CONTENT_DIR} + + # Install an out of date from WordPress.org repository + When I run `wp install --version=` + Then STDOUT should contain: + """ + installed successfully + """ When I run `wp status` Then STDOUT should contain: @@ -36,7 +47,54 @@ Feature: Manage WordPress themes and plugins Then the return code should be 1 And STDERR should not be empty + + # Install from local zip file + When I run `wp install {CACHE_DIR}/.zip` + Then STDOUT should contain: + """ + installed successfully. + """ + And the file should exist + + When I run `wp delete ` + Then STDOUT should contain: + """ + Success: Deleted '' . + """ + And the file should not exist + + # Install plugin from remote ZIP file (standard URL with no GET parameters) + When I run `wp install ` + Then STDOUT should contain: + """ + installed successfully. + """ + And the file should exist + + When I run `wp delete ` + Then STDOUT should contain: + """ + Success: Deleted '' . + """ + And the file should not exist + + # Install from remote ZIP file (complex URL with GET parameters) + When I run `wp install '?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` + Then STDOUT should contain: + """ + installed successfully. + """ + And the file should exist + + When I run `wp delete ` + Then STDOUT should contain: + """ + Success: Deleted '' . + """ + And the file should not exist + + Examples: - | type | item | version | - | theme | p2 | 1.0.1 | - | plugin | category-checklist-tree | 1.2 | + | type | type_name | item | version | zip_file | file_to_check | + | theme | Theme | p2 | 1.0.1 | http://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | + | plugin | Plugin | category-checklist-tree | 1.2 | http://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | From 01fd2847b18b762c7a993fbd6de1d3f701d3bea7 Mon Sep 17 00:00:00 2001 From: James Collins Date: Mon, 8 Jul 2013 17:32:01 +1000 Subject: [PATCH 1985/5359] behat: upgradables comment updates --- features/upgradables.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index fbda07e2d..7ca5b06ae 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -48,7 +48,7 @@ Feature: Manage WordPress themes and plugins And STDERR should not be empty - # Install from local zip file + # Install from a local zip file When I run `wp install {CACHE_DIR}/.zip` Then STDOUT should contain: """ @@ -63,7 +63,7 @@ Feature: Manage WordPress themes and plugins """ And the file should not exist - # Install plugin from remote ZIP file (standard URL with no GET parameters) + # Install from a remote zip file (standard URL with no GET parameters) When I run `wp install ` Then STDOUT should contain: """ @@ -78,7 +78,7 @@ Feature: Manage WordPress themes and plugins """ And the file should not exist - # Install from remote ZIP file (complex URL with GET parameters) + # Install from a remote zip file (complex URL with GET parameters) When I run `wp install '?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` Then STDOUT should contain: """ From 0281324c80a7326f53565cfdcca8e8a9b75299af Mon Sep 17 00:00:00 2001 From: James Collins Date: Mon, 8 Jul 2013 17:55:25 +1000 Subject: [PATCH 1986/5359] man-src updates for #581 --- man-src/plugin-install.txt | 6 +++++- man-src/theme-install.txt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/man-src/plugin-install.txt b/man-src/plugin-install.txt index 90f951721..f8887421c 100644 --- a/man-src/plugin-install.txt +++ b/man-src/plugin-install.txt @@ -2,7 +2,7 @@ * : - A plugin slug or the path to a zip file. + A plugin slug, the path to a local zip file, or URL to a remote zip file. * `--version`=: @@ -20,3 +20,7 @@ stable version. wp plugin install bbpress --version=dev wp plugin install ../my-plugin.zip + + wp plugin install http://mydomain.com/my-plugin.zip + + wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef diff --git a/man-src/theme-install.txt b/man-src/theme-install.txt index a7377e628..3ea74e081 100644 --- a/man-src/theme-install.txt +++ b/man-src/theme-install.txt @@ -2,7 +2,7 @@ * ``: - A theme slug or the path to a zip file. + A theme slug, the path to a local zip file, or URL to a remote zip file. * `--activate`: @@ -13,3 +13,7 @@ wp theme install twentytwelve --activate wp theme install ../my-theme.zip + + wp theme install http://mydomain.com/my-theme.zip + + wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef \ No newline at end of file From b85e04c8dc7e0564b10df126ef57e84da6da7f07 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 11:06:30 +0300 Subject: [PATCH 1987/5359] add comments to examples for plugin/theme install see #581 --- man-src/plugin-install.txt | 10 ++++++---- man-src/theme-install.txt | 9 +++++---- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/man-src/plugin-install.txt b/man-src/plugin-install.txt index f8887421c..9561c92ce 100644 --- a/man-src/plugin-install.txt +++ b/man-src/plugin-install.txt @@ -1,6 +1,6 @@ ## OPTIONS -* : +* : A plugin slug, the path to a local zip file, or URL to a remote zip file. @@ -15,12 +15,14 @@ stable version. ## EXAMPLES - wp plugin install bbpress --version=2.1 --activate + # Install the latest version from wordpress.org and activate + wp plugin install bbpress --activate + # Install the development version from wordpress.org wp plugin install bbpress --version=dev + # Install from a local zip file wp plugin install ../my-plugin.zip - wp plugin install http://mydomain.com/my-plugin.zip - + # Install from a remote zip file wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef diff --git a/man-src/theme-install.txt b/man-src/theme-install.txt index 3ea74e081..0cf7271e1 100644 --- a/man-src/theme-install.txt +++ b/man-src/theme-install.txt @@ -1,6 +1,6 @@ ## OPTIONS -* ``: +* ``: A theme slug, the path to a local zip file, or URL to a remote zip file. @@ -10,10 +10,11 @@ ## EXAMPLES + # Install the latest version from wordpress.org and activate wp theme install twentytwelve --activate + # Install from a local zip file wp theme install ../my-theme.zip - wp theme install http://mydomain.com/my-theme.zip - - wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef \ No newline at end of file + # Install from a remote zip file + wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c96d85465..17989e7f1 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -242,7 +242,7 @@ protected function get_item_list() { /** * Install a plugin. * - * @synopsis [--version=] [--activate] + * @synopsis [--version=] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 681d273be..b5639d25a 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -157,7 +157,7 @@ protected function get_item_list() { /** * Install a theme. * - * @synopsis [--version=] [--activate] + * @synopsis [--version=] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); From 25a02192559a31c2b461b3c62f9bb1b88365fcd5 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Mon, 8 Jul 2013 18:11:38 +1000 Subject: [PATCH 1988/5359] ternary -> if else --- templates/install-wp-tests.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 151c10b3d..e1f08050c 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -23,7 +23,11 @@ tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR # portable in-place argument for both GNU sed and Mac OSX sed -[[ $(uname -s) == 'Darwin' ]] && ioption=(-i "") || ioption=(-i) +if [[ $(uname -s) == 'Darwin' ]]; then + ioption=(-i "") +else + ioption=(-i) +fi # generate testing config file cd $WP_TESTS_DIR From 7f546af3c35dd34484b9734b258ccd4b04f549b9 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Mon, 8 Jul 2013 18:15:03 +1000 Subject: [PATCH 1989/5359] remove : --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index e1f08050c..3f4001ec4 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -8,7 +8,7 @@ fi DB_NAME=$1 DB_USER=$2 DB_PASS=$3 -DB_HOST=${4:-localhost} +DB_HOST=${4-localhost} WP_VERSION=${5-master} set -ex From 359a7084f223e279b7e99fc3b12f61f294be60b9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 8 Jul 2013 10:44:47 +0100 Subject: [PATCH 1990/5359] Force install Akismet, as it comes with a default WordPress install. --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 5c3e9fb26..49bcc55c7 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -64,7 +64,7 @@ Feature: Manage WordPress plugins Scenario: Install a plugin, activate, then force install an older version of the plugin Given a WP install - When I run `wp plugin install akismet --version=2.5.7` + When I run `wp plugin install akismet --version=2.5.7 --yes` Then STDOUT should not be empty When I run `wp plugin list` From fd265ff5bd3ca5b87ab46bbe4d258d1e519ee8f4 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Mon, 8 Jul 2013 19:48:16 +1000 Subject: [PATCH 1991/5359] ioption fixes --- templates/install-wp-tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 3f4001ec4..82cd598ed 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -24,19 +24,19 @@ svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP # portable in-place argument for both GNU sed and Mac OSX sed if [[ $(uname -s) == 'Darwin' ]]; then - ioption=(-i "") + ioption='-i ""' else - ioption=(-i) + ioption='-i' fi # generate testing config file cd $WP_TESTS_DIR cp wp-tests-config-sample.php wp-tests-config.php -sed "${ioption[@]}" "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php -sed "${ioption[@]}" "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php -sed "${ioption[@]}" "s/yourusernamehere/$DB_USER/" wp-tests-config.php -sed "${ioption[@]}" "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php -sed "${ioption[@]}" "s|localhost|${DB_HOST}|" wp-tests-config.php +sed $ioption "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php +sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php +sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php +sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php +sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php # parse DB_HOST for port or socket references PARTS=(${DB_HOST//\:/ }) From 473c1c8c448ca21324ff6ce4ba5577276ea177e1 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Mon, 8 Jul 2013 20:32:57 +1000 Subject: [PATCH 1992/5359] fix travis.yml --- templates/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index a91b121be..de2d819e5 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -12,6 +12,6 @@ env: before_script: - export WP_TESTS_DIR=/tmp/wordpress-tests/ - - bash bin/install-wp-tests.sh wordpress_test root '' $WP_VERSION + - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION script: phpunit From 515a1375f493c8ef489b18dd9fb7debdf7833ebd Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 18:51:58 +0300 Subject: [PATCH 1993/5359] replace --yes with --force --- features/plugin.feature | 4 ++-- features/theme.feature | 2 +- php/class-wp-cli.php | 2 +- php/commands/plugin.php | 5 +++-- php/commands/theme.php | 5 +++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 49bcc55c7..f48979760 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -64,7 +64,7 @@ Feature: Manage WordPress plugins Scenario: Install a plugin, activate, then force install an older version of the plugin Given a WP install - When I run `wp plugin install akismet --version=2.5.7 --yes` + When I run `wp plugin install akismet --version=2.5.7 --force` Then STDOUT should not be empty When I run `wp plugin list` @@ -75,7 +75,7 @@ Feature: Manage WordPress plugins When I run `wp plugin activate akismet` Then STDOUT should not be empty - When I run `wp plugin install akismet --version=2.5.6 --yes` + When I run `wp plugin install akismet --version=2.5.6 --force` Then STDOUT should not be empty When I run `wp plugin list` diff --git a/features/theme.feature b/features/theme.feature index afc96a97d..a42199f48 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -61,7 +61,7 @@ Feature: Manage WordPress themes When I run `wp theme activate p2` Then STDOUT should not be empty - When I run `wp theme install p2 --version=1.4.1 --yes` + When I run `wp theme install p2 --version=1.4.1 --force` Then STDOUT should not be empty When I run `wp theme list` diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 784a29622..7d2c9dff4 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -165,7 +165,7 @@ static function error( $message, $label = 'Error' ) { /** * Ask for confirmation before running a destructive operation. */ - static function confirm( $question, $assoc_args ) { + static function confirm( $question, $assoc_args = array() ) { if ( !isset( $assoc_args['yes'] ) ) { echo $question . " [y/n] "; diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 725a0fd9c..19259de28 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -175,7 +175,8 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( isset( $assoc_args['version'] ) && version_compare( $status['version'], $assoc_args['version'], '!=' ) ) { - WP_CLI::confirm( "A different version is installed. Overwrite it?", $assoc_args ); + if ( !isset( $assoc_args['force'] ) ) + WP_CLI::confirm( "A different version is installed. Overwrite it?" ); list( $file, $name ) = $this->parse_name( array( $api->slug ) ); $this->_delete( $file ); @@ -252,7 +253,7 @@ protected function get_item_list() { /** * Install a plugin. * - * @synopsis [--version=] [--activate] [--yes] + * @synopsis [--version=] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); diff --git a/php/commands/theme.php b/php/commands/theme.php index d6e82df7b..de17fb0f4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -121,7 +121,8 @@ protected function install_from_repo( $slug, $assoc_args ) { } else if ( $theme_obj->exists() && version_compare( $assoc_args['version'], $theme_obj->version, '!=' ) ) { // Theme is installed, but we want a different version - WP_CLI::confirm( "A different version is installed. Overwrite it?", $assoc_args ); + if ( !isset( $assoc_args['force'] ) ) + WP_CLI::confirm( "A different version is installed. Overwrite it?" ); WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); delete_theme( $theme_obj->stylesheet ); @@ -159,7 +160,7 @@ protected function get_item_list() { /** * Install a theme. * - * @synopsis [--version=] [--activate] [--yes] + * @synopsis [--version=] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); From 223ab887f3ff923fc76320d8daf96a0bd0d0c17c Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 18:56:14 +0300 Subject: [PATCH 1994/5359] document --force flag --- man-src/plugin-install.txt | 5 +++++ man-src/theme-install.txt | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/man-src/plugin-install.txt b/man-src/plugin-install.txt index 9561c92ce..e896cca2f 100644 --- a/man-src/plugin-install.txt +++ b/man-src/plugin-install.txt @@ -9,6 +9,11 @@ If set, get that particular version from wordpress.org, instead of the stable version. +* `--force`: + + If set, the command will overwrite any installed version of the plugin, without prompting +for confirmation. + * `--activate`: If set, the plugin will be activated immediately after install. diff --git a/man-src/theme-install.txt b/man-src/theme-install.txt index 0cf7271e1..b8eced70c 100644 --- a/man-src/theme-install.txt +++ b/man-src/theme-install.txt @@ -4,6 +4,11 @@ A theme slug, the path to a local zip file, or URL to a remote zip file. +* `--force`: + + If set, the command will overwrite any installed version of the theme, without prompting +for confirmation. + * `--activate`: If set, the theme will be activated immediately after install. From aa7537846abcdcf46a44bb28f3b8e8a54db6cf43 Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 20:36:13 +0300 Subject: [PATCH 1995/5359] make parse_name a private function, since it's not used in CommandWithUpgrade also, each implementation returns different things --- php/WP_CLI/CommandWithUpgrade.php | 2 -- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 1b3434842..74413303d 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -9,8 +9,6 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $upgrade_refresh; protected $upgrade_transient; - abstract protected function parse_name( $args ); - abstract protected function get_item_list(); abstract protected function get_all_items(); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 17989e7f1..e432b4699 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -330,7 +330,7 @@ protected function get_details( $file ) { * @param array $args * @return array */ - protected function parse_name( $args ) { + private function parse_name( $args ) { $name = $args[0]; $plugins = get_plugins( '/' . $name ); diff --git a/php/commands/theme.php b/php/commands/theme.php index b5639d25a..cabca9de0 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -216,7 +216,7 @@ function _list( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); } - protected function parse_name( $args ) { + private function parse_name( $args ) { $name = $args[0]; $theme = wp_get_theme( $name ); From c54acb14e04379bb2d40a10904d2db8a9bc958eb Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 21:07:10 +0300 Subject: [PATCH 1996/5359] plugin: parse_name() only needs the first arg and only needs to return the filename. It accepted the whole arguments initially because it used to check if the slug was missing. This is handled by the synopsis validator now, beforehand. --- php/commands/plugin.php | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e432b4699..8c5895fac 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -36,7 +36,8 @@ function status( $args ) { } protected function status_single( $args ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); $details = $this->get_details( $file ); @@ -77,7 +78,8 @@ protected function get_all_items() { * @synopsis [--network] */ function activate( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -96,7 +98,8 @@ function activate( $args, $assoc_args = array() ) { * @synopsis [--network] */ function deactivate( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -115,7 +118,8 @@ function deactivate( $args, $assoc_args = array() ) { * @synopsis [--network] */ function toggle( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -135,7 +139,7 @@ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { - list( $file, $name ) = $this->parse_name( $args ); + $file = $this->parse_name( $args[0] ); $path .= '/' . $file; if ( isset( $assoc_args['dir'] ) ) @@ -190,7 +194,8 @@ protected function install_from_repo( $slug, $assoc_args ) { * @synopsis [--version=] */ function update( $args, $assoc_args ) { - list( $basename ) = $this->parse_name( $args ); + $name = $args[0]; + $basename = $this->parse_name( $name ); if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { $this->_delete( $basename, false ); @@ -254,7 +259,8 @@ function install( $args, $assoc_args ) { * @synopsis [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); if ( is_plugin_active( $file ) ) { WP_CLI::error( 'The plugin is active.' ); @@ -276,7 +282,8 @@ function uninstall( $args, $assoc_args = array() ) { * @synopsis */ function delete( $args, $assoc_args = array() ) { - list( $file, $name ) = $this->parse_name( $args ); + $name = $args[0]; + $file = $this->parse_name( $name ); if ( $this->_delete( $file ) ) { WP_CLI::success( sprintf( "Deleted '%s' plugin.", $name ) ); @@ -325,14 +332,12 @@ protected function get_details( $file ) { } /** - * Parse the name of a plugin to a filename, check if it exists + * Parse the name of a plugin to a filename; check if it exists. * - * @param array $args - * @return array + * @param string name + * @return string */ - private function parse_name( $args ) { - $name = $args[0]; - + private function parse_name( $name ) { $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { @@ -349,9 +354,12 @@ private function parse_name( $args ) { } } - return array( $file, $name ); + return $file; } + /** + * Converts a plugin basename back into a friendly slug. + */ private function get_name( $file ) { if ( false === strpos( $file, '/' ) ) $name = basename( $file, '.php' ); From c83739c8c24e3eb7fd668540e18b3b0f1f2b56db Mon Sep 17 00:00:00 2001 From: scribu Date: Mon, 8 Jul 2013 21:23:35 +0300 Subject: [PATCH 1997/5359] theme: parse_name() only needs the first argument --- php/commands/theme.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index cabca9de0..3ac4a59a5 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -29,7 +29,7 @@ function status( $args ) { } protected function status_single( $args ) { - $theme = $this->parse_name( $args ); + $theme = $this->parse_name( $args[0] ); $status = $this->format_status( $this->get_status( $theme ), 'long' ); @@ -60,7 +60,7 @@ protected function get_status( $theme ) { * @synopsis */ public function activate( $args = array() ) { - $theme = $this->parse_name( $args ); + $theme = $this->parse_name( $args[0] ); switch_theme( $theme->get_template(), $theme->get_stylesheet() ); @@ -86,7 +86,7 @@ function path( $args, $assoc_args ) { if ( empty( $args ) ) { $path = WP_CONTENT_DIR . '/themes'; } else { - $theme = $this->parse_name( $args ); + $theme = $this->parse_name( $args[0] ); $path = $theme->get_stylesheet_directory(); @@ -169,7 +169,7 @@ function install( $args, $assoc_args ) { * @synopsis [--version=] */ function update( $args, $assoc_args ) { - $theme = $this->parse_name( $args ); + $theme = $this->parse_name( $args[0] ); parent::_update( $theme->get_stylesheet() ); } @@ -190,7 +190,7 @@ function update_all( $args, $assoc_args ) { * @synopsis */ function delete( $args ) { - $theme = $this->parse_name( $args ); + $theme = $this->parse_name( $args[0] ); $theme_slug = $theme->get_stylesheet(); if ( $this->is_active_theme( $theme ) ) { @@ -216,9 +216,13 @@ function _list( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); } - private function parse_name( $args ) { - $name = $args[0]; - + /** + * Parse the name of a plugin to a filename; check if it exists. + * + * @param string name + * @return object + */ + private function parse_name( $name ) { $theme = wp_get_theme( $name ); if ( !$theme->exists() ) { From f30d795bb4c69cbdaac16e89618b4a407c9a23b2 Mon Sep 17 00:00:00 2001 From: scribu Date: Tue, 9 Jul 2013 01:19:52 +0300 Subject: [PATCH 1998/5359] leverage 'clear_destination' parameter from WP_Upgrader --- php/WP_CLI/CommandWithUpgrade.php | 18 +++++++++--------- php/WP_CLI/DestructivePluginUpgrader.php | 18 ++++++++++++++++++ php/WP_CLI/DestructiveThemeUpgrader.php | 18 ++++++++++++++++++ php/commands/plugin.php | 18 +++++++++++------- php/commands/theme.php | 23 +++++++++++++---------- 5 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 php/WP_CLI/DestructivePluginUpgrader.php create mode 100644 php/WP_CLI/DestructiveThemeUpgrader.php diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 74413303d..aaac62ed9 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -5,10 +5,11 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $item_type; - protected $upgrader; protected $upgrade_refresh; protected $upgrade_transient; + abstract protected function get_upgrader_class( $force ); + abstract protected function get_item_list(); abstract protected function get_all_items(); @@ -115,7 +116,7 @@ function install( $args, $assoc_args ) { if ( ! empty( $local_or_remote_zip_file ) ) { // Install from local or remote zip file - $file_upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); + $file_upgrader = $this->get_upgrader( $assoc_args ); if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { $slug = $file_upgrader->result['destination_name']; @@ -168,10 +169,9 @@ protected static function alter_api_response( $response, $version ) { } } - protected function _update( $item ) { - call_user_func( $this->upgrade_refresh ); - - \WP_CLI\Utils\get_upgrader( $this->upgrader )->upgrade( $item ); + protected function get_upgrader( $assoc_args ) { + $upgrader_class = $this->get_upgrader_class( isset( $assoc_args['force'] ) ); + return \WP_CLI\Utils\get_upgrader( $upgrader_class ); } function update_all( $args, $assoc_args ) { @@ -196,13 +196,13 @@ function update_all( $args, $assoc_args ) { return; } - $upgrader = \WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = array(); // Only attempt to update if there is something to update - if ( !empty( $items_to_update ) ) + if ( !empty( $items_to_update ) ) { + $upgrader = $this->get_upgrader( $assoc_args ); $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); + } // Let the user know the results. $num_to_update = count( $items_to_update ); diff --git a/php/WP_CLI/DestructivePluginUpgrader.php b/php/WP_CLI/DestructivePluginUpgrader.php new file mode 100644 index 000000000..7fc0d16db --- /dev/null +++ b/php/WP_CLI/DestructivePluginUpgrader.php @@ -0,0 +1,18 @@ +_delete( $this->parse_name( $api->slug ) ); + $assoc_args['force'] = true; + } } // fallthrough - need to install the plugin nows case 'install': - $upgrader = WP_CLI\Utils\get_upgrader( $this->upgrader ); - $result = $upgrader->install( $api->download_link ); + $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); if ( $result && isset( $assoc_args['activate'] ) ) { WP_CLI::log( "Activating '$slug'..." ); @@ -214,7 +216,9 @@ function update( $args, $assoc_args ) { $was_active = is_plugin_active( $basename ); $was_network_active = is_plugin_active_for_network( $basename ); - parent::_update( $basename ); + call_user_func( $this->upgrade_refresh ); + + $this->get_upgrader( $assoc_args )->upgrade( $basename ); if ( $was_active ) { $new_args = array( $args[0] ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 5fb85eda1..b419b35ad 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -8,7 +8,6 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { protected $item_type = 'theme'; - protected $upgrader = 'Theme_Upgrader'; protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; @@ -19,6 +18,10 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { 'version' ); + protected function get_upgrader_class( $force ) { + return $force ? '\\WP_CLI\\DestructiveThemeUpgrader' : 'Theme_Upgrader'; + } + /** * See the status of one or all themes. * @@ -121,17 +124,15 @@ protected function install_from_repo( $slug, $assoc_args ) { } else if ( $theme_obj->exists() && version_compare( $assoc_args['version'], $theme_obj->version, '!=' ) ) { // Theme is installed, but we want a different version - if ( !isset( $assoc_args['force'] ) ) + if ( !isset( $assoc_args['force'] ) ) { WP_CLI::confirm( "A different version is installed. Overwrite it?" ); - - WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - delete_theme( $theme_obj->stylesheet ); - $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); - } else if ( ! $theme_obj->exists() ) { - WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - $result = WP_CLI\Utils\get_upgrader( $this->upgrader )->install( $api->download_link ); + $assoc_args['force'] = true; + } } + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); + // Finally, activate theme if requested. if ( $result && isset( $assoc_args['activate'] ) ) { WP_CLI::log( "Activating '$slug'..." ); @@ -174,7 +175,9 @@ function install( $args, $assoc_args ) { function update( $args, $assoc_args ) { $theme = $this->parse_name( $args[0] ); - parent::_update( $theme->get_stylesheet() ); + call_user_func( $this->upgrade_refresh ); + + $this->get_upgrader( $assoc_args )->upgrade( $theme->get_stylesheet() ); } /** From 54a92091ff573c6cf51d7760d8f11bf2efee8a3b Mon Sep 17 00:00:00 2001 From: scribu Date: Wed, 10 Jul 2013 14:15:29 +0300 Subject: [PATCH 1999/5359] simplify logic for theme and plugin installs --- php/commands/plugin.php | 36 +++++++++--------------------------- php/commands/theme.php | 13 ++----------- 2 files changed, 11 insertions(+), 38 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index a17fa70cc..630dbee3e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -168,35 +168,17 @@ protected function install_from_repo( $slug, $assoc_args ) { $status = install_plugin_install_status( $api ); + if ( !isset( $assoc_args['force'] ) && 'install' != $status['status'] ) { + // We know this will fail, so avoid a needless download of the package. + WP_CLI::error( 'Plugin already installed.' ); + } + WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - switch ( $status['status'] ) { - - case 'latest_installed': - WP_CLI::error( 'Latest version already installed.' ); - break; - - // Newer installed plugin, but we might want the older version - case 'newer_installed': - case 'update_available': - if ( isset( $assoc_args['version'] ) - && version_compare( $status['version'], $assoc_args['version'], '!=' ) ) { - - if ( !isset( $assoc_args['force'] ) ) { - WP_CLI::confirm( "A different version is installed. Overwrite it?" ); - $assoc_args['force'] = true; - } - } - // fallthrough - need to install the plugin nows - - case 'install': - $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - - if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } - break; + if ( $result && isset( $assoc_args['activate'] ) ) { + WP_CLI::log( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); } } diff --git a/php/commands/theme.php b/php/commands/theme.php index b419b35ad..843bf8d73 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -116,18 +116,9 @@ protected function install_from_repo( $slug, $assoc_args ) { self::alter_api_response( $api, $assoc_args['version'] ); } - $theme_obj = wp_get_theme( $slug ); - if ( $theme_obj->exists() - && empty( $assoc_args['version'] ) ) { - // Theme is already installed to the correct version. + if ( !isset( $assoc_args['force'] ) && wp_get_theme( $slug )->exists() ) { + // We know this will fail, so avoid a needless download of the package. WP_CLI::error( 'Theme already installed.' ); - } else if ( $theme_obj->exists() - && version_compare( $assoc_args['version'], $theme_obj->version, '!=' ) ) { - // Theme is installed, but we want a different version - if ( !isset( $assoc_args['force'] ) ) { - WP_CLI::confirm( "A different version is installed. Overwrite it?" ); - $assoc_args['force'] = true; - } } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); From 83b03bfd3cd1f6200889246809cc95eed05bb25f Mon Sep 17 00:00:00 2001 From: jmslbam Date: Thu, 11 Jul 2013 20:54:56 +0200 Subject: [PATCH 2000/5359] Fix notices no index featured_image --- php/commands/media.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 3657d3191..0f6db05b3 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -123,13 +123,13 @@ function import( $args, $assoc_args = array() ) { update_post_meta( $success, '_wp_attachment_image_alt', $assoc_args['alt'] ); // Set as featured image, if --post_id and --featured_image are set - if ( !is_wp_error( $success ) && $assoc_args['post_id'] && $assoc_args['featured_image'] ) + if ( !is_wp_error( $success ) && $assoc_args['post_id'] && isset($assoc_args['featured_image']) ) update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); $attachment_success_text = ''; if ( $assoc_args['post_id'] ) { $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; - if ( $assoc_args['featured_image'] ) + if ( isset($assoc_args['featured_image']) ) $attachment_success_text .= ' as featured image'; } From 935a4bdca3f88c234f63c186daf5beff01757c41 Mon Sep 17 00:00:00 2001 From: scribu Date: Thu, 11 Jul 2013 23:26:53 +0300 Subject: [PATCH 2001/5359] code formatting fixes in media.php --- php/commands/media.php | 57 ++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 0f6db05b3..4ffda2579 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -50,7 +50,10 @@ function regenerate( $args, $assoc_args = array() ) { $this->_process_regeneration( $id ); } - WP_CLI::success( sprintf( 'Finished regenerating %1$s.', ngettext('the image', 'all images', $count) ) ); + WP_CLI::success( sprintf( + 'Finished regenerating %1$s.', + ngettext('the image', 'all images', $count) + ) ); } /** @@ -59,17 +62,13 @@ function regenerate( $args, $assoc_args = array() ) { * @synopsis ... [--post_id=] [--title=] [--caption=<caption>] [--alt=<text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { - - $assoc_args = wp_parse_args( - $assoc_args, - array( - 'post_id' => false, - 'title' => null, - 'caption' => null, - 'alt' => null, - 'desc' => null - ) - ); + $assoc_args = wp_parse_args( $assoc_args, array( + 'post_id' => false, + 'title' => null, + 'caption' => null, + 'alt' => null, + 'desc' => null + ) ); if ( !get_post( $assoc_args['post_id'] ) ) { WP_CLI::warning( "Invalid --post_id" ); @@ -77,13 +76,11 @@ function import( $args, $assoc_args = array() ) { } foreach ( $args as $file ) { - $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); $orig_filename = $file; if ( empty( $is_file_remote ) ) { - // File appears to be a local file; make a copy first to work with - + // File appears to be local; make a working copy $tempfile = wp_tempnam( $file ); if ( ! $tempfile ) WP_CLI::error( 'Could not create temporary file.' ); @@ -91,10 +88,8 @@ function import( $args, $assoc_args = array() ) { copy( $file, $tempfile ); } else { - // File appear to be a remote file; download as temp file - + // File appears to be remote; download as temp file $tempfile = download_url( $file ); - } // Necessary because temp filename will probably have an extension like @@ -133,22 +128,18 @@ function import( $args, $assoc_args = array() ) { $attachment_success_text .= ' as featured image'; } - if ( is_wp_error( $success ) ) - WP_CLI::error( - sprintf( - 'Unable to import file %s. Reason: %s', - $orig_filename, implode( ', ', $success->get_error_messages() ) - ) - ); - else - WP_CLI::success( - sprintf( - 'Imported file %s as attachment ID %d%s.', - $orig_filename, $success, $attachment_success_text - ) - ); + if ( is_wp_error( $success ) ) { + WP_CLI::error( sprintf( + 'Unable to import file %s. Reason: %s', + $orig_filename, implode( ', ', $success->get_error_messages() ) + ) ); + } else { + WP_CLI::success( sprintf( + 'Imported file %s as attachment ID %d%s.', + $orig_filename, $success, $attachment_success_text + ) ); + } } - } From 44f246e4fd636616ce0aa25d6e87eb0613bf2366 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 00:04:47 +0300 Subject: [PATCH 2002/5359] media: don't call get_post() if --post_id isn't even passed --- php/commands/media.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 4ffda2579..0726f6a8f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -63,15 +63,18 @@ function regenerate( $args, $assoc_args = array() ) { */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( - 'post_id' => false, 'title' => null, 'caption' => null, 'alt' => null, 'desc' => null ) ); - if ( !get_post( $assoc_args['post_id'] ) ) { - WP_CLI::warning( "Invalid --post_id" ); + if ( isset( $assoc_args['post_id'] ) ) { + if ( !get_post( $assoc_args['post_id'] ) ) { + WP_CLI::warning( "Invalid --post_id" ); + $assoc_args['post_id'] = false; + } + } else { $assoc_args['post_id'] = false; } From ca6e32c8ddfebb44392da996adee02620660c320 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 11 Jul 2013 23:51:12 +0300 Subject: [PATCH 2003/5359] media: make the temp file have the proper extension from the start --- features/media.feature | 2 +- php/commands/media.php | 39 +++++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/features/media.feature b/features/media.feature index e09e2b173..74752d277 100644 --- a/features/media.feature +++ b/features/media.feature @@ -27,7 +27,7 @@ Feature: Manage WordPress attachments When I try `wp media import gobbledygook.png` Then STDERR should contain: """ - Error: Unable to import file gobbledygook.png. Reason: File is empty. + Unable to import file gobbledygook.png. Reason: File doesn't exist. """ @images diff --git a/php/commands/media.php b/php/commands/media.php index 0726f6a8f..22cae68c9 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -83,28 +83,17 @@ function import( $args, $assoc_args = array() ) { $orig_filename = $file; if ( empty( $is_file_remote ) ) { - // File appears to be local; make a working copy - $tempfile = wp_tempnam( $file ); - if ( ! $tempfile ) - WP_CLI::error( 'Could not create temporary file.' ); - - copy( $file, $tempfile ); - + if ( !file_exists( $file ) ) { + WP_CLI::warning( "Unable to import file $file. Reason: File doesn't exist." ); + break; + } + $tempfile = $this->_make_copy( $file ); } else { - // File appears to be remote; download as temp file $tempfile = download_url( $file ); } - // Necessary because temp filename will probably have an extension like - // .tmp, which is not in the list of permitted upload extensions - // and won't be recognized with the correct mime type - $extension = pathinfo( $file, PATHINFO_EXTENSION ); - $tempfile_extension = pathinfo( $tempfile, PATHINFO_EXTENSION ); - $file = preg_replace( "/$tempfile_extension$/", $extension, $tempfile ); - rename( $tempfile, $file ); - $file_array = array( - 'tmp_name' => $file, + 'tmp_name' => $tempfile, 'name' => basename( $file ) ); @@ -114,6 +103,7 @@ function import( $args, $assoc_args = array() ) { 'post_content' => $assoc_args['desc'] ); + // Deletes the temporary file. $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); // Set alt text @@ -132,7 +122,7 @@ function import( $args, $assoc_args = array() ) { } if ( is_wp_error( $success ) ) { - WP_CLI::error( sprintf( + WP_CLI::warning( sprintf( 'Unable to import file %s. Reason: %s', $orig_filename, implode( ', ', $success->get_error_messages() ) ) ); @@ -145,6 +135,19 @@ function import( $args, $assoc_args = array() ) { } } + // wp_tempnam() inexplicably forces a .tmp extension, which spoils MIME type detection + private function _make_copy( $path ) { + $dir = get_temp_dir(); + $filename = basename( $path ); + if ( empty( $filename ) ) + $filename = time(); + + $filename = $dir . wp_unique_filename( $dir, $filename ); + if ( !copy( $path, $filename ) ) + WP_CLI::error( "Could not create temporary file for $path" ); + + return $filename; + } private function _process_regeneration( $id ) { $image = get_post( $id ); From bbf481ad77886b24ebcc6f77ee8c6989172eb657 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 01:19:38 +0300 Subject: [PATCH 2004/5359] rename _download() to _read() to make it clearer that it doesn't deal with binary data --- php/commands/core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 59964c082..42419f649 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -46,14 +46,14 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } - private static function _download( $url ) { + private static function _read( $url ) { exec( 'curl -s ' . escapeshellarg( $url ), $lines, $r ); if ( $r ) exit( $r ); return implode( "\n", $lines ); } private function get_download_offer( $locale ) { - $out = unserialize( self::_download( + $out = unserialize( self::_read( 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ) ); return $out['offers'][0]; @@ -101,7 +101,7 @@ public function config( $_, $assoc_args ) { } // TODO: adapt more resilient code from wp-admin/setup-config.php - $assoc_args['keys-and-salts'] = self::_download( + $assoc_args['keys-and-salts'] = self::_read( 'https://api.wordpress.org/secret-key/1.1/salt/' ); $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); From 1d0ca4b0f09ee7196771e797e9ab77c5e6ca590b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Jun 2013 14:19:38 +0300 Subject: [PATCH 2005/5359] behat: make run_check() check STDERR --- features/bootstrap/Process.php | 2 +- features/flags.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 792277d9c..992428a0c 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -51,7 +51,7 @@ public function run( $subdir = '' ) { public function run_check( $subdir = '' ) { $r = $this->run( $subdir ); - if ( $r->return_code ) { + if ( $r->return_code || !empty( $r->STDERR ) ) { throw new \RuntimeException( sprintf( "%s: %s\ncwd: %s", $r->command, $r->STDERR, $r->cwd ) ); } diff --git a/features/flags.feature b/features/flags.feature index 8cb7107fc..ee07a67c7 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -28,7 +28,7 @@ Feature: Global flags CONST_WITHOUT_QUOTES """ - When I run `wp eval 'echo CONST_WITHOUT_QUOTES;' --debug` + When I try `wp eval 'echo CONST_WITHOUT_QUOTES;' --debug` Then the return code should be 0 And STDOUT should be: """ From 15910b0e738f820e71c1ab5f5076a05cba9eaf91 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 02:56:53 +0300 Subject: [PATCH 2006/5359] behat: no-op wp_mail() --- features/bootstrap/FeatureContext.php | 4 ++++ features/extra/no-mail.php | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 features/extra/no-mail.php diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 8c4dc9fad..b60c007b1 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -162,6 +162,10 @@ public function download_wp( $subdir = '' ) { if ( $subdir ) mkdir( $dest_dir ); Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); + + // disable emailing + mkdir( $dest_dir . '/wp-content/mu-plugins' ); + copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); } public function install_wp( $subdir = '' ) { diff --git a/features/extra/no-mail.php b/features/extra/no-mail.php new file mode 100644 index 000000000..ba222ad59 --- /dev/null +++ b/features/extra/no-mail.php @@ -0,0 +1,6 @@ +<?php + +function wp_mail() { + // do nothing +} + From 6804cf8a0fdefbd463238dca0dbc2eafd133e3b3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Jun 2013 16:36:39 +0300 Subject: [PATCH 2007/5359] behat: fix `user generate` test --- features/user.feature | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/features/user.feature b/features/user.feature index 137ee8936..f8f3b6136 100644 --- a/features/user.feature +++ b/features/user.feature @@ -28,9 +28,7 @@ Feature: Manage WordPress users Then STDOUT should be empty When I run `wp user generate --count=10` - Then STDOUT should not be empty - - When I run `wp user list --format=count` + And I run `wp user list --format=count` Then STDOUT should be: """ 10 From 88af0ed99071606c79257973512cd9e4e2563104 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 21 Jun 2013 16:02:24 +0300 Subject: [PATCH 2008/5359] don't show progress bar if not in a TTY this fixes 'tput: No value for $TERM and no -T specified' error --- features/import.feature | 9 ++------- php/WP_CLI/NoOp.php | 15 +++++++++++++++ php/commands/post.php | 2 +- php/commands/user.php | 2 +- php/utils.php | 7 +++++++ 5 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 php/WP_CLI/NoOp.php diff --git a/features/import.feature b/features/import.feature index a10af3184..e90d4c57b 100644 --- a/features/import.feature +++ b/features/import.feature @@ -2,13 +2,8 @@ Feature: Import content. Scenario: Basic export then import Given a WP install - - When I run `wp post generate --post_type=post --count=3` - Then STDOUT should not be empty - - When I run `wp post generate --post_type=page --count=2` - Then STDOUT should not be empty - + And I run `wp post generate --post_type=post --count=3` + And I run `wp post generate --post_type=page --count=2` When I run `wp post list --post_type=any --format=count` Then STDOUT should be: """ diff --git a/php/WP_CLI/NoOp.php b/php/WP_CLI/NoOp.php new file mode 100644 index 000000000..9334aff22 --- /dev/null +++ b/php/WP_CLI/NoOp.php @@ -0,0 +1,15 @@ +<?php + +namespace WP_CLI; + +final class NoOp { + + function __set( $key, $value ) { + // do nothing + } + + function __call( $method, $args ) { + // do nothing + } +} + diff --git a/php/commands/post.php b/php/commands/post.php index 438f86ac1..d37836603 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -243,7 +243,7 @@ public function generate( $args, $assoc_args ) { $limit = $count + $total; - $notify = new \cli\progress\Bar( 'Generating posts', $count ); + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); $current_depth = 1; $current_parent = 0; diff --git a/php/commands/user.php b/php/commands/user.php index 3533ec800..59dccb4ef 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -183,7 +183,7 @@ public function generate( $args, $assoc_args ) { $limit = $count + $total; - $notify = new \cli\progress\Bar( 'Generating users', $count ); + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); for ( $i = $total; $i < $limit; $i++ ) { $login = sprintf( 'user_%d_%d', $blog_id, $i ); diff --git a/php/utils.php b/php/utils.php index 278cf4cf7..8b8c463fc 100644 --- a/php/utils.php +++ b/php/utils.php @@ -407,3 +407,10 @@ function mustache_render( $template_name, $data ) { return $m->render( $template, $data ); } +function make_progress_bar( $message, $count ) { + if ( \cli\Shell::isPiped() ) + return new \WP_CLI\NoOp; + + return new \cli\progress\Bar( $message, $count ); +} + From d1c0f1fe88cdf44b878652351c316d70f02473d8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 01:24:32 +0300 Subject: [PATCH 2009/5359] suppress curl download meter if not running interactively --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 42419f649..1efda9f08 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -38,7 +38,8 @@ public function download( $args, $assoc_args ) { WP_CLI::log( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - $silent = WP_CLI::get_config('quiet') ? '--silent ' : ''; + $silent = WP_CLI::get_config('quiet') || \cli\Shell::isPiped() ? + '--silent ' : ''; $cmd = "curl -f $silent %s | tar xz --strip-components=1 --directory=%s"; WP_CLI::launch( Utils\esc_cmd( $cmd, $download_url, ABSPATH ) ); From 9e45d824866a547d7d629cb9af6c57cf2b207b05 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 03:50:59 +0300 Subject: [PATCH 2010/5359] behat: hide export warnings --- features/export.feature | 8 ++++++-- features/import.feature | 7 ++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/features/export.feature b/features/export.feature index 1194696f9..31ea12403 100644 --- a/features/export.feature +++ b/features/export.feature @@ -3,5 +3,9 @@ Feature: Export content. Scenario: Basic export Given a WP install - When I run `wp export` - Then STDOUT should not be empty + When I try `wp export` + Then the return code should be 0 + And STDOUT should contain: + """ + All done with export + """ diff --git a/features/import.feature b/features/import.feature index e90d4c57b..5a4c940ca 100644 --- a/features/import.feature +++ b/features/import.feature @@ -10,11 +10,8 @@ Feature: Import content. 7 """ - When I run `wp export` - Then STDOUT should contain: - """ - All done with export - """ + When I try `wp export` + Then the return code should be 0 And save STDOUT 'Writing to file %s' as {EXPORT_FILE} When I run `wp site empty --yes` From 864da43168f9834bc2f2ba8ad09e7e40303a66e3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 12 Jul 2013 18:42:21 +0300 Subject: [PATCH 2011/5359] behat: check STDERR when running `wp export` --- features/export.feature | 5 ++--- features/import.feature | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/features/export.feature b/features/export.feature index 31ea12403..f0bcfa85c 100644 --- a/features/export.feature +++ b/features/export.feature @@ -3,9 +3,8 @@ Feature: Export content. Scenario: Basic export Given a WP install - When I try `wp export` - Then the return code should be 0 - And STDOUT should contain: + When I run `wp export` + Then STDOUT should contain: """ All done with export """ diff --git a/features/import.feature b/features/import.feature index 5a4c940ca..b9faed264 100644 --- a/features/import.feature +++ b/features/import.feature @@ -10,8 +10,7 @@ Feature: Import content. 7 """ - When I try `wp export` - Then the return code should be 0 + When I run `wp export` And save STDOUT 'Writing to file %s' as {EXPORT_FILE} When I run `wp site empty --yes` From 4aa1b85cf80c6a3e443fc0aca013129dcb94920c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 13 Jul 2013 18:54:56 +0300 Subject: [PATCH 2012/5359] add missing docs for `user add-role`; improve docs for `user set-role` --- man-src/user-add-role.txt | 14 ++++++++++++++ man-src/user-set-role.txt | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 man-src/user-add-role.txt diff --git a/man-src/user-add-role.txt b/man-src/user-add-role.txt new file mode 100644 index 000000000..b6e5ab482 --- /dev/null +++ b/man-src/user-add-role.txt @@ -0,0 +1,14 @@ +## OPTIONS + +* `<user>`: + + User ID or user login. + +* `<role>`: + + Add the specified role to the user. + +## EXAMPLES + + wp user set-role bob author + wp user set-role 12 author diff --git a/man-src/user-set-role.txt b/man-src/user-set-role.txt index 84190293b..4817f740d 100644 --- a/man-src/user-set-role.txt +++ b/man-src/user-set-role.txt @@ -6,7 +6,8 @@ * `[<role>]`: - Add the user with the specified role. Defaults to blog default. + Make the user have the specified role. If not passed, the default role is +used. ## EXAMPLES From de5814f005f5e69c41a8fac09cb02c1a7a94ca7e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 13 Jul 2013 19:12:00 -0700 Subject: [PATCH 2013/5359] Update to accommodate scenario when multiple users are passed See https://github.com/wp-cli/wp-cli/pull/555#discussion_r5179695 --- php/commands/user.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index d4b23b3f9..102e17999 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -66,7 +66,9 @@ public function delete( $args, $assoc_args ) { 'reassign' => null ) ); - $args[0] = self::get_user_from_first_arg( $args[0] )->ID; + foreach( $args as $key => $arg ) { + $args[$key] = self::get_user_from_first_arg( $arg )->ID; + } parent::delete( $args, $assoc_args ); } @@ -150,7 +152,9 @@ protected function _create( $params ) { */ public function update( $args, $assoc_args ) { - $args[0] = self::get_user_from_first_arg( $args[0] )->ID; + foreach( $args as $key => $arg ) { + $args[$key] = self::get_user_from_first_arg( $arg )->ID; + } parent::update( $args, $assoc_args, 'user' ); } From 8d9c95f6662a22abe13bb95f550b21f389745d83 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 13 Jul 2013 19:15:37 -0700 Subject: [PATCH 2014/5359] Update "Generating Users" scenario to accommodate deleting multiple users in one go. --- features/user.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index 137ee8936..c2d4a51d2 100644 --- a/features/user.feature +++ b/features/user.feature @@ -19,7 +19,7 @@ Feature: Manage WordPress users When I run `wp user delete {USER_ID}` Then STDOUT should not be empty - Scenario: Generating users + Scenario: Generating and deleting users Given a WP install # Delete all users @@ -36,6 +36,10 @@ Feature: Manage WordPress users 10 """ + When I run `wp user delete $(wp user list --format=ids)` + And I run `wp user list --format=ids` + Then STDOUT should be empty + Scenario: Importing users from a CSV file Given a WP install And a users.csv file: From ed03bb4c5c100bd2a015782136b214fb82db7c33 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 13:50:33 +0300 Subject: [PATCH 2015/5359] rename get_user_from_first_arg() to get_user() --- php/commands/user.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 102e17999..880565a44 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -67,7 +67,7 @@ public function delete( $args, $assoc_args ) { ) ); foreach( $args as $key => $arg ) { - $args[$key] = self::get_user_from_first_arg( $arg )->ID; + $args[$key] = self::get_user( $arg )->ID; } parent::delete( $args, $assoc_args ); } @@ -153,7 +153,7 @@ protected function _create( $params ) { public function update( $args, $assoc_args ) { foreach( $args as $key => $arg ) { - $args[$key] = self::get_user_from_first_arg( $arg )->ID; + $args[$key] = self::get_user( $arg )->ID; } parent::update( $args, $assoc_args, 'user' ); } @@ -222,7 +222,7 @@ public function generate( $args, $assoc_args ) { * @synopsis <user> [<role>] */ public function set_role( $args, $assoc_args ) { - $user = self::get_user_from_first_arg( $args[0] ); + $user = self::get_user( $args[0] ); $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); @@ -242,7 +242,7 @@ public function set_role( $args, $assoc_args ) { * @synopsis <user> <role> */ public function add_role( $args, $assoc_args ) { - $user = self::get_user_from_first_arg( $args[0] ); + $user = self::get_user( $args[0] ); $role = $args[1]; @@ -258,7 +258,7 @@ public function add_role( $args, $assoc_args ) { * @synopsis <user> [<role>] */ public function remove_role( $args, $assoc_args ) { - $user = self::get_user_from_first_arg( $args[0] ); + $user = self::get_user( $args[0] ); if ( isset( $args[1] ) ) { $role = $args[1]; @@ -277,7 +277,7 @@ public function remove_role( $args, $assoc_args ) { } } - private static function get_user_from_first_arg( $id_or_login ) { + private static function get_user( $id_or_login ) { if ( is_numeric( $id_or_login ) ) $user = get_user_by( 'id', $id_or_login ); else From 3d23368e101b936f9a2ec9cf308ddb4c7024633e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 14:00:15 +0300 Subject: [PATCH 2016/5359] don't abort if a user isn't found --- features/user.feature | 9 ++++++--- php/commands/user.php | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/features/user.feature b/features/user.feature index c2d4a51d2..437c548cb 100644 --- a/features/user.feature +++ b/features/user.feature @@ -36,9 +36,12 @@ Feature: Manage WordPress users 10 """ - When I run `wp user delete $(wp user list --format=ids)` - And I run `wp user list --format=ids` - Then STDOUT should be empty + When I try `wp user delete invalid-user $(wp user list --format=ids)` + And I run `wp user list --format=count` + Then STDOUT should be: + """ + 0 + """ Scenario: Importing users from a CSV file Given a WP install diff --git a/php/commands/user.php b/php/commands/user.php index 880565a44..6998a1851 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -283,8 +283,9 @@ private static function get_user( $id_or_login ) { else $user = get_user_by( 'login', $id_or_login ); - if ( ! $user ) - WP_CLI::error( "Invalid user ID or login: $id_or_login" ); + if ( ! $user ) { + WP_CLI::warning( "Invalid user ID or login: $id_or_login" ); + } return $user; } From 85deb2d241d6cb1a5c86c623fbdbc5fa23e96911 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 14:51:54 +0300 Subject: [PATCH 2017/5359] simplify user test --- features/user.feature | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/features/user.feature b/features/user.feature index a5c847704..f61d3a1c2 100644 --- a/features/user.feature +++ b/features/user.feature @@ -22,12 +22,7 @@ Feature: Manage WordPress users Scenario: Generating and deleting users Given a WP install - # Delete all users - When I run `wp user delete $(wp user list --format=ids)` - And I run `wp user list --format=ids` - Then STDOUT should be empty - - When I run `wp user generate --count=10` + When I run `wp user generate --count=9` And I run `wp user list --format=count` Then STDOUT should be: """ From 7973a4ae5fa6e2b629110d529e233aec706b0e13 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 15:56:46 +0300 Subject: [PATCH 2018/5359] extract assoc_array_to_table() utility. Also: - unset the 'format_content' field; it can be just as long as 'post_content'. - unset the 'filter' field; it's a runtime value, not persistent data --- php/WP_CLI/CommandWithDBObject.php | 18 ++++++++++++++++++ php/commands/post.php | 19 +++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index fa735be9e..083b06875 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -68,6 +68,23 @@ protected function success_or_failure( $r ) { return $status; } + protected function assoc_array_to_table( $fields ) { + $rows = array(); + + foreach ( $fields as $field => $value ) { + if ( !is_string($value) ) { + $value = json_encode( $value ); + } + + $rows[] = (object) array( + 'Field' => $field, + 'Value' => $value + ); + } + + \WP_CLI\Utils\format_items( 'table', $rows, array( 'Field', 'Value' ) ); + } + public function delete( $args, $assoc_args ) { $status = 0; @@ -78,5 +95,6 @@ public function delete( $args, $assoc_args ) { exit( $status ); } + } diff --git a/php/commands/post.php b/php/commands/post.php index d37836603..8ef3c727e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -110,22 +110,9 @@ public function get( $args, $assoc_args ) { break; case 'table': - $items = array(); - foreach ( get_object_vars( $post ) as $field => $value ) { - if ( 'post_content' === $field ) - continue; - - if ( !is_string($value) ) { - $value = json_encode($value); - } - - $item = new \stdClass; - $item->Field = $field; - $item->Value = $value; - $items[] = $item; - } - - \WP_CLI\Utils\format_items( $format, $items, array( 'Field', 'Value' ) ); + $fields = get_object_vars( $post ); + unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); + $this->assoc_array_to_table( $fields ); break; case 'json': From 8514eee1105fe573b135ec66c79a8ace7b914bc9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 16:12:37 +0300 Subject: [PATCH 2019/5359] implement `wp user get` --- features/user.feature | 13 +++++++------ man-src/user-get.txt | 19 +++++++++++++++++++ php/commands/user.php | 29 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 man-src/user-get.txt diff --git a/features/user.feature b/features/user.feature index f61d3a1c2..ee18ec43c 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,6 +1,6 @@ Feature: Manage WordPress users - Scenario: Creating/updating/deleting users + Scenario: User CRUD operations Given a WP install When I run `wp user create testuser testuser@example.com --porcelain` @@ -10,11 +10,12 @@ Feature: Manage WordPress users When I try the previous command again Then the return code should be 1 - When I run `wp user update {USER_ID} --displayname=Foo` - Then STDOUT should be: - """ - Success: Updated user {USER_ID}. - """ + When I run `wp user update {USER_ID} --display_name=Foo` + And I run `wp user get {USER_ID}` + Then STDOUT should be a table containing rows: + | Field | Value | + | ID | {USER_ID} | + | display_name | Foo | When I run `wp user delete {USER_ID}` Then STDOUT should not be empty diff --git a/man-src/user-get.txt b/man-src/user-get.txt new file mode 100644 index 000000000..9493599ef --- /dev/null +++ b/man-src/user-get.txt @@ -0,0 +1,19 @@ +## OPTIONS + +* `[--format=<format>]`: + + The format to use when printing the user; acceptable values: + + **table**: Outputs all fields of the user as a table. + + **json**: Outputs all fields in JSON format. + +* `<user>`: + + User ID or user login. + +## EXAMPLES + + wp user get 12 + + wp user get bob --format=json > bob.json diff --git a/php/commands/user.php b/php/commands/user.php index eb03e03ef..b7cbc815f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -56,6 +56,35 @@ public function _list( $args, $assoc_args ) { WP_CLI\Utils\format_items( $params['format'], $users, $fields ); } + /** + * Get a single user. + * + * @synopsis [--format=<format>] <user> + */ + public function get( $args, $assoc_args ) { + $assoc_args = wp_parse_args( $assoc_args, array( + 'format' => 'table' + ) ); + + $user = self::get_user( $args[0] )->to_array(); + + switch ( $assoc_args['format'] ) { + + case 'table': + $this->assoc_array_to_table( $user ); + break; + + case 'json': + WP_CLI::print_value( $user, $assoc_args ); + break; + + default: + \WP_CLI::error( "Invalid value for format: " . $format ); + break; + + } + } + /** * Delete one or more users. * From 34fffe816ae704a1a38ff8bae3afc07c3def6699 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 16:22:53 +0300 Subject: [PATCH 2020/5359] behat: align table bars --- features/user.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index ee18ec43c..cb70e36fb 100644 --- a/features/user.feature +++ b/features/user.feature @@ -13,9 +13,9 @@ Feature: Manage WordPress users When I run `wp user update {USER_ID} --display_name=Foo` And I run `wp user get {USER_ID}` Then STDOUT should be a table containing rows: - | Field | Value | + | Field | Value | | ID | {USER_ID} | - | display_name | Foo | + | display_name | Foo | When I run `wp user delete {USER_ID}` Then STDOUT should not be empty From ed808c47e215a458eaa53632744624615682290b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 14 Jul 2013 16:38:17 +0300 Subject: [PATCH 2021/5359] WP_User->to_array() doesn't exist in WP 3.4 --- php/commands/user.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index b7cbc815f..d53cdd87d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -66,16 +66,23 @@ public function get( $args, $assoc_args ) { 'format' => 'table' ) ); - $user = self::get_user( $args[0] )->to_array(); + $user = self::get_user( $args[0] ); + + if ( method_exists( $user, 'to_array' ) ) { + $user_data = $user->to_array(); + } else { + // WP 3.4 compat + $user_data = $user->data; + } switch ( $assoc_args['format'] ) { case 'table': - $this->assoc_array_to_table( $user ); + $this->assoc_array_to_table( $user_data ); break; case 'json': - WP_CLI::print_value( $user, $assoc_args ); + WP_CLI::print_value( $user_data, $assoc_args ); break; default: From 7397a2507b23f7bfed26e90b505a5882f3792993 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 15 Jul 2013 16:25:28 +0300 Subject: [PATCH 2022/5359] bump version to 0.11.0-alpha2 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 1064b77e6..f721cde07 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.0-alpha' ); +define( 'WP_CLI_VERSION', '0.11.0-alpha2' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 1f981c86a1dd43f220c69384b1287e8eceb467c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 16 Jul 2013 23:20:28 +0300 Subject: [PATCH 2023/5359] introduce `wp core multisite-install` (doesn't work yet) --- features/core.feature | 13 ++++++++++ php/WP_CLI/Runner.php | 4 ++- php/commands/core.php | 58 +++++++++++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/features/core.feature b/features/core.feature index eda3c15b8..cc48e7ef9 100644 --- a/features/core.feature +++ b/features/core.feature @@ -125,6 +125,19 @@ Feature: Manage WordPress installation When I try `wp core install-network --title='test network'` Then the return code should be 1 + Scenario: Install multisite from scrath + Given a WP multisite install + And I run `wp db reset --yes` + + When I run `wp core multisite-install --title=Test --admin_email=admin@example.com --admin_password=1` + Then STDOUT should not be empty + + When I run `wp eval 'var_export( is_multisite() );'` + Then STDOUT should be: + """ + true + """ + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index abce20467..85a0563d6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -360,7 +360,9 @@ public function before_wp_load() { } if ( - $this->cmd_starts_with( array( 'core', 'install' ) ) + count( $this->arguments ) >= 2 && + $this->arguments[0] == 'core' && + in_array( $this->arguments[1], array( 'install', 'multisite-install' ) ) ) { define( 'WP_INSTALLING', true ); diff --git a/php/commands/core.php b/php/commands/core.php index 1efda9f08..0f9f2d578 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -131,6 +131,37 @@ public function is_installed() { * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { + $this->_install( $assoc_args ); + WP_CLI::success( 'WordPress installed successfully.' ); + } + + /** + * Transform a single-site install into a multi-site install. + * + * @subcommand multisite-convert + * @alias install-network + * @synopsis --title=<network-title> [--base=<url-path>] + */ + public function multisite_convert( $args, $assoc_args ) { + if ( is_multisite() ) + WP_CLI::error( 'This already is a multisite install.' ); + + $this->_multisite_convert( $assoc_args ); + } + + /** + * Install multisite from scratch. + * + * @subcommand multisite-install + * @synopsis --url=<url> [--base=<url-path>] --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> + */ + public function multisite_install( $args, $assoc_args ) { + $this->_install( $assoc_args ); + WP_CLI::log( 'Created single site database tables.' ); + $this->_multisite_convert( $assoc_args ); + } + + private function _install( $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); if ( is_blog_installed() ) { @@ -150,21 +181,10 @@ public function install( $args, $assoc_args ) { if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); - } else { - WP_CLI::success( 'WordPress installed successfully.' ); } } - /** - * Transform a single-site install into a multi-site install. - * - * @subcommand install-network - * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains] - */ - public function install_network( $args, $assoc_args ) { - if ( is_multisite() ) - WP_CLI::error( 'This already is a multisite install.' ); - + private function _multisite_convert( $assoc_args ) { global $wpdb; require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); @@ -181,17 +201,21 @@ public function install_network( $args, $assoc_args ) { $subdomain_install = isset( $assoc_args['subdomains'] ); install_network(); + WP_CLI::log( 'Created multisite database tables.' ); $result = populate_network( 1, $hostname, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); - if ( is_wp_error( $result ) ) { + if ( true === $result ) { + WP_CLI::log( 'Populated multisite options.' ); + } else if ( is_wp_error( $result ) ) { if ( $result->get_error_codes() === array( 'no_wildcard_dns' ) ) WP_CLI::warning( __( 'Wildcard DNS may not be configured correctly.' ) ); else WP_CLI::error( $result ); } - ob_start(); + if ( !defined( 'MULTISITE' ) ) { + ob_start(); ?> define('MULTISITE', true); define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>); @@ -202,9 +226,11 @@ public function install_network( $args, $assoc_args ) { define('BLOG_ID_CURRENT_SITE', 1); <?php - $ms_config = ob_get_clean(); + $ms_config = ob_get_clean(); - self::modify_wp_config( $ms_config ); + self::modify_wp_config( $ms_config ); + WP_CLI::log( 'Added multisite constants to wp-config.php.' ); + } wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); From b0db8685fb52293cda1928e6e61f82c126b10c68 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 00:40:25 +0300 Subject: [PATCH 2024/5359] skip ms_site_check() when installing --- php/wp-settings-cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 34cba9323..b40e1479c 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -304,7 +304,8 @@ do_action( 'init' ); // Check site status -if ( is_multisite() ) { +# if ( is_multisite() ) { // WP-CLI +if ( is_multisite() && !defined('WP_INSTALLING') ) { if ( true !== ( $file = ms_site_check() ) ) { require( $file ); die(); From f428094cf1de9e56cd201dd87ac0732abae8faaf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 03:18:54 +0300 Subject: [PATCH 2025/5359] test both with and without multisite constants scenarios --- features/core.feature | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index cc48e7ef9..1360d6271 100644 --- a/features/core.feature +++ b/features/core.feature @@ -125,17 +125,32 @@ Feature: Manage WordPress installation When I try `wp core install-network --title='test network'` Then the return code should be 1 - Scenario: Install multisite from scrath + Scenario: Install multisite from scratch + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` + Then STDOUT should not be empty + + When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` + Then STDOUT should be: + """ + foobar.org + """ + + Scenario: Install multisite from scratch, with MULTISITE already set in wp-config.php Given a WP multisite install And I run `wp db reset --yes` - When I run `wp core multisite-install --title=Test --admin_email=admin@example.com --admin_password=1` + When I run `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty - When I run `wp eval 'var_export( is_multisite() );'` + When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` Then STDOUT should be: """ - true + foobar.org """ Scenario: Custom wp-content directory From 02ce185f7d3e92b30e60adbcdc68e9649d72db54 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 02:34:18 +0300 Subject: [PATCH 2026/5359] copy the missing steps from populate_network() --- php/commands/core.php | 63 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 0f9f2d578..293fdf47b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -147,6 +147,7 @@ public function multisite_convert( $args, $assoc_args ) { WP_CLI::error( 'This already is a multisite install.' ); $this->_multisite_convert( $assoc_args ); + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); } /** @@ -158,7 +159,20 @@ public function multisite_convert( $args, $assoc_args ) { public function multisite_install( $args, $assoc_args ) { $this->_install( $assoc_args ); WP_CLI::log( 'Created single site database tables.' ); + $this->_multisite_convert( $assoc_args ); + + // do the steps that were skipped by populate_network(), which checks is_multisite() + if ( defined( 'MULTISITE' ) ) { + $site_user = get_user_by( 'email', $assoc_args['admin_email'] ); + self::add_site_admins( $site_user ); + $domain = self::get_clean_basedomain(); + $path = isset( $assoc_args['base'] ) ? $assoc_args['base'] : '/'; + $subdomain_install = isset( $assoc_args['subdomains'] ); + self::create_initial_blog( 1, 1, $domain, $path, $subdomain_install, $site_user ); + } + + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); } private function _install( $assoc_args ) { @@ -197,13 +211,13 @@ private function _multisite_convert( $assoc_args ) { 'base' => '/', ) ) ); - $hostname = self::get_clean_basedomain(); $subdomain_install = isset( $assoc_args['subdomains'] ); install_network(); WP_CLI::log( 'Created multisite database tables.' ); - $result = populate_network( 1, $hostname, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); + $domain = self::get_clean_basedomain(); + $result = populate_network( 1, $domain, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); if ( true === $result ) { WP_CLI::log( 'Populated multisite options.' ); @@ -214,13 +228,13 @@ private function _multisite_convert( $assoc_args ) { WP_CLI::error( $result ); } - if ( !defined( 'MULTISITE' ) ) { + if ( !is_multisite() ) { ob_start(); ?> define('MULTISITE', true); define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>); $base = '<?php echo $base; ?>'; -define('DOMAIN_CURRENT_SITE', '<?php echo $hostname; ?>'); +define('DOMAIN_CURRENT_SITE', '<?php echo $domain; ?>'); define('PATH_CURRENT_SITE', '<?php echo $base; ?>'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); @@ -233,8 +247,47 @@ private function _multisite_convert( $assoc_args ) { } wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); + } - WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + // copied from populate_network() + private static function create_initial_blog( $network_id, $blog_id, $domain, $path, + $subdomain_install, $site_user ) { + global $wpdb, $current_site, $wp_rewrite; + + $current_site = new stdClass; + $current_site->domain = $domain; + $current_site->path = $path; + $current_site->site_name = ucfirst( $domain ); + $wpdb->insert( $wpdb->blogs, array( + 'site_id' => $network_id, + 'domain' => $domain, + 'path' => $path, + 'registered' => current_time( 'mysql' ) + ) ); + $current_site->blog_id = $blog_id = $wpdb->insert_id; + update_user_meta( $site_user->ID, 'source_domain', $domain ); + update_user_meta( $site_user->ID, 'primary_blog', $blog_id ); + + if ( $subdomain_install ) + $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); + else + $wp_rewrite->set_permalink_structure( '/blog/%year%/%monthnum%/%day%/%postname%/' ); + + flush_rewrite_rules(); + } + + // copied from populate_network() + private static function add_site_admins( $site_user ) { + $site_admins = array( $site_user->user_login ); + $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) ); + if ( $users ) { + foreach ( $users as $user ) { + if ( is_super_admin( $user->ID ) && !in_array( $user->user_login, $site_admins ) ) + $site_admins[] = $user->user_login; + } + } + + update_site_option( 'site_admins', $site_admins ); } private static function modify_wp_config( $content ) { From d3e49e0465f37e6fb45adf5563ce705ef4374d55 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 03:19:22 +0300 Subject: [PATCH 2027/5359] fake $current_site and $current_blog globals --- php/WP_CLI/Runner.php | 60 ++++++++++++++++++++++++++++++++++++++++--- php/utils.php | 12 +++------ 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 85a0563d6..917f8431f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -97,7 +97,7 @@ private static function set_user( $assoc_args ) { } } - private static function set_url( $assoc_args ) { + private static function guess_url( $assoc_args ) { if ( isset( $assoc_args['blog'] ) ) { $assoc_args['url'] = $assoc_args['blog']; unset( $assoc_args['blog'] ); @@ -136,8 +136,10 @@ private static function set_url( $assoc_args ) { } if ( isset( $url ) ) { - Utils\set_url_params( $url ); + return $url; } + + return false; } private function cmd_starts_with( $prefix ) { @@ -336,7 +338,11 @@ public function before_wp_load() { self::set_wp_root( $this->config ); // Handle --url and --blog parameters - self::set_url( $this->config ); + $url = self::guess_url( $this->config ); + if ( $url ) { + $url_parts = self::parse_url( $url ); + Utils\set_url_params( $url_parts ); + } $this->do_early_invoke( 'before_wp_load' ); @@ -366,8 +372,15 @@ public function before_wp_load() { ) { define( 'WP_INSTALLING', true ); + // We really need a URL here if ( !isset( $_SERVER['HTTP_HOST'] ) ) { - Utils\set_url_params( 'http://example.com' ); + $url_parts = self::parse_url( 'http://example.com' ); + Utils\set_url_params( $url_parts ); + } + + if ( 'multisite-install' == $this->arguments[1] ) { + // need to fake some globals to skip the checks in wp-inclues/ms-settings.php + self::fake_current_site_blog( $url_parts ); } } @@ -375,7 +388,46 @@ public function before_wp_load() { define( 'WP_LOAD_IMPORTERS', true ); define( 'WP_IMPORTING', true ); } + } + + private static function parse_url( $url ) { + $url_parts = parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + return $url_parts; + } + + private static function fake_current_site_blog( $url_parts ) { + global $current_site, $current_blog; + + if ( !isset( $url_parts['path'] ) ) { + $url_parts['path'] = '/'; + } + + $current_site = (object) array( + 'id' => 1, + 'blog_id' => 1, + 'domain' => $url_parts['host'], + 'path' => $url_parts['path'], + 'cookie_domain' => $url_parts['host'], + 'site_name' => 'Fake Site', + ); + + $current_blog = (object) array( + 'blog_id' => 1, + 'site_id' => 1, + 'domain' => $url_parts['host'], + 'path' => $url_parts['path'], + 'public' => '1', + 'archived' => '0', + 'mature' => '0', + 'spam' => '0', + 'deleted' => '0', + 'lang_id' => '0', + ); } public function after_wp_load() { diff --git a/php/utils.php b/php/utils.php index 8b8c463fc..cb21c7ac7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -140,15 +140,9 @@ function esc_cmd( $cmd ) { /** * Sets the appropriate $_SERVER keys based on a given string * - * @param string $url The URL + * @param array $url_parts The URL, as represented by parse_url() */ -function set_url_params( $url ) { - $url_parts = parse_url( $url ); - - if ( !isset( $url_parts['scheme'] ) ) { - $url_parts = parse_url( 'http://' . $url ); - } - +function set_url_params( $url_parts ) { $f = function( $key ) use ( $url_parts ) { return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; }; @@ -255,7 +249,7 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ function format_items( $format, $items, $fields ) { - + if ( 'ids' == $format ) { echo implode( ' ', $items ); return; From 03db22492e065aff081129e6e4a10de6d1e26207 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 03:29:13 +0300 Subject: [PATCH 2028/5359] fix edge case in guess_url() --- php/WP_CLI/Runner.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 917f8431f..497208b4e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -129,10 +129,11 @@ private static function guess_url( $assoc_args ) { } } - if ( !empty( $hit ) && isset( $hit['domain'] ) ) + if ( !empty( $hit ) && isset( $hit['domain'] ) ) { $url = $hit['domain']; - if ( !empty( $hit ) && isset( $hit['path'] ) ) - $url .= $hit['path']; + if ( isset( $hit['path'] ) ) + $url .= $hit['path']; + } } if ( isset( $url ) ) { From e68eab4127fe98b75c1ab9e33f2df9e88208f92a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 03:36:23 +0300 Subject: [PATCH 2029/5359] move set_url_params() to WP_CLI\Runner It wasn't really meant to be a public utility. We just didn't have a runner class back then. --- php/WP_CLI/Runner.php | 26 ++++++++++++++++++++++++-- php/utils.php | 27 --------------------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 497208b4e..dc18ebf47 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -143,6 +143,28 @@ private static function guess_url( $assoc_args ) { return false; } + private static function set_url_params( $url_parts ) { + $f = function( $key ) use ( $url_parts ) { + return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; + }; + + if ( isset( $url_parts['host'] ) ) { + $_SERVER['HTTP_HOST'] = $url_parts['host']; + if ( isset( $url_parts['port'] ) ) { + $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; + } + + $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); + } + + $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); + $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; + $_SERVER['QUERY_STRING'] = $f('query'); + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; + $_SERVER['HTTP_USER_AGENT'] = ''; + $_SERVER['REQUEST_METHOD'] = 'GET'; + } + private function cmd_starts_with( $prefix ) { return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } @@ -342,7 +364,7 @@ public function before_wp_load() { $url = self::guess_url( $this->config ); if ( $url ) { $url_parts = self::parse_url( $url ); - Utils\set_url_params( $url_parts ); + self::set_url_params( $url_parts ); } $this->do_early_invoke( 'before_wp_load' ); @@ -376,7 +398,7 @@ public function before_wp_load() { // We really need a URL here if ( !isset( $_SERVER['HTTP_HOST'] ) ) { $url_parts = self::parse_url( 'http://example.com' ); - Utils\set_url_params( $url_parts ); + self::set_url_params( $url_parts ); } if ( 'multisite-install' == $this->arguments[1] ) { diff --git a/php/utils.php b/php/utils.php index cb21c7ac7..9c0396359 100644 --- a/php/utils.php +++ b/php/utils.php @@ -137,33 +137,6 @@ function esc_cmd( $cmd ) { return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); } -/** - * Sets the appropriate $_SERVER keys based on a given string - * - * @param array $url_parts The URL, as represented by parse_url() - */ -function set_url_params( $url_parts ) { - $f = function( $key ) use ( $url_parts ) { - return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; - }; - - if ( isset( $url_parts['host'] ) ) { - $_SERVER['HTTP_HOST'] = $url_parts['host']; - if ( isset( $url_parts['port'] ) ) { - $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; - } - - $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); - } - - $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); - $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; - $_SERVER['QUERY_STRING'] = $f('query'); - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; - $_SERVER['HTTP_USER_AGENT'] = ''; - $_SERVER['REQUEST_METHOD'] = 'GET'; -} - function locate_wp_config() { static $path; From c05ba4c1ba5b7f8d58b580541c89eab9f37949f0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 03:41:36 +0300 Subject: [PATCH 2030/5359] move docs for multisite-convert --- man-src/{core-install-network.txt => core-multisite-convert.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename man-src/{core-install-network.txt => core-multisite-convert.txt} (100%) diff --git a/man-src/core-install-network.txt b/man-src/core-multisite-convert.txt similarity index 100% rename from man-src/core-install-network.txt rename to man-src/core-multisite-convert.txt From 18b1b224e83a0f92cab5139b0a65dabbbeb8a4e6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 04:02:37 +0300 Subject: [PATCH 2031/5359] get rid of some DB warnings --- php/wp-settings-cli.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index b40e1479c..50687b3de 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -59,6 +59,22 @@ // WP_CLI: Early hooks Utils\replace_wp_die_handler(); add_filter( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); +if ( defined( 'WP_INSTALLING' ) && is_multisite() ) { + $values = array( + 'ms_files_rewriting' => null, + 'active_sitewide_plugins' => array(), + '_site_transient_update_core' => null, + '_site_transient_update_themes' => null, + '_site_transient_update_plugins' => null, + 'WPLANG' => '', + ); + foreach ( $values as $key => $value ) { + add_filter( "pre_site_option_$key", function () use ( $values, $key ) { + return $values[ $key ]; + } ); + } + unset( $values, $key, $value ); +} // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From e986f4ee626e8d315fef8ad210e837152b700c12 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 04:08:06 +0300 Subject: [PATCH 2032/5359] define COOKIEHASH to get rid of DB warning That's because wp_cookie_constants() goes looking for siteurl in the not-yet-existing wp_sitemeta table. --- php/WP_CLI/Runner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index dc18ebf47..47832b519 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -404,6 +404,10 @@ public function before_wp_load() { if ( 'multisite-install' == $this->arguments[1] ) { // need to fake some globals to skip the checks in wp-inclues/ms-settings.php self::fake_current_site_blog( $url_parts ); + + if ( !defined( 'COOKIEHASH' ) ) { + define( 'COOKIEHASH', md5( $url_parts['host'] ) ); + } } } From 34ed6ce4a8d98a28bcb56a647001798f5f0ff3eb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 04:29:27 +0300 Subject: [PATCH 2033/5359] behat: remove mismatched URL --- features/core.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index 1360d6271..5da719ccc 100644 --- a/features/core.feature +++ b/features/core.feature @@ -144,14 +144,14 @@ Feature: Manage WordPress installation Given a WP multisite install And I run `wp db reset --yes` - When I run `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` + When I run `wp core multisite-install --title=Test --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` Then STDOUT should be: """ - foobar.org - """ + example.com + """ Scenario: Custom wp-content directory Given a WP install From 874a0442ae9771324b8c572b0d61b6d0a0d086bd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 17 Jul 2013 22:12:51 +0300 Subject: [PATCH 2034/5359] account for already defined multisite constants --- php/commands/core.php | 70 ++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 293fdf47b..fff84d707 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -140,12 +140,14 @@ public function install( $args, $assoc_args ) { * * @subcommand multisite-convert * @alias install-network - * @synopsis --title=<network-title> [--base=<url-path>] + * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains] */ public function multisite_convert( $args, $assoc_args ) { if ( is_multisite() ) WP_CLI::error( 'This already is a multisite install.' ); + $assoc_args = self::_set_multisite_defaults( $assoc_args ); + $this->_multisite_convert( $assoc_args ); WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); } @@ -154,27 +156,60 @@ public function multisite_convert( $args, $assoc_args ) { * Install multisite from scratch. * * @subcommand multisite-install - * @synopsis --url=<url> [--base=<url-path>] --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> + * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function multisite_install( $args, $assoc_args ) { $this->_install( $assoc_args ); WP_CLI::log( 'Created single site database tables.' ); + $assoc_args = self::_set_multisite_defaults( $assoc_args ); + + // Overwrite runtime args, to avoid mismatches. + $consts_to_args = array( + 'SUBDOMAIN_INSTALL' => 'subdomains', + 'PATH_CURRENT_SITE' => 'base', + 'SITE_ID_CURRENT_SITE' => 'site_id', + 'BLOG_ID_CURRENT_SITE' => 'blog_id', + ); + + foreach ( $consts_to_args as $const => $arg ) { + if ( defined( $const ) ) { + $assoc_args[ $arg ] = constant( $const ); + } + } + $this->_multisite_convert( $assoc_args ); - // do the steps that were skipped by populate_network(), which checks is_multisite() - if ( defined( 'MULTISITE' ) ) { + // Do the steps that were skipped by populate_network(), + // which checks is_multisite(). + if ( is_multisite() ) { $site_user = get_user_by( 'email', $assoc_args['admin_email'] ); self::add_site_admins( $site_user ); $domain = self::get_clean_basedomain(); - $path = isset( $assoc_args['base'] ) ? $assoc_args['base'] : '/'; - $subdomain_install = isset( $assoc_args['subdomains'] ); - self::create_initial_blog( 1, 1, $domain, $path, $subdomain_install, $site_user ); + self::create_initial_blog( + $assoc_args['site_id'], + $assoc_args['blog_id'], + $domain, + $assoc_args['base'], + $assoc_args['subdomains'], + $site_user + ); } WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); } + private static function _set_multisite_defaults( $assoc_args ) { + $defaults = array( + 'subdomains' => false, + 'base' => '/', + 'site_id' => 1, + 'blog_id' => 1, + ); + + return array_merge( $defaults, $assoc_args ); + } + private function _install( $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); @@ -207,17 +242,18 @@ private function _multisite_convert( $assoc_args ) { foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) $wpdb->$table = $prefixed_table; - extract( wp_parse_args( $assoc_args, array( - 'base' => '/', - ) ) ); - - $subdomain_install = isset( $assoc_args['subdomains'] ); - install_network(); WP_CLI::log( 'Created multisite database tables.' ); $domain = self::get_clean_basedomain(); - $result = populate_network( 1, $domain, get_option( 'admin_email' ), $assoc_args['title'], $base, $subdomain_install ); + $result = populate_network( + $assoc_args['site_id'], + $domain, + get_option( 'admin_email' ), + $assoc_args['title'], + $assoc_args['base'], + $assoc_args['subdomains'] + ); if ( true === $result ) { WP_CLI::log( 'Populated multisite options.' ); @@ -232,10 +268,10 @@ private function _multisite_convert( $assoc_args ) { ob_start(); ?> define('MULTISITE', true); -define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>); -$base = '<?php echo $base; ?>'; +define('SUBDOMAIN_INSTALL', <?php var_export( $assoc_args['subdomains'] ); ?>); +$base = '<?php echo $assoc_args['base']; ?>'; define('DOMAIN_CURRENT_SITE', '<?php echo $domain; ?>'); -define('PATH_CURRENT_SITE', '<?php echo $base; ?>'); +define('PATH_CURRENT_SITE', '<?php echo $assoc_args['base']; ?>'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); From 1b7cb612e91c85aed99e778aaafbf6becd720790 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 18 Jul 2013 23:53:30 +0300 Subject: [PATCH 2035/5359] add docs for 'core multisite-install' --- man-src/core-multisite-install.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 man-src/core-multisite-install.txt diff --git a/man-src/core-multisite-install.txt b/man-src/core-multisite-install.txt new file mode 100644 index 000000000..eb9d7bd4d --- /dev/null +++ b/man-src/core-multisite-install.txt @@ -0,0 +1,30 @@ +## OPTIONS + +* `--url`=<url>: + + The address of the new site. + +* `--base`=<url-path>: + + Base path after the domain name that each site url in the network will start with. +Default: '/' + +* `--subdomains`: + + If passed, the network will use subdomains, instead of subdirectories. + +* `--title`=<site-title>: + + The title of the new site. + +* `--admin_name`=<username>: + + The name of the admin user. Default: 'admin' + +* `--admin_password`=<password>: + + The password for the admin user. + +* `--admin_email`=<email>: + + The email address for the admin user. From b57a0539ff32ea09817a64ba2aa1c155a9280b79 Mon Sep 17 00:00:00 2001 From: Veered <lucashansne@gmail.com> Date: Thu, 18 Jul 2013 15:36:46 -0700 Subject: [PATCH 2036/5359] Allow paths with spaces. --- bin/wp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wp b/bin/wp index f53faf413..706f6c9fd 100755 --- a/bin/wp +++ b/bin/wp @@ -63,4 +63,4 @@ export WP_CLI_PHP_USED=$php # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands -exec $php "$SCRIPT_PATH" "$@" +exec "$php" "$SCRIPT_PATH" "$@" From ffc80dcba0018504e545a8a50a53d8055ca88a93 Mon Sep 17 00:00:00 2001 From: Veered <lucashansne@gmail.com> Date: Thu, 18 Jul 2013 16:42:38 -0700 Subject: [PATCH 2037/5359] The Windows version of tar doesn't play nicely with pipes. This way is more cross-platform. --- php/commands/core.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1efda9f08..fa3142291 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -40,8 +40,9 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') || \cli\Shell::isPiped() ? '--silent ' : ''; - - $cmd = "curl -f $silent %s | tar xz --strip-components=1 --directory=%s"; + + $temp = tempnam(sys_get_temp_dir(), "wp_"); + $cmd = "curl -f $silent %s > $temp && tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; WP_CLI::launch( Utils\esc_cmd( $cmd, $download_url, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); From 67c074c5e4765a9756706fd723139194bdf2d214 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 19 Jul 2013 03:19:22 +0300 Subject: [PATCH 2038/5359] add comment about cURL + tar. see #604 --- php/commands/core.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index fa3142291..1458a8886 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -40,8 +40,10 @@ public function download( $args, $assoc_args ) { $silent = WP_CLI::get_config('quiet') || \cli\Shell::isPiped() ? '--silent ' : ''; - - $temp = tempnam(sys_get_temp_dir(), "wp_"); + + // We need to use a temporary file because piping from cURL to tar is flaky + // on MinGW (and probably in other environments too). + $temp = tempnam( sys_get_temp_dir(), "wp_" ); $cmd = "curl -f $silent %s > $temp && tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; WP_CLI::launch( Utils\esc_cmd( $cmd, $download_url, ABSPATH ) ); From 819b2b742ffe97b8779b97722b606220a4520728 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 20 Jul 2013 00:35:09 +0300 Subject: [PATCH 2039/5359] make --title optional for multisite-convert use the same logic from /wp-admin/network.php --- php/commands/core.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index fff84d707..0867d8750 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -140,13 +140,16 @@ public function install( $args, $assoc_args ) { * * @subcommand multisite-convert * @alias install-network - * @synopsis --title=<network-title> [--base=<url-path>] [--subdomains] + * @synopsis [--title=<network-title>] [--base=<url-path>] [--subdomains] */ public function multisite_convert( $args, $assoc_args ) { if ( is_multisite() ) WP_CLI::error( 'This already is a multisite install.' ); $assoc_args = self::_set_multisite_defaults( $assoc_args ); + if ( !isset( $assoc_args['title'] ) ) { + $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), get_option( 'blogname' ) ); + } $this->_multisite_convert( $assoc_args ); WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); @@ -163,6 +166,7 @@ public function multisite_install( $args, $assoc_args ) { WP_CLI::log( 'Created single site database tables.' ); $assoc_args = self::_set_multisite_defaults( $assoc_args ); + $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), $assoc_args['title'] ); // Overwrite runtime args, to avoid mismatches. $consts_to_args = array( @@ -243,7 +247,6 @@ private function _multisite_convert( $assoc_args ) { $wpdb->$table = $prefixed_table; install_network(); - WP_CLI::log( 'Created multisite database tables.' ); $domain = self::get_clean_basedomain(); $result = populate_network( @@ -256,7 +259,7 @@ private function _multisite_convert( $assoc_args ) { ); if ( true === $result ) { - WP_CLI::log( 'Populated multisite options.' ); + WP_CLI::log( 'Set up multisite database tables.' ); } else if ( is_wp_error( $result ) ) { if ( $result->get_error_codes() === array( 'no_wildcard_dns' ) ) WP_CLI::warning( __( 'Wildcard DNS may not be configured correctly.' ) ); From ec4d54403a1a1712c8e40e6b50041446573dc8e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Jul 2013 03:23:58 +0300 Subject: [PATCH 2040/5359] add --locale parameter to 'wp core config'. fixes #607 --- man-src/core-config.txt | 6 +++++- php/commands/core.php | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/man-src/core-config.txt b/man-src/core-config.txt index 2f5920998..9945a05c3 100644 --- a/man-src/core-config.txt +++ b/man-src/core-config.txt @@ -20,6 +20,10 @@ Set the database table prefix. Default: 'wp_' +* `--locale`=<locale>: + + Set the WPLANG constant. Defaults to $wp_local_package variable. + * `--extra-php`: If set, the command reads additional PHP code from STDIN. @@ -27,7 +31,7 @@ ## EXAMPLES # Standard wp-config.php file - wp core config --dbname=testing --dbuser=wp --dbpass=securepswd + wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO # Enable WP_DEBUG and WP_DEBUG_LOG wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP diff --git a/php/commands/core.php b/php/commands/core.php index 1458a8886..cc4eaf8af 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -75,7 +75,7 @@ private static function get_initial_locale() { /** * Set up a wp-config.php file. * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--extra-php] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] */ public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { From 398bc1ff7577cd492cac331a73d4bfd222228d43 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Jul 2013 18:59:08 +0300 Subject: [PATCH 2041/5359] don't fail if the site is already installed --- features/core.feature | 8 ++++++++ php/commands/core.php | 46 ++++++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/features/core.feature b/features/core.feature index 5da719ccc..27818a62a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -104,6 +104,10 @@ Feature: Manage WordPress installation true """ + # Can complain that it's already installed, but don't exit with an error code + When I try `wp core install --url='localhost:8001' --title='Test' --admin_email=admin@example.com --admin_password=1` + Then the return code should be 0 + Scenario: Convert install to multisite Given a WP install @@ -140,6 +144,10 @@ Feature: Manage WordPress installation foobar.org """ + # Can complain that it's already installed, but don't exit with an error code + When I try `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` + Then the return code should be 0 + Scenario: Install multisite from scratch, with MULTISITE already set in wp-config.php Given a WP multisite install And I run `wp db reset --yes` diff --git a/php/commands/core.php b/php/commands/core.php index 0867d8750..3781181a6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -131,8 +131,11 @@ public function is_installed() { * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { - $this->_install( $assoc_args ); - WP_CLI::success( 'WordPress installed successfully.' ); + if ( $this->_install( $assoc_args ) ) { + WP_CLI::success( 'WordPress installed successfully.' ); + } else { + WP_CLI::log( 'WordPress is already installed.' ); + } } /** @@ -151,8 +154,9 @@ public function multisite_convert( $args, $assoc_args ) { $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), get_option( 'blogname' ) ); } - $this->_multisite_convert( $assoc_args ); - WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + if ( $this->_multisite_convert( $assoc_args ) ) { + WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); + } } /** @@ -162,8 +166,11 @@ public function multisite_convert( $args, $assoc_args ) { * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function multisite_install( $args, $assoc_args ) { - $this->_install( $assoc_args ); - WP_CLI::log( 'Created single site database tables.' ); + if ( $this->_install( $assoc_args ) ) { + WP_CLI::log( 'Created single site database tables.' ); + } else { + WP_CLI::log( 'Single site database tables already present.' ); + } $assoc_args = self::_set_multisite_defaults( $assoc_args ); $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), $assoc_args['title'] ); @@ -182,7 +189,9 @@ public function multisite_install( $args, $assoc_args ) { } } - $this->_multisite_convert( $assoc_args ); + if ( !$this->_multisite_convert( $assoc_args ) ) { + return; + } // Do the steps that were skipped by populate_network(), // which checks is_multisite(). @@ -215,12 +224,12 @@ private static function _set_multisite_defaults( $assoc_args ) { } private function _install( $assoc_args ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - if ( is_blog_installed() ) { - WP_CLI::error( 'WordPress is already installed.' ); + return false; } + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + extract( wp_parse_args( $assoc_args, array( 'title' => '', 'admin_name' => 'admin', @@ -235,6 +244,8 @@ private function _install( $assoc_args ) { if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); } + + return true; } private function _multisite_convert( $assoc_args ) { @@ -261,10 +272,19 @@ private function _multisite_convert( $assoc_args ) { if ( true === $result ) { WP_CLI::log( 'Set up multisite database tables.' ); } else if ( is_wp_error( $result ) ) { - if ( $result->get_error_codes() === array( 'no_wildcard_dns' ) ) + switch ( $result->get_error_code() ) { + + case 'siteid_exists': + WP_CLI::log( $result->get_error_message() ); + return false; + + case 'no_wildcard_dns': WP_CLI::warning( __( 'Wildcard DNS may not be configured correctly.' ) ); - else + break; + + default: WP_CLI::error( $result ); + } } if ( !is_multisite() ) { @@ -286,6 +306,8 @@ private function _multisite_convert( $assoc_args ) { } wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); + + return true; } // copied from populate_network() From ef051f9dcfddf3384b98a977a6588a74e468fe9f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Jul 2013 22:03:53 +0300 Subject: [PATCH 2042/5359] clone object instead of calling constructor; fixes #592 --- php/utils.php | 8 ++------ tests/test-unserialize-replace.php | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 tests/test-unserialize-replace.php diff --git a/php/utils.php b/php/utils.php index 8b8c463fc..0bb98f1d7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -217,19 +217,15 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria } $data = $_tmp; - unset( $_tmp ); } - // Submitted by Tina Matter elseif ( is_object( $data ) ) { - $dataClass = get_class( $data ); - $_tmp = new $dataClass( ); + $_tmp = clone( $data ); foreach ( $data as $key => $value ) { $_tmp->$key = recursive_unserialize_replace( $from, $to, $value, false ); } $data = $_tmp; - unset( $_tmp ); } else { @@ -255,7 +251,7 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ function format_items( $format, $items, $fields ) { - + if ( 'ids' == $format ) { echo implode( ' ', $items ); return; diff --git a/tests/test-unserialize-replace.php b/tests/test-unserialize-replace.php new file mode 100644 index 000000000..3389336f3 --- /dev/null +++ b/tests/test-unserialize-replace.php @@ -0,0 +1,24 @@ +<?php + +class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { + + function testPrivateConstructor() { + $old_obj = ClassWithPrivateConstructor::get_instance(); + + $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_obj ); + $this->assertEquals( 'bar', $new_obj->prop ); + } +} + + +class ClassWithPrivateConstructor { + + public $prop = 'foo'; + + private function __construct() {} + + public static function get_instance() { + return new self; + } +} + From 2a21e33c38611c5b09cf7bc97e24fa153f0c07b5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Jul 2013 23:18:30 +0300 Subject: [PATCH 2043/5359] add comment above apparently unnecessary load_command() call --- php/WP_CLI/Runner.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index abce20467..9a0869401 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -319,6 +319,8 @@ public function before_wp_load() { if ( empty( $this->arguments ) ) $this->arguments[] = 'help'; + // Load bundled commands early, so that they're forced to use the same + // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); if ( isset( $this->config['require'] ) ) { From 5c1c36520b3706b40479e75dbb938c22a8741809 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 23 Jul 2013 22:57:52 +0300 Subject: [PATCH 2044/5359] move find_command_to_run() method to WP_CLI\Runner the WP_CLI class should be a simple facade, with only public methods --- php/WP_CLI/Runner.php | 41 ++++++++++++++++++++++++++++++++++++++++- php/class-wp-cli.php | 39 ++------------------------------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9a0869401..8af6b2a0c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -144,8 +144,47 @@ private function cmd_starts_with( $prefix ) { return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } + private function find_command_to_run( $args ) { + $command = \WP_CLI::get_root_command(); + + $cmd_path = array(); + + $disabled_commands = $this->config['disabled_commands']; + + while ( !empty( $args ) && $command->has_subcommands() ) { + $cmd_path[] = $args[0]; + $full_name = implode( ' ', $cmd_path ); + + $subcommand = $command->find_subcommand( $args ); + + if ( !$subcommand ) { + \WP_CLI::error( sprintf( + "'%s' is not a registered wp command. See 'wp help'.", + $full_name + ) ); + } + + if ( in_array( $full_name, $disabled_commands ) ) { + \WP_CLI::error( sprintf( + "The '%s' command has been disabled from the config file.", + $full_name + ) ); + } + + $command = $subcommand; + } + + return array( $command, $args ); + } + + public function run_command( $args, $assoc_args = array() ) { + list( $command, $final_args ) = $this->find_command_to_run( $args ); + + $command->invoke( $final_args, $assoc_args ); + } + private function _run_command() { - WP_CLI::run_command( $this->arguments, $this->assoc_args ); + $this->run_command( $this->arguments, $this->assoc_args ); } /** diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7d2c9dff4..1408f9728 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -266,49 +266,14 @@ static function get_config( $key = null ) { return self::get_runner()->config[ $key ]; } - private static function find_command_to_run( $args ) { - $command = self::get_root_command(); - - $cmd_path = array(); - - $disabled_commands = self::get_config('disabled_commands'); - - while ( !empty( $args ) && $command->has_subcommands() ) { - $cmd_path[] = $args[0]; - $full_name = implode( ' ', $cmd_path ); - - $subcommand = $command->find_subcommand( $args ); - - if ( !$subcommand ) { - self::error( sprintf( - "'%s' is not a registered wp command. See 'wp help'.", - $full_name - ) ); - } - - if ( in_array( $full_name, $disabled_commands ) ) { - self::error( sprintf( - "The '%s' command has been disabled from the config file.", - $full_name - ) ); - } - - $command = $subcommand; - } - - return array( $command, $args ); - } - /** * Run a given command. * * @param array * @param array */ - public static function run_command( $args, $assoc_args = array() ) { - list( $command, $final_args ) = self::find_command_to_run( $args ); - - $command->invoke( $final_args, $assoc_args ); + static function run_command( $args, $assoc_args = array() ) { + self::get_runner()->run_command( $args, $assoc_args ); } // back-compat From 09b5b2577a6e0af0b1c338410a20661d842e5de5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Jul 2013 00:02:35 +0300 Subject: [PATCH 2045/5359] show synopsis for incomplete commands, even without a WP install --- features/help.feature | 9 +++++++++ php/WP_CLI/Runner.php | 26 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/features/help.feature b/features/help.feature index 2f2193548..3aef3dbcb 100644 --- a/features/help.feature +++ b/features/help.feature @@ -47,3 +47,12 @@ Feature: Get help about WP-CLI commands """ wp test-help """ + + Scenario: Help for incomplete commands + Given an empty directory + + When I run `wp core` + Then STDOUT should contain: + """ + usage: wp core + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8af6b2a0c..515f75dca 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -158,17 +158,17 @@ private function find_command_to_run( $args ) { $subcommand = $command->find_subcommand( $args ); if ( !$subcommand ) { - \WP_CLI::error( sprintf( + return sprintf( "'%s' is not a registered wp command. See 'wp help'.", $full_name - ) ); + ); } if ( in_array( $full_name, $disabled_commands ) ) { - \WP_CLI::error( sprintf( + return sprintf( "The '%s' command has been disabled from the config file.", $full_name - ) ); + ); } $command = $subcommand; @@ -178,7 +178,12 @@ private function find_command_to_run( $args ) { } public function run_command( $args, $assoc_args = array() ) { - list( $command, $final_args ) = $this->find_command_to_run( $args ); + $r = $this->find_command_to_run( $args ); + if ( is_string( $r ) ) { + WP_CLI::error( $r ); + } + + list( $command, $final_args ) = $r; $command->invoke( $final_args, $assoc_args ); } @@ -368,6 +373,17 @@ public function before_wp_load() { } } + // Show synopsis if it's a composite command. + $r = $this->find_command_to_run( $args ); + if ( is_array( $r ) ) { + list( $command ) = $r; + + if ( $command->has_subcommands() ) { + $command->show_usage(); + exit; + } + } + // First try at showing man page if ( $this->cmd_starts_with( array( 'help' ) ) ) { $this->_run_command(); From 230c741467e8baf92506e67ee0c0f7bfad26bcc3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Jul 2013 00:23:45 +0300 Subject: [PATCH 2046/5359] extract init_config() helper method --- php/WP_CLI/Runner.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 515f75dca..8f5af6634 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -332,7 +332,7 @@ private function check_wp_version() { } } - public function before_wp_load() { + private function init_config() { list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -341,9 +341,7 @@ public function before_wp_load() { $this->config_path = self::get_config_path( $runtime_config ); - $local_config = \WP_CLI::get_configurator()->load_config( $this->config_path ); - - $this->config = $local_config; + $this->config = \WP_CLI::get_configurator()->load_config( $this->config_path ); foreach ( $runtime_config as $key => $value ) { if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { @@ -356,7 +354,10 @@ public function before_wp_load() { if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); } + } + public function before_wp_load() { + $this->init_config(); $this->init_colorization(); $this->init_logger(); @@ -374,7 +375,7 @@ public function before_wp_load() { } // Show synopsis if it's a composite command. - $r = $this->find_command_to_run( $args ); + $r = $this->find_command_to_run( $this->arguments ); if ( is_array( $r ) ) { list( $command ) = $r; @@ -430,7 +431,6 @@ public function before_wp_load() { define( 'WP_LOAD_IMPORTERS', true ); define( 'WP_IMPORTING', true ); } - } public function after_wp_load() { @@ -442,3 +442,4 @@ public function after_wp_load() { $this->_run_command(); } } + From 9d7940b1cb5be79a9bb1ab635f602912098f0af3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 24 Jul 2013 14:43:48 +0300 Subject: [PATCH 2047/5359] fix indentation in .travis.yml --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7ed5e423f..7a642a454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: php php: - - 5.3 - - 5.5 + - 5.3 + - 5.5 env: - - WP_VERSION=latest - - WP_VERSION=3.4.2 + - WP_VERSION=latest + - WP_VERSION=3.4.2 matrix: exclude: @@ -16,7 +16,7 @@ matrix: before_script: ./bin/ci/install_dependencies.sh script: ./bin/ci/run_build.sh - + notifications: - email: - on_success: never + email: + on_success: never From 0562f785855abc0fec13d7ac265f7478ac9d9af7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Jul 2013 19:17:14 +0300 Subject: [PATCH 2048/5359] allow WP_CLI::error() to do its thing (it prints both the error message and any additional data) --- php/commands/plugin.php | 5 +---- php/commands/theme.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 630dbee3e..e95c56845 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -156,10 +156,7 @@ protected function install_from_repo( $slug, $assoc_args ) { $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { - if ( null === maybe_unserialize( $api->get_error_data() ) ) - WP_CLI::error( "Can't find the plugin in the WordPress.org repository." ); - else - WP_CLI::error( $api ); + WP_CLI::error( $api ); } if ( isset( $assoc_args['version'] ) ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 843bf8d73..8db618bd4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -106,10 +106,7 @@ protected function install_from_repo( $slug, $assoc_args ) { $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { - if ( null === maybe_unserialize( $api->get_error_data() ) ) - WP_CLI::error( "Can't find the theme in the WordPress.org repository." ); - else - WP_CLI::error( $api ); + WP_CLI::error( $api ); } if ( isset( $assoc_args['version'] ) ) { From 7cd6d9d69894db971283e2c8ab19addb961feead Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Jul 2013 01:05:01 +0300 Subject: [PATCH 2049/5359] make `wp user get` show roles fixes #616 --- php/commands/user.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index d53cdd87d..f80b56c33 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -72,8 +72,9 @@ public function get( $args, $assoc_args ) { $user_data = $user->to_array(); } else { // WP 3.4 compat - $user_data = $user->data; + $user_data = (array) $user->data; } + $user_data['roles'] = implode( ', ', $user->roles ); switch ( $assoc_args['format'] ) { From 5de309a3057d2731affc62c1615e48757ef1e0a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 28 Jul 2013 19:42:13 +0300 Subject: [PATCH 2050/5359] add some Behat tests for `wp user *-role` see #594 --- features/user.feature | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/features/user.feature b/features/user.feature index cb70e36fb..ced0e4192 100644 --- a/features/user.feature +++ b/features/user.feature @@ -61,3 +61,34 @@ Feature: Manage WordPress users """ [{"user_login":"admin","display_name":"Existing User","user_email":"admin@domain.com","roles":"administrator"}] """ + + Scenario: Managing user roles + Given a WP install + + When I run `wp user add-role 1 editor` + Then STDOUT should not be empty + And I run `wp user get 1` + Then STDOUT should be a table containing rows: + | Field | Value | + | roles | administrator, editor | + + When I run `wp user set-role 1 author` + Then STDOUT should not be empty + And I run `wp user get 1` + Then STDOUT should be a table containing rows: + | Field | Value | + | roles | author | + + When I run `wp user remove-role 1 editor` + Then STDOUT should not be empty + And I run `wp user get 1` + Then STDOUT should be a table containing rows: + | Field | Value | + | roles | author | + + When I run `wp user remove-role 1` + Then STDOUT should not be empty + And I run `wp user get 1` + Then STDOUT should be a table containing rows: + | Field | Value | + | roles | | From 73ae6b0a1f00303a46f8f692ecd7c21dd6035704 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 29 Jul 2013 18:16:00 +0000 Subject: [PATCH 2051/5359] Per Codex instructions, use gettext context for `singlular_name` --- templates/taxonomy.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 96e18b586..f4431bf48 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -13,7 +13,7 @@ ), 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), + 'singular_name' => _x( '{{label_ucfirst}}', 'taxonomy general name', '{{textdomain}}' ), 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), 'popular_items' => __( 'Popular {{label_plural}}', '{{textdomain}}' ), 'all_items' => __( 'All {{label_plural}}', '{{textdomain}}' ), From 8bfdf451c411afd9c4552f61bcdd4bca403cafe6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Jul 2013 03:55:57 +0300 Subject: [PATCH 2052/5359] introduce SynopsisValidator class --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/WP_CLI/SynopsisParser.php | 95 ------------------------ php/WP_CLI/SynopsisValidator.php | 105 +++++++++++++++++++++++++++ tests/test-arg-validation.php | 12 +-- 4 files changed, 112 insertions(+), 102 deletions(-) create mode 100644 php/WP_CLI/SynopsisValidator.php diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 3203ef9d4..16d101e3f 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -42,7 +42,7 @@ private function validate_args( $args, &$assoc_args ) { if ( !$synopsis ) return; - $parser = new \WP_CLI\SynopsisParser( $synopsis ); + $parser = new \WP_CLI\SynopsisValidator( $synopsis ); if ( !$parser->enough_positionals( $args ) ) { $this->show_usage(); exit(1); diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index eb5dc8e0e..3daf70d3a 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -6,72 +6,6 @@ class SynopsisParser { private static $patterns = array(); - private $params = array(); - - public function __construct( $synopsis ) { - $this->params = $this->parse( $synopsis ); - } - - public function enough_positionals( $args ) { - $positional = $this->query_params( array( - 'type' => 'positional', - 'flavour' => 'mandatory' - ) ); - - return count( $args ) >= count( $positional ); - } - - public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { - $assoc = $this->query_params( array( - 'type' => 'assoc', - ) ); - - $errors = array( - 'fatal' => array(), - 'warning' => array() - ); - - foreach ( $assoc as $param ) { - $key = $param['name']; - - if ( in_array( $key, $ignored_keys ) ) - continue; - - if ( !isset( $assoc_args[ $key ] ) ) { - if ( 'mandatory' == $param['flavour'] ) { - $errors['fatal'][] = "missing --$key parameter"; - } - } else { - if ( true === $assoc_args[ $key ] ) { - $error_type = ( 'mandatory' == $param['flavour'] ) ? 'fatal' : 'warning'; - $errors[ $error_type ][] = "--$key parameter needs a value"; - - unset( $assoc_args[ $key ] ); - } - } - } - - return $errors; - } - - public function unknown_assoc( $assoc_args ) { - $generic = $this->query_params( array( - 'type' => 'generic', - ) ); - - if ( count( $generic ) ) - return array(); - - $known_assoc = array(); - - foreach ( $this->params as $param ) { - if ( in_array( $param['type'], array( 'assoc', 'flag' ) ) ) - $known_assoc[] = $param['name']; - } - - return array_diff( array_keys( $assoc_args ), $known_assoc ); - } - /** * @param string * @return array List of parameters @@ -134,34 +68,5 @@ private static function gen_patterns( $type, $pattern, $flavour_types ) { } } } - - /** - * Filters a list of associatve arrays, based on a set of key => value arguments. - * - * @param array $args An array of key => value arguments to match against - * @param string $operator - * @return array - */ - private function query_params( $args, $operator = 'AND' ) { - $operator = strtoupper( $operator ); - $count = count( $args ); - $filtered = array(); - - foreach ( $this->params as $key => $to_match ) { - $matched = 0; - foreach ( $args as $m_key => $m_value ) { - if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) - $matched++; - } - - if ( ( 'AND' == $operator && $matched == $count ) - || ( 'OR' == $operator && $matched > 0 ) - || ( 'NOT' == $operator && 0 == $matched ) ) { - $filtered[$key] = $to_match; - } - } - - return $filtered; - } } diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php new file mode 100644 index 000000000..597d89b52 --- /dev/null +++ b/php/WP_CLI/SynopsisValidator.php @@ -0,0 +1,105 @@ +<?php + +namespace WP_CLI; + +/** + * Checks if the list of parameters matches the specification defined in the synopsis. + */ +class SynopsisValidator { + + private $spec = array(); + + public function __construct( $synopsis ) { + $this->spec = SynopsisParser::parse( $synopsis ); + } + + public function enough_positionals( $args ) { + $positional = $this->query_spec( array( + 'type' => 'positional', + 'flavour' => 'mandatory' + ) ); + + return count( $args ) >= count( $positional ); + } + + public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { + $assoc = $this->query_spec( array( + 'type' => 'assoc', + ) ); + + $errors = array( + 'fatal' => array(), + 'warning' => array() + ); + + foreach ( $assoc as $param ) { + $key = $param['name']; + + if ( in_array( $key, $ignored_keys ) ) + continue; + + if ( !isset( $assoc_args[ $key ] ) ) { + if ( 'mandatory' == $param['flavour'] ) { + $errors['fatal'][] = "missing --$key parameter"; + } + } else { + if ( true === $assoc_args[ $key ] ) { + $error_type = ( 'mandatory' == $param['flavour'] ) ? 'fatal' : 'warning'; + $errors[ $error_type ][] = "--$key parameter needs a value"; + + unset( $assoc_args[ $key ] ); + } + } + } + + return $errors; + } + + public function unknown_assoc( $assoc_args ) { + $generic = $this->query_spec( array( + 'type' => 'generic', + ) ); + + if ( count( $generic ) ) + return array(); + + $known_assoc = array(); + + foreach ( $this->spec as $param ) { + if ( in_array( $param['type'], array( 'assoc', 'flag' ) ) ) + $known_assoc[] = $param['name']; + } + + return array_diff( array_keys( $assoc_args ), $known_assoc ); + } + + /** + * Filters a list of associatve arrays, based on a set of key => value arguments. + * + * @param array $args An array of key => value arguments to match against + * @param string $operator + * @return array + */ + private function query_spec( $args, $operator = 'AND' ) { + $operator = strtoupper( $operator ); + $count = count( $args ); + $filtered = array(); + + foreach ( $this->spec as $key => $to_match ) { + $matched = 0; + foreach ( $args as $m_key => $m_value ) { + if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) + $matched++; + } + + if ( ( 'AND' == $operator && $matched == $count ) + || ( 'OR' == $operator && $matched > 0 ) + || ( 'NOT' == $operator && 0 == $matched ) ) { + $filtered[$key] = $to_match; + } + } + + return $filtered; + } +} + diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php index 887589119..f579823c5 100644 --- a/tests/test-arg-validation.php +++ b/tests/test-arg-validation.php @@ -1,11 +1,11 @@ <?php -use WP_CLI\SynopsisParser; +use WP_CLI\SynopsisValidator; class ArgValidationTests extends PHPUnit_Framework_TestCase { function testMissingPositional() { - $parser = new SynopsisParser( '<foo> <bar> [<baz>]' ); + $parser = new SynopsisValidator( '<foo> <bar> [<baz>]' ); $this->assertFalse( $parser->enough_positionals( array() ) ); $this->assertTrue( $parser->enough_positionals( array( 1, 2 ) ) ); @@ -13,7 +13,7 @@ function testMissingPositional() { } function testRepeatingPositional() { - $parser = new SynopsisParser( '<foo> [<bar>...]' ); + $parser = new SynopsisValidator( '<foo> [<bar>...]' ); $this->assertFalse( $parser->enough_positionals( array() ) ); $this->assertTrue( $parser->enough_positionals( array( 1 ) ) ); @@ -21,14 +21,14 @@ function testRepeatingPositional() { } function testUnknownAssocEmpty() { - $parser = new SynopsisParser( '' ); + $parser = new SynopsisValidator( '' ); $assoc_args = array( 'foo' => true, 'bar' => false ); $this->assertEquals( array_keys( $assoc_args ), $parser->unknown_assoc( $assoc_args ) ); } function testUnknownAssoc() { - $parser = new SynopsisParser( '--type=<type> [--brand=<brand>] [--flag]' ); + $parser = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); $assoc_args = array( 'type' => 'analog', 'brand' => true, 'flag' => true ); $this->assertEmpty( $parser->unknown_assoc( $assoc_args ) ); @@ -38,7 +38,7 @@ function testUnknownAssoc() { } function testMissingAssoc() { - $parser = new SynopsisParser( '--type=<type> [--brand=<brand>] [--flag]' ); + $parser = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); $assoc_args = array( 'brand' => true, 'flag' => true ); $errors = $parser->validate_assoc( $assoc_args ); From caf035f7302ed4d8c0a587c912f8d2f0eb448ea2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Jul 2013 04:10:08 +0300 Subject: [PATCH 2053/5359] Rewrite SynopsisParser to support optional values for assoc parameters. Props @jmslbam for initial implementation and tests. see #570 --- php/WP_CLI/SynopsisParser.php | 108 +++++++++++++++++++------------ php/WP_CLI/SynopsisValidator.php | 6 +- tests/test-synopsis.php | 108 ++++++++++++++++++++----------- 3 files changed, 138 insertions(+), 84 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 3daf70d3a..d7e4c1ba1 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -4,68 +4,90 @@ class SynopsisParser { - private static $patterns = array(); - /** - * @param string + * @param string A synopsis * @return array List of parameters */ static function parse( $synopsis ) { - if ( empty( self::$patterns ) ) - self::init_patterns(); - $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); $params = array(); - foreach ( $tokens as $token ) { - $type = false; - - foreach ( self::$patterns as $regex => $desc ) { - if ( preg_match( $regex, $token, $matches ) ) { - $type = $desc['type']; - $params[] = array_merge( $matches, $desc ); - break; + $param = self::classify_token( $token ); + + // Some types of parameters shouldn't be mandatory + if ( isset( $param['optional'] ) && !$param['optional'] ) { + if ( 'flag' === $param['type'] || + ( 'assoc' === $param['type'] && $param['value']['optional'] ) + ) { + $param['type'] = 'unknown'; } } - if ( !$type ) { - $params[] = array( - 'type' => 'unknown', - 'token' => $token - ); - } + $param['token'] = $token; + $params[] = $param; } return $params; } - private static function init_patterns() { - $p_name = '(?P<name>[a-z-_]+)'; - $p_value = '(?P<value>[a-zA-Z-|]+)'; + private static function classify_token( $token ) { + $param = array(); - self::gen_patterns( 'positional', "<$p_value>", array( 'mandatory', 'optional', 'repeating' ) ); - self::gen_patterns( 'generic', "--<field>=<value>", array( 'mandatory', 'optional', 'repeating' ) ); - self::gen_patterns( 'assoc', "--$p_name=<$p_value>", array( 'mandatory', 'optional' ) ); - self::gen_patterns( 'flag', "--$p_name", array( 'optional' ) ); - } + list( $param['optional'], $token ) = self::is_optional( $token ); + list( $param['repeating'], $token ) = self::is_repeating( $token ); - private static function gen_patterns( $type, $pattern, $flavour_types ) { - static $flavours = array( - 'mandatory' => ':pattern:', - 'optional' => '\[:pattern:\]', - 'repeating' => array( ':pattern:...', '\[:pattern:...\]' ) - ); - - foreach ( $flavour_types as $flavour_type ) { - foreach ( (array) $flavours[ $flavour_type ] as $flavour ) { - $final_pattern = str_replace( ':pattern:', $pattern, $flavour ); - - self::$patterns[ '/^' . $final_pattern . '$/' ] = array( - 'type' => $type, - 'flavour' => $flavour_type - ); + $p_name = '([a-z-_]+)'; + $p_value = '([a-zA-Z-|]+)'; + + if ( '--<field>=<value>' === $token ) { + $param['type'] = 'generic'; + } elseif ( preg_match( "/^<$p_name>$/", $token, $matches ) ) { + $param['type'] = 'positional'; + } elseif ( preg_match( "/^--$p_name/", $token, $matches ) ) { + $param['name'] = $matches[1]; + + $value = substr( $token, strlen( $matches[0] ) ); + + if ( false === $value ) { + $param['type'] = 'flag'; + } else { + $param['type'] = 'assoc'; + + list( $param['value']['optional'], $value ) = self::is_optional( $value ); + + if ( preg_match( "/^=<$p_value>$/", $value, $matches ) ) { + $param['value']['name'] = $matches[1]; + } else { + $param = array( 'type' => 'unknown' ); + } } + } else { + $param['type'] = 'unknown'; + } + + return $param; + } + + /** + * An optional parameter is surrounded by square brackets. + */ + private static function is_optional( $token ) { + if ( '[' == substr( $token, 0, 1 ) && ']' == substr( $token, -1 ) ) { + return array( true, substr( $token, 1, -1 ) ); + } else { + return array( false, $token ); + } + } + + /** + * A repeating parameter is followed by an ellipsis. + */ + private static function is_repeating( $token ) { + if ( '...' === substr( $token, -3 ) ) { + return array( true, substr( $token, 0, -3 ) ); + } else { + return array( false, $token ); } } } diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 597d89b52..902b537d0 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -16,7 +16,7 @@ public function __construct( $synopsis ) { public function enough_positionals( $args ) { $positional = $this->query_spec( array( 'type' => 'positional', - 'flavour' => 'mandatory' + 'optional' => false ) ); return count( $args ) >= count( $positional ); @@ -39,12 +39,12 @@ public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { continue; if ( !isset( $assoc_args[ $key ] ) ) { - if ( 'mandatory' == $param['flavour'] ) { + if ( !$param['optional'] ) { $errors['fatal'][] = "missing --$key parameter"; } } else { if ( true === $assoc_args[ $key ] ) { - $error_type = ( 'mandatory' == $param['flavour'] ) ? 'fatal' : 'warning'; + $error_type = ( !$param['optional'] ) ? 'fatal' : 'warning'; $errors[ $error_type ][] = "--$key parameter needs a value"; unset( $assoc_args[ $key ] ); diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 9262b593e..22e7cb907 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -15,54 +15,80 @@ function testPositional() { $this->assertCount( 2, $r ); - $this->assertEquals( 'positional', $r[0]['type'] ); - $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + $param = $r[0]; + $this->assertEquals( 'positional', $param['type'] ); + $this->assertFalse( $param['optional'] ); - $this->assertEquals( 'positional', $r[1]['type'] ); - $this->assertEquals( 'optional', $r[1]['flavour'] ); + $param = $r[1]; + $this->assertEquals( 'positional', $param['type'] ); + $this->assertTrue( $param['optional'] ); } function testFlag() { $r = SynopsisParser::parse( '[--foo]' ); $this->assertCount( 1, $r ); - $this->assertEquals( 'flag', $r[0]['type'] ); - $this->assertEquals( 'optional', $r[0]['flavour'] ); + + $param = $r[0]; + $this->assertEquals( 'flag', $param['type'] ); + $this->assertTrue( $param['optional'] ); // flags can't be mandatory $r = SynopsisParser::parse( '--foo' ); $this->assertCount( 1, $r ); - $this->assertEquals( 'unknown', $r[0]['type'] ); + + $param = $r[0]; + $this->assertEquals( 'unknown', $param['type'] ); } function testGeneric() { - $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>]' ); + $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>] --<field>[=<value>] [--<field>[=<value>]]' ); - $this->assertCount( 2, $r ); + $this->assertCount( 4, $r ); - $this->assertEquals( 'generic', $r[0]['type'] ); - $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + $param = $r[0]; + $this->assertEquals( 'generic', $param['type'] ); + $this->assertFalse( $param['optional'] ); - $this->assertEquals( 'generic', $r[1]['type'] ); - $this->assertEquals( 'optional', $r[1]['flavour'] ); + $param = $r[1]; + $this->assertEquals( 'generic', $param['type'] ); + $this->assertTrue( $param['optional'] ); + + $param = $r[2]; + $this->assertEquals( 'unknown', $param['type'] ); + + $param = $r[3]; + $this->assertEquals( 'unknown', $param['type'] ); } function testAssoc() { - $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>]' ); + $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>] [--bar[=<value>]]' ); - $this->assertCount( 2, $r ); + $this->assertCount( 3, $r ); - $this->assertEquals( 'assoc', $r[0]['type'] ); - $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + $param = $r[0]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertFalse( $param['optional'] ); - $this->assertEquals( 'assoc', $r[1]['type'] ); - $this->assertEquals( 'optional', $r[1]['flavour'] ); + $param = $r[1]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertTrue( $param['optional'] ); + + $param = $r[2]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertTrue( $param['optional'] ); + $this->assertTrue( $param['value']['optional'] ); + } + + function testInvalidAssoc() { + $r = SynopsisParser::parse( '--bar[=<value>] --bar=[<value>] --count=100' ); + + $this->assertCount( 3, $r ); - // shouldn't pass defaults to assoc parameters - $r = SynopsisParser::parse( '--count=100' ); - $this->assertCount( 1, $r ); $this->assertEquals( 'unknown', $r[0]['type'] ); + $this->assertEquals( 'unknown', $r[1]['type'] ); + $this->assertEquals( 'unknown', $r[2]['type'] ); } function testRepeating() { @@ -70,38 +96,44 @@ function testRepeating() { $this->assertCount( 2, $r ); - $this->assertEquals( 'positional', $r[0]['type'] ); - $this->assertEquals( 'repeating', $r[0]['flavour'] ); + $param = $r[0]; + $this->assertEquals( 'positional', $param['type'] ); + $this->assertTrue( $param['repeating'] ); - $this->assertEquals( 'generic', $r[1]['type'] ); - $this->assertEquals( 'repeating', $r[1]['flavour'] ); + $param = $r[1]; + $this->assertEquals( 'generic', $param['type'] ); + $this->assertTrue( $param['repeating'] ); } function testCombined() { $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); + $this->assertCount( 4, $r ); + $this->assertEquals( 'positional', $r[0]['type'] ); $this->assertEquals( 'assoc', $r[1]['type'] ); $this->assertEquals( 'generic', $r[2]['type'] ); $this->assertEquals( 'flag', $r[3]['type'] ); } - function testAllowedValueCharacters() { - $r = SynopsisParser::parse( '--capitals=<VALUE> --hyphen=<val-ue> --combined=<VAL-ue> --disallowed=<wrong:char>' ); + function testAllowedValueCharacters() { + $r = SynopsisParser::parse( '--capitals=<VALUE> --hyphen=<val-ue> --combined=<VAL-ue> --disallowed=<wrong:char>' ); - $this->assertCount( 4, $r ); + $this->assertCount( 4, $r ); - $this->assertEquals( 'assoc', $r[0]['type'] ); - $this->assertEquals( 'mandatory', $r[0]['flavour'] ); + $param = $r[0]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertFalse( $param['optional'] ); - $this->assertEquals( 'assoc', $r[1]['type'] ); - $this->assertEquals( 'mandatory', $r[1]['flavour'] ); + $param = $r[1]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertFalse( $param['optional'] ); - $this->assertEquals( 'assoc', $r[2]['type'] ); - $this->assertEquals( 'mandatory', $r[2]['flavour'] ); - - $this->assertEquals( 'unknown', $r[3]['type'] ); - } + $param = $r[2]; + $this->assertEquals( 'assoc', $param['type'] ); + $this->assertFalse( $param['optional'] ); + $this->assertEquals( 'unknown', $r[3]['type'] ); + } } From 82473c155a125a850f45cc34a6d1cb17380c9fbf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Jul 2013 04:59:06 +0300 Subject: [PATCH 2054/5359] ignore repeating parameters in enough_positionals() This isn't necessarily the best approach, but it matches previous behaviour. (see parent commit) --- php/WP_CLI/SynopsisValidator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 902b537d0..4b62a364e 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -16,7 +16,8 @@ public function __construct( $synopsis ) { public function enough_positionals( $args ) { $positional = $this->query_spec( array( 'type' => 'positional', - 'optional' => false + 'optional' => false, + 'repeating' => false ) ); return count( $args ) >= count( $positional ); From e8ea7f5b62baeb860cdc329a029d2cbc854f2d5c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Jul 2013 04:54:32 +0300 Subject: [PATCH 2055/5359] remove redundant array_filter() around preg_split() --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index d7e4c1ba1..c28173e6a 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -9,7 +9,7 @@ class SynopsisParser { * @return array List of parameters */ static function parse( $synopsis ) { - $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); + $tokens = preg_split( '/[\s\t]+/', $synopsis ); $params = array(); foreach ( $tokens as $token ) { From b9325dbe15c87fa5955b8bcfaf59a8fb5ae8acfe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 30 Jul 2013 05:05:19 +0300 Subject: [PATCH 2056/5359] Revert "remove redundant array_filter() around preg_split()" This reverts commit e8ea7f5b62baeb860cdc329a029d2cbc854f2d5c. It's not redundant when the synopsis has leading or trailing whitespace or when it's an empty string. --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index c28173e6a..d7e4c1ba1 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -9,7 +9,7 @@ class SynopsisParser { * @return array List of parameters */ static function parse( $synopsis ) { - $tokens = preg_split( '/[\s\t]+/', $synopsis ); + $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); $params = array(); foreach ( $tokens as $token ) { From 0b80c51041717e0bc66bcd20dcc68cf04775d0ee Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Jul 2013 19:54:12 +0300 Subject: [PATCH 2057/5359] remove 'Need even more info' section --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 857924996..bad038e58 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Where can I get more info? -------------------------- For documentation, usage, and examples, check out [wp-cli.org](http://wp-cli.org/). +Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). + I'm running into troubles, what can I do? ----------------------------------------- To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). @@ -21,12 +23,8 @@ We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](ht A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). -Need even more info? --------------------- -Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). - -If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. - Contributing ------------ See [CONTRIBUTING.md](CONTRIBUTING.md). + +If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. From 5f4a5ae59123cbcd6e91339dcd83d64dfaefff89 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 31 Jul 2013 19:59:02 +0300 Subject: [PATCH 2058/5359] giving credit where credit is due --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index bad038e58..83a5f567d 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,19 @@ To suggest a feature, report a bug, or general discussion, visit the [issues sec If you're reporting a bug, please also post the output from `wp --info`. +Credits +------- + +Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: + +* [Drush](http://drush.ws/) for... a lot of things +* [wpshell](http://code.trac.wordpress.org/browser/wpshell) for `wp shell` +* [Regenerate Thumbnails](http://wordpress.org/plugins/regenerate-thumbnails/) for `wp media regenerate` +* [Search-Replace-DB](https://github.com/interconnectit/Search-Replace-DB) for `wp search-replace` +* [WordPress-CLI-Exporter](https://github.com/Automattic/WordPress-CLI-Exporter) for `wp export` +* [WordPress-CLI-Importer](https://github.com/Automattic/WordPress-CLI-Importer) for `wp import` +* [wordpress-plugin-tests](https://github.com/benbalter/wordpress-plugin-tests/) for `wp scaffold plugin-tests` + Who's behind this thing? ------------------------ We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). From 8bde3c0f9f471c765a010f9fa958dce9736b3ff9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 03:43:46 +0300 Subject: [PATCH 2059/5359] don't return 'filter' object in `wp post get --format=json` it's a transient value, not actual data --- php/commands/post.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 8ef3c727e..f368f7bab 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -37,7 +37,7 @@ public function create( $args, $assoc_args ) { } if ( isset( $assoc_args['edit'] ) ) { - $input = ( isset( $assoc_args['post_content'] ) ) ? + $input = isset( $assoc_args['post_content'] ) ? $assoc_args['post_content'] : ''; if ( $output = $this->_edit( $input, 'WP-CLI: New Post' ) ) @@ -116,7 +116,9 @@ public function get( $args, $assoc_args ) { break; case 'json': - WP_CLI::print_value( $post, $assoc_args ); + $fields = get_object_vars( $post ); + unset( $fields['filter'] ); + WP_CLI::print_value( $fields, $assoc_args ); break; default: From fa8c9253f7aedf49a92f5165c043b689d98c582f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 03:49:25 +0300 Subject: [PATCH 2060/5359] remove unnecessary temporary variable --- php/commands/post.php | 3 +-- php/commands/user.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index f368f7bab..179283099 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -97,7 +97,6 @@ public function get( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( 'format' => 'table' ) ); - $format = $assoc_args['format']; $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) @@ -122,7 +121,7 @@ public function get( $args, $assoc_args ) { break; default: - \WP_CLI::error( "Invalid value for format: " . $format ); + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); break; } diff --git a/php/commands/user.php b/php/commands/user.php index f80b56c33..7a874a07c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -87,7 +87,7 @@ public function get( $args, $assoc_args ) { break; default: - \WP_CLI::error( "Invalid value for format: " . $format ); + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); break; } From 3f5d5c2f07d05ec608533ba463d5773587b7c254 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 16:46:56 +0300 Subject: [PATCH 2061/5359] introduce utils/convert-docs.php script --- utils/convert-docs.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 utils/convert-docs.php diff --git a/utils/convert-docs.php b/utils/convert-docs.php new file mode 100644 index 000000000..a2dbf1c86 --- /dev/null +++ b/utils/convert-docs.php @@ -0,0 +1,26 @@ +<?php + +# usage: php utils/convert-docs.php man-src/*.txt + +function convert_file( $path ) { + $out = file_get_contents( $path ); + + // options to definition lists + $out = preg_replace_callback( '/\n\* (.+?):?\n\n\t/', function( $matches ) { + $arg = str_replace( '`', '', $matches[1] ); + + return "\n$arg\n: "; + }, $out ); + + // convert tabs to spaces + $out = preg_replace( '/^\t/m', " ", $out ); + + // prepend docblock notation + $out = preg_replace( '/^(.*)/m', "\t* \\1", $out ); + + file_put_contents( $path, $out ); +} + +foreach ( array_slice( $argv, 1 ) as $arg ) { + convert_file( $arg ); +} From 23c99f47b7ab2411f23fc061b046433b412a11de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 17:42:40 +0300 Subject: [PATCH 2062/5359] make `wp help` read intermediary format --- php/commands/help.php | 4 ++-- utils/convert-docs.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 7b6599dc7..9b86c0858 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -42,8 +42,8 @@ private static function show_help( $command ) { // section headers $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); - // old-style options - $out = preg_replace( '/\n\* `(.+)`([^\n]*):\n\n/', "\n\t\\1\\2\n\t\t", $out ); + // definition lists + $out = preg_replace( '/\n([^\n]+)\n: (.+?)\n/s', "\n\t\\1\n\t\t\\2\n", $out ); $out = str_replace( "\t", ' ', $out ); diff --git a/utils/convert-docs.php b/utils/convert-docs.php index a2dbf1c86..59c573347 100644 --- a/utils/convert-docs.php +++ b/utils/convert-docs.php @@ -16,7 +16,7 @@ function convert_file( $path ) { $out = preg_replace( '/^\t/m', " ", $out ); // prepend docblock notation - $out = preg_replace( '/^(.*)/m', "\t* \\1", $out ); + # $out = preg_replace( '/^(.*)/m', "\t* \\1", $out ); file_put_contents( $path, $out ); } From f7cc325d74074311d2df0f194eeefee569e824cb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 22:40:34 +0300 Subject: [PATCH 2063/5359] pass string to DocParser (makes it easier to unit test) --- php/WP_CLI/Dispatcher/CommandFactory.php | 4 ++-- php/WP_CLI/DocParser.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index 72eb104f3..4e7a0aae1 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -21,7 +21,7 @@ public static function create( $name, $class, $parent ) { } private static function create_subcommand( $parent, $name, $class_name, $method ) { - $docparser = new \WP_CLI\DocParser( $method ); + $docparser = new \WP_CLI\DocParser( $method->getDocComment() ); if ( !$name ) $name = $docparser->get_tag( 'subcommand' ); @@ -39,7 +39,7 @@ private static function create_subcommand( $parent, $name, $class_name, $method } private static function create_composite_command( $parent, $name, $reflection ) { - $docparser = new \WP_CLI\DocParser( $reflection ); + $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); $container = new CompositeCommand( $parent, $name, $docparser ); diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 4d597a631..c5bfb1648 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -6,8 +6,8 @@ class DocParser { protected $docComment; - function __construct( $reflection ) { - $this->docComment = $reflection->getDocComment(); + function __construct( $docComment ) { + $this->docComment = $docComment; } function get_shortdesc() { From fd37d17336bc433f2976eba6e48bdf66eb7d84b3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 23:08:40 +0300 Subject: [PATCH 2064/5359] add a few unit tests for DocParser --- php/WP_CLI/DocParser.php | 4 +++ tests/test-doc-parser.php | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/test-doc-parser.php diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index c5bfb1648..f830285e3 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -17,6 +17,10 @@ function get_shortdesc() { return $matches[1]; } + function get_longdesc() { + return false; + } + function get_tag( $name ) { if ( preg_match( '/@' . $name . '\s+([a-z-_]+)/', $this->docComment, $matches ) ) return $matches[1]; diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php new file mode 100644 index 000000000..2026b3af6 --- /dev/null +++ b/tests/test-doc-parser.php @@ -0,0 +1,75 @@ +<?php + +use WP_CLI\DocParser; + +class DocParserTests extends PHPUnit_Framework_TestCase { + + function test_only_tags() { + $doc = new DocParser( <<<EOB +/** + * @alias rock-on + */ +EOB + ); + + $this->assertFalse( $doc->get_shortdesc() ); + $this->assertFalse( $doc->get_longdesc() ); + $this->assertFalse( $doc->get_synopsis() ); + $this->assertFalse( $doc->get_tag('foo') ); + $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); + } + + function test_no_longdesc() { + $doc = new DocParser( <<<EOB +/** + * Rock and roll! + * @alias rock-on + */ +EOB + ); + + $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); + $this->assertFalse( $doc->get_longdesc() ); + $this->assertFalse( $doc->get_synopsis() ); + $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); + } + + function test_complete() { + $doc = new DocParser( <<<EOB +/** + * Rock and roll! + * + * ## OPTIONS + * + * --volume=<number> + * : Sets the volume. + * + * ## EXAMPLES + * + * wp rock-on --volume=11 + * + * @synopsis [--volume=<number>] + * @alias rock-on + */ +EOB + ); + + $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); + $this->assertEquals( '[--volume=<number>]', $doc->get_synopsis() ); + $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); + + $longdesc = <<<EOB +## OPTIONS + +--volume=<number> +: Sets the volume. + +## EXAMPLES + +wp rock-on --volume=11 +EOB + ; + $this->assertEquals( $longdesc, $doc->get_longdesc() ); + } +} + From 8868ee7da7e520a789666823bd7f088e0402967f Mon Sep 17 00:00:00 2001 From: Dan Gardner <dan@web.nearest.to> Date: Thu, 1 Aug 2013 21:09:16 +0100 Subject: [PATCH 2065/5359] Support multi-line argument values (#624) --- php/WP_CLI/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index e28c90f1f..239e95f23 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -45,7 +45,7 @@ function parse_args( $arguments ) { $mixed_args[] = array( $matches[1], false ); } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { $mixed_args[] = array( $matches[1], true ); - } elseif ( preg_match( '|^--([^=]+)=(.+)|', $arg, $matches ) ) { + } elseif ( preg_match( '|^--([^=]+)=(.+)|s', $arg, $matches ) ) { $mixed_args[] = array( $matches[1], $matches[2] ); } else { $regular_args[] = $arg; From 4efa6555190d2050455115bfb8da9f67119252c9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 23:18:57 +0300 Subject: [PATCH 2066/5359] DocParser: remove decorations before processing --- php/WP_CLI/DocParser.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index f830285e3..ebd9a5296 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -7,11 +7,19 @@ class DocParser { protected $docComment; function __construct( $docComment ) { - $this->docComment = $docComment; + $this->docComment = self::remove_decorations( $docComment ); + } + + private static function remove_decorations( $comment ) { + $comment = preg_replace( '|^/\*\*\n|', '', $comment ); + $comment = preg_replace( '|\n[\t ]*\*/$|', '', $comment ); + $comment = preg_replace( '|^[\t ]*\* ?|m', '', $comment ); + + return $comment; } function get_shortdesc() { - if ( !preg_match( '/\* (\w.+)\n*/', $this->docComment, $matches ) ) + if ( !preg_match( '|^([^@][^\n]+)\n*|', $this->docComment, $matches ) ) return false; return $matches[1]; @@ -22,14 +30,14 @@ function get_longdesc() { } function get_tag( $name ) { - if ( preg_match( '/@' . $name . '\s+([a-z-_]+)/', $this->docComment, $matches ) ) + if ( preg_match( '|^@' . $name . '\s+([a-z-_]+)|m', $this->docComment, $matches ) ) return $matches[1]; return false; } function get_synopsis() { - if ( !preg_match( '/@synopsis\s+([^\n]+)/', $this->docComment, $matches ) ) + if ( !preg_match( '|^@synopsis\s+(.+)|m', $this->docComment, $matches ) ) return false; return $matches[1]; From 7d5106c837821ed884c063a74dd10f35b7f39fe0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 23:45:01 +0300 Subject: [PATCH 2067/5359] DocParser: return empty string instead of false --- php/WP_CLI/DocParser.php | 6 +++--- tests/test-doc-parser.php | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index ebd9a5296..e146833ad 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -20,7 +20,7 @@ private static function remove_decorations( $comment ) { function get_shortdesc() { if ( !preg_match( '|^([^@][^\n]+)\n*|', $this->docComment, $matches ) ) - return false; + return ''; return $matches[1]; } @@ -33,12 +33,12 @@ function get_tag( $name ) { if ( preg_match( '|^@' . $name . '\s+([a-z-_]+)|m', $this->docComment, $matches ) ) return $matches[1]; - return false; + return ''; } function get_synopsis() { if ( !preg_match( '|^@synopsis\s+(.+)|m', $this->docComment, $matches ) ) - return false; + return ''; return $matches[1]; } diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index 2026b3af6..413848191 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -4,6 +4,15 @@ class DocParserTests extends PHPUnit_Framework_TestCase { + function test_empty() { + $doc = new DocParser( '' ); + + $this->assertEquals( '', $doc->get_shortdesc() ); + $this->assertEquals( '', $doc->get_longdesc() ); + $this->assertEquals( '', $doc->get_synopsis() ); + $this->assertEquals( '', $doc->get_tag('alias') ); + } + function test_only_tags() { $doc = new DocParser( <<<EOB /** @@ -12,10 +21,10 @@ function test_only_tags() { EOB ); - $this->assertFalse( $doc->get_shortdesc() ); - $this->assertFalse( $doc->get_longdesc() ); - $this->assertFalse( $doc->get_synopsis() ); - $this->assertFalse( $doc->get_tag('foo') ); + $this->assertEquals( '', $doc->get_shortdesc() ); + $this->assertEquals( '', $doc->get_longdesc() ); + $this->assertEquals( '', $doc->get_synopsis() ); + $this->assertEquals( '', $doc->get_tag('foo') ); $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); } @@ -29,8 +38,8 @@ function test_no_longdesc() { ); $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); - $this->assertFalse( $doc->get_longdesc() ); - $this->assertFalse( $doc->get_synopsis() ); + $this->assertEquals( '', $doc->get_longdesc() ); + $this->assertEquals( '', $doc->get_synopsis() ); $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); } From eada5446c3f328b0a24d3e8190cbe1dbcc1b3fdf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 1 Aug 2013 23:48:38 +0300 Subject: [PATCH 2068/5359] DocParser: implement get_longdesc() --- php/WP_CLI/DocParser.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index e146833ad..a999a9e1e 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -26,7 +26,22 @@ function get_shortdesc() { } function get_longdesc() { - return false; + $shortdesc = $this->get_shortdesc(); + if ( !$shortdesc ) + return ''; + + $longdesc = substr( $this->docComment, strlen( $shortdesc ) ); + + $lines = array(); + foreach ( explode( "\n", $longdesc ) as $line ) { + if ( 0 === strpos( $line, '@' ) ) + break; + + $lines[] = $line; + } + $longdesc = trim( implode( $lines, "\n" ) ); + + return $longdesc; } function get_tag( $name ) { From 127f409d29df737904e06a2c864fc8fd2d608059 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 2 Aug 2013 00:57:32 +0300 Subject: [PATCH 2069/5359] replace get_extra_markdown() with get_longdesc() --- php/WP_CLI/Dispatcher/CompositeCommand.php | 27 ++++------------------ php/WP_CLI/Dispatcher/RootCommand.php | 2 +- php/commands/cli.php | 1 + php/commands/help.php | 2 +- 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 1aa21b5d3..98cbbe734 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -17,6 +17,7 @@ public function __construct( $parent, $name, $docparser ) { $this->name = $name; $this->shortdesc = $docparser->get_shortdesc(); + $this->longdesc = $docparser->get_longdesc(); $when_to_invoke = $docparser->get_tag( 'when' ); if ( $when_to_invoke ) { @@ -50,6 +51,10 @@ function get_shortdesc() { return $this->shortdesc; } + function get_longdesc() { + return $this->longdesc; + } + function get_synopsis() { return '<subcommand>'; } @@ -73,28 +78,6 @@ function show_usage() { \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); } - function get_extra_markdown() { - $md_file = self::find_extra_markdown_file( $this ); - if ( !$md_file ) - return ''; - - return file_get_contents( $md_file ); - } - - private static function find_extra_markdown_file( $command ) { - $cmd_path = get_path( $command ); - array_shift( $cmd_path ); // discard 'wp' - $cmd_path = implode( '-', $cmd_path ); - - foreach ( \WP_CLI::get_man_dirs() as $src_dir ) { - $src_path = "$src_dir/$cmd_path.txt"; - if ( is_readable( $src_path ) ) - return $src_path; - } - - return false; - } - function find_subcommand( &$args ) { $name = array_shift( $args ); diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 311d295bb..d65c79fd4 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -17,7 +17,7 @@ function __construct() { $this->shortdesc = 'Manage WordPress through the command-line.'; } - function get_extra_markdown() { + function get_longdesc() { $binding = array(); foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { diff --git a/php/commands/cli.php b/php/commands/cli.php index a31493b87..2f550c885 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -14,6 +14,7 @@ private function command_to_array( $command ) { $dump = array( 'name' => $command->get_name(), 'description' => $command->get_shortdesc(), + 'longdesc' => $command->get_longdesc(), ); foreach ( $command->get_subcommands() as $subcommand ) { diff --git a/php/commands/help.php b/php/commands/help.php index 9b86c0858..fb42b8a40 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -37,7 +37,7 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); - $out .= $command->get_extra_markdown(); + $out .= $command->get_longdesc(); // section headers $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); From 27a2ff1e94ccb924d24a978c78fb3b1a9520ee25 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 2 Aug 2013 01:38:57 +0300 Subject: [PATCH 2070/5359] add test for multiline excerpt. see #624 --- features/post.feature | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index f8de28f0c..38dfb3a93 100644 --- a/features/post.feature +++ b/features/post.feature @@ -33,11 +33,23 @@ Feature: Manage WordPress posts It will be inserted in a post. """ + And a command.sh file: + """ + cat content.html | wp post create --post_title='Test post' --post_excerpt="A multiline + excerpt" --porcelain - + """ - When I run `wp post create --post_title='Test post' --porcelain - < content.html` + When I run `bash command.sh` Then STDOUT should match '%d' And save STDOUT as {POST_ID} + When I run `wp eval '$post_id = {POST_ID}; echo get_post( $post_id )->post_excerpt;'` + Then STDOUT should be: + """ + A multiline + excerpt + """ + When I run `wp post get --format=content {POST_ID}` Then STDOUT should be: """ From 8b21c3f17cd2eab2e6856aa96bf2772c031c3875 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 16:17:25 +0300 Subject: [PATCH 2071/5359] convert tabs to spaces only when displaying in the CLI --- php/commands/help.php | 3 +++ utils/convert-docs.php | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index fb42b8a40..e4686e155 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -45,6 +45,9 @@ private static function show_help( $command ) { // definition lists $out = preg_replace( '/\n([^\n]+)\n: (.+?)\n/s', "\n\t\\1\n\t\t\\2\n", $out ); + // convert tabs to spaces + $out = preg_replace( '/^\t/m', " ", $out ); + $out = str_replace( "\t", ' ', $out ); echo WP_CLI::colorize( $out ); diff --git a/utils/convert-docs.php b/utils/convert-docs.php index 59c573347..e898b0e62 100644 --- a/utils/convert-docs.php +++ b/utils/convert-docs.php @@ -12,9 +12,6 @@ function convert_file( $path ) { return "\n$arg\n: "; }, $out ); - // convert tabs to spaces - $out = preg_replace( '/^\t/m', " ", $out ); - // prepend docblock notation # $out = preg_replace( '/^(.*)/m', "\t* \\1", $out ); From 95ada7e37be56eac52115136760ff00467fc3779 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Sun, 4 Aug 2013 16:11:14 +0100 Subject: [PATCH 2072/5359] Clearer confirmation message when network-activating plugins --- php/commands/plugin.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e95c56845..c6f442835 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -89,7 +89,10 @@ function activate( $args, $assoc_args = array() ) { activate_plugin( $file, '', $network_wide ); if ( $this->check_active( $file, $network_wide ) ) { - WP_CLI::success( "Plugin '$name' activated." ); + if ( $network_wide ) + WP_CLI::success( "Plugin '$name' network activated." ); + else + WP_CLI::success( "Plugin '$name' activated." ); } else { WP_CLI::error( 'Could not activate plugin: ' . $name ); } @@ -109,7 +112,10 @@ function deactivate( $args, $assoc_args = array() ) { deactivate_plugins( $file, false, $network_wide ); if ( ! $this->check_active( $file, $network_wide ) ) { - WP_CLI::success( "Plugin '$name' deactivated." ); + if ( $network_wide ) + WP_CLI::success( "Plugin '$name' network deactivated." ); + else + WP_CLI::success( "Plugin '$name' deactivated." ); } else { WP_CLI::error( 'Could not deactivate plugin: ' . $name ); } From 95a445613c5e876cf71e21a36e97b4b0986f6e7e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 16:27:56 +0300 Subject: [PATCH 2073/5359] deprecate WP_CLI::add_man_dir() --- features/help.feature | 29 ----------------------------- php/class-wp-cli.php | 20 ++++++++------------ 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/features/help.feature b/features/help.feature index 3aef3dbcb..10626d66a 100644 --- a/features/help.feature +++ b/features/help.feature @@ -19,35 +19,6 @@ Feature: Get help about WP-CLI commands Then the return code should be 1 And STDERR should not be empty - Scenario: Help for third-party commands - Given a WP install - And a wp-content/plugins/test-cli/test-help.txt file: - """ - ## EXAMPLES - - wp test-help - """ - And a wp-content/plugins/test-cli/command.php file: - """ - <?php - // Plugin Name: Test CLI Help - - class Test_Help extends WP_CLI_Command { - function __invoke() {} - } - - WP_CLI::add_command( 'test-help', 'Test_Help' ); - - WP_CLI::add_man_dir( __DIR__, __DIR__ ); - """ - And I run `wp plugin activate test-cli` - - When I run `wp help test-help` - Then STDOUT should contain: - """ - wp test-help - """ - Scenario: Help for incomplete commands Given an empty directory diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1408f9728..da3a32be6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -14,14 +14,10 @@ class WP_CLI { private static $hooks = array(), $hooks_passed = array(); - private static $man_dirs = array(); - /** * Initialize WP_CLI static variables. */ static function init() { - self::add_man_dir( null, WP_CLI_ROOT . "/man-src" ); - self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); } @@ -102,14 +98,6 @@ static function add_command( $name, $class, $args = array() ) { self::get_root_command()->add_subcommand( $name, $command ); } - static function add_man_dir( $deprecated = null, $src_dir ) { - self::$man_dirs[] = $src_dir; - } - - static function get_man_dirs() { - return self::$man_dirs; - } - /** * Display a message in the CLI and end with a newline * @@ -276,6 +264,14 @@ static function run_command( $args, $assoc_args = array() ) { self::get_runner()->run_command( $args, $assoc_args ); } + + + // DEPRECATED STUFF + + static function add_man_dir() { + trigger_error( 'WP_CLI::add_man_dir() is deprecated. Add docs inline.', E_USER_WARNING ); + } + // back-compat static function out( $str ) { echo $str; From 003239d8586931246d54b88e85af366a18d56ec1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 16:39:07 +0300 Subject: [PATCH 2074/5359] add extra newline if longdesc exists --- php/commands/help.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index e4686e155..25048e6d1 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -37,7 +37,10 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); - $out .= $command->get_longdesc(); + $longdesc = $command->get_longdesc(); + if ( $longdesc ) { + $out .= $longdesc . "\n"; + } // section headers $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); From 94cb592712bfe8ed053d1795a9c75934a3838027 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 16:45:28 +0300 Subject: [PATCH 2075/5359] convert-docs.php: indentation fixes --- php/commands/help.php | 3 --- utils/convert-docs.php | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 25048e6d1..0e074f087 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -48,9 +48,6 @@ private static function show_help( $command ) { // definition lists $out = preg_replace( '/\n([^\n]+)\n: (.+?)\n/s', "\n\t\\1\n\t\t\\2\n", $out ); - // convert tabs to spaces - $out = preg_replace( '/^\t/m', " ", $out ); - $out = str_replace( "\t", ' ', $out ); echo WP_CLI::colorize( $out ); diff --git a/utils/convert-docs.php b/utils/convert-docs.php index e898b0e62..b3b9668c8 100644 --- a/utils/convert-docs.php +++ b/utils/convert-docs.php @@ -12,8 +12,12 @@ function convert_file( $path ) { return "\n$arg\n: "; }, $out ); + // fix indentation + $out = preg_replace( '/^ ([^ ]+)/m', "\t\\1", $out ); + $out = str_replace( "\t", ' ', $out ); + // prepend docblock notation - # $out = preg_replace( '/^(.*)/m', "\t* \\1", $out ); + $out = preg_replace( '/^/m', "\t * ", $out ); file_put_contents( $path, $out ); } From 1a62c552573909b643e97348ac4214ae2bf2c83f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 17:12:08 +0300 Subject: [PATCH 2076/5359] move docs from man-src/ into PHPDoc comments --- man-src/cache.txt | 5 - man-src/cap.txt | 10 -- man-src/comment-approve.txt | 9 -- man-src/comment-count.txt | 10 -- man-src/comment-create.txt | 14 --- man-src/comment-delete.txt | 13 --- man-src/comment-last.txt | 13 --- man-src/comment-spam.txt | 9 -- man-src/comment-status.txt | 9 -- man-src/comment-trash.txt | 9 -- man-src/comment-unapprove.txt | 9 -- man-src/comment-unspam.txt | 9 -- man-src/comment-untrash.txt | 9 -- man-src/core-config.txt | 40 -------- man-src/core-download.txt | 18 ---- man-src/core-init-tests.txt | 22 ----- man-src/core-install.txt | 21 ---- man-src/core-is-installed.txt | 5 - man-src/core-multisite-convert.txt | 14 --- man-src/core-multisite-install.txt | 30 ------ man-src/core-update-db.txt | 0 man-src/core-update.txt | 19 ---- man-src/core-version.txt | 5 - man-src/db.txt | 18 ---- man-src/eval-file.txt | 3 - man-src/eval.txt | 3 - man-src/export.txt | 54 ----------- man-src/help.txt | 7 -- man-src/import.txt | 13 --- man-src/media-import.txt | 45 --------- man-src/media-regenerate.txt | 15 --- man-src/network-meta.txt | 14 --- man-src/option.txt | 15 --- man-src/plugin-activate.txt | 9 -- man-src/plugin-deactivate.txt | 9 -- man-src/plugin-delete.txt | 9 -- man-src/plugin-install.txt | 33 ------- man-src/plugin-list.txt | 9 -- man-src/plugin-path.txt | 15 --- man-src/plugin-status.txt | 5 - man-src/plugin-toggle.txt | 9 -- man-src/plugin-uninstall.txt | 14 --- man-src/plugin-update-all.txt | 9 -- man-src/plugin-update.txt | 14 --- man-src/post-create.txt | 31 ------ man-src/post-delete.txt | 15 --- man-src/post-edit.txt | 9 -- man-src/post-generate.txt | 29 ------ man-src/post-get.txt | 22 ----- man-src/post-list.txt | 21 ---- man-src/post-meta.txt | 9 -- man-src/post-update.txt | 13 --- man-src/rewrite-dump.txt | 5 - man-src/rewrite-flush.txt | 7 -- man-src/rewrite-structure.txt | 14 --- man-src/role-create.txt | 15 --- man-src/role-delete.txt | 12 --- man-src/role-exists.txt | 16 --- man-src/role-list.txt | 13 --- man-src/scaffold-_s.txt | 21 ---- man-src/scaffold-child-theme.txt | 29 ------ man-src/scaffold-plugin-tests.txt | 17 ---- man-src/scaffold-plugin.txt | 9 -- man-src/scaffold-post-type.txt | 23 ----- man-src/scaffold-taxonomy.txt | 31 ------ man-src/search-replace.txt | 25 ----- man-src/shell.txt | 9 -- man-src/site-create.txt | 25 ----- man-src/site-delete.txt | 17 ---- man-src/site-empty.txt | 5 - man-src/term-create.txt | 29 ------ man-src/term-delete.txt | 13 --- man-src/term-list.txt | 19 ---- man-src/term-update.txt | 29 ------ man-src/theme-activate.txt | 5 - man-src/theme-delete.txt | 9 -- man-src/theme-install.txt | 25 ----- man-src/theme-list.txt | 9 -- man-src/theme-path.txt | 15 --- man-src/theme-status.txt | 5 - man-src/theme-update-all.txt | 9 -- man-src/theme-update.txt | 14 --- man-src/transient.txt | 3 - man-src/user-add-role.txt | 14 --- man-src/user-create.txt | 33 ------- man-src/user-delete.txt | 13 --- man-src/user-generate.txt | 9 -- man-src/user-get.txt | 19 ---- man-src/user-import-csv.txt | 16 --- man-src/user-list.txt | 21 ---- man-src/user-meta.txt | 9 -- man-src/user-remove-role.txt | 10 -- man-src/user-set-role.txt | 15 --- man-src/user-update.txt | 15 --- php/commands/cache.php | 6 +- php/commands/cap.php | 11 ++- php/commands/comment.php | 108 +++++++++++++++++++++ php/commands/core.php | 151 +++++++++++++++++++++++++++++ php/commands/db.php | 16 ++- php/commands/eval-file.php | 4 + php/commands/eval.php | 4 + php/commands/export.php | 44 +++++++++ php/commands/help.php | 8 ++ php/commands/import.php | 11 +++ php/commands/media.php | 53 ++++++++++ php/commands/network-meta.php | 13 ++- php/commands/option.php | 15 ++- php/commands/plugin.php | 127 ++++++++++++++++++++++++ php/commands/post-meta.php | 9 +- php/commands/post.php | 128 +++++++++++++++++++++++- php/commands/rewrite.php | 30 +++++- php/commands/role.php | 56 ++++++++++- php/commands/scaffold.php | 111 +++++++++++++++++++++ php/commands/search-replace.php | 23 +++++ php/commands/shell.php | 9 ++ php/commands/site.php | 39 ++++++++ php/commands/term.php | 77 +++++++++++++++ php/commands/theme.php | 88 +++++++++++++++++ php/commands/transient.php | 4 +- php/commands/user-meta.php | 9 +- php/commands/user.php | 151 +++++++++++++++++++++++++++++ 121 files changed, 1290 insertions(+), 1439 deletions(-) delete mode 100644 man-src/cache.txt delete mode 100644 man-src/cap.txt delete mode 100644 man-src/comment-approve.txt delete mode 100644 man-src/comment-count.txt delete mode 100644 man-src/comment-create.txt delete mode 100644 man-src/comment-delete.txt delete mode 100644 man-src/comment-last.txt delete mode 100644 man-src/comment-spam.txt delete mode 100644 man-src/comment-status.txt delete mode 100644 man-src/comment-trash.txt delete mode 100644 man-src/comment-unapprove.txt delete mode 100644 man-src/comment-unspam.txt delete mode 100644 man-src/comment-untrash.txt delete mode 100644 man-src/core-config.txt delete mode 100644 man-src/core-download.txt delete mode 100644 man-src/core-init-tests.txt delete mode 100644 man-src/core-install.txt delete mode 100644 man-src/core-is-installed.txt delete mode 100644 man-src/core-multisite-convert.txt delete mode 100644 man-src/core-multisite-install.txt delete mode 100644 man-src/core-update-db.txt delete mode 100644 man-src/core-update.txt delete mode 100644 man-src/core-version.txt delete mode 100644 man-src/db.txt delete mode 100644 man-src/eval-file.txt delete mode 100644 man-src/eval.txt delete mode 100644 man-src/export.txt delete mode 100644 man-src/help.txt delete mode 100644 man-src/import.txt delete mode 100644 man-src/media-import.txt delete mode 100644 man-src/media-regenerate.txt delete mode 100644 man-src/network-meta.txt delete mode 100644 man-src/option.txt delete mode 100644 man-src/plugin-activate.txt delete mode 100644 man-src/plugin-deactivate.txt delete mode 100644 man-src/plugin-delete.txt delete mode 100644 man-src/plugin-install.txt delete mode 100644 man-src/plugin-list.txt delete mode 100644 man-src/plugin-path.txt delete mode 100644 man-src/plugin-status.txt delete mode 100644 man-src/plugin-toggle.txt delete mode 100644 man-src/plugin-uninstall.txt delete mode 100644 man-src/plugin-update-all.txt delete mode 100644 man-src/plugin-update.txt delete mode 100644 man-src/post-create.txt delete mode 100644 man-src/post-delete.txt delete mode 100644 man-src/post-edit.txt delete mode 100644 man-src/post-generate.txt delete mode 100644 man-src/post-get.txt delete mode 100644 man-src/post-list.txt delete mode 100644 man-src/post-meta.txt delete mode 100644 man-src/post-update.txt delete mode 100644 man-src/rewrite-dump.txt delete mode 100644 man-src/rewrite-flush.txt delete mode 100644 man-src/rewrite-structure.txt delete mode 100644 man-src/role-create.txt delete mode 100644 man-src/role-delete.txt delete mode 100644 man-src/role-exists.txt delete mode 100644 man-src/role-list.txt delete mode 100644 man-src/scaffold-_s.txt delete mode 100644 man-src/scaffold-child-theme.txt delete mode 100644 man-src/scaffold-plugin-tests.txt delete mode 100644 man-src/scaffold-plugin.txt delete mode 100644 man-src/scaffold-post-type.txt delete mode 100644 man-src/scaffold-taxonomy.txt delete mode 100644 man-src/search-replace.txt delete mode 100644 man-src/shell.txt delete mode 100644 man-src/site-create.txt delete mode 100644 man-src/site-delete.txt delete mode 100644 man-src/site-empty.txt delete mode 100644 man-src/term-create.txt delete mode 100644 man-src/term-delete.txt delete mode 100644 man-src/term-list.txt delete mode 100644 man-src/term-update.txt delete mode 100644 man-src/theme-activate.txt delete mode 100644 man-src/theme-delete.txt delete mode 100644 man-src/theme-install.txt delete mode 100644 man-src/theme-list.txt delete mode 100644 man-src/theme-path.txt delete mode 100644 man-src/theme-status.txt delete mode 100644 man-src/theme-update-all.txt delete mode 100644 man-src/theme-update.txt delete mode 100644 man-src/transient.txt delete mode 100644 man-src/user-add-role.txt delete mode 100644 man-src/user-create.txt delete mode 100644 man-src/user-delete.txt delete mode 100644 man-src/user-generate.txt delete mode 100644 man-src/user-get.txt delete mode 100644 man-src/user-import-csv.txt delete mode 100644 man-src/user-list.txt delete mode 100644 man-src/user-meta.txt delete mode 100644 man-src/user-remove-role.txt delete mode 100644 man-src/user-set-role.txt delete mode 100644 man-src/user-update.txt diff --git a/man-src/cache.txt b/man-src/cache.txt deleted file mode 100644 index 70856ff26..000000000 --- a/man-src/cache.txt +++ /dev/null @@ -1,5 +0,0 @@ -## EXAMPLES - - wp cache set my_key my_value my_group 300 - - wp cache get my_key my_group diff --git a/man-src/cap.txt b/man-src/cap.txt deleted file mode 100644 index 73b0921b1..000000000 --- a/man-src/cap.txt +++ /dev/null @@ -1,10 +0,0 @@ -## EXAMPLES - - # Add 'spectate' capability to 'author' role - wp cap add 'author' 'spectate' - - # Add all caps from 'editor' role to 'author' role - wp cap list 'editor' | xargs wp cap add 'author' - - # Remove all caps from 'editor' role that also appear in 'author' role - wp cap list 'author' | xargs wp cap remove 'editor' diff --git a/man-src/comment-approve.txt b/man-src/comment-approve.txt deleted file mode 100644 index f703cd04b..000000000 --- a/man-src/comment-approve.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to approve. - -## EXAMPLES - - wp comment approve 1337 diff --git a/man-src/comment-count.txt b/man-src/comment-count.txt deleted file mode 100644 index 0c595e370..000000000 --- a/man-src/comment-count.txt +++ /dev/null @@ -1,10 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the post to count comments in - -## EXAMPLES - - wp comment count - wp comment count 42 diff --git a/man-src/comment-create.txt b/man-src/comment-create.txt deleted file mode 100644 index 0b093d2f0..000000000 --- a/man-src/comment-create.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* `--<field>`=<value>: - - Field values for the new comment. See wp_insert_comment(). - -* `--porcelain`: - - Output just the new comment id. - -## EXAMPLES - - wp comment create --comment_post_ID=15 --comment_content="hello blog" ---comment_author="wp-cli" diff --git a/man-src/comment-delete.txt b/man-src/comment-delete.txt deleted file mode 100644 index bd39300f7..000000000 --- a/man-src/comment-delete.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to delete. - -* `--force`: - - Skip the trash bin. - -## EXAMPLES - - wp comment delete 1337 --force diff --git a/man-src/comment-last.txt b/man-src/comment-last.txt deleted file mode 100644 index 34504ec53..000000000 --- a/man-src/comment-last.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `--id`: - - Output just the last comment id. - -* `--full`: - - Output complete comment information. - -## EXAMPLES - - wp comment last --full diff --git a/man-src/comment-spam.txt b/man-src/comment-spam.txt deleted file mode 100644 index b1a446cf1..000000000 --- a/man-src/comment-spam.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to mark as spam. - -## EXAMPLES - - wp comment spam 1337 diff --git a/man-src/comment-status.txt b/man-src/comment-status.txt deleted file mode 100644 index a53c32765..000000000 --- a/man-src/comment-status.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to check - -## EXAMPLES - - wp comment status 1337 diff --git a/man-src/comment-trash.txt b/man-src/comment-trash.txt deleted file mode 100644 index 3d1388178..000000000 --- a/man-src/comment-trash.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to trash. - -## EXAMPLES - - wp comment trash 1337 diff --git a/man-src/comment-unapprove.txt b/man-src/comment-unapprove.txt deleted file mode 100644 index 5569199c4..000000000 --- a/man-src/comment-unapprove.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to unapprove. - -## EXAMPLES - - wp comment unapprove 1337 diff --git a/man-src/comment-unspam.txt b/man-src/comment-unspam.txt deleted file mode 100644 index 1a055d2ce..000000000 --- a/man-src/comment-unspam.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to unmark as spam. - -## EXAMPLES - - wp comment unspam 1337 diff --git a/man-src/comment-untrash.txt b/man-src/comment-untrash.txt deleted file mode 100644 index 54fe15eb2..000000000 --- a/man-src/comment-untrash.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the comment to untrash. - -## EXAMPLES - - wp comment untrash 1337 diff --git a/man-src/core-config.txt b/man-src/core-config.txt deleted file mode 100644 index 9945a05c3..000000000 --- a/man-src/core-config.txt +++ /dev/null @@ -1,40 +0,0 @@ -## OPTIONS - -* `--dbname`=<dbname>: - - Set the database name. - -* `--dbuser`=<dbuser>: - - Set the database user. - -* `--dbpass`=<dbpass>: - - Set the database user password. - -* `--dbhost`=<dbhost>: - - Set the database host. Default: 'localhost' - -* `--dbprefix`=<dbprefix>: - - Set the database table prefix. Default: 'wp_' - -* `--locale`=<locale>: - - Set the WPLANG constant. Defaults to $wp_local_package variable. - -* `--extra-php`: - - If set, the command reads additional PHP code from STDIN. - -## EXAMPLES - - # Standard wp-config.php file - wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO - - # Enable WP_DEBUG and WP_DEBUG_LOG - wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP - define( 'WP_DEBUG', true ); - define( 'WP_DEBUG_LOG', true ); - PHP diff --git a/man-src/core-download.txt b/man-src/core-download.txt deleted file mode 100644 index a72ecc610..000000000 --- a/man-src/core-download.txt +++ /dev/null @@ -1,18 +0,0 @@ -## OPTIONS - -* `--locale`=<locale>: - - Select which language you want to download. The --version parameter is -ignored in this case. - -* `--version`=<version>: - - Select which version you want to download. - -* `--force`: - - Overwrites existing files, if present. - -## EXAMPLES - - wp core download --version=3.3 diff --git a/man-src/core-init-tests.txt b/man-src/core-init-tests.txt deleted file mode 100644 index 55d72eafc..000000000 --- a/man-src/core-init-tests.txt +++ /dev/null @@ -1,22 +0,0 @@ -## OPTIONS - -* `<path>`: - - The directory in which to download the testing suite files. (Optional) - -* `--dbname`=<dbname>: - - Set the database name. **WARNING**: The database will be whipped every time -you run the tests. - -* `--dbuser`=<dbuser>: - - Set the database user. - -* `--dbpass`=<dbpass>: - - Set the database user password. - -## EXAMPLE - - wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test diff --git a/man-src/core-install.txt b/man-src/core-install.txt deleted file mode 100644 index 711410e55..000000000 --- a/man-src/core-install.txt +++ /dev/null @@ -1,21 +0,0 @@ -## OPTIONS - -* `--url`=<url>: - - The address of the new site. - -* `--title`=<site-title>: - - The title of the new site. - -* `--admin_name`=<username>: - - The name of the admin user. Default: 'admin' - -* `--admin_password`=<password>: - - The password for the admin user. - -* `--admin_email`=<email>: - - The email address for the admin user. diff --git a/man-src/core-is-installed.txt b/man-src/core-is-installed.txt deleted file mode 100644 index afccd6c95..000000000 --- a/man-src/core-is-installed.txt +++ /dev/null @@ -1,5 +0,0 @@ -## EXAMPLES - - if ! $(wp core is-installed); then - wp core install - fi diff --git a/man-src/core-multisite-convert.txt b/man-src/core-multisite-convert.txt deleted file mode 100644 index 24494f117..000000000 --- a/man-src/core-multisite-convert.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* `--title`=<site-title>: - - The title of the new network. - -* `--base`=<url-path>: - - Base path after the domain name that each site url will start with. -Default: '/' - -* `--subdomains`: - - If passed, the network will use subdomains, instead of subdirectories. diff --git a/man-src/core-multisite-install.txt b/man-src/core-multisite-install.txt deleted file mode 100644 index eb9d7bd4d..000000000 --- a/man-src/core-multisite-install.txt +++ /dev/null @@ -1,30 +0,0 @@ -## OPTIONS - -* `--url`=<url>: - - The address of the new site. - -* `--base`=<url-path>: - - Base path after the domain name that each site url in the network will start with. -Default: '/' - -* `--subdomains`: - - If passed, the network will use subdomains, instead of subdirectories. - -* `--title`=<site-title>: - - The title of the new site. - -* `--admin_name`=<username>: - - The name of the admin user. Default: 'admin' - -* `--admin_password`=<password>: - - The password for the admin user. - -* `--admin_email`=<email>: - - The email address for the admin user. diff --git a/man-src/core-update-db.txt b/man-src/core-update-db.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/man-src/core-update.txt b/man-src/core-update.txt deleted file mode 100644 index 50caa5f2e..000000000 --- a/man-src/core-update.txt +++ /dev/null @@ -1,19 +0,0 @@ -## OPTIONS - -* `--version=`<new_version> [package/zip]: - - When passed, updates to new_version, optionally using package/zip as -input. - -* `--force`: - - Will update even when current WP version < passed version. Use with -caution. - -## EXAMPLES - - wp core update - - wp core update --version=3.4 ../latest.zip - - wp core update --version=3.1 --force diff --git a/man-src/core-version.txt b/man-src/core-version.txt deleted file mode 100644 index d1c5d6a6d..000000000 --- a/man-src/core-version.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `--extra`: - - Show extended version information. diff --git a/man-src/db.txt b/man-src/db.txt deleted file mode 100644 index d7ccfb703..000000000 --- a/man-src/db.txt +++ /dev/null @@ -1,18 +0,0 @@ -## OPTIONS - -* `--yes`: - - Answer yes to the confirmation message. - -* `<file>`: - - The name of the export file. If omitted, it will be '{dbname}.sql' - -* `<SQL>`: - - A SQL query. - -## EXAMPLES - - # execute a query stored in a file - wp db query < debug.sql diff --git a/man-src/eval-file.txt b/man-src/eval-file.txt deleted file mode 100644 index 57a808c10..000000000 --- a/man-src/eval-file.txt +++ /dev/null @@ -1,3 +0,0 @@ -## EXAMPLES - - wp eval-file my-code.php diff --git a/man-src/eval.txt b/man-src/eval.txt deleted file mode 100644 index 699b93f2e..000000000 --- a/man-src/eval.txt +++ /dev/null @@ -1,3 +0,0 @@ -## EXAMPLES - - wp eval 'echo WP_CONTENT_DIR;' diff --git a/man-src/export.txt b/man-src/export.txt deleted file mode 100644 index dcb8ea478..000000000 --- a/man-src/export.txt +++ /dev/null @@ -1,54 +0,0 @@ -## OPTIONS - -* `--dir`=<dirname>: - - Full path to directory where WXR export files should be stored. Defaults -to current working directory. - -* `--skip_comments`: - - Don't export comments. - -* `--file_item_count`=<count>: - - Break export into files with N posts. - -* `--verbose`: - - Show more information about the process on STDOUT. - -## FILTERS - -* `--start_date`=<date>: - - Export only posts newer than this date, in format YYYY-MM-DD. - -* `--end_date`=<date>: - - Export only posts older than this date, in format YYYY-MM-DD. - -* `--post_type`=<post_type>: - - Export only posts with this post_type. - -* `--post__in`=<pid>: - - Export all posts specified as a comma-separated list of IDs. - -* `--author`=<login/id>: - - Export only posts by this author. - -* `--category`=<category-id>: - - Export only posts in this category. - -* `--post_status`=<status>: - - Export only posts with this status. - -## EXAMPLES - - wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 - - wp export --dir=/tmp/ --post__in=123,124,125 diff --git a/man-src/help.txt b/man-src/help.txt deleted file mode 100644 index 19e660f7c..000000000 --- a/man-src/help.txt +++ /dev/null @@ -1,7 +0,0 @@ -## EXAMPLES - - # get help for `core` command - wp help core - - # get help for `core download` subcommand - wp help core download diff --git a/man-src/import.txt b/man-src/import.txt deleted file mode 100644 index 5f4e3dedf..000000000 --- a/man-src/import.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `<file>`: - - Path to a valid WXR file for importing. - -* `--authors=<authors>`: - - How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. - -* `--skip=<data-type>`: - - Skip importing specific data. Supported option is 'attachment'. diff --git a/man-src/media-import.txt b/man-src/media-import.txt deleted file mode 100644 index 5f7e7d1dc..000000000 --- a/man-src/media-import.txt +++ /dev/null @@ -1,45 +0,0 @@ -## OPTIONS - -* `<file>`: - - Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. - If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be - downloaded to a temp file before being sideloaded. - -* `--post_id=<post_id>` - - ID of the post to attach the imported files to - -* `--title=<title>` - - Attachment title (post title field) - -* `--caption=<caption>` - - Caption for attachent (post excerpt field) - -* `--alt=<alt_text>` - - Alt text for image (saved as post meta) - -* `--desc=<description>` - - "Description" field (post content) of attachment post - -* `--featured_image` - - If set, set the imported image as the Featured Image of the post its attached to. - - -## EXAMPLES - - # Import all jpgs in the current user's "Pictures" directory, not attached to any post - wp media import ~/Pictures/**/*.jpg - - # Import a local image and set it to be the post thumbnail for a post - wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image - - # Import an image from the web - wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" - - diff --git a/man-src/media-regenerate.txt b/man-src/media-regenerate.txt deleted file mode 100644 index f873f5349..000000000 --- a/man-src/media-regenerate.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `--yes`: - - Answer yes to the confirmation message. - -* `<attachment-id>`: - - One or more IDs of the attachments to regenerate. - -## EXAMPLES - - wp media regenerate 123 1337 - - wp media regenerate --yes \ No newline at end of file diff --git a/man-src/network-meta.txt b/man-src/network-meta.txt deleted file mode 100644 index c1899f2d4..000000000 --- a/man-src/network-meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* `<id>`: - - The network id (usually 1). - -* `--format=json`: - - Encode/decode values as JSON. - -## EXAMPLES - - # get a list of super-admins - wp network-meta get 1 site_admins diff --git a/man-src/option.txt b/man-src/option.txt deleted file mode 100644 index 99c8aab05..000000000 --- a/man-src/option.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `--format=json`: - - Encode/decode values as JSON. - -## EXAMPLES - - wp option get siteurl - - wp option add my_option foobar - - wp option update my_option '{"foo": "bar"}' --format=json - - wp option delete my_option diff --git a/man-src/plugin-activate.txt b/man-src/plugin-activate.txt deleted file mode 100644 index 555833891..000000000 --- a/man-src/plugin-activate.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<plugin>`: - - The plugin to activate. - -* `--network`: - - If set, the plugin will be activated for the entire multisite network. diff --git a/man-src/plugin-deactivate.txt b/man-src/plugin-deactivate.txt deleted file mode 100644 index 12be8084c..000000000 --- a/man-src/plugin-deactivate.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<plugin>`: - - The plugin to deactivate. - -* `--network`: - - If set, the plugin will be deactivated for the entire multisite network. diff --git a/man-src/plugin-delete.txt b/man-src/plugin-delete.txt deleted file mode 100644 index 111865f59..000000000 --- a/man-src/plugin-delete.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* <plugin>: - - The plugin to delete. - -## EXAMPLES - - wp plugin delete hello diff --git a/man-src/plugin-install.txt b/man-src/plugin-install.txt deleted file mode 100644 index e896cca2f..000000000 --- a/man-src/plugin-install.txt +++ /dev/null @@ -1,33 +0,0 @@ -## OPTIONS - -* <plugin|zip|url>: - - A plugin slug, the path to a local zip file, or URL to a remote zip file. - -* `--version`=<version>: - - If set, get that particular version from wordpress.org, instead of the -stable version. - -* `--force`: - - If set, the command will overwrite any installed version of the plugin, without prompting -for confirmation. - -* `--activate`: - - If set, the plugin will be activated immediately after install. - -## EXAMPLES - - # Install the latest version from wordpress.org and activate - wp plugin install bbpress --activate - - # Install the development version from wordpress.org - wp plugin install bbpress --version=dev - - # Install from a local zip file - wp plugin install ../my-plugin.zip - - # Install from a remote zip file - wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef diff --git a/man-src/plugin-list.txt b/man-src/plugin-list.txt deleted file mode 100644 index 8d2344d88..000000000 --- a/man-src/plugin-list.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--format`=<format>: - - Output list as table, CSV or JSON. Defaults to table. - -## EXAMPLES - - wp plugin list --format=json diff --git a/man-src/plugin-path.txt b/man-src/plugin-path.txt deleted file mode 100644 index a190a7702..000000000 --- a/man-src/plugin-path.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `<plugin>`: - - The plugin to get the path to. If not set, will return the path to the -plugins directory. - -* `--dir`: - - If set, get the path to the closest parent directory, instead of the -plugin file. - -## EXAMPLES - - cd $(wp theme path) diff --git a/man-src/plugin-status.txt b/man-src/plugin-status.txt deleted file mode 100644 index 6902ac270..000000000 --- a/man-src/plugin-status.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `<plugin>`: - - A particular plugin to show the status for. \ No newline at end of file diff --git a/man-src/plugin-toggle.txt b/man-src/plugin-toggle.txt deleted file mode 100644 index 97e284aed..000000000 --- a/man-src/plugin-toggle.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<plugin>`: - - The plugin to toggle. - -* `--network`: - - If set, the plugin will be toggled for the entire multisite network. diff --git a/man-src/plugin-uninstall.txt b/man-src/plugin-uninstall.txt deleted file mode 100644 index ea41bcbf1..000000000 --- a/man-src/plugin-uninstall.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* <plugin>: - - The plugin to uninstall. - -* `--no-delete`: - - If set, the plugin files will not be deleted. Only the uninstall procedure -will be run. - -## EXAMPLES - - wp plugin uninstall hello diff --git a/man-src/plugin-update-all.txt b/man-src/plugin-update-all.txt deleted file mode 100644 index 8ba4aaa51..000000000 --- a/man-src/plugin-update-all.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--dry-run`: - - Pretend to do the updates, to see what would happen. - -## EXAMPLES - - wp plugin update-all diff --git a/man-src/plugin-update.txt b/man-src/plugin-update.txt deleted file mode 100644 index 563c30373..000000000 --- a/man-src/plugin-update.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* <plugin>: - - The plugin to update. - -* `--version=dev`: - - If set, the plugin will be updated to the latest development version, -regardless of what version is currently installed. - -## EXAMPLES - - wp plugin update bbpress --version=dev diff --git a/man-src/post-create.txt b/man-src/post-create.txt deleted file mode 100644 index 770713c9c..000000000 --- a/man-src/post-create.txt +++ /dev/null @@ -1,31 +0,0 @@ -## OPTIONS - -* `<filename>`: - - Read post content from <filename>. If this value is present, the - `--post_content` argument will be ignored. - - Passing `-` as the filename will cause post content to - be read from STDIN. - -* `--<field>`=<value>: - - Field values for the new post. See wp_insert_post(). - -* `--edit`: - - Immediately open system's editor to write or edit post content. - - (If content is read from a file, from STDIN, or from the `--post_content` - argument, that text will be loaded into the editor; otherwise, an empty - file will be opened.) - -* `--porcelain`: - - Output just the new post id. - -## EXAMPLES - - wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' - - wp post create page.txt --post_type=page --post_title='Page from file' diff --git a/man-src/post-delete.txt b/man-src/post-delete.txt deleted file mode 100644 index d2a614bd8..000000000 --- a/man-src/post-delete.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the post to delete. - -* `--force`: - - Skip the trash bin. - -## EXAMPLES - - wp post delete 123 --force - - wp post delete $(wp post list --post_type='page' --format=ids) diff --git a/man-src/post-edit.txt b/man-src/post-edit.txt deleted file mode 100644 index 6e3607984..000000000 --- a/man-src/post-edit.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<id>`: - - The ID of the post to edit. - -## EXAMPLES - - wp post edit 123 diff --git a/man-src/post-generate.txt b/man-src/post-generate.txt deleted file mode 100644 index 7dba04a6f..000000000 --- a/man-src/post-generate.txt +++ /dev/null @@ -1,29 +0,0 @@ -## OPTIONS - -* `--count`=<number>: - - How many posts to generate. Default: 100 - -* `--post_type`=<type>: - - The type of the generated posts. Default: 'post' - -* `--post_status`=<status>: - - The status of the generated posts. Default: 'publish' - -* `--post_author`=<login>: - - The author of the generated posts. Default: none - -* `--post_date`=<yyyy-mm-dd>: - - The date of the generated posts. Default: current date - -* `--max_depth`=<number>: - - For hierarchical post types, generate child posts down to a certain depth. Default: 1 - -## EXAMPLES - - wp post generate --count=10 --post_type=page --post_date=1999-01-04 diff --git a/man-src/post-get.txt b/man-src/post-get.txt deleted file mode 100644 index 9b79b9ce9..000000000 --- a/man-src/post-get.txt +++ /dev/null @@ -1,22 +0,0 @@ -## OPTIONS - -* `[--format=<format>]`: - - The format to use when printing the post, acceptable values: - - **content**: Outputs only the post's content. - - **table**: Outputs all fields of the post as a table. Note that the - post_content field is omitted so that the table is readable. - - **json**: Outputs all fields in JSON format. - -* `<id>`: - - The ID of the post to get. - -## EXAMPLES - - wp post get 12 --format=content - - wp post get 12 > file.txt diff --git a/man-src/post-list.txt b/man-src/post-list.txt deleted file mode 100644 index 098d41c74..000000000 --- a/man-src/post-list.txt +++ /dev/null @@ -1,21 +0,0 @@ -## OPTIONS - -* `--<field>`=<value>: - - One or more args to pass to WP_Query. - -* `--fields`=<fields>: - - Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. - -* `--format`=<format>: - - Output list as table, CSV, JSON, or simply IDs. Defaults to table. - -## EXAMPLES - - wp post list --format=ids - - wp post list --post_type=post --posts_per_page=5 --format=json - - wp post list --post_type=page --fields=post_title,post_status diff --git a/man-src/post-meta.txt b/man-src/post-meta.txt deleted file mode 100644 index eeadc606f..000000000 --- a/man-src/post-meta.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--format=json`: - - Encode/decode values as JSON. - -## EXAMPLES - - wp post-meta set 123 _wp_page_template about.php diff --git a/man-src/post-update.txt b/man-src/post-update.txt deleted file mode 100644 index 0fd825e24..000000000 --- a/man-src/post-update.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `<ID>`: - - The ID of the post to update. - -* `--<field>`=<value>: - - One or more fields to update. See wp_update_post(). - -## EXAMPLES - - wp post update 123 --post_name=something --post_status=draft diff --git a/man-src/rewrite-dump.txt b/man-src/rewrite-dump.txt deleted file mode 100644 index f15473d02..000000000 --- a/man-src/rewrite-dump.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `--format=json`: - - Output rules in JSON format. diff --git a/man-src/rewrite-flush.txt b/man-src/rewrite-flush.txt deleted file mode 100644 index 60ae94af8..000000000 --- a/man-src/rewrite-flush.txt +++ /dev/null @@ -1,7 +0,0 @@ -## OPTIONS - -* `--soft`: - - Perform a soft flush - do not overwrite `.htaccess`. The default is to update - `.htaccess` rules as well as rewrite rules in database. - diff --git a/man-src/rewrite-structure.txt b/man-src/rewrite-structure.txt deleted file mode 100644 index 9dec9d860..000000000 --- a/man-src/rewrite-structure.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* <permastruct>: - - The new permalink structure to apply; like "/%year%/%monthnum%/%postname%". - -* `--category-base`=<categorybase>: - - Set the base for category permalinks, ie '/category/'. - -* `--tag-base`=<tagbase>: - - Set the base for tag permalinks, ie '/tag/'. - diff --git a/man-src/role-create.txt b/man-src/role-create.txt deleted file mode 100644 index dde7db553..000000000 --- a/man-src/role-create.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* <role-key>: - - The internal name of the role, e.g. editor - -* <role-name>: - - The publically visible name of the role, e.g. Editor - -## EXAMPLES - - wp role create approver Approver - - wp role create productadmin "Product Administrator" diff --git a/man-src/role-delete.txt b/man-src/role-delete.txt deleted file mode 100644 index f8519240d..000000000 --- a/man-src/role-delete.txt +++ /dev/null @@ -1,12 +0,0 @@ -## OPTIONS - -* <role-key>: - - The internal name of the role, e.g. editor - -## EXAMPLES - - wp role delete approver - - wp role delete productadmin - diff --git a/man-src/role-exists.txt b/man-src/role-exists.txt deleted file mode 100644 index 28a8ee0a5..000000000 --- a/man-src/role-exists.txt +++ /dev/null @@ -1,16 +0,0 @@ -## OPTIONS - -* <role-key>: - - The internal name of the role, e.g. editor - - -##DESCRIPTION - -Will exit with status 0 if the role exists, 1 if it does not. - - -## EXAMPLES - - wp role exists editor - diff --git a/man-src/role-list.txt b/man-src/role-list.txt deleted file mode 100644 index 2b7940161..000000000 --- a/man-src/role-list.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `--fields`=<fields>: - - Limit the output to specific object fields. Defaults to name,role. - -* `--format`=<format>: - - Output list as table, CSV or JSON. Defaults to table. - -## EXAMPLES - - wp role list --fields=role --format=csv diff --git a/man-src/scaffold-_s.txt b/man-src/scaffold-_s.txt deleted file mode 100644 index 82c57a8ab..000000000 --- a/man-src/scaffold-_s.txt +++ /dev/null @@ -1,21 +0,0 @@ -## OPTIONS - -* <slug>: - - The slug for the new theme, used for prefixing functions. - -* `--activate`: - - Activate the newly downloaded theme. - -* `--theme_name=<title>`: - - What to put in the 'Theme Name:' header in style.css - -* `--author=<full name>`: - - What to put in the 'Author:' header in style.css - -* `--author_uri=<http url>`: - - What to put in the 'Author URI:' header in style.css \ No newline at end of file diff --git a/man-src/scaffold-child-theme.txt b/man-src/scaffold-child-theme.txt deleted file mode 100644 index 2f05ab25f..000000000 --- a/man-src/scaffold-child-theme.txt +++ /dev/null @@ -1,29 +0,0 @@ -## OPTIONS - -* <slug>: - - The slug for the new child theme. - -* `--parent_theme=<slug>`: - - What to put in the 'Template:' header in style.css - -* `--theme_name=<title>`: - - What to put in the 'Theme Name:' header in style.css - -* `--author=<full name>`: - - What to put in the 'Author:' header in style.css - -* `--author_uri=<http url>`: - - What to put in the 'Author URI:' header in style.css - -* `--theme_uri=<http url>`: - - What to put in the 'Theme URI:' header in style.css - -* `--activate`: - - Activate the newly created child theme. diff --git a/man-src/scaffold-plugin-tests.txt b/man-src/scaffold-plugin-tests.txt deleted file mode 100644 index 7224977bd..000000000 --- a/man-src/scaffold-plugin-tests.txt +++ /dev/null @@ -1,17 +0,0 @@ -## DESCRIPTION - -These are the files that are generated: - -* `phpunit.xml` is the configuration file for PHPUnit -* `.travis.yml` is the configuration file for Travis CI -* `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite -* `tests/test-sample.php` is a sample file containing the actual tests - -## ENVIRONMENT - -The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment -variable. - -## EXAMPLE - - wp scaffold plugin-tests hello diff --git a/man-src/scaffold-plugin.txt b/man-src/scaffold-plugin.txt deleted file mode 100644 index bea18ef97..000000000 --- a/man-src/scaffold-plugin.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--activate`: - - Activate the newly generated plugin. - -* `--plugin_name=<title>`: - - What to put in the 'Plugin Name:' header diff --git a/man-src/scaffold-post-type.txt b/man-src/scaffold-post-type.txt deleted file mode 100644 index e164c1f3b..000000000 --- a/man-src/scaffold-post-type.txt +++ /dev/null @@ -1,23 +0,0 @@ -## OPTIONS - -* `--label=<label>`: - - The text used to translate the update messages - -* `--textdomain=<textdomain>`: - - The textdomain to use for the labels. - -* `--theme`: - - Create a file in the active theme directory, instead of sending to -STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. - -* `--plugin=<plugin>`: - - Create a file in the given plugin's directory, instead of sending to -STDOUT. - -* `--raw`: - - Just generate the `register_post_type()` call and nothing else. diff --git a/man-src/scaffold-taxonomy.txt b/man-src/scaffold-taxonomy.txt deleted file mode 100644 index 1015bf54c..000000000 --- a/man-src/scaffold-taxonomy.txt +++ /dev/null @@ -1,31 +0,0 @@ -## OPTIONS - -* `--post_types=<post_types>`: - - Post types to register for use with the taxonomy. - -* `--label=<label>`: - - The text used to translate the update messages - -* `--textdomain=<textdomain>`: - - The textdomain to use for the labels. - -* `--theme`: - - Create a file in the active theme directory, instead of sending to -STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. - -* `--plugin=<plugin>`: - - Create a file in the given plugin's directory, instead of sending to -STDOUT. - -* `--raw`: - - Just generate the `register_taxonomy()` call and nothing else. - -## EXAMPLES - - wp scaffold taxonomy venue --post_types=event,presentation diff --git a/man-src/search-replace.txt b/man-src/search-replace.txt deleted file mode 100644 index 812dfcc97..000000000 --- a/man-src/search-replace.txt +++ /dev/null @@ -1,25 +0,0 @@ -## DESCRIPTION - -This command will go through all rows in all tables and will replace all appearances of the old string with the new one. - -It will correctly handle serialized values, and will not change primary key values. - -## OPTIONS - -* `--network`: - - Search/replace through all the tables in a multisite install. - -* `--skip-columns=<columns>`: - - Do not perform the replacement in the comma-separated columns. - -* `--dry-run`: - - Show report, but don't perform the changes. - -## EXAMPLES - - wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid - - wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run diff --git a/man-src/shell.txt b/man-src/shell.txt deleted file mode 100644 index 7dd583a28..000000000 --- a/man-src/shell.txt +++ /dev/null @@ -1,9 +0,0 @@ -## DESCRIPTION - -`wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. - -## OPTIONS - -* `--basic`: - - Start in fail-safe mode, even if Boris is available. diff --git a/man-src/site-create.txt b/man-src/site-create.txt deleted file mode 100644 index 84c3df985..000000000 --- a/man-src/site-create.txt +++ /dev/null @@ -1,25 +0,0 @@ -## OPTIONS - -* `--slug`=<slug>: - - Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. - -* `--title`=<title>: - - Title of the new site. Default: prettified slug. - -* `--email`=<email>: - - Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. - -* `--network_id`=<network-id>: - - Network to associate new site with. Defaults to current network (typically 1). - -* `--private`: - - If set, the new site will be non-public (not indexed) - -* `--porcelain`: - - If set, only the site id will be output on success. diff --git a/man-src/site-delete.txt b/man-src/site-delete.txt deleted file mode 100644 index f119826b9..000000000 --- a/man-src/site-delete.txt +++ /dev/null @@ -1,17 +0,0 @@ -## OPTIONS - -* `<blog-id>`: - - The id of the blog to delete. If not provided, you must set the --slug parameter. - -* `--slug`=<slug>: - - Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. - -* `--yes`: - - Answer yes to the confirmation message. - -* `--keep-tables`: - - Delete the blog from the list, but don't drop it's tables. diff --git a/man-src/site-empty.txt b/man-src/site-empty.txt deleted file mode 100644 index bbb41c593..000000000 --- a/man-src/site-empty.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `--yes`: - - Proceed to empty the site without a confirmation prompt. \ No newline at end of file diff --git a/man-src/term-create.txt b/man-src/term-create.txt deleted file mode 100644 index 46b85b9f0..000000000 --- a/man-src/term-create.txt +++ /dev/null @@ -1,29 +0,0 @@ -## OPTIONS - -* `<term>`: - - A name for the new term. - -* `<taxonomy>`: - - Taxonomy for the new term. - -* `--slug`=<slug>: - - A unique slug for the new term. Defaults to sanitized version of name. - -* `--description`=<description>: - - A description for the new term. - -* `--parent`=<term-id>: - - A parent for the new term. - -* `--porcelain`: - - Output just the new term id. - -## EXAMPLES - - wp term create Apple category --description="A type of fruit" diff --git a/man-src/term-delete.txt b/man-src/term-delete.txt deleted file mode 100644 index 03f23097d..000000000 --- a/man-src/term-delete.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `<term-id>`: - - ID for the term to delete. - -* `<taxonomy>`: - - Taxonomy of the term to delete. - -## EXAMPLES - - wp term delete 15 category \ No newline at end of file diff --git a/man-src/term-list.txt b/man-src/term-list.txt deleted file mode 100644 index 18cd0a4ed..000000000 --- a/man-src/term-list.txt +++ /dev/null @@ -1,19 +0,0 @@ -## OPTIONS - -* `<taxonomy>`: - - List terms of a given taxonomy. - -* `--fields`=<fields>: - - Limit the output to specific object fields. Defaults to all of the term object fields. - -* `--format`=<format>: - - Output list as table, CSV, JSON, or simply IDs. Defaults to table. - -## EXAMPLES - - wp term list category --format=csv - - wp term list post_tag --fields=name,slug diff --git a/man-src/term-update.txt b/man-src/term-update.txt deleted file mode 100644 index cc6bc6cf9..000000000 --- a/man-src/term-update.txt +++ /dev/null @@ -1,29 +0,0 @@ -## OPTIONS - -* `<term-id>`: - - ID for the term to update. - -* `<taxonomy>`: - - Taxonomy of the term to update. - -* `--name`=<name>: - - A new name for the term. - -* `--slug`=<slug>: - - A new slug for the term. - -* `--description`=<description>: - - A new description for the term. - -* `--parent`=<term-id>: - - A new parent for the term. - -## EXAMPLES - - wp term update 15 category --name=Apple diff --git a/man-src/theme-activate.txt b/man-src/theme-activate.txt deleted file mode 100644 index c74047240..000000000 --- a/man-src/theme-activate.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `<theme>`: - - The theme to activate. diff --git a/man-src/theme-delete.txt b/man-src/theme-delete.txt deleted file mode 100644 index 030f781e4..000000000 --- a/man-src/theme-delete.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `<theme>`: - - The theme to delete. - -## EXAMPLES - - wp theme delete twentyeleven diff --git a/man-src/theme-install.txt b/man-src/theme-install.txt deleted file mode 100644 index b8eced70c..000000000 --- a/man-src/theme-install.txt +++ /dev/null @@ -1,25 +0,0 @@ -## OPTIONS - -* `<theme|zip|url>`: - - A theme slug, the path to a local zip file, or URL to a remote zip file. - -* `--force`: - - If set, the command will overwrite any installed version of the theme, without prompting -for confirmation. - -* `--activate`: - - If set, the theme will be activated immediately after install. - -## EXAMPLES - - # Install the latest version from wordpress.org and activate - wp theme install twentytwelve --activate - - # Install from a local zip file - wp theme install ../my-theme.zip - - # Install from a remote zip file - wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef diff --git a/man-src/theme-list.txt b/man-src/theme-list.txt deleted file mode 100644 index b875caeed..000000000 --- a/man-src/theme-list.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--format`=<format>: - - Output list as table, CSV or JSON. Defaults to table. - -## EXAMPLES - - wp theme list --format=csv diff --git a/man-src/theme-path.txt b/man-src/theme-path.txt deleted file mode 100644 index d54cec5b1..000000000 --- a/man-src/theme-path.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `<theme>`: - - The theme to get the path to. If not set, will return the path to the -themes directory. - -* `--dir`: - - If set, get the path to the closest parent directory, instead of the -theme file. - -## EXAMPLES - - cd $(wp theme path) diff --git a/man-src/theme-status.txt b/man-src/theme-status.txt deleted file mode 100644 index f4aa71335..000000000 --- a/man-src/theme-status.txt +++ /dev/null @@ -1,5 +0,0 @@ -## OPTIONS - -* `<theme>`: - - A particular theme to show the status for. diff --git a/man-src/theme-update-all.txt b/man-src/theme-update-all.txt deleted file mode 100644 index 5d24e29a5..000000000 --- a/man-src/theme-update-all.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--dry-run`: - - Pretend to do the updates, to see what would happen. - -## EXAMPLES - - wp theme update-all diff --git a/man-src/theme-update.txt b/man-src/theme-update.txt deleted file mode 100644 index b7e610940..000000000 --- a/man-src/theme-update.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* `<theme>`: - - The theme to update. - -* `--version=dev`: - - If set, the theme will be updated to the latest development version, -regardless of what version is currently installed. - -## EXAMPLES - - wp theme update twentytwelve diff --git a/man-src/transient.txt b/man-src/transient.txt deleted file mode 100644 index 64dcebe0f..000000000 --- a/man-src/transient.txt +++ /dev/null @@ -1,3 +0,0 @@ -## EXAMPLES - - wp transient set my_key my_value 300 diff --git a/man-src/user-add-role.txt b/man-src/user-add-role.txt deleted file mode 100644 index b6e5ab482..000000000 --- a/man-src/user-add-role.txt +++ /dev/null @@ -1,14 +0,0 @@ -## OPTIONS - -* `<user>`: - - User ID or user login. - -* `<role>`: - - Add the specified role to the user. - -## EXAMPLES - - wp user set-role bob author - wp user set-role 12 author diff --git a/man-src/user-create.txt b/man-src/user-create.txt deleted file mode 100644 index 8b860096b..000000000 --- a/man-src/user-create.txt +++ /dev/null @@ -1,33 +0,0 @@ -## OPTIONS - -* `<user-login>`: - - The login of the user to create. - -* `<user-email>`: - - The email address of the user to create. - -* `--role`=<role>: - - The role of the user to create. Default: default role - -* `--user_pass`=<password>: - - The user password. Default: randomly generated - -* `--user_registered`=<yyyy-mm-dd>: - - The date the user registered. Default: current date - -* `--display_name`=<name>: - - The display name. - -* `--porcelain`: - - Output just the new user id. - -## EXAMPLES - - wp user create bob bob@example.com --role=author diff --git a/man-src/user-delete.txt b/man-src/user-delete.txt deleted file mode 100644 index 88d8966a1..000000000 --- a/man-src/user-delete.txt +++ /dev/null @@ -1,13 +0,0 @@ -## OPTIONS - -* `<user>`: - - The user login or ID of the user to delete. - -* `--reassign`=<ID>: - - User to reassign the posts to. - -## EXAMPLES - - wp user delete 123 --reassign=567 diff --git a/man-src/user-generate.txt b/man-src/user-generate.txt deleted file mode 100644 index a2467abf0..000000000 --- a/man-src/user-generate.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--count`=<number>: - - How many users to generate. Default: 100 - -* `--role`=<role>: - - The role of the generated users. Default: default role from WP diff --git a/man-src/user-get.txt b/man-src/user-get.txt deleted file mode 100644 index 9493599ef..000000000 --- a/man-src/user-get.txt +++ /dev/null @@ -1,19 +0,0 @@ -## OPTIONS - -* `[--format=<format>]`: - - The format to use when printing the user; acceptable values: - - **table**: Outputs all fields of the user as a table. - - **json**: Outputs all fields in JSON format. - -* `<user>`: - - User ID or user login. - -## EXAMPLES - - wp user get 12 - - wp user get bob --format=json > bob.json diff --git a/man-src/user-import-csv.txt b/man-src/user-import-csv.txt deleted file mode 100644 index e8963372a..000000000 --- a/man-src/user-import-csv.txt +++ /dev/null @@ -1,16 +0,0 @@ -## OPTIONS - -* `<file>`: - - The CSV file of users to import. - -## EXAMPLES - - wp user import-csv /path/to/users.csv - - Sample users.csv file: - - user_login,user_email,display_name,role - bobjones,bobjones@domain.com,Bob Jones,contributor - newuser1,newuser1@domain.com,New User,author - existinguser,existinguser@domain.com,Existing User,administrator diff --git a/man-src/user-list.txt b/man-src/user-list.txt deleted file mode 100644 index 0aa7951da..000000000 --- a/man-src/user-list.txt +++ /dev/null @@ -1,21 +0,0 @@ -## OPTIONS - -* `--role`=<role>: - - Only display users with a certain role. - -* `--fields`=<fields>: - - Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles - -* `--format`=<format>: - - Output list as table, CSV, JSON, or simply IDs. Defaults to table. - -## EXAMPLES - - wp user list --format=ids - - wp user list --role=administrator --format=csv - - wp user list --fields=display_name,user_email diff --git a/man-src/user-meta.txt b/man-src/user-meta.txt deleted file mode 100644 index 94d507cc5..000000000 --- a/man-src/user-meta.txt +++ /dev/null @@ -1,9 +0,0 @@ -## OPTIONS - -* `--format=json`: - - Encode/decode values as JSON. - -## EXAMPLES - - wp user-meta set 123 description "Mary is a WordPress developer." diff --git a/man-src/user-remove-role.txt b/man-src/user-remove-role.txt deleted file mode 100644 index b4a77e47d..000000000 --- a/man-src/user-remove-role.txt +++ /dev/null @@ -1,10 +0,0 @@ -## OPTIONS - -* `<user>`: - - User ID or user login. - -## EXAMPLES - - wp user remove-role bob - wp user remove-role 12 diff --git a/man-src/user-set-role.txt b/man-src/user-set-role.txt deleted file mode 100644 index 4817f740d..000000000 --- a/man-src/user-set-role.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `<user>`: - - User ID or user login. - -* `[<role>]`: - - Make the user have the specified role. If not passed, the default role is -used. - -## EXAMPLES - - wp user set-role bob author - wp user set-role 12 author diff --git a/man-src/user-update.txt b/man-src/user-update.txt deleted file mode 100644 index 092ab8b59..000000000 --- a/man-src/user-update.txt +++ /dev/null @@ -1,15 +0,0 @@ -## OPTIONS - -* `<user>`: - - The user login or ID of the user to update. - -* `--<field>`=<value>: - - One or more fields to update. For accepted fields, see wp_update_user(). - -## EXAMPLES - - wp user update 123 --user_login=mary --display_name=Mary - - wp user update mary --user_pass=marypass diff --git a/php/commands/cache.php b/php/commands/cache.php index 4516e7e16..e522c4be5 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -3,7 +3,11 @@ /** * Manage the object cache. * - * @package wp-cli + * ## EXAMPLES + * + * wp cache set my_key my_value my_group 300 + * + * wp cache get my_key my_group */ class Cache_Command extends WP_CLI_Command { diff --git a/php/commands/cap.php b/php/commands/cap.php index 31004285c..97d84113c 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -3,7 +3,16 @@ /** * Manage user capabilities. * - * @package wp-cli + * ## EXAMPLES + * + * # Add 'spectate' capability to 'author' role + * wp cap add 'author' 'spectate' + * + * # Add all caps from 'editor' role to 'author' role + * wp cap list 'editor' | xargs wp cap add 'author' + * + * # Remove all caps from 'editor' role that also appear in 'author' role + * wp cap list 'author' | xargs wp cap remove 'editor' */ class Capabilities_Command extends WP_CLI_Command { diff --git a/php/commands/comment.php b/php/commands/comment.php index dd5442cda..179b08a6d 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -10,6 +10,18 @@ class Comment_Command extends WP_CLI_Command { /** * Insert a comment. * + * ## OPTIONS + * + * --<field>=<value> + * : Field values for the new comment. See wp_insert_comment(). + * + * --porcelain + * : Output just the new comment id. + * + * ## EXAMPLES + * + * wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" + * * @synopsis --<field>=<value> [--porcelain] */ public function create( $args, $assoc_args ) { @@ -34,6 +46,18 @@ public function create( $args, $assoc_args ) { /** * Delete a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to delete. + * + * --force + * : Skip the trash bin. + * + * ## EXAMPLES + * + * wp comment delete 1337 --force + * * @synopsis <id> [--force] */ public function delete( $args, $assoc_args ) { @@ -73,6 +97,15 @@ private function set_status( $args, $status, $success ) { /** * Trash a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to trash. + * + * ## EXAMPLES + * + * wp comment trash 1337 + * * @synopsis <id> */ public function trash( $args, $assoc_args ) { @@ -82,6 +115,15 @@ public function trash( $args, $assoc_args ) { /** * Untrash a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to untrash. + * + * ## EXAMPLES + * + * wp comment untrash 1337 + * * @synopsis <id> */ public function untrash( $args, $assoc_args ) { @@ -91,6 +133,15 @@ public function untrash( $args, $assoc_args ) { /** * Spam a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to mark as spam. + * + * ## EXAMPLES + * + * wp comment spam 1337 + * * @synopsis <id> */ public function spam( $args, $assoc_args ) { @@ -100,6 +151,14 @@ public function spam( $args, $assoc_args ) { /** * Unspam a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to unmark as spam. + * + * ## EXAMPLES + * + * wp comment unspam 1337 * @synopsis <id> */ public function unspam( $args, $assoc_args ) { @@ -109,6 +168,15 @@ public function unspam( $args, $assoc_args ) { /** * Approve a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to approve. + * + * ## EXAMPLES + * + * wp comment approve 1337 + * * @synopsis <id> */ public function approve( $args, $assoc_args ) { @@ -118,6 +186,15 @@ public function approve( $args, $assoc_args ) { /** * Unapprove a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to unapprove. + * + * ## EXAMPLES + * + * wp comment unapprove 1337 + * * @synopsis <id> */ public function unapprove( $args, $assoc_args ) { @@ -127,6 +204,16 @@ public function unapprove( $args, $assoc_args ) { /** * Count comments, on whole blog or on a given post. * + * ## OPTIONS + * + * <ID> + * : The ID of the post to count comments in + * + * ## EXAMPLES + * + * wp comment count + * wp comment count 42 + * * @synopsis [<post-id>] */ public function count( $args, $assoc_args ) { @@ -147,6 +234,15 @@ public function count( $args, $assoc_args ) { /** * Get status of a comment. * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to check + * + * ## EXAMPLES + * + * wp comment status 1337 + * * @synopsis <id> */ public function status( $args, $assoc_args ) { @@ -164,6 +260,18 @@ public function status( $args, $assoc_args ) { /** * Get last approved comment. * + * ## OPTIONS + * + * --id + * : Output just the last comment id. + * + * --full + * : Output complete comment information. + * + * ## EXAMPLES + * + * wp comment last --full + * * @synopsis [--id] [--full] */ function last( $args = array(), $assoc_args = array() ) { diff --git a/php/commands/core.php b/php/commands/core.php index eaa290130..5d21f820d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -12,6 +12,22 @@ class Core_Command extends WP_CLI_Command { /** * Download core WordPress files. * + * ## OPTIONS + * + * --locale=<locale> + * : Select which language you want to download. The --version parameter is + * ignored in this case. + * + * --version=<version> + * : Select which version you want to download. + * + * --force + * : Overwrites existing files, if present. + * + * ## EXAMPLES + * + * wp core download --version=3.3 + * * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] [--force] * * @when before_wp_load @@ -75,6 +91,40 @@ private static function get_initial_locale() { /** * Set up a wp-config.php file. * + * ## OPTIONS + * + * --dbname=<dbname> + * : Set the database name. + * + * --dbuser=<dbuser> + * : Set the database user. + * + * --dbpass=<dbpass> + * : Set the database user password. + * + * --dbhost=<dbhost> + * : Set the database host. Default: 'localhost' + * + * --dbprefix=<dbprefix> + * : Set the database table prefix. Default: 'wp_' + * + * --locale=<locale> + * : Set the WPLANG constant. Defaults to $wp_local_package variable. + * + * --extra-php + * : If set, the command reads additional PHP code from STDIN. + * + * ## EXAMPLES + * + * # Standard wp-config.php file + * wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO + * + * # Enable WP_DEBUG and WP_DEBUG_LOG + * wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP + * define( 'WP_DEBUG', true ); + * define( 'WP_DEBUG_LOG', true ); + * PHP + * * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] */ public function config( $_, $assoc_args ) { @@ -118,6 +168,12 @@ public function config( $_, $assoc_args ) { /** * Determine if the WordPress tables are installed. * + * ## EXAMPLES + * + * if ! $(wp core is-installed); then + * wp core install + * fi + * * @subcommand is-installed */ public function is_installed() { @@ -131,6 +187,23 @@ public function is_installed() { /** * Create the WordPress tables in the database. * + * ## OPTIONS + * + * --url=<url> + * : The address of the new site. + * + * --title=<site-title> + * : The title of the new site. + * + * --admin_name=<username> + * : The name of the admin user. Default: 'admin' + * + * --admin_password=<password> + * : The password for the admin user. + * + * --admin_email=<email> + * : The email address for the admin user. + * * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { @@ -144,6 +217,18 @@ public function install( $args, $assoc_args ) { /** * Transform a single-site install into a multi-site install. * + * ## OPTIONS + * + * --title=<site-title> + * : The title of the new network. + * + * --base=<url-path> + * : Base path after the domain name that each site url will start with. + * Default: '/' + * + * --subdomains + * : If passed, the network will use subdomains, instead of subdirectories. + * * @subcommand multisite-convert * @alias install-network * @synopsis [--title=<network-title>] [--base=<url-path>] [--subdomains] @@ -165,6 +250,30 @@ public function multisite_convert( $args, $assoc_args ) { /** * Install multisite from scratch. * + * ## OPTIONS + * + * --url=<url> + * : The address of the new site. + * + * --base=<url-path> + * : Base path after the domain name that each site url in the network will start with. + * Default: '/' + * + * --subdomains + * : If passed, the network will use subdomains, instead of subdirectories. + * + * --title=<site-title> + * : The title of the new site. + * + * --admin_name=<username> + * : The name of the admin user. Default: 'admin' + * + * --admin_password=<password> + * : The password for the admin user. + * + * --admin_email=<email> + * : The email address for the admin user. + * * @subcommand multisite-install * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] [--admin_name=<username>] --admin_email=<email> --admin_password=<password> */ @@ -374,6 +483,11 @@ private static function get_clean_basedomain() { /** * Display the WordPress version. * + * ## OPTIONS + * + * --extra + * : Show extended version information. + * * @synopsis [--extra] */ public function version( $args = array(), $assoc_args = array() ) { @@ -399,6 +513,24 @@ public function version( $args = array(), $assoc_args = array() ) { /** * Update WordPress. * + * ## OPTIONS + * + * --version=<new_version> [package/zip] + * : When passed, updates to new_version, optionally using package/zip as + * input. + * + * --force + * : Will update even when current WP version < passed version. Use with + * caution. + * + * ## EXAMPLES + * + * wp core update + * + * wp core update --version=3.4 ../latest.zip + * + * wp core update --version=3.1 --force + * * @alias upgrade * * @synopsis [<zip>] [--version=<version>] [--force] @@ -480,6 +612,25 @@ function update_db() { * * @subcommand init-tests * + * ## OPTIONS + * + * <path> + * : The directory in which to download the testing suite files. (Optional) + * + * --dbname=<dbname> + * : Set the database name. **WARNING**: The database will be whipped every time + * you run the tests. + * + * --dbuser=<dbuser> + * : Set the database user. + * + * --dbpass=<dbpass> + * : Set the database user password. + * + * ## EXAMPLE + * + * wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test + * * @synopsis [<path>] --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] */ function init_tests( $args, $assoc_args ) { diff --git a/php/commands/db.php b/php/commands/db.php index 662306d5f..66ed93d50 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -5,7 +5,21 @@ /** * Perform basic database operations. * - * @package wp-cli + * ## OPTIONS + * + * --yes + * : Answer yes to the confirmation message. + * + * <file> + * : The name of the export file. If omitted, it will be '{dbname}.sql' + * + * <SQL> + * : A SQL query. + * + * ## EXAMPLES + * + * # execute a query stored in a file + * wp db query < debug.sql */ class DB_Command extends WP_CLI_Command { diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index e1c60b9ef..330c384dd 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -5,6 +5,10 @@ class EvalFile_Command extends WP_CLI_Command { /** * Load and execute a PHP file after loading WordPress. * + * ## EXAMPLES + * + * wp eval-file my-code.php + * * @synopsis <path> */ public function __invoke( $args, $assoc_args ) { diff --git a/php/commands/eval.php b/php/commands/eval.php index 02b97c6a9..782752b76 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -5,6 +5,10 @@ class Eval_Command extends WP_CLI_Command { /** * Execute arbitrary PHP code after loading WordPress. * + * ## EXAMPLES + * + * wp eval 'echo WP_CONTENT_DIR;' + * * @synopsis <php-code> */ public function __invoke( $args, $assoc_args ) { diff --git a/php/commands/export.php b/php/commands/export.php index 3bde8c314..173ad2d13 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -11,6 +11,50 @@ class Export_Command extends WP_CLI_Command { /** * Export content to a WXR file. * + * ## OPTIONS + * + * --dir=<dirname> + * : Full path to directory where WXR export files should be stored. Defaults + * to current working directory. + * + * --skip_comments + * : Don't export comments. + * + * --file_item_count=<count> + * : Break export into files with N posts. + * + * --verbose + * : Show more information about the process on STDOUT. + * + * ## FILTERS + * + * --start_date=<date> + * : Export only posts newer than this date, in format YYYY-MM-DD. + * + * --end_date=<date> + * : Export only posts older than this date, in format YYYY-MM-DD. + * + * --post_type=<post_type> + * : Export only posts with this post_type. + * + * --post__in=<pid> + * : Export all posts specified as a comma-separated list of IDs. + * + * --author=<login/id> + * : Export only posts by this author. + * + * --category=<category-id> + * : Export only posts in this category. + * + * --post_status=<status> + * : Export only posts with this status. + * + * ## EXAMPLES + * + * wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + * + * wp export --dir=/tmp/ --post__in=123,124,125 + * * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] [--verbose] */ public function __invoke( $_, $assoc_args ) { diff --git a/php/commands/help.php b/php/commands/help.php index 0e074f087..93fc6ab5a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -8,6 +8,14 @@ class Help_Command extends WP_CLI_Command { /** * Get help on a certain command. * + * ## EXAMPLES + * + * # get help for `core` command + * wp help core + * + * # get help for `core download` subcommand + * wp help core download + * * @synopsis [<command>] */ function __invoke( $args, $assoc_args ) { diff --git a/php/commands/import.php b/php/commands/import.php index 1f2dc0892..d114d4f9d 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -5,6 +5,17 @@ class Import_Command extends WP_CLI_Command { /** * Import content from a WXR file. * + * ## OPTIONS + * + * <file> + * : Path to a valid WXR file for importing. + * + * --authors=<authors> + * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. + * + * --skip=<data-type> + * : Skip importing specific data. Supported option is 'attachment'. + * * @synopsis <file> --authors=<authors> [--skip=<data-type>] */ public function __invoke( $args, $assoc_args ) { diff --git a/php/commands/media.php b/php/commands/media.php index 22cae68c9..dfb188dce 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -10,6 +10,20 @@ class Media_Command extends WP_CLI_Command { /** * Regenerate thumbnail(s). * + * ## OPTIONS + * + * --yes + * : Answer yes to the confirmation message. + * + * <attachment-id> + * : One or more IDs of the attachments to regenerate. + * + * ## EXAMPLES + * + * wp media regenerate 123 1337 + * + * wp media regenerate --yes + * * @synopsis <attachment-id>... [--yes] */ function regenerate( $args, $assoc_args = array() ) { @@ -59,6 +73,45 @@ function regenerate( $args, $assoc_args = array() ) { /** * Create attachments from local files or from URLs. * + * ## OPTIONS + * + * <file> + * : Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. + * If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be + * downloaded to a temp file before being sideloaded. + * + * --post_id=<post_id> + * : ID of the post to attach the imported files to + * + * --title=<title> + * : Attachment title (post title field) + * + * --caption=<caption> + * : Caption for attachent (post excerpt field) + * + * --alt=<alt_text> + * : Alt text for image (saved as post meta) + * + * --desc=<description> + * : "Description" field (post content) of attachment post + * + * --featured_image + * : If set, set the imported image as the Featured Image of the post its attached to. + * + * + * ## EXAMPLES + * + * # Import all jpgs in the current user's "Pictures" directory, not attached to any post + * wp media import ~/Pictures/**/*.jpg + * + * # Import a local image and set it to be the post thumbnail for a post + * wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image + * + * # Import an image from the web + * wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" + * + * + * * @synopsis <file>... [--post_id=<id>] [--title=<title>] [--caption=<caption>] [--alt=<text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { diff --git a/php/commands/network-meta.php b/php/commands/network-meta.php index c7a603a90..181d22949 100644 --- a/php/commands/network-meta.php +++ b/php/commands/network-meta.php @@ -3,7 +3,18 @@ /** * Manage network custom fields. * - * @package wp-cli + * ## OPTIONS + * + * <id> + * : The network id (usually 1). + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * # get a list of super-admins + * wp network-meta get 1 site_admins */ class Network_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'site'; diff --git a/php/commands/option.php b/php/commands/option.php index da3f3ceaf..ccefe5bf4 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -3,7 +3,20 @@ /** * Manage options. * - * @package wp-cli + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp option get siteurl + * + * wp option add my_option foobar + * + * wp option update my_option '{"foo": "bar"}' --format=json + * + * wp option delete my_option */ class Option_Command extends WP_CLI_Command { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e95c56845..8f0120947 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -32,6 +32,11 @@ protected function get_upgrader_class( $force ) { /** * See the status of one or all plugins. * + * ## OPTIONS + * + * <plugin> + * : A particular plugin to show the status for. + * * @synopsis [<plugin>] */ function status( $args ) { @@ -78,6 +83,14 @@ protected function get_all_items() { /** * Activate a plugin. * + * ## OPTIONS + * + * <plugin> + * : The plugin to activate. + * + * --network + * : If set, the plugin will be activated for the entire multisite network. + * * @synopsis <plugin> [--network] */ function activate( $args, $assoc_args = array() ) { @@ -98,6 +111,14 @@ function activate( $args, $assoc_args = array() ) { /** * Deactivate a plugin. * + * ## OPTIONS + * + * <plugin> + * : The plugin to deactivate. + * + * --network + * : If set, the plugin will be deactivated for the entire multisite network. + * * @synopsis <plugin> [--network] */ function deactivate( $args, $assoc_args = array() ) { @@ -118,6 +139,14 @@ function deactivate( $args, $assoc_args = array() ) { /** * Toggle a plugin's activation state. * + * ## OPTIONS + * + * <plugin> + * : The plugin to toggle. + * + * --network + * : If set, the plugin will be toggled for the entire multisite network. + * * @synopsis <plugin> [--network] */ function toggle( $args, $assoc_args = array() ) { @@ -136,6 +165,20 @@ function toggle( $args, $assoc_args = array() ) { /** * Get the path to a plugin or to the plugin directory. * + * ## OPTIONS + * + * <plugin> + * : The plugin to get the path to. If not set, will return the path to the + * plugins directory. + * + * --dir + * : If set, get the path to the closest parent directory, instead of the + * plugin file. + * + * ## EXAMPLES + * + * cd $(wp theme path) + * * @synopsis [<plugin>] [--dir] */ function path( $args, $assoc_args ) { @@ -182,6 +225,19 @@ protected function install_from_repo( $slug, $assoc_args ) { /** * Update a plugin. * + * ## OPTIONS + * + * <plugin> + * : The plugin to update. + * + * --version=dev + * : If set, the plugin will be updated to the latest development version, + * regardless of what version is currently installed. + * + * ## EXAMPLES + * + * wp plugin update bbpress --version=dev + * * @synopsis <plugin> [--version=<version>] */ function update( $args, $assoc_args ) { @@ -214,6 +270,15 @@ function update( $args, $assoc_args ) { /** * Update all plugins. * + * ## OPTIONS + * + * --dry-run + * : Pretend to do the updates, to see what would happen. + * + * ## EXAMPLES + * + * wp plugin update-all + * * @subcommand update-all * @synopsis [--dry-run] */ @@ -240,6 +305,36 @@ protected function get_item_list() { /** * Install a plugin. * + * ## OPTIONS + * + * <plugin|zip|url> + * : A plugin slug, the path to a local zip file, or URL to a remote zip file. + * + * --version=<version> + * : If set, get that particular version from wordpress.org, instead of the + * stable version. + * + * --force + * : If set, the command will overwrite any installed version of the plugin, without prompting + * for confirmation. + * + * --activate + * : If set, the plugin will be activated immediately after install. + * + * ## EXAMPLES + * + * # Install the latest version from wordpress.org and activate + * wp plugin install bbpress --activate + * + * # Install the development version from wordpress.org + * wp plugin install bbpress --version=dev + * + * # Install from a local zip file + * wp plugin install ../my-plugin.zip + * + * # Install from a remote zip file + * wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * * @synopsis <plugin|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { @@ -249,6 +344,19 @@ function install( $args, $assoc_args ) { /** * Uninstall a plugin. * + * ## OPTIONS + * + * <plugin> + * : The plugin to uninstall. + * + * --no-delete + * : If set, the plugin files will not be deleted. Only the uninstall procedure + * will be run. + * + * ## EXAMPLES + * + * wp plugin uninstall hello + * * @synopsis <plugin> [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { @@ -272,6 +380,15 @@ function uninstall( $args, $assoc_args = array() ) { /** * Delete plugin files. * + * ## OPTIONS + * + * <plugin> + * : The plugin to delete. + * + * ## EXAMPLES + * + * wp plugin delete hello + * * @synopsis <plugin> */ function delete( $args, $assoc_args = array() ) { @@ -286,6 +403,16 @@ function delete( $args, $assoc_args = array() ) { /** * Get a list of plugins. * + * ## OPTIONS + * + * * `--format`=<format>: + * + * Output list as table, CSV or JSON. Defaults to table. + * + * ## EXAMPLES + * + * wp plugin list --format=json + * * @subcommand list * @synopsis [--format=<format>] */ diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php index 08a1052f0..31cf7572c 100644 --- a/php/commands/post-meta.php +++ b/php/commands/post-meta.php @@ -3,7 +3,14 @@ /** * Manage post custom fields. * - * @package wp-cli + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp post-meta set 123 _wp_page_template about.php */ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; diff --git a/php/commands/post.php b/php/commands/post.php index 179283099..f8f7a9b59 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -20,6 +20,33 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { /** * Create a post. * + * ## OPTIONS + * + * <filename> + * : Read post content from <filename>. If this value is present, the + * `--post_content` argument will be ignored. + * + * Passing `-` as the filename will cause post content to + * be read from STDIN. + * + * --<field>=<value> + * : Field values for the new post. See wp_insert_post(). + * + * --edit + * : Immediately open system's editor to write or edit post content. + * + * If content is read from a file, from STDIN, or from the `--post_content` + * argument, that text will be loaded into the editor. + * + * --porcelain + * : Output just the new post id. + * + * ## EXAMPLES + * + * wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' + * + * wp post create page.txt --post_type=page --post_title='Page from file' + * * @synopsis [<filename>] --<field>=<value> [--edit] [--porcelain] */ public function create( $args, $assoc_args ) { @@ -56,6 +83,18 @@ protected function _create( $params ) { /** * Update one or more posts. * + * ## OPTIONS + * + * <ID> + * : The ID of the post to update. + * + * --<field>=<value> + * : One or more fields to update. See wp_update_post(). + * + * ## EXAMPLES + * + * wp post update 123 --post_name=something --post_status=draft + * * @synopsis <id>... --<field>=<value> */ public function update( $args, $assoc_args ) { @@ -69,6 +108,15 @@ protected function _update( $params ) { /** * Launch system editor to edit post content. * + * ## OPTIONS + * + * <id> + * : The ID of the post to edit. + * + * ## EXAMPLES + * + * wp post edit 123 + * * @synopsis <id> */ public function edit( $args, $_ ) { @@ -91,7 +139,28 @@ protected function _edit( $content, $title ) { /** * Get a post's content by ID. * - * @synopsis [--format=<format>] <id> + * ## OPTIONS + * + * <ID> + * : The ID of the post to get. + * + * --format=<format> + * : The format to use when printing the post, acceptable values: + * + * - **content**: Outputs only the post's content. + * + * - **table**: Outputs all fields of the post as a table. Note that the + * post_content field is omitted so that the table is readable. + * + * - **json**: Outputs all fields in JSON format. + * + * ## EXAMPLES + * + * wp post get 12 --format=content + * + * wp post get 12 > file.txt + * + * @synopsis [--format=<format>] <ID> */ public function get( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( @@ -130,6 +199,20 @@ public function get( $args, $assoc_args ) { /** * Delete a post by ID. * + * ## OPTIONS + * + * <ID> + * : The ID of the post to delete. + * + * --force + * : Skip the trash bin. + * + * ## EXAMPLES + * + * wp post delete 123 --force + * + * wp post delete $(wp post list --post_type='page' --format=ids) + * * @synopsis <id>... [--force] */ public function delete( $args, $assoc_args ) { @@ -155,6 +238,25 @@ protected function _delete( $post_id, $assoc_args ) { /** * Get a list of posts. * + * ## OPTIONS + * + * --<field>=<value> + * : One or more args to pass to WP_Query. + * + * --fields=<fields> + * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. + * + * --format=<format> + * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * + * ## EXAMPLES + * + * wp post list --format=ids + * + * wp post list --post_type=post --posts_per_page=5 --format=json + * + * wp post list --post_type=page --fields=post_title,post_status + * * @subcommand list * @synopsis [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ @@ -195,6 +297,30 @@ public function _list( $_, $assoc_args ) { /** * Generate some posts. * + * ## OPTIONS + * + * --count=<number> + * : How many posts to generate. Default: 100 + * + * --post_type=<type> + * : The type of the generated posts. Default: 'post' + * + * --post_status=<status> + * : The status of the generated posts. Default: 'publish' + * + * --post_author=<login> + * : The author of the generated posts. Default: none + * + * --post_date=<yyyy-mm-dd> + * : The date of the generated posts. Default: current date + * + * --max_depth=<number> + * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 + * + * ## EXAMPLES + * + * wp post generate --count=10 --post_type=page --post_date=1999-01-04 + * * @synopsis [--count=<number>] [--post_type=<type>] [--post_status=<status>] [--post_author=<login>] [--post_date=<yyyy-mm-dd>] [--max_depth=<number>] */ public function generate( $args, $assoc_args ) { diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 71538d25b..b1c5a5104 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -10,6 +10,11 @@ class Rewrite_Command extends WP_CLI_Command { /** * Flush rewrite rules. * + * ## OPTIONS + * + * --hard + * : Perform a hard flush - do not overwrite `.htaccess`. The default is to update `.htaccess` rules as well as rewrite rules in database. + * * @synopsis [--hard] */ public function flush( $args, $assoc_args ) { @@ -21,6 +26,21 @@ public function flush( $args, $assoc_args ) { /** * Update the permalink structure. * + * ## OPTIONS + * + * <permastruct> + * : The new permalink structure to apply. + * + * --category-base=<categorybase> + * : Set the base for category permalinks, i.e. '/category/'. + * + * --tag-base=<tagbase> + * : Set the base for tag permalinks, i.e. '/tag/'. + * + * ## EXAMPLES + * + * wp rewrite structure '/%year%/%monthnum%/%postname%' + * * @synopsis <permastruct> [--category-base=<base>] [--tag-base=<base>] [--hard] */ public function structure( $args, $assoc_args ) { @@ -72,10 +92,14 @@ public function structure( $args, $assoc_args ) { /** * Print current rewrite rules. * - * @synopsis [--json] + * ## OPTIONS + * + * --format=json + * : Output rules in JSON format. + * + * @synopsis [--format=<format>] */ public function dump( $args, $assoc_args ) { - $rules = get_option( 'rewrite_rules' ); if ( ! $rules ) { $rules = array(); @@ -88,7 +112,6 @@ public function dump( $args, $assoc_args ) { foreach ( $rules as $route => $rule ) WP_CLI::line( $route . "\t" . $rule ); } - } /** @@ -125,7 +148,6 @@ function apache_get_modules() { } } } - } WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); diff --git a/php/commands/role.php b/php/commands/role.php index bfd974b63..3c032e8c1 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -15,6 +15,18 @@ class Role_Command extends WP_CLI_Command { /** * List all roles. * + * ## OPTIONS + * + * --fields=<fields> + * : Limit the output to specific object fields. Defaults to name,role. + * + * --format=<format> + * : Output list as table, CSV or JSON. Defaults to table. + * + * ## EXAMPLES + * + * wp role list --fields=role --format=csv + * * @subcommand list * @synopsis [--fields=<fields>] [--format=<format>] */ @@ -45,7 +57,20 @@ public function _list( $args, $assoc_args ) { /** * Check if a role exists. - * Will return 0 if the role exists, 1 if it does not. + * + * ##DESCRIPTION + * + * Will exit with status 0 if the role exists, 1 if it does not. + * + * ## OPTIONS + * + * * <role-key>: + * + * The internal name of the role, e.g. editor + * + * ## EXAMPLES + * + * wp role exists editor * * @synopsis <role-key> */ @@ -60,6 +85,22 @@ public function exists( $args ) { /** * Create a new role. * + * ## OPTIONS + * + * * <role-key>: + * + * The internal name of the role, e.g. editor + * + * * <role-name>: + * + * The publically visible name of the role, e.g. Editor + * + * ## EXAMPLES + * + * wp role create approver Approver + * + * wp role create productadmin "Product Administrator" + * * @synopsis <role-key> <role-name> */ public function create( $args ) { @@ -75,12 +116,23 @@ public function create( $args ) { WP_CLI::error( "Role couldn't be created." ); else WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); - } /** * Delete an existing role. * + * ## OPTIONS + * + * * <role-key>: + * + * The internal name of the role, e.g. editor + * + * ## EXAMPLES + * + * wp role delete approver + * + * wp role delete productadmin + * * @synopsis <role-key> */ public function delete( $args ) { diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 242833973..bdf3435d1 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -16,6 +16,25 @@ function __construct() { /** * Generate PHP code for registering a custom post type. * + * ## OPTIONS + * + * --label=<label> + * : The text used to translate the update messages + * + * --textdomain=<textdomain> + * : The textdomain to use for the labels. + * + * --theme + * : Create a file in the active theme directory, instead of sending to + * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. + * + * --plugin=<plugin> + * : Create a file in the given plugin's directory, instead of sending to + * STDOUT. + * + * --raw + * : Just generate the `register_post_type()` call and nothing else. + * * @subcommand post-type * * @alias cpt @@ -36,6 +55,32 @@ function post_type( $args, $assoc_args ) { /** * Generate PHP code for registering a custom taxonomy. * + * ## OPTIONS + * + * --post_types=<post_types> + * : Post types to register for use with the taxonomy. + * + * --label=<label> + * : The text used to translate the update messages + * + * --textdomain=<textdomain> + * : The textdomain to use for the labels. + * + * --theme + * : Create a file in the active theme directory, instead of sending to + * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. + * + * --plugin=<plugin> + * : Create a file in the given plugin's directory, instead of sending to + * STDOUT. + * + * --raw + * : Just generate the `register_taxonomy()` call and nothing else. + * + * ## EXAMPLES + * + * wp scaffold taxonomy venue --post_types=event,presentation + * * @subcommand taxonomy * * @alias tax @@ -112,6 +157,23 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) /** * Generate starter code for a theme. * + * ## OPTIONS + * + * <slug> + * : The slug for the new theme, used for prefixing functions. + * + * --activate + * : Activate the newly downloaded theme. + * + * --theme_name=<title> + * : What to put in the 'Theme Name:' header in style.css + * + * --author=<full name> + * : What to put in the 'Author:' header in style.css + * + * --author_uri=<http url> + * : What to put in the 'Author URI:' header in style.css + * * @synopsis <slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--activate] */ function _s( $args, $assoc_args ) { @@ -154,6 +216,29 @@ function _s( $args, $assoc_args ) { /** * Generate empty child theme. * + * ## OPTIONS + * + * <slug> + * : The slug for the new child theme. + * + * --parent_theme=<slug> + * : What to put in the 'Template:' header in style.css + * + * --theme_name=<title> + * : What to put in the 'Theme Name:' header in style.css + * + * --author=<full name> + * : What to put in the 'Author:' header in style.css + * + * --author_uri=<http url> + * : What to put in the 'Author URI:' header in style.css + * + * --theme_uri=<http url> + * : What to put in the 'Theme URI:' header in style.css + * + * --activate + * : Activate the newly created child theme. + * * @subcommand child-theme * * @synopsis <slug> --parent_theme=<slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] @@ -206,6 +291,14 @@ private function get_output_path( $assoc_args, $subdir ) { /** * Generate starter code for a plugin. * + * ## OPTIONS + * + * --activate + * : Activate the newly generated plugin. + * + * --plugin_name=<title> + * : What to put in the 'Plugin Name:' header + * * @synopsis <slug> [--plugin_name=<title>] [--activate] */ function plugin( $args, $assoc_args ) { @@ -233,6 +326,24 @@ function plugin( $args, $assoc_args ) { /** * Generate files needed for running PHPUnit tests. * + * ## DESCRIPTION + * + * These are the files that are generated: + * + * * `phpunit.xml` is the configuration file for PHPUnit + * * `.travis.yml` is the configuration file for Travis CI + * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite + * * `tests/test-sample.php` is a sample file containing the actual tests + * + * ## ENVIRONMENT + * + * The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment + * variable. + * + * ## EXAMPLE + * + * wp scaffold plugin-tests hello + * * @subcommand plugin-tests * * @synopsis <plugin> diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 1eee97656..418559810 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -10,6 +10,29 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * + * ## DESCRIPTION + * + * This command will go through all rows in all tables and will replace all appearances of the old string with the new one. + * + * It will correctly handle serialized values, and will not change primary key values. + * + * ## OPTIONS + * + * --network + * : Search/replace through all the tables in a multisite install. + * + * --skip-columns=<columns> + * : Do not perform the replacement in the comma-separated columns. + * + * --dry-run + * : Show report, but don't perform the changes. + * + * ## EXAMPLES + * + * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid + * + * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run + * * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--network] */ public function __invoke( $args, $assoc_args ) { diff --git a/php/commands/shell.php b/php/commands/shell.php index 4fbf4bbcc..ef0869e85 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -5,6 +5,15 @@ class Shell_Command extends \WP_CLI_Command { /** * Interactive PHP console. * + * ## DESCRIPTION + * + * `wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. + * + * ## OPTIONS + * + * --basic + * : Start in fail-safe mode, even if Boris is available. + * * @synopsis [--basic] */ public function __invoke( $_, $assoc_args ) { diff --git a/php/commands/site.php b/php/commands/site.php index f1208a129..1fd1ffa4b 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -110,6 +110,11 @@ private function _insert_default_terms() { /** * Empty a site of its content (posts, comments, and terms). * + * ## OPTIONS + * + * --yes + * : Proceed to empty the site without a confirmation prompt. + * * @subcommand empty * @synopsis [--yes] */ @@ -128,6 +133,20 @@ public function _empty( $args, $assoc_args ) { /** * Delete a site in a multisite install. * + * ## OPTIONS + * + * <blog-id> + * : The id of the blog to delete. If not provided, you must set the --slug parameter. + * + * --slug=<slug> + * : Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. + * + * --yes + * : Answer yes to the confirmation message. + * + * --keep-tables + * : Delete the blog from the list, but don't drop it's tables. + * * @synopsis [<site-id>] [--slug=<slug>] [--yes] [--keep-tables] */ function delete( $args, $assoc_args ) { @@ -179,6 +198,26 @@ private function _get_site( $site_id ) { /** * Create a site in a multisite install. * + * ## OPTIONS + * + * --slug=<slug> + * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. + * + * --title=<title> + * : Title of the new site. Default: prettified slug. + * + * --email=<email> + * : Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. + * + * --network_id=<network-id> + * : Network to associate new site with. Defaults to current network (typically 1). + * + * --private + * : If set, the new site will be non-public (not indexed) + * + * --porcelain + * : If set, only the site id will be output on success. + * * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--network_id=<network-id>] [--private] [--porcelain] */ public function create( $_, $assoc_args ) { diff --git a/php/commands/term.php b/php/commands/term.php index 5cbaf0a5a..2b400c84e 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -19,6 +19,23 @@ class Term_Command extends WP_CLI_Command { /** * List terms in a taxonomy. * + * ## OPTIONS + * + * <taxonomy> + * : List terms of a given taxonomy. + * + * --fields=<fields> + * : Limit the output to specific object fields. Defaults to all of the term object fields. + * + * --format=<format> + * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * + * ## EXAMPLES + * + * wp term list category --format=csv + * + * wp term list post_tag --fields=name,slug + * * @subcommand list * @synopsis <taxonomy> [--fields=<fields>] [--format=<format>] */ @@ -47,6 +64,30 @@ public function _list( $args, $assoc_args ) { /** * Create a term. * + * ## OPTIONS + * + * <term> + * : A name for the new term. + * + * <taxonomy> + * : Taxonomy for the new term. + * + * --slug=<slug> + * : A unique slug for the new term. Defaults to sanitized version of name. + * + * --description=<description> + * : A description for the new term. + * + * --parent=<term-id> + * : A parent for the new term. + * + * --porcelain + * : Output just the new term id. + * + * ## EXAMPLES + * + * wp term create Apple category --description="A type of fruit" + * * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<term-id>] [--porcelain] */ public function create( $args, $assoc_args ) { @@ -82,6 +123,30 @@ public function create( $args, $assoc_args ) { /** * Update a term. * + * ## OPTIONS + * + * <term-id> + * : ID for the term to update. + * + * <taxonomy> + * : Taxonomy of the term to update. + * + * --name=<name> + * : A new name for the term. + * + * --slug=<slug> + * : A new slug for the term. + * + * --description=<description> + * : A new description for the term. + * + * --parent=<term-id> + * : A new parent for the term. + * + * ## EXAMPLES + * + * wp term update 15 category --name=Apple + * * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<term-id>] */ public function update( $args, $assoc_args ) { @@ -112,6 +177,18 @@ public function update( $args, $assoc_args ) { /** * Delete a term. * + * ## OPTIONS + * + * <term-id> + * : ID for the term to delete. + * + * <taxonomy> + * : Taxonomy of the term to delete. + * + * ## EXAMPLES + * + * wp term delete 15 category + * * @synopsis <term-id> <taxonomy> */ public function delete( $args ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 8db618bd4..33d80413f 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -25,6 +25,11 @@ protected function get_upgrader_class( $force ) { /** * See the status of one or all themes. * + * ## OPTIONS + * + * <theme> + * : A particular theme to show the status for. + * * @synopsis [<theme>] */ function status( $args ) { @@ -60,6 +65,11 @@ protected function get_status( $theme ) { /** * Activate a theme. * + * ## OPTIONS + * + * <theme> + * : The theme to activate. + * * @synopsis <theme> */ public function activate( $args = array() ) { @@ -83,6 +93,20 @@ private function is_active_theme( $theme ) { /** * Get the path to a theme or to the theme directory. * + * ## OPTIONS + * + * <theme> + * : The theme to get the path to. If not set, will return the path to the + * themes directory. + * + * --dir + * : If set, get the path to the closest parent directory, instead of the + * theme file. + * + * ## EXAMPLES + * + * cd $(wp theme path) + * * @synopsis [<theme>] [--dir] */ function path( $args, $assoc_args ) { @@ -149,6 +173,29 @@ protected function get_item_list() { /** * Install a theme. * + * ## OPTIONS + * + * <theme|zip|url> + * : A theme slug, the path to a local zip file, or URL to a remote zip file. + * + * --force + * : If set, the command will overwrite any installed version of the theme, without prompting + * for confirmation. + * + * --activate + * : If set, the theme will be activated immediately after install. + * + * ## EXAMPLES + * + * # Install the latest version from wordpress.org and activate + * wp theme install twentytwelve --activate + * + * # Install from a local zip file + * wp theme install ../my-theme.zip + * + * # Install from a remote zip file + * wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * * @synopsis <theme|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { @@ -158,6 +205,19 @@ function install( $args, $assoc_args ) { /** * Update a theme. * + * ## OPTIONS + * + * <theme> + * : The theme to update. + * + * --version=dev + * : If set, the theme will be updated to the latest development version, + * regardless of what version is currently installed. + * + * ## EXAMPLES + * + * wp theme update twentytwelve + * * @synopsis <theme> [--version=<version>] */ function update( $args, $assoc_args ) { @@ -171,6 +231,15 @@ function update( $args, $assoc_args ) { /** * Update all themes. * + * ## OPTIONS + * + * --dry-run + * : Pretend to do the updates, to see what would happen. + * + * ## EXAMPLES + * + * wp theme update-all + * * @subcommand update-all * @synopsis [--dry-run] */ @@ -181,6 +250,15 @@ function update_all( $args, $assoc_args ) { /** * Delete a theme. * + * ## OPTIONS + * + * <theme> + * : The theme to delete. + * + * ## EXAMPLES + * + * wp theme delete twentyeleven + * * @synopsis <theme> */ function delete( $args ) { @@ -203,6 +281,16 @@ function delete( $args ) { /** * Get a list of themes. * + * ## OPTIONS + * + * * `--format`=<format>: + * + * Output list as table, CSV or JSON. Defaults to table. + * + * ## EXAMPLES + * + * wp theme list --format=csv + * * @subcommand list * @synopsis [--format=<format>] */ diff --git a/php/commands/transient.php b/php/commands/transient.php index 6294a7976..0691b5f05 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -3,7 +3,9 @@ /** * Manage transients. * - * @package wp-cli + * ## EXAMPLES + * + * wp transient set my_key my_value 300 */ class Transient_Command extends WP_CLI_Command { diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 59b4b739f..1e2dda038 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -3,7 +3,14 @@ /** * Manage user custom fields. * - * @package wp-cli + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp user-meta set 123 description "Mary is a WordPress developer." */ class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; diff --git a/php/commands/user.php b/php/commands/user.php index 7a874a07c..8f1a6335b 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -21,6 +21,25 @@ class User_Command extends \WP_CLI\CommandWithDBObject { /** * List users. * + * ## OPTIONS + * + * --role=<role> + * : Only display users with a certain role. + * + * --fields=<fields> + * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles + * + * --format=<format> + * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * + * ## EXAMPLES + * + * wp user list --format=ids + * + * wp user list --role=administrator --format=csv + * + * wp user list --fields=display_name,user_email + * * @subcommand list * @synopsis [--role=<role>] [--fields=<fields>] [--format=<format>] */ @@ -59,6 +78,24 @@ public function _list( $args, $assoc_args ) { /** * Get a single user. * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * --format=<format> + * : The format to use when printing the user; acceptable values: + * + * **table**: Outputs all fields of the user as a table. + * + * **json**: Outputs all fields in JSON format. + * + * ## EXAMPLES + * + * wp user get 12 + * + * wp user get bob --format=json > bob.json + * * @synopsis [--format=<format>] <user> */ public function get( $args, $assoc_args ) { @@ -96,6 +133,18 @@ public function get( $args, $assoc_args ) { /** * Delete one or more users. * + * ## OPTIONS + * + * <user> + * : The user login or ID of the user to delete. + * + * --reassign=<ID> + * : User to reassign the posts to. + * + * ## EXAMPLES + * + * wp user delete 123 --reassign=567 + * * @synopsis <user>... [--reassign=<id>] */ public function delete( $args, $assoc_args ) { @@ -126,6 +175,33 @@ protected function _delete( $user_id, $assoc_args ) { /** * Create a user. * + * ## OPTIONS + * + * <user-login> + * : The login of the user to create. + * + * <user-email> + * : The email address of the user to create. + * + * --role=<role> + * : The role of the user to create. Default: default role + * + * --user_pass=<password> + * : The user password. Default: randomly generated + * + * --user_registered=<yyyy-mm-dd> + * : The date the user registered. Default: current date + * + * --display_name=<name> + * : The display name. + * + * --porcelain + * : Output just the new user id. + * + * ## EXAMPLES + * + * wp user create bob bob@example.com --role=author + * * @synopsis <user-login> <user-email> [--role=<role>] [--user_pass=<password>] [--user_registered=<yyyy-mm-dd>] [--display_name=<name>] [--porcelain] */ public function create( $args, $assoc_args ) { @@ -185,6 +261,20 @@ protected function _create( $params ) { /** * Update a user. * + * ## OPTIONS + * + * <user> + * : The user login or ID of the user to update. + * + * --<field>=<value> + * : One or more fields to update. For accepted fields, see wp_update_user(). + * + * ## EXAMPLES + * + * wp user update 123 --user_login=mary --display_name=Mary + * + * wp user update mary --user_pass=marypass + * * @synopsis <user>... --<field>=<value> */ public function update( $args, $assoc_args ) { @@ -202,6 +292,14 @@ protected function _update( $params ) { /** * Generate users. * + * ## OPTIONS + * + * --count=<number> + * : How many users to generate. Default: 100 + * + * --role=<role> + * : The role of the generated users. Default: default role from WP + * * @synopsis [--count=<number>] [--role=<role>] */ public function generate( $args, $assoc_args ) { @@ -255,6 +353,20 @@ public function generate( $args, $assoc_args ) { /** * Set the user role (for a particular blog). * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * [<role>] + * : Make the user have the specified role. If not passed, the default role is + * used. + * + * ## EXAMPLES + * + * wp user set-role bob author + * wp user set-role 12 author + * * @subcommand set-role * @synopsis <user> [<role>] */ @@ -275,6 +387,19 @@ public function set_role( $args, $assoc_args ) { /** * Add a role for a user. * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * <role> + * : Add the specified role to the user. + * + * ## EXAMPLES + * + * wp user set-role bob author + * wp user set-role 12 author + * * @subcommand add-role * @synopsis <user> <role> */ @@ -291,6 +416,16 @@ public function add_role( $args, $assoc_args ) { /** * Remove a user's role. * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * ## EXAMPLES + * + * wp user remove-role bob + * wp user remove-role 12 + * * @subcommand remove-role * @synopsis <user> [<role>] */ @@ -330,6 +465,22 @@ private static function get_user( $id_or_login ) { /** * Import users from a CSV file. * + * ## OPTIONS + * + * <file> + * : The CSV file of users to import. + * + * ## EXAMPLES + * + * wp user import-csv /path/to/users.csv + * + * Sample users.csv file: + * + * user_login,user_email,display_name,role + * bobjones,bobjones@domain.com,Bob Jones,contributor + * newuser1,newuser1@domain.com,New User,author + * existinguser,existinguser@domain.com,Existing User,administrator + * * @subcommand import-csv * @synopsis <file> */ From 0212ebe4b3288bb456929e203d7db637c8fe42d6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 18:16:14 +0300 Subject: [PATCH 2077/5359] escape "*/" sequence in media.php --- php/commands/media.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index dfb188dce..3c3bbafcf 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -98,11 +98,10 @@ function regenerate( $args, $assoc_args = array() ) { * --featured_image * : If set, set the imported image as the Featured Image of the post its attached to. * - * * ## EXAMPLES * * # Import all jpgs in the current user's "Pictures" directory, not attached to any post - * wp media import ~/Pictures/**/*.jpg + * wp media import ~/Pictures/**\/*.jpg * * # Import a local image and set it to be the post thumbnail for a post * wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image @@ -110,8 +109,6 @@ function regenerate( $args, $assoc_args = array() ) { * # Import an image from the web * wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" * - * - * * @synopsis <file>... [--post_id=<id>] [--title=<title>] [--caption=<caption>] [--alt=<text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { From e3d50372fb740c7a6cab8780aaf13f0a23a3aed2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 21:40:23 +0300 Subject: [PATCH 2078/5359] remove buggy code that tries to use `more` for paging `wp help` * Windows throws an unexpected exit status when trying to use `less` * more doesn't have an '-r' flag --- php/commands/help.php | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index bd681c31a..c7df1475f 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -47,29 +47,12 @@ private static function show_help( $command ) { $out = str_replace( "\t", ' ', $out ); - self::pass_through_pager( WP_CLI::colorize( $out ) ); - } - - private static function launch_pager( $pager, $fd ) { - // launch pager - $descriptorspec = array( - 0 => $fd, - 1 => STDOUT, - 2 => array( 'pipe', 'w' ) - ); - - $r = proc_close( proc_open( $pager, $descriptorspec, $pipes ) ); - - if ( 127 == $r ) { - return false; + if ( strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ) { + // no paging for Windows cmd.exe; sorry + echo $out; + } else { + self::pass_through_pager( WP_CLI::colorize( $out ) ); } - - if ( $r ) { - fwrite( STDERR, stream_get_contents( $pipes[1] ) ); - exit( $r ); - } - - return true; } private static function pass_through_pager( $out ) { @@ -78,14 +61,13 @@ private static function pass_through_pager( $out ) { fputs( $fd, $out ); rewind( $fd ); - $pagers = array( 'less -r', 'more -r' ); - foreach ( $pagers as $pager ) { - if ( self::launch_pager( $pager, $fd ) ) - return; - } + $descriptorspec = array( + 0 => $fd, + 1 => STDOUT, + 2 => STDERR + ); - // no pager found - echo $out; + return proc_close( proc_open( 'less -r', $descriptorspec, $pipes ) ); } private static function find( $candidates, $callback ) { From 453eff2f35a6e90365312fe7ddf45431321cf853 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 21:53:35 +0300 Subject: [PATCH 2079/5359] always pass docs through WP_CLI::colorize() --- php/commands/help.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 72bd6c477..e2c28ae15 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -58,15 +58,16 @@ private static function show_help( $command ) { $out = str_replace( "\t", ' ', $out ); + self::pass_through_pager( WP_CLI::colorize( $out ) ); + } + + private static function pass_through_pager( $out ) { if ( strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ) { // no paging for Windows cmd.exe; sorry echo $out; - } else { - self::pass_through_pager( WP_CLI::colorize( $out ) ); + return 0; } - } - private static function pass_through_pager( $out ) { // convert string to file handle $fd = fopen( "php://temp", "r+" ); fputs( $fd, $out ); From 2dd66e0d1d983434e53a8d613a4e50469679b383 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 21:55:12 +0300 Subject: [PATCH 2080/5359] help: remove unused find() utility --- php/commands/help.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index e2c28ae15..6e90600b2 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -82,15 +82,6 @@ private static function pass_through_pager( $out ) { return proc_close( proc_open( 'less -r', $descriptorspec, $pipes ) ); } - private static function find( $candidates, $callback ) { - foreach ( $candidates as $candidate ) { - if ( call_user_func( $callback, $candidate ) ) - return $candidate; - } - - return false; - } - private static function get_initial_markdown( $command ) { $name = implode( ' ', Dispatcher\get_path( $command ) ); From 11993ae96f189f84ff1ebdd451cd2964f2978479 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 22:14:15 +0300 Subject: [PATCH 2081/5359] bump version to 0.11.0-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index f721cde07..b220b0d96 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.0-alpha2' ); +define( 'WP_CLI_VERSION', '0.11.0-beta' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From d823b0c273132ab5238f9e33f460ac15fce15b11 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 22:37:12 +0300 Subject: [PATCH 2082/5359] update to Mustache 2.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 832b311da..886935c21 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "require": { "php": ">=5.3.2", "wp-cli/php-cli-tools": "0.9.3", - "mustache/mustache": "~2.3" + "mustache/mustache": "~2.4" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" From 07e037d05206821a70dbbefc34f72d1ae80b6af7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 23:31:46 +0300 Subject: [PATCH 2083/5359] add shortdesc for 'wp cli' subcommands --- php/commands/cli.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index 2f550c885..d0046d4d1 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -28,10 +28,16 @@ private function command_to_array( $command ) { return $dump; } + /** + * Print WP-CLI version. + */ function version() { WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); } + /** + * Print various data about the CLI environment. + */ function info() { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); @@ -44,6 +50,8 @@ function info() { } /** + * Dump the list of global parameters, as JSON. + * * @subcommand param-dump */ function param_dump() { @@ -51,12 +59,17 @@ function param_dump() { } /** + * Dump the list of installed commands, as JSON. + * * @subcommand cmd-dump */ function cmd_dump() { echo json_encode( self::command_to_array( WP_CLI::get_root_command() ) ); } + /** + * Generate tab completion strings. + */ function completions() { foreach ( WP_CLI::get_root_command()->get_subcommands() as $name => $command ) { $subcommands = $command->get_subcommands(); From 336bcd96b71fc521c95546375537dfd5eb564040 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 4 Aug 2013 23:55:18 +0300 Subject: [PATCH 2084/5359] add new contributors since 0.10 --- .mailmap | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.mailmap b/.mailmap index 682554bd4..310cb19b8 100644 --- a/.mailmap +++ b/.mailmap @@ -3,11 +3,14 @@ bendoh <ben@thinkoomph.com> builtbylane <lanegoldberg@gmail.com> conatus <alex@recordsonribs.com> cyberhobo <dylan.k.kuhn@gmail.com> +dangardner <dan@web.nearest.to> danielbachhuber <d@danielbachhuber.com> +danielbachhuber <danielbachhuber@gmail.com> drrobotnik <B@Brandons-Mac-Pro-4.local> dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> +eugeneware <eugene@noblesamurai.com> future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> glebis <glebis@gmail.com> @@ -16,6 +19,7 @@ j3lamp <j3lamp@gmail.com> jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> jmslbam <jmslbam@gmail.com> +johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> kidfiction <ejdanderson@gmail.com> @@ -26,6 +30,7 @@ matiskay <matiskay@gmail.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> milesj <mileswjohnson@gmail.com> +MiteshShah <Mitesh.Shah@rtCamp.com> mwilliamson <michael.williamson@red-gate.com> mwilliamson <mike@zwobble.org> nacin <andrewnacin@gmail.com> @@ -33,6 +38,7 @@ navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> ocean90 <dominikschilling+git@gmail.com> om4james <james@jamesc.id.au> +om4james <james@om4.com.au> roelven <roel@soundcloud.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> @@ -46,6 +52,7 @@ tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> tott <tott@automattic.com> twisty <tim@brayshaw.com> +twratajczak <tomasz.ratajczak@espeo.pl> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> wopr42 <john@zippykid.com> From 573f35f646b236356f6ee6347c4a115176b8e0da Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 17:04:28 -0400 Subject: [PATCH 2085/5359] Add wordpress api plugin search method. fixes #615 --- php/commands/plugin.php | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 667e5dc66..b3b66fb49 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -43,6 +43,67 @@ function status( $args ) { parent::status( $args ); } + /** + * Search wordpress.org plugin repo + * + * ## OPTIONS + * + * <plugin> + * : A particular plugin to search for. + * + * --per_page + * : Optional number of results to display. Defaults to 10. + * + * --fields + * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. acceptable values: + * + * **name**: Plugin Name + * **slug**: Plugin Slug + * **version**: Current Version Number + * **author**: Plugin Author + * **author_profile**: Plugin Author Profile + * **contributors**: Plugin Contributors + * **requires**: Plugin Minimum Requirements + * **tested**: Plugin Tested Up To + * **compatibility**: Plugin Compatible With + * **rating**: Plugin Rating + * **num_ratings**: Number of Plugin Ratings + * **homepage**: Plugin Author's Homepage + * **description**: Plugin's Description + * **short_description**: Plugin's Short Description + * + * ## EXAMPLES + * + * wp plugin search dsgnwrks --per_page=20 + * + * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings + * + * @synopsis <plugin> + */ + function search( $args, $assoc_args = array() ) { + $term = $args[0]; + $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; + $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author_profile', 'rating' ); + + if ( $term ) { + $api = plugins_api( 'query_plugins', array( + 'per_page' => $per_page, + 'search' => $term, + ) ); + + if ( is_wp_error( $api ) ) + WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); + + if ( ! isset( $api->plugins ) ) + WP_CLI::error( $api->get_error_message() . __( 'API error. Try Again.' ) ); + + WP_CLI\Utils\format_items( 'table', $api->plugins, $fields ); + + WP_CLI::success( count( $api->plugins ). ' Plugins Found. Use slug for other plugin methods.' ); + } + + } + protected function status_single( $args ) { $name = $args[0]; $file = $this->parse_name( $name ); From d9a97ac3b8fe31974849615432633b3c97f459c5 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 17:15:00 -0400 Subject: [PATCH 2086/5359] Update per @danielbachhuber review. --- php/commands/plugin.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b3b66fb49..f3d60592f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -78,9 +78,9 @@ function status( $args ) { * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings * - * @synopsis <plugin> + * @synopsis <plugin> [--per_page=<per_page>] [--fields=<fields>] */ - function search( $args, $assoc_args = array() ) { + public function search( $args, $assoc_args = array() ) { $term = $args[0]; $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author_profile', 'rating' ); @@ -97,9 +97,9 @@ function search( $args, $assoc_args = array() ) { if ( ! isset( $api->plugins ) ) WP_CLI::error( $api->get_error_message() . __( 'API error. Try Again.' ) ); - WP_CLI\Utils\format_items( 'table', $api->plugins, $fields ); - WP_CLI::success( count( $api->plugins ). ' Plugins Found. Use slug for other plugin methods.' ); + + WP_CLI\Utils\format_items( 'table', $api->plugins, $fields ); } } From aeb3e2f81f89d93241127b6583a5dc87681d0ebc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 00:47:00 +0300 Subject: [PATCH 2087/5359] make Rewrite_Command::apache_modules() private other code has no business calling it --- php/commands/rewrite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index b1c5a5104..1e04593fd 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -137,7 +137,7 @@ public function dump( $args, $assoc_args ) { * If this isn't done then the .htaccess rewrite rules won't be flushed out * to disk. */ - public static function apache_modules() { + private static function apache_modules() { $mods = WP_CLI::get_config('apache_modules'); if ( !empty( $mods ) && !function_exists( 'apache_get_modules' ) ) { global $is_apache; From a5ed142fc58b8531caada5bff2a5feef3b90da00 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 02:54:31 +0300 Subject: [PATCH 2088/5359] 0.11.0 final --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index b220b0d96..d435efe16 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.0-beta' ); +define( 'WP_CLI_VERSION', '0.11.0' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 3f933876fd6b2f2062b6d3041999cffab4958e5b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 02:59:46 +0300 Subject: [PATCH 2089/5359] contrib-list: fix githubify function --- utils/contrib-list | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/contrib-list b/utils/contrib-list index 43d8f1542..fbce28190 100755 --- a/utils/contrib-list +++ b/utils/contrib-list @@ -9,14 +9,14 @@ prev_version=$1 linked=$2 githubify() { - local url="https://github.com/$name" - local response_code=$(curl -o /dev/null --silent --head --write-out '%{http_code}\n' $url) + while read name; do + local url="https://github.com/$name" + local response_code=$(curl -o /dev/null --silent --head --write-out '%{http_code}\n' $url) - if [ "200" != "$response_code" ]; then - echo "$response_code: $url" 1>&2; - fi + if [ "200" != "$response_code" ]; then + echo "$response_code: $url" 1>&2; + fi - while read name; do echo " [$name]($url)" done } From 11e37f7c7cdaf19b467388a1d99fb24fd047ecb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 03:02:13 +0300 Subject: [PATCH 2090/5359] contrib-list: don't show names starting with upper-case before others --- utils/contrib-list | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/contrib-list b/utils/contrib-list index fbce28190..b47f01697 100755 --- a/utils/contrib-list +++ b/utils/contrib-list @@ -23,7 +23,7 @@ githubify() { if [ '-l' == "$linked" ] then - git log --format="%aN" $prev_version -- | sort | uniq | githubify | tr '\n' ',' + git log --format="%aN" $prev_version -- | sort -f | uniq | githubify | tr '\n' ',' else - git log --format="%aN <%aE>" $prev_version -- | sort | uniq + git log --format="%aN <%aE>" $prev_version -- | sort -f | uniq fi From 953c51ba0ad564ee86f0f0bdc868063e9727d7de Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 22:53:10 -0400 Subject: [PATCH 2091/5359] 1) Move search method to CommandWithUpgrade parent class. 2) Add search method for themes. 3) add search=key replacement for plugin and theme methods that take a slug. --- php/WP_CLI/CommandWithUpgrade.php | 56 +++++++++++++++++++++++++++++ php/commands/plugin.php | 45 +++++++++++------------ php/commands/theme.php | 60 ++++++++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 23 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index aaac62ed9..0a6e9011b 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -308,4 +308,60 @@ private function get_color( $status ) { return $colors[ $status ]; } + + /** + * Search wordpress.org plugin repo + * + * @param object $api data from WP plugin/theme API + * @param array $fields Data fields to display in table. + * @param string $data_type Plugin or Theme api endpoint + */ + public function search( $api, $fields, $data_type = 'plugin' ) { + + // Sanitize to 1 of 2 types + $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; + $plural = $data_type . 's'; + $data = $api->$plural; + $count = isset( $api->info['results'] ) ? $api->info['results'] : count( $data ); + + if ( is_wp_error( $api ) ) + \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); + + if ( ! isset( $data ) ) + \WP_CLI::error( __( 'API error. Try Again.' ) ); + + \WP_CLI::success( $count .' '. $plural .' Found. \'search=$key\' in place of slug available for '. $data_type .' commands.' ); + + foreach ( $data as $key => $item ) { + $item->key = $key; + $data[$key] = $item; + } + + $set = set_site_transient( 'wpcli-$data_type-search-data', $data, 60*60 ); + + \WP_CLI\Utils\format_items( 'table', $data, array_merge( array( 'key' ), $fields ) ); + + } + + /** + * Parse the name of a plugin to check if 'search=' exists, and check search transient for the key + * + * @param string name + * @return string + */ + public function parse_search_key( $name, $data_type = 'plugin' ) { + + // Sanitize to 1 of 2 types + $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; + + if ( false !== strpos( $name, 'search=' ) ) { + $search_key = (int) str_replace( 'search=', '', $name ); + if ( ( $trans = get_site_transient( 'wpcli-$data_type-search-data' ) ) && isset( $trans[$search_key] ) ) + $name = $trans[$search_key]->slug; + else + \WP_CLI::error( 'There is no recent search with that key.' ); + } + return $name; + } + } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index f3d60592f..6e58e676f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -85,27 +85,17 @@ public function search( $args, $assoc_args = array() ) { $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author_profile', 'rating' ); - if ( $term ) { - $api = plugins_api( 'query_plugins', array( - 'per_page' => $per_page, - 'search' => $term, - ) ); + $api = plugins_api( 'query_plugins', array( + 'per_page' => $per_page, + 'search' => $term, + ) ); - if ( is_wp_error( $api ) ) - WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); - - if ( ! isset( $api->plugins ) ) - WP_CLI::error( $api->get_error_message() . __( 'API error. Try Again.' ) ); - - WP_CLI::success( count( $api->plugins ). ' Plugins Found. Use slug for other plugin methods.' ); - - WP_CLI\Utils\format_items( 'table', $api->plugins, $fields ); - } + parent::search( $api, $fields, 'plugin' ); } protected function status_single( $args ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); $details = $this->get_details( $file ); @@ -155,7 +145,7 @@ protected function get_all_items() { * @synopsis <plugin> [--network] */ function activate( $args, $assoc_args = array() ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -186,7 +176,7 @@ function activate( $args, $assoc_args = array() ) { * @synopsis <plugin> [--network] */ function deactivate( $args, $assoc_args = array() ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -217,7 +207,7 @@ function deactivate( $args, $assoc_args = array() ) { * @synopsis <plugin> [--network] */ function toggle( $args, $assoc_args = array() ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -308,7 +298,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * @synopsis <plugin> [--version=<version>] */ function update( $args, $assoc_args ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $basename = $this->parse_name( $name ); if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { @@ -405,6 +395,7 @@ protected function get_item_list() { * @synopsis <plugin|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { + $args[0] = $this->parse_search_key( $args[0] ); parent::install( $args, $assoc_args ); } @@ -427,7 +418,7 @@ function install( $args, $assoc_args ) { * @synopsis <plugin> [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); if ( is_plugin_active( $file ) ) { @@ -459,7 +450,7 @@ function uninstall( $args, $assoc_args = array() ) { * @synopsis <plugin> */ function delete( $args, $assoc_args = array() ) { - $name = $args[0]; + $name = $this->parse_search_key( $args[0] ); $file = $this->parse_name( $name ); if ( $this->_delete( $file ) ) { @@ -544,6 +535,16 @@ private function parse_name( $name ) { return $file; } + /** + * Parse the name of a plugin to check if 'search=' exists, and check search transient for the key + * + * @param string name + * @return string + */ + public function parse_search_key( $name ) { + return parent::parse_search_key( $name, 'plugin' ); + } + /** * Converts a plugin basename back into a friendly slug. */ diff --git a/php/commands/theme.php b/php/commands/theme.php index 33d80413f..b5852c448 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -36,6 +36,53 @@ function status( $args ) { parent::status( $args ); } + /** + * Search wordpress.org theme repo + * + * ## OPTIONS + * + * <theme> + * : A particular theme to search for. + * + * --per_page + * : Optional number of results to display. Defaults to 10. + * + * --fields + * : Ask for specific fields from the API. Defaults to name,slug,author,rating. acceptable values: + * + * **name**: Theme Name + * **slug**: Theme Slug + * **version**: Current Version Number + * **author**: Theme Author + * **preview_url**: Theme Preview URL + * **screenshot_url**: Theme Screenshot URL + * **rating**: Theme Rating + * **num_ratings**: Number of Theme Ratings + * **homepage**: Theme Author's Homepage + * **description**: Theme Description + * + * ## EXAMPLES + * + * wp theme search automattic --per_page=20 + * + * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description + * + * @synopsis <theme> [--per_page=<per_page>] [--fields=<fields>] + */ + public function search( $args, $assoc_args = array() ) { + $term = $args[0]; + $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; + $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author', 'rating' ); + + $api = themes_api( 'query_themes', array( + 'per_page' => $per_page, + 'search' => $term, + ) ); + + parent::search( $api, $fields, 'theme' ); + + } + protected function status_single( $args ) { $theme = $this->parse_name( $args[0] ); @@ -199,6 +246,7 @@ protected function get_item_list() { * @synopsis <theme|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { + $args[0] = $this->parse_search_key( $args[0] ); parent::install( $args, $assoc_args ); } @@ -305,7 +353,7 @@ function _list( $_, $assoc_args ) { * @return object */ private function parse_name( $name ) { - $theme = wp_get_theme( $name ); + $theme = wp_get_theme( $this->parse_search_key( $name ) ); if ( !$theme->exists() ) { WP_CLI::error( "The theme '$name' could not be found." ); @@ -314,6 +362,16 @@ private function parse_name( $name ) { return $theme; } + + /** + * Parse the name of a theme to check if 'search=' exists, and check search transient for the key + * + * @param string name + * @return string + */ + public function parse_search_key( $name ) { + return parent::parse_search_key( $name, 'theme' ); + } } WP_CLI::add_command( 'theme', 'Theme_Command' ); From 9c2407c4ee4cbb60920743d63d381c84b6de7577 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 23:03:22 -0400 Subject: [PATCH 2092/5359] Comply with PHP Strict Standards --- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 0a6e9011b..2e7bd69b0 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -316,7 +316,7 @@ private function get_color( $status ) { * @param array $fields Data fields to display in table. * @param string $data_type Plugin or Theme api endpoint */ - public function search( $api, $fields, $data_type = 'plugin' ) { + public function _search( $api, $fields, $data_type = 'plugin' ) { // Sanitize to 1 of 2 types $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 6e58e676f..83f58f3d1 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -90,7 +90,7 @@ public function search( $args, $assoc_args = array() ) { 'search' => $term, ) ); - parent::search( $api, $fields, 'plugin' ); + parent::_search( $api, $fields, 'plugin' ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index b5852c448..0cec54108 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -79,7 +79,7 @@ public function search( $args, $assoc_args = array() ) { 'search' => $term, ) ); - parent::search( $api, $fields, 'theme' ); + parent::_search( $api, $fields, 'theme' ); } From 7214f815e5fd14538057644d033efbb28fb515d9 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 23:12:39 -0400 Subject: [PATCH 2093/5359] Comply with PHP Strict Standards --- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 2e7bd69b0..edac698eb 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -349,7 +349,7 @@ public function _search( $api, $fields, $data_type = 'plugin' ) { * @param string name * @return string */ - public function parse_search_key( $name, $data_type = 'plugin' ) { + public function _parse_search_key( $name, $data_type = 'plugin' ) { // Sanitize to 1 of 2 types $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 83f58f3d1..f9d0dd517 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -542,7 +542,7 @@ private function parse_name( $name ) { * @return string */ public function parse_search_key( $name ) { - return parent::parse_search_key( $name, 'plugin' ); + return parent::_parse_search_key( $name, 'plugin' ); } /** diff --git a/php/commands/theme.php b/php/commands/theme.php index 0cec54108..4ac4a1af7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -370,7 +370,7 @@ private function parse_name( $name ) { * @return string */ public function parse_search_key( $name ) { - return parent::parse_search_key( $name, 'theme' ); + return parent::_parse_search_key( $name, 'theme' ); } } From 533beebcd0e56bfcd9c3da07e22792f1c5872d5c Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 23:33:27 -0400 Subject: [PATCH 2094/5359] classify_token method doesn't like underscores and throws a "Warning: unknown --per_page parameter" error. --- php/commands/plugin.php | 8 ++++---- php/commands/theme.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index f9d0dd517..be9b61e1d 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -51,7 +51,7 @@ function status( $args ) { * <plugin> * : A particular plugin to search for. * - * --per_page + * --per-page * : Optional number of results to display. Defaults to 10. * * --fields @@ -74,15 +74,15 @@ function status( $args ) { * * ## EXAMPLES * - * wp plugin search dsgnwrks --per_page=20 + * wp plugin search dsgnwrks --per-page=20 * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings * - * @synopsis <plugin> [--per_page=<per_page>] [--fields=<fields>] + * @synopsis <plugin> [--per-page=<per-page>] [--fields=<fields>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; - $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; + $per_page = isset( $assoc_args['per-page'] ) ? (int) $assoc_args['per-page'] : 10; $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author_profile', 'rating' ); $api = plugins_api( 'query_plugins', array( diff --git a/php/commands/theme.php b/php/commands/theme.php index 4ac4a1af7..7894afb42 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -44,7 +44,7 @@ function status( $args ) { * <theme> * : A particular theme to search for. * - * --per_page + * --per-page * : Optional number of results to display. Defaults to 10. * * --fields @@ -63,15 +63,15 @@ function status( $args ) { * * ## EXAMPLES * - * wp theme search automattic --per_page=20 + * wp theme search automattic --per-page=20 * * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description * - * @synopsis <theme> [--per_page=<per_page>] [--fields=<fields>] + * @synopsis <theme> [--per-page=<per-page>] [--fields=<fields>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; - $per_page = isset( $assoc_args['per_page'] ) ? (int) $assoc_args['per_page'] : 10; + $per_page = isset( $assoc_args['per-page'] ) ? (int) $assoc_args['per-page'] : 10; $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author', 'rating' ); $api = themes_api( 'query_themes', array( From 7ddaf5a2e89c82e9fda5129c7e898a130310a5c9 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Sun, 4 Aug 2013 23:34:53 -0400 Subject: [PATCH 2095/5359] update search items found message. Now "Showing $count of $total '$plural." --- php/WP_CLI/CommandWithUpgrade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index edac698eb..7b0b9c168 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -322,7 +322,7 @@ public function _search( $api, $fields, $data_type = 'plugin' ) { $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; $plural = $data_type . 's'; $data = $api->$plural; - $count = isset( $api->info['results'] ) ? $api->info['results'] : count( $data ); + $count = isset( $api->info['results'] ) ? $api->info['results'] : 'unknown'; if ( is_wp_error( $api ) ) \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); @@ -330,7 +330,7 @@ public function _search( $api, $fields, $data_type = 'plugin' ) { if ( ! isset( $data ) ) \WP_CLI::error( __( 'API error. Try Again.' ) ); - \WP_CLI::success( $count .' '. $plural .' Found. \'search=$key\' in place of slug available for '. $data_type .' commands.' ); + \WP_CLI::success( 'Showing '. count( $data ) .' of '. $count .' '. $plural .'. \'search=$key\' in place of slug available for '. $data_type .' commands.' ); foreach ( $data as $key => $item ) { $item->key = $key; From 985cf0e57b7ae4818d50b25d1b97efe1dbe783a4 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Mon, 5 Aug 2013 09:31:48 -0400 Subject: [PATCH 2096/5359] Less is more. All that info won't display well on smaller terminal windows. --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index be9b61e1d..b7e269a35 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -83,7 +83,7 @@ function status( $args ) { public function search( $args, $assoc_args = array() ) { $term = $args[0]; $per_page = isset( $assoc_args['per-page'] ) ? (int) $assoc_args['per-page'] : 10; - $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author_profile', 'rating' ); + $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'rating' ); $api = plugins_api( 'query_plugins', array( 'per_page' => $per_page, From 844612afc73a1afa37599a28f8df3d32b6c4f80f Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 5 Aug 2013 15:50:29 +0200 Subject: [PATCH 2097/5359] Fix notices undefined index post_types when scaffolding CPT Added post_type default value and use $control_args because it it won't be available in $vars --- php/commands/scaffold.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index bdf3435d1..13541038d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -107,13 +107,14 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) 'theme' => false, 'plugin' => false, 'raw' => false, + 'post_types' => false, ) ); $vars = $this->extract_args( $assoc_args, $defaults ); $vars['slug'] = $slug; - $vars['post_types'] = $this->quote_comma_list_elements( $vars['post_types'] ); + $vars['post_types'] = $this->quote_comma_list_elements( $control_args['post_types'] ); $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); From a95b73cb8e69fa9b96d1f8cd02c7f6c2c634b84f Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Mon, 5 Aug 2013 11:49:46 -0400 Subject: [PATCH 2098/5359] Allow formatting for search results. --- php/WP_CLI/CommandWithUpgrade.php | 13 ++++++++----- php/commands/plugin.php | 10 ++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 7b0b9c168..fb0867c23 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -312,11 +312,12 @@ private function get_color( $status ) { /** * Search wordpress.org plugin repo * - * @param object $api data from WP plugin/theme API - * @param array $fields Data fields to display in table. - * @param string $data_type Plugin or Theme api endpoint + * @param object $api Data from WP plugin/theme API + * @param array $fields Data fields to display in table. + * @param array $assoc_args Data passed in from command. + * @param string $data_type Plugin or Theme api endpoint */ - public function _search( $api, $fields, $data_type = 'plugin' ) { + public function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { // Sanitize to 1 of 2 types $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; @@ -339,7 +340,9 @@ public function _search( $api, $fields, $data_type = 'plugin' ) { $set = set_site_transient( 'wpcli-$data_type-search-data', $data, 60*60 ); - \WP_CLI\Utils\format_items( 'table', $data, array_merge( array( 'key' ), $fields ) ); + $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; + + \WP_CLI\Utils\format_items( $format, $data, array_merge( array( 'key' ), $fields ) ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b7e269a35..018e6ab9f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -54,6 +54,9 @@ function status( $args ) { * --per-page * : Optional number of results to display. Defaults to 10. * + * --format + * : Output list as table, CSV or JSON. Defaults to table. + * * --fields * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. acceptable values: * @@ -74,11 +77,11 @@ function status( $args ) { * * ## EXAMPLES * - * wp plugin search dsgnwrks --per-page=20 + * wp plugin search dsgnwrks --per-page=20 --format=json * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings * - * @synopsis <plugin> [--per-page=<per-page>] [--fields=<fields>] + * @synopsis <plugin> [--per-page=<per-page>] [--fields=<fields>] [--format=<format>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; @@ -90,8 +93,7 @@ public function search( $args, $assoc_args = array() ) { 'search' => $term, ) ); - parent::_search( $api, $fields, 'plugin' ); - + parent::_search( $api, $fields, $assoc_args, 'plugin' ); } protected function status_single( $args ) { From 5c2bc1ec3755d937c90884382105f785f6582edb Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Mon, 5 Aug 2013 11:57:10 -0400 Subject: [PATCH 2099/5359] Remove search=$key slug replacement method. :( --- php/WP_CLI/CommandWithUpgrade.php | 21 --------------------- php/commands/plugin.php | 25 +++++++------------------ php/commands/theme.php | 12 +----------- 3 files changed, 8 insertions(+), 50 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index fb0867c23..e0d5a29c9 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -346,25 +346,4 @@ public function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { } - /** - * Parse the name of a plugin to check if 'search=' exists, and check search transient for the key - * - * @param string name - * @return string - */ - public function _parse_search_key( $name, $data_type = 'plugin' ) { - - // Sanitize to 1 of 2 types - $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; - - if ( false !== strpos( $name, 'search=' ) ) { - $search_key = (int) str_replace( 'search=', '', $name ); - if ( ( $trans = get_site_transient( 'wpcli-$data_type-search-data' ) ) && isset( $trans[$search_key] ) ) - $name = $trans[$search_key]->slug; - else - \WP_CLI::error( 'There is no recent search with that key.' ); - } - return $name; - } - } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 018e6ab9f..ebb8d8a01 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -97,7 +97,7 @@ public function search( $args, $assoc_args = array() ) { } protected function status_single( $args ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); $details = $this->get_details( $file ); @@ -147,7 +147,7 @@ protected function get_all_items() { * @synopsis <plugin> [--network] */ function activate( $args, $assoc_args = array() ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -178,7 +178,7 @@ function activate( $args, $assoc_args = array() ) { * @synopsis <plugin> [--network] */ function deactivate( $args, $assoc_args = array() ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -209,7 +209,7 @@ function deactivate( $args, $assoc_args = array() ) { * @synopsis <plugin> [--network] */ function toggle( $args, $assoc_args = array() ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); $network_wide = isset( $assoc_args['network'] ); @@ -300,7 +300,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * @synopsis <plugin> [--version=<version>] */ function update( $args, $assoc_args ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $basename = $this->parse_name( $name ); if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { @@ -397,7 +397,6 @@ protected function get_item_list() { * @synopsis <plugin|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { - $args[0] = $this->parse_search_key( $args[0] ); parent::install( $args, $assoc_args ); } @@ -420,7 +419,7 @@ function install( $args, $assoc_args ) { * @synopsis <plugin> [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); if ( is_plugin_active( $file ) ) { @@ -452,7 +451,7 @@ function uninstall( $args, $assoc_args = array() ) { * @synopsis <plugin> */ function delete( $args, $assoc_args = array() ) { - $name = $this->parse_search_key( $args[0] ); + $name = $args[0]; $file = $this->parse_name( $name ); if ( $this->_delete( $file ) ) { @@ -537,16 +536,6 @@ private function parse_name( $name ) { return $file; } - /** - * Parse the name of a plugin to check if 'search=' exists, and check search transient for the key - * - * @param string name - * @return string - */ - public function parse_search_key( $name ) { - return parent::_parse_search_key( $name, 'plugin' ); - } - /** * Converts a plugin basename back into a friendly slug. */ diff --git a/php/commands/theme.php b/php/commands/theme.php index 7894afb42..8637b6b9f 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -246,7 +246,6 @@ protected function get_item_list() { * @synopsis <theme|zip|url> [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { - $args[0] = $this->parse_search_key( $args[0] ); parent::install( $args, $assoc_args ); } @@ -353,7 +352,7 @@ function _list( $_, $assoc_args ) { * @return object */ private function parse_name( $name ) { - $theme = wp_get_theme( $this->parse_search_key( $name ) ); + $theme = wp_get_theme( $name ); if ( !$theme->exists() ) { WP_CLI::error( "The theme '$name' could not be found." ); @@ -363,15 +362,6 @@ private function parse_name( $name ) { return $theme; } - /** - * Parse the name of a theme to check if 'search=' exists, and check search transient for the key - * - * @param string name - * @return string - */ - public function parse_search_key( $name ) { - return parent::_parse_search_key( $name, 'theme' ); - } } WP_CLI::add_command( 'theme', 'Theme_Command' ); From c6ef951089269640fb133ff99f7a2ccd4f2f688b Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Mon, 5 Aug 2013 12:58:18 -0400 Subject: [PATCH 2100/5359] =?UTF-8?q?THe=20stars=20have=20aligned=E2=80=A6?= =?UTF-8?q?=20https://github.com/wp-cli/wp-cli/pull/630/files#r5583311?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/commands/plugin.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ebb8d8a01..49bdfcde1 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -61,19 +61,19 @@ function status( $args ) { * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. acceptable values: * * **name**: Plugin Name - * **slug**: Plugin Slug - * **version**: Current Version Number - * **author**: Plugin Author - * **author_profile**: Plugin Author Profile - * **contributors**: Plugin Contributors - * **requires**: Plugin Minimum Requirements - * **tested**: Plugin Tested Up To - * **compatibility**: Plugin Compatible With - * **rating**: Plugin Rating - * **num_ratings**: Number of Plugin Ratings - * **homepage**: Plugin Author's Homepage - * **description**: Plugin's Description - * **short_description**: Plugin's Short Description + * **slug**: Plugin Slug + * **version**: Current Version Number + * **author**: Plugin Author + * **author_profile**: Plugin Author Profile + * **contributors**: Plugin Contributors + * **requires**: Plugin Minimum Requirements + * **tested**: Plugin Tested Up To + * **compatibility**: Plugin Compatible With + * **rating**: Plugin Rating + * **num_ratings**: Number of Plugin Ratings + * **homepage**: Plugin Author's Homepage + * **description**: Plugin's Description + * **short_description**: Plugin's Short Description * * ## EXAMPLES * From 03fa3278076b09865cdd12885b12f6424c88e6d3 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Mon, 5 Aug 2013 12:59:23 -0400 Subject: [PATCH 2101/5359] Make _search() a protected method and wrap 'key' field addition in a conditional for 'interactive' (add a @TODO inline comment) https://github.com/wp-cli/wp-cli/pull/630/files#r5583311 --- php/WP_CLI/CommandWithUpgrade.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e0d5a29c9..32f99da43 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -317,7 +317,7 @@ private function get_color( $status ) { * @param array $assoc_args Data passed in from command. * @param string $data_type Plugin or Theme api endpoint */ - public function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { + protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { // Sanitize to 1 of 2 types $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; @@ -333,16 +333,22 @@ public function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { \WP_CLI::success( 'Showing '. count( $data ) .' of '. $count .' '. $plural .'. \'search=$key\' in place of slug available for '. $data_type .' commands.' ); - foreach ( $data as $key => $item ) { - $item->key = $key; - $data[$key] = $item; - } + $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; - $set = set_site_transient( 'wpcli-$data_type-search-data', $data, 60*60 ); + // @TODO https://github.com/wp-cli/wp-cli/issues/635 + if ( isset( $assoc_args['interactive'] ) ) { + // Add key as a field + $fields = array_merge( array( 'key' ), $fields ) : $fields; + // & infuse object with $key + foreach ( $data as $key => $item ) { + $item->key = $key; + $data[$key] = $item; + } + } - $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; + $fields = isset( $assoc_args['interactive'] ) ? array_merge( array( 'key' ), $fields ) : $fields; - \WP_CLI\Utils\format_items( $format, $data, array_merge( array( 'key' ), $fields ) ); + \WP_CLI\Utils\format_items( $format, $data, $fields ); } From d6287f7622ec71653ec0d5b4e52a8b4992183e0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 22:59:21 +0300 Subject: [PATCH 2102/5359] add regression test --- features/help.feature | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index 10626d66a..f8ee09c2b 100644 --- a/features/help.feature +++ b/features/help.feature @@ -20,10 +20,17 @@ Feature: Get help about WP-CLI commands And STDERR should not be empty Scenario: Help for incomplete commands - Given an empty directory + Given a WP install When I run `wp core` Then STDOUT should contain: """ usage: wp core """ + + # See https://github.com/wp-cli/wp-cli/issues/633 + When I run `wp plugin install` + Then STDOUT should contain: + """ + usage: wp plugin install + """ From 10904b79b21652ebbb381b3a5c3ee4389845232b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 5 Aug 2013 23:09:15 +0300 Subject: [PATCH 2103/5359] add unit test for #633 It's better to test for the specific bug, when possible. This reverts commit d6287f7622ec71653ec0d5b4e52a8b4992183e0c. --- features/help.feature | 9 +-------- tests/test-synopsis.php | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/features/help.feature b/features/help.feature index f8ee09c2b..10626d66a 100644 --- a/features/help.feature +++ b/features/help.feature @@ -20,17 +20,10 @@ Feature: Get help about WP-CLI commands And STDERR should not be empty Scenario: Help for incomplete commands - Given a WP install + Given an empty directory When I run `wp core` Then STDOUT should contain: """ usage: wp core """ - - # See https://github.com/wp-cli/wp-cli/issues/633 - When I run `wp plugin install` - Then STDOUT should contain: - """ - usage: wp plugin install - """ diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 22e7cb907..427e2ab9b 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -11,7 +11,7 @@ function testEmpty() { } function testPositional() { - $r = SynopsisParser::parse( '<foo> [<bar>]' ); + $r = SynopsisParser::parse( '<plugin|zip> [<bar>]' ); $this->assertCount( 2, $r ); From e84d1e22ccb613528f8d863e0d8380db37d82bbb Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Mon, 5 Aug 2013 23:54:35 +0200 Subject: [PATCH 2104/5359] Move `--post_types` to taxonomy function Because a CPT doesn't need this arg. --- php/commands/scaffold.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 13541038d..af10af5fb 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -90,9 +90,13 @@ function post_type( $args, $assoc_args ) { function taxonomy( $args, $assoc_args ) { $defaults = array( 'textdomain' => '', - 'post_types' => 'post' + 'post_types' => "'post'" ); + if( isset($assoc_args['post_types']) ) { + $assoc_args['post_types'] = $this->quote_comma_list_elements( $assoc_args['post_types'] ); + } + $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( 'taxonomy.mustache', 'taxonomy_extended.mustache' @@ -107,15 +111,12 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) 'theme' => false, 'plugin' => false, 'raw' => false, - 'post_types' => false, ) ); $vars = $this->extract_args( $assoc_args, $defaults ); $vars['slug'] = $slug; - $vars['post_types'] = $this->quote_comma_list_elements( $control_args['post_types'] ); - $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); $vars['label'] = $control_args['label']; From 1512802316f68d44968c70c9765cbd6ec333e93d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Aug 2013 01:18:32 +0300 Subject: [PATCH 2105/5359] use $p_value instead of $p_name for positional parameters --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index d7e4c1ba1..1da1504ef 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -42,7 +42,7 @@ private static function classify_token( $token ) { if ( '--<field>=<value>' === $token ) { $param['type'] = 'generic'; - } elseif ( preg_match( "/^<$p_name>$/", $token, $matches ) ) { + } elseif ( preg_match( "/^<$p_value>$/", $token, $matches ) ) { $param['type'] = 'positional'; } elseif ( preg_match( "/^--$p_name/", $token, $matches ) ) { $param['name'] = $matches[1]; From aa915668f0b6d7a5a7934a4b9326871a1f984975 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Tue, 6 Aug 2013 01:19:56 +0300 Subject: [PATCH 2106/5359] Add/Remove capabilities for users --- php/commands/user.php | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 8f1a6335b..5f7d010eb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -448,6 +448,62 @@ public function remove_role( $args, $assoc_args ) { WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); } } + + /** + * Add a capability for a user. + * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * <cap> + * : Add the specified capability for the user. + * + * ## EXAMPLES + * + * wp user add-cap john create_premium_item + * wp user add-cap 15 edit_product + * + * @subcommand add-cap + * @synopsis <user> <cap> + */ + public function add_cap( $args, $assoc_args ) { + $user = self::get_user( $args[0] ); + $cap = $args[1]; + + $user->add_cap( $cap ); + + WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); + } + + /** + * Remove a user's capability. + * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * <cap> + * : Capability to be removed. + * + * ## EXAMPLES + * + * wp user remove-cap bob edit_themes + * wp user remove-cap 11 publish_newsletters + * + * @subcommand remove-cap + * @synopsis <user> <cap> + */ + public function remove_cap( $args, $assoc_args ) { + $user = self::get_user( $args[0] ); + $cap = $args[1]; + + $user->remove_cap( $cap ); + + WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); + } private static function get_user( $id_or_login ) { if ( is_numeric( $id_or_login ) ) From de37f20f4d1c230abcc2669680bf16f830083eab Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Aug 2013 01:58:33 +0300 Subject: [PATCH 2107/5359] add array_column() polyfill for PHP<5.5 --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 886935c21..a61727777 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "require": { "php": ">=5.3.2", "wp-cli/php-cli-tools": "0.9.3", - "mustache/mustache": "~2.4" + "mustache/mustache": "~2.4", + "rhumsaa/array_column": "~1.1" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" From 9078761a789880789eadfc0b6e613e0c15217d8b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Aug 2013 02:04:13 +0300 Subject: [PATCH 2108/5359] show warning for invalid synopsis parts --- php/WP_CLI/Dispatcher/Subcommand.php | 9 +++++++++ php/WP_CLI/SynopsisValidator.php | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 16d101e3f..45be83bd0 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -43,6 +43,15 @@ private function validate_args( $args, &$assoc_args ) { return; $parser = new \WP_CLI\SynopsisValidator( $synopsis ); + + $cmd_path = implode( ' ', get_path( $this ) ); + foreach ( $parser->get_unknown() as $token ) { + \WP_CLI::warning( sprintf( + "The `%s` command has an invalid synopsis part: %s", + $cmd_path, $token + ) ); + } + if ( !$parser->enough_positionals( $args ) ) { $this->show_usage(); exit(1); diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 4b62a364e..90a7cb877 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -13,6 +13,12 @@ public function __construct( $synopsis ) { $this->spec = SynopsisParser::parse( $synopsis ); } + public function get_unknown() { + return array_column( $this->query_spec( array( + 'type' => 'unknown', + ) ), 'token' ); + } + public function enough_positionals( $args ) { $positional = $this->query_spec( array( 'type' => 'positional', From 0423c4bdea8d9c00c8a5c22ede5b332357687b27 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Tue, 6 Aug 2013 02:08:18 +0300 Subject: [PATCH 2109/5359] Add capabilities list function for users --- php/commands/user.php | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 5f7d010eb..e1aca7ac6 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -504,6 +504,44 @@ public function remove_cap( $args, $assoc_args ) { WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); } + + /** + * List all user's capabilities. + * + * ## OPTIONS + * + * <user> + * : User ID or user login. + * + * ## EXAMPLES + * + * wp user list-caps admin + * wp user list-caps 21 + * + * @subcommand list-caps + * @synopsis <user> + */ + public function list_caps( $args, $assoc_args ) { + $user = self::get_user( $args[0] ); + $user->get_role_caps(); + + $user_caps_list = $user->allcaps; + $cap_table_titles = array( 'capability', 'status' ); + + // Get all active caps (marked as true) + $active_user_caps = array(); + + foreach( $user_caps_list as $cap => $active ) { + if( $active ) { + $active_user_caps[] = $cap; + } + } + + // Omit formatting from the Utils class due to the assoc array format + $user_caps = implode( ', ', $active_user_caps ); + + WP_CLI::success( sprintf( "User caps (role and individual) are: %s.", $user_caps ) ); + } private static function get_user( $id_or_login ) { if ( is_numeric( $id_or_login ) ) From e35799b1fa726793ec341a6ec30cf38ecb8664b4 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Tue, 6 Aug 2013 02:22:10 +0300 Subject: [PATCH 2110/5359] Listing each cap on a separate line --- php/commands/user.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index e1aca7ac6..8fcb031bc 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -527,20 +527,14 @@ public function list_caps( $args, $assoc_args ) { $user_caps_list = $user->allcaps; $cap_table_titles = array( 'capability', 'status' ); - - // Get all active caps (marked as true) - $active_user_caps = array(); + + WP_CLI::success( "User caps (role and individual) are: " ); foreach( $user_caps_list as $cap => $active ) { if( $active ) { - $active_user_caps[] = $cap; + \cli\line( $cap ); } } - - // Omit formatting from the Utils class due to the assoc array format - $user_caps = implode( ', ', $active_user_caps ); - - WP_CLI::success( sprintf( "User caps (role and individual) are: %s.", $user_caps ) ); } private static function get_user( $id_or_login ) { From 1fe10ae4e5efd83ef8f74b552bd5e0c1cc4ec3db Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Aug 2013 03:06:02 +0300 Subject: [PATCH 2111/5359] colorize update candidates. fixes #638 --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index aaac62ed9..8e3e6c8c7 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -192,7 +192,7 @@ function update_all( $args, $assoc_args ) { } } - \WP_CLI::line( $item_list ); + \WP_CLI::line( \WP_CLI::colorize( $item_list ) ); return; } From d8448f5a7e894a8a7e0509dd379bb10a541d48e1 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Tue, 6 Aug 2013 04:03:37 +0300 Subject: [PATCH 2112/5359] First test cases in Behat for capability management --- features/user.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/user.feature b/features/user.feature index ced0e4192..43bfe2ae4 100644 --- a/features/user.feature +++ b/features/user.feature @@ -92,3 +92,24 @@ Feature: Manage WordPress users Then STDOUT should be a table containing rows: | Field | Value | | roles | | + + Scenario: Managing user capabilities + Given a WP install + + When I run `wp user add-cap 1 edit_vip_product` + Then STDOUT should be: + """ + Success: Added 'edit_vip_product' capability for admin (1). + """ + + And I run `wp user list-caps 1 | tail -n 1` + Then STDOUT should be: + """ + edit_vip_product + """ + + And I run `wp user remove-cap 1 edit_vip_product` + Then STDOUT should be: + """ + Success: Removed 'edit_vip_product' cap for admin (1). + """ From 2c08a390f81da650a4fcddaee567a6751611b607 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 6 Aug 2013 13:38:35 +0300 Subject: [PATCH 2113/5359] introduce WP_CLI_PHP_ARGS environment variable also, remove old Drush code for looking up php.ini files fixes #631 --- bin/wp | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/bin/wp b/bin/wp index 706f6c9fd..762d6f5d9 100755 --- a/bin/wp +++ b/bin/wp @@ -39,28 +39,8 @@ else php=`which php` fi -# Check to see if the user has provided a php.ini file or wp-cli.ini file in any conf dir -# Last found wins, so search in reverse priority order -for conf_dir in $(dirname "$SELF_PATH") /etc/wp-cli $HOME/.wp-cli ; do - if [ -f $conf_dir/php.ini ] ; then - wp_cli_php_ini=$conf_dir/php.ini - fi - if [ -f $conf_dir/wp-cli.ini ] ; then - wp_cli_php_override=$conf_dir/wp-cli.ini - fi -done - -# Add in the php file location and/or the php override variables as appropriate -if [ "x$wp_cli_php_ini" != "x" ] ; then - php="$php --php-ini $wp_cli_php_ini" -fi -if [ "x$wp_cli_php_override" != "x" ] ; then - wp_cli_override_vars=`grep '^[a-z_A-Z0-9]\+ *=' $wp_cli_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' ' '` - php="$php $wp_cli_override_vars" -fi - -export WP_CLI_PHP_USED=$php - # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands -exec "$php" "$SCRIPT_PATH" "$@" +export WP_CLI_PHP_USED=$php + +exec "$php" $WP_CLI_PHP_ARGS "$SCRIPT_PATH" "$@" From 527e9d02c9802d7e7f8fa9c5fd35871946f1a51f Mon Sep 17 00:00:00 2001 From: Alex Ciobica <alex.ciobica@gmail.com> Date: Tue, 6 Aug 2013 14:33:04 +0300 Subject: [PATCH 2114/5359] Fix search replace reserved column name issues. --- php/commands/search-replace.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 418559810..c1e4b0070 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -101,10 +101,12 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry // We don't want to have to generate thousands of rows when running the test suite $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; + $fields = array( $primary_key, $col ); + $fields = array_map( function ($v) { return "`$v`"; }, $fields ); $args = array( 'table' => $table, - 'fields' => array( $primary_key, $col ), - 'where' => $col . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', + 'fields' => $fields, + 'where' => "`$col`" . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', 'chunk_size' => $chunk_size ); From 8a10e302b8376febec4ed7d5db3671a87708dd13 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 6 Aug 2013 18:38:26 +0100 Subject: [PATCH 2115/5359] Use `wp_parse_args()` where we can --- php/WP_CLI/CommandWithUpgrade.php | 11 ++--------- php/commands/post.php | 9 +-------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index aaac62ed9..6331de338 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -219,19 +219,12 @@ function update_all( $args, $assoc_args ) { } } - protected function _list( $_, $format ) { + protected function _list( $_, $assoc_args ) { $values = array( 'format' => 'table', 'fields' => $this->fields ); - - foreach ( $values as $key => &$value ) { - if ( isset( $format[ $key ] ) ) { - $value = $format[ $key ]; - unset( $format[ $key ] ); - } - } - unset( $value ); + $values = wp_parse_args( $assoc_args, $values ); $all_items = $this->get_all_items(); $items = $this->create_objects( $all_items ); diff --git a/php/commands/post.php b/php/commands/post.php index 179283099..7465cc51d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -168,14 +168,7 @@ public function _list( $_, $assoc_args ) { 'format' => 'table', 'fields' => $this->fields ); - - foreach ( $values as $key => &$value ) { - if ( isset( $assoc_args[ $key ] ) ) { - $value = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } - unset( $value ); + $values = wp_parse_args( $assoc_args, $values ); foreach ( $assoc_args as $key => $value ) { if ( true === $value ) From 0be7a0cf0d895fecba182b360aee25c73d88a015 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 00:47:19 +0300 Subject: [PATCH 2116/5359] add regression test for #645 --- features/help.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/help.feature b/features/help.feature index 10626d66a..b0225d0c0 100644 --- a/features/help.feature +++ b/features/help.feature @@ -19,6 +19,36 @@ Feature: Get help about WP-CLI commands Then the return code should be 1 And STDERR should not be empty + Scenario: Help for third-party commands + Given a WP install + And a wp-content/plugins/test-cli/command.php file: + """ + <?php + // Plugin Name: Test CLI Help + + class Test_Help extends WP_CLI_Command { + /** + * A dummy command. + */ + function __invoke() {} + } + + WP_CLI::add_command( 'test-help', 'Test_Help' ); + """ + And I run `wp plugin activate test-cli` + + When I run `wp help` + Then STDOUT should contain: + """ + A dummy command. + """ + + When I run `wp help test-help` + Then STDOUT should contain: + """ + wp test-help + """ + Scenario: Help for incomplete commands Given an empty directory From f44778231014f7531ac8745e43332d1a65600f7f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 01:39:37 +0300 Subject: [PATCH 2117/5359] show commands defined in plugins when running 'wp help' --- php/WP_CLI/Runner.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4d11ffc4a..1502ac7b3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -337,8 +337,12 @@ private function init_logger() { WP_CLI::set_logger( $logger ); } + private function wp_exists() { + return is_readable( ABSPATH . 'wp-includes/version.php' ); + } + private function check_wp_version() { - if ( !is_readable( ABSPATH . 'wp-includes/version.php' ) ) { + if ( !$this->wp_exists() ) { WP_CLI::error( "This does not seem to be a WordPress install.\n" . "Pass --path=`path/to/wordpress` or run `wp core download`." ); @@ -410,14 +414,15 @@ public function before_wp_load() { } } + // Handle --path parameter + self::set_wp_root( $this->config ); + // First try at showing man page - if ( $this->cmd_starts_with( array( 'help' ) ) ) { + if ( 'help' === $this->arguments[0] && + ( isset( $this->arguments[1] ) || !$this->wp_exists() ) ) { $this->_run_command(); } - // Handle --path parameter - self::set_wp_root( $this->config ); - // Handle --url and --blog parameters $url = self::guess_url( $this->config ); if ( $url ) { From 9eaab03283f4a8a30e91c0b2c6bf091d67ff0f1e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 02:35:23 +0300 Subject: [PATCH 2118/5359] add test for #634 --- features/option.feature | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/features/option.feature b/features/option.feature index 66c8d78e2..a009349d3 100644 --- a/features/option.feature +++ b/features/option.feature @@ -3,29 +3,46 @@ Feature: Manage WordPress options Scenario: Option CRUD Given a WP install - When I run `wp option add foo 'bar'` + # String values + When I run `wp option add str_opt 'bar'` Then STDOUT should not be empty - When I run `wp option get foo` + When I run `wp option get str_opt` Then STDOUT should be: """ bar """ - When I run `wp option set foo '[ 1, 2 ]' --format=json` + When I run `wp option delete str_opt` + Then STDOUT should not be empty + + When I try `wp option get str_opt` + Then the return code should be 1 + + + # Integer values + When I run `wp option update blog_public 0` Then STDOUT should not be empty When I run the previous command again Then STDOUT should not be empty - When I run `wp option get foo --format=json` + When I run `wp option get blog_public` Then STDOUT should be: """ - [1,2] + 0 """ - When I run `wp option delete foo` + + # JSON values + When I run `wp option set json_opt '[ 1, 2 ]' --format=json` Then STDOUT should not be empty - When I try `wp option get foo` - Then the return code should be 1 + When I run the previous command again + Then STDOUT should not be empty + + When I run `wp option get json_opt --format=json` + Then STDOUT should be: + """ + [1,2] + """ From f98a6f19fa6ca169e8e97ee3509dc1c410c56598 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 02:26:41 +0300 Subject: [PATCH 2119/5359] option update: use non-strict comparison --- php/commands/option.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index ccefe5bf4..a825342c5 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -67,7 +67,7 @@ public function update( $args, $assoc_args ) { $result = update_option( $key, $value ); // update_option() returns false if the value is the same - if ( !$result && $value !== get_option( $key ) ) { + if ( !$result && $value != get_option( $key ) ) { WP_CLI::error( "Could not update option '$key'." ); } else { WP_CLI::success( "Updated '$key' option." ); From e1f49a5c8ee7d4eaabf5f2be895927890f64249b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 02:55:27 +0300 Subject: [PATCH 2120/5359] bump version to 0.11.1-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index d435efe16..62cff3bfd 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.0' ); +define( 'WP_CLI_VERSION', '0.11.1-alpha' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 57e642f163985713f4eabb9a57ebdbb17d1a987a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 7 Aug 2013 03:16:50 +0300 Subject: [PATCH 2121/5359] move column escaping down into the table iterator see #641 --- php/WP_CLI/Iterators/Table.php | 13 ++++++++----- php/commands/search-replace.php | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 6e05cf9ed..441b69dc7 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -8,7 +8,7 @@ class Table extends Query { /** - * Creates an iterator over a database table + * Creates an iterator over a database table. * * <code> * foreach( new Iterators\Table( array( 'table' => $wpdb->posts, 'fields' => array( 'ID', 'post_content' ) ) ) as $post ) { @@ -31,7 +31,7 @@ class Table extends Query { * * @param array $args Supported arguments: * table – the name of the database table - * fields – an array of columns to get from the posst table, * is a valid value and the default + * fields – an array of columns to get from the table, '*' is a valid value and the default * where – conditions for filtering rows. Supports two formats: * = string – this will be the where clause * = array – each element is treated as a condition if it's positional, or as column => value if @@ -41,7 +41,7 @@ function __construct( $args = array() ) { global $wpdb; $defaults = array( - 'fields' => array( '*' ), + 'fields' => '*', 'where' => array(), 'table' => null, 'chunk_size' => 500 @@ -51,14 +51,17 @@ function __construct( $args = array() ) { $fields = self::build_fields( $args['fields'] ); $conditions = self::build_where_conditions( $args['where'] ); - $where_sql = $conditions? " WHERE $conditions" : ''; + $where_sql = $conditions ? " WHERE $conditions" : ''; $query = "SELECT $fields FROM $table $where_sql"; parent::__construct( $query, $args['chunk_size'] ); } private static function build_fields( $fields ) { - return implode( ', ', $fields ); + if ( '*' === $fields ) + return $fields; + + return implode( ', ', array_map( function ($v) { return "`$v`"; }, $fields ) ); } private static function build_where_conditions( $where ) { diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c1e4b0070..7cbb52019 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -102,7 +102,6 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; $fields = array( $primary_key, $col ); - $fields = array_map( function ($v) { return "`$v`"; }, $fields ); $args = array( 'table' => $table, 'fields' => $fields, From 0a831399559951ff1e8b277c874ed6a42400a731 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Wed, 7 Aug 2013 15:42:03 -0400 Subject: [PATCH 2122/5359] Whoops! parse_error fixed. --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 32f99da43..b50803de7 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -338,7 +338,7 @@ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) // @TODO https://github.com/wp-cli/wp-cli/issues/635 if ( isset( $assoc_args['interactive'] ) ) { // Add key as a field - $fields = array_merge( array( 'key' ), $fields ) : $fields; + $fields = array_merge( array( 'key' ), $fields ); // & infuse object with $key foreach ( $data as $key => $item ) { $item->key = $key; From 3085c6657a6a22e7bad8734b86dfada6d8125117 Mon Sep 17 00:00:00 2001 From: Josh Betz <j@joshbetz.com> Date: Wed, 7 Aug 2013 22:30:08 -0500 Subject: [PATCH 2123/5359] Add is-installed command to wp-cli --- php/commands/plugin.php | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 667e5dc66..48523213f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -383,6 +383,30 @@ function uninstall( $args, $assoc_args = array() ) { } } + + /** + * Check if the plugin is installed + * + * ## OPTIONS + * + * <plugin> + * : The plugin to check. + * + * ## EXAMPLES + * + * wp plugin is-installed hello + * + * @subcommand is-installed + * @synopsis <plugin> + */ + function is_installed( $args, $assoc_args = array() ) { + if ( $this->_parse_name( $args[0] ) ) { + exit( 0 ); + } else { + exit( 1 ); + } + } + /** * Delete plugin files. * @@ -463,7 +487,7 @@ protected function get_details( $file ) { * @param string name * @return string */ - private function parse_name( $name ) { + private function _parse_name( $name ) { $plugins = get_plugins( '/' . $name ); if ( !empty( $plugins ) ) { @@ -475,14 +499,22 @@ private function parse_name( $name ) { $plugins = get_plugins(); if ( !isset( $plugins[$file] ) ) { - WP_CLI::error( "The plugin '$name' could not be found." ); - exit(); + return false; } } return $file; } + private function parse_name( $name ) { + if ( $file = $this->_parse_name( $name ) ) { + return $file; + } else { + WP_CLI::error( "The plugin '$name' could not be found." ); + exit(); + } + } + /** * Converts a plugin basename back into a friendly slug. */ From 0440af257a912f21cf8405782a2c85359328ba00 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 16:14:32 +0300 Subject: [PATCH 2124/5359] update .mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 310cb19b8..76512b890 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,7 @@ andreascreten <andreas@madewithlove.be> bendoh <ben@thinkoomph.com> builtbylane <lanegoldberg@gmail.com> +c10b10 <alex.ciobica@gmail.com> conatus <alex@recordsonribs.com> cyberhobo <dylan.k.kuhn@gmail.com> dangardner <dan@web.nearest.to> From 49c31f899939461569553bf0745ecfea285f6e50 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 16:15:04 +0300 Subject: [PATCH 2125/5359] bump version to 0.11.1 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 62cff3bfd..27679afdd 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.1-alpha' ); +define( 'WP_CLI_VERSION', '0.11.1' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 37896391908934c16d95effdad3962cf8dc8fe1e Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Thu, 8 Aug 2013 17:00:38 +0300 Subject: [PATCH 2126/5359] Adding some checks for non-existing users --- php/commands/user.php | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 8fcb031bc..269a38dec 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -470,11 +470,12 @@ public function remove_role( $args, $assoc_args ) { */ public function add_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - $cap = $args[1]; - - $user->add_cap( $cap ); - - WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); + if( $user ) { + $cap = $args[1]; + $user->add_cap( $cap ); + + WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); + } } /** @@ -498,11 +499,12 @@ public function add_cap( $args, $assoc_args ) { */ public function remove_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - $cap = $args[1]; - - $user->remove_cap( $cap ); - - WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); + if( $user ) { + $cap = $args[1]; + $user->remove_cap( $cap ); + + WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); + } } /** @@ -523,16 +525,19 @@ public function remove_cap( $args, $assoc_args ) { */ public function list_caps( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - $user->get_role_caps(); - $user_caps_list = $user->allcaps; - $cap_table_titles = array( 'capability', 'status' ); - - WP_CLI::success( "User caps (role and individual) are: " ); - - foreach( $user_caps_list as $cap => $active ) { - if( $active ) { - \cli\line( $cap ); + if( $user ) { + $user->get_role_caps(); + + $user_caps_list = $user->allcaps; + $cap_table_titles = array( 'capability', 'status' ); + + WP_CLI::success( "User caps (role and individual) are: " ); + + foreach( $user_caps_list as $cap => $active ) { + if( $active ) { + \cli\line( $cap ); + } } } } From c4c0f88d898c4c5fa98482e8c3a186568cacdd62 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Thu, 8 Aug 2013 17:19:45 +0300 Subject: [PATCH 2127/5359] Check for existing file when trying to import CSV --- php/commands/user.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 269a38dec..d7a8a0c21 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -582,6 +582,10 @@ public function import_csv( $args, $assoc_args ) { $blog_users = get_users(); $filename = $args[0]; + + if (! file_exists( $filename ) ) { + WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + } foreach ( new \WP_CLI\Iterators\CSV( $filename ) as $i => $new_user ) { $defaults = array( From 778f7ad488b2f6704883b5f2a88b2f4bc5cdfe95 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 18:23:50 +0300 Subject: [PATCH 2128/5359] bump version to 0.12-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 27679afdd..4baaf4d21 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.11.1' ); +define( 'WP_CLI_VERSION', '0.12-alpha' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From ad3a3ee95e491561fadefb9c20ce894fcfbe2d90 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 18:27:10 +0300 Subject: [PATCH 2129/5359] remove success message from 'wp user list-caps'; fix coding standards; see #637 --- php/commands/user.php | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index d7a8a0c21..521e142f7 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -152,7 +152,7 @@ public function delete( $args, $assoc_args ) { 'reassign' => null ) ); - foreach( $args as $key => $arg ) { + foreach ( $args as $key => $arg ) { $args[$key] = self::get_user( $arg )->ID; } parent::delete( $args, $assoc_args ); @@ -279,7 +279,7 @@ protected function _create( $params ) { */ public function update( $args, $assoc_args ) { - foreach( $args as $key => $arg ) { + foreach ( $args as $key => $arg ) { $args[$key] = self::get_user( $arg )->ID; } parent::update( $args, $assoc_args, 'user' ); @@ -448,7 +448,7 @@ public function remove_role( $args, $assoc_args ) { WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); } } - + /** * Add a capability for a user. * @@ -470,14 +470,14 @@ public function remove_role( $args, $assoc_args ) { */ public function add_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - if( $user ) { - $cap = $args[1]; + if ( $user ) { + $cap = $args[1]; $user->add_cap( $cap ); WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); } } - + /** * Remove a user's capability. * @@ -499,14 +499,14 @@ public function add_cap( $args, $assoc_args ) { */ public function remove_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - if( $user ) { + if ( $user ) { $cap = $args[1]; $user->remove_cap( $cap ); WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); } } - + /** * List all user's capabilities. * @@ -525,17 +525,15 @@ public function remove_cap( $args, $assoc_args ) { */ public function list_caps( $args, $assoc_args ) { $user = self::get_user( $args[0] ); - - if( $user ) { + + if ( $user ) { $user->get_role_caps(); - + $user_caps_list = $user->allcaps; $cap_table_titles = array( 'capability', 'status' ); - - WP_CLI::success( "User caps (role and individual) are: " ); - - foreach( $user_caps_list as $cap => $active ) { - if( $active ) { + + foreach ( $user_caps_list as $cap => $active ) { + if ( $active ) { \cli\line( $cap ); } } @@ -582,8 +580,8 @@ public function import_csv( $args, $assoc_args ) { $blog_users = get_users(); $filename = $args[0]; - - if (! file_exists( $filename ) ) { + + if ( ! file_exists( $filename ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); } @@ -634,7 +632,7 @@ public function import_csv( $args, $assoc_args ) { delete_user_option( $user_id, 'user_level' ); } - if (!empty($existing_user)) { + if ( !empty( $existing_user ) ) { WP_CLI::success( $new_user['user_login'] . " updated" ); } else { WP_CLI::success( $new_user['user_login'] . " created" ); From 38c60f387016a589bd9011128cb177ed3a8017a8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 21:31:15 +0300 Subject: [PATCH 2130/5359] add more info about Behat --- CONTRIBUTING.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3580119b9..b049aafae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,17 +27,30 @@ All the test dependencies can be installed using [Composer](http://getcomposer.o php composer.phar install --dev -Before running the tests, you'll need a MySQL user called `wp_cli_test` with the +### Unit tests + +To run the unit tests, just execute: + + vendor/bin/phpunit + +### Functional tests + +Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; -Finally, to run the tests: +Then, to run the entire test suite: - vendor/bin/phpunit vendor/bin/behat --expand +Or to test a single feature: + + vendor/bin/behat features/core.feature + +More info can be found from `vendor/bin/behat --help`. + Finally... ---------- From c823207310378a91c84c366f094c65512e0348e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 8 Aug 2013 21:33:50 +0300 Subject: [PATCH 2131/5359] mention where the test files are --- CONTRIBUTING.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b049aafae..a3d736e4f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,14 +9,12 @@ So you've got an awesome idea to throw into WP-CLI. Great! Here's the process, i It doesn't matter if the code isn't perfect. The idea is to get feedback early and iterate. -If you're adding a new feature, please add one or more functional tests for it in the `features` directory. See below. - -Also, please create or update the appropriate `.txt` file in the `man-src` directory. See below. +If you're adding a new feature, please add one or more functional tests for it in the `features/` directory. See below. Lastly, please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). -Running the tests ------------------ +Running and writing tests +------------------------- There are two types of tests: @@ -33,6 +31,8 @@ To run the unit tests, just execute: vendor/bin/phpunit +The test files are in the `tests/` directory. + ### Functional tests Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the @@ -51,6 +51,8 @@ Or to test a single feature: More info can be found from `vendor/bin/behat --help`. +The feature files are in the `features/` directory. + Finally... ---------- From 309875b01ceaa4c567c1033b43b80c97913c7c65 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 02:24:14 +0300 Subject: [PATCH 2132/5359] Add requests support in composer and for core command --- composer.json | 8 +++++--- php/commands/core.php | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index a61727777..0153f1c6b 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.4", - "rhumsaa/array_column": "~1.1" + "rhumsaa/array_column": "~1.1", + "rmccue/requests": ">=1.0" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" @@ -21,6 +22,7 @@ "behat/behat": "~2.4" }, "autoload": { - "psr-0": { "WP_CLI": "php" } - } + "psr-0": { "WP_CLI": "php", "Requests": "library/" } + }, + "minimum-stability": "dev" } diff --git a/php/commands/core.php b/php/commands/core.php index 5d21f820d..999d55be6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -60,16 +60,40 @@ public function download( $args, $assoc_args ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). $temp = tempnam( sys_get_temp_dir(), "wp_" ); - $cmd = "curl -f $silent %s > $temp && tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; - WP_CLI::launch( Utils\esc_cmd( $cmd, $download_url, ABSPATH ) ); + + $headers = array('Accept' => 'application/json'); + $options = array( + 'verify' => false, + 'timeout' => 30, + 'filename' => $temp + ); + + try { + $request = Requests::get( $download_url, $headers, $options ); + } catch( Requests_Exception $ex ) { + WP_CLI::error( $ex->getMessage() ); + } + + $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; + + WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); } private static function _read( $url ) { - exec( 'curl -s ' . escapeshellarg( $url ), $lines, $r ); - if ( $r ) exit( $r ); - return implode( "\n", $lines ); + $headers = array('Accept' => 'application/json'); + $options = array(); + + $r = false; + try { + $request = Requests::get( $url, $headers, $options ); + $r = $request->body; + } catch( Requests_Exception $ex ) { + WP_CLI::error( $ex->getMessage() ); + } + + return $r; } private function get_download_offer( $locale ) { @@ -155,11 +179,11 @@ public function config( $_, $assoc_args ) { } // TODO: adapt more resilient code from wp-admin/setup-config.php + $assoc_args['keys-and-salts'] = self::_read( 'https://api.wordpress.org/secret-key/1.1/salt/' ); $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); - file_put_contents( ABSPATH . 'wp-config.php', $out ); WP_CLI::success( 'Generated wp-config.php file.' ); From de42b819c3ebc310aa78084c8ac3d165fd6778d1 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 02:43:19 +0300 Subject: [PATCH 2133/5359] Remove the minimum-stability argument --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0153f1c6b..1926311cf 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,5 @@ }, "autoload": { "psr-0": { "WP_CLI": "php", "Requests": "library/" } - }, - "minimum-stability": "dev" + } } From e5ba26e5369c2b66448f7e4ccd4f7b017636fdba Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 02:46:58 +0300 Subject: [PATCH 2134/5359] Remove Requests: library/ from composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1926311cf..57edd006b 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,6 @@ "behat/behat": "~2.4" }, "autoload": { - "psr-0": { "WP_CLI": "php", "Requests": "library/" } + "psr-0": { "WP_CLI": "php" } } } From 257f4648fbd49e94590ba229dee187a27f5537ef Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 02:53:17 +0300 Subject: [PATCH 2135/5359] Return minimum-stability due to https://github.com/rmccue/Requests/issues/43 --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 57edd006b..1cf0a5510 100644 --- a/composer.json +++ b/composer.json @@ -23,5 +23,6 @@ }, "autoload": { "psr-0": { "WP_CLI": "php" } - } + }, + "minimum-stability": "dev" } From 17d6323e71b023033d0bb70d2deb5ef0d66fc399 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 03:13:32 +0300 Subject: [PATCH 2136/5359] Add fallback to verify=false argument which works when certificate issues occur --- php/commands/core.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 999d55be6..88632e425 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -63,7 +63,6 @@ public function download( $args, $assoc_args ) { $headers = array('Accept' => 'application/json'); $options = array( - 'verify' => false, 'timeout' => 30, 'filename' => $temp ); @@ -71,7 +70,14 @@ public function download( $args, $assoc_args ) { try { $request = Requests::get( $download_url, $headers, $options ); } catch( Requests_Exception $ex ) { - WP_CLI::error( $ex->getMessage() ); + // Handle SSL certificate issues gracefully + $options['verify'] = false; + try { + $request = Requests::get( $download_url, $headers, $options ); + } + catch( Requests_Exception $ex ) { + WP_CLI::error( $ex->getMessage() ); + } } $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; @@ -90,7 +96,14 @@ private static function _read( $url ) { $request = Requests::get( $url, $headers, $options ); $r = $request->body; } catch( Requests_Exception $ex ) { - WP_CLI::error( $ex->getMessage() ); + // Handle SSL certificate issues gracefully + $options['verify'] = false; + try { + $request = Requests::get( $url, $headers, $options ); + $r = $request->body; + } catch( Requests_Exception $ex ) { + WP_CLI::error( $ex->getMessage() ); + } } return $r; From deff1ce419b4ecc18e07aaba7b16dbe9bddc537a Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 03:15:49 +0300 Subject: [PATCH 2137/5359] Add Behat tests for comments (approve/unapprove/exists commands) --- features/comment.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 features/comment.feature diff --git a/features/comment.feature b/features/comment.feature new file mode 100644 index 000000000..c2ca7bf32 --- /dev/null +++ b/features/comment.feature @@ -0,0 +1,20 @@ +Feature: Manage WordPress comments + + Scenario: Creating/updating/deleting comments + Given a WP install + + When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --porcelain` + Then STDOUT should match '%d' + And save STDOUT as {COMMENT_ID} + + When I run `wp comment exists {POST_ID}` + Then STDOUT should be: + """ + Success: Comment with ID {POST_ID} exists. + """ + + When I run `wp comment delete {POST_ID}` + Then STDOUT should be: + """ + Success: Deleted comment {POST_ID}. + """ From 1b837585c6a530dc9677d54db9fb82def81acd64 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Thu, 8 Aug 2013 23:13:27 -0400 Subject: [PATCH 2138/5359] Remove 'search=$key' helper text --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b50803de7..5626ffe33 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -331,7 +331,7 @@ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) if ( ! isset( $data ) ) \WP_CLI::error( __( 'API error. Try Again.' ) ); - \WP_CLI::success( 'Showing '. count( $data ) .' of '. $count .' '. $plural .'. \'search=$key\' in place of slug available for '. $data_type .' commands.' ); + \WP_CLI::success( 'Showing '. count( $data ) .' of '. $count .' '. $plural .'.' ); $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; From b1dec554cf73a4a3c667d1921b2d7af6d43d7521 Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Thu, 8 Aug 2013 23:13:56 -0400 Subject: [PATCH 2139/5359] 3rd parameter needs to be $assoc_args --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 8637b6b9f..9adcce6ed 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -79,7 +79,7 @@ public function search( $args, $assoc_args = array() ) { 'search' => $term, ) ); - parent::_search( $api, $fields, 'theme' ); + parent::_search( $api, $fields, $assoc_args, 'theme' ); } From aa5d71879cf3f2946f02b3bcb63c72f122473a5f Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Thu, 8 Aug 2013 23:14:27 -0400 Subject: [PATCH 2140/5359] Add a plugin/theme search behat test --- features/upgradables.feature | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 7ca5b06ae..a7fe00a80 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -93,8 +93,17 @@ Feature: Manage WordPress themes and plugins """ And the <file_to_check> file should not exist + When I run `wp <type> search <item> --per-page=1 --fields=name,slug` + Then STDOUT should contain: + """ + Showing 1 of + """ + And STDOUT should contain: + """ + <item_title> + """ Examples: - | type | type_name | item | version | zip_file | file_to_check | - | theme | Theme | p2 | 1.0.1 | http://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | - | plugin | Plugin | category-checklist-tree | 1.2 | http://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | + | type | type_name | item | item_title | version | zip_file | file_to_check | + | theme | Theme | p2 | P2 | 1.0.1 | http://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | + | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | http://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | From 8567deff150b25b3094140be07df5fd145b4228c Mon Sep 17 00:00:00 2001 From: jtsternberg <me@jtsternberg.com> Date: Fri, 9 Aug 2013 02:21:51 -0400 Subject: [PATCH 2141/5359] Add a new test, "should end with a table containing rows:" --- features/steps/basic_steps.php | 34 ++++++++++++++++++++++++++++++++++ features/upgradables.feature | 7 +++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 6d84fdc60..74d494b57 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -190,6 +190,40 @@ function ( $world, TableNode $expected ) { } ); +$steps->Then( '/^STDOUT should end with a table containing rows:$/', + function ( $world, TableNode $expected ) { + $output = $world->result->STDOUT; + $outputRows = explode( "\n", rtrim( $output, "\n" ) ); + + $expectedRows = array(); + foreach ( $expected->getRows() as $row ) { + $expectedRows[] = $world->replace_variables( implode( "\t", $row ) ); + } + + $remainingRows = array(); + $start = false; + foreach( $outputRows as $key => $row ) { + + // the first row is the header and must be present + if ( $expectedRows[0] == $row ) + $start = true; + + if ( $start ) + $remainingRows[] = $row; + } + + if ( ! $start ) + throw new \Exception( $output ); + + unset($remainingRows[0]); + unset($expectedRows[0]); + $matches = array_intersect( $expectedRows, $remainingRows ); + + if ( count( $expectedRows ) != count( $matches ) ) + throw new \Exception( $output ); + } +); + $steps->Then( '/^STDOUT should be JSON containing:$/', function ( $world, PyStringNode $expected ) { $output = $world->result->STDOUT; diff --git a/features/upgradables.feature b/features/upgradables.feature index a7fe00a80..fc9c32276 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -98,10 +98,9 @@ Feature: Manage WordPress themes and plugins """ Showing 1 of """ - And STDOUT should contain: - """ - <item_title> - """ + And STDOUT should end with a table containing rows: + | name | slug | + | <item_title> | <item> | Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | From 1a37ef465df03aac20a14694951264a2ea149bc9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 9 Aug 2013 15:09:09 +0300 Subject: [PATCH 2142/5359] use dev-master for rmccue/requests and remove minimum-stability flag see #655 --- composer.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 1cf0a5510..c852f8b04 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", - "rmccue/requests": ">=1.0" + "rmccue/requests": "dev-master" }, "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" @@ -23,6 +23,5 @@ }, "autoload": { "psr-0": { "WP_CLI": "php" } - }, - "minimum-stability": "dev" + } } From 56d597a7890436ae5519e953b1deb8e06b49c0b5 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 16:19:56 +0300 Subject: [PATCH 2143/5359] Comment functions for exists and fetch helper --- php/commands/comment.php | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 179b08a6d..a5b696ae9 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -83,9 +83,9 @@ private function call( $args, $status, $success, $failure ) { } private function set_status( $args, $status, $success ) { - list( $comment_id ) = $args; - - $r = wp_set_comment_status( $comment_id, 'approve', true ); + $comment = $this->_fetch_comment( $args ); + + $r = wp_set_comment_status( $comment->comment_ID, 'approve', true ); if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); @@ -296,6 +296,41 @@ function last( $args = array(), $assoc_args = array() ) { WP_CLI::line( str_pad( "$key:", 23 ) . $comment->$key ); } } + + /** + * Verify whether a comment exists. + * + * ## OPTIONS + * + * <ID> + * : The ID of the comment to check from. + * + * ## EXAMPLES + * + * wp comment exists 1337 + * + * @synopsis <id> + */ + public function exists( $args ) { + if ( $this->_fetch_comment( $args ) ) { + WP_CLI::success( "Comment with ID $args[0] exists." ); + } + } + + /** + * A helper function fetching a comment object from comment_id. + * + */ + private function _fetch_comment( $args ) { + $comment_id = (int) $args[0]; + $comment = get_comment( $comment_id ); + + if ( is_null( $comment ) ) { + WP_CLI::error( "Comment with ID $args[0] does not exist." ); + } + + return $comment; + } } WP_CLI::add_command( 'comment', 'Comment_Command' ); From 85f50580065282a6ec6a527a320dcb68186e1b7b Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 16:20:12 +0300 Subject: [PATCH 2144/5359] Role enhancements for exists function --- php/commands/role.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 3c032e8c1..9259875e4 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -78,8 +78,10 @@ public function exists( $args ) { global $wp_roles; if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - exit(1); + WP_CLI::error( "Role with ID $args[0] does not exist." ); } + + WP_CLI::success( "Role with ID $args[0] exists." ); } /** From cb91693c60a3d009c493e4575db882b1c1ab3760 Mon Sep 17 00:00:00 2001 From: mpeshev <mario@peshev.net> Date: Fri, 9 Aug 2013 16:40:08 +0300 Subject: [PATCH 2145/5359] Fixed variables in comment feature --- features/comment.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index c2ca7bf32..1641d33a8 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -7,14 +7,14 @@ Feature: Manage WordPress comments Then STDOUT should match '%d' And save STDOUT as {COMMENT_ID} - When I run `wp comment exists {POST_ID}` + When I run `wp comment exists {COMMENT_ID}` Then STDOUT should be: """ - Success: Comment with ID {POST_ID} exists. + Success: Comment with ID {COMMENT_ID} exists. """ - When I run `wp comment delete {POST_ID}` + When I run `wp comment delete {COMMENT_ID}` Then STDOUT should be: """ - Success: Deleted comment {POST_ID}. + Success: Deleted comment {COMMENT_ID}. """ From 572eaa32f05573da2b0311bceec57b246b375e6f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 9 Aug 2013 21:57:27 +0300 Subject: [PATCH 2146/5359] add Behat tests for `db export` and `db import` --- features/db.feature | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/features/db.feature b/features/db.feature index 6bef95986..61bd9f52d 100644 --- a/features/db.feature +++ b/features/db.feature @@ -11,9 +11,6 @@ Feature: Perform database operations When I try the previous command again Then the return code should be 1 - When I run `wp db reset --yes` - Then STDOUT should not be empty - When I run `wp db optimize` Then STDOUT should not be empty @@ -38,3 +35,39 @@ Feature: Perform database operations """ total """ + + Scenario: DB export/import + Given a WP install + + When I run `wp post list --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp db export /tmp/wp-cli-behat.sql` + Then STDOUT should contain: + """ + Success: Exported + """ + + When I run `wp db reset --yes` + Then STDOUT should contain: + """ + Success: Database reset. + """ + + When I try `wp post list --format=count` + Then STDERR should not be empty + + When I run `wp db import /tmp/wp-cli-behat.sql` + Then STDOUT should contain: + """ + Success: Imported + """ + + When I run `wp post list --format=count` + Then STDOUT should contain: + """ + 1 + """ From 83f3321f413f272f54c9e8d0d051f44b9f135147 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 9 Aug 2013 22:07:08 +0300 Subject: [PATCH 2147/5359] whitespace fixes after #653 --- php/commands/core.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 88632e425..3e9c922b8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -60,13 +60,13 @@ public function download( $args, $assoc_args ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). $temp = tempnam( sys_get_temp_dir(), "wp_" ); - + $headers = array('Accept' => 'application/json'); $options = array( 'timeout' => 30, 'filename' => $temp ); - + try { $request = Requests::get( $download_url, $headers, $options ); } catch( Requests_Exception $ex ) { @@ -79,9 +79,9 @@ public function download( $args, $assoc_args ) { WP_CLI::error( $ex->getMessage() ); } } - + $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; - + WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); @@ -90,7 +90,7 @@ public function download( $args, $assoc_args ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); $options = array(); - + $r = false; try { $request = Requests::get( $url, $headers, $options ); @@ -101,11 +101,11 @@ private static function _read( $url ) { try { $request = Requests::get( $url, $headers, $options ); $r = $request->body; - } catch( Requests_Exception $ex ) { + } catch( Requests_Exception $ex ) { WP_CLI::error( $ex->getMessage() ); - } + } } - + return $r; } From 485c4b44c9394e1ee3e1cc898c34a0e6bd678096 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 9 Aug 2013 22:10:47 +0300 Subject: [PATCH 2148/5359] core version: load only wp-includes/version.php fixes #659 --- features/core.feature | 3 +++ php/commands/core.php | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 27818a62a..856ddb2f1 100644 --- a/features/core.feature +++ b/features/core.feature @@ -25,6 +25,9 @@ Feature: Manage WordPress installation Then the return code should be 1 And STDERR should not be empty + When I run `wp core version` + Then STDOUT should not be empty + When I try `wp core install` Then the return code should be 1 And STDERR should be: diff --git a/php/commands/core.php b/php/commands/core.php index 3e9c922b8..8803f8d18 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -525,10 +525,19 @@ private static function get_clean_basedomain() { * --extra * : Show extended version information. * + * @when before_wp_load * @synopsis [--extra] */ public function version( $args = array(), $assoc_args = array() ) { - global $wp_version, $wp_db_version, $tinymce_version; + $versions_path = ABSPATH . 'wp-includes/version.php'; + + if ( !is_readable( $versions_path ) ) { + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); + } + + include $versions_path; if ( isset( $assoc_args['extra'] ) ) { preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); From 736cdf7d46589e60f2f560d29b941e4851b1918f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 9 Aug 2013 23:09:11 +0300 Subject: [PATCH 2149/5359] media regenerate: remove erroneus timer and decrease verbosity fixes #660 --- php/commands/media.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 3c3bbafcf..aaa7c08fe 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -204,30 +204,30 @@ private function _process_regeneration( $id ) { $fullsizepath = get_attached_file( $image->ID ); + $att_desc = sprintf( '"%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ); + if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "{$image->post_title} - Can't find {$fullsizepath}." ); + WP_CLI::warning( "Can't find $att_desc" ); return; } - WP_CLI::log( sprintf( 'Start processing of "%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ) ); - $this->remove_old_images( $image->ID ); $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); - if ( is_wp_error( $metadata ) ) { WP_CLI::warning( $metadata->get_error_message() ); return; } if ( empty( $metadata ) ) { - WP_CLI::warning( "Couldn't regenerate image." ); + WP_CLI::warning( "Couldn't regenerate thumbnails for $att_desc." ); return; } wp_update_attachment_metadata( $image->ID, $metadata ); - WP_CLI::success( "All thumbnails were successfully regenerated in " . timer_stop() . " seconds." ); + WP_CLI::log( "Regenerated thumbnails for $att_desc" ); + } private function remove_old_images( $att_id ) { @@ -244,10 +244,7 @@ private function remove_old_images( $att_id ) { if ( $intermediate_path == $original_path ) continue; - if ( unlink( $intermediate_path ) ) { - WP_CLI::log( sprintf( "Thumbnail %s x %s was deleted.", - $size_info['width'], $size_info['height'] ) ); - } + unlink( $intermediate_path ); } } From ad22bf204ad92cf09e11b9b4ca4b6d6e9302e5ef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Aug 2013 04:39:02 +0300 Subject: [PATCH 2150/5359] first pass at 'wp site list' command --- php/commands/site.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 1fd1ffa4b..c87fc63a7 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -318,6 +318,38 @@ public function create( $_, $assoc_args ) { else WP_CLI::success( "Site $id created: $url" ); } + + /** + * List all sites in a multisite install. + * + * ## OPTIONS + * + * --fields=<fields> + * : Comma-separated list of fields to show. + * + * --format=<format> + * : Output list as table, CSV, JSON. Defaults to table. + * + * ## EXAMPLES + * + * wp site list --fields=domain,path --format=csv + * + * @subcommand list + * @synopsis [--format=<format>] [--fields=<fields>] + */ + function _list( $_, $assoc_args ) { + global $wpdb; + + $defaults = array( + 'format' => 'table', + 'fields' => array( 'blog_id', 'domain', 'path' ) + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $it = new \WP_CLI\Iterators\Table( array( 'table' => $wpdb->blogs ) ); + + WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + } } WP_CLI::add_command( 'site', 'Site_Command' ); From 5a014bb721665c77f2bf7ca15460354ebfc26319 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Aug 2013 16:55:22 +0300 Subject: [PATCH 2151/5359] site list: check for multisite before doing anything --- php/commands/site.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index c87fc63a7..4f3877809 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -338,6 +338,10 @@ public function create( $_, $assoc_args ) { * @synopsis [--format=<format>] [--fields=<fields>] */ function _list( $_, $assoc_args ) { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + global $wpdb; $defaults = array( From 0ea15f3e548008a6d13c70110e831f7de065cfe9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Aug 2013 16:55:43 +0300 Subject: [PATCH 2152/5359] site list: incorporate into site.feature tests --- features/site.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/site.feature b/features/site.feature index 80a6c94ff..6cdf91426 100644 --- a/features/site.feature +++ b/features/site.feature @@ -7,6 +7,12 @@ Feature: Manage sites in a multisite installation Then STDOUT should match '%d' And save STDOUT as {SITE_ID} + When I run `wp site list` + Then STDOUT should be a table containing rows: + | blog_id | domain | path | + | 1 | example.com | / | + | 2 | example.com | /first/ | + When I run `wp site delete {SITE_ID} --yes` Then STDOUT should not be empty From 053bc90829a93580e076b8f56a5b332bc270b43c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 10 Aug 2013 22:52:50 +0300 Subject: [PATCH 2153/5359] site list: add --network parameter --- php/commands/site.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 4f3877809..51dc3b4d1 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -324,6 +324,9 @@ public function create( $_, $assoc_args ) { * * ## OPTIONS * + * --network=<id> + * : The network to which the sites belong. + * * --fields=<fields> * : Comma-separated list of fields to show. * @@ -335,7 +338,7 @@ public function create( $_, $assoc_args ) { * wp site list --fields=domain,path --format=csv * * @subcommand list - * @synopsis [--format=<format>] [--fields=<fields>] + * @synopsis [--network=<id>] [--format=<format>] [--fields=<fields>] */ function _list( $_, $assoc_args ) { if ( !is_multisite() ) { @@ -346,11 +349,20 @@ function _list( $_, $assoc_args ) { $defaults = array( 'format' => 'table', - 'fields' => array( 'blog_id', 'domain', 'path' ) + 'fields' => array( 'blog_id', 'domain', 'path' ), ); $assoc_args = array_merge( $defaults, $assoc_args ); - $it = new \WP_CLI\Iterators\Table( array( 'table' => $wpdb->blogs ) ); + $where = array(); + if ( isset( $assoc_args['network'] ) ) { + $where['site_id'] = $assoc_args['network']; + } + + $iterator_args = array( + 'table' => $wpdb->blogs, + 'where' => $where, + ); + $it = new \WP_CLI\Iterators\Table( $iterator_args ); WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); } From eb57761f738445b2404d82336a4e1324b23797ca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 11 Aug 2013 13:45:56 -0700 Subject: [PATCH 2154/5359] Update tests --- features/scaffold.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 5e2601964..d5efe9849 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -48,7 +48,11 @@ Feature: Wordpress code scaffolding When I run `wp scaffold taxonomy zombie-speed --label="Speed"` Then STDOUT should contain: """ - __( 'Speed' + __( 'Speeds' + """ + And STDOUT should contain: + """ + _x( 'Speed', 'taxonomy general name', """ # Test for all flags but --label, --theme, --plugin and --raw From ef5b47b8ae57e7949b513078b2cc2f1f89791158 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 11 Aug 2013 13:53:08 -0700 Subject: [PATCH 2155/5359] Make `--admin_name` required, to discourage use of 'admin' as the default user --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8803f8d18..1e0512139 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -241,7 +241,7 @@ public function is_installed() { * --admin_email=<email> * : The email address for the admin user. * - * @synopsis --url=<url> --title=<site-title> [--admin_name=<username>] --admin_email=<email> --admin_password=<password> + * @synopsis --url=<url> --title=<site-title> --admin_name=<username> --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -312,7 +312,7 @@ public function multisite_convert( $args, $assoc_args ) { * : The email address for the admin user. * * @subcommand multisite-install - * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] [--admin_name=<username>] --admin_email=<email> --admin_password=<password> + * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] --admin_name=<username> --admin_email=<email> --admin_password=<password> */ public function multisite_install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { From bfc56731eee840b0393068c0033b6d6db0565546 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 11 Aug 2013 14:16:39 -0700 Subject: [PATCH 2156/5359] Convert `--admin_name` to `--admin_user`, which is more semantic. --- php/WP_CLI/Runner.php | 6 ++++++ php/commands/core.php | 14 +++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 1502ac7b3..8e5931645 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -262,6 +262,12 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } + // core (multsite-)install --admin_name= -> --admin_user= + if ( count( $args ) > 0 && 'core' == $args[0] && isset( $assoc_args['admin_name'] ) ) { + $assoc_args['admin_user'] = $assoc_args['admin_name']; + unset( $assoc_args['admin_name'] ); + } + // site --site_id= -> site --network_id= if ( count( $args ) > 0 && 'site' == $args[0] && isset( $assoc_args['site_id'] ) ) { $assoc_args['network_id'] = $assoc_args['site_id']; diff --git a/php/commands/core.php b/php/commands/core.php index 1e0512139..1189f9dad 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -232,8 +232,8 @@ public function is_installed() { * --title=<site-title> * : The title of the new site. * - * --admin_name=<username> - * : The name of the admin user. Default: 'admin' + * --admin_user=<username> + * : The name of the admin user. * * --admin_password=<password> * : The password for the admin user. @@ -241,7 +241,7 @@ public function is_installed() { * --admin_email=<email> * : The email address for the admin user. * - * @synopsis --url=<url> --title=<site-title> --admin_name=<username> --admin_email=<email> --admin_password=<password> + * @synopsis --url=<url> --title=<site-title> --admin_user=<username> --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -302,7 +302,7 @@ public function multisite_convert( $args, $assoc_args ) { * --title=<site-title> * : The title of the new site. * - * --admin_name=<username> + * --admin_user=<username> * : The name of the admin user. Default: 'admin' * * --admin_password=<password> @@ -312,7 +312,7 @@ public function multisite_convert( $args, $assoc_args ) { * : The email address for the admin user. * * @subcommand multisite-install - * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] --admin_name=<username> --admin_email=<email> --admin_password=<password> + * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] --admin_user=<username> --admin_email=<email> --admin_password=<password> */ public function multisite_install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -381,14 +381,14 @@ private function _install( $assoc_args ) { extract( wp_parse_args( $assoc_args, array( 'title' => '', - 'admin_name' => 'admin', + 'admin_user' => '', 'admin_email' => '', 'admin_password' => '' ) ), EXTR_SKIP ); $public = true; - $result = wp_install( $title, $admin_name, $admin_email, $public, '', $admin_password ); + $result = wp_install( $title, $admin_user, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); From 421495471748712d648ff7a574444cffe5a36539 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 11 Aug 2013 14:18:27 -0700 Subject: [PATCH 2157/5359] Update tests --- features/bootstrap/FeatureContext.php | 1 + features/core.feature | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b60c007b1..76afc463d 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -179,6 +179,7 @@ public function install_wp( $subdir = '' ) { $install_args = array( 'url' => 'http://example.com', 'title' => 'WP CLI Site', + 'admin_user' => 'wpcli', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' ); diff --git a/features/core.feature b/features/core.feature index 856ddb2f1..7f7363f78 100644 --- a/features/core.feature +++ b/features/core.feature @@ -80,7 +80,7 @@ Feature: Manage WordPress installation Run `wp core install`. """ - When I run `wp core install --url='localhost:8001' --title='Test' --admin_email=admin@example.com --admin_password=1` + When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty When I run `wp eval 'echo home_url();'` @@ -108,7 +108,7 @@ Feature: Manage WordPress installation """ # Can complain that it's already installed, but don't exit with an error code - When I try `wp core install --url='localhost:8001' --title='Test' --admin_email=admin@example.com --admin_password=1` + When I try `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then the return code should be 0 Scenario: Convert install to multisite @@ -138,7 +138,7 @@ Feature: Manage WordPress installation And wp-config.php And a database - When I run `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` + When I run `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` @@ -148,14 +148,14 @@ Feature: Manage WordPress installation """ # Can complain that it's already installed, but don't exit with an error code - When I try `wp core multisite-install --url=foobar.org --title=Test --admin_email=admin@example.com --admin_password=1` + When I try `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then the return code should be 0 Scenario: Install multisite from scratch, with MULTISITE already set in wp-config.php Given a WP multisite install And I run `wp db reset --yes` - When I run `wp core multisite-install --title=Test --admin_email=admin@example.com --admin_password=1` + When I run `wp core multisite-install --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` From c1fa867669d2226004da260af1c86cf04ec87f2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 11 Aug 2013 14:32:14 -0700 Subject: [PATCH 2158/5359] Cleverness kills tests --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 76afc463d..0207b0c10 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -179,7 +179,7 @@ public function install_wp( $subdir = '' ) { $install_args = array( 'url' => 'http://example.com', 'title' => 'WP CLI Site', - 'admin_user' => 'wpcli', + 'admin_user' => 'admin', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1' ); From a76d8ca666c5bd2bb8f86037a3770d4b3b22e3f6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 12:40:17 +0300 Subject: [PATCH 2159/5359] tests: first pass at using global PHPUnit and Behat --- CONTRIBUTING.md | 22 ++++++++++++++++------ bin/ci/install_dependencies.sh | 6 +++++- bin/ci/run_build.sh | 4 ++-- composer.json | 4 ---- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3d736e4f..07a7bcfc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,20 +21,30 @@ There are two types of tests: * unit tests, implemented using [PHPUnit](http://phpunit.de/) * functional tests, implemented using [Behat](http://behat.org) -All the test dependencies can be installed using [Composer](http://getcomposer.org/): +### Unit tests - php composer.phar install --dev +Assuming you have `~/.wp-cli/bin/` in your PATH, you can do: -### Unit tests +```bash +# Install PHPUnit +curl http://pear.phpunit.de/get/phpunit.phar > ~/.wp-cli/bin/phpunit +chmod +x ~/.wp-cli/bin/phpunit To run the unit tests, just execute: - vendor/bin/phpunit + phpunit The test files are in the `tests/` directory. ### Functional tests +Assuming you have `~/.wp-cli/bin/` in your PATH, to install Behat, you can do: + +```bash +curl http://behat.org/downloads/behat.phar > ~/.wp-cli/bin/behat +chmod +x ~/.wp-cli/bin/behat +``` + Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: @@ -43,11 +53,11 @@ Running the following as root in MySQL should do the trick: Then, to run the entire test suite: - vendor/bin/behat --expand + behat --expand Or to test a single feature: - vendor/bin/behat features/core.feature + behat features/core.feature More info can be found from `vendor/bin/behat --help`. diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh index c75651098..7e83e2d25 100755 --- a/bin/ci/install_dependencies.sh +++ b/bin/ci/install_dependencies.sh @@ -4,8 +4,12 @@ set -ex +# install Behat +sudo curl http://behat.org/downloads/behat.phar > /usr/bin/behat +chmod +x /usr/bin/behat + # install dependencies -composer install --dev --no-interaction --prefer-source +composer install --no-interaction --prefer-source composer require d11wtq/boris=dev-master --no-interaction --prefer-source # set up WP install diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh index 3ed2e35cd..2711478a5 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/run_build.sh @@ -2,6 +2,6 @@ set -ex -vendor/bin/phpunit +phpunit -vendor/bin/behat --format progress +behat --format progress diff --git a/composer.json b/composer.json index c852f8b04..75262e771 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,6 @@ "suggest": { "d11wtq/boris": "Enhanced `wp shell` functionality" }, - "require-dev": { - "phpunit/phpunit": "~3.7", - "behat/behat": "~2.4" - }, "autoload": { "psr-0": { "WP_CLI": "php" } } From f72c44ff8fe022960b9713647c8295b48c51c186 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 12:44:49 +0300 Subject: [PATCH 2160/5359] travis: install Behat in the local build dir --- bin/ci/install_dependencies.sh | 3 +-- bin/ci/run_build.sh | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh index 7e83e2d25..6fbef5957 100755 --- a/bin/ci/install_dependencies.sh +++ b/bin/ci/install_dependencies.sh @@ -5,8 +5,7 @@ set -ex # install Behat -sudo curl http://behat.org/downloads/behat.phar > /usr/bin/behat -chmod +x /usr/bin/behat +curl http://behat.org/downloads/behat.phar > behat.phar # install dependencies composer install --no-interaction --prefer-source diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh index 2711478a5..2fb25dfea 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/run_build.sh @@ -4,4 +4,4 @@ set -ex phpunit -behat --format progress +php behat.phar --format progress From 63c6419c01f7ae8d366c32e09eaa5192b340a5f1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 14:14:00 +0300 Subject: [PATCH 2161/5359] site list: add a more useful example see #661 --- php/commands/site.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index 51dc3b4d1..e34fce87e 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -335,7 +335,8 @@ public function create( $_, $assoc_args ) { * * ## EXAMPLES * - * wp site list --fields=domain,path --format=csv + * # Output the list of site URLs + * wp site list --fields=domain,path --format=csv | tail -n +2 | sed 's/,//' * * @subcommand list * @synopsis [--network=<id>] [--format=<format>] [--fields=<fields>] From 2c249ea2d377068d63386a43049d534b0d97346f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 14:45:44 +0300 Subject: [PATCH 2162/5359] replace PHPUnit assertEquals() with homegrown variant --- features/bootstrap/FeatureContext.php | 2 -- features/bootstrap/support.php | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b60c007b1..f2e6855fa 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -7,8 +7,6 @@ use \WP_CLI\Utils; -require_once 'PHPUnit/Framework/Assert/Functions.php'; - require_once __DIR__ . '/../../php/utils.php'; /** diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index d213ea3de..b448519b8 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -2,6 +2,12 @@ // Utility functions used by Behat steps +function assertEquals( $expected, $actual ) { + if ( $expected != $actual ) { + throw new Exception( "Actual value: " . var_export( $actual ) ); + } +} + function checkString( $output, $expected, $action ) { switch ( $action ) { From bcbae42ce51a42d6d8ced2003a48f7dc07c0c91c Mon Sep 17 00:00:00 2001 From: MattiaG <bots@mattiaghedin.it> Date: Mon, 12 Aug 2013 19:28:21 +0200 Subject: [PATCH 2163/5359] allow to use both --locale and --version params for 'wp core download' Ugly coded, but not so different from source. If the requested combination of locale+version is not available, the script fails like with wrong version parameter. Tested setting it_IT and de_DE parameters and various versions. --- php/commands/core.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1189f9dad..b49774ca7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -15,8 +15,7 @@ class Core_Command extends WP_CLI_Command { * ## OPTIONS * * --locale=<locale> - * : Select which language you want to download. The --version parameter is - * ignored in this case. + * : Select which language you want to download. * * --version=<version> * : Select which version you want to download. @@ -41,7 +40,10 @@ public function download( $args, $assoc_args ) { WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); } - if ( isset( $assoc_args['locale'] ) ) { + if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version']) ) { + $download_url = 'https://'. substr($assoc_args['locale'],0,2) .'.wordpress.org/wordpress-' . $assoc_args['version'] . '-' .$assoc_args['locale']. '.tar.gz'; + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $assoc_args['locale'] ) ); + } else if ( isset( $assoc_args['locale'] ) ) { $offer = $this->get_download_offer( $assoc_args['locale'] ); $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', From 0638c636b3bb4993ba455c1f53dda15f1d12f2ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 21:36:13 +0300 Subject: [PATCH 2164/5359] fix coding standards; see #666 --- php/commands/core.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index b49774ca7..3cac1d111 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -40,13 +40,13 @@ public function download( $args, $assoc_args ) { WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); } - if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version']) ) { - $download_url = 'https://'. substr($assoc_args['locale'],0,2) .'.wordpress.org/wordpress-' . $assoc_args['version'] . '-' .$assoc_args['locale']. '.tar.gz'; - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $assoc_args['locale'] ) ); - } else if ( isset( $assoc_args['locale'] ) ) { + if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version'] ) ) { + $download_url = 'https://'. substr( $assoc_args['locale'],0,2 ) .'.wordpress.org/wordpress-' . $assoc_args['version'] . '-' .$assoc_args['locale']. '.tar.gz'; + WP_CLI::log( sprintf( 'Downloading WordPress %s ( %s )...', $assoc_args['version'], $assoc_args['locale'] ) ); + } else if ( isset( $assoc_args['locale'] ) ) { $offer = $this->get_download_offer( $assoc_args['locale'] ); $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', + WP_CLI::log( sprintf( 'Downloading WordPress %s ( %s )...', $offer['current'], $offer['locale'] ) ); } elseif ( isset( $assoc_args['version'] ) ) { $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; From a147ee9d03209e8b393f2a5197e754483b16b9a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 21:37:20 +0300 Subject: [PATCH 2165/5359] whitespace is nice, but let's not get ridiculous --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3cac1d111..dcb5b957f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -42,11 +42,11 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version'] ) ) { $download_url = 'https://'. substr( $assoc_args['locale'],0,2 ) .'.wordpress.org/wordpress-' . $assoc_args['version'] . '-' .$assoc_args['locale']. '.tar.gz'; - WP_CLI::log( sprintf( 'Downloading WordPress %s ( %s )...', $assoc_args['version'], $assoc_args['locale'] ) ); + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $assoc_args['locale'] ) ); } else if ( isset( $assoc_args['locale'] ) ) { $offer = $this->get_download_offer( $assoc_args['locale'] ); $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); - WP_CLI::log( sprintf( 'Downloading WordPress %s ( %s )...', + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $offer['current'], $offer['locale'] ) ); } elseif ( isset( $assoc_args['version'] ) ) { $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; From be4a66f3e7fef53feeb2cdb46ef332368806c8bf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 21:42:44 +0300 Subject: [PATCH 2166/5359] use sprintf() instead of concatenation; see #666 --- php/commands/core.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index dcb5b957f..81762a63e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -41,7 +41,8 @@ public function download( $args, $assoc_args ) { } if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version'] ) ) { - $download_url = 'https://'. substr( $assoc_args['locale'],0,2 ) .'.wordpress.org/wordpress-' . $assoc_args['version'] . '-' .$assoc_args['locale']. '.tar.gz'; + $download_url = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.tar.gz', + substr( $assoc_args['locale'], 0, 2 ), $assoc_args['version'], $assoc_args['locale'] ); WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $assoc_args['locale'] ) ); } else if ( isset( $assoc_args['locale'] ) ) { $offer = $this->get_download_offer( $assoc_args['locale'] ); @@ -65,9 +66,9 @@ public function download( $args, $assoc_args ) { $headers = array('Accept' => 'application/json'); $options = array( - 'timeout' => 30, - 'filename' => $temp - ); + 'timeout' => 30, + 'filename' => $temp + ); try { $request = Requests::get( $download_url, $headers, $options ); From 9cde1938c57699c2d0c61ad5b4284e69296c31d5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 22:48:58 +0300 Subject: [PATCH 2167/5359] replace assertStringMatchesFormat() with assertNumeric() --- features/bootstrap/support.php | 6 ++++++ features/comment.feature | 2 +- features/post.feature | 8 ++++---- features/site.feature | 2 +- features/steps/basic_steps.php | 6 +++--- features/term.feature | 4 ++-- features/user.feature | 2 +- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index b448519b8..b6245af2c 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -8,6 +8,12 @@ function assertEquals( $expected, $actual ) { } } +function assertNumeric( $actual ) { + if ( !is_numeric( $actual ) ) { + throw new Exception( "Actual value: " . var_export( $actual ) ); + } +} + function checkString( $output, $expected, $action ) { switch ( $action ) { diff --git a/features/comment.feature b/features/comment.feature index 1641d33a8..8a9d2502d 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress comments Given a WP install When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {COMMENT_ID} When I run `wp comment exists {COMMENT_ID}` diff --git a/features/post.feature b/features/post.feature index 38dfb3a93..16c88c6df 100644 --- a/features/post.feature +++ b/features/post.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress posts Given a WP install When I run `wp post create --post_title='Test post' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {POST_ID} When I run `wp post update {POST_ID} --post_title='Updated post'` @@ -40,7 +40,7 @@ Feature: Manage WordPress posts """ When I run `bash command.sh` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {POST_ID} When I run `wp eval '$post_id = {POST_ID}; echo get_post( $post_id )->post_excerpt;'` @@ -74,10 +74,10 @@ Feature: Manage WordPress posts Given a WP install When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number When I run `wp post create --post_title='Draft post' --post_content='Draft post content' --post_status='draft' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number When I run `wp post list --post_type='post' --fields=post_title,post_name,post_status --format=csv` Then STDOUT should be CSV containing: diff --git a/features/site.feature b/features/site.feature index 6cdf91426..aa53f8c36 100644 --- a/features/site.feature +++ b/features/site.feature @@ -4,7 +4,7 @@ Feature: Manage sites in a multisite installation Given a WP multisite install When I run `wp site create --slug=first --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {SITE_ID} When I run `wp site list` diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 74d494b57..778cb6317 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -160,9 +160,9 @@ function ( $world, $stream, $action, PyStringNode $expected ) { } ); -$steps->Then( '/^(STDOUT|STDERR) should match \'([^\']+)\'$/', - function ( $world, $stream, $format ) { - assertStringMatchesFormat( $format, $world->result->$stream ); +$steps->Then( '/^(STDOUT|STDERR) should be a number$/', + function ( $world, $stream ) { + assertNumeric( $world->result->$stream ); } ); diff --git a/features/term.feature b/features/term.feature index df7dea76c..97b5ad580 100644 --- a/features/term.feature +++ b/features/term.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress terms Given a WP install When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number When I try the previous command again Then STDERR should not be empty @@ -24,7 +24,7 @@ Feature: Manage WordPress terms Given a WP install When I run `wp term create 'Test delete term' post_tag --slug=test-delete --description='This is a test term to be deleted' --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {TERM_ID} When I run `wp term delete {TERM_ID} post_tag` diff --git a/features/user.feature b/features/user.feature index 43bfe2ae4..83f3f9000 100644 --- a/features/user.feature +++ b/features/user.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress users Given a WP install When I run `wp user create testuser testuser@example.com --porcelain` - Then STDOUT should match '%d' + Then STDOUT should be a number And save STDOUT as {USER_ID} When I try the previous command again From 69ea5e58209254d08cdc70cf6c18ccd620cfa448 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 22:56:15 +0300 Subject: [PATCH 2168/5359] replace remaining assertion calls with direct exceptions --- features/steps/basic_steps.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 778cb6317..8b7b33708 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -260,7 +260,9 @@ function ( $world, $stream ) { $steps->Then( '/^(STDOUT|STDERR) should not be empty$/', function ( $world, $stream ) { - assertNotEmpty( rtrim( $world->result->$stream, "\n" ) ); + if ( '' === rtrim( $world->result->$stream, "\n" ) ) { + throw new Exception( "$stream is empty." ); + } } ); @@ -274,13 +276,19 @@ function ( $world, $path, $action, $expected = null ) { switch ( $action ) { case 'exist': - assertFileExists( $path ); + if ( !file_exists( $path ) ) { + throw new Exception( "$path doesn't exist." ); + } break; case 'not exist': - assertFileNotExists( $path ); + if ( file_exists( $path ) ) { + throw new Exception( "$path exists." ); + } break; default: - assertFileExists( $path ); + if ( !file_exists( $path ) ) { + throw new Exception( "$path doesn't exist." ); + } $action = substr( $action, 0, -1 ); $expected = $world->replace_variables( (string) $expected ); checkString( file_get_contents( $path ), $expected, $action ); From f212f4d261bdd84d35caab228b078f8373be7490 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 23:05:39 +0300 Subject: [PATCH 2169/5359] fix assertNumeric() usage --- features/bootstrap/support.php | 4 ++-- features/steps/basic_steps.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index b6245af2c..1e9809ddf 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -4,13 +4,13 @@ function assertEquals( $expected, $actual ) { if ( $expected != $actual ) { - throw new Exception( "Actual value: " . var_export( $actual ) ); + throw new Exception( "Actual value: " . var_export( $actual, true ) ); } } function assertNumeric( $actual ) { if ( !is_numeric( $actual ) ) { - throw new Exception( "Actual value: " . var_export( $actual ) ); + throw new Exception( "Actual value: " . var_export( $actual, true ) ); } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 8b7b33708..d3b267ee6 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -162,7 +162,7 @@ function ( $world, $stream, $action, PyStringNode $expected ) { $steps->Then( '/^(STDOUT|STDERR) should be a number$/', function ( $world, $stream ) { - assertNumeric( $world->result->$stream ); + assertNumeric( trim( $world->result->$stream, "\n" ) ); } ); From 46fb8dad853d48b28aea5ce64a252d32cc0c27e0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 12 Aug 2013 23:41:16 +0300 Subject: [PATCH 2170/5359] update utils/dev-build --- .gitignore | 2 +- CONTRIBUTING.md | 34 +++++++++++++--------------------- utils/dev-build | 22 ++++++++++++---------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 03f9ead5d..8c20e7a9f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ composer.lock -composer.phar /vendor +/*.phar /phpunit.xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 07a7bcfc2..701e56b21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,34 +16,28 @@ Lastly, please follow the [WordPress Coding Standards](http://make.wordpress.org Running and writing tests ------------------------- -There are two types of tests: +There are two types of automated tests: * unit tests, implemented using [PHPUnit](http://phpunit.de/) * functional tests, implemented using [Behat](http://behat.org) -### Unit tests - -Assuming you have `~/.wp-cli/bin/` in your PATH, you can do: +To set everything up, just run: ```bash -# Install PHPUnit -curl http://pear.phpunit.de/get/phpunit.phar > ~/.wp-cli/bin/phpunit -chmod +x ~/.wp-cli/bin/phpunit +./utils/dev-build +``` -To run the unit tests, just execute: +### Unit tests - phpunit +The unit test files are in the `tests/` directory. -The test files are in the `tests/` directory. +To run the unit tests, just execute: + + php phpunit.phar ### Functional tests -Assuming you have `~/.wp-cli/bin/` in your PATH, to install Behat, you can do: - -```bash -curl http://behat.org/downloads/behat.phar > ~/.wp-cli/bin/behat -chmod +x ~/.wp-cli/bin/behat -``` +The functional test files are in the `features/` directory. Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. @@ -53,15 +47,13 @@ Running the following as root in MySQL should do the trick: Then, to run the entire test suite: - behat --expand + php behat.phar --expand Or to test a single feature: - behat features/core.feature - -More info can be found from `vendor/bin/behat --help`. + php behat.phar features/core.feature -The feature files are in the `features/` directory. +More info can be found from `php behat.phar --help`. Finally... ---------- diff --git a/utils/dev-build b/utils/dev-build index 299460360..d4f3f09e4 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -1,21 +1,23 @@ #!/usr/bin/env bash -# check that PHP is available command -v php > /dev/null || { echo "can't find PHP binary" >&2 exit 1 } -# install Composer -command -v composer > /dev/null || { - curl -sS https://getcomposer.org/installer | php - sudo mv composer.phar /usr/local/bin/composer -} +echo "Downloading Composer..." +curl -sS https://getcomposer.org/installer | php + +echo "Installing dependencies using Composer..." +php composer.phar install + +echo "Downloading PHPUnit..." +curl -sS http://pear.phpunit.de/get/phpunit.phar > phpunit.phar -# install dependencies -composer install --dev +echo "Downloading Behat..." +curl -sS http://behat.org/downloads/behat.phar > behat.phar -# add symlink to wp binary +echo "Creating symlink for the wp command..." for dir in /usr/bin /usr/local/bin; do if [ -d $dir ]; then sudo ln -sf $(pwd)/bin/wp $dir/wp @@ -23,7 +25,7 @@ for dir in /usr/bin /usr/local/bin; do fi done -# install bash completion file +echo "Installing bash completion file..." for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do if [ -d $dir ]; then sudo ln -sf $(pwd)/utils/wp-completion.bash $dir/wp From 94f5fe84823fc32f8d5c56abddbad3149f6e7035 Mon Sep 17 00:00:00 2001 From: Josh Betz <j@joshbetz.com> Date: Mon, 12 Aug 2013 17:37:07 -0500 Subject: [PATCH 2171/5359] First pass at Behat test for `wp plugin is-installed <plugin>` --- features/plugin.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index f48979760..5616bd639 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -29,6 +29,12 @@ Feature: Manage WordPress plugins Status: Active """ + When I run `wp plugin is-installed zombieland && echo "Zombieland"` + Then STDOUT should contain: + """ + Zombieland + """ + When I run `wp plugin status` Then STDOUT should not be empty From 09654d1f9e02cb1d515f68938ee9850b4019bd91 Mon Sep 17 00:00:00 2001 From: Josh Betz <j@joshbetz.com> Date: Mon, 12 Aug 2013 17:55:55 -0500 Subject: [PATCH 2172/5359] Fixed test for `wp plugin is-installed <plugin>` There was extra white space in the expected output --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 5616bd639..299a116d4 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -32,7 +32,7 @@ Feature: Manage WordPress plugins When I run `wp plugin is-installed zombieland && echo "Zombieland"` Then STDOUT should contain: """ - Zombieland + Zombieland """ When I run `wp plugin status` From 3e5d8c8a470e65081479b7785edbe5c938d75951 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 03:13:16 +0300 Subject: [PATCH 2173/5359] site list: add --format=url; see #661 --- php/commands/site.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index e34fce87e..285c37c39 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -331,12 +331,12 @@ public function create( $_, $assoc_args ) { * : Comma-separated list of fields to show. * * --format=<format> - * : Output list as table, CSV, JSON. Defaults to table. + * : Output list as table, csv, json or url. Defaults to table. * * ## EXAMPLES * * # Output the list of site URLs - * wp site list --fields=domain,path --format=csv | tail -n +2 | sed 's/,//' + * wp site list --format=url * * @subcommand list * @synopsis [--network=<id>] [--format=<format>] [--fields=<fields>] @@ -365,7 +365,13 @@ function _list( $_, $assoc_args ) { ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); - WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + if ( 'url' == $assoc_args['format'] ) { + foreach ( $it as $blog ) { + WP_CLI::line( $blog->domain . $blog->path ); + } + } else { + WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + } } } From 7e615b4047477e61cb7c580c579fd59c9ecdb3d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 16:14:46 +0300 Subject: [PATCH 2174/5359] allow passing 'php://stdin' to WP_CLI\Iterators\CSV --- php/WP_CLI/Iterators/CSV.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Iterators/CSV.php b/php/WP_CLI/Iterators/CSV.php index dde3fb51c..a349a3e3a 100644 --- a/php/WP_CLI/Iterators/CSV.php +++ b/php/WP_CLI/Iterators/CSV.php @@ -2,6 +2,9 @@ namespace WP_CLI\Iterators; +/** + * Allows incrementally reading and parsing lines from a CSV file. + */ class CSV implements \Iterator { const ROW_SIZE = 4096; @@ -16,8 +19,9 @@ class CSV implements \Iterator { public function __construct( $filename, $delimiter = ',' ) { $this->filePointer = fopen( $filename, 'r' ); - if ( !is_readable( $filename ) ) + if ( !$this->filePointer ) { \WP_CLI::error( sprintf( 'Could not open file: %s', $filename ) ); + } $this->delimiter = $delimiter; } From 56ca34fb3529466ef6c1b819faba405d097e9d72 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 15:54:08 +0300 Subject: [PATCH 2175/5359] combine 'domain' and 'path' fields into single 'url' field; remove --format=url see #661 --- php/commands/site.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 285c37c39..e0670189a 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -335,8 +335,8 @@ public function create( $_, $assoc_args ) { * * ## EXAMPLES * - * # Output the list of site URLs - * wp site list --format=url + * # Output a simple list of site URLs + * wp site list --fields=url --format=csv | tail -n +2 * * @subcommand list * @synopsis [--network=<id>] [--format=<format>] [--fields=<fields>] @@ -348,9 +348,13 @@ function _list( $_, $assoc_args ) { global $wpdb; + if ( isset( $assoc_args['fields'] ) ) { + $assoc_args['fields'] = preg_split( '/,[ \t]*/', $assoc_args['fields'] ); + } + $defaults = array( 'format' => 'table', - 'fields' => array( 'blog_id', 'domain', 'path' ), + 'fields' => array( 'blog_id', 'url', 'last_updated', 'registered' ), ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -365,13 +369,14 @@ function _list( $_, $assoc_args ) { ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); - if ( 'url' == $assoc_args['format'] ) { - foreach ( $it as $blog ) { - WP_CLI::line( $blog->domain . $blog->path ); - } - } else { - WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + $list = array(); + foreach ( $it as $blog ) { + print_r($blog); + $blog->url = $blog->domain . $blog->path; + $list[] = $blog; } + + WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); } } From 332caf61f61e7852ca327dc7cf6398d715e020ba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 16:41:29 +0300 Subject: [PATCH 2176/5359] remove stray print_r() --- php/commands/site.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index e0670189a..6da3de8c5 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -371,7 +371,6 @@ function _list( $_, $assoc_args ) { $list = array(); foreach ( $it as $blog ) { - print_r($blog); $blog->url = $blog->domain . $blog->path; $list[] = $blog; } From 4351a5c29a24321170820dc457f1eee007ab4445 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 16:51:44 +0300 Subject: [PATCH 2177/5359] update tests for 'wp site list'. see #661 --- features/site.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/site.feature b/features/site.feature index aa53f8c36..3e872852f 100644 --- a/features/site.feature +++ b/features/site.feature @@ -7,11 +7,11 @@ Feature: Manage sites in a multisite installation Then STDOUT should be a number And save STDOUT as {SITE_ID} - When I run `wp site list` + When I run `wp site list --fields=blog_id,url` Then STDOUT should be a table containing rows: - | blog_id | domain | path | - | 1 | example.com | / | - | 2 | example.com | /first/ | + | blog_id | url | + | 1 | example.com/ | + | 2 | example.com/first/ | When I run `wp site delete {SITE_ID} --yes` Then STDOUT should not be empty From 556f4c0bd600dce1343ee00ce825e63f62a0bead Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 13 Aug 2013 21:20:52 +0300 Subject: [PATCH 2178/5359] behat: extract compareTables() helper --- features/bootstrap/support.php | 15 ++++++++++ features/steps/basic_steps.php | 55 ++++++++++------------------------ 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 1e9809ddf..7b77eb7d0 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -38,6 +38,21 @@ function checkString( $output, $expected, $action ) { } } +function compareTables( $expected_rows, $actual_rows, $output ) { + // the first row is the header and must be present + if ( $expected_rows[0] != $actual_rows[0] ) { + throw new \Exception( $output ); + } + + unset( $actual_rows[0] ); + unset( $expected_rows[0] ); + + $missing_rows = array_diff( $expected_rows, $actual_rows ); + if ( !empty( $missing_rows ) ) { + throw new \Exception( $output ); + } +} + function compareContents( $expected, $actual ) { if ( gettype( $expected ) != gettype( $actual ) ) { return false; diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index d3b267ee6..0e1ab4881 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -168,59 +168,34 @@ function ( $world, $stream ) { $steps->Then( '/^STDOUT should be a table containing rows:$/', function ( $world, TableNode $expected ) { - $output = $world->result->STDOUT; - $outputRows = explode( "\n", rtrim( $output, "\n" ) ); + $output = $world->result->STDOUT; + $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); - $expectedRows = array(); + $expected_rows = array(); foreach ( $expected->getRows() as $row ) { - $expectedRows[] = $world->replace_variables( implode( "\t", $row ) ); + $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); } - // the first row is the header and must be present - if ( $expectedRows[0] != $outputRows[0] ) { - throw new \Exception( $output ); - } - - unset($outputRows[0]); - unset($expectedRows[0]); - $matches = array_intersect( $expectedRows, $outputRows ); - if ( count( $expectedRows ) != count( $matches ) ) { - throw new \Exception( $output ); - } + compareTables( $expected_rows, $actual_rows, $output ); } ); $steps->Then( '/^STDOUT should end with a table containing rows:$/', function ( $world, TableNode $expected ) { - $output = $world->result->STDOUT; - $outputRows = explode( "\n", rtrim( $output, "\n" ) ); + $output = $world->result->STDOUT; + $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); - $expectedRows = array(); + $expected_rows = array(); foreach ( $expected->getRows() as $row ) { - $expectedRows[] = $world->replace_variables( implode( "\t", $row ) ); + $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); } - $remainingRows = array(); - $start = false; - foreach( $outputRows as $key => $row ) { - - // the first row is the header and must be present - if ( $expectedRows[0] == $row ) - $start = true; + $start = array_search( $expected_rows[0], $actual_rows ); - if ( $start ) - $remainingRows[] = $row; - } - - if ( ! $start ) + if ( false === $start ) throw new \Exception( $output ); - unset($remainingRows[0]); - unset($expectedRows[0]); - $matches = array_intersect( $expectedRows, $remainingRows ); - - if ( count( $expectedRows ) != count( $matches ) ) - throw new \Exception( $output ); + compareTables( $expected_rows, array_slice( $actual_rows, $start ), $output ); } ); @@ -235,17 +210,17 @@ function ( $world, PyStringNode $expected ) { }); $steps->Then( '/^STDOUT should be CSV containing:$/', - function( $world, TableNode $expected ) { + function ( $world, TableNode $expected ) { $output = $world->result->STDOUT; - $expectedRows = $expected->getRows(); + $expected_rows = $expected->getRows(); foreach ( $expected as &$row ) { foreach ( $row as &$value ) { $value = $world->replace_variables( $value ); } } - if ( ! checkThatCsvStringContainsValues( $output, $expectedRows ) ) + if ( ! checkThatCsvStringContainsValues( $output, $expected_rows ) ) throw new \Exception( $output ); } ); From 0d9538f6e45d830dd2ef3644056dd7eb663a1b98 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Tue, 13 Aug 2013 11:49:51 -0700 Subject: [PATCH 2179/5359] Correct `wp user add-role` example --- php/commands/user.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 521e142f7..b694aaa67 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -397,8 +397,8 @@ public function set_role( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user set-role bob author - * wp user set-role 12 author + * wp user add-role bob author + * wp user add-role 12 author * * @subcommand add-role * @synopsis <user> <role> From e7144cfb9055b67df6b5ab49ef3a39e8cfd4241d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 02:51:15 +0300 Subject: [PATCH 2180/5359] add support for PsySH in `wp shell` also, replace Boris as suggested package --- bin/ci/install_dependencies.sh | 1 - composer.json | 2 +- php/commands/shell.php | 21 ++++++++++++++------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/bin/ci/install_dependencies.sh b/bin/ci/install_dependencies.sh index 6fbef5957..1b2e5723a 100755 --- a/bin/ci/install_dependencies.sh +++ b/bin/ci/install_dependencies.sh @@ -9,7 +9,6 @@ curl http://behat.org/downloads/behat.phar > behat.phar # install dependencies composer install --no-interaction --prefer-source -composer require d11wtq/boris=dev-master --no-interaction --prefer-source # set up WP install ./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ diff --git a/composer.json b/composer.json index a572e0a85..0e5aa5451 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "rmccue/requests": "dev-master" }, "suggest": { - "d11wtq/boris": "Enhanced `wp shell` functionality" + "psy/psysh": "Enhanced `wp shell` functionality" }, "autoload": { "psr-0": { "WP_CLI": "php" } diff --git a/php/commands/shell.php b/php/commands/shell.php index ef0869e85..ee95860e6 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -18,20 +18,27 @@ class Shell_Command extends \WP_CLI_Command { */ public function __invoke( $_, $assoc_args ) { $implementations = array( + '\\Psy\\Shell', '\\Boris\\Boris', '\\WP_CLI\\REPL', ); if ( isset( $assoc_args['basic'] ) ) { - unset( $implementations[0] ); + $class = '\\WP_CLI\\REPL'; + } else { + foreach ( $implementations as $candidate ) { + if ( class_exists( $candidate ) ) { + $class = $candidate; + break; + } + } } - foreach ( $implementations as $class ) { - if ( class_exists( $class ) ) { - $repl = new $class( 'wp> ' ); - $repl->start(); - break; - } + if ( '\\Psy\\Shell' == $class ) { + \Psy\Shell::debug(); + } else { + $repl = new $class( 'wp> ' ); + $repl->start(); } } } From fd881948697f91b29e91fead91b007f5b22db31a Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Wed, 14 Aug 2013 14:37:54 +0100 Subject: [PATCH 2181/5359] Let's use the simpler `array_merge()` instead of `wp_parse_args()` --- php/WP_CLI/CommandWithUpgrade.php | 6 +++--- php/commands/post.php | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index dac45fa87..6568bd21d 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -220,16 +220,16 @@ function update_all( $args, $assoc_args ) { } protected function _list( $_, $assoc_args ) { - $values = array( + $defaults = array( 'format' => 'table', 'fields' => $this->fields ); - $values = wp_parse_args( $assoc_args, $values ); + $assoc_args = array_merge( $defaults, $assoc_args ); $all_items = $this->get_all_items(); $items = $this->create_objects( $all_items ); - \WP_CLI\Utils\format_items( $values['format'], $items, $values['fields'] ); + \WP_CLI\Utils\format_items( $assoc_args['format'], $items, $assoc_args['fields'] ); } /** diff --git a/php/commands/post.php b/php/commands/post.php index fb6355461..22e09078f 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -163,9 +163,10 @@ protected function _edit( $content, $title ) { * @synopsis [--format=<format>] <ID> */ public function get( $args, $assoc_args ) { - $assoc_args = wp_parse_args( $assoc_args, array( + $defaults = array( 'format' => 'table' - ) ); + ); + $assoc_args = array_merge( $defaults, $assoc_args ); $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) @@ -216,9 +217,10 @@ public function get( $args, $assoc_args ) { * @synopsis <id>... [--force] */ public function delete( $args, $assoc_args ) { - $assoc_args = wp_parse_args( $assoc_args, array( + $defaults = array( 'force' => false - ) ); + ); + $assoc_args = array_merge( $defaults, $assoc_args ); parent::delete( $args, $assoc_args ); } @@ -265,12 +267,11 @@ public function _list( $_, $assoc_args ) { 'posts_per_page' => -1, 'post_status' => 'any', ); - - $values = array( + $defaults = array( 'format' => 'table', 'fields' => $this->fields ); - $values = wp_parse_args( $assoc_args, $values ); + $assoc_args = array_merge( $defaults, $assoc_args ); foreach ( $assoc_args as $key => $value ) { if ( true === $value ) @@ -279,12 +280,12 @@ public function _list( $_, $assoc_args ) { $query_args[ $key ] = $value; } - if ( 'ids' == $values['format'] ) + if ( 'ids' == $assoc_args['format'] ) $query_args['fields'] = 'ids'; $query = new WP_Query( $query_args ); - WP_CLI\Utils\format_items( $values['format'], $query->posts, $values['fields'] ); + WP_CLI\Utils\format_items( $assoc_args['format'], $query->posts, $assoc_args['fields'] ); } /** @@ -328,7 +329,7 @@ public function generate( $args, $assoc_args ) { 'post_date' => current_time( 'mysql' ), ); - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); + extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); if ( !post_type_exists( $post_type ) ) { WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); From 10845a747904cf2a6ddefbf9b6c07e1d769238c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 17:40:20 +0300 Subject: [PATCH 2182/5359] Don't pretend we're in wp-admin, but continue to load all admin APIs. The WP_CLI context is not like the WP_ADMIN context. It's a different animal. See #674 for more details. Fixes #477, #519, #574, #579, #582, #669 --- features/core.feature | 8 +------- php/WP_CLI/CommandWithUpgrade.php | 3 +++ php/wp-cli.php | 8 +------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/features/core.feature b/features/core.feature index 7f7363f78..9d248d631 100644 --- a/features/core.feature +++ b/features/core.feature @@ -98,15 +98,9 @@ Feature: Manage WordPress installation When I run `wp eval 'var_export( is_admin() );'` Then STDOUT should be: """ - true + false """ - When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` - Then STDOUT should be: - """ - true - """ - # Can complain that it's already installed, but don't exit with an error code When I try `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then the return code should be 0 diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 6568bd21d..96ce4df28 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -220,6 +220,9 @@ function update_all( $args, $assoc_args ) { } protected function _list( $_, $assoc_args ) { + // Force WordPress to check for updates + call_user_func( $this->upgrade_refresh ); + $defaults = array( 'format' => 'table', 'fields' => $this->fields diff --git a/php/wp-cli.php b/php/wp-cli.php index 4baaf4d21..d3638664d 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -19,20 +19,14 @@ // Load wp-config.php code, in the global scope eval( WP_CLI::get_runner()->get_wp_config_code() ); -// Simulate a /wp-admin/ page load -$_SERVER['PHP_SELF'] = '/wp-admin/index.php'; -define( 'WP_ADMIN', true ); -define( 'WP_NETWORK_ADMIN', false ); -define( 'WP_USER_ADMIN', false ); - // Load Core, mu-plugins, plugins, themes etc. require WP_CLI_ROOT . '/php/wp-settings-cli.php'; // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); +// Load all the admin APIs, for convenience require ABSPATH . 'wp-admin/includes/admin.php'; -do_action( 'admin_init' ); WP_CLI::get_runner()->after_wp_load(); From 5322b2bd65d8d08206d4f0a8a3f71bc801715d69 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 17:54:10 +0300 Subject: [PATCH 2183/5359] whitespace fixes [ci skip] --- php/commands/import.php | 4 ++-- php/commands/user.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index d114d4f9d..39fccb8f6 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -19,7 +19,6 @@ class Import_Command extends WP_CLI_Command { * @synopsis <file> --authors=<authors> [--skip=<data-type>] */ public function __invoke( $args, $assoc_args ) { - list( $file ) = $args; if ( ! file_exists( $file ) ) @@ -255,14 +254,15 @@ private function process_author_mapping( $authors_arg, $author_data ) { * Read an author mapping file */ private function read_author_mapping_file( $file ) { - $author_mapping = array(); + foreach ( new \WP_CLI\Iterators\CSV( $file ) as $i => $author ) { if ( ! array_key_exists( 'old_user_login', $author ) || ! array_key_exists( 'new_user_login', $author ) ) return new WP_Error( 'invalid-author-mapping', "Author mapping file isn't properly formatted." ); $author_mapping[] = $author; } + return $author_mapping; } diff --git a/php/commands/user.php b/php/commands/user.php index b694aaa67..c14108df5 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -473,7 +473,7 @@ public function add_cap( $args, $assoc_args ) { if ( $user ) { $cap = $args[1]; $user->add_cap( $cap ); - + WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); } } @@ -502,7 +502,7 @@ public function remove_cap( $args, $assoc_args ) { if ( $user ) { $cap = $args[1]; $user->remove_cap( $cap ); - + WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); } } From d5f2bb15c0bbcef834e3f6863d3d94240acdaae6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 20:00:07 +0300 Subject: [PATCH 2184/5359] bring back accidentally removed test; see #674 --- features/core.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/core.feature b/features/core.feature index 9d248d631..a06a966c9 100644 --- a/features/core.feature +++ b/features/core.feature @@ -101,6 +101,12 @@ Feature: Manage WordPress installation false """ + When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` + Then STDOUT should be: + """ + true + """ + # Can complain that it's already installed, but don't exit with an error code When I try `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then the return code should be 0 From 3106ee674b65b22da7f6139b0040448aaeba3e2c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 22:00:34 +0300 Subject: [PATCH 2185/5359] resurect Phar building code removed in 8483fb709b2285a033515f59b4ad818468a0372a changes: * make WP_CLI_ROOT relative to the root dir, not to php/ * remove man/ and add vendor/rmmcue --- php/boot-phar.php | 6 +++ utils/make-phar.php | 88 ++++++++++++++++++++++++++++++++++++++++ utils/test-phar-download | 6 +++ utils/update-phar | 46 +++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 php/boot-phar.php create mode 100644 utils/make-phar.php create mode 100755 utils/test-phar-download create mode 100755 utils/update-phar diff --git a/php/boot-phar.php b/php/boot-phar.php new file mode 100644 index 000000000..35b82e3a2 --- /dev/null +++ b/php/boot-phar.php @@ -0,0 +1,6 @@ +<?php + +define( 'WP_CLI_ROOT', 'phar://wp-cli.phar' ); + +include WP_CLI_ROOT . '/php/wp-cli.php'; + diff --git a/utils/make-phar.php b/utils/make-phar.php new file mode 100644 index 000000000..df96bab37 --- /dev/null +++ b/utils/make-phar.php @@ -0,0 +1,88 @@ +<?php + +if ( !isset( $argv[1] ) ) { + echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet]\n"; + exit(1); +} + +define( 'DEST_PATH', $argv[1] ); + +define( 'BE_QUIET', in_array( '--quiet', $argv ) ); + +function get_iterator( $dir ) { + return new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) + ); +} + +function add_file( $phar, $path ) { + $key = str_replace( './', '', $path ); + + if ( !BE_QUIET ) + echo "$key - $path\n"; + + $phar[ $key ] = file_get_contents( $path ); +} + +$phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); + +$phar->startBuffering(); + +// php files +foreach ( get_iterator( './php' ) as $path ) { + if ( !preg_match( '/\.php$/', $path ) ) + continue; + + add_file( $phar, $path ); +} + +// non-php files +$additional_dirs = array( + './templates', +); + +foreach ( $additional_dirs as $dir ) { + foreach ( get_iterator( $dir ) as $path ) { + add_file( $phar, $path ); + } +} + +// dependencies +$ignored_paths = array( + '/.git', +); + +$vendor_dirs = array( + './vendor/mustache', + './vendor/rmccue', + './vendor/wp-cli', + './vendor/composer', +); + +foreach ( $vendor_dirs as $vendor_dir ) { + foreach ( get_iterator( $vendor_dir ) as $path ) { + foreach ( $ignored_paths as $ignore ) { + if ( strpos( $path, $ignore ) ) + continue 2; + } + + add_file( $phar, $path ); + } +} + +add_file( $phar, './vendor/autoload.php' ); + +$phar->setStub( <<<EOB +#!/usr/bin/env php +<?php +Phar::mapPhar(); +include 'phar://wp-cli.phar/php/boot-phar.php'; +__HALT_COMPILER(); +?> +EOB +); + +$phar->stopBuffering(); + +echo "Generated " . DEST_PATH . "\n"; + diff --git a/utils/test-phar-download b/utils/test-phar-download new file mode 100755 index 000000000..f1a47e519 --- /dev/null +++ b/utils/test-phar-download @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | md5sum | cut -d ' ' -f 1) + +echo "expected:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.md5) +echo "actual: " $actual_checksum diff --git a/utils/update-phar b/utils/update-phar new file mode 100755 index 000000000..ea79bf112 --- /dev/null +++ b/utils/update-phar @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -ex + +current_rev=$(git rev-parse HEAD) +current_rev=${current_rev:0:10} + +packages_repo=../wp-cli-packages + +fname="phar/wp-cli.phar" + +# generate archive +php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet + +cd $packages_repo + +# smoke test +php $fname --version + +# check which wp-cli commit the previous Phar archive was based on +# can't use the md5 hash, since it will be different each time the +# archive is generated +new_commit_subj="update wp-cli.phar to wp-cli/wp-cli@$current_rev" + +current_commit_subj=$(git show -s --pretty=format:%s HEAD) + +if [ "$new_commit_subj" = "$current_commit_subj" ]; then + echo "already at latest revision" + exit 1 +fi + +# generate md5 checksum +if [ command -v md5sum > /dev/null ] +then + md5hash=$(md5sum $fname) +else + md5hash=$(md5 -r $fname) +fi + +echo $md5hash | cut -d ' ' -f 1 > $fname.md5 + +git add $fname $fname.md5 + +git commit -m "$new_commit_subj" + +git push From ceefca839c6fb9615f33fbd1258347f548d8e83a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 22:52:47 +0300 Subject: [PATCH 2186/5359] add symfony/finder as dev dependency --- composer.json | 3 ++ utils/make-phar.php | 77 +++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/composer.json b/composer.json index 0e5aa5451..8e1c9f77c 100644 --- a/composer.json +++ b/composer.json @@ -19,5 +19,8 @@ }, "autoload": { "psr-0": { "WP_CLI": "php" } + }, + "require-dev": { + "symfony/finder": "~2.3" } } diff --git a/utils/make-phar.php b/utils/make-phar.php index df96bab37..9ce99660d 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -1,5 +1,9 @@ <?php +require './vendor/autoload.php'; + +use Symfony\Component\Finder\Finder; + if ( !isset( $argv[1] ) ) { echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet]\n"; exit(1); @@ -9,12 +13,6 @@ define( 'BE_QUIET', in_array( '--quiet', $argv ) ); -function get_iterator( $dir ) { - return new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) - ); -} - function add_file( $phar, $path ) { $key = str_replace( './', '', $path ); @@ -28,46 +26,37 @@ function add_file( $phar, $path ) { $phar->startBuffering(); -// php files -foreach ( get_iterator( './php' ) as $path ) { - if ( !preg_match( '/\.php$/', $path ) ) - continue; - - add_file( $phar, $path ); -} - -// non-php files -$additional_dirs = array( - './templates', -); - -foreach ( $additional_dirs as $dir ) { - foreach ( get_iterator( $dir ) as $path ) { - add_file( $phar, $path ); - } +// PHP files +$finder = new Finder(); +$finder + ->files() + ->ignoreVCS(true) + ->name('*.php') + ->in('./php') + ->in('./vendor/wp-cli') + ->in('./vendor/mustache') + ->in('./vendor/rmccue/requests') + ->in('./vendor/composer') + ->exclude('test') + ->exclude('tests') + ->exclude('php-cli-tools/examples') + ; + +foreach ( $finder as $file ) { + add_file( $phar, $file ); } -// dependencies -$ignored_paths = array( - '/.git', -); - -$vendor_dirs = array( - './vendor/mustache', - './vendor/rmccue', - './vendor/wp-cli', - './vendor/composer', -); - -foreach ( $vendor_dirs as $vendor_dir ) { - foreach ( get_iterator( $vendor_dir ) as $path ) { - foreach ( $ignored_paths as $ignore ) { - if ( strpos( $path, $ignore ) ) - continue 2; - } - - add_file( $phar, $path ); - } +// other files +$finder = new Finder(); +$finder + ->files() + ->ignoreVCS(true) + ->name('*.mustache') + ->in('./templates') + ; + +foreach ( $finder as $file ) { + add_file( $phar, $file ); } add_file( $phar, './vendor/autoload.php' ); From bad20dad4bebe798c3422968a12ae055795070c3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 23:31:08 +0300 Subject: [PATCH 2187/5359] bump version to 0.12-alpha2 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index d3638664d..b6fda097a 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.12-alpha' ); +define( 'WP_CLI_VERSION', '0.12-alpha2' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From b46b4ea747cc687b747b9d8550fa8eb5a570589a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 23:20:29 +0300 Subject: [PATCH 2188/5359] run the functional tests against the Phar file --- bin/ci/run_build.sh | 11 ++++++++++- features/bootstrap/Process.php | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bin/ci/run_build.sh b/bin/ci/run_build.sh index 2fb25dfea..f3cd75e8e 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/run_build.sh @@ -4,4 +4,13 @@ set -ex phpunit -php behat.phar --format progress +# Run the functional tests against the Phar file + +WP_CLI_BIN_DIR=/tmp/wp-cli-phar + +mkdir -p $WP_CLI_BIN_DIR +php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet +mv wp-cli.phar $WP_CLI_BIN_DIR/wp +chmod +x $WP_CLI_BIN_DIR/wp + +WP_CLI_BIN_DIR=$WP_CLI_BIN_DIR php behat.phar --format progress diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 992428a0c..072b6b185 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -28,8 +28,10 @@ public function run( $subdir = '' ) { ); // Ensure we're using the expected `wp` binary + $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, array( - 'PATH' => realpath( __DIR__ . "/../../bin" ) . ':' . getenv( 'PATH' ), + 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), 'BEHAT_RUN' => 1 ) ); From b23a23051b81f3fe0677d3fddb487687253120fa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 23:21:32 +0300 Subject: [PATCH 2189/5359] phar: add missing rumsaa/array_column dependency --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 9ce99660d..a9f5477c4 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -37,6 +37,7 @@ function add_file( $phar, $path ) { ->in('./vendor/mustache') ->in('./vendor/rmccue/requests') ->in('./vendor/composer') + ->in('./vendor/rhumsaa/array_column') ->exclude('test') ->exclude('tests') ->exclude('php-cli-tools/examples') From cef5beb9ca909ceeecb10f19891132d5b978dfcf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 14 Aug 2013 23:38:45 +0300 Subject: [PATCH 2190/5359] phar: add all files from the templates/ directory --- utils/make-phar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index a9f5477c4..8f7bb90cd 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -52,7 +52,7 @@ function add_file( $phar, $path ) { $finder ->files() ->ignoreVCS(true) - ->name('*.mustache') + ->ignoreDotFiles(false) ->in('./templates') ; From ec9c530c60c64ce8a37aecea8226564873d00b71 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Aug 2013 00:03:38 +0300 Subject: [PATCH 2191/5359] give shorter names to ci scripts --- .travis.yml | 4 ++-- bin/ci/{run_build.sh => build.sh} | 6 +++--- bin/ci/{install_dependencies.sh => prepare.sh} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename bin/ci/{run_build.sh => build.sh} (79%) rename bin/ci/{install_dependencies.sh => prepare.sh} (100%) diff --git a/.travis.yml b/.travis.yml index 7a642a454..e05a986c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,9 @@ matrix: - php: 5.5 env: WP_VERSION=3.4.2 -before_script: ./bin/ci/install_dependencies.sh +before_script: ./bin/ci/prepare.sh -script: ./bin/ci/run_build.sh +script: ./bin/ci/build.sh notifications: email: diff --git a/bin/ci/run_build.sh b/bin/ci/build.sh similarity index 79% rename from bin/ci/run_build.sh rename to bin/ci/build.sh index f3cd75e8e..1dd2c52e2 100755 --- a/bin/ci/run_build.sh +++ b/bin/ci/build.sh @@ -2,15 +2,15 @@ set -ex +# Run the unit tests phpunit -# Run the functional tests against the Phar file - +# Create the Phar file WP_CLI_BIN_DIR=/tmp/wp-cli-phar - mkdir -p $WP_CLI_BIN_DIR php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet mv wp-cli.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp +# Run the functional tests WP_CLI_BIN_DIR=$WP_CLI_BIN_DIR php behat.phar --format progress diff --git a/bin/ci/install_dependencies.sh b/bin/ci/prepare.sh similarity index 100% rename from bin/ci/install_dependencies.sh rename to bin/ci/prepare.sh From 0b828831e6c9219963a66f2b3ff1e6fcd0e85f9a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Aug 2013 00:07:02 +0300 Subject: [PATCH 2192/5359] move WP_CLI_BIN_DIR env variable to .travis.yml --- .travis.yml | 7 +++++-- bin/ci/build.sh | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e05a986c7..41ebe18aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,11 @@ php: - 5.5 env: - - WP_VERSION=latest - - WP_VERSION=3.4.2 + global: + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + matrix: + - WP_VERSION=latest + - WP_VERSION=3.4.2 matrix: exclude: diff --git a/bin/ci/build.sh b/bin/ci/build.sh index 1dd2c52e2..4c77a2b8a 100755 --- a/bin/ci/build.sh +++ b/bin/ci/build.sh @@ -6,11 +6,10 @@ set -ex phpunit # Create the Phar file -WP_CLI_BIN_DIR=/tmp/wp-cli-phar mkdir -p $WP_CLI_BIN_DIR php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet mv wp-cli.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp # Run the functional tests -WP_CLI_BIN_DIR=$WP_CLI_BIN_DIR php behat.phar --format progress +php behat.phar --format progress From a2d38e61a3710f37617be47055e7f1f88ee63e77 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Aug 2013 21:50:05 +0000 Subject: [PATCH 2193/5359] Change load order of autoloaders --- php/utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 633603435..70f810035 100644 --- a/php/utils.php +++ b/php/utils.php @@ -8,8 +8,8 @@ function load_dependencies() { $vendor_paths = array( - WP_CLI_ROOT . '/vendor', // top-level project - WP_CLI_ROOT . '/../../../vendor', // part of a larger project + WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) + WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone ); $has_autoload = false; From 1f62efd183976d173c3aa58962dca0a5305c2d6e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Aug 2013 00:47:58 +0300 Subject: [PATCH 2194/5359] move Phar building to ci/prepare.sh and rename ci/build.sh to ci/test.sh --- .travis.yml | 2 +- bin/ci/build.sh | 15 --------------- bin/ci/prepare.sh | 15 +++++++++------ bin/ci/test.sh | 9 +++++++++ 4 files changed, 19 insertions(+), 22 deletions(-) delete mode 100755 bin/ci/build.sh create mode 100755 bin/ci/test.sh diff --git a/.travis.yml b/.travis.yml index 41ebe18aa..67e8d32ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ matrix: before_script: ./bin/ci/prepare.sh -script: ./bin/ci/build.sh +script: ./bin/ci/test.sh notifications: email: diff --git a/bin/ci/build.sh b/bin/ci/build.sh deleted file mode 100755 index 4c77a2b8a..000000000 --- a/bin/ci/build.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -ex - -# Run the unit tests -phpunit - -# Create the Phar file -mkdir -p $WP_CLI_BIN_DIR -php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet -mv wp-cli.phar $WP_CLI_BIN_DIR/wp -chmod +x $WP_CLI_BIN_DIR/wp - -# Run the functional tests -php behat.phar --format progress diff --git a/bin/ci/prepare.sh b/bin/ci/prepare.sh index 1b2e5723a..efb241ced 100755 --- a/bin/ci/prepare.sh +++ b/bin/ci/prepare.sh @@ -4,15 +4,18 @@ set -ex -# install Behat -curl http://behat.org/downloads/behat.phar > behat.phar - -# install dependencies composer install --no-interaction --prefer-source -# set up WP install +# the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR +mkdir -p $WP_CLI_BIN_DIR +php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet +mv wp-cli.phar $WP_CLI_BIN_DIR/wp +chmod +x $WP_CLI_BIN_DIR/wp + +# Travis CI doesn't come with Behat pre-installed +curl http://behat.org/downloads/behat.phar > behat.phar + ./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ -# set up database mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/bin/ci/test.sh b/bin/ci/test.sh new file mode 100755 index 000000000..3a94100a7 --- /dev/null +++ b/bin/ci/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +# Run the unit tests +phpunit + +# Run the functional tests +php behat.phar --format progress From 7622f0b96e28c05f410496e37a4495e56162391f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Aug 2013 17:08:43 +0300 Subject: [PATCH 2195/5359] automatically deploy Phar file to wp-cli/builds --- .travis.yml | 34 ++++++++++++++++++++++++++++++---- bin/ci/deploy.sh | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100755 bin/ci/deploy.sh diff --git a/.travis.yml b/.travis.yml index 67e8d32ca..536c0f539 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,20 +6,46 @@ php: env: global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + # Encripted deploy key. See https://gist.github.com/scribu/6241271 + - secure: "U8gOPW2m9fkJW8omnPjFHFZutGIqAAfVs0H1izpSKJhclUfYAGjAGl1Cb6ZiUp3jZE11iWa+fAZ5mmmLAQ5L9ijta40igfFw0s+o/Vt3WBM4a3Vdqpg6civ0rDi9tJYuwtMaEi/kF/yuhKzUT80EAMqVix5xPnf963iIUPyarfY=" + - secure: "W9t7pG5h/Khoi+TrxplpSeTWxaTr7r6cYRVJBsXgghZLDXsU/qn/OhGDdY+IMfSgzO49wjFyLh2EOs8zZSujY75fgFffK2+jd/882NUlpvpXoW9C3yEfZhLJVQZI/1idnpDe9f6zA0XlpBn3bQ2QeS3i2a/JwOGCD8BQjNobk1M=" + - secure: "YsVv3AKeHyr6nwkjhB+VingCdWIzfNP2VYMMHf841rnH6HsAXNw8PJcinnVYeMd15kgjA3Yk8PbITOmzZkf9yjAmbgJTvNempEElF/KG42FkoCACtZ2Wc/jIL9zEi5o47qUicwiS6LLWYx1uQa6vActpE4KdrcDLJ6pQHp/s7ss=" + - secure: "Qsx9+R7VBSdk3st1yVyRMYgAHV58lUUSqXJjvxAkUFXsumCEVFiNpuKepvA5+EZHHnpo7zQOK6EzrIDgUBHGfwEvVumI5eur8G1RKdHnvotuz4D7YCdoRnnrzbhJkAPnVcGrIBIHd5GlDHPTVBij77JwMq5kg2tfKoKcW3RuQTc=" + - secure: "NY3grWJVgnRcA7jQW0/DbPrSkIHVkGxfhdmVSVuSfhsRq5j4kA8/zhWTIwuQ4RtkE88GWye6NarJfjFYnz2KgnCUeaFPFdnB0VE3C3OUeWIsbitjYeqycUd1+JOikPREDZaXjBb79Ve6PGTHv7CUQ+R8vBYSR7eXGqNF9SBDTEw=" + - secure: "XuKAHb35W5vN/JX8iV4FipVdxUH8GbrfheOpOAwgZ0WS5+ua79farr6q73BIPzW8AMAg3p+p1UWNoKLFEaszKuW/mT7dQExsQO04aZ7ESeLbaoKS28EMUCVeOJl0Vo+AxNSruUAIbanvggyAcxq1ILGqH9iaHLpb9BgPei3LdEc=" + - secure: "GSPAeXVhSz5MQ/FRoGFQ7As6a3w/hsq5CslpSCvNz3q7jXUjK+HPzhq3MpWF8sBd6j5IS5YUn1Pl383BDfWj/RYhIzruzIwZhgD+M7VaFFHXcS7y6i9ritXKaw2g4u+16DYQC0zg0jBODXd5NspzyeB6IA5RSecqZeuPW7z/kJc=" + - secure: "BneSPyRBtN8BPNU//rAqFmma0HfVW2GXTgRf/vuTWDnkQ9aE3Uz4S8mlA4lcVpNigvVgRop7MltLVvpWNPDk4tVPu19CkhzKXIEj6Ny6UgD6f4ZHXid/T7I6T50dtJOfcj6leDih92M2JMNaBLPRxOvAUv6yN5FrSV2LNE/0XOw=" + - secure: "URrY5IoJxf40PX+UAldnJK5HZgL5EhJ/n+ildhltyFxDu3E29Ic8Unx89M4Cb09buv1sFBFMC59q3jxck9XOWBsxiRct9y/lvnzI1R1GmVoNiTssg7wLqL6MuD2iy/4fFHFgne2mg7DVDtujCUwTQgtdz7yoh8fQeF/6lBmge1U=" + - secure: "AlNVx6gd7x7lBgrk1Dcna3yfUgdx0wZEdH8V/5NaGirfGMnO7x7ZB1pQ2LVS4EIDCZSELqUCWirFzloJtxOyUJ5AZWCu2YSGzn0cxsHkZDdBsQ1J/oPYpO8PZ9bRBDhGqqqq96F4bPxav1e8G4TH165wBB6MsR1M/He0gPrL57g=" + - secure: "JOvovCe2mKyX6/Ihvqzu93px0RdE/RsNnyDJ6EYTJjFMOhpTP/GTQQcLhMVYq62pM6Ng9/jCQl5VMWEk0f7SGL7X/RW6Rz8HaL1KWy2U9/z67FQPMz+WlJMLTP77PXJouqVemG7Om8Mheg8vMUcgXV1W/vgoljzgeBf1zseQODg=" + - secure: "H7caXIeMS7r6mLuD2aombGuGskD3VwdptcPaY2X/natpMtvHHjbyonUFE26prTWsxFc29wT9Ot705w+yo0DK42SNGaqACpy1tjq6v6xwTCjIIYeGenfnb4FiFjOROCfCXdigJ9ANDS9ufvEd2pgB12BChyLvDVX8pn3FqVzO/wQ=" + - secure: "HbyEWzWOK/dtyYY4J6BcwwCy5EWKzRI1K51Qgsc7nyN6ZlQ4P7vvFmQuLX79zTX9k3PJb58/7Ahl0xQe2mhnpK3awAEuW4ZyqL9CFQnsn7FXAAm7DWcnD8WZvOR0BitiVOEAziuh9dM7FQYBkaq6vSU+Og7NC48osDX/y4PkmG8=" + - secure: "OtXKQFf7ef/1R67U+923TJwx8uafHkhIT3wUmw3QQFkimUDHAH3tPmEk5Qy6a59aMDEO0ESIZdTfwUcMcmfgqhAxNlvmDFSnfOgJmRxzeCD036/sU/8td8VNwRW93iCu48LoGcBfVcP3lM7EJVPK2NGjneBKjna8ekLMcSx8tmE=" + - secure: "G1+MwEPgBswGI3CGtvpwV6ELauqBgBo5b5QLDd44ijqhTOYiUZz5tzU2iKR+5sMm1TqVQjGpSNC/+Hpi4WTKnKCPfKnJh/Z4/859a90GlBytsEGLGK9kAduVeLiJ1T5aOA5lHAhHsWe+CL5+d4LVlFdzBeggcXjJj5+DHHZe7+s=" + - secure: "Z6jHEwZCotrkAvIbj7/fY2fNFvDK6CTZgkpRp+VRdTk8/krWBIBGpTXgSOPXxcx+yNWooRw/mS3sazFQzZ0cv2kqGFtKxTThfAHnWNf2wMlxXvk+FGGGlIOpwt6sB5Eh3N7sF/ZkfioYE66jIVWZg4AiXJ+iEH+DKNFKVrSkwk0=" + - secure: "BzGrbJOSRsuvPrHsSY3zwOn05G9qYq/l8mBltGikRgjMGLEJpH+9+vO5YyCSgS4tDsihSw+SFpNQojS3wDUyNFT7pe0IRnCukletOVp+gwPHdqD8NoEw1gKlWFhgFZNRrc/Ma6bQqPgaQmTV+HKbSM/oAIyW5NKA/+66WTESCrg=" + - secure: "JWzwwyjbZqrCki9ijj75+X2xRS7eLJDahiAS9x87GDz8wbCMuTpWzkA+lbrj5Za3wTRUe5S4wcAELhal2x0CTRO8wUQkxSo2cATN9Bk2p00SJtCBxRJrq2H5QmmYaLIluOmyIQNDpaNS/O+TQGgUCpVg2x8KzqgiCYYGXewgJ1g=" + - secure: "g1QgDqGFAYJqxv3qyT2tQplT62o/3xA19SAjO4sAzgEp8t/h6J9K+ehbyz3tlsGJhOP/b7VGyjvnUKLZ+4BlaRhSsS1TND753+YhWGD2PKhIZ58hdW4m4ARY0yrRkVFMQqEyyIj8D+TBC713yDc58L/tmehf8ZljZpFG2PICidE=" + - secure: "Gj9fw1wM3dfgZab0XqULeR9loDj9Gsa99z8bPgfAEWS7cWqoTitF2Y9SolUX1WZyOJUZ+5Shrl7jnihl8EOlm13wxt680Kmt7jTVX5DUH+NvzWVwkYDrZV7zSFayYZJTdx3FjEvSs+GIVrpzBeBvVFvCTQUuIphPkbxwR0JHonI=" + - secure: "XS4lJJSZ2+4rB+zkt9lsdhG+pZEQ6nUjRSdLcVAgS7f7yvFCOjJYWRXlQ5zP/Gl3/XVe/L8EuGLYZsztauLSd6Ob7nEwnb5vIegLaqzbZd7Yizp9TnBj0AFCqo/ZPY+ZhnURY9OLFqknfQMWhrTeVvGRT94nhnnIF+sxokQgv0M=" + - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" + - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=latest - - WP_VERSION=3.4.2 + - WP_VERSION=latest + - WP_VERSION=3.4.2 DEPLOY_BRANCH=phar-builder matrix: exclude: - php: 5.5 - env: WP_VERSION=3.4.2 + env: WP_VERSION=3.4.2 DEPLOY_BRANCH=phar-builder before_script: ./bin/ci/prepare.sh script: ./bin/ci/test.sh +after_success: ./bin/ci/deploy.sh + notifications: email: on_success: never diff --git a/bin/ci/deploy.sh b/bin/ci/deploy.sh new file mode 100755 index 000000000..a88cba3ba --- /dev/null +++ b/bin/ci/deploy.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# called by Travis CI + +if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then + echo "Not deploying pull requests." + exit +fi + +if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then + echo "Not on the '$DEPLOY_BRANCH' branch." + exit +fi + +# extract private key from decrypted environment variables stored in .travis.yml +echo -n $id_rsa_{00..30} >> ~/.ssh/id_rsa_base64 +base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa + +# anyone can read the build log, so it MUST NOT contain any sensitive data +set -x + +# add github's public key +echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts + +git clone git@github.com:wp-cli/builds.git +cd builds + +git config user.name "Travis CI" +git config user.email "travis@travis-ci.org" +git config push.default "simple" + +mv $WP_CLI_BIN_DIR/wp phar/wp-cli-nightly.phar +chmod -x phar/wp-cli-nightly.phar + +git add phar/wp-cli-nightly.phar +git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" + +git push From 68400d36c171a9a92202c68515e7bb744301d908 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 15 Aug 2013 18:15:34 +0300 Subject: [PATCH 2196/5359] set 'master' as the deploy branch; see #658 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 536c0f539..f683d3af9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,12 @@ env: - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - WP_VERSION=latest - - WP_VERSION=3.4.2 DEPLOY_BRANCH=phar-builder + - WP_VERSION=3.4.2 DEPLOY_BRANCH=master matrix: exclude: - php: 5.5 - env: WP_VERSION=3.4.2 DEPLOY_BRANCH=phar-builder + env: WP_VERSION=3.4.2 DEPLOY_BRANCH=master before_script: ./bin/ci/prepare.sh From f6ab73a592cb3df16b5efb1fabfc9fec1272e7e8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 02:57:15 +0300 Subject: [PATCH 2197/5359] avoid converting iterator into array unless absolutely necessary in format_items() --- php/utils.php | 64 ++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/php/utils.php b/php/utils.php index 70f810035..ef4c45de6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -230,42 +230,30 @@ function format_items( $format, $items, $fields ) { if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); - $output_items = array(); - foreach ( $items as $item ) { - - $output_item = new \stdClass; - foreach ( $fields as $key => $field ) { - - if ( ! isset( $item->$field ) ) { - unset( $fields[$key] ); - continue; - } - - $output_item->$field = $item->$field; - } - - $output_items[] = $output_item; - } - switch ( $format ) { case 'table': $table = new \cli\Table(); $table->setHeaders( $fields ); - foreach ( $output_items as $item ) { - $table->addRow( array_values( (array)$item ) ); + foreach ( $items as $item ) { + $table->addRow( array_values( array_pick( $item, $fields ) ) ); } $table->display(); break; + case 'csv': + write_csv( STDOUT, $items, $fields ); + break; + case 'json': + $out = array(); + foreach ( $items as $item ) { + $out[] = array_pick( $item, $fields ); + } - if ( 'json' == $format ) - echo json_encode( $output_items ); - else - write_csv( STDOUT, $output_items, $fields ); + echo json_encode( $out ); break; } } @@ -278,24 +266,32 @@ function format_items( $format, $items, $fields ) { * @param array $headers List of CSV columns (optional) */ function write_csv( $fd, $rows, $headers = array() ) { - - // Prepare the headers if they were specified - if ( ! empty( $headers ) ) + if ( ! empty( $headers ) ) { fputcsv( $fd, $headers ); + } foreach ( $rows as $row ) { - $row = (array) $row; - if ( ! empty( $headers ) ) { - $build_row = array(); - foreach ( $headers as $key ) { - $build_row[] = $row[ $key ]; - } - $row = $build_row; + $row = array_pick( $row, $headers ); } - fputcsv( $fd, $row ); + + fputcsv( $fd, array_values( $row ) ); + } +} + +/** + * Like array_slice(), but for associative arrays. + */ +function array_pick( $item, $fields ) { + $item = (array) $item; + + $values = array(); + + foreach ( $fields as $field ) { + $values[ $field ] = isset( $item[ $field ] ) ? $item[ $field ] : null; } + return $values; } /** From 262245904b21fcec6962eb2728ca520a7011e146 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 03:03:55 +0300 Subject: [PATCH 2198/5359] introduce iterator_map() and avoid converting iterator to array in `wp site list` --- php/WP_CLI/Iterators/Transform.php | 26 ++++++++++++++++++++++++ php/commands/site.php | 9 ++++----- php/utils.php | 32 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 php/WP_CLI/Iterators/Transform.php diff --git a/php/WP_CLI/Iterators/Transform.php b/php/WP_CLI/Iterators/Transform.php new file mode 100644 index 000000000..823e620b1 --- /dev/null +++ b/php/WP_CLI/Iterators/Transform.php @@ -0,0 +1,26 @@ +<?php + +namespace WP_CLI\Iterators; + +/** + * Aplies one or more callbacks to an item before returning it. + */ +class Transform extends \IteratorIterator { + + private $transformers = array(); + + public function add_transform( $fn ) { + $this->transformers[] = $fn; + } + + public function current() { + $value = parent::current(); + + foreach ( $this->transformers as $fn ) { + $value = $fn( $value ); + } + + return $value; + } +} + diff --git a/php/commands/site.php b/php/commands/site.php index 6da3de8c5..954274842 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -369,13 +369,12 @@ function _list( $_, $assoc_args ) { ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); - $list = array(); - foreach ( $it as $blog ) { + $it = \WP_CLI\Utils\iterator_map( $it, function( $blog ) { $blog->url = $blog->domain . $blog->path; - $list[] = $blog; - } + return $blog; + } ); - WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); + WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); } } diff --git a/php/utils.php b/php/utils.php index ef4c45de6..c313ce9d6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -5,6 +5,7 @@ namespace WP_CLI\Utils; use \WP_CLI\Dispatcher; +use \WP_CLI\Iterators\Transform; function load_dependencies() { $vendor_paths = array( @@ -51,6 +52,37 @@ function load_all_commands() { } } +/** + * Like array_map(), except it returns a new iterator, instead of a modified array. + * + * Example: + * + * $arr = array('Football', 'Socker'); + * + * $it = iterator_map($arr, 'strtolower', function($val) { + * return str_replace('foo', 'bar', $val); + * }); + * + * foreach ( $it as $val ) { + * var_dump($val); + * } + * + * @param array|object Either a plain array or another iterator + * @param callback The function to apply to an element + * @return object An iterator that applies the given callback(s) + */ +function iterator_map( $it, $fn ) { + if ( !is_object( $it ) || !method_exists( $it, 'add_transform' ) ) { + $it = new Transform( $it ); + } + + foreach ( array_slice( func_get_args(), 1 ) as $fn ) { + $it->add_transform( $fn ); + } + + return $it; +} + /** * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true * @param string|array The files (or file) to search for From b9f16a84e0f252477ee044f63cb0dfde25a81d5f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 03:38:35 +0300 Subject: [PATCH 2199/5359] add some missing conversions to/from iterators --- php/utils.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/php/utils.php b/php/utils.php index c313ce9d6..70d5937a9 100644 --- a/php/utils.php +++ b/php/utils.php @@ -72,7 +72,11 @@ function load_all_commands() { * @return object An iterator that applies the given callback(s) */ function iterator_map( $it, $fn ) { - if ( !is_object( $it ) || !method_exists( $it, 'add_transform' ) ) { + if ( is_array( $it ) ) { + $it = new \ArrayIterator( $it ); + } + + if ( !method_exists( $it, 'add_transform' ) ) { $it = new Transform( $it ); } @@ -250,19 +254,24 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ function format_items( $format, $items, $fields ) { - - if ( 'ids' == $format ) { - echo implode( ' ', $items ); - return; - } else if ( 'count' == $format ) { - echo count( $items ); - return; - } - if ( ! is_array( $fields ) ) $fields = explode( ',', $fields ); switch ( $format ) { + case 'count': + if ( !is_array( $items ) ) { + $items = iterator_to_array( $items ); + } + echo count( $items ); + break; + + case 'ids': + if ( !is_array( $items ) ) { + $items = iterator_to_array( $items ); + } + echo implode( ' ', $items ); + break; + case 'table': $table = new \cli\Table(); From 17487544aa9decfc2d5484b0510d5ae364df4a00 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 03:39:22 +0300 Subject: [PATCH 2200/5359] convert user object to array using its to_array() method --- php/commands/user.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index c14108df5..3f8169287 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -66,13 +66,17 @@ public function _list( $args, $assoc_args ) { $users = get_users( $params ); - if ( 'ids' != $params['format'] ) { - foreach ( $users as $user ) { - $user->roles = implode( ',', $user->roles ); - } - } + $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { + if ( !is_object( $user ) ) + return $user; + + $new_user = $user->to_array(); + $new_user['roles'] = implode( ',', $user->roles ); + + return $new_user; + } ); - WP_CLI\Utils\format_items( $params['format'], $users, $fields ); + WP_CLI\Utils\format_items( $params['format'], $it, $fields ); } /** From ae1d08bf2b4a3536f2f259444a9d0fbaf32290fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 03:52:30 +0300 Subject: [PATCH 2201/5359] cast arrays to objects instead of the other way around the advantage is that objects that have magic methods don't need special handling --- php/commands/user.php | 5 ++--- php/utils.php | 18 +++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 3f8169287..3e8bcd415 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -70,10 +70,9 @@ public function _list( $args, $assoc_args ) { if ( !is_object( $user ) ) return $user; - $new_user = $user->to_array(); - $new_user['roles'] = implode( ',', $user->roles ); + $user->roles = implode( ',', $user->roles ); - return $new_user; + return $user; } ); WP_CLI\Utils\format_items( $params['format'], $it, $fields ); diff --git a/php/utils.php b/php/utils.php index 70d5937a9..9c9450427 100644 --- a/php/utils.php +++ b/php/utils.php @@ -278,7 +278,7 @@ function format_items( $format, $items, $fields ) { $table->setHeaders( $fields ); foreach ( $items as $item ) { - $table->addRow( array_values( array_pick( $item, $fields ) ) ); + $table->addRow( array_values( pick_fields( $item, $fields ) ) ); } $table->display(); @@ -291,7 +291,7 @@ function format_items( $format, $items, $fields ) { case 'json': $out = array(); foreach ( $items as $item ) { - $out[] = array_pick( $item, $fields ); + $out[] = pick_fields( $item, $fields ); } echo json_encode( $out ); @@ -313,7 +313,7 @@ function write_csv( $fd, $rows, $headers = array() ) { foreach ( $rows as $row ) { if ( ! empty( $headers ) ) { - $row = array_pick( $row, $headers ); + $row = pick_fields( $row, $headers ); } fputcsv( $fd, array_values( $row ) ); @@ -321,15 +321,19 @@ function write_csv( $fd, $rows, $headers = array() ) { } /** - * Like array_slice(), but for associative arrays. + * Pick fields from an associative array or object. + * + * @param array|object Associative array or object to pick fields from + * @param array List of fields to pick + * @return array */ -function array_pick( $item, $fields ) { - $item = (array) $item; +function pick_fields( $item, $fields ) { + $item = (object) $item; $values = array(); foreach ( $fields as $field ) { - $values[ $field ] = isset( $item[ $field ] ) ? $item[ $field ] : null; + $values[ $field ] = isset( $item->$field ) ? $item->$field : null; } return $values; From 6bb30cc36a960ad900cb08f862460d0c75b6e026 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 18:09:27 +0300 Subject: [PATCH 2202/5359] make wp.bat executable --- bin/wp.bat | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/wp.bat diff --git a/bin/wp.bat b/bin/wp.bat old mode 100644 new mode 100755 From 5e240f3ea3b38899beace7166215387d8830ad8b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 18:11:30 +0300 Subject: [PATCH 2203/5359] always use bundled autoload in Phar file see #658 --- composer.json | 3 ++- php/utils.php | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 8e1c9f77c..91247c46f 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "psy/psysh": "Enhanced `wp shell` functionality" }, "autoload": { - "psr-0": { "WP_CLI": "php" } + "psr-0": { "WP_CLI": "php" }, + "files": [ "php/Spyc.php" ] }, "require-dev": { "symfony/finder": "~2.3" diff --git a/php/utils.php b/php/utils.php index 9c9450427..7db1d122c 100644 --- a/php/utils.php +++ b/php/utils.php @@ -8,6 +8,11 @@ use \WP_CLI\Iterators\Transform; function load_dependencies() { + if ( 0 === strpos( WP_CLI_ROOT, 'phar:' ) ) { + require WP_CLI_ROOT . '/vendor/autoload.php'; + return; + } + $vendor_paths = array( WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone @@ -27,8 +32,6 @@ function load_dependencies() { fputs( STDERR, "Internal error: Can't find Composer autoloader.\n" ); exit(3); } - - include WP_CLI_ROOT . '/php/Spyc.php'; } function load_command( $name ) { From 7bd05bacaf1d92172fe8f1f9c5a97b3b06119da2 Mon Sep 17 00:00:00 2001 From: mattes <matthias.kadenbach@gmail.com> Date: Fri, 16 Aug 2013 19:20:01 +0200 Subject: [PATCH 2204/5359] fixed bug, when having a port number in host --- php/commands/db.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 66ed93d50..fc04951e7 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -119,9 +119,17 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( 'mysqldump', Utils\esc_cmd( - '%s --user=%s --host=%s --result-file %s', - DB_NAME, DB_USER, DB_HOST, $result_file ) ); + if( strpos( DB_HOST, ':' ) !== false ) { + // extract port from host + $DB_HOST = preg_split("/:/", DB_HOST); + self::run( 'mysqldump', Utils\esc_cmd( + '%s --user=%s --host=%s --port=%s --result-file %s', + DB_NAME, DB_USER, $DB_HOST[0], $DB_HOST[1], $result_file ) ); + } else { + self::run( 'mysqldump', Utils\esc_cmd( + '%s --user=%s --host=%s --result-file %s', + DB_NAME, DB_USER, DB_HOST, $result_file ) ); + } WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } From e78c3abc194f9866b77b21cdc28b9df5e8cce2de Mon Sep 17 00:00:00 2001 From: mattes <matthias.kadenbach@gmail.com> Date: Fri, 16 Aug 2013 19:45:30 +0200 Subject: [PATCH 2205/5359] adding support for sockets --- php/commands/db.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index fc04951e7..e126ec883 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -119,17 +119,29 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - if( strpos( DB_HOST, ':' ) !== false ) { - // extract port from host - $DB_HOST = preg_split("/:/", DB_HOST); - self::run( 'mysqldump', Utils\esc_cmd( - '%s --user=%s --host=%s --port=%s --result-file %s', - DB_NAME, DB_USER, $DB_HOST[0], $DB_HOST[1], $result_file ) ); - } else { - self::run( 'mysqldump', Utils\esc_cmd( - '%s --user=%s --host=%s --result-file %s', - DB_NAME, DB_USER, DB_HOST, $result_file ) ); - } + $host_parts = explode( ':', DB_HOST ); + if ( count( $host_parts ) == 2 ) { + list( $host, $extra ) = $host_parts; + } else { + $host = DB_HOST; + } + + $arg_str = ''; + + if ( isset( $extra ) ) { + if ( is_numeric($extra) ) { + $arg_str .= Utils\esc_cmd( + '--port=%s --protocol=%s', intval( $extra ), 'tcp' ); + } else if ( trim($extra) !== '' ) { + $arg_str .= Utils\esc_cmd( + '--socket=%s', trim( $extra ) ); + } + } + + $arg_str .= Utils\esc_cmd( ' --host=%s --user=%s --result-file=%s %s', + $host, DB_USER, $result_file, DB_NAME ); + + self::run( 'mysqldump', $arg_str ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } From f50f84118ad753c42175310d164c547a338437a6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 21:34:19 +0300 Subject: [PATCH 2206/5359] pass MYSQL_PWD to proc_open(), instead of altering the current environment --- php/utils.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/utils.php b/php/utils.php index 7db1d122c..b3e02b341 100644 --- a/php/utils.php +++ b/php/utils.php @@ -395,13 +395,13 @@ function run_mysql_query( $query, $args ) { } function run_mysql_command( $cmd, $arg_str, $pass ) { - $old_val = getenv( 'MYSQL_PWD' ); - $final_cmd = "$cmd --no-defaults $arg_str"; - putenv( 'MYSQL_PWD=' . $pass ); - $r = proc_close( proc_open( $final_cmd, array( STDIN, STDOUT, STDERR ), $pipes ) ); - putenv( 'MYSQL_PWD=' . $old_val ); + $descriptors = array( STDIN, STDOUT, STDERR ); + + $r = proc_close( proc_open( $final_cmd, $descriptors, $pipes, null, array( + 'MYSQL_PWD' => $pass + ) ) ); if ( $r ) exit( $r ); } From a9f7b7c76d6e22f38ae922efa86de13f03324c63 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 23:24:15 +0300 Subject: [PATCH 2207/5359] Refactor MySQL utilities: * extract mysql_host_to_cli_args() helper * make run_mysql_command() accept an associative array of args * remove redundant run_mysql_query() utility --- features/bootstrap/FeatureContext.php | 3 +- php/commands/core.php | 6 ++- php/commands/db.php | 78 ++++++++++++--------------- php/utils.php | 68 +++++++++++++---------- 4 files changed, 81 insertions(+), 74 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4c5def0e8..fc3a15c51 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -113,7 +113,8 @@ private function set_cache_dir() { } private static function run_sql( $sql ) { - Utils\run_mysql_query( $sql, array( + Utils\run_mysql_command( 'mysql --no-defaults', array( + 'execute' => $sql, 'host' => 'localhost', 'user' => self::$db_settings['dbuser'], 'pass' => self::$db_settings['dbpass'], diff --git a/php/commands/core.php b/php/commands/core.php index 81762a63e..5dc62c925 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -184,7 +184,8 @@ public function config( $_, $assoc_args ) { WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); // Check DB connection - Utils\run_mysql_query( ';', array( + Utils\run_mysql_command( 'mysql --no-defaults', array( + 'execute' => ';', 'host' => $assoc_args['dbhost'], 'user' => $assoc_args['dbuser'], 'pass' => $assoc_args['dbpass'], @@ -699,7 +700,8 @@ function init_tests( $args, $assoc_args ) { // Create the database $query = sprintf( 'CREATE DATABASE IF NOT EXISTS `%s`', $assoc_args['dbname'] ); - Utils\run_mysql_query( $query, array( + Utils\run_mysql_command( 'mysql --no-defaults', array( + 'execute' => $query, 'host' => $assoc_args['dbhost'], 'user' => $assoc_args['dbuser'], 'pass' => $assoc_args['dbpass'], diff --git a/php/commands/db.php b/php/commands/db.php index e126ec883..0f2be91f2 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -63,9 +63,8 @@ function reset( $_, $assoc_args ) { * Optimize the database. */ function optimize() { - self::run( 'mysqlcheck', Utils\esc_cmd( - '--optimize --host=%s --user=%s %s', - DB_HOST, DB_USER, DB_NAME + self::run( Utils\esc_cmd( 'mysqlcheck %s', DB_NAME ), array( + 'optimize' => true, ) ); WP_CLI::success( "Database optimized." ); @@ -75,9 +74,9 @@ function optimize() { * Repair the database. */ function repair() { - self::run( 'mysqlcheck', Utils\esc_cmd( - '--repair --host=%s --user=%s %s', - DB_HOST, DB_USER, DB_NAME ) ); + self::run( Utils\esc_cmd( 'mysqlcheck %s', DB_NAME ), array( + 'repair' => true, + ) ); WP_CLI::success( "Database repaired." ); } @@ -88,9 +87,9 @@ function repair() { * @alias connect */ function cli() { - self::run( 'mysql', Utils\esc_cmd( - '--host=%s --user=%s --database=%s', - DB_HOST, DB_USER, DB_NAME ) ); + self::run( 'mysql --no-defaults', array( + 'database' => DB_NAME + ) ); } /** @@ -99,14 +98,16 @@ function cli() { * @synopsis [<sql>] */ function query( $args ) { - $cmd = '--host=%s --user=%s --database=%s'; - $cmd = Utils\esc_cmd( $cmd, DB_HOST, DB_USER, DB_NAME ); + $assoc_args = array( + 'database' => DB_NAME + ); + // The query might come from STDIN if ( !empty( $args ) ) { - $cmd .= Utils\esc_cmd( ' --execute=%s', $args[0] ); + $assoc_args['execute'] = $args[0]; } - self::run( 'mysql', $cmd ); + self::run( 'mysql --no-defaults', $assoc_args ); } /** @@ -119,29 +120,9 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - $host_parts = explode( ':', DB_HOST ); - if ( count( $host_parts ) == 2 ) { - list( $host, $extra ) = $host_parts; - } else { - $host = DB_HOST; - } - - $arg_str = ''; - - if ( isset( $extra ) ) { - if ( is_numeric($extra) ) { - $arg_str .= Utils\esc_cmd( - '--port=%s --protocol=%s', intval( $extra ), 'tcp' ); - } else if ( trim($extra) !== '' ) { - $arg_str .= Utils\esc_cmd( - '--socket=%s', trim( $extra ) ); - } - } - - $arg_str .= Utils\esc_cmd( ' --host=%s --user=%s --result-file=%s %s', - $host, DB_USER, $result_file, DB_NAME ); - - self::run( 'mysqldump', $arg_str ); + self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), array( + 'result-file' => $result_file + ) ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } @@ -153,10 +134,19 @@ function export( $args, $assoc_args ) { */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); + if ( !file_exists( $result_file ) ) { + WP_CLI::error( sprintf( 'Import file missing: %s', $result_file ) ); + } + + $descriptors = array( + array( 'file', $result_file, 'r' ), + STDOUT, + STDERR, + ); - self::run( 'mysql', Utils\esc_cmd( - '%s --user=%s --host=%s < %s', - DB_NAME, DB_USER, DB_HOST, $result_file ) ); + self::run( 'mysql --no-defaults', array( + 'database' => DB_NAME + ), $descriptors ); WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } @@ -169,15 +159,17 @@ private function get_file_name( $args ) { } private static function run_query( $query ) { - Utils\run_mysql_query( $query, array( + self::run( 'mysql --no-defaults', array( 'execute' => $query ) ); + } + + private static function run( $cmd, $assoc_args = array(), $descriptors = null ) { + $final_args = array_merge( $assoc_args, array( 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASSWORD, ) ); - } - private static function run( $cmd, $args ) { - Utils\run_mysql_command( $cmd, $args, DB_PASSWORD ); + Utils\run_mysql_command( $cmd, $final_args, $descriptors ); } } diff --git a/php/utils.php b/php/utils.php index b3e02b341..5606b02a4 100644 --- a/php/utils.php +++ b/php/utils.php @@ -370,38 +370,50 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { return $output; } -function run_mysql_query( $query, $args ) { - // TODO: use PDO? - - $host_parts = explode( ':', $args['host'] ); - if ( count( $host_parts ) == 2 ) { - list( $host, $extra ) = $host_parts; - } else { - $host = $args['host']; - } - - $arg_str = esc_cmd( '--host=%s --user=%s --execute=%s', - $host, $args['user'], $query ); - - if ( isset( $extra ) ) { - if ( is_numeric($extra) ) { - $arg_str .= esc_cmd( ' --port=%s --protocol=%s', intval( $extra ), 'tcp' ); - } else if ( trim($extra) !== '' ) { - $arg_str .= esc_cmd( ' --socket=%s', trim( $extra ) ); - } - } - - run_mysql_command( 'mysql', $arg_str, $args['pass'] ); +/** + * @param string MySQL host string, as defined in wp-config.php + * @return array + */ +function mysql_host_to_cli_args( $raw_host ) { + $assoc_args = array(); + + $host_parts = explode( ':', $raw_host ); + if ( count( $host_parts ) == 2 ) { + list( $assoc_args['host'], $extra ) = $host_parts; + if ( is_numeric($extra) ) { + $assoc_args['port'] = intval( $extra ); + $assoc_args['protocol'] = 'tcp'; + } else if ( trim($extra) !== '' ) { + $assoc_args['socket'] = trim( $extra ); + } + } else { + $assoc_args['host'] = $raw_host; + } + + return $assoc_args; } -function run_mysql_command( $cmd, $arg_str, $pass ) { - $final_cmd = "$cmd --no-defaults $arg_str"; +function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { + if ( !$descriptors ) + $descriptors = array( STDIN, STDOUT, STDERR ); + + if ( isset( $assoc_args['host'] ) ) { + $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); + } + + $env = array(); + if ( isset( $assoc_args['pass'] ) ) { + $env['MYSQL_PWD'] = $assoc_args['pass']; + unset( $assoc_args['pass'] ); + } + + $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); - $descriptors = array( STDIN, STDOUT, STDERR ); + $proc = proc_open( $final_cmd, $descriptors, $pipes, null, $env ); + if ( !$proc ) + exit(1); - $r = proc_close( proc_open( $final_cmd, $descriptors, $pipes, null, array( - 'MYSQL_PWD' => $pass - ) ) ); + $r = proc_close( $proc ); if ( $r ) exit( $r ); } From bc27bb4a025f2f966485ababaf7ff82ea79e75ed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 16 Aug 2013 23:45:18 +0300 Subject: [PATCH 2208/5359] minor cleanup in mysql_host_to_cli_args() --- php/utils.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 5606b02a4..125bd969c 100644 --- a/php/utils.php +++ b/php/utils.php @@ -380,11 +380,12 @@ function mysql_host_to_cli_args( $raw_host ) { $host_parts = explode( ':', $raw_host ); if ( count( $host_parts ) == 2 ) { list( $assoc_args['host'], $extra ) = $host_parts; - if ( is_numeric($extra) ) { + $extra = trim( $extra ); + if ( is_numeric( $extra ) ) { $assoc_args['port'] = intval( $extra ); $assoc_args['protocol'] = 'tcp'; - } else if ( trim($extra) !== '' ) { - $assoc_args['socket'] = trim( $extra ); + } else if ( $extra !== '' ) { + $assoc_args['socket'] = $extra; } } else { $assoc_args['host'] = $raw_host; From 5e9414f982fbf369ee0daa8b3a98ee789099313e Mon Sep 17 00:00:00 2001 From: Nikolay Kolev <nikolay@users.noreply.github.com> Date: Mon, 19 Aug 2013 13:11:16 -0700 Subject: [PATCH 2209/5359] Allows passing existing keys and salts vs generating afresh In a multi-server environment, if you want a consistent configuration without having to patch the automatically generated wp-config.php, there should be a way to pass the common keys and salts. --- php/commands/core.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 5dc62c925..d26f0e02c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -153,6 +153,9 @@ private static function get_initial_locale() { * * --extra-php * : If set, the command reads additional PHP code from STDIN. + * + * --keys-and-salts + * : Use existing secrets versus generating afresh as the default behavior. * * ## EXAMPLES * @@ -196,9 +199,10 @@ public function config( $_, $assoc_args ) { } // TODO: adapt more resilient code from wp-admin/setup-config.php - - $assoc_args['keys-and-salts'] = self::_read( - 'https://api.wordpress.org/secret-key/1.1/salt/' ); + if ( ! isset( $assoc_args['keys-and-salts'] ) ) { + $assoc_args['keys-and-salts'] = self::_read( + 'https://api.wordpress.org/secret-key/1.1/salt/' ); + } $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); file_put_contents( ABSPATH . 'wp-config.php', $out ); From 7a9db01d6941953a11e6e6c07e5c7459523da63f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 18 Aug 2013 07:49:33 -0700 Subject: [PATCH 2210/5359] Support for global `wp-cli.yml` and `wp-cli.local.yml` configs --- php/WP_CLI/Runner.php | 10 ++++++++++ php/utils.php | 14 ++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8e5931645..4c09fe818 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -62,6 +62,16 @@ private static function get_config_path( $runtime_config ) { return $path; } + // See if there is a global config file specified in the Composer + // install directory + foreach( $config_files as $config_file ) { + foreach( WP_CLI\Utils\get_vendor_paths() as $vendor_path ) { + $config_path = dirname( $vendor_path ) . '/' . $config_file; + if ( file_exists( $config_path ) ) + return $config_path; + } + } + return false; } diff --git a/php/utils.php b/php/utils.php index 125bd969c..926429a40 100644 --- a/php/utils.php +++ b/php/utils.php @@ -13,14 +13,9 @@ function load_dependencies() { return; } - $vendor_paths = array( - WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) - WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone - ); - $has_autoload = false; - foreach ( $vendor_paths as $vendor_path ) { + foreach ( get_vendor_paths() as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; $has_autoload = true; @@ -34,6 +29,13 @@ function load_dependencies() { } } +function get_vendor_paths() { + return array( + WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) + WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone + ); +} + function load_command( $name ) { $path = WP_CLI_ROOT . "/php/commands/$name.php"; From a85a0c50a2d73d486dd49594fd880c3fd7c204e8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 15:33:44 -0700 Subject: [PATCH 2211/5359] A helper method to prompt the user for some detail --- php/class-wp-cli.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index da3a32be6..6d907f3f7 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -164,6 +164,25 @@ static function confirm( $question, $assoc_args = array() ) { } } + /** + * Prompt a user for some input + */ + static function prompt( $question, $required = false ) { + + do { + + self::out( $question . ': ' ); + + $response = trim( fgets( STDIN ) ); + if ( $required && $response ) + $required = false; + + } while( $required ); + + return $response; + } + + /** * Read a value, from various formats * From 13a61d7edbc52ac824ab9ddb983405afe4bf92da Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 15:34:19 -0700 Subject: [PATCH 2212/5359] If the `--prompt` arg is specified, prompt the user for arguments --- php/WP_CLI/Dispatcher/Subcommand.php | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 45be83bd0..6834bb313 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -36,6 +36,31 @@ function show_usage( $prefix = 'usage: ' ) { ) ); } + private function prompt_args( $args, $assoc_args ) { + + $synopsis = $this->get_synopsis(); + + if ( ! $synopsis ) + return array( $args, $assoc_args ); + + $spec = array_filter( \WP_CLI\SynopsisParser::parse( $synopsis ), function( $spec_arg ) { + return in_array( $spec_arg['type'], array( 'positional', 'assoc' ) ); + }); + + $spec = array_values( $spec ); + + foreach( $spec as $key => $spec_arg ) { + + $required = ! $spec_arg['optional']; + $prompt = ( $key + 1 ) . '/' . count( $spec ) . ' ' . $spec_arg['token']; + $response = \WP_CLI::prompt( $prompt, $required ); + if ( $response ) + $assoc_args[$spec_arg['name']] = $response; + } + + return array( $args, $assoc_args ); + } + private function validate_args( $args, &$assoc_args ) { $synopsis = $this->get_synopsis(); @@ -76,6 +101,10 @@ private function validate_args( $args, &$assoc_args ) { } function invoke( $args, $assoc_args ) { + + if ( ! empty( $assoc_args['prompt'] ) ) + list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); + $this->validate_args( $args, $assoc_args ); \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); From 4579bbcdb53c53f0c6e31956e555e73a1959cf47 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 20 Aug 2013 01:41:51 +0300 Subject: [PATCH 2213/5359] add test for assoc arg with optional value --- tests/test-arg-validation.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php index f579823c5..e1c74b822 100644 --- a/tests/test-arg-validation.php +++ b/tests/test-arg-validation.php @@ -46,5 +46,15 @@ function testMissingAssoc() { $this->assertCount( 1, $errors['fatal'] ); $this->assertCount( 1, $errors['warning'] ); } + + function testAssocWithOptionalValue() { + $parser = new SynopsisValidator( '[--network[=<id>]]' ); + + $assoc_args = array( 'network' => true ); + $errors = $parser->validate_assoc( $assoc_args ); + + $this->assertCount( 0, $errors['fatal'] ); + $this->assertCount( 0, $errors['warning'] ); + } } From 7bd41b7880f70c9deca692d6ea446e74a8e4b8f9 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 1 Aug 2013 23:12:55 +0200 Subject: [PATCH 2214/5359] Exclude assoc args with that have an optional value from being unset An assoc args with an option value shouldn't trigger the message "--foo parameter needs a value". Because it doesn't needs a value. Else it would defeat the whole purpose of having `--foo[=<bar>]`. It needs to be available within the command so you can still do something with it. --- php/WP_CLI/SynopsisValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 90a7cb877..bee3f1920 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -50,7 +50,7 @@ public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { $errors['fatal'][] = "missing --$key parameter"; } } else { - if ( true === $assoc_args[ $key ] ) { + if ( true === $assoc_args[ $key ] && !$param['value']['optional'] ) { $error_type = ( !$param['optional'] ) ? 'fatal' : 'warning'; $errors[ $error_type ][] = "--$key parameter needs a value"; From 49f5105b53a99c21a155ce420f6304abee27fd66 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 15:52:45 -0700 Subject: [PATCH 2215/5359] Register `--prompt` as a global argument Doing so is more correct, and avoids this warning: ``` Warning: unknown --prompt parameter ``` --- php/WP_CLI/Dispatcher/Subcommand.php | 12 +++++++++++- php/WP_CLI/Runner.php | 9 +++++++++ php/config-spec.php | 7 +++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6834bb313..6b6ceb24c 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -11,6 +11,8 @@ class Subcommand extends CompositeCommand { private $when_invoked; + private $prompt = false; + function __construct( $parent, $name, $docparser, $when_invoked ) { $this->when_invoked = $when_invoked; @@ -28,6 +30,14 @@ function get_alias() { return $this->alias; } + function set_prompt( $value ) { + $this->prompt = (bool)$value; + } + + function get_prompt() { + return $this->prompt; + } + function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( sprintf( "%s%s %s", $prefix, @@ -102,7 +112,7 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { - if ( ! empty( $assoc_args['prompt'] ) ) + if ( $this->get_prompt() ) list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); $this->validate_args( $args, $assoc_args ); diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8e5931645..d17618182 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -436,6 +436,15 @@ public function before_wp_load() { self::set_url_params( $url_parts ); } + // Handle --prompt parameter + if ( $this->config['prompt'] ) { + $r = $this->find_command_to_run( $this->arguments ); + if ( is_array( $r ) ) { + list( $command ) = $r; + $command->set_prompt( true ); + } + } + $this->do_early_invoke( 'before_wp_load' ); $this->check_wp_version(); diff --git a/php/config-spec.php b/php/config-spec.php index a2f174769..8504d7890 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -57,6 +57,13 @@ 'desc' => 'Show all PHP errors', ), + 'prompt' => array( + 'runtime' => '', + 'file' => false, + 'default' => false, + 'desc' => 'Prompt the user to enter values for all command arguments', + ), + 'quiet' => array( 'runtime' => '', 'file' => '<bool>', From a14b7b575aba23f7a7acb101d5ca9fa9589ec7dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 16:46:11 -0700 Subject: [PATCH 2216/5359] Properly set positional arguments --- php/WP_CLI/Dispatcher/Subcommand.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6b6ceb24c..c784d5eb3 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -59,13 +59,24 @@ private function prompt_args( $args, $assoc_args ) { $spec = array_values( $spec ); + // 'positional' arguments are positional (aka zero-indexed) + // so $args needs to be reset before prompting for new arguments + $args = array(); foreach( $spec as $key => $spec_arg ) { $required = ! $spec_arg['optional']; $prompt = ( $key + 1 ) . '/' . count( $spec ) . ' ' . $spec_arg['token']; $response = \WP_CLI::prompt( $prompt, $required ); - if ( $response ) - $assoc_args[$spec_arg['name']] = $response; + if ( $response ) { + switch ( $spec_arg['type'] ) { + case 'positional': + $args[] = $response; + break; + case 'assoc': + $assoc_args[$spec_arg['name']] = $response; + break; + } + } } return array( $args, $assoc_args ); From ca3efb7a29939a3f2313366a8a90b099cd5d2487 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 16:58:55 -0700 Subject: [PATCH 2217/5359] Fix synopsis order Make it consistent with other core commands. --- php/commands/post.php | 4 ++-- php/commands/user.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 22e09078f..c0c37a25e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -141,7 +141,7 @@ protected function _edit( $content, $title ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the post to get. * * --format=<format> @@ -160,7 +160,7 @@ protected function _edit( $content, $title ) { * * wp post get 12 > file.txt * - * @synopsis [--format=<format>] <ID> + * @synopsis <id> [--format=<format>] */ public function get( $args, $assoc_args ) { $defaults = array( diff --git a/php/commands/user.php b/php/commands/user.php index 3e8bcd415..cf3d95624 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -99,7 +99,7 @@ public function _list( $args, $assoc_args ) { * * wp user get bob --format=json > bob.json * - * @synopsis [--format=<format>] <user> + * @synopsis <user> [--format=<format>] */ public function get( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( From a3bffb472147b889434441ac8f7f36aff644dc34 Mon Sep 17 00:00:00 2001 From: Nikolay Kolev <nikolay@users.noreply.github.com> Date: Mon, 19 Aug 2013 18:37:42 -0700 Subject: [PATCH 2218/5359] Switched from --keys-and-salts="..." option to --skip-salts based on @scribu and @danielbachhuber proposal --- php/commands/core.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d26f0e02c..988231cb4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -154,8 +154,8 @@ private static function get_initial_locale() { * --extra-php * : If set, the command reads additional PHP code from STDIN. * - * --keys-and-salts - * : Use existing secrets versus generating afresh as the default behavior. + * --skip-salts + * : If set, keys and salts won't be generated, but, instead, should be passed via --extra-php. * * ## EXAMPLES * @@ -168,7 +168,7 @@ private static function get_initial_locale() { * define( 'WP_DEBUG_LOG', true ); * PHP * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] [--skip-satls] */ public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { @@ -199,7 +199,7 @@ public function config( $_, $assoc_args ) { } // TODO: adapt more resilient code from wp-admin/setup-config.php - if ( ! isset( $assoc_args['keys-and-salts'] ) ) { + if ( ! isset( $assoc_args['skip-salts'] ) ) { $assoc_args['keys-and-salts'] = self::_read( 'https://api.wordpress.org/secret-key/1.1/salt/' ); } From 93f2e481fc96f41d89e5aa44eadf7d77c27ae39a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 22:12:24 -0700 Subject: [PATCH 2219/5359] This should explicitly be a public method. --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 9adcce6ed..b2cbc2797 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -156,7 +156,7 @@ private function is_active_theme( $theme ) { * * @synopsis [<theme>] [--dir] */ - function path( $args, $assoc_args ) { + public function path( $args, $assoc_args ) { if ( empty( $args ) ) { $path = WP_CONTENT_DIR . '/themes'; } else { From 0fa67448ba69b92dc0a70c7a5b76e638a2b5a918 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 22:24:03 -0700 Subject: [PATCH 2220/5359] A functional test for `wp theme path` --- features/theme.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index a42199f48..4231fc5df 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -68,3 +68,15 @@ Feature: Manage WordPress themes Then STDOUT should be a table containing rows: | name | status | update | version | | p2 | active | available | 1.4.1 | + + Scenario: Get the path of an installed theme + Given a WP install + + When I run `wp theme install twentyeleven` + Then STDOUT should not be empty + + When I run `wp theme path twentyeleven --dir` + Then STDOUT should contain: + """ + wp-content/themes/twentyeleven + """ From f3c5d482d381360c88019ef2fdfb7a57f79ee921 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 22:26:06 -0700 Subject: [PATCH 2221/5359] Clarification on what this command actually does --- php/commands/theme.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index b2cbc2797..4a3c0981e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -143,12 +143,12 @@ private function is_active_theme( $theme ) { * ## OPTIONS * * <theme> - * : The theme to get the path to. If not set, will return the path to the - * themes directory. + * : The theme to get the path to. Path includes "style.css" file. + * If not set, will return the path to the themes directory. * * --dir * : If set, get the path to the closest parent directory, instead of the - * theme file. + * theme's "style.css" file. * * ## EXAMPLES * From 460af3f1035958f410f2744813efcc94bb0eb299 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 22:57:01 -0700 Subject: [PATCH 2222/5359] Implement `wp theme get` --- features/theme.feature | 11 +++++++++ php/commands/theme.php | 56 ++++++++++++++++++++++++++++++++++++++++++ php/utils.php | 22 +++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index a42199f48..9aa1d8b5b 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -68,3 +68,14 @@ Feature: Manage WordPress themes Then STDOUT should be a table containing rows: | name | status | update | version | | p2 | active | available | 1.4.1 | + + Scenario: Get details about an installed theme + Given a WP install + + When I run `wp theme install twentyeleven` + Then STDOUT should not be empty + + When I run `wp theme get twentyeleven` + Then STDOUT should be a table containing rows: + | Field | Value | + | name | Twenty Eleven | diff --git a/php/commands/theme.php b/php/commands/theme.php index 9adcce6ed..87ce9cccc 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -249,6 +249,62 @@ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); } + /** + * Get a theme + * + * ## OPTIONS + * + * <theme> + * : The theme to get. + * + * * --format=<format> + * : The format to use when printing the theme, acceptable values: + * + * - **table**: Outputs all fields of the theme as a table. + * + * - **json**: Outputs all fields in JSON format. + * + * ## EXAMPLES + * + * wp theme get twentytwelve + * + * @synopsis <theme> [--format=<format>] + */ + public function get( $args, $assoc_args ) { + + $defaults = array( + 'format' => 'table' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $theme = $this->parse_name( $args[0] ); + + // WP_Theme object employs magic getter, unfortunately + $theme_vars = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', + ); + $theme_obj = new stdClass; + foreach( $theme_vars as $var ) { + $theme_obj->$var = $theme->$var; + } + + switch ( $assoc_args['format'] ) { + + case 'table': + unset( $theme_obj->tags ); + $fields = get_object_vars( $theme_obj ); + \WP_CLI\Utils\assoc_array_to_table( $fields ); + break; + + case 'json': + WP_CLI::print_value( $theme_obj, $assoc_args ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); + break; + } + } + /** * Update a theme. * diff --git a/php/utils.php b/php/utils.php index 125bd969c..1b3b1a6ce 100644 --- a/php/utils.php +++ b/php/utils.php @@ -302,6 +302,28 @@ function format_items( $format, $items, $fields ) { } } +/** + * Format an associative array as a table + * + * @param array $fields Fields and values to format + */ +function assoc_array_to_table( $fields ) { + $rows = array(); + + foreach ( $fields as $field => $value ) { + if ( !is_string($value) ) { + $value = json_encode( $value ); + } + + $rows[] = (object) array( + 'Field' => $field, + 'Value' => $value + ); + } + + format_items( 'table', $rows, array( 'Field', 'Value' ) ); +} + /** * Write data as CSV to a given file. * From 4ac027e3e23be2ed653fb6b79efd520dbb9a6acf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 23:08:13 -0700 Subject: [PATCH 2223/5359] Use P2 for tests instead, which won't fatal 3.4 (twentyeleven is already installed) --- features/theme.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 9aa1d8b5b..f09a44d92 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -72,10 +72,10 @@ Feature: Manage WordPress themes Scenario: Get details about an installed theme Given a WP install - When I run `wp theme install twentyeleven` + When I run `wp theme install p2` Then STDOUT should not be empty - When I run `wp theme get twentyeleven` + When I run `wp theme get p2` Then STDOUT should be a table containing rows: | Field | Value | - | name | Twenty Eleven | + | name | P2 | From f669861408e412449e55b9e1efa7d5e0f0bd9c86 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Aug 2013 07:13:30 -0700 Subject: [PATCH 2224/5359] Use P2, which isn't conditionally present in some WordPress installs --- features/theme.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index e01b40d19..c05ecd0f2 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -72,13 +72,13 @@ Feature: Manage WordPress themes Scenario: Get the path of an installed theme Given a WP install - When I run `wp theme install twentyeleven` + When I run `wp theme install p2` Then STDOUT should not be empty - When I run `wp theme path twentyeleven --dir` + When I run `wp theme path p2 --dir` Then STDOUT should contain: """ - wp-content/themes/twentyeleven + wp-content/themes/p2 """ Scenario: Get details about an installed theme From 5eb3c0824bd8b0d7b2226a6f46c4ab42ce7e4ef6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 23:02:36 -0700 Subject: [PATCH 2225/5359] Implement `wp comment get` --- php/commands/comment.php | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index a5b696ae9..dd7473013 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -43,6 +43,56 @@ public function create( $args, $assoc_args ) { WP_CLI::success( "Inserted comment $comment_id." ); } + /** + * Get a comment + * + * ## OPTIONS + * + * <id> + * : The comment to get. + * + * * --format=<format> + * : The format to use when printing the comment, acceptable values: + * + * - **table**: Outputs all fields of the comment as a table. + * + * - **json**: Outputs all fields in JSON format. + * + * ## EXAMPLES + * + * wp comment get 1 + * + * @synopsis <id> [--format=<format>] + */ + public function get( $args, $assoc_args ) { + + $defaults = array( + 'format' => 'table' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $comment_id = (int)$args[0]; + $comment = get_comment( $comment_id ); + if ( empty( $comment ) ) + WP_CLI::error( "Invalid comment ID." ); + + switch ( $assoc_args['format'] ) { + + case 'table': + $fields = get_object_vars( $comment ); + \WP_CLI\Utils\assoc_array_to_table( $fields ); + break; + + case 'json': + WP_CLI::print_value( $comment, $assoc_args ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); + break; + } + } + /** * Delete a comment. * From 021cf58519f2f20fbe7c45480d5e28f0dd7ba65a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Aug 2013 23:04:48 -0700 Subject: [PATCH 2226/5359] Test for `wp comment get` --- features/comment.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 8a9d2502d..69dee8dbb 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -18,3 +18,11 @@ Feature: Manage WordPress comments """ Success: Deleted comment {COMMENT_ID}. """ + + Scenario: Get details about an existing comment + Given a WP install + + When I run `wp comment get 1` + Then STDOUT should be a table containing rows: + | Field | Value | + | comment_author | Mr WordPress | From 52f76428cc1822a8c9e84aa9cf59cfffa73b8008 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Aug 2013 07:37:59 -0700 Subject: [PATCH 2227/5359] Use our new util function --- php/commands/post.php | 2 +- php/commands/user.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index c0c37a25e..c14887e17 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -181,7 +181,7 @@ public function get( $args, $assoc_args ) { case 'table': $fields = get_object_vars( $post ); unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); - $this->assoc_array_to_table( $fields ); + \WP_CLI\Utils\assoc_array_to_table( $fields ); break; case 'json': diff --git a/php/commands/user.php b/php/commands/user.php index cf3d95624..2e6454a11 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -119,7 +119,7 @@ public function get( $args, $assoc_args ) { switch ( $assoc_args['format'] ) { case 'table': - $this->assoc_array_to_table( $user_data ); + \WP_CLI\Utils\assoc_array_to_table( $user_data ); break; case 'json': From 013f6547d836ddb7b2f75eb2b49b607829a2e87b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Aug 2013 07:38:31 -0700 Subject: [PATCH 2228/5359] This method has been replaced by a helper util of the same functionality --- php/WP_CLI/CommandWithDBObject.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 083b06875..7978ce37b 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -68,23 +68,6 @@ protected function success_or_failure( $r ) { return $status; } - protected function assoc_array_to_table( $fields ) { - $rows = array(); - - foreach ( $fields as $field => $value ) { - if ( !is_string($value) ) { - $value = json_encode( $value ); - } - - $rows[] = (object) array( - 'Field' => $field, - 'Value' => $value - ); - } - - \WP_CLI\Utils\format_items( 'table', $rows, array( 'Field', 'Value' ) ); - } - public function delete( $args, $assoc_args ) { $status = 0; From aefd67f9004aff08a309fc6e42a8d3d33b60aa8d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Aug 2013 08:07:37 -0700 Subject: [PATCH 2229/5359] A subcommand for getting a taxonomy term --- php/commands/term.php | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index 2b400c84e..43539574c 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -120,6 +120,60 @@ public function create( $args, $assoc_args ) { } } + /** + * Get a taxonomy term + * + * ## OPTIONS + * + * <term-id> + * : ID of the term to get + * + * <taxonomy> + * : Taxonomy of the term to get + * + * --format=<format> + * : The format to use when printing the term, acceptable values: + * + * - **table**: Outputs all fields of the term as a table. + * + * - **json**: Outputs all fields in JSON format. + * + * ## EXAMPLES + * + * wp term get 1 category + * + * @synopsis <term-id> <taxonomy> [--format=<format>] + */ + public function get( $args, $assoc_args ) { + + list( $term_id, $taxonomy ) = $args; + + $defaults = array( + 'format' => 'table' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $term = get_term_by( 'id', $term_id, $taxonomy ); + if ( ! $term ) + WP_CLI::error( "Term doesn't exist." ); + + switch ( $assoc_args['format'] ) { + + case 'table': + $fields = get_object_vars( $term ); + \WP_CLI\Utils\assoc_array_to_table( $fields ); + break; + + case 'json': + WP_CLI::print_value( $term, $assoc_args ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); + break; + } + } + /** * Update a term. * From 7fa54a4ccb81942026393cff9b14f33cba017096 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Aug 2013 08:07:52 -0700 Subject: [PATCH 2230/5359] Test `wp term get` --- features/term.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/term.feature b/features/term.feature index 97b5ad580..076f65621 100644 --- a/features/term.feature +++ b/features/term.feature @@ -5,6 +5,7 @@ Feature: Manage WordPress terms When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` Then STDOUT should be a number + And save STDOUT as {TERM_ID} When I try the previous command again Then STDERR should not be empty @@ -20,6 +21,12 @@ Feature: Manage WordPress terms | name | slug | | Test term | test | + When I run `wp term get {TERM_ID} post_tag` + Then STDOUT should be a table containing rows: + | Field | Value | + | term_id | {TERM_ID} | + | name | Test term | + Scenario: Creating/deleting a term Given a WP install From ec41181d5fc5289bf8d06f1361a3e5548fbbd928 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 20 Aug 2013 18:57:26 +0100 Subject: [PATCH 2231/5359] Correct the inline docs for the `--hard` flag on `wp rewrite flush` --- php/commands/rewrite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 1e04593fd..1d3e16f7c 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -13,7 +13,7 @@ class Rewrite_Command extends WP_CLI_Command { * ## OPTIONS * * --hard - * : Perform a hard flush - do not overwrite `.htaccess`. The default is to update `.htaccess` rules as well as rewrite rules in database. + * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. * * @synopsis [--hard] */ From 08aab7a2b41c517fcf6b8b3b53c3950b8d0e50a3 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 20 Aug 2013 19:22:13 +0100 Subject: [PATCH 2232/5359] Fix the `--format` flag for the `wp rewrite dump` command --- php/commands/rewrite.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 1e04593fd..995533d58 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -105,12 +105,22 @@ public function dump( $args, $assoc_args ) { $rules = array(); WP_CLI::warning( 'No rewrite rules.' ); } + $defaults = array( + 'format' => '' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + switch ( $assoc_args['format'] ) { + + case 'json': + echo json_encode( $rules ); + break; + + default: + foreach ( $rules as $route => $rule ) + WP_CLI::line( $route . "\t" . $rule ); + break; - if ( isset( $assoc_args['json'] ) ) { - echo json_encode( $rules ); - } else { - foreach ( $rules as $route => $rule ) - WP_CLI::line( $route . "\t" . $rule ); } } From 602c17f23ae3d708320c7ff4057baa7b00315917 Mon Sep 17 00:00:00 2001 From: Nikolay Kolev <nikolay@users.noreply.github.com> Date: Wed, 21 Aug 2013 01:45:23 -0700 Subject: [PATCH 2233/5359] Don't include the comments, which would be irrelevant without the salts. Based on @scribu's idea. --- templates/wp-config.mustache | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 78cca7488..20b4b6b33 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -28,6 +28,7 @@ define('DB_CHARSET', 'utf8'); /** The Database Collate type. Don't change this if in doubt. */ define('DB_COLLATE', ''); +{{#keys-and-salts}} /**#@+ * Authentication Unique Keys and Salts. * @@ -37,6 +38,7 @@ define('DB_COLLATE', ''); */ {{{keys-and-salts}}} /**#@-*/ +{{/keys-and-salts}} /** * WordPress Database Table prefix. From 2ccb9af30e1329b38cda054a483a64fda60f7207 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 21 Aug 2013 23:06:36 +0300 Subject: [PATCH 2234/5359] add test that reproduces both #435 and #716 --- features/validation.feature | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 features/validation.feature diff --git a/features/validation.feature b/features/validation.feature new file mode 100644 index 000000000..683fe735f --- /dev/null +++ b/features/validation.feature @@ -0,0 +1,15 @@ +Feature: Argument validation + In order to catch errors fast + As a user + I need to see warnings and errors when I pass incorrect arguments + + Scenario: Validation for early commands + Given an empty directory + And WP files + + When I try `wp core config invalid` + Then the return code should be 1 + And STDERR should contain: + """ + Parameter errors: + """ From 31bf236c5acddf518ffe4ea003eddc5460e28369 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 21 Aug 2013 23:58:23 +0300 Subject: [PATCH 2235/5359] behat: show working dir when the return code is wrong --- features/bootstrap/Process.php | 21 +++++++++++++++++---- features/steps/basic_steps.php | 4 +++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 072b6b185..16b248df4 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -41,24 +41,37 @@ public function run( $subdir = '' ) { $STDERR = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); - return (object) array( + return new ProcessRun( array( 'STDOUT' => $STDOUT, 'STDERR' => $STDERR, 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd - ); + ) ); } public function run_check( $subdir = '' ) { $r = $this->run( $subdir ); if ( $r->return_code || !empty( $r->STDERR ) ) { - throw new \RuntimeException( sprintf( "%s: %s\ncwd: %s", - $r->command, $r->STDERR, $r->cwd ) ); + throw new \RuntimeException( $r ); } return $r; } } + +class ProcessRun { + + public function __construct( $props ) { + foreach ( $props as $key => $value ) { + $this->$key = $value; + } + } + + public function __toString() { + return sprintf( "%s: %s\ncwd: %s", $this->command, $this->STDERR, $this->cwd ); + } +} + diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 0e1ab4881..fe171c14a 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -148,7 +148,9 @@ function ( $world, $stream, $output_filter, $key ) { $steps->Then( '/^the return code should be (\d+)$/', function ( $world, $return_code ) { - assertEquals( $return_code, $world->result->return_code ); + if ( $return_code != $world->result->return_code ) { + throw new RuntimeException( $world->result ); + } } ); From d33530da14fa0144e6df3998e030c07346950285 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 00:05:14 +0300 Subject: [PATCH 2236/5359] core config: use cmd_starts_with() instead of doing a strict array comparison --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8e5931645..bb4d5c6f8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -440,7 +440,7 @@ public function before_wp_load() { $this->check_wp_version(); - if ( array( 'core', 'config' ) == $this->arguments ) { + if ( $this->cmd_starts_with( array( 'core', 'config' ) ) ) { $this->_run_command(); exit; } From e5c3195b658e4c78d4f06400d85954b6ddfed808 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 00:27:07 +0300 Subject: [PATCH 2237/5359] behat: replace hidden parameters to 'wp config' with explicit variable --- features/bootstrap/FeatureContext.php | 28 +++++++++------------------ features/core.feature | 2 +- features/steps/basic_steps.php | 4 ++-- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index fc3a15c51..cca8e3924 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -22,8 +22,6 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { 'dbpass' => 'password1' ); - private static $additional_args; - public $variables = array(); // We cache the results of `wp core download` to improve test performance @@ -43,14 +41,6 @@ private static function cache_wp_files() { */ public static function prepare( SuiteEvent $event ) { self::cache_wp_files(); - - self::$additional_args = array( - 'wp core config' => self::$db_settings, - - 'wp core install-network' => array( - 'title' => 'WP CLI Network' - ) - ); } /** @@ -75,6 +65,7 @@ public function afterScenario( $event ) { public function __construct( array $parameters ) { $this->drop_db(); $this->set_cache_dir(); + $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); } public function getStepDefinitionResources() { @@ -132,13 +123,6 @@ public function drop_db() { } public function proc( $command, $assoc_args = array() ) { - foreach ( self::$additional_args as $start => $additional_args ) { - if ( 0 === strpos( $command, $start ) ) { - $assoc_args = array_merge( $additional_args, $assoc_args ); - break; - } - } - if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); @@ -167,13 +151,19 @@ public function download_wp( $subdir = '' ) { copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); } + public function create_config() { + $this->proc( 'wp core config', self::$db_settings )->run_check(); + } + public function install_wp( $subdir = '' ) { $this->create_db(); $this->create_run_dir(); $this->download_wp( $subdir ); - $dbprefix = $subdir ?: 'wp_'; - $this->proc( 'wp core config', compact( 'dbprefix' ) )->run_check( $subdir ); + $db_args = self::$db_settings; + $db_args['dbprefix'] = $subdir ?: 'wp_'; + + $this->proc( 'wp core config', $db_args )->run_check( $subdir ); $install_args = array( 'url' => 'http://example.com', diff --git a/features/core.feature b/features/core.feature index a06a966c9..8238c0429 100644 --- a/features/core.feature +++ b/features/core.feature @@ -40,7 +40,7 @@ Feature: Manage WordPress installation """ define( 'WP_DEBUG_LOG', true ); """ - When I run `wp core config --extra-php < wp-config-extra.php` + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` Then the wp-config.php file should contain: """ define('AUTH_SALT', diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index fe171c14a..5c699bf7e 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -36,7 +36,7 @@ function ( $world ) { $steps->Given( '/^wp-config\.php$/', function ( $world ) { - $world->proc( 'wp core config' )->run_check(); + $world->create_config(); } ); @@ -61,7 +61,7 @@ function ( $world, $subdir ) { $steps->Given( '/^a WP multisite install$/', function ( $world ) { $world->install_wp(); - $world->proc( 'wp core install-network' )->run_check(); + $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network' ) )->run_check(); } ); From 141ed34673b53f61657168a7614fa8b6b89d4a6c Mon Sep 17 00:00:00 2001 From: Nikolay Kolev <nikolaynkolev@gmail.com> Date: Wed, 21 Aug 2013 14:27:42 -0700 Subject: [PATCH 2238/5359] Added tests for the --skip-salts parameter --- features/core.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/core.feature b/features/core.feature index a06a966c9..4a7b5b000 100644 --- a/features/core.feature +++ b/features/core.feature @@ -54,6 +54,20 @@ Feature: Manage WordPress installation Then the return code should be 1 And STDERR should not be empty + Scenario: Configure with existing salts + Given an empty directory + And WP files + + Given a wp-config-extra.php file: + """ + define( 'WP_DEBUG_LOG', true ); + """ + When I run `wp core config --extra-php --skip-salts < wp-config-extra.php` + Then the wp-config.php file should not contain: + """ + define('AUTH_SALT', + """ + Scenario: Database doesn't exist Given an empty directory And WP files From 4785e7a1d3b7370fe7b6b7f4eede3e40d6fc2609 Mon Sep 17 00:00:00 2001 From: Nikolay Kolev <nikolaynkolev@gmail.com> Date: Wed, 21 Aug 2013 14:59:07 -0700 Subject: [PATCH 2239/5359] Fixed a typoe in --skip-salts synopsis --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 988231cb4..0bfc0d04f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -168,7 +168,7 @@ private static function get_initial_locale() { * define( 'WP_DEBUG_LOG', true ); * PHP * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] [--skip-satls] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] [--skip-salts] */ public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { From 5ff289bc4d166d6973b8430268444b951cd447e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 01:09:24 +0300 Subject: [PATCH 2240/5359] fix and simplify the --skip-salts test. see #696 --- features/core.feature | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index 5bbd71cd7..0d2a8456e 100644 --- a/features/core.feature +++ b/features/core.feature @@ -58,11 +58,7 @@ Feature: Manage WordPress installation Given an empty directory And WP files - Given a wp-config-extra.php file: - """ - define( 'WP_DEBUG_LOG', true ); - """ - When I run `wp core config --extra-php --skip-salts < wp-config-extra.php` + When I run `wp core config {CORE_CONFIG_SETTINGS} --skip-salts --extra-php < /dev/null` Then the wp-config.php file should not contain: """ define('AUTH_SALT', From bf51257311cb506a9cd0e52f8a4073e824a3c158 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 21:05:06 +0300 Subject: [PATCH 2241/5359] allow passing multiple items to 'wp plugin update' and 'wp theme update' also, bring back `wp plugin update --all` and `wp theme update --all` --- php/WP_CLI/CommandWithUpgrade.php | 11 +++++- php/WP_CLI/Runner.php | 8 ++-- php/commands/plugin.php | 62 ++++++++++--------------------- php/commands/theme.php | 54 ++++++++++++--------------- 4 files changed, 55 insertions(+), 80 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 96ce4df28..de2a01297 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -11,6 +11,7 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { abstract protected function get_upgrader_class( $force ); abstract protected function get_item_list(); + abstract protected function filter_item_list( $items, $args ); abstract protected function get_all_items(); abstract protected function get_status( $file ); @@ -174,10 +175,16 @@ protected function get_upgrader( $assoc_args ) { return \WP_CLI\Utils\get_upgrader( $upgrader_class ); } - function update_all( $args, $assoc_args ) { + protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); - $items_to_update = wp_list_filter( $this->get_item_list(), array( + $items = $this->get_item_list(); + + if ( !isset( $assoc_args['all'] ) ) { + $items = $this->filter_item_list( $items, $args ); + } + + $items_to_update = wp_list_filter( $items, array( 'update' => true ) ); diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index bb4d5c6f8..9dab776d7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -274,12 +274,12 @@ private static function back_compat_conversions( $args, $assoc_args ) { unset( $assoc_args['site_id'] ); } - // {plugin|theme} update --all -> {plugin|theme} update-all + // {plugin|theme} update-all -> {plugin|theme} update --all if ( count( $args ) > 1 && in_array( $args[0], array( 'plugin', 'theme' ) ) - && $args[1] == 'update' && isset( $assoc_args['all'] ) + && $args[1] == 'update-all' ) { - $args[1] = 'update-all'; - unset( $assoc_args['all'] ); + $args[1] = 'update'; + $assoc_args['all'] = true; } // plugin scaffold -> scaffold plugin diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 7c7fb4234..6020f29aa 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -282,69 +282,40 @@ protected function install_from_repo( $slug, $assoc_args ) { } /** - * Update a plugin. + * Update one or more plugins. * * ## OPTIONS * * <plugin> - * : The plugin to update. + * : The plugin(s) to update. + * + * --all + * : If set, all plugins that have updates will be updated. * * --version=dev * : If set, the plugin will be updated to the latest development version, * regardless of what version is currently installed. * + * --dry-run + * : Preview which plugins would be updated. + * * ## EXAMPLES * * wp plugin update bbpress --version=dev * - * @synopsis <plugin> [--version=<version>] + * @synopsis <plugin>... [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { - $name = $args[0]; - $basename = $this->parse_name( $name ); - if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { - $this->_delete( $basename, false ); - $this->install( $args, $assoc_args ); - } else { - $was_active = is_plugin_active( $basename ); - $was_network_active = is_plugin_active_for_network( $basename ); - - call_user_func( $this->upgrade_refresh ); - - $this->get_upgrader( $assoc_args )->upgrade( $basename ); - - if ( $was_active ) { - $new_args = array( $args[0] ); - - $new_assoc_args = array(); - if ( $was_network_active ) - $new_assoc_args['network'] = true; - - $this->activate( $new_args, $new_assoc_args ); + foreach ( $args as $arg ) { + $this->_delete( $this->parse_name( $arg ) ); + $this->install( array( $arg ), $assoc_args ); } + } else { + parent::update_many( $args, $assoc_args ); } } - /** - * Update all plugins. - * - * ## OPTIONS - * - * --dry-run - * : Pretend to do the updates, to see what would happen. - * - * ## EXAMPLES - * - * wp plugin update-all - * - * @subcommand update-all - * @synopsis [--dry-run] - */ - function update_all( $args, $assoc_args ) { - parent::update_all( $args, $assoc_args ); - } - protected function get_item_list() { $items = array(); @@ -361,6 +332,11 @@ protected function get_item_list() { return $items; } + protected function filter_item_list( $items, $args ) { + $basenames = array_map( array( $this, 'parse_name' ), $args ); + return \WP_CLI\Utils\pick_fields( $items, $basenames ); + } + /** * Install a plugin. * diff --git a/php/commands/theme.php b/php/commands/theme.php index ee12ce23d..beafcefe7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -217,6 +217,15 @@ protected function get_item_list() { return $items; } + protected function filter_item_list( $items, $args ) { + $theme_files = array(); + foreach ( $args as $arg ) { + $theme_files[] = $this->parse_name( $arg )->get_stylesheet_directory(); + } + + return \WP_CLI\Utils\pick_fields( $items, $theme_files ); + } + /** * Install a theme. * @@ -251,23 +260,23 @@ function install( $args, $assoc_args ) { /** * Get a theme - * + * * ## OPTIONS * * <theme> * : The theme to get. - * + * * * --format=<format> * : The format to use when printing the theme, acceptable values: * * - **table**: Outputs all fields of the theme as a table. * * - **json**: Outputs all fields in JSON format. - * + * * ## EXAMPLES * * wp theme get twentytwelve - * + * * @synopsis <theme> [--format=<format>] */ public function get( $args, $assoc_args ) { @@ -306,48 +315,31 @@ public function get( $args, $assoc_args ) { } /** - * Update a theme. + * Update one or more themes. * * ## OPTIONS * * <theme> - * : The theme to update. + * : The theme(s) to update. + * + * --all + * : If set, all themes that have updates will be updated. * * --version=dev * : If set, the theme will be updated to the latest development version, * regardless of what version is currently installed. * - * ## EXAMPLES - * - * wp theme update twentytwelve - * - * @synopsis <theme> [--version=<version>] - */ - function update( $args, $assoc_args ) { - $theme = $this->parse_name( $args[0] ); - - call_user_func( $this->upgrade_refresh ); - - $this->get_upgrader( $assoc_args )->upgrade( $theme->get_stylesheet() ); - } - - /** - * Update all themes. - * - * ## OPTIONS - * * --dry-run - * : Pretend to do the updates, to see what would happen. + * : Preview which themes would be updated. * * ## EXAMPLES * - * wp theme update-all + * wp theme update twentytwelve * - * @subcommand update-all - * @synopsis [--dry-run] + * @synopsis <theme>... [--version=<version>] [--all] [--dry-run] */ - function update_all( $args, $assoc_args ) { - parent::update_all( $args, $assoc_args ); + function update( $args, $assoc_args ) { + parent::update_many( $args, $assoc_args ); } /** From c5f7e6230a81eaf0636b34f07cf83ee10a19c8af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 21:19:12 +0300 Subject: [PATCH 2242/5359] {plugin|theme} update: improve --dry-run output --- php/WP_CLI/CommandWithUpgrade.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index de2a01297..f45728252 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -189,17 +189,16 @@ protected function update_many( $args, $assoc_args ) { ) ); if ( isset( $assoc_args['dry-run'] ) ) { - $item_list = "Available {$this->item_type} updates:"; - if ( empty( $items_to_update ) ) { - $item_list .= " none"; - } else { - foreach ( $items_to_update as $file => $details ) { - $item_list .= "\n\t%y" . $details['name'] . "%n"; - } + \WP_CLI::line( "No {$this->item_type} updates available." ); + return; } - \WP_CLI::line( \WP_CLI::colorize( $item_list ) ); + \WP_CLI::line( "Available {$this->item_type} updates:" ); + + \WP_CLI\Utils\format_items( 'table', $items_to_update, + array( 'name', 'status', 'version' ) ); + return; } From 25bf077ec1eb41eec8657f8bc70e219262b028a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 21:58:25 +0300 Subject: [PATCH 2243/5359] {plugin|theme} update: add more examples [ci skip] --- php/commands/plugin.php | 2 ++ php/commands/theme.php | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 6020f29aa..8e19109dd 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -303,6 +303,8 @@ protected function install_from_repo( $slug, $assoc_args ) { * * wp plugin update bbpress --version=dev * + * wp plugin update --all + * * @synopsis <plugin>... [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index beafcefe7..e777c427d 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -334,7 +334,9 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp theme update twentytwelve + * wp theme update twentyeleven twentytwelve + * + * wp theme update --all * * @synopsis <theme>... [--version=<version>] [--all] [--dry-run] */ From 83cf1247719a51052d36d3e3ee8477ed111c47e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 22 Aug 2013 23:02:06 +0300 Subject: [PATCH 2244/5359] behat: whitespace fixes --- features/db.feature | 18 ++++++++-------- features/option.feature | 18 ++++++++-------- features/post-meta.feature | 12 +++++------ features/post.feature | 5 ++++- features/shell.feature | 34 +++++++++++++++--------------- features/term.feature | 8 +++++++- features/upgradables.feature | 40 ++++++++++++++++++------------------ features/user-meta.feature | 12 +++++------ features/user.feature | 33 ++++++++++++++++------------- 9 files changed, 97 insertions(+), 83 deletions(-) diff --git a/features/db.feature b/features/db.feature index 61bd9f52d..f8376e824 100644 --- a/features/db.feature +++ b/features/db.feature @@ -22,19 +22,19 @@ Feature: Perform database operations When I run `wp db query 'SELECT COUNT(*) as total FROM wp_posts'` Then STDOUT should contain: - """ - total - """ + """ + total + """ Given a debug.sql file: - """ - SELECT COUNT(*) as total FROM wp_posts - """ + """ + SELECT COUNT(*) as total FROM wp_posts + """ When I run `wp db query < debug.sql` Then STDOUT should contain: - """ - total - """ + """ + total + """ Scenario: DB export/import Given a WP install diff --git a/features/option.feature b/features/option.feature index a009349d3..28ea9a8c4 100644 --- a/features/option.feature +++ b/features/option.feature @@ -9,9 +9,9 @@ Feature: Manage WordPress options When I run `wp option get str_opt` Then STDOUT should be: - """ - bar - """ + """ + bar + """ When I run `wp option delete str_opt` Then STDOUT should not be empty @@ -29,9 +29,9 @@ Feature: Manage WordPress options When I run `wp option get blog_public` Then STDOUT should be: - """ - 0 - """ + """ + 0 + """ # JSON values @@ -43,6 +43,6 @@ Feature: Manage WordPress options When I run `wp option get json_opt --format=json` Then STDOUT should be: - """ - [1,2] - """ + """ + [1,2] + """ diff --git a/features/post-meta.feature b/features/post-meta.feature index 5c3ecd116..b756062a9 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -8,18 +8,18 @@ Feature: Manage post custom fields When I run `wp post-meta get 1 foo` Then STDOUT should be: - """ - bar - """ + """ + bar + """ When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty When I run `wp post-meta get 1 foo --format=json` Then STDOUT should be: - """ - ["1","2"] - """ + """ + ["1","2"] + """ When I run `wp post-meta delete 1 foo` Then STDOUT should not be empty diff --git a/features/post.feature b/features/post.feature index 16c88c6df..8d6816ad8 100644 --- a/features/post.feature +++ b/features/post.feature @@ -67,7 +67,10 @@ Feature: Manage WordPress posts When I run `wp post get --format=json {POST_ID}` Then STDOUT should be JSON containing: """ - {"ID":{POST_ID},"post_title":"Test post"} + { + "ID": {POST_ID}, + "post_title": "Test post" + } """ Scenario: Creating/listing posts diff --git a/features/shell.feature b/features/shell.feature index 1e855ae7f..d415c6c4e 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -11,32 +11,32 @@ Feature: WordPress REPL Scenario: Persistent environment Given a WP install And a session file: - """ - function is_empty_string( $str ) { return strlen( $str ) == 0; } - $a = get_option('home'); - is_empty_string( $a ); - """ + """ + function is_empty_string( $str ) { return strlen( $str ) == 0; } + $a = get_option('home'); + is_empty_string( $a ); + """ When I run `wp shell --basic < session` Then STDOUT should contain: - """ - bool(false) - """ + """ + bool(false) + """ Scenario: Multiline support (basic) Given a WP install And a session file: - """ - function is_empty_string( $str ) { \ - return strlen( $str ) == 0; \ - } + """ + function is_empty_string( $str ) { \ + return strlen( $str ) == 0; \ + } - function_exists( 'is_empty_string' ); - """ + function_exists( 'is_empty_string' ); + """ When I run `wp shell --basic < session` Then STDOUT should be: - """ - bool(true) - """ + """ + bool(true) + """ diff --git a/features/term.feature b/features/term.feature index 076f65621..b658eb97e 100644 --- a/features/term.feature +++ b/features/term.feature @@ -13,7 +13,13 @@ Feature: Manage WordPress terms When I run `wp term list post_tag --format=json` Then STDOUT should be JSON containing: """ - [{"name":"Test term","slug":"test","description":"This is a test term","parent":"0","count":"0"}] + [{ + "name": "Test term", + "slug":"test", + "description":"This is a test term", + "parent":"0", + "count":"0" + }] """ When I run `wp term list post_tag --fields=name,slug --format=csv` diff --git a/features/upgradables.feature b/features/upgradables.feature index fc9c32276..023f6fee3 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -3,12 +3,12 @@ Feature: Manage WordPress themes and plugins Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install And download: - | path | url | + | path | url | | {CACHE_DIR}/<item>.zip | <zip_file> | And I run `wp <type> path` And save STDOUT as {CONTENT_DIR} - # Install an out of date <item> from WordPress.org repository + # Install an out of date <item> from WordPress.org repository When I run `wp <type> install <item> --version=<version>` Then STDOUT should contain: """ @@ -51,46 +51,46 @@ Feature: Manage WordPress themes and plugins # Install <item> from a local zip file When I run `wp <type> install {CACHE_DIR}/<item>.zip` Then STDOUT should contain: - """ - <type_name> installed successfully. - """ + """ + <type_name> installed successfully. + """ And the <file_to_check> file should exist When I run `wp <type> delete <item>` Then STDOUT should contain: - """ - Success: Deleted '<item>' <type>. - """ + """ + Success: Deleted '<item>' <type>. + """ And the <file_to_check> file should not exist # Install <item> from a remote zip file (standard URL with no GET parameters) When I run `wp <type> install <zip_file>` Then STDOUT should contain: - """ - <type_name> installed successfully. - """ + """ + <type_name> installed successfully. + """ And the <file_to_check> file should exist When I run `wp <type> delete <item>` Then STDOUT should contain: - """ - Success: Deleted '<item>' <type>. - """ + """ + Success: Deleted '<item>' <type>. + """ And the <file_to_check> file should not exist # Install <item> from a remote zip file (complex URL with GET parameters) When I run `wp <type> install '<zip_file>?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` Then STDOUT should contain: - """ - <type_name> installed successfully. - """ + """ + <type_name> installed successfully. + """ And the <file_to_check> file should exist When I run `wp <type> delete <item>` Then STDOUT should contain: - """ - Success: Deleted '<item>' <type>. - """ + """ + Success: Deleted '<item>' <type>. + """ And the <file_to_check> file should not exist When I run `wp <type> search <item> --per-page=1 --fields=name,slug` diff --git a/features/user-meta.feature b/features/user-meta.feature index 945237153..7d3ac2b5f 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -8,18 +8,18 @@ Feature: Manage user custom fields When I run `wp user-meta get 1 foo` Then STDOUT should be: - """ - bar - """ + """ + bar + """ When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty When I run `wp user-meta get 1 foo --format=json` Then STDOUT should be: - """ - ["1","2"] - """ + """ + ["1","2"] + """ When I run `wp user-meta delete 1 foo` Then STDOUT should not be empty diff --git a/features/user.feature b/features/user.feature index 83f3f9000..1e39b3eb0 100644 --- a/features/user.feature +++ b/features/user.feature @@ -58,9 +58,14 @@ Feature: Manage WordPress users When I run `wp user list --format=json` Then STDOUT should be JSON containing: - """ - [{"user_login":"admin","display_name":"Existing User","user_email":"admin@domain.com","roles":"administrator"}] - """ + """ + [{ + "user_login":"admin", + "display_name":"Existing User", + "user_email":"admin@domain.com", + "roles":"administrator" + }] + """ Scenario: Managing user roles Given a WP install @@ -98,18 +103,18 @@ Feature: Manage WordPress users When I run `wp user add-cap 1 edit_vip_product` Then STDOUT should be: - """ - Success: Added 'edit_vip_product' capability for admin (1). - """ - + """ + Success: Added 'edit_vip_product' capability for admin (1). + """ + And I run `wp user list-caps 1 | tail -n 1` Then STDOUT should be: - """ - edit_vip_product - """ - + """ + edit_vip_product + """ + And I run `wp user remove-cap 1 edit_vip_product` Then STDOUT should be: - """ - Success: Removed 'edit_vip_product' cap for admin (1). - """ + """ + Success: Removed 'edit_vip_product' cap for admin (1). + """ From 69e93e3e9ec620a86f9d8f25db6540b988aaef44 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 25 Aug 2013 15:28:42 +0300 Subject: [PATCH 2245/5359] first pass at supporting multiple plugin/theme installs --- php/WP_CLI/CommandWithUpgrade.php | 51 +++++++++++++++++-------------- php/commands/plugin.php | 11 +++---- php/commands/theme.php | 14 +++------ 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index f45728252..b8999b811 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -99,40 +99,45 @@ function install( $args, $assoc_args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); - $slug = stripslashes( $args[0] ); + foreach ( $args as $slug ) { + $local_or_remote_zip_file = false; - $local_or_remote_zip_file = ''; - - // Check if a URL to a remote zip file has been specified - $url_path = parse_url( $slug, PHP_URL_PATH ); - if ( ! empty( $url_path ) && '.zip' === substr( $url_path, - 4 ) ) { - $local_or_remote_zip_file = $slug; - } else { - // Check if a local zip file has been specified - if ( 'zip' === pathinfo( $slug, PATHINFO_EXTENSION ) && file_exists( $slug ) ) { + // Check if a URL to a remote zip file has been specified + $url_path = parse_url( $slug, PHP_URL_PATH ); + if ( ! empty( $url_path ) && '.zip' === substr( $url_path, - 4 ) ) { $local_or_remote_zip_file = $slug; + } else { + // Check if a local zip file has been specified + if ( 'zip' === pathinfo( $slug, PATHINFO_EXTENSION ) && file_exists( $slug ) ) { + $local_or_remote_zip_file = $slug; + } } - } - if ( ! empty( $local_or_remote_zip_file ) ) { + if ( $local_or_remote_zip_file ) { + // Install from local or remote zip file + $file_upgrader = $this->get_upgrader( $assoc_args ); + + if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { + $slug = $file_upgrader->result['destination_name']; - // Install from local or remote zip file - $file_upgrader = $this->get_upgrader( $assoc_args ); + if ( isset( $assoc_args['activate'] ) ) { + \WP_CLI::log( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } + } + } else { + // Assume a plugin/theme slug from the WordPress.org repository has been specified + $result = $this->install_from_repo( $slug, $assoc_args ); - if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { - $slug = $file_upgrader->result['destination_name']; + if ( is_wp_error( $result ) ) { + \WP_CLI::warning( $result ); + } - if ( isset( $assoc_args['activate'] ) ) { + if ( $result && isset( $assoc_args['activate'] ) ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } - } else { - exit(1); } - - } else { - // Assume a plugin/theme slug from the WordPress.org repository has been specified - $this->install_from_repo( $slug, $assoc_args ); } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 8e19109dd..442c32192 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -258,7 +258,7 @@ protected function install_from_repo( $slug, $assoc_args ) { $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { - WP_CLI::error( $api ); + return $api; } if ( isset( $assoc_args['version'] ) ) { @@ -269,16 +269,13 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && 'install' != $status['status'] ) { // We know this will fail, so avoid a needless download of the package. - WP_CLI::error( 'Plugin already installed.' ); + return new WP_Error( 'already_installed', "$slug already installed." ); } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + return $result; } /** @@ -372,7 +369,7 @@ protected function filter_item_list( $items, $args ) { * # Install from a remote zip file * wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef * - * @synopsis <plugin|zip|url> [--version=<version>] [--force] [--activate] + * @synopsis <plugin|zip|url>... [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); diff --git a/php/commands/theme.php b/php/commands/theme.php index e777c427d..ef1d8fc60 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -172,12 +172,10 @@ public function path( $args, $assoc_args ) { } protected function install_from_repo( $slug, $assoc_args ) { - $result = NULL; - $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); if ( is_wp_error( $api ) ) { - WP_CLI::error( $api ); + return $api; } if ( isset( $assoc_args['version'] ) ) { @@ -186,17 +184,13 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && wp_get_theme( $slug )->exists() ) { // We know this will fail, so avoid a needless download of the package. - WP_CLI::error( 'Theme already installed.' ); + return new WP_Error( 'already_installed', "$slug already installed." ); } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - // Finally, activate theme if requested. - if ( $result && isset( $assoc_args['activate'] ) ) { - WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + return $result; } protected function get_item_list() { @@ -252,7 +246,7 @@ protected function filter_item_list( $items, $args ) { * # Install from a remote zip file * wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef * - * @synopsis <theme|zip|url> [--version=<version>] [--force] [--activate] + * @synopsis <theme|zip|url>... [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); From b1c2a2723ecd8b8c105d1fd7c1b2435e310e1480 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 25 Aug 2013 16:16:48 +0300 Subject: [PATCH 2246/5359] 'wp theme install' only shows a warning now --- features/theme.feature | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index c05ecd0f2..db0fabc6a 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -6,9 +6,6 @@ Feature: Manage WordPress themes When I run `wp theme install p2` Then STDOUT should not be empty - When I try the previous command again - Then the return code should be 1 - When I run `wp theme status p2` Then STDOUT should contain: """ From 6b37e7d78494543a791c07546489e591a797d0a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 25 Aug 2013 16:32:26 +0300 Subject: [PATCH 2247/5359] make sure the slug is always part of the warning The standard plugin/theme upgrader strings don't contain the slug. --- php/WP_CLI/CommandWithUpgrade.php | 17 +++++++---------- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b8999b811..d1a327c10 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -101,6 +101,7 @@ function install( $args, $assoc_args ) { foreach ( $args as $slug ) { $local_or_remote_zip_file = false; + $result = false; // Check if a URL to a remote zip file has been specified $url_path = parse_url( $slug, PHP_URL_PATH ); @@ -119,24 +120,20 @@ function install( $args, $assoc_args ) { if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { $slug = $file_upgrader->result['destination_name']; - - if ( isset( $assoc_args['activate'] ) ) { - \WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + $result = true; } } else { // Assume a plugin/theme slug from the WordPress.org repository has been specified $result = $this->install_from_repo( $slug, $assoc_args ); if ( is_wp_error( $result ) ) { - \WP_CLI::warning( $result ); + \WP_CLI::warning( "$slug: " . $result->get_error_message() ); } + } - if ( $result && isset( $assoc_args['activate'] ) ) { - \WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } + if ( $result && isset( $assoc_args['activate'] ) ) { + \WP_CLI::log( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); } } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 442c32192..9611905bd 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -269,7 +269,7 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && 'install' != $status['status'] ) { // We know this will fail, so avoid a needless download of the package. - return new WP_Error( 'already_installed', "$slug already installed." ); + return new WP_Error( 'already_installed', 'Plugin already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); diff --git a/php/commands/theme.php b/php/commands/theme.php index ef1d8fc60..c64ac1695 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -184,7 +184,7 @@ protected function install_from_repo( $slug, $assoc_args ) { if ( !isset( $assoc_args['force'] ) && wp_get_theme( $slug )->exists() ) { // We know this will fail, so avoid a needless download of the package. - return new WP_Error( 'already_installed', "$slug already installed." ); + return new WP_Error( 'already_installed', 'Theme already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); From 0f9d7473fa26084e8c2eb11b555fff353eddd3de Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 11:24:18 -0700 Subject: [PATCH 2248/5359] Use `\cli\prompt()` instead of reinventing the wheel See https://github.com/wp-cli/wp-cli/pull/673#issuecomment-22938858 --- php/class-wp-cli.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 6d907f3f7..db2456f1f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -171,9 +171,7 @@ static function prompt( $question, $required = false ) { do { - self::out( $question . ': ' ); - - $response = trim( fgets( STDIN ) ); + $response = \cli\prompt( $question ); if ( $required && $response ) $required = false; From 274546fea043b25138ad07e719e740a8aa1ff6e5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 11:32:11 -0700 Subject: [PATCH 2249/5359] Support for repeating positional arguments --- php/WP_CLI/Dispatcher/Subcommand.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c784d5eb3..e9de96496 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -70,7 +70,11 @@ private function prompt_args( $args, $assoc_args ) { if ( $response ) { switch ( $spec_arg['type'] ) { case 'positional': - $args[] = $response; + if ( $spec_arg['repeating'] ) + $response = explode( ' ', $response ); + else + $response = array( $response ); + $args = array_merge( $args, $response ); break; case 'assoc': $assoc_args[$spec_arg['name']] = $response; From 3b60175a8f2170df0c173d3c7e22f4ca3b046108 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 11:40:43 -0700 Subject: [PATCH 2250/5359] Better use of `\cli\prompt()`, which requires a default argument if the prompt is to be optional --- php/class-wp-cli.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index db2456f1f..ac9aecb95 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -169,15 +169,12 @@ static function confirm( $question, $assoc_args = array() ) { */ static function prompt( $question, $required = false ) { - do { + if ( ! $required ) + $default = ''; + else + $default = false; - $response = \cli\prompt( $question ); - if ( $required && $response ) - $required = false; - - } while( $required ); - - return $response; + return \cli\prompt( $question, $default ); } From f428b027e9e84ffe4d0a46c9feb420763dbb9b6a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 11:56:54 -0700 Subject: [PATCH 2251/5359] Add support for prompting `--flag` --- php/WP_CLI/Dispatcher/Subcommand.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index e9de96496..2d9772aac 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -54,7 +54,7 @@ private function prompt_args( $args, $assoc_args ) { return array( $args, $assoc_args ); $spec = array_filter( \WP_CLI\SynopsisParser::parse( $synopsis ), function( $spec_arg ) { - return in_array( $spec_arg['type'], array( 'positional', 'assoc' ) ); + return in_array( $spec_arg['type'], array( 'positional', 'assoc', 'flag' ) ); }); $spec = array_values( $spec ); @@ -66,6 +66,10 @@ private function prompt_args( $args, $assoc_args ) { $required = ! $spec_arg['optional']; $prompt = ( $key + 1 ) . '/' . count( $spec ) . ' ' . $spec_arg['token']; + + if ( 'flag' == $spec_arg['type'] ) + $prompt .= ' (Y/n)'; + $response = \WP_CLI::prompt( $prompt, $required ); if ( $response ) { switch ( $spec_arg['type'] ) { @@ -79,6 +83,10 @@ private function prompt_args( $args, $assoc_args ) { case 'assoc': $assoc_args[$spec_arg['name']] = $response; break; + case 'flag': + if ( 'Y' == $response ) + $assoc_args[$spec_arg['name']] = true; + break; } } } From 27c80945b71cbb0894405520a54fb23d96315aee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 12:23:09 -0700 Subject: [PATCH 2252/5359] Support for generic arguments --- php/WP_CLI/Dispatcher/Subcommand.php | 77 +++++++++++++++++++--------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 2d9772aac..6b303e55c 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -54,7 +54,7 @@ private function prompt_args( $args, $assoc_args ) { return array( $args, $assoc_args ); $spec = array_filter( \WP_CLI\SynopsisParser::parse( $synopsis ), function( $spec_arg ) { - return in_array( $spec_arg['type'], array( 'positional', 'assoc', 'flag' ) ); + return in_array( $spec_arg['type'], array( 'generic', 'positional', 'assoc', 'flag' ) ); }); $spec = array_values( $spec ); @@ -64,29 +64,60 @@ private function prompt_args( $args, $assoc_args ) { $args = array(); foreach( $spec as $key => $spec_arg ) { + $current_prompt = ( $key + 1 ) . '/' . count( $spec ) . ' '; $required = ! $spec_arg['optional']; - $prompt = ( $key + 1 ) . '/' . count( $spec ) . ' ' . $spec_arg['token']; - - if ( 'flag' == $spec_arg['type'] ) - $prompt .= ' (Y/n)'; - - $response = \WP_CLI::prompt( $prompt, $required ); - if ( $response ) { - switch ( $spec_arg['type'] ) { - case 'positional': - if ( $spec_arg['repeating'] ) - $response = explode( ' ', $response ); - else - $response = array( $response ); - $args = array_merge( $args, $response ); - break; - case 'assoc': - $assoc_args[$spec_arg['name']] = $response; - break; - case 'flag': - if ( 'Y' == $response ) - $assoc_args[$spec_arg['name']] = true; - break; + + // 'generic' permits arbitrary key=value (e.g. [--<field>=<value>] ) + if ( 'generic' == $spec_arg['type'] ) { + + list( $key_token, $value_token ) = explode( '=', $spec_arg['token'] ); + + $repeat = false; + do { + if ( ! $repeat ) + $key_prompt = $current_prompt . $key_token; + else + $key_prompt = str_repeat( " ", strlen( $current_prompt ) ) . $key_token; + + $key = \WP_CLI::prompt( $key_prompt, $required ); + if ( $key ) { + $key_prompt_count = strlen( $key_prompt ) - strlen( $value_token ) - 1; + $value_prompt = str_repeat( " ", $key_prompt_count ) . '=' . $value_token; + $value = \WP_CLI::prompt( $value_prompt ); + $assoc_args[$key] = $value; + + $repeat = true; + $required = false; + } else { + $repeat = false; + } + + } while( $required || $repeat ); + + } else { + + $prompt = $current_prompt . $spec_arg['token']; + if ( 'flag' == $spec_arg['type'] ) + $prompt .= ' (Y/n)'; + + $response = \WP_CLI::prompt( $prompt, $required ); + if ( $response ) { + switch ( $spec_arg['type'] ) { + case 'positional': + if ( $spec_arg['repeating'] ) + $response = explode( ' ', $response ); + else + $response = array( $response ); + $args = array_merge( $args, $response ); + break; + case 'assoc': + $assoc_args[$spec_arg['name']] = $response; + break; + case 'flag': + if ( 'Y' == $response ) + $assoc_args[$spec_arg['name']] = true; + break; + } } } } From dab1d025d9d8df686c45961a5d21009fbff2eee3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 12:33:16 -0700 Subject: [PATCH 2253/5359] A better way of achieving this. See https://github.com/wp-cli/wp-cli/pull/673/files#r5969302 --- php/WP_CLI/Dispatcher/Subcommand.php | 10 +--------- php/WP_CLI/Runner.php | 9 --------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6b303e55c..1f191ead5 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -30,14 +30,6 @@ function get_alias() { return $this->alias; } - function set_prompt( $value ) { - $this->prompt = (bool)$value; - } - - function get_prompt() { - return $this->prompt; - } - function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( sprintf( "%s%s %s", $prefix, @@ -166,7 +158,7 @@ private function validate_args( $args, &$assoc_args ) { function invoke( $args, $assoc_args ) { - if ( $this->get_prompt() ) + if ( \WP_CLI::get_config( 'prompt' ) ) list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); $this->validate_args( $args, $assoc_args ); diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cb9c4b3e9..9dab776d7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -436,15 +436,6 @@ public function before_wp_load() { self::set_url_params( $url_parts ); } - // Handle --prompt parameter - if ( $this->config['prompt'] ) { - $r = $this->find_command_to_run( $this->arguments ); - if ( is_array( $r ) ) { - list( $command ) = $r; - $command->set_prompt( true ); - } - } - $this->do_early_invoke( 'before_wp_load' ); $this->check_wp_version(); From a1decfeb18e7deeefb65974df33f4f3f3dd64e66 Mon Sep 17 00:00:00 2001 From: Andrey Savchenko <contact@rarst.net> Date: Sun, 25 Aug 2013 23:27:27 +0300 Subject: [PATCH 2254/5359] Fixed regex for better matching EOL when cleaning doc block --- php/WP_CLI/DocParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index a999a9e1e..b95df6e07 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -11,7 +11,7 @@ function __construct( $docComment ) { } private static function remove_decorations( $comment ) { - $comment = preg_replace( '|^/\*\*\n|', '', $comment ); + $comment = preg_replace( '|^/\*\*[\r\n]+|', '', $comment ); $comment = preg_replace( '|\n[\t ]*\*/$|', '', $comment ); $comment = preg_replace( '|^[\t ]*\* ?|m', '', $comment ); From b8be71e93d0eee8d8c6f7cdfd5317c60f7d3cb65 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 13:36:02 -0700 Subject: [PATCH 2255/5359] Implement `wp comment list` --- php/commands/comment.php | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index dd7473013..1adf7c98c 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -7,6 +7,15 @@ */ class Comment_Command extends WP_CLI_Command { + private $fields = array( + 'comment_ID', + 'comment_post_ID', + 'comment_date', + 'comment_approved', + 'comment_author', + 'comment_author_email', + ); + /** * Insert a comment. * @@ -93,6 +102,58 @@ public function get( $args, $assoc_args ) { } } + /** + * Get a list of comments. + * + * ## OPTIONS + * + * --<field>=<value> + * : One or more args to pass to WP_Comment_Query. + * + * --fields=<fields> + * : Limit the output to specific object fields. Defaults to comment_ID,comment_post_ID,comment_date,comment_approved,comment_author,comment_author_email + * + * --format=<format> + * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * + * ## EXAMPLES + * + * wp comment list --format=ids + * + * wp comment list --post_id=2 + * + * wp comment list --number=20 --comment_approved=1 + * + * @subcommand list + * @synopsis [--<field>=<value>] [--fields=<fields>] [--format=<format>] + */ + public function _list( $_, $assoc_args ) { + $query_args = array(); + $defaults = array( + 'format' => 'table', + 'fields' => $this->fields + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + foreach ( $assoc_args as $key => $value ) { + if ( true === $value ) + continue; + + $query_args[ $key ] = $value; + } + + if ( 'ids' == $assoc_args['format'] ) + $query_args['fields'] = 'ids'; + + $query = new WP_Comment_Query(); + $comments = $query->query( $query_args ); + + if ( 'ids' == $assoc_args['format'] ) + $comments = wp_list_pluck( $comments, 'comment_ID' ); + + WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); + } + /** * Delete a comment. * From 59c469932f66f074f7e9023794edc36ba59b1dc9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 13:36:14 -0700 Subject: [PATCH 2256/5359] A functional test for `wp comment list` --- features/comment.feature | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 69dee8dbb..e372172f0 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -26,3 +26,8 @@ Feature: Manage WordPress comments Then STDOUT should be a table containing rows: | Field | Value | | comment_author | Mr WordPress | + + When I run `wp comment list --fields=comment_approved,comment_author` + Then STDOUT should be a table containing rows: + | comment_approved | comment_author | + | 1 | Mr WordPress | From d82037c3c2a07a76a53327a31ad1811d04b7ef02 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 16:26:20 -0700 Subject: [PATCH 2257/5359] Catch the thrown exception --- php/class-wp-cli.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ac9aecb95..ba361a0c6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -174,7 +174,12 @@ static function prompt( $question, $required = false ) { else $default = false; - return \cli\prompt( $question, $default ); + try { + $response = \cli\prompt( $question, $default ); + } catch( Exception $e ) { + $response = ''; + } + return $response; } From 25a08b330601068c649fca8ca4d5d84318dadf24 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Aug 2013 17:17:36 -0700 Subject: [PATCH 2258/5359] We don't need a `prompt()` util right now. Instead, let's better utilize PHP cli tools --- php/WP_CLI/Dispatcher/Subcommand.php | 30 ++++++++++++++++++++++++---- php/class-wp-cli.php | 19 ------------------ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1f191ead5..5d91b9cab 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -38,6 +38,18 @@ function show_usage( $prefix = 'usage: ' ) { ) ); } + private function prompt( $question, $default ) { + + try { + $response = \cli\prompt( $question, $default ); + } catch( \Exception $e ) { + \WP_CLI::line(); + return false; + } + + return $response; + } + private function prompt_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); @@ -57,7 +69,7 @@ private function prompt_args( $args, $assoc_args ) { foreach( $spec as $key => $spec_arg ) { $current_prompt = ( $key + 1 ) . '/' . count( $spec ) . ' '; - $required = ! $spec_arg['optional']; + $default = ( $spec_arg['optional'] ) ? '' : false; // 'generic' permits arbitrary key=value (e.g. [--<field>=<value>] ) if ( 'generic' == $spec_arg['type'] ) { @@ -71,11 +83,18 @@ private function prompt_args( $args, $assoc_args ) { else $key_prompt = str_repeat( " ", strlen( $current_prompt ) ) . $key_token; - $key = \WP_CLI::prompt( $key_prompt, $required ); + $key = $this->prompt( $key_prompt, $default ); + if ( false === $key ) + return array( $args, $assoc_args ); + if ( $key ) { $key_prompt_count = strlen( $key_prompt ) - strlen( $value_token ) - 1; $value_prompt = str_repeat( " ", $key_prompt_count ) . '=' . $value_token; - $value = \WP_CLI::prompt( $value_prompt ); + + $value = $this->prompt( $value_prompt, $default ); + if ( false === $value ) + return array( $args, $assoc_args ); + $assoc_args[$key] = $value; $repeat = true; @@ -92,7 +111,10 @@ private function prompt_args( $args, $assoc_args ) { if ( 'flag' == $spec_arg['type'] ) $prompt .= ' (Y/n)'; - $response = \WP_CLI::prompt( $prompt, $required ); + $response = $this->prompt( $prompt, $default ); + if ( false === $response ) + return array( $args, $assoc_args ); + if ( $response ) { switch ( $spec_arg['type'] ) { case 'positional': diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ba361a0c6..da3a32be6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -164,25 +164,6 @@ static function confirm( $question, $assoc_args = array() ) { } } - /** - * Prompt a user for some input - */ - static function prompt( $question, $required = false ) { - - if ( ! $required ) - $default = ''; - else - $default = false; - - try { - $response = \cli\prompt( $question, $default ); - } catch( Exception $e ) { - $response = ''; - } - return $response; - } - - /** * Read a value, from various formats * From 7d11feb5a7a0ef73c4de4f9e1b30c2fd28a36ba4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 26 Aug 2013 03:24:40 +0300 Subject: [PATCH 2259/5359] remove leftover $prompt property --- php/WP_CLI/Dispatcher/Subcommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 5d91b9cab..8dca6c6d3 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -11,8 +11,6 @@ class Subcommand extends CompositeCommand { private $when_invoked; - private $prompt = false; - function __construct( $parent, $name, $docparser, $when_invoked ) { $this->when_invoked = $when_invoked; From 63e7d6c5df0766c460498d8de2d066ddc70c61a4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 27 Aug 2013 23:23:15 +0300 Subject: [PATCH 2260/5359] add behat test for variadic commands --- features/validation.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/validation.feature b/features/validation.feature index 683fe735f..cc2864932 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -3,6 +3,15 @@ Feature: Argument validation As a user I need to see warnings and errors when I pass incorrect arguments + Scenario: Passing zero arguments to a variadic command + Given a WP install + + When I run `wp plugin install` + Then STDOUT should contain: + """ + usage: wp plugin install + """ + Scenario: Validation for early commands Given an empty directory And WP files From 6dec5cb7aea69dc4aa0e7586f2c16732aefab6b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 27 Aug 2013 23:30:34 +0300 Subject: [PATCH 2261/5359] don't ignore repeating arguments in enough_positionals() check --- php/WP_CLI/SynopsisValidator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index bee3f1920..300dd67a4 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -23,7 +23,6 @@ public function enough_positionals( $args ) { $positional = $this->query_spec( array( 'type' => 'positional', 'optional' => false, - 'repeating' => false ) ); return count( $args ) >= count( $positional ); From 49e7d2e6076276ef73122a1d6b34e552a68d6a52 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 28 Aug 2013 00:10:51 +0300 Subject: [PATCH 2262/5359] media regenerate: attachment IDs are optional --- php/commands/media.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index aaa7c08fe..719170c3c 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -24,18 +24,15 @@ class Media_Command extends WP_CLI_Command { * * wp media regenerate --yes * - * @synopsis <attachment-id>... [--yes] + * @synopsis [<attachment-id>...] [--yes] */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; - // If id is given, skip confirm because it is only one file - if( !empty( $args ) ) { - $assoc_args['yes'] = true; + if ( empty( $args ) ) { + WP_CLI::confirm( 'Do you realy want to regenerate all images?', $assoc_args ); } - WP_CLI::confirm('Do you realy want to regenerate all images?', $assoc_args); - $query_args = array( 'post_type' => 'attachment', 'post__in' => $args, From a07738126eb7447ea53977d9cfa2fea3d75a387e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 28 Aug 2013 00:38:35 +0300 Subject: [PATCH 2263/5359] behat: remove unused 'I try to import it' step --- features/steps/basic_steps.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 5c699bf7e..c08a64afa 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -121,15 +121,6 @@ function ( $world, $mode ) { } ); -$steps->When( '/^I try to import it$/', - function ( $world ) { - if ( !isset( $world->variables['DOWNLOADED_IMAGE'] ) ) - throw new \Exception( 'Cached image not available.' ); - - $world->result = $world->proc( 'wp media import ' . $world->variables['DOWNLOADED_IMAGE'] . ' --post_id=1 --featured_image' )->run(); - } -); - $steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { From bac228b347564760f0cf280cc91cb92c8251a3f8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 28 Aug 2013 00:55:29 +0300 Subject: [PATCH 2264/5359] usage errors exit with code 1 --- features/validation.feature | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/validation.feature b/features/validation.feature index cc2864932..803d758af 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -6,7 +6,8 @@ Feature: Argument validation Scenario: Passing zero arguments to a variadic command Given a WP install - When I run `wp plugin install` + When I try `wp plugin install` + Then the return code should be 1 Then STDOUT should contain: """ usage: wp plugin install From e5a743932c2697222db2098ef471abfcbea19e3c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 28 Aug 2013 01:28:56 +0300 Subject: [PATCH 2265/5359] behat: pass process result to checkString() for richer error messages --- features/bootstrap/Process.php | 3 ++- features/bootstrap/support.php | 6 ++++-- features/steps/basic_steps.php | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 16b248df4..e0abcffbe 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -71,7 +71,8 @@ public function __construct( $props ) { } public function __toString() { - return sprintf( "%s: %s\ncwd: %s", $this->command, $this->STDERR, $this->cwd ); + return sprintf( "%s: %s\n" . "cwd: %s\n" . "exit status: %d", + $this->command, $this->STDERR, $this->cwd, $this->return_code ); } } diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 7b77eb7d0..afe96ec1d 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -14,7 +14,7 @@ function assertNumeric( $actual ) { } } -function checkString( $output, $expected, $action ) { +function checkString( $output, $expected, $action, $message = false ) { switch ( $action ) { case 'be': @@ -34,7 +34,9 @@ function checkString( $output, $expected, $action ) { } if ( !$r ) { - throw new Exception( $output ); + if ( false === $message ) + $message = $output; + throw new Exception( $message ); } } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index c08a64afa..1557f91c0 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -149,7 +149,7 @@ function ( $world, $return_code ) { function ( $world, $stream, $action, PyStringNode $expected ) { $expected = $world->replace_variables( (string) $expected ); - checkString( $world->result->$stream, $expected, $action ); + checkString( $world->result->$stream, $expected, $action, $world->result ); } ); From 7a983d338dc8a841a536613ba0ac0caf6079e277 Mon Sep 17 00:00:00 2001 From: = <stianlik@gmail.com> Date: Wed, 28 Aug 2013 12:37:17 +0200 Subject: [PATCH 2266/5359] Support for whitespace in file path --- bin/wp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/wp b/bin/wp index 762d6f5d9..4974e1887 100755 --- a/bin/wp +++ b/bin/wp @@ -7,8 +7,8 @@ # https://github.com/88mph/wpadmin/blob/master/wpadmin.php # Get the absolute path of this executable -ORIGDIR=$(pwd) -SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") +ORIGDIR="$(pwd)" +SELF_PATH="$(cd -P -- "$(dirname -- "$0")" && pwd -P)" && SELF_PATH="$SELF_PATH/$(basename -- "$0")" # Resolve symlinks - this is the equivalent of "readlink -f", but also works with non-standard OS X readlink. while [ -h "$SELF_PATH" ]; do @@ -16,18 +16,18 @@ while [ -h "$SELF_PATH" ]; do # 2) cd to the directory of where the symlink points # 3) Get the pwd # 4) Append the basename - DIR=$(dirname -- "$SELF_PATH") - SYM=$(readlink $SELF_PATH) - SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") + DIR="$(dirname -- "$SELF_PATH")" + SYM="$(readlink "$SELF_PATH")" + SELF_PATH="$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")" done cd "$ORIGDIR" # Build the path to the root PHP file -SCRIPT_PATH=$(dirname "$SELF_PATH")/../php/boot-fs.php +SCRIPT_PATH="$(dirname "$SELF_PATH")/../php/boot-fs.php" case $(uname -a) in CYGWIN*) - SCRIPT_PATH=$(cygpath -w -a -- "$SCRIPT_PATH") ;; + SCRIPT_PATH="$(cygpath -w -a -- "$SCRIPT_PATH")" ;; esac if [ ! -z "$WP_CLI_PHP" ] ; then @@ -36,11 +36,11 @@ if [ ! -z "$WP_CLI_PHP" ] ; then else # Default to using the php that we find on the PATH. # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 - php=`which php` + php="`which php`" fi # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run subcommands -export WP_CLI_PHP_USED=$php +export WP_CLI_PHP_USED="$php" exec "$php" $WP_CLI_PHP_ARGS "$SCRIPT_PATH" "$@" From 6b268f677298779985db9c7cc460af636a6bfc63 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Aug 2013 11:36:56 -0700 Subject: [PATCH 2267/5359] Support arbitrary filters when listing users --- php/commands/user.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 2e6454a11..8cce7cdfa 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -25,6 +25,9 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * * --role=<role> * : Only display users with a certain role. + * + * * --<field>=<value> + * : Filter by one or more fields. For accepted fields, see get_users(). * * --fields=<fields> * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles @@ -41,7 +44,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * wp user list --fields=display_name,user_email * * @subcommand list - * @synopsis [--role=<role>] [--fields=<fields>] [--format=<format>] + * @synopsis [--role=<role>] [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { From fbc41b535c72765de92bd744fb06b1a03bc9d262 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Aug 2013 11:41:07 -0700 Subject: [PATCH 2268/5359] Support arbitrary filtering when listing terms --- php/commands/term.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index 43539574c..415feb5d3 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -23,6 +23,9 @@ class Term_Command extends WP_CLI_Command { * * <taxonomy> * : List terms of a given taxonomy. + * + * --<field>=<value> + * : Filter by one or more fields. For accepted fields, see get_terms(). * * --fields=<fields> * : Limit the output to specific object fields. Defaults to all of the term object fields. @@ -37,7 +40,7 @@ class Term_Command extends WP_CLI_Command { * wp term list post_tag --fields=name,slug * * @subcommand list - * @synopsis <taxonomy> [--fields=<fields>] [--format=<format>] + * @synopsis <taxonomy> [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { From 74e2f4b25450bc3a463081489be29612680a06a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Aug 2013 13:51:34 -0700 Subject: [PATCH 2269/5359] Fix erroneous error --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 8cce7cdfa..9674f5e9f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -588,7 +588,7 @@ public function import_csv( $args, $assoc_args ) { $filename = $args[0]; if ( ! file_exists( $filename ) ) { - WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + WP_CLI::warning( sprintf( "Missing file: %s", $filename ) ); } foreach ( new \WP_CLI\Iterators\CSV( $filename ) as $i => $new_user ) { From 7ceea7cf596a2de6a79702819b73a9e077cb35c5 Mon Sep 17 00:00:00 2001 From: Nate Bedortha <nate@oknoway.com> Date: Fri, 30 Aug 2013 01:50:29 -0700 Subject: [PATCH 2270/5359] Fix small typo --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 173ad2d13..94fcaeb4e 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -406,7 +406,7 @@ private function export_wp( $args = array() ) { ob_end_clean(); WP_CLI::line( 'Exporting ' . count( $all_the_post_ids ) . ' items to be broken into ' . ceil( count( $all_the_post_ids ) / $args['file_item_count'] ) . ' files' ); - WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); + WP_CLI::line( 'Exporting ' . count( $cats ) . ' categories' ); WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); WP_CLI::line(); From 0bbf67912bde8a24d62bd73dc2d4bad7b3da0e9a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 16:46:07 +0300 Subject: [PATCH 2271/5359] first pass at making plugin {activate|deactivate|toggle} accept multiple items --- php/commands/plugin.php | 80 +++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 9611905bd..0cc591410 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -144,23 +144,26 @@ protected function get_all_items() { * --network * : If set, the plugin will be activated for the entire multisite network. * - * @synopsis <plugin> [--network] + * @synopsis <plugin>... [--network] */ function activate( $args, $assoc_args = array() ) { - $name = $args[0]; - $file = $this->parse_name( $name ); - $network_wide = isset( $assoc_args['network'] ); - activate_plugin( $file, '', $network_wide ); + foreach ( $args as $name ) { + $file = $this->parse_name( $name ); + if ( !$file ) + continue; - if ( $this->check_active( $file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '$name' network activated." ); - else - WP_CLI::success( "Plugin '$name' activated." ); - } else { - WP_CLI::error( 'Could not activate plugin: ' . $name ); + activate_plugin( $file, '', $network_wide ); + + if ( $this->check_active( $file, $network_wide ) ) { + if ( $network_wide ) + WP_CLI::success( "Plugin '$name' network activated." ); + else + WP_CLI::success( "Plugin '$name' activated." ); + } else { + WP_CLI::warning( 'Could not activate plugin: ' . $name ); + } } } @@ -175,23 +178,26 @@ function activate( $args, $assoc_args = array() ) { * --network * : If set, the plugin will be deactivated for the entire multisite network. * - * @synopsis <plugin> [--network] + * @synopsis <plugin>... [--network] */ function deactivate( $args, $assoc_args = array() ) { - $name = $args[0]; - $file = $this->parse_name( $name ); - $network_wide = isset( $assoc_args['network'] ); - deactivate_plugins( $file, false, $network_wide ); + foreach ( $args as $name ) { + $file = $this->parse_name( $name ); + if ( !$file ) + continue; - if ( ! $this->check_active( $file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '$name' network deactivated." ); - else - WP_CLI::success( "Plugin '$name' deactivated." ); - } else { - WP_CLI::error( 'Could not deactivate plugin: ' . $name ); + deactivate_plugins( $file, false, $network_wide ); + + if ( ! $this->check_active( $file, $network_wide ) ) { + if ( $network_wide ) + WP_CLI::success( "Plugin '$name' network deactivated." ); + else + WP_CLI::success( "Plugin '$name' deactivated." ); + } else { + WP_CLI::warning( 'Could not deactivate plugin: ' . $name ); + } } } @@ -206,18 +212,21 @@ function deactivate( $args, $assoc_args = array() ) { * --network * : If set, the plugin will be toggled for the entire multisite network. * - * @synopsis <plugin> [--network] + * @synopsis <plugin>... [--network] */ function toggle( $args, $assoc_args = array() ) { - $name = $args[0]; - $file = $this->parse_name( $name ); - $network_wide = isset( $assoc_args['network'] ); - if ( $this->check_active( $file, $network_wide ) ) { - $this->deactivate( $args, $assoc_args ); - } else { - $this->activate( $args, $assoc_args ); + foreach ( $args as $name ) { + $file = $this->parse_name( $name ); + if ( !$file ) + continue; + + if ( $this->check_active( $file, $network_wide ) ) { + $this->deactivate( array( $name ), $assoc_args ); + } else { + $this->activate( array( $name ), $assoc_args ); + } } } @@ -245,6 +254,9 @@ function path( $args, $assoc_args ) { if ( !empty( $args ) ) { $file = $this->parse_name( $args[0] ); + if ( !$file ) + return; + $path .= '/' . $file; if ( isset( $assoc_args['dir'] ) ) @@ -538,8 +550,8 @@ private function parse_name( $name ) { if ( $file = $this->_parse_name( $name ) ) { return $file; } else { - WP_CLI::error( "The plugin '$name' could not be found." ); - exit(); + WP_CLI::warning( "The plugin '$name' could not be found." ); + return false; } } From 3c701e568c4483d824d9b96efa923a91204c4472 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 18:12:53 +0300 Subject: [PATCH 2272/5359] replace parse_name() with validate_plugin_names(). --- features/plugin.feature | 10 +-- php/WP_CLI/CommandWithUpgrade.php | 7 ++ php/commands/plugin.php | 133 +++++++++++++++--------------- 3 files changed, 76 insertions(+), 74 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 299a116d4..26bd999c1 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -44,10 +44,9 @@ Feature: Manage WordPress plugins | zombieland | active | none | 0.1-alpha | When I try `wp plugin uninstall zombieland` - Then the return code should be 1 - And STDERR should contain: + Then STDERR should contain: """ - The plugin is active. + The 'zombieland' plugin is active. """ When I run `wp plugin deactivate zombieland` @@ -61,10 +60,9 @@ Feature: Manage WordPress plugins And the {PLUGIN_DIR}/zombieland file should not exist When I try the previous command again - Then the return code should be 1 - And STDERR should contain: + Then STDERR should contain: """ - The plugin 'zombieland' could not be found. + The 'zombieland' plugin could not be found. """ Scenario: Install a plugin, activate, then force install an older version of the plugin diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index d1a327c10..04d365dec 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -11,7 +11,14 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { abstract protected function get_upgrader_class( $force ); abstract protected function get_item_list(); + + /** + * @param array List of update candidates + * @param array List of item names + * @return array List of update candidates + */ abstract protected function filter_item_list( $items, $args ); + abstract protected function get_all_items(); abstract protected function get_status( $file ); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 0cc591410..5aeeed798 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -97,20 +97,23 @@ public function search( $args, $assoc_args = array() ) { } protected function status_single( $args ) { - $name = $args[0]; - $file = $this->parse_name( $name ); + $plugins = $this->validate_plugin_names( $args ); + if ( empty( $plugins ) ) + exit(1); - $details = $this->get_details( $file ); + list( $plugin ) = $plugins; - $status = $this->format_status( $this->get_status( $file ), 'long' ); + $details = $this->get_details( $plugin->file ); - $version = $details[ 'Version' ]; + $status = $this->format_status( $this->get_status( $plugin->file ), 'long' ); - if ( $this->has_update( $file ) ) + $version = $details['Version']; + + if ( $this->has_update( $plugin->file ) ) $version .= ' (%gUpdate available%n)'; echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'plugin-status.mustache', array( - 'slug' => $name, + 'slug' => $plugin->name, 'status' => $status, 'version' => $version, 'name' => $details['Name'], @@ -149,20 +152,16 @@ protected function get_all_items() { function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $args as $name ) { - $file = $this->parse_name( $name ); - if ( !$file ) - continue; - - activate_plugin( $file, '', $network_wide ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + activate_plugin( $plugin->file, '', $network_wide ); - if ( $this->check_active( $file, $network_wide ) ) { + if ( $this->check_active( $plugin->file, $network_wide ) ) { if ( $network_wide ) - WP_CLI::success( "Plugin '$name' network activated." ); + WP_CLI::success( "Plugin '{$plugin->name}' network activated." ); else - WP_CLI::success( "Plugin '$name' activated." ); + WP_CLI::success( "Plugin '{$plugin->name}' activated." ); } else { - WP_CLI::warning( 'Could not activate plugin: ' . $name ); + WP_CLI::warning( "Could not activate the '{$plugin->name}' plugin." ); } } } @@ -183,20 +182,16 @@ function activate( $args, $assoc_args = array() ) { function deactivate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $args as $name ) { - $file = $this->parse_name( $name ); - if ( !$file ) - continue; - - deactivate_plugins( $file, false, $network_wide ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + deactivate_plugins( $plugin->file, false, $network_wide ); - if ( ! $this->check_active( $file, $network_wide ) ) { + if ( ! $this->check_active( $plugin->file, $network_wide ) ) { if ( $network_wide ) - WP_CLI::success( "Plugin '$name' network deactivated." ); + WP_CLI::success( "Plugin '{$plugin->name}' network deactivated." ); else - WP_CLI::success( "Plugin '$name' deactivated." ); + WP_CLI::success( "Plugin '{$plugin->name}' deactivated." ); } else { - WP_CLI::warning( 'Could not deactivate plugin: ' . $name ); + WP_CLI::warning( "Could not deactivate the '{$plugin->name}' plugin." ); } } } @@ -217,15 +212,11 @@ function deactivate( $args, $assoc_args = array() ) { function toggle( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $args as $name ) { - $file = $this->parse_name( $name ); - if ( !$file ) - continue; - - if ( $this->check_active( $file, $network_wide ) ) { - $this->deactivate( array( $name ), $assoc_args ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + if ( $this->check_active( $plugin->file, $network_wide ) ) { + $this->deactivate( array( $plugin->name ), $assoc_args ); } else { - $this->activate( array( $name ), $assoc_args ); + $this->activate( array( $plugin->name ), $assoc_args ); } } } @@ -253,11 +244,13 @@ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { - $file = $this->parse_name( $args[0] ); - if ( !$file ) + $plugins = $this->validate_plugin_names( $args ); + if ( empty( $plugins ) ) return; - $path .= '/' . $file; + list( $plugin ) = $plugins; + + $path .= '/' . $plugin->file; if ( isset( $assoc_args['dir'] ) ) $path = dirname( $path ); @@ -318,9 +311,9 @@ protected function install_from_repo( $slug, $assoc_args ) { */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { - foreach ( $args as $arg ) { - $this->_delete( $this->parse_name( $arg ) ); - $this->install( array( $arg ), $assoc_args ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + $this->_delete( $plugin->file ); + $this->install( array( $plugin->name ), $assoc_args ); } } else { parent::update_many( $args, $assoc_args ); @@ -344,7 +337,7 @@ protected function get_item_list() { } protected function filter_item_list( $items, $args ) { - $basenames = array_map( array( $this, 'parse_name' ), $args ); + $basenames = wp_list_pluck( $this->validate_plugin_names( $args ), 'file' ); return \WP_CLI\Utils\pick_fields( $items, $basenames ); } @@ -403,27 +396,23 @@ function install( $args, $assoc_args ) { * * wp plugin uninstall hello * - * @synopsis <plugin> [--no-delete] + * @synopsis <plugin>... [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { - $name = $args[0]; - $file = $this->parse_name( $name ); - - if ( is_plugin_active( $file ) ) { - WP_CLI::error( 'The plugin is active.' ); - } - - uninstall_plugin( $file ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + if ( is_plugin_active( $plugin->file ) ) { + WP_CLI::warning( "The '{$plugin->name}' plugin is active." ); + continue; + } - if ( isset( $assoc_args['no-delete'] ) ) - return; + uninstall_plugin( $plugin->file ); - if ( $this->_delete( $file ) ) { - WP_CLI::success( sprintf( "Uninstalled '%s' plugin.", $name ) ); + if ( !isset( $assoc_args['no-delete'] ) && $this->_delete( $plugin->file ) ) { + WP_CLI::success( "Uninstalled '$plugin->name' plugin." ); + } } } - /** * Check if the plugin is installed * @@ -459,14 +448,13 @@ function is_installed( $args, $assoc_args = array() ) { * * wp plugin delete hello * - * @synopsis <plugin> + * @synopsis <plugin>... */ function delete( $args, $assoc_args = array() ) { - $name = $args[0]; - $file = $this->parse_name( $name ); - - if ( $this->_delete( $file ) ) { - WP_CLI::success( sprintf( "Deleted '%s' plugin.", $name ) ); + foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + if ( $this->_delete( $plugin->file ) ) { + WP_CLI::success( "Deleted '{$plugin->name}' plugin." ); + } } } @@ -546,13 +534,22 @@ private function _parse_name( $name ) { return $file; } - private function parse_name( $name ) { - if ( $file = $this->_parse_name( $name ) ) { - return $file; - } else { - WP_CLI::warning( "The plugin '$name' could not be found." ); - return false; + private function validate_plugin_names( $args ) { + $plugins = array(); + + foreach ( $args as $name ) { + $file = $this->_parse_name( $name ); + if ( $file ) { + $plugins[] = (object) array( + 'name' => $name, + 'file' => $file + ); + } else { + WP_CLI::warning( "The '$name' plugin could not be found." ); + } } + + return $plugins; } /** From c4f01fa50a40ab6624c84aeb9d1d9746f45f4118 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 19:22:07 +0300 Subject: [PATCH 2273/5359] make _delete() accept a plugin object --- php/commands/plugin.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 5aeeed798..e217d751e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -312,7 +312,7 @@ protected function install_from_repo( $slug, $assoc_args ) { function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { foreach ( $this->validate_plugin_names( $args ) as $plugin ) { - $this->_delete( $plugin->file ); + $this->_delete( $plugin ); $this->install( array( $plugin->name ), $assoc_args ); } } else { @@ -407,7 +407,7 @@ function uninstall( $args, $assoc_args = array() ) { uninstall_plugin( $plugin->file ); - if ( !isset( $assoc_args['no-delete'] ) && $this->_delete( $plugin->file ) ) { + if ( !isset( $assoc_args['no-delete'] ) && $this->_delete( $plugin ) ) { WP_CLI::success( "Uninstalled '$plugin->name' plugin." ); } } @@ -452,7 +452,7 @@ function is_installed( $args, $assoc_args = array() ) { */ function delete( $args, $assoc_args = array() ) { foreach ( $this->validate_plugin_names( $args ) as $plugin ) { - if ( $this->_delete( $plugin->file ) ) { + if ( $this->_delete( $plugin ) ) { WP_CLI::success( "Deleted '{$plugin->name}' plugin." ); } } @@ -564,8 +564,8 @@ private function get_name( $file ) { return $name; } - private function _delete( $file ) { - $plugin_dir = dirname( $file ); + private function _delete( $plugin ) { + $plugin_dir = dirname( $plugin->file ); if ( '.' == $plugin_dir ) $plugin_dir = $file; From 84b1fb5123f54a9de6cc381454aa025686af7e93 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 19:24:44 +0300 Subject: [PATCH 2274/5359] make get_details() accept a plugin object --- php/commands/plugin.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e217d751e..8348f9334 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -103,7 +103,7 @@ protected function status_single( $args ) { list( $plugin ) = $plugins; - $details = $this->get_details( $plugin->file ); + $details = $this->get_details( $plugin ); $status = $this->format_status( $this->get_status( $plugin->file ), 'long' ); @@ -497,14 +497,16 @@ protected function get_status( $file ) { } /** - * Get the details of a plugin + * Get the details of a plugin. * - * @param string $file + * @param object * @return array */ - protected function get_details( $file ) { + private function get_details( $plugin ) { + $file = $plugin->file; + $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); - $plugin_file = basename( ( $file ) ); + $plugin_file = basename( $file ); return $plugin_folder[$plugin_file]; } From 59f72ed557b536fe95ffc2ff78483f1505ae6f94 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 19:39:42 +0300 Subject: [PATCH 2275/5359] clean up _search() helper: * replace <plugin>/<theme> in synopsis with <search> * check is_wp_error() before using $api * rename $data to $items * remove unused code for --interactive; no point supporting it if it's not functional yet see #630 --- php/WP_CLI/CommandWithUpgrade.php | 36 ++++++++++--------------------- php/commands/plugin.php | 18 ++++++++++------ php/commands/theme.php | 19 +++++++++------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 04d365dec..db20e649a 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -321,7 +321,7 @@ private function get_color( $status ) { } /** - * Search wordpress.org plugin repo + * Search wordpress.org repo. * * @param object $api Data from WP plugin/theme API * @param array $fields Data fields to display in table. @@ -329,38 +329,24 @@ private function get_color( $status ) { * @param string $data_type Plugin or Theme api endpoint */ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { + if ( is_wp_error( $api ) ) + \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); // Sanitize to 1 of 2 types - $data_type = 'plugin' === $data_type ? 'plugin' : 'theme'; + $data_type = ( 'plugin' === $data_type ) ? 'plugin' : 'theme'; $plural = $data_type . 's'; - $data = $api->$plural; - $count = isset( $api->info['results'] ) ? $api->info['results'] : 'unknown'; - - if ( is_wp_error( $api ) ) - \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); - if ( ! isset( $data ) ) + if ( ! isset( $api->$plural ) ) \WP_CLI::error( __( 'API error. Try Again.' ) ); - \WP_CLI::success( 'Showing '. count( $data ) .' of '. $count .' '. $plural .'.' ); - - $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; + $items = $api->$plural; - // @TODO https://github.com/wp-cli/wp-cli/issues/635 - if ( isset( $assoc_args['interactive'] ) ) { - // Add key as a field - $fields = array_merge( array( 'key' ), $fields ); - // & infuse object with $key - foreach ( $data as $key => $item ) { - $item->key = $key; - $data[$key] = $item; - } - } - - $fields = isset( $assoc_args['interactive'] ) ? array_merge( array( 'key' ), $fields ) : $fields; + $count = isset( $api->info['results'] ) ? $api->info['results'] : 'unknown'; + \WP_CLI::success( sprintf( 'Showing %s of %s %s.', count( $items ), $count, $plural ) ); - \WP_CLI\Utils\format_items( $format, $data, $fields ); + $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; + \WP_CLI\Utils\format_items( $format, $items, $assoc_args['fields'] ); } - } + diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 8348f9334..93cb0331e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -44,12 +44,12 @@ function status( $args ) { } /** - * Search wordpress.org plugin repo + * Search the wordpress.org plugin repository. * * ## OPTIONS * - * <plugin> - * : A particular plugin to search for. + * <search> + * : The string to search for. * * --per-page * : Optional number of results to display. Defaults to 10. @@ -81,15 +81,19 @@ function status( $args ) { * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings * - * @synopsis <plugin> [--per-page=<per-page>] [--fields=<fields>] [--format=<format>] + * @synopsis <search> [--per-page=<per-page>] [--fields=<fields>] [--format=<format>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; - $per_page = isset( $assoc_args['per-page'] ) ? (int) $assoc_args['per-page'] : 10; - $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'rating' ); + + $defaults = array( + 'per-page' => 10, + 'fields' => array( 'name', 'slug', 'rating' ) + ); + $assoc_args = array_merge( $defaults, $assoc_args ); $api = plugins_api( 'query_plugins', array( - 'per_page' => $per_page, + 'per_page' => (int) $assoc_args['per-page'], 'search' => $term, ) ); diff --git a/php/commands/theme.php b/php/commands/theme.php index c64ac1695..d71cd5323 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -37,12 +37,12 @@ function status( $args ) { } /** - * Search wordpress.org theme repo + * Search the wordpress.org theme repository. * * ## OPTIONS * - * <theme> - * : A particular theme to search for. + * <search> + * : The string to search for. * * --per-page * : Optional number of results to display. Defaults to 10. @@ -67,20 +67,23 @@ function status( $args ) { * * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description * - * @synopsis <theme> [--per-page=<per-page>] [--fields=<fields>] + * @synopsis <search> [--per-page=<per-page>] [--fields=<fields>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; - $per_page = isset( $assoc_args['per-page'] ) ? (int) $assoc_args['per-page'] : 10; - $fields = isset( $assoc_args['fields'] ) ? $assoc_args['fields'] : array( 'name', 'slug', 'author', 'rating' ); + + $defaults = array( + 'per-page' => 10, + 'fields' => array( 'name', 'slug', 'author', 'rating' ) + ); + $assoc_args = array_merge( $defaults, $assoc_args ); $api = themes_api( 'query_themes', array( - 'per_page' => $per_page, + 'per_page' => (int) $assoc_args['per-page'], 'search' => $term, ) ); parent::_search( $api, $fields, $assoc_args, 'theme' ); - } protected function status_single( $args ) { From 1c3f9e5b5a00a9ba976572e736b47c8f28808d9a Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Thu, 5 Sep 2013 17:05:45 -0700 Subject: [PATCH 2276/5359] Specify DB_CHARSET as default-character-set for wp-db-import A DB export followed by a DB import of the same file was resulting in corrupted UTF-8 characters. The script was being run in the varying-vagrant-vagrants environment which has latin1 as the default charset: mysql> show variables like "character_set_%"; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ --- php/commands/db.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/db.php b/php/commands/db.php index 0f2be91f2..2068248fa 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -167,6 +167,7 @@ private static function run( $cmd, $assoc_args = array(), $descriptors = null ) 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASSWORD, + 'default-character-set' => DB_CHARSET, ) ); Utils\run_mysql_command( $cmd, $final_args, $descriptors ); From 7a2fb31fca5022d4cfa82b895b7418575ef79523 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Sep 2013 19:11:05 +0300 Subject: [PATCH 2277/5359] don't pass the message through colorization; only the label fixes #744 --- php/WP_CLI/Loggers/Regular.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index b33a7f84b..56c63f564 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -4,8 +4,8 @@ class Regular { - private function _line( $message, $handle = STDOUT ) { - fwrite( $handle, \WP_CLI::colorize( $message . "\n" ) ); + private function _line( $message, $label, $color, $handle = STDOUT ) { + fwrite( $handle, \WP_CLI::colorize( "$color$label:%n" ) . " $message\n" ); } function info( $message ) { @@ -13,16 +13,15 @@ function info( $message ) { } function success( $message, $label ) { - $this->_line( "%G$label:%n $message" ); + $this->_line( $message, $label, '%G' ); } function warning( $message, $label ) { - $this->_line( "%C$label:%n $message", STDERR ); + $this->_line( $message, $label, '%C', STDERR ); } function error( $message, $label ) { - $msg = '%R' . $label . ': %n' . $message; - $this->_line( $msg, STDERR ); + $this->_line( $message, $label, '%R', STDERR ); } } From 8ee1854dd766187e0234490549b1664c3de8937b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Sep 2013 19:27:01 +0300 Subject: [PATCH 2278/5359] remove $label parameter from logging methods The label text and color are just a way to signal to the user the type of message. Changing it can lead to confusion. Example: WP_CLI::error( 'Something bad happened!', 'Success' ); --- php/WP_CLI/Loggers/Quiet.php | 8 ++++---- php/WP_CLI/Loggers/Regular.php | 12 ++++++------ php/class-wp-cli.php | 15 ++++++--------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 926986c5e..6f32fbef3 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -8,16 +8,16 @@ function info( $message ) { // nothing } - function success( $message, $label ) { + function success( $message ) { // nothing } - function warning( $message, $label ) { + function warning( $message ) { // nothing } - function error( $message, $label ) { - fwrite( STDERR, \WP_CLI::colorize( "%R$label:%n $message\n" ) ); + function error( $message ) { + fwrite( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 56c63f564..b992faa1e 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -12,16 +12,16 @@ function info( $message ) { fwrite( STDOUT, $message . "\n" ); } - function success( $message, $label ) { - $this->_line( $message, $label, '%G' ); + function success( $message ) { + $this->_line( $message, 'Success', '%G' ); } - function warning( $message, $label ) { - $this->_line( $message, $label, '%C', STDERR ); + function warning( $message ) { + $this->_line( $message, 'Warning', '%C', STDERR ); } - function error( $message, $label ) { - $this->_line( $message, $label, '%R', STDERR ); + function error( $message ) { + $this->_line( $message, 'Error', '%R', STDERR ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index da3a32be6..67d06ea43 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -120,31 +120,28 @@ static function log( $message ) { * Display a success in the CLI and end with a newline * * @param string $message - * @param string $label */ - static function success( $message, $label = 'Success' ) { - self::$logger->success( $message, $label ); + static function success( $message ) { + self::$logger->success( $message ); } /** * Display a warning in the CLI and end with a newline * * @param string $message - * @param string $label */ - static function warning( $message, $label = 'Warning' ) { - self::$logger->warning( self::error_to_string( $message ), $label ); + static function warning( $message ) { + self::$logger->warning( self::error_to_string( $message ) ); } /** * Display an error in the CLI and end with a newline * * @param string $message - * @param string $label */ - static function error( $message, $label = 'Error' ) { + static function error( $message ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { - self::$logger->error( self::error_to_string( $message ), $label ); + self::$logger->error( self::error_to_string( $message ) ); } exit(1); From 7c86825b63cfb0a273ec9e70cf019dce2304efc1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Sep 2013 19:54:53 +0300 Subject: [PATCH 2279/5359] add unit test for regular logger --- php/WP_CLI/Loggers/Regular.php | 13 +++++++++++-- php/WP_CLI/Runner.php | 2 +- tests/test-logging.php | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 tests/test-logging.php diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index b992faa1e..b3ad21213 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -4,12 +4,21 @@ class Regular { + function __construct( $in_color ) { + $this->in_color = $in_color; + } + + protected function write( $handle, $str ) { + fwrite( $handle, $str ); + } + private function _line( $message, $label, $color, $handle = STDOUT ) { - fwrite( $handle, \WP_CLI::colorize( "$color$label:%n" ) . " $message\n" ); + $label = \cli\Colors::colorize( "$color$label:%n", $this->in_color ); + $this->write( $handle, "$label $message\n" ); } function info( $message ) { - fwrite( STDOUT, $message . "\n" ); + $this->write( STDOUT, $message . "\n" ); } function success( $message ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9dab776d7..a81e0d5a8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -338,7 +338,7 @@ private function init_logger() { if ( $this->config['quiet'] ) $logger = new \WP_CLI\Loggers\Quiet; else - $logger = new \WP_CLI\Loggers\Regular; + $logger = new \WP_CLI\Loggers\Regular( $this->in_color() ); WP_CLI::set_logger( $logger ); } diff --git a/tests/test-logging.php b/tests/test-logging.php new file mode 100644 index 000000000..02899d9a8 --- /dev/null +++ b/tests/test-logging.php @@ -0,0 +1,22 @@ +<?php + +class LoggerMock extends WP_CLI\Loggers\Regular { + + protected function write( $handle, $str ) { + echo $str; + } +} + + +class LoggingTests extends PHPUnit_Framework_TestCase { + + function testLogEscaping() { + $logger = new LoggerMock( false ); + + $message = 'foo%20bar'; + + $this->expectOutputString( "Success: $message\n" ); + $logger->success( $message ); + } +} + From 78782996e2870d927582e619cbd141984a314e13 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 6 Sep 2013 21:46:19 +0300 Subject: [PATCH 2280/5359] fix usage of $label parameter in WP_CLI::error() --- php/WP_CLI/Dispatcher/Subcommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 8dca6c6d3..c5d4c0c19 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -161,12 +161,12 @@ private function validate_args( $args, &$assoc_args ) { $errors = $parser->validate_assoc( $assoc_args, array_keys( \WP_CLI::get_config() ) ); if ( !empty( $errors['fatal'] ) ) { - $out = ''; + $out = 'Parameter errors:'; foreach ( $errors['fatal'] as $error ) { $out .= "\n " . $error; } - \WP_CLI::error( $out, "Parameter errors" ); + \WP_CLI::error( $out ); } array_map( '\\WP_CLI::warning', $errors['warning'] ); From 7856b70d154418b27cd4e9377e01de446ae9e65d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 10 Sep 2013 21:25:35 +0300 Subject: [PATCH 2281/5359] make 'update --all' work again and add test --- features/upgradables.feature | 3 +++ php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 023f6fee3..b7d1a3478 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -31,6 +31,9 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> update <item>` Then STDOUT should not be empty + When I run `wp <type> update --all` + Then STDOUT should not be empty + When I run `wp <type> status <item>` Then STDOUT should not contain: """ diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 93cb0331e..ff1784ebf 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -311,7 +311,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * * wp plugin update --all * - * @synopsis <plugin>... [--version=<version>] [--all] [--dry-run] + * @synopsis [<plugin>...] [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index d71cd5323..4a8293b82 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -335,7 +335,7 @@ public function get( $args, $assoc_args ) { * * wp theme update --all * - * @synopsis <theme>... [--version=<version>] [--all] [--dry-run] + * @synopsis [<theme>...] [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { parent::update_many( $args, $assoc_args ); From 819665c338a006334dd16d16ef527ec0263820c2 Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Tue, 10 Sep 2013 11:56:45 -0700 Subject: [PATCH 2282/5359] wp core config: Add dbcharset and dbcollate params Allow dbcharset and dbcollate to be set on config to avoid character set problems during migrations --- php/commands/core.php | 12 ++++++++++-- templates/wp-config.mustache | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 0bfc0d04f..5fb0c4632 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -148,12 +148,18 @@ private static function get_initial_locale() { * --dbprefix=<dbprefix> * : Set the database table prefix. Default: 'wp_' * + * --dbcharset=<dbcharset> + * : Set the database charset. Default: 'utf8' + * + * --dbcollate=<dbcollate> + * : Set the database collation. Default: '' + * * --locale=<locale> * : Set the WPLANG constant. Defaults to $wp_local_package variable. * * --extra-php * : If set, the command reads additional PHP code from STDIN. - * + * * --skip-salts * : If set, keys and salts won't be generated, but, instead, should be passed via --extra-php. * @@ -168,7 +174,7 @@ private static function get_initial_locale() { * define( 'WP_DEBUG_LOG', true ); * PHP * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--locale=<locale>] [--extra-php] [--skip-salts] + * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--dbcharset=<charset>] [--dbcollate=<collation>] [--locale=<locale>] [--extra-php] [--skip-salts] */ public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { @@ -179,6 +185,8 @@ public function config( $_, $assoc_args ) { 'dbhost' => 'localhost', 'dbpass' => '', 'dbprefix' => 'wp_', + 'dbcharset' => 'utf8', + 'dbcollate' => '', 'locale' => self::get_initial_locale() ); $assoc_args = array_merge( $defaults, $assoc_args ); diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 20b4b6b33..d0cec68c1 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -23,10 +23,10 @@ define('DB_PASSWORD', '{{dbpass}}'); define('DB_HOST', '{{dbhost}}'); /** Database Charset to use in creating database tables. */ -define('DB_CHARSET', 'utf8'); +define('DB_CHARSET', '{{dbcharset}}'); /** The Database Collate type. Don't change this if in doubt. */ -define('DB_COLLATE', ''); +define('DB_COLLATE', '{{dbcollate}}'); {{#keys-and-salts}} /**#@+ From a9adf7b78bcefe3b5db03e167f53c6263dab1549 Mon Sep 17 00:00:00 2001 From: smhmic <smhmic@gmail.com> Date: Tue, 10 Sep 2013 15:29:23 -0400 Subject: [PATCH 2283/5359] allow (but ignore) a leading "[no-]" before flag name in @synopsis `no-` prefix on flag name sets it to `false`, but there was no valid way to show this in usage synopsis. Showing this is relevant for flags with a dynamic default value (like `--color` config flag). This change makes `@synopsis [--[no-]flag]` valid. --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 1da1504ef..37cc3aca0 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -44,7 +44,7 @@ private static function classify_token( $token ) { $param['type'] = 'generic'; } elseif ( preg_match( "/^<$p_value>$/", $token, $matches ) ) { $param['type'] = 'positional'; - } elseif ( preg_match( "/^--$p_name/", $token, $matches ) ) { + } elseif ( preg_match( "/^--(?:\\[no-\\])?$p_name/", $token, $matches ) ) { $param['name'] = $matches[1]; $value = substr( $token, strlen( $matches[0] ) ); From fb803a141ad53271faf413657631c351c3c1fa73 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 11 Sep 2013 16:40:34 +0300 Subject: [PATCH 2284/5359] mention dev-build in README. fixes #757 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 83a5f567d..b6f4de555 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,12 @@ WP-CLI WP-CLI is a set of command-line tools for managing WordPress installations. +Installation +------------ +If you just want to use WP-CLI, see <http://wp-cli.org/#install>. + +If you want to hack on WP-CLI, then clone this repository and run `./utils/dev-build`. + Where can I get more info? -------------------------- For documentation, usage, and examples, check out [wp-cli.org](http://wp-cli.org/). From 9a30af2cbe8a724a957fd3c97166cc595d4024b0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 12 Sep 2013 00:31:27 +0300 Subject: [PATCH 2285/5359] first pass at extracting synopsis from longdesc --- php/WP_CLI/Dispatcher/Subcommand.php | 13 +++++++++++-- php/commands/core.php | 8 +++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c5d4c0c19..e51f1f702 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -12,12 +12,21 @@ class Subcommand extends CompositeCommand { private $when_invoked; function __construct( $parent, $name, $docparser, $when_invoked ) { + parent::__construct( $parent, $name, $docparser ); + $this->when_invoked = $when_invoked; - $this->synopsis = $docparser->get_synopsis(); $this->alias = $docparser->get_tag( 'alias' ); - parent::__construct( $parent, $name, $docparser ); + $this->synopsis = $docparser->get_synopsis(); + if ( !$this->synopsis && $this->longdesc ) { + $this->synopsis = self::extract_synopsis( $this->longdesc ); + } + } + + private static function extract_synopsis( $longdesc ) { + preg_match_all( '/(.+)\n:/', $longdesc, $matches ); + return implode( ' ', $matches[1] ); } function get_synopsis() { diff --git a/php/commands/core.php b/php/commands/core.php index 5fb0c4632..8657cf804 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -14,21 +14,19 @@ class Core_Command extends WP_CLI_Command { * * ## OPTIONS * - * --locale=<locale> + * [--locale=<locale>] * : Select which language you want to download. * - * --version=<version> + * [--version=<version>] * : Select which version you want to download. * - * --force + * [--force] * : Overwrites existing files, if present. * * ## EXAMPLES * * wp core download --version=3.3 * - * @synopsis [--locale=<locale>] [--version=<version>] [--path=<path>] [--force] - * * @when before_wp_load */ public function download( $args, $assoc_args ) { From eb84ccfbd390a970a6c765913bf99618901cb854 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 12 Sep 2013 01:34:39 +0300 Subject: [PATCH 2286/5359] remove synopsis tag from the rest of the core subcommands --- php/commands/core.php | 56 +++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8657cf804..248f34d63 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -137,28 +137,28 @@ private static function get_initial_locale() { * --dbuser=<dbuser> * : Set the database user. * - * --dbpass=<dbpass> + * [--dbpass=<dbpass>] * : Set the database user password. * - * --dbhost=<dbhost> + * [--dbhost=<dbhost>] * : Set the database host. Default: 'localhost' * - * --dbprefix=<dbprefix> + * [--dbprefix=<dbprefix>] * : Set the database table prefix. Default: 'wp_' * - * --dbcharset=<dbcharset> + * [--dbcharset=<dbcharset>] * : Set the database charset. Default: 'utf8' * - * --dbcollate=<dbcollate> + * [--dbcollate=<dbcollate>] * : Set the database collation. Default: '' * - * --locale=<locale> + * [--locale=<locale>] * : Set the WPLANG constant. Defaults to $wp_local_package variable. * - * --extra-php + * [--extra-php] * : If set, the command reads additional PHP code from STDIN. * - * --skip-salts + * [--skip-salts] * : If set, keys and salts won't be generated, but, instead, should be passed via --extra-php. * * ## EXAMPLES @@ -171,8 +171,6 @@ private static function get_initial_locale() { * define( 'WP_DEBUG', true ); * define( 'WP_DEBUG_LOG', true ); * PHP - * - * @synopsis --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] [--dbprefix=<prefix>] [--dbcharset=<charset>] [--dbcollate=<collation>] [--locale=<locale>] [--extra-php] [--skip-salts] */ public function config( $_, $assoc_args ) { if ( Utils\locate_wp_config() ) { @@ -254,8 +252,6 @@ public function is_installed() { * * --admin_email=<email> * : The email address for the admin user. - * - * @synopsis --url=<url> --title=<site-title> --admin_user=<username> --admin_email=<email> --admin_password=<password> */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -270,19 +266,18 @@ public function install( $args, $assoc_args ) { * * ## OPTIONS * - * --title=<site-title> + * [--title=<network-title>] * : The title of the new network. * - * --base=<url-path> + * [--base=<url-path>] * : Base path after the domain name that each site url will start with. * Default: '/' * - * --subdomains + * [--subdomains] * : If passed, the network will use subdomains, instead of subdirectories. * * @subcommand multisite-convert * @alias install-network - * @synopsis [--title=<network-title>] [--base=<url-path>] [--subdomains] */ public function multisite_convert( $args, $assoc_args ) { if ( is_multisite() ) @@ -306,11 +301,11 @@ public function multisite_convert( $args, $assoc_args ) { * --url=<url> * : The address of the new site. * - * --base=<url-path> + * [--base=<url-path>] * : Base path after the domain name that each site url in the network will start with. * Default: '/' * - * --subdomains + * [--subdomains] * : If passed, the network will use subdomains, instead of subdirectories. * * --title=<site-title> @@ -326,7 +321,6 @@ public function multisite_convert( $args, $assoc_args ) { * : The email address for the admin user. * * @subcommand multisite-install - * @synopsis --url=<url> --title=<site-title> [--base=<url-path>] [--subdomains] --admin_user=<username> --admin_email=<email> --admin_password=<password> */ public function multisite_install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -536,11 +530,10 @@ private static function get_clean_basedomain() { * * ## OPTIONS * - * --extra + * [--extra] * : Show extended version information. * * @when before_wp_load - * @synopsis [--extra] */ public function version( $args = array(), $assoc_args = array() ) { $versions_path = ABSPATH . 'wp-includes/version.php'; @@ -575,11 +568,13 @@ public function version( $args = array(), $assoc_args = array() ) { * * ## OPTIONS * - * --version=<new_version> [package/zip] - * : When passed, updates to new_version, optionally using package/zip as - * input. + * [<zip>] + * : Path to zip file to use, instead of downloading from wordpress.org. + * + * [--version=<version>] + * : Update to this version, instead of to the latest version. * - * --force + * [--force] * : Will update even when current WP version < passed version. Use with * caution. * @@ -592,8 +587,6 @@ public function version( $args = array(), $assoc_args = array() ) { * wp core update --version=3.1 --force * * @alias upgrade - * - * @synopsis [<zip>] [--version=<version>] [--force] */ function update( $args, $assoc_args ) { global $wp_version; @@ -674,7 +667,7 @@ function update_db() { * * ## OPTIONS * - * <path> + * [<path>] * : The directory in which to download the testing suite files. (Optional) * * --dbname=<dbname> @@ -684,14 +677,15 @@ function update_db() { * --dbuser=<dbuser> * : Set the database user. * - * --dbpass=<dbpass> + * [--dbpass=<dbpass>] * : Set the database user password. * + * [--dbhost=<host>] + * : Set the database host. + * * ## EXAMPLE * * wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test - * - * @synopsis [<path>] --dbname=<name> --dbuser=<user> [--dbpass=<password>] [--dbhost=<host>] */ function init_tests( $args, $assoc_args ) { if ( isset( $args[0] ) ) From e48aa6863c422c23ee0833a679d751a6cbab659b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 12 Sep 2013 03:18:53 +0300 Subject: [PATCH 2287/5359] use fwrite() instead of echo, to prevent buffering --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 67d06ea43..12b759e23 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -152,7 +152,7 @@ static function error( $message ) { */ static function confirm( $question, $assoc_args = array() ) { if ( !isset( $assoc_args['yes'] ) ) { - echo $question . " [y/n] "; + fwrite( STDOUT, $question . " [y/n] " ); $answer = trim( fgets( STDIN ) ); From 93cc47b1949056ed90866e9438e7b4f49e7042fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 12 Sep 2013 02:02:30 +0300 Subject: [PATCH 2288/5359] remove synopsis tag where not needed --- php/commands/comment.php | 106 ++++++++++++-------------------- php/commands/export.php | 24 ++++---- php/commands/import.php | 4 +- php/commands/media.php | 10 ++- php/commands/option.php | 2 +- php/commands/plugin.php | 87 ++++++++++---------------- php/commands/post-meta.php | 2 +- php/commands/post.php | 53 ++++++---------- php/commands/rewrite.php | 21 ++++--- php/commands/role.php | 34 ++++------ php/commands/scaffold.php | 76 +++++++++++------------ php/commands/search-replace.php | 17 +++-- php/commands/shell.php | 4 +- php/commands/site.php | 22 +++---- php/commands/term.php | 46 ++++++-------- php/commands/theme.php | 66 +++++++------------- php/commands/user.php | 67 ++++++++------------ 17 files changed, 258 insertions(+), 383 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 1adf7c98c..d59e134c9 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -8,13 +8,13 @@ class Comment_Command extends WP_CLI_Command { private $fields = array( - 'comment_ID', - 'comment_post_ID', - 'comment_date', - 'comment_approved', - 'comment_author', - 'comment_author_email', - ); + 'comment_ID', + 'comment_post_ID', + 'comment_date', + 'comment_approved', + 'comment_author', + 'comment_author_email', + ); /** * Insert a comment. @@ -22,16 +22,14 @@ class Comment_Command extends WP_CLI_Command { * ## OPTIONS * * --<field>=<value> - * : Field values for the new comment. See wp_insert_comment(). + * : Associative args for the new comment. See wp_insert_comment(). * - * --porcelain + * [--porcelain] * : Output just the new comment id. * * ## EXAMPLES * * wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" - * - * @synopsis --<field>=<value> [--porcelain] */ public function create( $args, $assoc_args ) { $post = get_post( $assoc_args['comment_post_ID'] ); @@ -53,25 +51,22 @@ public function create( $args, $assoc_args ) { } /** - * Get a comment - * + * Get a single comment. + * * ## OPTIONS * * <id> * : The comment to get. - * - * * --format=<format> + * + * [--format=<format>] * : The format to use when printing the comment, acceptable values: * * - **table**: Outputs all fields of the comment as a table. - * * - **json**: Outputs all fields in JSON format. - * + * * ## EXAMPLES * * wp comment get 1 - * - * @synopsis <id> [--format=<format>] */ public function get( $args, $assoc_args ) { @@ -107,13 +102,13 @@ public function get( $args, $assoc_args ) { * * ## OPTIONS * - * --<field>=<value> + * [--<field>=<value>] * : One or more args to pass to WP_Comment_Query. * - * --fields=<fields> + * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to comment_ID,comment_post_ID,comment_date,comment_approved,comment_author,comment_author_email * - * --format=<format> + * [--format=<format>] * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. * * ## EXAMPLES @@ -125,7 +120,6 @@ public function get( $args, $assoc_args ) { * wp comment list --number=20 --comment_approved=1 * * @subcommand list - * @synopsis [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $_, $assoc_args ) { $query_args = array(); @@ -159,17 +153,15 @@ public function _list( $_, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to delete. * - * --force + * [--force] * : Skip the trash bin. * * ## EXAMPLES * * wp comment delete 1337 --force - * - * @synopsis <id> [--force] */ public function delete( $args, $assoc_args ) { list( $comment_id ) = $args; @@ -195,7 +187,7 @@ private function call( $args, $status, $success, $failure ) { private function set_status( $args, $status, $success ) { $comment = $this->_fetch_comment( $args ); - + $r = wp_set_comment_status( $comment->comment_ID, 'approve', true ); if ( is_wp_error( $r ) ) { @@ -210,14 +202,12 @@ private function set_status( $args, $status, $success ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to trash. * * ## EXAMPLES * * wp comment trash 1337 - * - * @synopsis <id> */ public function trash( $args, $assoc_args ) { $this->call( $args, __FUNCTION__, 'Trashed', 'Failed trashing' ); @@ -228,14 +218,12 @@ public function trash( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to untrash. * * ## EXAMPLES * * wp comment untrash 1337 - * - * @synopsis <id> */ public function untrash( $args, $assoc_args ) { $this->call( $args, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); @@ -246,14 +234,12 @@ public function untrash( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to mark as spam. * * ## EXAMPLES * * wp comment spam 1337 - * - * @synopsis <id> */ public function spam( $args, $assoc_args ) { $this->call( $args, __FUNCTION__, 'Marked as spam', 'Failed marking as spam' ); @@ -264,13 +250,12 @@ public function spam( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to unmark as spam. * * ## EXAMPLES * * wp comment unspam 1337 - * @synopsis <id> */ public function unspam( $args, $assoc_args ) { $this->call( $args, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); @@ -281,14 +266,12 @@ public function unspam( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to approve. * * ## EXAMPLES * * wp comment approve 1337 - * - * @synopsis <id> */ public function approve( $args, $assoc_args ) { $this->set_status( $args, 'approve', "Approved" ); @@ -299,14 +282,12 @@ public function approve( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> + * <id> * : The ID of the comment to unapprove. * * ## EXAMPLES * * wp comment unapprove 1337 - * - * @synopsis <id> */ public function unapprove( $args, $assoc_args ) { $this->set_status( $args, 'hold', "Unapproved" ); @@ -317,15 +298,13 @@ public function unapprove( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> - * : The ID of the post to count comments in + * <post-id> + * : The ID of the post to count comments in. * * ## EXAMPLES * * wp comment count * wp comment count 42 - * - * @synopsis [<post-id>] */ public function count( $args, $assoc_args ) { $post_id = isset( $args[0] ) ? $args[0] : 0; @@ -347,14 +326,12 @@ public function count( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> - * : The ID of the comment to check + * <id> + * : The ID of the comment to check. * * ## EXAMPLES * * wp comment status 1337 - * - * @synopsis <id> */ public function status( $args, $assoc_args ) { list( $comment_id ) = $args; @@ -373,17 +350,15 @@ public function status( $args, $assoc_args ) { * * ## OPTIONS * - * --id + * [--id] * : Output just the last comment id. * - * --full + * [--full] * : Output complete comment information. * * ## EXAMPLES * * wp comment last --full - * - * @synopsis [--id] [--full] */ function last( $args = array(), $assoc_args = array() ) { $last = get_comments( array( 'number' => 1, 'status' => 'approve' ) ); @@ -407,39 +382,36 @@ function last( $args = array(), $assoc_args = array() ) { WP_CLI::line( str_pad( "$key:", 23 ) . $comment->$key ); } } - + /** * Verify whether a comment exists. * * ## OPTIONS * - * <ID> - * : The ID of the comment to check from. + * <id> + * : The ID of the comment to check. * * ## EXAMPLES * * wp comment exists 1337 - * - * @synopsis <id> */ public function exists( $args ) { if ( $this->_fetch_comment( $args ) ) { WP_CLI::success( "Comment with ID $args[0] exists." ); } } - + /** - * A helper function fetching a comment object from comment_id. - * + * A helper function fetching a comment object from comment_id. */ private function _fetch_comment( $args ) { $comment_id = (int) $args[0]; $comment = get_comment( $comment_id ); - + if ( is_null( $comment ) ) { WP_CLI::error( "Comment with ID $args[0] does not exist." ); } - + return $comment; } } diff --git a/php/commands/export.php b/php/commands/export.php index 94fcaeb4e..59781549e 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -13,40 +13,40 @@ class Export_Command extends WP_CLI_Command { * * ## OPTIONS * - * --dir=<dirname> + * [--dir=<dirname>] * : Full path to directory where WXR export files should be stored. Defaults * to current working directory. * - * --skip_comments + * [--skip_comments] * : Don't export comments. * - * --file_item_count=<count> + * [--file_item_count=<count>] * : Break export into files with N posts. * - * --verbose + * [--verbose] * : Show more information about the process on STDOUT. * * ## FILTERS * - * --start_date=<date> + * [--start_date=<date>] * : Export only posts newer than this date, in format YYYY-MM-DD. * - * --end_date=<date> + * [--end_date=<date>] * : Export only posts older than this date, in format YYYY-MM-DD. * - * --post_type=<post_type> + * [--post_type=<post_type>] * : Export only posts with this post_type. * - * --post__in=<pid> + * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. * - * --author=<login/id> + * [--author=<login/id>] * : Export only posts by this author. * - * --category=<category-id> + * [--category=<category-id>] * : Export only posts in this category. * - * --post_status=<status> + * [--post_status=<status>] * : Export only posts with this status. * * ## EXAMPLES @@ -54,8 +54,6 @@ class Export_Command extends WP_CLI_Command { * wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 * * wp export --dir=/tmp/ --post__in=123,124,125 - * - * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>] [--verbose] */ public function __invoke( $_, $assoc_args ) { $defaults = array( diff --git a/php/commands/import.php b/php/commands/import.php index 39fccb8f6..493badb64 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -13,10 +13,8 @@ class Import_Command extends WP_CLI_Command { * --authors=<authors> * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. * - * --skip=<data-type> + * [--skip=<data-type>] * : Skip importing specific data. Supported option is 'attachment'. - * - * @synopsis <file> --authors=<authors> [--skip=<data-type>] */ public function __invoke( $args, $assoc_args ) { list( $file ) = $args; diff --git a/php/commands/media.php b/php/commands/media.php index 719170c3c..eb5e4e938 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -12,19 +12,17 @@ class Media_Command extends WP_CLI_Command { * * ## OPTIONS * - * --yes - * : Answer yes to the confirmation message. - * - * <attachment-id> + * [<attachment-id>...] * : One or more IDs of the attachments to regenerate. * + * [--yes] + * : Answer yes to the confirmation message. + * * ## EXAMPLES * * wp media regenerate 123 1337 * * wp media regenerate --yes - * - * @synopsis [<attachment-id>...] [--yes] */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; diff --git a/php/commands/option.php b/php/commands/option.php index a825342c5..7f3e87a16 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -5,7 +5,7 @@ * * ## OPTIONS * - * --format=json + * [--format=json] * : Encode/decode values as JSON. * * ## EXAMPLES diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ff1784ebf..46a655f09 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -34,10 +34,8 @@ protected function get_upgrader_class( $force ) { * * ## OPTIONS * - * <plugin> + * [<plugin>] * : A particular plugin to show the status for. - * - * @synopsis [<plugin>] */ function status( $args ) { parent::status( $args ); @@ -51,14 +49,14 @@ function status( $args ) { * <search> * : The string to search for. * - * --per-page + * [--per-page=<per-page>] * : Optional number of results to display. Defaults to 10. * - * --format + * [--format=<format>] * : Output list as table, CSV or JSON. Defaults to table. * - * --fields - * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. acceptable values: + * [--fields=<fields>] + * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. Acceptable values: * * **name**: Plugin Name * **slug**: Plugin Slug @@ -80,8 +78,6 @@ function status( $args ) { * wp plugin search dsgnwrks --per-page=20 --format=json * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings - * - * @synopsis <search> [--per-page=<per-page>] [--fields=<fields>] [--format=<format>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; @@ -145,13 +141,11 @@ protected function get_all_items() { * * ## OPTIONS * - * <plugin> - * : The plugin to activate. + * <plugin>... + * : One or more plugins to activate. * - * --network + * [--network] * : If set, the plugin will be activated for the entire multisite network. - * - * @synopsis <plugin>... [--network] */ function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); @@ -175,13 +169,11 @@ function activate( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <plugin> - * : The plugin to deactivate. + * <plugin>... + * : One or more plugins to deactivate. * - * --network + * [--network] * : If set, the plugin will be deactivated for the entire multisite network. - * - * @synopsis <plugin>... [--network] */ function deactivate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); @@ -205,13 +197,11 @@ function deactivate( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <plugin> - * : The plugin to toggle. + * <plugin>... + * : One or more plugins to toggle. * - * --network + * [--network] * : If set, the plugin will be toggled for the entire multisite network. - * - * @synopsis <plugin>... [--network] */ function toggle( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); @@ -230,19 +220,17 @@ function toggle( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <plugin> + * [<plugin>] * : The plugin to get the path to. If not set, will return the path to the * plugins directory. * - * --dir + * [--dir] * : If set, get the path to the closest parent directory, instead of the * plugin file. * * ## EXAMPLES * * cd $(wp theme path) - * - * @synopsis [<plugin>] [--dir] */ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); @@ -292,17 +280,17 @@ protected function install_from_repo( $slug, $assoc_args ) { * * ## OPTIONS * - * <plugin> - * : The plugin(s) to update. + * [<plugin>...] + * : One or more plugins to update. * - * --all + * [--all] * : If set, all plugins that have updates will be updated. * - * --version=dev + * [--version=<version>] * : If set, the plugin will be updated to the latest development version, * regardless of what version is currently installed. * - * --dry-run + * [--dry-run] * : Preview which plugins would be updated. * * ## EXAMPLES @@ -310,8 +298,6 @@ protected function install_from_repo( $slug, $assoc_args ) { * wp plugin update bbpress --version=dev * * wp plugin update --all - * - * @synopsis [<plugin>...] [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { @@ -350,18 +336,18 @@ protected function filter_item_list( $items, $args ) { * * ## OPTIONS * - * <plugin|zip|url> + * <plugin|zip|url>... * : A plugin slug, the path to a local zip file, or URL to a remote zip file. * - * --version=<version> + * [--version=<version>] * : If set, get that particular version from wordpress.org, instead of the * stable version. * - * --force + * [--force] * : If set, the command will overwrite any installed version of the plugin, without prompting * for confirmation. * - * --activate + * [--activate] * : If set, the plugin will be activated immediately after install. * * ## EXAMPLES @@ -377,8 +363,6 @@ protected function filter_item_list( $items, $args ) { * * # Install from a remote zip file * wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef - * - * @synopsis <plugin|zip|url>... [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); @@ -389,18 +373,16 @@ function install( $args, $assoc_args ) { * * ## OPTIONS * - * <plugin> - * : The plugin to uninstall. + * <plugin>... + * : One or more plugins to uninstall. * - * --no-delete + * [--no-delete] * : If set, the plugin files will not be deleted. Only the uninstall procedure * will be run. * * ## EXAMPLES * * wp plugin uninstall hello - * - * @synopsis <plugin>... [--no-delete] */ function uninstall( $args, $assoc_args = array() ) { foreach ( $this->validate_plugin_names( $args ) as $plugin ) { @@ -430,7 +412,6 @@ function uninstall( $args, $assoc_args = array() ) { * wp plugin is-installed hello * * @subcommand is-installed - * @synopsis <plugin> */ function is_installed( $args, $assoc_args = array() ) { if ( $this->_parse_name( $args[0] ) ) { @@ -445,14 +426,12 @@ function is_installed( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <plugin> - * : The plugin to delete. + * <plugin>... + * : One or more plugins to delete. * * ## EXAMPLES * * wp plugin delete hello - * - * @synopsis <plugin>... */ function delete( $args, $assoc_args = array() ) { foreach ( $this->validate_plugin_names( $args ) as $plugin ) { @@ -467,16 +446,14 @@ function delete( $args, $assoc_args = array() ) { * * ## OPTIONS * - * * `--format`=<format>: - * - * Output list as table, CSV or JSON. Defaults to table. + * [--format=<format>] + * : Output list as table, CSV or JSON. Defaults to table. * * ## EXAMPLES * * wp plugin list --format=json * * @subcommand list - * @synopsis [--format=<format>] */ function _list( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php index 31cf7572c..be99bd813 100644 --- a/php/commands/post-meta.php +++ b/php/commands/post-meta.php @@ -5,7 +5,7 @@ * * ## OPTIONS * - * --format=json + * [--format=json] * : Encode/decode values as JSON. * * ## EXAMPLES diff --git a/php/commands/post.php b/php/commands/post.php index c14887e17..5b8a73467 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -22,23 +22,23 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { * * ## OPTIONS * - * <filename> + * [<filename>] * : Read post content from <filename>. If this value is present, the * `--post_content` argument will be ignored. * * Passing `-` as the filename will cause post content to * be read from STDIN. * - * --<field>=<value> - * : Field values for the new post. See wp_insert_post(). + * [--<field>=<value>] + * : Associative args for the new post. See wp_insert_post(). * - * --edit + * [--edit] * : Immediately open system's editor to write or edit post content. * * If content is read from a file, from STDIN, or from the `--post_content` * argument, that text will be loaded into the editor. * - * --porcelain + * [--porcelain] * : Output just the new post id. * * ## EXAMPLES @@ -46,8 +46,6 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { * wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' * * wp post create page.txt --post_type=page --post_title='Page from file' - * - * @synopsis [<filename>] --<field>=<value> [--edit] [--porcelain] */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { @@ -85,8 +83,8 @@ protected function _create( $params ) { * * ## OPTIONS * - * <ID> - * : The ID of the post to update. + * <id>... + * : One or more IDs of posts to update. * * --<field>=<value> * : One or more fields to update. See wp_update_post(). @@ -94,8 +92,6 @@ protected function _create( $params ) { * ## EXAMPLES * * wp post update 123 --post_name=something --post_status=draft - * - * @synopsis <id>... --<field>=<value> */ public function update( $args, $assoc_args ) { parent::update( $args, $assoc_args ); @@ -116,8 +112,6 @@ protected function _update( $params ) { * ## EXAMPLES * * wp post edit 123 - * - * @synopsis <id> */ public function edit( $args, $_ ) { $post_id = $args[0]; @@ -144,7 +138,7 @@ protected function _edit( $content, $title ) { * <id> * : The ID of the post to get. * - * --format=<format> + * [--format=<format>] * : The format to use when printing the post, acceptable values: * * - **content**: Outputs only the post's content. @@ -159,8 +153,6 @@ protected function _edit( $content, $title ) { * wp post get 12 --format=content * * wp post get 12 > file.txt - * - * @synopsis <id> [--format=<format>] */ public function get( $args, $assoc_args ) { $defaults = array( @@ -202,10 +194,10 @@ public function get( $args, $assoc_args ) { * * ## OPTIONS * - * <ID> - * : The ID of the post to delete. + * <id>... + * : One or more IDs of posts to delete. * - * --force + * [--force] * : Skip the trash bin. * * ## EXAMPLES @@ -213,8 +205,6 @@ public function get( $args, $assoc_args ) { * wp post delete 123 --force * * wp post delete $(wp post list --post_type='page' --format=ids) - * - * @synopsis <id>... [--force] */ public function delete( $args, $assoc_args ) { $defaults = array( @@ -242,13 +232,13 @@ protected function _delete( $post_id, $assoc_args ) { * * ## OPTIONS * - * --<field>=<value> + * [--<field>=<value>] * : One or more args to pass to WP_Query. * - * --fields=<fields> + * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. * - * --format=<format> + * [--format=<format>] * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. * * ## EXAMPLES @@ -260,7 +250,6 @@ protected function _delete( $post_id, $assoc_args ) { * wp post list --post_type=page --fields=post_title,post_status * * @subcommand list - * @synopsis [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $_, $assoc_args ) { $query_args = array( @@ -293,29 +282,27 @@ public function _list( $_, $assoc_args ) { * * ## OPTIONS * - * --count=<number> + * [--count=<number>] * : How many posts to generate. Default: 100 * - * --post_type=<type> + * [--post_type=<type>] * : The type of the generated posts. Default: 'post' * - * --post_status=<status> + * [--post_status=<status>] * : The status of the generated posts. Default: 'publish' * - * --post_author=<login> + * [--post_author=<login>] * : The author of the generated posts. Default: none * - * --post_date=<yyyy-mm-dd> + * [--post_date=<yyyy-mm-dd>] * : The date of the generated posts. Default: current date * - * --max_depth=<number> + * [--max_depth=<number>] * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 * * ## EXAMPLES * * wp post generate --count=10 --post_type=page --post_date=1999-01-04 - * - * @synopsis [--count=<number>] [--post_type=<type>] [--post_status=<status>] [--post_author=<login>] [--post_date=<yyyy-mm-dd>] [--max_depth=<number>] */ public function generate( $args, $assoc_args ) { global $wpdb; diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 1d3e16f7c..bf6616425 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -12,10 +12,8 @@ class Rewrite_Command extends WP_CLI_Command { * * ## OPTIONS * - * --hard + * [--hard] * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. - * - * @synopsis [--hard] */ public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config @@ -31,17 +29,18 @@ public function flush( $args, $assoc_args ) { * <permastruct> * : The new permalink structure to apply. * - * --category-base=<categorybase> + * [--category-base=<base>] * : Set the base for category permalinks, i.e. '/category/'. * - * --tag-base=<tagbase> + * [--tag-base=<base>] * : Set the base for tag permalinks, i.e. '/tag/'. * + * [--hard] + * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. + * * ## EXAMPLES * * wp rewrite structure '/%year%/%monthnum%/%postname%' - * - * @synopsis <permastruct> [--category-base=<base>] [--tag-base=<base>] [--hard] */ public function structure( $args, $assoc_args ) { global $wp_rewrite; @@ -94,10 +93,12 @@ public function structure( $args, $assoc_args ) { * * ## OPTIONS * - * --format=json - * : Output rules in JSON format. + * [--format=<format>] + * : Output list as JSON. Defaults to tab-separated lines. + * + * ## EXAMPLES * - * @synopsis [--format=<format>] + * wp rewrite dump --format=json */ public function dump( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); diff --git a/php/commands/role.php b/php/commands/role.php index 9259875e4..78a5fbdaf 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -17,10 +17,10 @@ class Role_Command extends WP_CLI_Command { * * ## OPTIONS * - * --fields=<fields> + * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to name,role. * - * --format=<format> + * [--format=<format>] * : Output list as table, CSV or JSON. Defaults to table. * * ## EXAMPLES @@ -28,7 +28,6 @@ class Role_Command extends WP_CLI_Command { * wp role list --fields=role --format=csv * * @subcommand list - * @synopsis [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { global $wp_roles; @@ -64,15 +63,12 @@ public function _list( $args, $assoc_args ) { * * ## OPTIONS * - * * <role-key>: - * - * The internal name of the role, e.g. editor + * <role-key> + * : The internal name of the role. * * ## EXAMPLES * * wp role exists editor - * - * @synopsis <role-key> */ public function exists( $args ) { global $wp_roles; @@ -80,7 +76,7 @@ public function exists( $args ) { if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { WP_CLI::error( "Role with ID $args[0] does not exist." ); } - + WP_CLI::success( "Role with ID $args[0] exists." ); } @@ -89,21 +85,17 @@ public function exists( $args ) { * * ## OPTIONS * - * * <role-key>: - * - * The internal name of the role, e.g. editor - * - * * <role-name>: + * <role-key> + * : The internal name of the role. * - * The publically visible name of the role, e.g. Editor + * <role-name> + * : The publicly visible name of the role. * * ## EXAMPLES * * wp role create approver Approver * * wp role create productadmin "Product Administrator" - * - * @synopsis <role-key> <role-name> */ public function create( $args ) { self::persistence_check(); @@ -125,20 +117,16 @@ public function create( $args ) { * * ## OPTIONS * - * * <role-key>: - * - * The internal name of the role, e.g. editor + * <role-key> + * : The internal name of the role. * * ## EXAMPLES * * wp role delete approver * * wp role delete productadmin - * - * @synopsis <role-key> */ public function delete( $args ) { - global $wp_roles; self::persistence_check(); diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index af10af5fb..5e7ba7269 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -18,28 +18,28 @@ function __construct() { * * ## OPTIONS * - * --label=<label> + * <slug> + * : The internal name of the post type. + * + * [--label=<label>] * : The text used to translate the update messages * - * --textdomain=<textdomain> + * [--textdomain=<textdomain>] * : The textdomain to use for the labels. * - * --theme + * [--theme] * : Create a file in the active theme directory, instead of sending to * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. * - * --plugin=<plugin> - * : Create a file in the given plugin's directory, instead of sending to - * STDOUT. + * [--plugin=<plugin>] + * : Create a file in the given plugin's directory, instead of sending to STDOUT. * - * --raw + * [--raw] * : Just generate the `register_post_type()` call and nothing else. * * @subcommand post-type * * @alias cpt - * - * @synopsis <slug> [--label=<label>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function post_type( $args, $assoc_args ) { $defaults = array( @@ -57,24 +57,26 @@ function post_type( $args, $assoc_args ) { * * ## OPTIONS * - * --post_types=<post_types> + * <slug> + * : The internal name of the taxonomy. + * + * [--post_types=<post-types>] * : Post types to register for use with the taxonomy. * - * --label=<label> + * [--label=<label>] * : The text used to translate the update messages * - * --textdomain=<textdomain> + * [--textdomain=<textdomain>] * : The textdomain to use for the labels. * - * --theme + * [--theme] * : Create a file in the active theme directory, instead of sending to * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. * - * --plugin=<plugin> - * : Create a file in the given plugin's directory, instead of sending to - * STDOUT. + * [--plugin=<plugin>] + * : Create a file in the given plugin's directory, instead of sending to STDOUT. * - * --raw + * [--raw] * : Just generate the `register_taxonomy()` call and nothing else. * * ## EXAMPLES @@ -84,8 +86,6 @@ function post_type( $args, $assoc_args ) { * @subcommand taxonomy * * @alias tax - * - * @synopsis <slug> [--post_types=<post-types>] [--label=<label>] [--textdomain=<textdomain>] [--theme] [--plugin=<plugin>] [--raw] */ function taxonomy( $args, $assoc_args ) { $defaults = array( @@ -164,19 +164,17 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * <slug> * : The slug for the new theme, used for prefixing functions. * - * --activate + * [--activate] * : Activate the newly downloaded theme. * - * --theme_name=<title> + * [--theme_name=<title>] * : What to put in the 'Theme Name:' header in style.css * - * --author=<full name> + * [--author=<full-name>] * : What to put in the 'Author:' header in style.css * - * --author_uri=<http url> + * [--author_uri=<uri>] * : What to put in the 'Author URI:' header in style.css - * - * @synopsis <slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--activate] */ function _s( $args, $assoc_args ) { @@ -226,24 +224,22 @@ function _s( $args, $assoc_args ) { * --parent_theme=<slug> * : What to put in the 'Template:' header in style.css * - * --theme_name=<title> + * [--theme_name=<title>] * : What to put in the 'Theme Name:' header in style.css * - * --author=<full name> + * [--author=<full-name>] * : What to put in the 'Author:' header in style.css * - * --author_uri=<http url> + * [--author_uri=<uri>] * : What to put in the 'Author URI:' header in style.css * - * --theme_uri=<http url> + * [--theme_uri=<uri>] * : What to put in the 'Theme URI:' header in style.css * - * --activate + * [--activate] * : Activate the newly created child theme. * * @subcommand child-theme - * - * @synopsis <slug> --parent_theme=<slug> [--theme_name=<title>] [--author=<full-name>] [--author_uri=<http-url>] [--theme_uri=<http-url>] [--activate] */ function child_theme( $args, $assoc_args ) { $theme_slug = $args[0]; @@ -295,13 +291,14 @@ private function get_output_path( $assoc_args, $subdir ) { * * ## OPTIONS * - * --activate + * <slug> + * : The internal name of the plugin. + * + * [--activate] * : Activate the newly generated plugin. * - * --plugin_name=<title> + * [--plugin_name=<title>] * : What to put in the 'Plugin Name:' header - * - * @synopsis <slug> [--plugin_name=<title>] [--activate] */ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; @@ -342,13 +339,16 @@ function plugin( $args, $assoc_args ) { * The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment * variable. * + * ## OPTIONS + * + * <plugin> + * : The name of the plugin to generate test files for. + * * ## EXAMPLE * * wp scaffold plugin-tests hello * * @subcommand plugin-tests - * - * @synopsis <plugin> */ function plugin_tests( $args, $assoc_args ) { global $wp_filesystem; diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7cbb52019..c7e80dac3 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -18,13 +18,22 @@ class Search_Replace_Command extends WP_CLI_Command { * * ## OPTIONS * - * --network + * <old> + * : The old string. + * + * <new> + * : The new string. + * + * [<table>...] + * : List of database tables to restrict the replacement to. + * + * [--network] * : Search/replace through all the tables in a multisite install. * - * --skip-columns=<columns> + * [--skip-columns=<columns>] * : Do not perform the replacement in the comma-separated columns. * - * --dry-run + * [--dry-run] * : Show report, but don't perform the changes. * * ## EXAMPLES @@ -32,8 +41,6 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run - * - * @synopsis <old> <new> [<table>...] [--skip-columns=<columns>] [--dry-run] [--network] */ public function __invoke( $args, $assoc_args ) { $old = array_shift( $args ); diff --git a/php/commands/shell.php b/php/commands/shell.php index ee95860e6..82b96484d 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -11,10 +11,8 @@ class Shell_Command extends \WP_CLI_Command { * * ## OPTIONS * - * --basic + * [--basic] * : Start in fail-safe mode, even if Boris is available. - * - * @synopsis [--basic] */ public function __invoke( $_, $assoc_args ) { $implementations = array( diff --git a/php/commands/site.php b/php/commands/site.php index 954274842..9a49c69c1 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -112,11 +112,10 @@ private function _insert_default_terms() { * * ## OPTIONS * - * --yes + * [--yes] * : Proceed to empty the site without a confirmation prompt. * * @subcommand empty - * @synopsis [--yes] */ public function _empty( $args, $assoc_args ) { @@ -135,19 +134,17 @@ public function _empty( $args, $assoc_args ) { * * ## OPTIONS * - * <blog-id> - * : The id of the blog to delete. If not provided, you must set the --slug parameter. + * [<site-id>] + * : The id of the site to delete. If not provided, you must set the --slug parameter. * - * --slug=<slug> + * [--slug=<slug>] * : Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. * - * --yes + * [--yes] * : Answer yes to the confirmation message. * - * --keep-tables + * [--keep-tables] * : Delete the blog from the list, but don't drop it's tables. - * - * @synopsis [<site-id>] [--slug=<slug>] [--yes] [--keep-tables] */ function delete( $args, $assoc_args ) { if ( !is_multisite() ) { @@ -324,13 +321,13 @@ public function create( $_, $assoc_args ) { * * ## OPTIONS * - * --network=<id> + * [--network=<id>] * : The network to which the sites belong. * - * --fields=<fields> + * [--fields=<fields>] * : Comma-separated list of fields to show. * - * --format=<format> + * [--format=<format>] * : Output list as table, csv, json or url. Defaults to table. * * ## EXAMPLES @@ -339,7 +336,6 @@ public function create( $_, $assoc_args ) { * wp site list --fields=url --format=csv | tail -n +2 * * @subcommand list - * @synopsis [--network=<id>] [--format=<format>] [--fields=<fields>] */ function _list( $_, $assoc_args ) { if ( !is_multisite() ) { diff --git a/php/commands/term.php b/php/commands/term.php index 415feb5d3..bcf58ac44 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -23,14 +23,14 @@ class Term_Command extends WP_CLI_Command { * * <taxonomy> * : List terms of a given taxonomy. - * - * --<field>=<value> + * + * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_terms(). * - * --fields=<fields> + * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to all of the term object fields. * - * --format=<format> + * [--format=<format>] * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. * * ## EXAMPLES @@ -40,7 +40,6 @@ class Term_Command extends WP_CLI_Command { * wp term list post_tag --fields=name,slug * * @subcommand list - * @synopsis <taxonomy> [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -75,23 +74,21 @@ public function _list( $args, $assoc_args ) { * <taxonomy> * : Taxonomy for the new term. * - * --slug=<slug> + * [--slug=<slug>] * : A unique slug for the new term. Defaults to sanitized version of name. * - * --description=<description> + * [--description=<description>] * : A description for the new term. * - * --parent=<term-id> + * [--parent=<term-id>] * : A parent for the new term. * - * --porcelain + * [--porcelain] * : Output just the new term id. * * ## EXAMPLES * * wp term create Apple category --description="A type of fruit" - * - * @synopsis <term> <taxonomy> [--slug=<slug>] [--description=<description>] [--parent=<term-id>] [--porcelain] */ public function create( $args, $assoc_args ) { @@ -125,27 +122,24 @@ public function create( $args, $assoc_args ) { /** * Get a taxonomy term - * + * * ## OPTIONS * * <term-id> * : ID of the term to get - * + * * <taxonomy> * : Taxonomy of the term to get - * - * --format=<format> + * + * [--format=<format>] * : The format to use when printing the term, acceptable values: * * - **table**: Outputs all fields of the term as a table. - * * - **json**: Outputs all fields in JSON format. - * + * * ## EXAMPLES * - * wp term get 1 category - * - * @synopsis <term-id> <taxonomy> [--format=<format>] + * wp term get 1 category --format=json */ public function get( $args, $assoc_args ) { @@ -188,23 +182,21 @@ public function get( $args, $assoc_args ) { * <taxonomy> * : Taxonomy of the term to update. * - * --name=<name> + * [--name=<name>] * : A new name for the term. * - * --slug=<slug> + * [--slug=<slug>] * : A new slug for the term. * - * --description=<description> + * [--description=<description>] * : A new description for the term. * - * --parent=<term-id> + * [--parent=<term-id>] * : A new parent for the term. * * ## EXAMPLES * * wp term update 15 category --name=Apple - * - * @synopsis <term-id> <taxonomy> [--name=<name>] [--slug=<slug>] [--description=<description>] [--parent=<term-id>] */ public function update( $args, $assoc_args ) { @@ -245,8 +237,6 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * wp term delete 15 category - * - * @synopsis <term-id> <taxonomy> */ public function delete( $args ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 4a8293b82..7f23b4278 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -27,10 +27,8 @@ protected function get_upgrader_class( $force ) { * * ## OPTIONS * - * <theme> + * [<theme>] * : A particular theme to show the status for. - * - * @synopsis [<theme>] */ function status( $args ) { parent::status( $args ); @@ -44,11 +42,11 @@ function status( $args ) { * <search> * : The string to search for. * - * --per-page + * [--per-page=<per-page>] * : Optional number of results to display. Defaults to 10. * - * --fields - * : Ask for specific fields from the API. Defaults to name,slug,author,rating. acceptable values: + * [--fields=<fields>] + * : Ask for specific fields from the API. Defaults to name,slug,author,rating. Acceptable values: * * **name**: Theme Name * **slug**: Theme Slug @@ -66,8 +64,6 @@ function status( $args ) { * wp theme search automattic --per-page=20 * * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description - * - * @synopsis <search> [--per-page=<per-page>] [--fields=<fields>] */ public function search( $args, $assoc_args = array() ) { $term = $args[0]; @@ -119,8 +115,6 @@ protected function get_status( $theme ) { * * <theme> * : The theme to activate. - * - * @synopsis <theme> */ public function activate( $args = array() ) { $theme = $this->parse_name( $args[0] ); @@ -145,19 +139,17 @@ private function is_active_theme( $theme ) { * * ## OPTIONS * - * <theme> + * [<theme>] * : The theme to get the path to. Path includes "style.css" file. * If not set, will return the path to the themes directory. * - * --dir + * [--dir] * : If set, get the path to the closest parent directory, instead of the * theme's "style.css" file. * * ## EXAMPLES * * cd $(wp theme path) - * - * @synopsis [<theme>] [--dir] */ public function path( $args, $assoc_args ) { if ( empty( $args ) ) { @@ -228,14 +220,18 @@ protected function filter_item_list( $items, $args ) { * * ## OPTIONS * - * <theme|zip|url> + * <theme|zip|url>... * : A theme slug, the path to a local zip file, or URL to a remote zip file. * - * --force + * [--version=<version>] + * : If set, get that particular version from wordpress.org, instead of the + * stable version. + * + * [--force] * : If set, the command will overwrite any installed version of the theme, without prompting * for confirmation. * - * --activate + * [--activate] * : If set, the theme will be activated immediately after install. * * ## EXAMPLES @@ -248,8 +244,6 @@ protected function filter_item_list( $items, $args ) { * * # Install from a remote zip file * wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef - * - * @synopsis <theme|zip|url>... [--version=<version>] [--force] [--activate] */ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); @@ -263,21 +257,14 @@ function install( $args, $assoc_args ) { * <theme> * : The theme to get. * - * * --format=<format> - * : The format to use when printing the theme, acceptable values: - * - * - **table**: Outputs all fields of the theme as a table. - * - * - **json**: Outputs all fields in JSON format. + * [--format=<format>] + * : Output list as table or JSON. Defaults to table. * * ## EXAMPLES * - * wp theme get twentytwelve - * - * @synopsis <theme> [--format=<format>] + * wp theme get twentytwelve --format=json */ public function get( $args, $assoc_args ) { - $defaults = array( 'format' => 'table' ); @@ -316,17 +303,17 @@ public function get( $args, $assoc_args ) { * * ## OPTIONS * - * <theme> - * : The theme(s) to update. + * [<theme>...] + * : One or more themes to update. * - * --all + * [--all] * : If set, all themes that have updates will be updated. * - * --version=dev + * [--version=<version>] * : If set, the theme will be updated to the latest development version, * regardless of what version is currently installed. * - * --dry-run + * [--dry-run] * : Preview which themes would be updated. * * ## EXAMPLES @@ -334,8 +321,6 @@ public function get( $args, $assoc_args ) { * wp theme update twentyeleven twentytwelve * * wp theme update --all - * - * @synopsis [<theme>...] [--version=<version>] [--all] [--dry-run] */ function update( $args, $assoc_args ) { parent::update_many( $args, $assoc_args ); @@ -352,8 +337,6 @@ function update( $args, $assoc_args ) { * ## EXAMPLES * * wp theme delete twentyeleven - * - * @synopsis <theme> */ function delete( $args ) { $theme = $this->parse_name( $args[0] ); @@ -377,16 +360,14 @@ function delete( $args ) { * * ## OPTIONS * - * * `--format`=<format>: - * - * Output list as table, CSV or JSON. Defaults to table. + * [--format=<format>] + * : Output list as table, CSV or JSON. Defaults to table. * * ## EXAMPLES * * wp theme list --format=csv * * @subcommand list - * @synopsis [--format=<format>] */ function _list( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); @@ -408,7 +389,6 @@ private function parse_name( $name ) { return $theme; } - } WP_CLI::add_command( 'theme', 'Theme_Command' ); diff --git a/php/commands/user.php b/php/commands/user.php index 9674f5e9f..5a0abe55f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -23,16 +23,16 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * * ## OPTIONS * - * --role=<role> + * [--role=<role>] * : Only display users with a certain role. - * - * * --<field>=<value> + * + * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_users(). * - * --fields=<fields> + * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles * - * --format=<format> + * [--format=<format>] * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. * * ## EXAMPLES @@ -44,7 +44,6 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * wp user list --fields=display_name,user_email * * @subcommand list - * @synopsis [--role=<role>] [--<field>=<value>] [--fields=<fields>] [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -89,7 +88,7 @@ public function _list( $args, $assoc_args ) { * <user> * : User ID or user login. * - * --format=<format> + * [--format=<format>] * : The format to use when printing the user; acceptable values: * * **table**: Outputs all fields of the user as a table. @@ -101,8 +100,6 @@ public function _list( $args, $assoc_args ) { * wp user get 12 * * wp user get bob --format=json > bob.json - * - * @synopsis <user> [--format=<format>] */ public function get( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( @@ -141,17 +138,15 @@ public function get( $args, $assoc_args ) { * * ## OPTIONS * - * <user> - * : The user login or ID of the user to delete. + * <user>... + * : The user login or ID of the user(s) to update. * - * --reassign=<ID> - * : User to reassign the posts to. + * [--reassign=<user-id>] + * : User ID to reassign the posts to. * * ## EXAMPLES * * wp user delete 123 --reassign=567 - * - * @synopsis <user>... [--reassign=<id>] */ public function delete( $args, $assoc_args ) { $assoc_args = wp_parse_args( $assoc_args, array( @@ -189,26 +184,24 @@ protected function _delete( $user_id, $assoc_args ) { * <user-email> * : The email address of the user to create. * - * --role=<role> + * [--role=<role>] * : The role of the user to create. Default: default role * - * --user_pass=<password> + * [--user_pass=<password>] * : The user password. Default: randomly generated * - * --user_registered=<yyyy-mm-dd> + * [--user_registered=<yyyy-mm-dd>] * : The date the user registered. Default: current date * - * --display_name=<name> + * [--display_name=<name>] * : The display name. * - * --porcelain + * [--porcelain] * : Output just the new user id. * * ## EXAMPLES * * wp user create bob bob@example.com --role=author - * - * @synopsis <user-login> <user-email> [--role=<role>] [--user_pass=<password>] [--user_registered=<yyyy-mm-dd>] [--display_name=<name>] [--porcelain] */ public function create( $args, $assoc_args ) { list( $user_login, $user_email ) = $args; @@ -269,8 +262,8 @@ protected function _create( $params ) { * * ## OPTIONS * - * <user> - * : The user login or ID of the user to update. + * <user>... + * : The user login or ID of the user(s) to update. * * --<field>=<value> * : One or more fields to update. For accepted fields, see wp_update_user(). @@ -280,8 +273,6 @@ protected function _create( $params ) { * wp user update 123 --user_login=mary --display_name=Mary * * wp user update mary --user_pass=marypass - * - * @synopsis <user>... --<field>=<value> */ public function update( $args, $assoc_args ) { @@ -300,13 +291,11 @@ protected function _update( $params ) { * * ## OPTIONS * - * --count=<number> + * [--count=<number>] * : How many users to generate. Default: 100 * - * --role=<role> + * [--role=<role>] * : The role of the generated users. Default: default role from WP - * - * @synopsis [--count=<number>] [--role=<role>] */ public function generate( $args, $assoc_args ) { global $blog_id; @@ -374,7 +363,6 @@ public function generate( $args, $assoc_args ) { * wp user set-role 12 author * * @subcommand set-role - * @synopsis <user> [<role>] */ public function set_role( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -407,7 +395,6 @@ public function set_role( $args, $assoc_args ) { * wp user add-role 12 author * * @subcommand add-role - * @synopsis <user> <role> */ public function add_role( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -427,13 +414,15 @@ public function add_role( $args, $assoc_args ) { * <user> * : User ID or user login. * + * [<role>] + * : A specific role to remove. + * * ## EXAMPLES * * wp user remove-role bob - * wp user remove-role 12 + * wp user remove-role 12 editor * * @subcommand remove-role - * @synopsis <user> [<role>] */ public function remove_role( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -464,7 +453,7 @@ public function remove_role( $args, $assoc_args ) { * : User ID or user login. * * <cap> - * : Add the specified capability for the user. + * : The capability to add. * * ## EXAMPLES * @@ -472,7 +461,6 @@ public function remove_role( $args, $assoc_args ) { * wp user add-cap 15 edit_product * * @subcommand add-cap - * @synopsis <user> <cap> */ public function add_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -493,7 +481,7 @@ public function add_cap( $args, $assoc_args ) { * : User ID or user login. * * <cap> - * : Capability to be removed. + * : The capability to be removed. * * ## EXAMPLES * @@ -501,7 +489,6 @@ public function add_cap( $args, $assoc_args ) { * wp user remove-cap 11 publish_newsletters * * @subcommand remove-cap - * @synopsis <user> <cap> */ public function remove_cap( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -519,7 +506,7 @@ public function remove_cap( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID or login. * * ## EXAMPLES * @@ -527,7 +514,6 @@ public function remove_cap( $args, $assoc_args ) { * wp user list-caps 21 * * @subcommand list-caps - * @synopsis <user> */ public function list_caps( $args, $assoc_args ) { $user = self::get_user( $args[0] ); @@ -579,7 +565,6 @@ private static function get_user( $id_or_login ) { * existinguser,existinguser@domain.com,Existing User,administrator * * @subcommand import-csv - * @synopsis <file> */ public function import_csv( $args, $assoc_args ) { From d1eeb09a959c62ef946a11f4e9b22f0171edfa5f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 16 Sep 2013 01:38:08 +0300 Subject: [PATCH 2289/5359] rename some variables, for clarity. --- php/WP_CLI/Dispatcher/Subcommand.php | 10 ++++---- php/WP_CLI/SynopsisValidator.php | 5 ++-- tests/test-arg-validation.php | 34 ++++++++++++++-------------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index e51f1f702..7e528c145 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -152,22 +152,22 @@ private function validate_args( $args, &$assoc_args ) { if ( !$synopsis ) return; - $parser = new \WP_CLI\SynopsisValidator( $synopsis ); + $validator = new \WP_CLI\SynopsisValidator( $synopsis ); $cmd_path = implode( ' ', get_path( $this ) ); - foreach ( $parser->get_unknown() as $token ) { + foreach ( $validator->get_unknown() as $token ) { \WP_CLI::warning( sprintf( "The `%s` command has an invalid synopsis part: %s", $cmd_path, $token ) ); } - if ( !$parser->enough_positionals( $args ) ) { + if ( !$validator->enough_positionals( $args ) ) { $this->show_usage(); exit(1); } - $errors = $parser->validate_assoc( $assoc_args, array_keys( \WP_CLI::get_config() ) ); + $errors = $validator->validate_assoc( $assoc_args, array_keys( \WP_CLI::get_config() ) ); if ( !empty( $errors['fatal'] ) ) { $out = 'Parameter errors:'; @@ -180,7 +180,7 @@ private function validate_args( $args, &$assoc_args ) { array_map( '\\WP_CLI::warning', $errors['warning'] ); - foreach ( $parser->unknown_assoc( $assoc_args ) as $key ) { + foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { \WP_CLI::warning( "unknown --$key parameter" ); } } diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 300dd67a4..c4490bd78 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -28,8 +28,9 @@ public function enough_positionals( $args ) { return count( $args ) >= count( $positional ); } + // Checks that all required keys are present and that they have values. public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { - $assoc = $this->query_spec( array( + $assoc_spec = $this->query_spec( array( 'type' => 'assoc', ) ); @@ -38,7 +39,7 @@ public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { 'warning' => array() ); - foreach ( $assoc as $param ) { + foreach ( $assoc_spec as $param ) { $key = $param['name']; if ( in_array( $key, $ignored_keys ) ) diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php index e1c74b822..3d1a2fa10 100644 --- a/tests/test-arg-validation.php +++ b/tests/test-arg-validation.php @@ -5,53 +5,53 @@ class ArgValidationTests extends PHPUnit_Framework_TestCase { function testMissingPositional() { - $parser = new SynopsisValidator( '<foo> <bar> [<baz>]' ); + $validator = new SynopsisValidator( '<foo> <bar> [<baz>]' ); - $this->assertFalse( $parser->enough_positionals( array() ) ); - $this->assertTrue( $parser->enough_positionals( array( 1, 2 ) ) ); - $this->assertTrue( $parser->enough_positionals( array( 1, 2, 3, 4 ) ) ); + $this->assertFalse( $validator->enough_positionals( array() ) ); + $this->assertTrue( $validator->enough_positionals( array( 1, 2 ) ) ); + $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3, 4 ) ) ); } function testRepeatingPositional() { - $parser = new SynopsisValidator( '<foo> [<bar>...]' ); + $validator = new SynopsisValidator( '<foo> [<bar>...]' ); - $this->assertFalse( $parser->enough_positionals( array() ) ); - $this->assertTrue( $parser->enough_positionals( array( 1 ) ) ); - $this->assertTrue( $parser->enough_positionals( array( 1, 2, 3 ) ) ); + $this->assertFalse( $validator->enough_positionals( array() ) ); + $this->assertTrue( $validator->enough_positionals( array( 1 ) ) ); + $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3 ) ) ); } function testUnknownAssocEmpty() { - $parser = new SynopsisValidator( '' ); + $validator = new SynopsisValidator( '' ); $assoc_args = array( 'foo' => true, 'bar' => false ); - $this->assertEquals( array_keys( $assoc_args ), $parser->unknown_assoc( $assoc_args ) ); + $this->assertEquals( array_keys( $assoc_args ), $validator->unknown_assoc( $assoc_args ) ); } function testUnknownAssoc() { - $parser = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); + $validator = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); $assoc_args = array( 'type' => 'analog', 'brand' => true, 'flag' => true ); - $this->assertEmpty( $parser->unknown_assoc( $assoc_args ) ); + $this->assertEmpty( $validator->unknown_assoc( $assoc_args ) ); $assoc_args['another'] = true; - $this->assertContains( 'another', $parser->unknown_assoc( $assoc_args ) ); + $this->assertContains( 'another', $validator->unknown_assoc( $assoc_args ) ); } function testMissingAssoc() { - $parser = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); + $validator = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); $assoc_args = array( 'brand' => true, 'flag' => true ); - $errors = $parser->validate_assoc( $assoc_args ); + $errors = $validator->validate_assoc( $assoc_args ); $this->assertCount( 1, $errors['fatal'] ); $this->assertCount( 1, $errors['warning'] ); } function testAssocWithOptionalValue() { - $parser = new SynopsisValidator( '[--network[=<id>]]' ); + $validator = new SynopsisValidator( '[--network[=<id>]]' ); $assoc_args = array( 'network' => true ); - $errors = $parser->validate_assoc( $assoc_args ); + $errors = $validator->validate_assoc( $assoc_args ); $this->assertCount( 0, $errors['fatal'] ); $this->assertCount( 0, $errors['warning'] ); From d2d9f5ba3c38e756d81c1039e4167b61d38f38ed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 16 Sep 2013 02:13:48 +0300 Subject: [PATCH 2290/5359] add test that catches #663 --- features/core.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/core.feature b/features/core.feature index 0d2a8456e..07849eda6 100644 --- a/features/core.feature +++ b/features/core.feature @@ -90,6 +90,13 @@ Feature: Manage WordPress installation Run `wp core install`. """ + When I try `wp core install` + Then the return code should be 1 + And STDERR should contain: + """ + missing --url parameter + """ + When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty From 0486d2b7adab67b2015a32e9fae09b73db87152c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 16 Sep 2013 02:06:14 +0300 Subject: [PATCH 2291/5359] instead of ignoring them, pass config values along with regular assoc args to validate_assoc() --- php/WP_CLI/Dispatcher/Subcommand.php | 6 +++++- php/WP_CLI/SynopsisValidator.php | 11 +++++------ php/commands/core.php | 2 +- tests/test-arg-validation.php | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 7e528c145..6d36411d3 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -167,7 +167,7 @@ private function validate_args( $args, &$assoc_args ) { exit(1); } - $errors = $validator->validate_assoc( $assoc_args, array_keys( \WP_CLI::get_config() ) ); + list( $errors, $to_unset ) = $validator->validate_assoc( array_merge( \WP_CLI::get_config(), $assoc_args ) ); if ( !empty( $errors['fatal'] ) ) { $out = 'Parameter errors:'; @@ -180,6 +180,10 @@ private function validate_args( $args, &$assoc_args ) { array_map( '\\WP_CLI::warning', $errors['warning'] ); + foreach ( $to_unset as $key ) { + unset( $assoc_args[ $key ] ); + } + foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { \WP_CLI::warning( "unknown --$key parameter" ); } diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index c4490bd78..ed67928ef 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -29,7 +29,7 @@ public function enough_positionals( $args ) { } // Checks that all required keys are present and that they have values. - public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { + public function validate_assoc( $assoc_args ) { $assoc_spec = $this->query_spec( array( 'type' => 'assoc', ) ); @@ -39,12 +39,11 @@ public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { 'warning' => array() ); + $to_unset = array(); + foreach ( $assoc_spec as $param ) { $key = $param['name']; - if ( in_array( $key, $ignored_keys ) ) - continue; - if ( !isset( $assoc_args[ $key ] ) ) { if ( !$param['optional'] ) { $errors['fatal'][] = "missing --$key parameter"; @@ -54,12 +53,12 @@ public function validate_assoc( &$assoc_args, $ignored_keys = array() ) { $error_type = ( !$param['optional'] ) ? 'fatal' : 'warning'; $errors[ $error_type ][] = "--$key parameter needs a value"; - unset( $assoc_args[ $key ] ); + $to_unset[] = $key; } } } - return $errors; + return array( $errors, $to_unset ); } public function unknown_assoc( $assoc_args ) { diff --git a/php/commands/core.php b/php/commands/core.php index 248f34d63..40c26a7cb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -298,7 +298,7 @@ public function multisite_convert( $args, $assoc_args ) { * * ## OPTIONS * - * --url=<url> + * [--url=<url>] * : The address of the new site. * * [--base=<url-path>] diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php index 3d1a2fa10..7db636a52 100644 --- a/tests/test-arg-validation.php +++ b/tests/test-arg-validation.php @@ -41,7 +41,7 @@ function testMissingAssoc() { $validator = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); $assoc_args = array( 'brand' => true, 'flag' => true ); - $errors = $validator->validate_assoc( $assoc_args ); + list( $errors, $to_unset ) = $validator->validate_assoc( $assoc_args ); $this->assertCount( 1, $errors['fatal'] ); $this->assertCount( 1, $errors['warning'] ); @@ -51,7 +51,7 @@ function testAssocWithOptionalValue() { $validator = new SynopsisValidator( '[--network[=<id>]]' ); $assoc_args = array( 'network' => true ); - $errors = $validator->validate_assoc( $assoc_args ); + list( $errors, $to_unset ) = $validator->validate_assoc( $assoc_args ); $this->assertCount( 0, $errors['fatal'] ); $this->assertCount( 0, $errors['warning'] ); From 510bd2c282bb6d7b06311b9820a401dcdc3023c3 Mon Sep 17 00:00:00 2001 From: LA Watts <luke@thisis.la> Date: Mon, 16 Sep 2013 05:20:26 +0100 Subject: [PATCH 2292/5359] Adds show_admin_column --- templates/taxonomy.mustache | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index f4431bf48..24f317c76 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -1,6 +1,7 @@ register_taxonomy( '{{slug}}', array( {{post_types}} ), array( 'hierarchical' => false, 'public' => true, + 'show_admin_column' => false, 'show_in_nav_menus' => true, 'show_ui' => true, 'query_var' => true, From 092f4a135c6eaf353a0d8a99cec2470766bc91d8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 16 Sep 2013 12:15:10 +0300 Subject: [PATCH 2293/5359] remove extra spaces in scaffold templates --- templates/post_type.mustache | 18 +++++++------- templates/taxonomy.mustache | 48 ++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 429e00226..cd242e053 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -1,13 +1,13 @@ register_post_type( '{{slug}}', array( - 'hierarchical' => false, - 'public' => true, - 'show_in_nav_menus' => true, - 'show_ui' => true, - 'supports' => array( 'title', 'editor' ), - 'has_archive' => true, - 'query_var' => true, - 'rewrite' => true, - 'labels' => array( + 'hierarchical' => false, + 'public' => true, + 'show_in_nav_menus' => true, + 'show_ui' => true, + 'supports' => array( 'title', 'editor' ), + 'has_archive' => true, + 'query_var' => true, + 'rewrite' => true, + 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), 'add_new' => __( 'Add new {{label}}', '{{textdomain}}' ), diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 24f317c76..911a6881c 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -1,32 +1,32 @@ register_taxonomy( '{{slug}}', array( {{post_types}} ), array( - 'hierarchical' => false, - 'public' => true, - 'show_admin_column' => false, - 'show_in_nav_menus' => true, - 'show_ui' => true, - 'query_var' => true, - 'rewrite' => true, - 'capabilities' => array( + 'hierarchical' => false, + 'public' => true, + 'show_in_nav_menus' => true, + 'show_ui' => true, + 'show_admin_column' => false, + 'query_var' => true, + 'rewrite' => true, + 'capabilities' => array( 'manage_terms' => 'edit_posts', 'edit_terms' => 'edit_posts', 'delete_terms' => 'edit_posts', 'assign_terms' => 'edit_posts' ), - 'labels' => array( - 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - 'singular_name' => _x( '{{label_ucfirst}}', 'taxonomy general name', '{{textdomain}}' ), - 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), - 'popular_items' => __( 'Popular {{label_plural}}', '{{textdomain}}' ), - 'all_items' => __( 'All {{label_plural}}', '{{textdomain}}' ), - 'parent_item' => __( 'Parent {{label}}', '{{textdomain}}' ), - 'parent_item_colon' => __( 'Parent {{label}}:', '{{textdomain}}' ), - 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), - 'update_item' => __( 'Update {{label}}', '{{textdomain}}' ), - 'add_new_item' => __( 'New {{label}}', '{{textdomain}}' ), - 'new_item_name' => __( 'New {{label}}', '{{textdomain}}' ), - 'separate_items_with_commas' => __( '{{label_plural_ucfirst}} separated by comma', '{{textdomain}}' ), - 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), - 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), - 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'labels' => array( + 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'singular_name' => _x( '{{label_ucfirst}}', 'taxonomy general name', '{{textdomain}}' ), + 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), + 'popular_items' => __( 'Popular {{label_plural}}', '{{textdomain}}' ), + 'all_items' => __( 'All {{label_plural}}', '{{textdomain}}' ), + 'parent_item' => __( 'Parent {{label}}', '{{textdomain}}' ), + 'parent_item_colon' => __( 'Parent {{label}}:', '{{textdomain}}' ), + 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), + 'update_item' => __( 'Update {{label}}', '{{textdomain}}' ), + 'add_new_item' => __( 'New {{label}}', '{{textdomain}}' ), + 'new_item_name' => __( 'New {{label}}', '{{textdomain}}' ), + 'separate_items_with_commas' => __( '{{label_plural_ucfirst}} separated by comma', '{{textdomain}}' ), + 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), + 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), + 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), ), ) ); From 7f43b89f915fddca980a4ffaab34ab1289322422 Mon Sep 17 00:00:00 2001 From: Andrey Savchenko <contact@rarst.net> Date: Tue, 17 Sep 2013 20:15:02 +0300 Subject: [PATCH 2294/5359] Trimmed whitespace on extracted synopsis lines Fixes #770 on Windows --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6d36411d3..208b90f1c 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -26,7 +26,7 @@ function __construct( $parent, $name, $docparser, $when_invoked ) { private static function extract_synopsis( $longdesc ) { preg_match_all( '/(.+)\n:/', $longdesc, $matches ); - return implode( ' ', $matches[1] ); + return implode( ' ', array_map( 'trim', $matches[1] ) ); } function get_synopsis() { From 679fd370fc8597cfd02e6d739587315739b6c8ae Mon Sep 17 00:00:00 2001 From: Andrey Savchenko <contact@rarst.net> Date: Wed, 18 Sep 2013 13:31:31 +0300 Subject: [PATCH 2295/5359] Refactored end of line trim of synopsis extraction into regex. --- php/WP_CLI/Dispatcher/Subcommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 208b90f1c..5d6145f37 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -25,8 +25,8 @@ function __construct( $parent, $name, $docparser, $when_invoked ) { } private static function extract_synopsis( $longdesc ) { - preg_match_all( '/(.+)\n:/', $longdesc, $matches ); - return implode( ' ', array_map( 'trim', $matches[1] ) ); + preg_match_all( '/(.+?)[\r\n]+:/', $longdesc, $matches ); + return implode( ' ', $matches[1] ); } function get_synopsis() { From 4002f0d18c1b41cdf21db50f42580fce6bc980dd Mon Sep 17 00:00:00 2001 From: Alex Ciobica <alex.ciobica@gmail.com> Date: Thu, 19 Sep 2013 18:14:27 +0300 Subject: [PATCH 2296/5359] Fix mysql environment issue. --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 1b3b1a6ce..7ef0475e0 100644 --- a/php/utils.php +++ b/php/utils.php @@ -424,7 +424,7 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); } - $env = array(); + $env = (array) $_ENV; if ( isset( $assoc_args['pass'] ) ) { $env['MYSQL_PWD'] = $assoc_args['pass']; unset( $assoc_args['pass'] ); From 5458bd5d4574f64f18ac90d798d713823e286aac Mon Sep 17 00:00:00 2001 From: Alex Ciobica <alex.ciobica@gmail.com> Date: Thu, 19 Sep 2013 18:14:49 +0300 Subject: [PATCH 2297/5359] Lint. --- php/utils.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 7ef0475e0..84289730e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -43,7 +43,7 @@ function load_command( $name ) { } function load_all_commands() { - $cmd_dir = WP_CLI_ROOT . "/php/commands"; + $cmd_dir = WP_CLI_ROOT . '/php/commands'; $iterator = new \DirectoryIterator( $cmd_dir ); @@ -217,7 +217,7 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria } elseif ( is_array( $data ) ) { - $_tmp = array( ); + $_tmp = array(); foreach ( $data as $key => $value ) { $_tmp[ $key ] = recursive_unserialize_replace( $from, $to, $value, false ); } @@ -311,7 +311,7 @@ function assoc_array_to_table( $fields ) { $rows = array(); foreach ( $fields as $field => $value ) { - if ( !is_string($value) ) { + if ( ! is_string( $value ) ) { $value = json_encode( $value ); } From 8e3202c23b3d5726d1eb9165443a9d004c2e14a9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 19 Sep 2013 23:18:49 +0300 Subject: [PATCH 2298/5359] add --field arg to 'wp post get' --- features/post.feature | 2 +- php/commands/post.php | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/features/post.feature b/features/post.feature index 8d6816ad8..8b7844714 100644 --- a/features/post.feature +++ b/features/post.feature @@ -50,7 +50,7 @@ Feature: Manage WordPress posts excerpt """ - When I run `wp post get --format=content {POST_ID}` + When I run `wp post get --field=content {POST_ID}` Then STDOUT should be: """ This is some content. diff --git a/php/commands/post.php b/php/commands/post.php index 5b8a73467..dc1d1d218 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -138,11 +138,13 @@ protected function _edit( $content, $title ) { * <id> * : The ID of the post to get. * + * [--field=<field>] + * : Instead of returning the whole post, returns the value of a single field. The --format= + * parameter is ignored in this case. + * * [--format=<format>] * : The format to use when printing the post, acceptable values: * - * - **content**: Outputs only the post's content. - * * - **table**: Outputs all fields of the post as a table. Note that the * post_content field is omitted so that the table is readable. * @@ -150,9 +152,8 @@ protected function _edit( $content, $title ) { * * ## EXAMPLES * - * wp post get 12 --format=content - * - * wp post get 12 > file.txt + * # save the post content to a file + * wp post get 12 --field=content > file.txt */ public function get( $args, $assoc_args ) { $defaults = array( @@ -162,13 +163,32 @@ public function get( $args, $assoc_args ) { $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) - \WP_CLI::error( "Failed opening post $post_id to get." ); + \WP_CLI::error( "Could not find the post with ID $post_id." ); - switch ( $assoc_args['format'] ) { + if ( isset( $assoc_args['field'] ) ) { + self::show_single_field( $post, $assoc_args['field'] ); + } else { + self::show_multiple_fields( $post, $assoc_args ); + } + } - case 'content': - WP_CLI::print_value( $post->post_content ); - break; + private function show_single_field( $post, $field ) { + $value = null; + + foreach ( array( $field, "post_$field" ) as $key ) { + if ( isset( $post->$key ) ) + $value = $post->$key; + } + + if ( null === $value ) { + \WP_CLI::error( "Invalid post field: $field." ); + } else { + WP_CLI::print_value( $value ); + } + } + + private function show_multiple_fields( $post, $assoc_args ) { + switch ( $assoc_args['format'] ) { case 'table': $fields = get_object_vars( $post ); From 65a6161078717a3e51f97701eaa46ea09c3df632 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 19 Sep 2013 23:32:02 +0300 Subject: [PATCH 2299/5359] add --field arg to 'wp user get' --- features/user.feature | 9 +++++---- php/WP_CLI/CommandWithDBObject.php | 30 +++++++++++++++++++++++------- php/commands/post.php | 24 ++++-------------------- php/commands/user.php | 13 ++++++++++++- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/features/user.feature b/features/user.feature index 1e39b3eb0..1f0413be9 100644 --- a/features/user.feature +++ b/features/user.feature @@ -72,10 +72,11 @@ Feature: Manage WordPress users When I run `wp user add-role 1 editor` Then STDOUT should not be empty - And I run `wp user get 1` - Then STDOUT should be a table containing rows: - | Field | Value | - | roles | administrator, editor | + And I run `wp user get 1 --field=roles` + Then STDOUT should be: + """ + administrator, editor + """ When I run `wp user set-role 1 author` Then STDOUT should not be empty diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 7978ce37b..3a751ce47 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -47,6 +47,17 @@ public function update( $args, $assoc_args ) { exit( $status ); } + public function delete( $args, $assoc_args ) { + $status = 0; + + foreach ( $args as $obj_id ) { + $r = $this->_delete( $obj_id, $assoc_args ); + $status = $this->success_or_failure( $r ); + } + + exit( $status ); + } + protected function wp_error_to_resp( $r, $success_msg ) { if ( is_wp_error( $r ) ) return array( 'error', $r->get_error_message() ); @@ -68,16 +79,21 @@ protected function success_or_failure( $r ) { return $status; } - public function delete( $args, $assoc_args ) { - $status = 0; + protected function show_single_field( $post, $field ) { + $value = null; - foreach ( $args as $obj_id ) { - $r = $this->_delete( $obj_id, $assoc_args ); - $status = $this->success_or_failure( $r ); + foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { + if ( isset( $post->$key ) ) { + $value = $post->$key; + break; + } } - exit( $status ); + if ( null === $value ) { + \WP_CLI::error( "Invalid $this->obj_type field: $field." ); + } else { + \WP_CLI::print_value( $value ); + } } - } diff --git a/php/commands/post.php b/php/commands/post.php index dc1d1d218..3bf21ec33 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -139,8 +139,7 @@ protected function _edit( $content, $title ) { * : The ID of the post to get. * * [--field=<field>] - * : Instead of returning the whole post, returns the value of a single field. The --format= - * parameter is ignored in this case. + * : Instead of returning the whole post, returns the value of a single field. * * [--format=<format>] * : The format to use when printing the post, acceptable values: @@ -152,7 +151,7 @@ protected function _edit( $content, $title ) { * * ## EXAMPLES * - * # save the post content to a file + * # save the post content to a file * wp post get 12 --field=content > file.txt */ public function get( $args, $assoc_args ) { @@ -166,24 +165,9 @@ public function get( $args, $assoc_args ) { \WP_CLI::error( "Could not find the post with ID $post_id." ); if ( isset( $assoc_args['field'] ) ) { - self::show_single_field( $post, $assoc_args['field'] ); + $this->show_single_field( $post, $assoc_args['field'] ); } else { - self::show_multiple_fields( $post, $assoc_args ); - } - } - - private function show_single_field( $post, $field ) { - $value = null; - - foreach ( array( $field, "post_$field" ) as $key ) { - if ( isset( $post->$key ) ) - $value = $post->$key; - } - - if ( null === $value ) { - \WP_CLI::error( "Invalid post field: $field." ); - } else { - WP_CLI::print_value( $value ); + $this->show_multiple_fields( $post, $assoc_args ); } } diff --git a/php/commands/user.php b/php/commands/user.php index 5a0abe55f..e4c8e2bef 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -88,6 +88,9 @@ public function _list( $args, $assoc_args ) { * <user> * : User ID or user login. * + * [--field=<field>] + * : Instead of returning the whole user, returns the value of a single field. + * * [--format=<format>] * : The format to use when printing the user; acceptable values: * @@ -97,7 +100,7 @@ public function _list( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user get 12 + * wp user get 12 --field=login * * wp user get bob --format=json > bob.json */ @@ -116,6 +119,14 @@ public function get( $args, $assoc_args ) { } $user_data['roles'] = implode( ', ', $user->roles ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( (object) $user_data, $assoc_args['field'] ); + } else { + $this->show_multiple_fields( $user_data, $assoc_args ); + } + } + + private function show_multiple_fields( $user_data, $assoc_args ) { switch ( $assoc_args['format'] ) { case 'table': From 53c1cf3a86fd91c016b31ecc1332b609921f9eaf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 20 Sep 2013 00:20:28 +0300 Subject: [PATCH 2300/5359] make Comment_Command extend CommandWithDbObject --- features/comment.feature | 10 ++++- php/WP_CLI/CommandWithDBObject.php | 7 +++- php/commands/comment.php | 60 ++++++++++++++++++++++++------ 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index e372172f0..551c870aa 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -3,7 +3,7 @@ Feature: Manage WordPress comments Scenario: Creating/updating/deleting comments Given a WP install - When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --porcelain` + When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --comment_author='Billy' --porcelain` Then STDOUT should be a number And save STDOUT as {COMMENT_ID} @@ -13,6 +13,14 @@ Feature: Manage WordPress comments Success: Comment with ID {COMMENT_ID} exists. """ + When I run `wp comment update {COMMENT_ID} --comment_author='Johnny'` + Then STDOUT should not be empty + + When I run `wp comment get {COMMENT_ID}` + Then STDOUT should be a table containing rows: + | Field | Value | + | comment_author | Johnny | + When I run `wp comment delete {COMMENT_ID}` Then STDOUT should be: """ diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 7978ce37b..d574b8e04 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -9,12 +9,15 @@ */ abstract class CommandWithDBObject extends \WP_CLI_Command { + protected $obj_type; + protected $obj_id_key = 'ID'; + abstract protected function _create( $params ); abstract protected function _update( $params ); abstract protected function _delete( $obj_id, $assoc_args ); public function create( $args, $assoc_args ) { - unset( $assoc_args['ID'] ); + unset( $assoc_args[ $this->obj_id_key ] ); $obj_id = $this->_create( $assoc_args ); @@ -36,7 +39,7 @@ public function update( $args, $assoc_args ) { } foreach ( $args as $obj_id ) { - $params = array_merge( $assoc_args, array( 'ID' => $obj_id ) ); + $params = array_merge( $assoc_args, array( $this->obj_id_key => $obj_id ) ); $status = $this->success_or_failure( $this->wp_error_to_resp( $this->_update( $params ), diff --git a/php/commands/comment.php b/php/commands/comment.php index d59e134c9..a480969d6 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -5,7 +5,10 @@ * * @package wp-cli */ -class Comment_Command extends WP_CLI_Command { +class Comment_Command extends \WP_CLI\CommandWithDBObject { + + protected $obj_type = 'comment'; + protected $obj_id_key = 'comment_ID'; private $fields = array( 'comment_ID', @@ -32,22 +35,51 @@ class Comment_Command extends WP_CLI_Command { * wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" */ public function create( $args, $assoc_args ) { + parent::create( $args, $assoc_args ); + } + + protected function _create( $assoc_args ) { $post = get_post( $assoc_args['comment_post_ID'] ); if ( !$post ) { - WP_CLI::error( "Cannot find post $comment_post_ID" ); + return new WP_Error( 'no_post', "Can't find post $comment_post_ID." ); } - // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and avoid wp_die() formatted messages or notifications + // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and + // avoid wp_die() formatted messages or notifications $comment_id = wp_insert_comment( $assoc_args ); if ( !$comment_id ) { - WP_CLI::error( "Could not create comment" ); + return new WP_Error( 'db_error', 'Could not create comment.' ); + } + + return $comment_id; + } + + /** + * Update one or more comments. + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of comments to update. + * + * --<field>=<value> + * : One or more fields to update. See wp_update_comment(). + * + * ## EXAMPLES + * + * wp comment update 123 --comment_author='That Guy' + */ + public function update( $args, $assoc_args ) { + parent::update( $args, $assoc_args ); + } + + protected function _update( $params ) { + if ( !wp_update_comment( $params ) ) { + return new WP_Error( 'Could not update comment.' ); } - if ( isset( $assoc_args['porcelain'] ) ) - WP_CLI::line( $comment_id ); - else - WP_CLI::success( "Inserted comment $comment_id." ); + return true; } /** @@ -164,12 +196,16 @@ public function _list( $_, $assoc_args ) { * wp comment delete 1337 --force */ public function delete( $args, $assoc_args ) { - list( $comment_id ) = $args; + parent::delete( $args, $assoc_args ); + } + + protected function _delete( $comment_id, $assoc_args ) { + $r = wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ); - if ( wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ) ) { - WP_CLI::success( "Deleted comment $comment_id." ); + if ( $r ) { + return array( 'success', "Deleted comment $comment_id." ); } else { - WP_CLI::error( "Failed deleting comment $comment_id" ); + return array( 'error', "Failed deleting comment $comment_id" ); } } From 9f09f4f29cbf7d6701e92b99e03d59c773ad74b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 20 Sep 2013 00:40:41 +0300 Subject: [PATCH 2301/5359] add --field arg to 'wp comment get' --- features/comment.feature | 9 +++++---- php/commands/comment.php | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 551c870aa..3ffebb821 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -16,10 +16,11 @@ Feature: Manage WordPress comments When I run `wp comment update {COMMENT_ID} --comment_author='Johnny'` Then STDOUT should not be empty - When I run `wp comment get {COMMENT_ID}` - Then STDOUT should be a table containing rows: - | Field | Value | - | comment_author | Johnny | + When I run `wp comment get {COMMENT_ID} --field=author` + Then STDOUT should be: + """ + Johnny + """ When I run `wp comment delete {COMMENT_ID}` Then STDOUT should be: diff --git a/php/commands/comment.php b/php/commands/comment.php index a480969d6..8120a81b0 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -90,6 +90,9 @@ protected function _update( $params ) { * <id> * : The comment to get. * + * [--field=<field>] + * : Instead of returning the whole comment, returns the value of a single field. + * * [--format=<format>] * : The format to use when printing the comment, acceptable values: * @@ -98,10 +101,9 @@ protected function _update( $params ) { * * ## EXAMPLES * - * wp comment get 1 + * wp comment get 1 --field=content */ public function get( $args, $assoc_args ) { - $defaults = array( 'format' => 'table' ); @@ -112,10 +114,19 @@ public function get( $args, $assoc_args ) { if ( empty( $comment ) ) WP_CLI::error( "Invalid comment ID." ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( $comment, $assoc_args['field'] ); + } else { + $this->show_multiple_fields( $comment, $assoc_args ); + } + } + + private function show_multiple_fields( $comment, $assoc_args ) { switch ( $assoc_args['format'] ) { case 'table': $fields = get_object_vars( $comment ); + unset( $fields['comment_content'] ); \WP_CLI\Utils\assoc_array_to_table( $fields ); break; From 670e66fb8103bbd6f4e530c4c5c8d37841f14094 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 20 Sep 2013 03:52:07 +0300 Subject: [PATCH 2302/5359] behat: use Background feature --- features/comment.feature | 5 ++--- features/media.feature | 14 +++----------- features/post.feature | 8 +++----- features/scaffold.feature | 17 +++++------------ features/term.feature | 5 ++--- features/user.feature | 12 +++--------- 6 files changed, 18 insertions(+), 43 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 3ffebb821..1b7da523f 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -1,8 +1,9 @@ Feature: Manage WordPress comments - Scenario: Creating/updating/deleting comments + Background: Given a WP install + Scenario: Creating/updating/deleting comments When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --comment_author='Billy' --porcelain` Then STDOUT should be a number And save STDOUT as {COMMENT_ID} @@ -29,8 +30,6 @@ Feature: Manage WordPress comments """ Scenario: Get details about an existing comment - Given a WP install - When I run `wp comment get 1` Then STDOUT should be a table containing rows: | Field | Value | diff --git a/features/media.feature b/features/media.feature index 74752d277..81a1d5bf1 100644 --- a/features/media.feature +++ b/features/media.feature @@ -1,39 +1,31 @@ Feature: Manage WordPress attachments - @images - Scenario: Regenerate all images while none exists + Background: Given a WP install + Scenario: Regenerate all images while none exists When I try `wp media regenerate --yes` Then STDERR should contain: """ Error: Unable to find the images """ - @images Scenario: Import image from remote URL - Given a WP install - When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ Success: Imported file http://s.wordpress.org/style/images/codeispoetry.png """ - @images Scenario: Fail to import missing image - Given a WP install - When I try `wp media import gobbledygook.png` Then STDERR should contain: """ Unable to import file gobbledygook.png. Reason: File doesn't exist. """ - @images Scenario: Import a file as attachment from a local image - Given a WP install - And download: + Given download: | path | url | | {CACHE_DIR}/large-image.jpg | http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg | diff --git a/features/post.feature b/features/post.feature index 8b7844714..84d864b98 100644 --- a/features/post.feature +++ b/features/post.feature @@ -1,8 +1,9 @@ Feature: Manage WordPress posts - Scenario: Creating/updating/deleting posts + Background: Given a WP install + Scenario: Creating/updating/deleting posts When I run `wp post create --post_title='Test post' --porcelain` Then STDOUT should be a number And save STDOUT as {POST_ID} @@ -26,8 +27,7 @@ Feature: Manage WordPress posts Then the return code should be 1 Scenario: Creating/getting posts - Given a WP install - And a content.html file: + Given a content.html file: """ This is some content. @@ -74,8 +74,6 @@ Feature: Manage WordPress posts """ Scenario: Creating/listing posts - Given a WP install - When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` Then STDOUT should be a number diff --git a/features/scaffold.feature b/features/scaffold.feature index d5efe9849..69431b33b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,9 +1,11 @@ Feature: Wordpress code scaffolding + Background: + Given a WP install + @theme Scenario: Scaffold a child theme - Given a WP install - And I run `wp theme path` + Given I run `wp theme path` And save STDOUT as {THEME_DIR} When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` @@ -12,8 +14,7 @@ Feature: Wordpress code scaffolding @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme - Given a WP install - And I run `wp eval 'echo STYLESHEETPATH;'` + Given I run `wp eval 'echo STYLESHEETPATH;'` And save STDOUT as {STYLESHEETPATH} When I run `wp scaffold taxonomy zombie-speed --theme` @@ -25,8 +26,6 @@ Feature: Wordpress code scaffolding # Test for all flags but --label, --theme, --plugin and --raw @tax Scenario: Scaffold a Custom Taxonomy and attach it to CPTs including one that is prefixed and has a text domain - Given a WP install - When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie,wraith" --textdomain=zombieland` Then STDOUT should contain: """ @@ -43,8 +42,6 @@ Feature: Wordpress code scaffolding @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" - Given a WP install - When I run `wp scaffold taxonomy zombie-speed --label="Speed"` Then STDOUT should contain: """ @@ -58,8 +55,6 @@ Feature: Wordpress code scaffolding # Test for all flags but --label, --theme, --plugin and --raw @cpt Scenario: Scaffold a Custom Post Type - Given a WP install - When I run `wp scaffold post-type zombie --textdomain=zombieland` Then STDOUT should contain: """ @@ -72,8 +67,6 @@ Feature: Wordpress code scaffolding @cpt Scenario: Scaffold a Custom Post Type with label - Given a WP install - When I run `wp scaffold post-type zombie --label="Brain eater"` Then STDOUT should contain: """ diff --git a/features/term.feature b/features/term.feature index b658eb97e..b0e1e0487 100644 --- a/features/term.feature +++ b/features/term.feature @@ -1,8 +1,9 @@ Feature: Manage WordPress terms - Scenario: Creating/listing a term + Background: Given a WP install + Scenario: Creating/listing a term When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` Then STDOUT should be a number And save STDOUT as {TERM_ID} @@ -34,8 +35,6 @@ Feature: Manage WordPress terms | name | Test term | Scenario: Creating/deleting a term - Given a WP install - When I run `wp term create 'Test delete term' post_tag --slug=test-delete --description='This is a test term to be deleted' --porcelain` Then STDOUT should be a number And save STDOUT as {TERM_ID} diff --git a/features/user.feature b/features/user.feature index 1f0413be9..68f85a9ad 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,8 +1,9 @@ Feature: Manage WordPress users - Scenario: User CRUD operations + Background: Given a WP install + Scenario: User CRUD operations When I run `wp user create testuser testuser@example.com --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} @@ -21,8 +22,6 @@ Feature: Manage WordPress users Then STDOUT should not be empty Scenario: Generating and deleting users - Given a WP install - When I run `wp user generate --count=9` And I run `wp user list --format=count` Then STDOUT should be: @@ -38,8 +37,7 @@ Feature: Manage WordPress users """ Scenario: Importing users from a CSV file - Given a WP install - And a users.csv file: + Given a users.csv file: """ user_login,user_email,display_name,role bobjones,bobjones@domain.com,Bob Jones,contributor @@ -68,8 +66,6 @@ Feature: Manage WordPress users """ Scenario: Managing user roles - Given a WP install - When I run `wp user add-role 1 editor` Then STDOUT should not be empty And I run `wp user get 1 --field=roles` @@ -100,8 +96,6 @@ Feature: Manage WordPress users | roles | | Scenario: Managing user capabilities - Given a WP install - When I run `wp user add-cap 1 edit_vip_product` Then STDOUT should be: """ From 72c6671393f038ee1f8005606e88e4a7a279a49e Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Sun, 22 Sep 2013 13:11:29 -0400 Subject: [PATCH 2303/5359] Adds --skip=image_resize to 'wp import' command. Gives import user the option to skip image thumbnail generation during image attachment import. Image resizing is extremely CPU intensive and makes imports run much slower, especially during test runs that don't necessarily require all image sizes. Image resizing can always be deferred post import by running the 'wp media regenerate' command. --- php/commands/import.php | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/php/commands/import.php b/php/commands/import.php index 493badb64..e5c6c33a0 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -124,6 +124,58 @@ private function import_wxr( $args ) { 'user_map' => $user_select, 'fetch_attachments' => $wp_import->fetch_attachments, ); + + if( in_array( 'image_resize', $args['skip'] ) ) { + add_filter( 'intermediate_image_sizes_advanced', function ($sizes) { + // Save the given sizes so that when the wp_generate_attachment_metadata hook + // is called we can place this info on to the $metadata array so that the + // info gets saved to the database, but the actual resize processing does + // not occur. + $this->sizes = $sizes; + + return null; + } ); + + add_filter( 'wp_generate_attachment_metadata', function ($metadata, $attachment_id) { + if( !isset( $metadata['file'] ) ) + return $metadata; + + $upload_dir = wp_upload_dir(); + $file_path = $upload_dir['basedir'] . '/' . $metadata['file']; + $path_info = pathinfo( $file_path ); + $mime_type = get_post_mime_type( $attachment_id ); + + // Return current meta untouched if can't determine current image mime type. + if( !$mime_type ) + return $metadata; + + $metadata['sizes'] = array( ); + + // Now time to generate the image size metadata since some resized files + // should already be on disk. We just have to point WordPress to them. + // Note: this logic will not find all possibled resized thumbnail files. + // To be sure _wp_attachment_metadata gets populated with all possible + // custom image sizes, run a command like WP-CLI's 'media regenerate' in order + // to re-generate and link to all the various configured image sizes. + foreach( $this->sizes as $size => $size_data ) { + $file = $path_info['filename'] . '-' . $size_data['width'] . 'x' . $size_data['height'] . '.' . $path_info['extension']; + + // Make sure the file exists before adding a size entry to the meta array. + if( !file_exists( $path_info['dirname'] . '/' . $file ) ) + continue; // File does not exist, don't point to it. + + $metadata['sizes'][$size] = array( + 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $file ) ), + 'width' => $size_data['width'], + 'height' => $size_data['height'], + 'mime-type' => $mime_type, + ); + } + + return $metadata; + }, 10, 2 ); + } + $wp_import->import( $args['file'] ); return true; From cb57cc0a7c7d57d595eeb275940d612da12f6522 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 23 Sep 2013 16:59:57 +0300 Subject: [PATCH 2304/5359] account for XDebug not being installed when setting 'display_errors' --- php/utils-wp.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index 4a307e753..1d925c6be 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -22,8 +22,8 @@ function wp_debug_mode() { \wp_debug_mode(); } - // Never show errors on STDOUT; only on STDERR - ini_set( 'display_errors', false ); + // XDebug already sends errors to STDERR + ini_set( 'display_errors', function_exists( 'xdebug_debug_zval' ) ? false : 'STDERR' ); } function replace_wp_die_handler() { From 44d72dab035e8c45cf1c56918e88316384867296 Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Tue, 24 Sep 2013 16:23:23 -0400 Subject: [PATCH 2305/5359] Re-factored patch to work with PHP < 5.4. --- php/commands/import.php | 99 +++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index e5c6c33a0..eeff977cc 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -126,54 +126,8 @@ private function import_wxr( $args ) { ); if( in_array( 'image_resize', $args['skip'] ) ) { - add_filter( 'intermediate_image_sizes_advanced', function ($sizes) { - // Save the given sizes so that when the wp_generate_attachment_metadata hook - // is called we can place this info on to the $metadata array so that the - // info gets saved to the database, but the actual resize processing does - // not occur. - $this->sizes = $sizes; - - return null; - } ); - - add_filter( 'wp_generate_attachment_metadata', function ($metadata, $attachment_id) { - if( !isset( $metadata['file'] ) ) - return $metadata; - - $upload_dir = wp_upload_dir(); - $file_path = $upload_dir['basedir'] . '/' . $metadata['file']; - $path_info = pathinfo( $file_path ); - $mime_type = get_post_mime_type( $attachment_id ); - - // Return current meta untouched if can't determine current image mime type. - if( !$mime_type ) - return $metadata; - - $metadata['sizes'] = array( ); - - // Now time to generate the image size metadata since some resized files - // should already be on disk. We just have to point WordPress to them. - // Note: this logic will not find all possibled resized thumbnail files. - // To be sure _wp_attachment_metadata gets populated with all possible - // custom image sizes, run a command like WP-CLI's 'media regenerate' in order - // to re-generate and link to all the various configured image sizes. - foreach( $this->sizes as $size => $size_data ) { - $file = $path_info['filename'] . '-' . $size_data['width'] . 'x' . $size_data['height'] . '.' . $path_info['extension']; - - // Make sure the file exists before adding a size entry to the meta array. - if( !file_exists( $path_info['dirname'] . '/' . $file ) ) - continue; // File does not exist, don't point to it. - - $metadata['sizes'][$size] = array( - 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $file ) ), - 'width' => $size_data['width'], - 'height' => $size_data['height'], - 'mime-type' => $mime_type, - ); - } - - return $metadata; - }, 10, 2 ); + add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_set_image_sizes' ) ); + add_filter( 'wp_generate_attachment_metadata', array( $this, 'filter_set_image_metadata' ), 10, 2 ); } $wp_import->import( $args['file'] ); @@ -181,6 +135,55 @@ private function import_wxr( $args ) { return true; } + public function filter_set_image_sizes( $sizes ) { + // Save the given sizes so that when the wp_generate_attachment_metadata hook + // is called we can place this info on to the $metadata array so that the + // info gets saved to the database, but the actual resize processing does + // not occur. + $this->image_sizes = $sizes; + + return null; + } + + public function filter_set_image_metadata( $metadata, $attachment_id ) { + if( !isset( $metadata['file'] ) ) + return $metadata; + + $upload_dir = wp_upload_dir(); + $file_path = $upload_dir['basedir'] . '/' . $metadata['file']; + $path_info = pathinfo( $file_path ); + $mime_type = get_post_mime_type( $attachment_id ); + + // Return current meta untouched if can't determine current image mime type. + if( !$mime_type ) + return $metadata; + + $metadata['sizes'] = array( ); + + // Now time to generate the image size metadata since some resized files + // should already be on disk. We just have to point WordPress to them. + // Note: this logic will not find all possibled resized thumbnail files. + // To be sure _wp_attachment_metadata gets populated with all possible + // custom image sizes, run a command like WP-CLI's 'media regenerate' in order + // to re-generate and link to all the various configured image sizes. + foreach( $this->image_sizes as $size => $size_data ) { + $file = $path_info['filename'] . '-' . $size_data['width'] . 'x' . $size_data['height'] . '.' . $path_info['extension']; + + // Make sure the file exists before adding a size entry to the meta array. + if( !file_exists( $path_info['dirname'] . '/' . $file ) ) + continue; // File does not exist, don't point to it. + + $metadata['sizes'][$size] = array( + 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $file ) ), + 'width' => $size_data['width'], + 'height' => $size_data['height'], + 'mime-type' => $mime_type, + ); + } + + return $metadata; + } + /** * Useful verbosity filters for the WXR importer */ From f6285d3b674e01fff81e37a2978a1436e1f94e69 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 27 Sep 2013 02:17:47 +0300 Subject: [PATCH 2306/5359] pass subcommand implementations as callbacks This allows child classes to implement only some of the subcommands. --- php/WP_CLI/CommandWithDBObject.php | 16 +++---- php/commands/comment.php | 68 ++++++++++++++---------------- php/commands/post.php | 36 +++++++--------- php/commands/user.php | 41 +++++++----------- 4 files changed, 68 insertions(+), 93 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 62f04f237..c231fe79c 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -12,14 +12,10 @@ abstract class CommandWithDBObject extends \WP_CLI_Command { protected $obj_type; protected $obj_id_key = 'ID'; - abstract protected function _create( $params ); - abstract protected function _update( $params ); - abstract protected function _delete( $obj_id, $assoc_args ); - - public function create( $args, $assoc_args ) { + protected function _create( $args, $assoc_args, $callback ) { unset( $assoc_args[ $this->obj_id_key ] ); - $obj_id = $this->_create( $assoc_args ); + $obj_id = $callback( $assoc_args ); if ( is_wp_error( $obj_id ) ) { \WP_CLI::error( $obj_id ); @@ -31,7 +27,7 @@ public function create( $args, $assoc_args ) { \WP_CLI::success( "Created $this->obj_type $obj_id." ); } - public function update( $args, $assoc_args ) { + protected function _update( $args, $assoc_args, $callback ) { $status = 0; if ( empty( $assoc_args ) ) { @@ -42,7 +38,7 @@ public function update( $args, $assoc_args ) { $params = array_merge( $assoc_args, array( $this->obj_id_key => $obj_id ) ); $status = $this->success_or_failure( $this->wp_error_to_resp( - $this->_update( $params ), + $callback( $params ), "Updated $this->obj_type $obj_id." ) ); } @@ -50,11 +46,11 @@ public function update( $args, $assoc_args ) { exit( $status ); } - public function delete( $args, $assoc_args ) { + protected function _delete( $args, $assoc_args, $callback ) { $status = 0; foreach ( $args as $obj_id ) { - $r = $this->_delete( $obj_id, $assoc_args ); + $r = $callback( $obj_id, $assoc_args ); $status = $this->success_or_failure( $r ); } diff --git a/php/commands/comment.php b/php/commands/comment.php index 8120a81b0..61f989bea 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -35,24 +35,22 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { * wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" */ public function create( $args, $assoc_args ) { - parent::create( $args, $assoc_args ); - } - - protected function _create( $assoc_args ) { - $post = get_post( $assoc_args['comment_post_ID'] ); - if ( !$post ) { - return new WP_Error( 'no_post', "Can't find post $comment_post_ID." ); - } - - // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and - // avoid wp_die() formatted messages or notifications - $comment_id = wp_insert_comment( $assoc_args ); - - if ( !$comment_id ) { - return new WP_Error( 'db_error', 'Could not create comment.' ); - } - - return $comment_id; + parent::_create( $args, $assoc_args, function ( $params ) { + $post = get_post( $params['comment_post_ID'] ); + if ( !$post ) { + return new WP_Error( 'no_post', "Can't find post $comment_post_ID." ); + } + + // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and + // avoid wp_die() formatted messages or notifications + $comment_id = wp_insert_comment( $params ); + + if ( !$comment_id ) { + return new WP_Error( 'db_error', 'Could not create comment.' ); + } + + return $comment_id; + } ); } /** @@ -71,15 +69,13 @@ protected function _create( $assoc_args ) { * wp comment update 123 --comment_author='That Guy' */ public function update( $args, $assoc_args ) { - parent::update( $args, $assoc_args ); - } + parent::_update( $args, $assoc_args, function ( $params ) { + if ( !wp_update_comment( $params ) ) { + return new WP_Error( 'Could not update comment.' ); + } - protected function _update( $params ) { - if ( !wp_update_comment( $params ) ) { - return new WP_Error( 'Could not update comment.' ); - } - - return true; + return true; + } ); } /** @@ -207,17 +203,15 @@ public function _list( $_, $assoc_args ) { * wp comment delete 1337 --force */ public function delete( $args, $assoc_args ) { - parent::delete( $args, $assoc_args ); - } - - protected function _delete( $comment_id, $assoc_args ) { - $r = wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ); - - if ( $r ) { - return array( 'success', "Deleted comment $comment_id." ); - } else { - return array( 'error', "Failed deleting comment $comment_id" ); - } + parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { + $r = wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ); + + if ( $r ) { + return array( 'success', "Deleted comment $comment_id." ); + } else { + return array( 'error', "Failed deleting comment $comment_id" ); + } + } ); } private function call( $args, $status, $success, $failure ) { diff --git a/php/commands/post.php b/php/commands/post.php index 3bf21ec33..d946293cf 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -71,11 +71,9 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = $input; } - parent::create( $args, $assoc_args ); - } - - protected function _create( $params ) { - return wp_insert_post( $params, true ); + parent::_create( $args, $assoc_args, function ( $params ) { + return wp_insert_post( $params, true ); + } ); } /** @@ -94,11 +92,9 @@ protected function _create( $params ) { * wp post update 123 --post_name=something --post_status=draft */ public function update( $args, $assoc_args ) { - parent::update( $args, $assoc_args ); - } - - protected function _update( $params ) { - return wp_update_post( $params, true ); + parent::_update( $args, $assoc_args, function ( $params ) { + return wp_update_post( $params, true ); + } ); } /** @@ -216,19 +212,17 @@ public function delete( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - parent::delete( $args, $assoc_args ); - } - - protected function _delete( $post_id, $assoc_args ) { - $r = wp_delete_post( $post_id, $assoc_args['force'] ); + parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { + $r = wp_delete_post( $post_id, $assoc_args['force'] ); - if ( $r ) { - $action = $assoc_args['force'] ? 'Deleted' : 'Trashed'; + if ( $r ) { + $action = $assoc_args['force'] ? 'Deleted' : 'Trashed'; - return array( 'success', "$action post $post_id." ); - } else { - return array( 'error', "Failed deleting post $post_id." ); - } + return array( 'success', "$action post $post_id." ); + } else { + return array( 'error', "Failed deleting post $post_id." ); + } + } ); } /** diff --git a/php/commands/user.php b/php/commands/user.php index e4c8e2bef..f1ffaa7fb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -165,23 +165,22 @@ public function delete( $args, $assoc_args ) { ) ); foreach ( $args as $key => $arg ) { - $args[$key] = self::get_user( $arg )->ID; + $args[ $key ] = self::get_user( $arg )->ID; } - parent::delete( $args, $assoc_args ); - } - protected function _delete( $user_id, $assoc_args ) { - if ( is_multisite() ) { - $r = wpmu_delete_user( $user_id ); - } else { - $r = wp_delete_user( $user_id, $assoc_args['reassign'] ); - } + parent::_delete( $args, $assoc_args, function ( $user_id, $assoc_args ) { + if ( is_multisite() ) { + $r = wpmu_delete_user( $user_id ); + } else { + $r = wp_delete_user( $user_id, $assoc_args['reassign'] ); + } - if ( $r ) { - return array( 'success', "Deleted user $user_id." ); - } else { - return array( 'error', "Failed deleting user $user_id." ); - } + if ( $r ) { + return array( 'success', "Deleted user $user_id." ); + } else { + return array( 'error', "Failed deleting user $user_id." ); + } + } ); } /** @@ -237,7 +236,7 @@ public function create( $args, $assoc_args ) { $generated_pass = true; } - $user_id = $this->_create( array( + $user_id = wp_insert_user( array( 'user_email' => $user_email, 'user_login' => $user_login, 'user_pass' => $user_pass, @@ -264,10 +263,6 @@ public function create( $args, $assoc_args ) { } } - protected function _create( $params ) { - return wp_insert_user( $params ); - } - /** * Update a user. * @@ -286,15 +281,11 @@ protected function _create( $params ) { * wp user update mary --user_pass=marypass */ public function update( $args, $assoc_args ) { - foreach ( $args as $key => $arg ) { - $args[$key] = self::get_user( $arg )->ID; + $args[ $key ] = self::get_user( $arg )->ID; } - parent::update( $args, $assoc_args, 'user' ); - } - protected function _update( $params ) { - return wp_update_user( $params ); + parent::_update( $args, $assoc_args, 'wp_update_user' ); } /** From fad4f75e705c86edb73abf6fac1b8ec95c1f6c63 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 27 Sep 2013 02:37:44 +0300 Subject: [PATCH 2307/5359] make Site_Command extend CommandWithDBObject --- php/commands/site.php | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 9a49c69c1..52a61b96d 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -5,7 +5,7 @@ * * @package wp-cli */ -class Site_Command extends WP_CLI_Command { +class Site_Command extends \WP_CLI\CommandWithDBObject { /** * Delete comments. @@ -174,24 +174,6 @@ function delete( $args, $assoc_args ) { WP_CLI::success( "The site at $blog->siteurl was deleted." ); } - /** - * Get site (network) data for a given id. - * - * @param int $site_id - * @return bool|array False if no network found with given id, array otherwise - */ - private function _get_site( $site_id ) { - global $wpdb; - // Load site data - $sites = $wpdb->get_results( "SELECT * FROM $wpdb->site WHERE `id` = ".$wpdb->escape( $site_id ) ); - if ( count( $sites ) > 0 ) { - // Only care about domain and path which are set here - return $sites[0]; - } - - return false; - } - /** * Create a site in a multisite install. * @@ -372,6 +354,27 @@ function _list( $_, $assoc_args ) { WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); } + + /** + * Get site (network) data for a given id. + * + * @param int $site_id + * @return bool|array False if no network found with given id, array otherwise + */ + private function _get_site( $site_id ) { + global $wpdb; + + // Load site data + $sites = $wpdb->get_results( $wpdb->prepare( + "SELECT * FROM $wpdb->site WHERE id = %d", $site_id ) ); + + if ( !empty( $sites ) ) { + // Only care about domain and path which are set here + return $sites[0]; + } + + return false; + } } WP_CLI::add_command( 'site', 'Site_Command' ); From f89c6f51d71fe0ff50773c6055d709d4ae61402a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 27 Sep 2013 03:39:43 +0300 Subject: [PATCH 2308/5359] behat: show STDOUT on error --- features/bootstrap/Process.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index e0abcffbe..1cbb194d9 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -71,8 +71,12 @@ public function __construct( $props ) { } public function __toString() { - return sprintf( "%s: %s\n" . "cwd: %s\n" . "exit status: %d", - $this->command, $this->STDERR, $this->cwd, $this->return_code ); + $out = "$ $this->command\n"; + $out .= "$this->STDOUT\n$this->STDERR"; + $out .= "cwd: $this->cwd\n"; + $out .= "exit status: $this->return_code"; + + return $out; } } From f592cff085f7279d7319d111e26fdf1ae488d731 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Fri, 27 Sep 2013 12:09:20 -0700 Subject: [PATCH 2309/5359] Apply default filters in content in `wp post edit` I noticed that without applying the `the_editor_content` and `content_save_pre` filters to the post content being edited, unexpected things could happen when editing posts with the system editor. For example, the Syntaxhighlighter Extended plugin uses these filters cto decode entities when retrieving a post from that database to edit, and then re-encode them on save. There may be some extra thought required as to what the expected behavior should be, but this apporach seems to make the most sense to me. --- php/commands/post.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index d946293cf..51e288f52 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -123,7 +123,9 @@ public function edit( $args, $_ ) { } protected function _edit( $content, $title ) { - return \WP_CLI\Utils\launch_editor_for_input( $content, $title ); + $content = apply_filters( 'the_editor_content', $content ); + $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title ); + return apply_filters( 'content_save_pre', $output ); } /** From 601f03ecff216d02d0bd58e0e325c8dbc62a4670 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 28 Sep 2013 17:35:28 +0300 Subject: [PATCH 2310/5359] fix `wp post edit` see #779 --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index d946293cf..a92b2f4f9 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -119,7 +119,7 @@ public function edit( $args, $_ ) { if ( $r === false ) \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); else - parent::update( $args, array( 'post_content' => $r ) ); + self::update( $args, array( 'post_content' => $r ) ); } protected function _edit( $content, $title ) { From b0dfe97c6caf0bcea59b5567411c8b50587c845a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 27 Sep 2013 03:41:24 +0300 Subject: [PATCH 2311/5359] implement --field= parameter for post, user and comment `list` subcommands --- features/comment.feature | 6 ++++++ features/post.feature | 6 ++++++ features/user.feature | 2 +- php/WP_CLI/CommandWithDBObject.php | 23 +++++++++++++---------- php/commands/comment.php | 16 ++++++++++++---- php/commands/post.php | 22 +++++++++++++++------- php/commands/user.php | 15 +++++++++++---- 7 files changed, 64 insertions(+), 26 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 1b7da523f..96b21e701 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -39,3 +39,9 @@ Feature: Manage WordPress comments Then STDOUT should be a table containing rows: | comment_approved | comment_author | | 1 | Mr WordPress | + + When I run `wp comment list --field=approved` + Then STDOUT should be: + """ + 1 + """ diff --git a/features/post.feature b/features/post.feature index 84d864b98..e12db9ef2 100644 --- a/features/post.feature +++ b/features/post.feature @@ -85,3 +85,9 @@ Feature: Manage WordPress posts | post_title | post_name | post_status | | Publish post | publish-post | publish | | Draft post | | draft | + + When I run `wp post list --post_type='page' --field=title` + Then STDOUT should be: + """ + Sample Page + """ diff --git a/features/user.feature b/features/user.feature index 68f85a9ad..5f3319d11 100644 --- a/features/user.feature +++ b/features/user.feature @@ -29,7 +29,7 @@ Feature: Manage WordPress users 10 """ - When I try `wp user delete invalid-user $(wp user list --format=ids)` + When I try `wp user list --field=ID | xargs wp user delete invalid-user` And I run `wp user list --format=count` Then STDOUT should be: """ diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index c231fe79c..1c69d81c2 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -78,21 +78,24 @@ protected function success_or_failure( $r ) { return $status; } - protected function show_single_field( $post, $field ) { - $value = null; + protected function show_single_field( $items, $field ) { + foreach ( $items as $item ) { + if ( !isset( $key ) ) { + $key = $this->find_field( $item, $field ); + } + + \WP_CLI::print_value( $item->$key ); + } + } + private function find_field( $item, $field ) { foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { - if ( isset( $post->$key ) ) { - $value = $post->$key; - break; + if ( isset( $item->$key ) ) { + return $key; } } - if ( null === $value ) { - \WP_CLI::error( "Invalid $this->obj_type field: $field." ); - } else { - \WP_CLI::print_value( $value ); - } + \WP_CLI::error( "Invalid $this->obj_type field: $field." ); } } diff --git a/php/commands/comment.php b/php/commands/comment.php index 61f989bea..7d91cf7f3 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -111,7 +111,7 @@ public function get( $args, $assoc_args ) { WP_CLI::error( "Invalid comment ID." ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $comment, $assoc_args['field'] ); + $this->show_single_field( array( $comment ), $assoc_args['field'] ); } else { $this->show_multiple_fields( $comment, $assoc_args ); } @@ -144,6 +144,9 @@ private function show_multiple_fields( $comment, $assoc_args ) { * [--<field>=<value>] * : One or more args to pass to WP_Comment_Query. * + * [--field=<field>] + * : Prints the value of a single field for each comment. + * * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to comment_ID,comment_post_ID,comment_date,comment_approved,comment_author,comment_author_email * @@ -152,7 +155,7 @@ private function show_multiple_fields( $comment, $assoc_args ) { * * ## EXAMPLES * - * wp comment list --format=ids + * wp comment list --field=ID * * wp comment list --post_id=2 * @@ -181,10 +184,15 @@ public function _list( $_, $assoc_args ) { $query = new WP_Comment_Query(); $comments = $query->query( $query_args ); - if ( 'ids' == $assoc_args['format'] ) + if ( 'ids' == $assoc_args['format'] ) { $comments = wp_list_pluck( $comments, 'comment_ID' ); + } - WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( $comments, $assoc_args['field'] ); + } else { + WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); + } } /** diff --git a/php/commands/post.php b/php/commands/post.php index ebe36de9d..1c6673a55 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -163,7 +163,7 @@ public function get( $args, $assoc_args ) { \WP_CLI::error( "Could not find the post with ID $post_id." ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $post, $assoc_args['field'] ); + $this->show_single_field( array( $post ), $assoc_args['field'] ); } else { $this->show_multiple_fields( $post, $assoc_args ); } @@ -235,6 +235,9 @@ public function delete( $args, $assoc_args ) { * [--<field>=<value>] * : One or more args to pass to WP_Query. * + * [--field=<field>] + * : Prints the value of a single field for each post. + * * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. * @@ -243,7 +246,7 @@ public function delete( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post list --format=ids + * wp post list --field=ID * * wp post list --post_type=post --posts_per_page=5 --format=json * @@ -252,16 +255,17 @@ public function delete( $args, $assoc_args ) { * @subcommand list */ public function _list( $_, $assoc_args ) { - $query_args = array( - 'posts_per_page' => -1, - 'post_status' => 'any', - ); $defaults = array( 'format' => 'table', 'fields' => $this->fields ); $assoc_args = array_merge( $defaults, $assoc_args ); + $query_args = array( + 'posts_per_page' => -1, + 'post_status' => 'any', + ); + foreach ( $assoc_args as $key => $value ) { if ( true === $value ) continue; @@ -274,7 +278,11 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); - WP_CLI\Utils\format_items( $assoc_args['format'], $query->posts, $assoc_args['fields'] ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( $query->posts, $assoc_args['field'] ); + } else { + WP_CLI\Utils\format_items( $assoc_args['format'], $query->posts, $assoc_args['fields'] ); + } } /** diff --git a/php/commands/user.php b/php/commands/user.php index f1ffaa7fb..eb0784546 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -29,6 +29,9 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_users(). * + * [--field=<field>] + * : Prints the value of a single field for each user. + * * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles * @@ -37,11 +40,11 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * * ## EXAMPLES * - * wp user list --format=ids + * wp user list --field=ID * * wp user list --role=administrator --format=csv * - * wp user list --fields=display_name,user_email + * wp user list --fields=display_name,user_email --format=json * * @subcommand list */ @@ -77,7 +80,11 @@ public function _list( $args, $assoc_args ) { return $user; } ); - WP_CLI\Utils\format_items( $params['format'], $it, $fields ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( $it, $assoc_args['field'] ); + } else { + WP_CLI\Utils\format_items( $params['format'], $it, $fields ); + } } /** @@ -120,7 +127,7 @@ public function get( $args, $assoc_args ) { $user_data['roles'] = implode( ', ', $user->roles ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( (object) $user_data, $assoc_args['field'] ); + $this->show_single_field( array( (object) $user_data ), $assoc_args['field'] ); } else { $this->show_multiple_fields( $user_data, $assoc_args ); } From 71155041f52aecf250a6f6f485b4f6b96eae6119 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 28 Sep 2013 20:44:52 +0300 Subject: [PATCH 2312/5359] implement --field= parameter for 'wp site list' --- features/site.feature | 7 +++++++ php/WP_CLI/CommandWithDBObject.php | 7 +++++-- php/commands/site.php | 18 ++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/features/site.feature b/features/site.feature index 3e872852f..bfbd49218 100644 --- a/features/site.feature +++ b/features/site.feature @@ -13,6 +13,13 @@ Feature: Manage sites in a multisite installation | 1 | example.com/ | | 2 | example.com/first/ | + When I run `wp site list --field=url` + Then STDOUT should be: + """ + example.com/ + example.com/first/ + """ + When I run `wp site delete {SITE_ID} --yes` Then STDOUT should not be empty diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 1c69d81c2..d8dbe8433 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -82,20 +82,23 @@ protected function show_single_field( $items, $field ) { foreach ( $items as $item ) { if ( !isset( $key ) ) { $key = $this->find_field( $item, $field ); + if ( !$key ) { + \WP_CLI::error( "Invalid $this->obj_type field: $field." ); + } } \WP_CLI::print_value( $item->$key ); } } - private function find_field( $item, $field ) { + protected function find_field( $item, $field ) { foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { if ( isset( $item->$key ) ) { return $key; } } - \WP_CLI::error( "Invalid $this->obj_type field: $field." ); + return false; } } diff --git a/php/commands/site.php b/php/commands/site.php index 52a61b96d..f62585407 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -306,6 +306,9 @@ public function create( $_, $assoc_args ) { * [--network=<id>] * : The network to which the sites belong. * + * [--field=<field>] + * : Prints the value of a single field for each site. + * * [--fields=<fields>] * : Comma-separated list of fields to show. * @@ -315,7 +318,7 @@ public function create( $_, $assoc_args ) { * ## EXAMPLES * * # Output a simple list of site URLs - * wp site list --fields=url --format=csv | tail -n +2 + * wp site list --field=url * * @subcommand list */ @@ -352,7 +355,18 @@ function _list( $_, $assoc_args ) { return $blog; } ); - WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( $it, $assoc_args['field'] ); + } else { + WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + } + } + + protected function find_field( $item, $field ) { + if ( 'url' == $field ) + return 'url'; + + return parent::find_field( $item, $field ); } /** From 1abe600b1bacc9c151fddaae04f87e497b980989 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 28 Sep 2013 21:23:14 +0300 Subject: [PATCH 2313/5359] move plugin/theme prepping code closer to where it's used --- php/WP_CLI/CommandWithUpgrade.php | 47 ++++++++++++------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index db20e649a..51bc3719a 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -245,9 +245,25 @@ protected function _list( $_, $assoc_args ) { $assoc_args = array_merge( $defaults, $assoc_args ); $all_items = $this->get_all_items(); - $items = $this->create_objects( $all_items ); + if ( !is_array( $all_items ) ) + \WP_CLI::error( "No {$this->item_type}s found." ); - \WP_CLI\Utils\format_items( $assoc_args['format'], $items, $assoc_args['fields'] ); + $it = \WP_CLI\Utils\iterator_map( $all_items, function( $item ) { + if ( empty( $item['version'] ) ) + $item['version'] = ''; + + foreach ( $item as $field => &$value ) { + if ( $value === true ) { + $value = 'available'; + } else if ( $value === false ) { + $value = 'none'; + } + } + + return $item; + } ); + + \WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); } /** @@ -278,33 +294,6 @@ protected function has_update( $slug ) { ) ); - private function create_objects( $items ) { - if ( !is_array( $items ) && !empty( $items ) ) - \WP_CLI::error( sprintf( "No '$this->item_type's found." ) ); - - $objects = array(); - - foreach ( $items as $item ) { - $object = new \stdClass; - - if ( empty( $item['version'] ) ) - $item['version'] = ""; - - foreach ( $item as $field => $value ) { - if ( $value === true ) { - $value = "available"; - } else if ( $value === false) { - $value = "none"; - } - - $object->{$field} = $value; - } - $objects[] = $object; - } - - return $objects; - } - protected function format_status( $status, $format ) { return $this->get_color( $status ) . $this->map[ $format ][ $status ]; } From d5d58cd973153bb1d7e2949fce07a85bfe0f378a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 28 Sep 2013 22:40:44 +0300 Subject: [PATCH 2314/5359] implement --field= parameter for 'wp plugin list' and 'wp theme list' --- features/upgradables.feature | 11 +++++++++++ php/WP_CLI/CommandWithUpgrade.php | 13 ++++++++++++- php/commands/plugin.php | 6 ++++++ php/commands/theme.php | 6 ++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index b7d1a3478..df5080414 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -15,6 +15,17 @@ Feature: Manage WordPress themes and plugins <type_name> installed successfully """ + When I run `wp <type> list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | <item> | inactive | available | <version> | + + When I run `wp <type> list --field=name` + Then STDOUT should contain: + """ + <item> + """ + When I run `wp <type> status` Then STDOUT should contain: """ diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 51bc3719a..d868cf772 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -263,7 +263,18 @@ protected function _list( $_, $assoc_args ) { return $item; } ); - \WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + if ( isset( $assoc_args['field'] ) ) { + $field = $assoc_args['field']; + + foreach ( $it as $item ) { + if ( !isset( $item[ $field ] ) ) { + \WP_CLI::error( "Invalid $this->item_type field: $field." ); + } + \WP_CLI::print_value( $item[ $field ] ); + } + } else { + \WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); + } } /** diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 46a655f09..92568e6ed 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -446,6 +446,12 @@ function delete( $args, $assoc_args = array() ) { * * ## OPTIONS * + * [--field=<field>] + * : Prints the value of a single field for each plugin. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to name,status,update,version. + * * [--format=<format>] * : Output list as table, CSV or JSON. Defaults to table. * diff --git a/php/commands/theme.php b/php/commands/theme.php index 7f23b4278..ec1bd1709 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -360,6 +360,12 @@ function delete( $args ) { * * ## OPTIONS * + * [--field=<field>] + * : Prints the value of a single field for each theme. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to name,status,update,version. + * * [--format=<format>] * : Output list as table, CSV or JSON. Defaults to table. * From 3deed97c7cea704e8ca0dd0ba3f34dfefbc749f1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 01:34:18 +0300 Subject: [PATCH 2315/5359] rewrap argument descriptions --- php/commands/help.php | 14 +++++++++++++- php/commands/scaffold.php | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 6e90600b2..b2aba852f 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -54,13 +54,25 @@ private static function show_help( $command ) { $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); // definition lists - $out = preg_replace( '/\n([^\n]+)\n: (.+?)\n/s', "\n\t\\1\n\t\t\\2\n", $out ); + $out = preg_replace_callback( '/([^\n]+)\n: (.+?)\n\n/s', function( $matches ) { + $param = $matches[1]; + $desc = self::indent( "\t\t", wordwrap( $matches[2] ) ); + return "\t$param\n$desc\n\n"; + }, $out ); $out = str_replace( "\t", ' ', $out ); self::pass_through_pager( WP_CLI::colorize( $out ) ); } + private static function indent( $whitespace, $text ) { + $lines = explode( "\n", $text ); + foreach ( $lines as &$line ) { + $line = $whitespace . $line; + } + return implode( $lines, "\n" ); + } + private static function pass_through_pager( $out ) { if ( strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ) { // no paging for Windows cmd.exe; sorry diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5e7ba7269..c69d1a342 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -64,7 +64,7 @@ function post_type( $args, $assoc_args ) { * : Post types to register for use with the taxonomy. * * [--label=<label>] - * : The text used to translate the update messages + * : The text used to translate the update messages. * * [--textdomain=<textdomain>] * : The textdomain to use for the labels. From 86d519ecc3dad0f208ae8f3e1a00c420da7c18fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 01:50:23 +0300 Subject: [PATCH 2316/5359] wordwrap synopsis --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index b2aba852f..c8cf35e91 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -102,7 +102,7 @@ private static function get_initial_markdown( $command ) { 'shortdesc' => $command->get_shortdesc(), ); - $binding['synopsis'] = "$name " . $command->get_synopsis(); + $binding['synopsis'] = wordwrap( "$name " . $command->get_synopsis(), 79 ); if ( $command->has_subcommands() ) { $binding['has-subcommands']['subcommands'] = self::render_subcommands( $command ); From 73141b2c6bca4ce4f0bda4269335f51320e68b2e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 02:11:09 +0300 Subject: [PATCH 2317/5359] in PHP 5.3, self:: does not work inside closures --- php/commands/help.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index c8cf35e91..36348b21a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -54,17 +54,19 @@ private static function show_help( $command ) { $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); // definition lists - $out = preg_replace_callback( '/([^\n]+)\n: (.+?)\n\n/s', function( $matches ) { - $param = $matches[1]; - $desc = self::indent( "\t\t", wordwrap( $matches[2] ) ); - return "\t$param\n$desc\n\n"; - }, $out ); + $out = preg_replace_callback( '/([^\n]+)\n: (.+?)\n\n/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); $out = str_replace( "\t", ' ', $out ); self::pass_through_pager( WP_CLI::colorize( $out ) ); } + private static function rewrap_param_desc( $matches ) { + $param = $matches[1]; + $desc = self::indent( "\t\t", wordwrap( $matches[2] ) ); + return "\t$param\n$desc\n\n"; + } + private static function indent( $whitespace, $text ) { $lines = explode( "\n", $text ); foreach ( $lines as &$line ) { From 8d98f69199a3c8ec8feae6feec4c1473b2fbc4aa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 03:24:54 +0300 Subject: [PATCH 2318/5359] handle case where there is nothing after the last parameter description --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 36348b21a..343b4e355 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -54,7 +54,7 @@ private static function show_help( $command ) { $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); // definition lists - $out = preg_replace_callback( '/([^\n]+)\n: (.+?)\n\n/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); + $out = preg_replace_callback( '/([^\n]+)\n: (.+?)(\n\n|$)/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); $out = str_replace( "\t", ' ', $out ); From f2938b9cf44adac7a8cd1c2a41cae1a22f5d1a0a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 03:52:52 +0300 Subject: [PATCH 2319/5359] remove 'wp comment last' subcommand was superseded by 'wp comment list' fixes #760 --- php/commands/comment.php | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 7d91cf7f3..8ca730efd 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -394,44 +394,6 @@ public function status( $args, $assoc_args ) { } } - /** - * Get last approved comment. - * - * ## OPTIONS - * - * [--id] - * : Output just the last comment id. - * - * [--full] - * : Output complete comment information. - * - * ## EXAMPLES - * - * wp comment last --full - */ - function last( $args = array(), $assoc_args = array() ) { - $last = get_comments( array( 'number' => 1, 'status' => 'approve' ) ); - - list( $comment ) = $last; - - if ( isset( $assoc_args['id'] ) ) { - WP_CLI::line( $comment->comment_ID ); - exit( 1 ); - } - - WP_CLI::line( "%yLast approved comment:%n " ); - - if ( isset( $assoc_args['full'] ) ) { - $keys = array_keys( get_object_vars( $comment ) ); - } else { - $keys = array( 'comment_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' ); - } - - foreach ( $keys as $key ) { - WP_CLI::line( str_pad( "$key:", 23 ) . $comment->$key ); - } - } - /** * Verify whether a comment exists. * From 80781ca8ac233231dcefad8a02d591f8be740061 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 04:06:55 +0300 Subject: [PATCH 2320/5359] make 'wp theme delete' support multiple args --- features/theme.feature | 5 ++--- php/commands/theme.php | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index db0fabc6a..400197788 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -35,10 +35,9 @@ Feature: Manage WordPress themes Then STDOUT should not be empty When I try the previous command again - Then the return code should be 1 - And STDERR should contain: + Then STDERR should contain: """ - Error: The theme 'p2' could not be found. + The 'p2' theme could not be found. """ When I run `wp theme list` diff --git a/php/commands/theme.php b/php/commands/theme.php index ec1bd1709..e8932ee05 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -331,28 +331,29 @@ function update( $args, $assoc_args ) { * * ## OPTIONS * - * <theme> - * : The theme to delete. + * <theme>... + * : One or more themes to delete. * * ## EXAMPLES * * wp theme delete twentyeleven */ function delete( $args ) { - $theme = $this->parse_name( $args[0] ); - $theme_slug = $theme->get_stylesheet(); + foreach ( $this->validate_theme_names( $args ) as $theme ) { + $theme_slug = $theme->get_stylesheet(); - if ( $this->is_active_theme( $theme ) ) { - WP_CLI::error( "Can't delete the currently active theme." ); - } + if ( $this->is_active_theme( $theme ) ) { + WP_CLI::warning( "Can't delete the currently active theme: $theme_slug" ); + } - $r = delete_theme( $theme_slug ); + $r = delete_theme( $theme_slug ); - if ( is_wp_error( $r ) ) { - WP_CLI::error( $r ); + if ( is_wp_error( $r ) ) { + WP_CLI::warning( $r ); + } else { + WP_CLI::success( "Deleted '$theme_slug' theme." ); + } } - - WP_CLI::success( sprintf( "Deleted '%s' theme.", $theme_slug ) ); } /** @@ -395,6 +396,22 @@ private function parse_name( $name ) { return $theme; } + + private function validate_theme_names( $args ) { + $themes = array(); + + foreach ( $args as $name ) { + $theme = wp_get_theme( $name ); + + if ( !$theme->exists() ) { + WP_CLI::warning( "The '$name' theme could not be found." ); + } else { + $themes[] = $theme; + } + } + + return $themes; + } } WP_CLI::add_command( 'theme', 'Theme_Command' ); From b074fd054d83527eddb2623134373fbb88ec7389 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 04:56:03 +0300 Subject: [PATCH 2321/5359] add warning when unregistered positional parameters are passed --- php/WP_CLI/Dispatcher/Subcommand.php | 6 ++++++ php/WP_CLI/SynopsisValidator.php | 17 +++++++++++++++++ tests/test-arg-validation.php | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 5d6145f37..07cbee7b3 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -167,6 +167,12 @@ private function validate_args( $args, &$assoc_args ) { exit(1); } + $unknown_positionals = $validator->unknown_positionals( $args ); + if ( !empty( $unknown_positionals ) ) { + \WP_CLI::warning( 'Too many positional arguments: ' . + implode( ' ', $unknown_positionals ) ); + } + list( $errors, $to_unset ) = $validator->validate_assoc( array_merge( \WP_CLI::get_config(), $assoc_args ) ); if ( !empty( $errors['fatal'] ) ) { diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index ed67928ef..ee0b824c4 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -28,6 +28,23 @@ public function enough_positionals( $args ) { return count( $args ) >= count( $positional ); } + public function unknown_positionals( $args ) { + $positional_repeating = $this->query_spec( array( + 'type' => 'positional', + 'repeating' => true, + ) ); + + if ( !empty( $positional_repeating ) ) + return array(); + + $positional = $this->query_spec( array( + 'type' => 'positional', + 'repeating' => false, + ) ); + + return array_slice( $args, count( $positional ) ); + } + // Checks that all required keys are present and that they have values. public function validate_assoc( $assoc_args ) { $assoc_spec = $this->query_spec( array( diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php index 7db636a52..4a3b3680c 100644 --- a/tests/test-arg-validation.php +++ b/tests/test-arg-validation.php @@ -10,6 +10,8 @@ function testMissingPositional() { $this->assertFalse( $validator->enough_positionals( array() ) ); $this->assertTrue( $validator->enough_positionals( array( 1, 2 ) ) ); $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3, 4 ) ) ); + + $this->assertEquals( array( 4 ), $validator->unknown_positionals( array( 1, 2, 3, 4 ) ) ); } function testRepeatingPositional() { @@ -18,6 +20,8 @@ function testRepeatingPositional() { $this->assertFalse( $validator->enough_positionals( array() ) ); $this->assertTrue( $validator->enough_positionals( array( 1 ) ) ); $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3 ) ) ); + + $this->assertEmpty( $validator->unknown_positionals( array( 1, 2, 3 ) ) ); } function testUnknownAssocEmpty() { From e03258378c66a5665cb417afa7c23ece4ae38f7a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 05:17:44 +0300 Subject: [PATCH 2322/5359] fix synopsis for 'wp help' --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 343b4e355..c56e47f12 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -16,7 +16,7 @@ class Help_Command extends WP_CLI_Command { * # get help for `core download` subcommand * wp help core download * - * @synopsis [<command>] + * @synopsis [<command>...] */ function __invoke( $args, $assoc_args ) { $command = self::find_subcommand( $args ); From 7295a52e62575f1edbbef776aa6f27ca51d1237d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 05:24:21 +0300 Subject: [PATCH 2323/5359] fix synopsis for 'wp option' --- php/commands/option.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 7f3e87a16..1c4c66095 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -39,7 +39,7 @@ public function get( $args, $assoc_args ) { /** * Add an option. * - * @synopsis <key> [--format=<format>] + * @synopsis <key> <value> [--format=<format>] */ public function add( $args, $assoc_args ) { $key = $args[0]; @@ -57,7 +57,7 @@ public function add( $args, $assoc_args ) { * Update an option. * * @alias set - * @synopsis <key> [--format=<format>] + * @synopsis <key> <value> [--format=<format>] */ public function update( $args, $assoc_args ) { $key = $args[0]; From 5e9c78fe9a1ee44887d00dc03d9a1e846e4327c3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 29 Sep 2013 06:02:38 +0300 Subject: [PATCH 2324/5359] fix bug where $_SERVER['SERVER_NAME'] was set incorrectly closes #765 --- features/flags.feature | 10 +++++++--- php/WP_CLI/Runner.php | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index ee07a67c7..7cd0288f7 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -3,10 +3,14 @@ Feature: Global flags Scenario: Setting the URL Given a WP install - When I run `wp --url=localhost:8001 eval 'echo $_SERVER["SERVER_PORT"];'` - Then STDOUT should be: + When I run `wp --url=localhost:8001 eval 'echo json_encode( $_SERVER );'` + Then STDOUT should be JSON containing: """ - 8001 + { + "HTTP_HOST": "localhost:8001", + "SERVER_NAME": "localhost", + "SERVER_PORT": "8001" + } """ Scenario: Quiet run diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a81e0d5a8..0d37f11a3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -154,7 +154,7 @@ private static function set_url_params( $url_parts ) { $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; } - $_SERVER['SERVER_NAME'] = substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.')); + $_SERVER['SERVER_NAME'] = $url_parts['host']; } $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); From b84a9541cf42262d47ec56ebac0b84cb6a500a37 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 30 Sep 2013 15:09:51 +0200 Subject: [PATCH 2325/5359] Implement `wp theme get --field=<field>` --- features/theme.feature | 6 +++++ php/WP_CLI/CommandWithUpgrade.php | 41 +++++++++++++++++++++++++++++++ php/commands/theme.php | 22 ++++++----------- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 400197788..59dfb0096 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -87,3 +87,9 @@ Feature: Manage WordPress themes Then STDOUT should be a table containing rows: | Field | Value | | name | P2 | + + When I run `wp theme get p2 --field=title` + Then STDOUT should contain: + """ + P2 + """ diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index d868cf772..efe1c3eb6 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -102,6 +102,47 @@ private function show_legend( $items ) { \WP_CLI::line( 'Legend: ' . implode( ', ', \WP_CLI::colorize( $legend_line ) ) ); } + protected function find_field( $item, $field ) { + foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { + if ( isset( $item->$key ) ) { + return $key; + } + } + + return false; + } + + protected function show_single_field( $items, $field ) { + foreach ( $items as $item ) { + if ( !isset( $key ) ) { + $key = $this->find_field( $item, $field ); + if ( !$key ) { + \WP_CLI::error( "Invalid $this->obj_type field: $field." ); + } + } + + \WP_CLI::print_value( $item->$key ); + } + } + + protected function show_multiple_fields( $data, $assoc_args ) { + switch ( $assoc_args['format'] ) { + + case 'table': + \WP_CLI\Utils\assoc_array_to_table( $data ); + break; + + case 'json': + WP_CLI::print_value( $data, $assoc_args ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); + break; + + } + } + function install( $args, $assoc_args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); diff --git a/php/commands/theme.php b/php/commands/theme.php index e8932ee05..4f85066a0 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -256,6 +256,9 @@ function install( $args, $assoc_args ) { * * <theme> * : The theme to get. + * + * [--field=<field>] + * : Instead of returning the whole theme, returns the value of a single field. * * [--format=<format>] * : Output list as table or JSON. Defaults to table. @@ -280,21 +283,10 @@ public function get( $args, $assoc_args ) { $theme_obj->$var = $theme->$var; } - switch ( $assoc_args['format'] ) { - - case 'table': - unset( $theme_obj->tags ); - $fields = get_object_vars( $theme_obj ); - \WP_CLI\Utils\assoc_array_to_table( $fields ); - break; - - case 'json': - WP_CLI::print_value( $theme_obj, $assoc_args ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; + if ( isset( $assoc_args['field'] ) ) { + $this->show_single_field( array( $theme_obj ), $assoc_args['field'] ); + } else { + $this->show_multiple_fields( $theme_obj, $assoc_args ); } } From e82a04ef45e492855e95cda785e6df7d3c4ddea0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 30 Sep 2013 15:18:15 +0200 Subject: [PATCH 2326/5359] Wordwrap the description --- php/commands/theme.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 4f85066a0..abb66bf0b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -283,6 +283,8 @@ public function get( $args, $assoc_args ) { $theme_obj->$var = $theme->$var; } + $theme_obj->description = wordwrap( $theme_obj->description ); + if ( isset( $assoc_args['field'] ) ) { $this->show_single_field( array( $theme_obj ), $assoc_args['field'] ); } else { From a91d8b186059b0fe56230c605ab94bea0102ed28 Mon Sep 17 00:00:00 2001 From: Mike Schroder <mike.schroder@dreamhost.com> Date: Mon, 30 Sep 2013 11:51:56 -0700 Subject: [PATCH 2327/5359] framework: Allow third-party Mustache templates Allow arbitrary mustache template to be supplied in mustache_render. --- php/utils.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 84289730e..ad4129ed5 100644 --- a/php/utils.php +++ b/php/utils.php @@ -442,7 +442,10 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { } function mustache_render( $template_name, $data ) { - $template = file_get_contents( WP_CLI_ROOT . "/templates/$template_name" ); + if ( ! file_exists( $template_name ) ) + $template_name = WP_CLI_ROOT . "/templates/$template_name"; + + $template = file_get_contents( $template_name ); $m = new \Mustache_Engine; From a66f523c3c0569f984dce897e6e43914b6c00bd2 Mon Sep 17 00:00:00 2001 From: Doug Cone <nullvariable@gmail.com> Date: Mon, 30 Sep 2013 17:59:37 -0400 Subject: [PATCH 2328/5359] rewrote the object loop to only deal with top level values that are unserialized. Anything deeper than the first level will be ignored. --- php/utils.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 84289730e..0b8e56875 100644 --- a/php/utils.php +++ b/php/utils.php @@ -197,6 +197,7 @@ function locate_wp_config() { /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. + * Will only handle the first level of any object to avoid recursions. * * @source https://github.com/interconnectit/Search-Replace-DB * @@ -228,7 +229,20 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria elseif ( is_object( $data ) ) { $_tmp = clone( $data ); foreach ( $data as $key => $value ) { - $_tmp->$key = recursive_unserialize_replace( $from, $to, $value, false ); + + if ( is_string( $value ) ) { + $data[$key] = str_replace( $from, $to, $value ); + } + + elseif ( is_array( $value ) ) { + $_tmp = array(); + foreach ( $value as $key => $sub_value ) { + $_tmp[ $key ] = str_replace( $from, $to, $sub_value ); + } + + $value = $_tmp; + } + } $data = $_tmp; @@ -237,6 +251,7 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria else { if ( is_string( $data ) ) $data = str_replace( $from, $to, $data ); + } if ( $serialised ) From ca668676b8bcc836a6119678bc92e463db0a3785 Mon Sep 17 00:00:00 2001 From: Doug Cone <nullvariable@gmail.com> Date: Mon, 30 Sep 2013 18:28:18 -0400 Subject: [PATCH 2329/5359] search-replace will ignore all object data types to avoid recursion. --- php/utils.php | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/php/utils.php b/php/utils.php index 0b8e56875..55b1cffc5 100644 --- a/php/utils.php +++ b/php/utils.php @@ -197,7 +197,7 @@ function locate_wp_config() { /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. - * Will only handle the first level of any object to avoid recursions. + * Ignores any serialized objects.. * * @source https://github.com/interconnectit/Search-Replace-DB * @@ -226,32 +226,9 @@ function recursive_unserialize_replace( $from = '', $to = '', $data = '', $seria $data = $_tmp; } - elseif ( is_object( $data ) ) { - $_tmp = clone( $data ); - foreach ( $data as $key => $value ) { - - if ( is_string( $value ) ) { - $data[$key] = str_replace( $from, $to, $value ); - } - - elseif ( is_array( $value ) ) { - $_tmp = array(); - foreach ( $value as $key => $sub_value ) { - $_tmp[ $key ] = str_replace( $from, $to, $sub_value ); - } - - $value = $_tmp; - } - - } - - $data = $_tmp; - } - else { if ( is_string( $data ) ) $data = str_replace( $from, $to, $data ); - } if ( $serialised ) From aca91d24968dd21181ede202ad049e0728edb67f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 01:58:30 +0300 Subject: [PATCH 2330/5359] rename `wp rewrite dump` to `wp rewrite list` ... and make its output consistent with the rest of the commands --- php/commands/rewrite.php | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 8b8ebc552..27888bd07 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -94,35 +94,31 @@ public function structure( $args, $assoc_args ) { * ## OPTIONS * * [--format=<format>] - * : Output list as JSON. Defaults to tab-separated lines. + * : Output list as table, JSON or CSV. Defaults to table. * * ## EXAMPLES * - * wp rewrite dump --format=json + * wp rewrite list --format=csv + * @subcommand list */ - public function dump( $args, $assoc_args ) { + public function _list( $args, $assoc_args ) { $rules = get_option( 'rewrite_rules' ); if ( ! $rules ) { $rules = array(); WP_CLI::warning( 'No rewrite rules.' ); } + $defaults = array( - 'format' => '' + 'format' => 'table' ); $assoc_args = array_merge( $defaults, $assoc_args ); - switch ( $assoc_args['format'] ) { - - case 'json': - echo json_encode( $rules ); - break; - - default: - foreach ( $rules as $route => $rule ) - WP_CLI::line( $route . "\t" . $rule ); - break; - + $rule_list = array(); + foreach ( $rules as $match => $query ) { + $rule_list[] = compact( 'match', 'query' ); } + + WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, array('match', 'query') ); } /** From ca826c7d2156f8d21c9529858ac59e7f19e297f4 Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Mon, 30 Sep 2013 16:07:20 -0700 Subject: [PATCH 2331/5359] Check for non-string exit code after `wp post edit` Fixes bug introduced in f592cff, where quitting out of the system editor would erase a post, because the `content_save_pre` filter would fail to interpret system exit codes, and treat them as an empty string. There must be a way to write a test for behavior like this, but how to actually do that is beyond my knowledge. I did test with several different $EDITOR settings (vi/nano/gedit), though, and this worked each time for me. --- php/commands/post.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 51e288f52..ae2127735 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -125,7 +125,8 @@ public function edit( $args, $_ ) { protected function _edit( $content, $title ) { $content = apply_filters( 'the_editor_content', $content ); $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title ); - return apply_filters( 'content_save_pre', $output ); + return ( is_string( $output ) ) ? + apply_filters( 'content_save_pre', $output ) : $output; } /** From eaebd7d42b8139ff6fc94cecb182b8e64db87839 Mon Sep 17 00:00:00 2001 From: Doug Cone <nullvariable@gmail.com> Date: Mon, 30 Sep 2013 19:23:54 -0400 Subject: [PATCH 2332/5359] removed unneeded object test case. --- tests/test-unserialize-replace.php | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 tests/test-unserialize-replace.php diff --git a/tests/test-unserialize-replace.php b/tests/test-unserialize-replace.php deleted file mode 100644 index 3389336f3..000000000 --- a/tests/test-unserialize-replace.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { - - function testPrivateConstructor() { - $old_obj = ClassWithPrivateConstructor::get_instance(); - - $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_obj ); - $this->assertEquals( 'bar', $new_obj->prop ); - } -} - - -class ClassWithPrivateConstructor { - - public $prop = 'foo'; - - private function __construct() {} - - public static function get_instance() { - return new self; - } -} - From 8decffd8893fd471497108e5079ff33b39e23f74 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 02:38:36 +0300 Subject: [PATCH 2333/5359] move recursive_unserialize_replace() into Search_Replace_Command class it's not meant to be a general-purpose utility; its behaviour changes according to the needs of the search-replace command --- php/commands/search-replace.php | 47 ++++++++++++++++++++++++++++++++- php/utils.php | 47 --------------------------------- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c7e80dac3..fbeeec184 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -124,7 +124,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry if ( '' === $row->$col ) continue; - $value = \WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col ); + $value = self::recursive_unserialize_replace( $old, $new, $row->$col ); if ( $dry_run ) { if ( $value != $row->$col ) @@ -140,6 +140,51 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry return $count; } + /** + * Take a serialised array and unserialise it replacing elements as needed and + * unserialising any subordinate arrays and performing the replace on those too. + * Ignores any serialized objects. + * + * Initial code from https://github.com/interconnectit/Search-Replace-DB + * + * @param string $from String we're looking to replace. + * @param string $to What we want it to be replaced with + * @param array $data Used to pass any subordinate arrays back to in. + * @param bool $serialised Does the array passed via $data need serialising. + * + * @return array The original array with all elements replaced as needed. + */ + private static function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) { + + // some unseriliased data cannot be re-serialised eg. SimpleXMLElements + try { + + if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { + $data = self::recursive_unserialize_replace( $from, $to, $unserialized, true ); + } + + elseif ( is_array( $data ) ) { + $_tmp = array(); + foreach ( $data as $key => $value ) { + $_tmp[ $key ] = self::recursive_unserialize_replace( $from, $to, $value, false ); + } + $data = $_tmp; + } + + else if ( is_string( $data ) ) { + $data = str_replace( $from, $to, $data ); + } + + if ( $serialised ) + return serialize( $data ); + + } catch( Exception $error ) { + + } + + return $data; + } + private static function get_columns( $table ) { global $wpdb; diff --git a/php/utils.php b/php/utils.php index 404d8d51d..c44e6e4de 100644 --- a/php/utils.php +++ b/php/utils.php @@ -194,53 +194,6 @@ function locate_wp_config() { return $path; } -/** - * Take a serialised array and unserialise it replacing elements as needed and - * unserialising any subordinate arrays and performing the replace on those too. - * Ignores any serialized objects.. - * - * @source https://github.com/interconnectit/Search-Replace-DB - * - * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with - * @param array $data Used to pass any subordinate arrays back to in. - * @param bool $serialised Does the array passed via $data need serialising. - * - * @return array The original array with all elements replaced as needed. - */ -function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) { - - // some unseriliased data cannot be re-serialised eg. SimpleXMLElements - try { - - if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { - $data = recursive_unserialize_replace( $from, $to, $unserialized, true ); - } - - elseif ( is_array( $data ) ) { - $_tmp = array(); - foreach ( $data as $key => $value ) { - $_tmp[ $key ] = recursive_unserialize_replace( $from, $to, $value, false ); - } - - $data = $_tmp; - } - - else { - if ( is_string( $data ) ) - $data = str_replace( $from, $to, $data ); - } - - if ( $serialised ) - return serialize( $data ); - - } catch( Exception $error ) { - - } - - return $data; -} - /** * Output items in a table, JSON, CSV, ids, or the total count * From c20384efc717514f31dc3b0a6eeed254db84b0b7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 04:31:48 +0200 Subject: [PATCH 2334/5359] Introduce `show_single_field()` and `show_multiple_fields()`, helper methods for printing object data --- php/utils.php | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/php/utils.php b/php/utils.php index 84289730e..823627cf6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -364,6 +364,63 @@ function pick_fields( $item, $fields ) { return $values; } +/** + * Show a single field from a list of items + * + * @param array Array of objects to show fields from + * @param string The field to show + * @param string Whether or not the field is typically prefixed (e.g. "content" => "post_content") + */ +function show_single_field( $items, $field, $field_prefix = '' ) { + + foreach ( $items as $item ) { + + if ( ! isset( $key ) ) { + + foreach ( array( $field, $field_prefix . '_' . $field ) as $maybe_key ) { + if ( isset( $item->$maybe_key ) ) { + $key = $maybe_key; + break; + } + } + + if ( ! $key ) { + \WP_CLI::error( "Invalid field: $field." ); + } + + } + + \WP_CLI::print_value( $item->$key ); + } + +} + +/** + * Show multiple fields of an object + * + * @param object|array Data to display + * @param string Format to display the data in + */ +function show_multiple_fields( $data, $format ) { + + switch ( $format ) { + + case 'table': + assoc_array_to_table( $data ); + break; + + case 'json': + \WP_CLI::print_value( $data, array( 'format' => $format ) ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $format ); + break; + + } + +} + /** * Launch system's $EDITOR to edit text * From ee618c07266d02ea47497b6187bf7a5d4dcb73c1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 04:38:16 +0200 Subject: [PATCH 2335/5359] Convert `wp theme get` to use new util function --- php/WP_CLI/CommandWithUpgrade.php | 41 ------------------------------- php/commands/theme.php | 4 +-- 2 files changed, 2 insertions(+), 43 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index efe1c3eb6..d868cf772 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -102,47 +102,6 @@ private function show_legend( $items ) { \WP_CLI::line( 'Legend: ' . implode( ', ', \WP_CLI::colorize( $legend_line ) ) ); } - protected function find_field( $item, $field ) { - foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { - if ( isset( $item->$key ) ) { - return $key; - } - } - - return false; - } - - protected function show_single_field( $items, $field ) { - foreach ( $items as $item ) { - if ( !isset( $key ) ) { - $key = $this->find_field( $item, $field ); - if ( !$key ) { - \WP_CLI::error( "Invalid $this->obj_type field: $field." ); - } - } - - \WP_CLI::print_value( $item->$key ); - } - } - - protected function show_multiple_fields( $data, $assoc_args ) { - switch ( $assoc_args['format'] ) { - - case 'table': - \WP_CLI\Utils\assoc_array_to_table( $data ); - break; - - case 'json': - WP_CLI::print_value( $data, $assoc_args ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; - - } - } - function install( $args, $assoc_args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); diff --git a/php/commands/theme.php b/php/commands/theme.php index abb66bf0b..20c460e5e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -286,9 +286,9 @@ public function get( $args, $assoc_args ) { $theme_obj->description = wordwrap( $theme_obj->description ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( array( $theme_obj ), $assoc_args['field'] ); + \WP_CLI\Utils\show_single_field( array( $theme_obj ), $assoc_args['field'] ); } else { - $this->show_multiple_fields( $theme_obj, $assoc_args ); + \WP_CLI\Utils\show_multiple_fields( $theme_obj, $assoc_args['format'] ); } } From 2fbde59b1139fbd3da4828025e25242528adbeae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 04:43:18 +0200 Subject: [PATCH 2336/5359] Convert `wp comment get` to new util functions --- php/commands/comment.php | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 8ca730efd..fecff3cb7 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -111,28 +111,16 @@ public function get( $args, $assoc_args ) { WP_CLI::error( "Invalid comment ID." ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( array( $comment ), $assoc_args['field'] ); - } else { - $this->show_multiple_fields( $comment, $assoc_args ); - } - } - private function show_multiple_fields( $comment, $assoc_args ) { - switch ( $assoc_args['format'] ) { + \WP_CLI\Utils\show_single_field( array( $comment ), $assoc_args['field'], 'comment' ); - case 'table': - $fields = get_object_vars( $comment ); - unset( $fields['comment_content'] ); - \WP_CLI\Utils\assoc_array_to_table( $fields ); - break; + } else { - case 'json': - WP_CLI::print_value( $comment, $assoc_args ); - break; + $comment = get_object_vars( $comment ); + if ( 'table' == $assoc_args['format'] ) + unset( $comment['comment_content'] ); - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; + \WP_CLI\Utils\show_multiple_fields( $comment, $assoc_args['format'] ); } } @@ -189,7 +177,7 @@ public function _list( $_, $assoc_args ) { } if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $comments, $assoc_args['field'] ); + \WP_CLI\Utils\show_single_field( $comments, $assoc_args['field'], 'comment' ); } else { WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); } From cff0bb698d3bbec857f67a8b6b28ee45eb091ca7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 04:52:55 +0200 Subject: [PATCH 2337/5359] Have `show_single_field()` logically persist the `--format` argument. --- features/theme.feature | 6 ++++++ php/commands/comment.php | 4 ++-- php/commands/theme.php | 2 +- php/utils.php | 13 +++++++++++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 59dfb0096..a57480f47 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -93,3 +93,9 @@ Feature: Manage WordPress themes """ P2 """ + + When I run `wp theme get p2 --field=title --format=json` + Then STDOUT should contain: + """ + {"title":"P2"} + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index fecff3cb7..707e02a41 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -112,7 +112,7 @@ public function get( $args, $assoc_args ) { if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( array( $comment ), $assoc_args['field'], 'comment' ); + \WP_CLI\Utils\show_single_field( array( $comment ), $assoc_args['field'], $assoc_args['format'], 'comment' ); } else { @@ -177,7 +177,7 @@ public function _list( $_, $assoc_args ) { } if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( $comments, $assoc_args['field'], 'comment' ); + \WP_CLI\Utils\show_single_field( $comments, $assoc_args['field'], $assoc_args['format'], 'comment' ); } else { WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 20c460e5e..abea4ae6b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -286,7 +286,7 @@ public function get( $args, $assoc_args ) { $theme_obj->description = wordwrap( $theme_obj->description ); if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( array( $theme_obj ), $assoc_args['field'] ); + \WP_CLI\Utils\show_single_field( array( $theme_obj ), $assoc_args['field'], $assoc_args['format'] ); } else { \WP_CLI\Utils\show_multiple_fields( $theme_obj, $assoc_args['format'] ); } diff --git a/php/utils.php b/php/utils.php index 823627cf6..062db61c2 100644 --- a/php/utils.php +++ b/php/utils.php @@ -369,9 +369,10 @@ function pick_fields( $item, $fields ) { * * @param array Array of objects to show fields from * @param string The field to show + * @param string The format to show the field in * @param string Whether or not the field is typically prefixed (e.g. "content" => "post_content") */ -function show_single_field( $items, $field, $field_prefix = '' ) { +function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { foreach ( $items as $item ) { @@ -390,7 +391,15 @@ function show_single_field( $items, $field, $field_prefix = '' ) { } - \WP_CLI::print_value( $item->$key ); + // Persist the field name for JSON + if ( 'json' == $format ) { + $data = new \stdClass; + $data->$key = $item->$key; + } else { + $data = $item->$key; + } + + \WP_CLI::print_value( $data, array( 'format' => $format ) ); } } From 1639e9bd84a315cf88e405a698095d95bd7abca6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:00:16 +0200 Subject: [PATCH 2338/5359] Run moar faster --- features/theme.feature | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index a57480f47..d8c18f5cd 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -1,8 +1,9 @@ Feature: Manage WordPress themes - Scenario: Installing a theme + Background: Given a WP install + Scenario: Installing a theme When I run `wp theme install p2` Then STDOUT should not be empty @@ -44,8 +45,6 @@ Feature: Manage WordPress themes Then STDOUT should not be empty Scenario: Install a theme, activate, then force install an older version of the theme - Given a WP install - When I run `wp theme install p2 --version=1.4.2` Then STDOUT should not be empty @@ -66,8 +65,6 @@ Feature: Manage WordPress themes | p2 | active | available | 1.4.1 | Scenario: Get the path of an installed theme - Given a WP install - When I run `wp theme install p2` Then STDOUT should not be empty @@ -78,8 +75,6 @@ Feature: Manage WordPress themes """ Scenario: Get details about an installed theme - Given a WP install - When I run `wp theme install p2` Then STDOUT should not be empty From 9ca5a468f59ebf60516c8122f9c145159f62fa00 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:03:16 +0200 Subject: [PATCH 2339/5359] Convert `wp user *` to new util functions. --- php/commands/user.php | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index eb0784546..171d91da5 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -81,7 +81,7 @@ public function _list( $args, $assoc_args ) { } ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $it, $assoc_args['field'] ); + \WP_CLI\Utils\show_single_field( $it, $assoc_args['field'], $assoc_args['format'], 'user' ); } else { WP_CLI\Utils\format_items( $params['format'], $it, $fields ); } @@ -127,27 +127,9 @@ public function get( $args, $assoc_args ) { $user_data['roles'] = implode( ', ', $user->roles ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( array( (object) $user_data ), $assoc_args['field'] ); + \WP_CLI\Utils\show_single_field( array( (object) $user_data ), $assoc_args['field'], $assoc_args['format'], 'user' ); } else { - $this->show_multiple_fields( $user_data, $assoc_args ); - } - } - - private function show_multiple_fields( $user_data, $assoc_args ) { - switch ( $assoc_args['format'] ) { - - case 'table': - \WP_CLI\Utils\assoc_array_to_table( $user_data ); - break; - - case 'json': - WP_CLI::print_value( $user_data, $assoc_args ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; - + \WP_CLI\Utils\show_multiple_fields( $user_data, $assoc_args['format'] ); } } From 537c215404705bbb05b1971074c5d42f5c29404f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:07:30 +0200 Subject: [PATCH 2340/5359] Convert `wp site list` to new util function. --- php/commands/site.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index f62585407..782d62127 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -356,7 +356,7 @@ function _list( $_, $assoc_args ) { } ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $it, $assoc_args['field'] ); + WP_CLI\Utils\show_single_field( $it, $assoc_args['field'], $assoc_args['format'], 'site' ); } else { WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); } From 5aee26adc1ea16cfea9585cb3298b67970149b0d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:08:35 +0200 Subject: [PATCH 2341/5359] Method isn't used anymore --- php/commands/site.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 782d62127..5af9489a7 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -362,13 +362,6 @@ function _list( $_, $assoc_args ) { } } - protected function find_field( $item, $field ) { - if ( 'url' == $field ) - return 'url'; - - return parent::find_field( $item, $field ); - } - /** * Get site (network) data for a given id. * From d9b509e6229028e729437aa0f245907e8e8c4cc6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:09:03 +0200 Subject: [PATCH 2342/5359] Convert `wp post *` to new util functions. --- php/commands/post.php | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 1c6673a55..422106096 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -163,31 +163,19 @@ public function get( $args, $assoc_args ) { \WP_CLI::error( "Could not find the post with ID $post_id." ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( array( $post ), $assoc_args['field'] ); - } else { - $this->show_multiple_fields( $post, $assoc_args ); - } - } - private function show_multiple_fields( $post, $assoc_args ) { - switch ( $assoc_args['format'] ) { + \WP_CLI\Utils\show_single_field( array( $post ), $assoc_args['field'], $assoc_args['format'], 'post' ); - case 'table': - $fields = get_object_vars( $post ); - unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); - \WP_CLI\Utils\assoc_array_to_table( $fields ); - break; + } else { - case 'json': $fields = get_object_vars( $post ); - unset( $fields['filter'] ); - WP_CLI::print_value( $fields, $assoc_args ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; + if ( 'table' == $assoc_args['format'] ) + unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); + else if ( 'json' == $assoc_args['format'] ) + unset( $fields['filter'] ); + + \WP_CLI\Utils\show_multiple_fields( $fields, $assoc_args['format'] ); } } @@ -279,7 +267,7 @@ public function _list( $_, $assoc_args ) { $query = new WP_Query( $query_args ); if ( isset( $assoc_args['field'] ) ) { - $this->show_single_field( $query->posts, $assoc_args['field'] ); + WP_CLI\Utils\show_single_field( $query->posts, $assoc_args['field'], $assoc_args['format'], 'post' ); } else { WP_CLI\Utils\format_items( $assoc_args['format'], $query->posts, $assoc_args['fields'] ); } From 97741b2c5de8768e964f5bc615a2bea412e45767 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:09:33 +0200 Subject: [PATCH 2343/5359] Remove unused methods --- php/WP_CLI/CommandWithDBObject.php | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index d8dbe8433..a9ed660be 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -78,27 +78,5 @@ protected function success_or_failure( $r ) { return $status; } - protected function show_single_field( $items, $field ) { - foreach ( $items as $item ) { - if ( !isset( $key ) ) { - $key = $this->find_field( $item, $field ); - if ( !$key ) { - \WP_CLI::error( "Invalid $this->obj_type field: $field." ); - } - } - - \WP_CLI::print_value( $item->$key ); - } - } - - protected function find_field( $item, $field ) { - foreach ( array( $field, $this->obj_type . '_' . $field ) as $key ) { - if ( isset( $item->$key ) ) { - return $key; - } - } - - return false; - } } From cd2dc66bd7ef87e1449a8e3d3b061ea5bc894c27 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:36:00 +0200 Subject: [PATCH 2344/5359] Simplify again --- features/plugin.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 26bd999c1..698e63ad3 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -1,7 +1,9 @@ Feature: Manage WordPress plugins - Scenario: Create, activate and check plugin status + Background: Given a WP install + + Scenario: Create, activate and check plugin status And I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} @@ -66,8 +68,6 @@ Feature: Manage WordPress plugins """ Scenario: Install a plugin, activate, then force install an older version of the plugin - Given a WP install - When I run `wp plugin install akismet --version=2.5.7 --force` Then STDOUT should not be empty From f2a52c40f5823c1832dacc241779327037e676ac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:37:45 +0200 Subject: [PATCH 2345/5359] Introduce `wp plugin get` Closes #796 --- features/plugin.feature | 21 +++++++++++++++++ php/commands/plugin.php | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 698e63ad3..d641f64a1 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -86,3 +86,24 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | update | version | | akismet | active | available | 2.5.6 | + + Scenario: Get details about an installed plugin + + When I run `wp plugin get akismet` + Then STDOUT should be a table containing rows: + | Field | Value | + | name | akismet | + + + When I run `wp plugin get akismet --field=title` + Then STDOUT should contain: + """ + Akismet + """ + + When I run `wp plugin get akismet --field=title --format=json` + Then STDOUT should contain: + """ + {"title":"Akismet"} + """ + diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 92568e6ed..1ca6670e5 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -368,6 +368,56 @@ function install( $args, $assoc_args ) { parent::install( $args, $assoc_args ); } + /** + * Get a plugin. + * + * ## OPTIONS + * + * <plugin> + * : The plugin to get. + * + * [--field=<field>] + * : Instead of returning the whole plugin, returns the value of a single field. + * + * [--format=<format>] + * : Output list as table or JSON. Defaults to table. + * + * ## EXAMPLES + * + * wp plugin get bbpress --format=json + */ + public function get( $args, $assoc_args ) { + + $defaults = array( + 'format' => 'table' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $file = $this->_parse_name( $args[0] ); + + $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); + + $plugin_obj = (object)array( + 'name' => $this->get_name( $file ), + 'title' => $plugin_data['Name'], + 'author' => $plugin_data['Author'], + 'version' => $plugin_data['Version'], + 'description' => wordwrap( $plugin_data['Description'] ), + 'status' => $this->get_status( $file ), + 'update' => $this->has_update( $file ), + ); + + if ( isset( $assoc_args['field'] ) ) { + + \WP_CLI\Utils\show_single_field( array( $plugin_obj ), $assoc_args['field'], $assoc_args['format'] ); + + } else { + + \WP_CLI\Utils\show_multiple_fields( $plugin_obj, $assoc_args['format'] ); + + } + } + /** * Uninstall a plugin. * From 18c90b3508365d8175b9cfc63037a18b39a29993 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 05:49:52 +0200 Subject: [PATCH 2346/5359] `--field=<field>` support for `wp term list` and `wp term get` --- features/term.feature | 6 ++++++ php/commands/term.php | 35 +++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/features/term.feature b/features/term.feature index b0e1e0487..6d0b6df92 100644 --- a/features/term.feature +++ b/features/term.feature @@ -39,6 +39,12 @@ Feature: Manage WordPress terms Then STDOUT should be a number And save STDOUT as {TERM_ID} + When I run `wp term get {TERM_ID} post_tag --field=slug --format=json` + Then STDOUT should contain: + """ + {"slug":"test-delete"} + """ + When I run `wp term delete {TERM_ID} post_tag` Then STDOUT should contain: """ diff --git a/php/commands/term.php b/php/commands/term.php index bcf58ac44..c2d760238 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -26,6 +26,9 @@ class Term_Command extends WP_CLI_Command { * * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_terms(). + * + * [--field=<field>] + * : Prints the value of a single field for each term. * * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to all of the term object fields. @@ -60,7 +63,16 @@ public function _list( $args, $assoc_args ) { if ( 'ids' == $assoc_args['format'] ) $terms = wp_list_pluck( $terms, 'term_id' ); - WP_CLI\Utils\format_items( $assoc_args['format'], $terms, $fields ); + if ( isset( $assoc_args['field'] ) ) { + + WP_CLI\Utils\show_single_field( $terms, $assoc_args['field'], $assoc_args['format'], 'term' ); + + } else { + + WP_CLI\Utils\format_items( $assoc_args['format'], $terms, $fields ); + + } + } /** @@ -130,6 +142,9 @@ public function create( $args, $assoc_args ) { * * <taxonomy> * : Taxonomy of the term to get + * + * [--field=<field>] + * : Instead of returning the whole term, returns the value of a single field. * * [--format=<format>] * : The format to use when printing the term, acceptable values: @@ -154,21 +169,17 @@ public function get( $args, $assoc_args ) { if ( ! $term ) WP_CLI::error( "Term doesn't exist." ); - switch ( $assoc_args['format'] ) { + if ( isset( $assoc_args['field'] ) ) { - case 'table': - $fields = get_object_vars( $term ); - \WP_CLI\Utils\assoc_array_to_table( $fields ); - break; + \WP_CLI\Utils\show_single_field( array( $term ), $assoc_args['field'], $assoc_args['format'], 'term' ); - case 'json': - WP_CLI::print_value( $term, $assoc_args ); - break; + } else { - default: - \WP_CLI::error( "Invalid format: " . $assoc_args['format'] ); - break; + $term = get_object_vars( $term ); + + \WP_CLI\Utils\show_multiple_fields( $term, $assoc_args['format'] ); } + } /** From 22809e03ed89a4327564b588571783b18b9430ca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 14:02:07 +0200 Subject: [PATCH 2347/5359] This is a better format See https://github.com/wp-cli/wp-cli/pull/795#issuecomment-25442654 --- features/plugin.feature | 2 +- features/term.feature | 2 +- features/theme.feature | 2 +- php/utils.php | 10 +--------- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index d641f64a1..3cd533783 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -104,6 +104,6 @@ Feature: Manage WordPress plugins When I run `wp plugin get akismet --field=title --format=json` Then STDOUT should contain: """ - {"title":"Akismet"} + {"Akismet"} """ diff --git a/features/term.feature b/features/term.feature index 6d0b6df92..0d60c3c8d 100644 --- a/features/term.feature +++ b/features/term.feature @@ -42,7 +42,7 @@ Feature: Manage WordPress terms When I run `wp term get {TERM_ID} post_tag --field=slug --format=json` Then STDOUT should contain: """ - {"slug":"test-delete"} + {"test-delete"} """ When I run `wp term delete {TERM_ID} post_tag` diff --git a/features/theme.feature b/features/theme.feature index d8c18f5cd..03064df9a 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -92,5 +92,5 @@ Feature: Manage WordPress themes When I run `wp theme get p2 --field=title --format=json` Then STDOUT should contain: """ - {"title":"P2"} + {"P2"} """ diff --git a/php/utils.php b/php/utils.php index 062db61c2..a07b0ab87 100644 --- a/php/utils.php +++ b/php/utils.php @@ -391,15 +391,7 @@ function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { } - // Persist the field name for JSON - if ( 'json' == $format ) { - $data = new \stdClass; - $data->$key = $item->$key; - } else { - $data = $item->$key; - } - - \WP_CLI::print_value( $data, array( 'format' => $format ) ); + \WP_CLI::print_value( $item->$key, array( 'format' => $format ) ); } } From 6a3ec7076af7e67f053a9b10d234eca5fa0f1929 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Oct 2013 14:03:07 +0200 Subject: [PATCH 2348/5359] Strings are strings --- features/plugin.feature | 2 +- features/term.feature | 2 +- features/theme.feature | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 3cd533783..bde1d71dd 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -104,6 +104,6 @@ Feature: Manage WordPress plugins When I run `wp plugin get akismet --field=title --format=json` Then STDOUT should contain: """ - {"Akismet"} + "Akismet" """ diff --git a/features/term.feature b/features/term.feature index 0d60c3c8d..375bc1d78 100644 --- a/features/term.feature +++ b/features/term.feature @@ -42,7 +42,7 @@ Feature: Manage WordPress terms When I run `wp term get {TERM_ID} post_tag --field=slug --format=json` Then STDOUT should contain: """ - {"test-delete"} + "test-delete" """ When I run `wp term delete {TERM_ID} post_tag` diff --git a/features/theme.feature b/features/theme.feature index 03064df9a..2cdf61a36 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -92,5 +92,5 @@ Feature: Manage WordPress themes When I run `wp theme get p2 --field=title --format=json` Then STDOUT should contain: """ - {"P2"} + "P2" """ From afb78ae980cc378d95e86300af405f4fa8388f08 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 16:36:55 +0300 Subject: [PATCH 2349/5359] whitespace fixes --- php/commands/plugin.php | 2 +- php/commands/post.php | 2 +- php/commands/term.php | 6 +++--- php/commands/theme.php | 2 +- php/utils.php | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1ca6670e5..1f1605ac7 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -375,7 +375,7 @@ function install( $args, $assoc_args ) { * * <plugin> * : The plugin to get. - * + * * [--field=<field>] * : Instead of returning the whole plugin, returns the value of a single field. * diff --git a/php/commands/post.php b/php/commands/post.php index 422106096..91ee1a47c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -174,7 +174,7 @@ public function get( $args, $assoc_args ) { unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); else if ( 'json' == $assoc_args['format'] ) unset( $fields['filter'] ); - + \WP_CLI\Utils\show_multiple_fields( $fields, $assoc_args['format'] ); } } diff --git a/php/commands/term.php b/php/commands/term.php index c2d760238..e9aad4400 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -26,7 +26,7 @@ class Term_Command extends WP_CLI_Command { * * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_terms(). - * + * * [--field=<field>] * : Prints the value of a single field for each term. * @@ -142,7 +142,7 @@ public function create( $args, $assoc_args ) { * * <taxonomy> * : Taxonomy of the term to get - * + * * [--field=<field>] * : Instead of returning the whole term, returns the value of a single field. * @@ -176,7 +176,7 @@ public function get( $args, $assoc_args ) { } else { $term = get_object_vars( $term ); - + \WP_CLI\Utils\show_multiple_fields( $term, $assoc_args['format'] ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index abea4ae6b..8b0c7b61e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -256,7 +256,7 @@ function install( $args, $assoc_args ) { * * <theme> * : The theme to get. - * + * * [--field=<field>] * : Instead of returning the whole theme, returns the value of a single field. * diff --git a/php/utils.php b/php/utils.php index 5404fa229..bdcaba124 100644 --- a/php/utils.php +++ b/php/utils.php @@ -310,8 +310,8 @@ function pick_fields( $item, $fields ) { } /** - * Show a single field from a list of items - * + * Show a single field from a list of items. + * * @param array Array of objects to show fields from * @param string The field to show * @param string The format to show the field in @@ -342,8 +342,8 @@ function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { } /** - * Show multiple fields of an object - * + * Show multiple fields of an object. + * * @param object|array Data to display * @param string Format to display the data in */ From a2f4ac8a3d23c14af76a9dace20455fb70c2e03e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 18:15:21 +0300 Subject: [PATCH 2350/5359] introduce WP_CLI\Formatter class --- php/WP_CLI/CommandWithDBObject.php | 4 +++ php/WP_CLI/CommandWithUpgrade.php | 4 +++ php/WP_CLI/Formatter.php | 50 ++++++++++++++++++++++++++++++ php/commands/comment.php | 50 ++++++------------------------ php/commands/plugin.php | 19 ++---------- php/commands/post.php | 50 ++++++------------------------ php/commands/site.php | 9 +++--- php/commands/term.php | 48 ++++++---------------------- php/commands/theme.php | 12 ++----- php/commands/user.php | 42 +++++-------------------- 10 files changed, 104 insertions(+), 184 deletions(-) create mode 100644 php/WP_CLI/Formatter.php diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index a9ed660be..a0785db23 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -11,6 +11,7 @@ abstract class CommandWithDBObject extends \WP_CLI_Command { protected $obj_type; protected $obj_id_key = 'ID'; + protected $obj_fields = null; protected function _create( $args, $assoc_args, $callback ) { unset( $assoc_args[ $this->obj_id_key ] ); @@ -78,5 +79,8 @@ protected function success_or_failure( $r ) { return $status; } + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, $this->obj_type ); + } } diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index d868cf772..39f754462 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -348,5 +348,9 @@ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) \WP_CLI\Utils\format_items( $format, $items, $assoc_args['fields'] ); } + + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, null, $this->item_type ); + } } diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php new file mode 100644 index 000000000..244ad9e6a --- /dev/null +++ b/php/WP_CLI/Formatter.php @@ -0,0 +1,50 @@ +<?php + +namespace WP_CLI; + +class Formatter { + + private $args; + private $prefix; + + public function __construct( &$assoc_args, $fields = null, $prefix = false ) { + $format_args = array( + 'format' => 'table', + 'fields' => $fields, + 'field' => null + ); + + foreach ( array( 'format', 'fields', 'field' ) as $key ) { + if ( isset( $assoc_args[ $key ] ) ) { + $format_args[ $key ] = $assoc_args[ $key ]; + unset( $assoc_args[ $key ] ); + } + } + + $this->args = $format_args; + $this->prefix = $prefix; + } + + public function __get( $key ) { + return $this->args[ $key ]; + } + + public function display_items( $items ) { + if ( $this->args['field'] ) { + \WP_CLI\Utils\show_single_field( $items, $this->args['field'], $this->args['format'], $this->prefix ); + } elseif ( $this->args['fields'] ) { + \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); + } else { + trigger_error( 'Both --field= and --fields= parameters are missing.', E_USER_ERROR ); + } + } + + public function display_item( $item ) { + if ( isset( $this->args['field'] ) ) { + \WP_CLI\Utils\show_single_field( array( (object) $item ), $this->args['field'], $this->args['format'], $this->prefix ); + } else { + \WP_CLI\Utils\show_multiple_fields( $item, $this->args['format'] ); + } + } +} + diff --git a/php/commands/comment.php b/php/commands/comment.php index 707e02a41..adefbcada 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -9,8 +9,7 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'comment'; protected $obj_id_key = 'comment_ID'; - - private $fields = array( + protected $obj_fields = array( 'comment_ID', 'comment_post_ID', 'comment_date', @@ -100,28 +99,13 @@ public function update( $args, $assoc_args ) { * wp comment get 1 --field=content */ public function get( $args, $assoc_args ) { - $defaults = array( - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $comment_id = (int)$args[0]; $comment = get_comment( $comment_id ); if ( empty( $comment ) ) WP_CLI::error( "Invalid comment ID." ); - if ( isset( $assoc_args['field'] ) ) { - - \WP_CLI\Utils\show_single_field( array( $comment ), $assoc_args['field'], $assoc_args['format'], 'comment' ); - - } else { - - $comment = get_object_vars( $comment ); - if ( 'table' == $assoc_args['format'] ) - unset( $comment['comment_content'] ); - - \WP_CLI\Utils\show_multiple_fields( $comment, $assoc_args['format'] ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $comment ); } /** @@ -152,35 +136,19 @@ public function get( $args, $assoc_args ) { * @subcommand list */ public function _list( $_, $assoc_args ) { - $query_args = array(); - $defaults = array( - 'format' => 'table', - 'fields' => $this->fields - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - foreach ( $assoc_args as $key => $value ) { - if ( true === $value ) - continue; - - $query_args[ $key ] = $value; - } + $formatter = $this->get_formatter( $assoc_args ); - if ( 'ids' == $assoc_args['format'] ) - $query_args['fields'] = 'ids'; + if ( 'ids' == $formatter->format ) + $assoc_args['fields'] = 'ids'; $query = new WP_Comment_Query(); - $comments = $query->query( $query_args ); + $comments = $query->query( $assoc_args ); - if ( 'ids' == $assoc_args['format'] ) { + if ( 'ids' == $formatter->format ) { $comments = wp_list_pluck( $comments, 'comment_ID' ); } - if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( $comments, $assoc_args['field'], $assoc_args['format'], 'comment' ); - } else { - WP_CLI\Utils\format_items( $assoc_args['format'], $comments, $assoc_args['fields'] ); - } + $formatter->display_items( $comments ); } /** diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1f1605ac7..e7742f666 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -387,12 +387,6 @@ function install( $args, $assoc_args ) { * wp plugin get bbpress --format=json */ public function get( $args, $assoc_args ) { - - $defaults = array( - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $file = $this->_parse_name( $args[0] ); $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); @@ -405,17 +399,10 @@ public function get( $args, $assoc_args ) { 'description' => wordwrap( $plugin_data['Description'] ), 'status' => $this->get_status( $file ), 'update' => $this->has_update( $file ), - ); - - if ( isset( $assoc_args['field'] ) ) { - - \WP_CLI\Utils\show_single_field( array( $plugin_obj ), $assoc_args['field'], $assoc_args['format'] ); - - } else { - - \WP_CLI\Utils\show_multiple_fields( $plugin_obj, $assoc_args['format'] ); + ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $plugin_obj ); } /** diff --git a/php/commands/post.php b/php/commands/post.php index 91ee1a47c..e4271d16d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -8,8 +8,7 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'post'; - - private $fields = array( + protected $obj_fields = array( 'ID', 'post_title', 'post_name', @@ -153,30 +152,15 @@ protected function _edit( $content, $title ) { * wp post get 12 --field=content > file.txt */ public function get( $args, $assoc_args ) { - $defaults = array( - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $post_id = $args[0]; if ( !$post_id || !$post = get_post( $post_id ) ) \WP_CLI::error( "Could not find the post with ID $post_id." ); - if ( isset( $assoc_args['field'] ) ) { - - \WP_CLI\Utils\show_single_field( array( $post ), $assoc_args['field'], $assoc_args['format'], 'post' ); - - } else { - - $fields = get_object_vars( $post ); - - if ( 'table' == $assoc_args['format'] ) - unset( $fields['filter'], $fields['post_content'], $fields['format_content'] ); - else if ( 'json' == $assoc_args['format'] ) - unset( $fields['filter'] ); + $post_arr = get_object_vars( $post ); + unset( $post_arr['filter'] ); - \WP_CLI\Utils\show_multiple_fields( $fields, $assoc_args['format'] ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $post_arr ); } /** @@ -243,34 +227,20 @@ public function delete( $args, $assoc_args ) { * @subcommand list */ public function _list( $_, $assoc_args ) { - $defaults = array( - 'format' => 'table', - 'fields' => $this->fields - ); - $assoc_args = array_merge( $defaults, $assoc_args ); + $formatter = $this->get_formatter( $assoc_args ); - $query_args = array( + $defaults = array( 'posts_per_page' => -1, 'post_status' => 'any', ); + $query_args = array_merge( $defaults, $assoc_args ); - foreach ( $assoc_args as $key => $value ) { - if ( true === $value ) - continue; - - $query_args[ $key ] = $value; - } - - if ( 'ids' == $assoc_args['format'] ) + if ( 'ids' == $formatter->format ) $query_args['fields'] = 'ids'; $query = new WP_Query( $query_args ); - if ( isset( $assoc_args['field'] ) ) { - WP_CLI\Utils\show_single_field( $query->posts, $assoc_args['field'], $assoc_args['format'], 'post' ); - } else { - WP_CLI\Utils\format_items( $assoc_args['format'], $query->posts, $assoc_args['fields'] ); - } + $formatter->display_items( $query->posts ); } /** diff --git a/php/commands/site.php b/php/commands/site.php index 5af9489a7..5bcdf6d62 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -7,6 +7,8 @@ */ class Site_Command extends \WP_CLI\CommandWithDBObject { + protected $obj_type = 'site'; + /** * Delete comments. */ @@ -355,11 +357,8 @@ function _list( $_, $assoc_args ) { return $blog; } ); - if ( isset( $assoc_args['field'] ) ) { - WP_CLI\Utils\show_single_field( $it, $assoc_args['field'], $assoc_args['format'], 'site' ); - } else { - WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); - } + $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); + $formatter->display_items( $it ); } /** diff --git a/php/commands/term.php b/php/commands/term.php index e9aad4400..770e5f3da 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -45,34 +45,18 @@ class Term_Command extends WP_CLI_Command { * @subcommand list */ public function _list( $args, $assoc_args ) { - - list( $taxonomy ) = $args; + $formatter = $this->get_formatter( $assoc_args ); $defaults = array( - 'fields' => implode( ',', $this->fields ), - 'format' => 'table', 'hide_empty' => false, ); - $assoc_args = wp_parse_args( $assoc_args, $defaults ); - - $fields = $assoc_args['fields']; - unset( $assoc_args['fields'] ); - - $terms = get_terms( array( $taxonomy ), $assoc_args ); + $assoc_args = array_merge( $defaults, $assoc_args ); - if ( 'ids' == $assoc_args['format'] ) + $terms = get_terms( $args, $assoc_args ); + if ( 'ids' == $formatter->format ) $terms = wp_list_pluck( $terms, 'term_id' ); - if ( isset( $assoc_args['field'] ) ) { - - WP_CLI\Utils\show_single_field( $terms, $assoc_args['field'], $assoc_args['format'], 'term' ); - - } else { - - WP_CLI\Utils\format_items( $assoc_args['format'], $terms, $fields ); - - } - + $formatter->display_items( $terms ); } /** @@ -157,29 +141,14 @@ public function create( $args, $assoc_args ) { * wp term get 1 category --format=json */ public function get( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); list( $term_id, $taxonomy ) = $args; - - $defaults = array( - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $term = get_term_by( 'id', $term_id, $taxonomy ); if ( ! $term ) WP_CLI::error( "Term doesn't exist." ); - if ( isset( $assoc_args['field'] ) ) { - - \WP_CLI\Utils\show_single_field( array( $term ), $assoc_args['field'], $assoc_args['format'], 'term' ); - - } else { - - $term = get_object_vars( $term ); - - \WP_CLI\Utils\show_multiple_fields( $term, $assoc_args['format'] ); - } - + $formatter->display_item( $term ); } /** @@ -263,6 +232,9 @@ public function delete( $args ) { WP_CLI::error( "Term doesn't exist." ); } + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'term' ); + } } WP_CLI::add_command( 'term', 'Term_Command' ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 8b0c7b61e..01533a754 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -268,11 +268,6 @@ function install( $args, $assoc_args ) { * wp theme get twentytwelve --format=json */ public function get( $args, $assoc_args ) { - $defaults = array( - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $theme = $this->parse_name( $args[0] ); // WP_Theme object employs magic getter, unfortunately @@ -285,11 +280,8 @@ public function get( $args, $assoc_args ) { $theme_obj->description = wordwrap( $theme_obj->description ); - if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( array( $theme_obj ), $assoc_args['field'], $assoc_args['format'] ); - } else { - \WP_CLI\Utils\show_multiple_fields( $theme_obj, $assoc_args['format'] ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $theme_obj ); } /** diff --git a/php/commands/user.php b/php/commands/user.php index 171d91da5..bc8f9afb1 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -8,8 +8,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'user'; - - private $fields = array( + protected $obj_fields = array( 'ID', 'user_login', 'display_name', @@ -49,27 +48,13 @@ class User_Command extends \WP_CLI\CommandWithDBObject { * @subcommand list */ public function _list( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); - $defaults = array( - 'blog_id' => get_current_blog_id(), - 'fields' => implode( ',', $this->fields ), - 'format' => 'table', - ); - $params = array_merge( $defaults, $assoc_args ); - - $fields = $params['fields']; - unset( $params['fields'] ); - - if ( array_key_exists( 'role', $assoc_args ) ) { - $params['role'] = $assoc_args['role']; + if ( 'ids' == $formatter->format ) { + $assoc_args['fields'] = 'ids'; } - if ( 'ids' == $params['format'] ) - $params['fields'] = 'ids'; - else - $params['fields'] = 'all_with_meta'; - - $users = get_users( $params ); + $users = get_users( $assoc_args ); $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { if ( !is_object( $user ) ) @@ -80,11 +65,7 @@ public function _list( $args, $assoc_args ) { return $user; } ); - if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( $it, $assoc_args['field'], $assoc_args['format'], 'user' ); - } else { - WP_CLI\Utils\format_items( $params['format'], $it, $fields ); - } + $formatter->display_items( $it ); } /** @@ -112,10 +93,6 @@ public function _list( $args, $assoc_args ) { * wp user get bob --format=json > bob.json */ public function get( $args, $assoc_args ) { - $assoc_args = wp_parse_args( $assoc_args, array( - 'format' => 'table' - ) ); - $user = self::get_user( $args[0] ); if ( method_exists( $user, 'to_array' ) ) { @@ -126,11 +103,8 @@ public function get( $args, $assoc_args ) { } $user_data['roles'] = implode( ', ', $user->roles ); - if ( isset( $assoc_args['field'] ) ) { - \WP_CLI\Utils\show_single_field( array( (object) $user_data ), $assoc_args['field'], $assoc_args['format'], 'user' ); - } else { - \WP_CLI\Utils\show_multiple_fields( $user_data, $assoc_args['format'] ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $user_data ); } /** From 801a6c19c7703f318ebb294fc1819f884949ddf4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 18:39:35 +0300 Subject: [PATCH 2351/5359] move disparate formatting utilities into the WP_CLI\Formatter class --- php/WP_CLI/Formatter.php | 86 ++++++++++++++++++++++++++++++++++++++-- php/utils.php | 80 ------------------------------------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 244ad9e6a..65cf87813 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -31,7 +31,7 @@ public function __get( $key ) { public function display_items( $items ) { if ( $this->args['field'] ) { - \WP_CLI\Utils\show_single_field( $items, $this->args['field'], $this->args['format'], $this->prefix ); + self::show_single_field( $items, $this->args['field'], $this->args['format'], $this->prefix ); } elseif ( $this->args['fields'] ) { \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); } else { @@ -41,10 +41,90 @@ public function display_items( $items ) { public function display_item( $item ) { if ( isset( $this->args['field'] ) ) { - \WP_CLI\Utils\show_single_field( array( (object) $item ), $this->args['field'], $this->args['format'], $this->prefix ); + self::show_single_field( array( (object) $item ), $this->args['field'], $this->args['format'], $this->prefix ); } else { - \WP_CLI\Utils\show_multiple_fields( $item, $this->args['format'] ); + self::show_multiple_fields( $item, $this->args['format'] ); } } + + /** + * Show a single field from a list of items. + * + * @param array Array of objects to show fields from + * @param string The field to show + * @param string The format to show the field in + * @param string Whether or not the field is typically prefixed (e.g. "content" => "post_content") + */ + private static function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { + + foreach ( $items as $item ) { + + if ( ! isset( $key ) ) { + + foreach ( array( $field, $field_prefix . '_' . $field ) as $maybe_key ) { + if ( isset( $item->$maybe_key ) ) { + $key = $maybe_key; + break; + } + } + + if ( ! $key ) { + \WP_CLI::error( "Invalid field: $field." ); + } + + } + + \WP_CLI::print_value( $item->$key, array( 'format' => $format ) ); + } + + } + + /** + * Show multiple fields of an object. + * + * @param object|array Data to display + * @param string Format to display the data in + */ + private static function show_multiple_fields( $data, $format ) { + + switch ( $format ) { + + case 'table': + self::assoc_array_to_table( $data ); + break; + + case 'json': + \WP_CLI::print_value( $data, array( 'format' => $format ) ); + break; + + default: + \WP_CLI::error( "Invalid format: " . $format ); + break; + + } + + } + + /** + * Format an associative array as a table + * + * @param array $fields Fields and values to format + */ + private static function assoc_array_to_table( $fields ) { + $rows = array(); + + foreach ( $fields as $field => $value ) { + if ( ! is_string( $value ) ) { + $value = json_encode( $value ); + } + + $rows[] = (object) array( + 'Field' => $field, + 'Value' => $value + ); + } + + \WP_CLI\Utils\format_items( 'table', $rows, array( 'Field', 'Value' ) ); + } } diff --git a/php/utils.php b/php/utils.php index bdcaba124..eff73ced7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -247,28 +247,6 @@ function format_items( $format, $items, $fields ) { } } -/** - * Format an associative array as a table - * - * @param array $fields Fields and values to format - */ -function assoc_array_to_table( $fields ) { - $rows = array(); - - foreach ( $fields as $field => $value ) { - if ( ! is_string( $value ) ) { - $value = json_encode( $value ); - } - - $rows[] = (object) array( - 'Field' => $field, - 'Value' => $value - ); - } - - format_items( 'table', $rows, array( 'Field', 'Value' ) ); -} - /** * Write data as CSV to a given file. * @@ -309,64 +287,6 @@ function pick_fields( $item, $fields ) { return $values; } -/** - * Show a single field from a list of items. - * - * @param array Array of objects to show fields from - * @param string The field to show - * @param string The format to show the field in - * @param string Whether or not the field is typically prefixed (e.g. "content" => "post_content") - */ -function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { - - foreach ( $items as $item ) { - - if ( ! isset( $key ) ) { - - foreach ( array( $field, $field_prefix . '_' . $field ) as $maybe_key ) { - if ( isset( $item->$maybe_key ) ) { - $key = $maybe_key; - break; - } - } - - if ( ! $key ) { - \WP_CLI::error( "Invalid field: $field." ); - } - - } - - \WP_CLI::print_value( $item->$key, array( 'format' => $format ) ); - } - -} - -/** - * Show multiple fields of an object. - * - * @param object|array Data to display - * @param string Format to display the data in - */ -function show_multiple_fields( $data, $format ) { - - switch ( $format ) { - - case 'table': - assoc_array_to_table( $data ); - break; - - case 'json': - \WP_CLI::print_value( $data, array( 'format' => $format ) ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $format ); - break; - - } - -} - /** * Launch system's $EDITOR to edit text * From dcead64385dccaae82a3f8e7023124147fc6ab45 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 18:42:18 +0300 Subject: [PATCH 2352/5359] let format_items() handle case where fields aren't set, for now --- php/WP_CLI/Formatter.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 65cf87813..d9c5c029a 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -32,10 +32,8 @@ public function __get( $key ) { public function display_items( $items ) { if ( $this->args['field'] ) { self::show_single_field( $items, $this->args['field'], $this->args['format'], $this->prefix ); - } elseif ( $this->args['fields'] ) { - \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); } else { - trigger_error( 'Both --field= and --fields= parameters are missing.', E_USER_ERROR ); + \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); } } From 47ac3ac68e7be1731738ee5de1f12ebd9544eb71 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 19:09:11 +0300 Subject: [PATCH 2353/5359] fix get_formatter() --- php/WP_CLI/CommandWithDBObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index a0785db23..7ea97c700 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -80,7 +80,7 @@ protected function success_or_failure( $r ) { } protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, $this->obj_type ); + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); } } From 1942964401013a7b3a715e57e4a22818679cd500 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 19:12:52 +0300 Subject: [PATCH 2354/5359] extract find_item_key() method --- php/WP_CLI/Formatter.php | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index d9c5c029a..6cdb5d097 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -31,7 +31,7 @@ public function __get( $key ) { public function display_items( $items ) { if ( $this->args['field'] ) { - self::show_single_field( $items, $this->args['field'], $this->args['format'], $this->prefix ); + $this->show_single_field( $items, $this->args['field'] ); } else { \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); } @@ -39,7 +39,7 @@ public function display_items( $items ) { public function display_item( $item ) { if ( isset( $this->args['field'] ) ) { - self::show_single_field( array( (object) $item ), $this->args['field'], $this->args['format'], $this->prefix ); + $this->show_single_field( array( (object) $item ), $this->args['field'] ); } else { self::show_multiple_fields( $item, $this->args['format'] ); } @@ -50,31 +50,30 @@ public function display_item( $item ) { * * @param array Array of objects to show fields from * @param string The field to show - * @param string The format to show the field in - * @param string Whether or not the field is typically prefixed (e.g. "content" => "post_content") */ - private static function show_single_field( $items, $field, $format = '', $field_prefix = '' ) { - + private function show_single_field( $items, $field ) { foreach ( $items as $item ) { - if ( ! isset( $key ) ) { + $key = $this->find_item_key( $item, $field ); + } - foreach ( array( $field, $field_prefix . '_' . $field ) as $maybe_key ) { - if ( isset( $item->$maybe_key ) ) { - $key = $maybe_key; - break; - } - } - - if ( ! $key ) { - \WP_CLI::error( "Invalid field: $field." ); - } + \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); + } + } + private function find_item_key( $item, $field ) { + foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { + if ( isset( $item->$maybe_key ) ) { + $key = $maybe_key; + break; } + } - \WP_CLI::print_value( $item->$key, array( 'format' => $format ) ); + if ( ! $key ) { + \WP_CLI::error( "Invalid field: $field." ); } + return $key; } /** From 5d4cdf075d9a231c639226b9526c38d62c5e077b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 19:24:34 +0300 Subject: [PATCH 2355/5359] move logic from format_items() into WP_CLI\Formatter class --- php/WP_CLI/Formatter.php | 57 ++++++++++++++++++++++++++++++++++++++-- php/utils.php | 46 +++----------------------------- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 6cdb5d097..4b8a3cfc2 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -21,6 +21,10 @@ public function __construct( &$assoc_args, $fields = null, $prefix = false ) { } } + if ( ! is_array( $format_args['fields'] ) ) { + $format_args['fields'] = explode( ',', $format_args['fields'] ); + } + $this->args = $format_args; $this->prefix = $prefix; } @@ -33,7 +37,7 @@ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); } else { - \WP_CLI\Utils\format_items( $this->args['format'], $items, $this->args['fields'] ); + $this->format( $items ); } } @@ -45,6 +49,43 @@ public function display_item( $item ) { } } + private function format( $items ) { + $fields = $this->args['fields']; + + switch ( $this->args['format'] ) { + case 'count': + if ( !is_array( $items ) ) { + $items = iterator_to_array( $items ); + } + echo count( $items ); + break; + + case 'ids': + if ( !is_array( $items ) ) { + $items = iterator_to_array( $items ); + } + echo implode( ' ', $items ); + break; + + case 'table': + self::show_table( $items, $fields ); + break; + + case 'csv': + \WP_CLI\Utils\write_csv( STDOUT, $items, $fields ); + break; + + case 'json': + $out = array(); + foreach ( $items as $item ) { + $out[] = \WP_CLI\Utils\pick_fields( $item, $fields ); + } + + echo json_encode( $out ); + break; + } + } + /** * Show a single field from a list of items. * @@ -102,6 +143,18 @@ private static function show_multiple_fields( $data, $format ) { } + private static function show_table( $items, $fields ) { + $table = new \cli\Table(); + + $table->setHeaders( $fields ); + + foreach ( $items as $item ) { + $table->addRow( array_values( \WP_CLI\Utils\pick_fields( $item, $fields ) ) ); + } + + $table->display(); + } + /** * Format an associative array as a table * @@ -121,7 +174,7 @@ private static function assoc_array_to_table( $fields ) { ); } - \WP_CLI\Utils\format_items( 'table', $rows, array( 'Field', 'Value' ) ); + self::show_table( $rows, array( 'Field', 'Value' ) ); } } diff --git a/php/utils.php b/php/utils.php index eff73ced7..020b8aef7 100644 --- a/php/utils.php +++ b/php/utils.php @@ -202,49 +202,9 @@ function locate_wp_config() { * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list */ function format_items( $format, $items, $fields ) { - if ( ! is_array( $fields ) ) - $fields = explode( ',', $fields ); - - switch ( $format ) { - case 'count': - if ( !is_array( $items ) ) { - $items = iterator_to_array( $items ); - } - echo count( $items ); - break; - - case 'ids': - if ( !is_array( $items ) ) { - $items = iterator_to_array( $items ); - } - echo implode( ' ', $items ); - break; - - case 'table': - $table = new \cli\Table(); - - $table->setHeaders( $fields ); - - foreach ( $items as $item ) { - $table->addRow( array_values( pick_fields( $item, $fields ) ) ); - } - - $table->display(); - break; - - case 'csv': - write_csv( STDOUT, $items, $fields ); - break; - - case 'json': - $out = array(); - foreach ( $items as $item ) { - $out[] = pick_fields( $item, $fields ); - } - - echo json_encode( $out ); - break; - } + $assoc_args = compact( 'format', 'fields' ); + $formatter = new \WP_CLI\Formatter( $assoc_args ); + $formatter->display_items( $items ); } /** From 97b8c81dcc37f3742ad64813b30c892e127854f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 19:41:57 +0300 Subject: [PATCH 2356/5359] use formatter in 'wp role list' --- features/roles.feature | 11 +++++++++++ php/commands/role.php | 12 ++---------- 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 features/roles.feature diff --git a/features/roles.feature b/features/roles.feature new file mode 100644 index 000000000..139cc41b9 --- /dev/null +++ b/features/roles.feature @@ -0,0 +1,11 @@ +Feature: Manage WordPress roles + + Background: + Given a WP install + + Scenario: Role CRUD operations + When I run `wp role list` + Then STDOUT should be a table containing rows: + | name | role | + | Subscriber | subscriber | + | Editor | editor | diff --git a/php/commands/role.php b/php/commands/role.php index 78a5fbdaf..97674ffbf 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -32,15 +32,6 @@ class Role_Command extends WP_CLI_Command { public function _list( $args, $assoc_args ) { global $wp_roles; - $defaults = array( - 'fields' => implode( ',', $this->fields ), - 'format' => 'table', - ); - $params = array_merge( $defaults, $assoc_args ); - - $fields = $params['fields']; - unset( $params['fields'] ); - $output_roles = array(); foreach ( $wp_roles->roles as $key => $role ) { $output_role = new stdClass; @@ -51,7 +42,8 @@ public function _list( $args, $assoc_args ) { $output_roles[] = $output_role; } - WP_CLI\Utils\format_items( $params['format'], $output_roles, $fields ); + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_roles ); } /** From c37f184eaf76e929f264229d544163781ba48893 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 20:26:29 +0300 Subject: [PATCH 2357/5359] use Formatter in CommandWithUpgrade->_list() --- php/WP_CLI/CommandWithUpgrade.php | 24 +++++------------------- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 39f754462..e491dfdea 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -5,6 +5,8 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $item_type; + protected $obj_fields; + protected $upgrade_refresh; protected $upgrade_transient; @@ -238,12 +240,6 @@ protected function _list( $_, $assoc_args ) { // Force WordPress to check for updates call_user_func( $this->upgrade_refresh ); - $defaults = array( - 'format' => 'table', - 'fields' => $this->fields - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $all_items = $this->get_all_items(); if ( !is_array( $all_items ) ) \WP_CLI::error( "No {$this->item_type}s found." ); @@ -263,18 +259,8 @@ protected function _list( $_, $assoc_args ) { return $item; } ); - if ( isset( $assoc_args['field'] ) ) { - $field = $assoc_args['field']; - - foreach ( $it as $item ) { - if ( !isset( $item[ $field ] ) ) { - \WP_CLI::error( "Invalid $this->item_type field: $field." ); - } - \WP_CLI::print_value( $item[ $field ] ); - } - } else { - \WP_CLI\Utils\format_items( $assoc_args['format'], $it, $assoc_args['fields'] ); - } + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $it ); } /** @@ -350,7 +336,7 @@ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) } protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, null, $this->item_type ); + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->item_type ); } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e7742f666..b25768917 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -11,7 +11,7 @@ class Plugin_Command extends \WP_CLI\CommandWithUpgrade { protected $upgrade_refresh = 'wp_update_plugins'; protected $upgrade_transient = 'update_plugins'; - protected $fields = array( + protected $obj_fields = array( 'name', 'status', 'update', diff --git a/php/commands/theme.php b/php/commands/theme.php index 01533a754..8f1f4dbbb 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -11,7 +11,7 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { protected $upgrade_refresh = 'wp_update_themes'; protected $upgrade_transient = 'update_themes'; - protected $fields = array( + protected $obj_fields = array( 'name', 'status', 'update', From 58229e326383688ac283408fd93a8a0a562feec2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 20:38:00 +0300 Subject: [PATCH 2358/5359] respect --format=json when --field= is passed in list subcommands --- features/steps/basic_steps.php | 14 ++++++++++++++ features/upgradables.feature | 6 ++++++ php/WP_CLI/Formatter.php | 16 ++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 1557f91c0..092c6c3fd 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -202,6 +202,20 @@ function ( $world, PyStringNode $expected ) { } }); +$steps->Then( '/^STDOUT should be a JSON array containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->STDOUT; + $expected = $world->replace_variables( (string) $expected ); + + $actualValues = json_decode( $output ); + $expectedValues = json_decode( $expected ); + + $missing = array_diff( $expectedValues, $actualValues ); + if ( !empty( $missing ) ) { + throw new \Exception( $output ); + } +}); + $steps->Then( '/^STDOUT should be CSV containing:$/', function ( $world, TableNode $expected ) { $output = $world->result->STDOUT; diff --git a/features/upgradables.feature b/features/upgradables.feature index df5080414..56ee10ddb 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -26,6 +26,12 @@ Feature: Manage WordPress themes and plugins <item> """ + When I run `wp <type> list --field=name --format=json` + Then STDOUT should be a JSON array containing: + """ + ["<item>"] + """ + When I run `wp <type> status` Then STDOUT should contain: """ diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 4b8a3cfc2..17b580ed7 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -43,7 +43,9 @@ public function display_items( $items ) { public function display_item( $item ) { if ( isset( $this->args['field'] ) ) { - $this->show_single_field( array( (object) $item ), $this->args['field'] ); + $item = (object) $item; + $key = $this->find_item_key( $item, $this->args['field'] ); + \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); } else { self::show_multiple_fields( $item, $this->args['format'] ); } @@ -94,11 +96,21 @@ private function format( $items ) { */ private function show_single_field( $items, $field ) { foreach ( $items as $item ) { + $item = (object) $item; + if ( ! isset( $key ) ) { $key = $this->find_item_key( $item, $field ); } - \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); + if ( 'json' == $this->args['format'] ) { + $values[] = $item->$key; + } else { + \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); + } + } + + if ( 'json' == $this->args['format'] ) { + echo json_encode( $values ); } } From be0ff407fa73be3c8537c886ad66c28faba15e84 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 1 Oct 2013 22:32:06 +0300 Subject: [PATCH 2359/5359] set all_with_meta, for WP 3.4 --- php/commands/user.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index bc8f9afb1..10fb90d18 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -51,7 +51,9 @@ public function _list( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); if ( 'ids' == $formatter->format ) { - $assoc_args['fields'] = 'ids'; + $assoc_args['fields'] = 'ids'; + } else { + $assoc_args['fields'] = 'all_with_meta'; } $users = get_users( $assoc_args ); From be316e0b0f8305fb7e7a554d8b6b018d1b3aa83e Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Tue, 1 Oct 2013 13:58:23 -0700 Subject: [PATCH 2360/5359] wp post edit should no longer call parent::update This broke in f6285d3 when CommandWithDBObject::update was removed and _update made protected. It should have been defined as $this->update from the beginning. --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index ae2127735..10ee29bac 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -119,7 +119,7 @@ public function edit( $args, $_ ) { if ( $r === false ) \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); else - parent::update( $args, array( 'post_content' => $r ) ); + $this->update( $args, array( 'post_content' => $r ) ); } protected function _edit( $content, $title ) { From 280f980364952d03fd130783c2b8e686f591c0fd Mon Sep 17 00:00:00 2001 From: goldenapples <goldenapplesdesign@gmail.com> Date: Tue, 1 Oct 2013 13:59:46 -0700 Subject: [PATCH 2361/5359] Add feature tests for `wp post edit` Adds two new feature tests for wp post edit: one that simulates opening an editor and quitting right out of it, and one that simulates chnaging a word and then saving. --- features/post.feature | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index 84d864b98..a7bf08998 100644 --- a/features/post.feature +++ b/features/post.feature @@ -26,7 +26,7 @@ Feature: Manage WordPress posts When I try the previous command again Then the return code should be 1 - Scenario: Creating/getting posts + Scenario: Creating/getting/editing posts Given a content.html file: """ This is some content. @@ -73,6 +73,27 @@ Feature: Manage WordPress posts } """ + When I try `EDITOR='ex -i NONE -c q!' wp post edit {POST_ID}` + Then STDERR should contain: + """ + No change made to post content. + """ + And the return code should be 0 + + When I try `EDITOR='ex -i NONE -c %s/content/bunkum -c wq' wp post edit {POST_ID}` + Then STDERR should be empty + Then STDOUT should contain: + """ + Updated post {POST_ID}. + """ + + When I run `wp post get --field=content {POST_ID}` + Then STDOUT should contain: + """ + This is some bunkum. + """ + + Scenario: Creating/listing posts When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` Then STDOUT should be a number From c3a2dfec6e2f2b939bd53d35200d1c2db9776bdd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 00:16:07 +0200 Subject: [PATCH 2362/5359] peg rmccue/requests to a specific revision still waiting for a stable tag: https://github.com/rmccue/Requests/issues/43 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 91247c46f..4cfe2e0de 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", - "rmccue/requests": "dev-master" + "rmccue/requests": "dev-master#ca0f58b6523a6d11c815ae25c79cc810cea69be7" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" From 7cea2ca5e0b8a79ebcc70d476c2ab5da310f2433 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 00:44:25 +0200 Subject: [PATCH 2363/5359] bump version to 0.12-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index b6fda097a..3ce45aaf4 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.12-alpha2' ); +define( 'WP_CLI_VERSION', '0.12-beta' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From f62a50c6a341f94bfcccde5c579ded1c9340bec4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 14:24:37 +0200 Subject: [PATCH 2364/5359] check response from _parse_name() --- features/upgradables.feature | 4 ++++ php/commands/plugin.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/features/upgradables.feature b/features/upgradables.feature index 56ee10ddb..4a21f4156 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -8,6 +8,10 @@ Feature: Manage WordPress themes and plugins And I run `wp <type> path` And save STDOUT as {CONTENT_DIR} + When I try `wp <type> get <item>` + Then the return code should be 1 + And STDERR should not be empty + # Install an out of date <item> from WordPress.org repository When I run `wp <type> install <item> --version=<version>` Then STDOUT should contain: diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b25768917..4686b5f6a 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -388,6 +388,9 @@ function install( $args, $assoc_args ) { */ public function get( $args, $assoc_args ) { $file = $this->_parse_name( $args[0] ); + if ( !$file ) { + WP_CLI::error( "The '{$args[0]}' plugin could not be found." ); + } $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); From 12a68a89a5277c18a8e5f10ed9d52e135ffdd578 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 14:28:39 +0200 Subject: [PATCH 2365/5359] combine tests for plugin|theme get --- features/plugin.feature | 21 --------------------- features/theme.feature | 21 --------------------- features/upgradables.feature | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index bde1d71dd..698e63ad3 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -86,24 +86,3 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | update | version | | akismet | active | available | 2.5.6 | - - Scenario: Get details about an installed plugin - - When I run `wp plugin get akismet` - Then STDOUT should be a table containing rows: - | Field | Value | - | name | akismet | - - - When I run `wp plugin get akismet --field=title` - Then STDOUT should contain: - """ - Akismet - """ - - When I run `wp plugin get akismet --field=title --format=json` - Then STDOUT should contain: - """ - "Akismet" - """ - diff --git a/features/theme.feature b/features/theme.feature index 2cdf61a36..7898f9d09 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -73,24 +73,3 @@ Feature: Manage WordPress themes """ wp-content/themes/p2 """ - - Scenario: Get details about an installed theme - When I run `wp theme install p2` - Then STDOUT should not be empty - - When I run `wp theme get p2` - Then STDOUT should be a table containing rows: - | Field | Value | - | name | P2 | - - When I run `wp theme get p2 --field=title` - Then STDOUT should contain: - """ - P2 - """ - - When I run `wp theme get p2 --field=title --format=json` - Then STDOUT should contain: - """ - "P2" - """ diff --git a/features/upgradables.feature b/features/upgradables.feature index 4a21f4156..4f4fea55c 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -19,6 +19,23 @@ Feature: Manage WordPress themes and plugins <type_name> installed successfully """ + When I run `wp <type> get <item>` + Then STDOUT should be a table containing rows: + | Field | Value | + | title | <item_title> | + + When I run `wp <type> get <item> --field=title` + Then STDOUT should contain: + """ + <item_title> + """ + + When I run `wp <type> get <item> --field=title --format=json` + Then STDOUT should contain: + """ + "<item_title>" + """ + When I run `wp <type> list` Then STDOUT should be a table containing rows: | name | status | update | version | From 1bd8e82be15441d4957fa259cf79c311b43cebba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 14:46:26 +0200 Subject: [PATCH 2366/5359] implement 'wp theme is-installed' --- features/plugin.feature | 6 ------ features/upgradables.feature | 7 +++++++ php/commands/plugin.php | 2 +- php/commands/theme.php | 24 ++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 698e63ad3..b9ebc00f2 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -31,12 +31,6 @@ Feature: Manage WordPress plugins Status: Active """ - When I run `wp plugin is-installed zombieland && echo "Zombieland"` - Then STDOUT should contain: - """ - Zombieland - """ - When I run `wp plugin status` Then STDOUT should not be empty diff --git a/features/upgradables.feature b/features/upgradables.feature index 4f4fea55c..672ab6c03 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -8,6 +8,10 @@ Feature: Manage WordPress themes and plugins And I run `wp <type> path` And save STDOUT as {CONTENT_DIR} + When I try `wp <type> is-installed <item>` + Then the return code should be 1 + And STDERR should be empty + When I try `wp <type> get <item>` Then the return code should be 1 And STDERR should not be empty @@ -19,6 +23,9 @@ Feature: Manage WordPress themes and plugins <type_name> installed successfully """ + When I try `wp <type> is-installed <item>` + Then the return code should be 0 + When I run `wp <type> get <item>` Then STDOUT should be a table containing rows: | Field | Value | diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 4686b5f6a..54fd8dfbb 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -440,7 +440,7 @@ function uninstall( $args, $assoc_args = array() ) { } /** - * Check if the plugin is installed + * Check if the plugin is installed. * * ## OPTIONS * diff --git a/php/commands/theme.php b/php/commands/theme.php index 8f1f4dbbb..1d9ac2dd4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -312,6 +312,30 @@ function update( $args, $assoc_args ) { parent::update_many( $args, $assoc_args ); } + /** + * Check if the theme is installed. + * + * ## OPTIONS + * + * <theme> + * : The theme to check. + * + * ## EXAMPLES + * + * wp theme is-installed twentytwelve + * + * @subcommand is-installed + */ + function is_installed( $args, $assoc_args = array() ) { + $theme = wp_get_theme( $args[0] ); + + if ( $theme->exists() ) { + exit( 0 ); + } else { + exit( 1 ); + } + } + /** * Delete a theme. * From 2772a74044c43e09f71bd10ef5e17c2a6b18756a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 15:41:39 +0200 Subject: [PATCH 2367/5359] add new contributors since the 0.11.2 release --- .mailmap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.mailmap b/.mailmap index 76512b890..72fbae088 100644 --- a/.mailmap +++ b/.mailmap @@ -23,6 +23,7 @@ jmslbam <jmslbam@gmail.com> johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> +joshbetz <j@joshbetz.com> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> @@ -37,21 +38,29 @@ mwilliamson <mike@zwobble.org> nacin <andrewnacin@gmail.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> +nikolay <nikolay@users.noreply.github.com> +nikolay <nikolaynkolev@gmail.com> +nullvariable <nullvariable@gmail.com> ocean90 <dominikschilling+git@gmail.com> +oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> +Rarst <contact@rarst.net> roelven <roel@soundcloud.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> soulou <leo@soulou.fr> spuriousdata <spuriousdata@gmail.com> +stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> taupecat <tracy@taupecat.com> tddewey <td@tddewey.com> +thisislawatts <luke@thisis.la> tlovett1 <admin@taylorlovett.com> tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> tott <tott@automattic.com> +trepmal <trepmal@gmail.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> westonruter <weston@x-team.com> From 594430cbef8a2366f3a41f30b875842ecc1af64f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 15:44:00 +0200 Subject: [PATCH 2368/5359] contrib-list: add newline --- utils/contrib-list | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/contrib-list b/utils/contrib-list index b47f01697..6d0e0897e 100755 --- a/utils/contrib-list +++ b/utils/contrib-list @@ -24,6 +24,7 @@ githubify() { if [ '-l' == "$linked" ] then git log --format="%aN" $prev_version -- | sort -f | uniq | githubify | tr '\n' ',' + echo else git log --format="%aN <%aE>" $prev_version -- | sort -f | uniq fi From a9b9c2d37ae80c927d378cda2ede2442cbeafc0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 4 Oct 2013 15:54:34 +0200 Subject: [PATCH 2369/5359] bump version to 0.12.0 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 3ce45aaf4..29acc3635 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.12-beta' ); +define( 'WP_CLI_VERSION', '0.12.0' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 30ceac062d70c98c1248e681ad598c9f8ca0c1f6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 13:07:37 +0000 Subject: [PATCH 2370/5359] Verbosity when the rewrite structure is set --- php/commands/rewrite.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 27888bd07..fab148c2b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -86,6 +86,7 @@ public function structure( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); flush_rewrite_rules( isset( $assoc_args['hard'] ) ); + WP_CLI::success( "Rewrite structure set." ); } /** From 610e0e20ac62fc28bf4c1bad5be1788078d247f0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 15:51:47 +0200 Subject: [PATCH 2371/5359] Functional tests for rewrite --- features/rewrite.feature | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 features/rewrite.feature diff --git a/features/rewrite.feature b/features/rewrite.feature new file mode 100644 index 000000000..1fee10929 --- /dev/null +++ b/features/rewrite.feature @@ -0,0 +1,33 @@ +Feature: Manage WordPress rewrites + + Background: + Given a WP install + + Scenario: Change site permastructs + When I run `wp rewrite structure /blog/%year%/%monthnum%/%day%/%postname%/ --category-base=section --tag-base=topic` + And I run `wp rewrite flush` + + When I run `wp option get permalink_structure` + Then STDOUT should contain: + """ + /blog/%year%/%monthnum%/%day%/%postname%/ + """ + + When I run `wp option get category_base` + Then STDOUT should contain: + """ + section + """ + + When I run `wp option get tag_base` + Then STDOUT should contain: + """ + topic + """ + + When I run `wp rewrite list --format=csv` + Then STDOUT should be CSV containing: + | match | query | + | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | + | topic/([^/]+)/?$ | index.php?tag=$matches[1] | + | section/(.+?)/?$ | index.php?category_name=$matches[1] | From 3b850aa7903523a13b03be785b44be73c64e04ab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 15:53:18 +0200 Subject: [PATCH 2372/5359] Support for `wp rewrite list --match=<url>` --- features/rewrite.feature | 5 +++++ php/commands/rewrite.php | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/features/rewrite.feature b/features/rewrite.feature index 1fee10929..c6a1854a9 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -31,3 +31,8 @@ Feature: Manage WordPress rewrites | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | | section/(.+?)/?$ | index.php?category_name=$matches[1] | + + When I run `wp rewrite list --match=/topic/apple/ --format=csv` + Then STDOUT should be CSV containing: + | match | query | + | topic/([^/]+)/?$ | index.php?tag=$matches[1] | diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index fab148c2b..7a95a9603 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -93,6 +93,9 @@ public function structure( $args, $assoc_args ) { * Print current rewrite rules. * * ## OPTIONS + * + * [--match=<url>] + * : Show rewrite rules matching a particular URL. * * [--format=<format>] * : Output list as table, JSON or CSV. Defaults to table. @@ -110,12 +113,18 @@ public function _list( $args, $assoc_args ) { } $defaults = array( + 'match' => '', 'format' => 'table' ); $assoc_args = array_merge( $defaults, $assoc_args ); $rule_list = array(); foreach ( $rules as $match => $query ) { + + if ( ! empty( $assoc_args['match'] ) + && ! preg_match( "!^$match!", trim( $assoc_args['match'], '/' ) ) ) + continue; + $rule_list[] = compact( 'match', 'query' ); } From 2a5af5aebe10432ca841a9f81ea092670e07e6ea Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 6 Oct 2013 16:38:57 +0200 Subject: [PATCH 2373/5359] bump version to 0.13.0-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 29acc3635..8eea44020 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if wp-cli is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.12.0' ); +define( 'WP_CLI_VERSION', '0.13.0-alpha' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 23b295a7a8ab2222264db9bc289fb207ccd4d6c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 6 Oct 2013 16:37:56 +0200 Subject: [PATCH 2374/5359] update to Requests 1.6 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4cfe2e0de..510a10275 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", - "rmccue/requests": "dev-master#ca0f58b6523a6d11c815ae25c79cc810cea69be7" + "rmccue/requests": "~1.6" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" From b0e7e20f92d412b51b0359373695339dd85e447b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 17:10:28 +0200 Subject: [PATCH 2375/5359] Support for displaying and filtering by the source of a given rewrite rule Mostly copied from Rewrite Rules Inspector. --- features/rewrite.feature | 12 +++++----- php/commands/rewrite.php | 49 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index c6a1854a9..a942bf5cb 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -27,12 +27,12 @@ Feature: Manage WordPress rewrites When I run `wp rewrite list --format=csv` Then STDOUT should be CSV containing: - | match | query | - | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | - | topic/([^/]+)/?$ | index.php?tag=$matches[1] | - | section/(.+?)/?$ | index.php?category_name=$matches[1] | + | match | query | source | + | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | post | + | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | + | section/(.+?)/?$ | index.php?category_name=$matches[1] | category | When I run `wp rewrite list --match=/topic/apple/ --format=csv` Then STDOUT should be CSV containing: - | match | query | - | topic/([^/]+)/?$ | index.php?tag=$matches[1] | + | match | query | source | + | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 7a95a9603..1d46d84cd 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -96,6 +96,9 @@ public function structure( $args, $assoc_args ) { * * [--match=<url>] * : Show rewrite rules matching a particular URL. + * + * [--source=<source>] + * : Show rewrite rules from a particular source. * * [--format=<format>] * : Output list as table, JSON or CSV. Defaults to table. @@ -106,6 +109,8 @@ public function structure( $args, $assoc_args ) { * @subcommand list */ public function _list( $args, $assoc_args ) { + global $wp_rewrite; + $rules = get_option( 'rewrite_rules' ); if ( ! $rules ) { $rules = array(); @@ -113,11 +118,41 @@ public function _list( $args, $assoc_args ) { } $defaults = array( + 'source' => '', 'match' => '', 'format' => 'table' ); $assoc_args = array_merge( $defaults, $assoc_args ); + $rewrite_rules_by_source = array(); + $rewrite_rules_by_source['post'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->permalink_structure, EP_PERMALINK ); + $rewrite_rules_by_source['date'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_date_permastruct(), EP_DATE ); + $rewrite_rules_by_source['root'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . '/', EP_ROOT ); + $rewrite_rules_by_source['comments'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . $wp_rewrite->comments_base, EP_COMMENTS, true, true, true, false ); + $rewrite_rules_by_source['search'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_search_permastruct(), EP_SEARCH ); + $rewrite_rules_by_source['author'] = $wp_rewrite->generate_rewrite_rules($wp_rewrite->get_author_permastruct(), EP_AUTHORS ); + $rewrite_rules_by_source['page'] = $wp_rewrite->page_rewrite_rules(); + + // Extra permastructs including tags, categories, etc. + foreach ( $wp_rewrite->extra_permastructs as $permastructname => $permastruct ) { + if ( is_array( $permastruct ) ) { + // Pre 3.4 compat + if ( count( $permastruct ) == 2 ) + $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct[0], $permastruct[1] ); + else + $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct['struct'], $permastruct['ep_mask'], $permastruct['paged'], $permastruct['feed'], $permastruct['forcomments'], $permastruct['walk_dirs'], $permastruct['endpoints'] ); + } else { + $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct, EP_NONE ); + } + } + + // Apply the filters used in core just in case + foreach( $rewrite_rules_by_source as $source => $source_rules ) { + $rewrite_rules_by_source[$source] = apply_filters( $source . '_rewrite_rules', $source_rules ); + if ( 'post_tag' == $source ) + $rewrite_rules_by_source[$source] = apply_filters( 'tag_rewrite_rules', $source_rules ); + } + $rule_list = array(); foreach ( $rules as $match => $query ) { @@ -125,10 +160,20 @@ public function _list( $args, $assoc_args ) { && ! preg_match( "!^$match!", trim( $assoc_args['match'], '/' ) ) ) continue; - $rule_list[] = compact( 'match', 'query' ); + $source = 'other'; + foreach( $rewrite_rules_by_source as $rules_source => $source_rules ) { + if ( array_key_exists( $match, $source_rules ) ) { + $source = $rules_source; + } + } + + if ( ! empty( $assoc_args['source'] ) && $source != $assoc_args['source'] ) + continue; + + $rule_list[] = compact( 'match', 'query', 'source' ); } - WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, array('match', 'query') ); + WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, array('match', 'query', 'source' ) ); } /** From 8636260d4c038d5d992fd0b68f3724ae36f06bfa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 17:20:16 +0200 Subject: [PATCH 2376/5359] Special treatment for `__` arguments (e.g. post__in, post__not_in) --- php/commands/post.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/post.php b/php/commands/post.php index b8c670fe8..a07b934ed 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -236,6 +236,11 @@ public function _list( $_, $assoc_args ) { ); $query_args = array_merge( $defaults, $assoc_args ); + foreach( $query_args as $key => $query_arg ) { + if ( false !== strpos( $key, '__' ) ) + $query_args[$key] = explode( ',', $query_arg ); + } + if ( 'ids' == $formatter->format ) $query_args['fields'] = 'ids'; From bf6cefb7f848d1430d1a51850d5ba8f62ab4bb8c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 17:23:21 +0200 Subject: [PATCH 2377/5359] Test `post__in` scenario --- features/post.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/post.feature b/features/post.feature index c530ffb96..b97f1c284 100644 --- a/features/post.feature +++ b/features/post.feature @@ -97,6 +97,7 @@ Feature: Manage WordPress posts Scenario: Creating/listing posts When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` Then STDOUT should be a number + And save STDOUT as {POST_ID} When I run `wp post create --post_title='Draft post' --post_content='Draft post content' --post_status='draft' --porcelain` Then STDOUT should be a number @@ -107,6 +108,11 @@ Feature: Manage WordPress posts | Publish post | publish-post | publish | | Draft post | | draft | + When I run `wp post list --post_type='post' --post__in={POST_ID} --fields=post_title,post_name,post_status --format=csv` + Then STDOUT should be CSV containing: + | post_title | post_name | post_status | + | Publish post | publish-post | publish | + When I run `wp post list --post_type='page' --field=title` Then STDOUT should be: """ From e1b3cb926272b133539850bd3b106a9fc9ae9d63 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 17:30:28 +0200 Subject: [PATCH 2378/5359] Drop pre-3.4 compat See https://github.com/wp-cli/wp-cli/pull/813#discussion_r6786977 --- php/commands/rewrite.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 1d46d84cd..0f85ddc12 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -136,11 +136,7 @@ public function _list( $args, $assoc_args ) { // Extra permastructs including tags, categories, etc. foreach ( $wp_rewrite->extra_permastructs as $permastructname => $permastruct ) { if ( is_array( $permastruct ) ) { - // Pre 3.4 compat - if ( count( $permastruct ) == 2 ) - $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct[0], $permastruct[1] ); - else - $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct['struct'], $permastruct['ep_mask'], $permastruct['paged'], $permastruct['feed'], $permastruct['forcomments'], $permastruct['walk_dirs'], $permastruct['endpoints'] ); + $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct['struct'], $permastruct['ep_mask'], $permastruct['paged'], $permastruct['feed'], $permastruct['forcomments'], $permastruct['walk_dirs'], $permastruct['endpoints'] ); } else { $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct, EP_NONE ); } From 861b1df97b94ab97ee1b83ad748c02fae48234a1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 6 Oct 2013 17:33:18 +0200 Subject: [PATCH 2379/5359] A more precise test See https://github.com/wp-cli/wp-cli/pull/777#discussion_r6787013 --- features/post.feature | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/features/post.feature b/features/post.feature index b97f1c284..d4231c87c 100644 --- a/features/post.feature +++ b/features/post.feature @@ -108,10 +108,11 @@ Feature: Manage WordPress posts | Publish post | publish-post | publish | | Draft post | | draft | - When I run `wp post list --post_type='post' --post__in={POST_ID} --fields=post_title,post_name,post_status --format=csv` - Then STDOUT should be CSV containing: - | post_title | post_name | post_status | - | Publish post | publish-post | publish | + When I run `wp post list --post__in={POST_ID} --format=count` + Then STDOUT should be: + """ + 1 + """ When I run `wp post list --post_type='page' --field=title` Then STDOUT should be: From 4a04bdacc0e4609a796a99a37fed07bb70004eaf Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sun, 6 Oct 2013 15:29:59 -0400 Subject: [PATCH 2380/5359] Allow db export to accept all mysqldump args --- php/commands/db.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 2068248fa..f9c971b06 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -111,20 +111,18 @@ function query( $args ) { } /** - * Exports the database using mysqldump. + * Exports the database using mysqldump. Accepts all of mysqldump's arguments. * * @alias dump * - * @synopsis [<file>] + * @synopsis [<file>] [--extended-insert=FALSE] [--comments] [--replace] ... */ function export( $args, $assoc_args ) { - $result_file = $this->get_file_name( $args ); + $assoc_args['result-file'] = $this->get_file_name( $args ); - self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), array( - 'result-file' => $result_file - ) ); + self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), $assoc_args ); - WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); + WP_CLI::success( sprintf( 'Exported to %s', $assoc_args['result-file'] ) ); } /** From c523af4f36ff6ecf100fe088cd4ab07479687df5 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sun, 6 Oct 2013 16:15:03 -0400 Subject: [PATCH 2381/5359] Add assoc arg for arbitrary mysqldump args Props @danielbachhuber --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index f9c971b06..06d2013fa 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -115,7 +115,7 @@ function query( $args ) { * * @alias dump * - * @synopsis [<file>] [--extended-insert=FALSE] [--comments] [--replace] ... + * @synopsis [<file>] [--extended-insert] [--skip-comments] [--<field>=<value>] */ function export( $args, $assoc_args ) { $assoc_args['result-file'] = $this->get_file_name( $args ); From bfb37aa2ed5e74e773b568cf237b872839c75279 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 7 Oct 2013 14:29:32 +0200 Subject: [PATCH 2382/5359] fix delete logic after plugin refactoring see c4f01fa50a40ab6624c84aeb9d1d9746f45f4118 props francescolaffi --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 54fd8dfbb..b0c816088 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -596,7 +596,7 @@ private function get_name( $file ) { private function _delete( $plugin ) { $plugin_dir = dirname( $plugin->file ); if ( '.' == $plugin_dir ) - $plugin_dir = $file; + $plugin_dir = $plugin->file; $command = 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ); From daeea3d199bba725d57b5ab84d8dcd0db5408ea8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 7 Oct 2013 14:53:18 +0200 Subject: [PATCH 2383/5359] first pass at 'wp super-admin' commmand --- php/commands/super-admin.php | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 php/commands/super-admin.php diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php new file mode 100644 index 000000000..6d973a28d --- /dev/null +++ b/php/commands/super-admin.php @@ -0,0 +1,59 @@ +<?php + +class SuperAdminCommand extends WP_CLI_Command { + + /** + * Show a list of users with super-admin capabilities. + * + * @subcommand list + */ + public function _list( $_, $assoc_args ) { + $super_admins = self::get_admins(); + foreach ( $super_admins as $user_login ) { + WP_CLI::line( $user_login ); + } + } + + /** + * Grant super-admin privileges to one or more users. + * + * <user>... + * : One or more user logins. + */ + public function add( $args, $_ ) { + $super_admins = self::get_admins(); + + foreach ( $args as $user_login ) { + $user = get_user_by( 'login', $user_login ); + if ( !$user ) { + WP_CLI::warning( "Couldn't find {$user_login} user." ); + } else { + $super_admins[] = $user->user_login; + } + } + + update_site_option( 'site_admins' , $super_admins ); + WP_CLI::success( 'Granted super-admin capabilities.' ); + } + + /** + * Revoke super-admin privileges to one or more users. + * + * <user>... + * : One or more user logins. + */ + public function remove( $args, $_ ) { + $super_admins = self::get_admins(); + $super_admins = array_diff( $super_admins, $args ); + update_site_option( 'site_admins' , $super_admins ); + WP_CLI::success( 'Revoked super-admin capabilities.' ); + } + + private static function get_admins() { + // We don't use get_super_admins() because we don't want to mess with the global + return get_site_option( 'site_admins', array('admin') ); + } +} + +WP_CLI::add_command( 'super-admin', 'SuperAdminCommand' ); + From e8f4778b067e7f986f45065f63e3d3363f64ef7c Mon Sep 17 00:00:00 2001 From: Japh <japhie@gmail.com> Date: Mon, 7 Oct 2013 15:55:50 +0200 Subject: [PATCH 2384/5359] Implements wp term generate, Fixes #389. --- php/commands/term.php | 96 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index bcf58ac44..07d822512 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -252,6 +252,102 @@ public function delete( $args ) { WP_CLI::error( "Term doesn't exist." ); } + /** + * Generate some terms. + * + * ## OPTIONS + * + * [--count=<number>] + * : How many terms to generate. Default: 100 + * + * [--taxonomy=<taxonomy>] + * : The taxonomy of the generated terms. Default: 'category' + * + * [--max_depth=<number>] + * : Generate child terms down to a certain depth. Default: 1 + * + * ## EXAMPLES + * + * wp term generate --count=10 + */ + public function generate( $args, $assoc_args ) { + global $wpdb; + + $defaults = array( + 'count' => 100, + 'max_depth' => 1, + 'taxonomy' => 'category', + ); + + extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); + + if ( !taxonomy_exists( $taxonomy ) ) { + WP_CLI::error( sprintf( "'%s' is not a registered taxonomy.", $taxonomy ) ); + } + + // Get the total number of terms + $total = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->terms" ); + + $label = get_taxonomy( $taxonomy )->labels->singular_name; + $slug = sanitize_title_with_dashes( $label ); + + $hierarchical = get_taxonomy( $taxonomy )->hierarchical; + + $limit = $count + $total; + + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); + + $current_depth = 1; + $current_parent = 0; + + $args = array( + 'orderby' => 'id', + 'hierarchical' => $hierarchical, + ); + + for ( $i = $total; $i < $limit; $i++ ) { + + if ( $hierarchical ) { + + if ( $this->maybe_make_child() && $current_depth < $max_depth ) { + + $current_parent = $term['term_id']; + $current_depth++; + + } else if ( $this->maybe_reset_depth() ) { + + $current_depth = 1; + $current_parent = 0; + + } + + } + + $args = array( + 'parent' => $current_parent, + 'slug' => $slug . "-$i", + ); + + $term = wp_insert_term( "$label $i", $taxonomy, $args ); + + $notify->tick(); + } + + delete_option( $taxonomy . '_children' ); + + $notify->finish(); + } + + private function maybe_make_child() { + // 50% chance of making child term + return ( mt_rand(1, 2) == 1 ); + } + + private function maybe_reset_depth() { + // 10% chance of reseting to root depth + return ( mt_rand(1, 10) == 7 ); + } + } WP_CLI::add_command( 'term', 'Term_Command' ); From 8a267589b6e2ddb216a6f4cdb730c056a27dc2c0 Mon Sep 17 00:00:00 2001 From: Julio Potier <juliobosk@gmail.com> Date: Mon, 7 Oct 2013 16:24:02 +0200 Subject: [PATCH 2385/5359] Fix notice + start manage windows OS --- php/commands/post.php | 3 ++- php/commands/scaffold.php | 2 +- php/utils.php | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index a07b934ed..8a03d3057 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -123,7 +123,8 @@ public function edit( $args, $_ ) { protected function _edit( $content, $title ) { $content = apply_filters( 'the_editor_content', $content ); - $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title ); + $os = strpos( $_SERVER['OS'], 'indows' )===false ? 'linux' : 'windows'; + $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title, $os ); return ( is_string( $output ) ) ? apply_filters( 'content_save_pre', $output ) : $output; } diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c69d1a342..02684a134 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -202,7 +202,7 @@ function _s( $args, $assoc_args ) { $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); - if ( $response['response']['code'] == 200 ) + if ( !is_wp_error( $response ) && $response['response']['code'] == 200 ) WP_CLI::success( "Created theme '".$data['theme_name']."'." ); unzip_file( $tmpfname, $theme_path ); diff --git a/php/utils.php b/php/utils.php index 020b8aef7..c6cf0ee55 100644 --- a/php/utils.php +++ b/php/utils.php @@ -254,16 +254,20 @@ function pick_fields( $item, $fields ) { * @return str|bool Edited text, if file is saved from editor * False, if no change to file */ -function launch_editor_for_input( $input, $title = 'WP-CLI' ) { +function launch_editor_for_input( $input, $title = 'WP-CLI', $os='linux' ) { $tmpfile = wp_tempnam( $title ); if ( !$tmpfile ) \WP_CLI::error( 'Error creating temporary file.' ); + $output = ''; file_put_contents( $tmpfile, $input ); + if( $os==='linux' ) \WP_CLI::launch( "\${EDITOR:-vi} '$tmpfile'" ); + else + exec("notepad $tmpfile" ); $output = file_get_contents( $tmpfile ); From 5d0bcc0a0c48605b9f8d9f7b7a52769ec3182a15 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 7 Oct 2013 17:17:47 +0200 Subject: [PATCH 2386/5359] move CI scripts out of the bin/ directory the idea is that the CI setup might contain other files besides executables --- .travis.yml | 6 +++--- {bin/ci => ci}/deploy.sh | 0 {bin/ci => ci}/prepare.sh | 0 {bin/ci => ci}/test.sh | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename {bin/ci => ci}/deploy.sh (100%) rename {bin/ci => ci}/prepare.sh (100%) rename {bin/ci => ci}/test.sh (100%) diff --git a/.travis.yml b/.travis.yml index f683d3af9..e36beae36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,11 +40,11 @@ matrix: - php: 5.5 env: WP_VERSION=3.4.2 DEPLOY_BRANCH=master -before_script: ./bin/ci/prepare.sh +before_script: ./ci/prepare.sh -script: ./bin/ci/test.sh +script: ./ci/test.sh -after_success: ./bin/ci/deploy.sh +after_success: ./ci/deploy.sh notifications: email: diff --git a/bin/ci/deploy.sh b/ci/deploy.sh similarity index 100% rename from bin/ci/deploy.sh rename to ci/deploy.sh diff --git a/bin/ci/prepare.sh b/ci/prepare.sh similarity index 100% rename from bin/ci/prepare.sh rename to ci/prepare.sh diff --git a/bin/ci/test.sh b/ci/test.sh similarity index 100% rename from bin/ci/test.sh rename to ci/test.sh From 09d6f366e29bfd3aafc117b8a4c86df584e57edf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 7 Oct 2013 15:01:11 +0200 Subject: [PATCH 2387/5359] move dev dependencies after regular dependencies --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 510a10275..96170b90b 100644 --- a/composer.json +++ b/composer.json @@ -14,14 +14,14 @@ "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6" }, + "require-dev": { + "symfony/finder": "~2.3" + }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" }, "autoload": { "psr-0": { "WP_CLI": "php" }, "files": [ "php/Spyc.php" ] - }, - "require-dev": { - "symfony/finder": "~2.3" } } From af36f237a3422d9375587583b3e534793c395cce Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 7 Oct 2013 16:58:05 +0200 Subject: [PATCH 2388/5359] travis: run CodeSniffer to detect undefined variable usage --- ci/prepare-codesniffer.sh | 6 ++++++ ci/prepare.sh | 3 +++ ci/ruleset.xml | 8 ++++++++ ci/test.sh | 3 +++ 4 files changed, 20 insertions(+) create mode 100755 ci/prepare-codesniffer.sh create mode 100644 ci/ruleset.xml diff --git a/ci/prepare-codesniffer.sh b/ci/prepare-codesniffer.sh new file mode 100755 index 000000000..630b818e3 --- /dev/null +++ b/ci/prepare-codesniffer.sh @@ -0,0 +1,6 @@ +#!/bin/bash +composer create-project squizlabs/php_codesniffer:1.4.7 codesniffer + +git clone https://github.com/illusori/PHP_Codesniffer-VariableAnalysis.git +cd PHP_Codesniffer-VariableAnalysis +./install.sh -d ../codesniffer/CodeSniffer diff --git a/ci/prepare.sh b/ci/prepare.sh index efb241ced..6d18180a8 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -15,6 +15,9 @@ chmod +x $WP_CLI_BIN_DIR/wp # Travis CI doesn't come with Behat pre-installed curl http://behat.org/downloads/behat.phar > behat.phar +# Install CodeSniffer things +./ci/prepare-codesniffer.sh + ./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ mysql -e 'CREATE DATABASE wp_cli_test;' -uroot diff --git a/ci/ruleset.xml b/ci/ruleset.xml new file mode 100644 index 000000000..748ba7a8c --- /dev/null +++ b/ci/ruleset.xml @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<ruleset name="WP-CLI"> + <description>WP-CLI coding standards.</description> + + <rule ref="Generic.CodeAnalysis.VariableAnalysis"> + <property name="allowUnusedFunctionParameters" value="1"/> + </rule> +</ruleset> diff --git a/ci/test.sh b/ci/test.sh index 3a94100a7..c213a4231 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -7,3 +7,6 @@ phpunit # Run the functional tests php behat.phar --format progress + +# Run CodeSniffer +./codesniffer/scripts/phpcs --standard=./ci/ php/ From ccf5954f390fd2671dce2d537bbea18a5953f424 Mon Sep 17 00:00:00 2001 From: Japh <japhie@gmail.com> Date: Wed, 9 Oct 2013 09:29:39 +0200 Subject: [PATCH 2389/5359] Added Behat tests for term generate command --- features/term.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/term.feature b/features/term.feature index 375bc1d78..69e05f3d0 100644 --- a/features/term.feature +++ b/features/term.feature @@ -53,3 +53,11 @@ Feature: Manage WordPress terms When I try the previous command again Then STDERR should not be empty + + Scenario: Generating terms + When I run `wp term generate --count=10` + And I run `wp term list category --format=count` + Then STDOUT should be: + """ + 11 + """ From 647047bec3b295f081da0c1cf92c95e22c65525b Mon Sep 17 00:00:00 2001 From: Matthias Kadenbach <matthias.kadenbach@gmail.com> Date: Wed, 9 Oct 2013 16:59:18 +0200 Subject: [PATCH 2390/5359] fix for issue #825 --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 020b8aef7..d298b1a22 100644 --- a/php/utils.php +++ b/php/utils.php @@ -126,7 +126,7 @@ function find_file_upward( $files, $dir = null, $stop_check = null ) { function is_path_absolute( $path ) { // Windows - if ( ':' === $path[1] ) + if ( isset($path[1]) && ':' === $path[1] ) return true; return $path[0] === '/'; From 6c6ab9d42e2e0e115aa6bb363a19bf00a650b46a Mon Sep 17 00:00:00 2001 From: Japh <japhie@gmail.com> Date: Thu, 10 Oct 2013 09:50:00 +0200 Subject: [PATCH 2391/5359] Taxonomy no longer has a default value for term generate --- php/commands/term.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index e1b49d2c5..3e594978b 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -237,12 +237,12 @@ public function delete( $args ) { * * ## OPTIONS * + * <taxonomy> + * : The taxonomy for the generated terms. + * * [--count=<number>] * : How many terms to generate. Default: 100 * - * [--taxonomy=<taxonomy>] - * : The taxonomy of the generated terms. Default: 'category' - * * [--max_depth=<number>] * : Generate child terms down to a certain depth. Default: 1 * @@ -253,10 +253,11 @@ public function delete( $args ) { public function generate( $args, $assoc_args ) { global $wpdb; + list ( $taxonomy ) = $args; + $defaults = array( 'count' => 100, 'max_depth' => 1, - 'taxonomy' => 'category', ); extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); From 0d90bffde8a736d5cb225808b8a658264bf4b747 Mon Sep 17 00:00:00 2001 From: Japh <japhie@gmail.com> Date: Thu, 10 Oct 2013 09:54:22 +0200 Subject: [PATCH 2392/5359] Term generate no longer makes redundant DB query for existing terms --- php/commands/term.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 3e594978b..efa52c217 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -266,16 +266,11 @@ public function generate( $args, $assoc_args ) { WP_CLI::error( sprintf( "'%s' is not a registered taxonomy.", $taxonomy ) ); } - // Get the total number of terms - $total = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->terms" ); - $label = get_taxonomy( $taxonomy )->labels->singular_name; $slug = sanitize_title_with_dashes( $label ); $hierarchical = get_taxonomy( $taxonomy )->hierarchical; - $limit = $count + $total; - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); $current_depth = 1; @@ -286,7 +281,7 @@ public function generate( $args, $assoc_args ) { 'hierarchical' => $hierarchical, ); - for ( $i = $total; $i < $limit; $i++ ) { + for ( $i = 0; $i < $count; $i++ ) { if ( $hierarchical ) { From c9d6bfd12dc10922faaab598a13fa25dfca682fb Mon Sep 17 00:00:00 2001 From: Japh <japhie@gmail.com> Date: Thu, 10 Oct 2013 10:01:24 +0200 Subject: [PATCH 2393/5359] Updated term generate test with new required parameter --- features/term.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 69e05f3d0..c2b6e8ef2 100644 --- a/features/term.feature +++ b/features/term.feature @@ -55,7 +55,7 @@ Feature: Manage WordPress terms Then STDERR should not be empty Scenario: Generating terms - When I run `wp term generate --count=10` + When I run `wp term generate category --count=10` And I run `wp term list category --format=count` Then STDOUT should be: """ From 3797134c9c4d646229cbb021cf45fe7ad7c41344 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 10 Oct 2013 21:01:40 +0300 Subject: [PATCH 2394/5359] add <properties> tag to ruleset --- ci/ruleset.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/ruleset.xml b/ci/ruleset.xml index 748ba7a8c..e8d39efb7 100644 --- a/ci/ruleset.xml +++ b/ci/ruleset.xml @@ -3,6 +3,8 @@ <description>WP-CLI coding standards.</description> <rule ref="Generic.CodeAnalysis.VariableAnalysis"> - <property name="allowUnusedFunctionParameters" value="1"/> + <properties> + <property name="allowUnusedFunctionParameters" value="1"/> + </properties> </rule> </ruleset> From 8c2f9726a0bcdfbb74508fc450cf7c1325525e68 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 8 Oct 2013 23:51:35 +0200 Subject: [PATCH 2395/5359] combine plugin/theme search code besides reducing duplication, it also fixes an undefined $fields variable notice --- php/WP_CLI/CommandWithUpgrade.php | 33 ++++++++++++++++++++++--------- php/commands/plugin.php | 24 +++++++--------------- php/commands/theme.php | 23 ++++++++------------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e491dfdea..9d23c5a5c 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -310,17 +310,34 @@ private function get_color( $status ) { * Search wordpress.org repo. * * @param object $api Data from WP plugin/theme API - * @param array $fields Data fields to display in table. * @param array $assoc_args Data passed in from command. - * @param string $data_type Plugin or Theme api endpoint */ - protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) { + protected function _search( $args, $assoc_args ) { + $term = $args[0]; + + $defaults = array( + 'per-page' => 10, + 'fields' => array( 'name', 'slug', 'rating' ) + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $formatter = $this->get_formatter( $assoc_args ); + + $api_args = array( + 'per_page' => (int) $assoc_args['per-page'], + 'search' => $term, + ); + + if ( 'plugin' == $this->item_type ) { + $api = plugins_api( 'query_plugins', $api_args ); + } else { + $api = themes_api( 'query_themes', $api_args ); + } + if ( is_wp_error( $api ) ) \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); - // Sanitize to 1 of 2 types - $data_type = ( 'plugin' === $data_type ) ? 'plugin' : 'theme'; - $plural = $data_type . 's'; + $plural = $this->item_type . 's'; if ( ! isset( $api->$plural ) ) \WP_CLI::error( __( 'API error. Try Again.' ) ); @@ -330,9 +347,7 @@ protected function _search( $api, $fields, $assoc_args, $data_type = 'plugin' ) $count = isset( $api->info['results'] ) ? $api->info['results'] : 'unknown'; \WP_CLI::success( sprintf( 'Showing %s of %s %s.', count( $items ), $count, $plural ) ); - $format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table'; - - \WP_CLI\Utils\format_items( $format, $items, $assoc_args['fields'] ); + $formatter->display_items( $items ); } protected function get_formatter( &$assoc_args ) { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b0c816088..535a3f469 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -52,8 +52,8 @@ function status( $args ) { * [--per-page=<per-page>] * : Optional number of results to display. Defaults to 10. * - * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * [--field=<field>] + * : Prints the value of a single field for each plugin. * * [--fields=<fields>] * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. Acceptable values: @@ -73,27 +73,17 @@ function status( $args ) { * **description**: Plugin's Description * **short_description**: Plugin's Short Description * + * [--format=<format>] + * : Output list as table, CSV or JSON. Defaults to table. + * * ## EXAMPLES * * wp plugin search dsgnwrks --per-page=20 --format=json * * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings */ - public function search( $args, $assoc_args = array() ) { - $term = $args[0]; - - $defaults = array( - 'per-page' => 10, - 'fields' => array( 'name', 'slug', 'rating' ) - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $api = plugins_api( 'query_plugins', array( - 'per_page' => (int) $assoc_args['per-page'], - 'search' => $term, - ) ); - - parent::_search( $api, $fields, $assoc_args, 'plugin' ); + public function search( $args, $assoc_args ) { + parent::_search( $args, $assoc_args ); } protected function status_single( $args ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 1d9ac2dd4..7e093a85f 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -45,6 +45,9 @@ function status( $args ) { * [--per-page=<per-page>] * : Optional number of results to display. Defaults to 10. * + * [--field=<field>] + * : Prints the value of a single field for each plugin. + * * [--fields=<fields>] * : Ask for specific fields from the API. Defaults to name,slug,author,rating. Acceptable values: * @@ -59,27 +62,17 @@ function status( $args ) { * **homepage**: Theme Author's Homepage * **description**: Theme Description * + * [--format=<format>] + * : Output list as table, CSV or JSON. Defaults to table. + * * ## EXAMPLES * * wp theme search automattic --per-page=20 * * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description */ - public function search( $args, $assoc_args = array() ) { - $term = $args[0]; - - $defaults = array( - 'per-page' => 10, - 'fields' => array( 'name', 'slug', 'author', 'rating' ) - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $api = themes_api( 'query_themes', array( - 'per_page' => (int) $assoc_args['per-page'], - 'search' => $term, - ) ); - - parent::_search( $api, $fields, $assoc_args, 'theme' ); + public function search( $args, $assoc_args ) { + parent::_search( $args, $assoc_args ); } protected function status_single( $args ) { From cb97cff413c77af7a32622dc70f0ca7d258ccb67 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Tue, 30 Jul 2013 10:14:17 +0200 Subject: [PATCH 2396/5359] packages cache by caching wp http api --- composer.json | 3 +- php/WP_CLI/CommandWithUpgrade.php | 18 +- php/WP_CLI/FileCache.php | 329 ++++++++++++++++++++++++++++++ php/WP_CLI/WpHttpCacheManager.php | 124 +++++++++++ php/class-wp-cli.php | 37 ++++ php/commands/plugin.php | 9 +- php/commands/theme.php | 8 +- 7 files changed, 524 insertions(+), 4 deletions(-) create mode 100644 php/WP_CLI/FileCache.php create mode 100644 php/WP_CLI/WpHttpCacheManager.php diff --git a/composer.json b/composer.json index 96170b90b..3531bcc1c 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "wp-cli/php-cli-tools": "0.9.3", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", - "rmccue/requests": "~1.6" + "rmccue/requests": "~1.6", + "symfony/finder": "~2.3" }, "require-dev": { "symfony/finder": "~2.3" diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9d23c5a5c..c1054e211 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -208,7 +208,7 @@ protected function update_many( $args, $assoc_args ) { \WP_CLI::line( "Available {$this->item_type} updates:" ); \WP_CLI\Utils\format_items( 'table', $items_to_update, - array( 'name', 'status', 'version' ) ); + array( 'name', 'status', 'version', 'update_version' ) ); return; } @@ -217,6 +217,10 @@ protected function update_many( $args, $assoc_args ) { // Only attempt to update if there is something to update if ( !empty( $items_to_update ) ) { + $cache_manager = \WP_CLI::get_http_cache_manager(); + foreach ($items_to_update as $item) { + $cache_manager->whitelist_package($item['update_package'], $this->item_type, $item['name'], $item['update_version']); + } $upgrader = $this->get_upgrader( $assoc_args ); $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); } @@ -276,6 +280,18 @@ protected function has_update( $slug ) { return isset( $update_list->response[ $slug ] ); } + /** + * Get the available update info + * + * @param string $slug The plugin/theme slug + * + * @return array|null + */ + protected function get_update_info( $slug ) { + $update_list = get_site_transient( $this->upgrade_transient ); + return isset( $update_list->response[ $slug ] ) ? (array) $update_list->response[ $slug ] : null; + } + private $map = array( 'short' => array( 'inactive' => 'I', diff --git a/php/WP_CLI/FileCache.php b/php/WP_CLI/FileCache.php new file mode 100644 index 000000000..65ee7487e --- /dev/null +++ b/php/WP_CLI/FileCache.php @@ -0,0 +1,329 @@ +<?php + +/* + * This file is heavily inspired and use code from Composer(getcomposer.org), + * in particular Composer/Cache and Composer/Util/FileSystem from 1.0.0-alpha7 + * + * The original code and this file are both released under MIT license. + * + * The copyright holders of the original code are: + * (c) Nils Adermann <naderman@naderman.de> + * Jordi Boggiano <j.boggiano@seld.be> + */ + +namespace WP_CLI; + +use Symfony\Component\Finder\Finder; + +/** + * Reads/writes to a filesystem cache + */ +class FileCache { + + /** + * @var string cache path + */ + protected $root; + /** + * @var bool + */ + protected $enabled = true; + /** + * @var int files time to live + */ + protected $ttl; + /** + * @var int max total size + */ + protected $maxSize; + /** + * @var string key allowed chars (regex class) + */ + protected $whitelist; + + /** + * @param string $cacheDir location of the cache + * @param int $ttl cache files default time to live (expiration) + * @param int $maxSize max total cache size + * @param string $whitelist List of characters that are allowed in path names (used in a regex character class) + */ + public function __construct( $cacheDir, $ttl, $maxSize, $whitelist = 'a-z0-9.' ) { + $this->root = rtrim( $cacheDir, '/\\' ) . '/'; + $this->ttl = (int) $ttl; + $this->maxSize = (int) $maxSize; + $this->whitelist = $whitelist; + + if ( !$this->ensure_dir_exists( $this->root ) ) { + $this->enabled = false; + } + + } + + /** + * Cache is enabled + * + * @return bool + */ + public function is_enabled() { + return $this->enabled; + } + + /** + * Cache root + * + * @return string + */ + public function get_root() { + return $this->root; + } + + + /** + * Check if a file is in cache and return its filename + * + * @param string $key cache key + * @param int $ttl time to live + * @return bool|string filename or false + */ + public function has( $key, $ttl = null ) { + if ( !$this->enabled ) { + return false; + } + + $filename = $this->filename( $key ); + + if ( !file_exists( $filename ) ) { + return false; + } + + // use ttl param or global ttl + if ( $ttl === null ) { + $ttl = $this->ttl; + } elseif ( $this->ttl > 0 ) { + $ttl = min( (int) $ttl, $this->ttl ); + } else { + $ttl = (int) $ttl; + } + + // + if ( $ttl > 0 && filemtime( $filename ) + $ttl < time() ) { + if ( $this->ttl > 0 && $ttl >= $this->ttl ) { + unlink( $filename ); + } + return false; + } + + return $filename; + } + + /** + * Write to cache file + * + * @param string $key cache key + * @param string $contents file contents + * @return bool + */ + public function write( $key, $contents ) { + $filename = $this->prepare_write( $key ); + + if ( $filename ) { + return file_put_contents( $filename, $contents ) && touch( $filename ); + } else { + return false; + } + } + + /** + * Read from cache file + * + * @param string $key cache key + * @param int $ttl time to live + * @return bool|string file contents or false + */ + public function read( $key, $ttl = null ) { + $filename = $this->has( $key, $ttl ); + + if ( $filename ) { + return file_get_contents( $filename ); + } else { + return false; + } + } + + /** + * Copy a file into the cache + * + * @param string $key cache key + * @param string $source source filename + * @return bool + */ + public function import( $key, $source ) { + $filename = $this->prepare_write( $key ); + + if ( $filename ) { + return copy( $source, $filename ) && touch( $filename ); + } else { + return false; + } + } + + /** + * Copy a file out of the cache + * + * @param string $key cache key + * @param string $target target filename + * @param int $ttl time to live + * @return bool + */ + public function export( $key, $target, $ttl = null ) { + $filename = $this->has( $key, $ttl ); + + if ( $filename ) { + return copy( $filename, $target ); + } else { + return false; + } + } + + /** + * Remove file from cache + * + * @param string $key cache key + * @return bool + */ + public function remove( $key ) { + if ( !$this->enabled ) { + return false; + } + + $filename = $this->filename( $key ); + + if ( file_exists( $filename ) ) { + return unlink( $filename ); + } else { + return false; + } + } + + /** + * Clean cache based on time to live and max size + * + * @return bool + */ + public function clean() { + if ( !$this->enabled ) { + return false; + } + + $ttl = $this->ttl; + $maxSize = $this->maxSize; + + // unlink expired files + if ( $ttl > 0 ) { + $expire = new \DateTime(); + $expire->modify( '-' . $ttl . ' seconds' ); + + $finder = $this->get_finder()->date( 'until ' . $expire->format( 'Y-m-d H:i:s' ) ); + foreach ( $finder as $file ) { + unlink( $file->getRealPath() ); + } + } + + // unlink older files if max cache size is exceeded + if ( $maxSize > 0 ) { + $files = array_reverse( iterator_to_array( $this->get_finder()->sortByAccessedTime()->getIterator() ) ); + $total = 0; + + foreach ( $files as $file ) { + if ( $total + $file->getSize() <= $maxSize ) { + $total += $file->getSize(); + } else { + unlink( $file->getRealPath() ); + } + } + } + + return true; + } + + /** + * Ensure directory exists + * + * @param string $dir directory + * @return bool + */ + protected function ensure_dir_exists( $dir ) { + if ( !is_dir( $dir ) ) { + if ( file_exists( $dir ) ) { + // exists and not a dir + return false; + } + if ( !@mkdir( $dir, 0777, true ) ) { + return false; + } + } + + return true; + } + + /** + * Prepare cache write + * + * @param string $key cache key + * @return bool|string filename or false + */ + protected function prepare_write( $key ) { + if ( !$this->enabled ) { + return false; + } + + $filename = $this->filename( $key ); + + if ( !$this->ensure_dir_exists( dirname( $filename ) ) ) { + return false; + } + + return $filename; + } + + /** + * Validate cache key + * + * @param string $key cache key + * @return string relative filename + */ + protected function validate_key( $key ) { + $url_parts = parse_url( $key ); + if ( $url_parts['scheme'] ) { // is url + $parts = array('misc'); + $parts[] = $url_parts['host'] . ( $url_parts['port'] ? '-' . $url_parts['port'] : '' ); + $parts[] = $url_parts['path'] . ( $url_parts['query'] ? '-' . $url_parts['query'] : '' ); + } else { + $key = str_replace( '\\', '/', $key ); + $parts = explode( '/', ltrim( $key ) ); + } + + $parts = preg_replace( "#[^{$this->whitelist}]#i", '-', $parts ); + + return implode( '/', $parts ); + } + + /** + * Filename from key + * + * @param string $key + * @return string filename + */ + protected function filename( $key ){ + return $this->root . $this->validate_key( $key ); + } + + /** + * Get a Finder that iterates in cache root only the files + * + * @return Finder + */ + protected function get_finder() { + return Finder::create()->in( $this->root )->files(); + } +} diff --git a/php/WP_CLI/WpHttpCacheManager.php b/php/WP_CLI/WpHttpCacheManager.php new file mode 100644 index 000000000..1fe5a8961 --- /dev/null +++ b/php/WP_CLI/WpHttpCacheManager.php @@ -0,0 +1,124 @@ +<?php + + +namespace WP_CLI; +use WP_CLI; + + +/** + * Manage caching with whitelisting + * + * @package WP_CLI + */ +class WpHttpCacheManager { + + /** + * @var array map whitelisted urls to keys and ttls + */ + protected $whitelist = array(); + /** + * @var FileCache + */ + protected $cache; + + /** + * @param FileCache $cache + */ + public function __construct( FileCache $cache ) { + $this->cache = $cache; + + // hook into wp http api + add_filter( 'pre_http_request', array($this, 'filter_pre_http_request'), 10, 3 ); + add_filter( 'http_response', array($this, 'filter_http_response'), 10, 3 ); + } + + + /** + * short circuit wp http api with cached file + */ + public function filter_pre_http_request( $response, $args, $url ) { + // check if whitelisted + if ( !isset( $this->whitelist[$url] ) ) { + return $response; + } + // check if downloading + if ( 'GET' !== $args['method'] || empty( $args['filename'] ) ) { + return $response; + } + // check cache and export to designated location + $filename = $this->cache->has( $this->whitelist[$url]['key'], $this->whitelist[$url]['ttl'] ); + if ( $filename ) { + WP_CLI::log( sprintf( 'Using cached file \'%s\'...', $filename, $url ) ); + if ( copy( $filename, $args['filename'] ) ) { + // simulate successful download response + return array( + 'response' => array('code' => ( 200 ), 'message' => 'OK'), + 'filename' => $args['filename'] + ); + } else { + WP_CLI::error( sprintf( 'Error copying cached file %s to %s', $filename, $url ) ); + } + } + return $response; + } + + + /** + * cache wp http api downloads + */ + public function filter_http_response( $response, $args, $url ) { + // check if whitelisted + if ( !isset( $this->whitelist[$url] ) ) { + return $response; + } + // check if downloading + if ( 'GET' !== $args['method'] || empty( $args['filename'] ) ) { + return $response; + } + // check if download was successful + if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { + return $response; + } + // cache downloaded file + $this->cache->import( $this->whitelist[$url]['key'], $response['filename']); + return $response; + } + + /** + * whitelist a package url + * + * @param string $url + * @param string $group package group (themes, plugins, ...) + * @param string $slug package slug + * @param string $version package version + * @param int $ttl + */ + public function whitelist_package( $url, $group, $slug, $version, $ttl = null ) { + $ext = pathinfo( parse_url( $url, PHP_URL_PATH ), PATHINFO_EXTENSION ); + $key = "$group/$slug-$version.$ext"; + $this->whitelist_url( $url, $key, $ttl ); + wp_update_plugins(); + } + + /** + * whitelist a url + * + * @param string $url + * @param string $key + * @param int $ttl + */ + public function whitelist_url( $url, $key = null, $ttl = null ) { + $key = $key ? : $url; + $this->whitelist[$url] = compact( 'key', 'ttl' ); + } + + /** + * check if url is whitelisted + * + * @param string $url + * @return bool + */ + public function is_whitelisted( $url ) { + return isset( $this->whitelist[$url] ); + } +} \ No newline at end of file diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 12b759e23..7be4ac939 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -2,6 +2,8 @@ use \WP_CLI\Utils; use \WP_CLI\Dispatcher; +use \WP_CLI\FileCache; +use \WP_CLI\WpHttpCacheManager; /** * Various utilities for WP-CLI commands. @@ -54,6 +56,41 @@ static function get_runner() { return $runner; } + /** + * @return FileCache + */ + static function get_cache() { + static $cache; + + if ( !$cache ) { + $home = getenv( 'HOME' ) ? : getenv( 'HOMEDRIVE' ) . '/' . getenv( 'HOMEPATH' ); + $dir = getenv( 'WP_CLI_CACHE_DIR' ) ? : "$home/.wp-cli/cache"; + // 6 months, 300mb + $cache = new FileCache( $dir, 15552000, 314572800); + + if (0 === mt_rand( 0, 50 ) ) { + register_shutdown_function( function () use ( $cache ) { + $cache->clean(); + } ); + } + } + + return $cache; + } + + /** + * @return WpHttpCacheManager + */ + static function get_http_cache_manager() { + static $http_cacher; + + if ( !$http_cacher ) { + $http_cacher = new WpHttpCacheManager( self::get_cache() ); + } + + return $http_cacher; + } + static function colorize( $string ) { return \cli\Colors::colorize( $string, self::get_runner()->in_color() ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 535a3f469..da853957b 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -260,6 +260,9 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + if ( 'dev' !== $assoc_args['version'] ) { + WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); + } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); return $result; @@ -304,10 +307,14 @@ protected function get_item_list() { $items = array(); foreach ( get_plugins() as $file => $details ) { + $update_info = $this->get_update_info( $file ); + $items[ $file ] = array( 'name' => $this->get_name( $file ), 'status' => $this->get_status( $file ), - 'update' => $this->has_update( $file ), + 'update' => (bool) $update_info, + 'update_version' => $update_info['new_version'], + 'update_package' => $update_info['package'], 'version' => $details['Version'], 'update_id' => $file, ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 7e093a85f..f5cf3ce97 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -176,6 +176,9 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + if ( 'dev' !== $assoc_args['version'] ) { + WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); + } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); return $result; @@ -186,11 +189,14 @@ protected function get_item_list() { foreach ( wp_get_themes() as $key => $theme ) { $file = $theme->get_stylesheet_directory(); + $update_info = $this->get_update_info( $theme->get_stylesheet() ); $items[ $file ] = array( 'name' => $key, 'status' => $this->get_status( $theme ), - 'update' => $this->has_update( $theme->get_stylesheet() ), + 'update' => (bool) $update_info, + 'update_version' => $update_info['new_version'], + 'update_package' => $update_info['package'], 'version' => $theme->get('Version'), 'update_id' => $theme->get_stylesheet(), ); From 10b8234acbd73e5a441a66690b0e3009a526f27d Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Thu, 10 Oct 2013 21:09:41 +0200 Subject: [PATCH 2397/5359] packages cache behat tests --- features/bootstrap/FeatureContext.php | 15 +++++++++++++-- features/bootstrap/Process.php | 13 ++++++++----- features/steps/basic_steps.php | 2 +- features/upgradables.feature | 27 +++++++++++++++++++++++---- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index cca8e3924..733c596e9 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -14,7 +14,7 @@ */ class FeatureContext extends BehatContext implements ClosuredContextInterface { - private static $cache_dir; + private static $cache_dir, $suite_cache_dir; private static $db_settings = array( 'dbname' => 'wp_cli_test', @@ -41,6 +41,15 @@ private static function cache_wp_files() { */ public static function prepare( SuiteEvent $event ) { self::cache_wp_files(); + self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); + mkdir( self::$suite_cache_dir ); + } + + /** + * @AfterSuite + */ + public static function afterSuite( SuiteEvent $event ) { + Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ) )->run(); } /** @@ -66,6 +75,7 @@ public function __construct( array $parameters ) { $this->drop_db(); $this->set_cache_dir(); $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); + $this->variables['SUITE_CACHE_DIR'] = self::$suite_cache_dir; } public function getStepDefinitionResources() { @@ -126,7 +136,8 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( $command, $this->variables['RUN_DIR'] ); + return Process::create( $command, $this->variables['RUN_DIR'], + array( 'WP_CLI_CACHE_DIR' => $this->variables['SUITE_CACHE_DIR'] ) ); } public function move_files( $src, $dest ) { diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 1cbb194d9..a8a3334b5 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -2,16 +2,17 @@ class Process { - public static function create( $command, $cwd = null ) { + public static function create( $command, $cwd = null, $env = array() ) { $proc = new self; $proc->command = $command; $proc->cwd = $cwd; + $proc->env = $env; return $proc; } - private $command, $cwd; + private $command, $cwd, $env; private function __construct() {} @@ -29,12 +30,13 @@ public function run( $subdir = '' ) { // Ensure we're using the expected `wp` binary $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); - - $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, array( + $env = array_merge( $this->env, array( 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), 'BEHAT_RUN' => 1 ) ); + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $env ); + $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); @@ -46,7 +48,8 @@ public function run( $subdir = '' ) { 'STDERR' => $STDERR, 'return_code' => proc_close( $proc ), 'command' => $this->command, - 'cwd' => $cwd + 'cwd' => $cwd, + 'env' => $env ) ); } diff --git a/features/steps/basic_steps.php b/features/steps/basic_steps.php index 092c6c3fd..44342b50b 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/basic_steps.php @@ -116,7 +116,7 @@ function ( $world, $mode ) { if ( !isset( $world->result ) ) throw new \Exception( 'No previous command.' ); - $proc = Process::create( $world->result->command, $world->result->cwd ); + $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); $world->result = invoke_proc( $proc, $mode ); } ); diff --git a/features/upgradables.feature b/features/upgradables.feature index 672ab6c03..527160f61 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -2,9 +2,6 @@ Feature: Manage WordPress themes and plugins Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install - And download: - | path | url | - | {CACHE_DIR}/<item>.zip | <zip_file> | And I run `wp <type> path` And save STDOUT as {CONTENT_DIR} @@ -22,6 +19,7 @@ Feature: Manage WordPress themes and plugins """ <type_name> installed successfully """ + And the {SUITE_CACHE_DIR}/<type>/<item>-<version>.zip file should exist When I try `wp <type> is-installed <item>` Then the return code should be 0 @@ -96,8 +94,29 @@ Feature: Manage WordPress themes and plugins And STDERR should not be empty + # Install and update <item> from cache + When I run `wp <type> install <item> --version=<version>` + Then STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/<type>/<item>-<version>.zip'... + """ + + When I run `wp <type> update <item>` + Then STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/<type>/<item>- + """ + + When I run `wp <type> delete <item>` + Then STDOUT should contain: + """ + Success: Deleted '<item>' <type>. + """ + And the <file_to_check> file should not exist + + # Install <item> from a local zip file - When I run `wp <type> install {CACHE_DIR}/<item>.zip` + When I run `wp <type> install {SUITE_CACHE_DIR}/<type>/<item>-<version>.zip` Then STDOUT should contain: """ <type_name> installed successfully. From 3ca1fdf5f1c65fc41478467ef3d473630bc7fb35 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Thu, 10 Oct 2013 22:52:14 +0200 Subject: [PATCH 2398/5359] stricter update package from cache test --- features/upgradables.feature | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 527160f61..830291fe7 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -72,7 +72,9 @@ Feature: Manage WordPress themes and plugins """ When I run `wp <type> update <item>` + And save STDOUT 'Downloading update from .*\/<item>\.%s\.zip' as {NEW_VERSION} Then STDOUT should not be empty + And the {SUITE_CACHE_DIR}/<type>/<item>-{NEW_VERSION}.zip file should exist When I run `wp <type> update --all` Then STDOUT should not be empty @@ -104,7 +106,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> update <item>` Then STDOUT should contain: """ - Using cached file '{SUITE_CACHE_DIR}/<type>/<item>- + Using cached file '{SUITE_CACHE_DIR}/<type>/<item>-{NEW_VERSION}.zip'... """ When I run `wp <type> delete <item>` From 0eb1431870b8a487c341078ac081ffb59ac13ab5 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Fri, 11 Oct 2013 00:56:25 +0200 Subject: [PATCH 2399/5359] better validation of urls as cache key --- php/WP_CLI/FileCache.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/FileCache.php b/php/WP_CLI/FileCache.php index 65ee7487e..a6a9fa624 100644 --- a/php/WP_CLI/FileCache.php +++ b/php/WP_CLI/FileCache.php @@ -294,10 +294,12 @@ protected function prepare_write( $key ) { */ protected function validate_key( $key ) { $url_parts = parse_url( $key ); - if ( $url_parts['scheme'] ) { // is url + if ( ! empty($url_parts['scheme']) ) { // is url $parts = array('misc'); - $parts[] = $url_parts['host'] . ( $url_parts['port'] ? '-' . $url_parts['port'] : '' ); - $parts[] = $url_parts['path'] . ( $url_parts['query'] ? '-' . $url_parts['query'] : '' ); + $parts[] = $url_parts['scheme'] . '-' . $url_parts['host'] . + ( empty( $url_parts['port'] ) ? '' : '-' . $url_parts['port'] ); + $parts[] = substr($url_parts['path'], 1) . + ( empty( $url_parts['query'] ) ? '' : '-' . $url_parts['query'] ); } else { $key = str_replace( '\\', '/', $key ); $parts = explode( '/', ltrim( $key ) ); From ed2111ab33391cf52062b82f86da8feb95cd26fa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 12:38:06 +0300 Subject: [PATCH 2400/5359] show response exception message as a warning --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 40c26a7cb..a224e487e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -70,7 +70,8 @@ public function download( $args, $assoc_args ) { try { $request = Requests::get( $download_url, $headers, $options ); - } catch( Requests_Exception $ex ) { + } catch ( Requests_Exception $ex ) { + WP_CLI::warning( $ex->getMessage() ); // Handle SSL certificate issues gracefully $options['verify'] = false; try { From 94a9277c9bf5383574897c204080df1ebd7d77e2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 12:59:06 +0300 Subject: [PATCH 2401/5359] enable SSL verification by default --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index a224e487e..dc3a48cbe 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -91,7 +91,7 @@ public function download( $args, $assoc_args ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - $options = array(); + $options = array('verify' => true); $r = false; try { From f4e1db61f13619d99f17c42c5356a8644d598121 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Fri, 11 Oct 2013 12:54:52 +0200 Subject: [PATCH 2402/5359] include symfony finder in phar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and remove duplicate dependency in composer.json from a rebase --- composer.json | 3 --- utils/make-phar.php | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 3531bcc1c..dad44f9cf 100644 --- a/composer.json +++ b/composer.json @@ -15,9 +15,6 @@ "rmccue/requests": "~1.6", "symfony/finder": "~2.3" }, - "require-dev": { - "symfony/finder": "~2.3" - }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" }, diff --git a/utils/make-phar.php b/utils/make-phar.php index 8f7bb90cd..0a7b16d83 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -37,6 +37,7 @@ function add_file( $phar, $path ) { ->in('./vendor/mustache') ->in('./vendor/rmccue/requests') ->in('./vendor/composer') + ->in('./vendor/symfony/finder') ->in('./vendor/rhumsaa/array_column') ->exclude('test') ->exclude('tests') From 577f415354e99bf5b9c8a2bbd60d7169e5968ee8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 14:05:05 +0300 Subject: [PATCH 2403/5359] extract duplicated request logic into a helper method --- php/commands/core.php | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index dc3a48cbe..981f5bcaa 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -68,19 +68,7 @@ public function download( $args, $assoc_args ) { 'filename' => $temp ); - try { - $request = Requests::get( $download_url, $headers, $options ); - } catch ( Requests_Exception $ex ) { - WP_CLI::warning( $ex->getMessage() ); - // Handle SSL certificate issues gracefully - $options['verify'] = false; - try { - $request = Requests::get( $download_url, $headers, $options ); - } - catch( Requests_Exception $ex ) { - WP_CLI::error( $ex->getMessage() ); - } - } + self::_request( 'GET', $download_url, $headers, $options ); $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; @@ -89,26 +77,24 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } - private static function _read( $url ) { - $headers = array('Accept' => 'application/json'); - $options = array('verify' => true); - - $r = false; + private static function _request( $method, $url, $headers = array(), $options = array() ) { try { - $request = Requests::get( $url, $headers, $options ); - $r = $request->body; + $options['verify'] = true; + return Requests::get( $url, $headers, $options ); } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully $options['verify'] = false; try { - $request = Requests::get( $url, $headers, $options ); - $r = $request->body; + return Requests::get( $url, $headers, $options ); } catch( Requests_Exception $ex ) { WP_CLI::error( $ex->getMessage() ); } } + } - return $r; + private static function _read( $url ) { + $headers = array('Accept' => 'application/json'); + return self::_request( 'GET', $url, $headers )->body; } private function get_download_offer( $locale ) { From d153411f477e2c165fc90e05eafb5360686d085a Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Fri, 11 Oct 2013 13:42:41 +0200 Subject: [PATCH 2404/5359] make WP_CLI::get_cache more readable and private --- php/class-wp-cli.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7be4ac939..0476c43ba 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -59,16 +59,22 @@ static function get_runner() { /** * @return FileCache */ - static function get_cache() { + private static function get_cache() { static $cache; if ( !$cache ) { - $home = getenv( 'HOME' ) ? : getenv( 'HOMEDRIVE' ) . '/' . getenv( 'HOMEPATH' ); + $home = getenv( 'HOME' ); + if ( !$home ) { + // sometime in windows $HOME is not defined + $home = getenv( 'HOMEDRIVE' ) . '/' . getenv( 'HOMEPATH' ); + } $dir = getenv( 'WP_CLI_CACHE_DIR' ) ? : "$home/.wp-cli/cache"; + // 6 months, 300mb - $cache = new FileCache( $dir, 15552000, 314572800); + $cache = new FileCache( $dir, 15552000, 314572800 ); - if (0 === mt_rand( 0, 50 ) ) { + // clean older files on shutdown with 1/50 probability + if ( 0 === mt_rand( 0, 50 ) ) { register_shutdown_function( function () use ( $cache ) { $cache->clean(); } ); From 1294a677817c8bb6b2a14dd38ca02fe3b508baa2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 15:03:33 +0300 Subject: [PATCH 2405/5359] add back warning message --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index 981f5bcaa..ec14f2a29 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -83,6 +83,7 @@ private static function _request( $method, $url, $headers = array(), $options = return Requests::get( $url, $headers, $options ); } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully + WP_CLI::warning( $ex->getMessage() ); $options['verify'] = false; try { return Requests::get( $url, $headers, $options ); From 73bfb93704dd90c126c56cc65463a2047423d2e6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 15:34:39 +0300 Subject: [PATCH 2406/5359] update contributor list since 0.12.0 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 72fbae088..5b7349285 100644 --- a/.mailmap +++ b/.mailmap @@ -29,6 +29,7 @@ lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> +mattes <matthias.kadenbach@gmail.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> milesj <mileswjohnson@gmail.com> From 1d71878436072c63c0c41dcb9064210ff1930dfb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 15:35:58 +0300 Subject: [PATCH 2407/5359] branding --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 8eea44020..e923f211f 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -1,6 +1,6 @@ <?php -// Can be used by plugins/themes to check if wp-cli is running or not +// Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); define( 'WP_CLI_VERSION', '0.13.0-alpha' ); From b1241f9544131696cc4319cc72bd22ebdda3c53b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 15:36:09 +0300 Subject: [PATCH 2408/5359] set version to 0.12.1 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index e923f211f..95335b0f7 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13.0-alpha' ); +define( 'WP_CLI_VERSION', '0.12.1' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From e9d7494e5180397f8966966b22eec330b21dafe1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 11 Oct 2013 22:49:15 +0300 Subject: [PATCH 2409/5359] test the waters before diving in --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 701e56b21..74af3fa22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,14 @@ Contribute ========== -So you've got an awesome idea to throw into WP-CLI. Great! Here's the process, in a nutshell: +Whether you want to fix a bug or implement a new feature, the process is pretty much the same: +0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, open a new issue so that you can get some initial feedback. 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. 2. Make the code changes in your fork. 3. Open a pull request. -It doesn't matter if the code isn't perfect. The idea is to get feedback early and iterate. +It doesn't matter if the code isn't perfect. The idea is to get it reviewed early and iterate on it. If you're adding a new feature, please add one or more functional tests for it in the `features/` directory. See below. From e4cbd9372319e884d52a1bd7bc76dafd16d33ece Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 14:43:48 +0300 Subject: [PATCH 2410/5359] restrict codesniffer warnings to undefined variables --- ci/prepare-codesniffer.sh | 2 +- ci/test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/prepare-codesniffer.sh b/ci/prepare-codesniffer.sh index 630b818e3..a5f5fa874 100755 --- a/ci/prepare-codesniffer.sh +++ b/ci/prepare-codesniffer.sh @@ -1,5 +1,5 @@ #!/bin/bash -composer create-project squizlabs/php_codesniffer:1.4.7 codesniffer +composer create-project squizlabs/php_codesniffer:1.5.0RC4 codesniffer git clone https://github.com/illusori/PHP_Codesniffer-VariableAnalysis.git cd PHP_Codesniffer-VariableAnalysis diff --git a/ci/test.sh b/ci/test.sh index c213a4231..7aeaaf197 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -9,4 +9,4 @@ phpunit php behat.phar --format progress # Run CodeSniffer -./codesniffer/scripts/phpcs --standard=./ci/ php/ +./codesniffer/scripts/phpcs --standard=./ci/ --sniffs=Generic.CodeAnalysis.VariableAnalysis.UndefinedVariable php/ From 7d3df119ab7858eefe430ac4647b1530b6377ab1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:03:49 +0300 Subject: [PATCH 2411/5359] reset temporary $levs array on each iteration also, use rsort(), since $levs isn't associative --- php/commands/import.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index 493badb64..fb0622019 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -351,11 +351,12 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { if ( $author_user_email && $user->user_email == $author_user_email ) return $user->user_login; + $levs = array(); $levs[] = levenshtein( $author_user_login, $user->display_name ); $levs[] = levenshtein( $author_user_login, $user->user_login ); $levs[] = levenshtein( $author_user_login, $user->user_email ); $levs[] = levenshtein( $author_user_login, array_shift( explode( "@", $user->user_email ) ) ); - arsort( $levs ); + rsort( $levs ); $lev = array_pop( $levs ); if ( 0 == $lev ) { $closest = $user->user_login; From 0abbda1287b169eb63899452d22959305addc6da Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:05:25 +0300 Subject: [PATCH 2412/5359] remove unused $silent parameter from when cURL was used directly --- php/commands/core.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ec14f2a29..9ffcecc12 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -55,9 +55,6 @@ public function download( $args, $assoc_args ) { WP_CLI::log( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); } - $silent = WP_CLI::get_config('quiet') || \cli\Shell::isPiped() ? - '--silent ' : ''; - // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). $temp = tempnam( sys_get_temp_dir(), "wp_" ); From 7af168b782e8e4b7ece3a03d42c9abee0222948b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:05:46 +0300 Subject: [PATCH 2413/5359] remove unused $wpdb variable --- php/WP_CLI/Iterators/Table.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 441b69dc7..eb7d1d60f 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -38,8 +38,6 @@ class Table extends Query { * it's a key/value pair. In the latter case the value is automatically quoted and escaped */ function __construct( $args = array() ) { - global $wpdb; - $defaults = array( 'fields' => '*', 'where' => array(), From a18dd9ec9bb24329acc529c24bf6bb9ef3b05e90 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:08:20 +0300 Subject: [PATCH 2414/5359] fix undefined variables in comment.php --- php/commands/comment.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index adefbcada..8d97df2e8 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -35,9 +35,10 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { */ public function create( $args, $assoc_args ) { parent::_create( $args, $assoc_args, function ( $params ) { - $post = get_post( $params['comment_post_ID'] ); + $post_id = $params['comment_post_ID']; + $post = get_post( $post_id ); if ( !$post ) { - return new WP_Error( 'no_post', "Can't find post $comment_post_ID." ); + return new WP_Error( 'no_post', "Can't find post $post_id." ); } // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and @@ -198,7 +199,7 @@ private function set_status( $args, $status, $success ) { if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); } else { - WP_CLI::success( "$success comment $comment_id" ); + WP_CLI::success( "$success comment $comment->comment_ID" ); } } From 727d3d40743f3a6e5b3efcaf09bf49197571ac64 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:10:14 +0300 Subject: [PATCH 2415/5359] fix undefined variables in Formatter.php --- php/WP_CLI/Formatter.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 17b580ed7..6f971b28b 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -95,10 +95,13 @@ private function format( $items ) { * @param string The field to show */ private function show_single_field( $items, $field ) { + $key = null; + $values = array(); + foreach ( $items as $item ) { $item = (object) $item; - if ( ! isset( $key ) ) { + if ( null === $key ) { $key = $this->find_item_key( $item, $field ); } From 90633a9690c04a180391c0d23a98b5833ecd1384 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:13:20 +0300 Subject: [PATCH 2416/5359] fix undefined variables in scaffold.php --- php/commands/scaffold.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c69d1a342..6ee800cc7 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -191,6 +191,7 @@ function _s( $args, $assoc_args ) { $theme_description = "Custom theme: ".$data['theme_name']." developed by, ".$data['author']; + $body = array(); $body['underscoresme_name'] = $data['theme_name']; $body['underscoresme_slug'] = $theme_slug; $body['underscoresme_author'] = $data['author']; @@ -265,14 +266,14 @@ function child_theme( $args, $assoc_args ) { } private function get_output_path( $assoc_args, $subdir ) { - extract( $assoc_args, EXTR_SKIP ); - - if ( $theme ) { + if ( $assoc_args['theme'] ) { + $theme = $assoc_args['theme']; if ( is_string( $theme ) ) $path = get_theme_root( $theme ) . '/' . $theme; else $path = get_stylesheet_directory(); - } elseif ( ! empty( $plugin ) ) { + } elseif ( $assoc_args['plugin'] ) { + $plugin = $assoc_args['plugin']; $path = WP_PLUGIN_DIR . '/' . $plugin; if ( !is_dir( $path ) ) { WP_CLI::error( "Can't find '$plugin' plugin." ); From a78ccafaf32f1dfb058858e53dc7510d59111dc4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:14:31 +0300 Subject: [PATCH 2417/5359] fix undefined variables in site.php --- php/commands/site.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 5bcdf6d62..e3d500da4 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -61,6 +61,7 @@ private function _empty_taxonomies() { // Empty taxonomies and terms $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); $ids = array(); + $taxonomies = array(); foreach ( (array) $terms as $term ) { $taxonomies[] = $term->taxonomy; $ids[] = $term->term_id; @@ -68,6 +69,7 @@ private function _empty_taxonomies() { } $taxonomies = array_unique( $taxonomies ); + $cleaned = array(); foreach ( $taxonomies as $taxonomy ) { if ( isset( $cleaned[$taxonomy] ) ) continue; From e7637a28724651e01dba63bd73111750f096b6de Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:19:12 +0300 Subject: [PATCH 2418/5359] bump version to 0.13-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 95335b0f7..ad8cd8d36 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.12.1' ); +define( 'WP_CLI_VERSION', '0.13-alpha' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From e398a82471dbb525f7ceb40ca3ea7b2b74bda505 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:38:46 +0300 Subject: [PATCH 2419/5359] ignore codesniffer warnings in core.php some are caused by using variables defined in wp-includes/version.php and some are caused by using extract(), which isn't that evil when used with EXTR_SKIP --- php/commands/core.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9ffcecc12..d8e34e775 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -105,8 +105,10 @@ private function get_download_offer( $locale ) { private static function get_initial_locale() { include ABSPATH . '/wp-includes/version.php'; + // @codingStandardsIgnoreStart if ( isset( $wp_local_package ) ) return $wp_local_package; + // @codingStandardsIgnoreEnd return ''; } @@ -381,11 +383,13 @@ private function _install( $assoc_args ) { $public = true; + // @codingStandardsIgnoreStart $result = wp_install( $title, $admin_user, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); } + // @codingStandardsIgnoreEnd return true; } @@ -531,9 +535,13 @@ public function version( $args = array(), $assoc_args = array() ) { include $versions_path; + // @codingStandardsIgnoreStart if ( isset( $assoc_args['extra'] ) ) { - preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ); - $human_readable_tiny_mce = $match ? $match[1] . '.' . $match[2] : ''; + if ( preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ) ) { + $human_readable_tiny_mce = $match[1] . '.' . $match[2]; + } else { + $human_readable_tiny_mce = ''; + } echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( 'wp-version' => $wp_version, @@ -546,6 +554,7 @@ public function version( $args = array(), $assoc_args = array() ) { } else { WP_CLI::line( $wp_version ); } + // @codingStandardsIgnoreEnd } /** From d6f4e47eaf67775b133ff8ded700ca41ba7a2452 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 15:44:04 +0300 Subject: [PATCH 2420/5359] make codesniffer ignore Spyc library --- ci/test.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index 7aeaaf197..5939c599a 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -9,4 +9,6 @@ phpunit php behat.phar --format progress # Run CodeSniffer -./codesniffer/scripts/phpcs --standard=./ci/ --sniffs=Generic.CodeAnalysis.VariableAnalysis.UndefinedVariable php/ +./codesniffer/scripts/phpcs \ + --standard=./ci/ --sniffs=Generic.CodeAnalysis.VariableAnalysis.UndefinedVariable \ + --ignore=php/Spyc.php php/ From 1d321ccc804773c4ecec002e281dbba69bd11494 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:11:29 +0300 Subject: [PATCH 2421/5359] ignore undefined variable warnings in post.php --- php/commands/post.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index a07b934ed..c4d8f24ba 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -287,9 +287,9 @@ public function generate( $args, $assoc_args ) { 'post_author' => false, 'post_date' => current_time( 'mysql' ), ); - extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); + // @codingStandardsIgnoreStart if ( !post_type_exists( $post_type ) ) { WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); } @@ -334,7 +334,7 @@ public function generate( $args, $assoc_args ) { $args = array( 'post_type' => $post_type, - 'post_title' => "$label $i", + 'post_title' => "$label $i", 'post_status' => $post_status, 'post_author' => $post_author, 'post_parent' => $current_parent, @@ -346,8 +346,8 @@ public function generate( $args, $assoc_args ) { $notify->tick(); } - $notify->finish(); + // @codingStandardsIgnoreEnd } private function maybe_make_child() { From 07618f93d902e7c8d7baa0854556dc262d04c477 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:14:04 +0300 Subject: [PATCH 2422/5359] fix undefined variable warnings in wp-settings-cli.php --- php/wp-settings-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 50687b3de..7af881697 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -80,11 +80,14 @@ require_wp_db(); // WP-CLI: Handle db error ourselves, instead of waiting for dead_db() +global $wpdb; if ( !empty( $wpdb->error ) ) wp_die( $wpdb->error ); // Set the database table prefix and the format specifiers for database table columns. +// @codingStandardsIgnoreStart $GLOBALS['table_prefix'] = $table_prefix; +// @codingStandardsIgnoreEnd wp_set_wpdb_vars(); // Start the WordPress object cache, or an external object cache if the drop-in is present. @@ -298,6 +301,7 @@ $GLOBALS['wp_locale'] = new WP_Locale(); // Load the functions for the active theme, for both parent and child theme if applicable. +global $pagenow; if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) include( STYLESHEETPATH . '/functions.php' ); From 708fe74088c92ea0af9de944d339208a00358691 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:15:58 +0300 Subject: [PATCH 2423/5359] ignore undefined variable warnings in Runner.php --- php/WP_CLI/Runner.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0d37f11a3..7ac2e56fb 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -358,6 +358,7 @@ private function check_wp_version() { $minimum_version = '3.4'; + // @codingStandardsIgnoreStart if ( version_compare( $wp_version, $minimum_version, '<' ) ) { WP_CLI::error( "WP-CLI needs WordPress $minimum_version or later to work properly. " . @@ -365,6 +366,7 @@ private function check_wp_version() { "Try running `wp core download --force`." ); } + // @codingStandardsIgnoreEnd } private function init_config() { From a3c62b8eff8224200e7485ab6a19104ba0302637 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:02:39 +0300 Subject: [PATCH 2424/5359] extract validate_role() helper method --- php/commands/user.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 10fb90d18..c6272ac60 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -187,14 +187,9 @@ public function create( $args, $assoc_args ) { 'user_registered' => strftime( "%F %T", time() ), 'display_name' => false, ); + extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - if ( 'none' == $role ) { - $role = false; - } elseif ( is_null( get_role( $role ) ) ) { - WP_CLI::error( "Invalid role." ); - } + $role = self::validate_role( $role ); if ( !$user_pass ) { $user_pass = wp_generate_password(); @@ -274,12 +269,7 @@ public function generate( $args, $assoc_args ) { extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - if ( 'none' == $role ) { - $role = false; - } elseif ( is_null( get_role( $role ) ) ) { - WP_CLI::warning( "invalid role." ); - exit; - } + $role = self::validate_role( $role ); $user_count = count_users(); @@ -552,9 +542,8 @@ public function import_csv( $args, $assoc_args ) { ); $new_user = array_merge( $defaults, $new_user ); - if ( 'none' == $new_user['role'] ) { + if ( 'none' === $new_user['role'] ) { $new_user['role'] = false; - } elseif ( is_null( get_role( $new_user['role'] ) ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); continue; @@ -597,6 +586,14 @@ public function import_csv( $args, $assoc_args ) { } } } + + private static function validate_role( $role ) { + if ( 'none' === $role ) { + $role = false; + } elseif ( is_null( get_role( $role ) ) ) { + WP_CLI::error( "Invalid role: $role" ); + } + } } WP_CLI::add_command( 'user', 'User_Command' ); From e231ce642acd619801a060252f9730419b94c3fb Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:07:20 +0300 Subject: [PATCH 2425/5359] fix undefined variable warnings in user.php --- php/commands/user.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index c6272ac60..95c4d05f3 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -191,6 +191,7 @@ public function create( $args, $assoc_args ) { $role = self::validate_role( $role ); + // @codingStandardsIgnoreStart if ( !$user_pass ) { $user_pass = wp_generate_password(); $generated_pass = true; @@ -221,6 +222,7 @@ public function create( $args, $assoc_args ) { if ( isset( $generated_pass ) ) WP_CLI::line( "Password: $user_pass" ); } + // @codingStandardsIgnoreEnd } /** @@ -266,18 +268,15 @@ public function generate( $args, $assoc_args ) { 'count' => 100, 'role' => get_option('default_role'), ); + $assoc_args = array_merge( $defaults, $assoc_args ); - extract( wp_parse_args( $assoc_args, $defaults ), EXTR_SKIP ); - - $role = self::validate_role( $role ); + $role = self::validate_role( $assoc_args['role'] ); $user_count = count_users(); - $total = $user_count['total_users']; + $limit = $assoc_args['count'] + $total; - $limit = $count + $total; - - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $assoc_args['count'] ); for ( $i = $total; $i < $limit; $i++ ) { $login = sprintf( 'user_%d_%d', $blog_id, $i ); From 2389790947ad0d3d26c8be86e4f4fc506ff8311b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 16:51:38 +0300 Subject: [PATCH 2426/5359] move codesniffer parameters to ruleset.xml --- ci/ruleset.xml | 4 ++++ ci/test.sh | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci/ruleset.xml b/ci/ruleset.xml index e8d39efb7..29a843d56 100644 --- a/ci/ruleset.xml +++ b/ci/ruleset.xml @@ -2,7 +2,11 @@ <ruleset name="WP-CLI"> <description>WP-CLI coding standards.</description> + <exclude-pattern>php/Spyc.php</exclude-pattern> + <rule ref="Generic.CodeAnalysis.VariableAnalysis"> + <exclude name="Generic.CodeAnalysis.VariableAnalysis.UnusedVariable"/> + <properties> <property name="allowUnusedFunctionParameters" value="1"/> </properties> diff --git a/ci/test.sh b/ci/test.sh index 5939c599a..c213a4231 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -9,6 +9,4 @@ phpunit php behat.phar --format progress # Run CodeSniffer -./codesniffer/scripts/phpcs \ - --standard=./ci/ --sniffs=Generic.CodeAnalysis.VariableAnalysis.UndefinedVariable \ - --ignore=php/Spyc.php php/ +./codesniffer/scripts/phpcs --standard=./ci/ php/ From c333de1c2b1f7e87c2cf7e5ef90b066b4f96b772 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 17:07:26 +0300 Subject: [PATCH 2427/5359] enable DisallowSpaceIndent sniff --- ci/ruleset.xml | 2 ++ php/WP_CLI/Configurator.php | 2 +- php/WP_CLI/Runner.php | 3 +-- php/WP_CLI/SynopsisParser.php | 4 +--- php/boot-fs.php | 2 +- php/commands/help.php | 2 +- php/commands/search-replace.php | 3 +-- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ci/ruleset.xml b/ci/ruleset.xml index 29a843d56..624677051 100644 --- a/ci/ruleset.xml +++ b/ci/ruleset.xml @@ -4,6 +4,8 @@ <exclude-pattern>php/Spyc.php</exclude-pattern> + <rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/> + <rule ref="Generic.CodeAnalysis.VariableAnalysis"> <exclude name="Generic.CodeAnalysis.VariableAnalysis.UnusedVariable"/> diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 239e95f23..1065fe4d2 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -93,7 +93,7 @@ function load_config( $yml_file ) { $value = array( $value ); } } else { - $value = $details['default']; + $value = $details['default']; } $sanitized_config[ $key ] = $value; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7ac2e56fb..c3b52e173 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -426,8 +426,7 @@ public function before_wp_load() { self::set_wp_root( $this->config ); // First try at showing man page - if ( 'help' === $this->arguments[0] && - ( isset( $this->arguments[1] ) || !$this->wp_exists() ) ) { + if ( 'help' === $this->arguments[0] && ( isset( $this->arguments[1] ) || !$this->wp_exists() ) ) { $this->_run_command(); } diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 37cc3aca0..499600053 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -17,9 +17,7 @@ static function parse( $synopsis ) { // Some types of parameters shouldn't be mandatory if ( isset( $param['optional'] ) && !$param['optional'] ) { - if ( 'flag' === $param['type'] || - ( 'assoc' === $param['type'] && $param['value']['optional'] ) - ) { + if ( 'flag' === $param['type'] || ( 'assoc' === $param['type'] && $param['value']['optional'] ) ) { $param['type'] = 'unknown'; } } diff --git a/php/boot-fs.php b/php/boot-fs.php index 7a13744db..c39ea2a47 100644 --- a/php/boot-fs.php +++ b/php/boot-fs.php @@ -8,7 +8,7 @@ } if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { - printf( "Error: WP-CLI requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); + printf( "Error: WP-CLI requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); die(-1); } diff --git a/php/commands/help.php b/php/commands/help.php index c56e47f12..d7eb30c83 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -116,7 +116,7 @@ private static function get_initial_markdown( $command ) { private static function render_subcommands( $command ) { $subcommands = array(); foreach ( $command->get_subcommands() as $subcommand ) { - $subcommands[ $subcommand->get_name() ] = $subcommand->get_shortdesc(); + $subcommands[ $subcommand->get_name() ] = $subcommand->get_shortdesc(); } $max_len = self::get_max_len( array_keys( $subcommands ) ); diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index fbeeec184..24f3d0f23 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -73,8 +73,7 @@ public function __invoke( $args, $assoc_args ) { if ( in_array( $col, $skip_columns ) ) continue; - $count = self::handle_col( $col, $primary_key, $table, $old, $new, - $dry_run ); + $count = self::handle_col( $col, $primary_key, $table, $old, $new, $dry_run ); $report[] = array( $table, $col, $count ); From 6449289df09269e5ba110075479af15325946666 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 17:14:44 +0300 Subject: [PATCH 2428/5359] enable EndFileNewline sniff --- ci/ruleset.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/ruleset.xml b/ci/ruleset.xml index 624677051..8208bd2a5 100644 --- a/ci/ruleset.xml +++ b/ci/ruleset.xml @@ -5,6 +5,7 @@ <exclude-pattern>php/Spyc.php</exclude-pattern> <rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/> + <rule ref="Generic.Files.EndFileNewline"/> <rule ref="Generic.CodeAnalysis.VariableAnalysis"> <exclude name="Generic.CodeAnalysis.VariableAnalysis.UnusedVariable"/> From 8e9f8359558560fa705bf4a5e1a34c338f471a89 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 17:28:05 +0300 Subject: [PATCH 2429/5359] split overly long lines --- php/WP_CLI/CommandWithUpgrade.php | 5 ++++- php/WP_CLI/Dispatcher/Subcommand.php | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9d23c5a5c..0197439e1 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -46,7 +46,10 @@ private function status_all() { $n = count( $items ); // Not interested in the translation, just the number logic - \WP_CLI::log( sprintf( _n( "%d installed {$this->item_type}:", "%d installed {$this->item_type}s:", $n ), $n ) ); + \WP_CLI::log( sprintf( _n( + "%d installed {$this->item_type}:", + "%d installed {$this->item_type}s:", + $n ), $n ) ); $padding = $this->get_padding($items); diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 07cbee7b3..78cda45c1 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -173,7 +173,9 @@ private function validate_args( $args, &$assoc_args ) { implode( ' ', $unknown_positionals ) ); } - list( $errors, $to_unset ) = $validator->validate_assoc( array_merge( \WP_CLI::get_config(), $assoc_args ) ); + list( $errors, $to_unset ) = $validator->validate_assoc( + array_merge( \WP_CLI::get_config(), $assoc_args ) + ); if ( !empty( $errors['fatal'] ) ) { $out = 'Parameter errors:'; From aef71e17abdda752fa7596d9c1f1582d585d4f76 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Oct 2013 17:29:40 +0300 Subject: [PATCH 2430/5359] simplify error message for --user= global parameter --- features/flags.feature | 2 +- php/WP_CLI/Runner.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 7cd0288f7..8f290a0a7 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -62,7 +62,7 @@ Feature: Global flags Then the return code should be 1 And STDERR should be: """ - Error: Could not get a user_id for this user: 'non-existing-user' + Error: Could not find user: non-existing-user """ Scenario: Using a custom logger diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c3b52e173..be1b7fa24 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -93,7 +93,7 @@ private static function set_user( $assoc_args ) { } if ( !$user_id || !wp_set_current_user( $user_id ) ) { - \WP_CLI::error( sprintf( 'Could not get a user_id for this user: %s', var_export( $user, true ) ) ); + \WP_CLI::error( "Could not find user: $user" ); } } From f074393deca33c5b5134c1c844bed3bff945eab9 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Mon, 14 Oct 2013 13:51:57 +0200 Subject: [PATCH 2431/5359] fix undefined index notice --- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index da853957b..3bb17465f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -260,7 +260,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - if ( 'dev' !== $assoc_args['version'] ) { + if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); diff --git a/php/commands/theme.php b/php/commands/theme.php index f5cf3ce97..b5dccf3fb 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -176,7 +176,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); - if ( 'dev' !== $assoc_args['version'] ) { + if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); From ed075ed50d252d2c857f4adf56f9391658eebd8b Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Mon, 14 Oct 2013 13:52:23 +0200 Subject: [PATCH 2432/5359] fix composer.json whitespace --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dad44f9cf..4fd173fb5 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", - "symfony/finder": "~2.3" + "symfony/finder": "~2.3" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" From a6bc7a966c281d3abd36472c25a3384baf476768 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Tue, 15 Oct 2013 11:27:36 +0200 Subject: [PATCH 2433/5359] fix missing EOF newline --- php/WP_CLI/WpHttpCacheManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/WpHttpCacheManager.php b/php/WP_CLI/WpHttpCacheManager.php index 1fe5a8961..f9e9efff9 100644 --- a/php/WP_CLI/WpHttpCacheManager.php +++ b/php/WP_CLI/WpHttpCacheManager.php @@ -121,4 +121,4 @@ public function whitelist_url( $url, $key = null, $ttl = null ) { public function is_whitelisted( $url ) { return isset( $this->whitelist[$url] ); } -} \ No newline at end of file +} From 66a02a66d8a3af8362ab9549a5313493d32d3ef5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 16 Oct 2013 21:52:33 +0300 Subject: [PATCH 2434/5359] colorize only section headers fixes #832 --- php/commands/help.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index d7eb30c83..d722a9205 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -51,14 +51,14 @@ private static function show_help( $command ) { } // section headers - $out = preg_replace( '/^## ([A-Z ]+)/m', '%9\1%n', $out ); + $out = preg_replace( '/^## ([A-Z ]+)/m', WP_CLI::colorize( '%9\1%n' ), $out ); // definition lists $out = preg_replace_callback( '/([^\n]+)\n: (.+?)(\n\n|$)/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); $out = str_replace( "\t", ' ', $out ); - self::pass_through_pager( WP_CLI::colorize( $out ) ); + self::pass_through_pager( $out ); } private static function rewrap_param_desc( $matches ) { From b7dc8635a1a910e50f70e44b5b69022a4efb91aa Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Thu, 17 Oct 2013 10:38:14 -0400 Subject: [PATCH 2435/5359] Removed thumbnail detection logic. --- php/commands/import.php | 47 +---------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index eeff977cc..21ad061cb 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -127,7 +127,6 @@ private function import_wxr( $args ) { if( in_array( 'image_resize', $args['skip'] ) ) { add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_set_image_sizes' ) ); - add_filter( 'wp_generate_attachment_metadata', array( $this, 'filter_set_image_metadata' ), 10, 2 ); } $wp_import->import( $args['file'] ); @@ -136,54 +135,10 @@ private function import_wxr( $args ) { } public function filter_set_image_sizes( $sizes ) { - // Save the given sizes so that when the wp_generate_attachment_metadata hook - // is called we can place this info on to the $metadata array so that the - // info gets saved to the database, but the actual resize processing does - // not occur. - $this->image_sizes = $sizes; - + // Return null here to prevent the core image resizing logic from running. return null; } - public function filter_set_image_metadata( $metadata, $attachment_id ) { - if( !isset( $metadata['file'] ) ) - return $metadata; - - $upload_dir = wp_upload_dir(); - $file_path = $upload_dir['basedir'] . '/' . $metadata['file']; - $path_info = pathinfo( $file_path ); - $mime_type = get_post_mime_type( $attachment_id ); - - // Return current meta untouched if can't determine current image mime type. - if( !$mime_type ) - return $metadata; - - $metadata['sizes'] = array( ); - - // Now time to generate the image size metadata since some resized files - // should already be on disk. We just have to point WordPress to them. - // Note: this logic will not find all possibled resized thumbnail files. - // To be sure _wp_attachment_metadata gets populated with all possible - // custom image sizes, run a command like WP-CLI's 'media regenerate' in order - // to re-generate and link to all the various configured image sizes. - foreach( $this->image_sizes as $size => $size_data ) { - $file = $path_info['filename'] . '-' . $size_data['width'] . 'x' . $size_data['height'] . '.' . $path_info['extension']; - - // Make sure the file exists before adding a size entry to the meta array. - if( !file_exists( $path_info['dirname'] . '/' . $file ) ) - continue; // File does not exist, don't point to it. - - $metadata['sizes'][$size] = array( - 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $file ) ), - 'width' => $size_data['width'], - 'height' => $size_data['height'], - 'mime-type' => $mime_type, - ); - } - - return $metadata; - } - /** * Useful verbosity filters for the WXR importer */ From 4635a195283d27cedb4d097d9ef84dc2f0143eba Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Thu, 17 Oct 2013 11:02:27 -0400 Subject: [PATCH 2436/5359] Added functional test for new --skip=image_resize option. Also added option to command doc output. --- features/import.feature | 3 +++ php/commands/import.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/features/import.feature b/features/import.feature index 5a4c940ca..60ed6582a 100644 --- a/features/import.feature +++ b/features/import.feature @@ -34,3 +34,6 @@ Feature: Import content. """ 7 """ + + When I run `wp import {EXPORT_FILE} --skip=image_resize` + Then STDOUT should not be empty \ No newline at end of file diff --git a/php/commands/import.php b/php/commands/import.php index 21ad061cb..4964de155 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -14,7 +14,7 @@ class Import_Command extends WP_CLI_Command { * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. * * [--skip=<data-type>] - * : Skip importing specific data. Supported option is 'attachment'. + * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). */ public function __invoke( $args, $assoc_args ) { list( $file ) = $args; From 679c36accfaf90a977f5b2ff5a1b52a4f1528f4e Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Thu, 17 Oct 2013 11:21:30 -0400 Subject: [PATCH 2437/5359] Fixed functional test (import requires --authors param to run correctly). --- features/import.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/import.feature b/features/import.feature index 60ed6582a..f14322420 100644 --- a/features/import.feature +++ b/features/import.feature @@ -35,5 +35,5 @@ Feature: Import content. 7 """ - When I run `wp import {EXPORT_FILE} --skip=image_resize` + When I run `wp import {EXPORT_FILE} --authors=skip --skip=image_resize` Then STDOUT should not be empty \ No newline at end of file From 3bc97c0f927bb88a88ccf910594bfa11d3b4ebda Mon Sep 17 00:00:00 2001 From: Corey Taylor <ctaylor@thinkoomph.com> Date: Thu, 17 Oct 2013 11:56:30 -0400 Subject: [PATCH 2438/5359] Added newline to EOF. --- features/import.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/import.feature b/features/import.feature index f14322420..c5375053b 100644 --- a/features/import.feature +++ b/features/import.feature @@ -36,4 +36,4 @@ Feature: Import content. """ When I run `wp import {EXPORT_FILE} --authors=skip --skip=image_resize` - Then STDOUT should not be empty \ No newline at end of file + Then STDOUT should not be empty From 9059abe2664e00ee90343a2852116937fc959812 Mon Sep 17 00:00:00 2001 From: Simon Wheatley <simonw@codeforthepeople.com> Date: Thu, 17 Oct 2013 17:22:02 +0100 Subject: [PATCH 2439/5359] Correct namespace. --- php/WP_CLI/Iterators/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 4fea0301e..03e7fbe40 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -73,7 +73,7 @@ private function load_items_from_db() { if ( !$this->results ) { if ( $this->db->last_error ) { - throw new Iterators\Exception( 'Database error: ' . $this->db->last_error ); + throw new Exception( 'Database error: ' . $this->db->last_error ); } else { return false; } From bb158fad4a161507be05ef7c5dc115698c1895b3 Mon Sep 17 00:00:00 2001 From: Simon Wheatley <simonw@codeforthepeople.com> Date: Thu, 17 Oct 2013 17:22:19 +0100 Subject: [PATCH 2440/5359] Wrap `invoke` in try/catch. --- php/WP_CLI/Runner.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index be1b7fa24..6621a7272 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -210,7 +210,11 @@ public function run_command( $args, $assoc_args = array() ) { list( $command, $final_args ) = $r; - $command->invoke( $final_args, $assoc_args ); + try { + $command->invoke( $final_args, $assoc_args ); + } catch ( WP_CLI\Iterators\Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } } private function _run_command() { From ab049844962bfae564ca1b127a3632e43d05a9e7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 17 Oct 2013 22:02:06 +0300 Subject: [PATCH 2441/5359] link to WPSE --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6f4de555..abb95cf6d 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ If you want to hack on WP-CLI, then clone this repository and run `./utils/dev-b Where can I get more info? -------------------------- -For documentation, usage, and examples, check out [wp-cli.org](http://wp-cli.org/). +For documentation and examples, check out [wp-cli.org](http://wp-cli.org/) and the [wiki](https://github.com/wp-cli/wp-cli/wiki). -Read our [wiki](https://github.com/wp-cli/wp-cli/wiki) and find out how to create your own commands with our [commands cookbook](https://github.com/wp-cli/wp-cli/wiki/Commands-Cookbook). +Also, WordPress Answers has a growing list of [WP-CLI related questions](http://wordpress.stackexchange.com/questions/tagged/wp-cli). I'm running into troubles, what can I do? ----------------------------------------- From 0b581dfbe4ca5c69df6981b7c2fbbd37ab28cb09 Mon Sep 17 00:00:00 2001 From: Nick Daugherty <ndaugherty987@gmail.com> Date: Fri, 18 Oct 2013 15:34:52 -0600 Subject: [PATCH 2442/5359] Conditionally load `wp-includes/date.php` Add support for the new `WP_Date_Query` class, used internally by `WP_Query`. http://core.trac.wordpress.org/changeset/25139 --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 7af881697..c94479931 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -122,6 +122,7 @@ require( ABSPATH . WPINC . '/formatting.php' ); require( ABSPATH . WPINC . '/capabilities.php' ); require( ABSPATH . WPINC . '/query.php' ); +Utils\maybe_require( '3.7-alpha-25139', ABSPATH . WPINC . '/date.php' ); require( ABSPATH . WPINC . '/theme.php' ); Utils\maybe_require( '3.4', ABSPATH . WPINC . '/class-wp-theme.php' ); Utils\maybe_require( '3.4', ABSPATH . WPINC . '/template.php' ); From ad97b366a4f68b06afcc0c24d7d5c4ec33b05dad Mon Sep 17 00:00:00 2001 From: QWp6t <QWp6t+github@xpdnc.org> Date: Fri, 18 Oct 2013 17:55:41 -0700 Subject: [PATCH 2443/5359] Use PharData class to extract tarball In some environments (read: mine), tar binary cannot access temp file because it is locked by php. This will resolve that issue. --- php/commands/core.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d8e34e775..2d3d8f21f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -66,10 +66,14 @@ public function download( $args, $assoc_args ) { ); self::_request( 'GET', $download_url, $headers, $options ); - - $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; - - WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); + + if ( class_exists( 'PharData' ) ) { + $tar = new PharData( $temp ); + $tar->extractTo( ABSPATH, null, true ); + } else { + $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; + WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); + } WP_CLI::success( 'WordPress downloaded.' ); } From fc2a63db801214e81c9c158202784591d181f856 Mon Sep 17 00:00:00 2001 From: Ryan Duff <ryan@fusionized.com> Date: Sat, 19 Oct 2013 10:20:34 -0400 Subject: [PATCH 2444/5359] escape abspath so paths with spaces work --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d8e34e775..d5dd5d40f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -69,7 +69,7 @@ public function download( $args, $assoc_args ) { $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; - WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); + WP_CLI::launch( Utils\esc_cmd( $cmd, ABSPATH ) ); WP_CLI::success( 'WordPress downloaded.' ); } From b0164cd155d05bec4f1dbb08218fc701419328be Mon Sep 17 00:00:00 2001 From: QWp6t <QWp6t+github@xpdnc.org> Date: Sat, 19 Oct 2013 15:41:07 -0700 Subject: [PATCH 2445/5359] Fixes PharData extraction bugs * $temp gets '.tar.gz' extension * _extract() method is created * PharData uses workaround for '--strip-components' compatibility --- php/commands/core.php | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2d3d8f21f..cc347fde9 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -57,7 +57,7 @@ public function download( $args, $assoc_args ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). - $temp = tempnam( sys_get_temp_dir(), "wp_" ); + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; $headers = array('Accept' => 'application/json'); $options = array( @@ -67,16 +67,28 @@ public function download( $args, $assoc_args ) { self::_request( 'GET', $download_url, $headers, $options ); - if ( class_exists( 'PharData' ) ) { - $tar = new PharData( $temp ); - $tar->extractTo( ABSPATH, null, true ); - } else { - $cmd = "tar xz --strip-components=1 --directory=%s -f $temp && rm $temp"; - WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); - } + self::_extract( $temp ); WP_CLI::success( 'WordPress downloaded.' ); } + + private static function _extract( $tarball ) { + if ( ! class_exists( 'PharData' ) ) { + $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball && rm $tarball"; + WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); + return ABSPATH; + } + $flags = FilesystemIterator::SKIP_DOTS | FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO; + $tempdir = substr( $tarball, 0, -7 ); + $tempOffset = strlen( $tempdir ) + 10; + $phar = new PharData( $tarball ); + $phar->extractTo( $tempdir, null, true ); + foreach( new RecursiveDirectoryIterator( $tempdir . '/wordpress', $flags ) as $path ) { + rename( $path->getPathName(), ABSPATH . substr( $path, $tempOffset ) ); + } + rmdir( $tempdir . '/wordpress' ); + rmdir( $tempdir ); + } private static function _request( $method, $url, $headers = array(), $options = array() ) { try { From c881793985b67179c7aa08e07d57c5a0f91edf93 Mon Sep 17 00:00:00 2001 From: QWp6t <QWp6t+github@xpdnc.org> Date: Sun, 20 Oct 2013 01:40:58 -0700 Subject: [PATCH 2446/5359] Makes extraction routine more readable / Fixes overwrite routine * creates separate _move_overwrite_files() method * more accurately simulates --strip-components=1 by using $phar->getFileName() --- php/commands/core.php | 50 ++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index cc347fde9..7518356d0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -67,27 +67,53 @@ public function download( $args, $assoc_args ) { self::_request( 'GET', $download_url, $headers, $options ); - self::_extract( $temp ); + self::_extract( $temp, ABSPATH ); WP_CLI::success( 'WordPress downloaded.' ); } - private static function _extract( $tarball ) { + private static function _extract( $tarball, $dest ) { if ( ! class_exists( 'PharData' ) ) { $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball && rm $tarball"; - WP_CLI::launch( sprintf( $cmd, ABSPATH ) ); - return ABSPATH; + WP_CLI::launch( sprintf( $cmd, $dest ) ); + return; } - $flags = FilesystemIterator::SKIP_DOTS | FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO; - $tempdir = substr( $tarball, 0, -7 ); - $tempOffset = strlen( $tempdir ) + 10; $phar = new PharData( $tarball ); - $phar->extractTo( $tempdir, null, true ); - foreach( new RecursiveDirectoryIterator( $tempdir . '/wordpress', $flags ) as $path ) { - rename( $path->getPathName(), ABSPATH . substr( $path, $tempOffset ) ); + $tempdir = implode( DIRECTORY_SEPARATOR, Array ( + dirname( $tarball ), + basename( $tarball, '.tar.gz' ), + $phar->getFileName() + ) ); + + $phar->extractTo( dirname( $tempdir ), null, true ); + + self::_move_overwrite_files( $tempdir, $dest ); + + rmdir( dirname( $tempdir ) ); + } + + private static function _move_overwrite_files( $source, $dest ) { + $flags = FilesystemIterator::SKIP_DOTS + | FilesystemIterator::KEY_AS_PATHNAME + | FilesystemIterator::CURRENT_AS_FILEINFO; + + $dstOffset = strlen( $source ); + + foreach( new RecursiveIteratorIterator ( + new RecursiveDirectoryIterator( $source, $flags ), + RecursiveIteratorIterator::CHILD_FIRST + ) as $src ) { + $dst = $dest . substr( $src, $dstOffset ); + $dstdir = dirname( $dst ); + if ( ! is_dir( $dstdir ) ) continue; + + if ( $src->isDir() && is_dir( $dst ) ) { + rmdir( $src ); + continue; + } + rename( $src, $dst ); } - rmdir( $tempdir . '/wordpress' ); - rmdir( $tempdir ); + rmdir( $source ); } private static function _request( $method, $url, $headers = array(), $options = array() ) { From 75c28fed9cda8ed2afd97ce771221e76b2fc7bec Mon Sep 17 00:00:00 2001 From: QWp6t <QWp6t+github@xpdnc.org> Date: Sun, 20 Oct 2013 01:56:15 -0700 Subject: [PATCH 2447/5359] Fixes readability * two lines were indented with spaces, converted to tabs --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 7518356d0..57b5dbeeb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -94,8 +94,8 @@ private static function _extract( $tarball, $dest ) { private static function _move_overwrite_files( $source, $dest ) { $flags = FilesystemIterator::SKIP_DOTS - | FilesystemIterator::KEY_AS_PATHNAME - | FilesystemIterator::CURRENT_AS_FILEINFO; + | FilesystemIterator::KEY_AS_PATHNAME + | FilesystemIterator::CURRENT_AS_FILEINFO; $dstOffset = strlen( $source ); From 7b182713e230175135eedd06dc7edec9b648cdd4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Oct 2013 02:33:12 +0300 Subject: [PATCH 2448/5359] bump version to 0.13-alpha2 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index ad8cd8d36..5380e8a27 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13-alpha' ); +define( 'WP_CLI_VERSION', '0.13-alpha2' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 8e0c1f6d0e1b781a11b40b3f38f08f5d30828810 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Oct 2013 02:37:03 +0300 Subject: [PATCH 2449/5359] use Utils\esc_cmd() for consistency --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d5dd5d40f..9965db4e7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -35,7 +35,7 @@ public function download( $args, $assoc_args ) { if ( !is_dir( ABSPATH ) ) { WP_CLI::log( sprintf( 'Creating directory %s', ABSPATH ) ); - WP_CLI::launch( sprintf( 'mkdir -p %s', escapeshellarg( ABSPATH ) ) ); + WP_CLI::launch( Utils\esc_cmd( 'mkdir -p %s', ABSPATH ) ); } if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version'] ) ) { From 3977c84d11396c5bd22d243517a8323910144d3f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Oct 2013 02:39:28 +0300 Subject: [PATCH 2450/5359] add space in download cache dir, for catching #839 --- ci/prepare.sh | 2 +- features/bootstrap/FeatureContext.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 6d18180a8..2a5b0e8e8 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -18,7 +18,7 @@ curl http://behat.org/downloads/behat.phar > behat.phar # Install CodeSniffer things ./ci/prepare-codesniffer.sh -./bin/wp core download --version=$WP_VERSION --path=/tmp/wp-cli-test-core-download-cache/ +./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 733c596e9..498e442b2 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -27,7 +27,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { // We cache the results of `wp core download` to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests private static function cache_wp_files() { - self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; + self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test core-download-cache'; if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) return; From 89e0f55ca6195b1cdfbe14776d1c4047614cf1f3 Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Tue, 22 Oct 2013 02:27:19 +0000 Subject: [PATCH 2451/5359] Output WP-CLI error if config file couldn't be created --- php/commands/core.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9965db4e7..22c5136d3 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -196,9 +196,13 @@ public function config( $_, $assoc_args ) { } $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); - file_put_contents( ABSPATH . 'wp-config.php', $out ); - WP_CLI::success( 'Generated wp-config.php file.' ); + $bytes_written = file_put_contents( ABSPATH . 'wp-config.php', $out ); + if ( ! $bytes_written ) { + WP_CLI::error( 'Could not create new config file.' ); + } else { + WP_CLI::success( 'Generated wp-config.php file.' ); + } } /** From d8dbe549e7235698535a64e5a7fc8ea14e590fde Mon Sep 17 00:00:00 2001 From: Taylor Lovett <admin@taylorlovett.com> Date: Tue, 22 Oct 2013 02:28:27 +0000 Subject: [PATCH 2452/5359] Tweak error message fixes #837 --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 22c5136d3..b093b1684 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -199,7 +199,7 @@ public function config( $_, $assoc_args ) { $bytes_written = file_put_contents( ABSPATH . 'wp-config.php', $out ); if ( ! $bytes_written ) { - WP_CLI::error( 'Could not create new config file.' ); + WP_CLI::error( 'Could not create new wp-config.php file.' ); } else { WP_CLI::success( 'Generated wp-config.php file.' ); } From f8ab4d14729354180172685b070437685ca07910 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Oct 2013 12:51:54 +0300 Subject: [PATCH 2453/5359] send REPL output directly to STDOUT, to avoid output buffers started by plugins fixes #719 --- php/WP_CLI/REPL.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index c065091a2..b3f902316 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -26,7 +26,10 @@ public function start() { if ( !self::starts_with( 'return', $line ) ) $line = 'return ' . $line; + // Write directly to STDOUT, to sidestep any output buffers created by plugins + ob_start(); var_dump( eval( $line ) ); + fwrite( STDOUT, ob_get_clean() ); } } } From 6ba67fba88be9ee5107eca96b0bc96defd0e7505 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 22 Oct 2013 12:53:59 +0300 Subject: [PATCH 2454/5359] use fwrite() instead of echo in WP_CLI::out(), to avoid output buffers --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0476c43ba..f9d9908f2 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -314,7 +314,7 @@ static function add_man_dir() { // back-compat static function out( $str ) { - echo $str; + fwrite( STDOUT, $str ); } // back-compat From 85a927471a5585f702125f996af101c644d32c3b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 23 Oct 2013 22:50:45 +0300 Subject: [PATCH 2455/5359] Introduce WP_CLI_CONFIG_PATH environment variable. It allows defining an additional config file, which gets loaded before any project config file. Also, remove the --config= global parameter, which becomes redundant. see #698 --- features/config.feature | 8 ++++---- php/WP_CLI/Configurator.php | 14 +++++++++---- php/WP_CLI/Runner.php | 40 ++++++++++++------------------------- php/class-wp-cli.php | 4 ---- php/commands/cli.php | 5 ++++- php/config-spec.php | 6 ------ 6 files changed, 31 insertions(+), 46 deletions(-) diff --git a/features/config.feature b/features/config.feature index a51d366c0..42dfe081f 100644 --- a/features/config.feature +++ b/features/config.feature @@ -68,14 +68,14 @@ Feature: Have a config file """ Scenario: Disabled subcommands - Given a WP install - And a wp-cli.yml file: + Given an empty directory + And a config.yml file: """ disabled_commands: - - db drop + - core version """ - When I try `wp db drop --yes` + When I try `WP_CLI_CONFIG_PATH=config.yml wp core version` Then STDERR should contain: """ command has been disabled diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 239e95f23..42b867a7b 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -92,11 +92,9 @@ function load_config( $yml_file ) { if ( $details['multiple'] && !is_array( $value ) ) { $value = array( $value ); } - } else { - $value = $details['default']; - } - $sanitized_config[ $key ] = $value; + $sanitized_config[ $key ] = $value; + } } // Make sure config-file-relative paths are made absolute. @@ -114,6 +112,14 @@ function load_config( $yml_file ) { return $sanitized_config; } + public function get_defaults() { + $defaults = array(); + foreach ( $this->spec as $key => $details ) { + $defaults[ $key ] = $details['default']; + } + return $defaults; + } + private static function absolutize( &$path, $base ) { if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { $path = $base . DIRECTORY_SEPARATOR . $path; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4c09fe818..f6620b1dc 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -8,7 +8,7 @@ class Runner { - private $config_path, $config; + private $global_config_path, $project_config_path, $config; private $arguments, $assoc_args; @@ -37,11 +37,7 @@ private function do_early_invoke( $when ) { } } - private static function get_config_path( $runtime_config ) { - if ( isset( $runtime_config['config'] ) && file_exists( $runtime_config['config'] ) ) { - return $runtime_config['config']; - } - + private static function get_project_config_path() { $config_files = array( 'wp-cli.local.yml', 'wp-cli.yml' @@ -49,7 +45,7 @@ private static function get_config_path( $runtime_config ) { // Stop looking upward when we find we have emerged from a subdirectory // install into a parent install - $path = Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { + return Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { static $wp_load_count = 0; $wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php'; if ( file_exists( $wp_load_path ) ) { @@ -57,22 +53,6 @@ private static function get_config_path( $runtime_config ) { } return $wp_load_count > 1; } ); - - if ( $path ) { - return $path; - } - - // See if there is a global config file specified in the Composer - // install directory - foreach( $config_files as $config_file ) { - foreach( WP_CLI\Utils\get_vendor_paths() as $vendor_path ) { - $config_path = dirname( $vendor_path ) . '/' . $config_file; - if ( file_exists( $config_path ) ) - return $config_path; - } - } - - return false; } private static function set_wp_root( $config ) { @@ -378,16 +358,22 @@ private function check_wp_version() { } private function init_config() { + $this->global_config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + $this->project_config_path = self::get_project_config_path(); + + $configurator = \WP_CLI::get_configurator(); + $this->config = array_merge( + $configurator->get_defaults(), + $configurator->load_config( $this->global_config_path ), + $configurator->load_config( $this->project_config_path ) + ); + list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( $args, $assoc_args ); - $this->config_path = self::get_config_path( $runtime_config ); - - $this->config = \WP_CLI::get_configurator()->load_config( $this->config_path ); - foreach ( $runtime_config as $key => $value ) { if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index da3a32be6..12e3b108a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -237,10 +237,6 @@ static function launch( $command, $exit_on_error = true ) { return $r; } - static function get_config_path() { - return self::get_runner()->config_path; - } - static function get_config( $key = null ) { if ( null === $key ) { return self::get_runner()->config; diff --git a/php/commands/cli.php b/php/commands/cli.php index d0046d4d1..3749b0452 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -41,11 +41,14 @@ function version() { function info() { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + $runner = WP_CLI::get_runner(); + WP_CLI::line( "PHP binary:\t" . $php_bin ); WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); WP_CLI::line( "WP-CLI root:\t" . WP_CLI_ROOT ); - WP_CLI::line( "WP-CLI config:\t" . WP_CLI::get_config_path() ); + WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); + WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); } diff --git a/php/config-spec.php b/php/config-spec.php index a2f174769..f105ca533 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -1,12 +1,6 @@ <?php return array( - 'config' => array( - 'runtime' => '=<path>', - 'file' => false, - 'desc' => 'Path to the wp-cli config file', - ), - 'path' => array( 'runtime' => '=<path>', 'file' => '<path>', From b980dad962218af3a7d3d1b4c760ecfcf4fd052e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 00:24:33 +0300 Subject: [PATCH 2456/5359] add back deprecated --config global parameter, for backwards compatibility --- php/WP_CLI/Runner.php | 16 ++++++++++------ php/config-spec.php | 5 +++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 443693373..39c237e34 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -360,7 +360,17 @@ private function check_wp_version() { } private function init_config() { + list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( + array_slice( $GLOBALS['argv'], 1 ) ); + + list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( + $args, $assoc_args ); + $this->global_config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + if ( isset( $runtime_config['config'] ) ) { + $this->global_config_path = $runtime_config['config']; + } + $this->project_config_path = self::get_project_config_path(); $configurator = \WP_CLI::get_configurator(); @@ -370,12 +380,6 @@ private function init_config() { $configurator->load_config( $this->project_config_path ) ); - list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( - array_slice( $GLOBALS['argv'], 1 ) ); - - list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( - $args, $assoc_args ); - foreach ( $runtime_config as $key => $value ) { if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); diff --git a/php/config-spec.php b/php/config-spec.php index 4bae081b5..399862e63 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -17,6 +17,11 @@ 'runtime' => '', ), + 'config' => array( + 'deprecated' => 'Use the WP_CLI_CONFIG_PATH environment variable instead', + 'runtime' => '=<path>', + ), + 'user' => array( 'runtime' => '=<id|login>', 'file' => '<id|login>', From eb6e7a8d686abfbbe84a97274fc4c5bbbe8bb376 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 00:27:40 +0300 Subject: [PATCH 2457/5359] show warning when deprecated global parameter is used --- php/WP_CLI/Configurator.php | 23 ++++++++++++++--------- php/WP_CLI/Runner.php | 4 +--- php/config-spec.php | 6 +++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 42b867a7b..27969b877 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -57,16 +57,21 @@ function parse_args( $arguments ) { foreach ( $mixed_args as $tmp ) { list( $key, $value ) = $tmp; - $enabled = isset( $this->spec[ $key ] ) ? $this->spec[ $key ]['runtime'] : false; - - if ( false === $enabled ) { - $assoc_args[ $key ] = $value; - } else { - if ( $this->spec[ $key ]['multiple'] ) { - $runtime_config[ $key ][] = $value; - } else { - $runtime_config[ $key ] = $value; + if ( isset( $this->spec[ $key ] ) ) { + $details = $this->spec[ $key ]; + if ( $details['runtime'] ) { + if ( isset( $details['deprecated'] ) ) { + fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); + } + + if ( $details['multiple'] ) { + $runtime_config[ $key ][] = $value; + } else { + $runtime_config[ $key ] = $value; + } } + } else { + $assoc_args[ $key ] = $value; } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 39c237e34..643769c18 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -90,8 +90,6 @@ private static function set_user( $assoc_args ) { private static function guess_url( $assoc_args ) { if ( isset( $assoc_args['blog'] ) ) { $assoc_args['url'] = $assoc_args['blog']; - unset( $assoc_args['blog'] ); - WP_CLI::warning( 'The --blog parameter is deprecated. Use --url instead.' ); } if ( isset( $assoc_args['url'] ) ) { @@ -430,7 +428,7 @@ public function before_wp_load() { $this->_run_command(); } - // Handle --url and --blog parameters + // Handle --url parameter $url = self::guess_url( $this->config ); if ( $url ) { $url_parts = self::parse_url( $url ); diff --git a/php/config-spec.php b/php/config-spec.php index 399862e63..d4e206e7e 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -13,12 +13,12 @@ 'desc' => 'Pretend request came from given URL', ), 'blog' => array( - 'deprecated' => 'Use --url instead', - 'runtime' => '', + 'deprecated' => 'Use --url instead.', + 'runtime' => '=<url>', ), 'config' => array( - 'deprecated' => 'Use the WP_CLI_CONFIG_PATH environment variable instead', + 'deprecated' => 'Use the WP_CLI_CONFIG_PATH environment variable instead.', 'runtime' => '=<path>', ), From 915fd1c7e7c495258f57eb1e2cdc03bda3f025ae Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 02:09:31 +0300 Subject: [PATCH 2458/5359] initialized configurator on demand --- php/class-wp-cli.php | 15 +++++++-------- php/wp-cli.php | 2 -- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e0996fada..abe3a5928 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -16,13 +16,6 @@ class WP_CLI { private static $hooks = array(), $hooks_passed = array(); - /** - * Initialize WP_CLI static variables. - */ - static function init() { - self::$configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); - } - /** * Set the logger instance. * @@ -33,7 +26,13 @@ static function set_logger( $logger ) { } static function get_configurator() { - return self::$configurator; + static $configurator; + + if ( !$configurator ) { + $configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); + } + + return $configurator; } static function get_root_command() { diff --git a/php/wp-cli.php b/php/wp-cli.php index 5380e8a27..f1fa299ce 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -12,8 +12,6 @@ \WP_CLI\Utils\load_dependencies(); -WP_CLI::init(); - WP_CLI::get_runner()->before_wp_load(); // Load wp-config.php code, in the global scope From 8f25e9d1dee9e65da7bac40003f2955d699847c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 02:22:12 +0300 Subject: [PATCH 2459/5359] properly merge keys that can contain multiple values --- php/WP_CLI/Configurator.php | 45 +++++++++++++++++-------------------- php/WP_CLI/Runner.php | 8 +++---- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 27969b877..ed79ee580 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -5,6 +5,7 @@ class Configurator { private $spec; + private $config = array(); function __construct( $path ) { $this->spec = include $path; @@ -17,11 +18,17 @@ function __construct( $path ) { 'multiple' => false, ); - foreach ( $this->spec as &$option ) { - $option = array_merge( $defaults, $option ); + foreach ( $this->spec as $key => &$details ) { + $details = array_merge( $defaults, $details ); + + $this->config[ $key ] = $details['default']; } } + function to_array() { + return $this->config; + } + /** * Get configuration specification, i.e. list of accepted keys. * @@ -80,8 +87,6 @@ function parse_args( $arguments ) { /** * Load values from a YML file and sanitize them according to the spec. - * - * @return array */ function load_config( $yml_file ) { if ( $yml_file ) @@ -89,40 +94,32 @@ function load_config( $yml_file ) { else $config = array(); - $sanitized_config = array(); - foreach ( $this->spec as $key => $details ) { if ( $details['file'] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; - if ( $details['multiple'] && !is_array( $value ) ) { - $value = array( $value ); - } + if ( $details['multiple'] ) { + if ( !is_array( $value ) ) { + $value = array( $value ); + } - $sanitized_config[ $key ] = $value; + $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); + } else { + $this->config[ $key ] = $value; + } } } // Make sure config-file-relative paths are made absolute. $yml_file_dir = dirname( $yml_file ); - if ( isset( $sanitized_config['path'] ) ) - self::absolutize( $sanitized_config['path'], $yml_file_dir ); + if ( isset( $this->config['path'] ) ) + self::absolutize( $this->config['path'], $yml_file_dir ); - if ( isset( $sanitized_config['require'] ) ) { - foreach ( $sanitized_config['require'] as &$path ) { + if ( isset( $this->config['require'] ) ) { + foreach ( $this->config['require'] as &$path ) { self::absolutize( $path, $yml_file_dir ); } } - - return $sanitized_config; - } - - public function get_defaults() { - $defaults = array(); - foreach ( $this->spec as $key => $details ) { - $defaults[ $key ] = $details['default']; - } - return $defaults; } private static function absolutize( &$path, $base ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 643769c18..e70b429ea 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -372,11 +372,9 @@ private function init_config() { $this->project_config_path = self::get_project_config_path(); $configurator = \WP_CLI::get_configurator(); - $this->config = array_merge( - $configurator->get_defaults(), - $configurator->load_config( $this->global_config_path ), - $configurator->load_config( $this->project_config_path ) - ); + $configurator->load_config( $this->global_config_path ); + $configurator->load_config( $this->project_config_path ); + $this->config = $configurator->to_array(); foreach ( $runtime_config as $key => $value ) { if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { From 1c4d4bea0c18a11d57ee71ec3d0d6036b387fcbe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 03:08:07 +0300 Subject: [PATCH 2460/5359] fix case where a file-only config key would make a runtime arg of the same name disappear --- php/WP_CLI/Configurator.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index ed79ee580..ff2d20456 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -64,18 +64,17 @@ function parse_args( $arguments ) { foreach ( $mixed_args as $tmp ) { list( $key, $value ) = $tmp; - if ( isset( $this->spec[ $key ] ) ) { + if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] ) { $details = $this->spec[ $key ]; - if ( $details['runtime'] ) { - if ( isset( $details['deprecated'] ) ) { - fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); - } - if ( $details['multiple'] ) { - $runtime_config[ $key ][] = $value; - } else { - $runtime_config[ $key ] = $value; - } + if ( isset( $details['deprecated'] ) ) { + fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); + } + + if ( $details['multiple'] ) { + $runtime_config[ $key ][] = $value; + } else { + $runtime_config[ $key ] = $value; } } else { $assoc_args[ $key ] = $value; From 6b26aad4a4bd9c53c5f2294ee02848687978a74f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 03:13:52 +0300 Subject: [PATCH 2461/5359] global flags have 'runtime' key '', which is falsy --- php/WP_CLI/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index ff2d20456..7be52c1b9 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -64,7 +64,7 @@ function parse_args( $arguments ) { foreach ( $mixed_args as $tmp ) { list( $key, $value ) = $tmp; - if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] ) { + if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { $details = $this->spec[ $key ]; if ( isset( $details['deprecated'] ) ) { From 19fb920fbae11001f120957420c3626029a5a186 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 03:14:50 +0300 Subject: [PATCH 2462/5359] separate YAML parsing from config merging --- php/WP_CLI/Configurator.php | 30 ++------------------------ php/WP_CLI/Runner.php | 42 +++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 7be52c1b9..791c6c5a1 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -84,47 +84,21 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args, $runtime_config ); } - /** - * Load values from a YML file and sanitize them according to the spec. - */ - function load_config( $yml_file ) { - if ( $yml_file ) - $config = spyc_load_file( $yml_file ); - else - $config = array(); - + function merge_config( $config ) { foreach ( $this->spec as $key => $details ) { if ( $details['file'] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; + if ( $details['multiple'] ) { if ( !is_array( $value ) ) { $value = array( $value ); } - $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); } else { $this->config[ $key ] = $value; } } } - - // Make sure config-file-relative paths are made absolute. - $yml_file_dir = dirname( $yml_file ); - - if ( isset( $this->config['path'] ) ) - self::absolutize( $this->config['path'], $yml_file_dir ); - - if ( isset( $this->config['require'] ) ) { - foreach ( $this->config['require'] as &$path ) { - self::absolutize( $path, $yml_file_dir ); - } - } - } - - private static function absolutize( &$path, $base ) { - if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { - $path = $base . DIRECTORY_SEPARATOR . $path; - } } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e70b429ea..498815bd4 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -372,20 +372,44 @@ private function init_config() { $this->project_config_path = self::get_project_config_path(); $configurator = \WP_CLI::get_configurator(); - $configurator->load_config( $this->global_config_path ); - $configurator->load_config( $this->project_config_path ); + foreach ( array( $this->global_config_path, $this->project_config_path ) as $config_path ) { + $configurator->merge_config( self::load_config( $config_path ) ); + } + $configurator->merge_config( $runtime_config ); $this->config = $configurator->to_array(); - foreach ( $runtime_config as $key => $value ) { - if ( isset( $this->config[ $key ] ) && is_array( $this->config[ $key ] ) ) { - $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); - } else { - $this->config[ $key ] = $value; + if ( !isset( $this->config['path'] ) ) { + $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); + } + } + + /** + * Load values from a YML file. + */ + private static function load_config( $yml_file ) { + if ( !$yml_file ) + return array(); + + $config = spyc_load_file( $yml_file ); + + // Make sure config-file-relative paths are made absolute. + $yml_file_dir = dirname( $yml_file ); + + if ( isset( $config['path'] ) ) + self::absolutize( $config['path'], $yml_file_dir ); + + if ( isset( $config['require'] ) ) { + foreach ( $config['require'] as &$path ) { + self::absolutize( $path, $yml_file_dir ); } } - if ( !isset( $this->config['path'] ) ) { - $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); + return $config; + } + + private static function absolutize( &$path, $base ) { + if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { + $path = $base . DIRECTORY_SEPARATOR . $path; } } From c848c9c3bc39c1ed161d716808b0b5579b0b863d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 03:34:03 +0300 Subject: [PATCH 2463/5359] arrayify require: key --- php/WP_CLI/Runner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 498815bd4..42a943dae 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -399,6 +399,7 @@ private static function load_config( $yml_file ) { self::absolutize( $config['path'], $yml_file_dir ); if ( isset( $config['require'] ) ) { + self::arrayify( $config['require'] ); foreach ( $config['require'] as &$path ) { self::absolutize( $path, $yml_file_dir ); } @@ -407,6 +408,12 @@ private static function load_config( $yml_file ) { return $config; } + private static function arrayify( &$val ) { + if ( !is_array( $val ) ) { + $val = array( $val ); + } + } + private static function absolutize( &$path, $base ) { if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { $path = $base . DIRECTORY_SEPARATOR . $path; From d6d8771791e7e9a71dacabe8371608e095520798 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 24 Oct 2013 03:53:28 +0300 Subject: [PATCH 2464/5359] behat: replace --config with WP_CLI_CONFIG_PATH --- features/flags.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index 8f290a0a7..9d1dcc93e 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -134,7 +134,7 @@ Feature: Global flags This is a custom command. """ - When I run `wp --config=wp-cli2.yml test req 'This is a custom command.'` + When I run `WP_CLI_CONFIG_PATH=wp-cli2.yml wp test req 'This is a custom command.'` Then STDOUT should contain: """ This is a custom command. From 4fff53f07a111a6b16751701489a270d2c1692fc Mon Sep 17 00:00:00 2001 From: wojsmol <wojsmol@wp.pl> Date: Thu, 24 Oct 2013 20:57:06 +0200 Subject: [PATCH 2465/5359] Change cd $(wp theme path) is cd $(wp plugin path) in plugin.php --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 3bb17465f..a9a2e838b 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -220,7 +220,7 @@ function toggle( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * cd $(wp theme path) + * cd $(wp plugin path) */ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); From 7a1499e0a3683f9d51dc18d73d8b087685a9e318 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Oct 2013 00:39:57 +0300 Subject: [PATCH 2466/5359] set default global config path; also, ignore if config file doesn't exist see #698 --- php/WP_CLI/Runner.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 42a943dae..2e59a706a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -37,6 +37,22 @@ private function do_early_invoke( $when ) { } } + private static function get_global_config_path() { + $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + if ( isset( $runtime_config['config'] ) ) { + $config_path = $runtime_config['config']; + } + + if ( !$config_path ) { + $config_path = getenv( 'HOME' ) . '/.config/wp-cli.yml'; + } + + if ( !is_readable( $config_path ) ) + return false; + + return $config_path; + } + private static function get_project_config_path() { $config_files = array( 'wp-cli.local.yml', @@ -364,11 +380,7 @@ private function init_config() { list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( $args, $assoc_args ); - $this->global_config_path = getenv( 'WP_CLI_CONFIG_PATH' ); - if ( isset( $runtime_config['config'] ) ) { - $this->global_config_path = $runtime_config['config']; - } - + $this->global_config_path = self::get_global_config_path(); $this->project_config_path = self::get_project_config_path(); $configurator = \WP_CLI::get_configurator(); From 570b8b078a37a95ef4c6b3390aad3371d264c9c3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Oct 2013 01:04:46 +0300 Subject: [PATCH 2467/5359] move link to contributor guide higher up --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index abb95cf6d..c334da485 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ WP-CLI -======== +====== [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) @@ -17,15 +17,20 @@ For documentation and examples, check out [wp-cli.org](http://wp-cli.org/) and t Also, WordPress Answers has a growing list of [WP-CLI related questions](http://wordpress.stackexchange.com/questions/tagged/wp-cli). +If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. + I'm running into troubles, what can I do? ----------------------------------------- To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). If you're reporting a bug, please also post the output from `wp --info`. +How can I help? +--------------- +See [CONTRIBUTING.md](CONTRIBUTING.md). + Credits ------- - Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: * [Drush](http://drush.ws/) for... a lot of things @@ -41,9 +46,3 @@ Who's behind this thing? We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). - -Contributing ------------- -See [CONTRIBUTING.md](CONTRIBUTING.md). - -If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. From 370d40c047e2b448f77a668734691955bca475b4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Oct 2013 01:18:07 +0300 Subject: [PATCH 2468/5359] behat: avoid making a request to the wp.org API each time a wp-config.php is needed it's not worth it for throwaway test installs --- features/bootstrap/FeatureContext.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 498e442b2..35d921724 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -162,8 +162,12 @@ public function download_wp( $subdir = '' ) { copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); } - public function create_config() { - $this->proc( 'wp core config', self::$db_settings )->run_check(); + public function create_config( $subdir = '' ) { + $params = self::$db_settings; + $params['dbprefix'] = $subdir ?: 'wp_'; + + $params['skip-salts'] = true; + $this->proc( 'wp core config', $params )->run_check( $subdir ); } public function install_wp( $subdir = '' ) { @@ -171,10 +175,7 @@ public function install_wp( $subdir = '' ) { $this->create_run_dir(); $this->download_wp( $subdir ); - $db_args = self::$db_settings; - $db_args['dbprefix'] = $subdir ?: 'wp_'; - - $this->proc( 'wp core config', $db_args )->run_check( $subdir ); + $this->create_config( $subdir ); $install_args = array( 'url' => 'http://example.com', From 8b97fa9f156c40f2adb277f8ee42479fbb808145 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 26 Oct 2013 23:28:57 +0300 Subject: [PATCH 2469/5359] replace 'subcommand' with 'command' in doc strings and inline comments see #848 --- bin/wp | 2 +- features/config.feature | 2 +- php/WP_CLI/Dispatcher/CompositeCommand.php | 4 ++-- templates/man-params.mustache | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/wp b/bin/wp index 4974e1887..25ea35d27 100755 --- a/bin/wp +++ b/bin/wp @@ -40,7 +40,7 @@ else fi # Pass in the path to php so that wp-cli knows which one -# to use if it re-launches itself to run subcommands +# to use if it re-launches itself to run other commands. export WP_CLI_PHP_USED="$php" exec "$php" $WP_CLI_PHP_ARGS "$SCRIPT_PATH" "$@" diff --git a/features/config.feature b/features/config.feature index 42dfe081f..6771d130d 100644 --- a/features/config.feature +++ b/features/config.feature @@ -67,7 +67,7 @@ Feature: Have a config file wp-cli.yml """ - Scenario: Disabled subcommands + Scenario: Disabled commands Given an empty directory And a config.yml file: """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 98cbbe734..f57d1f924 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -56,7 +56,7 @@ function get_longdesc() { } function get_synopsis() { - return '<subcommand>'; + return '<command>'; } function invoke( $args, $assoc_args ) { @@ -75,7 +75,7 @@ function show_usage() { } \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $this->name <subcommand>' for more information on a specific subcommand." ); + \WP_CLI::line( "See 'wp help $this->name <command>' for more information on a specific command." ); } function find_subcommand( &$args ) { diff --git a/templates/man-params.mustache b/templates/man-params.mustache index 2d3383f57..990412b74 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -5,4 +5,4 @@ {{desc}} {{/parameters}} -Run 'wp help <subcommand>' to get more information on a specific command. +Run 'wp help <command>' to get more information on a specific command. From ef23a97bdafeaac00061ed54913fd500e02a78b5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Oct 2013 23:29:53 +0200 Subject: [PATCH 2470/5359] behat: split step definition files --- features/bootstrap/FeatureContext.php | 2 +- features/steps/given.php | 105 +++++++++++++++ features/steps/{basic_steps.php => then.php} | 134 ------------------- features/steps/when.php | 39 ++++++ 4 files changed, 145 insertions(+), 135 deletions(-) create mode 100644 features/steps/given.php rename features/steps/{basic_steps.php => then.php} (54%) create mode 100644 features/steps/when.php diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 35d921724..d1650f5ba 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -79,7 +79,7 @@ public function __construct( array $parameters ) { } public function getStepDefinitionResources() { - return array( __DIR__ . '/../steps/basic_steps.php' ); + return glob( __DIR__ . '/../steps/*.php' ); } public function getHookDefinitionResources() { diff --git a/features/steps/given.php b/features/steps/given.php new file mode 100644 index 000000000..998a01313 --- /dev/null +++ b/features/steps/given.php @@ -0,0 +1,105 @@ +<?php + +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode; + +$steps->Given( '/^an empty directory$/', + function ( $world ) { + $world->create_run_dir(); + } +); + +$steps->Given( '/^a ([^\s]+) file:$/', + function ( $world, $path, PyStringNode $content ) { + $content = (string) $content . "\n"; + $full_path = $world->variables['RUN_DIR'] . "/$path"; + Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); + file_put_contents( $full_path, $content ); + } +); + +$steps->Given( '/^WP files$/', + function ( $world ) { + $world->download_wp(); + } +); + +$steps->Given( '/^wp-config\.php$/', + function ( $world ) { + $world->create_config(); + } +); + +$steps->Given( '/^a database$/', + function ( $world ) { + $world->create_db(); + } +); + +$steps->Given( '/^a WP install$/', + function ( $world ) { + $world->install_wp(); + } +); + +$steps->Given( "/^a WP install in '([^\s]+)'$/", + function ( $world, $subdir ) { + $world->install_wp( $subdir ); + } +); + +$steps->Given( '/^a WP multisite install$/', + function ( $world ) { + $world->install_wp(); + $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network' ) )->run_check(); + } +); + +$steps->Given( '/^a custom wp-content directory$/', + function ( $world ) { + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $world->move_files( 'wp-content', 'my-content' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); + + $world->move_files( 'my-content/plugins', 'my-plugins' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } +); + +$steps->Given( '/^download:$/', + function ( $world, TableNode $table ) { + foreach ( $table->getHash() as $row ) { + $path = $world->replace_variables( $row['path'] ); + if ( file_exists( $path ) ) { + // assume it's the same file and skip re-download + continue; + } + + \Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); + } + } +); + +$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', + function ( $world, $stream, $output_filter, $key ) { + + if ( $output_filter ) { + $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; + if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) + $output = array_pop( $matches ); + else + $output = ''; + } else { + $output = $world->result->$stream; + } + $world->variables[ $key ] = trim( $output, "\n" ); + } +); + diff --git a/features/steps/basic_steps.php b/features/steps/then.php similarity index 54% rename from features/steps/basic_steps.php rename to features/steps/then.php index 44342b50b..75845c0fa 100644 --- a/features/steps/basic_steps.php +++ b/features/steps/then.php @@ -3,140 +3,6 @@ use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; -function invoke_proc( $proc, $mode, $subdir = null ) { - $map = array( - 'run' => 'run_check', - 'try' => 'run' - ); - $method = $map[ $mode ]; - - return $proc->$method( $subdir ); -} - -$steps->Given( '/^an empty directory$/', - function ( $world ) { - $world->create_run_dir(); - } -); - -$steps->Given( '/^a ([^\s]+) file:$/', - function ( $world, $path, PyStringNode $content ) { - $content = (string) $content . "\n"; - $full_path = $world->variables['RUN_DIR'] . "/$path"; - Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); - file_put_contents( $full_path, $content ); - } -); - -$steps->Given( '/^WP files$/', - function ( $world ) { - $world->download_wp(); - } -); - -$steps->Given( '/^wp-config\.php$/', - function ( $world ) { - $world->create_config(); - } -); - -$steps->Given( '/^a database$/', - function ( $world ) { - $world->create_db(); - } -); - -$steps->Given( '/^a WP install$/', - function ( $world ) { - $world->install_wp(); - } -); - -$steps->Given( "/^a WP install in '([^\s]+)'$/", - function ( $world, $subdir ) { - $world->install_wp( $subdir ); - } -); - -$steps->Given( '/^a WP multisite install$/', - function ( $world ) { - $world->install_wp(); - $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network' ) )->run_check(); - } -); - -$steps->Given( '/^a custom wp-content directory$/', - function ( $world ) { - $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; - - $wp_config_code = file_get_contents( $wp_config_path ); - - $world->move_files( 'wp-content', 'my-content' ); - $world->add_line_to_wp_config( $wp_config_code, - "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); - - $world->move_files( 'my-content/plugins', 'my-plugins' ); - $world->add_line_to_wp_config( $wp_config_code, - "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); - - file_put_contents( $wp_config_path, $wp_config_code ); - } -); - -$steps->Given( '/^download:$/', - function ( $world, TableNode $table ) { - foreach ( $table->getHash() as $row ) { - $path = $world->replace_variables( $row['path'] ); - if ( file_exists( $path ) ) { - // assume it's the same file and skip re-download - continue; - } - - \Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); - } - } -); - -$steps->When( '/^I (run|try) `([^`]+)`$/', - function ( $world, $mode, $cmd ) { - $cmd = $world->replace_variables( $cmd ); - $world->result = invoke_proc( $world->proc( $cmd ), $mode ); - } -); - -$steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", - function ( $world, $mode, $cmd, $subdir ) { - $cmd = $world->replace_variables( $cmd ); - $world->result = invoke_proc( $world->proc( $cmd ), $mode, $subdir ); - } -); - -$steps->When( '/^I (run|try) the previous command again$/', - function ( $world, $mode ) { - if ( !isset( $world->result ) ) - throw new \Exception( 'No previous command.' ); - - $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); - $world->result = invoke_proc( $proc, $mode ); - } -); - -$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', - function ( $world, $stream, $output_filter, $key ) { - - if ( $output_filter ) { - $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; - if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) - $output = array_pop( $matches ); - else - $output = ''; - } else { - $output = $world->result->$stream; - } - $world->variables[ $key ] = trim( $output, "\n" ); - } -); - $steps->Then( '/^the return code should be (\d+)$/', function ( $world, $return_code ) { if ( $return_code != $world->result->return_code ) { diff --git a/features/steps/when.php b/features/steps/when.php new file mode 100644 index 000000000..81b4c9a6d --- /dev/null +++ b/features/steps/when.php @@ -0,0 +1,39 @@ +<?php + +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode; + +function invoke_proc( $proc, $mode, $subdir = null ) { + $map = array( + 'run' => 'run_check', + 'try' => 'run' + ); + $method = $map[ $mode ]; + + return $proc->$method( $subdir ); +} + +$steps->When( '/^I (run|try) `([^`]+)`$/', + function ( $world, $mode, $cmd ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd ), $mode ); + } +); + +$steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", + function ( $world, $mode, $cmd, $subdir ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd ), $mode, $subdir ); + } +); + +$steps->When( '/^I (run|try) the previous command again$/', + function ( $world, $mode ) { + if ( !isset( $world->result ) ) + throw new \Exception( 'No previous command.' ); + + $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); + $world->result = invoke_proc( $proc, $mode ); + } +); + From fb4258e554bc9ef29278480e88b120849fcc35e6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Oct 2013 23:39:01 +0200 Subject: [PATCH 2471/5359] behat: always show all the details when an error occurs --- features/steps/then.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/steps/then.php b/features/steps/then.php index 75845c0fa..f63800467 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -52,7 +52,7 @@ function ( $world, TableNode $expected ) { $start = array_search( $expected_rows[0], $actual_rows ); if ( false === $start ) - throw new \Exception( $output ); + throw new \Exception( $world->result ); compareTables( $expected_rows, array_slice( $actual_rows, $start ), $output ); } @@ -64,7 +64,7 @@ function ( $world, PyStringNode $expected ) { $expected = $world->replace_variables( (string) $expected ); if ( !checkThatJsonStringContainsJsonString( $output, $expected ) ) { - throw new \Exception( $output ); + throw new \Exception( $world->result ); } }); @@ -78,7 +78,7 @@ function ( $world, PyStringNode $expected ) { $missing = array_diff( $expectedValues, $actualValues ); if ( !empty( $missing ) ) { - throw new \Exception( $output ); + throw new \Exception( $world->result ); } }); @@ -94,14 +94,14 @@ function ( $world, TableNode $expected ) { } if ( ! checkThatCsvStringContainsValues( $output, $expected_rows ) ) - throw new \Exception( $output ); + throw new \Exception( $world->result ); } ); $steps->Then( '/^(STDOUT|STDERR) should be empty$/', function ( $world, $stream ) { if ( !empty( $world->result->$stream ) ) { - throw new \Exception( $world->result->$stream ); + throw new \Exception( $world->result ); } } ); @@ -109,7 +109,7 @@ function ( $world, $stream ) { $steps->Then( '/^(STDOUT|STDERR) should not be empty$/', function ( $world, $stream ) { if ( '' === rtrim( $world->result->$stream, "\n" ) ) { - throw new Exception( "$stream is empty." ); + throw new Exception( $world->result ); } } ); @@ -125,12 +125,12 @@ function ( $world, $path, $action, $expected = null ) { switch ( $action ) { case 'exist': if ( !file_exists( $path ) ) { - throw new Exception( "$path doesn't exist." ); + throw new Exception( $world->result ); } break; case 'not exist': if ( file_exists( $path ) ) { - throw new Exception( "$path exists." ); + throw new Exception( $world->result ); } break; default: From 89da305935cc6c2cc388b32c02166b2dbfce3372 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 27 Oct 2013 23:58:59 +0200 Subject: [PATCH 2472/5359] behat: show downloaded core version particularly useful when WP_VERSION=latest --- ci/prepare.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/prepare.sh b/ci/prepare.sh index 2a5b0e8e8..562701740 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -19,6 +19,7 @@ curl http://behat.org/downloads/behat.phar > behat.phar ./ci/prepare-codesniffer.sh ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' +./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot From d8dda0714a8b2432f563923587085a50d8af5f06 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 28 Oct 2013 00:37:47 +0200 Subject: [PATCH 2473/5359] travis: test against WP 3.6.1 for now; see #846 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e36beae36..a5bf15a94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=latest + - WP_VERSION=3.6.1 - WP_VERSION=3.4.2 DEPLOY_BRANCH=master matrix: From 30eafbd71ba740c0bf7a7b3a85d4c1a9b06b7d19 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 28 Oct 2013 21:34:54 +0200 Subject: [PATCH 2474/5359] handle case where request to underscor.es fails see #822 --- php/commands/scaffold.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f7ba9b89e..31e672109 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -203,12 +203,20 @@ function _s( $args, $assoc_args ) { $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); - if ( !is_wp_error( $response ) && $response['response']['code'] == 200 ) - WP_CLI::success( "Created theme '".$data['theme_name']."'." ); + if ( is_wp_error( $response ) ) { + WP_CLI::error( $response ); + } + + $response_code = wp_remote_retrieve_response_code( $response ); + if ( 200 != $response_code ) { + WP_CLI::error( "Couldn't create theme (received $response_code response)." ); + } unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); + WP_CLI::success( "Created theme '{$data['theme_name']}'." ); + if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); From 49dc008412aa845b62a5f6193d06552828f5de94 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 28 Oct 2013 21:43:15 +0200 Subject: [PATCH 2475/5359] move OS detection to launch_editor_for_input() see #822 --- php/commands/post.php | 3 +-- php/utils.php | 15 ++++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 0dfc2763d..c4d8f24ba 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -123,8 +123,7 @@ public function edit( $args, $_ ) { protected function _edit( $content, $title ) { $content = apply_filters( 'the_editor_content', $content ); - $os = strpos( $_SERVER['OS'], 'indows' )===false ? 'linux' : 'windows'; - $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title, $os ); + $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title ); return ( is_string( $output ) ) ? apply_filters( 'content_save_pre', $output ) : $output; } diff --git a/php/utils.php b/php/utils.php index 1b7d956fa..23f6d5e36 100644 --- a/php/utils.php +++ b/php/utils.php @@ -256,7 +256,7 @@ function pick_fields( $item, $fields ) { * @return str|bool Edited text, if file is saved from editor * False, if no change to file */ -function launch_editor_for_input( $input, $title = 'WP-CLI', $os='linux' ) { +function launch_editor_for_input( $input, $title = 'WP-CLI' ) { $tmpfile = wp_tempnam( $title ); @@ -266,10 +266,15 @@ function launch_editor_for_input( $input, $title = 'WP-CLI', $os='linux' ) { $output = ''; file_put_contents( $tmpfile, $input ); - if( $os==='linux' ) - \WP_CLI::launch( "\${EDITOR:-vi} '$tmpfile'" ); - else - exec("notepad $tmpfile" ); + $editor = getenv( 'EDITOR' ); + if ( !$editor ) { + if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) ) + $editor = 'notepad'; + else + $editor = 'vi'; + } + + \WP_CLI::launch( \WP_CLI\Utils\esc_cmd( "$editor %s", $tmpfile ) ); $output = file_get_contents( $tmpfile ); From c6c0a4ddeff4c565ca090488b7e554dee730c4b4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 28 Oct 2013 21:55:41 +0200 Subject: [PATCH 2476/5359] use escapeshellarg() instead of esc_cmd(), because the $editor variable can contain %s see #822 --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 23f6d5e36..d1713b54e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -274,7 +274,7 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { $editor = 'vi'; } - \WP_CLI::launch( \WP_CLI\Utils\esc_cmd( "$editor %s", $tmpfile ) ); + \WP_CLI::launch( "$editor " . escapeshellarg( $tmpfile ) ); $output = file_get_contents( $tmpfile ); From 5b7bfb25ef6b33934a404474a253af5eada90946 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 30 Oct 2013 13:40:38 +0200 Subject: [PATCH 2477/5359] replace rename() with copy() + unlink() --- php/commands/core.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index b0ddcd23b..97ebc1ecc 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -111,7 +111,10 @@ private static function _move_overwrite_files( $source, $dest ) { rmdir( $src ); continue; } - rename( $src, $dst ); + + // rename() is not reliable inside VMs: https://github.com/wp-cli/wp-cli/issues/853 + copy( $src, $dst ); + unlink( $src ); } rmdir( $source ); } From 532bb25f29a713cfff6466b52bcf31f17a4800c1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 30 Oct 2013 14:06:26 +0200 Subject: [PATCH 2478/5359] first copy all the files, then remove the temporary dir --- php/commands/core.php | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 97ebc1ecc..d129ac67f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -87,36 +87,38 @@ private static function _extract( $tarball, $dest ) { $phar->extractTo( dirname( $tempdir ), null, true ); - self::_move_overwrite_files( $tempdir, $dest ); + self::_copy_overwrite_files( $tempdir, $dest ); - rmdir( dirname( $tempdir ) ); + self::_rmdir( dirname( $tempdir ) ); } - private static function _move_overwrite_files( $source, $dest ) { - $flags = FilesystemIterator::SKIP_DOTS - | FilesystemIterator::KEY_AS_PATHNAME - | FilesystemIterator::CURRENT_AS_FILEINFO; - - $dstOffset = strlen( $source ); + private static function _copy_overwrite_files( $source, $dest ) { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::SELF_FIRST); + + foreach ( $iterator as $item ) { + if ( $item->isDir() ) { + $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); + if ( !is_dir( $dest_path ) ) { + mkdir( $dest_path ); + } + } else { + copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ); + } + } + } - foreach( new RecursiveIteratorIterator ( - new RecursiveDirectoryIterator( $source, $flags ), + private static function _rmdir( $dir ) { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST - ) as $src ) { - $dst = $dest . substr( $src, $dstOffset ); - $dstdir = dirname( $dst ); - if ( ! is_dir( $dstdir ) ) continue; - - if ( $src->isDir() && is_dir( $dst ) ) { - rmdir( $src ); - continue; - } + ); - // rename() is not reliable inside VMs: https://github.com/wp-cli/wp-cli/issues/853 - copy( $src, $dst ); - unlink( $src ); + foreach ( $files as $fileinfo ) { + $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; + $todo( $fileinfo->getRealPath() ); } - rmdir( $source ); } private static function _request( $method, $url, $headers = array(), $options = array() ) { From 5c52aa949334a205932ffc1f10426c814d9632a7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 30 Oct 2013 14:18:34 +0200 Subject: [PATCH 2479/5359] bump version to 0.13-alpha3 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index f1fa299ce..ebeac71ea 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13-alpha2' ); +define( 'WP_CLI_VERSION', '0.13-alpha3' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From fd211be75df0f101777ffa8c280f8892cefb65ca Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 30 Oct 2013 14:19:57 +0200 Subject: [PATCH 2480/5359] travis: switch back to WP_VERSION=latest see #846 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a5bf15a94..4bff5686f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=3.6.1 + - WP_VERSION=latest - WP_VERSION=3.4.2 DEPLOY_BRANCH=master matrix: From d133837c8c494b03ca4b068b7de8c178518b80cd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Nov 2013 23:39:35 +0200 Subject: [PATCH 2481/5359] test against latest stable release of WP, instead of the master revision from the github mirror --- templates/.travis.yml | 4 ++-- templates/install-wp-tests.sh | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index de2d819e5..4f688b98d 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -5,8 +5,8 @@ php: - 5.4 env: - - WP_VERSION=master WP_MULTISITE=0 - - WP_VERSION=master WP_MULTISITE=1 + - WP_VERSION=latest WP_MULTISITE=0 + - WP_VERSION=latest WP_MULTISITE=1 - WP_VERSION=3.5.1 WP_MULTISITE=0 - WP_VERSION=3.5.1 WP_MULTISITE=1 diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 82cd598ed..2320e61fd 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -16,7 +16,14 @@ set -ex # set up a WP install WP_CORE_DIR=/tmp/wordpress/ mkdir -p $WP_CORE_DIR -wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION + +if [ $WP_VERSION == 'latest' ]; then + ARCHIVE_NAME='latest' +else + ARCHIVE_NAME="wordpress-$WP_VERSION" +fi + +wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR # set up testing suite From d72b08d3ee9a78a568454554b0779c03fe3c168e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 1 Nov 2013 23:47:42 +0200 Subject: [PATCH 2482/5359] bump previous tested version to 3.6.1 --- templates/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 4f688b98d..bc729686e 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -7,8 +7,8 @@ php: env: - WP_VERSION=latest WP_MULTISITE=0 - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.5.1 WP_MULTISITE=0 - - WP_VERSION=3.5.1 WP_MULTISITE=1 + - WP_VERSION=3.6.1 WP_MULTISITE=0 + - WP_VERSION=3.6.1 WP_MULTISITE=1 before_script: - export WP_TESTS_DIR=/tmp/wordpress-tests/ From 64bce08a4dffc581a2eb57204cb21ac7bbeb1f0b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 4 Nov 2013 10:41:48 -0800 Subject: [PATCH 2483/5359] Include `--path` argument in `wp core download` --- php/commands/core.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index d129ac67f..d24f49712 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -13,6 +13,9 @@ class Core_Command extends WP_CLI_Command { * Download core WordPress files. * * ## OPTIONS + * + * [--path=<path>] + * : Specify the path in which to install WordPress. * * [--locale=<locale>] * : Select which language you want to download. From 074011c3476645c760e921d8bb1f60ffdda29692 Mon Sep 17 00:00:00 2001 From: Dion Hulse <contact-atlassian@dd32.id.au> Date: Thu, 7 Nov 2013 22:42:42 +1100 Subject: [PATCH 2484/5359] Use the SSL CA bundle that Requests includes, rather than relying upon the systems CA bundle which is often unavailable, or out of date. --- php/commands/core.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d24f49712..2a11de3a7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -126,7 +126,6 @@ private static function _rmdir( $dir ) { private static function _request( $method, $url, $headers = array(), $options = array() ) { try { - $options['verify'] = true; return Requests::get( $url, $headers, $options ); } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully From 24e296d1af078297c86a6eef49cd5bc0381ce2f2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 7 Nov 2013 18:10:51 +0200 Subject: [PATCH 2485/5359] make cacert.pem file available from Phar; closes #859 --- php/commands/core.php | 12 +++++++++++- utils/make-phar.php | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2a11de3a7..e0f2d7874 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -13,7 +13,7 @@ class Core_Command extends WP_CLI_Command { * Download core WordPress files. * * ## OPTIONS - * + * * [--path=<path>] * : Specify the path in which to install WordPress. * @@ -125,6 +125,16 @@ private static function _rmdir( $dir ) { } private static function _request( $method, $url, $headers = array(), $options = array() ) { + // cURL can't read Phar archives + if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { + $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; + + copy( + WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem', + $options['verify'] + ); + } + try { return Requests::get( $url, $headers, $options ); } catch( Requests_Exception $ex ) { diff --git a/utils/make-phar.php b/utils/make-phar.php index 0a7b16d83..4563f60a7 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -62,6 +62,7 @@ function add_file( $phar, $path ) { } add_file( $phar, './vendor/autoload.php' ); +add_file( $phar, './vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); $phar->setStub( <<<EOB #!/usr/bin/env php From a5c0302ba4fd8977b118ffc3a029ad9f72f6e83f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 9 Nov 2013 23:52:40 +0200 Subject: [PATCH 2486/5359] add behat test for #862 --- features/user.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/user.feature b/features/user.feature index 5f3319d11..14ecdf18a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -4,6 +4,10 @@ Feature: Manage WordPress users Given a WP install Scenario: User CRUD operations + When I try `wp user get bogus-user` + Then the return code should be 1 + And STDOUT should be empty + When I run `wp user create testuser testuser@example.com --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} From 60a19d7361bc34d089938ae99da3368106c9ab1f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 9 Nov 2013 23:54:22 +0200 Subject: [PATCH 2487/5359] move utilities for validating user ids/logins to FetcherUser class --- php/WP_CLI/Fetcher.php | 16 +++++++++++++ php/WP_CLI/FetcherUser.php | 41 +++++++++++++++++++++++++++++++++ php/commands/user.php | 47 ++++++++++++++++---------------------- 3 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 php/WP_CLI/Fetcher.php create mode 100644 php/WP_CLI/FetcherUser.php diff --git a/php/WP_CLI/Fetcher.php b/php/WP_CLI/Fetcher.php new file mode 100644 index 000000000..f1de345c9 --- /dev/null +++ b/php/WP_CLI/Fetcher.php @@ -0,0 +1,16 @@ +<?php + +namespace WP_CLI; + +interface Fetcher { + + // Returns the object if found; otherwise returns false + function get( $id ); + + // Returns the object if found; otherwise calls WP_CLI::error() + function get_check( $id ); + + // Returns the list of found objects + function get_many( $ids ); +} + diff --git a/php/WP_CLI/FetcherUser.php b/php/WP_CLI/FetcherUser.php new file mode 100644 index 000000000..1ed29bfcb --- /dev/null +++ b/php/WP_CLI/FetcherUser.php @@ -0,0 +1,41 @@ +<?php + +namespace WP_CLI; + +class FetcherUser implements Fetcher { + + public function get( $id_or_login ) { + if ( is_numeric( $id_or_login ) ) + $user = get_user_by( 'id', $id_or_login ); + else + $user = get_user_by( 'login', $id_or_login ); + + return $user; + } + + public function get_check( $id_or_login ) { + $user = $this->get( $id_or_login ); + + if ( ! $user ) { + \WP_CLI::error( "Invalid user ID or login: $id_or_login" ); + } + + return $user; + } + + public function get_many( $ids_or_logins ) { + $users = array(); + + foreach ( $ids_or_logins as $id_or_login ) { + $user = $this->get( $id_or_login ); + if ( $user ) { + $users[] = $user; + } else { + \WP_CLI::warning( "Invalid user ID or login: $id_or_login" ); + } + } + + return $users; + } +} + diff --git a/php/commands/user.php b/php/commands/user.php index 95c4d05f3..cf18fcb04 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -17,6 +17,10 @@ class User_Command extends \WP_CLI\CommandWithDBObject { 'roles' ); + public function __construct() { + $this->fetcher = new \WP_CLI\FetcherUser; + } + /** * List users. * @@ -95,7 +99,7 @@ public function _list( $args, $assoc_args ) { * wp user get bob --format=json > bob.json */ public function get( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); if ( method_exists( $user, 'to_array' ) ) { $user_data = $user->to_array(); @@ -129,11 +133,11 @@ public function delete( $args, $assoc_args ) { 'reassign' => null ) ); - foreach ( $args as $key => $arg ) { - $args[ $key ] = self::get_user( $arg )->ID; - } + $users = $this->fetcher->get_many( $args ); + + parent::_delete( $users, $assoc_args, function ( $user, $assoc_args ) { + $user_id = $user->ID; - parent::_delete( $args, $assoc_args, function ( $user_id, $assoc_args ) { if ( is_multisite() ) { $r = wpmu_delete_user( $user_id ); } else { @@ -243,11 +247,13 @@ public function create( $args, $assoc_args ) { * wp user update mary --user_pass=marypass */ public function update( $args, $assoc_args ) { - foreach ( $args as $key => $arg ) { - $args[ $key ] = self::get_user( $arg )->ID; + $user_ids = array(); + + foreach ( $this->fetcher->get_many( $args ) as $user ) { + $user_ids[] = $user->ID; } - parent::_update( $args, $assoc_args, 'wp_update_user' ); + parent::_update( $user_ids, $assoc_args, 'wp_update_user' ); } /** @@ -321,7 +327,7 @@ public function generate( $args, $assoc_args ) { * @subcommand set-role */ public function set_role( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); @@ -353,7 +359,7 @@ public function set_role( $args, $assoc_args ) { * @subcommand add-role */ public function add_role( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); $role = $args[1]; @@ -381,7 +387,7 @@ public function add_role( $args, $assoc_args ) { * @subcommand remove-role */ public function remove_role( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); if ( isset( $args[1] ) ) { $role = $args[1]; @@ -419,7 +425,7 @@ public function remove_role( $args, $assoc_args ) { * @subcommand add-cap */ public function add_cap( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); if ( $user ) { $cap = $args[1]; $user->add_cap( $cap ); @@ -447,7 +453,7 @@ public function add_cap( $args, $assoc_args ) { * @subcommand remove-cap */ public function remove_cap( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); if ( $user ) { $cap = $args[1]; $user->remove_cap( $cap ); @@ -472,7 +478,7 @@ public function remove_cap( $args, $assoc_args ) { * @subcommand list-caps */ public function list_caps( $args, $assoc_args ) { - $user = self::get_user( $args[0] ); + $user = $this->fetcher->get_check( $args[0] ); if ( $user ) { $user->get_role_caps(); @@ -488,19 +494,6 @@ public function list_caps( $args, $assoc_args ) { } } - private static function get_user( $id_or_login ) { - if ( is_numeric( $id_or_login ) ) - $user = get_user_by( 'id', $id_or_login ); - else - $user = get_user_by( 'login', $id_or_login ); - - if ( ! $user ) { - WP_CLI::warning( "Invalid user ID or login: $id_or_login" ); - } - - return $user; - } - /** * Import users from a CSV file. * From 733299f84f7cb39684db91fe010c51648356522d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 00:15:47 +0200 Subject: [PATCH 2488/5359] move utilities for validating plugin names to FetcherPlugin class --- php/WP_CLI/Fetcher.php | 6 +-- php/WP_CLI/FetcherPlugin.php | 57 ++++++++++++++++++++++++ php/commands/plugin.php | 86 ++++++++---------------------------- 3 files changed, 78 insertions(+), 71 deletions(-) create mode 100644 php/WP_CLI/FetcherPlugin.php diff --git a/php/WP_CLI/Fetcher.php b/php/WP_CLI/Fetcher.php index f1de345c9..58cf01f9b 100644 --- a/php/WP_CLI/Fetcher.php +++ b/php/WP_CLI/Fetcher.php @@ -4,13 +4,13 @@ interface Fetcher { - // Returns the object if found; otherwise returns false + // Returns the item if found; otherwise returns false function get( $id ); - // Returns the object if found; otherwise calls WP_CLI::error() + // Returns the item if found; otherwise calls WP_CLI::error() function get_check( $id ); - // Returns the list of found objects + // Returns the list of found items function get_many( $ids ); } diff --git a/php/WP_CLI/FetcherPlugin.php b/php/WP_CLI/FetcherPlugin.php new file mode 100644 index 000000000..03c656905 --- /dev/null +++ b/php/WP_CLI/FetcherPlugin.php @@ -0,0 +1,57 @@ +<?php + +namespace WP_CLI; + +class FetcherPlugin implements Fetcher { + + /** + * @param string $name The plugin slug + * @return string|false The plugin filename + */ + public function get( $name ) { + $plugins = get_plugins( '/' . $name ); + + if ( !empty( $plugins ) ) { + $file = $name . '/' . key( $plugins ); + } else { + $file = $name . '.php'; + + $plugins = get_plugins(); + + if ( !isset( $plugins[$file] ) ) { + return false; + } + } + + return $file; + } + + public function get_check( $name ) { + $file = $this->get( $name ); + + if ( ! $file ) { + \WP_CLI::error( "The '$name' plugin could not be found." ); + } + + return $file; + } + + public function get_many( $args ) { + $plugins = array(); + + foreach ( $args as $name ) { + $file = $this->get( $name ); + if ( $file ) { + $plugins[] = (object) array( + 'name' => $name, + 'file' => $file + ); + } else { + \WP_CLI::warning( "The '$name' plugin could not be found." ); + } + } + + return $plugins; + } +} + diff --git a/php/commands/plugin.php b/php/commands/plugin.php index a9a2e838b..948fa054f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -23,6 +23,8 @@ function __construct() { require_once ABSPATH.'wp-admin/includes/plugin-install.php'; parent::__construct(); + + $this->fetcher = new \WP_CLI\FetcherPlugin; } protected function get_upgrader_class( $force ) { @@ -87,23 +89,19 @@ public function search( $args, $assoc_args ) { } protected function status_single( $args ) { - $plugins = $this->validate_plugin_names( $args ); - if ( empty( $plugins ) ) - exit(1); - - list( $plugin ) = $plugins; + $file = $this->fetcher->get_check( $args[0] ); - $details = $this->get_details( $plugin ); + $details = $this->get_details( $file ); - $status = $this->format_status( $this->get_status( $plugin->file ), 'long' ); + $status = $this->format_status( $this->get_status( $file ), 'long' ); $version = $details['Version']; - if ( $this->has_update( $plugin->file ) ) + if ( $this->has_update( $file ) ) $version .= ' (%gUpdate available%n)'; echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'plugin-status.mustache', array( - 'slug' => $plugin->name, + 'slug' => $this->get_name( $file ), 'status' => $status, 'version' => $version, 'name' => $details['Name'], @@ -140,7 +138,7 @@ protected function get_all_items() { function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { activate_plugin( $plugin->file, '', $network_wide ); if ( $this->check_active( $plugin->file, $network_wide ) ) { @@ -168,7 +166,7 @@ function activate( $args, $assoc_args = array() ) { function deactivate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { deactivate_plugins( $plugin->file, false, $network_wide ); if ( ! $this->check_active( $plugin->file, $network_wide ) ) { @@ -196,7 +194,7 @@ function deactivate( $args, $assoc_args = array() ) { function toggle( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->check_active( $plugin->file, $network_wide ) ) { $this->deactivate( array( $plugin->name ), $assoc_args ); } else { @@ -226,7 +224,7 @@ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { - $plugins = $this->validate_plugin_names( $args ); + $plugins = $this->fetcher->get_many( $args ); if ( empty( $plugins ) ) return; @@ -294,7 +292,7 @@ protected function install_from_repo( $slug, $assoc_args ) { */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { $this->_delete( $plugin ); $this->install( array( $plugin->name ), $assoc_args ); } @@ -324,7 +322,7 @@ protected function get_item_list() { } protected function filter_item_list( $items, $args ) { - $basenames = wp_list_pluck( $this->validate_plugin_names( $args ), 'file' ); + $basenames = wp_list_pluck( $this->fetcher->get_many( $args ), 'file' ); return \WP_CLI\Utils\pick_fields( $items, $basenames ); } @@ -384,10 +382,7 @@ function install( $args, $assoc_args ) { * wp plugin get bbpress --format=json */ public function get( $args, $assoc_args ) { - $file = $this->_parse_name( $args[0] ); - if ( !$file ) { - WP_CLI::error( "The '{$args[0]}' plugin could not be found." ); - } + $file = $this->get_check( $args[0] ); $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); @@ -422,7 +417,7 @@ public function get( $args, $assoc_args ) { * wp plugin uninstall hello */ function uninstall( $args, $assoc_args = array() ) { - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( is_plugin_active( $plugin->file ) ) { WP_CLI::warning( "The '{$plugin->name}' plugin is active." ); continue; @@ -451,7 +446,7 @@ function uninstall( $args, $assoc_args = array() ) { * @subcommand is-installed */ function is_installed( $args, $assoc_args = array() ) { - if ( $this->_parse_name( $args[0] ) ) { + if ( $this->fetcher->get( $args[0] ) ) { exit( 0 ); } else { exit( 1 ); @@ -471,7 +466,7 @@ function is_installed( $args, $assoc_args = array() ) { * wp plugin delete hello */ function delete( $args, $assoc_args = array() ) { - foreach ( $this->validate_plugin_names( $args ) as $plugin ) { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->_delete( $plugin ) ) { WP_CLI::success( "Deleted '{$plugin->name}' plugin." ); } @@ -526,58 +521,13 @@ protected function get_status( $file ) { * @param object * @return array */ - private function get_details( $plugin ) { - $file = $plugin->file; - + private function get_details( $file ) { $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); $plugin_file = basename( $file ); return $plugin_folder[$plugin_file]; } - /** - * Parse the name of a plugin to a filename; check if it exists. - * - * @param string name - * @return string - */ - private function _parse_name( $name ) { - $plugins = get_plugins( '/' . $name ); - - if ( !empty( $plugins ) ) { - $file = $name . '/' . key( $plugins ); - } - else { - $file = $name . '.php'; - - $plugins = get_plugins(); - - if ( !isset( $plugins[$file] ) ) { - return false; - } - } - - return $file; - } - - private function validate_plugin_names( $args ) { - $plugins = array(); - - foreach ( $args as $name ) { - $file = $this->_parse_name( $name ); - if ( $file ) { - $plugins[] = (object) array( - 'name' => $name, - 'file' => $file - ); - } else { - WP_CLI::warning( "The '$name' plugin could not be found." ); - } - } - - return $plugins; - } - /** * Converts a plugin basename back into a friendly slug. */ From 87a91609259700d243d0e5a49f852fd5eec4ba09 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 00:41:55 +0200 Subject: [PATCH 2489/5359] convert Fetcher to abstract class --- php/WP_CLI/Fetcher.php | 55 +++++++++++++++++++++++++++++++----- php/WP_CLI/FetcherPlugin.php | 39 ++++--------------------- php/WP_CLI/FetcherUser.php | 27 +----------------- php/commands/plugin.php | 8 ++++-- php/commands/user.php | 2 +- 5 files changed, 60 insertions(+), 71 deletions(-) diff --git a/php/WP_CLI/Fetcher.php b/php/WP_CLI/Fetcher.php index 58cf01f9b..bf2446515 100644 --- a/php/WP_CLI/Fetcher.php +++ b/php/WP_CLI/Fetcher.php @@ -2,15 +2,56 @@ namespace WP_CLI; -interface Fetcher { +abstract class Fetcher { - // Returns the item if found; otherwise returns false - function get( $id ); + protected $msg; - // Returns the item if found; otherwise calls WP_CLI::error() - function get_check( $id ); + /** + * @param string $msg The message to display when an item is not found + */ + function __construct( $msg ) { + $this->msg = $msg; + } - // Returns the list of found items - function get_many( $ids ); + /** + * @param string $arg The raw CLI argument + * @return mixed|false The item if found; false otherwise + */ + abstract public function get( $arg ); + + /** + * Like get(), but calls WP_CLI::error() instead of returning false. + * + * @param string $arg The raw CLI argument + */ + public function get_check( $arg ) { + $item = $this->get( $arg ); + + if ( ! $item ) { + \WP_CLI::error( sprintf( $this->msg, $arg ) ); + } + + return $item; + } + + /** + * @param array The raw CLI arguments + * @return array The list of found items + */ + public function get_many( $args ) { + $items = array(); + + foreach ( $args as $arg ) { + $item = $this->get( $arg ); + + if ( $item ) { + $items[] = $item; + } else { + \WP_CLI::warning( sprintf( $this->msg, $arg ) ); + } + } + + return $items; + } } diff --git a/php/WP_CLI/FetcherPlugin.php b/php/WP_CLI/FetcherPlugin.php index 03c656905..3c8893a6e 100644 --- a/php/WP_CLI/FetcherPlugin.php +++ b/php/WP_CLI/FetcherPlugin.php @@ -2,12 +2,8 @@ namespace WP_CLI; -class FetcherPlugin implements Fetcher { +class FetcherPlugin extends Fetcher { - /** - * @param string $name The plugin slug - * @return string|false The plugin filename - */ public function get( $name ) { $plugins = get_plugins( '/' . $name ); @@ -23,35 +19,10 @@ public function get( $name ) { } } - return $file; - } - - public function get_check( $name ) { - $file = $this->get( $name ); - - if ( ! $file ) { - \WP_CLI::error( "The '$name' plugin could not be found." ); - } - - return $file; - } - - public function get_many( $args ) { - $plugins = array(); - - foreach ( $args as $name ) { - $file = $this->get( $name ); - if ( $file ) { - $plugins[] = (object) array( - 'name' => $name, - 'file' => $file - ); - } else { - \WP_CLI::warning( "The '$name' plugin could not be found." ); - } - } - - return $plugins; + return (object) array( + 'name' => $name, + 'file' => $file + ); } } diff --git a/php/WP_CLI/FetcherUser.php b/php/WP_CLI/FetcherUser.php index 1ed29bfcb..aea6ffbe1 100644 --- a/php/WP_CLI/FetcherUser.php +++ b/php/WP_CLI/FetcherUser.php @@ -2,7 +2,7 @@ namespace WP_CLI; -class FetcherUser implements Fetcher { +class FetcherUser extends Fetcher { public function get( $id_or_login ) { if ( is_numeric( $id_or_login ) ) @@ -12,30 +12,5 @@ public function get( $id_or_login ) { return $user; } - - public function get_check( $id_or_login ) { - $user = $this->get( $id_or_login ); - - if ( ! $user ) { - \WP_CLI::error( "Invalid user ID or login: $id_or_login" ); - } - - return $user; - } - - public function get_many( $ids_or_logins ) { - $users = array(); - - foreach ( $ids_or_logins as $id_or_login ) { - $user = $this->get( $id_or_login ); - if ( $user ) { - $users[] = $user; - } else { - \WP_CLI::warning( "Invalid user ID or login: $id_or_login" ); - } - } - - return $users; - } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 948fa054f..ab0bd6bed 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -24,7 +24,7 @@ function __construct() { parent::__construct(); - $this->fetcher = new \WP_CLI\FetcherPlugin; + $this->fetcher = new \WP_CLI\FetcherPlugin( "The '%s' plugin could not be found." ); } protected function get_upgrader_class( $force ) { @@ -89,7 +89,8 @@ public function search( $args, $assoc_args ) { } protected function status_single( $args ) { - $file = $this->fetcher->get_check( $args[0] ); + $plugin = $this->fetcher->get_check( $args[0] ); + $file = $plugin->file; $details = $this->get_details( $file ); @@ -382,7 +383,8 @@ function install( $args, $assoc_args ) { * wp plugin get bbpress --format=json */ public function get( $args, $assoc_args ) { - $file = $this->get_check( $args[0] ); + $plugin = $this->fetcher->get_check( $args[0] ); + $file = $plugin->file; $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); diff --git a/php/commands/user.php b/php/commands/user.php index cf18fcb04..df0c65e00 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -18,7 +18,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherUser; + $this->fetcher = new \WP_CLI\FetcherUser( "Invalid user ID or login: '%s'" ); } /** From 34b4c9d8e8f8defe3207b9131c07145595489235 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 00:50:14 +0200 Subject: [PATCH 2490/5359] extract FetcherTheme class --- php/WP_CLI/FetcherTheme.php | 17 +++++++++++++ php/commands/theme.php | 51 +++++++++---------------------------- 2 files changed, 29 insertions(+), 39 deletions(-) create mode 100644 php/WP_CLI/FetcherTheme.php diff --git a/php/WP_CLI/FetcherTheme.php b/php/WP_CLI/FetcherTheme.php new file mode 100644 index 000000000..032776343 --- /dev/null +++ b/php/WP_CLI/FetcherTheme.php @@ -0,0 +1,17 @@ +<?php + +namespace WP_CLI; + +class FetcherTheme extends Fetcher { + + public function get( $name ) { + $theme = wp_get_theme( $name ); + + if ( !$theme->exists() ) { + return false; + } + + return $theme; + } +} + diff --git a/php/commands/theme.php b/php/commands/theme.php index b5dccf3fb..8a8d6dd9e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -18,6 +18,12 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { 'version' ); + function __construct() { + parent::__construct(); + + $this->fetcher = new \WP_CLI\FetcherTheme( "The '%s' theme could not be found." ); + } + protected function get_upgrader_class( $force ) { return $force ? '\\WP_CLI\\DestructiveThemeUpgrader' : 'Theme_Upgrader'; } @@ -76,7 +82,7 @@ public function search( $args, $assoc_args ) { } protected function status_single( $args ) { - $theme = $this->parse_name( $args[0] ); + $theme = $this->fetcher->get_check( $args[0] ); $status = $this->format_status( $this->get_status( $theme ), 'long' ); @@ -110,7 +116,7 @@ protected function get_status( $theme ) { * : The theme to activate. */ public function activate( $args = array() ) { - $theme = $this->parse_name( $args[0] ); + $theme = $this->fetcher->get_check( $args[0] ); switch_theme( $theme->get_template(), $theme->get_stylesheet() ); @@ -148,7 +154,7 @@ public function path( $args, $assoc_args ) { if ( empty( $args ) ) { $path = WP_CONTENT_DIR . '/themes'; } else { - $theme = $this->parse_name( $args[0] ); + $theme = $this->fetcher->get_check( $args[0] ); $path = $theme->get_stylesheet_directory(); @@ -208,7 +214,7 @@ protected function get_item_list() { protected function filter_item_list( $items, $args ) { $theme_files = array(); foreach ( $args as $arg ) { - $theme_files[] = $this->parse_name( $arg )->get_stylesheet_directory(); + $theme_files[] = $this->fetcher->get_check( $arg )->get_stylesheet_directory(); } return \WP_CLI\Utils\pick_fields( $items, $theme_files ); @@ -267,7 +273,7 @@ function install( $args, $assoc_args ) { * wp theme get twentytwelve --format=json */ public function get( $args, $assoc_args ) { - $theme = $this->parse_name( $args[0] ); + $theme = $this->fetcher->get_check( $args[0] ); // WP_Theme object employs magic getter, unfortunately $theme_vars = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', @@ -348,7 +354,7 @@ function is_installed( $args, $assoc_args = array() ) { * wp theme delete twentyeleven */ function delete( $args ) { - foreach ( $this->validate_theme_names( $args ) as $theme ) { + foreach ( $this->fetcher->get_many( $args ) as $theme ) { $theme_slug = $theme->get_stylesheet(); if ( $this->is_active_theme( $theme ) ) { @@ -388,39 +394,6 @@ function delete( $args ) { function _list( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); } - - /** - * Parse the name of a plugin to a filename; check if it exists. - * - * @param string name - * @return object - */ - private function parse_name( $name ) { - $theme = wp_get_theme( $name ); - - if ( !$theme->exists() ) { - WP_CLI::error( "The theme '$name' could not be found." ); - exit; - } - - return $theme; - } - - private function validate_theme_names( $args ) { - $themes = array(); - - foreach ( $args as $name ) { - $theme = wp_get_theme( $name ); - - if ( !$theme->exists() ) { - WP_CLI::warning( "The '$name' theme could not be found." ); - } else { - $themes[] = $theme; - } - } - - return $themes; - } } WP_CLI::add_command( 'theme', 'Theme_Command' ); From 794ad160c041dd92f127a34fe88907db814efd4f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 00:58:23 +0200 Subject: [PATCH 2491/5359] extract FetcherComment class --- php/WP_CLI/FetcherComment.php | 18 ++++++++++++++++++ php/commands/comment.php | 22 ++++++---------------- 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 php/WP_CLI/FetcherComment.php diff --git a/php/WP_CLI/FetcherComment.php b/php/WP_CLI/FetcherComment.php new file mode 100644 index 000000000..806ece1f0 --- /dev/null +++ b/php/WP_CLI/FetcherComment.php @@ -0,0 +1,18 @@ +<?php + +namespace WP_CLI; + +class FetcherComment extends Fetcher { + + public function get( $arg ) { + $comment_id = (int) $arg; + $comment = get_comment( $comment_id ); + + if ( is_null( $comment ) ) { + return false; + } + + return $comment; + } +} + diff --git a/php/commands/comment.php b/php/commands/comment.php index 8d97df2e8..cb7c4f06d 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -18,6 +18,10 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { 'comment_author_email', ); + public function __construct() { + $this->fetcher = new \WP_CLI\FetcherComment( "Comment with ID %s does not exist." ); + } + /** * Insert a comment. * @@ -192,7 +196,7 @@ private function call( $args, $status, $success, $failure ) { } private function set_status( $args, $status, $success ) { - $comment = $this->_fetch_comment( $args ); + $comment = $this->fetcher->get_check( $args[0] ); $r = wp_set_comment_status( $comment->comment_ID, 'approve', true ); @@ -364,24 +368,10 @@ public function status( $args, $assoc_args ) { * wp comment exists 1337 */ public function exists( $args ) { - if ( $this->_fetch_comment( $args ) ) { + if ( $this->fetcher->get( $args[0] ) ) { WP_CLI::success( "Comment with ID $args[0] exists." ); } } - - /** - * A helper function fetching a comment object from comment_id. - */ - private function _fetch_comment( $args ) { - $comment_id = (int) $args[0]; - $comment = get_comment( $comment_id ); - - if ( is_null( $comment ) ) { - WP_CLI::error( "Comment with ID $args[0] does not exist." ); - } - - return $comment; - } } WP_CLI::add_command( 'comment', 'Comment_Command' ); From 69c005a97b59c09274eb05b644f26ccb9f47722b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 01:01:38 +0200 Subject: [PATCH 2492/5359] keep 'not found' message in Fetcher child classes otherwise, might get a mismatch between the class and the message --- php/WP_CLI/Fetcher.php | 6 +----- php/WP_CLI/FetcherComment.php | 2 ++ php/WP_CLI/FetcherPlugin.php | 2 ++ php/WP_CLI/FetcherTheme.php | 2 ++ php/WP_CLI/FetcherUser.php | 2 ++ php/commands/comment.php | 2 +- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- php/commands/user.php | 2 +- 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Fetcher.php b/php/WP_CLI/Fetcher.php index bf2446515..0ef9f92a5 100644 --- a/php/WP_CLI/Fetcher.php +++ b/php/WP_CLI/Fetcher.php @@ -4,14 +4,10 @@ abstract class Fetcher { - protected $msg; - /** * @param string $msg The message to display when an item is not found */ - function __construct( $msg ) { - $this->msg = $msg; - } + protected $msg; /** * @param string $arg The raw CLI argument diff --git a/php/WP_CLI/FetcherComment.php b/php/WP_CLI/FetcherComment.php index 806ece1f0..167b0432e 100644 --- a/php/WP_CLI/FetcherComment.php +++ b/php/WP_CLI/FetcherComment.php @@ -4,6 +4,8 @@ class FetcherComment extends Fetcher { + protected $msg = "Comment with ID %s does not exist."; + public function get( $arg ) { $comment_id = (int) $arg; $comment = get_comment( $comment_id ); diff --git a/php/WP_CLI/FetcherPlugin.php b/php/WP_CLI/FetcherPlugin.php index 3c8893a6e..bd6871290 100644 --- a/php/WP_CLI/FetcherPlugin.php +++ b/php/WP_CLI/FetcherPlugin.php @@ -4,6 +4,8 @@ class FetcherPlugin extends Fetcher { + protected $msg = "The '%s' plugin could not be found."; + public function get( $name ) { $plugins = get_plugins( '/' . $name ); diff --git a/php/WP_CLI/FetcherTheme.php b/php/WP_CLI/FetcherTheme.php index 032776343..5066983f0 100644 --- a/php/WP_CLI/FetcherTheme.php +++ b/php/WP_CLI/FetcherTheme.php @@ -4,6 +4,8 @@ class FetcherTheme extends Fetcher { + protected $msg = "The '%s' theme could not be found."; + public function get( $name ) { $theme = wp_get_theme( $name ); diff --git a/php/WP_CLI/FetcherUser.php b/php/WP_CLI/FetcherUser.php index aea6ffbe1..e1111e0ec 100644 --- a/php/WP_CLI/FetcherUser.php +++ b/php/WP_CLI/FetcherUser.php @@ -4,6 +4,8 @@ class FetcherUser extends Fetcher { + protected $msg = "Invalid user ID or login: '%s'"; + public function get( $id_or_login ) { if ( is_numeric( $id_or_login ) ) $user = get_user_by( 'id', $id_or_login ); diff --git a/php/commands/comment.php b/php/commands/comment.php index cb7c4f06d..aa73d1619 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -19,7 +19,7 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherComment( "Comment with ID %s does not exist." ); + $this->fetcher = new \WP_CLI\FetcherComment; } /** diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ab0bd6bed..ff90c5c30 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -24,7 +24,7 @@ function __construct() { parent::__construct(); - $this->fetcher = new \WP_CLI\FetcherPlugin( "The '%s' plugin could not be found." ); + $this->fetcher = new \WP_CLI\FetcherPlugin; } protected function get_upgrader_class( $force ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 8a8d6dd9e..d5437785b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -21,7 +21,7 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { function __construct() { parent::__construct(); - $this->fetcher = new \WP_CLI\FetcherTheme( "The '%s' theme could not be found." ); + $this->fetcher = new \WP_CLI\FetcherTheme; } protected function get_upgrader_class( $force ) { diff --git a/php/commands/user.php b/php/commands/user.php index df0c65e00..cf18fcb04 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -18,7 +18,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherUser( "Invalid user ID or login: '%s'" ); + $this->fetcher = new \WP_CLI\FetcherUser; } /** From d71f95de6dcdd16b83d9db52fe4524aa919f6dc1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 01:14:08 +0200 Subject: [PATCH 2493/5359] extract FetcherPost class --- php/WP_CLI/FetcherComment.php | 2 +- php/WP_CLI/FetcherPost.php | 13 +++++++++++++ php/commands/post.php | 12 ++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 php/WP_CLI/FetcherPost.php diff --git a/php/WP_CLI/FetcherComment.php b/php/WP_CLI/FetcherComment.php index 167b0432e..cc02cbb97 100644 --- a/php/WP_CLI/FetcherComment.php +++ b/php/WP_CLI/FetcherComment.php @@ -4,7 +4,7 @@ class FetcherComment extends Fetcher { - protected $msg = "Comment with ID %s does not exist."; + protected $msg = "Could not find the comment with ID %d."; public function get( $arg ) { $comment_id = (int) $arg; diff --git a/php/WP_CLI/FetcherPost.php b/php/WP_CLI/FetcherPost.php new file mode 100644 index 000000000..62f12711f --- /dev/null +++ b/php/WP_CLI/FetcherPost.php @@ -0,0 +1,13 @@ +<?php + +namespace WP_CLI; + +class FetcherPost extends Fetcher { + + protected $msg = "Could not find the post with ID %d."; + + public function get( $arg ) { + return get_post( $arg ); + } +} + diff --git a/php/commands/post.php b/php/commands/post.php index c4d8f24ba..143b02e9e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -16,6 +16,10 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { 'post_status' ); + public function __construct() { + $this->fetcher = new \WP_CLI\FetcherPost; + } + /** * Create a post. * @@ -109,9 +113,7 @@ public function update( $args, $assoc_args ) { * wp post edit 123 */ public function edit( $args, $_ ) { - $post_id = $args[0]; - if ( !$post_id || !$post = get_post( $post_id ) ) - \WP_CLI::error( "Failed opening post $post_id to edit." ); + $post = $this->fetcher->get_check( $args[0] ); $r = $this->_edit( $post->post_content, "WP-CLI post $post_id" ); @@ -153,9 +155,7 @@ protected function _edit( $content, $title ) { * wp post get 12 --field=content > file.txt */ public function get( $args, $assoc_args ) { - $post_id = $args[0]; - if ( !$post_id || !$post = get_post( $post_id ) ) - \WP_CLI::error( "Could not find the post with ID $post_id." ); + $post = $this->fetcher->get_check( $args[0] ); $post_arr = get_object_vars( $post ); unset( $post_arr['filter'] ); From 5948aac4375a40b34e045209b78608e1b1985d25 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 10 Nov 2013 02:14:13 +0200 Subject: [PATCH 2494/5359] move fetcher classes to their own directory; see #863 --- php/WP_CLI/{Fetcher.php => Fetchers/Base.php} | 4 ++-- php/WP_CLI/{FetcherComment.php => Fetchers/Comment.php} | 4 ++-- php/WP_CLI/{FetcherPlugin.php => Fetchers/Plugin.php} | 4 ++-- php/WP_CLI/{FetcherPost.php => Fetchers/Post.php} | 4 ++-- php/WP_CLI/{FetcherTheme.php => Fetchers/Theme.php} | 4 ++-- php/WP_CLI/{FetcherUser.php => Fetchers/User.php} | 4 ++-- php/commands/comment.php | 2 +- php/commands/plugin.php | 2 +- php/commands/post.php | 2 +- php/commands/theme.php | 2 +- php/commands/user.php | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) rename php/WP_CLI/{Fetcher.php => Fetchers/Base.php} (94%) rename php/WP_CLI/{FetcherComment.php => Fetchers/Comment.php} (81%) rename php/WP_CLI/{FetcherPlugin.php => Fetchers/Plugin.php} (88%) rename php/WP_CLI/{FetcherPost.php => Fetchers/Post.php} (70%) rename php/WP_CLI/{FetcherTheme.php => Fetchers/Theme.php} (79%) rename php/WP_CLI/{FetcherUser.php => Fetchers/User.php} (82%) diff --git a/php/WP_CLI/Fetcher.php b/php/WP_CLI/Fetchers/Base.php similarity index 94% rename from php/WP_CLI/Fetcher.php rename to php/WP_CLI/Fetchers/Base.php index 0ef9f92a5..9e4ebc310 100644 --- a/php/WP_CLI/Fetcher.php +++ b/php/WP_CLI/Fetchers/Base.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -abstract class Fetcher { +abstract class Base { /** * @param string $msg The message to display when an item is not found diff --git a/php/WP_CLI/FetcherComment.php b/php/WP_CLI/Fetchers/Comment.php similarity index 81% rename from php/WP_CLI/FetcherComment.php rename to php/WP_CLI/Fetchers/Comment.php index cc02cbb97..296b2533b 100644 --- a/php/WP_CLI/FetcherComment.php +++ b/php/WP_CLI/Fetchers/Comment.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -class FetcherComment extends Fetcher { +class Comment extends Base { protected $msg = "Could not find the comment with ID %d."; diff --git a/php/WP_CLI/FetcherPlugin.php b/php/WP_CLI/Fetchers/Plugin.php similarity index 88% rename from php/WP_CLI/FetcherPlugin.php rename to php/WP_CLI/Fetchers/Plugin.php index bd6871290..247192bfa 100644 --- a/php/WP_CLI/FetcherPlugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -class FetcherPlugin extends Fetcher { +class Plugin extends Base { protected $msg = "The '%s' plugin could not be found."; diff --git a/php/WP_CLI/FetcherPost.php b/php/WP_CLI/Fetchers/Post.php similarity index 70% rename from php/WP_CLI/FetcherPost.php rename to php/WP_CLI/Fetchers/Post.php index 62f12711f..4944561e3 100644 --- a/php/WP_CLI/FetcherPost.php +++ b/php/WP_CLI/Fetchers/Post.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -class FetcherPost extends Fetcher { +class Post extends Base { protected $msg = "Could not find the post with ID %d."; diff --git a/php/WP_CLI/FetcherTheme.php b/php/WP_CLI/Fetchers/Theme.php similarity index 79% rename from php/WP_CLI/FetcherTheme.php rename to php/WP_CLI/Fetchers/Theme.php index 5066983f0..1c3380502 100644 --- a/php/WP_CLI/FetcherTheme.php +++ b/php/WP_CLI/Fetchers/Theme.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -class FetcherTheme extends Fetcher { +class Theme extends Base { protected $msg = "The '%s' theme could not be found."; diff --git a/php/WP_CLI/FetcherUser.php b/php/WP_CLI/Fetchers/User.php similarity index 82% rename from php/WP_CLI/FetcherUser.php rename to php/WP_CLI/Fetchers/User.php index e1111e0ec..81bbbc20a 100644 --- a/php/WP_CLI/FetcherUser.php +++ b/php/WP_CLI/Fetchers/User.php @@ -1,8 +1,8 @@ <?php -namespace WP_CLI; +namespace WP_CLI\Fetchers; -class FetcherUser extends Fetcher { +class User extends Base { protected $msg = "Invalid user ID or login: '%s'"; diff --git a/php/commands/comment.php b/php/commands/comment.php index aa73d1619..06b4b64a4 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -19,7 +19,7 @@ class Comment_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherComment; + $this->fetcher = new \WP_CLI\Fetchers\Comment; } /** diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ff90c5c30..3edf31cb3 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -24,7 +24,7 @@ function __construct() { parent::__construct(); - $this->fetcher = new \WP_CLI\FetcherPlugin; + $this->fetcher = new \WP_CLI\Fetchers\Plugin; } protected function get_upgrader_class( $force ) { diff --git a/php/commands/post.php b/php/commands/post.php index 143b02e9e..ca9a156fd 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -17,7 +17,7 @@ class Post_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherPost; + $this->fetcher = new \WP_CLI\Fetchers\Post; } /** diff --git a/php/commands/theme.php b/php/commands/theme.php index d5437785b..87c806c72 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -21,7 +21,7 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { function __construct() { parent::__construct(); - $this->fetcher = new \WP_CLI\FetcherTheme; + $this->fetcher = new \WP_CLI\Fetchers\Theme; } protected function get_upgrader_class( $force ) { diff --git a/php/commands/user.php b/php/commands/user.php index cf18fcb04..ae1733a4d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -18,7 +18,7 @@ class User_Command extends \WP_CLI\CommandWithDBObject { ); public function __construct() { - $this->fetcher = new \WP_CLI\FetcherUser; + $this->fetcher = new \WP_CLI\Fetchers\User; } /** From 04655edbb69b0739b5be72046dab2f2b8184741e Mon Sep 17 00:00:00 2001 From: Jonathan Bardo <jonathanbardo@users.noreply.github.com> Date: Mon, 11 Nov 2013 09:15:33 -0500 Subject: [PATCH 2495/5359] Minor typo --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2e59a706a..c521c69d0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -511,7 +511,7 @@ public function before_wp_load() { } if ( 'multisite-install' == $this->arguments[1] ) { - // need to fake some globals to skip the checks in wp-inclues/ms-settings.php + // need to fake some globals to skip the checks in wp-includes/ms-settings.php self::fake_current_site_blog( $url_parts ); if ( !defined( 'COOKIEHASH' ) ) { From 72d8062072f49898f79c5e30a4f66f6ce7b8bea3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Nov 2013 00:21:29 +0200 Subject: [PATCH 2496/5359] introduce --skip-tests flag for 'wp scaffold plugin' --- php/commands/scaffold.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 31e672109..26ee0064a 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -303,11 +303,14 @@ private function get_output_path( $assoc_args, $subdir ) { * <slug> * : The internal name of the plugin. * - * [--activate] - * : Activate the newly generated plugin. - * * [--plugin_name=<title>] * : What to put in the 'Plugin Name:' header + * + * [--skip-tests] + * : Don't generate files for unit testing. + * + * [--activate] + * : Activate the newly generated plugin. */ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; @@ -325,10 +328,13 @@ function plugin( $args, $assoc_args ) { WP_CLI::success( "Created $plugin_dir" ); - WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); + if ( !isset( $assoc_args['skip-tests'] ) ) { + WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); + } - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); + } } /** From 7ed61de22f23390c0621ba0185d86028c9f347fd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Nov 2013 00:25:57 +0200 Subject: [PATCH 2497/5359] add behat test for --skip-tests --- features/plugin.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index b9ebc00f2..93c693a52 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -7,9 +7,15 @@ Feature: Manage WordPress plugins And I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} + When I run `wp plugin scaffold --skip-tests plugin1` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/plugin1/plugin1.php file should exist + And the {PLUGIN_DIR}/zombieland/phpunit.xml file should not exist + When I run `wp plugin scaffold zombieland --plugin_name="Zombieland"` Then STDOUT should not be empty And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist + And the {PLUGIN_DIR}/zombieland/phpunit.xml file should exist When I run `wp plugin status zombieland` Then STDOUT should contain: From acd70eec775745d87a299d4dc71e5033e10582d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Nov 2013 00:55:43 +0200 Subject: [PATCH 2498/5359] don't pick up php files inside plugin subdirs --- features/plugin.feature | 4 +++- php/WP_CLI/Fetchers/Plugin.php | 32 ++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 93c693a52..be9c51ceb 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -17,7 +17,9 @@ Feature: Manage WordPress plugins And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist And the {PLUGIN_DIR}/zombieland/phpunit.xml file should exist - When I run `wp plugin status zombieland` + # Check that the inner-plugin is not picked up + When I run `mv {PLUGIN_DIR}/plugin1 {PLUGIN_DIR}/zombieland/` + And I run `wp plugin status zombieland` Then STDOUT should contain: """ Plugin zombieland details: diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php index 247192bfa..f59672570 100644 --- a/php/WP_CLI/Fetchers/Plugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -9,22 +9,30 @@ class Plugin extends Base { public function get( $name ) { $plugins = get_plugins( '/' . $name ); - if ( !empty( $plugins ) ) { - $file = $name . '/' . key( $plugins ); - } else { - $file = $name . '.php'; + // some-plugin/the-plugin.php + while ( !empty( $plugins ) ) { + $file = key( $plugins ); + array_shift( $plugins ); + + // ignore files inside a plugin's subdirectory (like WP does) + if ( dirname( $file ) == '.' ) { + return (object) array( + 'name' => $name, + 'file' => $name . '/' . $file + ); + } + } - $plugins = get_plugins(); + // some-plugin.php + $file = $name . '.php'; - if ( !isset( $plugins[$file] ) ) { - return false; - } + $plugins = get_plugins(); + + if ( isset( $plugins[ $file ] ) ) { + return (object) compact( 'name', 'file' ); } - return (object) array( - 'name' => $name, - 'file' => $file - ); + return false; } } From 482e4abc37121bdf8690beac182b4b885bb78a02 Mon Sep 17 00:00:00 2001 From: Kevin Leary <info@kevinleary.net> Date: Tue, 12 Nov 2013 14:54:31 -0500 Subject: [PATCH 2499/5359] Use consistent capitalization for "Add New" in post type scaffold to match WordPress default for Post and Page. --- templates/post_type.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index cd242e053..51f0faa24 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -10,9 +10,9 @@ 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), - 'add_new' => __( 'Add new {{label}}', '{{textdomain}}' ), + 'add_new' => __( 'Add New {{label}}', '{{textdomain}}' ), 'all_items' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - 'add_new_item' => __( 'Add new {{label}}', '{{textdomain}}' ), + 'add_new_item' => __( 'Add New {{label}}', '{{textdomain}}' ), 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), 'view_item' => __( 'View {{label}}', '{{textdomain}}' ), From 74beb8c8a0708cd11d78723bd62c084be03f17c2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 12 Nov 2013 22:41:56 +0200 Subject: [PATCH 2500/5359] remove label from add_new default and move it above add_new_item, to make the difference clearer see #868 --- templates/post_type.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 51f0faa24..201a2fa13 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -10,11 +10,11 @@ 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), - 'add_new' => __( 'Add New {{label}}', '{{textdomain}}' ), 'all_items' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), + 'add_new' => __( 'Add New', '{{textdomain}}' ), 'add_new_item' => __( 'Add New {{label}}', '{{textdomain}}' ), 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), - 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), 'view_item' => __( 'View {{label}}', '{{textdomain}}' ), 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), 'not_found' => __( 'No {{label_plural}} found', '{{textdomain}}' ), From db61e2c9528254d0b78a652623607810d145d1c7 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 14 Nov 2013 01:24:35 +0200 Subject: [PATCH 2501/5359] increase timeout threshold for 'wp core download'. fixes #748 --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index e0f2d7874..09d15da96 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -64,7 +64,7 @@ public function download( $args, $assoc_args ) { $headers = array('Accept' => 'application/json'); $options = array( - 'timeout' => 30, + 'timeout' => 600, // 10 minutes ought to be enough for everybody 'filename' => $temp ); From 72ddf7408d0b59e433bc8b5430290c04a48a67c4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 14 Nov 2013 22:17:56 +0200 Subject: [PATCH 2502/5359] fix --category synopsis for 'wp export' closes #872 --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 59781549e..a2df80bfb 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -43,7 +43,7 @@ class Export_Command extends WP_CLI_Command { * [--author=<login/id>] * : Export only posts by this author. * - * [--category=<category-id>] + * [--category=<name>] * : Export only posts in this category. * * [--post_status=<status>] From f1310a7f08b8efb5a4e684847f5031f4e92fc856 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 15 Nov 2013 13:18:52 -0200 Subject: [PATCH 2503/5359] 'wp theme delete' should not delete active theme --- features/theme.feature | 30 ++++++++++++++++++++++++++++++ php/commands/theme.php | 1 + 2 files changed, 31 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 7898f9d09..121c2c3db 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -73,3 +73,33 @@ Feature: Manage WordPress themes """ wp-content/themes/p2 """ + + Scenario: Deleting a theme + When I run `wp theme install p2` + Then STDOUT should not be empty + + When I try `wp theme delete invalid-theme` + Then STDERR should contain: + """ + Warning: The 'invalid-theme' theme could not be found. + """ + And STDOUT should be empty + + When I run `wp theme delete p2` + Then STDOUT should be: + """ + Success: Deleted 'p2' theme. + """ + And STDERR should be empty + + When I run `wp theme install p2 --activate` + Then STDOUT should not be empty + + When I try `wp theme delete p2` + Then STDERR should be: + """ + Warning: Can't delete the currently active theme: p2 + """ + And STDOUT should be empty + + \ No newline at end of file diff --git a/php/commands/theme.php b/php/commands/theme.php index 87c806c72..3cfdfaeea 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -359,6 +359,7 @@ function delete( $args ) { if ( $this->is_active_theme( $theme ) ) { WP_CLI::warning( "Can't delete the currently active theme: $theme_slug" ); + continue; } $r = delete_theme( $theme_slug ); From 1a2143717617b06d2e19ae48843a8d3c97cb1dc2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 17 Nov 2013 14:15:08 +0200 Subject: [PATCH 2504/5359] merge theme install and delete scenarios; see #874 --- features/theme.feature | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 121c2c3db..f14a82003 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -3,7 +3,7 @@ Feature: Manage WordPress themes Background: Given a WP install - Scenario: Installing a theme + Scenario: Installing and deleting theme When I run `wp theme install p2` Then STDOUT should not be empty @@ -29,6 +29,13 @@ Feature: Manage WordPress themes Success: Switched to 'P2' theme. """ + When I try `wp theme delete p2` + Then STDERR should be: + """ + Warning: Can't delete the currently active theme: p2 + """ + And STDOUT should be empty + When I run `wp theme activate {PREVIOUS_THEME}` Then STDOUT should not be empty @@ -73,33 +80,3 @@ Feature: Manage WordPress themes """ wp-content/themes/p2 """ - - Scenario: Deleting a theme - When I run `wp theme install p2` - Then STDOUT should not be empty - - When I try `wp theme delete invalid-theme` - Then STDERR should contain: - """ - Warning: The 'invalid-theme' theme could not be found. - """ - And STDOUT should be empty - - When I run `wp theme delete p2` - Then STDOUT should be: - """ - Success: Deleted 'p2' theme. - """ - And STDERR should be empty - - When I run `wp theme install p2 --activate` - Then STDOUT should not be empty - - When I try `wp theme delete p2` - Then STDERR should be: - """ - Warning: Can't delete the currently active theme: p2 - """ - And STDOUT should be empty - - \ No newline at end of file From dca87a7f6512044cb90eaf0d66b7864bb61f0f68 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 20 Nov 2013 13:27:32 -0800 Subject: [PATCH 2505/5359] Copy, meet paste. Introduce `wp comment-meta`, derived from `wp user-meta` --- features/comment-meta.feature | 28 ++++++++++++++++++++++++++++ php/commands/comment-meta.php | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 features/comment-meta.feature create mode 100644 php/commands/comment-meta.php diff --git a/features/comment-meta.feature b/features/comment-meta.feature new file mode 100644 index 000000000..5eedef616 --- /dev/null +++ b/features/comment-meta.feature @@ -0,0 +1,28 @@ +Feature: Manage comment custom fields + + Scenario: Comment meta CRUD + Given a WP install + + When I run `wp comment-meta add 1 foo 'bar'` + Then STDOUT should not be empty + + When I run `wp comment-meta get 1 foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp comment-meta set 1 foo '[ "1", "2" ]' --format=json` + Then STDOUT should not be empty + + When I run `wp comment-meta get 1 foo --format=json` + Then STDOUT should be: + """ + ["1","2"] + """ + + When I run `wp comment-meta delete 1 foo` + Then STDOUT should not be empty + + When I try `wp comment-meta get 1 foo` + Then the return code should be 1 diff --git a/php/commands/comment-meta.php b/php/commands/comment-meta.php new file mode 100644 index 000000000..b1aba174b --- /dev/null +++ b/php/commands/comment-meta.php @@ -0,0 +1,19 @@ +<?php + +/** + * Manage comment custom fields. + * + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp comment-meta set 123 description "Mary is a WordPress developer." + */ +class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'comment'; +} + +WP_CLI::add_command( 'comment-meta', 'Comment_Meta_Command' ); From 855a989d28e13ee1644d08af2a4075f8c09ad5aa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 20 Nov 2013 14:19:27 -0800 Subject: [PATCH 2506/5359] Restore the use of `--prompt` as a runtime argument. The argument is unique of it's kind, and there isn't a great way of doing this otherwise. --- php/WP_CLI/Runner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e09a54a58..4893ded7c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -394,6 +394,10 @@ private function init_config() { $configurator->merge_config( $runtime_config ); $this->config = $configurator->to_array(); + // --prompt can't be set in file, but is still a valid runtime arg + if ( ! empty( $runtime_config['prompt'] ) ) + $this->config['prompt'] = true; + if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); } From 93cb822b285e66af1f834743fb2bbf628440e167 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 20 Nov 2013 14:44:05 -0800 Subject: [PATCH 2507/5359] Use new public methods of `\WP_CLI\Runner` to set the `url` if it was passed as an assoc arg by prompting. --- php/WP_CLI/Runner.php | 4 ++-- php/commands/core.php | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4893ded7c..315a04227 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -147,7 +147,7 @@ private static function guess_url( $assoc_args ) { return false; } - private static function set_url_params( $url_parts ) { + public static function set_url_params( $url_parts ) { $f = function( $key ) use ( $url_parts ) { return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; }; @@ -534,7 +534,7 @@ public function before_wp_load() { } } - private static function parse_url( $url ) { + public static function parse_url( $url ) { $url_parts = parse_url( $url ); if ( !isset( $url_parts['scheme'] ) ) { diff --git a/php/commands/core.php b/php/commands/core.php index 09d15da96..ab644f787 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -444,6 +444,13 @@ private function _install( $assoc_args ) { 'admin_password' => '' ) ), EXTR_SKIP ); + // Support prompting for the `--url=<url>`, + // which is normally a runtime argument + if ( isset( $assoc_args['url'] ) ) { + $url_parts = \WP_CLI\Runner::parse_url( $assoc_args['url'] ); + \WP_CLI\Runner::set_url_params( $url_parts ); + } + $public = true; // @codingStandardsIgnoreStart From f18d0f052df559d6d8b8cdf31e76ffd49d9cfa0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Nov 2013 11:12:44 +0200 Subject: [PATCH 2508/5359] avoid leaking private \WP_CLI\Runner properties and methods --- php/WP_CLI/Runner.php | 2 +- php/utils.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e09a54a58..17826954c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -450,7 +450,7 @@ public function before_wp_load() { if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { - require $path; + Utils\load_file( $path ); } } diff --git a/php/utils.php b/php/utils.php index d1713b54e..64a165fb0 100644 --- a/php/utils.php +++ b/php/utils.php @@ -36,6 +36,11 @@ function get_vendor_paths() { ); } +// Using require() directly inside a class grants access to private methods to the loaded code +function load_file( $path ) { + require $path; +} + function load_command( $name ) { $path = WP_CLI_ROOT . "/php/commands/$name.php"; From b87528f441b087bc5ad84e4a9bf0e34a8b5b99fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Nov 2013 11:12:55 +0200 Subject: [PATCH 2509/5359] implement `wp cli info --format=json` --- php/commands/cli.php | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 3749b0452..36d9055ce 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -37,19 +37,33 @@ function version() { /** * Print various data about the CLI environment. + * + * @synopsis [--format=<format>] */ - function info() { + function info( $_, $assoc_args ) { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); $runner = WP_CLI::get_runner(); - WP_CLI::line( "PHP binary:\t" . $php_bin ); - WP_CLI::line( "PHP version:\t" . PHP_VERSION ); - WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "WP-CLI root:\t" . WP_CLI_ROOT ); - WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); - WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); - WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); + if ( isset( $assoc_args['format'] ) && 'json' === $assoc_args['format'] ) { + $info = array( + 'php_binary_path' => $php_bin, + 'global_config_path' => $runner->global_config_path, + 'project_config_path' => $runner->project_config_path, + 'wp_cli_dir_path' => WP_CLI_ROOT, + 'wp_cli_version' => WP_CLI_VERSION, + ); + + WP_CLI::line( json_encode( $info ) ); + } else { + WP_CLI::line( "PHP binary:\t" . $php_bin ); + WP_CLI::line( "PHP version:\t" . PHP_VERSION ); + WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); + WP_CLI::line( "WP-CLI root dir:\t" . WP_CLI_ROOT ); + WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); + WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); + WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); + } } /** From 174d33ae33a1497755a71b46755c7c8d1854a2ff Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 21 Nov 2013 11:32:18 +0200 Subject: [PATCH 2510/5359] fix 'Warning: unknown --info parameter' --- php/WP_CLI/Runner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 17826954c..10c06148d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -322,6 +322,7 @@ private static function back_compat_conversions( $args, $assoc_args ) { foreach ( $special_flags as $key ) { if ( isset( $assoc_args[ $key ] ) ) { $args = array( 'cli', $key ); + unset( $assoc_args[ $key ] ); break; } } From 8949dc2a09152019d4ede3ecfcf07a3d59ec3fa6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 21 Nov 2013 16:28:39 -0200 Subject: [PATCH 2511/5359] implement 'wp post generate --post_content=<content>' --- php/commands/post.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index ca9a156fd..1f8f7100e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -268,7 +268,10 @@ public function _list( $_, $assoc_args ) { * * [--post_date=<yyyy-mm-dd>] * : The date of the generated posts. Default: current date - * + * + * [--post_content=<content>] + * : The content of the generated posts. Default: empty + * * [--max_depth=<number>] * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 * @@ -286,6 +289,7 @@ public function generate( $args, $assoc_args ) { 'post_status' => 'publish', 'post_author' => false, 'post_date' => current_time( 'mysql' ), + 'post_content' => '', ); extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); @@ -340,6 +344,7 @@ public function generate( $args, $assoc_args ) { 'post_parent' => $current_parent, 'post_name' => "post-$i", 'post_date' => $post_date, + 'post_content' => $post_content, ); wp_insert_post( $args, true ); From ab45bfd97b83e3e4fcd66add340f6e985a38ebb2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 08:14:11 -0800 Subject: [PATCH 2512/5359] Introduce `\WP_CLI::set_url()`, which will set the URL context for the execution. --- php/WP_CLI/Runner.php | 11 +++++------ php/class-wp-cli.php | 8 ++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4f7b0fa7d..68b345ffc 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -480,10 +480,8 @@ public function before_wp_load() { // Handle --url parameter $url = self::guess_url( $this->config ); - if ( $url ) { - $url_parts = self::parse_url( $url ); - self::set_url_params( $url_parts ); - } + if ( $url ) + \WP_CLI::set_url( $url ); $this->do_early_invoke( 'before_wp_load' ); @@ -515,12 +513,13 @@ public function before_wp_load() { // We really need a URL here if ( !isset( $_SERVER['HTTP_HOST'] ) ) { - $url_parts = self::parse_url( 'http://example.com' ); - self::set_url_params( $url_parts ); + $url = 'http://example.com'; + \WP_CLI::set_url( $url ); } if ( 'multisite-install' == $this->arguments[1] ) { // need to fake some globals to skip the checks in wp-includes/ms-settings.php + $url_parts = self::parse_url( $url ); self::fake_current_site_blog( $url_parts ); if ( !defined( 'COOKIEHASH' ) ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index abe3a5928..d412adb1c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -83,6 +83,14 @@ private static function get_cache() { return $cache; } + /** + * Set the context in which WP-CLI should be run + */ + static function set_url( $url ) { + $url_parts = WP_CLI\Runner::parse_url( $url ); + WP_CLI\Runner::set_url_params( $url_parts ); + } + /** * @return WpHttpCacheManager */ From 8a8b1044d43e9e0db4be4a1079bc933ed152d65d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 08:21:19 -0800 Subject: [PATCH 2513/5359] Use the new `set_url()` method introduced in ab45bfd --- php/commands/core.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ab644f787..732b7d599 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -446,10 +446,8 @@ private function _install( $assoc_args ) { // Support prompting for the `--url=<url>`, // which is normally a runtime argument - if ( isset( $assoc_args['url'] ) ) { - $url_parts = \WP_CLI\Runner::parse_url( $assoc_args['url'] ); - \WP_CLI\Runner::set_url_params( $url_parts ); - } + if ( isset( $assoc_args['url'] ) ) + $url_parts = WP_CLI::set_url( $assoc_args['url'] ); $public = true; From 8881f63add12d67fd7788bfbca9e87f094b05057 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 08:26:15 -0800 Subject: [PATCH 2514/5359] Move these methods to where they should be --- php/WP_CLI/Runner.php | 34 +--------------------------------- php/class-wp-cli.php | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 68b345ffc..01abb7fc2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -147,28 +147,6 @@ private static function guess_url( $assoc_args ) { return false; } - public static function set_url_params( $url_parts ) { - $f = function( $key ) use ( $url_parts ) { - return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; - }; - - if ( isset( $url_parts['host'] ) ) { - $_SERVER['HTTP_HOST'] = $url_parts['host']; - if ( isset( $url_parts['port'] ) ) { - $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; - } - - $_SERVER['SERVER_NAME'] = $url_parts['host']; - } - - $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); - $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; - $_SERVER['QUERY_STRING'] = $f('query'); - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; - $_SERVER['HTTP_USER_AGENT'] = ''; - $_SERVER['REQUEST_METHOD'] = 'GET'; - } - private function cmd_starts_with( $prefix ) { return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } @@ -519,7 +497,7 @@ public function before_wp_load() { if ( 'multisite-install' == $this->arguments[1] ) { // need to fake some globals to skip the checks in wp-includes/ms-settings.php - $url_parts = self::parse_url( $url ); + $url_parts = \WP_CLI::parse_url( $url ); self::fake_current_site_blog( $url_parts ); if ( !defined( 'COOKIEHASH' ) ) { @@ -534,16 +512,6 @@ public function before_wp_load() { } } - public static function parse_url( $url ) { - $url_parts = parse_url( $url ); - - if ( !isset( $url_parts['scheme'] ) ) { - $url_parts = parse_url( 'http://' . $url ); - } - - return $url_parts; - } - private static function fake_current_site_blog( $url_parts ) { global $current_site, $current_blog; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d412adb1c..27051d475 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -87,8 +87,40 @@ private static function get_cache() { * Set the context in which WP-CLI should be run */ static function set_url( $url ) { - $url_parts = WP_CLI\Runner::parse_url( $url ); - WP_CLI\Runner::set_url_params( $url_parts ); + $url_parts = self::parse_url( $url ); + self::set_url_params( $url_parts ); + } + + static function parse_url( $url ) { + $url_parts = parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + + return $url_parts; + } + + private static function set_url_params( $url_parts ) { + $f = function( $key ) use ( $url_parts ) { + return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; + }; + + if ( isset( $url_parts['host'] ) ) { + $_SERVER['HTTP_HOST'] = $url_parts['host']; + if ( isset( $url_parts['port'] ) ) { + $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; + } + + $_SERVER['SERVER_NAME'] = $url_parts['host']; + } + + $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); + $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; + $_SERVER['QUERY_STRING'] = $f('query'); + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; + $_SERVER['HTTP_USER_AGENT'] = ''; + $_SERVER['REQUEST_METHOD'] = 'GET'; } /** From 5fe976cdff3123015e3c63fbf26506e4689f9b35 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 08:26:34 -0800 Subject: [PATCH 2515/5359] Test install via prompting --- features/core.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/features/core.feature b/features/core.feature index 07849eda6..59c78a4f5 100644 --- a/features/core.feature +++ b/features/core.feature @@ -106,6 +106,29 @@ Feature: Manage WordPress installation http://localhost:8001 """ + Scenario: Install WordPress by prompting + Given an empty directory + And WP files + And wp-config.php + And a database + And a session file: + """ + localhost:8001 + Test + wpcli + wpcli + admin@example.com + """ + + When I run `wp core install --prompt < session` + Then STDOUT should not be empty + + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + http://localhost:8001 + """ + Scenario: Full install Given a WP install From 9d532c0ee824958cfe7e1788bfaeab9824767652 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 09:19:43 -0800 Subject: [PATCH 2516/5359] Introduce a helper method for launching a new WP-CLI process using the same context as the current process. --- php/class-wp-cli.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index abe3a5928..8b0c18a59 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -276,6 +276,36 @@ static function launch( $command, $exit_on_error = true ) { return $r; } + /** + * Launch another WP-CLI command using the runtime arguments for the current process + * + * @param string Command to call + * @param array $args Positional arguments to use + * @param array $assoc_args Associative arguments to use + * @param bool Whether to exit if the command returns an error status + * + * @return int The command exit status + */ + static function launch_wpcli( $command, $args, $assoc_args, $exit_on_error = true ) { + + $reused_runtime_args = array( + 'path', + 'url', + 'user', + ); + foreach( $reused_runtime_args as $key ) { + if ( $value = self::get_runner()->config[ $key ] ) + $assoc_args[$key] = $value; + } + + $full_command = constant( 'WP_CLI_ROOT' ) . '/bin/wp ' . $command . ' ' . implode( ' ', $args ); + foreach( $assoc_args as $key => $value ) { + $full_command .= ' --' . $key . '=' . $value; + } + + return self::launch( $full_command, $exit_on_error ); + } + static function get_config( $key = null ) { if ( null === $key ) { return self::get_runner()->config; From 3be1d9877a9739a6642248c4965c22618a1e4056 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 09:20:28 -0800 Subject: [PATCH 2517/5359] Now that we have a method to launch new WP-CLI processes, use it to flush rewrite rules after setting the structure. Fixes #814 --- features/rewrite.feature | 1 - php/commands/rewrite.php | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index a942bf5cb..9ccb04f0c 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -5,7 +5,6 @@ Feature: Manage WordPress rewrites Scenario: Change site permastructs When I run `wp rewrite structure /blog/%year%/%monthnum%/%day%/%postname%/ --category-base=section --tag-base=topic` - And I run `wp rewrite flush` When I run `wp option get permalink_structure` Then STDOUT should contain: diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 0f85ddc12..1597d9726 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -85,7 +85,14 @@ public function structure( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); - flush_rewrite_rules( isset( $assoc_args['hard'] ) ); + + // Launch a new process to flush rewrites because core expects flush + // to happen after rewrites are set + $new_assoc_args = array(); + if ( isset( $assoc_args['hard'] ) ) + $new_assoc_args['hard'] = true; + \WP_CLI::launch_wpcli( 'rewrite flush', array(), $new_assoc_args ); + WP_CLI::success( "Rewrite structure set." ); } From bf90f46695a4fd150836e9c543bb5f95c90dddf0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 09:58:38 -0800 Subject: [PATCH 2518/5359] Support for filtering plugin and theme lists based on object attributes. --- php/WP_CLI/CommandWithUpgrade.php | 12 ++++++++++++ php/commands/plugin.php | 3 +++ php/commands/theme.php | 3 +++ 3 files changed, 18 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 73c2162c0..7ded3098a 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -266,6 +266,18 @@ protected function _list( $_, $assoc_args ) { return $item; } ); + foreach( $it as $key => $item ) { + + foreach( $this->obj_fields as $field ) { + + if ( isset( $assoc_args[$field] ) + && $assoc_args[$field] != $item[$field] ) + $it->offsetUnset( $key ); + + } + + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $it ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 3edf31cb3..59436c641 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -479,6 +479,9 @@ function delete( $args, $assoc_args = array() ) { * Get a list of plugins. * * ## OPTIONS + * + * [--<field>=<value>] + * : Filter results based on the value of a field. * * [--field=<field>] * : Prints the value of a single field for each plugin. diff --git a/php/commands/theme.php b/php/commands/theme.php index 3cfdfaeea..1fdf3cbfe 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -376,6 +376,9 @@ function delete( $args ) { * Get a list of themes. * * ## OPTIONS + * + * [--<field>=<value>] + * : Filter results based on the value of a field. * * [--field=<field>] * : Prints the value of a single field for each theme. From c2f22eb53256b36b0e5a1e4b77c8aa49abda0d1c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Nov 2013 20:08:04 +0200 Subject: [PATCH 2519/5359] move parse_url() to utils.php, since it's a standalone utility --- php/WP_CLI/Runner.php | 2 +- php/class-wp-cli.php | 12 +----------- php/utils.php | 10 ++++++++++ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 01abb7fc2..a107a2850 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -497,7 +497,7 @@ public function before_wp_load() { if ( 'multisite-install' == $this->arguments[1] ) { // need to fake some globals to skip the checks in wp-includes/ms-settings.php - $url_parts = \WP_CLI::parse_url( $url ); + $url_parts = Utils\parse_url( $url ); self::fake_current_site_blog( $url_parts ); if ( !defined( 'COOKIEHASH' ) ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 27051d475..c510a84bf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -87,20 +87,10 @@ private static function get_cache() { * Set the context in which WP-CLI should be run */ static function set_url( $url ) { - $url_parts = self::parse_url( $url ); + $url_parts = Utils\parse_url( $url ); self::set_url_params( $url_parts ); } - static function parse_url( $url ) { - $url_parts = parse_url( $url ); - - if ( !isset( $url_parts['scheme'] ) ) { - $url_parts = parse_url( 'http://' . $url ); - } - - return $url_parts; - } - private static function set_url_params( $url_parts ) { $f = function( $key ) use ( $url_parts ) { return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; diff --git a/php/utils.php b/php/utils.php index 64a165fb0..c3abfdf19 100644 --- a/php/utils.php +++ b/php/utils.php @@ -358,3 +358,13 @@ function make_progress_bar( $message, $count ) { return new \cli\progress\Bar( $message, $count ); } +function parse_url( $url ) { + $url_parts = \parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + + return $url_parts; +} + From fd679d4ea3858be6a959dc44c7325c646ed0627d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 10:21:11 -0800 Subject: [PATCH 2520/5359] Test filtering based on object attribute --- features/plugin.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index be9c51ceb..da767952b 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -88,3 +88,16 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | update | version | | akismet | active | available | 2.5.6 | + + + Scenario: List plugins + When I run `wp plugin activate akismet hello` + Then STDOUT should not be empty + + When I run `wp plugin list --status=inactive` + Then STDOUT should be empty + + When I run `wp plugin list --status=active` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | active | available | 2.5.6 | From e96494ae3f3d22376613f4d2adf787e652c16e86 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 10:50:19 -0800 Subject: [PATCH 2521/5359] These arguments should be optional --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 8b0c18a59..bd8bb6892 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -286,7 +286,7 @@ static function launch( $command, $exit_on_error = true ) { * * @return int The command exit status */ - static function launch_wpcli( $command, $args, $assoc_args, $exit_on_error = true ) { + static function launch_wpcli( $command, $args = array(), $assoc_args = array(), $exit_on_error = true ) { $reused_runtime_args = array( 'path', From e1c4c29450b16add144366ccd148a40efe01b769 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 11:05:26 -0800 Subject: [PATCH 2522/5359] Call the PHP binary directly, and ensure all arguments are escaped --- php/class-wp-cli.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index bd8bb6892..7b6fa98c8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -298,10 +298,17 @@ static function launch_wpcli( $command, $args = array(), $assoc_args = array(), $assoc_args[$key] = $value; } - $full_command = constant( 'WP_CLI_ROOT' ) . '/bin/wp ' . $command . ' ' . implode( ' ', $args ); - foreach( $assoc_args as $key => $value ) { - $full_command .= ' --' . $key . '=' . $value; - } + $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + + $boot_fs_path = $GLOBALS['argv'][0]; + $wp_cli_root = constant( 'WP_CLI_ROOT' ); + if ( false === stripos( $boot_fs_path, $wp_cli_root ) ) + $boot_fs_path = $wp_cli_root . '/' . $boot_fs_path; + + $args = implode( ' ', array_map( 'escapeshellarg', $args ) ); + $assoc_args = \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); + + $full_command = "{$php_bin} {$boot_fs_path} {$command} {$args} {$assoc_args}"; return self::launch( $full_command, $exit_on_error ); } From c90a3245d77ce52ddac85186142567a20e9f4526 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 22 Nov 2013 11:12:18 -0800 Subject: [PATCH 2523/5359] Skip the iterator entirely --- features/plugin.feature | 8 ++++---- php/WP_CLI/CommandWithUpgrade.php | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index da767952b..ecd3aab3f 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -94,10 +94,10 @@ Feature: Manage WordPress plugins When I run `wp plugin activate akismet hello` Then STDOUT should not be empty - When I run `wp plugin list --status=inactive` + When I run `wp plugin list --status=inactive --field=name` Then STDOUT should be empty - When I run `wp plugin list --status=active` + When I run `wp plugin list --status=active --fields=name,status` Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | active | available | 2.5.6 | + | name | status | + | akismet | active | diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 7ded3098a..1e931bff1 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -251,7 +251,8 @@ protected function _list( $_, $assoc_args ) { if ( !is_array( $all_items ) ) \WP_CLI::error( "No {$this->item_type}s found." ); - $it = \WP_CLI\Utils\iterator_map( $all_items, function( $item ) { + foreach( $all_items as $key => &$item ) { + if ( empty( $item['version'] ) ) $item['version'] = ''; @@ -263,23 +264,18 @@ protected function _list( $_, $assoc_args ) { } } - return $item; - } ); - - foreach( $it as $key => $item ) { - foreach( $this->obj_fields as $field ) { if ( isset( $assoc_args[$field] ) && $assoc_args[$field] != $item[$field] ) - $it->offsetUnset( $key ); + unset( $all_items[$key] ); } } $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $it ); + $formatter->display_items( $all_items ); } /** From 4762bead90589baf4e5b6bca4884a18746e8964b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 22 Nov 2013 22:07:41 +0200 Subject: [PATCH 2524/5359] fix formatting and update examples --- php/WP_CLI/CommandWithUpgrade.php | 7 ++----- php/commands/plugin.php | 4 ++-- php/commands/theme.php | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 1e931bff1..e4047e099 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -251,7 +251,7 @@ protected function _list( $_, $assoc_args ) { if ( !is_array( $all_items ) ) \WP_CLI::error( "No {$this->item_type}s found." ); - foreach( $all_items as $key => &$item ) { + foreach ( $all_items as $key => &$item ) { if ( empty( $item['version'] ) ) $item['version'] = ''; @@ -264,14 +264,11 @@ protected function _list( $_, $assoc_args ) { } } - foreach( $this->obj_fields as $field ) { - + foreach ( $this->obj_fields as $field ) { if ( isset( $assoc_args[$field] ) && $assoc_args[$field] != $item[$field] ) unset( $all_items[$key] ); - } - } $formatter = $this->get_formatter( $assoc_args ); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 59436c641..f91aa01d0 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -479,7 +479,7 @@ function delete( $args, $assoc_args = array() ) { * Get a list of plugins. * * ## OPTIONS - * + * * [--<field>=<value>] * : Filter results based on the value of a field. * @@ -494,7 +494,7 @@ function delete( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * wp plugin list --format=json + * wp plugin list --status=active --format=json * * @subcommand list */ diff --git a/php/commands/theme.php b/php/commands/theme.php index 1fdf3cbfe..e9fa1e70a 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -376,7 +376,7 @@ function delete( $args ) { * Get a list of themes. * * ## OPTIONS - * + * * [--<field>=<value>] * : Filter results based on the value of a field. * @@ -391,7 +391,7 @@ function delete( $args ) { * * ## EXAMPLES * - * wp theme list --format=csv + * wp theme list --status=inactive --format=csv * * @subcommand list */ From db15b9c44bc2c8f6cb0f0af196e9105969c7f8dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 11:39:26 +0200 Subject: [PATCH 2525/5359] make merge_config() work for runtime args too --- php/WP_CLI/Configurator.php | 4 ++-- php/WP_CLI/Runner.php | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 791c6c5a1..2bfeacf25 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -84,9 +84,9 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args, $runtime_config ); } - function merge_config( $config ) { + function merge_config( $config, $type ) { foreach ( $this->spec as $key => $details ) { - if ( $details['file'] && isset( $config[ $key ] ) ) { + if ( false !== $details[ $type ] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; if ( $details['multiple'] ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a107a2850..707b371f6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -368,15 +368,11 @@ private function init_config() { $configurator = \WP_CLI::get_configurator(); foreach ( array( $this->global_config_path, $this->project_config_path ) as $config_path ) { - $configurator->merge_config( self::load_config( $config_path ) ); + $configurator->merge_config( self::load_config( $config_path ), 'file' ); } - $configurator->merge_config( $runtime_config ); + $configurator->merge_config( $runtime_config, 'runtime' ); $this->config = $configurator->to_array(); - // --prompt can't be set in file, but is still a valid runtime arg - if ( ! empty( $runtime_config['prompt'] ) ) - $this->config['prompt'] = true; - if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); } From 0b4792e67eaa3f9f459530752e290f801bbe7401 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 12:02:05 +0200 Subject: [PATCH 2526/5359] move YAML loading to Configurator --- php/WP_CLI/Configurator.php | 51 ++++++++++++++++++++++++++++++++++--- php/WP_CLI/Runner.php | 50 +++++------------------------------- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 2bfeacf25..283e0eb8b 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -84,15 +84,21 @@ function parse_args( $arguments ) { return array( $regular_args, $assoc_args, $runtime_config ); } - function merge_config( $config, $type ) { + function merge_yml( $path ) { + $this->merge_config( self::load_yml( $path ), 'file' ); + } + + function merge_array( $config ) { + $this->merge_config( $config, 'runtime' ); + } + + private function merge_config( $config, $type ) { foreach ( $this->spec as $key => $details ) { if ( false !== $details[ $type ] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; if ( $details['multiple'] ) { - if ( !is_array( $value ) ) { - $value = array( $value ); - } + self::arrayify( $value ); $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); } else { $this->config[ $key ] = $value; @@ -100,5 +106,42 @@ function merge_config( $config, $type ) { } } } + + /** + * Load values from a YAML file. + */ + private static function load_yml( $yml_file ) { + if ( !$yml_file ) + return array(); + + $config = spyc_load_file( $yml_file ); + + // Make sure config-file-relative paths are made absolute. + $yml_file_dir = dirname( $yml_file ); + + if ( isset( $config['path'] ) ) + self::absolutize( $config['path'], $yml_file_dir ); + + if ( isset( $config['require'] ) ) { + self::arrayify( $config['require'] ); + foreach ( $config['require'] as &$path ) { + self::absolutize( $path, $yml_file_dir ); + } + } + + return $config; + } + + private static function arrayify( &$val ) { + if ( !is_array( $val ) ) { + $val = array( $val ); + } + } + + private static function absolutize( &$path, $base ) { + if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { + $path = $base . DIRECTORY_SEPARATOR . $path; + } + } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 707b371f6..76e716f50 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -357,7 +357,9 @@ private function check_wp_version() { } private function init_config() { - list( $args, $assoc_args, $runtime_config ) = \WP_CLI::get_configurator()->parse_args( + $configurator = \WP_CLI::get_configurator(); + + list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( @@ -366,11 +368,10 @@ private function init_config() { $this->global_config_path = self::get_global_config_path(); $this->project_config_path = self::get_project_config_path(); - $configurator = \WP_CLI::get_configurator(); - foreach ( array( $this->global_config_path, $this->project_config_path ) as $config_path ) { - $configurator->merge_config( self::load_config( $config_path ), 'file' ); - } - $configurator->merge_config( $runtime_config, 'runtime' ); + $configurator->merge_yml( $this->global_config_path ); + $configurator->merge_yml( $this->project_config_path ); + $configurator->merge_array( $runtime_config ); + $this->config = $configurator->to_array(); if ( !isset( $this->config['path'] ) ) { @@ -378,43 +379,6 @@ private function init_config() { } } - /** - * Load values from a YML file. - */ - private static function load_config( $yml_file ) { - if ( !$yml_file ) - return array(); - - $config = spyc_load_file( $yml_file ); - - // Make sure config-file-relative paths are made absolute. - $yml_file_dir = dirname( $yml_file ); - - if ( isset( $config['path'] ) ) - self::absolutize( $config['path'], $yml_file_dir ); - - if ( isset( $config['require'] ) ) { - self::arrayify( $config['require'] ); - foreach ( $config['require'] as &$path ) { - self::absolutize( $path, $yml_file_dir ); - } - } - - return $config; - } - - private static function arrayify( &$val ) { - if ( !is_array( $val ) ) { - $val = array( $val ); - } - } - - private static function absolutize( &$path, $base ) { - if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { - $path = $base . DIRECTORY_SEPARATOR . $path; - } - } - public function before_wp_load() { $this->init_config(); $this->init_colorization(); From 1ae554bbecebded595b2f05fd13c88205fbb8e8e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 12:23:32 +0200 Subject: [PATCH 2527/5359] runtime config can be set after file config --- php/WP_CLI/Runner.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 76e716f50..25f6c0b03 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -359,18 +359,25 @@ private function check_wp_version() { private function init_config() { $configurator = \WP_CLI::get_configurator(); - list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( - array_slice( $GLOBALS['argv'], 1 ) ); + // File config + { + $this->global_config_path = self::get_global_config_path(); + $this->project_config_path = self::get_project_config_path(); - list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( - $args, $assoc_args ); + $configurator->merge_yml( $this->global_config_path ); + $configurator->merge_yml( $this->project_config_path ); + } + + // Runtime config and args + { + list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( + array_slice( $GLOBALS['argv'], 1 ) ); - $this->global_config_path = self::get_global_config_path(); - $this->project_config_path = self::get_project_config_path(); + list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( + $args, $assoc_args ); - $configurator->merge_yml( $this->global_config_path ); - $configurator->merge_yml( $this->project_config_path ); - $configurator->merge_array( $runtime_config ); + $configurator->merge_array( $runtime_config ); + } $this->config = $configurator->to_array(); From add0b0bfea83523d5445ad7432d1c4a9d16b03fa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 12:51:17 +0200 Subject: [PATCH 2528/5359] keep unknown config values in memory --- php/WP_CLI/Configurator.php | 21 ++++++++++++++------- php/WP_CLI/Runner.php | 6 ++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 283e0eb8b..e3b178f6a 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -5,7 +5,9 @@ class Configurator { private $spec; + private $config = array(); + private $extra_config = array(); function __construct( $path ) { $this->spec = include $path; @@ -26,7 +28,7 @@ function __construct( $path ) { } function to_array() { - return $this->config; + return array( $this->config, $this->extra_config ); } /** @@ -85,16 +87,21 @@ function parse_args( $arguments ) { } function merge_yml( $path ) { - $this->merge_config( self::load_yml( $path ), 'file' ); + foreach ( self::load_yml( $path ) as $key => $value ) { + if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { + $this->extra_config[ $key ] = $value; + } elseif ( $this->spec[ $key ]['multiple'] ) { + self::arrayify( $value ); + $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); + } else { + $this->config[ $key ] = $value; + } + } } function merge_array( $config ) { - $this->merge_config( $config, 'runtime' ); - } - - private function merge_config( $config, $type ) { foreach ( $this->spec as $key => $details ) { - if ( false !== $details[ $type ] && isset( $config[ $key ] ) ) { + if ( false !== $details['runtime'] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; if ( $details['multiple'] ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 25f6c0b03..a66ed049a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -8,7 +8,9 @@ class Runner { - private $global_config_path, $project_config_path, $config; + private $global_config_path, $project_config_path; + + private $config, $extra_config; private $arguments, $assoc_args; @@ -379,7 +381,7 @@ private function init_config() { $configurator->merge_array( $runtime_config ); } - $this->config = $configurator->to_array(); + list( $this->config, $this->extra_config ) = $configurator->to_array(); if ( !isset( $this->config['path'] ) ) { $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); From 95d6cc05fb91f6724dc08e445e09dc5bf027efba Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 13:09:15 +0200 Subject: [PATCH 2529/5359] pass config values to commands via $assoc_args --- php/WP_CLI/Runner.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a66ed049a..2dac7b30a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -4,7 +4,7 @@ use WP_CLI; use WP_CLI\Utils; - +use WP_CLI\Dispatcher; class Runner { @@ -183,7 +183,7 @@ private function find_command_to_run( $args ) { $command = $subcommand; } - return array( $command, $args ); + return array( $command, $args, $cmd_path ); } public function run_command( $args, $assoc_args = array() ) { @@ -192,7 +192,13 @@ public function run_command( $args, $assoc_args = array() ) { WP_CLI::error( $r ); } - list( $command, $final_args ) = $r; + list( $command, $final_args, $cmd_path ) = $r; + + $name = implode( ' ', $cmd_path ); + + if ( isset( $this->extra_config[ $name ] ) ) { + $assoc_args = array_merge( $this->extra_config[ $name ], $assoc_args ); + } try { $command->invoke( $final_args, $assoc_args ); From 716bd2f424c3125721a36172f61054b174b6c01a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 13:31:39 +0200 Subject: [PATCH 2530/5359] add test for command-specific configs --- features/config.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/config.feature b/features/config.feature index 6771d130d..76f19a4da 100644 --- a/features/config.feature +++ b/features/config.feature @@ -80,3 +80,17 @@ Feature: Have a config file """ command has been disabled """ + + Scenario: Command-specific configs + Given a WP install + And a wp-cli.yml file: + """ + eval: + foo: bar + """ + + When I run `wp eval 'echo json_encode( $assoc_args );'` + Then STDOUT should be JSON containing: + """ + {"foo": "bar"} + """ From 96f241bd635f23cef233d6df458855910dae122f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 13:43:57 +0200 Subject: [PATCH 2531/5359] merge command config values after validating positional parameters --- php/WP_CLI/Dispatcher/CompositeCommand.php | 2 +- php/WP_CLI/Dispatcher/Subcommand.php | 5 ++--- php/WP_CLI/Runner.php | 6 ++++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index f57d1f924..e5af82415 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -59,7 +59,7 @@ function get_synopsis() { return '<command>'; } - function invoke( $args, $assoc_args ) { + function invoke( $args, $assoc_args, $extra_args ) { $this->show_usage(); } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 78cda45c1..465b0d8ee 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -197,8 +197,7 @@ private function validate_args( $args, &$assoc_args ) { } } - function invoke( $args, $assoc_args ) { - + function invoke( $args, $assoc_args, $extra_args ) { if ( \WP_CLI::get_config( 'prompt' ) ) list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); @@ -206,7 +205,7 @@ function invoke( $args, $assoc_args ) { \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); - call_user_func( $this->when_invoked, $args, $assoc_args ); + call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2dac7b30a..65c376a43 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -197,11 +197,13 @@ public function run_command( $args, $assoc_args = array() ) { $name = implode( ' ', $cmd_path ); if ( isset( $this->extra_config[ $name ] ) ) { - $assoc_args = array_merge( $this->extra_config[ $name ], $assoc_args ); + $extra_args = $this->extra_config[ $name ]; + } else { + $extra_args = array(); } try { - $command->invoke( $final_args, $assoc_args ); + $command->invoke( $final_args, $assoc_args, $extra_args ); } catch ( WP_CLI\Iterators\Exception $e ) { WP_CLI::error( $e->getMessage() ); } From 302b2af1e03c57f5701e4c40ef4e2d21b084750d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 23 Nov 2013 13:54:09 +0200 Subject: [PATCH 2532/5359] test that CLI args overwrite config values --- features/bootstrap/support.php | 6 ++++++ features/config.feature | 8 ++++++++ features/steps/then.php | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index afe96ec1d..9df27c18a 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -14,6 +14,12 @@ function assertNumeric( $actual ) { } } +function assertNotNumeric( $actual ) { + if ( is_numeric( $actual ) ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + function checkString( $output, $expected, $action, $message = false ) { switch ( $action ) { diff --git a/features/config.feature b/features/config.feature index 76f19a4da..a39a943fc 100644 --- a/features/config.feature +++ b/features/config.feature @@ -87,6 +87,8 @@ Feature: Have a config file """ eval: foo: bar + post list: + format: count """ When I run `wp eval 'echo json_encode( $assoc_args );'` @@ -94,3 +96,9 @@ Feature: Have a config file """ {"foo": "bar"} """ + + # CLI args should trump config values + When I run `wp post list` + Then STDOUT should be a number + When I run `wp post list --format=json` + Then STDOUT should not be a number diff --git a/features/steps/then.php b/features/steps/then.php index f63800467..428001a5f 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -25,6 +25,12 @@ function ( $world, $stream ) { } ); +$steps->Then( '/^(STDOUT|STDERR) should not be a number$/', + function ( $world, $stream ) { + assertNotNumeric( trim( $world->result->$stream, "\n" ) ); + } +); + $steps->Then( '/^STDOUT should be a table containing rows:$/', function ( $world, TableNode $expected ) { $output = $world->result->STDOUT; From baaf3051b96c84a57a341525455db79125c5fe21 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 30 Aug 2013 18:13:53 +0300 Subject: [PATCH 2533/5359] switch to develop.svn and only download the test utilities --- templates/install-wp-tests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 2320e61fd..646b8c3d2 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -26,9 +26,6 @@ fi wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR -# set up testing suite -svn co --ignore-externals --quiet http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR - # portable in-place argument for both GNU sed and Mac OSX sed if [[ $(uname -s) == 'Darwin' ]]; then ioption='-i ""' @@ -36,10 +33,13 @@ else ioption='-i' fi -# generate testing config file +# set up testing suite +mkdir -p $WP_TESTS_DIR cd $WP_TESTS_DIR -cp wp-tests-config-sample.php wp-tests-config.php -sed $ioption "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php +svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ + +wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php +sed -i "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php From 8fee09040440ba1f8efc57444631853bff5de104 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Nov 2013 19:54:22 +0200 Subject: [PATCH 2534/5359] use $ioption for all sed invocations --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 646b8c3d2..7a7b91947 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -39,7 +39,7 @@ cd $WP_TESTS_DIR svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php -sed -i "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php +sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php From 41da7bf7fe80631261cf6c24f71156eed184bdbe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Nov 2013 20:00:31 +0200 Subject: [PATCH 2535/5359] refactor install-wp-tests.sh into 3 functions --- templates/install-wp-tests.sh | 94 +++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 7a7b91947..2ecb562c0 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -11,55 +11,65 @@ DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-master} +WP_CORE_DIR=/tmp/wordpress/ + set -ex -# set up a WP install -WP_CORE_DIR=/tmp/wordpress/ -mkdir -p $WP_CORE_DIR +install_wp() { + mkdir -p $WP_CORE_DIR -if [ $WP_VERSION == 'latest' ]; then - ARCHIVE_NAME='latest' -else - ARCHIVE_NAME="wordpress-$WP_VERSION" -fi + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi -wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz -tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz + tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR +} -# portable in-place argument for both GNU sed and Mac OSX sed -if [[ $(uname -s) == 'Darwin' ]]; then - ioption='-i ""' -else - ioption='-i' -fi +install_test_suite() { + # portable in-place argument for both GNU sed and Mac OSX sed + if [[ $(uname -s) == 'Darwin' ]]; then + local ioption='-i ""' + else + local ioption='-i' + fi -# set up testing suite -mkdir -p $WP_TESTS_DIR -cd $WP_TESTS_DIR -svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ + # set up testing suite + mkdir -p $WP_TESTS_DIR + cd $WP_TESTS_DIR + svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ -wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php -sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php -sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php -sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php -sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php -sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php + wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php + sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php +} -# parse DB_HOST for port or socket references -PARTS=(${DB_HOST//\:/ }) -DB_HOSTNAME=${PARTS[0]}; -DB_SOCK_OR_PORT=${PARTS[1]}; -EXTRA="" +install_db() { + # parse DB_HOST for port or socket references + local PARTS=(${DB_HOST//\:/ }) + local DB_HOSTNAME=${PARTS[0]}; + local DB_SOCK_OR_PORT=${PARTS[1]}; + local EXTRA="" -if ! [ -z $DB_HOSTNAME ] ; then - if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then - EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" - elif ! [ -z $DB_SOCK_OR_PORT ] ; then - EXTRA=" --socket=$DB_SOCK_OR_PORT" - elif ! [ -z $DB_HOSTNAME ] ; then - EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" - fi -fi + if ! [ -z $DB_HOSTNAME ] ; then + if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi + fi + + # create database + mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +} -# create database -mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +install_wp +install_test_suite +install_db From d98dcff457c44539773ef6374e60feba2b231187 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Nov 2013 20:03:56 +0200 Subject: [PATCH 2536/5359] fix DB name replacement --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 2ecb562c0..e92593f0f 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -43,7 +43,7 @@ install_test_suite() { wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php - sed $ioption "s/yourdbnamehere/$DB_NAME/" wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php From 1b2d6e4a550578267d955e0d7a9f6f537a943238 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Nov 2013 20:09:54 +0200 Subject: [PATCH 2537/5359] install wp-mysqli, to avoid deprecation warnings, which cause PHPUnit to fail --- templates/install-wp-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index e92593f0f..82fa4a8ec 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -26,6 +26,8 @@ install_wp() { wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + + wget -nv -O $WP_CORE_DIR/wp-content/db.php https://raw.github.com/markoheijnen/wp-mysqli/master/db.php } install_test_suite() { From 30f3c0cde9abf9d23354967d10fceaf390c020fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 24 Nov 2013 20:55:58 +0200 Subject: [PATCH 2538/5359] remove obsolete `wp core init-tests` command --- php/commands/core.php | 71 ------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 732b7d599..d4c4957c8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -721,77 +721,6 @@ function update_db() { wp_upgrade(); WP_CLI::success( 'WordPress database upgraded successfully.' ); } - - /** - * Set up the official test suite using the current WordPress instance. - * - * @subcommand init-tests - * - * ## OPTIONS - * - * [<path>] - * : The directory in which to download the testing suite files. (Optional) - * - * --dbname=<dbname> - * : Set the database name. **WARNING**: The database will be whipped every time - * you run the tests. - * - * --dbuser=<dbuser> - * : Set the database user. - * - * [--dbpass=<dbpass>] - * : Set the database user password. - * - * [--dbhost=<host>] - * : Set the database host. - * - * ## EXAMPLE - * - * wp core init-tests ~/svn/wp-tests --dbname=wp_test --dbuser=wp_test - */ - function init_tests( $args, $assoc_args ) { - if ( isset( $args[0] ) ) - $tests_dir = trailingslashit( $args[0] ); - else - $tests_dir = ABSPATH . 'unit-tests/'; - - $assoc_args = wp_parse_args( $assoc_args, array( - 'dbpass' => '', - 'dbhost' => 'localhost' - ) ); - - // Download the test suite - WP_CLI::launch( 'svn co https://unit-test.svn.wordpress.org/trunk/ ' . escapeshellarg( $tests_dir ) ); - - // Create the database - $query = sprintf( 'CREATE DATABASE IF NOT EXISTS `%s`', $assoc_args['dbname'] ); - - Utils\run_mysql_command( 'mysql --no-defaults', array( - 'execute' => $query, - 'host' => $assoc_args['dbhost'], - 'user' => $assoc_args['dbuser'], - 'pass' => $assoc_args['dbpass'], - ) ); - - // Create the wp-tests-config.php file - $config_file = file_get_contents( $tests_dir . 'wp-tests-config-sample.php' ); - - $replacements = array( - "dirname( __FILE__ ) . '/wordpress/'" => "'" . ABSPATH . "'", - "yourdbnamehere" => $assoc_args['dbname'], - "yourusernamehere" => $assoc_args['dbuser'], - "yourpasswordhere" => $assoc_args['dbpass'], - "localhost" => $assoc_args['dbhost'], - ); - - $config_file = str_replace( array_keys( $replacements ), array_values( $replacements ), $config_file ); - - $config_file_path = $tests_dir . 'wp-tests-config.php'; - - file_put_contents( $config_file_path, $config_file ); - - WP_CLI::success( "Created $config_file_path" ); - } } WP_CLI::add_command( 'core', 'Core_Command' ); From d9111162635742017d1d20e45de93370e2b8575d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Nov 2013 08:50:38 +0200 Subject: [PATCH 2539/5359] make WP_TESTS_DIR optional, by defaulting to a temporary path --- templates/.travis.yml | 1 - templates/bootstrap.mustache | 7 +++++-- templates/install-wp-tests.sh | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index bc729686e..81650f76b 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -11,7 +11,6 @@ env: - WP_VERSION=3.6.1 WP_MULTISITE=1 before_script: - - export WP_TESTS_DIR=/tmp/wordpress-tests/ - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION script: phpunit diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index 18f87a91a..c18a7fe3e 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -1,11 +1,14 @@ <?php -require_once getenv( 'WP_TESTS_DIR' ) . '/includes/functions.php'; +$_tests_dir = getenv('WP_TESTS_DIR'); +if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib'; + +require_once $_tests_dir . '/includes/functions.php'; function _manually_load_plugin() { require dirname( __FILE__ ) . '/../{{plugin_slug}}.php'; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); -require getenv( 'WP_TESTS_DIR' ) . '/includes/bootstrap.php'; +require $_tests_dir . '/includes/bootstrap.php'; diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 82fa4a8ec..88e2dd3f2 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -11,6 +11,7 @@ DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-master} +WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=/tmp/wordpress/ set -ex From 706f978b53991d4dcf3c1449cb97757f9caf3a9d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 25 Nov 2013 09:41:48 +0200 Subject: [PATCH 2540/5359] plugin tests: use better backup extension --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 88e2dd3f2..782dec87e 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -34,7 +34,7 @@ install_wp() { install_test_suite() { # portable in-place argument for both GNU sed and Mac OSX sed if [[ $(uname -s) == 'Darwin' ]]; then - local ioption='-i ""' + local ioption='-i .bak' else local ioption='-i' fi From 7de457b231a285c84606225cf0c5167051bae35c Mon Sep 17 00:00:00 2001 From: Tiago Hillebrandt <tiagohillebrandt@ubuntu.com> Date: Mon, 25 Nov 2013 03:10:42 -0600 Subject: [PATCH 2541/5359] Implements 'wp plugin deactivate --all' function --- php/commands/plugin.php | 45 ++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index f91aa01d0..8da2044ed 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -158,25 +158,46 @@ function activate( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <plugin>... + * [<plugin>...] * : One or more plugins to deactivate. * + * [--all] + * : If set, all plugins will be deactivated. + * * [--network] * : If set, the plugin will be deactivated for the entire multisite network. */ function deactivate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - deactivate_plugins( $plugin->file, false, $network_wide ); - - if ( ! $this->check_active( $plugin->file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '{$plugin->name}' network deactivated." ); - else - WP_CLI::success( "Plugin '{$plugin->name}' deactivated." ); - } else { - WP_CLI::warning( "Could not deactivate the '{$plugin->name}' plugin." ); + $disable_all = isset( $assoc_args['all'] ); + + if ( $disable_all ) { + foreach ( get_plugins() as $file => $details ) { + $name = $this->get_name( $file ); + + deactivate_plugins( $name, false, $network_wide ); + + if ( ! $this->check_active( $file, $network_wide ) ) { + if ( $network_wide ) + WP_CLI::success( "Plugin '{$name}' network deactivated." ); + else + WP_CLI::success( "Plugin '{$name}' deactivated." ); + } else { + WP_CLI::warning( "Could not deactivate the '{$name}' plugin." ); + } + } + } else { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + deactivate_plugins( $plugin->file, false, $network_wide ); + + if ( ! $this->check_active( $plugin->file, $network_wide ) ) { + if ( $network_wide ) + WP_CLI::success( "Plugin '{$plugin->name}' network deactivated." ); + else + WP_CLI::success( "Plugin '{$plugin->name}' deactivated." ); + } else { + WP_CLI::warning( "Could not deactivate the '{$plugin->name}' plugin." ); + } } } } From 2479dccb14850c034585e0a031b7fffb6a49ba7d Mon Sep 17 00:00:00 2001 From: Tiago Hillebrandt <tiagohillebrandt@ubuntu.com> Date: Mon, 25 Nov 2013 05:05:09 -0600 Subject: [PATCH 2542/5359] Implements the 'wp plugin deactivate --all' function --- php/commands/plugin.php | 44 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 8da2044ed..a747747f4 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -142,14 +142,7 @@ function activate( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { activate_plugin( $plugin->file, '', $network_wide ); - if ( $this->check_active( $plugin->file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '{$plugin->name}' network activated." ); - else - WP_CLI::success( "Plugin '{$plugin->name}' activated." ); - } else { - WP_CLI::warning( "Could not activate the '{$plugin->name}' plugin." ); - } + $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); } } @@ -172,32 +165,18 @@ function deactivate( $args, $assoc_args = array() ) { $disable_all = isset( $assoc_args['all'] ); if ( $disable_all ) { - foreach ( get_plugins() as $file => $details ) { + foreach ( get_plugins() as $file => $details ) { $name = $this->get_name( $file ); - deactivate_plugins( $name, false, $network_wide ); + deactivate_plugins( $file, false, $network_wide ); - if ( ! $this->check_active( $file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '{$name}' network deactivated." ); - else - WP_CLI::success( "Plugin '{$name}' deactivated." ); - } else { - WP_CLI::warning( "Could not deactivate the '{$name}' plugin." ); - } + $this->active_output( $name, $file, $network_wide, "deactivate" ); } } else { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { deactivate_plugins( $plugin->file, false, $network_wide ); - if ( ! $this->check_active( $plugin->file, $network_wide ) ) { - if ( $network_wide ) - WP_CLI::success( "Plugin '{$plugin->name}' network deactivated." ); - else - WP_CLI::success( "Plugin '{$plugin->name}' deactivated." ); - } else { - WP_CLI::warning( "Could not deactivate the '{$plugin->name}' plugin." ); - } + $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); } } } @@ -531,6 +510,19 @@ private function check_active( $file, $network_wide ) { return $required == $this->get_status( $file ); } + private function active_output( $name, $file, $network_wide, $action ) { + $check = $this->check_active( $file, $network_wide ); + + if ( ( $action == "activate" ) ? $check : ! $check ) { + if ( $network_wide ) + WP_CLI::success( "Plugin '{$name}' network {$action}d." ); + else + WP_CLI::success( "Plugin '{$name}' {$action}d." ); + } else { + WP_CLI::warning( "Could not {$action} the '{$name}' plugin." ); + } + } + protected function get_status( $file ) { if ( is_plugin_active_for_network( $file ) ) return 'active-network'; From 829ae8f8545f5081c8dd4b028d201b429fee94d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 26 Nov 2013 09:25:21 +0200 Subject: [PATCH 2543/5359] s/action/hook --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/class-wp-cli.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 465b0d8ee..534c367d7 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -203,7 +203,7 @@ function invoke( $args, $assoc_args, $extra_args ) { $this->validate_args( $args, $assoc_args ); - \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); + \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index c510a84bf..946bd304d 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -133,7 +133,7 @@ static function colorize( $string ) { /** * Schedule a callback to be executed at a certain point (before WP is loaded). */ - static function add_action( $when, $callback ) { + static function add_hook( $when, $callback ) { if ( in_array( $when, self::$hooks_passed ) ) call_user_func( $callback ); @@ -143,7 +143,7 @@ static function add_action( $when, $callback ) { /** * Execute registered callbacks. */ - static function do_action( $when ) { + static function do_hook( $when ) { self::$hooks_passed[] = $when; if ( !isset( self::$hooks[ $when ] ) ) @@ -164,7 +164,7 @@ static function add_command( $name, $class, $args = array() ) { $command = Dispatcher\CommandFactory::create( $name, $class, self::get_root_command() ); if ( isset( $args['before_invoke'] ) ) { - self::add_action( "before_invoke:$name", $args['before_invoke'] ); + self::add_hook( "before_invoke:$name", $args['before_invoke'] ); } self::get_root_command()->add_subcommand( $name, $command ); From 2a226bff97c00a7713418f46327cb1c15c64a77c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 26 Nov 2013 13:24:37 -0800 Subject: [PATCH 2544/5359] Support for `user_email` as a third type of argument that can be passed to `<user>` --- php/WP_CLI/Fetchers/User.php | 13 ++++++++----- php/commands/user.php | 18 +++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/Fetchers/User.php b/php/WP_CLI/Fetchers/User.php index 81bbbc20a..122dfd0fc 100644 --- a/php/WP_CLI/Fetchers/User.php +++ b/php/WP_CLI/Fetchers/User.php @@ -4,13 +4,16 @@ class User extends Base { - protected $msg = "Invalid user ID or login: '%s'"; + protected $msg = "Invalid user ID, email or login: '%s'"; - public function get( $id_or_login ) { - if ( is_numeric( $id_or_login ) ) - $user = get_user_by( 'id', $id_or_login ); + public function get( $id_email_or_login ) { + + if ( is_email( $id_email_or_login ) ) + $user = get_user_by( 'email', $id_email_or_login ); + else if ( is_numeric( $id_email_or_login ) ) + $user = get_user_by( 'id', $id_email_or_login ); else - $user = get_user_by( 'login', $id_or_login ); + $user = get_user_by( 'login', $id_email_or_login ); return $user; } diff --git a/php/commands/user.php b/php/commands/user.php index ae1733a4d..b60d4b021 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -80,7 +80,7 @@ public function _list( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * [--field=<field>] * : Instead of returning the whole user, returns the value of a single field. @@ -119,7 +119,7 @@ public function get( $args, $assoc_args ) { * ## OPTIONS * * <user>... - * : The user login or ID of the user(s) to update. + * : The user login, user email, or user ID of the user(s) to update. * * [--reassign=<user-id>] * : User ID to reassign the posts to. @@ -235,7 +235,7 @@ public function create( $args, $assoc_args ) { * ## OPTIONS * * <user>... - * : The user login or ID of the user(s) to update. + * : The user login, user email or user ID of the user(s) to update. * * --<field>=<value> * : One or more fields to update. For accepted fields, see wp_update_user(). @@ -313,7 +313,7 @@ public function generate( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * [<role>] * : Make the user have the specified role. If not passed, the default role is @@ -346,7 +346,7 @@ public function set_role( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * <role> * : Add the specified role to the user. @@ -374,7 +374,7 @@ public function add_role( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * [<role>] * : A specific role to remove. @@ -412,7 +412,7 @@ public function remove_role( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * <cap> * : The capability to add. @@ -440,7 +440,7 @@ public function add_cap( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or user login. + * : User ID, user email, or user login. * * <cap> * : The capability to be removed. @@ -468,7 +468,7 @@ public function remove_cap( $args, $assoc_args ) { * ## OPTIONS * * <user> - * : User ID or login. + * : User ID, user email, or login. * * ## EXAMPLES * From c052ca9286b88744e601ea07aa41864713d865bd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 26 Nov 2013 13:26:41 -0800 Subject: [PATCH 2545/5359] Update functional test with email case --- features/user.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/user.feature b/features/user.feature index 14ecdf18a..aae1ad930 100644 --- a/features/user.feature +++ b/features/user.feature @@ -22,6 +22,12 @@ Feature: Manage WordPress users | ID | {USER_ID} | | display_name | Foo | + When I run `wp user get testuser@example.com` + Then STDOUT should be a table containing rows: + | Field | Value | + | ID | {USER_ID} | + | display_name | Foo | + When I run `wp user delete {USER_ID}` Then STDOUT should not be empty From be36a7f29639717303eb64a556dc93d5b9328729 Mon Sep 17 00:00:00 2001 From: Tiago Hillebrandt <tiagohillebrandt@ubuntu.com> Date: Wed, 27 Nov 2013 09:53:12 -0600 Subject: [PATCH 2546/5359] Deactivate only active plugins. --- php/commands/plugin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index a747747f4..7b1ece99c 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -166,6 +166,9 @@ function deactivate( $args, $assoc_args = array() ) { if ( $disable_all ) { foreach ( get_plugins() as $file => $details ) { + if ( $this->get_status( $file ) == "inactive" ) + continue; + $name = $this->get_name( $file ); deactivate_plugins( $file, false, $network_wide ); From 27d80a619b1cc2c13b0d65d9904ab56bbb482f53 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Wed, 27 Nov 2013 20:59:12 +0000 Subject: [PATCH 2547/5359] Make validate_role() return a bool. Throw error at caller if required --- php/commands/user.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index ae1733a4d..b774423b9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -193,7 +193,9 @@ public function create( $args, $assoc_args ) { ); extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); - $role = self::validate_role( $role ); + if ( !self::validate_role( $role ) ) { + WP_CLI::error( "Invalid role: $role" ); + } // @codingStandardsIgnoreStart if ( !$user_pass ) { @@ -276,7 +278,9 @@ public function generate( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - $role = self::validate_role( $assoc_args['role'] ); + if ( !self::validate_role( $assoc_args['role'] ) ) { + WP_CLI::error( "Invalid role: $role" ); + } $user_count = count_users(); $total = $user_count['total_users']; @@ -580,11 +584,10 @@ public function import_csv( $args, $assoc_args ) { } private static function validate_role( $role ) { - if ( 'none' === $role ) { - $role = false; - } elseif ( is_null( get_role( $role ) ) ) { - WP_CLI::error( "Invalid role: $role" ); + if ( empty( $role ) || ! is_null( get_role( $role ) ) ) { + return true; } + return false; } } From 4c61e978354ab383c49eb3d4549b3227e81d1983 Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Wed, 27 Nov 2013 20:59:22 +0000 Subject: [PATCH 2548/5359] Add tests --- features/user.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/user.feature b/features/user.feature index 14ecdf18a..008665a94 100644 --- a/features/user.feature +++ b/features/user.feature @@ -8,6 +8,22 @@ Feature: Manage WordPress users Then the return code should be 1 And STDOUT should be empty + When I run `wp user create testuser2 testuser2@example.com --role=author --porcelain` + Then STDOUT should be a number + And save STDOUT as {USER_ID} + And I run `wp user get {USER_ID}` + Then STDOUT should be a table containing rows: + | Field | Value | + | ID | {USER_ID} | + | roles | author | + + When I run `wp user delete {USER_ID}` + Then STDOUT should not be empty + + When I try `wp user create testuser2 testuser2@example.com --role=wrongrole --porcelain` + Then the return code should be 1 + Then STDOUT should be empty + When I run `wp user create testuser testuser@example.com --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} From e2dc3cc8e4deacf7a1a019d3ec26ee862ba19bda Mon Sep 17 00:00:00 2001 From: Lee Willis <leewillis77@gmail.com> Date: Thu, 28 Nov 2013 10:14:58 +0000 Subject: [PATCH 2549/5359] Fix spacing --- features/user.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index 008665a94..df1ab11d1 100644 --- a/features/user.feature +++ b/features/user.feature @@ -11,8 +11,8 @@ Feature: Manage WordPress users When I run `wp user create testuser2 testuser2@example.com --role=author --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} - And I run `wp user get {USER_ID}` - Then STDOUT should be a table containing rows: + And I run `wp user get {USER_ID}` + Then STDOUT should be a table containing rows: | Field | Value | | ID | {USER_ID} | | roles | author | From cf35c7e6493bce575748de4af00e095ef17477a4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Nov 2013 21:19:09 +0200 Subject: [PATCH 2550/5359] bump version to 0.13-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index ebeac71ea..c73b19833 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13-alpha3' ); +define( 'WP_CLI_VERSION', '0.13-beta' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 011446f346fff4c66ec23c0a97b6bc0c6f7eb1a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Nov 2013 21:31:41 +0200 Subject: [PATCH 2551/5359] add test case for activating network-only plugins --- features/plugin.feature | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index ecd3aab3f..48517e456 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -1,9 +1,7 @@ Feature: Manage WordPress plugins - Background: - Given a WP install - Scenario: Create, activate and check plugin status + Given a WP install And I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} @@ -70,6 +68,8 @@ Feature: Manage WordPress plugins """ Scenario: Install a plugin, activate, then force install an older version of the plugin + Given a WP install + When I run `wp plugin install akismet --version=2.5.7 --force` Then STDOUT should not be empty @@ -89,8 +89,23 @@ Feature: Manage WordPress plugins | name | status | update | version | | akismet | active | available | 2.5.6 | + Scenario: Activate a network-only plugin + Given a WP multisite install + And a wp-content/plugins/network-only.php file: + """ + // Plugin Name: Example Plugin + // Network: true + """ + When I run `wp plugin activate network-only` + And I run `wp plugin status network-only` + Then STDOUT should contain: + """ + Status: Network Active + """ Scenario: List plugins + Given a WP install + When I run `wp plugin activate akismet hello` Then STDOUT should not be empty From c3ae0cfbe7093dd63b9bcea73ee28c294ee3c141 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 28 Nov 2013 21:42:44 +0200 Subject: [PATCH 2552/5359] check if plugin is network-only --- php/commands/plugin.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 7b1ece99c..5f9277abf 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -514,6 +514,8 @@ private function check_active( $file, $network_wide ) { } private function active_output( $name, $file, $network_wide, $action ) { + $network_wide = $network_wide || is_network_only_plugin( $file ); + $check = $this->check_active( $file, $network_wide ); if ( ( $action == "activate" ) ? $check : ! $check ) { From 6900ba58f63dccdb18402304e408dcbca83d53d2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Nov 2013 22:41:47 +0200 Subject: [PATCH 2553/5359] clarify inline docs for --format parameter; fixes #884 --- php/commands/cli.php | 5 ++++- php/commands/comment.php | 7 ++----- php/commands/plugin.php | 4 ++-- php/commands/post.php | 11 +++-------- php/commands/rewrite.php | 6 +++--- php/commands/role.php | 2 +- php/commands/site.php | 2 +- php/commands/term.php | 7 ++----- php/commands/theme.php | 6 +++--- php/commands/user.php | 8 ++------ 10 files changed, 23 insertions(+), 35 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 36d9055ce..752b1d603 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -38,7 +38,10 @@ function version() { /** * Print various data about the CLI environment. * - * @synopsis [--format=<format>] + * ## OPTIONS + * + * [--format=<format>] + * : Accepted values: json */ function info( $_, $assoc_args ) { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); diff --git a/php/commands/comment.php b/php/commands/comment.php index 06b4b64a4..6a45b839c 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -94,10 +94,7 @@ public function update( $args, $assoc_args ) { * : Instead of returning the whole comment, returns the value of a single field. * * [--format=<format>] - * : The format to use when printing the comment, acceptable values: - * - * - **table**: Outputs all fields of the comment as a table. - * - **json**: Outputs all fields in JSON format. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * @@ -128,7 +125,7 @@ public function get( $args, $assoc_args ) { * : Limit the output to specific object fields. Defaults to comment_ID,comment_post_ID,comment_date,comment_approved,comment_author,comment_author_email * * [--format=<format>] - * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 5f9277abf..d0e802f59 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -76,7 +76,7 @@ function status( $args ) { * **short_description**: Plugin's Short Description * * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * @@ -493,7 +493,7 @@ function delete( $args, $assoc_args = array() ) { * : Limit the output to specific object fields. Defaults to name,status,update,version. * * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * diff --git a/php/commands/post.php b/php/commands/post.php index ca9a156fd..f6f11ba66 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -142,12 +142,7 @@ protected function _edit( $content, $title ) { * : Instead of returning the whole post, returns the value of a single field. * * [--format=<format>] - * : The format to use when printing the post, acceptable values: - * - * - **table**: Outputs all fields of the post as a table. Note that the - * post_content field is omitted so that the table is readable. - * - * - **json**: Outputs all fields in JSON format. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * @@ -215,7 +210,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. * * [--format=<format>] - * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * @@ -236,7 +231,7 @@ public function _list( $_, $assoc_args ) { ); $query_args = array_merge( $defaults, $assoc_args ); - foreach( $query_args as $key => $query_arg ) { + foreach ( $query_args as $key => $query_arg ) { if ( false !== strpos( $key, '__' ) ) $query_args[$key] = explode( ',', $query_arg ); } diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 0f85ddc12..04f15cae7 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -93,15 +93,15 @@ public function structure( $args, $assoc_args ) { * Print current rewrite rules. * * ## OPTIONS - * + * * [--match=<url>] * : Show rewrite rules matching a particular URL. - * + * * [--source=<source>] * : Show rewrite rules from a particular source. * * [--format=<format>] - * : Output list as table, JSON or CSV. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * diff --git a/php/commands/role.php b/php/commands/role.php index 97674ffbf..99e5ecb60 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -21,7 +21,7 @@ class Role_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to name,role. * * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * diff --git a/php/commands/site.php b/php/commands/site.php index e3d500da4..111a91515 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -317,7 +317,7 @@ public function create( $_, $assoc_args ) { * : Comma-separated list of fields to show. * * [--format=<format>] - * : Output list as table, csv, json or url. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * diff --git a/php/commands/term.php b/php/commands/term.php index 770e5f3da..8e9fc9d7c 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -34,7 +34,7 @@ class Term_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to all of the term object fields. * * [--format=<format>] - * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * @@ -131,10 +131,7 @@ public function create( $args, $assoc_args ) { * : Instead of returning the whole term, returns the value of a single field. * * [--format=<format>] - * : The format to use when printing the term, acceptable values: - * - * - **table**: Outputs all fields of the term as a table. - * - **json**: Outputs all fields in JSON format. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * diff --git a/php/commands/theme.php b/php/commands/theme.php index e9fa1e70a..7975acb86 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -69,7 +69,7 @@ function status( $args ) { * **description**: Theme Description * * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * @@ -266,7 +266,7 @@ function install( $args, $assoc_args ) { * : Instead of returning the whole theme, returns the value of a single field. * * [--format=<format>] - * : Output list as table or JSON. Defaults to table. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * @@ -387,7 +387,7 @@ function delete( $args ) { * : Limit the output to specific object fields. Defaults to name,status,update,version. * * [--format=<format>] - * : Output list as table, CSV or JSON. Defaults to table. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * diff --git a/php/commands/user.php b/php/commands/user.php index b774423b9..9e02172f8 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -39,7 +39,7 @@ public function __construct() { * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles * * [--format=<format>] - * : Output list as table, CSV, JSON, or simply IDs. Defaults to table. + * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES * @@ -86,11 +86,7 @@ public function _list( $args, $assoc_args ) { * : Instead of returning the whole user, returns the value of a single field. * * [--format=<format>] - * : The format to use when printing the user; acceptable values: - * - * **table**: Outputs all fields of the user as a table. - * - * **json**: Outputs all fields in JSON format. + * : Accepted values: table, json. Default: table * * ## EXAMPLES * From 37b9a38853b083af855b57ec9e289c0b54ad9066 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Nov 2013 23:26:38 +0200 Subject: [PATCH 2554/5359] include extra args when checking required associative parameters; see #883 --- features/config.feature | 11 +++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/features/config.feature b/features/config.feature index a39a943fc..12267e573 100644 --- a/features/config.feature +++ b/features/config.feature @@ -85,12 +85,23 @@ Feature: Have a config file Given a WP install And a wp-cli.yml file: """ + core config: + dbname: wordpress + dbuser: root eval: foo: bar post list: format: count """ + # Required parameters should be recognized + When I try `wp core config` + Then STDERR should not contain: + """ + Parameter errors + """ + + # Arbitrary values should be passed, without warnings When I run `wp eval 'echo json_encode( $assoc_args );'` Then STDOUT should be JSON containing: """ diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 534c367d7..ae9bd32bb 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -146,9 +146,8 @@ private function prompt_args( $args, $assoc_args ) { return array( $args, $assoc_args ); } - private function validate_args( $args, &$assoc_args ) { + private function validate_args( $args, $assoc_args, $extra_args ) { $synopsis = $this->get_synopsis(); - if ( !$synopsis ) return; @@ -174,7 +173,7 @@ private function validate_args( $args, &$assoc_args ) { } list( $errors, $to_unset ) = $validator->validate_assoc( - array_merge( \WP_CLI::get_config(), $assoc_args ) + array_merge( \WP_CLI::get_config(), $extra_args, $assoc_args ) ); if ( !empty( $errors['fatal'] ) ) { @@ -188,22 +187,24 @@ private function validate_args( $args, &$assoc_args ) { array_map( '\\WP_CLI::warning', $errors['warning'] ); - foreach ( $to_unset as $key ) { - unset( $assoc_args[ $key ] ); - } - foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { \WP_CLI::warning( "unknown --$key parameter" ); } + + return $to_unset; } function invoke( $args, $assoc_args, $extra_args ) { if ( \WP_CLI::get_config( 'prompt' ) ) list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); - $this->validate_args( $args, $assoc_args ); + $to_unset = $this->validate_args( $args, $assoc_args, $extra_args ); + + foreach ( $to_unset as $key ) { + unset( $assoc_args[ $key ] ); + } - \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); + \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); } From b720f6d92828d4e8654bc0ae1d45f1c52a93c7be Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Nov 2013 23:31:04 +0200 Subject: [PATCH 2555/5359] replace do_action() with do_hook() again; see #883 --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index ae9bd32bb..41b7a135f 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -204,7 +204,7 @@ function invoke( $args, $assoc_args, $extra_args ) { unset( $assoc_args[ $key ] ); } - \WP_CLI::do_action( 'before_invoke:' . $this->get_parent()->get_name() ); + \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); } From 4fc145153689b3c8a38253bda5e974d7e56058d6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Nov 2013 23:40:00 +0200 Subject: [PATCH 2556/5359] make validate_args() always return an array see #883 --- php/WP_CLI/Dispatcher/Subcommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 41b7a135f..8f112c86b 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -146,10 +146,13 @@ private function prompt_args( $args, $assoc_args ) { return array( $args, $assoc_args ); } + /** + * @return array list of invalid $assoc_args keys to unset + */ private function validate_args( $args, $assoc_args, $extra_args ) { $synopsis = $this->get_synopsis(); if ( !$synopsis ) - return; + return array(); $validator = new \WP_CLI\SynopsisValidator( $synopsis ); From af6c9ef96c88d96365a340b6959e75fc95952daa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 Nov 2013 23:00:26 +0200 Subject: [PATCH 2557/5359] disable HTML escaping when rendering Mustache templates --- php/utils.php | 9 ++++++++- templates/man-params.mustache | 2 +- templates/man.mustache | 8 ++++---- templates/post_type_extended.mustache | 2 +- templates/taxonomy_extended.mustache | 2 +- templates/wp-config.mustache | 4 ++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/php/utils.php b/php/utils.php index c3abfdf19..1972c2505 100644 --- a/php/utils.php +++ b/php/utils.php @@ -340,13 +340,20 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { if ( $r ) exit( $r ); } +/** + * Render PHP or other types of files using Mustache templates. + * + * IMPORTANT: Automatic HTML escaping is disabled! + */ function mustache_render( $template_name, $data ) { if ( ! file_exists( $template_name ) ) $template_name = WP_CLI_ROOT . "/templates/$template_name"; $template = file_get_contents( $template_name ); - $m = new \Mustache_Engine; + $m = new \Mustache_Engine( array( + 'escape' => function ( $val ) { return $val; } + ) ); return $m->render( $template, $data ); } diff --git a/templates/man-params.mustache b/templates/man-params.mustache index 990412b74..dd848d83f 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -1,7 +1,7 @@ ## GLOBAL PARAMETERS {{#parameters}} - {{{synopsis}}} + {{synopsis}} {{desc}} {{/parameters}} diff --git a/templates/man.mustache b/templates/man.mustache index 6767c83d8..a42acbcc3 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -1,20 +1,20 @@ ## NAME - {{{name}}} + {{name}} ## DESCRIPTION - {{{shortdesc}}} + {{shortdesc}} ## SYNOPSIS - {{{synopsis}}} + {{synopsis}} {{#has-subcommands}} ## SUBCOMMANDS {{#subcommands}} - {{{.}}} + {{.}} {{/subcommands}} {{/has-subcommands}} diff --git a/templates/post_type_extended.mustache b/templates/post_type_extended.mustache index 9acbbb5d2..b8250fde9 100644 --- a/templates/post_type_extended.mustache +++ b/templates/post_type_extended.mustache @@ -1,7 +1,7 @@ <?php function {{machine_name}}_init() { -{{{output}}} +{{output}} } add_action( 'init', '{{machine_name}}_init' ); diff --git a/templates/taxonomy_extended.mustache b/templates/taxonomy_extended.mustache index 8e0e1a5c7..e2e584a11 100644 --- a/templates/taxonomy_extended.mustache +++ b/templates/taxonomy_extended.mustache @@ -1,6 +1,6 @@ <?php function {{machine_name}}_init() { -{{{output}}} +{{output}} } add_action( 'init', '{{machine_name}}_init' ); diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index d0cec68c1..e708cc189 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -36,7 +36,7 @@ define('DB_COLLATE', '{{dbcollate}}'); * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. */ -{{{keys-and-salts}}} +{{keys-and-salts}} /**#@-*/ {{/keys-and-salts}} @@ -58,7 +58,7 @@ $table_prefix = '{{dbprefix}}'; */ define('WPLANG', '{{locale}}'); -{{{extra-php}}} +{{extra-php}} /* That's all, stop editing! Happy blogging. */ From c7494c543a609ee30681f6724462c7f0396e1d9e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 00:10:03 +0200 Subject: [PATCH 2558/5359] add example of using sort with 'wp cap list'; closes #715 --- php/commands/cap.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/cap.php b/php/commands/cap.php index 97d84113c..c5cc77745 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -19,6 +19,11 @@ class Capabilities_Command extends WP_CLI_Command { /** * List capabilities for a given role. * + * ## EXAMPLES + * + * # Display alphabetical list of bbPress moderator capabilities + * wp cap list 'bbp_moderator' | sort + * * @subcommand list * @synopsis <role> */ From 099ecae9fd2ef8ca562fba2284f062fa2229bbb5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 00:30:07 +0200 Subject: [PATCH 2559/5359] exclude Finder tests from Phar --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 4563f60a7..2d789e617 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -41,6 +41,7 @@ function add_file( $phar, $path ) { ->in('./vendor/rhumsaa/array_column') ->exclude('test') ->exclude('tests') + ->exclude('Tests') ->exclude('php-cli-tools/examples') ; From 81329f749058b5f64f0faa775f344491ade1053d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 00:57:24 +0200 Subject: [PATCH 2560/5359] rename launch_wpcli() to launch_self() and make it work from inside a Phar file --- php/class-wp-cli.php | 38 ++++++++++++++++++++++++-------------- php/commands/rewrite.php | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7b6fa98c8..351782d65 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -278,40 +278,50 @@ static function launch( $command, $exit_on_error = true ) { /** * Launch another WP-CLI command using the runtime arguments for the current process - * + * * @param string Command to call * @param array $args Positional arguments to use * @param array $assoc_args Associative arguments to use * @param bool Whether to exit if the command returns an error status - * + * * @return int The command exit status */ - static function launch_wpcli( $command, $args = array(), $assoc_args = array(), $exit_on_error = true ) { - + static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true ) { $reused_runtime_args = array( 'path', 'url', 'user', - ); - foreach( $reused_runtime_args as $key ) { + ); + + foreach ( $reused_runtime_args as $key ) { if ( $value = self::get_runner()->config[ $key ] ) - $assoc_args[$key] = $value; + $assoc_args[ $key ] = $value; } - $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + $php_bin = self::get_php_binary(); - $boot_fs_path = $GLOBALS['argv'][0]; - $wp_cli_root = constant( 'WP_CLI_ROOT' ); - if ( false === stripos( $boot_fs_path, $wp_cli_root ) ) - $boot_fs_path = $wp_cli_root . '/' . $boot_fs_path; + $script_path = $GLOBALS['argv'][0]; $args = implode( ' ', array_map( 'escapeshellarg', $args ) ); $assoc_args = \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); - $full_command = "{$php_bin} {$boot_fs_path} {$command} {$args} {$assoc_args}"; + $full_command = "{$php_bin} {$script_path} {$command} {$args} {$assoc_args}"; return self::launch( $full_command, $exit_on_error ); - } + } + + private static function get_php_binary() { + if ( defined( 'PHP_BINARY' ) ) + return PHP_BINARY; + + if ( getenv( 'WP_CLI_PHP_USED' ) ) + return getenv( 'WP_CLI_PHP_USED' ); + + if ( getenv( 'WP_CLI_PHP' ) ) + return getenv( 'WP_CLI_PHP' ); + + return 'php'; + } static function get_config( $key = null ) { if ( null === $key ) { diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 1597d9726..4775d8884 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -91,7 +91,7 @@ public function structure( $args, $assoc_args ) { $new_assoc_args = array(); if ( isset( $assoc_args['hard'] ) ) $new_assoc_args['hard'] = true; - \WP_CLI::launch_wpcli( 'rewrite flush', array(), $new_assoc_args ); + \WP_CLI::launch_self( 'rewrite flush', array(), $new_assoc_args ); WP_CLI::success( "Rewrite structure set." ); } From ee6709fa9539f7c46078c752117d4390822e2ba6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 01:00:12 +0200 Subject: [PATCH 2561/5359] clean up rewrite.feature --- features/rewrite.feature | 42 +++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index 9ccb04f0c..2d5ec586f 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -1,37 +1,35 @@ Feature: Manage WordPress rewrites - Background: + Scenario: Change site permastructs Given a WP install - Scenario: Change site permastructs When I run `wp rewrite structure /blog/%year%/%monthnum%/%day%/%postname%/ --category-base=section --tag-base=topic` + And I run `wp option get permalink_structure` + Then STDOUT should contain: + """ + /blog/%year%/%monthnum%/%day%/%postname%/ + """ - When I run `wp option get permalink_structure` - Then STDOUT should contain: - """ - /blog/%year%/%monthnum%/%day%/%postname%/ - """ - - When I run `wp option get category_base` - Then STDOUT should contain: - """ - section - """ + When I run `wp option get category_base` + Then STDOUT should contain: + """ + section + """ - When I run `wp option get tag_base` - Then STDOUT should contain: - """ - topic - """ + When I run `wp option get tag_base` + Then STDOUT should contain: + """ + topic + """ - When I run `wp rewrite list --format=csv` - Then STDOUT should be CSV containing: + When I run `wp rewrite list --format=csv` + Then STDOUT should be CSV containing: | match | query | source | | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | post | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | | section/(.+?)/?$ | index.php?category_name=$matches[1] | category | - When I run `wp rewrite list --match=/topic/apple/ --format=csv` - Then STDOUT should be CSV containing: + When I run `wp rewrite list --match=/topic/apple/ --format=csv` + Then STDOUT should be CSV containing: | match | query | source | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | From 279cb5fc6b1072604f7cce317f017f32007c4e3f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 01:23:23 +0200 Subject: [PATCH 2562/5359] bump version to 0.13-RC --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index c73b19833..c6263f8b9 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13-beta' ); +define( 'WP_CLI_VERSION', '0.13-RC' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 5bf2b02d59c58852ddff1f12e0d6981ada56b1e8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 29 Nov 2013 23:03:02 -0200 Subject: [PATCH 2563/5359] --post_content as a flag that reads from STDIN --- features/post.feature | 9 +++++++++ php/commands/post.php | 9 +++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/features/post.feature b/features/post.feature index d4231c87c..d7d9588df 100644 --- a/features/post.feature +++ b/features/post.feature @@ -119,3 +119,12 @@ Feature: Manage WordPress posts """ Sample Page """ + + Scenario: Generating posts + When I run `echo "Content generated by wp post generate" | wp post generate --count=1 --post_content` + And I run `wp post list --field=post_content` + Then STDOUT should contain: + """ + Content generated by wp post generate + """ + And STDERR should be empty \ No newline at end of file diff --git a/php/commands/post.php b/php/commands/post.php index 1f8f7100e..8b772026e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -269,8 +269,8 @@ public function _list( $_, $assoc_args ) { * [--post_date=<yyyy-mm-dd>] * : The date of the generated posts. Default: current date * - * [--post_content=<content>] - * : The content of the generated posts. Default: empty + * [--post_content] + * : If set, the command reads the post_content from STDIN. * * [--max_depth=<number>] * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 @@ -278,6 +278,7 @@ public function _list( $_, $assoc_args ) { * ## EXAMPLES * * wp post generate --count=10 --post_type=page --post_date=1999-01-04 + * curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 */ public function generate( $args, $assoc_args ) { global $wpdb; @@ -305,6 +306,10 @@ public function generate( $args, $assoc_args ) { $post_author = $post_author->ID; } + if ( isset( $assoc_args['post_content'] ) ) { + $post_content = file_get_contents( 'php://stdin' ); + } + // Get the total number of posts $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); From 3821c694ae5409a58c779e8806f60ca3a8da4662 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Fri, 29 Nov 2013 17:08:26 -0800 Subject: [PATCH 2564/5359] Allow wp-db-export to write to STDOUT if <file> is - --- php/commands/db.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 2068248fa..c7ef38cb8 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -120,9 +120,11 @@ function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), array( - 'result-file' => $result_file - ) ); + $cmd_args = array(); + if ( '-' !== $result_file ) { + $cmd_args['result-file'] = $result_file; + } + self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), $cmd_args ); WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } From cdf1c9fef31f5b70d4494140fd8cc8e693bfe1a6 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Fri, 29 Nov 2013 17:37:02 -0800 Subject: [PATCH 2565/5359] Update wp-db-export phpdoc options --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index c7ef38cb8..328aff869 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -11,7 +11,7 @@ * : Answer yes to the confirmation message. * * <file> - * : The name of the export file. If omitted, it will be '{dbname}.sql' + * : The name of the export file. If '-', then outputs to STDOUT. If omitted, it will be '{dbname}.sql'. * * <SQL> * : A SQL query. From b4381cdc0bf761542e1e63411d86a9c8ff1592dc Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Fri, 29 Nov 2013 18:20:17 -0800 Subject: [PATCH 2566/5359] Suppress success message when exporting to STDOUT --- php/commands/db.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 328aff869..75eb6272d 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -119,14 +119,17 @@ function query( $args ) { */ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); + $stdout = ( '-' === $result_file ); $cmd_args = array(); - if ( '-' !== $result_file ) { + if ( ! $stdout ) { $cmd_args['result-file'] = $result_file; } self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), $cmd_args ); - WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); + if ( ! $stdout ) { + WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); + } } /** From afdd3d3fe0e1cc2e5b552cd23aab22a4c0a81216 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 13:35:34 +0200 Subject: [PATCH 2567/5359] update contributor list for 0.13 release --- .mailmap | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.mailmap b/.mailmap index 5b7349285..eaec314b5 100644 --- a/.mailmap +++ b/.mailmap @@ -1,17 +1,21 @@ andreascreten <andreas@madewithlove.be> bendoh <ben@thinkoomph.com> +BoiteAWeb <juliobosk@gmail.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> conatus <alex@recordsonribs.com> +ctayloroomphinc <ctaylor@thinkoomph.com> cyberhobo <dylan.k.kuhn@gmail.com> dangardner <dan@web.nearest.to> danielbachhuber <d@danielbachhuber.com> danielbachhuber <danielbachhuber@gmail.com> +dd32 <contact-atlassian@dd32.id.au> drrobotnik <B@Brandons-Mac-Pro-4.local> dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> eugeneware <eugene@noblesamurai.com> +francescolaffi <francesco.laffi@gmail.com> future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> glebis <glebis@gmail.com> @@ -23,7 +27,9 @@ jmslbam <jmslbam@gmail.com> johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> +jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> +Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> @@ -39,6 +45,7 @@ mwilliamson <mike@zwobble.org> nacin <andrewnacin@gmail.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> +nickdaugherty <ndaugherty987@gmail.com> nikolay <nikolay@users.noreply.github.com> nikolay <nikolaynkolev@gmail.com> nullvariable <nullvariable@gmail.com> @@ -47,9 +54,12 @@ oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> Rarst <contact@rarst.net> +rodrigoprimo <rodrigo@hacklab.com.br> roelven <roel@soundcloud.com> +ryanduff <ryan@fusionized.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> +simonwheatley <simonw@codeforthepeople.com> soulou <leo@soulou.fr> spuriousdata <spuriousdata@gmail.com> stianlik <stianlik@gmail.com> @@ -57,6 +67,7 @@ svaj <chris@chrisbot.(none)> taupecat <tracy@taupecat.com> tddewey <td@tddewey.com> thisislawatts <luke@thisis.la> +tiagohillebrandt <tiagohillebrandt@ubuntu.com> tlovett1 <admin@taylorlovett.com> tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> From 931b353757a21e614d2f5f46d8aaad27f895b485 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 14:38:28 +0200 Subject: [PATCH 2568/5359] change default global config path to ~/.wp-cli/config.yml context: #897 --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 65c376a43..06734b7e2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -46,7 +46,7 @@ private static function get_global_config_path() { } if ( !$config_path ) { - $config_path = getenv( 'HOME' ) . '/.config/wp-cli.yml'; + $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; } if ( !is_readable( $config_path ) ) From a7eaaecc62b8f5004cdf3b32273ed04884cbca2a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 Nov 2013 15:14:44 +0200 Subject: [PATCH 2569/5359] bump version to 0.13.0 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index c6263f8b9..a98a85d70 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13-RC' ); +define( 'WP_CLI_VERSION', '0.13.0' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From c68837da8102e3acc82fb371d070bb1f5e200f23 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sat, 30 Nov 2013 15:05:16 -0800 Subject: [PATCH 2570/5359] Make db-import accept - for STDIN Note there seems to be no difference with db-query for this. --- php/commands/db.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 75eb6272d..6661d5107 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -11,7 +11,7 @@ * : Answer yes to the confirmation message. * * <file> - * : The name of the export file. If '-', then outputs to STDOUT. If omitted, it will be '{dbname}.sql'. + * : The name of the SQL file for import/export. If '-', then inputs from STDIN and outputs to STDOUT. If omitted, it will be '{dbname}.sql'. * * <SQL> * : A SQL query. @@ -133,21 +133,30 @@ function export( $args, $assoc_args ) { } /** - * Import database from a file. + * Import database from a file or from STDIN. * * @synopsis [<file>] */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); - if ( !file_exists( $result_file ) ) { - WP_CLI::error( sprintf( 'Import file missing: %s', $result_file ) ); - } - $descriptors = array( - array( 'file', $result_file, 'r' ), - STDOUT, - STDERR, - ); + if ( '-' === $result_file ) { + $descriptors = array( + STDIN, + STDOUT, + STDERR, + ); + } else { + if ( ! file_exists( $result_file ) ) { + WP_CLI::error( sprintf( 'Import file missing: %s', $result_file ) ); + } + + $descriptors = array( + array( 'file', $result_file, 'r' ), + STDOUT, + STDERR, + ); + } self::run( 'mysql --no-defaults', array( 'database' => DB_NAME From 5a94a1a6ad6226309f80a5f95d4b5ed86661fb2a Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 1 Dec 2013 01:55:35 +0100 Subject: [PATCH 2571/5359] Use new PHPUnit url to curl from --- utils/dev-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/dev-build b/utils/dev-build index d4f3f09e4..0637d27b9 100755 --- a/utils/dev-build +++ b/utils/dev-build @@ -12,7 +12,7 @@ echo "Installing dependencies using Composer..." php composer.phar install echo "Downloading PHPUnit..." -curl -sS http://pear.phpunit.de/get/phpunit.phar > phpunit.phar +curl -sS https://phar.phpunit.de/phpunit.phar > phpunit.phar echo "Downloading Behat..." curl -sS http://behat.org/downloads/behat.phar > behat.phar From 100ab6a08cf3759ebdb70f9183b696dafbd291fc Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Sun, 1 Dec 2013 22:48:31 +0100 Subject: [PATCH 2572/5359] Simplify STDERR text check --- features/flags.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index 9d1dcc93e..9c3d4be44 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -40,7 +40,7 @@ Feature: Global flags """ And STDERR should contain: """ - PHP Notice: Use of undefined constant CONST_WITHOUT_QUOTES + Use of undefined constant CONST_WITHOUT_QUOTES """ Scenario: Setting the WP user From d73beb86854715283f85a1103e627796266a85e2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sun, 1 Dec 2013 22:53:12 -0200 Subject: [PATCH 2573/5359] stop wp-cli execution when there is an unknown parameter --- features/validation.feature | 8 ++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/features/validation.feature b/features/validation.feature index 803d758af..8910f3781 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -23,3 +23,11 @@ Feature: Argument validation """ Parameter errors: """ + + When I try `wp core config invalid --invalid --other-invalid` + Then the return code should be 1 + And STDERR should contain: + """ + unknown --unknown parameter + unknown --other-unknown parameter + """ \ No newline at end of file diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 8f112c86b..0e4685ae4 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -179,6 +179,10 @@ private function validate_args( $args, $assoc_args, $extra_args ) { array_merge( \WP_CLI::get_config(), $extra_args, $assoc_args ) ); + foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { + $errors['fatal'][] = "unknown --$key parameter"; + } + if ( !empty( $errors['fatal'] ) ) { $out = 'Parameter errors:'; foreach ( $errors['fatal'] as $error ) { @@ -190,10 +194,6 @@ private function validate_args( $args, $assoc_args, $extra_args ) { array_map( '\\WP_CLI::warning', $errors['warning'] ); - foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { - \WP_CLI::warning( "unknown --$key parameter" ); - } - return $to_unset; } From e38cc235684d43bee3bf77f7af093fe60ab12d56 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 3 Dec 2013 09:48:27 -0200 Subject: [PATCH 2574/5359] fix test --- features/validation.feature | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/features/validation.feature b/features/validation.feature index 8910f3781..ad1f89fef 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -28,6 +28,9 @@ Feature: Argument validation Then the return code should be 1 And STDERR should contain: """ - unknown --unknown parameter - unknown --other-unknown parameter - """ \ No newline at end of file + unknown --invalid parameter + """ + And STDERR should contain: + """ + unknown --other-invalid parameter + """ From e10ec5fc7f16d82d4c6148f2949ff1ceeab2b807 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Dec 2013 01:02:46 +0200 Subject: [PATCH 2575/5359] bump version to 0.14.0-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index a98a85d70..a592703db 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13.0' ); +define( 'WP_CLI_VERSION', '0.14.0-alpha' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 1f1fb69d42edbc73e40851eb568dd72514363328 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Dec 2013 01:43:05 +0200 Subject: [PATCH 2576/5359] db: move parameter descriptions to subcommands --- php/commands/db.php | 48 +++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 6661d5107..d0bb9cc4c 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -4,22 +4,6 @@ /** * Perform basic database operations. - * - * ## OPTIONS - * - * --yes - * : Answer yes to the confirmation message. - * - * <file> - * : The name of the SQL file for import/export. If '-', then inputs from STDIN and outputs to STDOUT. If omitted, it will be '{dbname}.sql'. - * - * <SQL> - * : A SQL query. - * - * ## EXAMPLES - * - * # execute a query stored in a file - * wp db query < debug.sql */ class DB_Command extends WP_CLI_Command { @@ -35,7 +19,10 @@ function create( $_, $assoc_args ) { /** * Delete the database. * - * @synopsis [--yes] + * ## OPTIONS + * + * [--yes] + * : Answer yes to the confirmation message. */ function drop( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); @@ -48,7 +35,10 @@ function drop( $_, $assoc_args ) { /** * Remove all tables from the database. * - * @synopsis [--yes] + * ## OPTIONS + * + * [--yes] + * : Answer yes to the confirmation message. */ function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); @@ -95,7 +85,15 @@ function cli() { /** * Execute a query against the database. * - * @synopsis [<sql>] + * ## OPTIONS + * + * [<sql>] + * : A SQL query. If not passed, will try to read from STDIN. + * + * ## EXAMPLES + * + * # execute a query stored in a file + * wp db query < debug.sql */ function query( $args ) { $assoc_args = array( @@ -111,11 +109,14 @@ function query( $args ) { } /** - * Exports the database using mysqldump. + * Exports the database to a file or to STDOUT. * - * @alias dump + * ## OPTIONS * - * @synopsis [<file>] + * [<file>] + * : The name of the SQL file to export. If '-', then outputs to STDOUT. If omitted, it will be '{dbname}.sql'. + * + * @alias dump */ function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); @@ -135,7 +136,8 @@ function export( $args, $assoc_args ) { /** * Import database from a file or from STDIN. * - * @synopsis [<file>] + * [<file>] + * : The name of the SQL file to export. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); From 335707f3898c23e58fb217cfaebef8177cfafd81 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 4 Dec 2013 01:46:32 +0200 Subject: [PATCH 2577/5359] I hear copy-pasta is not very nutritious. --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index d0bb9cc4c..83c60d9ae 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -137,7 +137,7 @@ function export( $args, $assoc_args ) { * Import database from a file or from STDIN. * * [<file>] - * : The name of the SQL file to export. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. + * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. */ function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); From 183595b6f0c9dde97c80310945725a469555c067 Mon Sep 17 00:00:00 2001 From: Justin de Vesine <justin@crowdfavorite.com> Date: Wed, 20 Nov 2013 14:21:59 -0700 Subject: [PATCH 2578/5359] Look for WP installation in simple subdir configs Teach WP-CLI about simple subdirectory installations of WP. If the current directory contains `index.php` and index.php contains a simple require of wp-blog-header.php (as the default index.php and simple modifications of it for WP-in-a-subdirectory both do), look for the WordPress installation based on that information. --- php/WP_CLI/Runner.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 06734b7e2..e4e7910ad 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -81,6 +81,22 @@ private static function set_wp_root( $config ) { $path = $config['path']; else $path .= '/' . $config['path']; + } else { + if ( file_exists( './index.php' ) ) { + $index_code = explode( "\n", file_get_contents( './index.php' ) ); + + foreach ( $index_code as $line ) { + if ( preg_match( '/^\s*require.+([\'"])(.*wp-blog-header\.php)\1/', $line, $matches ) ) { + $new_path = dirname( $matches[2] ); + if ( Utils\is_path_absolute( $new_path ) ) { + $path = $new_path; + } else { + $path .= '/' . $new_path; + } + break; + } + } + } } define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); From b95100eb611fcf51810696f6f6f80068d9f32e30 Mon Sep 17 00:00:00 2001 From: Justin de Vesine <justin@crowdfavorite.com> Date: Wed, 20 Nov 2013 14:38:23 -0700 Subject: [PATCH 2579/5359] Functional test for autodetection of subdir install --- features/config.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/config.feature b/features/config.feature index 12267e573..57f9e69f5 100644 --- a/features/config.feature +++ b/features/config.feature @@ -54,6 +54,19 @@ Feature: Have a config file When I run `wp core is-installed` from 'core/wp-content' Then STDOUT should be empty + Scenario: WP in a subdirectory (autodetected) + Given a WP install in 'core' + And a index.php file: + """ + require('./core/wp-blog-header.php'); + """ + + When I run `wp core is-installed` + Then STDOUT should be empty + + When I run `wp core is-installed` + Then STDOUT should be empty + Scenario: Nested installs Given a WP install And a WP install in 'subsite' From 8c82f96d7579471a7494564998abeeb4271cbfd0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 12 Dec 2013 12:56:25 -0200 Subject: [PATCH 2580/5359] fix undefined variable --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index d90bc93d6..c72ddd84c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -115,7 +115,7 @@ public function update( $args, $assoc_args ) { public function edit( $args, $_ ) { $post = $this->fetcher->get_check( $args[0] ); - $r = $this->_edit( $post->post_content, "WP-CLI post $post_id" ); + $r = $this->_edit( $post->post_content, "WP-CLI post {$post->ID}" ); if ( $r === false ) \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); From 0feb609e039eb8bd6f3f51385c61f8fb450490dd Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 12 Dec 2013 19:13:49 -0200 Subject: [PATCH 2581/5359] stop wp-cli execution when there are too many positional arguments --- features/validation.feature | 16 ++++++++++++++-- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/features/validation.feature b/features/validation.feature index ad1f89fef..9f30a30f7 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -17,14 +17,18 @@ Feature: Argument validation Given an empty directory And WP files - When I try `wp core config invalid` + When I try `wp core config` Then the return code should be 1 And STDERR should contain: """ Parameter errors: """ + And STDERR should contain: + """ + missing --dbname parameter + """ - When I try `wp core config invalid --invalid --other-invalid` + When I try `wp core config --invalid --other-invalid` Then the return code should be 1 And STDERR should contain: """ @@ -34,3 +38,11 @@ Feature: Argument validation """ unknown --other-invalid parameter """ + + When I try `wp core version invalid` + Then the return code should be 1 + And STDERR should contain: + """ + Error: Too many positional arguments: invalid + """ + And STDOUT should be empty \ No newline at end of file diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 0e4685ae4..89402b7b2 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -171,7 +171,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $unknown_positionals = $validator->unknown_positionals( $args ); if ( !empty( $unknown_positionals ) ) { - \WP_CLI::warning( 'Too many positional arguments: ' . + \WP_CLI::error( 'Too many positional arguments: ' . implode( ' ', $unknown_positionals ) ); } From 396c53abadba60a2e4d5860b47575ec62d49ae26 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 12 Dec 2013 19:52:21 -0200 Subject: [PATCH 2582/5359] add url subcommand to post, comment and site commands --- features/comment.feature | 6 ++++++ features/post.feature | 6 ++++++ features/site.feature | 20 +++++++++++++++++- php/WP_CLI/CommandWithDBObject.php | 5 +++++ php/WP_CLI/Fetchers/Site.php | 33 ++++++++++++++++++++++++++++++ php/commands/comment.php | 16 +++++++++++++++ php/commands/post.php | 16 +++++++++++++++ php/commands/site.php | 33 +++++++++++++++--------------- 8 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 php/WP_CLI/Fetchers/Site.php diff --git a/features/comment.feature b/features/comment.feature index 96b21e701..90f878383 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -45,3 +45,9 @@ Feature: Manage WordPress comments """ 1 """ + + When I run `wp comment url 1` + Then STDOUT should be: + """ + http://example.com/?p=1#comment-1 + """ \ No newline at end of file diff --git a/features/post.feature b/features/post.feature index d7d9588df..a4154e23b 100644 --- a/features/post.feature +++ b/features/post.feature @@ -92,6 +92,12 @@ Feature: Manage WordPress posts """ This is some bunkum. """ + + When I run `wp post url {POST_ID}` + Then STDOUT should be: + """ + http://example.com/?p=3 + """ Scenario: Creating/listing posts diff --git a/features/site.feature b/features/site.feature index bfbd49218..d40d99eb3 100644 --- a/features/site.feature +++ b/features/site.feature @@ -1,5 +1,14 @@ Feature: Manage sites in a multisite installation + Scenario: Create a site + Given a WP multisite install + + When I try `wp site create --slug=first --network_id=1000` + Then STDERR should contain: + """ + Network with id 1000 does not exist. + """ + Scenario: Delete a site by id Given a WP multisite install @@ -38,7 +47,7 @@ Feature: Manage sites in a multisite installation When I try the previous command again Then the return code should be 1 - Scenario: Empty a site + Scenario: Empty a site Given a WP install When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` @@ -55,3 +64,12 @@ Feature: Manage sites in a multisite installation When I run `wp term list post_tag --format=ids` Then STDOUT should be empty + + Scenario: Get site info + Given a WP multisite install + + When I run `wp site url 1` + Then STDOUT should be: + """ + http://example.com + """ \ No newline at end of file diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 7ea97c700..390d95811 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -82,5 +82,10 @@ protected function success_or_failure( $r ) { protected function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); } + + protected function _url( $args, $callback ) { + $object = $this->fetcher->get_check( $args[0] ); + \WP_CLI::print_value( $callback( $object->{$this->obj_id_key} ) ); + } } diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php new file mode 100644 index 000000000..d35eaa797 --- /dev/null +++ b/php/WP_CLI/Fetchers/Site.php @@ -0,0 +1,33 @@ +<?php + +namespace WP_CLI\Fetchers; + +class Site extends Base { + + protected $msg = "Could not find the site with ID %d."; + + public function get( $site_id ) { + return $this->_get_site( $site_id ); + } + + /** + * Get site (network) data for a given id. + * + * @param int $site_id + * @return bool|array False if no network found with given id, array otherwise + */ + private function _get_site( $site_id ) { + global $wpdb; + + // Load site data + $sites = $wpdb->get_results( $wpdb->prepare( + "SELECT * FROM $wpdb->site WHERE id = %d", $site_id ) ); + + if ( !empty( $sites ) ) { + // Only care about domain and path which are set here + return $sites[0]; + } + + return false; + } +} \ No newline at end of file diff --git a/php/commands/comment.php b/php/commands/comment.php index 6a45b839c..5fbe0e4a9 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -369,6 +369,22 @@ public function exists( $args ) { WP_CLI::success( "Comment with ID $args[0] exists." ); } } + + /** + * Get comment url + * + * ## OPTIONS + * + * <id> + * : The ID of the comment to get the URL. + * + * ## EXAMPLES + * + * wp comment url 123 + */ + public function url( $args ) { + parent::_url( $args, 'get_comment_link' ); + } } WP_CLI::add_command( 'comment', 'Comment_Command' ); diff --git a/php/commands/post.php b/php/commands/post.php index d90bc93d6..57624f19c 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -355,6 +355,22 @@ public function generate( $args, $assoc_args ) { // @codingStandardsIgnoreEnd } + /** + * Get post url + * + * ## OPTIONS + * + * <id> + * : The ID of the post to get the URL. + * + * ## EXAMPLES + * + * wp post url 123 + */ + public function url( $args ) { + parent::_url( $args, 'get_permalink' ); + } + private function maybe_make_child() { // 50% chance of making child post return ( mt_rand(1, 2) == 1 ); diff --git a/php/commands/site.php b/php/commands/site.php index 111a91515..48f40b379 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -9,6 +9,10 @@ class Site_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'site'; + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\Site; + } + /** * Delete comments. */ @@ -217,7 +221,7 @@ public function create( $_, $assoc_args ) { // Site if ( !empty( $assoc_args['network_id'] ) ) { - $site = $this->_get_site( $assoc_args['network_id'] ); + $site = $this->fetcher->get( $assoc_args['network_id'] ); if ( $site === false ) { WP_CLI::error( sprintf( 'Network with id %d does not exist.', $assoc_args['network_id'] ) ); } @@ -364,24 +368,19 @@ function _list( $_, $assoc_args ) { } /** - * Get site (network) data for a given id. + * Get site url + * + * ## OPTIONS + * + * <id> + * : The ID of the site to get the URL. + * + * ## EXAMPLES * - * @param int $site_id - * @return bool|array False if no network found with given id, array otherwise + * wp site url 123 */ - private function _get_site( $site_id ) { - global $wpdb; - - // Load site data - $sites = $wpdb->get_results( $wpdb->prepare( - "SELECT * FROM $wpdb->site WHERE id = %d", $site_id ) ); - - if ( !empty( $sites ) ) { - // Only care about domain and path which are set here - return $sites[0]; - } - - return false; + public function url( $args ) { + parent::_url( $args, 'get_site_url' ); } } From 0668464556cdd6616d69d691c2b3bd3fab6d5846 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 12 Dec 2013 20:54:42 -0200 Subject: [PATCH 2583/5359] add new line at the end of file --- features/validation.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/validation.feature b/features/validation.feature index 9f30a30f7..a43178764 100644 --- a/features/validation.feature +++ b/features/validation.feature @@ -45,4 +45,4 @@ Feature: Argument validation """ Error: Too many positional arguments: invalid """ - And STDOUT should be empty \ No newline at end of file + And STDOUT should be empty From 9bd25a7a0a360d572039a7be092fb3852cc91731 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 13 Dec 2013 00:56:32 +0200 Subject: [PATCH 2584/5359] make 'wp import' accept multiple files also, remove unused support for different import formats --- php/commands/import.php | 97 +++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 61 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index 2a1b8e987..d0963b50a 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -7,8 +7,8 @@ class Import_Command extends WP_CLI_Command { * * ## OPTIONS * - * <file> - * : Path to a valid WXR file for importing. + * <file>... + * : Path to one or more valid WXR files for importing. * * --authors=<authors> * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. @@ -17,62 +17,46 @@ class Import_Command extends WP_CLI_Command { * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). */ public function __invoke( $args, $assoc_args ) { - list( $file ) = $args; - - if ( ! file_exists( $file ) ) - WP_CLI::error( "File to import doesn't exist." ); - $defaults = array( - 'type' => 'wxr', 'authors' => null, 'skip' => array(), ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); - $assoc_args['file'] = $file; - - if ( ! empty( $assoc_args['skip'] ) ) + if ( ! is_array( $assoc_args['skip'] ) ) { $assoc_args['skip'] = explode( ',', $assoc_args['skip'] ); + } - $importer = $this->is_importer_available( $assoc_args['type'] ); - if ( is_wp_error( $importer ) ) - WP_CLI::error( $importer->get_error_message() ); + $importer = $this->is_importer_available(); + if ( is_wp_error( $importer ) ) { + WP_CLI::error( $importer ); + } - $ret = $this->import( $assoc_args ); + $this->add_wxr_filters(); - if ( is_wp_error( $ret ) ) { - WP_CLI::error( $ret->get_error_message() ); - } else { - WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line - WP_CLI::success( "Import complete." ); - } - } + foreach ( $args as $file ) { + if ( ! is_readable( $file ) ) { + WP_CLI::warning( "Can't read $file file." ); + } - /** - * Import a file into WordPress. - */ - private function import( $args ) { + $ret = $this->import_wxr( $file, $assoc_args ); - switch( $args['type'] ) { - case 'wxr': - case 'wordpress': - $this->add_wxr_filters(); - $ret = $this->import_wxr( $args ); - break; - default: - $ret = new WP_Error( 'missing-import-type', "Import type doesn't exist." ); - break; + if ( is_wp_error( $ret ) ) { + WP_CLI::warning( $ret ); + } else { + WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line + WP_CLI::success( "Finished importing from $file file." ); + } } - return $ret; } /** * Import a WXR file */ - private function import_wxr( $args ) { + private function import_wxr( $file, $args ) { $wp_import = new WP_Import; - $import_data = $wp_import->parse( $args['file'] ); + $import_data = $wp_import->parse( $file ); if ( is_wp_error( $import_data ) ) return $import_data; @@ -125,11 +109,11 @@ private function import_wxr( $args ) { 'fetch_attachments' => $wp_import->fetch_attachments, ); - if( in_array( 'image_resize', $args['skip'] ) ) { + if ( in_array( 'image_resize', $args['skip'] ) ) { add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_set_image_sizes' ) ); } - $wp_import->import( $args['file'] ); + $wp_import->import( $file ); return true; } @@ -201,30 +185,21 @@ private function add_wxr_filters() { /** * Is the requested importer available? */ - private function is_importer_available( $importer ) { - + private function is_importer_available() { require_once ABSPATH . 'wp-admin/includes/plugin.php'; - switch ( $importer ) { - case 'wxr': - case 'wordpress': - if ( class_exists( 'WP_Import' ) ) { - $ret = true; - } else { - $plugins = get_plugins(); - $wordpress_importer = 'wordpress-importer/wordpress-importer.php'; - if ( array_key_exists( $wordpress_importer, $plugins ) ) - $error_msg = "WordPress Importer needs to be activated. Try 'wp plugin activate wordpress-importer'."; - else - $error_msg = "WordPress Importer needs to be installed. Try 'wp plugin install wordpress-importer --activate'."; - $ret = new WP_Error( 'importer-missing', $error_msg ); - } - break; - default: - $ret = new WP_Error( 'missing-import-type', "Import type doesn't exist." ); - break; + if ( class_exists( 'WP_Import' ) ) { + return true; } - return $ret; + + $plugins = get_plugins(); + $wordpress_importer = 'wordpress-importer/wordpress-importer.php'; + if ( array_key_exists( $wordpress_importer, $plugins ) ) + $error_msg = "WordPress Importer needs to be activated. Try 'wp plugin activate wordpress-importer'."; + else + $error_msg = "WordPress Importer needs to be installed. Try 'wp plugin install wordpress-importer --activate'."; + + return new WP_Error( 'importer-missing', $error_msg ); } /** From 5e60c38b07986455d41d7b5fc156575be3394fe7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 12 Dec 2013 20:57:54 -0200 Subject: [PATCH 2585/5359] add new line to the end of files --- features/comment.feature | 2 +- features/site.feature | 2 +- php/WP_CLI/Fetchers/Site.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 90f878383..00e197d45 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -50,4 +50,4 @@ Feature: Manage WordPress comments Then STDOUT should be: """ http://example.com/?p=1#comment-1 - """ \ No newline at end of file + """ diff --git a/features/site.feature b/features/site.feature index d40d99eb3..2c260f87e 100644 --- a/features/site.feature +++ b/features/site.feature @@ -72,4 +72,4 @@ Feature: Manage sites in a multisite installation Then STDOUT should be: """ http://example.com - """ \ No newline at end of file + """ diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php index d35eaa797..abb9791cc 100644 --- a/php/WP_CLI/Fetchers/Site.php +++ b/php/WP_CLI/Fetchers/Site.php @@ -30,4 +30,4 @@ private function _get_site( $site_id ) { return false; } -} \ No newline at end of file +} From 6195f60319634648b1c56620c6fe8080358956b9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 14 Dec 2013 02:44:55 +0200 Subject: [PATCH 2586/5359] run regex once, using the PCRE_MULTILINE modifier; see #878 --- php/WP_CLI/Runner.php | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e4e7910ad..dd5e5953f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -81,20 +81,15 @@ private static function set_wp_root( $config ) { $path = $config['path']; else $path .= '/' . $config['path']; - } else { - if ( file_exists( './index.php' ) ) { - $index_code = explode( "\n", file_get_contents( './index.php' ) ); - - foreach ( $index_code as $line ) { - if ( preg_match( '/^\s*require.+([\'"])(.*wp-blog-header\.php)\1/', $line, $matches ) ) { - $new_path = dirname( $matches[2] ); - if ( Utils\is_path_absolute( $new_path ) ) { - $path = $new_path; - } else { - $path .= '/' . $new_path; - } - break; - } + } elseif ( file_exists( './index.php' ) ) { + $index_code = file_get_contents( './index.php' ); + + if ( preg_match( '/^\s*require.+([\'"])(.*wp-blog-header\.php)\1/m', $index_code, $matches ) ) { + $new_path = dirname( $matches[2] ); + if ( Utils\is_path_absolute( $new_path ) ) { + $path = $new_path; + } else { + $path .= '/' . $new_path; } } } From 6d0c75e93aa4df7b3c7ff111ab96a716b84ab25a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 14 Dec 2013 03:42:42 +0200 Subject: [PATCH 2587/5359] add oxymel to Phar file --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 2d789e617..bda5002a3 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -38,6 +38,7 @@ function add_file( $phar, $path ) { ->in('./vendor/rmccue/requests') ->in('./vendor/composer') ->in('./vendor/symfony/finder') + ->in('./vendor/nb/oxymel') ->in('./vendor/rhumsaa/array_column') ->exclude('test') ->exclude('tests') From e5fa03a09ee00c6ab01fc700d7f4286a757262a1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 14 Dec 2013 04:07:43 +0200 Subject: [PATCH 2588/5359] add start log --- php/commands/import.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/import.php b/php/commands/import.php index d0963b50a..451db0e6a 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -34,6 +34,8 @@ public function __invoke( $args, $assoc_args ) { $this->add_wxr_filters(); + WP_CLI::log( 'Starting the import process...' ); + foreach ( $args as $file ) { if ( ! is_readable( $file ) ) { WP_CLI::warning( "Can't read $file file." ); From 50ec479bba0aed4fd2307d254f4041c1ba525574 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 16 Dec 2013 09:52:40 -0200 Subject: [PATCH 2589/5359] replace WP_CLI::print_value() with WP_CLI::line() --- php/WP_CLI/CommandWithDBObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 390d95811..b0e52438a 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -85,7 +85,7 @@ protected function get_formatter( &$assoc_args ) { protected function _url( $args, $callback ) { $object = $this->fetcher->get_check( $args[0] ); - \WP_CLI::print_value( $callback( $object->{$this->obj_id_key} ) ); + \WP_CLI::line( $callback( $object->{$this->obj_id_key} ) ); } } From 58ea052de3090dc5738ef933fde2120ac39fe64e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 17 Dec 2013 04:48:08 +0200 Subject: [PATCH 2590/5359] fix issues around plugin activation by setting $GLOBALS['pagenow'] to the expected value closes #917 --- php/WP_CLI/Runner.php | 4 ++++ php/wp-settings-cli.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index dd5e5953f..3cd76b388 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -498,6 +498,10 @@ public function before_wp_load() { define( 'WP_LOAD_IMPORTERS', true ); define( 'WP_IMPORTING', true ); } + + if ( $this->cmd_starts_with( array( 'plugin' ) ) ) { + $GLOBALS['pagenow'] = 'plugins.php'; + } } private static function fake_current_site_blog( $url_parts ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index c94479931..d43118d8d 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -198,7 +198,7 @@ wp_ssl_constants( ); // Create common globals. -require( ABSPATH . WPINC . '/vars.php' ); +// require( ABSPATH . WPINC . '/vars.php' ); // Make taxonomies and posts available to plugins and themes. // @plugin authors: warning: these get registered again on the init hook. From 4a81e021e907a4c1fd6dc01ac59a5ee761dc509d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 17 Dec 2013 10:59:14 -0200 Subject: [PATCH 2591/5359] Fix wrong example in 'wp comment list' documentation --- php/commands/comment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 6a45b839c..28652b8fa 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -133,7 +133,7 @@ public function get( $args, $assoc_args ) { * * wp comment list --post_id=2 * - * wp comment list --number=20 --comment_approved=1 + * wp comment list --number=20 --status=approve * * @subcommand list */ From 6337d1f861a7c9368413aa06af6e71415b679a9b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 17 Dec 2013 11:20:52 -0200 Subject: [PATCH 2592/5359] make url subcommand accept multiple ids --- features/post.feature | 5 +++-- php/WP_CLI/CommandWithDBObject.php | 7 ++++--- php/commands/comment.php | 4 ++-- php/commands/post.php | 6 ++++-- php/commands/site.php | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/features/post.feature b/features/post.feature index a4154e23b..df556cc7d 100644 --- a/features/post.feature +++ b/features/post.feature @@ -92,10 +92,11 @@ Feature: Manage WordPress posts """ This is some bunkum. """ - - When I run `wp post url {POST_ID}` + + When I run `wp post url 1 {POST_ID}` Then STDOUT should be: """ + http://example.com/?p=1 http://example.com/?p=3 """ diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index b0e52438a..de831bab6 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -84,8 +84,9 @@ protected function get_formatter( &$assoc_args ) { } protected function _url( $args, $callback ) { - $object = $this->fetcher->get_check( $args[0] ); - \WP_CLI::line( $callback( $object->{$this->obj_id_key} ) ); + foreach ( $args as $obj_id ) { + $object = $this->fetcher->get_check( $obj_id ); + \WP_CLI::line( $callback( $object->{$this->obj_id_key} ) ); + } } } - diff --git a/php/commands/comment.php b/php/commands/comment.php index 5fbe0e4a9..b642170dd 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -375,8 +375,8 @@ public function exists( $args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to get the URL. + * <id>... + * : One or more IDs of comments to get the URL. * * ## EXAMPLES * diff --git a/php/commands/post.php b/php/commands/post.php index 57624f19c..20c04f709 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -360,12 +360,14 @@ public function generate( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the post to get the URL. + * <id>... + * : One or more IDs of posts get the URL. * * ## EXAMPLES * * wp post url 123 + * + * wp post url 123 324 */ public function url( $args ) { parent::_url( $args, 'get_permalink' ); diff --git a/php/commands/site.php b/php/commands/site.php index 48f40b379..72f3ef3ea 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -372,8 +372,8 @@ function _list( $_, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the site to get the URL. + * <id>... + * : One or more IDs of sites to get the URL. * * ## EXAMPLES * From 4863063f98e0c4c02a627d05d35498a62612e9dc Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 17 Dec 2013 17:47:50 -0200 Subject: [PATCH 2593/5359] make 'wp comment delete' accept multiple IDs --- features/comment.feature | 9 +++++++++ php/commands/comment.php | 6 ++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 96b21e701..162c40c98 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -28,6 +28,15 @@ Feature: Manage WordPress comments """ Success: Deleted comment {COMMENT_ID}. """ + + When I run `wp comment create --comment_post_ID=1` + And I run `wp comment create --comment_post_ID=1` + And I run `wp comment delete 3 4` + Then STDOUT should be: + """ + Success: Deleted comment 3. + Success: Deleted comment 4. + """ Scenario: Get details about an existing comment When I run `wp comment get 1` diff --git a/php/commands/comment.php b/php/commands/comment.php index 6a45b839c..90df4bff0 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -158,8 +158,8 @@ public function _list( $_, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to delete. + * <id>... + * : One or more IDs of comments to delete. * * [--force] * : Skip the trash bin. @@ -167,6 +167,8 @@ public function _list( $_, $assoc_args ) { * ## EXAMPLES * * wp comment delete 1337 --force + * + * wp comment delete 1337 2341 --force */ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { From 621913fa254fcc335faa7c05f89ce6f3e7fda071 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 19 Dec 2013 10:02:46 -0200 Subject: [PATCH 2594/5359] Fix bug in wp site url --- features/site.feature | 11 ++++++++--- php/WP_CLI/Fetchers/Site.php | 12 ++++++------ php/commands/site.php | 38 ++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/features/site.feature b/features/site.feature index 2c260f87e..da4c2cb10 100644 --- a/features/site.feature +++ b/features/site.feature @@ -67,9 +67,14 @@ Feature: Manage sites in a multisite installation Scenario: Get site info Given a WP multisite install - - When I run `wp site url 1` + + When I run `wp site create --slug=first --porcelain` + Then STDOUT should be a number + And save STDOUT as {SITE_ID} + + When I run `wp site url {SITE_ID}` Then STDOUT should be: """ - http://example.com + http://example.com/first """ + diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php index abb9791cc..1eaca959e 100644 --- a/php/WP_CLI/Fetchers/Site.php +++ b/php/WP_CLI/Fetchers/Site.php @@ -11,21 +11,21 @@ public function get( $site_id ) { } /** - * Get site (network) data for a given id. + * Get site (blog) data for a given id. * * @param int $site_id - * @return bool|array False if no network found with given id, array otherwise + * @return bool|array False if no site found with given id, array otherwise */ private function _get_site( $site_id ) { global $wpdb; // Load site data - $sites = $wpdb->get_results( $wpdb->prepare( - "SELECT * FROM $wpdb->site WHERE id = %d", $site_id ) ); + $site = $wpdb->get_row( $wpdb->prepare( + "SELECT * FROM $wpdb->blogs WHERE blog_id = %d", $site_id ) ); - if ( !empty( $sites ) ) { + if ( !empty( $site ) ) { // Only care about domain and path which are set here - return $sites[0]; + return $site; } return false; diff --git a/php/commands/site.php b/php/commands/site.php index 72f3ef3ea..79eb8d924 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -8,6 +8,7 @@ class Site_Command extends \WP_CLI\CommandWithDBObject { protected $obj_type = 'site'; + protected $obj_id_key = 'blog_id'; public function __construct() { $this->fetcher = new \WP_CLI\Fetchers\Site; @@ -219,15 +220,15 @@ public function create( $_, $assoc_args ) { $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; - // Site + // Network if ( !empty( $assoc_args['network_id'] ) ) { - $site = $this->fetcher->get( $assoc_args['network_id'] ); - if ( $site === false ) { + $network = $this->_get_network( $assoc_args['network_id'] ); + if ( $network === false ) { WP_CLI::error( sprintf( 'Network with id %d does not exist.', $assoc_args['network_id'] ) ); } } else { - $site = wpmu_current_site(); + $network = wpmu_current_site(); } $public = !isset( $assoc_args['private'] ); @@ -264,12 +265,12 @@ public function create( $_, $assoc_args ) { if ( is_subdomain_install() ) { $path = '/'; - $url = $newdomain = $base.'.'.preg_replace( '|^www\.|', '', $site->domain ); + $url = $newdomain = $base.'.'.preg_replace( '|^www\.|', '', $network->domain ); } else { - $newdomain = $site->domain; + $newdomain = $network->domain; $path = '/' . trim( $base, '/' ) . '/'; - $url = $site->domain . $path; + $url = $network->domain . $path; } $user_id = email_exists( $email ); @@ -285,7 +286,7 @@ public function create( $_, $assoc_args ) { } $wpdb->hide_errors(); - $id = wpmu_create_blog( $newdomain, $path, $title, $user_id, array( 'public' => $public ), $site->id ); + $id = wpmu_create_blog( $newdomain, $path, $title, $user_id, array( 'public' => $public ), $network->id ); $wpdb->show_errors(); if ( !is_wp_error( $id ) ) { if ( !is_super_admin( $user_id ) && !get_user_option( 'primary_blog', $user_id ) ) { @@ -306,6 +307,27 @@ public function create( $_, $assoc_args ) { WP_CLI::success( "Site $id created: $url" ); } + /** + * Get network data for a given id. + * + * @param int $network_id + * @return bool|array False if no network found with given id, array otherwise + */ + private function _get_network( $network_id ) { + global $wpdb; + + // Load network data + $networks = $wpdb->get_results( $wpdb->prepare( + "SELECT * FROM $wpdb->site WHERE id = %d", $network_id ) ); + + if ( !empty( $networks ) ) { + // Only care about domain and path which are set here + return $networks[0]; + } + + return false; + } + /** * List all sites in a multisite install. * From 8871c7dc7a12f6022a6a22767f99f00fa1cf7c4d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 19 Dec 2013 17:30:11 +0200 Subject: [PATCH 2595/5359] doc improvements for 'wp core config' --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d4c4957c8..9faf236b6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -173,7 +173,7 @@ private static function get_initial_locale() { } /** - * Set up a wp-config.php file. + * Generate a wp-config.php file. * * ## OPTIONS * @@ -205,7 +205,7 @@ private static function get_initial_locale() { * : If set, the command reads additional PHP code from STDIN. * * [--skip-salts] - * : If set, keys and salts won't be generated, but, instead, should be passed via --extra-php. + * : If set, keys and salts won't be generated, but should instead be passed via `--extra-php`. * * ## EXAMPLES * From c6283fe371fe35e36a2803642c0fb317652c0b5c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 20 Dec 2013 02:33:47 +0200 Subject: [PATCH 2596/5359] core multisite-install: stop creating blogs.dir; it's deprecated see http://core.trac.wordpress.org/ticket/19235 closes #927 --- php/commands/core.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9faf236b6..d01e2067b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -519,8 +519,6 @@ private function _multisite_convert( $assoc_args ) { WP_CLI::log( 'Added multisite constants to wp-config.php.' ); } - wp_mkdir_p( WP_CONTENT_DIR . '/blogs.dir' ); - return true; } From 2e5a1b628d5c5e37694dab71ea1cb6290a6e9612 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 20 Dec 2013 08:38:48 -0200 Subject: [PATCH 2597/5359] exit with an error when 'wp site url' is called on a non-multisite install --- features/site.feature | 6 ++++++ php/commands/site.php | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/features/site.feature b/features/site.feature index da4c2cb10..26f767841 100644 --- a/features/site.feature +++ b/features/site.feature @@ -50,6 +50,12 @@ Feature: Manage sites in a multisite installation Scenario: Empty a site Given a WP install + When I try `wp site url 1` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ + When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` Then STDOUT should not be empty diff --git a/php/commands/site.php b/php/commands/site.php index 79eb8d924..14ef18648 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -402,6 +402,10 @@ function _list( $_, $assoc_args ) { * wp site url 123 */ public function url( $args ) { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + parent::_url( $args, 'get_site_url' ); } } From 80f264392bb223a9e24e6ea665ed84b563e07b0e Mon Sep 17 00:00:00 2001 From: Simon Wheatley <simonw@codeforthepeople.com> Date: Fri, 20 Dec 2013 10:53:49 +0000 Subject: [PATCH 2598/5359] Add better docs around authors mapping CSV. --- php/commands/import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index 451db0e6a..36d2c46cf 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -11,7 +11,7 @@ class Import_Command extends WP_CLI_Command { * : Path to one or more valid WXR files for importing. * * --authors=<authors> - * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The last option will skip any author mapping. + * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The CSV requires two columns, and a header row like "old_user_login,new_user_login". The last option will skip any author mapping. * * [--skip=<data-type>] * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). From d775c111b30808179cbaf88a40e13788f7853824 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 21 Dec 2013 01:59:49 +0200 Subject: [PATCH 2599/5359] let the user know that --user_login= doesn't work see #926 --- php/commands/user.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 9e02172f8..ddee96e2a 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -240,13 +240,15 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user update 123 --user_login=mary --display_name=Mary - * - * wp user update mary --user_pass=marypass + * wp user update 123 --display_name=Mary --user_pass=marypass */ public function update( $args, $assoc_args ) { - $user_ids = array(); + if ( isset( $assoc_args['user_login'] ) ) { + WP_CLI::warning( "User logins can't be changed." ); + unset( $assoc_args['user_login'] ); + } + $user_ids = array(); foreach ( $this->fetcher->get_many( $args ) as $user ) { $user_ids[] = $user->ID; } From e062b9a070bc73f85b9df30c0cbb7f11de76545a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 23 Dec 2013 17:18:52 +0200 Subject: [PATCH 2600/5359] media regenerate: add seq example --- php/commands/media.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index eb5e4e938..97393e41b 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -20,9 +20,11 @@ class Media_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp media regenerate 123 1337 - * + * # re-generate all thumbnails, without confirmation * wp media regenerate --yes + * + * # re-generate all thumbnails that have IDs between 1000 and 2000 + * seq 1000 2000 | xargs wp media regenerate */ function regenerate( $args, $assoc_args = array() ) { global $wpdb; From e84a830a71433ff5a46723d648d6f844919d9189 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 23 Dec 2013 17:24:10 +0200 Subject: [PATCH 2601/5359] don't list all invalid attachment IDs it gets too long when using `seq` --- php/commands/media.php | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 97393e41b..6faff8edf 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -44,19 +44,15 @@ function regenerate( $args, $assoc_args = array() ) { $images = new WP_Query( $query_args ); - if ( $images->post_count == 0 ) { - //No images, so all keys in $args are not found within WP - WP_CLI::error( $this->_not_found_message( $args ) ); - } $count = $images->post_count; - WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); - - $not_found = array_diff( $args, $images->posts ); - if( !empty($not_found) ) { - WP_CLI::warning( $this->_not_found_message( $not_found ) ); + if ( !$count ) { + WP_CLI::log( 'No images found.' ); + return; } + WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); + foreach ( $images->posts as $id ) { $this->_process_regeneration( $id ); } @@ -244,17 +240,6 @@ private function remove_old_images( $att_id ) { unlink( $intermediate_path ); } } - - private function _not_found_message( $not_found_ids ){ - $count = count( $not_found_ids ); - - return vsprintf( 'Unable to find the %1$s (%2$s). Are you sure %3$s %4$s?', array( - ngettext('image', 'images', $count), - implode(", ", $not_found_ids), - ngettext('it', 'they', $count), - ngettext('exists', 'exist', $count), - ) ); - } } WP_CLI::add_command( 'media', 'Media_Command' ); From 5a7d75ead72ee06a93f04f2b4b52e18a6c09ee7f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 23 Dec 2013 17:52:12 +0200 Subject: [PATCH 2602/5359] make 'No images found' message a warning --- features/media.feature | 2 +- php/commands/media.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/media.feature b/features/media.feature index 81a1d5bf1..0dca83a0c 100644 --- a/features/media.feature +++ b/features/media.feature @@ -7,7 +7,7 @@ Feature: Manage WordPress attachments When I try `wp media regenerate --yes` Then STDERR should contain: """ - Error: Unable to find the images + No images found. """ Scenario: Import image from remote URL diff --git a/php/commands/media.php b/php/commands/media.php index 6faff8edf..5f57f5d9a 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -47,11 +47,12 @@ function regenerate( $args, $assoc_args = array() ) { $count = $images->post_count; if ( !$count ) { - WP_CLI::log( 'No images found.' ); + WP_CLI::warning( 'No images found.' ); return; } - WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, ngettext('image', 'images', $count) ) ); + WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, + ngettext( 'image', 'images', $count ) ) ); foreach ( $images->posts as $id ) { $this->_process_regeneration( $id ); From 496d07b36223734f16121760eb22e0589e4a5351 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 25 Dec 2013 19:13:50 +0200 Subject: [PATCH 2603/5359] introduce is_windows() helper --- php/commands/help.php | 2 +- php/utils.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index d722a9205..46cf470b3 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -76,7 +76,7 @@ private static function indent( $whitespace, $text ) { } private static function pass_through_pager( $out ) { - if ( strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ) { + if ( Utils\is_windows() ) { // no paging for Windows cmd.exe; sorry echo $out; return 0; diff --git a/php/utils.php b/php/utils.php index 1972c2505..a281bd167 100644 --- a/php/utils.php +++ b/php/utils.php @@ -375,3 +375,10 @@ function parse_url( $url ) { return $url_parts; } +/** + * Check if we're running in a Windows environment (cmd.exe). + */ +function is_windows() { + return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; +} + From e51666bf210ac5b7881161e7445aa16ea3dc0013 Mon Sep 17 00:00:00 2001 From: eliorivero <eliorivero@gmail.com> Date: Wed, 25 Dec 2013 17:32:27 -0300 Subject: [PATCH 2604/5359] Fix wp plugin delete on Windows --- php/commands/plugin.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index d0e802f59..6a66483f8 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -568,9 +568,16 @@ private function _delete( $plugin ) { if ( '.' == $plugin_dir ) $plugin_dir = $plugin->file; - $command = 'rm -rf ' . path_join( WP_PLUGIN_DIR, $plugin_dir ); + $path = path_join( WP_PLUGIN_DIR, $plugin_dir ); - return ! WP_CLI::launch( $command ); + if ( \WP_CLI\Utils\is_windows() ) { + $command = 'rd /s /q '; + $path = str_replace( "/", "\\", $path ); + } else { + $command = 'rm -rf '; + } + + return ! WP_CLI::launch( $command . $path ); } } From 87c4801895cd21d7b2a2c5f12ee7a2b5632ecebf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 26 Dec 2013 12:26:51 -0800 Subject: [PATCH 2605/5359] Perform `is_numeric()` checks before `is_email()`, as the former will be faster. --- php/WP_CLI/Fetchers/User.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Fetchers/User.php b/php/WP_CLI/Fetchers/User.php index 122dfd0fc..65e2f9c0f 100644 --- a/php/WP_CLI/Fetchers/User.php +++ b/php/WP_CLI/Fetchers/User.php @@ -8,10 +8,10 @@ class User extends Base { public function get( $id_email_or_login ) { - if ( is_email( $id_email_or_login ) ) - $user = get_user_by( 'email', $id_email_or_login ); - else if ( is_numeric( $id_email_or_login ) ) + if ( is_numeric( $id_email_or_login ) ) $user = get_user_by( 'id', $id_email_or_login ); + else if ( is_email( $id_email_or_login ) ) + $user = get_user_by( 'email', $id_email_or_login ); else $user = get_user_by( 'login', $id_email_or_login ); From e9a09d30938d1d87b8fcc21e82445588389ff02f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 26 Dec 2013 12:32:28 -0800 Subject: [PATCH 2606/5359] Support for using a user's email address in the `--user` flag. --- features/flags.feature | 6 ++++++ php/WP_CLI/Runner.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index 9d1dcc93e..86baa3458 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -58,6 +58,12 @@ Feature: Global flags admin """ + When I run `wp --user=admin@example.com eval 'echo wp_get_current_user()->user_login;'` + Then STDOUT should be: + """ + admin + """ + When I try `wp --user=non-existing-user eval 'echo wp_get_current_user()->user_login;'` Then the return code should be 1 And STDERR should be: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 65c376a43..7c9151b81 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -96,6 +96,9 @@ private static function set_user( $assoc_args ) { if ( is_numeric( $user ) ) { $user_id = (int) $user; + } else if ( is_email( $user ) ) { + $user_obj = get_user_by( 'email', $user ); + $user_id = ( $user_obj ) ? $user_obj->ID : 0; } else { $user_id = (int) username_exists( $user ); } From 37025efeab97e9529d66edfaedadca21d335f7c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 26 Dec 2013 12:33:59 -0800 Subject: [PATCH 2607/5359] Apparently this helper function exists --- php/WP_CLI/Runner.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7c9151b81..3a00dd31f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -97,8 +97,7 @@ private static function set_user( $assoc_args ) { if ( is_numeric( $user ) ) { $user_id = (int) $user; } else if ( is_email( $user ) ) { - $user_obj = get_user_by( 'email', $user ); - $user_id = ( $user_obj ) ? $user_obj->ID : 0; + $user_id = email_exists( $user ); } else { $user_id = (int) username_exists( $user ); } From 1b04e06fca552b7f400cec7a361da79f0805e2dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 26 Dec 2013 12:45:58 -0800 Subject: [PATCH 2608/5359] Use the fetcher instead --- features/flags.feature | 2 +- php/WP_CLI/Runner.php | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index 86baa3458..3bd8dfa69 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -68,7 +68,7 @@ Feature: Global flags Then the return code should be 1 And STDERR should be: """ - Error: Could not find user: non-existing-user + Error: Invalid user ID, email or login: 'non-existing-user' """ Scenario: Using a custom logger diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3a00dd31f..312c3ac11 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -92,19 +92,10 @@ private static function set_user( $assoc_args ) { if ( !isset( $assoc_args['user'] ) ) return; - $user = $assoc_args['user']; + $fetcher = new \WP_CLI\Fetchers\User; + $user = $fetcher->get_check( $assoc_args['user'] ); + wp_set_current_user( $user->ID ); - if ( is_numeric( $user ) ) { - $user_id = (int) $user; - } else if ( is_email( $user ) ) { - $user_id = email_exists( $user ); - } else { - $user_id = (int) username_exists( $user ); - } - - if ( !$user_id || !wp_set_current_user( $user_id ) ) { - \WP_CLI::error( "Could not find user: $user" ); - } } private static function guess_url( $assoc_args ) { From e8704a743469ce2d88f648ef780167305d2da261 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 26 Dec 2013 22:54:48 +0200 Subject: [PATCH 2609/5359] fix default for WP_VERSION; see #679 --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 782dec87e..1e39064a5 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -9,7 +9,7 @@ DB_NAME=$1 DB_USER=$2 DB_PASS=$3 DB_HOST=${4-localhost} -WP_VERSION=${5-master} +WP_VERSION=${5-latest} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=/tmp/wordpress/ From 264050706d1988875ab9abe867ca09845f935def Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Fri, 27 Dec 2013 12:33:25 -0500 Subject: [PATCH 2610/5359] Adding theme enable/disable commands for multisite installs. Closes #918. These commands allow the user to enable or disable themes for a site in a multisite network, or network enable/disable themes. --- php/commands/theme.php | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 7975acb86..40ef18552 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -129,6 +129,92 @@ public function activate( $args = array() ) { } } + /** + * Enable a theme. + * + * ## OPTIONS + * + * <theme> + * : The theme to enable. + * + * [--network] + * : If set, the theme is enabled for the entire network + * + * [--activate] + * : If set, the theme is activated for the current site. Note that + * the "network" flag has no influence on this. + * + * ## EXAMPLES + * + * wp theme enable twentythirteen + * + * wp theme enable twentythirteen --network + * + * wp theme enable twentythirteen --activate + */ + public function enable( $args, $assoc_args ) { + $theme = $this->fetcher->get_check( $args[0] ); + $name = $theme->get( 'Name' ); + + # If the --network flag is set, we'll be calling the (get|update)_site_option functions + $_site = ! empty( $assoc_args['network'] ) ? '_site' : ''; + + # Add the current theme to the allowed themes option or site option + $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); + if ( empty( $allowed_themes ) ) + $allowed_themes = array(); + $allowed_themes[ $theme->get_template() ] = true; + call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); + + if ( ! empty( $assoc_args['network'] ) ) + WP_CLI::success( "Network enabled the '$name' theme." ); + else + WP_CLI::success( "Enabled the '$name' theme." ); + + # If the --activate flag is set, activate the theme for the current site + if ( ! empty( $assoc_args['activate'] ) ) { + $this->activate( $args ); + } + } + + /** + * Disable a theme. + * + * ## OPTIONS + * + * <theme> + * : The theme to disable. + * + * [--network] + * : If set, the theme is disabled on the network level. Note that + * individual sites may still have this theme enabled if it was + * enabled for them independently. + * + * ## EXAMPLES + * + * wp theme disable twentythirteen + * + * wp theme disable twentythirteen --network + */ + public function disable( $args, $assoc_args ) { + $theme = $this->fetcher->get_check( $args[0] ); + $name = $theme->get( 'Name' ); + + # If the --network flag is set, we'll be calling the (get|update)_site_option functions + $_site = ! empty( $assoc_args['network'] ) ? '_site' : ''; + + # Add the current theme to the allowed themes option or site option + $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); + if ( ! empty( $allowed_themes[ $theme->get_template() ] ) ) + unset( $allowed_themes[ $theme->get_template() ] ); + call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); + + if ( ! empty( $assoc_args['network'] ) ) + WP_CLI::success( "Network disabled the '$name' theme." ); + else + WP_CLI::success( "Disabled the '$name' theme." ); + } + private function is_active_theme( $theme ) { return $theme->get_stylesheet_directory() == get_stylesheet_directory(); } From 89162a1c82c41ef65635f0ed13faee3c3276448a Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Fri, 27 Dec 2013 15:41:44 -0500 Subject: [PATCH 2611/5359] Ensuring that theme enable/disable commands are only ever run on multisite installs --- php/commands/theme.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 40ef18552..61c42f87b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -153,6 +153,10 @@ public function activate( $args = array() ) { * wp theme enable twentythirteen --activate */ public function enable( $args, $assoc_args ) { + if ( ! is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + $theme = $this->fetcher->get_check( $args[0] ); $name = $theme->get( 'Name' ); @@ -197,6 +201,10 @@ public function enable( $args, $assoc_args ) { * wp theme disable twentythirteen --network */ public function disable( $args, $assoc_args ) { + if ( ! is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + $theme = $this->fetcher->get_check( $args[0] ); $name = $theme->get( 'Name' ); From 5fac5102747ded46bbc93dc62f748178585078fb Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Fri, 27 Dec 2013 15:42:24 -0500 Subject: [PATCH 2612/5359] Adding feature tests for `theme enable` and `theme disable` --- features/theme.feature | 59 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index f14a82003..24c4237df 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -1,9 +1,8 @@ Feature: Manage WordPress themes - Background: + Scenario: Installing and deleting theme Given a WP install - Scenario: Installing and deleting theme When I run `wp theme install p2` Then STDOUT should not be empty @@ -52,6 +51,8 @@ Feature: Manage WordPress themes Then STDOUT should not be empty Scenario: Install a theme, activate, then force install an older version of the theme + Given a WP install + When I run `wp theme install p2 --version=1.4.2` Then STDOUT should not be empty @@ -72,6 +73,8 @@ Feature: Manage WordPress themes | p2 | active | available | 1.4.1 | Scenario: Get the path of an installed theme + Given a WP install + When I run `wp theme install p2` Then STDOUT should not be empty @@ -80,3 +83,55 @@ Feature: Manage WordPress themes """ wp-content/themes/p2 """ + + Scenario: Enabling and disabling a theme + Given a WP multisite install + + When I run `wp theme install p2` + Then STDOUT should not be empty + + When I run `wp theme enable p2` + Then STDOUT should contain: + """ + Success: Enabled the 'P2' theme. + """ + + When I run `wp theme disable p2` + Then STDOUT should contain: + """ + Success: Disabled the 'P2' theme. + """ + + When I run `wp theme enable p2 --activate` + Then STDOUT should contain: + """ + Success: Enabled the 'P2' theme. + Success: Switched to 'P2' theme. + """ + + When I run `wp theme enable p2 --network` + Then STDOUT should contain: + """ + Success: Network enabled the 'P2' theme. + """ + + When I run `wp theme disable p2 --network` + Then STDOUT should contain: + """ + Success: Network disabled the 'P2' theme. + """ + + Scenario: Enabling and disabling a theme without multisite + Given a WP install + + When I try `wp theme enable p2` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ + + When I try `wp theme disable p2` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ From d6bfb7261953d4bcbcda5c10879eb22f9caa0f6e Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Sat, 28 Dec 2013 00:47:20 -0500 Subject: [PATCH 2613/5359] Testing that themes are actually being en/disabled --- features/theme.feature | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 24c4237df..98153957f 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -90,18 +90,34 @@ Feature: Manage WordPress themes When I run `wp theme install p2` Then STDOUT should not be empty + When I try `wp option get allowedthemes` + Then the return code should be 1 + And STDERR should be empty + When I run `wp theme enable p2` Then STDOUT should contain: """ Success: Enabled the 'P2' theme. """ + When I run `wp option get allowedthemes` + Then STDOUT should contain: + """ + 'p2' => true + """ + When I run `wp theme disable p2` Then STDOUT should contain: """ Success: Disabled the 'P2' theme. """ + When I run `wp option get allowedthemes` + Then STDOUT should not contain: + """ + 'p2' => true + """ + When I run `wp theme enable p2 --activate` Then STDOUT should contain: """ @@ -109,18 +125,36 @@ Feature: Manage WordPress themes Success: Switched to 'P2' theme. """ + When I run `wp network-meta get 1 allowedthemes` + Then STDOUT should not contain: + """ + 'p2' => true + """ + When I run `wp theme enable p2 --network` Then STDOUT should contain: """ Success: Network enabled the 'P2' theme. """ + When I run `wp network-meta get 1 allowedthemes` + Then STDOUT should contain: + """ + 'p2' => true + """ + When I run `wp theme disable p2 --network` Then STDOUT should contain: """ Success: Network disabled the 'P2' theme. """ + When I run `wp network-meta get 1 allowedthemes` + Then STDOUT should not contain: + """ + 'p2' => true + """ + Scenario: Enabling and disabling a theme without multisite Given a WP install From 2054bf0e5b4606934a12205dd7ab8b7b3c1c76f1 Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Sat, 28 Dec 2013 01:28:54 -0500 Subject: [PATCH 2614/5359] Adding site and network enabled columns to wp theme list --- php/commands/theme.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 7975acb86..2d4128014 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -19,6 +19,10 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { ); function __construct() { + if ( is_multisite() ) { + $this->obj_fields[] = 'site_enabled'; + $this->obj_fields[] = 'network_enabled'; + } parent::__construct(); $this->fetcher = new \WP_CLI\Fetchers\Theme; @@ -193,6 +197,16 @@ protected function install_from_repo( $slug, $assoc_args ) { protected function get_item_list() { $items = array(); + if ( is_multisite() ) { + $site_enabled = get_option( 'allowedthemes' ); + if ( empty( $site_enabled ) ) + $site_enabled = array(); + + $network_enabled = get_site_option( 'allowedthemes' ); + if ( empty( $network_enabled ) ) + $network_enabled = array(); + } + foreach ( wp_get_themes() as $key => $theme ) { $file = $theme->get_stylesheet_directory(); $update_info = $this->get_update_info( $theme->get_stylesheet() ); @@ -206,6 +220,11 @@ protected function get_item_list() { 'version' => $theme->get('Version'), 'update_id' => $theme->get_stylesheet(), ); + + if ( is_multisite() ) { + $items[ $file ]['site_enabled'] = ! empty( $site_enabled[ $key ] ) ? 'enabled' : 'disabled'; + $items[ $file ]['network_enabled'] = ! empty( $network_enabled[ $key ] ) ? 'enabled' : 'disabled'; + } } return $items; From d801aca947726330c797f826e32b04c8cc9bdb6b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 28 Dec 2013 08:42:27 +0200 Subject: [PATCH 2615/5359] clarify description for theme 'enable' and 'disable' subcommands see #938 --- php/commands/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 61c42f87b..cac57cd44 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -130,7 +130,7 @@ public function activate( $args = array() ) { } /** - * Enable a theme. + * Enable a theme in a multisite install. * * ## OPTIONS * @@ -182,7 +182,7 @@ public function enable( $args, $assoc_args ) { } /** - * Disable a theme. + * Disable a theme in a multisite install. * * ## OPTIONS * From a7a72433e25ed3fa46569ab6fa2851443583b86a Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Sat, 28 Dec 2013 02:21:00 -0500 Subject: [PATCH 2616/5359] Merging the network and site enabled columns for `wp theme list` --- php/commands/theme.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 2d4128014..9f1c6efeb 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -20,8 +20,7 @@ class Theme_Command extends \WP_CLI\CommandWithUpgrade { function __construct() { if ( is_multisite() ) { - $this->obj_fields[] = 'site_enabled'; - $this->obj_fields[] = 'network_enabled'; + $this->obj_fields[] = 'enabled'; } parent::__construct(); @@ -222,8 +221,14 @@ protected function get_item_list() { ); if ( is_multisite() ) { - $items[ $file ]['site_enabled'] = ! empty( $site_enabled[ $key ] ) ? 'enabled' : 'disabled'; - $items[ $file ]['network_enabled'] = ! empty( $network_enabled[ $key ] ) ? 'enabled' : 'disabled'; + if ( ! empty( $site_enabled[ $key ] ) && ! empty( $network_enabled[ $key ] ) ) + $items[ $file ]['enabled'] = 'network,site'; + elseif ( ! empty( $network_enabled[ $key ] ) ) + $items[ $file ]['enabled'] = 'network'; + elseif ( ! empty( $site_enabled[ $key ] ) ) + $items[ $file ]['enabled'] = 'site'; + else + $items[ $file ]['enabled'] = 'no'; } } From 263390f25c3c0386c3371ec78e8cbf027bb6e2a8 Mon Sep 17 00:00:00 2001 From: Mike Burns <mgburns@bu.edu> Date: Fri, 3 Jan 2014 15:29:05 -0500 Subject: [PATCH 2617/5359] Store post ids during `wp post generate`. Fixes --max_depth which was broken in fe2be3169b. Closes #820. --- php/commands/post.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 3f9326837..3d57cf2de 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -316,6 +316,7 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); + $post_ids = array(); $current_depth = 1; $current_parent = 0; @@ -347,7 +348,7 @@ public function generate( $args, $assoc_args ) { 'post_content' => $post_content, ); - wp_insert_post( $args, true ); + $post_ids[$i] = wp_insert_post( $args, true ); $notify->tick(); } From 29454e3b568a1d9d21e0487ab88579fde94d3b36 Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Sat, 4 Jan 2014 00:57:36 -0800 Subject: [PATCH 2618/5359] Add a --recurse-objects flag Including --recurse-objects enables recursive find/replace into objects. This change also detects cycles in objects and arrays. If a cycle is detected, or the XDebug max nesting level is reached, the function stops recursing --- php/commands/search-replace.php | 62 ++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 24f3d0f23..06fffd9d9 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -36,6 +36,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--dry-run] * : Show report, but don't perform the changes. * + * [--recurse-objects] + * : Enable recursing into objects to replace strings + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -48,6 +51,7 @@ public function __invoke( $args, $assoc_args ) { $total = 0; $report = array(); $dry_run = isset( $assoc_args['dry-run'] ); + $recurse_objects = isset( $assoc_args['recurse-objects'] ); if ( isset( $assoc_args['skip-columns'] ) ) $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -73,7 +77,7 @@ public function __invoke( $args, $assoc_args ) { if ( in_array( $col, $skip_columns ) ) continue; - $count = self::handle_col( $col, $primary_key, $table, $old, $new, $dry_run ); + $count = self::handle_col( $col, $primary_key, $table, $old, $new, $dry_run, $recurse_objects ); $report[] = array( $table, $col, $count ); @@ -101,7 +105,7 @@ private static function get_table_list( $args, $network ) { return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } - private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run ) { + private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run, $recurse_objects ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -123,7 +127,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry if ( '' === $row->$col ) continue; - $value = self::recursive_unserialize_replace( $old, $new, $row->$col ); + $value = self::recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects ); if ( $dry_run ) { if ( $value != $row->$col ) @@ -146,28 +150,60 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry * * Initial code from https://github.com/interconnectit/Search-Replace-DB * - * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with - * @param array $data Used to pass any subordinate arrays back to in. - * @param bool $serialised Does the array passed via $data need serialising. + * @param string $from String we're looking to replace. + * @param string $to What we want it to be replaced with + * @param array|string $data Used to pass any subordinate arrays back to in. + * @param bool $serialised Does the array passed via $data need serialising. + * @param bool $recurse_objects Should objects be recursively replaced. + * @param int $max_recursion How many levels to recurse into the data, if $recurse_objects is set to true. + * @param int $recursion_level Current recursion depth within the original data. + * @param array $visited_data Data that has been seen in previous recursion iterations. * - * @return array The original array with all elements replaced as needed. + * @return array The original array with all elements replaced as needed. */ - private static function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) { + private static function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { // some unseriliased data cannot be re-serialised eg. SimpleXMLElements try { + if ( $recurse_objects ) { + + // If no maximum recursion level is set, use the XDebug limit if it exists + if ( -1 == $max_recursion ) { + // Get the XDebug nesting level. Will be zero (no limit) if no value is set + $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); + } + + // If we've reached the maximum recursion level, short circuit + if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) { + WP_CLI::warning("Maximum recursion level of $max_recursion reached"); + return $data; + } + + if ( ( is_array( $data ) || is_object( $data ) ) ) { + // If we've seen this exact object or array before, short circuit + if ( in_array( $data, $visited_data, true ) ) { + return $data; // Avoid infinite loops when there's a cycle + } + // Add this data to the list of + $visited_data[] = $data; + } + } + if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { - $data = self::recursive_unserialize_replace( $from, $to, $unserialized, true ); + $data = self::recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 ); } elseif ( is_array( $data ) ) { - $_tmp = array(); foreach ( $data as $key => $value ) { - $_tmp[ $key ] = self::recursive_unserialize_replace( $from, $to, $value, false ); + $data[ $key ] = &self::recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); + } + } + + elseif ( $recurse_objects && is_object( $data ) ) { + foreach ( $data as $key => $value ) { + $data->$key = self::recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); } - $data = $_tmp; } else if ( is_string( $data ) ) { From b405e9d535de975fd61ec3c93203c9700791aab2 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Sat, 4 Jan 2014 23:59:18 +0000 Subject: [PATCH 2619/5359] Correct spelling of whether --- php/commands/transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 0691b5f05..11fc6c09d 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -62,7 +62,7 @@ public function delete( $args ) { } /** - * See wether the transients API is using an object cache or the options table. + * See whether the transients API is using an object cache or the options table. */ public function type() { global $_wp_using_ext_object_cache, $wpdb; From 33b3b00f3bafa7468923a972696d4833dcefdc36 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 18 Dec 2013 01:23:39 +0200 Subject: [PATCH 2620/5359] make `wp core is-installed` exit with 1 when run against a multisite install with no database --- features/core.feature | 3 +++ php/WP_CLI/Runner.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 59c78a4f5..5f41b24fc 100644 --- a/features/core.feature +++ b/features/core.feature @@ -195,6 +195,9 @@ Feature: Manage WordPress installation Given a WP multisite install And I run `wp db reset --yes` + When I try `wp core is-installed` + Then the return code should be 1 + When I run `wp core multisite-install --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then STDOUT should not be empty diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b7d39592e..9033d4c0c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -466,7 +466,7 @@ public function before_wp_load() { if ( count( $this->arguments ) >= 2 && $this->arguments[0] == 'core' && - in_array( $this->arguments[1], array( 'install', 'multisite-install' ) ) + in_array( $this->arguments[1], array( 'install', 'multisite-install', 'is-installed' ) ) ) { define( 'WP_INSTALLING', true ); From 6c02d63ad5b35eec3b4295647c4e65b570330b8d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 5 Jan 2014 08:19:32 +0200 Subject: [PATCH 2621/5359] fix `wp core is-installed` expectations for singlesite --- features/core.feature | 5 ----- php/WP_CLI/Runner.php | 6 +++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index 5f41b24fc..bf9fd8ddc 100644 --- a/features/core.feature +++ b/features/core.feature @@ -84,11 +84,6 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 - And STDERR should be: - """ - Error: The site you have requested is not installed. - Run `wp core install`. - """ When I try `wp core install` Then the return code should be 1 diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9033d4c0c..15729dc0c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -463,10 +463,14 @@ public function before_wp_load() { exit; } + if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) ) { + define( 'WP_INSTALLING', true ); + } + if ( count( $this->arguments ) >= 2 && $this->arguments[0] == 'core' && - in_array( $this->arguments[1], array( 'install', 'multisite-install', 'is-installed' ) ) + in_array( $this->arguments[1], array( 'install', 'multisite-install' ) ) ) { define( 'WP_INSTALLING', true ); From 6261a9a57d4f0b8106e1dd31518c5459059ec577 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 6 Jan 2014 12:46:35 +0200 Subject: [PATCH 2622/5359] site create: fix description for --title= parameter --- php/commands/site.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 14ef18648..cbd5ef2d2 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -191,7 +191,7 @@ function delete( $args, $assoc_args ) { * --slug=<slug> * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. * - * --title=<title> + * --title=<title> * : Title of the new site. Default: prettified slug. * * --email=<email> @@ -391,7 +391,7 @@ function _list( $_, $assoc_args ) { /** * Get site url - * + * * ## OPTIONS * * <id>... From 5286a18f5b5c62cb842d62d493c80f17fcf750a1 Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Wed, 8 Jan 2014 00:35:31 -0800 Subject: [PATCH 2623/5359] Update documentation header for recursive_unserialize_replace --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 06fffd9d9..b31904f58 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -146,7 +146,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry /** * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. - * Ignores any serialized objects. + * Ignores any serialized objects unless $recurse_objects is set to true. * * Initial code from https://github.com/interconnectit/Search-Replace-DB * From e41f4fa8aca9a6abbfa900f1a71570ac07fd55fe Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Wed, 8 Jan 2014 02:16:18 -0800 Subject: [PATCH 2624/5359] Update array handling for safer recursive replacements --- php/commands/search-replace.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b31904f58..61615ef7c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -161,7 +161,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry * * @return array The original array with all elements replaced as needed. */ - private static function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { + private static function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { // some unseriliased data cannot be re-serialised eg. SimpleXMLElements try { @@ -195,8 +195,9 @@ private static function recursive_unserialize_replace( $from = '', $to = '', $da } elseif ( is_array( $data ) ) { - foreach ( $data as $key => $value ) { - $data[ $key ] = &self::recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); + $keys = array_keys( $data ); + foreach ( $keys as $key ) { + $data[ $key ]= self::recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); } } From 7833662ef34eaaf95dc91be9df50ee6c91f3ce91 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 05:32:51 +0200 Subject: [PATCH 2625/5359] remove duplicated check --- features/config.feature | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/config.feature b/features/config.feature index 57f9e69f5..8720f451a 100644 --- a/features/config.feature +++ b/features/config.feature @@ -64,9 +64,6 @@ Feature: Have a config file When I run `wp core is-installed` Then STDOUT should be empty - When I run `wp core is-installed` - Then STDOUT should be empty - Scenario: Nested installs Given a WP install And a WP install in 'subsite' From 1d7af0dc18bbf9de097b86193e17ed39140d9c9a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 05:50:16 +0200 Subject: [PATCH 2626/5359] Don't look for WP files upward when running `wp core download`. If you run `wp core download` in an empty directory, getting an "Error: WordPress files seem to already be present here." message is quite confusing. see #955 --- features/core.feature | 6 +++++- php/WP_CLI/Runner.php | 11 +++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index bf9fd8ddc..30fea76ed 100644 --- a/features/core.feature +++ b/features/core.feature @@ -8,9 +8,13 @@ Feature: Manage WordPress installation Then the return code should be 1 And STDERR should not be empty - When I run `wp core download --quiet` + When I run `wp core download` Then the wp-settings.php file should exist + When I run `mkdir inner` + And I run `cd inner && wp core download` + Then the inner/wp-settings.php file should exist + @download Scenario: Localized install Given an empty directory diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 15729dc0c..57f000a25 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -394,10 +394,6 @@ private function init_config() { } list( $this->config, $this->extra_config ) = $configurator->to_array(); - - if ( !isset( $this->config['path'] ) ) { - $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); - } } public function before_wp_load() { @@ -430,6 +426,13 @@ public function before_wp_load() { } // Handle --path parameter + if ( !isset( $this->config['path'] ) ) { + if ( $this->cmd_starts_with( array( 'core', 'download' ) ) ) { + $this->config['path'] = getcwd(); + } else { + $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); + } + } self::set_wp_root( $this->config ); // First try at showing man page From aa7df69a971bf748fee167ba993ff1109bc07809 Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Fri, 10 Jan 2014 23:01:50 -0800 Subject: [PATCH 2627/5359] Move recursive search-replace function to Utils and add unit tests --- php/commands/search-replace.php | 80 +-------------------------------- php/utils.php | 78 ++++++++++++++++++++++++++++++++ tests/test-search-replace.php | 71 +++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 79 deletions(-) create mode 100644 tests/test-search-replace.php diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 61615ef7c..b8d219d34 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -127,7 +127,7 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry if ( '' === $row->$col ) continue; - $value = self::recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects ); + $value = WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects ); if ( $dry_run ) { if ( $value != $row->$col ) @@ -143,84 +143,6 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry return $count; } - /** - * Take a serialised array and unserialise it replacing elements as needed and - * unserialising any subordinate arrays and performing the replace on those too. - * Ignores any serialized objects unless $recurse_objects is set to true. - * - * Initial code from https://github.com/interconnectit/Search-Replace-DB - * - * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with - * @param array|string $data Used to pass any subordinate arrays back to in. - * @param bool $serialised Does the array passed via $data need serialising. - * @param bool $recurse_objects Should objects be recursively replaced. - * @param int $max_recursion How many levels to recurse into the data, if $recurse_objects is set to true. - * @param int $recursion_level Current recursion depth within the original data. - * @param array $visited_data Data that has been seen in previous recursion iterations. - * - * @return array The original array with all elements replaced as needed. - */ - private static function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { - - // some unseriliased data cannot be re-serialised eg. SimpleXMLElements - try { - - if ( $recurse_objects ) { - - // If no maximum recursion level is set, use the XDebug limit if it exists - if ( -1 == $max_recursion ) { - // Get the XDebug nesting level. Will be zero (no limit) if no value is set - $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); - } - - // If we've reached the maximum recursion level, short circuit - if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) { - WP_CLI::warning("Maximum recursion level of $max_recursion reached"); - return $data; - } - - if ( ( is_array( $data ) || is_object( $data ) ) ) { - // If we've seen this exact object or array before, short circuit - if ( in_array( $data, $visited_data, true ) ) { - return $data; // Avoid infinite loops when there's a cycle - } - // Add this data to the list of - $visited_data[] = $data; - } - } - - if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { - $data = self::recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 ); - } - - elseif ( is_array( $data ) ) { - $keys = array_keys( $data ); - foreach ( $keys as $key ) { - $data[ $key ]= self::recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); - } - } - - elseif ( $recurse_objects && is_object( $data ) ) { - foreach ( $data as $key => $value ) { - $data->$key = self::recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); - } - } - - else if ( is_string( $data ) ) { - $data = str_replace( $from, $to, $data ); - } - - if ( $serialised ) - return serialize( $data ); - - } catch( Exception $error ) { - - } - - return $data; - } - private static function get_columns( $table ) { global $wpdb; diff --git a/php/utils.php b/php/utils.php index 1972c2505..eba6a3901 100644 --- a/php/utils.php +++ b/php/utils.php @@ -375,3 +375,81 @@ function parse_url( $url ) { return $url_parts; } + +/** + * Take a serialised array and unserialise it replacing elements as needed and + * unserialising any subordinate arrays and performing the replace on those too. + * Ignores any serialized objects unless $recurse_objects is set to true. + * + * Initial code from https://github.com/interconnectit/Search-Replace-DB + * + * @param string $from String we're looking to replace. + * @param string $to What we want it to be replaced with + * @param array|string $data Used to pass any subordinate arrays back to in. + * @param bool $serialised Does the array passed via $data need serialising. + * @param bool $recurse_objects Should objects be recursively replaced. + * @param int $max_recursion How many levels to recurse into the data, if $recurse_objects is set to true. + * @param int $recursion_level Current recursion depth within the original data. + * @param array $visited_data Data that has been seen in previous recursion iterations. + * + * @return array The original array with all elements replaced as needed. + */ +function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { + + // some unseriliased data cannot be re-serialised eg. SimpleXMLElements + try { + + if ( $recurse_objects ) { + + // If no maximum recursion level is set, use the XDebug limit if it exists + if ( -1 == $max_recursion ) { + // Get the XDebug nesting level. Will be zero (no limit) if no value is set + $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); + } + + // If we've reached the maximum recursion level, short circuit + if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) { + return $data; + } + + if ( ( is_array( $data ) || is_object( $data ) ) ) { + // If we've seen this exact object or array before, short circuit + if ( in_array( $data, $visited_data, true ) ) { + return $data; // Avoid infinite loops when there's a cycle + } + // Add this data to the list of + $visited_data[] = $data; + } + } + + if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { + $data = recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 ); + } + + elseif ( is_array( $data ) ) { + $keys = array_keys( $data ); + foreach ( $keys as $key ) { + $data[ $key ]= recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); + } + } + + elseif ( $recurse_objects && is_object( $data ) ) { + foreach ( $data as $key => $value ) { + $data->$key = recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); + } + } + + else if ( is_string( $data ) ) { + $data = str_replace( $from, $to, $data ); + } + + if ( $serialised ) + return serialize( $data ); + + } catch( Exception $error ) { + + } + + return $data; +} + diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php new file mode 100644 index 000000000..696d487ff --- /dev/null +++ b/tests/test-search-replace.php @@ -0,0 +1,71 @@ +<?php + +require_once getcwd() . '/php/class-wp-cli.php'; +require_once getcwd() . '/php/class-wp-cli-command.php'; +require_once getcwd() . '/php/commands/search-replace.php'; + +class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { + + function testReplaceString() { + $orig = 'foo'; + $replacement = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $orig ); + $this->assertEquals( 'bar', $replacement ); + } + + function testPrivateConstructor() { + $old_obj = ClassWithPrivateConstructor::get_instance(); + + $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_obj, false, true ); + $this->assertEquals( 'bar', $new_obj->prop ); + } + + function testObjectLoop() { + $old_object = new stdClass(); + $old_object->prop = 'foo'; + $old_object->self = $old_object; + + $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); + $this->assertEquals( 'bar', $new_obj->prop ); + } + + function testArrayLoop() { + $old_array = array( 'prop' => 'foo' ); + $old_array['self'] = &$old_array; + + $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); + $this->assertEquals( 'bar', $new_array['prop'] ); + } + + function testMixedObjectArrayLoop() { + $old_object = new stdClass(); + $old_object->prop = 'foo'; + $old_object->array = array('prop' => 'foo'); + $old_object->array['object'] = $old_object; + + $new_object = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); + $this->assertEquals( 'bar', $new_object->prop ); + $this->assertEquals( 'bar', $new_object->array['prop']); + } + + function testMixedArrayObjectLoop() { + $old_array = array( 'prop' => 'foo', 'object' => new stdClass() ); + $old_array['object']->prop = 'foo'; + $old_array['object']->array = &$old_array; + + $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); + $this->assertEquals( 'bar', $new_array['prop'] ); + $this->assertEquals( 'bar', $new_array['object']->prop); + } +} + + +class ClassWithPrivateConstructor { + + public $prop = 'foo'; + + private function __construct() {} + + public static function get_instance() { + return new self; + } +} From 52245c9441dd1bb344391249a81667c0e6740b83 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 09:47:19 +0200 Subject: [PATCH 2628/5359] remove unnecessary requires; see #951 --- tests/test-search-replace.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php index 696d487ff..4b9b4078b 100644 --- a/tests/test-search-replace.php +++ b/tests/test-search-replace.php @@ -1,9 +1,5 @@ <?php -require_once getcwd() . '/php/class-wp-cli.php'; -require_once getcwd() . '/php/class-wp-cli-command.php'; -require_once getcwd() . '/php/commands/search-replace.php'; - class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { function testReplaceString() { From 937a313f814b9bc295770ff1964cd3cbe6d929f6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 09:52:44 +0200 Subject: [PATCH 2629/5359] word-wrap command descriptions --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 46cf470b3..a3f42d3a0 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -47,7 +47,7 @@ private static function show_help( $command ) { $longdesc = $command->get_longdesc(); if ( $longdesc ) { - $out .= $longdesc . "\n"; + $out .= wordwrap( $longdesc, 79 ) . "\n"; } // section headers From 8f9393b7ac317c7e26e50726c89bef84131e4437 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 10:03:00 +0200 Subject: [PATCH 2630/5359] manually wrap long line in search-replace description --- php/commands/search-replace.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b8d219d34..81980e173 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -12,7 +12,8 @@ class Search_Replace_Command extends WP_CLI_Command { * * ## DESCRIPTION * - * This command will go through all rows in all tables and will replace all appearances of the old string with the new one. + * This command will go through all rows in all tables and will replace all + * appearances of the old string with the new one. * * It will correctly handle serialized values, and will not change primary key values. * From b23962ae8b94a9f6b0bd45ccca97c2e26e648d51 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 11:45:32 +0200 Subject: [PATCH 2631/5359] remove reference from $data parameter; see #951 also, improve parameter descriptions --- php/utils.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/utils.php b/php/utils.php index 1218dd14e..43edb3498 100644 --- a/php/utils.php +++ b/php/utils.php @@ -390,17 +390,17 @@ function is_windows() { * Initial code from https://github.com/interconnectit/Search-Replace-DB * * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with - * @param array|string $data Used to pass any subordinate arrays back to in. - * @param bool $serialised Does the array passed via $data need serialising. - * @param bool $recurse_objects Should objects be recursively replaced. + * @param string $to What we want it to be replaced with. + * @param array|string $data The data to operate on. + * @param bool $serialised Does the value of $data need to be unserialized? + * @param bool $recurse_objects Should objects be recursively replaced? * @param int $max_recursion How many levels to recurse into the data, if $recurse_objects is set to true. * @param int $recursion_level Current recursion depth within the original data. * @param array $visited_data Data that has been seen in previous recursion iterations. * * @return array The original array with all elements replaced as needed. */ -function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { +function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { // some unseriliased data cannot be re-serialised eg. SimpleXMLElements try { From 95d97b4c729a10518151ee6e60869b949d838603 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 11 Jan 2014 12:05:53 +0200 Subject: [PATCH 2632/5359] convert recursive_unserialize_replace() function to a class benefits: - avoids exposing intermediate recursion variables, such as $recursion_level - clearer which elements are constant and which change see #951 --- php/WP_CLI/SearchReplacer.php | 96 +++++++++++++++++++++++++++++++++ php/commands/search-replace.php | 4 +- php/utils.php | 77 -------------------------- tests/test-search-replace.php | 17 +++--- 4 files changed, 110 insertions(+), 84 deletions(-) create mode 100644 php/WP_CLI/SearchReplacer.php diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php new file mode 100644 index 000000000..e3910b20b --- /dev/null +++ b/php/WP_CLI/SearchReplacer.php @@ -0,0 +1,96 @@ +<?php + +namespace WP_CLI; + +class SearchReplacer { + + private $from, $to; + private $recurse_objects; + private $max_recursion; + + /** + * @param string $from String we're looking to replace. + * @param string $to What we want it to be replaced with. + * @param bool $recurse_objects Should objects be recursively replaced? + */ + function __construct( $from, $to, $recurse_objects = false ) { + $this->from = $from; + $this->to = $to; + $this->recurse_objects = $recurse_objects; + + // Get the XDebug nesting level. Will be zero (no limit) if no value is set + $this->max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); + } + + /** + * Take a serialised array and unserialise it replacing elements as needed and + * unserialising any subordinate arrays and performing the replace on those too. + * Ignores any serialized objects unless $recurse_objects is set to true. + * + * @param array|string $data The data to operate on. + * @param bool $serialised Does the value of $data need to be unserialized? + * + * @return array The original array with all elements replaced as needed. + */ + function run( $data, $serialised = false ) { + return $this->_run( $data, $serialised ); + } + + /** + * @param int $recursion_level Current recursion depth within the original data. + * @param array $visited_data Data that has been seen in previous recursion iterations. + */ + private function _run( $data, $serialised, $recursion_level = 0, &$visited_data = array() ) { + + // some unseriliased data cannot be re-serialised eg. SimpleXMLElements + try { + + if ( $this->recurse_objects ) { + + // If we've reached the maximum recursion level, short circuit + if ( $this->max_recursion != 0 && $recursion_level >= $this->max_recursion ) { + return $data; + } + + if ( is_array( $data ) || is_object( $data ) ) { + // If we've seen this exact object or array before, short circuit + if ( in_array( $data, $visited_data, true ) ) { + return $data; // Avoid infinite loops when there's a cycle + } + // Add this data to the list of + $visited_data[] = $data; + } + } + + if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { + $data = $this->_run( $unserialized, true, $recursion_level + 1 ); + } + + elseif ( is_array( $data ) ) { + $keys = array_keys( $data ); + foreach ( $keys as $key ) { + $data[ $key ]= $this->_run( $data[$key], false, $recursion_level + 1, $visited_data ); + } + } + + elseif ( $this->recurse_objects && is_object( $data ) ) { + foreach ( $data as $key => $value ) { + $data->$key = $this->_run( $value, false, $recursion_level + 1, $visited_data ); + } + } + + else if ( is_string( $data ) ) { + $data = str_replace( $this->from, $this->to, $data ); + } + + if ( $serialised ) + return serialize( $data ); + + } catch( Exception $error ) { + + } + + return $data; + } +} + diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 81980e173..d24d6ce9a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -124,11 +124,13 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry $count = 0; + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $recurse_objects ); + foreach ( $it as $row ) { if ( '' === $row->$col ) continue; - $value = WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects ); + $value = $replacer->run( $row->$col ); if ( $dry_run ) { if ( $value != $row->$col ) diff --git a/php/utils.php b/php/utils.php index 43edb3498..a281bd167 100644 --- a/php/utils.php +++ b/php/utils.php @@ -382,80 +382,3 @@ function is_windows() { return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } -/** - * Take a serialised array and unserialise it replacing elements as needed and - * unserialising any subordinate arrays and performing the replace on those too. - * Ignores any serialized objects unless $recurse_objects is set to true. - * - * Initial code from https://github.com/interconnectit/Search-Replace-DB - * - * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with. - * @param array|string $data The data to operate on. - * @param bool $serialised Does the value of $data need to be unserialized? - * @param bool $recurse_objects Should objects be recursively replaced? - * @param int $max_recursion How many levels to recurse into the data, if $recurse_objects is set to true. - * @param int $recursion_level Current recursion depth within the original data. - * @param array $visited_data Data that has been seen in previous recursion iterations. - * - * @return array The original array with all elements replaced as needed. - */ -function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) { - - // some unseriliased data cannot be re-serialised eg. SimpleXMLElements - try { - - if ( $recurse_objects ) { - - // If no maximum recursion level is set, use the XDebug limit if it exists - if ( -1 == $max_recursion ) { - // Get the XDebug nesting level. Will be zero (no limit) if no value is set - $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); - } - - // If we've reached the maximum recursion level, short circuit - if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) { - return $data; - } - - if ( ( is_array( $data ) || is_object( $data ) ) ) { - // If we've seen this exact object or array before, short circuit - if ( in_array( $data, $visited_data, true ) ) { - return $data; // Avoid infinite loops when there's a cycle - } - // Add this data to the list of - $visited_data[] = $data; - } - } - - if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { - $data = recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 ); - } - - elseif ( is_array( $data ) ) { - $keys = array_keys( $data ); - foreach ( $keys as $key ) { - $data[ $key ]= recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); - } - } - - elseif ( $recurse_objects && is_object( $data ) ) { - foreach ( $data as $key => $value ) { - $data->$key = recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data ); - } - } - - else if ( is_string( $data ) ) { - $data = str_replace( $from, $to, $data ); - } - - if ( $serialised ) - return serialize( $data ); - - } catch( Exception $error ) { - - } - - return $data; -} - diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php index 4b9b4078b..6b5cd27de 100644 --- a/tests/test-search-replace.php +++ b/tests/test-search-replace.php @@ -2,16 +2,21 @@ class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { + private static function recursive_unserialize_replace( $from, $to, $data, $serialised = false, $recurse_objects = false ) { + $replacer = new \WP_CLI\SearchReplacer( $from, $to, $recurse_objects ); + return $replacer->run( $data, $serialised ); + } + function testReplaceString() { $orig = 'foo'; - $replacement = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $orig ); + $replacement = self::recursive_unserialize_replace( 'foo', 'bar', $orig ); $this->assertEquals( 'bar', $replacement ); } function testPrivateConstructor() { $old_obj = ClassWithPrivateConstructor::get_instance(); - $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_obj, false, true ); + $new_obj = self::recursive_unserialize_replace( 'foo', 'bar', $old_obj, false, true ); $this->assertEquals( 'bar', $new_obj->prop ); } @@ -20,7 +25,7 @@ function testObjectLoop() { $old_object->prop = 'foo'; $old_object->self = $old_object; - $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); + $new_obj = self::recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); $this->assertEquals( 'bar', $new_obj->prop ); } @@ -28,7 +33,7 @@ function testArrayLoop() { $old_array = array( 'prop' => 'foo' ); $old_array['self'] = &$old_array; - $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); + $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); $this->assertEquals( 'bar', $new_array['prop'] ); } @@ -38,7 +43,7 @@ function testMixedObjectArrayLoop() { $old_object->array = array('prop' => 'foo'); $old_object->array['object'] = $old_object; - $new_object = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); + $new_object = self::recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); $this->assertEquals( 'bar', $new_object->prop ); $this->assertEquals( 'bar', $new_object->array['prop']); } @@ -48,7 +53,7 @@ function testMixedArrayObjectLoop() { $old_array['object']->prop = 'foo'; $old_array['object']->array = &$old_array; - $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); + $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); $this->assertEquals( 'bar', $new_array['prop'] ); $this->assertEquals( 'bar', $new_array['object']->prop); } From 99ff98cbaa49d568f8eb55226c50fbb13733e104 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Sun, 5 Jan 2014 19:55:58 +0100 Subject: [PATCH 2633/5359] core caching on download --- php/WP_CLI/FileCache.php | 2 +- php/class-wp-cli.php | 2 +- php/commands/core.php | 62 ++++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/php/WP_CLI/FileCache.php b/php/WP_CLI/FileCache.php index a6a9fa624..6fb0af3d7 100644 --- a/php/WP_CLI/FileCache.php +++ b/php/WP_CLI/FileCache.php @@ -47,7 +47,7 @@ class FileCache { * @param int $maxSize max total cache size * @param string $whitelist List of characters that are allowed in path names (used in a regex character class) */ - public function __construct( $cacheDir, $ttl, $maxSize, $whitelist = 'a-z0-9.' ) { + public function __construct( $cacheDir, $ttl, $maxSize, $whitelist = 'a-z0-9._-' ) { $this->root = rtrim( $cacheDir, '/\\' ) . '/'; $this->ttl = (int) $ttl; $this->maxSize = (int) $maxSize; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1f5343602..066486954 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -58,7 +58,7 @@ static function get_runner() { /** * @return FileCache */ - private static function get_cache() { + public static function get_cache() { static $cache; if ( !$cache ) { diff --git a/php/commands/core.php b/php/commands/core.php index d01e2067b..8da06b6e5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -41,43 +41,54 @@ public function download( $args, $assoc_args ) { WP_CLI::launch( Utils\esc_cmd( 'mkdir -p %s', ABSPATH ) ); } - if ( isset( $assoc_args['locale'] ) && isset( $assoc_args['version'] ) ) { - $download_url = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.tar.gz', - substr( $assoc_args['locale'], 0, 2 ), $assoc_args['version'], $assoc_args['locale'] ); - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $assoc_args['locale'] ) ); - } else if ( isset( $assoc_args['locale'] ) ) { - $offer = $this->get_download_offer( $assoc_args['locale'] ); - $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', - $offer['current'], $offer['locale'] ) ); - } elseif ( isset( $assoc_args['version'] ) ) { - $download_url = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.tar.gz'; - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); + $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; + + if ( isset( $assoc_args['version'] ) ) { + $version = $assoc_args['version']; + if ( 'en_US' === $locale ) { + $download_url = 'https://wordpress.org/wordpress-' . $version . '.tar.gz'; + } else { + $download_url = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.tar.gz', + substr( $assoc_args['locale'], 0, 2 ), $version, $locale ); + } } else { - $download_url = 'https://wordpress.org/latest.tar.gz'; - WP_CLI::log( sprintf( 'Downloading latest WordPress (%s)...', 'en_US' ) ); + $offer = $this->get_download_offer( $locale ); + $version = $offer['current']; + $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); } - // We need to use a temporary file because piping from cURL to tar is flaky - // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $version, $locale ) ); - $headers = array('Accept' => 'application/json'); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody - 'filename' => $temp - ); + $cache = WP_CLI::get_cache(); + $cache_key = "core/$locale-$version.tar.gz"; + $cache_file = $cache->has($cache_key); - self::_request( 'GET', $download_url, $headers, $options ); + if ( $cache_file ) { + WP_CLI::log( "Using cached file '$cache_file'..." ); + self::_extract( $cache_file, ABSPATH ); + } else { + // We need to use a temporary file because piping from cURL to tar is flaky + // on MinGW (and probably in other environments too). + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + + $headers = array('Accept' => 'application/json'); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); - self::_extract( $temp, ABSPATH ); + self::_request( 'GET', $download_url, $headers, $options ); + self::_extract( $temp, ABSPATH ); + $cache->import( $cache_key, $temp ); + unlink($temp); + } WP_CLI::success( 'WordPress downloaded.' ); } private static function _extract( $tarball, $dest ) { if ( ! class_exists( 'PharData' ) ) { - $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball && rm $tarball"; + $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); return; } @@ -122,6 +133,7 @@ private static function _rmdir( $dir ) { $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; $todo( $fileinfo->getRealPath() ); } + rmdir( $dir ); } private static function _request( $method, $url, $headers = array(), $options = array() ) { From f28da3c2f5caed2cf29b8719c9660f4a02a76abc Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Mon, 13 Jan 2014 14:24:23 +0100 Subject: [PATCH 2634/5359] core download caching tests --- features/core.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/core.feature b/features/core.feature index 30fea76ed..a7c647917 100644 --- a/features/core.feature +++ b/features/core.feature @@ -9,17 +9,29 @@ Feature: Manage WordPress installation And STDERR should not be empty When I run `wp core download` + And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/en_US-{VERSION}.tar.gz file should exist When I run `mkdir inner` And I run `cd inner && wp core download` Then the inner/wp-settings.php file should exist + # test core tarball cache + When I run `wp core download --force` + Then the wp-settings.php file should exist + And STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/core/en_US-{VERSION}.tar.gz'... + """ + @download Scenario: Localized install Given an empty directory When I run `wp core download --locale=de_DE` + And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/de_DE-{VERSION}.tar.gz file should exist Scenario: No wp-config.php Given an empty directory From d57711fbe2c0b58742096119e3c84772fe0ecbdf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 Jan 2014 20:59:16 +0200 Subject: [PATCH 2635/5359] make 'wp term delete' accept multiple args --- features/term.feature | 2 +- php/commands/term.php | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/features/term.feature b/features/term.feature index c2b6e8ef2..454455c64 100644 --- a/features/term.feature +++ b/features/term.feature @@ -45,7 +45,7 @@ Feature: Manage WordPress terms "test-delete" """ - When I run `wp term delete {TERM_ID} post_tag` + When I run `wp term delete post_tag {TERM_ID}` Then STDOUT should contain: """ Deleted post_tag {TERM_ID}. diff --git a/php/commands/term.php b/php/commands/term.php index 5bdaeb5a3..52a8723da 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -205,28 +205,31 @@ public function update( $args, $assoc_args ) { * * ## OPTIONS * - * <term-id> - * : ID for the term to delete. - * * <taxonomy> * : Taxonomy of the term to delete. * + * <term-id>... + * : One or more IDs of terms to delete. + * * ## EXAMPLES * - * wp term delete 15 category + * # delete all post tags + * wp term list post_tag --field=ID | xargs wp term delete post_tag */ public function delete( $args ) { + $taxonomy = array_shift( $args ); - list( $term_id, $taxonomy ) = $args; - - $ret = wp_delete_term( $term_id, $taxonomy ); + foreach ( $args as $term_id ) { + $ret = wp_delete_term( $term_id, $taxonomy ); - if ( is_wp_error( $ret ) ) - WP_CLI::error( $ret->get_error_message() ); - else if ( $ret ) - WP_CLI::success( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); - else - WP_CLI::error( "Term doesn't exist." ); + if ( is_wp_error( $ret ) ) { + WP_CLI::warning( $ret ); + } else if ( $ret ) { + WP_CLI::success( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); + } else { + WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); + } + } } /** From f44beb9d71213930bed6c048352671360e9ed261 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 Jan 2014 21:42:39 +0200 Subject: [PATCH 2636/5359] improve hierarchy generation; see #821 --- php/commands/post.php | 17 +++++++++++------ php/commands/term.php | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 3d57cf2de..c50eb527d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -263,10 +263,10 @@ public function _list( $_, $assoc_args ) { * * [--post_date=<yyyy-mm-dd>] * : The date of the generated posts. Default: current date - * + * * [--post_content] * : If set, the command reads the post_content from STDIN. - * + * * [--max_depth=<number>] * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 * @@ -316,7 +316,7 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); - $post_ids = array(); + $previous_post_id = 0; $current_depth = 1; $current_parent = 0; @@ -348,7 +348,12 @@ public function generate( $args, $assoc_args ) { 'post_content' => $post_content, ); - $post_ids[$i] = wp_insert_post( $args, true ); + $post_id = wp_insert_post( $args, true ); + if ( is_wp_error( $post_id ) ) { + WP_CLI::warning( $post_id ); + } else { + $previous_post_id = $post_id; + } $notify->tick(); } @@ -358,7 +363,7 @@ public function generate( $args, $assoc_args ) { /** * Get post url - * + * * ## OPTIONS * * <id>... @@ -367,7 +372,7 @@ public function generate( $args, $assoc_args ) { * ## EXAMPLES * * wp post url 123 - * + * * wp post url 123 324 */ public function url( $args ) { diff --git a/php/commands/term.php b/php/commands/term.php index 5bdaeb5a3..ddb3a5600 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -270,27 +270,28 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); - $current_depth = 1; - $current_parent = 0; - $args = array( 'orderby' => 'id', 'hierarchical' => $hierarchical, ); + $previous_term_id = 0; + $current_parent = 0; + $current_depth = 1; + for ( $i = 0; $i < $count; $i++ ) { if ( $hierarchical ) { - if ( $this->maybe_make_child() && $current_depth < $max_depth ) { + if ( $previous_term_id && $this->maybe_make_child() && $current_depth < $max_depth ) { - $current_parent = $term['term_id']; + $current_parent = $previous_term_id; $current_depth++; } else if ( $this->maybe_reset_depth() ) { - $current_depth = 1; $current_parent = 0; + $current_depth = 1; } @@ -302,6 +303,11 @@ public function generate( $args, $assoc_args ) { ); $term = wp_insert_term( "$label $i", $taxonomy, $args ); + if ( is_wp_error( $term ) ) { + WP_CLI::warning( $term ); + } else { + $previous_term_id = $term['term_id']; + } $notify->tick(); } From bcf2f68a1ce82b0c2bbd35319bd78f26bca5dcaf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 Jan 2014 21:04:05 +0200 Subject: [PATCH 2637/5359] make all the term subcommands accept the taxonomy as the first parameter --- features/site.feature | 2 +- features/term.feature | 8 ++++---- php/commands/term.php | 30 +++++++++++++++--------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/features/site.feature b/features/site.feature index 26f767841..3a0382007 100644 --- a/features/site.feature +++ b/features/site.feature @@ -59,7 +59,7 @@ Feature: Manage sites in a multisite installation When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` Then STDOUT should not be empty - When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term'` + When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term'` Then STDOUT should not be empty When I run `wp site empty --yes` diff --git a/features/term.feature b/features/term.feature index 454455c64..ebfae3b2f 100644 --- a/features/term.feature +++ b/features/term.feature @@ -4,7 +4,7 @@ Feature: Manage WordPress terms Given a WP install Scenario: Creating/listing a term - When I run `wp term create 'Test term' post_tag --slug=test --description='This is a test term' --porcelain` + When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` Then STDOUT should be a number And save STDOUT as {TERM_ID} @@ -28,18 +28,18 @@ Feature: Manage WordPress terms | name | slug | | Test term | test | - When I run `wp term get {TERM_ID} post_tag` + When I run `wp term get post_tag {TERM_ID}` Then STDOUT should be a table containing rows: | Field | Value | | term_id | {TERM_ID} | | name | Test term | Scenario: Creating/deleting a term - When I run `wp term create 'Test delete term' post_tag --slug=test-delete --description='This is a test term to be deleted' --porcelain` + When I run `wp term create post_tag 'Test delete term' --slug=test-delete --description='This is a test term to be deleted' --porcelain` Then STDOUT should be a number And save STDOUT as {TERM_ID} - When I run `wp term get {TERM_ID} post_tag --field=slug --format=json` + When I run `wp term get post_tag {TERM_ID} --field=slug --format=json` Then STDOUT should contain: """ "test-delete" diff --git a/php/commands/term.php b/php/commands/term.php index 52a8723da..2033dc10f 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -64,12 +64,12 @@ public function _list( $args, $assoc_args ) { * * ## OPTIONS * - * <term> - * : A name for the new term. - * * <taxonomy> * : Taxonomy for the new term. * + * <term> + * : A name for the new term. + * * [--slug=<slug>] * : A unique slug for the new term. Defaults to sanitized version of name. * @@ -84,11 +84,11 @@ public function _list( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term create Apple category --description="A type of fruit" + * wp term create category Apple --description="A type of fruit" */ public function create( $args, $assoc_args ) { - list( $term, $taxonomy ) = $args; + list( $taxonomy, $term ) = $args; $defaults = array( 'slug' => sanitize_title( $term ), @@ -121,12 +121,12 @@ public function create( $args, $assoc_args ) { * * ## OPTIONS * - * <term-id> - * : ID of the term to get - * * <taxonomy> * : Taxonomy of the term to get * + * <term-id> + * : ID of the term to get + * * [--field=<field>] * : Instead of returning the whole term, returns the value of a single field. * @@ -135,12 +135,12 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term get 1 category --format=json + * wp term get category 1 --format=json */ public function get( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); - list( $term_id, $taxonomy ) = $args; + list( $taxonomy, $term_id ) = $args; $term = get_term_by( 'id', $term_id, $taxonomy ); if ( ! $term ) WP_CLI::error( "Term doesn't exist." ); @@ -153,12 +153,12 @@ public function get( $args, $assoc_args ) { * * ## OPTIONS * - * <term-id> - * : ID for the term to update. - * * <taxonomy> * : Taxonomy of the term to update. * + * <term-id> + * : ID for the term to update. + * * [--name=<name>] * : A new name for the term. * @@ -173,11 +173,11 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term update 15 category --name=Apple + * wp term update category 15 --name=Apple */ public function update( $args, $assoc_args ) { - list( $term_id, $taxonomy ) = $args; + list( $taxonomy, $term_id ) = $args; $defaults = array( 'name' => null, From d00a3d3e57b71c43285aa1d4ae41ef65b9d7b4d5 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Tue, 14 Jan 2014 21:53:29 +0100 Subject: [PATCH 2638/5359] Unset possible ID column to prevent unwanted behaviour If the ID column isn't unset, then `wp_insert_user` will return this ID while not having created a new user. Therefor passing the `is_wp_error` check and showing the success message without actually having created a new user. --- php/commands/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/user.php b/php/commands/user.php index 630df43ff..85535b20a 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -561,6 +561,7 @@ public function import_csv( $args, $assoc_args ) { // Create the user } else { + unset( $new_user['ID'] ); // Unset else it will just return the ID $user_id = wp_insert_user( $new_user ); } From ae175ac8d88c61b9e8132f07ca2b200b2437a413 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 14 Jan 2014 22:12:54 +0200 Subject: [PATCH 2639/5359] slight improvement to behat step regex --- features/steps/given.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/given.php b/features/steps/given.php index 998a01313..5998f0d2f 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -87,7 +87,7 @@ function ( $world, TableNode $table ) { } ); -$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', +$steps->Given( '/^save (STDOUT|STDERR)( [\'].+[^\'])? as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { if ( $output_filter ) { From a2b320c8b3e36b2a92bdd576659e0ee624469820 Mon Sep 17 00:00:00 2001 From: Nikolay Bachiyski <nb@nikolay.bg> Date: Fri, 17 Jan 2014 18:13:11 -1000 Subject: [PATCH 2640/5359] Update WordPress stable in Travis CI template The 3.6 times are gone. --- templates/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 81650f76b..64be0af08 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -7,8 +7,8 @@ php: env: - WP_VERSION=latest WP_MULTISITE=0 - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.6.1 WP_MULTISITE=0 - - WP_VERSION=3.6.1 WP_MULTISITE=1 + - WP_VERSION=3.8 WP_MULTISITE=0 + - WP_VERSION=3.8 WP_MULTISITE=1 before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION From aad9a9636adbe1ec72f7c336aa280d504ed8f45d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 Jan 2014 17:57:31 +0200 Subject: [PATCH 2641/5359] readme: s/Installation/Installing/ just seems more friendly --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c334da485..9d6cce864 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ WP-CLI WP-CLI is a set of command-line tools for managing WordPress installations. -Installation +Installing ------------ If you just want to use WP-CLI, see <http://wp-cli.org/#install>. From b89cacc352a1eaa9d0b3d4704e4f00edec5d43d6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 18 Jan 2014 18:22:11 +0200 Subject: [PATCH 2642/5359] use get_check() in 'wp plugin path' --- features/plugin.feature | 12 ++++++++++++ php/commands/plugin.php | 7 +------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 48517e456..f198ebb9a 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -10,6 +10,18 @@ Feature: Manage WordPress plugins And the {PLUGIN_DIR}/plugin1/plugin1.php file should exist And the {PLUGIN_DIR}/zombieland/phpunit.xml file should not exist + When I run `wp plugin path plugin1` + Then STDOUT should be: + """ + {PLUGIN_DIR}/plugin1/plugin1.php + """ + + When I run `wp plugin path plugin1 --dir` + Then STDOUT should be: + """ + {PLUGIN_DIR}/plugin1 + """ + When I run `wp plugin scaffold zombieland --plugin_name="Zombieland"` Then STDOUT should not be empty And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 6a66483f8..fd4932d29 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -228,12 +228,7 @@ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { - $plugins = $this->fetcher->get_many( $args ); - if ( empty( $plugins ) ) - return; - - list( $plugin ) = $plugins; - + $plugin = $this->fetcher->get_check( $args[0] ); $path .= '/' . $plugin->file; if ( isset( $assoc_args['dir'] ) ) From c74e89ed90fb42ee41d04f69c5b32bbf8f2b2f8e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 Jan 2014 15:25:23 +0200 Subject: [PATCH 2643/5359] refactor long line in get_update_info() --- php/WP_CLI/CommandWithUpgrade.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e4047e099..485a8a1b2 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -297,7 +297,11 @@ protected function has_update( $slug ) { */ protected function get_update_info( $slug ) { $update_list = get_site_transient( $this->upgrade_transient ); - return isset( $update_list->response[ $slug ] ) ? (array) $update_list->response[ $slug ] : null; + + if ( !isset( $update_list->response[ $slug ] ) ) + return null; + + return (array) $update_list->response[ $slug ]; } private $map = array( From f7f251a03cde4823780582c52c248f8dcb92e443 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 Jan 2014 16:07:17 +0200 Subject: [PATCH 2644/5359] Revert "slight improvement to behat step regex" The new regex didn't catch all cases. This reverts commit ae175ac8d88c61b9e8132f07ca2b200b2437a413. --- features/steps/given.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/given.php b/features/steps/given.php index 5998f0d2f..998a01313 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -87,7 +87,7 @@ function ( $world, TableNode $table ) { } ); -$steps->Given( '/^save (STDOUT|STDERR)( [\'].+[^\'])? as \{(\w+)\}$/', +$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { if ( $output_filter ) { From 12481f91c30753c8a300004ff9b6b55ef6ed350a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 19 Jan 2014 19:22:47 +0200 Subject: [PATCH 2645/5359] wp plugin get: remove unreliable 'update' field we'd have to call wp_update_plugins() on each run, like we do for `wp plugin status` also, `wp theme get` doesn't have it --- php/commands/plugin.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index fd4932d29..18465c57b 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -393,7 +393,6 @@ public function get( $args, $assoc_args ) { 'version' => $plugin_data['Version'], 'description' => wordwrap( $plugin_data['Description'] ), 'status' => $this->get_status( $file ), - 'update' => $this->has_update( $file ), ); $formatter = $this->get_formatter( $assoc_args ); From 7433cdb85305d867d280b71f9f5f3d71e31e1a4b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 08:17:02 -0800 Subject: [PATCH 2646/5359] Update `wp user-meta` to support `user_login` as a first positional argument --- php/commands/user-meta.php | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 1e2dda038..045bf4d3a 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -14,6 +14,64 @@ */ class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + + /** + * Get meta field value. + * + * @synopsis <user> <key> [--format=<format>] + */ + public function get( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::get( $args, $assoc_args ); + } + + /** + * Delete a meta field. + * + * @synopsis <user> <key> + */ + public function delete( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::delete( $args, $assoc_args ); + } + + /** + * Add a meta field. + * + * @synopsis <user> <key> <value> [--format=<format>] + */ + public function add( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::add( $args, $assoc_args ); + } + + /** + * Update a meta field. + * + * @alias set + * @synopsis <user> <key> <value> [--format=<format>] + */ + public function update( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::update( $args, $assoc_args ); + } + + /** + * Replace user_login value with user ID + * user-meta is a special case that also supports user_login + * + * @param array + * @return array + */ + private function replace_login_with_user_id( $args ) { + $user = $this->fetcher->get_check( $args[0] ); + $args[0] = $user->ID; + return $args; + } } WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); From 0c8f1a229c7b053a8c7115d32356cee8ed9a7ac0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 08:17:34 -0800 Subject: [PATCH 2647/5359] Update tests to reflect 7433cdb --- features/user-meta.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/user-meta.feature b/features/user-meta.feature index 7d3ac2b5f..774941972 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -12,10 +12,10 @@ Feature: Manage user custom fields bar """ - When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` + When I run `wp user-meta set admin foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty - When I run `wp user-meta get 1 foo --format=json` + When I run `wp user-meta get admin foo --format=json` Then STDOUT should be: """ ["1","2"] From fa200a50dc3ad0c1284795ea694362ac31ec9125 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 08:49:43 -0800 Subject: [PATCH 2648/5359] `post_type` is a special key that should also support multiple arguments --- php/commands/post.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index c50eb527d..2f997335d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -232,8 +232,10 @@ public function _list( $_, $assoc_args ) { $query_args = array_merge( $defaults, $assoc_args ); foreach ( $query_args as $key => $query_arg ) { - if ( false !== strpos( $key, '__' ) ) + if ( false !== strpos( $key, '__' ) + || 'post_type' == $key ) { $query_args[$key] = explode( ',', $query_arg ); + } } if ( 'ids' == $formatter->format ) From c9bc79fc02806c92ac1e79309a7806bc2d6215b0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 09:00:53 -0800 Subject: [PATCH 2649/5359] Add another example to the description --- php/commands/user-meta.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 045bf4d3a..39021d24a 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -11,6 +11,8 @@ * ## EXAMPLES * * wp user-meta set 123 description "Mary is a WordPress developer." + * + * wp user-meta update admin first_name "George" */ class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; From c5fdadeb289d808c176efdfe921fc93de4d42c42 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 09:03:51 -0800 Subject: [PATCH 2650/5359] Copy and paste some command docs --- php/commands/user-meta.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 39021d24a..dbe0924b4 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -23,6 +23,17 @@ public function __construct() { /** * Get meta field value. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to get metadata for. + * + * <key> + * : The metadata key. + * + * [--format=<format>] + * : Accepted values: table, json. Default: table * * @synopsis <user> <key> [--format=<format>] */ @@ -33,6 +44,12 @@ public function get( $args, $assoc_args ) { /** * Delete a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to delete metadata from. + * + * <key> + * : The metadata key. * * @synopsis <user> <key> */ @@ -43,6 +60,15 @@ public function delete( $args, $assoc_args ) { /** * Add a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to add metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. * * @synopsis <user> <key> <value> [--format=<format>] */ @@ -53,6 +79,15 @@ public function add( $args, $assoc_args ) { /** * Update a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to update metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. * * @alias set * @synopsis <user> <key> <value> [--format=<format>] From 61a132901c8dc0d6f32b81d74908efda1c67043b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 09:10:05 -0800 Subject: [PATCH 2651/5359] Update `wp post list` examples --- php/commands/post.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 2f997335d..754d631cd 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -210,7 +210,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, ids. Default: table * * ## EXAMPLES * @@ -219,6 +219,8 @@ public function delete( $args, $assoc_args ) { * wp post list --post_type=post --posts_per_page=5 --format=json * * wp post list --post_type=page --fields=post_title,post_status + * + * wp post list --post_type=page,post --format=ids * * @subcommand list */ From 73f382e18078dc3cb2349a8d475b97c0e14df95d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Jan 2014 09:55:41 -0800 Subject: [PATCH 2652/5359] According to core, `post_type` == `any` has to be a string --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 754d631cd..72f4a87f3 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -235,7 +235,7 @@ public function _list( $_, $assoc_args ) { foreach ( $query_args as $key => $query_arg ) { if ( false !== strpos( $key, '__' ) - || 'post_type' == $key ) { + || ( 'post_type' == $key && 'any' != $query_arg ) ) { $query_args[$key] = explode( ',', $query_arg ); } } From 19c47b7a8ef929d72fcfaf1dc8290dd56e42a5d0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 21 Jan 2014 01:00:44 +0200 Subject: [PATCH 2653/5359] rename _list() to list_() to avoid confusing it with a non-public method --- php/commands/cap.php | 2 +- php/commands/comment.php | 2 +- php/commands/post.php | 2 +- php/commands/rewrite.php | 2 +- php/commands/role.php | 2 +- php/commands/term.php | 2 +- php/commands/user.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index c5cc77745..afeee5d54 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -27,7 +27,7 @@ class Capabilities_Command extends WP_CLI_Command { * @subcommand list * @synopsis <role> */ - public function _list( $args ) { + public function list_( $args ) { $role_obj = self::get_role( $args[0] ); foreach ( array_keys( $role_obj->capabilities ) as $cap ) diff --git a/php/commands/comment.php b/php/commands/comment.php index b7481ddb3..cb2716323 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -137,7 +137,7 @@ public function get( $args, $assoc_args ) { * * @subcommand list */ - public function _list( $_, $assoc_args ) { + public function list_( $_, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); if ( 'ids' == $formatter->format ) diff --git a/php/commands/post.php b/php/commands/post.php index 72f4a87f3..b73eef053 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -224,7 +224,7 @@ public function delete( $args, $assoc_args ) { * * @subcommand list */ - public function _list( $_, $assoc_args ) { + public function list_( $_, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); $defaults = array( diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 8328a31e2..64432ad64 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -115,7 +115,7 @@ public function structure( $args, $assoc_args ) { * wp rewrite list --format=csv * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { global $wp_rewrite; $rules = get_option( 'rewrite_rules' ); diff --git a/php/commands/role.php b/php/commands/role.php index 99e5ecb60..896bc0f48 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -29,7 +29,7 @@ class Role_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { global $wp_roles; $output_roles = array(); diff --git a/php/commands/term.php b/php/commands/term.php index d1fabf685..2e5fd3544 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -44,7 +44,7 @@ class Term_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); $defaults = array( diff --git a/php/commands/user.php b/php/commands/user.php index 85535b20a..e747d7b47 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -51,7 +51,7 @@ public function __construct() { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); if ( 'ids' == $formatter->format ) { From 515d33f0a5ecd47aef1148860b5b3b68cc71080b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 21 Jan 2014 01:05:57 +0200 Subject: [PATCH 2654/5359] more renaming from _list() to list_() --- php/commands/plugin.php | 2 +- php/commands/site.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 18465c57b..2b6ebef5e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -495,7 +495,7 @@ function delete( $args, $assoc_args = array() ) { * * @subcommand list */ - function _list( $_, $assoc_args ) { + public function list_( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); } diff --git a/php/commands/site.php b/php/commands/site.php index cbd5ef2d2..5d5637d27 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -352,7 +352,7 @@ private function _get_network( $network_id ) { * * @subcommand list */ - function _list( $_, $assoc_args ) { + public function list_( $_, $assoc_args ) { if ( !is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 4c8cddf60..45df5cab7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -513,7 +513,7 @@ function delete( $args ) { * * @subcommand list */ - function _list( $_, $assoc_args ) { + public function list_( $_, $assoc_args ) { parent::_list( $_, $assoc_args ); } } From 16fa5cf1071c38a1e6eed21190a2da45ef971323 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 21 Jan 2014 02:02:40 +0200 Subject: [PATCH 2655/5359] first pass at --skip-plugins flag --- features/flags.feature | 49 +++++++++++++++++++++++++++++++++++++++++ php/commands/plugin.php | 24 ++++++-------------- php/config-spec.php | 8 +++++++ php/utils-wp.php | 22 ++++++++++++++++++ php/wp-settings-cli.php | 6 +++-- 5 files changed, 90 insertions(+), 19 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index b81fdbb65..c666235e2 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -92,6 +92,55 @@ Feature: Global flags log: called 'error' method """ + Scenario: Skipping plugins + Given a WP install + And I run `wp plugin activate hello akismet` + + When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified plugin should be skipped + When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + false + """ + + # The specified plugin should still show up as an active plugin + When I run `wp --skip-plugins=akismet plugin status` + Then STDOUT should contain: + """ + akismet + """ + + # The un-specified plugin should continue to be loaded + When I run `wp --skip-plugins=akismet eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + true + """ + + # No plugins should be loaded when --skip-plugins doesn't have a value + When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + false + """ + When I run `wp --skip-plugins eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + false + """ + Scenario: Using --require Given an empty directory And a custom-cmd.php file: diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 2b6ebef5e..1d90b756e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -1,5 +1,7 @@ <?php +use \WP_CLI\Utils; + /** * Manage plugins. * @@ -102,7 +104,7 @@ protected function status_single( $args ) { $version .= ' (%gUpdate available%n)'; echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'plugin-status.mustache', array( - 'slug' => $this->get_name( $file ), + 'slug' => Utils\get_plugin_name( $file ), 'status' => $status, 'version' => $version, 'name' => $details['Name'], @@ -116,7 +118,7 @@ protected function get_all_items() { foreach ( get_mu_plugins() as $file => $mu_plugin ) { $items[ $file ] = array( - 'name' => $this->get_name( $file ), + 'name' => Utils\get_plugin_name( $file ), 'status' => 'must-use', 'update' => false ); @@ -169,7 +171,7 @@ function deactivate( $args, $assoc_args = array() ) { if ( $this->get_status( $file ) == "inactive" ) continue; - $name = $this->get_name( $file ); + $name = Utils\get_plugin_name( $file ); deactivate_plugins( $file, false, $network_wide ); @@ -307,7 +309,7 @@ protected function get_item_list() { $update_info = $this->get_update_info( $file ); $items[ $file ] = array( - 'name' => $this->get_name( $file ), + 'name' => Utils\get_plugin_name( $file ), 'status' => $this->get_status( $file ), 'update' => (bool) $update_info, 'update_version' => $update_info['new_version'], @@ -387,7 +389,7 @@ public function get( $args, $assoc_args ) { $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); $plugin_obj = (object)array( - 'name' => $this->get_name( $file ), + 'name' => Utils\get_plugin_name( $file ), 'title' => $plugin_data['Name'], 'author' => $plugin_data['Author'], 'version' => $plugin_data['Version'], @@ -545,18 +547,6 @@ private function get_details( $file ) { return $plugin_folder[$plugin_file]; } - /** - * Converts a plugin basename back into a friendly slug. - */ - private function get_name( $file ) { - if ( false === strpos( $file, '/' ) ) - $name = basename( $file, '.php' ); - else - $name = dirname( $file ); - - return $name; - } - private function _delete( $plugin ) { $plugin_dir = dirname( $plugin->file ); if ( '.' == $plugin_dir ) diff --git a/php/config-spec.php b/php/config-spec.php index d4e206e7e..dd7612125 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -28,6 +28,14 @@ 'desc' => 'Set the WordPress user', ), + 'skip-plugins' => array( + 'runtime' => '[=<plugin>]', + 'file' => false, + 'desc' => 'Skip loading all or some plugins', + 'multiple' => false, + 'default' => '', + ), + 'require' => array( 'runtime' => '=<path>', 'file' => '<path>', diff --git a/php/utils-wp.php b/php/utils-wp.php index 1d925c6be..a8a64fbfd 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -69,3 +69,25 @@ function get_upgrader( $class ) { return new $class( new \WP_CLI\UpgraderSkin ); } +/** + * Converts a plugin basename back into a friendly slug. + */ +function get_plugin_name( $basename ) { + if ( false === strpos( $basename, '/' ) ) + $name = basename( $basename, '.php' ); + else + $name = dirname( $basename ); + + return $name; +} + +function is_plugin_skipped( $file ) { + $name = get_plugin_name( str_replace( WP_PLUGIN_DIR . '/', '', $file ) ); + + $skipped_plugins = \WP_CLI::get_runner()->config['skip-plugins']; + if ( true === $skipped_plugins ) + return true; + + return in_array( $name, array_filter( explode( ',', $skipped_plugins ) ) ); +} + diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index d43118d8d..735e54f75 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -181,7 +181,8 @@ // Load network activated plugins. if ( is_multisite() ) { foreach( wp_get_active_network_plugins() as $network_plugin ) { - include_once( $network_plugin ); + if ( !Utils\is_plugin_skipped( $network_plugin ) ) + include_once( $network_plugin ); } unset( $network_plugin ); } @@ -210,7 +211,8 @@ // Load active plugins. foreach ( wp_get_active_and_valid_plugins() as $plugin ) - include_once( $plugin ); + if ( !Utils\is_plugin_skipped( $plugin ) ) + include_once( $plugin ); unset( $plugin ); // Load pluggable functions. From dd9299f658f55ab60be5605bdce7a1251831454c Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Mon, 20 Jan 2014 21:55:38 -0800 Subject: [PATCH 2656/5359] Don't allow wp-cli as root without --allow_root --- php/WP_CLI/Runner.php | 29 +++++++++++++++++++++++++++++ php/config-spec.php | 6 ++++++ 2 files changed, 35 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 57f000a25..c14bdb05a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -396,11 +396,40 @@ private function init_config() { list( $this->config, $this->extra_config ) = $configurator->to_array(); } + private function check_root() { + if ( $this->config['allow_root'] ) + return; # they're aware of the risks! + if ( !function_exists( 'posix_geteuid') ) + return; # posix functions not available + if ( posix_geteuid() !== 0 ) + return; # not root + + WP_CLI::error( + "YIKES! It looks like you're running this as root. You probably meant to" . + "run this as the user that your WordPress install exists under.\n" . + "\n" . + "If you REALLY mean to run this as root, we won't stop you, but just " . + "bear in mind that any code on this site will then have full control of " . + "your server, making it quite DANGEROUS.\n" . + "\n" . + "If you'd like to continue as root, please run this again, adding this " . + "flag: --allow_root\n" . + "\n" . + "If you'd like to run it as the user that this site is under, you can " . + "run the following to become the respective user:\n" . + "\n" . + " su USER -c -- wp ...\n" . + "\n" + ); + } + public function before_wp_load() { $this->init_config(); $this->init_colorization(); $this->init_logger(); + $this->check_root(); + if ( empty( $this->arguments ) ) $this->arguments[] = 'help'; diff --git a/php/config-spec.php b/php/config-spec.php index d4e206e7e..e05260971 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -76,5 +76,11 @@ 'multiple' => true, 'default' => array(), ), + + 'allow_root' => array( + 'runtime' => '=<allow_root>', + 'desc' => '(NOT RECCOMENDED) Allow wp-cli to run as root. This poses a security risk, so you probably do not want to do this.', + ), + ); From ceb262aca0cabea484d3d4d87d4ae7e8b9d13d7b Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Wed, 22 Jan 2014 10:38:35 -0800 Subject: [PATCH 2657/5359] Rename --allow_root to --allow-root --- php/WP_CLI/Runner.php | 4 ++-- php/config-spec.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c14bdb05a..acb95aacc 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -397,7 +397,7 @@ private function init_config() { } private function check_root() { - if ( $this->config['allow_root'] ) + if ( $this->config['allow-root'] ) return; # they're aware of the risks! if ( !function_exists( 'posix_geteuid') ) return; # posix functions not available @@ -413,7 +413,7 @@ private function check_root() { "your server, making it quite DANGEROUS.\n" . "\n" . "If you'd like to continue as root, please run this again, adding this " . - "flag: --allow_root\n" . + "flag: --allow-root\n" . "\n" . "If you'd like to run it as the user that this site is under, you can " . "run the following to become the respective user:\n" . diff --git a/php/config-spec.php b/php/config-spec.php index e05260971..ffddb174e 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -77,8 +77,8 @@ 'default' => array(), ), - 'allow_root' => array( - 'runtime' => '=<allow_root>', + 'allow-root' => array( + 'runtime' => '=<allow-root>', 'desc' => '(NOT RECCOMENDED) Allow wp-cli to run as root. This poses a security risk, so you probably do not want to do this.', ), From 2e2cf11d6aac3663feda6661a17fb3ca520d017d Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Wed, 22 Jan 2014 21:57:19 -0800 Subject: [PATCH 2658/5359] Adjust spec for --allow-root I know file=false is the default, but were that to change at any point, having this be true could potentially compromise the system's security if wp-cli was run as root. --- php/config-spec.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/config-spec.php b/php/config-spec.php index ffddb174e..273ad5dbc 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -78,7 +78,8 @@ ), 'allow-root' => array( - 'runtime' => '=<allow-root>', + 'file' => false, # Explicit. Just in case the default changes. + 'runtime' => '', 'desc' => '(NOT RECCOMENDED) Allow wp-cli to run as root. This poses a security risk, so you probably do not want to do this.', ), From 68e7e529f54cc11bafd5671120fb9a3c7628dc9c Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Thu, 23 Jan 2014 00:18:51 -0800 Subject: [PATCH 2659/5359] Don't show --allow-root in help. It'll still be there, it just won't show up in the man pages anymore, since the "NOT RECCOMENDED" is pretty ugly. :) --- php/WP_CLI/Dispatcher/RootCommand.php | 3 +++ php/config-spec.php | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index d65c79fd4..d11a9a215 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -27,6 +27,9 @@ function get_longdesc() { if ( isset( $details['deprecated'] ) ) continue; + if ( isset( $details['hidden'] ) ) + continue; + if ( true === $details['runtime'] ) $synopsis = "--[no-]$key"; else diff --git a/php/config-spec.php b/php/config-spec.php index 273ad5dbc..811473f17 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -77,10 +77,12 @@ 'default' => array(), ), + # --allow-root => (NOT RECCOMENDED) Allow wp-cli to run as root. This poses + # a security risk, so you probably do not want to do this. 'allow-root' => array( 'file' => false, # Explicit. Just in case the default changes. 'runtime' => '', - 'desc' => '(NOT RECCOMENDED) Allow wp-cli to run as root. This poses a security risk, so you probably do not want to do this.', + 'hidden' => true, ), ); From ea0ede09a2d4facf2484637e47b802350cbf11ce Mon Sep 17 00:00:00 2001 From: Barta Akos <akos@netpositive.hu> Date: Fri, 24 Jan 2014 09:56:08 +0100 Subject: [PATCH 2660/5359] added locale to core update --- php/commands/core.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8da06b6e5..ba0e091f4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -649,6 +649,9 @@ public function version( $args = array(), $assoc_args = array() ) { * [--force] * : Will update even when current WP version < passed version. Use with * caution. + * + * [--locale=<locale>] + * : Select which language you want to download. * * ## EXAMPLES * @@ -681,7 +684,16 @@ function update( $args, $assoc_args ) { $new_package = null; if ( empty( $args[0] ) ) { - $new_package = 'https://wordpress.org/wordpress-' . $assoc_args['version'] . '.zip'; + $version = $assoc_args['version']; + $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; + + if ( 'en_US' === $locale ) { + $new_package = 'https://wordpress.org/wordpress-' . $version . '.zip'; + } else { + $new_package = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.zip', + substr( $assoc_args['locale'], 0, 2 ), $version, $locale ); + } + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); } else { $new_package = $args[0]; From 5d70ab3ff106f04089b4ea081d1333fba81ee8b8 Mon Sep 17 00:00:00 2001 From: Barta Akos <akos@netpositive.hu> Date: Fri, 24 Jan 2014 10:06:50 +0100 Subject: [PATCH 2661/5359] added locale information to core update log --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index ba0e091f4..a23c413cf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -694,7 +694,7 @@ function update( $args, $assoc_args ) { substr( $assoc_args['locale'], 0, 2 ), $version, $locale ); } - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], 'en_US' ) ); + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $locale ) ); } else { $new_package = $args[0]; $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; From 01c53b37ba6107ce3c5b1280596557c76209ab63 Mon Sep 17 00:00:00 2001 From: Barta Akos <akos@netpositive.hu> Date: Fri, 24 Jan 2014 16:39:47 +0100 Subject: [PATCH 2662/5359] get_download_url --- php/commands/core.php | 44 +++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index a23c413cf..37a7453af 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -45,12 +45,7 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { $version = $assoc_args['version']; - if ( 'en_US' === $locale ) { - $download_url = 'https://wordpress.org/wordpress-' . $version . '.tar.gz'; - } else { - $download_url = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.tar.gz', - substr( $assoc_args['locale'], 0, 2 ), $version, $locale ); - } + $download_url = $this->get_download_url($version, $locale, 'tar.gz'); } else { $offer = $this->get_download_offer( $locale ); $version = $offer['current']; @@ -684,15 +679,10 @@ function update( $args, $assoc_args ) { $new_package = null; if ( empty( $args[0] ) ) { - $version = $assoc_args['version']; - $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; + $version = $assoc_args['version']; + $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; - if ( 'en_US' === $locale ) { - $new_package = 'https://wordpress.org/wordpress-' . $version . '.zip'; - } else { - $new_package = sprintf( 'https://%s.wordpress.org/wordpress-%s-%s.zip', - substr( $assoc_args['locale'], 0, 2 ), $version, $locale ); - } + $new_package = $this->get_download_url($version, $locale); WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $locale ) ); } else { @@ -743,6 +733,32 @@ function update_db() { wp_upgrade(); WP_CLI::success( 'WordPress database upgraded successfully.' ); } + + /** + * Gets download url based on version, locale and desired file type. + * + * @param $version + * @param string $locale + * @param string $file_type + * @return string + */ + private function get_download_url($version, $locale = 'en_US', $file_type = 'zip') + { + if ('en_US' === $locale) { + $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; + + return $url; + } else { + $url = sprintf( + 'https://%s.wordpress.org/wordpress-%s-%s.' . $file_type, + substr($locale, 0, 2), + $version, + $locale + ); + + return $url; + } + } } WP_CLI::add_command( 'core', 'Core_Command' ); From 5e6757af68f260c4d5deee841025ea878efe1e4a Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Fri, 24 Jan 2014 16:52:40 -0800 Subject: [PATCH 2663/5359] Minor typo fix. --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index acb95aacc..45821a93a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -405,7 +405,7 @@ private function check_root() { return; # not root WP_CLI::error( - "YIKES! It looks like you're running this as root. You probably meant to" . + "YIKES! It looks like you're running this as root. You probably meant to " . "run this as the user that your WordPress install exists under.\n" . "\n" . "If you REALLY mean to run this as root, we won't stop you, but just " . From a2d9a813cfced612aab8614050348e92ef35c690 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 Jan 2014 16:41:09 +0200 Subject: [PATCH 2664/5359] extract replace_path_consts() utility --- php/WP_CLI/Runner.php | 14 ++++---------- php/utils.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 57f000a25..578d9bf78 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -225,14 +225,6 @@ private function _run_command() { public function get_wp_config_code() { $wp_config_path = Utils\locate_wp_config(); - $replacements = array( - '__FILE__' => "'$wp_config_path'", - '__DIR__' => "'" . dirname( $wp_config_path ) . "'" - ); - - $old = array_keys( $replacements ); - $new = array_values( $replacements ); - $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); $lines_to_run = array(); @@ -241,10 +233,12 @@ public function get_wp_config_code() { if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) continue; - $lines_to_run[] = str_replace( $old, $new, $line ); + $lines_to_run[] = $line; } - return preg_replace( '|^\s*\<\?php\s*|', '', implode( "\n", $lines_to_run ) ); + $source = implode( "\n", $lines_to_run ); + $source = Utils\replace_path_consts( $source, $wp_config_path ); + return preg_replace( '|^\s*\<\?php\s*|', '', $source ); } // Transparently convert old syntaxes diff --git a/php/utils.php b/php/utils.php index a281bd167..7ce26e81b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -382,3 +382,21 @@ function is_windows() { return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } +/** + * Replace magic constants in some PHP source code. + * + * @param string $source The PHP code to manipulate. + * @param string $path The path to use instead of the magic constants + */ +function replace_path_consts( $source, $path ) { + $replacements = array( + '__FILE__' => "'$path'", + '__DIR__' => "'" . dirname( $path ) . "'" + ); + + $old = array_keys( $replacements ); + $new = array_values( $replacements ); + + return str_replace( $old, $new, $source ); +} + From 28a163f3cb9a05c3768b1c0135012aae820bb1c1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 Jan 2014 17:05:47 +0200 Subject: [PATCH 2665/5359] make autodetection of WP files in a subdirectory work in more cases fixes #929 --- features/config.feature | 9 ++++++++- php/WP_CLI/Runner.php | 37 ++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/features/config.feature b/features/config.feature index 8720f451a..d1a1768ab 100644 --- a/features/config.feature +++ b/features/config.feature @@ -56,11 +56,18 @@ Feature: Have a config file Scenario: WP in a subdirectory (autodetected) Given a WP install in 'core' - And a index.php file: + + Given a index.php file: """ require('./core/wp-blog-header.php'); """ + When I run `wp core is-installed` + Then STDOUT should be empty + Given a index.php file: + """ + require dirname(__FILE__) . '/core/wp-blog-header.php'; + """ When I run `wp core is-installed` Then STDOUT should be empty diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 578d9bf78..81f9a86de 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -73,6 +73,30 @@ private static function get_project_config_path() { } ); } + /** + * Attempts to find the path to the WP install inside index.php + */ + private static function extract_subdir_path( $index_path ) { + if ( !file_exists( $index_path ) ) + return false; + + $index_code = file_get_contents( $index_path ); + + if ( !preg_match( '|^\s*require\s*\(?\s*(.+?)/wp-blog-header\.php([\'"])|m', $index_code, $matches ) ) { + return false; + } + + $wp_path_src = $matches[1] . $matches[2]; + $wp_path_src = Utils\replace_path_consts( $wp_path_src, $index_path ); + $wp_path = eval( "return $wp_path_src;" ); + + if ( !Utils\is_path_absolute( $wp_path ) ) { + $wp_path = dirname( $index_path ) . "/$wp_path"; + } + + return $wp_path; + } + private static function set_wp_root( $config ) { $path = getcwd(); @@ -81,17 +105,8 @@ private static function set_wp_root( $config ) { $path = $config['path']; else $path .= '/' . $config['path']; - } elseif ( file_exists( './index.php' ) ) { - $index_code = file_get_contents( './index.php' ); - - if ( preg_match( '/^\s*require.+([\'"])(.*wp-blog-header\.php)\1/m', $index_code, $matches ) ) { - $new_path = dirname( $matches[2] ); - if ( Utils\is_path_absolute( $new_path ) ) { - $path = $new_path; - } else { - $path .= '/' . $new_path; - } - } + } elseif ( $wp_path = self::extract_subdir_path( $path . '/index.php' ) ) { + $path = $wp_path; } define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); From dcdbe7768cf0baf663b5825b51ae61d424f67705 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 25 Jan 2014 17:10:33 +0200 Subject: [PATCH 2666/5359] behat: allow correct grammar --- features/config.feature | 4 ++-- features/steps/given.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/config.feature b/features/config.feature index d1a1768ab..86294e962 100644 --- a/features/config.feature +++ b/features/config.feature @@ -57,14 +57,14 @@ Feature: Have a config file Scenario: WP in a subdirectory (autodetected) Given a WP install in 'core' - Given a index.php file: + Given an index.php file: """ require('./core/wp-blog-header.php'); """ When I run `wp core is-installed` Then STDOUT should be empty - Given a index.php file: + Given an index.php file: """ require dirname(__FILE__) . '/core/wp-blog-header.php'; """ diff --git a/features/steps/given.php b/features/steps/given.php index 998a01313..a7b29d3c2 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -9,7 +9,7 @@ function ( $world ) { } ); -$steps->Given( '/^a ([^\s]+) file:$/', +$steps->Given( '/^an? ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; $full_path = $world->variables['RUN_DIR'] . "/$path"; From 5cc18ad4f74f71e9d98ea706fded00c3d834a1d5 Mon Sep 17 00:00:00 2001 From: Wesley Spikes <wesley.spikes@gmail.com> Date: Sat, 25 Jan 2014 15:20:00 -0800 Subject: [PATCH 2667/5359] Recommend sudo instead of su. --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 45821a93a..fe5ffc90b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -418,7 +418,7 @@ private function check_root() { "If you'd like to run it as the user that this site is under, you can " . "run the following to become the respective user:\n" . "\n" . - " su USER -c -- wp ...\n" . + " sudo -u USER -i -- wp ...\n" . "\n" ); } From 14eae59a79858aa553f1a1dedbb76d5df9f1f3b2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 26 Jan 2014 03:07:17 +0200 Subject: [PATCH 2668/5359] fix --max_depth= again and add behat test closes #820 see #943 --- features/post.feature | 10 +++++++++- php/commands/post.php | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/features/post.feature b/features/post.feature index df556cc7d..aaec9469b 100644 --- a/features/post.feature +++ b/features/post.feature @@ -134,4 +134,12 @@ Feature: Manage WordPress posts """ Content generated by wp post generate """ - And STDERR should be empty \ No newline at end of file + And STDERR should be empty + + Scenario: Generating pages + When I run `wp post generate --post_type=page --max_depth=10` + And I run `wp post list --post_type=page --field=post_parent` + Then STDOUT should contain: + """ + 1 + """ diff --git a/php/commands/post.php b/php/commands/post.php index b73eef053..9cae10888 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -219,8 +219,8 @@ public function delete( $args, $assoc_args ) { * wp post list --post_type=post --posts_per_page=5 --format=json * * wp post list --post_type=page --fields=post_title,post_status - * - * wp post list --post_type=page,post --format=ids + * + * wp post list --post_type=page,post --format=ids * * @subcommand list */ @@ -330,7 +330,7 @@ public function generate( $args, $assoc_args ) { if( $this->maybe_make_child() && $current_depth < $max_depth ) { - $current_parent = $post_ids[$i-1]; + $current_parent = $previous_post_id; $current_depth++; } else if( $this->maybe_reset_depth() ) { From 8e0680f7009646f4e912bae53c261ff896daaa2e Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 26 Jan 2014 13:48:34 +0200 Subject: [PATCH 2669/5359] bump version to 0.14.0-alpha2 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index a592703db..8f70c7353 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.14.0-alpha' ); +define( 'WP_CLI_VERSION', '0.14.0-alpha2' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From aef5511f1f263c830923cbce33b2a84f9ae1c85d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 Jan 2014 01:57:29 +0200 Subject: [PATCH 2670/5359] group all logic that deals with finding the WP files into a single method --- php/WP_CLI/Runner.php | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 42af9644e..b4823e10e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -97,18 +97,32 @@ private static function extract_subdir_path( $index_path ) { return $wp_path; } - private static function set_wp_root( $config ) { - $path = getcwd(); + /** + * Find the directory that contains the WordPress files. Defaults to the current working dir. + * + * @return string An absolute path + */ + private function find_wp_root() { + if ( !empty( $this->config['path'] ) ) { + $path = $this->config['path']; + if ( !Utils\is_path_absolute( $path ) ) + $path = getcwd() . '/' . $path; - if ( !empty( $config['path'] ) ) { - if ( Utils\is_path_absolute( $config['path'] ) ) - $path = $config['path']; - else - $path .= '/' . $config['path']; - } elseif ( $wp_path = self::extract_subdir_path( $path . '/index.php' ) ) { - $path = $wp_path; + return $path; } + if ( $this->cmd_starts_with( array( 'core', 'download' ) ) ) { + return getcwd(); + } + + if ( $wp_load_path = Utils\find_file_upward( 'wp-load.php' ) ) { + return dirname( $wp_load_path ); + } + + return self::extract_subdir_path( getcwd() . '/index.php' ); + } + + private static function set_wp_root( $path ) { define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); @@ -464,14 +478,7 @@ public function before_wp_load() { } // Handle --path parameter - if ( !isset( $this->config['path'] ) ) { - if ( $this->cmd_starts_with( array( 'core', 'download' ) ) ) { - $this->config['path'] = getcwd(); - } else { - $this->config['path'] = dirname( Utils\find_file_upward( 'wp-load.php' ) ); - } - } - self::set_wp_root( $this->config ); + self::set_wp_root( $this->find_wp_root() ); // First try at showing man page if ( 'help' === $this->arguments[0] && ( isset( $this->arguments[1] ) || !$this->wp_exists() ) ) { From 719097b1cf4b7a15325c8cc20deb53634ba9a5a6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 Jan 2014 02:09:45 +0200 Subject: [PATCH 2671/5359] allow WP-CLI to be invoked from subdirectories other than the subdir the WP files are in --- features/config.feature | 8 ++++++++ php/WP_CLI/Runner.php | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/config.feature b/features/config.feature index 86294e962..f3021ecbc 100644 --- a/features/config.feature +++ b/features/config.feature @@ -54,6 +54,10 @@ Feature: Have a config file When I run `wp core is-installed` from 'core/wp-content' Then STDOUT should be empty + When I run `mkdir -p other/subdir` + And I run `wp core is-installed` from 'other/subdir' + Then STDOUT should be empty + Scenario: WP in a subdirectory (autodetected) Given a WP install in 'core' @@ -71,6 +75,10 @@ Feature: Have a config file When I run `wp core is-installed` Then STDOUT should be empty + When I run `mkdir -p other/subdir` + And I run `wp core is-installed` from 'other/subdir' + Then STDOUT should be empty + Scenario: Nested installs Given a WP install And a WP install in 'subsite' diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b4823e10e..6abb09a13 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -119,7 +119,7 @@ private function find_wp_root() { return dirname( $wp_load_path ); } - return self::extract_subdir_path( getcwd() . '/index.php' ); + return self::extract_subdir_path( Utils\find_file_upward( 'index.php' ) ); } private static function set_wp_root( $path ) { From f3aaf4ba83e383d4ac00eb98fc2b1f020ff39b95 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 Jan 2014 02:36:20 +0200 Subject: [PATCH 2672/5359] continue searching after finding an index.php that doesn't contain the path to wp-blog-header.php --- features/config.feature | 1 + php/WP_CLI/Runner.php | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/features/config.feature b/features/config.feature index f3021ecbc..b103ef73b 100644 --- a/features/config.feature +++ b/features/config.feature @@ -76,6 +76,7 @@ Feature: Have a config file Then STDOUT should be empty When I run `mkdir -p other/subdir` + And I run `echo '<?php // Silence is golden' > other/subdir/index.php` And I run `wp core is-installed` from 'other/subdir' Then STDOUT should be empty diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6abb09a13..d43b2c75e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -77,9 +77,6 @@ private static function get_project_config_path() { * Attempts to find the path to the WP install inside index.php */ private static function extract_subdir_path( $index_path ) { - if ( !file_exists( $index_path ) ) - return false; - $index_code = file_get_contents( $index_path ); if ( !preg_match( '|^\s*require\s*\(?\s*(.+?)/wp-blog-header\.php([\'"])|m', $index_code, $matches ) ) { @@ -115,11 +112,24 @@ private function find_wp_root() { return getcwd(); } - if ( $wp_load_path = Utils\find_file_upward( 'wp-load.php' ) ) { - return dirname( $wp_load_path ); - } + $dir = getcwd(); + + while ( is_readable( $dir ) ) { + if ( file_exists( "$dir/wp-load.php" ) ) { + return $dir; + } - return self::extract_subdir_path( Utils\find_file_upward( 'index.php' ) ); + if ( file_exists( "$dir/index.php" ) ) { + if ( $path = self::extract_subdir_path( "$dir/index.php" ) ) + return $path; + } + + $parent_dir = dirname( $dir ); + if ( empty($parent_dir) || $parent_dir === $dir ) { + break; + } + $dir = $parent_dir; + } } private static function set_wp_root( $path ) { From ff2ef21d352151d8f4739aaff8322a18968e8295 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 Jan 2014 03:32:54 +0200 Subject: [PATCH 2673/5359] allow reading values from STDIN for `wp option` and 'wp *-meta` subcommands --- features/option.feature | 19 +++++++++++++++++ features/post-meta.feature | 7 ++++++ php/WP_CLI/CommandWithMeta.php | 35 ++++++++++++++++++++++++++---- php/class-wp-cli.php | 25 +++++++++++++++++++++- php/commands/option.php | 39 ++++++++++++++++++++++++++++++---- 5 files changed, 116 insertions(+), 9 deletions(-) diff --git a/features/option.feature b/features/option.feature index 28ea9a8c4..ee9a7a509 100644 --- a/features/option.feature +++ b/features/option.feature @@ -46,3 +46,22 @@ Feature: Manage WordPress options """ [1,2] """ + + + # Reading from files + Given a value.json file: + """ + { + "foo": "bar", + "list": [1, 2, 3] + } + """ + When I run `wp option set foo --format=json < value.json` + And I run `wp option get foo --format=json` + Then STDOUT should be JSON containing: + """ + { + "foo": "bar", + "list": [1, 2, 3] + } + """ diff --git a/features/post-meta.feature b/features/post-meta.feature index b756062a9..b1daf1bba 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -21,6 +21,13 @@ Feature: Manage post custom fields ["1","2"] """ + When I run `echo 'via STDIN' | wp post-meta set 1 foo` + And I run `wp post-meta get 1 foo` + Then STDOUT should be: + """ + via STDIN + """ + When I run `wp post-meta delete 1 foo` Then STDOUT should not be empty diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 6695d1e51..f09d9fbcd 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -47,12 +47,25 @@ public function delete( $args, $assoc_args ) { /** * Add a meta field. * - * @synopsis <id> <key> <value> [--format=<format>] + * ## OPTIONS + * + * <id> + * : The ID of the object. + * + * <key> + * : The name of the meta field to create. + * + * [<value>] + * : The value of the meta field. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. */ public function add( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $meta_value = \WP_CLI::read_value( $args[2], $assoc_args ); + $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); + $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); $success = \add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); @@ -66,13 +79,27 @@ public function add( $args, $assoc_args ) { /** * Update a meta field. * + * ## OPTIONS + * + * <id> + * : The ID of the object. + * + * <key> + * : The name of the meta field to update. + * + * [<value>] + * : The new value. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * * @alias set - * @synopsis <id> <key> <value> [--format=<format>] */ public function update( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $meta_value = \WP_CLI::read_value( $args[2], $assoc_args ); + $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); + $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 066486954..88db5d790 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -234,7 +234,30 @@ static function confirm( $question, $assoc_args = array() ) { } /** - * Read a value, from various formats + * Read value from a positional argument or from STDIN. + * + * @param array $args The list of positional arguments. + * @param int $index At which position to check for the value. + * + * @return string + */ + public static function get_value_from_arg_or_stdin( $args, $index ) { + if ( isset( $args[ $index ] ) ) { + $raw_value = $args[ $index ]; + } else { + // We don't use file_get_contents() here because it doesn't handle + // Ctrl-D properly, when typing in the value interactively. + $raw_value = ''; + while ( ( $line = fgets( STDIN ) ) !== false ) { + $raw_value .= $line; + } + } + + return $raw_value; + } + + /** + * Read a value, from various formats. * * @param mixed $value * @param array $assoc_args diff --git a/php/commands/option.php b/php/commands/option.php index 1c4c66095..f5e025860 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -39,12 +39,27 @@ public function get( $args, $assoc_args ) { /** * Add an option. * - * @synopsis <key> <value> [--format=<format>] + * ## OPTIONS + * + * <key> + * : The name of the option to add. + * + * [<value>] + * : The value of the option to add. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * + * ## EXAMPLES + * + * # Create an option by reading a JSON file + * wp option add my_option --format=json < config.json */ public function add( $args, $assoc_args ) { $key = $args[0]; - $value = WP_CLI::read_value( $args[1], $assoc_args ); + $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); + $value = WP_CLI::read_value( $value, $assoc_args ); if ( !add_option( $key, $value ) ) { WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); @@ -56,13 +71,29 @@ public function add( $args, $assoc_args ) { /** * Update an option. * + * ## OPTIONS + * + * <key> + * : The name of the option to add. + * + * [<value>] + * : The new value. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * + * ## EXAMPLES + * + * # Update an option by reading from a file + * wp option update my_option < value.txt + * * @alias set - * @synopsis <key> <value> [--format=<format>] */ public function update( $args, $assoc_args ) { $key = $args[0]; - $value = WP_CLI::read_value( $args[1], $assoc_args ); + $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); + $value = WP_CLI::read_value( $value, $assoc_args ); $result = update_option( $key, $value ); From 656d32f51369cffe1ca3cb0181ce878f694faeda Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Thu, 30 Jan 2014 22:16:13 -0500 Subject: [PATCH 2674/5359] Define $role variable in User_Command::generate() This fixes role-setting when generating users. --- php/commands/user.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index e747d7b47..0ac77e767 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -276,7 +276,9 @@ public function generate( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - if ( !self::validate_role( $assoc_args['role'] ) ) { + $role = $assoc_args['role']; + + if ( !self::validate_role( $role ) ) { WP_CLI::error( "Invalid role: $role" ); } From aa74cb83189b473bec106d06015fde6252023ea8 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 31 Jan 2014 14:57:51 +0200 Subject: [PATCH 2675/5359] stop looking for deprecated wp-cli-blog file rationale: - it makes an extra access(2) syscall on each run - it's been deprecated for many versions --- php/WP_CLI/Runner.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index d43b2c75e..c701d2646 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -158,10 +158,6 @@ private static function guess_url( $assoc_args ) { if ( true === $url ) { WP_CLI::warning( 'The --url parameter expects a value.' ); } - } elseif ( is_readable( ABSPATH . 'wp-cli-blog' ) ) { - WP_CLI::warning( 'The wp-cli-blog file is deprecated. Use wp-cli.yml instead.' ); - - $url = trim( file_get_contents( ABSPATH . 'wp-cli-blog' ) ); } elseif ( $wp_config_path = Utils\locate_wp_config() ) { // Try to find the blog parameter in the wp-config file $wp_config_file = file_get_contents( $wp_config_path ); From 6286442ea6943f8f2318033a1d1b9596f87f36f6 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 1 Feb 2014 22:52:35 +0200 Subject: [PATCH 2676/5359] fix notice in find_item_by_key() --- php/WP_CLI/Formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 6f971b28b..7d3eacc0b 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -125,7 +125,7 @@ private function find_item_key( $item, $field ) { } } - if ( ! $key ) { + if ( ! isset( $key ) ) { \WP_CLI::error( "Invalid field: $field." ); } From 75a6a0c4f3619453afafca5ddc9d96e6299d37da Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 1 Feb 2014 22:58:11 +0200 Subject: [PATCH 2677/5359] add Behat test for #985 --- features/user.feature | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index 99aa75990..f25333519 100644 --- a/features/user.feature +++ b/features/user.feature @@ -48,8 +48,14 @@ Feature: Manage WordPress users Then STDOUT should not be empty Scenario: Generating and deleting users - When I run `wp user generate --count=9` - And I run `wp user list --format=count` + When I run `wp user list --role=editor --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp user generate --count=10 --role=editor` + And I run `wp user list --role=editor --format=count` Then STDOUT should be: """ 10 From e614cb569c631cc7fc29c4774b50fe69efa5e06a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 1 Feb 2014 23:52:19 +0200 Subject: [PATCH 2678/5359] make local plugin lookup case-sensitive the old lookup method returned false positives on case-insensitive filesystems (plugin basenames are treated as case-sensitive by WordPress) fixes #958 --- features/plugin.feature | 37 ++++++++++++++++++++-------------- php/WP_CLI/Fetchers/Plugin.php | 26 ++++-------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index f198ebb9a..4bbd84cde 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -22,17 +22,24 @@ Feature: Manage WordPress plugins {PLUGIN_DIR}/plugin1 """ - When I run `wp plugin scaffold zombieland --plugin_name="Zombieland"` + When I run `wp plugin scaffold Zombieland` Then STDOUT should not be empty - And the {PLUGIN_DIR}/zombieland/zombieland.php file should exist - And the {PLUGIN_DIR}/zombieland/phpunit.xml file should exist + And the {PLUGIN_DIR}/Zombieland/Zombieland.php file should exist + And the {PLUGIN_DIR}/Zombieland/phpunit.xml file should exist + + # Ensure case sensitivity + When I try `wp plugin status zombieLand` + Then STDERR should contain: + """ + The 'zombieLand' plugin could not be found. + """ # Check that the inner-plugin is not picked up - When I run `mv {PLUGIN_DIR}/plugin1 {PLUGIN_DIR}/zombieland/` - And I run `wp plugin status zombieland` + When I run `mv {PLUGIN_DIR}/plugin1 {PLUGIN_DIR}/Zombieland/` + And I run `wp plugin status Zombieland` Then STDOUT should contain: """ - Plugin zombieland details: + Plugin Zombieland details: Name: Zombieland Status: Inactive Version: 0.1-alpha @@ -40,10 +47,10 @@ Feature: Manage WordPress plugins Description: PLUGIN DESCRIPTION HERE """ - When I run `wp plugin activate zombieland` + When I run `wp plugin activate Zombieland` Then STDOUT should not be empty - When I run `wp plugin status zombieland` + When I run `wp plugin status Zombieland` Then STDOUT should contain: """ Status: Active @@ -55,28 +62,28 @@ Feature: Manage WordPress plugins When I run `wp plugin list` Then STDOUT should be a table containing rows: | name | status | update | version | - | zombieland | active | none | 0.1-alpha | + | Zombieland | active | none | 0.1-alpha | - When I try `wp plugin uninstall zombieland` + When I try `wp plugin uninstall Zombieland` Then STDERR should contain: """ - The 'zombieland' plugin is active. + The 'Zombieland' plugin is active. """ - When I run `wp plugin deactivate zombieland` + When I run `wp plugin deactivate Zombieland` Then STDOUT should not be empty - When I run `wp plugin uninstall zombieland` + When I run `wp plugin uninstall Zombieland` Then STDOUT should contain: """ - Success: Uninstalled 'zombieland' plugin. + Success: Uninstalled 'Zombieland' plugin. """ And the {PLUGIN_DIR}/zombieland file should not exist When I try the previous command again Then STDERR should contain: """ - The 'zombieland' plugin could not be found. + The 'Zombieland' plugin could not be found. """ Scenario: Install a plugin, activate, then force install an older version of the plugin diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php index f59672570..37f3e10a0 100644 --- a/php/WP_CLI/Fetchers/Plugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -7,31 +7,13 @@ class Plugin extends Base { protected $msg = "The '%s' plugin could not be found."; public function get( $name ) { - $plugins = get_plugins( '/' . $name ); - - // some-plugin/the-plugin.php - while ( !empty( $plugins ) ) { - $file = key( $plugins ); - array_shift( $plugins ); - - // ignore files inside a plugin's subdirectory (like WP does) - if ( dirname( $file ) == '.' ) { - return (object) array( - 'name' => $name, - 'file' => $name . '/' . $file - ); + foreach ( get_plugins() as $file => $_ ) { + if ( $file === "$name.php" || + ( dirname( $file ) === $name && $name !== '.' ) ) { + return (object) compact( 'name', 'file' ); } } - // some-plugin.php - $file = $name . '.php'; - - $plugins = get_plugins(); - - if ( isset( $plugins[ $file ] ) ) { - return (object) compact( 'name', 'file' ); - } - return false; } } From ab09a3d3adb5c6e23e3fb6830ebd5b5dd7e7c9f0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Feb 2014 00:45:07 +0200 Subject: [PATCH 2679/5359] switch to wp-cli/php-cli-tools:dev-master it contains https://github.com/wp-cli/php-cli-tools/commit/6079f27981a5dd91be6ff9f19643a7278dcdfbbb which fixes #947 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index aa1ed6271..ab68a433c 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.9.3", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 6aeee0f26c0fa4dabb42cb2a76aacde9dc023af1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Feb 2014 01:16:29 +0200 Subject: [PATCH 2680/5359] bump version to 0.14.0-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 8f70c7353..c9667d94b 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,7 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.14.0-alpha2' ); +define( 'WP_CLI_VERSION', '0.14.0-beta' ); include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; From 6f2367be725fd3aab27276ac616f37a2834805a3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Feb 2014 15:18:59 +0200 Subject: [PATCH 2681/5359] fix deploy script log from Travis CI: error: Malformed value for push.default: simple error: Must be one of nothing, matching, tracking or current. --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index a88cba3ba..e3b17b39f 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -28,7 +28,7 @@ cd builds git config user.name "Travis CI" git config user.email "travis@travis-ci.org" -git config push.default "simple" +git config push.default "current" mv $WP_CLI_BIN_DIR/wp phar/wp-cli-nightly.phar chmod -x phar/wp-cli-nightly.phar From b9be949426932aca1c1e9f07d8ddd3a2a8270031 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 3 Feb 2014 22:41:46 +0200 Subject: [PATCH 2682/5359] always set common HTTP headers; closes #989 --- php/class-wp-cli.php | 3 --- php/wp-cli.php | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 88db5d790..b44d1efb0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -108,9 +108,6 @@ private static function set_url_params( $url_parts ) { $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; $_SERVER['QUERY_STRING'] = $f('query'); - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; - $_SERVER['HTTP_USER_AGENT'] = ''; - $_SERVER['REQUEST_METHOD'] = 'GET'; } /** diff --git a/php/wp-cli.php b/php/wp-cli.php index c9667d94b..04277e019 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,9 +2,14 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); - define( 'WP_CLI_VERSION', '0.14.0-beta' ); +// Set common headers, to prevent warnings from plugins +$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; +$_SERVER['HTTP_USER_AGENT'] = ''; +$_SERVER['REQUEST_METHOD'] = 'GET'; +$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + include WP_CLI_ROOT . '/php/utils.php'; include WP_CLI_ROOT . '/php/dispatcher.php'; include WP_CLI_ROOT . '/php/class-wp-cli.php'; From fbef65891cd7e6205d69cbcf7001294b89d7d948 Mon Sep 17 00:00:00 2001 From: Alexei Yuzhakov <ayuzhakov@parallels.com> Date: Wed, 5 Feb 2014 13:05:45 +0700 Subject: [PATCH 2683/5359] Ability to obtain titles and descriptions for plugins and themes using list command. --- php/commands/plugin.php | 2 ++ php/commands/theme.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1d90b756e..095325c33 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -316,6 +316,8 @@ protected function get_item_list() { 'update_package' => $update_info['package'], 'version' => $details['Version'], 'update_id' => $file, + 'title' => $details['Name'], + 'description' => $details['Description'], ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 45df5cab7..c0d72003d 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -312,6 +312,8 @@ protected function get_item_list() { 'update_package' => $update_info['package'], 'version' => $theme->get('Version'), 'update_id' => $theme->get_stylesheet(), + 'title' => $theme->get('Name'), + 'description' => $theme->get('Description'), ); if ( is_multisite() ) { From 8bdd907bc72d1875922e3b1359f499d7efb468ed Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 00:59:36 +0200 Subject: [PATCH 2684/5359] switch php-cli-tools to a tag --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ab68a433c..19bceac58 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "wp-cli-0.14.0", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 56f55d720b657f52c3a00a3cf8c395f98f5182bd Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 01:06:34 +0200 Subject: [PATCH 2685/5359] switch php-cli-tools to 0.9.4-patch46 see #947 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 19bceac58..0dbcad2cf 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "wp-cli-0.14.0", + "wp-cli/php-cli-tools": "0.9.4-patch46", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From e9d700f3b5a407e23b79f67b06c0b7abd1eb39dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 02:00:31 +0200 Subject: [PATCH 2686/5359] map contributors for 0.14 release --- .mailmap | 7 +++++++ utils/contrib-list | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index eaec314b5..0086f7198 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,8 @@ andreascreten <andreas@madewithlove.be> +bartaakos <akos@netpositive.hu> bendoh <ben@thinkoomph.com> BoiteAWeb <juliobosk@gmail.com> +boonebgorges <boonebgorges@gmail.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> conatus <alex@recordsonribs.com> @@ -20,6 +22,7 @@ future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> +itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> @@ -36,6 +39,7 @@ leewillis77 <leewillis77@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> +mboynes <mboynes@alleyinteractive.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> milesj <mileswjohnson@gmail.com> @@ -59,8 +63,10 @@ roelven <roel@soundcloud.com> ryanduff <ryan@fusionized.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> +sibprogrammer <ayuzhakov@parallels.com> simonwheatley <simonw@codeforthepeople.com> soulou <leo@soulou.fr> +SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> @@ -78,3 +84,4 @@ twratajczak <tomasz.ratajczak@espeo.pl> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> wopr42 <john@zippykid.com> +ziz <justin@crowdfavorite.com> diff --git a/utils/contrib-list b/utils/contrib-list index 6d0e0897e..f3c887b84 100755 --- a/utils/contrib-list +++ b/utils/contrib-list @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ $# -lt 1 ]; then - echo "usage: $(basename $0) v0.8.0..v0.9.0 [-l]" + echo "usage: $(basename $0) v0.8.0..master [-l]" exit 1 fi From 7926fba978ae901758a7794ff0352197e2624647 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 02:02:26 +0200 Subject: [PATCH 2687/5359] bump version to 0.14.0 --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 04277e019..8b35616ce 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.14.0-beta' ); +define( 'WP_CLI_VERSION', '0.14.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 75656a4740d5093356a8c5d4d28933de6ab3940c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 18:39:39 +0200 Subject: [PATCH 2688/5359] pass allow-root along in launch_self() fixes #997 --- php/class-wp-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b44d1efb0..e5900ce0b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -341,6 +341,7 @@ static function launch_self( $command, $args = array(), $assoc_args = array(), $ 'path', 'url', 'user', + 'allow-root', ); foreach ( $reused_runtime_args as $key ) { From 6b90c20266906632199ea819c0adff780fba331d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 6 Feb 2014 18:40:23 +0200 Subject: [PATCH 2689/5359] bump version to 0.14.1-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 8b35616ce..e9976b54e 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.14.0' ); +define( 'WP_CLI_VERSION', '0.14.1-alpha' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 6857028f237537c95509e89f00ae433cb842efb4 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 12:30:43 -0800 Subject: [PATCH 2690/5359] Add `wp role reset` - resets any given default role to default capabilities --- php/commands/role.php | 172 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/php/commands/role.php b/php/commands/role.php index 896bc0f48..cd08a9892 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -139,6 +139,178 @@ public function delete( $args ) { } + /** + * Reset any default role to default capabilities. + * + * ## OPTIONS + * + * <role-key> + * : The internal name of the role. + * + * ## EXAMPLES + * + * wp role reset administrator + * + * wp role reset author + */ + public function reset( $args ) { + + self::persistence_check(); + + $role_key = array_shift( $args ); + + if ( empty( $role_key ) || ! in_array($role_key, array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ) ) ) + WP_CLI::error( "Role key not provided, or is invalid." ); + + if ( $role_key == 'administrator') { + remove_role( $role_key ); + add_role('administrator', 'Administrator'); + $role = get_role('administrator'); + $role->add_cap('switch_themes'); + $role->add_cap('edit_themes'); + $role->add_cap('activate_plugins'); + $role->add_cap('edit_plugins'); + $role->add_cap('edit_users'); + $role->add_cap('edit_files'); + $role->add_cap('manage_options'); + $role->add_cap('moderate_comments'); + $role->add_cap('manage_categories'); + $role->add_cap('manage_links'); + $role->add_cap('upload_files'); + $role->add_cap('import'); + $role->add_cap('unfiltered_html'); + $role->add_cap('edit_posts'); + $role->add_cap('edit_others_posts'); + $role->add_cap('edit_published_posts'); + $role->add_cap('publish_posts'); + $role->add_cap('edit_pages'); + $role->add_cap('read'); + $role->add_cap('level_10'); + $role->add_cap('level_9'); + $role->add_cap('level_8'); + $role->add_cap('level_7'); + $role->add_cap('level_6'); + $role->add_cap('level_5'); + $role->add_cap('level_4'); + $role->add_cap('level_3'); + $role->add_cap('level_2'); + $role->add_cap('level_1'); + $role->add_cap('level_0'); + $role->add_cap('edit_others_pages'); + $role->add_cap('edit_published_pages'); + $role->add_cap('publish_pages'); + $role->add_cap('delete_pages'); + $role->add_cap('delete_others_pages'); + $role->add_cap('delete_published_pages'); + $role->add_cap('delete_posts'); + $role->add_cap('delete_others_posts'); + $role->add_cap('delete_published_posts'); + $role->add_cap('delete_private_posts'); + $role->add_cap('edit_private_posts'); + $role->add_cap('read_private_posts'); + $role->add_cap('delete_private_pages'); + $role->add_cap('edit_private_pages'); + $role->add_cap('read_private_pages'); + $role->add_cap('delete_users'); + $role->add_cap('create_users'); + $role->add_cap( 'unfiltered_upload' ); + $role->add_cap( 'edit_dashboard' ); + $role->add_cap( 'update_plugins' ); + $role->add_cap( 'delete_plugins' ); + $role->add_cap( 'install_plugins' ); + $role->add_cap( 'update_themes' ); + $role->add_cap( 'install_themes' ); + $role->add_cap( 'update_core' ); + $role->add_cap( 'list_users' ); + $role->add_cap( 'remove_users' ); + + // Never used, will be removed. create_users or + // promote_users is the capability you're looking for. + $role->add_cap( 'add_users' ); + + $role->add_cap( 'promote_users' ); + $role->add_cap( 'edit_theme_options' ); + $role->add_cap( 'delete_themes' ); + $role->add_cap( 'export' ); + + } + if ( 'editor' == $role_key ) { + remove_role( $role_key ); + add_role('editor', 'Editor'); + $role = get_role('editor'); + $role->add_cap('moderate_comments'); + $role->add_cap('manage_categories'); + $role->add_cap('manage_links'); + $role->add_cap('upload_files'); + $role->add_cap('unfiltered_html'); + $role->add_cap('edit_posts'); + $role->add_cap('edit_others_posts'); + $role->add_cap('edit_published_posts'); + $role->add_cap('publish_posts'); + $role->add_cap('edit_pages'); + $role->add_cap('read'); + $role->add_cap('level_7'); + $role->add_cap('level_6'); + $role->add_cap('level_5'); + $role->add_cap('level_4'); + $role->add_cap('level_3'); + $role->add_cap('level_2'); + $role->add_cap('level_1'); + $role->add_cap('level_0'); + $role->add_cap('edit_others_pages'); + $role->add_cap('edit_published_pages'); + $role->add_cap('publish_pages'); + $role->add_cap('delete_pages'); + $role->add_cap('delete_others_pages'); + $role->add_cap('delete_published_pages'); + $role->add_cap('delete_posts'); + $role->add_cap('delete_others_posts'); + $role->add_cap('delete_published_posts'); + $role->add_cap('delete_private_posts'); + $role->add_cap('edit_private_posts'); + $role->add_cap('read_private_posts'); + $role->add_cap('delete_private_pages'); + $role->add_cap('edit_private_pages'); + $role->add_cap('read_private_pages'); + + } + if ( 'author' == $role_key ) { + remove_role( $role_key ); + add_role('author', 'Author'); + $role = get_role('author'); + $role->add_cap('upload_files'); + $role->add_cap('edit_posts'); + $role->add_cap('edit_published_posts'); + $role->add_cap('publish_posts'); + $role->add_cap('read'); + $role->add_cap('level_2'); + $role->add_cap('level_1'); + $role->add_cap('level_0'); + $role->add_cap('delete_posts'); + $role->add_cap('delete_published_posts'); + } + if ( 'contributor' == $role_key ) { + remove_role( $role_key ); + add_role('contributor', 'Contributor'); + $role = get_role('contributor'); + $role->add_cap('edit_posts'); + $role->add_cap('read'); + $role->add_cap('level_1'); + $role->add_cap('level_0'); + $role->add_cap('delete_posts'); + } + if ( 'subscriber' == $role_key ) { + remove_role( $role_key ); + add_role('subscriber', 'Subscriber'); + $role = get_role('subscriber'); + $role->add_cap('read'); + $role->add_cap('level_0'); + } + + WP_CLI::success( sprintf( "Role with key %s reset.", $role_key ) ); + + } + private static function persistence_check() { global $wp_roles; From 3c086188abbfbeb79d175b763a8e236dc163b756 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 15:33:56 -0800 Subject: [PATCH 2691/5359] formatting cleanup --- php/commands/role.php | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index cd08a9892..df7f6a0c5 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -213,25 +213,23 @@ public function reset( $args ) { $role->add_cap('read_private_pages'); $role->add_cap('delete_users'); $role->add_cap('create_users'); - $role->add_cap( 'unfiltered_upload' ); - $role->add_cap( 'edit_dashboard' ); - $role->add_cap( 'update_plugins' ); - $role->add_cap( 'delete_plugins' ); - $role->add_cap( 'install_plugins' ); - $role->add_cap( 'update_themes' ); - $role->add_cap( 'install_themes' ); - $role->add_cap( 'update_core' ); - $role->add_cap( 'list_users' ); - $role->add_cap( 'remove_users' ); - - // Never used, will be removed. create_users or - // promote_users is the capability you're looking for. - $role->add_cap( 'add_users' ); - + $role->add_cap('unfiltered_upload'); + $role->add_cap('edit_dashboard'); + $role->add_cap('update_plugins'); + $role->add_cap('delete_plugins'); + $role->add_cap('install_plugins'); + $role->add_cap('update_themes'); + $role->add_cap('install_themes'); + $role->add_cap('update_core'); + $role->add_cap('list_users'); + $role->add_cap('remove_users'); $role->add_cap( 'promote_users' ); $role->add_cap( 'edit_theme_options' ); $role->add_cap( 'delete_themes' ); $role->add_cap( 'export' ); + // Never used, will be removed. create_users or + // promote_users is the capability you're looking for. + $role->add_cap( 'add_users' ); } if ( 'editor' == $role_key ) { From b62050002f7252143f695859291de80dae91ef15 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 16:19:35 -0800 Subject: [PATCH 2692/5359] switch instead of ifs --- php/commands/role.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index df7f6a0c5..6e47adc2b 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -154,15 +154,17 @@ public function delete( $args ) { * wp role reset author */ public function reset( $args ) { + global $wp_roles; self::persistence_check(); $role_key = array_shift( $args ); - if ( empty( $role_key ) || ! in_array($role_key, array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ) ) ) + if ( empty( $role_key ) ) WP_CLI::error( "Role key not provided, or is invalid." ); - if ( $role_key == 'administrator') { + switch ( $role_key ) { + case 'administrator': remove_role( $role_key ); add_role('administrator', 'Administrator'); $role = get_role('administrator'); @@ -230,9 +232,9 @@ public function reset( $args ) { // Never used, will be removed. create_users or // promote_users is the capability you're looking for. $role->add_cap( 'add_users' ); + break; - } - if ( 'editor' == $role_key ) { + case 'editor': remove_role( $role_key ); add_role('editor', 'Editor'); $role = get_role('editor'); @@ -270,9 +272,9 @@ public function reset( $args ) { $role->add_cap('delete_private_pages'); $role->add_cap('edit_private_pages'); $role->add_cap('read_private_pages'); + break; - } - if ( 'author' == $role_key ) { + case 'author': remove_role( $role_key ); add_role('author', 'Author'); $role = get_role('author'); @@ -286,8 +288,9 @@ public function reset( $args ) { $role->add_cap('level_0'); $role->add_cap('delete_posts'); $role->add_cap('delete_published_posts'); - } - if ( 'contributor' == $role_key ) { + break; + + case 'contributor': remove_role( $role_key ); add_role('contributor', 'Contributor'); $role = get_role('contributor'); @@ -296,13 +299,19 @@ public function reset( $args ) { $role->add_cap('level_1'); $role->add_cap('level_0'); $role->add_cap('delete_posts'); - } - if ( 'subscriber' == $role_key ) { + break; + + case 'subscriber': remove_role( $role_key ); add_role('subscriber', 'Subscriber'); $role = get_role('subscriber'); $role->add_cap('read'); $role->add_cap('level_0'); + break; + + default: + WP_CLI::error( 'Must specify a default role to reset.' ); + } WP_CLI::success( sprintf( "Role with key %s reset.", $role_key ) ); From 380165285c2d26b843bbc242a14e640d6fbaa648 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 16:22:30 -0800 Subject: [PATCH 2693/5359] global not needed in command --- php/commands/role.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 6e47adc2b..78f9649f1 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -154,7 +154,6 @@ public function delete( $args ) { * wp role reset author */ public function reset( $args ) { - global $wp_roles; self::persistence_check(); From c5bdf2d9be85b3cab32202c05e53b31c28c5194d Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 18:21:56 -0800 Subject: [PATCH 2694/5359] Reset without hard-coded list of caps. Add reset all option --- php/commands/role.php | 200 +++++++++++------------------------------- 1 file changed, 53 insertions(+), 147 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 78f9649f1..7732612ed 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -162,155 +162,61 @@ public function reset( $args ) { if ( empty( $role_key ) ) WP_CLI::error( "Role key not provided, or is invalid." ); - switch ( $role_key ) { - case 'administrator': - remove_role( $role_key ); - add_role('administrator', 'Administrator'); - $role = get_role('administrator'); - $role->add_cap('switch_themes'); - $role->add_cap('edit_themes'); - $role->add_cap('activate_plugins'); - $role->add_cap('edit_plugins'); - $role->add_cap('edit_users'); - $role->add_cap('edit_files'); - $role->add_cap('manage_options'); - $role->add_cap('moderate_comments'); - $role->add_cap('manage_categories'); - $role->add_cap('manage_links'); - $role->add_cap('upload_files'); - $role->add_cap('import'); - $role->add_cap('unfiltered_html'); - $role->add_cap('edit_posts'); - $role->add_cap('edit_others_posts'); - $role->add_cap('edit_published_posts'); - $role->add_cap('publish_posts'); - $role->add_cap('edit_pages'); - $role->add_cap('read'); - $role->add_cap('level_10'); - $role->add_cap('level_9'); - $role->add_cap('level_8'); - $role->add_cap('level_7'); - $role->add_cap('level_6'); - $role->add_cap('level_5'); - $role->add_cap('level_4'); - $role->add_cap('level_3'); - $role->add_cap('level_2'); - $role->add_cap('level_1'); - $role->add_cap('level_0'); - $role->add_cap('edit_others_pages'); - $role->add_cap('edit_published_pages'); - $role->add_cap('publish_pages'); - $role->add_cap('delete_pages'); - $role->add_cap('delete_others_pages'); - $role->add_cap('delete_published_pages'); - $role->add_cap('delete_posts'); - $role->add_cap('delete_others_posts'); - $role->add_cap('delete_published_posts'); - $role->add_cap('delete_private_posts'); - $role->add_cap('edit_private_posts'); - $role->add_cap('read_private_posts'); - $role->add_cap('delete_private_pages'); - $role->add_cap('edit_private_pages'); - $role->add_cap('read_private_pages'); - $role->add_cap('delete_users'); - $role->add_cap('create_users'); - $role->add_cap('unfiltered_upload'); - $role->add_cap('edit_dashboard'); - $role->add_cap('update_plugins'); - $role->add_cap('delete_plugins'); - $role->add_cap('install_plugins'); - $role->add_cap('update_themes'); - $role->add_cap('install_themes'); - $role->add_cap('update_core'); - $role->add_cap('list_users'); - $role->add_cap('remove_users'); - $role->add_cap( 'promote_users' ); - $role->add_cap( 'edit_theme_options' ); - $role->add_cap( 'delete_themes' ); - $role->add_cap( 'export' ); - // Never used, will be removed. create_users or - // promote_users is the capability you're looking for. - $role->add_cap( 'add_users' ); - break; - - case 'editor': - remove_role( $role_key ); - add_role('editor', 'Editor'); - $role = get_role('editor'); - $role->add_cap('moderate_comments'); - $role->add_cap('manage_categories'); - $role->add_cap('manage_links'); - $role->add_cap('upload_files'); - $role->add_cap('unfiltered_html'); - $role->add_cap('edit_posts'); - $role->add_cap('edit_others_posts'); - $role->add_cap('edit_published_posts'); - $role->add_cap('publish_posts'); - $role->add_cap('edit_pages'); - $role->add_cap('read'); - $role->add_cap('level_7'); - $role->add_cap('level_6'); - $role->add_cap('level_5'); - $role->add_cap('level_4'); - $role->add_cap('level_3'); - $role->add_cap('level_2'); - $role->add_cap('level_1'); - $role->add_cap('level_0'); - $role->add_cap('edit_others_pages'); - $role->add_cap('edit_published_pages'); - $role->add_cap('publish_pages'); - $role->add_cap('delete_pages'); - $role->add_cap('delete_others_pages'); - $role->add_cap('delete_published_pages'); - $role->add_cap('delete_posts'); - $role->add_cap('delete_others_posts'); - $role->add_cap('delete_published_posts'); - $role->add_cap('delete_private_posts'); - $role->add_cap('edit_private_posts'); - $role->add_cap('read_private_posts'); - $role->add_cap('delete_private_pages'); - $role->add_cap('edit_private_pages'); - $role->add_cap('read_private_pages'); - break; - - case 'author': - remove_role( $role_key ); - add_role('author', 'Author'); - $role = get_role('author'); - $role->add_cap('upload_files'); - $role->add_cap('edit_posts'); - $role->add_cap('edit_published_posts'); - $role->add_cap('publish_posts'); - $role->add_cap('read'); - $role->add_cap('level_2'); - $role->add_cap('level_1'); - $role->add_cap('level_0'); - $role->add_cap('delete_posts'); - $role->add_cap('delete_published_posts'); - break; - - case 'contributor': - remove_role( $role_key ); - add_role('contributor', 'Contributor'); - $role = get_role('contributor'); - $role->add_cap('edit_posts'); - $role->add_cap('read'); - $role->add_cap('level_1'); - $role->add_cap('level_0'); - $role->add_cap('delete_posts'); - break; - - case 'subscriber': - remove_role( $role_key ); - add_role('subscriber', 'Subscriber'); - $role = get_role('subscriber'); - $role->add_cap('read'); - $role->add_cap('level_0'); - break; - - default: + // WP_CLI::error( ABSPATH.'wp-admin/includes/schema.php' ); + if ( ! function_exists( 'populate_roles' ) ) { + require_once( ABSPATH.'wp-admin/includes/schema.php' ); + } + + // get our default roles + $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); + + if ( 'all' == $role_key ) { + foreach( $preserve as $role ) { + remove_role( $role ); + } + populate_roles(); + + WP_CLI::success( sprintf( "All default roles reset.", $role_key ) ); + return; + + } + + // if key not found, bail + $key = array_search( $role_key, $preserve ); + if ( false === $key ) { WP_CLI::error( 'Must specify a default role to reset.' ); + } + + // remove the one to reset + unset( $preserve[ $key ] ); + + // for the roles we're not resetting + foreach( $preserve as $k => $role ) { + /* save roles + * if get_role is null + * save role name for re-removal + */ + $roleobj = get_role( $role ); + $preserve[$k] = is_null( $roleobj ) ? $role : $roleobj; + + remove_role( $role ); + } + + remove_role( $role_key ); + // put back all default roles and capabilities + populate_roles(); + + // restore the preserved roles + foreach( $preserve as $k => $roleobj ) { + // re-remove after populating + if ( is_a( $roleobj, 'WP_Role' ) ) { + remove_role( $roleobj->name ); + add_role( $roleobj->name, ucwords( $roleobj->name ), $roleobj->capabilities ); + } else { + // when not an object, that means the role didn't exist before + remove_role( $roleobj ); + } } WP_CLI::success( sprintf( "Role with key %s reset.", $role_key ) ); From 37bd3ab58f14215c7de0b9f0bfdac31948bf8ddc Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 7 Feb 2014 18:30:16 -0800 Subject: [PATCH 2695/5359] remove commented debug line and unnecessary sprintf --- php/commands/role.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 7732612ed..02ce4873b 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -162,7 +162,6 @@ public function reset( $args ) { if ( empty( $role_key ) ) WP_CLI::error( "Role key not provided, or is invalid." ); - // WP_CLI::error( ABSPATH.'wp-admin/includes/schema.php' ); if ( ! function_exists( 'populate_roles' ) ) { require_once( ABSPATH.'wp-admin/includes/schema.php' ); } @@ -176,7 +175,7 @@ public function reset( $args ) { } populate_roles(); - WP_CLI::success( sprintf( "All default roles reset.", $role_key ) ); + WP_CLI::success( 'All default roles reset.' ); return; } From 5cfa8f82d14611ee5333210724d053b77e9a7e13 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sat, 8 Feb 2014 20:20:39 -0800 Subject: [PATCH 2696/5359] reset multiple roles at once change `wp role reset all` to `wp role reset --all` compare before/after roles to determine success --- php/commands/role.php | 57 ++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 02ce4873b..f11d99f50 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -144,22 +144,23 @@ public function delete( $args ) { * * ## OPTIONS * - * <role-key> - * : The internal name of the role. + * [<role-key>...] + * : The internal name of one or more roles to reset. + * + * [--all] + * : If set, all default roles will be reset. * * ## EXAMPLES * - * wp role reset administrator + * wp role reset administrator author contributor * - * wp role reset author + * wp role reset --all */ - public function reset( $args ) { + public function reset( $args, $assoc_args ) { self::persistence_check(); - $role_key = array_shift( $args ); - - if ( empty( $role_key ) ) + if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) WP_CLI::error( "Role key not provided, or is invalid." ); if ( ! function_exists( 'populate_roles' ) ) { @@ -167,10 +168,10 @@ public function reset( $args ) { } // get our default roles - $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); + $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); - if ( 'all' == $role_key ) { - foreach( $preserve as $role ) { + if ( isset( $assoc_args['all'] ) ) { + foreach( $default_roles as $role ) { remove_role( $role ); } populate_roles(); @@ -180,14 +181,23 @@ public function reset( $args ) { } - // if key not found, bail - $key = array_search( $role_key, $preserve ); - if ( false === $key ) { - WP_CLI::error( 'Must specify a default role to reset.' ); + foreach( $args as $k => $role_key ) { + $key = array_search( $role_key, $default_roles ); + if ( false !== $key ) { + unset( $preserve[ $key ] ); + $before[ $role_key ] = get_role( $role_key ); + remove_role( $role_key ); + } else { + unset( $args[ $k ] ); + } } - // remove the one to reset - unset( $preserve[ $key ] ); + $num_to_reset = count( $args ); + + // no roles were unset, bail + if ( count( $default_roles ) == count( $preserve ) ) { + WP_CLI::error( 'Must specify a default role to reset.' ); + } // for the roles we're not resetting foreach( $preserve as $k => $role ) { @@ -201,8 +211,6 @@ public function reset( $args ) { remove_role( $role ); } - remove_role( $role_key ); - // put back all default roles and capabilities populate_roles(); @@ -218,7 +226,16 @@ public function reset( $args ) { } } - WP_CLI::success( sprintf( "Role with key %s reset.", $role_key ) ); + $num_reset = 0; + foreach( $args as $role_key ) { + $after[ $role_key ] = get_role( $role_key ); + + if ( $after[ $role_key ] != $before[ $role_key ] ) { + ++$num_reset; + } + } + + WP_CLI::success( "Reset $num_reset/$num_to_reset roles" ); } From 17860a741218d6230720d43cafa1c32f6a8a5ed2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 15:28:53 +0200 Subject: [PATCH 2697/5359] wp user create: validate fields before calling wp_insert_user() see #358 --- php/commands/user.php | 49 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 0ac77e767..46c6b6d8f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -179,34 +179,38 @@ public function delete( $args, $assoc_args ) { * wp user create bob bob@example.com --role=author */ public function create( $args, $assoc_args ) { - list( $user_login, $user_email ) = $args; + $user = new stdClass; - $defaults = array( - 'role' => get_option('default_role'), - 'user_pass' => false, - 'user_registered' => strftime( "%F %T", time() ), - 'display_name' => false, - ); - extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); + list( $user->user_login, $user->user_email ) = $args; - if ( !self::validate_role( $role ) ) { - WP_CLI::error( "Invalid role: $role" ); + if ( username_exists( $user->user_login ) ) { + WP_CLI::error( "The '{$user->user_login}' username is already registered." ); } - // @codingStandardsIgnoreStart - if ( !$user_pass ) { - $user_pass = wp_generate_password(); - $generated_pass = true; + if ( !is_email( $user->user_email ) ) { + WP_CLI::error( "The '{$user->user_email}' email address is invalid." ); } - $user_id = wp_insert_user( array( - 'user_email' => $user_email, - 'user_login' => $user_login, - 'user_pass' => $user_pass, - 'user_registered' => $user_registered, - 'display_name' => $display_name, - 'role' => $role, - ) ); + $user->user_registered = isset( $assoc_args['user_registered'] ) + ? $assoc_args['user_registered'] : strftime( "%F %T", current_time('timestamp') ); + + $user->display_name = isset( $assoc_args['display_name'] ) + ? $assoc_args['display_name'] : false; + + $user->user_pass = isset( $assoc_args['user_pass'] ) + ? $assoc_args['user_pass'] : wp_generate_password(); + + if ( isset( $assoc_args['role'] ) ) { + $role = $assoc_args['role']; + if ( !self::validate_role( $role ) ) { + WP_CLI::error( "Invalid role: $role" ); + } + } else { + $role = get_option('default_role'); + } + $user->role = $role; + + $user_id = wp_insert_user( $user ); if ( is_wp_error( $user_id ) ) { WP_CLI::error( $user_id ); @@ -224,7 +228,6 @@ public function create( $args, $assoc_args ) { if ( isset( $generated_pass ) ) WP_CLI::line( "Password: $user_pass" ); } - // @codingStandardsIgnoreEnd } /** From 79f2f06f6d688d7907ee2e75eb15e2e16d797f95 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 15:40:45 +0200 Subject: [PATCH 2698/5359] wp core install: validate admin email closes #358 --- php/commands/core.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 37a7453af..7390abf09 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -459,6 +459,10 @@ private function _install( $assoc_args ) { $public = true; // @codingStandardsIgnoreStart + if ( !is_email( $admin_email ) ) { + WP_CLI::error( "The '{$admin_email}' email address is invalid." ); + } + $result = wp_install( $title, $admin_user, $admin_email, $public, '', $admin_password ); if ( is_wp_error( $result ) ) { From c1c28aaac34a480df0ab7d68598044798d03b78f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 16:13:26 +0200 Subject: [PATCH 2699/5359] bump minimum required WP version to 3.5.2 --- .travis.yml | 4 ++-- php/WP_CLI/Runner.php | 2 +- php/commands/core.php | 2 +- php/commands/user.php | 10 ++-------- php/wp-settings-cli.php | 4 ++-- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4bff5686f..508251d01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,12 @@ env: - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - WP_VERSION=latest - - WP_VERSION=3.4.2 DEPLOY_BRANCH=master + - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: exclude: - php: 5.5 - env: WP_VERSION=3.4.2 DEPLOY_BRANCH=master + env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c701d2646..c8ffc2452 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -386,7 +386,7 @@ private function check_wp_version() { include ABSPATH . 'wp-includes/version.php'; - $minimum_version = '3.4'; + $minimum_version = '3.5.2'; // @codingStandardsIgnoreStart if ( version_compare( $wp_version, $minimum_version, '<' ) ) { diff --git a/php/commands/core.php b/php/commands/core.php index 7390abf09..8e0eee05b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -656,7 +656,7 @@ public function version( $args = array(), $assoc_args = array() ) { * * wp core update * - * wp core update --version=3.4 ../latest.zip + * wp core update --version=3.8 ../latest.zip * * wp core update --version=3.1 --force * diff --git a/php/commands/user.php b/php/commands/user.php index 46c6b6d8f..0267309de 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -96,13 +96,7 @@ public function list_( $args, $assoc_args ) { */ public function get( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); - - if ( method_exists( $user, 'to_array' ) ) { - $user_data = $user->to_array(); - } else { - // WP 3.4 compat - $user_data = (array) $user->data; - } + $user_data = $user->to_array(); $user_data['roles'] = implode( ', ', $user->roles ); $formatter = $this->get_formatter( $assoc_args ); @@ -566,7 +560,7 @@ public function import_csv( $args, $assoc_args ) { // Create the user } else { - unset( $new_user['ID'] ); // Unset else it will just return the ID + unset( $new_user['ID'] ); // Unset else it will just return the ID $user_id = wp_insert_user( $new_user ); } diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 735e54f75..8223901c0 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -124,8 +124,8 @@ require( ABSPATH . WPINC . '/query.php' ); Utils\maybe_require( '3.7-alpha-25139', ABSPATH . WPINC . '/date.php' ); require( ABSPATH . WPINC . '/theme.php' ); -Utils\maybe_require( '3.4', ABSPATH . WPINC . '/class-wp-theme.php' ); -Utils\maybe_require( '3.4', ABSPATH . WPINC . '/template.php' ); +require( ABSPATH . WPINC . '/class-wp-theme.php' ); +require( ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); require( ABSPATH . WPINC . '/meta.php' ); require( ABSPATH . WPINC . '/general-template.php' ); From ece9ef48b5fbd1d91ea49c0e30f1a5b5c0ebc5aa Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 17:35:40 +0200 Subject: [PATCH 2700/5359] wp media regenerate: check if there is platform support for generating images before starting --- php/commands/media.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 5f57f5d9a..c10f25b61 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -27,7 +27,10 @@ class Media_Command extends WP_CLI_Command { * seq 1000 2000 | xargs wp media regenerate */ function regenerate( $args, $assoc_args = array() ) { - global $wpdb; + if ( !wp_image_editor_supports() ) { + WP_CLI::error( 'No support for generating images found. ' . + 'Please install the Imagick or GD PHP extensions.' ); + } if ( empty( $args ) ) { WP_CLI::confirm( 'Do you realy want to regenerate all images?', $assoc_args ); From c9724c546fcb6380c146657a0872ec583e52dba5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 17:42:26 +0200 Subject: [PATCH 2701/5359] check for platform support before calling 'wp media import' too --- php/commands/media.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index c10f25b61..254942f4f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -27,11 +27,6 @@ class Media_Command extends WP_CLI_Command { * seq 1000 2000 | xargs wp media regenerate */ function regenerate( $args, $assoc_args = array() ) { - if ( !wp_image_editor_supports() ) { - WP_CLI::error( 'No support for generating images found. ' . - 'Please install the Imagick or GD PHP extensions.' ); - } - if ( empty( $args ) ) { WP_CLI::confirm( 'Do you realy want to regenerate all images?', $assoc_args ); } @@ -246,5 +241,12 @@ private function remove_old_images( $att_id ) { } } -WP_CLI::add_command( 'media', 'Media_Command' ); +WP_CLI::add_command( 'media', 'Media_Command', array( + 'before_invoke' => function () { + if ( !wp_image_editor_supports() ) { + WP_CLI::error( 'No support for generating images found. ' . + 'Please install the Imagick or GD PHP extensions.' ); + } + } +) ); From a298be35273bc44beb17f78492343f82393403fe Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 22:19:56 +0200 Subject: [PATCH 2702/5359] support arbitrary command nesting --- php/WP_CLI/Dispatcher/CompositeCommand.php | 18 +++++++++++--- php/WP_CLI/Dispatcher/Subcommand.php | 8 +++++-- php/class-wp-cli.php | 28 ++++++++++++++++++---- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index e5af82415..45217ed3c 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -59,8 +59,12 @@ function get_synopsis() { return '<command>'; } - function invoke( $args, $assoc_args, $extra_args ) { - $this->show_usage(); + function get_usage( $prefix ) { + return sprintf( "%s%s %s", + $prefix, + implode( ' ', get_path( $this ) ), + $this->get_synopsis() + ); } function show_usage() { @@ -71,13 +75,17 @@ function show_usage() { foreach ( $methods as $name => $subcommand ) { $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - $subcommand->show_usage( $prefix ); + \WP_CLI::line( $subcommand->get_usage( $prefix ) ); } \WP_CLI::line(); \WP_CLI::line( "See 'wp help $this->name <command>' for more information on a specific command." ); } + function invoke( $args, $assoc_args, $extra_args ) { + $this->show_usage(); + } + function find_subcommand( &$args ) { $name = array_shift( $args ); @@ -108,5 +116,9 @@ private static function get_aliases( $subcommands ) { return $aliases; } + + function get_alias() { + return false; + } } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 89402b7b2..1eebdea4b 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -38,11 +38,15 @@ function get_alias() { } function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( sprintf( "%s%s %s", + \WP_CLI::line( $this->get_usage( $prefix ) ); + } + + function get_usage( $prefix ) { + return sprintf( "%s%s %s", $prefix, implode( ' ', get_path( $this ) ), $this->get_synopsis() - ) ); + ); } private function prompt( $question, $default ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e5900ce0b..ad2ddf79e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -152,19 +152,39 @@ static function do_hook( $when ) { /** * Add a command to the wp-cli list of commands * - * @param string $name The name of the command that will be used in the cli + * @param string $name The name of the command that will be used in the CLI * @param string $class The command implementation * @param array $args An associative array with additional parameters: * 'before_invoke' => callback to execute before invoking the command */ static function add_command( $name, $class, $args = array() ) { - $command = Dispatcher\CommandFactory::create( $name, $class, self::get_root_command() ); - if ( isset( $args['before_invoke'] ) ) { self::add_hook( "before_invoke:$name", $args['before_invoke'] ); } - self::get_root_command()->add_subcommand( $name, $command ); + $path = preg_split( '/\s+/', $name ); + + $leaf_name = array_pop( $path ); + + $command = self::get_root_command(); + + while ( !empty( $path ) ) { + $subcommand_name = $path[0]; + $subcommand = $command->find_subcommand( $path ); + + // create an empty container + if ( !$subcommand ) { + $subcommand = new Dispatcher\CompositeCommand( $command, $subcommand_name, + new \WP_CLI\DocParser( '' ) ); + $command->add_subcommand( $subcommand_name, $subcommand ); + } + + $command = $subcommand; + } + + $leaf_command = Dispatcher\CommandFactory::create( $leaf_name, $class, $command ); + + $command->add_subcommand( $leaf_name, $leaf_command ); } /** From 776388eab6d0433e85706c68f016b252cb31dc21 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Feb 2014 23:40:58 +0200 Subject: [PATCH 2703/5359] prevent registering subcommands for concrete commands --- php/WP_CLI/Dispatcher/CompositeCommand.php | 4 ++-- php/WP_CLI/Dispatcher/RootCommand.php | 5 ----- php/WP_CLI/Dispatcher/Subcommand.php | 4 ++++ php/WP_CLI/Runner.php | 4 ++-- php/class-wp-cli.php | 6 ++++++ php/commands/help.php | 4 ++-- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 45217ed3c..2edb23687 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -33,8 +33,8 @@ function add_subcommand( $name, $command ) { $this->subcommands[ $name ] = $command; } - function has_subcommands() { - return !empty( $this->subcommands ); + function can_have_subcommands() { + return true; } function get_subcommands() { diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index d11a9a215..853cfa197 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -61,10 +61,5 @@ function get_subcommands() { return parent::get_subcommands(); } - - function has_subcommands() { - // Commands are lazy-loaded, so we need to assume there will be some - return true; - } } diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1eebdea4b..c8d1acc18 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -29,6 +29,10 @@ private static function extract_synopsis( $longdesc ) { return implode( ' ', $matches[1] ); } + function can_have_subcommands() { + return false; + } + function get_synopsis() { return $this->synopsis; } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c8ffc2452..4e9811fff 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -199,7 +199,7 @@ private function find_command_to_run( $args ) { $disabled_commands = $this->config['disabled_commands']; - while ( !empty( $args ) && $command->has_subcommands() ) { + while ( !empty( $args ) && $command->can_have_subcommands() ) { $cmd_path[] = $args[0]; $full_name = implode( ' ', $cmd_path ); @@ -477,7 +477,7 @@ public function before_wp_load() { if ( is_array( $r ) ) { list( $command ) = $r; - if ( $command->has_subcommands() ) { + if ( $command->can_have_subcommands() ) { $command->show_usage(); exit; } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ad2ddf79e..ca650fc2c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -165,6 +165,7 @@ static function add_command( $name, $class, $args = array() ) { $path = preg_split( '/\s+/', $name ); $leaf_name = array_pop( $path ); + $full_path = $path; $command = self::get_root_command(); @@ -184,6 +185,11 @@ static function add_command( $name, $class, $args = array() ) { $leaf_command = Dispatcher\CommandFactory::create( $leaf_name, $class, $command ); + if ( ! $command->can_have_subcommands() ) { + throw new Exception( sprintf( "'%s' can't have subcommands.", + implode( ' ' , Dispatcher\get_path( $command ) ) ) ); + } + $command->add_subcommand( $leaf_name, $leaf_command ); } diff --git a/php/commands/help.php b/php/commands/help.php index a3f42d3a0..b9abfcc0c 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -35,7 +35,7 @@ function __invoke( $args, $assoc_args ) { private static function find_subcommand( $args ) { $command = \WP_CLI::get_root_command(); - while ( !empty( $args ) && $command && $command->has_subcommands() ) { + while ( !empty( $args ) && $command && $command->can_have_subcommands() ) { $command = $command->find_subcommand( $args ); } @@ -106,7 +106,7 @@ private static function get_initial_markdown( $command ) { $binding['synopsis'] = wordwrap( "$name " . $command->get_synopsis(), 79 ); - if ( $command->has_subcommands() ) { + if ( $command->can_have_subcommands() ) { $binding['has-subcommands']['subcommands'] = self::render_subcommands( $command ); } From ac4437a68359ee67234769860c2ff6fdd704f5bf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 02:34:29 +0200 Subject: [PATCH 2704/5359] generate bash completions unambiguously for fourth-level subcommands --- php/WP_CLI/Configurator.php | 34 +++++++++++++++++++++++++--------- php/WP_CLI/Runner.php | 2 +- php/commands/cli.php | 28 +++++++++++++++++++++++----- utils/wp-completion.bash | 25 ++++++------------------- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index e3b178f6a..8a9ce8ac7 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -43,24 +43,40 @@ function get_spec() { /** * Splits a list of arguments into positional, associative and config. * - * @param string - * @return array + * @param array(string) + * @return array(array) + */ + public function parse_args( $arguments ) { + list( $positional_args, $mixed_args ) = self::extract_assoc( $arguments ); + list( $assoc_args, $runtime_config ) = $this->unmix_assoc_args( $mixed_args ); + return array( $positional_args, $assoc_args, $runtime_config ); + } + + /** + * Splits positional args from associative args. + * + * @param array + * @return array(array) */ - function parse_args( $arguments ) { - $regular_args = $mixed_args = array(); + public static function extract_assoc( $arguments ) { + $positional_args = $assoc_args = array(); foreach ( $arguments as $arg ) { if ( preg_match( '|^--no-([^=]+)$|', $arg, $matches ) ) { - $mixed_args[] = array( $matches[1], false ); + $assoc_args[] = array( $matches[1], false ); } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $mixed_args[] = array( $matches[1], true ); + $assoc_args[] = array( $matches[1], true ); } elseif ( preg_match( '|^--([^=]+)=(.+)|s', $arg, $matches ) ) { - $mixed_args[] = array( $matches[1], $matches[2] ); + $assoc_args[] = array( $matches[1], $matches[2] ); } else { - $regular_args[] = $arg; + $positional_args[] = $arg; } } + return array( $positional_args, $assoc_args ); + } + + private function unmix_assoc_args( $mixed_args ) { $assoc_args = $runtime_config = array(); foreach ( $mixed_args as $tmp ) { @@ -83,7 +99,7 @@ function parse_args( $arguments ) { } } - return array( $regular_args, $assoc_args, $runtime_config ); + return array( $assoc_args, $runtime_config ); } function merge_yml( $path ) { diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4e9811fff..3827656b7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -192,7 +192,7 @@ private function cmd_starts_with( $prefix ) { return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } - private function find_command_to_run( $args ) { + public function find_command_to_run( $args ) { $command = \WP_CLI::get_root_command(); $cmd_path = array(); diff --git a/php/commands/cli.php b/php/commands/cli.php index 752b1d603..2df3f4fcb 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -89,13 +89,31 @@ function cmd_dump() { /** * Generate tab completion strings. + * + * ## OPTIONS + * + * --line=<line> + * : The current command line to be executed + * + * --point=<point> + * : The index to the current cursor position relative to the beginning of the command */ - function completions() { - foreach ( WP_CLI::get_root_command()->get_subcommands() as $name => $command ) { - $subcommands = $command->get_subcommands(); + function completions( $_, $assoc_args ) { + $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); + $ends_with_space = ( ' ' === substr( $line, -1 ) ); - WP_CLI::line( $name . ' ' . implode( ' ', array_keys( $subcommands ) ) ); - } + // TODO: properly parse single and double quotes + $words = explode( ' ', $line ); + + array_shift( $words ); // first word is always `wp` + array_pop( $words ); // last word is either a space or an incomplete subcommand + + list( $positional_args, $assoc_args ) = \WP_CLI\Configurator::extract_assoc( $words ); + list( $command ) = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + + $subcommands = $command->get_subcommands(); + + WP_CLI::line( implode( ' ', array_keys( $subcommands ) ) ); } } diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index f3822d350..5d772e885 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -1,21 +1,8 @@ -# bash completion for the wp command +# bash completion for the `wp` command -_wp() { - local cur prev opts - - cur=${COMP_WORDS[COMP_CWORD]} - prev=${COMP_WORDS[COMP_CWORD-1]} - - if [[ 'wp' = $prev ]]; then - opts=$(wp --completions | cut -d ' ' -f 1 | tr '\n' ' ') - else - opts=$(wp --completions | grep ^$prev | cut -d ' ' -f 2- | tr '\n' ' ') - fi - - if [[ 'create' = $prev ]]; then - COMPREPLY=( $(compgen -f "$cur") ) - else - COMPREPLY=( $(compgen -W "$opts" -- $cur) ) - fi +_wp_complete() { + local cur=${COMP_WORDS[COMP_CWORD]} + local opts=$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT") + COMPREPLY=( $(compgen -W "$opts" -- $cur) ) } -complete -F _wp wp +complete -F _wp_complete wp From acbb757838501b39e55e5e9bf936859b6939d08d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 03:06:08 +0200 Subject: [PATCH 2705/5359] complete with filenames for commands that have <file> in their synopsis --- php/WP_CLI/SynopsisParser.php | 3 ++- php/commands/cli.php | 24 ++++++++++++++++++++---- php/commands/eval-file.php | 5 ++--- php/commands/post.php | 4 ++-- utils/wp-completion.bash | 8 +++++++- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 499600053..fb581ea88 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -40,8 +40,9 @@ private static function classify_token( $token ) { if ( '--<field>=<value>' === $token ) { $param['type'] = 'generic'; - } elseif ( preg_match( "/^<$p_value>$/", $token, $matches ) ) { + } elseif ( preg_match( "/^<($p_value)>$/", $token, $matches ) ) { $param['type'] = 'positional'; + $param['name'] = $matches[1]; } elseif ( preg_match( "/^--(?:\\[no-\\])?$p_name/", $token, $matches ) ) { $param['name'] = $matches[1]; diff --git a/php/commands/cli.php b/php/commands/cli.php index 2df3f4fcb..d4b89d860 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -100,6 +100,24 @@ function cmd_dump() { */ function completions( $_, $assoc_args ) { $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); + + list( $command, $args, $assoc_args ) = self::parse_line( $line ); + + $spec = \WP_CLI\SynopsisParser::parse( $command->get_synopsis() ); + + foreach ( $spec as $arg ) { + if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { + WP_CLI::line( '<file>' ); + return; + } + } + + $subcommands = $command->get_subcommands(); + + WP_CLI::line( implode( ' ', array_keys( $subcommands ) ) ); + } + + private static function parse_line( $line ) { $ends_with_space = ( ' ' === substr( $line, -1 ) ); // TODO: properly parse single and double quotes @@ -109,11 +127,9 @@ function completions( $_, $assoc_args ) { array_pop( $words ); // last word is either a space or an incomplete subcommand list( $positional_args, $assoc_args ) = \WP_CLI\Configurator::extract_assoc( $words ); - list( $command ) = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + list( $command, $args ) = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); - $subcommands = $command->get_subcommands(); - - WP_CLI::line( implode( ' ', array_keys( $subcommands ) ) ); + return array( $command, $args, $assoc_args ); } } diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 330c384dd..201bc1b34 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -7,9 +7,8 @@ class EvalFile_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp eval-file my-code.php - * - * @synopsis <path> + * [<file>] + * : The path to the PHP file to execute. */ public function __invoke( $args, $assoc_args ) { foreach ( $args as $file ) { diff --git a/php/commands/post.php b/php/commands/post.php index 9cae10888..44362dbd4 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -25,8 +25,8 @@ public function __construct() { * * ## OPTIONS * - * [<filename>] - * : Read post content from <filename>. If this value is present, the + * [<file>] + * : Read post content from <file>. If this value is present, the * `--post_content` argument will be ignored. * * Passing `-` as the filename will cause post content to diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index 5d772e885..008e32c6b 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -3,6 +3,12 @@ _wp_complete() { local cur=${COMP_WORDS[COMP_CWORD]} local opts=$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT") - COMPREPLY=( $(compgen -W "$opts" -- $cur) ) + + if [[ "$opts" = "<file>" ]] + then + COMPREPLY=( $(compgen -f -- $cur) ) + else + COMPREPLY=( $(compgen -W "$opts" -- $cur) ) + fi } complete -F _wp_complete wp From 4b875b82181baf9aa1e82b3c0ec4a224c64fbdef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 03:19:28 +0200 Subject: [PATCH 2706/5359] update Behat tests for completions --- features/flags.feature | 14 ++++++++++++-- php/commands/cli.php | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index c666235e2..dfbb1aae8 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -212,8 +212,18 @@ Feature: Global flags Scenario: Generate completions Given an empty directory - When I run `wp --completions` + + When I run `wp cli completions --line='wp bogus-comand ' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp media ' --point=100` + Then STDOUT should contain: + """ + import regenerate + """ + + When I run `wp cli completions --line='wp media import ' --point=100` Then STDOUT should contain: """ - transient delete get set type + <file> """ diff --git a/php/commands/cli.php b/php/commands/cli.php index d4b89d860..e03bbfdb4 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -101,7 +101,12 @@ function cmd_dump() { function completions( $_, $assoc_args ) { $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); - list( $command, $args, $assoc_args ) = self::parse_line( $line ); + $r = self::parse_line( $line ); + if ( !is_array( $r ) ) { + return; + } + + list( $command, $args, $assoc_args ) = $r; $spec = \WP_CLI\SynopsisParser::parse( $command->get_synopsis() ); @@ -127,7 +132,13 @@ private static function parse_line( $line ) { array_pop( $words ); // last word is either a space or an incomplete subcommand list( $positional_args, $assoc_args ) = \WP_CLI\Configurator::extract_assoc( $words ); - list( $command, $args ) = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + + $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + if ( !is_array( $r ) ) { + return $r; + } + + list( $command, $args ) = $r; return array( $command, $args, $assoc_args ); } From efe2deedb1e96254b23b550f81965384a84a0317 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 03:41:19 +0200 Subject: [PATCH 2707/5359] complete with command flags and associative parameters --- features/flags.feature | 22 +++++-- php/WP_CLI/Completions.php | 103 +++++++++++++++++++++++++++++++ php/WP_CLI/SynopsisValidator.php | 2 +- php/commands/cli.php | 43 +------------ utils/wp-completion.bash | 10 +-- 5 files changed, 130 insertions(+), 50 deletions(-) create mode 100644 php/WP_CLI/Completions.php diff --git a/features/flags.feature b/features/flags.feature index dfbb1aae8..acb13f770 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -216,14 +216,28 @@ Feature: Global flags When I run `wp cli completions --line='wp bogus-comand ' --point=100` Then STDOUT should be empty - When I run `wp cli completions --line='wp media ' --point=100` - Then STDOUT should contain: + When I run `wp cli completions --line='wp eva' --point=100` + Then STDOUT should be: + """ + eval + eval-file + """ + + When I run `wp cli completions --line='wp core config --dbname=' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` + Then STDOUT should not contain: + """ + --dbname= + """ + And STDOUT should contain: """ - import regenerate + --extra-php """ When I run `wp cli completions --line='wp media import ' --point=100` Then STDOUT should contain: """ - <file> + <file> """ diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php new file mode 100644 index 000000000..63bacbae7 --- /dev/null +++ b/php/WP_CLI/Completions.php @@ -0,0 +1,103 @@ +<?php + +namespace WP_CLI; + +class Completions { + + private $words; + private $opts = array(); + + function __construct( $line ) { + // TODO: properly parse single and double quotes + $this->words = explode( ' ', $line ); + + // first word is always `wp` + array_shift( $this->words ); + + // last word is either empty or an incomplete subcommand + $this->cur_word = end( $this->words ); + + $r = $this->get_command( $this->words ); + if ( !is_array( $r ) ) { + return; + } + + list( $command, $args, $assoc_args ) = $r; + + $spec = SynopsisParser::parse( $command->get_synopsis() ); + + foreach ( $spec as $arg ) { + if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { + $this->add( '<file> ' ); + return; + } + } + + if ( $command->can_have_subcommands() ) { + foreach ( $command->get_subcommands() as $name => $_ ) { + $this->add( "$name " ); + } + } else { + foreach ( $spec as $arg ) { + if ( in_array( $arg['type'], array( 'flag', 'assoc' ) ) ) { + if ( isset( $assoc_args[ $arg['name'] ] ) ) { + continue; + } + + $opt = "--{$arg['name']}"; + + if ( $arg['type'] == 'flag' ) { + $opt .= ' '; + } elseif ( !$arg['value']['optional'] ) { + $opt .= '='; + } + + $this->add( $opt ); + } + } + } + + } + + private function get_command( $words ) { + $positional_args = $assoc_args = array(); + + foreach ( $words as $arg ) { + if ( preg_match( '|^--([^=]+)=?|', $arg, $matches ) ) { + $assoc_args[ $matches[1] ] = true; + } else { + $positional_args[] = $arg; + } + } + + $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + if ( !is_array( $r ) && array_pop( $positional_args ) == $this->cur_word ) { + $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); + } + + if ( !is_array( $r ) ) { + return $r; + } + + list( $command, $args ) = $r; + + return array( $command, $args, $assoc_args ); + } + + private function add( $opt ) { + if ( $this->cur_word !== '' ) { + if ( strpos( $opt, $this->cur_word ) !== 0 ) { + return; + } + } + + $this->opts[] = $opt; + } + + public function render() { + foreach ( $this->opts as $opt ) { + \WP_CLI::line( $opt ); + } + } +} + diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index ee0b824c4..7c56f98e8 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -97,7 +97,7 @@ public function unknown_assoc( $assoc_args ) { } /** - * Filters a list of associatve arrays, based on a set of key => value arguments. + * Filters a list of associative arrays, based on a set of key => value arguments. * * @param array $args An array of key => value arguments to match against * @param string $operator diff --git a/php/commands/cli.php b/php/commands/cli.php index e03bbfdb4..bfc3a91a3 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -100,47 +100,8 @@ function cmd_dump() { */ function completions( $_, $assoc_args ) { $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); - - $r = self::parse_line( $line ); - if ( !is_array( $r ) ) { - return; - } - - list( $command, $args, $assoc_args ) = $r; - - $spec = \WP_CLI\SynopsisParser::parse( $command->get_synopsis() ); - - foreach ( $spec as $arg ) { - if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { - WP_CLI::line( '<file>' ); - return; - } - } - - $subcommands = $command->get_subcommands(); - - WP_CLI::line( implode( ' ', array_keys( $subcommands ) ) ); - } - - private static function parse_line( $line ) { - $ends_with_space = ( ' ' === substr( $line, -1 ) ); - - // TODO: properly parse single and double quotes - $words = explode( ' ', $line ); - - array_shift( $words ); // first word is always `wp` - array_pop( $words ); // last word is either a space or an incomplete subcommand - - list( $positional_args, $assoc_args ) = \WP_CLI\Configurator::extract_assoc( $words ); - - $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); - if ( !is_array( $r ) ) { - return $r; - } - - list( $command, $args ) = $r; - - return array( $command, $args, $assoc_args ); + $compl = new \WP_CLI\Completions( $line ); + $compl->render(); } } diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index 008e32c6b..682d53d9a 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -2,13 +2,15 @@ _wp_complete() { local cur=${COMP_WORDS[COMP_CWORD]} - local opts=$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT") - if [[ "$opts" = "<file>" ]] + IFS=$'\n'; # want to preserve spaces at the end + local opts=( $(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT") ) + + if [[ $opts = "<file>" ]] then COMPREPLY=( $(compgen -f -- $cur) ) else - COMPREPLY=( $(compgen -W "$opts" -- $cur) ) + COMPREPLY=$opts fi } -complete -F _wp_complete wp +complete -o nospace -F _wp_complete wp From 5a3e4f26b7d50f029b277ef877d28222abaf9015 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 05:01:11 +0200 Subject: [PATCH 2708/5359] remove conversion from 'wp --completions' to 'wp cli completions' the format is different and associative parameters are required --- php/WP_CLI/Runner.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3827656b7..26af00ad0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -337,9 +337,9 @@ private static function back_compat_conversions( $args, $assoc_args ) { unset( $assoc_args['json'] ); } - // --{version|info|completions} -> cli {version|info|completions} + // --{version|info} -> cli {version|info} if ( empty( $args ) ) { - $special_flags = array( 'version', 'info', 'completions' ); + $special_flags = array( 'version', 'info' ); foreach ( $special_flags as $key ) { if ( isset( $assoc_args[ $key ] ) ) { $args = array( 'cli', $key ); From 28c7aebc099b9806d4ba151aa1acb02457acce8b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 10 Feb 2014 05:12:48 +0200 Subject: [PATCH 2709/5359] bump version to 0.15-alpha --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index e9976b54e..cda6d57d2 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.14.1-alpha' ); +define( 'WP_CLI_VERSION', '0.15-alpha' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 0d2fc1d571800ed3797fd588f3c31334b6ade605 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Feb 2014 03:17:30 +0200 Subject: [PATCH 2710/5359] convert `wp *-meta` subcommands to `wp * meta` --- features/network-meta.feature | 2 +- php/WP_CLI/Runner.php | 9 +- php/commands/comment-meta.php | 19 --- php/commands/comment.php | 23 +++- .../{network-meta.php => network.php} | 4 +- php/commands/post-meta.php | 20 --- php/commands/post.php | 18 +++ php/commands/user-meta.php | 115 ------------------ php/commands/user.php | 112 +++++++++++++++++ 9 files changed, 161 insertions(+), 161 deletions(-) delete mode 100644 php/commands/comment-meta.php rename php/commands/{network-meta.php => network.php} (81%) delete mode 100644 php/commands/post-meta.php delete mode 100644 php/commands/user-meta.php diff --git a/features/network-meta.feature b/features/network-meta.feature index dd6bf9c88..f81c3b1b5 100644 --- a/features/network-meta.feature +++ b/features/network-meta.feature @@ -6,7 +6,7 @@ Feature: Manage network-wide custom fields. When I try `wp network-meta` Then STDOUT should contain: """ - usage: wp network-meta + usage: wp network meta """ When I try `wp network-meta get 1 site_admins` diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 26af00ad0..57ac14284 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -291,7 +291,14 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } - // core (multsite-)install --admin_name= -> --admin_user= + // *-meta -> * meta + if ( !empty( $args ) && preg_match( '/(post|comment|user|network)-meta/', $args[0], $matches ) ) { + array_shift( $args ); + array_unshift( $args, 'meta' ); + array_unshift( $args, $matches[1] ); + } + + // core (multsite-)install --admin_name= -> --admin_user= if ( count( $args ) > 0 && 'core' == $args[0] && isset( $assoc_args['admin_name'] ) ) { $assoc_args['admin_user'] = $assoc_args['admin_name']; unset( $assoc_args['admin_name'] ); diff --git a/php/commands/comment-meta.php b/php/commands/comment-meta.php deleted file mode 100644 index b1aba174b..000000000 --- a/php/commands/comment-meta.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -/** - * Manage comment custom fields. - * - * ## OPTIONS - * - * --format=json - * : Encode/decode values as JSON. - * - * ## EXAMPLES - * - * wp comment-meta set 123 description "Mary is a WordPress developer." - */ -class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'comment'; -} - -WP_CLI::add_command( 'comment-meta', 'Comment_Meta_Command' ); diff --git a/php/commands/comment.php b/php/commands/comment.php index cb2716323..285059757 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -167,7 +167,7 @@ public function list_( $_, $assoc_args ) { * ## EXAMPLES * * wp comment delete 1337 --force - * + * * wp comment delete 1337 2341 --force */ public function delete( $args, $assoc_args ) { @@ -371,10 +371,10 @@ public function exists( $args ) { WP_CLI::success( "Comment with ID $args[0] exists." ); } } - + /** * Get comment url - * + * * ## OPTIONS * * <id>... @@ -389,5 +389,22 @@ public function url( $args ) { } } +/** + * Manage comment custom fields. + * + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp comment meta set 123 description "Mary is a WordPress developer." + */ +class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'comment'; +} + WP_CLI::add_command( 'comment', 'Comment_Command' ); +WP_CLI::add_command( 'comment meta', 'Comment_Meta_Command' ); diff --git a/php/commands/network-meta.php b/php/commands/network.php similarity index 81% rename from php/commands/network-meta.php rename to php/commands/network.php index 181d22949..709c16b49 100644 --- a/php/commands/network-meta.php +++ b/php/commands/network.php @@ -14,13 +14,13 @@ * ## EXAMPLES * * # get a list of super-admins - * wp network-meta get 1 site_admins + * wp network meta get 1 site_admins */ class Network_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'site'; } -WP_CLI::add_command( 'network-meta', 'Network_Meta_Command', array( +WP_CLI::add_command( 'network meta', 'Network_Meta_Command', array( 'before_invoke' => function () { if ( !is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php deleted file mode 100644 index be99bd813..000000000 --- a/php/commands/post-meta.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -/** - * Manage post custom fields. - * - * ## OPTIONS - * - * [--format=json] - * : Encode/decode values as JSON. - * - * ## EXAMPLES - * - * wp post-meta set 123 _wp_page_template about.php - */ -class Post_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'post'; -} - -WP_CLI::add_command( 'post-meta', 'Post_Meta_Command' ); - diff --git a/php/commands/post.php b/php/commands/post.php index 44362dbd4..e289e95a1 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -394,4 +394,22 @@ private function maybe_reset_depth() { } } +/** + * Manage post custom fields. + * + * ## OPTIONS + * + * [--format=json] + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp post meta set 123 _wp_page_template about.php + */ +class Post_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'post'; +} + WP_CLI::add_command( 'post', 'Post_Command' ); +WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); + diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php deleted file mode 100644 index dbe0924b4..000000000 --- a/php/commands/user-meta.php +++ /dev/null @@ -1,115 +0,0 @@ -<?php - -/** - * Manage user custom fields. - * - * ## OPTIONS - * - * --format=json - * : Encode/decode values as JSON. - * - * ## EXAMPLES - * - * wp user-meta set 123 description "Mary is a WordPress developer." - * - * wp user-meta update admin first_name "George" - */ -class User_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'user'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * Get meta field value. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to get metadata for. - * - * <key> - * : The metadata key. - * - * [--format=<format>] - * : Accepted values: table, json. Default: table - * - * @synopsis <user> <key> [--format=<format>] - */ - public function get( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::get( $args, $assoc_args ); - } - - /** - * Delete a meta field. - * - * <user> - * : The user login, user email, or user ID of the user to delete metadata from. - * - * <key> - * : The metadata key. - * - * @synopsis <user> <key> - */ - public function delete( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::delete( $args, $assoc_args ); - } - - /** - * Add a meta field. - * - * <user> - * : The user login, user email, or user ID of the user to add metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * @synopsis <user> <key> <value> [--format=<format>] - */ - public function add( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::add( $args, $assoc_args ); - } - - /** - * Update a meta field. - * - * <user> - * : The user login, user email, or user ID of the user to update metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * @alias set - * @synopsis <user> <key> <value> [--format=<format>] - */ - public function update( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::update( $args, $assoc_args ); - } - - /** - * Replace user_login value with user ID - * user-meta is a special case that also supports user_login - * - * @param array - * @return array - */ - private function replace_login_with_user_id( $args ) { - $user = $this->fetcher->get_check( $args[0] ); - $args[0] = $user->ID; - return $args; - } -} - -WP_CLI::add_command( 'user-meta', 'User_Meta_Command' ); - diff --git a/php/commands/user.php b/php/commands/user.php index 0267309de..1767f80ed 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -589,5 +589,117 @@ private static function validate_role( $role ) { } } +/** + * Manage user custom fields. + * + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp user meta set 123 description "Mary is a WordPress developer." + * + * wp user meta update admin first_name "George" + */ +class User_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'user'; + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + + /** + * Get meta field value. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to get metadata for. + * + * <key> + * : The metadata key. + * + * [--format=<format>] + * : Accepted values: table, json. Default: table + * + * @synopsis <user> <key> [--format=<format>] + */ + public function get( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::get( $args, $assoc_args ); + } + + /** + * Delete a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to delete metadata from. + * + * <key> + * : The metadata key. + * + * @synopsis <user> <key> + */ + public function delete( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::delete( $args, $assoc_args ); + } + + /** + * Add a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to add metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. + * + * @synopsis <user> <key> <value> [--format=<format>] + */ + public function add( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::add( $args, $assoc_args ); + } + + /** + * Update a meta field. + * + * <user> + * : The user login, user email, or user ID of the user to update metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. + * + * @alias set + * @synopsis <user> <key> <value> [--format=<format>] + */ + public function update( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::update( $args, $assoc_args ); + } + + /** + * Replace user_login value with user ID + * user meta is a special case that also supports user_login + * + * @param array + * @return array + */ + private function replace_login_with_user_id( $args ) { + $user = $this->fetcher->get_check( $args[0] ); + $args[0] = $user->ID; + return $args; + } +} + WP_CLI::add_command( 'user', 'User_Command' ); +WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); From 7504a233cfbcb0c8b12e0da4f709be8d506a413d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 11 Feb 2014 03:38:18 +0200 Subject: [PATCH 2711/5359] pass full path to 'before_invoke:' --- php/WP_CLI/Dispatcher/Subcommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c8d1acc18..860b3c366 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -215,7 +215,8 @@ function invoke( $args, $assoc_args, $extra_args ) { unset( $assoc_args[ $key ] ); } - \WP_CLI::do_hook( 'before_invoke:' . $this->get_parent()->get_name() ); + $path = get_path( $this->get_parent() ); + \WP_CLI::do_hook( 'before_invoke:' . implode( ' ', array_slice( $path, 1 ) ) ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); } From c248604bd145b4af095edc495b7ff3a54bab02fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 06:53:56 -0800 Subject: [PATCH 2712/5359] Correct casing --- php/commands/super-admin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 6d973a28d..531146eeb 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -1,6 +1,6 @@ <?php -class SuperAdminCommand extends WP_CLI_Command { +class Super_Admin_Command extends WP_CLI_Command { /** * Show a list of users with super-admin capabilities. @@ -55,5 +55,5 @@ private static function get_admins() { } } -WP_CLI::add_command( 'super-admin', 'SuperAdminCommand' ); +WP_CLI::add_command( 'super-admin', 'Super_Admin_Command' ); From ce0695081676bc9aae4d34ed754289577e50704a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 06:57:53 -0800 Subject: [PATCH 2713/5359] Command description --- php/commands/super-admin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 531146eeb..07588f6de 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -1,5 +1,8 @@ <?php +/** + * List, add, and remove super admins from a network. + */ class Super_Admin_Command extends WP_CLI_Command { /** From 59486e5cc1f39527a143167e917672e2789f668d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 07:03:45 -0800 Subject: [PATCH 2714/5359] Basic Behat tests for `wp super-admin` --- features/super-admin.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 features/super-admin.feature diff --git a/features/super-admin.feature b/features/super-admin.feature new file mode 100644 index 000000000..421f3506c --- /dev/null +++ b/features/super-admin.feature @@ -0,0 +1,30 @@ +Feature: Manage super admins associated with a multisite instance + + Scenario: Add, list, and remove super admins. + Given a WP multisite install + + When I try `wp user create superadmin superadmin@example.com` + Then STDERR should be empty + + When I try `wp super-admin list` + Then STDOUT should contain: + """ + admin + """ + + When I try `wp super-admin add superadmin` + Then STDERR should be empty + + When I try `wp super-admin list` + Then STDOUT should contain: + """ + admin + superadmin + """ + + When I try `wp super-admin remove admin` + And I run `wp super-admin list` + Then STDOUT should contain: + """ + superadmin + """ From fd23fb66c12a1004b620dd9319b831bab2d8850e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 07:07:27 -0800 Subject: [PATCH 2715/5359] Support adding / removing super admins based on user ID or user login --- php/commands/super-admin.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 07588f6de..ba0329212 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -5,6 +5,10 @@ */ class Super_Admin_Command extends WP_CLI_Command { + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + /** * Show a list of users with super-admin capabilities. * @@ -21,12 +25,15 @@ public function _list( $_, $assoc_args ) { * Grant super-admin privileges to one or more users. * * <user>... - * : One or more user logins. + * : One or more user IDs, user emails, or user logins. */ public function add( $args, $_ ) { + + $users = $this->fetcher->get_many( $args ); + $user_logins = wp_list_pluck( $users, 'user_login' ); $super_admins = self::get_admins(); - foreach ( $args as $user_login ) { + foreach ( $user_logins as $user_login ) { $user = get_user_by( 'login', $user_login ); if ( !$user ) { WP_CLI::warning( "Couldn't find {$user_login} user." ); @@ -43,11 +50,14 @@ public function add( $args, $_ ) { * Revoke super-admin privileges to one or more users. * * <user>... - * : One or more user logins. + * : One or more user IDs, user emails, or user logins. */ public function remove( $args, $_ ) { + $users = $this->fetcher->get_many( $args ); + $user_logins = wp_list_pluck( $users, 'user_login' ); + $super_admins = self::get_admins(); - $super_admins = array_diff( $super_admins, $args ); + $super_admins = array_diff( $super_admins, $user_logins ); update_site_option( 'site_admins' , $super_admins ); WP_CLI::success( 'Revoked super-admin capabilities.' ); } From 8ae2147a0653e3bbe7748b5a9986eb1af8bdbbef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 07:09:37 -0800 Subject: [PATCH 2716/5359] Don't do anything if this isn't multisite --- php/commands/super-admin.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index ba0329212..b966fcd3d 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -68,5 +68,10 @@ private static function get_admins() { } } -WP_CLI::add_command( 'super-admin', 'Super_Admin_Command' ); - +WP_CLI::add_command( 'super-admin', 'Super_Admin_Command', array( + 'before_invoke' => function () { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + } + ) ); From 976de5fb6a0260649dbef6ef38874d6ae844827f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 07:43:08 -0800 Subject: [PATCH 2717/5359] Basic nav menu CRUD --- features/menu.feature | 23 +++++++++ php/commands/menu.php | 108 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 features/menu.feature create mode 100644 php/commands/menu.php diff --git a/features/menu.feature b/features/menu.feature new file mode 100644 index 000000000..1e45bcfa6 --- /dev/null +++ b/features/menu.feature @@ -0,0 +1,23 @@ +Feature: Manage WordPress menus + + Background: + Given a WP install + + Scenario: Menu CRUD operations + + When I try `wp menu create "My Menu"` + Then STDERR should be empty + + When I run `wp menu list --fields=name,slug` + Then STDOUT should be a table containing rows: + | name | slug | + | My Menu | my-menu | + + When I try `wp menu delete "My Menu"` + Then STDERR should be empty + + When I run `wp menu list --format=count` + Then STDOUT should be: + """ + 0 + """ diff --git a/php/commands/menu.php b/php/commands/menu.php new file mode 100644 index 000000000..58c801930 --- /dev/null +++ b/php/commands/menu.php @@ -0,0 +1,108 @@ +<?php + +/** + * List, create, assign, and delete menus + */ +class Menu_Command extends WP_CLI_Command { + + protected $obj_type = 'nav_menu'; + protected $obj_fields = array( + 'term_id', + 'name', + 'slug', + 'count', + ); + + /** + * Create a new menu + * + * <menu-name> + * : A descriptive name for the menu + * + * [--porcelain] + * : Output just the new menu id. + * + * ## EXAMPLES + * + * wp menu create "My Menu" + */ + public function create( $args, $assoc_args ) { + + $ret = wp_create_nav_menu( $args[0] ); + + if ( is_wp_error( $ret ) ) { + + WP_CLI::error( $ret->get_error_message() ); + + } else { + + if ( isset( $assoc_args['porcelain'] ) ) { + WP_CLI::line( $ret->term_id ); + } else { + WP_CLI::success( "Created menu $ret->term_id." ); + } + + } + } + + /** + * Delete a menu + * + * <menu> + * : The name, slug, or term ID for the menu + * + * ## EXAMPLES + * + * wp menu delete "My Menu" + */ + public function delete( $args, $_ ) { + + $ret = wp_delete_nav_menu( $args[0] ); + + if ( is_wp_error( $ret ) ) { + + WP_CLI::error( $ret->get_error_message() ); + + } else if ( ! $ret ) { + + WP_CLI::error( "Error deleting menu." ); + + } else { + + WP_CLI::success( "Menu deleted." ); + + } + } + + /** + * Get a list of menus. + * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to term_id,name,slug,count + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, ids. Default: table + * + * ## EXAMPLES + * + * wp menu list + * + * @subcommand list + */ + public function list_( $_, $assoc_args ) { + + $menus = wp_get_nav_menus(); + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $menus ); + + } + + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); + } + +} + +WP_CLI::add_command( 'menu', 'Menu_Command' ); From 491457a0cb5eb68ccc53e38491bf21681632be50 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 07:56:23 -0800 Subject: [PATCH 2718/5359] Present assigned nav menu locations in `wp menu list` --- php/commands/menu.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index 58c801930..3234d3e5e 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -10,6 +10,7 @@ class Menu_Command extends WP_CLI_Command { 'term_id', 'name', 'slug', + 'locations', 'count', ); @@ -94,6 +95,25 @@ public function delete( $args, $_ ) { public function list_( $_, $assoc_args ) { $menus = wp_get_nav_menus(); + + $menu_locations = get_nav_menu_locations(); + foreach( $menus as &$menu ) { + + $menu->locations = array(); + foreach( $menu_locations as $location => $term_id ) { + + if ( $term_id == $menu->term_id ) { + $menu->locations[] = $location; + } + + } + + // Normalize the data for some output formats + if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { + $menu->locations = implode( ',', $menu->locations ); + } + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $menus ); From 89f7e76cd7ec234359d2e6a536613a0035f747d8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 08:00:32 -0800 Subject: [PATCH 2719/5359] Easier to consolidate this code --- php/commands/menu.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 3234d3e5e..e6c9d2574 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -60,14 +60,10 @@ public function delete( $args, $_ ) { $ret = wp_delete_nav_menu( $args[0] ); - if ( is_wp_error( $ret ) ) { - - WP_CLI::error( $ret->get_error_message() ); - - } else if ( ! $ret ) { + if ( ! $ret || is_wp_error( $ret ) ) { WP_CLI::error( "Error deleting menu." ); - + } else { WP_CLI::success( "Menu deleted." ); From bd12d3b6193646fc4b73f94fa4ceb995d85bc2a8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 08:08:35 -0800 Subject: [PATCH 2720/5359] Use the nifty sub-sub-command functionality for `wp menu list` --- php/commands/menu.php | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index e6c9d2574..25107e26b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -121,4 +121,55 @@ protected function get_formatter( &$assoc_args ) { } +/** + * List, add, and delete items associated with a menu + */ +class Menu_Item_Command extends WP_CLI_Command { + + protected $obj_fields = array( + 'db_id', + 'type', + 'title', + 'url', + ); + + /** + * Get a list of items associated with a menu + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to db_id,type,title,url + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, ids. Default: table + * + * ## EXAMPLES + * + * wp menu item list <menu> + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + $items = wp_get_nav_menu_items( $args[0] ); + if ( false === $items || is_wp_error( $items ) ) { + WP_CLI::error( "Invalid menu" ); + } + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $items ); + + } + + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields ); + } + +} + WP_CLI::add_command( 'menu', 'Menu_Command' ); +WP_CLI::add_command( 'menu item', 'Menu_Item_Command' ); From 40f8ba7595d6f3ac1308f2743f75377793bd630b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 10:08:56 -0800 Subject: [PATCH 2721/5359] Update formatting of behat tests --- features/super-admin.feature | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index 421f3506c..e2f383e58 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -2,27 +2,24 @@ Feature: Manage super admins associated with a multisite instance Scenario: Add, list, and remove super admins. Given a WP multisite install - - When I try `wp user create superadmin superadmin@example.com` + When I run `wp user create superadmin superadmin@example.com` Then STDERR should be empty - - When I try `wp super-admin list` + And I run `wp super-admin list` Then STDOUT should contain: """ admin """ - When I try `wp super-admin add superadmin` + When I run `wp super-admin add superadmin` Then STDERR should be empty - - When I try `wp super-admin list` + And I run `wp super-admin list` Then STDOUT should contain: """ admin superadmin """ - When I try `wp super-admin remove admin` + When I run `wp super-admin remove admin` And I run `wp super-admin list` Then STDOUT should contain: """ From d8f59e47743b7edad0825309ce2b345022f59a50 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 13:28:30 -0800 Subject: [PATCH 2722/5359] WordPress is getting a Redis persistent object cache --- php/commands/cache.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/cache.php b/php/commands/cache.php index e522c4be5..ad0a8eafe 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -209,6 +209,11 @@ public function type( $args, $assoc_args ) { // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) } elseif ( class_exists( 'APC_Object_Cache' ) ) { $message = 'APC'; + + // Test for Redis Object Cache (https://github.com/alleyinteractive/wp-redis) + } elseif ( isset( $wp_object_cache->redis ) && is_a( $wp_object_cache->redis, 'Redis' ) ) { + $message = 'Redis'; + } else { $message = 'Unknown'; } From a2006ab77a989aa2c12a575746014ce9c3b9ce0e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 15:38:10 -0800 Subject: [PATCH 2723/5359] Less verbosity --- features/super-admin.feature | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index e2f383e58..a7a5ea1e4 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -3,17 +3,15 @@ Feature: Manage super admins associated with a multisite instance Scenario: Add, list, and remove super admins. Given a WP multisite install When I run `wp user create superadmin superadmin@example.com` - Then STDERR should be empty And I run `wp super-admin list` - Then STDOUT should contain: + Then STDOUT should be: """ admin """ When I run `wp super-admin add superadmin` - Then STDERR should be empty And I run `wp super-admin list` - Then STDOUT should contain: + Then STDOUT should be: """ admin superadmin @@ -21,7 +19,7 @@ Feature: Manage super admins associated with a multisite instance When I run `wp super-admin remove admin` And I run `wp super-admin list` - Then STDOUT should contain: + Then STDOUT should be: """ superadmin """ From cc99285428c6fd1e09581daa673f910cc28f9e99 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 15:38:50 -0800 Subject: [PATCH 2724/5359] Fix indentation --- php/commands/super-admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index b966fcd3d..4410f345c 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -74,4 +74,4 @@ private static function get_admins() { WP_CLI::error( 'This is not a multisite install.' ); } } - ) ); +) ); From f425dc23503992c9c8ff9a0a226c38a625f78f7d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 16:26:13 -0800 Subject: [PATCH 2725/5359] Consolidate Behat tests --- features/menu.feature | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 1e45bcfa6..b35ce104b 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -5,18 +5,14 @@ Feature: Manage WordPress menus Scenario: Menu CRUD operations - When I try `wp menu create "My Menu"` - Then STDERR should be empty - - When I run `wp menu list --fields=name,slug` + When I run `wp menu create "My Menu"` + And I run `wp menu list --fields=name,slug` Then STDOUT should be a table containing rows: | name | slug | | My Menu | my-menu | - When I try `wp menu delete "My Menu"` - Then STDERR should be empty - - When I run `wp menu list --format=count` + When I run `wp menu delete "My Menu"` + And I run `wp menu list --format=count` Then STDOUT should be: """ 0 From 04317ca387275bca3bae060f27b0d79208cb0343 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 18:01:12 -0800 Subject: [PATCH 2726/5359] List, assign, and remove locations from menus --- features/menu.feature | 22 +++++++++++ php/commands/menu.php | 88 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index b35ce104b..1e50911b4 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -17,3 +17,25 @@ Feature: Manage WordPress menus """ 0 """ + + Scenario: Assign / remove location from a menu + + When I run `wp theme activate twentythirteen` + And I run `wp menu theme-locations` + Then STDOUT should be a table containing rows: + | location | description | + | primary | Navigation Menu | + + When I run `wp menu create "Primary Menu"` + And I run `wp menu assign-location primary-menu primary` + And I run `wp menu list --fields=slug,locations` + Then STDOUT should be a table containing rows: + | slug | locations | + | primary-menu | primary | + + When I run `wp menu remove-location primary-menu primary` + And I run `wp menu list --fields=slug,locations` + Then STDOUT should be a table containing rows: + | slug | locations | + | primary-menu | | + diff --git a/php/commands/menu.php b/php/commands/menu.php index 25107e26b..c5e602d38 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -46,6 +46,94 @@ public function create( $args, $assoc_args ) { } } + /** + * List locations for the current theme. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, ids. Default: table + * + * @subcommand theme-locations + */ + public function theme_locations( $_, $assoc_args ) { + + $locations = get_registered_nav_menus(); + $location_objs = array(); + foreach( $locations as $location => $description ) { + $location_obj = new \stdClass; + $location_obj->location = $location; + $location_obj->description = $description; + $location_objs[] = $location_obj; + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); + $formatter->display_items( $location_objs ); + } + + /** + * Assign a location to a menu + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <location> + * : Location's slug + * + * @subcommand assign-location + */ + public function assign_location( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_registered_nav_menus(); + if ( ! array_key_exists( $location, $locations ) ) { + WP_CLI::error( "Invalid location." ); + } + + $locations = get_nav_menu_locations(); + $locations[ $location ] = $menu->term_id; + + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Assigned location to menu." ); + } + + /** + * Remove a location from a menu + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <location> + * : Location's slug + * + * @subcommand remove-location + */ + public function remove_location( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_nav_menu_locations(); + if ( ! isset( $locations[ $location ] ) || $locations[ $location ] != $menu->term_id ) { + WP_CLI::error( "Menu isn't assigned to location." ); + } + + $locations[ $location ] = 0; + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Removed location from menu." ); + + } + /** * Delete a menu * From 8d2cbca57459061f78430d745497e380f9b7e0b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 11 Feb 2014 18:17:57 -0800 Subject: [PATCH 2727/5359] Ensure `$menu_locations` is always an array --- php/commands/menu.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index c5e602d38..fcb9bb83d 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -181,6 +181,10 @@ public function list_( $_, $assoc_args ) { $menus = wp_get_nav_menus(); $menu_locations = get_nav_menu_locations(); + // < 3.6 $menu_locations could be false + if ( ! $menu_locations ) { + $menu_locations = array(); + } foreach( $menus as &$menu ) { $menu->locations = array(); From 8473ffbae52d38041888df61688bb0354783b3c1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 13:28:35 -0800 Subject: [PATCH 2728/5359] Sneak in `wp term url`, which I need for testing --- php/commands/term.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index 2e5fd3544..001fc40dc 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -320,6 +320,32 @@ public function generate( $args, $assoc_args ) { $notify->finish(); } + /** + * Get term url + * + * ## OPTIONS + * + * <taxonomy> + * : Taxonomy of the term(s) to get. + * + * <term-id>... + * : One or more IDs of terms to get the URL. + * + * ## EXAMPLES + * + * wp term url post_tag 123 + * + * wp term url post_tag 123 324 + */ + public function url( $args ) { + $term_link = get_term_link( (int)$args[1], $args[0] ); + if ( $term_link && ! is_wp_error( $term_link ) ) { + WP_CLI::line( $term_link ); + } else { + WP_CLI::error( "Invalid term." ); + } + } + private function maybe_make_child() { // 50% chance of making child term return ( mt_rand(1, 2) == 1 ); From 241258e5ddf8ceddfae4c77319f63399c81ae920 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 13:39:32 -0800 Subject: [PATCH 2729/5359] First pass at CRUD for menu items --- features/menu.feature | 36 ++++++++ php/commands/menu.php | 189 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 1e50911b4..60aea57b0 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -39,3 +39,39 @@ Feature: Manage WordPress menus | slug | locations | | primary-menu | | + + Scenario: Add / remove items from a menu + + When I run `wp post create --post_title='Test post' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp post url {POST_ID}` + Then save STDOUT as {POST_LINK} + + When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` + Then STDOUT should be a number + And save STDOUT as {TERM_ID} + + When I run `wp term url post_tag {TERM_ID}` + Then save STDOUT as {TERM_LINK} + + When I run `wp menu create "Sidebar Menu"` + And I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post"` + And I run `wp menu item add-term sidebar-menu post_tag {TERM_ID}` + And I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` + Then save STDOUT as {ITEM_ID} + + When I run `wp menu item list sidebar-menu --fields=type,title,url` + Then STDOUT should be a table containing rows: + | type | title | url | + | post_type | Custom Test Post | {POST_LINK} | + | taxonomy | Test term | {TERM_LINK} | + | custom | Apple | http://apple.com | + + When I run `wp menu item remove {ITEM_ID}` + And I run `wp menu item list sidebar-menu --format=count` + Then STDOUT should be: + """ + 2 + """ diff --git a/php/commands/menu.php b/php/commands/menu.php index fcb9bb83d..e76dceec0 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -223,6 +223,7 @@ class Menu_Item_Command extends WP_CLI_Command { 'type', 'title', 'url', + 'position', ); /** @@ -257,6 +258,194 @@ public function list_( $args, $assoc_args ) { } + /** + * Add a post as a menu item + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <post-id> + * : Post ID to add to the menu + * + * [--title=<title>] + * : Set a custom title for the menu item + * + * [--description=<description>] + * : Set a custom description for the menu item + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item + * + * [--porcelain] + * : Output just the new menu item id. + * + * @subcommand add-post + */ + public function add_post( $args, $assoc_args ) { + + $assoc_args['object-id'] = $args[1]; + unset( $args[1] ); + $post = get_post( $assoc_args['object-id'] ); + if ( ! $post ) { + WP_CLI::error( "Invalid post." ); + } + $assoc_args['object'] = $post->post_type; + + $this->add_or_update_item( 'post_type', $args, $assoc_args ); + } + + /** + * Add a taxonomy term as a menu item + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <taxonomy> + * : Taxonomy of the term to be added + * + * <term-id> + * : Term ID of the term to be added + * + * [--porcelain] + * : Output just the new menu item id. + * + * @subcommand add-term + */ + public function add_term( $args, $assoc_args ) { + + $assoc_args['object'] = $args[1]; + unset( $args[1] ); + $assoc_args['object-id'] = $args[2]; + unset( $args[2] ); + + if ( ! get_term_by( 'id', $assoc_args['object-id'], $assoc_args['object'] ) ) { + WP_CLI::error( "Invalid term." ); + } + + $this->add_or_update_item( 'taxonomy', $args, $assoc_args ); + } + + /** + * Add a custom menu item + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <title> + * : Title for the link + * + * <url> + * : Target URL for the link + * + * [--porcelain] + * : Output just the new menu item id. + * + * @subcommand add-custom + */ + public function add_custom( $args, $assoc_args ) { + + $assoc_args['title'] = $args[1]; + unset( $args[1] ); + $assoc_args['url'] = $args[2]; + unset( $args[2] ); + $this->add_or_update_item( 'custom', $args, $assoc_args ); + } + + /** + * Remove an item from a menu + * + * <db-id> + * : Database ID for the menu item. + * + * @subcommand remove + */ + public function remove( $args, $_ ) { + + $ret = wp_delete_post( $args[0], true ); + if ( $ret ) { + WP_CLI::success( "Menu item deleted." ); + } else { + WP_CLI::error( "Couldn't delete menu item." ); + } + + } + + /** + * Worker method to create new items or update existing ones + */ + private function add_or_update_item( $type, $args, $assoc_args ) { + + $menu = $args[0]; + $menu_item_db_id = ( isset( $args[1] ) ) ? $args[1] : 0; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $default_args = array( + 'position' => 0, + 'title' => '', + 'url' => '', + 'description' => '', + 'object' => '', + 'object-id' => '', + 'attr-title' => '', + 'target' => '', + 'classes' => '', + 'xfn' => '', + 'status' => '', + ); + $menu_item_args = array(); + foreach( $default_args as $key => $default_value ) { + // wp_update_nav_menu_item() has a weird argument prefix + $new_key = 'menu-item-' . $key; + if ( isset( $assoc_args[ $key ] ) ) { + $menu_item_args[ $new_key ] = $assoc_args[ $key ]; + } + } + + // Core oddly defaults to 'draft' for create, + // and 'publish' for update + // Easiest to always work with publish + if ( ! isset( $menu_item_args['menu-item-status'] ) ) { + $menu_item_args['menu-item-status'] = 'publish'; + } + + $menu_item_args['menu-item-type'] = $type; + $ret = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args ); + + if ( is_wp_error( $ret ) ) { + WP_CLI::error( $ret->get_error_message() ); + } else if ( ! $ret ) { + WP_CLI::error( "Couldn't add menu item." ); + } else { + + /** + * Set the menu + * + * wp_update_nav_menu_item() *should* take care of this, but + * depends on wp_insert_post()'s "tax_input" argument, which + * is ignored if the user can't edit the taxonomy + * + * @see https://core.trac.wordpress.org/ticket/27113 + */ + if ( ! is_object_in_term( $ret, 'nav_menu', (int) $menu->term_id ) ) { + wp_set_object_terms( $ret, array( (int)$menu->term_id ), 'nav_menu' ); + } + + if ( ! empty( $assoc_args['porcelain'] ) ) { + WP_CLI::line( $ret ); + } else { + WP_CLI::success( "Menu item added." ); + } + } + + } + protected function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields ); } From 507d339769452eb2c27e24dbae762fecee1899ce Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 13:48:37 -0800 Subject: [PATCH 2730/5359] Fix position inconsistency --- features/menu.feature | 10 +++++----- php/commands/menu.php | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 60aea57b0..531af8666 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -62,12 +62,12 @@ Feature: Manage WordPress menus And I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` Then save STDOUT as {ITEM_ID} - When I run `wp menu item list sidebar-menu --fields=type,title,url` + When I run `wp menu item list sidebar-menu --fields=type,title,position,url` Then STDOUT should be a table containing rows: - | type | title | url | - | post_type | Custom Test Post | {POST_LINK} | - | taxonomy | Test term | {TERM_LINK} | - | custom | Apple | http://apple.com | + | type | title | position | url | + | post_type | Custom Test Post | 1 | {POST_LINK} | + | taxonomy | Test term | 2 | {TERM_LINK} | + | custom | Apple | 3 | http://apple.com | When I run `wp menu item remove {ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` diff --git a/php/commands/menu.php b/php/commands/menu.php index e76dceec0..035148bdb 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -253,6 +253,12 @@ public function list_( $args, $assoc_args ) { WP_CLI::error( "Invalid menu" ); } + // Correct position inconsistency + $items = array_map( function( $item ) { + $item->position = $item->menu_order; + return $item; + }, $items ); + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $items ); From 6cbfd9f89e3557b36118fc7a1602e9f20848b9c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 14:18:47 -0800 Subject: [PATCH 2731/5359] First pass at update support for menu items --- features/menu.feature | 13 +++-- php/commands/menu.php | 124 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 531af8666..e139492a9 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -40,7 +40,7 @@ Feature: Manage WordPress menus | primary-menu | | - Scenario: Add / remove items from a menu + Scenario: Add / update / remove items from a menu When I run `wp post create --post_title='Test post' --porcelain` Then STDOUT should be a number @@ -62,12 +62,15 @@ Feature: Manage WordPress menus And I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` Then save STDOUT as {ITEM_ID} + When I run `wp menu item update {ITEM_ID} --title=WordPress --url='http://wordpress.org' --target=_blank --position=2` + Then STDERR should be empty + When I run `wp menu item list sidebar-menu --fields=type,title,position,url` Then STDOUT should be a table containing rows: - | type | title | position | url | - | post_type | Custom Test Post | 1 | {POST_LINK} | - | taxonomy | Test term | 2 | {TERM_LINK} | - | custom | Apple | 3 | http://apple.com | + | type | title | position | url | + | post_type | Custom Test Post | 1 | {POST_LINK} | + | custom | WordPress | 2 | http://wordpress.org | + | taxonomy | Test term | 3 | {TERM_LINK} | When I run `wp menu item remove {ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` diff --git a/php/commands/menu.php b/php/commands/menu.php index 035148bdb..58bbc196a 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -276,9 +276,21 @@ public function list_( $args, $assoc_args ) { * [--title=<title>] * : Set a custom title for the menu item * + * [--url=<url>] + * : Set a custom url for the menu item + * * [--description=<description>] * : Set a custom description for the menu item * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item + * + * [--target=<target>] + * : Set a custom link target for the menu item + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item + * * [--position=<position>] * : Specify the position of this menu item. * @@ -300,7 +312,7 @@ public function add_post( $args, $assoc_args ) { } $assoc_args['object'] = $post->post_type; - $this->add_or_update_item( 'post_type', $args, $assoc_args ); + $this->add_or_update_item( 'add', 'post_type', $args, $assoc_args ); } /** @@ -315,6 +327,30 @@ public function add_post( $args, $assoc_args ) { * <term-id> * : Term ID of the term to be added * + * [--title=<title>] + * : Set a custom title for the menu item + * + * [--url=<url>] + * : Set a custom url for the menu item + * + * [--description=<description>] + * : Set a custom description for the menu item + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item + * + * [--target=<target>] + * : Set a custom link target for the menu item + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item + * * [--porcelain] * : Output just the new menu item id. * @@ -331,7 +367,7 @@ public function add_term( $args, $assoc_args ) { WP_CLI::error( "Invalid term." ); } - $this->add_or_update_item( 'taxonomy', $args, $assoc_args ); + $this->add_or_update_item( 'add', 'taxonomy', $args, $assoc_args ); } /** @@ -346,6 +382,24 @@ public function add_term( $args, $assoc_args ) { * <url> * : Target URL for the link * + * [--description=<description>] + * : Set a custom description for the menu item + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item + * + * [--target=<target>] + * : Set a custom link target for the menu item + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item + * * [--porcelain] * : Output just the new menu item id. * @@ -357,7 +411,54 @@ public function add_custom( $args, $assoc_args ) { unset( $args[1] ); $assoc_args['url'] = $args[2]; unset( $args[2] ); - $this->add_or_update_item( 'custom', $args, $assoc_args ); + $this->add_or_update_item( 'add', 'custom', $args, $assoc_args ); + } + + /** + * Update a menu item + * + * <db-id> + * : Database ID for the menu item. + * + * [--title=<title>] + * : Set a custom title for the menu item + * + * [--url=<url>] + * : Set a custom url for the menu item + * + * [--description=<description>] + * : Set a custom description for the menu item + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item + * + * [--target=<target>] + * : Set a custom link target for the menu item + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item + * + * @subcommand update + */ + public function update( $args, $assoc_args ) { + + // Shuffle the position of these + $args[1] = $args[0]; + $terms = get_the_terms( $args[1], 'nav_menu' ); + if ( $terms && ! is_wp_error( $terms ) ) { + $args[0] = (int)$terms[0]->term_id; + } else { + $args[0] = 0; + } + $type = get_post_meta( $args[1], '_menu_item_type', true ); + $this->add_or_update_item( 'update', $type, $args, $assoc_args ); + } /** @@ -382,7 +483,7 @@ public function remove( $args, $_ ) { /** * Worker method to create new items or update existing ones */ - private function add_or_update_item( $type, $args, $assoc_args ) { + private function add_or_update_item( $method, $type, $args, $assoc_args ) { $menu = $args[0]; $menu_item_db_id = ( isset( $args[1] ) ) ? $args[1] : 0; @@ -405,6 +506,7 @@ private function add_or_update_item( $type, $args, $assoc_args ) { 'xfn' => '', 'status' => '', ); + $menu_item_args = array(); foreach( $default_args as $key => $default_value ) { // wp_update_nav_menu_item() has a weird argument prefix @@ -427,7 +529,11 @@ private function add_or_update_item( $type, $args, $assoc_args ) { if ( is_wp_error( $ret ) ) { WP_CLI::error( $ret->get_error_message() ); } else if ( ! $ret ) { - WP_CLI::error( "Couldn't add menu item." ); + if ( 'add' == $method ) { + WP_CLI::error( "Couldn't add menu item." ); + } else if ( 'update' == $method ) { + WP_CLI::error( "Couldn't update menu item." ); + } } else { /** @@ -443,10 +549,14 @@ private function add_or_update_item( $type, $args, $assoc_args ) { wp_set_object_terms( $ret, array( (int)$menu->term_id ), 'nav_menu' ); } - if ( ! empty( $assoc_args['porcelain'] ) ) { + if ( 'add' == $method && ! empty( $assoc_args['porcelain'] ) ) { WP_CLI::line( $ret ); } else { - WP_CLI::success( "Menu item added." ); + if ( 'add' == $method ) { + WP_CLI::success( "Menu item added." ); + } else if ( 'update' == $method ) { + WP_CLI::success( "Menu item updated." ); + } } } From 63eb7da0706a9a52ab80c49532f5519e724319e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 14:25:19 -0800 Subject: [PATCH 2732/5359] `url` is protected in WP-CLI-landia, so let's use `link` instead --- features/menu.feature | 6 +++--- php/commands/menu.php | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index e139492a9..fc28a8602 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -62,12 +62,12 @@ Feature: Manage WordPress menus And I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` Then save STDOUT as {ITEM_ID} - When I run `wp menu item update {ITEM_ID} --title=WordPress --url='http://wordpress.org' --target=_blank --position=2` + When I run `wp menu item update {ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` Then STDERR should be empty - When I run `wp menu item list sidebar-menu --fields=type,title,position,url` + When I run `wp menu item list sidebar-menu --fields=type,title,position,link` Then STDOUT should be a table containing rows: - | type | title | position | url | + | type | title | position | link | | post_type | Custom Test Post | 1 | {POST_LINK} | | custom | WordPress | 2 | http://wordpress.org | | taxonomy | Test term | 3 | {TERM_LINK} | diff --git a/php/commands/menu.php b/php/commands/menu.php index 58bbc196a..17a1e1138 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -222,7 +222,7 @@ class Menu_Item_Command extends WP_CLI_Command { 'db_id', 'type', 'title', - 'url', + 'link', 'position', ); @@ -235,7 +235,7 @@ class Menu_Item_Command extends WP_CLI_Command { * : The name, slug, or term ID for the menu * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to db_id,type,title,url + * : Limit the output to specific object fields. Defaults to db_id,type,title,link * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table @@ -253,9 +253,11 @@ public function list_( $args, $assoc_args ) { WP_CLI::error( "Invalid menu" ); } - // Correct position inconsistency + // Correct position inconsistency and + // protected `url` param in WP-CLI $items = array_map( function( $item ) { $item->position = $item->menu_order; + $item->link = $item->url; return $item; }, $items ); @@ -276,7 +278,7 @@ public function list_( $args, $assoc_args ) { * [--title=<title>] * : Set a custom title for the menu item * - * [--url=<url>] + * [--link=<link>] * : Set a custom url for the menu item * * [--description=<description>] @@ -330,7 +332,7 @@ public function add_post( $args, $assoc_args ) { * [--title=<title>] * : Set a custom title for the menu item * - * [--url=<url>] + * [--link=<link>] * : Set a custom url for the menu item * * [--description=<description>] @@ -379,7 +381,7 @@ public function add_term( $args, $assoc_args ) { * <title> * : Title for the link * - * <url> + * <link> * : Target URL for the link * * [--description=<description>] @@ -409,7 +411,7 @@ public function add_custom( $args, $assoc_args ) { $assoc_args['title'] = $args[1]; unset( $args[1] ); - $assoc_args['url'] = $args[2]; + $assoc_args['link'] = $args[2]; unset( $args[2] ); $this->add_or_update_item( 'add', 'custom', $args, $assoc_args ); } @@ -423,7 +425,7 @@ public function add_custom( $args, $assoc_args ) { * [--title=<title>] * : Set a custom title for the menu item * - * [--url=<url>] + * [--link=<link>] * : Set a custom url for the menu item * * [--description=<description>] @@ -493,6 +495,11 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { WP_CLI::error( "Invalid menu." ); } + // `url` is protected in WP-CLI, so we use `link` instead + if ( isset( $assoc_args['link'] ) ) { + $assoc_args['url'] = $assoc_args['link']; + } + $default_args = array( 'position' => 0, 'title' => '', From 1402dc39f087e1b150a784a515fef787a0452294 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 16:33:23 -0800 Subject: [PATCH 2733/5359] Use twentyeleven, which is available in all tested versions --- features/menu.feature | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index fc28a8602..94ccf7f35 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -20,11 +20,11 @@ Feature: Manage WordPress menus Scenario: Assign / remove location from a menu - When I run `wp theme activate twentythirteen` + When I run `wp theme activate twentyeleven` And I run `wp menu theme-locations` Then STDOUT should be a table containing rows: | location | description | - | primary | Navigation Menu | + | primary | Primary Menu | When I run `wp menu create "Primary Menu"` And I run `wp menu assign-location primary-menu primary` @@ -39,7 +39,6 @@ Feature: Manage WordPress menus | slug | locations | | primary-menu | | - Scenario: Add / update / remove items from a menu When I run `wp post create --post_title='Test post' --porcelain` From 37a6152466bac0c848f1fa016e50e87ab1498819 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Feb 2014 16:50:57 -0800 Subject: [PATCH 2734/5359] twentyeleven was removed from trunk. Let's try this one more time. --- features/menu.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/menu.feature b/features/menu.feature index 94ccf7f35..b9309253c 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -20,7 +20,7 @@ Feature: Manage WordPress menus Scenario: Assign / remove location from a menu - When I run `wp theme activate twentyeleven` + When I run `wp theme install p2 --activate` And I run `wp menu theme-locations` Then STDOUT should be a table containing rows: | location | description | From 35ea33ff3ef93ececfa9547491a6781bdab6d6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane?= <stephane.boisvert@automattic.com> Date: Thu, 13 Feb 2014 15:11:55 -0500 Subject: [PATCH 2735/5359] Add comma as valid character in synopsis parser Add a comma as a valid character in the value field of the synopsis parser. Example: [--allowed_themes=<themeA,themeB>] --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index fb581ea88..0d62ace78 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -36,7 +36,7 @@ private static function classify_token( $token ) { list( $param['repeating'], $token ) = self::is_repeating( $token ); $p_name = '([a-z-_]+)'; - $p_value = '([a-zA-Z-|]+)'; + $p_value = '([a-zA-Z-|,]+)'; if ( '--<field>=<value>' === $token ) { $param['type'] = 'generic'; From 8739fcce99925f5ccadcf8f0748c980c7d7492b5 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Feb 2014 22:24:33 +0200 Subject: [PATCH 2736/5359] wp eval-file: allow multiple files again fixes #1012 --- features/eval.feature | 28 ++++++++++++++++++++++++++++ php/commands/eval-file.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 features/eval.feature diff --git a/features/eval.feature b/features/eval.feature new file mode 100644 index 000000000..eff54bcc4 --- /dev/null +++ b/features/eval.feature @@ -0,0 +1,28 @@ +Feature: Evaluating PHP code and files. + + Scenario: Basics + Given a WP install + + When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));'` + Then STDOUT should be: + """ + bool(true) + """ + + Given a script1.php file: + """ + <?php + WP_CLI::line("script 1"); + """ + And a script2.php file: + """ + <?php + WP_CLI::line("script 2"); + """ + + When I run `wp eval-file script1.php script2.php` + Then STDOUT should be: + """ + script 1 + script 2 + """ diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 201bc1b34..509e62483 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -7,7 +7,7 @@ class EvalFile_Command extends WP_CLI_Command { * * ## EXAMPLES * - * [<file>] + * [<file>...] * : The path to the PHP file to execute. */ public function __invoke( $args, $assoc_args ) { From fd40c3159eaa96585c2af69941e3f7d399623d05 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Feb 2014 23:00:57 +0200 Subject: [PATCH 2737/5359] wp eval-file: allow passing arbitrary arguments to the script this behavior is more useful than evaluating multiple files, which can be replicated using --require= multiple times closes #1014 --- features/eval.feature | 14 ++++---------- php/commands/eval-file.php | 25 ++++++++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/features/eval.feature b/features/eval.feature index eff54bcc4..1e3e2bdf0 100644 --- a/features/eval.feature +++ b/features/eval.feature @@ -9,20 +9,14 @@ Feature: Evaluating PHP code and files. bool(true) """ - Given a script1.php file: + Given a script.php file: """ <?php - WP_CLI::line("script 1"); - """ - And a script2.php file: - """ - <?php - WP_CLI::line("script 2"); + WP_CLI::line( implode( ' ', $args ) ); """ - When I run `wp eval-file script1.php script2.php` + When I run `wp eval-file script.php foo bar` Then STDOUT should be: """ - script 1 - script 2 + foo bar """ diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 509e62483..62fac6c29 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -5,19 +5,26 @@ class EvalFile_Command extends WP_CLI_Command { /** * Load and execute a PHP file after loading WordPress. * - * ## EXAMPLES + * ## OPTIONS * - * [<file>...] + * <file> * : The path to the PHP file to execute. + * + * [<arg>...] + * : One or more arguments to pass to the file. */ - public function __invoke( $args, $assoc_args ) { - foreach ( $args as $file ) { - if ( !file_exists( $file ) ) { - WP_CLI::error( "'$file' does not exist." ); - } else { - include( $file ); - } + public function __invoke( $args ) { + $file = array_shift( $args ); + + if ( !file_exists( $file ) ) { + WP_CLI::error( "'$file' does not exist." ); } + + self::_eval( $file, $args ); + } + + private static function _eval( $file, $args ) { + include( $file ); } } From 3a6589733dce3a87d9539200fac390896771b86c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Feb 2014 15:47:51 +0200 Subject: [PATCH 2738/5359] remove non-portable utils/dev-build closes #995 --- CONTRIBUTING.md | 21 ++++++++++++++------- README.md | 6 +----- utils/dev-build | 34 ---------------------------------- 3 files changed, 15 insertions(+), 46 deletions(-) delete mode 100755 utils/dev-build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74af3fa22..5390d3149 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,24 @@ Contribute ========== +Setting up +---------- + +1. Clone this git repository on your local machine. +2. Install [Composer](https://getcomposer.org/) if you don't already have it. +2. Run `composer install` to fetch all the dependencies. +3. Run `./bin/wp --info` to test if everything was installed properly. +4. Download PHPUnit: `curl -L https://phar.phpunit.de/phpunit.phar > phpunit.phar` +5. Download Behat: `curl -L http://behat.org/downloads/behat.phar > behat.phar` + +Submitting patches +------------------ + Whether you want to fix a bug or implement a new feature, the process is pretty much the same: 0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, open a new issue so that you can get some initial feedback. 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. -2. Make the code changes in your fork. +2. Push the code changes from your local clone to your fork. 3. Open a pull request. It doesn't matter if the code isn't perfect. The idea is to get it reviewed early and iterate on it. @@ -22,12 +35,6 @@ There are two types of automated tests: * unit tests, implemented using [PHPUnit](http://phpunit.de/) * functional tests, implemented using [Behat](http://behat.org) -To set everything up, just run: - -```bash -./utils/dev-build -``` - ### Unit tests The unit test files are in the `tests/` directory. diff --git a/README.md b/README.md index 9d6cce864..cff45cfe7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Installing ------------ If you just want to use WP-CLI, see <http://wp-cli.org/#install>. -If you want to hack on WP-CLI, then clone this repository and run `./utils/dev-build`. +If you want to hack on WP-CLI, see [CONTRIBUTING.md](CONTRIBUTING.md). Where can I get more info? -------------------------- @@ -25,10 +25,6 @@ To suggest a feature, report a bug, or general discussion, visit the [issues sec If you're reporting a bug, please also post the output from `wp --info`. -How can I help? ---------------- -See [CONTRIBUTING.md](CONTRIBUTING.md). - Credits ------- Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: diff --git a/utils/dev-build b/utils/dev-build deleted file mode 100755 index 0637d27b9..000000000 --- a/utils/dev-build +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -command -v php > /dev/null || { - echo "can't find PHP binary" >&2 - exit 1 -} - -echo "Downloading Composer..." -curl -sS https://getcomposer.org/installer | php - -echo "Installing dependencies using Composer..." -php composer.phar install - -echo "Downloading PHPUnit..." -curl -sS https://phar.phpunit.de/phpunit.phar > phpunit.phar - -echo "Downloading Behat..." -curl -sS http://behat.org/downloads/behat.phar > behat.phar - -echo "Creating symlink for the wp command..." -for dir in /usr/bin /usr/local/bin; do - if [ -d $dir ]; then - sudo ln -sf $(pwd)/bin/wp $dir/wp - break - fi -done - -echo "Installing bash completion file..." -for dir in /etc/bash_completion.d /usr/local/etc/bash_completion.d; do - if [ -d $dir ]; then - sudo ln -sf $(pwd)/utils/wp-completion.bash $dir/wp - break - fi -done From 2f9268f1900bc6b0393ccf909932df3c4e0d2d6b Mon Sep 17 00:00:00 2001 From: "John P. Bloch" <johnpbloch@gmail.com> Date: Sat, 15 Feb 2014 12:13:28 -0500 Subject: [PATCH 2739/5359] Define the $wp_plugin_paths global array This fixes the Invalid argument supplied for foreach() warnings generated by `plugin_basename()`. Related to wp-cli/wp-cli#1015 --- php/wp-settings-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 8223901c0..7831a022a 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -172,6 +172,8 @@ // Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. wp_plugin_directory_constants( ); +$GLOBALS['wp_plugin_paths'] = array(); + // Load must-use plugins. foreach ( wp_get_mu_plugins() as $mu_plugin ) { include_once( $mu_plugin ); From 2af7afbc22cfe651c3bc3b940cde81b0dc7ec4ac Mon Sep 17 00:00:00 2001 From: "John P. Bloch" <johnpbloch@gmail.com> Date: Sat, 15 Feb 2014 12:21:29 -0500 Subject: [PATCH 2740/5359] Add support for symlinking plugins if available Adds support for the (new in 3.9) automatic detection and handling of symlinked plugins. Related to wp-cli/wp-cli#1015 --- php/wp-settings-cli.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 7831a022a..d566ec1d2 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -172,10 +172,15 @@ // Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. wp_plugin_directory_constants( ); -$GLOBALS['wp_plugin_paths'] = array(); +$symlinked_plugins_supported = function_exists( 'wp_register_plugin_realpath' ); +if ( $symlinked_plugins_supported ) { + $GLOBALS['wp_plugin_paths'] = array(); +} // Load must-use plugins. foreach ( wp_get_mu_plugins() as $mu_plugin ) { + if ( $symlinked_plugins_supported ) + wp_register_plugin_realpath( $mu_plugin ); include_once( $mu_plugin ); } unset( $mu_plugin ); @@ -183,8 +188,11 @@ // Load network activated plugins. if ( is_multisite() ) { foreach( wp_get_active_network_plugins() as $network_plugin ) { - if ( !Utils\is_plugin_skipped( $network_plugin ) ) + if ( !Utils\is_plugin_skipped( $network_plugin ) ) { + if ( $symlinked_plugins_supported ) + wp_register_plugin_realpath( $network_plugin ); include_once( $network_plugin ); + } } unset( $network_plugin ); } @@ -212,10 +220,14 @@ register_theme_directory( get_theme_root() ); // Load active plugins. -foreach ( wp_get_active_and_valid_plugins() as $plugin ) - if ( !Utils\is_plugin_skipped( $plugin ) ) +foreach ( wp_get_active_and_valid_plugins() as $plugin ) { + if ( !Utils\is_plugin_skipped( $plugin ) ) { + if ( $symlinked_plugins_supported ) + wp_register_plugin_realpath( $plugin ); include_once( $plugin ); -unset( $plugin ); + } +} +unset( $plugin, $symlinked_plugins_supported ); // Load pluggable functions. require( ABSPATH . WPINC . '/pluggable.php' ); From b35e302bae4db4d79c9fbba0480c990749054db0 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sat, 15 Feb 2014 22:58:56 -0800 Subject: [PATCH 2741/5359] add functional tests --- features/roles.feature | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/features/roles.feature b/features/roles.feature index 139cc41b9..bf62c1c2b 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -9,3 +9,36 @@ Feature: Manage WordPress roles | name | role | | Subscriber | subscriber | | Editor | editor | + + Scenario: Resetting a role + When I run `wp role reset author` + Then STDOUT should be: + """ + Success: Reset 0/1 roles + """ + + When I run `wp cap remove author read` + And I run `wp role reset author` + Then STDOUT should be: + """ + Success: Reset 1/1 roles + """ + + When I run `wp role reset author editor` + Then STDOUT should be: + """ + Success: Reset 0/2 roles + """ + + When I run `wp cap remove author read` + And I run `wp role reset author editor` + Then STDOUT should be: + """ + Success: Reset 1/2 roles + """ + + When I run `wp role reset --all` + Then STDOUT should be: + """ + Success: All default roles reset. + """ \ No newline at end of file From 38cbf81a445b2e153341cc30914a0bf2c05fc584 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sun, 16 Feb 2014 14:32:24 -0800 Subject: [PATCH 2742/5359] First pass at 'wp theme mod' commands. With functional tests --- features/theme-mod.feature | 63 +++++++++++++++++++ features/thememod.feature | 23 +++++++ php/commands/theme.php | 126 +++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 features/theme-mod.feature create mode 100644 features/thememod.feature diff --git a/features/theme-mod.feature b/features/theme-mod.feature new file mode 100644 index 000000000..7ef2115f7 --- /dev/null +++ b/features/theme-mod.feature @@ -0,0 +1,63 @@ +Feature: Manage WordPress theme mods + + Scenario: Getting theme mods + Given a WP install + + When I run `wp theme mod get --all` + Then STDOUT should be a table containing rows: + | key | value | + + When I try `wp theme mod get` + Then STDERR should contain: + """ + You must specify at least one mod or use --all. + """ + + When I run `wp theme mod set background_color 123456` + And I run `wp theme mod get --all` + Then STDOUT should be a table containing rows: + | key | value | + | background_color | 123456 | + + When I run `wp theme mod set background_color 123456` + And I run `wp theme mod get background_color header_textcolor` + Then STDOUT should be a table containing rows: + | key | value | + | background_color | 123456 | + | header_textcolor | | + + Scenario: Setting theme mods + Given a WP install + + When I run `wp theme mod set background_color 123456` + Then STDOUT should be: + """ + Success: Theme mod background_color set to 123456 + """ + + Scenario: Removing theme mods + Given a WP install + + When I run `wp theme mod remove --all` + Then STDOUT should be: + """ + Success: Theme mods removed. + """ + + When I try `wp theme mod remove` + Then STDERR should contain: + """ + You must specify at least one mod or use --all. + """ + + When I run `wp theme mod remove background_color` + Then STDOUT should be: + """ + Success: 1 mods removed. + """ + + When I run `wp theme mod remove background_color header_textcolor` + Then STDOUT should be: + """ + Success: 2 mods removed. + """ diff --git a/features/thememod.feature b/features/thememod.feature new file mode 100644 index 000000000..6dccbf816 --- /dev/null +++ b/features/thememod.feature @@ -0,0 +1,23 @@ +Feature: Manage WordPress theme mods + + Scenario: Getting theme mods + Given a WP install + + When I run `wp theme mod get --all` + Then STDOUT should be a table containing rows: + | key | value | + + Scenario: Setting theme mods + Given a WP install + + When I run `wp theme mod set background_color 123456` + Then STDOUT should be: + """ + Success: Theme mod background_color set to 123456 + """ + + When I run `wp theme mod set background_color 123456` + And I run `wp theme mod get --all` + Then STDOUT should be a table containing rows: + | key | value | + | background_color | 123456 | diff --git a/php/commands/theme.php b/php/commands/theme.php index c0d72003d..24df49e2e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -520,5 +520,131 @@ public function list_( $_, $assoc_args ) { } } +/** + * Manage theme mods. + * + */ +class Theme_Mod_command extends WP_CLI_Command { + + /** + * Get theme mod(s). + * + * ## OPTIONS + * + * [<mod>...] + * : One or more mods to get. + * + * [--all] + * : List all theme mods + * + * ## EXAMPLES + * + * wp theme mod get --all + * wp theme mod get background_color + * wp theme mod get background_color header_textcolor + */ + public function get( $args = array(), $assoc_args = array() ) { + + if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + WP_CLI::error( "You must specify at least one mod or use --all." ); + } + + if ( isset( $assoc_args['all'] ) && $assoc_args['all'] ) { + $args = array(); + } + + $list = array(); + $mods = get_theme_mods(); + if ( ! empty( $mods ) ) + foreach( $mods as $k => $v ) { + // if mods were given, skip the others + if ( ! empty( $args ) && ! in_array( $k, $args ) ) continue; + + if ( is_array( $v ) ) { + $list[] = array( 'key' => $k, 'value' => '=>' ); + foreach( $v as $_k => $_v ) { + $list[] = array( 'key' => " $_k", 'value' => $_v ); + } + } else { + $list[] = array( 'key' => $k, 'value' => $v ); + } + + } + + // For unset mods, show blank value + foreach( $args as $mod ) { + if ( ! isset( $mods[ $mod ] ) ) { + $list[] = array( 'key' => $mod, 'value' => '' ); + } + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array('key', 'value'), 'thememods' ); + $formatter->display_items( $list ); + + } + + /** + * Remove theme mod(s). + * + * ## OPTIONS + * + * [<mod>...] + * : One or more mods to get. + * + * [--all] + * : Remove all theme mods + * + * ## EXAMPLES + * + * wp theme mod remove --all + * wp theme mod remove background_color + * wp theme mod remove background_color header_textcolor + */ + public function remove( $args = array(), $assoc_args = array() ) { + + if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + WP_CLI::error( "You must specify at least one mod or use --all." ); + } + + if ( isset( $assoc_args['all'] ) && $assoc_args['all'] ) { + remove_theme_mods(); + WP_CLI::success( 'Theme mods removed.' ); + return; + } + + foreach( $args as $mod ) { + remove_theme_mod( $mod ); + } + + WP_CLI::success( sprintf( '%d mods removed.', count( $args ) ) ); + + } + + /** + * Set a theme mod. + * + * ## OPTIONS + * + * <mod> + * : Theme mod to set. + * + * <value> + * : Value to for mod. + * + * ## EXAMPLES + * + * wp theme mod set background_color 000000 + */ + public function set( $args = array(), $assoc_args = array() ) { + list( $mod, $value ) = $args; + set_theme_mod( $mod, $value ); + + if ( $value == get_theme_mod( $mod ) ) + WP_CLI::success( sprintf( "Theme mod %s set to %s", $mod, $value ) ); + } + +} + WP_CLI::add_command( 'theme', 'Theme_Command' ); +WP_CLI::add_command( 'theme mod', 'Theme_Mod_Command' ); From a45c8be9fe2c88d8ac448f9d03b98eb1edbdc286 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sun, 16 Feb 2014 14:35:02 -0800 Subject: [PATCH 2743/5359] remove old file --- features/thememod.feature | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 features/thememod.feature diff --git a/features/thememod.feature b/features/thememod.feature deleted file mode 100644 index 6dccbf816..000000000 --- a/features/thememod.feature +++ /dev/null @@ -1,23 +0,0 @@ -Feature: Manage WordPress theme mods - - Scenario: Getting theme mods - Given a WP install - - When I run `wp theme mod get --all` - Then STDOUT should be a table containing rows: - | key | value | - - Scenario: Setting theme mods - Given a WP install - - When I run `wp theme mod set background_color 123456` - Then STDOUT should be: - """ - Success: Theme mod background_color set to 123456 - """ - - When I run `wp theme mod set background_color 123456` - And I run `wp theme mod get --all` - Then STDOUT should be a table containing rows: - | key | value | - | background_color | 123456 | From 859385d884776ec0f8b7af6d80eec9cbb3cd1737 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sun, 16 Feb 2014 18:37:20 -0800 Subject: [PATCH 2744/5359] doc fix for theme mod --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 24df49e2e..4467beea7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -589,7 +589,7 @@ public function get( $args = array(), $assoc_args = array() ) { * ## OPTIONS * * [<mod>...] - * : One or more mods to get. + * : One or more mods to remove. * * [--all] * : Remove all theme mods From 1bbf78c712a132d1c0e1329907d04ef6f12de8e9 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Mon, 17 Feb 2014 08:47:49 -0800 Subject: [PATCH 2745/5359] formatting fixes for theme mod --- php/commands/theme.php | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 4467beea7..e5ccf8cdc 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -399,7 +399,7 @@ public function get( $args, $assoc_args ) { $theme_vars = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', ); $theme_obj = new stdClass; - foreach( $theme_vars as $var ) { + foreach ( $theme_vars as $var ) { $theme_obj->$var = $theme->$var; } @@ -537,10 +537,13 @@ class Theme_Mod_command extends WP_CLI_Command { * [--all] * : List all theme mods * + * [--format=<format>] + * : Accepted values: table, json. Default: table + * * ## EXAMPLES * * wp theme mod get --all - * wp theme mod get background_color + * wp theme mod get background_color --format=json * wp theme mod get background_color header_textcolor */ public function get( $args = array(), $assoc_args = array() ) { @@ -555,14 +558,17 @@ public function get( $args = array(), $assoc_args = array() ) { $list = array(); $mods = get_theme_mods(); - if ( ! empty( $mods ) ) - foreach( $mods as $k => $v ) { + if ( ! is_array( $mods ) ) { + // if no mods are set (perhaps new theme), make sure foreach still works + $mods = array(); + } + foreach ( $mods as $k => $v ) { // if mods were given, skip the others if ( ! empty( $args ) && ! in_array( $k, $args ) ) continue; if ( is_array( $v ) ) { $list[] = array( 'key' => $k, 'value' => '=>' ); - foreach( $v as $_k => $_v ) { + foreach ( $v as $_k => $_v ) { $list[] = array( 'key' => " $_k", 'value' => $_v ); } } else { @@ -572,7 +578,7 @@ public function get( $args = array(), $assoc_args = array() ) { } // For unset mods, show blank value - foreach( $args as $mod ) { + foreach ( $args as $mod ) { if ( ! isset( $mods[ $mod ] ) ) { $list[] = array( 'key' => $mod, 'value' => '' ); } @@ -612,7 +618,7 @@ public function remove( $args = array(), $assoc_args = array() ) { return; } - foreach( $args as $mod ) { + foreach ( $args as $mod ) { remove_theme_mod( $mod ); } @@ -626,10 +632,10 @@ public function remove( $args = array(), $assoc_args = array() ) { * ## OPTIONS * * <mod> - * : Theme mod to set. + * : The name of the theme mod to set or update. * - * <value> - * : Value to for mod. + * [<value>] + * : The new value. * * ## EXAMPLES * @@ -637,10 +643,14 @@ public function remove( $args = array(), $assoc_args = array() ) { */ public function set( $args = array(), $assoc_args = array() ) { list( $mod, $value ) = $args; + set_theme_mod( $mod, $value ); - if ( $value == get_theme_mod( $mod ) ) - WP_CLI::success( sprintf( "Theme mod %s set to %s", $mod, $value ) ); + if ( $value == get_theme_mod( $mod ) ) { + WP_CLI::success( sprintf( "Theme mod %s set to %s", $mod, $value ) ); + } else { + WP_CLI::success( sprintf( "Could not update theme mod %s", $mod ) ); + } } } From b6054e42223008533713723d44e135f768a747a6 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Mon, 17 Feb 2014 08:53:37 -0800 Subject: [PATCH 2746/5359] value not optional in theme mod set --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index e5ccf8cdc..d3fa8fe6e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -634,7 +634,7 @@ public function remove( $args = array(), $assoc_args = array() ) { * <mod> * : The name of the theme mod to set or update. * - * [<value>] + * <value> * : The new value. * * ## EXAMPLES From be2230e3de81e019011142655c79ccb4893c38c5 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Mon, 17 Feb 2014 19:10:05 +0100 Subject: [PATCH 2747/5359] fix wp rewrite flush --hard doesn't generate .htaccess --- features/rewrite.feature | 11 +++++++++++ php/commands/rewrite.php | 3 +++ 2 files changed, 14 insertions(+) diff --git a/features/rewrite.feature b/features/rewrite.feature index 2d5ec586f..f78c8504e 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -33,3 +33,14 @@ Feature: Manage WordPress rewrites Then STDOUT should be CSV containing: | match | query | source | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | + + Scenario: Generate .htaccess on hard flush + Given a WP install + And a wp-cli.yml file: + """ + apache_modules: [mod_rewrite] + """ + + When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` + And I run `wp rewrite flush --hard` + Then the .htaccess file should exist diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 64432ad64..3f33c1c92 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -208,6 +208,9 @@ private static function apache_modules() { global $is_apache; $is_apache = true; + // needed for get_home_path() and .htaccess location + $_SERVER['SCRIPT_FILENAME'] = ABSPATH; + function apache_get_modules() { return WP_CLI::get_config( 'apache_modules' ); } From a960d9f75c427d65eec3070cd0e1d810bcf62e71 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Tue, 18 Feb 2014 20:52:38 +0100 Subject: [PATCH 2748/5359] make all mysql command run with --no-defaults fix #377 regression introduced in a9f7b7c76d6e22f38ae922efa86de13f03324c63 --- php/commands/db.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 4afa05da3..712bc65a5 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -53,7 +53,7 @@ function reset( $_, $assoc_args ) { * Optimize the database. */ function optimize() { - self::run( Utils\esc_cmd( 'mysqlcheck %s', DB_NAME ), array( + self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( 'optimize' => true, ) ); @@ -64,7 +64,7 @@ function optimize() { * Repair the database. */ function repair() { - self::run( Utils\esc_cmd( 'mysqlcheck %s', DB_NAME ), array( + self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( 'repair' => true, ) ); @@ -133,7 +133,7 @@ function export( $args, $assoc_args ) { $assoc_args['result-file'] = $result_file; } - self::run( Utils\esc_cmd( 'mysqldump %s', DB_NAME ), $assoc_args ); + self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s', DB_NAME ), $assoc_args ); if ( ! $stdout ) { WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); From 11991d09ce981315b9bc97af42ff7fb34fa4ce09 Mon Sep 17 00:00:00 2001 From: Clemens Tolboom <clemens@build2be.com> Date: Wed, 19 Feb 2014 12:31:03 +0100 Subject: [PATCH 2749/5359] Add require-dev in order to remove downloads of phars. --- CONTRIBUTING.md | 10 ++++------ composer.json | 4 ++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5390d3149..3efb618b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,6 @@ Setting up 2. Install [Composer](https://getcomposer.org/) if you don't already have it. 2. Run `composer install` to fetch all the dependencies. 3. Run `./bin/wp --info` to test if everything was installed properly. -4. Download PHPUnit: `curl -L https://phar.phpunit.de/phpunit.phar > phpunit.phar` -5. Download Behat: `curl -L http://behat.org/downloads/behat.phar > behat.phar` Submitting patches ------------------ @@ -41,7 +39,7 @@ The unit test files are in the `tests/` directory. To run the unit tests, just execute: - php phpunit.phar + vendor/phpunit/phpunit/phpunit.php ### Functional tests @@ -55,13 +53,13 @@ Running the following as root in MySQL should do the trick: Then, to run the entire test suite: - php behat.phar --expand + vendor/behat/behat/bin/behat --expand Or to test a single feature: - php behat.phar features/core.feature + vendor/behat/behat/bin/behat features/core.feature -More info can be found from `php behat.phar --help`. +More info can be found from `vendor/behat/behat/bin/behat --help`. Finally... ---------- diff --git a/composer.json b/composer.json index 0dbcad2cf..db7c484be 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,10 @@ "symfony/finder": "~2.3", "nb/oxymel": "0.1.0" }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "behat/behat": "2.5.*@dev" + }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" }, From 93d721c6c0c051c622a7faa80050d140f74cb1a7 Mon Sep 17 00:00:00 2001 From: Clemens Tolboom <clemens@build2be.com> Date: Wed, 19 Feb 2014 13:31:32 +0100 Subject: [PATCH 2750/5359] Use vendor/bin --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3efb618b3..aaf85e2f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ The unit test files are in the `tests/` directory. To run the unit tests, just execute: - vendor/phpunit/phpunit/phpunit.php + vendor/bin/phpunit ### Functional tests @@ -53,11 +53,11 @@ Running the following as root in MySQL should do the trick: Then, to run the entire test suite: - vendor/behat/behat/bin/behat --expand + vendor/bin/behat --expand Or to test a single feature: - vendor/behat/behat/bin/behat features/core.feature + vendor/bin/behat features/core.feature More info can be found from `vendor/behat/behat/bin/behat --help`. From 3bdec1cbf8323b564157bf4035f35fdc6c8ae682 Mon Sep 17 00:00:00 2001 From: Clemens Tolboom <clemens@build2be.com> Date: Wed, 19 Feb 2014 14:30:02 +0100 Subject: [PATCH 2751/5359] No need for behat through ci/perpare.sh --- ci/prepare.sh | 3 --- ci/test.sh | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 562701740..611a068de 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -12,9 +12,6 @@ php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet mv wp-cli.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp -# Travis CI doesn't come with Behat pre-installed -curl http://behat.org/downloads/behat.phar > behat.phar - # Install CodeSniffer things ./ci/prepare-codesniffer.sh diff --git a/ci/test.sh b/ci/test.sh index c213a4231..9e14eacf9 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -3,10 +3,10 @@ set -ex # Run the unit tests -phpunit +vendor/bin/phpunit # Run the functional tests -php behat.phar --format progress +vendor/bin/behat --format progress # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From 818ac72ef457a427b22a3c69d6b4399205ccd7bd Mon Sep 17 00:00:00 2001 From: Clemens Tolboom <clemens@build2be.com> Date: Wed, 19 Feb 2014 14:31:59 +0100 Subject: [PATCH 2752/5359] No behat @dev versions. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index db7c484be..f2972a145 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ }, "require-dev": { "phpunit/phpunit": "3.7.*", - "behat/behat": "2.5.*@dev" + "behat/behat": "2.5.*" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" From 38ff3823614b034185f0929393e64d3208dbc32c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 19 Feb 2014 14:05:59 +0000 Subject: [PATCH 2753/5359] make phpunit & behat paths more tab-completion friendly --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aaf85e2f4..563153a4e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ The unit test files are in the `tests/` directory. To run the unit tests, just execute: - vendor/bin/phpunit + ./vendor/bin/phpunit ### Functional tests @@ -53,13 +53,13 @@ Running the following as root in MySQL should do the trick: Then, to run the entire test suite: - vendor/bin/behat --expand + ./vendor/bin/behat --expand Or to test a single feature: - vendor/bin/behat features/core.feature + ./vendor/bin/behat features/core.feature -More info can be found from `vendor/behat/behat/bin/behat --help`. +More info can be found by using `./vendor/bin/behat --help`. Finally... ---------- From 9098f32af60b1bafcdca0797875fd36ad29199f0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 19 Feb 2014 22:46:11 +0000 Subject: [PATCH 2754/5359] wp eval-file: mention $args and add example see #1014 --- php/commands/eval-file.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 62fac6c29..92798f544 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -11,7 +11,11 @@ class EvalFile_Command extends WP_CLI_Command { * : The path to the PHP file to execute. * * [<arg>...] - * : One or more arguments to pass to the file. + * : One or more arguments to pass to the file. They are placed in the $args variable. + * + * ## EXAMPLES + * + * wp eval-file my-code.php value1 value2 */ public function __invoke( $args ) { $file = array_shift( $args ); From 888f06973307fd86de8baf072e8f93d4bffc5c59 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 21 Feb 2014 13:46:46 -0300 Subject: [PATCH 2755/5359] fix test that was passing with the wrong error message --- features/help.feature | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/features/help.feature b/features/help.feature index b0225d0c0..ac576ad9a 100644 --- a/features/help.feature +++ b/features/help.feature @@ -1,7 +1,7 @@ Feature: Get help about WP-CLI commands Scenario: Help for internal commands - Given an empty directory + Given a WP install When I run `wp help` Then STDOUT should not be empty @@ -17,7 +17,10 @@ Feature: Get help about WP-CLI commands When I try `wp help non-existent-command` Then the return code should be 1 - And STDERR should not be empty + And STDERR should be: + """ + Error: 'non-existent-command' is not a registered wp command. + """ Scenario: Help for third-party commands Given a WP install From 0e63bd32a329800d1febc1e86e82e3423c638e06 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 21 Feb 2014 14:08:52 -0300 Subject: [PATCH 2756/5359] fix error message when fetching help for nested commands (fixes #1017) --- features/help.feature | 7 +++++++ php/commands/help.php | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index ac576ad9a..05c2f9975 100644 --- a/features/help.feature +++ b/features/help.feature @@ -21,6 +21,13 @@ Feature: Get help about WP-CLI commands """ Error: 'non-existent-command' is not a registered wp command. """ + + When I try `wp help non-existent-command non-existent-subcommand` + Then the return code should be 1 + And STDERR should be: + """ + Error: 'non-existent-command non-existent-subcommand' is not a registered wp command. + """ Scenario: Help for third-party commands Given a WP install diff --git a/php/commands/help.php b/php/commands/help.php index b9abfcc0c..6d5001da5 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -28,7 +28,8 @@ function __invoke( $args, $assoc_args ) { // WordPress is already loaded, so there's no chance we'll find the command if ( function_exists( 'add_filter' ) ) { - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $args[0] ) ); + $command_string = implode( ' ', $args ); + \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $command_string ) ); } } From cc48e675739b2a22f469b61abe7663e0efc329d2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 22 Feb 2014 23:04:38 +0000 Subject: [PATCH 2757/5359] set only the MYSQL_PWD environment variable this avoids having to use the unreliable $_ENV superglobal fixes #950 --- php/utils.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/utils.php b/php/utils.php index 7ce26e81b..a46e45f65 100644 --- a/php/utils.php +++ b/php/utils.php @@ -323,15 +323,14 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); } - $env = (array) $_ENV; if ( isset( $assoc_args['pass'] ) ) { - $env['MYSQL_PWD'] = $assoc_args['pass']; + $cmd = esc_cmd( 'MYSQL_PWD=%s ', $assoc_args['pass'] ) . $cmd; unset( $assoc_args['pass'] ); } $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); - $proc = proc_open( $final_cmd, $descriptors, $pipes, null, $env ); + $proc = proc_open( $final_cmd, $descriptors, $pipes ); if ( !$proc ) exit(1); From d99477a64dc60c1d5f18387d8e27bd42320add34 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 24 Feb 2014 12:15:13 -0300 Subject: [PATCH 2758/5359] split test scenario for help command (one for when wp is installed and other for when it is not) see #1034 --- features/help.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index 05c2f9975..994358c3f 100644 --- a/features/help.feature +++ b/features/help.feature @@ -1,7 +1,7 @@ Feature: Get help about WP-CLI commands Scenario: Help for internal commands - Given a WP install + Given an empty directory When I run `wp help` Then STDOUT should not be empty @@ -15,6 +15,9 @@ Feature: Get help about WP-CLI commands When I run `wp help help` Then STDOUT should not be empty + Scenario: Help for nonexistent commands + Given a WP install + When I try `wp help non-existent-command` Then the return code should be 1 And STDERR should be: From 38feb897bb07e9ecb06b48250ec4c5eeb40c8a5b Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Mon, 24 Feb 2014 23:03:16 -0800 Subject: [PATCH 2759/5359] Add support for exporting specific tables --- php/commands/db.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index 712bc65a5..cb69d6740 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -119,6 +119,9 @@ function query( $args ) { * [--<field>=<value>] * : Extra arguments to pass to mysqldump * + * [--tables=<tables>] + * : The comma separated list of specific tables to export. Excluding this parameter will export all tables + * * ## EXAMPLES * * wp db dump --add-drop-table @@ -133,7 +136,13 @@ function export( $args, $assoc_args ) { $assoc_args['result-file'] = $result_file; } - self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s', DB_NAME ), $assoc_args ); + if ( isset( $assoc_args['tables'] ) ) { + $tables = explode( ',', $assoc_args['tables'] ); + unset( $assoc_args['tables'] ); + self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s --tables %s', DB_NAME, implode( ' ', $tables ) ), $assoc_args ); + } else { + self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s', DB_NAME ), $assoc_args ); + } if ( ! $stdout ) { WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); From 31031e30b93dadfc51a0f9b58d4f1f62b45083cc Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Wed, 26 Feb 2014 03:54:08 -0800 Subject: [PATCH 2760/5359] Dynamically build mysqldump command rather than repeating it --- php/commands/db.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index cb69d6740..b3b0cd238 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -136,14 +136,23 @@ function export( $args, $assoc_args ) { $assoc_args['result-file'] = $result_file; } + $command = 'mysqldump --no-defaults %s'; + $command_esc_args = array( DB_NAME ); + if ( isset( $assoc_args['tables'] ) ) { $tables = explode( ',', $assoc_args['tables'] ); unset( $assoc_args['tables'] ); - self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s --tables %s', DB_NAME, implode( ' ', $tables ) ), $assoc_args ); - } else { - self::run( Utils\esc_cmd( 'mysqldump --no-defaults %s', DB_NAME ), $assoc_args ); + $command .= ' --tables'; + foreach ( $tables as $table ) { + $command .= ' %s'; + $command_esc_args[] = trim( $table ); + } } + $escaped_command = call_user_func_array( '\WP_CLI\Utils\esc_cmd', array_merge( array( $command ), $command_esc_args ) ); + + self::run( $escaped_command, $assoc_args ); + if ( ! $stdout ) { WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } From f69a55cfd6f6e4b684a852f73876747da517bb7e Mon Sep 17 00:00:00 2001 From: Will Anderson <will@itsananderson.com> Date: Wed, 26 Feb 2014 03:56:09 -0800 Subject: [PATCH 2761/5359] Add example for exporting specific tables --- php/commands/db.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/db.php b/php/commands/db.php index b3b0cd238..998b4ab42 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -125,6 +125,7 @@ function query( $args ) { * ## EXAMPLES * * wp db dump --add-drop-table + * wp db dump --tables=wp_options,wp_users * * @alias dump */ From 193b6d8a2e05931bc990f5c6990be4d4369f92b7 Mon Sep 17 00:00:00 2001 From: Andrey Savchenko <contact@rarst.net> Date: Wed, 26 Feb 2014 21:16:44 +0200 Subject: [PATCH 2762/5359] Whitelisted underscore in synopsis values. --- php/WP_CLI/SynopsisParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 0d62ace78..3d440a000 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -36,7 +36,7 @@ private static function classify_token( $token ) { list( $param['repeating'], $token ) = self::is_repeating( $token ); $p_name = '([a-z-_]+)'; - $p_value = '([a-zA-Z-|,]+)'; + $p_value = '([a-zA-Z-_|,]+)'; if ( '--<field>=<value>' === $token ) { $param['type'] = 'generic'; From b26d090c63ab39036109569c9ff45ca5d6b75608 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 2 Mar 2014 14:16:14 +0000 Subject: [PATCH 2763/5359] increase wordwrap width to 90 fixes display of long 'wp core config' example --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 6d5001da5..33d1d9e46 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -48,7 +48,7 @@ private static function show_help( $command ) { $longdesc = $command->get_longdesc(); if ( $longdesc ) { - $out .= wordwrap( $longdesc, 79 ) . "\n"; + $out .= wordwrap( $longdesc, 90 ) . "\n"; } // section headers From 30bdbace08718944aa8681184a2655c08363ac78 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Mar 2014 14:18:22 -0800 Subject: [PATCH 2764/5359] Turn `validate_role()` into a more helpful method and apply it in more places --- php/commands/user.php | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 1767f80ed..a72b33ead 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -196,9 +196,7 @@ public function create( $args, $assoc_args ) { if ( isset( $assoc_args['role'] ) ) { $role = $assoc_args['role']; - if ( !self::validate_role( $role ) ) { - WP_CLI::error( "Invalid role: $role" ); - } + self::validate_role( $role ); } else { $role = get_option('default_role'); } @@ -275,9 +273,7 @@ public function generate( $args, $assoc_args ) { $role = $assoc_args['role']; - if ( !self::validate_role( $role ) ) { - WP_CLI::error( "Invalid role: $role" ); - } + self::validate_role( $role ); $user_count = count_users(); $total = $user_count['total_users']; @@ -332,6 +328,8 @@ public function set_role( $args, $assoc_args ) { $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); + self::validate_role( $role ); + // Multisite if ( function_exists( 'add_user_to_blog' ) ) add_user_to_blog( get_current_blog_id(), $user->ID, $role ); @@ -364,6 +362,8 @@ public function add_role( $args, $assoc_args ) { $role = $args[1]; + self::validate_role( $role ); + $user->add_role( $role ); WP_CLI::success( sprintf( "Added '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); @@ -581,12 +581,19 @@ public function import_csv( $args, $assoc_args ) { } } + /** + * Check whether the role is valid + * + * @param string + */ private static function validate_role( $role ) { - if ( empty( $role ) || ! is_null( get_role( $role ) ) ) { - return true; + + if ( ! empty( $role ) && is_null( get_role( $role ) ) ) { + WP_CLI::error( sprintf( "Role doesn't exist: %s", $role ) ); } - return false; + } + } /** @@ -698,6 +705,7 @@ private function replace_login_with_user_id( $args ) { $args[0] = $user->ID; return $args; } + } WP_CLI::add_command( 'user', 'User_Command' ); From 54ceede7b04a6f45ed8968f6ee0da6406997e75e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Mar 2014 15:28:03 -0800 Subject: [PATCH 2765/5359] Also validate `wp user remove-role` --- php/commands/user.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index a72b33ead..4ba5d734b 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -393,6 +393,8 @@ public function remove_role( $args, $assoc_args ) { if ( isset( $args[1] ) ) { $role = $args[1]; + self::validate_role( $role ); + $user->remove_role( $role ); WP_CLI::success( sprintf( "Removed '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); From 2b305d2fdf84d6aee6239295bc284dc472c723bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Mar 2014 15:29:08 -0800 Subject: [PATCH 2766/5359] `$role` can be empty for `wp user generate` --- php/commands/user.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 4ba5d734b..256b12b33 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -273,7 +273,9 @@ public function generate( $args, $assoc_args ) { $role = $assoc_args['role']; - self::validate_role( $role ); + if ( ! empty( $role ) ) { + self::validate_role( $role ); + } $user_count = count_users(); $total = $user_count['total_users']; From 63a152e9f9b24f98b34d68cb594ec1b27979ae18 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Mar 2014 15:29:52 -0800 Subject: [PATCH 2767/5359] Add some tests for error conditions with roles --- features/user.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/user.feature b/features/user.feature index f25333519..18cf6d950 100644 --- a/features/user.feature +++ b/features/user.feature @@ -106,6 +106,15 @@ Feature: Manage WordPress users administrator, editor """ + When I try `wp user add-role 1 edit` + Then STDERR should not be empty + + When I try `wp user set-role 1 edit` + Then STDERR should not be empty + + When I try `wp user remove-role 1 edit` + Then STDERR should not be empty + When I run `wp user set-role 1 author` Then STDOUT should not be empty And I run `wp user get 1` From 2a457208c6d5f2e2561a416a554b9573a3fff324 Mon Sep 17 00:00:00 2001 From: Clemens Tolboom <clemens@build2be.com> Date: Thu, 6 Mar 2014 17:34:48 +0100 Subject: [PATCH 2768/5359] Changed dump into export. --- php/commands/db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 998b4ab42..2230470de 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -124,8 +124,8 @@ function query( $args ) { * * ## EXAMPLES * - * wp db dump --add-drop-table - * wp db dump --tables=wp_options,wp_users + * wp db export --add-drop-table + * wp db export --tables=wp_options,wp_users * * @alias dump */ From 13ee41b59271a1e80dfc3278e48272bed6d27de2 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Mar 2014 12:21:09 +0000 Subject: [PATCH 2769/5359] show error when invalid format is passed --- php/WP_CLI/Formatter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 7d3eacc0b..3b349f6de 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -85,6 +85,9 @@ private function format( $items ) { echo json_encode( $out ); break; + + default: + \WP_CLI::error( 'Invalid format: ' . $this->args['format'] ); } } From f7f6d605af901adaa09034f96389bbe37d2ee6af Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Mar 2014 12:30:06 +0000 Subject: [PATCH 2770/5359] move --format=ids handling to individual commands --- php/commands/post.php | 12 +++++++----- php/commands/term.php | 9 ++++++--- php/commands/user.php | 18 +++++++++++------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index e289e95a1..f17963419 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -240,12 +240,14 @@ public function list_( $_, $assoc_args ) { } } - if ( 'ids' == $formatter->format ) + if ( 'ids' == $formatter->format ) { $query_args['fields'] = 'ids'; - - $query = new WP_Query( $query_args ); - - $formatter->display_items( $query->posts ); + $query = new WP_Query( $query_args ); + echo implode( ' ', $query->posts ); + } else { + $query = new WP_Query( $query_args ); + $formatter->display_items( $query->posts ); + } } /** diff --git a/php/commands/term.php b/php/commands/term.php index 2e5fd3544..43f2e081c 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -53,10 +53,13 @@ public function list_( $args, $assoc_args ) { $assoc_args = array_merge( $defaults, $assoc_args ); $terms = get_terms( $args, $assoc_args ); - if ( 'ids' == $formatter->format ) - $terms = wp_list_pluck( $terms, 'term_id' ); - $formatter->display_items( $terms ); + if ( 'ids' == $formatter->format ) { + $terms = wp_list_pluck( $terms, 'term_id' ); + echo implode( ' ', $terms ); + } else { + $formatter->display_items( $terms ); + } } /** diff --git a/php/commands/user.php b/php/commands/user.php index 1767f80ed..41dab92ce 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -62,16 +62,20 @@ public function list_( $args, $assoc_args ) { $users = get_users( $assoc_args ); - $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { - if ( !is_object( $user ) ) - return $user; + if ( 'ids' == $formatter->format ) { + echo implode( ' ', $users ); + } else { + $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { + if ( !is_object( $user ) ) + return $user; - $user->roles = implode( ',', $user->roles ); + $user->roles = implode( ',', $user->roles ); - return $user; - } ); + return $user; + } ); - $formatter->display_items( $it ); + $formatter->display_items( $it ); + } } /** From a6539d7db710a47df7a9a7be1ebb953c34c1b4e4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 7 Mar 2014 21:12:33 +0000 Subject: [PATCH 2771/5359] test that failure is due to expected error --- features/user.feature | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/features/user.feature b/features/user.feature index 18cf6d950..038d18465 100644 --- a/features/user.feature +++ b/features/user.feature @@ -107,13 +107,22 @@ Feature: Manage WordPress users """ When I try `wp user add-role 1 edit` - Then STDERR should not be empty + Then STDERR should contain: + """ + Role doesn't exist + """ When I try `wp user set-role 1 edit` - Then STDERR should not be empty + Then STDERR should contain: + """ + Role doesn't exist + """ When I try `wp user remove-role 1 edit` - Then STDERR should not be empty + Then STDERR should contain: + """ + Role doesn't exist + """ When I run `wp user set-role 1 author` Then STDOUT should not be empty From 6b6a300561ed35b6ad74315ba24d02e4591b5ef9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Mar 2014 17:12:14 +0000 Subject: [PATCH 2772/5359] throw error when wp-config.php looks invalid --- php/WP_CLI/Runner.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 57ac14284..bec000fb7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -262,15 +262,23 @@ public function get_wp_config_code() { $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); + $found_wp_settings = false; + $lines_to_run = array(); foreach ( $wp_config_code as $line ) { - if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) + if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) { + $found_wp_settings = true; continue; + } $lines_to_run[] = $line; } + if ( !$found_wp_settings ) { + WP_CLI::error( 'Strange wp-config.php file: wp-settings.php is not loaded directly.' ); + } + $source = implode( "\n", $lines_to_run ); $source = Utils\replace_path_consts( $source, $wp_config_path ); return preg_replace( '|^\s*\<\?php\s*|', '', $source ); From 4d379cbbeeb08780364a77cc3ca9ba74ebdbc485 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 9 Mar 2014 20:00:56 +0000 Subject: [PATCH 2773/5359] show full command name in usage output; fixes #1016 --- php/WP_CLI/Dispatcher/CompositeCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 2edb23687..6f7778969 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -78,8 +78,10 @@ function show_usage() { \WP_CLI::line( $subcommand->get_usage( $prefix ) ); } + $cmd_name = implode( ' ', array_slice( get_path( $this ), 1 ) ); + \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $this->name <command>' for more information on a specific command." ); + \WP_CLI::line( "See 'wp help $cmd_name <command>' for more information on a specific command." ); } function invoke( $args, $assoc_args, $extra_args ) { From b878b484cc35dca90af96e71c927b8988dc1e5dc Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Mon, 10 Mar 2014 17:32:19 -0700 Subject: [PATCH 2774/5359] allow --skip-plugins to be set in wp-cli.yml --- php/config-spec.php | 3 +-- php/utils-wp.php | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index df260551e..e4bfa1f5d 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -30,9 +30,8 @@ 'skip-plugins' => array( 'runtime' => '[=<plugin>]', - 'file' => false, + 'file' => '<list>', 'desc' => 'Skip loading all or some plugins', - 'multiple' => false, 'default' => '', ), diff --git a/php/utils-wp.php b/php/utils-wp.php index a8a64fbfd..4048a8d06 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -88,6 +88,10 @@ function is_plugin_skipped( $file ) { if ( true === $skipped_plugins ) return true; - return in_array( $name, array_filter( explode( ',', $skipped_plugins ) ) ); + if ( ! is_array( $skipped_plugins ) ) { + $skipped_plugins = explode( ',', $skipped_plugins ); + } + + return in_array( $name, array_filter( $skipped_plugins ) ); } From 07cc5b20c26168c47bff8fa1d48e41ecb29cc384 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Mar 2014 07:03:08 -0700 Subject: [PATCH 2775/5359] Support for network-activating a plugin upon install Usage `wp plugin install user-switching --network` --- features/plugin.feature | 11 +++++++++++ php/WP_CLI/CommandWithUpgrade.php | 4 ++-- php/commands/plugin.php | 3 +++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 4bbd84cde..a933943f0 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -122,6 +122,17 @@ Feature: Manage WordPress plugins Status: Network Active """ + Scenario: Network activate a plugin + Given a WP multisite install + + When I run `wp plugin install user-switching --network` + Then STDOUT should not be empty + + When I run `wp plugin list --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | user-switching | active-network | + Scenario: List plugins Given a WP install diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 485a8a1b2..88debb6e4 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -143,9 +143,9 @@ function install( $args, $assoc_args ) { } } - if ( $result && isset( $assoc_args['activate'] ) ) { + if ( $result && ( isset( $assoc_args['activate'] ) || isset( $assoc_args['network'] ) ) ) { \WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); + $this->activate( array( $slug ), $assoc_args ); } } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 095325c33..0a5a66bbf 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -347,6 +347,9 @@ protected function filter_item_list( $items, $args ) { * * [--activate] * : If set, the plugin will be activated immediately after install. + * + * [--network] + * : If set, the plugin will be network activated immediately after install * * ## EXAMPLES * From 6723e54cb63fcb80a85cd511b9ec22dfa172dd5c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Mar 2014 07:15:14 -0700 Subject: [PATCH 2776/5359] Use the `$current_site` global instead of `wpmu_current_site()`, which is being removed in trunk See http://irclogs.wordpress.org/chanlog.php?channel=wordpress-dev&day=2014-03-04&sort=asc#m803847 --- php/commands/site.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5d5637d27..7aa6ab2ef 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -213,7 +213,7 @@ public function create( $_, $assoc_args ) { WP_CLI::error( 'This is not a multisite install.' ); } - global $wpdb; + global $wpdb, $current_site; $base = $assoc_args['slug']; $title = isset( $assoc_args['title'] ) ? $assoc_args['title'] : ucfirst( $base ); @@ -228,7 +228,7 @@ public function create( $_, $assoc_args ) { } } else { - $network = wpmu_current_site(); + $network = $current_site; } $public = !isset( $assoc_args['private'] ); From 9bdca32dd6babfb71d3af24a78ac70bc828fe9e0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 12 Mar 2014 19:42:56 +0000 Subject: [PATCH 2777/5359] run functional tests against WP 3.9-beta1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 508251d01..9a3e92cbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=latest + - WP_VERSION=3.9-beta1 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: From dd4cf87b5bc1aa857096bcc27a8da0a90b70259a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 13 Mar 2014 11:07:00 -0700 Subject: [PATCH 2778/5359] Change syntax from `--network` to `--activate-network` for clarity --- features/plugin.feature | 2 +- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/commands/plugin.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index a933943f0..dcad44778 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -125,7 +125,7 @@ Feature: Manage WordPress plugins Scenario: Network activate a plugin Given a WP multisite install - When I run `wp plugin install user-switching --network` + When I run `wp plugin install user-switching --activate-network` Then STDOUT should not be empty When I run `wp plugin list --fields=name,status` diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 88debb6e4..79783fa2d 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -143,7 +143,7 @@ function install( $args, $assoc_args ) { } } - if ( $result && ( isset( $assoc_args['activate'] ) || isset( $assoc_args['network'] ) ) ) { + if ( $result && ( isset( $assoc_args['activate'] ) || isset( $assoc_args['activate-network'] ) ) ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ), $assoc_args ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 0a5a66bbf..fbe6d2a56 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -139,7 +139,7 @@ protected function get_all_items() { * : If set, the plugin will be activated for the entire multisite network. */ function activate( $args, $assoc_args = array() ) { - $network_wide = isset( $assoc_args['network'] ); + $network_wide = ( isset( $assoc_args['network'] ) || isset( $assoc_args['activate-network'] ) ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { activate_plugin( $plugin->file, '', $network_wide ); @@ -348,7 +348,7 @@ protected function filter_item_list( $items, $args ) { * [--activate] * : If set, the plugin will be activated immediately after install. * - * [--network] + * [--activate-network] * : If set, the plugin will be network activated immediately after install * * ## EXAMPLES From cc77c9a58435b8848fd9061504b631c05462739b Mon Sep 17 00:00:00 2001 From: Robert Boloc <robertboloc@gmail.com> Date: Thu, 13 Mar 2014 20:33:36 +0100 Subject: [PATCH 2779/5359] added skip-check param for core.config --- php/commands/core.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8e0eee05b..c632c9e2d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -214,6 +214,9 @@ private static function get_initial_locale() { * [--skip-salts] * : If set, keys and salts won't be generated, but should instead be passed via `--extra-php`. * + * [--skip-check] + * : If set, the datbase connection is not checked. + * * ## EXAMPLES * * # Standard wp-config.php file @@ -244,12 +247,14 @@ public function config( $_, $assoc_args ) { WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); // Check DB connection - Utils\run_mysql_command( 'mysql --no-defaults', array( - 'execute' => ';', - 'host' => $assoc_args['dbhost'], - 'user' => $assoc_args['dbuser'], - 'pass' => $assoc_args['dbpass'], - ) ); + if ( !isset( $assoc_args['skip-check'] ) ) { + Utils\run_mysql_command( 'mysql --no-defaults', array( + 'execute' => ';', + 'host' => $assoc_args['dbhost'], + 'user' => $assoc_args['dbuser'], + 'pass' => $assoc_args['dbpass'], + ) ); + } if ( isset( $assoc_args['extra-php'] ) ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); From a8f1056aaafeb11e698c9045109470339350990f Mon Sep 17 00:00:00 2001 From: Robert Boloc <robertboloc@gmail.com> Date: Thu, 13 Mar 2014 20:39:24 +0100 Subject: [PATCH 2780/5359] fixed typo --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index c632c9e2d..f2c9247ba 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -215,7 +215,7 @@ private static function get_initial_locale() { * : If set, keys and salts won't be generated, but should instead be passed via `--extra-php`. * * [--skip-check] - * : If set, the datbase connection is not checked. + * : If set, the database connection is not checked. * * ## EXAMPLES * From d9d43d026215e0e37554062127ddbde284bc4cc4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 13 Mar 2014 12:48:13 -0700 Subject: [PATCH 2781/5359] Fix the semantics of where `activate-network` is handled --- php/WP_CLI/CommandWithUpgrade.php | 8 +++++++- php/commands/plugin.php | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 79783fa2d..0fba0e500 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -143,7 +143,13 @@ function install( $args, $assoc_args ) { } } - if ( $result && ( isset( $assoc_args['activate'] ) || isset( $assoc_args['activate-network'] ) ) ) { + if ( isset( $assoc_args['activate-network'] ) ) { + $assoc_args['activate'] = true; + $assoc_args['network'] = true; + unset( $assoc_args['activate-network'] ); + } + + if ( $result && isset( $assoc_args['activate'] ) ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ), $assoc_args ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index fbe6d2a56..bb4e5eaad 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -139,7 +139,7 @@ protected function get_all_items() { * : If set, the plugin will be activated for the entire multisite network. */ function activate( $args, $assoc_args = array() ) { - $network_wide = ( isset( $assoc_args['network'] ) || isset( $assoc_args['activate-network'] ) ); + $network_wide = isset( $assoc_args['network'] ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { activate_plugin( $plugin->file, '', $network_wide ); From 7f3bc8de0e181e2e29152287c877c24654b320ef Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Mar 2014 20:42:48 +0000 Subject: [PATCH 2782/5359] 'wp plugin activate' doesn't have an --activate flag --- php/WP_CLI/CommandWithUpgrade.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 0fba0e500..79bba9ca4 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -144,7 +144,6 @@ function install( $args, $assoc_args ) { } if ( isset( $assoc_args['activate-network'] ) ) { - $assoc_args['activate'] = true; $assoc_args['network'] = true; unset( $assoc_args['activate-network'] ); } From 92a046ae67f9dc45e50632aa8fd0972718fe486d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Mar 2014 21:25:38 +0000 Subject: [PATCH 2783/5359] avoid reusing $assoc_args when invoking the activate() subcommand --- php/WP_CLI/CommandWithUpgrade.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 79bba9ca4..5aa067c2c 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -143,14 +143,16 @@ function install( $args, $assoc_args ) { } } - if ( isset( $assoc_args['activate-network'] ) ) { - $assoc_args['network'] = true; - unset( $assoc_args['activate-network'] ); - } + if ( $result ) { + if ( isset( $assoc_args['activate-network'] ) ) { + \WP_CLI::log( "Network-activating '$slug'..." ); + $this->activate( array( $slug ), array( 'network' => true ) ); + } - if ( $result && isset( $assoc_args['activate'] ) ) { - \WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ), $assoc_args ); + if ( isset( $assoc_args['activate'] ) ) { + \WP_CLI::log( "Activating '$slug'..." ); + $this->activate( array( $slug ) ); + } } } } From 1d76f83a007774dd39c0fcb4ac5e60b2f26b5d39 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Mar 2014 22:25:26 +0000 Subject: [PATCH 2784/5359] add functional test for 'wp user delete --reassign' --- features/user.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/user.feature b/features/user.feature index 038d18465..5d2170e10 100644 --- a/features/user.feature +++ b/features/user.feature @@ -47,6 +47,27 @@ Feature: Manage WordPress users When I run `wp user delete {USER_ID}` Then STDOUT should not be empty + Scenario: Reassigning user posts + When I run `wp user create bob bob@example.com --role=author --porcelain` + And save STDOUT as {BOB_ID} + + And I run `wp user create sally sally@example.com --role=editor --porcelain` + And save STDOUT as {SALLY_ID} + + When I run `wp post generate --count=3 --post_author=bob` + And I run `wp post list --author={BOB_ID} --format=count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp user delete bob --reassign={SALLY_ID}` + And I run `wp post list --author={SALLY_ID} --format=count` + Then STDOUT should be: + """ + 3 + """ + Scenario: Generating and deleting users When I run `wp user list --role=editor --format=count` Then STDOUT should be: From 30cd4ea914aa03d5b3e2e1dd833df3533d685318 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 13 Mar 2014 22:27:36 +0000 Subject: [PATCH 2785/5359] avoid using wpmu_delete_user(), which doesn't support reassigning posts --- features/user.feature | 17 +++++++++++++---- php/commands/user.php | 8 +------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/features/user.feature b/features/user.feature index 5d2170e10..793c3bf6a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,9 +1,8 @@ Feature: Manage WordPress users - Background: + Scenario: User CRUD operations Given a WP install - Scenario: User CRUD operations When I try `wp user get bogus-user` Then the return code should be 1 And STDOUT should be empty @@ -11,7 +10,8 @@ Feature: Manage WordPress users When I run `wp user create testuser2 testuser2@example.com --role=author --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} - And I run `wp user get {USER_ID}` + + When I run `wp user get {USER_ID}` Then STDOUT should be a table containing rows: | Field | Value | | ID | {USER_ID} | @@ -48,6 +48,8 @@ Feature: Manage WordPress users Then STDOUT should not be empty Scenario: Reassigning user posts + Given a WP multisite install + When I run `wp user create bob bob@example.com --role=author --porcelain` And save STDOUT as {BOB_ID} @@ -69,6 +71,8 @@ Feature: Manage WordPress users """ Scenario: Generating and deleting users + Given a WP install + When I run `wp user list --role=editor --format=count` Then STDOUT should be: """ @@ -90,7 +94,8 @@ Feature: Manage WordPress users """ Scenario: Importing users from a CSV file - Given a users.csv file: + Given a WP install + And a users.csv file: """ user_login,user_email,display_name,role bobjones,bobjones@domain.com,Bob Jones,contributor @@ -119,6 +124,8 @@ Feature: Manage WordPress users """ Scenario: Managing user roles + Given a WP install + When I run `wp user add-role 1 editor` Then STDOUT should not be empty And I run `wp user get 1 --field=roles` @@ -167,6 +174,8 @@ Feature: Manage WordPress users | roles | | Scenario: Managing user capabilities + Given a WP install + When I run `wp user add-cap 1 edit_vip_product` Then STDOUT should be: """ diff --git a/php/commands/user.php b/php/commands/user.php index 49ad2b6c6..cb327b24c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -132,13 +132,7 @@ public function delete( $args, $assoc_args ) { parent::_delete( $users, $assoc_args, function ( $user, $assoc_args ) { $user_id = $user->ID; - if ( is_multisite() ) { - $r = wpmu_delete_user( $user_id ); - } else { - $r = wp_delete_user( $user_id, $assoc_args['reassign'] ); - } - - if ( $r ) { + if ( wp_delete_user( $user_id, $assoc_args['reassign'] ) ) { return array( 'success', "Deleted user $user_id." ); } else { return array( 'error', "Failed deleting user $user_id." ); From f3018676e3de83cb85383b6e9e194caae2664fad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Mar 2014 15:00:05 +0000 Subject: [PATCH 2786/5359] clarify scope of 'wp user delete'; see #1072 --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index cb327b24c..b3ce47bc3 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -108,7 +108,7 @@ public function get( $args, $assoc_args ) { } /** - * Delete one or more users. + * Delete one or more users from the current site. * * ## OPTIONS * From c5b7d154b6977a771e475616da365c9eaf4c5592 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 14 Mar 2014 14:07:12 -0700 Subject: [PATCH 2787/5359] tests for skip-plugins flag --- features/flags.feature | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index acb13f770..97ddb16b0 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -241,3 +241,89 @@ Feature: Global flags """ <file> """ + + Scenario: Not skipping a plugin + Given a WP install + + When I run `wp plugin activate hello` + And I run `wp eval 'echo hello_dolly();'` + Then STDOUT should contain: + """ + id='dolly' + """ + + Scenario: Skipping a plugin + Given a WP install + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();' --skip-plugins=hello` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping multiple plugins + Given a WP install + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();' --skip-plugins=hello,akismet` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping all plugins + Given a WP install + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();' --skip-plugins` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping a plugin with wp-cli.yml + Given a WP install + And a wp-cli.yml file: + """ + skip-plugins: + - hello + """ + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping multiple plugins with wp-cli.yml + Given a WP install + And a wp-cli.yml file: + """ + skip-plugins: + - hello + - akismet + """ + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping all plugins with wp-cli.yml + Given a WP install + And a wp-cli.yml file: + """ + skip-plugins: true + """ + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + From f3e8883475aab0ceb80b9a962271e929e2f5c13d Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 14 Mar 2014 21:39:25 +0000 Subject: [PATCH 2788/5359] remove duplicate --skip-plugins tests and move to separate file see #1062 --- features/flags.feature | 135 ---------------------------------- features/skip-plugins.feature | 87 ++++++++++++++++++++++ 2 files changed, 87 insertions(+), 135 deletions(-) create mode 100644 features/skip-plugins.feature diff --git a/features/flags.feature b/features/flags.feature index 97ddb16b0..064648099 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -92,55 +92,6 @@ Feature: Global flags log: called 'error' method """ - Scenario: Skipping plugins - Given a WP install - And I run `wp plugin activate hello akismet` - - When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` - Then STDOUT should be: - """ - true - """ - - When I run `wp eval 'var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - true - """ - - # The specified plugin should be skipped - When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` - Then STDOUT should be: - """ - false - """ - - # The specified plugin should still show up as an active plugin - When I run `wp --skip-plugins=akismet plugin status` - Then STDOUT should contain: - """ - akismet - """ - - # The un-specified plugin should continue to be loaded - When I run `wp --skip-plugins=akismet eval 'var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - true - """ - - # No plugins should be loaded when --skip-plugins doesn't have a value - When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );'` - Then STDOUT should be: - """ - false - """ - When I run `wp --skip-plugins eval 'var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - false - """ - Scenario: Using --require Given an empty directory And a custom-cmd.php file: @@ -241,89 +192,3 @@ Feature: Global flags """ <file> """ - - Scenario: Not skipping a plugin - Given a WP install - - When I run `wp plugin activate hello` - And I run `wp eval 'echo hello_dolly();'` - Then STDOUT should contain: - """ - id='dolly' - """ - - Scenario: Skipping a plugin - Given a WP install - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();' --skip-plugins=hello` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping multiple plugins - Given a WP install - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();' --skip-plugins=hello,akismet` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping all plugins - Given a WP install - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();' --skip-plugins` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping a plugin with wp-cli.yml - Given a WP install - And a wp-cli.yml file: - """ - skip-plugins: - - hello - """ - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping multiple plugins with wp-cli.yml - Given a WP install - And a wp-cli.yml file: - """ - skip-plugins: - - hello - - akismet - """ - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping all plugins with wp-cli.yml - Given a WP install - And a wp-cli.yml file: - """ - skip-plugins: true - """ - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - diff --git a/features/skip-plugins.feature b/features/skip-plugins.feature new file mode 100644 index 000000000..2dc828d8c --- /dev/null +++ b/features/skip-plugins.feature @@ -0,0 +1,87 @@ +Feature: Skipping plugins + + Scenario: Skipping plugins via global flag + Given a WP install + And I run `wp plugin activate hello akismet` + + When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified plugin should be skipped + When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + false + """ + + # The specified plugin should still show up as an active plugin + When I run `wp --skip-plugins=akismet plugin status` + Then STDOUT should contain: + """ + akismet + """ + + # The un-specified plugin should continue to be loaded + When I run `wp --skip-plugins=akismet eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + true + """ + + # Can specify multiple plugins to skip + When I try `wp eval --skip-plugins=hello,akismet 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + # No plugins should be loaded when --skip-plugins doesn't have a value + When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + false + """ + When I run `wp --skip-plugins eval 'var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + false + """ + + Scenario: Skipping multiple plugins via config file + Given a WP install + And a wp-cli.yml file: + """ + skip-plugins: + - hello + - akismet + """ + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ + + Scenario: Skipping all plugins via config file + Given a WP install + And a wp-cli.yml file: + """ + skip-plugins: true + """ + + When I run `wp plugin activate hello` + And I try `wp eval 'echo hello_dolly();'` + Then STDERR should contain: + """ + Call to undefined function hello_dolly() + """ From f6fae0eb17807df135d42ba58e5ab5ba5e2b4701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Mon, 17 Mar 2014 16:15:17 +0100 Subject: [PATCH 2789/5359] removing block comments --- templates/wp-config.mustache | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index e708cc189..6951c9bb0 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -1,15 +1,7 @@ <?php -/** - * The base configurations of the WordPress. - * - * This file has the following configurations: MySQL settings, Table Prefix, - * Secret Keys, WordPress Language, and ABSPATH. You can find more information - * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing - * wp-config.php} Codex page. You can get the MySQL settings from your web host. - * @package WordPress - */ -// ** MySQL settings - You can get this info from your web host ** // + +// ** MySQL settings ** // /** The name of the database for WordPress */ define('DB_NAME', '{{dbname}}'); @@ -29,37 +21,16 @@ define('DB_CHARSET', '{{dbcharset}}'); define('DB_COLLATE', '{{dbcollate}}'); {{#keys-and-salts}} -/**#@+ - * Authentication Unique Keys and Salts. - * - * Change these to different unique phrases! - * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} - * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. - */ {{keys-and-salts}} -/**#@-*/ {{/keys-and-salts}} -/** - * WordPress Database Table prefix. - * - * You can have multiple installations in one database if you give each a unique - * prefix. Only numbers, letters, and underscores please! - */ $table_prefix = '{{dbprefix}}'; -/** - * WordPress Localized Language, defaults to English. - * - * Change this to localize WordPress. A corresponding MO file for the chosen - * language must be installed to wp-content/languages. For example, install - * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German - * language support. - */ define('WPLANG', '{{locale}}'); {{extra-php}} + /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ From 6f8bbe2771e8246adaf59b9473b76215375966dc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Mar 2014 17:56:25 +0200 Subject: [PATCH 2790/5359] add missing OPTIONS header to 'wp db import' docs --- php/commands/db.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/db.php b/php/commands/db.php index 2230470de..15e1b1e63 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -162,6 +162,8 @@ function export( $args, $assoc_args ) { /** * Import database from a file or from STDIN. * + * ## OPTIONS + * * [<file>] * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. */ From bbc6e08065f19119638c064dce0a37c7ea37e933 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Mon, 24 Mar 2014 17:56:54 +0200 Subject: [PATCH 2791/5359] first pass at 'wp db tables' command --- php/WP_CLI/Runner.php | 2 +- php/commands/db.php | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index bec000fb7..7a4cf0163 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -526,7 +526,7 @@ public function before_wp_load() { "Either create one manually or use `wp core config`." ); } - if ( $this->cmd_starts_with( array( 'db' ) ) ) { + if ( $this->cmd_starts_with( array( 'db' ) ) && !$this->cmd_starts_with( array( 'db', 'tables' ) ) ) { eval( $this->get_wp_config_code() ); $this->_run_command(); exit; diff --git a/php/commands/db.php b/php/commands/db.php index 15e1b1e63..72ccd7526 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -195,6 +195,31 @@ function import( $args, $assoc_args ) { WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); } + /** + * List the database tables. + * + * ## OPTIONS + * + * [--scope=<scope>] + * : Can be all, global, ms_global, blog, or old tables. Defaults to all. + * + * ## EXAMPLES + * + * # Export only tables for a single site + * wp db export --tables=$(wp db tables --url=sub.example.com | tr '\n' ',') + */ + function tables( $args, $assoc_args ) { + global $wpdb; + + $scope = isset( $assoc_args['scope'] ) ? $assoc_args['scope'] : 'all'; + + $tables = $wpdb->tables( $scope ); + + foreach ( $tables as $table ) { + WP_CLI::line( $table ); + } + } + private function get_file_name( $args ) { if ( empty( $args ) ) return sprintf( '%s.sql', DB_NAME ); From 65cf004239eb29b4003f0b854a31af677b5d12a0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 25 Mar 2014 09:55:14 +0200 Subject: [PATCH 2792/5359] fix handling of --post_category parameter; closes #986 --- php/commands/post.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index f17963419..05a2184df 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -48,7 +48,7 @@ public function __construct() { * * wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' * - * wp post create page.txt --post_type=page --post_title='Page from file' + * wp post create ./post-content.txt --post_category=201,345 --post_title='Post from file' */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { @@ -74,6 +74,10 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = $input; } + if ( isset( $assoc_args['post_category'] ) ) { + $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); + } + parent::_create( $args, $assoc_args, function ( $params ) { return wp_insert_post( $params, true ); } ); From 0f97042c634dd6f115d9d9c67700294890996736 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 27 Mar 2014 07:49:55 +0200 Subject: [PATCH 2793/5359] use putenv() instead of relying on Bash inline variables fixes #1086 --- php/utils.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index a46e45f65..b918d1824 100644 --- a/php/utils.php +++ b/php/utils.php @@ -323,10 +323,11 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); } - if ( isset( $assoc_args['pass'] ) ) { - $cmd = esc_cmd( 'MYSQL_PWD=%s ', $assoc_args['pass'] ) . $cmd; - unset( $assoc_args['pass'] ); - } + $pass = $assoc_args['pass']; + unset( $assoc_args['pass'] ); + + $old_pass = getenv( 'MYSQL_PWD' ); + putenv( 'MYSQL_PWD=' . $pass ); $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); @@ -336,6 +337,8 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { $r = proc_close( $proc ); + putenv( 'MYSQL_PWD=' . $old_pass ); + if ( $r ) exit( $r ); } From fb4942f6bbbece59344f29c6c20e318272ed7c7f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 27 Mar 2014 08:22:52 +0200 Subject: [PATCH 2794/5359] wp cache: remove redundant exit calls and use WP_CLI::line() --- php/commands/cache.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index ad0a8eafe..0c9274811 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -25,7 +25,6 @@ public function add( $args, $assoc_args ) { if ( ! wp_cache_add( $key, $value, $group, $expiration ) ) { WP_CLI::error( "Could not add object '$key' in group '$group'. Does it already exist?" ); - exit; } WP_CLI::success( "Added object '$key' in group '$group'." ); @@ -66,7 +65,6 @@ public function delete( $args, $assoc_args ) { if ( false === $result ) { WP_CLI::error( 'The object was not deleted.' ); - exit; } WP_CLI::success( 'Object deleted.' ); @@ -80,7 +78,6 @@ public function flush( $args, $assoc_args ) { if ( false === $value ) { WP_CLI::error( 'The object cache could not be flushed.' ); - exit; } WP_CLI::success( 'The cache was flushed.' ); @@ -100,7 +97,6 @@ public function get( $args, $assoc_args ) { if ( false === $value ) { WP_CLI::error( "Object with key '$key' and group '$group' not found." ); - exit; } WP_CLI::print_value( $value, $assoc_args ); @@ -122,7 +118,6 @@ public function incr( $args, $assoc_args ) { if ( false === $value ) { WP_CLI::error( 'The value was not incremented.' ); - exit; } WP_CLI::print_value( $value, $assoc_args ); @@ -144,7 +139,6 @@ public function replace( $args, $assoc_args ) { if ( false === $result ) { WP_CLI::error( "Could not replace object '$key' in group '$group'. Does it already exist?" ); - exit; } WP_CLI::success( "Replaced object '$key' in group '$group'." ); @@ -166,7 +160,6 @@ public function set( $args, $assoc_args ) { if ( false === $result ) { WP_CLI::error( "Could not add object '$key' in group '$group'." ); - exit; } WP_CLI::success( "Set object '$key' in group '$group'." ); @@ -221,7 +214,7 @@ public function type( $args, $assoc_args ) { $message = 'Default'; } - WP_CLI::print_value( $message ); + WP_CLI::line( $message ); } } From 08121cb4df0a305eae1fccd3875c80994c2ed626 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 27 Mar 2014 08:38:53 +0200 Subject: [PATCH 2795/5359] abort loading if APC object cache is detected see #283 --- php/wp-settings-cli.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index d566ec1d2..3d3d2ba17 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -93,6 +93,11 @@ // Start the WordPress object cache, or an external object cache if the drop-in is present. wp_start_object_cache(); +// WP-CLI: the APC cache is not available on the command-line, so bail, to prevent cache poisoning +if ( wp_using_ext_object_cache() && class_exists( 'APC_Object_Cache' ) ) { + WP_CLI::error( 'WP-CLI is not compatible with the APC object cache.' ); +} + // Attach the default filters. require( ABSPATH . WPINC . '/default-filters.php' ); From b24ddf1b0423542db6db3520bd04774b41e7f3fc Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 27 Mar 2014 08:49:54 +0200 Subject: [PATCH 2796/5359] avoid using wp_using_ext_object_cache() function, which was only introduced in WP 3.7 --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 3d3d2ba17..401495881 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -94,7 +94,7 @@ wp_start_object_cache(); // WP-CLI: the APC cache is not available on the command-line, so bail, to prevent cache poisoning -if ( wp_using_ext_object_cache() && class_exists( 'APC_Object_Cache' ) ) { +if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { WP_CLI::error( 'WP-CLI is not compatible with the APC object cache.' ); } From 98e7f61fd2569f9ded5625efc2a1eb2dc13aa101 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 27 Mar 2014 09:03:24 +0200 Subject: [PATCH 2797/5359] make search-replace work with tables that have a composite primary key --- php/commands/search-replace.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d24d6ce9a..e6a8739df 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -65,11 +65,11 @@ public function __invoke( $args, $assoc_args ) { $tables = self::get_table_list( $args, isset( $assoc_args['network'] ) ); foreach ( $tables as $table ) { - list( $primary_key, $columns ) = self::get_columns( $table ); + list( $primary_keys, $columns ) = self::get_columns( $table ); // since we'll be updating one row at a time, // we need a primary key to identify the row - if ( null === $primary_key ) { + if ( empty( $primary_keys ) ) { $report[] = array( $table, '', 'skipped' ); continue; } @@ -78,7 +78,7 @@ public function __invoke( $args, $assoc_args ) { if ( in_array( $col, $skip_columns ) ) continue; - $count = self::handle_col( $col, $primary_key, $table, $old, $new, $dry_run, $recurse_objects ); + $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); $report[] = array( $table, $col, $count ); @@ -106,13 +106,15 @@ private static function get_table_list( $args, $network ) { return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } - private static function handle_col( $col, $primary_key, $table, $old, $new, $dry_run, $recurse_objects ) { + private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; - $fields = array( $primary_key, $col ); + $fields = $primary_keys; + $fields[] = $col; + $args = array( 'table' => $table, 'fields' => $fields, @@ -136,10 +138,12 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry if ( $value != $row->$col ) $count++; } else { - $count += $wpdb->update( $table, - array( $col => $value ), - array( $primary_key => $row->$primary_key ) - ); + $where = array(); + foreach ( $primary_keys as $primary_key ) { + $where[ $primary_key ] = $row->$primary_key; + } + + $count += $wpdb->update( $table, array( $col => $value ), $where ); } } @@ -149,13 +153,13 @@ private static function handle_col( $col, $primary_key, $table, $old, $new, $dry private static function get_columns( $table ) { global $wpdb; - $primary_key = null; + $primary_keys = array(); $columns = array(); foreach ( $wpdb->get_results( "DESCRIBE $table" ) as $col ) { if ( 'PRI' === $col->Key ) { - $primary_key = $col->Field; + $primary_keys[] = $col->Field; continue; } @@ -165,7 +169,7 @@ private static function get_columns( $table ) { $columns[] = $col->Field; } - return array( $primary_key, $columns ); + return array( $primary_keys, $columns ); } private static function is_text_col( $type ) { From 2c83d8a408dcd3af1d6bc0698268802c854d0d0f Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 12:34:40 +0000 Subject: [PATCH 2798/5359] delete all and expired transient commands --- php/commands/transient.php | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index 11fc6c09d..d21260772 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -74,6 +74,54 @@ public function type() { WP_CLI::line( $message ); } + + /** + * Delete all expired transients. + * + * @subcommand delete-expired + */ + public function delete_expired() { + global $wpdb; + + // Always delete all transients from DB too. + $time = time(); + $wpdb->query( + "DELETE a, b FROM $wpdb->options a, $wpdb->options b WHERE + a.option_name LIKE '\_transient\_%' AND + a.option_name NOT LIKE '\_transient\_timeout\_%' AND + b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) ) + AND b.option_value < $time" + ); + + WP_CLI::success( 'Expired transients deleted from the database.' ); + + if ( wp_using_ext_object_cache() ) { + WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); + } + } + + /** + * Delete all transients. + * + * @subcommand delete-all + */ + public function delete_all() { + global $wpdb; + + // Always delete all transients from DB too. + $wpdb->query( + "DELETE FROM $wpdb->options + WHERE option_name LIKE '\_transient\_%' + OR option_name LIKE '\_site\_transient\_%'" + ); + + WP_CLI::success( 'All transients deleted from the database.' ); + + if ( wp_using_ext_object_cache() ) { + WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); + } + } + } WP_CLI::add_command( 'transient', 'Transient_Command' ); From b36d7240963459ac0d018b409a0cac8cc50324b3 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:09:27 +0000 Subject: [PATCH 2799/5359] Use global _wp_using_ext_object_cache directly for backwards compatibility --- php/commands/transient.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index d21260772..6bdfc3a20 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -81,7 +81,7 @@ public function type() { * @subcommand delete-expired */ public function delete_expired() { - global $wpdb; + global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. $time = time(); @@ -95,7 +95,7 @@ public function delete_expired() { WP_CLI::success( 'Expired transients deleted from the database.' ); - if ( wp_using_ext_object_cache() ) { + if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); } } @@ -106,7 +106,7 @@ public function delete_expired() { * @subcommand delete-all */ public function delete_all() { - global $wpdb; + global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. $wpdb->query( @@ -117,7 +117,7 @@ public function delete_all() { WP_CLI::success( 'All transients deleted from the database.' ); - if ( wp_using_ext_object_cache() ) { + if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); } } From 50350a8892c22a2bdb456af84e94d00c9d6fca92 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:09:51 +0000 Subject: [PATCH 2800/5359] Use WordPress current_time instead of PHP time --- php/commands/transient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 6bdfc3a20..4c4b09404 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -84,8 +84,8 @@ public function delete_expired() { global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. - $time = time(); - $wpdb->query( + $time = current_time(); + $count = $wpdb->query( "DELETE a, b FROM $wpdb->options a, $wpdb->options b WHERE a.option_name LIKE '\_transient\_%' AND a.option_name NOT LIKE '\_transient\_timeout\_%' AND From 56b9b696bd4d8774c74acc610063a7961c30e380 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:10:17 +0000 Subject: [PATCH 2801/5359] Pass count rows affected to success message --- php/commands/transient.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 4c4b09404..fa275dff3 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -93,7 +93,7 @@ public function delete_expired() { AND b.option_value < $time" ); - WP_CLI::success( 'Expired transients deleted from the database.' ); + WP_CLI::success( "$count expired transients deleted from the database." ); if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); @@ -109,13 +109,13 @@ public function delete_all() { global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. - $wpdb->query( - "DELETE FROM $wpdb->options - WHERE option_name LIKE '\_transient\_%' + $count = $wpdb->query( + "DELETE FROM $wpdb->options + WHERE option_name LIKE '\_transient\_%' OR option_name LIKE '\_site\_transient\_%'" ); - WP_CLI::success( 'All transients deleted from the database.' ); + WP_CLI::success( "$count expired transients deleted from the database." ); if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); From 91bb83cf4d9ad4a8254a80d66ff4b7cb405c31b7 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:39:16 +0000 Subject: [PATCH 2802/5359] display different notice if no transients found --- php/commands/transient.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index fa275dff3..8caec0c3b 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -93,7 +93,11 @@ public function delete_expired() { AND b.option_value < $time" ); - WP_CLI::success( "$count expired transients deleted from the database." ); + if ( $count > 0 ) { + WP_CLI::success( "$count expired transients deleted from the database." ); + } else { + WP_CLI::success( "No transients found" ); + } if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); @@ -115,7 +119,11 @@ public function delete_all() { OR option_name LIKE '\_site\_transient\_%'" ); - WP_CLI::success( "$count expired transients deleted from the database." ); + if ( $count > 0 ) { + WP_CLI::success( "$count transients deleted from the database." ); + } else { + WP_CLI::success( "No transients found" ); + } if ( $_wp_using_ext_object_cache ) { WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); From b9f540c786517c2b2fdce7d18eec3681ece2c255 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:40:54 +0000 Subject: [PATCH 2803/5359] oops... pass timestamp to current_time --- php/commands/transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 8caec0c3b..f76461e94 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -84,7 +84,7 @@ public function delete_expired() { global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. - $time = current_time(); + $time = current_time('timestamp'); $count = $wpdb->query( "DELETE a, b FROM $wpdb->options a, $wpdb->options b WHERE a.option_name LIKE '\_transient\_%' AND From 5862de31ba694dd8bc147da9d06e1f6515497f88 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 28 Mar 2014 13:42:23 +0000 Subject: [PATCH 2804/5359] better message text --- php/commands/transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index f76461e94..16248d454 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -96,7 +96,7 @@ public function delete_expired() { if ( $count > 0 ) { WP_CLI::success( "$count expired transients deleted from the database." ); } else { - WP_CLI::success( "No transients found" ); + WP_CLI::success( "No expired transients found" ); } if ( $_wp_using_ext_object_cache ) { From 68b46b747ca3404391cd5c2f9bd53b36c4e6ff92 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 28 Mar 2014 20:55:24 -0700 Subject: [PATCH 2805/5359] Make post id optional in wp comment count --- php/commands/comment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 285059757..8c19ed0a7 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -307,7 +307,7 @@ public function unapprove( $args, $assoc_args ) { * * ## OPTIONS * - * <post-id> + * [<post-id>] * : The ID of the post to count comments in. * * ## EXAMPLES From f47e6b9523e4d546ee66907e8d12a0b8fdc3d04a Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Fri, 28 Mar 2014 22:07:00 -0700 Subject: [PATCH 2806/5359] behat tests for 'wp comment count' --- features/comment.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 269ae1015..1451e7906 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -60,3 +60,26 @@ Feature: Manage WordPress comments """ http://example.com/?p=1#comment-1 """ + + Scenario: Count comments + When I run `wp comment count 1` + Then STDOUT should be: + """ + approved: 1 + moderated: 0 + spam: 0 + trash: 0 + post-trashed: 0 + total_comments: 1 + """ + + When I run `wp comment count` + Then STDOUT should be: + """ + approved: 1 + moderated: 0 + spam: 0 + trash: 0 + post-trashed: 0 + total_comments: 1 + """ From 56953f76600b011cade9d54ecd1d382e881ec34f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 31 Mar 2014 08:25:39 -0700 Subject: [PATCH 2807/5359] Few PHP docs for the `Subcommand` class --- php/WP_CLI/Dispatcher/Subcommand.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 860b3c366..c3e0d3bad 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -37,14 +37,32 @@ function get_synopsis() { return $this->synopsis; } + /** + * If an alias is set, grant access to it + * Aliases permit subcommands to be instantiated + * with a secondary identity + * + * @return string + */ function get_alias() { return $this->alias; } + /** + * Print the usage details to the end user + * + * @param string $prefix + */ function show_usage( $prefix = 'usage: ' ) { \WP_CLI::line( $this->get_usage( $prefix ) ); } + /** + * Get the usage of the subcommand as a formatted string + * + * @param string $prefix + * @return string + */ function get_usage( $prefix ) { return sprintf( "%s%s %s", $prefix, From c9963f39b5eecdf6a77fa22145ab8e3ac8450198 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 31 Mar 2014 08:28:39 -0700 Subject: [PATCH 2808/5359] Docs for the User fetcher --- php/WP_CLI/Fetchers/User.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/WP_CLI/Fetchers/User.php b/php/WP_CLI/Fetchers/User.php index 65e2f9c0f..5b8e0a63a 100644 --- a/php/WP_CLI/Fetchers/User.php +++ b/php/WP_CLI/Fetchers/User.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress user based on one of its attributes. + */ class User extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "Invalid user ID, email or login: '%s'"; + /** + * Get a user object by one of its identifying attributes + * + * @param mixed $id_email_or_login + * @return WP_User|false + */ public function get( $id_email_or_login ) { if ( is_numeric( $id_email_or_login ) ) From d0ff55cd2fa658cf52f44337c6ce7b1fe5038344 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 31 Mar 2014 08:29:48 -0700 Subject: [PATCH 2809/5359] PHPdoc for Fetcher base command --- php/WP_CLI/Fetchers/Base.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/Fetchers/Base.php b/php/WP_CLI/Fetchers/Base.php index 9e4ebc310..262e1bfab 100644 --- a/php/WP_CLI/Fetchers/Base.php +++ b/php/WP_CLI/Fetchers/Base.php @@ -2,6 +2,9 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress entity for use in a subcommand. + */ abstract class Base { /** From ed47187207ee98eb8cc91e8cc31d2215c551849f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 31 Mar 2014 08:35:14 -0700 Subject: [PATCH 2810/5359] Copy pasta documentation for the rest of the fetcher classes --- php/WP_CLI/Fetchers/Comment.php | 12 ++++++++++++ php/WP_CLI/Fetchers/Plugin.php | 12 ++++++++++++ php/WP_CLI/Fetchers/Post.php | 12 ++++++++++++ php/WP_CLI/Fetchers/Site.php | 12 ++++++++++++ php/WP_CLI/Fetchers/Theme.php | 12 ++++++++++++ 5 files changed, 60 insertions(+) diff --git a/php/WP_CLI/Fetchers/Comment.php b/php/WP_CLI/Fetchers/Comment.php index 296b2533b..027030452 100644 --- a/php/WP_CLI/Fetchers/Comment.php +++ b/php/WP_CLI/Fetchers/Comment.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress comment based on one of its attributes. + */ class Comment extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "Could not find the comment with ID %d."; + /** + * Get a comment object by ID + * + * @param int $arg + * @return object|false + */ public function get( $arg ) { $comment_id = (int) $arg; $comment = get_comment( $comment_id ); diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php index 37f3e10a0..36235a85a 100644 --- a/php/WP_CLI/Fetchers/Plugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress plugin based on one of its attributes. + */ class Plugin extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "The '%s' plugin could not be found."; + /** + * Get a plugin object by name + * + * @param string $name + * @return object|false + */ public function get( $name ) { foreach ( get_plugins() as $file => $_ ) { if ( $file === "$name.php" || diff --git a/php/WP_CLI/Fetchers/Post.php b/php/WP_CLI/Fetchers/Post.php index 4944561e3..402a6f1f1 100644 --- a/php/WP_CLI/Fetchers/Post.php +++ b/php/WP_CLI/Fetchers/Post.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress post based on one of its attributes. + */ class Post extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "Could not find the post with ID %d."; + /** + * Get a post object by ID + * + * @param int $arg + * @return WP_Post|false + */ public function get( $arg ) { return get_post( $arg ); } diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php index 1eaca959e..b3de87360 100644 --- a/php/WP_CLI/Fetchers/Site.php +++ b/php/WP_CLI/Fetchers/Site.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress site based on one of its attributes. + */ class Site extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "Could not find the site with ID %d."; + /** + * Get a site object by ID + * + * @param int $site_id + * @return object|false + */ public function get( $site_id ) { return $this->_get_site( $site_id ); } diff --git a/php/WP_CLI/Fetchers/Theme.php b/php/WP_CLI/Fetchers/Theme.php index 1c3380502..c3e3357e4 100644 --- a/php/WP_CLI/Fetchers/Theme.php +++ b/php/WP_CLI/Fetchers/Theme.php @@ -2,10 +2,22 @@ namespace WP_CLI\Fetchers; +/** + * Fetch a WordPress theme based on one of its attributes. + */ class Theme extends Base { + /** + * @param string $msg Error message to use when invalid data is provided + */ protected $msg = "The '%s' theme could not be found."; + /** + * Get a theme object by name + * + * @param string $name + * @return object|false + */ public function get( $name ) { $theme = wp_get_theme( $name ); From 5476ebf556fe74b8972ffd68bee5d3d2c12605fa Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Sat, 5 Apr 2014 20:49:02 +0100 Subject: [PATCH 2811/5359] fix wp-cli/wp-cli#1036 --- php/commands/media.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 254942f4f..f6e0261a2 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -236,7 +236,8 @@ private function remove_old_images( $att_id ) { if ( $intermediate_path == $original_path ) continue; - unlink( $intermediate_path ); + if ( file_exists( $intermediate_path ) ) + unlink( $intermediate_path ); } } } From 20099c177db002643cc2e9a924dc7183aa2c0d5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 12:56:29 -0700 Subject: [PATCH 2812/5359] Command to list registered sidebars --- features/sidebar.feature | 12 +++++++++++ php/commands/sidebar.php | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 features/sidebar.feature create mode 100644 php/commands/sidebar.php diff --git a/features/sidebar.feature b/features/sidebar.feature new file mode 100644 index 000000000..1126cfa98 --- /dev/null +++ b/features/sidebar.feature @@ -0,0 +1,12 @@ +Feature: Manage WordPress sidebars + + Scenario: List available sidebars + Given a WP install + + When I run `wp theme install p2 --activate` + Then STDOUT should not be empty + + When I run `wp sidebar list --fields=name,id` + Then STDOUT should be a table containing rows: + | name | id | + | Sidebar | sidebar-1 | diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php new file mode 100644 index 000000000..9e930f83f --- /dev/null +++ b/php/commands/sidebar.php @@ -0,0 +1,46 @@ +<?php + +/** + * Manage sidebars. + */ +class Sidebar_Command extends WP_CLI_Command { + + private $fields = array( + 'name', + 'id', + 'description' + ); + + /** + * List registered sidebars. + * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to name, id, description + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## EXAMPLES + * + * wp sidebar list --fields=role --format=csv + * + * @subcommand list + */ + public function _list( $args, $assoc_args ) { + global $wp_registered_sidebars; + + $output_sidebars = array(); + foreach( $wp_registered_sidebars as $registered_sidebar ) { + $output_sidebars[] = (object)$registered_sidebar; + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_sidebars ); + + } + +} + +WP_CLI::add_command( 'sidebar', 'Sidebar_Command' ); From dba201d62eadccc3ed3331c73023e0fd30b6f7a6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 13:15:31 -0700 Subject: [PATCH 2813/5359] Fix copy pasta --- php/commands/sidebar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 9e930f83f..afd55d860 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -24,7 +24,7 @@ class Sidebar_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp sidebar list --fields=role --format=csv + * wp sidebar list --fields=name,id --format=csv * * @subcommand list */ From 16892f074fc2d688f267299cdfabd63c68e3bc27 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 15:15:29 -0700 Subject: [PATCH 2814/5359] Update `WP_CLI\Utils\load_command()` to handle commands like `sidebar widget` Previously, `load_command()` only supported commands where the name matched exactly (e.g. `wp post` and `post.php`). The `* meta` commands escaped this by defining their classes within the parent class file. This change means `wp sidebar widget` will resolve to `sidebar-widget.php`, as well as `sidebar.php` --- php/WP_CLI/Runner.php | 2 +- php/utils.php | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7a4cf0163..b685ee337 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -479,7 +479,7 @@ public function before_wp_load() { // Load bundled commands early, so that they're forced to use the same // APIs as non-bundled commands. - Utils\load_command( $this->arguments[0] ); + Utils\load_command( $this->arguments ); if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { diff --git a/php/utils.php b/php/utils.php index b918d1824..c697df928 100644 --- a/php/utils.php +++ b/php/utils.php @@ -41,12 +41,30 @@ function load_file( $path ) { require $path; } +/** + * Load a given internal WP-CLI command + * + * @param mixed + */ function load_command( $name ) { - $path = WP_CLI_ROOT . "/php/commands/$name.php"; - if ( is_readable( $path ) ) { - include_once $path; + if ( is_string( $name ) ) { + $name = array( $name ); } + + do { + + $file_name = implode( '-', $name ); + $path = WP_CLI_ROOT . "/php/commands/{$file_name}.php"; + + if ( is_readable( $path ) ) { + include_once $path; + } + + array_pop( $name ); + + } while( $name ); + } function load_all_commands() { From c7900b78be44d859532f576a82ee3793a662531c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 15:19:34 -0700 Subject: [PATCH 2815/5359] Introduce `wp sidebar widget` with list, update, and remove --- php/commands/sidebar-widget.php | 228 ++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 php/commands/sidebar-widget.php diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php new file mode 100644 index 000000000..99c454daf --- /dev/null +++ b/php/commands/sidebar-widget.php @@ -0,0 +1,228 @@ +<?php + +/** + * Manage sidebar widgets. + */ + +class Widget_Command extends WP_CLI_Command { + + private $fields = array( + 'name', + 'position', + 'options', + ); + + /** + * List widgets associated with a sidebar. + * + * <sidebar-id> + * : ID for the corresponding sidebar. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to name, id, description + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## EXAMPLES + * + * wp sidebar widget list <sidebar> --fields=name --format=csv + * + * @subcommand list + */ + public function _list( $args, $assoc_args ) { + + list( $sidebar_id ) = $args; + + $this->validate_sidebar( $sidebar_id ); + + $output_widgets = $this->get_sidebar_widgets( $sidebar_id ); + + if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv') ) ) { + foreach( $output_widgets as &$output_widget ) { + $output_widget->options = json_encode( $output_widget->options ); + } + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_widgets ); + + } + + /** + * Update a given widget's options. + * + * <sidebar-id> + * : ID for the corresponding sidebar. + * + * <name> + * : Widget name. + * + * <position> + * : Widget's current position within the sidebar. + * + * [--<field>=<value>] + * : Field to update, with its new value + * + * @subcommand update + */ + public function update( $args, $assoc_args ) { + + list( $sidebar_id, $name, $position ) = $args; + $this->validate_sidebar_widget( $sidebar_id, $name, $position ); + + if ( empty( $assoc_args ) ) { + WP_CLI::error( "No options specified to update." ); + } + + $option_key = 'widget_' . $name; + $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); + $widget_options = get_option( $option_key ); + if ( ! isset( $widget_options[ $option_index ] ) ) { + $widget_options[ $option_index ] = $assoc_args; + } else { + $widget_options[ $option_index ] = array_merge( $widget_options[ $option_index ], $assoc_args ); + } + update_option( $option_key, $widget_options ); + + WP_CLI::success( "Widget updated." ); + + } + + /** + * Remove a widget from a sidebar. + * + * <sidebar-id> + * : ID for the corresponding sidebar. + * + * <name> + * : Widget name. + * + * <position> + * : Widget's current position within the sidebar. + * + * @subcommand + */ + public function remove( $args, $assoc_args ) { + + list( $sidebar_id, $name, $position ) = $args; + $this->validate_sidebar_widget( $sidebar_id, $name, $position ); + + // Remove the widget's settings + $option_key = 'widget_' . $name; + $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); + $widget_options = get_option( $option_key ); + unset( $widget_options[ $option_index ] ); + update_option( $option_key, $widget_options ); + + // Remove the widget from the sidebar + $all_widgets = wp_get_sidebars_widgets(); + $position--; + unset( $all_widgets[ $sidebar_id ][ $position ] ); + update_option( 'sidebars_widgets', $all_widgets ); + + // Reset the global just in case + wp_get_sidebars_widgets(); + + WP_CLI::success( "Widget removed from sidebar." ); + } + + /** + * Check whether a sidebar is a valid sidebar + * + * @param string $sidebar_id + */ + private function validate_sidebar( $sidebar_id ) { + global $wp_registered_sidebars; + + if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { + WP_CLI::error( "Invalid sidebar." ); + } + } + + /** + * Check whether the specified widget is on the sidebar + * + * @param string $sidebar_id + * @param string $name + * @param int $position + */ + private function validate_sidebar_widget( $sidebar_id, $name, $position ) { + + $this->validate_sidebar( $sidebar_id ); + + $sidebar_widgets = $this->get_sidebar_widgets( $sidebar_id ); + + $widget_exists = false; + foreach( $sidebar_widgets as $sidebar_widget ) { + + if ( $name == $sidebar_widget->name && $position == $sidebar_widget->position ) { + $widget_exists = true; + break; + } + + } + + if ( false === $widget_exists ) { + WP_CLI::error( "Specified widget isn't present on sidebar." ); + } + + } + + /** + * Get the widgets (and their associated data) for a given sidebar + * + * @param string $sidebar_id + * @return array + */ + private function get_sidebar_widgets( $sidebar_id ) { + + $all_widgets = wp_get_sidebars_widgets(); + + if ( empty( $all_widgets[ $sidebar_id ] ) ) { + return array(); + } + + $prepared_widgets = array(); + foreach( $all_widgets[ $sidebar_id ] as $key => $widget_name ) { + + $prepared_widget = new stdClass; + + $parts = explode( '-', $widget_name ); + $option_index = array_pop( $parts ); + $widget_name = implode( '-', $parts ); + + $prepared_widget->name = $widget_name; + $prepared_widget->position = $key + 1; + $widget_options = get_option( 'widget_' . $widget_name ); + $prepared_widget->options = $widget_options[ $option_index ]; + + $prepared_widgets[] = $prepared_widget; + } + + return $prepared_widgets; + } + + /** + * Get the widget's option index from its location on the sidebar + * + * @param string $sidebar_id + * @param string $name + * @param int $position + * @return int + */ + private function get_widget_option_index( $sidebar_id, $name, $position ) { + + $all_widgets = wp_get_sidebars_widgets(); + $sidebar_widgets = $all_widgets[ $sidebar_id ]; + $position--; + $widget_real_name = $sidebar_widgets[ $position ]; + $parts = explode( '-', $widget_real_name ); + $option_index = array_pop( $parts ); + + return $option_index; + } + +} + +WP_CLI::add_command( 'sidebar widget', 'Widget_Command' ); From c13b56a69b7376b81a00109a55d8afab9b87b9e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 15:49:37 -0700 Subject: [PATCH 2816/5359] Re-index the sidebar's list of widgets after a widget is removed --- php/commands/sidebar-widget.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 99c454daf..79f673581 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -119,6 +119,7 @@ public function remove( $args, $assoc_args ) { $all_widgets = wp_get_sidebars_widgets(); $position--; unset( $all_widgets[ $sidebar_id ][ $position ] ); + $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); update_option( 'sidebars_widgets', $all_widgets ); // Reset the global just in case From d5c55c363f2b5c860acadddccbad87d7c44de6c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 16:06:47 -0700 Subject: [PATCH 2817/5359] Move widgets between positions on a sidebar --- php/commands/sidebar-widget.php | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 79f673581..6858d08bc 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -89,6 +89,51 @@ public function update( $args, $assoc_args ) { } + /** + * Move a widget from one position on a sidebar to another. + * + * <sidebar-id> + * : ID for the corresponding sidebar. + * + * <name> + * : Widget name. + * + * <current-position> + * : Widget's current position within the sidebar. + * + * <new-position> + * : Widget's new position within the sidebar. + * + * @subcommand move + */ + public function move( $args, $assoc_args ) { + + list( $sidebar_id, $name, $current_position, $new_position ) = $args; + $this->validate_sidebar_widget( $sidebar_id, $name, $current_position ); + + if ( $new_position < -1 ) { + $new_position = 1; + } + + // Human-readable positions are different than numerically indexed array + $current_position--; + $new_position--; + + // Reposition and update + $all_widgets = wp_get_sidebars_widgets(); + $sidebar_widgets = $all_widgets[ $sidebar_id ]; + $part = array_splice( $sidebar_widgets, $current_position, 1 ); + array_splice( $sidebar_widgets, $new_position, 0, $part ); + $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); + update_option( 'sidebars_widgets', $all_widgets ); + + // Reset the global just in case + wp_get_sidebars_widgets(); + + WP_CLI::success( "Widget moved." ); + + } + /** * Remove a widget from a sidebar. * From 91cdd40baaccc1d92ec5bbd09322cf0248d19d55 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 16:14:07 -0700 Subject: [PATCH 2818/5359] Basic tests for sidebar widgets --- features/sidebar-widget.feature | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 features/sidebar-widget.feature diff --git a/features/sidebar-widget.feature b/features/sidebar-widget.feature new file mode 100644 index 000000000..17ce7cd1c --- /dev/null +++ b/features/sidebar-widget.feature @@ -0,0 +1,55 @@ +Feature: Manage widgets in WordPress sidebar + + Scenario: Widget CRUD + Given a WP install + + When I run `wp theme install p2 --activate` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position` + Then STDOUT should be a table containing rows: + | name | position | + | search | 1 | + | recent-posts | 2 | + | recent-comments | 3 | + | archives | 4 | + | categories | 5 | + | meta | 6 | + + When I run `wp sidebar widget move sidebar-1 recent-comments 3 2` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position` + Then STDOUT should be a table containing rows: + | name | position | + | search | 1 | + | recent-comments | 2 | + | recent-posts | 3 | + | archives | 4 | + | categories | 5 | + | meta | 6 | + + When I run `wp sidebar widget move sidebar-1 recent-comments 2 5` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position` + Then STDOUT should be a table containing rows: + | name | position | + | search | 1 | + | recent-posts | 2 | + | archives | 3 | + | categories | 4 | + | recent-comments | 5 | + | meta | 6 | + + When I run `wp sidebar widget remove sidebar-1 recent-comments 5` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position` + Then STDOUT should be a table containing rows: + | name | position | + | search | 1 | + | recent-posts | 2 | + | archives | 3 | + | categories | 4 | + | meta | 5 | From df80294d501fc47e45b5c6ec3d256d0859a22510 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 16:21:30 -0700 Subject: [PATCH 2819/5359] Register the "Inactive Widgets" sidebar, because core doesn't normally do this for us --- php/commands/sidebar-widget.php | 2 ++ php/commands/sidebar.php | 23 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 6858d08bc..02c48e2ac 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -181,6 +181,8 @@ public function remove( $args, $assoc_args ) { private function validate_sidebar( $sidebar_id ) { global $wp_registered_sidebars; + Sidebar_Command::register_unused_sidebar(); + if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { WP_CLI::error( "Invalid sidebar." ); } diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index afd55d860..a52cadb47 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -29,7 +29,9 @@ class Sidebar_Command extends WP_CLI_Command { * @subcommand list */ public function _list( $args, $assoc_args ) { - global $wp_registered_sidebars; + global $wp_registered_sidebars; + + self::register_unused_sidebar(); $output_sidebars = array(); foreach( $wp_registered_sidebars as $registered_sidebar ) { @@ -41,6 +43,25 @@ public function _list( $args, $assoc_args ) { } + /** + * Register the sidebar for unused widgets + * Core does this in /wp-admin/widgets.php, which isn't helpful + */ + public static function register_unused_sidebar() { + + register_sidebar(array( + 'name' => __('Inactive Widgets'), + 'id' => 'wp_inactive_widgets', + 'class' => 'inactive-sidebar', + 'description' => __( 'Drag widgets here to remove them from the sidebar but keep their settings.' ), + 'before_widget' => '', + 'after_widget' => '', + 'before_title' => '', + 'after_title' => '', + )); + + } + } WP_CLI::add_command( 'sidebar', 'Sidebar_Command' ); From ee5057af3f4e9c343da413a1cf6eef6c3756b3d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 16:49:10 -0700 Subject: [PATCH 2820/5359] Sanitize a widget's options using its defined callback --- php/commands/sidebar-widget.php | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 02c48e2ac..f3b46f5f2 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -78,11 +78,8 @@ public function update( $args, $assoc_args ) { $option_key = 'widget_' . $name; $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); $widget_options = get_option( $option_key ); - if ( ! isset( $widget_options[ $option_index ] ) ) { - $widget_options[ $option_index ] = $assoc_args; - } else { - $widget_options[ $option_index ] = array_merge( $widget_options[ $option_index ], $assoc_args ); - } + $clean_options = $this->sanitize_widget_options( $name, $assoc_args, $widget_options[ $option_index ] ); + $widget_options[ $option_index ] = array_merge( (array)$widget_options[ $option_index ], $clean_options ); update_option( $option_key, $widget_options ); WP_CLI::success( "Widget updated." ); @@ -271,6 +268,27 @@ private function get_widget_option_index( $sidebar_id, $name, $position ) { return $option_index; } + /** + * Clean up a widget's options based on its update callback + * + * @param string $id_base Name of the widget + * @param mixed $dirty_options + * @param mixed $old_options + * @return mixed + */ + private function sanitize_widget_options( $id_base, $dirty_options, $old_options ) { + global $wp_widget_factory; + + $widget = wp_filter_object_list( $wp_widget_factory->widgets, array( 'id_base' => $id_base ) ); + if ( empty( $widget ) ) { + return array(); + } + + $widget = array_pop( $widget ); + return $widget->update( $dirty_options, $old_options ); + + } + } WP_CLI::add_command( 'sidebar widget', 'Widget_Command' ); From f6f2cc92b1f04f4be2884932e80b88bbfee8777d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 16:54:28 -0700 Subject: [PATCH 2821/5359] Further abstraction that will be useful down the line --- php/commands/sidebar-widget.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index f3b46f5f2..96c0dd05e 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -268,6 +268,23 @@ private function get_widget_option_index( $sidebar_id, $name, $position ) { return $option_index; } + /** + * Get a widget's instantiated object based on its name + * + * @param string $id_base Name of the widget + * @return WP_Widget|false + */ + private function get_widget_obj( $id_base ) { + global $wp_widget_factory; + + $widget = wp_filter_object_list( $wp_widget_factory->widgets, array( 'id_base' => $id_base ) ); + if ( empty( $widget ) ) { + false; + } + + return array_pop( $widget ); + } + /** * Clean up a widget's options based on its update callback * @@ -277,14 +294,12 @@ private function get_widget_option_index( $sidebar_id, $name, $position ) { * @return mixed */ private function sanitize_widget_options( $id_base, $dirty_options, $old_options ) { - global $wp_widget_factory; - $widget = wp_filter_object_list( $wp_widget_factory->widgets, array( 'id_base' => $id_base ) ); + $widget = $this->get_widget_obj( $id_base ); if ( empty( $widget ) ) { return array(); } - $widget = array_pop( $widget ); return $widget->update( $dirty_options, $old_options ); } From 06c3598ba91f560d1afbe72d79555075b15dda9b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 17:29:34 -0700 Subject: [PATCH 2822/5359] Utility functions for getting and updating options associated with a given widget --- php/commands/sidebar-widget.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 96c0dd05e..cb6894e11 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -268,6 +268,26 @@ private function get_widget_option_index( $sidebar_id, $name, $position ) { return $option_index; } + /** + * Get the options for a given widget + * + * @param string $name + * @return array + */ + private function get_widget_options( $name ) { + return get_option( 'widget_' . $name, array() ); + } + + /** + * Update the options for a given widget + * + * @param string $name + * @param mixed + */ + private function update_widget_options( $name, $value ) { + update_option( 'widget_' . $name, $value ); + } + /** * Get a widget's instantiated object based on its name * From 7ce1e184e75157981f8a0532755dab9fd67fb0e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 17:32:27 -0700 Subject: [PATCH 2823/5359] Support for adding a widget to a sidebar --- features/sidebar-widget.feature | 13 +++++++ php/commands/sidebar-widget.php | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/features/sidebar-widget.feature b/features/sidebar-widget.feature index 17ce7cd1c..ae68e0e37 100644 --- a/features/sidebar-widget.feature +++ b/features/sidebar-widget.feature @@ -53,3 +53,16 @@ Feature: Manage widgets in WordPress sidebar | archives | 3 | | categories | 4 | | meta | 5 | + + When I run `wp sidebar widget add sidebar-1 calendar 2 --title="Calendar"` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position` + Then STDOUT should be a table containing rows: + | name | position | + | search | 1 | + | calendar | 2 | + | recent-posts | 3 | + | archives | 4 | + | categories | 5 | + | meta | 6 | diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index cb6894e11..fe88141c3 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -49,6 +49,68 @@ public function _list( $args, $assoc_args ) { } + /** + * Add a widget to a sidebar. + * + * <sidebar-id> + * : ID for the corresponding sidebar. + * + * <name> + * : Widget name. + * + * [<position>] + * : Widget's current position within the sidebar. Defaults to last + * + * [--<field>=<value>] + * : Widget option to add, with its new value + * + * @subcommand add + */ + public function add( $args, $assoc_args ) { + + list( $sidebar_id, $name ) = $args; + if ( isset( $args[2] ) ) { + $position = (int) $args[2]; + } else { + $position = false; + } + $this->validate_sidebar( $sidebar_id ); + + if ( false == ( $widget = $this->get_widget_obj( $name ) ) ) { + WP_CLI::error( "Invalid widget type." ); + } + + /** + * Adding a widget is as easy as: + * 1. Creating a new widget option + * 2. Adding the widget to the sidebar + * 3. Positioning appropriately + */ + $widget_options = $option_keys = $this->get_widget_options( $name ); + unset( $option_keys['_multiwidget'] ); + $option_keys = array_keys( $option_keys ); + $last_key = array_pop( $option_keys ); + $option_index = $last_key + 1; + $widget_options[ $option_index ] = $this->sanitize_widget_options( $name, $assoc_args, array() ); + $this->update_widget_options( $name, $widget_options ); + + $all_widgets = wp_get_sidebars_widgets(); + $sidebar_widgets = $all_widgets[ $sidebar_id ]; + $sidebar_widgets[] = $name . '-' . $option_index; + + $current_position = count( $sidebar_widgets ) - 1; + if ( $position ) { + $new_position = $position - 1; + $part = array_splice( $sidebar_widgets, $current_position, 1 ); + array_splice( $sidebar_widgets, $new_position, 0, $part ); + $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); + } + update_option( 'sidebars_widgets', $all_widgets ); + + WP_CLI::success( "Added widget." ); + + } + /** * Update a given widget's options. * From db8b4f290e7344b070a9f24832fafe9e12cf23e3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 17:51:19 -0700 Subject: [PATCH 2824/5359] Refactor to use new sidebar widget getter Core's private function isn't doing it for us because it's dependent on the global --- php/commands/sidebar-widget.php | 70 +++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index fe88141c3..8225c6c77 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -137,12 +137,11 @@ public function update( $args, $assoc_args ) { WP_CLI::error( "No options specified to update." ); } - $option_key = 'widget_' . $name; $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); - $widget_options = get_option( $option_key ); + $widget_options = $this->get_widget_options( $name ); $clean_options = $this->sanitize_widget_options( $name, $assoc_args, $widget_options[ $option_index ] ); $widget_options[ $option_index ] = array_merge( (array)$widget_options[ $option_index ], $clean_options ); - update_option( $option_key, $widget_options ); + $this->update_widget_options( $name, $widget_options ); WP_CLI::success( "Widget updated." ); @@ -174,20 +173,7 @@ public function move( $args, $assoc_args ) { $new_position = 1; } - // Human-readable positions are different than numerically indexed array - $current_position--; - $new_position--; - - // Reposition and update - $all_widgets = wp_get_sidebars_widgets(); - $sidebar_widgets = $all_widgets[ $sidebar_id ]; - $part = array_splice( $sidebar_widgets, $current_position, 1 ); - array_splice( $sidebar_widgets, $new_position, 0, $part ); - $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); - update_option( 'sidebars_widgets', $all_widgets ); - - // Reset the global just in case - wp_get_sidebars_widgets(); + $this->reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ); WP_CLI::success( "Widget moved." ); @@ -213,22 +199,18 @@ public function remove( $args, $assoc_args ) { $this->validate_sidebar_widget( $sidebar_id, $name, $position ); // Remove the widget's settings - $option_key = 'widget_' . $name; $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); - $widget_options = get_option( $option_key ); + $widget_options = $this->get_widget_options( $name ); unset( $widget_options[ $option_index ] ); - update_option( $option_key, $widget_options ); + $this->update_widget_options( $name, $widget_options ); // Remove the widget from the sidebar - $all_widgets = wp_get_sidebars_widgets(); + $all_widgets = $this->wp_get_sidebars_widgets(); $position--; unset( $all_widgets[ $sidebar_id ][ $position ] ); $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); update_option( 'sidebars_widgets', $all_widgets ); - // Reset the global just in case - wp_get_sidebars_widgets(); - WP_CLI::success( "Widget removed from sidebar." ); } @@ -284,7 +266,7 @@ private function validate_sidebar_widget( $sidebar_id, $name, $position ) { */ private function get_sidebar_widgets( $sidebar_id ) { - $all_widgets = wp_get_sidebars_widgets(); + $all_widgets = $this->wp_get_sidebars_widgets(); if ( empty( $all_widgets[ $sidebar_id ] ) ) { return array(); @@ -310,6 +292,19 @@ private function get_sidebar_widgets( $sidebar_id ) { return $prepared_widgets; } + /** + * Re-implementation of wp_get_sidebars_widgets() + */ + private function wp_get_sidebars_widgets() { + $sidebars_widgets = get_option( 'sidebars_widgets', array() ); + + if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) { + unset( $sidebars_widgets['array_version'] ); + } + + return $sidebars_widgets; + } + /** * Get the widget's option index from its location on the sidebar * @@ -320,7 +315,7 @@ private function get_sidebar_widgets( $sidebar_id ) { */ private function get_widget_option_index( $sidebar_id, $name, $position ) { - $all_widgets = wp_get_sidebars_widgets(); + $all_widgets = $this->wp_get_sidebars_widgets(); $sidebar_widgets = $all_widgets[ $sidebar_id ]; $position--; $widget_real_name = $sidebar_widgets[ $position ]; @@ -350,6 +345,29 @@ private function update_widget_options( $name, $value ) { update_option( 'widget_' . $name, $value ); } + /** + * Reposition a widget within a sidebar + * + * @param string $sidebar_id + * @param int $current_position + * @param int $new_position + */ + private function reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ) { + + // Human-readable positions are different than numerically indexed array + $current_position--; + $new_position--; + + // Reposition and update + $all_widgets = $this->wp_get_sidebars_widgets(); + $sidebar_widgets = $all_widgets[ $sidebar_id ]; + $part = array_splice( $sidebar_widgets, $current_position, 1 ); + array_splice( $sidebar_widgets, $new_position, 0, $part ); + $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); + update_option( 'sidebars_widgets', $all_widgets ); + + } + /** * Get a widget's instantiated object based on its name * From 483fe97b814488e9e17c4348668f6dbbb148928d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 17:55:03 -0700 Subject: [PATCH 2825/5359] Update tests to include `wp sidebar widget update` case --- features/sidebar-widget.feature | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/features/sidebar-widget.feature b/features/sidebar-widget.feature index ae68e0e37..1d924e3d0 100644 --- a/features/sidebar-widget.feature +++ b/features/sidebar-widget.feature @@ -54,7 +54,7 @@ Feature: Manage widgets in WordPress sidebar | categories | 4 | | meta | 5 | - When I run `wp sidebar widget add sidebar-1 calendar 2 --title="Calendar"` + When I run `wp sidebar widget add sidebar-1 calendar 2` Then STDOUT should not be empty When I run `wp sidebar widget list sidebar-1 --fields=name,position` @@ -66,3 +66,11 @@ Feature: Manage widgets in WordPress sidebar | archives | 4 | | categories | 5 | | meta | 6 | + + When I run `wp sidebar widget update sidebar-1 calendar 2 --title="Calendar"` + Then STDOUT should not be empty + + When I run `wp sidebar widget list sidebar-1 --fields=name,position,options` + Then STDOUT should be a table containing rows: + | name | position | options | + | calendar | 2 | {"title":"Calendar"} | From 36626ab80eefbf26b348a91238307ef77cff6063 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 8 Apr 2014 17:55:23 -0700 Subject: [PATCH 2826/5359] Continue consolidation and refactor --- php/commands/sidebar-widget.php | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/php/commands/sidebar-widget.php b/php/commands/sidebar-widget.php index 8225c6c77..aef7d5909 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/sidebar-widget.php @@ -69,11 +69,7 @@ public function _list( $args, $assoc_args ) { public function add( $args, $assoc_args ) { list( $sidebar_id, $name ) = $args; - if ( isset( $args[2] ) ) { - $position = (int) $args[2]; - } else { - $position = false; - } + $new_position = ( isset( $args[2] ) ) ? (int) $args[2] : false; $this->validate_sidebar( $sidebar_id ); if ( false == ( $widget = $this->get_widget_obj( $name ) ) ) { @@ -87,6 +83,9 @@ public function add( $args, $assoc_args ) { * 3. Positioning appropriately */ $widget_options = $option_keys = $this->get_widget_options( $name ); + if ( ! isset( $widget_options['_multiwidget'] ) ) { + $widget_options['_multiwidget'] = 1; + } unset( $option_keys['_multiwidget'] ); $option_keys = array_keys( $option_keys ); $last_key = array_pop( $option_keys ); @@ -94,19 +93,15 @@ public function add( $args, $assoc_args ) { $widget_options[ $option_index ] = $this->sanitize_widget_options( $name, $assoc_args, array() ); $this->update_widget_options( $name, $widget_options ); - $all_widgets = wp_get_sidebars_widgets(); - $sidebar_widgets = $all_widgets[ $sidebar_id ]; - $sidebar_widgets[] = $name . '-' . $option_index; - - $current_position = count( $sidebar_widgets ) - 1; - if ( $position ) { - $new_position = $position - 1; - $part = array_splice( $sidebar_widgets, $current_position, 1 ); - array_splice( $sidebar_widgets, $new_position, 0, $part ); - $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); - } + $all_widgets = $this->wp_get_sidebars_widgets(); + $all_widgets[ $sidebar_id ][] = $name . '-' . $option_index; update_option( 'sidebars_widgets', $all_widgets ); + $current_position = count( $all_widgets[ $sidebar_id ] ); + if ( $new_position ) { + $this->reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ); + } + WP_CLI::success( "Added widget." ); } From 88e7b6f75b2fc46f4c6fe67174ab4ec4c6023369 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 Apr 2014 12:32:57 +0300 Subject: [PATCH 2827/5359] bump to WP 3.9-RC1 see https://core.trac.wordpress.org/changeset/27999 --- .travis.yml | 2 +- php/wp-settings-cli.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9a3e92cbe..94c066ac1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=3.9-beta1 + - WP_VERSION=3.9-RC1 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 401495881..67ad27f98 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -184,8 +184,6 @@ // Load must-use plugins. foreach ( wp_get_mu_plugins() as $mu_plugin ) { - if ( $symlinked_plugins_supported ) - wp_register_plugin_realpath( $mu_plugin ); include_once( $mu_plugin ); } unset( $mu_plugin ); From 77222f7967b989e174b75b2852d9fad66ae90bfa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 07:17:50 -0700 Subject: [PATCH 2828/5359] Revert "Update `WP_CLI\Utils\load_command()` to handle commands like `sidebar widget`" This reverts commit 16892f074fc2d688f267299cdfabd63c68e3bc27. See https://github.com/wp-cli/wp-cli/commit/16892f074fc2d688f267299cdfabd63c68e3bc27#commitcomment-5951766 --- php/WP_CLI/Runner.php | 2 +- php/utils.php | 24 +++--------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b685ee337..7a4cf0163 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -479,7 +479,7 @@ public function before_wp_load() { // Load bundled commands early, so that they're forced to use the same // APIs as non-bundled commands. - Utils\load_command( $this->arguments ); + Utils\load_command( $this->arguments[0] ); if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { diff --git a/php/utils.php b/php/utils.php index c697df928..b918d1824 100644 --- a/php/utils.php +++ b/php/utils.php @@ -41,30 +41,12 @@ function load_file( $path ) { require $path; } -/** - * Load a given internal WP-CLI command - * - * @param mixed - */ function load_command( $name ) { + $path = WP_CLI_ROOT . "/php/commands/$name.php"; - if ( is_string( $name ) ) { - $name = array( $name ); + if ( is_readable( $path ) ) { + include_once $path; } - - do { - - $file_name = implode( '-', $name ); - $path = WP_CLI_ROOT . "/php/commands/{$file_name}.php"; - - if ( is_readable( $path ) ) { - include_once $path; - } - - array_pop( $name ); - - } while( $name ); - } function load_all_commands() { From d4b940d6e5a79d45b12ad062afef6a06fa181a8c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 07:26:16 -0700 Subject: [PATCH 2829/5359] Rename and refactor to accommodate 77222f7967b989e174b75b2852d9fad66ae90bfa --- ...{sidebar-widget.feature => widget.feature} | 22 +++++++++---------- php/commands/sidebar.php | 21 +----------------- .../{sidebar-widget.php => widget.php} | 4 ++-- php/utils-wp.php | 18 +++++++++++++++ 4 files changed, 32 insertions(+), 33 deletions(-) rename features/{sidebar-widget.feature => widget.feature} (72%) rename php/commands/{sidebar-widget.php => widget.php} (98%) diff --git a/features/sidebar-widget.feature b/features/widget.feature similarity index 72% rename from features/sidebar-widget.feature rename to features/widget.feature index 1d924e3d0..0758c0562 100644 --- a/features/sidebar-widget.feature +++ b/features/widget.feature @@ -6,7 +6,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp theme install p2 --activate` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,position` Then STDOUT should be a table containing rows: | name | position | | search | 1 | @@ -16,10 +16,10 @@ Feature: Manage widgets in WordPress sidebar | categories | 5 | | meta | 6 | - When I run `wp sidebar widget move sidebar-1 recent-comments 3 2` + When I run `wp widget move sidebar-1 recent-comments 3 2` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,position` Then STDOUT should be a table containing rows: | name | position | | search | 1 | @@ -29,10 +29,10 @@ Feature: Manage widgets in WordPress sidebar | categories | 5 | | meta | 6 | - When I run `wp sidebar widget move sidebar-1 recent-comments 2 5` + When I run `wp widget move sidebar-1 recent-comments 2 5` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,position` Then STDOUT should be a table containing rows: | name | position | | search | 1 | @@ -42,10 +42,10 @@ Feature: Manage widgets in WordPress sidebar | recent-comments | 5 | | meta | 6 | - When I run `wp sidebar widget remove sidebar-1 recent-comments 5` + When I run `wp widget remove sidebar-1 recent-comments 5` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,position` Then STDOUT should be a table containing rows: | name | position | | search | 1 | @@ -54,10 +54,10 @@ Feature: Manage widgets in WordPress sidebar | categories | 4 | | meta | 5 | - When I run `wp sidebar widget add sidebar-1 calendar 2` + When I run `wp widget add sidebar-1 calendar 2` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,position` Then STDOUT should be a table containing rows: | name | position | | search | 1 | @@ -67,10 +67,10 @@ Feature: Manage widgets in WordPress sidebar | categories | 5 | | meta | 6 | - When I run `wp sidebar widget update sidebar-1 calendar 2 --title="Calendar"` + When I run `wp widget update sidebar-1 calendar 2 --title="Calendar"` Then STDOUT should not be empty - When I run `wp sidebar widget list sidebar-1 --fields=name,position,options` + When I run `wp widget list sidebar-1 --fields=name,position,options` Then STDOUT should be a table containing rows: | name | position | options | | calendar | 2 | {"title":"Calendar"} | diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index a52cadb47..3ba865d69 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -31,7 +31,7 @@ class Sidebar_Command extends WP_CLI_Command { public function _list( $args, $assoc_args ) { global $wp_registered_sidebars; - self::register_unused_sidebar(); + \WP_CLI\Utils\wp_register_unused_sidebar(); $output_sidebars = array(); foreach( $wp_registered_sidebars as $registered_sidebar ) { @@ -43,25 +43,6 @@ public function _list( $args, $assoc_args ) { } - /** - * Register the sidebar for unused widgets - * Core does this in /wp-admin/widgets.php, which isn't helpful - */ - public static function register_unused_sidebar() { - - register_sidebar(array( - 'name' => __('Inactive Widgets'), - 'id' => 'wp_inactive_widgets', - 'class' => 'inactive-sidebar', - 'description' => __( 'Drag widgets here to remove them from the sidebar but keep their settings.' ), - 'before_widget' => '', - 'after_widget' => '', - 'before_title' => '', - 'after_title' => '', - )); - - } - } WP_CLI::add_command( 'sidebar', 'Sidebar_Command' ); diff --git a/php/commands/sidebar-widget.php b/php/commands/widget.php similarity index 98% rename from php/commands/sidebar-widget.php rename to php/commands/widget.php index aef7d5909..0a6b1c605 100644 --- a/php/commands/sidebar-widget.php +++ b/php/commands/widget.php @@ -217,7 +217,7 @@ public function remove( $args, $assoc_args ) { private function validate_sidebar( $sidebar_id ) { global $wp_registered_sidebars; - Sidebar_Command::register_unused_sidebar(); + \WP_CLI\Utils\wp_register_unused_sidebar(); if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { WP_CLI::error( "Invalid sidebar." ); @@ -401,4 +401,4 @@ private function sanitize_widget_options( $id_base, $dirty_options, $old_options } -WP_CLI::add_command( 'sidebar widget', 'Widget_Command' ); +WP_CLI::add_command( 'widget', 'Widget_Command' ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 4048a8d06..dba28dfc2 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -95,3 +95,21 @@ function is_plugin_skipped( $file ) { return in_array( $name, array_filter( $skipped_plugins ) ); } +/** + * Register the sidebar for unused widgets + * Core does this in /wp-admin/widgets.php, which isn't helpful + */ +function wp_register_unused_sidebar() { + + register_sidebar(array( + 'name' => __('Inactive Widgets'), + 'id' => 'wp_inactive_widgets', + 'class' => 'inactive-sidebar', + 'description' => __( 'Drag widgets here to remove them from the sidebar but keep their settings.' ), + 'before_widget' => '', + 'after_widget' => '', + 'before_title' => '', + 'after_title' => '', + )); + +} From 2d9b281e30ce51af1dd4714b67f6eb07563f9126 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 07:46:51 -0700 Subject: [PATCH 2830/5359] Clarify why this method required re-implementing --- php/commands/widget.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/widget.php b/php/commands/widget.php index 0a6b1c605..bfdb8ea54 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -289,6 +289,7 @@ private function get_sidebar_widgets( $sidebar_id ) { /** * Re-implementation of wp_get_sidebars_widgets() + * because the original has a nasty global component */ private function wp_get_sidebars_widgets() { $sidebars_widgets = get_option( 'sidebars_widgets', array() ); From 4fb3d033a44875d7b61f6f188a1f91690f8c672e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 08:58:52 -0700 Subject: [PATCH 2831/5359] Refactor: `widget-id` is a unique widget key we can use across the board --- features/widget.feature | 90 +++++++++--------- php/commands/widget.php | 205 ++++++++++++++++++++++------------------ 2 files changed, 159 insertions(+), 136 deletions(-) diff --git a/features/widget.feature b/features/widget.feature index 0758c0562..76c0cc6b1 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -6,68 +6,70 @@ Feature: Manage widgets in WordPress sidebar When I run `wp theme install p2 --activate` Then STDOUT should not be empty - When I run `wp widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: - | name | position | - | search | 1 | - | recent-posts | 2 | - | recent-comments | 3 | - | archives | 4 | - | categories | 5 | - | meta | 6 | + | name | id | position | + | search | search-2 | 1 | + | recent-posts | recent-posts-2 | 2 | + | recent-comments | recent-comments-2 | 3 | + | archives | archives-2 | 4 | + | categories | categories-2 | 5 | + | meta | meta-2 | 6 | - When I run `wp widget move sidebar-1 recent-comments 3 2` + When I run `wp widget move recent-comments-2 --position=2` Then STDOUT should not be empty - When I run `wp widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: - | name | position | - | search | 1 | - | recent-comments | 2 | - | recent-posts | 3 | - | archives | 4 | - | categories | 5 | - | meta | 6 | + | name | id | position | + | search | search-2 | 1 | + | recent-comments | recent-comments-2 | 2 | + | recent-posts | recent-posts-2 | 3 | + | archives | archives-2 | 4 | + | categories | categories-2 | 5 | + | meta | meta-2 | 6 | - When I run `wp widget move sidebar-1 recent-comments 2 5` + When I run `wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets` Then STDOUT should not be empty - When I run `wp widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: - | name | position | - | search | 1 | - | recent-posts | 2 | - | archives | 3 | - | categories | 4 | - | recent-comments | 5 | - | meta | 6 | + | name | id | position | + | search | search-2 | 1 | + | recent-posts | recent-posts-2 | 2 | + | archives | archives-2 | 3 | + | categories | categories-2 | 4 | + | meta | meta-2 | 5 | - When I run `wp widget remove sidebar-1 recent-comments 5` + When I run `wp widget list wp_inactive_widgets --fields=name,id,position` + Then STDOUT should be a table containing rows: + | name | id | position | + | recent-comments | recent-comments-2 | 1 | + + When I run `wp widget delete archives-2` Then STDOUT should not be empty - When I run `wp widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: - | name | position | - | search | 1 | - | recent-posts | 2 | - | archives | 3 | - | categories | 4 | - | meta | 5 | + | name | id | position | + | search | search-2 | 1 | + | recent-posts | recent-posts-2 | 2 | + | categories | categories-2 | 3 | + | meta | meta-2 | 4 | - When I run `wp widget add sidebar-1 calendar 2` + When I run `wp widget add calendar sidebar-1 2` Then STDOUT should not be empty - When I run `wp widget list sidebar-1 --fields=name,position` + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: - | name | position | - | search | 1 | - | calendar | 2 | - | recent-posts | 3 | - | archives | 4 | - | categories | 5 | - | meta | 6 | + | name | id | position | + | search | search-2 | 1 | + | calendar | calendar-1 | 2 | + | recent-posts | recent-posts-2 | 3 | + | categories | categories-2 | 4 | + | meta | meta-2 | 5 | - When I run `wp widget update sidebar-1 calendar 2 --title="Calendar"` + When I run `wp widget update calendar-1 --title="Calendar"` Then STDOUT should not be empty When I run `wp widget list sidebar-1 --fields=name,position,options` diff --git a/php/commands/widget.php b/php/commands/widget.php index bfdb8ea54..cf247a987 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -8,6 +8,7 @@ class Widget_Command extends WP_CLI_Command { private $fields = array( 'name', + 'id', 'position', 'options', ); @@ -52,12 +53,12 @@ public function _list( $args, $assoc_args ) { /** * Add a widget to a sidebar. * - * <sidebar-id> - * : ID for the corresponding sidebar. - * * <name> * : Widget name. * + * <sidebar-id> + * : ID for the corresponding sidebar. + * * [<position>] * : Widget's current position within the sidebar. Defaults to last * @@ -68,8 +69,8 @@ public function _list( $args, $assoc_args ) { */ public function add( $args, $assoc_args ) { - list( $sidebar_id, $name ) = $args; - $new_position = ( isset( $args[2] ) ) ? (int) $args[2] : false; + list( $name, $sidebar_id ) = $args; + $position = ( isset( $args[2] ) ) ? (int) $args[2] - 1 : 0; $this->validate_sidebar( $sidebar_id ); if ( false == ( $widget = $this->get_widget_obj( $name ) ) ) { @@ -93,30 +94,19 @@ public function add( $args, $assoc_args ) { $widget_options[ $option_index ] = $this->sanitize_widget_options( $name, $assoc_args, array() ); $this->update_widget_options( $name, $widget_options ); - $all_widgets = $this->wp_get_sidebars_widgets(); - $all_widgets[ $sidebar_id ][] = $name . '-' . $option_index; - update_option( 'sidebars_widgets', $all_widgets ); - - $current_position = count( $all_widgets[ $sidebar_id ] ); - if ( $new_position ) { - $this->reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ); - } + $widget_id = $name . '-' . $option_index; + $this->move_sidebar_widget( $widget_id, null, $sidebar_id, null, $position ); - WP_CLI::success( "Added widget." ); + WP_CLI::success( "Added widget to sidebar." ); + } /** * Update a given widget's options. * - * <sidebar-id> - * : ID for the corresponding sidebar. - * - * <name> - * : Widget name. - * - * <position> - * : Widget's current position within the sidebar. + * <widget-id> + * : Unique ID for the widget * * [--<field>=<value>] * : Field to update, with its new value @@ -125,14 +115,15 @@ public function add( $args, $assoc_args ) { */ public function update( $args, $assoc_args ) { - list( $sidebar_id, $name, $position ) = $args; - $this->validate_sidebar_widget( $sidebar_id, $name, $position ); + list( $widget_id ) = $args; + $this->validate_sidebar_widget( $widget_id ); if ( empty( $assoc_args ) ) { WP_CLI::error( "No options specified to update." ); } - $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); + list( $name, $option_index ) = $this->get_widget_data( $widget_id ); + $widget_options = $this->get_widget_options( $name ); $clean_options = $this->sanitize_widget_options( $name, $assoc_args, $widget_options[ $option_index ] ); $widget_options[ $option_index ] = array_merge( (array)$widget_options[ $option_index ], $clean_options ); @@ -145,64 +136,66 @@ public function update( $args, $assoc_args ) { /** * Move a widget from one position on a sidebar to another. * - * <sidebar-id> - * : ID for the corresponding sidebar. - * - * <name> - * : Widget name. + * <widget-id> + * : Unique ID for the widget * - * <current-position> - * : Widget's current position within the sidebar. + * [--position=<position>] + * : Assign the widget to a new position. * - * <new-position> - * : Widget's new position within the sidebar. + * [--sidebar-id=<sidebar-id>] + * : Assign the widget to a new sidebar * * @subcommand move */ public function move( $args, $assoc_args ) { - list( $sidebar_id, $name, $current_position, $new_position ) = $args; - $this->validate_sidebar_widget( $sidebar_id, $name, $current_position ); + list( $widget_id ) = $args; + $this->validate_sidebar_widget( $widget_id ); + + if ( empty( $assoc_args['position'] ) && empty( $assoc_args['sidebar-id'] ) ) { + WP_CLI::error( "A new position or new sidebar must be specified." ); + } + + list( $name, $option_index, $current_sidebar_id, $current_sidebar_index ) = $this->get_widget_data( $widget_id ); + + $new_sidebar_id = ! empty( $assoc_args['sidebar-id'] ) ? $assoc_args['sidebar-id'] : $current_sidebar_id; + $this->validate_sidebar( $new_sidebar_id ); - if ( $new_position < -1 ) { - $new_position = 1; + $new_sidebar_index = ! empty( $assoc_args['position'] ) ? $assoc_args['position'] - 1 : $current_sidebar_index; + // Moving between sidebars adds to the top + if ( $new_sidebar_id != $current_sidebar_id && $new_sidebar_index == $current_sidebar_index ) { + // Human-readable positions are different than numerically indexed array + $new_sidebar_index = 0; } - $this->reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ); + $this->move_sidebar_widget( $widget_id, $current_sidebar_id, $new_sidebar_id, $current_sidebar_index, $new_sidebar_index ); WP_CLI::success( "Widget moved." ); } /** - * Remove a widget from a sidebar. - * - * <sidebar-id> - * : ID for the corresponding sidebar. - * - * <name> - * : Widget name. + * Delete a widget from a sidebar. * - * <position> - * : Widget's current position within the sidebar. + * <widget-id> + * : Unique ID for the widget * - * @subcommand + * @subcommand delete */ - public function remove( $args, $assoc_args ) { + public function delete( $args, $assoc_args ) { - list( $sidebar_id, $name, $position ) = $args; - $this->validate_sidebar_widget( $sidebar_id, $name, $position ); + list( $widget_id ) = $args; + $this->validate_sidebar_widget( $widget_id ); // Remove the widget's settings - $option_index = $this->get_widget_option_index( $sidebar_id, $name, $position ); + list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); $widget_options = $this->get_widget_options( $name ); unset( $widget_options[ $option_index ] ); $this->update_widget_options( $name, $widget_options ); // Remove the widget from the sidebar $all_widgets = $this->wp_get_sidebars_widgets(); - $position--; - unset( $all_widgets[ $sidebar_id ][ $position ] ); + unset( $all_widgets[ $sidebar_id ][ $sidebar_index ] ); $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); update_option( 'sidebars_widgets', $all_widgets ); @@ -227,20 +220,16 @@ private function validate_sidebar( $sidebar_id ) { /** * Check whether the specified widget is on the sidebar * - * @param string $sidebar_id - * @param string $name - * @param int $position + * @param string $widget_id */ - private function validate_sidebar_widget( $sidebar_id, $name, $position ) { - - $this->validate_sidebar( $sidebar_id ); + private function validate_sidebar_widget( $widget_id ) { - $sidebar_widgets = $this->get_sidebar_widgets( $sidebar_id ); + $sidebars_widgets = $this->wp_get_sidebars_widgets(); $widget_exists = false; - foreach( $sidebar_widgets as $sidebar_widget ) { + foreach( $sidebars_widgets as $sidebar_id => $widgets ) { - if ( $name == $sidebar_widget->name && $position == $sidebar_widget->position ) { + if ( in_array( $widget_id, $widgets ) ) { $widget_exists = true; break; } @@ -268,15 +257,16 @@ private function get_sidebar_widgets( $sidebar_id ) { } $prepared_widgets = array(); - foreach( $all_widgets[ $sidebar_id ] as $key => $widget_name ) { + foreach( $all_widgets[ $sidebar_id ] as $key => $widget_id ) { $prepared_widget = new stdClass; - $parts = explode( '-', $widget_name ); + $parts = explode( '-', $widget_id ); $option_index = array_pop( $parts ); $widget_name = implode( '-', $parts ); $prepared_widget->name = $widget_name; + $prepared_widget->id = $widget_id; $prepared_widget->position = $key + 1; $widget_options = get_option( 'widget_' . $widget_name ); $prepared_widget->options = $widget_options[ $option_index ]; @@ -302,23 +292,31 @@ private function wp_get_sidebars_widgets() { } /** - * Get the widget's option index from its location on the sidebar - * - * @param string $sidebar_id - * @param string $name - * @param int $position - * @return int + * Get the widget's name, option index, sidebar, and sidebar index from its ID + * + * @param string $widget_id + * @return array */ - private function get_widget_option_index( $sidebar_id, $name, $position ) { + private function get_widget_data( $widget_id ) { - $all_widgets = $this->wp_get_sidebars_widgets(); - $sidebar_widgets = $all_widgets[ $sidebar_id ]; - $position--; - $widget_real_name = $sidebar_widgets[ $position ]; - $parts = explode( '-', $widget_real_name ); + $parts = explode( '-', $widget_id ); $option_index = array_pop( $parts ); + $name = implode( '-', $parts ); + + $sidebar_id = false; + $sidebar_index = false; + $all_widgets = $this->wp_get_sidebars_widgets(); + foreach( $all_widgets as $s_id => &$widgets ) { + + if ( false !== ( $key = array_search( $widget_id, $widgets ) ) ) { + $sidebar_id = $s_id; + $sidebar_index = $key; + break; + } + + } - return $option_index; + return array( $name, $option_index, $sidebar_id, $sidebar_index ); } /** @@ -344,22 +342,45 @@ private function update_widget_options( $name, $value ) { /** * Reposition a widget within a sidebar * - * @param string $sidebar_id - * @param int $current_position - * @param int $new_position + * @param string $widget_id + * @param string $current_sidebar_id + * @param string $new_sidebar_id + * @param int $current_index + * @param int $new_index */ - private function reposition_sidebar_widget( $sidebar_id, $current_position, $new_position ) { + private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_sidebar_id, $current_index, $new_index ) { - // Human-readable positions are different than numerically indexed array - $current_position--; - $new_position--; - - // Reposition and update $all_widgets = $this->wp_get_sidebars_widgets(); - $sidebar_widgets = $all_widgets[ $sidebar_id ]; - $part = array_splice( $sidebar_widgets, $current_position, 1 ); - array_splice( $sidebar_widgets, $new_position, 0, $part ); - $all_widgets[ $sidebar_id ] = array_values( $sidebar_widgets ); + $needs_placement = true; + // Existing widget + if ( $current_sidebar_id && $current_index ) { + + $widgets = $all_widgets[ $current_sidebar_id ]; + if ( $current_sidebar_id != $new_sidebar_id ) { + + unset( $widgets[ $current_index ] ); + + } else { + + $part = array_splice( $widgets, $current_index, 1 ); + array_splice( $widgets, $new_index, 0, $part ); + + $needs_placement = false; + + } + + $all_widgets[ $current_sidebar_id ] = array_values( $widgets ); + + } + + if ( $needs_placement ) { + $widgets = $all_widgets[ $new_sidebar_id ]; + $before = array_slice( $widgets, 0, $new_index, true ); + $after = array_slice( $widgets, $new_index, count( $widgets ), true ); + $widgets = array_merge( $before, array( $widget_id ), $after ); + $all_widgets[ $new_sidebar_id ] = array_values( $widgets ); + } + update_option( 'sidebars_widgets', $all_widgets ); } From fea27789eaaa430e60b66a3b563af573a2bf987a Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 Apr 2014 19:06:33 +0300 Subject: [PATCH 2832/5359] remove unnecessary casting to objects --- php/commands/sidebar.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 3ba865d69..a88c93ab0 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -13,7 +13,7 @@ class Sidebar_Command extends WP_CLI_Command { /** * List registered sidebars. - * + * * ## OPTIONS * * [--fields=<fields>] @@ -33,14 +33,8 @@ public function _list( $args, $assoc_args ) { \WP_CLI\Utils\wp_register_unused_sidebar(); - $output_sidebars = array(); - foreach( $wp_registered_sidebars as $registered_sidebar ) { - $output_sidebars[] = (object)$registered_sidebar; - } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_sidebars ); - + $formatter->display_items( $wp_registered_sidebars ); } } From 30b47132df3b339af58ccc0a8e69254bcb52d662 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 9 Apr 2014 19:07:06 +0300 Subject: [PATCH 2833/5359] s/_list/list_/g --- php/commands/sidebar.php | 2 +- php/commands/widget.php | 54 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index a88c93ab0..626476868 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -28,7 +28,7 @@ class Sidebar_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { global $wp_registered_sidebars; \WP_CLI\Utils\wp_register_unused_sidebar(); diff --git a/php/commands/widget.php b/php/commands/widget.php index cf247a987..4282a04fc 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -15,10 +15,10 @@ class Widget_Command extends WP_CLI_Command { /** * List widgets associated with a sidebar. - * + * * <sidebar-id> * : ID for the corresponding sidebar. - * + * * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to name, id, description * @@ -31,7 +31,7 @@ class Widget_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { list( $sidebar_id ) = $args; @@ -52,19 +52,19 @@ public function _list( $args, $assoc_args ) { /** * Add a widget to a sidebar. - * + * * <name> * : Widget name. - * + * * <sidebar-id> * : ID for the corresponding sidebar. - * + * * [<position>] * : Widget's current position within the sidebar. Defaults to last - * + * * [--<field>=<value>] * : Widget option to add, with its new value - * + * * @subcommand add */ public function add( $args, $assoc_args ) { @@ -98,19 +98,19 @@ public function add( $args, $assoc_args ) { $this->move_sidebar_widget( $widget_id, null, $sidebar_id, null, $position ); WP_CLI::success( "Added widget to sidebar." ); - + } /** * Update a given widget's options. - * + * * <widget-id> * : Unique ID for the widget - * + * * [--<field>=<value>] * : Field to update, with its new value - * + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -135,16 +135,16 @@ public function update( $args, $assoc_args ) { /** * Move a widget from one position on a sidebar to another. - * + * * <widget-id> * : Unique ID for the widget - * + * * [--position=<position>] * : Assign the widget to a new position. - * + * * [--sidebar-id=<sidebar-id>] * : Assign the widget to a new sidebar - * + * * @subcommand move */ public function move( $args, $assoc_args ) { @@ -176,10 +176,10 @@ public function move( $args, $assoc_args ) { /** * Delete a widget from a sidebar. - * + * * <widget-id> * : Unique ID for the widget - * + * * @subcommand delete */ public function delete( $args, $assoc_args ) { @@ -204,7 +204,7 @@ public function delete( $args, $assoc_args ) { /** * Check whether a sidebar is a valid sidebar - * + * * @param string $sidebar_id */ private function validate_sidebar( $sidebar_id ) { @@ -244,7 +244,7 @@ private function validate_sidebar_widget( $widget_id ) { /** * Get the widgets (and their associated data) for a given sidebar - * + * * @param string $sidebar_id * @return array */ @@ -280,7 +280,7 @@ private function get_sidebar_widgets( $sidebar_id ) { /** * Re-implementation of wp_get_sidebars_widgets() * because the original has a nasty global component - */ + */ private function wp_get_sidebars_widgets() { $sidebars_widgets = get_option( 'sidebars_widgets', array() ); @@ -293,7 +293,7 @@ private function wp_get_sidebars_widgets() { /** * Get the widget's name, option index, sidebar, and sidebar index from its ID - * + * * @param string $widget_id * @return array */ @@ -321,7 +321,7 @@ private function get_widget_data( $widget_id ) { /** * Get the options for a given widget - * + * * @param string $name * @return array */ @@ -331,7 +331,7 @@ private function get_widget_options( $name ) { /** * Update the options for a given widget - * + * * @param string $name * @param mixed */ @@ -341,7 +341,7 @@ private function update_widget_options( $name, $value ) { /** * Reposition a widget within a sidebar - * + * * @param string $widget_id * @param string $current_sidebar_id * @param string $new_sidebar_id @@ -387,7 +387,7 @@ private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_side /** * Get a widget's instantiated object based on its name - * + * * @param string $id_base Name of the widget * @return WP_Widget|false */ @@ -404,7 +404,7 @@ private function get_widget_obj( $id_base ) { /** * Clean up a widget's options based on its update callback - * + * * @param string $id_base Name of the widget * @param mixed $dirty_options * @param mixed $old_options From 6cb10ef5e4ae07cc4a1c5d7935a0f89ffedd54d9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 09:18:05 -0700 Subject: [PATCH 2834/5359] Support deleting multiple widgets in one go --- features/widget.feature | 12 +++++------- php/commands/widget.php | 33 +++++++++++++++++---------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/features/widget.feature b/features/widget.feature index 76c0cc6b1..49dfb2a83 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -46,16 +46,15 @@ Feature: Manage widgets in WordPress sidebar | name | id | position | | recent-comments | recent-comments-2 | 1 | - When I run `wp widget delete archives-2` + When I run `wp widget delete archives-2 recent-posts-2` Then STDOUT should not be empty When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: | name | id | position | | search | search-2 | 1 | - | recent-posts | recent-posts-2 | 2 | - | categories | categories-2 | 3 | - | meta | meta-2 | 4 | + | categories | categories-2 | 2 | + | meta | meta-2 | 3 | When I run `wp widget add calendar sidebar-1 2` Then STDOUT should not be empty @@ -65,9 +64,8 @@ Feature: Manage widgets in WordPress sidebar | name | id | position | | search | search-2 | 1 | | calendar | calendar-1 | 2 | - | recent-posts | recent-posts-2 | 3 | - | categories | categories-2 | 4 | - | meta | meta-2 | 5 | + | categories | categories-2 | 3 | + | meta | meta-2 | 4 | When I run `wp widget update calendar-1 --title="Calendar"` Then STDOUT should not be empty diff --git a/php/commands/widget.php b/php/commands/widget.php index 4282a04fc..a9aa72414 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -175,31 +175,32 @@ public function move( $args, $assoc_args ) { } /** - * Delete a widget from a sidebar. + * Delete one or more widgets from a sidebar. * - * <widget-id> - * : Unique ID for the widget + * <widget-id>... + * : Unique ID for the widget(s) * * @subcommand delete */ public function delete( $args, $assoc_args ) { - list( $widget_id ) = $args; - $this->validate_sidebar_widget( $widget_id ); + foreach( $args as $widget_id ) { + $this->validate_sidebar_widget( $widget_id ); - // Remove the widget's settings - list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); - $widget_options = $this->get_widget_options( $name ); - unset( $widget_options[ $option_index ] ); - $this->update_widget_options( $name, $widget_options ); + // Remove the widget's settings + list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); + $widget_options = $this->get_widget_options( $name ); + unset( $widget_options[ $option_index ] ); + $this->update_widget_options( $name, $widget_options ); - // Remove the widget from the sidebar - $all_widgets = $this->wp_get_sidebars_widgets(); - unset( $all_widgets[ $sidebar_id ][ $sidebar_index ] ); - $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); - update_option( 'sidebars_widgets', $all_widgets ); + // Remove the widget from the sidebar + $all_widgets = $this->wp_get_sidebars_widgets(); + unset( $all_widgets[ $sidebar_id ][ $sidebar_index ] ); + $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); + update_option( 'sidebars_widgets', $all_widgets ); + } - WP_CLI::success( "Widget removed from sidebar." ); + WP_CLI::success( "Widget(s) removed from sidebar." ); } /** From c2eb40ad3ed8cf7d5d0ee92a2bded59330bf67e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 09:29:50 -0700 Subject: [PATCH 2835/5359] Hook up some widget examples --- php/commands/widget.php | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index a9aa72414..eaf30131d 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -2,6 +2,20 @@ /** * Manage sidebar widgets. + * + * ## EXAMPLES + * + * # List widgets on a given sidebar + * wp widget list sidebar-1 + * + * # Add a calendar widget to the second position on the sidebar + * wp widget add calendar sidebar-1 2 + * + * # Update option(s) associated with a given widget + * wp widget update calendar-1 --title="Calendar" + * + * # Delete one or more widgets entirely + * wp widget delete calendar-2 archive-1 */ class Widget_Command extends WP_CLI_Command { @@ -27,7 +41,7 @@ class Widget_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp sidebar widget list <sidebar> --fields=name --format=csv + * wp sidebar widget list <sidebar-id> --fields=name --format=csv * * @subcommand list */ @@ -65,6 +79,10 @@ public function list_( $args, $assoc_args ) { * [--<field>=<value>] * : Widget option to add, with its new value * + * ## EXAMPLES + * + * wp widget add calendar sidebar-1 2 --title="Calendar" + * * @subcommand add */ public function add( $args, $assoc_args ) { @@ -111,6 +129,10 @@ public function add( $args, $assoc_args ) { * [--<field>=<value>] * : Field to update, with its new value * + * ## EXAMPLES + * + * wp widget update calendar-1 --title="Calendar" + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -145,6 +167,12 @@ public function update( $args, $assoc_args ) { * [--sidebar-id=<sidebar-id>] * : Assign the widget to a new sidebar * + * ## EXAMPLES + * + * wp widget move recent-comments-2 --position=2 + * + * wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets + * * @subcommand move */ public function move( $args, $assoc_args ) { @@ -180,6 +208,10 @@ public function move( $args, $assoc_args ) { * <widget-id>... * : Unique ID for the widget(s) * + * ## EXAMPLES + * + * wp widget delete recent-comments-2 + * * @subcommand delete */ public function delete( $args, $assoc_args ) { From b081e5332a34d7f348d3ba5be7c5261d63ca91b8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 09:36:48 -0700 Subject: [PATCH 2836/5359] Add `wp widget deactivate` for moving widgets to the deactivated sidebar --- features/widget.feature | 9 +++++---- php/commands/widget.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/features/widget.feature b/features/widget.feature index 49dfb2a83..b5c731761 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -32,6 +32,9 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets` Then STDOUT should not be empty + When I run `wp widget deactivate meta-2` + Then STDOUT should not be empty + When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: | name | id | position | @@ -39,12 +42,12 @@ Feature: Manage widgets in WordPress sidebar | recent-posts | recent-posts-2 | 2 | | archives | archives-2 | 3 | | categories | categories-2 | 4 | - | meta | meta-2 | 5 | When I run `wp widget list wp_inactive_widgets --fields=name,id,position` Then STDOUT should be a table containing rows: | name | id | position | - | recent-comments | recent-comments-2 | 1 | + | meta | meta-2 | 1 | + | recent-comments | recent-comments-2 | 2 | When I run `wp widget delete archives-2 recent-posts-2` Then STDOUT should not be empty @@ -54,7 +57,6 @@ Feature: Manage widgets in WordPress sidebar | name | id | position | | search | search-2 | 1 | | categories | categories-2 | 2 | - | meta | meta-2 | 3 | When I run `wp widget add calendar sidebar-1 2` Then STDOUT should not be empty @@ -65,7 +67,6 @@ Feature: Manage widgets in WordPress sidebar | search | search-2 | 1 | | calendar | calendar-1 | 2 | | categories | categories-2 | 3 | - | meta | meta-2 | 4 | When I run `wp widget update calendar-1 --title="Calendar"` Then STDOUT should not be empty diff --git a/php/commands/widget.php b/php/commands/widget.php index eaf30131d..00ca77231 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -202,6 +202,36 @@ public function move( $args, $assoc_args ) { } + /** + * Deactivate one or more widgets from an active sidebar. + * + * <widget-id>... + * : Unique ID for the widget(s) + * + * ## EXAMPLES + * + * wp widget deactivate recent-comments-2 + * + * @subcommand deactivate + */ + public function deactivate( $args, $assoc_args ) { + + foreach( $args as $widget_id ) { + $this->validate_sidebar_widget( $widget_id ); + + list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); + if ( 'wp_inactive_widgets' == $sidebar_id ) { + WP_CLI::warning( sprintf( "'%s' is already deactivated.", $widget_id ) ); + continue; + } + + $this->move_sidebar_widget( $widget_id, $sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); + + } + + WP_CLI::success( "Widget(s) deactivated" ); + } + /** * Delete one or more widgets from a sidebar. * From 45789f75e0a3c7520dcf9c28f2225365e7c95309 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 11:45:04 -0700 Subject: [PATCH 2837/5359] Add `--network` support for `wp core is-installed` --- features/core.feature | 16 ++++++++++++++-- php/commands/core.php | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index a7c647917..73ac9662c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -101,6 +101,9 @@ Feature: Manage WordPress installation When I try `wp core is-installed` Then the return code should be 1 + When I try `wp core is-installed --network` + Then the return code should be 1 + When I try `wp core install` Then the return code should be 1 And STDERR should contain: @@ -117,6 +120,9 @@ Feature: Manage WordPress installation http://localhost:8001 """ + When I try `wp core is-installed --network` + Then the return code should be 1 + Scenario: Install WordPress by prompting Given an empty directory And WP files @@ -169,7 +175,10 @@ Feature: Manage WordPress installation Then STDOUT should be: """ false - """ + """ + + When I try `wp core is-installed --network` + Then the return code should be 1 When I run `wp core install-network --title='test network'` Then STDOUT should not be empty @@ -178,7 +187,10 @@ Feature: Manage WordPress installation Then STDOUT should be: """ true - """ + """ + + When I run `wp core is-installed --network` + Then the return code should be 0 When I try `wp core install-network --title='test network'` Then the return code should be 1 diff --git a/php/commands/core.php b/php/commands/core.php index f2c9247ba..8bec2be5a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -279,6 +279,9 @@ public function config( $_, $assoc_args ) { /** * Determine if the WordPress tables are installed. * + * [--network] + * : Check if this is a multisite install + * * ## EXAMPLES * * if ! $(wp core is-installed); then @@ -287,8 +290,15 @@ public function config( $_, $assoc_args ) { * * @subcommand is-installed */ - public function is_installed() { - if ( is_blog_installed() ) { + public function is_installed( $_, $assoc_args ) { + + if ( isset( $assoc_args['network'] ) ) { + if ( is_blog_installed() && is_multisite() ) { + exit( 0 ); + } else { + exit( 1 ); + } + } else if ( is_blog_installed() ) { exit( 0 ); } else { exit( 1 ); From 5bcba9124feea5bdc933f38554eeed0d1585c177 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 12:00:43 -0700 Subject: [PATCH 2838/5359] Optionally send an email to the user when their account is created --- php/commands/user.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index b3ce47bc3..a7622b6ad 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -163,6 +163,9 @@ public function delete( $args, $assoc_args ) { * [--display_name=<name>] * : The display name. * + * [--send-email] + * : Send an email to the user with their new account details. + * * [--porcelain] * : Output just the new user id. * @@ -201,6 +204,9 @@ public function create( $args, $assoc_args ) { $user->role = $role; $user_id = wp_insert_user( $user ); + if ( isset( $assoc_args['send-email'] ) ) { + wp_new_user_notification( $user_id, $user->user_pass ); + } if ( is_wp_error( $user_id ) ) { WP_CLI::error( $user_id ); @@ -505,6 +511,9 @@ public function list_caps( $args, $assoc_args ) { * <file> * : The CSV file of users to import. * + * [--send-email] + * : Send an email to new users with their account details. + * * ## EXAMPLES * * wp user import-csv /path/to/users.csv @@ -564,6 +573,9 @@ public function import_csv( $args, $assoc_args ) { } else { unset( $new_user['ID'] ); // Unset else it will just return the ID $user_id = wp_insert_user( $new_user ); + if ( isset( $assoc_args['send-email'] ) ) { + wp_new_user_notification( $user_id, $new_user['user_pass'] ); + } } if ( is_wp_error( $user_id ) ) { From 7390b8b1dbe4ad250548841a636c265ed4ef34ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 14:31:18 -0700 Subject: [PATCH 2839/5359] Whitespace cleanup --- php/commands/menu.php | 136 +++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 17a1e1138..b9f3ea5d8 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -16,13 +16,13 @@ class Menu_Command extends WP_CLI_Command { /** * Create a new menu - * + * * <menu-name> * : A descriptive name for the menu * * [--porcelain] - * : Output just the new menu id. - * + * : Output just the new menu id. + * * ## EXAMPLES * * wp menu create "My Menu" @@ -48,10 +48,10 @@ public function create( $args, $assoc_args ) { /** * List locations for the current theme. - * + * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table - * + * * @subcommand theme-locations */ public function theme_locations( $_, $assoc_args ) { @@ -71,10 +71,10 @@ public function theme_locations( $_, $assoc_args ) { /** * Assign a location to a menu - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * <location> * : Location's slug * @@ -87,7 +87,7 @@ public function assign_location( $args, $_ ) { $menu = wp_get_nav_menu_object( $menu ); if ( ! $menu || is_wp_error( $menu ) ) { WP_CLI::error( "Invalid menu." ); - } + } $locations = get_registered_nav_menus(); if ( ! array_key_exists( $location, $locations ) ) { @@ -95,7 +95,7 @@ public function assign_location( $args, $_ ) { } $locations = get_nav_menu_locations(); - $locations[ $location ] = $menu->term_id; + $locations[ $location ] = $menu->term_id; set_theme_mod( 'nav_menu_locations', $locations ); @@ -104,10 +104,10 @@ public function assign_location( $args, $_ ) { /** * Remove a location from a menu - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * <location> * : Location's slug * @@ -120,14 +120,14 @@ public function remove_location( $args, $_ ) { $menu = wp_get_nav_menu_object( $menu ); if ( ! $menu || is_wp_error( $menu ) ) { WP_CLI::error( "Invalid menu." ); - } + } $locations = get_nav_menu_locations(); if ( ! isset( $locations[ $location ] ) || $locations[ $location ] != $menu->term_id ) { WP_CLI::error( "Menu isn't assigned to location." ); } - $locations[ $location ] = 0; + $locations[ $location ] = 0; set_theme_mod( 'nav_menu_locations', $locations ); WP_CLI::success( "Removed location from menu." ); @@ -136,10 +136,10 @@ public function remove_location( $args, $_ ) { /** * Delete a menu - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * ## EXAMPLES * * wp menu delete "My Menu" @@ -195,7 +195,7 @@ public function list_( $_, $assoc_args ) { } } - + // Normalize the data for some output formats if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { $menu->locations = implode( ',', $menu->locations ); @@ -230,7 +230,7 @@ class Menu_Item_Command extends WP_CLI_Command { * Get a list of items associated with a menu * * ## OPTIONS - * + * * <menu> * : The name, slug, or term ID for the menu * @@ -268,40 +268,40 @@ public function list_( $args, $assoc_args ) { /** * Add a post as a menu item - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * <post-id> * : Post ID to add to the menu - * + * * [--title=<title>] * : Set a custom title for the menu item - * + * * [--link=<link>] * : Set a custom url for the menu item - * + * * [--description=<description>] * : Set a custom description for the menu item - * + * * [--attr-title=<attr-title>] * : Set a custom title attribute for the menu item - * + * * [--target=<target>] * : Set a custom link target for the menu item - * + * * [--classes=<classes>] * : Set a custom link classes for the menu item - * + * * [--position=<position>] * : Specify the position of this menu item. - * + * * [--parent-id=<parent-id>] * : Make this menu item a child of another menu item - * + * * [--porcelain] * : Output just the new menu item id. - * + * * @subcommand add-post */ public function add_post( $args, $assoc_args ) { @@ -319,43 +319,43 @@ public function add_post( $args, $assoc_args ) { /** * Add a taxonomy term as a menu item - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * <taxonomy> * : Taxonomy of the term to be added - * + * * <term-id> * : Term ID of the term to be added - * + * * [--title=<title>] * : Set a custom title for the menu item - * + * * [--link=<link>] * : Set a custom url for the menu item - * + * * [--description=<description>] * : Set a custom description for the menu item - * + * * [--attr-title=<attr-title>] * : Set a custom title attribute for the menu item - * + * * [--target=<target>] * : Set a custom link target for the menu item - * + * * [--classes=<classes>] * : Set a custom link classes for the menu item - * + * * [--position=<position>] * : Specify the position of this menu item. - * + * * [--parent-id=<parent-id>] * : Make this menu item a child of another menu item - * + * * [--porcelain] * : Output just the new menu item id. - * + * * @subcommand add-term */ public function add_term( $args, $assoc_args ) { @@ -374,37 +374,37 @@ public function add_term( $args, $assoc_args ) { /** * Add a custom menu item - * + * * <menu> * : The name, slug, or term ID for the menu - * + * * <title> * : Title for the link - * + * * <link> * : Target URL for the link - * + * * [--description=<description>] * : Set a custom description for the menu item - * + * * [--attr-title=<attr-title>] * : Set a custom title attribute for the menu item - * + * * [--target=<target>] * : Set a custom link target for the menu item - * + * * [--classes=<classes>] * : Set a custom link classes for the menu item - * + * * [--position=<position>] * : Specify the position of this menu item. - * + * * [--parent-id=<parent-id>] * : Make this menu item a child of another menu item - * + * * [--porcelain] * : Output just the new menu item id. - * + * * @subcommand add-custom */ public function add_custom( $args, $assoc_args ) { @@ -418,34 +418,34 @@ public function add_custom( $args, $assoc_args ) { /** * Update a menu item - * + * * <db-id> * : Database ID for the menu item. - * + * * [--title=<title>] * : Set a custom title for the menu item - * + * * [--link=<link>] * : Set a custom url for the menu item - * + * * [--description=<description>] * : Set a custom description for the menu item - * + * * [--attr-title=<attr-title>] * : Set a custom title attribute for the menu item - * + * * [--target=<target>] * : Set a custom link target for the menu item - * + * * [--classes=<classes>] * : Set a custom link classes for the menu item - * + * * [--position=<position>] * : Specify the position of this menu item. - * + * * [--parent-id=<parent-id>] * : Make this menu item a child of another menu item - * + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -465,10 +465,10 @@ public function update( $args, $assoc_args ) { /** * Remove an item from a menu - * + * * <db-id> * : Database ID for the menu item. - * + * * @subcommand remove */ public function remove( $args, $_ ) { @@ -516,7 +516,7 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { $menu_item_args = array(); foreach( $default_args as $key => $default_value ) { - // wp_update_nav_menu_item() has a weird argument prefix + // wp_update_nav_menu_item() has a weird argument prefix $new_key = 'menu-item-' . $key; if ( isset( $assoc_args[ $key ] ) ) { $menu_item_args[ $new_key ] = $assoc_args[ $key ]; @@ -545,11 +545,11 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { /** * Set the menu - * + * * wp_update_nav_menu_item() *should* take care of this, but * depends on wp_insert_post()'s "tax_input" argument, which * is ignored if the user can't edit the taxonomy - * + * * @see https://core.trac.wordpress.org/ticket/27113 */ if ( ! is_object_in_term( $ret, 'nav_menu', (int) $menu->term_id ) ) { From 10445774053543fa10138596d73f53aa97b0f24e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 14:36:16 -0700 Subject: [PATCH 2840/5359] Put menu location management in its own sub-sub-command --- features/menu.feature | 6 +- php/commands/menu.php | 185 ++++++++++++++++++++++-------------------- 2 files changed, 100 insertions(+), 91 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index b9309253c..65d7774c9 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -21,19 +21,19 @@ Feature: Manage WordPress menus Scenario: Assign / remove location from a menu When I run `wp theme install p2 --activate` - And I run `wp menu theme-locations` + And I run `wp menu location list` Then STDOUT should be a table containing rows: | location | description | | primary | Primary Menu | When I run `wp menu create "Primary Menu"` - And I run `wp menu assign-location primary-menu primary` + And I run `wp menu location assign primary-menu primary` And I run `wp menu list --fields=slug,locations` Then STDOUT should be a table containing rows: | slug | locations | | primary-menu | primary | - When I run `wp menu remove-location primary-menu primary` + When I run `wp menu location remove primary-menu primary` And I run `wp menu list --fields=slug,locations` Then STDOUT should be a table containing rows: | slug | locations | diff --git a/php/commands/menu.php b/php/commands/menu.php index b9f3ea5d8..b20934690 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -46,94 +46,6 @@ public function create( $args, $assoc_args ) { } } - /** - * List locations for the current theme. - * - * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table - * - * @subcommand theme-locations - */ - public function theme_locations( $_, $assoc_args ) { - - $locations = get_registered_nav_menus(); - $location_objs = array(); - foreach( $locations as $location => $description ) { - $location_obj = new \stdClass; - $location_obj->location = $location; - $location_obj->description = $description; - $location_objs[] = $location_obj; - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); - $formatter->display_items( $location_objs ); - } - - /** - * Assign a location to a menu - * - * <menu> - * : The name, slug, or term ID for the menu - * - * <location> - * : Location's slug - * - * @subcommand assign-location - */ - public function assign_location( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - $locations = get_registered_nav_menus(); - if ( ! array_key_exists( $location, $locations ) ) { - WP_CLI::error( "Invalid location." ); - } - - $locations = get_nav_menu_locations(); - $locations[ $location ] = $menu->term_id; - - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Assigned location to menu." ); - } - - /** - * Remove a location from a menu - * - * <menu> - * : The name, slug, or term ID for the menu - * - * <location> - * : Location's slug - * - * @subcommand remove-location - */ - public function remove_location( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - $locations = get_nav_menu_locations(); - if ( ! isset( $locations[ $location ] ) || $locations[ $location ] != $menu->term_id ) { - WP_CLI::error( "Menu isn't assigned to location." ); - } - - $locations[ $location ] = 0; - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Removed location from menu." ); - - } - /** * Delete a menu * @@ -575,5 +487,102 @@ protected function get_formatter( &$assoc_args ) { } +/** + * Manage a menu's assignment to locations. + */ +class Menu_Location_Command extends WP_CLI_Command { + + /** + * List locations for the current theme. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, ids. Default: table + * + * @subcommand list + */ + public function list_( $_, $assoc_args ) { + + $locations = get_registered_nav_menus(); + $location_objs = array(); + foreach( $locations as $location => $description ) { + $location_obj = new \stdClass; + $location_obj->location = $location; + $location_obj->description = $description; + $location_objs[] = $location_obj; + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); + $formatter->display_items( $location_objs ); + } + + /** + * Assign a location to a menu + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <location> + * : Location's slug + * + * @subcommand assign + */ + public function assign( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_registered_nav_menus(); + if ( ! array_key_exists( $location, $locations ) ) { + WP_CLI::error( "Invalid location." ); + } + + $locations = get_nav_menu_locations(); + $locations[ $location ] = $menu->term_id; + + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Assigned location to menu." ); + } + + /** + * Remove a location from a menu + * + * <menu> + * : The name, slug, or term ID for the menu + * + * <location> + * : Location's slug + * + * @subcommand remove + */ + public function remove( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_nav_menu_locations(); + if ( ! isset( $locations[ $location ] ) || $locations[ $location ] != $menu->term_id ) { + WP_CLI::error( "Menu isn't assigned to location." ); + } + + $locations[ $location ] = 0; + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Removed location from menu." ); + + } + + +} + WP_CLI::add_command( 'menu', 'Menu_Command' ); WP_CLI::add_command( 'menu item', 'Menu_Item_Command' ); +WP_CLI::add_command( 'menu location', 'Menu_Location_Command' ); From f69026bb5a8fb46362a5fb4dbe1848aa4a4338e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 14:41:30 -0700 Subject: [PATCH 2841/5359] First pass at updating examples --- php/commands/menu.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index b20934690..ed397bf4b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -214,6 +214,10 @@ public function list_( $args, $assoc_args ) { * [--porcelain] * : Output just the new menu item id. * + * ## EXAMPLES + * + * wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * * @subcommand add-post */ public function add_post( $args, $assoc_args ) { @@ -268,6 +272,10 @@ public function add_post( $args, $assoc_args ) { * [--porcelain] * : Output just the new menu item id. * + * ## EXAMPLES + * + * wp menu item add-term sidebar-menu post_tag 24 + * * @subcommand add-term */ public function add_term( $args, $assoc_args ) { @@ -317,6 +325,10 @@ public function add_term( $args, $assoc_args ) { * [--porcelain] * : Output just the new menu item id. * + * ## EXAMPLES + * + * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain + * * @subcommand add-custom */ public function add_custom( $args, $assoc_args ) { @@ -358,6 +370,10 @@ public function add_custom( $args, $assoc_args ) { * [--parent-id=<parent-id>] * : Make this menu item a child of another menu item * + * ## EXAMPLES + * + * wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -381,6 +397,10 @@ public function update( $args, $assoc_args ) { * <db-id> * : Database ID for the menu item. * + * ## EXAMPLES + * + * wp menu item remove 45 + * * @subcommand remove */ public function remove( $args, $_ ) { From 08a649468171924299f827ff1c23615e244bb2b4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 14:50:36 -0700 Subject: [PATCH 2842/5359] More example coverage --- php/commands/menu.php | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index ed397bf4b..240db7dc6 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -2,6 +2,14 @@ /** * List, create, assign, and delete menus + * + * ## EXAMPLES + * + * # Create a new menu + * wp menu create "My Menu" + * + * # List existing menus + * wp menu list */ class Menu_Command extends WP_CLI_Command { @@ -127,6 +135,14 @@ protected function get_formatter( &$assoc_args ) { /** * List, add, and delete items associated with a menu + * + * ## EXAMPLES + * + * # Add an existing post to an existing menu + * wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * + * # Create a new menu link item + * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain */ class Menu_Item_Command extends WP_CLI_Command { @@ -509,6 +525,17 @@ protected function get_formatter( &$assoc_args ) { /** * Manage a menu's assignment to locations. + * + * ## EXAMPLES + * + * # List available menu locations + * wp menu location list + * + * # Assign the 'primary-menu' menu to the 'primary' location + * wp menu location assign primary-menu primary + * + * # Remove the 'primary-menu' menu from the 'primary' location + * wp menu location remove primary-menu primary */ class Menu_Location_Command extends WP_CLI_Command { @@ -518,6 +545,10 @@ class Menu_Location_Command extends WP_CLI_Command { * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## EXAMPLES + * + * wp menu location list + * * @subcommand list */ public function list_( $_, $assoc_args ) { @@ -544,6 +575,10 @@ public function list_( $_, $assoc_args ) { * <location> * : Location's slug * + * ## EXAMPLES + * + * wp menu location assign primary-menu primary + * * @subcommand assign */ public function assign( $args, $_ ) { @@ -577,6 +612,10 @@ public function assign( $args, $_ ) { * <location> * : Location's slug * + * ## EXAMPLES + * + * wp menu location remove primary-menu primary + * * @subcommand remove */ public function remove( $args, $_ ) { From acc9c1ae2341e86f3e411f8f9c46fbfa971c673b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 14:51:22 -0700 Subject: [PATCH 2843/5359] Because `wp menu` is the "top"-level entity, offer discoverability for its children commands --- php/commands/menu.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index 240db7dc6..902e89c34 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -10,6 +10,12 @@ * * # List existing menus * wp menu list + * + * # Create a new menu link item + * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain + * + * # Assign the 'primary-menu' menu to the 'primary' location + * wp menu location assign primary-menu primary */ class Menu_Command extends WP_CLI_Command { From 94c66ba97c945508aa6a7f22a8348a3cd4a17a58 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 15:23:44 -0700 Subject: [PATCH 2844/5359] Core PHPdoc lies, `wp_create_nav_menu()` returns a term ID See https://core.trac.wordpress.org/ticket/27745 --- php/commands/menu.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 902e89c34..b359df3ae 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -43,18 +43,18 @@ class Menu_Command extends WP_CLI_Command { */ public function create( $args, $assoc_args ) { - $ret = wp_create_nav_menu( $args[0] ); + $menu_id = wp_create_nav_menu( $args[0] ); - if ( is_wp_error( $ret ) ) { + if ( is_wp_error( $menu_id ) ) { - WP_CLI::error( $ret->get_error_message() ); + WP_CLI::error( $menu_id->get_error_message() ); } else { if ( isset( $assoc_args['porcelain'] ) ) { - WP_CLI::line( $ret->term_id ); + WP_CLI::line( $menu_id ); } else { - WP_CLI::success( "Created menu $ret->term_id." ); + WP_CLI::success( "Created menu $menu_id." ); } } From 50b05e17df97da471a2b3aaa1817b733b7b1d0fd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 15:25:34 -0700 Subject: [PATCH 2845/5359] For consistency, let's call this `delete` instead of `remove` It permanently destroys the menu item. --- features/menu.feature | 2 +- php/commands/menu.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 65d7774c9..60862576e 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -71,7 +71,7 @@ Feature: Manage WordPress menus | custom | WordPress | 2 | http://wordpress.org | | taxonomy | Test term | 3 | {TERM_LINK} | - When I run `wp menu item remove {ITEM_ID}` + When I run `wp menu item delete {ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: """ diff --git a/php/commands/menu.php b/php/commands/menu.php index b359df3ae..af4501312 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -414,7 +414,7 @@ public function update( $args, $assoc_args ) { } /** - * Remove an item from a menu + * Delete an item from a menu * * <db-id> * : Database ID for the menu item. @@ -423,9 +423,9 @@ public function update( $args, $assoc_args ) { * * wp menu item remove 45 * - * @subcommand remove + * @subcommand delete */ - public function remove( $args, $_ ) { + public function delete( $args, $_ ) { $ret = wp_delete_post( $args[0], true ); if ( $ret ) { From 0600b1700c3db6acfcb571d351b928be2f662f80 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 9 Apr 2014 15:29:22 -0700 Subject: [PATCH 2846/5359] Support for deleting more than one menu or menu item --- php/commands/menu.php | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index af4501312..47160a541 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -61,10 +61,10 @@ public function create( $args, $assoc_args ) { } /** - * Delete a menu + * Delete one or more menus * - * <menu> - * : The name, slug, or term ID for the menu + * <menu>... + * : The name, slug, or term ID for the menu(s) * * ## EXAMPLES * @@ -72,17 +72,20 @@ public function create( $args, $assoc_args ) { */ public function delete( $args, $_ ) { - $ret = wp_delete_nav_menu( $args[0] ); + foreach( $args as $arg ) { - if ( ! $ret || is_wp_error( $ret ) ) { + $ret = wp_delete_nav_menu( $args[0] ); - WP_CLI::error( "Error deleting menu." ); + if ( ! $ret || is_wp_error( $ret ) ) { - } else { + WP_CLI::warning( "Error deleting menu." ); - WP_CLI::success( "Menu deleted." ); + } } + + WP_CLI::success( "Menu(s) deleted." ); + } /** @@ -414,10 +417,10 @@ public function update( $args, $assoc_args ) { } /** - * Delete an item from a menu + * Delete one or more items from a menu * - * <db-id> - * : Database ID for the menu item. + * <db-id>... + * : Database ID for the menu item(s). * * ## EXAMPLES * @@ -427,12 +430,15 @@ public function update( $args, $assoc_args ) { */ public function delete( $args, $_ ) { - $ret = wp_delete_post( $args[0], true ); - if ( $ret ) { - WP_CLI::success( "Menu item deleted." ); - } else { - WP_CLI::error( "Couldn't delete menu item." ); + foreach( $args as $arg ) { + + $ret = wp_delete_post( $arg, true ); + if ( ! $ret ) { + WP_CLI::warning( "Couldn't delete menu item." ); + } + } + WP_CLI::success( "Menu item(s) deleted." ); } From cffcf6958f3d38e77ba22fcd5e08cd469ef0d3f3 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 10 Apr 2014 02:49:03 +0300 Subject: [PATCH 2847/5359] allow shared cache in non-cache related behat tests --- features/bootstrap/FeatureContext.php | 21 +++++++++++++++------ features/core.feature | 2 ++ features/steps/given.php | 6 ++++++ features/upgradables.feature | 3 +++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d1650f5ba..20dda8ab5 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -41,15 +41,15 @@ private static function cache_wp_files() { */ public static function prepare( SuiteEvent $event ) { self::cache_wp_files(); - self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); - mkdir( self::$suite_cache_dir ); } /** * @AfterSuite */ public static function afterSuite( SuiteEvent $event ) { - Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ) )->run(); + if ( self::$suite_cache_dir ) { + Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ) )->run(); + } } /** @@ -65,6 +65,12 @@ public function afterScenario( $event ) { } } + public static function create_cache_dir() { + self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); + mkdir( self::$suite_cache_dir ); + return self::$suite_cache_dir; + } + /** * Initializes context. * Every scenario gets it's own context object. @@ -75,7 +81,6 @@ public function __construct( array $parameters ) { $this->drop_db(); $this->set_cache_dir(); $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); - $this->variables['SUITE_CACHE_DIR'] = self::$suite_cache_dir; } public function getStepDefinitionResources() { @@ -136,8 +141,12 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - return Process::create( $command, $this->variables['RUN_DIR'], - array( 'WP_CLI_CACHE_DIR' => $this->variables['SUITE_CACHE_DIR'] ) ); + $env = array(); + if ( isset( $this->variables['SUITE_CACHE_DIR'] ) ) { + $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; + } + + return Process::create( $command, $this->variables['RUN_DIR'], $env ); } public function move_files( $src, $dest ) { diff --git a/features/core.feature b/features/core.feature index 73ac9662c..fd7793eaa 100644 --- a/features/core.feature +++ b/features/core.feature @@ -3,6 +3,7 @@ Feature: Manage WordPress installation @download Scenario: Empty dir Given an empty directory + And an empty cache When I try `wp core is-installed` Then the return code should be 1 @@ -28,6 +29,7 @@ Feature: Manage WordPress installation @download Scenario: Localized install Given an empty directory + And an empty cache When I run `wp core download --locale=de_DE` And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist diff --git a/features/steps/given.php b/features/steps/given.php index a7b29d3c2..21117c55b 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -9,6 +9,12 @@ function ( $world ) { } ); +$steps->Given( '/^an empty cache/', + function ( $world ) { + $world->variables['SUITE_CACHE_DIR'] = FeatureContext::create_cache_dir(); + } +); + $steps->Given( '/^an? ([^\s]+) file:$/', function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; diff --git a/features/upgradables.feature b/features/upgradables.feature index 830291fe7..2bc9c2e06 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -1,5 +1,8 @@ Feature: Manage WordPress themes and plugins + Background: + Given an empty cache + Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install And I run `wp <type> path` From 108d875956ba973219473c5e71f95358bef463f4 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 10 Apr 2014 14:14:54 +0300 Subject: [PATCH 2848/5359] wp core update: fix description for --force parameter closes #1110 --- php/commands/core.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8bec2be5a..a112cc4f9 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -661,8 +661,7 @@ public function version( $args = array(), $assoc_args = array() ) { * : Update to this version, instead of to the latest version. * * [--force] - * : Will update even when current WP version < passed version. Use with - * caution. + * : Update even when installed WP version is greater than the requested version. * * [--locale=<locale>] * : Select which language you want to download. From 7d26d6afb59486e42200e76d612ed39cc5c6a791 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 10 Apr 2014 11:22:09 -0300 Subject: [PATCH 2849/5359] use wp locale instead of 'en_US' if locale argument is not used in wp core update --- php/commands/core.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index a112cc4f9..3a064aaf5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -685,7 +685,6 @@ function update( $args, $assoc_args ) { if ( empty( $assoc_args['version'] ) ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); - if ( empty( $from_api->updates ) ) $update = false; else @@ -698,7 +697,7 @@ function update( $args, $assoc_args ) { if ( empty( $args[0] ) ) { $version = $assoc_args['version']; - $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; + $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); $new_package = $this->get_download_url($version, $locale); From 6161a641b7d28ec6bfc81c4b104651a90ddf8cc4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 10 Apr 2014 15:05:47 -0300 Subject: [PATCH 2850/5359] add again line removed by mistake --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index 3a064aaf5..1ea378638 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -685,6 +685,7 @@ function update( $args, $assoc_args ) { if ( empty( $assoc_args['version'] ) ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); + if ( empty( $from_api->updates ) ) $update = false; else From 43f6ed09674f7bc6d6f18d274da0d8d726ef10b3 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 11 Apr 2014 23:43:14 -0300 Subject: [PATCH 2851/5359] add --autoload option to 'wp option add' command --- php/commands/option.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index f5e025860..ded55ce2b 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -50,6 +50,9 @@ public function get( $args, $assoc_args ) { * [--format=<format>] * : The serialization format for the value. Default is plaintext. * + * [--autoload=<autoload>] + * : Should this option be automatically loaded. Accepted values: yes, no. Default: yes + * * ## EXAMPLES * * # Create an option by reading a JSON file @@ -61,7 +64,13 @@ public function add( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); - if ( !add_option( $key, $value ) ) { + if ( isset( $assoc_args['autoload'] ) && $assoc_args['autoload'] == 'no' ) { + $autoload = 'no'; + } else { + $autoload = 'yes'; + } + + if ( !add_option( $key, $value, '', $autoload ) ) { WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); } else { WP_CLI::success( "Added '$key' option." ); From f3c70ecbccdcffa897ef936fd511e3bb73485a1b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 16:48:07 +0300 Subject: [PATCH 2852/5359] wp core download: error if the requested locale is not found fixes #1117 --- php/commands/core.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1ea378638..2853b27ec 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -28,7 +28,7 @@ class Core_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp core download --version=3.3 + * wp core download --locale=nl_NL * * @when before_wp_load */ @@ -48,6 +48,9 @@ public function download( $args, $assoc_args ) { $download_url = $this->get_download_url($version, $locale, 'tar.gz'); } else { $offer = $this->get_download_offer( $locale ); + if ( !$offer ) { + WP_CLI::error( "The requested locale ($locale) was not found." ); + } $version = $offer['current']; $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); } @@ -165,7 +168,13 @@ private function get_download_offer( $locale ) { $out = unserialize( self::_read( 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ) ); - return $out['offers'][0]; + $offer = $out['offers'][0]; + + if ( $offer['locale'] != $locale ) { + return false; + } + + return $offer; } private static function get_initial_locale() { From a8e0ff31edfdbae0ac4e455eda613414146e0a40 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 17:37:21 +0300 Subject: [PATCH 2853/5359] introduce --network flag for 'wp user delete' --- features/user.feature | 15 +++++++++++++++ php/commands/user.php | 27 +++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/features/user.feature b/features/user.feature index 793c3bf6a..abda33917 100644 --- a/features/user.feature +++ b/features/user.feature @@ -70,6 +70,21 @@ Feature: Manage WordPress users 3 """ + Scenario: Deleting user from the whole network + Given a WP multisite install + + When I run `wp user create bob bob@example.com --role=author --porcelain` + And save STDOUT as {BOB_ID} + + When I run `wp user get bob` + Then STDOUT should not be empty + + When I run `wp user delete bob --network` + Then STDOUT should not be empty + + When I try `wp user get bob` + Then STDERR should not be empty + Scenario: Generating and deleting users Given a WP install diff --git a/php/commands/user.php b/php/commands/user.php index a7622b6ad..2ce568b26 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -115,25 +115,40 @@ public function get( $args, $assoc_args ) { * <user>... * : The user login, user email, or user ID of the user(s) to update. * + * [--network] + * : On multisite, delete the user from the entire network. + * * [--reassign=<user-id>] * : User ID to reassign the posts to. * * ## EXAMPLES * + * # Delete user 123 and reassign posts to user 567 * wp user delete 123 --reassign=567 */ public function delete( $args, $assoc_args ) { - $assoc_args = wp_parse_args( $assoc_args, array( - 'reassign' => null - ) ); + $network = isset( $assoc_args['network'] ) && is_multisite(); + $reassign = isset( $assoc_args['reassign'] ) ? $assoc_args['reassign'] : null; + + if ( $network && $reassign ) { + WP_CLI::error('Reassigning content to a different user is not supported on multisite.'); + } $users = $this->fetcher->get_many( $args ); - parent::_delete( $users, $assoc_args, function ( $user, $assoc_args ) { + parent::_delete( $users, $assoc_args, function ( $user ) use ( $network, $reassign ) { $user_id = $user->ID; - if ( wp_delete_user( $user_id, $assoc_args['reassign'] ) ) { - return array( 'success', "Deleted user $user_id." ); + if ( $network ) { + $r = wpmu_delete_user( $user_id ); + $message = "Deleted user $user_id."; + } else { + $r = wp_delete_user( $user_id, $reassign ); + $message = "Removed user $user_id from " . home_url(); + } + + if ( $r ) { + return array( 'success', $message ); } else { return array( 'error', "Failed deleting user $user_id." ); } From 0a7cac5a1340a299231b5a3833967a035bb8636f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 17:50:08 +0300 Subject: [PATCH 2854/5359] show confirmation prompt before deleting user without reassigning posts --- features/user.feature | 8 ++++---- php/commands/user.php | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/features/user.feature b/features/user.feature index abda33917..ba508535f 100644 --- a/features/user.feature +++ b/features/user.feature @@ -17,7 +17,7 @@ Feature: Manage WordPress users | ID | {USER_ID} | | roles | author | - When I run `wp user delete {USER_ID}` + When I run `wp user delete {USER_ID} --yes` Then STDOUT should not be empty When I try `wp user create testuser2 testuser2@example.com --role=wrongrole --porcelain` @@ -44,7 +44,7 @@ Feature: Manage WordPress users | ID | {USER_ID} | | display_name | Foo | - When I run `wp user delete {USER_ID}` + When I run `wp user delete {USER_ID} --yes` Then STDOUT should not be empty Scenario: Reassigning user posts @@ -79,7 +79,7 @@ Feature: Manage WordPress users When I run `wp user get bob` Then STDOUT should not be empty - When I run `wp user delete bob --network` + When I run `wp user delete bob --network --yes` Then STDOUT should not be empty When I try `wp user get bob` @@ -101,7 +101,7 @@ Feature: Manage WordPress users 10 """ - When I try `wp user list --field=ID | xargs wp user delete invalid-user` + When I try `wp user list --field=ID | xargs wp user delete invalid-user --yes` And I run `wp user list --format=count` Then STDOUT should be: """ diff --git a/php/commands/user.php b/php/commands/user.php index 2ce568b26..68771013f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -121,6 +121,9 @@ public function get( $args, $assoc_args ) { * [--reassign=<user-id>] * : User ID to reassign the posts to. * + * [--yes] + * : Answer yes to any confirmation propmts. + * * ## EXAMPLES * * # Delete user 123 and reassign posts to user 567 @@ -134,6 +137,10 @@ public function delete( $args, $assoc_args ) { WP_CLI::error('Reassigning content to a different user is not supported on multisite.'); } + if ( !$reassign ) { + WP_CLI::confirm( '--reassign parameter not passed. All associated posts will be deleted. Proceed?', $assoc_args ); + } + $users = $this->fetcher->get_many( $args ); parent::_delete( $users, $assoc_args, function ( $user ) use ( $network, $reassign ) { From 1fa1a5cd2d2995577c7bbf6ca324ee044473ca51 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 18:15:04 +0300 Subject: [PATCH 2855/5359] allow defining --extra-php in wp-cli.yml --- features/config.feature | 25 ++++++++++++++++--------- php/commands/core.php | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/features/config.feature b/features/config.feature index b103ef73b..b8711ae2d 100644 --- a/features/config.feature +++ b/features/config.feature @@ -107,26 +107,33 @@ Feature: Have a config file command has been disabled """ - Scenario: Command-specific configs - Given a WP install + Scenario: 'core config' parameters + Given an empty directory + And WP files And a wp-cli.yml file: """ core config: dbname: wordpress dbuser: root + extra-php: | + define( 'WP_DEBUG', true ); + define( 'WP_POST_REVISIONS', 50 ); + """ + + When I run `wp core config --skip-check` + And I run `grep WP_POST_REVISIONS wp-config.php` + Then STDOUT should not be empty + + Scenario: Command-specific configs + Given a WP install + And a wp-cli.yml file: + """ eval: foo: bar post list: format: count """ - # Required parameters should be recognized - When I try `wp core config` - Then STDERR should not contain: - """ - Parameter errors - """ - # Arbitrary values should be passed, without warnings When I run `wp eval 'echo json_encode( $assoc_args );'` Then STDOUT should be JSON containing: diff --git a/php/commands/core.php b/php/commands/core.php index 2853b27ec..2f365e515 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -265,7 +265,7 @@ public function config( $_, $assoc_args ) { ) ); } - if ( isset( $assoc_args['extra-php'] ) ) { + if ( isset( $assoc_args['extra-php'] ) && $assoc_args['extra-php'] === true ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); } From 8d9acb3d59de16a5b547b5977d596eb47dc3e282 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 19:05:56 +0300 Subject: [PATCH 2856/5359] enable unfiltered HTML when an explicit user is not passed fixes #945 --- features/post.feature | 15 ++++++--------- php/WP_CLI/Runner.php | 14 +++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/features/post.feature b/features/post.feature index aaec9469b..e1993e1f1 100644 --- a/features/post.feature +++ b/features/post.feature @@ -31,7 +31,9 @@ Feature: Manage WordPress posts """ This is some content. - It will be inserted in a post. + <script> + alert('This should not be stripped.'); + </script> """ And a command.sh file: """ @@ -43,20 +45,15 @@ Feature: Manage WordPress posts Then STDOUT should be a number And save STDOUT as {POST_ID} - When I run `wp eval '$post_id = {POST_ID}; echo get_post( $post_id )->post_excerpt;'` + When I run `wp post get --field=excerpt {POST_ID}` Then STDOUT should be: """ A multiline excerpt """ - When I run `wp post get --field=content {POST_ID}` - Then STDOUT should be: - """ - This is some content. - - It will be inserted in a post. - """ + When I run `wp post get --field=content {POST_ID} | diff -Bu content.html -` + Then STDOUT should be empty When I run `wp post get --format=table {POST_ID}` Then STDOUT should be a table containing rows: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7a4cf0163..10db74c19 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -139,13 +139,13 @@ private static function set_wp_root( $path ) { } private static function set_user( $assoc_args ) { - if ( !isset( $assoc_args['user'] ) ) - return; - - $fetcher = new \WP_CLI\Fetchers\User; - $user = $fetcher->get_check( $assoc_args['user'] ); - wp_set_current_user( $user->ID ); - + if ( isset( $assoc_args['user'] ) ) { + $fetcher = new \WP_CLI\Fetchers\User; + $user = $fetcher->get_check( $assoc_args['user'] ); + wp_set_current_user( $user->ID ); + } else { + kses_remove_filters(); + } } private static function guess_url( $assoc_args ) { From fd5a95f208bb0fa9422a03cf40091e1a7704e481 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sun, 13 Apr 2014 20:06:28 +0300 Subject: [PATCH 2857/5359] bump version to 0.15-beta --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index cda6d57d2..a98ce59e3 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.15-alpha' ); +define( 'WP_CLI_VERSION', '0.15-beta' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 5206df754c8370d441a23a0fcc7071e45d1656e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 15 Apr 2014 18:32:15 +0300 Subject: [PATCH 2858/5359] bump version to 0.15.0 and update .mailmap --- .mailmap | 7 +++++++ php/wp-cli.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 0086f7198..001d93e0a 100644 --- a/.mailmap +++ b/.mailmap @@ -5,11 +5,13 @@ BoiteAWeb <juliobosk@gmail.com> boonebgorges <boonebgorges@gmail.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> +clemens-tolboom <clemens@build2be.com> conatus <alex@recordsonribs.com> ctayloroomphinc <ctaylor@thinkoomph.com> cyberhobo <dylan.k.kuhn@gmail.com> dangardner <dan@web.nearest.to> danielbachhuber <d@danielbachhuber.com> +danielbachhuber <daniel@handbuilt.co> danielbachhuber <danielbachhuber@gmail.com> dd32 <contact-atlassian@dd32.id.au> drrobotnik <B@Brandons-Mac-Pro-4.local> @@ -39,6 +41,7 @@ leewillis77 <leewillis77@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> +mattheu <matthew@matth.eu> mboynes <mboynes@alleyinteractive.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> @@ -53,14 +56,17 @@ nickdaugherty <ndaugherty987@gmail.com> nikolay <nikolay@users.noreply.github.com> nikolay <nikolaynkolev@gmail.com> nullvariable <nullvariable@gmail.com> +nyordanov <me@nyordanov.com> ocean90 <dominikschilling+git@gmail.com> oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> Rarst <contact@rarst.net> +robertboloc <robertboloc@gmail.com> rodrigoprimo <rodrigo@hacklab.com.br> roelven <roel@soundcloud.com> ryanduff <ryan@fusionized.com> +sboisvert <stephane.boisvert@automattic.com> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> sibprogrammer <ayuzhakov@parallels.com> @@ -70,6 +76,7 @@ SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> +szepeviktor <viktor@szepe.net> taupecat <tracy@taupecat.com> tddewey <td@tddewey.com> thisislawatts <luke@thisis.la> diff --git a/php/wp-cli.php b/php/wp-cli.php index a98ce59e3..f9615aded 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.15-beta' ); +define( 'WP_CLI_VERSION', '0.15.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From b56ef13961fde7ace574e79b26186d3d36a16482 Mon Sep 17 00:00:00 2001 From: jmslbam <jmslbam@gmail.com> Date: Thu, 17 Apr 2014 12:50:48 +0200 Subject: [PATCH 2859/5359] Use the WP _n instead of ngettext function --- php/commands/media.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index f6e0261a2..08770b097 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -50,7 +50,7 @@ function regenerate( $args, $assoc_args = array() ) { } WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, - ngettext( 'image', 'images', $count ) ) ); + _n( 'image', 'images', $count ) ) ); foreach ( $images->posts as $id ) { $this->_process_regeneration( $id ); @@ -58,7 +58,7 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::success( sprintf( 'Finished regenerating %1$s.', - ngettext('the image', 'all images', $count) + _n('the image', 'all images', $count) ) ); } From ce532edd6fa64b0febcf1da65b802497b2969dcc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 17 Apr 2014 06:37:03 -0700 Subject: [PATCH 2860/5359] Internalize remote assets used in behat tests This way, we aren't at the mercy of external services that go down. Except our own. --- features/media.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/media.feature b/features/media.feature index 0dca83a0c..ee77d30bc 100644 --- a/features/media.feature +++ b/features/media.feature @@ -11,10 +11,10 @@ Feature: Manage WordPress attachments """ Scenario: Import image from remote URL - When I run `wp media import 'http://s.wordpress.org/style/images/codeispoetry.png' --post_id=1` + When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ - Success: Imported file http://s.wordpress.org/style/images/codeispoetry.png + Success: Imported file http://wp-cli.org/behat-data/codeispoetry.png """ Scenario: Fail to import missing image @@ -26,8 +26,8 @@ Feature: Manage WordPress attachments Scenario: Import a file as attachment from a local image Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wordpresswallpaper.com/wp-content/gallery/photo-based-wallpaper/1058.jpg | + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` Then STDOUT should contain: From 4e8c7191c84233affe6fef25c642c765a5fadc9b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 17 Apr 2014 07:15:18 -0700 Subject: [PATCH 2861/5359] To prevent PHP error notices, also pass `version` in the update object Core began using the `version` attribute in the stats it reports back to WordPress.org: https://core.trac.wordpress.org/changeset/25863 When `--version` is explicitly passed, or we're performing an update, we can include the version data for stats purposes. When we're performing an update from a provided ZIP file, it's not worth it to try and parse the version from the provided zip file. --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2f365e515..ea3c8e3f4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -703,7 +703,7 @@ function update( $args, $assoc_args ) { } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) || isset( $assoc_args['force'] ) ) { - $new_package = null; + $new_package = $version = null; if ( empty( $args[0] ) ) { $version = $assoc_args['version']; @@ -727,6 +727,7 @@ function update( $args, $assoc_args ) { 'no_content' => null, 'full' => $new_package, ), + 'version' => $version, ); } else { From b6ae4202652a679271f3c5276c78a20b79faa3e1 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 17 Apr 2014 19:43:34 +0300 Subject: [PATCH 2862/5359] update list of maintainers [ci skip] --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cff45cfe7..35090ea9a 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ Besides the libraries defined in [composer.json](composer.json), we have used co Who's behind this thing? ------------------------ -We are [Andreas Creten](https://github.com/andreascreten) and [Cristi Burcă](https://github.com/scribu), friendly guys from Europe. For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). +* [Andreas Creten](https://github.com/andreascreten) - founder +* [Cristi Burcă](https://github.com/scribu) - previous maintainer +* [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer + +For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). From 32118f3a3f3e649247432f6f8fbdd2043a27a690 Mon Sep 17 00:00:00 2001 From: Ryan Duff <ryan@fusionized.com> Date: Thu, 17 Apr 2014 13:12:53 -0400 Subject: [PATCH 2863/5359] Wrap with quotes for ZSH support --- utils/wp-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index 682d53d9a..bc109024a 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -4,7 +4,7 @@ _wp_complete() { local cur=${COMP_WORDS[COMP_CWORD]} IFS=$'\n'; # want to preserve spaces at the end - local opts=( $(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT") ) + local opts="$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT")" if [[ $opts = "<file>" ]] then From c40f2386e137669b50d6f27b2303e8a43cca8d00 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 21 Apr 2014 16:47:46 +0100 Subject: [PATCH 2864/5359] Introduce `\WP_CLI\Utils\interval()` and `\WP_CLI\Utils\time_since()` functions for working with human-readable time intervals --- php/utils.php | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/php/utils.php b/php/utils.php index b918d1824..d17b3f387 100644 --- a/php/utils.php +++ b/php/utils.php @@ -402,3 +402,72 @@ function replace_path_consts( $source, $path ) { return str_replace( $old, $new, $source ); } +/** + * Convert a time interval into human-readable format. + * + * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. + * + * @param int $since An interval of time in seconds + * @return string The interval in human readable format + */ +function interval( $since ) { + if ( $since <= 0 ) { + return 'now'; + } + + $since = absint( $since ); + + // array of time period chunks + $chunks = array( + array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), + array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), + array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), + array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), + array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), + array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), + array( 1 , \_n_noop( '%s second', '%s seconds' ) ), + ); + + // we only want to output two chunks of time here, eg: + // x years, xx months + // x days, xx hours + // so there's only two bits of calculation below: + + // step one: the first chunk + for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { + $seconds = $chunks[$i][0]; + $name = $chunks[$i][1]; + + // finding the biggest chunk (if the chunk fits, break) + if ( ( $count = floor( $since / $seconds ) ) != 0 ){ + break; + } + } + + // set output var + $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); + + // step two: the second chunk + if ( $i + 1 < $j ) { + $seconds2 = $chunks[$i + 1][0]; + $name2 = $chunks[$i + 1][1]; + + if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { + // add to output var + $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); + } + } + + return $output; +} + +/** + * Returns a human-readable time difference between two times. + * + * @param int $older_date A Unix timestamp + * @param int $newer_date A Unix timestamp + * @return string The time difference in a human-readable format + */ +function time_since( $older_date, $newer_date ) { + return interval( $newer_date - $older_date ); +} From 7fb389b94cc8babfb467f1a20aea64dcabaab1b6 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 21 Apr 2014 16:49:36 +0100 Subject: [PATCH 2865/5359] First pass at initial `wp cron` commands. Available commands: * `wp cron event list` * `wp cron event run <hook>` * `wp cron event delete <hook>` * `wp cron schedule list` * `wp cron test` --- php/commands/cron.php | 336 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 php/commands/cron.php diff --git a/php/commands/cron.php b/php/commands/cron.php new file mode 100644 index 000000000..987f25ba5 --- /dev/null +++ b/php/commands/cron.php @@ -0,0 +1,336 @@ +<?php + +/** + * Manage WP-Cron events. + * + * @package wp-cli + */ +class Cron_Event_Command extends WP_CLI_Command { + + /** + * List scheduled cron events. + * + * @subcommand list + * @synopsis [--format=<format>] + */ + public function _list( $args, $assoc_args ) { + + $values = array_merge( array( + 'format' => 'table', + ), $assoc_args ); + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + WP_CLI::line( WP_CLI::error_to_string( $events ) ); + exit; + } + + $fields = array( + 'hook', + 'next_run', + 'next_run_gmt', + 'next_run_relative', + 'recurrence', + ); + + \WP_CLI\Utils\format_items( $values['format'], $events, $fields ); + + } + + /** + * Run the next scheduled cron event for the given hook. + * + * ## OPTIONS + * + * <hook> + * : The hook name + * + * @synopsis <hook> + */ + public function run( $args, $assoc_args ) { + + $hook = $args[0]; + $result = false; + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + WP_CLI::error( $events ); + } + + foreach ( $events as $id => $event ) { + if ( $event->hook == $hook ) { + $result = self::run_event( $event ); + break; + } + } + + if ( $result ) { + WP_CLI::success( sprintf( "Successfully executed the cron event '%s'", $hook ) ); + } else { + WP_CLI::error( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); + } + + } + + /** + * Executes an event immediately by scheduling a new single event with the same arguments. + * + * @param stdClass $event The event + * @return bool Whether the event was successfully executed or not. + */ + protected static function run_event( stdClass $event ) { + + delete_transient( 'doing_cron' ); + $scheduled = wp_schedule_single_event( time()-1, $event->hook, $event->args ); + + if ( false === $scheduled ) { + return false; + } + + spawn_cron(); + + return true; + + } + + /** + * Delete the next scheduled cron event for the given hook. + * + * ## OPTIONS + * + * <hook> + * : The hook name + * + * @synopsis <hook> + */ + public function delete( $args, $assoc_args ) { + + $hook = $args[0]; + $result = false; + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + WP_CLI::error( $events ); + } + + foreach ( $events as $id => $event ) { + if ( $event->hook == $hook ) { + $result = self::delete_event( $event ); + break; + } + } + + if ( $result ) { + WP_CLI::success( sprintf( "Successfully deleted the cron event '%s'", $hook ) ); + } else { + WP_CLI::error( sprintf( "Failed to the delete the cron event '%s'", $hook ) ); + } + + } + + /** + * Deletes a cron event. + * + * @param stdClass $event The event + * @return bool Whether the event was successfully deleted or not. + */ + protected static function delete_event( stdClass $event ) { + $crons = _get_cron_array(); + + if ( ! isset( $crons[$event->time][$event->hook][$event->sig] ) ) { + return false; + } + + wp_unschedule_event( $event->time, $event->hook, $event->args ); + return true; + } + + /** + * Callback function to format a cron event. + * + * @param stdClass $event The event. + * @return stdClass The formatted event object. + */ + protected static function format_event( stdClass $event ) { + $time_format = 'Y-m-d H:i:s'; + + $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), $time_format ); + $event->next_run_gmt = date( $time_format, $event->time ); + $event->next_run_relative = \WP_CLI\Utils\time_since( time(), $event->time ); + $event->recurrence = ( $event->schedule ) ? \WP_CLI\Utils\interval( $event->interval ) : 'Non-repeating'; + + return $event; + } + + /** + * Fetch an array of scheduled cron events. + * + * @return array|WP_Error An array of event objects, or a WP_Error object if there are no events scheduled. + */ + protected static function get_cron_events() { + + $crons = _get_cron_array(); + $events = array(); + + if ( empty( $crons ) ) { + return new WP_Error( + 'no_events', + 'You currently have no scheduled cron events.' + ); + } + + // @TODO rename these vars a bit more better nicely nicer: + foreach ( $crons as $time => $cron ) { + foreach ( $cron as $hook => $dings ) { + foreach ( $dings as $sig => $data ) { + + $events["$hook-$sig"] = (object) array( + 'hook' => $hook, + 'time' => $time, + 'sig' => $sig, + 'args' => $data['args'], + 'schedule' => $data['schedule'], + 'interval' => isset( $data['interval'] ) ? $data['interval'] : null, + ); + + } + } + } + + $events = array_map( 'Cron_Event_Command::format_event', $events ); + + return $events; + + } + +} + +/** + * Manage WP-Cron schedules. + */ +class Cron_Schedule_Command extends WP_CLI_Command { + + /** + * List available cron schedules. + * + * @subcommand list + * @synopsis [--format=<format>] + */ + public function _list( $args, $assoc_args ) { + + $values = array_merge( array( + 'format' => 'table', + ), $assoc_args ); + + $schedules = self::get_schedules(); + + $fields = array( + 'name', + 'display', + 'interval', + ); + + \WP_CLI\Utils\format_items( $values['format'], $schedules, $fields ); + + } + + /** + * Callback function to format a cron schedule. + * + * @param array $schedule The schedule. + * @param string $name The schedule name. + * @return array The formatted schedule. + */ + protected static function format_schedule( array $schedule, $name ) { + $schedule['name'] = $name; + return $schedule; + } + + /** + * Return a list of the cron schedules sorted according to interval. + * + * @return array The array of cron schedules. Each schedule is itself an array. + */ + protected static function get_schedules() { + $schedules = wp_get_schedules(); + if ( !empty( $schedules ) ) { + uasort( $schedules, 'Cron_Schedule_Command::sort' ); + $schedules = array_map( 'Cron_Schedule_Command::format_schedule', $schedules, array_keys( $schedules ) ); + } + return $schedules; + } + + /** + * Callback function to sort the cron schedule array by interval. + * + */ + protected static function sort( array $a, array $b ) { + return $a['interval'] - $b['interval']; + } + +} + +/** + * Manage WP-Cron events and schedules. + */ +class Cron_Command extends WP_CLI_Command { + + /** + * Test the WP Cron spawning system and report back any errors. + */ + public function test() { + + $status = self::test_cron_spawn(); + + if ( is_wp_error( $status ) ) { + WP_CLI::error( $status ); + } else { + WP_CLI::success( 'WP-Cron is working as expected.' ); + } + + } + + /** + * Gets the status of WP-Cron functionality on the site by performing a test spawn. + * + * This function is designed to mimic the functionality in `spawn_cron()` with the addition of checking + * the return value of the call to `wp_remote_post()`. + * + * @return bool|WP_Error Boolean true if the cron spawn test is successful, WP_Error object if not. + */ + protected static function test_cron_spawn() { + + if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { + return true; + } + + $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); + + $cron_request = apply_filters( 'cron_request', array( + 'url' => site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron ), + 'key' => $doing_wp_cron, + 'args' => array( + 'timeout' => 3, + 'blocking' => true, + 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) + ) + ) ); + + # Enforce a blocking request in case something that's hooked onto the 'cron_request' filter sets it to false + $cron_request['args']['blocking'] = true; + + $result = wp_remote_post( $cron_request['url'], $cron_request['args'] ); + + if ( is_wp_error( $result ) ) { + return $result; + } else { + return true; + } + + } + +} + +WP_CLI::add_command( 'cron', 'Cron_Command' ); +WP_CLI::add_command( 'cron event', 'Cron_Event_Command' ); +WP_CLI::add_command( 'cron schedule', 'Cron_Schedule_Command' ); From e5089a44df3f8f8610a8f615c5d0558a9fbf5b7c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 21 Apr 2014 16:48:29 -0700 Subject: [PATCH 2866/5359] Throw an error if plugin(s) / theme(s) aren't specified for update `wp plugin update` and `wp theme update` both require either passed plugin(s) / theme(s), or an `--all` argument. Our synopsis parser isn't smart enough to require one argument or another, so this will be the catch-all instead. --- features/plugin.feature | 9 +++++++++ features/theme.feature | 9 +++++++++ php/WP_CLI/CommandWithUpgrade.php | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index dcad44778..a683999dd 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -108,6 +108,15 @@ Feature: Manage WordPress plugins | name | status | update | version | | akismet | active | available | 2.5.6 | + When I try `wp plugin update` + Then STDERR should be: + """ + Error: Please specify one or more plugins, or use --all. + """ + + When I run `wp plugin update --all` + Then STDOUT should not be empty + Scenario: Activate a network-only plugin Given a WP multisite install And a wp-content/plugins/network-only.php file: diff --git a/features/theme.feature b/features/theme.feature index 98153957f..76ef76a82 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -72,6 +72,15 @@ Feature: Manage WordPress themes | name | status | update | version | | p2 | active | available | 1.4.1 | + When I try `wp theme update` + Then STDERR should be: + """ + Error: Please specify one or more themes, or use --all. + """ + + When I run `wp theme update --all` + Then STDOUT should not be empty + Scenario: Get the path of an installed theme Given a WP install diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 5aa067c2c..1bbe9ae56 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -199,6 +199,10 @@ protected function get_upgrader( $assoc_args ) { protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); + if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + \WP_CLI::error( "Please specify one or more {$this->item_type}s, or use --all." ); + } + $items = $this->get_item_list(); if ( !isset( $assoc_args['all'] ) ) { From a4d947a9da4c7fb2de05680d17c08b40746ae1ce Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 21 Apr 2014 19:21:35 -0700 Subject: [PATCH 2867/5359] If the sidebar doesn't exist yet, `array_slice()` will fail on a null value --- php/commands/widget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 00ca77231..b3ff2c879 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -437,7 +437,7 @@ private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_side } if ( $needs_placement ) { - $widgets = $all_widgets[ $new_sidebar_id ]; + $widgets = ! empty( $all_widgets[ $new_sidebar_id ] ) ? $all_widgets[ $new_sidebar_id ] : array(); $before = array_slice( $widgets, 0, $new_index, true ); $after = array_slice( $widgets, $new_index, count( $widgets ), true ); $widgets = array_merge( $before, array( $widget_id ), $after ); From 46f9b87b865825806d4d1f4c611773ad3199b443 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 23 Apr 2014 14:47:42 -0700 Subject: [PATCH 2868/5359] Suppress errors when using a Widget's `update()` callback Each widget can expect arbitrary array keys, and it's not possible to know what those array keys might be without processing `form()`. This is much easier for our purposes. --- php/commands/widget.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index b3ff2c879..5a5ec7a05 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -480,7 +480,9 @@ private function sanitize_widget_options( $id_base, $dirty_options, $old_options return array(); } - return $widget->update( $dirty_options, $old_options ); + // No easy way to determine expected array keys for $dirty_options + // because Widget API dependent on the form fields + return @$widget->update( $dirty_options, $old_options ); } From 32b70759aa3e97417fb3b0aec423876ee9aefcb0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 23 Apr 2014 17:46:33 -0700 Subject: [PATCH 2869/5359] Make regenerating rewrite rules more user-friendly * Throw a warning if the user is trying to regenerate `.htaccess` without the special declaration. * Add directions on how to resolve the problem in the usage docs for each relevant command. --- php/commands/rewrite.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 3f33c1c92..8b380afbd 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -10,6 +10,16 @@ class Rewrite_Command extends WP_CLI_Command { /** * Flush rewrite rules. * + * ## DESCRIPTION + * + * Resets WordPress' rewrite rules based on registered post types, etc. + * + * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module + * to your wp-cli.yml or config.yml. For example: + * + * apache_modules: + * - mod_rewrite + * * ## OPTIONS * * [--hard] @@ -18,12 +28,25 @@ class Rewrite_Command extends WP_CLI_Command { public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); + if ( isset( $assoc_args['hard'] ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { + WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); + } flush_rewrite_rules( isset( $assoc_args['hard'] ) ); } /** * Update the permalink structure. * + * ## DESCRIPTION + * + * Updates the post permalink structure. + * + * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module + * to your wp-cli.yml or config.yml. For example: + * + * apache_modules: + * - mod_rewrite + * * ## OPTIONS * * <permastruct> @@ -89,8 +112,13 @@ public function structure( $args, $assoc_args ) { // Launch a new process to flush rewrites because core expects flush // to happen after rewrites are set $new_assoc_args = array(); - if ( isset( $assoc_args['hard'] ) ) + if ( isset( $assoc_args['hard'] ) ) { $new_assoc_args['hard'] = true; + if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { + WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); + } + } + \WP_CLI::launch_self( 'rewrite flush', array(), $new_assoc_args ); WP_CLI::success( "Rewrite structure set." ); From 9fae0ab780349b7471e2423c30ff2a564755ece0 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 16:58:50 +0100 Subject: [PATCH 2870/5359] Docblock updates --- php/commands/cron.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 987f25ba5..cdf15eab5 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -3,15 +3,18 @@ /** * Manage WP-Cron events. * - * @package wp-cli */ class Cron_Event_Command extends WP_CLI_Command { /** * List scheduled cron events. * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to all of the cron event fields. + * * @subcommand list - * @synopsis [--format=<format>] */ public function _list( $args, $assoc_args ) { @@ -213,8 +216,12 @@ class Cron_Schedule_Command extends WP_CLI_Command { /** * List available cron schedules. * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to all of the cron schedule fields. + * * @subcommand list - * @synopsis [--format=<format>] */ public function _list( $args, $assoc_args ) { From d523a82f83fd5a318655b2899cfb840a5d5f18bb Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 17:02:09 +0100 Subject: [PATCH 2871/5359] Switch from `\WP_CLI\Utils\format_items()` to the newer `\WP_CLI\Formatter->display_items()` method. --- php/commands/cron.php | 58 ++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index cdf15eab5..6e24a5b6e 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -6,6 +6,15 @@ */ class Cron_Event_Command extends WP_CLI_Command { + private $fields = array( + 'hook', + 'next_run', + 'next_run_gmt', + 'next_run_relative', + 'next_run_diff', + 'recurrence', + ); + /** * List scheduled cron events. * @@ -17,10 +26,8 @@ class Cron_Event_Command extends WP_CLI_Command { * @subcommand list */ public function _list( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); - $values = array_merge( array( - 'format' => 'table', - ), $assoc_args ); $events = self::get_cron_events(); if ( is_wp_error( $events ) ) { @@ -28,15 +35,11 @@ public function _list( $args, $assoc_args ) { exit; } - $fields = array( - 'hook', - 'next_run', - 'next_run_gmt', - 'next_run_relative', - 'recurrence', - ); - - \WP_CLI\Utils\format_items( $values['format'], $events, $fields ); + if ( 'ids' == $formatter->format ) { + echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); + } else { + $formatter->display_items( $events ); + } } @@ -206,6 +209,10 @@ protected static function get_cron_events() { } + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'event' ); + } + } /** @@ -213,6 +220,12 @@ protected static function get_cron_events() { */ class Cron_Schedule_Command extends WP_CLI_Command { + private $fields = array( + 'name', + 'display', + 'interval', + ); + /** * List available cron schedules. * @@ -224,20 +237,15 @@ class Cron_Schedule_Command extends WP_CLI_Command { * @subcommand list */ public function _list( $args, $assoc_args ) { - - $values = array_merge( array( - 'format' => 'table', - ), $assoc_args ); + $formatter = $this->get_formatter( $assoc_args ); $schedules = self::get_schedules(); - $fields = array( - 'name', - 'display', - 'interval', - ); - - \WP_CLI\Utils\format_items( $values['format'], $schedules, $fields ); + if ( 'ids' == $formatter->format ) { + echo implode( ' ', wp_list_pluck( $schedules, 'name' ) ); + } else { + $formatter->display_items( $schedules ); + } } @@ -275,6 +283,10 @@ protected static function sort( array $a, array $b ) { return $a['interval'] - $b['interval']; } + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'schedule' ); + } + } /** From 6073535a202adf90c91c4404c9f65039a7fb5742 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 17:02:56 +0100 Subject: [PATCH 2872/5359] Output an empty table instead of a message when there are no cron events on the site --- php/commands/cron.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 6e24a5b6e..747a58158 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -31,8 +31,7 @@ public function _list( $args, $assoc_args ) { $events = self::get_cron_events(); if ( is_wp_error( $events ) ) { - WP_CLI::line( WP_CLI::error_to_string( $events ) ); - exit; + $events = array(); } if ( 'ids' == $formatter->format ) { From 5d84bffd6b46ddd19d1084266599f10f2d4904fd Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 17:03:42 +0100 Subject: [PATCH 2873/5359] Remove some test code --- php/commands/cron.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 747a58158..67693d65c 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -11,7 +11,6 @@ class Cron_Event_Command extends WP_CLI_Command { 'next_run', 'next_run_gmt', 'next_run_relative', - 'next_run_diff', 'recurrence', ); From b2d474909cc2ad5d3f0a75dd2d80a33a32eade2a Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 17:03:57 +0100 Subject: [PATCH 2874/5359] Correct indentation --- php/utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index d17b3f387..393c06ee2 100644 --- a/php/utils.php +++ b/php/utils.php @@ -412,7 +412,7 @@ function replace_path_consts( $source, $path ) { */ function interval( $since ) { if ( $since <= 0 ) { - return 'now'; + return 'now'; } $since = absint( $since ); @@ -469,5 +469,5 @@ function interval( $since ) { * @return string The time difference in a human-readable format */ function time_since( $older_date, $newer_date ) { - return interval( $newer_date - $older_date ); + return interval( $newer_date - $older_date ); } From d01050b0bce02d8d24571cbbabe85470ae293610 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 24 Apr 2014 10:08:18 -0700 Subject: [PATCH 2875/5359] When scaffolding a theme or plugin, create the `themes` or `plugins` directory if it doesn't exist For developers who use the scaffolding commands on brand new projects, this can save a moment of d'oh. --- php/commands/scaffold.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 26ee0064a..fff531796 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -212,6 +212,8 @@ function _s( $args, $assoc_args ) { WP_CLI::error( "Couldn't create theme (received $response_code response)." ); } + $this->maybe_create_themes_dir(); + unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -265,6 +267,8 @@ function child_theme( $args, $assoc_args ) { $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; + $this->maybe_create_themes_dir(); + $this->create_file( $theme_style_path, Utils\mustache_render( 'child_theme.mustache', $data ) ); WP_CLI::success( "Created $theme_dir" ); @@ -324,6 +328,8 @@ function plugin( $args, $assoc_args ) { $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; $plugin_path = "$plugin_dir/$plugin_slug.php"; + $this->maybe_create_plugins_dir(); + $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); WP_CLI::success( "Created $plugin_dir" ); @@ -491,6 +497,30 @@ protected function extract_args( $assoc_args, $defaults ) { protected function quote_comma_list_elements( $comma_list ) { return "'" . implode( "', '", explode( ',', $comma_list ) ) . "'"; } + + /** + * Create the themes directory if it doesn't already exist + */ + protected function maybe_create_themes_dir() { + + $themes_dir = WP_CONTENT_DIR . '/themes'; + if ( ! is_dir( $themes_dir ) ) { + wp_mkdir_p( $themes_dir ); + } + + } + + /** + * Create the plugins directory if it doesn't already exist + */ + protected function maybe_create_plugins_dir() { + + if ( ! is_dir( WP_PLUGIN_DIR ) ) { + wp_mkdir_p( WP_PLUGIN_DIR ); + } + + } + } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); From 36c55889cb984983386e0365f45583d61d7a97fd Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 21:16:52 +0100 Subject: [PATCH 2876/5359] Important bugfix --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 69431b33b..0d1d011cf 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,4 +1,4 @@ -Feature: Wordpress code scaffolding +Feature: WordPress code scaffolding Background: Given a WP install From 60327a7e70fe3a4e90094d339851e49fc88ed9d2 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 21:46:11 +0100 Subject: [PATCH 2877/5359] Rename `_list()` methods to `list_()` --- php/commands/cron.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 67693d65c..c2104db0b 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -24,7 +24,7 @@ class Cron_Event_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); $events = self::get_cron_events(); @@ -234,7 +234,7 @@ class Cron_Schedule_Command extends WP_CLI_Command { * * @subcommand list */ - public function _list( $args, $assoc_args ) { + public function list_( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); $schedules = self::get_schedules(); From c26ad22ff5dbfeba5189419f440b35db5c8ff1c9 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 23:29:00 +0100 Subject: [PATCH 2878/5359] Make `$time_format` a property on the `Cron_Event_Command` class --- php/commands/cron.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index c2104db0b..fba436472 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -13,6 +13,7 @@ class Cron_Event_Command extends WP_CLI_Command { 'next_run_relative', 'recurrence', ); + private static $time_format = 'Y-m-d H:i:s'; /** * List scheduled cron events. @@ -156,10 +157,9 @@ protected static function delete_event( stdClass $event ) { * @return stdClass The formatted event object. */ protected static function format_event( stdClass $event ) { - $time_format = 'Y-m-d H:i:s'; - $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), $time_format ); - $event->next_run_gmt = date( $time_format, $event->time ); + $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), self::$time_format ); + $event->next_run_gmt = date( self::$time_format, $event->time ); $event->next_run_relative = \WP_CLI\Utils\time_since( time(), $event->time ); $event->recurrence = ( $event->schedule ) ? \WP_CLI\Utils\interval( $event->interval ) : 'Non-repeating'; From 75e033048a3e96a8b41ebc0ae70850c6f7c276b4 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 23:29:34 +0100 Subject: [PATCH 2879/5359] Introduce `wp cron event schedule` for scheduling new events --- php/commands/cron.php | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index fba436472..206094e6e 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -42,6 +42,76 @@ public function list_( $args, $assoc_args ) { } + /** + * Schedule a new cron event. + * + * ## OPTIONS + * + * <hook> + * : The hook name + * + * [--next_run=<value>] + * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. + * + * [--recurrence=<value>] + * : How often the event should recur. See `wp cron schedule list` for available schedule names. Defaults to no recurrence. + * + * [--<field>=<value>] + * : Associative args for the event. + * + * ## EXAMPLES + * + * wp cron event schedule cron_test + * + * wp cron event schedule cron_test --next_run='+1 hour' --recurrence=hourly + * + * wp cron event schedule cron_test --recurrence=daily --foo=1 --bar=2 + */ + public function schedule( $args, $assoc_args ) { + + list( $hook ) = $args; + + if ( !isset( $assoc_args['next_run'] ) ) { + $timestamp = time(); + } else if ( is_numeric( $assoc_args['next_run'] ) ) { + $timestamp = absint( $assoc_args['next_run'] ); + } else { + $timestamp = strtotime( $assoc_args['next_run'] ); + } + + if ( ! $timestamp ) { + WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $assoc_args['next_run'] ) ); + } + + $event_args = array_diff_key( $assoc_args, array_flip( array( + 'next_run', 'recurrence' + ) ) ); + + if ( isset( $assoc_args['recurrence'] ) ) { + + $recurrence = $assoc_args['recurrence']; + $schedules = wp_get_schedules(); + + if ( ! isset( $schedules[$recurrence] ) ) { + WP_CLI::error( sprintf( "'%s' is not a valid schedule name for recurrence.", $recurrence ) ); + } + + $event = wp_schedule_event( $timestamp, $recurrence, $hook, $event_args ); + + } else { + + $event = wp_schedule_single_event( $timestamp, $hook, $event_args ); + + } + + if ( false !== $event ) { + WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s.", $hook, date( self::$time_format, $timestamp ) ) ); + } else { + WP_CLI::error( 'Event not scheduled' ); + } + + } + /** * Run the next scheduled cron event for the given hook. * From 494ff810e83bdeff1e2aebf6905d926faf72fb59 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 24 Apr 2014 23:30:04 +0100 Subject: [PATCH 2880/5359] Remove `next_run` from the default list of event fields for now --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 206094e6e..02e69c858 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -8,7 +8,7 @@ class Cron_Event_Command extends WP_CLI_Command { private $fields = array( 'hook', - 'next_run', + // 'next_run', 'next_run_gmt', 'next_run_relative', 'recurrence', From c45cc9ea0c90be2582beba8aa30f9033138afd50 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 25 Apr 2014 00:48:20 +0100 Subject: [PATCH 2881/5359] Add the `--format` argument to our `list` commands --- php/commands/cron.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index 02e69c858..4e342365d 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -23,6 +23,9 @@ class Cron_Event_Command extends WP_CLI_Command { * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to all of the cron event fields. * + * [--format=<format>] + * : Accepted values: table, json, csv, ids. Default: table. + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -302,6 +305,9 @@ class Cron_Schedule_Command extends WP_CLI_Command { * [--fields=<fields>] * : Limit the output to specific object fields. Defaults to all of the cron schedule fields. * + * [--format=<format>] + * : Accepted values: table, json, csv, ids. Default: table. + * * @subcommand list */ public function list_( $args, $assoc_args ) { From 080cd8cb534c2bba45e7f02952b60e097064e15c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 09:57:09 -0700 Subject: [PATCH 2882/5359] Fuller PHPdoc coverage for `WP_CLI\Dispatcher\Subcommand` --- php/WP_CLI/Dispatcher/Subcommand.php | 67 ++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index c3e0d3bad..673bc99f3 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -4,6 +4,8 @@ /** * A leaf node in the command tree. + * + * @package WP_CLI */ class Subcommand extends CompositeCommand { @@ -24,24 +26,43 @@ function __construct( $parent, $name, $docparser, $when_invoked ) { } } + /** + * Extract the synopsis from PHPdoc string. + * + * @param string $longdesc Command docs via PHPdoc + * @return string + */ private static function extract_synopsis( $longdesc ) { preg_match_all( '/(.+?)[\r\n]+:/', $longdesc, $matches ); return implode( ' ', $matches[1] ); } + /** + * Subcommands can't have subcommands because they + * represent code to be executed. + * + * @return bool + */ function can_have_subcommands() { return false; } + /** + * Get the synopsis string for this subcommand. + * A synopsis defines what runtime arguments are + * expected, useful to humans and argument validation. + * + * @return string + */ function get_synopsis() { return $this->synopsis; } /** - * If an alias is set, grant access to it + * If an alias is set, grant access to it. * Aliases permit subcommands to be instantiated - * with a secondary identity - * + * with a secondary identity. + * * @return string */ function get_alias() { @@ -49,8 +70,8 @@ function get_alias() { } /** - * Print the usage details to the end user - * + * Print the usage details to the end user. + * * @param string $prefix */ function show_usage( $prefix = 'usage: ' ) { @@ -58,8 +79,8 @@ function show_usage( $prefix = 'usage: ' ) { } /** - * Get the usage of the subcommand as a formatted string - * + * Get the usage of the subcommand as a formatted string. + * * @param string $prefix * @return string */ @@ -71,6 +92,13 @@ function get_usage( $prefix ) { ); } + /** + * Wrapper for CLI Tools' prompt() method. + * + * @param string $question + * @param string $default + * @return string|false + */ private function prompt( $question, $default ) { try { @@ -83,6 +111,14 @@ private function prompt( $question, $default ) { return $response; } + /** + * Interactively prompt the user for input + * based on defined synopsis and passed arguments. + * + * @param array $args + * @param array $assoc_args + * @return array + */ private function prompt_args( $args, $assoc_args ) { $synopsis = $this->get_synopsis(); @@ -173,6 +209,13 @@ private function prompt_args( $args, $assoc_args ) { } /** + * Validate the supplied arguments to the command. + * Throws warnings or errors if arguments are missing + * or invalid. + * + * @param array $args + * @param array $assoc_args + * @param array $extra_args * @return array list of invalid $assoc_args keys to unset */ private function validate_args( $args, $assoc_args, $extra_args ) { @@ -223,7 +266,15 @@ private function validate_args( $args, $assoc_args, $extra_args ) { return $to_unset; } - function invoke( $args, $assoc_args, $extra_args ) { + /** + * Invoke the subcommand with the supplied arguments. + * Given a --prompt argument, interactively request input + * from the end user. + * + * @param array $args + * @param array $assoc_args + */ + public function invoke( $args, $assoc_args, $extra_args ) { if ( \WP_CLI::get_config( 'prompt' ) ) list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); From 5647c4afd2ef8915b6cc9010e0aabdfb773f4aec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 09:58:59 -0700 Subject: [PATCH 2883/5359] Document `WP_CLI\Dispatcher\get_path()` --- php/dispatcher.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/dispatcher.php b/php/dispatcher.php index 8157d21b6..bd11a3927 100644 --- a/php/dispatcher.php +++ b/php/dispatcher.php @@ -2,6 +2,12 @@ namespace WP_CLI\Dispatcher; +/** + * Get the path to a command, e.g. "core download" + * + * @param WP_CLI\Dispatcher\Subcommand $command + * @return string + */ function get_path( $command ) { $path = array(); From 88bb66d0cf82b0216aed0d4c205f8e1cf9e54db9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 10:17:31 -0700 Subject: [PATCH 2884/5359] PHPdoc and explicit method definitions for `WP_CLI\Dispatcher\RootCommand` --- php/WP_CLI/Dispatcher/RootCommand.php | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index 853cfa197..d5c19826b 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -6,10 +6,12 @@ /** * The root node in the command tree. + * + * @package WP_CLI */ class RootCommand extends CompositeCommand { - function __construct() { + public function __construct() { $this->parent = false; $this->name = 'wp'; @@ -17,7 +19,12 @@ function __construct() { $this->shortdesc = 'Manage WordPress through the command-line.'; } - function get_longdesc() { + /** + * Get the human-readable long description. + * + * @return string + */ + public function get_longdesc() { $binding = array(); foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { @@ -44,7 +51,14 @@ function get_longdesc() { return Utils\mustache_render( 'man-params.mustache', $binding ); } - function find_subcommand( &$args ) { + /** + * Find a subcommand registered on the root + * command. + * + * @param array $args + * @return \WP_CLI\Dispatcher\Subcommand|false + */ + public function find_subcommand( &$args ) { $command = array_shift( $args ); Utils\load_command( $command ); @@ -56,7 +70,12 @@ function find_subcommand( &$args ) { return $this->subcommands[ $command ]; } - function get_subcommands() { + /** + * Get all registered subcommands. + * + * @return array + */ + public function get_subcommands() { Utils\load_all_commands(); return parent::get_subcommands(); From eb9ddf0ec7b25cdc1fe7891c90f12248a41e11e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 10:39:50 -0700 Subject: [PATCH 2885/5359] PHPdoc coverage for `\WP_CLI\Dispatcher\CompositeCommand` --- php/WP_CLI/Dispatcher/CompositeCommand.php | 120 ++++++++++++++++++--- 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 6f7778969..30e6e0038 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -4,6 +4,9 @@ /** * A non-leaf node in the command tree. + * Contains one or more Subcommands. + * + * @package WP_CLI */ class CompositeCommand { @@ -11,6 +14,13 @@ class CompositeCommand { protected $parent, $subcommands = array(); + /** + * Instantiate a new CompositeCommand + * + * @param mixed $parent Parent command (either Root or Composite) + * @param string $name Represents how command should be invoked + * @param \WP_CLI\DocParser + */ public function __construct( $parent, $name, $docparser ) { $this->parent = $parent; @@ -25,41 +35,94 @@ public function __construct( $parent, $name, $docparser ) { } } - function get_parent() { + /** + * Get the parent composite (or root) command + * + * @return mixed + */ + public function get_parent() { return $this->parent; } - function add_subcommand( $name, $command ) { + /** + * Add a named subcommand to this composite command's + * set of contained subcommands. + * + * @param string $name Represents how subcommand should be invoked + * @param \WP_CLI\Dispatcher\Subcommand + */ + public function add_subcommand( $name, $command ) { $this->subcommands[ $name ] = $command; } - function can_have_subcommands() { + /** + * Composite commands always contain subcommands. + * + * @return true + */ + public function can_have_subcommands() { return true; } - function get_subcommands() { + /** + * Get the subcommands contained by this composite + * command. + * + * @return array + */ + public function get_subcommands() { ksort( $this->subcommands ); return $this->subcommands; } - function get_name() { + /** + * Get the name of this composite command. + * + * @return string + */ + public function get_name() { return $this->name; } - function get_shortdesc() { + /** + * Get the short description for this composite + * command. + * + * @return string + */ + public function get_shortdesc() { return $this->shortdesc; } - function get_longdesc() { + /** + * Get the long description for this composite + * command. + * + * @return string + */ + public function get_longdesc() { return $this->longdesc; } - function get_synopsis() { + /** + * Get the synopsis for this composite command. + * As a collection of subcommands, the composite + * command is only intended to invoke those + * subcommands. + * + * @return string + */ + public function get_synopsis() { return '<command>'; } - function get_usage( $prefix ) { + /** + * Get the usage for this composite command. + * + * @return string + */ + public function get_usage( $prefix ) { return sprintf( "%s%s %s", $prefix, implode( ' ', get_path( $this ) ), @@ -67,7 +130,11 @@ function get_usage( $prefix ) { ); } - function show_usage() { + /** + * Show the usage for all subcommands contained + * by the composite command. + */ + public function show_usage() { $methods = $this->get_subcommands(); $i = 0; @@ -84,11 +151,26 @@ function show_usage() { \WP_CLI::line( "See 'wp help $cmd_name <command>' for more information on a specific command." ); } - function invoke( $args, $assoc_args, $extra_args ) { + /** + * When a composite command is invoked, it shows usage + * docs for its subcommands. + * + * @param array $args + * @param array $assoc_args + * @param array $extra_args + */ + public function invoke( $args, $assoc_args, $extra_args ) { $this->show_usage(); } - function find_subcommand( &$args ) { + /** + * Given supplied arguments, find a contained + * subcommand + * + * @param array $args + * @return \WP_CLI\Dispatcher\Subcommand|false + */ + public function find_subcommand( &$args ) { $name = array_shift( $args ); $subcommands = $this->get_subcommands(); @@ -107,6 +189,13 @@ function find_subcommand( &$args ) { return $subcommands[ $name ]; } + /** + * Get any registered aliases for this composite command's + * subcommands. + * + * @param array $subcommands + * @return array + */ private static function get_aliases( $subcommands ) { $aliases = array(); @@ -119,7 +208,12 @@ private static function get_aliases( $subcommands ) { return $aliases; } - function get_alias() { + /** + * Composite commands can only be known by one name. + * + * @return false + */ + public function get_alias() { return false; } } From 7f75f8d6e8d1a32548711396b36e53c54816c926 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 10:49:10 -0700 Subject: [PATCH 2886/5359] PHPdoc for `\WP_CLI\Dispatcher\CommandFactory` --- php/WP_CLI/Dispatcher/CommandFactory.php | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index 4e7a0aae1..2bc884e01 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -4,9 +4,18 @@ /** * Creates CompositeCommand or Subcommand instances. + * + * @package WP_CLI */ class CommandFactory { + /** + * Create a new CompositeCommand (or Subcommand if class has __invoke()) + * + * @param string $name Represents how the command should be invoked + * @param string $class A subclass of WP_CLI_Command + * @param mixed $parent The new command's parent Composite (or Root) command + */ public static function create( $name, $class, $parent ) { $reflection = new \ReflectionClass( $class ); @@ -20,6 +29,14 @@ public static function create( $name, $class, $parent ) { return $command; } + /** + * Create a new Subcommand instance. + * + * @param mixed $parent The new command's parent Composite command + * @param string $name Represents how the command should be invoked + * @param string $class A subclass of WP_CLI_Command + * @param string $method Class method to be called upon invocation. + */ private static function create_subcommand( $parent, $name, $class_name, $method ) { $docparser = new \WP_CLI\DocParser( $method->getDocComment() ); @@ -38,6 +55,13 @@ private static function create_subcommand( $parent, $name, $class_name, $method return new Subcommand( $parent, $name, $docparser, $when_invoked ); } + /** + * Create a new Composite command instance. + * + * @param mixed $parent The new command's parent Root or Composite command + * @param string $name Represents how the command should be invoked + * @param ReflectionClass $reflection + */ private static function create_composite_command( $parent, $name, $reflection ) { $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); @@ -57,6 +81,12 @@ private static function create_composite_command( $parent, $name, $reflection ) return $container; } + /** + * Check whether a method is actually callable. + * + * @param ReflectionMethod $method + * @return bool + */ private static function is_good_method( $method ) { return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); } From beb7b4cef8b61f35bb9b98c417ada045b63a3230 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 10:58:50 -0700 Subject: [PATCH 2887/5359] More PHPdoc for `\WP_CLI\Runner` --- php/WP_CLI/Runner.php | 81 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 10db74c19..49ff4c012 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -6,6 +6,11 @@ use WP_CLI\Utils; use WP_CLI\Dispatcher; +/** + * Performs the execution of a command. + * + * @package WP_CLI + */ class Runner { private $global_config_path, $project_config_path; @@ -23,10 +28,21 @@ public function __get( $key ) { return $this->$key; } + /** + * Register a command for early invocation, generally before WordPress loads. + * + * @param string $when Named execution hook + * @param WP_CLI\Dispatcher\Subcommand $command + */ public function register_early_invoke( $when, $command ) { $this->_early_invoke[ $when ][] = array_slice( Dispatcher\get_path( $command ), 1 ); } + /** + * Perform the early invocation of a command. + * + * @param string $when Named execution hook + */ private function do_early_invoke( $when ) { if ( !isset( $this->_early_invoke[ $when ] ) ) return; @@ -39,6 +55,11 @@ private function do_early_invoke( $when ) { } } + /** + * Get the path to the global configuration YAML file. + * + * @return string|false + */ private static function get_global_config_path() { $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); if ( isset( $runtime_config['config'] ) ) { @@ -55,6 +76,13 @@ private static function get_global_config_path() { return $config_path; } + /** + * Get the path to the project-specific configuration + * YAML file. + * wp-cli.local.yml takes priority over wp-cli.yml. + * + * @return string|false + */ private static function get_project_config_path() { $config_files = array( 'wp-cli.local.yml', @@ -75,6 +103,9 @@ private static function get_project_config_path() { /** * Attempts to find the path to the WP install inside index.php + * + * @param string $index_path + * @return string|false */ private static function extract_subdir_path( $index_path ) { $index_code = file_get_contents( $index_path ); @@ -95,7 +126,8 @@ private static function extract_subdir_path( $index_path ) { } /** - * Find the directory that contains the WordPress files. Defaults to the current working dir. + * Find the directory that contains the WordPress files. + * Defaults to the current working dir. * * @return string An absolute path */ @@ -132,12 +164,22 @@ private function find_wp_root() { } } + /** + * Set WordPress root as a given path. + * + * @param string $path + */ private static function set_wp_root( $path ) { define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); } + /** + * Set a specific user context for WordPress. + * + * @param array $assoc_args + */ private static function set_user( $assoc_args ) { if ( isset( $assoc_args['user'] ) ) { $fetcher = new \WP_CLI\Fetchers\User; @@ -148,6 +190,12 @@ private static function set_user( $assoc_args ) { } } + /** + * Guess which URL context WP-CLI has been invoked under. + * + * @param array $assoc_args + * @return string|false + */ private static function guess_url( $assoc_args ) { if ( isset( $assoc_args['blog'] ) ) { $assoc_args['url'] = $assoc_args['blog']; @@ -192,6 +240,12 @@ private function cmd_starts_with( $prefix ) { return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); } + /** + * Given positional arguments, find the command to execute. + * + * @param array $args + * @return array|string Command, args, and path on success; error message on failure + */ public function find_command_to_run( $args ) { $command = \WP_CLI::get_root_command(); @@ -225,6 +279,13 @@ public function find_command_to_run( $args ) { return array( $command, $args, $cmd_path ); } + /** + * Find the WP-CLI command to run given arguments, + * and invoke it. + * + * @param array $args Positional arguments including command name + * @param array $assoc_args + */ public function run_command( $args, $assoc_args = array() ) { $r = $this->find_command_to_run( $args ); if ( is_string( $r ) ) { @@ -284,7 +345,13 @@ public function get_wp_config_code() { return preg_replace( '|^\s*\<\?php\s*|', '', $source ); } - // Transparently convert old syntaxes + /** + * Transparently convert deprecated syntaxes + * + * @param array $args + * @param array $assoc_args + * @return array + */ private static function back_compat_conversions( $args, $assoc_args ) { $top_level_aliases = array( 'sql' => 'db', @@ -367,6 +434,11 @@ private static function back_compat_conversions( $args, $assoc_args ) { return array( $args, $assoc_args ); } + /** + * Whether or not the output should be rendered in color + * + * @return bool + */ public function in_color() { return $this->colorize; } @@ -388,6 +460,11 @@ private function init_logger() { WP_CLI::set_logger( $logger ); } + /** + * Do WordPress core files exist? + * + * @return bool + */ private function wp_exists() { return is_readable( ABSPATH . 'wp-includes/version.php' ); } From c775c2c299f13054c434f186160bb75fad4a4a46 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 10:59:10 -0700 Subject: [PATCH 2888/5359] `WP_CLI` and `WP_CLI\Configurator` also got some PHPdoc coverage --- php/WP_CLI/Configurator.php | 18 ++++++++++++++++++ php/class-wp-cli.php | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 8a9ce8ac7..92bffd9d5 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -2,6 +2,11 @@ namespace WP_CLI; +/** + * Handles file- and runtime-based configuration values. + * + * @package WP_CLI + */ class Configurator { private $spec; @@ -27,6 +32,11 @@ function __construct( $path ) { } } + /** + * Get declared configuration values as an array. + * + * @return array + */ function to_array() { return array( $this->config, $this->extra_config ); } @@ -132,6 +142,9 @@ function merge_array( $config ) { /** * Load values from a YAML file. + * + * @param string $yml_file Path to the YAML file + * @return array $config Declared configuration values */ private static function load_yml( $yml_file ) { if ( !$yml_file ) @@ -155,6 +168,11 @@ private static function load_yml( $yml_file ) { return $config; } + /** + * Conform a variable to an array. + * + * @param mixed $val A string or an array + */ private static function arrayify( &$val ) { if ( !is_array( $val ) ) { $val = array( $val ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ca650fc2c..e6dbe54f6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -25,6 +25,11 @@ static function set_logger( $logger ) { self::$logger = $logger; } + /** + * Get the Configurator instance + * + * @return \WP_CLI\Configurator + */ static function get_configurator() { static $configurator; From aa27fd943291dd750a662a80599f8e65e6684488 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 11:46:25 -0700 Subject: [PATCH 2889/5359] Update @nb's new export API with @dllh's fix for orphaned terms --- php/export/class-wp-export-query.php | 33 +++++++++++++++- php/export/writers.php | 56 +++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index b99636e04..d826d17f6 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -27,6 +27,8 @@ class WP_Export_Query { private $author; private $category; + public $missing_parents = false; + public function __construct( $filters = array() ) { $this->filters = wp_parse_args( $filters, self::$defaults ); $this->post_ids = $this->calculate_post_ids(); @@ -70,13 +72,17 @@ public function authors() { public function categories() { if ( $this->category ) { - return array( $this->category ); + return $this->category; } if ( $this->filters['post_type'] ) { return array(); } $categories = (array) get_categories( array( 'get' => 'all' ) ); + + $this->check_for_orphaned_terms( $categories ); + $categories = self::topologically_sort_terms( $categories ); + return $categories; } @@ -85,6 +91,9 @@ public function tags() { return array(); } $tags = (array) get_tags( array( 'get' => 'all' ) ); + + $this->check_for_orphaned_terms( $tags ); + return $tags; } @@ -94,6 +103,7 @@ public function custom_taxonomies_terms() { } $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); + $this->check_for_orphaned_terms( $custom_terms ); $custom_terms = self::topologically_sort_terms( $custom_terms ); return $custom_terms; } @@ -271,6 +281,24 @@ private static function topologically_sort_terms( $terms ) { return $sorted; } + private function check_for_orphaned_terms( $terms ) { + $term_ids = array(); + $have_parent = array(); + + foreach ( $terms as $term ) { + $term_ids[ $term->term_id ] = true; + if ( $term->parent != 0 ) + $have_parent[] = $term; + } + + foreach ( $have_parent as $has_parent ) { + if ( ! isset( $term_ids[ $has_parent->parent ] ) ) { + $this->missing_parents = $has_parent; + throw new WP_Export_Term_Exception( __( 'Term is missing a parent.' ) ); + } + } + } + private static function get_terms_for_post( $post ) { $taxonomies = get_object_taxonomies( $post->post_type ); if ( empty( $taxonomies ) ) @@ -309,3 +337,6 @@ private static function get_comments_for_post( $post ) { class WP_Export_Exception extends RuntimeException { } + +class WP_Export_Term_Exception extends RuntimeException { +} diff --git a/php/export/writers.php b/php/export/writers.php index 751d356a1..5aa0927d2 100644 --- a/php/export/writers.php +++ b/php/export/writers.php @@ -26,14 +26,34 @@ function __construct( $formatter, $file_name ) { } public function export() { - header( 'Content-Description: File Transfer' ); - header( 'Content-Disposition: attachment; filename=' . $this->file_name ); - header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); - parent::export(); + try { + $export = $this->get_export(); + $this->send_headers(); + echo $export; + } catch ( WP_Export_Exception $e ) { + $message = apply_filters( 'export_error_message', $e->getMessage() ); + wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); + } catch ( WP_Export_Term_Exception $e ) { + do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); + $message = apply_filters( 'export_term_error_message', $e->getMessage() ); + wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); + } } protected function write( $xml ) { - echo $xml; + $this->result .= $xml; + } + + protected function get_export() { + $this->result = ''; + parent::export(); + return $this->result; + } + + protected function send_headers() { + header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: attachment; filename=' . $this->file_name ); + header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); } } @@ -42,7 +62,17 @@ class WP_Export_Returner extends WP_Export_Base_Writer { public function export() { $this->private = ''; - parent::export(); + try { + parent::export(); + } catch ( WP_Export_Exception $e ) { + $message = apply_filters( 'export_error_message', $e->getMessage() ); + return new WP_Error( 'wp-export-error', $message ); + + } catch ( WP_Export_Term_Exception $e ) { + do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); + $message = apply_filters( 'export_term_error_message', $e->getMessage() ); + return new WP_Error( 'wp-export-error', $message ); + } return $this->result; } protected function write( $xml ) { @@ -64,7 +94,15 @@ public function export() { if ( !$this->f ) { throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) ); } - parent::export(); + + try { + parent::export(); + } catch ( WP_Export_Exception $e ) { + throw $e; + } catch ( WP_Export_Term_Exception $e ) { + throw $e; + } + fclose( $this->f ); } @@ -85,7 +123,7 @@ class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer { function __construct( $formatter, $writer_args = array() ) { parent::__construct( $formatter ); //TODO: check if args are not missing - $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; + $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $max_file_size; $this->destination_directory = $writer_args['destination_directory']; $this->filename_template = $writer_args['filename_template']; $this->before_posts_xml = $this->formatter->before_posts(); @@ -95,7 +133,7 @@ function __construct( $formatter, $writer_args = array() ) { public function export() { $this->start_new_file(); foreach( $this->formatter->posts() as $post_xml ) { - if ( ( $this->current_file_size + strlen( $post_xml ) ) > $this->max_file_size ) { + if ( $this->current_file_size + strlen( $post_xml ) > $this->max_file_size ) { $this->start_new_file(); } $this->write( $post_xml ); From b4770d9d66ce60c65bb1bb539ffd39f0d035e2b9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 25 Apr 2014 11:51:46 -0700 Subject: [PATCH 2890/5359] Writer should use passed argument, not unknown variable --- php/export/writers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/writers.php b/php/export/writers.php index 5aa0927d2..989dd18e8 100644 --- a/php/export/writers.php +++ b/php/export/writers.php @@ -123,7 +123,7 @@ class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer { function __construct( $formatter, $writer_args = array() ) { parent::__construct( $formatter ); //TODO: check if args are not missing - $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $max_file_size; + $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; $this->destination_directory = $writer_args['destination_directory']; $this->filename_template = $writer_args['filename_template']; $this->before_posts_xml = $this->formatter->before_posts(); From 6ac65d13ff1b0067e6d9a93cd5a3f84bbe69705e Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 17:33:12 +0100 Subject: [PATCH 2891/5359] Docblock updates. --- php/commands/cron.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 4e342365d..713bcef8a 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -8,7 +8,6 @@ class Cron_Event_Command extends WP_CLI_Command { private $fields = array( 'hook', - // 'next_run', 'next_run_gmt', 'next_run_relative', 'recurrence', @@ -21,7 +20,7 @@ class Cron_Event_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to all of the cron event fields. + * : Limit the output to specific object fields. Available fields: hook, next_run, next_run_gmt, next_run_relative, recurrence. * * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. @@ -122,8 +121,6 @@ public function schedule( $args, $assoc_args ) { * * <hook> * : The hook name - * - * @synopsis <hook> */ public function run( $args, $assoc_args ) { @@ -178,8 +175,6 @@ protected static function run_event( stdClass $event ) { * * <hook> * : The hook name - * - * @synopsis <hook> */ public function delete( $args, $assoc_args ) { @@ -303,7 +298,7 @@ class Cron_Schedule_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to all of the cron schedule fields. + * : Limit the output to specific object fields. Available fields: name, display, interval. * * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. From 721e561f69e4ce5fe940aab0ae5f823b71d7a83b Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 17:39:44 +0100 Subject: [PATCH 2892/5359] Examples for the `list` commands --- php/commands/cron.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index 713bcef8a..bb82490bf 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -25,6 +25,12 @@ class Cron_Event_Command extends WP_CLI_Command { * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. * + * ## EXAMPLES + * + * wp cron event list + * + * wp cron event list --fields=hook,next_run --format=json + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -303,6 +309,12 @@ class Cron_Schedule_Command extends WP_CLI_Command { * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. * + * ## EXAMPLES + * + * wp cron schedule list + * + * wp cron schedule list --fields=name --format=ids + * * @subcommand list */ public function list_( $args, $assoc_args ) { From a6683cfb387c0c8fc8da25b03dbd4bf7ecb6aa24 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 18:09:51 +0100 Subject: [PATCH 2893/5359] Move `interval()` into `Cron_Event_Command` as a private method. Remove `time_since()` altogether. --- php/commands/cron.php | 63 ++++++++++++++++++++++++++++++++++++-- php/utils.php | 70 ------------------------------------------- 2 files changed, 61 insertions(+), 72 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index bb82490bf..5d35027be 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -234,8 +234,8 @@ protected static function format_event( stdClass $event ) { $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), self::$time_format ); $event->next_run_gmt = date( self::$time_format, $event->time ); - $event->next_run_relative = \WP_CLI\Utils\time_since( time(), $event->time ); - $event->recurrence = ( $event->schedule ) ? \WP_CLI\Utils\interval( $event->interval ) : 'Non-repeating'; + $event->next_run_relative = self::interval( $event->time - time() ); + $event->recurrence = ( $event->schedule ) ? self::interval( $event->interval ) : 'Non-repeating'; return $event; } @@ -281,6 +281,65 @@ protected static function get_cron_events() { } + /** + * Convert a time interval into human-readable format. + * + * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. + * + * @param int $since An interval of time in seconds + * @return string The interval in human readable format + */ + private static function interval( $since ) { + if ( $since <= 0 ) { + return 'now'; + } + + $since = absint( $since ); + + // array of time period chunks + $chunks = array( + array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), + array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), + array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), + array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), + array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), + array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), + array( 1 , \_n_noop( '%s second', '%s seconds' ) ), + ); + + // we only want to output two chunks of time here, eg: + // x years, xx months + // x days, xx hours + // so there's only two bits of calculation below: + + // step one: the first chunk + for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { + $seconds = $chunks[$i][0]; + $name = $chunks[$i][1]; + + // finding the biggest chunk (if the chunk fits, break) + if ( ( $count = floor( $since / $seconds ) ) != 0 ){ + break; + } + } + + // set output var + $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); + + // step two: the second chunk + if ( $i + 1 < $j ) { + $seconds2 = $chunks[$i + 1][0]; + $name2 = $chunks[$i + 1][1]; + + if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { + // add to output var + $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); + } + } + + return $output; + } + private function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'event' ); } diff --git a/php/utils.php b/php/utils.php index 393c06ee2..fe21f32e2 100644 --- a/php/utils.php +++ b/php/utils.php @@ -401,73 +401,3 @@ function replace_path_consts( $source, $path ) { return str_replace( $old, $new, $source ); } - -/** - * Convert a time interval into human-readable format. - * - * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. - * - * @param int $since An interval of time in seconds - * @return string The interval in human readable format - */ -function interval( $since ) { - if ( $since <= 0 ) { - return 'now'; - } - - $since = absint( $since ); - - // array of time period chunks - $chunks = array( - array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), - array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), - array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), - array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), - array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), - array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), - array( 1 , \_n_noop( '%s second', '%s seconds' ) ), - ); - - // we only want to output two chunks of time here, eg: - // x years, xx months - // x days, xx hours - // so there's only two bits of calculation below: - - // step one: the first chunk - for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { - $seconds = $chunks[$i][0]; - $name = $chunks[$i][1]; - - // finding the biggest chunk (if the chunk fits, break) - if ( ( $count = floor( $since / $seconds ) ) != 0 ){ - break; - } - } - - // set output var - $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); - - // step two: the second chunk - if ( $i + 1 < $j ) { - $seconds2 = $chunks[$i + 1][0]; - $name2 = $chunks[$i + 1][1]; - - if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { - // add to output var - $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); - } - } - - return $output; -} - -/** - * Returns a human-readable time difference between two times. - * - * @param int $older_date A Unix timestamp - * @param int $newer_date A Unix timestamp - * @return string The time difference in a human-readable format - */ -function time_since( $older_date, $newer_date ) { - return interval( $newer_date - $older_date ); -} From 82930548af63acd4cacd0de02c64ea333e5a9eb7 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 18:11:13 +0100 Subject: [PATCH 2894/5359] Convert `next_run` and `recurrence` into optional positional arguments --- php/commands/cron.php | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 5d35027be..1d9baaa70 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -58,10 +58,10 @@ public function list_( $args, $assoc_args ) { * <hook> * : The hook name * - * [--next_run=<value>] + * [<next-run>] * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. * - * [--recurrence=<value>] + * [<recurrence>] * : How often the event should recur. See `wp cron schedule list` for available schedule names. Defaults to no recurrence. * * [--<field>=<value>] @@ -71,44 +71,39 @@ public function list_( $args, $assoc_args ) { * * wp cron event schedule cron_test * - * wp cron event schedule cron_test --next_run='+1 hour' --recurrence=hourly + * wp cron event schedule cron_test now hourly * - * wp cron event schedule cron_test --recurrence=daily --foo=1 --bar=2 + * wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 */ public function schedule( $args, $assoc_args ) { - list( $hook ) = $args; + list( $hook, $next_run, $recurrence ) = $args; - if ( !isset( $assoc_args['next_run'] ) ) { + if ( !isset( $next_run ) ) { $timestamp = time(); - } else if ( is_numeric( $assoc_args['next_run'] ) ) { - $timestamp = absint( $assoc_args['next_run'] ); + } else if ( is_numeric( $next_run ) ) { + $timestamp = absint( $next_run ); } else { - $timestamp = strtotime( $assoc_args['next_run'] ); + $timestamp = strtotime( $next_run ); } if ( ! $timestamp ) { - WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $assoc_args['next_run'] ) ); + WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $next_run ) ); } - $event_args = array_diff_key( $assoc_args, array_flip( array( - 'next_run', 'recurrence' - ) ) ); + if ( isset( $recurrence ) ) { - if ( isset( $assoc_args['recurrence'] ) ) { - - $recurrence = $assoc_args['recurrence']; - $schedules = wp_get_schedules(); + $schedules = wp_get_schedules(); if ( ! isset( $schedules[$recurrence] ) ) { WP_CLI::error( sprintf( "'%s' is not a valid schedule name for recurrence.", $recurrence ) ); } - $event = wp_schedule_event( $timestamp, $recurrence, $hook, $event_args ); + $event = wp_schedule_event( $timestamp, $recurrence, $hook, $assoc_args ); } else { - $event = wp_schedule_single_event( $timestamp, $hook, $event_args ); + $event = wp_schedule_single_event( $timestamp, $hook, $assoc_args ); } From d3befe68cd8dc6e209c0601d9f1d60d526d478e3 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 18:11:30 +0100 Subject: [PATCH 2895/5359] Clarify that cron event times are in GMT --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 1d9baaa70..1e4e57e73 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -108,7 +108,7 @@ public function schedule( $args, $assoc_args ) { } if ( false !== $event ) { - WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s.", $hook, date( self::$time_format, $timestamp ) ) ); + WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s GMT.", $hook, date( self::$time_format, $timestamp ) ) ); } else { WP_CLI::error( 'Event not scheduled' ); } From f03532c9480adcb795636ae97b11768139ac805e Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 20:52:07 +0100 Subject: [PATCH 2896/5359] First pass at a Behat test for `wp cron` --- features/cron.feature | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 features/cron.feature diff --git a/features/cron.feature b/features/cron.feature new file mode 100644 index 000000000..3791341c6 --- /dev/null +++ b/features/cron.feature @@ -0,0 +1,53 @@ +Feature: Manage WP-Cron events and schedules + + Background: + Given a WP install + + Scenario: Scheduling an event + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour'` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_1' + """ + + When I run `wp cron event list --format=csv --fields=hook,recurrence` + Then STDOUT should be CSV containing: + | hook | recurrence | + | wp_cli_test_event_1 | Non-repeating | + + When I run `wp cron event delete wp_cli_test_event_1` + Then STDOUT should contain: + """ + Success: Successfully deleted the cron event 'wp_cli_test_event_1' + """ + + Scenario: Scheduling a recurring event + When I run `wp cron event schedule wp_cli_test_event_2 now daily` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_2' + """ + + When I run `wp cron event list --format=csv --fields=hook,recurrence` + Then STDOUT should be CSV containing: + | hook | recurrence | + | wp_cli_test_event_2 | 1 day | + + When I run `wp cron event delete wp_cli_test_event_2` + Then STDOUT should contain: + """ + Success: Successfully deleted the cron event 'wp_cli_test_event_2' + """ + + Scenario: Listing cron schedules + When I run `wp cron schedule list --format=csv --fields=name,interval` + Then STDOUT should be CSV containing: + | name | interval | + | hourly | 3600 | + + Scenario: Testing WP-Cron + When I run `wp cron test` + Then STDOUT should contain: + """ + Success: WP-Cron is working as expected + """ From 41b1d02e03651f8751e6afede9f660e871f76652 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 28 Apr 2014 21:02:04 +0100 Subject: [PATCH 2897/5359] Code tidy up --- php/commands/cron.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 1e4e57e73..5b9b097b5 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -252,10 +252,9 @@ protected static function get_cron_events() { ); } - // @TODO rename these vars a bit more better nicely nicer: - foreach ( $crons as $time => $cron ) { - foreach ( $cron as $hook => $dings ) { - foreach ( $dings as $sig => $data ) { + foreach ( $crons as $time => $hooks ) { + foreach ( $hooks as $hook => $hook_events ) { + foreach ( $hook_events as $sig => $data ) { $events["$hook-$sig"] = (object) array( 'hook' => $hook, From 3f284f1514c2b17edaddf670516275ef3626cb0f Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 29 Apr 2014 11:08:40 +0100 Subject: [PATCH 2898/5359] Update from develop branch of WP-Crontrol. When testing cron, return an error if `DISABLE_WP_CRON` is set. --- php/commands/cron.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index 5b9b097b5..42f012094 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -457,6 +457,10 @@ protected static function test_cron_spawn() { return true; } + if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) { + return new WP_Error( 'disable_wp_cron', 'The DISABLE_WP_CRON constant is set to true. WP-Cron is disabled.' ); + } + $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); $cron_request = apply_filters( 'cron_request', array( From b1916775157e3cd37e7b109b6d01e5daeb63a232 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 29 Apr 2014 08:30:51 -0700 Subject: [PATCH 2899/5359] Remove unused `check_verbose()` method Added in 32402827d8e738c7c4e6025b7b3bbc6d7a1a45d2 but doesn't appear to be used. aa542585aeeef589b1ce1e18edf3d4aa30a06786 removed the verbosity argument --- php/commands/export.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 862818cbd..31d9d84e2 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -130,12 +130,6 @@ private function validate_args( $args ) { } } - private function check_verbose( $verbose ) { - $this->verbose = $verbose; - - return true; - } - private function check_dir( $path ) { if ( empty( $path ) ) { $path = getcwd(); From e4e0bac7fd7f7605f3d97b0ec3358efcf2af4132 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 2 May 2014 10:33:04 -0300 Subject: [PATCH 2900/5359] add params first_name and last_name to wp user create --- features/user.feature | 14 +++++++++++++- php/commands/user.php | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index ba508535f..c603a5688 100644 --- a/features/user.feature +++ b/features/user.feature @@ -7,7 +7,7 @@ Feature: Manage WordPress users Then the return code should be 1 And STDOUT should be empty - When I run `wp user create testuser2 testuser2@example.com --role=author --porcelain` + When I run `wp user create testuser2 testuser2@example.com --first_name=test --last_name=user --role=author --porcelain` Then STDOUT should be a number And save STDOUT as {USER_ID} @@ -17,6 +17,18 @@ Feature: Manage WordPress users | ID | {USER_ID} | | roles | author | + When I run `wp user meta get {USER_ID} first_name` + Then STDOUT should be: + """ + test + """ + + When I run `wp user meta get {USER_ID} last_name` + Then STDOUT should be: + """ + user + """ + When I run `wp user delete {USER_ID} --yes` Then STDOUT should not be empty diff --git a/php/commands/user.php b/php/commands/user.php index 68771013f..61ea9dd5f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -185,6 +185,12 @@ public function delete( $args, $assoc_args ) { * [--display_name=<name>] * : The display name. * + * [--first_name=<first_name>] + * : The user's first name. + * + * [--last_name=<last_name>] + * : The user's last name. + * * [--send-email] * : Send an email to the user with their new account details. * @@ -214,6 +220,12 @@ public function create( $args, $assoc_args ) { $user->display_name = isset( $assoc_args['display_name'] ) ? $assoc_args['display_name'] : false; + $user->first_name = isset( $assoc_args['first_name'] ) + ? $assoc_args['first_name'] : false; + + $user->last_name = isset( $assoc_args['last_name'] ) + ? $assoc_args['last_name'] : false; + $user->user_pass = isset( $assoc_args['user_pass'] ) ? $assoc_args['user_pass'] : wp_generate_password(); From 0bc1a32c27d2831b9d9f7fb73585d7015fda1f93 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 2 May 2014 10:55:22 -0300 Subject: [PATCH 2901/5359] add basic test to 'wp scaffold plugin' command --- features/scaffold.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 0d1d011cf..2c48377ed 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -72,3 +72,11 @@ Feature: WordPress code scaffolding """ __( 'Brain eaters' """ + + Scenario: Scaffold a plugin + Given I run `wp plugin path` + And save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin hello-world` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist \ No newline at end of file From 2255a083b6b93b11a3fe4cc716d88e36c42eebb8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 2 May 2014 11:00:32 -0300 Subject: [PATCH 2902/5359] `wp scaffold plugin` generate a sample readme.txt --- features/scaffold.feature | 3 +- php/commands/scaffold.php | 2 + templates/plugin-readme.mustache | 114 +++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 templates/plugin-readme.mustache diff --git a/features/scaffold.feature b/features/scaffold.feature index 2c48377ed..419590e3d 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -79,4 +79,5 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world` Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist \ No newline at end of file + And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist + And the {PLUGIN_DIR}/hello-world/readme.txt file should exist \ No newline at end of file diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index fff531796..e090fa582 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -327,10 +327,12 @@ function plugin( $args, $assoc_args ) { $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; $plugin_path = "$plugin_dir/$plugin_slug.php"; + $plugin_readme_path = "$plugin_dir/readme.txt"; $this->maybe_create_plugins_dir(); $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); + $this->create_file( $plugin_readme_path, Utils\mustache_render( 'plugin-readme.mustache', $data ) ); WP_CLI::success( "Created $plugin_dir" ); diff --git a/templates/plugin-readme.mustache b/templates/plugin-readme.mustache new file mode 100644 index 000000000..44c117a68 --- /dev/null +++ b/templates/plugin-readme.mustache @@ -0,0 +1,114 @@ +=== {{plugin_name}} === +Contributors: (this should be a list of wordpress.org userid's) +Donate link: http://example.com/ +Tags: comments, spam +Requires at least: 3.0.1 +Tested up to: 3.4 +Stable tag: 4.3 +License: GPLv2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html + +Here is a short description of the plugin. This should be no more than 150 characters. No markup here. + +== Description == + +This is the long description. No limit, and you can use Markdown (as well as in the following sections). + +For backwards compatibility, if this section is missing, the full length of the short description will be used, and +Markdown parsed. + +A few notes about the sections above: + +* "Contributors" is a comma separated list of wp.org/wp-plugins.org usernames +* "Tags" is a comma separated list of tags that apply to the plugin +* "Requires at least" is the lowest version that the plugin will work on +* "Tested up to" is the highest version that you've *successfully used to test the plugin*. Note that it might work on +higher versions... this is just the highest one you've verified. +* Stable tag should indicate the Subversion "tag" of the latest stable version, or "trunk," if you use `/trunk/` for +stable. + + Note that the `readme.txt` of the stable tag is the one that is considered the defining one for the plugin, so +if the `/trunk/readme.txt` file says that the stable tag is `4.3`, then it is `/tags/4.3/readme.txt` that'll be used +for displaying information about the plugin. In this situation, the only thing considered from the trunk `readme.txt` +is the stable tag pointer. Thus, if you develop in trunk, you can update the trunk `readme.txt` to reflect changes in +your in-development version, without having that information incorrectly disclosed about the current stable version +that lacks those changes -- as long as the trunk's `readme.txt` points to the correct stable tag. + + If no stable tag is provided, it is assumed that trunk is stable, but you should specify "trunk" if that's where +you put the stable version, in order to eliminate any doubt. + +== Installation == + +This section describes how to install the plugin and get it working. + +e.g. + +1. Upload `plugin-name.php` to the `/wp-content/plugins/` directory +1. Activate the plugin through the 'Plugins' menu in WordPress +1. Place `<?php do_action('plugin_name_hook'); ?>` in your templates + +== Frequently Asked Questions == + += A question that someone might have = + +An answer to that question. + += What about foo bar? = + +Answer to foo bar dilemma. + +== Screenshots == + +1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from +the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets +directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png` +(or jpg, jpeg, gif). +2. This is the second screen shot + +== Changelog == + += 1.0 = +* A change since the previous version. +* Another change. + += 0.5 = +* List versions from most recent at top to oldest at bottom. + +== Upgrade Notice == + += 1.0 = +Upgrade notices describe the reason a user should upgrade. No more than 300 characters. + += 0.5 = +This version fixes a security related bug. Upgrade immediately. + +== Arbitrary section == + +You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated +plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or +"installation." Arbitrary sections will be shown below the built-in sections outlined above. + +== A brief Markdown Example == + +Ordered list: + +1. Some feature +1. Another feature +1. Something else about the plugin + +Unordered list: + +* something +* something else +* third thing + +Here's a link to [WordPress](http://wordpress.org/ "Your favorite software") and one to [Markdown's Syntax Documentation][markdown syntax]. +Titles are optional, naturally. + +[markdown syntax]: http://daringfireball.net/projects/markdown/syntax + "Markdown is what the parser uses to process much of the readme file" + +Markdown uses email style notation for blockquotes and I've been told: +> Asterisks for *emphasis*. Double it up for **strong**. + +`<?php code(); // goes in backticks ?>` From 5e47794129a8d6f4a216161d6f50b9edb9e6bd90 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 2 May 2014 08:58:08 -0700 Subject: [PATCH 2903/5359] Add `--fields` support to `wp user get` --- php/commands/user.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 61ea9dd5f..11b7f53ae 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -89,6 +89,9 @@ public function list_( $args, $assoc_args ) { * [--field=<field>] * : Instead of returning the whole user, returns the value of a single field. * + * [--fields=<fields>] + * : Get a specific subset of the user's fields. + * * [--format=<format>] * : Accepted values: table, json. Default: table * From 01b55ad79b75d9bb0c152575e591e2023f565d43 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 2 May 2014 08:58:28 -0700 Subject: [PATCH 2904/5359] Add `--skip-update` flag to `wp user import-csv` --- features/user.feature | 33 +++++++++++++++++++++++++++++++++ php/commands/user.php | 11 ++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index c603a5688..a50e3bb3a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -150,6 +150,39 @@ Feature: Manage WordPress users }] """ + Scenario: Import new users but don't update existing + Given a WP install + And a users.csv file: + """ + user_login,user_email,display_name,role + bobjones,bobjones@domain.com,Bob Jones,contributor + newuser1,newuser1@domain.com,New User,author + admin,admin@domain.com,Existing User,administrator + """ + + When I run `wp user create bobjones bobjones@domain.com --display_name="Robert Jones" --role=administrator` + Then STDOUT should not be empty + + When I run `wp user import-csv users.csv --skip-update` + Then STDOUT should not be empty + + When I run `wp user list --format=count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp user get bobjones --fields=user_login,display_name,user_email,roles --format=json` + Then STDOUT should be JSON containing: + """ + { + "user_login":"bobjones", + "display_name":"Robert Jones", + "user_email":"bobjones@domain.com", + "roles":"administrator" + } + """ + Scenario: Managing user roles Given a WP install diff --git a/php/commands/user.php b/php/commands/user.php index 11b7f53ae..81bca8f40 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -551,6 +551,9 @@ public function list_caps( $args, $assoc_args ) { * [--send-email] * : Send an email to new users with their account details. * + * [--skip-update] + * : Don't update users that already exist. + * * ## EXAMPLES * * wp user import-csv /path/to/users.csv @@ -597,7 +600,13 @@ public function import_csv( $args, $assoc_args ) { $existing_user = get_user_by( 'login', $new_user['user_login'] ); } - if ( $existing_user ) { + if ( $existing_user && isset( $assoc_args['skip-update'] ) ) { + + WP_CLI::log( "{$existing_user->user_login} exists and has been skipped" ); + continue; + + } else if ( $existing_user ) { + $new_user['ID'] = $existing_user->ID; $user_id = wp_update_user( $new_user ); From 9d15ec0be6c0ec9f7f590db96e7f0f58c485c785 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 20:11:06 +0100 Subject: [PATCH 2905/5359] Formatting tweak --- features/cron.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cron.feature b/features/cron.feature index 3791341c6..d345940ce 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -12,7 +12,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event list --format=csv --fields=hook,recurrence` Then STDOUT should be CSV containing: - | hook | recurrence | + | hook | recurrence | | wp_cli_test_event_1 | Non-repeating | When I run `wp cron event delete wp_cli_test_event_1` From bca449463047aa16f3dc91eb0eb401396afced39 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 20:13:52 +0100 Subject: [PATCH 2906/5359] Alter `wp cron event run <hook>` so it fires the event inline instead of asynchronously --- php/commands/cron.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 42f012094..e80960bd1 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -141,6 +141,7 @@ public function run( $args, $assoc_args ) { } if ( $result ) { + WP_CLI::line( '' ); WP_CLI::success( sprintf( "Successfully executed the cron event '%s'", $hook ) ); } else { WP_CLI::error( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); @@ -149,21 +150,18 @@ public function run( $args, $assoc_args ) { } /** - * Executes an event immediately by scheduling a new single event with the same arguments. + * Executes an event immediately. * * @param stdClass $event The event * @return bool Whether the event was successfully executed or not. */ protected static function run_event( stdClass $event ) { - delete_transient( 'doing_cron' ); - $scheduled = wp_schedule_single_event( time()-1, $event->hook, $event->args ); - - if ( false === $scheduled ) { - return false; + if ( ! defined( 'DOING_CRON' ) ) { + define( 'DOING_CRON', true ); } - spawn_cron(); + do_action_ref_array( $event->hook, $event->args ); return true; From 1ce77bd1a6648c66d96f1f2c405e79aca7e4aa28 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 20:17:30 +0100 Subject: [PATCH 2907/5359] More comprehensive testing in `wp cron test`: * Displays an error if `DISABLE_WP_CRON` is set to true * Displays an error if the cron spawn fails * Displays a warning when `ALTERNATE_WP_CRON` is set to true * Displays a warning when the cron spawn request's HTTP status is something other than a 200 --- php/commands/cron.php | 49 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index e80960bd1..15bc3c451 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -427,37 +427,44 @@ private function get_formatter( &$assoc_args ) { class Cron_Command extends WP_CLI_Command { /** - * Test the WP Cron spawning system and report back any errors. + * Test the WP Cron spawning system and report back its status. */ public function test() { - $status = self::test_cron_spawn(); + if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) { + WP_CLI::error( 'The DISABLE_WP_CRON constant is set to true. WP-Cron spawning is disabled.' ); + } + + if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { + WP_CLI::warning( 'The ALTERNATE_WP_CRON constant is set to true. WP-Cron spawning is not asynchronous.' ); + } + + $spawn = self::get_cron_spawn(); + + if ( is_wp_error( $spawn ) ) { + WP_CLI::error( sprintf( 'WP-Cron spawn failed with error: %s', $spawn->get_error_message() ) ); + } + + $code = wp_remote_retrieve_response_code( $spawn ); + $message = wp_remote_retrieve_response_message( $spawn ); - if ( is_wp_error( $status ) ) { - WP_CLI::error( $status ); + if ( 200 === $code ) { + WP_CLI::success( 'WP-Cron spawning is working as expected.' ); } else { - WP_CLI::success( 'WP-Cron is working as expected.' ); + WP_CLI::warning( sprintf( 'WP-Cron spawn succeeded but returned HTTP status code: %1$s %2$s', $code, $message ) ); } } /** - * Gets the status of WP-Cron functionality on the site by performing a test spawn. + * Spawn a request to `wp-cron.php` and return the response. * - * This function is designed to mimic the functionality in `spawn_cron()` with the addition of checking - * the return value of the call to `wp_remote_post()`. + * This function is designed to mimic the functionality in `spawn_cron()` with the addition of returning + * the result of the `wp_remote_post()` request. * - * @return bool|WP_Error Boolean true if the cron spawn test is successful, WP_Error object if not. + * @return WP_Error|array The response or WP_Error on failure. */ - protected static function test_cron_spawn() { - - if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { - return true; - } - - if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) { - return new WP_Error( 'disable_wp_cron', 'The DISABLE_WP_CRON constant is set to true. WP-Cron is disabled.' ); - } + protected static function get_cron_spawn() { $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); @@ -476,11 +483,7 @@ protected static function test_cron_spawn() { $result = wp_remote_post( $cron_request['url'], $cron_request['args'] ); - if ( is_wp_error( $result ) ) { - return $result; - } else { - return true; - } + return $result; } From 4e53c54f7c6b96a7d6b3363de7ac982ed6d37e23 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 20:36:26 +0100 Subject: [PATCH 2908/5359] Update the behat test for `wp cron test`. Not currently passing. --- features/cron.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index d345940ce..9d647c8b7 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -47,7 +47,7 @@ Feature: Manage WP-Cron events and schedules Scenario: Testing WP-Cron When I run `wp cron test` - Then STDOUT should contain: + Then STDOUT should not contain: """ - Success: WP-Cron is working as expected + Error: """ From 9c5989dfa060cb494f946fb2d8004c82e091b838 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 2 May 2014 13:01:35 -0700 Subject: [PATCH 2909/5359] Let's see if skipping PHP 5.5.11 does the trick to fix Travis builds --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94c066ac1..85086d37a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ language: php php: - 5.3 - - 5.5 + # WP-CLI currently fails on PHP 5.5.11, which Travis is using + - 5.4 env: global: @@ -32,12 +33,12 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=3.9-RC1 + - WP_VERSION=3.9 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: exclude: - - php: 5.5 + - php: 5.4 env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From 69b4099ae54fdd157d7c5f7160d3965544d344ee Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 21:23:43 +0100 Subject: [PATCH 2910/5359] Update the `wp cron test` feature test so it handles STDERR output --- features/cron.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 9d647c8b7..13e344130 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -46,8 +46,8 @@ Feature: Manage WP-Cron events and schedules | hourly | 3600 | Scenario: Testing WP-Cron - When I run `wp cron test` - Then STDOUT should not contain: + When I try `wp cron test` + Then STDERR should not contain: """ Error: """ From 4cab441f8901deb0920a1f1856621628c748e639 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Fri, 2 May 2014 21:30:25 +0100 Subject: [PATCH 2911/5359] Add tests to check that `wp cron event delete` has worked --- features/cron.feature | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 13e344130..d33a694b5 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -3,7 +3,7 @@ Feature: Manage WP-Cron events and schedules Background: Given a WP install - Scenario: Scheduling an event + Scenario: Scheduling and then deleting an event When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour'` Then STDOUT should contain: """ @@ -21,7 +21,13 @@ Feature: Manage WP-Cron events and schedules Success: Successfully deleted the cron event 'wp_cli_test_event_1' """ - Scenario: Scheduling a recurring event + When I run `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_1 + """ + + Scenario: Scheduling and then deleting a recurring event When I run `wp cron event schedule wp_cli_test_event_2 now daily` Then STDOUT should contain: """ @@ -39,6 +45,12 @@ Feature: Manage WP-Cron events and schedules Success: Successfully deleted the cron event 'wp_cli_test_event_2' """ + When I run `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_2 + """ + Scenario: Listing cron schedules When I run `wp cron schedule list --format=csv --fields=name,interval` Then STDOUT should be CSV containing: From f5655d919d890ed0b7ee577b8920973d735ab107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Sat, 3 May 2014 01:07:42 +0200 Subject: [PATCH 2912/5359] don't set user whwn installing Is it all right?? --- php/WP_CLI/Runner.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 49ff4c012..76419a541 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -681,7 +681,9 @@ public function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); // Handle --user parameter - self::set_user( $this->config ); + if ( ! defined( 'WP_INSTALLING' ) ) { + self::set_user( $this->config ); + } $this->_run_command(); } From 0891e45e63b7759da39020640f814891fd8ede4e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 5 May 2014 11:14:50 -0700 Subject: [PATCH 2913/5359] Functional tests for #1180 --- features/core.feature | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/features/core.feature b/features/core.feature index fd7793eaa..f8b363b0d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -238,3 +238,22 @@ Feature: Manage WordPress installation When I run `wp plugin status hello` Then STDOUT should not be empty + + Scenario: User defined in wp-cli.yml + Given an empty directory + And WP files + And wp-config.php + And a database + And a wp-cli.yml file: + """ + user: wpcli + """ + + When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` + Then STDOUT should not be empty + + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + http://localhost:8001 + """ From 79649ae24b08b9cf2daba8cc8be26c00a039514d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 5 May 2014 11:54:46 -0700 Subject: [PATCH 2914/5359] Support passing `--parent-id` to set the parent of a menu item --- features/menu.feature | 28 +++++++++++++++++----------- php/commands/menu.php | 1 + 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 60862576e..f8bef10e9 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -56,22 +56,28 @@ Feature: Manage WordPress menus Then save STDOUT as {TERM_LINK} When I run `wp menu create "Sidebar Menu"` - And I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post"` - And I run `wp menu item add-term sidebar-menu post_tag {TERM_ID}` - And I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` - Then save STDOUT as {ITEM_ID} + Then STDOUT should not be empty - When I run `wp menu item update {ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` + When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --porcelain` + Then save STDOUT as {POST_ITEM_ID} + + When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` + Then save STDOUT as {TERM_ITEM_ID} + + When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --parent-id={POST_ITEM_ID} --porcelain` + Then save STDOUT as {CUSTOM_ITEM_ID} + + When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` Then STDERR should be empty - When I run `wp menu item list sidebar-menu --fields=type,title,position,link` + When I run `wp menu item list sidebar-menu --fields=type,title,position,link,menu_item_parent` Then STDOUT should be a table containing rows: - | type | title | position | link | - | post_type | Custom Test Post | 1 | {POST_LINK} | - | custom | WordPress | 2 | http://wordpress.org | - | taxonomy | Test term | 3 | {TERM_LINK} | + | type | title | position | link | menu_item_parent | + | post_type | Custom Test Post | 1 | {POST_LINK} | 0 | + | custom | WordPress | 2 | http://wordpress.org | {POST_ITEM_ID} | + | taxonomy | Test term | 3 | {TERM_LINK} | 0 | - When I run `wp menu item delete {ITEM_ID}` + When I run `wp menu item delete {CUSTOM_ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: """ diff --git a/php/commands/menu.php b/php/commands/menu.php index 47160a541..25223b948 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -467,6 +467,7 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { 'description' => '', 'object' => '', 'object-id' => '', + 'parent-id' => '', 'attr-title' => '', 'target' => '', 'classes' => '', From 71b2e2fc65bde06f15cae6781e1314d9f503eb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Mon, 5 May 2014 21:14:06 +0200 Subject: [PATCH 2915/5359] indent --- php/commands/db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 72ccd7526..6e676e160 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -205,8 +205,8 @@ function import( $args, $assoc_args ) { * * ## EXAMPLES * - * # Export only tables for a single site - * wp db export --tables=$(wp db tables --url=sub.example.com | tr '\n' ',') + * # Export only tables for a single site + * wp db export --tables=$(wp db tables --url=sub.example.com | tr '\n' ',') */ function tables( $args, $assoc_args ) { global $wpdb; From 1539cb378c8e470ee624fedd2c16106c500c0f7c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 5 May 2014 12:22:58 -0700 Subject: [PATCH 2916/5359] When updating a menu item, always persist its data Fixes a bug in core where the data will be lost https://core.trac.wordpress.org/ticket/28138 --- features/menu.feature | 15 ++++++---- php/commands/menu.php | 69 ++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index f8bef10e9..75753186c 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -58,9 +58,12 @@ Feature: Manage WordPress menus When I run `wp menu create "Sidebar Menu"` Then STDOUT should not be empty - When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --porcelain` + When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --description="Georgia peaches" --porcelain` Then save STDOUT as {POST_ITEM_ID} + When I run `wp menu item update {POST_ITEM_ID} --description="Washington Apples"` + Then STDERR should be empty + When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` Then save STDOUT as {TERM_ITEM_ID} @@ -70,12 +73,12 @@ Feature: Manage WordPress menus When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` Then STDERR should be empty - When I run `wp menu item list sidebar-menu --fields=type,title,position,link,menu_item_parent` + When I run `wp menu item list sidebar-menu --fields=type,title,description,position,link,menu_item_parent` Then STDOUT should be a table containing rows: - | type | title | position | link | menu_item_parent | - | post_type | Custom Test Post | 1 | {POST_LINK} | 0 | - | custom | WordPress | 2 | http://wordpress.org | {POST_ITEM_ID} | - | taxonomy | Test term | 3 | {TERM_LINK} | 0 | + | type | title | description | position | link | menu_item_parent | + | post_type | Custom Test Post | Washington Apples | 1 | {POST_LINK} | 0 | + | custom | WordPress | | 2 | http://wordpress.org | {POST_ITEM_ID} | + | taxonomy | Test term | | 3 | {TERM_LINK} | 0 | When I run `wp menu item delete {CUSTOM_ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` diff --git a/php/commands/menu.php b/php/commands/menu.php index 25223b948..8d133a56c 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -460,35 +460,56 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { $assoc_args['url'] = $assoc_args['link']; } - $default_args = array( - 'position' => 0, - 'title' => '', - 'url' => '', - 'description' => '', - 'object' => '', - 'object-id' => '', - 'parent-id' => '', - 'attr-title' => '', - 'target' => '', - 'classes' => '', - 'xfn' => '', - 'status' => '', - ); + // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 + if ( 'update' == $method ) { + + $menu_item_obj = get_post( $menu_item_db_id ); + $menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj ); + + $default_args = array( + 'position' => $menu_item_obj->menu_order, + 'title' => $menu_item_obj->title, + 'url' => $menu_item_obj->url, + 'description' => $menu_item_obj->description, + 'object' => $menu_item_obj->object, + 'object-id' => $menu_item_obj->object_id, + 'parent-id' => $menu_item_obj->menu_item_parent, + 'attr-title' => $menu_item_obj->attr_title, + 'target' => $menu_item_obj->target, + 'classes' => implode( ' ', $menu_item_obj->classes ), // stored in the database as array + 'xfn' => $menu_item_obj->xfn, + 'status' => $menu_item_obj->post_status, + ); + + error_log( var_export( $default_args, true ) ); + + } else { + + $default_args = array( + 'position' => 0, + 'title' => '', + 'url' => '', + 'description' => '', + 'object' => '', + 'object-id' => 0, + 'parent-id' => 0, + 'attr-title' => '', + 'target' => '', + 'classes' => '', + 'xfn' => '', + // Core oddly defaults to 'draft' for create, + // and 'publish' for update + // Easiest to always work with publish + 'status' => 'publish', + ); + + } $menu_item_args = array(); foreach( $default_args as $key => $default_value ) { // wp_update_nav_menu_item() has a weird argument prefix $new_key = 'menu-item-' . $key; - if ( isset( $assoc_args[ $key ] ) ) { - $menu_item_args[ $new_key ] = $assoc_args[ $key ]; - } - } - - // Core oddly defaults to 'draft' for create, - // and 'publish' for update - // Easiest to always work with publish - if ( ! isset( $menu_item_args['menu-item-status'] ) ) { - $menu_item_args['menu-item-status'] = 'publish'; + $menu_item_args[ $new_key ] = isset( $assoc_args[ $key ] ) ? $assoc_args[ $key ] : $default_value; } $menu_item_args['menu-item-type'] = $type; From 721bb4f14261f08124a673fb4714cbeae1a2aba9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 5 May 2014 12:31:37 -0700 Subject: [PATCH 2917/5359] Persist the appropriate position when updating a menu item See https://core.trac.wordpress.org/ticket/28140 --- php/commands/menu.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 8d133a56c..e5de9bfd3 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -466,8 +466,11 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { $menu_item_obj = get_post( $menu_item_db_id ); $menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj ); + // Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140 + $position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order; + $default_args = array( - 'position' => $menu_item_obj->menu_order, + 'position' => $position, 'title' => $menu_item_obj->title, 'url' => $menu_item_obj->url, 'description' => $menu_item_obj->description, @@ -481,8 +484,6 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { 'status' => $menu_item_obj->post_status, ); - error_log( var_export( $default_args, true ) ); - } else { $default_args = array( From 0ce031477d31ed4bb0682e60fe8330680d2f214e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 5 May 2014 13:08:52 -0700 Subject: [PATCH 2918/5359] Fix coding standards error --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index e5de9bfd3..55191c8db 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -486,7 +486,7 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { } else { - $default_args = array( + $default_args = array( 'position' => 0, 'title' => '', 'url' => '', From 1a3e44fe35f0dae2822dae4cab802df24e9d0a08 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 08:08:22 -0700 Subject: [PATCH 2919/5359] Remove extra line --- php/commands/cron.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 15bc3c451..5f27b3dcb 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -141,7 +141,6 @@ public function run( $args, $assoc_args ) { } if ( $result ) { - WP_CLI::line( '' ); WP_CLI::success( sprintf( "Successfully executed the cron event '%s'", $hook ) ); } else { WP_CLI::error( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); From 8bc2c5bb79ab269a63beef6be8ccdb9cf95ab38e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 08:13:54 -0700 Subject: [PATCH 2920/5359] When a cron event runs, clear it from cron entries However, if it's scheduled to reoccur, reschedule the cron event. Adds functional tests. --- features/cron.feature | 42 ++++++++++++++++++++++++++++++++++++++++++ php/commands/cron.php | 7 +++++++ 2 files changed, 49 insertions(+) diff --git a/features/cron.feature b/features/cron.feature index d33a694b5..a25404172 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -27,6 +27,48 @@ Feature: Manage WP-Cron events and schedules wp_cli_test_event_1 """ + Scenario: Scheduling and then running an event + When I run `wp cron event schedule wp_cli_test_event_3 '-1 minutes'` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_3' + """ + + When I run `wp cron event list --format=csv --fields=hook,recurrence` + Then STDOUT should be CSV containing: + | hook | recurrence | + | wp_cli_test_event_3 | Non-repeating | + + When I run `wp cron event run wp_cli_test_event_3` + Then STDOUT should not be empty + + When I run `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_3 + """ + + Scenario: Scheduling and then running a re-occurring event + When I run `wp cron event schedule wp_cli_test_event_4 now hourly` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_4' + """ + + When I run `wp cron event list --format=csv --fields=hook,recurrence` + Then STDOUT should be CSV containing: + | hook | recurrence | + | wp_cli_test_event_4 | 1 hour | + + When I run `wp cron event run wp_cli_test_event_4` + Then STDOUT should not be empty + + When I run `wp cron event list` + Then STDOUT should contain: + """ + wp_cli_test_event_4 + """ + Scenario: Scheduling and then deleting a recurring event When I run `wp cron event schedule wp_cli_test_event_2 now daily` Then STDOUT should contain: diff --git a/php/commands/cron.php b/php/commands/cron.php index 5f27b3dcb..db4e07dd2 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -160,6 +160,13 @@ protected static function run_event( stdClass $event ) { define( 'DOING_CRON', true ); } + if ( $event->schedule != false ) { + $new_args = array( $event->time, $event->schedule, $event->hook, $event->args ); + call_user_func_array( 'wp_reschedule_event', $new_args ); + } + + wp_unschedule_event( $event->time, $event->hook, $event->args ); + do_action_ref_array( $event->hook, $event->args ); return true; From c2f4c1878089e9cef702e0530561dd2081b81f1f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 08:51:00 -0700 Subject: [PATCH 2921/5359] Support empty `DB_CHARSET` value when running MySQL commands See #1143 --- features/db.feature | 20 ++++++++++++++++++++ php/commands/db.php | 11 ++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/features/db.feature b/features/db.feature index f8376e824..92074c225 100644 --- a/features/db.feature +++ b/features/db.feature @@ -71,3 +71,23 @@ Feature: Perform database operations """ 1 """ + + Scenario: DB export no charset + Given a WP install + And a replace-script.php file: + """ + <?php + $wp_config = file_get_contents( 'wp-config.php' ); + $wp_config = str_replace( 'utf8', '', $wp_config ); + file_put_contents( 'wp-config.php', $wp_config ); + WP_CLI::success( "Replaced charset" ); + """ + + When I run `wp eval-file replace-script.php` + Then STDOUT should not be empty + + When I run `wp db export /tmp/wp-cli-behat.sql` + Then STDOUT should contain: + """ + Success: Exported + """ diff --git a/php/commands/db.php b/php/commands/db.php index 6e676e160..b641c8499 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -232,12 +232,17 @@ private static function run_query( $query ) { } private static function run( $cmd, $assoc_args = array(), $descriptors = null ) { - $final_args = array_merge( $assoc_args, array( + $required = array( 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASSWORD, - 'default-character-set' => DB_CHARSET, - ) ); + ); + + if ( defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { + $required['default-character-set'] = constant( 'DB_CHARSET' ); + } + + $final_args = array_merge( $assoc_args, $required ); Utils\run_mysql_command( $cmd, $final_args, $descriptors ); } From 3919514d0e89d26942023bb9686355b5cd44155f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 09:40:03 -0700 Subject: [PATCH 2922/5359] No synopsis needed if the options are properly declared --- php/commands/media.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 08770b097..5ce897724 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -67,27 +67,27 @@ function regenerate( $args, $assoc_args = array() ) { * * ## OPTIONS * - * <file> + * <file>... * : Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. * If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be * downloaded to a temp file before being sideloaded. * - * --post_id=<post_id> + * [--post_id=<post_id>] * : ID of the post to attach the imported files to * - * --title=<title> + * [--title=<title>] * : Attachment title (post title field) * - * --caption=<caption> + * [--caption=<caption>] * : Caption for attachent (post excerpt field) * - * --alt=<alt_text> + * [--alt=<alt_text>] * : Alt text for image (saved as post meta) * - * --desc=<description> + * [--desc=<description>] * : "Description" field (post content) of attachment post * - * --featured_image + * [--featured_image] * : If set, set the imported image as the Featured Image of the post its attached to. * * ## EXAMPLES @@ -100,8 +100,6 @@ function regenerate( $args, $assoc_args = array() ) { * * # Import an image from the web * wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" - * - * @synopsis <file>... [--post_id=<id>] [--title=<title>] [--caption=<caption>] [--alt=<text>] [--desc=<description>] [--featured_image] */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( From 58d6040951a9385c7cffbca178745ed227626580 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 09:46:11 -0700 Subject: [PATCH 2923/5359] Reduce redundant calls to `is_wp_error()` --- php/commands/media.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 5ce897724..c6f4f7f41 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -145,14 +145,23 @@ function import( $args, $assoc_args = array() ) { // Deletes the temporary file. $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); + if ( is_wp_error( $success ) ) { + WP_CLI::warning( sprintf( + 'Unable to import file %s. Reason: %s', + $orig_filename, implode( ', ', $success->get_error_messages() ) + ) ); + continue; + } // Set alt text - if ( !is_wp_error( $success ) && $assoc_args['alt'] ) + if ( $assoc_args['alt'] ) { update_post_meta( $success, '_wp_attachment_image_alt', $assoc_args['alt'] ); + } // Set as featured image, if --post_id and --featured_image are set - if ( !is_wp_error( $success ) && $assoc_args['post_id'] && isset($assoc_args['featured_image']) ) + if ( $assoc_args['post_id'] && isset( $assoc_args['featured_image'] ) ) { update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); + } $attachment_success_text = ''; if ( $assoc_args['post_id'] ) { @@ -161,17 +170,10 @@ function import( $args, $assoc_args = array() ) { $attachment_success_text .= ' as featured image'; } - if ( is_wp_error( $success ) ) { - WP_CLI::warning( sprintf( - 'Unable to import file %s. Reason: %s', - $orig_filename, implode( ', ', $success->get_error_messages() ) - ) ); - } else { - WP_CLI::success( sprintf( - 'Imported file %s as attachment ID %d%s.', - $orig_filename, $success, $attachment_success_text - ) ); - } + WP_CLI::success( sprintf( + 'Imported file %s as attachment ID %d%s.', + $orig_filename, $success, $attachment_success_text + ) ); } } From 4d21d944fb2fe829e826d922a3f288606aa8696d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 09:54:11 -0700 Subject: [PATCH 2924/5359] Support for `--porcelain` with `wp media import` `--porcelain` makes it much easier to use a new entity in subsequent commands. --- features/media.feature | 14 ++++++++++++++ php/commands/media.php | 15 +++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/features/media.feature b/features/media.feature index ee77d30bc..fa28cff85 100644 --- a/features/media.feature +++ b/features/media.feature @@ -39,3 +39,17 @@ Feature: Manage WordPress attachments and attached to post 1 as featured image """ And the {CACHE_DIR}/large-image.jpg file should exist + + Scenario: Import a file as an attachment but porcelain style + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + + When I run `wp post get {ATTACHMENT_ID} --field=title` + Then STDOUT should be: + """ + My imported attachment + """ \ No newline at end of file diff --git a/php/commands/media.php b/php/commands/media.php index c6f4f7f41..0db379468 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -90,6 +90,9 @@ function regenerate( $args, $assoc_args = array() ) { * [--featured_image] * : If set, set the imported image as the Featured Image of the post its attached to. * + * [--porcelain] + * : Output just the new attachment id. + * * ## EXAMPLES * * # Import all jpgs in the current user's "Pictures" directory, not attached to any post @@ -170,10 +173,14 @@ function import( $args, $assoc_args = array() ) { $attachment_success_text .= ' as featured image'; } - WP_CLI::success( sprintf( - 'Imported file %s as attachment ID %d%s.', - $orig_filename, $success, $attachment_success_text - ) ); + if ( isset( $assoc_args['porcelain'] ) ) { + WP_CLI::line( $success ); + } else { + WP_CLI::success( sprintf( + 'Imported file %s as attachment ID %d%s.', + $orig_filename, $success, $attachment_success_text + ) ); + } } } From 8aa4032e4118fe63020613f443c347fdc9576369 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 10:24:14 -0700 Subject: [PATCH 2925/5359] `wp post generate --post_author=` can accept user login, email address, or ID --- features/post.feature | 12 ++++++++++++ php/commands/post.php | 6 ++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/features/post.feature b/features/post.feature index e1993e1f1..171508d6a 100644 --- a/features/post.feature +++ b/features/post.feature @@ -133,6 +133,18 @@ Feature: Manage WordPress posts """ And STDERR should be empty + Scenario: Generating posts by a specific author + + When I run `wp user create dummyuser dummy@example.com --porcelain` + Then save STDOUT as {AUTHOR_ID} + + When I run `wp post generate --post_author={AUTHOR_ID} --post_type=post --count=16` + And I run `wp post list --post_type=post --author={AUTHOR_ID} --format=count` + Then STDOUT should contain: + """ + 16 + """ + Scenario: Generating pages When I run `wp post generate --post_type=page --max_depth=10` And I run `wp post list --post_type=page --field=post_parent` diff --git a/php/commands/post.php b/php/commands/post.php index 05a2184df..a7c81ec41 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -305,10 +305,8 @@ public function generate( $args, $assoc_args ) { } if ( $post_author ) { - $post_author = get_user_by( 'login', $post_author ); - - if ( $post_author ) - $post_author = $post_author->ID; + $user_fetcher = new \WP_CLI\Fetchers\User; + $post_author = $user_fetcher->get_check( $post_author )->ID; } if ( isset( $assoc_args['post_content'] ) ) { From 7e2a397069231ea1335c76ada7e896e6cd85e3de Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 10:37:19 -0700 Subject: [PATCH 2926/5359] Correct config spec for `--user=<user>` Works with email addresses since 1b04e06fca552b7f400cec7a361da79f0805e2dc --- php/config-spec.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index e4bfa1f5d..519a6880c 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -23,8 +23,8 @@ ), 'user' => array( - 'runtime' => '=<id|login>', - 'file' => '<id|login>', + 'runtime' => '=<id|login|email>', + 'file' => '<id|login|email>', 'desc' => 'Set the WordPress user', ), From 82a63c61f4b327a8b29a557fccb7001eb0ead7a9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 11:13:54 -0700 Subject: [PATCH 2927/5359] When a command is disabled, hide it from the usage docs Hiding disabled commands makes it more clear to the end user as to what's accessible on the system and what's not. --- features/config.feature | 31 +++++++++++++++++++--- php/WP_CLI/Dispatcher/CompositeCommand.php | 6 +++++ php/commands/help.php | 19 +++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/features/config.feature b/features/config.feature index b8711ae2d..e80d86d77 100644 --- a/features/config.feature +++ b/features/config.feature @@ -94,14 +94,39 @@ Feature: Have a config file """ Scenario: Disabled commands - Given an empty directory + Given a WP install And a config.yml file: """ disabled_commands: - - core version + - eval-file + - core multisite-convert + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp` + Then STDOUT should not contain: + """ + eval-file + """ + + When I try `WP_CLI_CONFIG_PATH=config.yml wp help eval-file` + Then STDERR should be: + """ + Error: The 'eval-file' command has been disabled from the config file. + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp core` + Then STDOUT should not contain: + """ + or: wp core multisite-convert + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp help core` + Then STDOUT should not contain: + """ + multisite-convert """ - When I try `WP_CLI_CONFIG_PATH=config.yml wp core version` + When I try `WP_CLI_CONFIG_PATH=config.yml wp core multisite-convert` Then STDERR should contain: """ command has been disabled diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 30e6e0038..dba8053a8 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -139,9 +139,15 @@ public function show_usage() { $i = 0; + $disabled_commands = \WP_CLI::get_runner()->config['disabled_commands']; foreach ( $methods as $name => $subcommand ) { $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; + $path = implode( ' ', array_slice( get_path( $subcommand ), 1 ) ); + if ( in_array( $path, $disabled_commands ) ) { + continue; + } + \WP_CLI::line( $subcommand->get_usage( $prefix ) ); } diff --git a/php/commands/help.php b/php/commands/help.php index 33d1d9e46..0a74f160a 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -22,6 +22,15 @@ function __invoke( $args, $assoc_args ) { $command = self::find_subcommand( $args ); if ( $command ) { + + $full_name = implode( ' ', array_slice( WP_CLI\Dispatcher\get_path( $command ), 1 ) ); + if ( in_array( $full_name , self::get_disabled_commands() ) ) { + WP_CLI::error( sprintf( + "The '%s' command has been disabled from the config file.", + $full_name + ) ); + } + self::show_help( $command ); exit; } @@ -117,6 +126,12 @@ private static function get_initial_markdown( $command ) { private static function render_subcommands( $command ) { $subcommands = array(); foreach ( $command->get_subcommands() as $subcommand ) { + + $path = implode( ' ', array_slice( WP_CLI\Dispatcher\get_path( $subcommand ), 1 ) ); + if ( in_array( $path , self::get_disabled_commands() ) ) { + continue; + } + $subcommands[ $subcommand->get_name() ] = $subcommand->get_shortdesc(); } @@ -140,6 +155,10 @@ private static function get_max_len( $strings ) { return $max_len; } + + private static function get_disabled_commands() { + return WP_CLI::get_runner()->config['disabled_commands']; + } } WP_CLI::add_command( 'help', 'Help_Command' ); From 253cbc63f8450bd69a453a608fae1b684605e3c4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 6 May 2014 11:25:50 -0700 Subject: [PATCH 2928/5359] Better abstraction for checking whether a command is disabled --- features/config.feature | 6 ++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 4 +--- php/WP_CLI/Runner.php | 14 +++++++++++--- php/commands/help.php | 12 ++++-------- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/features/config.feature b/features/config.feature index e80d86d77..3ed1e17aa 100644 --- a/features/config.feature +++ b/features/config.feature @@ -132,6 +132,12 @@ Feature: Have a config file command has been disabled """ + When I try `WP_CLI_CONFIG_PATH=config.yml wp help core multisite-convert` + Then STDERR should contain: + """ + Error: The 'core multisite-convert' command has been disabled from the config file. + """ + Scenario: 'core config' parameters Given an empty directory And WP files diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index dba8053a8..77cad3905 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -139,12 +139,10 @@ public function show_usage() { $i = 0; - $disabled_commands = \WP_CLI::get_runner()->config['disabled_commands']; foreach ( $methods as $name => $subcommand ) { $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - $path = implode( ' ', array_slice( get_path( $subcommand ), 1 ) ); - if ( in_array( $path, $disabled_commands ) ) { + if ( \WP_CLI::get_runner()->is_command_disabled( $subcommand ) ) { continue; } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 76419a541..e7e48a97e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -251,8 +251,6 @@ public function find_command_to_run( $args ) { $cmd_path = array(); - $disabled_commands = $this->config['disabled_commands']; - while ( !empty( $args ) && $command->can_have_subcommands() ) { $cmd_path[] = $args[0]; $full_name = implode( ' ', $cmd_path ); @@ -266,7 +264,7 @@ public function find_command_to_run( $args ) { ); } - if ( in_array( $full_name, $disabled_commands ) ) { + if ( $this->is_command_disabled( $subcommand ) ) { return sprintf( "The '%s' command has been disabled from the config file.", $full_name @@ -313,6 +311,16 @@ private function _run_command() { $this->run_command( $this->arguments, $this->assoc_args ); } + /** + * Check whether a given command is disabled by the config + * + * @return bool + */ + public function is_command_disabled( $command ) { + $path = implode( ' ', array_slice( \WP_CLI\Dispatcher\get_path( $command ), 1 ) ); + return in_array( $path, $this->config['disabled_commands'] ); + } + /** * Returns wp-config.php code, skipping the loading of wp-settings.php * diff --git a/php/commands/help.php b/php/commands/help.php index 0a74f160a..f8c7d9d9f 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -23,11 +23,11 @@ function __invoke( $args, $assoc_args ) { if ( $command ) { - $full_name = implode( ' ', array_slice( WP_CLI\Dispatcher\get_path( $command ), 1 ) ); - if ( in_array( $full_name , self::get_disabled_commands() ) ) { + if ( WP_CLI::get_runner()->is_command_disabled( $command ) ) { + $path = implode( ' ', array_slice( \WP_CLI\Dispatcher\get_path( $command ), 1 ) ); WP_CLI::error( sprintf( "The '%s' command has been disabled from the config file.", - $full_name + $path ) ); } @@ -127,8 +127,7 @@ private static function render_subcommands( $command ) { $subcommands = array(); foreach ( $command->get_subcommands() as $subcommand ) { - $path = implode( ' ', array_slice( WP_CLI\Dispatcher\get_path( $subcommand ), 1 ) ); - if ( in_array( $path , self::get_disabled_commands() ) ) { + if ( WP_CLI::get_runner()->is_command_disabled( $subcommand ) ) { continue; } @@ -156,9 +155,6 @@ private static function get_max_len( $strings ) { return $max_len; } - private static function get_disabled_commands() { - return WP_CLI::get_runner()->config['disabled_commands']; - } } WP_CLI::add_command( 'help', 'Help_Command' ); From b916290d2d2bc3e869f97258caa37fe62748ac77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Fri, 9 May 2014 13:47:11 +0200 Subject: [PATCH 2929/5359] bash solution for setting array value --- utils/wp-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index bc109024a..ac7e99250 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -10,7 +10,7 @@ _wp_complete() { then COMPREPLY=( $(compgen -f -- $cur) ) else - COMPREPLY=$opts + COMPREPLY=( ${opts[*]} ) fi } complete -o nospace -F _wp_complete wp From 37e21459696bd569bc3bc46461a9ec8a3522ad09 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sun, 11 May 2014 16:16:01 -0400 Subject: [PATCH 2930/5359] Make sure widget at index=0 is removed from sidebar when deactivated Without this change, deactivating a widget at the beginning of a widget area will appear twice, once in the original sidebar and again in the Inactive Widgets sidebar. --- php/commands/widget.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 5a5ec7a05..f0b01d547 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -406,9 +406,9 @@ private function update_widget_options( $name, $value ) { * Reposition a widget within a sidebar * * @param string $widget_id - * @param string $current_sidebar_id + * @param string|null $current_sidebar_id * @param string $new_sidebar_id - * @param int $current_index + * @param int|null $current_index * @param int $new_index */ private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_sidebar_id, $current_index, $new_index ) { @@ -416,10 +416,10 @@ private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_side $all_widgets = $this->wp_get_sidebars_widgets(); $needs_placement = true; // Existing widget - if ( $current_sidebar_id && $current_index ) { + if ( $current_sidebar_id && ! is_null( $current_index ) ) { $widgets = $all_widgets[ $current_sidebar_id ]; - if ( $current_sidebar_id != $new_sidebar_id ) { + if ( $current_sidebar_id !== $new_sidebar_id ) { unset( $widgets[ $current_index ] ); From a44af937bb8104bffcff8f9efe6e2fa9b96e42df Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@x-team.com> Date: Sun, 11 May 2014 16:36:18 -0400 Subject: [PATCH 2931/5359] Update move_sidebar_widget DocBlock Indicate that it also moves to another sidebar --- php/commands/widget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index f0b01d547..6687265f2 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -403,7 +403,7 @@ private function update_widget_options( $name, $value ) { } /** - * Reposition a widget within a sidebar + * Reposition a widget within a sidebar or move to another sidebar. * * @param string $widget_id * @param string|null $current_sidebar_id From 103bf8891293062a4527833bf066aa7e244781b2 Mon Sep 17 00:00:00 2001 From: Matthew Boynes <mboynes@alleyinteractive.com> Date: Tue, 13 May 2014 13:12:17 -0400 Subject: [PATCH 2932/5359] Fixing typo in menu bulk deleting --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 55191c8db..adc6ab2f0 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -74,7 +74,7 @@ public function delete( $args, $_ ) { foreach( $args as $arg ) { - $ret = wp_delete_nav_menu( $args[0] ); + $ret = wp_delete_nav_menu( $arg ); if ( ! $ret || is_wp_error( $ret ) ) { From a9337705744859ad388512c8a716ea77b798a0d6 Mon Sep 17 00:00:00 2001 From: Matthew Boynes <mboynes@alleyinteractive.com> Date: Tue, 13 May 2014 14:01:01 -0400 Subject: [PATCH 2933/5359] Add tests for deleting multiple menu items --- features/menu.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 75753186c..68a412663 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -86,3 +86,10 @@ Feature: Manage WordPress menus """ 2 """ + + When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` + And I run `wp menu item list sidebar-menu --format=count` + Then STDOUT should be: + """ + 0 + """ From c582fa3bf2d62e18de12d124e561a3da80ef9bdf Mon Sep 17 00:00:00 2001 From: Matt Boynes <mboynes@alleyinteractive.com> Date: Tue, 13 May 2014 14:18:38 -0400 Subject: [PATCH 2934/5359] Adding tests for deleting multiple menus --- features/menu.feature | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 68a412663..b350f094d 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -18,6 +18,21 @@ Feature: Manage WordPress menus 0 """ + When I run `wp menu create "First Menu"` + And I run `wp menu create "Second Menu"` + And I run `wp menu list --fields=name,slug` + Then STDOUT should be a table containing rows: + | name | slug | + | First Menu | first-menu | + | Second Menu | second-menu | + + When I run `wp menu delete "First Menu" "Second Menu"` + And I run `wp menu list --format=count` + Then STDOUT should be: + """ + 0 + """ + Scenario: Assign / remove location from a menu When I run `wp theme install p2 --activate` From b8bdfe135fec022ae25c74092d7e461c9a6fb7d8 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Wed, 14 May 2014 10:32:37 -0400 Subject: [PATCH 2935/5359] Use foreach loop rather than array_map() to invoke do_hook() callbacks array_map( 'call_user_func', $hooks ) causes segmentation faults on PHP 5.5.12. --- php/class-wp-cli.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e6dbe54f6..d2e34b754 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -151,7 +151,9 @@ static function do_hook( $when ) { if ( !isset( self::$hooks[ $when ] ) ) return; - array_map( 'call_user_func', self::$hooks[ $when ] ); + foreach ( self::$hooks[ $when ] as $callback ) { + call_user_func( $callback ); + } } /** From c9e15fe62dae5f030f89f7cf355d96a55f56594e Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Wed, 14 May 2014 10:59:22 -0400 Subject: [PATCH 2936/5359] Add PHP 5.5 to travis-ci test matrix. See #1208 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 85086d37a..2f16bc2ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 5.3 # WP-CLI currently fails on PHP 5.5.11, which Travis is using - 5.4 + - 5.5 env: global: From a97e72c0a9deaa8d3e02d9d1fecebaaa2b573e3d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 May 2014 15:28:52 -0700 Subject: [PATCH 2937/5359] Update matrix to properly test PHP 5.5, but only run three tests instead of five Fixes #1178 --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2f16bc2ba..3e6f78d2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: php php: - 5.3 - # WP-CLI currently fails on PHP 5.5.11, which Travis is using - - 5.4 - 5.5 env: @@ -39,7 +37,7 @@ env: matrix: exclude: - - php: 5.4 + - php: 5.5 env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From 8e90243ce179a589ca7f505f21b6c21e5353d831 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 15 May 2014 09:21:02 -0700 Subject: [PATCH 2938/5359] Update current version [ci-skip] --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index f9615aded..485cececd 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.15.0' ); +define( 'WP_CLI_VERSION', '0.15.1' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From e1e241721aa2ac9a8cea1bda87bde48530590480 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 15 May 2014 09:23:04 -0700 Subject: [PATCH 2939/5359] Add example for deleting all spam comments See #1209 [ci-skip] --- php/commands/comment.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index 8c19ed0a7..6a014cefd 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -3,6 +3,11 @@ /** * Manage comments. * + * ## EXAMPLES + * + * # delete all spam comments. + * wp comment delete $(wp comment list --status=spam --format=ids) + * * @package wp-cli */ class Comment_Command extends \WP_CLI\CommandWithDBObject { From 48958885f579ec5f2bb9e8858ba6392769c91ba4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 18 May 2014 09:56:50 -0700 Subject: [PATCH 2940/5359] Add `--format=ids` support to `wp widget list` --- features/widget.feature | 6 ++++++ php/commands/widget.php | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/features/widget.feature b/features/widget.feature index b5c731761..610d963ea 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -68,6 +68,12 @@ Feature: Manage widgets in WordPress sidebar | calendar | calendar-1 | 2 | | categories | categories-2 | 3 | + When I run `wp widget list sidebar-1 --format=ids` + Then STDOUT should be: + """ + search-2 calendar-1 categories-2 + """ + When I run `wp widget update calendar-1 --title="Calendar"` Then STDOUT should not be empty diff --git a/php/commands/widget.php b/php/commands/widget.php index 6687265f2..32924b557 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -37,7 +37,7 @@ class Widget_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to name, id, description * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, ids. Default: table * * ## EXAMPLES * @@ -59,6 +59,10 @@ public function list_( $args, $assoc_args ) { } } + if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { + $output_widgets = wp_list_pluck( $output_widgets, 'id' ); + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); $formatter->display_items( $output_widgets ); From 4f5e0271a8b42ed04bb3a38fa73846b922dda554 Mon Sep 17 00:00:00 2001 From: joshlevinson <joshalevinson@gmail.com> Date: Mon, 19 May 2014 14:54:30 -0400 Subject: [PATCH 2941/5359] Create a valid local file location vs a URL I got this fatal error when trying to utilize a cached "wp core download": PHP Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Cannot create a phar archive from a URL like "C://Users/xxx/.wp-cli/cache/core/en_US-3.9.1.tar.gz". Phar objects can only be created from local files' in C:\Users\xxx\wp-cli\php\commands\core.php:93 I'm not sure if my pull is the best solution, but the comments seem to suggest that $home is only manually constructed on Windows, so removing the middle slash may work for everyone. It did for me. After making this change and running the command again, all was well. I'm using PHP 5.5.9.0 on Windows 8.1. --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d2e34b754..47bcfc6e9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -70,7 +70,7 @@ public static function get_cache() { $home = getenv( 'HOME' ); if ( !$home ) { // sometime in windows $HOME is not defined - $home = getenv( 'HOMEDRIVE' ) . '/' . getenv( 'HOMEPATH' ); + $home = getenv( 'HOMEDRIVE' ) . getenv( 'HOMEPATH' ); } $dir = getenv( 'WP_CLI_CACHE_DIR' ) ? : "$home/.wp-cli/cache"; From 262f19117c7ac7b6711b55519e14d1e636da1142 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 May 2014 16:52:16 -0700 Subject: [PATCH 2942/5359] Clarify `wp user list --<field>=<value>` See https://github.com/wp-cli/wp-cli/issues/1213#issuecomment-43615946 [ci-skip] --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 81bca8f40..7e3ca9cd5 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -30,7 +30,7 @@ public function __construct() { * : Only display users with a certain role. * * [--<field>=<value>] - * : Filter by one or more fields. For accepted fields, see get_users(). + * : Control output by one or more arguments of get_users(). * * [--field=<field>] * : Prints the value of a single field for each user. From 241e57b2e0a65dad4992d8ceea2fced4a87c225a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 13:08:14 -0700 Subject: [PATCH 2943/5359] Throw a warning when rewrite rules end up empty after flushing This has tripped me up more than once, and I'm sure it trips up others. --- features/rewrite.feature | 18 ++++++++++++++++++ php/commands/rewrite.php | 3 +++ 2 files changed, 21 insertions(+) diff --git a/features/rewrite.feature b/features/rewrite.feature index f78c8504e..6ab22a61e 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -34,6 +34,24 @@ Feature: Manage WordPress rewrites | match | query | source | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | + Scenario: Missing permalink_structure + Given a WP install + + When I run `wp option delete permalink_structure` + And I try `wp option get permalink_structure` + Then STDOUT should be empty + + When I try `wp rewrite flush` + Then STDERR should contain: + """ + Warning: Rewrite rules are empty, possibly because of a missing permalink_structure option. + """ + And STDOUT should be empty + + When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` + Then I run `wp rewrite flush` + Then STDOUT should be empty + Scenario: Generate .htaccess on hard flush Given a WP install And a wp-cli.yml file: diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 8b380afbd..ccaffbc2b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -32,6 +32,9 @@ public function flush( $args, $assoc_args ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); } flush_rewrite_rules( isset( $assoc_args['hard'] ) ); + if ( ! get_option( 'rewrite_rules' ) ) { + WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); + } } /** From d36519aee0531f820afd6fa0ffa68977785288ac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 13:26:48 -0700 Subject: [PATCH 2944/5359] Properly catch exporter exceptions, and throw an error if we run into one --- features/export.feature | 12 ++++++++++++ php/commands/export.php | 22 +++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/features/export.feature b/features/export.feature index f0bcfa85c..593ad6544 100644 --- a/features/export.feature +++ b/features/export.feature @@ -8,3 +8,15 @@ Feature: Export content. """ All done with export """ + + Scenario: Term with a non-existent parent + Given a WP install + + When I run `wp term create category Apple --parent=99 --porcelain` + Then STDOUT should be a number + + When I try `wp export` + Then STDERR should be: + """ + Error: Term is missing a parent. + """ diff --git a/php/commands/export.php b/php/commands/export.php index 31d9d84e2..5af133174 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -78,15 +78,19 @@ public function __invoke( $_, $assoc_args ) { WP_CLI::log( sprintf( "Writing to file %s", $file_path ) ); } ); - wp_export( array( - 'filters' => $this->export_args, - 'writer' => 'WP_Export_Split_Files_Writer', - 'writer_args' => array( - 'max_file_size' => $this->max_file_size * MB_IN_BYTES, - 'destination_directory' => $this->wxr_path, - 'filename_template' => self::get_filename_template() - ) - ) ); + try { + wp_export( array( + 'filters' => $this->export_args, + 'writer' => 'WP_Export_Split_Files_Writer', + 'writer_args' => array( + 'max_file_size' => $this->max_file_size * MB_IN_BYTES, + 'destination_directory' => $this->wxr_path, + 'filename_template' => self::get_filename_template() + ) + ) ); + } catch ( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } WP_CLI::success( 'All done with export.' ); } From e8fb64d1996e6181f210ed202c2b93f6e90725c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 13:33:19 -0700 Subject: [PATCH 2945/5359] Coding standards --- php/commands/export.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 5af133174..9984d5fc0 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -97,7 +97,9 @@ public function __invoke( $_, $assoc_args ) { private static function get_filename_template() { $sitename = sanitize_key( get_bloginfo( 'name' ) ); - if ( ! empty($sitename) ) $sitename .= '.'; + if ( ! empty( $sitename ) ) { + $sitename .= '.'; + } return $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.%d.xml'; } From 9a70cc28c4d64225d615b31d453b88aa0a87aa9a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 13:36:11 -0700 Subject: [PATCH 2946/5359] Correct typo --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 9984d5fc0..7584ab40d 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -181,7 +181,7 @@ private function check_post_type( $post_type ) { $post_types = get_post_types(); if ( !in_array( $post_type, $post_types ) ) { - WP_CLI::warning( sprintf( 'The post type %s does not exists. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); + WP_CLI::warning( sprintf( 'The post type %s does not exist. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); return false; } $this->export_args['post_type'] = $post_type; From 79fc4df82ced8ba3bb26d9a59a5168e0c753b941 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 13:41:06 -0700 Subject: [PATCH 2947/5359] Add tests for argument validator --- features/export.feature | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/features/export.feature b/features/export.feature index 593ad6544..5d3c55eda 100644 --- a/features/export.feature +++ b/features/export.feature @@ -20,3 +20,30 @@ Feature: Export content. """ Error: Term is missing a parent. """ + + Scenario: Export argument validator + Given a WP install + + When I try `wp export --post_type=wp-cli-party` + Then STDERR should contain: + """ + Warning: The post type wp-cli-party does not exist. + """ + + When I try `wp export --author=invalid-author` + Then STDERR should contain: + """ + Warning: Could not find a matching author for invalid-author + """ + + When I try `wp export --start_date=invalid-date` + Then STDERR should contain: + """ + Warning: The start_date invalid-date is invalid + """ + + When I try `wp export --end_date=invalid-date` + Then STDERR should contain: + """ + Warning: The end_date invalid-date is invalid + """ From 9a956cde79ae98a3687c6ad7f7bdebe4f41245bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 14:31:06 -0700 Subject: [PATCH 2948/5359] Clarify argument --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 7584ab40d..bc6fa3d19 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -32,7 +32,7 @@ class Export_Command extends WP_CLI_Command { * : Export only posts older than this date, in format YYYY-MM-DD. * * [--post_type=<post-type>] - * : Export only posts with this post_type. + * : Export only posts with this post_type. Defaults to all. * * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. From 8d936b609f54d60647e867017e3bea2d41d57915 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 14:46:07 -0700 Subject: [PATCH 2949/5359] Update Behat `Given` with support for specifying installed / active plugins --- features/steps/given.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/steps/given.php b/features/steps/given.php index 21117c55b..ea581d159 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -61,6 +61,13 @@ function ( $world ) { } ); +$steps->Given( '/^these installed and active plugins:(.+)$/', + function( $world, $plugins ) { + $plugins = implode( ' ', array_map( 'trim', explode( ',', $plugins ) ) ); + $world->proc( "wp plugin install $plugins --activate" )->run_check(); + } +); + $steps->Given( '/^a custom wp-content directory$/', function ( $world ) { $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; From 336eef9a0b14a974e65b49bcc375ffc8303b145d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 14:54:11 -0700 Subject: [PATCH 2950/5359] Clarify these arguments --- php/commands/export.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index bc6fa3d19..987dcdbc9 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -26,10 +26,10 @@ class Export_Command extends WP_CLI_Command { * ## FILTERS * * [--start_date=<date>] - * : Export only posts newer than this date, in format YYYY-MM-DD. + * : Export only posts published after this date, in format YYYY-MM-DD. * * [--end_date=<date>] - * : Export only posts older than this date, in format YYYY-MM-DD. + * : Export only posts published before this date, in format YYYY-MM-DD. * * [--post_type=<post-type>] * : Export only posts with this post_type. Defaults to all. From fc145ec8b1e6f055b8fa090b6564612a700b42c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 May 2014 14:54:29 -0700 Subject: [PATCH 2951/5359] Add some tests for exporting with filters --- features/export.feature | 68 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/features/export.feature b/features/export.feature index 5d3c55eda..c202dd756 100644 --- a/features/export.feature +++ b/features/export.feature @@ -47,3 +47,71 @@ Feature: Export content. """ Warning: The end_date invalid-date is invalid """ + + Scenario: Export with post_type and post_status argument + Given a WP install + And these installed and active plugins: wordpress-importer + + When I run `wp site empty --yes` + And I run `wp post generate --post_type=page --post_status=draft --count=10` + And I run `wp post list --post_type=page --post_status=draft --format=count` + Then STDOUT should be: + """ + 10 + """ + + When I run `wp export --post_type=page --post_status=draft` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --post_status=draft --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --post_status=draft --format=count` + Then STDOUT should be: + """ + 10 + """ + + Scenario: Export posts within a given date range + Given a WP install + And these installed and active plugins: wordpress-importer + + When I run `wp site empty --yes` + And I run `wp post generate --post_type=post --post_date=2013-08-01 --count=10` + And I run `wp post generate --post_type=post --post_date=2013-08-02 --count=10` + And I run `wp post generate --post_type=post --post_date=2013-08-03 --count=10` + And I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 30 + """ + + When I run `wp export --post_type=post --start_date=2013-08-02 --end_date=2013-08-02` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 10 + """ From 44e4246ccf41097d3142072181bd8bdffa9c3c72 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 22 May 2014 05:50:07 -0700 Subject: [PATCH 2952/5359] This syntax is more consistent with our existing configuration --- features/export.feature | 10 ++++++++-- features/steps/given.php | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/features/export.feature b/features/export.feature index c202dd756..7ff5f118b 100644 --- a/features/export.feature +++ b/features/export.feature @@ -50,7 +50,10 @@ Feature: Export content. Scenario: Export with post_type and post_status argument Given a WP install - And these installed and active plugins: wordpress-importer + And these installed and active plugins: + """ + wordpress-importer + """ When I run `wp site empty --yes` And I run `wp post generate --post_type=page --post_status=draft --count=10` @@ -83,7 +86,10 @@ Feature: Export content. Scenario: Export posts within a given date range Given a WP install - And these installed and active plugins: wordpress-importer + And these installed and active plugins: + """ + wordpress-importer + """ When I run `wp site empty --yes` And I run `wp post generate --post_type=post --post_date=2013-08-01 --count=10` diff --git a/features/steps/given.php b/features/steps/given.php index ea581d159..8fa71cf42 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -61,9 +61,9 @@ function ( $world ) { } ); -$steps->Given( '/^these installed and active plugins:(.+)$/', - function( $world, $plugins ) { - $plugins = implode( ' ', array_map( 'trim', explode( ',', $plugins ) ) ); +$steps->Given( '/^these installed and active plugins:$/', + function( $world, $stream ) { + $plugins = implode( ' ', array_map( 'trim', explode( PHP_EOL, (string)$stream ) ) ); $world->proc( "wp plugin install $plugins --activate" )->run_check(); } ); From 295c9938934104d11e5dd22abf3e97e99ae20f3e Mon Sep 17 00:00:00 2001 From: Leonardo Santagada <santagada@gmail.com> Date: Sun, 8 Jun 2014 21:38:23 -0300 Subject: [PATCH 2953/5359] change data directly in mysql for some tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit search-replace on tables that don’t contain serialised data can be changed directly in mysql --- php/commands/search-replace.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e6a8739df..384162839 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -78,7 +78,10 @@ public function __invoke( $args, $assoc_args ) { if ( in_array( $col, $skip_columns ) ) continue; - $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + if ( substr( $table, -9 ) == '_comments' || substr( $table, -6 ) == '_posts' ) { + $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); + } else + $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); $report[] = array( $table, $col, $count ); @@ -106,6 +109,15 @@ private static function get_table_list( $args, $network ) { return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } + private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { + global $wpdb; + + if ( $dry_run ) + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); + else + return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + } + private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { global $wpdb; From ce49db72d7f62d864d23e389b93e3e6008a2e009 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 15 Jun 2014 16:34:25 -0600 Subject: [PATCH 2954/5359] Clarify method See #1231 --- php/class-wp-cli.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 47bcfc6e9..ea54f18c0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -394,6 +394,12 @@ static function launch_self( $command, $args = array(), $assoc_args = array(), $ return self::launch( $full_command, $exit_on_error ); } + /** + * Get the path to the PHP binary used when executing WP-CLI. + * Environment values permit specific binaries to be indicated. + * + * @return string + */ private static function get_php_binary() { if ( defined( 'PHP_BINARY' ) ) return PHP_BINARY; From 79190a0ac8aed2a391081191d22dcdfe79176a3e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 18 Jun 2014 14:51:58 -0700 Subject: [PATCH 2955/5359] If the plugins directory doesn't exist, create it before installing --- features/plugin.feature | 15 +++++++++++++++ php/commands/plugin.php | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index a683999dd..1794657fb 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -155,3 +155,18 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | | akismet | active | + + Scenario: Install a plugin when directory doesn't yet exist + Given a WP install + + When I run `rm -rf wp-content/plugins` + And I run `if test -d wp-content/plugins; then echo "fail"; fi` + Then STDOUT should be empty + + When I run `wp plugin activate akismet hello` + Then STDOUT should not be empty + + When I run `wp plugin list --status=active --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | akismet | active | diff --git a/php/commands/plugin.php b/php/commands/plugin.php index bb4e5eaad..873acffe8 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -366,6 +366,11 @@ protected function filter_item_list( $items, $args ) { * wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef */ function install( $args, $assoc_args ) { + + if ( ! is_dir( WP_PLUGIN_DIR ) ) { + wp_mkdir_p( WP_PLUGIN_DIR ); + } + parent::install( $args, $assoc_args ); } From 888cbd8cf0f1bf6354cf5183e8cc0bcaaadfc401 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 19 Jun 2014 15:36:38 -0700 Subject: [PATCH 2956/5359] Fix copy pasta --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 1794657fb..f77be4619 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -163,7 +163,7 @@ Feature: Manage WordPress plugins And I run `if test -d wp-content/plugins; then echo "fail"; fi` Then STDOUT should be empty - When I run `wp plugin activate akismet hello` + When I run `wp plugin install akismet hello` Then STDOUT should not be empty When I run `wp plugin list --status=active --fields=name,status` From fb236b79a2773fa40d363022e55164148b9256d2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 19 Jun 2014 15:45:53 -0700 Subject: [PATCH 2957/5359] Support for automagically creating the theme directory too --- features/theme.feature | 15 +++++++++++++++ php/commands/theme.php | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 76ef76a82..27613ee39 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -93,6 +93,21 @@ Feature: Manage WordPress themes wp-content/themes/p2 """ + Scenario: Install a theme when the theme directory doesn't yet exist + Given a WP install + + When I run `rm -rf wp-content/themes` + And I run `if test -d wp-content/themes; then echo "fail"; fi` + Then STDOUT should be empty + + When I run `wp theme install p2 --activate` + Then STDOUT should not be empty + + When I run `wp theme list --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | p2 | active | + Scenario: Enabling and disabling a theme Given a WP multisite install diff --git a/php/commands/theme.php b/php/commands/theme.php index d3fa8fe6e..2bc92e687 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -371,6 +371,12 @@ protected function filter_item_list( $items, $args ) { * wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef */ function install( $args, $assoc_args ) { + + $theme_root = get_theme_root(); + if ( $theme_root && ! is_dir( $theme_root ) ) { + wp_mkdir_p( $theme_root ); + } + parent::install( $args, $assoc_args ); } From bb61b085e58fedfc47865b97adbc2b1cd5d439cd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 19 Jun 2014 16:25:48 -0700 Subject: [PATCH 2958/5359] Allow updating core directly from a ZIP file Previously, updating core from a ZIP file also required passing `--version` --- php/commands/core.php | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ea3c8e3f4..bf9a0a75a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -691,31 +691,44 @@ function update( $args, $assoc_args ) { $update = $from_api = null; $upgrader = 'Core_Upgrader'; - if ( empty( $assoc_args['version'] ) ) { + if ( ! empty( $args[0] ) ) { + + $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; + $version = ! empty( $assoc_args['version'] ) ? $assoc_args['version'] : null; + + $update = (object) array( + 'response' => 'upgrade', + 'current' => $version, + 'download' => $args[0], + 'packages' => (object) array ( + 'partial' => null, + 'new_bundled' => null, + 'no_content' => null, + 'full' => $args[0], + ), + 'version' => $version, + ); + + } else if ( empty( $assoc_args['version'] ) ) { + wp_version_check(); $from_api = get_site_transient( 'update_core' ); - if ( empty( $from_api->updates ) ) + if ( empty( $from_api->updates ) ) { $update = false; - else + } else { list( $update ) = $from_api->updates; + } } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) || isset( $assoc_args['force'] ) ) { - $new_package = $version = null; - - if ( empty( $args[0] ) ) { - $version = $assoc_args['version']; - $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); + $version = $assoc_args['version']; + $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); - $new_package = $this->get_download_url($version, $locale); + $new_package = $this->get_download_url($version, $locale); - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $locale ) ); - } else { - $new_package = $args[0]; - $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; - } + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $locale ) ); $update = (object) array( 'response' => 'upgrade', From 0f4c8d750631c91ef97c4820233d3dd4dd0b543d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 19 Jun 2014 16:40:16 -0700 Subject: [PATCH 2959/5359] Test coverage for permitting updates from file without specifying version --- features/core.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/features/core.feature b/features/core.feature index f8b363b0d..1d537e434 100644 --- a/features/core.feature +++ b/features/core.feature @@ -232,6 +232,34 @@ Feature: Manage WordPress installation example.com """ + Scenario: Update from a ZIP file + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp eval 'echo $GLOBALS["wp_version"];'` + Then STDOUT should be: + """ + 3.8 + """ + + When I run `wget http://wordpress.org/wordpress-3.9.zip --quiet` + Then STDOUT should be empty + + When I run `wp core update wordpress-3.9.zip` + Then STDOUT should be: + """ + Unpacking the update... + Success: WordPress updated successfully. + """ + + When I run `wp eval 'echo $GLOBALS["wp_version"];'` + Then STDOUT should be: + """ + 3.9 + """ + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory From 2899f71ddecbf54e0f6af35b5755d7f28fc1c61b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 23 Jun 2014 19:08:42 -0700 Subject: [PATCH 2960/5359] Fix silly copy and paste error again. `hello` exists in WP.org as `hello-dolly` --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index f77be4619..78026726a 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -163,7 +163,7 @@ Feature: Manage WordPress plugins And I run `if test -d wp-content/plugins; then echo "fail"; fi` Then STDOUT should be empty - When I run `wp plugin install akismet hello` + When I run `wp plugin install akismet --activate` Then STDOUT should not be empty When I run `wp plugin list --status=active --fields=name,status` From b6d69f775a740f181b438ce4c48795ce7247e581 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 23 Jun 2014 19:39:32 -0700 Subject: [PATCH 2961/5359] Need to register the theme directory after it's been created --- php/commands/theme.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 2bc92e687..35410a175 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -375,6 +375,7 @@ function install( $args, $assoc_args ) { $theme_root = get_theme_root(); if ( $theme_root && ! is_dir( $theme_root ) ) { wp_mkdir_p( $theme_root ); + register_theme_directory( $theme_root ); } parent::install( $args, $assoc_args ); From b4b8a7301d7a5b52e2fd90a7d5cb4e907ab6c85f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 23 Jun 2014 20:05:59 -0700 Subject: [PATCH 2962/5359] List meta for an object, demo commit --- php/WP_CLI/CommandWithMeta.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index f09d9fbcd..e543d73cc 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -11,6 +11,26 @@ abstract class CommandWithMeta extends \WP_CLI_Command { protected $meta_type; + /** + * List all metadata associated with an object. + * + * <id> + * : ID for the object. + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + list( $object_id ) = $args; + + $values = get_metadata( $this->meta_type, $object_id ); + + $values = wp_cache_get( $object_id, 'post_meta' ); + + error_log( var_export( $values, true ) ); + + } + /** * Get meta field value. * From 43d24a813dac0d2c8cdc8c357039fb26ffbf71e2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 23 Jun 2014 21:07:15 -0700 Subject: [PATCH 2963/5359] Special treatment for JSON, and tests that fail because meta_value isn't unserialized --- features/user.feature | 25 ++++++++++++++++++ php/WP_CLI/CommandWithMeta.php | 47 ++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index a50e3bb3a..9ce4273e5 100644 --- a/features/user.feature +++ b/features/user.feature @@ -253,3 +253,28 @@ Feature: Manage WordPress users """ Success: Removed 'edit_vip_product' cap for admin (1). """ + + @ticket + Scenario: List user meta + Given a WP install + + When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` + Then STDOUT should not be empty + + When I run `wp user-meta list 1 --format=json --keys=nickname,foo` + Then STDOUT should be JSON containing: + """ + { + "nickname": "admin", + "foo": ["1","2"] + } + """ + + When I run `wp user-meta list 1 --format=csv --keys=nickname,foo` + Then STDOUT should be CSV containing: + """ + | meta_key | meta_value | + | nickname | admin | + | foo | ["1","2"] | + """ + diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index e543d73cc..5be394d29 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -17,17 +17,60 @@ abstract class CommandWithMeta extends \WP_CLI_Command { * <id> * : ID for the object. * + * [--keys=<keys>] + * : Limit output to metadata of specific keys. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * * @subcommand list */ public function list_( $args, $assoc_args ) { list( $object_id ) = $args; + $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); + $values = get_metadata( $this->meta_type, $object_id ); - $values = wp_cache_get( $object_id, 'post_meta' ); + foreach( $values as $meta_key => $meta_value ) { + + if ( ! empty( $keys ) && ! in_array( $meta_key, $keys ) ) { + unset( $values[ $meta_key ] ); + continue; + } + + if ( count( $values[ $meta_key ] ) == 1 ) { + $values[ $meta_key ] = $values[ $meta_key ][ 0 ]; + } + + } + + // Special treatment for JSON + if ( ! empty( $assoc_args['format'] ) && 'json' === $assoc_args['format'] ) { - error_log( var_export( $values, true ) ); + echo json_encode( $values ); + + } else { + + foreach( $values as $meta_key => $meta_value ) { + + $items = array(); + if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) ) { + $meta_value = json_encode( $meta_value ); + } + + $items[] = (object) array( + 'meta_key' => $meta_key, + 'meta_value' => $meta_value, + ); + + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'meta_key', 'meta_value' ), $this->meta_type ); + $formatter->display_items( $items ); + + } } From 64974979c0b71f18359415ca55ca3026cef468b1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 11:42:00 -0700 Subject: [PATCH 2964/5359] Throw warnings if the plugin is already active --- php/commands/plugin.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 873acffe8..cffdf77fd 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -142,6 +142,16 @@ function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + + $status = $this->get_status( $plugin->file ); + if ( ! $network_wide && 'active' === $status ) { + WP_CLI::warning( "The '{$plugin->name}' plugin is already active." ); + continue; + } else if ( $network_wide && 'activate-network' === $status ) { + WP_CLI::warning( "The '{$plugin->name}' plugin is already network active." ); + continue; + } + activate_plugin( $plugin->file, '', $network_wide ); $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); From 516fddb801cc439a298f171b6f32546ef1a84b58 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 12:59:25 -0700 Subject: [PATCH 2965/5359] When a given theme is already active, provide a contextually appropriate message Also prevents triggering of `switch_theme()` if the theme is already activated. --- features/theme.feature | 18 ++++++++++++++++++ php/commands/theme.php | 9 +++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 27613ee39..6ad011a7e 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -93,6 +93,24 @@ Feature: Manage WordPress themes wp-content/themes/p2 """ + Scenario: Activate an already active theme + Given a WP install + + When I run `wp theme install p2` + Then STDOUT should not be empty + + When I run `wp theme activate p2` + Then STDOUT should be: + """ + Success: Switched to 'P2' theme. + """ + + When I run `wp theme activate p2` + Then STDOUT should be: + """ + Success: The 'P2' theme is already active. + """ + Scenario: Install a theme when the theme directory doesn't yet exist Given a WP install diff --git a/php/commands/theme.php b/php/commands/theme.php index 35410a175..3fd58af36 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -121,10 +121,15 @@ protected function get_status( $theme ) { public function activate( $args = array() ) { $theme = $this->fetcher->get_check( $args[0] ); - switch_theme( $theme->get_template(), $theme->get_stylesheet() ); - $name = $theme->get('Name'); + if ( 'active' === $this->get_status( $theme ) ) { + WP_CLI::success( "The '$name' theme is already active." ); + exit; + } + + switch_theme( $theme->get_template(), $theme->get_stylesheet() ); + if ( $this->is_active_theme( $theme ) ) { WP_CLI::success( "Switched to '$name' theme." ); } else { From 56736ce61c5c435811a2c69ce7bc4a0cbadb6b76 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 13:09:34 -0700 Subject: [PATCH 2966/5359] Messaging more consistent with the rest of `wp plugin` --- php/commands/plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index cffdf77fd..0dff24ee7 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -145,10 +145,10 @@ function activate( $args, $assoc_args = array() ) { $status = $this->get_status( $plugin->file ); if ( ! $network_wide && 'active' === $status ) { - WP_CLI::warning( "The '{$plugin->name}' plugin is already active." ); + WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); continue; - } else if ( $network_wide && 'activate-network' === $status ) { - WP_CLI::warning( "The '{$plugin->name}' plugin is already network active." ); + } else if ( $network_wide && 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); continue; } From ba8647f8ad75aa614176de35c4b665bec770b5af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 13:09:55 -0700 Subject: [PATCH 2967/5359] Test cases for these warning messages --- features/plugin.feature | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 78026726a..615de8666 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -170,3 +170,36 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | | akismet | active | + + Scenario: Activate a plugin which is already active + Given a WP multisite install + + When I run `wp plugin activate akismet` + Then STDOUT should be: + """ + Success: Plugin 'akismet' activated. + """ + + When I try `wp plugin activate akismet` + Then STDERR should be: + """ + Warning: Plugin 'akismet' is already active. + """ + + When I run `wp plugin deactivate akismet` + Then STDOUT should be: + """ + Success: Plugin 'akismet' deactivated. + """ + + When I run `wp plugin activate akismet --network` + Then STDOUT should be: + """ + Success: Plugin 'akismet' network activated. + """ + + When I try `wp plugin activate akismet --network` + Then STDERR should be: + """ + Warning: Plugin 'akismet' is already network active. + """ From 2e52f1fdd4fcf4ac35ed621faf78dceeb1d2fe20 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 13:39:40 -0700 Subject: [PATCH 2968/5359] Network-only plugin check should only happen on multisite --- features/plugin.feature | 30 ++++++++++++++++++++++++++++-- php/commands/plugin.php | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 615de8666..13ffd7b51 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -117,15 +117,41 @@ Feature: Manage WordPress plugins When I run `wp plugin update --all` Then STDOUT should not be empty - Scenario: Activate a network-only plugin + Scenario: Activate a network-only plugin on single site + Given a WP install + And a wp-content/plugins/network-only.php file: + """ + // Plugin Name: Example Plugin + // Network: true + """ + + When I run `wp plugin activate network-only` + Then STDOUT should be: + """ + Success: Plugin 'network-only' activated. + """ + + When I run `wp plugin status network-only` + Then STDOUT should contain: + """ + Status: Active + """ + + Scenario: Activate a network-only plugin on multisite Given a WP multisite install And a wp-content/plugins/network-only.php file: """ // Plugin Name: Example Plugin // Network: true """ + When I run `wp plugin activate network-only` - And I run `wp plugin status network-only` + Then STDOUT should be: + """ + Success: Plugin 'network-only' network activated. + """ + + When I run `wp plugin status network-only` Then STDOUT should contain: """ Status: Network Active diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 0dff24ee7..74af879cb 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -530,7 +530,7 @@ private function check_active( $file, $network_wide ) { } private function active_output( $name, $file, $network_wide, $action ) { - $network_wide = $network_wide || is_network_only_plugin( $file ); + $network_wide = $network_wide || ( is_multisite() && is_network_only_plugin( $file ) ); $check = $this->check_active( $file, $network_wide ); From b0095bca565b144840e1835987dcc116dc799cee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 14:40:27 -0700 Subject: [PATCH 2969/5359] Move this to its appropriate place --- features/user-meta.feature | 24 ++++++++++++++++++++++++ features/user.feature | 25 ------------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/features/user-meta.feature b/features/user-meta.feature index 774941972..f8d23ba25 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -26,3 +26,27 @@ Feature: Manage user custom fields When I try `wp user-meta get 1 foo` Then the return code should be 1 + + @ticket + Scenario: List user meta + Given a WP install + + When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` + Then STDOUT should not be empty + + When I run `wp user-meta list 1 --format=json --keys=nickname,foo` + Then STDOUT should be JSON containing: + """ + { + "nickname": "admin", + "foo": ["1","2"] + } + """ + + When I run `wp user-meta list 1 --format=csv --keys=nickname,foo` + Then STDOUT should be CSV containing: + """ + | meta_key | meta_value | + | nickname | admin | + | foo | ["1","2"] | + """ diff --git a/features/user.feature b/features/user.feature index 9ce4273e5..a50e3bb3a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -253,28 +253,3 @@ Feature: Manage WordPress users """ Success: Removed 'edit_vip_product' cap for admin (1). """ - - @ticket - Scenario: List user meta - Given a WP install - - When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run `wp user-meta list 1 --format=json --keys=nickname,foo` - Then STDOUT should be JSON containing: - """ - { - "nickname": "admin", - "foo": ["1","2"] - } - """ - - When I run `wp user-meta list 1 --format=csv --keys=nickname,foo` - Then STDOUT should be CSV containing: - """ - | meta_key | meta_value | - | nickname | admin | - | foo | ["1","2"] | - """ - From 0e22a66c3539f5736ea562b2cc30c793de811f38 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 15:02:57 -0700 Subject: [PATCH 2970/5359] Because `get_metadata()` is lossy, roll our own SQL queries --- features/user-meta.feature | 25 ++++----- php/WP_CLI/CommandWithMeta.php | 92 ++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/features/user-meta.feature b/features/user-meta.feature index f8d23ba25..1882048d7 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -27,26 +27,23 @@ Feature: Manage user custom fields When I try `wp user-meta get 1 foo` Then the return code should be 1 - @ticket Scenario: List user meta Given a WP install - When I run `wp user-meta set 1 foo '[ "1", "2" ]' --format=json` + When I run `wp user meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty - When I run `wp user-meta list 1 --format=json --keys=nickname,foo` + When I run `wp user meta list 1 --format=json --keys=nickname,foo` Then STDOUT should be JSON containing: """ - { - "nickname": "admin", - "foo": ["1","2"] - } + [{"meta_key":"nickname","meta_value":"admin"},{"meta_key":"foo","meta_value":["1","2"]}] """ - When I run `wp user-meta list 1 --format=csv --keys=nickname,foo` - Then STDOUT should be CSV containing: - """ - | meta_key | meta_value | - | nickname | admin | - | foo | ["1","2"] | - """ + When I run `wp user meta set 1 foo bar` + Then STDOUT should not be empty + + When I run `wp user meta list 1 --keys=nickname,foo --fields=user_id,meta_key,meta_value` + Then STDOUT should be a table containing rows: + | user_id | meta_key | meta_value | + | 1 | nickname | admin | + | 1 | foo | bar | diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 5be394d29..684b2ff25 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -20,6 +20,9 @@ abstract class CommandWithMeta extends \WP_CLI_Command { * [--keys=<keys>] * : Limit output to metadata of specific keys. * + * [--fields=<fields>] + * : Limit the output to specific row fields. Defaults to meta_key,meta_value. + * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * @@ -29,49 +32,27 @@ public function list_( $args, $assoc_args ) { list( $object_id ) = $args; - $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); - - $values = get_metadata( $this->meta_type, $object_id ); + $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : false; - foreach( $values as $meta_key => $meta_value ) { + $values = $this->get_metadata( $object_id, $keys ); - if ( ! empty( $keys ) && ! in_array( $meta_key, $keys ) ) { - unset( $values[ $meta_key ] ); - continue; - } + foreach( $values as &$value ) { - if ( count( $values[ $meta_key ] ) == 1 ) { - $values[ $meta_key ] = $values[ $meta_key ][ 0 ]; + if ( ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) ) && ( is_object( $value->meta_value ) || is_array( $value->meta_value ) ) ) { + $value->meta_value = json_encode( $value->meta_value ); } } - // Special treatment for JSON - if ( ! empty( $assoc_args['format'] ) && 'json' === $assoc_args['format'] ) { - - echo json_encode( $values ); - + if ( ! empty( $assoc_args['fields'] ) ) { + $fields = explode( ',', $assoc_args['fields'] ); } else { - - foreach( $values as $meta_key => $meta_value ) { - - $items = array(); - if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) ) { - $meta_value = json_encode( $meta_value ); - } - - $items[] = (object) array( - 'meta_key' => $meta_key, - 'meta_value' => $meta_value, - ); - - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'meta_key', 'meta_value' ), $this->meta_type ); - $formatter->display_items( $items ); - + $fields = array( 'meta_key', 'meta_value' ); } + $formatter = new \WP_CLI\Formatter( $assoc_args, $fields, $this->meta_type ); + $formatter->display_items( $values ); + } /** @@ -172,5 +153,50 @@ public function update( $args, $assoc_args ) { \WP_CLI::error( "Failed to update custom field." ); } } + + /** + * Get the fields for this object's meta + * + * @return array + */ + private function get_fields() { + + $fields = array(); + if ( 'user' === $this->meta_type ) { + $fields[] = 'umeta_id'; + } else { + $fields[] = 'meta_id'; + } + $fields[] = "{$this->meta_type}_id"; + $fields[] = 'meta_key'; + $fields[] = 'meta_value'; + + return $fields; + } + + /** + * Non-lossy getter for metadata. + * get_metadata loses track of the meta_id + * + * @param int $object_id + * @return array + */ + private function get_metadata( $object_id, $keys = false ) { + global $wpdb; + + $fields = implode( ', ', $this->get_fields() ); + $table = "{$this->meta_type}meta"; + $query = $wpdb->prepare( "SELECT {$fields} FROM {$wpdb->$table} WHERE {$this->meta_type}_id = %d", $object_id ); + if ( $keys ) { + $query .= " AND meta_key IN ( '" . implode( "','", $keys ) . "')"; + } + $results = $wpdb->get_results( $query ); + + $results = array_map( function( $row ) { + $row->meta_value = maybe_unserialize( $row->meta_value ); + return $row; + }, $results ); + return $results; + } } From cf2e14e6b4cc553f860541e8aeeb206041219135 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 15:21:29 -0700 Subject: [PATCH 2971/5359] As it turns out, `get_metadata()` isn't lossy - it just obscures `meta_id` --- features/user-meta.feature | 13 +++++------- php/WP_CLI/CommandWithMeta.php | 39 ++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/features/user-meta.feature b/features/user-meta.feature index 1882048d7..701af9ac5 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -33,17 +33,14 @@ Feature: Manage user custom fields When I run `wp user meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty - When I run `wp user meta list 1 --format=json --keys=nickname,foo` + When I run `wp user meta list 1 --format=json --keys=nickname,foo --fields=meta_key,meta_value` Then STDOUT should be JSON containing: """ [{"meta_key":"nickname","meta_value":"admin"},{"meta_key":"foo","meta_value":["1","2"]}] """ - When I run `wp user meta set 1 foo bar` - Then STDOUT should not be empty - - When I run `wp user meta list 1 --keys=nickname,foo --fields=user_id,meta_key,meta_value` + When I run `wp user meta list 1 --keys=nickname,foo` Then STDOUT should be a table containing rows: - | user_id | meta_key | meta_value | - | 1 | nickname | admin | - | 1 | foo | bar | + | user_id | meta_key | meta_value | + | 1 | nickname | admin | + | 1 | foo | ["1","2"] | diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 684b2ff25..3bcdda454 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -21,7 +21,7 @@ abstract class CommandWithMeta extends \WP_CLI_Command { * : Limit output to metadata of specific keys. * * [--fields=<fields>] - * : Limit the output to specific row fields. Defaults to meta_key,meta_value. + * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table @@ -32,14 +32,32 @@ public function list_( $args, $assoc_args ) { list( $object_id ) = $args; - $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : false; + $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); - $values = $this->get_metadata( $object_id, $keys ); + $metadata = get_metadata( $this->meta_type, $object_id ); - foreach( $values as &$value ) { + $items = array(); + foreach( $metadata as $key => $values ) { + + // Skip if not requested + if ( ! empty( $keys ) && ! in_array( $key, $keys ) ) { + continue; + } + + foreach( $values as $item_value ) { + + $item_value = maybe_unserialize( $item_value ); + + if ( ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) )&& ( is_object( $item_value ) || is_array( $item_value ) ) ) { + $item_value = json_encode( $item_value ); + } + + $items[] = (object) array( + "{$this->meta_type}_id" => $object_id, + 'meta_key' => $key, + 'meta_value' => $item_value, + ); - if ( ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) ) && ( is_object( $value->meta_value ) || is_array( $value->meta_value ) ) ) { - $value->meta_value = json_encode( $value->meta_value ); } } @@ -47,11 +65,11 @@ public function list_( $args, $assoc_args ) { if ( ! empty( $assoc_args['fields'] ) ) { $fields = explode( ',', $assoc_args['fields'] ); } else { - $fields = array( 'meta_key', 'meta_value' ); + $fields = $this->get_fields(); } $formatter = new \WP_CLI\Formatter( $assoc_args, $fields, $this->meta_type ); - $formatter->display_items( $values ); + $formatter->display_items( $items ); } @@ -162,11 +180,6 @@ public function update( $args, $assoc_args ) { private function get_fields() { $fields = array(); - if ( 'user' === $this->meta_type ) { - $fields[] = 'umeta_id'; - } else { - $fields[] = 'meta_id'; - } $fields[] = "{$this->meta_type}_id"; $fields[] = 'meta_key'; $fields[] = 'meta_value'; From c8a08f550616ac3e9177b1fe688cfc8fe8a3026f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 15:22:51 -0700 Subject: [PATCH 2972/5359] This method isn't needed --- php/WP_CLI/CommandWithMeta.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 3bcdda454..84d31a17e 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -187,29 +187,5 @@ private function get_fields() { return $fields; } - /** - * Non-lossy getter for metadata. - * get_metadata loses track of the meta_id - * - * @param int $object_id - * @return array - */ - private function get_metadata( $object_id, $keys = false ) { - global $wpdb; - - $fields = implode( ', ', $this->get_fields() ); - $table = "{$this->meta_type}meta"; - $query = $wpdb->prepare( "SELECT {$fields} FROM {$wpdb->$table} WHERE {$this->meta_type}_id = %d", $object_id ); - if ( $keys ) { - $query .= " AND meta_key IN ( '" . implode( "','", $keys ) . "')"; - } - $results = $wpdb->get_results( $query ); - - $results = array_map( function( $row ) { - $row->meta_value = maybe_unserialize( $row->meta_value ); - return $row; - }, $results ); - return $results; - } } From a2c912ce0f350000651aa4b67c1f252ae01f65eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 15:29:53 -0700 Subject: [PATCH 2973/5359] Clean this up --- php/WP_CLI/CommandWithMeta.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 84d31a17e..8a1ffa5a0 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -178,13 +178,11 @@ public function update( $args, $assoc_args ) { * @return array */ private function get_fields() { - - $fields = array(); - $fields[] = "{$this->meta_type}_id"; - $fields[] = 'meta_key'; - $fields[] = 'meta_value'; - - return $fields; + return array( + "{$this->meta_type}_id", + 'meta_key', + 'meta_value', + ); } } From a7afbb4b5496b581da07d9f947722b51e97f5e3a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 15:39:43 -0700 Subject: [PATCH 2974/5359] Tests for post meta --- features/post-meta.feature | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/features/post-meta.feature b/features/post-meta.feature index b1daf1bba..19a92cb6f 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -33,3 +33,20 @@ Feature: Manage post custom fields When I try `wp post-meta get 1 foo` Then the return code should be 1 + + Scenario: List post meta + Given a WP install + + When I run `wp post meta add 1 apple banana` + And I run `wp post meta add 1 apple banana` + Then STDOUT should not be empty + + When I run `wp post meta set 1 banana '["apple", "apple"]' --format=json` + Then STDOUT should not be empty + + When I run `wp post meta list 1` + Then STDOUT should be a table containing rows: + | post_id | meta_key | meta_value | + | 1 | apple | banana | + | 1 | apple | banana | + | 1 | banana | ["apple","apple"] | From 82d2b25dbaed0313279b4c217bbecc5e2d7fa5a2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 28 Jun 2014 16:13:24 -0700 Subject: [PATCH 2975/5359] Fix meta delete. It should support passing a value `delete_metadata()` supports receiving a specific value to only delete rows matching that value. --- features/user-meta.feature | 19 +++++++++++++++++++ php/WP_CLI/CommandWithMeta.php | 16 ++++++++++++++-- php/commands/user.php | 3 ++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/features/user-meta.feature b/features/user-meta.feature index 701af9ac5..a7adffae6 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -27,6 +27,25 @@ Feature: Manage user custom fields When I try `wp user-meta get 1 foo` Then the return code should be 1 + When I run `wp user meta add 1 foo bar` + And I run `wp user meta add 1 foo bar2` + And I run `wp user meta add 1 foo bar3` + Then STDOUT should not be empty + + When I run `wp user meta delete 1 foo bar2` + And I run `wp user meta list 1 --keys=foo --format=count` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp user meta delete 1 foo` + And I run `wp user meta list 1 --keys=foo --format=count` + Then STDOUT should be: + """ + 0 + """ + Scenario: List user meta Given a WP install diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 8a1ffa5a0..2f3d7b49c 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -35,6 +35,9 @@ public function list_( $args, $assoc_args ) { $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); $metadata = get_metadata( $this->meta_type, $object_id ); + if ( ! $metadata ) { + $metadata = array(); + } $items = array(); foreach( $metadata as $key => $values ) { @@ -92,12 +95,21 @@ public function get( $args, $assoc_args ) { /** * Delete a meta field. * - * @synopsis <id> <key> + * <id> + * : The ID of the object. + * + * <key> + * : The name of the meta field to create. + * + * [<value>] + * : The value to delete. If omitted, all rows with key will deleted. */ public function delete( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $success = \delete_metadata( $this->meta_type, $object_id, $meta_key ); + $meta_value = ! empty( $args[2] ) ? $args[2] : ''; + + $success = \delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { \WP_CLI::success( "Deleted custom field." ); diff --git a/php/commands/user.php b/php/commands/user.php index 7e3ca9cd5..bdb7bc7c8 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -707,7 +707,8 @@ public function get( $args, $assoc_args ) { * <key> * : The metadata key. * - * @synopsis <user> <key> + * [<value>] + * : The value to delete. If omitted, all rows with key will deleted. */ public function delete( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); From 6d6a84095510dd4bf939209dedd50a29ef484ac9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 09:44:59 -0700 Subject: [PATCH 2976/5359] Handle shorter versions of item keys --- php/WP_CLI/Formatter.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 3b349f6de..5a589a178 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -37,6 +37,12 @@ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); } else { + $item = isset( $items[0] ) ? $items[0] : array(); + if ( ! empty( $this->args['fields'] ) ) { + foreach( $this->args['fields'] as &$field ) { + $field = $this->find_item_key( $item, $field ); + } + } $this->format( $items ); } } From 3b78b8afaf02b3091530bea9c351331fefe3b705 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 10:34:19 -0700 Subject: [PATCH 2977/5359] Handle non-numerically indexed arrays too --- php/WP_CLI/Formatter.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 5a589a178..13abf8ec0 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -37,11 +37,12 @@ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); } else { - $item = isset( $items[0] ) ? $items[0] : array(); - if ( ! empty( $this->args['fields'] ) ) { + $item = ! empty( $items ) ? array_shift( $items ) : array(); + if ( ! empty( $item ) && ! empty( $this->args['fields'] ) ) { foreach( $this->args['fields'] as &$field ) { $field = $this->find_item_key( $item, $field ); } + array_unshift( $items, $item ); } $this->format( $items ); } From 4e468e4261ee6e823a1ce3f2dc703e6c98991db6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 10:41:31 -0700 Subject: [PATCH 2978/5359] Tests for #803 --- features/post.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/post.feature b/features/post.feature index 171508d6a..1ff2128fe 100644 --- a/features/post.feature +++ b/features/post.feature @@ -112,6 +112,12 @@ Feature: Manage WordPress posts | Publish post | publish-post | publish | | Draft post | | draft | + When I run `wp post list --post_type='post' --fields=title,name,status --format=csv` + Then STDOUT should be CSV containing: + | post_title | post_name | post_status | + | Publish post | publish-post | publish | + | Draft post | | draft | + When I run `wp post list --post__in={POST_ID} --format=count` Then STDOUT should be: """ From 1cc4e270bb764877f6395507a414271b684c4d0d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 11:07:53 -0700 Subject: [PATCH 2979/5359] Accommodate both types of items --- php/WP_CLI/Formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 13abf8ec0..09cce4176 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -129,7 +129,7 @@ private function show_single_field( $items, $field ) { private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( isset( $item->$maybe_key ) ) { + if ( ( is_object( $item ) && isset( $item->$maybe_key ) ) || ( is_array( $item ) && isset( $item[$maybe_key] ) ) ) { $key = $maybe_key; break; } From 9fbc4bce183f466f6447a8b127bfad202728fb77 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 11:24:46 -0700 Subject: [PATCH 2980/5359] Accommodate array iterators, which can be passed to `display_items()` --- php/WP_CLI/Formatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 09cce4176..5b81ec6fd 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -37,8 +37,8 @@ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); } else { - $item = ! empty( $items ) ? array_shift( $items ) : array(); - if ( ! empty( $item ) && ! empty( $this->args['fields'] ) ) { + $item = is_array( $items ) && ! empty( $items ) ? array_shift( $items ) : false; + if ( $item && ! empty( $this->args['fields'] ) ) { foreach( $this->args['fields'] as &$field ) { $field = $this->find_item_key( $item, $field ); } From 9bd7cce8407aecb94a12f6363e41d234b1d599ed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 11:58:03 -0700 Subject: [PATCH 2981/5359] Only modify relevant output formats --- php/WP_CLI/Formatter.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 5b81ec6fd..5f188a747 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -37,12 +37,14 @@ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); } else { - $item = is_array( $items ) && ! empty( $items ) ? array_shift( $items ) : false; - if ( $item && ! empty( $this->args['fields'] ) ) { - foreach( $this->args['fields'] as &$field ) { - $field = $this->find_item_key( $item, $field ); + if ( in_array( $this->args['format'], array( 'csv', 'json', 'table' ) ) ) { + $item = is_array( $items ) && ! empty( $items ) ? array_shift( $items ) : false; + if ( $item && ! empty( $this->args['fields'] ) ) { + foreach( $this->args['fields'] as &$field ) { + $field = $this->find_item_key( $item, $field ); + } + array_unshift( $items, $item ); } - array_unshift( $items, $item ); } $this->format( $items ); } From 01dd983240fccf3bad45b12fdd13143e7fa57a7e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 13:05:22 -0700 Subject: [PATCH 2982/5359] Update to php-cli-tools latest, which fixes Hungarian cron list --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f2972a145..eddbf52a9 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.9.4-patch46", + "wp-cli/php-cli-tools": "0.9.5", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From dfbcac42b284104849d5108fc654ca014083d41a Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:28:12 -0700 Subject: [PATCH 2983/5359] check for serialized before running serial safe replace --- php/commands/search-replace.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 384162839..6f897a850 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -47,6 +47,7 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run */ public function __invoke( $args, $assoc_args ) { + global $wpdb; $old = array_shift( $args ); $new = array_shift( $args ); $total = 0; @@ -75,10 +76,13 @@ public function __invoke( $args, $assoc_args ) { } foreach ( $columns as $col ) { - if ( in_array( $col, $skip_columns ) ) + if ( in_array( $col, $skip_columns ) ) { continue; + } + + $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE $col REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( substr( $table, -9 ) == '_comments' || substr( $table, -6 ) == '_posts' ) { + if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } else $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); From 8afdaa22445b2f74d5b25dee92c7d86b20f6d5f1 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:36:59 -0700 Subject: [PATCH 2984/5359] Single quote table and col names for edge cases --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 6f897a850..63b943de7 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,7 +80,7 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE $col REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + $serialRow = $wpdb->get_col( "SELECT * FROM '$table' WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); From 4a636efbb383bac51ecece36febf3f1f63ef639f Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:39:01 -0700 Subject: [PATCH 2985/5359] now quotes on table name --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 63b943de7..4539c7f36 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,7 +80,7 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM '$table' WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); From 32418eec31c013aabd17fd0b84c0bd576b79ab10 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:44:55 -0700 Subject: [PATCH 2986/5359] Spell count correctly --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 4539c7f36..b14e31416 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,7 +82,7 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( 0 < cont( $serialized ) ) { + if ( 0 < count( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } else $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); From 34e66b5bc7b1e48e791a9fda72a74acd2be1f165 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:47:55 -0700 Subject: [PATCH 2987/5359] Formatting and variable names --- php/commands/search-replace.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b14e31416..737f0862a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,10 +82,11 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( 0 < count( $serialized ) ) { + if ( 0 < count( $serialRow ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); - } else + } else { $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + } $report[] = array( $table, $col, $count ); From e8b39904add3474fe97d4ce0e255c067a518cbf2 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:17:39 -0700 Subject: [PATCH 2988/5359] Add backticks and show which replace is used --- php/commands/search-replace.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 737f0862a..e2bae8584 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,12 +80,13 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - - if ( 0 < count( $serialRow ) ) { - $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); - } else { + $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + if ( NULL !== $serialRow ) { + WP_CLI::line( 'safe-replace' ); $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + } else { + WP_CLI::line( 'fast-replace' ); + $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } $report[] = array( $table, $col, $count ); @@ -117,10 +118,11 @@ private static function get_table_list( $args, $network ) { private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; - if ( $dry_run ) + if ( $dry_run ) { return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); - else + } else { return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + } } private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { From cbe88c6ab9752a5d773c6caa12eebc76a9430cc9 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:24:11 -0700 Subject: [PATCH 2989/5359] Back tick all the things and better debuggin --- php/commands/search-replace.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e2bae8584..0445769ff 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,10 +82,10 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( NULL !== $serialRow ) { - WP_CLI::line( 'safe-replace' ); + WP_CLI::line( "safe-replace-$table:$col" ); $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - WP_CLI::line( 'fast-replace' ); + WP_CLI::line( "fast-replace-$table:$col" ); $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } @@ -119,9 +119,9 @@ private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { - return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); } else { - return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + return $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } } From 8ed36e69f6d4523b6c0d07f7940637f16fe65dd2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 14:25:43 -0700 Subject: [PATCH 2990/5359] Use checksum API to verify core files --- features/core.feature | 29 +++++++++++++++++++++++++++++ php/commands/core.php | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/features/core.feature b/features/core.feature index 1d537e434..d6ec9ea46 100644 --- a/features/core.feature +++ b/features/core.feature @@ -267,6 +267,35 @@ Feature: Manage WordPress installation When I run `wp plugin status hello` Then STDOUT should not be empty + Scenario: Verify core checksums + Given a WP install + + When I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ + + When I run `sed -i.bak s/WordPress/Wordpress/g readme.html` + Then STDERR should be empty + + When I try `wp core verify-checksums` + Then STDERR should be: + """ + Warning: File doesn't verify against checksum: readme.html + Error: WordPress install doesn't verify against checksums. + """ + + When I run `rm readme.html` + Then STDERR should be empty + + When I try `wp core verify-checksums` + Then STDERR should be: + """ + Warning: File doesn't exist: readme.html + Error: WordPress install doesn't verify against checksums. + """ + Scenario: User defined in wp-cli.yml Given an empty directory And WP files diff --git a/php/commands/core.php b/php/commands/core.php index bf9a0a75a..f464f8442 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -658,6 +658,47 @@ public function version( $args = array(), $assoc_args = array() ) { // @codingStandardsIgnoreEnd } + /** + * Verify WordPress files against WordPress.org's checksums. + * + * @subcommand verify-checksums + */ + public function verify_checksums( $args, $assoc_args ) { + global $wp_version, $wp_local_package; + + $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); + + if ( ! is_array( $checksums ) ) { + WP_CLI::error( "Couldn't get checksums from WordPress.org." ); + } + + $has_errors = false; + foreach ( $checksums as $file => $checksum ) { + // Skip files which get updated + if ( 'wp-content' == substr( $file, 0, 10 ) ) { + continue; + } + + if ( ! file_exists( ABSPATH . $file ) ) { + WP_CLI::warning( "File doesn't exist: {$file}" ); + $has_errors = true; + continue; + } + + $md5_file = md5_file( ABSPATH . $file ); + if ( $md5_file !== $checksum ) { + WP_CLI::warning( "File doesn't verify against checksum: {$file}" ); + $has_errors = true; + } + } + + if ( ! $has_errors ) { + WP_CLI::success( "WordPress install verifies against checksums." ); + } else { + WP_CLI::error( "WordPress install doesn't verify against checksums." ); + } + } + /** * Update WordPress. * From 338768b76e1e1886e15a1ff7373fb89519d7b986 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 29 Jun 2014 14:33:09 -0700 Subject: [PATCH 2991/5359] Core only offers checksums down to 3.7, so this will have to do Let's always test against latest though --- features/core.feature | 3 +++ php/commands/core.php | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index d6ec9ea46..8fec27a7c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -270,6 +270,9 @@ Feature: Manage WordPress installation Scenario: Verify core checksums Given a WP install + When I run `wp core update` + Then STDOUT should not be empty + When I run `wp core verify-checksums` Then STDOUT should be: """ diff --git a/php/commands/core.php b/php/commands/core.php index f464f8442..025a543b8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -666,7 +666,12 @@ public function version( $args = array(), $assoc_args = array() ) { public function verify_checksums( $args, $assoc_args ) { global $wp_version, $wp_local_package; - $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); + // Introduced in 3.7 + if ( function_exists( 'get_core_checksums' ) ) { + $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); + } else { + $checksums = false; + } if ( ! is_array( $checksums ) ) { WP_CLI::error( "Couldn't get checksums from WordPress.org." ); From e10ab16f7173acb0f3cd8f4548a7eba0b8323a6a Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:38:33 -0700 Subject: [PATCH 2992/5359] Safe flag and table output --- php/commands/search-replace.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0445769ff..f9e17c13a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -37,6 +37,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--dry-run] * : Show report, but don't perform the changes. * + * [--safe] + * : Use only serialization safe replacement method. + * * [--recurse-objects] * : Enable recursing into objects to replace strings * @@ -53,6 +56,7 @@ public function __invoke( $args, $assoc_args ) { $total = 0; $report = array(); $dry_run = isset( $assoc_args['dry-run'] ); + $safe_only = isset( $assoc_args['safe'] ); $recurse_objects = isset( $assoc_args['recurse-objects'] ); if ( isset( $assoc_args['skip-columns'] ) ) @@ -80,23 +84,26 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( NULL !== $serialRow ) { - WP_CLI::line( "safe-replace-$table:$col" ); + if ( ! $safe_only ) { + $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + } + + if ( $safe_only || NULL !== $serialRow ) { + $safe = 'Y'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - WP_CLI::line( "fast-replace-$table:$col" ); + $safe = 'N'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } - $report[] = array( $table, $col, $count ); + $report[] = array( $table, $col, $count, $safe ); $total += $count; } } $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements' ) ); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Safe Replace' ) ); $table->setRows( $report ); $table->display(); From 55edfb53a21172203f9a2747cbfbf33810dc4254 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:52:56 -0700 Subject: [PATCH 2993/5359] Use 'Fast Replace' as column name to avoid confusion --- php/commands/search-replace.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f9e17c13a..ea49f8aaf 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -89,10 +89,10 @@ public function __invoke( $args, $assoc_args ) { } if ( $safe_only || NULL !== $serialRow ) { - $safe = 'Y'; + $safe = 'No'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - $safe = 'N'; + $safe = 'Yes'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } @@ -103,7 +103,7 @@ public function __invoke( $args, $assoc_args ) { } $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Safe Replace' ) ); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Fast Replace' ) ); $table->setRows( $report ); $table->display(); From cea783423d1b4ffcf4cd321e2fc2e85de5dea842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 30 Jun 2014 02:02:29 +0200 Subject: [PATCH 2994/5359] security copy of core function --- php/commands/core.php | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 025a543b8..2a323402d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -658,6 +658,45 @@ public function version( $args = array(), $assoc_args = array() ) { // @codingStandardsIgnoreEnd } + /** + * Security copy of the core funtion - Gets and caches the checksums for the given version of WordPress. + * + * @since 3.7.0 + * + * @param string $version Version string to query. + * @param string $locale Locale to query. + * @return bool|array False on failure. An array of checksums on success. + */ + private static function _get_core_checksums( $version, $locale ) { + $return = array(); + + $url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); + + if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) + $url = set_url_scheme( $url, 'https' ); + + $options = array( + 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ), + ); + + $response = wp_remote_get( $url, $options ); + if ( $ssl && is_wp_error( $response ) ) { + trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); + $response = wp_remote_get( $http_url, $options ); + } + + if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) + return false; + + $body = trim( wp_remote_retrieve_body( $response ) ); + $body = json_decode( $body, true ); + + if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) + return false; + + return $body['checksums']; + } + /** * Verify WordPress files against WordPress.org's checksums. * @@ -668,7 +707,7 @@ public function verify_checksums( $args, $assoc_args ) { // Introduced in 3.7 if ( function_exists( 'get_core_checksums' ) ) { - $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); + $checksums = self::_get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); } else { $checksums = false; } From 81d15849f6917d67d21acdad3db50ccf83439f13 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Sun, 29 Jun 2014 18:17:38 -0700 Subject: [PATCH 2995/5359] filename tab completion --- utils/wp-completion.bash | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index ac7e99250..863704407 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -7,6 +7,9 @@ _wp_complete() { local opts="$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT")" if [[ $opts = "<file>" ]] + then + COMPREPLY=( $(compgen -f -- $cur) ) + elif [[ $opts = "" ]] then COMPREPLY=( $(compgen -f -- $cur) ) else From dee969b74ab73899cde1930d5e3f799fa7d1caa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 30 Jun 2014 03:24:24 +0200 Subject: [PATCH 2996/5359] with Requests --- php/commands/core.php | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2a323402d..4a88d6de8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -659,36 +659,38 @@ public function version( $args = array(), $assoc_args = array() ) { } /** - * Security copy of the core funtion - Gets and caches the checksums for the given version of WordPress. - * - * @since 3.7.0 + * Security copy of the core function with Requests - Gets the checksums for the given version of WordPress. * * @param string $version Version string to query. * @param string $locale Locale to query. * @return bool|array False on failure. An array of checksums on success. */ - private static function _get_core_checksums( $version, $locale ) { + private static function get_core_checksums( $version, $locale ) { $return = array(); $url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) - $url = set_url_scheme( $url, 'https' ); + $url = 'https' . substr( $url, 4 ); $options = array( - 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ), + 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ) + ); + + $headers = array( + 'Accept' => 'application/json' ); + $response = self::_request( 'GET', $url, $headers, $options ); - $response = wp_remote_get( $url, $options ); - if ( $ssl && is_wp_error( $response ) ) { + if ( $ssl && ! $response->success ) { trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); - $response = wp_remote_get( $http_url, $options ); + $response = self::_request( 'GET', $http_url, $headers, $options ); } - if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) + if ( ! $response->success || 200 != $response->status_code ) return false; - $body = trim( wp_remote_retrieve_body( $response ) ); + $body = trim( $response->body ); $body = json_decode( $body, true ); if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) @@ -705,12 +707,7 @@ private static function _get_core_checksums( $version, $locale ) { public function verify_checksums( $args, $assoc_args ) { global $wp_version, $wp_local_package; - // Introduced in 3.7 - if ( function_exists( 'get_core_checksums' ) ) { - $checksums = self::_get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); - } else { - $checksums = false; - } + $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); if ( ! is_array( $checksums ) ) { WP_CLI::error( "Couldn't get checksums from WordPress.org." ); From 093bb057169c71c82d5379bb8b9871cf074c9baf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 30 Jun 2014 17:02:33 -0700 Subject: [PATCH 2997/5359] Update mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 001d93e0a..b2fd54a52 100644 --- a/.mailmap +++ b/.mailmap @@ -34,6 +34,7 @@ johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> +joshlevinson <joshalevinson@gmail.com> Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> From 1e363d53030ff9f1f658fa2b1085ca9c0e2a2c0b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 30 Jun 2014 17:05:47 -0700 Subject: [PATCH 2998/5359] Bumpity bump --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 485cececd..c0a45246e 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.15.1' ); +define( 'WP_CLI_VERSION', '0.16.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 42af19f1166574a65ca7aab4ffe48aef8218508b Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Tue, 1 Jul 2014 11:47:04 -0700 Subject: [PATCH 2999/5359] trim commas on tables list in wp db export In running `wp db export --tables=$(wp db tables --url=local.dev/msstable/feta --scope=blog | tr '\n' ',')` the list of tables passed looks like `wp_4_posts,wp_4_comments,wp_4_links,wp_4_options,wp_4_postmeta,wp_4_terms,wp_4_term_taxonomy,wp_4_term_relationships,wp_4_commentmeta,` When the list is later explode()d, the trailing comma causes there to be an empty element in the array, and on export an extra table gets included (whatever is first alphabetically). --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index b641c8499..32543d7a7 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -141,7 +141,7 @@ function export( $args, $assoc_args ) { $command_esc_args = array( DB_NAME ); if ( isset( $assoc_args['tables'] ) ) { - $tables = explode( ',', $assoc_args['tables'] ); + $tables = explode( ',', trim( $assoc_args['tables'], ',' ) ); unset( $assoc_args['tables'] ); $command .= ' --tables'; foreach ( $tables as $table ) { From 54cfda102872ebdd387ec4281f611bb94b27d845 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Wed, 2 Jul 2014 17:47:10 -0700 Subject: [PATCH 3000/5359] tab completion re-fixed --- utils/wp-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index 863704407..94896ca52 100755 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -6,7 +6,7 @@ _wp_complete() { IFS=$'\n'; # want to preserve spaces at the end local opts="$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT")" - if [[ $opts = "<file>" ]] + if [[ "$opts" =~ \<file\>\s* ]] then COMPREPLY=( $(compgen -f -- $cur) ) elif [[ $opts = "" ]] From bd10a95d8780d125666a55306e50e4d795927303 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Fri, 4 Jul 2014 18:50:41 -0700 Subject: [PATCH 3001/5359] Allow for always fast replace is same str length --- php/commands/search-replace.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ea49f8aaf..23100e759 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -79,24 +79,27 @@ public function __invoke( $args, $assoc_args ) { continue; } + // Can we do everything with a fast replace? + $fast_only = ( ! $safe_only && mb_strlen( $old ) === mb_strlen( $new ) ); + foreach ( $columns as $col ) { if ( in_array( $col, $skip_columns ) ) { continue; } - if ( ! $safe_only ) { + if ( ! $safe_only && ! $fast_only ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $safe_only || NULL !== $serialRow ) { - $safe = 'No'; + if ( $safe_only || ! $fast_only || NULL !== $serialRow ) { + $fast = 'No'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - $safe = 'Yes'; + $fast = 'Yes'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } - $report[] = array( $table, $col, $count, $safe ); + $report[] = array( $table, $col, $count, $fast ); $total += $count; } From 53dd4f13398776711495905eeeff945ec4c6cbaa Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Fri, 4 Jul 2014 18:51:25 -0700 Subject: [PATCH 3002/5359] Fix behat tests and add one for fast-s-r scenarios --- features/search-replace.feature | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 2031ceb14..684fb6755 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -20,9 +20,9 @@ Feature: Do global search/replace And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` And I run `wp search-replace foo bar --network` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_2_posts | guid | 2 | - | wp_blogs | path | 1 | + | Table | Column | Replacements | Fast Replace | + | wp_2_posts | guid | 2 | Yes | + | wp_blogs | path | 1 | Yes | Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install @@ -32,11 +32,28 @@ Feature: Do global search/replace When I run `wp search-replace <flags> {SITEURL} <replacement>` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_posts | guid | 22 | + | Table | Column | Replacements | Fast Replace | + | wp_posts | guid | 22 | No | Examples: | replacement | flags | | {SITEURL}/subdir | | | http://newdomain.com | | | http://newdomain.com | --dry-run | + + Scenario Outline: Fast and Safe search/replace due to string length and flags + Given a WP install + And I run `wp option get siteurl` + And save STDOUT as {SITEURL} + And I run `wp search-replace {SITEURL} {SITEURL}/teststring` + + When I run `wp search-replace <flags> {SITEURL}/teststring <replacement>` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Fast Replace | + | wp_options | option_value | 2 | <fast> | + + Examples: + | replacement | flags | fast | + | {SITEURL}/different | | No | + | {SITEURL}/samelength | --safe | No | + | {SITEURL}/samelength | | Yes | From 86efc1528b0537c297b8d741222f90bc9805d9c7 Mon Sep 17 00:00:00 2001 From: Leonardo Santagada <santagada@gmail.com> Date: Sun, 8 Jun 2014 21:38:23 -0300 Subject: [PATCH 3003/5359] change data directly in mysql for some tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit search-replace on tables that don’t contain serialised data can be changed directly in mysql --- php/commands/search-replace.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e6a8739df..384162839 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -78,7 +78,10 @@ public function __invoke( $args, $assoc_args ) { if ( in_array( $col, $skip_columns ) ) continue; - $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + if ( substr( $table, -9 ) == '_comments' || substr( $table, -6 ) == '_posts' ) { + $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); + } else + $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); $report[] = array( $table, $col, $count ); @@ -106,6 +109,15 @@ private static function get_table_list( $args, $network ) { return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } + private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { + global $wpdb; + + if ( $dry_run ) + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); + else + return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + } + private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { global $wpdb; From 916d1d88d793ce981d041c4e7fe4e6379143862a Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:28:12 -0700 Subject: [PATCH 3004/5359] check for serialized before running serial safe replace --- php/commands/search-replace.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 384162839..6f897a850 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -47,6 +47,7 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run */ public function __invoke( $args, $assoc_args ) { + global $wpdb; $old = array_shift( $args ); $new = array_shift( $args ); $total = 0; @@ -75,10 +76,13 @@ public function __invoke( $args, $assoc_args ) { } foreach ( $columns as $col ) { - if ( in_array( $col, $skip_columns ) ) + if ( in_array( $col, $skip_columns ) ) { continue; + } + + $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE $col REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( substr( $table, -9 ) == '_comments' || substr( $table, -6 ) == '_posts' ) { + if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } else $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); From aa91d81563f279ff2282656837e66d2455f8cace Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:36:59 -0700 Subject: [PATCH 3005/5359] Single quote table and col names for edge cases --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 6f897a850..63b943de7 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,7 +80,7 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE $col REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + $serialRow = $wpdb->get_col( "SELECT * FROM '$table' WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); From 18c04bc464205a8d21a1f453eb639094ea9b9611 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:39:01 -0700 Subject: [PATCH 3006/5359] now quotes on table name --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 63b943de7..4539c7f36 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,7 +80,7 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM '$table' WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( 0 < cont( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); From 0b53b222731ac9183aea5af95a12425d30dcae78 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:44:55 -0700 Subject: [PATCH 3007/5359] Spell count correctly --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 4539c7f36..b14e31416 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,7 +82,7 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( 0 < cont( $serialized ) ) { + if ( 0 < count( $serialized ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } else $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); From 802d5d4adbc03ce63bff7b364087e63c80d37996 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 13:47:55 -0700 Subject: [PATCH 3008/5359] Formatting and variable names --- php/commands/search-replace.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b14e31416..737f0862a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,10 +82,11 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( 0 < count( $serialized ) ) { + if ( 0 < count( $serialRow ) ) { $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); - } else + } else { $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + } $report[] = array( $table, $col, $count ); From c56227538d38ae62d52251f8221ab7f94e78574b Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:17:39 -0700 Subject: [PATCH 3009/5359] Add backticks and show which replace is used --- php/commands/search-replace.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 737f0862a..e2bae8584 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,12 +80,13 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_col( "SELECT * FROM $table WHERE '$col' REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - - if ( 0 < count( $serialRow ) ) { - $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); - } else { + $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + if ( NULL !== $serialRow ) { + WP_CLI::line( 'safe-replace' ); $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + } else { + WP_CLI::line( 'fast-replace' ); + $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } $report[] = array( $table, $col, $count ); @@ -117,10 +118,11 @@ private static function get_table_list( $args, $network ) { private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; - if ( $dry_run ) + if ( $dry_run ) { return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); - else + } else { return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + } } private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { From edadb0de61ddde9a08e8bab380e82f2dbb18e158 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:24:11 -0700 Subject: [PATCH 3010/5359] Back tick all the things and better debuggin --- php/commands/search-replace.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e2bae8584..0445769ff 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,10 +82,10 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); if ( NULL !== $serialRow ) { - WP_CLI::line( 'safe-replace' ); + WP_CLI::line( "safe-replace-$table:$col" ); $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - WP_CLI::line( 'fast-replace' ); + WP_CLI::line( "fast-replace-$table:$col" ); $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } @@ -119,9 +119,9 @@ private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { - return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT($col) FROM $table WHERE $col LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); } else { - return $wpdb->query( $wpdb->prepare( "UPDATE $table SET $col = REPLACE($col, %s, %s);", $old, $new ) ); + return $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } } From 834d186481aa5ccc7873d89798ba8d2920ce1553 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:38:33 -0700 Subject: [PATCH 3011/5359] Safe flag and table output --- php/commands/search-replace.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0445769ff..f9e17c13a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -37,6 +37,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--dry-run] * : Show report, but don't perform the changes. * + * [--safe] + * : Use only serialization safe replacement method. + * * [--recurse-objects] * : Enable recursing into objects to replace strings * @@ -53,6 +56,7 @@ public function __invoke( $args, $assoc_args ) { $total = 0; $report = array(); $dry_run = isset( $assoc_args['dry-run'] ); + $safe_only = isset( $assoc_args['safe'] ); $recurse_objects = isset( $assoc_args['recurse-objects'] ); if ( isset( $assoc_args['skip-columns'] ) ) @@ -80,23 +84,26 @@ public function __invoke( $args, $assoc_args ) { continue; } - $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - if ( NULL !== $serialRow ) { - WP_CLI::line( "safe-replace-$table:$col" ); + if ( ! $safe_only ) { + $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + } + + if ( $safe_only || NULL !== $serialRow ) { + $safe = 'Y'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - WP_CLI::line( "fast-replace-$table:$col" ); + $safe = 'N'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } - $report[] = array( $table, $col, $count ); + $report[] = array( $table, $col, $count, $safe ); $total += $count; } } $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements' ) ); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Safe Replace' ) ); $table->setRows( $report ); $table->display(); From a70797022c42962c8a9a3d94fe4ad6f55fa4995f Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 29 Jun 2014 14:52:56 -0700 Subject: [PATCH 3012/5359] Use 'Fast Replace' as column name to avoid confusion --- php/commands/search-replace.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f9e17c13a..ea49f8aaf 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -89,10 +89,10 @@ public function __invoke( $args, $assoc_args ) { } if ( $safe_only || NULL !== $serialRow ) { - $safe = 'Y'; + $safe = 'No'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - $safe = 'N'; + $safe = 'Yes'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } @@ -103,7 +103,7 @@ public function __invoke( $args, $assoc_args ) { } $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Safe Replace' ) ); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Fast Replace' ) ); $table->setRows( $report ); $table->display(); From 2977eec15c1763d06f4ebe763740a778c5dd5a8b Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Fri, 4 Jul 2014 18:50:41 -0700 Subject: [PATCH 3013/5359] Allow for always fast replace is same str length --- php/commands/search-replace.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ea49f8aaf..23100e759 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -79,24 +79,27 @@ public function __invoke( $args, $assoc_args ) { continue; } + // Can we do everything with a fast replace? + $fast_only = ( ! $safe_only && mb_strlen( $old ) === mb_strlen( $new ) ); + foreach ( $columns as $col ) { if ( in_array( $col, $skip_columns ) ) { continue; } - if ( ! $safe_only ) { + if ( ! $safe_only && ! $fast_only ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $safe_only || NULL !== $serialRow ) { - $safe = 'No'; + if ( $safe_only || ! $fast_only || NULL !== $serialRow ) { + $fast = 'No'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - $safe = 'Yes'; + $fast = 'Yes'; $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); } - $report[] = array( $table, $col, $count, $safe ); + $report[] = array( $table, $col, $count, $fast ); $total += $count; } From becf46314327205cb9541458b4062325d7c6a479 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Fri, 4 Jul 2014 18:51:25 -0700 Subject: [PATCH 3014/5359] Fix behat tests and add one for fast-s-r scenarios --- features/search-replace.feature | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 2031ceb14..684fb6755 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -20,9 +20,9 @@ Feature: Do global search/replace And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` And I run `wp search-replace foo bar --network` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_2_posts | guid | 2 | - | wp_blogs | path | 1 | + | Table | Column | Replacements | Fast Replace | + | wp_2_posts | guid | 2 | Yes | + | wp_blogs | path | 1 | Yes | Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install @@ -32,11 +32,28 @@ Feature: Do global search/replace When I run `wp search-replace <flags> {SITEURL} <replacement>` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | - | wp_posts | guid | 22 | + | Table | Column | Replacements | Fast Replace | + | wp_posts | guid | 22 | No | Examples: | replacement | flags | | {SITEURL}/subdir | | | http://newdomain.com | | | http://newdomain.com | --dry-run | + + Scenario Outline: Fast and Safe search/replace due to string length and flags + Given a WP install + And I run `wp option get siteurl` + And save STDOUT as {SITEURL} + And I run `wp search-replace {SITEURL} {SITEURL}/teststring` + + When I run `wp search-replace <flags> {SITEURL}/teststring <replacement>` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Fast Replace | + | wp_options | option_value | 2 | <fast> | + + Examples: + | replacement | flags | fast | + | {SITEURL}/different | | No | + | {SITEURL}/samelength | --safe | No | + | {SITEURL}/samelength | | Yes | From dc9e615d19fb04dc5e00b5801248b47c84069e29 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 6 Jul 2014 16:29:49 -0700 Subject: [PATCH 3015/5359] Test for bug in normal circumstances fast replace fails to run --- features/search-replace.feature | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 684fb6755..9f054ed19 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -50,10 +50,11 @@ Feature: Do global search/replace When I run `wp search-replace <flags> {SITEURL}/teststring <replacement>` Then STDOUT should be a table containing rows: | Table | Column | Replacements | Fast Replace | - | wp_options | option_value | 2 | <fast> | + | wp_options | option_value | 2 | <serial> | + | wp_posts | post_title | 0 | <noserial> | Examples: - | replacement | flags | fast | - | {SITEURL}/different | | No | - | {SITEURL}/samelength | --safe | No | - | {SITEURL}/samelength | | Yes | + | replacement | flags | serial | noserial | + | {SITEURL}/different | | No | Yes | + | {SITEURL}/samelength | --safe | No | No | + | {SITEURL}/samelength | | Yes | Yes | From 59935b48687f6e1e6f4fc8cfe6a589dfbbf7628b Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 6 Jul 2014 16:32:57 -0700 Subject: [PATCH 3016/5359] Guid replace should be fast since there is no serialized data --- features/search-replace.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 9f054ed19..95027ecef 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -33,7 +33,7 @@ Feature: Do global search/replace When I run `wp search-replace <flags> {SITEURL} <replacement>` Then STDOUT should be a table containing rows: | Table | Column | Replacements | Fast Replace | - | wp_posts | guid | 22 | No | + | wp_posts | guid | 22 | Yes | Examples: | replacement | flags | From 28dfcf47cc9245f1c93aa576cec664d07bc28397 Mon Sep 17 00:00:00 2001 From: Luke Woodward <woodward.lucas@gmail.com> Date: Sun, 6 Jul 2014 16:33:33 -0700 Subject: [PATCH 3017/5359] Fix conditional to properly switch to fast method --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 23100e759..c3a725e0c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -91,7 +91,7 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $safe_only || ! $fast_only || NULL !== $serialRow ) { + if ( $safe_only || ( ! $fast_only && NULL !== $serialRow ) ) { $fast = 'No'; $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { From 6409fdc9f39275c82fe870c5cd086fb6e79ce7bb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 13 Jul 2014 15:38:51 +0000 Subject: [PATCH 3018/5359] Correct line breaks --- CONTRIBUTING.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 563153a4e..013140f97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,9 +45,7 @@ To run the unit tests, just execute: The functional test files are in the `features/` directory. -Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the -password `password1` that has full privileges on the MySQL database `wp_cli_test`. -Running the following as root in MySQL should do the trick: +Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; @@ -64,5 +62,4 @@ More info can be found by using `./vendor/bin/behat --help`. Finally... ---------- -Thanks! Hacking on WP-CLI should be fun. If you find any of this hard to figure -out, let us know so we can improve our process or documentation! +Thanks! Hacking on WP-CLI should be fun. If you find any of this hard to figure out, let us know so we can improve our process or documentation! From 32af46f83b5ed44b60b6fd108f8c912b69735437 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 13 Jul 2014 15:40:22 +0000 Subject: [PATCH 3019/5359] Add mention that each contribution should be on a separate branch. --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 013140f97..001b2400e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,8 +16,9 @@ Whether you want to fix a bug or implement a new feature, the process is pretty 0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, open a new issue so that you can get some initial feedback. 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. -2. Push the code changes from your local clone to your fork. -3. Open a pull request. +2. Create a branch for each issue you'd like to address. Commit your changes. +3. Push the code changes from your local clone to your fork. +4. Open a pull request. It doesn't matter if the code isn't perfect. The idea is to get it reviewed early and iterate on it. From 16bf1beaf8a0f65c98535edc46bdb7c5a1c016d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 14 Jul 2014 15:32:09 +0000 Subject: [PATCH 3020/5359] Fix incorrect argument in example Fixes #1276 --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index a7c81ec41..84fa861a4 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -46,7 +46,7 @@ public function __construct() { * * ## EXAMPLES * - * wp post create --post_type=page --post_status=publish --post_title='A future post' --post-status=future --post_date='2020-12-01 07:00:00' + * wp post create --post_type=page --post_title='A future post' --post_status=future --post_date='2020-12-01 07:00:00' * * wp post create ./post-content.txt --post_category=201,345 --post_title='Post from file' */ From 74f3f67717fde5327d8aec07d2b0d35430cfd70b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 13:30:34 +0000 Subject: [PATCH 3021/5359] Show generated password when creating a user This is helpful to the end developer, and was accidentally removed in 17860a741218d6230720d43cafa1c32f6a8a5ed2 --- features/user.feature | 15 +++++++++++++++ php/commands/user.php | 10 +++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/features/user.feature b/features/user.feature index a50e3bb3a..2809ac97c 100644 --- a/features/user.feature +++ b/features/user.feature @@ -253,3 +253,18 @@ Feature: Manage WordPress users """ Success: Removed 'edit_vip_product' cap for admin (1). """ + + Scenario: Show password when creating a user + Given a WP install + + When I run `wp user create testrandompass testrandompass@example.com` + Then STDOUT should contain: + """ + Password: + """ + + When I run `wp user create testsuppliedpass testsuppliedpass@example.com --user_pass=suppliedpass` + Then STDOUT should not contain: + """ + Password: + """ diff --git a/php/commands/user.php b/php/commands/user.php index bdb7bc7c8..b93cf1c4b 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -229,8 +229,12 @@ public function create( $args, $assoc_args ) { $user->last_name = isset( $assoc_args['last_name'] ) ? $assoc_args['last_name'] : false; - $user->user_pass = isset( $assoc_args['user_pass'] ) - ? $assoc_args['user_pass'] : wp_generate_password(); + if ( isset( $assoc_args['user_pass'] ) ) { + $user->user_pass = $assoc_args['user_pass']; + } else { + $user->user_pass = wp_generate_password(); + $generated_pass = true; + } if ( isset( $assoc_args['role'] ) ) { $role = $assoc_args['role']; @@ -259,7 +263,7 @@ public function create( $args, $assoc_args ) { } else { WP_CLI::success( "Created user $user_id." ); if ( isset( $generated_pass ) ) - WP_CLI::line( "Password: $user_pass" ); + WP_CLI::line( "Password: $user->user_pass" ); } } From ef851ba7fff305b649bc910e14f3ab7d6adc4733 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 13:44:28 +0000 Subject: [PATCH 3022/5359] Test case to confirm #1272 --- features/config.feature | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/features/config.feature b/features/config.feature index 3ed1e17aa..9fadc2273 100644 --- a/features/config.feature +++ b/features/config.feature @@ -177,3 +177,24 @@ Feature: Have a config file Then STDOUT should be a number When I run `wp post list --format=json` Then STDOUT should not be a number + + Scenario: Required files should not be loaded twice + Given an empty directory + And a custom-file.php file: + """ + <?php + define( 'FOOBUG', 'BAR' ); + """ + And a config.yml file: + """ + require: + - custom-file.php + """ + And a wp-cli.yml file: + """ + require: + - custom-file.php + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp help` + Then STDERR should be empty From ca07b8a3c1eecc01c185e7ee176a6c70fcdd977c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 13:48:41 +0000 Subject: [PATCH 3023/5359] Ensure config.yml in a separate directory is tested --- features/config.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/config.feature b/features/config.feature index 9fadc2273..ad5f2e05e 100644 --- a/features/config.feature +++ b/features/config.feature @@ -185,10 +185,10 @@ Feature: Have a config file <?php define( 'FOOBUG', 'BAR' ); """ - And a config.yml file: + And a test-dir/config.yml file: """ require: - - custom-file.php + - ../custom-file.php """ And a wp-cli.yml file: """ @@ -196,5 +196,5 @@ Feature: Have a config file - custom-file.php """ - When I run `WP_CLI_CONFIG_PATH=config.yml wp help` + When I run `WP_CLI_CONFIG_PATH=test-dir/config.yml wp help` Then STDERR should be empty From 5c1c6fd96603b66d0c77f9a7e162adb75d859ced Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 13:50:52 +0000 Subject: [PATCH 3024/5359] Use `require_once()` to prevent a given file from being loaded twice --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index fe21f32e2..e033be5bb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -38,7 +38,7 @@ function get_vendor_paths() { // Using require() directly inside a class grants access to private methods to the loaded code function load_file( $path ) { - require $path; + require_once $path; } function load_command( $name ) { From 869c29037863e267757aa2de8bddcb5e91a21feb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 14:17:59 +0000 Subject: [PATCH 3025/5359] Update step to handle directories too --- features/steps/then.php | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/features/steps/then.php b/features/steps/then.php index 428001a5f..ef11a52bb 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -120,32 +120,47 @@ function ( $world, $stream ) { } ); -$steps->Then( '/^the (.+) file should (exist|not exist|be:|contain:|not contain:)$/', - function ( $world, $path, $action, $expected = null ) { +$steps->Then( '/^the (.+) (file|directory) should (exist|not exist|be:|contain:|not contain:)$/', + function ( $world, $path, $type, $action, $expected = null ) { $path = $world->replace_variables( $path ); // If it's a relative path, make it relative to the current test dir if ( '/' !== $path[0] ) $path = $world->variables['RUN_DIR'] . "/$path"; + if ( 'file' == $type ) { + $test = 'file_exists'; + } else if ( 'directory' == $type ) { + $test = 'is_dir'; + } + switch ( $action ) { case 'exist': - if ( !file_exists( $path ) ) { + if ( ! $test( $path ) ) { throw new Exception( $world->result ); } break; case 'not exist': - if ( file_exists( $path ) ) { + if ( $test( $path ) ) { throw new Exception( $world->result ); } break; default: - if ( !file_exists( $path ) ) { + if ( ! $test( $path ) ) { throw new Exception( "$path doesn't exist." ); } $action = substr( $action, 0, -1 ); $expected = $world->replace_variables( (string) $expected ); - checkString( file_get_contents( $path ), $expected, $action ); + if ( 'file' == $type ) { + $contents = file_get_contents( $path ); + } else if ( 'directory' == $type ) { + $files = glob( rtrim( $path, '/' ) . '/*' ); + foreach( $files as &$file ) { + $file = str_replace( $path . '/', '', $file ); + } + $contents = implode( PHP_EOL, $files ); + } + checkString( $contents, $expected, $action ); } } ); From 10c30e447781d7a38787349141bd5a29b2ba7cf3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 14:18:15 +0000 Subject: [PATCH 3026/5359] Test coverage for scaffolding plugin unit tests --- features/scaffold.feature | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 419590e3d..f66047491 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -80,4 +80,28 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world` Then STDOUT should not be empty And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist - And the {PLUGIN_DIR}/hello-world/readme.txt file should exist \ No newline at end of file + And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + + Scenario: Scaffold plugin tests + When I run `wp plugin path` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin hello-world --skip-tests` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist + And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + And the {PLUGIN_DIR}/hello-world/tests directory should not exist + + When I run `wp scaffold plugin-tests hello-world` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/tests directory should contain: + """ + bootstrap.php + test-sample.php + """ + And the {PLUGIN_DIR}/hello-world/bin directory should contain: + """ + install-wp-tests.sh + """ + And the {PLUGIN_DIR}/hello-world/phpunit.xml file should exist + And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist From a9dd218f25d73a8bc7f64676007f1d098ddfa499 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 14:27:49 +0000 Subject: [PATCH 3027/5359] Mark install script as executable after copy --- features/scaffold.feature | 6 ++++++ php/commands/scaffold.php | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index f66047491..f7fa235fd 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -105,3 +105,9 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/phpunit.xml file should exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist + + When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` + Then STDOUT should be: + """ + executable + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index e090fa582..0aa9addee 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -397,6 +397,11 @@ function plugin_tests( $args, $assoc_args ) { foreach ( $to_copy as $file => $dir ) { $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); + if ( 'install-wp-tests.sh' === $file ) { + if ( ! $wp_filesystem->chmod( "$dir/$file", '0755' ) ) { + WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); + } + } } WP_CLI::success( "Created test files." ); From 4288363866e9985776560a4cdb89741ba35a3db5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 17:47:22 +0000 Subject: [PATCH 3028/5359] Add methods to DocParser for getting arg descriptions --- php/WP_CLI/DocParser.php | 31 +++++++++++++++++++++++++++++++ tests/test-doc-parser.php | 14 ++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index b95df6e07..948db7009 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -57,5 +57,36 @@ function get_synopsis() { return $matches[1]; } + + /** + * Get the description for a given argument. + * + * @param string $name Argument's doc name. + * @return string + */ + public function get_argdesc( $name ) { + + if ( preg_match( "/\[?<{$name}>[\S]+\n: (.+?)(\n|$)/s", $this->docComment, $matches ) ) { + return $matches[1]; + } + + return ''; + + } + + /** + * Get the description for a given parameter. + * + * @param string $key Parameter's key. + * @return string + */ + public function get_paramdesc( $key ) { + + if ( preg_match( "/\[?--{$key}=[\S]+\n: (.+?)(\n|$)/s", $this->docComment, $matches ) ) { + return $matches[1]; + } + + return ''; + } } diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index 413848191..fc8202093 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -50,9 +50,15 @@ function test_complete() { * * ## OPTIONS * + * <genre>... + * : Start with one or more genres. + * * --volume=<number> * : Sets the volume. * + * --artist=<artist-name> + * : Limit to a specific artist. + * * ## EXAMPLES * * wp rock-on --volume=11 @@ -65,14 +71,22 @@ function test_complete() { $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); $this->assertEquals( '[--volume=<number>]', $doc->get_synopsis() ); + $this->assertEquals( 'Start with one or more genres.', $doc->get_argdesc( 'genre' ) ); + $this->assertEquals( 'Sets the volume.', $doc->get_paramdesc( 'volume' ) ); $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); $longdesc = <<<EOB ## OPTIONS +<genre>... +: Start with one or more genres. + --volume=<number> : Sets the volume. +--artist=<artist-name> +: Limit to a specific artist. + ## EXAMPLES wp rock-on --volume=11 From 8bc33d7efaf9721e0711a3eb06753554adc53466 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 17:48:44 +0000 Subject: [PATCH 3029/5359] Show param description when required param is missing --- features/core.feature | 2 +- php/WP_CLI/Dispatcher/CompositeCommand.php | 3 ++- php/WP_CLI/Dispatcher/Subcommand.php | 7 +++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index 8fec27a7c..f7f1b8690 100644 --- a/features/core.feature +++ b/features/core.feature @@ -110,7 +110,7 @@ Feature: Manage WordPress installation Then the return code should be 1 And STDERR should contain: """ - missing --url parameter + missing --url parameter (The address of the new site.) """ When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 77cad3905..7296652f7 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -10,7 +10,7 @@ */ class CompositeCommand { - protected $name, $shortdesc, $synopsis; + protected $name, $shortdesc, $synopsis, $docparser; protected $parent, $subcommands = array(); @@ -28,6 +28,7 @@ public function __construct( $parent, $name, $docparser ) { $this->shortdesc = $docparser->get_shortdesc(); $this->longdesc = $docparser->get_longdesc(); + $this->docparser = $docparser; $when_to_invoke = $docparser->get_tag( 'when' ); if ( $when_to_invoke ) { diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 673bc99f3..d970f428d 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -254,8 +254,11 @@ private function validate_args( $args, $assoc_args, $extra_args ) { if ( !empty( $errors['fatal'] ) ) { $out = 'Parameter errors:'; - foreach ( $errors['fatal'] as $error ) { - $out .= "\n " . $error; + foreach ( $errors['fatal'] as $key => $error ) { + $out .= "\n {$error}"; + if ( $desc = $this->docparser->get_paramdesc( $key ) ) { + $out .= " ({$desc})"; + } } \WP_CLI::error( $out ); From f904673c9cf31b6c340d0359bb79a2243a9bce5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 17:52:44 +0000 Subject: [PATCH 3030/5359] Don't be so grabby, and accommodate trailing whitespace --- php/WP_CLI/DocParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 948db7009..b9b046583 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -66,7 +66,7 @@ function get_synopsis() { */ public function get_argdesc( $name ) { - if ( preg_match( "/\[?<{$name}>[\S]+\n: (.+?)(\n|$)/s", $this->docComment, $matches ) ) { + if ( preg_match( "/\[?<{$name}>.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { return $matches[1]; } @@ -82,7 +82,7 @@ public function get_argdesc( $name ) { */ public function get_paramdesc( $key ) { - if ( preg_match( "/\[?--{$key}=[\S]+\n: (.+?)(\n|$)/s", $this->docComment, $matches ) ) { + if ( preg_match( "/\[?--{$key}=.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { return $matches[1]; } From 2646ef86cc64f8c28d161a1dc3b5311c3693d085 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:27:06 +0000 Subject: [PATCH 3031/5359] Support for detailed results from `WP_CLI::launch()` and `::launch_self()` --- php/class-wp-cli.php | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ea54f18c0..f7c528c8e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -347,16 +347,42 @@ static function error_to_string( $errors ) { * * @param string Command to call * @param bool Whether to exit if the command returns an error status + * @param bool Whether to return an exit status (default) or detailed execution results * * @return int The command exit status */ - static function launch( $command, $exit_on_error = true ) { - $r = proc_close( proc_open( $command, array( STDIN, STDOUT, STDERR ), $pipes ) ); + static function launch( $command, $exit_on_error = true, $return_detailed = false ) { + + if ( $return_detailed ) { + $descriptorspec = array( + 0 => array( 'file', 'php://stdin', 'r' ), + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + } else { + $descriptorspec = array( STDIN, STDOUT, STDERR ); + } + + $process = proc_open( $command, $descriptorspec, $pipes ); + + if ( $return_detailed ) { + $ret_val = array( + 'stdout' => stream_get_contents( $pipes[1] ), + 'stderr' => stream_get_contents( $pipes[2] ), + ); + } + + $r = proc_close( $process ); if ( $r && $exit_on_error ) exit($r); - return $r; + if ( $return_detailed ) { + $ret_val['exit_status'] = $r; + return $ret_val; + } else { + return $r; + } } /** @@ -366,10 +392,11 @@ static function launch( $command, $exit_on_error = true ) { * @param array $args Positional arguments to use * @param array $assoc_args Associative arguments to use * @param bool Whether to exit if the command returns an error status + * @param bool Whether to return an exit status (default) or detailed execution results * * @return int The command exit status */ - static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true ) { + static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false ) { $reused_runtime_args = array( 'path', 'url', @@ -391,7 +418,7 @@ static function launch_self( $command, $args = array(), $assoc_args = array(), $ $full_command = "{$php_bin} {$script_path} {$command} {$args} {$assoc_args}"; - return self::launch( $full_command, $exit_on_error ); + return self::launch( $full_command, $exit_on_error, $return_detailed ); } /** From 893df5603a0f1cccc3d8ce4aad5b956d346a91b0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:32:32 +0000 Subject: [PATCH 3032/5359] Better naming for these methods. --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/WP_CLI/DocParser.php | 4 ++-- tests/test-doc-parser.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index d970f428d..373ee4e61 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -256,7 +256,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $out = 'Parameter errors:'; foreach ( $errors['fatal'] as $key => $error ) { $out .= "\n {$error}"; - if ( $desc = $this->docparser->get_paramdesc( $key ) ) { + if ( $desc = $this->docparser->get_param_desc( $key ) ) { $out .= " ({$desc})"; } } diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index b9b046583..29e51e66a 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -64,7 +64,7 @@ function get_synopsis() { * @param string $name Argument's doc name. * @return string */ - public function get_argdesc( $name ) { + public function get_arg_desc( $name ) { if ( preg_match( "/\[?<{$name}>.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { return $matches[1]; @@ -80,7 +80,7 @@ public function get_argdesc( $name ) { * @param string $key Parameter's key. * @return string */ - public function get_paramdesc( $key ) { + public function get_param_desc( $key ) { if ( preg_match( "/\[?--{$key}=.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { return $matches[1]; diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index fc8202093..150a33158 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -71,8 +71,8 @@ function test_complete() { $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); $this->assertEquals( '[--volume=<number>]', $doc->get_synopsis() ); - $this->assertEquals( 'Start with one or more genres.', $doc->get_argdesc( 'genre' ) ); - $this->assertEquals( 'Sets the volume.', $doc->get_paramdesc( 'volume' ) ); + $this->assertEquals( 'Start with one or more genres.', $doc->get_arg_desc( 'genre' ) ); + $this->assertEquals( 'Sets the volume.', $doc->get_param_desc( 'volume' ) ); $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); $longdesc = <<<EOB From ebbcf6788dd61e9e2172f63abb7e411b5ec066ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:36:55 +0000 Subject: [PATCH 3033/5359] Include the key in the error response This is later used to look up more details about the argument. --- php/WP_CLI/SynopsisValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index 7c56f98e8..ea2f59394 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -63,12 +63,12 @@ public function validate_assoc( $assoc_args ) { if ( !isset( $assoc_args[ $key ] ) ) { if ( !$param['optional'] ) { - $errors['fatal'][] = "missing --$key parameter"; + $errors['fatal'][$key] = "missing --$key parameter"; } } else { if ( true === $assoc_args[ $key ] && !$param['value']['optional'] ) { $error_type = ( !$param['optional'] ) ? 'fatal' : 'warning'; - $errors[ $error_type ][] = "--$key parameter needs a value"; + $errors[ $error_type ][$key] = "--$key parameter needs a value"; $to_unset[] = $key; } From 5f691cad3e14fe4ca106c06c2ccdb85824208567 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:46:40 +0000 Subject: [PATCH 3034/5359] Relocate the Process class so we can use it in WP-CLI --- features/bootstrap/FeatureContext.php | 2 ++ {features/bootstrap => php/WP_CLI}/Process.php | 2 ++ 2 files changed, 4 insertions(+) rename {features/bootstrap => php/WP_CLI}/Process.php (98%) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 20dda8ab5..1ddc7d753 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -5,9 +5,11 @@ Behat\Behat\Context\BehatContext, Behat\Behat\Event\SuiteEvent; +use \WP_CLI\Process; use \WP_CLI\Utils; require_once __DIR__ . '/../../php/utils.php'; +require_once __DIR__ . '/../../php/WP_CLI/Process.php'; /** * Features context. diff --git a/features/bootstrap/Process.php b/php/WP_CLI/Process.php similarity index 98% rename from features/bootstrap/Process.php rename to php/WP_CLI/Process.php index a8a3334b5..a2589385b 100644 --- a/features/bootstrap/Process.php +++ b/php/WP_CLI/Process.php @@ -1,5 +1,7 @@ <?php +namespace WP_CLI; + class Process { public static function create( $command, $cwd = null, $env = array() ) { From 2421b382f74f48792b43663ba596a8ba4b07aa47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:55:24 +0000 Subject: [PATCH 3035/5359] Refactor `WP_CLI\Process` so it isn't Behat-specific --- features/bootstrap/FeatureContext.php | 26 ++++++++++++++++++++------ features/steps/given.php | 3 ++- features/steps/when.php | 3 ++- php/WP_CLI/Process.php | 11 ++--------- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 1ddc7d753..522749708 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -26,6 +26,20 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { public $variables = array(); + /** + * Get the environment variables required for launched `wp` processes + * @beforeSuite + */ + private static function get_process_env_variables() { + // Ensure we're using the expected `wp` binary + $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); + $env = array( + 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), + 'BEHAT_RUN' => 1 + ); + return $env; + } + // We cache the results of `wp core download` to improve test performance // Ideally, we'd cache at the HTTP layer for more reliable tests private static function cache_wp_files() { @@ -35,7 +49,7 @@ private static function cache_wp_files() { return; $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); - Process::create( $cmd )->run_check(); + Process::create( $cmd, null, self::get_process_env_variables() )->run_check(); } /** @@ -50,7 +64,7 @@ public static function prepare( SuiteEvent $event ) { */ public static function afterSuite( SuiteEvent $event ) { if ( self::$suite_cache_dir ) { - Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ) )->run(); + Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ), null, self::get_process_env_variables() )->run(); } } @@ -63,7 +77,7 @@ public function afterScenario( $event ) { // remove altered WP install, unless there's an error if ( $event->getResult() < 4 ) { - Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); + Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ), null, self::get_process_env_variables() )->run(); } } @@ -116,7 +130,7 @@ public function create_run_dir() { private function set_cache_dir() { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ), null, self::get_process_env_variables() )->run_check(); $this->variables['CACHE_DIR'] = $path; } @@ -143,7 +157,7 @@ public function proc( $command, $assoc_args = array() ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); - $env = array(); + $env = self::get_process_env_variables(); if ( isset( $this->variables['SUITE_CACHE_DIR'] ) ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } @@ -166,7 +180,7 @@ public function download_wp( $subdir = '' ) { if ( $subdir ) mkdir( $dest_dir ); - Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); + Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ), null, self::get_process_env_variables() )->run_check(); // disable emailing mkdir( $dest_dir . '/wp-content/mu-plugins' ); diff --git a/features/steps/given.php b/features/steps/given.php index 8fa71cf42..10eb318f0 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -1,7 +1,8 @@ <?php use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode; + Behat\Gherkin\Node\TableNode, + WP_CLI\Process; $steps->Given( '/^an empty directory$/', function ( $world ) { diff --git a/features/steps/when.php b/features/steps/when.php index 81b4c9a6d..68ff28baf 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -1,7 +1,8 @@ <?php use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode; + Behat\Gherkin\Node\TableNode, + WP_CLI\Process; function invoke_proc( $proc, $mode, $subdir = null ) { $map = array( diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index a2589385b..9e853c438 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -30,14 +30,7 @@ public function run( $subdir = '' ) { 2 => array( 'pipe', 'w' ), ); - // Ensure we're using the expected `wp` binary - $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); - $env = array_merge( $this->env, array( - 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), - 'BEHAT_RUN' => 1 - ) ); - - $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $env ); + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); @@ -51,7 +44,7 @@ public function run( $subdir = '' ) { 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd, - 'env' => $env + 'env' => $this->env ) ); } From ab394eb23f49ca41bc78ab99081d064231a0fd3b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 18:55:46 +0000 Subject: [PATCH 3036/5359] Use our new Process class for `WP_CLI::launch()` --- php/class-wp-cli.php | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f7c528c8e..8b5ba0e34 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -353,35 +353,16 @@ static function error_to_string( $errors ) { */ static function launch( $command, $exit_on_error = true, $return_detailed = false ) { - if ( $return_detailed ) { - $descriptorspec = array( - 0 => array( 'file', 'php://stdin', 'r' ), - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); - } else { - $descriptorspec = array( STDIN, STDOUT, STDERR ); - } - - $process = proc_open( $command, $descriptorspec, $pipes ); - - if ( $return_detailed ) { - $ret_val = array( - 'stdout' => stream_get_contents( $pipes[1] ), - 'stderr' => stream_get_contents( $pipes[2] ), - ); - } - - $r = proc_close( $process ); + $proc = new Process( $command ); + $results = $proc->run(); - if ( $r && $exit_on_error ) - exit($r); + if ( $results['return_code'] && $exit_on_error ) + exit( $results['return_code'] ); if ( $return_detailed ) { - $ret_val['exit_status'] = $r; - return $ret_val; + return $results; } else { - return $r; + return $results['return_code']; } } From 1f8b5679644e48df1ddd84341f76ecde574fd968 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 19:02:00 +0000 Subject: [PATCH 3037/5359] Fix my broken code :( --- php/class-wp-cli.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 8b5ba0e34..ce801abbc 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -3,6 +3,7 @@ use \WP_CLI\Utils; use \WP_CLI\Dispatcher; use \WP_CLI\FileCache; +use \WP_CLI\Process; use \WP_CLI\WpHttpCacheManager; /** @@ -353,8 +354,8 @@ static function error_to_string( $errors ) { */ static function launch( $command, $exit_on_error = true, $return_detailed = false ) { - $proc = new Process( $command ); - $results = $proc->run(); + $proc = Process::create( $command ); + $results = (array)$proc->run(); if ( $results['return_code'] && $exit_on_error ) exit( $results['return_code'] ); From 53acced15c3048cefb8d87ddcb22d30a6c47931c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 19:03:54 +0000 Subject: [PATCH 3038/5359] Returning the instance will give more flexibility in the future --- php/class-wp-cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ce801abbc..3ec3d0cb8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -350,20 +350,20 @@ static function error_to_string( $errors ) { * @param bool Whether to exit if the command returns an error status * @param bool Whether to return an exit status (default) or detailed execution results * - * @return int The command exit status + * @return int|ProcessRun The command exit status, or a ProcessRun instance */ static function launch( $command, $exit_on_error = true, $return_detailed = false ) { $proc = Process::create( $command ); - $results = (array)$proc->run(); + $results = $proc->run(); - if ( $results['return_code'] && $exit_on_error ) - exit( $results['return_code'] ); + if ( $results->return_code && $exit_on_error ) + exit( $results->return_code ); if ( $return_detailed ) { return $results; } else { - return $results['return_code']; + return $results->return_code; } } @@ -376,7 +376,7 @@ static function launch( $command, $exit_on_error = true, $return_detailed = fals * @param bool Whether to exit if the command returns an error status * @param bool Whether to return an exit status (default) or detailed execution results * - * @return int The command exit status + * @return int|ProcessRun The command exit status, or a ProcessRun instance */ static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false ) { $reused_runtime_args = array( From 05d0a8fea8d9493d9a174fa380a30c2db21e30a0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 19:12:05 +0000 Subject: [PATCH 3039/5359] Throw an error when post type slug is too long --- features/scaffold.feature | 7 +++++++ php/commands/scaffold.php | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index f7fa235fd..3ec35028b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -65,6 +65,13 @@ Feature: WordPress code scaffolding __( 'Zombies', 'zombieland' """ + Scenario: CPT slug is too long + When I try `wp scaffold post-type slugiswaytoolonginfact` + Then STDERR should be: + """ + Error: Post type slugs cannot exceed 20 characters in length. + """ + @cpt Scenario: Scaffold a Custom Post Type with label When I run `wp scaffold post-type zombie --label="Brain eater"` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 0aa9addee..b35ce22b3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -42,6 +42,11 @@ function __construct() { * @alias cpt */ function post_type( $args, $assoc_args ) { + + if ( strlen( $args[0] ) > 20 ) { + WP_CLI::error( "Post type slugs cannot exceed 20 characters in length." ); + } + $defaults = array( 'textdomain' => '', ); From 35444539dd871b44acaef86054353e982593f6e2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 19:14:36 +0000 Subject: [PATCH 3040/5359] This class is now in local scope --- features/steps/given.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/given.php b/features/steps/given.php index 10eb318f0..5f88f60a8 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -96,7 +96,7 @@ function ( $world, TableNode $table ) { continue; } - \Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); + Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); } } ); From da7462a11c983f7e01ad18da0548d5a9c3d4f379 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:01:01 +0000 Subject: [PATCH 3041/5359] Only constants should be uppercased --- php/WP_CLI/Process.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 9e853c438..7a0add5bc 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -32,15 +32,15 @@ public function run( $subdir = '' ) { $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); - $STDOUT = stream_get_contents( $pipes[1] ); + $stdout = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); - $STDERR = stream_get_contents( $pipes[2] ); + $stderr = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); return new ProcessRun( array( - 'STDOUT' => $STDOUT, - 'STDERR' => $STDERR, + 'stdout' => $stdout, + 'stderr' => $stderr, 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd, From 837c4984e0578d16121f6193892b6578271b6275 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:05:10 +0000 Subject: [PATCH 3042/5359] Couple more instances need to be lowercase --- php/WP_CLI/Process.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 7a0add5bc..88f05666b 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -51,7 +51,7 @@ public function run( $subdir = '' ) { public function run_check( $subdir = '' ) { $r = $this->run( $subdir ); - if ( $r->return_code || !empty( $r->STDERR ) ) { + if ( $r->return_code || !empty( $r->stderr ) ) { throw new \RuntimeException( $r ); } @@ -70,7 +70,7 @@ public function __construct( $props ) { public function __toString() { $out = "$ $this->command\n"; - $out .= "$this->STDOUT\n$this->STDERR"; + $out .= "$this->stdout\n$this->stderr"; $out .= "cwd: $this->cwd\n"; $out .= "exit status: $this->return_code"; From 282b6b9782c115cca2814d0418a88b225328dc61 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:05:32 +0000 Subject: [PATCH 3043/5359] Deprecate this argument, which should be a part of construct anyway --- features/bootstrap/FeatureContext.php | 9 +++++---- php/WP_CLI/Process.php | 9 +++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 522749708..994313bf1 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -153,7 +153,7 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - public function proc( $command, $assoc_args = array() ) { + public function proc( $command, $assoc_args = array(), $path = '' ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); @@ -162,7 +162,8 @@ public function proc( $command, $assoc_args = array() ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } - return Process::create( $command, $this->variables['RUN_DIR'], $env ); + $path = $this->variables['RUN_DIR'] + $path; + return Process::create( $command, $path, $env ); } public function move_files( $src, $dest ) { @@ -192,7 +193,7 @@ public function create_config( $subdir = '' ) { $params['dbprefix'] = $subdir ?: 'wp_'; $params['skip-salts'] = true; - $this->proc( 'wp core config', $params )->run_check( $subdir ); + $this->proc( 'wp core config', $params, $subdir )->run_check(); } public function install_wp( $subdir = '' ) { @@ -210,7 +211,7 @@ public function install_wp( $subdir = '' ) { 'admin_password' => 'password1' ); - $this->proc( 'wp core install', $install_args )->run_check( $subdir ); + $this->proc( 'wp core install', $install_args, $subdir )->run_check(); } } diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 88f05666b..e17ba66e2 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -18,11 +18,8 @@ public static function create( $command, $cwd = null, $env = array() ) { private function __construct() {} - public function run( $subdir = '' ) { + public function run() { $cwd = $this->cwd; - if ( $subdir ) { - $cwd .= '/' . $subdir; - } $descriptors = array( 0 => STDIN, @@ -48,8 +45,8 @@ public function run( $subdir = '' ) { ) ); } - public function run_check( $subdir = '' ) { - $r = $this->run( $subdir ); + public function run_check() { + $r = $this->run(); if ( $r->return_code || !empty( $r->stderr ) ) { throw new \RuntimeException( $r ); From d311435472ea5b4436725a2c1c983489ba71c680 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:08:54 +0000 Subject: [PATCH 3044/5359] Backwards compat, because a lot of stuff breaks --- php/WP_CLI/Process.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index e17ba66e2..712bf475a 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -62,6 +62,11 @@ class ProcessRun { public function __construct( $props ) { foreach ( $props as $key => $value ) { $this->$key = $value; + // Backwards compat + if ( in_array( $key, array( 'stdout', 'stderr' ) ) ) { + $key = strtoupper( $key ); + $this->$key = $value; + } } } From c8cd93788841318d1fdefa7bec17e933571a4380 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:10:48 +0000 Subject: [PATCH 3045/5359] Revert "Only constants should be uppercased" This reverts commit da7462a11c983f7e01ad18da0548d5a9c3d4f379. --- php/WP_CLI/Process.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 712bf475a..d5d73576e 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -29,15 +29,15 @@ public function run() { $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); - $stdout = stream_get_contents( $pipes[1] ); + $STDOUT = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); - $stderr = stream_get_contents( $pipes[2] ); + $STDERR = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); return new ProcessRun( array( - 'stdout' => $stdout, - 'stderr' => $stderr, + 'STDOUT' => $STDOUT, + 'STDERR' => $STDERR, 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd, From 3a27f2bd9c7c73b03705e2eaba92d3166f2c5c20 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:11:10 +0000 Subject: [PATCH 3046/5359] Revert "Couple more instances need to be lowercase" This reverts commit 837c4984e0578d16121f6193892b6578271b6275. --- php/WP_CLI/Process.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index d5d73576e..2f45f8f0f 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -48,7 +48,7 @@ public function run() { public function run_check() { $r = $this->run(); - if ( $r->return_code || !empty( $r->stderr ) ) { + if ( $r->return_code || !empty( $r->STDERR ) ) { throw new \RuntimeException( $r ); } @@ -72,7 +72,7 @@ public function __construct( $props ) { public function __toString() { $out = "$ $this->command\n"; - $out .= "$this->stdout\n$this->stderr"; + $out .= "$this->STDOUT\n$this->STDERR"; $out .= "cwd: $this->cwd\n"; $out .= "exit status: $this->return_code"; From 2474fea3a1ad7763eceb7f0c6bd09e1a8ecdaf28 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:13:28 +0000 Subject: [PATCH 3047/5359] Properly handle `$path` --- features/bootstrap/FeatureContext.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 994313bf1..7a4c24e38 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -153,7 +153,7 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - public function proc( $command, $assoc_args = array(), $path = '' ) { + public function proc( $command, $assoc_args = array(), $path = null ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); @@ -162,7 +162,12 @@ public function proc( $command, $assoc_args = array(), $path = '' ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } - $path = $this->variables['RUN_DIR'] + $path; + if ( $path ) { + $path = $this->variables['RUN_DIR'] + $path; + } else { + $path = $this->variables['RUN_DIR']; + } + return Process::create( $command, $path, $env ); } From 563b84b38cd85ddf7c64de5d647fb62b4034e359 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 18 Jul 2014 20:13:51 +0000 Subject: [PATCH 3048/5359] Revert "Backwards compat, because a lot of stuff breaks" This reverts commit d311435472ea5b4436725a2c1c983489ba71c680. --- php/WP_CLI/Process.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 2f45f8f0f..eb8ae700c 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -62,11 +62,6 @@ class ProcessRun { public function __construct( $props ) { foreach ( $props as $key => $value ) { $this->$key = $value; - // Backwards compat - if ( in_array( $key, array( 'stdout', 'stderr' ) ) ) { - $key = strtoupper( $key ); - $this->$key = $value; - } } } From d921af93be02de5216777ae700d93b585b70160c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 19:44:53 +0000 Subject: [PATCH 3049/5359] Lowercase for STDOUT and STDERR as variables --- features/steps/given.php | 2 ++ features/steps/then.php | 15 +++++++++++++++ php/WP_CLI/Process.php | 10 +++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/features/steps/given.php b/features/steps/given.php index 5f88f60a8..3e7a7b26d 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -104,6 +104,8 @@ function ( $world, TableNode $table ) { $steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { + $stream = strtolower( $stream ); + if ( $output_filter ) { $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) diff --git a/features/steps/then.php b/features/steps/then.php index ef11a52bb..819899ff9 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -13,6 +13,9 @@ function ( $world, $return_code ) { $steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', function ( $world, $stream, $action, PyStringNode $expected ) { + + $stream = strtolower( $stream ); + $expected = $world->replace_variables( (string) $expected ); checkString( $world->result->$stream, $expected, $action, $world->result ); @@ -21,12 +24,18 @@ function ( $world, $stream, $action, PyStringNode $expected ) { $steps->Then( '/^(STDOUT|STDERR) should be a number$/', function ( $world, $stream ) { + + $stream = strtolower( $stream ); + assertNumeric( trim( $world->result->$stream, "\n" ) ); } ); $steps->Then( '/^(STDOUT|STDERR) should not be a number$/', function ( $world, $stream ) { + + $stream = strtolower( $stream ); + assertNotNumeric( trim( $world->result->$stream, "\n" ) ); } ); @@ -106,6 +115,9 @@ function ( $world, TableNode $expected ) { $steps->Then( '/^(STDOUT|STDERR) should be empty$/', function ( $world, $stream ) { + + $stream = strtolower( $stream ); + if ( !empty( $world->result->$stream ) ) { throw new \Exception( $world->result ); } @@ -114,6 +126,9 @@ function ( $world, $stream ) { $steps->Then( '/^(STDOUT|STDERR) should not be empty$/', function ( $world, $stream ) { + + $stream = strtolower( $stream ); + if ( '' === rtrim( $world->result->$stream, "\n" ) ) { throw new Exception( $world->result ); } diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index eb8ae700c..8245e4714 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -29,15 +29,15 @@ public function run() { $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); - $STDOUT = stream_get_contents( $pipes[1] ); + $stdout = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); - $STDERR = stream_get_contents( $pipes[2] ); + $stderr = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); return new ProcessRun( array( - 'STDOUT' => $STDOUT, - 'STDERR' => $STDERR, + 'stdout' => $stdout, + 'stderr' => $stderr, 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd, @@ -67,7 +67,7 @@ public function __construct( $props ) { public function __toString() { $out = "$ $this->command\n"; - $out .= "$this->STDOUT\n$this->STDERR"; + $out .= "$this->stdout\n$this->stderr"; $out .= "cwd: $this->cwd\n"; $out .= "exit status: $this->return_code"; From 77eda6203a6ca24c847c1b7b8c752025c6d62734 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 19:46:41 +0000 Subject: [PATCH 3050/5359] Few more instances need to be lowercased --- features/steps/then.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/steps/then.php b/features/steps/then.php index 819899ff9..f2e15fb32 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -42,7 +42,7 @@ function ( $world, $stream ) { $steps->Then( '/^STDOUT should be a table containing rows:$/', function ( $world, TableNode $expected ) { - $output = $world->result->STDOUT; + $output = $world->result->stdout; $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); $expected_rows = array(); @@ -56,7 +56,7 @@ function ( $world, TableNode $expected ) { $steps->Then( '/^STDOUT should end with a table containing rows:$/', function ( $world, TableNode $expected ) { - $output = $world->result->STDOUT; + $output = $world->result->stdout; $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); $expected_rows = array(); @@ -75,7 +75,7 @@ function ( $world, TableNode $expected ) { $steps->Then( '/^STDOUT should be JSON containing:$/', function ( $world, PyStringNode $expected ) { - $output = $world->result->STDOUT; + $output = $world->result->stdout; $expected = $world->replace_variables( (string) $expected ); if ( !checkThatJsonStringContainsJsonString( $output, $expected ) ) { @@ -85,7 +85,7 @@ function ( $world, PyStringNode $expected ) { $steps->Then( '/^STDOUT should be a JSON array containing:$/', function ( $world, PyStringNode $expected ) { - $output = $world->result->STDOUT; + $output = $world->result->stdout; $expected = $world->replace_variables( (string) $expected ); $actualValues = json_decode( $output ); @@ -99,7 +99,7 @@ function ( $world, PyStringNode $expected ) { $steps->Then( '/^STDOUT should be CSV containing:$/', function ( $world, TableNode $expected ) { - $output = $world->result->STDOUT; + $output = $world->result->stdout; $expected_rows = $expected->getRows(); foreach ( $expected as &$row ) { From 445ccd55a6deb20b3d0269116192096e2276f43b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 19:50:28 +0000 Subject: [PATCH 3051/5359] Coding standards --- features/bootstrap/FeatureContext.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 7a4c24e38..de58f738c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -184,7 +184,9 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) { public function download_wp( $subdir = '' ) { $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; - if ( $subdir ) mkdir( $dest_dir ); + if ( $subdir ) { + mkdir( $dest_dir ); + } Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ), null, self::get_process_env_variables() )->run_check(); From 8e7f082e6f10afb4509ee34a1e97ed9b4be880c5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 19:51:36 +0000 Subject: [PATCH 3052/5359] Fix string concatenation --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index de58f738c..6881e6d22 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -163,7 +163,7 @@ public function proc( $command, $assoc_args = array(), $path = null ) { } if ( $path ) { - $path = $this->variables['RUN_DIR'] + $path; + $path = rtrim( $this->variables['RUN_DIR'], '/' ) . '/' . $path; } else { $path = $this->variables['RUN_DIR']; } From ee8a2d54bc381e85c3072dc83115f0587a6d5696 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 20:03:37 +0000 Subject: [PATCH 3053/5359] Pass subdir when instantiating --- features/steps/when.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/steps/when.php b/features/steps/when.php index 68ff28baf..55651d9b3 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -4,14 +4,14 @@ Behat\Gherkin\Node\TableNode, WP_CLI\Process; -function invoke_proc( $proc, $mode, $subdir = null ) { +function invoke_proc( $proc, $mode ) { $map = array( 'run' => 'run_check', 'try' => 'run' ); $method = $map[ $mode ]; - return $proc->$method( $subdir ); + return $proc->$method(); } $steps->When( '/^I (run|try) `([^`]+)`$/', @@ -24,7 +24,7 @@ function ( $world, $mode, $cmd ) { $steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", function ( $world, $mode, $cmd, $subdir ) { $cmd = $world->replace_variables( $cmd ); - $world->result = invoke_proc( $world->proc( $cmd ), $mode, $subdir ); + $world->result = invoke_proc( $world->proc( $cmd, array(), $subdir ), $mode ); } ); From 3c542ab6f74ae8b07cfe99c53e1e8444d9dcd7f5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 19 Jul 2014 20:04:37 +0000 Subject: [PATCH 3054/5359] Better way of building the string --- features/bootstrap/FeatureContext.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 6881e6d22..803c3379f 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -153,7 +153,7 @@ public function drop_db() { self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); } - public function proc( $command, $assoc_args = array(), $path = null ) { + public function proc( $command, $assoc_args = array(), $path = '' ) { if ( !empty( $assoc_args ) ) $command .= Utils\assoc_args_to_str( $assoc_args ); @@ -162,12 +162,7 @@ public function proc( $command, $assoc_args = array(), $path = null ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } - if ( $path ) { - $path = rtrim( $this->variables['RUN_DIR'], '/' ) . '/' . $path; - } else { - $path = $this->variables['RUN_DIR']; - } - + $path = "{$this->variables['RUN_DIR']}/{$path}"; return Process::create( $command, $path, $env ); } From 01791f19ff1e0a57f55e4e6519a45ee9ab0fadd7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 12:37:23 +0000 Subject: [PATCH 3055/5359] Doc coverage for `CommandWithDBObject` --- php/WP_CLI/CommandWithDBObject.php | 51 +++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index de831bab6..e7fed7a08 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -13,6 +13,14 @@ abstract class CommandWithDBObject extends \WP_CLI_Command { protected $obj_id_key = 'ID'; protected $obj_fields = null; + /** + * Create a given database object. + * Exits with status. + * + * @param array $args Arguments passed to command. Generally unused. + * @param array $assoc_args Parameters passed to command to be passed to callback. + * @param string $callback Function used to create object. + */ protected function _create( $args, $assoc_args, $callback ) { unset( $assoc_args[ $this->obj_id_key ] ); @@ -28,6 +36,14 @@ protected function _create( $args, $assoc_args, $callback ) { \WP_CLI::success( "Created $this->obj_type $obj_id." ); } + /** + * Update a given database object. + * Exits with status. + * + * @param array $args Collection of one or more object ids to update. + * @param array $assoc_args Fields => values to update on each object. + * @param string $callback Function used to update object. + */ protected function _update( $args, $assoc_args, $callback ) { $status = 0; @@ -47,6 +63,14 @@ protected function _update( $args, $assoc_args, $callback ) { exit( $status ); } + /** + * Delete a given database object. + * Exits with status. + * + * @param array $args Collection of one or more object ids to delete. + * @param array $assoc_args Any arguments needed for the callback function. + * @param string $callback Function used to delete object. + */ protected function _delete( $args, $assoc_args, $callback ) { $status = 0; @@ -58,6 +82,13 @@ protected function _delete( $args, $assoc_args, $callback ) { exit( $status ); } + /** + * Format callback response to consistent format. + * + * @param WP_Error|true $r Response from CRUD callback. + * @param string $success_msg + * @return array + */ protected function wp_error_to_resp( $r, $success_msg ) { if ( is_wp_error( $r ) ) return array( 'error', $r->get_error_message() ); @@ -65,6 +96,12 @@ protected function wp_error_to_resp( $r, $success_msg ) { return array( 'success', $success_msg ); } + /** + * Display success or warning based on response; return proper exit code. + * + * @param array $r Formatted from a CRUD callback. + * @return int $status + */ protected function success_or_failure( $r ) { list( $type, $msg ) = $r; @@ -79,10 +116,22 @@ protected function success_or_failure( $r ) { return $status; } + /** + * Get Formatter object based on supplied parameters. + * + * @param array $assoc_args Parameters passed to command. Determines formatting. + * @return \WP_CLI\Formatter + */ protected function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); } - + + /** + * Given a callback, display the URL for one or more objects. + * + * @param array $args One or more object references. + * @param string $callback Function to get URL for the object. + */ protected function _url( $args, $callback ) { foreach ( $args as $obj_id ) { $object = $this->fetcher->get_check( $obj_id ); From fc227023ac1446600758c61715250f4b6fd66b75 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 12:40:26 +0000 Subject: [PATCH 3056/5359] Param doc coverage for `CommandWithDBObject` --- php/WP_CLI/CommandWithDBObject.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index e7fed7a08..f7f99ff7f 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -9,8 +9,19 @@ */ abstract class CommandWithDBObject extends \WP_CLI_Command { + /** + * @param string $object_type WordPress' expected name for the object. + */ protected $obj_type; + + /** + * @param string $obj_id_key Key representing object's PK field in db. + */ protected $obj_id_key = 'ID'; + + /** + * @param array $obj_fields Default fields to display for each object. + */ protected $obj_fields = null; /** From 8760566abf333b6f973703e68dcd00637344216e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 12:43:33 +0000 Subject: [PATCH 3057/5359] Mark these explicitly `public` --- php/class-wp-cli.php | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3ec3d0cb8..63fb63f38 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -22,7 +22,7 @@ class WP_CLI { * * @param object $logger */ - static function set_logger( $logger ) { + public static function set_logger( $logger ) { self::$logger = $logger; } @@ -31,7 +31,7 @@ static function set_logger( $logger ) { * * @return \WP_CLI\Configurator */ - static function get_configurator() { + public static function get_configurator() { static $configurator; if ( !$configurator ) { @@ -41,7 +41,7 @@ static function get_configurator() { return $configurator; } - static function get_root_command() { + public static function get_root_command() { static $root; if ( !$root ) { @@ -51,7 +51,7 @@ static function get_root_command() { return $root; } - static function get_runner() { + public static function get_runner() { static $runner; if ( !$runner ) { @@ -92,7 +92,7 @@ public static function get_cache() { /** * Set the context in which WP-CLI should be run */ - static function set_url( $url ) { + public static function set_url( $url ) { $url_parts = Utils\parse_url( $url ); self::set_url_params( $url_parts ); } @@ -119,7 +119,7 @@ private static function set_url_params( $url_parts ) { /** * @return WpHttpCacheManager */ - static function get_http_cache_manager() { + public static function get_http_cache_manager() { static $http_cacher; if ( !$http_cacher ) { @@ -129,14 +129,14 @@ static function get_http_cache_manager() { return $http_cacher; } - static function colorize( $string ) { + public static function colorize( $string ) { return \cli\Colors::colorize( $string, self::get_runner()->in_color() ); } /** * Schedule a callback to be executed at a certain point (before WP is loaded). */ - static function add_hook( $when, $callback ) { + public static function add_hook( $when, $callback ) { if ( in_array( $when, self::$hooks_passed ) ) call_user_func( $callback ); @@ -146,7 +146,7 @@ static function add_hook( $when, $callback ) { /** * Execute registered callbacks. */ - static function do_hook( $when ) { + public static function do_hook( $when ) { self::$hooks_passed[] = $when; if ( !isset( self::$hooks[ $when ] ) ) @@ -165,7 +165,7 @@ static function do_hook( $when ) { * @param array $args An associative array with additional parameters: * 'before_invoke' => callback to execute before invoking the command */ - static function add_command( $name, $class, $args = array() ) { + public static function add_command( $name, $class, $args = array() ) { if ( isset( $args['before_invoke'] ) ) { self::add_hook( "before_invoke:$name", $args['before_invoke'] ); } @@ -206,7 +206,7 @@ static function add_command( $name, $class, $args = array() ) { * * @param string $message */ - static function line( $message = '' ) { + public static function line( $message = '' ) { echo $message . "\n"; } @@ -215,7 +215,7 @@ static function line( $message = '' ) { * * @param string $message */ - static function log( $message ) { + public static function log( $message ) { self::$logger->info( $message ); } @@ -224,7 +224,7 @@ static function log( $message ) { * * @param string $message */ - static function success( $message ) { + public static function success( $message ) { self::$logger->success( $message ); } @@ -233,7 +233,7 @@ static function success( $message ) { * * @param string $message */ - static function warning( $message ) { + public static function warning( $message ) { self::$logger->warning( self::error_to_string( $message ) ); } @@ -242,7 +242,7 @@ static function warning( $message ) { * * @param string $message */ - static function error( $message ) { + public static function error( $message ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { self::$logger->error( self::error_to_string( $message ) ); } @@ -253,7 +253,7 @@ static function error( $message ) { /** * Ask for confirmation before running a destructive operation. */ - static function confirm( $question, $assoc_args = array() ) { + public static function confirm( $question, $assoc_args = array() ) { if ( !isset( $assoc_args['yes'] ) ) { fwrite( STDOUT, $question . " [y/n] " ); @@ -293,7 +293,7 @@ public static function get_value_from_arg_or_stdin( $args, $index ) { * @param mixed $value * @param array $assoc_args */ - static function read_value( $raw_value, $assoc_args = array() ) { + public static function read_value( $raw_value, $assoc_args = array() ) { if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { $value = json_decode( $raw_value, true ); if ( null === $value ) { @@ -312,7 +312,7 @@ static function read_value( $raw_value, $assoc_args = array() ) { * @param mixed $value * @param array $assoc_args */ - static function print_value( $value, $assoc_args = array() ) { + public static function print_value( $value, $assoc_args = array() ) { if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { $value = json_encode( $value ); } elseif ( is_array( $value ) || is_object( $value ) ) { @@ -328,7 +328,7 @@ static function print_value( $value, $assoc_args = array() ) { * @param mixed $errors * @return string */ - static function error_to_string( $errors ) { + public static function error_to_string( $errors ) { if ( is_string( $errors ) ) { return $errors; } @@ -352,7 +352,7 @@ static function error_to_string( $errors ) { * * @return int|ProcessRun The command exit status, or a ProcessRun instance */ - static function launch( $command, $exit_on_error = true, $return_detailed = false ) { + public static function launch( $command, $exit_on_error = true, $return_detailed = false ) { $proc = Process::create( $command ); $results = $proc->run(); @@ -378,7 +378,7 @@ static function launch( $command, $exit_on_error = true, $return_detailed = fals * * @return int|ProcessRun The command exit status, or a ProcessRun instance */ - static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false ) { + public static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false ) { $reused_runtime_args = array( 'path', 'url', @@ -422,7 +422,7 @@ private static function get_php_binary() { return 'php'; } - static function get_config( $key = null ) { + public static function get_config( $key = null ) { if ( null === $key ) { return self::get_runner()->config; } @@ -441,7 +441,7 @@ static function get_config( $key = null ) { * @param array * @param array */ - static function run_command( $args, $assoc_args = array() ) { + public static function run_command( $args, $assoc_args = array() ) { self::get_runner()->run_command( $args, $assoc_args ); } @@ -449,17 +449,17 @@ static function run_command( $args, $assoc_args = array() ) { // DEPRECATED STUFF - static function add_man_dir() { + public static function add_man_dir() { trigger_error( 'WP_CLI::add_man_dir() is deprecated. Add docs inline.', E_USER_WARNING ); } // back-compat - static function out( $str ) { + public static function out( $str ) { fwrite( STDOUT, $str ); } // back-compat - static function addCommand( $name, $class ) { + public static function addCommand( $name, $class ) { trigger_error( sprintf( 'wp %s: %s is deprecated. use WP_CLI::add_command() instead.', $name, __FUNCTION__ ), E_USER_WARNING ); self::add_command( $name, $class ); From 94f600a3e91a1e0f9e413ab10ff461b8e74e0638 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 13:48:08 +0000 Subject: [PATCH 3058/5359] PHPdoc for standard logger --- php/WP_CLI/Loggers/Regular.php | 50 ++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index b3ad21213..f5dda04fc 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -2,35 +2,75 @@ namespace WP_CLI\Loggers; +/** + * Default logger for success, warning, error, and standard messages. + */ class Regular { + /** + * @param bool $in_color Whether or not to Colorize strings. + */ function __construct( $in_color ) { $this->in_color = $in_color; } + /** + * Write a string to a resource. + * + * @param resource $handle Commonly STDOUT or STDERR. + * @param string $str Message to write. + */ protected function write( $handle, $str ) { fwrite( $handle, $str ); } + /** + * Output one line of message to a resource. + * + * @param string $message Message to write. + * @param string $label Prefix message with a label. + * @param string $color Colorize label with a given color. + * @param resource $handle Resource to write to. Defaults to STDOUT. + */ private function _line( $message, $label, $color, $handle = STDOUT ) { $label = \cli\Colors::colorize( "$color$label:%n", $this->in_color ); $this->write( $handle, "$label $message\n" ); } - function info( $message ) { + /** + * Write an informational message to STDOUT. + * + * @param string $message Message to write. + */ + public function info( $message ) { $this->write( STDOUT, $message . "\n" ); } - function success( $message ) { + /** + * Write a success message, prefixed with "Success: ". + * + * @param string $message Message to write. + */ + public function success( $message ) { $this->_line( $message, 'Success', '%G' ); } - function warning( $message ) { + /** + * Write a warning message to STDERR, prefixed with "Warning: ". + * + * @param string $message Message to write. + */ + public function warning( $message ) { $this->_line( $message, 'Warning', '%C', STDERR ); } - function error( $message ) { + /** + * Write an message to STDERR, prefixed with "Error: ". + * + * @param string $message Message to write. + */ + public function error( $message ) { $this->_line( $message, 'Error', '%R', STDERR ); } -} +} From ca34d8b7069bbefbcb1b27ff614b585ae298c703 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 13:50:50 +0000 Subject: [PATCH 3059/5359] PHPdoc for the Quiet logger --- php/WP_CLI/Loggers/Quiet.php | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 6f32fbef3..6ccbb4029 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -2,22 +2,45 @@ namespace WP_CLI\Loggers; +/** + * Quiet logger only logs errors. + */ class Quiet { - function info( $message ) { + /** + * Informational messages aren't logged. + * + * @param string $message Message to write. + */ + public function info( $message ) { // nothing } - function success( $message ) { + /** + * Success messages aren't logged. + * + * @param string $message Message to write. + */ + public function success( $message ) { // nothing } - function warning( $message ) { + /** + * Warning messages aren't logged. + * + * @param string $message Message to write. + */ + public function warning( $message ) { // nothing } - function error( $message ) { + /** + * Write an error message to STDERR, prefixed with "Error: ". + * + * @param string $message Message to write. + */ + public function error( $message ) { fwrite( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); } -} +} From f82103f13b145eb0295ade266f16b96c148e6b0a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 14:37:00 +0000 Subject: [PATCH 3060/5359] These two should be explicitly public --- php/WP_CLI/Configurator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 92bffd9d5..9d79b110b 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -112,7 +112,7 @@ private function unmix_assoc_args( $mixed_args ) { return array( $assoc_args, $runtime_config ); } - function merge_yml( $path ) { + public function merge_yml( $path ) { foreach ( self::load_yml( $path ) as $key => $value ) { if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { $this->extra_config[ $key ] = $value; @@ -125,7 +125,7 @@ function merge_yml( $path ) { } } - function merge_array( $config ) { + public function merge_array( $config ) { foreach ( $this->spec as $key => $details ) { if ( false !== $details['runtime'] && isset( $config[ $key ] ) ) { $value = $config[ $key ]; From cc23fa99d23ee72aba84b2aed9313777ccdddb1a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 14:42:40 +0000 Subject: [PATCH 3061/5359] PHPdoc for `Configurator` --- php/WP_CLI/Configurator.php | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 9d79b110b..533629a42 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -9,11 +9,24 @@ */ class Configurator { + /** + * @param array $spec Configurator argument specification. + */ private $spec; + /** + * @param array $config Values for keys defined in Configurator spec. + */ private $config = array(); + + /** + * @param array $extra_config Extra config values not specified in spec. + */ private $extra_config = array(); + /** + * @param string $path Path to config spec file. + */ function __construct( $path ) { $this->spec = include $path; @@ -86,6 +99,12 @@ public static function extract_assoc( $arguments ) { return array( $positional_args, $assoc_args ); } + /** + * Separate runtime parameters from command-specific parameters. + * + * @param array $mixed_args + * @return array + */ private function unmix_assoc_args( $mixed_args ) { $assoc_args = $runtime_config = array(); @@ -112,6 +131,11 @@ private function unmix_assoc_args( $mixed_args ) { return array( $assoc_args, $runtime_config ); } + /** + * Load a YAML file of parameters into scope. + * + * @param string $path Path to YAML file. + */ public function merge_yml( $path ) { foreach ( self::load_yml( $path ) as $key => $value ) { if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { @@ -125,6 +149,11 @@ public function merge_yml( $path ) { } } + /** + * Merge an array of values into the configurator config. + * + * @param array $config + */ public function merge_array( $config ) { foreach ( $this->spec as $key => $details ) { if ( false !== $details['runtime'] && isset( $config[ $key ] ) ) { @@ -179,10 +208,16 @@ private static function arrayify( &$val ) { } } + /** + * Make a path absolute. + * + * @param string $path Path to file. + * @param string $base Base path to prepend. + */ private static function absolutize( &$path, $base ) { if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { $path = $base . DIRECTORY_SEPARATOR . $path; } } -} +} From 00cb543253538a661859706e7f02b77bc3a9f167 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 14:49:44 +0000 Subject: [PATCH 3062/5359] PHPdoc for `DocParser` --- php/WP_CLI/DocParser.php | 49 +++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 29e51e66a..0166fca49 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -2,14 +2,30 @@ namespace WP_CLI; +/** + * Parse command attributes from its PHPdoc. + * Used to determine execution characteristics (arguments, etc.). + */ class DocParser { + /** + * @param string $docComment PHPdoc command for the command. + */ protected $docComment; - function __construct( $docComment ) { + /** + * @param string $docComment + */ + public function __construct( $docComment ) { $this->docComment = self::remove_decorations( $docComment ); } + /** + * Remove unused cruft from PHPdoc comment. + * + * @param string $comment PHPdoc comment. + * @return string + */ private static function remove_decorations( $comment ) { $comment = preg_replace( '|^/\*\*[\r\n]+|', '', $comment ); $comment = preg_replace( '|\n[\t ]*\*/$|', '', $comment ); @@ -18,14 +34,24 @@ private static function remove_decorations( $comment ) { return $comment; } - function get_shortdesc() { + /** + * Get the command's short description (e.g. summary). + * + * @return string + */ + public function get_shortdesc() { if ( !preg_match( '|^([^@][^\n]+)\n*|', $this->docComment, $matches ) ) return ''; return $matches[1]; } - function get_longdesc() { + /** + * Get the command's full description + * + * @return string + */ + public function get_longdesc() { $shortdesc = $this->get_shortdesc(); if ( !$shortdesc ) return ''; @@ -44,14 +70,25 @@ function get_longdesc() { return $longdesc; } - function get_tag( $name ) { + /** + * Get the value for a given tag (e.g. "@alias" or "@subcommand") + * + * @param string $name Name for the tag, without '@' + * @return string + */ + public function get_tag( $name ) { if ( preg_match( '|^@' . $name . '\s+([a-z-_]+)|m', $this->docComment, $matches ) ) return $matches[1]; return ''; } - function get_synopsis() { + /** + * Get the command's synopsis. + * + * @return string + */ + public function get_synopsis() { if ( !preg_match( '|^@synopsis\s+(.+)|m', $this->docComment, $matches ) ) return ''; @@ -88,5 +125,5 @@ public function get_param_desc( $key ) { return ''; } -} +} From f51c3c1dbf1975f73e6c88dd2fcf9b25935705f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 14:51:48 +0000 Subject: [PATCH 3063/5359] Params are passed to methods --- php/WP_CLI/CommandWithDBObject.php | 6 +++--- php/WP_CLI/Configurator.php | 6 +++--- php/WP_CLI/DocParser.php | 2 +- php/WP_CLI/Fetchers/Base.php | 2 +- php/WP_CLI/Fetchers/Comment.php | 2 +- php/WP_CLI/Fetchers/Plugin.php | 2 +- php/WP_CLI/Fetchers/Post.php | 2 +- php/WP_CLI/Fetchers/Site.php | 2 +- php/WP_CLI/Fetchers/Theme.php | 2 +- php/WP_CLI/Fetchers/User.php | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index f7f99ff7f..90adb0933 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -10,17 +10,17 @@ abstract class CommandWithDBObject extends \WP_CLI_Command { /** - * @param string $object_type WordPress' expected name for the object. + * @var string $object_type WordPress' expected name for the object. */ protected $obj_type; /** - * @param string $obj_id_key Key representing object's PK field in db. + * @var string $obj_id_key Key representing object's PK field in db. */ protected $obj_id_key = 'ID'; /** - * @param array $obj_fields Default fields to display for each object. + * @var array $obj_fields Default fields to display for each object. */ protected $obj_fields = null; diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 533629a42..f8120926f 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -10,17 +10,17 @@ class Configurator { /** - * @param array $spec Configurator argument specification. + * @var array $spec Configurator argument specification. */ private $spec; /** - * @param array $config Values for keys defined in Configurator spec. + * @var array $config Values for keys defined in Configurator spec. */ private $config = array(); /** - * @param array $extra_config Extra config values not specified in spec. + * @var array $extra_config Extra config values not specified in spec. */ private $extra_config = array(); diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 0166fca49..06d57d328 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -9,7 +9,7 @@ class DocParser { /** - * @param string $docComment PHPdoc command for the command. + * @var string $docComment PHPdoc command for the command. */ protected $docComment; diff --git a/php/WP_CLI/Fetchers/Base.php b/php/WP_CLI/Fetchers/Base.php index 262e1bfab..639efe103 100644 --- a/php/WP_CLI/Fetchers/Base.php +++ b/php/WP_CLI/Fetchers/Base.php @@ -8,7 +8,7 @@ abstract class Base { /** - * @param string $msg The message to display when an item is not found + * @var string $msg The message to display when an item is not found */ protected $msg; diff --git a/php/WP_CLI/Fetchers/Comment.php b/php/WP_CLI/Fetchers/Comment.php index 027030452..0cf0f9a0c 100644 --- a/php/WP_CLI/Fetchers/Comment.php +++ b/php/WP_CLI/Fetchers/Comment.php @@ -8,7 +8,7 @@ class Comment extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "Could not find the comment with ID %d."; diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php index 36235a85a..5f29dfc31 100644 --- a/php/WP_CLI/Fetchers/Plugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -8,7 +8,7 @@ class Plugin extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "The '%s' plugin could not be found."; diff --git a/php/WP_CLI/Fetchers/Post.php b/php/WP_CLI/Fetchers/Post.php index 402a6f1f1..20b7d9855 100644 --- a/php/WP_CLI/Fetchers/Post.php +++ b/php/WP_CLI/Fetchers/Post.php @@ -8,7 +8,7 @@ class Post extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "Could not find the post with ID %d."; diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php index b3de87360..981e52b41 100644 --- a/php/WP_CLI/Fetchers/Site.php +++ b/php/WP_CLI/Fetchers/Site.php @@ -8,7 +8,7 @@ class Site extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "Could not find the site with ID %d."; diff --git a/php/WP_CLI/Fetchers/Theme.php b/php/WP_CLI/Fetchers/Theme.php index c3e3357e4..d72a7ad12 100644 --- a/php/WP_CLI/Fetchers/Theme.php +++ b/php/WP_CLI/Fetchers/Theme.php @@ -8,7 +8,7 @@ class Theme extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "The '%s' theme could not be found."; diff --git a/php/WP_CLI/Fetchers/User.php b/php/WP_CLI/Fetchers/User.php index 5b8e0a63a..e7fe2f93d 100644 --- a/php/WP_CLI/Fetchers/User.php +++ b/php/WP_CLI/Fetchers/User.php @@ -8,7 +8,7 @@ class User extends Base { /** - * @param string $msg Error message to use when invalid data is provided + * @var string $msg Error message to use when invalid data is provided */ protected $msg = "Invalid user ID, email or login: '%s'"; From 681c74b4298ff5e35c60af5c7bf66435189099d1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 15:00:01 +0000 Subject: [PATCH 3064/5359] PHPdoc for `Formatter` --- php/WP_CLI/Formatter.php | 54 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 5f188a747..7f70aa800 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -2,11 +2,26 @@ namespace WP_CLI; +/** + * Output one or more items in a given format (e.g. table, JSON). + */ class Formatter { + /** + * @var array $args How the items should be output. + */ private $args; + + /** + * @var string $prefix Standard prefix for object fields. + */ private $prefix; + /** + * @param array $assoc_args Output format arguments. + * @param array $fields Fields to display of each item. + * @param string $prefix Check if fields have a standard prefix. + */ public function __construct( &$assoc_args, $fields = null, $prefix = false ) { $format_args = array( 'format' => 'table', @@ -29,10 +44,21 @@ public function __construct( &$assoc_args, $fields = null, $prefix = false ) { $this->prefix = $prefix; } + /** + * Magic getter for arguments. + * + * @param string $key + * @return mixed + */ public function __get( $key ) { return $this->args[ $key ]; } + /** + * Display multiple items according to the output arguments. + * + * @param array $items + */ public function display_items( $items ) { if ( $this->args['field'] ) { $this->show_single_field( $items, $this->args['field'] ); @@ -50,6 +76,11 @@ public function display_items( $items ) { } } + /** + * Display a single item according to the output arguments. + * + * @param mixed $item + */ public function display_item( $item ) { if ( isset( $this->args['field'] ) ) { $item = (object) $item; @@ -60,6 +91,11 @@ public function display_item( $item ) { } } + /** + * Format items according to arguments. + * + * @param array $items + */ private function format( $items ) { $fields = $this->args['fields']; @@ -129,6 +165,14 @@ private function show_single_field( $items, $field ) { } } + /** + * Find an object's key. + * If $prefix is set, a key with that prefix will be prioritized. + * + * @param object $item + * @param string $field + * @return string $key + */ private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { if ( ( is_object( $item ) && isset( $item->$maybe_key ) ) || ( is_array( $item ) && isset( $item[$maybe_key] ) ) ) { @@ -170,6 +214,12 @@ private static function show_multiple_fields( $data, $format ) { } + /** + * Show items in a \cli\Table. + * + * @param array $items + * @param array $fields + */ private static function show_table( $items, $fields ) { $table = new \cli\Table(); @@ -183,7 +233,7 @@ private static function show_table( $items, $fields ) { } /** - * Format an associative array as a table + * Format an associative array as a table. * * @param array $fields Fields and values to format */ @@ -203,5 +253,5 @@ private static function assoc_array_to_table( $fields ) { self::show_table( $rows, array( 'Field', 'Value' ) ); } -} +} From eb9c3e6591560f3c07c83be4a0c8722748577dc8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 15:01:15 +0000 Subject: [PATCH 3065/5359] PHPdoc for `NoOp` --- php/WP_CLI/NoOp.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/NoOp.php b/php/WP_CLI/NoOp.php index 9334aff22..1aca5f9b3 100644 --- a/php/WP_CLI/NoOp.php +++ b/php/WP_CLI/NoOp.php @@ -2,6 +2,9 @@ namespace WP_CLI; +/** + * Escape route for not doing anything. + */ final class NoOp { function __set( $key, $value ) { From efb55b4138fb0d6e883e46993eaa00d541ce536d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 15:06:34 +0000 Subject: [PATCH 3066/5359] PHPdoc for `Process` and `ProcessRun` --- php/WP_CLI/Process.php | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 8245e4714..5be6a0d36 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -2,8 +2,16 @@ namespace WP_CLI; +/** + * Run a system process, and learn what happened. + */ class Process { + /** + * @param string $command Command to execute. + * @param string $cwd Directory to execute the command in. + * @param array $env Environment variables to set when running the command. + */ public static function create( $command, $cwd = null, $env = array() ) { $proc = new self; @@ -18,6 +26,11 @@ public static function create( $command, $cwd = null, $env = array() ) { private function __construct() {} + /** + * Run the command. + * + * @return ProcessRun + */ public function run() { $cwd = $this->cwd; @@ -45,6 +58,11 @@ public function run() { ) ); } + /** + * Run the command, but throw an Exception on error. + * + * @return ProcessRun + */ public function run_check() { $r = $this->run(); @@ -56,15 +74,25 @@ public function run_check() { } } - +/** + * Results of an executed command. + */ class ProcessRun { + /** + * @var array $props Properties of executed command. + */ public function __construct( $props ) { foreach ( $props as $key => $value ) { $this->$key = $value; } } + /** + * Return properties of executed command as a string. + * + * @return string + */ public function __toString() { $out = "$ $this->command\n"; $out .= "$this->stdout\n$this->stderr"; @@ -73,5 +101,5 @@ public function __toString() { return $out; } -} +} From 9970e7923a25d471c17a41ade228bdec167586e3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 11:14:58 -0400 Subject: [PATCH 3067/5359] PHPdoc for Synopsis parser --- php/WP_CLI/SynopsisParser.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 3d440a000..271af49ec 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -2,13 +2,16 @@ namespace WP_CLI; +/** + * Generate a synopsis from a command's PHPdoc arguments. + */ class SynopsisParser { /** * @param string A synopsis * @return array List of parameters */ - static function parse( $synopsis ) { + public static function parse( $synopsis ) { $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); $params = array(); @@ -29,6 +32,12 @@ static function parse( $synopsis ) { return $params; } + /** + * Classify argument attributes based on its syntax. + * + * @param string $token + * @return array $param + */ private static function classify_token( $token ) { $param = array(); @@ -70,6 +79,9 @@ private static function classify_token( $token ) { /** * An optional parameter is surrounded by square brackets. + * + * @param string $token + * @return array */ private static function is_optional( $token ) { if ( '[' == substr( $token, 0, 1 ) && ']' == substr( $token, -1 ) ) { @@ -81,6 +93,9 @@ private static function is_optional( $token ) { /** * A repeating parameter is followed by an ellipsis. + * + * @param string $token + * @return array */ private static function is_repeating( $token ) { if ( '...' === substr( $token, -3 ) ) { From ad8238fc7d886829728e8d033672a361c29bd477 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 11:16:34 -0400 Subject: [PATCH 3068/5359] Example for the `SynopsisParser` --- php/WP_CLI/SynopsisParser.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 271af49ec..43b89cc80 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -4,6 +4,8 @@ /** * Generate a synopsis from a command's PHPdoc arguments. + * Turns something like "<object-id>..." + * into [ optional=>false, type=>positional, repeating=>true, name=>object-id ] */ class SynopsisParser { From 609bb89b0c8924162ccd31c3c4df5db8766fe007 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 11:27:00 -0400 Subject: [PATCH 3069/5359] Docs for SynopsisValidator --- php/WP_CLI/SynopsisValidator.php | 39 ++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php index ea2f59394..f2dd2e5ff 100644 --- a/php/WP_CLI/SynopsisValidator.php +++ b/php/WP_CLI/SynopsisValidator.php @@ -7,18 +7,35 @@ */ class SynopsisValidator { + /** + * @var array $spec Structured representation of command synopsis. + */ private $spec = array(); + /** + * @param string $synopsis Command's synopsis. + */ public function __construct( $synopsis ) { $this->spec = SynopsisParser::parse( $synopsis ); } + /** + * Get any unknown arugments. + * + * @return array + */ public function get_unknown() { return array_column( $this->query_spec( array( 'type' => 'unknown', ) ), 'token' ); } + /** + * Check whether there are enough positional arguments. + * + * @param array $args Positional arguments. + * @return bool + */ public function enough_positionals( $args ) { $positional = $this->query_spec( array( 'type' => 'positional', @@ -28,12 +45,19 @@ public function enough_positionals( $args ) { return count( $args ) >= count( $positional ); } + /** + * Check for any unknown positionals. + * + * @param array $args Positional arguments. + * @return array + */ public function unknown_positionals( $args ) { $positional_repeating = $this->query_spec( array( 'type' => 'positional', 'repeating' => true, ) ); + // At least one positional supports as many as possible. if ( !empty( $positional_repeating ) ) return array(); @@ -45,7 +69,12 @@ public function unknown_positionals( $args ) { return array_slice( $args, count( $positional ) ); } - // Checks that all required keys are present and that they have values. + /** + * Check that all required keys are present and that they have values. + * + * @param array $assoc_args Parameters passed to command. + * @return array + */ public function validate_assoc( $assoc_args ) { $assoc_spec = $this->query_spec( array( 'type' => 'assoc', @@ -78,6 +107,12 @@ public function validate_assoc( $assoc_args ) { return array( $errors, $to_unset ); } + /** + * Check whether there are unknown parameters supplied. + * + * @param array $assoc_args Parameters passed to command. + * @return array|false + */ public function unknown_assoc( $assoc_args ) { $generic = $this->query_spec( array( 'type' => 'generic', @@ -124,5 +159,5 @@ private function query_spec( $args, $operator = 'AND' ) { return $filtered; } -} +} From 1ec65482c42072f41f9331cb499dc297878907f6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 20 Jul 2014 11:29:25 -0400 Subject: [PATCH 3070/5359] Couple changes to `WpHttpCacheManager` --- php/WP_CLI/WpHttpCacheManager.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/WpHttpCacheManager.php b/php/WP_CLI/WpHttpCacheManager.php index f9e9efff9..a9cad95db 100644 --- a/php/WP_CLI/WpHttpCacheManager.php +++ b/php/WP_CLI/WpHttpCacheManager.php @@ -16,6 +16,7 @@ class WpHttpCacheManager { * @var array map whitelisted urls to keys and ttls */ protected $whitelist = array(); + /** * @var FileCache */ @@ -32,7 +33,6 @@ public function __construct( FileCache $cache ) { add_filter( 'http_response', array($this, 'filter_http_response'), 10, 3 ); } - /** * short circuit wp http api with cached file */ @@ -65,6 +65,10 @@ public function filter_pre_http_request( $response, $args, $url ) { /** * cache wp http api downloads + * + * @param array $response + * @param array $args + * @param string $url */ public function filter_http_response( $response, $args, $url ) { // check if whitelisted @@ -121,4 +125,5 @@ public function whitelist_url( $url, $key = null, $ttl = null ) { public function is_whitelisted( $url ) { return isset( $this->whitelist[$url] ); } + } From fa1bcd8aa0b976ac74451bc77c6f20fce99974d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Mon, 21 Jul 2014 16:19:30 +0200 Subject: [PATCH 3071/5359] clarification Now I understand it also. --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 4a88d6de8..a3c064a9f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -218,7 +218,7 @@ private static function get_initial_locale() { * : Set the WPLANG constant. Defaults to $wp_local_package variable. * * [--extra-php] - * : If set, the command reads additional PHP code from STDIN. + * : If set, the command copies additional PHP code into wp-config.php from STDIN. * * [--skip-salts] * : If set, keys and salts won't be generated, but should instead be passed via `--extra-php`. From 23a1ea90324694e6b32f83c4cbd448657a9e06bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Mon, 21 Jul 2014 20:37:01 +0200 Subject: [PATCH 3072/5359] DOING_CRON left in --- php/commands/core.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index a3c064a9f..a32e886d5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -666,15 +666,13 @@ public function version( $args = array(), $assoc_args = array() ) { * @return bool|array False on failure. An array of checksums on success. */ private static function get_core_checksums( $version, $locale ) { - $return = array(); - $url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) $url = 'https' . substr( $url, 4 ); $options = array( - 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ) + 'timeout' => 30 ); $headers = array( @@ -683,7 +681,7 @@ private static function get_core_checksums( $version, $locale ) { $response = self::_request( 'GET', $url, $headers, $options ); if ( $ssl && ! $response->success ) { - trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); + trigger_error( __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); $response = self::_request( 'GET', $http_url, $headers, $options ); } From cafee1829c8be77bd8effbd7098e12548a1901ba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 22 Jul 2014 05:23:21 -0700 Subject: [PATCH 3073/5359] A test for #1288 --- features/core.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/core.feature b/features/core.feature index f7f1b8690..e168e5dad 100644 --- a/features/core.feature +++ b/features/core.feature @@ -153,6 +153,7 @@ Feature: Manage WordPress installation When I run `wp core is-installed` Then STDOUT should be empty + And the wp-content/uploads directory should exist When I run `wp eval 'var_export( is_admin() );'` Then STDOUT should be: From 604e5836c4df501af72f81966b53cab31c7a5693 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 22 Jul 2014 05:34:06 -0700 Subject: [PATCH 3074/5359] Create the uploads directory during the install process --- php/commands/core.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4a88d6de8..8f0cda1fc 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -494,6 +494,12 @@ private function _install( $assoc_args ) { } // @codingStandardsIgnoreEnd + // Confirm the uploads directory exists + $upload_dir = wp_upload_dir(); + if ( ! empty( $upload_dir['error'] ) ) { + WP_CLI::warning( $upload_dir['error'] ); + } + return true; } From 971696e79180664b82242d7d07ecf0e94d27f8e5 Mon Sep 17 00:00:00 2001 From: David Herrera <david@alleyinteractive.com> Date: Wed, 23 Jul 2014 00:56:20 -0400 Subject: [PATCH 3075/5359] Scaffold post type args in order of documentation --- templates/post_type.mustache | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 201a2fa13..4cf479eb6 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -1,12 +1,4 @@ register_post_type( '{{slug}}', array( - 'hierarchical' => false, - 'public' => true, - 'show_in_nav_menus' => true, - 'show_ui' => true, - 'supports' => array( 'title', 'editor' ), - 'has_archive' => true, - 'query_var' => true, - 'rewrite' => true, 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), @@ -22,4 +14,12 @@ 'parent_item_colon' => __( 'Parent {{label}}', '{{textdomain}}' ), 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), ), + 'public' => true, + 'hierarchical' => false, + 'show_ui' => true, + 'show_in_nav_menus' => true, + 'supports' => array( 'title', 'editor' ), + 'has_archive' => true, + 'rewrite' => true, + 'query_var' => true, ) ); From 0d510b84848e87aa7c4a6d8c40b4b3ee29e35ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Wed, 23 Jul 2014 16:42:17 +0200 Subject: [PATCH 3076/5359] WP_CLI::warning --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index a32e886d5..14de43ecf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -681,7 +681,7 @@ private static function get_core_checksums( $version, $locale ) { $response = self::_request( 'GET', $url, $headers, $options ); if ( $ssl && ! $response->success ) { - trigger_error( __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); + WP_CLI::warning( 'wp-cli could not establish a secure connection to WordPress.org. Please contact your server administrator.' ); $response = self::_request( 'GET', $http_url, $headers, $options ); } From b849d079aa81631241c2180d174ed9a02201e4d4 Mon Sep 17 00:00:00 2001 From: Tom Willmot <tom@humanmade.co.uk> Date: Fri, 25 Jul 2014 13:15:31 +0100 Subject: [PATCH 3077/5359] Remove extraneous space in wp_plugin_directory_constants `wp_plugin_directory_constants( )` should be `wp_plugin_directory_constants()` --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 67ad27f98..d189f412f 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -175,7 +175,7 @@ // Define constants that rely on the API to obtain the default value. // Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. -wp_plugin_directory_constants( ); +wp_plugin_directory_constants(); $symlinked_plugins_supported = function_exists( 'wp_register_plugin_realpath' ); if ( $symlinked_plugins_supported ) { From f9c4f7a99f5613d1db4a7b86e99d96dfdb5cbae0 Mon Sep 17 00:00:00 2001 From: Taylor Dewey <td@tddewey.com> Date: Sun, 27 Jul 2014 12:24:54 -0700 Subject: [PATCH 3078/5359] * Add new test for Search/Replace to ensure serializd data isn't mangled, * Remove length check for strings to determine if the MYSQL version could be used. Instead just use PHP. * Change some test verbiage for clarity. * Refactor 'fast' and 'safe' to 'mysql' and 'php' in method and variable names * Change the 'safe' flag to 'precise' to better explain its purpose. --- features/search-replace.feature | 50 +++++++++++++++++++++++---------- php/commands/search-replace.php | 29 +++++++++---------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 95027ecef..cd0dc39ff 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -20,9 +20,9 @@ Feature: Do global search/replace And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` And I run `wp search-replace foo bar --network` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Fast Replace | - | wp_2_posts | guid | 2 | Yes | - | wp_blogs | path | 1 | Yes | + | Table | Column | Replacements | Type | + | wp_2_posts | guid | 2 | SQL | + | wp_blogs | path | 1 | SQL | Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install @@ -32,8 +32,8 @@ Feature: Do global search/replace When I run `wp search-replace <flags> {SITEURL} <replacement>` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Fast Replace | - | wp_posts | guid | 22 | Yes | + | Table | Column | Replacements | Type | + | wp_posts | guid | 22 | SQL | Examples: | replacement | flags | @@ -41,20 +41,40 @@ Feature: Do global search/replace | http://newdomain.com | | | http://newdomain.com | --dry-run | - Scenario Outline: Fast and Safe search/replace due to string length and flags + Scenario Outline: Choose replacement method (PHP or MySQL) given proper flags or data. Given a WP install And I run `wp option get siteurl` And save STDOUT as {SITEURL} - And I run `wp search-replace {SITEURL} {SITEURL}/teststring` + When I run `wp search-replace <flags> {SITEURL} http://wordpress.org` - When I run `wp search-replace <flags> {SITEURL}/teststring <replacement>` Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Fast Replace | - | wp_options | option_value | 2 | <serial> | - | wp_posts | post_title | 0 | <noserial> | + | Table | Column | Replacements | Type | + | wp_options | option_value | 2 | <serial> | + | wp_posts | post_title | 0 | <noserial> | Examples: - | replacement | flags | serial | noserial | - | {SITEURL}/different | | No | Yes | - | {SITEURL}/samelength | --safe | No | No | - | {SITEURL}/samelength | | Yes | Yes | + | flags | serial | noserial | + | | PHP | SQL | + | --precise | PHP | PHP | + +Scenario Outline: Ensure search and replace uses PHP (precise) mode when serialized data is found + Given a WP install + And I run `wp post create --post_content='<input>' --porcelain` + And save STDOUT as {CONTROLPOST} + And I run `wp search-replace --precise foo bar` + And I run `wp post get {CONTROLPOST} --field=content` + And save STDOUT as {CONTROL} + And I run `wp post create --post_content='<input>' --porcelain` + And save STDOUT as {TESTPOST} + And I run `wp search-replace foo bar` + + When I run `wp post get {TESTPOST} --field=content` + Then STDOUT should be: + """ + {CONTROL} + """ + + Examples: + | input | + | a:1:{s:3:"bar";s:3:"foo";} | + | O:8:"stdClass":1:{s:1:"a";s:3:"foo";} | \ No newline at end of file diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c3a725e0c..410fda229 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -37,8 +37,8 @@ class Search_Replace_Command extends WP_CLI_Command { * [--dry-run] * : Show report, but don't perform the changes. * - * [--safe] - * : Use only serialization safe replacement method. + * [--precise] + * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. * * [--recurse-objects] * : Enable recursing into objects to replace strings @@ -56,7 +56,7 @@ public function __invoke( $args, $assoc_args ) { $total = 0; $report = array(); $dry_run = isset( $assoc_args['dry-run'] ); - $safe_only = isset( $assoc_args['safe'] ); + $php_only = isset( $assoc_args['precise'] ); $recurse_objects = isset( $assoc_args['recurse-objects'] ); if ( isset( $assoc_args['skip-columns'] ) ) @@ -79,34 +79,31 @@ public function __invoke( $args, $assoc_args ) { continue; } - // Can we do everything with a fast replace? - $fast_only = ( ! $safe_only && mb_strlen( $old ) === mb_strlen( $new ) ); - foreach ( $columns as $col ) { if ( in_array( $col, $skip_columns ) ) { continue; } - if ( ! $safe_only && ! $fast_only ) { + if ( ! $php_only ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $safe_only || ( ! $fast_only && NULL !== $serialRow ) ) { - $fast = 'No'; - $count = self::handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + if ( $php_only || NULL !== $serialRow ) { + $type = 'PHP'; + $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); } else { - $fast = 'Yes'; - $count = self::fast_handle_col( $col, $table, $old, $new, $dry_run ); + $type = 'SQL'; + $count = self::sql_handle_col( $col, $table, $old, $new, $dry_run ); } - $report[] = array( $table, $col, $count, $fast ); + $report[] = array( $table, $col, $count, $type ); $total += $count; } } $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Fast Replace' ) ); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); $table->setRows( $report ); $table->display(); @@ -125,7 +122,7 @@ private static function get_table_list( $args, $network ) { return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } - private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { + private static function sql_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { @@ -135,7 +132,7 @@ private static function fast_handle_col( $col, $table, $old, $new, $dry_run ) { } } - private static function handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { + private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite From c76bd7c61a302778de07e60123f39b1c4ff51cd9 Mon Sep 17 00:00:00 2001 From: Taylor Dewey <td@tddewey.com> Date: Sun, 27 Jul 2014 12:31:57 -0700 Subject: [PATCH 3079/5359] Add newline at EOF --- features/search-replace.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index cd0dc39ff..c01d64f89 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -77,4 +77,4 @@ Scenario Outline: Ensure search and replace uses PHP (precise) mode when seriali Examples: | input | | a:1:{s:3:"bar";s:3:"foo";} | - | O:8:"stdClass":1:{s:1:"a";s:3:"foo";} | \ No newline at end of file + | O:8:"stdClass":1:{s:1:"a";s:3:"foo";} | From 7b062d2edd4e0ca34fb55e61e5b47023c14b2b1e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 28 Jul 2014 07:39:16 -0700 Subject: [PATCH 3080/5359] Fix indent See #1261 --- features/search-replace.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index c01d64f89..86f67cbaa 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -57,7 +57,7 @@ Feature: Do global search/replace | | PHP | SQL | | --precise | PHP | PHP | -Scenario Outline: Ensure search and replace uses PHP (precise) mode when serialized data is found + Scenario Outline: Ensure search and replace uses PHP (precise) mode when serialized data is found Given a WP install And I run `wp post create --post_content='<input>' --porcelain` And save STDOUT as {CONTROLPOST} From 303a06a7cbebb47c8f9cf7d655eeaa140331cdb7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 30 Jul 2014 07:10:03 -0700 Subject: [PATCH 3081/5359] Support `--quiet` config arg for `wp search-replace` Previously #1230 --- features/search-replace.feature | 6 ++++++ php/commands/search-replace.php | 16 ++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 86f67cbaa..0b90f81ae 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -24,6 +24,12 @@ Feature: Do global search/replace | wp_2_posts | guid | 2 | SQL | | wp_blogs | path | 1 | SQL | + Scenario: Quiet search/replace + Given a WP install + + When I run `wp search-replace foo bar --quiet` + Then STDOUT should be empty + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 410fda229..c19d8ab5e 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -102,13 +102,17 @@ public function __invoke( $args, $assoc_args ) { } } - $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); - $table->setRows( $report ); - $table->display(); + if ( ! WP_CLI::get_config( 'quiet' ) ) { - if ( !$dry_run ) - WP_CLI::success( "Made $total replacements." ); + $table = new \cli\Table(); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); + $table->setRows( $report ); + $table->display(); + + if ( !$dry_run ) + WP_CLI::success( "Made $total replacements." ); + + } } private static function get_table_list( $args, $network ) { From 7e83172c7fe75133fed1e3fdfb5bd4f54a69f3bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 30 Jul 2014 09:40:46 -0700 Subject: [PATCH 3082/5359] Only perform search / replace on tables registered to `$wpdb` `$wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%'` is lossy, as it matches a separate WordPress install with similar prefix (e.g. `wp_` and `wp_en_`) --- php/commands/search-replace.php | 38 ++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c19d8ab5e..7406eca9d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -122,8 +122,44 @@ private static function get_table_list( $args, $network ) { return $args; $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; + $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); + + $allowed_tables = array(); + $allowed_table_types = array( 'tables', 'global_tables' ); + if ( $network ) { + $allowed_table_types[] = 'ms_global_tables'; + } + foreach( $allowed_table_types as $table_type ) { + foreach( $wpdb->$table_type as $table ) { + $allowed_tables[] = $prefix . $table; + } + } + + // Given our matching tables, also allow site-specific tables on the network + foreach( $matching_tables as $key => $matched_table ) { + + if ( in_array( $matched_table, $allowed_tables ) ) { + continue; + } + + if ( $network ) { + $valid_table = false; + foreach( array_merge( $wpdb->tables, $wpdb->old_tables ) as $maybe_site_table ) { + if ( preg_match( "#{$prefix}([\d]+)_{$maybe_site_table}#", $matched_table ) ) { + $valid_table = true; + } + } + if ( $valid_table ) { + continue; + } + } + + unset( $matching_tables[ $key ] ); + + } + + return array_values( $matching_tables ); - return $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); } private static function sql_handle_col( $col, $table, $old, $new, $dry_run ) { From 5ddad9b0906eb4725b41c117c4a9ec409ac8d6f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 30 Jul 2014 09:46:53 -0700 Subject: [PATCH 3083/5359] Explicit test to make sure we aren't clobbering unexpected tables --- features/search-replace.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 0b90f81ae..43207edbe 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -24,6 +24,16 @@ Feature: Do global search/replace | wp_2_posts | guid | 2 | SQL | | wp_blogs | path | 1 | SQL | + Scenario: Don't run on unregistered tables + Given a WP install + And I run `wp db query "CREATE TABLE wp_awesome ( id int(11) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` + + When I run `wp search-replace foo bar` + Then STDOUT should not contain: + """ + wp_awesome + """ + Scenario: Quiet search/replace Given a WP install From f001fb61a673e264525685610dfd64269b938c18 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 08:21:19 -0400 Subject: [PATCH 3084/5359] Make the scaffold command conditionally dependent on WP_Filesystem --- php/commands/scaffold.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b35ce22b3..14cb569a8 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -9,10 +9,6 @@ */ class Scaffold_Command extends WP_CLI_Command { - function __construct() { - WP_Filesystem(); - } - /** * Generate PHP code for registering a custom post type. * @@ -109,7 +105,7 @@ function taxonomy( $args, $assoc_args ) { } private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) { - global $wp_filesystem; + $wp_filesystem = $this->init_wp_filesystem(); $control_args = $this->extract_args( $assoc_args, array( 'label' => preg_replace( '/_|-/', ' ', strtolower( $slug ) ), @@ -379,7 +375,7 @@ function plugin( $args, $assoc_args ) { * @subcommand plugin-tests */ function plugin_tests( $args, $assoc_args ) { - global $wp_filesystem; + $wp_filesystem = $this->init_wp_filesystem(); $plugin_slug = $args[0]; @@ -413,7 +409,7 @@ function plugin_tests( $args, $assoc_args ) { } private function create_file( $filename, $contents ) { - global $wp_filesystem; + $wp_filesystem = $this->init_wp_filesystem(); $wp_filesystem->mkdir( dirname( $filename ) ); @@ -533,6 +529,15 @@ protected function maybe_create_plugins_dir() { } + /** + * Initialize WP Filesystem + */ + private function init_wp_filesystem() { + global $wp_filesystem; + WP_Filesystem(); + return $wp_filesystem; + } + } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); From e5253e5dda5c003fa27bba6754af33f1407c0d47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 08:21:59 -0400 Subject: [PATCH 3085/5359] Allow community packages to use WP-CLI testing framework First pass --- features/scaffold.feature | 33 +++++++++++++++++++ php/commands/scaffold.php | 61 +++++++++++++++++++++++++++++++++++ templates/load-wp-cli.feature | 10 ++++++ utils/make-phar.php | 1 + 4 files changed, 105 insertions(+) create mode 100644 templates/load-wp-cli.feature diff --git a/features/scaffold.feature b/features/scaffold.feature index 3ec35028b..2e4f538de 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -118,3 +118,36 @@ Feature: WordPress code scaffolding """ executable """ + + Scenario: Scaffold package tests + Given a community-command/command.php file: + """ + <?php + """ + + When I run `wp scaffold package-tests community-command` + Then STDOUT should not be empty + And the community-command/features directory should contain: + """ + bootstrap + extra + load-wp-cli.feature + steps + """ + And the community-command/features/bootstrap directory should contain: + """ + FeatureContext.php + Process.php + support.php + utils.php + """ + And the community-command/features/steps directory should contain: + """ + given.php + then.php + when.php + """ + And the community-command/features/extra directory should contain: + """ + no-mail.php + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 14cb569a8..d59e6e912 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -1,6 +1,7 @@ <?php use WP_CLI\Utils; +use WP_CLI\Process; /** * Generate code for post types, taxonomies, etc. @@ -300,6 +301,66 @@ private function get_output_path( $assoc_args, $subdir ) { return $path; } + /** + * Generate files needed for running PHPUnit tests. + * + * ## DESCRIPTION + * + * These are the files that are generated: + * + * * `.travis.yml` is the configuration file for Travis CI + * + * ## OPTIONS + * + * <dir> + * : The package directory to generate tests for + * + * ## EXAMPLE + * + * wp scaffold package-tests /path/to/command/dir/ + * + * @when before_wp_load + * @subcommand package-tests + */ + public function package_tests( $args, $assoc_args ) { + + list( $package_dir ) = $args; + + $package_dir = rtrim( $package_dir, '/' ) . '/'; + $features_dir = $package_dir . 'features/'; + $bootstrap_dir = $features_dir . 'bootstrap/'; + $steps_dir = $features_dir . 'steps/'; + $extra_dir = $features_dir . 'extra/'; + foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir ) as $dir ) { + if ( ! is_dir( $dir ) ) { + Process::create( Utils\esc_cmd( 'mkdir %s', $dir ) )->run(); + } + } + + $to_copy = array( + 'templates/load-wp-cli.feature' => $features_dir, + 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, + 'features/bootstrap/support.php' => $bootstrap_dir, + 'php/WP_CLI/Process.php' => $bootstrap_dir, + 'php/utils.php' => $bootstrap_dir, + 'features/steps/given.php' => $steps_dir, + 'features/steps/when.php' => $steps_dir, + 'features/steps/then.php' => $steps_dir, + 'features/extra/no-mail.php' => $extra_dir, + ); + + foreach ( $to_copy as $file => $dir ) { + // file_get_contents() works with Phar-archived files + $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); + $file_path = $dir . basename( $file ); + $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); + file_put_contents( $file_path, $contents ); + } + + WP_CLI::success( "Created test files." ); + + } + /** * Generate starter code for a plugin. * diff --git a/templates/load-wp-cli.feature b/templates/load-wp-cli.feature new file mode 100644 index 000000000..035b86730 --- /dev/null +++ b/templates/load-wp-cli.feature @@ -0,0 +1,10 @@ +Feature: Test that WP-CLI loads. + + Scenario: WP-CLI loads for your tests + Given a WP install + + When I run `wp eval 'echo "Hello world.";'` + Then STDOUT should contain: + """ + Hello world. + """ diff --git a/utils/make-phar.php b/utils/make-phar.php index bda5002a3..e75d5a93c 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -33,6 +33,7 @@ function add_file( $phar, $path ) { ->ignoreVCS(true) ->name('*.php') ->in('./php') + ->in('./features') ->in('./vendor/wp-cli') ->in('./vendor/mustache') ->in('./vendor/rmccue/requests') From caf41749c0a1c8dc4eb292f18b11bbf381b96a97 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 09:27:55 -0400 Subject: [PATCH 3086/5359] Handle community package context where these files are copied --- features/bootstrap/FeatureContext.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 803c3379f..dc14eda1c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -8,8 +8,15 @@ use \WP_CLI\Process; use \WP_CLI\Utils; -require_once __DIR__ . '/../../php/utils.php'; -require_once __DIR__ . '/../../php/WP_CLI/Process.php'; +// Inside a community package +if ( file_exists( __DIR__ . '/utils.php' ) ) { + require_once __DIR__ . '/utils.php'; + require_once __DIR__ . '/Process.php'; +// Inside WP-CLI +} else { + require_once __DIR__ . '/../../php/utils.php'; + require_once __DIR__ . '/../../php/WP_CLI/Process.php'; +} /** * Features context. From dfbf026966a76ac5a574622fb092f07f73df9235 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:04:48 -0400 Subject: [PATCH 3087/5359] Travis file for package tests --- features/scaffold.feature | 1 + php/commands/scaffold.php | 2 ++ templates/.travis.package.yml | 14 ++++++++++++++ 3 files changed, 17 insertions(+) create mode 100644 templates/.travis.package.yml diff --git a/features/scaffold.feature b/features/scaffold.feature index 2e4f538de..3d3423713 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -127,6 +127,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty + And the community-command/.travis.yml file should exist And the community-command/features directory should contain: """ bootstrap diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d59e6e912..f76ce5a0c 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -338,6 +338,7 @@ public function package_tests( $args, $assoc_args ) { } $to_copy = array( + 'templates/.travis.package.yml' => $package_dir, 'templates/load-wp-cli.feature' => $features_dir, 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, 'features/bootstrap/support.php' => $bootstrap_dir, @@ -353,6 +354,7 @@ public function package_tests( $args, $assoc_args ) { // file_get_contents() works with Phar-archived files $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); $file_path = $dir . basename( $file ); + $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml'), $file_path ); $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); file_put_contents( $file_path, $contents ); } diff --git a/templates/.travis.package.yml b/templates/.travis.package.yml new file mode 100644 index 000000000..09641d59d --- /dev/null +++ b/templates/.travis.package.yml @@ -0,0 +1,14 @@ +language: php + +php: + - 5.3 + - 5.5 + +env: + global: + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + +before_script: + - bash bin/install-package-tests.sh + +script: php behat.phar From 86cc38d4c3c74a511d1b95cd4616baae1cb92cd0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:25:18 -0400 Subject: [PATCH 3088/5359] Helper utility for building the test config --- features/scaffold.feature | 1 + php/commands/scaffold.php | 4 +++- utils/make-phar.php | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 3d3423713..e467e5ed7 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -128,6 +128,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty And the community-command/.travis.yml file should exist + And the community-command/utils/get-package-require-from-composer.php file should exist And the community-command/features directory should contain: """ bootstrap diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f76ce5a0c..bd68b0500 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -327,11 +327,12 @@ public function package_tests( $args, $assoc_args ) { list( $package_dir ) = $args; $package_dir = rtrim( $package_dir, '/' ) . '/'; + $utils_dir = $package_dir . 'utils/'; $features_dir = $package_dir . 'features/'; $bootstrap_dir = $features_dir . 'bootstrap/'; $steps_dir = $features_dir . 'steps/'; $extra_dir = $features_dir . 'extra/'; - foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir ) as $dir ) { + foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir ) as $dir ) { if ( ! is_dir( $dir ) ) { Process::create( Utils\esc_cmd( 'mkdir %s', $dir ) )->run(); } @@ -344,6 +345,7 @@ public function package_tests( $args, $assoc_args ) { 'features/bootstrap/support.php' => $bootstrap_dir, 'php/WP_CLI/Process.php' => $bootstrap_dir, 'php/utils.php' => $bootstrap_dir, + 'utils/get-package-require-from-composer.php' => $utils_dir, 'features/steps/given.php' => $steps_dir, 'features/steps/when.php' => $steps_dir, 'features/steps/then.php' => $steps_dir, diff --git a/utils/make-phar.php b/utils/make-phar.php index e75d5a93c..4558cfbfb 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -65,6 +65,7 @@ function add_file( $phar, $path ) { } add_file( $phar, './vendor/autoload.php' ); +add_file( $phar, './utils/get-package-require-from-composer.php' ); add_file( $phar, './vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); $phar->setStub( <<<EOB From 3cc14fa5998a638edf2c7feb105c824207eff1b0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:32:54 -0400 Subject: [PATCH 3089/5359] Commit the helper utility --- utils/get-package-require-from-composer.php | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 utils/get-package-require-from-composer.php diff --git a/utils/get-package-require-from-composer.php b/utils/get-package-require-from-composer.php new file mode 100644 index 000000000..33e30ccfd --- /dev/null +++ b/utils/get-package-require-from-composer.php @@ -0,0 +1,23 @@ +<?php + +$file = $argv[1]; +if ( ! file_exists( $file ) ) { + echo 'File does not exist.'; + exit(1); +} + +$contents = file_get_contents( $file ); +$composer = json_decode( $contents ); + +if ( empty( $composer ) || ! is_object( $composer ) ) { + echo 'Invalid composer.json for package.'; + exit(1); +} + +if ( empty( $composer->autoload->files ) ) { + echo 'composer.json must specify valid "autoload" => "files"'; + exit(1); +} + +echo implode( PHP_EOL, $composer->autoload->files ); +exit(0); \ No newline at end of file From cd1b17a669db0a4e6a79eddb8be24b5baf162df5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:42:42 -0400 Subject: [PATCH 3090/5359] Persist a supplied config path variable --- features/bootstrap/FeatureContext.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index dc14eda1c..ae06d8eaa 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -44,6 +44,9 @@ private static function get_process_env_variables() { 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), 'BEHAT_RUN' => 1 ); + if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { + $env['WP_CLI_CONFIG_PATH'] = $config_path; + } return $env; } From 09f85bb0b1894eb3a16628b8e4201aa6164b7f33 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:43:08 -0400 Subject: [PATCH 3091/5359] Bash script for installing package tests --- features/scaffold.feature | 1 + php/commands/scaffold.php | 2 ++ templates/.travis.package.yml | 3 +- templates/install-package-tests.sh | 46 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 templates/install-package-tests.sh diff --git a/features/scaffold.feature b/features/scaffold.feature index e467e5ed7..3379020c2 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -128,6 +128,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty And the community-command/.travis.yml file should exist + And the community-command/bin/install-package-tests.sh file should exist And the community-command/utils/get-package-require-from-composer.php file should exist And the community-command/features directory should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index bd68b0500..6a70e8b1e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -327,6 +327,7 @@ public function package_tests( $args, $assoc_args ) { list( $package_dir ) = $args; $package_dir = rtrim( $package_dir, '/' ) . '/'; + $bin_dir = $package_dir . 'bin/'; $utils_dir = $package_dir . 'utils/'; $features_dir = $package_dir . 'features/'; $bootstrap_dir = $features_dir . 'bootstrap/'; @@ -341,6 +342,7 @@ public function package_tests( $args, $assoc_args ) { $to_copy = array( 'templates/.travis.package.yml' => $package_dir, 'templates/load-wp-cli.feature' => $features_dir, + 'templates/install-package-tests.sh' => $bin_dir, 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, 'features/bootstrap/support.php' => $bootstrap_dir, 'php/WP_CLI/Process.php' => $bootstrap_dir, diff --git a/templates/.travis.package.yml b/templates/.travis.package.yml index 09641d59d..737aea122 100644 --- a/templates/.travis.package.yml +++ b/templates/.travis.package.yml @@ -7,8 +7,9 @@ php: env: global: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + - WP_CLI_CONFIG_PATH=/tmp/wp-cli-phar/config.yml before_script: - bash bin/install-package-tests.sh -script: php behat.phar +script: ./vendor/bin/behat diff --git a/templates/install-package-tests.sh b/templates/install-package-tests.sh new file mode 100644 index 000000000..74c76b587 --- /dev/null +++ b/templates/install-package-tests.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -ex + +PACKAGE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )" + +install_wp_cli() { + + # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR + mkdir -p $WP_CLI_BIN_DIR + wget https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar + mv wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp + chmod +x $WP_CLI_BIN_DIR/wp + +} + +set_package_context() { + + touch $WP_CLI_CONFIG_PATH + printf 'require:' > $WP_CLI_CONFIG_PATH + requires=$(php $PACKAGE_DIR/utils/get-package-require-from-composer.php composer.json) + for require in "${requires[@]}" + do + printf "\n%2s-%1s$PACKAGE_DIR/$require" >> $WP_CLI_CONFIG_PATH + done + printf "\n" >> $WP_CLI_CONFIG_PATH + +} + +download_behat() { + + cd $PACKAGE_DIR + curl -s https://getcomposer.org/installer | php + php composer.phar require --dev behat/behat='~2.5' + +} + +install_db() { + mysql -e 'CREATE DATABASE IF NOT EXISTS wp_cli_test;' -uroot + mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot +} + +install_wp_cli +set_package_context +download_behat +install_db From e2b3fd9e0897618b9612126b8a9e8c19f7759bea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 10:54:36 -0400 Subject: [PATCH 3092/5359] Make sure the bin directory is created --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 6a70e8b1e..198d7c788 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -333,7 +333,7 @@ public function package_tests( $args, $assoc_args ) { $bootstrap_dir = $features_dir . 'bootstrap/'; $steps_dir = $features_dir . 'steps/'; $extra_dir = $features_dir . 'extra/'; - foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir ) as $dir ) { + foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir, $bin_dir ) as $dir ) { if ( ! is_dir( $dir ) ) { Process::create( Utils\esc_cmd( 'mkdir %s', $dir ) )->run(); } From 054e3e22855e0a2b7f10fb3db313209335a3ef39 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 2 Aug 2014 11:16:44 -0400 Subject: [PATCH 3093/5359] Update the docs some --- php/commands/scaffold.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 198d7c788..675cd0b04 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -302,18 +302,28 @@ private function get_output_path( $assoc_args, $subdir ) { } /** - * Generate files needed for running PHPUnit tests. + * Generate files needed for writing Behat tests for your command. * * ## DESCRIPTION * * These are the files that are generated: * * * `.travis.yml` is the configuration file for Travis CI + * * `bin/install-package-tests.sh` will configure environment to run tests. Script expects WP_CLI_BIN_DIR and WP_CLI_CONFIG_PATH environment variables. + * * `features/load-wp-cli.feature` is a basic test to confirm WP-CLI can load. + * * `features/bootstrap`, `features/steps`, `features/extra` are Behat configuration files. + * * `utils/generate-package-require-from-composer.php` generates a test config.yml file from your package's composer.json + * + * ## ENVIRONMENT + * + * The `features/bootstrap/FeatureContext.php` file expects the WP_CLI_BIN_DIR and WP_CLI_CONFIG_PATH environment variables. + * + * WP-CLI Behat framework uses Behat ~2.5. * * ## OPTIONS * * <dir> - * : The package directory to generate tests for + * : The package directory to generate tests for. * * ## EXAMPLE * From fc0170b54d7cc5a46ce9570ebc9b3a6108510876 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Aug 2014 07:31:27 -0400 Subject: [PATCH 3094/5359] Ignore `config.yml`, which means developer has cloned into `~/.wp-cli` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8c20e7a9f..2f087dd74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ composer.lock +config.yml /vendor /*.phar /phpunit.xml From 3800713894ba241ae1d866934fa06cd7661d673f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Aug 2014 12:59:49 -0400 Subject: [PATCH 3095/5359] Test explicitly for composer.json file --- features/scaffold.feature | 27 +++++++++++++++++++++++++++ php/commands/scaffold.php | 12 +++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 3379020c2..c535c1809 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -124,6 +124,27 @@ Feature: WordPress code scaffolding """ <?php """ + And a community-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "require": { + }, + "autoload": { + "files": [ "dictator.php" ] + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + And a invalid-command/command.php file: + """ + <?php + """ When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty @@ -154,3 +175,9 @@ Feature: WordPress code scaffolding """ no-mail.php """ + + When I try `wp scaffold package-tests invalid-command` + Then STDERR should be: + """ + Error: Invalid package directory. composer.json file must be present. + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 675cd0b04..c61930cc3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -336,7 +336,17 @@ public function package_tests( $args, $assoc_args ) { list( $package_dir ) = $args; - $package_dir = rtrim( $package_dir, '/' ) . '/'; + if ( is_file( $package_dir ) ) { + $package_dir = dirname( $package_dir ); + } else if ( is_dir( $package_dir ) ) { + $package_dir = rtrim( $package_dir, '/' ); + } + + if ( ! is_dir( $package_dir ) || ! file_exists( $package_dir . '/composer.json' ) ) { + WP_CLI::error( "Invalid package directory. composer.json file must be present." ); + } + + $package_dir .= '/'; $bin_dir = $package_dir . 'bin/'; $utils_dir = $package_dir . 'utils/'; $features_dir = $package_dir . 'features/'; From b346493afc1266966ab26f98782e05311d05e18f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 3 Aug 2014 13:09:05 -0400 Subject: [PATCH 3096/5359] Ensure `install-package-tests.sh` ends up as executable --- features/scaffold.feature | 6 ++++++ php/commands/scaffold.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index c535c1809..a02d3d9f2 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -176,6 +176,12 @@ Feature: WordPress code scaffolding no-mail.php """ + When I run `wp eval "if ( is_executable( 'community-command/bin/install-package-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` + Then STDOUT should be: + """ + executable + """ + When I try `wp scaffold package-tests invalid-command` Then STDERR should be: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c61930cc3..3fd04361d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -381,6 +381,9 @@ public function package_tests( $args, $assoc_args ) { $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml'), $file_path ); $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); file_put_contents( $file_path, $contents ); + if ( 'templates/install-package-tests.sh' === $file ) { + Process::create( Utils\esc_cmd( 'chmod +x %s', $file_path ) )->run(); + } } WP_CLI::success( "Created test files." ); From 1e06f0f05597b594f07a722e58c3b327e83bb07b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 4 Aug 2014 11:16:37 -0400 Subject: [PATCH 3097/5359] Update importer to handle one or more directories Specify one or more directories when using `wp import`, and it will find and import `.xml` and `.wxr` files. --- features/import.feature | 43 +++++++++++++++++++++++++++++++++++++++++ php/commands/import.php | 13 ++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/features/import.feature b/features/import.feature index bbb869e68..b401e3164 100644 --- a/features/import.feature +++ b/features/import.feature @@ -36,3 +36,46 @@ Feature: Import content. When I run `wp import {EXPORT_FILE} --authors=skip --skip=image_resize` Then STDOUT should not be empty + + Scenario: Export and import a directory of files + Given a WP install + And I run `mkdir export-posts` + And I run `mkdir export-pages` + + When I run `wp post generate --count=49` + When I run `wp post generate --post_type=page --count=49` + And I run `wp post list --post_type=post,page --format=count` + Then STDOUT should be: + """ + 100 + """ + + When I run `wp export --dir=export-posts --post_type=post` + When I run `wp export --dir=export-pages --post_type=page` + Then STDOUT should not be empty + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post,page --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `find export-* -type f | wc -l` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp plugin install wordpress-importer --activate` + And I run `wp import export-posts --authors=skip --skip=image_resize` + And I run `wp import export-pages --authors=skip --skip=image_resize` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post,page --format=count` + Then STDOUT should be: + """ + 100 + """ diff --git a/php/commands/import.php b/php/commands/import.php index 36d2c46cf..a0fd39d54 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -8,7 +8,7 @@ class Import_Command extends WP_CLI_Command { * ## OPTIONS * * <file>... - * : Path to one or more valid WXR files for importing. + * : Path to one or more valid WXR files for importing. Directories are also accepted. * * --authors=<authors> * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The CSV requires two columns, and a header row like "old_user_login,new_user_login". The last option will skip any author mapping. @@ -36,6 +36,17 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::log( 'Starting the import process...' ); + $new_args = array(); + foreach( $args as $arg ) { + if ( is_dir( $arg ) ) { + $files = glob( rtrim( $arg, '/' ) . '/*.{wxr,xml}', GLOB_BRACE ); + $new_args = array_merge( $new_args, $files ); + } else { + $new_args[] = $arg; + } + } + $args = $new_args; + foreach ( $args as $file ) { if ( ! is_readable( $file ) ) { WP_CLI::warning( "Can't read $file file." ); From dd24ddea35e8307fe00220d73ccf3826c7f5864d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 4 Aug 2014 14:50:44 -0400 Subject: [PATCH 3098/5359] Failing test for #1296 --- features/db.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/db.feature b/features/db.feature index 92074c225..877d2edad 100644 --- a/features/db.feature +++ b/features/db.feature @@ -91,3 +91,19 @@ Feature: Perform database operations """ Success: Exported """ + + Scenario: Persist DB collation + Given a WP install + And I run `sed -i.bak s/define\(\'DB_COLLATE\'\,\s\'\'\)\;/define\(\'DB_COLLATE\'\,\s'utf8-hungarian-ci\'\)\;/ wp-config.php` + + When I run `wp db reset --yes` + Then STDOUT should not be empty + + When I run `wp core install --title="WP-CLI Test" --url=example.com --admin_user=admin --admin_password=admin --admin_email=admin@example.com` + Then STDOUT should not be empty + + When I run `wp db query 'SHOW variables LIKE "collation_database";'` + Then STDOUT should contain: + """ + utf8-hungarian-ci + """ From 3c739623433252b300654af4620a01589eb8ad74 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 4 Aug 2014 15:26:37 -0400 Subject: [PATCH 3099/5359] Persist `DB_COLLATE` value when creating database --- features/db.feature | 35 +++++++++++++++++++++++++++++++---- php/commands/db.php | 17 +++++++++++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/features/db.feature b/features/db.feature index 877d2edad..2fc9b71e5 100644 --- a/features/db.feature +++ b/features/db.feature @@ -92,9 +92,30 @@ Feature: Perform database operations Success: Exported """ - Scenario: Persist DB collation - Given a WP install - And I run `sed -i.bak s/define\(\'DB_COLLATE\'\,\s\'\'\)\;/define\(\'DB_COLLATE\'\,\s'utf8-hungarian-ci\'\)\;/ wp-config.php` + Scenario: Persist DB charset and collation + Given an empty directory + And WP files + + When I run `wp core config {CORE_CONFIG_SETTINGS} --dbcharset=latin1 --dbcollate=latin1_spanish_ci` + Then STDOUT should not be empty + + When I run `wp db create` + Then STDERR should be empty + + When I run `wp core install --title="WP-CLI Test" --url=example.com --admin_user=admin --admin_password=admin --admin_email=admin@example.com` + Then STDOUT should not be empty + + When I run `wp db query 'SHOW variables LIKE "character_set_database";'` + Then STDOUT should contain: + """ + latin1 + """ + + When I run `wp db query 'SHOW variables LIKE "collation_database";'` + Then STDOUT should contain: + """ + latin1_spanish_ci + """ When I run `wp db reset --yes` Then STDOUT should not be empty @@ -102,8 +123,14 @@ Feature: Perform database operations When I run `wp core install --title="WP-CLI Test" --url=example.com --admin_user=admin --admin_password=admin --admin_email=admin@example.com` Then STDOUT should not be empty + When I run `wp db query 'SHOW variables LIKE "character_set_database";'` + Then STDOUT should contain: + """ + latin1 + """ + When I run `wp db query 'SHOW variables LIKE "collation_database";'` Then STDOUT should contain: """ - utf8-hungarian-ci + latin1_spanish_ci """ diff --git a/php/commands/db.php b/php/commands/db.php index 32543d7a7..edaa20aa5 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -11,7 +11,8 @@ class DB_Command extends WP_CLI_Command { * Create the database, as specified in wp-config.php */ function create( $_, $assoc_args ) { - self::run_query( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); + + self::run_query( self::get_create_query() ); WP_CLI::success( "Database created." ); } @@ -44,7 +45,7 @@ function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); self::run_query( sprintf( 'DROP DATABASE IF EXISTS `%s`', DB_NAME ) ); - self::run_query( sprintf( 'CREATE DATABASE `%s`', DB_NAME ) ); + self::run_query( self::get_create_query() ); WP_CLI::success( "Database reset." ); } @@ -227,6 +228,18 @@ private function get_file_name( $args ) { return $args[0]; } + private static function get_create_query() { + + $create_query = sprintf( 'CREATE DATABASE `%s`', DB_NAME ); + if ( defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { + $create_query .= sprintf( ' DEFAULT CHARSET `%s`', constant( 'DB_CHARSET' ) ); + } + if ( defined( 'DB_COLLATE' ) && constant( 'DB_COLLATE' ) ) { + $create_query .= sprintf( ' DEFAULT COLLATE `%s`', constant( 'DB_COLLATE' ) ); + } + return $create_query; + } + private static function run_query( $query ) { self::run( 'mysql --no-defaults', array( 'execute' => $query ) ); } From d56c5841c20031e4512a752f75474fa86df1e92f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 4 Aug 2014 17:22:05 -0400 Subject: [PATCH 3100/5359] Switch php-cli-tools to dev-master We'll let WP-CLI users dogfood php-cli-tools during the release cycle. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index eddbf52a9..40ec7edf6 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.9.5", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From e4f7ef1dc413054b7709f71dc6c672452b431e17 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Wed, 6 Aug 2014 19:34:37 +0300 Subject: [PATCH 3101/5359] core update: add intermediate message to break the long silence --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 70a1053ea..85004dcb4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -836,6 +836,8 @@ function update( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); + $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); if ( is_wp_error($result) ) { From 9a3b764f19fd2f6a2c539de67d8750af1e9027fd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 7 Aug 2014 08:46:29 -0700 Subject: [PATCH 3102/5359] Broken test to establish #1318 --- features/export.feature | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/features/export.feature b/features/export.feature index 7ff5f118b..b7878a96b 100644 --- a/features/export.feature +++ b/features/export.feature @@ -84,6 +84,39 @@ Feature: Export content. 10 """ + Scenario: Export only one post + Given a WP install + And these installed and active plugins: + """ + wordpress-importer + """ + + When I run `wp post generate --count=10` + And I run `wp post list --format=count` + Then STDOUT should be: + """ + 11 + """ + + When I run `wp post create --post_title='Test post' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp export --post__in={POST_ID}` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 1 + """ + Scenario: Export posts within a given date range Given a WP install And these installed and active plugins: From 91d62fbcf411527797fd544014ae9c0fa41459b4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 7 Aug 2014 08:51:29 -0700 Subject: [PATCH 3103/5359] Pass `post__in` to new exporter in a format it understands --- php/commands/export.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 987dcdbc9..4569d6d08 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -197,7 +197,8 @@ private function check_post__in( $post__in ) { WP_CLI::warning( "post__in should be comma-separated post IDs" ); return false; } - $this->export_args['post__in'] = implode( ',', $post__in ); + // New exporter uses a different argument + $this->export_args['post_ids'] = $post__in; return true; } From 352fb6bbdb98deb3e7b0c2e77e0d5577150ca6da Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Thu, 7 Aug 2014 23:59:29 +0300 Subject: [PATCH 3104/5359] fix cases when update version isn't known --- features/core.feature | 5 ++--- php/commands/core.php | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index e168e5dad..a8998aecd 100644 --- a/features/core.feature +++ b/features/core.feature @@ -246,11 +246,10 @@ Feature: Manage WordPress installation """ When I run `wget http://wordpress.org/wordpress-3.9.zip --quiet` - Then STDOUT should be empty - - When I run `wp core update wordpress-3.9.zip` + And I run `wp core update wordpress-3.9.zip` Then STDOUT should be: """ + Starting update... Unpacking the update... Success: WordPress updated successfully. """ diff --git a/php/commands/core.php b/php/commands/core.php index 85004dcb4..8982223c0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -793,6 +793,7 @@ function update( $args, $assoc_args ) { 'full' => $args[0], ), 'version' => $version, + 'locale' => null ); } else if ( empty( $assoc_args['version'] ) ) { @@ -827,6 +828,7 @@ function update( $args, $assoc_args ) { 'full' => $new_package, ), 'version' => $version, + 'locale' => $locale ); } else { @@ -836,7 +838,11 @@ function update( $args, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); + if ( $update->version ) { + WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); + } else { + WP_CLI::log( "Starting update..." ); + } $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); From b3eb03c747b58a1e3a20df72b0a05b82fa5a4c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Fri, 8 Aug 2014 16:14:53 +0200 Subject: [PATCH 3105/5359] delete CA file --- php/commands/core.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 8982223c0..e3a2c31ab 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -146,10 +146,13 @@ private static function _request( $method, $url, $headers = array(), $options = } try { - return Requests::get( $url, $headers, $options ); + $request = Requests::get( $url, $headers, $options ); + unlink( $options['verify'] ); + return $request; } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully WP_CLI::warning( $ex->getMessage() ); + unlink( $options['verify'] ); $options['verify'] = false; try { return Requests::get( $url, $headers, $options ); From f09919a33c28249221f2b451225a88454230c9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sz=C3=A9pe=20Viktor?= <viktor@szepe.net> Date: Fri, 8 Aug 2014 16:25:51 +0200 Subject: [PATCH 3106/5359] only when CA file is copied could be `if ( ! empty( $options['verify'] ) ) {` --- php/commands/core.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index e3a2c31ab..1358f6a5c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -147,12 +147,16 @@ private static function _request( $method, $url, $headers = array(), $options = try { $request = Requests::get( $url, $headers, $options ); - unlink( $options['verify'] ); + if ( $options['verify'] ) { + unlink( $options['verify'] ); + } return $request; } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully WP_CLI::warning( $ex->getMessage() ); - unlink( $options['verify'] ); + if ( $options['verify'] ) { + unlink( $options['verify'] ); + } $options['verify'] = false; try { return Requests::get( $url, $headers, $options ); From 1e810f7b0fbe464c40210329539764f728361d02 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 10 Aug 2014 12:42:30 -0700 Subject: [PATCH 3107/5359] Ignore WP-CLI's cache directory when installed to `~/.wp-cli` Related fc0170b54d7cc5a46ce9570ebc9b3a6108510876 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2f087dd74..ee37a1d64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ composer.lock config.yml +/cache /vendor /*.phar /phpunit.xml From 0be771a370e8de8e1c1b02115d5c5664151d5d16 Mon Sep 17 00:00:00 2001 From: Noah Schoenholtz <noah@alleyinteractive.com> Date: Mon, 11 Aug 2014 16:02:47 -0400 Subject: [PATCH 3108/5359] esc_url before outputting GUID to WXR to avoid 'unterminated entity reference' error when GUID contains ampersand --- php/export/class-wp-export-wxr-formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index c169029fe..5a99543a7 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -166,7 +166,7 @@ public function post( $post ) { ->link( esc_url( apply_filters('the_permalink_rss', get_permalink() ) ) ) ->pubDate( mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ) ) ->tag( 'dc:creator', get_the_author_meta( 'login' ) ) - ->guid( get_the_guid(), array( 'isPermaLink' => 'false' ) ) + ->guid( esc_url( get_the_guid() ), array( 'isPermaLink' => 'false' ) ) ->description( '' ) ->tag( 'content:encoded' )->contains->cdata( $post->post_content )->end ->tag( 'excerpt:encoded' )->contains->cdata( $post->post_excerpt )->end From 67b98de33e3d036893b2f5886eba4390467de485 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 13 Aug 2014 16:58:12 -0700 Subject: [PATCH 3109/5359] Update `wp term list` to support multiple taxonomies Fortunately, `get_terms()` does the heavy lifting behind the scenes. --- features/term.feature | 9 +++++++++ php/commands/term.php | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/features/term.feature b/features/term.feature index ebfae3b2f..90b2a0b07 100644 --- a/features/term.feature +++ b/features/term.feature @@ -28,6 +28,15 @@ Feature: Manage WordPress terms | name | slug | | Test term | test | + When I run `wp term create category 'Test category' --slug=test-category --description='This is a test category'` + Then STDOUT should not be empty + + When I run `wp term list post_tag category --fields=name,slug --format=csv` + Then STDOUT should be CSV containing: + | name | slug | + | Test term | test | + | Test category | test-category | + When I run `wp term get post_tag {TERM_ID}` Then STDOUT should be a table containing rows: | Field | Value | diff --git a/php/commands/term.php b/php/commands/term.php index 55569a4e4..a073ff601 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -21,8 +21,8 @@ class Term_Command extends WP_CLI_Command { * * ## OPTIONS * - * <taxonomy> - * : List terms of a given taxonomy. + * <taxonomy>... + * : List terms of one or more taxonomies * * [--<field>=<value>] * : Filter by one or more fields. For accepted fields, see get_terms(). From 0bffc3cb0ef2b16b72da25c2b48cf0a20db61180 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 14 Aug 2014 11:38:17 -0700 Subject: [PATCH 3110/5359] Clarify `--url` global config argument For new users working with multisite, let's be explicit. --- php/config-spec.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/config-spec.php b/php/config-spec.php index 519a6880c..37f98fbf5 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -10,7 +10,7 @@ 'url' => array( 'runtime' => '=<url>', 'file' => '<url>', - 'desc' => 'Pretend request came from given URL', + 'desc' => 'Pretend request came from given URL. In multisite, this argument is how the target site is specified.', ), 'blog' => array( 'deprecated' => 'Use --url instead.', From c0f62830ce95a1a4727a8b3952ba7d0c2316bca3 Mon Sep 17 00:00:00 2001 From: Matth_eu <matthew@matth.eu> Date: Fri, 15 Aug 2014 17:02:13 +0100 Subject: [PATCH 3111/5359] Fix term delete example --- php/commands/term.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index a073ff601..503fb9dac 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -217,7 +217,7 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * # delete all post tags - * wp term list post_tag --field=ID | xargs wp term delete post_tag + * wp term list post_tag --field=term_id | xargs wp term delete post_tag */ public function delete( $args ) { $taxonomy = array_shift( $args ); @@ -327,7 +327,7 @@ public function generate( $args, $assoc_args ) { * Get term url * * ## OPTIONS - * + * * <taxonomy> * : Taxonomy of the term(s) to get. * From e32fce99655cb70d4a94d817a1efaab22b7394f7 Mon Sep 17 00:00:00 2001 From: Pippin Williamson <pippin@pippinsplugins.com> Date: Sun, 17 Aug 2014 17:22:12 -0500 Subject: [PATCH 3112/5359] Better error message for update() Improves the error message for update() when the existing value is the same as the new one, as suggested in #1254 --- php/commands/option.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index ded55ce2b..7b9bc80af 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -108,7 +108,7 @@ public function update( $args, $assoc_args ) { // update_option() returns false if the value is the same if ( !$result && $value != get_option( $key ) ) { - WP_CLI::error( "Could not update option '$key'." ); + WP_CLI::error( "Option '$key' value is already set to '$value'." ); } else { WP_CLI::success( "Updated '$key' option." ); } From e427c8ee0c7ff8e265b9fdc560ff099e2bb9c40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 18 Aug 2014 22:00:30 +0200 Subject: [PATCH 3113/5359] Update core.php --- php/commands/core.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1358f6a5c..c9c084a4e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -135,6 +135,8 @@ private static function _rmdir( $dir ) { } private static function _request( $method, $url, $headers = array(), $options = array() ) { + $pem_copied = false; + // cURL can't read Phar archives if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; @@ -143,18 +145,19 @@ private static function _request( $method, $url, $headers = array(), $options = WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem', $options['verify'] ); + $pem_copied = true; } try { $request = Requests::get( $url, $headers, $options ); - if ( $options['verify'] ) { + if ( $pem_copied ) { unlink( $options['verify'] ); } return $request; } catch( Requests_Exception $ex ) { // Handle SSL certificate issues gracefully WP_CLI::warning( $ex->getMessage() ); - if ( $options['verify'] ) { + if ( $pem_copied ) { unlink( $options['verify'] ); } $options['verify'] = false; From 913d706f70082a9ea339028e60c00a2bdd210ea7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 19 Aug 2014 08:47:34 -0700 Subject: [PATCH 3114/5359] Explicit support for importing remote CSVs It worked before, but threw a warning that the file was missing. --- php/commands/user.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index b93cf1c4b..5f84ca4f2 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -550,7 +550,7 @@ public function list_caps( $args, $assoc_args ) { * ## OPTIONS * * <file> - * : The CSV file of users to import. + * : The local or remote CSV file of users to import. * * [--send-email] * : Send an email to new users with their account details. @@ -561,6 +561,7 @@ public function list_caps( $args, $assoc_args ) { * ## EXAMPLES * * wp user import-csv /path/to/users.csv + * wp user import-csv http://example.com/users.csv * * Sample users.csv file: * @@ -577,7 +578,13 @@ public function import_csv( $args, $assoc_args ) { $filename = $args[0]; - if ( ! file_exists( $filename ) ) { + if ( 0 === stripos( $filename, 'http://' ) || 0 === stripos( $filename, 'https://' ) ) { + $response = wp_remote_head( $filename ); + $response_code = (string)wp_remote_retrieve_response_code( $response ); + if ( in_array( $response_code[0], array( 4, 5 ) ) ) { + WP_CLI::error( "Couldn't access remote CSV file." ); + } + } else if ( ! file_exists( $filename ) ) { WP_CLI::warning( sprintf( "Missing file: %s", $filename ) ); } From a7a329ba6be52d3dc2cce015418b67d2c46a2616 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 19 Aug 2014 08:49:54 -0700 Subject: [PATCH 3115/5359] Throw an explicit warning when the file doesn't exist The iterator will eventually error anyway. Let's do this before we get to that. --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 5f84ca4f2..919b8c25d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -585,7 +585,7 @@ public function import_csv( $args, $assoc_args ) { WP_CLI::error( "Couldn't access remote CSV file." ); } } else if ( ! file_exists( $filename ) ) { - WP_CLI::warning( sprintf( "Missing file: %s", $filename ) ); + WP_CLI::error( sprintf( "Missing file: %s", $filename ) ); } foreach ( new \WP_CLI\Iterators\CSV( $filename ) as $i => $new_user ) { From 9e91d1a4c7284a21cf068edb1887abef5a83629e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 19 Aug 2014 08:51:25 -0700 Subject: [PATCH 3116/5359] Make this error more explicit by including response code --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 919b8c25d..a46378d18 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -582,7 +582,7 @@ public function import_csv( $args, $assoc_args ) { $response = wp_remote_head( $filename ); $response_code = (string)wp_remote_retrieve_response_code( $response ); if ( in_array( $response_code[0], array( 4, 5 ) ) ) { - WP_CLI::error( "Couldn't access remote CSV file." ); + WP_CLI::error( "Couldn't access remote CSV file (HTTP {$response_code} response)." ); } } else if ( ! file_exists( $filename ) ) { WP_CLI::error( sprintf( "Missing file: %s", $filename ) ); From 8d43e20744af1a1e7d5ceb682f708b851029c9d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 19 Aug 2014 08:55:35 -0700 Subject: [PATCH 3117/5359] Add tests for error case --- features/user.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/user.feature b/features/user.feature index 2809ac97c..3f99421c6 100644 --- a/features/user.feature +++ b/features/user.feature @@ -130,6 +130,12 @@ Feature: Manage WordPress users admin,admin@domain.com,Existing User,administrator """ + When I try `wp user import-csv users-incorrect.csv --skip-update` + Then STDERR should be: + """ + Error: Missing file: users-incorrect.csv + """ + When I run `wp user import-csv users.csv` Then STDOUT should not be empty From 50809e4d577277a108fa5c2492580da9cb2c0293 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 19 Aug 2014 08:57:34 -0700 Subject: [PATCH 3118/5359] Test case for remote csv error --- features/user.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/user.feature b/features/user.feature index 3f99421c6..ddbea8ab7 100644 --- a/features/user.feature +++ b/features/user.feature @@ -136,6 +136,12 @@ Feature: Manage WordPress users Error: Missing file: users-incorrect.csv """ + When I try `wp user import-csv http://example.com/users.csv --skip-update` + Then STDERR should be: + """ + Error: Couldn't access remote CSV file (HTTP 404 response). + """ + When I run `wp user import-csv users.csv` Then STDOUT should not be empty From f76be9c4de8bf49c94cd7a0339a59aa2925aa070 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 07:35:52 -0700 Subject: [PATCH 3119/5359] Allow themes and plugins to be listed with `update_version` When there's no `update_version` available, the attribute is `null` on the plugin info array. `isset()` returns false for null values, but `array_key_exists()` and `property_exists()` do the job --- features/plugin.feature | 10 +++++++--- php/WP_CLI/Formatter.php | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 13ffd7b51..0d582808f 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -92,10 +92,14 @@ Feature: Manage WordPress plugins When I run `wp plugin install akismet --version=2.5.7 --force` Then STDOUT should not be empty - When I run `wp plugin list` + When I run `wp plugin list --name=akismet --field=update_version` + Then STDOUT should not be empty + And save STDOUT as {UPDATE_VERSION} + + When I run `wp plugin list --fields=name,status,update,version,update_version` Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | inactive | available | 2.5.7 | + | name | status | update | version | update_version | + | akismet | inactive | available | 2.5.7 | {UPDATE_VERSION} | When I run `wp plugin activate akismet` Then STDOUT should not be empty diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 7f70aa800..cd9717a7d 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -175,7 +175,7 @@ private function show_single_field( $items, $field ) { */ private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( ( is_object( $item ) && isset( $item->$maybe_key ) ) || ( is_array( $item ) && isset( $item[$maybe_key] ) ) ) { + if ( ( is_object( $item ) && property_exists( $item, $maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { $key = $maybe_key; break; } From e703e18251edb1f1c681780598844ed0650a282a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 07:49:06 -0700 Subject: [PATCH 3120/5359] Check if `Spyc` exists before including it Other projects may have included it via Composer, and this will prevent a fatal --- php/Spyc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/Spyc.php b/php/Spyc.php index b6a42af67..13b4c3415 100644 --- a/php/Spyc.php +++ b/php/Spyc.php @@ -32,6 +32,7 @@ function spyc_load_file ($file) { } } +if ( ! class_exists( 'Spyc' ) ) : /** * The Simple PHP YAML Class. * @@ -1031,3 +1032,4 @@ private function stripGroup ($line, $group) { } } +endif; From 20c4aa696c0e7d314d2922c19edfa39bf5fd802d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 07:50:27 -0700 Subject: [PATCH 3121/5359] Make it clearer where the `function_exists()` check ends --- php/Spyc.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/Spyc.php b/php/Spyc.php index 13b4c3415..4227b3ed9 100644 --- a/php/Spyc.php +++ b/php/Spyc.php @@ -10,7 +10,7 @@ * @package Spyc */ -if (!function_exists('spyc_load')) { +if (!function_exists('spyc_load')) : /** * Parses YAML to array. * @param string $string YAML string. @@ -19,9 +19,9 @@ function spyc_load ($string) { return Spyc::YAMLLoadString($string); } -} +endif; -if (!function_exists('spyc_load_file')) { +if (!function_exists('spyc_load_file')) : /** * Parses YAML to array. * @param string $file Path to YAML file. @@ -30,7 +30,7 @@ function spyc_load ($string) { function spyc_load_file ($file) { return Spyc::YAMLLoad($file); } -} +endif; if ( ! class_exists( 'Spyc' ) ) : /** From b9cef4020c279e6c9e8e313a9336aee1a44ab695 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 08:14:52 -0700 Subject: [PATCH 3122/5359] More clearly specify which fields are available on a cron event --- php/commands/cron.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index db4e07dd2..ebe9f95f9 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -20,11 +20,27 @@ class Cron_Event_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Available fields: hook, next_run, next_run_gmt, next_run_relative, recurrence. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each cron event: + * * hook + * * next_run_gmt + * * next_run_relative + * * recurrence + * + * These fields are optionally available: + * * time + * * sig + * * args + * * schedule + * * interval + * * next_run + * * ## EXAMPLES * * wp cron event list From 537c60a96e03b6c47489cc330f772955064aad09 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 08:18:18 -0700 Subject: [PATCH 3123/5359] Prevent error notices when these variables aren't set --- php/commands/cron.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index ebe9f95f9..640925fa1 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -58,6 +58,13 @@ public function list_( $args, $assoc_args ) { $events = array(); } + if ( in_array( $formatter->format, array( 'table', 'csv' ) ) ) { + $events = array_map( function( $event ){ + $event->args = json_encode( $event->args ); + return $event; + }, $events ); + } + if ( 'ids' == $formatter->format ) { echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); } else { @@ -93,9 +100,11 @@ public function list_( $args, $assoc_args ) { */ public function schedule( $args, $assoc_args ) { - list( $hook, $next_run, $recurrence ) = $args; + $hook = $args[0]; + $next_run = ( isset( $args[1] ) ) ? $args[1] : false; + $recurrence = ( isset( $args[2] ) ) ? $args[2] : false; - if ( !isset( $next_run ) ) { + if ( ! empty( $next_run ) ) { $timestamp = time(); } else if ( is_numeric( $next_run ) ) { $timestamp = absint( $next_run ); @@ -107,7 +116,7 @@ public function schedule( $args, $assoc_args ) { WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $next_run ) ); } - if ( isset( $recurrence ) ) { + if ( ! empty( $recurrence ) ) { $schedules = wp_get_schedules(); From dd17b1930e8dfdf67916a3c172ad7ff320911dd7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 08:23:18 -0700 Subject: [PATCH 3124/5359] Tests for 537c60a96e03b6c47489cc330f772955064aad09 --- features/cron.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index a25404172..e8596301e 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -4,16 +4,16 @@ Feature: Manage WP-Cron events and schedules Given a WP install Scenario: Scheduling and then deleting an event - When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour'` + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour' --apple=banana` Then STDOUT should contain: """ Success: Scheduled event with hook 'wp_cli_test_event_1' """ - When I run `wp cron event list --format=csv --fields=hook,recurrence` + When I run `wp cron event list --format=csv --fields=hook,recurrence,args` Then STDOUT should be CSV containing: - | hook | recurrence | - | wp_cli_test_event_1 | Non-repeating | + | hook | recurrence | args | + | wp_cli_test_event_1 | Non-repeating | {"apple":"banana"} | When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: From 3004b1b0c1454e7d4fe885626ca5191b42ab00c4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 08:57:47 -0700 Subject: [PATCH 3125/5359] If there is more than one instance of an event, perform action on all instances Previously, the `break;` meant only the first instance would be affected. --- features/cron.feature | 61 +++++++++++++++++++++++++++++++++++++++++-- php/commands/cron.php | 28 +++++++++++++------- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index e8596301e..dbce7c356 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -18,7 +18,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: """ - Success: Successfully deleted the cron event 'wp_cli_test_event_1' + Success: Deleted 1 instances of the cron event 'wp_cli_test_event_1' """ When I run `wp cron event list` @@ -48,6 +48,63 @@ Feature: Manage WP-Cron events and schedules wp_cli_test_event_3 """ + Scenario: Scheduling, running, and deleting duplicate events + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --apple=banana` + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --foo=bar` + Then STDOUT should not be empty + + When I run `wp cron event list --format=csv --fields=hook,recurrence,args` + Then STDOUT should be CSV containing: + | hook | recurrence | args | + | wp_cli_test_event_5 | Non-repeating | {"apple":"banana"} | + | wp_cli_test_event_5 | Non-repeating | {"foo":"bar"} | + + When I run `wp cron event run wp_cli_test_event_5` + Then STDOUT should be: + """ + Success: Executed 2 instances of the cron event 'wp_cli_test_event_5' + """ + + When I run `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_5 + """ + + When I try `wp cron event run wp_cli_test_event_5` + Then STDERR should be: + """ + Error: Invalid cron event 'wp_cli_test_event_5' + """ + + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --apple=banana` + When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --foo=bar` + Then STDOUT should not be empty + + When I run `wp cron event list` + Then STDOUT should contain: + """ + wp_cli_test_event_5 + """ + + When I run `wp cron event delete wp_cli_test_event_5` + Then STDOUT should be: + """ + Success: Deleted 2 instances of the cron event 'wp_cli_test_event_5' + """ + + When I run `wp cron event list` + Then STDOUT should not contain: + """ + wp_cli_test_event_5 + """ + + When I try `wp cron event delete wp_cli_test_event_5` + Then STDERR should be: + """ + Error: Invalid cron event 'wp_cli_test_event_5' + """ + Scenario: Scheduling and then running a re-occurring event When I run `wp cron event schedule wp_cli_test_event_4 now hourly` Then STDOUT should contain: @@ -84,7 +141,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event delete wp_cli_test_event_2` Then STDOUT should contain: """ - Success: Successfully deleted the cron event 'wp_cli_test_event_2' + Success: Deleted 1 instances of the cron event 'wp_cli_test_event_2' """ When I run `wp cron event list` diff --git a/php/commands/cron.php b/php/commands/cron.php index 640925fa1..9e73d145d 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -151,24 +151,28 @@ public function schedule( $args, $assoc_args ) { public function run( $args, $assoc_args ) { $hook = $args[0]; - $result = false; $events = self::get_cron_events(); if ( is_wp_error( $events ) ) { WP_CLI::error( $events ); } + $executed = 0; foreach ( $events as $id => $event ) { if ( $event->hook == $hook ) { $result = self::run_event( $event ); - break; + if ( $result ) { + $executed++; + } else { + WP_CLI::warning( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); + } } } - if ( $result ) { - WP_CLI::success( sprintf( "Successfully executed the cron event '%s'", $hook ) ); + if ( $executed ) { + WP_CLI::success( sprintf( "Executed %d instances of the cron event '%s'", $executed, $hook ) ); } else { - WP_CLI::error( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); + WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); } } @@ -209,24 +213,28 @@ protected static function run_event( stdClass $event ) { public function delete( $args, $assoc_args ) { $hook = $args[0]; - $result = false; $events = self::get_cron_events(); if ( is_wp_error( $events ) ) { WP_CLI::error( $events ); } + $deleted = 0; foreach ( $events as $id => $event ) { if ( $event->hook == $hook ) { $result = self::delete_event( $event ); - break; + if ( $result ) { + $deleted++; + } else { + WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'", $hook ) ); + } } } - if ( $result ) { - WP_CLI::success( sprintf( "Successfully deleted the cron event '%s'", $hook ) ); + if ( $deleted ) { + WP_CLI::success( sprintf( "Deleted %d instances of the cron event '%s'", $deleted, $hook ) ); } else { - WP_CLI::error( sprintf( "Failed to the delete the cron event '%s'", $hook ) ); + WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); } } From 2e57b4eed6d1f946e051690bd45029fc99f08348 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 10:55:40 -0700 Subject: [PATCH 3126/5359] Abstract `_request()` to a common utility so we can use inside a filter --- php/commands/core.php | 43 ++++--------------------------------------- php/utils.php | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index c9c084a4e..8a6fa747c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -75,7 +75,7 @@ public function download( $args, $assoc_args ) { 'filename' => $temp ); - self::_request( 'GET', $download_url, $headers, $options ); + Utils\get_request( $download_url, $headers, $options ); self::_extract( $temp, ABSPATH ); $cache->import( $cache_key, $temp ); unlink($temp); @@ -134,44 +134,9 @@ private static function _rmdir( $dir ) { rmdir( $dir ); } - private static function _request( $method, $url, $headers = array(), $options = array() ) { - $pem_copied = false; - - // cURL can't read Phar archives - if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { - $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; - - copy( - WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem', - $options['verify'] - ); - $pem_copied = true; - } - - try { - $request = Requests::get( $url, $headers, $options ); - if ( $pem_copied ) { - unlink( $options['verify'] ); - } - return $request; - } catch( Requests_Exception $ex ) { - // Handle SSL certificate issues gracefully - WP_CLI::warning( $ex->getMessage() ); - if ( $pem_copied ) { - unlink( $options['verify'] ); - } - $options['verify'] = false; - try { - return Requests::get( $url, $headers, $options ); - } catch( Requests_Exception $ex ) { - WP_CLI::error( $ex->getMessage() ); - } - } - } - private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - return self::_request( 'GET', $url, $headers )->body; + return Utils\get_request( $url, $headers )->body; } private function get_download_offer( $locale ) { @@ -694,11 +659,11 @@ private static function get_core_checksums( $version, $locale ) { $headers = array( 'Accept' => 'application/json' ); - $response = self::_request( 'GET', $url, $headers, $options ); + $response = Utils\get_request( $url, $headers, $options ); if ( $ssl && ! $response->success ) { WP_CLI::warning( 'wp-cli could not establish a secure connection to WordPress.org. Please contact your server administrator.' ); - $response = self::_request( 'GET', $http_url, $headers, $options ); + $response = Utils\get_request( $http_url, $headers, $options ); } if ( ! $response->success || 200 != $response->status_code ) diff --git a/php/utils.php b/php/utils.php index e033be5bb..60362ad7b 100644 --- a/php/utils.php +++ b/php/utils.php @@ -401,3 +401,45 @@ function replace_path_consts( $source, $path ) { return str_replace( $old, $new, $source ); } + +/** + * Download a remote URL + * + * @param string $url + * @param array $headers + * @param array $options + */ +function get_request( $url, $headers = array(), $options = array() ) { + $pem_copied = false; + + // cURL can't read Phar archives + if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { + $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; + + copy( + WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem', + $options['verify'] + ); + $pem_copied = true; + } + + try { + $request = \Requests::get( $url, $headers, $options ); + if ( $pem_copied ) { + unlink( $options['verify'] ); + } + return $request; + } catch( \Requests_Exception $ex ) { + // Handle SSL certificate issues gracefully + \WP_CLI::warning( $ex->getMessage() ); + if ( $pem_copied ) { + unlink( $options['verify'] ); + } + $options['verify'] = false; + try { + return \Requests::get( $url, $headers, $options ); + } catch( \Requests_Exception $ex ) { + \WP_CLI::error( $ex->getMessage() ); + } + } +} From 7e4d2f685608b33fa6210b0c3e20b8b082272635 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 11:01:21 -0700 Subject: [PATCH 3127/5359] `wp core update` should use cached files too --- features/core.feature | 20 ++++++++++++++++++++ php/commands/core.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/features/core.feature b/features/core.feature index a8998aecd..4191bdb6f 100644 --- a/features/core.feature +++ b/features/core.feature @@ -299,6 +299,26 @@ Feature: Manage WordPress installation Error: WordPress install doesn't verify against checksums. """ + Scenario: Core update from cache + Given a WP install + And an empty cache + + When I run `wp core update --version=3.8.1 --force` + Then STDOUT should not contain: + """ + Using cached file + """ + + When I run `wp core update --version=3.9 --force` + Then STDOUT should not be empty + + When I run `wp core update --version=3.8.1 --force` + Then STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/core/en_US-3.8.1.tar.gz'... + """ + + Scenario: User defined in wp-cli.yml Given an empty directory And WP files diff --git a/php/commands/core.php b/php/commands/core.php index 8a6fa747c..c8483cdb1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -819,7 +819,38 @@ function update( $args, $assoc_args ) { WP_CLI::log( "Starting update..." ); } + $defer_cached_file = function( $reply, $package, $upgrader ) use ( $update ) { + + if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists( $package ) ) //Local file or remote? + return $reply; //must be a local file.. + + $cache = WP_CLI::get_cache(); + $cache_key = "core/{$update->locale}-{$update->version}.tar.gz"; + $cache_file = $cache->has( $cache_key ); + + if ( $cache_file ) { + WP_CLI::log( "Using cached file '$cache_file'..." ); + return $cache_file; + } else { + // We need to use a temporary file because piping from cURL to tar is flaky + // on MinGW (and probably in other environments too). + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + + $headers = array('Accept' => 'application/json'); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); + + Utils\get_request( $package, $headers, $options ); + $cache->import( $cache_key, $temp ); + unlink($temp); + return $cache->has( $cache_key ); + } + }; + add_filter( 'upgrader_pre_download', $defer_cached_file, 10, 3 ); $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); + remove_filter( 'upgrader_pre_download', $defer_cached_file ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); From 5fbcb26b8b1cca7aa29a1ac8b163b80aa9d96b2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 11:43:11 -0700 Subject: [PATCH 3128/5359] Copy cache to a temp file, so upgrader can later delete it --- php/commands/core.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index c8483cdb1..cd411989b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -824,13 +824,16 @@ function update( $args, $assoc_args ) { if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists( $package ) ) //Local file or remote? return $reply; //must be a local file.. + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + $cache = WP_CLI::get_cache(); $cache_key = "core/{$update->locale}-{$update->version}.tar.gz"; $cache_file = $cache->has( $cache_key ); if ( $cache_file ) { WP_CLI::log( "Using cached file '$cache_file'..." ); - return $cache_file; + copy( $cache_file, $temp ); + return $temp; } else { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). @@ -844,8 +847,7 @@ function update( $args, $assoc_args ) { Utils\get_request( $package, $headers, $options ); $cache->import( $cache_key, $temp ); - unlink($temp); - return $cache->has( $cache_key ); + return $temp; } }; add_filter( 'upgrader_pre_download', $defer_cached_file, 10, 3 ); From 8359b62380c99bbc8aa9bd20a8178b45f070bf2e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 12:36:43 -0700 Subject: [PATCH 3129/5359] Subclass, because the filter we want to use isn't available until 3.7.1 --- php/WP_CLI/CoreUpgrader.php | 67 +++++++++++++++++++++++ php/WP_CLI/NonDestructiveCoreUpgrader.php | 2 +- php/commands/core.php | 37 +------------ 3 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 php/WP_CLI/CoreUpgrader.php diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php new file mode 100644 index 000000000..37cc7f0d4 --- /dev/null +++ b/php/WP_CLI/CoreUpgrader.php @@ -0,0 +1,67 @@ +<?php + +namespace WP_CLI; + +use WP_CLI; + +/** + * A Core Upgrader class that caches the download, and uses cached if available + * + * @package wp-cli + */ +class CoreUpgrader extends \Core_Upgrader { + + function download_package( $package ) { + + /** + * Filter whether to return the package. + * + * @since 3.7.0 + * + * @param bool $reply Whether to bail without returning the package. Default is false. + * @param string $package The package file name. + * @param object $this The WP_Upgrader instance. + */ + $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); + if ( false !== $reply ) + return $reply; + + if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote? + return $package; //must be a local file.. + + if ( empty( $package ) ) + return new WP_Error( 'no_package', $this->strings['no_package'] ); + + $this->skin->feedback( 'downloading_package', $package ); + + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + + $cache = WP_CLI::get_cache(); + $update = $GLOBALS['wp_cli_update_obj']; + $cache_key = "core/{$update->locale}-{$update->version}.tar.gz"; + $cache_file = $cache->has( $cache_key ); + + if ( $cache_file ) { + WP_CLI::log( "Using cached file '$cache_file'..." ); + copy( $cache_file, $temp ); + return $temp; + } else { + // We need to use a temporary file because piping from cURL to tar is flaky + // on MinGW (and probably in other environments too). + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + + $headers = array('Accept' => 'application/json'); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); + + Utils\get_request( $package, $headers, $options ); + $cache->import( $cache_key, $temp ); + return $temp; + } + + } + +} + diff --git a/php/WP_CLI/NonDestructiveCoreUpgrader.php b/php/WP_CLI/NonDestructiveCoreUpgrader.php index 41ba05949..ebad21cbd 100644 --- a/php/WP_CLI/NonDestructiveCoreUpgrader.php +++ b/php/WP_CLI/NonDestructiveCoreUpgrader.php @@ -7,7 +7,7 @@ * * @package wp-cli */ -class NonDestructiveCoreUpgrader extends \Core_Upgrader { +class NonDestructiveCoreUpgrader extends CoreUpgrader { function unpack_package($package, $delete_package = false) { return parent::unpack_package( $package, $delete_package ); } diff --git a/php/commands/core.php b/php/commands/core.php index cd411989b..f95e396e9 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -750,7 +750,7 @@ function update( $args, $assoc_args ) { global $wp_version; $update = $from_api = null; - $upgrader = 'Core_Upgrader'; + $upgrader = 'WP_CLI\\CoreUpgrader'; if ( ! empty( $args[0] ) ) { @@ -819,40 +819,9 @@ function update( $args, $assoc_args ) { WP_CLI::log( "Starting update..." ); } - $defer_cached_file = function( $reply, $package, $upgrader ) use ( $update ) { - - if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists( $package ) ) //Local file or remote? - return $reply; //must be a local file.. - - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; - - $cache = WP_CLI::get_cache(); - $cache_key = "core/{$update->locale}-{$update->version}.tar.gz"; - $cache_file = $cache->has( $cache_key ); - - if ( $cache_file ) { - WP_CLI::log( "Using cached file '$cache_file'..." ); - copy( $cache_file, $temp ); - return $temp; - } else { - // We need to use a temporary file because piping from cURL to tar is flaky - // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; - - $headers = array('Accept' => 'application/json'); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody - 'filename' => $temp - ); - - Utils\get_request( $package, $headers, $options ); - $cache->import( $cache_key, $temp ); - return $temp; - } - }; - add_filter( 'upgrader_pre_download', $defer_cached_file, 10, 3 ); + $GLOBALS['wp_cli_update_obj'] = $update; $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); - remove_filter( 'upgrader_pre_download', $defer_cached_file ); + unset( $GLOBALS['wp_cli_update_obj'] ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); From 8ec0370bdee7ca01db980ada68a397d3de055e34 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 12:40:36 -0700 Subject: [PATCH 3130/5359] Only indicate "Downloading" when we're actually downloading something --- features/core.feature | 8 ++++++++ php/WP_CLI/CoreUpgrader.php | 4 ++-- php/commands/core.php | 2 -- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index 4191bdb6f..9be8d2686 100644 --- a/features/core.feature +++ b/features/core.feature @@ -308,6 +308,10 @@ Feature: Manage WordPress installation """ Using cached file """ + And STDOUT should contain: + """ + Downloading + """ When I run `wp core update --version=3.9 --force` Then STDOUT should not be empty @@ -317,6 +321,10 @@ Feature: Manage WordPress installation """ Using cached file '{SUITE_CACHE_DIR}/core/en_US-3.8.1.tar.gz'... """ + And STDOUT should not contain: + """ + Downloading + """ Scenario: User defined in wp-cli.yml diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 37cc7f0d4..f30dfbdbb 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -32,8 +32,6 @@ function download_package( $package ) { if ( empty( $package ) ) return new WP_Error( 'no_package', $this->strings['no_package'] ); - $this->skin->feedback( 'downloading_package', $package ); - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; $cache = WP_CLI::get_cache(); @@ -56,6 +54,8 @@ function download_package( $package ) { 'filename' => $temp ); + $this->skin->feedback( 'downloading_package', $package ); + Utils\get_request( $package, $headers, $options ); $cache->import( $cache_key, $temp ); return $temp; diff --git a/php/commands/core.php b/php/commands/core.php index f95e396e9..fed6a8cc6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -790,8 +790,6 @@ function update( $args, $assoc_args ) { $new_package = $this->get_download_url($version, $locale); - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $assoc_args['version'], $locale ) ); - $update = (object) array( 'response' => 'upgrade', 'current' => $assoc_args['version'], From 3811d39e217b333b0dcf86428368f7a1cc02e6ef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 12:44:46 -0700 Subject: [PATCH 3131/5359] Make this method generally more useful --- php/WP_CLI/CoreUpgrader.php | 2 +- php/commands/core.php | 8 ++++---- php/utils.php | 10 +++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index f30dfbdbb..931fd4bba 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -56,7 +56,7 @@ function download_package( $package ) { $this->skin->feedback( 'downloading_package', $package ); - Utils\get_request( $package, $headers, $options ); + Utils\http_request( 'GET', $package, $headers, $options ); $cache->import( $cache_key, $temp ); return $temp; } diff --git a/php/commands/core.php b/php/commands/core.php index fed6a8cc6..d88f3e6a0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -75,7 +75,7 @@ public function download( $args, $assoc_args ) { 'filename' => $temp ); - Utils\get_request( $download_url, $headers, $options ); + Utils\http_request( 'GET', $download_url, $headers, $options ); self::_extract( $temp, ABSPATH ); $cache->import( $cache_key, $temp ); unlink($temp); @@ -136,7 +136,7 @@ private static function _rmdir( $dir ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - return Utils\get_request( $url, $headers )->body; + return Utils\http_request( 'GET', $url, $headers )->body; } private function get_download_offer( $locale ) { @@ -659,11 +659,11 @@ private static function get_core_checksums( $version, $locale ) { $headers = array( 'Accept' => 'application/json' ); - $response = Utils\get_request( $url, $headers, $options ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); if ( $ssl && ! $response->success ) { WP_CLI::warning( 'wp-cli could not establish a secure connection to WordPress.org. Please contact your server administrator.' ); - $response = Utils\get_request( $http_url, $headers, $options ); + $response = Utils\http_request( 'GET', $http_url, $headers, $options ); } if ( ! $response->success || 200 != $response->status_code ) diff --git a/php/utils.php b/php/utils.php index 60362ad7b..3b34f5360 100644 --- a/php/utils.php +++ b/php/utils.php @@ -403,13 +403,15 @@ function replace_path_consts( $source, $path ) { } /** - * Download a remote URL + * Make a HTTP request to a remote URL * + * @param string $method * @param string $url * @param array $headers * @param array $options + * @return object */ -function get_request( $url, $headers = array(), $options = array() ) { +function http_request( $method, $url, $headers = array(), $options = array() ) { $pem_copied = false; // cURL can't read Phar archives @@ -423,8 +425,10 @@ function get_request( $url, $headers = array(), $options = array() ) { $pem_copied = true; } + $method = strtolower( $method ); + try { - $request = \Requests::get( $url, $headers, $options ); + $request = \Requests::$method( $url, $headers, $options ); if ( $pem_copied ) { unlink( $options['verify'] ); } From b438af1924057350a7ab93b690b74c90ac0fc22e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 12:47:42 -0700 Subject: [PATCH 3132/5359] Validate methods --- php/utils.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 3b34f5360..96d641939 100644 --- a/php/utils.php +++ b/php/utils.php @@ -414,6 +414,13 @@ function replace_path_consts( $source, $path ) { function http_request( $method, $url, $headers = array(), $options = array() ) { $pem_copied = false; + $method = strtolower( $method ); + + if ( ! in_array( $method, array( 'get', 'post', 'put', 'delete', 'head', 'patch' ) ) ) { + $method = strtoupper( $method ); + WP_CLI::error( "Invalid method: {$method}" ); + } + // cURL can't read Phar archives if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; @@ -425,8 +432,6 @@ function http_request( $method, $url, $headers = array(), $options = array() ) { $pem_copied = true; } - $method = strtolower( $method ); - try { $request = \Requests::$method( $url, $headers, $options ); if ( $pem_copied ) { From 494cc3e82c754496ac8fec1098839337dcceab72 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 15:15:19 -0700 Subject: [PATCH 3133/5359] Allow `\Requests` to validate method on its own --- php/utils.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/php/utils.php b/php/utils.php index 96d641939..e9baef00e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -414,13 +414,6 @@ function replace_path_consts( $source, $path ) { function http_request( $method, $url, $headers = array(), $options = array() ) { $pem_copied = false; - $method = strtolower( $method ); - - if ( ! in_array( $method, array( 'get', 'post', 'put', 'delete', 'head', 'patch' ) ) ) { - $method = strtoupper( $method ); - WP_CLI::error( "Invalid method: {$method}" ); - } - // cURL can't read Phar archives if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; @@ -433,7 +426,7 @@ function http_request( $method, $url, $headers = array(), $options = array() ) { } try { - $request = \Requests::$method( $url, $headers, $options ); + $request = \Requests::request( $url, null, $method, $headers, $options ); if ( $pem_copied ) { unlink( $options['verify'] ); } @@ -446,7 +439,7 @@ function http_request( $method, $url, $headers = array(), $options = array() ) { } $options['verify'] = false; try { - return \Requests::get( $url, $headers, $options ); + return \Requests::request( $url, null, $method, $headers, $options ); } catch( \Requests_Exception $ex ) { \WP_CLI::error( $ex->getMessage() ); } From ec52a45ca1255dcafe46cfb0b30fc5a441a661fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 21 Aug 2014 15:44:24 -0700 Subject: [PATCH 3134/5359] Pass args in expected order, and allow `$data` as an option too --- php/WP_CLI/CoreUpgrader.php | 2 +- php/commands/core.php | 8 ++++---- php/utils.php | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 931fd4bba..d3d3692e4 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -56,7 +56,7 @@ function download_package( $package ) { $this->skin->feedback( 'downloading_package', $package ); - Utils\http_request( 'GET', $package, $headers, $options ); + Utils\http_request( 'GET', $package, null, $headers, $options ); $cache->import( $cache_key, $temp ); return $temp; } diff --git a/php/commands/core.php b/php/commands/core.php index d88f3e6a0..9466a3e6f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -75,7 +75,7 @@ public function download( $args, $assoc_args ) { 'filename' => $temp ); - Utils\http_request( 'GET', $download_url, $headers, $options ); + Utils\http_request( 'GET', $download_url, null, $headers, $options ); self::_extract( $temp, ABSPATH ); $cache->import( $cache_key, $temp ); unlink($temp); @@ -136,7 +136,7 @@ private static function _rmdir( $dir ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - return Utils\http_request( 'GET', $url, $headers )->body; + return Utils\http_request( 'GET', $url, null, $headers )->body; } private function get_download_offer( $locale ) { @@ -659,11 +659,11 @@ private static function get_core_checksums( $version, $locale ) { $headers = array( 'Accept' => 'application/json' ); - $response = Utils\http_request( 'GET', $url, $headers, $options ); + $response = Utils\http_request( 'GET', $url, null, $headers, $options ); if ( $ssl && ! $response->success ) { WP_CLI::warning( 'wp-cli could not establish a secure connection to WordPress.org. Please contact your server administrator.' ); - $response = Utils\http_request( 'GET', $http_url, $headers, $options ); + $response = Utils\http_request( 'GET', $http_url, null, $headers, $options ); } if ( ! $response->success || 200 != $response->status_code ) diff --git a/php/utils.php b/php/utils.php index e9baef00e..fbee550ac 100644 --- a/php/utils.php +++ b/php/utils.php @@ -411,7 +411,7 @@ function replace_path_consts( $source, $path ) { * @param array $options * @return object */ -function http_request( $method, $url, $headers = array(), $options = array() ) { +function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { $pem_copied = false; // cURL can't read Phar archives @@ -426,7 +426,7 @@ function http_request( $method, $url, $headers = array(), $options = array() ) { } try { - $request = \Requests::request( $url, null, $method, $headers, $options ); + $request = \Requests::request( $url, $headers, $data, $method, $options ); if ( $pem_copied ) { unlink( $options['verify'] ); } @@ -439,7 +439,7 @@ function http_request( $method, $url, $headers = array(), $options = array() ) { } $options['verify'] = false; try { - return \Requests::request( $url, null, $method, $headers, $options ); + return \Requests::request( $url, $headers, $data, $method, $options ); } catch( \Requests_Exception $ex ) { \WP_CLI::error( $ex->getMessage() ); } From f8f6d71fac046d396b593e230506b82a619cefab Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 25 Aug 2014 21:01:02 +0100 Subject: [PATCH 3135/5359] Correct the grammar when executing or deleting cron events where there is only one instance. --- features/cron.feature | 4 ++-- php/commands/cron.php | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index dbce7c356..0f638f6f6 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -18,7 +18,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: """ - Success: Deleted 1 instances of the cron event 'wp_cli_test_event_1' + Success: Deleted the cron event 'wp_cli_test_event_1' """ When I run `wp cron event list` @@ -141,7 +141,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event delete wp_cli_test_event_2` Then STDOUT should contain: """ - Success: Deleted 1 instances of the cron event 'wp_cli_test_event_2' + Success: Deleted the cron event 'wp_cli_test_event_2' """ When I run `wp cron event list` diff --git a/php/commands/cron.php b/php/commands/cron.php index 9e73d145d..4bdf4904c 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -170,7 +170,8 @@ public function run( $args, $assoc_args ) { } if ( $executed ) { - WP_CLI::success( sprintf( "Executed %d instances of the cron event '%s'", $executed, $hook ) ); + $message = ( 1 == $executed ) ? "Executed the cron event '%2\$s'" : "Executed %1\$d instances of the cron event '%2\$s'"; + WP_CLI::success( sprintf( $message, $executed, $hook ) ); } else { WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); } @@ -232,7 +233,8 @@ public function delete( $args, $assoc_args ) { } if ( $deleted ) { - WP_CLI::success( sprintf( "Deleted %d instances of the cron event '%s'", $deleted, $hook ) ); + $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'" : "Deleted %1\$d instances of the cron event '%2\$s'"; + WP_CLI::success( sprintf( $message, $deleted, $hook ) ); } else { WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); } From 680a08771dc6112e3ebffd411b12dec8333c6477 Mon Sep 17 00:00:00 2001 From: Joshua Eichorn <joshua.eichorn@pagely.com> Date: Wed, 27 Aug 2014 19:18:19 +0000 Subject: [PATCH 3136/5359] Fix WP_CLI::colorize warnings Passing an array to colorize causes warnings since the passed in value ends up being passed into md5 Warning was PHP Warning: md5() expects parameter 1 to be string, array given in git/wp-cli/vendor/wp-cli/php-cli-tools/lib/cli/Colors.php on line 118 --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 1bbe9ae56..0ce9d34e9 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -104,7 +104,7 @@ private function show_legend( $items ) { if ( in_array( true, wp_list_pluck( $items, 'update' ) ) ) $legend_line[] = '%yU = Update Available%n'; - \WP_CLI::line( 'Legend: ' . implode( ', ', \WP_CLI::colorize( $legend_line ) ) ); + \WP_CLI::line( 'Legend: ' . \WP_CLI::colorize( implode( ', ', $legend_line ) ) ); } function install( $args, $assoc_args ) { From 6398db537750b233a810c689eb8c2e5fa63f8b10 Mon Sep 17 00:00:00 2001 From: Joshua Eichorn <joshua.eichorn@pagely.com> Date: Wed, 27 Aug 2014 20:54:34 +0000 Subject: [PATCH 3137/5359] Add a summary table to the output of plugin update Example: Enabling Maintenance mode... Downloading update from https://downloads.wordpress.org/plugin/akismet.3.0.2.zip... Using cached file '/home/jeichorn/.wp-cli/cache/plugin/akismet-3.0.2.zip'... Unpacking the update... Installing the latest version... Removing the old version of the plugin... Plugin updated successfully. Disabling Maintenance mode... Success: Updated 1/1 plugins. +---------+-------------+-------------+---------+ | name | old_version | new_version | status | +---------+-------------+-------------+---------+ | akismet | 3.0.0 | 3.0.2 | Updated | +---------+-------------+-------------+---------+ --- php/WP_CLI/CommandWithUpgrade.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 1bbe9ae56..01b146f05 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -252,6 +252,20 @@ protected function update_many( $args, $assoc_args ) { } else { \WP_CLI::error( $line ); } + + if ($num_to_update > 0) { + $status = array(); + foreach($items_to_update as $item_to_update => $info) { + $status[$item_to_update] = array( + 'name' => $info['name'], + 'old_version' => $info['version'], + 'new_version' => $info['update_version'], + 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', + ); + } + \WP_CLI\Utils\format_items( 'table', $status, + array( 'name', 'old_version', 'new_version', 'status' ) ); + } } protected function _list( $_, $assoc_args ) { From b76388b2be29b535c1f1724c2cc9aafbb5f18f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 28 Aug 2014 21:47:55 +0200 Subject: [PATCH 3138/5359] param-dump dumps current values --- php/commands/cli.php | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index bfc3a91a3..8964f6f02 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -70,12 +70,34 @@ function info( $_, $assoc_args ) { } /** - * Dump the list of global parameters, as JSON. + * Dump the list of global parameters, as JSON or by var_export. + * + * ## OPTIONS + * + * [--format=<format>] + * : Accepted values: var_export * * @subcommand param-dump */ - function param_dump() { - echo json_encode( \WP_CLI::get_configurator()->get_spec() ); + function param_dump( $_, $assoc_args ) { + $spec = \WP_CLI::get_configurator()->get_spec(); + $config = \WP_CLI::get_configurator()->to_array(); + + // copy current config values to $spec + foreach ( $spec as $key => $value ) { + if ( isset( $config[0][$key] ) ) { + $current = $config[0][$key]; + } else { + $current = NULL; + } + $spec[$key]['current'] = $current; + } + + if ( isset( $assoc_args['format'] ) && 'var_export' === $assoc_args['format'] ) { + var_export( $spec ); + } else { + echo json_encode( $spec ); + } } /** From 363fe0ef06709f9837bc856adf6007b53dbc62ff Mon Sep 17 00:00:00 2001 From: Joshua Eichorn <joshua.eichorn@pagely.com> Date: Thu, 28 Aug 2014 21:16:49 +0000 Subject: [PATCH 3139/5359] Convert spaces to hard tabs --- php/WP_CLI/CommandWithUpgrade.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 01b146f05..cc8936139 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -253,19 +253,19 @@ protected function update_many( $args, $assoc_args ) { \WP_CLI::error( $line ); } - if ($num_to_update > 0) { - $status = array(); - foreach($items_to_update as $item_to_update => $info) { - $status[$item_to_update] = array( - 'name' => $info['name'], - 'old_version' => $info['version'], - 'new_version' => $info['update_version'], - 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', - ); - } - \WP_CLI\Utils\format_items( 'table', $status, - array( 'name', 'old_version', 'new_version', 'status' ) ); - } + if ($num_to_update > 0) { + $status = array(); + foreach($items_to_update as $item_to_update => $info) { + $status[$item_to_update] = array( + 'name' => $info['name'], + 'old_version' => $info['version'], + 'new_version' => $info['update_version'], + 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', + ); + } + \WP_CLI\Utils\format_items( 'table', $status, + array( 'name', 'old_version', 'new_version', 'status' ) ); + } } protected function _list( $_, $assoc_args ) { From b8ce086765e61bea52986cd6e7a95d10510c261e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 30 Aug 2014 00:44:17 +0200 Subject: [PATCH 3140/5359] core check-update --- php/commands/core.php | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 9466a3e6f..be93ee0cf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -9,6 +9,59 @@ */ class Core_Command extends WP_CLI_Command { + /** + * Check for update via Version Check API. Returns latest version if there's an update, or empty if no update available. + * + * ## OPTIONS + * + * [--major] + * : Compare only the first two parts of the version numbers. + * + * @subcommand check-update + */ + function check_update( $_, $assoc_args ) { + $versions_path = ABSPATH . 'wp-includes/version.php'; + + if ( ! is_readable( $versions_path ) ) { + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); + } + + include $versions_path; + + $url = 'http://api.wordpress.org/core/version-check/1.7/'; + + $options = array( + 'timeout' => 30 + ); + + $headers = array( + 'Accept' => 'application/json' + ); + $response = Utils\request( 'GET', $url, $headers, $options ); + + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( "Failed to get latest version." ); + } + + $latest_data = json_decode( $response->body ); + + $latest = $latest_data->offers[0]->current; + + if ( isset( $assoc_args['major'] ) ) { + $latest_major = explode( '.', $latest ); + $current_major = explode( '.', $wp_version ); + if ( $latest_major[0] !== $current_major[0] + || $latest_major[1] !== $current_major[1] ) { + WP_CLI::line( $latest ); + } + + } else { + WP_CLI::line( $latest ); + } + } + /** * Download core WordPress files. * From 882d25ba05cfe7e3cdc12defab7c2f81c511bf9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 30 Aug 2014 00:55:03 +0200 Subject: [PATCH 3141/5359] http_request and elseif() --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index be93ee0cf..811371013 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -39,7 +39,7 @@ function check_update( $_, $assoc_args ) { $headers = array( 'Accept' => 'application/json' ); - $response = Utils\request( 'GET', $url, $headers, $options ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); if ( ! $response->success || 200 !== $response->status_code ) { WP_CLI::error( "Failed to get latest version." ); @@ -57,7 +57,7 @@ function check_update( $_, $assoc_args ) { WP_CLI::line( $latest ); } - } else { + } elseif ( $wp_version !== $latest ) { WP_CLI::line( $latest ); } } From 0f53bd07ca5e49c27b384cd1ed3788a46883fa18 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 30 Aug 2014 11:50:14 -0700 Subject: [PATCH 3142/5359] Example: Update one option against multiple sites See #1367 --- php/commands/option.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index ded55ce2b..962ef03ce 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -96,6 +96,9 @@ public function add( $args, $assoc_args ) { * # Update an option by reading from a file * wp option update my_option < value.txt * + * # Update one option on multiple sites using xargs + * wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} option update <key> <value>' + * * @alias set */ public function update( $args, $assoc_args ) { From 912169a00b6ca4e4a18990b8d2b1b90f85b94cc4 Mon Sep 17 00:00:00 2001 From: Pippin Williamson <pippin@pippinsplugins.com> Date: Tue, 2 Sep 2014 19:09:17 -0500 Subject: [PATCH 3143/5359] Better error message for update() Return error messages for both identical values and update failures. --- php/commands/option.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 7b9bc80af..ea5d17f7d 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -107,8 +107,10 @@ public function update( $args, $assoc_args ) { $result = update_option( $key, $value ); // update_option() returns false if the value is the same - if ( !$result && $value != get_option( $key ) ) { - WP_CLI::error( "Option '$key' value is already set to '$value'." ); + if ( ! $result ) { + WP_CLI::error( "Could not update option '$key'." ); + } else if ( $value == get_option( $key ) ) { + WP_CLI::error( "Value passed for '$key' option is unchanged." ); } else { WP_CLI::success( "Updated '$key' option." ); } From 31b9a2feb04c673764328568f8bddc0ecf15dfa8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigosprimo@gmail.com> Date: Thu, 4 Sep 2014 23:36:51 -0300 Subject: [PATCH 3144/5359] test coverage for `wp scaffold _s` --- features/scaffold.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index a02d3d9f2..438e1842e 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -187,3 +187,15 @@ Feature: WordPress code scaffolding """ Error: Invalid package directory. composer.json file must be present. """ + + Scenario: Scaffold starter code for a theme + Given I run `wp theme path` + And save STDOUT as {THEME_DIR} + + When I run `wp scaffold _s starter-theme` + Then STDOUT should contain: + """ + Success: Created theme 'Starter-theme'. + """ + And the {THEME_DIR}/starter-theme/style.css file should exist + From 5e905ca9e3c7b7a235754e9791ce953be71b653c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigosprimo@gmail.com> Date: Fri, 5 Sep 2014 00:00:28 -0300 Subject: [PATCH 3145/5359] fix `wp scaffold _s` --- php/commands/scaffold.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 3fd04361d..babe849e4 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -216,6 +216,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); + $this->init_wp_filesystem(); unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); From 27b23a8a085595dd0493233bc034b875e44ff8d5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 09:58:36 -0700 Subject: [PATCH 3146/5359] Denote all available fields for `wp comment list` --- php/commands/comment.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 6a014cefd..b490c902c 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -127,11 +127,34 @@ public function get( $args, $assoc_args ) { * : Prints the value of a single field for each comment. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to comment_ID,comment_post_ID,comment_date,comment_approved,comment_author,comment_author_email + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each comment: + * + * * comment_ID + * * comment_post_ID + * * comment_date + * * comment_approved + * * comment_author + * * comment_author_email + * + * These fields are optionally available: + * + * * comment_author_url + * * comment_author_IP + * * comment_date_gmt + * * comment_content + * * comment_karma + * * comment_agent + * * comment_type + * * comment_parent + * * user_id + * * ## EXAMPLES * * wp comment list --field=ID From 4b9d5c0e7d0d356de7cf8eab0a66139f063f62e2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:01:56 -0700 Subject: [PATCH 3147/5359] Denote available fields for `wp cron schedule list` --- php/commands/cron.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 4bdf4904c..93a75ee12 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -396,11 +396,21 @@ class Cron_Schedule_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Available fields: name, display, interval. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, json, csv, ids. Default: table. * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each cron schedule: + * + * * name + * * display + * * interval + * + * There are no additional fields. + * * ## EXAMPLES * * wp cron schedule list From bb7c308c251758e92b4ef4bfcbf2a97ff5cd21d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:05:13 -0700 Subject: [PATCH 3148/5359] Denote available fields for `wp menu list` --- php/commands/menu.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index adc6ab2f0..fe9739837 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -94,11 +94,29 @@ public function delete( $args, $_ ) { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to term_id,name,slug,count + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each menu: + * + * * term_id + * * name + * * slug + * * count + * + * These fields are optionally available: + * + * * term_group + * * term_taxonomy_id + * * taxonomy + * * description + * * parent + * * locations + * * ## EXAMPLES * * wp menu list From 172e36bdf768a4095f8e17e83a69e32a2564d40f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:10:30 -0700 Subject: [PATCH 3149/5359] Denote relevant available fields for `wp menu item list` --- php/commands/menu.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index fe9739837..8219df7ae 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -190,11 +190,34 @@ class Menu_Item_Command extends WP_CLI_Command { * : The name, slug, or term ID for the menu * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to db_id,type,title,link + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each menu item: + * + * * db_id + * * type + * * title + * * link + * * position + * + * These fields are optionally available: + * + * * menu_item_parent + * * object_id + * * object + * * type + * * type_label + * * target + * * attr_title + * * description + * * classes + * * xfn + * * ## EXAMPLES * * wp menu item list <menu> From 639f884bdafec1a8b05a8d13838ddb1d61349d93 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:12:15 -0700 Subject: [PATCH 3150/5359] Fix display of menu item classes in list table --- php/commands/menu.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 8219df7ae..ee679c77f 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -233,9 +233,12 @@ public function list_( $args, $assoc_args ) { // Correct position inconsistency and // protected `url` param in WP-CLI - $items = array_map( function( $item ) { + $items = array_map( function( $item ) use ( $assoc_args ) { $item->position = $item->menu_order; $item->link = $item->url; + if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'json' ) ) ) { + $item->classes = json_encode( $item->classes ); + } return $item; }, $items ); From 5f0b465c78e135d79782689b6ac7af22ba898fa4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:16:18 -0700 Subject: [PATCH 3151/5359] Denote available fields for `wp menu location list` --- php/commands/menu.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index ee679c77f..f71f9dbda 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -624,6 +624,13 @@ class Menu_Location_Command extends WP_CLI_Command { * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each location: + * + * * name + * * description + * * ## EXAMPLES * * wp menu location list From 5750ccd1c7318601739ee9cbe4da2102d8e8198a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:31:21 -0700 Subject: [PATCH 3152/5359] Denote available fields for `wp plugin list` --- php/commands/plugin.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 74af879cb..e33d27097 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -506,11 +506,28 @@ function delete( $args, $assoc_args = array() ) { * : Prints the value of a single field for each plugin. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to name,status,update,version. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each plugin: + * + * * name + * * status + * * update + * * version + * + * These fields are optionally available: + * + * * update_version + * * update_package + * * update_id + * * title + * * description + * * ## EXAMPLES * * wp plugin list --status=active --format=json From db74d8da674906e6a083252632048a21a7a55c49 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:31:57 -0700 Subject: [PATCH 3153/5359] Denote available fields for `wp theme list` --- php/commands/theme.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 3fd58af36..c7eee76e4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -516,11 +516,28 @@ function delete( $args ) { * : Prints the value of a single field for each theme. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to name,status,update,version. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, json. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each theme: + * + * * name + * * status + * * update + * * version + * + * These fields are optionally available: + * + * * update_version + * * update_package + * * update_id + * * title + * * description + * * ## EXAMPLES * * wp theme list --status=inactive --format=csv From 6950c89cdffc21f3e9ee4631f7f167c39d7a4e1d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:33:34 -0700 Subject: [PATCH 3154/5359] Formatting --- php/commands/rewrite.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index ccaffbc2b..4bc3dced5 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -144,6 +144,7 @@ public function structure( $args, $assoc_args ) { * ## EXAMPLES * * wp rewrite list --format=csv + * * @subcommand list */ public function list_( $args, $assoc_args ) { From 680b6dea126c718428e38e930e3b1b00b6f8e4a2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:36:29 -0700 Subject: [PATCH 3155/5359] Denote available fields for `wp post list` --- php/commands/post.php | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 84fa861a4..fdd0203f0 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -211,11 +211,43 @@ public function delete( $args, $assoc_args ) { * : Prints the value of a single field for each post. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to ID,post_title,post_name,post_date,post_status. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each post: + * + * * ID + * * post_title + * * post_name + * * post_date + * * post_status + * + * These fields are optionally available: + * + * * post_author + * * post_date_gmt + * * post_content + * * post_excerpt + * * comment_status + * * ping_status + * * post_password + * * to_ping + * * pinged + * * post_modified + * * post_modified_gmt + * * post_content_filtered + * * post_parent + * * guid + * * menu_order + * * post_type + * * post_mime_type + * * comment_count + * * filter + * * ## EXAMPLES * * wp post list --field=ID From 23120d184f5c5dfefc598fd4b7434d958a4f043a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:38:06 -0700 Subject: [PATCH 3156/5359] Denote available fields for `wp role list` --- php/commands/role.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index f11d99f50..88b46eab0 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -18,11 +18,20 @@ class Role_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to name,role. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each role: + * + * * name + * * role + * + * There are no optional fields. + * * ## EXAMPLES * * wp role list --fields=role --format=csv From 0e345ace27f5461b44a8e3efab90f89affdaf2eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:45:13 -0700 Subject: [PATCH 3157/5359] Denote available fields for `wp sidebar list` --- php/commands/sidebar.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 626476868..0096d4a6c 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -17,11 +17,27 @@ class Sidebar_Command extends WP_CLI_Command { * ## OPTIONS * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to name, id, description + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each sidebar: + * + * * name + * * id + * * description + * + * These fields are optionally available: + * + * * class + * * before_widget + * * after_widget + * * before_title + * * after_title + * * ## EXAMPLES * * wp sidebar list --fields=name,id --format=csv From aa4b55a5e75c93d860ad251b4d6e76d59695d5fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:50:38 -0700 Subject: [PATCH 3158/5359] Denote available fields for `wp site list --- php/commands/site.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 7aa6ab2ef..7f286e167 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -345,6 +345,27 @@ private function _get_network( $network_id ) { * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each site: + * + * * blog_id + * * url + * * last_updated + * * registered + * + * These fields are optionally available: + * + * * site_id + * * domain + * * path + * * public + * * archived + * * mature + * * spam + * * deleted + * * lang_id + * * ## EXAMPLES * * # Output a simple list of site URLs From 964d75a15a718fedd3861a0b1fb406ea77b31249 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:52:41 -0700 Subject: [PATCH 3159/5359] Denote available fields for `wp term list` --- php/commands/term.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 503fb9dac..2e3e22ccd 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -25,17 +25,31 @@ class Term_Command extends WP_CLI_Command { * : List terms of one or more taxonomies * * [--<field>=<value>] - * : Filter by one or more fields. For accepted fields, see get_terms(). + * : Filter by one or more fields. * * [--field=<field>] * : Prints the value of a single field for each term. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to all of the term object fields. + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each term: + * + * * term_id + * * term_taxonomy_id + * * name + * * slug + * * description + * * parent + * * count + * + * There are no optionally available fields. + * * ## EXAMPLES * * wp term list category --format=csv From 08b5e4fd5b70dfddce741ab167ac467c50fe1571 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:57:11 -0700 Subject: [PATCH 3160/5359] Denote available fields for `wp user list` --- php/commands/user.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index a46378d18..f41ea4b83 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -36,11 +36,36 @@ public function __construct() { * : Prints the value of a single field for each user. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to ID,user_login,display_name,user_email,user_registered,roles + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each user: + * + * * ID + * * user_login + * * display_name + * * user_email + * * user_registered + * * roles + * + * These fields are optionally available: + * + * * user_pass + * * user_nicename + * * user_url + * * user_activation_key + * * user_status + * * spam + * * deleted + * * caps + * * cap_key + * * allcaps + * * filter + * * ## EXAMPLES * * wp user list --field=ID From 97518998dc69e060bc63dc6944814b63623ec6e3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 10:59:17 -0700 Subject: [PATCH 3161/5359] Denote available fields for `wp widget list` --- php/commands/widget.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 32924b557..19c9568d4 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -34,11 +34,22 @@ class Widget_Command extends WP_CLI_Command { * : ID for the corresponding sidebar. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to name, id, description + * : Limit the output to specific object fields. * * [--format=<format>] * : Accepted values: table, csv, json, count, ids. Default: table * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each widget: + * + * * name + * * id + * * position + * * options + * + * There are no optionally available fields. + * * ## EXAMPLES * * wp sidebar widget list <sidebar-id> --fields=name --format=csv From e93617d5eed18db222ce9b2b91765662216f989a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 6 Sep 2014 11:16:12 -0700 Subject: [PATCH 3162/5359] Ensure all non-section header bodies are indented --- php/commands/help.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index f8c7d9d9f..615089bbc 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -60,12 +60,15 @@ private static function show_help( $command ) { $out .= wordwrap( $longdesc, 90 ) . "\n"; } - // section headers - $out = preg_replace( '/^## ([A-Z ]+)/m', WP_CLI::colorize( '%9\1%n' ), $out ); - // definition lists $out = preg_replace_callback( '/([^\n]+)\n: (.+?)(\n\n|$)/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); + // Ensure all non-section headers are indented + $out = preg_replace( '#^([^\s^\#])#m', "\t$1", $out ); + + // section headers + $out = preg_replace( '/^## ([A-Z ]+)/m', WP_CLI::colorize( '%9\1%n' ), $out ); + $out = str_replace( "\t", ' ', $out ); self::pass_through_pager( $out ); From b51ae3b126efc957f33164245126fa22b4cff8c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 15:11:50 -0700 Subject: [PATCH 3163/5359] Switch php-cli-tools to latest release in preparation for 0.17.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 40ec7edf6..b02fa6093 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "0.10.0", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 57d689c7e05cb720ddc2174070a1d9b7e0b890c4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 16:11:48 -0700 Subject: [PATCH 3164/5359] Tag syntax for requiring a specific min version of WP Looks like this `@require-wp-4.0` Currently non-functional. Something's wrong with my bash --- ci/test.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index 9e14eacf9..309c70ea8 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -5,8 +5,57 @@ set -ex # Run the unit tests vendor/bin/phpunit +# http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format +function vercomp () { + echo $1 + echo $2 + if [[ $1 == $2 ]] + then + return 0 + fi + local IFS=. + local i ver1=($1) ver2=($2) + # fill empty fields in ver1 with zeros + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) + do + ver1[i]=0 + done + for ((i=0; i<${#ver1[@]}; i++)) + do + if [[ -z ${ver2[i]} ]] + then + # fill empty fields in ver2 with zeros + ver2[i]=0 + fi + if ((10#${ver1[i]} > 10#${ver2[i]})) + then + return 1 + fi + if ((10#${ver1[i]} < 10#${ver2[i]})) + then + return 2 + fi + done + return 0 +} + +if [[ ! -z "$WP_VERSION" ]]; then + + skip_tags="--tags='" + requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) + for (( i = 0; i < ${#requires[@]}; i++ )); do + version=${requires[$i]:12} + comp=$(vercomp $version $WP_VERSION) + if [[ 1 == $comp ]]; then + skip_tags="$skip_tags~$tag," + fi + done + skip_tags="$skip_tags'" + +fi + # Run the functional tests -vendor/bin/behat --format progress +vendor/bin/behat --format progress $skip_tags # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From ac93efc82405e6018927070c82ff8ba6a5fc79f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 20:26:27 -0700 Subject: [PATCH 3165/5359] Properly execute this bash function, and save our assigned data --- ci/test.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ci/test.sh b/ci/test.sh index 309c70ea8..2ea7a134b 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -6,9 +6,7 @@ set -ex vendor/bin/phpunit # http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format -function vercomp () { - echo $1 - echo $2 +vercomp() { if [[ $1 == $2 ]] then return 0 @@ -44,13 +42,16 @@ if [[ ! -z "$WP_VERSION" ]]; then skip_tags="--tags='" requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) for (( i = 0; i < ${#requires[@]}; i++ )); do - version=${requires[$i]:12} - comp=$(vercomp $version $WP_VERSION) - if [[ 1 == $comp ]]; then - skip_tags="$skip_tags~$tag," + version=${requires[$i]:13} + require=${requires[$i]} + vercomp $version $WP_VERSION + compare="$?" + if [[ 1 == $compare ]]; then + skip_tags="$skip_tags~$require," fi done - skip_tags="$skip_tags'" + skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' + skip_tags="$skip_tags'" # close the argument fi From e3bffa71f57f9a7cef6614557b44317884048f03 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 21:01:55 -0700 Subject: [PATCH 3166/5359] List available core translations --- features/core.feature | 10 ++++ php/WP_CLI/CommandWithTranslation.php | 78 +++++++++++++++++++++++++++ php/commands/core.php | 7 +++ 3 files changed, 95 insertions(+) create mode 100644 php/WP_CLI/CommandWithTranslation.php diff --git a/features/core.feature b/features/core.feature index 9be8d2686..f0c3f8387 100644 --- a/features/core.feature +++ b/features/core.feature @@ -345,3 +345,13 @@ Feature: Manage WordPress installation """ http://localhost:8001 """ + + @require-wp-4.0 + Scenario: Core translation CRUD + Given a WP install + + When I run `wp core i18n list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php new file mode 100644 index 000000000..1c2c9ad4a --- /dev/null +++ b/php/WP_CLI/CommandWithTranslation.php @@ -0,0 +1,78 @@ +<?php + +namespace WP_CLI; + +/** + * Base class for WP-CLI commands that deal with translations + * + * @package wp-cli + */ +abstract class CommandWithTranslation extends \WP_CLI_Command { + + protected $obj_type; + + protected $obj_fields = array( + 'language', + 'english_name', + 'native_name', + 'status', + 'updated', + ); + + /** + * List all languages available. + * + * [--keys=<keys>] + * : Limit output to metadata of specific keys. + * + * [--fields=<fields>] + * : Limit the output to specific fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each translation: + * + * * language + * * english_name + * * native_name + * * status + * * updated + * + * These fields are optionally available: + * + * * version + * * package + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + require_once ABSPATH . '/wp-admin/includes/translation-install.php'; + + $response = translations_api( $this->object_type ); + $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); + $available = get_available_languages(); + $translations = array_map( function( $translation ) use ( $available ) { + $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; + return $translation; + }, $translations ); + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $translations ); + + } + + /** + * Get Formatter object based on supplied parameters. + * + * @param array $assoc_args Parameters passed to command. Determines formatting. + * @return \WP_CLI\Formatter + */ + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); + } + +} diff --git a/php/commands/core.php b/php/commands/core.php index 9466a3e6f..a732f29a7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -873,3 +873,10 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip WP_CLI::add_command( 'core', 'Core_Command' ); +class Core_i18n_Command extends WP_CLI\CommandWithTranslation { + + protected $object_type = 'core'; + +} + +WP_CLI::add_command( 'core i18n', 'Core_i18n_Command' ); From e2df73aa3742c432507f93cc3a00b20765db1256 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 21:13:24 -0700 Subject: [PATCH 3167/5359] Throw an error for the whole command if < WP 4.0 --- php/commands/core.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index a732f29a7..43dff99e1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -879,4 +879,10 @@ class Core_i18n_Command extends WP_CLI\CommandWithTranslation { } -WP_CLI::add_command( 'core i18n', 'Core_i18n_Command' ); +WP_CLI::add_command( 'core i18n', 'Core_i18n_Command', array( + 'before_invoke' => function() { + if ( version_compare( $GLOBALS['wp_version'], '4.0', '<' ) ) { + WP_CLI::error( "Requires WordPress 4.0 or greater." ); + } + }) +); From 8c3dc5b9b70843cb4a5b42c5eab11dcfeaf9136c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 21:28:53 -0700 Subject: [PATCH 3168/5359] Break into a separate file so it doesn't affect our verbosity --- ci/set-behat-tags.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++ ci/test.sh | 52 ++-------------------------------------- 2 files changed, 59 insertions(+), 50 deletions(-) create mode 100755 ci/set-behat-tags.sh diff --git a/ci/set-behat-tags.sh b/ci/set-behat-tags.sh new file mode 100755 index 000000000..043a71fdf --- /dev/null +++ b/ci/set-behat-tags.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format +vercomp() { + if [[ $1 == $2 ]] + then + return 0 + fi + local IFS=. + local i ver1=($1) ver2=($2) + # fill empty fields in ver1 with zeros + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) + do + ver1[i]=0 + done + for ((i=0; i<${#ver1[@]}; i++)) + do + if [[ -z ${ver2[i]} ]] + then + # fill empty fields in ver2 with zeros + ver2[i]=0 + fi + if ((10#${ver1[i]} > 10#${ver2[i]})) + then + return 1 + fi + if ((10#${ver1[i]} < 10#${ver2[i]})) + then + return 2 + fi + done + return 0 +} + +if [[ ! -z "$WP_VERSION" ]]; then + + skip_tags="--tags='" + requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) + for (( i = 0; i < ${#requires[@]}; i++ )); do + version=${requires[$i]:12} + require=${requires[$i]} + vercomp $version $WP_VERSION + compare="$?" + if [[ 1 == $compare ]]; then + skip_tags="$skip_tags~$require," + fi + done + if [[ "--tags='" != $skip_tags ]]; then + skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' + skip_tags="$skip_tags'" # close the argument + else + skip_tags='' + fi + +fi + +echo export behat_tags=$skip_tags \ No newline at end of file diff --git a/ci/test.sh b/ci/test.sh index 2ea7a134b..0972b3a34 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -5,58 +5,10 @@ set -ex # Run the unit tests vendor/bin/phpunit -# http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format -vercomp() { - if [[ $1 == $2 ]] - then - return 0 - fi - local IFS=. - local i ver1=($1) ver2=($2) - # fill empty fields in ver1 with zeros - for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) - do - ver1[i]=0 - done - for ((i=0; i<${#ver1[@]}; i++)) - do - if [[ -z ${ver2[i]} ]] - then - # fill empty fields in ver2 with zeros - ver2[i]=0 - fi - if ((10#${ver1[i]} > 10#${ver2[i]})) - then - return 1 - fi - if ((10#${ver1[i]} < 10#${ver2[i]})) - then - return 2 - fi - done - return 0 -} - -if [[ ! -z "$WP_VERSION" ]]; then - - skip_tags="--tags='" - requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) - for (( i = 0; i < ${#requires[@]}; i++ )); do - version=${requires[$i]:13} - require=${requires[$i]} - vercomp $version $WP_VERSION - compare="$?" - if [[ 1 == $compare ]]; then - skip_tags="$skip_tags~$require," - fi - done - skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' - skip_tags="$skip_tags'" # close the argument - -fi +eval $(./ci/set-behat-tags.sh) # Run the functional tests -vendor/bin/behat --format progress $skip_tags +vendor/bin/behat --format progress $behat_tags # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From c6f49c294d2e956eda88a7de026c851cd8b0cb6e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 7 Sep 2014 21:40:58 -0700 Subject: [PATCH 3169/5359] Install a given language --- features/core.feature | 13 ++++++++++++ php/WP_CLI/CommandWithTranslation.php | 29 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/features/core.feature b/features/core.feature index f0c3f8387..238e8695c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -355,3 +355,16 @@ Feature: Manage WordPress installation | language | english_name | status | | ar | Arabic | uninstalled | | az | Azerbaijani | uninstalled | + | en_GB | English (UK) | uninstalled | + + When I run `wp core i18n install en_GB` + Then STDOUT should be: + """ + Success: Language installed. + """ + + When I run `wp core i18n install en_GB` + Then STDOUT should be: + """ + Warning: Language already installed. + """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 1c2c9ad4a..65f9552f7 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -65,6 +65,35 @@ public function list_( $args, $assoc_args ) { } + /** + * Install a given language. + * + * <language> + * : Language code to install. + * + * @subcommand install + */ + public function install( $args, $assoc_args ) { + + list( $language_code ) = $args; + + $available = get_available_languages(); + if ( in_array( $language_code, $available ) ) { + \WP_CLI::warning( "Language already installed." ); + exit; + } + + require_once ABSPATH . '/wp-admin/includes/translation-install.php'; + + $response = wp_download_language_pack( $language_code ); + if ( $response == $language_code ) { + \WP_CLI::success( "Language installed." ); + } else { + \WP_CLI::error( "Couldn't install language." ); + } + + } + /** * Get Formatter object based on supplied parameters. * From a84903503a6cbe416acd0d4d348e4f90f3904ae9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Sep 2014 05:41:05 -0700 Subject: [PATCH 3170/5359] Switch to php-cli-tools v0.10.1 See https://github.com/wp-cli/php-cli-tools/releases/tag/v0.10.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b02fa6093..da62d1b49 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.0", + "wp-cli/php-cli-tools": "0.10.1", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 96edff066daf4cad0d37d743a2fda31221d85172 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 05:45:43 -0700 Subject: [PATCH 3171/5359] Test latest version of WP, now 4.0 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e6f78d2a..b5b6e3185 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=3.9 + - WP_VERSION=4.0 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: From 5a9033fb76ba3868610d5d4cd1378d1c5d6ad33e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 05:55:59 -0700 Subject: [PATCH 3172/5359] Use `try` for `STDERR` --- features/core.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 238e8695c..0571e7be1 100644 --- a/features/core.feature +++ b/features/core.feature @@ -363,8 +363,8 @@ Feature: Manage WordPress installation Success: Language installed. """ - When I run `wp core i18n install en_GB` - Then STDOUT should be: + When I try `wp core i18n install en_GB` + Then STDERR should be: """ Warning: Language already installed. """ From b6656b40fa071bef548e38bcd1c52fdd6f653e00 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:05:48 -0700 Subject: [PATCH 3173/5359] Another test --- features/core.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/core.feature b/features/core.feature index 0571e7be1..9da9cc810 100644 --- a/features/core.feature +++ b/features/core.feature @@ -368,3 +368,11 @@ Feature: Manage WordPress installation """ Warning: Language already installed. """ + + When I run `wp core i18n list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_GB | English (UK) | installed | + From 0a455aec84705099ff333d54b6bde8606383a081 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:06:00 -0700 Subject: [PATCH 3174/5359] Standardize on `obj_type` for consistency --- php/WP_CLI/CommandWithTranslation.php | 2 +- php/commands/core.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 65f9552f7..b49b69435 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -52,7 +52,7 @@ public function list_( $args, $assoc_args ) { require_once ABSPATH . '/wp-admin/includes/translation-install.php'; - $response = translations_api( $this->object_type ); + $response = translations_api( $this->obj_type ); $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); $available = get_available_languages(); $translations = array_map( function( $translation ) use ( $available ) { diff --git a/php/commands/core.php b/php/commands/core.php index 43dff99e1..6d4648560 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -875,7 +875,7 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip class Core_i18n_Command extends WP_CLI\CommandWithTranslation { - protected $object_type = 'core'; + protected $obj_type = 'core'; } From f4922c3b5de1c84d8aa36295c651efe2ae24aca0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:07:56 -0700 Subject: [PATCH 3175/5359] Use `wp_get_installed_translations()`, which allows us to pass the type --- php/WP_CLI/CommandWithTranslation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index b49b69435..bbdcd7578 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -54,7 +54,8 @@ public function list_( $args, $assoc_args ) { $response = translations_api( $this->obj_type ); $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); - $available = get_available_languages(); + $available = wp_get_installed_translations( $this->obj_type ); + $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); $translations = array_map( function( $translation ) use ( $available ) { $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; return $translation; From b7272053c93e9becf91f51db314bfb1b289b4790 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:15:55 -0700 Subject: [PATCH 3176/5359] Defer to `wp_get_installed_translations()` --- php/WP_CLI/CommandWithTranslation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index bbdcd7578..2476892d7 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -78,7 +78,8 @@ public function install( $args, $assoc_args ) { list( $language_code ) = $args; - $available = get_available_languages(); + $available = wp_get_installed_translations( $this->obj_type ); + $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); if ( in_array( $language_code, $available ) ) { \WP_CLI::warning( "Language already installed." ); exit; From a24165930e9b4f7bdc4004f6de2154f9c09bd194 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:55:12 -0700 Subject: [PATCH 3177/5359] Uninstall command for core language --- features/core.feature | 17 +++++++++- php/WP_CLI/CommandWithTranslation.php | 48 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 9da9cc810..787fbbdbc 100644 --- a/features/core.feature +++ b/features/core.feature @@ -358,7 +358,9 @@ Feature: Manage WordPress installation | en_GB | English (UK) | uninstalled | When I run `wp core i18n install en_GB` - Then STDOUT should be: + Then the wp-content/languages/admin-en_GB.po file should exist + And the wp-content/languages/en_GB.po file should exist + And STDOUT should be: """ Success: Language installed. """ @@ -376,3 +378,16 @@ Feature: Manage WordPress installation | az | Azerbaijani | uninstalled | | en_GB | English (UK) | installed | + When I run `wp core i18n uninstall en_GB` + Then the wp-content/languages/admin-en_GB.po file should not exist + And the wp-content/languages/en_GB.po file should not exist + And STDOUT should be: + """ + Success: Language uninstalled. + """ + + When I try `wp core i18n uninstall en_GB` + Then STDERR should be: + """ + Error: Language not installed. + """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 2476892d7..1ec851910 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -96,6 +96,54 @@ public function install( $args, $assoc_args ) { } + /** + * Uninstall a given language. + * + * <language> + * : Language code to uninstall. + * + * @subcommand uninstall + */ + public function uninstall( $args, $assoc_args ) { + global $wp_filesystem; + + list( $language_code ) = $args; + + $available = wp_get_installed_translations( $this->obj_type ); + $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + if ( ! in_array( $language_code, $available ) ) { + \WP_CLI::error( "Language not installed." ); + } + + $dir = 'core' === $this->obj_type ? '' : "/$this->obj_type"; + $files = scandir( WP_LANG_DIR . $dir ); + if ( ! $files ) { + \WP_CLI::error( "No files found in language directory." ); + } + + // As of WP 4.0, no API for deleting a language pack + WP_Filesystem(); + $deleted = false; + foreach ( $files as $file ) { + if ( '.' === $file[0] || is_dir( $file ) ) { + continue; + } + $extension_length = strlen( $language_code ) + 4; + $ending = substr( $file, -$extension_length ); + if ( ! in_array( $file, array( $language_code . '.po', $language_code . '.mo' ) ) && ! in_array( $ending, array( '-' . $language_code . '.po', '-' . $language_code . '.mo' ) ) ) { + continue; + } + $deleted = $wp_filesystem->delete( WP_LANG_DIR . $dir . '/' . $file ); + } + + if ( $deleted ) { + \WP_CLI::success( "Language uninstalled." ); + } else { + \WP_CLI::error( "Couldn't uninstall language." ); + } + + } + /** * Get Formatter object based on supplied parameters. * From 4ae5c78e131ae9ed1ce424655773136e42bb3c88 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 06:56:34 -0700 Subject: [PATCH 3178/5359] Rename to `wp core language` --- features/core.feature | 12 ++++++------ php/commands/core.php | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/features/core.feature b/features/core.feature index 787fbbdbc..5ced9955d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -350,14 +350,14 @@ Feature: Manage WordPress installation Scenario: Core translation CRUD Given a WP install - When I run `wp core i18n list --fields=language,english_name,status` + When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: | language | english_name | status | | ar | Arabic | uninstalled | | az | Azerbaijani | uninstalled | | en_GB | English (UK) | uninstalled | - When I run `wp core i18n install en_GB` + When I run `wp core language install en_GB` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist And STDOUT should be: @@ -365,20 +365,20 @@ Feature: Manage WordPress installation Success: Language installed. """ - When I try `wp core i18n install en_GB` + When I try `wp core language install en_GB` Then STDERR should be: """ Warning: Language already installed. """ - When I run `wp core i18n list --fields=language,english_name,status` + When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: | language | english_name | status | | ar | Arabic | uninstalled | | az | Azerbaijani | uninstalled | | en_GB | English (UK) | installed | - When I run `wp core i18n uninstall en_GB` + When I run `wp core language uninstall en_GB` Then the wp-content/languages/admin-en_GB.po file should not exist And the wp-content/languages/en_GB.po file should not exist And STDOUT should be: @@ -386,7 +386,7 @@ Feature: Manage WordPress installation Success: Language uninstalled. """ - When I try `wp core i18n uninstall en_GB` + When I try `wp core language uninstall en_GB` Then STDERR should be: """ Error: Language not installed. diff --git a/php/commands/core.php b/php/commands/core.php index 6d4648560..aa7f8e75c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -873,13 +873,13 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip WP_CLI::add_command( 'core', 'Core_Command' ); -class Core_i18n_Command extends WP_CLI\CommandWithTranslation { +class Core_Language_Command extends WP_CLI\CommandWithTranslation { protected $obj_type = 'core'; } -WP_CLI::add_command( 'core i18n', 'Core_i18n_Command', array( +WP_CLI::add_command( 'core language', 'Core_Language_Command', array( 'before_invoke' => function() { if ( version_compare( $GLOBALS['wp_version'], '4.0', '<' ) ) { WP_CLI::error( "Requires WordPress 4.0 or greater." ); From 56fa910582ccb3765cc74160079b75343464065e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 07:01:06 -0700 Subject: [PATCH 3179/5359] Remove some copy and paste --- php/WP_CLI/CommandWithTranslation.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 1ec851910..ca1b8e63f 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -22,14 +22,11 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { /** * List all languages available. * - * [--keys=<keys>] - * : Limit output to metadata of specific keys. - * * [--fields=<fields>] * : Limit the output to specific fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json. Default: table * * ## AVAILABLE FIELDS * From 0bc1eaf7097a8e46aa801947eb842c893b15ed4c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 07:13:38 -0700 Subject: [PATCH 3180/5359] Command to activate a core language --- features/core.feature | 19 ++++++++++++++++++ php/WP_CLI/CommandWithTranslation.php | 28 ++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 5ced9955d..dac89c77b 100644 --- a/features/core.feature +++ b/features/core.feature @@ -378,6 +378,25 @@ Feature: Manage WordPress installation | az | Azerbaijani | uninstalled | | en_GB | English (UK) | installed | + When I run `wp core language activate en_GB` + Then STDOUT should be: + """ + Success: Language activated. + """ + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_GB | English (UK) | active | + + When I try `wp core language activate invalid_lang` + Then STDERR should be: + """ + Error: Language not installed. + """ + When I run `wp core language uninstall en_GB` Then the wp-content/languages/admin-en_GB.po file should not exist And the wp-content/languages/en_GB.po file should not exist diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index ca1b8e63f..36ca451a2 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -53,8 +53,12 @@ public function list_( $args, $assoc_args ) { $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); $available = wp_get_installed_translations( $this->obj_type ); $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); - $translations = array_map( function( $translation ) use ( $available ) { + $current_locale = get_locale(); + $translations = array_map( function( $translation ) use ( $available, $current_locale ) { $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; + if ( $current_locale == $translation['language'] ) { + $translation['status'] = 'active'; + } return $translation; }, $translations ); @@ -93,6 +97,28 @@ public function install( $args, $assoc_args ) { } + /** + * Activate a given language. + * + * <language> + * : Language code to activate. + * + * @subcommand activate + */ + public function activate( $args, $assoc_args ) { + + list( $language_code ) = $args; + + $available = wp_get_installed_translations( $this->obj_type ); + $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + if ( ! in_array( $language_code, $available ) ) { + \WP_CLI::error( "Language not installed." ); + } + + update_option( 'WPLANG', $language_code ); + \WP_CLI::success( "Language activated." ); + } + /** * Uninstall a given language. * From a57778faba65a58a104c45154f690751402191ca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 07:31:39 -0700 Subject: [PATCH 3181/5359] Mimic core's behavior of preventing orphaned terms for all versions --- features/term.feature | 7 +++++++ php/commands/term.php | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 90b2a0b07..2dc2d3d05 100644 --- a/features/term.feature +++ b/features/term.feature @@ -70,3 +70,10 @@ Feature: Manage WordPress terms """ 11 """ + + Scenario: Term with a non-existent parent + When I try `wp term create category Apple --parent=99 --porcelain` + Then STDERR should be: + """ + Error: Parent term does not exist. + """ diff --git a/php/commands/term.php b/php/commands/term.php index 2e3e22ccd..d7a35e295 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -110,7 +110,7 @@ public function create( $args, $assoc_args ) { $defaults = array( 'slug' => sanitize_title( $term ), 'description' => '', - 'parent' => '', + 'parent' => 0, ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); @@ -121,6 +121,11 @@ public function create( $args, $assoc_args ) { $porcelain = false; } + // Compatibility for < WP 4.0 + if ( $assoc_args['parent'] > 0 && ! term_exists( (int) $assoc_args['parent'] ) ) { + WP_CLI::error( 'Parent term does not exist.' ); + } + $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); if ( is_wp_error( $ret ) ) { From 9aaed7ea2aeb146f4ad9056990b01c90582ab4a6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 07:35:00 -0700 Subject: [PATCH 3182/5359] Update orphan term test to get around core's new check for parent --- features/export.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/export.feature b/features/export.feature index b7878a96b..8539e309c 100644 --- a/features/export.feature +++ b/features/export.feature @@ -12,8 +12,12 @@ Feature: Export content. Scenario: Term with a non-existent parent Given a WP install - When I run `wp term create category Apple --parent=99 --porcelain` + When I run `wp term create category Apple --porcelain` Then STDOUT should be a number + And save STDOUT as {TERM_ID} + + When I run `wp term update category {TERM_ID} --parent=99` + Then STDOUT should not be empty When I try `wp export` Then STDERR should be: From 4663fce9e06c122696866b26cdb5f34dd0b125d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 18:26:12 +0200 Subject: [PATCH 3183/5359] major,minor and Formatter --- php/commands/cli.php | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index bfc3a91a3..b0d26adb7 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -69,6 +69,85 @@ function info( $_, $assoc_args ) { } } + /** + * Check for update via Github API. Returns the available versions if there are updates, or empty if no update available. + * + * ## OPTIONS + * + * [--minor] + * : Compare only the first two parts of the version number. + * + * [--major] + * : Compare only the first part of the version number. + * + * [--field=<field>] + * : Prints the value of a single field for each update. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to version,type,package_url. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * @subcommand check-update + */ + function check_update( $_, $assoc_args ) { + $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; + + $options = array( + 'timeout' => 30 + ); + + $headers = array( + 'Accept' => 'application/json' + ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); + + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( "Failed to get latest version." ); + } + + $release_data = json_decode( $response->body ); + $current_parts = explode( '.', WP_CLI_VERSION ); + $updates = array(); + + foreach ( $release_data as $release ) { + $release_version = $release->tag_name; + // get rid of leading "v" + if ( 'v' === substr( $release_version, 0, 1 ) ) { + $release_version = ltrim( $release_version, 'v' ); + } + // don't list the current version + if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) + continue; + $release_parts = explode( '.', $release_version ); + $release_type = 'major'; + + if ( $release_parts[0] === $current_parts[0] + && $release_parts[1] === $current_parts[1] ) { + $release_type = 'minor'; + } + + if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) + && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) + ) { + $updates[] = array( + 'version' => $release_version, + 'type' => $release_type, + 'package_url' => $release->assets[0]->browser_download_url + ); + } + } + + if ( $updates ) { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'type', 'package_url' ) + ); + $formatter->display_items( $updates ); + } + } + /** * Dump the list of global parameters, as JSON. * From 5a809b2bdc73f707341c6696f042b3ace6f334c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 18:49:37 +0200 Subject: [PATCH 3184/5359] WP.org announces only one version --- php/commands/core.php | 67 +++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 20682e65a..9287d0588 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -14,20 +14,25 @@ class Core_Command extends WP_CLI_Command { * * ## OPTIONS * + * [--minor] + * : Compare only the first two parts of the version number. + * * [--major] - * : Compare only the first two parts of the version numbers. + * : Compare only the first part of the version number. + * + * [--field=<field>] + * : Prints the value of a single field for each update. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to version,type,package_url. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table * * @subcommand check-update */ function check_update( $_, $assoc_args ) { $versions_path = ABSPATH . 'wp-includes/version.php'; - - if ( ! is_readable( $versions_path ) ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } - include $versions_path; $url = 'http://api.wordpress.org/core/version-check/1.7/'; @@ -45,20 +50,46 @@ function check_update( $_, $assoc_args ) { WP_CLI::error( "Failed to get latest version." ); } - $latest_data = json_decode( $response->body ); + $release_data = json_decode( $response->body ); + + $current_parts = explode( '.', $wp_version ); + $updates = array(); + + foreach ( $release_data as $release ) { + $release_version = $release->tag_name; + // get rid of leading "v" + if ( 'v' === substr( $release_version, 0, 1 ) ) { + $release_version = ltrim( $release_version, 'v' ); + } + // don't list the current version + if ( version_compare( $release_version, $wp_version '<=' ) ) + continue; + $release_parts = explode( '.', $release_version ); + $release_type = 'major'; - $latest = $latest_data->offers[0]->current; + if ( $release_parts[0] === $current_parts[0] + && $release_parts[1] === $current_parts[1] ) { + $release_type = 'minor'; + } - if ( isset( $assoc_args['major'] ) ) { - $latest_major = explode( '.', $latest ); - $current_major = explode( '.', $wp_version ); - if ( $latest_major[0] !== $current_major[0] - || $latest_major[1] !== $current_major[1] ) { - WP_CLI::line( $latest ); + if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) + && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) + ) { + $updates[] = array( + 'version' => $release_version, + 'type' => $release_type, + // there's onyl one version on WP.org + 'package_url' => $release->assets[0]->browser_download_url + ); } + } - } elseif ( $wp_version !== $latest ) { - WP_CLI::line( $latest ); + if ( $updates ) { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'type', 'package_url' ) + ); + $formatter->display_items( $updates ); } } From 95a4f7006d960269879cb9c9e492fa882f7f0559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 18:51:51 +0200 Subject: [PATCH 3185/5359] Let's call this update_type to be specific. --- php/commands/cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index b0d26adb7..d030fe74d 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -121,19 +121,19 @@ function check_update( $_, $assoc_args ) { if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) continue; $release_parts = explode( '.', $release_version ); - $release_type = 'major'; + $update_type = 'major'; if ( $release_parts[0] === $current_parts[0] && $release_parts[1] === $current_parts[1] ) { - $release_type = 'minor'; + $update_type = 'minor'; } - if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) - && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) + if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) + && ! ( isset( $assoc_args['major'] ) && 'major' !== $update_type ) ) { $updates[] = array( 'version' => $release_version, - 'type' => $release_type, + 'type' => $update_type, 'package_url' => $release->assets[0]->browser_download_url ); } From ef95444b292aff41a2e148644615f18420698df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 18:54:50 +0200 Subject: [PATCH 3186/5359] major -> minor, minor -> patch --- php/commands/cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index d030fe74d..8aa4e6408 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -74,10 +74,10 @@ function info( $_, $assoc_args ) { * * ## OPTIONS * - * [--minor] + * [--patch] * : Compare only the first two parts of the version number. * - * [--major] + * [--minor] * : Compare only the first part of the version number. * * [--field=<field>] @@ -121,15 +121,15 @@ function check_update( $_, $assoc_args ) { if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) continue; $release_parts = explode( '.', $release_version ); - $update_type = 'major'; + $update_type = 'minor'; if ( $release_parts[0] === $current_parts[0] && $release_parts[1] === $current_parts[1] ) { - $update_type = 'minor'; + $update_type = 'patch'; } - if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) - && ! ( isset( $assoc_args['major'] ) && 'major' !== $update_type ) + if ( ! ( isset( $assoc_args['patch'] ) && 'patch' !== $update_type ) + && ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) ) { $updates[] = array( 'version' => $release_version, From 69f13fb2c42332eb016675b6af339998dc41389f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 19:27:16 +0200 Subject: [PATCH 3187/5359] only show the latest version for each minor version --- php/commands/cli.php | 18 +++++++++++++++++- php/wp-cli.php | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 8aa4e6408..9653b3d61 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -69,6 +69,21 @@ function info( $_, $assoc_args ) { } } + /** + * Compare the last processed release to the current one, return true if it's the same minor version. + * + */ + private function same_minor_release( $release_parts, $updates ) { + $previous = end( $updates ); + if ( false === $previous ) + return false; + + $previous_parts = explode( '.', $previous['version'] ); + + return ( $previous_parts[0] === $release_parts[0] + && $previous_parts[1] === $release_parts[1] ); + } + /** * Check for update via Github API. Returns the available versions if there are updates, or empty if no update available. * @@ -117,7 +132,7 @@ function check_update( $_, $assoc_args ) { if ( 'v' === substr( $release_version, 0, 1 ) ) { $release_version = ltrim( $release_version, 'v' ); } - // don't list the current version + // don't list earlier releases if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) continue; $release_parts = explode( '.', $release_version ); @@ -130,6 +145,7 @@ function check_update( $_, $assoc_args ) { if ( ! ( isset( $assoc_args['patch'] ) && 'patch' !== $update_type ) && ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) + && ! $this->same_minor_release( $release_parts, $updates ) ) { $updates[] = array( 'version' => $release_version, diff --git a/php/wp-cli.php b/php/wp-cli.php index c0a45246e..e0acf8b28 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.16.0' ); +define( 'WP_CLI_VERSION', '0.13.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From d3a459e071c46ec7cf8d415a0dcb56d2203df139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 19:29:46 +0200 Subject: [PATCH 3188/5359] oops again --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index e0acf8b28..c0a45246e 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.13.0' ); +define( 'WP_CLI_VERSION', '0.16.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From cd1ed9cd58cb4c4b0f238881bacd0f378c0d610f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 19:42:32 +0200 Subject: [PATCH 3189/5359] halfdone check-update --- php/commands/core.php | 59 ++++++++----------------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9287d0588..305578190 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -14,17 +14,11 @@ class Core_Command extends WP_CLI_Command { * * ## OPTIONS * - * [--minor] - * : Compare only the first two parts of the version number. - * - * [--major] - * : Compare only the first part of the version number. - * * [--field=<field>] * : Prints the value of a single field for each update. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,type,package_url. + * : Limit the output to specific object fields. Defaults to version,package_url. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table @@ -32,9 +26,7 @@ class Core_Command extends WP_CLI_Command { * @subcommand check-update */ function check_update( $_, $assoc_args ) { - $versions_path = ABSPATH . 'wp-includes/version.php'; - include $versions_path; - + //TODO all versions: http://api.wordpress.org/core/stable-check/1.0/ $url = 'http://api.wordpress.org/core/version-check/1.7/'; $options = array( @@ -52,45 +44,16 @@ function check_update( $_, $assoc_args ) { $release_data = json_decode( $response->body ); - $current_parts = explode( '.', $wp_version ); - $updates = array(); - - foreach ( $release_data as $release ) { - $release_version = $release->tag_name; - // get rid of leading "v" - if ( 'v' === substr( $release_version, 0, 1 ) ) { - $release_version = ltrim( $release_version, 'v' ); - } - // don't list the current version - if ( version_compare( $release_version, $wp_version '<=' ) ) - continue; - $release_parts = explode( '.', $release_version ); - $release_type = 'major'; - - if ( $release_parts[0] === $current_parts[0] - && $release_parts[1] === $current_parts[1] ) { - $release_type = 'minor'; - } - - if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) - && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) - ) { - $updates[] = array( - 'version' => $release_version, - 'type' => $release_type, - // there's onyl one version on WP.org - 'package_url' => $release->assets[0]->browser_download_url - ); - } - } + $updates[] = array( + 'version' => $release_data->offers[0]->version, + 'package_url' => $release_data->offers[0]->packages->no_content + ); - if ( $updates ) { - $formatter = new \WP_CLI\Formatter( - $assoc_args, - array( 'version', 'type', 'package_url' ) - ); - $formatter->display_items( $updates ); - } + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'package_url' ) + ); + $formatter->display_items( $updates ); } /** From e938929303c205bdf339412cf36d911252008806 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 10:56:52 -0700 Subject: [PATCH 3190/5359] Clarify what this `type` refers to by calling it `update_type` See #1386 --- php/commands/cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 9653b3d61..31d8738f7 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -149,7 +149,7 @@ function check_update( $_, $assoc_args ) { ) { $updates[] = array( 'version' => $release_version, - 'type' => $update_type, + 'update_type' => $update_type, 'package_url' => $release->assets[0]->browser_download_url ); } @@ -158,7 +158,7 @@ function check_update( $_, $assoc_args ) { if ( $updates ) { $formatter = new \WP_CLI\Formatter( $assoc_args, - array( 'version', 'type', 'package_url' ) + array( 'version', 'update_type', 'package_url' ) ); $formatter->display_items( $updates ); } From 40b233b88b9a29a0221e8963dedefb4c88e97c35 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 11:02:32 -0700 Subject: [PATCH 3191/5359] Success message when WP-CLI is up to date See #1386 --- php/commands/cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index 31d8738f7..eead271f6 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -161,6 +161,8 @@ function check_update( $_, $assoc_args ) { array( 'version', 'update_type', 'package_url' ) ); $formatter->display_items( $updates ); + } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { + WP_CLI::success( "WP-CLI is at the latest version." ); } } From 9aa1975ed34e4d36656d6e587a51abd8febe37f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 20:27:22 +0200 Subject: [PATCH 3192/5359] list all releases --- php/commands/core.php | 48 +++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 9287d0588..ce82d9e36 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -9,6 +9,28 @@ */ class Core_Command extends WP_CLI_Command { + /** + * Compare processed releases to the current one, and delete older one. Return remaining updates. + * + */ + private function remove_same_minor_releases( $release_parts, $updates ) { + if ( empty( $updates ) ) + return false; + + $differents = array(); + foreach ( $updates as $processed ) { + $processed_parts = explode( '.', $processed['version'] ); + + // later releases are always later in the array + if ( $processed_parts[0] !== $release_parts[0] + && $processed_parts[1] !== $release_parts[1] ) { + $differents[] = $processed; + } + } + + return $differents; + } + /** * Check for update via Version Check API. Returns latest version if there's an update, or empty if no update available. * @@ -35,12 +57,11 @@ function check_update( $_, $assoc_args ) { $versions_path = ABSPATH . 'wp-includes/version.php'; include $versions_path; - $url = 'http://api.wordpress.org/core/version-check/1.7/'; + $url = 'http://api.wordpress.org/core/stable-check/1.0/'; $options = array( 'timeout' => 30 ); - $headers = array( 'Accept' => 'application/json' ); @@ -51,35 +72,32 @@ function check_update( $_, $assoc_args ) { } $release_data = json_decode( $response->body ); + $locale = get_locale(); $current_parts = explode( '.', $wp_version ); $updates = array(); - foreach ( $release_data as $release ) { - $release_version = $release->tag_name; - // get rid of leading "v" - if ( 'v' === substr( $release_version, 0, 1 ) ) { - $release_version = ltrim( $release_version, 'v' ); - } - // don't list the current version - if ( version_compare( $release_version, $wp_version '<=' ) ) + foreach ( $release_data as $release_version => $release ) { + // don't list earliers versions + if ( version_compare( $release_version, $wp_version, '<=' ) ) continue; + $release_parts = explode( '.', $release_version ); - $release_type = 'major'; + $update_type = 'major'; if ( $release_parts[0] === $current_parts[0] && $release_parts[1] === $current_parts[1] ) { - $release_type = 'minor'; + $update_type = 'minor'; } if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) ) { + $updates = $this->remove_same_minor_releases( $release_parts, $updates ); $updates[] = array( 'version' => $release_version, - 'type' => $release_type, - // there's onyl one version on WP.org - 'package_url' => $release->assets[0]->browser_download_url + 'type' => $update_type, + 'package_url' => $this->get_download_url( $release_version, $locale ) ); } } From 49903dd349e8b111b53a7e1a11f3239b208c6605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 20:29:40 +0200 Subject: [PATCH 3193/5359] list all releases --- php/commands/core.php | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index b5141bc96..ce82d9e36 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -36,11 +36,17 @@ private function remove_same_minor_releases( $release_parts, $updates ) { * * ## OPTIONS * + * [--minor] + * : Compare only the first two parts of the version number. + * + * [--major] + * : Compare only the first part of the version number. + * * [--field=<field>] * : Prints the value of a single field for each update. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,package_url. + * : Limit the output to specific object fields. Defaults to version,type,package_url. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table @@ -48,15 +54,10 @@ private function remove_same_minor_releases( $release_parts, $updates ) { * @subcommand check-update */ function check_update( $_, $assoc_args ) { -<<<<<<< HEAD $versions_path = ABSPATH . 'wp-includes/version.php'; include $versions_path; $url = 'http://api.wordpress.org/core/stable-check/1.0/'; -======= - //TODO all versions: http://api.wordpress.org/core/stable-check/1.0/ - $url = 'http://api.wordpress.org/core/version-check/1.7/'; ->>>>>>> cd1ed9cd58cb4c4b0f238881bacd0f378c0d610f $options = array( 'timeout' => 30 @@ -73,7 +74,6 @@ function check_update( $_, $assoc_args ) { $release_data = json_decode( $response->body ); $locale = get_locale(); -<<<<<<< HEAD $current_parts = explode( '.', $wp_version ); $updates = array(); @@ -101,18 +101,14 @@ function check_update( $_, $assoc_args ) { ); } } -======= - $updates[] = array( - 'version' => $release_data->offers[0]->version, - 'package_url' => $release_data->offers[0]->packages->no_content - ); ->>>>>>> cd1ed9cd58cb4c4b0f238881bacd0f378c0d610f - $formatter = new \WP_CLI\Formatter( - $assoc_args, - array( 'version', 'package_url' ) - ); - $formatter->display_items( $updates ); + if ( $updates ) { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'type', 'package_url' ) + ); + $formatter->display_items( $updates ); + } } /** From cd99c897ce11560c264a92f6134432b9ba386fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 20:40:03 +0200 Subject: [PATCH 3194/5359] variable name --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ce82d9e36..4d26e9fa7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -90,8 +90,8 @@ function check_update( $_, $assoc_args ) { $update_type = 'minor'; } - if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $release_type ) - && ! ( isset( $assoc_args['major'] ) && 'major' !== $release_type ) + if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) + && ! ( isset( $assoc_args['major'] ) && 'major' !== $update_type ) ) { $updates = $this->remove_same_minor_releases( $release_parts, $updates ); $updates[] = array( From 222b75b1f95ea1831242ddc0c4d47d56dd81ab2a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 11:40:10 -0700 Subject: [PATCH 3195/5359] One instance missed in e938929303c205bdf339412cf36d911252008806 --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index eead271f6..deb9b86f9 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -99,7 +99,7 @@ private function same_minor_release( $release_parts, $updates ) { * : Prints the value of a single field for each update. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,type,package_url. + * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table From 0e0d6fdc93b42275d7bacf1c1f592a834add22f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 10 Sep 2014 22:41:21 +0200 Subject: [PATCH 3196/5359] 3 tests for wp core check-update --- features/core.feature | 31 +++++++++++++++++++++++++++++++ php/commands/core.php | 12 +++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index dac89c77b..e06bc1531 100644 --- a/features/core.feature +++ b/features/core.feature @@ -260,6 +260,37 @@ Feature: Manage WordPress installation 3.9 """ + @download + Scenario: Check for update via Version Check API + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp core check-update` + Then STDOUT should be: + """ + version update_type package_url + 3.8.4 minor https://wordpress.org/wordpress-3.8.4.zip + 3.9.2 major https://wordpress.org/wordpress-3.9.2.zip + 4.0 major https://wordpress.org/wordpress-4.0.zip + """ + + When I run `wp core check-update --major` + Then STDOUT should be: + """ + version update_type package_url + 3.9.2 major https://wordpress.org/wordpress-3.9.2.zip + 4.0 major https://wordpress.org/wordpress-4.0.zip + """ + + When I run `wp core check-update --minor` + Then STDOUT should be: + """ + version update_type package_url + 3.8.4 minor https://wordpress.org/wordpress-3.8.4.zip + """ + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory diff --git a/php/commands/core.php b/php/commands/core.php index 4d26e9fa7..f3b5eb3f0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -23,7 +23,7 @@ private function remove_same_minor_releases( $release_parts, $updates ) { // later releases are always later in the array if ( $processed_parts[0] !== $release_parts[0] - && $processed_parts[1] !== $release_parts[1] ) { + || $processed_parts[1] !== $release_parts[1] ) { $differents[] = $processed; } } @@ -46,10 +46,10 @@ private function remove_same_minor_releases( $release_parts, $updates ) { * : Prints the value of a single field for each update. * * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,type,package_url. + * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json. Default: table * * @subcommand check-update */ @@ -96,7 +96,7 @@ function check_update( $_, $assoc_args ) { $updates = $this->remove_same_minor_releases( $release_parts, $updates ); $updates[] = array( 'version' => $release_version, - 'type' => $update_type, + 'update_type' => $update_type, 'package_url' => $this->get_download_url( $release_version, $locale ) ); } @@ -105,9 +105,11 @@ function check_update( $_, $assoc_args ) { if ( $updates ) { $formatter = new \WP_CLI\Formatter( $assoc_args, - array( 'version', 'type', 'package_url' ) + array( 'version', 'update_type', 'package_url' ) ); $formatter->display_items( $updates ); + } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { + WP_CLI::success( "WordPress is at the latest version." ); } } From 70952f2f369286b86e48f29c6b098eb80802856e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 16:48:16 -0700 Subject: [PATCH 3197/5359] Fix typo; move private method to the bottom of the class See #1365 --- php/commands/core.php | 45 ++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index f3b5eb3f0..f6f82afec 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -9,28 +9,6 @@ */ class Core_Command extends WP_CLI_Command { - /** - * Compare processed releases to the current one, and delete older one. Return remaining updates. - * - */ - private function remove_same_minor_releases( $release_parts, $updates ) { - if ( empty( $updates ) ) - return false; - - $differents = array(); - foreach ( $updates as $processed ) { - $processed_parts = explode( '.', $processed['version'] ); - - // later releases are always later in the array - if ( $processed_parts[0] !== $release_parts[0] - || $processed_parts[1] !== $release_parts[1] ) { - $differents[] = $processed; - } - } - - return $differents; - } - /** * Check for update via Version Check API. Returns latest version if there's an update, or empty if no update available. * @@ -973,6 +951,29 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip return $url; } } + + /** + * Compare processed releases to the current one, and delete older one. Return remaining updates. + * + */ + private function remove_same_minor_releases( $release_parts, $updates ) { + if ( empty( $updates ) ) + return false; + + $difference = array(); + foreach ( $updates as $processed ) { + $processed_parts = explode( '.', $processed['version'] ); + + // later releases are always later in the array + if ( $processed_parts[0] !== $release_parts[0] + || $processed_parts[1] !== $release_parts[1] ) { + $difference[] = $processed; + } + } + + return $difference; + } + } WP_CLI::add_command( 'core', 'Core_Command' ); From 8d34aff1e7fb68853cd768054227ea2a72f147bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 10 Sep 2014 16:59:01 -0700 Subject: [PATCH 3198/5359] Mirror behaviour of `wp cli check-update` by listing most recent atop See #1365 --- features/core.feature | 30 +++++++++++++++++++++--------- php/commands/core.php | 7 ++++++- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/features/core.feature b/features/core.feature index e06bc1531..3e59a8c5a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -268,27 +268,39 @@ Feature: Manage WordPress installation Then STDOUT should not be empty When I run `wp core check-update` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | + | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | + | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + + When I run `wp core check-update --field=version | wc -l` Then STDOUT should be: """ - version update_type package_url - 3.8.4 minor https://wordpress.org/wordpress-3.8.4.zip - 3.9.2 major https://wordpress.org/wordpress-3.9.2.zip - 4.0 major https://wordpress.org/wordpress-4.0.zip + 3 """ When I run `wp core check-update --major` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | + | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | + + When I run `wp core check-update --major --field=version | wc -l` Then STDOUT should be: """ - version update_type package_url - 3.9.2 major https://wordpress.org/wordpress-3.9.2.zip - 4.0 major https://wordpress.org/wordpress-4.0.zip + 2 """ When I run `wp core check-update --minor` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + + When I run `wp core check-update --minor --field=version | wc -l` Then STDOUT should be: """ - version update_type package_url - 3.8.4 minor https://wordpress.org/wordpress-3.8.4.zip + 1 """ Scenario: Custom wp-content directory diff --git a/php/commands/core.php b/php/commands/core.php index f6f82afec..548476d90 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -50,12 +50,17 @@ function check_update( $_, $assoc_args ) { } $release_data = json_decode( $response->body ); + $release_versions = array_keys( (array) $release_data ); + usort( $release_versions, function( $a, $b ){ + return ! version_compare( $a, $b ); + }); + $locale = get_locale(); $current_parts = explode( '.', $wp_version ); $updates = array(); - foreach ( $release_data as $release_version => $release ) { + foreach ( $release_versions as $release_version ) { // don't list earliers versions if ( version_compare( $release_version, $wp_version, '<=' ) ) continue; From ebb46e33988c784431e391e0f65517665795ba86 Mon Sep 17 00:00:00 2001 From: Patrick Holberg Hesselberg <phh@peytz.dk> Date: Thu, 11 Sep 2014 18:47:20 +0000 Subject: [PATCH 3199/5359] removes like_escape deprecation notice and uses $wpdb->esc_like() if the method is available. Fallbacks to old like_escape() --- php/commands/search-replace.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7406eca9d..efb8955e6 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -122,7 +122,7 @@ private static function get_table_list( $args, $network ) { return $args; $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; - $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", like_escape( $prefix ) . '%' ) ); + $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); $allowed_tables = array(); $allowed_table_types = array( 'tables', 'global_tables' ); @@ -166,7 +166,10 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { - return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . like_escape( esc_sql( $old ) ) . '%' ) ); + // Remove notices in 4.0 and support backwards compatibility + $old = method_exists( $wpdb, 'esc_like' ) ? $wpdb->esc_like( $old ) : like_escape( esc_sql( $old ) ); + + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . $old . '%' ) ); } else { return $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } @@ -181,10 +184,13 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $fields = $primary_keys; $fields[] = $col; + // Remove notices in 4.0 and support backwards compatibility + $old = method_exists( $wpdb, 'esc_like' ) ? $wpdb->esc_like( $old ) : like_escape( esc_sql( $old ) ); + $args = array( 'table' => $table, 'fields' => $fields, - 'where' => "`$col`" . ' LIKE "%' . like_escape( esc_sql( $old ) ) . '%"', + 'where' => "`$col`" . ' LIKE "%' . $old . '%"', 'chunk_size' => $chunk_size ); From 7c2bb438ab1fff65342a5dff287228fee5658e67 Mon Sep 17 00:00:00 2001 From: Patrick Holberg Hesselberg <phh@peytz.dk> Date: Thu, 11 Sep 2014 19:01:10 +0000 Subject: [PATCH 3200/5359] avoids using a one-liner and uses a static method instead --- php/commands/search-replace.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index efb8955e6..d62d54dce 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -166,10 +166,7 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { - // Remove notices in 4.0 and support backwards compatibility - $old = method_exists( $wpdb, 'esc_like' ) ? $wpdb->esc_like( $old ) : like_escape( esc_sql( $old ) ); - - return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . $old . '%' ) ); + return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { return $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } @@ -184,13 +181,10 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $fields = $primary_keys; $fields[] = $col; - // Remove notices in 4.0 and support backwards compatibility - $old = method_exists( $wpdb, 'esc_like' ) ? $wpdb->esc_like( $old ) : like_escape( esc_sql( $old ) ); - $args = array( 'table' => $table, 'fields' => $fields, - 'where' => "`$col`" . ' LIKE "%' . $old . '%"', + 'where' => "`$col`" . ' LIKE "%' . self::esc_like( $old ) . '%"', 'chunk_size' => $chunk_size ); @@ -252,6 +246,21 @@ private static function is_text_col( $type ) { return false; } + + private static function esc_like( $old ) { + global $wpdb; + + // Remove notices in 4.0 and support backwards compatibility + if( method_exists( $wpdb, 'esc_like' ) ) { + // 4.0 + $old = $wpdb->esc_like( $old ); + } else { + // 3.9 or less + $old = like_escape( esc_sql( $old ) ); + } + + return $old; + } } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); From edbcc1c0dc54a7dc943072d5151da60136459eba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 11 Sep 2014 16:38:49 -0700 Subject: [PATCH 3201/5359] If no time supplied, `wp cron schedule` should default to "now" --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 93a75ee12..0b9854d5c 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -101,7 +101,7 @@ public function list_( $args, $assoc_args ) { public function schedule( $args, $assoc_args ) { $hook = $args[0]; - $next_run = ( isset( $args[1] ) ) ? $args[1] : false; + $next_run = ( isset( $args[1] ) ) ? $args[1] : 'now'; $recurrence = ( isset( $args[2] ) ) ? $args[2] : false; if ( ! empty( $next_run ) ) { From 6a43a8f015ba0e839817dc45b591011a4a6a8f25 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 11 Sep 2014 16:41:01 -0700 Subject: [PATCH 3202/5359] Test for edbcc1c --- features/cron.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/cron.feature b/features/cron.feature index 0f638f6f6..90f43ba15 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -34,6 +34,12 @@ Feature: Manage WP-Cron events and schedules Success: Scheduled event with hook 'wp_cli_test_event_3' """ + When I run `wp cron event schedule wp_cli_test_event_4` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_4' + """ + When I run `wp cron event list --format=csv --fields=hook,recurrence` Then STDOUT should be CSV containing: | hook | recurrence | From 1fb79c687c4b8afba082d586ae7c48bd71c1652b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 11 Sep 2014 17:07:48 -0700 Subject: [PATCH 3203/5359] Update .mailmap --- .mailmap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.mailmap b/.mailmap index b2fd54a52..9d78defad 100644 --- a/.mailmap +++ b/.mailmap @@ -13,6 +13,7 @@ dangardner <dan@web.nearest.to> danielbachhuber <d@danielbachhuber.com> danielbachhuber <daniel@handbuilt.co> danielbachhuber <danielbachhuber@gmail.com> +dlh01 <david@alleyinteractive.com> dd32 <contact-atlassian@dd32.id.au> drrobotnik <B@Brandons-Mac-Pro-4.local> dwightjack <marco.solazzi@gmail.com> @@ -35,10 +36,13 @@ johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> +jeichorn <joshua.eichorn@pagely.com> Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> +santagada <santagada@gmail.com> +lkwdwrd <woodward.lucas@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> @@ -56,18 +60,22 @@ nb <nb@nikolay.bg> nickdaugherty <ndaugherty987@gmail.com> nikolay <nikolay@users.noreply.github.com> nikolay <nikolaynkolev@gmail.com> +nschoenholtz <noah@alleyinteractive.com> nullvariable <nullvariable@gmail.com> nyordanov <me@nyordanov.com> ocean90 <dominikschilling+git@gmail.com> oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> +phh <phh@peytz.dk> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> +rodrigoprimo <rodrigosprimo@gmail.com> rodrigoprimo <rodrigo@hacklab.com.br> roelven <roel@soundcloud.com> ryanduff <ryan@fusionized.com> sboisvert <stephane.boisvert@automattic.com> +scribu <mail@scribu.net> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> sibprogrammer <ayuzhakov@parallels.com> @@ -91,5 +99,6 @@ twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> +willmot <tom@humanmade.co.uk> wopr42 <john@zippykid.com> ziz <justin@crowdfavorite.com> From a17fa6f1ad9ba79446bada40abf00b521260f0ec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 11 Sep 2014 17:49:44 -0700 Subject: [PATCH 3204/5359] Version bump --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index c0a45246e..28fe469ca 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.16.0' ); +define( 'WP_CLI_VERSION', '0.17.0' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 366eb4e1ad4b5f23c6b57101deaa861a79103bfa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 17 Sep 2014 06:47:38 -0700 Subject: [PATCH 3205/5359] URL hacking to easily transform production to local See #1232 --- php/commands/search-replace.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d62d54dce..52ffbeaa1 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -48,6 +48,9 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run + * + * # Turn your production database into a local database + * wp search-replace --url=example.com example.com example.dev */ public function __invoke( $args, $assoc_args ) { global $wpdb; From 55b9731b902b03717ec64b2b4567d7aff2b26d70 Mon Sep 17 00:00:00 2001 From: William Turrell <william@wturrell.co.uk> Date: Fri, 12 Sep 2014 21:06:26 +0000 Subject: [PATCH 3206/5359] fix blank response for wp comment list --format-ids --- php/commands/comment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index b490c902c..b1ed1a630 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -169,7 +169,7 @@ public function list_( $_, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); if ( 'ids' == $formatter->format ) - $assoc_args['fields'] = 'ids'; + $assoc_args['fields'] = 'comment_ID'; $query = new WP_Comment_Query(); $comments = $query->query( $assoc_args ); From f4701db287dee07958cb413661a7aaf49504038d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 16 Sep 2014 22:24:27 +0200 Subject: [PATCH 3207/5359] adding functional tests --- features/comment.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 1451e7906..8d2a44518 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -55,6 +55,12 @@ Feature: Manage WordPress comments 1 """ + When I run `wp comment list --format=ids` + Then STDOUT should be: + """ + 1 + """ + When I run `wp comment url 1` Then STDOUT should be: """ From 0456b68dfd63d887c23ae9ed19120add46bbfe95 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 17 Sep 2014 18:59:26 -0700 Subject: [PATCH 3208/5359] Force https when accessing WordPress.org WordPress.org started redirecting to https anyway. Sometimes WordPress.org APIs return http though. --- php/WP_CLI/CommandWithUpgrade.php | 4 ++++ php/commands/core.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 0ce9d34e9..982cbee27 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -167,6 +167,10 @@ protected static function alter_api_response( $response, $version ) { if ( $response->version == $version ) return; + // WordPress.org forces https, but still sometimes returns http + // See https://twitter.com/nacin/status/512362694205140992 + $response->download_link = str_replace( 'http://', 'https://', $response->download_link ); + list( $link ) = explode( $response->slug, $response->download_link ); if ( false !== strpos( $response->download_link, 'theme' ) ) diff --git a/php/commands/core.php b/php/commands/core.php index 548476d90..aa3139a00 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -35,7 +35,7 @@ function check_update( $_, $assoc_args ) { $versions_path = ABSPATH . 'wp-includes/version.php'; include $versions_path; - $url = 'http://api.wordpress.org/core/stable-check/1.0/'; + $url = 'https://api.wordpress.org/core/stable-check/1.0/'; $options = array( 'timeout' => 30 From 87ae8886db79a38eb13a5585c57956d89a261fd9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 19 Sep 2014 15:21:54 -0300 Subject: [PATCH 3209/5359] skip parameter check when calling help command --- features/help.feature | 7 +++++++ php/WP_CLI/Dispatcher/Subcommand.php | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/features/help.feature b/features/help.feature index 994358c3f..5221c847f 100644 --- a/features/help.feature +++ b/features/help.feature @@ -15,6 +15,13 @@ Feature: Get help about WP-CLI commands When I run `wp help help` Then STDOUT should not be empty + When I run `wp post list --post_type=post --posts_per_page=5 --help` + Then STDERR should be empty + And STDOUT should contain: + """ + wp post list + """ + Scenario: Help for nonexistent commands Given a WP install diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 373ee4e61..83c87c7d2 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -248,8 +248,10 @@ private function validate_args( $args, $assoc_args, $extra_args ) { array_merge( \WP_CLI::get_config(), $extra_args, $assoc_args ) ); - foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { - $errors['fatal'][] = "unknown --$key parameter"; + if ( $this->name != 'help' ) { + foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { + $errors['fatal'][] = "unknown --$key parameter"; + } } if ( !empty( $errors['fatal'] ) ) { From 468c57f3c369a45d962eaddd85a56a69ccf2253c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 19 Sep 2014 22:41:02 -0300 Subject: [PATCH 3210/5359] add --activate param to `wp core language install --activate` --- features/core.feature | 9 +++++++++ php/WP_CLI/CommandWithTranslation.php | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/features/core.feature b/features/core.feature index 3e59a8c5a..1c08fba6c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -453,3 +453,12 @@ Feature: Manage WordPress installation """ Error: Language not installed. """ + + When I run `wp core language install --activate en_GB` + Then the wp-content/languages/admin-en_GB.po file should exist + And the wp-content/languages/en_GB.po file should exist + And STDOUT should be: + """ + Success: Language installed. + Success: Language activated. + """ \ No newline at end of file diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 36ca451a2..48c93d67b 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -73,6 +73,9 @@ public function list_( $args, $assoc_args ) { * <language> * : Language code to install. * + * [--activate] + * : If set, the language will be activated immediately after install. + * * @subcommand install */ public function install( $args, $assoc_args ) { @@ -91,6 +94,10 @@ public function install( $args, $assoc_args ) { $response = wp_download_language_pack( $language_code ); if ( $response == $language_code ) { \WP_CLI::success( "Language installed." ); + + if ( isset( $assoc_args['activate'] ) ) { + $this->activate( array( $language_code ), array() ); + } } else { \WP_CLI::error( "Couldn't install language." ); } From 85d50bb63ceb62d9e01759c42b3ac4a146692326 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 19 Sep 2014 23:33:42 -0300 Subject: [PATCH 3211/5359] add en_US to the list of languages --- features/core.feature | 9 +++++---- php/WP_CLI/CommandWithTranslation.php | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index 3e59a8c5a..4ca86a9d2 100644 --- a/features/core.feature +++ b/features/core.feature @@ -395,10 +395,11 @@ Feature: Manage WordPress installation When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_GB | English (UK) | uninstalled | + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_US | English (United States) | active | + | en_GB | English (UK) | uninstalled | When I run `wp core language install en_GB` Then the wp-content/languages/admin-en_GB.po file should exist diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 36ca451a2..c8d5419a2 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -51,6 +51,17 @@ public function list_( $args, $assoc_args ) { $response = translations_api( $this->obj_type ); $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); + + $en_us = array( + 'language' => 'en_US', + 'english_name' => 'English (United States)', + 'native_name' => 'English (United States)', + 'status' => ( empty( $current_locale ) ) ? 'active' : 'installed', + ); + + array_push( $translations, $en_us ); + uasort( $translations, array( $this, '_sort_translations_callback' ) ); + $available = wp_get_installed_translations( $this->obj_type ); $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); $current_locale = get_locale(); @@ -67,6 +78,13 @@ public function list_( $args, $assoc_args ) { } + /** + * Callback to sort array by a 'language' key. + */ + protected function _sort_translations_callback( $a, $b ) { + return strnatcasecmp( $a['language'], $b['language'] ); + } + /** * Install a given language. * From 8b4d2b1e948413a53474e92635fcb65b6652d09d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 19 Sep 2014 23:58:14 -0300 Subject: [PATCH 3212/5359] make it possible to activate en_US language --- features/core.feature | 14 ++++++ php/WP_CLI/CommandWithTranslation.php | 70 ++++++++++++++++++--------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/features/core.feature b/features/core.feature index 4ca86a9d2..b2f1c68aa 100644 --- a/features/core.feature +++ b/features/core.feature @@ -435,6 +435,20 @@ Feature: Manage WordPress installation | az | Azerbaijani | uninstalled | | en_GB | English (UK) | active | + When I run `wp core language activate en_US` + Then STDOUT should be: + """ + Success: Language activated. + """ + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | en_US | English (United States) | active | + | en_GB | English (UK) | installed | + + When I try `wp core language activate invalid_lang` Then STDERR should be: """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index c8d5419a2..d4b7bc5ac 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -47,23 +47,9 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { */ public function list_( $args, $assoc_args ) { - require_once ABSPATH . '/wp-admin/includes/translation-install.php'; - - $response = translations_api( $this->obj_type ); - $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); - - $en_us = array( - 'language' => 'en_US', - 'english_name' => 'English (United States)', - 'native_name' => 'English (United States)', - 'status' => ( empty( $current_locale ) ) ? 'active' : 'installed', - ); + $translations = $this->_get_all_languages(); + $available = $this->_get_installed_languages(); - array_push( $translations, $en_us ); - uasort( $translations, array( $this, '_sort_translations_callback' ) ); - - $available = wp_get_installed_translations( $this->obj_type ); - $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); $current_locale = get_locale(); $translations = array_map( function( $translation ) use ( $available, $current_locale ) { $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; @@ -97,8 +83,8 @@ public function install( $args, $assoc_args ) { list( $language_code ) = $args; - $available = wp_get_installed_translations( $this->obj_type ); - $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + $available = $this->_get_installed_languages(); + if ( in_array( $language_code, $available ) ) { \WP_CLI::warning( "Language already installed." ); exit; @@ -127,16 +113,56 @@ public function activate( $args, $assoc_args ) { list( $language_code ) = $args; - $available = wp_get_installed_translations( $this->obj_type ); - $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + $available = $this->_get_installed_languages(); + if ( ! in_array( $language_code, $available ) ) { \WP_CLI::error( "Language not installed." ); } + if ( $language_code == 'en_US' ) { + $language_code = ''; + } + update_option( 'WPLANG', $language_code ); \WP_CLI::success( "Language activated." ); } + /** + * Return a list of installed languages. + * + * @return array + */ + protected function _get_installed_languages() { + $available = wp_get_installed_translations( $this->obj_type ); + $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + $available[] = 'en_US'; + + return $available; + } + + /** + * Return a list of all languages + * + * @return array + */ + protected function _get_all_languages() { + require_once ABSPATH . '/wp-admin/includes/translation-install.php'; + + $response = translations_api( $this->obj_type ); + $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); + + $en_us = array( + 'language' => 'en_US', + 'english_name' => 'English (United States)', + 'native_name' => 'English (United States)', + ); + + array_push( $translations, $en_us ); + uasort( $translations, array( $this, '_sort_translations_callback' ) ); + + return $translations; + } + /** * Uninstall a given language. * @@ -150,8 +176,8 @@ public function uninstall( $args, $assoc_args ) { list( $language_code ) = $args; - $available = wp_get_installed_translations( $this->obj_type ); - $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); + $available = $this->_get_installed_languages(); + if ( ! in_array( $language_code, $available ) ) { \WP_CLI::error( "Language not installed." ); } From 489458a0f00a9ed2b5e53e92cf9c4558c7614b8f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sat, 20 Sep 2014 12:34:44 -0300 Subject: [PATCH 3213/5359] Add functionality to filter list of languages --- features/core.feature | 9 +++++++++ php/WP_CLI/CommandWithTranslation.php | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index b2f1c68aa..c9c55b24a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -468,3 +468,12 @@ Feature: Manage WordPress installation """ Error: Language not installed. """ + + When I run `wp core language list --fields=language,english_name,status --status=active` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | en_US | English (United States) | active | + And STDOUT should not contain: + """ + English (UK) + """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index d4b7bc5ac..57fc3a503 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -22,6 +22,9 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { /** * List all languages available. * + * [--<field>=<value>] + * : Filter results based on the value of a field. + * * [--fields=<fields>] * : Limit the output to specific fields. * @@ -56,12 +59,20 @@ public function list_( $args, $assoc_args ) { if ( $current_locale == $translation['language'] ) { $translation['status'] = 'active'; } + return $translation; }, $translations ); + foreach ( $translations as $key => $translation ) { + foreach ( $this->obj_fields as $field ) { + if ( isset( $assoc_args[$field] ) && $assoc_args[$field] != $translation[$field] ) { + unset( $translations[$key] ); + } + } + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $translations ); - } /** From 3e459a9d04b167e99cae65b0f702f60a925f5b90 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sat, 20 Sep 2014 12:38:47 -0300 Subject: [PATCH 3214/5359] add missing new line at end of file --- features/core.feature | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 1c08fba6c..4d063f7de 100644 --- a/features/core.feature +++ b/features/core.feature @@ -461,4 +461,5 @@ Feature: Manage WordPress installation """ Success: Language installed. Success: Language activated. - """ \ No newline at end of file + """ + From 1a571218f1a2a195b2311f5ff46d59176f9f74d7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sat, 20 Sep 2014 17:00:15 -0300 Subject: [PATCH 3215/5359] remove empty line added by mistake --- php/WP_CLI/CommandWithTranslation.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 57fc3a503..810362161 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -59,7 +59,6 @@ public function list_( $args, $assoc_args ) { if ( $current_locale == $translation['language'] ) { $translation['status'] = 'active'; } - return $translation; }, $translations ); From 6952bc4b859655afb46cd679ab60998180224aed Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Sep 2014 11:45:25 -0300 Subject: [PATCH 3216/5359] improve test for `wp core language --<field>=<value>` --- features/core.feature | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index c9c55b24a..2ac94a4d7 100644 --- a/features/core.feature +++ b/features/core.feature @@ -473,7 +473,9 @@ Feature: Manage WordPress installation Then STDOUT should be a table containing rows: | language | english_name | status | | en_US | English (United States) | active | - And STDOUT should not contain: + + When I run `wp core language list --fields=language,english_name,status --status=active | wc -l` + Then STDOUT should be: """ - English (UK) + 2 """ From b4477a4bb05c6f0b58955cb81f3ba06fb8e31ad4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Sep 2014 11:49:16 -0300 Subject: [PATCH 3217/5359] remove underscores from methods names --- php/WP_CLI/CommandWithTranslation.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 810362161..a93361a52 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -50,8 +50,8 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { */ public function list_( $args, $assoc_args ) { - $translations = $this->_get_all_languages(); - $available = $this->_get_installed_languages(); + $translations = $this->get_all_languages(); + $available = $this->get_installed_languages(); $current_locale = get_locale(); $translations = array_map( function( $translation ) use ( $available, $current_locale ) { @@ -77,7 +77,7 @@ public function list_( $args, $assoc_args ) { /** * Callback to sort array by a 'language' key. */ - protected function _sort_translations_callback( $a, $b ) { + protected function sort_translations_callback( $a, $b ) { return strnatcasecmp( $a['language'], $b['language'] ); } @@ -93,7 +93,7 @@ public function install( $args, $assoc_args ) { list( $language_code ) = $args; - $available = $this->_get_installed_languages(); + $available = $this->get_installed_languages(); if ( in_array( $language_code, $available ) ) { \WP_CLI::warning( "Language already installed." ); @@ -123,7 +123,7 @@ public function activate( $args, $assoc_args ) { list( $language_code ) = $args; - $available = $this->_get_installed_languages(); + $available = $this->get_installed_languages(); if ( ! in_array( $language_code, $available ) ) { \WP_CLI::error( "Language not installed." ); @@ -142,7 +142,7 @@ public function activate( $args, $assoc_args ) { * * @return array */ - protected function _get_installed_languages() { + protected function get_installed_languages() { $available = wp_get_installed_translations( $this->obj_type ); $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); $available[] = 'en_US'; @@ -155,7 +155,7 @@ protected function _get_installed_languages() { * * @return array */ - protected function _get_all_languages() { + protected function get_all_languages() { require_once ABSPATH . '/wp-admin/includes/translation-install.php'; $response = translations_api( $this->obj_type ); @@ -168,7 +168,7 @@ protected function _get_all_languages() { ); array_push( $translations, $en_us ); - uasort( $translations, array( $this, '_sort_translations_callback' ) ); + uasort( $translations, array( $this, 'sort_translations_callback' ) ); return $translations; } @@ -186,7 +186,7 @@ public function uninstall( $args, $assoc_args ) { list( $language_code ) = $args; - $available = $this->_get_installed_languages(); + $available = $this->get_installed_languages(); if ( ! in_array( $language_code, $available ) ) { \WP_CLI::error( "Language not installed." ); From 57ffd7afb9cf25c60060ffd03901953149b258c3 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Sep 2014 12:00:21 -0300 Subject: [PATCH 3218/5359] remove unecessary check --- features/help.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index 5221c847f..dff1de523 100644 --- a/features/help.feature +++ b/features/help.feature @@ -16,7 +16,6 @@ Feature: Get help about WP-CLI commands Then STDOUT should not be empty When I run `wp post list --post_type=post --posts_per_page=5 --help` - Then STDERR should be empty And STDOUT should contain: """ wp post list From 4d95eb6467234b2fe72bba82b976e4150683a29e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Sep 2014 14:35:58 -0300 Subject: [PATCH 3219/5359] typo --- features/help.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index dff1de523..4e48d26af 100644 --- a/features/help.feature +++ b/features/help.feature @@ -16,7 +16,7 @@ Feature: Get help about WP-CLI commands Then STDOUT should not be empty When I run `wp post list --post_type=post --posts_per_page=5 --help` - And STDOUT should contain: + Then STDOUT should contain: """ wp post list """ From 1321638d324aa0be4759c4910d3acc0b08cea2ba Mon Sep 17 00:00:00 2001 From: Tiago Hillebrandt <tiagohillebrandt@ubuntu.com> Date: Mon, 22 Sep 2014 21:14:03 -0500 Subject: [PATCH 3220/5359] Implements the enable all plugins function. --- php/commands/plugin.php | 66 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e33d27097..d69180368 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -132,29 +132,36 @@ protected function get_all_items() { * * ## OPTIONS * - * <plugin>... + * [<plugin>...] * : One or more plugins to activate. * + * [--all] + * : If set, all plugins will be activated. + * * [--network] * : If set, the plugin will be activated for the entire multisite network. */ function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); + $enable_all = isset( $assoc_args['all'] ); - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - - $status = $this->get_status( $plugin->file ); - if ( ! $network_wide && 'active' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); - continue; - } else if ( $network_wide && 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); - continue; - } + if ( $enable_all ) { + $this->update_plugins_status( "activate", $network_wide ); + } else { + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + $status = $this->get_status( $plugin->file ); + if ( ! $network_wide && 'active' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); + continue; + } else if ( $network_wide && 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); + continue; + } - activate_plugin( $plugin->file, '', $network_wide ); + activate_plugin( $plugin->file, '', $network_wide ); - $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); + $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); + } } } @@ -177,16 +184,7 @@ function deactivate( $args, $assoc_args = array() ) { $disable_all = isset( $assoc_args['all'] ); if ( $disable_all ) { - foreach ( get_plugins() as $file => $details ) { - if ( $this->get_status( $file ) == "inactive" ) - continue; - - $name = Utils\get_plugin_name( $file ); - - deactivate_plugins( $file, false, $network_wide ); - - $this->active_output( $name, $file, $network_wide, "deactivate" ); - } + $this->update_plugins_status( "deactivate", $network_wide ); } else { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { deactivate_plugins( $plugin->file, false, $network_wide ); @@ -357,7 +355,7 @@ protected function filter_item_list( $items, $args ) { * * [--activate] * : If set, the plugin will be activated immediately after install. - * + * * [--activate-network] * : If set, the plugin will be network activated immediately after install * @@ -561,6 +559,25 @@ private function active_output( $name, $file, $network_wide, $action ) { } } + /** + * Enable or disable all plugins. + */ + private function update_plugins_status( $action, $network_wide ) { + $status = ( $action == "activate" ) ? "active" : "inactive"; + foreach ( get_plugins() as $file => $details ) { + if ( $this->get_status( $file ) == $status ) + continue; + + if ( $action == "activate" ) + activate_plugins( $file, false, $network_wide ); + else + deactivate_plugins( $file, false, $network_wide ); + + $name = Utils\get_plugin_name( $file ); + $this->active_output( $name, $file, $network_wide, $action ); + } + } + protected function get_status( $file ) { if ( is_plugin_active_for_network( $file ) ) return 'active-network'; @@ -603,4 +620,3 @@ private function _delete( $plugin ) { } WP_CLI::add_command( 'plugin', 'Plugin_Command' ); - From 37f662a997ff416a48f29600e84291195b1c7e2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 25 Sep 2014 10:34:03 -0700 Subject: [PATCH 3221/5359] Wrap `new DateTime` with try{ } catch() {} It can trigger an Exception if `date.timezone` isn't set --- php/WP_CLI/FileCache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/FileCache.php b/php/WP_CLI/FileCache.php index 6fb0af3d7..623807007 100644 --- a/php/WP_CLI/FileCache.php +++ b/php/WP_CLI/FileCache.php @@ -220,7 +220,11 @@ public function clean() { // unlink expired files if ( $ttl > 0 ) { - $expire = new \DateTime(); + try { + $expire = new \DateTime(); + } catch ( \Exception $e ) { + \WP_CLI::error( $e->getMessage() ); + } $expire->modify( '-' . $ttl . ' seconds' ); $finder = $this->get_finder()->date( 'until ' . $expire->format( 'Y-m-d H:i:s' ) ); From bf6bc5efcaf5b52c6f5bfaca18c148c382d88358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 25 Sep 2014 22:36:44 +0200 Subject: [PATCH 3222/5359] Add option list subcommand. --- php/commands/option.php | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index 962ef03ce..087d1d1e0 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -77,6 +77,81 @@ public function add( $args, $assoc_args ) { } } + /** + * List options. + * + * [--search=<sql-like-pattern>] + * : SQL pattern matching enables you to use "_" to match any single character and "%" to match an arbitrary number of characters. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. + * + * [--autoload] + * : Match only autoload options. + * + * [--total] + * : Display only the total size of matching options. + * + * [--format=<format>] + * : The serialization format for the value. Default is table. + * + * ## AVAILABLE FIELDS + * + * This field will be displayed by default for each matching option: + * + * * option_name + * + * These fields are optionally available: + * + * * option_name + * * autoload + * * size + * + * @subcommand list + * @synopsis [--search=<sql-like-pattern>] [--total] [--autoload] [--fields=<fields>] [--format=<format>] + */ + public function list_( $args, $assoc_args ) { + + global $wpdb; + $size_query = "LENGTH(option_value) AS size"; + $autoload_query = ''; + + if ( isset( $assoc_args['search'] ) ) { + $pattern = $assoc_args['search']; + } else { + $pattern = '%'; + } + + if ( isset( $assoc_args['fields'] ) ) { + $fields = explode( ',', $assoc_args['fields'] ); + } else { + $fields = array( 'option_name' ); + } + + if ( isset( $assoc_args['total'] ) ) { + $fields = array( 'size' ); + $size_query = "SUM(LENGTH(option_value)) AS size"; + } + + if ( isset( $assoc_args['autoload'] ) ) { + $autoload_query = " AND autoload='yes'"; + } + + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT option_name,option_value,autoload," . $size_query + . " FROM $wpdb->options WHERE option_name LIKE %s" . $autoload_query, + $pattern + ) + ); + + $formatter = new \WP_CLI\Formatter( + $assoc_args, + $fields + ); + $formatter->display_items( $results ); + } + /** * Update an option. * From 66ac9908c494ae0d192ea650decac8a18b64a416 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 06:06:16 -0700 Subject: [PATCH 3223/5359] WPorg API returns names with HTML entities. We can decode for CLI. --- features/plugin.feature | 9 +++++++++ php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 0d582808f..41823ad30 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -233,3 +233,12 @@ Feature: Manage WordPress plugins """ Warning: Plugin 'akismet' is already network active. """ + + Scenario: Plugin name with HTML entities + Given a WP install + + When I run `wp plugin install debug-bar-list-dependencies` + Then STDOUT should contain: + """ + Installing Debug Bar List Script & Style Dependencies + """ diff --git a/php/commands/plugin.php b/php/commands/plugin.php index e33d27097..118d976e5 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -268,7 +268,7 @@ protected function install_from_repo( $slug, $assoc_args ) { return new WP_Error( 'already_installed', 'Plugin already installed.' ); } - WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name ), $api->version ) ); if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index c7eee76e4..94b73e54b 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -283,7 +283,7 @@ protected function install_from_repo( $slug, $assoc_args ) { return new WP_Error( 'already_installed', 'Theme already installed.' ); } - WP_CLI::log( sprintf( 'Installing %s (%s)', $api->name, $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name ), $api->version ) ); if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } From 9bd35fb54affda982d55146f1c922d4ea34b0262 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 06:16:23 -0700 Subject: [PATCH 3224/5359] Sniff out the custom vendor path if we're a part of a Composer project --- php/utils.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index fbee550ac..77d0d9817 100644 --- a/php/utils.php +++ b/php/utils.php @@ -30,10 +30,18 @@ function load_dependencies() { } function get_vendor_paths() { - return array( + $vendor_paths = array( WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone ); + $maybe_composer_json = WP_CLI_ROOT . '/../../../composer.json'; + if ( file_exists( $maybe_composer_json ) && is_readable( $maybe_composer_json ) ) { + $composer = json_decode( file_get_contents( $maybe_composer_json ) ); + if ( ! empty( $composer->{'vendor-dir'} ) ) { + array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->{'vendor-dir'} ); + } + } + return $vendor_paths; } // Using require() directly inside a class grants access to private methods to the loaded code From b5a2cd7d99616141e469fc4a72b8f7de12c03702 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 06:35:19 -0700 Subject: [PATCH 3225/5359] PHP magic methods, except `__invoke()`, aren't valid WP-CLI commands PHP reserves `__` prefix for magic methods. Don't use function names starting with `__` unless you're using magic methods. --- features/help.feature | 47 ++++++++++++++++++++++++ php/WP_CLI/Dispatcher/CommandFactory.php | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index 994358c3f..d84be1c55 100644 --- a/features/help.feature +++ b/features/help.feature @@ -70,3 +70,50 @@ Feature: Get help about WP-CLI commands """ usage: wp core """ + + Scenario: Help for commands with magic methods + Given a WP install + And a wp-content/plugins/test-cli/command.php file: + """ + <?php + // Plugin Name: Test CLI Help + + class Test_Magic_Methods extends WP_CLI_Command { + /** + * A dummy command. + * + * @subcommand my-command + */ + function my_command() {} + + /** + * Magic methods should not appear as commands + */ + function __construct() {} + function __destruct() {} + function __call( $name, $arguments ) {} + function __get( $key ) {} + function __set( $key, $value ) {} + function __isset( $key ) {} + function __unset( $key ) {} + function __sleep() {} + function __wakeup() {} + function __toString() {} + function __set_state() {} + function __clone() {} + function __debugInfo() {} + } + + WP_CLI::add_command( 'test-magic-methods', 'Test_Magic_Methods' ); + """ + And I run `wp plugin activate test-cli` + + When I run `wp test-magic-methods` + Then STDOUT should contain: + """ + usage: wp test-magic-methods my-command + """ + And STDOUT should not contain: + """ + __destruct + """ diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index 2bc884e01..b4f941dd0 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -88,7 +88,7 @@ private static function create_composite_command( $parent, $name, $reflection ) * @return bool */ private static function is_good_method( $method ) { - return $method->isPublic() && !$method->isConstructor() && !$method->isStatic(); + return $method->isPublic() && !$method->isStatic() && 0 !== strpos( $method->getName(), '__' ); } } From 1dcc78f3d43db09ad9a2e863133b814fdd3a58c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 06:47:12 -0700 Subject: [PATCH 3226/5359] Limit `wp core language list` output by fields --- features/core.feature | 6 ++++++ php/WP_CLI/CommandWithTranslation.php | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/features/core.feature b/features/core.feature index 3e59a8c5a..1f77dfcc6 100644 --- a/features/core.feature +++ b/features/core.feature @@ -427,6 +427,12 @@ Feature: Manage WordPress installation Success: Language activated. """ + When I run `wp core language list --field=language --status=active` + Then STDOUT should be: + """ + en_GB + """ + When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: | language | english_name | status | diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 36ca451a2..ba9192b91 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -22,6 +22,12 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { /** * List all languages available. * + * [--field=<field>] + * : Display the value of a single field + * + * [--<field>=<value>] + * : Filter results by key=value pairs. + * * [--fields=<fields>] * : Limit the output to specific fields. * @@ -62,6 +68,16 @@ public function list_( $args, $assoc_args ) { return $translation; }, $translations ); + foreach( $translations as $key => $translation ) { + + $fields = array_keys( $translation ); + foreach( $fields as $field ) { + if ( isset( $assoc_args[ $field ] ) && $assoc_args[ $field ] != $translation[ $field ] ) { + unset( $translations[ $key ] ); + } + } + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $translations ); From 401b9975743d2dff84b7825cf3e2c309aa68f7af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 09:05:30 -0700 Subject: [PATCH 3227/5359] Formatter: Gracefully handle items with objects / arrays as values We've been preflighting the data to `json_encode()` each time. This is unnecessary. --- php/WP_CLI/CommandWithMeta.php | 4 ---- php/WP_CLI/Formatter.php | 22 +++++++++++++++++++++- php/commands/cron.php | 7 ------- php/commands/menu.php | 3 --- php/commands/widget.php | 6 ------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 2f3d7b49c..7b54511a1 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -51,10 +51,6 @@ public function list_( $args, $assoc_args ) { $item_value = maybe_unserialize( $item_value ); - if ( ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv' ) ) )&& ( is_object( $item_value ) || is_array( $item_value ) ) ) { - $item_value = json_encode( $item_value ); - } - $items[] = (object) array( "{$this->meta_type}_id" => $object_id, 'meta_key' => $key, diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index cd9717a7d..ac1bc24d2 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -72,6 +72,22 @@ public function display_items( $items ) { array_unshift( $items, $item ); } } + + if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) ) { + $items = array_map( function( $item ){ + foreach( (array)$item as $key => $value ) { + if ( is_array( $value ) || is_object( $value ) ) { + if ( is_object( $item ) ) { + $item->$key = json_encode( $value ); + } else if ( is_array( $item ) ) { + $item[ $key ] = json_encode( $value ); + } + } + } + return $item; + }, $items ); + } + $this->format( $items ); } } @@ -85,7 +101,11 @@ public function display_item( $item ) { if ( isset( $this->args['field'] ) ) { $item = (object) $item; $key = $this->find_item_key( $item, $this->args['field'] ); - \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); + $value = $item->$key; + if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) && ( is_object( $value ) || is_array( $value ) ) ) { + $value = json_encode( $value ); + } + \WP_CLI::print_value( $value, array( 'format' => $this->args['format'] ) ); } else { self::show_multiple_fields( $item, $this->args['format'] ); } diff --git a/php/commands/cron.php b/php/commands/cron.php index 0b9854d5c..c34079228 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -58,13 +58,6 @@ public function list_( $args, $assoc_args ) { $events = array(); } - if ( in_array( $formatter->format, array( 'table', 'csv' ) ) ) { - $events = array_map( function( $event ){ - $event->args = json_encode( $event->args ); - return $event; - }, $events ); - } - if ( 'ids' == $formatter->format ) { echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); } else { diff --git a/php/commands/menu.php b/php/commands/menu.php index f71f9dbda..0277cbba0 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -236,9 +236,6 @@ public function list_( $args, $assoc_args ) { $items = array_map( function( $item ) use ( $assoc_args ) { $item->position = $item->menu_order; $item->link = $item->url; - if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'json' ) ) ) { - $item->classes = json_encode( $item->classes ); - } return $item; }, $items ); diff --git a/php/commands/widget.php b/php/commands/widget.php index 19c9568d4..af8a0a88d 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -64,12 +64,6 @@ public function list_( $args, $assoc_args ) { $output_widgets = $this->get_sidebar_widgets( $sidebar_id ); - if ( empty( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'table', 'csv') ) ) { - foreach( $output_widgets as &$output_widget ) { - $output_widget->options = json_encode( $output_widget->options ); - } - } - if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { $output_widgets = wp_list_pluck( $output_widgets, 'id' ); } From 0b729355e905cb561d2dd0d5ea80987f6b384142 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 10:13:55 -0700 Subject: [PATCH 3228/5359] `wp <object> get` should support limiting output based off `--fields` Adds support to `wp post`, `wp comment`, and `wp term`. `wp user` already had it. Unlike `wp <object> list`, `* get` defaults to all object fields. Adds `--format=csv` to `* get` as well. --- features/comment.feature | 6 ++++++ features/post.feature | 8 +++++++ features/term.feature | 8 ++++++- php/WP_CLI/CommandWithDBObject.php | 12 ++++++++++- php/WP_CLI/Formatter.php | 34 +++++++++++++++++++++++++----- php/commands/comment.php | 13 ++++++++++-- php/commands/post.php | 9 +++++++- php/commands/term.php | 15 ++++++++++--- php/commands/user.php | 2 +- 9 files changed, 93 insertions(+), 14 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 8d2a44518..94aeb9d9b 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -44,6 +44,12 @@ Feature: Manage WordPress comments | Field | Value | | comment_author | Mr WordPress | + When I run `wp comment get 1 --fields=comment_author,comment_author_email --format=json` + Then STDOUT should be: + """ + {"comment_author":"Mr WordPress","comment_author_email":""} + """ + When I run `wp comment list --fields=comment_approved,comment_author` Then STDOUT should be a table containing rows: | comment_approved | comment_author | diff --git a/features/post.feature b/features/post.feature index 1ff2128fe..1d297a9ec 100644 --- a/features/post.feature +++ b/features/post.feature @@ -60,6 +60,14 @@ Feature: Manage WordPress posts | Field | Value | | ID | {POST_ID} | | post_title | Test post | + | post_name | | + | post_type | post | + + When I run `wp post get {POST_ID} --format=csv --fields=post_title,type | wc -l` + Then STDOUT should be: + """ + 3 + """ When I run `wp post get --format=json {POST_ID}` Then STDOUT should be JSON containing: diff --git a/features/term.feature b/features/term.feature index 2dc2d3d05..6bcf63720 100644 --- a/features/term.feature +++ b/features/term.feature @@ -43,13 +43,19 @@ Feature: Manage WordPress terms | term_id | {TERM_ID} | | name | Test term | + When I run `wp term get post_tag {TERM_ID} --format=csv --fields=name,taxonomy` + Then STDOUT should be CSV containing: + | Field | Value | + | name | Test term | + | taxonomy | post_tag | + Scenario: Creating/deleting a term When I run `wp term create post_tag 'Test delete term' --slug=test-delete --description='This is a test term to be deleted' --porcelain` Then STDOUT should be a number And save STDOUT as {TERM_ID} When I run `wp term get post_tag {TERM_ID} --field=slug --format=json` - Then STDOUT should contain: + Then STDOUT should be: """ "test-delete" """ diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 90adb0933..8a52bfc92 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -134,7 +134,17 @@ protected function success_or_failure( $r ) { * @return \WP_CLI\Formatter */ protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); + + if ( ! empty( $assoc_args['fields'] ) ) { + if ( is_string( $assoc_args['fields'] ) ) { + $fields = explode( ',', $assoc_args['fields'] ); + } else { + $fields = $assoc_args['fields']; + } + } else { + $fields = $this->obj_fields; + } + return new \WP_CLI\Formatter( $assoc_args, $fields, $this->obj_type ); } /** diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index cd9717a7d..d38db2b8f 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -87,7 +87,7 @@ public function display_item( $item ) { $key = $this->find_item_key( $item, $this->args['field'] ); \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); } else { - self::show_multiple_fields( $item, $this->args['format'] ); + $this->show_multiple_fields( $item, $this->args['format'] ); } } @@ -194,12 +194,34 @@ private function find_item_key( $item, $field ) { * @param object|array Data to display * @param string Format to display the data in */ - private static function show_multiple_fields( $data, $format ) { + private function show_multiple_fields( $data, $format ) { + + $true_fields = array(); + foreach( $this->args['fields'] as $field ) { + $true_fields[] = $this->find_item_key( $data, $field ); + } + + foreach( $data as $key => $value ) { + if ( ! in_array( $key, $true_fields ) ) { + if ( is_array( $data ) ) { + unset( $data[ $key ] ); + } else if ( is_object( $data ) ) { + unset( $data->$key ); + } + } + } switch ( $format ) { case 'table': - self::assoc_array_to_table( $data ); + case 'csv': + $rows = $this->assoc_array_to_rows( $data ); + $fields = array( 'Field', 'Value' ); + if ( 'table' == $format ) { + self::show_table( $rows, $fields ); + } else if ( 'csv' == $format ) { + \WP_CLI\Utils\write_csv( STDOUT, $rows, $fields ); + } break; case 'json': @@ -236,11 +258,13 @@ private static function show_table( $items, $fields ) { * Format an associative array as a table. * * @param array $fields Fields and values to format + * @return array $rows */ - private static function assoc_array_to_table( $fields ) { + private function assoc_array_to_rows( $fields ) { $rows = array(); foreach ( $fields as $field => $value ) { + if ( ! is_string( $value ) ) { $value = json_encode( $value ); } @@ -251,7 +275,7 @@ private static function assoc_array_to_table( $fields ) { ); } - self::show_table( $rows, array( 'Field', 'Value' ) ); + return $rows; } } diff --git a/php/commands/comment.php b/php/commands/comment.php index b1ed1a630..cdf7641d4 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -98,8 +98,11 @@ public function update( $args, $assoc_args ) { * [--field=<field>] * : Instead of returning the whole comment, returns the value of a single field. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv. Default: table * * ## EXAMPLES * @@ -108,8 +111,14 @@ public function update( $args, $assoc_args ) { public function get( $args, $assoc_args ) { $comment_id = (int)$args[0]; $comment = get_comment( $comment_id ); - if ( empty( $comment ) ) + if ( empty( $comment ) ) { WP_CLI::error( "Invalid comment ID." ); + } + + if ( empty( $assoc_args['fields'] ) ) { + $comment_array = get_object_vars( $comment ); + $assoc_args['fields'] = array_keys( $comment_array ); + } $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $comment ); diff --git a/php/commands/post.php b/php/commands/post.php index fdd0203f0..69784641f 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -145,8 +145,11 @@ protected function _edit( $content, $title ) { * [--field=<field>] * : Instead of returning the whole post, returns the value of a single field. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv. Default: table * * ## EXAMPLES * @@ -159,6 +162,10 @@ public function get( $args, $assoc_args ) { $post_arr = get_object_vars( $post ); unset( $post_arr['filter'] ); + if ( empty( $assoc_args['fields'] ) ) { + $assoc_args['fields'] = array_keys( $post_arr ); + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $post_arr ); } diff --git a/php/commands/term.php b/php/commands/term.php index d7a35e295..8aeae04bd 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -152,21 +152,30 @@ public function create( $args, $assoc_args ) { * [--field=<field>] * : Instead of returning the whole term, returns the value of a single field. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv. Default: table * * ## EXAMPLES * * wp term get category 1 --format=json */ public function get( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); list( $taxonomy, $term_id ) = $args; $term = get_term_by( 'id', $term_id, $taxonomy ); - if ( ! $term ) + if ( ! $term ) { WP_CLI::error( "Term doesn't exist." ); + } + if ( empty( $assoc_args['fields'] ) ) { + $term_array = get_object_vars( $term ); + $assoc_args['fields'] = array_keys( $term_array ); + } + + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $term ); } diff --git a/php/commands/user.php b/php/commands/user.php index f41ea4b83..816ff3c97 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -118,7 +118,7 @@ public function list_( $args, $assoc_args ) { * : Get a specific subset of the user's fields. * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv. Default: table * * ## EXAMPLES * From 671c6e0869d751189be89eec4254d32a3fdbbd81 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 10:29:45 -0700 Subject: [PATCH 3229/5359] Safely handle supplied iterators --- php/WP_CLI/Formatter.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index ac1bc24d2..6e58e297c 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -74,7 +74,7 @@ public function display_items( $items ) { } if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) ) { - $items = array_map( function( $item ){ + $callback = function( $item ){ foreach( (array)$item as $key => $value ) { if ( is_array( $value ) || is_object( $value ) ) { if ( is_object( $item ) ) { @@ -85,7 +85,12 @@ public function display_items( $items ) { } } return $item; - }, $items ); + }; + if ( is_object( $items ) && is_a( $items, 'Iterator' ) ) { + $items = \WP_CLI\Utils\iterator_map( $items, $callback ); + } else { + $items = array_map( $callback, $items ); + } } $this->format( $items ); From d7ae0c41ae9b1fcd3f9f577222e361d548f61d6c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 10:51:49 -0700 Subject: [PATCH 3230/5359] Update post_content from a file or `STDIN` --- features/post.feature | 51 +++++++++++++++++++++++++++++++++++++++++-- php/commands/post.php | 47 ++++++++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/features/post.feature b/features/post.feature index 1ff2128fe..aa0247284 100644 --- a/features/post.feature +++ b/features/post.feature @@ -35,13 +35,13 @@ Feature: Manage WordPress posts alert('This should not be stripped.'); </script> """ - And a command.sh file: + And a create-post.sh file: """ cat content.html | wp post create --post_title='Test post' --post_excerpt="A multiline excerpt" --porcelain - """ - When I run `bash command.sh` + When I run `bash create-post.sh` Then STDOUT should be a number And save STDOUT as {POST_ID} @@ -97,6 +97,53 @@ Feature: Manage WordPress posts http://example.com/?p=3 """ + Scenario: Update a post from file or STDIN + Given a content.html file: + """ + Oh glorious CLI + """ + And a content-2.html file: + """ + Let it be the weekend + """ + + When I run `wp post create --post_title="Testing update via STDIN" --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `cat content.html | wp post update {POST_ID} -` + Then STDOUT should contain: + """ + Success: Updated post {POST_ID} + """ + + When I run `wp post get --field=post_content {POST_ID}` + Then STDOUT should be: + """ + Oh glorious CLI + """ + + When I run `wp post create --post_title="Testing update via STDIN. Again!" --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID_TWO} + + When I run `wp post update {POST_ID} {POST_ID_TWO} content-2.html` + Then STDOUT should contain: + """ + Success: Updated post {POST_ID_TWO} + """ + + When I run `wp post get --field=post_content {POST_ID_TWO}` + Then STDOUT should be: + """ + Let it be the weekend + """ + + When I try `wp post update {POST_ID} invalid-file.html` + Then STDERR should be: + """ + Error: Unable to read content from invalid-file.html. + """ Scenario: Creating/listing posts When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` diff --git a/php/commands/post.php b/php/commands/post.php index fdd0203f0..3e2d028a9 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -52,16 +52,7 @@ public function __construct() { */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { - if ( $args[0] !== '-' ) { - $readfile = $args[0]; - if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) { - \WP_CLI::error( "Unable to read content from $readfile." ); - } - } else { - $readfile = 'php://stdin'; - } - - $assoc_args['post_content'] = file_get_contents( $readfile ); + $assoc_args['post_content'] = $this->read_from_file_or_stdin( $args[0] ); } if ( isset( $assoc_args['edit'] ) ) { @@ -91,6 +82,13 @@ public function create( $args, $assoc_args ) { * <id>... * : One or more IDs of posts to update. * + * [<file>] + * : Read post content from <file>. If this value is present, the + * `--post_content` argument will be ignored. + * + * Passing `-` as the filename will cause post content to + * be read from STDIN. + * * --<field>=<value> * : One or more fields to update. See wp_update_post(). * @@ -99,6 +97,17 @@ public function create( $args, $assoc_args ) { * wp post update 123 --post_name=something --post_status=draft */ public function update( $args, $assoc_args ) { + + foreach( $args as $key => $arg ) { + if ( is_numeric( $arg ) ) { + continue; + } + + $assoc_args['post_content'] = $this->read_from_file_or_stdin( $arg ); + unset( $args[ $key ] ); + break; + } + parent::_update( $args, $assoc_args, function ( $params ) { return wp_update_post( $params, true ); } ); @@ -428,6 +437,24 @@ private function maybe_reset_depth() { // 10% chance of reseting to root depth return ( mt_rand(1, 10) == 7 ); } + + /** + * Read post content from file or STDIN + * + * @param string $arg Supplied argument + * @return string + */ + private function read_from_file_or_stdin( $arg ) { + if ( $arg !== '-' ) { + $readfile = $arg; + if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) { + \WP_CLI::error( "Unable to read content from $readfile." ); + } + } else { + $readfile = 'php://stdin'; + } + return file_get_contents( $readfile ); + } } /** From 445266dc04b1cb25b1ab49a93fee0fcd5cf7dee3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 11:06:46 -0700 Subject: [PATCH 3231/5359] Use https URLs --- features/upgradables.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 2bc9c2e06..027668c83 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -176,5 +176,5 @@ Feature: Manage WordPress themes and plugins Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | - | theme | Theme | p2 | P2 | 1.0.1 | http://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | - | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | http://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | + | theme | Theme | p2 | P2 | 1.0.1 | https://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | + | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | https://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | From 0a1e8b39282c9b04c62195f5aa91144e992d6bbb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 11:19:35 -0700 Subject: [PATCH 3232/5359] `wp theme get` and `wp plugin get` should also benefit from 0b729355e905cb561d2dd0d5ea80987f6b384142 --- php/commands/plugin.php | 10 +++++++++- php/commands/theme.php | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 118d976e5..7b3fee466 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -395,8 +395,11 @@ function install( $args, $assoc_args ) { * [--field=<field>] * : Instead of returning the whole plugin, returns the value of a single field. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] - * : Output list as table or JSON. Defaults to table. + * : Output list as table, json, CSV. Defaults to table. * * ## EXAMPLES * @@ -417,6 +420,11 @@ public function get( $args, $assoc_args ) { 'status' => $this->get_status( $file ), ); + if ( empty( $assoc_args['fields'] ) ) { + $plugin_array = get_object_vars( $plugin_obj ); + $assoc_args['fields'] = array_keys( $plugin_array ); + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $plugin_obj ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 94b73e54b..aaef43c5d 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -397,8 +397,11 @@ function install( $args, $assoc_args ) { * [--field=<field>] * : Instead of returning the whole theme, returns the value of a single field. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv. Default: table * * ## EXAMPLES * @@ -417,6 +420,10 @@ public function get( $args, $assoc_args ) { $theme_obj->description = wordwrap( $theme_obj->description ); + if ( empty( $assoc_args['fields'] ) ) { + $assoc_args['fields'] = $theme_vars; + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $theme_obj ); } From d8488b4d3e271d6fef2dbaf524cd3200c79d0124 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 13:19:54 -0700 Subject: [PATCH 3233/5359] Test that should fail for #1437 --- features/user.feature | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/features/user.feature b/features/user.feature index ddbea8ab7..336d1cae4 100644 --- a/features/user.feature +++ b/features/user.feature @@ -23,6 +23,11 @@ Feature: Manage WordPress users test """ + When I run `wp user list --fields=user_login,roles` + Then STDOUT should be a table containing rows: + | user_login | roles | + | testuser2 | author | + When I run `wp user meta get {USER_ID} last_name` Then STDOUT should be: """ From 747a73898d9dd903d3180fa13a2208e79f0c6295 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 13:21:07 -0700 Subject: [PATCH 3234/5359] Fix mangling of `wp user list` 1. Only JSON encode fields that will be displayed on output. `WP_User`'s `data` attribute was getting JSON-encoded, which meant the magic getter no longer worked. 2. Using `isset()` for object properties, instead of `property_exists()`, means we can check if magic properties are available. --- php/WP_CLI/Formatter.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 23bd528ce..cb7cfcd52 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -74,13 +74,16 @@ public function display_items( $items ) { } if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) ) { - $callback = function( $item ){ - foreach( (array)$item as $key => $value ) { + $fields = $this->args['fields']; + $callback = function( $item ) use ( $fields ) { + foreach( $fields as $field ) { + $true_field = $this->find_item_key( $item, $field ); + $value = is_object( $item ) ? $item->$true_field : $item[ $true_field ]; if ( is_array( $value ) || is_object( $value ) ) { if ( is_object( $item ) ) { - $item->$key = json_encode( $value ); + $item->$true_field = json_encode( $value ); } else if ( is_array( $item ) ) { - $item[ $key ] = json_encode( $value ); + $item[ $true_field ] = json_encode( $value ); } } } @@ -200,7 +203,7 @@ private function show_single_field( $items, $field ) { */ private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( ( is_object( $item ) && property_exists( $item, $maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { + if ( ( is_object( $item ) && isset( $item->$maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { $key = $maybe_key; break; } From 28dab1b46c480fccc0d852271eb0799aff2f5be7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 13:33:37 -0700 Subject: [PATCH 3235/5359] Increase timeout when getting download offer Helpful for low-bandwidth airplane connections --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index aa3139a00..e2625d154 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -223,7 +223,7 @@ private static function _rmdir( $dir ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - return Utils\http_request( 'GET', $url, null, $headers )->body; + return Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) )->body; } private function get_download_offer( $locale ) { From 12e0381053d765ac96487c09764c1e13852125e7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 14:26:59 -0700 Subject: [PATCH 3236/5359] Pre 5.5 backwards compat --- php/WP_CLI/Formatter.php | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index cb7cfcd52..5da9926b0 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -74,25 +74,10 @@ public function display_items( $items ) { } if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) ) { - $fields = $this->args['fields']; - $callback = function( $item ) use ( $fields ) { - foreach( $fields as $field ) { - $true_field = $this->find_item_key( $item, $field ); - $value = is_object( $item ) ? $item->$true_field : $item[ $true_field ]; - if ( is_array( $value ) || is_object( $value ) ) { - if ( is_object( $item ) ) { - $item->$true_field = json_encode( $value ); - } else if ( is_array( $item ) ) { - $item[ $true_field ] = json_encode( $value ); - } - } - } - return $item; - }; if ( is_object( $items ) && is_a( $items, 'Iterator' ) ) { - $items = \WP_CLI\Utils\iterator_map( $items, $callback ); + $items = \WP_CLI\Utils\iterator_map( $items, array( $this, 'transform_item_values_to_json' ) ); } else { - $items = array_map( $callback, $items ); + $items = array_map( array( $this, 'transform_item_values_to_json' ), $items ); } } @@ -306,4 +291,25 @@ private function assoc_array_to_rows( $fields ) { return $rows; } + /** + * Transforms objects and arrays to JSON as necessary + * + * @param mixed $item + * @return mixed + */ + public function transform_item_values_to_json( $item ) { + foreach( $this->args['fields'] as $field ) { + $true_field = $this->find_item_key( $item, $field ); + $value = is_object( $item ) ? $item->$true_field : $item[ $true_field ]; + if ( is_array( $value ) || is_object( $value ) ) { + if ( is_object( $item ) ) { + $item->$true_field = json_encode( $value ); + } else if ( is_array( $item ) ) { + $item[ $true_field ] = json_encode( $value ); + } + } + } + return $item; + } + } From a66640a4abf1fa5e43368b71a804ee50200433f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 15:13:16 -0700 Subject: [PATCH 3237/5359] Ensure mu-plugins conform to our established spec for plugins Fixes this error: https://travis-ci.org/wp-cli/wp-cli/jobs/37127895 --- php/commands/plugin.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 7b3fee466..f9e675b45 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -118,9 +118,15 @@ protected function get_all_items() { foreach ( get_mu_plugins() as $file => $mu_plugin ) { $items[ $file ] = array( - 'name' => Utils\get_plugin_name( $file ), - 'status' => 'must-use', - 'update' => false + 'name' => Utils\get_plugin_name( $file ), + 'status' => 'must-use', + 'update' => false, + 'update_version' => NULL, + 'update_package' => NULL, + 'version' => '', + 'update_id' => '', + 'title' => '', + 'description' => '', ); } From ebf3a53abb83f77c49816d7bf18b4051e2099eb3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 15:29:50 -0700 Subject: [PATCH 3238/5359] PHP 5.3 compat --- php/WP_CLI/Iterators/Transform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Iterators/Transform.php b/php/WP_CLI/Iterators/Transform.php index 823e620b1..0c8e05590 100644 --- a/php/WP_CLI/Iterators/Transform.php +++ b/php/WP_CLI/Iterators/Transform.php @@ -17,7 +17,7 @@ public function current() { $value = parent::current(); foreach ( $this->transformers as $fn ) { - $value = $fn( $value ); + $value = call_user_func( $fn, $value ); } return $value; From dbb357223030c2c0ba575aa22b3a82a283932d3e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 5 Oct 2014 15:56:53 -0700 Subject: [PATCH 3239/5359] `wp user import-csv` should support CSVs generated from `wp user list` Key change is acknowledging a "roles" column, which can include one or more roles. --- features/user.feature | 37 +++++++++++++++++++++++++++++++++++++ php/commands/user.php | 23 ++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index 336d1cae4..5b6fc0175 100644 --- a/features/user.feature +++ b/features/user.feature @@ -200,6 +200,43 @@ Feature: Manage WordPress users } """ + @daniel + Scenario: Import users from a CSV file generated by `wp user list` + Given a WP install + + When I run `wp user delete 1 --yes` + And I run `wp user create bobjones bobjones@domain.com --display_name="Bob Jones" --role=contributor` + And I run `wp user create billjones billjones@domain.com --display_name="Bill Jones" --role=administrator` + And I run `wp user add-role billjones author` + Then STDOUT should not be empty + + When I run `wp user list --field=user_login | wc -l` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp user list --format=csv > users.csv` + Then the users.csv file should exist + + When I run `wp user delete $(wp user list --format=ids) --yes` + Then STDOUT should not be empty + + When I run `wp user list --field=user_login | wc -l` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp user import-csv users.csv` + Then STDOUT should not be empty + + When I run `wp user list --fields=display_name,roles` + Then STDOUT should be a table containing rows: + | display_name | roles | + | Bob Jones | contributor | + | Bill Jones | administrator,author | + Scenario: Managing user roles Given a WP install diff --git a/php/commands/user.php b/php/commands/user.php index 816ff3c97..50c28b756 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -622,7 +622,23 @@ public function import_csv( $args, $assoc_args ) { ); $new_user = array_merge( $defaults, $new_user ); - if ( 'none' === $new_user['role'] ) { + $secondary_roles = array(); + if ( ! empty( $new_user['roles'] ) ) { + $roles = array_map( 'trim', explode( ',', $new_user['roles'] ) ); + $invalid_role = false; + foreach( $roles as $role ) { + if ( is_null( get_role( $role ) ) ) { + WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + $invalid_role = true; + break; + } + } + if ( $invalid_role ) { + continue; + } + $new_user['role'] = array_shift( $roles ); + $secondary_roles = $roles; + } else if ( 'none' === $new_user['role'] ) { $new_user['role'] = false; } elseif ( is_null( get_role( $new_user['role'] ) ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); @@ -669,6 +685,11 @@ public function import_csv( $args, $assoc_args ) { delete_user_option( $user_id, 'user_level' ); } + $user = get_user_by( 'id', $user_id ); + foreach( $secondary_roles as $secondary_role ) { + $user->add_role( $secondary_role ); + } + if ( !empty( $existing_user ) ) { WP_CLI::success( $new_user['user_login'] . " updated" ); } else { From 1ce63ad1cca5e306997d320c7d42d29d44a0f5ab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 6 Oct 2014 07:57:18 -0400 Subject: [PATCH 3240/5359] Remove temp tag --- features/user.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index 5b6fc0175..44bc1a2eb 100644 --- a/features/user.feature +++ b/features/user.feature @@ -200,7 +200,6 @@ Feature: Manage WordPress users } """ - @daniel Scenario: Import users from a CSV file generated by `wp user list` Given a WP install From 1451c685b7e08742a0d18bd382ccb8eb0d244bc2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 6 Oct 2014 07:57:28 -0400 Subject: [PATCH 3241/5359] Fix indentation --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 50c28b756..27ab5385c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -627,7 +627,7 @@ public function import_csv( $args, $assoc_args ) { $roles = array_map( 'trim', explode( ',', $new_user['roles'] ) ); $invalid_role = false; foreach( $roles as $role ) { - if ( is_null( get_role( $role ) ) ) { + if ( is_null( get_role( $role ) ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); $invalid_role = true; break; From c73e5af4942899de8b84042e738a3d33ccdd55d2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 6 Oct 2014 21:59:20 -0300 Subject: [PATCH 3242/5359] Revert "improve test for `wp core language --<field>=<value>`" This reverts commit 6952bc4b859655afb46cd679ab60998180224aed. --- features/core.feature | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/features/core.feature b/features/core.feature index 2ac94a4d7..c9c55b24a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -473,9 +473,7 @@ Feature: Manage WordPress installation Then STDOUT should be a table containing rows: | language | english_name | status | | en_US | English (United States) | active | - - When I run `wp core language list --fields=language,english_name,status --status=active | wc -l` - Then STDOUT should be: + And STDOUT should not contain: """ - 2 + English (UK) """ From 950077f31ba0299f938531a65c93a4038c7b2b7b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 6 Oct 2014 22:00:07 -0300 Subject: [PATCH 3243/5359] Revert "remove empty line added by mistake" This reverts commit 1a571218f1a2a195b2311f5ff46d59176f9f74d7. --- php/WP_CLI/CommandWithTranslation.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index a93361a52..d2d9ad63f 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -59,6 +59,7 @@ public function list_( $args, $assoc_args ) { if ( $current_locale == $translation['language'] ) { $translation['status'] = 'active'; } + return $translation; }, $translations ); From 7f17a11bb3d3f9c24ca5bd73ad19b351870e8fcd Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 6 Oct 2014 22:00:21 -0300 Subject: [PATCH 3244/5359] Revert "Add functionality to filter list of languages" This reverts commit 489458a0f00a9ed2b5e53e92cf9c4558c7614b8f. --- features/core.feature | 9 --------- php/WP_CLI/CommandWithTranslation.php | 13 +------------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/features/core.feature b/features/core.feature index c9c55b24a..b2f1c68aa 100644 --- a/features/core.feature +++ b/features/core.feature @@ -468,12 +468,3 @@ Feature: Manage WordPress installation """ Error: Language not installed. """ - - When I run `wp core language list --fields=language,english_name,status --status=active` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | en_US | English (United States) | active | - And STDOUT should not contain: - """ - English (UK) - """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index d2d9ad63f..5caa95fdd 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -22,9 +22,6 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { /** * List all languages available. * - * [--<field>=<value>] - * : Filter results based on the value of a field. - * * [--fields=<fields>] * : Limit the output to specific fields. * @@ -59,20 +56,12 @@ public function list_( $args, $assoc_args ) { if ( $current_locale == $translation['language'] ) { $translation['status'] = 'active'; } - return $translation; }, $translations ); - foreach ( $translations as $key => $translation ) { - foreach ( $this->obj_fields as $field ) { - if ( isset( $assoc_args[$field] ) && $assoc_args[$field] != $translation[$field] ) { - unset( $translations[$key] ); - } - } - } - $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $translations ); + } /** From 4e882a9c3351a961a356dc1570f24ae9de8b386f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 7 Oct 2014 08:59:32 -0400 Subject: [PATCH 3245/5359] Prevent error caused by #1417 by ensuring item confirms to expected --- php/WP_CLI/CommandWithTranslation.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 1e93b99ff..c7e544f5e 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -178,6 +178,7 @@ protected function get_all_languages() { 'language' => 'en_US', 'english_name' => 'English (United States)', 'native_name' => 'English (United States)', + 'updated' => '', ); array_push( $translations, $en_us ); From ea168a6402c87b58b4264c2decdcb2f909a3a055 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 9 Oct 2014 13:29:25 -0300 Subject: [PATCH 3246/5359] fix `wp comment approve` and `wp comment unapprove` commands --- features/comment.feature | 18 ++++++++++++++++++ php/commands/comment.php | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/features/comment.feature b/features/comment.feature index 94aeb9d9b..b1c930a1e 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -95,3 +95,21 @@ Feature: Manage WordPress comments post-trashed: 0 total_comments: 1 """ + + Scenario: Approving/unapproving comments + Given I run `wp comment create --comment_post_ID=1 --comment_approved=0 --porcelain` + And save STDOUT as {COMMENT_ID} + + When I run `wp comment approve {COMMENT_ID}` + Then STDOUT should contain: + """ + Approved comment {COMMENT_ID} + """ + + When I run `wp comment unapprove {COMMENT_ID}` + Then STDOUT should contain: + """ + Unapproved comment {COMMENT_ID} + """ + + diff --git a/php/commands/comment.php b/php/commands/comment.php index cdf7641d4..fa19bad29 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -234,7 +234,7 @@ private function call( $args, $status, $success, $failure ) { private function set_status( $args, $status, $success ) { $comment = $this->fetcher->get_check( $args[0] ); - $r = wp_set_comment_status( $comment->comment_ID, 'approve', true ); + $r = wp_set_comment_status( $comment->comment_ID, $status, true ); if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); From e19f55dd6d75b832ded8c5e3738448833fd8a13f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 9 Oct 2014 16:02:51 -0300 Subject: [PATCH 3247/5359] make sure comment approve and unapprove are changing comment status --- features/comment.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index b1c930a1e..dd8ee017a 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -106,10 +106,21 @@ Feature: Manage WordPress comments Approved comment {COMMENT_ID} """ + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 1 + """ + When I run `wp comment unapprove {COMMENT_ID}` Then STDOUT should contain: """ Unapproved comment {COMMENT_ID} """ + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 0 + """ From b3d6befa26b8c4fbfe645caace155523cea7817a Mon Sep 17 00:00:00 2001 From: Borek Bernard <borekb@gmail.com> Date: Thu, 23 Oct 2014 00:44:46 +0200 Subject: [PATCH 3248/5359] Fixed mkdir command in `wp core download` on Windows --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index e2625d154..ede953645 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -125,7 +125,8 @@ public function download( $args, $assoc_args ) { if ( !is_dir( ABSPATH ) ) { WP_CLI::log( sprintf( 'Creating directory %s', ABSPATH ) ); - WP_CLI::launch( Utils\esc_cmd( 'mkdir -p %s', ABSPATH ) ); + $mkdir = \WP_CLI\Utils\is_windows() ? 'mkdir %s' : 'mkdir -p %s'; + WP_CLI::launch( Utils\esc_cmd( $mkdir, ABSPATH ) ); } $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; From 06e5e84f0f5ba5122b88f53393ff9b6b8b75f630 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Oct 2014 06:51:07 -0700 Subject: [PATCH 3249/5359] Don't iterate when there aren't image sizes --- php/commands/media.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index 0db379468..7d8c774e2 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -237,6 +237,10 @@ private function remove_old_images( $att_id ) { $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; $original_path = $dir_path . basename( $metadata['file'] ); + if ( empty( $metadata['sizes'] ) ) { + return; + } + foreach ( $metadata['sizes'] as $size => $size_info ) { $intermediate_path = $dir_path . $size_info['file']; From 569a08eed0d11071f31b06a360eee8fcf0d449cf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 26 Oct 2014 11:48:05 -0700 Subject: [PATCH 3250/5359] Only set up testing suite if it doesn't exist --- templates/install-wp-tests.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 1e39064a5..f4ece0efc 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -39,8 +39,13 @@ install_test_suite() { local ioption='-i' fi - # set up testing suite - mkdir -p $WP_TESTS_DIR + # set up testing suite if it doesn't yet exist + if [ ! "$(ls -A $WP_TESTS_DIR)" ]; then + # set up testing suite + mkdir -p $WP_TESTS_DIR + svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR + fi + cd $WP_TESTS_DIR svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ From 2cd2bee4610fbeba65036e7e46ed29096cc48325 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 26 Oct 2014 11:48:22 -0700 Subject: [PATCH 3251/5359] Only configure tests config if it doesn't exist --- templates/install-wp-tests.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index f4ece0efc..336c22bbc 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -47,14 +47,15 @@ install_test_suite() { fi cd $WP_TESTS_DIR - svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ - - wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php + + if [ ! -f wp-tests-config.php ]; then + wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php + fi } install_db() { From 3d76824570da4a6e08ae67109afd7226b74407dd Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sun, 26 Oct 2014 16:48:12 -0700 Subject: [PATCH 3252/5359] remove unused variables --- php/commands/core.php | 5 +++-- php/commands/cron.php | 4 ++-- php/commands/media.php | 2 +- php/commands/term.php | 7 ------- php/commands/user.php | 1 - 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index e2625d154..c88ec74b0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -539,8 +539,9 @@ private function _install( $assoc_args ) { // Support prompting for the `--url=<url>`, // which is normally a runtime argument - if ( isset( $assoc_args['url'] ) ) - $url_parts = WP_CLI::set_url( $assoc_args['url'] ); + if ( isset( $assoc_args['url'] ) ) { + WP_CLI::set_url( $assoc_args['url'] ); + } $public = true; diff --git a/php/commands/cron.php b/php/commands/cron.php index c34079228..32d195950 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -151,7 +151,7 @@ public function run( $args, $assoc_args ) { } $executed = 0; - foreach ( $events as $id => $event ) { + foreach ( $events as $event ) { if ( $event->hook == $hook ) { $result = self::run_event( $event ); if ( $result ) { @@ -214,7 +214,7 @@ public function delete( $args, $assoc_args ) { } $deleted = 0; - foreach ( $events as $id => $event ) { + foreach ( $events as $event ) { if ( $event->hook == $hook ) { $result = self::delete_event( $event ); if ( $result ) { diff --git a/php/commands/media.php b/php/commands/media.php index 0db379468..df5435314 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -237,7 +237,7 @@ private function remove_old_images( $att_id ) { $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; $original_path = $dir_path . basename( $metadata['file'] ); - foreach ( $metadata['sizes'] as $size => $size_info ) { + foreach ( $metadata['sizes'] as $size_info ) { $intermediate_path = $dir_path . $size_info['file']; if ( $intermediate_path == $original_path ) diff --git a/php/commands/term.php b/php/commands/term.php index 8aeae04bd..e7befa0c2 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -282,8 +282,6 @@ public function delete( $args ) { * wp term generate --count=10 */ public function generate( $args, $assoc_args ) { - global $wpdb; - list ( $taxonomy ) = $args; $defaults = array( @@ -304,11 +302,6 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); - $args = array( - 'orderby' => 'id', - 'hierarchical' => $hierarchical, - ); - $previous_term_id = 0; $current_parent = 0; $current_depth = 1; diff --git a/php/commands/user.php b/php/commands/user.php index 27ab5385c..b9575d3a4 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -559,7 +559,6 @@ public function list_caps( $args, $assoc_args ) { $user->get_role_caps(); $user_caps_list = $user->allcaps; - $cap_table_titles = array( 'capability', 'status' ); foreach ( $user_caps_list as $cap => $active ) { if ( $active ) { From 651d987ce2c6de2277bd28db29af0c2b1904ea4d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Sun, 26 Oct 2014 17:09:05 -0700 Subject: [PATCH 3253/5359] add tests to `wp plugin activate --all` and `wp plugin deactivate --all` --- features/plugin.feature | 33 +++++++++++++++++++++++++++++++++ php/commands/plugin.php | 8 +++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 41823ad30..7f98233bb 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -242,3 +242,36 @@ Feature: Manage WordPress plugins """ Installing Debug Bar List Script & Style Dependencies """ + + Scenario: Enable and disable all plugins + Given a WP install + + When I run `wp plugin activate --all` + Then STDOUT should be: + """ + Success: Plugin 'akismet' activated. + Success: Plugin 'hello' activated. + """ + + When I run `wp plugin list --field=status` + Then STDOUT should be: + """ + active + active + must-use + """ + + When I run `wp plugin deactivate --all` + Then STDOUT should be: + """ + Success: Plugin 'akismet' deactivated. + Success: Plugin 'hello' deactivated. + """ + + When I run `wp plugin list --field=status` + Then STDOUT should be: + """ + inactive + inactive + must-use + """ diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 13da51291..4977dffe8 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -579,13 +579,15 @@ private function active_output( $name, $file, $network_wide, $action ) { private function update_plugins_status( $action, $network_wide ) { $status = ( $action == "activate" ) ? "active" : "inactive"; foreach ( get_plugins() as $file => $details ) { - if ( $this->get_status( $file ) == $status ) + if ( $this->get_status( $file ) == $status ) { continue; + } - if ( $action == "activate" ) + if ( $action == "activate" ) { activate_plugins( $file, false, $network_wide ); - else + } else { deactivate_plugins( $file, false, $network_wide ); + } $name = Utils\get_plugin_name( $file ); $this->active_output( $name, $file, $network_wide, $action ); From c252c27c96aa720689721964ae38357d73aa282a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 31 Oct 2014 22:13:52 +0100 Subject: [PATCH 3254/5359] Added CHECK TABLE example --- php/commands/db.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/db.php b/php/commands/db.php index edaa20aa5..dae4537b2 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -95,6 +95,7 @@ function cli() { * * # execute a query stored in a file * wp db query < debug.sql + * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" */ function query( $args ) { $assoc_args = array( From dcf415cbf71272c5782afb3840acca04a1b72b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 31 Oct 2014 22:16:06 +0100 Subject: [PATCH 3255/5359] Added comment --- php/commands/db.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/db.php b/php/commands/db.php index dae4537b2..491755dd3 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -95,6 +95,7 @@ function cli() { * * # execute a query stored in a file * wp db query < debug.sql + * # check all tables in the database * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" */ function query( $args ) { From 2e1770073d7e2358b475db27752f9b41868f0812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 31 Oct 2014 22:17:06 +0100 Subject: [PATCH 3256/5359] And an empty line too --- php/commands/db.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/db.php b/php/commands/db.php index 491755dd3..bfd7e021f 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -95,6 +95,7 @@ function cli() { * * # execute a query stored in a file * wp db query < debug.sql + * * # check all tables in the database * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" */ From 04074c5696f96113deb496f72ee4604e55d1cee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 1 Nov 2014 14:01:36 +0100 Subject: [PATCH 3257/5359] fixed search+tests --- features/option.feature | 23 +++++++++++++++++ php/commands/option.php | 56 +++++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/features/option.feature b/features/option.feature index ee9a7a509..8db89c3af 100644 --- a/features/option.feature +++ b/features/option.feature @@ -13,6 +13,29 @@ Feature: Manage WordPress options bar """ + When I run `wp option list --search='str_o*'` + Then STDOUT should be: + """ + option_name + str_opt + """ + + When I run `wp option list --search='str_o*' --total` + Then STDOUT should be: + """ + size + 3 + """ + + When I run `wp option add auto_opt --autoload=no 'bar'` + Then STDOUT should not be empty + + When I run `wp option list --search='auto_opt' --autoload` + Then STDOUT should not be empty + + When I run `wp option list | grep -q "str_opt"` + Then the return code should be 0 + When I run `wp option delete str_opt` Then STDOUT should not be empty diff --git a/php/commands/option.php b/php/commands/option.php index 087d1d1e0..137ffab19 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -80,21 +80,29 @@ public function add( $args, $assoc_args ) { /** * List options. * - * [--search=<sql-like-pattern>] - * : SQL pattern matching enables you to use "_" to match any single character and "%" to match an arbitrary number of characters. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. + * [--search=<pattern>] + * : Use wildcards ( * and ? ) to match option name. * * [--autoload] * : Match only autoload options. * * [--total] - * : Display only the total size of matching options. + * : Display only the total size of matching options in bytes. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. * * [--format=<format>] * : The serialization format for the value. Default is table. * + * ## EXAMPLES + * + * # Get the total size of all autoload options + * wp option list --total --autoload + * + * # List all options begining with "i2f_" + * wp option list --search "i2f_*" + * * ## AVAILABLE FIELDS * * This field will be displayed by default for each matching option: @@ -103,7 +111,7 @@ public function add( $args, $assoc_args ) { * * These fields are optionally available: * - * * option_name + * * option_value * * autoload * * size * @@ -113,24 +121,25 @@ public function add( $args, $assoc_args ) { public function list_( $args, $assoc_args ) { global $wpdb; - $size_query = "LENGTH(option_value) AS size"; + $pattern = '%'; + $fields = array( 'option_name' ); + $size_query = ",LENGTH(option_value) AS size"; $autoload_query = ''; if ( isset( $assoc_args['search'] ) ) { - $pattern = $assoc_args['search']; - } else { - $pattern = '%'; + $pattern = self::esc_like( esc_sql( $assoc_args['search'] ) ); + // substitute wildcards + $pattern = str_replace( '*', '%', $pattern ); + $pattern = str_replace( '?', '_', $pattern ); } if ( isset( $assoc_args['fields'] ) ) { $fields = explode( ',', $assoc_args['fields'] ); - } else { - $fields = array( 'option_name' ); } if ( isset( $assoc_args['total'] ) ) { $fields = array( 'size' ); - $size_query = "SUM(LENGTH(option_value)) AS size"; + $size_query = ",SUM(LENGTH(option_value)) AS `size`"; } if ( isset( $assoc_args['autoload'] ) ) { @@ -139,8 +148,8 @@ public function list_( $args, $assoc_args ) { $results = $wpdb->get_results( $wpdb->prepare( - "SELECT option_name,option_value,autoload," . $size_query - . " FROM $wpdb->options WHERE option_name LIKE %s" . $autoload_query, + "SELECT `option_name`,`option_value`,`autoload`" . $size_query + . " FROM `$wpdb->options` WHERE `option_name` LIKE %s" . $autoload_query, $pattern ) ); @@ -206,6 +215,21 @@ public function delete( $args ) { WP_CLI::success( "Deleted '$key' option." ); } } + + private static function esc_like( $old ) { + global $wpdb; + + // Remove notices in 4.0 and support backwards compatibility + if( method_exists( $wpdb, 'esc_like' ) ) { + // 4.0 + $old = $wpdb->esc_like( $old ); + } else { + // 3.9 or less + $old = like_escape( esc_sql( $old ) ); + } + + return $old; + } } WP_CLI::add_command( 'option', 'Option_Command' ); From 01dd52e5f7822245a5fa06e27b8ff5b99248f4ed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 1 Nov 2014 10:54:35 -0700 Subject: [PATCH 3258/5359] If core directory is already around, skip --- templates/install-wp-tests.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 336c22bbc..28c932064 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -17,6 +17,11 @@ WP_CORE_DIR=/tmp/wordpress/ set -ex install_wp() { + + if [ -d $WP_CORE_DIR ]; then + return; + fi + mkdir -p $WP_CORE_DIR if [ $WP_VERSION == 'latest' ]; then From f9d597726ebcd5c5b15fc89ec6f30852b374c84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 1 Nov 2014 22:09:00 +0100 Subject: [PATCH 3259/5359] make total a format, and autoload=off --- features/option.feature | 8 +++++- php/commands/option.php | 54 +++++++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/features/option.feature b/features/option.feature index 8db89c3af..4dd061690 100644 --- a/features/option.feature +++ b/features/option.feature @@ -13,6 +13,12 @@ Feature: Manage WordPress options bar """ + When I run `wp option list + Then STDOUT should not be empty + + When I run `wp option list --autoload=on + Then STDOUT should not be empty + When I run `wp option list --search='str_o*'` Then STDOUT should be: """ @@ -20,7 +26,7 @@ Feature: Manage WordPress options str_opt """ - When I run `wp option list --search='str_o*' --total` + When I run `wp option list --search='str_o*' --format=total_bytes` Then STDOUT should be: """ size diff --git a/php/commands/option.php b/php/commands/option.php index 137ffab19..6cccab2b9 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -83,22 +83,24 @@ public function add( $args, $assoc_args ) { * [--search=<pattern>] * : Use wildcards ( * and ? ) to match option name. * - * [--autoload] - * : Match only autoload options. - * - * [--total] - * : Display only the total size of matching options in bytes. + * [--autoload=<value>] + * : Match only autoload options when value is on, and only not-autoload option when off. * * [--fields=<fields>] * : Limit the output to specific object fields. * * [--format=<format>] - * : The serialization format for the value. Default is table. + * : The serialization format for the value. + * : total_bytes displays the total size of matching options in bytes. + * : Accepted values: table, json, csv, count, total_bytes. Default: table * * ## EXAMPLES * * # Get the total size of all autoload options - * wp option list --total --autoload + * wp option list --autoload=on --format=total_bytes + * + * # Find biggest transients + * wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail * * # List all options begining with "i2f_" * wp option list --search "i2f_*" @@ -108,22 +110,22 @@ public function add( $args, $assoc_args ) { * This field will be displayed by default for each matching option: * * * option_name + * * option_value * * These fields are optionally available: * - * * option_value * * autoload - * * size + * * size_bytes * * @subcommand list - * @synopsis [--search=<sql-like-pattern>] [--total] [--autoload] [--fields=<fields>] [--format=<format>] + * @synopsis [--search=<sql-like-pattern>] [--autoload=<value>] [--fields=<fields>] [--format=<format>] */ public function list_( $args, $assoc_args ) { global $wpdb; $pattern = '%'; - $fields = array( 'option_name' ); - $size_query = ",LENGTH(option_value) AS size"; + $fields = array( 'option_name', 'option_value' ); + $size_query = ",LENGTH(option_value) AS `size_bytes`"; $autoload_query = ''; if ( isset( $assoc_args['search'] ) ) { @@ -137,13 +139,19 @@ public function list_( $args, $assoc_args ) { $fields = explode( ',', $assoc_args['fields'] ); } - if ( isset( $assoc_args['total'] ) ) { - $fields = array( 'size' ); - $size_query = ",SUM(LENGTH(option_value)) AS `size`"; + if ( isset( $assoc_args['format'] ) && 'total_bytes' === $assoc_args['format'] ) { + $fields = array( 'size_bytes' ); + $size_query = ",SUM(LENGTH(option_value)) AS `size_bytes`"; } if ( isset( $assoc_args['autoload'] ) ) { - $autoload_query = " AND autoload='yes'"; + if ( 'on' === $assoc_args['autoload'] ) { + $autoload_query = " AND autoload='yes'"; + } elseif ( 'off' === $assoc_args['autoload'] ) { + $autoload_query = " AND autoload='no'"; + } else { + WP_CLI::error( "Value of '--autoload' should be on or off." ); + } } $results = $wpdb->get_results( @@ -154,11 +162,15 @@ public function list_( $args, $assoc_args ) { ) ); - $formatter = new \WP_CLI\Formatter( - $assoc_args, - $fields - ); - $formatter->display_items( $results ); + if ( isset( $assoc_args['format'] ) && 'total_bytes' === $assoc_args['format'] ) { + WP_CLI::line( $results[0]->size_bytes ); + } else { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + $fields + ); + $formatter->display_items( $results ); + } } /** From f54ef85d658e05e194fe0707bbbabc003706dc7c Mon Sep 17 00:00:00 2001 From: Brad Parbs <brad@bradparbs.com> Date: Tue, 4 Nov 2014 12:29:33 -0600 Subject: [PATCH 3260/5359] Fix running as sudo error message to be consistent in how help files show place to run command --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e7e48a97e..6fe89d0fe 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -547,7 +547,7 @@ private function check_root() { "If you'd like to run it as the user that this site is under, you can " . "run the following to become the respective user:\n" . "\n" . - " sudo -u USER -i -- wp ...\n" . + " sudo -u USER -i -- wp <command>\n" . "\n" ); } From 2a48ea09bc5c9fe634ed899ba10b04c8f90d6633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 6 Nov 2014 01:40:47 +0100 Subject: [PATCH 3261/5359] Show mu-plugin version too --- php/commands/plugin.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 4977dffe8..ca92ccd04 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -117,13 +117,17 @@ protected function get_all_items() { $items = $this->get_item_list(); foreach ( get_mu_plugins() as $file => $mu_plugin ) { + $mu_version = ''; + if ( ! empty( $mu_plugin['Version'] ) ) + $mu_version = $mu_plugin['Version']; + $items[ $file ] = array( 'name' => Utils\get_plugin_name( $file ), 'status' => 'must-use', 'update' => false, 'update_version' => NULL, 'update_package' => NULL, - 'version' => '', + 'version' => $mu_version, 'update_id' => '', 'title' => '', 'description' => '', From 48c730d3b3a655f2d1dd37e426a28c2747b2575a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 6 Nov 2014 02:04:41 +0100 Subject: [PATCH 3262/5359] WP coding standards --- php/commands/plugin.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ca92ccd04..3f2321f61 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -118,8 +118,9 @@ protected function get_all_items() { foreach ( get_mu_plugins() as $file => $mu_plugin ) { $mu_version = ''; - if ( ! empty( $mu_plugin['Version'] ) ) + if ( ! empty( $mu_plugin['Version'] ) ) { $mu_version = $mu_plugin['Version']; + } $items[ $file ] = array( 'name' => Utils\get_plugin_name( $file ), From 679ad873f88e7b29743bf799e474c5815ef87924 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 6 Nov 2014 16:10:57 -0800 Subject: [PATCH 3263/5359] Decode quotes too --- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 3f2321f61..68ffd5177 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -277,7 +277,7 @@ protected function install_from_repo( $slug, $assoc_args ) { return new WP_Error( 'already_installed', 'Plugin already installed.' ); } - WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name ), $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index aaef43c5d..adceda527 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -283,7 +283,7 @@ protected function install_from_repo( $slug, $assoc_args ) { return new WP_Error( 'already_installed', 'Theme already installed.' ); } - WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name ), $api->version ) ); + WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } From f73d6011d11f866c22816aee6e0ea39addd49be1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 6 Nov 2014 16:23:31 -0800 Subject: [PATCH 3264/5359] Check response code in `::_read()` If WordPress.org returns a bad response, we want to know about it --- php/commands/core.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d87aed2ea..dfdb15e28 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -224,7 +224,12 @@ private static function _rmdir( $dir ) { private static function _read( $url ) { $headers = array('Accept' => 'application/json'); - return Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) )->body; + $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); + if ( 200 === $response->status_code ) { + return $response->body; + } else { + WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})" ); + } } private function get_download_offer( $locale ) { From 325dfa01a0c56509f3c402c407cb104e288a005f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 07:37:04 -0800 Subject: [PATCH 3265/5359] Test for #1485 --- features/config.feature | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/features/config.feature b/features/config.feature index ad5f2e05e..6c755d64e 100644 --- a/features/config.feature +++ b/features/config.feature @@ -197,4 +197,19 @@ Feature: Have a config file """ When I run `WP_CLI_CONFIG_PATH=test-dir/config.yml wp help` - Then STDERR should be empty + Then STDERR should be empty + + Scenario: Missing required files should not fatal WP-CLI + Given an empty directory + And a wp-cli.yml file: + """ + require: + - missing-file.php + """ + + When I try `wp help` + Then STDERR should contain: + """ + Error: Required file 'missing-file.php' doesn't exist + """ + From 85c5d632fa0c2d056915ac314c6d50b0ccff61b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 07:37:25 -0800 Subject: [PATCH 3266/5359] Throw a human-friendly error if required file is missing --- php/WP_CLI/Runner.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6fe89d0fe..de8122abf 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -568,6 +568,9 @@ public function before_wp_load() { if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { + if ( ! file_exists( $path ) ) { + WP_CLI::error( sprintf( "Required file '%s' doesn't exist", basename( $path ) ) ); + } Utils\load_file( $path ); } } From 0efd4a736bfb7a64082755218b455474c4b1c918 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 07:52:37 -0800 Subject: [PATCH 3267/5359] Update php-cli-tools to 0.10.2 Release notes https://github.com/wp-cli/php-cli-tools/releases/tag/v0.10.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index da62d1b49..f503e3906 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.1", + "wp-cli/php-cli-tools": "0.10.2", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From c1b6ae001edbdfdd981a2dd4b89f529f4d180c58 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 08:25:57 -0800 Subject: [PATCH 3268/5359] Fix editing post content in an editor `\WP_CLI::launch()` now uses the `Process` class, which pipes STDOUT to return the results. Because all we care about is running the process, it's simpler to just internalize that here. --- php/utils.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index fbee550ac..963a3a463 100644 --- a/php/utils.php +++ b/php/utils.php @@ -279,7 +279,12 @@ function launch_editor_for_input( $input, $title = 'WP-CLI' ) { $editor = 'vi'; } - \WP_CLI::launch( "$editor " . escapeshellarg( $tmpfile ) ); + $descriptorspec = array( STDIN, STDOUT, STDERR ); + $process = proc_open( "$editor " . escapeshellarg( $tmpfile ), $descriptorspec, $pipes ); + $r = proc_close( $process ); + if ( $r ) { + exit( $r ); + } $output = file_get_contents( $tmpfile ); From b10bef5f0401e53c6c1644c86bf11ad0d448b57b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 09:01:06 -0800 Subject: [PATCH 3269/5359] More tests for #1485 --- features/config.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/config.feature b/features/config.feature index 6c755d64e..2a2b3ae84 100644 --- a/features/config.feature +++ b/features/config.feature @@ -213,3 +213,9 @@ Feature: Have a config file Error: Required file 'missing-file.php' doesn't exist """ + When I run `wp cli info` + Then STDOUT should not be empty + + When I run `wp --info` + Then STDOUT should not be empty + From cbeb521ef46b0bae040418ef87ede32c18022a86 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 09:08:11 -0800 Subject: [PATCH 3270/5359] Run `wp cli info` early to protect from runtime If a config file includes poor declarations, we still want `wp cli info` to work. --- php/WP_CLI/Runner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index de8122abf..787d4dd52 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -562,6 +562,12 @@ public function before_wp_load() { if ( empty( $this->arguments ) ) $this->arguments[] = 'help'; + // Protect 'cli info' from most of the runtime + if ( 'cli' === $this->arguments[0] && ! empty( $this->arguments[1] ) && 'info' === $this->arguments[1] ) { + $this->_run_command(); + exit; + } + // Load bundled commands early, so that they're forced to use the same // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); From 28cf2fac657196b2e03c15880b25c3398c499902 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 09:22:27 -0800 Subject: [PATCH 3271/5359] Failing test for #1489 --- features/plugin.feature | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 7f98233bb..814ec42b3 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -274,4 +274,14 @@ Feature: Manage WordPress plugins inactive inactive must-use - """ + """ + + Scenario: Uninstall a plugin without deleting + Given a WP install + + When I run `wp plugin install akismet --version=2.5.7 --force` + Then STDOUT should not be empty + + When I run `wp plugin uninstall akismet --no-delete` + Then STDOUT should not be empty + From 894a35ced5edabf4502f34758e5107732cd76b34 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 09:30:25 -0800 Subject: [PATCH 3272/5359] Turn `plugin uninstall --no-delete` into `plugin uninstall --skip-delete` The `--no-delete` flag has been broken since a9adf7b78bcefe3b5db03e167f53c6263dab1549 (5 releases), so I'm not concerned about a backwards compat shim. Adds more verbosity too. --- features/plugin.feature | 8 ++++++-- php/commands/plugin.php | 8 +++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 814ec42b3..0ef5a21ac 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -282,6 +282,10 @@ Feature: Manage WordPress plugins When I run `wp plugin install akismet --version=2.5.7 --force` Then STDOUT should not be empty - When I run `wp plugin uninstall akismet --no-delete` - Then STDOUT should not be empty + When I run `wp plugin uninstall akismet --skip-delete` + Then STDOUT should contain: + """ + Success: Ran uninstall procedure for + """ + diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 68ffd5177..214c78e8d 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -446,7 +446,7 @@ public function get( $args, $assoc_args ) { * <plugin>... * : One or more plugins to uninstall. * - * [--no-delete] + * [--skip-delete] * : If set, the plugin files will not be deleted. Only the uninstall procedure * will be run. * @@ -463,8 +463,10 @@ function uninstall( $args, $assoc_args = array() ) { uninstall_plugin( $plugin->file ); - if ( !isset( $assoc_args['no-delete'] ) && $this->_delete( $plugin ) ) { - WP_CLI::success( "Uninstalled '$plugin->name' plugin." ); + if ( !isset( $assoc_args['skip-delete'] ) && $this->_delete( $plugin ) ) { + WP_CLI::success( "Uninstalled and deleted '$plugin->name' plugin." ); + } else { + WP_CLI::success( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); } } } From 2bcca7edf7c08e5103798a13b16f4ccff79f4a7f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 10:14:18 -0800 Subject: [PATCH 3273/5359] Failing test for #1432 --- features/core.feature | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index b0cc7b5d6..60d4f9e9c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -367,7 +367,20 @@ Feature: Manage WordPress installation And STDOUT should not contain: """ Downloading - """ + """ + + Scenario: Don't run update when up-to-date + Given a WP install + + When I run `wp core update` + Then STDOUT should contain: + """ + WordPress is at the latest version + """ + And STDOUT should not contain: + """ + Updating + """ Scenario: User defined in wp-cli.yml From 69a77e5fe14be009bc90eb3a7899bde5ac38f22e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 10:24:19 -0800 Subject: [PATCH 3274/5359] Don't attempt to update when `$update` isn't set Also, unless `--force` is specified, don't update when the versions are the same. Previously, an invalid conditional meant the update process executed even when `$update` wasn't set. --- features/core.feature | 9 +++++++-- php/commands/core.php | 43 ++++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/features/core.feature b/features/core.feature index 60d4f9e9c..3f84b643d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -375,13 +375,18 @@ Feature: Manage WordPress installation When I run `wp core update` Then STDOUT should contain: """ - WordPress is at the latest version + WordPress is up to date """ And STDOUT should not contain: """ - Updating + Updating """ + When I run `wp core update --force` + Then STDOUT should contain: + """ + Updating + """ Scenario: User defined in wp-cli.yml Given an empty directory diff --git a/php/commands/core.php b/php/commands/core.php index dfdb15e28..e3b2ace8c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -870,9 +870,7 @@ function update( $args, $assoc_args ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); - if ( empty( $from_api->updates ) ) { - $update = false; - } else { + if ( ! empty( $from_api->updates ) ) { list( $update ) = $from_api->updates; } @@ -898,32 +896,35 @@ function update( $args, $assoc_args ) { 'locale' => $locale ); - } else { - WP_CLI::success( 'WordPress is up to date.' ); - return; } + + if ( ! empty( $update ) && ( $update->version != $wp_version || isset( $assoc_args['force'] ) ) ) { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - if ( $update->version ) { - WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); - } else { - WP_CLI::log( "Starting update..." ); - } + if ( $update->version ) { + WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); + } else { + WP_CLI::log( "Starting update..." ); + } - $GLOBALS['wp_cli_update_obj'] = $update; - $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); - unset( $GLOBALS['wp_cli_update_obj'] ); + $GLOBALS['wp_cli_update_obj'] = $update; + $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); + unset( $GLOBALS['wp_cli_update_obj'] ); - if ( is_wp_error($result) ) { - $msg = WP_CLI::error_to_string( $result ); - if ( 'up_to_date' != $result->get_error_code() ) { - WP_CLI::error( $msg ); + if ( is_wp_error($result) ) { + $msg = WP_CLI::error_to_string( $result ); + if ( 'up_to_date' != $result->get_error_code() ) { + WP_CLI::error( $msg ); + } else { + WP_CLI::success( $msg ); + } } else { - WP_CLI::success( $msg ); + WP_CLI::success( 'WordPress updated successfully.' ); } + } else { - WP_CLI::success( 'WordPress updated successfully.' ); + WP_CLI::success( 'WordPress is up to date.' ); } } From 90f38f7200fe4d21e63cdd6d70cef1804cb1c025 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 11:28:22 -0800 Subject: [PATCH 3275/5359] Update existing test for 894a35ced5edabf4502f34758e5107732cd76b34 --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 0ef5a21ac..fec30f86a 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -76,7 +76,7 @@ Feature: Manage WordPress plugins When I run `wp plugin uninstall Zombieland` Then STDOUT should contain: """ - Success: Uninstalled 'Zombieland' plugin. + Success: Uninstalled and deleted 'Zombieland' plugin. """ And the {PLUGIN_DIR}/zombieland file should not exist From 7382430c1b3d3e55a44c8fb416668126913120eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 11:32:35 -0800 Subject: [PATCH 3276/5359] Lock down permissions for bash completion --- utils/wp-completion.bash | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 utils/wp-completion.bash diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash old mode 100755 new mode 100644 From e04e7e934a48b0d47bf6ccd14ca684eb9d1f908d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 12:08:09 -0800 Subject: [PATCH 3277/5359] No indentation here --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index e3b2ace8c..27723b6cb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -897,7 +897,7 @@ function update( $args, $assoc_args ) { ); } - + if ( ! empty( $update ) && ( $update->version != $wp_version || isset( $assoc_args['force'] ) ) ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); From b72e32fc2ceb0598a655d238a41f24c9daf0285b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 12 Nov 2014 22:12:21 +0100 Subject: [PATCH 3278/5359] indent examples --- php/commands/option.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 6cccab2b9..6309b6bdb 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -96,14 +96,14 @@ public function add( $args, $assoc_args ) { * * ## EXAMPLES * - * # Get the total size of all autoload options - * wp option list --autoload=on --format=total_bytes + * # Get the total size of all autoload options + * wp option list --autoload=on --format=total_bytes * - * # Find biggest transients - * wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail + * # Find biggest transients + * wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail * - * # List all options begining with "i2f_" - * wp option list --search "i2f_*" + * # List all options begining with "i2f_" + * wp option list --search "i2f_*" * * ## AVAILABLE FIELDS * From 7e0d3ee461529c38392b737de7985aa242d7c5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 12 Nov 2014 22:40:27 +0100 Subject: [PATCH 3279/5359] wrapping up `wp option list` tests --- features/option.feature | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/features/option.feature b/features/option.feature index 4dd061690..4e33f6ef5 100644 --- a/features/option.feature +++ b/features/option.feature @@ -13,23 +13,26 @@ Feature: Manage WordPress options bar """ - When I run `wp option list + When I run `wp option list` Then STDOUT should not be empty - When I run `wp option list --autoload=on + When I run `wp option list` + Then STDOUT should contain: + """ + bar + """ + + When I run `wp option list --autoload=on` Then STDOUT should not be empty When I run `wp option list --search='str_o*'` - Then STDOUT should be: - """ - option_name - str_opt - """ + Then STDOUT should be a table containing rows: + | option_name | option_value | + | str_opt | bar | When I run `wp option list --search='str_o*' --format=total_bytes` Then STDOUT should be: """ - size 3 """ @@ -45,10 +48,15 @@ Feature: Manage WordPress options When I run `wp option delete str_opt` Then STDOUT should not be empty + When I run `wp option list` + Then STDOUT should not contain: + """ + str_opt + """ + When I try `wp option get str_opt` Then the return code should be 1 - # Integer values When I run `wp option update blog_public 0` Then STDOUT should not be empty From 0261d6713cc268927461d4361840c061d365431b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 14:14:49 -0800 Subject: [PATCH 3280/5359] Disambiguate two plugins sharing the same directory --- features/plugin.feature | 18 ++++++++++++++++++ php/commands/plugin.php | 18 ++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index fec30f86a..1d86171a8 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -288,4 +288,22 @@ Feature: Manage WordPress plugins Success: Ran uninstall procedure for """ + Scenario: Two plugins, one directory + Given a WP install + And I run `svn co https://meta.svn.wordpress.org/sites/trunk/wordpress.org/public_html/wp-content/plugins/handbook wp-content/plugins/handbook` + + When I run `wp plugin list --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | handbook/handbook | inactive | + | handbook/functionality-for-pages | inactive | + + When I run `wp plugin activate handbook/functionality-for-pages` + Then STDOUT should not be empty + + When I run `wp plugin list --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | handbook/handbook | inactive | + | handbook/functionality-for-pages | active | diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 214c78e8d..95cd478b7 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -322,13 +322,18 @@ function update( $args, $assoc_args ) { } protected function get_item_list() { - $items = array(); + $items = $duplicate_names = array(); foreach ( get_plugins() as $file => $details ) { $update_info = $this->get_update_info( $file ); + $name = Utils\get_plugin_name( $file ); + if ( ! isset( $duplicate_names[ $name ] ) ) { + $duplicate_names[ $name ] = array(); + } + $duplicate_names[ $name ][] = $file; $items[ $file ] = array( - 'name' => Utils\get_plugin_name( $file ), + 'name' => $name, 'status' => $this->get_status( $file ), 'update' => (bool) $update_info, 'update_version' => $update_info['new_version'], @@ -340,6 +345,15 @@ protected function get_item_list() { ); } + foreach( $duplicate_names as $name => $files ) { + if ( count( $files ) <= 1 ) { + continue; + } + foreach( $files as $file ) { + $items[ $file ]['name'] = str_replace( '.' . pathinfo( $file, PATHINFO_EXTENSION ), '', $file ); + } + } + return $items; } From d500fb54d5166c1929efbe63a2c3bf6e1baedd38 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 14:18:45 -0800 Subject: [PATCH 3281/5359] Fix indentation --- features/plugin.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 1d86171a8..3de6cfb29 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -296,7 +296,7 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | | handbook/handbook | inactive | - | handbook/functionality-for-pages | inactive | + | handbook/functionality-for-pages | inactive | When I run `wp plugin activate handbook/functionality-for-pages` Then STDOUT should not be empty @@ -305,5 +305,5 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | status | | handbook/handbook | inactive | - | handbook/functionality-for-pages | active | + | handbook/functionality-for-pages | active | From a53b49fddbebb7155a016b656c5aa126b388a779 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 12 Nov 2014 14:20:23 -0800 Subject: [PATCH 3282/5359] More indentation fixes --- features/plugin.feature | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 3de6cfb29..8b578fb8e 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -274,34 +274,34 @@ Feature: Manage WordPress plugins inactive inactive must-use - """ + """ Scenario: Uninstall a plugin without deleting Given a WP install - When I run `wp plugin install akismet --version=2.5.7 --force` - Then STDOUT should not be empty + When I run `wp plugin install akismet --version=2.5.7 --force` + Then STDOUT should not be empty - When I run `wp plugin uninstall akismet --skip-delete` - Then STDOUT should contain: - """ - Success: Ran uninstall procedure for - """ + When I run `wp plugin uninstall akismet --skip-delete` + Then STDOUT should contain: + """ + Success: Ran uninstall procedure for + """ Scenario: Two plugins, one directory Given a WP install And I run `svn co https://meta.svn.wordpress.org/sites/trunk/wordpress.org/public_html/wp-content/plugins/handbook wp-content/plugins/handbook` - When I run `wp plugin list --fields=name,status` + When I run `wp plugin list --fields=name,status` Then STDOUT should be a table containing rows: | name | status | | handbook/handbook | inactive | | handbook/functionality-for-pages | inactive | - When I run `wp plugin activate handbook/functionality-for-pages` - Then STDOUT should not be empty + When I run `wp plugin activate handbook/functionality-for-pages` + Then STDOUT should not be empty - When I run `wp plugin list --fields=name,status` + When I run `wp plugin list --fields=name,status` Then STDOUT should be a table containing rows: | name | status | | handbook/handbook | inactive | From f334c09f0096041eac254dfb5dddc8088cd6c2a4 Mon Sep 17 00:00:00 2001 From: borekb <borekb@gmail.com> Date: Thu, 13 Nov 2014 14:45:23 +0100 Subject: [PATCH 3283/5359] Update .gitattributes WP-CLI only works well with LF line endings (see e.g. comment parsing) and the original settings cause auto-translation to CRLF on Windows. The `eol=lf` bit fixes that so that the working copy files are LF on Windows too. --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 0fdf7ac9b..a5666637c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # Auto detect text files and perform EOL normalization -* text=auto +* text=auto eol=lf From 43c56556374dee00977e448a4fc3f400b33d2dd5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 18 Nov 2014 05:34:20 -0800 Subject: [PATCH 3284/5359] Internalize these files for performance --- features/plugin.feature | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 8b578fb8e..530c217d7 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -290,7 +290,24 @@ Feature: Manage WordPress plugins Scenario: Two plugins, one directory Given a WP install - And I run `svn co https://meta.svn.wordpress.org/sites/trunk/wordpress.org/public_html/wp-content/plugins/handbook wp-content/plugins/handbook` + And a wp-content/plugins/handbook/handbook.php file: + """ + <?php + /** + * Plugin Name: Handbook + * Description: Features for a handbook, complete with glossary and table of contents + * Author: Nacin + */ + """ + And a wp-content/plugins/handbook/functionality-for-pages.php file: + """ + <?php + /** + * Plugin Name: Handbook Functionality for Pages + * Description: Adds handbook-like table of contents to all Pages for a site. Covers Table of Contents and the "watch this page" widget + * Author: Nacin + */ + """ When I run `wp plugin list --fields=name,status` Then STDOUT should be a table containing rows: From b6699b37f26ee2b23b04b0cfdb96081a0ff9860d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 18 Nov 2014 07:36:04 -0800 Subject: [PATCH 3285/5359] Version bump --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 28fe469ca..2199b643d 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.17.0' ); +define( 'WP_CLI_VERSION', '0.17.1' ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From 2fba48c7a2da53a117f6ad48b2c3939982514f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 19 Nov 2014 01:24:44 +0100 Subject: [PATCH 3286/5359] Debian package builder --- utils/wp-cli-updatedeb.sh | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 utils/wp-cli-updatedeb.sh diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh new file mode 100644 index 000000000..c4f34efb5 --- /dev/null +++ b/utils/wp-cli-updatedeb.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Package wp-cli to be installed in Debian-compatible systems. +# Only the phar file is included. +# +# VERSION :0.2 +# DATE :2014-11-19 +# AUTHOR :Viktor Szépe <viktor@szepe.net> +# LICENSE :The MIT License (MIT) +# URL :https://github.com/wp-cli/wp-cli/tree/master/utils +# BASH-VERSION :4.2+ + +# packages source path +DIR="php-wpcli" +# phar URL +PHAR="https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli.phar" + +die() { + local RET="$1" + shift + + echo -e "$@" >&2 + exit "$RET" +} + +dump_control() { + cat > DEBIAN/control <<CTRL +Package: php-wpcli +Version: 0.0.0 +Architecture: all +Maintainer: Daniel Bachhuber <daniel@handbuilt.co> +Section: php +Priority: optional +Depends: php5-cli, php5-mysql | php5-mysqlnd, mysql-client +Homepage: http://wp-cli.org/ +Description: wp-cli is a set of command-line tools for managing + WordPress installations. You can update plugins, set up multisite + installs and much more, without using a web browser. + +CTRL +} + +# deb's dir +if ! [ -d "$DIR" ]; then + mkdir "$DIR" || die 1 "Cannot create directory here: ${PWD}" +fi + +pushd "$DIR" + +# control file +if ! [ -r DEBIAN/control ]; then + mkdir DEBIAN + dump_control +fi + +# content dirs +[ -d usr/bin ] || mkdir -p usr/bin + +# download current version +wget -nv -O usr/bin/wp "$PHAR" || die 3 "Phar download failure" +chmod +x usr/bin/wp || die 4 "chmod failure" + +# get version +WPCLI_VER="$(grep -ao "define.*WP_CLI_VERSION.*;" usr/bin/wp | cut -d"'" -f4)" +[ -z "$WPCLI_VER" ] && die 5 "Cannot get wp-cli version" +echo "Current version: ${WPCLI_VER}" + +# update version +sed -i "s/^Version: .*$/Version: ${WPCLI_VER}/" DEBIAN/control || die 6 "Version update failure" + +# update MD5-s +find usr -type f -exec md5sum \{\} \; > DEBIAN/md5sums || die 7 "md5sum creation failure" + +popd + +# build package in the current diretory +WPCLI_PKG="${PWD}/php-wpcli_${WPCLI_VER}_all.deb" +fakeroot dpkg-deb --build "$DIR" "$WPCLI_PKG" || die 8 "Packaging failed" + +# optional steps +echo "sign it: dpkg-sig -k <YOUR-KEY> -s builder \"$WPCLI_PKG\"" +echo "include in your repo: pushd /var/www/<REPO-DIR>" +echo "reprepro includedeb wheezy \"$WPCLI_PKG\" && popd" From 367fb6fe7f1972586cf7c6b84391cace00e525f0 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Fri, 21 Nov 2014 21:23:18 -0500 Subject: [PATCH 3287/5359] Better 'version' support for `wp [plugin|theme] update`. See #1488. --- php/commands/plugin.php | 7 ++++--- php/commands/theme.php | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 95cd478b7..1cdaadaae 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -298,8 +298,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * : If set, all plugins that have updates will be updated. * * [--version=<version>] - * : If set, the plugin will be updated to the latest development version, - * regardless of what version is currently installed. + * : If set, the plugin will be updated to the specified version. * * [--dry-run] * : Preview which plugins would be updated. @@ -311,9 +310,11 @@ protected function install_from_repo( $slug, $assoc_args ) { * wp plugin update --all */ function update( $args, $assoc_args ) { - if ( isset( $assoc_args['version'] ) && 'dev' == $assoc_args['version'] ) { + if ( isset( $assoc_args['version'] ) ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { $this->_delete( $plugin ); + + $assoc_args['force'] = 1; $this->install( array( $plugin->name ), $assoc_args ); } } else { diff --git a/php/commands/theme.php b/php/commands/theme.php index adceda527..9a09e10f0 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -440,8 +440,7 @@ public function get( $args, $assoc_args ) { * : If set, all themes that have updates will be updated. * * [--version=<version>] - * : If set, the theme will be updated to the latest development version, - * regardless of what version is currently installed. + * : If set, the plugin will be updated to the specified version. * * [--dry-run] * : Preview which themes would be updated. @@ -453,7 +452,19 @@ public function get( $args, $assoc_args ) { * wp theme update --all */ function update( $args, $assoc_args ) { - parent::update_many( $args, $assoc_args ); + if ( isset( $assoc_args['version'] ) ) { + foreach ( $this->fetcher->get_many( $args ) as $theme ) { + $r = delete_theme( $theme->stylesheet ); + if ( is_wp_error( $r ) ) { + WP_CLI::warning( $r ); + } else { + $assoc_args['force'] = 1; + $this->install( array( $theme->stylesheet ), $assoc_args ); + } + } + } else { + parent::update_many( $args, $assoc_args ); + } } /** From 0c3c34013493ae9782656f52006d7086b1549c4b Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 23 Nov 2014 02:09:44 +0900 Subject: [PATCH 3288/5359] fix incorrect param for chmod --- php/commands/scaffold.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index babe849e4..050b81228 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -490,7 +490,7 @@ function plugin_tests( $args, $assoc_args ) { foreach ( $to_copy as $file => $dir ) { $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); if ( 'install-wp-tests.sh' === $file ) { - if ( ! $wp_filesystem->chmod( "$dir/$file", '0755' ) ) { + if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); } } @@ -632,4 +632,3 @@ private function init_wp_filesystem() { } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); - From 20017ec6ada642f28b51a840f06a971aaa59db12 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Nov 2014 07:26:27 -0800 Subject: [PATCH 3289/5359] Update version numbers to fix failing tests --- features/core.feature | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index b0cc7b5d6..7a4f8d499 100644 --- a/features/core.feature +++ b/features/core.feature @@ -270,9 +270,9 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | - | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | - | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | + | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | + | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | When I run `wp core check-update --field=version | wc -l` Then STDOUT should be: @@ -283,8 +283,8 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | - | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | + | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | + | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | When I run `wp core check-update --major --field=version | wc -l` Then STDOUT should be: @@ -295,7 +295,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | When I run `wp core check-update --minor --field=version | wc -l` Then STDOUT should be: From 4c4e0cfdab807193f2c710e73e6153fb8314770a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Nov 2014 07:42:37 -0800 Subject: [PATCH 3290/5359] Properly sort WordPress versions `version_compare()` can return `-1` or `0`, both of which are falsy. This caused inconsistent results when the WordPress API started returning versions out of order --- features/core.feature | 4 ++-- php/commands/core.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index 7a4f8d499..0a9f5af4c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -272,7 +272,7 @@ Feature: Manage WordPress installation | version | update_type | package_url | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | - | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | + | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | When I run `wp core check-update --field=version | wc -l` Then STDOUT should be: @@ -295,7 +295,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | + | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | When I run `wp core check-update --minor --field=version | wc -l` Then STDOUT should be: diff --git a/php/commands/core.php b/php/commands/core.php index dfdb15e28..85807ad80 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -52,7 +52,7 @@ function check_update( $_, $assoc_args ) { $release_data = json_decode( $response->body ); $release_versions = array_keys( (array) $release_data ); usort( $release_versions, function( $a, $b ){ - return ! version_compare( $a, $b ); + return 1 === version_compare( $a, $b ); }); $locale = get_locale(); @@ -86,6 +86,7 @@ function check_update( $_, $assoc_args ) { } if ( $updates ) { + $updates = array_reverse( $updates ); $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'version', 'update_type', 'package_url' ) From 1f7c7edc2462636a8725837508c1ea1353882618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 19 Nov 2014 01:24:44 +0100 Subject: [PATCH 3291/5359] Debian package builder --- utils/wp-cli-updatedeb.sh | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 utils/wp-cli-updatedeb.sh diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh new file mode 100644 index 000000000..c4f34efb5 --- /dev/null +++ b/utils/wp-cli-updatedeb.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Package wp-cli to be installed in Debian-compatible systems. +# Only the phar file is included. +# +# VERSION :0.2 +# DATE :2014-11-19 +# AUTHOR :Viktor Szépe <viktor@szepe.net> +# LICENSE :The MIT License (MIT) +# URL :https://github.com/wp-cli/wp-cli/tree/master/utils +# BASH-VERSION :4.2+ + +# packages source path +DIR="php-wpcli" +# phar URL +PHAR="https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli.phar" + +die() { + local RET="$1" + shift + + echo -e "$@" >&2 + exit "$RET" +} + +dump_control() { + cat > DEBIAN/control <<CTRL +Package: php-wpcli +Version: 0.0.0 +Architecture: all +Maintainer: Daniel Bachhuber <daniel@handbuilt.co> +Section: php +Priority: optional +Depends: php5-cli, php5-mysql | php5-mysqlnd, mysql-client +Homepage: http://wp-cli.org/ +Description: wp-cli is a set of command-line tools for managing + WordPress installations. You can update plugins, set up multisite + installs and much more, without using a web browser. + +CTRL +} + +# deb's dir +if ! [ -d "$DIR" ]; then + mkdir "$DIR" || die 1 "Cannot create directory here: ${PWD}" +fi + +pushd "$DIR" + +# control file +if ! [ -r DEBIAN/control ]; then + mkdir DEBIAN + dump_control +fi + +# content dirs +[ -d usr/bin ] || mkdir -p usr/bin + +# download current version +wget -nv -O usr/bin/wp "$PHAR" || die 3 "Phar download failure" +chmod +x usr/bin/wp || die 4 "chmod failure" + +# get version +WPCLI_VER="$(grep -ao "define.*WP_CLI_VERSION.*;" usr/bin/wp | cut -d"'" -f4)" +[ -z "$WPCLI_VER" ] && die 5 "Cannot get wp-cli version" +echo "Current version: ${WPCLI_VER}" + +# update version +sed -i "s/^Version: .*$/Version: ${WPCLI_VER}/" DEBIAN/control || die 6 "Version update failure" + +# update MD5-s +find usr -type f -exec md5sum \{\} \; > DEBIAN/md5sums || die 7 "md5sum creation failure" + +popd + +# build package in the current diretory +WPCLI_PKG="${PWD}/php-wpcli_${WPCLI_VER}_all.deb" +fakeroot dpkg-deb --build "$DIR" "$WPCLI_PKG" || die 8 "Packaging failed" + +# optional steps +echo "sign it: dpkg-sig -k <YOUR-KEY> -s builder \"$WPCLI_PKG\"" +echo "include in your repo: pushd /var/www/<REPO-DIR>" +echo "reprepro includedeb wheezy \"$WPCLI_PKG\" && popd" From 099f3227c5f3ab0a8174e57bd26be2f50c6bee30 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 23 Nov 2014 02:09:44 +0900 Subject: [PATCH 3292/5359] fix incorrect param for chmod --- php/commands/scaffold.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index babe849e4..050b81228 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -490,7 +490,7 @@ function plugin_tests( $args, $assoc_args ) { foreach ( $to_copy as $file => $dir ) { $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); if ( 'install-wp-tests.sh' === $file ) { - if ( ! $wp_filesystem->chmod( "$dir/$file", '0755' ) ) { + if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); } } @@ -632,4 +632,3 @@ private function init_wp_filesystem() { } WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); - From 4bf792a679d621187d1c77ed6cc5b2361c4e5283 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Nov 2014 07:26:27 -0800 Subject: [PATCH 3293/5359] Update version numbers to fix failing tests --- features/core.feature | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index b0cc7b5d6..7a4f8d499 100644 --- a/features/core.feature +++ b/features/core.feature @@ -270,9 +270,9 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | - | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | - | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | + | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | + | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | When I run `wp core check-update --field=version | wc -l` Then STDOUT should be: @@ -283,8 +283,8 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0 | major | https://wordpress.org/wordpress-4.0.zip | - | 3.9.2 | major | https://wordpress.org/wordpress-3.9.2.zip | + | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | + | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | When I run `wp core check-update --major --field=version | wc -l` Then STDOUT should be: @@ -295,7 +295,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.4 | minor | https://wordpress.org/wordpress-3.8.4.zip | + | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | When I run `wp core check-update --minor --field=version | wc -l` Then STDOUT should be: From 1ea6266d39ff9c3895d289f4e4ea060a6cb72928 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Nov 2014 07:42:37 -0800 Subject: [PATCH 3294/5359] Properly sort WordPress versions `version_compare()` can return `-1` or `0`, both of which are falsy. This caused inconsistent results when the WordPress API started returning versions out of order --- features/core.feature | 4 ++-- php/commands/core.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index 7a4f8d499..0a9f5af4c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -272,7 +272,7 @@ Feature: Manage WordPress installation | version | update_type | package_url | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | - | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | + | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | When I run `wp core check-update --field=version | wc -l` Then STDOUT should be: @@ -295,7 +295,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.1 | minor | https://wordpress.org/wordpress-3.8.1.zip | + | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | When I run `wp core check-update --minor --field=version | wc -l` Then STDOUT should be: diff --git a/php/commands/core.php b/php/commands/core.php index dfdb15e28..85807ad80 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -52,7 +52,7 @@ function check_update( $_, $assoc_args ) { $release_data = json_decode( $response->body ); $release_versions = array_keys( (array) $release_data ); usort( $release_versions, function( $a, $b ){ - return ! version_compare( $a, $b ); + return 1 === version_compare( $a, $b ); }); $locale = get_locale(); @@ -86,6 +86,7 @@ function check_update( $_, $assoc_args ) { } if ( $updates ) { + $updates = array_reverse( $updates ); $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'version', 'update_type', 'package_url' ) From 638014639f4eb3fea3089fed4973d5778ad54dff Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Mon, 24 Nov 2014 16:50:11 -0500 Subject: [PATCH 3295/5359] Behat test for `wp plugin update --version`. See #1510. --- features/plugin.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 530c217d7..c79aee297 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -324,3 +324,16 @@ Feature: Manage WordPress plugins | handbook/handbook | inactive | | handbook/functionality-for-pages | active | + Scenario: Install a plugin, then update to a specific version of that plugin + Given a WP install + + When I run `wp plugin install akismet --version=2.5.7 --force` + Then STDOUT should not be empty + + When I run `wp plugin update akismet --version=2.6.0` + Then STDOUT should not be empty + + When I run `wp plugin list --fields=name,version` + Then STDOUT should be a table containing rows: + | name | version | + | akismet | 2.6.0 | From e492c44c2c5224a8dcedd8f77f4e5835688f1232 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Mon, 24 Nov 2014 16:50:36 -0500 Subject: [PATCH 3296/5359] Behat test for `wp theme update --version`. See #1510. --- features/theme.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 6ad011a7e..fde24c993 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -211,3 +211,17 @@ Feature: Manage WordPress themes """ Error: This is not a multisite install. """ + + Scenario: Install a theme, then update to a specific version of that theme + Given a WP install + + When I run `wp theme install p2 --version=1.4.1` + Then STDOUT should not be empty + + When I run `wp theme update p2 --version=1.4.2` + Then STDOUT should not be empty + + When I run `wp theme list --fields=name,version` + Then STDOUT should be a table containing rows: + | name | version | + | p2 | 1.4.2 | From dbf252bf338c7adf138b691fc60bcfeeac15e0bb Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 24 Nov 2014 22:27:40 -0200 Subject: [PATCH 3297/5359] add global parameters for all subcommands --- features/help.feature | 6 ++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 37 ++++++++++++++++++++++ php/WP_CLI/Dispatcher/RootCommand.php | 25 +-------------- templates/man-params.mustache | 8 ++++- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/features/help.feature b/features/help.feature index b4551a60d..e94455d51 100644 --- a/features/help.feature +++ b/features/help.feature @@ -15,6 +15,12 @@ Feature: Get help about WP-CLI commands When I run `wp help help` Then STDOUT should not be empty + When I run `wp help help` + Then STDOUT should contain: + """ + GLOBAL PARAMETERS + """ + When I run `wp post list --post_type=post --posts_per_page=5 --help` Then STDOUT should contain: """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 7296652f7..cc7258d03 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -2,6 +2,8 @@ namespace WP_CLI\Dispatcher; +use \WP_CLI\Utils; + /** * A non-leaf node in the command tree. * Contains one or more Subcommands. @@ -28,6 +30,7 @@ public function __construct( $parent, $name, $docparser ) { $this->shortdesc = $docparser->get_shortdesc(); $this->longdesc = $docparser->get_longdesc(); + $this->longdesc .= $this->get_global_params(); $this->docparser = $docparser; $when_to_invoke = $docparser->get_tag( 'when' ); @@ -221,5 +224,39 @@ private static function get_aliases( $subcommands ) { public function get_alias() { return false; } + + /*** + * Get the list of global parameters + * + * @param string $root_command whether to include or not root command specific description + * @return string + */ + protected function get_global_params( $root_command = false ) { + $binding = array(); + $binding['root_command'] = $root_command; + + foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { + if ( false === $details['runtime'] ) + continue; + + if ( isset( $details['deprecated'] ) ) + continue; + + if ( isset( $details['hidden'] ) ) + continue; + + if ( true === $details['runtime'] ) + $synopsis = "--[no-]$key"; + else + $synopsis = "--$key" . $details['runtime']; + + $binding['parameters'][] = array( + 'synopsis' => $synopsis, + 'desc' => $details['desc'] + ); + } + + return Utils\mustache_render( 'man-params.mustache', $binding ); + } } diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index d5c19826b..fb730da07 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -25,30 +25,7 @@ public function __construct() { * @return string */ public function get_longdesc() { - $binding = array(); - - foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { - if ( false === $details['runtime'] ) - continue; - - if ( isset( $details['deprecated'] ) ) - continue; - - if ( isset( $details['hidden'] ) ) - continue; - - if ( true === $details['runtime'] ) - $synopsis = "--[no-]$key"; - else - $synopsis = "--$key" . $details['runtime']; - - $binding['parameters'][] = array( - 'synopsis' => $synopsis, - 'desc' => $details['desc'] - ); - } - - return Utils\mustache_render( 'man-params.mustache', $binding ); + return $this->get_global_params( true ); } /** diff --git a/templates/man-params.mustache b/templates/man-params.mustache index dd848d83f..e1417bd7c 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -1,3 +1,7 @@ +{{^root_command}} + + +{{/root_command}} ## GLOBAL PARAMETERS {{#parameters}} @@ -5,4 +9,6 @@ {{desc}} {{/parameters}} -Run 'wp help <command>' to get more information on a specific command. +{{#root_command}} + Run 'wp help <command>' to get more information on a specific command. +{{/root_command}} \ No newline at end of file From 16bf57219ca3e10be351aa8b293b06932d0c661d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 24 Nov 2014 22:31:56 -0200 Subject: [PATCH 3298/5359] add missing new line --- templates/man-params.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/man-params.mustache b/templates/man-params.mustache index e1417bd7c..a27f4d846 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -11,4 +11,4 @@ {{/parameters}} {{#root_command}} Run 'wp help <command>' to get more information on a specific command. -{{/root_command}} \ No newline at end of file +{{/root_command}} From a74a434dd6d97efe0fafdde9bdbfdf8842e2c1ee Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 26 Nov 2014 11:45:11 -0200 Subject: [PATCH 3299/5359] define WPLANG only for WP < 4.0 --- php/commands/core.php | 9 +++++++++ templates/wp-config.mustache | 2 ++ 2 files changed, 11 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 85807ad80..a096dd690 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -311,6 +311,9 @@ public function config( $_, $assoc_args ) { WP_CLI::error( "The 'wp-config.php' file already exists." ); } + $versions_path = ABSPATH . 'wp-includes/version.php'; + include $versions_path; + $defaults = array( 'dbhost' => 'localhost', 'dbpass' => '', @@ -344,6 +347,12 @@ public function config( $_, $assoc_args ) { 'https://api.wordpress.org/secret-key/1.1/salt/' ); } + if ( version_compare( $wp_version, '4.0', '<' ) ) { + $assoc_args['add-wplang'] = true; + } else { + $assoc_args['add-wplang'] = false; + } + $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); $bytes_written = file_put_contents( ABSPATH . 'wp-config.php', $out ); diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 6951c9bb0..104a37946 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -26,7 +26,9 @@ define('DB_COLLATE', '{{dbcollate}}'); $table_prefix = '{{dbprefix}}'; +{{#add-wplang}} define('WPLANG', '{{locale}}'); +{{/add-wplang}} {{extra-php}} From 3228254276ac4554a4b1739c723830007e6753c7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 28 Nov 2014 08:54:20 -0200 Subject: [PATCH 3300/5359] add tests to check if WPLANG is defined only for WP < 4.0 --- features/core.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/core.feature b/features/core.feature index 0a9f5af4c..47f385f92 100644 --- a/features/core.feature +++ b/features/core.feature @@ -67,6 +67,10 @@ Feature: Manage WordPress installation """ define( 'WP_DEBUG_LOG', true ); """ + And the wp-config.php file should not contain: + """ + define( 'WPLANG', '' ); + """ When I try the previous command again Then the return code should be 1 @@ -82,6 +86,16 @@ Feature: Manage WordPress installation define('AUTH_SALT', """ + Scenario: Define WPLANG when running WP < 4.0 + Given an empty directory + And I run `wp core download --version=3.9 --force` + + When I run `wp core config {CORE_CONFIG_SETTINGS}` + Then the wp-config.php file should contain: + """ + define('WPLANG', ''); + """ + Scenario: Database doesn't exist Given an empty directory And WP files From 27b4f78971d40462fbf1653f9cee2c0b0f009cd7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 28 Nov 2014 10:55:10 -0800 Subject: [PATCH 3301/5359] Don't allow active language to be uninstalled --- features/core.feature | 12 ++++++++++++ php/WP_CLI/CommandWithTranslation.php | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/features/core.feature b/features/core.feature index 0a9f5af4c..6523036aa 100644 --- a/features/core.feature +++ b/features/core.feature @@ -484,3 +484,15 @@ Feature: Manage WordPress installation Success: Language activated. """ + @require-wp-4.0 + Scenario: Don't allow active language to be uninstalled + Given a WP install + + When I run `wp core language install en_GB --activate` + Then STDOUT should not be empty + + When I try `wp core language uninstall en_GB` + Then STDERR should be: + """ + Warning: The 'en_GB' language is active. + """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index c7e544f5e..06aa8c6ab 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -212,6 +212,12 @@ public function uninstall( $args, $assoc_args ) { \WP_CLI::error( "No files found in language directory." ); } + $current_locale = get_locale(); + if ( $language_code === $current_locale ) { + \WP_CLI::warning( "The '{$language_code}' language is active." ); + exit; + } + // As of WP 4.0, no API for deleting a language pack WP_Filesystem(); $deleted = false; From 1098d4070e31f5d9dd2b28750fcef8ec0913df5d Mon Sep 17 00:00:00 2001 From: spacedmonkey <spacedmonkey2@gmail.com> Date: Sun, 30 Nov 2014 22:12:22 +0000 Subject: [PATCH 3302/5359] Added new subcommands wp user term and wp post term --- features/post-term.feature | 86 ++++++++++++ features/user-term.feature | 102 ++++++++++++++ php/WP_CLI/CommandWithTerms.php | 226 ++++++++++++++++++++++++++++++++ php/commands/post.php | 27 ++++ php/commands/user.php | 18 +++ 5 files changed, 459 insertions(+) create mode 100644 features/post-term.feature create mode 100644 features/user-term.feature create mode 100644 php/WP_CLI/CommandWithTerms.php diff --git a/features/post-term.feature b/features/post-term.feature new file mode 100644 index 000000000..f23dd11df --- /dev/null +++ b/features/post-term.feature @@ -0,0 +1,86 @@ +Feature: Manage post term + + Scenario: Postterm CRUD + Given a WP install + + When I run `wp post term add 1 category foo` + Then STDOUT should be: + """ + Success: Added term. + """ + + When I run `wp post term list 1 category --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | foo | foo | category | + + When I run `wp post term add 1 category bar` + Then STDOUT should be: + """ + Success: Added term. + """ + + When I run `wp post term list 1 category --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | foo | foo | category | + | bar | bar | category | + + When I run `wp post term set 1 category new` + Then STDOUT should be: + """ + Success: Set terms. + """ + + When I run `wp post term list 1 category --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | new | new | category | + + When I run `wp post term remove 1 category new` + Then STDOUT should be: + """ + Success: Deleted term. + """ + + Scenario: Multiple post term + Given a WP install + + When I run `wp post term add 1 category apple` + And I run `wp post term add 1 category apple` + Then STDOUT should be: + """ + Success: Added term. + """ + + When I run `wp post term set 1 category 'apple1, apple2'` + Then STDOUT should be: + """ + Success: Set terms. + """ + + When I run `wp post term list 1 category --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | apple1 | apple1 | category | + | apple2 | apple2 | category | + + Scenario: Invalid Post ID + Given a WP install + + When I try `wp post term add 99999 category boo` + Then the return code should be 1 + And STDERR should be: + """ + Error: Could not find the post with ID 99999. + """ + + Scenario: Postterm Add invalid tax + Given a WP install + + When I try `wp post term add 1 foo2 boo` + Then the return code should be 1 + And STDERR should be: + """ + Error: Invalid taxonomy. + """ diff --git a/features/user-term.feature b/features/user-term.feature new file mode 100644 index 000000000..8fd84eddc --- /dev/null +++ b/features/user-term.feature @@ -0,0 +1,102 @@ +Feature: Manage user term + + Scenario: Userterm CRUD + Given a WP install + And a wp-content/plugins/test-add-tax/plugin.php file: + """ + <?php + // Plugin Name: Test Add Tax + + function add_cli_tax(){ + register_taxonomy( 'user_type', 'user' ); + } + + add_action('init','add_cli_tax'); + """ + And I run `wp plugin activate test-add-tax` + + + When I run `wp user term add 1 user_type foo` + Then STDOUT should be: + """ + Success: Added term. + """ + + When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | foo | foo | user_type | + + When I run `wp user term add 1 user_type bar` + Then STDOUT should be: + """ + Success: Added term. + """ + + When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | foo | foo | user_type | + | bar | bar | user_type | + + When I run `wp user term set 1 user_type new` + Then STDOUT should be: + """ + Success: Set terms. + """ + + When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` + Then STDOUT should be a table containing rows: + | name | slug | taxonomy | + | new | new | user_type | + + When I run `wp user term remove 1 user_type new` + Then STDOUT should be: + """ + Success: Deleted term. + """ + + Scenario: Multiple user term + Given a WP install + + And a wp-content/plugins/test-add-tax/plugin.php file: + """ + <?php + // Plugin Name: Test Add Tax + + function add_cli_tax(){ + register_taxonomy( 'user_type', 'user' ); + } + + add_action('init','add_cli_tax'); + """ + And I run `wp plugin activate test-add-tax` + + When I run `wp user term add 1 user_type apple` + And I run `wp user term add 1 user_type apple` + Then STDOUT should contain: + """ + Success: Added term. + """ + + When I run `wp user term set 1 user_type 'apple1, apple2'` + Then STDOUT should contain: + """ + Success: Set terms. + """ + + When I run `wp user term list 1 user_type --format=json --fields=name,slug,taxonomy` + Then STDOUT should contain: + """ + [{"name":"apple1","slug":"apple1","taxonomy":"user_type"},{"name":"apple2","slug":"apple2","taxonomy":"user_type"}] + """ + + Scenario: Userterm Add invalid tax + Given a WP install + + When I try `wp user term add 1 boo foo2` + Then the return code should be 1 + And STDERR should be: + """ + Error: Invalid taxonomy. + """ \ No newline at end of file diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php new file mode 100644 index 000000000..4c8b0c8c5 --- /dev/null +++ b/php/WP_CLI/CommandWithTerms.php @@ -0,0 +1,226 @@ +<?php + +namespace WP_CLI; + +use WP_CLI; + +/** + * Base class for WP-CLI commands that deal with terms + * + * @package wp-cli + */ +abstract class CommandWithTerms extends \WP_CLI_Command { + + /** + * @var string $object_type WordPress' expected name for the object. + */ + protected $obj_type; + + /** + * @var string $object_id WordPress' object id. + */ + protected $obj_id; + + /** + * @var array $obj_fields Default fields to display for each object. + */ + protected $obj_fields = array( + "term_id", + "name", + "slug", + "taxonomy" + ); + + /** + * List all terms associated with an object. + * + * <id> + * : ID for the object. + * + * <taxonomy>... + * : One or more taxonomies to list. + * + * [--fields=<fields>] + * : Limit the output to specific row fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each term: + * + * * term_id + * * name + * * slug + * * taxonomy + * + * These fields are optionally available: + * + * * term_taxonomy_id + * * description + * * term_group + * * parent + * * count + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + $object_id = array_shift( $args ); + $taxonomy_names = $args; + + $this->set_obj_id( $object_id ); + + $items = wp_get_object_terms( $object_id, $taxonomy_names ); + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $items ); + + } + + + /** + * Remove a term. + * + * <id> + * : The ID of the object. + * + * <taxonomy> + * : The name of the taxonomy type to deleted. + * + * <term> + * : The name of the term to deleted. + */ + public function remove( $args, $assoc_args ) { + list( $object_id, $taxonomy, $term ) = $args; + + $this->set_obj_id( $object_id ); + + $this->taxonomy_exists( $taxonomy ); + + $terms = explode( ",", $term ); + + $result = wp_remove_object_terms( $object_id, $terms, $taxonomy ); + + if ( ! is_wp_error( $result ) ) { + WP_CLI::success( "Deleted term." ); + } else { + WP_CLI::error( "Failed to delete term." ); + } + } + + /** + * Add a term. Appends to existed + * + * <id> + * : The ID of the object. + * + * <taxonomy> + * : The name of the taxonomy type to be added. + * + * <term> + * : The name of the term to be added. + */ + public function add( $args, $assoc_args ) { + list( $object_id, $taxonomy, $term ) = $args; + + $this->set_obj_id( $object_id ); + + $this->taxonomy_exists( $taxonomy ); + + $terms = explode( ",", $term ); + + $result = wp_set_object_terms( $object_id, $terms, $taxonomy, true ); + + if ( ! is_wp_error( $result ) ) { + WP_CLI::success( "Added term." ); + } else { + WP_CLI::error( "Failed to add term." ); + } + } + + /** + * Set terms. Replaces existing terms + * + * <id> + * : The ID of the object. + * + * <taxonomy> + * : The name of the taxonomy type to be updated. + * + * <term> + * : The name of the term to be updated. + */ + public function set( $args, $assoc_args ) { + list( $object_id, $taxonomy, $term ) = $args; + + $this->set_obj_id( $object_id ); + + $this->taxonomy_exists( $taxonomy ); + + $terms = explode( ",", $term ); + + $result = wp_set_object_terms( $object_id, $terms, $taxonomy, false ); + + if ( ! is_wp_error( $result ) ) { + WP_CLI::success( "Set terms." ); + } else { + WP_CLI::error( "Failed to set terms." ); + } + } + + /** + * Check if taxonomy exists + * + * @param $taxonomy + */ + protected function taxonomy_exists( $taxonomy ) { + + $taxonomy_names = get_object_taxonomies( $this->get_object_type() ); + + if ( ! in_array( $taxonomy, $taxonomy_names ) ) { + WP_CLI::error( 'Invalid taxonomy.' ); + } + } + + /** + * Set obj_id Class variable + * + * @param string $obj_id + */ + protected function set_obj_id( $obj_id ) { + $this->obj_id = $obj_id; + } + + /** + * Get obj_id Class variable + * + * @return string + */ + protected function get_obj_id() { + return $this->obj_id; + } + + + /** + * Get obj_type Class variable + * + * @return string $obj_type + */ + protected function get_object_type() { + return $this->obj_type; + } + + /** + * Get Formatter object based on supplied parameters. + * + * @param array $assoc_args Parameters passed to command. Determines formatting. + * + * @return WP_CLI\Formatter + */ + protected function get_formatter( &$assoc_args ) { + return new WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); + } +} + diff --git a/php/commands/post.php b/php/commands/post.php index 954766804..2a9f50e14 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -480,6 +480,33 @@ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; } +/** + * Manage post terms. + * + * ## OPTIONS + * + * [--format=json] + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp post term set 123 test category + */ +class Post_Term_Command extends \WP_CLI\CommandWithTerms { + protected $obj_type = 'post'; + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\Post; + } + + protected function get_object_type() { + $post = $this->fetcher->get_check( $this->get_obj_id() ); + + return $post->post_type; + } +} + WP_CLI::add_command( 'post', 'Post_Command' ); WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); +WP_CLI::add_command( 'post term', 'Post_Term_Command' ); diff --git a/php/commands/user.php b/php/commands/user.php index b9575d3a4..698692bfc 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -825,6 +825,24 @@ private function replace_login_with_user_id( $args ) { } +/** + * Manage user terms. + * + * ## OPTIONS + * + * [--format=json] + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp user term set 123 test category + */ +class User_Term_Command extends \WP_CLI\CommandWithTerms { + protected $obj_type = 'user'; +} + + WP_CLI::add_command( 'user', 'User_Command' ); WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); +WP_CLI::add_command( 'user term', 'User_Term_Command' ); From 05d79b50cb64f0b26b85680f05997be8ec338327 Mon Sep 17 00:00:00 2001 From: spacedmonkey <spacedmonkey2@gmail.com> Date: Mon, 1 Dec 2014 01:29:34 +0000 Subject: [PATCH 3303/5359] Improved tests, formatting and backwards compatibility for post / user term --- features/post-term.feature | 21 ++++-- features/user-term.feature | 19 ++++-- php/WP_CLI/CommandWithTerms.php | 115 +++++++++++++++++++++++++++----- php/commands/post.php | 4 -- php/commands/user.php | 4 -- 5 files changed, 126 insertions(+), 37 deletions(-) diff --git a/features/post-term.feature b/features/post-term.feature index f23dd11df..20ab616b2 100644 --- a/features/post-term.feature +++ b/features/post-term.feature @@ -32,10 +32,11 @@ Feature: Manage post term Success: Set terms. """ - When I run `wp post term list 1 category --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | new | new | category | + When I run `wp post term list 1 category --fields=name,slug,taxonomy --format=count` + Then STDOUT should be: + """ + 1 + """ When I run `wp post term remove 1 category new` Then STDOUT should be: @@ -43,6 +44,12 @@ Feature: Manage post term Success: Deleted term. """ + When I run `wp post term list 1 category --fields=name,slug,taxonomy --format=count` + Then STDOUT should be: + """ + 0 + """ + Scenario: Multiple post term Given a WP install @@ -53,7 +60,7 @@ Feature: Manage post term Success: Added term. """ - When I run `wp post term set 1 category 'apple1, apple2'` + When I run `wp post term set 1 category apple1 apple2` Then STDOUT should be: """ Success: Set terms. @@ -73,7 +80,7 @@ Feature: Manage post term And STDERR should be: """ Error: Could not find the post with ID 99999. - """ + """ Scenario: Postterm Add invalid tax Given a WP install @@ -83,4 +90,4 @@ Feature: Manage post term And STDERR should be: """ Error: Invalid taxonomy. - """ + """ diff --git a/features/user-term.feature b/features/user-term.feature index 8fd84eddc..3895f20a2 100644 --- a/features/user-term.feature +++ b/features/user-term.feature @@ -45,10 +45,11 @@ Feature: Manage user term Success: Set terms. """ - When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | new | new | user_type | + When I run `wp user term list 1 user_type --fields=name,slug,taxonomy --format=count` + Then STDOUT should be: + """ + 1 + """ When I run `wp user term remove 1 user_type new` Then STDOUT should be: @@ -56,6 +57,12 @@ Feature: Manage user term Success: Deleted term. """ + When I run `wp user term list 1 user_type --fields=name,slug,taxonomy --format=count` + Then STDOUT should be: + """ + 0 + """ + Scenario: Multiple user term Given a WP install @@ -79,7 +86,7 @@ Feature: Manage user term Success: Added term. """ - When I run `wp user term set 1 user_type 'apple1, apple2'` + When I run `wp user term set 1 user_type apple1 apple2` Then STDOUT should contain: """ Success: Set terms. @@ -99,4 +106,4 @@ Feature: Manage user term And STDERR should be: """ Error: Invalid taxonomy. - """ \ No newline at end of file + """ \ No newline at end of file diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index 4c8b0c8c5..1ba36170f 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -89,19 +89,19 @@ public function list_( $args, $assoc_args ) { * <taxonomy> * : The name of the taxonomy type to deleted. * - * <term> - * : The name of the term to deleted. + * <term>... + * : The name of the term or terms to deleted. */ public function remove( $args, $assoc_args ) { - list( $object_id, $taxonomy, $term ) = $args; + $object_id = array_shift( $args ); + $taxonomy = array_shift( $args ); + $terms = $args; $this->set_obj_id( $object_id ); $this->taxonomy_exists( $taxonomy ); - $terms = explode( ",", $term ); - - $result = wp_remove_object_terms( $object_id, $terms, $taxonomy ); + $result = self::wp_remove_object_terms( $object_id, $terms, $taxonomy ); if ( ! is_wp_error( $result ) ) { WP_CLI::success( "Deleted term." ); @@ -119,18 +119,18 @@ public function remove( $args, $assoc_args ) { * <taxonomy> * : The name of the taxonomy type to be added. * - * <term> - * : The name of the term to be added. + * <term>... + * : The name of the term or terms to be added. */ public function add( $args, $assoc_args ) { - list( $object_id, $taxonomy, $term ) = $args; + $object_id = array_shift( $args ); + $taxonomy = array_shift( $args ); + $terms = $args; $this->set_obj_id( $object_id ); $this->taxonomy_exists( $taxonomy ); - $terms = explode( ",", $term ); - $result = wp_set_object_terms( $object_id, $terms, $taxonomy, true ); if ( ! is_wp_error( $result ) ) { @@ -149,18 +149,18 @@ public function add( $args, $assoc_args ) { * <taxonomy> * : The name of the taxonomy type to be updated. * - * <term> - * : The name of the term to be updated. + * <term>... + * : The name of the term or terms to be updated. */ public function set( $args, $assoc_args ) { - list( $object_id, $taxonomy, $term ) = $args; + $object_id = array_shift( $args ); + $taxonomy = array_shift( $args ); + $terms = $args; $this->set_obj_id( $object_id ); $this->taxonomy_exists( $taxonomy ); - $terms = explode( ",", $term ); - $result = wp_set_object_terms( $object_id, $terms, $taxonomy, false ); if ( ! is_wp_error( $result ) ) { @@ -170,6 +170,89 @@ public function set( $args, $assoc_args ) { } } + + /** + * Remove term(s) associated with a given object. + * + * + * @global wpdb $wpdb WordPress database abstraction object. + * + * @param int $object_id The ID of the object from which the terms will be removed. + * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove. + * @param array|string $taxonomy Taxonomy name. + * @return bool|WP_Error True on success, false or WP_Error on failure. + */ + private static function wp_remove_object_terms( $object_id, $terms, $taxonomy ) { + global $wpdb; + + // Remove notices in below 3.6 and support backwards compatibility + + if( function_exists( 'wp_remove_object_terms' ) ){ + return wp_remove_object_terms( $object_id, $terms, $taxonomy ); + } + + $object_id = (int) $object_id; + + if ( ! taxonomy_exists( $taxonomy ) ) { + return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) ); + } + + if ( ! is_array( $terms ) ) { + $terms = array( $terms ); + } + + $tt_ids = array(); + + foreach ( (array) $terms as $term ) { + if ( ! strlen( trim( $term ) ) ) { + continue; + } + + if ( ! $term_info = term_exists( $term, $taxonomy ) ) { + // Skip if a non-existent term ID is passed. + if ( is_int( $term ) ) { + continue; + } + } + + if ( is_wp_error( $term_info ) ) { + return $term_info; + } + + $tt_ids[] = $term_info['term_taxonomy_id']; + } + + if ( $tt_ids ) { + $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'"; + + /** + * Fires immediately before an object-term relationship is deleted. + * + * @since 2.9.0 + * + * @param int $object_id Object ID. + * @param array $tt_ids An array of term taxonomy IDs. + */ + do_action( 'delete_term_relationships', $object_id, $tt_ids ); + $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); + + /** + * Fires immediately after an object-term relationship is deleted. + * + * @since 2.9.0 + * + * @param int $object_id Object ID. + * @param array $tt_ids An array of term taxonomy IDs. + */ + do_action( 'deleted_term_relationships', $object_id, $tt_ids ); + wp_update_term_count( $tt_ids, $taxonomy ); + + return (bool) $deleted; + } + + return false; + } + /** * Check if taxonomy exists * diff --git a/php/commands/post.php b/php/commands/post.php index 2a9f50e14..a5977e565 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -483,10 +483,6 @@ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { /** * Manage post terms. * - * ## OPTIONS - * - * [--format=json] - * : Encode/decode values as JSON. * * ## EXAMPLES * diff --git a/php/commands/user.php b/php/commands/user.php index 698692bfc..76a347fac 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -828,10 +828,6 @@ private function replace_login_with_user_id( $args ) { /** * Manage user terms. * - * ## OPTIONS - * - * [--format=json] - * : Encode/decode values as JSON. * * ## EXAMPLES * From 55ed9fd1bf9ab19696a0340e3769cb21b6ce2f59 Mon Sep 17 00:00:00 2001 From: mikey dubs <mike@herebox.org> Date: Sun, 30 Nov 2014 16:32:30 -0800 Subject: [PATCH 3304/5359] install-wp-tests.sh svn wget https wordpress.org Use https for requests to wordpress.org Fixes svn checkout currently failing using http like: svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ svn: E175002: Unable to connect to a repository at URL 'http://develop.svn.wordpress.org/trunk/tests/phpunit/includes' github issue wp-cli/wp-cli#1529 --- templates/install-wp-tests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 1e39064a5..b9ddf1f06 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -25,7 +25,7 @@ install_wp() { local ARCHIVE_NAME="wordpress-$WP_VERSION" fi - wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz + wget -nv -O /tmp/wordpress.tar.gz https://wordpress.org/${ARCHIVE_NAME}.tar.gz tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR wget -nv -O $WP_CORE_DIR/wp-content/db.php https://raw.github.com/markoheijnen/wp-mysqli/master/db.php @@ -42,9 +42,9 @@ install_test_suite() { # set up testing suite mkdir -p $WP_TESTS_DIR cd $WP_TESTS_DIR - svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ + svn co --quiet https://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ - wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php + wget -nv -O wp-tests-config.php https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php From 3035f78d3e61762526d998a39e09f514e1fcb000 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Dec 2014 16:07:39 -0800 Subject: [PATCH 3305/5359] Tests to establish errors in #1427 --- features/core.feature | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/features/core.feature b/features/core.feature index 8fbe329db..dfd8d408a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -510,3 +510,59 @@ Feature: Manage WordPress installation """ Warning: The 'en_GB' language is active. """ + + Scenario: Ensure file cache isn't corrupted by core update, part one + Given a WP install + And an empty cache + + When I run `wp core update --version=4.0 --force` + Then STDOUT should contain: + """ + Success: WordPress updated successfully + """ + + When I run `wp core version` + Then STDOUT should be: + """ + 4.0 + """ + + When I run `wp core download --version=4.0 --force` + Then STDOUT should contain: + """ + Success: WordPress downloaded + """ + + When I run `wp core version` + Then STDOUT should be: + """ + 4.0 + """ + + Scenario: Ensure file cache isn't corrupted by core update, part two + Given a WP install + And an empty cache + + When I run `wp core download --version=4.0 --force` + Then STDOUT should contain: + """ + Success: WordPress downloaded + """ + + When I run `wp core version` + Then STDOUT should be: + """ + 4.0 + """ + + When I run `wp core update --version=4.0 --force` + Then STDOUT should contain: + """ + Success: WordPress updated successfully + """ + + When I run `wp core version` + Then STDOUT should be: + """ + 4.0 + """ From 07fc75513c29c19583e0ec5659e0e3db2ba4f4a1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Dec 2014 16:18:22 -0800 Subject: [PATCH 3306/5359] If there's a bad cache, fall back to downloading fresh --- features/core.feature | 4 ++++ php/commands/core.php | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index dfd8d408a..896ad52bf 100644 --- a/features/core.feature +++ b/features/core.feature @@ -532,6 +532,10 @@ Feature: Manage WordPress installation """ Success: WordPress downloaded """ + And STDERR should contain: + """ + Warning: Extraction failed, downloading a new copy... + """ When I run `wp core version` Then STDOUT should be: diff --git a/php/commands/core.php b/php/commands/core.php index a096dd690..73200db38 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -150,10 +150,18 @@ public function download( $args, $assoc_args ) { $cache_key = "core/$locale-$version.tar.gz"; $cache_file = $cache->has($cache_key); + $bad_cache = false; if ( $cache_file ) { WP_CLI::log( "Using cached file '$cache_file'..." ); - self::_extract( $cache_file, ABSPATH ); - } else { + try{ + self::_extract( $cache_file, ABSPATH ); + } catch ( Exception $e ) { + WP_CLI::warning( "Extraction failed, downloading a new copy..." ); + $bad_cache = true; + } + } + + if ( ! $cache_file || $bad_cache ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; From f16b0e6e2bf3f02e271380b7c23c0b75f5e7d156 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Dec 2014 16:25:35 -0800 Subject: [PATCH 3307/5359] Persist package file extension in `WP_CLI\CoreUpgrader` `wp core update` uses ZIP files, while `wp core download` uses gzipped TAR files. Renaming ZIP files to `.tar.gz` causes nasty bugs. Let's keep them cached separately. --- features/core.feature | 15 ++------------- php/WP_CLI/CoreUpgrader.php | 8 +++++--- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/features/core.feature b/features/core.feature index 896ad52bf..8ba517e5a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -511,21 +511,10 @@ Feature: Manage WordPress installation Warning: The 'en_GB' language is active. """ - Scenario: Ensure file cache isn't corrupted by core update, part one + Scenario: Ensure file cache isn't corrupted by a ZIP masquerading as a gzipped TAR, part one Given a WP install And an empty cache - - When I run `wp core update --version=4.0 --force` - Then STDOUT should contain: - """ - Success: WordPress updated successfully - """ - - When I run `wp core version` - Then STDOUT should be: - """ - 4.0 - """ + And I run `mkdir -p {SUITE_CACHE_DIR}/core; wget -O {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz https://wordpress.org/wordpress-4.0.zip` When I run `wp core download --version=4.0 --force` Then STDOUT should contain: diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index d3d3692e4..e156649f5 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -32,11 +32,13 @@ function download_package( $package ) { if ( empty( $package ) ) return new WP_Error( 'no_package', $this->strings['no_package'] ); - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + $ext = pathinfo( $package, PATHINFO_EXTENSION ); + + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; $cache = WP_CLI::get_cache(); $update = $GLOBALS['wp_cli_update_obj']; - $cache_key = "core/{$update->locale}-{$update->version}.tar.gz"; + $cache_key = "core/{$update->locale}-{$update->version}.{$ext}"; $cache_file = $cache->has( $cache_key ); if ( $cache_file ) { @@ -46,7 +48,7 @@ function download_package( $package ) { } else { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; $headers = array('Accept' => 'application/json'); $options = array( From d348f0821d936e875c2274e612b4e6070fddf93b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 2 Dec 2014 07:22:30 -0800 Subject: [PATCH 3308/5359] Update cache was changed to ZIP --- features/core.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 8ba517e5a..c68af4ba5 100644 --- a/features/core.feature +++ b/features/core.feature @@ -376,7 +376,7 @@ Feature: Manage WordPress installation When I run `wp core update --version=3.8.1 --force` Then STDOUT should contain: """ - Using cached file '{SUITE_CACHE_DIR}/core/en_US-3.8.1.tar.gz'... + Using cached file '{SUITE_CACHE_DIR}/core/en_US-3.8.1.zip'... """ And STDOUT should not contain: """ From 2d4aa021efb6dbe25a148078150babcd551312b3 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Tue, 2 Dec 2014 18:08:26 +0000 Subject: [PATCH 3309/5359] Implement #522 --- php/commands/cli.php | 101 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index deb9b86f9..d6fe42819 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -107,6 +107,97 @@ private function same_minor_release( $release_parts, $updates ) { * @subcommand check-update */ function check_update( $_, $assoc_args ) { + $updates = $this->get_updates( $assoc_args ); + + if ( $updates ) { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'update_type', 'package_url' ) + ); + $formatter->display_items( $updates ); + } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + } + } + + /** + * Fetch most recent update matching the requirements. Returns the available versions if there are updates, or empty if no update available. + * + * ## OPTIONS + * + * [--patch] + * : Compare only the first two parts of the version number. + * + * [--minor] + * : Compare only the first part of the version number. + * + * [--yes] + * : Do not prompt for confirmation + * + * @subcommand self-update + */ + function self_update( $_, $assoc_args ) { + if ( 0 !== strpos( WP_CLI_ROOT, 'phar://' ) ) { + WP_CLI::error( "You can only self-update PHARs" ); + } + + $old_phar = realpath( $_SERVER['argv'][0] ); + + if ( ! is_writable( $old_phar ) ) { + WP_CLI::error( sprintf( "%s is not writable by current user", $old_phar ) ); + } + + $updates = $this->get_updates( $assoc_args ); + + if ( $updates ) { + $newest = $updates[0]; + + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); + + $download_url = $newest['package_url']; + + WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); + + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.phar'; + + $headers = array(); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); + + Utils\http_request( 'GET', $download_url, null, $headers, $options ); + + exec( "php $temp --version", $output, $status ); + + if ( 0 !== $status ) { + WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); + } + + WP_CLI::log( 'New version works. Proceeding to replace.' ); + + $mode = fileperms( $old_phar ) & 511; + + if ( false === @chmod( $temp, $mode ) ) { + WP_CLI::error( sprintf( "Cannot chmod %s", $temp ) ); + } + + class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class + + if ( false === @rename( $temp, $old_phar ) ) { + WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); + } + + WP_CLI::success( sprintf( 'Successfully update WP-CLI to %s', $newest['version'] ) ); + } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + } + } + + /** + * Returns update information + */ + private function get_updates( $assoc_args ) { $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; $options = array( @@ -155,15 +246,7 @@ function check_update( $_, $assoc_args ) { } } - if ( $updates ) { - $formatter = new \WP_CLI\Formatter( - $assoc_args, - array( 'version', 'update_type', 'package_url' ) - ); - $formatter->display_items( $updates ); - } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { - WP_CLI::success( "WP-CLI is at the latest version." ); - } + return $updates; } /** From 777218040353a8c3b5bd002a47c6dd7c16b4beab Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Wed, 3 Dec 2014 09:55:52 +0000 Subject: [PATCH 3310/5359] Refactoring and better errors Changes to WP_CLI::error(): - can now take an array of lines, which will be printed in a red box, similar to Composer's exceptions - new boolean $exit param - if false will not exit(1); defaults to old behaviour Both loggers get a new error_box( $message_lines ) function `wp cli self-update` is now `wp cli update` --- php/WP_CLI/Loggers/Quiet.php | 11 ++++++ php/WP_CLI/Loggers/Regular.php | 26 ++++++++++++++ php/class-wp-cli.php | 15 +++++--- php/commands/cli.php | 62 ++++++++++++++++++---------------- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 6ccbb4029..44a86ca34 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -43,4 +43,15 @@ public function error( $message ) { fwrite( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); } + /** + * Similar to error( $message ), but outputs $message in a red box + * + * @param array $message Message to write. + */ + public function error_box( $message_lines ) { + $message = implode( "\n", $message_lines ); + + fwrite( STDERR, \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); + fwrite( STDERR, \WP_CLI::colorize( "%R---------%n\n\n" ) ); + } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index f5dda04fc..32d4a772a 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -73,4 +73,30 @@ public function error( $message ) { $this->_line( $message, 'Error', '%R', STDERR ); } + /** + * Similar to error( $message ), but outputs $message in a red box + * + * @param array $message Message to write. + */ + public function error_box( $message_lines ) { + // convert tabs to four spaces, as some shells will output the tabs as variable-length + $message_lines = array_map( function( $line ) { + return str_replace( "\t", ' ', $line ); + } , $message_lines ); + + $longest = max( array_map( 'strlen', $message_lines ) ); + + // write an empty line before the message + $empty_line = \cli\Colors::colorize( '%w%1 ' . str_repeat( ' ', $longest ) . ' %n' ); + $this->write( STDERR, "\n\t$empty_line\n" ); + + foreach ( $message_lines as $line ) { + $padding = str_repeat( ' ', $longest - strlen( $line ) ); + $line = \cli\Colors::colorize( "%w%1 $line $padding%n" ); + $this->write( STDERR, "\t$line\n" ); + } + + // write an empty line after the message + $this->write( STDERR, "\t$empty_line\n\n" ); + } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 63fb63f38..9d83c2e6f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -240,14 +240,21 @@ public static function warning( $message ) { /** * Display an error in the CLI and end with a newline * - * @param string $message + * @param string|array|WP_Error $message + * @param bool $exit if true, the script will exit() */ - public static function error( $message ) { + public static function error( $message, $exit = true ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { - self::$logger->error( self::error_to_string( $message ) ); + if ( is_array( $message ) ) { + self::$logger->error_box( array_map( array( __CLASS__, 'error_to_string' ), $message ) ); + } else { + self::$logger->error( self::error_to_string( $message ) ); + } } - exit(1); + if ( $exit ) { + exit(1); + } } /** diff --git a/php/commands/cli.php b/php/commands/cli.php index d6fe42819..7bcc113c8 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -134,9 +134,9 @@ function check_update( $_, $assoc_args ) { * [--yes] * : Do not prompt for confirmation * - * @subcommand self-update + * @subcommand update */ - function self_update( $_, $assoc_args ) { + function update( $_, $assoc_args ) { if ( 0 !== strpos( WP_CLI_ROOT, 'phar://' ) ) { WP_CLI::error( "You can only self-update PHARs" ); } @@ -149,49 +149,51 @@ function self_update( $_, $assoc_args ) { $updates = $this->get_updates( $assoc_args ); - if ( $updates ) { - $newest = $updates[0]; + if ( empty( $updates ) ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + } - WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); + $newest = $updates[0]; - $download_url = $newest['package_url']; + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); - WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); + $download_url = $newest['package_url']; - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.phar'; + WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); - $headers = array(); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody - 'filename' => $temp - ); + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.phar'; - Utils\http_request( 'GET', $download_url, null, $headers, $options ); + $headers = array(); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); - exec( "php $temp --version", $output, $status ); + Utils\http_request( 'GET', $download_url, null, $headers, $options ); - if ( 0 !== $status ) { - WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); - } + exec( "php $temp --version", $output, $status ); - WP_CLI::log( 'New version works. Proceeding to replace.' ); + if ( 0 !== $status ) { + WP_CLI::error( $output, false ); - $mode = fileperms( $old_phar ) & 511; + WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); + } - if ( false === @chmod( $temp, $mode ) ) { - WP_CLI::error( sprintf( "Cannot chmod %s", $temp ) ); - } + WP_CLI::log( 'New version works. Proceeding to replace.' ); - class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class + $mode = fileperms( $old_phar ) & 511; - if ( false === @rename( $temp, $old_phar ) ) { - WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); - } + if ( false === @chmod( $temp, $mode ) ) { + WP_CLI::error( sprintf( "Cannot chmod %s", $temp ) ); + } - WP_CLI::success( sprintf( 'Successfully update WP-CLI to %s', $newest['version'] ) ); - } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { - WP_CLI::success( "WP-CLI is at the latest version." ); + class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class + + if ( false === @rename( $temp, $old_phar ) ) { + WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); } + + WP_CLI::success( sprintf( 'Successfully update WP-CLI to %s', $newest['version'] ) ); } /** From 456c5cc88307c6f7b960768c7e0a4ea39304cd15 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Wed, 3 Dec 2014 12:34:55 +0000 Subject: [PATCH 3311/5359] Extract WP_CLI_VERSION to a separate file - Implements #680 - It is now possibile to set the version at build time (required for #1535): --version=x.y.z - Keywords for incrementing the version number by one: --version=[patch|minor|major] - When no arguments are passed, the old behaviour is preverved - utils/update-phar takes an option argument: `update-phar [same|patch|minor|major|x.y.z]` --- VERSION | 1 + composer.json | 5 ++-- php/wp-cli.php | 2 +- utils/make-phar.php | 61 ++++++++++++++++++++++++++++++++++++++++++--- utils/update-phar | 4 ++- 5 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..14a8c2457 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.17.1 \ No newline at end of file diff --git a/composer.json b/composer.json index f503e3906..ee4763449 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "wp-cli/wp-cli", "description": "A command line interface for WordPress", - "keywords": [ "cli", "wordpress" ], + "keywords": [ "cli", "wordpress" ], "homepage": "http://wp-cli.org", "license": "MIT", "bin": [ @@ -18,7 +18,8 @@ }, "require-dev": { "phpunit/phpunit": "3.7.*", - "behat/behat": "2.5.*" + "behat/behat": "2.5.*", + "ulrichsg/getopt-php": "2.2.*" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" diff --git a/php/wp-cli.php b/php/wp-cli.php index 2199b643d..46d703336 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', '0.17.1' ); +define( 'WP_CLI_VERSION', file_get_contents( WP_CLI_ROOT . '/VERSION' ) ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; diff --git a/utils/make-phar.php b/utils/make-phar.php index 4558cfbfb..687970ca6 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -3,15 +3,67 @@ require './vendor/autoload.php'; use Symfony\Component\Finder\Finder; +use Ulrichsg\Getopt\Getopt; +use Ulrichsg\Getopt\Option; -if ( !isset( $argv[1] ) ) { - echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet]\n"; +$getopt = new Getopt( array( + new Option( null, 'version', Getopt::REQUIRED_ARGUMENT ), + new Option( null, 'quiet' ), + new Option( 'o', 'output', Getopt::REQUIRED_ARGUMENT ), +) ); + +$getopt->parse(); + +if ( ! $getopt['output'] && ! $getopt->getOperand(0) ) { + echo "usage: php -dphar.readonly=0 $argv[0] -o <path> [--quiet] [--version=same|patch|minor|major|x.y.z]\n"; exit(1); } -define( 'DEST_PATH', $argv[1] ); +define( 'DEST_PATH', $getopt['output'] ?: $getopt->getOperand(0) ); + +define( 'BE_QUIET', (bool) $getopt['quiet'] ); + +if ( $getopt['version'] ) { + // split version ussuming the format is x.y.z-pre + $current_version = explode( '-', file_get_contents( './VERSION' ), 2 ); + $current_version[0] = explode( '.', $current_version[0] ); + + switch ( $getopt['version'] ) { + case 'same': + // do nothing + break; + + case 'patch': + $current_version[0][2]++; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; -define( 'BE_QUIET', in_array( '--quiet', $argv ) ); + case 'minor': + $current_version[0][1]++; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + case 'major': + $current_version[0][0]++; + $current_version[0][1] = 0; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + default: + $current_version = array( array( $getopt['version'] ) ); + break; + } + + // reconstruct version string + $current_version[0] = implode( '.', $current_version[0] ); + $current_version = implode( '-', $current_version ); + file_put_contents( './VERSION', $current_version ); +} function add_file( $phar, $path ) { $key = str_replace( './', '', $path ); @@ -67,6 +119,7 @@ function add_file( $phar, $path ) { add_file( $phar, './vendor/autoload.php' ); add_file( $phar, './utils/get-package-require-from-composer.php' ); add_file( $phar, './vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); +add_file( $phar, './VERSION' ); $phar->setStub( <<<EOB #!/usr/bin/env php diff --git a/utils/update-phar b/utils/update-phar index ea79bf112..7eeb24f88 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -2,6 +2,8 @@ set -ex +version=${1-"same"} + current_rev=$(git rev-parse HEAD) current_rev=${current_rev:0:10} @@ -10,7 +12,7 @@ packages_repo=../wp-cli-packages fname="phar/wp-cli.phar" # generate archive -php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet +php -dphar.readonly=0 -o ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version cd $packages_repo From 733d34f982b9524a98a8826ed4b471731a34599b Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Wed, 3 Dec 2014 16:00:30 +0000 Subject: [PATCH 3312/5359] wp cli update - fix success message --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 7bcc113c8..fc3d4ccf9 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -193,7 +193,7 @@ class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); } - WP_CLI::success( sprintf( 'Successfully update WP-CLI to %s', $newest['version'] ) ); + WP_CLI::success( sprintf( 'Updated WP-CLI to %s', $newest['version'] ) ); } /** From a036ec39d8afedec11b8d5570c6a0eaf4222adf3 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Wed, 3 Dec 2014 16:50:02 +0000 Subject: [PATCH 3313/5359] update checker options - change description of --patch and --minor - introduce --ignore-patch and --ignore-minor --- php/commands/cli.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index fc3d4ccf9..8779fd567 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -90,10 +90,16 @@ private function same_minor_release( $release_parts, $updates ) { * ## OPTIONS * * [--patch] - * : Compare only the first two parts of the version number. + * : Only list patch updates + * + * [--ignore-patch] + * : Do not list patch updates * * [--minor] - * : Compare only the first part of the version number. + * : Only list minor updates + * + * [--ignore-minor] + * : Do not list minor updates * * [--field=<field>] * : Prints the value of a single field for each update. @@ -126,10 +132,16 @@ function check_update( $_, $assoc_args ) { * ## OPTIONS * * [--patch] - * : Compare only the first two parts of the version number. + * : Only list patch updates + * + * [--ignore-patch] + * : Do not list patch updates * * [--minor] - * : Compare only the first part of the version number. + * : Only list minor updates + * + * [--ignore-minor] + * : Do not list minor updates * * [--yes] * : Do not prompt for confirmation @@ -237,7 +249,9 @@ private function get_updates( $assoc_args ) { } if ( ! ( isset( $assoc_args['patch'] ) && 'patch' !== $update_type ) + && ! ( isset( $assoc_args['ignore-patch'] ) && 'patch' === $update_type ) && ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) + && ! ( isset( $assoc_args['ignore-minor'] ) && 'minor' === $update_type ) && ! $this->same_minor_release( $release_parts, $updates ) ) { $updates[] = array( From 6fd93c2fdd9813280b56e8e81a15fb17f06d1f75 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Wed, 3 Dec 2014 17:25:33 +0000 Subject: [PATCH 3314/5359] New function - WP_CLI::error_multi_line() --- php/WP_CLI/Loggers/Quiet.php | 2 +- php/WP_CLI/Loggers/Regular.php | 2 +- php/class-wp-cli.php | 23 ++++++++++++++--------- php/commands/cli.php | 3 ++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 44a86ca34..f1140f858 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -48,7 +48,7 @@ public function error( $message ) { * * @param array $message Message to write. */ - public function error_box( $message_lines ) { + public function error_multi_line( $message_lines ) { $message = implode( "\n", $message_lines ); fwrite( STDERR, \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 32d4a772a..d5358dee6 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -78,7 +78,7 @@ public function error( $message ) { * * @param array $message Message to write. */ - public function error_box( $message_lines ) { + public function error_multi_line( $message_lines ) { // convert tabs to four spaces, as some shells will output the tabs as variable-length $message_lines = array_map( function( $line ) { return str_replace( "\t", ' ', $line ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9d83c2e6f..f0a576407 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -240,20 +240,25 @@ public static function warning( $message ) { /** * Display an error in the CLI and end with a newline * - * @param string|array|WP_Error $message - * @param bool $exit if true, the script will exit() + * @param string|WP_Error $message + * @param bool $exit if true, the script will exit() */ public static function error( $message, $exit = true ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { - if ( is_array( $message ) ) { - self::$logger->error_box( array_map( array( __CLASS__, 'error_to_string' ), $message ) ); - } else { - self::$logger->error( self::error_to_string( $message ) ); - } + self::$logger->error( self::error_to_string( $message ) ); } - if ( $exit ) { - exit(1); + exit(1); + } + + /** + * Display an error in the CLI and end with a newline + * + * @param array $message each element from the array will be printed on its own line + */ + public static function error_multi_line( $message_lines ) { + if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) && is_array( $message_lines ) ) { + self::$logger->error_multi_line( array_map( array( __CLASS__, 'error_to_string' ), $message_lines ) ); } } diff --git a/php/commands/cli.php b/php/commands/cli.php index 8779fd567..b1c8132d6 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -163,6 +163,7 @@ function update( $_, $assoc_args ) { if ( empty( $updates ) ) { WP_CLI::success( "WP-CLI is at the latest version." ); + exit(0); } $newest = $updates[0]; @@ -186,7 +187,7 @@ function update( $_, $assoc_args ) { exec( "php $temp --version", $output, $status ); if ( 0 !== $status ) { - WP_CLI::error( $output, false ); + WP_CLI::error_multi_line( $output ); WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); } From 3270b1151111392bf4c9e658f5b27e6e406ef5d6 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Thu, 4 Dec 2014 11:48:43 +0000 Subject: [PATCH 3315/5359] WP_CLI\Utils\increment_version() and tests --- php/utils.php | 54 ++++++++++++++++++++++++++++++++++++++++++++ tests/test-utils.php | 37 ++++++++++++++++++++++++++++++ utils/make-phar.php | 43 ++++------------------------------- 3 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 tests/test-utils.php diff --git a/php/utils.php b/php/utils.php index 963a3a463..4b81cb8d0 100644 --- a/php/utils.php +++ b/php/utils.php @@ -450,3 +450,57 @@ function http_request( $method, $url, $data = null, $headers = array(), $options } } } + +/** + * Increments a version string using the "x.y.z-pre" format + * + * Can increment the major, minor or patch number by one + * If $new_version == "same" the version string is not changed + * If $new_version is not a known keyword, it will be used as the new version string directly + * + * @param string $current_version + * @param string $new_version + * @return string + */ +function increment_version( $current_version, $new_version ) { + // split version assuming the format is x.y.z-pre + $current_version = explode( '-', $current_version, 2 ); + $current_version[0] = explode( '.', $current_version[0] ); + + switch ( $new_version ) { + case 'same': + // do nothing + break; + + case 'patch': + $current_version[0][2]++; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + case 'minor': + $current_version[0][1]++; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + case 'major': + $current_version[0][0]++; + $current_version[0][1] = 0; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + default: // not a keyword + $current_version = array( array( $new_version ) ); + break; + } + + // reconstruct version string + $current_version[0] = implode( '.', $current_version[0] ); + $current_version = implode( '-', $current_version ); + + return $current_version; +} \ No newline at end of file diff --git a/tests/test-utils.php b/tests/test-utils.php new file mode 100644 index 000000000..005abedeb --- /dev/null +++ b/tests/test-utils.php @@ -0,0 +1,37 @@ +<?php + +use WP_CLI\Utils; + +class UtilsTest extends PHPUnit_Framework_TestCase { + + function testIncrementVersion() { + // keyword increments + $this->assertEquals( + Utils\increment_version( '1.2.3-pre', 'same' ), + '1.2.3-pre' + ); + + $this->assertEquals( + Utils\increment_version( '1.2.3-pre', 'patch' ), + '1.2.4' + ); + + $this->assertEquals( + Utils\increment_version( '1.2.3-pre', 'minor' ), + '1.3.0' + ); + + $this->assertEquals( + Utils\increment_version( '1.2.3-pre', 'major' ), + '2.0.0' + ); + + // custom version string + $this->assertEquals( + Utils\increment_version( '1.2.3-pre', '4.5.6-alpha1' ), + '4.5.6-alpha1' + ); + } + +} + diff --git a/utils/make-phar.php b/utils/make-phar.php index 687970ca6..2459809fb 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -1,10 +1,12 @@ <?php require './vendor/autoload.php'; +require './php/utils.php'; use Symfony\Component\Finder\Finder; use Ulrichsg\Getopt\Getopt; use Ulrichsg\Getopt\Option; +use WP_CLI\Utils; $getopt = new Getopt( array( new Option( null, 'version', Getopt::REQUIRED_ARGUMENT ), @@ -24,45 +26,10 @@ define( 'BE_QUIET', (bool) $getopt['quiet'] ); if ( $getopt['version'] ) { - // split version ussuming the format is x.y.z-pre - $current_version = explode( '-', file_get_contents( './VERSION' ), 2 ); - $current_version[0] = explode( '.', $current_version[0] ); + $current_version = file_get_contents( './VERSION' ); + $new_version = $getopt['version']; - switch ( $getopt['version'] ) { - case 'same': - // do nothing - break; - - case 'patch': - $current_version[0][2]++; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - case 'minor': - $current_version[0][1]++; - $current_version[0][2] = 0; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - case 'major': - $current_version[0][0]++; - $current_version[0][1] = 0; - $current_version[0][2] = 0; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - default: - $current_version = array( array( $getopt['version'] ) ); - break; - } - - // reconstruct version string - $current_version[0] = implode( '.', $current_version[0] ); - $current_version = implode( '-', $current_version ); - file_put_contents( './VERSION', $current_version ); + file_put_contents( './VERSION', utils\increment_version( $current_version, $new_version ) ); } function add_file( $phar, $path ) { From fc41d0f938c664f90624b218f72b2f01e4d7c8ef Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Thu, 4 Dec 2014 13:07:30 +0000 Subject: [PATCH 3316/5359] add a new line at the end of php/utils.php --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 4b81cb8d0..b80c0ea17 100644 --- a/php/utils.php +++ b/php/utils.php @@ -503,4 +503,4 @@ function increment_version( $current_version, $new_version ) { $current_version = implode( '-', $current_version ); return $current_version; -} \ No newline at end of file +} From 696dc1697057118c0a6853dd8b2de52fb14c4d1b Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Thu, 4 Dec 2014 13:34:43 +0000 Subject: [PATCH 3317/5359] Use WP_CLI\Configurator instead of Ulrichsg\Getopt\Getopt in utils/make-phar.php --- composer.json | 3 +-- utils/make-phar-spec.php | 23 +++++++++++++++++++++++ utils/make-phar.php | 23 +++++++++-------------- utils/update-phar | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 utils/make-phar-spec.php diff --git a/composer.json b/composer.json index ee4763449..6c8a5ea5e 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,7 @@ }, "require-dev": { "phpunit/phpunit": "3.7.*", - "behat/behat": "2.5.*", - "ulrichsg/getopt-php": "2.2.*" + "behat/behat": "2.5.*" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" diff --git a/utils/make-phar-spec.php b/utils/make-phar-spec.php new file mode 100644 index 000000000..cc4fd4955 --- /dev/null +++ b/utils/make-phar-spec.php @@ -0,0 +1,23 @@ +<?php + +return array( + 'output' => array( + 'runtime' => '=<path>', + 'file' => '<path>', + 'desc' => 'Path to output file', + ), + + 'version' => array( + 'runtime' => '=<version>', + 'file' => '<version>', + 'desc' => 'New package version', + ), + + 'quiet' => array( + 'runtime' => '', + 'file' => '<bool>', + 'default' => false, + 'desc' => 'Suppress informational messages', + ), +); + diff --git a/utils/make-phar.php b/utils/make-phar.php index 2459809fb..744e57be9 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -4,30 +4,25 @@ require './php/utils.php'; use Symfony\Component\Finder\Finder; -use Ulrichsg\Getopt\Getopt; -use Ulrichsg\Getopt\Option; use WP_CLI\Utils; +use WP_CLI\Configurator; -$getopt = new Getopt( array( - new Option( null, 'version', Getopt::REQUIRED_ARGUMENT ), - new Option( null, 'quiet' ), - new Option( 'o', 'output', Getopt::REQUIRED_ARGUMENT ), -) ); +$configurator = new Configurator( './utils/make-phar-spec.php' ); -$getopt->parse(); +list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); -if ( ! $getopt['output'] && ! $getopt->getOperand(0) ) { - echo "usage: php -dphar.readonly=0 $argv[0] -o <path> [--quiet] [--version=same|patch|minor|major|x.y.z]\n"; +if ( ! isset( $args[0] ) || empty( $args[0] ) ) { + echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet] [--version=same|patch|minor|major|x.y.z]\n"; exit(1); } -define( 'DEST_PATH', $getopt['output'] ?: $getopt->getOperand(0) ); +define( 'DEST_PATH', $args[0] ); -define( 'BE_QUIET', (bool) $getopt['quiet'] ); +define( 'BE_QUIET', isset( $runtime_config['quiet'] ) && $runtime_config['quiet'] ); -if ( $getopt['version'] ) { +if ( isset( $runtime_config['version'] ) ) { $current_version = file_get_contents( './VERSION' ); - $new_version = $getopt['version']; + $new_version = $runtime_config['version']; file_put_contents( './VERSION', utils\increment_version( $current_version, $new_version ) ); } diff --git a/utils/update-phar b/utils/update-phar index 7eeb24f88..ee911f0a0 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -12,7 +12,7 @@ packages_repo=../wp-cli-packages fname="phar/wp-cli.phar" # generate archive -php -dphar.readonly=0 -o ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version +php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version cd $packages_repo From 02ed51480a974b1d86384d6e6393630359c03100 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 10:39:12 +0000 Subject: [PATCH 3318/5359] New behat feature for `wp cli` tasks features/cli.feature: - wp cli check-updates should return at least one update after version 0.0.0 - wp cli update should perform a successful update of version 0.0.0 --- features/bootstrap/FeatureContext.php | 29 +++++++++++++++++++++++++++ features/cli.feature | 26 ++++++++++++++++++++++++ features/steps/given.php | 5 +++++ 3 files changed, 60 insertions(+) create mode 100644 features/cli.feature diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index ae06d8eaa..168076969 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -91,6 +91,24 @@ public function afterScenario( $event ) { } } + /** + * @BeforeScenario @cli-update + */ + public function setLowVersion( $scope ) + { + $this->variables['TRUE_VERSION'] = file_get_contents( './VERSION' ); + file_put_contents( './VERSION', '0.0.0' ); + } + + /** + * @AfterScenario @cli-update + */ + public function restoreVersion( $scope ) + { + file_put_contents( './VERSION', $this->variables['TRUE_VERSION'] ); + unset( $this->variables['TRUE_VERSION'] ); + } + public static function create_cache_dir() { self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); mkdir( self::$suite_cache_dir ); @@ -138,6 +156,17 @@ public function create_run_dir() { } } + public function build_phar() { + $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; + + Process::create( + Utils\esc_cmd( 'php -dphar.readonly=0 %s %2$s && chmod +x %2$s', __DIR__ . '/../../utils/make-phar.php', $this->variables['PHAR_PATH'] ), + null, + self::get_process_env_variables() + )->run_check(); + // passthru( 'php -dphar.readonly=0 ' . . $this->variables['PHAR_PATH'] . ' && chmod +x ' . $this->variables['PHAR_PATH'] ); + } + private function set_cache_dir() { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ), null, self::get_process_env_variables() )->run_check(); diff --git a/features/cli.feature b/features/cli.feature new file mode 100644 index 000000000..4557f3b3e --- /dev/null +++ b/features/cli.feature @@ -0,0 +1,26 @@ +Feature: `wp cli` tasks + + @cli-update + Scenario: Check for updates + Given an empty directory + And a new Phar + + When I run `{PHAR_PATH} cli check-update` + Then STDOUT should contain: + """ + package_url + """ + And STDERR should be empty + + @cli-update + Scenario: Do WP-CLI Update + Given an empty directory + And a new Phar + + When I run `{PHAR_PATH} cli update --yes` + Then STDOUT should contain: + """ + Success: + """ + And STDERR should be empty + And the return code should be 0 diff --git a/features/steps/given.php b/features/steps/given.php index 3e7a7b26d..c2f783d6b 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -119,3 +119,8 @@ function ( $world, $stream, $output_filter, $key ) { } ); +$steps->Given( '/^a new Phar$/', + function ( $world ) { + $world->build_phar(); + } +); \ No newline at end of file From 80978c4f057a9d76f1ef5e759dabc538ce52cd9b Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 10:46:47 +0000 Subject: [PATCH 3319/5359] Add a version param to "Given a new Phar" --- features/bootstrap/FeatureContext.php | 29 +++++++-------------------- features/cli.feature | 6 ++---- features/steps/given.php | 6 +++--- 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 168076969..7ae97d6b4 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -91,24 +91,6 @@ public function afterScenario( $event ) { } } - /** - * @BeforeScenario @cli-update - */ - public function setLowVersion( $scope ) - { - $this->variables['TRUE_VERSION'] = file_get_contents( './VERSION' ); - file_put_contents( './VERSION', '0.0.0' ); - } - - /** - * @AfterScenario @cli-update - */ - public function restoreVersion( $scope ) - { - file_put_contents( './VERSION', $this->variables['TRUE_VERSION'] ); - unset( $this->variables['TRUE_VERSION'] ); - } - public static function create_cache_dir() { self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); mkdir( self::$suite_cache_dir ); @@ -156,15 +138,18 @@ public function create_run_dir() { } } - public function build_phar() { - $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; + public function build_phar( $version ) { + $this->variables['TRUE_VERSION'] = file_get_contents( './VERSION' ); + $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; Process::create( - Utils\esc_cmd( 'php -dphar.readonly=0 %s %2$s && chmod +x %2$s', __DIR__ . '/../../utils/make-phar.php', $this->variables['PHAR_PATH'] ), + Utils\esc_cmd( 'php -dphar.readonly=0 %s %2$s --version=%s && chmod +x %2$s', __DIR__ . '/../../utils/make-phar.php', $this->variables['PHAR_PATH'], $version ), null, self::get_process_env_variables() )->run_check(); - // passthru( 'php -dphar.readonly=0 ' . . $this->variables['PHAR_PATH'] . ' && chmod +x ' . $this->variables['PHAR_PATH'] ); + + file_put_contents( './VERSION', $this->variables['TRUE_VERSION'] ); + unset( $this->variables['TRUE_VERSION'] ); } private function set_cache_dir() { diff --git a/features/cli.feature b/features/cli.feature index 4557f3b3e..b9b06f5be 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -1,9 +1,8 @@ Feature: `wp cli` tasks - @cli-update Scenario: Check for updates Given an empty directory - And a new Phar + And a new Phar with version "0.0.0" When I run `{PHAR_PATH} cli check-update` Then STDOUT should contain: @@ -12,10 +11,9 @@ Feature: `wp cli` tasks """ And STDERR should be empty - @cli-update Scenario: Do WP-CLI Update Given an empty directory - And a new Phar + And a new Phar with version "0.0.0" When I run `{PHAR_PATH} cli update --yes` Then STDOUT should contain: diff --git a/features/steps/given.php b/features/steps/given.php index c2f783d6b..3af6b3213 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -119,8 +119,8 @@ function ( $world, $stream, $output_filter, $key ) { } ); -$steps->Given( '/^a new Phar$/', - function ( $world ) { - $world->build_phar(); +$steps->Given( '/^a new Phar(?: with version "([^"]+)")$/', + function ( $world, $version ) { + $world->build_phar( $version ); } ); \ No newline at end of file From 47026a20a497552f8709559b1dcd608d7d310be3 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 11:31:22 +0000 Subject: [PATCH 3320/5359] Move version changes to make-phar.php - make-phar.php gains a new optional flag --store-version which defaults to false. The script will change the contents of VERSION only if this is true. This is false when building temporary Phars with custom versions for tests. - Because of that there is a new function set_file_contents() in make-phar.php This is similar to add_file(), but the contents of the new file are passed as an argument, instead of reading them via file_get_contents() - Behat test for building a temporary Phar with a fake version Also ensure that VERSION is not modified --- features/bootstrap/FeatureContext.php | 20 ++++++++++++++------ features/cli.feature | 15 +++++++++++++++ features/steps/given.php | 17 +++++++++++++++++ utils/make-phar-spec.php | 7 +++++++ utils/make-phar.php | 27 +++++++++++++++++++++------ utils/update-phar | 2 +- 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 7ae97d6b4..a9f09a0ea 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -78,6 +78,13 @@ public static function afterSuite( SuiteEvent $event ) { } } + /** + * @BeforeScenario + */ + public function beforeScenario( $event ) { + $this->variables['SRC_DIR'] = realpath( __DIR__ . '/../..' ); + } + /** * @AfterScenario */ @@ -138,18 +145,19 @@ public function create_run_dir() { } } - public function build_phar( $version ) { - $this->variables['TRUE_VERSION'] = file_get_contents( './VERSION' ); + public function build_phar( $version = 'same' ) { $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; Process::create( - Utils\esc_cmd( 'php -dphar.readonly=0 %s %2$s --version=%s && chmod +x %2$s', __DIR__ . '/../../utils/make-phar.php', $this->variables['PHAR_PATH'], $version ), + Utils\esc_cmd( + 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', + __DIR__ . '/../../utils/make-phar.php', + $this->variables['PHAR_PATH'], + $version + ), null, self::get_process_env_variables() )->run_check(); - - file_put_contents( './VERSION', $this->variables['TRUE_VERSION'] ); - unset( $this->variables['TRUE_VERSION'] ); } private function set_cache_dir() { diff --git a/features/cli.feature b/features/cli.feature index b9b06f5be..7371efa28 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -1,5 +1,20 @@ Feature: `wp cli` tasks + Scenario: Ability to set a custom version when building + Given an empty directory + And save the {SRC_DIR}/VERSION file as {TRUE_VERSION} + And a new Phar with version "1.2.3" + + When I run `{PHAR_PATH} cli version` + Then STDOUT should be: + """ + WP-CLI 1.2.3 + """ + And the {SRC_DIR}/VERSION file should be: + """ + {TRUE_VERSION} + """ + Scenario: Check for updates Given an empty directory And a new Phar with version "0.0.0" diff --git a/features/steps/given.php b/features/steps/given.php index 3af6b3213..a9f536a7c 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -123,4 +123,21 @@ function ( $world, $stream, $output_filter, $key ) { function ( $world, $version ) { $world->build_phar( $version ); } +); + +$steps->Given( '/^save the (.+) file ([\'].+[^\'])?as \{(\w+)\}$/', + function ( $world, $filepath, $output_filter, $key ) { + $full_file = file_get_contents( $world->replace_variables( $filepath ) ); + + if ( $output_filter ) { + $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; + if ( false !== preg_match( $output_filter, $full_file, $matches ) ) + $output = array_pop( $matches ); + else + $output = ''; + } else { + $output = $full_file; + } + $world->variables[ $key ] = trim( $output, "\n" ); + } ); \ No newline at end of file diff --git a/utils/make-phar-spec.php b/utils/make-phar-spec.php index cc4fd4955..d5f3165c4 100644 --- a/utils/make-phar-spec.php +++ b/utils/make-phar-spec.php @@ -13,6 +13,13 @@ 'desc' => 'New package version', ), + 'store-version' => array( + 'runtime' => '', + 'file' => '<bool>', + 'default' => false, + 'desc' => 'If true the contents of ./VERSION will be set to the value passed to --version', + ), + 'quiet' => array( 'runtime' => '', 'file' => '<bool>', diff --git a/utils/make-phar.php b/utils/make-phar.php index 744e57be9..1841dcd34 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -12,7 +12,7 @@ list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); if ( ! isset( $args[0] ) || empty( $args[0] ) ) { - echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet] [--version=same|patch|minor|major|x.y.z]\n"; + echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet] [--version=same|patch|minor|major|x.y.z] [--store-version]\n"; exit(1); } @@ -20,11 +20,17 @@ define( 'BE_QUIET', isset( $runtime_config['quiet'] ) && $runtime_config['quiet'] ); +$current_version = file_get_contents( './VERSION' ); + if ( isset( $runtime_config['version'] ) ) { - $current_version = file_get_contents( './VERSION' ); - $new_version = $runtime_config['version']; + $new_version = $runtime_config['version']; + $new_version = Utils\increment_version( $current_version, $new_version ); + + if ( isset( $runtime_config['store-version'] ) && $runtime_config['store-version'] ) { + file_put_contents( './VERSION', $new_version ); + } - file_put_contents( './VERSION', utils\increment_version( $current_version, $new_version ) ); + $current_version = $new_version; } function add_file( $phar, $path ) { @@ -36,6 +42,15 @@ function add_file( $phar, $path ) { $phar[ $key ] = file_get_contents( $path ); } +function set_file_contents( $phar, $path, $content ) { + $key = str_replace( './', '', $path ); + + if ( !BE_QUIET ) + echo "$key - $path\n"; + + $phar[ $key ] = $content; +} + $phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); $phar->startBuffering(); @@ -81,7 +96,8 @@ function add_file( $phar, $path ) { add_file( $phar, './vendor/autoload.php' ); add_file( $phar, './utils/get-package-require-from-composer.php' ); add_file( $phar, './vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); -add_file( $phar, './VERSION' ); + +set_file_contents( $phar, './VERSION', $current_version ); $phar->setStub( <<<EOB #!/usr/bin/env php @@ -96,4 +112,3 @@ function add_file( $phar, $path ) { $phar->stopBuffering(); echo "Generated " . DEST_PATH . "\n"; - diff --git a/utils/update-phar b/utils/update-phar index ee911f0a0..3c6a1b547 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -12,7 +12,7 @@ packages_repo=../wp-cli-packages fname="phar/wp-cli.phar" # generate archive -php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version +php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version --store-version cd $packages_repo From fc548076b58bf4a02e9c267b288a56cd05f86ee7 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 12:05:26 +0000 Subject: [PATCH 3321/5359] fix whitespace --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index a9f09a0ea..c17d1842b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -146,7 +146,7 @@ public function create_run_dir() { } public function build_phar( $version = 'same' ) { - $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; + $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; Process::create( Utils\esc_cmd( From b76d88369696a1c58fa31cffb56fb9db762ff06d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 14:26:18 -0800 Subject: [PATCH 3322/5359] Define wp_is_mobile() function It's normally defined in `vars.php`, and some plugins / themes expect it --- php/wp-settings-cli.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index d189f412f..f2e2fc85e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -211,8 +211,11 @@ // Define and enforce our SSL constants wp_ssl_constants( ); -// Create common globals. +// Don't create common globals, but we still need wp_is_mobile() // require( ABSPATH . WPINC . '/vars.php' ); +function wp_is_mobile() { + return false; +} // Make taxonomies and posts available to plugins and themes. // @plugin authors: warning: these get registered again on the init hook. From 910e65012d05534174805b54f7e6c9fe44796142 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 22:50:24 +0000 Subject: [PATCH 3323/5359] `wp cli update/check-update` arguments --- php/commands/cli.php | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index b1c8132d6..4c40336e0 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -92,15 +92,9 @@ private function same_minor_release( $release_parts, $updates ) { * [--patch] * : Only list patch updates * - * [--ignore-patch] - * : Do not list patch updates - * * [--minor] * : Only list minor updates * - * [--ignore-minor] - * : Do not list minor updates - * * [--field=<field>] * : Prints the value of a single field for each update. * @@ -132,16 +126,10 @@ function check_update( $_, $assoc_args ) { * ## OPTIONS * * [--patch] - * : Only list patch updates - * - * [--ignore-patch] - * : Do not list patch updates + * : Only perform patch updates * * [--minor] - * : Only list minor updates - * - * [--ignore-minor] - * : Do not list minor updates + * : Only perform minor updates * * [--yes] * : Do not prompt for confirmation @@ -249,10 +237,10 @@ private function get_updates( $assoc_args ) { $update_type = 'patch'; } - if ( ! ( isset( $assoc_args['patch'] ) && 'patch' !== $update_type ) - && ! ( isset( $assoc_args['ignore-patch'] ) && 'patch' === $update_type ) - && ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) - && ! ( isset( $assoc_args['ignore-minor'] ) && 'minor' === $update_type ) + if ( ! ( isset( $assoc_args['patch'] ) && $assoc_args['patch'] && 'patch' !== $update_type ) + && ! ( isset( $assoc_args['patch'] ) && ! $assoc_args['patch'] && 'patch' === $update_type ) + && ! ( isset( $assoc_args['minor'] ) && $assoc_args['minor'] && 'minor' !== $update_type ) + && ! ( isset( $assoc_args['minor'] ) && ! $assoc_args['minor'] && 'minor' === $update_type ) && ! $this->same_minor_release( $release_parts, $updates ) ) { $updates[] = array( From e02362b5ab8d6b05cc8301731975a098ea4b92c3 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 23:04:02 +0000 Subject: [PATCH 3324/5359] More Behat tests for `wp cli update` - from 0.14.0 with --patch - from 0.14.0 with --no-patch --- features/cli.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/features/cli.feature b/features/cli.feature index 7371efa28..37257dccd 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -37,3 +37,31 @@ Feature: `wp cli` tasks """ And STDERR should be empty And the return code should be 0 + + Scenario: Patch update from 0.14.0 to 0.14.1 + Given an empty directory + And a new Phar with version "0.14.0" + + When I run `{PHAR_PATH} cli update --patch --yes` + Then STDOUT should contain: + """ + Success: Updated WP-CLI to 0.14.1 + """ + And STDERR should be empty + And the return code should be 0 + + Scenario: Not a patch update from 0.14.0 + Given an empty directory + And a new Phar with version "0.14.0" + + When I run `{PHAR_PATH} cli update --no-patch --yes` + Then STDOUT should contain: + """ + Success: + """ + And STDOUT should not contain: + """ + 0.14.1 + """ + And STDERR should be empty + And the return code should be 0 \ No newline at end of file From d2c900b61e78b5899729400f1512d5141d7dcfc4 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 5 Dec 2014 23:07:10 +0000 Subject: [PATCH 3325/5359] missing newline charater at the end of features/cli.feature --- features/cli.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cli.feature b/features/cli.feature index 37257dccd..d0cf96056 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -64,4 +64,4 @@ Feature: `wp cli` tasks 0.14.1 """ And STDERR should be empty - And the return code should be 0 \ No newline at end of file + And the return code should be 0 From ccd3ece3700c6b14d588f701f2f893f0e394642f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 15:16:01 -0800 Subject: [PATCH 3326/5359] Introduce `wp user list --network` shorthand This makes it easier to list all users in a network. --- features/user.feature | 33 +++++++++++++++++++++++++++++++++ php/commands/user.php | 10 ++++++++++ 2 files changed, 43 insertions(+) diff --git a/features/user.feature b/features/user.feature index 44bc1a2eb..a1151b09b 100644 --- a/features/user.feature +++ b/features/user.feature @@ -321,3 +321,36 @@ Feature: Manage WordPress users """ Password: """ + + Scenario: List network users + Given a WP multisite install + + When I run `wp user create testsubscriber testsubscriber@example.com` + Then STDOUT should contain: + """ + Success: Created user + """ + + When I run `wp user list --field=user_login` + Then STDOUT should contain: + """ + testsubscriber + """ + + When I run `wp user delete testsubscriber --yes` + Then STDOUT should contain: + """ + Success: Removed user + """ + + When I run `wp user list --field=user_login` + Then STDOUT should not contain: + """ + testsubscriber + """ + + When I run `wp user list --field=user_login --network` + Then STDOUT should contain: + """ + testsubscriber + """ diff --git a/php/commands/user.php b/php/commands/user.php index 76a347fac..103b9e659 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -32,6 +32,9 @@ public function __construct() { * [--<field>=<value>] * : Control output by one or more arguments of get_users(). * + * [--network] + * : List all users in the network for multisite. + * * [--field=<field>] * : Prints the value of a single field for each user. * @@ -85,6 +88,13 @@ public function list_( $args, $assoc_args ) { $assoc_args['fields'] = 'all_with_meta'; } + if ( isset( $assoc_args['network'] ) ) { + if ( ! is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + $assoc_args['blog_id'] = 0; + } + $users = get_users( $assoc_args ); if ( 'ids' == $formatter->format ) { From c0fe260e295061c6ea827ffb1df42f75c1c7ec87 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 15:20:05 -0800 Subject: [PATCH 3327/5359] Roles shouldn't be exposed with `--network` --- php/commands/user.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 103b9e659..fae201e42 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -80,19 +80,26 @@ public function __construct() { * @subcommand list */ public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - if ( 'ids' == $formatter->format ) { - $assoc_args['fields'] = 'ids'; - } else { - $assoc_args['fields'] = 'all_with_meta'; - } if ( isset( $assoc_args['network'] ) ) { if ( ! is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } $assoc_args['blog_id'] = 0; + if ( isset( $assoc_args['fields'] ) ) { + $fields = explode( ',', $assoc_args['fields'] ); + $assoc_args['fields'] = array_diff( $fields, array( 'roles' ) ); + } else { + $assoc_args['fields'] = array_diff( $this->obj_fields, array( 'roles' ) ); + } + } + + $formatter = $this->get_formatter( $assoc_args ); + + if ( 'ids' == $formatter->format ) { + $assoc_args['fields'] = 'ids'; + } else { + $assoc_args['fields'] = 'all_with_meta'; } $users = get_users( $assoc_args ); From e98fa0f3c3520024396b01a7022ab9e6b2bac9b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 15:27:47 -0800 Subject: [PATCH 3328/5359] Test for #1548 --- features/menu.feature | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index b350f094d..8c0f059bd 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -95,6 +95,9 @@ Feature: Manage WordPress menus | custom | WordPress | | 2 | http://wordpress.org | {POST_ITEM_ID} | | taxonomy | Test term | | 3 | {TERM_LINK} | 0 | + When I run `wp menu item list sidebar-menu --format=ids` + Then STDOUT should not be empty + When I run `wp menu item delete {CUSTOM_ITEM_ID}` And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: From 992e0ac120c1906243c7f97c99b76da67b5dcb00 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 15:30:04 -0800 Subject: [PATCH 3329/5359] Use `db_id` as the id for `wp menu list item` --- php/commands/menu.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index 0277cbba0..136a6e421 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -239,6 +239,12 @@ public function list_( $args, $assoc_args ) { return $item; }, $items ); + if ( ! empty( $assoc_args['format'] ) && 'ids' == $assoc_args['format'] ) { + $items = array_map( function( $item ) { + return $item->db_id; + }, $items ); + } + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $items ); From 59c9f77ed6427091b53dd8a48fcbe9c7e22373a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 5 Dec 2014 15:40:46 -0800 Subject: [PATCH 3330/5359] Don't throw error, as this will change existing behavior More verbose tests --- features/option.feature | 13 +++++++++++-- php/commands/option.php | 15 +++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/features/option.feature b/features/option.feature index ee9a7a509..ba1afb692 100644 --- a/features/option.feature +++ b/features/option.feature @@ -21,11 +21,20 @@ Feature: Manage WordPress options # Integer values - When I run `wp option update blog_public 0` + When I run `wp option update blog_public 1` Then STDOUT should not be empty + When I run `wp option update blog_public 0` + Then STDOUT should contain: + """ + Success: Updated 'blog_public' option. + """ + When I run the previous command again - Then STDOUT should not be empty + Then STDOUT should contain: + """ + Success: Value passed for 'blog_public' option is unchanged. + """ When I run `wp option get blog_public` Then STDOUT should be: diff --git a/php/commands/option.php b/php/commands/option.php index ea5d17f7d..7ab27d3ff 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -104,15 +104,14 @@ public function update( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); - $result = update_option( $key, $value ); - - // update_option() returns false if the value is the same - if ( ! $result ) { - WP_CLI::error( "Could not update option '$key'." ); - } else if ( $value == get_option( $key ) ) { - WP_CLI::error( "Value passed for '$key' option is unchanged." ); + if ( $value === get_option( $key ) ) { + WP_CLI::success( "Value passed for '$key' option is unchanged." ); } else { - WP_CLI::success( "Updated '$key' option." ); + if ( update_option( $key, $value ) ) { + WP_CLI::success( "Updated '$key' option." ); + } else { + WP_CLI::error( "Could not update option '$key'." ); + } } } From d6756825ade291e0152289253e7446cfab29580d Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Mon, 8 Dec 2014 13:10:28 +0000 Subject: [PATCH 3331/5359] Force SHA-512 signature for Phars --- utils/make-phar.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 744e57be9..bdae34500 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -38,6 +38,8 @@ function add_file( $phar, $path ) { $phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); +$phar->setSignatureAlgorithm( Phar::SHA512 ); + $phar->startBuffering(); // PHP files @@ -97,3 +99,5 @@ function add_file( $phar, $path ) { echo "Generated " . DEST_PATH . "\n"; +$signature = $phar->getSignature(); +echo "{$signature['hash_type']} signature: {$signature['hash']}\n"; \ No newline at end of file From 30c93ebb545a18c108bf65e99158a19fda5500a7 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Mon, 8 Dec 2014 15:12:21 +0000 Subject: [PATCH 3332/5359] checksums for nightly builds --- ci/deploy.sh | 11 ++++++++--- utils/test-phar-download | 5 +++++ utils/update-phar | 4 +++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index e3b17b39f..8829599d5 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -30,10 +30,15 @@ git config user.name "Travis CI" git config user.email "travis@travis-ci.org" git config push.default "current" -mv $WP_CLI_BIN_DIR/wp phar/wp-cli-nightly.phar -chmod -x phar/wp-cli-nightly.phar +fname="phar/wp-cli-nightly.phar" -git add phar/wp-cli-nightly.phar +mv $WP_CLI_BIN_DIR/wp $fname +chmod -x $fname + +md5sum $fname | cut -d ' ' -f 1 > $fname.md5 +sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 + +git add $fname.phar $fname.md5 $fname.sha512 git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" git push diff --git a/utils/test-phar-download b/utils/test-phar-download index f1a47e519..f4c9ad7f4 100755 --- a/utils/test-phar-download +++ b/utils/test-phar-download @@ -4,3 +4,8 @@ actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | md5sum | cu echo "expected:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.md5) echo "actual: " $actual_checksum + +actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | sha512sum | cut -d ' ' -f 1) + +echo "expected SHA-512:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.sha512) +echo "actual SHA-512: " $actual_checksum diff --git a/utils/update-phar b/utils/update-phar index ee911f0a0..009b5542d 100755 --- a/utils/update-phar +++ b/utils/update-phar @@ -41,7 +41,9 @@ fi echo $md5hash | cut -d ' ' -f 1 > $fname.md5 -git add $fname $fname.md5 +sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 + +git add $fname $fname.md5 $fname.sha512 git commit -m "$new_commit_subj" From 4f852f6861cafa267e557fa36dceb54502b5bf14 Mon Sep 17 00:00:00 2001 From: Alex Mills <git@viper007bond.com> Date: Wed, 10 Dec 2014 18:07:53 -0800 Subject: [PATCH 3333/5359] Disable colors by default when being run under Windows. Colors don't render correctly. --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 787d4dd52..c2e29132d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -453,7 +453,7 @@ public function in_color() { private function init_colorization() { if ( 'auto' === $this->config['color'] ) { - $this->colorize = !\cli\Shell::isPiped(); + $this->colorize = ( !\cli\Shell::isPiped() && !\WP_CLI\Utils\is_windows() ); } else { $this->colorize = $this->config['color']; } From 01190b6e8fe20629dd81095e350f958c7bcbf682 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 15 Dec 2014 12:12:55 -0200 Subject: [PATCH 3334/5359] add test scenario for exporting posts from a given category --- features/export.feature | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/features/export.feature b/features/export.feature index 8539e309c..7f5de8997 100644 --- a/features/export.feature +++ b/features/export.feature @@ -158,3 +158,50 @@ Feature: Export content. """ 10 """ + + Scenario: Export posts from a given category + Given a WP install + And these installed and active plugins: + """ + wordpress-importer + """ + + When I run `wp term create category Apple --porcelain` + Then STDOUT should be a number + And save STDOUT as {TERM_ID} + + When I run `wp site empty --yes` + And I run `wp post generate --post_type=post --count=10` + And I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 10 + """ + + When I run `for id in $(wp post list --posts_per_page=5 --ids); do wp post term add $id category Apple; done` + And I run `wp post list --post_type=post --cat={TERM_ID} --format=count` + Then STDOUT should be: + """ + 5 + """ + + When I run `wp export --post_type=post --category=apple` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 5 + """ From 058af9db07b194842c67ca9306b5f2f629f8a18f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 15 Dec 2014 12:35:45 -0200 Subject: [PATCH 3335/5359] category information should be included before posts on export file --- features/export.feature | 4 ++++ php/export/class-wp-export-query.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/features/export.feature b/features/export.feature index 7f5de8997..196bca335 100644 --- a/features/export.feature +++ b/features/export.feature @@ -187,6 +187,10 @@ Feature: Export content. When I run `wp export --post_type=post --category=apple` And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + Then the {EXPORT_FILE} file should contain: + """ + <wp:category_nicename>apple</wp:category_nicename> + """ When I run `wp site empty --yes` Then STDOUT should not be empty diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index d826d17f6..6f5bb9bf3 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -72,7 +72,7 @@ public function authors() { public function categories() { if ( $this->category ) { - return $this->category; + return array( $this->category ); } if ( $this->filters['post_type'] ) { return array(); From b3d7b1c5c3e65d9cbd69da0303308dc1206d29c9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 16 Dec 2014 12:07:33 -0200 Subject: [PATCH 3336/5359] author_email is not always in the WXR file --- php/commands/import.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index a0fd39d54..eca7db4c2 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -80,9 +80,11 @@ private function import_wxr( $file, $args ) { $author = new \stdClass; // Always in the WXR $author->user_login = $wxr_author['author_login']; - $author->user_email = $wxr_author['author_email']; // Should be in the WXR; no guarantees + if ( isset ( $wxr_author['author_email'] ) ) { + $author->user_email = $wxr_author['author_email']; + } if ( isset( $wxr_author['author_display_name'] ) ) $author->display_name = $wxr_author['author_display_name']; if ( isset( $wxr_author['author_first_name'] ) ) From 4606d3210f6932afd3b343a7b72580f6a209def7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 11:54:45 -0800 Subject: [PATCH 3337/5359] Alias `wp theme uninstall` to `wp theme delete` Even though themes don't have an uninstall process, plugins do. This brings them to closer interface parity. --- php/commands/theme.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 9a09e10f0..5843333d8 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -502,6 +502,8 @@ function is_installed( $args, $assoc_args = array() ) { * ## EXAMPLES * * wp theme delete twentyeleven + * + * @alias uninstall */ function delete( $args ) { foreach ( $this->fetcher->get_many( $args ) as $theme ) { From dd03e18d79048c27f833e974bd3533fba740b68c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 12:32:44 -0800 Subject: [PATCH 3338/5359] Report HTTP error code on failure to install This gives the end user more information as to why their command failed. --- php/WP_CLI/CommandWithUpgrade.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 982cbee27..b24f1c6fe 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -187,10 +187,11 @@ protected static function alter_api_response( $response, $version ) { // check if the requested version exists $response = wp_remote_head( $response->download_link ); - if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { + $response_code = wp_remote_retrieve_response_code( $response ); + if ( 200 !== $response_code ) { \WP_CLI::error( sprintf( - "Can't find the requested %s's version %s in the WordPress.org %s repository.", - $download_type, $version, $download_type ) ); + "Can't find the requested %s's version %s in the WordPress.org %s repository (HTTP code %d).", + $download_type, $version, $download_type, $response_code ) ); } } } From 76e9d690bd6f1756f02a7996c4487683140eb716 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 12:48:50 -0800 Subject: [PATCH 3339/5359] Update php-cli-tools to v0.10.3 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6c8a5ea5e..8d35b340c 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.2", + "wp-cli/php-cli-tools": "0.10.3", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 4a1631d166376a8e7031238051eabf6bc2432ba4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 13:16:09 -0800 Subject: [PATCH 3340/5359] Failing test condition for #1541 --- features/post-meta.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/post-meta.feature b/features/post-meta.feature index 19a92cb6f..7fd2eba5c 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -12,6 +12,12 @@ Feature: Manage post custom fields bar """ + When I try `wp post meta get 2 foo` + Then STDERR should be: + """ + Error: Could not find the post with ID 2. + """ + When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty From 292da5952b6b6fe6a95799eac9550fcb47fe3e45 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 13:18:11 -0800 Subject: [PATCH 3341/5359] Also test user meta --- features/user-meta.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/user-meta.feature b/features/user-meta.feature index a7adffae6..8d96312b2 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -12,6 +12,12 @@ Feature: Manage user custom fields bar """ + When I try `wp user-meta get 2 foo` + Then STDERR should be: + """ + Error: Invalid user ID, email or login: '2' + """ + When I run `wp user-meta set admin foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty From d41d8fed8566f70370cb9084eab1f5c8e04678d7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 16 Dec 2014 13:28:23 -0800 Subject: [PATCH 3342/5359] Check that post ID exists before changing metadata --- features/post-meta.feature | 4 ++-- php/WP_CLI/CommandWithMeta.php | 20 ++++++++++++++++++++ php/commands/post.php | 11 +++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 7fd2eba5c..821be2fad 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -12,10 +12,10 @@ Feature: Manage post custom fields bar """ - When I try `wp post meta get 2 foo` + When I try `wp post meta get 999999 foo` Then STDERR should be: """ - Error: Could not find the post with ID 2. + Error: Could not find the post with ID 999999. """ When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 7b54511a1..1d1f72eca 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -34,6 +34,8 @@ public function list_( $args, $assoc_args ) { $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); + $object_id = $this->check_object_id( $object_id ); + $metadata = get_metadata( $this->meta_type, $object_id ); if ( ! $metadata ) { $metadata = array(); @@ -80,6 +82,8 @@ public function list_( $args, $assoc_args ) { public function get( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; + $object_id = $this->check_object_id( $object_id ); + $value = \get_metadata( $this->meta_type, $object_id, $meta_key, true ); if ( '' === $value ) @@ -105,6 +109,8 @@ public function delete( $args, $assoc_args ) { $meta_value = ! empty( $args[2] ) ? $args[2] : ''; + $object_id = $this->check_object_id( $object_id ); + $success = \delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { @@ -137,6 +143,8 @@ public function add( $args, $assoc_args ) { $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); + $object_id = $this->check_object_id( $object_id ); + $success = \add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { @@ -171,6 +179,8 @@ public function update( $args, $assoc_args ) { $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); + $object_id = $this->check_object_id( $object_id ); + $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { @@ -193,5 +203,15 @@ private function get_fields() { ); } + /** + * Check that the object ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + // Needs to be set in subclass + return $object_id; + } + } diff --git a/php/commands/post.php b/php/commands/post.php index a5977e565..edde22682 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -478,6 +478,17 @@ private function read_from_file_or_stdin( $arg ) { */ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; + + /** + * Check that the post ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $fetcher = new \WP_CLI\Fetchers\Post; + $post = $fetcher->get_check( $object_id ); + return $post->ID; + } } /** From f8e03be4a478762007058c179342440c84022426 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:13:43 -0800 Subject: [PATCH 3343/5359] Drop test for term with non-existent parent Core's term API has changed, and no longer will permit the pre-condition. Our code still works; we just don't need to test for it anymore. --- features/export.feature | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/features/export.feature b/features/export.feature index 196bca335..40caccd2f 100644 --- a/features/export.feature +++ b/features/export.feature @@ -9,22 +9,6 @@ Feature: Export content. All done with export """ - Scenario: Term with a non-existent parent - Given a WP install - - When I run `wp term create category Apple --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID} - - When I run `wp term update category {TERM_ID} --parent=99` - Then STDOUT should not be empty - - When I try `wp export` - Then STDERR should be: - """ - Error: Term is missing a parent. - """ - Scenario: Export argument validator Given a WP install From 04a8a7168d00cebbf9719bf63b356efd086a5c2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:17:23 -0800 Subject: [PATCH 3344/5359] Explicitly install WordPress importer This will let us catch plugin installation failures, instead of letting the precondition pass and test fail later --- features/export.feature | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/features/export.feature b/features/export.feature index 40caccd2f..a342d608c 100644 --- a/features/export.feature +++ b/features/export.feature @@ -38,10 +38,9 @@ Feature: Export content. Scenario: Export with post_type and post_status argument Given a WP install - And these installed and active plugins: - """ - wordpress-importer - """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should not be empty When I run `wp site empty --yes` And I run `wp post generate --post_type=page --post_status=draft --count=10` @@ -74,10 +73,9 @@ Feature: Export content. Scenario: Export only one post Given a WP install - And these installed and active plugins: - """ - wordpress-importer - """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should not be empty When I run `wp post generate --count=10` And I run `wp post list --format=count` @@ -107,10 +105,9 @@ Feature: Export content. Scenario: Export posts within a given date range Given a WP install - And these installed and active plugins: - """ - wordpress-importer - """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should not be empty When I run `wp site empty --yes` And I run `wp post generate --post_type=post --post_date=2013-08-01 --count=10` @@ -145,10 +142,9 @@ Feature: Export content. Scenario: Export posts from a given category Given a WP install - And these installed and active plugins: - """ - wordpress-importer - """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should not be empty When I run `wp term create category Apple --porcelain` Then STDOUT should be a number From 9e1892baef2d94b5e2b04e5e36e6c4b8721999d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:35:18 -0800 Subject: [PATCH 3345/5359] Test comment validation for comment meta --- features/comment-meta.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/comment-meta.feature b/features/comment-meta.feature index 5eedef616..f6f779ecb 100644 --- a/features/comment-meta.feature +++ b/features/comment-meta.feature @@ -12,6 +12,12 @@ Feature: Manage comment custom fields bar """ + When I try `wp comment meta get 999999 foo` + Then STDERR should be: + """ + Error: Invalid comment ID. + """ + When I run `wp comment-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty From d247ec812251114b2a3310259a6a7273282e66be Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:37:58 -0800 Subject: [PATCH 3346/5359] Validate comment ID for comment meta --- php/commands/comment.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index fa19bad29..662f4f734 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -440,6 +440,17 @@ public function url( $args ) { */ class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'comment'; + + /** + * Check that the comment ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $fetcher = new \WP_CLI\Fetchers\Comment; + $comment = $fetcher->get_check( $object_id ); + return $comment->comment_ID; + } } WP_CLI::add_command( 'comment', 'Comment_Command' ); From d470978e9993352e48882c592254e0d2b944733f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:38:18 -0800 Subject: [PATCH 3347/5359] Fix error message used in test --- features/comment-meta.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/comment-meta.feature b/features/comment-meta.feature index f6f779ecb..f1bb0abf3 100644 --- a/features/comment-meta.feature +++ b/features/comment-meta.feature @@ -15,7 +15,7 @@ Feature: Manage comment custom fields When I try `wp comment meta get 999999 foo` Then STDERR should be: """ - Error: Invalid comment ID. + Error: Could not find the comment with ID 999999. """ When I run `wp comment-meta set 1 foo '[ "1", "2" ]' --format=json` From 012d934a99456b132a1cb529e83a38916a33411e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:49:45 -0800 Subject: [PATCH 3348/5359] Use our formatter, so we can catch errors --- features/core.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index c68af4ba5..e6201b8b0 100644 --- a/features/core.feature +++ b/features/core.feature @@ -288,7 +288,7 @@ Feature: Manage WordPress installation | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | - When I run `wp core check-update --field=version | wc -l` + When I run `wp core check-update --format=count` Then STDOUT should be: """ 3 @@ -300,7 +300,7 @@ Feature: Manage WordPress installation | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | - When I run `wp core check-update --major --field=version | wc -l` + When I run `wp core check-update --major --format=count` Then STDOUT should be: """ 2 @@ -311,7 +311,7 @@ Feature: Manage WordPress installation | version | update_type | package_url | | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | - When I run `wp core check-update --minor --field=version | wc -l` + When I run `wp core check-update --minor --format=count` Then STDOUT should be: """ 1 From 7b6a9d28fc2ed28f6dc7ae8edcffc988f72fcd5c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 12:53:10 -0800 Subject: [PATCH 3349/5359] Update version check test to accommodate WP4.1 --- features/core.feature | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index e6201b8b0..b226393cb 100644 --- a/features/core.feature +++ b/features/core.feature @@ -284,6 +284,7 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.1 | major | https://wordpress.org/wordpress-4.1.zip | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | @@ -291,19 +292,20 @@ Feature: Manage WordPress installation When I run `wp core check-update --format=count` Then STDOUT should be: """ - 3 + 4 """ When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.1 | major | https://wordpress.org/wordpress-4.1.zip | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: """ - 2 + 3 """ When I run `wp core check-update --minor` From de73ef1dccece8477d729921483ae13bdc4572d1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 18 Dec 2014 13:22:46 -0800 Subject: [PATCH 3350/5359] Use Travis' nifty dependency caching --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index b5b6e3185..c78c12632 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,10 @@ script: ./ci/test.sh after_success: ./ci/deploy.sh +cache: + directories: + - vendor + notifications: email: on_success: never From cc34083c3e968d40566d2b81b83ba40a7aad6cf6 Mon Sep 17 00:00:00 2001 From: Stephen Edgar <stephen@netweb.com.au> Date: Fri, 19 Dec 2014 12:21:54 +1100 Subject: [PATCH 3351/5359] Use new Travis container-based infrastructure for improved speed and cache http://docs.travis-ci.com/user/workers/container-based-infrastructure/ --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c78c12632..b6bf25eca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +sudo: false + language: php php: From 61eeda1a240c9cdc27cf40514a5abe7e9e0d2b8f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 11:55:02 -0800 Subject: [PATCH 3352/5359] For performance, use a plugin we're already using --- features/plugin.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index c79aee297..21a98e663 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -164,13 +164,13 @@ Feature: Manage WordPress plugins Scenario: Network activate a plugin Given a WP multisite install - When I run `wp plugin install user-switching --activate-network` + When I run `wp plugin activate akismet --network` Then STDOUT should not be empty When I run `wp plugin list --fields=name,status` Then STDOUT should be a table containing rows: | name | status | - | user-switching | active-network | + | akismet | active-network | Scenario: List plugins Given a WP install From 779649b3f01ab91d686d4e6351611ccdad37ad86 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:06:02 -0800 Subject: [PATCH 3353/5359] More reliable behavior for network activating a plugin * If the plugin is already active, allow it to be network-activated. * If the plugin is already network-active, don't change status. --- features/plugin.feature | 28 +++++++++++++++++++++++++--- php/commands/plugin.php | 9 ++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 21a98e663..df1b50b3c 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -161,16 +161,38 @@ Feature: Manage WordPress plugins Status: Network Active """ + @daniel Scenario: Network activate a plugin Given a WP multisite install - When I run `wp plugin activate akismet --network` - Then STDOUT should not be empty + When I run `wp plugin activate akismet` + Then STDOUT should contain: + """ + Success: Plugin 'akismet' activated. + """ When I run `wp plugin list --fields=name,status` Then STDOUT should be a table containing rows: | name | status | - | akismet | active-network | + | akismet | active | + + When I run `wp plugin activate akismet` + Then STDERR should contain: + """ + Warning: Plugin 'akismet' is already active. + """ + + When I run `wp plugin activate akismet --network` + Then STDOUT should contain: + """ + Success: Plugin 'akismet' network activated. + """ + + When I run `wp plugin activate akismet --network` + Then STDERR should contain: + """ + Warning: Plugin 'akismet' is already network active. + """ Scenario: List plugins Given a WP install diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1cdaadaae..ce05cd800 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -161,12 +161,15 @@ function activate( $args, $assoc_args = array() ) { } else { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { $status = $this->get_status( $plugin->file ); + // Network-active is the highest level of activation status + if ( 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); + continue; + } + // Don't reactivate active plugins, but do let them become network-active if ( ! $network_wide && 'active' === $status ) { WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); continue; - } else if ( $network_wide && 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); - continue; } activate_plugin( $plugin->file, '', $network_wide ); From deb90bd4c5d29e23f1ab311d44678951863b4876 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:07:17 -0800 Subject: [PATCH 3354/5359] Drop tag used for local dev --- features/plugin.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index df1b50b3c..dd04762d0 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -161,7 +161,6 @@ Feature: Manage WordPress plugins Status: Network Active """ - @daniel Scenario: Network activate a plugin Given a WP multisite install From fbe94017020f04f57cf52dc0a2d2fe68839e972b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:08:02 -0800 Subject: [PATCH 3355/5359] Drop tests we no longer need --- features/plugin.feature | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index dd04762d0..49811617b 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -222,39 +222,6 @@ Feature: Manage WordPress plugins | name | status | | akismet | active | - Scenario: Activate a plugin which is already active - Given a WP multisite install - - When I run `wp plugin activate akismet` - Then STDOUT should be: - """ - Success: Plugin 'akismet' activated. - """ - - When I try `wp plugin activate akismet` - Then STDERR should be: - """ - Warning: Plugin 'akismet' is already active. - """ - - When I run `wp plugin deactivate akismet` - Then STDOUT should be: - """ - Success: Plugin 'akismet' deactivated. - """ - - When I run `wp plugin activate akismet --network` - Then STDOUT should be: - """ - Success: Plugin 'akismet' network activated. - """ - - When I try `wp plugin activate akismet --network` - Then STDERR should be: - """ - Warning: Plugin 'akismet' is already network active. - """ - Scenario: Plugin name with HTML entities Given a WP install From 80e50b9a47327d444f5f988c6f18d8d76626791b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:24:08 -0800 Subject: [PATCH 3356/5359] More consistent behavior for plugin deactivation * Network active plugins must be deactivated with `--network` flag * Throw a warning when an inactive plugin is attempted to be deactivated * Active plugins must be deactivated before network activating --- features/plugin.feature | 18 ++++++++++++++++++ php/commands/plugin.php | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 49811617b..1436c2325 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -193,6 +193,24 @@ Feature: Manage WordPress plugins Warning: Plugin 'akismet' is already network active. """ + When I run `wp plugin deactivate akismet` + Then STDERR should contain: + """ + Warning: Plugin 'akismet' is network active and must be deactivated with --network flag. + """ + + When I run `wp plugin deactivate akismet --network` + Then STDOUT should contain: + """ + Success: Plugin 'akismet' network deactivated. + """ + + When I run `wp plugin deactivate akismet` + Then STDERR should contain: + """ + Warning: Plugin 'akismet' isn't active. + """ + Scenario: List plugins Given a WP install diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ce05cd800..6cd60ff4c 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -172,6 +172,11 @@ function activate( $args, $assoc_args = array() ) { continue; } + // Plugins need to be deactivated before being network activated + if ( $network_wide && 'active' === $status ) { + deactivate_plugins( $plugin->file, false, false ); + } + activate_plugin( $plugin->file, '', $network_wide ); $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); @@ -201,6 +206,19 @@ function deactivate( $args, $assoc_args = array() ) { $this->update_plugins_status( "deactivate", $network_wide ); } else { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + + $status = $this->get_status( $plugin->file ); + // Network active plugins must be explicitly deactivated + if ( ! $network_wide && 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); + continue; + } + + if ( ! in_array( $status, array( 'active', 'active-network' ) ) ) { + WP_CLI::warning( "Plugin '{$plugin->name}' isn't active." ); + continue; + } + deactivate_plugins( $plugin->file, false, $network_wide ); $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); From 53776e5c64c09376a7eadfc98e96285bbcb2032e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:33:43 -0800 Subject: [PATCH 3357/5359] Update plugin fetcher to match on full path WordPress stores dirname/filename.php in the database, so this is a valid name to use --- php/WP_CLI/Fetchers/Plugin.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php index 5f29dfc31..13ccfaf25 100644 --- a/php/WP_CLI/Fetchers/Plugin.php +++ b/php/WP_CLI/Fetchers/Plugin.php @@ -21,6 +21,7 @@ class Plugin extends Base { public function get( $name ) { foreach ( get_plugins() as $file => $_ ) { if ( $file === "$name.php" || + ( $name && $file === $name ) || ( dirname( $file ) === $name && $name !== '.' ) ) { return (object) compact( 'name', 'file' ); } From 678593f338d0d257eb6b3e9075ff68e1e44fb449 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 19 Dec 2014 12:39:12 -0800 Subject: [PATCH 3358/5359] Drop unnecessary abstraction We're dropping duplicate code, and reusing our status checking logic --- php/commands/plugin.php | 109 +++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 6cd60ff4c..349e13c94 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -154,34 +154,36 @@ protected function get_all_items() { */ function activate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); - $enable_all = isset( $assoc_args['all'] ); - if ( $enable_all ) { - $this->update_plugins_status( "activate", $network_wide ); - } else { - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - $status = $this->get_status( $plugin->file ); - // Network-active is the highest level of activation status - if ( 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); - continue; - } - // Don't reactivate active plugins, but do let them become network-active - if ( ! $network_wide && 'active' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); - continue; - } - - // Plugins need to be deactivated before being network activated - if ( $network_wide && 'active' === $status ) { - deactivate_plugins( $plugin->file, false, false ); - } - - activate_plugin( $plugin->file, '', $network_wide ); - - $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); + if ( isset( $assoc_args['all'] ) ) { + $args = array_map( function( $file ){ + return Utils\get_plugin_name( $file ); + }, array_keys( get_plugins() ) ); + } + + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + $status = $this->get_status( $plugin->file ); + // Network-active is the highest level of activation status + if ( 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); + continue; + } + // Don't reactivate active plugins, but do let them become network-active + if ( ! $network_wide && 'active' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); + continue; + } + + // Plugins need to be deactivated before being network activated + if ( $network_wide && 'active' === $status ) { + deactivate_plugins( $plugin->file, false, false ); } + + activate_plugin( $plugin->file, '', $network_wide ); + + $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); } + } /** @@ -202,27 +204,29 @@ function deactivate( $args, $assoc_args = array() ) { $network_wide = isset( $assoc_args['network'] ); $disable_all = isset( $assoc_args['all'] ); - if ( $disable_all ) { - $this->update_plugins_status( "deactivate", $network_wide ); - } else { - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - - $status = $this->get_status( $plugin->file ); - // Network active plugins must be explicitly deactivated - if ( ! $network_wide && 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); - continue; - } + if ( isset( $assoc_args['all'] ) ) { + $args = array_map( function( $file ){ + return Utils\get_plugin_name( $file ); + }, array_keys( get_plugins() ) ); + } - if ( ! in_array( $status, array( 'active', 'active-network' ) ) ) { - WP_CLI::warning( "Plugin '{$plugin->name}' isn't active." ); - continue; - } + foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - deactivate_plugins( $plugin->file, false, $network_wide ); + $status = $this->get_status( $plugin->file ); + // Network active plugins must be explicitly deactivated + if ( ! $network_wide && 'active-network' === $status ) { + WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); + continue; + } - $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); + if ( ! in_array( $status, array( 'active', 'active-network' ) ) ) { + WP_CLI::warning( "Plugin '{$plugin->name}' isn't active." ); + continue; } + + deactivate_plugins( $plugin->file, false, $network_wide ); + + $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); } } @@ -616,27 +620,6 @@ private function active_output( $name, $file, $network_wide, $action ) { } } - /** - * Enable or disable all plugins. - */ - private function update_plugins_status( $action, $network_wide ) { - $status = ( $action == "activate" ) ? "active" : "inactive"; - foreach ( get_plugins() as $file => $details ) { - if ( $this->get_status( $file ) == $status ) { - continue; - } - - if ( $action == "activate" ) { - activate_plugins( $file, false, $network_wide ); - } else { - deactivate_plugins( $file, false, $network_wide ); - } - - $name = Utils\get_plugin_name( $file ); - $this->active_output( $name, $file, $network_wide, $action ); - } - } - protected function get_status( $file ) { if ( is_plugin_active_for_network( $file ) ) return 'active-network'; From d59761f63f36c31a73d07d34269a9e7f9e03acee Mon Sep 17 00:00:00 2001 From: "Svetoslav Marinov (Slavi)" <slavi@orbisius.com> Date: Sun, 21 Dec 2014 14:48:14 +0200 Subject: [PATCH 3359/5359] Fix: handling the case where plugins that are not in own folders e.g. Hello Dolly -> plugins/hello.php --- php/commands/plugin.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 1cdaadaae..6082ed770 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -647,7 +647,13 @@ private function _delete( $plugin ) { $path = path_join( WP_PLUGIN_DIR, $plugin_dir ); if ( \WP_CLI\Utils\is_windows() ) { - $command = 'rd /s /q '; + // Handles plugins that are not in own folders + // e.g. Hello Dolly -> plugins/hello.php + if ( is_file( $path ) ) { + $command = 'del /f /q '; + } else { + $command = 'rd /s /q '; + } $path = str_replace( "/", "\\", $path ); } else { $command = 'rm -rf '; From 2b89a1584994aa1b1433bb995f65b4fe10603ea0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 14:50:55 -0200 Subject: [PATCH 3360/5359] remove extra lines before global parameters when calling `wp post --help` --- php/WP_CLI/Dispatcher/CompositeCommand.php | 4 ++++ templates/man-params.mustache | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index cc7258d03..7b01e02fe 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -235,6 +235,10 @@ protected function get_global_params( $root_command = false ) { $binding = array(); $binding['root_command'] = $root_command; + if (! $this->can_have_subcommands() || ( is_object( $this->parent ) && get_class( $this->parent ) == 'WP_CLI\Dispatcher\CompositeCommand' )) { + $binding['is_subcommand'] = true; + } + foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { if ( false === $details['runtime'] ) continue; diff --git a/templates/man-params.mustache b/templates/man-params.mustache index a27f4d846..53ca9addc 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -1,7 +1,7 @@ -{{^root_command}} +{{#is_subcommand}} -{{/root_command}} +{{/is_subcommand}} ## GLOBAL PARAMETERS {{#parameters}} From a2481164aec1510ea2f6240ff3a4043681c84e13 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 15:36:40 -0200 Subject: [PATCH 3361/5359] add `wp site archive` and `wp site unarchive` subcommands --- features/site.feature | 26 ++++++++++++++++++++++++ php/commands/site.php | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/features/site.feature b/features/site.feature index 3a0382007..300094374 100644 --- a/features/site.feature +++ b/features/site.feature @@ -84,3 +84,29 @@ Feature: Manage sites in a multisite installation http://example.com/first """ + Scenario: Archive/unarchive a site + Given a WP multisite install + And I run `wp site create --slug=first --porcelain` + And save STDOUT as {SITE_ID} + + When I run `wp site archive {SITE_ID}` + Then STDOUT should be: + """ + Success: Site {SITE_ID} archived. + """ + + When I run `wp site list --fields=blog_id,archived` + Then STDOUT should be a table containing rows: + | blog_id | archived | + | {SITE_ID} | 1 | + + When I run `wp site unarchive {SITE_ID}` + Then STDOUT should be: + """ + Success: Site {SITE_ID} unarchived. + """ + + When I run `wp site list --fields=blog_id,archived` + Then STDOUT should be a table containing rows: + | blog_id | archived | + | {SITE_ID} | 0 | diff --git a/php/commands/site.php b/php/commands/site.php index 7f286e167..b01f0dabb 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -429,6 +429,52 @@ public function url( $args ) { parent::_url( $args, 'get_site_url' ); } + + /** + * Archive one or more sites + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to archive. + * + * ## EXAMPLES + * + * wp site archive 123 + */ + public function archive( $args ) { + $this->update_site_status( $args, 'archived', 1 ); + } + + /** + * Unarchive one or more sites + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to unarchive. + * + * ## EXAMPLES + * + * wp site unarchive 123 + */ + public function unarchive( $args ) { + $this->update_site_status( $args, 'archived', 0 ); + } + + private function update_site_status( $ids, $pref, $value ) { + if ( $pref == 'archived' && $value == 1 ) { + $action = 'archived'; + } else if ( $pref == 'archived' && $value == 0) { + $action = 'unarchived'; + } + + foreach ( $ids as $site_id ) { + $site = $this->fetcher->get_check( $site_id ); + update_blog_status( $site->blog_id, $pref, $value ); + WP_CLI::success( "Site {$site->blog_id} $action." ); + } + } } WP_CLI::add_command( 'site', 'Site_Command' ); From a865a1561411145329ea943cc009acd9fa404b6e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 15:51:12 -0200 Subject: [PATCH 3362/5359] warning message when trying to archive a site that is already archived --- features/site.feature | 35 ++++++++++++++++++++++++++--------- php/commands/site.php | 7 +++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/features/site.feature b/features/site.feature index 300094374..deeecc14a 100644 --- a/features/site.feature +++ b/features/site.feature @@ -87,26 +87,43 @@ Feature: Manage sites in a multisite installation Scenario: Archive/unarchive a site Given a WP multisite install And I run `wp site create --slug=first --porcelain` - And save STDOUT as {SITE_ID} + And save STDOUT as {FIRST_SITE} + And I run `wp site create --slug=second --porcelain` + And save STDOUT as {SECOND_SITE} - When I run `wp site archive {SITE_ID}` + When I run `wp site archive {FIRST_SITE}` Then STDOUT should be: """ - Success: Site {SITE_ID} archived. + Success: Site {FIRST_SITE} archived. + """ + + When I run `wp site list --fields=blog_id,archived` + Then STDOUT should be a table containing rows: + | blog_id | archived | + | {FIRST_SITE} | 1 | + + When I run `wp site archive {FIRST_SITE} {SECOND_SITE}` + Then STDERR should be: + """ + Warning: Site {FIRST_SITE} already archived. + """ + And STDOUT should be: + """ + Success: Site {SECOND_SITE} archived. """ When I run `wp site list --fields=blog_id,archived` Then STDOUT should be a table containing rows: - | blog_id | archived | - | {SITE_ID} | 1 | + | blog_id | archived | + | {FIRST_SITE} | 1 | - When I run `wp site unarchive {SITE_ID}` + When I run `wp site unarchive {FIRST_SITE}` Then STDOUT should be: """ - Success: Site {SITE_ID} unarchived. + Success: Site {FIRST_SITE} unarchived. """ When I run `wp site list --fields=blog_id,archived` Then STDOUT should be a table containing rows: - | blog_id | archived | - | {SITE_ID} | 0 | + | blog_id | archived | + | {FIRST_SITE} | 0 | diff --git a/php/commands/site.php b/php/commands/site.php index b01f0dabb..08687e66e 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -471,6 +471,13 @@ private function update_site_status( $ids, $pref, $value ) { foreach ( $ids as $site_id ) { $site = $this->fetcher->get_check( $site_id ); + $old_value = get_blog_status( $site->blog_id, $pref ); + + if ( $value == $old_value ) { + WP_CLI::warning( "Site {$site->blog_id} already $action." ); + continue; + } + update_blog_status( $site->blog_id, $pref, $value ); WP_CLI::success( "Site {$site->blog_id} $action." ); } From 144fe62e61e292645cd9b48dd920f065cddc206f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 16:03:38 -0200 Subject: [PATCH 3363/5359] warning when user tries to change the main site --- features/site.feature | 6 ++++++ php/commands/site.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/features/site.feature b/features/site.feature index deeecc14a..fdb7d70e8 100644 --- a/features/site.feature +++ b/features/site.feature @@ -127,3 +127,9 @@ Feature: Manage sites in a multisite installation Then STDOUT should be a table containing rows: | blog_id | archived | | {FIRST_SITE} | 0 | + + When I run `wp site archive 1` + Then STDERR should be: + """ + Warning: You are not allowed to change the main site. + """ \ No newline at end of file diff --git a/php/commands/site.php b/php/commands/site.php index 08687e66e..a4a03ace6 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -471,6 +471,12 @@ private function update_site_status( $ids, $pref, $value ) { foreach ( $ids as $site_id ) { $site = $this->fetcher->get_check( $site_id ); + + if ( is_main_site( $site->blog_id ) ) { + WP_CLI::warning( "You are not allowed to change the main site." ); + continue; + } + $old_value = get_blog_status( $site->blog_id, $pref ); if ( $value == $old_value ) { From 6c8a700f3f85893e9c0f76add2db7b6cbe8902dd Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 16:16:25 -0200 Subject: [PATCH 3364/5359] add subcommands to activate and deactivate a site --- features/site.feature | 50 +++++++++++++++++++++++++++++++++++++++++++ php/commands/site.php | 36 +++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/features/site.feature b/features/site.feature index fdb7d70e8..a7fd496c1 100644 --- a/features/site.feature +++ b/features/site.feature @@ -129,6 +129,56 @@ Feature: Manage sites in a multisite installation | {FIRST_SITE} | 0 | When I run `wp site archive 1` + Then STDERR should be: + """ + Warning: You are not allowed to change the main site. + """ + + Scenario: Activate/deactivate a site + Given a WP multisite install + And I run `wp site create --slug=first --porcelain` + And save STDOUT as {FIRST_SITE} + And I run `wp site create --slug=second --porcelain` + And save STDOUT as {SECOND_SITE} + + When I run `wp site deactivate {FIRST_SITE}` + Then STDOUT should be: + """ + Success: Site {FIRST_SITE} deactivated. + """ + + When I run `wp site list --fields=blog_id,deleted` + Then STDOUT should be a table containing rows: + | blog_id | deleted | + | {FIRST_SITE} | 1 | + + When I run `wp site deactivate {FIRST_SITE} {SECOND_SITE}` + Then STDERR should be: + """ + Warning: Site {FIRST_SITE} already deactivated. + """ + And STDOUT should be: + """ + Success: Site {SECOND_SITE} deactivated. + """ + + When I run `wp site list --fields=blog_id,deleted` + Then STDOUT should be a table containing rows: + | blog_id | deleted | + | {FIRST_SITE} | 1 | + + When I run `wp site activate {FIRST_SITE}` + Then STDOUT should be: + """ + Success: Site {FIRST_SITE} activated. + """ + + When I run `wp site list --fields=blog_id,deleted` + Then STDOUT should be a table containing rows: + | blog_id | deleted | + | {FIRST_SITE} | 0 | + + When I run `wp site deactivate 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. diff --git a/php/commands/site.php b/php/commands/site.php index a4a03ace6..2eddda164 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -462,11 +462,47 @@ public function unarchive( $args ) { $this->update_site_status( $args, 'archived', 0 ); } + /** + * Activate one or more sites + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to activate. + * + * ## EXAMPLES + * + * wp site activate 123 + */ + public function activate( $args ) { + $this->update_site_status( $args, 'deleted', 0 ); + } + + /** + * Deactivate one or more sites + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to deactivate. + * + * ## EXAMPLES + * + * wp site deactivate 123 + */ + public function deactivate( $args ) { + $this->update_site_status( $args, 'deleted', 1 ); + } + private function update_site_status( $ids, $pref, $value ) { if ( $pref == 'archived' && $value == 1 ) { $action = 'archived'; } else if ( $pref == 'archived' && $value == 0) { $action = 'unarchived'; + } else if ( $pref == 'deleted' && $value == 1 ) { + $action = 'deactivated'; + } else if ( $pref == 'deleted' && $value == 0 ) { + $action = 'activated'; } foreach ( $ids as $site_id ) { From 1e62ae3f1f9c15f0ec24b8b1ffe25434f46bed73 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 16:33:51 -0200 Subject: [PATCH 3365/5359] add subcommands to mark or remove a site from spam --- features/site.feature | 50 +++++++++++++++++++++++++++++++++++++++++++ php/commands/site.php | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/features/site.feature b/features/site.feature index a7fd496c1..87493ce66 100644 --- a/features/site.feature +++ b/features/site.feature @@ -179,6 +179,56 @@ Feature: Manage sites in a multisite installation | {FIRST_SITE} | 0 | When I run `wp site deactivate 1` + Then STDERR should be: + """ + Warning: You are not allowed to change the main site. + """ + + Scenario: Mark/remove a site from spam + Given a WP multisite install + And I run `wp site create --slug=first --porcelain` + And save STDOUT as {FIRST_SITE} + And I run `wp site create --slug=second --porcelain` + And save STDOUT as {SECOND_SITE} + + When I run `wp site spam {FIRST_SITE}` + Then STDOUT should be: + """ + Success: Site {FIRST_SITE} marked as spam. + """ + + When I run `wp site list --fields=blog_id,spam` + Then STDOUT should be a table containing rows: + | blog_id | spam | + | {FIRST_SITE} | 1 | + + When I run `wp site spam {FIRST_SITE} {SECOND_SITE}` + Then STDERR should be: + """ + Warning: Site {FIRST_SITE} already marked as spam. + """ + And STDOUT should be: + """ + Success: Site {SECOND_SITE} marked as spam. + """ + + When I run `wp site list --fields=blog_id,spam` + Then STDOUT should be a table containing rows: + | blog_id | spam | + | {FIRST_SITE} | 1 | + + When I run `wp site not-spam {FIRST_SITE}` + Then STDOUT should be: + """ + Success: Site {FIRST_SITE} removed from spam. + """ + + When I run `wp site list --fields=blog_id,spam` + Then STDOUT should be a table containing rows: + | blog_id | spam | + | {FIRST_SITE} | 0 | + + When I run `wp site spam 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. diff --git a/php/commands/site.php b/php/commands/site.php index 2eddda164..075ca2ba5 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -494,6 +494,40 @@ public function deactivate( $args ) { $this->update_site_status( $args, 'deleted', 1 ); } + /** + * Mark one or more sites as spam + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to be marked as spam. + * + * ## EXAMPLES + * + * wp site spam 123 + */ + public function spam( $args ) { + $this->update_site_status( $args, 'spam', 1 ); + } + + /** + * Remove one or more sites from spam + * + * ## OPTIONS + * + * <id>... + * : One or more IDs of sites to remove from spam. + * + * ## EXAMPLES + * + * wp site not-spam 123 + * + * @subcommand not-spam + */ + public function not_spam( $args ) { + $this->update_site_status( $args, 'spam', 0 ); + } + private function update_site_status( $ids, $pref, $value ) { if ( $pref == 'archived' && $value == 1 ) { $action = 'archived'; @@ -503,6 +537,10 @@ private function update_site_status( $ids, $pref, $value ) { $action = 'deactivated'; } else if ( $pref == 'deleted' && $value == 0 ) { $action = 'activated'; + } else if ( $pref == 'spam' && $value == 1 ) { + $action = 'marked as spam'; + } else if ( $pref == 'spam' && $value == 0 ) { + $action = 'removed from spam'; } foreach ( $ids as $site_id ) { From f7bf2f87d4e31d4a4754c5e6e49a355b7e83c732 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 22 Dec 2014 16:35:58 -0200 Subject: [PATCH 3366/5359] add missing new line to the end of the file --- features/site.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/site.feature b/features/site.feature index 87493ce66..5b5767fda 100644 --- a/features/site.feature +++ b/features/site.feature @@ -232,4 +232,4 @@ Feature: Manage sites in a multisite installation Then STDERR should be: """ Warning: You are not allowed to change the main site. - """ \ No newline at end of file + """ From 53378cc92897f8251fd566d805b1a454840c9d6e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 22 Dec 2014 12:42:17 -0800 Subject: [PATCH 3367/5359] Don't force update check on plugin install This reduces our dependency on WordPress.org API for installing. The genesis of this call appears to be a copy and paste error: 1. https://github.com/wp-cli/wp-cli/commit/1e2b9ee2384139c16aadb772ce0ccbcd7df52acb#diff-59ccae364a062cc72d61b0199f525e79R112 2. https://github.com/wp-cli/wp-cli/commit/1e2b9ee2384139c16aadb772ce0ccbcd7df52acb#diff-78c563be62d40fb1c0c180515eef9636L60 --- php/WP_CLI/CommandWithUpgrade.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b24f1c6fe..b3d7a3578 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -108,8 +108,6 @@ private function show_legend( $items ) { } function install( $args, $assoc_args ) { - // Force WordPress to check for updates - call_user_func( $this->upgrade_refresh ); foreach ( $args as $slug ) { $local_or_remote_zip_file = false; From 12a6de75c42dd52635c38ca7c069578484dceb02 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 22 Dec 2014 13:00:20 -0800 Subject: [PATCH 3368/5359] Throw error when converting multisite to subdomains with "localhost" Subdomains don't work at all when the domain is "localhost" --- features/core.feature | 12 ++++++++++++ php/commands/core.php | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index b226393cb..32d3210ce 100644 --- a/features/core.feature +++ b/features/core.feature @@ -247,6 +247,18 @@ Feature: Manage WordPress installation example.com """ + Scenario: Install multisite with subdomains on localhost + Given an empty directory + And WP files + And wp-config.php + And a database + + When I try `wp core multisite-install --url=http://localhost/ --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1 --subdomains` + Then STDERR should contain: + """ + Error: Multisite with subdomains cannot be configured when domain is 'localhost'. + """ + Scenario: Update from a ZIP file Given a WP install diff --git a/php/commands/core.php b/php/commands/core.php index 73200db38..982b18ddc 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -441,7 +441,7 @@ public function install( $args, $assoc_args ) { * Default: '/' * * [--subdomains] - * : If passed, the network will use subdomains, instead of subdirectories. + * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. * * @subcommand multisite-convert * @alias install-network @@ -473,7 +473,7 @@ public function multisite_convert( $args, $assoc_args ) { * Default: '/' * * [--subdomains] - * : If passed, the network will use subdomains, instead of subdirectories. + * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. * * --title=<site-title> * : The title of the new site. @@ -595,13 +595,17 @@ private function _multisite_convert( $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + $domain = self::get_clean_basedomain(); + if ( 'localhost' === $domain && ! empty( $assoc_args['subdomains'] ) ) { + WP_CLI::error( "Multisite with subdomains cannot be configured when domain is 'localhost'." ); + } + // need to register the multisite tables manually for some reason foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) $wpdb->$table = $prefixed_table; install_network(); - $domain = self::get_clean_basedomain(); $result = populate_network( $assoc_args['site_id'], $domain, From f4472aa75d3064df42481d81dcceb79eb36bdfd5 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Tue, 23 Dec 2014 11:55:45 +0100 Subject: [PATCH 3369/5359] Add behat test for scaffolding post type with icon --- features/scaffold.feature | 11 +++++++++++ templates/post_type.mustache | 1 + 2 files changed, 12 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 438e1842e..86b2f307b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -64,6 +64,10 @@ Feature: WordPress code scaffolding """ __( 'Zombies', 'zombieland' """ + And STDOUT should contain: + """ + 'menu_icon' => 'dashicons-admin-post', + """ Scenario: CPT slug is too long When I try `wp scaffold post-type slugiswaytoolonginfact` @@ -80,6 +84,13 @@ Feature: WordPress code scaffolding __( 'Brain eaters' """ + Scenario: Scaffold a Custom Post Type with icon + When I run `wp scaffold post-type zombie --icon="art"` + Then STDOUT should contain: + """ + 'menu_icon' => 'dashicons-art', + """ + Scenario: Scaffold a plugin Given I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 4cf479eb6..d3ddf21bc 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -22,4 +22,5 @@ 'has_archive' => true, 'rewrite' => true, 'query_var' => true, + 'menu_icon' => 'dashicons-admin-post', ) ); From 739126c5d2ff97344dae5eb0e7715165c20c3431 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Geus <sebastiaan@hoppinger.com> Date: Tue, 23 Dec 2014 11:56:50 +0100 Subject: [PATCH 3370/5359] implement icon argument for scaffold post type command --- php/commands/scaffold.php | 4 ++++ templates/post_type.mustache | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 050b81228..2f50a0867 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -24,6 +24,9 @@ class Scaffold_Command extends WP_CLI_Command { * [--textdomain=<textdomain>] * : The textdomain to use for the labels. * + * [--icon=<icon>] + * : The dashicon to use in the menu. + * * [--theme] * : Create a file in the active theme directory, instead of sending to * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. @@ -46,6 +49,7 @@ function post_type( $args, $assoc_args ) { $defaults = array( 'textdomain' => '', + 'icon' => 'admin-post', ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( diff --git a/templates/post_type.mustache b/templates/post_type.mustache index d3ddf21bc..f017dccaf 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -22,5 +22,5 @@ 'has_archive' => true, 'rewrite' => true, 'query_var' => true, - 'menu_icon' => 'dashicons-admin-post', + 'menu_icon' => 'dashicons-{{icon}}', ) ); From d4d19dd2edccf6183a9a748198cb3c0875d5f55b Mon Sep 17 00:00:00 2001 From: ozh <ozh@ozh.org> Date: Wed, 31 Dec 2014 11:06:50 +0100 Subject: [PATCH 3371/5359] Work around =~ operator for older Bash versions --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index b9ddf1f06..4238760ad 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -60,7 +60,7 @@ install_db() { local EXTRA="" if ! [ -z $DB_HOSTNAME ] ; then - if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then + if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" elif ! [ -z $DB_SOCK_OR_PORT ] ; then EXTRA=" --socket=$DB_SOCK_OR_PORT" From 9e4723feace69357fdc755f0399ca25d113c4c43 Mon Sep 17 00:00:00 2001 From: ozh <ozh@ozh.org> Date: Fri, 2 Jan 2015 22:13:30 +0100 Subject: [PATCH 3372/5359] Use env variable for WP_CORE_DIR if set --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 4238760ad..a3f1184df 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -12,7 +12,7 @@ DB_HOST=${4-localhost} WP_VERSION=${5-latest} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} -WP_CORE_DIR=/tmp/wordpress/ +WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} set -ex From 235aaa1d305a5eadf61c3e5bbd0aeb4a574a2f66 Mon Sep 17 00:00:00 2001 From: oneumyvakin <oneumyvakin@gmail.com> Date: Wed, 7 Jan 2015 14:12:35 +0600 Subject: [PATCH 3373/5359] Add "skip-themes" command --- php/config-spec.php | 7 +++++++ php/utils-wp.php | 18 ++++++++++++++++++ php/wp-settings-cli.php | 10 ++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 37f98fbf5..1d67b11b8 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -34,6 +34,13 @@ 'desc' => 'Skip loading all or some plugins', 'default' => '', ), + + 'skip-themes' => array( + 'runtime' => '[=<theme>]', + 'file' => '<list>', + 'desc' => 'Skip loading all or some themes', + 'default' => '', + ), 'require' => array( 'runtime' => '=<path>', diff --git a/php/utils-wp.php b/php/utils-wp.php index dba28dfc2..b9ee33c19 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -95,6 +95,24 @@ function is_plugin_skipped( $file ) { return in_array( $name, array_filter( $skipped_plugins ) ); } +function get_theme_name( $path ) { + return basename( $path ); +} + +function is_theme_skipped( $path ) { + $name = get_theme_name( $path ); + + $skipped_themes = \WP_CLI::get_runner()->config['skip-themes']; + if ( true === $skipped_themes ) + return true; + + if ( ! is_array( $skipped_themes ) ) { + $skipped_themes = explode( ',', $skipped_themes ); + } + + return in_array( $name, array_filter( $skipped_themes ) ); +} + /** * Register the sidebar for unused widgets * Core does this in /wp-admin/widgets.php, which isn't helpful diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index f2e2fc85e..6944f3797 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -326,10 +326,12 @@ function wp_is_mobile() { // Load the functions for the active theme, for both parent and child theme if applicable. global $pagenow; if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { - if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) - include( STYLESHEETPATH . '/functions.php' ); - if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) - include( TEMPLATEPATH . '/functions.php' ); + if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { + if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) + include( STYLESHEETPATH . '/functions.php' ); + if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) + include( TEMPLATEPATH . '/functions.php' ); + } } do_action( 'after_setup_theme' ); From 2d31834d10db293ef48939ac1640b7137fa3fe57 Mon Sep 17 00:00:00 2001 From: oneumyvakin <oneumyvakin@gmail.com> Date: Thu, 8 Jan 2015 16:37:59 +0600 Subject: [PATCH 3374/5359] Add tests for "skip-themes" --- features/skip-themes.feature | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 features/skip-themes.feature diff --git a/features/skip-themes.feature b/features/skip-themes.feature new file mode 100644 index 000000000..bd9cd2b41 --- /dev/null +++ b/features/skip-themes.feature @@ -0,0 +1,80 @@ +Feature: Skipping themes + + Scenario: Skipping themes via global flag + Given a WP install + And I run `wp theme install classic` + And I run `wp theme install default --activate` + + When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified theme should be skipped + When I run `wp --skip-themes=default eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + # All themes should be not skipped + When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + # Skip another theme + When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified theme should still show up as an active theme + When I run `wp --skip-themes theme status default` + Then STDOUT should contain: + """ + Active + """ + + # Skip several themes + When I run `wp --skip-themes=classic,default eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + Scenario: Skipping multiple themes via config file + Given a WP install + And a wp-cli.yml file: + """ + skip-themes: + - classic + - default + """ + And I run `wp theme install classic --activate` + And I run `wp theme install default` + + # The classic theme should show up as an active theme + When I run `wp theme status` + Then STDOUT should contain: + """ + A classic + """ + + # The default theme should show up as an installed theme + When I run `wp theme status` + Then STDOUT should contain: + """ + I default + """ + + And I run `wp theme activate default` + # The specified theme should be skipped + When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ \ No newline at end of file From 37d9f4709738ca0c64a6edd31082643379f76371 Mon Sep 17 00:00:00 2001 From: oneumyvakin <oneumyvakin@gmail.com> Date: Thu, 8 Jan 2015 16:49:51 +0600 Subject: [PATCH 3375/5359] Revert "Add tests for "skip-themes"" This reverts commit 2d31834d10db293ef48939ac1640b7137fa3fe57. --- features/skip-themes.feature | 80 ------------------------------------ 1 file changed, 80 deletions(-) delete mode 100644 features/skip-themes.feature diff --git a/features/skip-themes.feature b/features/skip-themes.feature deleted file mode 100644 index bd9cd2b41..000000000 --- a/features/skip-themes.feature +++ /dev/null @@ -1,80 +0,0 @@ -Feature: Skipping themes - - Scenario: Skipping themes via global flag - Given a WP install - And I run `wp theme install classic` - And I run `wp theme install default --activate` - - When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - true - """ - - # The specified theme should be skipped - When I run `wp --skip-themes=default eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - - # All themes should be not skipped - When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - - # Skip another theme - When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - true - """ - - # The specified theme should still show up as an active theme - When I run `wp --skip-themes theme status default` - Then STDOUT should contain: - """ - Active - """ - - # Skip several themes - When I run `wp --skip-themes=classic,default eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - - Scenario: Skipping multiple themes via config file - Given a WP install - And a wp-cli.yml file: - """ - skip-themes: - - classic - - default - """ - And I run `wp theme install classic --activate` - And I run `wp theme install default` - - # The classic theme should show up as an active theme - When I run `wp theme status` - Then STDOUT should contain: - """ - A classic - """ - - # The default theme should show up as an installed theme - When I run `wp theme status` - Then STDOUT should contain: - """ - I default - """ - - And I run `wp theme activate default` - # The specified theme should be skipped - When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ \ No newline at end of file From d5f7177ccfdc3e555a9cf2d62b76eab7dbee9640 Mon Sep 17 00:00:00 2001 From: oneumyvakin <oneumyvakin@gmail.com> Date: Thu, 8 Jan 2015 17:17:01 +0600 Subject: [PATCH 3376/5359] Add skip-themes command with tests --- features/skip-themes.feature | 80 ++++++++++++++++++++++++++++++++++++ php/wp-settings-cli.php | 10 +++-- 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 features/skip-themes.feature diff --git a/features/skip-themes.feature b/features/skip-themes.feature new file mode 100644 index 000000000..bd9cd2b41 --- /dev/null +++ b/features/skip-themes.feature @@ -0,0 +1,80 @@ +Feature: Skipping themes + + Scenario: Skipping themes via global flag + Given a WP install + And I run `wp theme install classic` + And I run `wp theme install default --activate` + + When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified theme should be skipped + When I run `wp --skip-themes=default eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + # All themes should be not skipped + When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + # Skip another theme + When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + true + """ + + # The specified theme should still show up as an active theme + When I run `wp --skip-themes theme status default` + Then STDOUT should contain: + """ + Active + """ + + # Skip several themes + When I run `wp --skip-themes=classic,default eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ + + Scenario: Skipping multiple themes via config file + Given a WP install + And a wp-cli.yml file: + """ + skip-themes: + - classic + - default + """ + And I run `wp theme install classic --activate` + And I run `wp theme install default` + + # The classic theme should show up as an active theme + When I run `wp theme status` + Then STDOUT should contain: + """ + A classic + """ + + # The default theme should show up as an installed theme + When I run `wp theme status` + Then STDOUT should contain: + """ + I default + """ + + And I run `wp theme activate default` + # The specified theme should be skipped + When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` + Then STDOUT should be: + """ + false + """ \ No newline at end of file diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 6944f3797..21014a654 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -327,10 +327,12 @@ function wp_is_mobile() { global $pagenow; if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { - if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) - include( STYLESHEETPATH . '/functions.php' ); - if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) - include( TEMPLATEPATH . '/functions.php' ); + if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { + if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) + include( STYLESHEETPATH . '/functions.php' ); + if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) + include( TEMPLATEPATH . '/functions.php' ); + } } } From 230ba53bd56148b703112caa13cf58238058568b Mon Sep 17 00:00:00 2001 From: oneumyvakin <oneumyvakin@gmail.com> Date: Thu, 8 Jan 2015 22:53:30 +0600 Subject: [PATCH 3377/5359] Remove unnecessary condition, fix formatting in tests --- features/skip-themes.feature | 23 ++++++++++++----------- php/wp-settings-cli.php | 10 ++++------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/features/skip-themes.feature b/features/skip-themes.feature index bd9cd2b41..a285eec79 100644 --- a/features/skip-themes.feature +++ b/features/skip-themes.feature @@ -3,7 +3,7 @@ Feature: Skipping themes Scenario: Skipping themes via global flag Given a WP install And I run `wp theme install classic` - And I run `wp theme install default --activate` + And I run `wp theme install default --activate` When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` Then STDOUT should be: @@ -17,14 +17,14 @@ Feature: Skipping themes """ false """ - - # All themes should be not skipped + + # All themes should be skipped When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` Then STDOUT should be: """ false """ - + # Skip another theme When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` Then STDOUT should be: @@ -54,9 +54,9 @@ Feature: Skipping themes - classic - default """ - And I run `wp theme install classic --activate` - And I run `wp theme install default` - + And I run `wp theme install classic --activate` + And I run `wp theme install default` + # The classic theme should show up as an active theme When I run `wp theme status` Then STDOUT should contain: @@ -70,11 +70,12 @@ Feature: Skipping themes """ I default """ - - And I run `wp theme activate default` - # The specified theme should be skipped + + And I run `wp theme activate default` + + # The default theme should be skipped When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` Then STDOUT should be: """ false - """ \ No newline at end of file + """ diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 21014a654..6944f3797 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -327,12 +327,10 @@ function wp_is_mobile() { global $pagenow; if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { - if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { - if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) - include( STYLESHEETPATH . '/functions.php' ); - if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) - include( TEMPLATEPATH . '/functions.php' ); - } + if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) + include( STYLESHEETPATH . '/functions.php' ); + if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) + include( TEMPLATEPATH . '/functions.php' ); } } From 3155fbac809a51e24a8b8a68561027c3e58fff74 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 04:38:55 -0800 Subject: [PATCH 3378/5359] Indentation fixes again --- features/core.feature | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/features/core.feature b/features/core.feature index 3f84b643d..afee37b21 100644 --- a/features/core.feature +++ b/features/core.feature @@ -370,23 +370,23 @@ Feature: Manage WordPress installation """ Scenario: Don't run update when up-to-date - Given a WP install + Given a WP install - When I run `wp core update` - Then STDOUT should contain: - """ - WordPress is up to date - """ - And STDOUT should not contain: - """ - Updating - """ + When I run `wp core update` + Then STDOUT should contain: + """ + WordPress is up to date + """ + And STDOUT should not contain: + """ + Updating + """ - When I run `wp core update --force` - Then STDOUT should contain: - """ - Updating - """ + When I run `wp core update --force` + Then STDOUT should contain: + """ + Updating + """ Scenario: User defined in wp-cli.yml Given an empty directory From 6406e8a13798fcf194ec14c2f5ddfd8f2be7d290 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 04:39:38 -0800 Subject: [PATCH 3379/5359] First make sure core is up to date; required for older versions --- features/core.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/core.feature b/features/core.feature index afee37b21..c993a315a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -371,6 +371,7 @@ Feature: Manage WordPress installation Scenario: Don't run update when up-to-date Given a WP install + And I run `wp core update` When I run `wp core update` Then STDOUT should contain: From cf203804559a9428a998dfe25cb15921c2e8abda Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 04:42:23 -0800 Subject: [PATCH 3380/5359] Explicitly mark public --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 4c40336e0..b4809f4af 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -106,7 +106,7 @@ private function same_minor_release( $release_parts, $updates ) { * * @subcommand check-update */ - function check_update( $_, $assoc_args ) { + public function check_update( $_, $assoc_args ) { $updates = $this->get_updates( $assoc_args ); if ( $updates ) { From ec7ed9c5470d169c7ce50682311088d3addbcaf4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 04:43:01 -0800 Subject: [PATCH 3381/5359] More methods to be marked public --- php/commands/cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index b4809f4af..4cd16a8aa 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -31,7 +31,7 @@ private function command_to_array( $command ) { /** * Print WP-CLI version. */ - function version() { + public function version() { WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); } @@ -43,7 +43,7 @@ function version() { * [--format=<format>] * : Accepted values: json */ - function info( $_, $assoc_args ) { + public function info( $_, $assoc_args ) { $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); $runner = WP_CLI::get_runner(); @@ -136,7 +136,7 @@ public function check_update( $_, $assoc_args ) { * * @subcommand update */ - function update( $_, $assoc_args ) { + public function update( $_, $assoc_args ) { if ( 0 !== strpos( WP_CLI_ROOT, 'phar://' ) ) { WP_CLI::error( "You can only self-update PHARs" ); } @@ -259,7 +259,7 @@ private function get_updates( $assoc_args ) { * * @subcommand param-dump */ - function param_dump() { + public function param_dump() { echo json_encode( \WP_CLI::get_configurator()->get_spec() ); } @@ -268,7 +268,7 @@ function param_dump() { * * @subcommand cmd-dump */ - function cmd_dump() { + public function cmd_dump() { echo json_encode( self::command_to_array( WP_CLI::get_root_command() ) ); } @@ -283,7 +283,7 @@ function cmd_dump() { * --point=<point> * : The index to the current cursor position relative to the beginning of the command */ - function completions( $_, $assoc_args ) { + public function completions( $_, $assoc_args ) { $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); $compl = new \WP_CLI\Completions( $line ); $compl->render(); From 53ade8583989a8fd70a5e6a5c948cda1b40a9558 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 04:45:36 -0800 Subject: [PATCH 3382/5359] When GH returns an error, give more visibility into the error --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 4cd16a8aa..29239088d 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -213,7 +213,7 @@ private function get_updates( $assoc_args ) { $response = Utils\http_request( 'GET', $url, $headers, $options ); if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( "Failed to get latest version." ); + WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d)", $response->status_code ) ); } $release_data = json_decode( $response->body ); From 6e0e7b2c9c87b5c616fb09d8e592e1cec8535de2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 05:37:34 -0800 Subject: [PATCH 3383/5359] Trim contents, so we don't have to worry about newline --- php/wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-cli.php b/php/wp-cli.php index 46d703336..ab8bcf68b 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -2,7 +2,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', file_get_contents( WP_CLI_ROOT . '/VERSION' ) ); +define( 'WP_CLI_VERSION', trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ) ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From d3ea18a17965f94d1498a607087e02594fc826f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 06:10:29 -0800 Subject: [PATCH 3384/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 14a8c2457..66333910a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.17.1 \ No newline at end of file +0.18.0 From b234659488568850d9e74b8af073a0740815a892 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 07:24:28 -0800 Subject: [PATCH 3385/5359] Update .mailmap for v0.18.0 --- .mailmap | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index 9d78defad..78ecffe33 100644 --- a/.mailmap +++ b/.mailmap @@ -1,8 +1,12 @@ +Alex Mills <git@viper007bond.com> andreascreten <andreas@madewithlove.be> bartaakos <akos@netpositive.hu> bendoh <ben@thinkoomph.com> BoiteAWeb <juliobosk@gmail.com> boonebgorges <boonebgorges@gmail.com> +Borek Bernard <borekb@gmail.com> +borekb <borekb@gmail.com> +Brad Parbs <brad@bradparbs.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> clemens-tolboom <clemens@build2be.com> @@ -13,8 +17,8 @@ dangardner <dan@web.nearest.to> danielbachhuber <d@danielbachhuber.com> danielbachhuber <daniel@handbuilt.co> danielbachhuber <danielbachhuber@gmail.com> -dlh01 <david@alleyinteractive.com> dd32 <contact-atlassian@dd32.id.au> +dlh01 <david@alleyinteractive.com> drrobotnik <B@Brandons-Mac-Pro-4.local> dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> @@ -27,6 +31,7 @@ glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> +jeichorn <joshua.eichorn@pagely.com> jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> jmslbam <jmslbam@gmail.com> @@ -36,12 +41,10 @@ johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> -jeichorn <joshua.eichorn@pagely.com> Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> -santagada <santagada@gmail.com> lkwdwrd <woodward.lucas@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> @@ -50,8 +53,10 @@ mattheu <matthew@matth.eu> mboynes <mboynes@alleyinteractive.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> +mikey dubs <mike@herebox.org> milesj <mileswjohnson@gmail.com> MiteshShah <Mitesh.Shah@rtCamp.com> +miya0001 <miya@wpist.me> mwilliamson <michael.williamson@red-gate.com> mwilliamson <mike@zwobble.org> nacin <andrewnacin@gmail.com> @@ -67,13 +72,17 @@ ocean90 <dominikschilling+git@gmail.com> oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> +oneumyvakin <oneumyvakin@gmail.com> +ozh <ozh@ozh.org> phh <phh@peytz.dk> +Pippin Williamson <pippin@pippinsplugins.com> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> -rodrigoprimo <rodrigosprimo@gmail.com> rodrigoprimo <rodrigo@hacklab.com.br> +rodrigoprimo <rodrigosprimo@gmail.com> roelven <roel@soundcloud.com> ryanduff <ryan@fusionized.com> +santagada <santagada@gmail.com> sboisvert <stephane.boisvert@automattic.com> scribu <mail@scribu.net> scribu <scribu@gmail.com> @@ -81,10 +90,13 @@ sebastiaandegeus <sebastiaan@hoppinger.com> sibprogrammer <ayuzhakov@parallels.com> simonwheatley <simonw@codeforthepeople.com> soulou <leo@soulou.fr> +spacedmonkey <spacedmonkey2@gmail.com> SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> +Stephen Edgar <stephen@netweb.com.au> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> +Svetoslav Marinov (Slavi) <slavi@orbisius.com> szepeviktor <viktor@szepe.net> taupecat <tracy@taupecat.com> tddewey <td@tddewey.com> @@ -99,6 +111,7 @@ twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> +William Turrell <william@wturrell.co.uk> willmot <tom@humanmade.co.uk> wopr42 <john@zippykid.com> ziz <justin@crowdfavorite.com> From 2005f210c100e836a6d3f5f446ceb02076b8d62c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Jan 2015 09:13:22 -0800 Subject: [PATCH 3386/5359] Make sure version is trimmed on build too --- utils/make-phar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index 1841dcd34..1ce6f7b87 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -20,7 +20,7 @@ define( 'BE_QUIET', isset( $runtime_config['quiet'] ) && $runtime_config['quiet'] ); -$current_version = file_get_contents( './VERSION' ); +$current_version = trim( file_get_contents( './VERSION' ) ); if ( isset( $runtime_config['version'] ) ) { $new_version = $runtime_config['version']; From 6b52960318b6537ac76d29b49ec14e73651db872 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 15 Jan 2015 12:58:05 +0000 Subject: [PATCH 3387/5359] s/domain.com/example.com --- features/user.feature | 22 +++++++++++----------- php/commands/user.php | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/features/user.feature b/features/user.feature index a1151b09b..30890875a 100644 --- a/features/user.feature +++ b/features/user.feature @@ -130,9 +130,9 @@ Feature: Manage WordPress users And a users.csv file: """ user_login,user_email,display_name,role - bobjones,bobjones@domain.com,Bob Jones,contributor - newuser1,newuser1@domain.com,New User,author - admin,admin@domain.com,Existing User,administrator + bobjones,bobjones@example.com,Bob Jones,contributor + newuser1,newuser1@example.com,New User,author + admin,admin@example.com,Existing User,administrator """ When I try `wp user import-csv users-incorrect.csv --skip-update` @@ -162,7 +162,7 @@ Feature: Manage WordPress users [{ "user_login":"admin", "display_name":"Existing User", - "user_email":"admin@domain.com", + "user_email":"admin@example.com", "roles":"administrator" }] """ @@ -172,12 +172,12 @@ Feature: Manage WordPress users And a users.csv file: """ user_login,user_email,display_name,role - bobjones,bobjones@domain.com,Bob Jones,contributor - newuser1,newuser1@domain.com,New User,author - admin,admin@domain.com,Existing User,administrator + bobjones,bobjones@example.com,Bob Jones,contributor + newuser1,newuser1@example.com,New User,author + admin,admin@example.com,Existing User,administrator """ - When I run `wp user create bobjones bobjones@domain.com --display_name="Robert Jones" --role=administrator` + When I run `wp user create bobjones bobjones@example.com --display_name="Robert Jones" --role=administrator` Then STDOUT should not be empty When I run `wp user import-csv users.csv --skip-update` @@ -195,7 +195,7 @@ Feature: Manage WordPress users { "user_login":"bobjones", "display_name":"Robert Jones", - "user_email":"bobjones@domain.com", + "user_email":"bobjones@example.com", "roles":"administrator" } """ @@ -204,8 +204,8 @@ Feature: Manage WordPress users Given a WP install When I run `wp user delete 1 --yes` - And I run `wp user create bobjones bobjones@domain.com --display_name="Bob Jones" --role=contributor` - And I run `wp user create billjones billjones@domain.com --display_name="Bill Jones" --role=administrator` + And I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones" --role=contributor` + And I run `wp user create billjones billjones@example.com --display_name="Bill Jones" --role=administrator` And I run `wp user add-role billjones author` Then STDOUT should not be empty diff --git a/php/commands/user.php b/php/commands/user.php index fae201e42..d9597fca0 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -607,9 +607,9 @@ public function list_caps( $args, $assoc_args ) { * Sample users.csv file: * * user_login,user_email,display_name,role - * bobjones,bobjones@domain.com,Bob Jones,contributor - * newuser1,newuser1@domain.com,New User,author - * existinguser,existinguser@domain.com,Existing User,administrator + * bobjones,bobjones@example.com,Bob Jones,contributor + * newuser1,newuser1@example.com,New User,author + * existinguser,existinguser@example.com,Existing User,administrator * * @subcommand import-csv */ From 82e2c14e05abdbc2f50e9830ae05326635ae4337 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 15 Jan 2015 05:39:28 -0800 Subject: [PATCH 3388/5359] Properly catch error when WordPress importer install fails Plugin install failure doesn't elevate exit code yet, so it's more subtle --- features/export.feature | 20 ++++++++++++++++---- features/import.feature | 12 ++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/features/export.feature b/features/export.feature index a342d608c..ae0281bd4 100644 --- a/features/export.feature +++ b/features/export.feature @@ -40,7 +40,10 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDOUT should not be empty + Then STDERR should not contain: + """ + Warning: + """ When I run `wp site empty --yes` And I run `wp post generate --post_type=page --post_status=draft --count=10` @@ -75,7 +78,10 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDOUT should not be empty + Then STDERR should not contain: + """ + Warning: + """ When I run `wp post generate --count=10` And I run `wp post list --format=count` @@ -107,7 +113,10 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDOUT should not be empty + Then STDERR should not contain: + """ + Warning: + """ When I run `wp site empty --yes` And I run `wp post generate --post_type=post --post_date=2013-08-01 --count=10` @@ -144,7 +153,10 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDOUT should not be empty + Then STDERR should not contain: + """ + Warning: + """ When I run `wp term create category Apple --porcelain` Then STDOUT should be a number diff --git a/features/import.feature b/features/import.feature index b401e3164..c975325b2 100644 --- a/features/import.feature +++ b/features/import.feature @@ -23,7 +23,10 @@ Feature: Import content. """ When I run `wp plugin install wordpress-importer --activate` - Then STDOUT should not be empty + Then STDERR should not contain: + """ + Warning: + """ When I run `wp import {EXPORT_FILE} --authors=skip` Then STDOUT should not be empty @@ -70,7 +73,12 @@ Feature: Import content. """ When I run `wp plugin install wordpress-importer --activate` - And I run `wp import export-posts --authors=skip --skip=image_resize` + Then STDERR should not contain: + """ + Warning: + """ + + When I run `wp import export-posts --authors=skip --skip=image_resize` And I run `wp import export-pages --authors=skip --skip=image_resize` Then STDOUT should not be empty From 6a2adbacd819c19ce1b2a0d0c1a0422a949e68de Mon Sep 17 00:00:00 2001 From: 2ndkauboy <bernhard@kau-boys.de> Date: Mon, 19 Jan 2015 02:31:15 +0100 Subject: [PATCH 3389/5359] implement the new best practice from the CODEX to enqueue the parent themes script through the functions.php file instead of importing it in the child themes style.css file --- php/commands/scaffold.php | 2 ++ templates/child_theme.mustache | 4 +--- templates/child_theme_functions.mustache | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 templates/child_theme_functions.mustache diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 050b81228..7f9ae4f59 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -269,10 +269,12 @@ function child_theme( $args, $assoc_args ) { $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; $theme_style_path = "$theme_dir/style.css"; + $theme_functions_path = "$theme_dir/functions.php"; $this->maybe_create_themes_dir(); $this->create_file( $theme_style_path, Utils\mustache_render( 'child_theme.mustache', $data ) ); + $this->create_file( $theme_functions_path, Utils\mustache_render( 'child_theme_functions.mustache', $data ) ); WP_CLI::success( "Created $theme_dir" ); diff --git a/templates/child_theme.mustache b/templates/child_theme.mustache index 6e96440f1..0ff54a109 100644 --- a/templates/child_theme.mustache +++ b/templates/child_theme.mustache @@ -6,6 +6,4 @@ Author: {{author}} Author URI: {{author_uri}} Template: {{parent_theme}} Version: 0.1.0 -*/ - -@import '../{{parent_theme}}/style.css'; +*/ \ No newline at end of file diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache new file mode 100644 index 000000000..da47ec199 --- /dev/null +++ b/templates/child_theme_functions.mustache @@ -0,0 +1,8 @@ +<?php + +add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' ); + +function {{parent_theme}}_parent_theme_enqueue_styles() { + wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); + +} \ No newline at end of file From 3c197e28627e6d768db3e4d9408ec6cfd6fa5694 Mon Sep 17 00:00:00 2001 From: 2ndkauboy <bernhard@kau-boys.de> Date: Tue, 20 Jan 2015 00:20:39 +0100 Subject: [PATCH 3390/5359] remove unnecessary newline in function --- templates/child_theme_functions.mustache | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index da47ec199..e6b8390e2 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -4,5 +4,4 @@ add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' function {{parent_theme}}_parent_theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); - } \ No newline at end of file From 89972be4c7d04614e597047c08a664d4ad7e2a5e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Jan 2015 16:17:37 -0800 Subject: [PATCH 3391/5359] On Travis, serve Github update check requests from cache This will prevent us from hitting the API request rate-limiting. When `WP_CLI_REQUESTS_CACHE_DIR` environment variable is set, check to see if a cached version of the request is available from the static file cache. If the cached version is available, serve it. If it's not available, do the request and stash it in the cache. Ideally, we'd be injecting our own `Requests_Transport` class, but `Requests` doesn't easily support this. --- .travis.yml | 1 + ci/prepare.sh | 2 ++ ...a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 | 1 + features/bootstrap/FeatureContext.php | 5 +++-- php/utils.php | 16 ++++++++++++++++ 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 diff --git a/.travis.yml b/.travis.yml index b6bf25eca..c1998eac3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ php: env: global: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + - WP_CLI_REQUESTS_CACHE_DIR=/tmp/wp-cli-requests-cache-dir # Encripted deploy key. See https://gist.github.com/scribu/6241271 - secure: "U8gOPW2m9fkJW8omnPjFHFZutGIqAAfVs0H1izpSKJhclUfYAGjAGl1Cb6ZiUp3jZE11iWa+fAZ5mmmLAQ5L9ijta40igfFw0s+o/Vt3WBM4a3Vdqpg6civ0rDi9tJYuwtMaEi/kF/yuhKzUT80EAMqVix5xPnf963iIUPyarfY=" - secure: "W9t7pG5h/Khoi+TrxplpSeTWxaTr7r6cYRVJBsXgghZLDXsU/qn/OhGDdY+IMfSgzO49wjFyLh2EOs8zZSujY75fgFffK2+jd/882NUlpvpXoW9C3yEfZhLJVQZI/1idnpDe9f6zA0XlpBn3bQ2QeS3i2a/JwOGCD8BQjNobk1M=" diff --git a/ci/prepare.sh b/ci/prepare.sh index 611a068de..0abf482c5 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -18,5 +18,7 @@ chmod +x $WP_CLI_BIN_DIR/wp ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' ./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' +cp -Rf ./ci/requests-cache $WP_CLI_REQUESTS_CACHE_DIR + mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 b/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 new file mode 100644 index 000000000..c15234fba --- /dev/null +++ b/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 @@ -0,0 +1 @@ +{"body":"[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":83,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3322,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2945,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6232,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":180,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":21,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":480,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":45,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","raw":"HTTP\/1.1 200 OK\r\nServer: GitHub.com\r\nDate: Tue, 20 Jan 2015 00:06:54 GMT\r\nContent-Type: application\/json; charset=utf-8\r\nTransfer-Encoding: chunked\r\nStatus: 200 OK\r\nX-RateLimit-Limit: 60\r\nX-RateLimit-Remaining: 43\r\nX-RateLimit-Reset: 1421714966\r\nCache-Control: public, max-age=60, s-maxage=60\r\nETag: W\/\"431ba748cd115b111a96bdc64bd25c55\"\r\nVary: Accept\r\nX-GitHub-Media-Type: github.v3\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: deny\r\nContent-Security-Policy: default-src 'none'\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval\r\nAccess-Control-Allow-Origin: *\r\nX-GitHub-Request-Id: CFAD13E4:1D6D:1E0FBDD:54BD9C1E\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains; preload\r\nX-Content-Type-Options: nosniff\r\nVary: Accept-Encoding\r\nX-Served-By: d594a23ec74671eba905bf91ef329026\r\nContent-Encoding: gzip\r\n\r\n[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":83,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3322,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2945,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6232,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":180,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":21,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":480,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":45,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","headers":{},"status_code":200,"success":true,"redirects":0,"url":"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases","history":[],"cookies":{}} \ No newline at end of file diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index c17d1842b..9d920a032 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -41,8 +41,9 @@ private static function get_process_env_variables() { // Ensure we're using the expected `wp` binary $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); $env = array( - 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), - 'BEHAT_RUN' => 1 + 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), + 'BEHAT_RUN' => 1, + 'WP_CLI_REQUESTS_CACHE_DIR' => getenv( 'WP_CLI_REQUESTS_CACHE_DIR' ) ?: false, ); if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { $env['WP_CLI_CONFIG_PATH'] = $config_path; diff --git a/php/utils.php b/php/utils.php index b80c0ea17..79b055b4a 100644 --- a/php/utils.php +++ b/php/utils.php @@ -430,11 +430,27 @@ function http_request( $method, $url, $data = null, $headers = array(), $options $pem_copied = true; } + $cache_file = false; + if ( $cache_dir = getenv( 'WP_CLI_REQUESTS_CACHE_DIR' ) ) { + $cache_key = hash_hmac( 'sha256', 'requests_' . $url . serialize( $headers ) . serialize( $data ) . serialize( $options ), '' ); + $cache_file = rtrim( $cache_dir, '/' ) . '/' . $cache_key; + if ( file_exists( $cache_file ) && is_readable( $cache_file ) ) { + return json_decode( file_get_contents( $cache_file ) ); + } + } + try { $request = \Requests::request( $url, $headers, $data, $method, $options ); if ( $pem_copied ) { unlink( $options['verify'] ); } + if ( ! empty( $cache_file ) ) { + $cache_dir = dirname( $cache_file ); + if ( ! is_dir( $cache_dir ) ) { + mkdir( $cache_dir, 0755, true ); + } + file_put_contents( $cache_file, json_encode( $request ) ); + } return $request; } catch( \Requests_Exception $ex ) { // Handle SSL certificate issues gracefully From f4dac3bef26c57285ba898f8424ceb36ae80cf14 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 Jan 2015 07:00:37 -0800 Subject: [PATCH 3392/5359] Force isn't necessary If this is run twice, we'll get a duplicate subdirectory. But, it doesn't cause any problems --- ci/prepare.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 0abf482c5..0b94367cd 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -18,7 +18,7 @@ chmod +x $WP_CLI_BIN_DIR/wp ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' ./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' -cp -Rf ./ci/requests-cache $WP_CLI_REQUESTS_CACHE_DIR +cp -r ./ci/requests-cache $WP_CLI_REQUESTS_CACHE_DIR mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot From 91670f46e8729c9045a148adb4e995c8728b7260 Mon Sep 17 00:00:00 2001 From: BA <kau@connecticum.de> Date: Wed, 21 Jan 2015 20:10:10 +0100 Subject: [PATCH 3393/5359] add newlines at end of changed mustache templates --- templates/child_theme.mustache | 2 +- templates/child_theme_functions.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/child_theme.mustache b/templates/child_theme.mustache index 0ff54a109..3fda10143 100644 --- a/templates/child_theme.mustache +++ b/templates/child_theme.mustache @@ -6,4 +6,4 @@ Author: {{author}} Author URI: {{author_uri}} Template: {{parent_theme}} Version: 0.1.0 -*/ \ No newline at end of file +*/ diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index e6b8390e2..c8f541767 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -4,4 +4,4 @@ add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' function {{parent_theme}}_parent_theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); -} \ No newline at end of file +} From 1a3b677f2196e0b69ec0f089d01888dbe4e61d02 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 23 Jan 2015 07:10:25 -0800 Subject: [PATCH 3394/5359] Update cached Github request Somehow the key changed... --- ...6307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc | 1 + ...b3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc delete mode 100644 ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 diff --git a/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc b/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc new file mode 100644 index 000000000..94235eb4d --- /dev/null +++ b/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc @@ -0,0 +1 @@ +{"body":"[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":257,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3550,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2949,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6236,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":184,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":23,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":536,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":47,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","raw":"HTTP\/1.1 200 OK\r\nServer: GitHub.com\r\nDate: Fri, 23 Jan 2015 15:05:37 GMT\r\nContent-Type: application\/json; charset=utf-8\r\nTransfer-Encoding: chunked\r\nStatus: 200 OK\r\nX-RateLimit-Limit: 60\r\nX-RateLimit-Remaining: 58\r\nX-RateLimit-Reset: 1422029028\r\nCache-Control: public, max-age=60, s-maxage=60\r\nETag: W\/\"cc5da6bb9b75b9409843ff24258f0035\"\r\nVary: Accept\r\nX-GitHub-Media-Type: github.v3\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: deny\r\nContent-Security-Policy: default-src 'none'\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval\r\nAccess-Control-Allow-Origin: *\r\nX-GitHub-Request-Id: 49A4CEBC:1D6B:6DD46FA:54C26340\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains; preload\r\nX-Content-Type-Options: nosniff\r\nVary: Accept-Encoding\r\nX-Served-By: 13d09b732ebe76f892093130dc088652\r\nContent-Encoding: gzip\r\n\r\n[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":257,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3550,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2949,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6236,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":184,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":23,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":536,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":47,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","headers":{},"status_code":200,"success":true,"redirects":0,"url":"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases","history":[],"cookies":{}} \ No newline at end of file diff --git a/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 b/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 deleted file mode 100644 index c15234fba..000000000 --- a/ci/requests-cache/f0db3d31346d4a5c733a1fac25aa46ba8a454b1e403fd7447a0c2161f2d07f13 +++ /dev/null @@ -1 +0,0 @@ -{"body":"[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":83,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3322,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2945,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6232,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":180,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":21,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":480,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":45,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","raw":"HTTP\/1.1 200 OK\r\nServer: GitHub.com\r\nDate: Tue, 20 Jan 2015 00:06:54 GMT\r\nContent-Type: application\/json; charset=utf-8\r\nTransfer-Encoding: chunked\r\nStatus: 200 OK\r\nX-RateLimit-Limit: 60\r\nX-RateLimit-Remaining: 43\r\nX-RateLimit-Reset: 1421714966\r\nCache-Control: public, max-age=60, s-maxage=60\r\nETag: W\/\"431ba748cd115b111a96bdc64bd25c55\"\r\nVary: Accept\r\nX-GitHub-Media-Type: github.v3\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: deny\r\nContent-Security-Policy: default-src 'none'\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval\r\nAccess-Control-Allow-Origin: *\r\nX-GitHub-Request-Id: CFAD13E4:1D6D:1E0FBDD:54BD9C1E\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains; preload\r\nX-Content-Type-Options: nosniff\r\nVary: Accept-Encoding\r\nX-Served-By: d594a23ec74671eba905bf91ef329026\r\nContent-Encoding: gzip\r\n\r\n[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":83,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3322,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2945,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6232,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":180,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":21,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":480,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":45,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","headers":{},"status_code":200,"success":true,"redirects":0,"url":"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases","history":[],"cookies":{}} \ No newline at end of file From 1760511e32db3eaf92f42fffa32868be24f09e59 Mon Sep 17 00:00:00 2001 From: Francesco Laffi <francesco.laffi@gmail.com> Date: Fri, 30 Jan 2015 12:57:06 +0100 Subject: [PATCH 3395/5359] add flag to search-replace command to ignore wpdb table lists --- features/search-replace.feature | 10 ++++++++-- php/commands/search-replace.php | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 43207edbe..de0351846 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -24,9 +24,9 @@ Feature: Do global search/replace | wp_2_posts | guid | 2 | SQL | | wp_blogs | path | 1 | SQL | - Scenario: Don't run on unregistered tables + Scenario: Don't run on unregistered tables by default Given a WP install - And I run `wp db query "CREATE TABLE wp_awesome ( id int(11) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` + And I run `wp db query "CREATE TABLE wp_awesome ( id int(11) unsigned NOT NULL AUTO_INCREMENT, awesome_stuff TEXT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` When I run `wp search-replace foo bar` Then STDOUT should not contain: @@ -34,6 +34,12 @@ Feature: Do global search/replace wp_awesome """ + When I run `wp search-replace foo bar --all-tables` + Then STDOUT should contain: + """ + wp_awesome + """ + Scenario: Quiet search/replace Given a WP install diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 52ffbeaa1..bd2985cf5 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -43,6 +43,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--recurse-objects] * : Enable recursing into objects to replace strings * + * [--all-tables] + * : Enable replacement on any tables that match the table prefix even if not registered on wpdb + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -70,7 +73,7 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - $tables = self::get_table_list( $args, isset( $assoc_args['network'] ) ); + $tables = self::get_table_list( $args, isset( $assoc_args['network'] ), isset( $assoc_args['all-tables'] ) ); foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); @@ -118,7 +121,7 @@ public function __invoke( $args, $assoc_args ) { } } - private static function get_table_list( $args, $network ) { + private static function get_table_list( $args, $network, $all ) { global $wpdb; if ( !empty( $args ) ) @@ -127,6 +130,10 @@ private static function get_table_list( $args, $network ) { $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); + if ( $all ) { + return $matching_tables; + } + $allowed_tables = array(); $allowed_table_types = array( 'tables', 'global_tables' ); if ( $network ) { From 7afa42ec60a69c1b4af12adb64c7e6508884f444 Mon Sep 17 00:00:00 2001 From: Andreas Heigl <andreas@heigl.org> Date: Wed, 4 Feb 2015 16:12:08 +0100 Subject: [PATCH 3396/5359] Adds possibility to download via curl This also removes the wget-call from install-package-tests as curl is already a requirement. --- templates/install-package-tests.sh | 2 +- templates/install-wp-tests.sh | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/templates/install-package-tests.sh b/templates/install-package-tests.sh index 74c76b587..0df429c56 100644 --- a/templates/install-package-tests.sh +++ b/templates/install-package-tests.sh @@ -8,7 +8,7 @@ install_wp_cli() { # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR mkdir -p $WP_CLI_BIN_DIR - wget https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar + curl -s https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar mv wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index a3f1184df..ab6396707 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -16,6 +16,14 @@ WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} set -ex +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + install_wp() { mkdir -p $WP_CORE_DIR @@ -25,10 +33,10 @@ install_wp() { local ARCHIVE_NAME="wordpress-$WP_VERSION" fi - wget -nv -O /tmp/wordpress.tar.gz https://wordpress.org/${ARCHIVE_NAME}.tar.gz + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - wget -nv -O $WP_CORE_DIR/wp-content/db.php https://raw.github.com/markoheijnen/wp-mysqli/master/db.php + download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php } install_test_suite() { @@ -44,7 +52,7 @@ install_test_suite() { cd $WP_TESTS_DIR svn co --quiet https://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ - wget -nv -O wp-tests-config.php https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php + download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php wp-tests-config.php sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php From 483887a3ac06ee7a517d1bd986e171e0d7892bbb Mon Sep 17 00:00:00 2001 From: Andreas Heigl <andreas@heigl.org> Date: Thu, 5 Feb 2015 07:22:09 +0100 Subject: [PATCH 3397/5359] Adds download-function to install-package-tests.sh --- templates/install-package-tests.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/templates/install-package-tests.sh b/templates/install-package-tests.sh index 0df429c56..cbde91ef2 100644 --- a/templates/install-package-tests.sh +++ b/templates/install-package-tests.sh @@ -4,12 +4,19 @@ set -ex PACKAGE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )" +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + install_wp_cli() { # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR mkdir -p $WP_CLI_BIN_DIR - curl -s https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar - mv wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp + download https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp } @@ -30,7 +37,8 @@ set_package_context() { download_behat() { cd $PACKAGE_DIR - curl -s https://getcomposer.org/installer | php + download https://getcomposer.org/installer installer + php installer php composer.phar require --dev behat/behat='~2.5' } From 66b7e6332e2a3ec934ace651b2040ea3135ebfb3 Mon Sep 17 00:00:00 2001 From: Andreas Heigl <andreas@heigl.org> Date: Thu, 5 Feb 2015 07:22:35 +0100 Subject: [PATCH 3398/5359] Fixes some indentation-issues --- templates/install-wp-tests.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index ab6396707..56647cee9 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -17,11 +17,11 @@ WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} set -ex download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; + if [ `which curl` ]; then + curl -s "$1" > "$2"; elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi + wget -nv -O "$2" "$1" + fi } install_wp() { From 72643760081926b37002fefed454c70f453e2208 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 9 Feb 2015 16:47:50 +0100 Subject: [PATCH 3399/5359] Correct the inline docs for `CommandWithUpgrade::_search()`. --- php/WP_CLI/CommandWithUpgrade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b3d7a3578..39da96241 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -351,8 +351,8 @@ private function get_color( $status ) { /** * Search wordpress.org repo. * - * @param object $api Data from WP plugin/theme API - * @param array $assoc_args Data passed in from command. + * @param array $args A arguments array containing the search term in the first element. + * @param array $assoc_args Data passed in from command. */ protected function _search( $args, $assoc_args ) { $term = $args[0]; From 7d5bb04a92445db08a7aa2c146d76c0b31bd2175 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 9 Feb 2015 10:41:12 -0800 Subject: [PATCH 3400/5359] Test against the latest version of WordPress --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c1998eac3..fe4c4b610 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=4.0 + - WP_VERSION=4.1 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: From 5344805cef642e989a87e752cfca784b3fd9e86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 12 Feb 2015 23:13:09 +0100 Subject: [PATCH 3401/5359] Check command class --- php/class-wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f0a576407..01256b506 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -166,6 +166,10 @@ public static function do_hook( $when ) { * 'before_invoke' => callback to execute before invoking the command */ public static function add_command( $name, $class, $args = array() ) { + if ( ! class_exists( $class ) ) { + WP_CLI::error( sprintf( "Class '%s' does not exist.", $class ) ); + } + if ( isset( $args['before_invoke'] ) ) { self::add_hook( "before_invoke:$name", $args['before_invoke'] ); } From dd6f717608e55d8b5eca1e68bf21818c88e2e244 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 12 Feb 2015 20:10:08 -0800 Subject: [PATCH 3402/5359] Fix builds by increasing the # of items per page WordPress.org API is giving us junk results for `per_page=1` See https://meta.trac.wordpress.org/ticket/866 --- features/upgradables.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 027668c83..dc195e89e 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -165,10 +165,10 @@ Feature: Manage WordPress themes and plugins """ And the <file_to_check> file should not exist - When I run `wp <type> search <item> --per-page=1 --fields=name,slug` + When I run `wp <type> search <item> --per-page=2 --fields=name,slug` Then STDOUT should contain: """ - Showing 1 of + Showing 2 of """ And STDOUT should end with a table containing rows: | name | slug | From 8ddc599ea1b1f1cd3822af1ba0fe641b20b714f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 14:10:55 -0800 Subject: [PATCH 3403/5359] Don't instantiate the `Import_Command` class when registering Proper use is to provide the class name as a string --- php/commands/import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index eca7db4c2..d082d3797 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -378,5 +378,5 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { } -WP_CLI::add_command( 'import', new Import_Command ); +WP_CLI::add_command( 'import', 'Import_Command' ); From b6439a7302b826ec2de2c6bbb84eb455ea3202ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 13 Feb 2015 23:16:10 +0100 Subject: [PATCH 3404/5359] Class-proof class_exists --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 01256b506..cfe4ae30a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -166,7 +166,7 @@ public static function do_hook( $when ) { * 'before_invoke' => callback to execute before invoking the command */ public static function add_command( $name, $class, $args = array() ) { - if ( ! class_exists( $class ) ) { + if ( is_string( $class ) && ! class_exists( (string) $class ) ) { WP_CLI::error( sprintf( "Class '%s' does not exist.", $class ) ); } From daecd1427f95948203a7775b2b467e96e5c437a6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 14:24:58 -0800 Subject: [PATCH 3405/5359] Rename `--all-tables` to `--all-tables-with-prefix` for clarity --- features/search-replace.feature | 2 +- php/commands/search-replace.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index de0351846..f85ae7c24 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -34,7 +34,7 @@ Feature: Do global search/replace wp_awesome """ - When I run `wp search-replace foo bar --all-tables` + When I run `wp search-replace foo bar --all-tables-with-prefix` Then STDOUT should contain: """ wp_awesome diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index bd2985cf5..cd09e1861 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -43,7 +43,7 @@ class Search_Replace_Command extends WP_CLI_Command { * [--recurse-objects] * : Enable recursing into objects to replace strings * - * [--all-tables] + * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * * ## EXAMPLES @@ -73,7 +73,7 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - $tables = self::get_table_list( $args, isset( $assoc_args['network'] ), isset( $assoc_args['all-tables'] ) ); + $tables = self::get_table_list( $args, isset( $assoc_args['network'] ), isset( $assoc_args['all-tables-with-prefix'] ) ); foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); @@ -121,7 +121,7 @@ public function __invoke( $args, $assoc_args ) { } } - private static function get_table_list( $args, $network, $all ) { + private static function get_table_list( $args, $network, $all_with_prefix ) { global $wpdb; if ( !empty( $args ) ) @@ -130,7 +130,7 @@ private static function get_table_list( $args, $network, $all ) { $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); - if ( $all ) { + if ( $all_with_prefix ) { return $matching_tables; } From b8a092f2e959c3618f9be97ccdd1a69e2a79942d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 14:31:34 -0800 Subject: [PATCH 3406/5359] Rename `--icon` argument to `--dashicon` for clarity --- features/scaffold.feature | 4 ++-- php/commands/scaffold.php | 4 ++-- templates/post_type.mustache | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 86b2f307b..1f3086bcd 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -84,8 +84,8 @@ Feature: WordPress code scaffolding __( 'Brain eaters' """ - Scenario: Scaffold a Custom Post Type with icon - When I run `wp scaffold post-type zombie --icon="art"` + Scenario: Scaffold a Custom Post Type with dashicon + When I run `wp scaffold post-type zombie --dashicon="art"` Then STDOUT should contain: """ 'menu_icon' => 'dashicons-art', diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 8f4f6b91c..c26f26c40 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -24,7 +24,7 @@ class Scaffold_Command extends WP_CLI_Command { * [--textdomain=<textdomain>] * : The textdomain to use for the labels. * - * [--icon=<icon>] + * [--dashicon=<dashicon>] * : The dashicon to use in the menu. * * [--theme] @@ -49,7 +49,7 @@ function post_type( $args, $assoc_args ) { $defaults = array( 'textdomain' => '', - 'icon' => 'admin-post', + 'dashicon' => 'admin-post', ); $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( diff --git a/templates/post_type.mustache b/templates/post_type.mustache index f017dccaf..68e0814b0 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -22,5 +22,5 @@ 'has_archive' => true, 'rewrite' => true, 'query_var' => true, - 'menu_icon' => 'dashicons-{{icon}}', + 'menu_icon' => 'dashicons-{{dashicon}}', ) ); From b982ae03ff84344c141ed90038c88994c45d78f6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 14:41:13 -0800 Subject: [PATCH 3407/5359] Add `--sassify` option to `wp scaffold _s` --- php/commands/scaffold.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 8f4f6b91c..61a99a238 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -181,6 +181,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * * [--author_uri=<uri>] * : What to put in the 'Author URI:' header in style.css + * + * [--sassify] + * : Include stylesheets as SASS */ function _s( $args, $assoc_args ) { @@ -205,6 +208,9 @@ function _s( $args, $assoc_args ) { $body['underscoresme_description'] = $theme_description; $body['underscoresme_generate_submit'] = "Generate"; $body['underscoresme_generate'] = "1"; + if ( isset( $assoc_args['sassify'] ) ) { + $body['underscoresme_sass'] = 1; + } $tmpfname = wp_tempnam($url); $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); From 725769d75c256dd012a992141d40d443f57167f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 14:50:04 -0800 Subject: [PATCH 3408/5359] Test for `--sassify` optoin --- features/scaffold.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 86b2f307b..adb946aea 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -210,3 +210,13 @@ Feature: WordPress code scaffolding """ And the {THEME_DIR}/starter-theme/style.css file should exist + Scenario: Scaffold starter code for a theme with sass + Given I run `wp theme path` + And save STDOUT as {THEME_DIR} + + When I run `wp scaffold _s starter-theme --sassify` + Then STDOUT should contain: + """ + Success: Created theme 'Starter-theme'. + """ + And the {THEME_DIR}/starter-theme/sass directory should exist From 0816fa17ea26bd5baee55157ccb4db2ef2db88f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 15:25:37 -0800 Subject: [PATCH 3409/5359] Skip Github API tests by default Being rate-limited isn't a problem worth solving --- ci/set-behat-tags.sh | 13 ++++++------- features/cli.feature | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ci/set-behat-tags.sh b/ci/set-behat-tags.sh index 043a71fdf..86bb9cc62 100755 --- a/ci/set-behat-tags.sh +++ b/ci/set-behat-tags.sh @@ -32,6 +32,8 @@ vercomp() { return 0 } +# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +skip_tags="--tags='~github-api," if [[ ! -z "$WP_VERSION" ]]; then skip_tags="--tags='" @@ -45,13 +47,10 @@ if [[ ! -z "$WP_VERSION" ]]; then skip_tags="$skip_tags~$require," fi done - if [[ "--tags='" != $skip_tags ]]; then - skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' - skip_tags="$skip_tags'" # close the argument - else - skip_tags='' - fi fi -echo export behat_tags=$skip_tags \ No newline at end of file +skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' +skip_tags="$skip_tags'" # close the argument + +echo export behat_tags=$skip_tags,~github-api diff --git a/features/cli.feature b/features/cli.feature index d0cf96056..d15e4888e 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -1,3 +1,4 @@ +@github-api Feature: `wp cli` tasks Scenario: Ability to set a custom version when building From e3a04302f740b35caaaa82d59f09cd147387b5fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 15:27:27 -0800 Subject: [PATCH 3410/5359] Revert "Merge pull request #1618 from wp-cli/1612-cache-requests" This reverts commit b28bde37be5e0fc8e8feb762b7d380c1ee958064, reversing changes made to aa15356fd208a07cd18d05b4062e5d18ca6f0591. --- .travis.yml | 1 - ci/prepare.sh | 2 -- features/bootstrap/FeatureContext.php | 5 ++--- php/utils.php | 16 ---------------- 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe4c4b610..9ab5b14b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ php: env: global: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - - WP_CLI_REQUESTS_CACHE_DIR=/tmp/wp-cli-requests-cache-dir # Encripted deploy key. See https://gist.github.com/scribu/6241271 - secure: "U8gOPW2m9fkJW8omnPjFHFZutGIqAAfVs0H1izpSKJhclUfYAGjAGl1Cb6ZiUp3jZE11iWa+fAZ5mmmLAQ5L9ijta40igfFw0s+o/Vt3WBM4a3Vdqpg6civ0rDi9tJYuwtMaEi/kF/yuhKzUT80EAMqVix5xPnf963iIUPyarfY=" - secure: "W9t7pG5h/Khoi+TrxplpSeTWxaTr7r6cYRVJBsXgghZLDXsU/qn/OhGDdY+IMfSgzO49wjFyLh2EOs8zZSujY75fgFffK2+jd/882NUlpvpXoW9C3yEfZhLJVQZI/1idnpDe9f6zA0XlpBn3bQ2QeS3i2a/JwOGCD8BQjNobk1M=" diff --git a/ci/prepare.sh b/ci/prepare.sh index 0b94367cd..611a068de 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -18,7 +18,5 @@ chmod +x $WP_CLI_BIN_DIR/wp ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' ./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' -cp -r ./ci/requests-cache $WP_CLI_REQUESTS_CACHE_DIR - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 9d920a032..c17d1842b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -41,9 +41,8 @@ private static function get_process_env_variables() { // Ensure we're using the expected `wp` binary $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); $env = array( - 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), - 'BEHAT_RUN' => 1, - 'WP_CLI_REQUESTS_CACHE_DIR' => getenv( 'WP_CLI_REQUESTS_CACHE_DIR' ) ?: false, + 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), + 'BEHAT_RUN' => 1 ); if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { $env['WP_CLI_CONFIG_PATH'] = $config_path; diff --git a/php/utils.php b/php/utils.php index 79b055b4a..b80c0ea17 100644 --- a/php/utils.php +++ b/php/utils.php @@ -430,27 +430,11 @@ function http_request( $method, $url, $data = null, $headers = array(), $options $pem_copied = true; } - $cache_file = false; - if ( $cache_dir = getenv( 'WP_CLI_REQUESTS_CACHE_DIR' ) ) { - $cache_key = hash_hmac( 'sha256', 'requests_' . $url . serialize( $headers ) . serialize( $data ) . serialize( $options ), '' ); - $cache_file = rtrim( $cache_dir, '/' ) . '/' . $cache_key; - if ( file_exists( $cache_file ) && is_readable( $cache_file ) ) { - return json_decode( file_get_contents( $cache_file ) ); - } - } - try { $request = \Requests::request( $url, $headers, $data, $method, $options ); if ( $pem_copied ) { unlink( $options['verify'] ); } - if ( ! empty( $cache_file ) ) { - $cache_dir = dirname( $cache_file ); - if ( ! is_dir( $cache_dir ) ) { - mkdir( $cache_dir, 0755, true ); - } - file_put_contents( $cache_file, json_encode( $request ) ); - } return $request; } catch( \Requests_Exception $ex ) { // Handle SSL certificate issues gracefully From bc565d7b9bcbdbf48cd9d66012a5549071a4a9fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 14 Feb 2015 00:27:44 +0100 Subject: [PATCH 3411/5359] Test non-existent class in add_command() --- features/command.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 features/command.feature diff --git a/features/command.feature b/features/command.feature new file mode 100644 index 000000000..e7b72e479 --- /dev/null +++ b/features/command.feature @@ -0,0 +1,16 @@ +Feature: WP-CLI Commands + + Scenario: Invalid class is specified for a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + + WP_CLI::add_command( 'command example', 'Non_Existent_Class' ); + """ + + When I run `wp --require=custom-cmd.php help` + Then STDOUT should contain: + """ + Error: Class 'Non_Existent_Class' does not exist. + """ From 659d3dce1183f82eaf902b0b0346262a9537ad84 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 15:28:37 -0800 Subject: [PATCH 3412/5359] Don't need this cache file anymore --- ...6307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc | 1 - 1 file changed, 1 deletion(-) delete mode 100644 ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc diff --git a/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc b/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc deleted file mode 100644 index 94235eb4d..000000000 --- a/ci/requests-cache/7166307ee3b279227528edb0d3c10ee7308e00e6cbee2ffe7aed21b9273f4fcc +++ /dev/null @@ -1 +0,0 @@ -{"body":"[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":257,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3550,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2949,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6236,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":184,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":23,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":536,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":47,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","raw":"HTTP\/1.1 200 OK\r\nServer: GitHub.com\r\nDate: Fri, 23 Jan 2015 15:05:37 GMT\r\nContent-Type: application\/json; charset=utf-8\r\nTransfer-Encoding: chunked\r\nStatus: 200 OK\r\nX-RateLimit-Limit: 60\r\nX-RateLimit-Remaining: 58\r\nX-RateLimit-Reset: 1422029028\r\nCache-Control: public, max-age=60, s-maxage=60\r\nETag: W\/\"cc5da6bb9b75b9409843ff24258f0035\"\r\nVary: Accept\r\nX-GitHub-Media-Type: github.v3\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: deny\r\nContent-Security-Policy: default-src 'none'\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval\r\nAccess-Control-Allow-Origin: *\r\nX-GitHub-Request-Id: 49A4CEBC:1D6B:6DD46FA:54C26340\r\nStrict-Transport-Security: max-age=31536000; includeSubdomains; preload\r\nX-Content-Type-Options: nosniff\r\nVary: Accept-Encoding\r\nX-Served-By: 13d09b732ebe76f892093130dc088652\r\nContent-Encoding: gzip\r\n\r\n[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/851681\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.18.0\",\"id\":851681,\"tag_name\":\"v0.18.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.18.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2015-01-14T14:10:29Z\",\"published_at\":\"2015-01-14T16:54:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/379372\",\"id\":379372,\"name\":\"wp-cli-0.18.0.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1342749,\"download_count\":257,\"created_at\":\"2015-01-14T16:53:08Z\",\"updated_at\":\"2015-01-14T16:54:37Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.18.0\/wp-cli-0.18.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.18.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.18.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.18.0.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/713614\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.1\",\"id\":713614,\"tag_name\":\"v0.17.1\",\"target_commitish\":\"release-0.17.1\",\"name\":\"Version 0.17.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-11-18T14:04:52Z\",\"published_at\":\"2014-11-18T14:56:27Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/310207\",\"id\":310207,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1317194,\"download_count\":3550,\"created_at\":\"2014-11-18T14:54:16Z\",\"updated_at\":\"2014-11-18T14:54:18Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.1\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/552464\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.17.0\",\"id\":552464,\"tag_name\":\"v0.17.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.17.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-09-12T00:49:44Z\",\"published_at\":\"2014-09-12T01:12:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/235975\",\"id\":235975,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1315849,\"download_count\":2949,\"created_at\":\"2014-09-12T01:12:02Z\",\"updated_at\":\"2014-09-12T01:12:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.17.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.17.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.17.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.17.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/403843\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.16.0\",\"id\":403843,\"tag_name\":\"v0.16.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.16.0\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-07-01T00:05:47Z\",\"published_at\":\"2014-07-01T00:48:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/172144\",\"id\":172144,\"name\":\"wp-cli.phar\",\"label\":null,\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1235702,\"download_count\":6236,\"created_at\":\"2014-07-01T00:34:43Z\",\"updated_at\":\"2014-07-01T00:34:50Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.16.0\/wp-cli.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.16.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.16.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.16.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/321103\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.1\",\"id\":321103,\"tag_name\":\"v0.15.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.1\",\"draft\":false,\"author\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-05-14T23:36:21Z\",\"published_at\":\"2014-05-14T23:53:00Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/135615\",\"id\":135615,\"name\":\"wp-cli-0.15.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"danielbachhuber\",\"id\":36432,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/36432?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/danielbachhuber\",\"html_url\":\"https:\/\/github.com\/danielbachhuber\",\"followers_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/danielbachhuber\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":2124218,\"download_count\":235,\"created_at\":\"2014-05-14T23:52:51Z\",\"updated_at\":\"2014-05-14T23:53:00Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.1\/wp-cli-0.15.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.1\",\"body\":\"Release notes http:\/\/wp-cli.org\/blog\/version-0.15.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/273283\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.15.0\",\"id\":273283,\"tag_name\":\"v0.15.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.15.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-04-15T16:16:50Z\",\"published_at\":\"2014-04-15T18:28:48Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/116905\",\"id\":116905,\"name\":\"wp-cli-0.15.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1195268,\"download_count\":184,\"created_at\":\"2014-04-17T17:19:40Z\",\"updated_at\":\"2014-04-17T17:19:55Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.15.0\/wp-cli-0.15.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.15.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.15.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.15.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244583\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.0\",\"id\":244583,\"tag_name\":\"v0.12.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-04T13:54:34Z\",\"published_at\":\"2014-03-27T22:35:13Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102407\",\"id\":102407,\"name\":\"wp-cli-0.12.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":669359,\"download_count\":7,\"created_at\":\"2014-03-27T22:35:08Z\",\"updated_at\":\"2014-03-27T22:35:13Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.0\/wp-cli-0.12.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/244580\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.12.1\",\"id\":244580,\"tag_name\":\"v0.12.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.12.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-10-11T12:36:09Z\",\"published_at\":\"2014-03-27T22:33:29Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102406\",\"id\":102406,\"name\":\"wp-cli-0.12.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":677814,\"download_count\":23,\"created_at\":\"2014-03-27T22:32:59Z\",\"updated_at\":\"2014-03-27T22:33:29Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.12.1\/wp-cli-0.12.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.12.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.12.1\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.12.1.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/204805\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.1\",\"id\":204805,\"tag_name\":\"v0.14.1\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.1\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-28T15:47:44Z\",\"published_at\":\"2014-02-28T18:22:18Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102398\",\"id\":102398,\"name\":\"wp-cli-0.14.1.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1106244,\"download_count\":536,\"created_at\":\"2014-03-27T22:24:59Z\",\"updated_at\":\"2014-03-27T22:25:09Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.1\/wp-cli-0.14.1.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.1\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.1\",\"body\":\"Resolved issues: https:\/\/github.com\/wp-cli\/wp-cli\/issues?labels=&milestone=22&page=1&state=closed\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/174903\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.14.0\",\"id\":174903,\"tag_name\":\"v0.14.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.14.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2014-02-06T00:02:26Z\",\"published_at\":\"2014-02-06T00:29:37Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102401\",\"id\":102401,\"name\":\"wp-cli-0.14.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1101392,\"download_count\":229,\"created_at\":\"2014-03-27T22:26:59Z\",\"updated_at\":\"2014-03-27T22:27:15Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.14.0\/wp-cli-0.14.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.14.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.14.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.14.html\"},{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\",\"assets_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets\",\"upload_url\":\"https:\/\/uploads.github.com\/repos\/wp-cli\/wp-cli\/releases\/114831\/assets{?name}\",\"html_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/tag\/v0.13.0\",\"id\":114831,\"tag_name\":\"v0.13.0\",\"target_commitish\":\"master\",\"name\":\"Version 0.13.0\",\"draft\":false,\"author\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"prerelease\":false,\"created_at\":\"2013-11-30T13:14:44Z\",\"published_at\":\"2013-12-06T22:31:35Z\",\"assets\":[{\"url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases\/assets\/102405\",\"id\":102405,\"name\":\"wp-cli-0.13.0.phar\",\"label\":\"\",\"uploader\":{\"login\":\"scribu\",\"id\":225715,\"avatar_url\":\"https:\/\/avatars.githubusercontent.com\/u\/225715?v=3\",\"gravatar_id\":\"\",\"url\":\"https:\/\/api.github.com\/users\/scribu\",\"html_url\":\"https:\/\/github.com\/scribu\",\"followers_url\":\"https:\/\/api.github.com\/users\/scribu\/followers\",\"following_url\":\"https:\/\/api.github.com\/users\/scribu\/following{\/other_user}\",\"gists_url\":\"https:\/\/api.github.com\/users\/scribu\/gists{\/gist_id}\",\"starred_url\":\"https:\/\/api.github.com\/users\/scribu\/starred{\/owner}{\/repo}\",\"subscriptions_url\":\"https:\/\/api.github.com\/users\/scribu\/subscriptions\",\"organizations_url\":\"https:\/\/api.github.com\/users\/scribu\/orgs\",\"repos_url\":\"https:\/\/api.github.com\/users\/scribu\/repos\",\"events_url\":\"https:\/\/api.github.com\/users\/scribu\/events{\/privacy}\",\"received_events_url\":\"https:\/\/api.github.com\/users\/scribu\/received_events\",\"type\":\"User\",\"site_admin\":false},\"content_type\":\"application\/octet-stream\",\"state\":\"uploaded\",\"size\":1043153,\"download_count\":47,\"created_at\":\"2014-03-27T22:30:36Z\",\"updated_at\":\"2014-03-27T22:30:43Z\",\"browser_download_url\":\"https:\/\/github.com\/wp-cli\/wp-cli\/releases\/download\/v0.13.0\/wp-cli-0.13.0.phar\"}],\"tarball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/tarball\/v0.13.0\",\"zipball_url\":\"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/zipball\/v0.13.0\",\"body\":\"Release notes: http:\/\/wp-cli.org\/blog\/version-0.13.html\"}]","headers":{},"status_code":200,"success":true,"redirects":0,"url":"https:\/\/api.github.com\/repos\/wp-cli\/wp-cli\/releases","history":[],"cookies":{}} \ No newline at end of file From 84cc9b172cf4edd15632116ddc5b1f67d488d86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 14 Feb 2015 00:49:36 +0100 Subject: [PATCH 3413/5359] Test fixed by "When I try" and STDERR --- features/command.feature | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/features/command.feature b/features/command.feature index e7b72e479..6e034d6b2 100644 --- a/features/command.feature +++ b/features/command.feature @@ -9,8 +9,9 @@ Feature: WP-CLI Commands WP_CLI::add_command( 'command example', 'Non_Existent_Class' ); """ - When I run `wp --require=custom-cmd.php help` - Then STDOUT should contain: + When I try `wp --require=custom-cmd.php help` + Then the return code should be 1 + And STDERR should contain: """ - Error: Class 'Non_Existent_Class' does not exist. + Class 'Non_Existent_Class' does not exist. """ From a6124c15ba75331f428aeaed2fbebc96f54fba83 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 16:24:51 -0800 Subject: [PATCH 3414/5359] Properly format Behat tags --- ci/set-behat-tags.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ci/set-behat-tags.sh b/ci/set-behat-tags.sh index 86bb9cc62..f3ccb1fe9 100755 --- a/ci/set-behat-tags.sh +++ b/ci/set-behat-tags.sh @@ -33,10 +33,9 @@ vercomp() { } # Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -skip_tags="--tags='~github-api," +skip_tags="--tags='~@github-api," if [[ ! -z "$WP_VERSION" ]]; then - skip_tags="--tags='" requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) for (( i = 0; i < ${#requires[@]}; i++ )); do version=${requires[$i]:12} @@ -53,4 +52,4 @@ fi skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' skip_tags="$skip_tags'" # close the argument -echo export behat_tags=$skip_tags,~github-api +echo export behat_tags=$skip_tags From e5f1927560c796f53c7ebb640350258aa288f800 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 13 Feb 2015 17:28:45 -0800 Subject: [PATCH 3415/5359] Comma means `OR`, `&&` means `AND` --- ci/set-behat-tags.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/set-behat-tags.sh b/ci/set-behat-tags.sh index f3ccb1fe9..ee5de2143 100755 --- a/ci/set-behat-tags.sh +++ b/ci/set-behat-tags.sh @@ -33,7 +33,7 @@ vercomp() { } # Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -skip_tags="--tags='~@github-api," +skip_tags="--tags='~@github-api&&" if [[ ! -z "$WP_VERSION" ]]; then requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) @@ -43,13 +43,13 @@ if [[ ! -z "$WP_VERSION" ]]; then vercomp $version $WP_VERSION compare="$?" if [[ 1 == $compare ]]; then - skip_tags="$skip_tags~$require," + skip_tags="$skip_tags~$require&&" fi done fi -skip_tags=$(echo $skip_tags| sed 's/\,$//') # trim trailing ',' +skip_tags=$(echo $skip_tags| sed 's/&&$//') # trim trailing '&&' skip_tags="$skip_tags'" # close the argument echo export behat_tags=$skip_tags From 8760891fa7ec583c40f24321def434deb1d09800 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 15 Feb 2015 10:18:27 -0800 Subject: [PATCH 3416/5359] Clarify this is all tables in the database. See #1225 --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index bfd7e021f..4b9eb0757 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -124,7 +124,7 @@ function query( $args ) { * : Extra arguments to pass to mysqldump * * [--tables=<tables>] - * : The comma separated list of specific tables to export. Excluding this parameter will export all tables + * : The comma separated list of specific tables to export. Excluding this parameter will export all tables in the database. * * ## EXAMPLES * From 0f172f0e96ed6044b5218c342d1681fe0cccd119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sun, 15 Feb 2015 21:49:33 +0100 Subject: [PATCH 3417/5359] The best I could do in the field of "tabular format" --- features/option.feature | 17 +++++++++++++---- php/commands/option.php | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/features/option.feature b/features/option.feature index 569d4da6d..bc23bcf9f 100644 --- a/features/option.feature +++ b/features/option.feature @@ -19,11 +19,14 @@ Feature: Manage WordPress options When I run `wp option list` Then STDOUT should contain: """ - bar + str_opt bar """ - When I run `wp option list --autoload=on` - Then STDOUT should not be empty + When I run `wp option list --autoload=off` + Then STDOUT should not contain: + """ + str_opt bar + """ When I run `wp option list --search='str_o*'` Then STDOUT should be a table containing rows: @@ -36,6 +39,12 @@ Feature: Manage WordPress options 3 """ + When I run `wp option list` + Then STDOUT should contain: + """ + home http://example.com + """ + When I run `wp option add auto_opt --autoload=no 'bar'` Then STDOUT should not be empty @@ -51,7 +60,7 @@ Feature: Manage WordPress options When I run `wp option list` Then STDOUT should not contain: """ - str_opt + str_opt bar """ When I try `wp option get str_opt` diff --git a/php/commands/option.php b/php/commands/option.php index cfaa0fba3..443bfaac5 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -118,7 +118,7 @@ public function add( $args, $assoc_args ) { * * size_bytes * * @subcommand list - * @synopsis [--search=<sql-like-pattern>] [--autoload=<value>] [--fields=<fields>] [--format=<format>] + * @synopsis [--search=<glob-style-pattern>] [--autoload=<value>] [--fields=<fields>] [--format=<format>] */ public function list_( $args, $assoc_args ) { From 6d4daea55f87c320d1d8a18ea4ec7e02dddd85eb Mon Sep 17 00:00:00 2001 From: mwithheld <vhmark@gmail.com> Date: Thu, 19 Feb 2015 11:14:43 -0800 Subject: [PATCH 3418/5359] Update version check test to accommodate WP4.1.1 --- features/core.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 24c07cc83..505b3caa9 100644 --- a/features/core.feature +++ b/features/core.feature @@ -296,7 +296,7 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.1 | major | https://wordpress.org/wordpress-4.1.zip | + | 4.1.1 | major | https://wordpress.org/wordpress-4.1.1.zip | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | @@ -310,7 +310,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.1 | major | https://wordpress.org/wordpress-4.1.zip | + | 4.1.1 | major | https://wordpress.org/wordpress-4.1.1.zip | | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | From 15bc0fdfe26040fedc12b237b018e5a0355262bc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 19 Feb 2015 22:01:22 -0800 Subject: [PATCH 3419/5359] Use `mysql` with `--no-auto-rehash` for perf boost --- php/commands/db.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 4b9eb0757..e6f01bfa1 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -78,7 +78,7 @@ function repair() { * @alias connect */ function cli() { - self::run( 'mysql --no-defaults', array( + self::run( 'mysql --no-defaults --no-auto-rehash', array( 'database' => DB_NAME ) ); } @@ -109,7 +109,7 @@ function query( $args ) { $assoc_args['execute'] = $args[0]; } - self::run( 'mysql --no-defaults', $assoc_args ); + self::run( 'mysql --no-defaults --no-auto-rehash', $assoc_args ); } /** @@ -192,7 +192,7 @@ function import( $args, $assoc_args ) { ); } - self::run( 'mysql --no-defaults', array( + self::run( 'mysql --no-defaults --no-auto-rehash', array( 'database' => DB_NAME ), $descriptors ); @@ -244,7 +244,7 @@ private static function get_create_query() { } private static function run_query( $query ) { - self::run( 'mysql --no-defaults', array( 'execute' => $query ) ); + self::run( 'mysql --no-defaults --no-auto-rehash', array( 'execute' => $query ) ); } private static function run( $cmd, $assoc_args = array(), $descriptors = null ) { From c2b4a8bbb858a93ca5d4028dcd2e1a6c6891b295 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 20 Feb 2015 22:45:06 +0000 Subject: [PATCH 3420/5359] do not force a SHA512 signature in make-phar.php --- utils/make-phar.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index 83e0e106f..1ce6f7b87 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -53,8 +53,6 @@ function set_file_contents( $phar, $path, $content ) { $phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); -$phar->setSignatureAlgorithm( Phar::SHA512 ); - $phar->startBuffering(); // PHP files @@ -114,6 +112,3 @@ function set_file_contents( $phar, $path, $content ) { $phar->stopBuffering(); echo "Generated " . DEST_PATH . "\n"; - -$signature = $phar->getSignature(); -echo "{$signature['hash_type']} signature: {$signature['hash']}\n"; From 8b59d511034ff8313a7b9eb48043173fc7137a45 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 21 Feb 2015 10:23:38 -0800 Subject: [PATCH 3421/5359] Don't append `.phar` because it's already included in `$fname` See #1555 --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 8829599d5..893920836 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -38,7 +38,7 @@ chmod -x $fname md5sum $fname | cut -d ' ' -f 1 > $fname.md5 sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 -git add $fname.phar $fname.md5 $fname.sha512 +git add $fname $fname.md5 $fname.sha512 git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" git push From 9e4ee3f5a160f5ff12ca295ba62a36a5f65b11d0 Mon Sep 17 00:00:00 2001 From: Josh Betz <j@joshbetz.com> Date: Wed, 25 Feb 2015 22:35:05 -0600 Subject: [PATCH 3422/5359] Pad export filenames with zeros It's helpful in many cases to have these files automatically ordered correctly. Without padded zeros, they will be ordered something like: ``` *.1.xml *.10.xml *.2.xml *.3.xml ... ``` --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 4569d6d08..976901d7b 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -100,7 +100,7 @@ private static function get_filename_template() { if ( ! empty( $sitename ) ) { $sitename .= '.'; } - return $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.%d.xml'; + return $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.%03d.xml'; } private static function load_export_api() { From 6fbb217e875e9cd7bb73a774bac98b1a95d50950 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 26 Feb 2015 13:36:34 +0000 Subject: [PATCH 3423/5359] When testing WP-Cron, correctly set the `sslverify `argument depending on the version of WordPress in use. --- php/commands/cron.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 32d195950..527e42798 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -509,7 +509,9 @@ public function test() { * @return WP_Error|array The response or WP_Error on failure. */ protected static function get_cron_spawn() { + global $wp_version; + $sslverify = version_compare( $wp_version, 4.0, '<' ); $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); $cron_request = apply_filters( 'cron_request', array( @@ -518,7 +520,7 @@ protected static function get_cron_spawn() { 'args' => array( 'timeout' => 3, 'blocking' => true, - 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) + 'sslverify' => apply_filters( 'https_local_ssl_verify', $sslverify ) ) ) ); From 078585bfa30fd2759484bbc2e7cb3bc8dc1959f5 Mon Sep 17 00:00:00 2001 From: JQ <JeyKeu@users.noreply.github.com> Date: Tue, 3 Mar 2015 15:16:02 +0500 Subject: [PATCH 3424/5359] Elaborated error message This should fix #1434 When we download the `non-phar` version of `wp-cli` we have to run `composer install` to install it's dependencies. If we try to run `wp` when we haven't run `composer install`, we get this error: `Internal error: Can't find Composer autoloader.` which doesn't help. Instead I added: `Try running: composer install\n` Giving: `Internal error: Can't find Composer autoloader.\nTry running: composer install\n` Which makes more sense. --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index b80c0ea17..9581c164d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -24,7 +24,7 @@ function load_dependencies() { } if ( !$has_autoload ) { - fputs( STDERR, "Internal error: Can't find Composer autoloader.\n" ); + fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); exit(3); } } From 6f373e06c590abf8990e4ae19455905a2e75f604 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 3 Mar 2015 19:45:59 -0800 Subject: [PATCH 3425/5359] Throw hard error if importing a file returns WP_Error `create_author_mapping_file()` uses WP_Error to report that an author mapping file needs to be updated. However, when importing a directory of WXR files, only using `::warning()` means the second file will use the author mapping file of the first, which should've been edited. --- php/commands/import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index d082d3797..58668db4d 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -55,7 +55,7 @@ public function __invoke( $args, $assoc_args ) { $ret = $this->import_wxr( $file, $assoc_args ); if ( is_wp_error( $ret ) ) { - WP_CLI::warning( $ret ); + WP_CLI::error( $ret ); } else { WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line WP_CLI::success( "Finished importing from $file file." ); From c81c3042855f109926d5cd8a948a29d6ca6b00e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 3 Mar 2015 20:21:15 -0800 Subject: [PATCH 3426/5359] Ensure our fake cached WordPress download is considered fresh WPorg started serving WordPress downloads with a historic filemtime, meaning our cache gets cleared as soon as we try to use it. --- features/core.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 505b3caa9..fa783ea10 100644 --- a/features/core.feature +++ b/features/core.feature @@ -547,7 +547,7 @@ Feature: Manage WordPress installation Scenario: Ensure file cache isn't corrupted by a ZIP masquerading as a gzipped TAR, part one Given a WP install And an empty cache - And I run `mkdir -p {SUITE_CACHE_DIR}/core; wget -O {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz https://wordpress.org/wordpress-4.0.zip` + And I run `mkdir -p {SUITE_CACHE_DIR}/core; wget -O {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz https://wordpress.org/wordpress-4.0.zip; touch {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz` When I run `wp core download --version=4.0 --force` Then STDOUT should contain: From 8825b8b183a46bc5e2c4e503320130b03cd3f4b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 3 Mar 2015 20:28:18 -0800 Subject: [PATCH 3427/5359] If a term is missing a parent, be more descriptive as to where it's missing --- php/export/class-wp-export-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 6f5bb9bf3..95c176c75 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -294,7 +294,7 @@ private function check_for_orphaned_terms( $terms ) { foreach ( $have_parent as $has_parent ) { if ( ! isset( $term_ids[ $has_parent->parent ] ) ) { $this->missing_parents = $has_parent; - throw new WP_Export_Term_Exception( __( 'Term is missing a parent.' ) ); + throw new WP_Export_Term_Exception( sprintf( __( 'Term is missing a parent: %s (%d)' ), $has_parent->slug, $has_parent->term_taxonomy_id ) ); } } } From 2818c2057b1d064f2257e6ea7821a3794f510041 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 4 Mar 2015 07:06:23 -0800 Subject: [PATCH 3428/5359] Update php-cli-tools to v0.10.4 See https://github.com/wp-cli/php-cli-tools/releases/tag/v0.10.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8d35b340c..6b17472c7 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.3", + "wp-cli/php-cli-tools": "0.10.4", "mustache/mustache": "~2.4", "rhumsaa/array_column": "~1.1", "rmccue/requests": "~1.6", From 7bd1553d9a0fab8885384367c493a8272a9eff82 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 4 Mar 2015 07:14:49 -0800 Subject: [PATCH 3429/5359] Wrap comment meta values in CDATA on export --- php/export/class-wp-export-wxr-formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index 5a99543a7..92c15f768 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -252,7 +252,7 @@ protected function comment_meta( $comment ) { foreach( $metas as $meta ) { $oxymel->tag( 'wp:commentmeta' )->contains ->tag( 'wp:meta_key', $meta->meta_key ) - ->tag( 'wp:meta_value', $meta->meta_value ) + ->tag( 'wp:meta_value' )->contains->cdata( $meta->meta_value )->end ->end; } return $oxymel; From 71377a3b56c4196ddb7883441b0832b60acb89bb Mon Sep 17 00:00:00 2001 From: Keith Grennan <keith@nearlyfree.org> Date: Wed, 4 Mar 2015 13:39:51 -0800 Subject: [PATCH 3430/5359] sanitize option before checking value equality If a plugin defines a sanitize_option filter, the equality check in 'wp option update' may indicate that the the new option value is different from the original when in fact it is not. The result is a spurious error message on an unchanged option, instead of succeeding with 'Value passed for 'foo' option is unchanged'. I see this with the Yoast SEO plugin which defines this filter. --- php/commands/option.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index 443bfaac5..6f8b8e888 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -203,6 +203,8 @@ public function update( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); + $value = sanitize_option( $key, $value ); + if ( $value === get_option( $key ) ) { WP_CLI::success( "Value passed for '$key' option is unchanged." ); } else { @@ -246,4 +248,3 @@ private static function esc_like( $old ) { } WP_CLI::add_command( 'option', 'Option_Command' ); - From bfa7266d137a50a4d4ac50101398f5c3db9de25e Mon Sep 17 00:00:00 2001 From: Keith Grennan <keith@nearlyfree.org> Date: Thu, 5 Mar 2015 06:34:35 -0800 Subject: [PATCH 3431/5359] sanitize the value to compare as well The === comparison in 'wp option update' was breaking due to sanitize_option() turning the value of blog_public from a string to an integer. This comparison logic seems brittle but I understand the problem that WP's update_option returns false both on errors and when the option is unchanged, so we're trying to distinguish between them. --- php/commands/option.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index 6f8b8e888..6575da1a3 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -204,8 +204,9 @@ public function update( $args, $assoc_args ) { $value = WP_CLI::read_value( $value, $assoc_args ); $value = sanitize_option( $key, $value ); + $old_value = sanitize_option( $key, get_option( $key ) ); - if ( $value === get_option( $key ) ) { + if ( $value === $old_value ) { WP_CLI::success( "Value passed for '$key' option is unchanged." ); } else { if ( update_option( $key, $value ) ) { From b79f7e31aac7c8251556bc267b7adc5f4a55ad05 Mon Sep 17 00:00:00 2001 From: Keith Grennan <keith@nearlyfree.org> Date: Thu, 5 Mar 2015 07:43:33 -0800 Subject: [PATCH 3432/5359] apply option unchanged logic to post meta --- features/post-meta.feature | 3 +++ php/WP_CLI/CommandWithMeta.php | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 821be2fad..9e37fd510 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -21,6 +21,9 @@ Feature: Manage post custom fields When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty + When I run the previous command again + Then STDOUT should not be empty + When I run `wp post-meta get 1 foo --format=json` Then STDOUT should be: """ diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 1d1f72eca..9e9b07518 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -181,13 +181,22 @@ public function update( $args, $assoc_args ) { $object_id = $this->check_object_id( $object_id ); - $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $meta_value = sanitize_meta( $meta_key, $meta_value, $this->meta_type ); + $old_value = sanitize_meta( $meta_key, get_metadata( $this->meta_type, $object_id, $meta_key, true ), $this->meta_type ); - if ( $success ) { - \WP_CLI::success( "Updated custom field." ); + if ( $meta_value === $old_value ) { + \WP_CLI::success( "Value passed for custom field '$meta_key' is unchanged." ); } else { - \WP_CLI::error( "Failed to update custom field." ); + $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + + if ( $success ) { + \WP_CLI::success( "Updated custom field '$meta_key'." ); + } else { + \WP_CLI::error( "Failed to update custom field '$meta_key'." ); + } + } + } /** @@ -214,4 +223,3 @@ protected function check_object_id( $object_id ) { } } - From 09c8208cd045f3125cc64309424a954a1d1212e4 Mon Sep 17 00:00:00 2001 From: Keith Grennan <keith@nearlyfree.org> Date: Thu, 5 Mar 2015 13:13:37 -0800 Subject: [PATCH 3433/5359] check for the specific message --- features/post-meta.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 9e37fd510..74b30eabc 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -22,7 +22,10 @@ Feature: Manage post custom fields Then STDOUT should not be empty When I run the previous command again - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Value passed for custom field 'foo' is unchanged. + """ When I run `wp post-meta get 1 foo --format=json` Then STDOUT should be: From d91f39d77462ed58b098db123e47d9b552d675f8 Mon Sep 17 00:00:00 2001 From: Jim Reevior <jim@thinkoomph.com> Date: Thu, 5 Mar 2015 17:58:32 -0500 Subject: [PATCH 3434/5359] Added allow multisite constant to multisite install and convert. The multisite install and convert procedures do not include: define( 'WP_ALLOW_MULTISITE', true ); If this isn't present, the "Network Settings" and "Network Setup" menu items are not available in the network admin. --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index 9fbbb34cd..c79c9ed5a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -636,6 +636,7 @@ private function _multisite_convert( $assoc_args ) { if ( !is_multisite() ) { ob_start(); ?> +define( 'WP_ALLOW_MULTISITE', true ); define('MULTISITE', true); define('SUBDOMAIN_INSTALL', <?php var_export( $assoc_args['subdomains'] ); ?>); $base = '<?php echo $assoc_args['base']; ?>'; From 4e88a33d10794d0ddbdc8eb7714e056722a19bd4 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Thu, 5 Mar 2015 23:42:45 -0600 Subject: [PATCH 3435/5359] Add --all-tables flag to search-replace command --- php/commands/search-replace.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index cd09e1861..20fbb7e76 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -46,6 +46,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * + * [--all-tables] + * : Enable replacement on ALL tables in the database, regardless of the prefix. Overrides --network and --all-tables-with-prefix. + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -64,6 +67,7 @@ public function __invoke( $args, $assoc_args ) { $dry_run = isset( $assoc_args['dry-run'] ); $php_only = isset( $assoc_args['precise'] ); $recurse_objects = isset( $assoc_args['recurse-objects'] ); + $all_tables = isset( $assoc_args['all-tables'] ); if ( isset( $assoc_args['skip-columns'] ) ) $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -73,7 +77,16 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - $tables = self::get_table_list( $args, isset( $assoc_args['network'] ), isset( $assoc_args['all-tables-with-prefix'] ) ); + if ( $all_tables ) { + WP_CLI::confirm( "Will run against ALL tables in the database, not only WordPress tables. Continue?" ); + $tables = $wpdb->get_col( 'SHOW TABLES' ); + } else { + $tables = self::get_table_list( + $args, + isset( $assoc_args['network'] ), + isset( $assoc_args['all-tables-with-prefix'] ) + ); + } foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); From aa783be40c36c477a6afbcd18c8545a14d646f55 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Thu, 5 Mar 2015 23:43:37 -0600 Subject: [PATCH 3436/5359] Add tests for --all-tables flag --- features/search-replace.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index f85ae7c24..d66b6bcef 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -40,6 +40,22 @@ Feature: Do global search/replace wp_awesome """ + Scenario: Run on unregistered, unprefixed tables with --all-tables flag + Given a WP install + And I run `wp db query "CREATE TABLE awesome_table ( id int(11) unsigned NOT NULL AUTO_INCREMENT, awesome_stuff TEXT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` + + When I run `wp search-replace foo bar` + Then STDOUT should not contain: + """ + awesome_table + """ + + When I run `wp search-replace foo bar --all-tables` + Then STDOUT should contain: + """ + awesome_table + """ + Scenario: Quiet search/replace Given a WP install From f4b28dab4c4aadb774343532ce2a5a3b0e74782f Mon Sep 17 00:00:00 2001 From: yivi <ivan@ojiva.es> Date: Sat, 7 Mar 2015 11:52:27 +0100 Subject: [PATCH 3437/5359] Check to see if _s theme has actually been created, or if the unzip operation failed. --- php/commands/scaffold.php | 213 ++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 98 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a4d239b72..1b8d7485d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -39,7 +39,7 @@ class Scaffold_Command extends WP_CLI_Command { * * @subcommand post-type * - * @alias cpt + * @alias cpt */ function post_type( $args, $assoc_args ) { @@ -91,7 +91,7 @@ function post_type( $args, $assoc_args ) { * * @subcommand taxonomy * - * @alias tax + * @alias tax */ function taxonomy( $args, $assoc_args ) { $defaults = array( @@ -99,7 +99,7 @@ function taxonomy( $args, $assoc_args ) { 'post_types' => "'post'" ); - if( isset($assoc_args['post_types']) ) { + if ( isset( $assoc_args['post_types'] ) ) { $assoc_args['post_types'] = $this->quote_comma_list_elements( $assoc_args['post_types'] ); } @@ -114,9 +114,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $control_args = $this->extract_args( $assoc_args, array( 'label' => preg_replace( '/_|-/', ' ', strtolower( $slug ) ), - 'theme' => false, - 'plugin' => false, - 'raw' => false, + 'theme' => FALSE, + 'plugin' => FALSE, + 'raw' => FALSE, ) ); $vars = $this->extract_args( $assoc_args, $defaults ); @@ -132,7 +132,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $vars['label_plural_ucfirst'] = ucfirst( $vars['label_plural'] ); // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $slug ); + $machine_name = preg_replace( '/-/', '_', $slug ); $machine_name_plural = $this->pluralize( $slug ); list( $raw_template, $extended_template ) = $templates; @@ -142,7 +142,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) if ( ! $control_args['raw'] ) { $vars = array_merge( $vars, array( 'machine_name' => $machine_name, - 'output' => $raw_output + 'output' => $raw_output ) ); $final_output = Utils\mustache_render( $extended_template, $vars ); @@ -151,7 +151,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) } if ( $path = $this->get_output_path( $control_args, $subdir ) ) { - $filename = $path . $slug .'.php'; + $filename = $path . $slug . '.php'; $this->create_file( $filename, $final_output ); @@ -189,31 +189,35 @@ function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; - $url = "http://underscores.me"; - $timeout = 30; + $url = "http://underscores.me"; + $timeout = 30; $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), - 'author' => "Me", + 'author' => "Me", 'author_uri' => "", ) ); - $theme_description = "Custom theme: ".$data['theme_name']." developed by, ".$data['author']; + $theme_description = "Custom theme: " . $data['theme_name'] . " developed by, " . $data['author']; - $body = array(); - $body['underscoresme_name'] = $data['theme_name']; - $body['underscoresme_slug'] = $theme_slug; - $body['underscoresme_author'] = $data['author']; - $body['underscoresme_author_uri'] = $data['author_uri']; - $body['underscoresme_description'] = $theme_description; + $body = array(); + $body['underscoresme_name'] = $data['theme_name']; + $body['underscoresme_slug'] = $theme_slug; + $body['underscoresme_author'] = $data['author']; + $body['underscoresme_author_uri'] = $data['author_uri']; + $body['underscoresme_description'] = $theme_description; $body['underscoresme_generate_submit'] = "Generate"; - $body['underscoresme_generate'] = "1"; + $body['underscoresme_generate'] = "1"; if ( isset( $assoc_args['sassify'] ) ) { $body['underscoresme_sass'] = 1; } - $tmpfname = wp_tempnam($url); - $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, 'stream' => true, 'filename' => $tmpfname ) ); + $tmpfname = wp_tempnam( $url ); + $response = wp_remote_post( $url, array( 'timeout' => $timeout, + 'body' => $body, + 'stream' => TRUE, + 'filename' => $tmpfname + ) ); if ( is_wp_error( $response ) ) { WP_CLI::error( $response ); @@ -227,13 +231,19 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); - unzip_file( $tmpfname, $theme_path ); + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); - WP_CLI::success( "Created theme '{$data['theme_name']}'." ); + if ( TRUE === $unzip_result ) { + WP_CLI::success( "Created theme '{$data['theme_name']}'." ); + } else { + WP_CLI::error( "Could not decompress your theme files ('$tmpfname') at '$theme_path': " . $unzip_result->get_error_message() ); + print_r( $unzip_result ); + } - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + } } @@ -270,15 +280,15 @@ function child_theme( $args, $assoc_args ) { $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), - 'author' => "Me", + 'author' => "Me", 'author_uri' => "", - 'theme_uri' => "" + 'theme_uri' => "" ) ); $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; - $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; - $theme_style_path = "$theme_dir/style.css"; + $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; + $theme_style_path = "$theme_dir/style.css"; $theme_functions_path = "$theme_dir/functions.php"; $this->maybe_create_themes_dir(); @@ -288,25 +298,27 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + } } private function get_output_path( $assoc_args, $subdir ) { if ( $assoc_args['theme'] ) { $theme = $assoc_args['theme']; - if ( is_string( $theme ) ) + if ( is_string( $theme ) ) { $path = get_theme_root( $theme ) . '/' . $theme; - else + } else { $path = get_stylesheet_directory(); + } } elseif ( $assoc_args['plugin'] ) { $plugin = $assoc_args['plugin']; - $path = WP_PLUGIN_DIR . '/' . $plugin; - if ( !is_dir( $path ) ) { + $path = WP_PLUGIN_DIR . '/' . $plugin; + if ( ! is_dir( $path ) ) { WP_CLI::error( "Can't find '$plugin' plugin." ); } } else { - return false; + return FALSE; } $path .= $subdir; @@ -342,7 +354,7 @@ private function get_output_path( $assoc_args, $subdir ) { * * wp scaffold package-tests /path/to/command/dir/ * - * @when before_wp_load + * @when before_wp_load * @subcommand package-tests */ public function package_tests( $args, $assoc_args ) { @@ -360,39 +372,39 @@ public function package_tests( $args, $assoc_args ) { } $package_dir .= '/'; - $bin_dir = $package_dir . 'bin/'; - $utils_dir = $package_dir . 'utils/'; - $features_dir = $package_dir . 'features/'; + $bin_dir = $package_dir . 'bin/'; + $utils_dir = $package_dir . 'utils/'; + $features_dir = $package_dir . 'features/'; $bootstrap_dir = $features_dir . 'bootstrap/'; - $steps_dir = $features_dir . 'steps/'; - $extra_dir = $features_dir . 'extra/'; - foreach( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir, $bin_dir ) as $dir ) { + $steps_dir = $features_dir . 'steps/'; + $extra_dir = $features_dir . 'extra/'; + foreach ( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir, $bin_dir ) as $dir ) { if ( ! is_dir( $dir ) ) { Process::create( Utils\esc_cmd( 'mkdir %s', $dir ) )->run(); } } $to_copy = array( - 'templates/.travis.package.yml' => $package_dir, - 'templates/load-wp-cli.feature' => $features_dir, - 'templates/install-package-tests.sh' => $bin_dir, - 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, - 'features/bootstrap/support.php' => $bootstrap_dir, - 'php/WP_CLI/Process.php' => $bootstrap_dir, - 'php/utils.php' => $bootstrap_dir, + 'templates/.travis.package.yml' => $package_dir, + 'templates/load-wp-cli.feature' => $features_dir, + 'templates/install-package-tests.sh' => $bin_dir, + 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, + 'features/bootstrap/support.php' => $bootstrap_dir, + 'php/WP_CLI/Process.php' => $bootstrap_dir, + 'php/utils.php' => $bootstrap_dir, 'utils/get-package-require-from-composer.php' => $utils_dir, - 'features/steps/given.php' => $steps_dir, - 'features/steps/when.php' => $steps_dir, - 'features/steps/then.php' => $steps_dir, - 'features/extra/no-mail.php' => $extra_dir, + 'features/steps/given.php' => $steps_dir, + 'features/steps/when.php' => $steps_dir, + 'features/steps/then.php' => $steps_dir, + 'features/extra/no-mail.php' => $extra_dir, ); foreach ( $to_copy as $file => $dir ) { // file_get_contents() works with Phar-archived files - $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); + $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); $file_path = $dir . basename( $file ); - $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml'), $file_path ); - $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); + $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml' ), $file_path ); + $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); file_put_contents( $file_path, $contents ); if ( 'templates/install-package-tests.sh' === $file ) { Process::create( Utils\esc_cmd( 'chmod +x %s', $file_path ) )->run(); @@ -429,8 +441,8 @@ function plugin( $args, $assoc_args ) { $data['textdomain'] = $plugin_slug; - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - $plugin_path = "$plugin_dir/$plugin_slug.php"; + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + $plugin_path = "$plugin_dir/$plugin_slug.php"; $plugin_readme_path = "$plugin_dir/readme.txt"; $this->maybe_create_plugins_dir(); @@ -440,7 +452,7 @@ function plugin( $args, $assoc_args ) { WP_CLI::success( "Created $plugin_dir" ); - if ( !isset( $assoc_args['skip-tests'] ) ) { + if ( ! isset( $assoc_args['skip-tests'] ) ) { WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); } @@ -483,8 +495,8 @@ function plugin_tests( $args, $assoc_args ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - $tests_dir = "$plugin_dir/tests"; - $bin_dir = "$plugin_dir/bin"; + $tests_dir = "$plugin_dir/tests"; + $bin_dir = "$plugin_dir/bin"; $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); @@ -494,13 +506,13 @@ function plugin_tests( $args, $assoc_args ) { $to_copy = array( 'install-wp-tests.sh' => $bin_dir, - '.travis.yml' => $plugin_dir, - 'phpunit.xml' => $plugin_dir, - 'test-sample.php' => $tests_dir, + '.travis.yml' => $plugin_dir, + 'phpunit.xml' => $plugin_dir, + 'test-sample.php' => $tests_dir, ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", TRUE ); if ( 'install-wp-tests.sh' === $file ) { if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); @@ -516,7 +528,7 @@ private function create_file( $filename, $contents ) { $wp_filesystem->mkdir( dirname( $filename ) ); - if ( !$wp_filesystem->put_contents( $filename, $contents ) ) { + if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { WP_CLI::error( "Error creating file: $filename" ); } } @@ -526,62 +538,65 @@ private function create_file( $filename, $contents ) { * Same goes for when plugin is being used. */ private function get_textdomain( $textdomain, $args ) { - if ( strlen( $textdomain ) ) + if ( strlen( $textdomain ) ) { return $textdomain; + } - if ( $args['theme'] ) + if ( $args['theme'] ) { return strtolower( wp_get_theme()->template ); + } - if ( $args['plugin'] && true !== $args['plugin'] ) + if ( $args['plugin'] && TRUE !== $args['plugin'] ) { return $args['plugin']; + } return 'YOUR-TEXTDOMAIN'; } private function pluralize( $word ) { $plural = array( - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)ix|ex$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(buffal|tomat)o$/i' => '\1oes', - '/(bu)s$/i' => '1ses', - '/(alias|status)/i' => '\1es', - '/(octop|vir)us$/i' => '1i', - '/(ax|test)is$/i' => '\1es', - '/s$/i' => 's', - '/$/' => 's' + '/(quiz)$/i' => '\1zes', + '/^(ox)$/i' => '\1en', + '/([m|l])ouse$/i' => '\1ice', + '/(matr|vert|ind)ix|ex$/i' => '\1ices', + '/(x|ch|ss|sh)$/i' => '\1es', + '/([^aeiouy]|qu)ies$/i' => '\1y', + '/([^aeiouy]|qu)y$/i' => '\1ies', + '/(hive)$/i' => '\1s', + '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', + '/sis$/i' => 'ses', + '/([ti])um$/i' => '\1a', + '/(buffal|tomat)o$/i' => '\1oes', + '/(bu)s$/i' => '1ses', + '/(alias|status)/i' => '\1es', + '/(octop|vir)us$/i' => '1i', + '/(ax|test)is$/i' => '\1es', + '/s$/i' => 's', + '/$/' => 's' ); $uncountable = array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep' ); $irregular = array( - 'person' => 'people', - 'man' => 'men', - 'woman' => 'women', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves' + 'person' => 'people', + 'man' => 'men', + 'woman' => 'women', + 'child' => 'children', + 'sex' => 'sexes', + 'move' => 'moves' ); $lowercased_word = strtolower( $word ); foreach ( $uncountable as $_uncountable ) { - if ( substr( $lowercased_word, ( -1 * strlen( $_uncountable ) ) ) == $_uncountable ) { + if ( substr( $lowercased_word, ( - 1 * strlen( $_uncountable ) ) ) == $_uncountable ) { return $word; } } - foreach ( $irregular as $_plural=> $_singular ) { - if ( preg_match( '/('.$_plural.')$/i', $word, $arr ) ) { - return preg_replace( '/('.$_plural.')$/i', substr( $arr[0], 0, 1 ).substr( $_singular, 1 ), $word ); + foreach ( $irregular as $_plural => $_singular ) { + if ( preg_match( '/(' . $_plural . ')$/i', $word, $arr ) ) { + return preg_replace( '/(' . $_plural . ')$/i', substr( $arr[0], 0, 1 ) . substr( $_singular, 1 ), $word ); } } @@ -590,7 +605,8 @@ private function pluralize( $word ) { return preg_replace( $rule, $replacement, $word ); } } - return false; + + return FALSE; } protected function extract_args( $assoc_args, $defaults ) { @@ -638,6 +654,7 @@ protected function maybe_create_plugins_dir() { private function init_wp_filesystem() { global $wp_filesystem; WP_Filesystem(); + return $wp_filesystem; } From 286c49816061fd4a8e379ecd91ca0e8408ba1f0e Mon Sep 17 00:00:00 2001 From: yivi <ivan@ojiva.es> Date: Sat, 7 Mar 2015 12:13:49 +0100 Subject: [PATCH 3438/5359] changed spaces for tabs to pass travis tests --- php/commands/scaffold.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 1b8d7485d..f43be21eb 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -213,11 +213,12 @@ function _s( $args, $assoc_args ) { } $tmpfname = wp_tempnam( $url ); - $response = wp_remote_post( $url, array( 'timeout' => $timeout, - 'body' => $body, - 'stream' => TRUE, - 'filename' => $tmpfname - ) ); + $response = wp_remote_post( $url, array( + 'timeout' => $timeout, + 'body' => $body, + 'stream' => TRUE, + 'filename' => $tmpfname + ) ); if ( is_wp_error( $response ) ) { WP_CLI::error( $response ); From 589ca86392f7790e3446bcbf11c12295c35a9f24 Mon Sep 17 00:00:00 2001 From: Bobby Walters <bobbymwalters@gmail.com> Date: Sat, 7 Mar 2015 23:31:02 -0500 Subject: [PATCH 3439/5359] Honor https scheme on --url option When using the --url global option (or during core install), URLs with an https scheme were being treated as http. The WP is_ssl() function checks for the $_SERVER['HTTPS'] flag or port 443 being set. This change allows standard and non-standard ports to be used so is_ssl() will return true when the supplied URL has an https scheme. This helps with the wp_guess_url() call during wp_install() so the proper URL is used when populating the database. --- php/class-wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cfe4ae30a..f571c47a5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -103,6 +103,10 @@ private static function set_url_params( $url_parts ) { }; if ( isset( $url_parts['host'] ) ) { + if ( isset( $url_parts['scheme'] ) && 'https' === strtolower( $url_parts['scheme'] ) ) { + $_SERVER['HTTPS'] = 'on'; + } + $_SERVER['HTTP_HOST'] = $url_parts['host']; if ( isset( $url_parts['port'] ) ) { $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; From 29e345f5f945e1995fae5f465786155e94b5a078 Mon Sep 17 00:00:00 2001 From: Bobby Walters <bobbymwalters@gmail.com> Date: Sun, 8 Mar 2015 16:12:12 -0400 Subject: [PATCH 3440/5359] Added functional tests for --url=https://... --- features/core.feature | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/features/core.feature b/features/core.feature index fa783ea10..636989d60 100644 --- a/features/core.feature +++ b/features/core.feature @@ -53,7 +53,7 @@ Feature: Manage WordPress installation Error: wp-config.php not found. Either create one manually or use `wp core config`. """ - + Given a wp-config-extra.php file: """ define( 'WP_DEBUG_LOG', true ); @@ -162,6 +162,36 @@ Feature: Manage WordPress installation http://localhost:8001 """ + Scenario: Install WordPress with an https scheme + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core install --url='https://localhost' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` + Then the return code should be 0 + + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + https://localhost + """ + + Scenario: Install WordPress with an https scheme and non-standard port + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core install --url='https://localhost:8443' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` + Then the return code should be 0 + + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + https://localhost:8443 + """ + Scenario: Full install Given a WP install @@ -173,7 +203,7 @@ Feature: Manage WordPress installation Then STDOUT should be: """ false - """ + """ When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` Then STDOUT should be: @@ -225,7 +255,7 @@ Feature: Manage WordPress installation Then STDOUT should be: """ foobar.org - """ + """ # Can complain that it's already installed, but don't exit with an error code When I try `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` From 87dda00ffcae850b4c542b90b98611cce37832de Mon Sep 17 00:00:00 2001 From: yivi <ivan@ojiva.es> Date: Mon, 9 Mar 2015 11:53:53 +0100 Subject: [PATCH 3441/5359] uppercase booleans to lowercase braces for variables inside a string. --- php/commands/scaffold.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f43be21eb..0e52489c7 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -114,9 +114,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $control_args = $this->extract_args( $assoc_args, array( 'label' => preg_replace( '/_|-/', ' ', strtolower( $slug ) ), - 'theme' => FALSE, - 'plugin' => FALSE, - 'raw' => FALSE, + 'theme' => false, + 'plugin' => false, + 'raw' => false, ) ); $vars = $this->extract_args( $assoc_args, $defaults ); @@ -216,7 +216,7 @@ function _s( $args, $assoc_args ) { $response = wp_remote_post( $url, array( 'timeout' => $timeout, 'body' => $body, - 'stream' => TRUE, + 'stream' => true, 'filename' => $tmpfname ) ); @@ -235,11 +235,10 @@ function _s( $args, $assoc_args ) { $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); - if ( TRUE === $unzip_result ) { + if ( true === $unzip_result ) { WP_CLI::success( "Created theme '{$data['theme_name']}'." ); } else { - WP_CLI::error( "Could not decompress your theme files ('$tmpfname') at '$theme_path': " . $unzip_result->get_error_message() ); - print_r( $unzip_result ); + WP_CLI::error( "Could not decompress your theme files ('{$tmpfname}') at '{$theme_path}': {$unzip_result->get_error_message()}" ); } if ( isset( $assoc_args['activate'] ) ) { @@ -319,7 +318,7 @@ private function get_output_path( $assoc_args, $subdir ) { WP_CLI::error( "Can't find '$plugin' plugin." ); } } else { - return FALSE; + return false; } $path .= $subdir; @@ -513,7 +512,7 @@ function plugin_tests( $args, $assoc_args ) { ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", TRUE ); + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); if ( 'install-wp-tests.sh' === $file ) { if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); @@ -547,7 +546,7 @@ private function get_textdomain( $textdomain, $args ) { return strtolower( wp_get_theme()->template ); } - if ( $args['plugin'] && TRUE !== $args['plugin'] ) { + if ( $args['plugin'] && true !== $args['plugin'] ) { return $args['plugin']; } @@ -607,7 +606,7 @@ private function pluralize( $word ) { } } - return FALSE; + return false; } protected function extract_args( $assoc_args, $defaults ) { From ad0dfddf558b24c379ed18d6036757d9e615a647 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 9 Mar 2015 12:26:09 -0300 Subject: [PATCH 3442/5359] `wp post term list` display error for invalid taxonomy --- features/post-term.feature | 8 +++++++- php/WP_CLI/CommandWithTerms.php | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/features/post-term.feature b/features/post-term.feature index 20ab616b2..d38f628c2 100644 --- a/features/post-term.feature +++ b/features/post-term.feature @@ -26,6 +26,12 @@ Feature: Manage post term | foo | foo | category | | bar | bar | category | + When I try `wp post term list 1 foo2` + Then STDERR should be: + """ + Error: Invalid taxonomy foo2. + """ + When I run `wp post term set 1 category new` Then STDOUT should be: """ @@ -89,5 +95,5 @@ Feature: Manage post term Then the return code should be 1 And STDERR should be: """ - Error: Invalid taxonomy. + Error: Invalid taxonomy foo2. """ diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index 1ba36170f..277fe4aed 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -72,6 +72,10 @@ public function list_( $args, $assoc_args ) { $this->set_obj_id( $object_id ); + foreach ( $taxonomy_names as $taxonomy ) { + $this->taxonomy_exists( $taxonomy ); + } + $items = wp_get_object_terms( $object_id, $taxonomy_names ); $formatter = $this->get_formatter( $assoc_args ); @@ -263,7 +267,7 @@ protected function taxonomy_exists( $taxonomy ) { $taxonomy_names = get_object_taxonomies( $this->get_object_type() ); if ( ! in_array( $taxonomy, $taxonomy_names ) ) { - WP_CLI::error( 'Invalid taxonomy.' ); + WP_CLI::error( "Invalid taxonomy {$taxonomy}." ); } } From 32417605ff1fe16fb659266f3163548792b36437 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 9 Mar 2015 14:44:00 -0300 Subject: [PATCH 3443/5359] fix failing test --- features/user-term.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/user-term.feature b/features/user-term.feature index 3895f20a2..0c83e2f7a 100644 --- a/features/user-term.feature +++ b/features/user-term.feature @@ -105,5 +105,5 @@ Feature: Manage user term Then the return code should be 1 And STDERR should be: """ - Error: Invalid taxonomy. + Error: Invalid taxonomy boo. """ \ No newline at end of file From 2f6d0374ec589b483213f6d19e3b1439496f08d3 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 13:41:47 -0400 Subject: [PATCH 3444/5359] Create utility function for options. --- php/utils.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/php/utils.php b/php/utils.php index 9581c164d..46143896f 100644 --- a/php/utils.php +++ b/php/utils.php @@ -504,3 +504,18 @@ function increment_version( $current_version, $new_version ) { return $current_version; } + +/** + * Determine the boolean value of a flag in an array. + * + * Primarily useful for determining the status of a boolean flag for a command. This is needed because a flag can be + * prefixed with --no- to set it to false. Therefore it is not sufficient to only check whether a flag is set. + * + * @param array $array The array to check. + * @param string $key The key to check for. + * + * @return bool True if the key is set in the array and is truthy, false otherwise. + */ +function flag( $array, $key ) { + return isset( $array[ $key ] ) && $array[ $key ]; +} From 35e3fec28430c40ccf3d876a5fdb0c625d10ada5 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 13:49:08 -0400 Subject: [PATCH 3445/5359] Formatting updates --- php/commands/search-replace.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 20fbb7e76..d34c510ff 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -69,10 +69,11 @@ public function __invoke( $args, $assoc_args ) { $recurse_objects = isset( $assoc_args['recurse-objects'] ); $all_tables = isset( $assoc_args['all-tables'] ); - if ( isset( $assoc_args['skip-columns'] ) ) + if ( isset( $assoc_args['skip-columns'] ) ) { $skip_columns = explode( ',', $assoc_args['skip-columns'] ); - else + } else { $skip_columns = array(); + } // never mess with hashed passwords $skip_columns[] = 'user_pass'; @@ -128,8 +129,9 @@ public function __invoke( $args, $assoc_args ) { $table->setRows( $report ); $table->display(); - if ( !$dry_run ) + if ( ! $dry_run ) { WP_CLI::success( "Made $total replacements." ); + } } } From ce2df83279f482a682f9b173a1b3591e4cd8c214 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 13:50:59 -0400 Subject: [PATCH 3446/5359] Update get_table_list to process assoc_args directly --- php/commands/search-replace.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d34c510ff..b8bd7bee8 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -136,11 +136,23 @@ public function __invoke( $args, $assoc_args ) { } } - private static function get_table_list( $args, $network, $all_with_prefix ) { + /** + * Retrieve a list of tables from the database. + * + * @param array $assoc_args Array of options passed to this command. + * + * @return array The array of table names. + */ + private static function get_table_list( $assoc_args ) { global $wpdb; - if ( !empty( $args ) ) - return $args; + $network = \WP_CLI\Utils\flag( $assoc_args, 'network' ); + $all_tables = \WP_CLI\Utils\flag( $assoc_args, 'all-tables' ); + $all_with_prefix = \WP_CLI\Utils\flag( $assoc_args, 'all-tables-with-prefix' ); + + if ( $all_tables ) { + return $wpdb->get_col( 'SHOW TABLES' ); + } $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); From a5ce331223173b84982a9d9937a3a5919b71c6ad Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 13:51:17 -0400 Subject: [PATCH 3447/5359] Use new utility function for flags --- php/commands/search-replace.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b8bd7bee8..86d4bb4de 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -64,10 +64,9 @@ public function __invoke( $args, $assoc_args ) { $new = array_shift( $args ); $total = 0; $report = array(); - $dry_run = isset( $assoc_args['dry-run'] ); - $php_only = isset( $assoc_args['precise'] ); - $recurse_objects = isset( $assoc_args['recurse-objects'] ); - $all_tables = isset( $assoc_args['all-tables'] ); + $dry_run = \WP_CLI\Utils\flag( $assoc_args, 'dry-run' ); + $php_only = \WP_CLI\Utils\flag( $assoc_args, 'precise' ); + $recurse_objects = \WP_CLI\Utils\flag( $assoc_args, 'recurse-objects' ); if ( isset( $assoc_args['skip-columns'] ) ) { $skip_columns = explode( ',', $assoc_args['skip-columns'] ); From 53eec3e5640c79296cb82a0d2f01abd449822db6 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 13:51:38 -0400 Subject: [PATCH 3448/5359] Update call to get_table_list --- php/commands/search-replace.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 86d4bb4de..372312d8b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -77,17 +77,8 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - if ( $all_tables ) { - WP_CLI::confirm( "Will run against ALL tables in the database, not only WordPress tables. Continue?" ); - $tables = $wpdb->get_col( 'SHOW TABLES' ); - } else { - $tables = self::get_table_list( - $args, - isset( $assoc_args['network'] ), - isset( $assoc_args['all-tables-with-prefix'] ) - ); - } - + // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use + $tables = empty( $args ) ? self::get_table_list( $args, $assoc_args ) : $args; foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); From beae4842d3cbad76e5399749136599b141e64394 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 14:00:11 -0400 Subject: [PATCH 3449/5359] Align consecutive assignments --- php/commands/search-replace.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 372312d8b..6035a2cd9 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -60,12 +60,12 @@ class Search_Replace_Command extends WP_CLI_Command { */ public function __invoke( $args, $assoc_args ) { global $wpdb; - $old = array_shift( $args ); - $new = array_shift( $args ); - $total = 0; - $report = array(); - $dry_run = \WP_CLI\Utils\flag( $assoc_args, 'dry-run' ); - $php_only = \WP_CLI\Utils\flag( $assoc_args, 'precise' ); + $old = array_shift( $args ); + $new = array_shift( $args ); + $total = 0; + $report = array(); + $dry_run = \WP_CLI\Utils\flag( $assoc_args, 'dry-run' ); + $php_only = \WP_CLI\Utils\flag( $assoc_args, 'precise' ); $recurse_objects = \WP_CLI\Utils\flag( $assoc_args, 'recurse-objects' ); if ( isset( $assoc_args['skip-columns'] ) ) { From 6741683cc556b04f09b5b1b4623d7f0a7b7214e0 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 14:00:22 -0400 Subject: [PATCH 3450/5359] Add global tag to docblock --- php/commands/search-replace.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 6035a2cd9..fcec22930 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -129,6 +129,8 @@ public function __invoke( $args, $assoc_args ) { /** * Retrieve a list of tables from the database. * + * @global wpdb $wpdb + * * @param array $assoc_args Array of options passed to this command. * * @return array The array of table names. From 968d0acaabe829c316a583e68cae50196682dbc6 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 18:01:46 -0400 Subject: [PATCH 3451/5359] Move helper into class method --- php/commands/search-replace.php | 27 +++++++++++++++++++++------ php/utils.php | 15 --------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index fcec22930..f1da25679 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -64,9 +64,9 @@ public function __invoke( $args, $assoc_args ) { $new = array_shift( $args ); $total = 0; $report = array(); - $dry_run = \WP_CLI\Utils\flag( $assoc_args, 'dry-run' ); - $php_only = \WP_CLI\Utils\flag( $assoc_args, 'precise' ); - $recurse_objects = \WP_CLI\Utils\flag( $assoc_args, 'recurse-objects' ); + $dry_run = self::check_flag( $assoc_args, 'dry-run' ); + $php_only = self::check_flag( $assoc_args, 'precise' ); + $recurse_objects = self::check_flag( $assoc_args, 'recurse-objects' ); if ( isset( $assoc_args['skip-columns'] ) ) { $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -138,9 +138,9 @@ public function __invoke( $args, $assoc_args ) { private static function get_table_list( $assoc_args ) { global $wpdb; - $network = \WP_CLI\Utils\flag( $assoc_args, 'network' ); - $all_tables = \WP_CLI\Utils\flag( $assoc_args, 'all-tables' ); - $all_with_prefix = \WP_CLI\Utils\flag( $assoc_args, 'all-tables-with-prefix' ); + $network = self::check_flag( $assoc_args, 'network' ); + $all_tables = self::check_flag( $assoc_args, 'all-tables' ); + $all_with_prefix = self::check_flag( $assoc_args, 'all-tables-with-prefix' ); if ( $all_tables ) { return $wpdb->get_col( 'SHOW TABLES' ); @@ -290,6 +290,21 @@ private static function esc_like( $old ) { return $old; } + + /** + * Determine the boolean value of a flag in an array. + * + * Primarily useful for determining the status of a boolean flag for a command. This is needed because a flag can be + * prefixed with --no- to set it to false. Therefore it is not sufficient to only check whether a flag is set. + * + * @param array $array The array to check. + * @param string $key The key to check for. + * + * @return bool True if the key is set in the array and is truthy, false otherwise. + */ + private static function check_flag( $array, $key ) { + return isset( $array[ $key ] ) && $array[ $key ]; + } } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); diff --git a/php/utils.php b/php/utils.php index 46143896f..9581c164d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -504,18 +504,3 @@ function increment_version( $current_version, $new_version ) { return $current_version; } - -/** - * Determine the boolean value of a flag in an array. - * - * Primarily useful for determining the status of a boolean flag for a command. This is needed because a flag can be - * prefixed with --no- to set it to false. Therefore it is not sufficient to only check whether a flag is set. - * - * @param array $array The array to check. - * @param string $key The key to check for. - * - * @return bool True if the key is set in the array and is truthy, false otherwise. - */ -function flag( $array, $key ) { - return isset( $array[ $key ] ) && $array[ $key ]; -} From e83c082495f67131577586262dda6aa9f8e5bd61 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Tue, 10 Mar 2015 18:05:34 -0400 Subject: [PATCH 3452/5359] Pass correct arguments to get_table_list --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f1da25679..d9b8e3129 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -78,7 +78,7 @@ public function __invoke( $args, $assoc_args ) { $skip_columns[] = 'user_pass'; // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use - $tables = empty( $args ) ? self::get_table_list( $args, $assoc_args ) : $args; + $tables = empty( $args ) ? self::get_table_list( $assoc_args ) : $args; foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); From 42c9d4a59ec506f09a6c5545e8cacaf85b5c7027 Mon Sep 17 00:00:00 2001 From: Jeremy Pry <jeremy.pry@gmail.com> Date: Wed, 11 Mar 2015 10:47:55 -0400 Subject: [PATCH 3453/5359] Modify get_table_list This method now accepts a string as a parameter, and will function differently depending on which string is passed. --- php/commands/search-replace.php | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d9b8e3129..fe1cd8a22 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -77,8 +77,20 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; + // Determine how to limit the list of tables. Defaults to 'wordpress' + $table_type = 'wordpress'; + if ( self::check_flag( $assoc_args, 'network' ) ) { + $table_type = 'network'; + } + if ( self::check_flag( $assoc_args, 'all-tables-with-prefix' ) ) { + $table_type = 'all-tables-with-prefix'; + } + if ( self::check_flag( $assoc_args, 'all-tables' ) ) { + $table_type = 'all-tables'; + } + // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use - $tables = empty( $args ) ? self::get_table_list( $assoc_args ) : $args; + $tables = empty( $args ) ? self::get_table_list( $table_type ) : $args; foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); @@ -131,25 +143,27 @@ public function __invoke( $args, $assoc_args ) { * * @global wpdb $wpdb * - * @param array $assoc_args Array of options passed to this command. + * @param string $limit_to Sting defining how to limit the list of tables to retrieve. Acceptable vales are: + * - 'wordpress' for default WordPress tables only + * - 'network' for default Multisite tables only + * - 'all-tables-with-prefix' for all tables using the WordPress DB prefix + * - 'all-tables' for all tables in the DB * * @return array The array of table names. */ - private static function get_table_list( $assoc_args ) { + private static function get_table_list( $limit_to ) { global $wpdb; - $network = self::check_flag( $assoc_args, 'network' ); - $all_tables = self::check_flag( $assoc_args, 'all-tables' ); - $all_with_prefix = self::check_flag( $assoc_args, 'all-tables-with-prefix' ); + $network = 'network' == $limit_to; - if ( $all_tables ) { + if ( 'all-tables' == $limit_to ) { return $wpdb->get_col( 'SHOW TABLES' ); } $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); - if ( $all_with_prefix ) { + if ( 'all-tables-with-prefix' == $limit_to ) { return $matching_tables; } From 8e9d127e2feb717cb88b527d0ccfb53a28de8416 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 11 Mar 2015 08:56:14 -0700 Subject: [PATCH 3454/5359] Fix PHP strict standards in importer ``` PHP Strict Standards: Only variables should be passed by reference in /home/vagrant/.wp-cli/php/commands/import.php on line 358 ``` --- php/commands/import.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/import.php b/php/commands/import.php index 58668db4d..d31d36d59 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -355,7 +355,9 @@ private function suggest_user( $author_user_login, $author_user_email = '' ) { $levs[] = levenshtein( $author_user_login, $user->display_name ); $levs[] = levenshtein( $author_user_login, $user->user_login ); $levs[] = levenshtein( $author_user_login, $user->user_email ); - $levs[] = levenshtein( $author_user_login, array_shift( explode( "@", $user->user_email ) ) ); + $email_parts = explode( "@", $user->user_email ); + $email_login = array_shift( $email_parts ); + $levs[] = levenshtein( $author_user_login, $email_login ); rsort( $levs ); $lev = array_pop( $levs ); if ( 0 == $lev ) { From 0434117232844fb352d62092f246edb885ab4dae Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 16:18:41 -0400 Subject: [PATCH 3455/5359] Add test for activate option of scaffold _s subcommand --- features/scaffold.feature | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index cecc11085..4d912e01f 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -39,7 +39,7 @@ Feature: WordPress code scaffolding """ __( 'Zombie speeds', 'zombieland' """ - + @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" When I run `wp scaffold taxonomy zombie-speed --label="Speed"` @@ -220,3 +220,10 @@ Feature: WordPress code scaffolding Success: Created theme 'Starter-theme'. """ And the {THEME_DIR}/starter-theme/sass directory should exist + + Scenario: Scaffold starter code for a theme and activate it + When I run `wp scaffold _s starter-theme --activate` + Then STDOUT should contain: + """ + Switched to 'Starter-theme' theme. + """ From 54694e142e09425efea76e6f98bbadcbc4cb4424 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 17:01:28 -0400 Subject: [PATCH 3456/5359] Add test for activate option of scaffold plugin subcommand --- features/scaffold.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 4d912e01f..cc8be4c13 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -100,6 +100,13 @@ Feature: WordPress code scaffolding And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + Scenario: Scaffold a plugin and activate it + When I run `wp scaffold plugin hello-world --activate` + Then STDOUT should contain: + """ + Plugin 'hello-world' activated. + """ + Scenario: Scaffold plugin tests When I run `wp plugin path` Then save STDOUT as {PLUGIN_DIR} From 49abd64b396341dae60dcc40cd771390384891b5 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 17:04:49 -0400 Subject: [PATCH 3457/5359] Failing test for new scaffold plugin option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let’s make it pass --- features/scaffold.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index cc8be4c13..8650dee10 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -107,6 +107,13 @@ Feature: WordPress code scaffolding Plugin 'hello-world' activated. """ + Scenario: Scaffold a plugin and network activate it + When I run `wp scaffold plugin hello-world --activate-network` + Then STDOUT should contain: + """ + Plugin 'hello-world' network activated. + """ + Scenario: Scaffold plugin tests When I run `wp plugin path` Then save STDOUT as {PLUGIN_DIR} From 797852b6825691850dc378ae6f0a7ca888575152 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 17:43:47 -0400 Subject: [PATCH 3458/5359] Fix tests by removing WP install background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To test multisite, can’t have `Given a WP install` as background --- features/scaffold.feature | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 8650dee10..3a1b446a6 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -1,10 +1,8 @@ Feature: WordPress code scaffolding - Background: - Given a WP install - @theme Scenario: Scaffold a child theme + Given a WP install Given I run `wp theme path` And save STDOUT as {THEME_DIR} @@ -14,6 +12,7 @@ Feature: WordPress code scaffolding @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme + Given a WP install Given I run `wp eval 'echo STYLESHEETPATH;'` And save STDOUT as {STYLESHEETPATH} @@ -26,6 +25,7 @@ Feature: WordPress code scaffolding # Test for all flags but --label, --theme, --plugin and --raw @tax Scenario: Scaffold a Custom Taxonomy and attach it to CPTs including one that is prefixed and has a text domain + Given a WP install When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie,wraith" --textdomain=zombieland` Then STDOUT should contain: """ @@ -42,6 +42,7 @@ Feature: WordPress code scaffolding @tax Scenario: Scaffold a Custom Taxonomy with label "Speed" + Given a WP install When I run `wp scaffold taxonomy zombie-speed --label="Speed"` Then STDOUT should contain: """ @@ -55,6 +56,7 @@ Feature: WordPress code scaffolding # Test for all flags but --label, --theme, --plugin and --raw @cpt Scenario: Scaffold a Custom Post Type + Given a WP install When I run `wp scaffold post-type zombie --textdomain=zombieland` Then STDOUT should contain: """ @@ -70,6 +72,7 @@ Feature: WordPress code scaffolding """ Scenario: CPT slug is too long + Given a WP install When I try `wp scaffold post-type slugiswaytoolonginfact` Then STDERR should be: """ @@ -78,6 +81,7 @@ Feature: WordPress code scaffolding @cpt Scenario: Scaffold a Custom Post Type with label + Given a WP install When I run `wp scaffold post-type zombie --label="Brain eater"` Then STDOUT should contain: """ @@ -85,6 +89,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold a Custom Post Type with dashicon + Given a WP install When I run `wp scaffold post-type zombie --dashicon="art"` Then STDOUT should contain: """ @@ -92,6 +97,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold a plugin + Given a WP install Given I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} @@ -101,6 +107,7 @@ Feature: WordPress code scaffolding And the {PLUGIN_DIR}/hello-world/readme.txt file should exist Scenario: Scaffold a plugin and activate it + Given a WP install When I run `wp scaffold plugin hello-world --activate` Then STDOUT should contain: """ @@ -108,6 +115,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold a plugin and network activate it + Given a WP multisite install When I run `wp scaffold plugin hello-world --activate-network` Then STDOUT should contain: """ @@ -115,6 +123,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold plugin tests + Given a WP install When I run `wp plugin path` Then save STDOUT as {PLUGIN_DIR} @@ -145,6 +154,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold package tests + Given a WP install Given a community-command/command.php file: """ <?php @@ -214,6 +224,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold starter code for a theme + Given a WP install Given I run `wp theme path` And save STDOUT as {THEME_DIR} @@ -225,6 +236,7 @@ Feature: WordPress code scaffolding And the {THEME_DIR}/starter-theme/style.css file should exist Scenario: Scaffold starter code for a theme with sass + Given a WP install Given I run `wp theme path` And save STDOUT as {THEME_DIR} @@ -236,6 +248,7 @@ Feature: WordPress code scaffolding And the {THEME_DIR}/starter-theme/sass directory should exist Scenario: Scaffold starter code for a theme and activate it + Given a WP install When I run `wp scaffold _s starter-theme --activate` Then STDOUT should contain: """ From e77b13d95234b6acf9b49d9fa05240af6470dcc4 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 17:48:25 -0400 Subject: [PATCH 3459/5359] Add activate-network option, fix wp-cli/wp-cli#1709 --- php/commands/scaffold.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a4d239b72..00da18bf3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -419,6 +419,9 @@ public function package_tests( $args, $assoc_args ) { * * [--activate] * : Activate the newly generated plugin. + * + * [--activate-network] + * : Network activate the newly generated plugin. */ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; @@ -447,6 +450,10 @@ function plugin( $args, $assoc_args ) { if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); } + + if ( isset( $assoc_args['activate-network'] ) ) { + WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug), array( 'network' => true ) ); + } } /** From fe04feac18aa6c3880126b329108ac2e8a56af90 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 12 Mar 2015 18:09:10 -0400 Subject: [PATCH 3460/5359] Should be elsif (mutually exclusive options) --- php/commands/scaffold.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 00da18bf3..dffe4c9c6 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -449,9 +449,7 @@ function plugin( $args, $assoc_args ) { if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); - } - - if ( isset( $assoc_args['activate-network'] ) ) { + } else if ( isset( $assoc_args['activate-network'] ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug), array( 'network' => true ) ); } } From d2dafaa00180f1f94bc361862ca3d45da1c03785 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Fri, 13 Mar 2015 12:21:43 -0400 Subject: [PATCH 3461/5359] Add test for scaffold child-theme --enable-network option --- features/scaffold.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 3a1b446a6..221c11bb3 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -10,6 +10,15 @@ Feature: WordPress code scaffolding Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist + Scenario: Scaffold a child theme and network enable it + Given a WP multisite install + + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --enable-network` + Then STDOUT should contain: + """ + Success: Network enabled the 'Zombieland' theme. + """ + @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install From 8556cabcee8c78fb1b6ee7770c3c8e03d52fd6a8 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Fri, 13 Mar 2015 12:22:55 -0400 Subject: [PATCH 3462/5359] Add support for scaffold child-theme --enable-network Tests passing again --- php/commands/scaffold.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index dffe4c9c6..74e7f9ab0 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -263,6 +263,9 @@ function _s( $args, $assoc_args ) { * [--activate] * : Activate the newly created child theme. * + * [--enable-network] + * : Enable the newly created child theme for the entire network. + * * @subcommand child-theme */ function child_theme( $args, $assoc_args ) { @@ -288,8 +291,11 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + } else if ( isset( $assoc_args['enable-network'] ) ) { + WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); + } } private function get_output_path( $assoc_args, $subdir ) { From 681f7be059b2b1e5d2fb5ca57d1d83e78e2bc55e Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Fri, 13 Mar 2015 12:27:06 -0400 Subject: [PATCH 3463/5359] Add test for scaffold _s --enable-network option --- features/scaffold.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 221c11bb3..556b3006f 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -263,3 +263,11 @@ Feature: WordPress code scaffolding """ Switched to 'Starter-theme' theme. """ + + Scenario: Scaffold starter code for a theme and network enable it + Given a WP multisite install + When I run `wp scaffold _s starter-theme --enable-network` + Then STDOUT should contain: + """ + Success: Network enabled the 'Starter-theme' theme. + """ From 508f98393bae5a536146394460dff307d63c1655 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Fri, 13 Mar 2015 14:04:57 -0400 Subject: [PATCH 3464/5359] Add --enable-network option to scaffold _s; fix #1711 --- php/commands/scaffold.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 74e7f9ab0..96e6ed054 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -173,6 +173,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * [--activate] * : Activate the newly downloaded theme. * + * [--enable-network] + * : Enable the newly downloaded theme for the entire network. + * * [--theme_name=<title>] * : What to put in the 'Theme Name:' header in style.css * @@ -232,9 +235,11 @@ function _s( $args, $assoc_args ) { WP_CLI::success( "Created theme '{$data['theme_name']}'." ); - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - + } else if ( isset( $assoc_args['enable-network'] ) ) { + WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); + } } /** From 15812c0b19b1293c58e2c40dbfe06b10f14a1fc0 Mon Sep 17 00:00:00 2001 From: Ross Hattori <rhattori@saymedia.com> Date: Sun, 15 Mar 2015 15:37:45 -0700 Subject: [PATCH 3465/5359] Change the properties for the author names https://github.com/WordPress/WordPress/blob/60b0cd7943b9150b5f69e3ebc9fd06828b9f1e75/wp-admin/includes/export.php#L272-273 --- php/export/class-wp-export-wxr-formatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index 92c15f768..def92ac6e 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -103,8 +103,8 @@ public function authors() { ->tag( 'wp:author_login', $author->user_login ) ->tag( 'wp:author_email', $author->user_email ) ->tag( 'wp:author_display_name' )->contains->cdata( $author->display_name )->end - ->tag( 'wp:author_first_name' )->contains->cdata( $author->user_first_name )->end - ->tag( 'wp:author_last_name' )->contains->cdata( $author->user_last_name )->end + ->tag( 'wp:author_first_name' )->contains->cdata( $author->user_firstname )->end + ->tag( 'wp:author_last_name' )->contains->cdata( $author->user_lastname )->end ->end; } return $oxymel->to_string(); From 8ab0c30a06fca35cb929d4110c52b6ecc3333b63 Mon Sep 17 00:00:00 2001 From: Ross Hattori <rhattori@saymedia.com> Date: Sun, 15 Mar 2015 15:51:53 -0700 Subject: [PATCH 3466/5359] Add wp:author_id tag to author export --- php/export/class-wp-export-wxr-formatter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index def92ac6e..d2bc4d5af 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -100,6 +100,7 @@ public function authors() { foreach ( $authors as $author ) { $oxymel ->tag( 'wp:wp_author' )->contains + ->tag( 'wp:author_id', $author->ID ) ->tag( 'wp:author_login', $author->user_login ) ->tag( 'wp:author_email', $author->user_email ) ->tag( 'wp:author_display_name' )->contains->cdata( $author->display_name )->end From d3ddd49abc105b76eae45913da2ea78c6d1f282c Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Mon, 16 Mar 2015 11:41:19 -0400 Subject: [PATCH 3467/5359] Revert fe04fea..508f983 This rolls back to commit fe04feac18aa6c3880126b329108ac2e8a56af90. --- features/scaffold.feature | 17 ----------------- php/commands/scaffold.php | 17 +++-------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 556b3006f..3a1b446a6 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -10,15 +10,6 @@ Feature: WordPress code scaffolding Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist - Scenario: Scaffold a child theme and network enable it - Given a WP multisite install - - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --enable-network` - Then STDOUT should contain: - """ - Success: Network enabled the 'Zombieland' theme. - """ - @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install @@ -263,11 +254,3 @@ Feature: WordPress code scaffolding """ Switched to 'Starter-theme' theme. """ - - Scenario: Scaffold starter code for a theme and network enable it - Given a WP multisite install - When I run `wp scaffold _s starter-theme --enable-network` - Then STDOUT should contain: - """ - Success: Network enabled the 'Starter-theme' theme. - """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 96e6ed054..dffe4c9c6 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -173,9 +173,6 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * [--activate] * : Activate the newly downloaded theme. * - * [--enable-network] - * : Enable the newly downloaded theme for the entire network. - * * [--theme_name=<title>] * : What to put in the 'Theme Name:' header in style.css * @@ -235,11 +232,9 @@ function _s( $args, $assoc_args ) { WP_CLI::success( "Created theme '{$data['theme_name']}'." ); - if ( isset( $assoc_args['activate'] ) ) { + if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( isset( $assoc_args['enable-network'] ) ) { - WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); - } + } /** @@ -268,9 +263,6 @@ function _s( $args, $assoc_args ) { * [--activate] * : Activate the newly created child theme. * - * [--enable-network] - * : Enable the newly created child theme for the entire network. - * * @subcommand child-theme */ function child_theme( $args, $assoc_args ) { @@ -296,11 +288,8 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) { + if ( isset( $assoc_args['activate'] ) ) WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( isset( $assoc_args['enable-network'] ) ) { - WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); - } } private function get_output_path( $assoc_args, $subdir ) { From d7f19908f6268f2358ec6e9ea3ff5d515b98b434 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 16 Mar 2015 15:23:11 -0300 Subject: [PATCH 3468/5359] fix author's xml node name --- php/export/class-wp-export-wxr-formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-wxr-formatter.php b/php/export/class-wp-export-wxr-formatter.php index d2bc4d5af..ca874c6ff 100644 --- a/php/export/class-wp-export-wxr-formatter.php +++ b/php/export/class-wp-export-wxr-formatter.php @@ -99,7 +99,7 @@ public function authors() { $authors = $this->export->authors(); foreach ( $authors as $author ) { $oxymel - ->tag( 'wp:wp_author' )->contains + ->tag( 'wp:author' )->contains ->tag( 'wp:author_id', $author->ID ) ->tag( 'wp:author_login', $author->user_login ) ->tag( 'wp:author_email', $author->user_email ) From 5bbfe9eeff4e954f6b644297d9dc8bb0b2abef36 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 17 Mar 2015 12:11:42 -0300 Subject: [PATCH 3469/5359] add test to make sure that the users information is exported correctly --- features/export.feature | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/features/export.feature b/features/export.feature index ae0281bd4..ddc1626f7 100644 --- a/features/export.feature +++ b/features/export.feature @@ -201,3 +201,29 @@ Feature: Export content. """ 5 """ + + Scenario: Export posts should include user information + Given a WP install + And I run `wp plugin install wordpress-importer --activate` + And I run `wp user create user user@user.com --role=editor --display_name="Test User"` + And I run `wp post generate --post_type=post --count=10 --post_author=user` + + When I run `wp export` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + Then the {EXPORT_FILE} file should contain: + """ + <wp:author_display_name><![CDATA[Test User]]></wp:author_display_name> + """ + + When I run `wp site empty --yes` + And I run `wp user list --field=user_login | xargs -n 1 wp user delete --yes` + Then STDOUT should not be empty + + When I run `wp import {EXPORT_FILE} --authors=create` + Then STDOUT should not be empty + + When I run `wp user get user --field=display_name` + Then STDOUT should be: + """ + Test User + """ \ No newline at end of file From 2e2547f162e66ae7efbd017c4d108330f5e15df6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 17 Mar 2015 12:20:24 -0300 Subject: [PATCH 3470/5359] add missing line to the end of the file --- features/export.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/export.feature b/features/export.feature index ddc1626f7..f7be508ce 100644 --- a/features/export.feature +++ b/features/export.feature @@ -226,4 +226,4 @@ Feature: Export content. Then STDOUT should be: """ Test User - """ \ No newline at end of file + """ From a3a6adea68a07a4d01454a0768d96ff31e99ff7b Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Tue, 17 Mar 2015 20:22:24 -0400 Subject: [PATCH 3471/5359] Consistent functional test assertions for scaffold command --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 3a1b446a6..e1f48aee1 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -252,5 +252,5 @@ Feature: WordPress code scaffolding When I run `wp scaffold _s starter-theme --activate` Then STDOUT should contain: """ - Switched to 'Starter-theme' theme. + Success: Switched to 'Starter-theme' theme. """ From 399589c067a16438f7ef795dd2499f6e08f6c0b4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 25 Mar 2015 14:30:42 -0300 Subject: [PATCH 3472/5359] add `--format=ids` to `wp post term list` --- features/post-term.feature | 6 ++++++ features/user-term.feature | 6 ++++++ php/WP_CLI/CommandWithTerms.php | 9 +++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/features/post-term.feature b/features/post-term.feature index d38f628c2..94893c427 100644 --- a/features/post-term.feature +++ b/features/post-term.feature @@ -26,6 +26,12 @@ Feature: Manage post term | foo | foo | category | | bar | bar | category | + When I run `wp post term list 1 category --format=ids` + Then STDOUT should be: + """ + 3 2 1 + """ + When I try `wp post term list 1 foo2` Then STDERR should be: """ diff --git a/features/user-term.feature b/features/user-term.feature index 0c83e2f7a..c5c81939c 100644 --- a/features/user-term.feature +++ b/features/user-term.feature @@ -39,6 +39,12 @@ Feature: Manage user term | foo | foo | user_type | | bar | bar | user_type | + When I run `wp user term list 1 user_type --format=ids` + Then STDOUT should be: + """ + 3 2 + """ + When I run `wp user term set 1 user_type new` Then STDOUT should be: """ diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index 277fe4aed..f906f7b3c 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -44,7 +44,7 @@ abstract class CommandWithTerms extends \WP_CLI_Command { * : Limit the output to specific row fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, ids. Default: table * * ## AVAILABLE FIELDS * @@ -69,6 +69,7 @@ public function list_( $args, $assoc_args ) { $object_id = array_shift( $args ); $taxonomy_names = $args; + $taxonomy_args = array(); $this->set_obj_id( $object_id ); @@ -76,7 +77,11 @@ public function list_( $args, $assoc_args ) { $this->taxonomy_exists( $taxonomy ); } - $items = wp_get_object_terms( $object_id, $taxonomy_names ); + if ( $assoc_args['format'] == 'ids' ) { + $taxonomy_args['fields'] = 'ids'; + } + + $items = wp_get_object_terms( $object_id, $taxonomy_names, $taxonomy_args ); $formatter = $this->get_formatter( $assoc_args ); $formatter->display_items( $items ); From 3dc3421c98ce3380fc4d6628dfa0d0fca349e9fe Mon Sep 17 00:00:00 2001 From: Morgan Estes <morgan.estes@gmail.com> Date: Wed, 25 Mar 2015 14:16:27 -0500 Subject: [PATCH 3473/5359] Switch from rhumsaa/array_column to ramsey/array_column, as the former isn't supported anymore. --- composer.json | 2 +- utils/make-phar.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 6b17472c7..6cec94c7d 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "0.10.4", "mustache/mustache": "~2.4", - "rhumsaa/array_column": "~1.1", + "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", "symfony/finder": "~2.3", "nb/oxymel": "0.1.0" diff --git a/utils/make-phar.php b/utils/make-phar.php index 1ce6f7b87..69ae514ff 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -69,7 +69,7 @@ function set_file_contents( $phar, $path, $content ) { ->in('./vendor/composer') ->in('./vendor/symfony/finder') ->in('./vendor/nb/oxymel') - ->in('./vendor/rhumsaa/array_column') + ->in('./vendor/ramsey/array_column') ->exclude('test') ->exclude('tests') ->exclude('Tests') From 5195b2319dc5e746d4a5d47b73fe034d349d4457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Sat, 28 Mar 2015 18:41:33 -0400 Subject: [PATCH 3474/5359] Add `wp core language update` command and Behat tests --- features/core.feature | 11 ++++ php/WP_CLI/CommandWithTranslation.php | 89 +++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/features/core.feature b/features/core.feature index 636989d60..60ef63791 100644 --- a/features/core.feature +++ b/features/core.feature @@ -505,6 +505,17 @@ Feature: Manage WordPress installation Success: Language activated. """ + When I run `wp core language update --dry-run` + Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} + + When I run `wp core language update` + Then STDOUT should contain: + """ + Success: Updated {UPDATES}/{UPDATES} translations. + """ + And the wp-content/languages/plugins directory should exist + And the wp-content/languages/themes directory should exist + When I run `wp core language list --field=language --status=active` Then STDOUT should be: """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 06aa8c6ab..761b07b64 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -124,6 +124,95 @@ public function install( $args, $assoc_args ) { } + /** + * Updates the active translation of core, plugins, and themes. + * + * [--dry-run] + * : Preview which translations would be updated. + * + * @subcommand update + */ + public function update( $args, $assoc_args ) { + + // Ignore updates for the default locale. + if ( 'en_US' == get_locale() ) { + \WP_CLI::line( "Translations updates are not needed for the default locale." ); + + return; + } + + wp_version_check(); // Check for Core updates. + wp_update_themes(); // Check for Theme updates. + wp_update_plugins(); // Check for Plugin updates. + + $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. + + if ( empty( $updates ) ) { + \WP_CLI::line( "No translations updates available." ); + + return; + } + + // Gets a list of all languages. + $all_languages = $this->get_all_languages(); + + // Formats the updates list. + foreach ( $updates as $update ) { + if ( 'plugin' == $update->type ) { + $plugin_data = array_shift( get_plugins( '/' . $update->slug ) ); + $name = $plugin_data['Name']; + } elseif ( 'theme' == $update->type ) { + $theme_data = wp_get_theme( $update->slug ); + $name = $theme_data['Name']; + } else { // Core + $name = 'WordPress'; + } + + // Gets the translation data. + $translation = (object) reset( wp_list_filter( $all_languages, array( + 'language' => $update->language + ) ) ); + + $update->Type = ucfirst( $update->type ); + $update->Name = $name; + $update->Version = $update->version; + $update->Language = $translation->english_name; + } + + // Only preview which translations would be updated. + if ( isset( $assoc_args['dry-run'] ) ) { + \WP_CLI::line( sprintf( 'Available %d translations updates:', count( $updates ) ) ); + \WP_CLI\Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); + + return; + } + + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + + $upgrader = new \Language_Pack_Upgrader( new \Automatic_Upgrader_Skin() ); + $results = array(); + + // Update translations. + foreach ( $updates as $update ) { + \WP_CLI::line( "Updating '{$update->Language}' translations for {$update->Name} {$update->Version}..." ); + $results[] = $upgrader->upgrade( $update ); + } + + $num_to_update = count( $updates ); + $num_updated = count( array_filter( $results ) ); + + $line = "Updated $num_updated/$num_to_update translations."; + + if ( $num_to_update == $num_updated ) { + \WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + \WP_CLI::warning( $line ); + } else { + \WP_CLI::error( $line ); + } + + } + /** * Activate a given language. * From eb55b068bfdae9a19d2c1cde4d60b341f26f6e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Sat, 28 Mar 2015 22:21:39 -0400 Subject: [PATCH 3475/5359] Fix `wp core language update` to check 'dry-run' arg value --- php/WP_CLI/CommandWithTranslation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 761b07b64..0169e0760 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -180,7 +180,7 @@ public function update( $args, $assoc_args ) { } // Only preview which translations would be updated. - if ( isset( $assoc_args['dry-run'] ) ) { + if ( isset( $assoc_args['dry-run'] ) && $assoc_args['dry-run'] ) { \WP_CLI::line( sprintf( 'Available %d translations updates:', count( $updates ) ) ); \WP_CLI\Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); From 5402ea90ad08dddaf80f1bc706b354766ea69b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Sat, 28 Mar 2015 23:29:09 -0400 Subject: [PATCH 3476/5359] Add `WP_CLI::check_flag` function Function to check if a command flag is set and has the expected value. --- php/class-wp-cli.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f571c47a5..9e4e7ef9a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -465,6 +465,18 @@ public static function run_command( $args, $assoc_args = array() ) { self::get_runner()->run_command( $args, $assoc_args ); } + /** + * Check if the flag is set and has the expected value. + * + * @param array $args The arguments array to check. + * @param string $flag The flag to check for. + * @param mixed $expected The expected value for the flag. Default: TRUE + * @return bool + */ + public static function check_flag( $args, $flag, $expected = true ) { + return isset( $args[ $flag ] ) && $args[ $flag ] == $expected; + } + // DEPRECATED STUFF From 61681173caa558dc530ea886ed4d5c54258bc8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 30 Mar 2015 14:32:29 -0400 Subject: [PATCH 3477/5359] Improves `wp core language update` messages --- php/WP_CLI/CommandWithTranslation.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 0169e0760..cdcc4a5e8 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -136,7 +136,7 @@ public function update( $args, $assoc_args ) { // Ignore updates for the default locale. if ( 'en_US' == get_locale() ) { - \WP_CLI::line( "Translations updates are not needed for the default locale." ); + \WP_CLI::success( "Translations updates are not needed for the 'English (US)' locale." ); return; } @@ -148,7 +148,7 @@ public function update( $args, $assoc_args ) { $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. if ( empty( $updates ) ) { - \WP_CLI::line( "No translations updates available." ); + \WP_CLI::success( 'Translations are up to date.' ); return; } @@ -194,8 +194,18 @@ public function update( $args, $assoc_args ) { // Update translations. foreach ( $updates as $update ) { - \WP_CLI::line( "Updating '{$update->Language}' translations for {$update->Name} {$update->Version}..." ); - $results[] = $upgrader->upgrade( $update ); + \WP_CLI::line( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); + \WP_CLI::line( "Downloading translation from {$update->package}..." ); + + $result = $upgrader->upgrade( $update ); + + if ( $result ) { + \WP_CLI::line( 'Translation updated successfully.' ); + } else { + \WP_CLI::line( 'Translation update failed.' ); + } + + $results[] = $result; } $num_to_update = count( $updates ); From fda3162469711b3048df6e7cb9b93bd78e3fb727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 30 Mar 2015 17:30:40 -0400 Subject: [PATCH 3478/5359] Indicates whether there is a new version in `wp core language list` --- php/WP_CLI/CommandWithTranslation.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index cdcc4a5e8..e9deb9103 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -16,7 +16,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { 'english_name', 'native_name', 'status', - 'updated', + 'update', ); /** @@ -42,7 +42,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { * * english_name * * native_name * * status - * * updated + * * update * * These fields are optionally available: * @@ -56,12 +56,27 @@ public function list_( $args, $assoc_args ) { $translations = $this->get_all_languages(); $available = $this->get_installed_languages(); + wp_version_check(); // Check for Core updates. + wp_update_themes(); // Check for Theme updates. + wp_update_plugins(); // Check for Plugin updates. + $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. + $current_locale = get_locale(); - $translations = array_map( function( $translation ) use ( $available, $current_locale ) { + $translations = array_map( function( $translation ) use ( $available, $current_locale, $updates ) { $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; if ( $current_locale == $translation['language'] ) { $translation['status'] = 'active'; } + + $update = wp_list_filter( $updates, array( + 'language' => $translation['language'] + ) ); + if ( $update ) { + $translation['update'] = 'available'; + } else { + $translation['update'] = 'none'; + } + return $translation; }, $translations ); From 751003ae8e4f7a37f94a22bc04897ed1d0daa182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 30 Mar 2015 18:19:35 -0400 Subject: [PATCH 3479/5359] Add `--force` flag to `wp core language update` command --- features/core.feature | 2 +- php/WP_CLI/CommandWithTranslation.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 60ef63791..86d0eab36 100644 --- a/features/core.feature +++ b/features/core.feature @@ -505,7 +505,7 @@ Feature: Manage WordPress installation Success: Language activated. """ - When I run `wp core language update --dry-run` + When I run `wp core language update --dry-run --force` Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} When I run `wp core language update` diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index e9deb9103..14b8fc029 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -145,6 +145,9 @@ public function install( $args, $assoc_args ) { * [--dry-run] * : Preview which translations would be updated. * + * [--force] + * : Force the check for updates. + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -156,6 +159,10 @@ public function update( $args, $assoc_args ) { return; } + if ( isset( $assoc_args['force'] ) && $assoc_args['force'] ) { + wp_clean_update_cache(); // Clear existing update caches. + } + wp_version_check(); // Check for Core updates. wp_update_themes(); // Check for Theme updates. wp_update_plugins(); // Check for Plugin updates. From 921c6572c447995dcd707e5d19899a99cf6adeae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 30 Mar 2015 18:32:50 -0400 Subject: [PATCH 3480/5359] Do not check for translations updates after updating plugins/themes --- php/WP_CLI/CommandWithUpgrade.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 39da96241..b4c505ec4 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -10,6 +10,13 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $upgrade_refresh; protected $upgrade_transient; + function __construct() { + // Do not automatically check translations updates after updating plugins/themes. + add_action( 'upgrader_process_complete', function() { + remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); + }, 1 ); + } + abstract protected function get_upgrader_class( $force ); abstract protected function get_item_list(); From 8fdeea3d1e311bc4f26848e971d545d2359d53a9 Mon Sep 17 00:00:00 2001 From: Brian MacKinney <brian@getpantheon.com> Date: Thu, 2 Apr 2015 11:40:48 -0700 Subject: [PATCH 3481/5359] Correctly enqueue parent and child themes Completes #1706 --- templates/child_theme_functions.mustache | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index c8f541767..09c74101e 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -1,7 +1,12 @@ <?php -add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' ); +add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' ); -function {{parent_theme}}_parent_theme_enqueue_styles() { +function theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); + wp_enqueue_style( '{{slug}}-style', + get_stylesheet_directory_uri() . '/style.css', + array('{{parent_theme}}-style') + ); + } From b959d55f56b7221d7c96fdfac065a9fdf06b34cd Mon Sep 17 00:00:00 2001 From: Brian MacKinney <brian@getpantheon.com> Date: Thu, 2 Apr 2015 14:52:54 -0700 Subject: [PATCH 3482/5359] Revert function name change {{parent_theme}}_parent_theme_enque_styles matches wp-cli function naming conventions. --- templates/child_theme_functions.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index 09c74101e..1c0809939 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -1,8 +1,8 @@ <?php -add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' ); +add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' ); -function theme_enqueue_styles() { +function {{parent_theme}}_parent_theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); wp_enqueue_style( '{{slug}}-style', get_stylesheet_directory_uri() . '/style.css', From 7788937a750b0cd023d9e65290ca344057232535 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 2 Apr 2015 20:41:53 -0400 Subject: [PATCH 3483/5359] Add test for scaffold child-theme --enable-network --- features/scaffold.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index e1f48aee1..eb6e50958 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -10,6 +10,15 @@ Feature: WordPress code scaffolding Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist + Scenario: Scaffold a child theme and network enable it + Given a WP multisite install + + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --enable-network` + Then STDOUT should contain: + """ + Success: Network enabled the 'Zombieland' theme. + """ + @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install From 4c4654bbb66b1a460b32fbed58e388bcbfef1901 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 2 Apr 2015 20:42:06 -0400 Subject: [PATCH 3484/5359] Add test for scaffold _s --enable-network --- features/scaffold.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index eb6e50958..ba218c24a 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -263,3 +263,11 @@ Feature: WordPress code scaffolding """ Success: Switched to 'Starter-theme' theme. """ + + Scenario: Scaffold starter code for a theme and network enable it + Given a WP multisite install + When I run `wp scaffold _s starter-theme --enable-network` + Then STDOUT should contain: + """ + Success: Network enabled the 'Starter-theme' theme. + """ From be859e3530032dfac45441ae5280b8453902a6a5 Mon Sep 17 00:00:00 2001 From: Andrew Patton <andrew@acusti.ca> Date: Thu, 2 Apr 2015 20:44:50 -0400 Subject: [PATCH 3485/5359] Add --enable-network for scaffold theme commands, fix #1711 --- php/commands/scaffold.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index dffe4c9c6..96e6ed054 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -173,6 +173,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * [--activate] * : Activate the newly downloaded theme. * + * [--enable-network] + * : Enable the newly downloaded theme for the entire network. + * * [--theme_name=<title>] * : What to put in the 'Theme Name:' header in style.css * @@ -232,9 +235,11 @@ function _s( $args, $assoc_args ) { WP_CLI::success( "Created theme '{$data['theme_name']}'." ); - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - + } else if ( isset( $assoc_args['enable-network'] ) ) { + WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); + } } /** @@ -263,6 +268,9 @@ function _s( $args, $assoc_args ) { * [--activate] * : Activate the newly created child theme. * + * [--enable-network] + * : Enable the newly created child theme for the entire network. + * * @subcommand child-theme */ function child_theme( $args, $assoc_args ) { @@ -288,8 +296,11 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) + if ( isset( $assoc_args['activate'] ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); + } else if ( isset( $assoc_args['enable-network'] ) ) { + WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); + } } private function get_output_path( $assoc_args, $subdir ) { From 19515799b5785054f2e283534c28055015e14e60 Mon Sep 17 00:00:00 2001 From: yivi <ivan@yivoff.com> Date: Sat, 4 Apr 2015 11:44:34 +0200 Subject: [PATCH 3486/5359] functional test: _s scaffolding check for failure when wp_content_dir it's not set properly --- features/scaffold.feature | 9 +++++++++ features/steps/given.php | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index e1f48aee1..bc5cbc1ae 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -254,3 +254,12 @@ Feature: WordPress code scaffolding """ Success: Switched to 'Starter-theme' theme. """ + + Scenario: Scaffold starter code for a theme, but can't unzip theme files + Given a WP install + And a misconfigured WP_CONTENT_DIR constant directory + When I try `wp scaffold _s starter-theme` + Then STDERR should contain: + """ + Error: Could not decompress your theme files + """ diff --git a/features/steps/given.php b/features/steps/given.php index a9f536a7c..0d6509876 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -140,4 +140,17 @@ function ( $world, $filepath, $output_filter, $key ) { } $world->variables[ $key ] = trim( $output, "\n" ); } +); + +$steps->Given('/^a misconfigured WP_CONTENT_DIR constant directory$/', + function($world) { + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', '' );" ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } ); \ No newline at end of file From 911c494fb975a7c3823847f58c380f91a766f989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 01:00:59 -0400 Subject: [PATCH 3487/5359] Clear update caches by default when checking for updates in `wp core language` --- php/WP_CLI/CommandWithTranslation.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 14b8fc029..3dd0a93a0 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -56,6 +56,7 @@ public function list_( $args, $assoc_args ) { $translations = $this->get_all_languages(); $available = $this->get_installed_languages(); + wp_clean_update_cache(); // Clear existing update caches. wp_version_check(); // Check for Core updates. wp_update_themes(); // Check for Theme updates. wp_update_plugins(); // Check for Plugin updates. @@ -145,9 +146,6 @@ public function install( $args, $assoc_args ) { * [--dry-run] * : Preview which translations would be updated. * - * [--force] - * : Force the check for updates. - * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -159,10 +157,7 @@ public function update( $args, $assoc_args ) { return; } - if ( isset( $assoc_args['force'] ) && $assoc_args['force'] ) { - wp_clean_update_cache(); // Clear existing update caches. - } - + wp_clean_update_cache(); // Clear existing update caches. wp_version_check(); // Check for Core updates. wp_update_themes(); // Check for Theme updates. wp_update_plugins(); // Check for Plugin updates. From 4d8fb256b3bc9eb7416845a2bd569180a938ba6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 01:04:22 -0400 Subject: [PATCH 3488/5359] Run the `wp core language update` command after updating plugin/themes Instead of running the default translations updates from WordPress, which returns HTML tags to the standard output, runs the command `wp core language update` after updating plugin or themes. --- php/WP_CLI/CommandWithUpgrade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b4c505ec4..9f57669f8 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -11,9 +11,10 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $upgrade_transient; function __construct() { - // Do not automatically check translations updates after updating plugins/themes. + // After updating plugins/themes also update translations by running the `core language update` command. add_action( 'upgrader_process_complete', function() { remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); + \WP_CLI::run_command( array( 'core', 'language', 'update' ), array( 'dry-run' => false ) ); }, 1 ); } From 58dcb46c8899ea5aa9664a389dd84b19d13e036d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 01:21:43 -0400 Subject: [PATCH 3489/5359] Adds back the 'updated' column to the `wp core language list` command --- php/WP_CLI/CommandWithTranslation.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 3dd0a93a0..8bed161ac 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -17,6 +17,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { 'native_name', 'status', 'update', + 'updated', ); /** @@ -43,6 +44,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { * * native_name * * status * * update + * * updated * * These fields are optionally available: * From 6757d94f3662755b11b458bb09beddc3718a61ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 02:12:53 -0400 Subject: [PATCH 3490/5359] Fix `wp core language update` Behat tests --- features/core.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 86d0eab36..60ef63791 100644 --- a/features/core.feature +++ b/features/core.feature @@ -505,7 +505,7 @@ Feature: Manage WordPress installation Success: Language activated. """ - When I run `wp core language update --dry-run --force` + When I run `wp core language update --dry-run` Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} When I run `wp core language update` From 6b95e929a009324c20ccf3fa8d961e72e8131864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 15:40:21 -0400 Subject: [PATCH 3491/5359] Add Behat tests for the `update` field in `wp core language list` --- features/core.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/core.feature b/features/core.feature index 60ef63791..779b83501 100644 --- a/features/core.feature +++ b/features/core.feature @@ -505,6 +505,14 @@ Feature: Manage WordPress installation Success: Language activated. """ + When I run `wp core language list --fields=language,english_name,update` + Then STDOUT should be a table containing rows: + | language | english_name | update | + | ar | Arabic | none | + | az | Azerbaijani | none | + | en_US | English (United States) | none | + | en_GB | English (UK) | available | + When I run `wp core language update --dry-run` Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} From 89a9cc46a64098a2a053a3e48c39971ab1ef6d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 16:54:17 -0400 Subject: [PATCH 3492/5359] Changes `\WP_CLI::check_flag` function to `\WP_CLI\Utils\check_flag` --- php/class-wp-cli.php | 12 ------------ php/utils.php | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9e4e7ef9a..f571c47a5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -465,18 +465,6 @@ public static function run_command( $args, $assoc_args = array() ) { self::get_runner()->run_command( $args, $assoc_args ); } - /** - * Check if the flag is set and has the expected value. - * - * @param array $args The arguments array to check. - * @param string $flag The flag to check for. - * @param mixed $expected The expected value for the flag. Default: TRUE - * @return bool - */ - public static function check_flag( $args, $flag, $expected = true ) { - return isset( $args[ $flag ] ) && $args[ $flag ] == $expected; - } - // DEPRECATED STUFF diff --git a/php/utils.php b/php/utils.php index 9581c164d..45b36ee99 100644 --- a/php/utils.php +++ b/php/utils.php @@ -504,3 +504,15 @@ function increment_version( $current_version, $new_version ) { return $current_version; } + +/** + * Check if the flag is set and has the expected value. + * + * @param array $args The arguments array to check. + * @param string $flag The flag to check for. + * @param mixed $expected The expected value for the flag. Default: TRUE + * @return bool + */ +function check_flag( $args, $flag, $expected = true ) { + return isset( $args[ $flag ] ) && ( $args[ $flag ] === $expected ); +} From 4b5f91353d0167a12e79bd646336d05120bf5e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 6 Apr 2015 19:46:15 -0400 Subject: [PATCH 3493/5359] Small fix in comments --- php/WP_CLI/CommandWithTranslation.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 8bed161ac..507c4dd52 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -59,9 +59,9 @@ public function list_( $args, $assoc_args ) { $available = $this->get_installed_languages(); wp_clean_update_cache(); // Clear existing update caches. - wp_version_check(); // Check for Core updates. - wp_update_themes(); // Check for Theme updates. - wp_update_plugins(); // Check for Plugin updates. + wp_version_check(); // Check for Core translation updates. + wp_update_themes(); // Check for Theme translation updates. + wp_update_plugins(); // Check for Plugin translation updates. $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. $current_locale = get_locale(); @@ -160,9 +160,9 @@ public function update( $args, $assoc_args ) { } wp_clean_update_cache(); // Clear existing update caches. - wp_version_check(); // Check for Core updates. - wp_update_themes(); // Check for Theme updates. - wp_update_plugins(); // Check for Plugin updates. + wp_version_check(); // Check for Core translation updates. + wp_update_themes(); // Check for Theme translation updates. + wp_update_plugins(); // Check for Plugin translation updates. $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. From 83a0bc471e5f4172703eaef3b85992caaf3f87ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 13 Apr 2015 00:10:25 -0400 Subject: [PATCH 3494/5359] Refactor code to use the `\WP_CLI\Utils\check_flag` function --- php/WP_CLI/CommandWithDBObject.php | 2 +- php/WP_CLI/CommandWithTranslation.php | 4 ++-- php/WP_CLI/CommandWithUpgrade.php | 12 ++++++------ php/class-wp-cli.php | 6 +++--- php/commands/cli.php | 10 +++++----- php/commands/comment.php | 2 +- php/commands/core.php | 20 ++++++++++---------- php/commands/media.php | 6 +++--- php/commands/menu.php | 2 +- php/commands/option.php | 6 +++--- php/commands/plugin.php | 20 ++++++++++---------- php/commands/post.php | 4 ++-- php/commands/rewrite.php | 6 +++--- php/commands/role.php | 4 ++-- php/commands/scaffold.php | 16 ++++++++-------- php/commands/search-replace.php | 26 ++++++-------------------- php/commands/shell.php | 2 +- php/commands/site.php | 6 +++--- php/commands/term.php | 8 ++------ php/commands/theme.php | 14 +++++++------- php/commands/user.php | 12 ++++++------ 21 files changed, 85 insertions(+), 103 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 8a52bfc92..dcd2be9b4 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -41,7 +41,7 @@ protected function _create( $args, $assoc_args, $callback ) { \WP_CLI::error( $obj_id ); } - if ( isset( $assoc_args['porcelain'] ) ) + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) \WP_CLI::line( $obj_id ); else \WP_CLI::success( "Created $this->obj_type $obj_id." ); diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 507c4dd52..c78b326c4 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -133,7 +133,7 @@ public function install( $args, $assoc_args ) { if ( $response == $language_code ) { \WP_CLI::success( "Language installed." ); - if ( isset( $assoc_args['activate'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { $this->activate( array( $language_code ), array() ); } } else { @@ -199,7 +199,7 @@ public function update( $args, $assoc_args ) { } // Only preview which translations would be updated. - if ( isset( $assoc_args['dry-run'] ) && $assoc_args['dry-run'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ) ) { \WP_CLI::line( sprintf( 'Available %d translations updates:', count( $updates ) ) ); \WP_CLI\Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9f57669f8..0b3c592ce 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -150,12 +150,12 @@ function install( $args, $assoc_args ) { } if ( $result ) { - if ( isset( $assoc_args['activate-network'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate-network' ) ) { \WP_CLI::log( "Network-activating '$slug'..." ); $this->activate( array( $slug ), array( 'network' => true ) ); } - if ( isset( $assoc_args['activate'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } @@ -203,20 +203,20 @@ protected static function alter_api_response( $response, $version ) { } protected function get_upgrader( $assoc_args ) { - $upgrader_class = $this->get_upgrader_class( isset( $assoc_args['force'] ) ); + $upgrader_class = $this->get_upgrader_class( \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ); return \WP_CLI\Utils\get_upgrader( $upgrader_class ); } protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); - if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { \WP_CLI::error( "Please specify one or more {$this->item_type}s, or use --all." ); } $items = $this->get_item_list(); - if ( !isset( $assoc_args['all'] ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { $items = $this->filter_item_list( $items, $args ); } @@ -224,7 +224,7 @@ protected function update_many( $args, $assoc_args ) { 'update' => true ) ); - if ( isset( $assoc_args['dry-run'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ) ) { if ( empty( $items_to_update ) ) { \WP_CLI::line( "No {$this->item_type} updates available." ); return; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f571c47a5..897781a49 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -274,7 +274,7 @@ public static function error_multi_line( $message_lines ) { * Ask for confirmation before running a destructive operation. */ public static function confirm( $question, $assoc_args = array() ) { - if ( !isset( $assoc_args['yes'] ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'yes' ) ) { fwrite( STDOUT, $question . " [y/n] " ); $answer = trim( fgets( STDIN ) ); @@ -314,7 +314,7 @@ public static function get_value_from_arg_or_stdin( $args, $index ) { * @param array $assoc_args */ public static function read_value( $raw_value, $assoc_args = array() ) { - if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { $value = json_decode( $raw_value, true ); if ( null === $value ) { WP_CLI::error( sprintf( 'Invalid JSON: %s', $raw_value ) ); @@ -333,7 +333,7 @@ public static function read_value( $raw_value, $assoc_args = array() ) { * @param array $assoc_args */ public static function print_value( $value, $assoc_args = array() ) { - if ( isset( $assoc_args['format'] ) && 'json' == $assoc_args['format'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { $value = json_encode( $value ); } elseif ( is_array( $value ) || is_object( $value ) ) { $value = var_export( $value ); diff --git a/php/commands/cli.php b/php/commands/cli.php index 29239088d..e1355bdf5 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -48,7 +48,7 @@ public function info( $_, $assoc_args ) { $runner = WP_CLI::get_runner(); - if ( isset( $assoc_args['format'] ) && 'json' === $assoc_args['format'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { $info = array( 'php_binary_path' => $php_bin, 'global_config_path' => $runner->global_config_path, @@ -237,10 +237,10 @@ private function get_updates( $assoc_args ) { $update_type = 'patch'; } - if ( ! ( isset( $assoc_args['patch'] ) && $assoc_args['patch'] && 'patch' !== $update_type ) - && ! ( isset( $assoc_args['patch'] ) && ! $assoc_args['patch'] && 'patch' === $update_type ) - && ! ( isset( $assoc_args['minor'] ) && $assoc_args['minor'] && 'minor' !== $update_type ) - && ! ( isset( $assoc_args['minor'] ) && ! $assoc_args['minor'] && 'minor' === $update_type ) + if ( ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'patch' ) && 'patch' !== $update_type ) + && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'patch', false ) && 'patch' === $update_type ) + && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor' ) && 'minor' !== $update_type ) + && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor', false ) && 'minor' === $update_type ) && ! $this->same_minor_release( $release_parts, $updates ) ) { $updates[] = array( diff --git a/php/commands/comment.php b/php/commands/comment.php index 662f4f734..824f974a5 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -209,7 +209,7 @@ public function list_( $_, $assoc_args ) { */ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { - $r = wp_delete_comment( $comment_id, isset( $assoc_args['force'] ) ); + $r = wp_delete_comment( $comment_id, \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ); if ( $r ) { return array( 'success', "Deleted comment $comment_id." ); diff --git a/php/commands/core.php b/php/commands/core.php index c79c9ed5a..a74be9d14 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -73,8 +73,8 @@ function check_update( $_, $assoc_args ) { $update_type = 'minor'; } - if ( ! ( isset( $assoc_args['minor'] ) && 'minor' !== $update_type ) - && ! ( isset( $assoc_args['major'] ) && 'major' !== $update_type ) + if ( ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor' ) && 'minor' !== $update_type ) + && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'major' ) && 'major' !== $update_type ) ) { $updates = $this->remove_same_minor_releases( $release_parts, $updates ); $updates[] = array( @@ -121,7 +121,7 @@ function check_update( $_, $assoc_args ) { * @when before_wp_load */ public function download( $args, $assoc_args ) { - if ( !isset( $assoc_args['force'] ) && is_readable( ABSPATH . 'wp-load.php' ) ) + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( !is_dir( ABSPATH ) ) { @@ -336,7 +336,7 @@ public function config( $_, $assoc_args ) { WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); // Check DB connection - if ( !isset( $assoc_args['skip-check'] ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-check' ) ) { Utils\run_mysql_command( 'mysql --no-defaults', array( 'execute' => ';', 'host' => $assoc_args['dbhost'], @@ -345,12 +345,12 @@ public function config( $_, $assoc_args ) { ) ); } - if ( isset( $assoc_args['extra-php'] ) && $assoc_args['extra-php'] === true ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'extra-php' ) ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); } // TODO: adapt more resilient code from wp-admin/setup-config.php - if ( ! isset( $assoc_args['skip-salts'] ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-salts' ) ) { $assoc_args['keys-and-salts'] = self::_read( 'https://api.wordpress.org/secret-key/1.1/salt/' ); } @@ -387,7 +387,7 @@ public function config( $_, $assoc_args ) { */ public function is_installed( $_, $assoc_args ) { - if ( isset( $assoc_args['network'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { if ( is_blog_installed() && is_multisite() ) { exit( 0 ); } else { @@ -735,7 +735,7 @@ public function version( $args = array(), $assoc_args = array() ) { include $versions_path; // @codingStandardsIgnoreStart - if ( isset( $assoc_args['extra'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'extra' ) ) { if ( preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ) ) { $human_readable_tiny_mce = $match[1] . '.' . $match[2]; } else { @@ -898,7 +898,7 @@ function update( $args, $assoc_args ) { } } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) - || isset( $assoc_args['force'] ) ) { + || \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ) { $version = $assoc_args['version']; $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); @@ -921,7 +921,7 @@ function update( $args, $assoc_args ) { } - if ( ! empty( $update ) && ( $update->version != $wp_version || isset( $assoc_args['force'] ) ) ) { + if ( ! empty( $update ) && ( $update->version != $wp_version || \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ) ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); diff --git a/php/commands/media.php b/php/commands/media.php index 9f73deca5..5228ff2a6 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -162,18 +162,18 @@ function import( $args, $assoc_args = array() ) { } // Set as featured image, if --post_id and --featured_image are set - if ( $assoc_args['post_id'] && isset( $assoc_args['featured_image'] ) ) { + if ( $assoc_args['post_id'] && \WP_CLI\Utils\check_flag( $assoc_args, 'featured_image' ) ) { update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); } $attachment_success_text = ''; if ( $assoc_args['post_id'] ) { $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; - if ( isset($assoc_args['featured_image']) ) + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'featured_image' ) ) $attachment_success_text .= ' as featured image'; } - if ( isset( $assoc_args['porcelain'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $success ); } else { WP_CLI::success( sprintf( diff --git a/php/commands/menu.php b/php/commands/menu.php index 136a6e421..afab17d3e 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -51,7 +51,7 @@ public function create( $args, $assoc_args ) { } else { - if ( isset( $assoc_args['porcelain'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $menu_id ); } else { WP_CLI::success( "Created menu $menu_id." ); diff --git a/php/commands/option.php b/php/commands/option.php index 6575da1a3..142847ab1 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -64,7 +64,7 @@ public function add( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); - if ( isset( $assoc_args['autoload'] ) && $assoc_args['autoload'] == 'no' ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'autoload', 'no' ) ) { $autoload = 'no'; } else { $autoload = 'yes'; @@ -139,7 +139,7 @@ public function list_( $args, $assoc_args ) { $fields = explode( ',', $assoc_args['fields'] ); } - if ( isset( $assoc_args['format'] ) && 'total_bytes' === $assoc_args['format'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'total_bytes' ) ) { $fields = array( 'size_bytes' ); $size_query = ",SUM(LENGTH(option_value)) AS `size_bytes`"; } @@ -162,7 +162,7 @@ public function list_( $args, $assoc_args ) { ) ); - if ( isset( $assoc_args['format'] ) && 'total_bytes' === $assoc_args['format'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'total_bytes' ) ) { WP_CLI::line( $results[0]->size_bytes ); } else { $formatter = new \WP_CLI\Formatter( diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c5352befe..bafdb8ad2 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -153,9 +153,9 @@ protected function get_all_items() { * : If set, the plugin will be activated for the entire multisite network. */ function activate( $args, $assoc_args = array() ) { - $network_wide = isset( $assoc_args['network'] ); + $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); - if ( isset( $assoc_args['all'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { $args = array_map( function( $file ){ return Utils\get_plugin_name( $file ); }, array_keys( get_plugins() ) ); @@ -201,10 +201,10 @@ function activate( $args, $assoc_args = array() ) { * : If set, the plugin will be deactivated for the entire multisite network. */ function deactivate( $args, $assoc_args = array() ) { - $network_wide = isset( $assoc_args['network'] ); - $disable_all = isset( $assoc_args['all'] ); + $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); + $disable_all = \WP_CLI\Utils\check_flag( $assoc_args, 'all' ); - if ( isset( $assoc_args['all'] ) ) { + if ( $disable_all ) { $args = array_map( function( $file ){ return Utils\get_plugin_name( $file ); }, array_keys( get_plugins() ) ); @@ -242,7 +242,7 @@ function deactivate( $args, $assoc_args = array() ) { * : If set, the plugin will be toggled for the entire multisite network. */ function toggle( $args, $assoc_args = array() ) { - $network_wide = isset( $assoc_args['network'] ); + $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->check_active( $plugin->file, $network_wide ) ) { @@ -277,7 +277,7 @@ function path( $args, $assoc_args ) { $plugin = $this->fetcher->get_check( $args[0] ); $path .= '/' . $plugin->file; - if ( isset( $assoc_args['dir'] ) ) + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dir' ) ) $path = dirname( $path ); } @@ -297,13 +297,13 @@ protected function install_from_repo( $slug, $assoc_args ) { $status = install_plugin_install_status( $api ); - if ( !isset( $assoc_args['force'] ) && 'install' != $status['status'] ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && 'install' != $status['status'] ) { // We know this will fail, so avoid a needless download of the package. return new WP_Error( 'already_installed', 'Plugin already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'version', 'dev' ) ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); @@ -503,7 +503,7 @@ function uninstall( $args, $assoc_args = array() ) { uninstall_plugin( $plugin->file ); - if ( !isset( $assoc_args['skip-delete'] ) && $this->_delete( $plugin ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { WP_CLI::success( "Uninstalled and deleted '$plugin->name' plugin." ); } else { WP_CLI::success( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); diff --git a/php/commands/post.php b/php/commands/post.php index edde22682..dd80cda14 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -55,7 +55,7 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = $this->read_from_file_or_stdin( $args[0] ); } - if ( isset( $assoc_args['edit'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'edit' ) ) { $input = isset( $assoc_args['post_content'] ) ? $assoc_args['post_content'] : ''; @@ -357,7 +357,7 @@ public function generate( $args, $assoc_args ) { $post_author = $user_fetcher->get_check( $post_author )->ID; } - if ( isset( $assoc_args['post_content'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'post_content' ) ) { $post_content = file_get_contents( 'php://stdin' ); } diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 4bc3dced5..bea5dfd5f 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -28,10 +28,10 @@ class Rewrite_Command extends WP_CLI_Command { public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); - if ( isset( $assoc_args['hard'] ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); } - flush_rewrite_rules( isset( $assoc_args['hard'] ) ); + flush_rewrite_rules( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) ); if ( ! get_option( 'rewrite_rules' ) ) { WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); } @@ -115,7 +115,7 @@ public function structure( $args, $assoc_args ) { // Launch a new process to flush rewrites because core expects flush // to happen after rewrites are set $new_assoc_args = array(); - if ( isset( $assoc_args['hard'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) ) { $new_assoc_args['hard'] = true; if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); diff --git a/php/commands/role.php b/php/commands/role.php index 88b46eab0..b12ed8ad0 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -169,7 +169,7 @@ public function reset( $args, $assoc_args ) { self::persistence_check(); - if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) WP_CLI::error( "Role key not provided, or is invalid." ); if ( ! function_exists( 'populate_roles' ) ) { @@ -179,7 +179,7 @@ public function reset( $args, $assoc_args ) { // get our default roles $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); - if ( isset( $assoc_args['all'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { foreach( $default_roles as $role ) { remove_role( $role ); } diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 96e6ed054..e78cc59d0 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -211,7 +211,7 @@ function _s( $args, $assoc_args ) { $body['underscoresme_description'] = $theme_description; $body['underscoresme_generate_submit'] = "Generate"; $body['underscoresme_generate'] = "1"; - if ( isset( $assoc_args['sassify'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'sassify' ) ) { $body['underscoresme_sass'] = 1; } @@ -235,9 +235,9 @@ function _s( $args, $assoc_args ) { WP_CLI::success( "Created theme '{$data['theme_name']}'." ); - if ( isset( $assoc_args['activate'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( isset( $assoc_args['enable-network'] ) ) { + } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'enable-network' ) ) { WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); } } @@ -296,9 +296,9 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( isset( $assoc_args['activate'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( isset( $assoc_args['enable-network'] ) ) { + } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'enable-network' ) ) { WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); } } @@ -454,13 +454,13 @@ function plugin( $args, $assoc_args ) { WP_CLI::success( "Created $plugin_dir" ); - if ( !isset( $assoc_args['skip-tests'] ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-tests' ) ) { WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); } - if ( isset( $assoc_args['activate'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); - } else if ( isset( $assoc_args['activate-network'] ) ) { + } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate-network' ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug), array( 'network' => true ) ); } } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index fe1cd8a22..195cb0a7a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -64,9 +64,9 @@ public function __invoke( $args, $assoc_args ) { $new = array_shift( $args ); $total = 0; $report = array(); - $dry_run = self::check_flag( $assoc_args, 'dry-run' ); - $php_only = self::check_flag( $assoc_args, 'precise' ); - $recurse_objects = self::check_flag( $assoc_args, 'recurse-objects' ); + $dry_run = \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ); + $php_only = \WP_CLI\Utils\check_flag( $assoc_args, 'precise' ); + $recurse_objects = \WP_CLI\Utils\check_flag( $assoc_args, 'recurse-objects' ); if ( isset( $assoc_args['skip-columns'] ) ) { $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -79,13 +79,13 @@ public function __invoke( $args, $assoc_args ) { // Determine how to limit the list of tables. Defaults to 'wordpress' $table_type = 'wordpress'; - if ( self::check_flag( $assoc_args, 'network' ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { $table_type = 'network'; } - if ( self::check_flag( $assoc_args, 'all-tables-with-prefix' ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all-tables-with-prefix' ) ) { $table_type = 'all-tables-with-prefix'; } - if ( self::check_flag( $assoc_args, 'all-tables' ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all-tables' ) ) { $table_type = 'all-tables'; } @@ -305,20 +305,6 @@ private static function esc_like( $old ) { return $old; } - /** - * Determine the boolean value of a flag in an array. - * - * Primarily useful for determining the status of a boolean flag for a command. This is needed because a flag can be - * prefixed with --no- to set it to false. Therefore it is not sufficient to only check whether a flag is set. - * - * @param array $array The array to check. - * @param string $key The key to check for. - * - * @return bool True if the key is set in the array and is truthy, false otherwise. - */ - private static function check_flag( $array, $key ) { - return isset( $array[ $key ] ) && $array[ $key ]; - } } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); diff --git a/php/commands/shell.php b/php/commands/shell.php index 82b96484d..d805a2d8e 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -21,7 +21,7 @@ public function __invoke( $_, $assoc_args ) { '\\WP_CLI\\REPL', ); - if ( isset( $assoc_args['basic'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'basic' ) ) { $class = '\\WP_CLI\\REPL'; } else { foreach ( $implementations as $candidate ) { diff --git a/php/commands/site.php b/php/commands/site.php index 7f286e167..c292f53c6 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -178,7 +178,7 @@ function delete( $args, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl site?", $assoc_args ); - wpmu_delete_blog( $blog->blog_id, !isset( $assoc_args['keep-tables'] ) ); + wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\check_flag( $assoc_args, 'keep-tables' ) ); WP_CLI::success( "The site at $blog->siteurl was deleted." ); } @@ -231,7 +231,7 @@ public function create( $_, $assoc_args ) { $network = $current_site; } - $public = !isset( $assoc_args['private'] ); + $public = ! \WP_CLI\Utils\check_flag( $assoc_args, 'private' ); // Sanitize if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { @@ -301,7 +301,7 @@ public function create( $_, $assoc_args ) { WP_CLI::error( $id->get_error_message() ); } - if ( isset( $assoc_args['porcelain'] ) ) + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) WP_CLI::line( $id ); else WP_CLI::success( "Site $id created: $url" ); diff --git a/php/commands/term.php b/php/commands/term.php index e7befa0c2..46a005e63 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -114,12 +114,8 @@ public function create( $args, $assoc_args ) { ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); - if ( isset( $assoc_args['porcelain'] ) ) { - $porcelain = true; - unset( $assoc_args['porcelain'] ); - } else { - $porcelain = false; - } + $porcelain = \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ); + unset( $assoc_args['porcelain'] ); // Compatibility for < WP 4.0 if ( $assoc_args['parent'] > 0 && ! term_exists( (int) $assoc_args['parent'] ) ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 5843333d8..79dc55c76 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -260,7 +260,7 @@ public function path( $args, $assoc_args ) { $path = $theme->get_stylesheet_directory(); - if ( !isset( $assoc_args['dir'] ) ) + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'dir' ) ) $path .= '/style.css'; } @@ -278,13 +278,13 @@ protected function install_from_repo( $slug, $assoc_args ) { self::alter_api_response( $api, $assoc_args['version'] ); } - if ( !isset( $assoc_args['force'] ) && wp_get_theme( $slug )->exists() ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && wp_get_theme( $slug )->exists() ) { // We know this will fail, so avoid a needless download of the package. return new WP_Error( 'already_installed', 'Theme already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( !isset( $assoc_args['version'] ) || 'dev' !== $assoc_args['version'] ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'version', 'dev' ) ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); @@ -597,11 +597,11 @@ class Theme_Mod_command extends WP_CLI_Command { */ public function get( $args = array(), $assoc_args = array() ) { - if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { WP_CLI::error( "You must specify at least one mod or use --all." ); } - if ( isset( $assoc_args['all'] ) && $assoc_args['all'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { $args = array(); } @@ -657,11 +657,11 @@ public function get( $args = array(), $assoc_args = array() ) { */ public function remove( $args = array(), $assoc_args = array() ) { - if ( ! isset( $assoc_args['all'] ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { WP_CLI::error( "You must specify at least one mod or use --all." ); } - if ( isset( $assoc_args['all'] ) && $assoc_args['all'] ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { remove_theme_mods(); WP_CLI::success( 'Theme mods removed.' ); return; diff --git a/php/commands/user.php b/php/commands/user.php index d9597fca0..580a0c5fd 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -81,7 +81,7 @@ public function __construct() { */ public function list_( $args, $assoc_args ) { - if ( isset( $assoc_args['network'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { if ( ! is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } @@ -175,7 +175,7 @@ public function get( $args, $assoc_args ) { * wp user delete 123 --reassign=567 */ public function delete( $args, $assoc_args ) { - $network = isset( $assoc_args['network'] ) && is_multisite(); + $network = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) && is_multisite(); $reassign = isset( $assoc_args['reassign'] ) ? $assoc_args['reassign'] : null; if ( $network && $reassign ) { @@ -287,7 +287,7 @@ public function create( $args, $assoc_args ) { $user->role = $role; $user_id = wp_insert_user( $user ); - if ( isset( $assoc_args['send-email'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'send-email' ) ) { wp_new_user_notification( $user_id, $user->user_pass ); } @@ -300,7 +300,7 @@ public function create( $args, $assoc_args ) { } } - if ( isset( $assoc_args['porcelain'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $user_id ); } else { WP_CLI::success( "Created user $user_id." ); @@ -668,7 +668,7 @@ public function import_csv( $args, $assoc_args ) { $existing_user = get_user_by( 'login', $new_user['user_login'] ); } - if ( $existing_user && isset( $assoc_args['skip-update'] ) ) { + if ( $existing_user && \WP_CLI\Utils\check_flag( $assoc_args, 'skip-update' ) ) { WP_CLI::log( "{$existing_user->user_login} exists and has been skipped" ); continue; @@ -687,7 +687,7 @@ public function import_csv( $args, $assoc_args ) { } else { unset( $new_user['ID'] ); // Unset else it will just return the ID $user_id = wp_insert_user( $new_user ); - if ( isset( $assoc_args['send-email'] ) ) { + if ( \WP_CLI\Utils\check_flag( $assoc_args, 'send-email' ) ) { wp_new_user_notification( $user_id, $new_user['user_pass'] ); } } From b00ea2237acf70939b10a6b4c20dac5cdce82f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Mon, 13 Apr 2015 00:41:05 -0400 Subject: [PATCH 3495/5359] Fix incorrect type of value When set, flags must be strictly boolean values. --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 79dc55c76..4ef1ced63 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -458,7 +458,7 @@ function update( $args, $assoc_args ) { if ( is_wp_error( $r ) ) { WP_CLI::warning( $r ); } else { - $assoc_args['force'] = 1; + $assoc_args['force'] = true; $this->install( array( $theme->stylesheet ), $assoc_args ); } } From a604b83d03a86187cdb02a82f3e80c82403a3a5e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 16 Apr 2015 11:58:56 -0700 Subject: [PATCH 3496/5359] Scaffold plugin and plugin tests to arbitrary directory mu-plugins is one use case, and plugins within themes is another --- features/scaffold.feature | 21 +++++++++++++++++++++ php/commands/scaffold.php | 36 +++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index e1f48aee1..86039c9fe 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -254,3 +254,24 @@ Feature: WordPress code scaffolding """ Success: Switched to 'Starter-theme' theme. """ + + Scenario: Scaffold plugin and tests for non-standard plugin directory + Given a WP install + + When I run `wp scaffold plugin custom-plugin --dir=wp-content/mu-plugins --skip-tests` + Then STDOUT should not be empty + And the wp-content/mu-plugins/custom-plugin/custom-plugin.php file should exist + And the wp-content/mu-plugins/custom-plugin/tests directory should not exist + + When I try `wp scaffold plugin-tests --dir=wp-content/mu-plugins/incorrect-custom-plugin` + Then STDERR should contain: + """ + Error: Invalid plugin specified. + """ + + When I run `wp scaffold plugin-tests --dir=wp-content/mu-plugins/custom-plugin` + Then STDOUT should contain: + """ + Success: Created test files. + """ + And the wp-content/mu-plugins/custom-plugin/tests directory should exist diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index dffe4c9c6..768781f70 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -411,6 +411,9 @@ public function package_tests( $args, $assoc_args ) { * <slug> * : The internal name of the plugin. * + * [--dir=<dirname>] + * : Put the new plugin in some arbitrary directory path. Plugin directory will be path plus supplied slug. + * * [--plugin_name=<title>] * : What to put in the 'Plugin Name:' header * @@ -432,19 +435,26 @@ function plugin( $args, $assoc_args ) { $data['textdomain'] = $plugin_slug; - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + if ( ! empty( $assoc_args['dir'] ) ) { + if ( ! is_dir( $assoc_args['dir'] ) ) { + WP_CLI::error( "Cannot create plugin in directory that doesn't exist." ); + } + $plugin_dir = $assoc_args['dir'] . "/$plugin_slug"; + } else { + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + $this->maybe_create_plugins_dir(); + } + $plugin_path = "$plugin_dir/$plugin_slug.php"; $plugin_readme_path = "$plugin_dir/readme.txt"; - $this->maybe_create_plugins_dir(); - $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); $this->create_file( $plugin_readme_path, Utils\mustache_render( 'plugin-readme.mustache', $data ) ); WP_CLI::success( "Created $plugin_dir" ); if ( !isset( $assoc_args['skip-tests'] ) ) { - WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ) ); + WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir ) ); } if ( isset( $assoc_args['activate'] ) ) { @@ -473,9 +483,12 @@ function plugin( $args, $assoc_args ) { * * ## OPTIONS * - * <plugin> + * [<plugin>] * : The name of the plugin to generate test files for. * + * [--dir=<dirname>] + * : Generate test files for a non-standard plugin path. + * * ## EXAMPLE * * wp scaffold plugin-tests hello @@ -485,9 +498,18 @@ function plugin( $args, $assoc_args ) { function plugin_tests( $args, $assoc_args ) { $wp_filesystem = $this->init_wp_filesystem(); - $plugin_slug = $args[0]; + if ( ! empty( $assoc_args['dir'] ) ) { + $plugin_dir = $assoc_args['dir']; + if ( ! is_dir( $plugin_dir ) ) { + WP_CLI::error( 'Invalid plugin specified.' ); + } + } else if ( ! empty( $args[0] ) ) { + $plugin_slug = $args[0]; + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + } else { + WP_CLI::error( 'Invalid plugin specified.' ); + } - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; $tests_dir = "$plugin_dir/tests"; $bin_dir = "$plugin_dir/bin"; From 7511f519e870a7e2a92e1afa1d5cd94671aa0fdf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 17 Apr 2015 07:06:37 -0700 Subject: [PATCH 3497/5359] Document how to delete all posts in the trash --- php/commands/post.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/post.php b/php/commands/post.php index edde22682..a9bdd70a5 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -195,6 +195,9 @@ public function get( $args, $assoc_args ) { * wp post delete 123 --force * * wp post delete $(wp post list --post_type='page' --format=ids) + * + * # delete all posts in the trash + * wp post delete $(wp post list --post_status=trash --format=ids) */ public function delete( $args, $assoc_args ) { $defaults = array( From 4b4113a81f7cebd44246489b8c3e83236f63317d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 17 Apr 2015 07:08:59 -0700 Subject: [PATCH 3498/5359] Failing test case for incorrect language when deleting trashed post --- features/post.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index daec7467a..4969598dc 100644 --- a/features/post.feature +++ b/features/post.feature @@ -21,7 +21,10 @@ Feature: Manage WordPress posts """ When I run the previous command again - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Deleted post {POST_ID} + """ When I try the previous command again Then the return code should be 1 From 3f410275e190bfcb76fadb016414d81090766ed6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 17 Apr 2015 07:13:09 -0700 Subject: [PATCH 3499/5359] If the post is already trashed, clarify success language --- features/post.feature | 2 +- php/commands/post.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/post.feature b/features/post.feature index 4969598dc..012c61f02 100644 --- a/features/post.feature +++ b/features/post.feature @@ -23,7 +23,7 @@ Feature: Manage WordPress posts When I run the previous command again Then STDOUT should be: """ - Success: Deleted post {POST_ID} + Success: Deleted post {POST_ID}. """ When I try the previous command again diff --git a/php/commands/post.php b/php/commands/post.php index edde22682..964e8e5cd 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -203,10 +203,11 @@ public function delete( $args, $assoc_args ) { $assoc_args = array_merge( $defaults, $assoc_args ); parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { + $status = get_post_status( $post_id ); $r = wp_delete_post( $post_id, $assoc_args['force'] ); if ( $r ) { - $action = $assoc_args['force'] ? 'Deleted' : 'Trashed'; + $action = $assoc_args['force'] || 'trash' === $status ? 'Deleted' : 'Trashed'; return array( 'success', "$action post $post_id." ); } else { From 19ba6160695ecc74cbc5816d63c19f5b44f31dc4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 17 Apr 2015 09:52:33 -0700 Subject: [PATCH 3500/5359] Add `after_invoke` hook for any post-execution tasks --- php/WP_CLI/Dispatcher/Subcommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 83c87c7d2..dd601c34e 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -293,6 +293,8 @@ public function invoke( $args, $assoc_args, $extra_args ) { \WP_CLI::do_hook( 'before_invoke:' . implode( ' ', array_slice( $path, 1 ) ) ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); + + \WP_CLI::do_hook( 'after_invoke:' . implode( ' ', array_slice( $path, 1 ) ) ); } } From 4532e1d5223c1e79bdd16f22cdad2da0ae31f1c7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 17 Apr 2015 10:08:18 -0700 Subject: [PATCH 3501/5359] Respect `$exit` argument in `WP_CLI::error()` --- php/class-wp-cli.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f571c47a5..aa73f8cee 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -256,7 +256,9 @@ public static function error( $message, $exit = true ) { self::$logger->error( self::error_to_string( $message ) ); } - exit(1); + if ( $exit ) { + exit(1); + } } /** From 74dd4231cc1763c29a667502a449678ea15473e6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 13:49:00 -0700 Subject: [PATCH 3502/5359] Add default Gruntfile to plugin scaffold with two helpful tasks --- features/scaffold.feature | 2 ++ php/commands/scaffold.php | 3 ++ templates/plugin-gruntfile.mustache | 54 +++++++++++++++++++++++++++++ templates/plugin-packages.mustache | 12 +++++++ 4 files changed, 71 insertions(+) create mode 100644 templates/plugin-gruntfile.mustache create mode 100644 templates/plugin-packages.mustache diff --git a/features/scaffold.feature b/features/scaffold.feature index 346b0e08c..59e6ebb04 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -114,6 +114,8 @@ Feature: WordPress code scaffolding Then STDOUT should not be empty And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + And the {PLUGIN_DIR}/hello-world/package.json file should exist + And the {PLUGIN_DIR}/hello-world/Gruntfile.js file should exist Scenario: Scaffold a plugin and activate it Given a WP install diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f61ad2cec..d06109c19 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -441,6 +441,7 @@ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; $data = wp_parse_args( $assoc_args, array( + 'plugin_slug' => $plugin_slug, 'plugin_name' => ucfirst( $plugin_slug ), ) ); @@ -461,6 +462,8 @@ function plugin( $args, $assoc_args ) { $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); $this->create_file( $plugin_readme_path, Utils\mustache_render( 'plugin-readme.mustache', $data ) ); + $this->create_file( "$plugin_dir/package.json", Utils\mustache_render( 'plugin-packages.mustache', $data ) ); + $this->create_file( "$plugin_dir/Gruntfile.js", Utils\mustache_render( 'plugin-gruntfile.mustache', $data ) ); WP_CLI::success( "Created $plugin_dir" ); diff --git a/templates/plugin-gruntfile.mustache b/templates/plugin-gruntfile.mustache new file mode 100644 index 000000000..96dba5e2d --- /dev/null +++ b/templates/plugin-gruntfile.mustache @@ -0,0 +1,54 @@ +module.exports = function( grunt ) { + + 'use strict'; + var remapify = require('remapify'); + var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n'; + // Project configuration + grunt.initConfig( { + + pkg: grunt.file.readJSON( 'package.json' ), + + addtextdomain: { + options: { + textdomain: '{{textdomain}}', + }, + target: { + files: { + src: [ '*.php', '**/*.php', '!node_modules/**', '!php-tests/**', '!bin/**' ] + } + } + }, + + wp_readme_to_markdown: { + your_target: { + files: { + 'README.md': 'readme.txt' + } + }, + }, + + makepot: { + target: { + options: { + domainPath: '/languages', + mainFile: '{{plugin_slug}}.php', + potFilename: '{{plugin_slug}}.pot', + potHeaders: { + poedit: true, + 'x-poedit-keywordslist': true + }, + type: 'wp-plugin', + updateTimestamp: true + } + } + }, + } ); + + grunt.loadNpmTasks( 'grunt-wp-i18n' ); + grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' ); + grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] ); + grunt.registerTask( 'readme', ['wp_readme_to_markdown']); + + grunt.util.linefeed = '\n'; + +}; diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache new file mode 100644 index 000000000..ef736af27 --- /dev/null +++ b/templates/plugin-packages.mustache @@ -0,0 +1,12 @@ + +{ + "name": "{{plugin_name}}", + "version": "0.0.0", + "main": "Gruntfile.js", + "author": "YOUR NAME HERE", + "devDependencies": { + "grunt": "^0.4.5", + "grunt-wp-i18n": "^0.5.0", + "grunt-wp-readme-to-markdown": "~0.9.0" + } +} From ce7154ecbbf55fb697b8d480c197ed9833b18ea6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:05:12 -0700 Subject: [PATCH 3503/5359] Don't permit child themes to be activated without their parent If a child theme is dependent on parent functions, WP can fatal. --- features/theme.feature | 9 +++++++++ php/commands/theme.php | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index fde24c993..040d4e6bc 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -225,3 +225,12 @@ Feature: Manage WordPress themes Then STDOUT should be a table containing rows: | name | version | | p2 | 1.4.2 | + + Scenario: Install and attempt to activate a child theme without its parent + Given a WP install + + When I try `wp theme install biker --activate` + Then STDERR should contain: + """ + Error: The 'biker' theme cannot be activated without its parent, 'jolene'. + """ diff --git a/php/commands/theme.php b/php/commands/theme.php index 5843333d8..34e5fec52 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -128,6 +128,10 @@ public function activate( $args = array() ) { exit; } + if ( $theme->get_stylesheet() != $theme->get_template() && ! $this->fetcher->get( $theme->get_template() ) ) { + WP_CLI::error( "The '{$theme->get_stylesheet()}' theme cannot be activated without its parent, '{$theme->get_template()}'." ); + } + switch_theme( $theme->get_template(), $theme->get_stylesheet() ); if ( $this->is_active_theme( $theme ) ) { From 666c12e6b4307bc5f3a80ba71bab9c0457b7cb6b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:15:36 -0700 Subject: [PATCH 3504/5359] Failing test case for #1728 --- features/cron.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 90f43ba15..e8d0513db 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -4,16 +4,16 @@ Feature: Manage WP-Cron events and schedules Given a WP install Scenario: Scheduling and then deleting an event - When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour' --apple=banana` + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 2 minutes' --apple=banana` Then STDOUT should contain: """ Success: Scheduled event with hook 'wp_cli_test_event_1' """ - When I run `wp cron event list --format=csv --fields=hook,recurrence,args` + When I run `wp cron event list --format=csv --fields=hook,recurrence,next_run_relative,args` Then STDOUT should be CSV containing: - | hook | recurrence | args | - | wp_cli_test_event_1 | Non-repeating | {"apple":"banana"} | + | hook | recurrence | next_run_relative | args | + | wp_cli_test_event_1 | Non-repeating | 1 hour 1 minute | {"apple":"banana"} | When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: From 25bdcbefb7f01e18193467e22f9667a0be9ba4df Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:16:36 -0700 Subject: [PATCH 3505/5359] Fix broken conditional for `<next-run>` argument --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 527e42798..b9b4ed0cb 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -97,7 +97,7 @@ public function schedule( $args, $assoc_args ) { $next_run = ( isset( $args[1] ) ) ? $args[1] : 'now'; $recurrence = ( isset( $args[2] ) ) ? $args[2] : false; - if ( ! empty( $next_run ) ) { + if ( empty( $next_run ) ) { $timestamp = time(); } else if ( is_numeric( $next_run ) ) { $timestamp = absint( $next_run ); From 5ba7cdbbb8bb6e5c8e5df1e2b5c427dd8053dfbb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:26:44 -0700 Subject: [PATCH 3506/5359] Support filtering by site value in `wp site list` --- features/site.feature | 19 +++++++++++++++++++ php/commands/site.php | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/features/site.feature b/features/site.feature index 3a0382007..989177cfd 100644 --- a/features/site.feature +++ b/features/site.feature @@ -35,6 +35,25 @@ Feature: Manage sites in a multisite installation When I try the previous command again Then the return code should be 1 + Scenario: Filter site list + Given a WP multisite install + + When I run `wp site create --slug=first --porcelain` + Then STDOUT should be a number + And save STDOUT as {SITE_ID} + + When I run `wp site list --fields=blog_id,url` + Then STDOUT should be a table containing rows: + | blog_id | url | + | 1 | example.com/ | + | 2 | example.com/first/ | + + When I run `wp site list --field=url --blog_id=2` + Then STDOUT should be: + """ + example.com/first/ + """ + Scenario: Delete a site by slug Given a WP multisite install diff --git a/php/commands/site.php b/php/commands/site.php index 7f286e167..a5992ce85 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -336,6 +336,9 @@ private function _get_network( $network_id ) { * [--network=<id>] * : The network to which the sites belong. * + * [--<field>=<value>] + * : Filter by one or more fields. + * * [--field=<field>] * : Prints the value of a single field for each site. * @@ -391,6 +394,14 @@ public function list_( $_, $assoc_args ) { $assoc_args = array_merge( $defaults, $assoc_args ); $where = array(); + + $site_cols = array( 'blog_id', 'url', 'last_updated', 'registered', 'site_id', 'domain', 'path', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ); + foreach( $site_cols as $col ) { + if ( isset( $assoc_args[ $col ] ) ) { + $where[ $col ] = $assoc_args[ $col ]; + } + } + if ( isset( $assoc_args['network'] ) ) { $where['site_id'] = $assoc_args['network']; } From 59b123642117315196ed120c7c3f66c04a90dbad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:29:32 -0700 Subject: [PATCH 3507/5359] Don't attempt to activate a child without a parent --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 346b0e08c..4b4452db3 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -6,7 +6,7 @@ Feature: WordPress code scaffolding Given I run `wp theme path` And save STDOUT as {THEME_DIR} - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --activate` + When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com` Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist From a221fa4d60a26aedeb7eb57f10264aed0fd434dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 14:58:35 -0700 Subject: [PATCH 3508/5359] On multisite, run user creation through validation rules --- features/user.feature | 46 +++++++++++++++++++++++++++++++++++++++++++ php/commands/user.php | 45 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index 30890875a..f35d936a9 100644 --- a/features/user.feature +++ b/features/user.feature @@ -167,6 +167,52 @@ Feature: Manage WordPress users }] """ + Scenario: Import new users on multisite + Given a WP multisite install + And a user-invalid.csv file: + """ + user_login,user_email,display_name,role + bob-jones,bobjones@example.com,Bob Jones,contributor + """ + And a user-valid.csv file: + """ + user_login,user_email,display_name,role + bobjones,bobjones@example.com,Bob Jones,contributor + """ + + When I try `wp user import-csv user-invalid.csv` + Then STDERR should contain: + """ + Warning: Only lowercase letters (a-z) and numbers are allowed. + """ + + When I run `wp user import-csv user-valid.csv` + Then STDOUT should not be empty + + When I run `wp user get bobjones --field=display_name` + Then STDOUT should be: + """ + Bob Jones + """ + + Scenario: Create new users on multisite + Given a WP multisite install + + When I try `wp user create bob-jones bobjones@example.com` + Then STDERR should contain: + """ + Warning: Only lowercase letters (a-z) and numbers are allowed. + """ + + When I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones"` + Then STDOUT should not be empty + + When I run `wp user get bobjones --field=display_name` + Then STDOUT should be: + """ + Bob Jones + """ + Scenario: Import new users but don't update existing Given a WP install And a users.csv file: diff --git a/php/commands/user.php b/php/commands/user.php index d9597fca0..c77f7085a 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -286,7 +286,27 @@ public function create( $args, $assoc_args ) { } $user->role = $role; - $user_id = wp_insert_user( $user ); + if ( is_multisite() ) { + $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); + if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { + WP_CLI::warning( $ret['errors'] ); + continue; + } + $user_id = wpmu_create_user( $user->user_login, $user->user_email, $user->user_login, $user->user_pass ); + if ( ! $user_id ) { + WP_CLI::warning( "Unknown error creating new user" ); + continue; + } + $user->ID = $user_id; + $user_id = wp_update_user( $user ); + if ( is_wp_error( $user_id ) ) { + WP_CLI::warning( $user_id ); + continue; + } + } else { + $user_id = wp_insert_user( $user ); + } + if ( isset( $assoc_args['send-email'] ) ) { wp_new_user_notification( $user_id, $user->user_pass ); } @@ -686,7 +706,28 @@ public function import_csv( $args, $assoc_args ) { // Create the user } else { unset( $new_user['ID'] ); // Unset else it will just return the ID - $user_id = wp_insert_user( $new_user ); + + if ( is_multisite() ) { + $ret = wpmu_validate_user_signup( $new_user['user_login'], $new_user['user_email'] ); + if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { + WP_CLI::warning( $ret['errors'] ); + continue; + } + $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_email'], $new_user['user_pass'] ); + if ( ! $user_id ) { + WP_CLI::warning( "Unknown error creating new user" ); + continue; + } + $new_user['ID'] = $user_id; + $user_id = wp_update_user( $new_user ); + if ( is_wp_error( $user_id ) ) { + WP_CLI::warning( $user_id ); + continue; + } + } else { + $user_id = wp_insert_user( $new_user ); + } + if ( isset( $assoc_args['send-email'] ) ) { wp_new_user_notification( $user_id, $new_user['user_pass'] ); } From 02fca9a4131969b541b36f7a32cbcb15a740bff6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 15:02:15 -0700 Subject: [PATCH 3509/5359] Be more fault tolerant with timing in CI --- features/cron.feature | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index e8d0513db..73b46d393 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -4,16 +4,22 @@ Feature: Manage WP-Cron events and schedules Given a WP install Scenario: Scheduling and then deleting an event - When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 2 minutes' --apple=banana` + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 5 minutes' --apple=banana` Then STDOUT should contain: """ Success: Scheduled event with hook 'wp_cli_test_event_1' """ - When I run `wp cron event list --format=csv --fields=hook,recurrence,next_run_relative,args` + When I run `wp cron event list --format=csv --fields=hook,recurrence,args` Then STDOUT should be CSV containing: - | hook | recurrence | next_run_relative | args | - | wp_cli_test_event_1 | Non-repeating | 1 hour 1 minute | {"apple":"banana"} | + | hook | recurrence | args | + | wp_cli_test_event_1 | Non-repeating | {"apple":"banana"} | + + When I run `wp cron event list --fields=hook,next_run_relative | grep wp_cli_test_event_1` + Then STDOUT should contain: + """ + 1 hour + """ When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: From ae4a6edb88512ab5cc26fb233b64e5b4180cf24f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 15:07:52 -0700 Subject: [PATCH 3510/5359] Rename `wp site not-spam` to `wp site unspam` --- features/site.feature | 2 +- php/commands/site.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/site.feature b/features/site.feature index 5b5767fda..7edd3ec1b 100644 --- a/features/site.feature +++ b/features/site.feature @@ -217,7 +217,7 @@ Feature: Manage sites in a multisite installation | blog_id | spam | | {FIRST_SITE} | 1 | - When I run `wp site not-spam {FIRST_SITE}` + When I run `wp site unspam {FIRST_SITE}` Then STDOUT should be: """ Success: Site {FIRST_SITE} removed from spam. diff --git a/php/commands/site.php b/php/commands/site.php index 075ca2ba5..189f95e65 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -520,11 +520,11 @@ public function spam( $args ) { * * ## EXAMPLES * - * wp site not-spam 123 + * wp site unspam 123 * - * @subcommand not-spam + * @subcommand unspam */ - public function not_spam( $args ) { + public function unspam( $args ) { $this->update_site_status( $args, 'spam', 0 ); } From cff2b5d496989cc11f7e59859c19c21a98d16c3b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 15:08:42 -0700 Subject: [PATCH 3511/5359] Wrap actions in brackets --- php/commands/site.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 189f95e65..376652f48 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -554,12 +554,12 @@ private function update_site_status( $ids, $pref, $value ) { $old_value = get_blog_status( $site->blog_id, $pref ); if ( $value == $old_value ) { - WP_CLI::warning( "Site {$site->blog_id} already $action." ); + WP_CLI::warning( "Site {$site->blog_id} already {$action}." ); continue; } update_blog_status( $site->blog_id, $pref, $value ); - WP_CLI::success( "Site {$site->blog_id} $action." ); + WP_CLI::success( "Site {$site->blog_id} {$action}." ); } } } From df5cf19d64e2f50e316acac61353127b2f608887 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 15:21:11 -0700 Subject: [PATCH 3512/5359] Helpful error message when user provides invalid version or locale --- features/core.feature | 9 +++++++++ php/commands/core.php | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 779b83501..d733c63fd 100644 --- a/features/core.feature +++ b/features/core.feature @@ -641,3 +641,12 @@ Feature: Manage WordPress installation """ 4.0 """ + + Scenario: Catch download of non-existent WP version + Given an empty directory + + When I try `wp core download --version=4.1.0 --force` + Then STDERR should contain: + """ + Error: Release not found. + """ diff --git a/php/commands/core.php b/php/commands/core.php index c79c9ed5a..b95b729b5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -172,7 +172,12 @@ public function download( $args, $assoc_args ) { 'filename' => $temp ); - Utils\http_request( 'GET', $download_url, null, $headers, $options ); + $response = Utils\http_request( 'GET', $download_url, null, $headers, $options ); + if ( 404 == $response->status_code ) { + WP_CLI::error( "Release not found. Double-check locale or version." ); + } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { + WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); + } self::_extract( $temp, ABSPATH ); $cache->import( $cache_key, $temp ); unlink($temp); From 5b3dda9463ece12690f3c50a9d8cd4d7d356cff1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 17:40:12 -0700 Subject: [PATCH 3513/5359] Hard error, because it's not looped --- php/commands/user.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index c77f7085a..11aa5829d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -289,19 +289,16 @@ public function create( $args, $assoc_args ) { if ( is_multisite() ) { $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { - WP_CLI::warning( $ret['errors'] ); - continue; + WP_CLI::error( $ret['errors'] ); } $user_id = wpmu_create_user( $user->user_login, $user->user_email, $user->user_login, $user->user_pass ); if ( ! $user_id ) { - WP_CLI::warning( "Unknown error creating new user" ); - continue; + WP_CLI::error( "Unknown error creating new user" ); } $user->ID = $user_id; $user_id = wp_update_user( $user ); if ( is_wp_error( $user_id ) ) { - WP_CLI::warning( $user_id ); - continue; + WP_CLI::error( $user_id ); } } else { $user_id = wp_insert_user( $user ); From a09fbc98f221ea2da1c517dfea2ae8c2fd25df4f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 17:42:50 -0700 Subject: [PATCH 3514/5359] Update tests for multisite --- features/user.feature | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/user.feature b/features/user.feature index f35d936a9..d65b246d7 100644 --- a/features/user.feature +++ b/features/user.feature @@ -67,20 +67,20 @@ Feature: Manage WordPress users Scenario: Reassigning user posts Given a WP multisite install - When I run `wp user create bob bob@example.com --role=author --porcelain` + When I run `wp user create bobjones bob@example.com --role=author --porcelain` And save STDOUT as {BOB_ID} And I run `wp user create sally sally@example.com --role=editor --porcelain` And save STDOUT as {SALLY_ID} - When I run `wp post generate --count=3 --post_author=bob` + When I run `wp post generate --count=3 --post_author=bobjones` And I run `wp post list --author={BOB_ID} --format=count` Then STDOUT should be: """ 3 """ - When I run `wp user delete bob --reassign={SALLY_ID}` + When I run `wp user delete bobjones --reassign={SALLY_ID}` And I run `wp post list --author={SALLY_ID} --format=count` Then STDOUT should be: """ @@ -90,16 +90,16 @@ Feature: Manage WordPress users Scenario: Deleting user from the whole network Given a WP multisite install - When I run `wp user create bob bob@example.com --role=author --porcelain` + When I run `wp user create bobjones bob@example.com --role=author --porcelain` And save STDOUT as {BOB_ID} - When I run `wp user get bob` + When I run `wp user get bobjones` Then STDOUT should not be empty - When I run `wp user delete bob --network --yes` + When I run `wp user delete bobjones --network --yes` Then STDOUT should not be empty - When I try `wp user get bob` + When I try `wp user get bobjones` Then STDERR should not be empty Scenario: Generating and deleting users @@ -201,7 +201,7 @@ Feature: Manage WordPress users When I try `wp user create bob-jones bobjones@example.com` Then STDERR should contain: """ - Warning: Only lowercase letters (a-z) and numbers are allowed. + Error: Only lowercase letters (a-z) and numbers are allowed. """ When I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones"` From b9f82017af69fd146d7be4def86cce27166e7932 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 19 Apr 2015 18:08:14 -0700 Subject: [PATCH 3515/5359] Fix indentation --- php/commands/user.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 11aa5829d..e9b326e4d 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -298,7 +298,7 @@ public function create( $args, $assoc_args ) { $user->ID = $user_id; $user_id = wp_update_user( $user ); if ( is_wp_error( $user_id ) ) { - WP_CLI::error( $user_id ); + WP_CLI::error( $user_id ); } } else { $user_id = wp_insert_user( $user ); @@ -718,8 +718,8 @@ public function import_csv( $args, $assoc_args ) { $new_user['ID'] = $user_id; $user_id = wp_update_user( $new_user ); if ( is_wp_error( $user_id ) ) { - WP_CLI::warning( $user_id ); - continue; + WP_CLI::warning( $user_id ); + continue; } } else { $user_id = wp_insert_user( $new_user ); From 3b4cc5fac86b29b7d212b19b94d7cead61ec6b4f Mon Sep 17 00:00:00 2001 From: yivi <ivan@ojiva.es> Date: Mon, 20 Apr 2015 13:00:13 +0200 Subject: [PATCH 3516/5359] removed .idea files --- .idea/php.xml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .idea/php.xml diff --git a/.idea/php.xml b/.idea/php.xml deleted file mode 100644 index b06e40b21..000000000 --- a/.idea/php.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="Behat"> - <behat_settings> - <BehatSettings behat_path="$PROJECT_DIR$/vendor/behat/behat/bin/behat" /> - </behat_settings> - </component> - <component name="PhpProjectSharedConfiguration" php_language_level="5.5.0" /> -</project> - From 976cf9134fd62693e595294f89366f2b43a50d95 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 20 Apr 2015 17:03:30 -0700 Subject: [PATCH 3517/5359] Bail early if there's no `file` set We need it to continue with the operation --- php/commands/media.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index 9f73deca5..901b1e0a2 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -234,6 +234,10 @@ private function remove_old_images( $att_id ) { $metadata = wp_get_attachment_metadata( $att_id ); + if ( empty( $metadata['file'] ) ) { + return; + } + $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; $original_path = $dir_path . basename( $metadata['file'] ); From 31f1f0e023754adedab460ca5afbee3ff7a8126c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Apr 2015 10:31:55 -0700 Subject: [PATCH 3518/5359] Increase max PHP tested version for plugins to 5.5 --- templates/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 64be0af08..8b561acd3 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -2,7 +2,7 @@ language: php php: - 5.3 - - 5.4 + - 5.5 env: - WP_VERSION=latest WP_MULTISITE=0 From 7f273e6711f525ed77678008eb7223db8c600568 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Apr 2015 10:41:52 -0700 Subject: [PATCH 3519/5359] Use plugin slug in plugin's packages.json `npm install` fails on the name --- templates/plugin-packages.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache index ef736af27..657df4608 100644 --- a/templates/plugin-packages.mustache +++ b/templates/plugin-packages.mustache @@ -1,6 +1,6 @@ { - "name": "{{plugin_name}}", + "name": "{{plugin_slug}}", "version": "0.0.0", "main": "Gruntfile.js", "author": "YOUR NAME HERE", From e73d44ad14cbcbfed6e672487c8f34eb92eb2b39 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Apr 2015 10:44:29 -0700 Subject: [PATCH 3520/5359] Scaffolded unit tests should follow coding standards --- templates/bootstrap.mustache | 8 +++++--- templates/test-sample.php | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index c18a7fe3e..e2802af05 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -1,12 +1,14 @@ <?php -$_tests_dir = getenv('WP_TESTS_DIR'); -if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib'; +$_tests_dir = getenv( 'WP_TESTS_DIR' ); +if ( ! $_tests_dir ) { + $_tests_dir = '/tmp/wordpress-tests-lib'; +} require_once $_tests_dir . '/includes/functions.php'; function _manually_load_plugin() { - require dirname( __FILE__ ) . '/../{{plugin_slug}}.php'; + require dirname( __FILE__ ) . '/../.php'; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); diff --git a/templates/test-sample.php b/templates/test-sample.php index 1a23460d3..79ba8f9a2 100644 --- a/templates/test-sample.php +++ b/templates/test-sample.php @@ -2,7 +2,7 @@ class SampleTest extends WP_UnitTestCase { - function testSample() { + function test_sample() { // replace this with some actual testing code $this->assertTrue( true ); } From 04c7b00445b5c1045199ecc744d453f96dd866c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Apr 2015 12:07:53 -0700 Subject: [PATCH 3521/5359] Update tested WordPress versions to reflect new stable --- features/core.feature | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/core.feature b/features/core.feature index d733c63fd..046eca25d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,10 +326,10 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.1.1 | major | https://wordpress.org/wordpress-4.1.1.zip | - | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | - | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | - | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | + | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | + | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | + | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | + | 3.8.6 | minor | https://wordpress.org/wordpress-3.8.6.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -340,9 +340,9 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.1.1 | major | https://wordpress.org/wordpress-4.1.1.zip | - | 4.0.1 | major | https://wordpress.org/wordpress-4.0.1.zip | - | 3.9.3 | major | https://wordpress.org/wordpress-3.9.3.zip | + | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | + | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | + | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -353,7 +353,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.5 | minor | https://wordpress.org/wordpress-3.8.5.zip | + | 3.8.6 | minor | https://wordpress.org/wordpress-3.8.6.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From 2e84fa50f985e55670567eaecaf289d5f806c560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Tue, 21 Apr 2015 17:52:00 -0400 Subject: [PATCH 3522/5359] Change `\WP_CLI\Utils\check_flag` function name and operation `\WP_CLI\Utils\check_flag` -> `\WP_CLI\Utils\get_flag_value` The operation was changed to fit in other cases. --- php/WP_CLI/CommandWithDBObject.php | 2 +- php/WP_CLI/CommandWithTranslation.php | 4 ++-- php/WP_CLI/CommandWithUpgrade.php | 12 ++++++------ php/class-wp-cli.php | 6 +++--- php/commands/cli.php | 10 +++++----- php/commands/comment.php | 2 +- php/commands/core.php | 20 ++++++++++---------- php/commands/media.php | 6 +++--- php/commands/menu.php | 2 +- php/commands/option.php | 6 +++--- php/commands/plugin.php | 18 +++++++++--------- php/commands/post.php | 4 ++-- php/commands/rewrite.php | 6 +++--- php/commands/role.php | 4 ++-- php/commands/scaffold.php | 16 ++++++++-------- php/commands/search-replace.php | 12 ++++++------ php/commands/shell.php | 2 +- php/commands/site.php | 6 +++--- php/commands/term.php | 2 +- php/commands/theme.php | 14 +++++++------- php/commands/user.php | 12 ++++++------ php/utils.php | 16 ++++++++-------- 22 files changed, 91 insertions(+), 91 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index dcd2be9b4..ef32e3586 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -41,7 +41,7 @@ protected function _create( $args, $assoc_args, $callback ) { \WP_CLI::error( $obj_id ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) \WP_CLI::line( $obj_id ); else \WP_CLI::success( "Created $this->obj_type $obj_id." ); diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index c78b326c4..b46ed1274 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -133,7 +133,7 @@ public function install( $args, $assoc_args ) { if ( $response == $language_code ) { \WP_CLI::success( "Language installed." ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { $this->activate( array( $language_code ), array() ); } } else { @@ -199,7 +199,7 @@ public function update( $args, $assoc_args ) { } // Only preview which translations would be updated. - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { \WP_CLI::line( sprintf( 'Available %d translations updates:', count( $updates ) ) ); \WP_CLI\Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 0b3c592ce..ed1d7214b 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -150,12 +150,12 @@ function install( $args, $assoc_args ) { } if ( $result ) { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate-network' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate-network' ) ) { \WP_CLI::log( "Network-activating '$slug'..." ); $this->activate( array( $slug ), array( 'network' => true ) ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } @@ -203,20 +203,20 @@ protected static function alter_api_response( $response, $version ) { } protected function get_upgrader( $assoc_args ) { - $upgrader_class = $this->get_upgrader_class( \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ); + $upgrader_class = $this->get_upgrader_class( \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ); return \WP_CLI\Utils\get_upgrader( $upgrader_class ); } protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { \WP_CLI::error( "Please specify one or more {$this->item_type}s, or use --all." ); } $items = $this->get_item_list(); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $items = $this->filter_item_list( $items, $args ); } @@ -224,7 +224,7 @@ protected function update_many( $args, $assoc_args ) { 'update' => true ) ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { if ( empty( $items_to_update ) ) { \WP_CLI::line( "No {$this->item_type} updates available." ); return; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0dd7345d8..2dcd96680 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -276,7 +276,7 @@ public static function error_multi_line( $message_lines ) { * Ask for confirmation before running a destructive operation. */ public static function confirm( $question, $assoc_args = array() ) { - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'yes' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'yes' ) ) { fwrite( STDOUT, $question . " [y/n] " ); $answer = trim( fgets( STDIN ) ); @@ -316,7 +316,7 @@ public static function get_value_from_arg_or_stdin( $args, $index ) { * @param array $assoc_args */ public static function read_value( $raw_value, $assoc_args = array() ) { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { $value = json_decode( $raw_value, true ); if ( null === $value ) { WP_CLI::error( sprintf( 'Invalid JSON: %s', $raw_value ) ); @@ -335,7 +335,7 @@ public static function read_value( $raw_value, $assoc_args = array() ) { * @param array $assoc_args */ public static function print_value( $value, $assoc_args = array() ) { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { $value = json_encode( $value ); } elseif ( is_array( $value ) || is_object( $value ) ) { $value = var_export( $value ); diff --git a/php/commands/cli.php b/php/commands/cli.php index e1355bdf5..5553335a0 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -48,7 +48,7 @@ public function info( $_, $assoc_args ) { $runner = WP_CLI::get_runner(); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'json' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { $info = array( 'php_binary_path' => $php_bin, 'global_config_path' => $runner->global_config_path, @@ -237,10 +237,10 @@ private function get_updates( $assoc_args ) { $update_type = 'patch'; } - if ( ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'patch' ) && 'patch' !== $update_type ) - && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'patch', false ) && 'patch' === $update_type ) - && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor' ) && 'minor' !== $update_type ) - && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor', false ) && 'minor' === $update_type ) + if ( ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) && 'patch' !== $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) === false && 'patch' === $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) && 'minor' !== $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) === false && 'minor' === $update_type ) && ! $this->same_minor_release( $release_parts, $updates ) ) { $updates[] = array( diff --git a/php/commands/comment.php b/php/commands/comment.php index 824f974a5..2aac405a4 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -209,7 +209,7 @@ public function list_( $_, $assoc_args ) { */ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { - $r = wp_delete_comment( $comment_id, \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ); + $r = wp_delete_comment( $comment_id, \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ); if ( $r ) { return array( 'success', "Deleted comment $comment_id." ); diff --git a/php/commands/core.php b/php/commands/core.php index ae7c9ea7f..43a040c22 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -73,8 +73,8 @@ function check_update( $_, $assoc_args ) { $update_type = 'minor'; } - if ( ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'minor' ) && 'minor' !== $update_type ) - && ! ( \WP_CLI\Utils\check_flag( $assoc_args, 'major' ) && 'major' !== $update_type ) + if ( ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) && 'minor' !== $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'major' ) && 'major' !== $update_type ) ) { $updates = $this->remove_same_minor_releases( $release_parts, $updates ); $updates[] = array( @@ -121,7 +121,7 @@ function check_update( $_, $assoc_args ) { * @when before_wp_load */ public function download( $args, $assoc_args ) { - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && is_readable( ABSPATH . 'wp-load.php' ) ) + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && is_readable( ABSPATH . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( !is_dir( ABSPATH ) ) { @@ -341,7 +341,7 @@ public function config( $_, $assoc_args ) { WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); // Check DB connection - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-check' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-check' ) ) { Utils\run_mysql_command( 'mysql --no-defaults', array( 'execute' => ';', 'host' => $assoc_args['dbhost'], @@ -350,12 +350,12 @@ public function config( $_, $assoc_args ) { ) ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'extra-php' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra-php' ) ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); } // TODO: adapt more resilient code from wp-admin/setup-config.php - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-salts' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-salts' ) ) { $assoc_args['keys-and-salts'] = self::_read( 'https://api.wordpress.org/secret-key/1.1/salt/' ); } @@ -392,7 +392,7 @@ public function config( $_, $assoc_args ) { */ public function is_installed( $_, $assoc_args ) { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { if ( is_blog_installed() && is_multisite() ) { exit( 0 ); } else { @@ -740,7 +740,7 @@ public function version( $args = array(), $assoc_args = array() ) { include $versions_path; // @codingStandardsIgnoreStart - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'extra' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra' ) ) { if ( preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ) ) { $human_readable_tiny_mce = $match[1] . '.' . $match[2]; } else { @@ -903,7 +903,7 @@ function update( $args, $assoc_args ) { } } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) - || \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ) { + || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { $version = $assoc_args['version']; $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); @@ -926,7 +926,7 @@ function update( $args, $assoc_args ) { } - if ( ! empty( $update ) && ( $update->version != $wp_version || \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) ) ) { + if ( ! empty( $update ) && ( $update->version != $wp_version || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); diff --git a/php/commands/media.php b/php/commands/media.php index 5228ff2a6..a3e856c19 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -162,18 +162,18 @@ function import( $args, $assoc_args = array() ) { } // Set as featured image, if --post_id and --featured_image are set - if ( $assoc_args['post_id'] && \WP_CLI\Utils\check_flag( $assoc_args, 'featured_image' ) ) { + if ( $assoc_args['post_id'] && \WP_CLI\Utils\get_flag_value( $assoc_args, 'featured_image' ) ) { update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); } $attachment_success_text = ''; if ( $assoc_args['post_id'] ) { $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'featured_image' ) ) + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'featured_image' ) ) $attachment_success_text .= ' as featured image'; } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $success ); } else { WP_CLI::success( sprintf( diff --git a/php/commands/menu.php b/php/commands/menu.php index afab17d3e..e21471104 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -51,7 +51,7 @@ public function create( $args, $assoc_args ) { } else { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $menu_id ); } else { WP_CLI::success( "Created menu $menu_id." ); diff --git a/php/commands/option.php b/php/commands/option.php index 142847ab1..ff6cadc63 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -64,7 +64,7 @@ public function add( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'autoload', 'no' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'autoload' ) === 'no' ) { $autoload = 'no'; } else { $autoload = 'yes'; @@ -139,7 +139,7 @@ public function list_( $args, $assoc_args ) { $fields = explode( ',', $assoc_args['fields'] ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'total_bytes' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { $fields = array( 'size_bytes' ); $size_query = ",SUM(LENGTH(option_value)) AS `size_bytes`"; } @@ -162,7 +162,7 @@ public function list_( $args, $assoc_args ) { ) ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'format', 'total_bytes' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { WP_CLI::line( $results[0]->size_bytes ); } else { $formatter = new \WP_CLI\Formatter( diff --git a/php/commands/plugin.php b/php/commands/plugin.php index bafdb8ad2..ebf37da0a 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -153,9 +153,9 @@ protected function get_all_items() { * : If set, the plugin will be activated for the entire multisite network. */ function activate( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $args = array_map( function( $file ){ return Utils\get_plugin_name( $file ); }, array_keys( get_plugins() ) ); @@ -201,8 +201,8 @@ function activate( $args, $assoc_args = array() ) { * : If set, the plugin will be deactivated for the entire multisite network. */ function deactivate( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); - $disable_all = \WP_CLI\Utils\check_flag( $assoc_args, 'all' ); + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); + $disable_all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); if ( $disable_all ) { $args = array_map( function( $file ){ @@ -242,7 +242,7 @@ function deactivate( $args, $assoc_args = array() ) { * : If set, the plugin will be toggled for the entire multisite network. */ function toggle( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ); + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->check_active( $plugin->file, $network_wide ) ) { @@ -277,7 +277,7 @@ function path( $args, $assoc_args ) { $plugin = $this->fetcher->get_check( $args[0] ); $path .= '/' . $plugin->file; - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'dir' ) ) + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dir' ) ) $path = dirname( $path ); } @@ -297,13 +297,13 @@ protected function install_from_repo( $slug, $assoc_args ) { $status = install_plugin_install_status( $api ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && 'install' != $status['status'] ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && 'install' != $status['status'] ) { // We know this will fail, so avoid a needless download of the package. return new WP_Error( 'already_installed', 'Plugin already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'version', 'dev' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) === 'dev' ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); @@ -503,7 +503,7 @@ function uninstall( $args, $assoc_args = array() ) { uninstall_plugin( $plugin->file ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { WP_CLI::success( "Uninstalled and deleted '$plugin->name' plugin." ); } else { WP_CLI::success( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); diff --git a/php/commands/post.php b/php/commands/post.php index f4e286c28..7a149bcd5 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -55,7 +55,7 @@ public function create( $args, $assoc_args ) { $assoc_args['post_content'] = $this->read_from_file_or_stdin( $args[0] ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'edit' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'edit' ) ) { $input = isset( $assoc_args['post_content'] ) ? $assoc_args['post_content'] : ''; @@ -361,7 +361,7 @@ public function generate( $args, $assoc_args ) { $post_author = $user_fetcher->get_check( $post_author )->ID; } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'post_content' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'post_content' ) ) { $post_content = file_get_contents( 'php://stdin' ); } diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index bea5dfd5f..f7df4ff5a 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -28,10 +28,10 @@ class Rewrite_Command extends WP_CLI_Command { public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); } - flush_rewrite_rules( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) ); + flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); if ( ! get_option( 'rewrite_rules' ) ) { WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); } @@ -115,7 +115,7 @@ public function structure( $args, $assoc_args ) { // Launch a new process to flush rewrites because core expects flush // to happen after rewrites are set $new_assoc_args = array(); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'hard' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ) { $new_assoc_args['hard'] = true; if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); diff --git a/php/commands/role.php b/php/commands/role.php index b12ed8ad0..436fb689a 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -169,7 +169,7 @@ public function reset( $args, $assoc_args ) { self::persistence_check(); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) WP_CLI::error( "Role key not provided, or is invalid." ); if ( ! function_exists( 'populate_roles' ) ) { @@ -179,7 +179,7 @@ public function reset( $args, $assoc_args ) { // get our default roles $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { foreach( $default_roles as $role ) { remove_role( $role ); } diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 85ffba8ff..a6d6a4e83 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -211,7 +211,7 @@ function _s( $args, $assoc_args ) { $body['underscoresme_description'] = $theme_description; $body['underscoresme_generate_submit'] = "Generate"; $body['underscoresme_generate'] = "1"; - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'sassify' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'sassify' ) ) { $body['underscoresme_sass'] = 1; } @@ -244,9 +244,9 @@ function _s( $args, $assoc_args ) { WP_CLI::error( "Could not decompress your theme files ('{$tmpfname}') at '{$theme_path}': {$unzip_result->get_error_message()}" ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'enable-network' ) ) { + } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'enable-network' ) ) { WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); } } @@ -305,9 +305,9 @@ function child_theme( $args, $assoc_args ) { WP_CLI::success( "Created $theme_dir" ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'enable-network' ) ) { + } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'enable-network' ) ) { WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); } } @@ -477,13 +477,13 @@ function plugin( $args, $assoc_args ) { WP_CLI::success( "Created $plugin_dir" ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'skip-tests' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir ) ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); - } else if ( \WP_CLI\Utils\check_flag( $assoc_args, 'activate-network' ) ) { + } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate-network' ) ) { WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug), array( 'network' => true ) ); } } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 195cb0a7a..630767439 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -64,9 +64,9 @@ public function __invoke( $args, $assoc_args ) { $new = array_shift( $args ); $total = 0; $report = array(); - $dry_run = \WP_CLI\Utils\check_flag( $assoc_args, 'dry-run' ); - $php_only = \WP_CLI\Utils\check_flag( $assoc_args, 'precise' ); - $recurse_objects = \WP_CLI\Utils\check_flag( $assoc_args, 'recurse-objects' ); + $dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); + $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); + $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects' ); if ( isset( $assoc_args['skip-columns'] ) ) { $skip_columns = explode( ',', $assoc_args['skip-columns'] ); @@ -79,13 +79,13 @@ public function __invoke( $args, $assoc_args ) { // Determine how to limit the list of tables. Defaults to 'wordpress' $table_type = 'wordpress'; - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { $table_type = 'network'; } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all-tables-with-prefix' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all-tables-with-prefix' ) ) { $table_type = 'all-tables-with-prefix'; } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all-tables' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all-tables' ) ) { $table_type = 'all-tables'; } diff --git a/php/commands/shell.php b/php/commands/shell.php index d805a2d8e..0bb052ff5 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -21,7 +21,7 @@ public function __invoke( $_, $assoc_args ) { '\\WP_CLI\\REPL', ); - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'basic' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'basic' ) ) { $class = '\\WP_CLI\\REPL'; } else { foreach ( $implementations as $candidate ) { diff --git a/php/commands/site.php b/php/commands/site.php index e42e9c577..545f33b9c 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -178,7 +178,7 @@ function delete( $args, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl site?", $assoc_args ); - wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\check_flag( $assoc_args, 'keep-tables' ) ); + wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'keep-tables' ) ); WP_CLI::success( "The site at $blog->siteurl was deleted." ); } @@ -231,7 +231,7 @@ public function create( $_, $assoc_args ) { $network = $current_site; } - $public = ! \WP_CLI\Utils\check_flag( $assoc_args, 'private' ); + $public = ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'private' ); // Sanitize if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { @@ -301,7 +301,7 @@ public function create( $_, $assoc_args ) { WP_CLI::error( $id->get_error_message() ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) WP_CLI::line( $id ); else WP_CLI::success( "Site $id created: $url" ); diff --git a/php/commands/term.php b/php/commands/term.php index 46a005e63..31cedcec9 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -114,7 +114,7 @@ public function create( $args, $assoc_args ) { ); $assoc_args = wp_parse_args( $assoc_args, $defaults ); - $porcelain = \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ); + $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); unset( $assoc_args['porcelain'] ); // Compatibility for < WP 4.0 diff --git a/php/commands/theme.php b/php/commands/theme.php index 4ef1ced63..b074d5e6e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -260,7 +260,7 @@ public function path( $args, $assoc_args ) { $path = $theme->get_stylesheet_directory(); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'dir' ) ) + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'dir' ) ) $path .= '/style.css'; } @@ -278,13 +278,13 @@ protected function install_from_repo( $slug, $assoc_args ) { self::alter_api_response( $api, $assoc_args['version'] ); } - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'force' ) && wp_get_theme( $slug )->exists() ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && wp_get_theme( $slug )->exists() ) { // We know this will fail, so avoid a needless download of the package. return new WP_Error( 'already_installed', 'Theme already installed.' ); } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'version', 'dev' ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) === 'dev' ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); @@ -597,11 +597,11 @@ class Theme_Mod_command extends WP_CLI_Command { */ public function get( $args = array(), $assoc_args = array() ) { - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { WP_CLI::error( "You must specify at least one mod or use --all." ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $args = array(); } @@ -657,11 +657,11 @@ public function get( $args = array(), $assoc_args = array() ) { */ public function remove( $args = array(), $assoc_args = array() ) { - if ( ! \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) && empty( $args ) ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { WP_CLI::error( "You must specify at least one mod or use --all." ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'all' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { remove_theme_mods(); WP_CLI::success( 'Theme mods removed.' ); return; diff --git a/php/commands/user.php b/php/commands/user.php index 9d1ecb8d0..d4fdd39fb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -81,7 +81,7 @@ public function __construct() { */ public function list_( $args, $assoc_args ) { - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { if ( ! is_multisite() ) { WP_CLI::error( 'This is not a multisite install.' ); } @@ -175,7 +175,7 @@ public function get( $args, $assoc_args ) { * wp user delete 123 --reassign=567 */ public function delete( $args, $assoc_args ) { - $network = \WP_CLI\Utils\check_flag( $assoc_args, 'network' ) && is_multisite(); + $network = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); $reassign = isset( $assoc_args['reassign'] ) ? $assoc_args['reassign'] : null; if ( $network && $reassign ) { @@ -304,7 +304,7 @@ public function create( $args, $assoc_args ) { $user_id = wp_insert_user( $user ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'send-email' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { wp_new_user_notification( $user_id, $user->user_pass ); } @@ -317,7 +317,7 @@ public function create( $args, $assoc_args ) { } } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'porcelain' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $user_id ); } else { WP_CLI::success( "Created user $user_id." ); @@ -685,7 +685,7 @@ public function import_csv( $args, $assoc_args ) { $existing_user = get_user_by( 'login', $new_user['user_login'] ); } - if ( $existing_user && \WP_CLI\Utils\check_flag( $assoc_args, 'skip-update' ) ) { + if ( $existing_user && \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-update' ) ) { WP_CLI::log( "{$existing_user->user_login} exists and has been skipped" ); continue; @@ -725,7 +725,7 @@ public function import_csv( $args, $assoc_args ) { $user_id = wp_insert_user( $new_user ); } - if ( \WP_CLI\Utils\check_flag( $assoc_args, 'send-email' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { wp_new_user_notification( $user_id, $new_user['user_pass'] ); } } diff --git a/php/utils.php b/php/utils.php index 45b36ee99..21bad5bb9 100644 --- a/php/utils.php +++ b/php/utils.php @@ -506,13 +506,13 @@ function increment_version( $current_version, $new_version ) { } /** - * Check if the flag is set and has the expected value. + * Return the flag value or, if it's not set, the $default value. * - * @param array $args The arguments array to check. - * @param string $flag The flag to check for. - * @param mixed $expected The expected value for the flag. Default: TRUE - * @return bool + * @param array $args Arguments array. + * @param string $flag Flag to get the value. + * @param mixed $default Default value for the flag. Default: NULL + * @return mixed */ -function check_flag( $args, $flag, $expected = true ) { - return isset( $args[ $flag ] ) && ( $args[ $flag ] === $expected ); -} +function get_flag_value( $args, $flag, $default = null ) { + return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; +} \ No newline at end of file From 47d3f61911e5ad890149accc7d9bf366f46782b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Tue, 21 Apr 2015 19:26:41 -0400 Subject: [PATCH 3523/5359] Refactor additional entries to use the `\WP_CLI\Utils\get_flag_value` function --- php/Spyc.php | 2 +- php/WP_CLI/CommandWithUpgrade.php | 2 +- php/class-wp-cli.php | 19 ++++++++---------- php/commands/cache.php | 24 +++++++++++------------ php/commands/comment.php | 2 +- php/commands/core.php | 6 +++--- php/commands/cron.php | 6 +++--- php/commands/db.php | 2 +- php/commands/menu.php | 10 ++++------ php/commands/post.php | 3 +-- php/commands/scaffold.php | 4 +--- php/commands/search-replace.php | 6 +----- php/commands/site.php | 2 +- php/commands/transient.php | 2 +- php/commands/user.php | 29 ++++++++++++---------------- php/commands/widget.php | 2 +- php/export/class-wp-export-query.php | 2 +- 17 files changed, 53 insertions(+), 70 deletions(-) diff --git a/php/Spyc.php b/php/Spyc.php index 4227b3ed9..7a0c28284 100644 --- a/php/Spyc.php +++ b/php/Spyc.php @@ -755,7 +755,7 @@ private function addArray ($incoming_data, $incoming_indent) { return $this->addArrayInline ($incoming_data, $incoming_indent); $key = key ($incoming_data); - $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + $value = \WP_CLI\Utils\get_flag_value( $incoming_data, $key ); if ($key === '__!YAMLZero') $key = '0'; if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index ed1d7214b..ee113cfa0 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -394,7 +394,7 @@ protected function _search( $args, $assoc_args ) { $items = $api->$plural; - $count = isset( $api->info['results'] ) ? $api->info['results'] : 'unknown'; + $count = \WP_CLI\Utils\get_flag_value( $api->info, 'results', 'unknown' ); \WP_CLI::success( sprintf( 'Showing %s of %s %s.', count( $items ), $count, $plural ) ); $formatter->display_items( $items ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 2dcd96680..e721c6327 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -99,7 +99,7 @@ public static function set_url( $url ) { private static function set_url_params( $url_parts ) { $f = function( $key ) use ( $url_parts ) { - return isset( $url_parts[ $key ] ) ? $url_parts[ $key ] : ''; + return \WP_CLI\Utils\get_flag_value( $url_parts, $key, '' ); }; if ( isset( $url_parts['host'] ) ) { @@ -116,7 +116,7 @@ private static function set_url_params( $url_parts ) { } $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); - $_SERVER['SERVER_PORT'] = isset( $url_parts['port'] ) ? $url_parts['port'] : '80'; + $_SERVER['SERVER_PORT'] = \WP_CLI\Utils\get_flag_value( $url_parts, 'port', '80' ); $_SERVER['QUERY_STRING'] = $f('query'); } @@ -295,15 +295,12 @@ public static function confirm( $question, $assoc_args = array() ) { * @return string */ public static function get_value_from_arg_or_stdin( $args, $index ) { - if ( isset( $args[ $index ] ) ) { - $raw_value = $args[ $index ]; - } else { - // We don't use file_get_contents() here because it doesn't handle - // Ctrl-D properly, when typing in the value interactively. - $raw_value = ''; - while ( ( $line = fgets( STDIN ) ) !== false ) { - $raw_value .= $line; - } + $raw_value = \WP_CLI\Utils\get_flag_value( $args, $index, '' ); + + // We don't use file_get_contents() here because it doesn't handle + // Ctrl-D properly, when typing in the value interactively. + while ( ( $line = fgets( STDIN ) ) !== false ) { + $raw_value .= $line; } return $raw_value; diff --git a/php/commands/cache.php b/php/commands/cache.php index 0c9274811..c78ce1ce4 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -19,9 +19,9 @@ class Cache_Command extends WP_CLI_Command { public function add( $args, $assoc_args ) { list( $key, $value ) = $args; - $group = ( isset( $args[2] ) ) ? $args[2] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); if ( ! wp_cache_add( $key, $value, $group, $expiration ) ) { WP_CLI::error( "Could not add object '$key' in group '$group'. Does it already exist?" ); @@ -38,9 +38,9 @@ public function add( $args, $assoc_args ) { public function decr( $args, $assoc_args ) { $key = $args[0]; - $offset = ( isset( $args[1] ) ) ? $args[1] : 1; + $offset = \WP_CLI\Utils\get_flag_value( $args, 1, 1 ); - $group = ( isset( $args[2] ) ) ? $args[2] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); $value = wp_cache_decr( $key, $offset, $group ); @@ -59,7 +59,7 @@ public function decr( $args, $assoc_args ) { public function delete( $args, $assoc_args ) { $key = $args[0]; - $group = ( isset( $args[1] ) ) ? $args[1] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 1, '' ); $result = wp_cache_delete( $key, $group ); @@ -91,7 +91,7 @@ public function flush( $args, $assoc_args ) { public function get( $args, $assoc_args ) { $key = $args[0]; - $group = ( isset( $args[1] ) ) ? $args[1] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 1, '' ); $value = wp_cache_get( $key, $group ); @@ -110,9 +110,9 @@ public function get( $args, $assoc_args ) { public function incr( $args, $assoc_args ) { $key = $args[0]; - $offset = ( isset( $args[1] ) ) ? $args[1] : 1; + $offset = \WP_CLI\Utils\get_flag_value( $args, 1, 1 ); - $group = ( isset( $args[2] ) ) ? $args[2] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); $value = wp_cache_incr( $key, $offset, $group ); @@ -131,9 +131,9 @@ public function incr( $args, $assoc_args ) { public function replace( $args, $assoc_args ) { list( $key, $value ) = $args; - $group = ( isset( $args[2] ) ) ? $args[2] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); $result = wp_cache_replace( $key, $value, $group, $expiration ); @@ -152,9 +152,9 @@ public function replace( $args, $assoc_args ) { public function set( $args, $assoc_args ) { list( $key, $value ) = $args; - $group = ( isset( $args[2] ) ) ? $args[2] : ''; + $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - $expiration = ( isset( $args[3] ) ) ? $args[3] : 0; + $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); $result = wp_cache_set( $key, $value, $group, $expiration ); diff --git a/php/commands/comment.php b/php/commands/comment.php index 2aac405a4..4b16eca07 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -353,7 +353,7 @@ public function unapprove( $args, $assoc_args ) { * wp comment count 42 */ public function count( $args, $assoc_args ) { - $post_id = isset( $args[0] ) ? $args[0] : 0; + $post_id = \WP_CLI\Utils\get_flag_value( $args, 0, 0 ); $count = wp_count_comments( $post_id ); diff --git a/php/commands/core.php b/php/commands/core.php index 43a040c22..fc3d791cf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -130,7 +130,7 @@ public function download( $args, $assoc_args ) { WP_CLI::launch( Utils\esc_cmd( $mkdir, ABSPATH ) ); } - $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : 'en_US'; + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); if ( isset( $assoc_args['version'] ) ) { $version = $assoc_args['version']; @@ -877,7 +877,7 @@ function update( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; - $version = ! empty( $assoc_args['version'] ) ? $assoc_args['version'] : null; + $version = \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ); $update = (object) array( 'response' => 'upgrade', @@ -906,7 +906,7 @@ function update( $args, $assoc_args ) { || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { $version = $assoc_args['version']; - $locale = isset( $assoc_args['locale'] ) ? $assoc_args['locale'] : get_locale(); + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); $new_package = $this->get_download_url($version, $locale); diff --git a/php/commands/cron.php b/php/commands/cron.php index b9b4ed0cb..7025c26b2 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -94,8 +94,8 @@ public function list_( $args, $assoc_args ) { public function schedule( $args, $assoc_args ) { $hook = $args[0]; - $next_run = ( isset( $args[1] ) ) ? $args[1] : 'now'; - $recurrence = ( isset( $args[2] ) ) ? $args[2] : false; + $next_run = \WP_CLI\Utils\get_flag_value( $args, 1, 'now' ); + $recurrence = \WP_CLI\Utils\get_flag_value( $args, 2, false ); if ( empty( $next_run ) ) { $timestamp = time(); @@ -294,7 +294,7 @@ protected static function get_cron_events() { 'sig' => $sig, 'args' => $data['args'], 'schedule' => $data['schedule'], - 'interval' => isset( $data['interval'] ) ? $data['interval'] : null, + 'interval' => \WP_CLI\Utils\get_flag_value( $data, 'interval' ), ); } diff --git a/php/commands/db.php b/php/commands/db.php index e6f01bfa1..956c9647c 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -215,7 +215,7 @@ function import( $args, $assoc_args ) { function tables( $args, $assoc_args ) { global $wpdb; - $scope = isset( $assoc_args['scope'] ) ? $assoc_args['scope'] : 'all'; + $scope = \WP_CLI\Utils\get_flag_value( $assoc_args, 'scope', 'all' ); $tables = $wpdb->tables( $scope ); diff --git a/php/commands/menu.php b/php/commands/menu.php index e21471104..240427580 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -495,7 +495,7 @@ public function delete( $args, $_ ) { private function add_or_update_item( $method, $type, $args, $assoc_args ) { $menu = $args[0]; - $menu_item_db_id = ( isset( $args[1] ) ) ? $args[1] : 0; + $menu_item_db_id = \WP_CLI\Utils\get_flag_value( $args, 1, 0 ); $menu = wp_get_nav_menu_object( $menu ); if ( ! $menu || is_wp_error( $menu ) ) { @@ -503,9 +503,7 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { } // `url` is protected in WP-CLI, so we use `link` instead - if ( isset( $assoc_args['link'] ) ) { - $assoc_args['url'] = $assoc_args['link']; - } + $assoc_args['url'] = \WP_CLI\Utils\get_flag_value( $assoc_args, 'link' ); // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 if ( 'update' == $method ) { @@ -557,7 +555,7 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) { foreach( $default_args as $key => $default_value ) { // wp_update_nav_menu_item() has a weird argument prefix $new_key = 'menu-item-' . $key; - $menu_item_args[ $new_key ] = isset( $assoc_args[ $key ] ) ? $assoc_args[ $key ] : $default_value; + $menu_item_args[ $new_key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $default_value ); } $menu_item_args['menu-item-type'] = $type; @@ -717,7 +715,7 @@ public function remove( $args, $_ ) { } $locations = get_nav_menu_locations(); - if ( ! isset( $locations[ $location ] ) || $locations[ $location ] != $menu->term_id ) { + if ( \WP_CLI\Utils\get_flag_value( $locations, $location ) != $menu->term_id ) { WP_CLI::error( "Menu isn't assigned to location." ); } diff --git a/php/commands/post.php b/php/commands/post.php index 7a149bcd5..e0ae7a855 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -56,8 +56,7 @@ public function create( $args, $assoc_args ) { } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'edit' ) ) { - $input = isset( $assoc_args['post_content'] ) ? - $assoc_args['post_content'] : ''; + $input = \WP_CLI\Utils\get_flag_value( $assoc_args, 'post_content', '' ); if ( $output = $this->_edit( $input, 'WP-CLI: New Post' ) ) $assoc_args['post_content'] = $output; diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a6d6a4e83..b51a9b8b4 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -652,9 +652,7 @@ protected function extract_args( $assoc_args, $defaults ) { $out = array(); foreach ( $defaults as $key => $value ) { - $out[ $key ] = isset( $assoc_args[ $key ] ) - ? $assoc_args[ $key ] - : $value; + $out[ $key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $value ); } return $out; diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 630767439..54008e984 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -68,11 +68,7 @@ public function __invoke( $args, $assoc_args ) { $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects' ); - if ( isset( $assoc_args['skip-columns'] ) ) { - $skip_columns = explode( ',', $assoc_args['skip-columns'] ); - } else { - $skip_columns = array(); - } + $skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); // never mess with hashed passwords $skip_columns[] = 'user_pass'; diff --git a/php/commands/site.php b/php/commands/site.php index 545f33b9c..cbdf6ac18 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -216,7 +216,7 @@ public function create( $_, $assoc_args ) { global $wpdb, $current_site; $base = $assoc_args['slug']; - $title = isset( $assoc_args['title'] ) ? $assoc_args['title'] : ucfirst( $base ); + $title = \WP_CLI\Utils\get_flag_value( $assoc_args, 'title', ucfirst( $base ) ); $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; diff --git a/php/commands/transient.php b/php/commands/transient.php index 16248d454..3ea4b19b0 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -35,7 +35,7 @@ public function get( $args, $assoc_args ) { public function set( $args ) { list( $key, $value ) = $args; - $expiration = isset( $args[2] ) ? $args[2] : 0; + $expiration = \WP_CLI\Utils\get_flag_value( $args, 2, 0 ); if ( set_transient( $key, $value, $expiration ) ) WP_CLI::success( 'Transient added.' ); diff --git a/php/commands/user.php b/php/commands/user.php index d4fdd39fb..52a73d49b 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -176,7 +176,7 @@ public function get( $args, $assoc_args ) { */ public function delete( $args, $assoc_args ) { $network = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); - $reassign = isset( $assoc_args['reassign'] ) ? $assoc_args['reassign'] : null; + $reassign = \WP_CLI\Utils\get_flag_value( $assoc_args, 'reassign' ); if ( $network && $reassign ) { WP_CLI::error('Reassigning content to a different user is not supported on multisite.'); @@ -259,17 +259,17 @@ public function create( $args, $assoc_args ) { WP_CLI::error( "The '{$user->user_email}' email address is invalid." ); } - $user->user_registered = isset( $assoc_args['user_registered'] ) - ? $assoc_args['user_registered'] : strftime( "%F %T", current_time('timestamp') ); + $user->user_registered = \WP_CLI\Utils\get_flag_value( + $assoc_args, + 'user_registered', + strftime( "%F %T", current_time('timestamp') ) + ); - $user->display_name = isset( $assoc_args['display_name'] ) - ? $assoc_args['display_name'] : false; + $user->display_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'display_name', false ); - $user->first_name = isset( $assoc_args['first_name'] ) - ? $assoc_args['first_name'] : false; + $user->first_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'first_name', false ); - $user->last_name = isset( $assoc_args['last_name'] ) - ? $assoc_args['last_name'] : false; + $user->last_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'last_name', false ); if ( isset( $assoc_args['user_pass'] ) ) { $user->user_pass = $assoc_args['user_pass']; @@ -278,13 +278,8 @@ public function create( $args, $assoc_args ) { $generated_pass = true; } - if ( isset( $assoc_args['role'] ) ) { - $role = $assoc_args['role']; - self::validate_role( $role ); - } else { - $role = get_option('default_role'); - } - $user->role = $role; + $user->role = \WP_CLI\Utils\get_flag_value( $assoc_args, 'role', get_option('default_role') ); + self::validate_role( $user->role ); if ( is_multisite() ) { $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); @@ -432,7 +427,7 @@ public function generate( $args, $assoc_args ) { public function set_role( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); - $role = isset( $args[1] ) ? $args[1] : get_option( 'default_role' ); + $role = \WP_CLI\Utils\get_flag_value( $args, 1, get_option('default_role') ); self::validate_role( $role ); diff --git a/php/commands/widget.php b/php/commands/widget.php index af8a0a88d..81064269b 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -97,7 +97,7 @@ public function list_( $args, $assoc_args ) { public function add( $args, $assoc_args ) { list( $name, $sidebar_id ) = $args; - $position = ( isset( $args[2] ) ) ? (int) $args[2] - 1 : 0; + $position = \WP_CLI\Utils\get_flag_value( $args, 2, 1 ) - 1; $this->validate_sidebar( $sidebar_id ); if ( false == ( $widget = $this->get_widget_obj( $name ) ) ) { diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 95c176c75..381b7bfdc 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -118,7 +118,7 @@ public function nav_menu_terms() { public function exportify_post( $post ) { $GLOBALS['wp_query']->in_the_loop = true; - $previous_global_post = isset( $GLOBALS['post'] )? $GLOBALS['post'] : null; + $previous_global_post = \WP_CLI\Utils\get_flag_value( $GLOBALS, 'post' ); $GLOBALS['post'] = $post; setup_postdata( $post ); $post->post_content = apply_filters( 'the_content_export', $post->post_content ); From b6a57ede3c5b1d3f8baec7e74fff23ba95cd2ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wendell=20J=C3=BAnior?= <wrnx00@gmail.com> Date: Tue, 21 Apr 2015 21:53:59 -0400 Subject: [PATCH 3524/5359] Reverse incorrect changes and fix some --- php/class-wp-cli.php | 15 +++++++++------ php/commands/core.php | 2 +- php/commands/plugin.php | 2 +- php/commands/theme.php | 2 +- php/utils.php | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e721c6327..44bf9ace5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -295,12 +295,15 @@ public static function confirm( $question, $assoc_args = array() ) { * @return string */ public static function get_value_from_arg_or_stdin( $args, $index ) { - $raw_value = \WP_CLI\Utils\get_flag_value( $args, $index, '' ); - - // We don't use file_get_contents() here because it doesn't handle - // Ctrl-D properly, when typing in the value interactively. - while ( ( $line = fgets( STDIN ) ) !== false ) { - $raw_value .= $line; + if ( isset( $args[ $index ] ) ) { + $raw_value = $args[ $index ]; + } else { + // We don't use file_get_contents() here because it doesn't handle + // Ctrl-D properly, when typing in the value interactively. + $raw_value = ''; + while ( ( $line = fgets( STDIN ) ) !== false ) { + $raw_value .= $line; + } } return $raw_value; diff --git a/php/commands/core.php b/php/commands/core.php index fc3d791cf..d5f5d3c5d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -350,7 +350,7 @@ public function config( $_, $assoc_args ) { ) ); } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra-php' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra-php' ) === true ) { $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index ebf37da0a..568eaa3db 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -303,7 +303,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) === 'dev' ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) != 'dev' ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); diff --git a/php/commands/theme.php b/php/commands/theme.php index b074d5e6e..4786a8dec 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -284,7 +284,7 @@ protected function install_from_repo( $slug, $assoc_args ) { } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) === 'dev' ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) != 'dev' ) { WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); } $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); diff --git a/php/utils.php b/php/utils.php index 21bad5bb9..a16a7a669 100644 --- a/php/utils.php +++ b/php/utils.php @@ -514,5 +514,5 @@ function increment_version( $current_version, $new_version ) { * @return mixed */ function get_flag_value( $args, $flag, $default = null ) { - return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; -} \ No newline at end of file + return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; +} From 352d3c4883da6572ccfadd8aab80498d971af629 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 05:57:21 -0700 Subject: [PATCH 3525/5359] Periodically clear object cache on import WordPress' internal object cache can grow until all memory is consumed because cache invalidation is disabled. On large imports, this can fatal the import. --- php/commands/import.php | 12 ++++++++++-- php/utils-wp.php | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index d31d36d59..f63df2f5c 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -171,10 +171,18 @@ private function add_wxr_filters() { } ); add_action( 'wp_import_insert_post', function( $post_id, $original_post_ID, $post, $postdata ) { - if ( is_wp_error( $post_id ) ) + global $wpcli_import_counts; + if ( is_wp_error( $post_id ) ) { WP_CLI::warning( "-- Error importing post: " . $post_id->get_error_code() ); - else + } else { WP_CLI::line( "-- Imported post as post_id #{$post_id}" ); + } + + if ( $wpcli_import_counts['current_post'] % 500 === 0 ) { + WP_CLI\Utils\wp_clear_object_cache(); + WP_CLI::line( "-- Cleared object cache." ); + } + }, 10, 4 ); add_action( 'wp_import_insert_term', function( $t, $import_term, $post_id, $post ) { diff --git a/php/utils-wp.php b/php/utils-wp.php index b9ee33c19..8501ce7ad 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -131,3 +131,25 @@ function wp_register_unused_sidebar() { )); } + +/** + * Clear all of the caches for memory management + */ +function wp_clear_object_cache() { + global $wpdb, $wp_object_cache; + + $wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); + + if ( ! is_object( $wp_object_cache ) ) { + return; + } + + $wp_object_cache->group_ops = array(); + $wp_object_cache->stats = array(); + $wp_object_cache->memcache_debug = array(); + $wp_object_cache->cache = array(); + + if ( is_callable( $wp_object_cache, '__remoteset' ) ) { + $wp_object_cache->__remoteset(); // important + } +} From 8a838b1750e1f59c76173aa281f50d570370f4f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 06:33:18 -0700 Subject: [PATCH 3526/5359] Ensure the parent doesn't actually exist Sometimes WordPress installs the parent for us --- features/theme.feature | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index 040d4e6bc..a40800555 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -228,8 +228,10 @@ Feature: Manage WordPress themes Scenario: Install and attempt to activate a child theme without its parent Given a WP install + And I run `wp theme install biker` + And I run `rm -rf wp-content/themes/jolene` - When I try `wp theme install biker --activate` + When I try `wp theme activate biker` Then STDERR should contain: """ Error: The 'biker' theme cannot be activated without its parent, 'jolene'. From 57c45a5a2eda5098280653e519e5775890f80080 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 07:15:24 -0700 Subject: [PATCH 3527/5359] Deactivate and uninstall a plugin in one go Adds `--uninstall` flag to `wp plugin deactivate` --- features/plugin.feature | 22 ++++++++++++++++++++++ php/commands/plugin.php | 9 +++++++++ 2 files changed, 31 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index 1436c2325..abaa0ba53 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -282,6 +282,28 @@ Feature: Manage WordPress plugins must-use """ + Scenario: Deactivate and uninstall a plugin + Given a WP install + And these installed and active plugins: + """ + akismet + """ + + When I run `wp plugin deactivate akismet --uninstall` + Then STDOUT should contain: + """ + Success: Plugin 'akismet' deactivated. + Uninstalling 'akismet'... + Success: Uninstalled and deleted 'akismet' plugin. + """ + + When I try `wp plugin get akismet` + Then STDERR should be: + """ + Error: The 'akismet' plugin could not be found. + """ + + Scenario: Uninstall a plugin without deleting Given a WP install diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 568eaa3db..b94a2d11e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -194,6 +194,9 @@ function activate( $args, $assoc_args = array() ) { * [<plugin>...] * : One or more plugins to deactivate. * + * [--uninstall] + * : Uninstall the plugin after deactivation. + * * [--all] * : If set, all plugins will be deactivated. * @@ -227,6 +230,12 @@ function deactivate( $args, $assoc_args = array() ) { deactivate_plugins( $plugin->file, false, $network_wide ); $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uninstall' ) ) { + WP_CLI::log( "Uninstalling '{$plugin->name}'..." ); + $this->uninstall( array( $plugin->name ) ); + } + } } From 91357037c69e14662804e77e3eeb67e7ed18b584 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 07:29:02 -0700 Subject: [PATCH 3528/5359] Support uninstalling with `--deactivate` flag --- features/plugin.feature | 23 ++++++++++++++++++++++- php/commands/plugin.php | 10 +++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index abaa0ba53..cee0eb4a7 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -282,7 +282,7 @@ Feature: Manage WordPress plugins must-use """ - Scenario: Deactivate and uninstall a plugin + Scenario: Deactivate and uninstall a plugin, part one Given a WP install And these installed and active plugins: """ @@ -303,6 +303,27 @@ Feature: Manage WordPress plugins Error: The 'akismet' plugin could not be found. """ + Scenario: Deactivate and uninstall a plugin, part two + Given a WP install + And these installed and active plugins: + """ + akismet + """ + + When I run `wp plugin uninstall akismet --deactivate` + Then STDOUT should contain: + """ + Deactivating 'akismet'... + Success: Plugin 'akismet' deactivated. + Success: Uninstalled and deleted 'akismet' plugin. + """ + + When I try `wp plugin get akismet` + Then STDERR should be: + """ + Error: The 'akismet' plugin could not be found. + """ + Scenario: Uninstall a plugin without deleting Given a WP install diff --git a/php/commands/plugin.php b/php/commands/plugin.php index b94a2d11e..2a941cba6 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -495,6 +495,9 @@ public function get( $args, $assoc_args ) { * <plugin>... * : One or more plugins to uninstall. * + * [--deactivate] + * : Deactivate the plugin before uninstalling. Default behavior is to warn and skip if the plugin is active. + * * [--skip-delete] * : If set, the plugin files will not be deleted. Only the uninstall procedure * will be run. @@ -505,11 +508,16 @@ public function get( $args, $assoc_args ) { */ function uninstall( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - if ( is_plugin_active( $plugin->file ) ) { + if ( is_plugin_active( $plugin->file ) && ! WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { WP_CLI::warning( "The '{$plugin->name}' plugin is active." ); continue; } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { + WP_CLI::log( "Deactivating '{$plugin->name}'..." ); + $this->deactivate( array( $plugin->name ) ); + } + uninstall_plugin( $plugin->file ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { From fc8c25349d77e8db61aa180d947035cb7896aee0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 08:20:24 -0700 Subject: [PATCH 3529/5359] Add `--skip-delete` flag to `wp media regenerate` This allows old thumbnails to remain around afterwards, which can be important on many sites. --- features/media.feature | 61 +++++++++++++++++++++++++++++++++++++++++- php/commands/media.php | 13 ++++++--- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/features/media.feature b/features/media.feature index fa28cff85..d0d0207a5 100644 --- a/features/media.feature +++ b/features/media.feature @@ -52,4 +52,63 @@ Feature: Manage WordPress attachments Then STDOUT should be: """ My imported attachment - """ \ No newline at end of file + """ + + Scenario: Delete existing thumbnails when media is regenerated + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 100, 100, true ); + }); + """ + And I run `wp option update uploads_use_yearmonth_folders 0` + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + And the wp-content/uploads/large-image-100x100.jpg file should exist + + Given a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 200, 200, true ); + }); + """ + When I run `wp media regenerate --yes` + Then STDOUT should not be empty + And the wp-content/uploads/large-image-100x100.jpg file should not exist + And the wp-content/uploads/large-image-200x200.jpg file should exist + + Scenario: Skip deletion of existing thumbnails when media is regenerated + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 100, 100, true ); + }); + """ + And I run `wp option update uploads_use_yearmonth_folders 0` + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + And the wp-content/uploads/large-image-100x100.jpg file should exist + + Given a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 200, 200, true ); + }); + """ + When I run `wp media regenerate --skip-delete --yes` + Then STDOUT should not be empty + And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-200x200.jpg file should exist + diff --git a/php/commands/media.php b/php/commands/media.php index a3e856c19..2c391dcd3 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -15,6 +15,9 @@ class Media_Command extends WP_CLI_Command { * [<attachment-id>...] * : One or more IDs of the attachments to regenerate. * + * [--skip-delete] + * : Skip deletion of the original thumbnails. If your thumbnails are linked from sources outside your control, it's likely best to leave them around. Defaults to false. + * * [--yes] * : Answer yes to the confirmation message. * @@ -31,6 +34,8 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::confirm( 'Do you realy want to regenerate all images?', $assoc_args ); } + $skip_delete = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ); + $query_args = array( 'post_type' => 'attachment', 'post__in' => $args, @@ -53,7 +58,7 @@ function regenerate( $args, $assoc_args = array() ) { _n( 'image', 'images', $count ) ) ); foreach ( $images->posts as $id ) { - $this->_process_regeneration( $id ); + $this->_process_regeneration( $id, $skip_delete ); } WP_CLI::success( sprintf( @@ -198,7 +203,7 @@ private function _make_copy( $path ) { return $filename; } - private function _process_regeneration( $id ) { + private function _process_regeneration( $id, $skip_delete = false ) { $image = get_post( $id ); $fullsizepath = get_attached_file( $image->ID ); @@ -210,7 +215,9 @@ private function _process_regeneration( $id ) { return; } - $this->remove_old_images( $image->ID ); + if ( ! $skip_delete ) { + $this->remove_old_images( $image->ID ); + } $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); if ( is_wp_error( $metadata ) ) { From 08d25c5567439924b34b07ff364ecabf02e22a20 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 10:15:55 -0700 Subject: [PATCH 3530/5359] Update tests to acknowledge WordPress 4.2 --- features/core.feature | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 046eca25d..e0f351cac 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,6 +326,7 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | @@ -334,12 +335,13 @@ Feature: Manage WordPress installation When I run `wp core check-update --format=count` Then STDOUT should be: """ - 4 + 5 """ When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | @@ -347,7 +349,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --major --format=count` Then STDOUT should be: """ - 3 + 4 """ When I run `wp core check-update --minor` From cb90a740a22cf63b724109e608c603e8166c4f2d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 14:37:36 -0700 Subject: [PATCH 3531/5359] Update test cases to fail for child themes --- features/theme.feature | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index a40800555..c8557e468 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -128,73 +128,72 @@ Feature: Manage WordPress themes Scenario: Enabling and disabling a theme Given a WP multisite install - - When I run `wp theme install p2` - Then STDOUT should not be empty + And I run `wp theme install jolene` + And I run `wp theme install biker` When I try `wp option get allowedthemes` Then the return code should be 1 And STDERR should be empty - When I run `wp theme enable p2` + When I run `wp theme enable biker` Then STDOUT should contain: """ - Success: Enabled the 'P2' theme. + Success: Enabled the 'Biker' theme. """ When I run `wp option get allowedthemes` Then STDOUT should contain: """ - 'p2' => true + 'biker' => true """ - When I run `wp theme disable p2` + When I run `wp theme disable biker` Then STDOUT should contain: """ - Success: Disabled the 'P2' theme. + Success: Disabled the 'Biker' theme. """ When I run `wp option get allowedthemes` Then STDOUT should not contain: """ - 'p2' => true + 'biker' => true """ - When I run `wp theme enable p2 --activate` + When I run `wp theme enable biker --activate` Then STDOUT should contain: """ - Success: Enabled the 'P2' theme. - Success: Switched to 'P2' theme. + Success: Enabled the 'Biker' theme. + Success: Switched to 'Biker' theme. """ When I run `wp network-meta get 1 allowedthemes` Then STDOUT should not contain: """ - 'p2' => true + 'biker' => true """ - When I run `wp theme enable p2 --network` + When I run `wp theme enable biker --network` Then STDOUT should contain: """ - Success: Network enabled the 'P2' theme. + Success: Network enabled the 'Biker' theme. """ When I run `wp network-meta get 1 allowedthemes` Then STDOUT should contain: """ - 'p2' => true + 'biker' => true """ - When I run `wp theme disable p2 --network` + When I run `wp theme disable biker --network` Then STDOUT should contain: """ - Success: Network disabled the 'P2' theme. + Success: Network disabled the 'Biker' theme. """ When I run `wp network-meta get 1 allowedthemes` Then STDOUT should not contain: """ - 'p2' => true + 'biker' => true """ Scenario: Enabling and disabling a theme without multisite From 5712d571054a2052e635d7a040e1ccbb58c4842e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 14:38:06 -0700 Subject: [PATCH 3532/5359] Use `stylesheet` to track enabled themes `template` is shared by parent and child themes, which means the child theme couldn't ever be enabled --- php/commands/theme.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index f4cfc9917..254afc949 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -179,7 +179,7 @@ public function enable( $args, $assoc_args ) { $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); if ( empty( $allowed_themes ) ) $allowed_themes = array(); - $allowed_themes[ $theme->get_template() ] = true; + $allowed_themes[ $theme->get_stylesheet() ] = true; call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); if ( ! empty( $assoc_args['network'] ) ) @@ -225,8 +225,8 @@ public function disable( $args, $assoc_args ) { # Add the current theme to the allowed themes option or site option $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); - if ( ! empty( $allowed_themes[ $theme->get_template() ] ) ) - unset( $allowed_themes[ $theme->get_template() ] ); + if ( ! empty( $allowed_themes[ $theme->get_stylesheet() ] ) ) + unset( $allowed_themes[ $theme->get_stylesheet() ] ); call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); if ( ! empty( $assoc_args['network'] ) ) From dea90c52b3f7eca4d3b75a22f8b46ae7f6ce2c89 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 23 Apr 2015 15:23:22 -0700 Subject: [PATCH 3533/5359] Update tests to accommodate yet another core minor release --- features/core.feature | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/core.feature b/features/core.feature index e0f351cac..8c142b580 100644 --- a/features/core.feature +++ b/features/core.feature @@ -327,10 +327,10 @@ Feature: Manage WordPress installation Then STDOUT should be a table containing rows: | version | update_type | package_url | | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | - | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | - | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | - | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | - | 3.8.6 | minor | https://wordpress.org/wordpress-3.8.6.zip | + | 4.1.3 | major | https://wordpress.org/wordpress-4.1.3.zip | + | 4.0.3 | major | https://wordpress.org/wordpress-4.0.3.zip | + | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | + | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -342,9 +342,9 @@ Feature: Manage WordPress installation Then STDOUT should be a table containing rows: | version | update_type | package_url | | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | - | 4.1.2 | major | https://wordpress.org/wordpress-4.1.2.zip | - | 4.0.2 | major | https://wordpress.org/wordpress-4.0.2.zip | - | 3.9.4 | major | https://wordpress.org/wordpress-3.9.4.zip | + | 4.1.3 | major | https://wordpress.org/wordpress-4.1.3.zip | + | 4.0.3 | major | https://wordpress.org/wordpress-4.0.3.zip | + | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -355,7 +355,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.6 | minor | https://wordpress.org/wordpress-3.8.6.zip | + | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From 9f0c9ec312057fe411f8370c52775146e6230572 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 24 Apr 2015 06:39:06 -0700 Subject: [PATCH 3534/5359] Don't require remapify in default plugin Gruntfile It's copy-paste leftovers --- templates/plugin-gruntfile.mustache | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/plugin-gruntfile.mustache b/templates/plugin-gruntfile.mustache index 96dba5e2d..661d0e309 100644 --- a/templates/plugin-gruntfile.mustache +++ b/templates/plugin-gruntfile.mustache @@ -1,7 +1,6 @@ module.exports = function( grunt ) { 'use strict'; - var remapify = require('remapify'); var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n'; // Project configuration grunt.initConfig( { From 9c7b1235322d2ae061f5e513ce4aba48e3aeb27e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 24 Apr 2015 13:38:51 -0700 Subject: [PATCH 3535/5359] Switch indentation to two spaces instead of four --- templates/.travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 8b561acd3..6476f89ba 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -1,16 +1,16 @@ language: php php: - - 5.3 - - 5.5 + - 5.3 + - 5.5 env: - - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.8 WP_MULTISITE=0 - - WP_VERSION=3.8 WP_MULTISITE=1 + - WP_VERSION=latest WP_MULTISITE=0 + - WP_VERSION=latest WP_MULTISITE=1 + - WP_VERSION=3.8 WP_MULTISITE=0 + - WP_VERSION=3.8 WP_MULTISITE=1 before_script: - - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION + - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION script: phpunit From fa2dbff87b2270dcf6dca86b6bba6954c91e09d9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 24 Apr 2015 13:44:53 -0700 Subject: [PATCH 3536/5359] Only notify developers on build failure --- templates/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/.travis.yml b/templates/.travis.yml index 6476f89ba..25a3edb53 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -1,5 +1,9 @@ language: php +notifications: + on_success: never + on_failure: change + php: - 5.3 - 5.5 From 6b9260d6cbec904bfe280367fcd0f6b7ae409652 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 24 Apr 2015 13:51:01 -0700 Subject: [PATCH 3537/5359] Make the matrix smarter about the builds it spawns --- templates/.travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index 25a3edb53..b4393cc7d 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -10,9 +10,11 @@ php: env: - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=latest WP_MULTISITE=1 - - WP_VERSION=3.8 WP_MULTISITE=0 - - WP_VERSION=3.8 WP_MULTISITE=1 + +matrix: + include: + - php: 5.3 + env: WP_VERSION=latest WP_MULTISITE=1 before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION From 966e380584f3b42a746310f16ae15abd231e5743 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 25 Apr 2015 13:54:44 -0700 Subject: [PATCH 3538/5359] Update mailmap --- .mailmap | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.mailmap b/.mailmap index 78ecffe33..23d32791f 100644 --- a/.mailmap +++ b/.mailmap @@ -1,12 +1,18 @@ +2ndkauboy <bernhard@kau-boys.de> Alex Mills <git@viper007bond.com> +Andreas Heigl <andreas@heigl.org> andreascreten <andreas@madewithlove.be> +Andrew Patton <andrew@acusti.ca> +BA <kau@connecticum.de> bartaakos <akos@netpositive.hu> bendoh <ben@thinkoomph.com> +Bobby Walters <bobbymwalters@gmail.com> BoiteAWeb <juliobosk@gmail.com> boonebgorges <boonebgorges@gmail.com> Borek Bernard <borekb@gmail.com> borekb <borekb@gmail.com> Brad Parbs <brad@bradparbs.com> +Brian MacKinney <brian@getpantheon.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> clemens-tolboom <clemens@build2be.com> @@ -14,6 +20,7 @@ conatus <alex@recordsonribs.com> ctayloroomphinc <ctaylor@thinkoomph.com> cyberhobo <dylan.k.kuhn@gmail.com> dangardner <dan@web.nearest.to> +Daniel Bachhuber <daniel.bachhuber@fusion.net> danielbachhuber <d@danielbachhuber.com> danielbachhuber <daniel@handbuilt.co> danielbachhuber <danielbachhuber@gmail.com> @@ -32,8 +39,10 @@ goldenapples <ntaintor@janrain.com> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> jeichorn <joshua.eichorn@pagely.com> +Jeremy Pry <jeremy.pry@gmail.com> jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> +Jim Reevior <jim@thinkoomph.com> jmslbam <jmslbam@gmail.com> johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> @@ -41,6 +50,8 @@ johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> +JQ <JeyKeu@users.noreply.github.com> +Keith Grennan <keith@nearlyfree.org> Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> @@ -57,8 +68,10 @@ mikey dubs <mike@herebox.org> milesj <mileswjohnson@gmail.com> MiteshShah <Mitesh.Shah@rtCamp.com> miya0001 <miya@wpist.me> +Morgan Estes <morgan.estes@gmail.com> mwilliamson <michael.williamson@red-gate.com> mwilliamson <mike@zwobble.org> +mwithheld <vhmark@gmail.com> nacin <andrewnacin@gmail.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> @@ -81,6 +94,7 @@ robertboloc <robertboloc@gmail.com> rodrigoprimo <rodrigo@hacklab.com.br> rodrigoprimo <rodrigosprimo@gmail.com> roelven <roel@soundcloud.com> +Ross Hattori <rhattori@saymedia.com> ryanduff <ryan@fusionized.com> santagada <santagada@gmail.com> sboisvert <stephane.boisvert@automattic.com> @@ -109,9 +123,12 @@ tott <tott@automattic.com> trepmal <trepmal@gmail.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> +Wendell Júnior <wrnx00@gmail.com> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> William Turrell <william@wturrell.co.uk> willmot <tom@humanmade.co.uk> wopr42 <john@zippykid.com> +yivi <ivan@ojiva.es> +yivi <ivan@yivoff.com> ziz <justin@crowdfavorite.com> From 8c54240ec1c9fee352f7c74d8ef151275b1f3d39 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 25 Apr 2015 14:04:29 -0700 Subject: [PATCH 3539/5359] Bump stable to v0.19.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 66333910a..1cf0537c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.18.0 +0.19.0 From 419ac2b00a27e3756fbdcfb1f92a573824df2d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sun, 26 Apr 2015 19:56:41 +0200 Subject: [PATCH 3540/5359] With the new VERSION file version string detection is only possible by running wp-cli --- utils/wp-cli-updatedeb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 utils/wp-cli-updatedeb.sh diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh old mode 100644 new mode 100755 index c4f34efb5..7f1aefe33 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -61,7 +61,7 @@ wget -nv -O usr/bin/wp "$PHAR" || die 3 "Phar download failure" chmod +x usr/bin/wp || die 4 "chmod failure" # get version -WPCLI_VER="$(grep -ao "define.*WP_CLI_VERSION.*;" usr/bin/wp | cut -d"'" -f4)" +WPCLI_VER="$(usr/bin/wp cli version|cut -d" " -f2)" [ -z "$WPCLI_VER" ] && die 5 "Cannot get wp-cli version" echo "Current version: ${WPCLI_VER}" From 9149e7da41340f5fd63d1db993e5741dc2a57a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Vor=C3=A1=C4=8Dek?= <jan@voracek.net> Date: Mon, 27 Apr 2015 14:25:09 +0200 Subject: [PATCH 3541/5359] Fixed user role checking --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 52a73d49b..1a255792a 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -306,7 +306,7 @@ public function create( $args, $assoc_args ) { if ( is_wp_error( $user_id ) ) { WP_CLI::error( $user_id ); } else { - if ( false === $role ) { + if ( false === $user->role ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } From 3dbf6223dca50f81014cde3de35c758e3aa4cd62 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 1 May 2015 04:27:52 -0700 Subject: [PATCH 3542/5359] Update core tests for WP 4.2.1 --- features/core.feature | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index 8c142b580..3886fbd0a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,9 +326,9 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | - | 4.1.3 | major | https://wordpress.org/wordpress-4.1.3.zip | - | 4.0.3 | major | https://wordpress.org/wordpress-4.0.3.zip | + | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | + | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | + | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | @@ -341,9 +341,9 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2 | major | https://wordpress.org/wordpress-4.2.zip | - | 4.1.3 | major | https://wordpress.org/wordpress-4.1.3.zip | - | 4.0.3 | major | https://wordpress.org/wordpress-4.0.3.zip | + | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | + | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | + | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | When I run `wp core check-update --major --format=count` From 97a0d042ecd7fc7afc2951e452e3c9bdb8b94467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sun, 3 May 2015 20:00:59 +0200 Subject: [PATCH 3543/5359] Reworked parm-dump with current values --- php/commands/cli.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 8964f6f02..0a85ae75d 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -70,27 +70,32 @@ function info( $_, $assoc_args ) { } /** - * Dump the list of global parameters, as JSON or by var_export. + * Dump the list of global parameters, as JSON or in var_export format. * * ## OPTIONS * + * [--with-values] + * : Display current values also. + * * [--format=<format>] - * : Accepted values: var_export + * : Accepted values: var_export, json. Default: var_export. * * @subcommand param-dump */ function param_dump( $_, $assoc_args ) { $spec = \WP_CLI::get_configurator()->get_spec(); - $config = \WP_CLI::get_configurator()->to_array(); - - // copy current config values to $spec - foreach ( $spec as $key => $value ) { - if ( isset( $config[0][$key] ) ) { - $current = $config[0][$key]; - } else { - $current = NULL; + + if ( isset( $assoc_args['with-values'] ) ) { + $config = \WP_CLI::get_configurator()->to_array(); + // Copy current config values to $spec + foreach ( $spec as $key => $value ) { + if ( isset( $config[0][$key] ) ) { + $current = $config[0][$key]; + } else { + $current = NULL; + } + $spec[$key]['current'] = $current; } - $spec[$key]['current'] = $current; } if ( isset( $assoc_args['format'] ) && 'var_export' === $assoc_args['format'] ) { From 4519b9ef36f7a0ec3a65f4117a8e9a2e2a4bf872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sun, 3 May 2015 20:24:03 +0200 Subject: [PATCH 3544/5359] Test for param-dump with current values --- features/cli.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/features/cli.feature b/features/cli.feature index d15e4888e..34d6d48be 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -66,3 +66,14 @@ Feature: `wp cli` tasks """ And STDERR should be empty And the return code should be 0 + + Scenario: Dump the list of global parameters with values + Given a WP install + + When I run `wp cli param-dump --with-values | grep -o '"current":' | uniq -c` + Then STDOUT should be: + """ + 15 "current": + """ + And STDERR should be empty + And the return code should be 0 From 69f55923b65568b9456cd473a4a05076251cabc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sun, 3 May 2015 20:28:15 +0200 Subject: [PATCH 3545/5359] Revert removed functions in cli.php --- php/commands/cli.php | 185 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index fccab59d6..918c46241 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -69,6 +69,191 @@ public function info( $_, $assoc_args ) { } } + /** + * Compare the last processed release to the current one, return true if it's the same minor version. + * + */ + private function same_minor_release( $release_parts, $updates ) { + $previous = end( $updates ); + if ( false === $previous ) + return false; + + $previous_parts = explode( '.', $previous['version'] ); + + return ( $previous_parts[0] === $release_parts[0] + && $previous_parts[1] === $release_parts[1] ); + } + + /** + * Check for update via Github API. Returns the available versions if there are updates, or empty if no update available. + * + * ## OPTIONS + * + * [--patch] + * : Only list patch updates + * + * [--minor] + * : Only list minor updates + * + * [--field=<field>] + * : Prints the value of a single field for each update. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. Defaults to version,update_type,package_url. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * @subcommand check-update + */ + public function check_update( $_, $assoc_args ) { + $updates = $this->get_updates( $assoc_args ); + + if ( $updates ) { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + array( 'version', 'update_type', 'package_url' ) + ); + $formatter->display_items( $updates ); + } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + } + } + + /** + * Fetch most recent update matching the requirements. Returns the available versions if there are updates, or empty if no update available. + * + * ## OPTIONS + * + * [--patch] + * : Only perform patch updates + * + * [--minor] + * : Only perform minor updates + * + * [--yes] + * : Do not prompt for confirmation + * + * @subcommand update + */ + public function update( $_, $assoc_args ) { + if ( 0 !== strpos( WP_CLI_ROOT, 'phar://' ) ) { + WP_CLI::error( "You can only self-update PHARs" ); + } + + $old_phar = realpath( $_SERVER['argv'][0] ); + + if ( ! is_writable( $old_phar ) ) { + WP_CLI::error( sprintf( "%s is not writable by current user", $old_phar ) ); + } + + $updates = $this->get_updates( $assoc_args ); + + if ( empty( $updates ) ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + exit(0); + } + + $newest = $updates[0]; + + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); + + $download_url = $newest['package_url']; + + WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); + + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.phar'; + + $headers = array(); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); + + Utils\http_request( 'GET', $download_url, null, $headers, $options ); + + exec( "php $temp --version", $output, $status ); + + if ( 0 !== $status ) { + WP_CLI::error_multi_line( $output ); + + WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); + } + + WP_CLI::log( 'New version works. Proceeding to replace.' ); + + $mode = fileperms( $old_phar ) & 511; + + if ( false === @chmod( $temp, $mode ) ) { + WP_CLI::error( sprintf( "Cannot chmod %s", $temp ) ); + } + + class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class + + if ( false === @rename( $temp, $old_phar ) ) { + WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); + } + + WP_CLI::success( sprintf( 'Updated WP-CLI to %s', $newest['version'] ) ); + } + + /** + * Returns update information + */ + private function get_updates( $assoc_args ) { + $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; + + $options = array( + 'timeout' => 30 + ); + + $headers = array( + 'Accept' => 'application/json' + ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); + + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d)", $response->status_code ) ); + } + + $release_data = json_decode( $response->body ); + $current_parts = explode( '.', WP_CLI_VERSION ); + $updates = array(); + + foreach ( $release_data as $release ) { + $release_version = $release->tag_name; + // get rid of leading "v" + if ( 'v' === substr( $release_version, 0, 1 ) ) { + $release_version = ltrim( $release_version, 'v' ); + } + // don't list earlier releases + if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) + continue; + $release_parts = explode( '.', $release_version ); + $update_type = 'minor'; + + if ( $release_parts[0] === $current_parts[0] + && $release_parts[1] === $current_parts[1] ) { + $update_type = 'patch'; + } + + if ( ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) && 'patch' !== $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) === false && 'patch' === $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) && 'minor' !== $update_type ) + && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) === false && 'minor' === $update_type ) + && ! $this->same_minor_release( $release_parts, $updates ) + ) { + $updates[] = array( + 'version' => $release_version, + 'update_type' => $update_type, + 'package_url' => $release->assets[0]->browser_download_url + ); + } + } + + return $updates; + } + /** * Dump the list of global parameters, as JSON or in var_export format. * From 42372ef33ba3523a61cab87aad0f49f10381b023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 4 May 2015 09:53:02 +0200 Subject: [PATCH 3546/5359] Use get_flag_value() --- php/commands/cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 918c46241..9592131ad 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -270,7 +270,7 @@ private function get_updates( $assoc_args ) { function param_dump( $_, $assoc_args ) { $spec = \WP_CLI::get_configurator()->get_spec(); - if ( isset( $assoc_args['with-values'] ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'with-values' ) ) { $config = \WP_CLI::get_configurator()->to_array(); // Copy current config values to $spec foreach ( $spec as $key => $value ) { @@ -283,7 +283,7 @@ function param_dump( $_, $assoc_args ) { } } - if ( isset( $assoc_args['format'] ) && 'var_export' === $assoc_args['format'] ) { + if ( 'var_export' === \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) ) { var_export( $spec ); } else { echo json_encode( $spec ); From cf6f5bfb4d63d11ca451086b14aa9bac4b60faa8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Mon, 4 May 2015 05:48:22 -0700 Subject: [PATCH 3547/5359] Fix documentation: the default is json See #1363 --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 9592131ad..ddc4d0530 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -263,7 +263,7 @@ private function get_updates( $assoc_args ) { * : Display current values also. * * [--format=<format>] - * : Accepted values: var_export, json. Default: var_export. + * : Accepted values: var_export, json. Default: json. * * @subcommand param-dump */ From 78b2e470096b389313ea07e278d2bcdd2490174b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 6 May 2015 12:42:03 -0700 Subject: [PATCH 3548/5359] Simple `wp comment generate` command Supports `--count` to start --- features/comment.feature | 7 +++++++ php/commands/comment.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index dd8ee017a..293936ab2 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -124,3 +124,10 @@ Feature: Manage WordPress comments 0 """ + Scenario: Generate comments + When I run `wp comment generate --count=20` + And I run `wp comment list --format=count` + Then STDOUT should be: + """ + 21 + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index 4b16eca07..a10248f01 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -87,6 +87,37 @@ public function update( $args, $assoc_args ) { } ); } + /** + * Generate comments. + * + * ## OPTIONS + * + * [--count=<number>] + * : How many comments to generate. Default: 100 + */ + public function generate( $args, $assoc_args ) { + + $defaults = array( + 'count' => 100, + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); + $comment_count = wp_count_comments(); + $total = (int )$comment_count->total_comments; + $limit = $total + $assoc_args['count']; + + for ( $i = $total; $i < $limit; $i++ ) { + wp_insert_comment( array( + 'comment_content' => "Comment {$i}", + ) ); + $notify->tick(); + } + + $notify->finish(); + + } + /** * Get a single comment. * From 71a130cc574b4d2f31e8eaf78edcf9abb8d07964 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Thu, 7 May 2015 15:45:20 -0400 Subject: [PATCH 3549/5359] In `wp term generate`, try to generate unique term names. --- features/term.feature | 9 +++++++++ php/commands/term.php | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 6bcf63720..2ee4447dd 100644 --- a/features/term.feature +++ b/features/term.feature @@ -77,6 +77,15 @@ Feature: Manage WordPress terms 11 """ + Scenario: Generating terms when terms already exist + When I run `wp term generate category --count=10` + And I run `wp term generate category --count=10` + And I run `wp term list category --format=count` + Then STDOUT should be: + """ + 21 + """ + Scenario: Term with a non-existent parent When I try `wp term create category Apple --parent=99 --porcelain` Then STDERR should be: diff --git a/php/commands/term.php b/php/commands/term.php index 31cedcec9..7b0c0762d 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -278,6 +278,8 @@ public function delete( $args ) { * wp term generate --count=10 */ public function generate( $args, $assoc_args ) { + global $wpdb; + list ( $taxonomy ) = $args; $defaults = array( @@ -302,6 +304,8 @@ public function generate( $args, $assoc_args ) { $current_parent = 0; $current_depth = 1; + $max_id = (int) $wpdb->get_var( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy ORDER BY term_taxonomy_id DESC LIMIT 1" ); + for ( $i = 0; $i < $count; $i++ ) { if ( $hierarchical ) { @@ -325,7 +329,9 @@ public function generate( $args, $assoc_args ) { 'slug' => $slug . "-$i", ); - $term = wp_insert_term( "$label $i", $taxonomy, $args ); + // Try to generate a unique term name. + $name = $label . ' ' . ( $max_id + $i + 1 ); + $term = wp_insert_term( $name, $taxonomy, $args ); if ( is_wp_error( $term ) ) { WP_CLI::warning( $term ); } else { From 496df802d8eb19c31374474199d247bf679cda39 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 7 May 2015 16:11:07 -0700 Subject: [PATCH 3550/5359] Update core tests for WP 4.2.2 --- features/core.feature | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/features/core.feature b/features/core.feature index 3886fbd0a..3fa82fe65 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,11 +326,11 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | - | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | - | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | - | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | - | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | + | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | + | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | + | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | + | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | + | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -341,10 +341,10 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | - | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | - | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | - | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | + | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | + | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | + | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | + | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -355,7 +355,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | + | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From f66c49649cf86ad2060041bae238a66ba36eb619 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 7 May 2015 16:11:07 -0700 Subject: [PATCH 3551/5359] Update core tests for WP 4.2.2 --- features/core.feature | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/features/core.feature b/features/core.feature index 3886fbd0a..3fa82fe65 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,11 +326,11 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | - | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | - | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | - | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | - | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | + | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | + | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | + | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | + | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | + | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -341,10 +341,10 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.1 | major | https://wordpress.org/wordpress-4.2.1.zip | - | 4.1.4 | major | https://wordpress.org/wordpress-4.1.4.zip | - | 4.0.4 | major | https://wordpress.org/wordpress-4.0.4.zip | - | 3.9.5 | major | https://wordpress.org/wordpress-3.9.5.zip | + | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | + | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | + | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | + | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -355,7 +355,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.7 | minor | https://wordpress.org/wordpress-3.8.7.zip | + | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From 5b3d3b64677f3e3e791f0ee341ae47985e017813 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Thu, 7 May 2015 20:40:25 -0400 Subject: [PATCH 3552/5359] Simplify logic for ensuring unique term slug/name. --- php/commands/term.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 7b0c0762d..b858ea3b0 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -306,7 +306,7 @@ public function generate( $args, $assoc_args ) { $max_id = (int) $wpdb->get_var( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy ORDER BY term_taxonomy_id DESC LIMIT 1" ); - for ( $i = 0; $i < $count; $i++ ) { + for ( $i = $max_id; $i <= $max_id + $count; $i++ ) { if ( $hierarchical ) { @@ -329,8 +329,7 @@ public function generate( $args, $assoc_args ) { 'slug' => $slug . "-$i", ); - // Try to generate a unique term name. - $name = $label . ' ' . ( $max_id + $i + 1 ); + $name = "$label $i"; $term = wp_insert_term( $name, $taxonomy, $args ); if ( is_wp_error( $term ) ) { WP_CLI::warning( $term ); From a27b92e608eb13f370d76261604a33d75213b461 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Thu, 7 May 2015 20:43:30 -0400 Subject: [PATCH 3553/5359] Counting is fun. --- php/commands/term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index b858ea3b0..f9c93b9c8 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -306,7 +306,7 @@ public function generate( $args, $assoc_args ) { $max_id = (int) $wpdb->get_var( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy ORDER BY term_taxonomy_id DESC LIMIT 1" ); - for ( $i = $max_id; $i <= $max_id + $count; $i++ ) { + for ( $i = $max_id + 1; $i <= $max_id + $count; $i++ ) { if ( $hierarchical ) { From 49e9a59f5c47513a1581a3f5260a70c0350c27c1 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sat, 9 May 2015 00:57:46 +0900 Subject: [PATCH 3554/5359] fix install-wp-tests.sh problem --- templates/install-wp-tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 6bb7fcd2f..25fb88e5e 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -11,7 +11,7 @@ DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-latest} -WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} +WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib/includes} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} set -ex @@ -62,12 +62,12 @@ install_test_suite() { cd $WP_TESTS_DIR if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php wp-tests-config.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php + download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php ${WP_TESTS_DIR}/../wp-tests-config.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" ${WP_TESTS_DIR}/../wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" ${WP_TESTS_DIR}/../wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" ${WP_TESTS_DIR}/../wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" ${WP_TESTS_DIR}/../wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" ${WP_TESTS_DIR}/../wp-tests-config.php fi } From d8c449b2b863b73b2a17c53d3db7b03057c6265e Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sat, 9 May 2015 11:23:35 +0900 Subject: [PATCH 3555/5359] missing plugin slug in tests/bootstrap.php --- features/scaffold.feature | 4 ++++ php/commands/scaffold.php | 8 ++++++-- templates/bootstrap.mustache | 5 ++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 35104a108..2b908b182 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -151,6 +151,10 @@ Feature: WordPress code scaffolding bootstrap.php test-sample.php """ + And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: + """ + hello-world.php + """ And the {PLUGIN_DIR}/hello-world/bin directory should contain: """ install-wp-tests.sh diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b51a9b8b4..e824ad803 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -527,10 +527,14 @@ function plugin_tests( $args, $assoc_args ) { if ( ! is_dir( $plugin_dir ) ) { WP_CLI::error( 'Invalid plugin specified.' ); } - } else if ( ! empty( $args[0] ) ) { + } + + if ( ! empty( $args[0] ) ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - } else { + } + + if ( empty( $assoc_args['dir'] ) && empty( $args[0] ) ) { WP_CLI::error( 'Invalid plugin specified.' ); } diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index e2802af05..4628e2d3f 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -8,9 +8,8 @@ if ( ! $_tests_dir ) { require_once $_tests_dir . '/includes/functions.php'; function _manually_load_plugin() { - require dirname( __FILE__ ) . '/../.php'; + require dirname( __FILE__ ) . '/../{{plugin_slug}}.php'; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); -require $_tests_dir . '/includes/bootstrap.php'; - +require $_tests_dir . '/includes/bootstrap.php'; \ No newline at end of file From 64147e80a844bb324c66986e443b70b280016ef9 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sat, 9 May 2015 11:46:10 +0900 Subject: [PATCH 3556/5359] add new line --- templates/bootstrap.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index 4628e2d3f..0f7a5391f 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -12,4 +12,4 @@ function _manually_load_plugin() { } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); -require $_tests_dir . '/includes/bootstrap.php'; \ No newline at end of file +require $_tests_dir . '/includes/bootstrap.php'; From 1924c718a1683866351c3bad78b730f46106719e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sat, 9 May 2015 14:56:33 -0700 Subject: [PATCH 3557/5359] Correct spelling --- php/config-spec.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/config-spec.php b/php/config-spec.php index 1d67b11b8..501a806b6 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -91,7 +91,7 @@ 'default' => array(), ), - # --allow-root => (NOT RECCOMENDED) Allow wp-cli to run as root. This poses + # --allow-root => (NOT RECOMMENDED) Allow wp-cli to run as root. This poses # a security risk, so you probably do not want to do this. 'allow-root' => array( 'file' => false, # Explicit. Just in case the default changes. From 95f8b30fd45433fb82738323a6393da378f5cd83 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 10 May 2015 11:06:46 +0900 Subject: [PATCH 3558/5359] update to test whole line --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 2b908b182..07e9d716b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -153,7 +153,7 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: """ - hello-world.php + require dirname( __FILE__ ) . '/../hello-world.php'; """ And the {PLUGIN_DIR}/hello-world/bin directory should contain: """ From f442684744f64e09d5a2aaaa14e086c3c883eaef Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 11 May 2015 15:23:37 +0900 Subject: [PATCH 3559/5359] fix problem when --dir=path/to/directory --- features/scaffold.feature | 5 +++++ php/commands/scaffold.php | 9 +++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 07e9d716b..5d6df9091 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -290,6 +290,11 @@ Feature: WordPress code scaffolding Success: Created test files. """ And the wp-content/mu-plugins/custom-plugin/tests directory should exist + And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should exist + And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should contain: + """ + require dirname( __FILE__ ) . '/../custom-plugin.php'; + """ Scenario: Scaffold starter code for a theme and network enable it Given a WP multisite install diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index e824ad803..001c53b56 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -527,14 +527,11 @@ function plugin_tests( $args, $assoc_args ) { if ( ! is_dir( $plugin_dir ) ) { WP_CLI::error( 'Invalid plugin specified.' ); } - } - - if ( ! empty( $args[0] ) ) { + $plugin_slug = basename( $plugin_dir ); + } elseif ( ! empty( $args[0] ) ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - } - - if ( empty( $assoc_args['dir'] ) && empty( $args[0] ) ) { + } else { WP_CLI::error( 'Invalid plugin specified.' ); } From f2c31cf28a59cb07a4006aba61904361726a9950 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 11 May 2015 15:27:01 +0900 Subject: [PATCH 3560/5359] elseif to elseif :) --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 001c53b56..358859a4e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -528,7 +528,7 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::error( 'Invalid plugin specified.' ); } $plugin_slug = basename( $plugin_dir ); - } elseif ( ! empty( $args[0] ) ) { + } else if ( ! empty( $args[0] ) ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; } else { From dd3dfecdae782c92b6d996b0dd08b8eac683989e Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 12 May 2015 05:16:06 +0900 Subject: [PATCH 3561/5359] change `...` to `dirname()` --- features/scaffold.feature | 4 ++-- templates/bootstrap.mustache | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 5d6df9091..edae7ba19 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -153,7 +153,7 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: """ - require dirname( __FILE__ ) . '/../hello-world.php'; + require dirname( dirname( __FILE__ ) ) . '/hello-world.php'; """ And the {PLUGIN_DIR}/hello-world/bin directory should contain: """ @@ -293,7 +293,7 @@ Feature: WordPress code scaffolding And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should exist And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should contain: """ - require dirname( __FILE__ ) . '/../custom-plugin.php'; + require dirname( dirname( __FILE__ ) ) . '/custom-plugin.php'; """ Scenario: Scaffold starter code for a theme and network enable it diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index 0f7a5391f..be86eeaea 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -8,7 +8,7 @@ if ( ! $_tests_dir ) { require_once $_tests_dir . '/includes/functions.php'; function _manually_load_plugin() { - require dirname( __FILE__ ) . '/../{{plugin_slug}}.php'; + require dirname( dirname( __FILE__ ) ) . '/{{plugin_slug}}.php'; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); From 8f5f50ee41bd814faebf016895821a5385e8b873 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 12 May 2015 05:55:27 +0900 Subject: [PATCH 3562/5359] change `...` to `dirname` in install-wp-tests.sh --- templates/install-wp-tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 25fb88e5e..6b2d4aefd 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -32,7 +32,7 @@ install_wp() { mkdir -p $WP_CORE_DIR - if [ $WP_VERSION == 'latest' ]; then + if [ $WP_VERSION == 'latest' ]; then local ARCHIVE_NAME='latest' else local ARCHIVE_NAME="wordpress-$WP_VERSION" @@ -62,12 +62,12 @@ install_test_suite() { cd $WP_TESTS_DIR if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php ${WP_TESTS_DIR}/../wp-tests-config.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" ${WP_TESTS_DIR}/../wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" ${WP_TESTS_DIR}/../wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" ${WP_TESTS_DIR}/../wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" ${WP_TESTS_DIR}/../wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" ${WP_TESTS_DIR}/../wp-tests-config.php + download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php fi } From fc2d3b53d5f3e6c55bb07b38ed4ca78261c84eee Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Mon, 11 May 2015 19:55:04 -0500 Subject: [PATCH 3563/5359] adds tests for verbose search-replace flag --- features/search-replace.feature | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index d66b6bcef..fc544a8ac 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,6 +15,7 @@ Feature: Do global search/replace guid """ + Scenario: Multisite search/replace Given a WP multisite install And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` @@ -62,6 +63,29 @@ Feature: Do global search/replace When I run `wp search-replace foo bar --quiet` Then STDOUT should be empty + Scenario: Verbose search/replace + Given a WP install + And I run `wp post create --post_title='Replace this text' --porcelain` + And save STDOUT as {POSTID} + + When I run `wp search-replace 'Replace' 'Replaced' --verbose` + Then STDOUT should contain: + """ + Updating wp_posts.post_title from 'Replace' to 'Replaced' + """ + + When I run `wp search-replace 'Replace' 'Replaced' --verbose --dry-run` + Then STDOUT should contain: + """ + This would update wp_posts.post_title from 'Replace' to 'Replaced' + """ + + When I run `wp search-replace 'Replace' 'Replaced' --verbose --precise` + Then STDOUT should contain: + """ + Updating wp_posts.post_title from 'Replace' to 'Replaced' + """ + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` From dd162887790455fa9b677005260e447160873c76 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Mon, 11 May 2015 19:55:21 -0500 Subject: [PATCH 3564/5359] handles --verbose flag added to searchreplace --- php/commands/search-replace.php | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 54008e984..1b9e69ca4 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -49,6 +49,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--all-tables] * : Enable replacement on ALL tables in the database, regardless of the prefix. Overrides --network and --all-tables-with-prefix. * + * [--verbose] + * : Prints rows to the console as they're updated. + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -67,6 +70,7 @@ public function __invoke( $args, $assoc_args ) { $dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects' ); + $verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); $skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); @@ -108,10 +112,10 @@ public function __invoke( $args, $assoc_args ) { if ( $php_only || NULL !== $serialRow ) { $type = 'PHP'; - $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ); + $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose ); } else { $type = 'SQL'; - $count = self::sql_handle_col( $col, $table, $old, $new, $dry_run ); + $count = self::sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ); } $report[] = array( $table, $col, $count, $type ); @@ -201,17 +205,21 @@ private static function get_table_list( $limit_to ) { } - private static function sql_handle_col( $col, $table, $old, $new, $dry_run ) { + private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { global $wpdb; if ( $dry_run ) { - return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); + $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { - return $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); + $result = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); + } + if ( $result && $verbose ) { + self::log_verbose_details( $table, $col, $old, $new, $dry_run ); } + return $result; } - private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects ) { + private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -252,6 +260,10 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, } } + if ( $count && $verbose ) { + self::log_verbose_details( $table, $col, $old, $new, $dry_run ); + } + return $count; } @@ -301,6 +313,12 @@ private static function esc_like( $old ) { return $old; } + private static function log_verbose_details( $table, $col, $old, $new, $dry_run ) { + $action = $dry_run ? 'This would update' : 'Updating'; + $verbose_output = "$action $table.$col from '$old' to '$new'\r\n"; + WP_CLI::log( $verbose_output ); + } + } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); From 0c82f831b972e9ae168f1ce4269cf8be01d6f761 Mon Sep 17 00:00:00 2001 From: Boone B Gorges <boonebgorges@gmail.com> Date: Tue, 12 May 2015 16:14:46 -0400 Subject: [PATCH 3565/5359] Skip cache invalidation when generating terms. When generating terms in a hierarchical category, `clean_term_cache()` triggers a rebuild of the taxonomy hierarchy with every call to `wp_insert_term()`. This is extremely slow when the taxonomy has many terms. We only need to bust the cache once, after all terms have been generated. See https://core.trac.wordpress.org/changeset/32498. --- php/commands/term.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index f9c93b9c8..fe155ea03 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -306,6 +306,9 @@ public function generate( $args, $assoc_args ) { $max_id = (int) $wpdb->get_var( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy ORDER BY term_taxonomy_id DESC LIMIT 1" ); + $suspend_cache_invalidation = wp_suspend_cache_invalidation( true ); + $created = array(); + for ( $i = $max_id + 1; $i <= $max_id + $count; $i++ ) { if ( $hierarchical ) { @@ -334,13 +337,15 @@ public function generate( $args, $assoc_args ) { if ( is_wp_error( $term ) ) { WP_CLI::warning( $term ); } else { + $created[] = $term['term_id']; $previous_term_id = $term['term_id']; } $notify->tick(); } - delete_option( $taxonomy . '_children' ); + wp_suspend_cache_invalidation( $suspend_cache_invalidation ); + clean_term_cache( $created, $taxonomy ); $notify->finish(); } From 3ce55ba6f953a5dc1e67a4c965c14aedb8c2bbf6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 13 May 2015 11:02:34 -0700 Subject: [PATCH 3566/5359] More sensible behavior for scaffolding plugin tests with `--dir=<dir>` arg If a plugin slug is provided, use that instead of the directory basename. But, if no slug is provided, use directory basename. --- features/scaffold.feature | 26 +++++++++++++++++++++++++- php/commands/scaffold.php | 20 +++++++++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index edae7ba19..699b25513 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -281,7 +281,7 @@ Feature: WordPress code scaffolding When I try `wp scaffold plugin-tests --dir=wp-content/mu-plugins/incorrect-custom-plugin` Then STDERR should contain: """ - Error: Invalid plugin specified. + Error: Invalid plugin directory specified. """ When I run `wp scaffold plugin-tests --dir=wp-content/mu-plugins/custom-plugin` @@ -296,6 +296,30 @@ Feature: WordPress code scaffolding require dirname( dirname( __FILE__ ) ) . '/custom-plugin.php'; """ + Scenario: Scaffold tests for a plugin with a different slug than plugin directory + Given a WP install + And a wp-content/mu-plugins/custom-plugin2/custom-plugin-slug.php file: + """ + <?php + /** + * Plugin Name: Handbook + * Description: Features for a handbook, complete with glossary and table of contents + * Author: Nacin + */ + """ + + When I run `wp scaffold plugin-tests custom-plugin-slug --dir=wp-content/mu-plugins/custom-plugin2` + Then STDOUT should contain: + """ + Success: Created test files. + """ + And the wp-content/mu-plugins/custom-plugin2/tests directory should exist + And the wp-content/mu-plugins/custom-plugin2/tests/bootstrap.php file should exist + And the wp-content/mu-plugins/custom-plugin2/tests/bootstrap.php file should contain: + """ + require dirname( dirname( __FILE__ ) ) . '/custom-plugin-slug.php'; + """ + Scenario: Scaffold starter code for a theme and network enable it Given a WP multisite install When I run `wp scaffold _s starter-theme --enable-network` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 358859a4e..33060e4b2 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -511,7 +511,7 @@ function plugin( $args, $assoc_args ) { * : The name of the plugin to generate test files for. * * [--dir=<dirname>] - * : Generate test files for a non-standard plugin path. + * : Generate test files for a non-standard plugin path. If no plugin slug is specified, the directory name is used. * * ## EXAMPLE * @@ -522,16 +522,22 @@ function plugin( $args, $assoc_args ) { function plugin_tests( $args, $assoc_args ) { $wp_filesystem = $this->init_wp_filesystem(); + if ( ! empty( $args[0] ) ) { + $plugin_slug = $args[0]; + $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + } + if ( ! empty( $assoc_args['dir'] ) ) { $plugin_dir = $assoc_args['dir']; if ( ! is_dir( $plugin_dir ) ) { - WP_CLI::error( 'Invalid plugin specified.' ); + WP_CLI::error( 'Invalid plugin directory specified.' ); } - $plugin_slug = basename( $plugin_dir ); - } else if ( ! empty( $args[0] ) ) { - $plugin_slug = $args[0]; - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - } else { + if ( empty( $plugin_slug ) ) { + $plugin_slug = basename( $plugin_dir ); + } + } + + if ( empty( $plugin_slug ) || empty( $plugin_dir ) ) { WP_CLI::error( 'Invalid plugin specified.' ); } From fa4fe115818f5311d2d8f5125bdb40f257935b5a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 13 May 2015 12:38:06 -0700 Subject: [PATCH 3567/5359] Version bump for master --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1cf0537c3..41915c799 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.19.0 +0.19.1 From 3a8f83aff623d2d9de539026ac489df5ffec8ffa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 15 May 2015 13:08:35 -0700 Subject: [PATCH 3568/5359] Filter taxonomy terms by `term_id` It's a bit hacky, but that's alright. We can work around WP core. --- features/term.feature | 11 +++++++++++ php/commands/term.php | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/features/term.feature b/features/term.feature index 2ee4447dd..fa85f1f8b 100644 --- a/features/term.feature +++ b/features/term.feature @@ -92,3 +92,14 @@ Feature: Manage WordPress terms """ Error: Parent term does not exist. """ + + Scenario: Filter terms by term_id + When I run `wp term generate category --count=10` + And I run `wp term create category "My Test Category" --porcelain` + And save STDOUT as {TERM_ID} + + When I run `wp term list category --term_id={TERM_ID} --field=name` + Then STDOUT should be: + """ + My Test Category + """ diff --git a/php/commands/term.php b/php/commands/term.php index fe155ea03..66d7bcced 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -66,7 +66,12 @@ public function list_( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - $terms = get_terms( $args, $assoc_args ); + if ( ! empty( $assoc_args['term_id'] ) ) { + $term = get_term_by( 'id', $assoc_args['term_id'], $args[0] ); + $terms = array( $term ); + } else { + $terms = get_terms( $args, $assoc_args ); + } if ( 'ids' == $formatter->format ) { $terms = wp_list_pluck( $terms, 'term_id' ); From 0cf22cc2c4a965a3fea8854538151b0d6b712a35 Mon Sep 17 00:00:00 2001 From: KDoole <dev@Kevins-iMac.local> Date: Fri, 15 May 2015 16:10:33 -0500 Subject: [PATCH 3569/5359] updated the verbose message --- features/search-replace.feature | 12 ++++-------- php/commands/search-replace.php | 18 ++++++++---------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index fc544a8ac..5649cd84c 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -71,19 +71,15 @@ Feature: Do global search/replace When I run `wp search-replace 'Replace' 'Replaced' --verbose` Then STDOUT should contain: """ - Updating wp_posts.post_title from 'Replace' to 'Replaced' - """ - - When I run `wp search-replace 'Replace' 'Replaced' --verbose --dry-run` - Then STDOUT should contain: - """ - This would update wp_posts.post_title from 'Replace' to 'Replaced' + Checking wp_posts.post_title + 1 rows affected """ When I run `wp search-replace 'Replace' 'Replaced' --verbose --precise` Then STDOUT should contain: """ - Updating wp_posts.post_title from 'Replace' to 'Replaced' + Checking wp_posts.post_title + 1 rows affected """ Scenario Outline: Large guid search/replace where replacement contains search (or not) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 1b9e69ca4..023b2b9b2 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -209,14 +209,14 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $ver global $wpdb; if ( $dry_run ) { - $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); + $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { - $result = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); + $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } - if ( $result && $verbose ) { - self::log_verbose_details( $table, $col, $old, $new, $dry_run ); + if ( $count && $verbose ) { + self::log_verbose_details( $table, $col, $count ); } - return $result; + return $count; } private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose ) { @@ -261,7 +261,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, } if ( $count && $verbose ) { - self::log_verbose_details( $table, $col, $old, $new, $dry_run ); + self::log_verbose_details( $table, $col, $count ); } return $count; @@ -313,10 +313,8 @@ private static function esc_like( $old ) { return $old; } - private static function log_verbose_details( $table, $col, $old, $new, $dry_run ) { - $action = $dry_run ? 'This would update' : 'Updating'; - $verbose_output = "$action $table.$col from '$old' to '$new'\r\n"; - WP_CLI::log( $verbose_output ); + private static function log_verbose_details( $table, $col, $count ) { + WP_CLI::log( sprintf( 'Checking: %s.%s' . PHP_EOL . '%d rows affected', $table, $col, $count ) ); } } From 6a2abcca83b9e5d4c1cce3029940dee271c158a6 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Fri, 15 May 2015 16:17:23 -0500 Subject: [PATCH 3570/5359] includes verbose messages for unaffected rows --- features/search-replace.feature | 4 ++-- php/commands/search-replace.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 5649cd84c..cba391557 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -71,14 +71,14 @@ Feature: Do global search/replace When I run `wp search-replace 'Replace' 'Replaced' --verbose` Then STDOUT should contain: """ - Checking wp_posts.post_title + Checking: wp_posts.post_title 1 rows affected """ When I run `wp search-replace 'Replace' 'Replaced' --verbose --precise` Then STDOUT should contain: """ - Checking wp_posts.post_title + Checking: wp_posts.post_title 1 rows affected """ diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 023b2b9b2..f0d0c433d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -213,7 +213,7 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $ver } else { $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } - if ( $count && $verbose ) { + if ( $verbose ) { self::log_verbose_details( $table, $col, $count ); } return $count; @@ -260,7 +260,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, } } - if ( $count && $verbose ) { + if ( $verbose ) { self::log_verbose_details( $table, $col, $count ); } From a824c6b542698b1f3afa9bfc6e65ce70ba2bfba0 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Thu, 28 May 2015 09:54:21 -0400 Subject: [PATCH 3571/5359] Added the --start_id argument to the `wp export` command to specify a starting post ID --- php/commands/export.php | 17 +++++++++++++++++ php/export/class-wp-export-query.php | 12 ++++++++++++ 2 files changed, 29 insertions(+) diff --git a/php/commands/export.php b/php/commands/export.php index 976901d7b..b4125f6cb 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -37,6 +37,9 @@ class Export_Command extends WP_CLI_Command { * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. * + * [--start_id=<pid>] + * : Export only posts with IDs greater than or equal to this post ID. + * * [--author=<author>] * : Export only posts by this author. Can be either user login or user ID. * @@ -62,6 +65,7 @@ public function __invoke( $_, $assoc_args ) { 'category' => NULL, 'post_status' => NULL, 'post__in' => NULL, + 'start_id' => NULL, 'skip_comments' => NULL, 'max_file_size' => 15, ); @@ -202,6 +206,19 @@ private function check_post__in( $post__in ) { return true; } + private function check_start_id( $start_id ) { + $start_id = intval( $start_id ); + + // Post IDs must be greater than 0 + if ( 0 >= $start_id ) { + WP_CLI::warning( sprintf( __( 'Invalid start ID: %d' ), $start_id ) ); + return false; + } + + $this->export_args['start_id'] = $start_id; + return true; + } + private function check_author( $author ) { if ( is_null( $author ) ) return true; diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 381b7bfdc..c970eb17f 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -14,6 +14,7 @@ class WP_Export_Query { 'author' => null, 'start_date' => null, 'end_date' => null, + 'start_id' => null, 'category' => null, ); @@ -146,6 +147,7 @@ private function calculate_post_ids() { $this->author_where(); $this->start_date_where(); $this->end_date_where(); + $this->start_id_where(); $this->category_where(); $where = implode( ' AND ', array_filter( $this->wheres ) ); @@ -212,6 +214,16 @@ private function end_date_where() { $this->wheres[] = $wpdb->prepare( 'p.post_date <= %s', date( 'Y-m-d 23:59:59', $timestamp ) ); } + private function start_id_where() { + global $wpdb; + + $start_id = absint( $this->filters['start_id'] ); + if ( 0 === $start_id ) { + return; + } + $this->wheres[] = $wpdb->prepare( 'p.ID >= %d', $start_id ); + } + private function get_timestamp_for_the_last_day_of_a_month( $yyyy_mm ) { return strtotime( "$yyyy_mm +1month -1day" ); } From 1107b9cc7726214e6b8f0b60eb1dde025903f362 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Thu, 28 May 2015 10:21:01 -0400 Subject: [PATCH 3572/5359] Bail early from check_start_id if one isn't set --- php/commands/export.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/export.php b/php/commands/export.php index b4125f6cb..e3a6ee588 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -207,6 +207,10 @@ private function check_post__in( $post__in ) { } private function check_start_id( $start_id ) { + if ( is_null( $start_id ) ) { + return true; + } + $start_id = intval( $start_id ); // Post IDs must be greater than 0 From 2b8709ce1b96de9f67bfec83eea65951bfea1458 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <steve@stevegrunwell.com> Date: Thu, 28 May 2015 17:08:25 +0000 Subject: [PATCH 3573/5359] Enable the --post_type argument of `wp export` to accept multiple, comma-separated post types --- php/commands/export.php | 17 +++++++++++++---- php/export/class-wp-export-query.php | 26 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 976901d7b..6adc6800d 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -32,7 +32,8 @@ class Export_Command extends WP_CLI_Command { * : Export only posts published before this date, in format YYYY-MM-DD. * * [--post_type=<post-type>] - * : Export only posts with this post_type. Defaults to all. + * : Export only posts with this post_type. Separate multiple post types with a + * comma. Defaults to all. * * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. @@ -179,10 +180,18 @@ private function check_post_type( $post_type ) { if ( is_null( $post_type ) ) return true; + $post_type = array_unique( array_filter( explode( ',', $post_type ) ) ); $post_types = get_post_types(); - if ( !in_array( $post_type, $post_types ) ) { - WP_CLI::warning( sprintf( 'The post type %s does not exist. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); - return false; + + foreach ( $post_type as $type ) { + if ( ! in_array( $type, $post_types ) ) { + WP_CLI::warning( sprintf( + 'The post type %s does not exist. Choose "all" or any of these existing post types instead: %s', + $type, + implode( ", ", $post_types ) + ) ); + return false; + } } $this->export_args['post_type'] = $post_type; return true; diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 381b7bfdc..f1e2422a7 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -159,12 +159,30 @@ private function calculate_post_ids() { private function post_type_where() { global $wpdb; - $post_types_filters = array( 'can_export' => true ); + $post_types_filters = array( 'can_export' => true, 'name' => null ); if ( $this->filters['post_type'] ) { - $post_types_filters = array_merge( $post_types_filters, array( 'name' => $this->filters['post_type'] ) ); + $post_types = $this->filters['post_type']; + + // Flatten single post types + if ( is_array( $post_types ) && 1 === count( $post_types ) ) { + $post_types = array_shift( $post_types ); + } + $post_types_filters = array_merge( $post_types_filters, array( 'name' => $post_types ) ); } - $post_types = get_post_types( $post_types_filters ); - if ( !$post_types ) { + + // Multiple post types + if ( is_array( $post_types_filters['name'] ) ) { + $post_types = array(); + foreach ( $post_types_filters['name'] as $post_type ) { + if ( post_type_exists( $post_type ) ) { + $post_types[] = $post_type; + } + } + } else { + $post_types = get_post_types( $post_types_filters ); + } + + if ( ! $post_types ) { $this->wheres[] = 'p.post_type IS NULL'; return; } From a233803633a1e74ace3a1aace073340858f28591 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 8 May 2015 14:59:34 +0300 Subject: [PATCH 3574/5359] behat: be consistent about dbhost --- features/bootstrap/FeatureContext.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index c17d1842b..87085229c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -28,7 +28,8 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { private static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1' + 'dbpass' => 'password1', + 'dbhost' => '127.0.0.1', ); public $variables = array(); @@ -169,7 +170,7 @@ private function set_cache_dir() { private static function run_sql( $sql ) { Utils\run_mysql_command( 'mysql --no-defaults', array( 'execute' => $sql, - 'host' => 'localhost', + 'host' => self::$db_settings['dbhost'], 'user' => self::$db_settings['dbuser'], 'pass' => self::$db_settings['dbpass'], ) ); From 65e8bf4c06415e18f8390a342e3396c6a0bd1b40 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 May 2015 22:40:06 +0300 Subject: [PATCH 3575/5359] add `wp server` command --- features/bootstrap/FeatureContext.php | 55 ++++++++++++++++++ features/server.feature | 13 +++++ features/steps/when.php | 6 ++ php/commands/server.php | 60 ++++++++++++++++++++ php/router-lib.php | 81 +++++++++++++++++++++++++++ php/router.php | 27 +++++++++ 6 files changed, 242 insertions(+) create mode 100644 features/server.feature create mode 100644 php/commands/server.php create mode 100644 php/router-lib.php create mode 100644 php/router.php diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 87085229c..02d22011c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -32,6 +32,8 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { 'dbhost' => '127.0.0.1', ); + private $running_procs = array(); + public $variables = array(); /** @@ -97,6 +99,36 @@ public function afterScenario( $event ) { if ( $event->getResult() < 4 ) { Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ), null, self::get_process_env_variables() )->run(); } + + foreach ( $this->running_procs as $proc ) { + self::terminate_proc( $proc ); + } + } + + /** + * Terminate a process and any of its children. + */ + private static function terminate_proc( $proc ) { + $status = proc_get_status( $proc ); + + $master_pid = $status['pid']; + + $output = `ps -o ppid,pid,command | grep ^$master_pid`; + + foreach ( explode( "\n", $output ) as $line ) { + if ( preg_match( '/^(\d+)\s+(\d+)/', $line, $matches ) ) { + $parent = $matches[1]; + $child = $matches[2]; + + if ( $parent == $master_pid ) { + if ( ! posix_kill( $child, 9 ) ) { + throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); + } + } + } + } + + proc_close( $proc ); } public static function create_cache_dir() { @@ -199,6 +231,29 @@ public function proc( $command, $assoc_args = array(), $path = '' ) { return Process::create( $command, $path, $env ); } + /** + * Start a background process. Will automatically be closed when the tests finish. + */ + public function background_proc( $cmd ) { + $descriptors = array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + + $proc = proc_open( $cmd, $descriptors, $pipes, $this->variables['RUN_DIR'], self::get_process_env_variables() ); + + sleep(1); + + $status = proc_get_status( $proc ); + + if ( !$status['running'] ) { + throw new RuntimeException( stream_get_contents( $pipes[2] ) ); + } else { + $this->running_procs[] = $proc; + } + } + public function move_files( $src, $dest ) { rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); } diff --git a/features/server.feature b/features/server.feature new file mode 100644 index 000000000..ad9ff53bd --- /dev/null +++ b/features/server.feature @@ -0,0 +1,13 @@ +Feature: Serve WordPress locally + + Scenario: Vanilla install + Given a WP install + And I start `wp server --host=localhost --port=8181` + + When I run `curl -sS localhost:8181` + Then STDOUT should contain: + """ + Just another WordPress site + """ + + When I run `test "$(curl -sS localhost:8181/license.txt)" == "$(cat license.txt)"` diff --git a/features/steps/when.php b/features/steps/when.php index 55651d9b3..b1ad61445 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -14,6 +14,12 @@ function invoke_proc( $proc, $mode ) { return $proc->$method(); } +$steps->When( '/^I start `([^`]+)`$/', + function ( $world, $cmd ) { + $world->background_proc( $cmd ); + } +); + $steps->When( '/^I (run|try) `([^`]+)`$/', function ( $world, $mode, $cmd ) { $cmd = $world->replace_variables( $cmd ); diff --git a/php/commands/server.php b/php/commands/server.php new file mode 100644 index 000000000..5af14a50e --- /dev/null +++ b/php/commands/server.php @@ -0,0 +1,60 @@ +<?php + +class Server_Command extends WP_CLI_Command { + + /** + * Start a development server. + * + * ## OPTIONS + * + * --host=<host> + * : The hostname to bind the server to. Default: localhost + * + * --port=<port> + * : The port number to bind the server to. Default: 8080 + * + * ## EXAMPLES + * + * # Make the instance available on any address (with port 8080) + * wp server --host=0.0.0.0 + * + * # Run on port 80 (for multisite) + * sudo wp server --host=localhost.localdomain --port=80 + * + * @when before_wp_load + * @synopsis [--host=<host>] [--port=<port>] + */ + function __invoke( $_, $assoc_args ) { + $min_version = '5.4'; + if ( version_compare( PHP_VERSION, $min_version, '<' ) ) { + WP_CLI::error( "The `wp server` command requires PHP $min_version or newer." ); + } + + $defaults = array( + 'host' => 'localhost', + 'port' => 8080 + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $config_path = WP_CLI::get_runner()->project_config_path; + + if ( !$config_path ) { + $docroot = ABSPATH; + } else { + $docroot = dirname( $config_path ); + } + + $cmd = \WP_CLI\Utils\esc_cmd( PHP_BINARY . ' -S %s -t %s %s', + $assoc_args['host'] . ':' . $assoc_args['port'], + $docroot, + WP_CLI_ROOT . '/php/router.php' + ); + + $descriptors = array( STDIN, STDOUT, STDERR ); + + exit( proc_close( proc_open( $cmd, $descriptors, $pipes ) ) ); + } +} + +WP_CLI::add_command( 'server', 'Server_Command' ); + diff --git a/php/router-lib.php b/php/router-lib.php new file mode 100644 index 000000000..08a400d41 --- /dev/null +++ b/php/router-lib.php @@ -0,0 +1,81 @@ +<?php + +namespace WP_CLI\Router; + +function get_full_host( $url ) { + $parsed_url = parse_url( $url ); + + $host = $parsed_url['host']; + if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) + $host .= ':' . $parsed_url['port']; + + return $host; +} + +function option_home( $url ) { + $GLOBALS['_wp_cli_original_url'] = $url; + + return 'http://' . $_SERVER['HTTP_HOST']; +} + +function option_siteurl( $url ) { + if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) + get_option('home'); + + $home_url_host = get_full_host( $GLOBALS['_wp_cli_original_url'] ); + $site_url_host = get_full_host( $url ); + + if ( $site_url_host == $home_url_host ) { + $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); + } + + return $url; +} + +function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + global $wp_filter, $merged_filters; + + $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); + $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + unset( $merged_filters[ $tag ] ); + return true; +} + +function _wp_filter_build_unique_id($tag, $function, $priority) { + global $wp_filter; + static $filter_id_count = 0; + + if ( is_string($function) ) + return $function; + + if ( is_object($function) ) { + // Closures are currently implemented as objects + $function = array( $function, '' ); + } else { + $function = (array) $function; + } + + if (is_object($function[0]) ) { + // Object Class Calling + if ( function_exists('spl_object_hash') ) { + return spl_object_hash($function[0]) . $function[1]; + } else { + $obj_idx = get_class($function[0]).$function[1]; + if ( !isset($function[0]->wp_filter_id) ) { + if ( false === $priority ) + return false; + $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; + $function[0]->wp_filter_id = $filter_id_count; + ++$filter_id_count; + } else { + $obj_idx .= $function[0]->wp_filter_id; + } + + return $obj_idx; + } + } else if ( is_string($function[0]) ) { + // Static Calling + return $function[0] . '::' . $function[1]; + } +} + diff --git a/php/router.php b/php/router.php new file mode 100644 index 000000000..613be42c4 --- /dev/null +++ b/php/router.php @@ -0,0 +1,27 @@ +<?php +// Used by `wp server` to route requests. + +require_once __DIR__ . '/router-lib.php'; + +WP_CLI\Router\add_filter( 'option_home', '\\WP_CLI\\Router\\option_home', 20 ); +WP_CLI\Router\add_filter( 'option_siteurl', '\\WP_CLI\\Router\\option_siteurl', 20 ); + +$root = $_SERVER['DOCUMENT_ROOT']; +$path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' ); + +if ( file_exists( $root.$path ) ) { + if ( is_dir( $root.$path ) && substr( $path, -1 ) !== '/' ) { + header( "Location: $path/" ); + exit; + } + + if ( strpos( $path, '.php' ) !== false ) { + chdir( dirname( $root.$path ) ); + require_once $root.$path; + } else { + return false; + } +} else { + chdir( $root ); + require_once 'index.php'; +} From 9878b947ca87c291165cfc88fe9a7edd9b37e8c0 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Fri, 29 May 2015 23:50:09 +0300 Subject: [PATCH 3576/5359] port Behat tag script to PHP --- ci/behat-tags.php | 22 ++++++++++++++++++ ci/set-behat-tags.sh | 55 -------------------------------------------- ci/test.sh | 4 ++-- 3 files changed, 24 insertions(+), 57 deletions(-) create mode 100644 ci/behat-tags.php delete mode 100755 ci/set-behat-tags.sh diff --git a/ci/behat-tags.php b/ci/behat-tags.php new file mode 100644 index 000000000..ec573189e --- /dev/null +++ b/ci/behat-tags.php @@ -0,0 +1,22 @@ +<?php + +# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +$skip_tags = array('@github-api'); + +exec( 'grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); + +$WP_VERSION = getenv( 'WP_VERSION' ); + +if ( $WP_VERSION ) { + foreach ( $existing_tags as $tag ) { + $version = str_replace( '@require-wp-', '', $tag ); + if ( version_compare( $version, $WP_VERSION, '>' ) ) { + $skip_tags[] = $tag; + } + } +} + +if ( !empty( $skip_tags ) ) { + echo '--tags=~' . implode( '&&~', $skip_tags ); +} + diff --git a/ci/set-behat-tags.sh b/ci/set-behat-tags.sh deleted file mode 100755 index ee5de2143..000000000 --- a/ci/set-behat-tags.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -# http://stackoverflow.com/questions/4023830/bash-how-compare-two-strings-in-version-format -vercomp() { - if [[ $1 == $2 ]] - then - return 0 - fi - local IFS=. - local i ver1=($1) ver2=($2) - # fill empty fields in ver1 with zeros - for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) - do - ver1[i]=0 - done - for ((i=0; i<${#ver1[@]}; i++)) - do - if [[ -z ${ver2[i]} ]] - then - # fill empty fields in ver2 with zeros - ver2[i]=0 - fi - if ((10#${ver1[i]} > 10#${ver2[i]})) - then - return 1 - fi - if ((10#${ver1[i]} < 10#${ver2[i]})) - then - return 2 - fi - done - return 0 -} - -# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -skip_tags="--tags='~@github-api&&" -if [[ ! -z "$WP_VERSION" ]]; then - - requires=($(grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq)) - for (( i = 0; i < ${#requires[@]}; i++ )); do - version=${requires[$i]:12} - require=${requires[$i]} - vercomp $version $WP_VERSION - compare="$?" - if [[ 1 == $compare ]]; then - skip_tags="$skip_tags~$require&&" - fi - done - -fi - -skip_tags=$(echo $skip_tags| sed 's/&&$//') # trim trailing '&&' -skip_tags="$skip_tags'" # close the argument - -echo export behat_tags=$skip_tags diff --git a/ci/test.sh b/ci/test.sh index 0972b3a34..930f2b4a5 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -5,10 +5,10 @@ set -ex # Run the unit tests vendor/bin/phpunit -eval $(./ci/set-behat-tags.sh) +BEHAT_TAGS=$(php ci/behat-tags.php) # Run the functional tests -vendor/bin/behat --format progress $behat_tags +vendor/bin/behat --format progress $BEHAT_TAGS # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From 06120ce0362b2540f3a815cee6d6f194091d9f0c Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 May 2015 00:04:17 +0300 Subject: [PATCH 3577/5359] behat: check environment before running tests that require a specific PHP version --- ci/behat-tags.php | 31 ++++++++++++++++++++++++------- features/server.feature | 1 + 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index ec573189e..145d90f88 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -1,21 +1,38 @@ <?php -# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -$skip_tags = array('@github-api'); +error_reporting(E_ALL); +ini_set('display_errors', 1); + +function php_version_tags() { + exec( 'grep "@require-php-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); +} + +function version_tags( $prefix, $current ) { + if ( ! $current ) + return; -exec( 'grep "@require-wp-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); + exec( "grep '@{$prefix}-[0-9\.]*' -h -o features/*.feature | uniq", $existing_tags ); -$WP_VERSION = getenv( 'WP_VERSION' ); + $skip_tags = array(); -if ( $WP_VERSION ) { foreach ( $existing_tags as $tag ) { - $version = str_replace( '@require-wp-', '', $tag ); - if ( version_compare( $version, $WP_VERSION, '>' ) ) { + $required = str_replace( "@{$prefix}-", '', $tag ); + if ( version_compare( $current, $required, '<' ) ) { $skip_tags[] = $tag; } } + + return $skip_tags; } +$skip_tags = array_merge( + version_tags( 'require-wp', getenv( 'WP_VERSION' ) ), + version_tags( 'require-php', PHP_VERSION ) +); + +# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +$skip_tags[] = '@github-api'; + if ( !empty( $skip_tags ) ) { echo '--tags=~' . implode( '&&~', $skip_tags ); } diff --git a/features/server.feature b/features/server.feature index ad9ff53bd..f9be1bcdb 100644 --- a/features/server.feature +++ b/features/server.feature @@ -1,3 +1,4 @@ +@require-php-5.4 Feature: Serve WordPress locally Scenario: Vanilla install From b4beeb10fc416cc15ea7b4c78c4dc2579bf6a165 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 May 2015 01:30:54 +0300 Subject: [PATCH 3578/5359] extract router.php from phar, before starting the server --- php/commands/server.php | 2 +- php/router-lib.php | 81 --------------------------------------- php/router.php | 84 +++++++++++++++++++++++++++++++++++++++-- php/utils.php | 44 ++++++++++++--------- 4 files changed, 108 insertions(+), 103 deletions(-) delete mode 100644 php/router-lib.php diff --git a/php/commands/server.php b/php/commands/server.php index 5af14a50e..e050fa4b6 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -47,7 +47,7 @@ function __invoke( $_, $assoc_args ) { $cmd = \WP_CLI\Utils\esc_cmd( PHP_BINARY . ' -S %s -t %s %s', $assoc_args['host'] . ':' . $assoc_args['port'], $docroot, - WP_CLI_ROOT . '/php/router.php' + \WP_CLI\Utils\extract_from_phar( WP_CLI_ROOT . '/php/router.php' ) ); $descriptors = array( STDIN, STDOUT, STDERR ); diff --git a/php/router-lib.php b/php/router-lib.php deleted file mode 100644 index 08a400d41..000000000 --- a/php/router-lib.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php - -namespace WP_CLI\Router; - -function get_full_host( $url ) { - $parsed_url = parse_url( $url ); - - $host = $parsed_url['host']; - if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) - $host .= ':' . $parsed_url['port']; - - return $host; -} - -function option_home( $url ) { - $GLOBALS['_wp_cli_original_url'] = $url; - - return 'http://' . $_SERVER['HTTP_HOST']; -} - -function option_siteurl( $url ) { - if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) - get_option('home'); - - $home_url_host = get_full_host( $GLOBALS['_wp_cli_original_url'] ); - $site_url_host = get_full_host( $url ); - - if ( $site_url_host == $home_url_host ) { - $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); - } - - return $url; -} - -function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { - global $wp_filter, $merged_filters; - - $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); - $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); - unset( $merged_filters[ $tag ] ); - return true; -} - -function _wp_filter_build_unique_id($tag, $function, $priority) { - global $wp_filter; - static $filter_id_count = 0; - - if ( is_string($function) ) - return $function; - - if ( is_object($function) ) { - // Closures are currently implemented as objects - $function = array( $function, '' ); - } else { - $function = (array) $function; - } - - if (is_object($function[0]) ) { - // Object Class Calling - if ( function_exists('spl_object_hash') ) { - return spl_object_hash($function[0]) . $function[1]; - } else { - $obj_idx = get_class($function[0]).$function[1]; - if ( !isset($function[0]->wp_filter_id) ) { - if ( false === $priority ) - return false; - $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; - $function[0]->wp_filter_id = $filter_id_count; - ++$filter_id_count; - } else { - $obj_idx .= $function[0]->wp_filter_id; - } - - return $obj_idx; - } - } else if ( is_string($function[0]) ) { - // Static Calling - return $function[0] . '::' . $function[1]; - } -} - diff --git a/php/router.php b/php/router.php index 613be42c4..869129630 100644 --- a/php/router.php +++ b/php/router.php @@ -1,10 +1,88 @@ <?php // Used by `wp server` to route requests. -require_once __DIR__ . '/router-lib.php'; +namespace WP_CLI\Router; -WP_CLI\Router\add_filter( 'option_home', '\\WP_CLI\\Router\\option_home', 20 ); -WP_CLI\Router\add_filter( 'option_siteurl', '\\WP_CLI\\Router\\option_siteurl', 20 ); +function get_full_host( $url ) { + $parsed_url = parse_url( $url ); + + $host = $parsed_url['host']; + if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) + $host .= ':' . $parsed_url['port']; + + return $host; +} + +function option_home( $url ) { + $GLOBALS['_wp_cli_original_url'] = $url; + + return 'http://' . $_SERVER['HTTP_HOST']; +} + +function option_siteurl( $url ) { + if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) + get_option('home'); + + $home_url_host = get_full_host( $GLOBALS['_wp_cli_original_url'] ); + $site_url_host = get_full_host( $url ); + + if ( $site_url_host == $home_url_host ) { + $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); + } + + return $url; +} + +// This should be identical to the normal WordPress add_filter() function. +function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + global $wp_filter, $merged_filters; + + $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); + $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + unset( $merged_filters[ $tag ] ); + return true; +} + +function _wp_filter_build_unique_id($tag, $function, $priority) { + global $wp_filter; + static $filter_id_count = 0; + + if ( is_string($function) ) + return $function; + + if ( is_object($function) ) { + // Closures are currently implemented as objects + $function = array( $function, '' ); + } else { + $function = (array) $function; + } + + if (is_object($function[0]) ) { + // Object Class Calling + if ( function_exists('spl_object_hash') ) { + return spl_object_hash($function[0]) . $function[1]; + } else { + $obj_idx = get_class($function[0]).$function[1]; + if ( !isset($function[0]->wp_filter_id) ) { + if ( false === $priority ) + return false; + $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; + $function[0]->wp_filter_id = $filter_id_count; + ++$filter_id_count; + } else { + $obj_idx .= $function[0]->wp_filter_id; + } + + return $obj_idx; + } + } else if ( is_string($function[0]) ) { + // Static Calling + return $function[0] . '::' . $function[1]; + } +} + +add_filter( 'option_home', '\\WP_CLI\\Router\\option_home', 20 ); +add_filter( 'option_siteurl', '\\WP_CLI\\Router\\option_siteurl', 20 ); $root = $_SERVER['DOCUMENT_ROOT']; $path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' ); diff --git a/php/utils.php b/php/utils.php index a16a7a669..1dd6bd2b6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -7,8 +7,31 @@ use \WP_CLI\Dispatcher; use \WP_CLI\Iterators\Transform; +function inside_phar() { + return 0 === strpos( WP_CLI_ROOT, 'phar://' ); +} + +// Files that need to be read by external programs have to be extracted from the Phar archive. +function extract_from_phar( $path ) { + if ( ! inside_phar() ) { + return $path; + } + + $fname = basename( $path ); + + $tmp_path = sys_get_temp_dir() . "/wp-cli-$fname"; + + copy( $path, $tmp_path ); + + register_shutdown_function( function() use ( $tmp_path ) { + unlink( $tmp_path ); + } ); + + return $tmp_path; +} + function load_dependencies() { - if ( 0 === strpos( WP_CLI_ROOT, 'phar:' ) ) { + if ( inside_phar() ) { require WP_CLI_ROOT . '/vendor/autoload.php'; return; } @@ -417,31 +440,16 @@ function replace_path_consts( $source, $path ) { * @return object */ function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { - $pem_copied = false; - // cURL can't read Phar archives - if ( 0 === strpos( WP_CLI_ROOT, 'phar://' ) ) { - $options['verify'] = sys_get_temp_dir() . '/wp-cli-cacert.pem'; - - copy( - WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem', - $options['verify'] - ); - $pem_copied = true; - } + $options['verify'] = extract_from_phar( + WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); try { $request = \Requests::request( $url, $headers, $data, $method, $options ); - if ( $pem_copied ) { - unlink( $options['verify'] ); - } return $request; } catch( \Requests_Exception $ex ) { // Handle SSL certificate issues gracefully \WP_CLI::warning( $ex->getMessage() ); - if ( $pem_copied ) { - unlink( $options['verify'] ); - } $options['verify'] = false; try { return \Requests::request( $url, $headers, $data, $method, $options ); From c661d6076785b1c884040507350c153a13894ec9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 May 2015 02:40:34 +0300 Subject: [PATCH 3579/5359] behat: use cmp instead of test --- features/server.feature | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/server.feature b/features/server.feature index f9be1bcdb..fc1a71663 100644 --- a/features/server.feature +++ b/features/server.feature @@ -11,4 +11,6 @@ Feature: Serve WordPress locally Just another WordPress site """ - When I run `test "$(curl -sS localhost:8181/license.txt)" == "$(cat license.txt)"` + When I run `curl -sS localhost:8181/license.txt > /tmp/license.txt` + And I run `cmp /tmp/license.txt license.txt` + Then STDOUT should be empty From 7c1f9d20cb0157c1c554df8433fdc0188632ec1b Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 May 2015 04:58:08 +0300 Subject: [PATCH 3580/5359] behat: use proc helper method wherever possible --- features/bootstrap/FeatureContext.php | 40 +++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 02d22011c..22b9a78e0 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -92,12 +92,11 @@ public function beforeScenario( $event ) { * @AfterScenario */ public function afterScenario( $event ) { - if ( !isset( $this->variables['RUN_DIR'] ) ) - return; - - // remove altered WP install, unless there's an error - if ( $event->getResult() < 4 ) { - Process::create( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ), null, self::get_process_env_variables() )->run(); + if ( isset( $this->variables['RUN_DIR'] ) ) { + // remove altered WP install, unless there's an error + if ( $event->getResult() < 4 ) { + $this->proc( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); + } } foreach ( $this->running_procs as $proc ) { @@ -181,21 +180,17 @@ public function create_run_dir() { public function build_phar( $version = 'same' ) { $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; - Process::create( - Utils\esc_cmd( - 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', - __DIR__ . '/../../utils/make-phar.php', - $this->variables['PHAR_PATH'], - $version - ), - null, - self::get_process_env_variables() - )->run_check(); + $this->proc( Utils\esc_cmd( + 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', + __DIR__ . '/../../utils/make-phar.php', + $this->variables['PHAR_PATH'], + $version + ) )->run_check(); } private function set_cache_dir() { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - Process::create( Utils\esc_cmd( 'mkdir -p %s', $path ), null, self::get_process_env_variables() )->run_check(); + $this->proc( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); $this->variables['CACHE_DIR'] = $path; } @@ -227,8 +222,13 @@ public function proc( $command, $assoc_args = array(), $path = '' ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } - $path = "{$this->variables['RUN_DIR']}/{$path}"; - return Process::create( $command, $path, $env ); + if ( isset( $this->variables['RUN_DIR'] ) ) { + $cwd = "{$this->variables['RUN_DIR']}/{$path}"; + } else { + $cwd = null; + } + + return Process::create( $command, $cwd, $env ); } /** @@ -271,7 +271,7 @@ public function download_wp( $subdir = '' ) { mkdir( $dest_dir ); } - Process::create( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ), null, self::get_process_env_variables() )->run_check(); + $this->proc( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); // disable emailing mkdir( $dest_dir . '/wp-content/mu-plugins' ); From 06ab8fd20e155a678bb33fc94a3265d7582b0b64 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Sat, 30 May 2015 05:29:11 +0300 Subject: [PATCH 3581/5359] behat: prevent stalled builds by using posix_kill() instead of proc_close() --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 22b9a78e0..75e0e6fe4 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -127,7 +127,7 @@ private static function terminate_proc( $proc ) { } } - proc_close( $proc ); + posix_kill( $master_pid, 9 ); } public static function create_cache_dir() { From 9addcdaab8b237f3c1b7bb1a8fe080023097ab8b Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 30 May 2015 01:01:36 -0400 Subject: [PATCH 3582/5359] Add a feature test for `wp export --start_id=<id>` --- features/export.feature | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/features/export.feature b/features/export.feature index f7be508ce..59d9c8f41 100644 --- a/features/export.feature +++ b/features/export.feature @@ -227,3 +227,41 @@ Feature: Export content. """ Test User """ + + Scenario: Export posts from a given starting post ID + Given a WP install + + When I run `wp plugin install wordpress-importer --activate` + Then STDERR should not contain: + """ + Warning: + """ + + When I run `wp site empty --yes` + And I run `wp post generate --post_type=post --count=10` + And I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 10 + """ + + When I run `wp export --start_id=6` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 5 + """ \ No newline at end of file From 9431cb1c70b770677304f6d11ff8b453662b7128 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 30 May 2015 01:30:15 -0400 Subject: [PATCH 3583/5359] Add functional tests for comma-separated --post_type arguments on `wp export` --- features/export.feature | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/features/export.feature b/features/export.feature index f7be508ce..05d389e32 100644 --- a/features/export.feature +++ b/features/export.feature @@ -74,6 +74,58 @@ Feature: Export content. 10 """ + Scenario: Export a comma-separated list of post types + Given a WP install + + When I run `wp plugin install wordpress-importer --activate` + Then STDERR should not contain: + """ + Warning: + """ + + When I run `wp site empty --yes` + And I run `wp post generate --post_type=page --count=10` + And I run `wp post generate --post_type=post --count=10` + And I run `wp post generate --post_type=attachment --count=10` + And I run `wp post list --post_type=page,post,attachment --format=count` + Then STDOUT should be: + """ + 30 + """ + + When I run `wp export --post_type=page,post` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page,post --format=count` + Then STDOUT should be: + """ + 20 + """ + + When I run `wp post list --post_type=page --format=count` + Then STDOUT should be: + """ + 10 + """ + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 10 + """ + Scenario: Export only one post Given a WP install From dbc97f28873e0f8b9a9e9fbed897f19ce41cbf3f Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Sun, 31 May 2015 14:11:36 -0500 Subject: [PATCH 3584/5359] initial stab at adding regex to search-replace --- features/search-replace.feature | 14 ++++++++++++++ php/WP_CLI/Iterators/Query.php | 2 +- php/WP_CLI/Iterators/Table.php | 1 - php/WP_CLI/SearchReplacer.php | 13 +++++++++++-- php/commands/search-replace.php | 14 +++++++++----- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index cba391557..4f950768a 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -81,6 +81,20 @@ Feature: Do global search/replace Checking: wp_posts.post_title 1 rows affected """ + @wip + Scenario: Regex search/replace + Given a WP install + When I run `wp search-replace '(Hello)\s(world)' '$2, $1' --regex` + Then STDOUT should contain: + """ + wp_posts + """ + When I run `wp post list --fields=post_title` + Then STDOUT should contain: + """ + world, Hello + """ + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php index 03e7fbe40..a5fdec554 100644 --- a/php/WP_CLI/Iterators/Query.php +++ b/php/WP_CLI/Iterators/Query.php @@ -36,7 +36,7 @@ class Query implements \Iterator { */ public function __construct( $query, $chunk_size = 500 ) { $this->query = $query; - + $this->count_query = preg_replace( '/^.*? FROM /', 'SELECT COUNT(*) FROM ', $query, 1, $replacements ); if ( $replacements != 1 ) $this->count_query = ''; diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index eb7d1d60f..71807f710 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -51,7 +51,6 @@ function __construct( $args = array() ) { $conditions = self::build_where_conditions( $args['where'] ); $where_sql = $conditions ? " WHERE $conditions" : ''; $query = "SELECT $fields FROM $table $where_sql"; - parent::__construct( $query, $args['chunk_size'] ); } diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index e3910b20b..d888eb81a 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -13,10 +13,11 @@ class SearchReplacer { * @param string $to What we want it to be replaced with. * @param bool $recurse_objects Should objects be recursively replaced? */ - function __construct( $from, $to, $recurse_objects = false ) { + function __construct( $from, $to, $recurse_objects = false, $regex = false ) { $this->from = $from; $this->to = $to; $this->recurse_objects = $recurse_objects; + $this->regex = $regex; // Get the XDebug nesting level. Will be zero (no limit) if no value is set $this->max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); @@ -80,7 +81,7 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data } else if ( is_string( $data ) ) { - $data = str_replace( $this->from, $this->to, $data ); + $data = $this->str_replace( $this->from, $this->to, $data ); } if ( $serialised ) @@ -92,5 +93,13 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data return $data; } + + private function str_replace( $from, $to, $data ) { + if ( $this->regex ) { + return preg_replace( "/$from/", $to, $data ); + } else { + return str_replace( $from, $to, $data ); + } + } } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f0d0c433d..9e0767fd7 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -52,6 +52,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--verbose] * : Prints rows to the console as they're updated. * + * [--regex] + * : Runs the search using a regular expression. Using --regex slows the search-replace down significantly. + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -71,6 +74,7 @@ public function __invoke( $args, $assoc_args ) { $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects' ); $verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); + $regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); $skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); @@ -110,9 +114,9 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $php_only || NULL !== $serialRow ) { + if ( $php_only || $regex || NULL !== $serialRow ) { $type = 'PHP'; - $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose ); + $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); } else { $type = 'SQL'; $count = self::sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ); @@ -219,7 +223,7 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $ver return $count; } - private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose ) { + private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -231,7 +235,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $args = array( 'table' => $table, 'fields' => $fields, - 'where' => "`$col`" . ' LIKE "%' . self::esc_like( $old ) . '%"', + 'where' => $regex ? '' : "`$col`" . ' LIKE "%' . self::esc_like( $old ) . '%"', 'chunk_size' => $chunk_size ); @@ -239,7 +243,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $count = 0; - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $recurse_objects ); + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $recurse_objects, $regex ); foreach ( $it as $row ) { if ( '' === $row->$col ) From 443359e563c6a81902e8714670e4a3d22c6da886 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Sun, 31 May 2015 14:59:02 -0500 Subject: [PATCH 3585/5359] adds a basic confirm message when scaffold will overwrite an existing file --- php/commands/scaffold.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 33060e4b2..50bcf8ce7 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -574,6 +574,9 @@ private function create_file( $filename, $contents ) { $wp_filesystem->mkdir( dirname( $filename ) ); + if ( file_exists( $filename ) ) { + WP_CLI::confirm( 'Scaffold will overwrite "' . $filename . '". Continue?' ); + } if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { WP_CLI::error( "Error creating file: $filename" ); } From 599536d40a7d58be9cc39a51a3c7881bed270306 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Sun, 31 May 2015 21:41:23 -0500 Subject: [PATCH 3586/5359] create_file accepts an array, wp-cli warns when fules will be overriden --- php/commands/scaffold.php | 42 +++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 50bcf8ce7..d26e52c97 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -153,7 +153,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) if ( $path = $this->get_output_path( $control_args, $subdir ) ) { $filename = $path . $slug . '.php'; - $this->create_file( $filename, $final_output ); + $this->create_files( array( $filename => $final_output ) ); WP_CLI::success( "Created $filename" ); } else { @@ -300,8 +300,10 @@ function child_theme( $args, $assoc_args ) { $this->maybe_create_themes_dir(); - $this->create_file( $theme_style_path, Utils\mustache_render( 'child_theme.mustache', $data ) ); - $this->create_file( $theme_functions_path, Utils\mustache_render( 'child_theme_functions.mustache', $data ) ); + $this->create_files( array( + $theme_style_path => Utils\mustache_render( 'child_theme.mustache', $data ), + $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) + ) ); WP_CLI::success( "Created $theme_dir" ); @@ -470,11 +472,12 @@ function plugin( $args, $assoc_args ) { $plugin_path = "$plugin_dir/$plugin_slug.php"; $plugin_readme_path = "$plugin_dir/readme.txt"; - $this->create_file( $plugin_path, Utils\mustache_render( 'plugin.mustache', $data ) ); - $this->create_file( $plugin_readme_path, Utils\mustache_render( 'plugin-readme.mustache', $data ) ); - $this->create_file( "$plugin_dir/package.json", Utils\mustache_render( 'plugin-packages.mustache', $data ) ); - $this->create_file( "$plugin_dir/Gruntfile.js", Utils\mustache_render( 'plugin-gruntfile.mustache', $data ) ); - + $this->create_files( array( + $plugin_path => Utils\mustache_render( 'plugin.mustache', $data ), + $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), + "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), + "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), + ) ); WP_CLI::success( "Created $plugin_dir" ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { @@ -547,8 +550,8 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); - $this->create_file( "$tests_dir/bootstrap.php", - Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ); + $this->create_files( array( "$tests_dir/bootstrap.php" => + Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ) ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, @@ -569,16 +572,21 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::success( "Created test files." ); } - private function create_file( $filename, $contents ) { + private function create_files( $files_and_contents ) { $wp_filesystem = $this->init_wp_filesystem(); - $wp_filesystem->mkdir( dirname( $filename ) ); - - if ( file_exists( $filename ) ) { - WP_CLI::confirm( 'Scaffold will overwrite "' . $filename . '". Continue?' ); + $pre_existing_files = array_filter( array_keys( $files_and_contents ), 'file_exists' ); + if ( ! empty( $pre_existing_files ) ) { + WP_CLI::warning( 'Scaffold will overwrite: ' . PHP_EOL . implode( PHP_EOL, $pre_existing_files ) ); + WP_CLI::confirm( 'Overwrite files and continue?' ); } - if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { - WP_CLI::error( "Error creating file: $filename" ); + + foreach ( $files_and_contents as $filename => $contents ) { + $wp_filesystem->mkdir( dirname( $filename ) ); + + if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { + WP_CLI::error( "Error creating file: $filename" ); + } } } From 5abfd5680c98f21332fb5c594b4a25c0cb084e61 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 00:23:29 +0300 Subject: [PATCH 3587/5359] use inside_phar() in one more place --- php/commands/cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index ddc4d0530..2c2d078a6 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -137,8 +137,8 @@ public function check_update( $_, $assoc_args ) { * @subcommand update */ public function update( $_, $assoc_args ) { - if ( 0 !== strpos( WP_CLI_ROOT, 'phar://' ) ) { - WP_CLI::error( "You can only self-update PHARs" ); + if ( ! Utils\inside_phar() ) { + WP_CLI::error( "You can only self-update Phar files." ); } $old_phar = realpath( $_SERVER['argv'][0] ); From 890f43f62973bc06765adf2d223c8d5637434b6f Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 00:39:06 +0300 Subject: [PATCH 3588/5359] clarify command description --- php/commands/server.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/server.php b/php/commands/server.php index e050fa4b6..47dea0f5b 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -3,7 +3,9 @@ class Server_Command extends WP_CLI_Command { /** - * Start a development server. + * Launch PHP's built-in web server for this specific WordPress installation. + * + * <http://php.net/manual/en/features.commandline.webserver.php> * * ## OPTIONS * From 9433772e164c100f01c589a1b5e346d622afb2ad Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 00:44:02 +0300 Subject: [PATCH 3589/5359] behat: s/start/launch in the background/ --- features/server.feature | 2 +- features/steps/when.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/server.feature b/features/server.feature index fc1a71663..0a0100685 100644 --- a/features/server.feature +++ b/features/server.feature @@ -3,7 +3,7 @@ Feature: Serve WordPress locally Scenario: Vanilla install Given a WP install - And I start `wp server --host=localhost --port=8181` + And I launch in the background `wp server --host=localhost --port=8181` When I run `curl -sS localhost:8181` Then STDOUT should contain: diff --git a/features/steps/when.php b/features/steps/when.php index b1ad61445..b0832493e 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -14,7 +14,7 @@ function invoke_proc( $proc, $mode ) { return $proc->$method(); } -$steps->When( '/^I start `([^`]+)`$/', +$steps->When( '/^I launch in the background `([^`]+)`$/', function ( $world, $cmd ) { $world->background_proc( $cmd ); } From a5fac0214872d2a3e8e8c9aa39b2ae56a3141406 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 00:45:50 +0300 Subject: [PATCH 3590/5359] ci: remove error reporting re-config it's up to the developer to change his php.ini file --- ci/behat-tags.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 145d90f88..18943e380 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -1,8 +1,5 @@ <?php -error_reporting(E_ALL); -ini_set('display_errors', 1); - function php_version_tags() { exec( 'grep "@require-php-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); } From 59931910afe61b8ed7e421bd82c73561daac2c00 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 00:50:49 +0300 Subject: [PATCH 3591/5359] add --docroot option fixes https://github.com/wp-cli/server-command/issues/3 --- php/commands/server.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index 47dea0f5b..cd88e98a0 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -9,12 +9,15 @@ class Server_Command extends WP_CLI_Command { * * ## OPTIONS * - * --host=<host> + * [--host=<host>] * : The hostname to bind the server to. Default: localhost * - * --port=<port> + * [--port=<port>] * : The port number to bind the server to. Default: 8080 * + * [--docroot=<path>] + * : The path to use as the document root. + * * ## EXAMPLES * * # Make the instance available on any address (with port 8080) @@ -34,16 +37,21 @@ function __invoke( $_, $assoc_args ) { $defaults = array( 'host' => 'localhost', - 'port' => 8080 + 'port' => 8080, + 'docroot' => false ); $assoc_args = array_merge( $defaults, $assoc_args ); - $config_path = WP_CLI::get_runner()->project_config_path; + $docroot = $assoc_args['docroot']; + + if ( !$docroot ) { + $config_path = WP_CLI::get_runner()->project_config_path; - if ( !$config_path ) { - $docroot = ABSPATH; - } else { - $docroot = dirname( $config_path ); + if ( !$config_path ) { + $docroot = ABSPATH; + } else { + $docroot = dirname( $config_path ); + } } $cmd = \WP_CLI\Utils\esc_cmd( PHP_BINARY . ' -S %s -t %s %s', From e23b2400cb56a28d8d44ef8bd516790e8773c7e9 Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 01:51:46 +0300 Subject: [PATCH 3592/5359] reorganize router functions --- php/router.php | 72 +++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/php/router.php b/php/router.php index 869129630..9e524e4b0 100644 --- a/php/router.php +++ b/php/router.php @@ -3,37 +3,11 @@ namespace WP_CLI\Router; -function get_full_host( $url ) { - $parsed_url = parse_url( $url ); - - $host = $parsed_url['host']; - if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) - $host .= ':' . $parsed_url['port']; - - return $host; -} - -function option_home( $url ) { - $GLOBALS['_wp_cli_original_url'] = $url; - - return 'http://' . $_SERVER['HTTP_HOST']; -} - -function option_siteurl( $url ) { - if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) - get_option('home'); - - $home_url_host = get_full_host( $GLOBALS['_wp_cli_original_url'] ); - $site_url_host = get_full_host( $url ); - - if ( $site_url_host == $home_url_host ) { - $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); - } - - return $url; -} - -// This should be identical to the normal WordPress add_filter() function. +/** + * This is a copy of WordPress's add_filter() function. + * + * We duplicate it because WordPress is not loaded yet. + */ function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { global $wp_filter, $merged_filters; @@ -43,6 +17,11 @@ function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) return true; } +/** + * This is a copy of WordPress's _wp_filter_build_unique_id() function. + * + * We duplicate it because WordPress is not loaded yet. + */ function _wp_filter_build_unique_id($tag, $function, $priority) { global $wp_filter; static $filter_id_count = 0; @@ -81,8 +60,35 @@ function _wp_filter_build_unique_id($tag, $function, $priority) { } } -add_filter( 'option_home', '\\WP_CLI\\Router\\option_home', 20 ); -add_filter( 'option_siteurl', '\\WP_CLI\\Router\\option_siteurl', 20 ); +function _get_full_host( $url ) { + $parsed_url = parse_url( $url ); + + $host = $parsed_url['host']; + if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) + $host .= ':' . $parsed_url['port']; + + return $host; +} + +add_filter( 'option_home', function ( $url ) { + $GLOBALS['_wp_cli_original_url'] = $url; + + return 'http://' . $_SERVER['HTTP_HOST']; +}, 20 ); + +add_filter( 'option_siteurl', function ( $url ) { + if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) + get_option('home'); + + $home_url_host = _get_full_host( $GLOBALS['_wp_cli_original_url'] ); + $site_url_host = _get_full_host( $url ); + + if ( $site_url_host == $home_url_host ) { + $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); + } + + return $url; +}, 20 ); $root = $_SERVER['DOCUMENT_ROOT']; $path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' ); From 92e0cbf82b2819e0b02c5c5701855d1a57fbb4da Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 1 Jun 2015 15:56:10 -0700 Subject: [PATCH 3593/5359] Switch php-cli-tools to `dev-master` so we can dogfood changes --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6cec94c7d..7d9ab3cb4 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.4", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", From c5d5d240e976e779ee5b8502ce45f8c224f265cf Mon Sep 17 00:00:00 2001 From: scribu <mail@scribu.net> Date: Tue, 2 Jun 2015 02:00:16 +0300 Subject: [PATCH 3594/5359] add a few more comments --- php/router.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/router.php b/php/router.php index 9e524e4b0..289840227 100644 --- a/php/router.php +++ b/php/router.php @@ -70,6 +70,7 @@ function _get_full_host( $url ) { return $host; } +// We need to trick WordPress into using the URL set by `wp server`, especially on multisite. add_filter( 'option_home', function ( $url ) { $GLOBALS['_wp_cli_original_url'] = $url; @@ -78,7 +79,7 @@ function _get_full_host( $url ) { add_filter( 'option_siteurl', function ( $url ) { if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) - get_option('home'); + get_option('home'); // trigger the option_home filter $home_url_host = _get_full_host( $GLOBALS['_wp_cli_original_url'] ); $site_url_host = _get_full_host( $url ); From 3fb5f393f26d246246e1feec464e452ba6054fb6 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Mon, 1 Jun 2015 22:38:03 -0500 Subject: [PATCH 3595/5359] added a WP_CLI@prompt --- php/class-wp-cli.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 44bf9ace5..d77e5269e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -286,6 +286,19 @@ public static function confirm( $question, $assoc_args = array() ) { } } + /** + * Prompt before continuing. + */ + public static function prompt( $question, $assoc_args = array() ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { + fwrite( STDOUT, $question . " [s/r] " ); + + $answer = trim( fgets( STDIN ) ); + + return ( 'r' == $answer ); + } + } + /** * Read value from a positional argument or from STDIN. * From 1e27028f13a8bb345a8d2b22d24b53e33ae4e396 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Mon, 1 Jun 2015 22:38:47 -0500 Subject: [PATCH 3596/5359] WIP; playing around with log message formats --- php/commands/scaffold.php | 44 ++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d26e52c97..f708158fa 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -472,13 +472,20 @@ function plugin( $args, $assoc_args ) { $plugin_path = "$plugin_dir/$plugin_slug.php"; $plugin_readme_path = "$plugin_dir/readme.txt"; - $this->create_files( array( + $files_written = $this->create_files( array( $plugin_path => Utils\mustache_render( 'plugin.mustache', $data ), $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), ) ); - WP_CLI::success( "Created $plugin_dir" ); + + if ( empty( $files_written ) ) { + WP_CLI::log( 'All files skipped' ); + } else { + WP_CLI::log( PHP_EOL ); + WP_CLI::success( "Created plugin files:" ); + WP_CLI::log( implode( PHP_EOL, $files_written ) ); + } if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir ) ); @@ -550,7 +557,7 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); - $this->create_files( array( "$tests_dir/bootstrap.php" => + $files_written = $this->create_files( array( "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ) ); $to_copy = array( @@ -569,25 +576,42 @@ function plugin_tests( $args, $assoc_args ) { } } + if ( empty( $files_written ) ) { + WP_CLI::log( 'All files skipped' ); + } else { + WP_CLI::log( PHP_EOL ); + WP_CLI::success( "Created plugin files:" ); + WP_CLI::log( implode( PHP_EOL, $files_written ) ); + } + WP_CLI::success( "Created test files." ); } private function create_files( $files_and_contents ) { $wp_filesystem = $this->init_wp_filesystem(); - - $pre_existing_files = array_filter( array_keys( $files_and_contents ), 'file_exists' ); - if ( ! empty( $pre_existing_files ) ) { - WP_CLI::warning( 'Scaffold will overwrite: ' . PHP_EOL . implode( PHP_EOL, $pre_existing_files ) ); - WP_CLI::confirm( 'Overwrite files and continue?' ); - } + $wrote_files = array(); foreach ( $files_and_contents as $filename => $contents ) { - $wp_filesystem->mkdir( dirname( $filename ) ); + $should_write_file = true; + + if ( file_exists( $filename ) ) { + WP_CLI::log( PHP_EOL ); + WP_CLI::warning( 'File already exists:' ); + WP_CLI::log( $filename ); + $should_write_file = WP_CLI::prompt( 'Skip this file, or replace it with scaffolding?' ); + } + + if ( $should_write_file ) { + $wp_filesystem->mkdir( dirname( $filename ) ); + } if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { WP_CLI::error( "Error creating file: $filename" ); + } elseif ( $should_write_file ) { + $wrote_files[] = $filename; } } + return $wrote_files; } /** From c668e24e5abaeb553c0dcb5594cf43add7b7689f Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Tue, 2 Jun 2015 10:15:57 -0500 Subject: [PATCH 3597/5359] adds a warning message to regex help text --- php/WP_CLI/Iterators/Table.php | 1 + php/commands/search-replace.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 71807f710..eb7d1d60f 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -51,6 +51,7 @@ function __construct( $args = array() ) { $conditions = self::build_where_conditions( $args['where'] ); $where_sql = $conditions ? " WHERE $conditions" : ''; $query = "SELECT $fields FROM $table $where_sql"; + parent::__construct( $query, $args['chunk_size'] ); } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 9e0767fd7..889a7923e 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -53,7 +53,7 @@ class Search_Replace_Command extends WP_CLI_Command { * : Prints rows to the console as they're updated. * * [--regex] - * : Runs the search using a regular expression. Using --regex slows the search-replace down significantly. + * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. * * ## EXAMPLES * From e3c833d856248638de4414f4eba6157dd660f727 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Tue, 2 Jun 2015 18:22:31 -0500 Subject: [PATCH 3598/5359] no longer logs every single file which gets created. prompts for additional files not originally covered --- php/commands/scaffold.php | 48 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f708158fa..5da178f08 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -201,6 +201,13 @@ function _s( $args, $assoc_args ) { 'author_uri' => "", ) ); + $_s_theme_path = "$theme_path/$data[theme_name]"; + $should_write_file = $this->prompt_if_files_will_be_overwritten( $_s_theme_path ); + if ( ! $should_write_file ) { + WP_CLI::log( 'No files created' ); + die; + } + $theme_description = "Custom theme: " . $data['theme_name'] . " developed by, " . $data['author']; $body = array(); @@ -235,6 +242,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -415,6 +423,10 @@ public function package_tests( $args, $assoc_args ) { $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); $file_path = $dir . basename( $file ); $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml' ), $file_path ); + + $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path ); + if ( ! $should_write_file ) continue; + $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); file_put_contents( $file_path, $contents ); if ( 'templates/install-package-tests.sh' === $file ) { @@ -483,8 +495,7 @@ function plugin( $args, $assoc_args ) { WP_CLI::log( 'All files skipped' ); } else { WP_CLI::log( PHP_EOL ); - WP_CLI::success( "Created plugin files:" ); - WP_CLI::log( implode( PHP_EOL, $files_written ) ); + WP_CLI::success( "Created plugin files." ); } if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { @@ -568,7 +579,13 @@ function plugin_tests( $args, $assoc_args ) { ); foreach ( $to_copy as $file => $dir ) { - $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", "$dir/$file", true ); + $file_name = "$dir/$file"; + + $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_name ); + if ( ! $should_write_file ) continue; + $files_written[] = $file_name; + + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", $file_name, true ); if ( 'install-wp-tests.sh' === $file ) { if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); @@ -580,11 +597,8 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::log( 'All files skipped' ); } else { WP_CLI::log( PHP_EOL ); - WP_CLI::success( "Created plugin files:" ); - WP_CLI::log( implode( PHP_EOL, $files_written ) ); + WP_CLI::success( "Created test files." ); } - - WP_CLI::success( "Created test files." ); } private function create_files( $files_and_contents ) { @@ -592,14 +606,7 @@ private function create_files( $files_and_contents ) { $wrote_files = array(); foreach ( $files_and_contents as $filename => $contents ) { - $should_write_file = true; - - if ( file_exists( $filename ) ) { - WP_CLI::log( PHP_EOL ); - WP_CLI::warning( 'File already exists:' ); - WP_CLI::log( $filename ); - $should_write_file = WP_CLI::prompt( 'Skip this file, or replace it with scaffolding?' ); - } + $should_write_file = $this->prompt_if_files_will_be_overwritten( $filename ); if ( $should_write_file ) { $wp_filesystem->mkdir( dirname( $filename ) ); @@ -614,6 +621,17 @@ private function create_files( $files_and_contents ) { return $wrote_files; } + private function prompt_if_files_will_be_overwritten( $filename ) { + $should_write_file = true; + if ( file_exists( $filename ) ) { + WP_CLI::log( PHP_EOL ); + WP_CLI::warning( 'File already exists:' ); + WP_CLI::log( $filename ); + $should_write_file = WP_CLI::prompt( 'Skip this file, or replace it with scaffolding?' ); + } + return $should_write_file; + } + /** * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. * Same goes for when plugin is being used. From 0a45e331d53cf5d75f306b89da3b9af803a7f323 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Tue, 2 Jun 2015 18:56:44 -0500 Subject: [PATCH 3599/5359] pulled out a method for logging whether files were crearted --- php/commands/scaffold.php | 59 +++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5da178f08..f42939403 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -153,9 +153,13 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) if ( $path = $this->get_output_path( $control_args, $subdir ) ) { $filename = $path . $slug . '.php'; - $this->create_files( array( $filename => $final_output ) ); + $files_written = $this->create_files( array( $filename => $final_output ) ); + log_whether_files_written( + $files_written, + $skip_message = "Skipped creating $filename", + $success_message = "Created $filename" + ); - WP_CLI::success( "Created $filename" ); } else { // STDOUT echo $final_output; @@ -308,12 +312,15 @@ function child_theme( $args, $assoc_args ) { $this->maybe_create_themes_dir(); - $this->create_files( array( + $files_written = $this->create_files( array( $theme_style_path => Utils\mustache_render( 'child_theme.mustache', $data ), $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ) ); - - WP_CLI::success( "Created $theme_dir" ); + log_whether_files_written( + $files_written, + $skip_message = 'All theme files were skipped.', + $success_message = "Created $theme_dir." + ); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); @@ -418,6 +425,7 @@ public function package_tests( $args, $assoc_args ) { 'features/extra/no-mail.php' => $extra_dir, ); + $files_written = array(); foreach ( $to_copy as $file => $dir ) { // file_get_contents() works with Phar-archived files $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); @@ -426,6 +434,7 @@ public function package_tests( $args, $assoc_args ) { $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path ); if ( ! $should_write_file ) continue; + $files_written[] = $file_path; $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); file_put_contents( $file_path, $contents ); @@ -433,8 +442,11 @@ public function package_tests( $args, $assoc_args ) { Process::create( Utils\esc_cmd( 'chmod +x %s', $file_path ) )->run(); } } - - WP_CLI::success( "Created test files." ); + log_whether_files_written( + $files_written, + $skip_message = 'All package tests were skipped.', + $success_message = 'Created test files.' + ); } @@ -491,12 +503,11 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), ) ); - if ( empty( $files_written ) ) { - WP_CLI::log( 'All files skipped' ); - } else { - WP_CLI::log( PHP_EOL ); - WP_CLI::success( "Created plugin files." ); - } + log_whether_files_written( + $files_written, + $skip_message = 'All plugin files were skipped.', + $success_message = 'Created plugin files.' + ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir ) ); @@ -592,13 +603,11 @@ function plugin_tests( $args, $assoc_args ) { } } } - - if ( empty( $files_written ) ) { - WP_CLI::log( 'All files skipped' ); - } else { - WP_CLI::log( PHP_EOL ); - WP_CLI::success( "Created test files." ); - } + log_whether_files_written( + $files_written, + $skip_message = 'All test files were skipped.', + $success_message = 'Created test files.' + ); } private function create_files( $files_and_contents ) { @@ -624,14 +633,22 @@ private function create_files( $files_and_contents ) { private function prompt_if_files_will_be_overwritten( $filename ) { $should_write_file = true; if ( file_exists( $filename ) ) { - WP_CLI::log( PHP_EOL ); WP_CLI::warning( 'File already exists:' ); WP_CLI::log( $filename ); $should_write_file = WP_CLI::prompt( 'Skip this file, or replace it with scaffolding?' ); + WP_CLI::log( PHP_EOL ); } return $should_write_file; } + private function log_whether_files_written( $files_written, $skip_message, $success_message ) { + if ( empty( $files_written ) ) { + WP_CLI::log( $skip_message ); + } else { + WP_CLI::success( $success_message ); + } + } + /** * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. * Same goes for when plugin is being used. From ad42a504e22e52ec34760306c961c9899f28fe6d Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Tue, 2 Jun 2015 18:57:58 -0500 Subject: [PATCH 3600/5359] fixes my last commit --- php/commands/scaffold.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index f42939403..a6f4e9632 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -154,7 +154,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $filename = $path . $slug . '.php'; $files_written = $this->create_files( array( $filename => $final_output ) ); - log_whether_files_written( + $this->log_whether_files_written( $files_written, $skip_message = "Skipped creating $filename", $success_message = "Created $filename" @@ -316,7 +316,7 @@ function child_theme( $args, $assoc_args ) { $theme_style_path => Utils\mustache_render( 'child_theme.mustache', $data ), $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ) ); - log_whether_files_written( + $this->log_whether_files_written( $files_written, $skip_message = 'All theme files were skipped.', $success_message = "Created $theme_dir." @@ -442,7 +442,7 @@ public function package_tests( $args, $assoc_args ) { Process::create( Utils\esc_cmd( 'chmod +x %s', $file_path ) )->run(); } } - log_whether_files_written( + $this->log_whether_files_written( $files_written, $skip_message = 'All package tests were skipped.', $success_message = 'Created test files.' @@ -503,7 +503,7 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), ) ); - log_whether_files_written( + $this->log_whether_files_written( $files_written, $skip_message = 'All plugin files were skipped.', $success_message = 'Created plugin files.' @@ -603,7 +603,7 @@ function plugin_tests( $args, $assoc_args ) { } } } - log_whether_files_written( + $this->log_whether_files_written( $files_written, $skip_message = 'All test files were skipped.', $success_message = 'Created test files.' From 03abffc532b9ad19194c51c6fdbb337d9674e6e2 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Wed, 3 Jun 2015 09:49:32 -0500 Subject: [PATCH 3601/5359] adds behat tests for --force overwriting files with scaffold --- features/scaffold.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 699b25513..db258777f 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -336,3 +336,17 @@ Feature: WordPress code scaffolding """ Error: Could not decompress your theme files """ + + @wip + Scenario: Overwrite existing files + Given a WP install + When I run `wp scaffold plugin test` + And I run `wp scaffold plugin test --force` + Then STDERR should contain: + """ + already exists + """ + And STDOUT should contain: + """ + Replaced + """ \ No newline at end of file From d49b4fed6988669bfef5ef344554f40568de66c7 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Wed, 3 Jun 2015 09:51:20 -0500 Subject: [PATCH 3602/5359] refactored WP_CLI::prompt --- php/class-wp-cli.php | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d77e5269e..dce06ca23 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -286,17 +286,23 @@ public static function confirm( $question, $assoc_args = array() ) { } } - /** - * Prompt before continuing. - */ - public static function prompt( $question, $assoc_args = array() ) { - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { - fwrite( STDOUT, $question . " [s/r] " ); - - $answer = trim( fgets( STDIN ) ); - - return ( 'r' == $answer ); - } + /** + * Prompt before continuing. + * + * @param string $question The question to pose + * @param bool $default The default response + * @param array $answers when the users responds with $answers[0] return false, with $answers[1] return true + * @param bool $hide Hide the user's response + * @return bool + */ + public static function prompt( $question, $default = false, $answers = array( 'no', 'yes' ), $hide = false ) { + $marker = '[' . implode( '/', $answers ) . ']: '; + + do { + $answer = cli\prompt( $question, $default, $marker, $hide ); + } while ( ! in_array( $answer, $answers ) ); + + return $answers[ 1 ] === $answer; } /** From e6eb2365a623bef60e1e1fe5dd1a74fd76e032af Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Wed, 3 Jun 2015 09:52:13 -0500 Subject: [PATCH 3603/5359] implements --force to overwrite existing files when scaffolding --- php/commands/scaffold.php | 72 ++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a6f4e9632..18f44ffd5 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -37,6 +37,9 @@ class Scaffold_Command extends WP_CLI_Command { * [--raw] * : Just generate the `register_post_type()` call and nothing else. * + * [--force] + * : Overwrite files that already exist. + * * @subcommand post-type * * @alias cpt @@ -85,6 +88,9 @@ function post_type( $args, $assoc_args ) { * [--raw] * : Just generate the `register_taxonomy()` call and nothing else. * + * [--force] + * : Overwrite files that already exist. + * * ## EXAMPLES * * wp scaffold taxonomy venue --post_types=event,presentation @@ -153,7 +159,8 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) if ( $path = $this->get_output_path( $control_args, $subdir ) ) { $filename = $path . $slug . '.php'; - $files_written = $this->create_files( array( $filename => $final_output ) ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( $files_written, $skip_message = "Skipped creating $filename", @@ -191,6 +198,10 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * * [--sassify] * : Include stylesheets as SASS + * + * [--force] + * : Overwrite files that already exist. + * */ function _s( $args, $assoc_args ) { @@ -206,7 +217,8 @@ function _s( $args, $assoc_args ) { ) ); $_s_theme_path = "$theme_path/$data[theme_name]"; - $should_write_file = $this->prompt_if_files_will_be_overwritten( $_s_theme_path ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + $should_write_file = $this->prompt_if_files_will_be_overwritten( $_s_theme_path, $force ); if ( ! $should_write_file ) { WP_CLI::log( 'No files created' ); die; @@ -292,6 +304,9 @@ function _s( $args, $assoc_args ) { * [--enable-network] * : Enable the newly created child theme for the entire network. * + * [--force] + * : Overwrite files that already exist. + * * @subcommand child-theme */ function child_theme( $args, $assoc_args ) { @@ -312,10 +327,11 @@ function child_theme( $args, $assoc_args ) { $this->maybe_create_themes_dir(); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $theme_style_path => Utils\mustache_render( 'child_theme.mustache', $data ), $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) - ) ); + ), $force ); $this->log_whether_files_written( $files_written, $skip_message = 'All theme files were skipped.', @@ -376,6 +392,9 @@ private function get_output_path( $assoc_args, $subdir ) { * <dir> * : The package directory to generate tests for. * + * [--force] + * : Overwrite files that already exist. + * * ## EXAMPLE * * wp scaffold package-tests /path/to/command/dir/ @@ -432,7 +451,8 @@ public function package_tests( $args, $assoc_args ) { $file_path = $dir . basename( $file ); $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml' ), $file_path ); - $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path, $force ); if ( ! $should_write_file ) continue; $files_written[] = $file_path; @@ -472,6 +492,10 @@ public function package_tests( $args, $assoc_args ) { * * [--activate-network] * : Network activate the newly generated plugin. + * + * [--force] + * : Overwrite files that already exist. + * */ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; @@ -496,12 +520,13 @@ function plugin( $args, $assoc_args ) { $plugin_path = "$plugin_dir/$plugin_slug.php"; $plugin_readme_path = "$plugin_dir/readme.txt"; + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $plugin_path => Utils\mustache_render( 'plugin.mustache', $data ), $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), - ) ); + ), $force ); $this->log_whether_files_written( $files_written, @@ -510,7 +535,7 @@ function plugin( $args, $assoc_args ) { ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { - WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir ) ); + WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir, 'force' => $force ) ); } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { @@ -545,6 +570,9 @@ function plugin( $args, $assoc_args ) { * [--dir=<dirname>] * : Generate test files for a non-standard plugin path. If no plugin slug is specified, the directory name is used. * + * [--force] + * : Overwrite files that already exist. + * * ## EXAMPLE * * wp scaffold plugin-tests hello @@ -579,8 +607,9 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( "$tests_dir/bootstrap.php" => - Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ) ); + Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ), $force ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, @@ -591,8 +620,8 @@ function plugin_tests( $args, $assoc_args ) { foreach ( $to_copy as $file => $dir ) { $file_name = "$dir/$file"; - - $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_name ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_name, $force ); if ( ! $should_write_file ) continue; $files_written[] = $file_name; @@ -610,12 +639,12 @@ function plugin_tests( $args, $assoc_args ) { ); } - private function create_files( $files_and_contents ) { + private function create_files( $files_and_contents, $force ) { $wp_filesystem = $this->init_wp_filesystem(); $wrote_files = array(); foreach ( $files_and_contents as $filename => $contents ) { - $should_write_file = $this->prompt_if_files_will_be_overwritten( $filename ); + $should_write_file = $this->prompt_if_files_will_be_overwritten( $filename, $force ); if ( $should_write_file ) { $wp_filesystem->mkdir( dirname( $filename ) ); @@ -630,14 +659,23 @@ private function create_files( $files_and_contents ) { return $wrote_files; } - private function prompt_if_files_will_be_overwritten( $filename ) { + private function prompt_if_files_will_be_overwritten( $filename, $force ) { $should_write_file = true; - if ( file_exists( $filename ) ) { - WP_CLI::warning( 'File already exists:' ); - WP_CLI::log( $filename ); - $should_write_file = WP_CLI::prompt( 'Skip this file, or replace it with scaffolding?' ); - WP_CLI::log( PHP_EOL ); + if ( ! file_exists( $filename ) ) { + return true; } + + WP_CLI::warning( $filename . ' already exists.' ); + if ( ! $force ) { + $should_write_file = WP_CLI::prompt( + $question = 'Skip this file, or replace it with scaffolding?', + $default = false, + $answers = array( 's', 'r' ), + $hide = false + ); + } + WP_CLI::log( $should_write_file ? 'Replaced' : 'Skipped' ); + return $should_write_file; } From 998883c02363b2b82b8f25af5320ed1ad6a9726c Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Wed, 3 Jun 2015 13:42:59 -0500 Subject: [PATCH 3604/5359] removes @wip from behat test --- features/search-replace.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 4f950768a..f684f9ed4 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -81,7 +81,7 @@ Feature: Do global search/replace Checking: wp_posts.post_title 1 rows affected """ - @wip + Scenario: Regex search/replace Given a WP install When I run `wp search-replace '(Hello)\s(world)' '$2, $1' --regex` From 1505c7d4d8f3e61dd8b1ba5d03728cc81c2b77fa Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Wed, 3 Jun 2015 14:09:28 -0500 Subject: [PATCH 3605/5359] pulls SearchReplacer->str_replace() into SearchReplacer->_run() --- php/WP_CLI/SearchReplacer.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index d888eb81a..45181703b 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -81,7 +81,11 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data } else if ( is_string( $data ) ) { - $data = $this->str_replace( $this->from, $this->to, $data ); + if ( $this->regex ) { + $data = preg_replace( "/$from/", $to, $data ); + } else { + $data = str_replace( $from, $to, $data ); + } } if ( $serialised ) @@ -93,13 +97,5 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data return $data; } - - private function str_replace( $from, $to, $data ) { - if ( $this->regex ) { - return preg_replace( "/$from/", $to, $data ); - } else { - return str_replace( $from, $to, $data ); - } - } } From 59d6036f168b3b0cf33b225b1d79aa75387652c5 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 00:20:12 -0500 Subject: [PATCH 3606/5359] converted spaces to tabs --- php/class-wp-cli.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index dce06ca23..0f4ef5c84 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -286,21 +286,21 @@ public static function confirm( $question, $assoc_args = array() ) { } } - /** - * Prompt before continuing. - * - * @param string $question The question to pose - * @param bool $default The default response - * @param array $answers when the users responds with $answers[0] return false, with $answers[1] return true - * @param bool $hide Hide the user's response - * @return bool - */ + /** + * Prompt before continuing. + * + * @param string $question The question to pose + * @param bool $default The default response + * @param array $answers when the users responds with $answers[0] return false, with $answers[1] return true + * @param bool $hide Hide the user's response + * @return bool + */ public static function prompt( $question, $default = false, $answers = array( 'no', 'yes' ), $hide = false ) { - $marker = '[' . implode( '/', $answers ) . ']: '; + $marker = '[' . implode( '/', $answers ) . ']: '; - do { - $answer = cli\prompt( $question, $default, $marker, $hide ); - } while ( ! in_array( $answer, $answers ) ); + do { + $answer = cli\prompt( $question, $default, $marker, $hide ); + } while ( ! in_array( $answer, $answers ) ); return $answers[ 1 ] === $answer; } From 796ca695a1625889248f8b1e8215d9f0e363f8ca Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 00:26:36 -0500 Subject: [PATCH 3607/5359] improves file overwrite prompt output --- php/commands/scaffold.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 18f44ffd5..9422c443b 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -665,7 +665,8 @@ private function prompt_if_files_will_be_overwritten( $filename, $force ) { return true; } - WP_CLI::warning( $filename . ' already exists.' ); + WP_CLI::warning( 'File already exists' ); + WP_CLI::log( $filename ); if ( ! $force ) { $should_write_file = WP_CLI::prompt( $question = 'Skip this file, or replace it with scaffolding?', @@ -674,7 +675,8 @@ private function prompt_if_files_will_be_overwritten( $filename, $force ) { $hide = false ); } - WP_CLI::log( $should_write_file ? 'Replaced' : 'Skipped' ); + $outcome = $should_write_file ? 'Replaced' : 'Skipped'; + WP_CLI::log( $outcome . PHP_EOL ); return $should_write_file; } From 8e16143b4da654dd402d24ddafb136acc5dff47a Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 00:30:06 -0500 Subject: [PATCH 3608/5359] fixes my last commit... --- php/WP_CLI/SearchReplacer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index 45181703b..d832ed2b3 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -82,9 +82,9 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data else if ( is_string( $data ) ) { if ( $this->regex ) { - $data = preg_replace( "/$from/", $to, $data ); + $data = preg_replace( "/$this->from/", $this->to, $data ); } else { - $data = str_replace( $from, $to, $data ); + $data = str_replace( $this->from, $this->to, $data ); } } From 49c79ce17b1cc2f78acb43432ace2e5e5088c417 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 15:15:10 -0500 Subject: [PATCH 3609/5359] fixes formatting issues --- features/scaffold.feature | 3 +-- php/commands/scaffold.php | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index db258777f..01e5aab28 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -337,7 +337,6 @@ Feature: WordPress code scaffolding Error: Could not decompress your theme files """ - @wip Scenario: Overwrite existing files Given a WP install When I run `wp scaffold plugin test` @@ -349,4 +348,4 @@ Feature: WordPress code scaffolding And STDOUT should contain: """ Replaced - """ \ No newline at end of file + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 9422c443b..d7675dc45 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -453,7 +453,9 @@ public function package_tests( $args, $assoc_args ) { $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path, $force ); - if ( ! $should_write_file ) continue; + if ( ! $should_write_file ) { + continue; + } $files_written[] = $file_path; $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); From 77498838ddd07aecb83c015c9a384c85f9649b4c Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 15:30:13 -0500 Subject: [PATCH 3610/5359] moved prompt method into scaffold command. fixed a logic error in prompt_if_files_will_be_overwritten --- php/class-wp-cli.php | 19 ------------------- php/commands/scaffold.php | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0f4ef5c84..44bf9ace5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -286,25 +286,6 @@ public static function confirm( $question, $assoc_args = array() ) { } } - /** - * Prompt before continuing. - * - * @param string $question The question to pose - * @param bool $default The default response - * @param array $answers when the users responds with $answers[0] return false, with $answers[1] return true - * @param bool $hide Hide the user's response - * @return bool - */ - public static function prompt( $question, $default = false, $answers = array( 'no', 'yes' ), $hide = false ) { - $marker = '[' . implode( '/', $answers ) . ']: '; - - do { - $answer = cli\prompt( $question, $default, $marker, $hide ); - } while ( ! in_array( $answer, $answers ) ); - - return $answers[ 1 ] === $answer; - } - /** * Read value from a positional argument or from STDIN. * diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d7675dc45..604438054 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -647,11 +647,12 @@ private function create_files( $files_and_contents, $force ) { foreach ( $files_and_contents as $filename => $contents ) { $should_write_file = $this->prompt_if_files_will_be_overwritten( $filename, $force ); - - if ( $should_write_file ) { - $wp_filesystem->mkdir( dirname( $filename ) ); + if ( ! $should_write_file ) { + continue; } + $wp_filesystem->mkdir( dirname( $filename ) ); + if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { WP_CLI::error( "Error creating file: $filename" ); } elseif ( $should_write_file ) { @@ -670,13 +671,16 @@ private function prompt_if_files_will_be_overwritten( $filename, $force ) { WP_CLI::warning( 'File already exists' ); WP_CLI::log( $filename ); if ( ! $force ) { - $should_write_file = WP_CLI::prompt( - $question = 'Skip this file, or replace it with scaffolding?', - $default = false, - $answers = array( 's', 'r' ), - $hide = false - ); + do { + $answer = cli\prompt( + 'Skip this file, or replace it with scaffolding?', + $default = false, + $marker = '[s/r]: ' + ); + } while ( ! in_array( $answer, array( 's', 'r' ) ) ); + $should_write_file = 'r' === $answer; } + $outcome = $should_write_file ? 'Replaced' : 'Skipped'; WP_CLI::log( $outcome . PHP_EOL ); From eb7ae1f7017e5d217cb1d6fd3dd75fbc105a33d4 Mon Sep 17 00:00:00 2001 From: Kevin Doole <kdoole@farmmedia.com> Date: Thu, 4 Jun 2015 15:39:02 -0500 Subject: [PATCH 3611/5359] for accuracy, changed copy in logged outcome of skip/replace prompt --- features/scaffold.feature | 2 +- php/commands/scaffold.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 01e5aab28..fc7aeea93 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -347,5 +347,5 @@ Feature: WordPress code scaffolding """ And STDOUT should contain: """ - Replaced + Replacing """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 604438054..1db452d18 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -681,7 +681,7 @@ private function prompt_if_files_will_be_overwritten( $filename, $force ) { $should_write_file = 'r' === $answer; } - $outcome = $should_write_file ? 'Replaced' : 'Skipped'; + $outcome = $should_write_file ? 'Replacing' : 'Skipping'; WP_CLI::log( $outcome . PHP_EOL ); return $should_write_file; From f149f0dde7050c514350287e1dea0c4974dbb9bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 8 Jun 2015 14:35:02 -0700 Subject: [PATCH 3612/5359] Internalize `wp_clean_update_cache()` to prevent fatals in WP 4.0 The function was introduced in WP 4.1 --- php/WP_CLI/CommandWithTranslation.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index b46ed1274..e83e39342 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -58,7 +58,7 @@ public function list_( $args, $assoc_args ) { $translations = $this->get_all_languages(); $available = $this->get_installed_languages(); - wp_clean_update_cache(); // Clear existing update caches. + $this->wp_clean_update_cache(); // Clear existing update caches. wp_version_check(); // Check for Core translation updates. wp_update_themes(); // Check for Theme translation updates. wp_update_plugins(); // Check for Plugin translation updates. @@ -159,7 +159,7 @@ public function update( $args, $assoc_args ) { return; } - wp_clean_update_cache(); // Clear existing update caches. + $this->wp_clean_update_cache(); // Clear existing update caches. wp_version_check(); // Check for Core translation updates. wp_update_themes(); // Check for Theme translation updates. wp_update_plugins(); // Check for Plugin translation updates. @@ -369,4 +369,17 @@ protected function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); } + /** + * Replicates wp_clean_update_cache() for use in WP 4.0 + */ + private static function wp_clean_update_cache() { + if ( function_exists( 'wp_clean_plugins_cache' ) ) { + wp_clean_plugins_cache(); + } else { + delete_site_transient( 'update_plugins' ); + } + wp_clean_themes_cache(); + delete_site_transient( 'update_core' ); + } + } From 429d4e590ebb70fa7b7e5d8bfedfd5cd21805e66 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 8 Jun 2015 14:58:33 -0700 Subject: [PATCH 3613/5359] Switch tests to WP 4.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ab5b14b7..58b187c0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=4.1 + - WP_VERSION=4.2 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: From 4242406c71100559064a7ed2113088f2d5549ea9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 8 Jun 2015 15:56:27 -0700 Subject: [PATCH 3614/5359] Only run `help` early when WordPress isn't loaded When WordPress is loaded, we may have a plugin adding commands to a namespace --- features/help.feature | 28 ++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index e94455d51..d73cde31e 100644 --- a/features/help.feature +++ b/features/help.feature @@ -129,3 +129,31 @@ Feature: Get help about WP-CLI commands """ __destruct """ + + Scenario: Help for commands loaded into existing namespaces + Given a WP install + And a wp-content/plugins/test-cli/command.php file: + """ + <?php + // Plugin Name: Test CLI Extra Site Command + + class Test_CLI_Extra_Site_Command extends WP_CLI_Command { + + /** + * A dummy command. + * + * @subcommand my-command + */ + function my_command() {} + + } + + WP_CLI::add_command( 'site test-extra', 'Test_CLI_Extra_Site_Command' ); + """ + And I run `wp plugin activate test-cli` + + When I run `wp help site` + Then STDOUT should contain: + """ + test-extra + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c2e29132d..218a72a13 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -596,7 +596,7 @@ public function before_wp_load() { self::set_wp_root( $this->find_wp_root() ); // First try at showing man page - if ( 'help' === $this->arguments[0] && ( isset( $this->arguments[1] ) || !$this->wp_exists() ) ) { + if ( 'help' === $this->arguments[0] && ! $this->wp_exists() ) { $this->_run_command(); } From 5cd6baeede34a3b47a908e16b262b8a0e6dad782 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 9 Jun 2015 18:47:40 +0100 Subject: [PATCH 3615/5359] Correct the error message text in `wp cli update` If the `wp cli update` command errors, it tells you to attempt `wp cli self-update` again, which is incorrect. --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 2c2d078a6..e578e4b04 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -177,7 +177,7 @@ public function update( $_, $assoc_args ) { if ( 0 !== $status ) { WP_CLI::error_multi_line( $output ); - WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli self-update again.' ); + WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli update again.' ); } WP_CLI::log( 'New version works. Proceeding to replace.' ); From d015fa84cfcb1211cabd7b530e59e2db91623c0a Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Sat, 20 Jun 2015 16:08:42 +0100 Subject: [PATCH 3616/5359] Update the Travis notification syntax The [Travis linter](http://lint.travis-ci.org/) complains about the `notifications` syntax as it is currently. This fixes that. --- templates/.travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index b4393cc7d..cd4bc26e7 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -1,8 +1,9 @@ language: php notifications: - on_success: never - on_failure: change + email: + on_success: never + on_failure: change php: - 5.3 From 3d115990b19cc416194c2946b3da5a1d88b9213c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Jun 2015 13:04:36 -0700 Subject: [PATCH 3617/5359] Restore expected behavior of `WP_TESTS_DIR` environment variable In 49e9a59f5c47513a1581a3f5260a70c0350c27c1, the default value was changed to include `includes` in the path. Because this change broke compatibility with existing use of `WP_TESTS_DIR`, and broke scaffolding generally, we should restore the expected behavior. --- templates/install-wp-tests.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 6b2d4aefd..c96a09f17 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -11,7 +11,7 @@ DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-latest} -WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib/includes} +WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} set -ex @@ -53,21 +53,21 @@ install_test_suite() { fi # set up testing suite if it doesn't yet exist - if [ ! "$(ls -A $WP_TESTS_DIR)" ]; then + if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR + svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR/includes fi cd $WP_TESTS_DIR if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php $(dirname ${WP_TESTS_DIR})/wp-tests-config.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" $(dirname ${WP_TESTS_DIR})/wp-tests-config.php + download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php fi } From e20d953b4321c99a746e9291baf4364ceb4cd9fd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Jun 2015 14:06:51 -0700 Subject: [PATCH 3618/5359] Bump to latest version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 41915c799..61e6e92d9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.19.1 +0.19.2 From f83b66637c264ee5599897d772131d5fcbb40ee0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Jun 2015 14:15:25 -0700 Subject: [PATCH 3619/5359] Backtick `wp rewrite flush` snippet, so it gets formatted in docs --- php/commands/rewrite.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index f7df4ff5a..d2d8e5942 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -17,8 +17,8 @@ class Rewrite_Command extends WP_CLI_Command { * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module * to your wp-cli.yml or config.yml. For example: * - * apache_modules: - * - mod_rewrite + * `apache_modules: + * - mod_rewrite` * * ## OPTIONS * From b315fca810fce7307fa94c952cb7dc125708fd86 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 20 Jun 2015 14:24:12 -0700 Subject: [PATCH 3620/5359] Support `Requests` installed to parent project in `http_request()` --- php/utils.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/php/utils.php b/php/utils.php index 1dd6bd2b6..88d504657 100644 --- a/php/utils.php +++ b/php/utils.php @@ -440,6 +440,24 @@ function replace_path_consts( $source, $path ) { * @return object */ function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { + + $cert_path = '/rmccue/requests/library/Requests/Transport/cacert.pem'; + if ( inside_phar() ) { + // cURL can't read Phar archives + $options['verify'] = extract_from_phar( + WP_CLI_ROOT . '/vendor' . $cert_path ); + } else { + foreach( get_vendor_paths() as $vendor_path ) { + if ( file_exists( $vendor_path . $cert_path ) ) { + $options['verify'] = $vendor_path . $cert_path; + break; + } + } + if ( empty( $options['verify'] ) ){ + WP_CLI::error_log( "Cannot find SSL certificate." ); + } + } + // cURL can't read Phar archives $options['verify'] = extract_from_phar( WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); From 4d789c09f637fa55a6529a4d3f2fb3419cc882e4 Mon Sep 17 00:00:00 2001 From: Morgan Estes <morgan.estes@gmail.com> Date: Tue, 23 Jun 2015 21:19:06 -0500 Subject: [PATCH 3621/5359] Fixed the 'realy' typo that annoyed me. --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 0f6117b2c..dc83e9050 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -31,7 +31,7 @@ class Media_Command extends WP_CLI_Command { */ function regenerate( $args, $assoc_args = array() ) { if ( empty( $args ) ) { - WP_CLI::confirm( 'Do you realy want to regenerate all images?', $assoc_args ); + WP_CLI::confirm( 'Do you really want to regenerate all images?', $assoc_args ); } $skip_delete = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ); From e2adbe4722413036b8f81548f1437ff2ac4b1918 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 24 Jun 2015 03:49:47 -0700 Subject: [PATCH 3622/5359] Catch failure to extract WordPress archive file And provide a helpful error message --- php/commands/core.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d5f5d3c5d..0a82e617c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -178,7 +178,12 @@ public function download( $args, $assoc_args ) { } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); } - self::_extract( $temp, ABSPATH ); + + try { + self::_extract( $temp, ABSPATH ); + } catch ( Exception $e ) { + WP_CLI::error( "Couldn't extract WordPress archive. " . $e->getMessage() ); + } $cache->import( $cache_key, $temp ); unlink($temp); } From d293c04506a05d1cc705b0723eaddb71f26b6a5c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 24 Jun 2015 03:54:17 -0700 Subject: [PATCH 3623/5359] Remove code missed in b315fca810fce7307fa94c952cb7dc125708fd86 --- php/utils.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index 88d504657..78cda6bdc 100644 --- a/php/utils.php +++ b/php/utils.php @@ -458,10 +458,6 @@ function http_request( $method, $url, $data = null, $headers = array(), $options } } - // cURL can't read Phar archives - $options['verify'] = extract_from_phar( - WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); - try { $request = \Requests::request( $url, $headers, $data, $method, $options ); return $request; From e2bc7220cddaa3833045385d1171869849c77d22 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 24 Jun 2015 04:45:42 -0700 Subject: [PATCH 3624/5359] Document one-liner for listing all plugins in a network --- php/commands/plugin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 2a941cba6..3a6e27fbd 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -608,6 +608,9 @@ function delete( $args, $assoc_args = array() ) { * * wp plugin list --status=active --format=json * + * # List plugins on each site in a network + * wp site list --field=url | xargs -n 1 -I % wp plugin list --url=% + * * @subcommand list */ public function list_( $_, $assoc_args ) { From bdf63466bd8258faeafc587ff9eca036274b4585 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 24 Jun 2015 04:56:09 -0700 Subject: [PATCH 3625/5359] Failing test case for checking cached partial upgrades --- features/core.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/core.feature b/features/core.feature index 3fa82fe65..f8769736c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -652,3 +652,19 @@ Feature: Manage WordPress installation """ Error: Release not found. """ + + Scenario: Ensure cached partial upgrades aren't used in full upgrade + Given a WP install + And an empty cache + + When I run `wp core download --version=4.2.1 --force` + And I run `wp core update` + Then STDOUT should not be empty + + When I run `wp core download --version=4.1.1 --force` + And I run `wp core update` + And I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ From 10305edbbe636a96a46ec323142c336a3bb6864b Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Wed, 24 Jun 2015 20:05:45 -0700 Subject: [PATCH 3626/5359] accept associative args with no right-side data --- php/WP_CLI/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index f8120926f..21ae2ad3f 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -89,7 +89,7 @@ public static function extract_assoc( $arguments ) { $assoc_args[] = array( $matches[1], false ); } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { $assoc_args[] = array( $matches[1], true ); - } elseif ( preg_match( '|^--([^=]+)=(.+)|s', $arg, $matches ) ) { + } elseif ( preg_match( '|^--([^=]+)=(.*)|s', $arg, $matches ) ) { $assoc_args[] = array( $matches[1], $matches[2] ); } else { $positional_args[] = $arg; From e5a12ee02234a5cd14d887f87f8705e84cbe6dbe Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Fri, 26 Jun 2015 13:23:36 -0700 Subject: [PATCH 3627/5359] add configurator::extract_assoc unit tests --- tests/test-configurator.php | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test-configurator.php diff --git a/tests/test-configurator.php b/tests/test-configurator.php new file mode 100644 index 000000000..55c291acb --- /dev/null +++ b/tests/test-configurator.php @@ -0,0 +1,51 @@ +<?php + +use WP_CLI\Configurator; + +class ConfiguratorTest extends PHPUnit_Framework_TestCase { + + function testExtractAssoc() { + $args = Configurator::extract_assoc( array( 'foo', '--bar', '--baz=text' ) ); + + $this->assertCount( 1, $args[0] ); + $this->assertCount( 2, $args[1] ); + + $this->assertEquals( 'foo', $args[0][0] ); + + $this->assertEquals( 'bar', $args[1][0][0] ); + $this->assertTrue( $args[1][0][1] ); + + $this->assertEquals( 'baz', $args[1][1][0] ); + $this->assertEquals( 'text', $args[1][1][1] ); + + } + + function testExtractAssocNoValue() { + $args = Configurator::extract_assoc( array( 'foo', '--bar=', '--baz=text' ) ); + + $this->assertCount( 1, $args[0] ); + $this->assertCount( 2, $args[1] ); + + $this->assertEquals( 'foo', $args[0][0] ); + + $this->assertEquals( 'bar', $args[1][0][0] ); + $this->assertEmpty( $args[1][0][1] ); + + $this->assertEquals( 'baz', $args[1][1][0] ); + $this->assertEquals( 'text', $args[1][1][1] ); + + } + + function testExtractAssocDoubleDashInValue() { + $args = Configurator::extract_assoc( array( '--test=text--text' ) ); + + $this->assertCount( 0, $args[0] ); + $this->assertCount( 1, $args[1] ); + + $this->assertEquals( 'test', $args[1][0][0] ); + $this->assertEquals( 'text--text', $args[1][0][1] ); + + } + + +} \ No newline at end of file From 0b8a45d78e0f24c9bf12fb1ebd7943860027c716 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 29 Jun 2015 09:47:01 -0300 Subject: [PATCH 3628/5359] exit with a message when --url parameter is used with a unexistent site url --- features/flags.feature | 9 +++++++++ php/wp-settings-cli.php | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index 064648099..912c1ab6a 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -13,6 +13,15 @@ Feature: Global flags } """ + Scenario: Invalid URL + Given a WP multisite install + + When I try `wp post list --url=invalid.example.com` + Then STDERR should be: + """ + Error: Site invalid.example.com not found. + """ + Scenario: Quiet run Given a WP install diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 6944f3797..f94283025 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -76,6 +76,13 @@ unset( $values, $key, $value ); } +// In a multisite install, die if unable to find site given in --url parameter +if ( is_multisite() ) { + add_action( 'ms_site_not_found', function( $current_site, $domain, $path ) { + WP_CLI::error( "Site {$domain}{$path} not found." ); + }, 10, 3 ); +} + // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From 5d136aea03cd6b28f682edece6119a58606354de Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 29 Jun 2015 14:55:48 -0300 Subject: [PATCH 3629/5359] run test only if wp_version >= 3.9 the hook ms_site_not_found was introduced in version 3.9 --- features/flags.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/flags.feature b/features/flags.feature index 912c1ab6a..b50006f24 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -13,6 +13,7 @@ Feature: Global flags } """ + @require-wp-3.9 Scenario: Invalid URL Given a WP multisite install From c3eb7391b86239fd9f40a1ae28c6539c5ea4a5f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 6 Jul 2015 09:25:24 -0700 Subject: [PATCH 3630/5359] Remove redundant `@subcommand` tag --- php/commands/cli.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index e578e4b04..71053c4a3 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -133,8 +133,6 @@ public function check_update( $_, $assoc_args ) { * * [--yes] * : Do not prompt for confirmation - * - * @subcommand update */ public function update( $_, $assoc_args ) { if ( ! Utils\inside_phar() ) { From fa1d278121d7fbe614d55746e10f2b8bfd9abbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 16 Jul 2015 20:59:53 +0200 Subject: [PATCH 3631/5359] Fixing bash completion for now, closes #1919 --- utils/wp-completion.bash | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash index 94896ca52..9df572b6d 100644 --- a/utils/wp-completion.bash +++ b/utils/wp-completion.bash @@ -1,6 +1,7 @@ # bash completion for the `wp` command _wp_complete() { + local OLD_IFS="$IFS" local cur=${COMP_WORDS[COMP_CWORD]} IFS=$'\n'; # want to preserve spaces at the end @@ -15,5 +16,8 @@ _wp_complete() { else COMPREPLY=( ${opts[*]} ) fi + + IFS="$OLD_IFS" + return 0 } complete -o nospace -F _wp_complete wp From ca6348caf7fb085cdaf424a653dae4de4e03da83 Mon Sep 17 00:00:00 2001 From: Akeda Bagus <admin@gedex.web.id> Date: Sun, 19 Jul 2015 00:29:14 +0700 Subject: [PATCH 3632/5359] Fix delete user help message. It should 'delete' instead of 'update'. --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 1a255792a..08b173be5 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -158,7 +158,7 @@ public function get( $args, $assoc_args ) { * ## OPTIONS * * <user>... - * : The user login, user email, or user ID of the user(s) to update. + * : The user login, user email, or user ID of the user(s) to delete. * * [--network] * : On multisite, delete the user from the entire network. From 204079e246a4362f66ade613fbb42c45658f0006 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Jul 2015 07:44:06 -0700 Subject: [PATCH 3633/5359] Properly pass error message to `error_multi_line()` in `cli update` `exec()` only _returns_ the last line, and renders the rest. `WP_CLI\Process` is more versatile for our needs --- php/commands/cli.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 71053c4a3..ee7114e07 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -170,11 +170,11 @@ public function update( $_, $assoc_args ) { Utils\http_request( 'GET', $download_url, null, $headers, $options ); - exec( "php $temp --version", $output, $status ); - - if ( 0 !== $status ) { - WP_CLI::error_multi_line( $output ); - + $process = WP_CLI\Process::create( "php $temp --version" ); + $result = $process->run(); + if ( 0 !== $result->return_code ) { + $multi_line = explode( PHP_EOL, $result->stderr ); + WP_CLI::error_multi_line( $multi_line ); WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli update again.' ); } From 366d60274647e40537a5b0509ece60c1f2732030 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Jul 2015 08:00:34 -0700 Subject: [PATCH 3634/5359] Pass thru `--allow-root` in `cli update` This will let root update WP-CLI when it errored previously --- php/commands/cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index ee7114e07..837ee4b8d 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -170,7 +170,8 @@ public function update( $_, $assoc_args ) { Utils\http_request( 'GET', $download_url, null, $headers, $options ); - $process = WP_CLI\Process::create( "php $temp --version" ); + $allow_root = WP_CLI::get_runner()->config['allow-root'] ? '--allow-root' : ''; + $process = WP_CLI\Process::create( "php $temp --version {$allow_root}" ); $result = $process->run(); if ( 0 !== $result->return_code ) { $multi_line = explode( PHP_EOL, $result->stderr ); From dbb358d6978266bd9581a593d824f5e95cd01379 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Jul 2015 08:09:59 -0700 Subject: [PATCH 3635/5359] Prevent error notice in `cli update` ``` PHP Warning: unlink(/tmp/wp-cli-cacert.pem): No such file or directory in phar:///home/vagrant/.wp-cli/test.phar/php/utils.php on line 28 ``` Because we make a remote request against Github twice, the shutdown function is registered (and called) twice. The file is deleted the first time. --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 78cda6bdc..2bfa71d78 100644 --- a/php/utils.php +++ b/php/utils.php @@ -24,7 +24,7 @@ function extract_from_phar( $path ) { copy( $path, $tmp_path ); register_shutdown_function( function() use ( $tmp_path ) { - unlink( $tmp_path ); + @unlink( $tmp_path ); } ); return $tmp_path; From d8895b6ad3c8fd3706b4c7f528d3f3df2d6a1252 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 21 Jul 2015 08:55:29 -0700 Subject: [PATCH 3636/5359] Use `wp (plugin|theme) update --format=summary` for one-liner messages --- features/plugin.feature | 7 +++++-- features/theme.feature | 7 +++++-- php/WP_CLI/CommandWithUpgrade.php | 28 +++++++++++++++++----------- php/commands/plugin.php | 3 +++ php/commands/theme.php | 3 +++ 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index cee0eb4a7..0eb663708 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -118,8 +118,11 @@ Feature: Manage WordPress plugins Error: Please specify one or more plugins, or use --all. """ - When I run `wp plugin update --all` - Then STDOUT should not be empty + When I run `wp plugin update --all --format=summary | grep 'updated successfully from'` + Then STDOUT should contain: + """ + Akismet updated successfully from version 2.5.6 to version + """ Scenario: Activate a network-only plugin on single site Given a WP install diff --git a/features/theme.feature b/features/theme.feature index c8557e468..cf8143185 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -78,8 +78,11 @@ Feature: Manage WordPress themes Error: Please specify one or more themes, or use --all. """ - When I run `wp theme update --all` - Then STDOUT should not be empty + When I run `wp theme update --all --format=summary | grep 'updated successfully from'` + Then STDOUT should contain: + """ + P2 updated successfully from version 1.4.1 to version + """ Scenario: Get the path of an installed theme Given a WP install diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 6119b8b01..d4c526ddf 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -264,18 +264,24 @@ protected function update_many( $args, $assoc_args ) { \WP_CLI::error( $line ); } - if ($num_to_update > 0) { - $status = array(); - foreach($items_to_update as $item_to_update => $info) { - $status[$item_to_update] = array( - 'name' => $info['name'], - 'old_version' => $info['version'], - 'new_version' => $info['update_version'], - 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', - ); + if ( $num_to_update > 0 ) { + if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { + foreach( $items_to_update as $item_to_update => $info ) { + $message = $result[$item_to_update] !== null ? 'updated successfully' : 'did not update'; + \WP_CLI::log( "{$info['title']} {$message} from version {$info['version']} to version {$info['update_version']}" ); + } + } else { + $status = array(); + foreach($items_to_update as $item_to_update => $info) { + $status[$item_to_update] = array( + 'name' => $info['name'], + 'old_version' => $info['version'], + 'new_version' => $info['update_version'], + 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', + ); + } + \WP_CLI\Utils\format_items( 'table', $status, array( 'name', 'old_version', 'new_version', 'status' ) ); } - \WP_CLI\Utils\format_items( 'table', $status, - array( 'name', 'old_version', 'new_version', 'status' ) ); } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 3a6e27fbd..5b3860fad 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -331,6 +331,9 @@ protected function install_from_repo( $slug, $assoc_args ) { * [--all] * : If set, all plugins that have updates will be updated. * + * [--format=<format>] + * : Output summary as table or summary. Defaults to table. + * * [--version=<version>] * : If set, the plugin will be updated to the specified version. * diff --git a/php/commands/theme.php b/php/commands/theme.php index 254afc949..0cebcebfa 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -443,6 +443,9 @@ public function get( $args, $assoc_args ) { * [--all] * : If set, all themes that have updates will be updated. * + * [--format=<format>] + * : Output summary as table or summary. Defaults to table. + * * [--version=<version>] * : If set, the plugin will be updated to the specified version. * From 7b2e1e7382a4ef15bce249d95ac6f678192adbe9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 26 Jul 2015 19:01:05 -0700 Subject: [PATCH 3637/5359] Update core tests to reflect new minor WP version --- features/core.feature | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/features/core.feature b/features/core.feature index 3fa82fe65..d54e48b72 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,11 +326,11 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | - | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | - | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | - | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | - | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | + | 4.2.3 | major | https://wordpress.org/wordpress-4.2.3.zip | + | 4.1.6 | major | https://wordpress.org/wordpress-4.1.6.zip | + | 4.0.6 | major | https://wordpress.org/wordpress-4.0.6.zip | + | 3.9.7 | major | https://wordpress.org/wordpress-3.9.7.zip | + | 3.8.9 | minor | https://wordpress.org/wordpress-3.8.9.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -341,10 +341,10 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.2.2 | major | https://wordpress.org/wordpress-4.2.2.zip | - | 4.1.5 | major | https://wordpress.org/wordpress-4.1.5.zip | - | 4.0.5 | major | https://wordpress.org/wordpress-4.0.5.zip | - | 3.9.6 | major | https://wordpress.org/wordpress-3.9.6.zip | + | 4.2.3 | major | https://wordpress.org/wordpress-4.2.3.zip | + | 4.1.6 | major | https://wordpress.org/wordpress-4.1.6.zip | + | 4.0.6 | major | https://wordpress.org/wordpress-4.0.6.zip | + | 3.9.7 | major | https://wordpress.org/wordpress-3.9.7.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -355,7 +355,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.8 | minor | https://wordpress.org/wordpress-3.8.8.zip | + | 3.8.9 | minor | https://wordpress.org/wordpress-3.8.9.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From 06e9d1f27942db745d77980c3702e5c5d3f3d375 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 27 Jul 2015 14:47:50 -0700 Subject: [PATCH 3638/5359] Prevent undefined notice when no `--format=<format>` is supplied ``` PHP Notice: Undefined index: format in /home/vagrant/.wp-cli/php/WP_CLI/CommandWithTerms.php on line 80 ``` --- php/WP_CLI/CommandWithTerms.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index f906f7b3c..285ae2994 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -67,6 +67,11 @@ abstract class CommandWithTerms extends \WP_CLI_Command { */ public function list_( $args, $assoc_args ) { + $defaults = array( + 'format' => 'table', + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + $object_id = array_shift( $args ); $taxonomy_names = $args; $taxonomy_args = array(); From 5424174f46faef1bd6894f7a09e5bea8519f3eb6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 27 Jul 2015 15:02:04 -0700 Subject: [PATCH 3639/5359] Failing test case for #1944 --- features/post.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/features/post.feature b/features/post.feature index 012c61f02..31d909306 100644 --- a/features/post.feature +++ b/features/post.feature @@ -216,3 +216,14 @@ Feature: Manage WordPress posts """ 1 """ + + Scenario: Update categories on a post + When I run `wp term create category "Test Category" --porcelain` + Then save STDOUT as {TERM_ID} + + When I run `wp post update 1 --post_category={TERM_ID}` + And I run `wp post term list 1 category --format=json --fields=name` + Then STDOUT should be: + """ + [{"name":"Test Category"}] + """ From e79934b64c6906e3fa8f0316644d82e0a2044016 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 27 Jul 2015 15:04:48 -0700 Subject: [PATCH 3640/5359] Properly handle `post_category` for `wp post update` --- php/commands/post.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/post.php b/php/commands/post.php index e0ae7a855..3d5fa4557 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -107,6 +107,10 @@ public function update( $args, $assoc_args ) { break; } + if ( isset( $assoc_args['post_category'] ) ) { + $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); + } + parent::_update( $args, $assoc_args, function ( $params ) { return wp_update_post( $params, true ); } ); From 10167ce3695f450e00184f0db5988578a782eebf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 27 Jul 2015 15:28:58 -0700 Subject: [PATCH 3641/5359] Create a new role from another role with `--clone=<role>` --- features/roles.feature | 41 ++++++++++++++++++++++++++++++++++++++++- php/commands/role.php | 34 +++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index bf62c1c2b..53ac7046a 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -10,6 +10,12 @@ Feature: Manage WordPress roles | Subscriber | subscriber | | Editor | editor | + When I run `wp role create reporter Reporter` + Then STDOUT should be: + """ + Success: Role with key reporter created. + """ + Scenario: Resetting a role When I run `wp role reset author` Then STDOUT should be: @@ -41,4 +47,37 @@ Feature: Manage WordPress roles Then STDOUT should be: """ Success: All default roles reset. - """ \ No newline at end of file + """ + + Scenario: Cloning a role + When I try `wp role create reporter Reporter --clone=no-role` + Then STDERR should be: + """ + Error: 'no-role' role not found. + """ + + When I run `wp role create reporter Reporter --clone=author` + Then STDOUT should be: + """ + Success: Role with key reporter created. Cloned capabilities from author. + """ + + When I run `wp role list` + Then STDOUT should be a table containing rows: + | name | role | + | Reporter | reporter | + + When I run `wp cap list reporter` + Then STDOUT should be: + """ + upload_files + edit_posts + edit_published_posts + publish_posts + read + level_2 + level_1 + level_0 + delete_posts + delete_published_posts + """ diff --git a/php/commands/role.php b/php/commands/role.php index 436fb689a..31b76cf95 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -92,25 +92,49 @@ public function exists( $args ) { * <role-name> * : The publicly visible name of the role. * + * [--clone=<role>] + * : Clone capabilities from an existing role. + * * ## EXAMPLES * * wp role create approver Approver * * wp role create productadmin "Product Administrator" */ - public function create( $args ) { + public function create( $args, $assoc_args ) { + global $wp_roles; + self::persistence_check(); $role_key = array_shift( $args ); $role_name = array_shift( $args ); - if ( empty( $role_key ) || empty( $role_name ) ) + if ( empty( $role_key ) || empty( $role_name ) ) { WP_CLI::error( "Can't create role, insufficient information provided."); + } - if ( ! add_role( $role_key, $role_name ) ) + $capabilities = false; + if ( ! empty( $assoc_args['clone'] ) ) { + $role_obj = $wp_roles->get_role( $assoc_args['clone'] ); + if ( ! $role_obj ) { + WP_CLI::error( "'{$assoc_args['clone']}' role not found." ); + } + $capabilities = array_keys( $role_obj->capabilities ); + } + + if ( add_role( $role_key, $role_name ) ) { + if ( ! empty( $capabilities ) ) { + $role_obj = $wp_roles->get_role( $role_key ); + foreach( $capabilities as $cap ) { + $role_obj->add_cap( $cap ); + } + WP_CLI::success( sprintf( "Role with key %s created. Cloned capabilities from %s.", $role_key, $assoc_args['clone'] ) ); + } else { + WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + } + } else { WP_CLI::error( "Role couldn't be created." ); - else - WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + } } /** From d4cd2b97087d419c330896efb61751562f49f986 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 27 Jul 2015 16:00:03 -0700 Subject: [PATCH 3642/5359] Designate version in-progress with `-alpha` --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 61e6e92d9..4863f59c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.19.2 +0.20.0-alpha From 5ef1cbd413cc20778bb8bf66f8eb9828672fad5e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 31 Jul 2015 09:08:31 -0700 Subject: [PATCH 3643/5359] Document how to delete inactive plugins --- php/commands/plugin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 3a6e27fbd..ccf69eb4f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -561,6 +561,9 @@ function is_installed( $args, $assoc_args = array() ) { * ## EXAMPLES * * wp plugin delete hello + * + * # Delete inactive plugins + * wp plugin delete $(wp plugin list --status=inactive --field=name) */ function delete( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { From 2156c86cee6784d3fc7707320f06ce78b9015d20 Mon Sep 17 00:00:00 2001 From: Chris Montgomery <chris@montchr.io> Date: Mon, 3 Aug 2015 23:03:39 -0400 Subject: [PATCH 3644/5359] add doc for CommandWithMeta->get() --- php/WP_CLI/CommandWithMeta.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 9e9b07518..c2010277b 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -77,6 +77,12 @@ public function list_( $args, $assoc_args ) { /** * Get meta field value. * + * <id> + * : The ID of the object. + * + * <key> + * : The name of the meta field to get. + * * @synopsis <id> <key> [--format=<format>] */ public function get( $args, $assoc_args ) { From 8ce9199e5938fab754cf1ae482274611195a8431 Mon Sep 17 00:00:00 2001 From: Chris Montgomery <chris@montchr.io> Date: Mon, 3 Aug 2015 23:04:26 -0400 Subject: [PATCH 3645/5359] correct typo in CommandWithMeta->delete() --- php/WP_CLI/CommandWithMeta.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index c2010277b..97d0c74a2 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -105,7 +105,7 @@ public function get( $args, $assoc_args ) { * : The ID of the object. * * <key> - * : The name of the meta field to create. + * : The name of the meta field to delete. * * [<value>] * : The value to delete. If omitted, all rows with key will deleted. From d9dcff5297e5be2340da4ad7197501d8eb0fa10a Mon Sep 17 00:00:00 2001 From: Chris Montgomery <chris@montchr.io> Date: Mon, 3 Aug 2015 23:13:09 -0400 Subject: [PATCH 3646/5359] add CommandWithMeta->get() format option to docs --- php/WP_CLI/CommandWithMeta.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 97d0c74a2..73f86458e 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -83,6 +83,9 @@ public function list_( $args, $assoc_args ) { * <key> * : The name of the meta field to get. * + * [--format=<format>] + * : Accepted values: table, json. Default: table + * * @synopsis <id> <key> [--format=<format>] */ public function get( $args, $assoc_args ) { From e122de344402b4a3c5736c70f635696ff48adaca Mon Sep 17 00:00:00 2001 From: Ryan McCue <me@ryanmccue.info> Date: Tue, 4 Aug 2015 11:48:45 +0200 Subject: [PATCH 3647/5359] Unset things we don't need during import With large imports, this can cause memory issues due to parsing the data twice and keeping it loaded in memory. --- php/commands/import.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/import.php b/php/commands/import.php index f63df2f5c..815d137df 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -75,6 +75,11 @@ private function import_wxr( $file, $args ) { // Prepare the data to be used in process_author_mapping(); $wp_import->get_authors_from_import( $import_data ); + + // We no longer need the original data, so unset to avoid using excess + // memory. + unset( $import_data ); + $author_data = array(); foreach ( $wp_import->authors as $wxr_author ) { $author = new \stdClass; @@ -102,6 +107,8 @@ private function import_wxr( $file, $args ) { $author_in = wp_list_pluck( $author_mapping, 'old_user_login' ); $author_out = wp_list_pluck( $author_mapping, 'new_user_login' ); + unset( $author_mapping, $author_data ); + // $user_select needs to be an array of user IDs $user_select = array(); $invalid_user_select = array(); @@ -115,6 +122,8 @@ private function import_wxr( $file, $args ) { if ( ! empty( $invalid_user_select ) ) return new WP_Error( 'invalid-author-mapping', sprintf( "These user_logins are invalid: %s", implode( ',', $invalid_user_select ) ) ); + unset( $author_out ); + // Drive the import $wp_import->fetch_attachments = !in_array( 'attachment', $args['skip'] ); $_GET = array( 'import' => 'wordpress', 'step' => 2 ); From dbbb417d4cb0a2c879d9b07ef9b9f6a9210bf08a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Aug 2015 07:50:46 -0700 Subject: [PATCH 3648/5359] Update tests for WordPress 4.2.4 and related point releases --- features/core.feature | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/features/core.feature b/features/core.feature index d54e48b72..872771ac9 100644 --- a/features/core.feature +++ b/features/core.feature @@ -325,12 +325,12 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.2.3 | major | https://wordpress.org/wordpress-4.2.3.zip | - | 4.1.6 | major | https://wordpress.org/wordpress-4.1.6.zip | - | 4.0.6 | major | https://wordpress.org/wordpress-4.0.6.zip | - | 3.9.7 | major | https://wordpress.org/wordpress-3.9.7.zip | - | 3.8.9 | minor | https://wordpress.org/wordpress-3.8.9.zip | + | version | update_type | package_url | + | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | + | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | + | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | + | 3.9.8 | major | https://wordpress.org/wordpress-3.9.8.zip | + | 3.8.10 | minor | https://wordpress.org/wordpress-3.8.10.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -340,11 +340,11 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.2.3 | major | https://wordpress.org/wordpress-4.2.3.zip | - | 4.1.6 | major | https://wordpress.org/wordpress-4.1.6.zip | - | 4.0.6 | major | https://wordpress.org/wordpress-4.0.6.zip | - | 3.9.7 | major | https://wordpress.org/wordpress-3.9.7.zip | + | version | update_type | package_url | + | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | + | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | + | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | + | 3.9.8 | major | https://wordpress.org/wordpress-3.9.8.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -354,8 +354,8 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 3.8.9 | minor | https://wordpress.org/wordpress-3.8.9.zip | + | version | update_type | package_url | + | 3.8.10 | minor | https://wordpress.org/wordpress-3.8.10.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From 867e57b5e7384ba81eebe23184a95c02ab818592 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 4 Aug 2015 09:08:19 -0700 Subject: [PATCH 3649/5359] Remove unnecessary backslashes from `CommandWithMeta` --- php/WP_CLI/CommandWithMeta.php | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 9e9b07518..25a0d363d 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -2,6 +2,8 @@ namespace WP_CLI; +use WP_CLI; + /** * Base class for WP-CLI commands that deal with metadata * @@ -84,12 +86,12 @@ public function get( $args, $assoc_args ) { $object_id = $this->check_object_id( $object_id ); - $value = \get_metadata( $this->meta_type, $object_id, $meta_key, true ); + $value = get_metadata( $this->meta_type, $object_id, $meta_key, true ); if ( '' === $value ) die(1); - \WP_CLI::print_value( $value, $assoc_args ); + WP_CLI::print_value( $value, $assoc_args ); } /** @@ -111,12 +113,12 @@ public function delete( $args, $assoc_args ) { $object_id = $this->check_object_id( $object_id ); - $success = \delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $success = delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { - \WP_CLI::success( "Deleted custom field." ); + WP_CLI::success( "Deleted custom field." ); } else { - \WP_CLI::error( "Failed to delete custom field." ); + WP_CLI::error( "Failed to delete custom field." ); } } @@ -140,17 +142,17 @@ public function delete( $args, $assoc_args ) { public function add( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); - $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); + $meta_value = WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); + $meta_value = WP_CLI::read_value( $meta_value, $assoc_args ); $object_id = $this->check_object_id( $object_id ); - $success = \add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { - \WP_CLI::success( "Added custom field." ); + WP_CLI::success( "Added custom field." ); } else { - \WP_CLI::error( "Failed to add custom field." ); + WP_CLI::error( "Failed to add custom field." ); } } @@ -176,8 +178,8 @@ public function add( $args, $assoc_args ) { public function update( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; - $meta_value = \WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); - $meta_value = \WP_CLI::read_value( $meta_value, $assoc_args ); + $meta_value = WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); + $meta_value = WP_CLI::read_value( $meta_value, $assoc_args ); $object_id = $this->check_object_id( $object_id ); @@ -185,14 +187,14 @@ public function update( $args, $assoc_args ) { $old_value = sanitize_meta( $meta_key, get_metadata( $this->meta_type, $object_id, $meta_key, true ), $this->meta_type ); if ( $meta_value === $old_value ) { - \WP_CLI::success( "Value passed for custom field '$meta_key' is unchanged." ); + WP_CLI::success( "Value passed for custom field '$meta_key' is unchanged." ); } else { - $success = \update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { - \WP_CLI::success( "Updated custom field '$meta_key'." ); + WP_CLI::success( "Updated custom field '$meta_key'." ); } else { - \WP_CLI::error( "Failed to update custom field '$meta_key'." ); + WP_CLI::error( "Failed to update custom field '$meta_key'." ); } } From c7d97fb93936282fb9a9d36b830e24961f453405 Mon Sep 17 00:00:00 2001 From: Chris Montgomery <chris@montchr.io> Date: Tue, 4 Aug 2015 12:27:26 -0400 Subject: [PATCH 3650/5359] remove @synopsis from CommandWithMeta->get() --- php/WP_CLI/CommandWithMeta.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 73f86458e..dd348b5c6 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -85,8 +85,6 @@ public function list_( $args, $assoc_args ) { * * [--format=<format>] * : Accepted values: table, json. Default: table - * - * @synopsis <id> <key> [--format=<format>] */ public function get( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; From 6f31197280806e73572cd386d5c252edd6501e3a Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 15 Aug 2015 11:27:29 -0400 Subject: [PATCH 3651/5359] Change the default argument for 'post_type' from 'all' to 'any' --- php/commands/export.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index f790e4c7d..8b60c22ec 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -33,7 +33,7 @@ class Export_Command extends WP_CLI_Command { * * [--post_type=<post-type>] * : Export only posts with this post_type. Separate multiple post types with a - * comma. Defaults to all. + * comma. Defaults to "any". * * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. @@ -181,7 +181,7 @@ private function check_end_date( $date ) { } private function check_post_type( $post_type ) { - if ( is_null( $post_type ) ) + if ( is_null( $post_type ) || 'any' === $post_type ) return true; $post_type = array_unique( array_filter( explode( ',', $post_type ) ) ); @@ -190,7 +190,7 @@ private function check_post_type( $post_type ) { foreach ( $post_type as $type ) { if ( ! in_array( $type, $post_types ) ) { WP_CLI::warning( sprintf( - 'The post type %s does not exist. Choose "all" or any of these existing post types instead: %s', + 'The post type %s does not exist. Choose "any" or any of these existing post types instead: %s', $type, implode( ", ", $post_types ) ) ); From db7ed2ed2a512c96aaf20f671cb5a4d26d782e6a Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 15 Aug 2015 11:36:04 -0400 Subject: [PATCH 3652/5359] Good advice: test against what you're expecting, not what you're expecting *not* to see --- features/export.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/export.feature b/features/export.feature index e86546cd6..27a470c1a 100644 --- a/features/export.feature +++ b/features/export.feature @@ -130,9 +130,9 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: + Then STDERR should contain: """ - Warning: + Success: """ When I run `wp post generate --count=10` From 505023389cac7bdda02bc1b4b097563a7facf2a5 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 15 Aug 2015 11:37:31 -0400 Subject: [PATCH 3653/5359] Stick closer to the original language, since 'any' isn't truly the default value --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 8b60c22ec..de8ab4063 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -33,7 +33,7 @@ class Export_Command extends WP_CLI_Command { * * [--post_type=<post-type>] * : Export only posts with this post_type. Separate multiple post types with a - * comma. Defaults to "any". + * comma. Defaults to all. * * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. From 6bee93886bf0435cde7d194b27ac87226ae2d902 Mon Sep 17 00:00:00 2001 From: Steve Grunwell <steve.grunwell@10up.com> Date: Sat, 15 Aug 2015 16:00:24 +0000 Subject: [PATCH 3654/5359] Fix some broken feature tests with odd expectations --- features/export.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/export.feature b/features/export.feature index 27a470c1a..58d183546 100644 --- a/features/export.feature +++ b/features/export.feature @@ -78,9 +78,9 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: + Then STDOUT should contain: """ - Warning: + Success: """ When I run `wp site empty --yes` @@ -130,7 +130,7 @@ Feature: Export content. Given a WP install When I run `wp plugin install wordpress-importer --activate` - Then STDERR should contain: + Then STDOUT should contain: """ Success: """ @@ -233,7 +233,7 @@ Feature: Export content. And save STDOUT 'Writing to file %s' as {EXPORT_FILE} Then the {EXPORT_FILE} file should contain: """ - <wp:category_nicename>apple</wp:category_nicename> + <category domain="category" nicename="apple"><![CDATA[Apple]]></category> """ When I run `wp site empty --yes` From 7d9a1ee8022e583c413bd9efe92126fa9e59f37f Mon Sep 17 00:00:00 2001 From: Steve Grunwell <stevegrunwell@gmail.com> Date: Sat, 15 Aug 2015 13:21:44 -0400 Subject: [PATCH 3655/5359] Ensure that the comma-separated --post_type changes won't affect the rest of the exporter --- php/export/class-wp-export-query.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 2b7c2f4ae..4d271b48f 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -161,7 +161,7 @@ private function calculate_post_ids() { private function post_type_where() { global $wpdb; - $post_types_filters = array( 'can_export' => true, 'name' => null ); + $post_types_filters = array( 'can_export' => true ); if ( $this->filters['post_type'] ) { $post_types = $this->filters['post_type']; @@ -248,7 +248,7 @@ private function get_timestamp_for_the_last_day_of_a_month( $yyyy_mm ) { private function category_where() { global $wpdb; - if ( 'post' != $this->filters['post_type'] ) { + if ( 'post' != $this->filters['post_type'] && ! in_array( 'post', (array) $this->filters['post_type'] ) ) { return; } $category = $this->find_category_from_any_object( $this->filters['category'] ); From 1aab880df588d3a400ed4f169580722f22872bdb Mon Sep 17 00:00:00 2001 From: Marc Addeo <marcaddeo@gmail.com> Date: Mon, 17 Aug 2015 11:12:24 -0400 Subject: [PATCH 3656/5359] Add the docroot option to the synopsis so wp-cli parses it as a valid option --- php/commands/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/server.php b/php/commands/server.php index cd88e98a0..a4be4a9e4 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -27,7 +27,7 @@ class Server_Command extends WP_CLI_Command { * sudo wp server --host=localhost.localdomain --port=80 * * @when before_wp_load - * @synopsis [--host=<host>] [--port=<port>] + * @synopsis [--host=<host>] [--port=<port>] [--docroot=<docroot>] */ function __invoke( $_, $assoc_args ) { $min_version = '5.4'; From bb5196c4d5f5fb8e2aaa26f00854e73b6984e617 Mon Sep 17 00:00:00 2001 From: Marc Addeo <marcaddeo@gmail.com> Date: Mon, 17 Aug 2015 11:51:10 -0400 Subject: [PATCH 3657/5359] Remove the `@synopsis` annotation completely, as it is deprecated --- php/commands/server.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/server.php b/php/commands/server.php index a4be4a9e4..d82fc7be6 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -27,7 +27,6 @@ class Server_Command extends WP_CLI_Command { * sudo wp server --host=localhost.localdomain --port=80 * * @when before_wp_load - * @synopsis [--host=<host>] [--port=<port>] [--docroot=<docroot>] */ function __invoke( $_, $assoc_args ) { $min_version = '5.4'; From dc8502de2d5fb39fe2430b4447633a171628adbb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 18 Aug 2015 16:25:57 -0700 Subject: [PATCH 3658/5359] Ensure `$pagenow` global is always set Core sets the variable in `wp-includes/vars.php` --- php/wp-settings-cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index f94283025..41e8b79df 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -218,8 +218,9 @@ // Define and enforce our SSL constants wp_ssl_constants( ); -// Don't create common globals, but we still need wp_is_mobile() +// Don't create common globals, but we still need wp_is_mobile() and $pagenow // require( ABSPATH . WPINC . '/vars.php' ); +$GLOBALS['pagenow'] = null; function wp_is_mobile() { return false; } From 63a8987cbd8c698ba5ad5c652ff49c007623f467 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 20 Aug 2015 05:53:38 -0700 Subject: [PATCH 3659/5359] Update tests for WordPress 4.3 --- features/core.feature | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 872771ac9..a9882c81d 100644 --- a/features/core.feature +++ b/features/core.feature @@ -326,6 +326,7 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.3 | major | https://wordpress.org/wordpress-4.3.zip | | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | @@ -335,12 +336,13 @@ Feature: Manage WordPress installation When I run `wp core check-update --format=count` Then STDOUT should be: """ - 5 + 6 """ When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | + | 4.3 | major | https://wordpress.org/wordpress-4.3.zip | | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | @@ -349,7 +351,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --major --format=count` Then STDOUT should be: """ - 4 + 5 """ When I run `wp core check-update --minor` From d12c64285e646c3c63eff87c14eaea664bec8206 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 20 Aug 2015 06:28:25 -0700 Subject: [PATCH 3660/5359] Fix typo in `apache_modules()` PHPdoc --- php/commands/rewrite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d2d8e5942..4fabc7d69 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -222,7 +222,7 @@ public function list_( $args, $assoc_args ) { * to see: * * 1. if the $is_apache variable is set. - * 2. if the mod_rewrite module is returned from the apche_get_modules + * 2. if the mod_rewrite module is returned from the apache_get_modules * function. * * To get this to work with wp-cli you'll need to add the mod_rewrite module From 3d018a5b70ced75926d5db83f137fba8f8b68c33 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 20 Aug 2015 13:15:35 -0700 Subject: [PATCH 3661/5359] Clarify `wp post term` documentation --- php/WP_CLI/CommandWithTerms.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index 285ae2994..bfae4653a 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -125,7 +125,7 @@ public function remove( $args, $assoc_args ) { } /** - * Add a term. Appends to existed + * Add a term. Appends to existing set of terms on the object. * * <id> * : The ID of the object. @@ -134,7 +134,7 @@ public function remove( $args, $assoc_args ) { * : The name of the taxonomy type to be added. * * <term>... - * : The name of the term or terms to be added. + * : The slug of the term or terms to be added. */ public function add( $args, $assoc_args ) { $object_id = array_shift( $args ); @@ -155,7 +155,7 @@ public function add( $args, $assoc_args ) { } /** - * Set terms. Replaces existing terms + * Set terms. Replaces existing terms on the object. * * <id> * : The ID of the object. @@ -164,7 +164,7 @@ public function add( $args, $assoc_args ) { * : The name of the taxonomy type to be updated. * * <term>... - * : The name of the term or terms to be updated. + * : The slug of the term or terms to be updated. */ public function set( $args, $assoc_args ) { $object_id = array_shift( $args ); From 92075fe75b63bb78b84b529e26067c469a7d677d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 22 Aug 2015 07:32:16 -0700 Subject: [PATCH 3662/5359] Try against the next major release --- features/core.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 40cbfe3da..59e487978 100644 --- a/features/core.feature +++ b/features/core.feature @@ -660,11 +660,11 @@ Feature: Manage WordPress installation And an empty cache When I run `wp core download --version=4.2.1 --force` - And I run `wp core update` + And I run `wp core update --version=4.2.2` Then STDOUT should not be empty When I run `wp core download --version=4.1.1 --force` - And I run `wp core update` + And I run `wp core update --version=4.2.2` And I run `wp core verify-checksums` Then STDOUT should be: """ From e3b779d70da410b93368cebe248ffff2caeb731e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 22 Aug 2015 07:52:03 -0700 Subject: [PATCH 3663/5359] Use the proper key for the result array `$item_to_update` is some arbitrary string that only works for plugins --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index d4c526ddf..47d425066 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -267,7 +267,7 @@ protected function update_many( $args, $assoc_args ) { if ( $num_to_update > 0 ) { if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { foreach( $items_to_update as $item_to_update => $info ) { - $message = $result[$item_to_update] !== null ? 'updated successfully' : 'did not update'; + $message = $result[ $info['update_id'] ] !== null ? 'updated successfully' : 'did not update'; \WP_CLI::log( "{$info['title']} {$message} from version {$info['version']} to version {$info['update_version']}" ); } } else { From 11523591385a9c97a5caa6190bd1af4078034c1f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 22 Aug 2015 08:17:09 -0700 Subject: [PATCH 3664/5359] Use absolute file paths for `make-phar.php` This makes it possible to call the script from the Behat context --- utils/make-phar.php | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index 69ae514ff..69445c7f8 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -1,13 +1,15 @@ <?php -require './vendor/autoload.php'; -require './php/utils.php'; +define( 'WP_CLI_ROOT', dirname( dirname( __FILE__ ) ) ); + +require WP_CLI_ROOT . '/vendor/autoload.php'; +require WP_CLI_ROOT . '/php/utils.php'; use Symfony\Component\Finder\Finder; use WP_CLI\Utils; use WP_CLI\Configurator; -$configurator = new Configurator( './utils/make-phar-spec.php' ); +$configurator = new Configurator( WP_CLI_ROOT . '/utils/make-phar-spec.php' ); list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); @@ -20,21 +22,21 @@ define( 'BE_QUIET', isset( $runtime_config['quiet'] ) && $runtime_config['quiet'] ); -$current_version = trim( file_get_contents( './VERSION' ) ); +$current_version = trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ); if ( isset( $runtime_config['version'] ) ) { $new_version = $runtime_config['version']; $new_version = Utils\increment_version( $current_version, $new_version ); if ( isset( $runtime_config['store-version'] ) && $runtime_config['store-version'] ) { - file_put_contents( './VERSION', $new_version ); + file_put_contents( WP_CLI_ROOT . '/VERSION', $new_version ); } $current_version = $new_version; } function add_file( $phar, $path ) { - $key = str_replace( './', '', $path ); + $key = str_replace( WP_CLI_ROOT, '', $path ); if ( !BE_QUIET ) echo "$key - $path\n"; @@ -43,7 +45,7 @@ function add_file( $phar, $path ) { } function set_file_contents( $phar, $path, $content ) { - $key = str_replace( './', '', $path ); + $key = str_replace( WP_CLI_ROOT, '', $path ); if ( !BE_QUIET ) echo "$key - $path\n"; @@ -61,15 +63,15 @@ function set_file_contents( $phar, $path, $content ) { ->files() ->ignoreVCS(true) ->name('*.php') - ->in('./php') - ->in('./features') - ->in('./vendor/wp-cli') - ->in('./vendor/mustache') - ->in('./vendor/rmccue/requests') - ->in('./vendor/composer') - ->in('./vendor/symfony/finder') - ->in('./vendor/nb/oxymel') - ->in('./vendor/ramsey/array_column') + ->in(WP_CLI_ROOT . '/php') + ->in(WP_CLI_ROOT . '/features') + ->in(WP_CLI_ROOT . '/vendor/wp-cli') + ->in(WP_CLI_ROOT . '/vendor/mustache') + ->in(WP_CLI_ROOT . '/vendor/rmccue/requests') + ->in(WP_CLI_ROOT . '/vendor/composer') + ->in(WP_CLI_ROOT . '/vendor/symfony/finder') + ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') + ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') ->exclude('test') ->exclude('tests') ->exclude('Tests') @@ -86,18 +88,18 @@ function set_file_contents( $phar, $path, $content ) { ->files() ->ignoreVCS(true) ->ignoreDotFiles(false) - ->in('./templates') + ->in( WP_CLI_ROOT . '/templates') ; foreach ( $finder as $file ) { add_file( $phar, $file ); } -add_file( $phar, './vendor/autoload.php' ); -add_file( $phar, './utils/get-package-require-from-composer.php' ); -add_file( $phar, './vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); +add_file( $phar, WP_CLI_ROOT . '/utils/get-package-require-from-composer.php' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); -set_file_contents( $phar, './VERSION', $current_version ); +set_file_contents( $phar, WP_CLI_ROOT . '/VERSION', $current_version ); $phar->setStub( <<<EOB #!/usr/bin/env php From 53db8d7b64dd7740d3586c29e965d8cab17dab68 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 22 Aug 2015 08:18:47 -0700 Subject: [PATCH 3665/5359] Introduce `wp cli update --nightly` for updating to nightly release --- features/cli.feature | 13 +++++++++++++ php/commands/cli.php | 36 +++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/features/cli.feature b/features/cli.feature index 34d6d48be..83c0f2ea5 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -67,6 +67,19 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + Scenario: Install WP-CLI nightly + Given an empty directory + And a new Phar with version "0.14.0" + + When I run `{PHAR_PATH} cli update --nightly --yes` + Then STDOUT should contain: + """ + Success: Updated WP-CLI to the latest nightly release + """ + + And STDERR should be empty + And the return code should be 0 + Scenario: Dump the list of global parameters with values Given a WP install diff --git a/php/commands/cli.php b/php/commands/cli.php index 837ee4b8d..fd8c11ede 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -131,6 +131,9 @@ public function check_update( $_, $assoc_args ) { * [--minor] * : Only perform minor updates * + * [--nightly] + * : Update to the latest built version of the master branch. Potentially unstable. + * * [--yes] * : Do not prompt for confirmation */ @@ -145,18 +148,28 @@ public function update( $_, $assoc_args ) { WP_CLI::error( sprintf( "%s is not writable by current user", $old_phar ) ); } - $updates = $this->get_updates( $assoc_args ); + if ( isset( $assoc_args['nightly'] ) ) { - if ( empty( $updates ) ) { - WP_CLI::success( "WP-CLI is at the latest version." ); - exit(0); - } + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest nightly?', WP_CLI_VERSION ), $assoc_args ); + + $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar'; + + } else { - $newest = $updates[0]; + $updates = $this->get_updates( $assoc_args ); - WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); + if ( empty( $updates ) ) { + WP_CLI::success( "WP-CLI is at the latest version." ); + exit(0); + } + + $newest = $updates[0]; - $download_url = $newest['package_url']; + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); + + $download_url = $newest['package_url']; + + } WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); @@ -193,7 +206,12 @@ class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); } - WP_CLI::success( sprintf( 'Updated WP-CLI to %s', $newest['version'] ) ); + if ( isset( $assoc_args['nightly'] ) ) { + $updated_version = 'the latest nightly release'; + } else { + $updated_version = $newest['version']; + } + WP_CLI::success( sprintf( 'Updated WP-CLI to %s', $updated_version ) ); } /** From d3ed4c6e2fc27f98f8e12ced66ebe61afee190b1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sat, 22 Aug 2015 08:38:31 -0700 Subject: [PATCH 3666/5359] Append git short hash to alpha versions When using `wp cli update --nightly`, the short hash will be helpful for keeping track of which version you're running. --- ci/prepare.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 611a068de..0baee0dc8 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -6,9 +6,17 @@ set -ex composer install --no-interaction --prefer-source +CLI_VERSION=$(head -n 1 VERSION) +if [[ $CLI_VERSION == *"-alpha"* ]] +then + GIT_HASH=$(git rev-parse HEAD) + GIT_SHORT_HASH=${GIT_HASH:0:7} + CLI_VERSION="$CLI_VERSION-$GIT_SHORT_HASH" +fi + # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR mkdir -p $WP_CLI_BIN_DIR -php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet +php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet --version=$CLI_VERSION mv wp-cli.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp From 69009b8f34f03ca22f1e249e286c219fee625532 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Aug 2015 07:03:41 -0700 Subject: [PATCH 3667/5359] Mock API response to get a failing build for partial update again See https://github.com/wp-cli/wp-cli/issues/1898#issuecomment-134206853 --- features/core.feature | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 59e487978..28b55e0f4 100644 --- a/features/core.feature +++ b/features/core.feature @@ -658,13 +658,43 @@ Feature: Manage WordPress installation Scenario: Ensure cached partial upgrades aren't used in full upgrade Given a WP install And an empty cache + And a wp-content/mu-plugins/upgrade-override.php file: + """ + <?php + add_filter( 'pre_site_transient_update_core', function(){ + return (object) array( + 'updates' => array( + (object) array( + 'response' => 'autoupdate', + 'download' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', + 'locale' => 'en_US', + 'packages' => (object) array( + 'full' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', + 'no_content' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-no-content.zip', + 'new_bundled' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-new-bundled.zip', + 'partial' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-partial-1.zip', + 'rollback' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-rollback-1.zip', + ), + 'current' => '4.2.4', + 'version' => '4.2.4', + 'php_version' => '5.2.4', + 'mysql_version' => '5.0', + 'new_bundled' => '4.1', + 'partial_version' => '4.2.1', + 'support_email' => 'updatehelp42@wordpress.org', + 'new_files' => '', + ), + ), + ); + }); + """ When I run `wp core download --version=4.2.1 --force` - And I run `wp core update --version=4.2.2` + And I run `wp core update` Then STDOUT should not be empty When I run `wp core download --version=4.1.1 --force` - And I run `wp core update --version=4.2.2` + And I run `wp core update` And I run `wp core verify-checksums` Then STDOUT should be: """ From 392aba67ebb58d6a6568f4065a808807d0992903 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 24 Aug 2015 07:41:28 -0700 Subject: [PATCH 3668/5359] Use WPorg API filename in our cache key to accommodate for partials WordPress can actually return a variety of files, and we want to make sure our cache properly handles each. Cache key is renamed for all WordPress core archive files, so no longer need to worry about mismatched extensions. --- features/core.feature | 69 +++++++++---------------------------- php/WP_CLI/CoreUpgrader.php | 3 +- php/commands/core.php | 2 +- 3 files changed, 19 insertions(+), 55 deletions(-) diff --git a/features/core.feature b/features/core.feature index 28b55e0f4..465fc47f9 100644 --- a/features/core.feature +++ b/features/core.feature @@ -12,7 +12,7 @@ Feature: Manage WordPress installation When I run `wp core download` And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/en_US-{VERSION}.tar.gz file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist When I run `mkdir inner` And I run `cd inner && wp core download` @@ -23,7 +23,7 @@ Feature: Manage WordPress installation Then the wp-settings.php file should exist And STDOUT should contain: """ - Using cached file '{SUITE_CACHE_DIR}/core/en_US-{VERSION}.tar.gz'... + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz'... """ @download @@ -33,7 +33,7 @@ Feature: Manage WordPress installation When I run `wp core download --locale=de_DE` And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/de_DE-{VERSION}.tar.gz file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist Scenario: No wp-config.php Given an empty directory @@ -424,7 +424,7 @@ Feature: Manage WordPress installation When I run `wp core update --version=3.8.1 --force` Then STDOUT should contain: """ - Using cached file '{SUITE_CACHE_DIR}/core/en_US-3.8.1.zip'... + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-3.8.1-en_US.zip'... """ And STDOUT should not contain: """ @@ -597,55 +597,6 @@ Feature: Manage WordPress installation Warning: The 'en_GB' language is active. """ - Scenario: Ensure file cache isn't corrupted by a ZIP masquerading as a gzipped TAR, part one - Given a WP install - And an empty cache - And I run `mkdir -p {SUITE_CACHE_DIR}/core; wget -O {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz https://wordpress.org/wordpress-4.0.zip; touch {SUITE_CACHE_DIR}/core/en_US-4.0.tar.gz` - - When I run `wp core download --version=4.0 --force` - Then STDOUT should contain: - """ - Success: WordPress downloaded - """ - And STDERR should contain: - """ - Warning: Extraction failed, downloading a new copy... - """ - - When I run `wp core version` - Then STDOUT should be: - """ - 4.0 - """ - - Scenario: Ensure file cache isn't corrupted by core update, part two - Given a WP install - And an empty cache - - When I run `wp core download --version=4.0 --force` - Then STDOUT should contain: - """ - Success: WordPress downloaded - """ - - When I run `wp core version` - Then STDOUT should be: - """ - 4.0 - """ - - When I run `wp core update --version=4.0 --force` - Then STDOUT should contain: - """ - Success: WordPress updated successfully - """ - - When I run `wp core version` - Then STDOUT should be: - """ - 4.0 - """ - Scenario: Catch download of non-existent WP version Given an empty directory @@ -692,6 +643,11 @@ Feature: Manage WordPress installation When I run `wp core download --version=4.2.1 --force` And I run `wp core update` Then STDOUT should not be empty + And the {SUITE_CACHE_DIR}/core directory should contain: + """ + wordpress-4.2.1-en_US.tar.gz + wordpress-4.2.4-partial-1-en_US.zip + """ When I run `wp core download --version=4.1.1 --force` And I run `wp core update` @@ -700,3 +656,10 @@ Feature: Manage WordPress installation """ Success: WordPress install verifies against checksums. """ + And the {SUITE_CACHE_DIR}/core directory should contain: + """ + wordpress-4.1.1-en_US.tar.gz + wordpress-4.2.1-en_US.tar.gz + wordpress-4.2.4-no-content-en_US.zip + wordpress-4.2.4-partial-1-en_US.zip + """ diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index e156649f5..25dc2335a 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -32,13 +32,14 @@ function download_package( $package ) { if ( empty( $package ) ) return new WP_Error( 'no_package', $this->strings['no_package'] ); + $filename = pathinfo( $package, PATHINFO_FILENAME ); $ext = pathinfo( $package, PATHINFO_EXTENSION ); $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; $cache = WP_CLI::get_cache(); $update = $GLOBALS['wp_cli_update_obj']; - $cache_key = "core/{$update->locale}-{$update->version}.{$ext}"; + $cache_key = "core/{$filename}-{$update->locale}.{$ext}"; $cache_file = $cache->has( $cache_key ); if ( $cache_file ) { diff --git a/php/commands/core.php b/php/commands/core.php index 0a82e617c..ccbcfa5b8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -147,7 +147,7 @@ public function download( $args, $assoc_args ) { WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $version, $locale ) ); $cache = WP_CLI::get_cache(); - $cache_key = "core/$locale-$version.tar.gz"; + $cache_key = "core/wordpress-{$version}-{$locale}.tar.gz"; $cache_file = $cache->has($cache_key); $bad_cache = false; From 218742209476748d1b4ebfcd4157a689ef059b88 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Mon, 24 Aug 2015 18:24:58 +0200 Subject: [PATCH 3669/5359] Switch away from `wp_download_language_pack()` so it's possible to install language packs when, for example, the `DISALLOW_FILE_MODS` constant is defined and set to true. See #1879. --- features/core.feature | 6 ++++ php/WP_CLI/CommandWithTranslation.php | 47 ++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index a9882c81d..488a66555 100644 --- a/features/core.feature +++ b/features/core.feature @@ -584,6 +584,12 @@ Feature: Manage WordPress installation Success: Language activated. """ + When I try `wp core language install invalid_lang` + Then STDERR should be: + """ + Error: Language 'invalid_lang' not found. + """ + @require-wp-4.0 Scenario: Don't allow active language to be uninstalled Given a WP install diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index e83e39342..368655568 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -127,17 +127,15 @@ public function install( $args, $assoc_args ) { exit; } - require_once ABSPATH . '/wp-admin/includes/translation-install.php'; - - $response = wp_download_language_pack( $language_code ); - if ( $response == $language_code ) { + $response = $this->download_language_pack( $language_code ); + if ( ! is_wp_error( $response ) ) { \WP_CLI::success( "Language installed." ); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { $this->activate( array( $language_code ), array() ); } } else { - \WP_CLI::error( "Couldn't install language." ); + \WP_CLI::error( $response ); } } @@ -268,6 +266,45 @@ public function activate( $args, $assoc_args ) { \WP_CLI::success( "Language activated." ); } + /** + * Download a language pack. + * + * @see wp_download_language_pack() + * + * @param string $download Language code to download. + * @return string|WP_Error Returns the language code if successfully downloaded, or a WP_Error object on failure. + */ + protected function download_language_pack( $download ) { + + $translations = $this->get_all_languages(); + + foreach ( $translations as $translation ) { + if ( $translation['language'] === $download ) { + $translation_to_load = true; + break; + } + } + + if ( empty( $translation_to_load ) ) { + return new \WP_Error( 'not_found', "Language '{$download}' not found." ); + } + $translation = (object) $translation; + + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + $skin = new \Automatic_Upgrader_Skin; + $upgrader = new \Language_Pack_Upgrader( $skin ); + $translation->type = 'core'; + $result = $upgrader->upgrade( $translation, array( 'clear_update_cache' => false ) ); + + if ( is_wp_error( $result ) ) { + return $result; + } else if ( ! $result ) { + return new \WP_Error( 'not_installed', "Could not install language '{$download}'." ); + } + + return $translation->language; + } + /** * Return a list of installed languages. * From c74120ed673755dc6ab2d1f2185343381906159a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Mon, 24 Aug 2015 10:20:26 -0700 Subject: [PATCH 3670/5359] Change to `private` so we don't have to worry about bc --- php/WP_CLI/CommandWithTranslation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 368655568..74d3537b4 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -274,7 +274,7 @@ public function activate( $args, $assoc_args ) { * @param string $download Language code to download. * @return string|WP_Error Returns the language code if successfully downloaded, or a WP_Error object on failure. */ - protected function download_language_pack( $download ) { + private function download_language_pack( $download ) { $translations = $this->get_all_languages(); From bd5ecd48d116e341730927e9c6460b79e5024c47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Aug 2015 10:57:05 -0700 Subject: [PATCH 3671/5359] Warn on cli update when directory isn't writeable `rename()` requires both the file and directory to be writeable. Erroring earlier is more helpful to the end user. --- php/commands/cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index fd8c11ede..718979abe 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -146,6 +146,8 @@ public function update( $_, $assoc_args ) { if ( ! is_writable( $old_phar ) ) { WP_CLI::error( sprintf( "%s is not writable by current user", $old_phar ) ); + } else if ( ! is_writeable( dirname( $old_phar ) ) ) { + WP_CLI::error( sprintf( "%s is not writable by current user", dirname( $old_phar ) ) ); } if ( isset( $assoc_args['nightly'] ) ) { From 9e480000ad068cd1c64f3927adabeb3687ed6209 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Aug 2015 15:10:39 -0700 Subject: [PATCH 3672/5359] Deliberately flag specific scenarios dependent on Github API The other `cli.feature` scenarios are fine to run each Travis build --- features/cli.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/cli.feature b/features/cli.feature index 83c0f2ea5..68ed68fde 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -1,4 +1,3 @@ -@github-api Feature: `wp cli` tasks Scenario: Ability to set a custom version when building @@ -16,6 +15,7 @@ Feature: `wp cli` tasks {TRUE_VERSION} """ + @github-api Scenario: Check for updates Given an empty directory And a new Phar with version "0.0.0" @@ -27,6 +27,7 @@ Feature: `wp cli` tasks """ And STDERR should be empty + @github-api Scenario: Do WP-CLI Update Given an empty directory And a new Phar with version "0.0.0" @@ -39,6 +40,7 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + @github-api Scenario: Patch update from 0.14.0 to 0.14.1 Given an empty directory And a new Phar with version "0.14.0" @@ -51,6 +53,7 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + @github-api Scenario: Not a patch update from 0.14.0 Given an empty directory And a new Phar with version "0.14.0" @@ -80,6 +83,7 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + @github-api Scenario: Dump the list of global parameters with values Given a WP install From ad63ed626b7107c364dc55fde15bf82c04c1ece7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Aug 2015 15:32:18 -0700 Subject: [PATCH 3673/5359] Deprecate `@synopsis` for `wp cache` in favor of better docs --- php/commands/cache.php | 72 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index c78ce1ce4..dcc729d57 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -14,7 +14,19 @@ class Cache_Command extends WP_CLI_Command { /** * Add a value to the object cache. * - * @synopsis <key> <value> [<group>] [<expiration>] + * If a value already exists for the key, the value isn't added. + * + * <key> + * : Cache key. + * + * <value> + * : Value to add to the key. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * [<expiration>] + * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). */ public function add( $args, $assoc_args ) { list( $key, $value ) = $args; @@ -33,7 +45,14 @@ public function add( $args, $assoc_args ) { /** * Decrement a value in the object cache. * - * @synopsis <key> [<offset>] [<group>] + * <key> + * : Cache key. + * + * [<offset>] + * : The amount by which to decrement the item's value. Default is 1. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. */ public function decr( $args, $assoc_args ) { $key = $args[0]; @@ -54,7 +73,11 @@ public function decr( $args, $assoc_args ) { /** * Remove a value from the object cache. * - * @synopsis <key> [<group>] + * <key> + * : Cache key. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. */ public function delete( $args, $assoc_args ) { $key = $args[0]; @@ -86,7 +109,11 @@ public function flush( $args, $assoc_args ) { /** * Get a value from the object cache. * - * @synopsis <key> [<group>] + * <key> + * : Cache key. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. */ public function get( $args, $assoc_args ) { $key = $args[0]; @@ -105,7 +132,14 @@ public function get( $args, $assoc_args ) { /** * Increment a value in the object cache. * - * @synopsis <key> [<offset>] [<group>] + * <key> + * : Cache key. + * + * [<offset>] + * : The amount by which to increment the item's value. Default is 1. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. */ public function incr( $args, $assoc_args ) { $key = $args[0]; @@ -124,9 +158,19 @@ public function incr( $args, $assoc_args ) { } /** - * Replace an existing value in the object cache. + * Replace a value in the object cache, if the value already exists. + * + * <key> + * : Cache key. + * + * <value> + * : Value to replace. * - * @synopsis <key> <value> [<group>] [<expiration>] + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * [<expiration>] + * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). */ public function replace( $args, $assoc_args ) { list( $key, $value ) = $args; @@ -145,9 +189,19 @@ public function replace( $args, $assoc_args ) { } /** - * Set a value to the object cache. + * Set a value to the object cache, regardless of whether it already exists. + * + * <key> + * : Cache key. + * + * <value> + * : Value to set on the key. + * + * [<group>] + * : Method for grouping data within the cache which allows the same key to be used across groups. * - * @synopsis <key> <value> [<group>] [<expiration>] + * [<expiration>] + * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). */ public function set( $args, $assoc_args ) { list( $key, $value ) = $args; From d087648838db1f32472ed20a3e6ed9c5d94e9936 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 25 Aug 2015 20:29:20 -0700 Subject: [PATCH 3674/5359] Lock php-cli-tools to v0.10.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7d9ab3cb4..26dcc72c2 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "0.10.5", "mustache/mustache": "~2.4", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", From dedf06cc3b66215f27015ee0f075de710202bcdc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Wed, 26 Aug 2015 06:59:45 -0700 Subject: [PATCH 3675/5359] Load WP_HTTP with require_once because core now loads in http.php r33748 --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 41e8b79df..28cc2380b 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -167,7 +167,7 @@ Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); -require( ABSPATH . WPINC . '/class-http.php' ); +require_once( ABSPATH . WPINC . '/class-http.php' ); require( ABSPATH . WPINC . '/widgets.php' ); require( ABSPATH . WPINC . '/nav-menu.php' ); require( ABSPATH . WPINC . '/nav-menu-template.php' ); From 1db2f8143d8f54e5bb7f50a6595e2d2a3a28d3e4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Wed, 26 Aug 2015 07:01:41 -0700 Subject: [PATCH 3676/5359] Test against the latest version of WordPress --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 58b187c0d..28e3bdd2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=4.2 + - WP_VERSION=4.3 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: From 096af51ba82381ab1243353010c410a462cf0264 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 26 Aug 2015 08:30:10 -0700 Subject: [PATCH 3677/5359] Update `.mailmap` with contributors to v0.20.0 --- .mailmap | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.mailmap b/.mailmap index 23d32791f..c5b31ad86 100644 --- a/.mailmap +++ b/.mailmap @@ -1,4 +1,5 @@ 2ndkauboy <bernhard@kau-boys.de> +Akeda Bagus <admin@gedex.web.id> Alex Mills <git@viper007bond.com> Andreas Heigl <andreas@heigl.org> andreascreten <andreas@madewithlove.be> @@ -15,6 +16,7 @@ Brad Parbs <brad@bradparbs.com> Brian MacKinney <brian@getpantheon.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> +Chris Montgomery <chris@montchr.io> clemens-tolboom <clemens@build2be.com> conatus <alex@recordsonribs.com> ctayloroomphinc <ctaylor@thinkoomph.com> @@ -38,6 +40,7 @@ glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> +Jan VoráÄek <jan@voracek.net> jeichorn <joshua.eichorn@pagely.com> Jeremy Pry <jeremy.pry@gmail.com> jghazally <jeff@bigfish.co.uk> @@ -51,12 +54,15 @@ jonathanbardo <jonathanbardo@users.noreply.github.com> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> JQ <JeyKeu@users.noreply.github.com> +KDoole <dev@Kevins-iMac.local> Keith Grennan <keith@nearlyfree.org> +Kevin Doole <kdoole@farmmedia.com> Kevinlearynet <info@kevinleary.net> kidfiction <ejdanderson@gmail.com> lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> lkwdwrd <woodward.lucas@gmail.com> +Marc Addeo <marcaddeo@gmail.com> marcoceppi <marco@ceppi.net> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> @@ -95,6 +101,7 @@ rodrigoprimo <rodrigo@hacklab.com.br> rodrigoprimo <rodrigosprimo@gmail.com> roelven <roel@soundcloud.com> Ross Hattori <rhattori@saymedia.com> +Ryan McCue <me@ryanmccue.info> ryanduff <ryan@fusionized.com> santagada <santagada@gmail.com> sboisvert <stephane.boisvert@automattic.com> @@ -108,6 +115,9 @@ spacedmonkey <spacedmonkey2@gmail.com> SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> Stephen Edgar <stephen@netweb.com.au> +Steve Grunwell <steve.grunwell@10up.com> +Steve Grunwell <steve@stevegrunwell.com> +Steve Grunwell <stevegrunwell@gmail.com> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> Svetoslav Marinov (Slavi) <slavi@orbisius.com> From 284a1aa6df81c95017656a17b4298e72e123035b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Wed, 26 Aug 2015 09:19:25 -0700 Subject: [PATCH 3678/5359] Correct wording in theme documentation --- php/commands/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 0cebcebfa..c3879282e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -55,7 +55,7 @@ function status( $args ) { * : Optional number of results to display. Defaults to 10. * * [--field=<field>] - * : Prints the value of a single field for each plugin. + * : Prints the value of a single field for each theme. * * [--fields=<fields>] * : Ask for specific fields from the API. Defaults to name,slug,author,rating. Acceptable values: @@ -447,7 +447,7 @@ public function get( $args, $assoc_args ) { * : Output summary as table or summary. Defaults to table. * * [--version=<version>] - * : If set, the plugin will be updated to the specified version. + * : If set, the theme will be updated to the specified version. * * [--dry-run] * : Preview which themes would be updated. From 58317fce36e34a10473bbd397b42a185edd10438 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 26 Aug 2015 10:38:02 -0700 Subject: [PATCH 3679/5359] Bump version to 0.20.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4863f59c3..5a03fb737 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20.0-alpha +0.20.0 From 5307f30b6e901c23a27e7bc58b4525e0ce080eec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 26 Aug 2015 16:48:30 -0700 Subject: [PATCH 3680/5359] Bump to new working version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5a03fb737..217292ece 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20.0 +0.21.0-alpha From f076bfa02b664ad5c7ad4f7893979571a2b763cc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 27 Aug 2015 16:15:50 -0700 Subject: [PATCH 3681/5359] Failing test case for #2015 --- features/upgradables.feature | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index dc195e89e..bc1576597 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -76,7 +76,11 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> update <item>` And save STDOUT 'Downloading update from .*\/<item>\.%s\.zip' as {NEW_VERSION} - Then STDOUT should not be empty + And STDOUT should not be empty + Then STDOUT should not contain: + """ + Error + """ And the {SUITE_CACHE_DIR}/<type>/<item>-{NEW_VERSION}.zip file should exist When I run `wp <type> update --all` From cab23b21c5301db525c54a53a4e006344753544c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 27 Aug 2015 16:17:10 -0700 Subject: [PATCH 3682/5359] Use proper key identified in e3b779d70da410b93368cebe248ffff2caeb731e --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 47d425066..20e347fac 100644 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -277,7 +277,7 @@ protected function update_many( $args, $assoc_args ) { 'name' => $info['name'], 'old_version' => $info['version'], 'new_version' => $info['update_version'], - 'status' => $result[$item_to_update] !== null ? 'Updated' : 'Error', + 'status' => $result[ $info['update_id'] ] !== null ? 'Updated' : 'Error', ); } \WP_CLI\Utils\format_items( 'table', $status, array( 'name', 'old_version', 'new_version', 'status' ) ); From 86e925396c2d2b2f98fae4147792ab93377cc4e0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 28 Aug 2015 14:37:19 -0300 Subject: [PATCH 3683/5359] add error message when trying to use `wp rewrite flush --hard` on a ms install --- features/rewrite.feature | 13 +++++++++++++ php/commands/rewrite.php | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index 6ab22a61e..d1fcacfbf 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -62,3 +62,16 @@ Feature: Manage WordPress rewrites When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` And I run `wp rewrite flush --hard` Then the .htaccess file should exist + + Scenario: Error when trying to generate .htaccess on a multisite install + Given a WP multisite install + And a wp-cli.yml file: + """ + apache_modules: [mod_rewrite] + """ + + When I try `wp rewrite flush --hard` + Then STDERR should be: + """ + Error: WordPress can't generate .htaccess file for a multisite install. + """ diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 4fabc7d69..0096a6b6e 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -23,15 +23,22 @@ class Rewrite_Command extends WP_CLI_Command { * ## OPTIONS * * [--hard] - * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. + * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. Works only on single site installs. */ public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && is_multisite() ) { + WP_CLI::error( "WordPress can't generate .htaccess file for a multisite install." ); + } + flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); + if ( ! get_option( 'rewrite_rules' ) ) { WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); } From 818f28de5c0911276aae36c466c9636954644788 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 28 Aug 2015 15:08:40 -0300 Subject: [PATCH 3684/5359] replace error with warning --- features/rewrite.feature | 2 +- php/commands/rewrite.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index d1fcacfbf..25fe482e1 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -73,5 +73,5 @@ Feature: Manage WordPress rewrites When I try `wp rewrite flush --hard` Then STDERR should be: """ - Error: WordPress can't generate .htaccess file for a multisite install. + Warning: WordPress can't generate .htaccess file for a multisite install. """ diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 0096a6b6e..58c5ff26c 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -34,7 +34,7 @@ public function flush( $args, $assoc_args ) { } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && is_multisite() ) { - WP_CLI::error( "WordPress can't generate .htaccess file for a multisite install." ); + WP_CLI::warning( "WordPress can't generate .htaccess file for a multisite install." ); } flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); From 684b3c94427c7053e608d7ffdf8772baf97772ae Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Tue, 1 Sep 2015 13:29:44 +0200 Subject: [PATCH 3685/5359] s/propmts/prompts --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 08b173be5..6db4b15ac 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -167,7 +167,7 @@ public function get( $args, $assoc_args ) { * : User ID to reassign the posts to. * * [--yes] - * : Answer yes to any confirmation propmts. + * : Answer yes to any confirmation prompts. * * ## EXAMPLES * From b559f2f76f0b43e1f48d762d60cffd1ca3eece27 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Sep 2015 12:35:47 -0700 Subject: [PATCH 3686/5359] Failing tests for #2019 --- features/config.feature | 103 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/features/config.feature b/features/config.feature index 2a2b3ae84..d324ac20d 100644 --- a/features/config.feature +++ b/features/config.feature @@ -219,3 +219,106 @@ Feature: Have a config file When I run `wp --info` Then STDOUT should not be empty + Scenario: WordPress install with commented out DOMAIN_CURRENT_SITE, first style + Given a WP multisite install + And a wp-config.php file: + """ +<?php +// ** MySQL settings ** // +/** The name of the database for WordPress */ +define('DB_NAME', 'wp_cli_test'); + +/** MySQL database username */ +define('DB_USER', 'wp_cli_test'); + +/** MySQL database password */ +define('DB_PASSWORD', 'password1'); + +/** MySQL hostname */ +define('DB_HOST', '127.0.0.1'); + +/** Database Charset to use in creating database tables. */ +define('DB_CHARSET', 'utf8'); + +/** The Database Collate type. Don't change this if in doubt. */ +define('DB_COLLATE', ''); + +$table_prefix = 'wp_'; + +define( 'WP_ALLOW_MULTISITE', true ); +define('MULTISITE', true); +define('SUBDOMAIN_INSTALL', false); +$base = '/'; +define('DOMAIN_CURRENT_SITE', 'example.com'); +# define('DOMAIN_CURRENT_SITE', 'bta.example.com'); +define('PATH_CURRENT_SITE', '/'); +define('SITE_ID_CURRENT_SITE', 1); +define('BLOG_ID_CURRENT_SITE', 1); + +/* That's all, stop editing! Happy blogging. */ + +/** Absolute path to the WordPress directory. */ +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + +/** Sets up WordPress vars and included files. */ +require_once(ABSPATH . 'wp-settings.php'); + """ + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ + + Scenario: WordPress install with commented out DOMAIN_CURRENT_SITE, second style + Given a WP multisite install + And a wp-config.php file: + """ +<?php +// ** MySQL settings ** // +/** The name of the database for WordPress */ +define('DB_NAME', 'wp_cli_test'); + +/** MySQL database username */ +define('DB_USER', 'wp_cli_test'); + +/** MySQL database password */ +define('DB_PASSWORD', 'password1'); + +/** MySQL hostname */ +define('DB_HOST', '127.0.0.1'); + +/** Database Charset to use in creating database tables. */ +define('DB_CHARSET', 'utf8'); + +/** The Database Collate type. Don't change this if in doubt. */ +define('DB_COLLATE', ''); + +$table_prefix = 'wp_'; + +define( 'WP_ALLOW_MULTISITE', true ); +define('MULTISITE', true); +define('SUBDOMAIN_INSTALL', false); +$base = '/'; +define('DOMAIN_CURRENT_SITE', 'example.com'); +//define('DOMAIN_CURRENT_SITE', 'bta.example.com'); +define('PATH_CURRENT_SITE', '/'); +define('SITE_ID_CURRENT_SITE', 1); +define('BLOG_ID_CURRENT_SITE', 1); + +/* That's all, stop editing! Happy blogging. */ + +/** Absolute path to the WordPress directory. */ +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + +/** Sets up WordPress vars and included files. */ +require_once(ABSPATH . 'wp-settings.php'); + """ + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ From d4d67de8e73c61fc494ca577ba0ef7267a7853a8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Sep 2015 12:52:46 -0700 Subject: [PATCH 3687/5359] Ignore commented `define('DOMAIN_CURRENT_SITE')` statements in wp-config --- php/WP_CLI/Runner.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 218a72a13..3e36d818d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -211,14 +211,17 @@ private static function guess_url( $assoc_args ) { $wp_config_file = file_get_contents( $wp_config_path ); $hit = array(); - $re_define = "#.*define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;#iU"; + $re_define = "~(.*)define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;~iU"; if ( preg_match_all( $re_define, $wp_config_file, $matches ) ) { - foreach ( $matches[2] as $def_key => $def_name ) { + foreach ( $matches[3] as $def_key => $def_name ) { + if ( false !== strpos( $matches[1][$def_key], '#' ) || false !== strpos( $matches[1][$def_key], '//' ) ) { + continue; + } if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[5][$def_key]; + $hit['domain'] = $matches[6][$def_key]; if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[5][$def_key]; + $hit['path'] = $matches[6][$def_key]; } } From ff0085738f5a374203b853fdb4baf5ff2956c849 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Sep 2015 13:43:38 -0700 Subject: [PATCH 3688/5359] Break core language tests into dedicated file --- features/core-language.feature | 134 +++++++++++++++++++++++++++++++++ features/core.feature | 133 -------------------------------- 2 files changed, 134 insertions(+), 133 deletions(-) create mode 100644 features/core-language.feature diff --git a/features/core-language.feature b/features/core-language.feature new file mode 100644 index 000000000..3e6501c41 --- /dev/null +++ b/features/core-language.feature @@ -0,0 +1,134 @@ +Feature: Manage translation files for a WordPress install + + @require-wp-4.0 + Scenario: Core translation CRUD + Given a WP install + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_US | English (United States) | active | + | en_GB | English (UK) | uninstalled | + + When I run `wp core language install en_GB` + Then the wp-content/languages/admin-en_GB.po file should exist + And the wp-content/languages/en_GB.po file should exist + And STDOUT should be: + """ + Success: Language installed. + """ + + When I try `wp core language install en_GB` + Then STDERR should be: + """ + Warning: Language already installed. + """ + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_GB | English (UK) | installed | + + When I run `wp core language activate en_GB` + Then STDOUT should be: + """ + Success: Language activated. + """ + + When I run `wp core language list --fields=language,english_name,update` + Then STDOUT should be a table containing rows: + | language | english_name | update | + | ar | Arabic | none | + | az | Azerbaijani | none | + | en_US | English (United States) | none | + | en_GB | English (UK) | available | + + When I run `wp core language update --dry-run` + Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} + + When I run `wp core language update` + Then STDOUT should contain: + """ + Success: Updated {UPDATES}/{UPDATES} translations. + """ + And the wp-content/languages/plugins directory should exist + And the wp-content/languages/themes directory should exist + + When I run `wp core language list --field=language --status=active` + Then STDOUT should be: + """ + en_GB + """ + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | az | Azerbaijani | uninstalled | + | en_GB | English (UK) | active | + + When I run `wp core language activate en_US` + Then STDOUT should be: + """ + Success: Language activated. + """ + + When I run `wp core language list --fields=language,english_name,status` + Then STDOUT should be a table containing rows: + | language | english_name | status | + | ar | Arabic | uninstalled | + | en_US | English (United States) | active | + | en_GB | English (UK) | installed | + + + When I try `wp core language activate invalid_lang` + Then STDERR should be: + """ + Error: Language not installed. + """ + + When I run `wp core language uninstall en_GB` + Then the wp-content/languages/admin-en_GB.po file should not exist + And the wp-content/languages/en_GB.po file should not exist + And STDOUT should be: + """ + Success: Language uninstalled. + """ + + When I try `wp core language uninstall en_GB` + Then STDERR should be: + """ + Error: Language not installed. + """ + + When I run `wp core language install --activate en_GB` + Then the wp-content/languages/admin-en_GB.po file should exist + And the wp-content/languages/en_GB.po file should exist + And STDOUT should be: + """ + Success: Language installed. + Success: Language activated. + """ + + When I try `wp core language install invalid_lang` + Then STDERR should be: + """ + Error: Language 'invalid_lang' not found. + """ + + @require-wp-4.0 + Scenario: Don't allow active language to be uninstalled + Given a WP install + + When I run `wp core language install en_GB --activate` + Then STDOUT should not be empty + + When I try `wp core language uninstall en_GB` + Then STDERR should be: + """ + Warning: The 'en_GB' language is active. + """ diff --git a/features/core.feature b/features/core.feature index 90a2910f2..558fcb70f 100644 --- a/features/core.feature +++ b/features/core.feature @@ -470,139 +470,6 @@ Feature: Manage WordPress installation http://localhost:8001 """ - @require-wp-4.0 - Scenario: Core translation CRUD - Given a WP install - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_US | English (United States) | active | - | en_GB | English (UK) | uninstalled | - - When I run `wp core language install en_GB` - Then the wp-content/languages/admin-en_GB.po file should exist - And the wp-content/languages/en_GB.po file should exist - And STDOUT should be: - """ - Success: Language installed. - """ - - When I try `wp core language install en_GB` - Then STDERR should be: - """ - Warning: Language already installed. - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_GB | English (UK) | installed | - - When I run `wp core language activate en_GB` - Then STDOUT should be: - """ - Success: Language activated. - """ - - When I run `wp core language list --fields=language,english_name,update` - Then STDOUT should be a table containing rows: - | language | english_name | update | - | ar | Arabic | none | - | az | Azerbaijani | none | - | en_US | English (United States) | none | - | en_GB | English (UK) | available | - - When I run `wp core language update --dry-run` - Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} - - When I run `wp core language update` - Then STDOUT should contain: - """ - Success: Updated {UPDATES}/{UPDATES} translations. - """ - And the wp-content/languages/plugins directory should exist - And the wp-content/languages/themes directory should exist - - When I run `wp core language list --field=language --status=active` - Then STDOUT should be: - """ - en_GB - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_GB | English (UK) | active | - - When I run `wp core language activate en_US` - Then STDOUT should be: - """ - Success: Language activated. - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | en_US | English (United States) | active | - | en_GB | English (UK) | installed | - - - When I try `wp core language activate invalid_lang` - Then STDERR should be: - """ - Error: Language not installed. - """ - - When I run `wp core language uninstall en_GB` - Then the wp-content/languages/admin-en_GB.po file should not exist - And the wp-content/languages/en_GB.po file should not exist - And STDOUT should be: - """ - Success: Language uninstalled. - """ - - When I try `wp core language uninstall en_GB` - Then STDERR should be: - """ - Error: Language not installed. - """ - - When I run `wp core language install --activate en_GB` - Then the wp-content/languages/admin-en_GB.po file should exist - And the wp-content/languages/en_GB.po file should exist - And STDOUT should be: - """ - Success: Language installed. - Success: Language activated. - """ - - When I try `wp core language install invalid_lang` - Then STDERR should be: - """ - Error: Language 'invalid_lang' not found. - """ - - @require-wp-4.0 - Scenario: Don't allow active language to be uninstalled - Given a WP install - - When I run `wp core language install en_GB --activate` - Then STDOUT should not be empty - - When I try `wp core language uninstall en_GB` - Then STDERR should be: - """ - Warning: The 'en_GB' language is active. - """ - Scenario: Catch download of non-existent WP version Given an empty directory From 1debfdf2f389697db0dc3d05d848b16e3235f2cb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 1 Sep 2015 14:01:08 -0700 Subject: [PATCH 3689/5359] Get all available translation updates, not just the current locale Currently only works for themes and plugins, because the core filter only accepts a single locale. --- features/core-language.feature | 2 ++ php/WP_CLI/CommandWithTranslation.php | 39 ++++++++++++++++++--------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/features/core-language.feature b/features/core-language.feature index 3e6501c41..e975c921c 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -13,6 +13,7 @@ Feature: Manage translation files for a WordPress install | en_GB | English (UK) | uninstalled | When I run `wp core language install en_GB` + And I run `wp core language install en_AU` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist And STDOUT should be: @@ -44,6 +45,7 @@ Feature: Manage translation files for a WordPress install | language | english_name | update | | ar | Arabic | none | | az | Azerbaijani | none | + | en_AU | English (Australia) | available | | en_US | English (United States) | none | | en_GB | English (UK) | available | diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 74d3537b4..277fb630e 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -58,11 +58,7 @@ public function list_( $args, $assoc_args ) { $translations = $this->get_all_languages(); $available = $this->get_installed_languages(); - $this->wp_clean_update_cache(); // Clear existing update caches. - wp_version_check(); // Check for Core translation updates. - wp_update_themes(); // Check for Theme translation updates. - wp_update_plugins(); // Check for Plugin translation updates. - $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. + $updates = $this->get_translation_updates(); $current_locale = get_locale(); $translations = array_map( function( $translation ) use ( $available, $current_locale, $updates ) { @@ -157,13 +153,7 @@ public function update( $args, $assoc_args ) { return; } - $this->wp_clean_update_cache(); // Clear existing update caches. - wp_version_check(); // Check for Core translation updates. - wp_update_themes(); // Check for Theme translation updates. - wp_update_plugins(); // Check for Plugin translation updates. - - $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. - + $updates = $this->get_translation_updates(); if ( empty( $updates ) ) { \WP_CLI::success( 'Translations are up to date.' ); @@ -266,6 +256,31 @@ public function activate( $args, $assoc_args ) { \WP_CLI::success( "Language activated." ); } + /** + * Get all updates available for all translations + * + * @return array + */ + private function get_translation_updates() { + $available = $this->get_installed_languages(); + $func = function() use ( $available ) { + return $available; + }; + $filters = array( 'plugins_update_check_locales', 'themes_update_check_locales' ); + foreach( $filters as $filter ) { + add_filter( $filter, $func ); + } + $this->wp_clean_update_cache(); // Clear existing update caches. + wp_version_check(); // Check for Core translation updates. + wp_update_themes(); // Check for Theme translation updates. + wp_update_plugins(); // Check for Plugin translation updates. + foreach( $filters as $filter ) { + remove_filter( $filter, $func ); + } + $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. + return $updates; + } + /** * Download a language pack. * From 9eccb492aeb49a088c4e0d455bb9ac69bcf22576 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 2 Sep 2015 07:31:45 -0700 Subject: [PATCH 3690/5359] Introduce `wp comment recount` for recalculating `comment_count` --- features/comment.feature | 22 ++++++++++++++++++++++ php/commands/comment.php | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 293936ab2..f79a2ac23 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -131,3 +131,25 @@ Feature: Manage WordPress comments """ 21 """ + + Scenario: Recounting comments + When I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` + And I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` + And I run `wp post get 1 --field=comment_count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) );'` + And I run `wp post get 1 --field=comment_count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp comment recount 1` + Then STDOUT should be: + """ + Updated post 1 comment count to 3 + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index a10248f01..e27d30647 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -398,6 +398,24 @@ public function count( $args, $assoc_args ) { } } + /** + * Recount the comment_count value for one or more posts. + * + * <id>... + * : IDs for one or more posts to update. + */ + public function recount( $args ) { + foreach( $args as $id ) { + wp_update_comment_count( $id ); + $post = get_post( $id ); + if ( $post ) { + WP_CLI::log( sprintf( "Updated post %d comment count to %d", $post->ID, $post->comment_count ) ); + } else { + WP_CLI::warning( sprintf( "Post %d doesn't exist", $post->ID ) ); + } + } + } + /** * Get status of a comment. * From 6213a3906644252f2f1d9882f597b05a7dd6070e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 2 Sep 2015 12:13:14 -0700 Subject: [PATCH 3691/5359] Clarify expected behavior for `WP_CLI::run_command()` See https://wordpress.slack.com/archives/cli/p1441220169000129 --- php/class-wp-cli.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 44bf9ace5..620457433 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -458,7 +458,10 @@ public static function get_config( $key = null ) { } /** - * Run a given command. + * Run a given command within the current process using the same global parameters. + * + * To run a command using a new process with the same global parameters, use WP_CLI::launch_self() + * To run a command using a new process with different global parameters, use WP_CLI::launch() * * @param array * @param array From 5063ec6be418b0aee94b638dd5c6c5667fc0d484 Mon Sep 17 00:00:00 2001 From: John Blackbourn <johnbillion@gmail.com> Date: Thu, 3 Sep 2015 12:36:43 +0200 Subject: [PATCH 3692/5359] Return a more useful error message when running `wp scaffold plugin-tests` with an invalid plugin slug. --- features/scaffold.feature | 8 ++++++++ php/commands/scaffold.php | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index fc7aeea93..a691bb8fb 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -349,3 +349,11 @@ Feature: WordPress code scaffolding """ Replacing """ + Scenario: Scaffold tests for invalid plugin directory + Given a WP install + + When I try `wp scaffold plugin-tests incorrect-custom-plugin` + Then STDERR should contain: + """ + Error: Invalid plugin directory specified. + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 1db452d18..e58b7f5ef 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -603,6 +603,10 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::error( 'Invalid plugin specified.' ); } + if ( ! is_dir( $plugin_dir ) ) { + WP_CLI::error( 'Invalid plugin directory specified.' ); + } + $tests_dir = "$plugin_dir/tests"; $bin_dir = "$plugin_dir/bin"; From 8867542e28a97c12f7ca9109029088997331395a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 3 Sep 2015 05:57:42 -0700 Subject: [PATCH 3693/5359] Clarify it's an invalid plugin slug; `--dir` is checked elsewhere --- features/scaffold.feature | 2 +- php/commands/scaffold.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index a691bb8fb..777403f37 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -355,5 +355,5 @@ Feature: WordPress code scaffolding When I try `wp scaffold plugin-tests incorrect-custom-plugin` Then STDERR should contain: """ - Error: Invalid plugin directory specified. + Error: Invalid plugin slug specified. """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index e58b7f5ef..ba197763d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -587,6 +587,9 @@ function plugin_tests( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; + if ( ! is_dir( $plugin_dir ) ) { + WP_CLI::error( 'Invalid plugin slug specified.' ); + } } if ( ! empty( $assoc_args['dir'] ) ) { @@ -603,10 +606,6 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::error( 'Invalid plugin specified.' ); } - if ( ! is_dir( $plugin_dir ) ) { - WP_CLI::error( 'Invalid plugin directory specified.' ); - } - $tests_dir = "$plugin_dir/tests"; $bin_dir = "$plugin_dir/bin"; From 41b56158a2cfa908958565cdd8ad81d6c4e51a6f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 3 Sep 2015 06:32:15 -0700 Subject: [PATCH 3694/5359] Permit custom directories to be specified with slugs --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ba197763d..5591b98a8 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -587,7 +587,7 @@ function plugin_tests( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { $plugin_slug = $args[0]; $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - if ( ! is_dir( $plugin_dir ) ) { + if ( empty( $assoc_args['dir'] ) && ! is_dir( $plugin_dir ) ) { WP_CLI::error( 'Invalid plugin slug specified.' ); } } From cacca9b9b40eabadc7386f36d337cb38d215ba4f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 3 Sep 2015 14:06:26 -0700 Subject: [PATCH 3695/5359] In `wp theme list`, indicate a parent theme with `status=parent` This will more clearly distinguish between a genuinely inactive theme vs. an "inactive" theme being used as a parent theme. --- features/theme.feature | 11 +++++++++++ php/commands/theme.php | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index cf8143185..42144d0cd 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -238,3 +238,14 @@ Feature: Manage WordPress themes """ Error: The 'biker' theme cannot be activated without its parent, 'jolene'. """ + + Scenario: List an active theme with its parent + Given a WP install + And I run `wp theme install jolene` + And I run `wp theme install --activate biker` + + When I run `wp theme list --fields=name,status` + Then STDOUT should be a table containing rows: + | name | status | + | biker | active | + | jolene | parent | diff --git a/php/commands/theme.php b/php/commands/theme.php index c3879282e..380a4fadd 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -107,7 +107,13 @@ protected function get_all_items() { } protected function get_status( $theme ) { - return ( $this->is_active_theme( $theme ) ) ? 'active' : 'inactive'; + if ( $this->is_active_theme( $theme ) ) { + return 'active'; + } else if ( $theme->get_stylesheet_directory() === get_template_directory() ) { + return 'parent'; + } else { + return 'inactive'; + } } /** From f42e7d17256af2035aac79bda37f1d5e5cf5097b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 4 Sep 2015 10:53:52 -0700 Subject: [PATCH 3696/5359] Fix example in `wp menu item delete` See https://github.com/wp-cli/wp-cli.github.com/pull/63 --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 240427580..fd1a5428e 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -471,7 +471,7 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item remove 45 + * wp menu item delete 45 * * @subcommand delete */ From f57298898b6d85a962e1ecbf9376b0400eecee58 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 7 Sep 2015 07:17:52 -0700 Subject: [PATCH 3697/5359] Warn user when `wp-config.php` isn't writable for multisite convert WordPress multisite needs extra constants in `wp-config.php`. If WP-CLI can't add them, we should let the user know instead of failing silently. --- php/commands/core.php | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ccbcfa5b8..939a78f93 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -644,22 +644,26 @@ private function _multisite_convert( $assoc_args ) { } if ( !is_multisite() ) { - ob_start(); -?> + $subdomain_export = Utils\get_flag_value( $assoc_args, 'subdomains' ) ? 'true' : 'false'; + $ms_config = <<<EOT define( 'WP_ALLOW_MULTISITE', true ); -define('MULTISITE', true); -define('SUBDOMAIN_INSTALL', <?php var_export( $assoc_args['subdomains'] ); ?>); -$base = '<?php echo $assoc_args['base']; ?>'; -define('DOMAIN_CURRENT_SITE', '<?php echo $domain; ?>'); -define('PATH_CURRENT_SITE', '<?php echo $assoc_args['base']; ?>'); -define('SITE_ID_CURRENT_SITE', 1); -define('BLOG_ID_CURRENT_SITE', 1); - -<?php - $ms_config = ob_get_clean(); - - self::modify_wp_config( $ms_config ); - WP_CLI::log( 'Added multisite constants to wp-config.php.' ); +define( 'MULTISITE', true ); +define( 'SUBDOMAIN_INSTALL', {$subdomain_export} ); +\$base = '{$assoc_args['base']}'; +define( 'DOMAIN_CURRENT_SITE', '{$domain}' ); +define( 'PATH_CURRENT_SITE', '{$assoc_args['base']}' ); +define( 'SITE_ID_CURRENT_SITE', 1 ); +define( 'BLOG_ID_CURRENT_SITE', 1 ); +EOT; + + $wp_config_path = Utils\locate_wp_config(); + if ( is_writable( $wp_config_path ) ) { + self::modify_wp_config( $ms_config ); + WP_CLI::log( 'Added multisite constants to wp-config.php.' ); + } else { + WP_CLI::warning( 'Multisite constants could not be written to wp-config.php:' ); + WP_CLI::log( $ms_config ); + } } return true; From 2e570c809fe197e58425bc2dc57542feb30865c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 7 Sep 2015 07:19:57 -0700 Subject: [PATCH 3698/5359] Clarify the end user may need to add the constants manually --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 939a78f93..d65410043 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -661,7 +661,7 @@ private function _multisite_convert( $assoc_args ) { self::modify_wp_config( $ms_config ); WP_CLI::log( 'Added multisite constants to wp-config.php.' ); } else { - WP_CLI::warning( 'Multisite constants could not be written to wp-config.php:' ); + WP_CLI::warning( 'Multisite constants could not be written to wp-config.php. You may need to add them manually:' ); WP_CLI::log( $ms_config ); } } From d7abd6c7d8e9c3063f3bff98a899364bb8d06045 Mon Sep 17 00:00:00 2001 From: Grant McInnes <grant.mcinnes@eyesopen.ca> Date: Fri, 11 Sep 2015 13:15:38 -0400 Subject: [PATCH 3699/5359] Improve description of search-replace behavior This description used to emphasize that search-replace worked on all tables. That's not true. If plugins create tables and don't register the tables on the $wpdb object, search-replace will ignore them in the default configuration. This clarifies it I hope. Hopefully also clarifies that --all-tables ignores the wpdb registry. --- php/commands/search-replace.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 889a7923e..b6e93a71b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -12,8 +12,10 @@ class Search_Replace_Command extends WP_CLI_Command { * * ## DESCRIPTION * - * This command will go through all rows in all tables and will replace all - * appearances of the old string with the new one. + * This command will go through all rows in a selection of tables + * and will replace all appearances of the old string with the new one. The + * default tables are those registered on the $wpdb object (usually just wordpress + * core tables). * * It will correctly handle serialized values, and will not change primary key values. * @@ -47,7 +49,7 @@ class Search_Replace_Command extends WP_CLI_Command { * : Enable replacement on any tables that match the table prefix even if not registered on wpdb * * [--all-tables] - * : Enable replacement on ALL tables in the database, regardless of the prefix. Overrides --network and --all-tables-with-prefix. + * : Enable replacement on ALL tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --network and --all-tables-with-prefix. * * [--verbose] * : Prints rows to the console as they're updated. From eb0f8670d034f324babb8cf43030a144baaab7c3 Mon Sep 17 00:00:00 2001 From: Grant McInnes <grant.mcinnes@eyesopen.ca> Date: Fri, 11 Sep 2015 13:56:53 -0400 Subject: [PATCH 3700/5359] Update search-replace.php --- php/commands/search-replace.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b6e93a71b..5e2df5649 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -14,8 +14,8 @@ class Search_Replace_Command extends WP_CLI_Command { * * This command will go through all rows in a selection of tables * and will replace all appearances of the old string with the new one. The - * default tables are those registered on the $wpdb object (usually just wordpress - * core tables). + * default tables are those registered on the $wpdb object (usually + * just Wordpress core tables). * * It will correctly handle serialized values, and will not change primary key values. * From 380a5862a9af3c5b3d80ad72bbd5ee22a3b73e78 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Fri, 11 Sep 2015 11:26:55 -0700 Subject: [PATCH 3701/5359] capital P See #2045 --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 5e2df5649..f3c1b2f00 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -15,7 +15,7 @@ class Search_Replace_Command extends WP_CLI_Command { * This command will go through all rows in a selection of tables * and will replace all appearances of the old string with the new one. The * default tables are those registered on the $wpdb object (usually - * just Wordpress core tables). + * just WordPress core tables). * * It will correctly handle serialized values, and will not change primary key values. * From 031c531072013686a12e04a83dc3626d9d7a83d6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 13 Sep 2015 06:38:39 -0700 Subject: [PATCH 3702/5359] Generic args for `wp comment create` should always be optional ... including setting a post ID --- php/commands/comment.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index e27d30647..38d0bdb12 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -32,7 +32,7 @@ public function __construct() { * * ## OPTIONS * - * --<field>=<value> + * [--<field>=<value>] * : Associative args for the new comment. See wp_insert_comment(). * * [--porcelain] @@ -44,10 +44,12 @@ public function __construct() { */ public function create( $args, $assoc_args ) { parent::_create( $args, $assoc_args, function ( $params ) { - $post_id = $params['comment_post_ID']; - $post = get_post( $post_id ); - if ( !$post ) { - return new WP_Error( 'no_post', "Can't find post $post_id." ); + if ( isset( $params['comment_post_ID'] ) ) { + $post_id = $params['comment_post_ID']; + $post = get_post( $post_id ); + if ( !$post ) { + return new WP_Error( 'no_post', "Can't find post $post_id." ); + } } // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and From bf1f0297661c384e90634c46dbeb5e3766c59225 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 13 Sep 2015 07:20:46 -0700 Subject: [PATCH 3703/5359] Add `--post_type__not_in` argument to `wp export` This argument makes it easier to generate an export with all post types _except_ those identified. --- features/export.feature | 62 ++++++++++++++++++++++++++++++++++++++++- php/commands/export.php | 50 +++++++++++++++++++++++++-------- 2 files changed, 100 insertions(+), 12 deletions(-) diff --git a/features/export.feature b/features/export.feature index 58d183546..ab8c51b40 100644 --- a/features/export.feature +++ b/features/export.feature @@ -316,4 +316,64 @@ Feature: Export content. Then STDOUT should be: """ 5 - """ \ No newline at end of file + """ + + Scenario: Exclude a specific post type from export + Given a WP install + And I run `wp post generate --post_type=post --count=10` + And I run `wp plugin install wordpress-importer --activate` + + When I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 12 + """ + + When I run `wp export --post_type__not_in=post` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post generate --post_type=post --count=10` + And I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 11 + """ + + When I run `wp export --post_type__not_in=post,page` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=count` + Then STDOUT should be: + """ + 0 + """ diff --git a/php/commands/export.php b/php/commands/export.php index de8ab4063..230548afd 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -35,6 +35,10 @@ class Export_Command extends WP_CLI_Command { * : Export only posts with this post_type. Separate multiple post types with a * comma. Defaults to all. * + * [--post_type__not_in=<post-type>] + * : Export all post types except those identified. Seperate multiple post types + * with a comma. Defaults to none. + * * [--post__in=<pid>] * : Export all posts specified as a comma-separated list of IDs. * @@ -58,17 +62,18 @@ class Export_Command extends WP_CLI_Command { */ public function __invoke( $_, $assoc_args ) { $defaults = array( - 'dir' => NULL, - 'start_date' => NULL, - 'end_date' => NULL, - 'post_type' => NULL, - 'author' => NULL, - 'category' => NULL, - 'post_status' => NULL, - 'post__in' => NULL, - 'start_id' => NULL, - 'skip_comments' => NULL, - 'max_file_size' => 15, + 'dir' => NULL, + 'start_date' => NULL, + 'end_date' => NULL, + 'post_type' => NULL, + 'post_type__not_in' => NULL, + 'author' => NULL, + 'category' => NULL, + 'post_status' => NULL, + 'post__in' => NULL, + 'start_id' => NULL, + 'skip_comments' => NULL, + 'max_file_size' => 15, ); $this->validate_args( wp_parse_args( $assoc_args, $defaults ) ); @@ -201,6 +206,29 @@ private function check_post_type( $post_type ) { return true; } + private function check_post_type__not_in( $post_type ) { + if ( is_null( $post_type ) ) { + return true; + } + + $post_type = array_unique( array_filter( explode( ',', $post_type ) ) ); + $post_types = get_post_types(); + + $keep_post_types = array(); + foreach ( $post_type as $type ) { + if ( ! in_array( $type, $post_types ) ) { + WP_CLI::warning( sprintf( + 'The post type %s does not exist. Use any of these existing post types instead: %s', + $type, + implode( ", ", $post_types ) + ) ); + return false; + } + } + $this->export_args['post_type'] = array_diff( $post_types, $post_type ); + return true; + } + private function check_post__in( $post__in ) { if ( is_null( $post__in ) ) return true; From deb904f024c0ff307bdc662fb888534916a1c136 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 13 Sep 2015 07:50:57 -0700 Subject: [PATCH 3704/5359] Use `wp core update-db --network` to upgrade databases across network --- features/core.feature | 11 +++++++++++ php/class-wp-cli.php | 7 +++++-- php/commands/core.php | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index 558fcb70f..7d508c7d1 100644 --- a/features/core.feature +++ b/features/core.feature @@ -289,6 +289,17 @@ Feature: Manage WordPress installation Error: Multisite with subdomains cannot be configured when domain is 'localhost'. """ + Scenario: Update db across network + Given a WP multisite install + And I run `wp site create --slug=foo` + And I run `wp site create --slug=bar` + + When I run `wp core update-db --network` + Then STDOUT should contain: + """ + Success: WordPress database upgraded on 3/3 sites. + """ + Scenario: Update from a ZIP file Given a WP install diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 620457433..c4255ac68 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -397,10 +397,11 @@ public static function launch( $command, $exit_on_error = true, $return_detailed * @param array $assoc_args Associative arguments to use * @param bool Whether to exit if the command returns an error status * @param bool Whether to return an exit status (default) or detailed execution results + * @param array $runtime_args Override one or more global args (path,url,user,allow-root) * * @return int|ProcessRun The command exit status, or a ProcessRun instance */ - public static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false ) { + public static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false, $runtime_args = array() ) { $reused_runtime_args = array( 'path', 'url', @@ -409,7 +410,9 @@ public static function launch_self( $command, $args = array(), $assoc_args = arr ); foreach ( $reused_runtime_args as $key ) { - if ( $value = self::get_runner()->config[ $key ] ) + if ( isset( $runtime_args[ $key ] ) ) { + $assoc_args[ $key ] = $runtime_args[ $key ]; + } else if ( $value = self::get_runner()->config[ $key ] ) $assoc_args[ $key ] = $value; } diff --git a/php/commands/core.php b/php/commands/core.php index d65410043..fae093dcc 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -968,12 +968,42 @@ function update( $args, $assoc_args ) { /** * Update the WordPress database. * + * [--network] + * : Update databases for all sites on a network + * * @subcommand update-db */ - function update_db() { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - wp_upgrade(); - WP_CLI::success( 'WordPress database upgraded successfully.' ); + function update_db( $_, $assoc_args ) { + global $wpdb; + + $network = Utils\get_flag_value( $assoc_args, 'network' ); + if ( $network && ! is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + + if ( $network ) { + $iterator_args = array( + 'table' => $wpdb->blogs, + ); + $it = new \WP_CLI\Iterators\Table( $iterator_args ); + $success = $total = 0; + foreach( $it as $blog ) { + $total++; + $url = $blog->domain . $blog->path; + $process = WP_CLI::launch_self( 'core update-db', array(), array(), false, true, array( 'url' => $url ) ); + if ( 0 == $process->return_code ) { + WP_CLI::log( "Database upgraded successfully on {$url}" ); + $success++; + } else { + WP_CLI::warning( "Database failed to upgrade on {$url}" ); + } + } + WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); + } else { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + wp_upgrade(); + WP_CLI::success( 'WordPress database upgraded successfully.' ); + } } /** From ea6ee604fa54e6de7c1f247ad0bf7deb136a2361 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Tue, 15 Sep 2015 16:33:55 -0700 Subject: [PATCH 3705/5359] Failing test case for wp-includes/session.php not loading See #2049 --- features/framework.feature | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 features/framework.feature diff --git a/features/framework.feature b/features/framework.feature new file mode 100644 index 000000000..438471e25 --- /dev/null +++ b/features/framework.feature @@ -0,0 +1,15 @@ +Feature: Load WP-CLI + + Scenario: A plugin calling wp_signon() shouldn't fatal + Given a WP install + And I run `wp user create testuser test@example.org --user_pass=testuser` + And a wp-content/mu-plugins/test.php file: + """ + <?php + add_action( 'plugins_loaded', function(){ + wp_signon( array( 'user_login' => 'testuser', 'user_password' => 'testuser' ) ); + }); + """ + + When I run `wp option get home` + Then STDOUT should not be empty From 519ad782bf7e370f19eb81f4dcc5b8b8bac1bcc3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Tue, 15 Sep 2015 16:35:01 -0700 Subject: [PATCH 3706/5359] Ensure wp-includes/session.php is loaded in bootstrap --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 28cc2380b..720ef44af 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -139,6 +139,7 @@ require( ABSPATH . WPINC . '/class-wp-theme.php' ); require( ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); +require( ABSPATH . WPINC . '/session.php' ); require( ABSPATH . WPINC . '/meta.php' ); require( ABSPATH . WPINC . '/general-template.php' ); require( ABSPATH . WPINC . '/link-template.php' ); From 1a947094432c7e4bf10508c9444ae3144eee9b3d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Tue, 15 Sep 2015 16:43:11 -0700 Subject: [PATCH 3707/5359] Dismiss admin notice if all upgrades were successful --- php/commands/core.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index fae093dcc..2fd10be8d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -974,7 +974,7 @@ function update( $args, $assoc_args ) { * @subcommand update-db */ function update_db( $_, $assoc_args ) { - global $wpdb; + global $wpdb, $wp_db_version; $network = Utils\get_flag_value( $assoc_args, 'network' ); if ( $network && ! is_multisite() ) { @@ -998,6 +998,9 @@ function update_db( $_, $assoc_args ) { WP_CLI::warning( "Database failed to upgrade on {$url}" ); } } + if ( $total && $success == $total ) { + update_site_option( 'wpmu_upgrade_site', $wp_db_version ); + } WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); } else { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); From ff2c2522c031a51df535dde4324eebcf257e9862 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Tue, 15 Sep 2015 16:50:25 -0700 Subject: [PATCH 3708/5359] Update tests for WP 4.3.1 and associated security releases --- features/core.feature | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/features/core.feature b/features/core.feature index 558fcb70f..2cae7ea1a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -316,7 +316,7 @@ Feature: Manage WordPress installation 3.9 """ - @download + @download @update-check Scenario: Check for update via Version Check API Given a WP install @@ -326,12 +326,12 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.3 | major | https://wordpress.org/wordpress-4.3.zip | - | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | - | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | - | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | - | 3.9.8 | major | https://wordpress.org/wordpress-3.9.8.zip | - | 3.8.10 | minor | https://wordpress.org/wordpress-3.8.10.zip | + | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | + | 4.2.5 | major | https://wordpress.org/wordpress-4.2.5.zip | + | 4.1.8 | major | https://wordpress.org/wordpress-4.1.8.zip | + | 4.0.8 | major | https://wordpress.org/wordpress-4.0.8.zip | + | 3.9.9 | major | https://wordpress.org/wordpress-3.9.9.zip | + | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -342,11 +342,11 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.3 | major | https://wordpress.org/wordpress-4.3.zip | - | 4.2.4 | major | https://wordpress.org/wordpress-4.2.4.zip | - | 4.1.7 | major | https://wordpress.org/wordpress-4.1.7.zip | - | 4.0.7 | major | https://wordpress.org/wordpress-4.0.7.zip | - | 3.9.8 | major | https://wordpress.org/wordpress-3.9.8.zip | + | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | + | 4.2.5 | major | https://wordpress.org/wordpress-4.2.5.zip | + | 4.1.8 | major | https://wordpress.org/wordpress-4.1.8.zip | + | 4.0.8 | major | https://wordpress.org/wordpress-4.0.8.zip | + | 3.9.9 | major | https://wordpress.org/wordpress-3.9.9.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -357,7 +357,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.10 | minor | https://wordpress.org/wordpress-3.8.10.zip | + | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: From ff176910ee47290f1593206264ca4d7f679056f1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Wed, 16 Sep 2015 06:21:57 -0700 Subject: [PATCH 3709/5359] `session.php` was introduced in WP 4.0 --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 720ef44af..c52034c15 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -139,7 +139,7 @@ require( ABSPATH . WPINC . '/class-wp-theme.php' ); require( ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); -require( ABSPATH . WPINC . '/session.php' ); +Utils\maybe_require( '4.0', ABSPATH . WPINC . '/session.php' ); require( ABSPATH . WPINC . '/meta.php' ); require( ABSPATH . WPINC . '/general-template.php' ); require( ABSPATH . WPINC . '/link-template.php' ); From b1b6c0dbc920abc4a6a53713005d3393d1e9165a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 19 Sep 2015 15:06:53 +0200 Subject: [PATCH 3710/5359] Fixed deb creator script: added changelog, man page, copyright --- utils/wp-cli-updatedeb.sh | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index 7f1aefe33..fe40b73e4 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -24,7 +24,7 @@ die() { } dump_control() { - cat > DEBIAN/control <<CTRL + cat > DEBIAN/control <<EOF Package: php-wpcli Version: 0.0.0 Architecture: all @@ -37,7 +37,7 @@ Description: wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser. -CTRL +EOF } # deb's dir @@ -53,6 +53,31 @@ if ! [ -r DEBIAN/control ]; then dump_control fi +# copyright +if ! [ -r usr/share/doc/php-wpcli/copyright ];then + mkdir -p usr/share/doc/php-wpcli &> /dev/null + wget -nv -O usr/share/doc/php-wpcli/copyright https://github.com/wp-cli/wp-cli/raw/master/LICENSE.txt +fi + +# changelog +if ! [ -r usr/share/doc/php-wpcli/changelog.gz ];then + mkdir -p usr/share/doc/php-wpcli &> /dev/null + echo "Changelog can be found in the blog: http://wp-cli.org/blog/" \ + | gzip -9 > usr/share/doc/php-wpcli/changelog.gz +fi + +# minimal man page +if ! [ -r usr/share/man/man1/wp.1.gz ];then + mkdir -p usr/share/man/man1 &> /dev/null + { + echo '.TH "WP" "1"' + wp --help + } \ + | sed 's/^\([A-Z ]\+\)$/.SH "\1"/' \ + | sed 's/^ wp$/wp \\- A command line interface for WordPress/' \ + | gzip -9 > usr/share/man/man1/wp.1.gz +fi + # content dirs [ -d usr/bin ] || mkdir -p usr/bin @@ -78,6 +103,6 @@ WPCLI_PKG="${PWD}/php-wpcli_${WPCLI_VER}_all.deb" fakeroot dpkg-deb --build "$DIR" "$WPCLI_PKG" || die 8 "Packaging failed" # optional steps -echo "sign it: dpkg-sig -k <YOUR-KEY> -s builder \"$WPCLI_PKG\"" -echo "include in your repo: pushd /var/www/<REPO-DIR>" -echo "reprepro includedeb wheezy \"$WPCLI_PKG\" && popd" +echo "sign it: dpkg-sig -k YOUR-KEY -s builder \"${WPCLI_PKG}\"" +echo "include in your repo: pushd /var/www/REPO-DIR" +echo " reprepro includedeb jessie \"${WPCLI_PKG}\" && popd" From f71b4c1c6fcbd65bac0d45272b5e01afe204afac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sat, 19 Sep 2015 11:02:21 -0700 Subject: [PATCH 3711/5359] Let user know when invalid subcommand has a valid parent command --- features/command.feature | 24 ++++++++++++++++++++++++ php/WP_CLI/Runner.php | 19 +++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/features/command.feature b/features/command.feature index 6e034d6b2..2039cc123 100644 --- a/features/command.feature +++ b/features/command.feature @@ -15,3 +15,27 @@ Feature: WP-CLI Commands """ Class 'Non_Existent_Class' does not exist. """ + + Scenario: Invalid subcommand of valid command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + /** + * @when before_wp_load + */ + class Custom_Command_Class extends WP_CLI_Command { + + public function valid() { + WP_CLI::success( 'Hello world' ); + } + + } + WP_CLI::add_command( 'command', 'Custom_Command_Class' ); + """ + + When I try `wp --require=custom-cmd.php command invalid` + Then STDERR should be: + """ + Error: 'invalid' is not a registered subcommand of 'command'. See 'wp help command'. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3e36d818d..7a6b02715 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -261,10 +261,21 @@ public function find_command_to_run( $args ) { $subcommand = $command->find_subcommand( $args ); if ( !$subcommand ) { - return sprintf( - "'%s' is not a registered wp command. See 'wp help'.", - $full_name - ); + if ( count( $cmd_path ) > 1 ) { + $child = array_pop( $cmd_path ); + $parent_name = implode( ' ', $cmd_path ); + return sprintf( + "'%s' is not a registered subcommand of '%s'. See 'wp help %s'.", + $child, + $parent_name, + $parent_name + ); + } else { + return sprintf( + "'%s' is not a registered wp command. See 'wp help'.", + $full_name + ); + } } if ( $this->is_command_disabled( $subcommand ) ) { From 6b54e61a793f8d8b78014863f6c0f07199ed8761 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sat, 19 Sep 2015 11:26:30 -0700 Subject: [PATCH 3712/5359] Permit `--path` for `wp core download`, even when WP is detected This lets a custom WP-CLI command download WP to a different directory, when loaded from the scope of an existing WP install. --- features/core.feature | 26 ++++++++++++++++++++++++++ php/commands/core.php | 15 +++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/features/core.feature b/features/core.feature index a731cf6f6..d0e3b16bd 100644 --- a/features/core.feature +++ b/features/core.feature @@ -490,6 +490,32 @@ Feature: Manage WordPress installation Error: Release not found. """ + Scenario: Core download to a directory specified by `--path` in custom command + Given a WP install + And a download-command.php file: + """ + <?php + class Download_Command extends WP_CLI_Command { + public function __invoke() { + WP_CLI::run_command( array( 'core', 'download' ), array( 'path' => 'src/' ) ); + } + } + WP_CLI::add_command( 'custom-download', 'Download_Command' ); + """ + + When I run `wp --require=download-command.php custom-download` + Then STDOUT should not be empty + And the src directory should contain: + """ + wp-load.php + """ + + When I try `wp --require=download-command.php custom-download` + Then STDERR should be: + """ + Error: WordPress files seem to already be present here. + """ + Scenario: Ensure cached partial upgrades aren't used in full upgrade Given a WP install And an empty cache diff --git a/php/commands/core.php b/php/commands/core.php index 2fd10be8d..81694a707 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -121,13 +121,16 @@ function check_update( $_, $assoc_args ) { * @when before_wp_load */ public function download( $args, $assoc_args ) { - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && is_readable( ABSPATH . 'wp-load.php' ) ) + + $download_dir = ! empty( $assoc_args['path'] ) ? $assoc_args['path'] : ABSPATH; + + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && is_readable( $download_dir . 'wp-load.php' ) ) WP_CLI::error( 'WordPress files seem to already be present here.' ); - if ( !is_dir( ABSPATH ) ) { - WP_CLI::log( sprintf( 'Creating directory %s', ABSPATH ) ); + if ( !is_dir( $download_dir ) ) { + WP_CLI::log( sprintf( 'Creating directory %s', $download_dir ) ); $mkdir = \WP_CLI\Utils\is_windows() ? 'mkdir %s' : 'mkdir -p %s'; - WP_CLI::launch( Utils\esc_cmd( $mkdir, ABSPATH ) ); + WP_CLI::launch( Utils\esc_cmd( $mkdir, $download_dir ) ); } $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); @@ -154,7 +157,7 @@ public function download( $args, $assoc_args ) { if ( $cache_file ) { WP_CLI::log( "Using cached file '$cache_file'..." ); try{ - self::_extract( $cache_file, ABSPATH ); + self::_extract( $cache_file, $download_dir ); } catch ( Exception $e ) { WP_CLI::warning( "Extraction failed, downloading a new copy..." ); $bad_cache = true; @@ -180,7 +183,7 @@ public function download( $args, $assoc_args ) { } try { - self::_extract( $temp, ABSPATH ); + self::_extract( $temp, $download_dir ); } catch ( Exception $e ) { WP_CLI::error( "Couldn't extract WordPress archive. " . $e->getMessage() ); } From 5f677bcedf829738ab66d6963354ff4904ac7b66 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sat, 19 Sep 2015 11:50:07 -0700 Subject: [PATCH 3713/5359] Pass any `rewrite flush` warnings when using `rewrite structure` --- features/rewrite.feature | 6 ++++++ php/commands/rewrite.php | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index 25fe482e1..3c49c4843 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -75,3 +75,9 @@ Feature: Manage WordPress rewrites """ Warning: WordPress can't generate .htaccess file for a multisite install. """ + + When I try `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` + Then STDERR should contain: + """ + Warning: WordPress can't generate .htaccess file for a multisite install. + """ diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 58c5ff26c..5a6f4ab0b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -129,7 +129,11 @@ public function structure( $args, $assoc_args ) { } } - \WP_CLI::launch_self( 'rewrite flush', array(), $new_assoc_args ); + $process_run = WP_CLI::launch_self( 'rewrite flush', array(), $new_assoc_args, true, true, array( 'apache_modules', WP_CLI::get_config( 'apache_modules' ) ) ); + if ( ! empty( $process_run->stderr ) ) { + // Strip "Warning: " + WP_CLI::warning( substr( $process_run->stderr, 9 ) ); + } WP_CLI::success( "Rewrite structure set." ); } From 8a3af834b43f34d998f79a426370ffb5b3b41de5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sat, 19 Sep 2015 11:56:24 -0700 Subject: [PATCH 3714/5359] Run test suite against PHP 5.6, instead of PHP 5.5 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 28e3bdd2b..8f37b55a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ language: php php: - 5.3 - - 5.5 + - 5.6 env: global: @@ -34,12 +34,12 @@ env: - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: - - WP_VERSION=4.3 + - WP_VERSION=4.3.1 - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: exclude: - - php: 5.5 + - php: 5.6 env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From a77a9df6c3106cef756b087d07cd776efbcf30f4 Mon Sep 17 00:00:00 2001 From: Stephen Edgar <stephen@netweb.com.au> Date: Sun, 20 Sep 2015 10:00:24 +1000 Subject: [PATCH 3715/5359] Use HTTPS for w.org SVN checkout --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index c96a09f17..80ba41649 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -56,7 +56,7 @@ install_test_suite() { if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR/includes fi cd $WP_TESTS_DIR From 9f597261f0f7d60f50e6e1e1b86d6ee41d18abd9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 05:45:27 -0700 Subject: [PATCH 3716/5359] Deprecate `wp post url` in favor of `wp post list --field=url` --- php/WP_CLI/Runner.php | 11 +++++++++++ php/commands/post.php | 25 ++++++------------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7a6b02715..33ef848ee 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -453,6 +453,17 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } + // post url --> post list --post__in --field=url + if ( count( $args ) >= 2 && 'post' === $args[0] && 'url' === $args[1] ) { + $post_ids = array_slice( $args, 2 ); + $args = array( 'post', 'list' ); + $assoc_args['post__in'] = implode( ',', $post_ids ); + $assoc_args['post_type'] = 'any'; + $assoc_args['orderby'] = 'post__in'; + $assoc_args['field'] = 'url'; + break; + } + return array( $args, $assoc_args ); } diff --git a/php/commands/post.php b/php/commands/post.php index 3d5fa4557..38dd7d2c6 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -270,6 +270,7 @@ public function delete( $args, $assoc_args ) { * * post_mime_type * * comment_count * * filter + * * url * * ## EXAMPLES * @@ -305,7 +306,11 @@ public function list_( $_, $assoc_args ) { echo implode( ' ', $query->posts ); } else { $query = new WP_Query( $query_args ); - $formatter->display_items( $query->posts ); + $posts = array_map( function( $post ) { + $post->url = get_permalink( $post->ID ); + return $post; + }, $query->posts ); + $formatter->display_items( $posts ); } } @@ -424,24 +429,6 @@ public function generate( $args, $assoc_args ) { // @codingStandardsIgnoreEnd } - /** - * Get post url - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of posts get the URL. - * - * ## EXAMPLES - * - * wp post url 123 - * - * wp post url 123 324 - */ - public function url( $args ) { - parent::_url( $args, 'get_permalink' ); - } - private function maybe_make_child() { // 50% chance of making child post return ( mt_rand(1, 2) == 1 ); From 6b7bbe7690183c2d1daf82e6fa595a9ac1e74bea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 06:01:27 -0700 Subject: [PATCH 3717/5359] Attempt two at seeing what fails in PHP 7 --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8f37b55a4..46b1adf30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: php php: - 5.3 - 5.6 + - '7' env: global: @@ -41,6 +42,8 @@ matrix: exclude: - php: 5.6 env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master + - php: '7' + env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From aa74d5ecd0a7e674a30968ea60ba8bf7df16332b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 06:08:09 -0700 Subject: [PATCH 3718/5359] Remove errant `break` --- php/WP_CLI/Runner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 33ef848ee..e84a9a177 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -461,7 +461,6 @@ private static function back_compat_conversions( $args, $assoc_args ) { $assoc_args['post_type'] = 'any'; $assoc_args['orderby'] = 'post__in'; $assoc_args['field'] = 'url'; - break; } return array( $args, $assoc_args ); From 5e5733803c0d8e79f997b4de951e5c722f4650b5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 07:01:51 -0700 Subject: [PATCH 3719/5359] Deprecate `wp site url` in favor of `wp site list --field=url` Also uses `get_site_url()` to produce `url` in `wp site list` for consistency with other resources --- features/site.feature | 31 +++++++++++++++++++++---------- php/WP_CLI/Iterators/Table.php | 11 ++++++++--- php/WP_CLI/Runner.php | 26 ++++++++++++++++++-------- php/commands/site.php | 29 ++++++++--------------------- 4 files changed, 55 insertions(+), 42 deletions(-) diff --git a/features/site.feature b/features/site.feature index 58eb137f8..f46478da9 100644 --- a/features/site.feature +++ b/features/site.feature @@ -18,15 +18,15 @@ Feature: Manage sites in a multisite installation When I run `wp site list --fields=blog_id,url` Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | example.com/ | - | 2 | example.com/first/ | + | blog_id | url | + | 1 | http://example.com/ | + | 2 | http://example.com/first/ | When I run `wp site list --field=url` Then STDOUT should be: """ - example.com/ - example.com/first/ + http://example.com/ + http://example.com/first/ """ When I run `wp site delete {SITE_ID} --yes` @@ -44,14 +44,14 @@ Feature: Manage sites in a multisite installation When I run `wp site list --fields=blog_id,url` Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | example.com/ | - | 2 | example.com/first/ | + | blog_id | url | + | 1 | http://example.com/ | + | 2 | http://example.com/first/ | When I run `wp site list --field=url --blog_id=2` Then STDOUT should be: """ - example.com/first/ + http://example.com/first/ """ Scenario: Delete a site by slug @@ -100,7 +100,18 @@ Feature: Manage sites in a multisite installation When I run `wp site url {SITE_ID}` Then STDOUT should be: """ - http://example.com/first + http://example.com/first/ + """ + + When I run `wp site create --slug=second --porcelain` + Then STDOUT should be a number + And save STDOUT as {SECOND_ID} + + When I run `wp site url {SECOND_ID} {SITE_ID}` + Then STDOUT should be: + """ + http://example.com/second/ + http://example.com/first/ """ Scenario: Archive/unarchive a site diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index eb7d1d60f..cebb812bd 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -36,11 +36,13 @@ class Table extends Query { * = string – this will be the where clause * = array – each element is treated as a condition if it's positional, or as column => value if * it's a key/value pair. In the latter case the value is automatically quoted and escaped + * append - add arbitrary extra SQL */ function __construct( $args = array() ) { $defaults = array( 'fields' => '*', 'where' => array(), + 'append' => '', 'table' => null, 'chunk_size' => 500 ); @@ -50,7 +52,7 @@ function __construct( $args = array() ) { $fields = self::build_fields( $args['fields'] ); $conditions = self::build_where_conditions( $args['where'] ); $where_sql = $conditions ? " WHERE $conditions" : ''; - $query = "SELECT $fields FROM $table $where_sql"; + $query = "SELECT $fields FROM $table $where_sql {$args['append']}"; parent::__construct( $query, $args['chunk_size'] ); } @@ -67,10 +69,13 @@ private static function build_where_conditions( $where ) { if ( is_array( $where ) ) { $conditions = array(); foreach( $where as $key => $value ) { - if ( is_numeric( $key ) ) + if ( is_array( $value ) ) { + $conditions[] = $key . ' IN (' . $wpdb->escape( implode( ',', $value ) ) . ')'; + } else if ( is_numeric( $key ) ) { $conditions[] = $value; - else + } else { $conditions[] = $key . ' = "' . $wpdb->escape( $value ) .'"'; + } } $where = implode( ' AND ', $conditions ); } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e84a9a177..5a3927f46 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -453,14 +453,24 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } - // post url --> post list --post__in --field=url - if ( count( $args ) >= 2 && 'post' === $args[0] && 'url' === $args[1] ) { - $post_ids = array_slice( $args, 2 ); - $args = array( 'post', 'list' ); - $assoc_args['post__in'] = implode( ',', $post_ids ); - $assoc_args['post_type'] = 'any'; - $assoc_args['orderby'] = 'post__in'; - $assoc_args['field'] = 'url'; + // (post|site) url --> (post|site) list --*__in --field=url + if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'site' ) ) && 'url' === $args[1] ) { + switch ( $args[0] ) { + case 'post': + $post_ids = array_slice( $args, 2 ); + $args = array( 'post', 'list' ); + $assoc_args['post__in'] = implode( ',', $post_ids ); + $assoc_args['post_type'] = 'any'; + $assoc_args['orderby'] = 'post__in'; + $assoc_args['field'] = 'url'; + break; + case 'site': + $site_ids = array_slice( $args, 2 ); + $args = array( 'site', 'list' ); + $assoc_args['site__in'] = implode( ',', $site_ids ); + $assoc_args['field'] = 'url'; + break; + } } return array( $args, $assoc_args ); diff --git a/php/commands/site.php b/php/commands/site.php index cbdf6ac18..d9faf3e9a 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -394,6 +394,7 @@ public function list_( $_, $assoc_args ) { $assoc_args = array_merge( $defaults, $assoc_args ); $where = array(); + $append = ''; $site_cols = array( 'blog_id', 'url', 'last_updated', 'registered', 'site_id', 'domain', 'path', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ); foreach( $site_cols as $col ) { @@ -402,6 +403,11 @@ public function list_( $_, $assoc_args ) { } } + if ( isset( $assoc_args['site__in'] ) ) { + $where['blog_id'] = explode( ',', $assoc_args['site__in'] ); + $append = "ORDER BY FIELD( blog_id, " . implode( ',', array_map( 'intval', $where['blog_id'] ) ) . " )"; + } + if ( isset( $assoc_args['network'] ) ) { $where['site_id'] = $assoc_args['network']; } @@ -409,11 +415,12 @@ public function list_( $_, $assoc_args ) { $iterator_args = array( 'table' => $wpdb->blogs, 'where' => $where, + 'append' => $append, ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); $it = \WP_CLI\Utils\iterator_map( $it, function( $blog ) { - $blog->url = $blog->domain . $blog->path; + $blog->url = trailingslashit( get_site_url( $blog->blog_id ) ); return $blog; } ); @@ -421,26 +428,6 @@ public function list_( $_, $assoc_args ) { $formatter->display_items( $it ); } - /** - * Get site url - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to get the URL. - * - * ## EXAMPLES - * - * wp site url 123 - */ - public function url( $args ) { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - parent::_url( $args, 'get_site_url' ); - } - /** * Archive one or more sites * From 69bb3694663a32455a22fe5e8336cb5ebb624760 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 07:07:44 -0700 Subject: [PATCH 3720/5359] Add test case for custom base path for multisite --- features/core.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/core.feature b/features/core.feature index d0e3b16bd..4eb71f8eb 100644 --- a/features/core.feature +++ b/features/core.feature @@ -490,6 +490,16 @@ Feature: Manage WordPress installation Error: Release not found. """ + Scenario: Test output in a multisite install with custom base path + Given a WP install + + When I run `wp core multisite-convert --title=Test --base=/test/` + And I run `wp post list` + Then STDOUT should contain: + """ + Hello world! + """ + Scenario: Core download to a directory specified by `--path` in custom command Given a WP install And a download-command.php file: From ce7b969cd8571eaed6c996cb3f0d096c5bad96f9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 07:36:50 -0700 Subject: [PATCH 3721/5359] Update db tests to use empty `DB_CHARSET` instead of file mod hack --- features/db.feature | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/features/db.feature b/features/db.feature index 2fc9b71e5..373498951 100644 --- a/features/db.feature +++ b/features/db.feature @@ -73,17 +73,19 @@ Feature: Perform database operations """ Scenario: DB export no charset - Given a WP install - And a replace-script.php file: + Given an empty directory + And WP files + + When I run `wp core config {CORE_CONFIG_SETTINGS} --dbcharset=""` + Then STDOUT should not be empty + + When I run `cat wp-config.php` + Then STDOUT should contain: """ - <?php - $wp_config = file_get_contents( 'wp-config.php' ); - $wp_config = str_replace( 'utf8', '', $wp_config ); - file_put_contents( 'wp-config.php', $wp_config ); - WP_CLI::success( "Replaced charset" ); + define('DB_CHARSET', ''); """ - When I run `wp eval-file replace-script.php` + When I run `wp db create` Then STDOUT should not be empty When I run `wp db export /tmp/wp-cli-behat.sql` From e1c5db0b383979bce60734b0cf6a499af9850c5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 07:48:09 -0700 Subject: [PATCH 3722/5359] Support APC cache with WP-CLI, but only after warning with confirmation --- php/wp-settings-cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index c52034c15..a72c3d50d 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -102,7 +102,8 @@ // WP-CLI: the APC cache is not available on the command-line, so bail, to prevent cache poisoning if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { - WP_CLI::error( 'WP-CLI is not compatible with the APC object cache.' ); + WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' ); + WP_CLI::confirm( 'Given the consequences, do you wish to continue?' ); } // Attach the default filters. From e430b6228a52b4c0215b3cf2698ec2d216806190 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 14:06:41 -0700 Subject: [PATCH 3723/5359] Deprecate `@synopsis` for `cap`, `eval`, `help`, `option`, and others --- php/commands/cap.php | 16 +++++++++++++--- php/commands/eval.php | 5 +++-- php/commands/help.php | 7 ++++--- php/commands/option.php | 10 +++++++--- php/commands/site.php | 12 +++++------- php/commands/transient.php | 18 +++++++++++++++--- php/commands/user.php | 5 ----- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index afeee5d54..9330c2c9a 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -19,13 +19,15 @@ class Capabilities_Command extends WP_CLI_Command { /** * List capabilities for a given role. * + * <role> + * : Key for the role. + * * ## EXAMPLES * * # Display alphabetical list of bbPress moderator capabilities * wp cap list 'bbp_moderator' | sort * * @subcommand list - * @synopsis <role> */ public function list_( $args ) { $role_obj = self::get_role( $args[0] ); @@ -37,7 +39,11 @@ public function list_( $args ) { /** * Add capabilities to a given role. * - * @synopsis <role> <cap>... + * <role> + * : Key for the role. + * + * <cap>... + * : One or more capabilities to add. */ public function add( $args ) { self::persistence_check(); @@ -63,7 +69,11 @@ public function add( $args ) { /** * Remove capabilities from a given role. * - * @synopsis <role> <cap>... + * <role> + * : Key for the role. + * + * <cap>... + * : One or more capabilities to remove. */ public function remove( $args ) { self::persistence_check(); diff --git a/php/commands/eval.php b/php/commands/eval.php index 782752b76..cce2ca4b2 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -5,11 +5,12 @@ class Eval_Command extends WP_CLI_Command { /** * Execute arbitrary PHP code after loading WordPress. * + * <php-code> + * : The code to execute, as a string. + * * ## EXAMPLES * * wp eval 'echo WP_CONTENT_DIR;' - * - * @synopsis <php-code> */ public function __invoke( $args, $assoc_args ) { eval( $args[0] ); diff --git a/php/commands/help.php b/php/commands/help.php index 615089bbc..ec2dcce53 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -6,7 +6,10 @@ class Help_Command extends WP_CLI_Command { /** - * Get help on a certain command. + * Get help on WP-CLI, or on a specific. command. + * + * [<command>...] + * : Get help on a specific command. * * ## EXAMPLES * @@ -15,8 +18,6 @@ class Help_Command extends WP_CLI_Command { * * # get help for `core download` subcommand * wp help core download - * - * @synopsis [<command>...] */ function __invoke( $args, $assoc_args ) { $command = self::find_subcommand( $args ); diff --git a/php/commands/option.php b/php/commands/option.php index ff6cadc63..979a53b28 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -23,7 +23,11 @@ class Option_Command extends WP_CLI_Command { /** * Get an option. * - * @synopsis <key> [--format=<format>] + * <key> + * : Key for the option + * + * [--format=<format>] + * : Get value as var_export() or JSON. Default: var_export() */ public function get( $args, $assoc_args ) { list( $key ) = $args; @@ -118,7 +122,6 @@ public function add( $args, $assoc_args ) { * * size_bytes * * @subcommand list - * @synopsis [--search=<glob-style-pattern>] [--autoload=<value>] [--fields=<fields>] [--format=<format>] */ public function list_( $args, $assoc_args ) { @@ -220,7 +223,8 @@ public function update( $args, $assoc_args ) { /** * Delete an option. * - * @synopsis <key> + * <key> + * : Key for the option. */ public function delete( $args ) { list( $key ) = $args; diff --git a/php/commands/site.php b/php/commands/site.php index d9faf3e9a..d21d1c361 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -191,22 +191,20 @@ function delete( $args, $assoc_args ) { * --slug=<slug> * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. * - * --title=<title> + * [--title=<title>] * : Title of the new site. Default: prettified slug. * - * --email=<email> + * [--email=<email>] * : Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. * - * --network_id=<network-id> + * [--network_id=<network-id>] * : Network to associate new site with. Defaults to current network (typically 1). * - * --private + * [--private] * : If set, the new site will be non-public (not indexed) * - * --porcelain + * [--porcelain] * : If set, only the site id will be output on success. - * - * @synopsis --slug=<slug> [--title=<title>] [--email=<email>] [--network_id=<network-id>] [--private] [--porcelain] */ public function create( $_, $assoc_args ) { if ( !is_multisite() ) { diff --git a/php/commands/transient.php b/php/commands/transient.php index 3ea4b19b0..4b6de95b0 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -12,7 +12,11 @@ class Transient_Command extends WP_CLI_Command { /** * Get a transient value. * - * @synopsis <key> [--json] + * <key> + * : Key for the transient. + * + * [--json] + * : Format output as JSON. */ public function get( $args, $assoc_args ) { list( $key ) = $args; @@ -30,7 +34,14 @@ public function get( $args, $assoc_args ) { /** * Set a transient value. <expiration> is the time until expiration, in seconds. * - * @synopsis <key> <value> [<expiration>] + * <key> + * : Key for the transient. + * + * <value> + * : Value to be set for the transient. + * + * [<expiration] + * : Time until expiration, in seconds. */ public function set( $args ) { list( $key, $value ) = $args; @@ -46,7 +57,8 @@ public function set( $args ) { /** * Delete a transient value. * - * @synopsis <key> + * <key> + * : Key for the transient. */ public function delete( $args ) { list( $key ) = $args; diff --git a/php/commands/user.php b/php/commands/user.php index 6db4b15ac..09eda770f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -796,8 +796,6 @@ public function __construct() { * * [--format=<format>] * : Accepted values: table, json. Default: table - * - * @synopsis <user> <key> [--format=<format>] */ public function get( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -832,8 +830,6 @@ public function delete( $args, $assoc_args ) { * * <value> * : The new metadata value. - * - * @synopsis <user> <key> <value> [--format=<format>] */ public function add( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -853,7 +849,6 @@ public function add( $args, $assoc_args ) { * : The new metadata value. * * @alias set - * @synopsis <user> <key> <value> [--format=<format>] */ public function update( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); From 10bcfefc560e12097bea16ead3457f17f3e171c1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 14:37:01 -0700 Subject: [PATCH 3724/5359] Let eval'd `DOMAIN_CURRENT_SITE` set URL, unless `--url` is passed. Props @mboynes --- features/config.feature | 86 ++++++++++++----------------------------- php/WP_CLI/Runner.php | 41 ++++++++------------ php/wp-cli.php | 2 + 3 files changed, 44 insertions(+), 85 deletions(-) diff --git a/features/config.feature b/features/config.feature index d324ac20d..0959c9983 100644 --- a/features/config.feature +++ b/features/config.feature @@ -197,7 +197,7 @@ Feature: Have a config file """ When I run `WP_CLI_CONFIG_PATH=test-dir/config.yml wp help` - Then STDERR should be empty + Then STDERR should be empty Scenario: Missing required files should not fatal WP-CLI Given an empty directory @@ -207,23 +207,32 @@ Feature: Have a config file - missing-file.php """ - When I try `wp help` - Then STDERR should contain: - """ - Error: Required file 'missing-file.php' doesn't exist - """ + When I try `wp help` + Then STDERR should contain: + """ + Error: Required file 'missing-file.php' doesn't exist + """ When I run `wp cli info` - Then STDOUT should not be empty + Then STDOUT should not be empty When I run `wp --info` - Then STDOUT should not be empty + Then STDOUT should not be empty - Scenario: WordPress install with commented out DOMAIN_CURRENT_SITE, first style + Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE Given a WP multisite install + And a local-dev.php file: + """ + <?php + define( 'DOMAIN_CURRENT_SITE', 'example.dev' ); + """ And a wp-config.php file: """ <?php +if ( file_exists( __DIR__ . '/local-dev.php' ) ) { + require_once __DIR__ . '/local-dev.php'; +} + // ** MySQL settings ** // /** The name of the database for WordPress */ define('DB_NAME', 'wp_cli_test'); @@ -249,8 +258,9 @@ define( 'WP_ALLOW_MULTISITE', true ); define('MULTISITE', true); define('SUBDOMAIN_INSTALL', false); $base = '/'; -define('DOMAIN_CURRENT_SITE', 'example.com'); -# define('DOMAIN_CURRENT_SITE', 'bta.example.com'); +if ( ! defined( 'DOMAIN_CURRENT_SITE' ) ) { + define('DOMAIN_CURRENT_SITE', 'example.com'); +} define('PATH_CURRENT_SITE', '/'); define('SITE_ID_CURRENT_SITE', 1); define('BLOG_ID_CURRENT_SITE', 1); @@ -265,59 +275,13 @@ if ( !defined('ABSPATH') ) require_once(ABSPATH . 'wp-settings.php'); """ - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.com - """ - - Scenario: WordPress install with commented out DOMAIN_CURRENT_SITE, second style - Given a WP multisite install - And a wp-config.php file: + When I try `wp option get home` + Then STDERR should be: """ -<?php -// ** MySQL settings ** // -/** The name of the database for WordPress */ -define('DB_NAME', 'wp_cli_test'); - -/** MySQL database username */ -define('DB_USER', 'wp_cli_test'); - -/** MySQL database password */ -define('DB_PASSWORD', 'password1'); - -/** MySQL hostname */ -define('DB_HOST', '127.0.0.1'); - -/** Database Charset to use in creating database tables. */ -define('DB_CHARSET', 'utf8'); - -/** The Database Collate type. Don't change this if in doubt. */ -define('DB_COLLATE', ''); - -$table_prefix = 'wp_'; - -define( 'WP_ALLOW_MULTISITE', true ); -define('MULTISITE', true); -define('SUBDOMAIN_INSTALL', false); -$base = '/'; -define('DOMAIN_CURRENT_SITE', 'example.com'); -//define('DOMAIN_CURRENT_SITE', 'bta.example.com'); -define('PATH_CURRENT_SITE', '/'); -define('SITE_ID_CURRENT_SITE', 1); -define('BLOG_ID_CURRENT_SITE', 1); - -/* That's all, stop editing! Happy blogging. */ - -/** Absolute path to the WordPress directory. */ -if ( !defined('ABSPATH') ) - define('ABSPATH', dirname(__FILE__) . '/'); - -/** Sets up WordPress vars and included files. */ -require_once(ABSPATH . 'wp-settings.php'); + Error: Site example.dev/ not found. """ - When I run `wp option get home` + When I run `wp option get home --url=example.com` Then STDOUT should be: """ http://example.com diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 5a3927f46..87e435b47 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -206,30 +206,6 @@ private static function guess_url( $assoc_args ) { if ( true === $url ) { WP_CLI::warning( 'The --url parameter expects a value.' ); } - } elseif ( $wp_config_path = Utils\locate_wp_config() ) { - // Try to find the blog parameter in the wp-config file - $wp_config_file = file_get_contents( $wp_config_path ); - $hit = array(); - - $re_define = "~(.*)define\s*\(\s*(['|\"]{1})(.+)(['|\"]{1})\s*,\s*(['|\"]{1})(.+)(['|\"]{1})\s*\)\s*;~iU"; - - if ( preg_match_all( $re_define, $wp_config_file, $matches ) ) { - foreach ( $matches[3] as $def_key => $def_name ) { - if ( false !== strpos( $matches[1][$def_key], '#' ) || false !== strpos( $matches[1][$def_key], '//' ) ) { - continue; - } - if ( 'DOMAIN_CURRENT_SITE' == $def_name ) - $hit['domain'] = $matches[6][$def_key]; - if ( 'PATH_CURRENT_SITE' == $def_name ) - $hit['path'] = $matches[6][$def_key]; - } - } - - if ( !empty( $hit ) && isset( $hit['domain'] ) ) { - $url = $hit['domain']; - if ( isset( $hit['path'] ) ) - $url .= $hit['path']; - } } if ( isset( $url ) ) { @@ -728,6 +704,23 @@ private static function fake_current_site_blog( $url_parts ) { ); } + /** + * Called after wp-config.php is eval'd, to potentially reset `--url` + */ + public function maybe_update_url_from_domain_constant() { + if ( ! empty( $this->config['url'] ) || ! empty( $this->config['blog'] ) ) { + return; + } + + if ( defined( 'DOMAIN_CURRENT_SITE' ) ) { + $url = DOMAIN_CURRENT_SITE; + if ( defined( 'PATH_CURRENT_SITE' ) ) { + $url .= PATH_CURRENT_SITE; + } + \WP_CLI::set_url( $url ); + } + } + public function after_wp_load() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); diff --git a/php/wp-cli.php b/php/wp-cli.php index ab8bcf68b..3d1df759a 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -22,6 +22,8 @@ // Load wp-config.php code, in the global scope eval( WP_CLI::get_runner()->get_wp_config_code() ); +WP_CLI::get_runner()->maybe_update_url_from_domain_constant(); + // Load Core, mu-plugins, plugins, themes etc. require WP_CLI_ROOT . '/php/wp-settings-cli.php'; From b151bf82044c4e5ae01d27a08ad49d8477a4fddd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 14:51:12 -0700 Subject: [PATCH 3725/5359] Restore use of `--format` for `user meta (add|update)` --- php/commands/user.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 09eda770f..cb5d35afe 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -830,6 +830,9 @@ public function delete( $args, $assoc_args ) { * * <value> * : The new metadata value. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. */ public function add( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -848,6 +851,9 @@ public function add( $args, $assoc_args ) { * <value> * : The new metadata value. * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * * @alias set */ public function update( $args, $assoc_args ) { From aa951dd14fcbbda606c75c0bfac70ecaa7e28bed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 14:58:11 -0700 Subject: [PATCH 3726/5359] Compatibility with a different error in WP 3.5 --- features/config.feature | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/config.feature b/features/config.feature index 0959c9983..cc22badef 100644 --- a/features/config.feature +++ b/features/config.feature @@ -276,10 +276,7 @@ require_once(ABSPATH . 'wp-settings.php'); """ When I try `wp option get home` - Then STDERR should be: - """ - Error: Site example.dev/ not found. - """ + Then STDERR should not be empty When I run `wp option get home --url=example.com` Then STDOUT should be: From 9f5467bebec8d74ddc40f46f835812a258ac3fe8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 15:24:17 -0700 Subject: [PATCH 3727/5359] Use `--defer-term-counting` to recalculate term count in batch for perf --- php/WP_CLI/CommandWithDBObject.php | 8 ++++++++ php/commands/post.php | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index ef32e3586..b72a648f8 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -71,6 +71,10 @@ protected function _update( $args, $assoc_args, $callback ) { ) ); } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( false ); + } + exit( $status ); } @@ -90,6 +94,10 @@ protected function _delete( $args, $assoc_args, $callback ) { $status = $this->success_or_failure( $r ); } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( false ); + } + exit( $status ); } diff --git a/php/commands/post.php b/php/commands/post.php index 38dd7d2c6..c2bf43b3e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -91,6 +91,9 @@ public function create( $args, $assoc_args ) { * --<field>=<value> * : One or more fields to update. See wp_update_post(). * + * [--defer-term-counting] + * : Recalculate term count in batch, for a performance boost. + * * ## EXAMPLES * * wp post update 123 --post_name=something --post_status=draft @@ -111,6 +114,10 @@ public function update( $args, $assoc_args ) { $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( true ); + } + parent::_update( $args, $assoc_args, function ( $params ) { return wp_update_post( $params, true ); } ); @@ -193,6 +200,9 @@ public function get( $args, $assoc_args ) { * [--force] * : Skip the trash bin. * + * [--defer-term-counting] + * : Recalculate term count in batch, for a performance boost. + * * ## EXAMPLES * * wp post delete 123 --force @@ -208,6 +218,10 @@ public function delete( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( true ); + } + parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { $status = get_post_status( $post_id ); $r = wp_delete_post( $post_id, $assoc_args['force'] ); From 6865afe64cb906a5bcbc0b80b1aae725c3576766 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 15:25:47 -0700 Subject: [PATCH 3728/5359] Move all deferred term counting logic to parent method --- php/WP_CLI/CommandWithDBObject.php | 8 ++++++++ php/commands/post.php | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index b72a648f8..0702956a4 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -62,6 +62,10 @@ protected function _update( $args, $assoc_args, $callback ) { \WP_CLI::error( "Need some fields to update." ); } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( true ); + } + foreach ( $args as $obj_id ) { $params = array_merge( $assoc_args, array( $this->obj_id_key => $obj_id ) ); @@ -89,6 +93,10 @@ protected function _update( $args, $assoc_args, $callback ) { protected function _delete( $args, $assoc_args, $callback ) { $status = 0; + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { + wp_defer_term_counting( true ); + } + foreach ( $args as $obj_id ) { $r = $callback( $obj_id, $assoc_args ); $status = $this->success_or_failure( $r ); diff --git a/php/commands/post.php b/php/commands/post.php index c2bf43b3e..5a5198ce5 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -114,10 +114,6 @@ public function update( $args, $assoc_args ) { $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( true ); - } - parent::_update( $args, $assoc_args, function ( $params ) { return wp_update_post( $params, true ); } ); @@ -218,10 +214,6 @@ public function delete( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( true ); - } - parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { $status = get_post_status( $post_id ); $r = wp_delete_post( $post_id, $assoc_args['force'] ); From 2f4d6695fdec0f9da54684bf5a9825a536099061 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 15:30:34 -0700 Subject: [PATCH 3729/5359] Revert "Compatibility with a different error in WP 3.5" This reverts commit aa951dd14fcbbda606c75c0bfac70ecaa7e28bed. --- features/config.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/config.feature b/features/config.feature index cc22badef..0959c9983 100644 --- a/features/config.feature +++ b/features/config.feature @@ -276,7 +276,10 @@ require_once(ABSPATH . 'wp-settings.php'); """ When I try `wp option get home` - Then STDERR should not be empty + Then STDERR should be: + """ + Error: Site example.dev/ not found. + """ When I run `wp option get home --url=example.com` Then STDOUT should be: From 93d45ddedcc2572e02fbdfec2814a441b6396387 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Sun, 20 Sep 2015 15:31:00 -0700 Subject: [PATCH 3730/5359] Increase minimum requirement for this test --- features/config.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/config.feature b/features/config.feature index 0959c9983..f5d16ad29 100644 --- a/features/config.feature +++ b/features/config.feature @@ -219,6 +219,7 @@ Feature: Have a config file When I run `wp --info` Then STDOUT should not be empty + @require-wp-3.9 Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE Given a WP multisite install And a local-dev.php file: From e184e69844a55701f81bb5068f42653d2b4fa02b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Mon, 21 Sep 2015 06:17:40 -0700 Subject: [PATCH 3731/5359] `--autoload=(yes|no)` support for `update option` --- features/option.feature | 20 ++++++++++++++++++++ php/commands/option.php | 12 ++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/features/option.feature b/features/option.feature index bc23bcf9f..8a44855f3 100644 --- a/features/option.feature +++ b/features/option.feature @@ -120,3 +120,23 @@ Feature: Manage WordPress options "list": [1, 2, 3] } """ + + Scenario: Update autoload value for custom option + Given a WP install + And I run `wp option add hello world --autoload=no` + + When I run `wp option update hello universe` + Then STDOUT should not be empty + + When I run `wp option list --search='hello' --fields=option_name,option_value,autoload` + Then STDOUT should be a table containing rows: + | option_name | option_value | autoload | + | hello | universe | no | + + When I run `wp option update hello island --autoload=yes` + Then STDOUT should not be empty + + When I run `wp option list --search='hello' --fields=option_name,option_value,autoload` + Then STDOUT should be a table containing rows: + | option_name | option_value | autoload | + | hello | island | yes | diff --git a/php/commands/option.php b/php/commands/option.php index 979a53b28..5cfdcd37a 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -187,6 +187,9 @@ public function list_( $args, $assoc_args ) { * [<value>] * : The new value. If ommited, the value is read from STDIN. * + * [--autoload=<autoload>] + * : Should this option be automatically loaded. Accepted values: yes, no. Default: yes + * * [--format=<format>] * : The serialization format for the value. Default is plaintext. * @@ -206,13 +209,18 @@ public function update( $args, $assoc_args ) { $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); $value = WP_CLI::read_value( $value, $assoc_args ); + $autoload = \WP_CLI\Utils\get_flag_value( $assoc_args, 'autoload' ); + if ( ! in_array( $autoload, array( 'yes', 'no' ) ) ) { + $autoload = null; + } + $value = sanitize_option( $key, $value ); $old_value = sanitize_option( $key, get_option( $key ) ); - if ( $value === $old_value ) { + if ( $value === $old_value && is_null( $autoload ) ) { WP_CLI::success( "Value passed for '$key' option is unchanged." ); } else { - if ( update_option( $key, $value ) ) { + if ( update_option( $key, $value, $autoload ) ) { WP_CLI::success( "Updated '$key' option." ); } else { WP_CLI::error( "Could not update option '$key'." ); From e7b71e8c28dc3e572d968a0f1fd83f5a15408383 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Mon, 21 Sep 2015 06:21:16 -0700 Subject: [PATCH 3732/5359] Fix invalid synopsis part for `wp option list` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` salty-wordpress âžœ wordpress-test.dev wp option list --search="apple" Warning: The `wp option list` command has an invalid synopsis part: The Warning: The `wp option list` command has an invalid synopsis part: serialization Warning: The `wp option list` command has an invalid synopsis part: format Warning: The `wp option list` command has an invalid synopsis part: for Warning: The `wp option list` command has an invalid synopsis part: the Warning: The `wp option list` command has an invalid synopsis part: value. Warning: The `wp option list` command has an invalid synopsis part: total_bytes Warning: The `wp option list` command has an invalid synopsis part: displays Warning: The `wp option list` command has an invalid synopsis part: the Warning: The `wp option list` command has an invalid synopsis part: total Warning: The `wp option list` command has an invalid synopsis part: size Warning: The `wp option list` command has an invalid synopsis part: of Warning: The `wp option list` command has an invalid synopsis part: matching Warning: The `wp option list` command has an invalid synopsis part: options Warning: The `wp option list` command has an invalid synopsis part: in Warning: The `wp option list` command has an invalid synopsis part: bytes. ``` --- php/commands/option.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 979a53b28..a4bf9251b 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -94,9 +94,7 @@ public function add( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : The serialization format for the value. - * : total_bytes displays the total size of matching options in bytes. - * : Accepted values: table, json, csv, count, total_bytes. Default: table + * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. Accepted values: table, json, csv, count, total_bytes. Default: table * * ## EXAMPLES * From 4e96b943257b16b98547ca26d247e50f7bc36f5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Mon, 21 Sep 2015 06:45:43 -0700 Subject: [PATCH 3733/5359] `--autoload` requires WP 4.2 --- features/option.feature | 1 + php/commands/option.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/features/option.feature b/features/option.feature index 8a44855f3..cd44b4596 100644 --- a/features/option.feature +++ b/features/option.feature @@ -121,6 +121,7 @@ Feature: Manage WordPress options } """ + @require-wp-4.2 Scenario: Update autoload value for custom option Given a WP install And I run `wp option add hello world --autoload=no` diff --git a/php/commands/option.php b/php/commands/option.php index 5cfdcd37a..9e05f30b5 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -188,7 +188,7 @@ public function list_( $args, $assoc_args ) { * : The new value. If ommited, the value is read from STDIN. * * [--autoload=<autoload>] - * : Should this option be automatically loaded. Accepted values: yes, no. Default: yes + * : Requires WP 4.2. Should this option be automatically loaded. Accepted values: yes, no. Default: yes * * [--format=<format>] * : The serialization format for the value. Default is plaintext. From 05d5553083730ab70f12b0f223da17964acaf26a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 21 Sep 2015 14:24:24 -0700 Subject: [PATCH 3734/5359] Exhaust all possible options when finding PHP binary --- php/class-wp-cli.php | 2 +- php/commands/cli.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index c4255ac68..4f1e64541 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -434,7 +434,7 @@ public static function launch_self( $command, $args = array(), $assoc_args = arr * * @return string */ - private static function get_php_binary() { + public static function get_php_binary() { if ( defined( 'PHP_BINARY' ) ) return PHP_BINARY; diff --git a/php/commands/cli.php b/php/commands/cli.php index 718979abe..ffb83ff89 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -44,7 +44,7 @@ public function version() { * : Accepted values: json */ public function info( $_, $assoc_args ) { - $php_bin = defined( 'PHP_BINARY' ) ? PHP_BINARY : getenv( 'WP_CLI_PHP_USED' ); + $php_bin = WP_CLI::get_php_binary(); $runner = WP_CLI::get_runner(); @@ -186,7 +186,8 @@ public function update( $_, $assoc_args ) { Utils\http_request( 'GET', $download_url, null, $headers, $options ); $allow_root = WP_CLI::get_runner()->config['allow-root'] ? '--allow-root' : ''; - $process = WP_CLI\Process::create( "php $temp --version {$allow_root}" ); + $php_binary = WP_CLI::get_php_binary(); + $process = WP_CLI\Process::create( "{$php_binary} $temp --version {$allow_root}" ); $result = $process->run(); if ( 0 !== $result->return_code ) { $multi_line = explode( PHP_EOL, $result->stderr ); From e664ca96923d3bbf088dff2e66f427ec68e6bf05 Mon Sep 17 00:00:00 2001 From: Hiroshi Urabe <mail@torounit.com> Date: Thu, 24 Sep 2015 18:21:12 +0900 Subject: [PATCH 3735/5359] Use WP_VERSION when checkout wordpress tests. #2050 --- templates/install-wp-tests.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 80ba41649..9cd88e16d 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -14,6 +14,12 @@ WP_VERSION=${5-latest} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} +if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then + WP_TESTS_TAG="tags/$WP_VERSION" +else + WP_TESTS_TAG='trunk' +fi + set -ex download() { @@ -56,13 +62,13 @@ install_test_suite() { if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes fi cd $WP_TESTS_DIR if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php From a5152d73f86bb6e5de07be3b47998999257478ac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 24 Sep 2015 16:52:30 -0700 Subject: [PATCH 3736/5359] Support multiple comment ids for `comment (spam|trash|approve)` et al From https://wordpress.slack.com/archives/cli/p1443138041000281 --- php/commands/comment.php | 48 +++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 38d0bdb12..372a5e428 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -281,15 +281,17 @@ private function set_status( $args, $status, $success ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to trash. + * <id>... + * : The IDs of the comments to trash. * * ## EXAMPLES * * wp comment trash 1337 */ public function trash( $args, $assoc_args ) { - $this->call( $args, __FUNCTION__, 'Trashed', 'Failed trashing' ); + foreach( $args as $id ) { + $this->call( $id, __FUNCTION__, 'Trashed', 'Failed trashing' ); + } } /** @@ -297,15 +299,17 @@ public function trash( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to untrash. + * <id>... + * : The IDs of the comments to untrash. * * ## EXAMPLES * * wp comment untrash 1337 */ public function untrash( $args, $assoc_args ) { - $this->call( $args, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); + foreach( $args as $id ) { + $this->call( $id, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); + } } /** @@ -313,15 +317,17 @@ public function untrash( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to mark as spam. + * <id>... + * : The IDs of the comments to mark as spam. * * ## EXAMPLES * * wp comment spam 1337 */ public function spam( $args, $assoc_args ) { - $this->call( $args, __FUNCTION__, 'Marked as spam', 'Failed marking as spam' ); + foreach( $args as $id ) { + $this->call( $id, __FUNCTION__, 'Marked as spam', 'Failed marking as spam' ); + } } /** @@ -329,15 +335,17 @@ public function spam( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to unmark as spam. + * <id>... + * : The IDs of the comments to unmark as spam. * * ## EXAMPLES * * wp comment unspam 1337 */ public function unspam( $args, $assoc_args ) { - $this->call( $args, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); + foreach( $args as $id ) { + $this->call( $args, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); + } } /** @@ -345,15 +353,17 @@ public function unspam( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to approve. + * <id>... + * : The IDs of the comments to approve. * * ## EXAMPLES * * wp comment approve 1337 */ public function approve( $args, $assoc_args ) { - $this->set_status( $args, 'approve', "Approved" ); + foreach( $args as $id ) { + $this->set_status( $id, 'approve', "Approved" ); + } } /** @@ -361,15 +371,17 @@ public function approve( $args, $assoc_args ) { * * ## OPTIONS * - * <id> - * : The ID of the comment to unapprove. + * <id>... + * : The IDs of the comments to unapprove. * * ## EXAMPLES * * wp comment unapprove 1337 */ public function unapprove( $args, $assoc_args ) { - $this->set_status( $args, 'hold', "Unapproved" ); + foreach( $args as $id ) { + $this->set_status( $id, 'hold', "Unapproved" ); + } } /** From 1028f8a7627de7c5b0fff3802543080be5aee788 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 28 Sep 2015 16:47:36 -0700 Subject: [PATCH 3737/5359] Only run `wp core update-db --network` on active sites --- features/core.feature | 9 +++++++++ php/commands/core.php | 1 + 2 files changed, 10 insertions(+) diff --git a/features/core.feature b/features/core.feature index 4eb71f8eb..29a96bc9c 100644 --- a/features/core.feature +++ b/features/core.feature @@ -293,6 +293,15 @@ Feature: Manage WordPress installation Given a WP multisite install And I run `wp site create --slug=foo` And I run `wp site create --slug=bar` + And I run `wp site create --slug=burrito --porcelain` + And save STDOUT as {BURRITO_ID} + And I run `wp site create --slug=taco --porcelain` + And save STDOUT as {TACO_ID} + And I run `wp site create --slug=pizza --porcelain` + And save STDOUT as {PIZZA_ID} + And I run `wp site archive {BURRITO_ID}` + And I run `wp site spam {TACO_ID}` + And I run `wp site delete {PIZZA_ID} --yes` When I run `wp core update-db --network` Then STDOUT should contain: diff --git a/php/commands/core.php b/php/commands/core.php index 81694a707..892611fa2 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -987,6 +987,7 @@ function update_db( $_, $assoc_args ) { if ( $network ) { $iterator_args = array( 'table' => $wpdb->blogs, + 'where' => array( 'spam' => 0, 'deleted' => 0, 'archived' => 0 ), ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); $success = $total = 0; From d2dfb216bed4fe15ea4ac2da28f89e853f02f873 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Mon, 28 Sep 2015 21:16:03 -0400 Subject: [PATCH 3738/5359] alias update as upgrade --- php/commands/plugin.php | 2 ++ php/commands/theme.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index bb26cd5c4..d266aae99 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -345,6 +345,8 @@ protected function install_from_repo( $slug, $assoc_args ) { * wp plugin update bbpress --version=dev * * wp plugin update --all + * + * @alias upgrade */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { diff --git a/php/commands/theme.php b/php/commands/theme.php index 380a4fadd..59f5fd20e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -463,6 +463,8 @@ public function get( $args, $assoc_args ) { * wp theme update twentyeleven twentytwelve * * wp theme update --all + * + * @alias upgrade */ function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { From e578f4059edd2a01ce566209966b5f448d0814b8 Mon Sep 17 00:00:00 2001 From: Borek Bernard <borekb@gmail.com> Date: Wed, 30 Sep 2015 16:54:56 +0200 Subject: [PATCH 3739/5359] Paginate help output on Windows using `more` --- php/commands/help.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index ec2dcce53..5b2c3cf5e 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -90,11 +90,8 @@ private static function indent( $whitespace, $text ) { } private static function pass_through_pager( $out ) { - if ( Utils\is_windows() ) { - // no paging for Windows cmd.exe; sorry - echo $out; - return 0; - } + + $pager = Utils\is_windows() ? 'more' : 'less -r'; // convert string to file handle $fd = fopen( "php://temp", "r+" ); @@ -107,7 +104,7 @@ private static function pass_through_pager( $out ) { 2 => STDERR ); - return proc_close( proc_open( 'less -r', $descriptorspec, $pipes ) ); + return proc_close( proc_open( $pager, $descriptorspec, $pipes ) ); } private static function get_initial_markdown( $command ) { From ec701315c9001bd9565bf44f70abd09a008d0591 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 2 Oct 2015 13:27:18 -0700 Subject: [PATCH 3740/5359] Clarify expected output for `wp core check-update` [ci-skip] --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 81694a707..30cf9dc5b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -10,7 +10,9 @@ class Core_Command extends WP_CLI_Command { /** - * Check for update via Version Check API. Returns latest version if there's an update, or empty if no update available. + * Check for update via Version Check API. + * + * Lists the most recent versions when there are updates available, or success message when up to date. * * ## OPTIONS * From 0d5c9319532368f41a9e2e7593ef3d599b359fa1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 2 Oct 2015 15:02:48 -0700 Subject: [PATCH 3741/5359] Permit space-delimited IDs for `wp export --post__in` This makes it easier to pass IDs returned by one command into export. --- features/export.feature | 32 ++++++++++++++++++++++++++++++++ php/commands/export.php | 5 +++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/features/export.feature b/features/export.feature index ab8c51b40..cb2720ef6 100644 --- a/features/export.feature +++ b/features/export.feature @@ -161,6 +161,38 @@ Feature: Export content. 1 """ + Scenario: Export multiple posts, separated by spaces + Given a WP install + + When I run `wp plugin install wordpress-importer --activate` + Then STDOUT should contain: + """ + Success: + """ + + When I run `wp post create --post_title='Test post' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp post create --post_title='Test post 2' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID_TWO} + + When I run `wp export --post__in="{POST_ID} {POST_ID_TWO}"` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=post --format=count` + Then STDOUT should be: + """ + 2 + """ + Scenario: Export posts within a given date range Given a WP install diff --git a/php/commands/export.php b/php/commands/export.php index 230548afd..50b077c45 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -40,7 +40,7 @@ class Export_Command extends WP_CLI_Command { * with a comma. Defaults to none. * * [--post__in=<pid>] - * : Export all posts specified as a comma-separated list of IDs. + * : Export all posts specified as a comma- or space-separated list of IDs. * * [--start_id=<pid>] * : Export only posts with IDs greater than or equal to this post ID. @@ -233,7 +233,8 @@ private function check_post__in( $post__in ) { if ( is_null( $post__in ) ) return true; - $post__in = array_unique( array_map( 'intval', explode( ',', $post__in ) ) ); + $separator = false !== stripos( $post__in, ' ' ) ? ' ' : ','; + $post__in = array_unique( array_map( 'intval', explode( $separator, $post__in ) ) ); if ( empty( $post__in ) ) { WP_CLI::warning( "post__in should be comma-separated post IDs" ); return false; From 68bf55ae6a4584d09b3d5e320b6874a59700e577 Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Fri, 2 Oct 2015 16:05:04 -0600 Subject: [PATCH 3742/5359] check if file is writable before copying and don't report success if file isn't copied to current directory --- php/commands/core.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 892611fa2..368e04b14 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -219,6 +219,8 @@ private static function _copy_overwrite_files( $source, $dest ) { new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), RecursiveIteratorIterator::SELF_FIRST); + $error = 0; + foreach ( $iterator as $item ) { if ( $item->isDir() ) { $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); @@ -226,9 +228,18 @@ private static function _copy_overwrite_files( $source, $dest ) { mkdir( $dest_path ); } } else { - copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ); + if ( ! $item->isWritable() ) { + copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ) ) { + } else { + $error = 1; + WP_CLI::warning( 'Unable to copy ' . $iterator->getSubPathName() . ' to current directory.' ); + } } } + + if ( $error ) { + WP_CLI::error( 'There was an error downloading all WordPress files.' ); + } } private static function _rmdir( $dir ) { From 3fb770288a8f44d20bc87220eb64c3db7dfd1ab9 Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Fri, 2 Oct 2015 16:08:27 -0600 Subject: [PATCH 3743/5359] fix garbage I missed from troubleshooting. --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 368e04b14..bf0babc9b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -229,7 +229,7 @@ private static function _copy_overwrite_files( $source, $dest ) { } } else { if ( ! $item->isWritable() ) { - copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ) ) { + copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ); } else { $error = 1; WP_CLI::warning( 'Unable to copy ' . $iterator->getSubPathName() . ' to current directory.' ); From 28f26688944cd00fa1306b4c6a37196d92781520 Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Fri, 2 Oct 2015 16:09:56 -0600 Subject: [PATCH 3744/5359] its friday... remove an erroneous not check --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index bf0babc9b..bf5206876 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -228,7 +228,7 @@ private static function _copy_overwrite_files( $source, $dest ) { mkdir( $dest_path ); } } else { - if ( ! $item->isWritable() ) { + if ( $item->isWritable() ) { copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ); } else { $error = 1; From d0fdb9a789520a4d523059ca1cc7bb4dd5172c01 Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Fri, 2 Oct 2015 16:17:17 -0600 Subject: [PATCH 3745/5359] check the right file for writability --- php/commands/core.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index bf5206876..fe880e464 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -222,14 +222,16 @@ private static function _copy_overwrite_files( $source, $dest ) { $error = 0; foreach ( $iterator as $item ) { + + $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); + if ( $item->isDir() ) { - $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); if ( !is_dir( $dest_path ) ) { mkdir( $dest_path ); } } else { - if ( $item->isWritable() ) { - copy( $item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName() ); + if ( is_writable( $dest_path ) ) { + copy( $item, $dest_path ); } else { $error = 1; WP_CLI::warning( 'Unable to copy ' . $iterator->getSubPathName() . ' to current directory.' ); From 786628eda71c5b874579aabc72e54c71a0cd760a Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Fri, 2 Oct 2015 16:40:11 -0600 Subject: [PATCH 3746/5359] check if file exists and is writable. files that don't exist aren't writable --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index fe880e464..aff297f7b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -230,7 +230,9 @@ private static function _copy_overwrite_files( $source, $dest ) { mkdir( $dest_path ); } } else { - if ( is_writable( $dest_path ) ) { + if ( file_exists( $dest_path ) && is_writable( $dest_path ) ) { + copy( $item, $dest_path ); + } elseif ( ! file_exists( $dest_path ) ) { copy( $item, $dest_path ); } else { $error = 1; From f3ad656ee73dadd8e89d2e2cc54b8fd9b747ce0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 5 Oct 2015 15:38:17 +0200 Subject: [PATCH 3747/5359] Added syntax highlight --- CONTRIBUTING.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 001b2400e..4063c7592 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,9 @@ The unit test files are in the `tests/` directory. To run the unit tests, just execute: - ./vendor/bin/phpunit +```bash +./vendor/bin/phpunit +``` ### Functional tests @@ -48,15 +50,21 @@ The functional test files are in the `features/` directory. Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: - GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; +```sql +GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; +``` Then, to run the entire test suite: - ./vendor/bin/behat --expand +```bash +./vendor/bin/behat --expand +``` Or to test a single feature: - ./vendor/bin/behat features/core.feature +```bash +./vendor/bin/behat features/core.feature +``` More info can be found by using `./vendor/bin/behat --help`. From c60adb7f777183eb390f368eeb0b7c81eae458ab Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 5 Oct 2015 23:34:35 -0300 Subject: [PATCH 3748/5359] add `wp taxonomy list` command --- features/taxonomy.feature | 16 +++++++++ php/commands/taxonomy.php | 71 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 features/taxonomy.feature create mode 100644 php/commands/taxonomy.php diff --git a/features/taxonomy.feature b/features/taxonomy.feature new file mode 100644 index 000000000..ece9b7327 --- /dev/null +++ b/features/taxonomy.feature @@ -0,0 +1,16 @@ +Feature: Manage WordPress taxonomies + + Background: + Given a WP install + + Scenario: Listing taxonomies + When I run `wp taxonomy list --format=csv` + Then STDOUT should be CSV containing: + | name | label | description | public | hierarchical | + | category | Categories | | 1 | 1 | + | post_tag | Tags | | 1 | | + + When I run `wp taxonomy list --object_type=link --format=csv` + Then STDOUT should be CSV containing: + | name | label | description | public | hierarchical | + | link_category | Link Categories | | | | diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php new file mode 100644 index 000000000..aef6c17a1 --- /dev/null +++ b/php/commands/taxonomy.php @@ -0,0 +1,71 @@ +<?php +/** + * Manage taxonomies. + * + * @package wp-cli + */ +class Taxonomy_Command extends WP_CLI_Command { + + private $fields = array( + 'name', + 'label', + 'description', + 'public', + 'hierarchical' + ); + + /** + * List taxonomies. + * + * ## OPTIONS + * + * [--<field>=<value>] + * : Filter by one or more fields (see get_taxonomies() first parameter for a list of available fields). + * + * [--field=<field>] + * : Prints the value of a single field for each taxonomy. + * + * [--fields=<fields>] + * : Limit the output to specific taxonomy fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each term: + * + * * name + * * label + * * description + * * public + * * hierarchical + * + * There are no optionally available fields. + * + * ## EXAMPLES + * + * wp taxonomy list --format=csv + * + * wp taxonomy list --object-type=post --fields=name,public + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); + + if ( isset( $assoc_args['object_type'] ) ) { + $assoc_args['object_type'] = array( $assoc_args['object_type'] ); + } + + $taxonomies = get_taxonomies( $assoc_args, 'objects' ); + + $formatter->display_items( $taxonomies ); + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'taxonomy' ); + } +} + +WP_CLI::add_command( 'taxonomy', 'Taxonomy_Command' ); From 47aa5229c8b860849a2f0d9a054008891874be53 Mon Sep 17 00:00:00 2001 From: Brandon Kraft <public@brandonkraft.com> Date: Tue, 6 Oct 2015 16:08:59 -0500 Subject: [PATCH 3749/5359] Include new WP file https://core.trac.wordpress.org/changeset/34851 added WPINC/embed-functions.php This'll work for the build svn repo. Develop will need a version bump. --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index a72c3d50d..24c376a1a 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -168,6 +168,7 @@ require( ABSPATH . WPINC . '/shortcodes.php' ); Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); +Utils\maybe_require( '4.4-alpha-34851', ABSPATH . WPINC . '/embed-functions.php' ); require( ABSPATH . WPINC . '/http.php' ); require_once( ABSPATH . WPINC . '/class-http.php' ); require( ABSPATH . WPINC . '/widgets.php' ); From ef2f66ecc12c5c4a87a7fd741c67c63ae20eefc4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Oct 2015 06:24:06 -0700 Subject: [PATCH 3750/5359] Load WordPress with `WP_CLI\Runner::load_wordpress()` This also lets other commands running before WordPress loads to load WordPress on their own. --- features/framework.feature | 34 ++++++++++++++++++++++ php/WP_CLI/Runner.php | 58 ++++++++++++++++++++++++++++++-------- php/wp-cli.php | 19 +------------ 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/features/framework.feature b/features/framework.feature index 438471e25..6a1e370ce 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -13,3 +13,37 @@ Feature: Load WP-CLI When I run `wp option get home` Then STDOUT should not be empty + + Scenario: A command loaded before WordPress then calls WordPress to load + Given a WP install + And a custom-cmd.php file: + """ + <?php + class Load_WordPress_Command_Class extends WP_CLI_Command { + + /** + * @when before_wp_load + */ + public function __invoke() { + if ( ! function_exists( 'update_option' ) ) { + WP_CLI::log( 'WordPress not loaded.' ); + } + WP_CLI::get_runner()->load_wordpress(); + if ( function_exists( 'update_option' ) ) { + WP_CLI::log( 'WordPress loaded!' ); + } + WP_CLI::get_runner()->load_wordpress(); + WP_CLI::log( 'load_wordpress() can safely be called twice.' ); + } + + } + WP_CLI::add_command( 'load-wordpress', 'Load_WordPress_Command_Class' ); + """ + + When I run `wp --require=custom-cmd.php load-wordpress` + Then STDOUT should be: + """ + WordPress not loaded. + WordPress loaded! + load_wordpress() can safely be called twice. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 87e435b47..9aa22e949 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -562,7 +562,7 @@ private function check_root() { ); } - public function before_wp_load() { + public function start() { $this->init_config(); $this->init_colorization(); $this->init_logger(); @@ -672,6 +672,50 @@ public function before_wp_load() { if ( $this->cmd_starts_with( array( 'plugin' ) ) ) { $GLOBALS['pagenow'] = 'plugins.php'; } + + $this->load_wordpress(); + + $this->_run_command(); + + } + + /** + * Load WordPress, if it hasn't already been loaded + */ + public function load_wordpress() { + static $wp_cli_is_loaded; + // Globals not explicitly globalized in WordPress + global $wpdb, $wp, $wp_rewrite, $wp_version, $wp_db_version, + $current_site, $current_blog, $tinymce_version, $required_php_version, + $shortcode_tags, $required_mysql_version, $wp_local_package; + + if ( ! empty( $wp_cli_is_loaded ) ) { + return; + } + + $wp_cli_is_loaded = true; + + // Load wp-config.php code, in the global scope + eval( $this->get_wp_config_code() ); + + $this->maybe_update_url_from_domain_constant(); + + // Load Core, mu-plugins, plugins, themes etc. + require WP_CLI_ROOT . '/php/wp-settings-cli.php'; + + // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 + @ini_set( 'memory_limit', -1 ); + + // Load all the admin APIs, for convenience + require ABSPATH . 'wp-admin/includes/admin.php'; + + add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); + + // Handle --user parameter + if ( ! defined( 'WP_INSTALLING' ) ) { + self::set_user( $this->config ); + } + } private static function fake_current_site_blog( $url_parts ) { @@ -707,7 +751,7 @@ private static function fake_current_site_blog( $url_parts ) { /** * Called after wp-config.php is eval'd, to potentially reset `--url` */ - public function maybe_update_url_from_domain_constant() { + private function maybe_update_url_from_domain_constant() { if ( ! empty( $this->config['url'] ) || ! empty( $this->config['blog'] ) ) { return; } @@ -721,15 +765,5 @@ public function maybe_update_url_from_domain_constant() { } } - public function after_wp_load() { - add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - - // Handle --user parameter - if ( ! defined( 'WP_INSTALLING' ) ) { - self::set_user( $this->config ); - } - - $this->_run_command(); - } } diff --git a/php/wp-cli.php b/php/wp-cli.php index 3d1df759a..0d0e499e6 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -17,21 +17,4 @@ \WP_CLI\Utils\load_dependencies(); -WP_CLI::get_runner()->before_wp_load(); - -// Load wp-config.php code, in the global scope -eval( WP_CLI::get_runner()->get_wp_config_code() ); - -WP_CLI::get_runner()->maybe_update_url_from_domain_constant(); - -// Load Core, mu-plugins, plugins, themes etc. -require WP_CLI_ROOT . '/php/wp-settings-cli.php'; - -// Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 -@ini_set( 'memory_limit', -1 ); - -// Load all the admin APIs, for convenience -require ABSPATH . 'wp-admin/includes/admin.php'; - -WP_CLI::get_runner()->after_wp_load(); - +WP_CLI::get_runner()->start(); From 742e11d669ca21b7bc8a92a620d2911d9a65063e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Oct 2015 06:47:48 -0700 Subject: [PATCH 3751/5359] Globalize as core now does in `wp-settings.php` --- php/WP_CLI/Runner.php | 4 +--- php/wp-settings-cli.php | 15 +++++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9aa22e949..95dc29aaa 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -685,9 +685,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $wpdb, $wp, $wp_rewrite, $wp_version, $wp_db_version, - $current_site, $current_blog, $tinymce_version, $required_php_version, - $shortcode_tags, $required_mysql_version, $wp_local_package; + global $current_site, $current_blog, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index a72c3d50d..deb51f1af 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -15,6 +15,13 @@ // Include files required for initialization. require( ABSPATH . WPINC . '/load.php' ); require( ABSPATH . WPINC . '/default-constants.php' ); + +/* + * These can't be directly globalized in version.php. When updating, + * we're including version.php from another install and don't want + * these values to be overridden if already set. + */ +global $wp_version, $wp_db_version, $tinymce_version, $required_php_version, $required_mysql_version; require( ABSPATH . WPINC . '/version.php' ); // Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE. @@ -271,7 +278,7 @@ function wp_is_mobile() { * @global object $wp_the_query * @since 2.0.0 */ -$wp_the_query = new WP_Query(); +$GLOBALS['wp_the_query'] = new WP_Query(); /** * Holds the reference to @see $wp_the_query @@ -279,7 +286,7 @@ function wp_is_mobile() { * @global object $wp_query * @since 1.5.0 */ -$wp_query = $wp_the_query; +$GLOBALS['wp_query'] = $wp_the_query; /** * Holds the WordPress Rewrite object for creating pretty URLs @@ -293,7 +300,7 @@ function wp_is_mobile() { * @global object $wp * @since 2.0.0 */ -$wp = new WP(); +$GLOBALS['wp'] = new WP(); /** * WordPress Widget Factory Object @@ -347,7 +354,7 @@ function wp_is_mobile() { do_action( 'after_setup_theme' ); // Set up current user. -$wp->init(); +$GLOBALS['wp']->init(); /** * Most of WP is loaded at this stage, and the user is authenticated. WP continues From 36001b73a7eaa650766bc93c04d8142490bcd9b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Oct 2015 07:00:34 -0700 Subject: [PATCH 3752/5359] Use global version of the variable because it doesn't exist in local scope --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index deb51f1af..5fe61d7c0 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -286,7 +286,7 @@ function wp_is_mobile() { * @global object $wp_query * @since 1.5.0 */ -$GLOBALS['wp_query'] = $wp_the_query; +$GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; /** * Holds the WordPress Rewrite object for creating pretty URLs From fe642e4d26fe3452b7f558ad1a16f329f8151123 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Oct 2015 09:08:11 -0700 Subject: [PATCH 3753/5359] Check for version and wp-config.php inside of `Runner::load_wordpress()` Because commands can call this method directly, we want to make sure everything is set up as expected. --- features/framework.feature | 36 ++++++++++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 8 ++++++++ 2 files changed, 44 insertions(+) diff --git a/features/framework.feature b/features/framework.feature index 6a1e370ce..ea69fcc5f 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -47,3 +47,39 @@ Feature: Load WP-CLI WordPress loaded! load_wordpress() can safely be called twice. """ + + Scenario: A command loaded before WordPress then calls WordPress to load, but WP doesn't exist + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Load_WordPress_Command_Class extends WP_CLI_Command { + + /** + * @when before_wp_load + */ + public function __invoke() { + if ( ! function_exists( 'update_option' ) ) { + WP_CLI::log( 'WordPress not loaded.' ); + } + WP_CLI::get_runner()->load_wordpress(); + if ( function_exists( 'update_option' ) ) { + WP_CLI::log( 'WordPress loaded!' ); + } + WP_CLI::get_runner()->load_wordpress(); + WP_CLI::log( 'load_wordpress() can safely be called twice.' ); + } + + } + WP_CLI::add_command( 'load-wordpress', 'Load_WordPress_Command_Class' ); + """ + + When I try `wp --require=custom-cmd.php load-wordpress` + Then STDOUT should be: + """ + WordPress not loaded. + """ + And STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 95dc29aaa..f106ca68d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -693,6 +693,14 @@ public function load_wordpress() { $wp_cli_is_loaded = true; + $this->check_wp_version(); + + if ( !Utils\locate_wp_config() ) { + WP_CLI::error( + "wp-config.php not found.\n" . + "Either create one manually or use `wp core config`." ); + } + // Load wp-config.php code, in the global scope eval( $this->get_wp_config_code() ); From 095773b6ae125675ad16e56eed54251c87c132ae Mon Sep 17 00:00:00 2001 From: Robin Schneider <ypid@riseup.net> Date: Thu, 8 Oct 2015 00:15:16 +0200 Subject: [PATCH 3754/5359] Support MariaDB client library. When mariadb-client is already installed on a system, installing wpcli currently requires to remove mariadb-client because mariadb-client and mysql-client are in conflict. --- utils/wp-cli-updatedeb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index fe40b73e4..955829564 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -31,7 +31,7 @@ Architecture: all Maintainer: Daniel Bachhuber <daniel@handbuilt.co> Section: php Priority: optional -Depends: php5-cli, php5-mysql | php5-mysqlnd, mysql-client +Depends: php5-cli, php5-mysql | php5-mysqlnd, mysql-client | mariadb-client Homepage: http://wp-cli.org/ Description: wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite From b6c7eeff9736c6e54ac2942507247648ddd51494 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 7 Oct 2015 16:05:33 -0700 Subject: [PATCH 3755/5359] Remove string match on upgradeable list search Every time WordPress.org changes their algorithm, this breaks. I'd rather not keep fixing it. --- features/upgradables.feature | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index bc1576597..49c40a05f 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -174,9 +174,6 @@ Feature: Manage WordPress themes and plugins """ Showing 2 of """ - And STDOUT should end with a table containing rows: - | name | slug | - | <item_title> | <item> | Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | From 4cbdef7870595680b2bd4dbc7fd8186fea57f527 Mon Sep 17 00:00:00 2001 From: Ryan McCue <me@ryanmccue.info> Date: Thu, 8 Oct 2015 12:47:24 +1000 Subject: [PATCH 3756/5359] Load the REST API in wp-settings --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 50d216ae2..38f08aba5 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -182,6 +182,7 @@ require( ABSPATH . WPINC . '/nav-menu.php' ); require( ABSPATH . WPINC . '/nav-menu-template.php' ); require( ABSPATH . WPINC . '/admin-bar.php' ); +Utils\maybe_require( '4.4-alpha-34928', ABSPATH . WPINC . '/rest-api.php' ); // Load multisite-specific files. if ( is_multisite() ) { From 36e41f1a7cfb8fc89fb3f70974cd5af17af1860a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 8 Oct 2015 07:40:37 -0700 Subject: [PATCH 3757/5359] `eval` or `eval-file` without WordPress via `--skip-wordpress` --- features/eval.feature | 35 +++++++++++++++++++++++++++++++++++ php/commands/eval-file.php | 13 +++++++++++-- php/commands/eval.php | 12 +++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/features/eval.feature b/features/eval.feature index 1e3e2bdf0..b78a5ad6c 100644 --- a/features/eval.feature +++ b/features/eval.feature @@ -20,3 +20,38 @@ Feature: Evaluating PHP code and files. """ foo bar """ + + Scenario: Eval without WordPress install + Given an empty directory + + When I try `wp eval 'var_dump(defined("WP_CONTENT_DIR"));'` + Then STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ + + When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));' --skip-wordpress` + Then STDOUT should be: + """ + bool(false) + """ + + Scenario: Eval file without WordPress install + Given an empty directory + And a script.php file: + """ + <?php + var_dump(defined("WP_CONTENT_DIR")); + """ + + When I try `wp eval-file script.php` + Then STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ + + When I run `wp eval-file script.php --skip-wordpress` + Then STDOUT should be: + """ + bool(false) + """ diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php index 92798f544..d42391c93 100644 --- a/php/commands/eval-file.php +++ b/php/commands/eval-file.php @@ -3,7 +3,7 @@ class EvalFile_Command extends WP_CLI_Command { /** - * Load and execute a PHP file after loading WordPress. + * Load and execute a PHP file. * * ## OPTIONS * @@ -13,17 +13,26 @@ class EvalFile_Command extends WP_CLI_Command { * [<arg>...] * : One or more arguments to pass to the file. They are placed in the $args variable. * + * [--skip-wordpress] + * : Load and execute file without loading WordPress. + * + * @when before_wp_load + * * ## EXAMPLES * * wp eval-file my-code.php value1 value2 */ - public function __invoke( $args ) { + public function __invoke( $args, $assoc_args ) { $file = array_shift( $args ); if ( !file_exists( $file ) ) { WP_CLI::error( "'$file' does not exist." ); } + if ( null === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-wordpress' ) ) { + WP_CLI::get_runner()->load_wordpress(); + } + self::_eval( $file, $args ); } diff --git a/php/commands/eval.php b/php/commands/eval.php index cce2ca4b2..f81a626da 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -3,16 +3,26 @@ class Eval_Command extends WP_CLI_Command { /** - * Execute arbitrary PHP code after loading WordPress. + * Execute arbitrary PHP code. * * <php-code> * : The code to execute, as a string. * + * [--skip-wordpress] + * : Execute code without loading WordPress. + * + * @when before_wp_load + * * ## EXAMPLES * * wp eval 'echo WP_CONTENT_DIR;' */ public function __invoke( $args, $assoc_args ) { + + if ( null === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-wordpress' ) ) { + WP_CLI::get_runner()->load_wordpress(); + } + eval( $args[0] ); } } From 1624d1294b35c64ee90fc24734f7a32033077e16 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 8 Oct 2015 09:06:54 -0700 Subject: [PATCH 3758/5359] Globalize `$blog_id` before loading WordPress Without `$blog_id` globalized, users with persistent object cache drop-ins experience cache pollution. ``` vagrant@vip:/srv/www$ wp option get home http://vip.local vagrant@vip:/srv/www$ sudo service memcached restart Restarting memcached: memcached. vagrant@vip:/srv/www$ wp option get home http://vip.local/fusion vagrant@vip:/srv/www$ wp option get home --url=vip.local http://vip.local/fusion vagrant@vip:/srv/www$ sudo service memcached restart Restarting memcached: memcached. vagrant@vip:/srv/www$ wp option get home --url=vip.local http://vip.local ``` Somewhere, there's usage of `$blog_id` in WordPress that should be explicitly globalized, but isn't. --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index f106ca68d..3785c6c62 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -685,7 +685,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $current_site, $current_blog, $shortcode_tags; + global $blog_id, $current_site, $current_blog, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; From b728d757e0e38e0073262c7237f44ab781b02006 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel.bachhuber@fusion.net> Date: Thu, 8 Oct 2015 09:45:04 -0700 Subject: [PATCH 3759/5359] More core variables that need to be explicitly globalized Props @jeremyfelt --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3785c6c62..a196c1cc4 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -685,7 +685,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $blog_id, $current_site, $current_blog, $shortcode_tags; + global $blog_id, $site_id, $public, $current_site, $current_blog, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; From 92dac0f1b95d248ac11ddee095911557005547eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Fri, 9 Oct 2015 05:51:53 -0700 Subject: [PATCH 3760/5359] Use proper tests checkout for WP_VERSION=latest --- templates/install-wp-tests.sh | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 9cd88e16d..0aaf09f3c 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -14,14 +14,6 @@ WP_VERSION=${5-latest} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} -if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then - WP_TESTS_TAG="tags/$WP_VERSION" -else - WP_TESTS_TAG='trunk' -fi - -set -ex - download() { if [ `which curl` ]; then curl -s "$1" > "$2"; @@ -30,6 +22,22 @@ download() { fi } +if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then + WP_TESTS_TAG="tags/$WP_VERSION" +else + # http serves a single offer, whereas https serves multiple. we only want one + download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json + grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json + LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') + if [[ -z "$LATEST_VERSION" ]]; then + echo "Latest WordPress version could not be found" + exit 1 + fi + WP_TESTS_TAG="tags/$LATEST_VERSION" +fi + +set -ex + install_wp() { if [ -d $WP_CORE_DIR ]; then From 3f2aa3771667c13f327661b1e12a26f8127ebcfc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 07:22:35 -0700 Subject: [PATCH 3761/5359] Globalize `$blog_id` as core does See https://core.trac.wordpress.org/changeset/34961 --- php/WP_CLI/Runner.php | 2 +- php/wp-settings-cli.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a196c1cc4..13d29a036 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -685,7 +685,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $blog_id, $site_id, $public, $current_site, $current_blog, $shortcode_tags; + global $site_id, $public, $current_site, $current_blog, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 38f08aba5..caaebf4fc 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -24,6 +24,15 @@ global $wp_version, $wp_db_version, $tinymce_version, $required_php_version, $required_mysql_version; require( ABSPATH . WPINC . '/version.php' ); +/** + * If not already configured, `$blog_id` will default to 1 in a single site + * configuration. In multisite, it will be overridden by default in ms-settings.php. + * + * @global int $blog_id + * @since 2.0.0 + */ +global $blog_id; + // Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE. wp_initial_constants(); From 0ab7662046fd3d958f1caf53a11e8686c5cd02d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 08:22:05 -0700 Subject: [PATCH 3762/5359] Use `--debug` for more verbosity during WP-CLI bootstrap process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` salty-wordpress âžœ wordpress-test.dev wp option get home --debug Debug: Using default global config: /home/vagrant/.wp-cli/config.yml (0.057s) Debug: Using project config: /srv/www/wordpress-test.dev/wp-cli.yml (0.061s) Debug: Required file from config: /srv/www/wp-rest-cli/wp-rest-cli.php (0.144s) Debug: ABSPATH defined: /srv/www/wordpress-test.dev/ (0.145s) Debug: Begin WordPress load (0.148s) Debug: wp-config.php path: /srv/www/wordpress-test.dev/wp-config.php (0.15s) Debug: Set URL: wordpress-test.dev/ (0.152s) Debug: Loaded WordPress (0.925s) http://wordpress-test.dev ``` --- features/config.feature | 25 ++++++++++++++++ php/WP_CLI/Loggers/Quiet.php | 12 ++++++++ php/WP_CLI/Loggers/Regular.php | 12 ++++++++ php/WP_CLI/Runner.php | 53 +++++++++++++++++++++++++--------- php/class-wp-cli.php | 10 +++++++ php/config-spec.php | 2 +- php/wp-cli.php | 1 + 7 files changed, 101 insertions(+), 14 deletions(-) diff --git a/features/config.feature b/features/config.feature index f5d16ad29..729140a04 100644 --- a/features/config.feature +++ b/features/config.feature @@ -199,6 +199,31 @@ Feature: Have a config file When I run `WP_CLI_CONFIG_PATH=test-dir/config.yml wp help` Then STDERR should be empty + Scenario: Load WordPress with `--debug` + Given a WP install + + When I run `wp option get home --debug` + Then STDERR should contain: + """ + No readable global config found + """ + Then STDERR should contain: + """ + No project config found + """ + And STDERR should contain: + """ + Begin WordPress load + """ + And STDERR should contain: + """ + wp-config.php path: + """ + And STDERR should contain: + """ + Loaded WordPress + """ + Scenario: Missing required files should not fatal WP-CLI Given an empty directory And a wp-cli.yml file: diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index f1140f858..130c2ff9b 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -25,6 +25,18 @@ public function success( $message ) { // nothing } + /** + * Write a message to STDERR, prefixed with "Debug: ". + * + * @param string $message Message to write. + */ + public function debug( $message ) { + if ( \WP_CLI::get_runner()->config['debug'] ) { + $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); + $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); + } + } + /** * Warning messages aren't logged. * diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index d5358dee6..20eb869b2 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -55,6 +55,18 @@ public function success( $message ) { $this->_line( $message, 'Success', '%G' ); } + /** + * Write a message to STDERR, prefixed with "Debug: ". + * + * @param string $message Message to write. + */ + public function debug( $message ) { + if ( \WP_CLI::get_runner()->config['debug'] ) { + $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); + $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); + } + } + /** * Write a warning message to STDERR, prefixed with "Warning: ". * diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a196c1cc4..3672545c8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -21,6 +21,10 @@ class Runner { private $_early_invoke = array(); + private $_global_config_path_debug; + + private $_project_config_path_debug; + public function __get( $key ) { if ( '_' === $key[0] ) return null; @@ -60,20 +64,25 @@ private function do_early_invoke( $when ) { * * @return string|false */ - private static function get_global_config_path() { - $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + private function get_global_config_path() { + if ( isset( $runtime_config['config'] ) ) { $config_path = $runtime_config['config']; - } - - if ( !$config_path ) { + $this->_global_config_path_debug = 'Using global config from config runtime arg: ' . $config_path; + } else if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { + $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + $this->_global_config_path_debug = 'Using global config from WP_CLI_CONFIG_PATH env var: ' . $config_path; + } else { $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; + $this->_global_config_path_debug = 'Using default global config: ' . $config_path; } - if ( !is_readable( $config_path ) ) + if ( is_readable( $config_path ) ) { + return $config_path; + } else { + $this->_global_config_path_debug = 'No readable global config found'; return false; - - return $config_path; + } } /** @@ -83,7 +92,7 @@ private static function get_global_config_path() { * * @return string|false */ - private static function get_project_config_path() { + private function get_project_config_path() { $config_files = array( 'wp-cli.local.yml', 'wp-cli.yml' @@ -91,7 +100,7 @@ private static function get_project_config_path() { // Stop looking upward when we find we have emerged from a subdirectory // install into a parent install - return Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { + $project_config_path = Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { static $wp_load_count = 0; $wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php'; if ( file_exists( $wp_load_path ) ) { @@ -99,6 +108,12 @@ private static function get_project_config_path() { } return $wp_load_count > 1; } ); + if ( ! empty( $project_config_path ) ) { + $this->_project_config_path_debug = 'Using project config: ' . $project_config_path; + } else { + $this->_project_config_path_debug = 'No project config found'; + } + return $project_config_path; } /** @@ -171,6 +186,7 @@ private function find_wp_root() { */ private static function set_wp_root( $path ) { define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); + WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH ); $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); } @@ -514,8 +530,8 @@ private function init_config() { // File config { - $this->global_config_path = self::get_global_config_path(); - $this->project_config_path = self::get_project_config_path(); + $this->global_config_path = $this->get_global_config_path(); + $this->project_config_path = $this->get_project_config_path(); $configurator->merge_yml( $this->global_config_path ); $configurator->merge_yml( $this->project_config_path ); @@ -567,6 +583,9 @@ public function start() { $this->init_colorization(); $this->init_logger(); + WP_CLI::debug( $this->_global_config_path_debug ); + WP_CLI::debug( $this->_project_config_path_debug ); + $this->check_root(); if ( empty( $this->arguments ) ) @@ -588,6 +607,7 @@ public function start() { WP_CLI::error( sprintf( "Required file '%s' doesn't exist", basename( $path ) ) ); } Utils\load_file( $path ); + WP_CLI::debug( 'Required file from config: ' . $path ); } } @@ -693,14 +713,19 @@ public function load_wordpress() { $wp_cli_is_loaded = true; + WP_CLI::debug( 'Begin WordPress load' ); + $this->check_wp_version(); - if ( !Utils\locate_wp_config() ) { + $wp_config_path = Utils\locate_wp_config(); + if ( ! $wp_config_path ) { WP_CLI::error( "wp-config.php not found.\n" . "Either create one manually or use `wp core config`." ); } + WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path ); + // Load wp-config.php code, in the global scope eval( $this->get_wp_config_code() ); @@ -722,6 +747,8 @@ public function load_wordpress() { self::set_user( $this->config ); } + WP_CLI::debug( 'Loaded WordPress' ); + } private static function fake_current_site_blog( $url_parts ) { diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4f1e64541..74839ceef 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -93,6 +93,7 @@ public static function get_cache() { * Set the context in which WP-CLI should be run */ public static function set_url( $url ) { + WP_CLI::debug( 'Set URL: ' . $url ); $url_parts = Utils\parse_url( $url ); self::set_url_params( $url_parts ); } @@ -236,6 +237,15 @@ public static function success( $message ) { self::$logger->success( $message ); } + /** + * Log debug information + * + * @param string $message + */ + public static function debug( $message ) { + self::$logger->debug( self::error_to_string( $message ) ); + } + /** * Display a warning in the CLI and end with a newline * diff --git a/php/config-spec.php b/php/config-spec.php index 501a806b6..4e6622b0e 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -67,7 +67,7 @@ 'runtime' => '', 'file' => '<bool>', 'default' => false, - 'desc' => 'Show all PHP errors', + 'desc' => 'Show all PHP errors; add verbosity to WP-CLI bootstrap', ), 'prompt' => array( diff --git a/php/wp-cli.php b/php/wp-cli.php index 0d0e499e6..7aa32bb46 100644 --- a/php/wp-cli.php +++ b/php/wp-cli.php @@ -3,6 +3,7 @@ // Can be used by plugins/themes to check if WP-CLI is running or not define( 'WP_CLI', true ); define( 'WP_CLI_VERSION', trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ) ); +define( 'WP_CLI_START_MICROTIME', microtime( true ) ); // Set common headers, to prevent warnings from plugins $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; From eaddd49dc72ff9f3bc9818dc87bd126e973f94b3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 08:28:51 -0700 Subject: [PATCH 3763/5359] Abstract common methods to a base logger class --- php/WP_CLI/Loggers/Base.php | 51 ++++++++++++++++++++++++++++++++++ php/WP_CLI/Loggers/Quiet.php | 20 +++---------- php/WP_CLI/Loggers/Regular.php | 37 +----------------------- 3 files changed, 56 insertions(+), 52 deletions(-) create mode 100644 php/WP_CLI/Loggers/Base.php diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php new file mode 100644 index 000000000..ef6fab196 --- /dev/null +++ b/php/WP_CLI/Loggers/Base.php @@ -0,0 +1,51 @@ +<?php + +namespace WP_CLI\Loggers; + +/** + * Base logger class + */ +abstract class Base { + + abstract public function info( $message ); + + abstract public function success( $message ); + + abstract public function warning( $message ); + + /** + * Write a message to STDERR, prefixed with "Debug: ". + * + * @param string $message Message to write. + */ + public function debug( $message ) { + if ( \WP_CLI::get_runner()->config['debug'] ) { + $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); + $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); + } + } + + /** + * Write a string to a resource. + * + * @param resource $handle Commonly STDOUT or STDERR. + * @param string $str Message to write. + */ + protected function write( $handle, $str ) { + fwrite( $handle, $str ); + } + + /** + * Output one line of message to a resource. + * + * @param string $message Message to write. + * @param string $label Prefix message with a label. + * @param string $color Colorize label with a given color. + * @param resource $handle Resource to write to. Defaults to STDOUT. + */ + protected function _line( $message, $label, $color, $handle = STDOUT ) { + $label = \cli\Colors::colorize( "$color$label:%n", $this->in_color ); + $this->write( $handle, "$label $message\n" ); + } + +} diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php index 130c2ff9b..e8de7be82 100644 --- a/php/WP_CLI/Loggers/Quiet.php +++ b/php/WP_CLI/Loggers/Quiet.php @@ -5,7 +5,7 @@ /** * Quiet logger only logs errors. */ -class Quiet { +class Quiet extends Base { /** * Informational messages aren't logged. @@ -25,18 +25,6 @@ public function success( $message ) { // nothing } - /** - * Write a message to STDERR, prefixed with "Debug: ". - * - * @param string $message Message to write. - */ - public function debug( $message ) { - if ( \WP_CLI::get_runner()->config['debug'] ) { - $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); - $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); - } - } - /** * Warning messages aren't logged. * @@ -52,7 +40,7 @@ public function warning( $message ) { * @param string $message Message to write. */ public function error( $message ) { - fwrite( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); + $this->write( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); } /** @@ -63,7 +51,7 @@ public function error( $message ) { public function error_multi_line( $message_lines ) { $message = implode( "\n", $message_lines ); - fwrite( STDERR, \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); - fwrite( STDERR, \WP_CLI::colorize( "%R---------%n\n\n" ) ); + $this->write( STDERR, \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); + $this->write( STDERR, \WP_CLI::colorize( "%R---------%n\n\n" ) ); } } diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php index 20eb869b2..eeb392047 100644 --- a/php/WP_CLI/Loggers/Regular.php +++ b/php/WP_CLI/Loggers/Regular.php @@ -5,7 +5,7 @@ /** * Default logger for success, warning, error, and standard messages. */ -class Regular { +class Regular extends Base { /** * @param bool $in_color Whether or not to Colorize strings. @@ -14,29 +14,6 @@ function __construct( $in_color ) { $this->in_color = $in_color; } - /** - * Write a string to a resource. - * - * @param resource $handle Commonly STDOUT or STDERR. - * @param string $str Message to write. - */ - protected function write( $handle, $str ) { - fwrite( $handle, $str ); - } - - /** - * Output one line of message to a resource. - * - * @param string $message Message to write. - * @param string $label Prefix message with a label. - * @param string $color Colorize label with a given color. - * @param resource $handle Resource to write to. Defaults to STDOUT. - */ - private function _line( $message, $label, $color, $handle = STDOUT ) { - $label = \cli\Colors::colorize( "$color$label:%n", $this->in_color ); - $this->write( $handle, "$label $message\n" ); - } - /** * Write an informational message to STDOUT. * @@ -55,18 +32,6 @@ public function success( $message ) { $this->_line( $message, 'Success', '%G' ); } - /** - * Write a message to STDERR, prefixed with "Debug: ". - * - * @param string $message Message to write. - */ - public function debug( $message ) { - if ( \WP_CLI::get_runner()->config['debug'] ) { - $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); - $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); - } - } - /** * Write a warning message to STDERR, prefixed with "Warning: ". * From 7b5bf21bcc3cbc0d680388924ae9afbc0a1acf2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 08:35:49 -0700 Subject: [PATCH 3764/5359] Remove test because it fails sporadically This part of the codebase is pretty mature. We don't really need to worry about this breaking. --- features/user.feature | 6 ------ 1 file changed, 6 deletions(-) diff --git a/features/user.feature b/features/user.feature index d65b246d7..11c0a0811 100644 --- a/features/user.feature +++ b/features/user.feature @@ -141,12 +141,6 @@ Feature: Manage WordPress users Error: Missing file: users-incorrect.csv """ - When I try `wp user import-csv http://example.com/users.csv --skip-update` - Then STDERR should be: - """ - Error: Couldn't access remote CSV file (HTTP 404 response). - """ - When I run `wp user import-csv users.csv` Then STDOUT should not be empty From c539a57ce1cfeae32ee1141a9b061a1573e2a124 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 08:46:54 -0700 Subject: [PATCH 3765/5359] Update test to account for `WP_CLI::debug()`, which always gets called --- features/flags.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/flags.feature b/features/flags.feature index b50006f24..0ecbf1bd8 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -97,7 +97,7 @@ Feature: Global flags """ When I try `wp --require=custom-logger.php is-installed` - Then STDOUT should be: + Then STDOUT should contain: """ log: called 'error' method """ From 3d72acea6d0995704d0c70a52eba73c5a3effaeb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 08:52:19 -0700 Subject: [PATCH 3766/5359] Log the command being run --- features/config.feature | 4 ++++ php/WP_CLI/Runner.php | 1 + 2 files changed, 5 insertions(+) diff --git a/features/config.feature b/features/config.feature index 729140a04..b56b58f24 100644 --- a/features/config.feature +++ b/features/config.feature @@ -223,6 +223,10 @@ Feature: Have a config file """ Loaded WordPress """ + And STDERR should contain: + """ + Running command: option get + """ Scenario: Missing required files should not fatal WP-CLI Given an empty directory diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3672545c8..be25d7d94 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -306,6 +306,7 @@ public function run_command( $args, $assoc_args = array() ) { $extra_args = array(); } + WP_CLI::debug( 'Running command: ' . $name ); try { $command->invoke( $final_args, $assoc_args, $extra_args ); } catch ( WP_CLI\Iterators\Exception $e ) { From e26bfbfa0c588b893f7db84d6d7d4051598cf812 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 09:06:17 -0700 Subject: [PATCH 3767/5359] In PHP 7, `substr()` returns empty string when string === # start char Because we're checking to see if there's any value beyond the flag string, updating our check is functionally equivalent --- php/WP_CLI/SynopsisParser.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index 43b89cc80..d4ba77924 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -59,7 +59,8 @@ private static function classify_token( $token ) { $value = substr( $token, strlen( $matches[0] ) ); - if ( false === $value ) { + // substr returns false <= PHP 5.6, and '' PHP 7+ + if ( false === $value || '' === $value ) { $param['type'] = 'flag'; } else { $param['type'] = 'assoc'; From 36e2a1d05386591edb80aaacf608006b7096b54a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 10:24:05 -0700 Subject: [PATCH 3768/5359] Update `wp cli check-update` to accommodate major releases Also, if `--major`, `--minor` or `--patch` is specified in a check, then success message will parrot the supplied flag. --- composer.json | 1 + php/commands/cli.php | 123 ++++++++++++++++++++++++++++--------------- utils/make-phar.php | 1 + 3 files changed, 84 insertions(+), 41 deletions(-) diff --git a/composer.json b/composer.json index 26dcc72c2..1fe600e04 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "0.10.5", "mustache/mustache": "~2.4", + "composer/semver": "1.0.0", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", "symfony/finder": "~2.3", diff --git a/php/commands/cli.php b/php/commands/cli.php index ffb83ff89..ee1841bdd 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -1,7 +1,9 @@ <?php -use \WP_CLI\Dispatcher, - \WP_CLI\Utils; +use \Composer\Semver\Comparator; +use \Composer\Semver\Semver; +use \WP_CLI\Dispatcher; +use \WP_CLI\Utils; /** * Get information about WP-CLI itself. @@ -69,21 +71,6 @@ public function info( $_, $assoc_args ) { } } - /** - * Compare the last processed release to the current one, return true if it's the same minor version. - * - */ - private function same_minor_release( $release_parts, $updates ) { - $previous = end( $updates ); - if ( false === $previous ) - return false; - - $previous_parts = explode( '.', $previous['version'] ); - - return ( $previous_parts[0] === $release_parts[0] - && $previous_parts[1] === $release_parts[1] ); - } - /** * Check for update via Github API. Returns the available versions if there are updates, or empty if no update available. * @@ -95,6 +82,9 @@ private function same_minor_release( $release_parts, $updates ) { * [--minor] * : Only list minor updates * + * [--major] + * : Only list major updates + * * [--field=<field>] * : Prints the value of a single field for each update. * @@ -116,7 +106,8 @@ public function check_update( $_, $assoc_args ) { ); $formatter->display_items( $updates ); } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { - WP_CLI::success( "WP-CLI is at the latest version." ); + $update_type = $this->get_update_type_str( $assoc_args ); + WP_CLI::success( "WP-CLI is at the latest{$update_type}version." ); } } @@ -131,6 +122,9 @@ public function check_update( $_, $assoc_args ) { * [--minor] * : Only perform minor updates * + * [--major] + * : Only perform major updates + * * [--nightly] * : Update to the latest built version of the master branch. Potentially unstable. * @@ -161,7 +155,8 @@ public function update( $_, $assoc_args ) { $updates = $this->get_updates( $assoc_args ); if ( empty( $updates ) ) { - WP_CLI::success( "WP-CLI is at the latest version." ); + $update_type = $this->get_update_type_str( $assoc_args ); + WP_CLI::success( "WP-CLI is at the latest{$update_type}version." ); exit(0); } @@ -237,41 +232,48 @@ private function get_updates( $assoc_args ) { } $release_data = json_decode( $response->body ); - $current_parts = explode( '.', WP_CLI_VERSION ); - $updates = array(); + $updates = array( + 'major' => false, + 'minor' => false, + 'patch' => false, + ); foreach ( $release_data as $release ) { + + // get rid of leading "v" if there is one set $release_version = $release->tag_name; - // get rid of leading "v" if ( 'v' === substr( $release_version, 0, 1 ) ) { $release_version = ltrim( $release_version, 'v' ); } - // don't list earlier releases - if ( version_compare( $release_version, WP_CLI_VERSION, '<=' ) ) + + $update_type = $this->get_named_sem_ver( $release_version ); + if ( ! $update_type ) { continue; - $release_parts = explode( '.', $release_version ); - $update_type = 'minor'; + } - if ( $release_parts[0] === $current_parts[0] - && $release_parts[1] === $current_parts[1] ) { - $update_type = 'patch'; + if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $release_version, $updates[ $update_type ]['version'] ) ) { + continue; } - if ( ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) && 'patch' !== $update_type ) - && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'patch' ) === false && 'patch' === $update_type ) - && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) && 'minor' !== $update_type ) - && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) === false && 'minor' === $update_type ) - && ! $this->same_minor_release( $release_parts, $updates ) - ) { - $updates[] = array( - 'version' => $release_version, - 'update_type' => $update_type, - 'package_url' => $release->assets[0]->browser_download_url - ); + $updates[ $update_type ] = array( + 'version' => $release_version, + 'update_type' => $update_type, + 'package_url' => $release->assets[0]->browser_download_url + ); + } + + foreach( $updates as $type => $value ) { + if ( empty( $value ) ) { + unset( $updates[ $type ] ); } } - return $updates; + foreach( array( 'major', 'minor', 'patch' ) as $type ) { + if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { + return ! empty( $updates[ $type ] ) ? array( $updates[ $type ] ) : false; + } + } + return array_values( $updates ); } /** @@ -335,6 +337,45 @@ public function completions( $_, $assoc_args ) { $compl = new \WP_CLI\Completions( $line ); $compl->render(); } + + /** + * Get the named semantic version + * + * @param string $version + * @return string $name 'major', 'minor', 'patch' + */ + private function get_named_sem_ver( $version ) { + + if ( ! Comparator::greaterThan( $version, WP_CLI_VERSION ) ) { + return ''; + } + + $parts = explode( '-', WP_CLI_VERSION ); + list( $major, $minor, $patch ) = explode( '.', $parts[0] ); + + if ( Semver::satisfies( $version, "{$major}.{$minor}.x" ) ) { + return 'patch'; + } else if ( Semver::satisfies( $version, "{$major}.x.x" ) ) { + return 'minor'; + } else { + return 'major'; + } + } + + /** + * Get a string representing the type of update being checked for + */ + private function get_update_type_str( $assoc_args ) { + $update_type = ' '; + foreach( array( 'major', 'minor', 'patch' ) as $type ) { + if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { + $update_type = ' ' . $type . ' '; + break; + } + } + return $update_type; + } + } WP_CLI::add_command( 'cli', 'CLI_Command' ); diff --git a/utils/make-phar.php b/utils/make-phar.php index 69445c7f8..7e2432bee 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -72,6 +72,7 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/symfony/finder') ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') + ->in(WP_CLI_ROOT . '/vendor/composer/semver') ->exclude('test') ->exclude('tests') ->exclude('Tests') From 84feba8e00672e7e8a76880b8d62364d53f37aaa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 12 Oct 2015 10:48:33 -0700 Subject: [PATCH 3769/5359] Abstract to a utility to add test coverage around it --- php/commands/cli.php | 27 +-------------------------- php/utils.php | 27 +++++++++++++++++++++++++++ tests/test-utils.php | 11 +++++++++++ 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index ee1841bdd..30baa3237 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -1,7 +1,6 @@ <?php use \Composer\Semver\Comparator; -use \Composer\Semver\Semver; use \WP_CLI\Dispatcher; use \WP_CLI\Utils; @@ -246,7 +245,7 @@ private function get_updates( $assoc_args ) { $release_version = ltrim( $release_version, 'v' ); } - $update_type = $this->get_named_sem_ver( $release_version ); + $update_type = Utils\get_named_sem_ver( $release_version, WP_CLI_VERSION ); if ( ! $update_type ) { continue; } @@ -338,30 +337,6 @@ public function completions( $_, $assoc_args ) { $compl->render(); } - /** - * Get the named semantic version - * - * @param string $version - * @return string $name 'major', 'minor', 'patch' - */ - private function get_named_sem_ver( $version ) { - - if ( ! Comparator::greaterThan( $version, WP_CLI_VERSION ) ) { - return ''; - } - - $parts = explode( '-', WP_CLI_VERSION ); - list( $major, $minor, $patch ) = explode( '.', $parts[0] ); - - if ( Semver::satisfies( $version, "{$major}.{$minor}.x" ) ) { - return 'patch'; - } else if ( Semver::satisfies( $version, "{$major}.x.x" ) ) { - return 'minor'; - } else { - return 'major'; - } - } - /** * Get a string representing the type of update being checked for */ diff --git a/php/utils.php b/php/utils.php index 62bfe7cae..22e3281a4 100644 --- a/php/utils.php +++ b/php/utils.php @@ -4,6 +4,8 @@ namespace WP_CLI\Utils; +use \Composer\Semver\Comparator; +use \Composer\Semver\Semver; use \WP_CLI\Dispatcher; use \WP_CLI\Iterators\Transform; @@ -535,6 +537,31 @@ function increment_version( $current_version, $new_version ) { return $current_version; } +/** + * Compare two version strings to get the named semantic version + * + * @param string $new_version + * @param string $original_version + * @return string $name 'major', 'minor', 'patch' + */ +function get_named_sem_ver( $new_version, $original_version ) { + + if ( ! Comparator::greaterThan( $new_version, $original_version ) ) { + return ''; + } + + $parts = explode( '-', $original_version ); + list( $major, $minor, $patch ) = explode( '.', $parts[0] ); + + if ( Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { + return 'patch'; + } else if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { + return 'minor'; + } else { + return 'major'; + } +} + /** * Return the flag value or, if it's not set, the $default value. * diff --git a/tests/test-utils.php b/tests/test-utils.php index 005abedeb..01bbc5101 100644 --- a/tests/test-utils.php +++ b/tests/test-utils.php @@ -33,5 +33,16 @@ function testIncrementVersion() { ); } + public function testGetSemVer() { + $original_version = '0.19.1'; + $this->assertEmpty( Utils\get_named_sem_ver( '0.18.0', $original_version ) ); + $this->assertEmpty( Utils\get_named_sem_ver( '0.19.1', $original_version ) ); + $this->assertEquals( 'patch', Utils\get_named_sem_ver( '0.19.2', $original_version ) ); + $this->assertEquals( 'minor', Utils\get_named_sem_ver( '0.20.0', $original_version ) ); + $this->assertEquals( 'minor', Utils\get_named_sem_ver( '0.20.3', $original_version ) ); + $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.0.0', $original_version ) ); + $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.1.1', $original_version ) ); + } + } From 9c527a3cc2803124cdefcafb3ecd64bf85c2d694 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 13 Oct 2015 19:34:42 +0900 Subject: [PATCH 3770/5359] Add .editorconfig to scaffold plugin, plugin-tests and package-tests. --- features/scaffold.feature | 4 +++- php/commands/scaffold.php | 14 ++++++++------ templates/.editorconfig | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 templates/.editorconfig diff --git a/features/scaffold.feature b/features/scaffold.feature index 777403f37..9695021e1 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -161,6 +161,7 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/phpunit.xml file should exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` Then STDOUT should be: @@ -199,6 +200,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty And the community-command/.travis.yml file should exist + And the community-command/.editorconfig file should exist And the community-command/bin/install-package-tests.sh file should exist And the community-command/utils/get-package-require-from-composer.php file should exist And the community-command/features directory should contain: @@ -351,7 +353,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold tests for invalid plugin directory Given a WP install - + When I try `wp scaffold plugin-tests incorrect-custom-plugin` Then STDERR should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5591b98a8..c7208bc3d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,7 +162,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = "Skipped creating $filename", $success_message = "Created $filename" ); @@ -258,7 +258,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); - + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -333,7 +333,7 @@ function child_theme( $args, $assoc_args ) { $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All theme files were skipped.', $success_message = "Created $theme_dir." ); @@ -431,6 +431,7 @@ public function package_tests( $args, $assoc_args ) { $to_copy = array( 'templates/.travis.package.yml' => $package_dir, + 'templates/.editorconfig' => $package_dir, 'templates/load-wp-cli.feature' => $features_dir, 'templates/install-package-tests.sh' => $bin_dir, 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, @@ -465,7 +466,7 @@ public function package_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All package tests were skipped.', $success_message = 'Created test files.' ); @@ -531,7 +532,7 @@ function plugin( $args, $assoc_args ) { ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All plugin files were skipped.', $success_message = 'Created plugin files.' ); @@ -621,6 +622,7 @@ function plugin_tests( $args, $assoc_args ) { '.travis.yml' => $plugin_dir, 'phpunit.xml' => $plugin_dir, 'test-sample.php' => $tests_dir, + '.editorconfig' => $plugin_dir, ); foreach ( $to_copy as $file => $dir ) { @@ -638,7 +640,7 @@ function plugin_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All test files were skipped.', $success_message = 'Created test files.' ); diff --git a/templates/.editorconfig b/templates/.editorconfig new file mode 100644 index 000000000..e1cc194eb --- /dev/null +++ b/templates/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf From 518522344910420e93b526cc81a1c057db7700ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 13 Oct 2015 07:16:23 -0700 Subject: [PATCH 3771/5359] Break `core verify-checksums` tests into separate file --- features/core-checksums.feature | 33 +++++++++++++++++++++++++++++++++ features/core.feature | 32 -------------------------------- 2 files changed, 33 insertions(+), 32 deletions(-) create mode 100644 features/core-checksums.feature diff --git a/features/core-checksums.feature b/features/core-checksums.feature new file mode 100644 index 000000000..11bd61438 --- /dev/null +++ b/features/core-checksums.feature @@ -0,0 +1,33 @@ +Feature: Validate checksums for WordPress install + + Scenario: Verify core checksums + Given a WP install + + When I run `wp core update` + Then STDOUT should not be empty + + When I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ + + When I run `sed -i.bak s/WordPress/Wordpress/g readme.html` + Then STDERR should be empty + + When I try `wp core verify-checksums` + Then STDERR should be: + """ + Warning: File doesn't verify against checksum: readme.html + Error: WordPress install doesn't verify against checksums. + """ + + When I run `rm readme.html` + Then STDERR should be empty + + When I try `wp core verify-checksums` + Then STDERR should be: + """ + Warning: File doesn't exist: readme.html + Error: WordPress install doesn't verify against checksums. + """ diff --git a/features/core.feature b/features/core.feature index 29a96bc9c..b9adda980 100644 --- a/features/core.feature +++ b/features/core.feature @@ -392,38 +392,6 @@ Feature: Manage WordPress installation When I run `wp plugin status hello` Then STDOUT should not be empty - Scenario: Verify core checksums - Given a WP install - - When I run `wp core update` - Then STDOUT should not be empty - - When I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - When I run `sed -i.bak s/WordPress/Wordpress/g readme.html` - Then STDERR should be empty - - When I try `wp core verify-checksums` - Then STDERR should be: - """ - Warning: File doesn't verify against checksum: readme.html - Error: WordPress install doesn't verify against checksums. - """ - - When I run `rm readme.html` - Then STDERR should be empty - - When I try `wp core verify-checksums` - Then STDERR should be: - """ - Warning: File doesn't exist: readme.html - Error: WordPress install doesn't verify against checksums. - """ - Scenario: Core update from cache Given a WP install And an empty cache From 0ecd899c769bbb7341ae9f717e3fcefdbd5fe47f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 13 Oct 2015 07:35:06 -0700 Subject: [PATCH 3772/5359] Support for verifying checksums without loading WordPress --- features/core-checksums.feature | 22 ++++++++++++++++++++++ php/commands/core.php | 32 +++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/features/core-checksums.feature b/features/core-checksums.feature index 11bd61438..9c622976b 100644 --- a/features/core-checksums.feature +++ b/features/core-checksums.feature @@ -31,3 +31,25 @@ Feature: Validate checksums for WordPress install Warning: File doesn't exist: readme.html Error: WordPress install doesn't verify against checksums. """ + + Scenario: Verify core checksums without loading WordPress + Given an empty directory + And I run `wp core download --version=4.3` + + When I try `wp core verify-checksums` + Then STDERR should contain: + """ + Error: wp-config.php not found. + """ + + When I run `wp core verify-checksums --version=4.3 --locale=en_US` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ + + When I try `wp core verify-checksums --version=4.2 --locale=en_US` + Then STDERR should contain: + """ + Error: WordPress install doesn't verify against checksums. + """ diff --git a/php/commands/core.php b/php/commands/core.php index 433b0f846..d35b055ac 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -798,10 +798,7 @@ public function version( $args = array(), $assoc_args = array() ) { * @return bool|array False on failure. An array of checksums on success. */ private static function get_core_checksums( $version, $locale ) { - $url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); - - if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) - $url = 'https' . substr( $url, 4 ); + $url = 'https://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); $options = array( 'timeout' => 30 @@ -812,11 +809,6 @@ private static function get_core_checksums( $version, $locale ) { ); $response = Utils\http_request( 'GET', $url, null, $headers, $options ); - if ( $ssl && ! $response->success ) { - WP_CLI::warning( 'wp-cli could not establish a secure connection to WordPress.org. Please contact your server administrator.' ); - $response = Utils\http_request( 'GET', $http_url, null, $headers, $options ); - } - if ( ! $response->success || 200 != $response->status_code ) return false; @@ -832,11 +824,33 @@ private static function get_core_checksums( $version, $locale ) { /** * Verify WordPress files against WordPress.org's checksums. * + * Specify version to verify checksums without loading WordPress. + * + * [--version=<version>] + * : Verify checksums against a specific version of WordPress. + * + * [--locale=<locale>] + * : Verify checksums against a specific locale of WordPress. + * + * @when before_wp_load + * * @subcommand verify-checksums */ public function verify_checksums( $args, $assoc_args ) { global $wp_version, $wp_local_package; + if ( ! empty( $assoc_args['version'] ) ) { + $wp_version = $assoc_args['version']; + } + + if ( ! empty( $assoc_args['locale'] ) ) { + $wp_local_package = $assoc_args['locale']; + } + + if ( empty( $wp_version ) ) { + WP_CLI::get_runner()->load_wordpress(); + } + $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); if ( ! is_array( $checksums ) ) { From 0671d55c3f46aea4b022a7bec6ecb1615020aba4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 13 Oct 2015 08:22:13 -0700 Subject: [PATCH 3773/5359] Explicitly identify jobs for clarity --- .travis.yml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46b1adf30..aa680e987 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,6 @@ sudo: false language: php -php: - - 5.3 - - 5.6 - - '7' - env: global: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar @@ -34,16 +29,17 @@ env: - secure: "XS4lJJSZ2+4rB+zkt9lsdhG+pZEQ6nUjRSdLcVAgS7f7yvFCOjJYWRXlQ5zP/Gl3/XVe/L8EuGLYZsztauLSd6Ob7nEwnb5vIegLaqzbZd7Yizp9TnBj0AFCqo/ZPY+ZhnURY9OLFqknfQMWhrTeVvGRT94nhnnIF+sxokQgv0M=" - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" - matrix: - - WP_VERSION=4.3.1 - - WP_VERSION=3.5.2 DEPLOY_BRANCH=master matrix: - exclude: - - php: 5.6 - env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master - - php: '7' - env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master + include: + - php: 5.3 + env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master + - php: 5.6 + env: WP_VERSION=3.5.2 + - php: 5.6 + env: WP_VERSION=4.3.1 + - php: 7.0 + env: WP_VERSION=4.3.1 before_script: ./ci/prepare.sh From f1d27fb807c7804ea28dad0eeab0ba719f066a79 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 13 Oct 2015 08:29:39 -0700 Subject: [PATCH 3774/5359] Allow PHP7 to fail --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index aa680e987..b1c87df12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,8 @@ matrix: env: WP_VERSION=4.3.1 - php: 7.0 env: WP_VERSION=4.3.1 + allow_failures: + - php: 7.0 before_script: ./ci/prepare.sh From 2c3d1cf9a36a6fe540bf5b43c5a5c431da93ccb3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 13 Oct 2015 08:30:07 -0700 Subject: [PATCH 3775/5359] Formatting --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index b1c87df12..7f9acd404 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,16 +32,16 @@ env: matrix: include: - - php: 5.3 - env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master - - php: 5.6 - env: WP_VERSION=3.5.2 - - php: 5.6 - env: WP_VERSION=4.3.1 - - php: 7.0 - env: WP_VERSION=4.3.1 + - php: 5.3 + env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master + - php: 5.6 + env: WP_VERSION=3.5.2 + - php: 5.6 + env: WP_VERSION=4.3.1 + - php: 7.0 + env: WP_VERSION=4.3.1 allow_failures: - - php: 7.0 + - php: 7.0 before_script: ./ci/prepare.sh From af56d4ac8c6b9f42f56ad0e18960489b0efd5881 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 14 Oct 2015 12:08:19 -0300 Subject: [PATCH 3776/5359] improve `wp term list --<field>=<value>` documentation --- php/commands/term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index 66d7bcced..4367506bd 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -25,7 +25,7 @@ class Term_Command extends WP_CLI_Command { * : List terms of one or more taxonomies * * [--<field>=<value>] - * : Filter by one or more fields. + * : Filter by one or more fields (see get_terms() $args parameter for a list of fields). * * [--field=<field>] * : Prints the value of a single field for each term. From ca404a8268069bcc0ba0fe1ba63f1cbfbb34f9d3 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 14 Oct 2015 15:23:59 -0300 Subject: [PATCH 3777/5359] remove description field from `wp taxonomy list` as it was added after wp 3.5.2 --- features/taxonomy.feature | 10 +++++----- php/commands/taxonomy.php | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/features/taxonomy.feature b/features/taxonomy.feature index ece9b7327..f31eddfd3 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -6,11 +6,11 @@ Feature: Manage WordPress taxonomies Scenario: Listing taxonomies When I run `wp taxonomy list --format=csv` Then STDOUT should be CSV containing: - | name | label | description | public | hierarchical | - | category | Categories | | 1 | 1 | - | post_tag | Tags | | 1 | | + | name | label | public | hierarchical | + | category | Categories | 1 | 1 | + | post_tag | Tags | 1 | | When I run `wp taxonomy list --object_type=link --format=csv` Then STDOUT should be CSV containing: - | name | label | description | public | hierarchical | - | link_category | Link Categories | | | | + | name | label | public | hierarchical | + | link_category | Link Categories | | | diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index aef6c17a1..e7762fc4b 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -9,7 +9,6 @@ class Taxonomy_Command extends WP_CLI_Command { private $fields = array( 'name', 'label', - 'description', 'public', 'hierarchical' ); From 3641d0efd02e797d0b8871de3027df8d1a618cd1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 14 Oct 2015 14:17:36 -0700 Subject: [PATCH 3778/5359] Test PHP 7 and 5.6 against WordPress trunk It'll be helpful to see what our compatibility is like --- .travis.yml | 7 +++++-- ci/prepare.sh | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f9acd404..fb932211e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,11 +37,14 @@ matrix: - php: 5.6 env: WP_VERSION=3.5.2 - php: 5.6 - env: WP_VERSION=4.3.1 + env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=trunk - php: 7.0 - env: WP_VERSION=4.3.1 + env: WP_VERSION=trunk allow_failures: - php: 7.0 + - env: WP_VERSION=trunk before_script: ./ci/prepare.sh diff --git a/ci/prepare.sh b/ci/prepare.sh index 0baee0dc8..a279e3158 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -23,7 +23,15 @@ chmod +x $WP_CLI_BIN_DIR/wp # Install CodeSniffer things ./ci/prepare-codesniffer.sh -./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' +if [[ $WP_VERSION == "trunk" ]] +then + wget https://wordpress.org/nightly-builds/wordpress-latest.zip + unzip wordpress-latest.zip + mv wordpress '/tmp/wp-cli-test core-download-cache/' +else + ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' +fi + ./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' mysql -e 'CREATE DATABASE wp_cli_test;' -uroot From 6b206234373449777f6bedd3a857af6a90ca95a4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 15 Oct 2015 06:17:02 -0700 Subject: [PATCH 3779/5359] Ensure oEmbed controller is loaded in bootstrap --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index caaebf4fc..6a7f4b58e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -185,6 +185,7 @@ Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); Utils\maybe_require( '4.4-alpha-34851', ABSPATH . WPINC . '/embed-functions.php' ); +Utils\maybe_require( '4.4-alpha-34903', ABSPATH . WPINC . '/class-wp-oembed-controller.php' ); require( ABSPATH . WPINC . '/http.php' ); require_once( ABSPATH . WPINC . '/class-http.php' ); require( ABSPATH . WPINC . '/widgets.php' ); From 7220ea0f869537afbbed1c2b01e4fe64dcf70ca8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 15 Oct 2015 22:30:28 -0300 Subject: [PATCH 3780/5359] make `wp taxonomy list` expose the same fields WP-API exposes --- features/taxonomy.feature | 10 +++++----- php/commands/taxonomy.php | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/features/taxonomy.feature b/features/taxonomy.feature index f31eddfd3..823262fd2 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -6,11 +6,11 @@ Feature: Manage WordPress taxonomies Scenario: Listing taxonomies When I run `wp taxonomy list --format=csv` Then STDOUT should be CSV containing: - | name | label | public | hierarchical | - | category | Categories | 1 | 1 | - | post_tag | Tags | 1 | | + | name | label | description | object_type | show_tagcloud | hierarchical | public | + | category | Categories | | post | 1 | 1 | 1 | + | post_tag | Tags | | post | 1 | | 1 | When I run `wp taxonomy list --object_type=link --format=csv` Then STDOUT should be CSV containing: - | name | label | public | hierarchical | - | link_category | Link Categories | | | + | name | label | description | object_type | show_tagcloud | hierarchical | public | + | link_category | Link Categories | | link | | | | diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index e7762fc4b..0bd7d6076 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -9,10 +9,24 @@ class Taxonomy_Command extends WP_CLI_Command { private $fields = array( 'name', 'label', + 'description', + 'object_type', + 'show_tagcloud', + 'hierarchical', 'public', - 'hierarchical' ); + public function __construct() { + global $wp_version; + + if ( version_compare( $wp_version, 3.7, '<' ) ) { + // remove description for wp <= 3.7 + $this->fields = array_values( array_diff( $this->fields, array( 'description' ) ) ); + } + + parent::__construct(); + } + /** * List taxonomies. * @@ -59,6 +73,11 @@ public function list_( $args, $assoc_args ) { $taxonomies = get_taxonomies( $assoc_args, 'objects' ); + $taxonomies = array_map( function( $taxonomy ) { + $taxonomy->object_type = implode( ', ', $taxonomy->object_type ); + return $taxonomy; + }, $taxonomies ); + $formatter->display_items( $taxonomies ); } From 535bd15f2f49e108693a3f4cd2aac580352dd72a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Thu, 15 Oct 2015 23:14:44 -0300 Subject: [PATCH 3781/5359] run taxonomy tests only on wp >= 3.7 --- features/taxonomy.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/taxonomy.feature b/features/taxonomy.feature index 823262fd2..79ff76aac 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -3,6 +3,7 @@ Feature: Manage WordPress taxonomies Background: Given a WP install + @require-wp-3.7 Scenario: Listing taxonomies When I run `wp taxonomy list --format=csv` Then STDOUT should be CSV containing: From 877fad19ebf935a9c7b9918b69b8814c733ba616 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 16 Oct 2015 14:18:21 +0900 Subject: [PATCH 3782/5359] Revert "Add .editorconfig to scaffold plugin, plugin-tests and package-tests." This reverts commit 9c527a3cc2803124cdefcafb3ecd64bf85c2d694. --- features/scaffold.feature | 4 +--- php/commands/scaffold.php | 14 ++++++-------- templates/.editorconfig | 21 --------------------- 3 files changed, 7 insertions(+), 32 deletions(-) delete mode 100644 templates/.editorconfig diff --git a/features/scaffold.feature b/features/scaffold.feature index 9695021e1..777403f37 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -161,7 +161,6 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/phpunit.xml file should exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist - And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` Then STDOUT should be: @@ -200,7 +199,6 @@ Feature: WordPress code scaffolding When I run `wp scaffold package-tests community-command` Then STDOUT should not be empty And the community-command/.travis.yml file should exist - And the community-command/.editorconfig file should exist And the community-command/bin/install-package-tests.sh file should exist And the community-command/utils/get-package-require-from-composer.php file should exist And the community-command/features directory should contain: @@ -353,7 +351,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold tests for invalid plugin directory Given a WP install - + When I try `wp scaffold plugin-tests incorrect-custom-plugin` Then STDERR should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c7208bc3d..5591b98a8 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,7 +162,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = "Skipped creating $filename", $success_message = "Created $filename" ); @@ -258,7 +258,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); - + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -333,7 +333,7 @@ function child_theme( $args, $assoc_args ) { $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All theme files were skipped.', $success_message = "Created $theme_dir." ); @@ -431,7 +431,6 @@ public function package_tests( $args, $assoc_args ) { $to_copy = array( 'templates/.travis.package.yml' => $package_dir, - 'templates/.editorconfig' => $package_dir, 'templates/load-wp-cli.feature' => $features_dir, 'templates/install-package-tests.sh' => $bin_dir, 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, @@ -466,7 +465,7 @@ public function package_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All package tests were skipped.', $success_message = 'Created test files.' ); @@ -532,7 +531,7 @@ function plugin( $args, $assoc_args ) { ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All plugin files were skipped.', $success_message = 'Created plugin files.' ); @@ -622,7 +621,6 @@ function plugin_tests( $args, $assoc_args ) { '.travis.yml' => $plugin_dir, 'phpunit.xml' => $plugin_dir, 'test-sample.php' => $tests_dir, - '.editorconfig' => $plugin_dir, ); foreach ( $to_copy as $file => $dir ) { @@ -640,7 +638,7 @@ function plugin_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All test files were skipped.', $success_message = 'Created test files.' ); diff --git a/templates/.editorconfig b/templates/.editorconfig deleted file mode 100644 index e1cc194eb..000000000 --- a/templates/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org - -# WordPress Coding Standards -# https://make.wordpress.org/core/handbook/coding-standards/ - -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_style = tab - -[{.jshintrc,*.json,*.yml}] -indent_style = space -indent_size = 2 - -[{*.txt,wp-config-sample.php}] -end_of_line = crlf From f60a61681ec343760e789056b20b2d7e85b5f278 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 16 Oct 2015 14:43:15 +0900 Subject: [PATCH 3783/5359] add .editorconfig to --- features/scaffold.feature | 4 +++- php/commands/scaffold.php | 15 +++++++++------ templates/.editorconfig | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 templates/.editorconfig diff --git a/features/scaffold.feature b/features/scaffold.feature index 777403f37..4fdb96447 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -112,6 +112,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world` Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist And the {PLUGIN_DIR}/hello-world/package.json file should exist @@ -140,6 +141,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world --skip-tests` Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist And the {PLUGIN_DIR}/hello-world/tests directory should not exist @@ -351,7 +353,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold tests for invalid plugin directory Given a WP install - + When I try `wp scaffold plugin-tests incorrect-custom-plugin` Then STDERR should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5591b98a8..c123927ef 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,7 +162,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = "Skipped creating $filename", $success_message = "Created $filename" ); @@ -258,7 +258,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); - + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -333,7 +333,7 @@ function child_theme( $args, $assoc_args ) { $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All theme files were skipped.', $success_message = "Created $theme_dir." ); @@ -465,7 +465,7 @@ public function package_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All package tests were skipped.', $success_message = 'Created test files.' ); @@ -530,8 +530,11 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), ), $force ); + $wp_filesystem = $this->init_wp_filesystem(); + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/.editorconfig", "$plugin_dir/.editorconfig", true ); + $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All plugin files were skipped.', $success_message = 'Created plugin files.' ); @@ -638,7 +641,7 @@ function plugin_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All test files were skipped.', $success_message = 'Created test files.' ); diff --git a/templates/.editorconfig b/templates/.editorconfig new file mode 100644 index 000000000..e1cc194eb --- /dev/null +++ b/templates/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf From 1fa452a5538d1a5b5af646ada73edeabdbb9e115 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 16 Oct 2015 14:43:15 +0900 Subject: [PATCH 3784/5359] add .editorconfig to `wp scaffold plugin` --- features/scaffold.feature | 4 +++- php/commands/scaffold.php | 15 +++++++++------ templates/.editorconfig | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 templates/.editorconfig diff --git a/features/scaffold.feature b/features/scaffold.feature index 777403f37..4fdb96447 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -112,6 +112,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world` Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist And the {PLUGIN_DIR}/hello-world/package.json file should exist @@ -140,6 +141,7 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world --skip-tests` Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist And the {PLUGIN_DIR}/hello-world/tests directory should not exist @@ -351,7 +353,7 @@ Feature: WordPress code scaffolding """ Scenario: Scaffold tests for invalid plugin directory Given a WP install - + When I try `wp scaffold plugin-tests incorrect-custom-plugin` Then STDERR should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5591b98a8..c123927ef 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -162,7 +162,7 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = "Skipped creating $filename", $success_message = "Created $filename" ); @@ -258,7 +258,7 @@ function _s( $args, $assoc_args ) { $this->maybe_create_themes_dir(); $this->init_wp_filesystem(); - + $unzip_result = unzip_file( $tmpfname, $theme_path ); unlink( $tmpfname ); @@ -333,7 +333,7 @@ function child_theme( $args, $assoc_args ) { $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) ), $force ); $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All theme files were skipped.', $success_message = "Created $theme_dir." ); @@ -465,7 +465,7 @@ public function package_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All package tests were skipped.', $success_message = 'Created test files.' ); @@ -530,8 +530,11 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), ), $force ); + $wp_filesystem = $this->init_wp_filesystem(); + $wp_filesystem->copy( WP_CLI_ROOT . "/templates/.editorconfig", "$plugin_dir/.editorconfig", true ); + $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All plugin files were skipped.', $success_message = 'Created plugin files.' ); @@ -638,7 +641,7 @@ function plugin_tests( $args, $assoc_args ) { } } $this->log_whether_files_written( - $files_written, + $files_written, $skip_message = 'All test files were skipped.', $success_message = 'Created test files.' ); diff --git a/templates/.editorconfig b/templates/.editorconfig new file mode 100644 index 000000000..e1cc194eb --- /dev/null +++ b/templates/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf From b72ec0a66a547eac57728839f0a1faf3da367841 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 19 Oct 2015 00:51:09 +0900 Subject: [PATCH 3785/5359] move into create_files() --- php/commands/scaffold.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c123927ef..873a7faa1 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -528,11 +528,9 @@ function plugin( $args, $assoc_args ) { $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), + "$plugin_dir/.editorconfig" => file_get_contents( WP_CLI_ROOT . "/templates/.editorconfig" ), ), $force ); - $wp_filesystem = $this->init_wp_filesystem(); - $wp_filesystem->copy( WP_CLI_ROOT . "/templates/.editorconfig", "$plugin_dir/.editorconfig", true ); - $this->log_whether_files_written( $files_written, $skip_message = 'All plugin files were skipped.', From dd0e4c770450dce55c316f9acf6826620ff6b204 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 19 Oct 2015 06:34:29 -0700 Subject: [PATCH 3786/5359] Remove unnecessary `get_post()` from `_process_regeneration()` Because we're passing `$id`, and only ever using the `ID` attribute from `$image`, we don't need to assign `$image` --- php/commands/media.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index dc83e9050..997d67014 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -204,11 +204,10 @@ private function _make_copy( $path ) { } private function _process_regeneration( $id, $skip_delete = false ) { - $image = get_post( $id ); - $fullsizepath = get_attached_file( $image->ID ); + $fullsizepath = get_attached_file( $id ); - $att_desc = sprintf( '"%1$s" (ID %2$d).', get_the_title( $image->ID ), $image->ID ); + $att_desc = sprintf( '"%1$s" (ID %2$d).', get_the_title( $id ), $id ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { WP_CLI::warning( "Can't find $att_desc" ); @@ -216,10 +215,10 @@ private function _process_regeneration( $id, $skip_delete = false ) { } if ( ! $skip_delete ) { - $this->remove_old_images( $image->ID ); + $this->remove_old_images( $id ); } - $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath ); + $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); if ( is_wp_error( $metadata ) ) { WP_CLI::warning( $metadata->get_error_message() ); return; @@ -230,7 +229,7 @@ private function _process_regeneration( $id, $skip_delete = false ) { return; } - wp_update_attachment_metadata( $image->ID, $metadata ); + wp_update_attachment_metadata( $id, $metadata ); WP_CLI::log( "Regenerated thumbnails for $att_desc" ); From 94707b052c535c31df8487ff8ff2a8e1d5bab15d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Tue, 20 Oct 2015 15:50:58 -0700 Subject: [PATCH 3787/5359] Accommodate `wp_new_user_notification()`'s deprecated second argument --- php/commands/user.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index cb5d35afe..fb9292173 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -300,7 +300,7 @@ public function create( $args, $assoc_args ) { } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - wp_new_user_notification( $user_id, $user->user_pass ); + self::wp_new_user_notification( $user_id, $user->user_pass ); } if ( is_wp_error( $user_id ) ) { @@ -721,7 +721,7 @@ public function import_csv( $args, $assoc_args ) { } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - wp_new_user_notification( $user_id, $new_user['user_pass'] ); + self::wp_new_user_notification( $user_id, $new_user['user_pass'] ); } } @@ -760,6 +760,27 @@ private static function validate_role( $role ) { } + /** + * Acommodate three different behaviors for wp_new_user_notification() + * - 4.3.1 and above: expect second argument to be deprecated + * - 4.3: Second argument was repurposed as $notify + * - Below 4.3: Send the password in the notification + * + * @param string $user_id + * @param string $password + */ + private static function wp_new_user_notification( $user_id, $password ) { + global $wp_version; + $version = str_replace( '-src', '', $wp_version ); + if ( version_compare( $version, '4.3.1', '>=' ) ) { + wp_new_user_notification( $user_id, null, 'both' ); + } else if ( version_compare( $version, '4.3', '>' ) ) { + wp_new_user_notification( $user_id, 'both' ); + } else { + wp_new_user_notification( $user_id, $password ); + } + } + } /** From ab17e5a201c083516ea9c22cc3af1e6e9e145e09 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 21 Oct 2015 06:05:17 -0700 Subject: [PATCH 3788/5359] Properly match on WP 4.3 --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index fb9292173..4d11b1bdb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -774,7 +774,7 @@ private static function wp_new_user_notification( $user_id, $password ) { $version = str_replace( '-src', '', $wp_version ); if ( version_compare( $version, '4.3.1', '>=' ) ) { wp_new_user_notification( $user_id, null, 'both' ); - } else if ( version_compare( $version, '4.3', '>' ) ) { + } else if ( version_compare( $version, '4.3', '>=' ) ) { wp_new_user_notification( $user_id, 'both' ); } else { wp_new_user_notification( $user_id, $password ); From 51d692f3d3d572b772c717280ea5dc1a894d7128 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Oct 2015 10:09:42 -0700 Subject: [PATCH 3789/5359] Break `core update-db` tests to a separate features file --- features/core-update-db.feature | 21 +++++++++++++++++++++ features/core.feature | 20 -------------------- 2 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 features/core-update-db.feature diff --git a/features/core-update-db.feature b/features/core-update-db.feature new file mode 100644 index 000000000..3d5075efe --- /dev/null +++ b/features/core-update-db.feature @@ -0,0 +1,21 @@ +Feature: Update core's database + + Scenario: Update db across network + Given a WP multisite install + And I run `wp site create --slug=foo` + And I run `wp site create --slug=bar` + And I run `wp site create --slug=burrito --porcelain` + And save STDOUT as {BURRITO_ID} + And I run `wp site create --slug=taco --porcelain` + And save STDOUT as {TACO_ID} + And I run `wp site create --slug=pizza --porcelain` + And save STDOUT as {PIZZA_ID} + And I run `wp site archive {BURRITO_ID}` + And I run `wp site spam {TACO_ID}` + And I run `wp site delete {PIZZA_ID} --yes` + + When I run `wp core update-db --network` + Then STDOUT should contain: + """ + Success: WordPress database upgraded on 3/3 sites. + """ diff --git a/features/core.feature b/features/core.feature index b9adda980..bdedea78a 100644 --- a/features/core.feature +++ b/features/core.feature @@ -289,26 +289,6 @@ Feature: Manage WordPress installation Error: Multisite with subdomains cannot be configured when domain is 'localhost'. """ - Scenario: Update db across network - Given a WP multisite install - And I run `wp site create --slug=foo` - And I run `wp site create --slug=bar` - And I run `wp site create --slug=burrito --porcelain` - And save STDOUT as {BURRITO_ID} - And I run `wp site create --slug=taco --porcelain` - And save STDOUT as {TACO_ID} - And I run `wp site create --slug=pizza --porcelain` - And save STDOUT as {PIZZA_ID} - And I run `wp site archive {BURRITO_ID}` - And I run `wp site spam {TACO_ID}` - And I run `wp site delete {PIZZA_ID} --yes` - - When I run `wp core update-db --network` - Then STDOUT should contain: - """ - Success: WordPress database upgraded on 3/3 sites. - """ - Scenario: Update from a ZIP file Given a WP install From d3a6c8336f6765fda59bc923a6f2cec519d40130 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Oct 2015 10:28:49 -0700 Subject: [PATCH 3790/5359] Provide more verbosity when updating core database schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can be helpful to know what version we were at, and what we updated to. ``` salty-wordpress âžœ wordpress-test.dev wp core update-db --network WordPress database already at latest db version 30135 on wordpress-test.dev/ WordPress database upgraded successfully from db version 33056 to 30135 on wordpress-test.dev/foo/ WordPress database upgraded successfully from db version 33056 to 30135 on wordpress-test.dev/bar/ Success: WordPress database upgraded on 3/3 sites ``` --- features/core-update-db.feature | 19 ++++++++++++++++++- php/commands/core.php | 21 ++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 3d5075efe..eec53c026 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -1,5 +1,22 @@ Feature: Update core's database + Scenario: Update db on a single site + Given a WP install + And I run `wp core download --version=4.1 --force` + And I run `wp option update db_version 29630` + + When I run `wp core update-db` + Then STDOUT should contain: + """ + Success: WordPress database upgraded successfully from 29630 to 30133 + """ + + When I run `wp core update-db` + Then STDOUT should contain: + """ + Success: WordPress database already at latest version 30133 + """ + Scenario: Update db across network Given a WP multisite install And I run `wp site create --slug=foo` @@ -17,5 +34,5 @@ Feature: Update core's database When I run `wp core update-db --network` Then STDOUT should contain: """ - Success: WordPress database upgraded on 3/3 sites. + Success: WordPress database upgraded on 3/3 sites """ diff --git a/php/commands/core.php b/php/commands/core.php index d35b055ac..3520bf7c0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1008,7 +1008,7 @@ function update( $args, $assoc_args ) { * @subcommand update-db */ function update_db( $_, $assoc_args ) { - global $wpdb, $wp_db_version; + global $wpdb, $wp_db_version, $wp_current_db_version; $network = Utils\get_flag_value( $assoc_args, 'network' ); if ( $network && ! is_multisite() ) { @@ -1027,7 +1027,13 @@ function update_db( $_, $assoc_args ) { $url = $blog->domain . $blog->path; $process = WP_CLI::launch_self( 'core update-db', array(), array(), false, true, array( 'url' => $url ) ); if ( 0 == $process->return_code ) { - WP_CLI::log( "Database upgraded successfully on {$url}" ); + // See if we can parse the stdout + if ( preg_match( '#Success: (.+)#', $process->stdout, $matches ) ) { + $message = "{$matches[1]} on {$url}"; + } else { + $message = "Database upgraded successfully on {$url}"; + } + WP_CLI::log( $message ); $success++; } else { WP_CLI::warning( "Database failed to upgrade on {$url}" ); @@ -1036,11 +1042,16 @@ function update_db( $_, $assoc_args ) { if ( $total && $success == $total ) { update_site_option( 'wpmu_upgrade_site', $wp_db_version ); } - WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); + WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites', $success, $total ) ); } else { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - wp_upgrade(); - WP_CLI::success( 'WordPress database upgraded successfully.' ); + $wp_current_db_version = __get_option( 'db_version' ); + if ( $wp_db_version != $wp_current_db_version ) { + wp_upgrade(); + WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}" ); + } else { + WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}" ); + } } } From d3360668bda1198972a5d74d68f8aa378340b920 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 25 Oct 2015 11:21:42 -0700 Subject: [PATCH 3791/5359] Update tests to accommodate new messages --- features/core-update-db.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index eec53c026..b26e596e6 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -8,13 +8,13 @@ Feature: Update core's database When I run `wp core update-db` Then STDOUT should contain: """ - Success: WordPress database upgraded successfully from 29630 to 30133 + Success: WordPress database upgraded successfully from db version 29630 to 30133 """ When I run `wp core update-db` Then STDOUT should contain: """ - Success: WordPress database already at latest version 30133 + Success: WordPress database already at latest db version 30133 """ Scenario: Update db across network From a8501bdb782797a42e71448579264386f4e47410 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 26 Oct 2015 16:15:08 -0200 Subject: [PATCH 3792/5359] add subcommand `wp taxonomy get` --- features/taxonomy.feature | 14 +++++++++++ php/commands/taxonomy.php | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/features/taxonomy.feature b/features/taxonomy.feature index 79ff76aac..35605a47c 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -15,3 +15,17 @@ Feature: Manage WordPress taxonomies Then STDOUT should be CSV containing: | name | label | description | object_type | show_tagcloud | hierarchical | public | | link_category | Link Categories | | link | | | | + + Scenario: Get taxonomy + When I try `wp taxonomy get invalid-taxonomy` + Then STDERR should be: + """ + Error: Taxonomy invalid-taxonomy doesn't exist. + """ + + When I run `wp taxonomy get category` + Then STDOUT should be a table containing rows: + | Field | Value | + | name | category | + | object_type | ["post"] | + | label | Categories | \ No newline at end of file diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index 0bd7d6076..be26a0f16 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -81,6 +81,59 @@ public function list_( $args, $assoc_args ) { $formatter->display_items( $taxonomies ); } + /** + * Get a taxonomy + * + * ## OPTIONS + * + * <taxonomy> + * : Taxonomy slug + * + * [--field=<field>] + * : Instead of returning the whole taxonomy, returns the value of a single field. + * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * + * [--format=<format>] + * : Accepted values: table, json, csv. Default: table + * + * ## EXAMPLES + * + * wp taxonomy get post_tag --format=json + */ + public function get( $args, $assoc_args ) { + $taxonomy = get_taxonomy( $args[0] ); + + if ( ! $taxonomy ) { + WP_CLI::error( "Taxonomy {$args[0]} doesn't exist." ); + } + + if ( empty( $assoc_args['fields'] ) ) { + $default_fields = array_merge( $this->fields, array( + 'labels', + 'cap' + ) ); + + $assoc_args['fields'] = $default_fields; + } + + $data = array( + 'name' => $taxonomy->name, + 'label' => $taxonomy->label, + 'description' => $taxonomy->description, + 'object_type' => $taxonomy->object_type, + 'show_tagcloud' => $taxonomy->show_tagcloud, + 'hierarchical' => $taxonomy->hierarchical, + 'public' => $taxonomy->public, + 'labels' => $taxonomy->labels, + 'cap' => $taxonomy->cap, + ); + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $data ); + } + private function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'taxonomy' ); } From 23dc7b30cb3f05d2e0ad58865c01bf08e4d70dd6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Mon, 26 Oct 2015 16:16:50 -0200 Subject: [PATCH 3793/5359] add missing new line at the end of the file --- features/taxonomy.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/taxonomy.feature b/features/taxonomy.feature index 35605a47c..e2d75c316 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -28,4 +28,4 @@ Feature: Manage WordPress taxonomies | Field | Value | | name | category | | object_type | ["post"] | - | label | Categories | \ No newline at end of file + | label | Categories | From 64fd82fff1463d1160eea59773467651e7495783 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 26 Oct 2015 11:39:35 -0700 Subject: [PATCH 3794/5359] Remove unnecessary `esc_sql()` from `wp option list --search=` The query is run through `$wpdb->prepare()` later on --- php/commands/option.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index 9f2f66f84..6fd527429 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -130,7 +130,7 @@ public function list_( $args, $assoc_args ) { $autoload_query = ''; if ( isset( $assoc_args['search'] ) ) { - $pattern = self::esc_like( esc_sql( $assoc_args['search'] ) ); + $pattern = self::esc_like( $assoc_args['search'] ); // substitute wildcards $pattern = str_replace( '*', '%', $pattern ); $pattern = str_replace( '?', '_', $pattern ); From abeb6ad84d8be35f58803cecd579c027338f98c4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 26 Oct 2015 11:44:56 -0700 Subject: [PATCH 3795/5359] Use `esc_sql()` and `$wpdb->prepare()` instead of deprecated method --- php/WP_CLI/Iterators/Table.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index cebb812bd..143dbcc67 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -65,16 +65,15 @@ private static function build_fields( $fields ) { } private static function build_where_conditions( $where ) { - global $wpdb; if ( is_array( $where ) ) { $conditions = array(); foreach( $where as $key => $value ) { if ( is_array( $value ) ) { - $conditions[] = $key . ' IN (' . $wpdb->escape( implode( ',', $value ) ) . ')'; + $conditions[] = $key . ' IN (' . esc_sql( implode( ',', $value ) ) . ')'; } else if ( is_numeric( $key ) ) { $conditions[] = $value; } else { - $conditions[] = $key . ' = "' . $wpdb->escape( $value ) .'"'; + $conditions[] = $key . $wpdb->prepare( ' = %s', $value ); } } $where = implode( ' AND ', $conditions ); From 493ad29e433a3bcf7a6189faa4fe0a19a7788427 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 26 Oct 2015 12:29:01 -0700 Subject: [PATCH 3796/5359] Restore `$wpdb` global --- php/WP_CLI/Iterators/Table.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 143dbcc67..472129ef8 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -65,6 +65,7 @@ private static function build_fields( $fields ) { } private static function build_where_conditions( $where ) { + global $wpdb; if ( is_array( $where ) ) { $conditions = array(); foreach( $where as $key => $value ) { From 55282c8aac32139ac188a2ebd15c9bf4a54cb4e8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 27 Oct 2015 08:13:00 -0200 Subject: [PATCH 3797/5359] add `wp post-type` command --- features/post-type.feature | 11 ++++++ php/commands/post-type.php | 69 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 features/post-type.feature create mode 100644 php/commands/post-type.php diff --git a/features/post-type.feature b/features/post-type.feature new file mode 100644 index 000000000..fb98b0173 --- /dev/null +++ b/features/post-type.feature @@ -0,0 +1,11 @@ +Feature: Manage WordPress post types + + Background: + Given a WP install + + Scenario: Listing post types + When I run `wp post-type list --format=csv` + Then STDOUT should be CSV containing: + | name | label | description | hierarchical | public | capability_type | + | post | Posts | | | 1 | post | + | page | Pages | | 1 | 1 | page | diff --git a/php/commands/post-type.php b/php/commands/post-type.php new file mode 100644 index 000000000..3b6f67178 --- /dev/null +++ b/php/commands/post-type.php @@ -0,0 +1,69 @@ +<?php +/** + * Manage post types. + * + * @package wp-cli + */ +class Post_Type_Command extends WP_CLI_Command { + + private $fields = array( + 'name', + 'label', + 'description', + 'hierarchical', + 'public', + 'capability_type', + ); + + /** + * List post types. + * + * ## OPTIONS + * + * [--<field>=<value>] + * : Filter by one or more fields (see get_post_types() first parameter for a list of available fields). + * + * [--field=<field>] + * : Prints the value of a single field for each post type. + * + * [--fields=<fields>] + * : Limit the output to specific post type fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each term: + * + * * name + * * label + * * description + * * hierarchical + * * public + * * capability_type + * + * There are no optionally available fields. + * + * ## EXAMPLES + * + * wp post-type list --format=csv + * + * wp post-type list --object-type=post --fields=name,public + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); + + $types = get_post_types( $assoc_args, 'objects' ); + + $formatter->display_items( $types ); + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'post-type' ); + } +} + +WP_CLI::add_command( 'post-type', 'Post_Type_Command' ); From 0d5afaab128a6a541f9992b8b8dae9cf59c1b63d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 27 Oct 2015 08:35:09 -0200 Subject: [PATCH 3798/5359] add subcommand `wp post-type get <post-type>` --- features/post-type.feature | 13 ++++++++++ php/commands/post-type.php | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/features/post-type.feature b/features/post-type.feature index fb98b0173..08f2a1f61 100644 --- a/features/post-type.feature +++ b/features/post-type.feature @@ -9,3 +9,16 @@ Feature: Manage WordPress post types | name | label | description | hierarchical | public | capability_type | | post | Posts | | | 1 | post | | page | Pages | | 1 | 1 | page | + + Scenario: Get a post type + When I try `wp post-type get invalid-post-type` + Then STDERR should be: + """ + Error: Post type invalid-post-type doesn't exist. + """ + + When I run `wp post-type get page` + Then STDOUT should be a table containing rows: + | Field | Value | + | name | page | + | label | Pages | diff --git a/php/commands/post-type.php b/php/commands/post-type.php index 3b6f67178..d83ec398f 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -61,6 +61,58 @@ public function list_( $args, $assoc_args ) { $formatter->display_items( $types ); } + /** + * Get a post type + * + * ## OPTIONS + * + * <post-type> + * : Post type slug + * + * [--field=<field>] + * : Instead of returning the whole taxonomy, returns the value of a single field. + * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * + * [--format=<format>] + * : Accepted values: table, json, csv. Default: table + * + * ## EXAMPLES + * + * wp post-type get page --format=json + */ + public function get( $args, $assoc_args ) { + $post_type = get_post_type_object( $args[0] ); + + if ( ! $post_type ) { + WP_CLI::error( "Post type {$args[0]} doesn't exist." ); + } + + if ( empty( $assoc_args['fields'] ) ) { + $default_fields = array_merge( $this->fields, array( + 'labels', + 'cap' + ) ); + + $assoc_args['fields'] = $default_fields; + } + + $data = array( + 'name' => $post_type->name, + 'label' => $post_type->label, + 'description' => $post_type->description, + 'hierarchical' => $post_type->hierarchical, + 'public' => $post_type->public, + 'capability_type' => $post_type->capability_type, + 'labels' => $post_type->labels, + 'cap' => $post_type->cap, + ); + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_item( $data ); + } + private function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'post-type' ); } From e0b43d7dff6b30fba3144948c191b2b0d9ed22ed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 05:19:58 -0700 Subject: [PATCH 3799/5359] Don't allow failures against WordPress trunk We need to make sure WP-CLI is fully-compatible with WP 4.4 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fb932211e..b714914cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,6 @@ matrix: env: WP_VERSION=trunk allow_failures: - php: 7.0 - - env: WP_VERSION=trunk before_script: ./ci/prepare.sh From aa4068f35bf10b7312e1d2e0845dcf98020561ca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 05:32:33 -0700 Subject: [PATCH 3800/5359] Pick another rewrite rule to match Core changed the regex for this one in 4.4 See https://core.trac.wordpress.org/ticket/11694#comment:39 --- features/rewrite.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index 3c49c4843..7e86f16ba 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -25,7 +25,7 @@ Feature: Manage WordPress rewrites When I run `wp rewrite list --format=csv` Then STDOUT should be CSV containing: | match | query | source | - | blog/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/([^/]+)(/[0-9]+)?/?$ | index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&page=$matches[5] | post | + | blog/[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/trackback/?$ | index.php?attachment=$matches[1]&tb=1 | post | | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | | section/(.+?)/?$ | index.php?category_name=$matches[1] | category | From 94db54d1c8decf9c095c038d78239db82cda2a73 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 05:36:02 -0700 Subject: [PATCH 3801/5359] Make this a lower-fidelity test, because core changed the retval --- features/comment.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index f79a2ac23..ff970332c 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -68,9 +68,9 @@ Feature: Manage WordPress comments """ When I run `wp comment url 1` - Then STDOUT should be: + Then STDOUT should contain: """ - http://example.com/?p=1#comment-1 + #comment-1 """ Scenario: Count comments From 41db5ec515c5f9b745c51173d55768636322bc10 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 05:39:29 -0700 Subject: [PATCH 3802/5359] Update `wp comment count` tests for WP 4.4 WordPress returns a new `all` value, which fails the original tests. --- features/comment.feature | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index ff970332c..8e368e244 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -75,24 +75,30 @@ Feature: Manage WordPress comments Scenario: Count comments When I run `wp comment count 1` - Then STDOUT should be: + Then STDOUT should contain: """ approved: 1 + """ + And STDOUT should contain: + """ moderated: 0 - spam: 0 - trash: 0 - post-trashed: 0 + """ + And STDOUT should contain: + """ total_comments: 1 """ When I run `wp comment count` - Then STDOUT should be: + Then STDOUT should contain: """ approved: 1 + """ + And STDOUT should contain: + """ moderated: 0 - spam: 0 - trash: 0 - post-trashed: 0 + """ + And STDOUT should contain: + """ total_comments: 1 """ From 676afbbcb764aef1f476cb5ac549333e0d76675e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 05:56:13 -0700 Subject: [PATCH 3803/5359] Use functionally-equivalent empty strings instead of `null` Something changed deep in the bowels of `wp_insert_post()` that causes SQL failures when `null` is provided. --- php/commands/media.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 997d67014..e2f459943 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -111,10 +111,10 @@ function regenerate( $args, $assoc_args = array() ) { */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( - 'title' => null, - 'caption' => null, - 'alt' => null, - 'desc' => null + 'title' => '', + 'caption' => '', + 'alt' => '', + 'desc' => '', ) ); if ( isset( $assoc_args['post_id'] ) ) { From ffe2d0d5d36f882e5e74f8a456bf9262055b9223 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 06:19:47 -0700 Subject: [PATCH 3804/5359] Cast `parent` and `count` on terms as `int` Core began doing this in 4.4, and we should do it too --- features/term.feature | 4 ++-- php/commands/term.php | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/features/term.feature b/features/term.feature index fa85f1f8b..03f2bbbb6 100644 --- a/features/term.feature +++ b/features/term.feature @@ -18,8 +18,8 @@ Feature: Manage WordPress terms "name": "Test term", "slug":"test", "description":"This is a test term", - "parent":"0", - "count":"0" + "parent":0, + "count":0 }] """ diff --git a/php/commands/term.php b/php/commands/term.php index 4367506bd..f5ddfb3e5 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -73,6 +73,12 @@ public function list_( $args, $assoc_args ) { $terms = get_terms( $args, $assoc_args ); } + $terms = array_map( function( $term ){ + $term->count = (int)$term->count; + $term->parent = (int)$term->parent; + return $term; + }, $terms ); + if ( 'ids' == $formatter->format ) { $terms = wp_list_pluck( $terms, 'term_id' ); echo implode( ' ', $terms ); From e9b7f8ed7e1ae2a37ced0b258e2b9e04a63db1fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 06:21:05 -0700 Subject: [PATCH 3805/5359] Cast as int, see ffe2d0d --- php/commands/term.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index f5ddfb3e5..113a6620c 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -182,6 +182,9 @@ public function get( $args, $assoc_args ) { $assoc_args['fields'] = array_keys( $term_array ); } + $term->count = (int) $term->count; + $term->parent = (int) $term->parent; + $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $term ); } From 51f2e16f11013931c65c73b55675442be7d4f1b8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 06:24:58 -0700 Subject: [PATCH 3806/5359] Make test strings less precise, to work with 4.3 and 4.4 --- features/user.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/user.feature b/features/user.feature index 11c0a0811..62ed3fe2b 100644 --- a/features/user.feature +++ b/features/user.feature @@ -177,7 +177,7 @@ Feature: Manage WordPress users When I try `wp user import-csv user-invalid.csv` Then STDERR should contain: """ - Warning: Only lowercase letters (a-z) and numbers are allowed. + lowercase letters (a-z) and numbers """ When I run `wp user import-csv user-valid.csv` @@ -195,7 +195,7 @@ Feature: Manage WordPress users When I try `wp user create bob-jones bobjones@example.com` Then STDERR should contain: """ - Error: Only lowercase letters (a-z) and numbers are allowed. + lowercase letters (a-z) and numbers """ When I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones"` From d478ce3e470676fd9baa2a2b3f63c5f852f31fd0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 29 Oct 2015 06:47:29 -0700 Subject: [PATCH 3807/5359] Support `$WP_VERSION=trunk` or `$WP_VERSION=nightly` in WP test install While technically `trunk` is different than `nightly`, pragmatically they're the same, and I'd like to use a built archive instead of SVN checkout. --- templates/install-wp-tests.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 0aaf09f3c..5baa6cb56 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -24,6 +24,8 @@ download() { if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then WP_TESTS_TAG="tags/$WP_VERSION" +elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + WP_TESTS_TAG="trunk" else # http serves a single offer, whereas https serves multiple. we only want one download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json @@ -46,15 +48,21 @@ install_wp() { mkdir -p $WP_CORE_DIR - if [ $WP_VERSION == 'latest' ]; then - local ARCHIVE_NAME='latest' + if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + mkdir -p /tmp/wordpress-nightly + download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip + unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/ + mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR else - local ARCHIVE_NAME="wordpress-$WP_VERSION" + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz + tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR fi - download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php } From cc8aa8001bc439a6403874cac3bc8802ae10efad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Sun, 1 Nov 2015 14:32:44 -0800 Subject: [PATCH 3808/5359] Provide human-friendly output when rewrite rules successfully flush This makes `wp rewrite flush` more consistent with other commands. --- features/rewrite.feature | 5 ++++- php/commands/rewrite.php | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index 7e86f16ba..d2908d4f5 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -50,7 +50,10 @@ Feature: Manage WordPress rewrites When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` Then I run `wp rewrite flush` - Then STDOUT should be empty + Then STDOUT should be: + """ + Success: Rewrite rules flushed. + """ Scenario: Generate .htaccess on hard flush Given a WP install diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 5a6f4ab0b..db5eba43e 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -41,6 +41,8 @@ public function flush( $args, $assoc_args ) { if ( ! get_option( 'rewrite_rules' ) ) { WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); + } else { + WP_CLI::success( 'Rewrite rules flushed.' ); } } From 8702c14a199f11180accb2b22e68593e160a9af5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 2 Nov 2015 08:03:00 -0800 Subject: [PATCH 3809/5359] Add syntax highlighting to `wp rewrite structure` docs --- php/commands/rewrite.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index db5eba43e..ed0e046cd 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -56,8 +56,8 @@ public function flush( $args, $assoc_args ) { * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module * to your wp-cli.yml or config.yml. For example: * - * apache_modules: - * - mod_rewrite + * `apache_modules: + * - mod_rewrite` * * ## OPTIONS * From c7e4a2a91550711386ba9130d86ebf6af024054e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 2 Nov 2015 08:05:08 -0800 Subject: [PATCH 3810/5359] Test PHP 5.6 instead of 5.5 in plugin tests .travis.yml --- templates/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index cd4bc26e7..eeb11ff8c 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -7,7 +7,7 @@ notifications: php: - 5.3 - - 5.5 + - 5.6 env: - WP_VERSION=latest WP_MULTISITE=0 From 2e09584f2c387fc6776723673aa12474f9ec67df Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Mon, 2 Nov 2015 08:05:44 -0800 Subject: [PATCH 3811/5359] Remove trailing space --- templates/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/.travis.yml b/templates/.travis.yml index eeb11ff8c..375e59ed2 100644 --- a/templates/.travis.yml +++ b/templates/.travis.yml @@ -18,6 +18,6 @@ matrix: env: WP_VERSION=latest WP_MULTISITE=1 before_script: - - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION + - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION script: phpunit From 7ac800b0bbcc539df4e0f47c785e33cc6277d7c6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 4 Nov 2015 14:55:27 -0800 Subject: [PATCH 3812/5359] Update mailmap with latest contributors --- .mailmap | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.mailmap b/.mailmap index c5b31ad86..080fcc238 100644 --- a/.mailmap +++ b/.mailmap @@ -13,6 +13,7 @@ boonebgorges <boonebgorges@gmail.com> Borek Bernard <borekb@gmail.com> borekb <borekb@gmail.com> Brad Parbs <brad@bradparbs.com> +Brandon Kraft <public@brandonkraft.com> Brian MacKinney <brian@getpantheon.com> builtbylane <lanegoldberg@gmail.com> c10b10 <alex.ciobica@gmail.com> @@ -33,14 +34,18 @@ dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> eugeneware <eugene@noblesamurai.com> +Evan Mattson <me@aaemnnost.tv> francescolaffi <francesco.laffi@gmail.com> future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> +Grant McInnes <grant.mcinnes@eyesopen.ca> +Hiroshi Urabe <mail@torounit.com> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> Jan VoráÄek <jan@voracek.net> +Jeff Gould <jrgould@gmail.com> jeichorn <joshua.eichorn@pagely.com> Jeremy Pry <jeremy.pry@gmail.com> jghazally <jeff@bigfish.co.uk> @@ -97,6 +102,7 @@ phh <phh@peytz.dk> Pippin Williamson <pippin@pippinsplugins.com> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> +Robin Schneider <ypid@riseup.net> rodrigoprimo <rodrigo@hacklab.com.br> rodrigoprimo <rodrigosprimo@gmail.com> roelven <roel@soundcloud.com> @@ -133,6 +139,7 @@ tott <tott@automattic.com> trepmal <trepmal@gmail.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> +voldemortensen <voldemortensen@users.noreply.github.com> Wendell Júnior <wrnx00@gmail.com> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> From a1154ef06a6ce67c7d7ccd62fc8ecba26b9a4855 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Wed, 4 Nov 2015 15:40:56 -0800 Subject: [PATCH 3813/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 217292ece..885415662 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.21.0-alpha +0.21.0 From 4f99ec616f328349b6f4ab632e4e7f202710408f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <d@danielbachhuber.com> Date: Thu, 5 Nov 2015 06:32:19 -0800 Subject: [PATCH 3814/5359] Back to work --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 885415662..394160575 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.21.0 +0.22.0-alpha From fe8da658c5d9c3e071c609e1c6c40b8e73be60a8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 5 Nov 2015 13:49:23 -0800 Subject: [PATCH 3815/5359] Failing test case for running `wp help core config` --- features/help.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/help.feature b/features/help.feature index d73cde31e..fb066f603 100644 --- a/features/help.feature +++ b/features/help.feature @@ -27,6 +27,16 @@ Feature: Get help about WP-CLI commands wp post list """ + Scenario: Help when WordPress is downloaded but not installed + Given an empty directory + + When I run `wp core download` + And I run `wp help core config` + Then STDOUT should contain: + """ + wp core config + """ + Scenario: Help for nonexistent commands Given a WP install From 573ab9220a69506ec1d76c60000261b62109a7f1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 5 Nov 2015 13:58:27 -0800 Subject: [PATCH 3816/5359] Display help early when WordPress is downloaded, but not configured --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b227d7caa..799518ed3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -627,7 +627,7 @@ public function start() { self::set_wp_root( $this->find_wp_root() ); // First try at showing man page - if ( 'help' === $this->arguments[0] && ! $this->wp_exists() ) { + if ( 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() ) ) { $this->_run_command(); } From 9bb4e5ee6b47a711ac4a56cbc1fa5f8eb99882b2 Mon Sep 17 00:00:00 2001 From: Corey Worrell <proskater55@gmail.com> Date: Fri, 6 Nov 2015 15:30:17 -0800 Subject: [PATCH 3817/5359] Allowing remote plugin files without `.zip` in filename Fixes #2170 --- php/WP_CLI/CommandWithUpgrade.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) mode change 100644 => 100755 php/WP_CLI/CommandWithUpgrade.php diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php old mode 100644 new mode 100755 index 20e347fac..7db521842 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -121,15 +121,9 @@ function install( $args, $assoc_args ) { $local_or_remote_zip_file = false; $result = false; - // Check if a URL to a remote zip file has been specified - $url_path = parse_url( $slug, PHP_URL_PATH ); - if ( ! empty( $url_path ) && '.zip' === substr( $url_path, - 4 ) ) { + // Check if a URL to a remote or local zip has been specified + if ( strpos( $slug, '://' ) || ( pathinfo( $slug, PATHINFO_EXTENSION ) === 'zip' && is_file( $slug ) ) ) { $local_or_remote_zip_file = $slug; - } else { - // Check if a local zip file has been specified - if ( 'zip' === pathinfo( $slug, PATHINFO_EXTENSION ) && file_exists( $slug ) ) { - $local_or_remote_zip_file = $slug; - } } if ( $local_or_remote_zip_file ) { From b4dadf39f28da753bb4562a3cada65492db8f713 Mon Sep 17 00:00:00 2001 From: Corey Worrell <proskater55@gmail.com> Date: Fri, 6 Nov 2015 15:36:49 -0800 Subject: [PATCH 3818/5359] Adding tighter check to `strpos` --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 7db521842..e03724218 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -122,7 +122,7 @@ function install( $args, $assoc_args ) { $result = false; // Check if a URL to a remote or local zip has been specified - if ( strpos( $slug, '://' ) || ( pathinfo( $slug, PATHINFO_EXTENSION ) === 'zip' && is_file( $slug ) ) ) { + if ( strpos( $slug, '://' ) !== false || ( pathinfo( $slug, PATHINFO_EXTENSION ) === 'zip' && is_file( $slug ) ) ) { $local_or_remote_zip_file = $slug; } From 044f59602b417b01bceeae2e314c3d4e73b2898d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 9 Nov 2015 07:31:51 -0800 Subject: [PATCH 3819/5359] Have Travis only send email notifications on initial failure --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b714914cb..c058d4068 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,3 +58,4 @@ cache: notifications: email: on_success: never + on_failure: change From cbe9fa4cf50319f79e3de96c5bf6e8eda0c0f44f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 9 Nov 2015 16:23:39 -0800 Subject: [PATCH 3820/5359] Include `not_found` label when scaffolding a custom taxonomy --- templates/taxonomy.mustache | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 911a6881c..e47807605 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -27,6 +27,7 @@ 'separate_items_with_commas' => __( '{{label_plural_ucfirst}} separated by comma', '{{textdomain}}' ), 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), + 'not_found' => __( 'No {{label_plural}} found.', '{{textdomain}}' ), 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), ), ) ); From ba20cd35662468493cc212a2b3dbcbcc89b545db Mon Sep 17 00:00:00 2001 From: Josh Eaton <josh@josheaton.org> Date: Mon, 9 Nov 2015 20:54:16 -0500 Subject: [PATCH 3821/5359] Fix scaffolded plugin header so it passes WPCS. * Add @package tag * Use correct comment type. --- templates/plugin.mustache | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/templates/plugin.mustache b/templates/plugin.mustache index d992cd094..29aded1f7 100644 --- a/templates/plugin.mustache +++ b/templates/plugin.mustache @@ -1,12 +1,12 @@ <?php -/* -Plugin Name: {{plugin_name}} -Version: 0.1-alpha -Description: PLUGIN DESCRIPTION HERE -Author: YOUR NAME HERE -Author URI: YOUR SITE HERE -Plugin URI: PLUGIN SITE HERE -Text Domain: {{textdomain}} -Domain Path: /languages -*/ - +/** + * Plugin Name: {{plugin_name}} + * Version: 0.1-alpha + * Description: PLUGIN DESCRIPTION HERE + * Author: YOUR NAME HERE + * Author URI: YOUR SITE HERE + * Plugin URI: PLUGIN SITE HERE + * Text Domain: {{textdomain}} + * Domain Path: /languages + * @package {{plugin_name}} + */ From 8c2ddda14a202de50cdec44b20fd5e3c5a29a2b7 Mon Sep 17 00:00:00 2001 From: Josh Eaton <josh@josheaton.org> Date: Mon, 9 Nov 2015 20:56:02 -0500 Subject: [PATCH 3822/5359] Fix minor spacing issues with scaffolded Gruntfile. --- templates/plugin-gruntfile.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/plugin-gruntfile.mustache b/templates/plugin-gruntfile.mustache index 661d0e309..86a021bfb 100644 --- a/templates/plugin-gruntfile.mustache +++ b/templates/plugin-gruntfile.mustache @@ -5,7 +5,7 @@ module.exports = function( grunt ) { // Project configuration grunt.initConfig( { - pkg: grunt.file.readJSON( 'package.json' ), + pkg: grunt.file.readJSON( 'package.json' ), addtextdomain: { options: { @@ -46,7 +46,7 @@ module.exports = function( grunt ) { grunt.loadNpmTasks( 'grunt-wp-i18n' ); grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' ); grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] ); - grunt.registerTask( 'readme', ['wp_readme_to_markdown']); + grunt.registerTask( 'readme', ['wp_readme_to_markdown'] ); grunt.util.linefeed = '\n'; From 3bc3adc1775b46c6e126eedc5cc400d6a85931f1 Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Fri, 13 Nov 2015 11:14:02 -0500 Subject: [PATCH 3823/5359] prevent duplicate super-admin grants --- php/commands/super-admin.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 4410f345c..6dc47baee 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -35,11 +35,18 @@ public function add( $args, $_ ) { foreach ( $user_logins as $user_login ) { $user = get_user_by( 'login', $user_login ); + if ( !$user ) { WP_CLI::warning( "Couldn't find {$user_login} user." ); - } else { - $super_admins[] = $user->user_login; + continue; + } + + if ( in_array( $user->user_login, $super_admins ) ) { + WP_CLI::warning( "User {$user_login} already has super-admin capabilities." ); + continue; } + + $super_admins[] = $user->user_login; } update_site_option( 'site_admins' , $super_admins ); From 636042f9a994b4c45fd0e61ad22b9f92402741fc Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Fri, 13 Nov 2015 11:14:55 -0500 Subject: [PATCH 3824/5359] super-admin add: only output success message if option update succeeds --- php/commands/super-admin.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 6dc47baee..9d52fed9d 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -49,8 +49,9 @@ public function add( $args, $_ ) { $super_admins[] = $user->user_login; } - update_site_option( 'site_admins' , $super_admins ); - WP_CLI::success( 'Granted super-admin capabilities.' ); + if ( update_site_option( 'site_admins' , $super_admins ) ) { + WP_CLI::success( 'Granted super-admin capabilities.' ); + } } /** From 5c7295aa1b4f47f0a7a388d4e801aac1aa2e7eb6 Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Fri, 13 Nov 2015 14:56:55 -0500 Subject: [PATCH 3825/5359] add error & nochange states for super-admin add --- php/commands/super-admin.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 9d52fed9d..c57d6be30 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -32,6 +32,7 @@ public function add( $args, $_ ) { $users = $this->fetcher->get_many( $args ); $user_logins = wp_list_pluck( $users, 'user_login' ); $super_admins = self::get_admins(); + $num_super_admins = count( $super_admins ); foreach ( $user_logins as $user_login ) { $user = get_user_by( 'login', $user_login ); @@ -49,8 +50,14 @@ public function add( $args, $_ ) { $super_admins[] = $user->user_login; } - if ( update_site_option( 'site_admins' , $super_admins ) ) { - WP_CLI::success( 'Granted super-admin capabilities.' ); + if ( $num_super_admins === count( $super_admins ) ) { + WP_CLI::log( 'No changes.' ); + } else { + if ( update_site_option( 'site_admins' , $super_admins ) ) { + WP_CLI::success( 'Granted super-admin capabilities.' ); + } else { + WP_CLI::error( 'Site options update failed!' ); + } } } From fce03bbf541dcab1b82411814b5b511bdc0c314e Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Fri, 13 Nov 2015 14:57:14 -0500 Subject: [PATCH 3826/5359] add duplicate prevention feature test for super-admin add --- features/super-admin.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/super-admin.feature b/features/super-admin.feature index a7a5ea1e4..f53b2ba35 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -17,6 +17,14 @@ Feature: Manage super admins associated with a multisite instance superadmin """ + When I run `wp super-admin add superadmin` + And I run `wp super-admin list` + Then STDOUT should be: + """ + admin + superadmin + """ + When I run `wp super-admin remove admin` And I run `wp super-admin list` Then STDOUT should be: From 22a7aa6a09b8b0a1dc75855ae8f7479572e66893 Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Fri, 13 Nov 2015 14:58:27 -0500 Subject: [PATCH 3827/5359] whitespace --- features/super-admin.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index f53b2ba35..b4d523858 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -21,8 +21,8 @@ Feature: Manage super admins associated with a multisite instance And I run `wp super-admin list` Then STDOUT should be: """ - admin - superadmin + admin + superadmin """ When I run `wp super-admin remove admin` From e97a67975be0e8a693474940b9a870cdb69c65af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 13 Nov 2015 12:53:22 -0800 Subject: [PATCH 3828/5359] Use safe version of parent theme slug for child enequeue function A parent theme can include dashes, which aren't safe for a function. Also passes `slug` to the template, so the ID for the child theme stylesheet is populated. --- php/commands/scaffold.php | 2 ++ templates/child_theme_functions.mustache | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 873a7faa1..100b621e0 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -318,6 +318,8 @@ function child_theme( $args, $assoc_args ) { 'author_uri' => "", 'theme_uri' => "" ) ); + $data['slug'] = $theme_slug; + $data['parent_theme_function_safe'] = str_replace( '-', '_', $data['parent_theme'] ); $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index 1c0809939..395cf0def 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -1,8 +1,8 @@ <?php -add_action( 'wp_enqueue_scripts', '{{parent_theme}}_parent_theme_enqueue_styles' ); +add_action( 'wp_enqueue_scripts', '{{parent_theme_function_safe}}_parent_theme_enqueue_styles' ); -function {{parent_theme}}_parent_theme_enqueue_styles() { +function {{parent_theme_function_safe}}_parent_theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); wp_enqueue_style( '{{slug}}-style', get_stylesheet_directory_uri() . '/style.css', From 336d529d2dfa8b095fae97d85b47cc80bf81ddb1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 14 Nov 2015 12:04:34 -0800 Subject: [PATCH 3829/5359] Clarify documentation for `wp cache flush` When using a persistent object cache with Multisite, flushing is typically a global operation. --- php/commands/cache.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/cache.php b/php/commands/cache.php index dcc729d57..6fe77130d 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -95,6 +95,9 @@ public function delete( $args, $assoc_args ) { /** * Flush the object cache. + * + * For sites using a persistent object cache, because WordPress Multisite simply adds a blog id + * to the cache key, flushing cache is typically a global operation. */ public function flush( $args, $assoc_args ) { $value = wp_cache_flush(); From 27ee1df363fad6e0e8f47638b74d63c783606229 Mon Sep 17 00:00:00 2001 From: Dave Leach <dave@dmleach.com> Date: Sun, 15 Nov 2015 12:17:30 -0500 Subject: [PATCH 3830/5359] 2209: Added in_color property to base logger; added relevant unit tests --- php/WP_CLI/Loggers/Base.php | 14 +++++++++++++- tests/test-logging.php | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php index ef6fab196..4354e87a4 100644 --- a/php/WP_CLI/Loggers/Base.php +++ b/php/WP_CLI/Loggers/Base.php @@ -7,19 +7,31 @@ */ abstract class Base { + protected $in_color = false; + abstract public function info( $message ); abstract public function success( $message ); abstract public function warning( $message ); + /** + * Retrieve the runner instance from the base CLI object. This facilitates + * unit testing, where the WP_CLI instance isn't available + * + * @return Runner Instance of the runner class + */ + protected function getRunner() { + return \WP_CLI::get_runner(); + } + /** * Write a message to STDERR, prefixed with "Debug: ". * * @param string $message Message to write. */ public function debug( $message ) { - if ( \WP_CLI::get_runner()->config['debug'] ) { + if ( $this->getRunner()->config['debug'] ) { $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); } diff --git a/tests/test-logging.php b/tests/test-logging.php index 02899d9a8..c047943e6 100644 --- a/tests/test-logging.php +++ b/tests/test-logging.php @@ -1,17 +1,48 @@ <?php -class LoggerMock extends WP_CLI\Loggers\Regular { +class MockRegularLogger extends WP_CLI\Loggers\Regular { + + protected function getRunner() { + return (object) array ( + 'config' => array ( + 'debug' => true + ) + ); + } protected function write( $handle, $str ) { echo $str; } } +class MockQuietLogger extends WP_CLI\Loggers\Quiet { + + protected function getRunner() { + return (object) array ( + 'config' => array ( + 'debug' => true + ) + ); + } +} class LoggingTests extends PHPUnit_Framework_TestCase { + function testLogDebug() { + define( 'WP_CLI_START_MICROTIME', microtime( true ) ); + $message = 'This is a test message.'; + + $regularLogger = new MockRegularLogger( false ); + $this->expectOutputRegex( "/Debug: {$message} \(\d+\.*\d*s\)/" ); + $regularLogger->debug( $message ); + + $quietLogger = new MockQuietLogger(); + $this->expectOutputRegex( "/Debug: {$message} \(\d+\.*\d*s\)/" ); + $quietLogger->debug( $message ); + } + function testLogEscaping() { - $logger = new LoggerMock( false ); + $logger = new MockRegularLogger( false ); $message = 'foo%20bar'; @@ -19,4 +50,3 @@ function testLogEscaping() { $logger->success( $message ); } } - From 0dacfc831c67d9ce08ee933b923ad2f147384063 Mon Sep 17 00:00:00 2001 From: Ryan Williams <ryrowi@gmail.com> Date: Mon, 16 Nov 2015 10:09:33 -0500 Subject: [PATCH 3831/5359] update super-admin tests to include warning message check --- features/super-admin.feature | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index b4d523858..ac6a5b7a6 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -18,7 +18,12 @@ Feature: Manage super admins associated with a multisite instance """ When I run `wp super-admin add superadmin` - And I run `wp super-admin list` + Then STDERR should contain: + """ + Warning: User superadmin already has super-admin capabilities. + """ + + When I run `wp super-admin list` Then STDOUT should be: """ admin From b2e8eddc6a45bdfa79b28de3487c34dba8e4c472 Mon Sep 17 00:00:00 2001 From: Dave Leach <dave@dmleach.com> Date: Mon, 16 Nov 2015 10:40:17 -0500 Subject: [PATCH 3832/5359] 2209: Renamed getRunner to get_runner to fit naming convention --- php/WP_CLI/Loggers/Base.php | 4 ++-- tests/test-logging.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php index 4354e87a4..2f36446ce 100644 --- a/php/WP_CLI/Loggers/Base.php +++ b/php/WP_CLI/Loggers/Base.php @@ -21,7 +21,7 @@ abstract public function warning( $message ); * * @return Runner Instance of the runner class */ - protected function getRunner() { + protected function get_runner() { return \WP_CLI::get_runner(); } @@ -31,7 +31,7 @@ protected function getRunner() { * @param string $message Message to write. */ public function debug( $message ) { - if ( $this->getRunner()->config['debug'] ) { + if ( $this->get_runner()->config['debug'] ) { $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); } diff --git a/tests/test-logging.php b/tests/test-logging.php index c047943e6..98604965f 100644 --- a/tests/test-logging.php +++ b/tests/test-logging.php @@ -2,7 +2,7 @@ class MockRegularLogger extends WP_CLI\Loggers\Regular { - protected function getRunner() { + protected function get_runner() { return (object) array ( 'config' => array ( 'debug' => true @@ -17,7 +17,7 @@ protected function write( $handle, $str ) { class MockQuietLogger extends WP_CLI\Loggers\Quiet { - protected function getRunner() { + protected function get_runner() { return (object) array ( 'config' => array ( 'debug' => true From ee935ba2c810afc1472298e50e9628a74e8cd452 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 Nov 2015 07:50:13 -0800 Subject: [PATCH 3833/5359] Fix test indentation --- features/super-admin.feature | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index ac6a5b7a6..656499e23 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -5,34 +5,34 @@ Feature: Manage super admins associated with a multisite instance When I run `wp user create superadmin superadmin@example.com` And I run `wp super-admin list` Then STDOUT should be: - """ - admin - """ + """ + admin + """ When I run `wp super-admin add superadmin` And I run `wp super-admin list` Then STDOUT should be: - """ - admin - superadmin - """ + """ + admin + superadmin + """ When I run `wp super-admin add superadmin` Then STDERR should contain: - """ - Warning: User superadmin already has super-admin capabilities. - """ + """ + Warning: User superadmin already has super-admin capabilities. + """ When I run `wp super-admin list` Then STDOUT should be: - """ - admin - superadmin - """ + """ + admin + superadmin + """ When I run `wp super-admin remove admin` And I run `wp super-admin list` Then STDOUT should be: - """ - superadmin - """ + """ + superadmin + """ From 55b23591b88c2f517948a2bb9285a2028b5b12cb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 Nov 2015 10:30:12 -0800 Subject: [PATCH 3834/5359] Suppress notices when using `is_readable()` If `open_basedir` is in effect, PHP will throw a notice when `is_readable()` is used on an unreadable directory. We _could_ have some more complicated check to see if the path being checked is within `open_basedir` defined paths, but checking the return value of `is_readable()` is sufficient for our needs. --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 22e3281a4..7d1f9afad 100644 --- a/php/utils.php +++ b/php/utils.php @@ -142,7 +142,7 @@ function find_file_upward( $files, $dir = null, $stop_check = null ) { if ( is_null( $dir ) ) { $dir = getcwd(); } - while ( is_readable( $dir ) ) { + while ( @is_readable( $dir ) ) { // Stop walking up when the supplied callable returns true being passed the $dir if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { return null; From 39bcee6f9a3bc270e1c8211e1c0070d5c7d34015 Mon Sep 17 00:00:00 2001 From: 2ndkauboy <bernhard@kau-boys.de> Date: Tue, 17 Nov 2015 18:05:13 +0100 Subject: [PATCH 3835/5359] prepend `all_items` label with `All `, as it is the default for CPTs --- templates/post_type.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index 68e0814b0..a86f73131 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -2,7 +2,7 @@ 'labels' => array( 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), - 'all_items' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), + 'all_items' => __( 'All {{label_plural_ucfirst}}', '{{textdomain}}' ), 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), 'add_new' => __( 'Add New', '{{textdomain}}' ), 'add_new_item' => __( 'Add New {{label}}', '{{textdomain}}' ), From 3d40b4a4f8a67634c0f4cbfd0bdc9f8ce654f162 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 17 Nov 2015 10:13:47 -0800 Subject: [PATCH 3836/5359] Make sure we download redirected version of nightly Otherwise, we'll just download the redirect --- templates/install-package-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-package-tests.sh b/templates/install-package-tests.sh index cbde91ef2..37fa69525 100644 --- a/templates/install-package-tests.sh +++ b/templates/install-package-tests.sh @@ -16,7 +16,7 @@ install_wp_cli() { # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR mkdir -p $WP_CLI_BIN_DIR - download https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp + download https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp chmod +x $WP_CLI_BIN_DIR/wp } From a3f54a26d9a15cf91f7a6921ee3338591d60afc1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 06:06:51 -0800 Subject: [PATCH 3837/5359] Include more files in `wp-settings-cli.php` in prep for WP 4.4 See https://core.trac.wordpress.org/changeset/35718#file17 Also updates `Utils\maybe_require()` to handle `$wp_version` with `-src` in the value. --- php/utils-wp.php | 5 ++--- php/wp-settings-cli.php | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index 8501ce7ad..934c324b5 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -56,10 +56,9 @@ function wp_redirect_handler( $url ) { } function maybe_require( $since, $path ) { - global $wp_version; - - if ( version_compare( $wp_version, $since, '>=' ) ) + if ( version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, '>=' ) ) { require $path; + } } function get_upgrader( $class ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 6a7f4b58e..544f2cfb5 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -150,27 +150,41 @@ require( ABSPATH . WPINC . '/class-wp-ajax-response.php' ); require( ABSPATH . WPINC . '/formatting.php' ); require( ABSPATH . WPINC . '/capabilities.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-roles.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-role.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-user.php' ); require( ABSPATH . WPINC . '/query.php' ); Utils\maybe_require( '3.7-alpha-25139', ABSPATH . WPINC . '/date.php' ); require( ABSPATH . WPINC . '/theme.php' ); require( ABSPATH . WPINC . '/class-wp-theme.php' ); require( ABSPATH . WPINC . '/template.php' ); require( ABSPATH . WPINC . '/user.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-user-query.php' ); Utils\maybe_require( '4.0', ABSPATH . WPINC . '/session.php' ); require( ABSPATH . WPINC . '/meta.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-meta-query.php' ); require( ABSPATH . WPINC . '/general-template.php' ); require( ABSPATH . WPINC . '/link-template.php' ); require( ABSPATH . WPINC . '/author-template.php' ); require( ABSPATH . WPINC . '/post.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page-dropdown.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-post.php' ); require( ABSPATH . WPINC . '/post-template.php' ); Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/revision.php' ); Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/post-formats.php' ); require( ABSPATH . WPINC . '/post-thumbnail-template.php' ); require( ABSPATH . WPINC . '/category.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-category.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-category-dropdown.php' ); require( ABSPATH . WPINC . '/category-template.php' ); require( ABSPATH . WPINC . '/comment.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-comment.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-comment-query.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-comment.php' ); require( ABSPATH . WPINC . '/comment-template.php' ); require( ABSPATH . WPINC . '/rewrite.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-rewrite.php' ); require( ABSPATH . WPINC . '/feed.php' ); require( ABSPATH . WPINC . '/bookmark.php' ); require( ABSPATH . WPINC . '/bookmark-template.php' ); @@ -179,20 +193,33 @@ require( ABSPATH . WPINC . '/deprecated.php' ); require( ABSPATH . WPINC . '/script-loader.php' ); require( ABSPATH . WPINC . '/taxonomy.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-term.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-tax-query.php' ); require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/embed.php' ); Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); -Utils\maybe_require( '4.4-alpha-34851', ABSPATH . WPINC . '/embed-functions.php' ); Utils\maybe_require( '4.4-alpha-34903', ABSPATH . WPINC . '/class-wp-oembed-controller.php' ); require( ABSPATH . WPINC . '/http.php' ); require_once( ABSPATH . WPINC . '/class-http.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-streams.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-curl.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-proxy.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-cookie.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-encoding.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-response.php' ); require( ABSPATH . WPINC . '/widgets.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget-factory.php' ); require( ABSPATH . WPINC . '/nav-menu.php' ); require( ABSPATH . WPINC . '/nav-menu-template.php' ); require( ABSPATH . WPINC . '/admin-bar.php' ); Utils\maybe_require( '4.4-alpha-34928', ABSPATH . WPINC . '/rest-api.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' ); +Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' ); // Load multisite-specific files. if ( is_multisite() ) { From 72d36c714ecc3050944824fdf447aa64a4af3fec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 07:09:36 -0800 Subject: [PATCH 3838/5359] Switch to git clone of trunk The nightly build is always later than we want it to be --- ci/prepare.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index a279e3158..b02a1e94e 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -25,8 +25,8 @@ chmod +x $WP_CLI_BIN_DIR/wp if [[ $WP_VERSION == "trunk" ]] then - wget https://wordpress.org/nightly-builds/wordpress-latest.zip - unzip wordpress-latest.zip + git clone --depth 1 git@github.com:WordPress/WordPress.git wordpress + rm -rf wordpress/.git mv wordpress '/tmp/wp-cli-test core-download-cache/' else ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' From f4d5c98d5a12c2a06750bc9111598168326230e5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 07:28:20 -0800 Subject: [PATCH 3839/5359] Even easier: use the Github version of WP nightly --- ci/prepare.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index b02a1e94e..6a9f00279 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -25,9 +25,9 @@ chmod +x $WP_CLI_BIN_DIR/wp if [[ $WP_VERSION == "trunk" ]] then - git clone --depth 1 git@github.com:WordPress/WordPress.git wordpress - rm -rf wordpress/.git - mv wordpress '/tmp/wp-cli-test core-download-cache/' + wget https://github.com/WordPress/WordPress/archive/master.zip + unzip -q master.zip + mv WordPress-master '/tmp/wp-cli-test core-download-cache/' else ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' fi From deb0af97a525efacbe81dbba1309e5642bf2f16e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 07:54:06 -0800 Subject: [PATCH 3840/5359] Revert "Switch to git clone of trunk" Akismet isn't packaged with the Github version of WordPress This reverts commit 72d36c714ecc3050944824fdf447aa64a4af3fec. --- ci/prepare.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 6a9f00279..a279e3158 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -25,9 +25,9 @@ chmod +x $WP_CLI_BIN_DIR/wp if [[ $WP_VERSION == "trunk" ]] then - wget https://github.com/WordPress/WordPress/archive/master.zip - unzip -q master.zip - mv WordPress-master '/tmp/wp-cli-test core-download-cache/' + wget https://wordpress.org/nightly-builds/wordpress-latest.zip + unzip wordpress-latest.zip + mv wordpress '/tmp/wp-cli-test core-download-cache/' else ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' fi From c4ec8439183cdc0f25761cead532c487e817513e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 09:12:29 -0800 Subject: [PATCH 3841/5359] Failing test case for #1719 --- features/search-replace.feature | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index f684f9ed4..f3f943f1b 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -95,6 +95,30 @@ Feature: Do global search/replace world, Hello """ + Scenario: Search and replace within theme mods + Given a WP install + And a setup-theme-mod.php file: + """ + <?php + set_theme_mod( 'header_image_data', (object) array( 'url' => 'http://subdomain.example.com/foo.jpg' ) ); + """ + And I run `wp eval-file setup-theme-mod.php` + + When I run `wp theme mod get header_image_data` + Then STDOUT should be a table containing rows: + | key | value | + | header_image_data | {"url":"http:\/\/subdomain.example.com\/foo.jpg"} | + + When I run `wp search-replace subdomain.example.com example.com` + Then STDERR should be empty + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 1 | PHP | + + When I run `wp theme mod get header_image_data` + Then STDOUT should be a table containing rows: + | key | value | + | header_image_data | {"url":"http:\/\/example.com\/foo.jpg"} | Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install From eff58d25b6b6252bcc9b5b512386831531d1786c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 09:18:07 -0800 Subject: [PATCH 3842/5359] Recurse objects by default when replacing inside of serialized data However, if `--no-recurse-objects` is provided, respect that flag too. --- features/search-replace.feature | 6 +++++- php/commands/search-replace.php | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index f3f943f1b..fce672361 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -109,8 +109,12 @@ Feature: Do global search/replace | key | value | | header_image_data | {"url":"http:\/\/subdomain.example.com\/foo.jpg"} | + When I run `wp search-replace subdomain.example.com example.com --no-recurse-objects` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 0 | PHP | + When I run `wp search-replace subdomain.example.com example.com` - Then STDERR should be empty Then STDOUT should be a table containing rows: | Table | Column | Replacements | Type | | wp_options | option_value | 1 | PHP | diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f3c1b2f00..c23d72c26 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -118,6 +118,9 @@ public function __invoke( $args, $assoc_args ) { if ( $php_only || $regex || NULL !== $serialRow ) { $type = 'PHP'; + if ( ! empty( $serialRow ) && null === $recurse_objects ) { + $recurse_objects = true; + } $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); } else { $type = 'SQL'; From a6ce33e5d13893c8574243bedb2157432f6803f8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 10:18:11 -0800 Subject: [PATCH 3843/5359] Actually default to recursing objects in a bc way We shouldn't blindly recurse objects *just* when we've detected serialized data. --- php/commands/search-replace.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c23d72c26..ed491cbd7 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -74,7 +74,7 @@ public function __invoke( $args, $assoc_args ) { $report = array(); $dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); - $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects' ); + $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); $verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); $regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); @@ -118,9 +118,6 @@ public function __invoke( $args, $assoc_args ) { if ( $php_only || $regex || NULL !== $serialRow ) { $type = 'PHP'; - if ( ! empty( $serialRow ) && null === $recurse_objects ) { - $recurse_objects = true; - } $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); } else { $type = 'SQL'; From 72499dac5f7193668e75d3b1e816494d532b5d10 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 20 Nov 2015 10:21:56 -0800 Subject: [PATCH 3844/5359] Clarify default behavior for `--recurse-objects` --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ed491cbd7..8d7e5373f 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -43,7 +43,7 @@ class Search_Replace_Command extends WP_CLI_Command { * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. * * [--recurse-objects] - * : Enable recursing into objects to replace strings + * : Enable recursing into objects to replace strings. Defaults to true; pass --no-recurse-objects to disable. * * [--all-tables-with-prefix] * : Enable replacement on any tables that match the table prefix even if not registered on wpdb From bbba16dc24b53f3a5a9992edfdb80e9d0f614c05 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 05:14:27 -0800 Subject: [PATCH 3845/5359] Failing test case for #1613 --- features/search-replace.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index fce672361..99d174240 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -124,6 +124,29 @@ Feature: Do global search/replace | key | value | | header_image_data | {"url":"http:\/\/example.com\/foo.jpg"} | + Scenario: Search and replace with quoted strings + Given a WP install + + When I run `wp post create --post_content='<a href="http://apple.com">Apple</a>' --porcelain` + Then save STDOUT as {POST_ID} + + When I run `wp post get {POST_ID} --field=content` + Then STDOUT should be: + """ + <a href="http://apple.com">Apple</a> + """ + + When I run `wp search-replace '<a href="http://apple.com">Apple</a>' '<a href="http://google.com">Google</a>'` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_posts | post_content | 1 | PHP | + + When I run `wp post get {POST_ID} --field=content` + Then STDOUT should be: + """ + <a href="http://google.com">Google</a> + """ + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` From 02755f06851a85afeed68a2058b4e6816700a0ff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 05:29:06 -0800 Subject: [PATCH 3846/5359] Correct test to specify `SQL` --- features/search-replace.feature | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 99d174240..65d135a61 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -136,10 +136,15 @@ Feature: Do global search/replace <a href="http://apple.com">Apple</a> """ + When I run `wp search-replace '<a href="http://apple.com">Apple</a>' '<a href="http://google.com">Google</a>' --dry-run` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_posts | post_content | 1 | SQL | + When I run `wp search-replace '<a href="http://apple.com">Apple</a>' '<a href="http://google.com">Google</a>'` Then STDOUT should be a table containing rows: | Table | Column | Replacements | Type | - | wp_posts | post_content | 1 | PHP | + | wp_posts | post_content | 1 | SQL | When I run `wp post get {POST_ID} --field=content` Then STDOUT should be: From 23e40059b2d35ff9d3a370e01d5480a0967736bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 05:29:50 -0800 Subject: [PATCH 3847/5359] Properly prepare value passed to search / replace Ensures quotes, etc. are properly escaped --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 8d7e5373f..0022419a5 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -237,7 +237,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $args = array( 'table' => $table, 'fields' => $fields, - 'where' => $regex ? '' : "`$col`" . ' LIKE "%' . self::esc_like( $old ) . '%"', + 'where' => $regex ? '' : "`$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ), 'chunk_size' => $chunk_size ); From da293006e6d9a1ab0b18eaace11f0e3846278c87 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 05:34:40 -0800 Subject: [PATCH 3848/5359] Break out `wp post generate` tests to `features/post-generate.feature` --- features/post-generate.feature | 33 +++++++++++++++++++++++++++++++++ features/post.feature | 29 ----------------------------- 2 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 features/post-generate.feature diff --git a/features/post-generate.feature b/features/post-generate.feature new file mode 100644 index 000000000..9a3e039c5 --- /dev/null +++ b/features/post-generate.feature @@ -0,0 +1,33 @@ +Feature: Generate new WordPress posts + + Background: + Given a WP install + + Scenario: Generating posts + When I run `echo "Content generated by wp post generate" | wp post generate --count=1 --post_content` + And I run `wp post list --field=post_content` + Then STDOUT should contain: + """ + Content generated by wp post generate + """ + And STDERR should be empty + + Scenario: Generating posts by a specific author + + When I run `wp user create dummyuser dummy@example.com --porcelain` + Then save STDOUT as {AUTHOR_ID} + + When I run `wp post generate --post_author={AUTHOR_ID} --post_type=post --count=16` + And I run `wp post list --post_type=post --author={AUTHOR_ID} --format=count` + Then STDOUT should contain: + """ + 16 + """ + + Scenario: Generating pages + When I run `wp post generate --post_type=page --max_depth=10` + And I run `wp post list --post_type=page --field=post_parent` + Then STDOUT should contain: + """ + 1 + """ diff --git a/features/post.feature b/features/post.feature index 31d909306..d9e5e0793 100644 --- a/features/post.feature +++ b/features/post.feature @@ -188,35 +188,6 @@ Feature: Manage WordPress posts Sample Page """ - Scenario: Generating posts - When I run `echo "Content generated by wp post generate" | wp post generate --count=1 --post_content` - And I run `wp post list --field=post_content` - Then STDOUT should contain: - """ - Content generated by wp post generate - """ - And STDERR should be empty - - Scenario: Generating posts by a specific author - - When I run `wp user create dummyuser dummy@example.com --porcelain` - Then save STDOUT as {AUTHOR_ID} - - When I run `wp post generate --post_author={AUTHOR_ID} --post_type=post --count=16` - And I run `wp post list --post_type=post --author={AUTHOR_ID} --format=count` - Then STDOUT should contain: - """ - 16 - """ - - Scenario: Generating pages - When I run `wp post generate --post_type=page --max_depth=10` - And I run `wp post list --post_type=page --field=post_parent` - Then STDOUT should contain: - """ - 1 - """ - Scenario: Update categories on a post When I run `wp term create category "Test Category" --porcelain` Then save STDOUT as {TERM_ID} From cb455dfc2c2c865d8c01e1fe1e51a00e0e4ffbc2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 09:01:07 -0800 Subject: [PATCH 3849/5359] Support wildcards / globs in table names with `wp search-replace` --- features/search-replace.feature | 72 +++++++++++++++++++++++++++++++++ php/commands/search-replace.php | 45 ++++++++++++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 65d135a61..412048056 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -57,6 +57,78 @@ Feature: Do global search/replace awesome_table """ + @daniel + Scenario: Run on all tables matching string with wildcard + Given a WP install + + When I run `wp option set bar foo` + And I run `wp option get bar` + Then STDOUT should be: + """ + foo + """ + + When I run `wp post create --post_title=bar --porcelain` + Then save STDOUT as {POST_ID} + + When I run `wp post meta add {POST_ID} foo bar` + Then STDOUT should not be empty + + When I run `wp search-replace bar burrito wp_post\?` + And STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_posts | post_title | 1 | SQL | + And STDOUT should not contain: + """ + wp_options + """ + + When I run `wp post get {POST_ID} --field=title` + Then STDOUT should be: + """ + burrito + """ + + When I run `wp post meta get {POST_ID} foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp option get bar` + Then STDOUT should be: + """ + foo + """ + + When I try `wp search-replace foo burrito wp_opt\*on` + Then STDERR should be: + """ + Error: Couldn't find any tables matching: wp_opt*on + """ + + When I run `wp search-replace foo burrito wp_opt\* wp_postme\*` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 1 | PHP | + | wp_postmeta | meta_key | 1 | SQL | + And STDOUT should not contain: + """ + wp_posts + """ + + When I run `wp option get bar` + Then STDOUT should be: + """ + burrito + """ + + When I run `wp post meta get {POST_ID} burrito` + Then STDOUT should be: + """ + bar + """ + Scenario: Quiet search/replace Given a WP install diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0022419a5..47926894a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -28,7 +28,7 @@ class Search_Replace_Command extends WP_CLI_Command { * : The new string. * * [<table>...] - * : List of database tables to restrict the replacement to. + * : List of database tables to restrict the replacement to. Wildcards are supported, e.g. wp_\*_options or wp_post\?. * * [--network] * : Search/replace through all the tables in a multisite install. @@ -64,7 +64,7 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production database into a local database - * wp search-replace --url=example.com example.com example.dev + * wp search-replace --url=example.com example.com example.dev wp_\*_options */ public function __invoke( $args, $assoc_args ) { global $wpdb; @@ -95,6 +95,22 @@ public function __invoke( $args, $assoc_args ) { $table_type = 'all-tables'; } + if ( ! empty( $args ) ) { + $new_tables = array(); + foreach( $args as $key => $table ) { + if ( false !== strpos( $table, '*' ) || false !== strpos( $table, '?' ) ) { + $expanded_tables = self::get_tables_for_glob( $table ); + if ( empty( $expanded_tables ) ) { + WP_CLI::error( "Couldn't find any tables matching: {$table}" ); + } + $new_tables = array_merge( $new_tables, $expanded_tables ); + } else { + $new_tables[] = $table; + } + } + $args = $new_tables; + } + // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use $tables = empty( $args ) ? self::get_table_list( $table_type ) : $args; foreach ( $tables as $table ) { @@ -295,6 +311,31 @@ private static function get_columns( $table ) { return array( $primary_keys, $columns ); } + /** + * Get all the tables that match a glob pattern + * + * @param string $glob + * @return array + */ + private static function get_tables_for_glob( $glob ) { + + static $all_tables = array(); + + if ( ! $all_tables ) { + $all_tables = self::get_table_list( 'all-tables' ); + } + + $tables = array(); + + foreach ( $all_tables as $table) { + if ( fnmatch( $glob, $table ) ) { + $tables[] = $table; + } + } + + return $tables; + } + private static function is_text_col( $type ) { foreach ( array( 'text', 'varchar' ) as $token ) { if ( false !== strpos( $type, $token ) ) From cc0b05db6223fd90a6d765227fdfb75e147ccfa1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 09:09:45 -0800 Subject: [PATCH 3850/5359] In `wp import`, use `WP_CLI::log()` instead of `WP_CLI::line()` The former gives us more control over verbosity. --- php/commands/import.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index 815d137df..40b9c31bf 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -57,7 +57,7 @@ public function __invoke( $args, $assoc_args ) { if ( is_wp_error( $ret ) ) { WP_CLI::error( $ret ); } else { - WP_CLI::line(); // WXR import ends with HTML, so make sure message is on next line + WP_CLI::log(''); // WXR import ends with HTML, so make sure message is on next line WP_CLI::success( "Finished importing from $file file." ); } } @@ -170,11 +170,11 @@ private function add_wxr_filters() { global $wpcli_import_counts; $wpcli_import_counts['current_post']++; - WP_CLI::line(); - WP_CLI::line(); - WP_CLI::line( sprintf( 'Processing post #%d ("%s") (post_type: %s)', $post['post_id'], $post['post_title'], $post['post_type'] ) ); - WP_CLI::line( sprintf( '-- %s of %s', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ) ) ); - WP_CLI::line( '-- ' . date( 'r' ) ); + WP_CLI::log(''); + WP_CLI::log(''); + WP_CLI::log( sprintf( 'Processing post #%d ("%s") (post_type: %s)', $post['post_id'], $post['post_title'], $post['post_type'] ) ); + WP_CLI::log( sprintf( '-- %s of %s', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ) ) ); + WP_CLI::log( '-- ' . date( 'r' ) ); return $post; } ); @@ -184,32 +184,32 @@ private function add_wxr_filters() { if ( is_wp_error( $post_id ) ) { WP_CLI::warning( "-- Error importing post: " . $post_id->get_error_code() ); } else { - WP_CLI::line( "-- Imported post as post_id #{$post_id}" ); + WP_CLI::log( "-- Imported post as post_id #{$post_id}" ); } if ( $wpcli_import_counts['current_post'] % 500 === 0 ) { WP_CLI\Utils\wp_clear_object_cache(); - WP_CLI::line( "-- Cleared object cache." ); + WP_CLI::log( "-- Cleared object cache." ); } }, 10, 4 ); add_action( 'wp_import_insert_term', function( $t, $import_term, $post_id, $post ) { - WP_CLI::line( "-- Created term \"{$import_term['name']}\"" ); + WP_CLI::log( "-- Created term \"{$import_term['name']}\"" ); }, 10, 4 ); add_action( 'wp_import_set_post_terms', function( $tt_ids, $term_ids, $taxonomy, $post_id, $post ) { - WP_CLI::line( "-- Added terms (" . implode( ',', $term_ids ) .") for taxonomy \"{$taxonomy}\"" ); + WP_CLI::log( "-- Added terms (" . implode( ',', $term_ids ) .") for taxonomy \"{$taxonomy}\"" ); }, 10, 5 ); add_action( 'wp_import_insert_comment', function( $comment_id, $comment, $comment_post_ID, $post ) { global $wpcli_import_counts; $wpcli_import_counts['current_comment']++; - WP_CLI::line( sprintf( '-- Added comment #%d (%s of %s)', $comment_id, number_format( $wpcli_import_counts['current_comment'] ), number_format( $wpcli_import_counts['total_comments'] ) ) ); + WP_CLI::log( sprintf( '-- Added comment #%d (%s of %s)', $comment_id, number_format( $wpcli_import_counts['current_comment'] ), number_format( $wpcli_import_counts['total_comments'] ) ) ); }, 10, 4 ); add_action( 'import_post_meta', function( $post_id, $key, $value ) { - WP_CLI::line( "-- Added post_meta $key" ); + WP_CLI::log( "-- Added post_meta $key" ); }, 10, 3 ); } From c95e1e60f381f7d5249470a10b5d15dcc4422f5a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 09:28:28 -0800 Subject: [PATCH 3851/5359] Bail early on search-replace when terms are the same Let's help save developers from themselves. --- features/search-replace.feature | 10 ++++++++++ php/commands/search-replace.php | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 65d135a61..9c0240136 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -152,6 +152,16 @@ Feature: Do global search/replace <a href="http://google.com">Google</a> """ + Scenario: Search and replace with the same terms + Given a WP install + + When I run `wp search-replace foo foo` + Then STDERR should be: + """ + Warning: Replacement value 'foo' is identical to search value 'foo'. Skipping operation. + """ + And STDOUT should be empty + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0022419a5..12407c961 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -80,6 +80,11 @@ public function __invoke( $args, $assoc_args ) { $skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); + if ( $old === $new && ! $regex ) { + WP_CLI::warning( "Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation." ); + exit; + } + // never mess with hashed passwords $skip_columns[] = 'user_pass'; From dc5d690a5df0591ab9308f763749517fdbbcc10c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 09:34:49 -0800 Subject: [PATCH 3852/5359] Abstract cache type to helper utility --- php/commands/cache.php | 42 +-------------------------------- php/utils-wp.php | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index 6fe77130d..51df60802 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -230,47 +230,7 @@ public function set( $args, $assoc_args ) { * problems with this function's ability to determine which object cache is being used. */ public function type( $args, $assoc_args ) { - global $_wp_using_ext_object_cache, $wp_object_cache; - - if ( false !== $_wp_using_ext_object_cache ) { - // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) - if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) { - $message = 'Memcached'; - - // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) - } elseif ( isset( $wp_object_cache->mc ) ) { - $is_memcache = true; - foreach ( $wp_object_cache->mc as $bucket ) { - if ( ! is_a( $bucket, 'Memcache' ) ) - $is_memcache = false; - } - - if ( $is_memcache ) - $message = 'Memcache'; - - // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) - } elseif ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) { - $message = 'Xcache'; - - // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) - } elseif ( class_exists( 'WinCache_Object_Cache' ) ) { - $message = 'WinCache'; - - // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) - } elseif ( class_exists( 'APC_Object_Cache' ) ) { - $message = 'APC'; - - // Test for Redis Object Cache (https://github.com/alleyinteractive/wp-redis) - } elseif ( isset( $wp_object_cache->redis ) && is_a( $wp_object_cache->redis, 'Redis' ) ) { - $message = 'Redis'; - - } else { - $message = 'Unknown'; - } - } else { - $message = 'Default'; - } - + $message = WP_CLI\Utils\wp_get_cache_type(); WP_CLI::line( $message ); } } diff --git a/php/utils-wp.php b/php/utils-wp.php index 934c324b5..5d2c82d0f 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -131,6 +131,59 @@ function wp_register_unused_sidebar() { } +/** + * Attempts to determine which object cache is being used. + * + * Note that the guesses made by this function are based on the WP_Object_Cache classes + * that define the 3rd party object cache extension. Changes to those classes could render + * problems with this function's ability to determine which object cache is being used. + * + * @return string + */ +function wp_get_cache_type() { + global $_wp_using_ext_object_cache, $wp_object_cache; + + if ( ! empty( $_wp_using_ext_object_cache ) ) { + // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) + if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) { + $message = 'Memcached'; + + // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) + } elseif ( isset( $wp_object_cache->mc ) ) { + $is_memcache = true; + foreach ( $wp_object_cache->mc as $bucket ) { + if ( ! is_a( $bucket, 'Memcache' ) ) + $is_memcache = false; + } + + if ( $is_memcache ) + $message = 'Memcache'; + + // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) + } elseif ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) { + $message = 'Xcache'; + + // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) + } elseif ( class_exists( 'WinCache_Object_Cache' ) ) { + $message = 'WinCache'; + + // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) + } elseif ( class_exists( 'APC_Object_Cache' ) ) { + $message = 'APC'; + + // Test for Redis Object Cache (https://github.com/alleyinteractive/wp-redis) + } elseif ( isset( $wp_object_cache->redis ) && is_a( $wp_object_cache->redis, 'Redis' ) ) { + $message = 'Redis'; + + } else { + $message = 'Unknown'; + } + } else { + $message = 'Default'; + } + return $message; +} + /** * Clear all of the caches for memory management */ From 880c66699ee8bc0eeb27b81074e647bd122b114f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 09:39:00 -0800 Subject: [PATCH 3853/5359] Let users know to flush their persistent object cache after s/r --- php/commands/search-replace.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0022419a5..590bb495b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -138,7 +138,11 @@ public function __invoke( $args, $assoc_args ) { $table->display(); if ( ! $dry_run ) { - WP_CLI::success( "Made $total replacements." ); + $success_message = "Made $total replacements."; + if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { + $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; + } + WP_CLI::success( $success_message ); } } From f1be82a47708dcfc36ead84ee88865b1c9bef022 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 10:00:36 -0800 Subject: [PATCH 3854/5359] Introduce `wp_version_compare()` for comparing WP versions Tagged WordPress releases include `-src` in `$wp_version`, which `version_compare()` doesn't like. We need to make sure to strip it to get an accurate result. --- php/commands/core.php | 8 ++++---- php/commands/cron.php | 3 +-- php/commands/taxonomy.php | 3 +-- php/commands/user.php | 6 ++---- php/utils-wp.php | 6 +++++- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3520bf7c0..531866b64 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -64,7 +64,7 @@ function check_update( $_, $assoc_args ) { foreach ( $release_versions as $release_version ) { // don't list earliers versions - if ( version_compare( $release_version, $wp_version, '<=' ) ) + if ( \WP_CLI\Utils\wp_version_compare( $release_version, '>=' ) ) continue; $release_parts = explode( '.', $release_version ); @@ -385,7 +385,7 @@ public function config( $_, $assoc_args ) { 'https://api.wordpress.org/secret-key/1.1/salt/' ); } - if ( version_compare( $wp_version, '4.0', '<' ) ) { + if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { $assoc_args['add-wplang'] = true; } else { $assoc_args['add-wplang'] = false; @@ -945,7 +945,7 @@ function update( $args, $assoc_args ) { list( $update ) = $from_api->updates; } - } else if ( version_compare( $wp_version, $assoc_args['version'], '<' ) + } else if ( \WP_CLI\Utils\wp_version_compare( $assoc_args['version'], '<' ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { $version = $assoc_args['version']; @@ -1115,7 +1115,7 @@ class Core_Language_Command extends WP_CLI\CommandWithTranslation { WP_CLI::add_command( 'core language', 'Core_Language_Command', array( 'before_invoke' => function() { - if ( version_compare( $GLOBALS['wp_version'], '4.0', '<' ) ) { + if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { WP_CLI::error( "Requires WordPress 4.0 or greater." ); } }) diff --git a/php/commands/cron.php b/php/commands/cron.php index 7025c26b2..9dacd2656 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -509,9 +509,8 @@ public function test() { * @return WP_Error|array The response or WP_Error on failure. */ protected static function get_cron_spawn() { - global $wp_version; - $sslverify = version_compare( $wp_version, 4.0, '<' ); + $sslverify = \WP_CLI\Utils\wp_version_compare( 4.0, '<' ); $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); $cron_request = apply_filters( 'cron_request', array( diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index be26a0f16..7d34abe7e 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -17,9 +17,8 @@ class Taxonomy_Command extends WP_CLI_Command { ); public function __construct() { - global $wp_version; - if ( version_compare( $wp_version, 3.7, '<' ) ) { + if ( \WP_CLI\Utils\wp_version_compare( 3.7, '<' ) ) { // remove description for wp <= 3.7 $this->fields = array_values( array_diff( $this->fields, array( 'description' ) ) ); } diff --git a/php/commands/user.php b/php/commands/user.php index 4d11b1bdb..d3fd69bb9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -770,11 +770,9 @@ private static function validate_role( $role ) { * @param string $password */ private static function wp_new_user_notification( $user_id, $password ) { - global $wp_version; - $version = str_replace( '-src', '', $wp_version ); - if ( version_compare( $version, '4.3.1', '>=' ) ) { + if ( \WP_CLI\Utils\wp_version_compare( '4.3.1', '>=' ) ) { wp_new_user_notification( $user_id, null, 'both' ); - } else if ( version_compare( $version, '4.3', '>=' ) ) { + } else if ( \WP_CLI\Utils\wp_version_compare( '4.3', '>=' ) ) { wp_new_user_notification( $user_id, 'both' ); } else { wp_new_user_notification( $user_id, $password ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 934c324b5..a7414f42e 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -56,11 +56,15 @@ function wp_redirect_handler( $url ) { } function maybe_require( $since, $path ) { - if ( version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, '>=' ) ) { + if ( wp_version_compare( $since, '>=' ) ) { require $path; } } +function wp_version_compare( $since, $operator ) { + return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); +} + function get_upgrader( $class ) { if ( !class_exists( '\WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; From 59d2ca9c76e579e4fe0a4c9387f610b889b61a32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 10:52:07 -0800 Subject: [PATCH 3855/5359] Ensure `upload_space_check_disabled=>1` when installing multisite Because of how core executes `populate_network()`, this option is erroneously set to an empty value when WP-CLI installs multisite. The correct behavior is to disable multisite quotas by default on new installs. See https://core.trac.wordpress.org/ticket/21513 --- features/core.feature | 12 ++++++++++++ php/commands/core.php | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/features/core.feature b/features/core.feature index bdedea78a..c9d18e77b 100644 --- a/features/core.feature +++ b/features/core.feature @@ -242,6 +242,12 @@ Feature: Manage WordPress installation When I try `wp core install-network --title='test network'` Then the return code should be 1 + When I run `wp network meta get 1 upload_space_check_disabled` + Then STDOUT should be: + """ + 1 + """ + Scenario: Install multisite from scratch Given an empty directory And WP files @@ -261,6 +267,12 @@ Feature: Manage WordPress installation When I try `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` Then the return code should be 0 + When I run `wp network meta get 1 upload_space_check_disabled` + Then STDOUT should be: + """ + 1 + """ + Scenario: Install multisite from scratch, with MULTISITE already set in wp-config.php Given a WP multisite install And I run `wp db reset --yes` diff --git a/php/commands/core.php b/php/commands/core.php index 3520bf7c0..37eb975ec 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -663,6 +663,10 @@ private function _multisite_convert( $assoc_args ) { } } + // delete_site_option() cleans the alloptions cache to prevent dupe option + delete_site_option( 'upload_space_check_disabled' ); + update_site_option( 'upload_space_check_disabled', 1 ); + if ( !is_multisite() ) { $subdomain_export = Utils\get_flag_value( $assoc_args, 'subdomains' ) ? 'true' : 'false'; $ms_config = <<<EOT From 03de8042351530cdfc2e40f01432d0718fc34cc9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 12:18:28 -0800 Subject: [PATCH 3856/5359] Provide a more helpful message when image regeneration fails If only a single image was regenerated, the message will be: > An error occurred with image regeneration. If multiple images were regenerated, the message will be: > An error occurred regenerating one or more images. --- php/commands/media.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index e2f459943..9d9ff7a53 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -57,14 +57,21 @@ function regenerate( $args, $assoc_args = array() ) { WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, _n( 'image', 'images', $count ) ) ); + $errored = false; foreach ( $images->posts as $id ) { - $this->_process_regeneration( $id, $skip_delete ); + if ( ! $this->_process_regeneration( $id, $skip_delete ) ) { + $errored = true; + } } - WP_CLI::success( sprintf( - 'Finished regenerating %1$s.', - _n('the image', 'all images', $count) - ) ); + if ( $errored ) { + WP_CLI::log( _n( 'An error occurred with image regeneration.', 'An error occurred regenerating one or more images.', $count ) ); + } else { + WP_CLI::success( sprintf( + 'Finished regenerating %1$s.', + _n('the image', 'all images', $count) + ) ); + } } /** @@ -211,7 +218,7 @@ private function _process_regeneration( $id, $skip_delete = false ) { if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { WP_CLI::warning( "Can't find $att_desc" ); - return; + return false; } if ( ! $skip_delete ) { @@ -221,18 +228,18 @@ private function _process_regeneration( $id, $skip_delete = false ) { $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); if ( is_wp_error( $metadata ) ) { WP_CLI::warning( $metadata->get_error_message() ); - return; + return false; } if ( empty( $metadata ) ) { WP_CLI::warning( "Couldn't regenerate thumbnails for $att_desc." ); - return; + return false; } wp_update_attachment_metadata( $id, $metadata ); WP_CLI::log( "Regenerated thumbnails for $att_desc" ); - + return true; } private function remove_old_images( $att_id ) { From 3d527829fc020354dc51fc277e1edfd976adc8d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 12:26:19 -0800 Subject: [PATCH 3857/5359] Add tests for error state --- features/media.feature | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/features/media.feature b/features/media.feature index d0d0207a5..c753624e2 100644 --- a/features/media.feature +++ b/features/media.feature @@ -79,7 +79,10 @@ Feature: Manage WordPress attachments }); """ When I run `wp media regenerate --yes` - Then STDOUT should not be empty + Then STDOUT should contain: + """ + Success: Finished regenerating the image. + """ And the wp-content/uploads/large-image-100x100.jpg file should not exist And the wp-content/uploads/large-image-200x200.jpg file should exist @@ -108,7 +111,39 @@ Feature: Manage WordPress attachments }); """ When I run `wp media regenerate --skip-delete --yes` - Then STDOUT should not be empty + Then STDOUT should contain: + """ + Success: Finished regenerating the image. + """ And the wp-content/uploads/large-image-100x100.jpg file should exist And the wp-content/uploads/large-image-200x200.jpg file should exist + Scenario: Provide helpful error messages when media can't be regenerated + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 100, 100, true ); + }); + """ + And I run `wp option update uploads_use_yearmonth_folders 0` + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + And the wp-content/uploads/large-image-100x100.jpg file should exist + + When I run `rm wp-content/uploads/large-image.jpg` + Then STDOUT should be empty + + When I run `wp media regenerate --yes` + Then STDOUT should contain: + """ + An error occurred with image regeneration. + """ + And STDERR should contain: + """ + Warning: Can't find + """ From 9b891d82a9f03519c086fd4bee9062630ecfe731 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 Nov 2015 14:05:22 -0800 Subject: [PATCH 3858/5359] Move `wp_version_compare()` to `utils.php`, so it's aways available --- php/utils-wp.php | 4 ---- php/utils.php | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index e39cd11de..e3519af48 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -61,10 +61,6 @@ function maybe_require( $since, $path ) { } } -function wp_version_compare( $since, $operator ) { - return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); -} - function get_upgrader( $class ) { if ( !class_exists( '\WP_Upgrader' ) ) require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; diff --git a/php/utils.php b/php/utils.php index 7d1f9afad..69ad1c355 100644 --- a/php/utils.php +++ b/php/utils.php @@ -234,6 +234,10 @@ function locate_wp_config() { return $path; } +function wp_version_compare( $since, $operator ) { + return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); +} + /** * Output items in a table, JSON, CSV, ids, or the total count * From f9e61c1373a1e07bc5319293c5683993875c79a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 12:25:46 -0800 Subject: [PATCH 3859/5359] Indicate execution time when running search/replace with `--verbose` ``` Checking: wp_users.user_email 0 rows affected (0.002s) Checking: wp_users.user_url 0 rows affected (0.001s) Checking: wp_users.user_activation_key 0 rows affected (0.001s) Checking: wp_users.display_name 0 rows affected (0.002s) ``` This can be helpful for better understanding where bottlenecks are --- php/commands/search-replace.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 3059aa8ff..39c429900 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -239,13 +239,20 @@ private static function get_table_list( $limit_to ) { private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { global $wpdb; + if ( $verbose ) { + $time = microtime( true ); + WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); + } + if ( $dry_run ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } + if ( $verbose ) { - self::log_verbose_details( $table, $col, $count ); + $time = round( microtime( true ) - $time, 3 ); + WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); } return $count; } @@ -259,6 +266,11 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $fields = $primary_keys; $fields[] = $col; + if ( $verbose ) { + $time = microtime( true ); + WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); + } + $args = array( 'table' => $table, 'fields' => $fields, @@ -292,7 +304,8 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, } if ( $verbose ) { - self::log_verbose_details( $table, $col, $count ); + $time = round( microtime( true ) - $time, 3 ); + WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); } return $count; @@ -369,10 +382,6 @@ private static function esc_like( $old ) { return $old; } - private static function log_verbose_details( $table, $col, $count ) { - WP_CLI::log( sprintf( 'Checking: %s.%s' . PHP_EOL . '%d rows affected', $table, $col, $count ) ); - } - } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); From 354d4f4e412237894da8f4fcd1cd6451d82b3a77 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 12:37:10 -0800 Subject: [PATCH 3860/5359] Globalize `$wp_version` in a couple places we need it as a global --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 08450fa4c..b4ee483c6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -34,6 +34,7 @@ class Core_Command extends WP_CLI_Command { * @subcommand check-update */ function check_update( $_, $assoc_args ) { + global $wp_version; $versions_path = ABSPATH . 'wp-includes/version.php'; include $versions_path; @@ -345,6 +346,7 @@ private static function get_initial_locale() { * PHP */ public function config( $_, $assoc_args ) { + global $wp_version; if ( Utils\locate_wp_config() ) { WP_CLI::error( "The 'wp-config.php' file already exists." ); } From 1feb73e9ad1cd84efd5250f1c9d057e6c77b08bc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 15:03:03 -0800 Subject: [PATCH 3861/5359] Start time tracking earlier, to get serialization check --- php/commands/search-replace.php | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 39c429900..76e1c2f21 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -133,16 +133,21 @@ public function __invoke( $args, $assoc_args ) { continue; } + if ( $verbose ) { + $this->start_time = microtime( true ); + WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); + } + if ( ! $php_only ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } if ( $php_only || $regex || NULL !== $serialRow ) { $type = 'PHP'; - $count = self::php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); + $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); } else { $type = 'SQL'; - $count = self::sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ); + $count = $this->sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ); } $report[] = array( $table, $col, $count, $type ); @@ -236,14 +241,9 @@ private static function get_table_list( $limit_to ) { } - private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { + private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { global $wpdb; - if ( $verbose ) { - $time = microtime( true ); - WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); - } - if ( $dry_run ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { @@ -251,13 +251,13 @@ private static function sql_handle_col( $col, $table, $old, $new, $dry_run, $ver } if ( $verbose ) { - $time = round( microtime( true ) - $time, 3 ); + $time = round( microtime( true ) - $this->start_time, 3 ); WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); } return $count; } - private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ) { + private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -266,11 +266,6 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, $fields = $primary_keys; $fields[] = $col; - if ( $verbose ) { - $time = microtime( true ); - WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); - } - $args = array( 'table' => $table, 'fields' => $fields, @@ -304,7 +299,7 @@ private static function php_handle_col( $col, $primary_keys, $table, $old, $new, } if ( $verbose ) { - $time = round( microtime( true ) - $time, 3 ); + $time = round( microtime( true ) - $this->start_time, 3 ); WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); } From 995ea29c1393a48ee57c7916911b023a848944af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 15:04:22 -0800 Subject: [PATCH 3862/5359] Clarify what this means --- php/commands/search-replace.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 76e1c2f21..6777eb57c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -252,7 +252,7 @@ private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) if ( $verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected (in %ss)', $count, $time ) ); } return $count; } @@ -300,7 +300,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r if ( $verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected (%ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected (in %ss)', $count, $time ) ); } return $count; From 0bf3a5771f8bd9d7c37bea54fba4ad3b480d9c7d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 15:05:10 -0800 Subject: [PATCH 3863/5359] Clarify type too --- php/commands/search-replace.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 6777eb57c..7fb259277 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -252,7 +252,7 @@ private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) if ( $verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected (in %ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected using SQL (in %ss)', $count, $time ) ); } return $count; } @@ -300,7 +300,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r if ( $verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected (in %ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected using PHP (in %ss)', $count, $time ) ); } return $count; From 70cf30bd4e954d496cfe8e5c572fa97483974372 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 24 Nov 2015 17:54:32 -0800 Subject: [PATCH 3864/5359] Prevent unnecessary calls to `$wpdb->update()` when no replacements If the replacement value is the same as the original value, we don't need to perform an update --- php/commands/search-replace.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7fb259277..3a6a50652 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -285,6 +285,10 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r $value = $replacer->run( $row->$col ); + if ( $value === $row->$col ) { + continue; + } + if ( $dry_run ) { if ( $value != $row->$col ) $count++; From a249578ae2053b88c3174b15378266c9c65a9dfe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 07:21:03 -0800 Subject: [PATCH 3865/5359] Lock symfony to v2.7.x There's something broken in v2.8.0 --- composer.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1fe600e04..ba6f9d758 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,14 @@ "composer/semver": "1.0.0", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", - "symfony/finder": "~2.3", + "symfony/finder": "2.7.*", + "symfony/yaml": "2.7.*", + "symfony/filesystem": "2.7.*", + "symfony/config": "2.7.*", + "symfony/console": "2.7.*", + "symfony/dependency-injection": "2.7.*", + "symfony/event-dispatcher": "2.7.*", + "symfony/translation": "2.7.*", "nb/oxymel": "0.1.0" }, "require-dev": { From 2915ba7167e5945efa1e06362021c6cc2a0d7da2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 07:54:45 -0800 Subject: [PATCH 3866/5359] Abstract s/r table preparation to `WP_CLI\Utils\wp_get_table_names()` This will let us reuse it in other contexts (e.g. db export) --- php/commands/search-replace.php | 124 +------------------------------- php/utils-wp.php | 105 +++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 122 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 3a6a50652..bbaa7a50d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -88,36 +88,8 @@ public function __invoke( $args, $assoc_args ) { // never mess with hashed passwords $skip_columns[] = 'user_pass'; - // Determine how to limit the list of tables. Defaults to 'wordpress' - $table_type = 'wordpress'; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { - $table_type = 'network'; - } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all-tables-with-prefix' ) ) { - $table_type = 'all-tables-with-prefix'; - } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all-tables' ) ) { - $table_type = 'all-tables'; - } - - if ( ! empty( $args ) ) { - $new_tables = array(); - foreach( $args as $key => $table ) { - if ( false !== strpos( $table, '*' ) || false !== strpos( $table, '?' ) ) { - $expanded_tables = self::get_tables_for_glob( $table ); - if ( empty( $expanded_tables ) ) { - WP_CLI::error( "Couldn't find any tables matching: {$table}" ); - } - $new_tables = array_merge( $new_tables, $expanded_tables ); - } else { - $new_tables[] = $table; - } - } - $args = $new_tables; - } - - // Get the array of tables to work with. If there is anything left in $args, assume those are table names to use - $tables = empty( $args ) ? self::get_table_list( $table_type ) : $args; + // Get table names based on leftover $args or supplied $assoc_args + $tables = \WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); foreach ( $tables as $table ) { list( $primary_keys, $columns ) = self::get_columns( $table ); @@ -174,73 +146,6 @@ public function __invoke( $args, $assoc_args ) { } } - /** - * Retrieve a list of tables from the database. - * - * @global wpdb $wpdb - * - * @param string $limit_to Sting defining how to limit the list of tables to retrieve. Acceptable vales are: - * - 'wordpress' for default WordPress tables only - * - 'network' for default Multisite tables only - * - 'all-tables-with-prefix' for all tables using the WordPress DB prefix - * - 'all-tables' for all tables in the DB - * - * @return array The array of table names. - */ - private static function get_table_list( $limit_to ) { - global $wpdb; - - $network = 'network' == $limit_to; - - if ( 'all-tables' == $limit_to ) { - return $wpdb->get_col( 'SHOW TABLES' ); - } - - $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; - $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); - - if ( 'all-tables-with-prefix' == $limit_to ) { - return $matching_tables; - } - - $allowed_tables = array(); - $allowed_table_types = array( 'tables', 'global_tables' ); - if ( $network ) { - $allowed_table_types[] = 'ms_global_tables'; - } - foreach( $allowed_table_types as $table_type ) { - foreach( $wpdb->$table_type as $table ) { - $allowed_tables[] = $prefix . $table; - } - } - - // Given our matching tables, also allow site-specific tables on the network - foreach( $matching_tables as $key => $matched_table ) { - - if ( in_array( $matched_table, $allowed_tables ) ) { - continue; - } - - if ( $network ) { - $valid_table = false; - foreach( array_merge( $wpdb->tables, $wpdb->old_tables ) as $maybe_site_table ) { - if ( preg_match( "#{$prefix}([\d]+)_{$maybe_site_table}#", $matched_table ) ) { - $valid_table = true; - } - } - if ( $valid_table ) { - continue; - } - } - - unset( $matching_tables[ $key ] ); - - } - - return array_values( $matching_tables ); - - } - private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { global $wpdb; @@ -332,31 +237,6 @@ private static function get_columns( $table ) { return array( $primary_keys, $columns ); } - /** - * Get all the tables that match a glob pattern - * - * @param string $glob - * @return array - */ - private static function get_tables_for_glob( $glob ) { - - static $all_tables = array(); - - if ( ! $all_tables ) { - $all_tables = self::get_table_list( 'all-tables' ); - } - - $tables = array(); - - foreach ( $all_tables as $table) { - if ( fnmatch( $glob, $table ) ) { - $tables[] = $table; - } - } - - return $tables; - } - private static function is_text_col( $type ) { foreach ( array( 'text', 'varchar' ) as $token ) { if ( false !== strpos( $type, $token ) ) diff --git a/php/utils-wp.php b/php/utils-wp.php index e3519af48..470ab3997 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -205,3 +205,108 @@ function wp_clear_object_cache() { $wp_object_cache->__remoteset(); // important } } + +/** + * Get a set of tables in the database. + * + * Interprets common command-line options into a resolved set of table names. + * + * @param array $args Provided table names, or tables with wildcards. + * @param array $assoc_args Optional flags for groups of tables (e.g. --network) + * @return array $tables + */ +function wp_get_table_names( $args, $assoc_args = array() ) { + global $wpdb; + + // Prioritize any supplied $args as tables + if ( ! empty( $args ) ) { + $new_tables = array(); + $get_tables_for_glob = function( $glob ) { + global $wpdb; + static $all_tables = array(); + if ( ! $all_tables ) { + $all_tables = $wpdb->get_col( 'SHOW TABLES' ); + } + $tables = array(); + foreach ( $all_tables as $table) { + if ( fnmatch( $glob, $table ) ) { + $tables[] = $table; + } + } + return $tables; + }; + foreach( $args as $key => $table ) { + if ( false !== strpos( $table, '*' ) || false !== strpos( $table, '?' ) ) { + $expanded_tables = $get_tables_for_glob( $table ); + if ( empty( $expanded_tables ) ) { + \WP_CLI::error( "Couldn't find any tables matching: {$table}" ); + } + $new_tables = array_merge( $new_tables, $expanded_tables ); + } else { + $new_tables[] = $table; + } + } + return $new_tables; + } + + // Fall back to flag if no tables were passed + $table_type = 'wordpress'; + if ( get_flag_value( $assoc_args, 'network' ) ) { + $table_type = 'network'; + } + if ( get_flag_value( $assoc_args, 'all-tables-with-prefix' ) ) { + $table_type = 'all-tables-with-prefix'; + } + if ( get_flag_value( $assoc_args, 'all-tables' ) ) { + $table_type = 'all-tables'; + } + + $network = 'network' == $table_type; + + if ( 'all-tables' == $table_type ) { + return $wpdb->get_col( 'SHOW TABLES' ); + } + + $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; + $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); + + if ( 'all-tables-with-prefix' == $table_type ) { + return $matching_tables; + } + + $allowed_tables = array(); + $allowed_table_types = array( 'tables', 'global_tables' ); + if ( $network ) { + $allowed_table_types[] = 'ms_global_tables'; + } + foreach( $allowed_table_types as $table_type ) { + foreach( $wpdb->$table_type as $table ) { + $allowed_tables[] = $prefix . $table; + } + } + + // Given our matching tables, also allow site-specific tables on the network + foreach( $matching_tables as $key => $matched_table ) { + + if ( in_array( $matched_table, $allowed_tables ) ) { + continue; + } + + if ( $network ) { + $valid_table = false; + foreach( array_merge( $wpdb->tables, $wpdb->old_tables ) as $maybe_site_table ) { + if ( preg_match( "#{$prefix}([\d]+)_{$maybe_site_table}#", $matched_table ) ) { + $valid_table = true; + } + } + if ( $valid_table ) { + continue; + } + } + + unset( $matching_tables[ $key ] ); + + } + + return array_values( $matching_tables ); +} From fd32e4ede5d2ea3983fb576c740e11112ae27f6b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 07:56:12 -0800 Subject: [PATCH 3867/5359] Remove flag I didn't mean to commit long ago --- features/search-replace.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index f8590a123..fb526766a 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -57,7 +57,6 @@ Feature: Do global search/replace awesome_table """ - @daniel Scenario: Run on all tables matching string with wildcard Given a WP install From 7845a67b97c162573212b6bcf6aff62bfad2957c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 08:22:28 -0800 Subject: [PATCH 3868/5359] Use `WP_CLI\Utils\wp_get_table_names()` in `wp db tables` --- features/db-table.feature | 92 +++++++++++++++++++++++++++++++++++++++ php/commands/db.php | 18 ++++++-- php/utils-wp.php | 4 ++ 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 features/db-table.feature diff --git a/features/db-table.feature b/features/db-table.feature new file mode 100644 index 000000000..4aedecaf3 --- /dev/null +++ b/features/db-table.feature @@ -0,0 +1,92 @@ +Feature: List database tables + + Scenario: List database tables on a single WordPress install + Given a WP install + + When I run `wp db tables` + Then STDOUT should contain: + """ + wp_users + wp_usermeta + wp_posts + wp_comments + wp_links + wp_options + wp_postmeta + wp_terms + wp_term_taxonomy + wp_term_relationships + """ + + Scenario: List database tables on a multisite WordPress install + Given a WP multisite install + + When I run `wp db tables` + Then STDOUT should contain: + """ + wp_users + wp_usermeta + wp_posts + wp_comments + wp_links + wp_options + wp_postmeta + wp_terms + wp_term_taxonomy + wp_term_relationships + """ + And STDOUT should contain: + """ + wp_blogs + wp_signups + wp_site + wp_sitemeta + wp_sitecategories + wp_registration_log + wp_blog_versions + """ + + When I run `wp site create --slug=foo` + And I run `wp db tables --url=example.com/foo` + Then STDOUT should contain: + """ + wp_users + wp_usermeta + wp_2_posts + """ + + When I run `wp db tables --url=example.com/foo --scope=global` + Then STDOUT should not contain: + """ + wp_2_posts + """ + + When I run `wp db tables --all-tables-with-prefix` + Then STDOUT should contain: + """ + wp_2_posts + """ + And STDOUT should contain: + """ + wp_posts + """ + + When I run `wp db tables --url=example.com/foo --all-tables-with-prefix` + Then STDOUT should contain: + """ + wp_2_posts + """ + And STDOUT should not contain: + """ + wp_posts + """ + + When I run `wp db tables --url=example.com/foo --network` + Then STDOUT should contain: + """ + wp_2_posts + """ + And STDOUT should contain: + """ + wp_posts + """ diff --git a/php/commands/db.php b/php/commands/db.php index 956c9647c..e2f3a4bc7 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -202,22 +202,34 @@ function import( $args, $assoc_args ) { /** * List the database tables. * + * Defaults to all tables registered to $wpdb. + * * ## OPTIONS * * [--scope=<scope>] * : Can be all, global, ms_global, blog, or old tables. Defaults to all. * + * [--network] + * : List all the tables in a multisite install. Overrides --scope=<scope>. + * + * [--all-tables-with-prefix] + * : List all tables that match the table prefix even if not registered on $wpdb. Overrides --network. + * + * [--all-tables] + * : List all tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --all-tables-with-prefix. + * * ## EXAMPLES * * # Export only tables for a single site * wp db export --tables=$(wp db tables --url=sub.example.com | tr '\n' ',') */ function tables( $args, $assoc_args ) { - global $wpdb; - $scope = \WP_CLI\Utils\get_flag_value( $assoc_args, 'scope', 'all' ); + if ( empty( $assoc_args ) ) { + $assoc_args['scope'] = 'all'; + } - $tables = $wpdb->tables( $scope ); + $tables = WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); foreach ( $tables as $table ) { WP_CLI::line( $table ); diff --git a/php/utils-wp.php b/php/utils-wp.php index 470ab3997..b4202dd84 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -274,6 +274,10 @@ function wp_get_table_names( $args, $assoc_args = array() ) { return $matching_tables; } + if ( $scope = get_flag_value( $assoc_args, 'scope' ) ) { + return $wpdb->tables( $scope ); + } + $allowed_tables = array(); $allowed_table_types = array( 'tables', 'global_tables' ); if ( $network ) { From 5880e442c1e79ecacbac54048d96260f7bed61ec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 09:00:06 -0800 Subject: [PATCH 3869/5359] Add wildcard table searching and `--format=csv` for easier composing --- features/db-table.feature | 12 ++++++++++++ php/commands/db.php | 27 +++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/features/db-table.feature b/features/db-table.feature index 4aedecaf3..e0b6a907d 100644 --- a/features/db-table.feature +++ b/features/db-table.feature @@ -18,6 +18,18 @@ Feature: List database tables wp_term_relationships """ + When I run `wp db tables --format=csv` + Then STDOUT should contain: + """ + wp_terms,wp_usermeta,wp_users + """ + + When I run `wp db tables 'wp_post*' --format=csv` + Then STDOUT should be: + """ + wp_postmeta,wp_posts + """ + Scenario: List database tables on a multisite WordPress install Given a WP multisite install diff --git a/php/commands/db.php b/php/commands/db.php index e2f3a4bc7..f8a7a281a 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -131,6 +131,12 @@ function query( $args ) { * wp db export --add-drop-table * wp db export --tables=wp_options,wp_users * + * # Export all tables matching a wildcard + * wp db export --tables=$(wp db tables 'wp_user*' --format=csv) + * + * # Export all tables matching prefix + * wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) + * * @alias dump */ function export( $args, $assoc_args ) { @@ -206,6 +212,9 @@ function import( $args, $assoc_args ) { * * ## OPTIONS * + * [<table>...] + * : List tables based on wildcard search, e.g. 'wp_*_options' or 'wp_post?'. + * * [--scope=<scope>] * : Can be all, global, ms_global, blog, or old tables. Defaults to all. * @@ -218,21 +227,31 @@ function import( $args, $assoc_args ) { * [--all-tables] * : List all tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --all-tables-with-prefix. * + * [--format=<format>] + * : Accepted values: list, csv. Default: list + * * ## EXAMPLES * * # Export only tables for a single site - * wp db export --tables=$(wp db tables --url=sub.example.com | tr '\n' ',') + * wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) + * + * # Export all tables matching prefix + * wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) */ function tables( $args, $assoc_args ) { - if ( empty( $assoc_args ) ) { + if ( empty( $args ) && empty( $assoc_args ) ) { $assoc_args['scope'] = 'all'; } $tables = WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); - foreach ( $tables as $table ) { - WP_CLI::line( $table ); + if ( ! empty( $assoc_args['format'] ) && 'csv' === $assoc_args['format'] ) { + WP_CLI::line( implode( ',', $tables ) ); + } else { + foreach ( $tables as $table ) { + WP_CLI::line( $table ); + } } } From c4a6385ee3fed63df3700b82bca01d90f81e2589 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Dec 2015 09:23:44 -0800 Subject: [PATCH 3870/5359] Set to the version WordPress began incrementing blog tables --- features/db-table.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/db-table.feature b/features/db-table.feature index e0b6a907d..8c8ab1bc0 100644 --- a/features/db-table.feature +++ b/features/db-table.feature @@ -30,6 +30,7 @@ Feature: List database tables wp_postmeta,wp_posts """ + @require-wp-3.9 Scenario: List database tables on a multisite WordPress install Given a WP multisite install From da9167d1d4b49cf5cb9d83f4e45d4bfa1ebc57d1 Mon Sep 17 00:00:00 2001 From: Ian Dunn <ian@iandunn.name> Date: Mon, 30 Nov 2015 11:26:03 -0800 Subject: [PATCH 3871/5359] Add .dist extension to PHPUnit configuration file in plugin-tests. Naming the file `phpunit.xml.dist` instead of `phpunit.xml` is considered a best practice because it allows other developers working on a project to override the configuration without messing with extra command line parameters or dirtying their local version control state. See http://www.testically.org/2010/08/24/best-practice-how-to-ship-phpunit-configuration/ --- .gitignore | 2 +- features/plugin.feature | 4 ++-- features/scaffold.feature | 2 +- php/commands/scaffold.php | 4 ++-- templates/{phpunit.xml => phpunit.xml.dist} | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename templates/{phpunit.xml => phpunit.xml.dist} (100%) diff --git a/.gitignore b/.gitignore index ee37a1d64..665e3e8af 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ config.yml /cache /vendor /*.phar -/phpunit.xml +/phpunit.xml.dist diff --git a/features/plugin.feature b/features/plugin.feature index 0eb663708..65da74df6 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -8,7 +8,7 @@ Feature: Manage WordPress plugins When I run `wp plugin scaffold --skip-tests plugin1` Then STDOUT should not be empty And the {PLUGIN_DIR}/plugin1/plugin1.php file should exist - And the {PLUGIN_DIR}/zombieland/phpunit.xml file should not exist + And the {PLUGIN_DIR}/zombieland/phpunit.xml.dist file should not exist When I run `wp plugin path plugin1` Then STDOUT should be: @@ -25,7 +25,7 @@ Feature: Manage WordPress plugins When I run `wp plugin scaffold Zombieland` Then STDOUT should not be empty And the {PLUGIN_DIR}/Zombieland/Zombieland.php file should exist - And the {PLUGIN_DIR}/Zombieland/phpunit.xml file should exist + And the {PLUGIN_DIR}/Zombieland/phpunit.xml.dist file should exist # Ensure case sensitivity When I try `wp plugin status zombieLand` diff --git a/features/scaffold.feature b/features/scaffold.feature index 4fdb96447..6814597d0 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -161,7 +161,7 @@ Feature: WordPress code scaffolding """ install-wp-tests.sh """ - And the {PLUGIN_DIR}/hello-world/phpunit.xml file should exist + And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 100b621e0..5672e79ab 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -557,7 +557,7 @@ function plugin( $args, $assoc_args ) { * * These are the files that are generated: * - * * `phpunit.xml` is the configuration file for PHPUnit + * * `phpunit.xml.dist` is the configuration file for PHPUnit * * `.travis.yml` is the configuration file for Travis CI * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite * * `tests/test-sample.php` is a sample file containing the actual tests @@ -622,7 +622,7 @@ function plugin_tests( $args, $assoc_args ) { $to_copy = array( 'install-wp-tests.sh' => $bin_dir, '.travis.yml' => $plugin_dir, - 'phpunit.xml' => $plugin_dir, + 'phpunit.xml.dist' => $plugin_dir, 'test-sample.php' => $tests_dir, ); diff --git a/templates/phpunit.xml b/templates/phpunit.xml.dist similarity index 100% rename from templates/phpunit.xml rename to templates/phpunit.xml.dist From 7b9643c8b3f3ec4c1eaf7e1856d5281915264732 Mon Sep 17 00:00:00 2001 From: Tristan Penman <tristan@tristanpenman.com> Date: Thu, 3 Dec 2015 00:09:39 +0000 Subject: [PATCH 3872/5359] Improve plugin vs. theme detection for the error generated when the requested version of a plugin or theme does not exist Previously, the alter_api_response function would check for the substring 'theme' in the URL returned by the WordPress repository API. When requesting a non-existant version of a plugin such as Easy Updates Manager (which has the slug 'stops-core-theme-and-plugin-updates'), this would incorrectly report that the requested version of the _theme_ could not be found. This change makes the substring test stricter, by expecting the URL to contain the string '/theme/' for themes. It also performs a similar check for plugins ('/plugin/'), and if both checks fail, it will produce a more generic response (e.g. Can't find the requested plugin/theme's version...) --- php/WP_CLI/CommandWithUpgrade.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e03724218..8d988e2ce 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -173,10 +173,12 @@ protected static function alter_api_response( $response, $version ) { list( $link ) = explode( $response->slug, $response->download_link ); - if ( false !== strpos( $response->download_link, 'theme' ) ) + if ( false !== strpos( $response->download_link, '/theme/' ) ) $download_type = 'theme'; - else + else if ( false !== strpos( $response->download_link, '/plugin/' ) ) $download_type = 'plugin'; + else + $download_type = 'plugin/theme'; if ( 'dev' == $version ) { $response->download_link = $link . $response->slug . '.zip'; From 018711fb1a95c1704f13e8371c891fbb49eaed39 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 3 Dec 2015 16:11:58 -0800 Subject: [PATCH 3873/5359] Use `--export=<file>` to `search-replace` to a saved file Props @westonruter for much of the original code --- features/search-replace.feature | 25 ++++++++++++++++++++++++ php/commands/search-replace.php | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index fb526766a..29d25ac43 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,6 +15,31 @@ Feature: Do global search/replace guid """ + Scenario: Search/replace with export + Given a WP install + + When I run `wp search-replace example.com example.net --export` + Then STDOUT should contain: + """ + DROP TABLE IF EXISTS `wp_commentmeta`; + CREATE TABLE `wp_commentmeta` + """ + And STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.org', 'yes'); + """ + + When I run `wp search-replace example.com example.org --skip-columns=option_value --export` + Then STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'); + """ + + When I run `wp search-replace foo bar --export | tail -n 1` + Then STDOUT should not contain: + """ + Success: Made + """ Scenario: Multisite search/replace Given a WP multisite install diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index bbaa7a50d..e8fcb92f7 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -7,6 +7,8 @@ */ class Search_Replace_Command extends WP_CLI_Command { + private $export_handle = false; + /** * Search/replace strings in the database. * @@ -57,6 +59,9 @@ class Search_Replace_Command extends WP_CLI_Command { * [--regex] * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. * + * [--export[=<file>]] + * : Write transformed data as SQL file instead of performing in-place replacements. If <file> is not supplied, will output to STDOUT. + * * ## EXAMPLES * * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid @@ -85,12 +90,35 @@ public function __invoke( $args, $assoc_args ) { exit; } + if ( null !== ( $export = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export' ) ) ) { + if ( $dry_run ) { + WP_CLI::error( 'You cannot supply --dry-run and --export at the same time.' ); + } + if ( true === $export ) { + $this->export_handle = STDOUT; + $verbose = false; + } else { + $this->export_handle = fopen( $assoc_args['export'], 'w' ); + if ( false === $this->export_handle ) { + WP_CLI::error( sprintf( 'Unable to open "%s" for writing', $assoc_args['export'] ) ); + } + } + $php_only = true; + } + // never mess with hashed passwords $skip_columns[] = 'user_pass'; // Get table names based on leftover $args or supplied $assoc_args $tables = \WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); foreach ( $tables as $table ) { + + if ( $this->export_handle ) { + fwrite( $this->export_handle, "\nDROP TABLE IF EXISTS `$table`;\n" ); + $row = $wpdb->get_row( "SHOW CREATE TABLE `$table`", ARRAY_N ); + fwrite( $this->export_handle, $row[1] . ";\n" ); + } + list( $primary_keys, $columns ) = self::get_columns( $table ); // since we'll be updating one row at a time, @@ -128,7 +156,11 @@ public function __invoke( $args, $assoc_args ) { } } - if ( ! WP_CLI::get_config( 'quiet' ) ) { + if ( $this->export_handle && STDOUT !== $this->export_handle ) { + fclose( $this->export_handle ); + } + + if ( ! WP_CLI::get_config( 'quiet' ) && STDOUT !== $this->export_handle ) { $table = new \cli\Table(); $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); From f06605cf0c530ce1b5bec17d0e138ff58c281f55 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 4 Dec 2015 12:32:31 +0000 Subject: [PATCH 3874/5359] Convert .travis.yml into mustache template --- templates/{.travis.yml => .travis.mustache} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename templates/{.travis.yml => .travis.mustache} (77%) diff --git a/templates/.travis.yml b/templates/.travis.mustache similarity index 77% rename from templates/.travis.yml rename to templates/.travis.mustache index 375e59ed2..5a77b81b6 100644 --- a/templates/.travis.yml +++ b/templates/.travis.mustache @@ -10,7 +10,9 @@ php: - 5.6 env: - - WP_VERSION=latest WP_MULTISITE=0 +{{#wp_versions_to_test}} + - WP_VERSION={{.}} WP_MULTISITE=0 +{{/wp_versions_to_test}} matrix: include: From f87d1c8ed5af7c5222af87739b9fb878ceba634d Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 4 Dec 2015 12:33:15 +0000 Subject: [PATCH 3875/5359] Parse plugin readme.txt to find WP versions to test --- php/commands/scaffold.php | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5672e79ab..b7c1ad0ca 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -615,13 +615,29 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); + $wp_versions_to_test = array('latest'); + // Parse plugin readme.txt + if ( file_exists( $plugin_dir . '/readme.txt' ) ) { + $readme_content = file_get_contents( $plugin_dir . '/readme.txt' ); + + preg_match( '/Requires at least\:(.*)\n/m', $readme_content, $matches ); + if ( isset( $matches[1] ) && $matches[1] ) { + $wp_versions_to_test[] = trim( $matches[1] ); + } + preg_match( '/Tested up to\:(.*)\n/m', $readme_content, $matches ); + if ( isset( $matches[1] ) && $matches[1] ) { + $wp_versions_to_test[] = trim( $matches[1] ); + } + } + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_written = $this->create_files( array( "$tests_dir/bootstrap.php" => - Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ) ), $force ); + $files_written = $this->create_files( array( + "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ), + "$plugin_dir/.travis.yml" => Utils\mustache_render( '.travis.mustache', compact( 'wp_versions_to_test' ) ) + ), $force ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, - '.travis.yml' => $plugin_dir, 'phpunit.xml.dist' => $plugin_dir, 'test-sample.php' => $tests_dir, ); From 7284bf48bd132fbbf49e25fef1c5aaeaac84f617 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 4 Dec 2015 14:52:05 +0000 Subject: [PATCH 3876/5359] Add functional test --- features/scaffold.feature | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 6814597d0..377b9666b 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -322,6 +322,23 @@ Feature: WordPress code scaffolding require dirname( dirname( __FILE__ ) ) . '/custom-plugin-slug.php'; """ + Scenario: Scaffold tests parses plugin readme.txt + Given a WP install + When I run `wp plugin path` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin hello-world` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist + And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: + """ + env: + - WP_VERSION=latest WP_MULTISITE=0 + - WP_VERSION=3.0.1 WP_MULTISITE=0 + - WP_VERSION=3.4 WP_MULTISITE=0 + """ + Scenario: Scaffold starter code for a theme and network enable it Given a WP multisite install When I run `wp scaffold _s starter-theme --enable-network` From cd41122b91a7f287e6a252d08bcd24c5eac8ce3c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 06:52:55 -0800 Subject: [PATCH 3877/5359] Bail early, to prevent nested conditional --- php/commands/search-replace.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e8fcb92f7..7433e3546 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -160,21 +160,22 @@ public function __invoke( $args, $assoc_args ) { fclose( $this->export_handle ); } - if ( ! WP_CLI::get_config( 'quiet' ) && STDOUT !== $this->export_handle ) { + // Only informational output after this point + if ( WP_CLI::get_config( 'quiet' ) || STDOUT === $this->export_handle ) { + return; + } - $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); - $table->setRows( $report ); - $table->display(); + $table = new \cli\Table(); + $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); + $table->setRows( $report ); + $table->display(); - if ( ! $dry_run ) { - $success_message = "Made $total replacements."; - if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { - $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; - } - WP_CLI::success( $success_message ); + if ( ! $dry_run ) { + $success_message = "Made $total replacements."; + if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { + $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; } - + WP_CLI::success( $success_message ); } } From c3a859c8a67936c0f9933a0fe13b651cebe6091f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 09:14:56 -0800 Subject: [PATCH 3878/5359] Write each row of data to export file Abstracts some arguments to class variables for better reusability throughout --- features/search-replace-export.feature | 146 +++++++++++++++++++++++++ features/search-replace.feature | 26 ----- php/commands/search-replace.php | 133 ++++++++++++++++------ 3 files changed, 246 insertions(+), 59 deletions(-) create mode 100644 features/search-replace-export.feature diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature new file mode 100644 index 000000000..4727ae785 --- /dev/null +++ b/features/search-replace-export.feature @@ -0,0 +1,146 @@ +Feature: Search / replace with file export + + Scenario: Search / replace export to STDOUT + Given a WP install + + When I run `wp search-replace example.com example.net --export` + Then STDOUT should contain: + """ + DROP TABLE IF EXISTS `wp_commentmeta`; + CREATE TABLE `wp_commentmeta` + """ + And STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.net', 'yes'); + """ + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ + + When I run `wp search-replace example.com example.net --skip-columns=option_value --export` + Then STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'); + """ + + When I run `wp search-replace foo bar --export | tail -n 1` + Then STDOUT should not contain: + """ + Success: Made + """ + + When I run `wp search-replace example.com example.net --export > wordpress.sql` + And I run `wp db import wordpress.sql` + Then STDOUT should not be empty + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.net + """ + + Scenario: Search / replace export to file + Given a WP install + And I run `wp post generate --count=30` + + When I run `wp search-replace example.com example.net --export=wordpress.sql` + Then STDOUT should contain: + """ + Success: Made 39 replacements and exported to wordpress.sql + """ + And STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 5 | PHP | + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ + + When I run `wp site empty --yes` + And I run `wp post list --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp db import wordpress.sql` + Then STDOUT should not be empty + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.net + """ + + When I run `wp post list --format=count` + Then STDOUT should be: + """ + 31 + """ + + Scenario: Search / replace export to file with verbosity + Given a WP install + + When I run `wp search-replace example.com example.net --export=wordpress.sql --verbose` + Then STDOUT should contain: + """ + Checking: wp_posts + """ + And STDOUT should contain: + """ + Checking: wp_options + """ + + Scenario: Search / replace export with dry-run + Given a WP install + + When I try `wp search-replace example.com example.net --export --dry-run` + Then STDERR should be: + """ + Error: You cannot supply --dry-run and --export at the same time. + """ + + Scenario: Search / replace shouldn't affect primary key + Given a WP install + And I run `wp post create --post_title=foo --porcelain` + Then save STDOUT as {POST_ID} + + When I run `wp option update {POST_ID} foo` + And I run `wp option get {POST_ID}` + Then STDOUT should be: + """ + foo + """ + + When I run `wp search-replace {POST_ID} 99999999 --export=wordpress.sql` + And I run `wp db import wordpress.sql` + Then STDOUT should not be empty + + When I run `wp post get {POST_ID} --field=title` + Then STDOUT should be: + """ + foo + """ + + When I try `wp option get {POST_ID}` + Then STDOUT should be empty + + When I run `wp option get 99999999` + Then STDOUT should be: + """ + foo + """ + + Scenario: Search / replace export invalid file + Given a WP install + + When I try `wp search-replace example.com example.net --export=foo/bar.sql` + Then STDERR should contain: + """ + Error: Unable to open "foo/bar.sql" for writing. + """ diff --git a/features/search-replace.feature b/features/search-replace.feature index 29d25ac43..eb0783361 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,32 +15,6 @@ Feature: Do global search/replace guid """ - Scenario: Search/replace with export - Given a WP install - - When I run `wp search-replace example.com example.net --export` - Then STDOUT should contain: - """ - DROP TABLE IF EXISTS `wp_commentmeta`; - CREATE TABLE `wp_commentmeta` - """ - And STDOUT should contain: - """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.org', 'yes'); - """ - - When I run `wp search-replace example.com example.org --skip-columns=option_value --export` - Then STDOUT should contain: - """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'); - """ - - When I run `wp search-replace foo bar --export | tail -n 1` - Then STDOUT should not contain: - """ - Success: Made - """ - Scenario: Multisite search/replace Given a WP multisite install And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7433e3546..94698e6f0 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -8,6 +8,9 @@ class Search_Replace_Command extends WP_CLI_Command { private $export_handle = false; + private $recurse_objects; + private $regex; + private $skip_columns; /** * Search/replace strings in the database. @@ -79,13 +82,13 @@ public function __invoke( $args, $assoc_args ) { $report = array(); $dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); - $recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); - $verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); - $regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); + $this->recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); + $this->verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); + $this->regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); - $skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); + $this->skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); - if ( $old === $new && ! $regex ) { + if ( $old === $new && ! $this->regex ) { WP_CLI::warning( "Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation." ); exit; } @@ -96,18 +99,18 @@ public function __invoke( $args, $assoc_args ) { } if ( true === $export ) { $this->export_handle = STDOUT; - $verbose = false; + $this->verbose = false; } else { $this->export_handle = fopen( $assoc_args['export'], 'w' ); if ( false === $this->export_handle ) { - WP_CLI::error( sprintf( 'Unable to open "%s" for writing', $assoc_args['export'] ) ); + WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); } } $php_only = true; } // never mess with hashed passwords - $skip_columns[] = 'user_pass'; + $this->skip_columns[] = 'user_pass'; // Get table names based on leftover $args or supplied $assoc_args $tables = \WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); @@ -117,9 +120,14 @@ public function __invoke( $args, $assoc_args ) { fwrite( $this->export_handle, "\nDROP TABLE IF EXISTS `$table`;\n" ); $row = $wpdb->get_row( "SHOW CREATE TABLE `$table`", ARRAY_N ); fwrite( $this->export_handle, $row[1] . ";\n" ); + list( $table_report, $total_rows ) = $this->php_export_table( $table, $old, $new ); + $report = array_merge( $report, $table_report ); + $total += $total_rows; + // Don't perform replacements on the actual database + continue; } - list( $primary_keys, $columns ) = self::get_columns( $table ); + list( $primary_keys, $columns, $all_columns ) = self::get_columns( $table ); // since we'll be updating one row at a time, // we need a primary key to identify the row @@ -129,11 +137,11 @@ public function __invoke( $args, $assoc_args ) { } foreach ( $columns as $col ) { - if ( in_array( $col, $skip_columns ) ) { + if ( in_array( $col, $this->skip_columns ) ) { continue; } - if ( $verbose ) { + if ( $this->verbose ) { $this->start_time = microtime( true ); WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); } @@ -142,12 +150,12 @@ public function __invoke( $args, $assoc_args ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } - if ( $php_only || $regex || NULL !== $serialRow ) { + if ( $php_only || $this->regex || NULL !== $serialRow ) { $type = 'PHP'; - $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ); + $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run ); } else { $type = 'SQL'; - $count = $this->sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ); + $count = $this->sql_handle_col( $col, $table, $old, $new, $dry_run ); } $report[] = array( $table, $col, $count, $type ); @@ -171,7 +179,7 @@ public function __invoke( $args, $assoc_args ) { $table->display(); if ( ! $dry_run ) { - $success_message = "Made $total replacements."; + $success_message = ! empty( $assoc_args['export'] ) ? "Made {$total} replacements and exported to {$assoc_args['export']}." : "Made $total replacements."; if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; } @@ -179,7 +187,56 @@ public function __invoke( $args, $assoc_args ) { } } - private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) { + private function php_export_table( $table, $old, $new ) { + list( $primary_keys, $columns, $all_columns ) = self::get_columns( $table ); + $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; + $args = array( + 'table' => $table, + 'fields' => $all_columns, + 'chunk_size' => $chunk_size + ); + + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex ); + $col_counts = array_fill_keys( $all_columns, 0 ); + if ( $this->verbose ) { + $this->start_time = microtime( true ); + WP_CLI::log( sprintf( 'Checking: %s', $table ) ); + } + foreach ( new \WP_CLI\Iterators\Table( $args ) as $i => $row ) { + $row_fields = array(); + foreach( $all_columns as $col ) { + $value = $row->$col; + if ( $value && ! in_array( $col, $primary_keys ) && ! in_array( $col, $this->skip_columns ) ) { + $new_value = $replacer->run( $value ); + if ( $new_value !== $value ) { + $col_counts[ $col ]++; + $value = $new_value; + } + } + $row_fields[ $col ] = $value; + } + $this->write_sql_row_fields( $table, $row_fields ); + } + + $table_report = array(); + $total_rows = $total_cols = 0; + foreach ( $col_counts as $col => $col_count ) { + $table_report[] = array( $table, $col, $col_count, 'PHP' ); + if ( $col_count ) { + $total_cols++; + $total_rows += $col_count; + } + } + + if ( $this->verbose ) { + $time = round( microtime( true ) - $this->start_time, 3 ); + WP_CLI::log( sprintf( '%d columns and %d total rows affected using PHP (in %ss)', $total_cols, $total_rows, $time ) ); + } + + return array( $table_report, $total_rows ); + } + + private function sql_handle_col( $col, $table, $old, $new, $dry_run ) { global $wpdb; if ( $dry_run ) { @@ -188,14 +245,14 @@ private function sql_handle_col( $col, $table, $old, $new, $dry_run, $verbose ) $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); } - if ( $verbose ) { + if ( $this->verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); WP_CLI::log( sprintf( '%d rows affected using SQL (in %ss)', $count, $time ) ); } return $count; } - private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run, $recurse_objects, $verbose, $regex ) { + private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -207,7 +264,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r $args = array( 'table' => $table, 'fields' => $fields, - 'where' => $regex ? '' : "`$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ), + 'where' => $this->regex ? '' : "`$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ), 'chunk_size' => $chunk_size ); @@ -215,7 +272,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r $count = 0; - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $recurse_objects, $regex ); + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex ); foreach ( $it as $row ) { if ( '' === $row->$col ) @@ -240,7 +297,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r } } - if ( $verbose ) { + if ( $this->verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); WP_CLI::log( sprintf( '%d rows affected using PHP (in %ss)', $count, $time ) ); } @@ -248,26 +305,36 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r return $count; } - private static function get_columns( $table ) { + private function write_sql_row_fields( $table, $row_fields ) { global $wpdb; + $sql = "INSERT INTO `$table` ("; + $sql .= join( ', ', array_map( + function ( $field ) { + return "`$field`"; + }, + array_keys( $row_fields ) + ) ); + $sql .= ') VALUES ('; + $sql .= join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ); + $sql .= ");\n"; + $sql = $wpdb->prepare( $sql, array_values( $row_fields ) ); + fwrite( $this->export_handle, $sql ); + } - $primary_keys = array(); - - $columns = array(); + private static function get_columns( $table ) { + global $wpdb; + $primary_keys = $text_columns = $all_columns = array(); foreach ( $wpdb->get_results( "DESCRIBE $table" ) as $col ) { if ( 'PRI' === $col->Key ) { $primary_keys[] = $col->Field; - continue; } - - if ( !self::is_text_col( $col->Type ) ) - continue; - - $columns[] = $col->Field; + if ( self::is_text_col( $col->Type ) ) { + $text_columns[] = $col->Field; + } + $all_columns[] = $col->Field; } - - return array( $primary_keys, $columns ); + return array( $primary_keys, $text_columns, $all_columns ); } private static function is_text_col( $type ) { From 04099b93fbafc5812cc46e6b011b1353539ed6a3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 09:23:07 -0800 Subject: [PATCH 3879/5359] Include a test for search / replace export on a specific table --- features/search-replace-export.feature | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index 4727ae785..e50bde0cc 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -144,3 +144,37 @@ Feature: Search / replace with file export """ Error: Unable to open "foo/bar.sql" for writing. """ + + Scenario: Search / replace specific table + Given a WP install + + When I run `wp post create --post_title=foo --porcelain` + Then save STDOUT as {POST_ID} + + When I run `wp option update bar foo` + Then STDOUT should not be empty + + When I run `wp search-replace foo burrito wp_posts --export=wordpress.sql --verbose` + Then STDOUT should contain: + """ + Checking: wp_posts + """ + And STDOUT should contain: + """ + Success: Made 1 replacements and exported to wordpress.sql. + """ + + When I run `wp db import wordpress.sql` + Then STDOUT should not be empty + + When I run `wp post get {POST_ID} --field=title` + Then STDOUT should be: + """ + burrito + """ + + When I run `wp option get bar` + Then STDOUT should be: + """ + foo + """ From 37a9208d6e9fc3bdd711777fd95e960bdba63ff6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 09:25:49 -0800 Subject: [PATCH 3880/5359] Abstract `$dry_run` to class variable for better reusability --- php/commands/search-replace.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 94698e6f0..35f6d6d44 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -7,6 +7,7 @@ */ class Search_Replace_Command extends WP_CLI_Command { + private $dry_run; private $export_handle = false; private $recurse_objects; private $regex; @@ -80,7 +81,7 @@ public function __invoke( $args, $assoc_args ) { $new = array_shift( $args ); $total = 0; $report = array(); - $dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); + $this->dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); $this->recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); $this->verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); @@ -94,7 +95,7 @@ public function __invoke( $args, $assoc_args ) { } if ( null !== ( $export = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export' ) ) ) { - if ( $dry_run ) { + if ( $this->dry_run ) { WP_CLI::error( 'You cannot supply --dry-run and --export at the same time.' ); } if ( true === $export ) { @@ -152,10 +153,10 @@ public function __invoke( $args, $assoc_args ) { if ( $php_only || $this->regex || NULL !== $serialRow ) { $type = 'PHP'; - $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run ); + $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new ); } else { $type = 'SQL'; - $count = $this->sql_handle_col( $col, $table, $old, $new, $dry_run ); + $count = $this->sql_handle_col( $col, $table, $old, $new ); } $report[] = array( $table, $col, $count, $type ); @@ -178,7 +179,7 @@ public function __invoke( $args, $assoc_args ) { $table->setRows( $report ); $table->display(); - if ( ! $dry_run ) { + if ( ! $this->dry_run ) { $success_message = ! empty( $assoc_args['export'] ) ? "Made {$total} replacements and exported to {$assoc_args['export']}." : "Made $total replacements."; if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; @@ -236,10 +237,10 @@ private function php_export_table( $table, $old, $new ) { return array( $table_report, $total_rows ); } - private function sql_handle_col( $col, $table, $old, $new, $dry_run ) { + private function sql_handle_col( $col, $table, $old, $new ) { global $wpdb; - if ( $dry_run ) { + if ( $this->dry_run ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); } else { $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); @@ -252,7 +253,7 @@ private function sql_handle_col( $col, $table, $old, $new, $dry_run ) { return $count; } - private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_run ) { + private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { global $wpdb; // We don't want to have to generate thousands of rows when running the test suite @@ -284,7 +285,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new, $dry_r continue; } - if ( $dry_run ) { + if ( $this->dry_run ) { if ( $value != $row->$col ) $count++; } else { From 4af2fdd58420aa65637bff2075605d97bbc79f13 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 09:32:10 -0800 Subject: [PATCH 3881/5359] Add helpful example for this new feature --- php/commands/search-replace.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 35f6d6d44..ada5cf46d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -74,6 +74,9 @@ class Search_Replace_Command extends WP_CLI_Command { * * # Turn your production database into a local database * wp search-replace --url=example.com example.com example.dev wp_\*_options + * + * # Search/replace to a SQL file without transforming the database + * wp search-replace foo bar --export=database.sql */ public function __invoke( $args, $assoc_args ) { global $wpdb; From b6a5ed763ffefe90487891067e4b650fdd48039d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 09:50:16 -0800 Subject: [PATCH 3882/5359] We don't need to include the object cache flush message with `--export` --- php/commands/search-replace.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ada5cf46d..d2f705e6a 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -183,9 +183,13 @@ public function __invoke( $args, $assoc_args ) { $table->display(); if ( ! $this->dry_run ) { - $success_message = ! empty( $assoc_args['export'] ) ? "Made {$total} replacements and exported to {$assoc_args['export']}." : "Made $total replacements."; - if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { - $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; + if ( ! empty( $assoc_args['export'] ) ) { + $success_message = "Made {$total} replacements and exported to {$assoc_args['export']}."; + } else { + $success_message = "Made $total replacements."; + if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { + $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; + } } WP_CLI::success( $success_message ); } From 5c7eb3f22345eec1ee3114f7bd818f38e139f4fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 15:03:11 -0800 Subject: [PATCH 3883/5359] Abstract update getter, so we can use it with `wp core update` This changes the behavior of `wp core check-upate` to only list one major update. Users should be updating to the latest major release, not an intermediate one. --- features/core.feature | 12 +--- php/commands/core.php | 133 +++++++++++++++++++++--------------------- 2 files changed, 69 insertions(+), 76 deletions(-) diff --git a/features/core.feature b/features/core.feature index c9d18e77b..74e45feaa 100644 --- a/features/core.feature +++ b/features/core.feature @@ -339,31 +339,23 @@ Feature: Manage WordPress installation Then STDOUT should be a table containing rows: | version | update_type | package_url | | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | - | 4.2.5 | major | https://wordpress.org/wordpress-4.2.5.zip | - | 4.1.8 | major | https://wordpress.org/wordpress-4.1.8.zip | - | 4.0.8 | major | https://wordpress.org/wordpress-4.0.8.zip | - | 3.9.9 | major | https://wordpress.org/wordpress-3.9.9.zip | | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | When I run `wp core check-update --format=count` Then STDOUT should be: """ - 6 + 2 """ When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | - | 4.2.5 | major | https://wordpress.org/wordpress-4.2.5.zip | - | 4.1.8 | major | https://wordpress.org/wordpress-4.1.8.zip | - | 4.0.8 | major | https://wordpress.org/wordpress-4.0.8.zip | - | 3.9.9 | major | https://wordpress.org/wordpress-3.9.9.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: """ - 5 + 1 """ When I run `wp core check-update --minor` diff --git a/php/commands/core.php b/php/commands/core.php index b4ee483c6..59b784cb1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1,5 +1,6 @@ <?php +use \Composer\Semver\Comparator; use \WP_CLI\Utils; /** @@ -34,60 +35,8 @@ class Core_Command extends WP_CLI_Command { * @subcommand check-update */ function check_update( $_, $assoc_args ) { - global $wp_version; - $versions_path = ABSPATH . 'wp-includes/version.php'; - include $versions_path; - - $url = 'https://api.wordpress.org/core/stable-check/1.0/'; - - $options = array( - 'timeout' => 30 - ); - $headers = array( - 'Accept' => 'application/json' - ); - $response = Utils\http_request( 'GET', $url, $headers, $options ); - - if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( "Failed to get latest version." ); - } - - $release_data = json_decode( $response->body ); - $release_versions = array_keys( (array) $release_data ); - usort( $release_versions, function( $a, $b ){ - return 1 === version_compare( $a, $b ); - }); - - $locale = get_locale(); - - $current_parts = explode( '.', $wp_version ); - $updates = array(); - - foreach ( $release_versions as $release_version ) { - // don't list earliers versions - if ( \WP_CLI\Utils\wp_version_compare( $release_version, '>=' ) ) - continue; - - $release_parts = explode( '.', $release_version ); - $update_type = 'major'; - - if ( $release_parts[0] === $current_parts[0] - && $release_parts[1] === $current_parts[1] ) { - $update_type = 'minor'; - } - - if ( ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) && 'minor' !== $update_type ) - && ! ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'major' ) && 'major' !== $update_type ) - ) { - $updates = $this->remove_same_minor_releases( $release_parts, $updates ); - $updates[] = array( - 'version' => $release_version, - 'update_type' => $update_type, - 'package_url' => $this->get_download_url( $release_version, $locale ) - ); - } - } + $updates = $this->get_updates( $assoc_args ); if ( $updates ) { $updates = array_reverse( $updates ); $formatter = new \WP_CLI\Formatter( @@ -1088,25 +1037,77 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip } /** - * Compare processed releases to the current one, and delete older one. Return remaining updates. - * + * Returns update information */ - private function remove_same_minor_releases( $release_parts, $updates ) { - if ( empty( $updates ) ) - return false; + private function get_updates( $assoc_args ) { + global $wp_version; + $versions_path = ABSPATH . 'wp-includes/version.php'; + include $versions_path; + + $url = 'https://api.wordpress.org/core/stable-check/1.0/'; + + $options = array( + 'timeout' => 30 + ); + $headers = array( + 'Accept' => 'application/json' + ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); + + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( "Failed to get latest version list." ); + } + + $release_data = json_decode( $response->body ); + $release_versions = array_keys( (array) $release_data ); + usort( $release_versions, function( $a, $b ){ + return 1 === version_compare( $a, $b ); + }); + + $locale = get_locale(); + $compare_version = str_replace( '-src', '', $GLOBALS['wp_version'] ); + + $updates = array( + 'major' => false, + 'minor' => false, + ); + foreach ( $release_versions as $release_version ) { - $difference = array(); - foreach ( $updates as $processed ) { - $processed_parts = explode( '.', $processed['version'] ); + $update_type = Utils\get_named_sem_ver( $release_version, $compare_version ); + if ( ! $update_type ) { + continue; + } - // later releases are always later in the array - if ( $processed_parts[0] !== $release_parts[0] - || $processed_parts[1] !== $release_parts[1] ) { - $difference[] = $processed; + // WordPress follow its own versioning which is roughly equivalent to semver + if ( 'minor' === $update_type ) { + $update_type = 'major'; + } else if ( 'patch' === $update_type ) { + $update_type = 'minor'; } + + if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $release_version, $updates[ $update_type ]['version'] ) ) { + continue; + } + + $updates[ $update_type ] = array( + 'version' => $release_version, + 'update_type' => $update_type, + 'package_url' => $this->get_download_url( $release_version, $locale ) + ); } - return $difference; + foreach( $updates as $type => $value ) { + if ( empty( $value ) ) { + unset( $updates[ $type ] ); + } + } + + foreach( array( 'major', 'minor' ) as $type ) { + if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { + return ! empty( $updates[ $type ] ) ? array( $updates[ $type ] ) : false; + } + } + return array_values( $updates ); } } From ebf9b59de75fd365b8a4a25703450ebcd61457b3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Dec 2015 15:22:30 -0800 Subject: [PATCH 3884/5359] Use `--minor` flag with `wp core update` to update to latest minor --- features/core.feature | 19 +++++++++++++++++++ php/commands/core.php | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 74e45feaa..24f61c1c5 100644 --- a/features/core.feature +++ b/features/core.feature @@ -369,6 +369,25 @@ Feature: Manage WordPress installation 1 """ + @download + Scenario: Update to the latest minor release + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp core update --minor` + Then STDOUT should contain: + """ + Downloading update + """ + + When I run `wp core update --minor` + Then STDOUT should be: + """ + Success: WordPress is at the latest minor release. + """ + Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory diff --git a/php/commands/core.php b/php/commands/core.php index 59b784cb1..91ab75080 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -847,8 +847,11 @@ public function verify_checksums( $args, $assoc_args ) { * [<zip>] * : Path to zip file to use, instead of downloading from wordpress.org. * + * [--minor] + * : Only perform updates for minor releases. + * * [--version=<version>] - * : Update to this version, instead of to the latest version. + * : Update to a specific version, instead of to the latest version. * * [--force] * : Update even when installed WP version is greater than the requested version. @@ -872,6 +875,16 @@ function update( $args, $assoc_args ) { $update = $from_api = null; $upgrader = 'WP_CLI\\CoreUpgrader'; + if ( empty( $args[0] ) && empty( $assoc_args['version'] ) && \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) ) { + $updates = $this->get_updates( array( 'minor' => true ) ); + if ( ! empty( $updates ) ) { + $assoc_args['version'] = $updates['version']; + } else { + WP_CLI::success( 'WordPress is at the latest minor release.' ); + return; + } + } + if ( ! empty( $args[0] ) ) { $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; From 6450d322020a4f8fee372844b29b601236623670 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 08:08:05 -0800 Subject: [PATCH 3885/5359] Increase minimum supported WP version to 3.7.11 --- .travis.yml | 4 ++-- php/WP_CLI/Runner.php | 2 +- php/wp-settings-cli.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c058d4068..90ef90221 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,9 +33,9 @@ env: matrix: include: - php: 5.3 - env: WP_VERSION=3.5.2 DEPLOY_BRANCH=master + env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master - php: 5.6 - env: WP_VERSION=3.5.2 + env: WP_VERSION=3.7.11 - php: 5.6 env: WP_VERSION=latest - php: 5.6 diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 799518ed3..1de58f573 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -513,7 +513,7 @@ private function check_wp_version() { include ABSPATH . 'wp-includes/version.php'; - $minimum_version = '3.5.2'; + $minimum_version = '3.7'; // @codingStandardsIgnoreStart if ( version_compare( $wp_version, $minimum_version, '<' ) ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 544f2cfb5..f4f23c4ba 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -199,7 +199,7 @@ require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/embed.php' ); -Utils\maybe_require( '3.5-alpha-22024', ABSPATH . WPINC . '/class-wp-embed.php' ); +require( ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/media.php' ); Utils\maybe_require( '4.4-alpha-34903', ABSPATH . WPINC . '/class-wp-oembed-controller.php' ); require( ABSPATH . WPINC . '/http.php' ); From 1a2a438b960669360e83fd7c88e666d14642c866 Mon Sep 17 00:00:00 2001 From: Steve Persch <steve.persch@pantheon.io> Date: Sun, 6 Dec 2015 14:48:41 -0500 Subject: [PATCH 3886/5359] Writing a behat test to cover https://github.com/wp-cli/wp-cli/issues/2246 --- features/menu.feature | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 8c0f059bd..f2b554d6b 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -111,3 +111,32 @@ Feature: Manage WordPress menus """ 0 """ + + Scenario: Preserve grandparent item as ancestor of child item when parent item is removed. + + When I run `wp menu create "Grandparent Test"` + Then STDOUT should not be empty + + When I run `wp menu item add-custom grandparent-test Grandparent http://example.com/grandparent --porcelain` + Then save STDOUT as {GRANDPARENT_ID} + + When I run `wp menu item add-custom grandparent-test Parent http://example.com/parent --porcelain --parent-id={GRANDPARENT_ID}` + Then save STDOUT as {PARENT_ID} + + When I run `wp menu item add-custom grandparent-test Child http://example.com/child --porcelain --parent-id={PARENT_ID}` + Then save STDOUT as {CHILD_ID} + + When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` + Then STDOUT should be a table containing rows: + | title | db_id | menu_item_parent | + | Grandparent | {GRANDPARENT_ID} | 0 | + | Parent | {PARENT_ID} | {GRANDPARENT_ID} | + | Child | {CHILD_ID} | {PARENT_ID} | + + When I run `wp menu item delete {PARENT_ID}` + + When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` + Then STDOUT should be a table containing rows: + | title | db_id | menu_item_parent | + | Grandparent | {GRANDPARENT_ID} | 0 | + | Child | {CHILD_ID} | {GRANDPARENT_ID} | From 667d6e67a26765278f901c34c5ef39494ee13c5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 08:42:20 -0800 Subject: [PATCH 3887/5359] Properly update menu sub-item parent when parent is deleted --- php/commands/menu.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index fd1a5428e..33cfcf0fa 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -476,12 +476,23 @@ public function update( $args, $assoc_args ) { * @subcommand delete */ public function delete( $args, $_ ) { + global $wpdb; foreach( $args as $arg ) { + $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); $ret = wp_delete_post( $arg, true ); if ( ! $ret ) { WP_CLI::warning( "Couldn't delete menu item." ); + } else if ( $parent_menu_id ) { + $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); + if ( $children ) { + $children_query = $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %d WHERE meta_key = '_menu_item_menu_item_parent' AND meta_value=%s", $parent_menu_id, (int) $arg ); + $wpdb->query( $children_query ); + foreach( $children as $child ) { + clean_post_cache( $child ); + } + } } } From 52541f32f74870e182763b1253b5ae56d19d8a8e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 09:10:47 -0800 Subject: [PATCH 3888/5359] Only call `wp core language update` when WP >= 4.0 The utility isn't available before then. --- php/WP_CLI/CommandWithUpgrade.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 8d988e2ce..b265e370b 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -14,7 +14,9 @@ function __construct() { // After updating plugins/themes also update translations by running the `core language update` command. add_action( 'upgrader_process_complete', function() { remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); - \WP_CLI::run_command( array( 'core', 'language', 'update' ), array( 'dry-run' => false ) ); + if ( Utils\wp_version_compare( '4.0', '>=' ) ) { + \WP_CLI::run_command( array( 'core', 'language', 'update' ), array( 'dry-run' => false ) ); + } }, 1 ); } From 17e2877090b999bc65cc6dca215421fd677cfd1d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 10:58:10 -0800 Subject: [PATCH 3889/5359] Defer to `$PAGER` environment variable when set Doing so gives more control to the end user on how their output will be presented. --- php/commands/help.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 5b2c3cf5e..4894c54f3 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -91,7 +91,9 @@ private static function indent( $whitespace, $text ) { private static function pass_through_pager( $out ) { - $pager = Utils\is_windows() ? 'more' : 'less -r'; + if ( false === ( $pager = getenv( 'PAGER' ) ) ) { + $pager = Utils\is_windows() ? 'more' : 'less -r'; + } // convert string to file handle $fd = fopen( "php://temp", "r+" ); From fabbf7b75050ccda7b458ee6784fd90d4eb3b255 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 11:35:35 -0800 Subject: [PATCH 3890/5359] Delete all post or user meta with `--all` flag --- features/post-meta.feature | 33 ++++++++++++++++++++++++++++ php/WP_CLI/CommandWithMeta.php | 39 ++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/features/post-meta.feature b/features/post-meta.feature index 74b30eabc..307edf060 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -62,3 +62,36 @@ Feature: Manage post custom fields | 1 | apple | banana | | 1 | apple | banana | | 1 | banana | ["apple","apple"] | + + Scenario: Delete all post meta + Given a WP install + + When I run `wp post meta add 1 apple banana` + And I run `wp post meta add 1 _foo banana` + Then STDOUT should not be empty + + When I run `wp post meta list 1 --format=count` + Then STDOUT should be: + """ + 2 + """ + + When I try `wp post meta delete 1` + Then STDERR should be: + """ + Error: Please specify a meta key, or use the --all flag. + """ + + When I run `wp post meta delete 1 --all` + Then STDOUT should contain: + """ + Deleted 'apple' custom field. + Deleted '_foo' custom field. + Success: Deleted all custom fields. + """ + + When I run `wp post meta list 1 --format=count` + Then STDOUT should be: + """ + 0 + """ diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 15824298d..0e8a07a39 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -107,25 +107,50 @@ public function get( $args, $assoc_args ) { * <id> * : The ID of the object. * - * <key> + * [<key>] * : The name of the meta field to delete. * * [<value>] * : The value to delete. If omitted, all rows with key will deleted. + * + * [--all] + * : Delete all meta for the object. */ public function delete( $args, $assoc_args ) { - list( $object_id, $meta_key ) = $args; + list( $object_id ) = $args; + $meta_key = ! empty( $args[1] ) ? $args[1] : ''; $meta_value = ! empty( $args[2] ) ? $args[2] : ''; - $object_id = $this->check_object_id( $object_id ); + if ( empty( $meta_key ) && ! Utils\get_flag_value( $assoc_args, 'all' ) ) { + WP_CLI::error( 'Please specify a meta key, or use the --all flag.' ); + } - $success = delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + $object_id = $this->check_object_id( $object_id ); - if ( $success ) { - WP_CLI::success( "Deleted custom field." ); + if ( Utils\get_flag_value( $assoc_args, 'all' ) ) { + $errors = false; + foreach( get_metadata( $this->meta_type, $object_id ) as $meta_key => $values ) { + $success = delete_metadata( $this->meta_type, $object_id, $meta_key ); + if ( $success ) { + WP_CLI::log( "Deleted '{$meta_key}' custom field." ); + } else { + WP_CLI::warning( "Failed to delete '{$meta_key}' custom field." ); + $errors = true; + } + } + if ( $errors ) { + WP_CLI::error( 'Failed to delete all custom fields.' ); + } else { + WP_CLI::success( 'Deleted all custom fields.' ); + } } else { - WP_CLI::error( "Failed to delete custom field." ); + $success = delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); + if ( $success ) { + WP_CLI::success( "Deleted custom field." ); + } else { + WP_CLI::error( "Failed to delete custom field." ); + } } } From 5d5c702434c653a58e63ce9f3b6b843ec8884a05 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 11:45:52 -0800 Subject: [PATCH 3891/5359] Document CSV values for `wp post list --post__in=<ids>` --- php/commands/post.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/post.php b/php/commands/post.php index 5a5198ce5..b0e9fadf8 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -288,6 +288,8 @@ public function delete( $args, $assoc_args ) { * * wp post list --post_type=page,post --format=ids * + * wp post list --post__in=1,3 + * * @subcommand list */ public function list_( $_, $assoc_args ) { From cf8631cb6d800ae4dfd32221735a93f5667406c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 12:54:08 -0800 Subject: [PATCH 3892/5359] A more helpful error message when a plugin or theme slug doesn't exist We can, more or less, safely interpret this `WP_Error` response to mean no matching plugins or themes. --- features/upgradables.feature | 6 ++++++ php/WP_CLI/CommandWithUpgrade.php | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 49c40a05f..fd66e585d 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -175,6 +175,12 @@ Feature: Manage WordPress themes and plugins Showing 2 of """ + When I try `wp <type> install an-impossible-slug-because-abc3fr` + Then STDERR should contain: + """ + Warning: Couldn't find 'an-impossible-slug-because-abc3fr' in the WordPress.org <type> directory. + """ + Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | | theme | Theme | p2 | P2 | 1.0.1 | https://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index b265e370b..9b71ea1c7 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -141,7 +141,14 @@ function install( $args, $assoc_args ) { $result = $this->install_from_repo( $slug, $assoc_args ); if ( is_wp_error( $result ) ) { - \WP_CLI::warning( "$slug: " . $result->get_error_message() ); + + $key = $result->get_error_code(); + if ( in_array( $result->get_error_code(), array( 'plugins_api_failed', 'themes_api_failed' ) ) + && ! empty( $result->error_data[ $key ] ) && in_array( $result->error_data[ $key ], array( 'N;', 'b:0;' ) ) ) { + \WP_CLI::warning( "Couldn't find '$slug' in the WordPress.org {$this->item_type} directory." ); + } else { + \WP_CLI::warning( "$slug: " . $result->get_error_message() ); + } } } From 45ad777d3ae7d193d4c53d4324d997bac9863708 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 12:58:57 -0800 Subject: [PATCH 3893/5359] Split `media import` and `media regenerate` into separate test files --- features/media-import.feature | 48 +++++++++++++++++++ ...media.feature => media-regenerate.feature} | 48 +------------------ 2 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 features/media-import.feature rename features/{media.feature => media-regenerate.feature} (69%) diff --git a/features/media-import.feature b/features/media-import.feature new file mode 100644 index 000000000..adc20bcaf --- /dev/null +++ b/features/media-import.feature @@ -0,0 +1,48 @@ +Feature: Manage WordPress attachments + + Background: + Given a WP install + + Scenario: Import image from remote URL + When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` + Then STDOUT should contain: + """ + Success: Imported file http://wp-cli.org/behat-data/codeispoetry.png + """ + + Scenario: Fail to import missing image + When I try `wp media import gobbledygook.png` + Then STDERR should contain: + """ + Unable to import file gobbledygook.png. Reason: File doesn't exist. + """ + + Scenario: Import a file as attachment from a local image + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` + Then STDOUT should contain: + """ + Success: Imported file + """ + And STDOUT should contain: + """ + and attached to post 1 as featured image + """ + And the {CACHE_DIR}/large-image.jpg file should exist + + Scenario: Import a file as an attachment but porcelain style + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + + When I run `wp post get {ATTACHMENT_ID} --field=title` + Then STDOUT should be: + """ + My imported attachment + """ diff --git a/features/media.feature b/features/media-regenerate.feature similarity index 69% rename from features/media.feature rename to features/media-regenerate.feature index c753624e2..a589b334e 100644 --- a/features/media.feature +++ b/features/media-regenerate.feature @@ -1,5 +1,5 @@ -Feature: Manage WordPress attachments - +Feature: Regenerate WordPress attachments + Background: Given a WP install @@ -10,50 +10,6 @@ Feature: Manage WordPress attachments No images found. """ - Scenario: Import image from remote URL - When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` - Then STDOUT should contain: - """ - Success: Imported file http://wp-cli.org/behat-data/codeispoetry.png - """ - - Scenario: Fail to import missing image - When I try `wp media import gobbledygook.png` - Then STDERR should contain: - """ - Unable to import file gobbledygook.png. Reason: File doesn't exist. - """ - - Scenario: Import a file as attachment from a local image - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` - Then STDOUT should contain: - """ - Success: Imported file - """ - And STDOUT should contain: - """ - and attached to post 1 as featured image - """ - And the {CACHE_DIR}/large-image.jpg file should exist - - Scenario: Import a file as an attachment but porcelain style - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - - When I run `wp post get {ATTACHMENT_ID} --field=title` - Then STDOUT should be: - """ - My imported attachment - """ - Scenario: Delete existing thumbnails when media is regenerated Given download: | path | url | From 2e4c10d7eb3eb80ba5503f4ed04a115e9bd4b4ef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Dec 2015 15:30:43 -0800 Subject: [PATCH 3894/5359] Support `--fields=<fields>` for `wp rewrite list` --- features/rewrite.feature | 10 +++++++--- php/commands/rewrite.php | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index d2908d4f5..f5c22050d 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -29,10 +29,14 @@ Feature: Manage WordPress rewrites | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | | section/(.+?)/?$ | index.php?category_name=$matches[1] | category | - When I run `wp rewrite list --match=/topic/apple/ --format=csv` + When I run `wp rewrite list --match=/topic/apple/ --format=csv --fields=match,query` Then STDOUT should be CSV containing: - | match | query | source | - | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | + | match | query | + | topic/([^/]+)/?$ | index.php?tag=$matches[1] | + And STDOUT should not contain: + """ + source + """ Scenario: Missing permalink_structure Given a WP install diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index ed0e046cd..db2c9946f 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -151,6 +151,9 @@ public function structure( $args, $assoc_args ) { * [--source=<source>] * : Show rewrite rules from a particular source. * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to match,query,source. + * * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * @@ -172,7 +175,8 @@ public function list_( $args, $assoc_args ) { $defaults = array( 'source' => '', 'match' => '', - 'format' => 'table' + 'format' => 'table', + 'fields' => 'match,query,source', ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -221,7 +225,7 @@ public function list_( $args, $assoc_args ) { $rule_list[] = compact( 'match', 'query', 'source' ); } - WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, array('match', 'query', 'source' ) ); + WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, explode( ',', $assoc_args['fields'] ) ); } /** From a0c795fd593c5bd5cdad5aea1904d9b16e319e02 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <ernilambar@users.noreply.github.com> Date: Wed, 9 Dec 2015 10:21:09 +0545 Subject: [PATCH 3895/5359] Fixing spacing around parenthesis --- templates/child_theme_functions.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache index 395cf0def..d654c23db 100644 --- a/templates/child_theme_functions.mustache +++ b/templates/child_theme_functions.mustache @@ -6,7 +6,7 @@ function {{parent_theme_function_safe}}_parent_theme_enqueue_styles() { wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); wp_enqueue_style( '{{slug}}-style', get_stylesheet_directory_uri() . '/style.css', - array('{{parent_theme}}-style') + array( '{{parent_theme}}-style' ) ); } From db0f3249ce0f05c96eb732e967e8e3dc39fe05a4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 05:13:03 -0800 Subject: [PATCH 3896/5359] Update tests for WordPress 4.4 --- features/core.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 24f61c1c5..db1d4403b 100644 --- a/features/core.feature +++ b/features/core.feature @@ -338,7 +338,7 @@ Feature: Manage WordPress installation When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | + | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | When I run `wp core check-update --format=count` @@ -350,7 +350,7 @@ Feature: Manage WordPress installation When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.3.1 | major | https://wordpress.org/wordpress-4.3.1.zip | + | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: From ff2e5b30a5746d25a2ba9001d0fbc4b71331e48e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 05:16:48 -0800 Subject: [PATCH 3897/5359] Split `core download` tests into a separate feature file --- features/core-download.feature | 69 +++++++++++++++++++++++++++++++++ features/core.feature | 70 ---------------------------------- 2 files changed, 69 insertions(+), 70 deletions(-) create mode 100644 features/core-download.feature diff --git a/features/core-download.feature b/features/core-download.feature new file mode 100644 index 000000000..c36801b82 --- /dev/null +++ b/features/core-download.feature @@ -0,0 +1,69 @@ +Feature: Download WordPress + + Scenario: Empty dir + Given an empty directory + And an empty cache + + When I try `wp core is-installed` + Then the return code should be 1 + And STDERR should not be empty + + When I run `wp core download` + And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} + Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist + + When I run `mkdir inner` + And I run `cd inner && wp core download` + Then the inner/wp-settings.php file should exist + + # test core tarball cache + When I run `wp core download --force` + Then the wp-settings.php file should exist + And STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz'... + """ + + Scenario: Localized install + Given an empty directory + And an empty cache + When I run `wp core download --locale=de_DE` + And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} + Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist + + Scenario: Catch download of non-existent WP version + Given an empty directory + + When I try `wp core download --version=4.1.0 --force` + Then STDERR should contain: + """ + Error: Release not found. + """ + + Scenario: Core download to a directory specified by `--path` in custom command + Given a WP install + And a download-command.php file: + """ + <?php + class Download_Command extends WP_CLI_Command { + public function __invoke() { + WP_CLI::run_command( array( 'core', 'download' ), array( 'path' => 'src/' ) ); + } + } + WP_CLI::add_command( 'custom-download', 'Download_Command' ); + """ + + When I run `wp --require=download-command.php custom-download` + Then STDOUT should not be empty + And the src directory should contain: + """ + wp-load.php + """ + + When I try `wp --require=download-command.php custom-download` + Then STDERR should be: + """ + Error: WordPress files seem to already be present here. + """ diff --git a/features/core.feature b/features/core.feature index db1d4403b..079581e65 100644 --- a/features/core.feature +++ b/features/core.feature @@ -1,40 +1,5 @@ Feature: Manage WordPress installation - @download - Scenario: Empty dir - Given an empty directory - And an empty cache - - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp core download` - And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} - Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist - - When I run `mkdir inner` - And I run `cd inner && wp core download` - Then the inner/wp-settings.php file should exist - - # test core tarball cache - When I run `wp core download --force` - Then the wp-settings.php file should exist - And STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz'... - """ - - @download - Scenario: Localized install - Given an empty directory - And an empty cache - When I run `wp core download --locale=de_DE` - And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} - Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist - Scenario: No wp-config.php Given an empty directory And WP files @@ -461,15 +426,6 @@ Feature: Manage WordPress installation http://localhost:8001 """ - Scenario: Catch download of non-existent WP version - Given an empty directory - - When I try `wp core download --version=4.1.0 --force` - Then STDERR should contain: - """ - Error: Release not found. - """ - Scenario: Test output in a multisite install with custom base path Given a WP install @@ -480,32 +436,6 @@ Feature: Manage WordPress installation Hello world! """ - Scenario: Core download to a directory specified by `--path` in custom command - Given a WP install - And a download-command.php file: - """ - <?php - class Download_Command extends WP_CLI_Command { - public function __invoke() { - WP_CLI::run_command( array( 'core', 'download' ), array( 'path' => 'src/' ) ); - } - } - WP_CLI::add_command( 'custom-download', 'Download_Command' ); - """ - - When I run `wp --require=download-command.php custom-download` - Then STDOUT should not be empty - And the src directory should contain: - """ - wp-load.php - """ - - When I try `wp --require=download-command.php custom-download` - Then STDERR should be: - """ - Error: WordPress files seem to already be present here. - """ - Scenario: Ensure cached partial upgrades aren't used in full upgrade Given a WP install And an empty cache From 4cc8b046d6abc97d2467cbf673eafcd627fba2ce Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 05:19:41 -0800 Subject: [PATCH 3898/5359] Split `core config` tests into a separate feature file --- features/core-config.feature | 62 ++++++++++++++++++++++++++++++++++++ features/core.feature | 61 ----------------------------------- 2 files changed, 62 insertions(+), 61 deletions(-) create mode 100644 features/core-config.feature diff --git a/features/core-config.feature b/features/core-config.feature new file mode 100644 index 000000000..d940433e5 --- /dev/null +++ b/features/core-config.feature @@ -0,0 +1,62 @@ +Feature: Manage wp-config + + Scenario: No wp-config.php + Given an empty directory + And WP files + + When I try `wp core is-installed` + Then the return code should be 1 + And STDERR should not be empty + + When I run `wp core version` + Then STDOUT should not be empty + + When I try `wp core install` + Then the return code should be 1 + And STDERR should be: + """ + Error: wp-config.php not found. + Either create one manually or use `wp core config`. + """ + + Given a wp-config-extra.php file: + """ + define( 'WP_DEBUG_LOG', true ); + """ + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` + Then the wp-config.php file should contain: + """ + define('AUTH_SALT', + """ + And the wp-config.php file should contain: + """ + define( 'WP_DEBUG_LOG', true ); + """ + And the wp-config.php file should not contain: + """ + define( 'WPLANG', '' ); + """ + + When I try the previous command again + Then the return code should be 1 + And STDERR should not be empty + + Scenario: Configure with existing salts + Given an empty directory + And WP files + + When I run `wp core config {CORE_CONFIG_SETTINGS} --skip-salts --extra-php < /dev/null` + Then the wp-config.php file should not contain: + """ + define('AUTH_SALT', + """ + + Scenario: Define WPLANG when running WP < 4.0 + Given an empty directory + And I run `wp core download --version=3.9 --force` + + When I run `wp core config {CORE_CONFIG_SETTINGS}` + Then the wp-config.php file should contain: + """ + define('WPLANG', ''); + """ diff --git a/features/core.feature b/features/core.feature index 079581e65..3c04a4826 100644 --- a/features/core.feature +++ b/features/core.feature @@ -1,66 +1,5 @@ Feature: Manage WordPress installation - Scenario: No wp-config.php - Given an empty directory - And WP files - - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp core version` - Then STDOUT should not be empty - - When I try `wp core install` - Then the return code should be 1 - And STDERR should be: - """ - Error: wp-config.php not found. - Either create one manually or use `wp core config`. - """ - - Given a wp-config-extra.php file: - """ - define( 'WP_DEBUG_LOG', true ); - """ - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` - Then the wp-config.php file should contain: - """ - define('AUTH_SALT', - """ - And the wp-config.php file should contain: - """ - define( 'WP_DEBUG_LOG', true ); - """ - And the wp-config.php file should not contain: - """ - define( 'WPLANG', '' ); - """ - - When I try the previous command again - Then the return code should be 1 - And STDERR should not be empty - - Scenario: Configure with existing salts - Given an empty directory - And WP files - - When I run `wp core config {CORE_CONFIG_SETTINGS} --skip-salts --extra-php < /dev/null` - Then the wp-config.php file should not contain: - """ - define('AUTH_SALT', - """ - - Scenario: Define WPLANG when running WP < 4.0 - Given an empty directory - And I run `wp core download --version=3.9 --force` - - When I run `wp core config {CORE_CONFIG_SETTINGS}` - Then the wp-config.php file should contain: - """ - define('WPLANG', ''); - """ - Scenario: Database doesn't exist Given an empty directory And WP files From 270734e50d4aff9654b10b76c495b9db0e42a73d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 05:22:27 -0800 Subject: [PATCH 3899/5359] Split `core check-update` features into a separate file --- features/core-check-update.feature | 41 ++++++++++++++++++++++++++++++ features/core.feature | 41 ------------------------------ 2 files changed, 41 insertions(+), 41 deletions(-) create mode 100644 features/core-check-update.feature diff --git a/features/core-check-update.feature b/features/core-check-update.feature new file mode 100644 index 000000000..4d6acc236 --- /dev/null +++ b/features/core-check-update.feature @@ -0,0 +1,41 @@ +Feature: Check for more recent versions + + Scenario: Check for update via Version Check API + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp core check-update` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | + | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | + + When I run `wp core check-update --format=count` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp core check-update --major` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | + + When I run `wp core check-update --major --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp core check-update --minor` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | + + When I run `wp core check-update --minor --format=count` + Then STDOUT should be: + """ + 1 + """ diff --git a/features/core.feature b/features/core.feature index 3c04a4826..2749168b8 100644 --- a/features/core.feature +++ b/features/core.feature @@ -232,47 +232,6 @@ Feature: Manage WordPress installation 3.9 """ - @download @update-check - Scenario: Check for update via Version Check API - Given a WP install - - When I run `wp core download --version=3.8 --force` - Then STDOUT should not be empty - - When I run `wp core check-update` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | - | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | - - When I run `wp core check-update --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp core check-update --major` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | - - When I run `wp core check-update --major --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp core check-update --minor` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | - - When I run `wp core check-update --minor --format=count` - Then STDOUT should be: - """ - 1 - """ - @download Scenario: Update to the latest minor release Given a WP install From b51bac798186ce61c474734efae2094555cc5ec5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 05:25:33 -0800 Subject: [PATCH 3900/5359] Split `core update` tests into a separate file --- features/core-update.feature | 151 +++++++++++++++++++++++++++++++++++ features/core.feature | 151 ----------------------------------- 2 files changed, 151 insertions(+), 151 deletions(-) create mode 100644 features/core-update.feature diff --git a/features/core-update.feature b/features/core-update.feature new file mode 100644 index 000000000..0604fdb6e --- /dev/null +++ b/features/core-update.feature @@ -0,0 +1,151 @@ +Feature: Update WordPress core + + Scenario: Update from a ZIP file + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp eval 'echo $GLOBALS["wp_version"];'` + Then STDOUT should be: + """ + 3.8 + """ + + When I run `wget http://wordpress.org/wordpress-3.9.zip --quiet` + And I run `wp core update wordpress-3.9.zip` + Then STDOUT should be: + """ + Starting update... + Unpacking the update... + Success: WordPress updated successfully. + """ + + When I run `wp eval 'echo $GLOBALS["wp_version"];'` + Then STDOUT should be: + """ + 3.9 + """ + + Scenario: Update to the latest minor release + Given a WP install + + When I run `wp core download --version=3.8 --force` + Then STDOUT should not be empty + + When I run `wp core update --minor` + Then STDOUT should contain: + """ + Downloading update + """ + + When I run `wp core update --minor` + Then STDOUT should be: + """ + Success: WordPress is at the latest minor release. + """ + + Scenario: Core update from cache + Given a WP install + And an empty cache + + When I run `wp core update --version=3.8.1 --force` + Then STDOUT should not contain: + """ + Using cached file + """ + And STDOUT should contain: + """ + Downloading + """ + + When I run `wp core update --version=3.9 --force` + Then STDOUT should not be empty + + When I run `wp core update --version=3.8.1 --force` + Then STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-3.8.1-en_US.zip'... + """ + And STDOUT should not contain: + """ + Downloading + """ + + Scenario: Don't run update when up-to-date + Given a WP install + And I run `wp core update` + + When I run `wp core update` + Then STDOUT should contain: + """ + WordPress is up to date + """ + And STDOUT should not contain: + """ + Updating + """ + + When I run `wp core update --force` + Then STDOUT should contain: + """ + Updating + """ + + Scenario: Ensure cached partial upgrades aren't used in full upgrade + Given a WP install + And an empty cache + And a wp-content/mu-plugins/upgrade-override.php file: + """ + <?php + add_filter( 'pre_site_transient_update_core', function(){ + return (object) array( + 'updates' => array( + (object) array( + 'response' => 'autoupdate', + 'download' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', + 'locale' => 'en_US', + 'packages' => (object) array( + 'full' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', + 'no_content' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-no-content.zip', + 'new_bundled' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-new-bundled.zip', + 'partial' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-partial-1.zip', + 'rollback' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-rollback-1.zip', + ), + 'current' => '4.2.4', + 'version' => '4.2.4', + 'php_version' => '5.2.4', + 'mysql_version' => '5.0', + 'new_bundled' => '4.1', + 'partial_version' => '4.2.1', + 'support_email' => 'updatehelp42@wordpress.org', + 'new_files' => '', + ), + ), + ); + }); + """ + + When I run `wp core download --version=4.2.1 --force` + And I run `wp core update` + Then STDOUT should not be empty + And the {SUITE_CACHE_DIR}/core directory should contain: + """ + wordpress-4.2.1-en_US.tar.gz + wordpress-4.2.4-partial-1-en_US.zip + """ + + When I run `wp core download --version=4.1.1 --force` + And I run `wp core update` + And I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ + And the {SUITE_CACHE_DIR}/core directory should contain: + """ + wordpress-4.1.1-en_US.tar.gz + wordpress-4.2.1-en_US.tar.gz + wordpress-4.2.4-no-content-en_US.zip + wordpress-4.2.4-partial-1-en_US.zip + """ diff --git a/features/core.feature b/features/core.feature index 2749168b8..13331c1c5 100644 --- a/features/core.feature +++ b/features/core.feature @@ -205,52 +205,6 @@ Feature: Manage WordPress installation Error: Multisite with subdomains cannot be configured when domain is 'localhost'. """ - Scenario: Update from a ZIP file - Given a WP install - - When I run `wp core download --version=3.8 --force` - Then STDOUT should not be empty - - When I run `wp eval 'echo $GLOBALS["wp_version"];'` - Then STDOUT should be: - """ - 3.8 - """ - - When I run `wget http://wordpress.org/wordpress-3.9.zip --quiet` - And I run `wp core update wordpress-3.9.zip` - Then STDOUT should be: - """ - Starting update... - Unpacking the update... - Success: WordPress updated successfully. - """ - - When I run `wp eval 'echo $GLOBALS["wp_version"];'` - Then STDOUT should be: - """ - 3.9 - """ - - @download - Scenario: Update to the latest minor release - Given a WP install - - When I run `wp core download --version=3.8 --force` - Then STDOUT should not be empty - - When I run `wp core update --minor` - Then STDOUT should contain: - """ - Downloading update - """ - - When I run `wp core update --minor` - Then STDOUT should be: - """ - Success: WordPress is at the latest minor release. - """ - Scenario: Custom wp-content directory Given a WP install And a custom wp-content directory @@ -258,53 +212,6 @@ Feature: Manage WordPress installation When I run `wp plugin status hello` Then STDOUT should not be empty - Scenario: Core update from cache - Given a WP install - And an empty cache - - When I run `wp core update --version=3.8.1 --force` - Then STDOUT should not contain: - """ - Using cached file - """ - And STDOUT should contain: - """ - Downloading - """ - - When I run `wp core update --version=3.9 --force` - Then STDOUT should not be empty - - When I run `wp core update --version=3.8.1 --force` - Then STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-3.8.1-en_US.zip'... - """ - And STDOUT should not contain: - """ - Downloading - """ - - Scenario: Don't run update when up-to-date - Given a WP install - And I run `wp core update` - - When I run `wp core update` - Then STDOUT should contain: - """ - WordPress is up to date - """ - And STDOUT should not contain: - """ - Updating - """ - - When I run `wp core update --force` - Then STDOUT should contain: - """ - Updating - """ - Scenario: User defined in wp-cli.yml Given an empty directory And WP files @@ -333,61 +240,3 @@ Feature: Manage WordPress installation """ Hello world! """ - - Scenario: Ensure cached partial upgrades aren't used in full upgrade - Given a WP install - And an empty cache - And a wp-content/mu-plugins/upgrade-override.php file: - """ - <?php - add_filter( 'pre_site_transient_update_core', function(){ - return (object) array( - 'updates' => array( - (object) array( - 'response' => 'autoupdate', - 'download' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', - 'locale' => 'en_US', - 'packages' => (object) array( - 'full' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', - 'no_content' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-no-content.zip', - 'new_bundled' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-new-bundled.zip', - 'partial' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-partial-1.zip', - 'rollback' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-rollback-1.zip', - ), - 'current' => '4.2.4', - 'version' => '4.2.4', - 'php_version' => '5.2.4', - 'mysql_version' => '5.0', - 'new_bundled' => '4.1', - 'partial_version' => '4.2.1', - 'support_email' => 'updatehelp42@wordpress.org', - 'new_files' => '', - ), - ), - ); - }); - """ - - When I run `wp core download --version=4.2.1 --force` - And I run `wp core update` - Then STDOUT should not be empty - And the {SUITE_CACHE_DIR}/core directory should contain: - """ - wordpress-4.2.1-en_US.tar.gz - wordpress-4.2.4-partial-1-en_US.zip - """ - - When I run `wp core download --version=4.1.1 --force` - And I run `wp core update` - And I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - And the {SUITE_CACHE_DIR}/core directory should contain: - """ - wordpress-4.1.1-en_US.tar.gz - wordpress-4.2.1-en_US.tar.gz - wordpress-4.2.4-no-content-en_US.zip - wordpress-4.2.4-partial-1-en_US.zip - """ From d3837e2023ffb9fcd051927b44a726bd38d1c864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 9 Dec 2015 16:38:25 +0100 Subject: [PATCH 3901/5359] Directing "issue openers" to wiki/How-to-solve-an-issue --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4063c7592..ae1980944 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Submitting patches Whether you want to fix a bug or implement a new feature, the process is pretty much the same: -0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, open a new issue so that you can get some initial feedback. +0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, [open a new issue](https://github.com/wp-cli/wp-cli/wiki/How-to-solve-an-issue) so that you can get some initial feedback. 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. 2. Create a branch for each issue you'd like to address. Commit your changes. 3. Push the code changes from your local clone to your fork. From 0fdb6eaed1a04d16b42574df607bbd7a3e2d0e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 9 Dec 2015 16:50:46 +0100 Subject: [PATCH 3902/5359] Rename of my rude Wiki page --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ae1980944..292dd1b8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Submitting patches Whether you want to fix a bug or implement a new feature, the process is pretty much the same: -0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, [open a new issue](https://github.com/wp-cli/wp-cli/wiki/How-to-solve-an-issue) so that you can get some initial feedback. +0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, [open a new issue](https://github.com/wp-cli/wp-cli/wiki/Creating-Helpful-Bug-Reports) so that you can get some initial feedback. 1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. 2. Create a branch for each issue you'd like to address. Commit your changes. 3. Push the code changes from your local clone to your fork. From e2e234fa9495ee13704a622e7621737b17f136f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 07:53:15 -0800 Subject: [PATCH 3903/5359] Load `utils-wp.php` right before `wp-settings-cli.php` is called This helps to reduce the difference between `wp-settings-cli.php` and `wp-settings.php`. It has no functional differences. --- php/WP_CLI/Runner.php | 3 +++ php/wp-settings-cli.php | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 1de58f573..444ebc2c0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -732,6 +732,9 @@ public function load_wordpress() { $this->maybe_update_url_from_domain_constant(); + // Load WP-CLI utilities + require WP_CLI_ROOT . '/php/utils-wp.php'; + // Load Core, mu-plugins, plugins, themes etc. require WP_CLI_ROOT . '/php/wp-settings-cli.php'; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index f4f23c4ba..953cd04ba 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -55,9 +55,6 @@ // Start loading timer. timer_start(); -// Load WP-CLI utilities -require WP_CLI_ROOT . '/php/utils-wp.php'; - // Check if we're in WP_DEBUG mode. Utils\wp_debug_mode(); From d13bff6bbf1fc0375f69b43855fe5f8e6d4155c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Dec 2015 09:07:31 -0800 Subject: [PATCH 3904/5359] Don't ever prefix rewrite rules with `index.php` Core does some fancy logic to determine whether `index.php` needs to be prepended to rewrite rules. `got_url_rewrite()` returns true if mod rewrite is available or `$GLOBALS['is_nginx']` is set. However, php-cli doesn't easily have access to these values. Instead, let's assume the developer knows the value they're passing, and that rewrites are configured for the site. --- php/commands/rewrite.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index db2c9946f..f0b9ca09b 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -81,12 +81,8 @@ public function structure( $args, $assoc_args ) { global $wp_rewrite; // copypasta from /wp-admin/options-permalink.php - $home_path = get_home_path(); - $iis7_permalinks = iis7_supports_permalinks(); $prefix = $blog_prefix = ''; - if ( ! got_mod_rewrite() && ! $iis7_permalinks ) - $prefix = '/index.php'; if ( is_multisite() && !is_subdomain_install() && is_main_site() ) $blog_prefix = '/blog'; From 1806acc122944ff1a0dc08cde20d65b81798ae9f Mon Sep 17 00:00:00 2001 From: Greg Anderson <greg.1.anderson@greenknowe.org> Date: Wed, 9 Dec 2015 09:30:58 -0800 Subject: [PATCH 3905/5359] Commit composer.lock to repository. --- .gitignore | 1 - composer.lock | 1240 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1240 insertions(+), 1 deletion(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 665e3e8af..27990f835 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -composer.lock config.yml /cache /vendor diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..7c51a4dda --- /dev/null +++ b/composer.lock @@ -0,0 +1,1240 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "7359993f535213af66c2148ea27369b3", + "content-hash": "da7f9e8dee2ffe0f76e5ed64233ecda9", + "packages": [ + { + "name": "composer/semver", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba", + "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "~2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com" + }, + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "time": "2015-09-21 09:42:36" + }, + { + "name": "mustache/mustache", + "version": "v2.9.0", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/mustache.php.git", + "reference": "c745b01956caf27d26b55a72a90aff56bc169cd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/c745b01956caf27d26b55a72a90aff56bc169cd6", + "reference": "c745b01956caf27d26b55a72a90aff56bc169cd6", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "fabpot/php-cs-fixer": "~1.6", + "phpunit/phpunit": "~3.7|~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Mustache": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", + "keywords": [ + "mustache", + "templating" + ], + "time": "2015-08-15 19:23:13" + }, + { + "name": "nb/oxymel", + "version": "v0.1.0", + "source": { + "type": "git", + "url": "https://github.com/nb/oxymel.git", + "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nb/oxymel/zipball/cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", + "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "type": "library", + "autoload": { + "psr-0": { + "Oxymel": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nikolay Bachiyski", + "email": "nb@nikolay.bg", + "homepage": "http://extrapolate.me/" + } + ], + "description": "A sweet XML builder", + "homepage": "https://github.com/nb/oxymel", + "keywords": [ + "xml" + ], + "time": "2013-02-24 15:01:54" + }, + { + "name": "ramsey/array_column", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/array_column.git", + "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/array_column/zipball/f8e52eb28e67eb50e613b451dd916abcf783c1db", + "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db", + "shasum": "" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "0.8.*", + "phpunit/phpunit": "~4.5", + "satooshi/php-coveralls": "0.6.*", + "squizlabs/php_codesniffer": "~2.2" + }, + "type": "library", + "autoload": { + "files": [ + "src/array_column.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "homepage": "http://benramsey.com" + } + ], + "description": "Provides functionality for array_column() to projects using PHP earlier than version 5.5.", + "homepage": "https://github.com/ramsey/array_column", + "keywords": [ + "array", + "array_column", + "column" + ], + "time": "2015-03-20 22:07:39" + }, + { + "name": "rmccue/requests", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/rmccue/Requests.git", + "reference": "6aac485666c2955077d77b796bbdd25f0013a4ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rmccue/Requests/zipball/6aac485666c2955077d77b796bbdd25f0013a4ea", + "reference": "6aac485666c2955077d77b796bbdd25f0013a4ea", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "psr-0": { + "Requests": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Ryan McCue", + "homepage": "http://ryanmccue.info" + } + ], + "description": "A HTTP library written in PHP, for human beings.", + "homepage": "http://github.com/rmccue/Requests", + "keywords": [ + "curl", + "fsockopen", + "http", + "idna", + "ipv6", + "iri", + "sockets" + ], + "time": "2014-05-18 04:59:02" + }, + { + "name": "symfony/config", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "61973327bfb054f6f470de7be033a28b76c1dc20" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/61973327bfb054f6f470de7be033a28b76c1dc20", + "reference": "61973327bfb054f6f470de7be033a28b76c1dc20", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/filesystem": "~2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "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 Config Component", + "homepage": "https://symfony.com", + "time": "2015-11-02 20:20:53" + }, + { + "name": "symfony/console", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "16bb1cb86df43c90931df65f529e7ebd79636750" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/16bb1cb86df43c90931df65f529e7ebd79636750", + "reference": "16bb1cb86df43c90931df65f529e7ebd79636750", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "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 Console Component", + "homepage": "https://symfony.com", + "time": "2015-11-18 09:54:26" + }, + { + "name": "symfony/dependency-injection", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "7a201bf08c29e47075047cbb378724ad46dfe217" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a201bf08c29e47075047cbb378724ad46dfe217", + "reference": "7a201bf08c29e47075047cbb378724ad46dfe217", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "conflict": { + "symfony/expression-language": "<2.6" + }, + "require-dev": { + "symfony/config": "~2.2", + "symfony/expression-language": "~2.6", + "symfony/yaml": "~2.1" + }, + "suggest": { + "symfony/config": "", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "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 DependencyInjection Component", + "homepage": "https://symfony.com", + "time": "2015-11-23 10:17:36" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "7e2f9c31645680026c2372edf66f863fc7757af5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7e2f9c31645680026c2372edf66f863fc7757af5", + "reference": "7e2f9c31645680026c2372edf66f863fc7757af5", + "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": "2015-10-30 20:10:21" + }, + { + "name": "symfony/filesystem", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e173509d7fdbbba3cf34d6d072f2073c0210c1d", + "reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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 Filesystem Component", + "homepage": "https://symfony.com", + "time": "2015-11-18 13:41:01" + }, + { + "name": "symfony/finder", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/a06a0c0ff7db3736a50d530c908cca547bf13da9", + "reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-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": "2015-10-30 20:10:21" + }, + { + "name": "symfony/translation", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/e4ecb9c3ba1304eaf24de15c2d7a428101c1982f", + "reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "conflict": { + "symfony/config": "<2.7" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.7", + "symfony/intl": "~2.4", + "symfony/yaml": "~2.2" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "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 Translation Component", + "homepage": "https://symfony.com", + "time": "2015-11-18 13:41:01" + }, + { + "name": "symfony/yaml", + "version": "v2.7.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4cfcd7a9fceba662b3c036b7d9a91f6197af046c", + "reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "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 Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-11-18 13:41:01" + }, + { + "name": "wp-cli/php-cli-tools", + "version": "v0.10.5", + "source": { + "type": "git", + "url": "https://github.com/wp-cli/php-cli-tools.git", + "reference": "037a010441a5c220cd1df26cdc9b20ad73408356" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/037a010441a5c220cd1df26cdc9b20ad73408356", + "reference": "037a010441a5c220cd1df26cdc9b20ad73408356", + "shasum": "" + }, + "require": { + "php": ">= 5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "cli": "lib/" + }, + "files": [ + "lib/cli/cli.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "James Logsdon", + "email": "jlogsdon@php.net", + "role": "Developer" + }, + { + "name": "Daniel Bachhuber", + "email": "daniel@handbuilt.co", + "role": "Maintainer" + } + ], + "description": "Console utilities for PHP", + "homepage": "http://github.com/wp-cli/php-cli-tools", + "keywords": [ + "cli", + "console" + ], + "time": "2015-08-10 12:46:19" + } + ], + "packages-dev": [ + { + "name": "behat/behat", + "version": "v2.5.5", + "source": { + "type": "git", + "url": "https://github.com/Behat/Behat.git", + "reference": "c1e48826b84669c97a1efa78459aedfdcdcf2120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Behat/zipball/c1e48826b84669c97a1efa78459aedfdcdcf2120", + "reference": "c1e48826b84669c97a1efa78459aedfdcdcf2120", + "shasum": "" + }, + "require": { + "behat/gherkin": "~2.3.0", + "php": ">=5.3.1", + "symfony/config": "~2.3", + "symfony/console": "~2.0", + "symfony/dependency-injection": "~2.0", + "symfony/event-dispatcher": "~2.0", + "symfony/finder": "~2.0", + "symfony/translation": "~2.3", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.19" + }, + "suggest": { + "behat/mink-extension": "for integration with Mink testing framework", + "behat/symfony2-extension": "for integration with Symfony2 web framework", + "behat/yii-extension": "for integration with Yii web framework" + }, + "bin": [ + "bin/behat" + ], + "type": "library", + "autoload": { + "psr-0": { + "Behat\\Behat": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Scenario-oriented BDD framework for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Symfony2" + ], + "time": "2015-06-01 09:37:55" + }, + { + "name": "behat/gherkin", + "version": "v2.3.5", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "2b33963da5525400573560c173ab5c9c057e1852" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/2b33963da5525400573560c173ab5c9c057e1852", + "reference": "2b33963da5525400573560c173ab5c9c057e1852", + "shasum": "" + }, + "require": { + "php": ">=5.3.1", + "symfony/finder": "~2.0" + }, + "require-dev": { + "symfony/config": "~2.0", + "symfony/translation": "~2.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "symfony/config": "If you want to use Config component to manage resources", + "symfony/translation": "If you want to use Symfony2 translations adapter", + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "DSL", + "Symfony2", + "parser" + ], + "time": "2013-10-15 11:22:17" + }, + { + "name": "phpunit/php-code-coverage", + "version": "1.2.18", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.2.0@stable", + "phpunit/php-token-stream": ">=1.1.3,<1.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2014-09-02 10:13:14" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2015-06-21 08:01:12" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2014-03-03 05:10:30" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.38", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~1.2", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.1", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~1.2", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "pear-pear.php.net/pear": "1.9.4" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2014-10-17 09:04:17" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.2" + }, + "platform-dev": [] +} From 45a70610bf14f8e0be1ae588e3d6969242bd3e71 Mon Sep 17 00:00:00 2001 From: Ryan Hoover <ryanshoover@gmail.com> Date: Wed, 9 Dec 2015 14:46:45 -0600 Subject: [PATCH 3906/5359] Fix typo in function synopsis There's a typo in the synopsis for `set`. That typo is causing fatal errors in commands like `wp transient set "51ecb1f884" "Cache rules everything around me." "2592001"` Adding in the missing **>** fixes the problem. --- php/commands/transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 4b6de95b0..6331f633f 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -40,7 +40,7 @@ public function get( $args, $assoc_args ) { * <value> * : Value to be set for the transient. * - * [<expiration] + * [<expiration>] * : Time until expiration, in seconds. */ public function set( $args ) { From 25418ce02e5337f311b19425ea377b5749ea2072 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 06:05:11 -0800 Subject: [PATCH 3907/5359] Failing test case for #2286 --- features/core-checksums.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/core-checksums.feature b/features/core-checksums.feature index 9c622976b..055639275 100644 --- a/features/core-checksums.feature +++ b/features/core-checksums.feature @@ -53,3 +53,13 @@ Feature: Validate checksums for WordPress install """ Error: WordPress install doesn't verify against checksums. """ + + Scenario: Verify core checksums for a non US local + Given a WP install + And I run `wp core download --locale=en_GB --version=4.3.1 --force` + + When I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ From 8fda3f656161fa5cf3b7b1f0db71963016beddfe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 06:08:28 -0800 Subject: [PATCH 3908/5359] Explicitly globalize `$wp_locale_package` This variable is included in non-US English locales --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 953cd04ba..000db74a5 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -21,7 +21,7 @@ * we're including version.php from another install and don't want * these values to be overridden if already set. */ -global $wp_version, $wp_db_version, $tinymce_version, $required_php_version, $required_mysql_version; +global $wp_version, $wp_db_version, $tinymce_version, $required_php_version, $required_mysql_version, $wp_local_package; require( ABSPATH . WPINC . '/version.php' ); /** From 666d9f91e88d7d2d9098977279fa779e8f1904aa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 06:10:26 -0800 Subject: [PATCH 3909/5359] Rename test file for consistency with command --- .../{core-checksums.feature => core-verify-checksums.feature} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename features/{core-checksums.feature => core-verify-checksums.feature} (100%) diff --git a/features/core-checksums.feature b/features/core-verify-checksums.feature similarity index 100% rename from features/core-checksums.feature rename to features/core-verify-checksums.feature From 5c65b1e5460ae62829e622cfe12d4f0fa7d17f49 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 13:52:22 -0800 Subject: [PATCH 3910/5359] Use `--only-missing` to only regenerate images missing sizes This flag is helpful on sites with lots of images where only a small number of images are missing sizes. Props @michalkleiner for much of the original code --- features/media-regenerate.feature | 42 +++++++++++++++++++ php/commands/media.php | 70 ++++++++++++++++++++++++------- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index a589b334e..a9048a1ff 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -103,3 +103,45 @@ Feature: Regenerate WordPress attachments """ Warning: Can't find """ + + Scenario: Only regenerate images which are missing sizes + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 100, 100, true ); + }); + """ + And I run `wp option update uploads_use_yearmonth_folders 0` + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + And the wp-content/uploads/large-image-100x100.jpg file should exist + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My second imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID2} + And the wp-content/uploads/large-image-1-100x100.jpg file should exist + + When I run `rm wp-content/uploads/large-image-100x100.jpg` + Then the wp-content/uploads/large-image-100x100.jpg file should not exist + + When I run `wp media regenerate --only-missing --yes` + Then STDOUT should contain: + """ + Found 2 images to regenerate. + """ + And STDOUT should contain: + """ + No thumbnail regeneration needed for "My second imported attachment" + """ + And STDOUT should contain: + """ + Regenerated thumbnails for "My imported attachment" + """ + And STDOUT should contain: + """ + Success: Finished regenerating all images. + """ diff --git a/php/commands/media.php b/php/commands/media.php index 9d9ff7a53..3bb2becee 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -18,6 +18,9 @@ class Media_Command extends WP_CLI_Command { * [--skip-delete] * : Skip deletion of the original thumbnails. If your thumbnails are linked from sources outside your control, it's likely best to leave them around. Defaults to false. * + * [--only-missing] + * : Only generate thumbnails for images missing image sizes. + * * [--yes] * : Answer yes to the confirmation message. * @@ -35,6 +38,10 @@ function regenerate( $args, $assoc_args = array() ) { } $skip_delete = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ); + $only_missing = \WP_CLI\Utils\get_flag_value( $assoc_args, 'only-missing' ); + if ( $only_missing ) { + $skip_delete = true; + } $query_args = array( 'post_type' => 'attachment', @@ -59,7 +66,7 @@ function regenerate( $args, $assoc_args = array() ) { $errored = false; foreach ( $images->posts as $id ) { - if ( ! $this->_process_regeneration( $id, $skip_delete ) ) { + if ( ! $this->_process_regeneration( $id, $skip_delete, $only_missing ) ) { $errored = true; } } @@ -210,7 +217,7 @@ private function _make_copy( $path ) { return $filename; } - private function _process_regeneration( $id, $skip_delete = false ) { + private function _process_regeneration( $id, $skip_delete = false, $only_missing = false ) { $fullsizepath = get_attached_file( $id ); @@ -225,21 +232,27 @@ private function _process_regeneration( $id, $skip_delete = false ) { $this->remove_old_images( $id ); } - $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); - if ( is_wp_error( $metadata ) ) { - WP_CLI::warning( $metadata->get_error_message() ); - return false; - } + if ( ! $only_missing || $this->needs_regeneration( $id ) ) { - if ( empty( $metadata ) ) { - WP_CLI::warning( "Couldn't regenerate thumbnails for $att_desc." ); - return false; - } + $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); + if ( is_wp_error( $metadata ) ) { + WP_CLI::warning( $metadata->get_error_message() ); + return false; + } + + if ( empty( $metadata ) ) { + WP_CLI::warning( "Couldn't regenerate thumbnails for $att_desc." ); + return false; + } - wp_update_attachment_metadata( $id, $metadata ); + wp_update_attachment_metadata( $id, $metadata ); - WP_CLI::log( "Regenerated thumbnails for $att_desc" ); - return true; + WP_CLI::log( "Regenerated thumbnails for $att_desc" ); + return true; + } else { + WP_CLI::log( "No thumbnail regeneration needed for $att_desc" ); + return true; + } } private function remove_old_images( $att_id ) { @@ -268,6 +281,35 @@ private function remove_old_images( $att_id ) { unlink( $intermediate_path ); } } + + private function needs_regeneration( $att_id ) { + $wud = wp_upload_dir(); + + $metadata = wp_get_attachment_metadata($att_id); + + if ( empty($metadata['file'] ) ) { + return false; + } + + $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; + $original_path = $dir_path . basename( $metadata['file'] ); + + if ( empty( $metadata['sizes'] ) ) { + return false; + } + + foreach( $metadata['sizes'] as $size_info ) { + $intermediate_path = $dir_path . $size_info['file']; + + if ( $intermediate_path == $original_path ) + continue; + + if ( ! file_exists( $intermediate_path ) ) { + return true; + } + } + return false; + } } WP_CLI::add_command( 'media', 'Media_Command', array( From 2baf7c2e6cdc120cdc6cfa1b91eb8f8f615b1747 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 14:07:04 -0800 Subject: [PATCH 3911/5359] Use `wp core update-db --dry-run` to see if database needs update This can be helpful for determining whether a backup should be made, without incurring a backup each time `wp core update-db` is run. --- features/core-update-db.feature | 36 +++++++++++++++++++++++++++++++++ php/commands/core.php | 16 ++++++++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index b26e596e6..140616e39 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -17,6 +17,18 @@ Feature: Update core's database Success: WordPress database already at latest db version 30133 """ + Scenario: Dry run update db on a single site + Given a WP install + And I run `wp core download --version=4.1 --force` + And I run `wp option update db_version 29630` + + When I run `wp core update-db --dry-run` + Then STDOUT should be: + """ + Performing a dry run, with no database modification. + Success: WordPress database upgraded successfully from db version 29630 to 30133 + """ + Scenario: Update db across network Given a WP multisite install And I run `wp site create --slug=foo` @@ -36,3 +48,27 @@ Feature: Update core's database """ Success: WordPress database upgraded on 3/3 sites """ + + Scenario: Update db across network + Given a WP multisite install + And I run `wp site create --slug=foo` + And I run `wp site create --slug=bar` + And I run `wp site create --slug=burrito --porcelain` + And save STDOUT as {BURRITO_ID} + And I run `wp site create --slug=taco --porcelain` + And save STDOUT as {TACO_ID} + And I run `wp site create --slug=pizza --porcelain` + And save STDOUT as {PIZZA_ID} + And I run `wp site archive {BURRITO_ID}` + And I run `wp site spam {TACO_ID}` + And I run `wp site delete {PIZZA_ID} --yes` + + When I run `wp core update-db --network --dry-run` + Then STDOUT should contain: + """ + Performing a dry run, with no database modification. + """ + And STDOUT should contain: + """ + Success: WordPress database upgraded on 3/3 sites + """ diff --git a/php/commands/core.php b/php/commands/core.php index 91ab75080..2045dabff 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -973,6 +973,9 @@ function update( $args, $assoc_args ) { * [--network] * : Update databases for all sites on a network * + * [--dry-run] + * : Compare database versions without performing the update. + * * @subcommand update-db */ function update_db( $_, $assoc_args ) { @@ -983,6 +986,11 @@ function update_db( $_, $assoc_args ) { WP_CLI::error( 'This is not a multisite install.' ); } + $dry_run = Utils\get_flag_value( $assoc_args, 'dry-run' ); + if ( $dry_run ) { + WP_CLI::log( 'Performing a dry run, with no database modification.' ); + } + if ( $network ) { $iterator_args = array( 'table' => $wpdb->blogs, @@ -993,7 +1001,7 @@ function update_db( $_, $assoc_args ) { foreach( $it as $blog ) { $total++; $url = $blog->domain . $blog->path; - $process = WP_CLI::launch_self( 'core update-db', array(), array(), false, true, array( 'url' => $url ) ); + $process = WP_CLI::launch_self( 'core update-db', array(), array(), false, true, array( 'url' => $url, 'dry-run' => $dry_run ) ); if ( 0 == $process->return_code ) { // See if we can parse the stdout if ( preg_match( '#Success: (.+)#', $process->stdout, $matches ) ) { @@ -1007,7 +1015,7 @@ function update_db( $_, $assoc_args ) { WP_CLI::warning( "Database failed to upgrade on {$url}" ); } } - if ( $total && $success == $total ) { + if ( ! $dry_run && $total && $success == $total ) { update_site_option( 'wpmu_upgrade_site', $wp_db_version ); } WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites', $success, $total ) ); @@ -1015,7 +1023,9 @@ function update_db( $_, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); $wp_current_db_version = __get_option( 'db_version' ); if ( $wp_db_version != $wp_current_db_version ) { - wp_upgrade(); + if ( ! $dry_run ) { + wp_upgrade(); + } WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}" ); } else { WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}" ); From 7b6321ab059dbcc940f8edd499b8e68967d30d89 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 14:35:40 -0800 Subject: [PATCH 3912/5359] Dashed image names were introduced in WP 4.4 We can remove this assertion without affecting the integrity of the test --- features/media-regenerate.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index a9048a1ff..fb4f99be6 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -123,7 +123,6 @@ Feature: Regenerate WordPress attachments When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My second imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID2} - And the wp-content/uploads/large-image-1-100x100.jpg file should exist When I run `rm wp-content/uploads/large-image-100x100.jpg` Then the wp-content/uploads/large-image-100x100.jpg file should not exist From 0062ddd7744cc44f4659ade9581f3a9a48e69562 Mon Sep 17 00:00:00 2001 From: Mihail Minkov <Mihail.Minkov.BG@gmail.com> Date: Fri, 11 Dec 2015 01:01:16 +0200 Subject: [PATCH 3913/5359] Fixed grammatical error. --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index b7c1ad0ca..969295fd6 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -224,7 +224,7 @@ function _s( $args, $assoc_args ) { die; } - $theme_description = "Custom theme: " . $data['theme_name'] . " developed by, " . $data['author']; + $theme_description = "Custom theme: " . $data['theme_name'] . ", developed by " . $data['author']; $body = array(); $body['underscoresme_name'] = $data['theme_name']; From be7fee0059ff74b2ee7520cecde65ee1366ae76c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Dec 2015 16:13:33 -0800 Subject: [PATCH 3914/5359] Add one last sanity check test --- features/core-update-db.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 140616e39..f3abbe1ea 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -29,6 +29,12 @@ Feature: Update core's database Success: WordPress database upgraded successfully from db version 29630 to 30133 """ + When I run `wp option get db_version` + Then STDOUT should be: + """ + 29630 + """ + Scenario: Update db across network Given a WP multisite install And I run `wp site create --slug=foo` From 95ab7ddd2dcc1c0e29a361f145f798d03fc61c85 Mon Sep 17 00:00:00 2001 From: Duncan Brown <duncanjbrown@gmail.com> Date: Fri, 11 Dec 2015 18:02:54 +0000 Subject: [PATCH 3915/5359] Failing test for plugin gitignore --- features/scaffold.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 377b9666b..4ab5c271f 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -112,11 +112,17 @@ Feature: WordPress code scaffolding When I run `wp scaffold plugin hello-world` Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.gitignore file should exist And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist And the {PLUGIN_DIR}/hello-world/readme.txt file should exist And the {PLUGIN_DIR}/hello-world/package.json file should exist And the {PLUGIN_DIR}/hello-world/Gruntfile.js file should exist + And the {PLUGIN_DIR}/hello-world/.gitignore file should contain: + """ + .DS_Store + node_modules/ + """ Scenario: Scaffold a plugin and activate it Given a WP install From e4b12812e0c08c6a377e953435cff7ac4b7b2da1 Mon Sep 17 00:00:00 2001 From: Duncan Brown <duncanjbrown@gmail.com> Date: Fri, 11 Dec 2015 18:07:26 +0000 Subject: [PATCH 3916/5359] Add .gitignore to plugin scaffold --- php/commands/scaffold.php | 1 + templates/plugin-gitignore.mustache | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 templates/plugin-gitignore.mustache diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 969295fd6..a9d863d4f 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -530,6 +530,7 @@ function plugin( $args, $assoc_args ) { $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), + "$plugin_dir/.gitignore" => Utils\mustache_render( 'plugin-gitignore.mustache', $data ), "$plugin_dir/.editorconfig" => file_get_contents( WP_CLI_ROOT . "/templates/.editorconfig" ), ), $force ); diff --git a/templates/plugin-gitignore.mustache b/templates/plugin-gitignore.mustache new file mode 100644 index 000000000..646ac519e --- /dev/null +++ b/templates/plugin-gitignore.mustache @@ -0,0 +1,2 @@ +.DS_Store +node_modules/ From 3266e1c9dbf811b8e2fd217e4152c29434964afe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Dec 2015 16:15:11 -0800 Subject: [PATCH 3917/5359] Support custom export filename formats with `--filename_format=` --- features/export.feature | 13 +++++++++++++ php/commands/export.php | 17 +++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/features/export.feature b/features/export.feature index cb2720ef6..3f201eea2 100644 --- a/features/export.feature +++ b/features/export.feature @@ -409,3 +409,16 @@ Feature: Export content. """ 0 """ + + Scenario: Export a site with a custom filename format + Given a WP install + + When I run `wp export --filename_format='foo-bar.{date}.{n}.xml'` + Then STDOUT should contain: + """ + foo-bar. + """ + And STDOUT should contain: + """ + 000.xml + """ diff --git a/php/commands/export.php b/php/commands/export.php index 50b077c45..6fc6dfba3 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -54,6 +54,9 @@ class Export_Command extends WP_CLI_Command { * [--post_status=<status>] * : Export only posts with this status. * + * [--filename_format=<format>] + * : Use a custom format for export filenames. Defaults to '{site}.wordpress.{date}.{n}.xml'. + * * ## EXAMPLES * * wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 @@ -74,9 +77,11 @@ public function __invoke( $_, $assoc_args ) { 'start_id' => NULL, 'skip_comments' => NULL, 'max_file_size' => 15, + 'filename_format' => '{site}.wordpress.{date}.{n}.xml', ); - $this->validate_args( wp_parse_args( $assoc_args, $defaults ) ); + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + $this->validate_args( $assoc_args ); if ( !function_exists( 'wp_export' ) ) { self::load_export_api(); @@ -95,7 +100,7 @@ public function __invoke( $_, $assoc_args ) { 'writer_args' => array( 'max_file_size' => $this->max_file_size * MB_IN_BYTES, 'destination_directory' => $this->wxr_path, - 'filename_template' => self::get_filename_template() + 'filename_template' => self::get_filename_template( $assoc_args['filename_format'] ), ) ) ); } catch ( Exception $e ) { @@ -105,12 +110,12 @@ public function __invoke( $_, $assoc_args ) { WP_CLI::success( 'All done with export.' ); } - private static function get_filename_template() { + private static function get_filename_template( $filename_format ) { $sitename = sanitize_key( get_bloginfo( 'name' ) ); - if ( ! empty( $sitename ) ) { - $sitename .= '.'; + if ( empty( $sitename ) ) { + $sitename = 'site'; } - return $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.%03d.xml'; + return str_replace( array( '{site}', '{date}', '{n}' ), array( $sitename, date( 'Y-m-d' ), '%03d' ), $filename_format ); } private static function load_export_api() { From 89aae167023651ea8e2a007ac885997fec090332 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Dec 2015 16:37:00 -0800 Subject: [PATCH 3918/5359] Consistently use periods in global param docs --- php/config-spec.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 4e6622b0e..3fda4edff 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -4,7 +4,7 @@ 'path' => array( 'runtime' => '=<path>', 'file' => '<path>', - 'desc' => 'Path to the WordPress files', + 'desc' => 'Path to the WordPress files.', ), 'url' => array( @@ -25,27 +25,27 @@ 'user' => array( 'runtime' => '=<id|login|email>', 'file' => '<id|login|email>', - 'desc' => 'Set the WordPress user', + 'desc' => 'Set the WordPress user.', ), 'skip-plugins' => array( 'runtime' => '[=<plugin>]', 'file' => '<list>', - 'desc' => 'Skip loading all or some plugins', + 'desc' => 'Skip loading all or some plugins.', 'default' => '', ), 'skip-themes' => array( 'runtime' => '[=<theme>]', 'file' => '<list>', - 'desc' => 'Skip loading all or some themes', + 'desc' => 'Skip loading all or some themes.', 'default' => '', ), 'require' => array( 'runtime' => '=<path>', 'file' => '<path>', - 'desc' => 'Load PHP file before running the command (may be used more than once)', + 'desc' => 'Load PHP file before running the command (may be used more than once).', 'multiple' => true, 'default' => array(), ), @@ -53,40 +53,40 @@ 'disabled_commands' => array( 'file' => '<list>', 'default' => array(), - 'desc' => '(Sub)commands to disable', + 'desc' => '(Sub)commands to disable.', ), 'color' => array( 'runtime' => true, 'file' => '<bool>', 'default' => 'auto', - 'desc' => 'Whether to colorize the output', + 'desc' => 'Whether to colorize the output.', ), 'debug' => array( 'runtime' => '', 'file' => '<bool>', 'default' => false, - 'desc' => 'Show all PHP errors; add verbosity to WP-CLI bootstrap', + 'desc' => 'Show all PHP errors; add verbosity to WP-CLI bootstrap.', ), 'prompt' => array( 'runtime' => '', 'file' => false, 'default' => false, - 'desc' => 'Prompt the user to enter values for all command arguments', + 'desc' => 'Prompt the user to enter values for all command arguments.', ), 'quiet' => array( 'runtime' => '', 'file' => '<bool>', 'default' => false, - 'desc' => 'Suppress informational messages', + 'desc' => 'Suppress informational messages.', ), 'apache_modules' => array( 'file' => '<list>', - 'desc' => 'List of Apache Modules that are to be reported as loaded', + 'desc' => 'List of Apache Modules that are to be reported as loaded.', 'multiple' => true, 'default' => array(), ), From 24e9917452c0a591fe9e6405683459c08e497f9b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Dec 2015 16:53:15 -0800 Subject: [PATCH 3919/5359] Split out tests for comment generate and comment recount --- features/comment-generate.feature | 11 +++++++++++ features/comment-recount.feature | 25 +++++++++++++++++++++++++ features/comment.feature | 30 ------------------------------ 3 files changed, 36 insertions(+), 30 deletions(-) create mode 100644 features/comment-generate.feature create mode 100644 features/comment-recount.feature diff --git a/features/comment-generate.feature b/features/comment-generate.feature new file mode 100644 index 000000000..609fc257d --- /dev/null +++ b/features/comment-generate.feature @@ -0,0 +1,11 @@ +Feature: Generate comments + + Scenario: Generate a specific number of comments + Given a WP install + + When I run `wp comment generate --count=20` + And I run `wp comment list --format=count` + Then STDOUT should be: + """ + 21 + """ diff --git a/features/comment-recount.feature b/features/comment-recount.feature new file mode 100644 index 000000000..5de768a0f --- /dev/null +++ b/features/comment-recount.feature @@ -0,0 +1,25 @@ +Feature: Recount comments on a post + + Scenario: Recount comments on a post + Given a WP install + + When I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` + And I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` + And I run `wp post get 1 --field=comment_count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) );'` + And I run `wp post get 1 --field=comment_count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp comment recount 1` + Then STDOUT should be: + """ + Updated post 1 comment count to 3 + """ diff --git a/features/comment.feature b/features/comment.feature index 8e368e244..f636f6087 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -129,33 +129,3 @@ Feature: Manage WordPress comments """ 0 """ - - Scenario: Generate comments - When I run `wp comment generate --count=20` - And I run `wp comment list --format=count` - Then STDOUT should be: - """ - 21 - """ - - Scenario: Recounting comments - When I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` - And I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` - And I run `wp post get 1 --field=comment_count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) );'` - And I run `wp post get 1 --field=comment_count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment recount 1` - Then STDOUT should be: - """ - Updated post 1 comment count to 3 - """ From c1edf396ceef8f68a89abea17c2cd4f821234356 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 14 Dec 2015 06:42:36 -0800 Subject: [PATCH 3920/5359] Permit failures on trunk Trunk has a fatal right now --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 90ef90221..8f7e5b553 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,7 @@ matrix: env: WP_VERSION=trunk allow_failures: - php: 7.0 + - env: WP_VERSION=trunk before_script: ./ci/prepare.sh From 138ab6ec00209c2b0f637f36d21ace522dbbe362 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 14 Dec 2015 09:56:55 -0800 Subject: [PATCH 3921/5359] Don't use table iterator when running search / replace with PHP On large datasets, running `LIKE` twice per 1000 rows is far less efficient than running `LIKE` once to get keys for all rows to operate on, and `SELECT` to get the corresponding values for each row. On small datasets, this change will have a negligible impact. For a post meta table of ~3.5 million rows with 75610 affected records, this change improves execution time from 734.926s to 225.509s --- php/commands/search-replace.php | 40 ++++++++++++++------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d2f705e6a..4ef2f3b26 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -263,42 +263,36 @@ private function sql_handle_col( $col, $table, $old, $new ) { private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { global $wpdb; - // We don't want to have to generate thousands of rows when running the test suite - $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; - - $fields = $primary_keys; - $fields[] = $col; - - $args = array( - 'table' => $table, - 'fields' => $fields, - 'where' => $this->regex ? '' : "`$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ), - 'chunk_size' => $chunk_size - ); - - $it = new \WP_CLI\Iterators\Table( $args ); - $count = 0; - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex ); - foreach ( $it as $row ) { - if ( '' === $row->$col ) + $where = $this->regex ? '' : " WHERE `$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ); + $primary_keys_sql = esc_sql( implode( ',', $primary_keys ) ); + $col_sql = esc_sql( $col ); + $table_sql = esc_sql( $table ); + $rows = $wpdb->get_results( "SELECT {$primary_keys_sql} FROM {$table_sql}{$where}" ); + foreach ( $rows as $keys ) { + $where_sql = ''; + foreach( (array) $keys as $k => $v ) { + $where_sql .= "{$k}={$v}"; + } + $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM {$table_sql} WHERE {$where_sql}" ); + if ( '' === $col_value ) continue; - $value = $replacer->run( $row->$col ); + $value = $replacer->run( $col_value ); - if ( $value === $row->$col ) { + if ( $value === $col_value ) { continue; } if ( $this->dry_run ) { - if ( $value != $row->$col ) + if ( $value != $col_value ) $count++; } else { $where = array(); - foreach ( $primary_keys as $primary_key ) { - $where[ $primary_key ] = $row->$primary_key; + foreach( (array) $keys as $k => $v ) { + $where[ $k ] = $v; } $count += $wpdb->update( $table, array( $col => $value ), $where ); From e3c71cc72218ecf6abaf900ed892e8be3e1af045 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 14 Dec 2015 10:11:56 -0800 Subject: [PATCH 3922/5359] search-replace: Drop unneeded `REGEXP` when in regex mode We'll be using PHP mode in this context anyway --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index d2f705e6a..dfa03e264 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -150,7 +150,7 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); } - if ( ! $php_only ) { + if ( ! $php_only && ! $this->regex ) { $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); } From e23ad5950dadb99b5b5ddc7cef7e5f6567953458 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 21 Dec 2015 07:36:44 -0800 Subject: [PATCH 3923/5359] Clarify behavior of `wp plugin delete` It's different than deactivating + uninstalling. --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index d266aae99..37181d3c0 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -556,7 +556,7 @@ function is_installed( $args, $assoc_args = array() ) { } /** - * Delete plugin files. + * Delete plugin files without deactivating or uninstalling. * * ## OPTIONS * From b129b84824ed8e12c7b79b65e74d6a77a1ce9bc4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 21 Dec 2015 08:13:29 -0800 Subject: [PATCH 3924/5359] Magically globalize any new variables defined in wp-config.php They're expected to be global, so we should explicitly make it so. --- features/framework.feature | 24 ++++++++++++++++++++++++ php/WP_CLI/Runner.php | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/features/framework.feature b/features/framework.feature index ea69fcc5f..0772cfb21 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -83,3 +83,27 @@ Feature: Load WP-CLI """ Error: This does not seem to be a WordPress install. """ + + Scenario: Globalize global variables in wp-config.php + Given an empty directory + And WP files + And a wp-config-extra.php file: + """ + $redis_server = 'foo'; + """ + + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` + Then the wp-config.php file should contain: + """ + $redis_server = 'foo'; + """ + + When I run `wp db create` + And I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` + Then STDOUT should not be empty + + When I run `wp eval 'echo $GLOBALS["redis_server"];'` + Then STDOUT should be: + """ + foo + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 444ebc2c0..9da535565 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -728,7 +728,14 @@ public function load_wordpress() { WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path ); // Load wp-config.php code, in the global scope + $wp_cli_original_defined_vars = get_defined_vars(); eval( $this->get_wp_config_code() ); + foreach( get_defined_vars() as $key => $var ) { + if ( array_key_exists( $key, $wp_cli_original_defined_vars ) || 'wp_cli_original_defined_vars' === $key ) { + continue; + } + $GLOBALS[ $key ] = $var; + } $this->maybe_update_url_from_domain_constant(); From e86e4a11465bf7b04d43c7f27876b245a12b8b03 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 21 Dec 2015 08:59:39 -0800 Subject: [PATCH 3925/5359] Revert "Permit failures on trunk" This reverts commit c1edf396ceef8f68a89abea17c2cd4f821234356. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8f7e5b553..90ef90221 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,6 @@ matrix: env: WP_VERSION=trunk allow_failures: - php: 7.0 - - env: WP_VERSION=trunk before_script: ./ci/prepare.sh From cdd1c2f6585a8ca9b2ab926ffe99b1d8eba8fed5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 06:52:54 -0800 Subject: [PATCH 3926/5359] Failing test case for #2308 --- features/post-meta.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/post-meta.feature b/features/post-meta.feature index 307edf060..a7eacd135 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -95,3 +95,17 @@ Feature: Manage post custom fields """ 0 """ + + Scenario: List post meta with a null value + Given a WP install + And a setup.php file: + """ + <?php + update_post_meta( 1, 'foo', NULL ); + """ + And I run `wp eval-file setup.php` + + When I run `wp post meta list 1` + Then STDOUT should be a table containing rows: + | post_id | meta_key | meta_value | + | 1 | foo | | From d9f8412fb131952ee0cc9fb53f59fca28a6a6d24 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 06:53:53 -0800 Subject: [PATCH 3927/5359] Properly check for null values on objects --- php/WP_CLI/Formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 5da9926b0..56616835e 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -188,7 +188,7 @@ private function show_single_field( $items, $field ) { */ private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( ( is_object( $item ) && isset( $item->$maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { + if ( ( is_object( $item ) && property_exists( $item, $maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { $key = $maybe_key; break; } From b32fe69166cc4b7202c40d47ef668ab529ec7ba9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 07:14:49 -0800 Subject: [PATCH 3928/5359] Run multiple cron events, or use `--all` to run all of them Note: `wp cron event run` ignores the scheduled time for the event. If you need to run a specific event on a specific schedule, you'll need to replicate said schedule with system cron. --- features/cron.feature | 43 ++++++++++++++++++++++++++++++++++++++++++- php/commands/cron.php | 36 ++++++++++++++++++++++++------------ 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 73b46d393..10dcf99dc 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -74,7 +74,9 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event run wp_cli_test_event_5` Then STDOUT should be: """ - Success: Executed 2 instances of the cron event 'wp_cli_test_event_5' + Executed the cron event 'wp_cli_test_event_5'. + Executed the cron event 'wp_cli_test_event_5'. + Success: Executed a total of 2 cron event(s). """ When I run `wp cron event list` @@ -174,3 +176,42 @@ Feature: Manage WP-Cron events and schedules """ Error: """ + + Scenario: Run multiple cron events + When I try `wp cron event run` + Then STDERR should be: + """ + Error: Please specify one or more cron events, or use --all. + """ + + When I run `wp cron event run wp_version_check wp_update_plugins` + Then STDOUT should contain: + """ + Executed the cron event 'wp_version_check'. + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_update_plugins'. + """ + And STDOUT should contain: + """ + Success: Executed a total of 2 cron event(s). + """ + + When I run `wp cron event run --all` + Then STDOUT should contain: + """ + Executed the cron event 'wp_version_check'. + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_update_plugins'. + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_update_themes'. + """ + And STDOUT should contain: + """ + Success: Executed a total of + """ diff --git a/php/commands/cron.php b/php/commands/cron.php index 9dacd2656..ec04b6b78 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -138,37 +138,49 @@ public function schedule( $args, $assoc_args ) { * * ## OPTIONS * - * <hook> - * : The hook name + * [<hook>...] + * : One or more hooks to run. + * + * [--all] + * : Run all hooks. */ public function run( $args, $assoc_args ) { - $hook = $args[0]; + if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + WP_CLI::error( 'Please specify one or more cron events, or use --all.' ); + } + $events = self::get_cron_events(); if ( is_wp_error( $events ) ) { WP_CLI::error( $events ); } + + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + $hooks = wp_list_pluck( $events, 'hook' ); + foreach( $args as $hook ) { + if ( ! in_array( $hook, $hooks ) ) { + WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); + } + } + } + $executed = 0; foreach ( $events as $event ) { - if ( $event->hook == $hook ) { + if ( in_array( $event->hook, $args ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $result = self::run_event( $event ); if ( $result ) { $executed++; + WP_CLI::log( sprintf( "Executed the cron event '%s'.", $event->hook ) ); } else { - WP_CLI::warning( sprintf( "Failed to the execute the cron event '%s'", $hook ) ); + WP_CLI::warning( sprintf( "Failed to the execute the cron event '%s'.", $event->hook ) ); } } } - if ( $executed ) { - $message = ( 1 == $executed ) ? "Executed the cron event '%2\$s'" : "Executed %1\$d instances of the cron event '%2\$s'"; - WP_CLI::success( sprintf( $message, $executed, $hook ) ); - } else { - WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); - } - + $message = 'Executed a total of %d cron event(s).'; + WP_CLI::success( sprintf( $message, $executed ) ); } /** From be3694a20a9eaa50ba13509365232ae2986afe4d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 07:34:14 -0800 Subject: [PATCH 3929/5359] Failing test case for #1722 --- features/media-import.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/media-import.feature b/features/media-import.feature index adc20bcaf..4f971b0d6 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -17,6 +17,13 @@ Feature: Manage WordPress attachments Unable to import file gobbledygook.png. Reason: File doesn't exist. """ + Scenario: Fail to import missing image on Windows + When I try `wp media import c:/path/gobbledygook.png` + Then STDERR should contain: + """ + Unable to import file c:/path/gobbledygook.png. Reason: File doesn't exist. + """ + Scenario: Import a file as attachment from a local image Given download: | path | url | From 4d56828a1eec620af0b5e2dc143ae3555df29a72 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 07:41:13 -0800 Subject: [PATCH 3930/5359] Use host instead of scheme to determine whether a file is remote or local Local files can have schemes on Windows, but local files never have hosts --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 3bb2becee..877fed9a6 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -141,7 +141,7 @@ function import( $args, $assoc_args = array() ) { } foreach ( $args as $file ) { - $is_file_remote = parse_url( $file, PHP_URL_SCHEME ); + $is_file_remote = parse_url( $file, PHP_URL_HOST ); $orig_filename = $file; if ( empty( $is_file_remote ) ) { From 7f695c548b1b90c33a47e3a76f293cbdde3e52f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 08:08:31 -0800 Subject: [PATCH 3931/5359] Use readline for `--prompt`, which properly supports arrow keys --- php/WP_CLI/Dispatcher/Subcommand.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index dd601c34e..19ecbc3ab 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -101,14 +101,13 @@ function get_usage( $prefix ) { */ private function prompt( $question, $default ) { - try { - $response = \cli\prompt( $question, $default ); - } catch( \Exception $e ) { - \WP_CLI::line(); - return false; + $question .= ': '; + if ( function_exists( 'readline' ) ) { + return readline( $question ); + } else { + echo $question; + return stream_get_line( STDIN, 1024, PHP_EOL ); } - - return $response; } /** From 3c9dff91022f43ad7d87886e180a43c53f4b436d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Dec 2015 08:12:56 -0800 Subject: [PATCH 3932/5359] Use `property_exists()` *and* `isset()` because WP has magic getters --- php/WP_CLI/Formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 56616835e..31c4a169e 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -188,7 +188,7 @@ private function show_single_field( $items, $field ) { */ private function find_item_key( $item, $field ) { foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( ( is_object( $item ) && property_exists( $item, $maybe_key ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { + if ( ( is_object( $item ) && ( property_exists( $item, $maybe_key ) || isset( $item->$maybe_key ) ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { $key = $maybe_key; break; } From aa19a9d36a6d5c07cdc9f316569ab64cb48587c2 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett <fjarrett@godaddy.com> Date: Wed, 23 Dec 2015 23:57:49 -0600 Subject: [PATCH 3933/5359] Fix widget list command example --- php/commands/widget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 81064269b..3976272c9 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -52,7 +52,7 @@ class Widget_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp sidebar widget list <sidebar-id> --fields=name --format=csv + * wp widget list sidebar-1 --fields=name --format=csv * * @subcommand list */ From c76fc69bd75a8a3cf079f3787cc469f77c54f8a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Dec 2015 07:48:24 -0800 Subject: [PATCH 3934/5359] Remove unused `php_version_tags()` function --- ci/behat-tags.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 18943e380..cca8ebf41 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -1,9 +1,5 @@ <?php -function php_version_tags() { - exec( 'grep "@require-php-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); -} - function version_tags( $prefix, $current ) { if ( ! $current ) return; From f1d46049eb1a468491cc041d9823a09cb9ff51a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Dec 2015 08:02:39 -0800 Subject: [PATCH 3935/5359] Officially support PHP 7 Skip tests which download versions of WordPress earlier than 4.4, as they throw error notices in PHP 7. --- .travis.yml | 4 +--- ci/behat-tags.php | 11 ++++++----- features/core-check-update.feature | 1 + features/core-update.feature | 3 +++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 90ef90221..5fb2dfcfd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,9 +41,7 @@ matrix: - php: 5.6 env: WP_VERSION=trunk - php: 7.0 - env: WP_VERSION=trunk - allow_failures: - - php: 7.0 + env: WP_VERSION=latest before_script: ./ci/prepare.sh diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 18943e380..ee10b4006 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -4,7 +4,7 @@ function php_version_tags() { exec( 'grep "@require-php-[0-9\.]*" -h -o features/*.feature | uniq', $existing_tags ); } -function version_tags( $prefix, $current ) { +function version_tags( $prefix, $current, $operator = '<' ) { if ( ! $current ) return; @@ -13,8 +13,8 @@ function version_tags( $prefix, $current ) { $skip_tags = array(); foreach ( $existing_tags as $tag ) { - $required = str_replace( "@{$prefix}-", '', $tag ); - if ( version_compare( $current, $required, '<' ) ) { + $compare = str_replace( "@{$prefix}-", '', $tag ); + if ( version_compare( $current, $compare, $operator ) ) { $skip_tags[] = $tag; } } @@ -23,8 +23,9 @@ function version_tags( $prefix, $current ) { } $skip_tags = array_merge( - version_tags( 'require-wp', getenv( 'WP_VERSION' ) ), - version_tags( 'require-php', PHP_VERSION ) + version_tags( 'require-wp', getenv( 'WP_VERSION' ), '<' ), + version_tags( 'require-php', PHP_VERSION, '<' ), + version_tags( 'less-than-php', PHP_VERSION, '>' ) ); # Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 4d6acc236..f35d28a1a 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -1,5 +1,6 @@ Feature: Check for more recent versions + @less-than-php-7 Scenario: Check for update via Version Check API Given a WP install diff --git a/features/core-update.feature b/features/core-update.feature index 0604fdb6e..ee2065a3d 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -1,5 +1,6 @@ Feature: Update WordPress core + @less-than-php-7 Scenario: Update from a ZIP file Given a WP install @@ -27,6 +28,7 @@ Feature: Update WordPress core 3.9 """ + @less-than-php-7 Scenario: Update to the latest minor release Given a WP install @@ -45,6 +47,7 @@ Feature: Update WordPress core Success: WordPress is at the latest minor release. """ + @less-than-php-7 Scenario: Core update from cache Given a WP install And an empty cache From 9cd571e8dc63161e39137ef414ddc8bd027d517f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Dec 2015 09:08:04 -0800 Subject: [PATCH 3936/5359] Explicitly set menu position for term WordPress doesn't do this inherently, so we end up with two posts of the same menu order. --- features/menu.feature | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index f2b554d6b..194829d17 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -77,7 +77,10 @@ Feature: Manage WordPress menus Then save STDOUT as {POST_ITEM_ID} When I run `wp menu item update {POST_ITEM_ID} --description="Washington Apples"` - Then STDERR should be empty + Then STDOUT should be: + """ + Success: Menu item updated. + """ When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` Then save STDOUT as {TERM_ITEM_ID} @@ -86,7 +89,16 @@ Feature: Manage WordPress menus Then save STDOUT as {CUSTOM_ITEM_ID} When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` - Then STDERR should be empty + Then STDOUT should be: + """ + Success: Menu item updated. + """ + + When I run `wp menu item update {TERM_ITEM_ID} --position=3` + Then STDOUT should be: + """ + Success: Menu item updated. + """ When I run `wp menu item list sidebar-menu --fields=type,title,description,position,link,menu_item_parent` Then STDOUT should be a table containing rows: From a13e5862cf9e44c1cfbb8e93e2eec689b8530e22 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Dec 2015 09:09:45 -0800 Subject: [PATCH 3937/5359] Use "should contain" instead of "should be" PHP 7.0.0 is producing unexpected output which is already fixed in 7.0.1. While it would be nice to be explicit, it's not wholly necessary. --- features/eval.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/eval.feature b/features/eval.feature index b78a5ad6c..c8308b67b 100644 --- a/features/eval.feature +++ b/features/eval.feature @@ -4,7 +4,7 @@ Feature: Evaluating PHP code and files. Given a WP install When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));'` - Then STDOUT should be: + Then STDOUT should contain: """ bool(true) """ @@ -16,7 +16,7 @@ Feature: Evaluating PHP code and files. """ When I run `wp eval-file script.php foo bar` - Then STDOUT should be: + Then STDOUT should contain: """ foo bar """ @@ -31,7 +31,7 @@ Feature: Evaluating PHP code and files. """ When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));' --skip-wordpress` - Then STDOUT should be: + Then STDOUT should contain: """ bool(false) """ @@ -51,7 +51,7 @@ Feature: Evaluating PHP code and files. """ When I run `wp eval-file script.php --skip-wordpress` - Then STDOUT should be: + Then STDOUT should contain: """ bool(false) """ From be9b601ff1bcb20b19562a08d432ce47870c25fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Dec 2015 16:09:25 -0800 Subject: [PATCH 3938/5359] Less precise, because PHP 7 produces more output See a13e5862cf9e44c1cfbb8e93e2eec689b8530e22 --- features/shell.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/shell.feature b/features/shell.feature index d415c6c4e..03dd6cb3e 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -35,7 +35,7 @@ Feature: WordPress REPL """ When I run `wp shell --basic < session` - Then STDOUT should be: + Then STDOUT should contain: """ bool(true) """ From 19099b9c51573cdf1ecc2832c94b4a08539cddc6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 07:03:07 -0800 Subject: [PATCH 3939/5359] Switch php-cli-tools to `dev-master` --- composer.json | 2 +- composer.lock | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index ba6f9d758..d4bee1081 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.10.5", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "composer/semver": "1.0.0", "ramsey/array_column": "~1.1", diff --git a/composer.lock b/composer.lock index 7c51a4dda..d56818577 100644 --- a/composer.lock +++ b/composer.lock @@ -692,16 +692,16 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "v0.10.5", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "037a010441a5c220cd1df26cdc9b20ad73408356" + "reference": "c6f72ea088518ffda711634e46589c2dbc0036cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/037a010441a5c220cd1df26cdc9b20ad73408356", - "reference": "037a010441a5c220cd1df26cdc9b20ad73408356", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/c6f72ea088518ffda711634e46589c2dbc0036cb", + "reference": "c6f72ea088518ffda711634e46589c2dbc0036cb", "shasum": "" }, "require": { @@ -1230,7 +1230,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "wp-cli/php-cli-tools": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 5f7cd8793c567c3339014ae9d7a2005746c76700 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 10:22:04 -0800 Subject: [PATCH 3940/5359] Clean up search-replace documentation * Expand description to clarify on default behavior. * Order arguments based on priority. * Format argument descriptions within 80 character width. --- php/commands/search-replace.php | 64 ++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 36cd267f8..c4088216b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -18,53 +18,67 @@ class Search_Replace_Command extends WP_CLI_Command { * * ## DESCRIPTION * - * This command will go through all rows in a selection of tables - * and will replace all appearances of the old string with the new one. The - * default tables are those registered on the $wpdb object (usually - * just WordPress core tables). + * This command will searches through all rows in a selection of tables + * and replaces appearances of the first string with the second string. * - * It will correctly handle serialized values, and will not change primary key values. + * By default, the command uses tables registered to the $wpdb object. On + * multisite, this will just be the tables for the current site unless + * --network is specified. + * + * Search/replace intelligently handles PHP serialized data, and does not + * change primary key values. * * ## OPTIONS * * <old> - * : The old string. + * : A string to search for within the database. * * <new> - * : The new string. + * : Replace instances of the first string with this new string. * * [<table>...] - * : List of database tables to restrict the replacement to. Wildcards are supported, e.g. wp_\*_options or wp_post\?. + * : List of database tables to restrict the replacement to. Wildcards are + * supported, e.g. 'wp_*_options' or 'wp_post*'. + * + * [--dry-run] + * : Run the entire search/replace operation and show report, but don't save + * changes to the database. * * [--network] - * : Search/replace through all the tables in a multisite install. + * : Search/replace through all the tables registered to $wpdb in a + * multisite install. * - * [--skip-columns=<columns>] - * : Do not perform the replacement in the comma-separated columns. + * [--all-tables-with-prefix] + * : Enable replacement on any tables that match the table prefix even if + * not registered on $wpdb. * - * [--dry-run] - * : Show report, but don't perform the changes. + * [--all-tables] + * : Enable replacement on ALL tables in the database, regardless of the + * prefix, and even if not registered on $wpdb. Overrides --network + * and --all-tables-with-prefix. * - * [--precise] - * : Force the use of PHP (instead of SQL) which is more thorough, but slower. Use if you see issues with serialized data. + * [--export[=<file>]] + * : Write transformed data as SQL file instead of saving replacements to + * the database. If <file> is not supplied, will output to STDOUT. * - * [--recurse-objects] - * : Enable recursing into objects to replace strings. Defaults to true; pass --no-recurse-objects to disable. + * [--skip-columns=<columns>] + * : Do not perform the replacement on specific columns. Use commas to + * specify multiple columns. 'guid' is skipped by default. * - * [--all-tables-with-prefix] - * : Enable replacement on any tables that match the table prefix even if not registered on wpdb + * [--precise] + * : Force the use of PHP (instead of SQL) which is more thorough, + * but slower. * - * [--all-tables] - * : Enable replacement on ALL tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --network and --all-tables-with-prefix. + * [--recurse-objects] + * : Enable recursing into objects to replace strings. Defaults to true; + * pass --no-recurse-objects to disable. * * [--verbose] * : Prints rows to the console as they're updated. * * [--regex] - * : Runs the search using a regular expression. Warning: search-replace will take about 15-20x longer when using --regex. - * - * [--export[=<file>]] - * : Write transformed data as SQL file instead of performing in-place replacements. If <file> is not supplied, will output to STDOUT. + * : Runs the search using a regular expression. Warning: search-replace + * will take about 15-20x longer when using --regex. * * ## EXAMPLES * From 03bdf9641f5eeb214f551fe9b7872d01aace413f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 10:57:55 -0800 Subject: [PATCH 3941/5359] Specify context for missing required files ``` Error: Required file 'missing-file.php' doesn't exist (from project's wp-cli.yml). ``` ``` Error: Required file 'baz.php' doesn't exist (from global config.yml). ``` --- features/config.feature | 45 +++++++++++++++++++++++++++++++---------- php/WP_CLI/Runner.php | 26 +++++++++++++++++++++++- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/features/config.feature b/features/config.feature index b56b58f24..9702f8da7 100644 --- a/features/config.feature +++ b/features/config.feature @@ -231,22 +231,45 @@ Feature: Have a config file Scenario: Missing required files should not fatal WP-CLI Given an empty directory And a wp-cli.yml file: - """ - require: - - missing-file.php - """ + """ + require: + - missing-file.php + """ - When I try `wp help` - Then STDERR should contain: - """ - Error: Required file 'missing-file.php' doesn't exist - """ + When I try `wp help` + Then STDERR should contain: + """ + Error: Required file 'missing-file.php' doesn't exist (from project's wp-cli.yml). + """ When I run `wp cli info` - Then STDOUT should not be empty + Then STDOUT should not be empty When I run `wp --info` - Then STDOUT should not be empty + Then STDOUT should not be empty + + Scenario: Missing required file in global config + Given an empty directory + And a config.yml file: + """ + require: + - /foo/baz.php + """ + + When I try `WP_CLI_CONFIG_PATH=config.yml wp help` + Then STDERR should contain: + """ + Error: Required file 'baz.php' doesn't exist (from global config.yml). + """ + + Scenario: Missing required file as runtime argument + Given an empty directory + + When I try `wp help --require=foo.php` + Then STDERR should contain: + """ + Error: Required file 'foo.php' doesn't exist (from runtime argument). + """ @require-wp-3.9 Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9da535565..d33094c7e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -25,6 +25,8 @@ class Runner { private $_project_config_path_debug; + private $_required_files; + public function __get( $key ) { if ( '_' === $key[0] ) return null; @@ -535,7 +537,11 @@ private function init_config() { $this->project_config_path = $this->get_project_config_path(); $configurator->merge_yml( $this->global_config_path ); + $config = $configurator->to_array(); + $this->_required_files['global'] = $config[0]['require']; $configurator->merge_yml( $this->project_config_path ); + $config = $configurator->to_array(); + $this->_required_files['project'] = $config[0]['require']; } // Runtime config and args @@ -550,6 +556,7 @@ private function init_config() { } list( $this->config, $this->extra_config ) = $configurator->to_array(); + $this->_required_files['runtime'] = $this->config['require']; } private function check_root() { @@ -605,7 +612,24 @@ public function start() { if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { if ( ! file_exists( $path ) ) { - WP_CLI::error( sprintf( "Required file '%s' doesn't exist", basename( $path ) ) ); + $context = ''; + foreach( array( 'global', 'project', 'runtime' ) as $scope ) { + if ( in_array( $path, $this->_required_files[ $scope ] ) ) { + switch ( $scope ) { + case 'global': + $context = ' (from global ' . basename( $this->global_config_path ) . ')'; + break; + case 'project': + $context = ' (from project\'s ' . basename( $this->project_config_path ) . ')'; + break; + case 'runtime': + $context = ' (from runtime argument)'; + break; + } + break; + } + } + WP_CLI::error( sprintf( "Required file '%s' doesn't exist%s.", basename( $path ), $context ) ); } Utils\load_file( $path ); WP_CLI::debug( 'Required file from config: ' . $path ); From 253ca656d82afb8606859ed2b91cda325940215d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 13:12:44 -0800 Subject: [PATCH 3942/5359] Assume db errors during `wp_install()` to be installation failure If database errors occur, let the user know with: ``` Error: Installation produced database errors, and may have partially or completely failed. ``` We should only show a success message when there aren't database errors. --- php/commands/core.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 2045dabff..440a8fd2c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -562,6 +562,10 @@ private function _install( $assoc_args ) { } // @codingStandardsIgnoreEnd + if ( ! empty( $GLOBALS['wpdb']->last_error ) ) { + WP_CLI::error( 'Installation produced database errors, and may have partially or completely failed.' ); + } + // Confirm the uploads directory exists $upload_dir = wp_upload_dir(); if ( ! empty( $upload_dir['error'] ) ) { From aff7ef10ad31b15f823536526f4634b1f8f2afb5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 13:53:43 -0800 Subject: [PATCH 3943/5359] Provide plugin header details at runtime for `wp scaffold plugin` This makes it possible to expose them with `--prompt` --- php/commands/scaffold.php | 20 ++++++++++++++++++-- templates/plugin.mustache | 8 ++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index a9d863d4f..4f302782e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -488,6 +488,18 @@ public function package_tests( $args, $assoc_args ) { * [--plugin_name=<title>] * : What to put in the 'Plugin Name:' header * + * [--plugin_description=<description>] + * : What to put in the 'Description:' header. + * + * [--plugin_author=<author>] + * : What to put in the 'Author:' header. + * + * [--plugin_author_uri=<url>] + * : What to put in the 'Author URI:' header. + * + * [--plugin_uri=<url>] + * : What to put in the 'Plugin URI:' header. + * * [--skip-tests] * : Don't generate files for unit testing. * @@ -505,8 +517,12 @@ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; $data = wp_parse_args( $assoc_args, array( - 'plugin_slug' => $plugin_slug, - 'plugin_name' => ucfirst( $plugin_slug ), + 'plugin_slug' => $plugin_slug, + 'plugin_name' => ucfirst( $plugin_slug ), + 'plugin_description' => 'PLUGIN DESCRIPTION HERE', + 'plugin_author' => 'YOUR NAME HERE', + 'plugin_author_uri' => 'YOUR SITE HERE', + 'plugin_uri' => 'PLUGIN SITE HERE', ) ); $data['textdomain'] = $plugin_slug; diff --git a/templates/plugin.mustache b/templates/plugin.mustache index 29aded1f7..1673f7357 100644 --- a/templates/plugin.mustache +++ b/templates/plugin.mustache @@ -2,10 +2,10 @@ /** * Plugin Name: {{plugin_name}} * Version: 0.1-alpha - * Description: PLUGIN DESCRIPTION HERE - * Author: YOUR NAME HERE - * Author URI: YOUR SITE HERE - * Plugin URI: PLUGIN SITE HERE + * Description: {{plugin_description}} + * Author: {{plugin_author}} + * Author URI: {{plugin_author_uri}} + * Plugin URI: {{plugin_uri}} * Text Domain: {{textdomain}} * Domain Path: /languages * @package {{plugin_name}} From f93a4b7d443410f9e103c279dff800296c16ce24 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 14:33:53 -0800 Subject: [PATCH 3944/5359] Use `--uploads` with `wp site empty` to delete the uploads dir too --- features/site.feature | 33 +++++++++++++++++++++++++++++++++ php/commands/site.php | 29 ++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/features/site.feature b/features/site.feature index f46478da9..db90fa7de 100644 --- a/features/site.feature +++ b/features/site.feature @@ -68,6 +68,13 @@ Feature: Manage sites in a multisite installation Scenario: Empty a site Given a WP install + And I run `wp option update uploads_use_yearmonth_folders 0` + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1` + Then the wp-content/uploads/large-image.jpg file should exist When I try `wp site url 1` Then STDERR should be: @@ -83,6 +90,7 @@ Feature: Manage sites in a multisite installation When I run `wp site empty --yes` Then STDOUT should not be empty + And the wp-content/uploads/large-image.jpg file should exist When I run `wp post list --format=ids` Then STDOUT should be empty @@ -90,6 +98,31 @@ Feature: Manage sites in a multisite installation When I run `wp term list post_tag --format=ids` Then STDOUT should be empty + Scenario: Empty a site and its uploads directory + Given a WP multisite install + And I run `wp site create --slug=foo` + And I run `wp --url=example.com/foo option update uploads_use_yearmonth_folders 0` + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp --url=example.com/foo media import {CACHE_DIR}/large-image.jpg --post_id=1` + Then the wp-content/uploads/sites/2/large-image.jpg file should exist + + When I run `wp site empty --uploads --yes` + Then STDOUT should not be empty + And the wp-content/uploads/sites/2/large-image.jpg file should exist + + When I run `wp post list --format=ids` + Then STDOUT should be empty + + When I run `wp --url=example.com/foo site empty --uploads --yes` + Then STDOUT should not be empty + And the wp-content/uploads/sites/2/large-image.jpg file should not exist + + When I run `wp --url=example.com/foo post list --format=ids` + Then STDOUT should be empty + Scenario: Get site info Given a WP multisite install diff --git a/php/commands/site.php b/php/commands/site.php index d21d1c361..923abc580 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -121,6 +121,9 @@ private function _insert_default_terms() { * * ## OPTIONS * + * [--uploads] + * : Also delete *all* files in the site's in the uploads directory. + * * [--yes] * : Proceed to empty the site without a confirmation prompt. * @@ -128,13 +131,37 @@ private function _insert_default_terms() { */ public function _empty( $args, $assoc_args ) { - WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . ' of all posts, comments, and terms?', $assoc_args ); + $upload_message = ''; + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uploads' ) ) { + $upload_message = ', and delete its uploads directory'; + } + + WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . ' of all posts, comments, and terms' . $upload_message . '?', $assoc_args ); $this->_empty_posts(); $this->_empty_comments(); $this->_empty_taxonomies(); $this->_insert_default_terms(); + if ( ! empty( $upload_message ) ) { + $upload_dir = wp_upload_dir(); + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $upload_dir['basedir'], RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ( $files as $fileinfo ) { + $realpath = $fileinfo->getRealPath(); + // Don't clobber subsites when operating on the main site + if ( is_main_site() && false !== stripos( $realpath, '/sites/' ) ) { + continue; + } + $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; + $todo( $realpath ); + } + rmdir( $upload_dir['basedir'] ); + } + WP_CLI::success( 'The site at ' . site_url() . ' was emptied.' ); } From c82dfeae61ace3f2306cfa705486f274bd160d92 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 14:35:36 -0800 Subject: [PATCH 3945/5359] Move `site empty` tests into their own file --- features/site-empty.feature | 58 +++++++++++++++++++++++++++++++++++++ features/site.feature | 57 ------------------------------------ 2 files changed, 58 insertions(+), 57 deletions(-) create mode 100644 features/site-empty.feature diff --git a/features/site-empty.feature b/features/site-empty.feature new file mode 100644 index 000000000..873dfdb22 --- /dev/null +++ b/features/site-empty.feature @@ -0,0 +1,58 @@ +Feature: Empty a WordPress site of its data + + Scenario: Empty a site + Given a WP install + And I run `wp option update uploads_use_yearmonth_folders 0` + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1` + Then the wp-content/uploads/large-image.jpg file should exist + + When I try `wp site url 1` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ + + When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` + Then STDOUT should not be empty + + When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term'` + Then STDOUT should not be empty + + When I run `wp site empty --yes` + Then STDOUT should not be empty + And the wp-content/uploads/large-image.jpg file should exist + + When I run `wp post list --format=ids` + Then STDOUT should be empty + + When I run `wp term list post_tag --format=ids` + Then STDOUT should be empty + + Scenario: Empty a site and its uploads directory + Given a WP multisite install + And I run `wp site create --slug=foo` + And I run `wp --url=example.com/foo option update uploads_use_yearmonth_folders 0` + And download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp --url=example.com/foo media import {CACHE_DIR}/large-image.jpg --post_id=1` + Then the wp-content/uploads/sites/2/large-image.jpg file should exist + + When I run `wp site empty --uploads --yes` + Then STDOUT should not be empty + And the wp-content/uploads/sites/2/large-image.jpg file should exist + + When I run `wp post list --format=ids` + Then STDOUT should be empty + + When I run `wp --url=example.com/foo site empty --uploads --yes` + Then STDOUT should not be empty + And the wp-content/uploads/sites/2/large-image.jpg file should not exist + + When I run `wp --url=example.com/foo post list --format=ids` + Then STDOUT should be empty diff --git a/features/site.feature b/features/site.feature index db90fa7de..9f80f1cb6 100644 --- a/features/site.feature +++ b/features/site.feature @@ -66,63 +66,6 @@ Feature: Manage sites in a multisite installation When I try the previous command again Then the return code should be 1 - Scenario: Empty a site - Given a WP install - And I run `wp option update uploads_use_yearmonth_folders 0` - And download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1` - Then the wp-content/uploads/large-image.jpg file should exist - - When I try `wp site url 1` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` - Then STDOUT should not be empty - - When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term'` - Then STDOUT should not be empty - - When I run `wp site empty --yes` - Then STDOUT should not be empty - And the wp-content/uploads/large-image.jpg file should exist - - When I run `wp post list --format=ids` - Then STDOUT should be empty - - When I run `wp term list post_tag --format=ids` - Then STDOUT should be empty - - Scenario: Empty a site and its uploads directory - Given a WP multisite install - And I run `wp site create --slug=foo` - And I run `wp --url=example.com/foo option update uploads_use_yearmonth_folders 0` - And download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp --url=example.com/foo media import {CACHE_DIR}/large-image.jpg --post_id=1` - Then the wp-content/uploads/sites/2/large-image.jpg file should exist - - When I run `wp site empty --uploads --yes` - Then STDOUT should not be empty - And the wp-content/uploads/sites/2/large-image.jpg file should exist - - When I run `wp post list --format=ids` - Then STDOUT should be empty - - When I run `wp --url=example.com/foo site empty --uploads --yes` - Then STDOUT should not be empty - And the wp-content/uploads/sites/2/large-image.jpg file should not exist - - When I run `wp --url=example.com/foo post list --format=ids` - Then STDOUT should be empty - Scenario: Get site info Given a WP multisite install From d513302d882a91b23107130b6bbd7f15b68f5813 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 15:33:22 -0800 Subject: [PATCH 3946/5359] Failing test case for `wp core update --minor` It updates to the latest major release, which it shouldn't --- features/core-update.feature | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/features/core-update.feature b/features/core-update.feature index ee2065a3d..058e880d0 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -32,13 +32,13 @@ Feature: Update WordPress core Scenario: Update to the latest minor release Given a WP install - When I run `wp core download --version=3.8 --force` + When I run `wp core download --version=3.7.9 --force` Then STDOUT should not be empty When I run `wp core update --minor` Then STDOUT should contain: """ - Downloading update + Updating to version 3.7.11 """ When I run `wp core update --minor` @@ -47,6 +47,12 @@ Feature: Update WordPress core Success: WordPress is at the latest minor release. """ + When I run `wp core version` + Then STDOUT should be: + """ + 3.7.11 + """ + @less-than-php-7 Scenario: Core update from cache Given a WP install From 2d3950c4591b49d54566a78cddfb6ffecafadc77 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 15:35:05 -0800 Subject: [PATCH 3947/5359] Fix `wp core update --minor` by using the proper return value --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 440a8fd2c..c8d841246 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -882,7 +882,7 @@ function update( $args, $assoc_args ) { if ( empty( $args[0] ) && empty( $assoc_args['version'] ) && \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) ) { $updates = $this->get_updates( array( 'minor' => true ) ); if ( ! empty( $updates ) ) { - $assoc_args['version'] = $updates['version']; + $assoc_args['version'] = $updates[0]['version']; } else { WP_CLI::success( 'WordPress is at the latest minor release.' ); return; From b701632fb552c6c370366bd1a153bb29ddfcf29c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 15:41:47 -0800 Subject: [PATCH 3948/5359] Failing testcase for using `--url` with multisite in WP < 3.9 --- features/flags.feature | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index 0ecbf1bd8..b521a65f1 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -13,6 +13,16 @@ Feature: Global flags } """ + Scenario: Setting the URL on multisite + Given a WP multisite install + And I run `wp site create --slug=foo` + + When I run `wp --url=example.com/foo option get home` + Then STDOUT should be: + """ + http://example.com/foo + """ + @require-wp-3.9 Scenario: Invalid URL Given a WP multisite install From f08fbf9b173bf2f1baf94585b025789043747f04 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Dec 2015 15:50:28 -0800 Subject: [PATCH 3949/5359] Globalize `$path`, used until WP 3.9 for determining subsites in MS --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index d33094c7e..af6932e2d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -730,7 +730,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $site_id, $public, $current_site, $current_blog, $shortcode_tags; + global $site_id, $public, $current_site, $current_blog, $path, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; From 4f8eed42b20451e2980ed03e97213988daae7036 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 07:17:35 -0800 Subject: [PATCH 3950/5359] Include ci/behat-tags.php in `scaffold package-tests` --- ci/behat-tags.php | 13 +++++++++++++ features/scaffold.feature | 4 ++++ php/commands/scaffold.php | 1 + 3 files changed, 18 insertions(+) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 7595af15b..14e52e3e8 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -1,4 +1,17 @@ <?php +/** + * Generate a list of tags to skip during the test run. + * + * Require a minimum version of WordPress: + * + * @require-wp-4.0 + * Scenario: Core translation CRUD + * + * Then use in bash script: + * + * BEHAT_TAGS=$(php behat-tags.php) + * vendor/bin/behat --format progress $BEHAT_TAGS + */ function version_tags( $prefix, $current, $operator = '<' ) { if ( ! $current ) diff --git a/features/scaffold.feature b/features/scaffold.feature index 4ab5c271f..f2653bec2 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -208,6 +208,10 @@ Feature: WordPress code scaffolding Then STDOUT should not be empty And the community-command/.travis.yml file should exist And the community-command/bin/install-package-tests.sh file should exist + And the community-command/utils/behat-tags.php file should contain: + """ + require-wp + """ And the community-command/utils/get-package-require-from-composer.php file should exist And the community-command/features directory should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4f302782e..1df51eb1b 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -439,6 +439,7 @@ public function package_tests( $args, $assoc_args ) { 'features/bootstrap/support.php' => $bootstrap_dir, 'php/WP_CLI/Process.php' => $bootstrap_dir, 'php/utils.php' => $bootstrap_dir, + 'ci/behat-tags.php' => $utils_dir, 'utils/get-package-require-from-composer.php' => $utils_dir, 'features/steps/given.php' => $steps_dir, 'features/steps/when.php' => $steps_dir, From de34d7f78276c4c6808670f42752e97b447ba2bc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 07:39:21 -0800 Subject: [PATCH 3951/5359] Support for testing multisite with subdomains --- features/site.feature | 20 +++++++++++++++++++- features/steps/given.php | 7 ++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/features/site.feature b/features/site.feature index 9f80f1cb6..a6980b163 100644 --- a/features/site.feature +++ b/features/site.feature @@ -9,8 +9,26 @@ Feature: Manage sites in a multisite installation Network with id 1000 does not exist. """ + Scenario: Create a subdomain site + Given a WP multisite subdomain install + + When I run `wp site create --slug=first` + Then STDOUT should not be empty + + When I run `wp site list --fields=blog_id,url` + Then STDOUT should be a table containing rows: + | blog_id | url | + | 1 | http://example.com/ | + | 2 | http://first.example.com/ | + + When I run `wp --url=first.example.com option get home` + Then STDOUT should be: + """ + http://first.example.com + """ + Scenario: Delete a site by id - Given a WP multisite install + Given a WP multisite subdirectory install When I run `wp site create --slug=first --porcelain` Then STDOUT should be a number diff --git a/features/steps/given.php b/features/steps/given.php index 0d6509876..017d1a5d8 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -55,10 +55,11 @@ function ( $world, $subdir ) { } ); -$steps->Given( '/^a WP multisite install$/', - function ( $world ) { +$steps->Given( '/^a WP multisite (subdirectory|subdomain)?\s?install$/', + function ( $world, $type = 'subdirectory' ) { $world->install_wp(); - $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network' ) )->run_check(); + $subdomains = ! empty( $type ) && 'subdomain' === $type ? 1 : 0; + $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network', 'subdomains' => $subdomains ) )->run_check(); } ); From 485a346fd4ec4270b172f706564cd1f86c1d0e7e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 08:04:08 -0800 Subject: [PATCH 3952/5359] Make sure to include `behat-tags.php` in the Phar build --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 7e2432bee..6e7924e6a 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -97,6 +97,7 @@ function set_file_contents( $phar, $path, $content ) { } add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); +add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); add_file( $phar, WP_CLI_ROOT . '/utils/get-package-require-from-composer.php' ); add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); From 1ae891308e94b75c233f26eff6ba4c646eaac0bc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 08:34:07 -0800 Subject: [PATCH 3953/5359] Use `--skip-email` to disable email notif on `core install` --- php/commands/core.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index c8d841246..4e901c0d9 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -400,6 +400,9 @@ public function is_installed( $_, $assoc_args ) { * * --admin_email=<email> * : The email address for the admin user. + * + * [--skip-email] + * : Don't send an email notification to the new admin user. */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -468,6 +471,9 @@ public function multisite_convert( $args, $assoc_args ) { * --admin_email=<email> * : The email address for the admin user. * + * [--skip-email] + * : Don't send an email notification to the new admin user. + * * @subcommand multisite-install */ public function multisite_install( $args, $assoc_args ) { @@ -533,6 +539,12 @@ private function _install( $assoc_args ) { return false; } + if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-email' ) ) { + function wp_new_blog_notification() { + // Silence is golden + } + } + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); extract( wp_parse_args( $assoc_args, array( From 1d7adbc5f8dbf21934f6e015c488f1aa5c86ae8b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 08:58:17 -0800 Subject: [PATCH 3954/5359] Failing test case for #1950 --- features/plugin-update.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 features/plugin-update.feature diff --git a/features/plugin-update.feature b/features/plugin-update.feature new file mode 100644 index 000000000..818430cb4 --- /dev/null +++ b/features/plugin-update.feature @@ -0,0 +1,23 @@ +Feature: Update WordPress plugins + + Scenario: Updating plugin with invalid version shouldn't remove the old version + Given a WP install + + When I run `wp plugin install akismet --version=2.5.6 --force` + Then STDOUT should not be empty + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | inactive | available | 2.5.6 | + + When I try `wp plugin update akismet --version=2.9.0` + Then STDERR should be: + """ + Error: Can't find the requested plugin's version 2.9.0 in the WordPress.org plugin repository (HTTP code 404). + """ + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | inactive | available | 2.5.6 | From abd3a1dcb9d48c30fd2a88ab397a226a84773277 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 09:03:03 -0800 Subject: [PATCH 3955/5359] Updating plugin with invalid version shouldn't delete the plugin `install --force` does the trick for us, so we don't need to delete --- features/plugin-update.feature | 12 ++++++++++++ php/commands/plugin.php | 2 -- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/features/plugin-update.feature b/features/plugin-update.feature index 818430cb4..7144cccae 100644 --- a/features/plugin-update.feature +++ b/features/plugin-update.feature @@ -6,6 +6,10 @@ Feature: Update WordPress plugins When I run `wp plugin install akismet --version=2.5.6 --force` Then STDOUT should not be empty + When I run `wp plugin list --name=akismet --field=update_version` + Then STDOUT should not be empty + And save STDOUT as {UPDATE_VERSION} + When I run `wp plugin list` Then STDOUT should be a table containing rows: | name | status | update | version | @@ -21,3 +25,11 @@ Feature: Update WordPress plugins Then STDOUT should be a table containing rows: | name | status | update | version | | akismet | inactive | available | 2.5.6 | + + When I run `wp plugin update akismet` + Then STDOUT should not be empty + + When I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | + | akismet | inactive | none | {UPDATE_VERSION} | diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 37181d3c0..885f69fb9 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -351,8 +351,6 @@ protected function install_from_repo( $slug, $assoc_args ) { function update( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - $this->_delete( $plugin ); - $assoc_args['force'] = 1; $this->install( array( $plugin->name ), $assoc_args ); } From 0b53f0e46b9fbe716e21bee4b8732b5e91c6bda7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 09:13:50 -0800 Subject: [PATCH 3956/5359] Indicate error when `wp_insert_user()` returns 0 It shouldn't, but in some cases it does. Also prevents email notification from being sent when a user isn't created. --- php/commands/user.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index d3fd69bb9..130a4ff34 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -299,11 +299,10 @@ public function create( $args, $assoc_args ) { $user_id = wp_insert_user( $user ); } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - self::wp_new_user_notification( $user_id, $user->user_pass ); - } - - if ( is_wp_error( $user_id ) ) { + if ( ! $user_id || is_wp_error( $user_id ) ) { + if ( ! $user_id ) { + $user_id = 'Unknown error creating new user.'; + } WP_CLI::error( $user_id ); } else { if ( false === $user->role ) { @@ -312,6 +311,10 @@ public function create( $args, $assoc_args ) { } } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { + self::wp_new_user_notification( $user_id, $user->user_pass ); + } + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $user_id ); } else { From 6c87033f52dd97d14e995e208f66f4e2f9a52d84 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 10:00:23 -0800 Subject: [PATCH 3957/5359] Document how users can export a random subset of their content --- php/commands/export.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/export.php b/php/commands/export.php index 6fc6dfba3..8d5731df0 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -62,6 +62,9 @@ class Export_Command extends WP_CLI_Command { * wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 * * wp export --dir=/tmp/ --post__in=123,124,125 + * + * # Export a random subset of content + * wp export --post__in=$(wp post list --post_type=post --orderby=rand --posts_per_page=8 --format=ids) */ public function __invoke( $_, $assoc_args ) { $defaults = array( From e78b2471950e7dcff8eca49127bfb651af8e7ddc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 15:18:40 -0800 Subject: [PATCH 3958/5359] Ensure `wp_new_blog_notification()` isn't defined before we do so While it wouldn't realistically ever be defined in this scope, a PHP script calling `install()` twice would fatal on the second time. Better safe than sorry. --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 4e901c0d9..a754c7fdd 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -539,7 +539,8 @@ private function _install( $assoc_args ) { return false; } - if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-email' ) ) { + if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-email' ) + && ! function_exists( 'wp_new_blog_notification' ) ) { function wp_new_blog_notification() { // Silence is golden } From 7028b1c32ff9333efff93336f240f1fb746d39ec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 15:45:54 -0800 Subject: [PATCH 3959/5359] Use `mustangostang/spyc` instead of bundling our own copy --- composer.json | 2 +- composer.lock | 47 ++ php/Spyc.php | 1035 ------------------------------------------- utils/make-phar.php | 1 + 4 files changed, 49 insertions(+), 1036 deletions(-) delete mode 100644 php/Spyc.php diff --git a/composer.json b/composer.json index d4bee1081..d8d6c5246 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", + "mustangostang/spyc": "0.5.1", "composer/semver": "1.0.0", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", @@ -33,7 +34,6 @@ }, "autoload": { "psr-0": { "WP_CLI": "php" }, - "files": [ "php/Spyc.php" ], "classmap": [ "php/export" ] } } diff --git a/composer.lock b/composer.lock index d56818577..5dc2673cb 100644 --- a/composer.lock +++ b/composer.lock @@ -114,6 +114,53 @@ ], "time": "2015-08-15 19:23:13" }, + { + "name": "mustangostang/spyc", + "version": "0.5.1", + "source": { + "type": "git", + "url": "https://github.com/mustangostang/spyc.git", + "reference": "dc4785b4d7227fd9905e086d499fb8abfadf9977" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/dc4785b4d7227fd9905e086d499fb8abfadf9977", + "reference": "dc4785b4d7227fd9905e086d499fb8abfadf9977", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "autoload": { + "files": [ + "Spyc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT License" + ], + "authors": [ + { + "name": "mustangostang", + "email": "vlad.andersen@gmail.com" + } + ], + "description": "A simple YAML loader/dumper class for PHP", + "homepage": "https://github.com/mustangostang/spyc/", + "keywords": [ + "spyc", + "yaml", + "yml" + ], + "time": "2013-02-21 10:52:01" + }, { "name": "nb/oxymel", "version": "v0.1.0", diff --git a/php/Spyc.php b/php/Spyc.php deleted file mode 100644 index 7a0c28284..000000000 --- a/php/Spyc.php +++ /dev/null @@ -1,1035 +0,0 @@ -<?php -/** - * Spyc -- A Simple PHP YAML Class - * @version 0.5 - * @author Vlad Andersen <vlad.andersen@gmail.com> - * @author Chris Wanstrath <chris@ozmm.org> - * @link http://code.google.com/p/spyc/ - * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen - * @license http://www.opensource.org/licenses/mit-license.php MIT License - * @package Spyc - */ - -if (!function_exists('spyc_load')) : - /** - * Parses YAML to array. - * @param string $string YAML string. - * @return array - */ - function spyc_load ($string) { - return Spyc::YAMLLoadString($string); - } -endif; - -if (!function_exists('spyc_load_file')) : - /** - * Parses YAML to array. - * @param string $file Path to YAML file. - * @return array - */ - function spyc_load_file ($file) { - return Spyc::YAMLLoad($file); - } -endif; - -if ( ! class_exists( 'Spyc' ) ) : -/** - * The Simple PHP YAML Class. - * - * This class can be used to read a YAML file and convert its contents - * into a PHP array. It currently supports a very limited subsection of - * the YAML spec. - * - * Usage: - * <code> - * $Spyc = new Spyc; - * $array = $Spyc->load($file); - * </code> - * or: - * <code> - * $array = Spyc::YAMLLoad($file); - * </code> - * or: - * <code> - * $array = spyc_load_file($file); - * </code> - * @package Spyc - */ -class Spyc { - - // SETTINGS - - const REMPTY = "\0\0\0\0\0"; - - /** - * Setting this to true will force YAMLDump to enclose any string value in - * quotes. False by default. - * - * @var bool - */ - public $setting_dump_force_quotes = false; - - /** - * Setting this to true will forse YAMLLoad to use syck_load function when - * possible. False by default. - * @var bool - */ - public $setting_use_syck_is_possible = false; - - - - /**#@+ - * @access private - * @var mixed - */ - private $_dumpIndent; - private $_dumpWordWrap; - private $_containsGroupAnchor = false; - private $_containsGroupAlias = false; - private $path; - private $result; - private $LiteralPlaceHolder = '___YAML_Literal_Block___'; - private $SavedGroups = array(); - private $indent; - /** - * Path modifier that should be applied after adding current element. - * @var array - */ - private $delayedPath = array(); - - /**#@+ - * @access public - * @var mixed - */ - public $_nodeId; - -/** - * Load a valid YAML string to Spyc. - * @param string $input - * @return array - */ - public function load ($input) { - return $this->__loadString($input); - } - - /** - * Load a valid YAML file to Spyc. - * @param string $file - * @return array - */ - public function loadFile ($file) { - return $this->__load($file); - } - - /** - * Load YAML into a PHP array statically - * - * The load method, when supplied with a YAML stream (string or file), - * will do its best to convert YAML in a file into a PHP array. Pretty - * simple. - * Usage: - * <code> - * $array = Spyc::YAMLLoad('lucky.yaml'); - * print_r($array); - * </code> - * @access public - * @return array - * @param string $input Path of YAML file or string containing YAML - */ - public static function YAMLLoad($input) { - $Spyc = new Spyc; - return $Spyc->__load($input); - } - - /** - * Load a string of YAML into a PHP array statically - * - * The load method, when supplied with a YAML string, will do its best - * to convert YAML in a string into a PHP array. Pretty simple. - * - * Note: use this function if you don't want files from the file system - * loaded and processed as YAML. This is of interest to people concerned - * about security whose input is from a string. - * - * Usage: - * <code> - * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); - * print_r($array); - * </code> - * @access public - * @return array - * @param string $input String containing YAML - */ - public static function YAMLLoadString($input) { - $Spyc = new Spyc; - return $Spyc->__loadString($input); - } - - /** - * Dump YAML from PHP array statically - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as nothing.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - public static function YAMLDump($array,$indent = false,$wordwrap = false) { - $spyc = new Spyc; - return $spyc->dump($array,$indent,$wordwrap); - } - - - /** - * Dump PHP array to YAML - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as tasteful.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - public function dump($array,$indent = false,$wordwrap = false) { - // Dumps to some very clean YAML. We'll have to add some more features - // and options soon. And better support for folding. - - // New features and options. - if ($indent === false or !is_numeric($indent)) { - $this->_dumpIndent = 2; - } else { - $this->_dumpIndent = $indent; - } - - if ($wordwrap === false or !is_numeric($wordwrap)) { - $this->_dumpWordWrap = 40; - } else { - $this->_dumpWordWrap = $wordwrap; - } - - // New YAML document - $string = "---\n"; - - // Start at the base of the array and move through it. - if ($array) { - $array = (array)$array; - $previous_key = -1; - foreach ($array as $key => $value) { - if (!isset($first_key)) $first_key = $key; - $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); - $previous_key = $key; - } - } - return $string; - } - - /** - * Attempts to convert a key / value array item to YAML - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { - if (is_array($value)) { - if (empty ($value)) - return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); - // It has children. What to do? - // Make it the right kind of item - $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); - // Add the indent - $indent += $this->_dumpIndent; - // Yamlize the array - $string .= $this->_yamlizeArray($value,$indent); - } elseif (!is_array($value)) { - // It doesn't have children. Yip. - $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); - } - return $string; - } - - /** - * Attempts to convert an array to YAML - * @access private - * @return string - * @param $array The array you want to convert - * @param $indent The indent of the current level - */ - private function _yamlizeArray($array,$indent) { - if (is_array($array)) { - $string = ''; - $previous_key = -1; - foreach ($array as $key => $value) { - if (!isset($first_key)) $first_key = $key; - $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); - $previous_key = $key; - } - return $string; - } else { - return false; - } - } - - /** - * Returns YAML from a key and a value - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { - // do some folding here, for blocks - if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || - strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false || - strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || - substr ($value, -1, 1) == ':') - ) { - $value = $this->_doLiteralBlock($value,$indent); - } else { - $value = $this->_doFolding($value,$indent); - } - - if ($value === array()) $value = '[ ]'; - if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) { - $value = $this->_doLiteralBlock($value,$indent); - } - if (trim ($value) != $value) - $value = $this->_doLiteralBlock($value,$indent); - - if (is_bool($value)) { - $value = ($value) ? "true" : "false"; - } - - if ($value === null) $value = 'null'; - if ($value === "'" . self::REMPTY . "'") $value = null; - - $spaces = str_repeat(' ',$indent); - - //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { - if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { - // It's a sequence - $string = $spaces.'- '.$value."\n"; - } else { - // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); - // It's mapped - if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } - $string = rtrim ($spaces.$key.': '.$value)."\n"; - } - return $string; - } - - /** - * Creates a literal block for dumping - * @access private - * @return string - * @param $value - * @param $indent int The value of the indent - */ - private function _doLiteralBlock($value,$indent) { - if ($value === "\n") return '\n'; - if (strpos($value, "\n") === false && strpos($value, "'") === false) { - return sprintf ("'%s'", $value); - } - if (strpos($value, "\n") === false && strpos($value, '"') === false) { - return sprintf ('"%s"', $value); - } - $exploded = explode("\n",$value); - $newValue = '|'; - $indent += $this->_dumpIndent; - $spaces = str_repeat(' ',$indent); - foreach ($exploded as $line) { - $newValue .= "\n" . $spaces . ($line); - } - return $newValue; - } - - /** - * Folds a string of text, if necessary - * @access private - * @return string - * @param $value The string you wish to fold - */ - private function _doFolding($value,$indent) { - // Don't do anything if wordwrap is set to 0 - - if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { - $indent += $this->_dumpIndent; - $indent = str_repeat(' ',$indent); - $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); - $value = ">\n".$indent.$wrapped; - } else { - if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) - $value = '"' . $value . '"'; - } - - - return $value; - } - -// LOADING FUNCTIONS - - private function __load($input) { - $Source = $this->loadFromSource($input); - return $this->loadWithSource($Source); - } - - private function __loadString($input) { - $Source = $this->loadFromString($input); - return $this->loadWithSource($Source); - } - - private function loadWithSource($Source) { - if (empty ($Source)) return array(); - if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { - $array = syck_load (implode ('', $Source)); - return is_array($array) ? $array : array(); - } - - $this->path = array(); - $this->result = array(); - - $cnt = count($Source); - for ($i = 0; $i < $cnt; $i++) { - $line = $Source[$i]; - - $this->indent = strlen($line) - strlen(ltrim($line)); - $tempPath = $this->getParentPathByIndent($this->indent); - $line = self::stripIndent($line, $this->indent); - if (self::isComment($line)) continue; - if (self::isEmpty($line)) continue; - $this->path = $tempPath; - - $literalBlockStyle = self::startsLiteralBlock($line); - if ($literalBlockStyle) { - $line = rtrim ($line, $literalBlockStyle . " \n"); - $literalBlock = ''; - $line .= $this->LiteralPlaceHolder; - $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); - while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { - $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); - } - $i--; - } - - while (++$i < $cnt && self::greedilyNeedNextLine($line)) { - $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); - } - $i--; - - - - if (strpos ($line, '#')) { - if (strpos ($line, '"') === false && strpos ($line, "'") === false) - $line = preg_replace('/\s+#(.+)$/','',$line); - } - - $lineArray = $this->_parseLine($line); - - if ($literalBlockStyle) - $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); - - $this->addArray($lineArray, $this->indent); - - foreach ($this->delayedPath as $indent => $delayedPath) - $this->path[$indent] = $delayedPath; - - $this->delayedPath = array(); - - } - return $this->result; - } - - private function loadFromSource ($input) { - if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) - return file($input); - - return $this->loadFromString($input); - } - - private function loadFromString ($input) { - $lines = explode("\n",$input); - foreach ($lines as $k => $_) { - $lines[$k] = rtrim ($_, "\r"); - } - return $lines; - } - - /** - * Parses YAML code and returns an array for a node - * @access private - * @return array - * @param string $line A line from the YAML file - */ - private function _parseLine($line) { - if (!$line) return array(); - $line = trim($line); - if (!$line) return array(); - - $array = array(); - - $group = $this->nodeContainsGroup($line); - if ($group) { - $this->addGroup($line, $group); - $line = $this->stripGroup ($line, $group); - } - - if ($this->startsMappedSequence($line)) - return $this->returnMappedSequence($line); - - if ($this->startsMappedValue($line)) - return $this->returnMappedValue($line); - - if ($this->isArrayElement($line)) - return $this->returnArrayElement($line); - - if ($this->isPlainArray($line)) - return $this->returnPlainArray($line); - - - return $this->returnKeyValuePair($line); - - } - - /** - * Finds the type of the passed value, returns the value as the new type. - * @access private - * @param string $value - * @return mixed - */ - private function _toType($value) { - if ($value === '') return null; - $first_character = $value[0]; - $last_character = substr($value, -1, 1); - - $is_quoted = false; - do { - if (!$value) break; - if ($first_character != '"' && $first_character != "'") break; - if ($last_character != '"' && $last_character != "'") break; - $is_quoted = true; - } while (0); - - if ($is_quoted) - return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); - - if (strpos($value, ' #') !== false && !$is_quoted) - $value = preg_replace('/\s+#(.+)$/','',$value); - - if (!$is_quoted) $value = str_replace('\n', "\n", $value); - - if ($first_character == '[' && $last_character == ']') { - // Take out strings sequences and mappings - $innerValue = trim(substr ($value, 1, -1)); - if ($innerValue === '') return array(); - $explode = $this->_inlineEscape($innerValue); - // Propagate value array - $value = array(); - foreach ($explode as $v) { - $value[] = $this->_toType($v); - } - return $value; - } - - if (strpos($value,': ')!==false && $first_character != '{') { - $array = explode(': ',$value); - $key = trim($array[0]); - array_shift($array); - $value = trim(implode(': ',$array)); - $value = $this->_toType($value); - return array($key => $value); - } - - if ($first_character == '{' && $last_character == '}') { - $innerValue = trim(substr ($value, 1, -1)); - if ($innerValue === '') return array(); - // Inline Mapping - // Take out strings sequences and mappings - $explode = $this->_inlineEscape($innerValue); - // Propagate value array - $array = array(); - foreach ($explode as $v) { - $SubArr = $this->_toType($v); - if (empty($SubArr)) continue; - if (is_array ($SubArr)) { - $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; - } - $array[] = $SubArr; - } - return $array; - } - - if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { - return null; - } - - if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ - $intvalue = (int)$value; - if ($intvalue != PHP_INT_MAX) - $value = $intvalue; - return $value; - } - - if (in_array($value, - array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { - return true; - } - - if (in_array(strtolower($value), - array('false', 'off', '-', 'no', 'n'))) { - return false; - } - - if (is_numeric($value)) { - if ($value === '0') return 0; - if (rtrim ($value, 0) === $value) - $value = (float)$value; - return $value; - } - - return $value; - } - - /** - * Used in inlines to check for more inlines or quoted strings - * @access private - * @return array - */ - private function _inlineEscape($inline) { - // There's gotta be a cleaner way to do this... - // While pure sequences seem to be nesting just fine, - // pure mappings and mappings with sequences inside can't go very - // deep. This needs to be fixed. - - $seqs = array(); - $maps = array(); - $saved_strings = array(); - - // Check for strings - $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; - if (preg_match_all($regex,$inline,$strings)) { - $saved_strings = $strings[0]; - $inline = preg_replace($regex,'YAMLString',$inline); - } - unset($regex); - - $i = 0; - do { - - // Check for sequences - while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { - $seqs[] = $matchseqs[0]; - $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); - } - - // Check for mappings - while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { - $maps[] = $matchmaps[0]; - $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); - } - - if ($i++ >= 10) break; - - } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); - - $explode = explode(', ',$inline); - $stringi = 0; $i = 0; - - while (1) { - - // Re-add the sequences - if (!empty($seqs)) { - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLSeq') !== false) { - foreach ($seqs as $seqk => $seq) { - $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); - $value = $explode[$key]; - } - } - } - } - - // Re-add the mappings - if (!empty($maps)) { - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLMap') !== false) { - foreach ($maps as $mapk => $map) { - $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); - $value = $explode[$key]; - } - } - } - } - - - // Re-add the strings - if (!empty($saved_strings)) { - foreach ($explode as $key => $value) { - while (strpos($value,'YAMLString') !== false) { - $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); - unset($saved_strings[$stringi]); - ++$stringi; - $value = $explode[$key]; - } - } - } - - $finished = true; - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLSeq') !== false) { - $finished = false; break; - } - if (strpos($value,'YAMLMap') !== false) { - $finished = false; break; - } - if (strpos($value,'YAMLString') !== false) { - $finished = false; break; - } - } - if ($finished) break; - - $i++; - if ($i > 10) - break; // Prevent infinite loops. - } - - return $explode; - } - - private function literalBlockContinues ($line, $lineIndent) { - if (!trim($line)) return true; - if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; - return false; - } - - private function referenceContentsByAlias ($alias) { - do { - if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } - $groupPath = $this->SavedGroups[$alias]; - $value = $this->result; - foreach ($groupPath as $k) { - $value = $value[$k]; - } - } while (false); - return $value; - } - - private function addArrayInline ($array, $indent) { - $CommonGroupPath = $this->path; - if (empty ($array)) return false; - - foreach ($array as $k => $_) { - $this->addArray(array($k => $_), $indent); - $this->path = $CommonGroupPath; - } - return true; - } - - private function addArray ($incoming_data, $incoming_indent) { - - // print_r ($incoming_data); - - if (count ($incoming_data) > 1) - return $this->addArrayInline ($incoming_data, $incoming_indent); - - $key = key ($incoming_data); - $value = \WP_CLI\Utils\get_flag_value( $incoming_data, $key ); - if ($key === '__!YAMLZero') $key = '0'; - - if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. - if ($key || $key === '' || $key === '0') { - $this->result[$key] = $value; - } else { - $this->result[] = $value; end ($this->result); $key = key ($this->result); - } - $this->path[$incoming_indent] = $key; - return; - } - - - - $history = array(); - // Unfolding inner array tree. - $history[] = $_arr = $this->result; - foreach ($this->path as $k) { - $history[] = $_arr = $_arr[$k]; - } - - if ($this->_containsGroupAlias) { - $value = $this->referenceContentsByAlias($this->_containsGroupAlias); - $this->_containsGroupAlias = false; - } - - - // Adding string or numeric key to the innermost level or $this->arr. - if (is_string($key) && $key == '<<') { - if (!is_array ($_arr)) { $_arr = array (); } - - $_arr = array_merge ($_arr, $value); - } else if ($key || $key === '' || $key === '0') { - if (!is_array ($_arr)) - $_arr = array ($key=>$value); - else - $_arr[$key] = $value; - } else { - if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } - else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } - } - - $reverse_path = array_reverse($this->path); - $reverse_history = array_reverse ($history); - $reverse_history[0] = $_arr; - $cnt = count($reverse_history) - 1; - for ($i = 0; $i < $cnt; $i++) { - $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; - } - $this->result = $reverse_history[$cnt]; - - $this->path[$incoming_indent] = $key; - - if ($this->_containsGroupAnchor) { - $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; - if (is_array ($value)) { - $k = key ($value); - if (!is_int ($k)) { - $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; - } - } - $this->_containsGroupAnchor = false; - } - - } - - private static function startsLiteralBlock ($line) { - $lastChar = substr (trim($line), -1); - if ($lastChar != '>' && $lastChar != '|') return false; - if ($lastChar == '|') return $lastChar; - // HTML tags should not be counted as literal blocks. - if (preg_match ('#<.*?>$#', $line)) return false; - return $lastChar; - } - - private static function greedilyNeedNextLine($line) { - $line = trim ($line); - if (!strlen($line)) return false; - if (substr ($line, -1, 1) == ']') return false; - if ($line[0] == '[') return true; - if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; - return false; - } - - private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { - $line = self::stripIndent($line, $indent); - if ($literalBlockStyle !== '|') { - $line = self::stripIndent($line); - } - $line = rtrim ($line, "\r\n\t ") . "\n"; - if ($literalBlockStyle == '|') { - return $literalBlock . $line; - } - if (strlen($line) == 0) - return rtrim($literalBlock, ' ') . "\n"; - if ($line == "\n" && $literalBlockStyle == '>') { - return rtrim ($literalBlock, " \t") . "\n"; - } - if ($line != "\n") - $line = trim ($line, "\r\n ") . " "; - return $literalBlock . $line; - } - - function revertLiteralPlaceHolder ($lineArray, $literalBlock) { - foreach ($lineArray as $k => $_) { - if (is_array($_)) - $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); - else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) - $lineArray[$k] = rtrim ($literalBlock, " \r\n"); - } - return $lineArray; - } - - private static function stripIndent ($line, $indent = -1) { - if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); - return substr ($line, $indent); - } - - private function getParentPathByIndent ($indent) { - if ($indent == 0) return array(); - $linePath = $this->path; - do { - end($linePath); $lastIndentInParentPath = key($linePath); - if ($indent <= $lastIndentInParentPath) array_pop ($linePath); - } while ($indent <= $lastIndentInParentPath); - return $linePath; - } - - - private function clearBiggerPathValues ($indent) { - - - if ($indent == 0) $this->path = array(); - if (empty ($this->path)) return true; - - foreach ($this->path as $k => $_) { - if ($k > $indent) unset ($this->path[$k]); - } - - return true; - } - - - private static function isComment ($line) { - if (!$line) return false; - if ($line[0] == '#') return true; - if (trim($line, " \r\n\t") == '---') return true; - return false; - } - - private static function isEmpty ($line) { - return (trim ($line) === ''); - } - - - private function isArrayElement ($line) { - if (!$line) return false; - if ($line[0] != '-') return false; - if (strlen ($line) > 3) - if (substr($line,0,3) == '---') return false; - - return true; - } - - private function isHashElement ($line) { - return strpos($line, ':'); - } - - private function isLiteral ($line) { - if ($this->isArrayElement($line)) return false; - if ($this->isHashElement($line)) return false; - return true; - } - - - private static function unquote ($value) { - if (!$value) return $value; - if (!is_string($value)) return $value; - if ($value[0] == '\'') return trim ($value, '\''); - if ($value[0] == '"') return trim ($value, '"'); - return $value; - } - - private function startsMappedSequence ($line) { - return ($line[0] == '-' && substr ($line, -1, 1) == ':'); - } - - private function returnMappedSequence ($line) { - $array = array(); - $key = self::unquote(trim(substr($line,1,-1))); - $array[$key] = array(); - $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); - return array($array); - } - - private function returnMappedValue ($line) { - $array = array(); - $key = self::unquote (trim(substr($line,0,-1))); - $array[$key] = ''; - return $array; - } - - private function startsMappedValue ($line) { - return (substr ($line, -1, 1) == ':'); - } - - private function isPlainArray ($line) { - return ($line[0] == '[' && substr ($line, -1, 1) == ']'); - } - - private function returnPlainArray ($line) { - return $this->_toType($line); - } - - private function returnKeyValuePair ($line) { - $array = array(); - $key = ''; - if (strpos ($line, ':')) { - // It's a key/value pair most likely - // If the key is in double quotes pull it out - if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { - $value = trim(str_replace($matches[1],'',$line)); - $key = $matches[2]; - } else { - // Do some guesswork as to the key and the value - $explode = explode(':',$line); - $key = trim($explode[0]); - array_shift($explode); - $value = trim(implode(':',$explode)); - } - // Set the type of the value. Int, string, etc - $value = $this->_toType($value); - if ($key === '0') $key = '__!YAMLZero'; - $array[$key] = $value; - } else { - $array = array ($line); - } - return $array; - - } - - - private function returnArrayElement ($line) { - if (strlen($line) <= 1) return array(array()); // Weird %) - $array = array(); - $value = trim(substr($line,1)); - $value = $this->_toType($value); - $array[] = $value; - return $array; - } - - - private function nodeContainsGroup ($line) { - $symbolsForReference = 'A-z0-9_\-'; - if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) - if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; - if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; - if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; - return false; - - } - - private function addGroup ($line, $group) { - if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); - if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); - //print_r ($this->path); - } - - private function stripGroup ($line, $group) { - $line = trim(str_replace($group, '', $line)); - return $line; - } -} - -endif; diff --git a/utils/make-phar.php b/utils/make-phar.php index 6e7924e6a..95e89f38e 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -73,6 +73,7 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') ->in(WP_CLI_ROOT . '/vendor/composer/semver') + ->in(WP_CLI_ROOT . '/vendor/mustangostang') ->exclude('test') ->exclude('tests') ->exclude('Tests') From d93fb7d78837d3dca08ac8b16b3b33ca777b013c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 16:33:32 -0800 Subject: [PATCH 3960/5359] Use `--network` flag for `wp transient *` to manage site transients --- features/transient.feature | 56 ++++++++++++++++++++++++++++++++++++++ php/commands/transient.php | 28 ++++++++++++++----- 2 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 features/transient.feature diff --git a/features/transient.feature b/features/transient.feature new file mode 100644 index 000000000..fcbd9d8ea --- /dev/null +++ b/features/transient.feature @@ -0,0 +1,56 @@ +Feature: Manage WordPress transient cache + + Scenario: Transient CRUD + Given a WP install + + When I try `wp transient get foo` + Then STDERR should be: + """ + Warning: Transient with key "foo" is not set. + """ + + When I run `wp transient set foo bar` + Then STDOUT should be: + """ + Success: Transient added. + """ + + When I run `wp transient get foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp transient delete foo` + Then STDOUT should be: + """ + Success: Transient deleted. + """ + + Scenario: Network transient CRUD + Given a WP multisite install + And I run `wp site create --slug=foo` + + When I run `wp transient set foo bar --network` + Then STDOUT should be: + """ + Success: Transient added. + """ + + When I run `wp --url=example.com/foo transient get foo --network` + Then STDOUT should be: + """ + bar + """ + + When I try `wp transient get foo` + Then STDERR should be: + """ + Warning: Transient with key "foo" is not set. + """ + + When I run `wp transient delete foo --network` + Then STDOUT should be: + """ + Success: Transient deleted. + """ diff --git a/php/commands/transient.php b/php/commands/transient.php index 6331f633f..09d05eb1c 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -17,11 +17,15 @@ class Transient_Command extends WP_CLI_Command { * * [--json] * : Format output as JSON. + * + * [--network] + * : Get the value of the network transient, instead of the single site. */ public function get( $args, $assoc_args ) { list( $key ) = $args; - $value = get_transient( $key ); + $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; + $value = $func( $key ); if ( false === $value ) { WP_CLI::warning( 'Transient with key "' . $key . '" is not set.' ); @@ -42,16 +46,21 @@ public function get( $args, $assoc_args ) { * * [<expiration>] * : Time until expiration, in seconds. + * + * [--network] + * : Set the transient value on the network, instead of single site. */ - public function set( $args ) { + public function set( $args, $assoc_args ) { list( $key, $value ) = $args; $expiration = \WP_CLI\Utils\get_flag_value( $args, 2, 0 ); - if ( set_transient( $key, $value, $expiration ) ) + $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'set_site_transient' : 'set_transient'; + if ( $func( $key, $value, $expiration ) ) { WP_CLI::success( 'Transient added.' ); - else + } else { WP_CLI::error( 'Transient could not be set.' ); + } } /** @@ -59,14 +68,19 @@ public function set( $args ) { * * <key> * : Key for the transient. + * + * [--network] + * : Delete the value of a network transient, instead of that on a single site. */ - public function delete( $args ) { + public function delete( $args, $assoc_args ) { list( $key ) = $args; - if ( delete_transient( $key ) ) { + $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'delete_site_transient' : 'delete_transient'; + if ( $func( $key ) ) { WP_CLI::success( 'Transient deleted.' ); } else { - if ( get_transient( $key ) ) + $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; + if ( $func( $key ) ) WP_CLI::error( 'Transient was not deleted even though the transient appears to exist.' ); else WP_CLI::warning( 'Transient was not deleted; however, the transient does not appear to exist.' ); From 5c78610488c73af3451efacf283d15597b826522 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 16:43:20 -0800 Subject: [PATCH 3961/5359] Move `user import-csv` tests to their own file --- features/user-import-csv.feature | 134 +++++++++++++++++++++++++++++++ features/user.feature | 133 ------------------------------ 2 files changed, 134 insertions(+), 133 deletions(-) create mode 100644 features/user-import-csv.feature diff --git a/features/user-import-csv.feature b/features/user-import-csv.feature new file mode 100644 index 000000000..990d29243 --- /dev/null +++ b/features/user-import-csv.feature @@ -0,0 +1,134 @@ +Feature: Import users from CSV + + Scenario: Importing users from a CSV file + Given a WP install + And a users.csv file: + """ + user_login,user_email,display_name,role + bobjones,bobjones@example.com,Bob Jones,contributor + newuser1,newuser1@example.com,New User,author + admin,admin@example.com,Existing User,administrator + """ + + When I try `wp user import-csv users-incorrect.csv --skip-update` + Then STDERR should be: + """ + Error: Missing file: users-incorrect.csv + """ + + When I run `wp user import-csv users.csv` + Then STDOUT should not be empty + + When I run `wp user list --format=count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp user list --format=json` + Then STDOUT should be JSON containing: + """ + [{ + "user_login":"admin", + "display_name":"Existing User", + "user_email":"admin@example.com", + "roles":"administrator" + }] + """ + + Scenario: Import new users on multisite + Given a WP multisite install + And a user-invalid.csv file: + """ + user_login,user_email,display_name,role + bob-jones,bobjones@example.com,Bob Jones,contributor + """ + And a user-valid.csv file: + """ + user_login,user_email,display_name,role + bobjones,bobjones@example.com,Bob Jones,contributor + """ + + When I try `wp user import-csv user-invalid.csv` + Then STDERR should contain: + """ + lowercase letters (a-z) and numbers + """ + + When I run `wp user import-csv user-valid.csv` + Then STDOUT should not be empty + + When I run `wp user get bobjones --field=display_name` + Then STDOUT should be: + """ + Bob Jones + """ + + Scenario: Import new users but don't update existing + Given a WP install + And a users.csv file: + """ + user_login,user_email,display_name,role + bobjones,bobjones@example.com,Bob Jones,contributor + newuser1,newuser1@example.com,New User,author + admin,admin@example.com,Existing User,administrator + """ + + When I run `wp user create bobjones bobjones@example.com --display_name="Robert Jones" --role=administrator` + Then STDOUT should not be empty + + When I run `wp user import-csv users.csv --skip-update` + Then STDOUT should not be empty + + When I run `wp user list --format=count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp user get bobjones --fields=user_login,display_name,user_email,roles --format=json` + Then STDOUT should be JSON containing: + """ + { + "user_login":"bobjones", + "display_name":"Robert Jones", + "user_email":"bobjones@example.com", + "roles":"administrator" + } + """ + + Scenario: Import users from a CSV file generated by `wp user list` + Given a WP install + + When I run `wp user delete 1 --yes` + And I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones" --role=contributor` + And I run `wp user create billjones billjones@example.com --display_name="Bill Jones" --role=administrator` + And I run `wp user add-role billjones author` + Then STDOUT should not be empty + + When I run `wp user list --field=user_login | wc -l` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp user list --format=csv > users.csv` + Then the users.csv file should exist + + When I run `wp user delete $(wp user list --format=ids) --yes` + Then STDOUT should not be empty + + When I run `wp user list --field=user_login | wc -l` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp user import-csv users.csv` + Then STDOUT should not be empty + + When I run `wp user list --fields=display_name,roles` + Then STDOUT should be a table containing rows: + | display_name | roles | + | Bob Jones | contributor | + | Bill Jones | administrator,author | diff --git a/features/user.feature b/features/user.feature index 62ed3fe2b..93a012bb1 100644 --- a/features/user.feature +++ b/features/user.feature @@ -125,70 +125,6 @@ Feature: Manage WordPress users 0 """ - Scenario: Importing users from a CSV file - Given a WP install - And a users.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - newuser1,newuser1@example.com,New User,author - admin,admin@example.com,Existing User,administrator - """ - - When I try `wp user import-csv users-incorrect.csv --skip-update` - Then STDERR should be: - """ - Error: Missing file: users-incorrect.csv - """ - - When I run `wp user import-csv users.csv` - Then STDOUT should not be empty - - When I run `wp user list --format=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp user list --format=json` - Then STDOUT should be JSON containing: - """ - [{ - "user_login":"admin", - "display_name":"Existing User", - "user_email":"admin@example.com", - "roles":"administrator" - }] - """ - - Scenario: Import new users on multisite - Given a WP multisite install - And a user-invalid.csv file: - """ - user_login,user_email,display_name,role - bob-jones,bobjones@example.com,Bob Jones,contributor - """ - And a user-valid.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - """ - - When I try `wp user import-csv user-invalid.csv` - Then STDERR should contain: - """ - lowercase letters (a-z) and numbers - """ - - When I run `wp user import-csv user-valid.csv` - Then STDOUT should not be empty - - When I run `wp user get bobjones --field=display_name` - Then STDOUT should be: - """ - Bob Jones - """ - Scenario: Create new users on multisite Given a WP multisite install @@ -207,75 +143,6 @@ Feature: Manage WordPress users Bob Jones """ - Scenario: Import new users but don't update existing - Given a WP install - And a users.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - newuser1,newuser1@example.com,New User,author - admin,admin@example.com,Existing User,administrator - """ - - When I run `wp user create bobjones bobjones@example.com --display_name="Robert Jones" --role=administrator` - Then STDOUT should not be empty - - When I run `wp user import-csv users.csv --skip-update` - Then STDOUT should not be empty - - When I run `wp user list --format=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp user get bobjones --fields=user_login,display_name,user_email,roles --format=json` - Then STDOUT should be JSON containing: - """ - { - "user_login":"bobjones", - "display_name":"Robert Jones", - "user_email":"bobjones@example.com", - "roles":"administrator" - } - """ - - Scenario: Import users from a CSV file generated by `wp user list` - Given a WP install - - When I run `wp user delete 1 --yes` - And I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones" --role=contributor` - And I run `wp user create billjones billjones@example.com --display_name="Bill Jones" --role=administrator` - And I run `wp user add-role billjones author` - Then STDOUT should not be empty - - When I run `wp user list --field=user_login | wc -l` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp user list --format=csv > users.csv` - Then the users.csv file should exist - - When I run `wp user delete $(wp user list --format=ids) --yes` - Then STDOUT should not be empty - - When I run `wp user list --field=user_login | wc -l` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp user import-csv users.csv` - Then STDOUT should not be empty - - When I run `wp user list --fields=display_name,roles` - Then STDOUT should be a table containing rows: - | display_name | roles | - | Bob Jones | contributor | - | Bill Jones | administrator,author | - Scenario: Managing user roles Given a WP install From ae443b9a31123ddae1c5b6e5d724209447ee8ee3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 16:59:11 -0800 Subject: [PATCH 3962/5359] Introduce `WP_CLI\Utils\get_temp_dir()` for safer temp directories Also warns end user when the temp directory isn't writable. --- php/WP_CLI/CoreUpgrader.php | 2 +- php/WP_CLI/REPL.php | 2 +- php/commands/cli.php | 2 +- php/commands/core.php | 2 +- php/utils.php | 32 +++++++++++++++++++++++++++++++- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 25dc2335a..1b9bf6293 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -35,7 +35,7 @@ function download_package( $package ) { $filename = pathinfo( $package, PATHINFO_FILENAME ); $ext = pathinfo( $package, PATHINFO_EXTENSION ); - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.' . $ext; $cache = WP_CLI::get_cache(); $update = $GLOBALS['wp_cli_update_obj']; diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index b3f902316..576359ecc 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -99,7 +99,7 @@ private static function create_prompt_cmd( $prompt, $history_path ) { private function set_history_file() { $data = getcwd() . get_current_user(); - $this->history_file = sys_get_temp_dir() . '/wp-cli-history-' . md5( $data ); + $this->history_file = \WP_CLI\Utils\get_temp_dir() . 'wp-cli-history-' . md5( $data ); } private static function starts_with( $tokens, $line ) { diff --git a/php/commands/cli.php b/php/commands/cli.php index 30baa3237..a021f6acd 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -169,7 +169,7 @@ public function update( $_, $assoc_args ) { WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.phar'; + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.phar'; $headers = array(); $options = array( diff --git a/php/commands/core.php b/php/commands/core.php index 4e901c0d9..55055b7b7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -119,7 +119,7 @@ public function download( $args, $assoc_args ) { if ( ! $cache_file || $bad_cache ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.tar.gz'; + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.tar.gz'; $headers = array('Accept' => 'application/json'); $options = array( diff --git a/php/utils.php b/php/utils.php index 69ad1c355..8cdc5dbe9 100644 --- a/php/utils.php +++ b/php/utils.php @@ -21,7 +21,7 @@ function extract_from_phar( $path ) { $fname = basename( $path ); - $tmp_path = sys_get_temp_dir() . "/wp-cli-$fname"; + $tmp_path = get_temp_dir() . "wp-cli-$fname"; copy( $path, $tmp_path ); @@ -577,3 +577,33 @@ function get_named_sem_ver( $new_version, $original_version ) { function get_flag_value( $args, $flag, $default = null ) { return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; } + +/** + * Get the temp directory, and let the user know if it isn't writable. + * + * @return string + */ +function get_temp_dir() { + static $temp = ''; + + $trailingslashit = function( $path ) { + return rtrim( $path ) . '/'; + }; + + if ( $temp ) + return $trailingslashit( $temp ); + + if ( function_exists( 'sys_get_temp_dir' ) ) { + $temp = sys_get_temp_dir(); + } else if ( ini_get( 'upload_tmp_dir' ) ) { + $temp = ini_get( 'upload_tmp_dir' ); + } else { + $temp = '/tmp/'; + } + + if ( ! @is_writable( $temp ) ) { + WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); + } + + return $trailingslashit( $temp ); +} From cc1a58b78eeb68ca435dc0c8906156d2d37ae700 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Dec 2015 17:02:33 -0800 Subject: [PATCH 3963/5359] php-cli-tools: a more impossible placeholder pattern See https://github.com/wp-cli/php-cli-tools/pull/93 --- composer.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.lock b/composer.lock index d56818577..c54b3c3f5 100644 --- a/composer.lock +++ b/composer.lock @@ -696,12 +696,12 @@ "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "c6f72ea088518ffda711634e46589c2dbc0036cb" + "reference": "d0564da283585c7289e18877ed2f9c35c1b67013" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/c6f72ea088518ffda711634e46589c2dbc0036cb", - "reference": "c6f72ea088518ffda711634e46589c2dbc0036cb", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d0564da283585c7289e18877ed2f9c35c1b67013", + "reference": "d0564da283585c7289e18877ed2f9c35c1b67013", "shasum": "" }, "require": { From 816564344eea06e8c9156b61424241665d59bc6d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Jan 2016 20:10:26 -0800 Subject: [PATCH 3964/5359] Update WordPress versions for 4.4.1 and brethren, attempt two --- features/core-check-update.feature | 8 ++++---- features/core-update.feature | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index f35d28a1a..7d9a3d2d5 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -10,8 +10,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | - | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | + | 4.4.1 | major | https://wordpress.org/wordpress-4.4.1.zip | + | 3.8.12 | minor | https://wordpress.org/wordpress-3.8.12.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -22,7 +22,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4 | major | https://wordpress.org/wordpress-4.4.zip | + | 4.4.1 | major | https://wordpress.org/wordpress-4.4.1.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -33,7 +33,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.11 | minor | https://wordpress.org/wordpress-3.8.11.zip | + | 3.8.12 | minor | https://wordpress.org/wordpress-3.8.12.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: diff --git a/features/core-update.feature b/features/core-update.feature index 058e880d0..7a4c45e27 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -38,7 +38,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.11 + Updating to version 3.7.12 """ When I run `wp core update --minor` @@ -50,7 +50,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.11 + 3.7.12 """ @less-than-php-7 From 7a4908a0090693c6ca7d6aba52b18182955256d9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jan 2016 07:17:48 -0800 Subject: [PATCH 3965/5359] Lock `php-cli-tools` to 0.11.0 --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d8d6c5246..cfa9066ea 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "0.11.0", "mustache/mustache": "~2.4", "mustangostang/spyc": "0.5.1", "composer/semver": "1.0.0", diff --git a/composer.lock b/composer.lock index c24b9ebcd..3968ddb0c 100644 --- a/composer.lock +++ b/composer.lock @@ -739,7 +739,7 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "dev-master", + "version": "0.11.0", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", From 19641b8a5a64769824b1e457500f07cdbf6c4a69 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jan 2016 08:03:03 -0800 Subject: [PATCH 3966/5359] Update `.mailmap` for v0.22.0 --- .mailmap | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.mailmap b/.mailmap index 080fcc238..9f24a1a94 100644 --- a/.mailmap +++ b/.mailmap @@ -20,6 +20,7 @@ c10b10 <alex.ciobica@gmail.com> Chris Montgomery <chris@montchr.io> clemens-tolboom <clemens@build2be.com> conatus <alex@recordsonribs.com> +Corey Worrell <proskater55@gmail.com> ctayloroomphinc <ctaylor@thinkoomph.com> cyberhobo <dylan.k.kuhn@gmail.com> dangardner <dan@web.nearest.to> @@ -27,21 +28,27 @@ Daniel Bachhuber <daniel.bachhuber@fusion.net> danielbachhuber <d@danielbachhuber.com> danielbachhuber <daniel@handbuilt.co> danielbachhuber <danielbachhuber@gmail.com> +Dave Leach <dave@dmleach.com> dd32 <contact-atlassian@dd32.id.au> dlh01 <david@alleyinteractive.com> drrobotnik <B@Brandons-Mac-Pro-4.local> +Duncan Brown <duncanjbrown@gmail.com> dwightjack <marco.solazzi@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> eugeneware <eugene@noblesamurai.com> Evan Mattson <me@aaemnnost.tv> francescolaffi <francesco.laffi@gmail.com> +Frankie Jarrett <fjarrett@godaddy.com> future500 <ramon@future500.nl> getsource <mike.schroder@dreamhost.com> +Gilbert Pellegrom <gilbert@pellegrom.me> glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> Grant McInnes <grant.mcinnes@eyesopen.ca> +Greg Anderson <greg.1.anderson@greenknowe.org> Hiroshi Urabe <mail@torounit.com> +Ian Dunn <ian@iandunn.name> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> Jan VoráÄek <jan@voracek.net> @@ -56,6 +63,7 @@ johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> +Josh Eaton <josh@josheaton.org> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> JQ <JeyKeu@users.noreply.github.com> @@ -75,6 +83,7 @@ mattheu <matthew@matth.eu> mboynes <mboynes@alleyinteractive.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> +Mihail Minkov <Mihail.Minkov.BG@gmail.com> mikey dubs <mike@herebox.org> milesj <mileswjohnson@gmail.com> MiteshShah <Mitesh.Shah@rtCamp.com> @@ -89,6 +98,7 @@ nb <nb@nikolay.bg> nickdaugherty <ndaugherty987@gmail.com> nikolay <nikolay@users.noreply.github.com> nikolay <nikolaynkolev@gmail.com> +Nilambar Sharma <ernilambar@users.noreply.github.com> nschoenholtz <noah@alleyinteractive.com> nullvariable <nullvariable@gmail.com> nyordanov <me@nyordanov.com> @@ -107,7 +117,9 @@ rodrigoprimo <rodrigo@hacklab.com.br> rodrigoprimo <rodrigosprimo@gmail.com> roelven <roel@soundcloud.com> Ross Hattori <rhattori@saymedia.com> +Ryan Hoover <ryanshoover@gmail.com> Ryan McCue <me@ryanmccue.info> +Ryan Williams <ryrowi@gmail.com> ryanduff <ryan@fusionized.com> santagada <santagada@gmail.com> sboisvert <stephane.boisvert@automattic.com> @@ -124,6 +136,7 @@ Stephen Edgar <stephen@netweb.com.au> Steve Grunwell <steve.grunwell@10up.com> Steve Grunwell <steve@stevegrunwell.com> Steve Grunwell <stevegrunwell@gmail.com> +Steve Persch <steve.persch@pantheon.io> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> Svetoslav Marinov (Slavi) <slavi@orbisius.com> @@ -137,6 +150,7 @@ tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> tott <tott@automattic.com> trepmal <trepmal@gmail.com> +Tristan Penman <tristan@tristanpenman.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> voldemortensen <voldemortensen@users.noreply.github.com> From e52a853016ef34e3b36e5862e373f77289218e5a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jan 2016 08:10:01 -0800 Subject: [PATCH 3967/5359] Cut Travis' workload down on PRs --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5fb2dfcfd..aa03bd705 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,10 @@ cache: directories: - vendor +branches: + only: + - master + notifications: email: on_success: never From 45460a55328db9952e0c93023c8b79a2432332d9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jan 2016 08:36:32 -0800 Subject: [PATCH 3968/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 394160575..215740905 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.22.0-alpha +0.22.0 From 25e773a860a12debd7be3530e1d87793ba7e2211 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jan 2016 10:01:55 -0800 Subject: [PATCH 3969/5359] Bump version to 0.23.0-alpha --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 215740905..c648a65ef 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.22.0 +0.23.0-alpha From a63a08af529e80aefdf0edc3fa7dcba5315d8bb5 Mon Sep 17 00:00:00 2001 From: Anant Shrivastava <anant@anantshri.info> Date: Sat, 9 Jan 2016 12:16:00 +0530 Subject: [PATCH 3970/5359] Switched response to auto lower case Switching response to auto lower case allows us to use Y or y as yes --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 74839ceef..299622f65 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -289,7 +289,7 @@ public static function confirm( $question, $assoc_args = array() ) { if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'yes' ) ) { fwrite( STDOUT, $question . " [y/n] " ); - $answer = trim( fgets( STDIN ) ); + $answer = strtolower( trim( fgets( STDIN ) ) ); if ( 'y' != $answer ) exit; From 73393ee80f3762d6dab7e4b482bc7997d0e99658 Mon Sep 17 00:00:00 2001 From: hina <hina@hinaloe.net> Date: Mon, 11 Jan 2016 11:06:57 +0900 Subject: [PATCH 3971/5359] Check update file response status --- php/WP_CLI/CoreUpgrader.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 1b9bf6293..9e18c1f64 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -59,7 +59,11 @@ function download_package( $package ) { $this->skin->feedback( 'downloading_package', $package ); - Utils\http_request( 'GET', $package, null, $headers, $options ); + /** @var \Requests_Response|null $req */ + $req = Utils\http_request( 'GET', $package, null, $headers, $options ); + if ( ! is_null( $req ) && $req->status_code !== 200 ) { + return new \WP_Error( 'download_failed', $this->strings['download_failed'] ); + } $cache->import( $cache_key, $temp ); return $temp; } @@ -67,4 +71,3 @@ function download_package( $package ) { } } - From bb8c85e984ea5bffafebde03dc9469ab6ef4de40 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Jan 2016 04:45:19 -0800 Subject: [PATCH 3972/5359] Improve performance of `wp user list --format=count` * Only fetch user IDs, to avoid join with user meta table. * Skip unnecessary `SQL_CALC_FOUND_ROWS` --- php/commands/user.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 130a4ff34..a65b986ba 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -96,16 +96,19 @@ public function list_( $args, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); - if ( 'ids' == $formatter->format ) { + if ( in_array( $formatter->format, array( 'ids', 'count' ) ) ) { $assoc_args['fields'] = 'ids'; } else { $assoc_args['fields'] = 'all_with_meta'; } + $assoc_args['count_total'] = false; $users = get_users( $assoc_args ); if ( 'ids' == $formatter->format ) { echo implode( ' ', $users ); + } else if ( 'count' === $formatter->format ) { + $formatter->display_items( $users ); } else { $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { if ( !is_object( $user ) ) From 7466d6b80f4703dc4e0701b26de18daf699bff5c Mon Sep 17 00:00:00 2001 From: Marco <mcastelluccio@mozilla.com> Date: Tue, 12 Jan 2016 16:03:32 +0100 Subject: [PATCH 3973/5359] Don't cd in WP_TESTS_DIR before dowloading and setting up wp-tests-config.php The paths in the remaining of the function are relative to the main directory, so the script shouldn't cd in WP_TESTS_DIR. --- templates/install-wp-tests.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 5baa6cb56..4f5335586 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -81,8 +81,6 @@ install_test_suite() { svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes fi - cd $WP_TESTS_DIR - if [ ! -f wp-tests-config.php ]; then download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php From 290edcb252a8134322bbdcff2a038fd97317a16d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Jan 2016 06:55:33 -0800 Subject: [PATCH 3974/5359] Register an arbitrary function, closure, or method as a command --- features/command.feature | 162 ++++++++++++++++++++++- php/WP_CLI/Dispatcher/CommandFactory.php | 54 +++++--- php/class-wp-cli.php | 25 +++- 3 files changed, 216 insertions(+), 25 deletions(-) diff --git a/features/command.feature b/features/command.feature index 2039cc123..525eded94 100644 --- a/features/command.feature +++ b/features/command.feature @@ -13,7 +13,7 @@ Feature: WP-CLI Commands Then the return code should be 1 And STDERR should contain: """ - Class 'Non_Existent_Class' does not exist. + Callable "Non_Existent_Class" does not exist, and cannot be registered as `wp command example`. """ Scenario: Invalid subcommand of valid command @@ -39,3 +39,163 @@ Feature: WP-CLI Commands """ Error: 'invalid' is not a registered subcommand of 'command'. See 'wp help command'. """ + + Scenario: Use a closure as a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + /** + * My awesome closure command + * + * <message> + * : An awesome message to display + * + * @when before_wp_load + */ + $foo = function( $args ) { + WP_CLI::success( $args[0] ); + }; + WP_CLI::add_command( 'foo', $foo ); + """ + + When I run `wp --require=custom-cmd.php help` + Then STDOUT should contain: + """ + foo + """ + + When I run `wp --require=custom-cmd.php help foo` + Then STDOUT should contain: + """ + My awesome closure command + """ + + When I try `wp --require=custom-cmd.php foo bar --burrito` + Then STDERR should contain: + """ + unknown --burrito parameter + """ + + When I run `wp --require=custom-cmd.php foo bar` + Then STDOUT should contain: + """ + Success: bar + """ + + Scenario: Use a function as a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + /** + * My awesome function command + * + * <message> + * : An awesome message to display + * + * @when before_wp_load + */ + function foo( $args ) { + WP_CLI::success( $args[0] ); + } + WP_CLI::add_command( 'foo', 'foo' ); + """ + + When I run `wp --require=custom-cmd.php help` + Then STDOUT should contain: + """ + foo + """ + + When I run `wp --require=custom-cmd.php help foo` + Then STDOUT should contain: + """ + My awesome function command + """ + + When I try `wp --require=custom-cmd.php foo bar --burrito` + Then STDERR should contain: + """ + unknown --burrito parameter + """ + + When I run `wp --require=custom-cmd.php foo bar` + Then STDOUT should contain: + """ + Success: bar + """ + + Scenario: Use a class method as a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Foo_Class extends WP_CLI_Command { + /** + * My awesome class method command + * + * <message> + * : An awesome message to display + * + * @when before_wp_load + */ + function foo( $args ) { + WP_CLI::success( $args[0] ); + } + } + $foo = new Foo_Class; + WP_CLI::add_command( 'foo', array( $foo, 'foo' ) ); + """ + + When I run `wp --require=custom-cmd.php help` + Then STDOUT should contain: + """ + foo + """ + + When I run `wp --require=custom-cmd.php help foo` + Then STDOUT should contain: + """ + My awesome class method command + """ + + When I try `wp --require=custom-cmd.php foo bar --burrito` + Then STDERR should contain: + """ + unknown --burrito parameter + """ + + When I run `wp --require=custom-cmd.php foo bar` + Then STDOUT should contain: + """ + Success: bar + """ + + Scenario: Use an invalid class method as a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Foo_Class extends WP_CLI_Command { + /** + * My awesome class method command + * + * <message> + * : An awesome message to display + * + * @when before_wp_load + */ + function foo( $args ) { + WP_CLI::success( $args[0] ); + } + } + $foo = new Foo_Class; + WP_CLI::add_command( 'bar', array( $foo, 'bar' ) ); + """ + + When I try `wp --require=custom-cmd.php bar` + Then STDERR should contain: + """ + Error: Callable ["Foo_Class","bar"] does not exist, and cannot be registered as `wp bar`. + """ diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index b4f941dd0..274d53201 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -13,17 +13,27 @@ class CommandFactory { * Create a new CompositeCommand (or Subcommand if class has __invoke()) * * @param string $name Represents how the command should be invoked - * @param string $class A subclass of WP_CLI_Command + * @param string $callable A subclass of WP_CLI_Command, a function, or a closure * @param mixed $parent The new command's parent Composite (or Root) command */ - public static function create( $name, $class, $parent ) { - $reflection = new \ReflectionClass( $class ); - - if ( $reflection->hasMethod( '__invoke' ) ) { - $command = self::create_subcommand( $parent, $name, $reflection->name, - $reflection->getMethod( '__invoke' ) ); + public static function create( $name, $callable, $parent ) { + + if ( ( is_object( $callable ) && ( $callable instanceof \Closure ) ) + || ( is_string( $callable ) && function_exists( $callable ) ) ) { + $reflection = new \ReflectionFunction( $callable ); + $command = self::create_subcommand( $parent, $name, $callable, $reflection ); + } else if ( is_array( $callable ) && is_callable( $callable ) ) { + $reflection = new \ReflectionClass( $callable[0] ); + $command = self::create_subcommand( $parent, $name, array( $reflection->name, $callable[1] ), + $reflection->getMethod( $callable[1] ) ); } else { - $command = self::create_composite_command( $parent, $name, $reflection ); + $reflection = new \ReflectionClass( $callable ); + if ( $reflection->hasMethod( '__invoke' ) ) { + $command = self::create_subcommand( $parent, $name, array( $reflection->name, '__invoke' ), + $reflection->getMethod( '__invoke' ) ); + } else { + $command = self::create_composite_command( $parent, $name, $reflection ); + } } return $command; @@ -34,22 +44,28 @@ public static function create( $name, $class, $parent ) { * * @param mixed $parent The new command's parent Composite command * @param string $name Represents how the command should be invoked + * @param mixed $callable A callable function or closure, or class name and method + * @param object $reflection Reflection instance, for doc parsing * @param string $class A subclass of WP_CLI_Command * @param string $method Class method to be called upon invocation. */ - private static function create_subcommand( $parent, $name, $class_name, $method ) { - $docparser = new \WP_CLI\DocParser( $method->getDocComment() ); - - if ( !$name ) - $name = $docparser->get_tag( 'subcommand' ); + private static function create_subcommand( $parent, $name, $callable, $reflection ) { + $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); - if ( !$name ) - $name = $method->name; + if ( is_array( $callable ) ) { + if ( !$name ) + $name = $docparser->get_tag( 'subcommand' ); - $method_name = $method->name; + if ( !$name ) + $name = $reflection->name; + } - $when_invoked = function ( $args, $assoc_args ) use ( $class_name, $method_name ) { - call_user_func( array( new $class_name, $method_name ), $args, $assoc_args ); + $when_invoked = function ( $args, $assoc_args ) use ( $callable ) { + if ( is_array( $callable ) ) { + call_user_func( array( new $callable[0], $callable[1] ), $args, $assoc_args ); + } else { + call_user_func( $callable, $args, $assoc_args ); + } }; return new Subcommand( $parent, $name, $docparser, $when_invoked ); @@ -71,7 +87,7 @@ private static function create_composite_command( $parent, $name, $reflection ) if ( !self::is_good_method( $method ) ) continue; - $subcommand = self::create_subcommand( $container, false, $reflection->name, $method ); + $subcommand = self::create_subcommand( $container, false, array( $reflection->name, $method->name ), $method ); $subcommand_name = $subcommand->get_name(); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 299622f65..df0785e73 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -166,13 +166,28 @@ public static function do_hook( $when ) { * Add a command to the wp-cli list of commands * * @param string $name The name of the command that will be used in the CLI - * @param string $class The command implementation + * @param string $callable The command implementation as a class, function or closure * @param array $args An associative array with additional parameters: * 'before_invoke' => callback to execute before invoking the command */ - public static function add_command( $name, $class, $args = array() ) { - if ( is_string( $class ) && ! class_exists( (string) $class ) ) { - WP_CLI::error( sprintf( "Class '%s' does not exist.", $class ) ); + public static function add_command( $name, $callable, $args = array() ) { + $valid = false; + if ( is_object( $callable ) && ( $callable instanceof \Closure ) ) { + $valid = true; + } else if ( is_string( $callable ) && function_exists( $callable ) ) { + $valid = true; + } else if ( is_string( $callable ) && class_exists( (string) $callable ) ) { + $valid = true; + } else if ( is_object( $callable ) ) { + $valid = true; + } else if ( is_array( $callable ) && is_callable( $callable ) ) { + $valid = true; + } + if ( ! $valid ) { + if ( is_array( $callable ) ) { + $callable = array( get_class( $callable[0] ), $callable[1] ); + } + WP_CLI::error( sprintf( "Callable %s does not exist, and cannot be registered as `wp %s`.", json_encode( $callable ), $name ) ); } if ( isset( $args['before_invoke'] ) ) { @@ -200,7 +215,7 @@ public static function add_command( $name, $class, $args = array() ) { $command = $subcommand; } - $leaf_command = Dispatcher\CommandFactory::create( $leaf_name, $class, $command ); + $leaf_command = Dispatcher\CommandFactory::create( $leaf_name, $callable, $command ); if ( ! $command->can_have_subcommands() ) { throw new Exception( sprintf( "'%s' can't have subcommands.", From 2c9a3dca58b86663769c39da8bff5437e8925ca4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Jan 2016 07:25:43 -0800 Subject: [PATCH 3975/5359] Add `(before|after)_wp(_config)_load` hooks in WP load process This enables code injected via `--require` to make modifications at runtime. --- php/WP_CLI/Runner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index af6932e2d..5c48e329b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -739,6 +739,7 @@ public function load_wordpress() { $wp_cli_is_loaded = true; WP_CLI::debug( 'Begin WordPress load' ); + WP_CLI::do_hook( 'before_wp_load' ); $this->check_wp_version(); @@ -750,6 +751,7 @@ public function load_wordpress() { } WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path ); + WP_CLI::do_hook( 'before_wp_config_load' ); // Load wp-config.php code, in the global scope $wp_cli_original_defined_vars = get_defined_vars(); @@ -762,6 +764,7 @@ public function load_wordpress() { } $this->maybe_update_url_from_domain_constant(); + WP_CLI::do_hook( 'after_wp_config_load' ); // Load WP-CLI utilities require WP_CLI_ROOT . '/php/utils-wp.php'; @@ -783,6 +786,7 @@ public function load_wordpress() { } WP_CLI::debug( 'Loaded WordPress' ); + WP_CLI::do_hook( 'after_wp_load' ); } From 2190333ed9eaff4777b9f6e2adeae080d36714e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 14 Jan 2016 06:26:33 -0800 Subject: [PATCH 3976/5359] Prevent dupe builds with Travis defaults in `scaffold plugin-tests` --- templates/.travis.mustache | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/.travis.mustache b/templates/.travis.mustache index 5a77b81b6..38a8ae25a 100644 --- a/templates/.travis.mustache +++ b/templates/.travis.mustache @@ -5,6 +5,10 @@ notifications: on_success: never on_failure: change +branches: + only: + - master + php: - 5.3 - 5.6 From 4bebf622b455c14d327ce57af81149250c37bac6 Mon Sep 17 00:00:00 2001 From: Eduardo Alencar <ealencar10@gmail.com> Date: Thu, 14 Jan 2016 14:11:07 -0200 Subject: [PATCH 3977/5359] Remove whitespace on rewrite command --- php/commands/rewrite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 3f33c1c92..dc3bb68b6 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -218,5 +218,5 @@ function apache_get_modules() { } } -WP_CLI:: add_command( 'rewrite', 'Rewrite_Command' ); +WP_CLI::add_command( 'rewrite', 'Rewrite_Command' ); From 04b82e1bd1719a6a2a9d42f5101ad39c3f41114d Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 12:03:24 +0000 Subject: [PATCH 3978/5359] Make `wp core download --force` and `wp core update --force` clean up files when downgrading from 4.4 --- php/commands/core.php | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index fdaadb186..40c7d03e4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -99,6 +99,14 @@ public function download( $args, $assoc_args ) { $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); } + $from_version = ''; + $includes_folder = defined( 'WPINC' ) ? WPINC : '/wp-includes'; + if ( file_exists( $download_dir . $includes_folder . '/version.php' ) ) { + global $wp_version; + require_once( $download_dir . $includes_folder . '/version.php' ); + $from_version = $wp_version; + } + WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $version, $locale ) ); $cache = WP_CLI::get_cache(); @@ -143,6 +151,8 @@ public function download( $args, $assoc_args ) { unlink($temp); } + $this->_maybe_remove_unused_files( $from_version, $assoc_args['version'] ); + WP_CLI::success( 'WordPress downloaded.' ); } @@ -964,10 +974,14 @@ function update( $args, $assoc_args ) { WP_CLI::log( "Starting update..." ); } + $from_version = $wp_version; + $GLOBALS['wp_cli_update_obj'] = $update; $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); unset( $GLOBALS['wp_cli_update_obj'] ); + $this->_maybe_remove_unused_files( $from_version, $update->version ); + if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); if ( 'up_to_date' != $result->get_error_code() ) { @@ -1150,6 +1164,29 @@ private function get_updates( $assoc_args ) { return array_values( $updates ); } + private function _maybe_remove_unused_files( $version_from, $version_to) { + if ( ! $version_from || ! $version_to ) { + return; + } + + $files_to_remove = array(); + $includes_folder = defined( 'WPINC' ) ? WPINC : '/wp-includes'; + + if ( version_compare( $version_from, '4.4', '>=' ) && version_compare( $version_to, '4.4', '<' ) ) { + $files_to_remove[] = ABSPATH . $includes_folder . '/embed-functions.php'; + $files_to_remove[] = ABSPATH . $includes_folder . '/class-wp-oembed-controller.php'; + $files_to_remove[] = ABSPATH . $includes_folder . '/rest-api.php'; + } + + if ( ! empty( $files_to_remove ) ) { + foreach ( $files_to_remove as $file ) { + if ( file_exists( $file ) ) { + unlink( $file ); + } + } + } + } + } WP_CLI::add_command( 'core', 'Core_Command' ); From 5c605c0d6c6e622884443727c4297518af98db47 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 12:28:28 +0000 Subject: [PATCH 3979/5359] Add functional tests --- features/core-download.feature | 8 ++++++++ features/core-update.feature | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/features/core-download.feature b/features/core-download.feature index c36801b82..ec2a49695 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -67,3 +67,11 @@ Feature: Download WordPress """ Error: WordPress files seem to already be present here. """ + + Scenario: Downgrade from 4.4 to 4.3.2 cleans up files + Given an empty directory + When I run `wp core download --version=4.4` + Then the wp-includes/rest-api.php file should exist + + When I run `wp core download --version=4.3.2 --force` + Then the wp-includes/rest-api.php file should not exist diff --git a/features/core-update.feature b/features/core-update.feature index 7a4c45e27..72992fcd5 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -158,3 +158,11 @@ Feature: Update WordPress core wordpress-4.2.4-no-content-en_US.zip wordpress-4.2.4-partial-1-en_US.zip """ + + Scenario: Downgrade from 4.4 to 4.3.2 cleans up files + Given a WP install + When I run `wp core update --version=4.4 --force` + Then the wp-includes/rest-api.php file should exist + + When I run `wp core update --version=4.3.2 --force` + Then the wp-includes/rest-api.php file should not exist From f0471d8738adea63d165a62f5ebfdcb83a0b2480 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 14:58:50 +0000 Subject: [PATCH 3980/5359] Remove underscore --- php/commands/core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 40c7d03e4..aa32f7e93 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -151,7 +151,7 @@ public function download( $args, $assoc_args ) { unlink($temp); } - $this->_maybe_remove_unused_files( $from_version, $assoc_args['version'] ); + $this->maybe_remove_unused_files( $from_version, $assoc_args['version'] ); WP_CLI::success( 'WordPress downloaded.' ); } @@ -980,7 +980,7 @@ function update( $args, $assoc_args ) { $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); unset( $GLOBALS['wp_cli_update_obj'] ); - $this->_maybe_remove_unused_files( $from_version, $update->version ); + $this->maybe_remove_unused_files( $from_version, $update->version ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); @@ -1164,7 +1164,7 @@ private function get_updates( $assoc_args ) { return array_values( $updates ); } - private function _maybe_remove_unused_files( $version_from, $version_to) { + private function maybe_remove_unused_files( $version_from, $version_to) { if ( ! $version_from || ! $version_to ) { return; } From 4a11410d6f7f0026548ffc5e02730ad66f6f1ed9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 15 Jan 2016 07:27:52 -0800 Subject: [PATCH 3981/5359] Improve .travis.yml for package tests * Disable noisy email notifications by default. * Prevent duplicate builds on pull requests. * Use two space indentation instead of four. --- templates/.travis.package.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/templates/.travis.package.yml b/templates/.travis.package.yml index 737aea122..bb11edec4 100644 --- a/templates/.travis.package.yml +++ b/templates/.travis.package.yml @@ -1,15 +1,24 @@ language: php +notifications: + email: + on_success: never + on_failure: change + +branches: + only: + - master + php: - - 5.3 - - 5.5 + - 5.3 + - 5.6 env: - global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - - WP_CLI_CONFIG_PATH=/tmp/wp-cli-phar/config.yml + global: + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + - WP_CLI_CONFIG_PATH=/tmp/wp-cli-phar/config.yml before_script: - - bash bin/install-package-tests.sh + - bash bin/install-package-tests.sh script: ./vendor/bin/behat From cad1153b735aeb665c2ca5920174c3b30ae9bf73 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 15:42:10 +0000 Subject: [PATCH 3982/5359] Fix includes folder path --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index aa32f7e93..dd221d8b6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -100,7 +100,7 @@ public function download( $args, $assoc_args ) { } $from_version = ''; - $includes_folder = defined( 'WPINC' ) ? WPINC : '/wp-includes'; + $includes_folder = defined( 'WPINC' ) ? WPINC : 'wp-includes'; if ( file_exists( $download_dir . $includes_folder . '/version.php' ) ) { global $wp_version; require_once( $download_dir . $includes_folder . '/version.php' ); From 342a07b080a6992e0072fb5ba4f703376b35d4fa Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 15:43:35 +0000 Subject: [PATCH 3983/5359] Move version comparison outside the method and pass locale --- php/commands/core.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index dd221d8b6..3bc0a4226 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -151,7 +151,9 @@ public function download( $args, $assoc_args ) { unlink($temp); } - $this->maybe_remove_unused_files( $from_version, $assoc_args['version'] ); + if ( version_compare( $from_version, '4.4', '>=' ) && version_compare( $assoc_args['version'], '4.4', '<' ) ) { + $this->remove_unused_files( $from_version, $assoc_args['version'], $locale ); + } WP_CLI::success( 'WordPress downloaded.' ); } @@ -980,7 +982,10 @@ function update( $args, $assoc_args ) { $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); unset( $GLOBALS['wp_cli_update_obj'] ); - $this->maybe_remove_unused_files( $from_version, $update->version ); + if ( version_compare( $from_version, '4.4', '>=' ) && version_compare( $update->version, '4.4', '<' ) ) { + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); + $this->remove_unused_files( $from_version, $update->version, $locale ); + } if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); @@ -1164,7 +1169,7 @@ private function get_updates( $assoc_args ) { return array_values( $updates ); } - private function maybe_remove_unused_files( $version_from, $version_to) { + private function remove_unused_files( $version_from, $version_to, $locale ) { if ( ! $version_from || ! $version_to ) { return; } From a41899790a5be8b256383e2eee8dec530e4d7d8c Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 15:44:06 +0000 Subject: [PATCH 3984/5359] Use get_core_checksums to calculate files to remove --- php/commands/core.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3bc0a4226..0957a7f44 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1174,19 +1174,19 @@ private function remove_unused_files( $version_from, $version_to, $locale ) { return; } - $files_to_remove = array(); - $includes_folder = defined( 'WPINC' ) ? WPINC : '/wp-includes'; + $old_checksums = self::get_core_checksums( $version_from, $locale ? $locale : 'en_US' ); + $new_checksums = self::get_core_checksums( $version_to, $locale ? $locale : 'en_US' ); - if ( version_compare( $version_from, '4.4', '>=' ) && version_compare( $version_to, '4.4', '<' ) ) { - $files_to_remove[] = ABSPATH . $includes_folder . '/embed-functions.php'; - $files_to_remove[] = ABSPATH . $includes_folder . '/class-wp-oembed-controller.php'; - $files_to_remove[] = ABSPATH . $includes_folder . '/rest-api.php'; + if ( empty( $old_checksums ) || empty( $new_checksums ) ) { + return; } + $files_to_remove = array_diff( array_keys( $old_checksums ), array_keys( $new_checksums ) ); + if ( ! empty( $files_to_remove ) ) { foreach ( $files_to_remove as $file ) { - if ( file_exists( $file ) ) { - unlink( $file ); + if ( file_exists( ABSPATH . $file ) ) { + unlink( ABSPATH . $file ); } } } From a23fbf25e52a73200fd87d9a057c47c96edacf52 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 15:44:22 +0000 Subject: [PATCH 3985/5359] Output count of files deleted --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index 0957a7f44..db02aa8a2 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1189,6 +1189,7 @@ private function remove_unused_files( $version_from, $version_to, $locale ) { unlink( ABSPATH . $file ); } } + WP_CLI::log( count($files_to_remove) . ' files cleaned up' ); } } From 05db2eb716491923dd4666ac62f0c345f97b7575 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 16:06:35 +0000 Subject: [PATCH 3986/5359] Remove version comparison checks --- php/commands/core.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index db02aa8a2..d95bedf54 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -151,9 +151,7 @@ public function download( $args, $assoc_args ) { unlink($temp); } - if ( version_compare( $from_version, '4.4', '>=' ) && version_compare( $assoc_args['version'], '4.4', '<' ) ) { - $this->remove_unused_files( $from_version, $assoc_args['version'], $locale ); - } + $this->remove_unused_files( $from_version, $assoc_args['version'], $locale ); WP_CLI::success( 'WordPress downloaded.' ); } @@ -982,10 +980,8 @@ function update( $args, $assoc_args ) { $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); unset( $GLOBALS['wp_cli_update_obj'] ); - if ( version_compare( $from_version, '4.4', '>=' ) && version_compare( $update->version, '4.4', '<' ) ) { - $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); - $this->remove_unused_files( $from_version, $update->version, $locale ); - } + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); + $this->remove_unused_files( $from_version, $update->version, $locale ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); From 1a4714548196cc33b3af87a0afd3a543c8f24701 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 16:06:48 +0000 Subject: [PATCH 3987/5359] Better logging --- php/commands/core.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d95bedf54..10ad84838 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1167,6 +1167,7 @@ private function get_updates( $assoc_args ) { private function remove_unused_files( $version_from, $version_to, $locale ) { if ( ! $version_from || ! $version_to ) { + WP_CLI::warning( 'Failed to find WordPress version. Please cleanup unused files manually.' ); return; } @@ -1174,18 +1175,23 @@ private function remove_unused_files( $version_from, $version_to, $locale ) { $new_checksums = self::get_core_checksums( $version_to, $locale ? $locale : 'en_US' ); if ( empty( $old_checksums ) || empty( $new_checksums ) ) { + WP_CLI::warning( 'Failed to fetch checksums. Please cleanup unused files manually.' ); return; } $files_to_remove = array_diff( array_keys( $old_checksums ), array_keys( $new_checksums ) ); if ( ! empty( $files_to_remove ) ) { + WP_CLI::log( 'Cleaning up unused files...' ); + foreach ( $files_to_remove as $file ) { if ( file_exists( ABSPATH . $file ) ) { unlink( ABSPATH . $file ); + WP_CLI::log( 'File removed: ' . $file ); } } - WP_CLI::log( count($files_to_remove) . ' files cleaned up' ); + + WP_CLI::success( count( $files_to_remove ) . ' unused files cleaned up' ); } } From 958f98ed4c4fcf0731489108bd4ee89937515d86 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 16:11:43 +0000 Subject: [PATCH 3988/5359] Count actual files deleted --- php/commands/core.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 10ad84838..87bc9904d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1184,14 +1184,18 @@ private function remove_unused_files( $version_from, $version_to, $locale ) { if ( ! empty( $files_to_remove ) ) { WP_CLI::log( 'Cleaning up unused files...' ); + $count = 0; foreach ( $files_to_remove as $file ) { if ( file_exists( ABSPATH . $file ) ) { unlink( ABSPATH . $file ); WP_CLI::log( 'File removed: ' . $file ); + $count++; } } - WP_CLI::success( count( $files_to_remove ) . ' unused files cleaned up' ); + if ( $count ) { + WP_CLI::success( number_format( $count ) . ' unused files cleaned up' ); + } } } From 4ca2925c8938771e2c8bf2499e9503c5df4ecd47 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 15 Jan 2016 16:18:34 +0000 Subject: [PATCH 3989/5359] Update tests --- features/core-download.feature | 2 +- features/core-update.feature | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/features/core-download.feature b/features/core-download.feature index ec2a49695..429125f58 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -68,7 +68,7 @@ Feature: Download WordPress Error: WordPress files seem to already be present here. """ - Scenario: Downgrade from 4.4 to 4.3.2 cleans up files + Scenario: Make sure unused files are cleaned up Given an empty directory When I run `wp core download --version=4.4` Then the wp-includes/rest-api.php file should exist diff --git a/features/core-update.feature b/features/core-update.feature index 72992fcd5..0c13e5c2f 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -159,10 +159,15 @@ Feature: Update WordPress core wordpress-4.2.4-partial-1-en_US.zip """ - Scenario: Downgrade from 4.4 to 4.3.2 cleans up files + Scenario: Make sure unused files are cleaned up Given a WP install When I run `wp core update --version=4.4 --force` Then the wp-includes/rest-api.php file should exist When I run `wp core update --version=4.3.2 --force` Then the wp-includes/rest-api.php file should not exist + + When I run `wp option add str_opt 'bar'` + Then STDOUT should not be empty + When I run `wp post create --post_title='Test post' --porcelain` + Then STDOUT should be a number From c01e19c997d4e8aadd0d1e70e6b128caec7889b8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 18 Jan 2016 05:31:41 -0800 Subject: [PATCH 3990/5359] Faster performance for `wp post list --format=count` When we only want the sum total, we don't need to fetch all data for each post. --- php/commands/post.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/post.php b/php/commands/post.php index b0e9fadf8..1fdafec57 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -312,6 +312,10 @@ public function list_( $_, $assoc_args ) { $query_args['fields'] = 'ids'; $query = new WP_Query( $query_args ); echo implode( ' ', $query->posts ); + } else if ( 'count' === $formatter->format ) { + $query_args['fields'] = 'ids'; + $query = new WP_Query( $query_args ); + $formatter->display_items( $query->posts ); } else { $query = new WP_Query( $query_args ); $posts = array_map( function( $post ) { From e02f7cd76baa135beb5e9c2bd0bc9ff9d0102c2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 18 Jan 2016 07:43:14 -0800 Subject: [PATCH 3991/5359] Generate comments for a specific post with `--post_id=<post-id>` --- features/comment-generate.feature | 16 ++++++++++++++++ php/commands/comment.php | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/features/comment-generate.feature b/features/comment-generate.feature index 609fc257d..e3742ee9a 100644 --- a/features/comment-generate.feature +++ b/features/comment-generate.feature @@ -9,3 +9,19 @@ Feature: Generate comments """ 21 """ + + Scenario: Generate comments assigned to a specific post + Given a WP install + + When I run `wp comment generate --count=4 --post_id=2` + And I run `wp comment list --post_id=2 --format=count` + Then STDOUT should be: + """ + 4 + """ + + When I run `wp comment list --post_id=1 --format=count` + Then STDOUT should be: + """ + 1 + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index 372a5e428..9524d9252 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -96,11 +96,15 @@ public function update( $args, $assoc_args ) { * * [--count=<number>] * : How many comments to generate. Default: 100 + * + * [--post_id=<post-id>] + * : Assign comments to a specific post. */ public function generate( $args, $assoc_args ) { $defaults = array( - 'count' => 100, + 'count' => 100, + 'post_id' => null, ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -112,6 +116,7 @@ public function generate( $args, $assoc_args ) { for ( $i = $total; $i < $limit; $i++ ) { wp_insert_comment( array( 'comment_content' => "Comment {$i}", + 'comment_post_ID' => $assoc_args['post_id'], ) ); $notify->tick(); } From 937c4a623d2a0ffec07b6b5fc054467f5cc7e64f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 18 Jan 2016 09:55:02 -0800 Subject: [PATCH 3992/5359] Use `shortdesc`, `synopsis`, and `when` with `::add_subcommand()` Permits registration of these command attributes through variable, instead of PHPDoc --- features/command.feature | 53 ++++++++++++++++++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 9 ++++ php/WP_CLI/Dispatcher/Subcommand.php | 9 ++++ php/WP_CLI/SynopsisParser.php | 41 +++++++++++++++++ php/class-wp-cli.php | 21 ++++++++- 5 files changed, 132 insertions(+), 1 deletion(-) diff --git a/features/command.feature b/features/command.feature index 525eded94..503fc1407 100644 --- a/features/command.feature +++ b/features/command.feature @@ -199,3 +199,56 @@ Feature: WP-CLI Commands """ Error: Callable ["Foo_Class","bar"] does not exist, and cannot be registered as `wp bar`. """ + + Scenario: Register a synopsis for a given command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + function foo( $args ) { + $message = array_shift( $args ); + WP_CLI::log( 'Message is: ' . $message ); + WP_CLI::success( $args[0] ); + } + WP_CLI::add_command( 'foo', 'foo', array( + 'shortdesc' => 'My awesome function command', + 'when' => 'before_wp_load', + 'synopsis' => array( + array( + 'type' => 'positional', + 'name' => 'message', + 'description' => 'An awesome message to display', + 'optional' => false, + ), + array( + 'type' => 'assoc', + 'name' => 'apple', + 'description' => 'A type of fruit.', + 'optional' => false, + ), + array( + 'type' => 'assoc', + 'name' => 'meal', + 'description' => 'A type of meal.', + 'optional' => true, + ), + ), + ) ); + """ + And a wp-cli.yml file: + """ + require: + - custom-cmd.php + """ + + When I try `wp foo` + Then STDOUT should contain: + """ + usage: wp foo <message> --apple=<apple> [--meal=<meal>] + """ + + When I run `wp help foo` + Then STDOUT should contain: + """ + My awesome function command + """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 7b01e02fe..8ec1f5152 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -99,6 +99,15 @@ public function get_shortdesc() { return $this->shortdesc; } + /** + * Set the short description for this composite command. + * + * @param string + */ + public function set_shortdesc( $shortdesc ) { + $this->shortdesc = $shortdesc; + } + /** * Get the long description for this composite * command. diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 19ecbc3ab..1bba0b605 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -58,6 +58,15 @@ function get_synopsis() { return $this->synopsis; } + /** + * Set the synopsis string for this subcommand. + * + * @param string + */ + public function set_synopsis( $synopsis ) { + $this->synopsis = $synopsis; + } + /** * If an alias is set, grant access to it. * Aliases permit subcommands to be instantiated diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index d4ba77924..f825cc4ef 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -34,6 +34,47 @@ public static function parse( $synopsis ) { return $params; } + /** + * @param array A structured synopsis + * @return string Rendered synopsis + */ + public static function render( $synopsis ) { + if ( ! is_array( $synopsis ) ) { + return ''; + } + $bits = array( 'positional' => '', 'assoc' => '', 'flag' => '' ); + foreach( $bits as $key => &$value ) { + foreach( $synopsis as $arg ) { + if ( empty( $arg['type'] ) + || empty( $arg['name'] ) + || $key !== $arg['type'] ) { + continue; + } + if ( 'positional' === $key ) { + $rendered_arg = "<{$arg['name']}>"; + } else if ( 'assoc' === $key ) { + $rendered_arg = "--{$arg['name']}=<{$arg['name']}>"; + } else if ( 'flag' === $key ) { + $rendered_arg = "--{$arg['name']}"; + } + if ( ! empty( $arg['repeating'] ) ) { + $rendered_arg = "{$rendered_arg}..."; + } + if ( ! empty( $arg['optional'] ) ) { + $rendered_arg = "[{$rendered_arg}]"; + } + $value .= "{$rendered_arg} "; + } + } + $rendered = ''; + foreach( $bits as $v ) { + if ( ! empty( $v ) ) { + $rendered .= $v; + } + } + return rtrim( $rendered, ' ' ); + } + /** * Classify argument attributes based on its syntax. * diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index df0785e73..81ab4a945 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -168,7 +168,10 @@ public static function do_hook( $when ) { * @param string $name The name of the command that will be used in the CLI * @param string $callable The command implementation as a class, function or closure * @param array $args An associative array with additional parameters: - * 'before_invoke' => callback to execute before invoking the command + * 'before_invoke' => callback to execute before invoking the command, + * 'shortdesc' => short description (80 char or less) for the command, + * 'synopsis' => the synopsis for the command (string or array) + * 'when' => execute callback on a named WP-CLI hook (e.g. before_wp_load) */ public static function add_command( $name, $callable, $args = array() ) { $valid = false; @@ -222,6 +225,22 @@ public static function add_command( $name, $callable, $args = array() ) { implode( ' ' , Dispatcher\get_path( $command ) ) ) ); } + if ( isset( $args['shortdesc'] ) ) { + $leaf_command->set_shortdesc( $args['shortdesc'] ); + } + + if ( isset( $args['synopsis'] ) ) { + if ( is_string( $args['synopsis'] ) ) { + $leaf_command->set_synopsis( $args['synopsis'] ); + } else if ( is_array( $args['synopsis'] ) ) { + $leaf_command->set_synopsis( \WP_CLI\SynopsisParser::render( $args['synopsis'] ) ); + } + } + + if ( isset( $args['when'] ) ) { + self::get_runner()->register_early_invoke( $args['when'], $leaf_command ); + } + $command->add_subcommand( $leaf_name, $leaf_command ); } From 16546dbe9f6c4198b8e06783fa15186a11204d17 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 07:39:33 -0800 Subject: [PATCH 3993/5359] Support for generic args; add tests for `::render()` --- php/WP_CLI/SynopsisParser.php | 11 +++++++--- tests/test-synopsis.php | 38 ++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php index f825cc4ef..b79f8a3ff 100644 --- a/php/WP_CLI/SynopsisParser.php +++ b/php/WP_CLI/SynopsisParser.php @@ -42,18 +42,24 @@ public static function render( $synopsis ) { if ( ! is_array( $synopsis ) ) { return ''; } - $bits = array( 'positional' => '', 'assoc' => '', 'flag' => '' ); + $bits = array( 'positional' => '', 'assoc' => '', 'generic' => '', 'flag' => '' ); foreach( $bits as $key => &$value ) { foreach( $synopsis as $arg ) { if ( empty( $arg['type'] ) - || empty( $arg['name'] ) || $key !== $arg['type'] ) { continue; } + + if ( empty( $arg['name'] ) && 'generic' !== $arg['type'] ) { + continue; + } + if ( 'positional' === $key ) { $rendered_arg = "<{$arg['name']}>"; } else if ( 'assoc' === $key ) { $rendered_arg = "--{$arg['name']}=<{$arg['name']}>"; + } else if ( 'generic' === $key ) { + $rendered_arg = "--<field>=<value>"; } else if ( 'flag' === $key ) { $rendered_arg = "--{$arg['name']}"; } @@ -149,4 +155,3 @@ private static function is_repeating( $token ) { } } } - diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php index 427e2ab9b..919227d9e 100644 --- a/tests/test-synopsis.php +++ b/tests/test-synopsis.php @@ -135,5 +135,41 @@ function testAllowedValueCharacters() { $this->assertEquals( 'unknown', $r[3]['type'] ); } -} + function testRender() { + $a = array( + array( + 'name' => 'message', + 'type' => 'positional', + 'description' => 'A short message to display to the user.', + ), + array( + 'name' => 'secrets', + 'type' => 'positional', + 'description' => 'You may tell secrets, or you may not', + 'optional' => true, + 'repeating' => true, + ), + array( + 'name' => 'meal', + 'type' => 'assoc', + 'description' => 'A meal during the day or night.', + ), + array( + 'name' => 'snack', + 'type' => 'assoc', + 'description' => 'If you are hungry between meals, you should snack.', + 'optional' => true, + ) + ); + $this->assertEquals( '<message> [<secrets>...] --meal=<meal> [--snack=<snack>]', SynopsisParser::render( $a ) ); + } + + function testParseThenRender() { + $o = '<positional> --assoc=<assoc> --<field>=<value> [--flag]'; + $a = SynopsisParser::parse( $o ); + $r = SynopsisParser::render( $a ); + $this->assertEquals( $o, $r ); + } + +} From 8d03857a6649072a87a8a1b5b9f698f4591741e4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 07:44:00 -0800 Subject: [PATCH 3994/5359] Add `.editorconfig` to project root based on WPCS --- .editorconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..71f819ca1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# http://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[*.json,*.yml,*.feature] +indent_style = space +indent_size = 2 + From 71fc0927270d2de2ecd6a85ec62ca4a789a3fdea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 09:17:21 -0800 Subject: [PATCH 3995/5359] Use Travis' native file encryption --- .travis.yml | 28 ++++------------------------ ci/deploy.sh | 5 ----- ci/id_rsa.enc | Bin 0 -> 3248 bytes 3 files changed, 4 insertions(+), 29 deletions(-) create mode 100644 ci/id_rsa.enc diff --git a/.travis.yml b/.travis.yml index aa03bd705..80673fcde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,30 +5,6 @@ language: php env: global: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - # Encripted deploy key. See https://gist.github.com/scribu/6241271 - - secure: "U8gOPW2m9fkJW8omnPjFHFZutGIqAAfVs0H1izpSKJhclUfYAGjAGl1Cb6ZiUp3jZE11iWa+fAZ5mmmLAQ5L9ijta40igfFw0s+o/Vt3WBM4a3Vdqpg6civ0rDi9tJYuwtMaEi/kF/yuhKzUT80EAMqVix5xPnf963iIUPyarfY=" - - secure: "W9t7pG5h/Khoi+TrxplpSeTWxaTr7r6cYRVJBsXgghZLDXsU/qn/OhGDdY+IMfSgzO49wjFyLh2EOs8zZSujY75fgFffK2+jd/882NUlpvpXoW9C3yEfZhLJVQZI/1idnpDe9f6zA0XlpBn3bQ2QeS3i2a/JwOGCD8BQjNobk1M=" - - secure: "YsVv3AKeHyr6nwkjhB+VingCdWIzfNP2VYMMHf841rnH6HsAXNw8PJcinnVYeMd15kgjA3Yk8PbITOmzZkf9yjAmbgJTvNempEElF/KG42FkoCACtZ2Wc/jIL9zEi5o47qUicwiS6LLWYx1uQa6vActpE4KdrcDLJ6pQHp/s7ss=" - - secure: "Qsx9+R7VBSdk3st1yVyRMYgAHV58lUUSqXJjvxAkUFXsumCEVFiNpuKepvA5+EZHHnpo7zQOK6EzrIDgUBHGfwEvVumI5eur8G1RKdHnvotuz4D7YCdoRnnrzbhJkAPnVcGrIBIHd5GlDHPTVBij77JwMq5kg2tfKoKcW3RuQTc=" - - secure: "NY3grWJVgnRcA7jQW0/DbPrSkIHVkGxfhdmVSVuSfhsRq5j4kA8/zhWTIwuQ4RtkE88GWye6NarJfjFYnz2KgnCUeaFPFdnB0VE3C3OUeWIsbitjYeqycUd1+JOikPREDZaXjBb79Ve6PGTHv7CUQ+R8vBYSR7eXGqNF9SBDTEw=" - - secure: "XuKAHb35W5vN/JX8iV4FipVdxUH8GbrfheOpOAwgZ0WS5+ua79farr6q73BIPzW8AMAg3p+p1UWNoKLFEaszKuW/mT7dQExsQO04aZ7ESeLbaoKS28EMUCVeOJl0Vo+AxNSruUAIbanvggyAcxq1ILGqH9iaHLpb9BgPei3LdEc=" - - secure: "GSPAeXVhSz5MQ/FRoGFQ7As6a3w/hsq5CslpSCvNz3q7jXUjK+HPzhq3MpWF8sBd6j5IS5YUn1Pl383BDfWj/RYhIzruzIwZhgD+M7VaFFHXcS7y6i9ritXKaw2g4u+16DYQC0zg0jBODXd5NspzyeB6IA5RSecqZeuPW7z/kJc=" - - secure: "BneSPyRBtN8BPNU//rAqFmma0HfVW2GXTgRf/vuTWDnkQ9aE3Uz4S8mlA4lcVpNigvVgRop7MltLVvpWNPDk4tVPu19CkhzKXIEj6Ny6UgD6f4ZHXid/T7I6T50dtJOfcj6leDih92M2JMNaBLPRxOvAUv6yN5FrSV2LNE/0XOw=" - - secure: "URrY5IoJxf40PX+UAldnJK5HZgL5EhJ/n+ildhltyFxDu3E29Ic8Unx89M4Cb09buv1sFBFMC59q3jxck9XOWBsxiRct9y/lvnzI1R1GmVoNiTssg7wLqL6MuD2iy/4fFHFgne2mg7DVDtujCUwTQgtdz7yoh8fQeF/6lBmge1U=" - - secure: "AlNVx6gd7x7lBgrk1Dcna3yfUgdx0wZEdH8V/5NaGirfGMnO7x7ZB1pQ2LVS4EIDCZSELqUCWirFzloJtxOyUJ5AZWCu2YSGzn0cxsHkZDdBsQ1J/oPYpO8PZ9bRBDhGqqqq96F4bPxav1e8G4TH165wBB6MsR1M/He0gPrL57g=" - - secure: "JOvovCe2mKyX6/Ihvqzu93px0RdE/RsNnyDJ6EYTJjFMOhpTP/GTQQcLhMVYq62pM6Ng9/jCQl5VMWEk0f7SGL7X/RW6Rz8HaL1KWy2U9/z67FQPMz+WlJMLTP77PXJouqVemG7Om8Mheg8vMUcgXV1W/vgoljzgeBf1zseQODg=" - - secure: "H7caXIeMS7r6mLuD2aombGuGskD3VwdptcPaY2X/natpMtvHHjbyonUFE26prTWsxFc29wT9Ot705w+yo0DK42SNGaqACpy1tjq6v6xwTCjIIYeGenfnb4FiFjOROCfCXdigJ9ANDS9ufvEd2pgB12BChyLvDVX8pn3FqVzO/wQ=" - - secure: "HbyEWzWOK/dtyYY4J6BcwwCy5EWKzRI1K51Qgsc7nyN6ZlQ4P7vvFmQuLX79zTX9k3PJb58/7Ahl0xQe2mhnpK3awAEuW4ZyqL9CFQnsn7FXAAm7DWcnD8WZvOR0BitiVOEAziuh9dM7FQYBkaq6vSU+Og7NC48osDX/y4PkmG8=" - - secure: "OtXKQFf7ef/1R67U+923TJwx8uafHkhIT3wUmw3QQFkimUDHAH3tPmEk5Qy6a59aMDEO0ESIZdTfwUcMcmfgqhAxNlvmDFSnfOgJmRxzeCD036/sU/8td8VNwRW93iCu48LoGcBfVcP3lM7EJVPK2NGjneBKjna8ekLMcSx8tmE=" - - secure: "G1+MwEPgBswGI3CGtvpwV6ELauqBgBo5b5QLDd44ijqhTOYiUZz5tzU2iKR+5sMm1TqVQjGpSNC/+Hpi4WTKnKCPfKnJh/Z4/859a90GlBytsEGLGK9kAduVeLiJ1T5aOA5lHAhHsWe+CL5+d4LVlFdzBeggcXjJj5+DHHZe7+s=" - - secure: "Z6jHEwZCotrkAvIbj7/fY2fNFvDK6CTZgkpRp+VRdTk8/krWBIBGpTXgSOPXxcx+yNWooRw/mS3sazFQzZ0cv2kqGFtKxTThfAHnWNf2wMlxXvk+FGGGlIOpwt6sB5Eh3N7sF/ZkfioYE66jIVWZg4AiXJ+iEH+DKNFKVrSkwk0=" - - secure: "BzGrbJOSRsuvPrHsSY3zwOn05G9qYq/l8mBltGikRgjMGLEJpH+9+vO5YyCSgS4tDsihSw+SFpNQojS3wDUyNFT7pe0IRnCukletOVp+gwPHdqD8NoEw1gKlWFhgFZNRrc/Ma6bQqPgaQmTV+HKbSM/oAIyW5NKA/+66WTESCrg=" - - secure: "JWzwwyjbZqrCki9ijj75+X2xRS7eLJDahiAS9x87GDz8wbCMuTpWzkA+lbrj5Za3wTRUe5S4wcAELhal2x0CTRO8wUQkxSo2cATN9Bk2p00SJtCBxRJrq2H5QmmYaLIluOmyIQNDpaNS/O+TQGgUCpVg2x8KzqgiCYYGXewgJ1g=" - - secure: "g1QgDqGFAYJqxv3qyT2tQplT62o/3xA19SAjO4sAzgEp8t/h6J9K+ehbyz3tlsGJhOP/b7VGyjvnUKLZ+4BlaRhSsS1TND753+YhWGD2PKhIZ58hdW4m4ARY0yrRkVFMQqEyyIj8D+TBC713yDc58L/tmehf8ZljZpFG2PICidE=" - - secure: "Gj9fw1wM3dfgZab0XqULeR9loDj9Gsa99z8bPgfAEWS7cWqoTitF2Y9SolUX1WZyOJUZ+5Shrl7jnihl8EOlm13wxt680Kmt7jTVX5DUH+NvzWVwkYDrZV7zSFayYZJTdx3FjEvSs+GIVrpzBeBvVFvCTQUuIphPkbxwR0JHonI=" - - secure: "XS4lJJSZ2+4rB+zkt9lsdhG+pZEQ6nUjRSdLcVAgS7f7yvFCOjJYWRXlQ5zP/Gl3/XVe/L8EuGLYZsztauLSd6Ob7nEwnb5vIegLaqzbZd7Yizp9TnBj0AFCqo/ZPY+ZhnURY9OLFqknfQMWhrTeVvGRT94nhnnIF+sxokQgv0M=" - - secure: "TVMYSuxuZojZUHn3R9me8FCA1V6RaOTNE6A5gta7LSTtqZFLAQOer6tfLVof5fB3SHh2ANcOYPpjO729Mcrg195p1I/0nS18WZ0BVYvsN0Dob1I79rqYvsaW8syxCd/6TZvr7XZYdd1fDtt7kxsv74SljkliYwI2mTniQDxMONE=" - - secure: "OqbgLy6Rn+NvhjpYygNZDWf6rj8sVejRZJBmssNi5fHRXopEtfIHids2FjSXZUVPs3ShqNuczo1jzgt7N3JHbcSaiedHlc7ONqDK0SyyOcsv1oKOR81bvYcL/KIoGiMRvkQI5IW01YWfSZlS0wgL2NYdJvYanCnSUUv6nNZAF7E=" matrix: include: @@ -43,6 +19,10 @@ matrix: - php: 7.0 env: WP_VERSION=latest +before_install: + - openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in ci/id_rsa.enc -out ~/.ssh/id_rsa -d + - chmod 600 ~/.ssh/id_rsa + before_script: ./ci/prepare.sh script: ./ci/test.sh diff --git a/ci/deploy.sh b/ci/deploy.sh index 893920836..7e74e0299 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,11 +12,6 @@ if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then exit fi -# extract private key from decrypted environment variables stored in .travis.yml -echo -n $id_rsa_{00..30} >> ~/.ssh/id_rsa_base64 -base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa -chmod 600 ~/.ssh/id_rsa - # anyone can read the build log, so it MUST NOT contain any sensitive data set -x diff --git a/ci/id_rsa.enc b/ci/id_rsa.enc new file mode 100644 index 0000000000000000000000000000000000000000..dc8ca5344be0d6a3492af863046de37e7f9f0db5 GIT binary patch literal 3248 zcmV;h3{Ufn&B$YxQhT5yUa!Tbn-L%Boi&hD-pD{=!p6OkNE^*m-Z&Nk@;ZX??lv|Q z%J-}A-?QmB@P8Kvc?-v|xNX56-^jJ``yFusQZng9){=cRK=C+N&RGG<w$gx+37WY9 z=YFnG;O$?ZfNy$K<DAirsm!3=2X2=ubp{Q<pPc@(bkd@bFyhn5rb60{h7`ZFN^f7| zV@EzRiW?p$|71Flhpthrc{Mt{h{6bT$AjC(^Br?n>Ea?oc7Moe)t;7ZtzJO7(f>(W zQ`7;Sk^=~n?TRiZ+*iUa-5k!vI9L`Hy7hBqQ-8`2sbYK#S;&3gi<q&3gkkh?Gu?^V zCi{SDOt#6OM6PoYQSd-B0eNfm7FhSo)Nj^sX9Y*Fr2>SW#h!+jQy&#}=BpG3xxW`` zWo}50PS_h-Vs|+N_joDm|I+*w8G_TQuq1#!3(0zj<j9VAPjr?-na4AFdty+eJg9e4 zY#M-E-&tFXcvr{_>xVlS)<fWXldtIT9fh*4C|1GCdb58r0UC1PT`0a>u%}U40la)T z`__K)x!btEOLLx62&X~J#&x9)aO6n7_Q(yl3(n~KzK;c}0~xm8-JB6QTc}uGwkQRX z-ws<Op*@~U@g6*QseeM&<UV<{T27hW!yI0V+^kW>^(xdW&9%Rf!c7LgA$(wVGXNk( z(}wa4W#x}I?lg8krb<($x<I>=5(y4JQoQR|9%G(iI!%($n=hCsjA;@nt<os$cO_@X z6*LXD8RPS4PaC<N!gRygC$n>vQ?!zxz*m4|Lt3yaH1B}Ph!HGeWwTp&-l}Tiac{xn zg-qjet)Z%75$9596tZ0(ICXd|mY=H{otu);Yz&U9W>(VG@#lU&>d*zRcp0^4#5acB zs_Q}XBj@PB-aNZpl4X$zFTNK;0Py%abdFF*U!jqT{g?7890bCmUtt0lNv8q<c>ZqO zQ*+^eh{m9ht%%t)mB24gO?oAsDxU&EeAoHsizoedugP!&GKYxIgxg2TE0pX0_-S(} zy;DX=u`_PCgNn~NshcRU&VER5sLo4viDUD{V(v&pmN4g^YkaI_jy9Xl-etM_J($D7 z(W`NWM^qc4^X?^J(@)oKGOfw}j8gRX=cJMyWZuH_{2&!(O3W8JQ19NCdg`U<-2eHf zK*C(88`*9hctpP%!*^`!Gd~~V%zzLQq*;j!#4}1Bm6xs*WKnIshKebcW36N9mhv&N zCKmJ1{OFt#Jh@&5FuF@_e<enb2HzUig<|kaAST%e4Y6jUOUQ32PL5+7e}C*W&5*CZ zVwVgoA?_4+jV1O&$Zt-Z4LAk*?U#E_Lm+52P65w4T^DPsfio|8Y^l47l(GEJL{v!v z&E_iaKU&&)L?mXXEn-2%KYnoHX;2O_&VqWcpxF<7;%T6s|EODs$j}<coPJX;CvpF3 z@gZD_y2SXe&AgT`7M`l3dt%oVDQb9&Mk=Ed?n&}YmXwZ)aLD@JgMK|;E&_HTk`%Sw zCOJdks-w5nisR}4n8EscjsV;jhQrY>oc)uf1zUSbWOkjvKAZ1=hB<xgcJ>`fFKj81 z<<-qF98`&_C=Nr*$RY6u$w+@00E|og$5yU+kA{?UBMdn+j8nS0#<IK9kl87HQ4E$( zsU=f8?3Eu|JathRfnzNEYT25X`?1h5-xG`oNMPpH&UL?2ccRNfnh$6&2#UXhWx}4n zigJ@rDuJb+Yp-kUEWgF{XtG83F_UFDL^4+(*6?;pb-JRgA6E7H0+^bEb1j57tBI}T zjWGvG(&n093589sYV#DJJ&oz>ToUtuB$1VjUHX8=E_8*)9-M-TRCe_w3h4f;U&g=R zTmlZ!2TiI%f#tb&z8f^7d<7;M91!XJ+zl(bb+Nyen}Ief0ZsnTR+d1@UzW2@_Ck?b zq0?m0EFqV+;#dUt+Joh+0<THjy`31)v@|f6ddHfa9swl6(*1>O&dbLfdu#i~7lUfX zqH5YH2=PNp==o}Yruv4+X>Qxp1QQfd^Q$77i97n1TLTZQ49H$bPJ7UU?5E@ViCBA_ z-{Q?x($Lbr{kU@2aG6Kp6~(3IQW9N$+PGr<dt?27u@oiU$%HH&4&2N_`8+8pX}|KP zluf0TNyERk09!!G7vMPIXL2CFX_jfo&04lhXFho1KDHvazcqvtxSQeEm>d+SAyJF~ ze$m2%Vn+RmK~`Xc3s&KZ{jf?tAJAlYw(IaEmDC*9LX2Wat_?jfpgY7}4(dBP<;9`` zV|RqR{!yvpjWaJ=@3RaZ9HHmU&SdnF2v2t;rYK}B(|`js!do(9;TooFdk9~Ap(6%r zr9SLnTurWyW#ifQH2JAAZ#Sk7F#^v!l1?;eYQ+H}qh+s2)sLmJ-Kg(6fUU+e#?}J{ zG(P9rym2i|fbgBwocfF%`b}C>!@GBv7t>cyv@6QsW}2>#h}Hg>nDvwx_7n#?&wczC z?U`Gv=EqMfP&#OUA}5$tJv{zCuw<L+ww&TqEO1O_|CdF&JXx?8&u*;V@RSIMi)zDQ za-g15|1nXJt~d&J#z@v&W#P>2_wPz`@voOen4#AbC+r0E`lW|ESP$4j_j!S(>6&7E z258^vVw%SBa)hF41R;x2Fji`bJugL3?tppx<m$4pf)kN0Xej_l<DZPI!fAY3=VyOT ze?Fb|p3SkTOijl*e34i04D=|Pisk$p1W$0)doCsol5KTlL=-7G?_n(mJn8IJClHK* z6Y3_Nm~G{E!0#&TmK4EwM$E)oKp}7QU#C;#R+Bv)@=vM-k~RLER5R*AP@2xhf)vrP zXmG3uE$Tf6n{ni=5;*4EyQ52tywpu<2aZJJW&NDgpZumoEB38|ASIA?)t{N{E?_t( zr-vomgDs8ZVQU?UE4vPM^~%eK?{-1+2T~|x74`2M)|k1=Rpx3|Y7MPTqw2px#|lsi zf6c@jMV}ydBMWD=ZbE~Jkbaz@4mnT-kFP$a+ht?A`3A4Ec3PCxp07J<HdhJzSmw6x zOTc?rREJK30*f~tnMh(h<Ikzkc?VL(j2`~jNR%8jj%KBy9+jqvL@=-q@&754(bF^o zm(tl*`9+_ev~q)rpPKwI8KXe=rX44FV6nV+Cr<i{suDp+0Z-TiGSZ_5lr=cgdz6h$ zqyPP`k2fF#4}T#b;+ZuE9(kzZd6!g$nJeD+LR#rQJYouUrwTv3w^6&maMRs3E%fdE z#)5*B7Aot8_QSJ+fkgboq)3qbVPQ0=ef@?>p|5i>Wff_vMO^0izYYykLrjkaO0< z{QdO#++21_d^+j3$5`fm-f>J`ZfJe`G|rD7p-}T%98J>AZSvuq?vnvw+~8N(<ZsPi zvxx%K@`7f0=SAQCkuD^)j>C1h3#3a8>rkPTulj@$%@Hmz(uB=mKW%TTu3%}wa#J^P zPFifyt*gJ7cafU5sR=f=xTl;LG%hg>H{R|@`GR#}U-QUpdl8o4=B=QgXA?~F=TQv* zZs-Z;3@%&SK`eAG5MW_~k>vZ4kwF$d1)lyhd<pc4&{pYb(IGHEUSGlck!D3BHolz( zsm%6Gu&Mo`i#!3CCiY`D(_h=c$1<Q%?=b8`sUwV6n=Mg3FCtshpQ<kXJUAAm-d{b| zPV<jg(10tzxEwE|Q6&<(6_M6<qb8n#SG&a4hVlpf7M-KvK9EgeZDuFc{w{ieQ}s7+ z`C8?5L<0%hZry+{M-<UkH_{<1{{XYHgpw>onkO0QLB=ms2HmH*#e(FyD+^W*q=4M* z8BU8~td8NjCBF@k@oOFqi@bf5^YApVx*LR03s|o9Y;1=v`NYJDP;NtD^_;U~<Y#>{ zArwMUa(BHj)8q%bj@7o+0Q#bakYmq}zKxEwon$_aLo==<6G=@xpj#C?_y<>QQSd(N zXsa3>y;W*IDy705-d5&bsW-=m5PW#;c&1UgUg))Ze<jR<SiAquKZ8e#8rrfkv;a;m z(a=c`YFi#7&(~9`&j7J;O9t^f6Sk*sb$upa)=k}*Z<Ie6+xP!;!z-_S^^<~q-$F{k zupe!&`K)x@%`N2Qsp@PUUtVI6IEkDkDYS&A^QexFyWqg`+MLE9fA}?F4D!wEKRc%4 zqK!0pD+5RMjx2knF*rTm#va6nR`j_Ck~fCyIDxG#O5~Zkg}!h673`yjxNH)tuv(^| zmT0J^iB(!Rn=RlWUG9OlZ0K@5tp%0fA?WL0RtPvHj~!s3k!-r#J5H>(O|ZOsyLQQc iBGT$y^M*Jdj#$oo>AL9zZL$4BtMaF|@s2JZIh$gQs$-A< literal 0 HcmV?d00001 From 35e6ade79b3dff7a023407ef56f1643b2ebd48a9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 12:38:07 -0800 Subject: [PATCH 3996/5359] In `WP_CLI::error_to_string()`, `json_encode()` `WP_Error` data Data is typically an array. Giving us a flattened array is more helpful than indicating "Array" --- php/class-wp-cli.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 81ab4a945..536ee0621 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -401,10 +401,11 @@ public static function error_to_string( $errors ) { if ( is_object( $errors ) && is_a( $errors, 'WP_Error' ) ) { foreach ( $errors->get_error_messages() as $message ) { - if ( $errors->get_error_data() ) - return $message . ' ' . $errors->get_error_data(); - else + if ( $errors->get_error_data() ) { + return $message . ' ' . json_encode( $errors->get_error_data() ); + } else { return $message; + } } } } From ccb66073ab6203422b9ea5ea0e864f04fe4b7427 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 12:52:15 -0800 Subject: [PATCH 3997/5359] Persist object when using `WP_CLI::add_command()` with class method This permits an instance to be shared between commands, or be instantiated with additional data. --- php/WP_CLI/Dispatcher/CommandFactory.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index 274d53201..bd3874117 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -24,7 +24,7 @@ public static function create( $name, $callable, $parent ) { $command = self::create_subcommand( $parent, $name, $callable, $reflection ); } else if ( is_array( $callable ) && is_callable( $callable ) ) { $reflection = new \ReflectionClass( $callable[0] ); - $command = self::create_subcommand( $parent, $name, array( $reflection->name, $callable[1] ), + $command = self::create_subcommand( $parent, $name, array( $callable[0], $callable[1] ), $reflection->getMethod( $callable[1] ) ); } else { $reflection = new \ReflectionClass( $callable ); @@ -62,7 +62,8 @@ private static function create_subcommand( $parent, $name, $callable, $reflectio $when_invoked = function ( $args, $assoc_args ) use ( $callable ) { if ( is_array( $callable ) ) { - call_user_func( array( new $callable[0], $callable[1] ), $args, $assoc_args ); + $callable[0] = is_object( $callable[0] ) ? $callable[0] : new $callable[0]; + call_user_func( array( $callable[0], $callable[1] ), $args, $assoc_args ); } else { call_user_func( $callable, $args, $assoc_args ); } From 034170ce528e3f7dd5989a004e23e6bea18c9146 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 19 Jan 2016 13:00:17 -0800 Subject: [PATCH 3998/5359] Add a test to cover two different types of passing classes --- features/command.feature | 53 ++++++++++++++++++++++++++++++++++++++-- php/class-wp-cli.php | 3 ++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/features/command.feature b/features/command.feature index 503fc1407..c73f90622 100644 --- a/features/command.feature +++ b/features/command.feature @@ -132,6 +132,10 @@ Feature: WP-CLI Commands """ <?php class Foo_Class extends WP_CLI_Command { + + public function __construct( $prefix ) { + $this->prefix = $prefix; + } /** * My awesome class method command * @@ -141,10 +145,10 @@ Feature: WP-CLI Commands * @when before_wp_load */ function foo( $args ) { - WP_CLI::success( $args[0] ); + WP_CLI::success( $this->prefix . ':' . $args[0] ); } } - $foo = new Foo_Class; + $foo = new Foo_Class( 'boo' ); WP_CLI::add_command( 'foo', array( $foo, 'foo' ) ); """ @@ -166,6 +170,51 @@ Feature: WP-CLI Commands unknown --burrito parameter """ + When I run `wp --require=custom-cmd.php foo bar` + Then STDOUT should contain: + """ + Success: boo:bar + """ + + Scenario: Use a class method as a command + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Foo_Class extends WP_CLI_Command { + /** + * My awesome class method command + * + * <message> + * : An awesome message to display + * + * @when before_wp_load + */ + function foo( $args ) { + WP_CLI::success( $args[0] ); + } + } + WP_CLI::add_command( 'foo', array( 'Foo_Class', 'foo' ) ); + """ + + When I run `wp --require=custom-cmd.php help` + Then STDOUT should contain: + """ + foo + """ + + When I run `wp --require=custom-cmd.php help foo` + Then STDOUT should contain: + """ + My awesome class method command + """ + + When I try `wp --require=custom-cmd.php foo bar --burrito` + Then STDERR should contain: + """ + unknown --burrito parameter + """ + When I run `wp --require=custom-cmd.php foo bar` Then STDOUT should contain: """ diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 81ab4a945..1c2f84e8f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -188,7 +188,8 @@ public static function add_command( $name, $callable, $args = array() ) { } if ( ! $valid ) { if ( is_array( $callable ) ) { - $callable = array( get_class( $callable[0] ), $callable[1] ); + $callable[0] = is_object( $callable[0] ) ? get_class( $callable[0] ) : $callable[0]; + $callable = array( $callable[0], $callable[1] ); } WP_CLI::error( sprintf( "Callable %s does not exist, and cannot be registered as `wp %s`.", json_encode( $callable ), $name ) ); } From cba6d73fe0ff5e299c4536d72f29c4cc0d448845 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Wed, 20 Jan 2016 10:05:46 +0000 Subject: [PATCH 3999/5359] Remove WPINC check --- php/commands/core.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 87bc9904d..6b715deb8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -100,10 +100,9 @@ public function download( $args, $assoc_args ) { } $from_version = ''; - $includes_folder = defined( 'WPINC' ) ? WPINC : 'wp-includes'; - if ( file_exists( $download_dir . $includes_folder . '/version.php' ) ) { + if ( file_exists( $download_dir . 'wp-includes/version.php' ) ) { global $wp_version; - require_once( $download_dir . $includes_folder . '/version.php' ); + require_once( $download_dir . 'wp-includes/version.php' ); $from_version = $wp_version; } From 99e6488e496c82c1248138abdb690f02efabec9b Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Wed, 20 Jan 2016 10:06:00 +0000 Subject: [PATCH 4000/5359] Rename method --- php/commands/core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 6b715deb8..726c8581f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -150,7 +150,7 @@ public function download( $args, $assoc_args ) { unlink($temp); } - $this->remove_unused_files( $from_version, $assoc_args['version'], $locale ); + $this->cleanup_extra_files( $from_version, $assoc_args['version'], $locale ); WP_CLI::success( 'WordPress downloaded.' ); } @@ -980,7 +980,7 @@ function update( $args, $assoc_args ) { unset( $GLOBALS['wp_cli_update_obj'] ); $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); - $this->remove_unused_files( $from_version, $update->version, $locale ); + $this->cleanup_extra_files( $from_version, $update->version, $locale ); if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); @@ -1164,7 +1164,7 @@ private function get_updates( $assoc_args ) { return array_values( $updates ); } - private function remove_unused_files( $version_from, $version_to, $locale ) { + private function cleanup_extra_files( $version_from, $version_to, $locale ) { if ( ! $version_from || ! $version_to ) { WP_CLI::warning( 'Failed to find WordPress version. Please cleanup unused files manually.' ); return; From 2e49124bb5ab27aa7aa501e764cbd576fedd51c9 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Wed, 20 Jan 2016 10:06:24 +0000 Subject: [PATCH 4001/5359] Cleanup language --- php/commands/core.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 726c8581f..5ca76bdf2 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1166,7 +1166,7 @@ private function get_updates( $assoc_args ) { private function cleanup_extra_files( $version_from, $version_to, $locale ) { if ( ! $version_from || ! $version_to ) { - WP_CLI::warning( 'Failed to find WordPress version. Please cleanup unused files manually.' ); + WP_CLI::warning( 'Failed to find WordPress version. Please cleanup files manually.' ); return; } @@ -1174,14 +1174,14 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { $new_checksums = self::get_core_checksums( $version_to, $locale ? $locale : 'en_US' ); if ( empty( $old_checksums ) || empty( $new_checksums ) ) { - WP_CLI::warning( 'Failed to fetch checksums. Please cleanup unused files manually.' ); + WP_CLI::warning( 'Failed to fetch checksums. Please cleanup files manually.' ); return; } $files_to_remove = array_diff( array_keys( $old_checksums ), array_keys( $new_checksums ) ); if ( ! empty( $files_to_remove ) ) { - WP_CLI::log( 'Cleaning up unused files...' ); + WP_CLI::log( 'Cleaning up files...' ); $count = 0; foreach ( $files_to_remove as $file ) { @@ -1193,7 +1193,7 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { } if ( $count ) { - WP_CLI::success( number_format( $count ) . ' unused files cleaned up' ); + WP_CLI::log( number_format( $count ) . ' files cleaned up' ); } } } From 439427c323c41f1a5014450bf12f8042f0d87786 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Wed, 20 Jan 2016 10:07:03 +0000 Subject: [PATCH 4002/5359] Add message when no files found --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 5ca76bdf2..21bb1ec27 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1194,6 +1194,8 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { if ( $count ) { WP_CLI::log( number_format( $count ) . ' files cleaned up' ); + } else { + WP_CLI::log( 'No files found that need cleaned up' ); } } } From 196c8f30adca70a04e3c52c3af2b490200b461e3 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Wed, 20 Jan 2016 10:07:12 +0000 Subject: [PATCH 4003/5359] Update tests --- features/core-download.feature | 4 +++- features/core-update.feature | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/features/core-download.feature b/features/core-download.feature index 429125f58..9e3eaace6 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -68,10 +68,12 @@ Feature: Download WordPress Error: WordPress files seem to already be present here. """ - Scenario: Make sure unused files are cleaned up + Scenario: Make sure files are cleaned up Given an empty directory When I run `wp core download --version=4.4` Then the wp-includes/rest-api.php file should exist + Then the wp-includes/class-wp-comment.php file should exist When I run `wp core download --version=4.3.2 --force` Then the wp-includes/rest-api.php file should not exist + Then the wp-includes/class-wp-comment.php file should not exist diff --git a/features/core-update.feature b/features/core-update.feature index 0c13e5c2f..2b97dd73c 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -159,13 +159,26 @@ Feature: Update WordPress core wordpress-4.2.4-partial-1-en_US.zip """ - Scenario: Make sure unused files are cleaned up + Scenario: Make sure files are cleaned up Given a WP install When I run `wp core update --version=4.4 --force` Then the wp-includes/rest-api.php file should exist + Then the wp-includes/class-wp-comment.php file should exist When I run `wp core update --version=4.3.2 --force` Then the wp-includes/rest-api.php file should not exist + Then the wp-includes/class-wp-comment.php file should not exist + Then STDOUT should contain: + """ + File removed: wp-includes/class-walker-comment.php + File removed: wp-includes/class-wp-network.php + File removed: wp-includes/embed-template.php + File removed: wp-includes/class-wp-comment.php + File removed: wp-includes/class-wp-http-response.php + File removed: wp-includes/class-walker-category-dropdown.php + File removed: wp-includes/rest-api.php + 150 files cleaned up + """ When I run `wp option add str_opt 'bar'` Then STDOUT should not be empty From 8524ed20d25ac68a6955b1774a832a3a1cda5cd8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jan 2016 06:51:54 -0800 Subject: [PATCH 4004/5359] Only decrypt on deploys, when the key is present --- .travis.yml | 4 ---- ci/deploy.sh | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80673fcde..7d2d6bba5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,10 +19,6 @@ matrix: - php: 7.0 env: WP_VERSION=latest -before_install: - - openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in ci/id_rsa.enc -out ~/.ssh/id_rsa -d - - chmod 600 ~/.ssh/id_rsa - before_script: ./ci/prepare.sh script: ./ci/test.sh diff --git a/ci/deploy.sh b/ci/deploy.sh index 7e74e0299..b289940fd 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,6 +12,9 @@ if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then exit fi +openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in id_rsa.enc -out ~/.ssh/id_rsa -d +chmod 600 ~/.ssh/id_rsa + # anyone can read the build log, so it MUST NOT contain any sensitive data set -x From b361f359a2a1e5be693b3715f35fafd829138cbf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jan 2016 07:22:56 -0800 Subject: [PATCH 4005/5359] Script is run from project root --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index b289940fd..9f942dffc 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,7 +12,7 @@ if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then exit fi -openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in id_rsa.enc -out ~/.ssh/id_rsa -d +openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in ci/id_rsa.enc -out ~/.ssh/id_rsa -d chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data From e0b593e3135ce3bcb3594b2820be274b8078f151 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jan 2016 08:05:46 -0800 Subject: [PATCH 4006/5359] Revert "Revert "Permit failures on trunk"" This reverts commit e86e4a11465bf7b04d43c7f27876b245a12b8b03. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7d2d6bba5..ab26ba81a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,8 @@ matrix: env: WP_VERSION=trunk - php: 7.0 env: WP_VERSION=latest + allow_failures: + - env: WP_VERSION=trunk before_script: ./ci/prepare.sh From 1d86cb6879cd42fd03ac6371251cbe1844f1da38 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jan 2016 14:02:38 -0800 Subject: [PATCH 4007/5359] Failing test case for scaffolding a plugin with prompting --- features/scaffold.feature | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index f2653bec2..635cd4144 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -124,6 +124,43 @@ Feature: WordPress code scaffolding node_modules/ """ + Scenario: Scaffold a plugin by prompting + Given a WP install + And a session file: + """ + hello-world + + Hello World + An awesome introductory plugin for WordPress + WP-CLI + http://wp-cli.org + http://wp-cli.org + n + Y + n + n + """ + + When I run `wp scaffold plugin --prompt < session` + Then STDOUT should not be empty + And the wp-content/plugins/hello-world/hello-world.php file should exist + And the wp-content/plugins/hello-world/readme.txt file should exist + And the wp-content/plugins/hello-world/tests directory should exist + + When I run `wp plugin status hello-world` + Then STDOUT should contain: + """ + Status: Active + """ + And STDOUT should contain: + """ + Name: Hello World + """ + And STDOUT should contain: + """ + Description: An awesome introductory plugin for WordPress + """ + Scenario: Scaffold a plugin and activate it Given a WP install When I run `wp scaffold plugin hello-world --activate` From 9874ecc5070c613cb596a7c8991bda02e363f9ad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jan 2016 14:03:13 -0800 Subject: [PATCH 4008/5359] Only prompt for the first command in the execution thread Some WP-CLI commands call other WP-CLI commands, and can produce erroneous results when they prompt a second time. --- php/WP_CLI/Dispatcher/Subcommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1bba0b605..202d51e73 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -288,8 +288,11 @@ private function validate_args( $args, $assoc_args, $extra_args ) { * @param array $assoc_args */ public function invoke( $args, $assoc_args, $extra_args ) { - if ( \WP_CLI::get_config( 'prompt' ) ) + static $prompted_once = false; + if ( \WP_CLI::get_config( 'prompt' ) && ! $prompted_once ) { list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); + $prompted_once = true; + } $to_unset = $this->validate_args( $args, $assoc_args, $extra_args ); From a9b2021b622a15ffe248d94a04a28f9ea25a9546 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Thu, 21 Jan 2016 16:31:15 +0000 Subject: [PATCH 4009/5359] Remove file count --- features/core-update.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/core-update.feature b/features/core-update.feature index 2b97dd73c..a1ac048b1 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -177,7 +177,6 @@ Feature: Update WordPress core File removed: wp-includes/class-wp-http-response.php File removed: wp-includes/class-walker-category-dropdown.php File removed: wp-includes/rest-api.php - 150 files cleaned up """ When I run `wp option add str_opt 'bar'` From 326c3bb2b86ea2639c38d1585fc09dc8d1c06d35 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 21 Jan 2016 10:31:51 -0800 Subject: [PATCH 4010/5359] Introduce a dedicated job for testing Git clone installation --- .travis.yml | 6 ++---- ci/prepare.sh | 15 +++++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab26ba81a..e0174c6cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,6 @@ sudo: false language: php -env: - global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - matrix: include: - php: 5.3 @@ -14,6 +10,8 @@ matrix: env: WP_VERSION=3.7.11 - php: 5.6 env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=latest BUILD=git - php: 5.6 env: WP_VERSION=trunk - php: 7.0 diff --git a/ci/prepare.sh b/ci/prepare.sh index a279e3158..a64af0f67 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -15,10 +15,17 @@ then fi # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR -mkdir -p $WP_CLI_BIN_DIR -php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet --version=$CLI_VERSION -mv wp-cli.phar $WP_CLI_BIN_DIR/wp -chmod +x $WP_CLI_BIN_DIR/wp +if [[ $BUILD == 'git' ]] +then + export WP_CLI_BIN_DIR=bin/wp + echo $CLI_VERSION > VERSION +else + export WP_CLI_BIN_DIR=/tmp/wp-cli-phar + mkdir -p $WP_CLI_BIN_DIR + php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet --version=$CLI_VERSION + mv wp-cli.phar $WP_CLI_BIN_DIR/wp + chmod +x $WP_CLI_BIN_DIR/wp +fi # Install CodeSniffer things ./ci/prepare-codesniffer.sh From 23c2dbae64640a38bea7d6e78935c77de5f38e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= <otto@seravo.fi> Date: Fri, 22 Jan 2016 15:23:48 +0200 Subject: [PATCH 4011/5359] Mention MariaDB in docs to clarify that WP-CLI works with it too --- CONTRIBUTING.md | 4 ++-- features/search-replace.feature | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 292dd1b8e..415dc8c24 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ To run the unit tests, just execute: The functional test files are in the `features/` directory. -Before running the functional tests, you'll need a MySQL user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: +Before running the functional tests, you'll need a MySQL (or MariaDB) user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: ```sql GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; @@ -62,7 +62,7 @@ Then, to run the entire test suite: Or to test a single feature: -```bash +```bash ./vendor/bin/behat features/core.feature ``` diff --git a/features/search-replace.feature b/features/search-replace.feature index eb0783361..0f98c95dc 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -249,7 +249,7 @@ Feature: Do global search/replace | http://newdomain.com | | | http://newdomain.com | --dry-run | - Scenario Outline: Choose replacement method (PHP or MySQL) given proper flags or data. + Scenario Outline: Choose replacement method (PHP or MySQL/MariaDB) given proper flags or data. Given a WP install And I run `wp option get siteurl` And save STDOUT as {SITEURL} From b1f3e820c45451e42dab1988c9ec1cbde5bb36c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 22 Jan 2016 09:38:21 -0800 Subject: [PATCH 4012/5359] Failing test case for not cleaning up wp-content --- features/core-download.feature | 8 ++++++++ features/core-update.feature | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/features/core-download.feature b/features/core-download.feature index 9e3eaace6..38ebaa5bf 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -73,7 +73,15 @@ Feature: Download WordPress When I run `wp core download --version=4.4` Then the wp-includes/rest-api.php file should exist Then the wp-includes/class-wp-comment.php file should exist + And STDOUT should not contain: + """ + File removed: wp-content + """ When I run `wp core download --version=4.3.2 --force` Then the wp-includes/rest-api.php file should not exist Then the wp-includes/class-wp-comment.php file should not exist + And STDOUT should not contain: + """ + File removed: wp-content + """ diff --git a/features/core-update.feature b/features/core-update.feature index a1ac048b1..6565f026b 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -164,6 +164,10 @@ Feature: Update WordPress core When I run `wp core update --version=4.4 --force` Then the wp-includes/rest-api.php file should exist Then the wp-includes/class-wp-comment.php file should exist + And STDOUT should not contain: + """ + File removed: wp-content + """ When I run `wp core update --version=4.3.2 --force` Then the wp-includes/rest-api.php file should not exist @@ -178,6 +182,10 @@ Feature: Update WordPress core File removed: wp-includes/class-walker-category-dropdown.php File removed: wp-includes/rest-api.php """ + And STDOUT should not contain: + """ + File removed: wp-content + """ When I run `wp option add str_opt 'bar'` Then STDOUT should not be empty From f616e58315eec91512de8b5a2fd00b99147fafac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 22 Jan 2016 09:40:19 -0800 Subject: [PATCH 4013/5359] Don't ever clean up wp-content with `wp core update` or `wp core download` --- php/commands/core.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 21bb1ec27..efcd6875c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1185,6 +1185,12 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { $count = 0; foreach ( $files_to_remove as $file ) { + + // wp-content should be considered user data + if ( 0 === stripos( $file, 'wp-content' ) ) { + continue; + } + if ( file_exists( ABSPATH . $file ) ) { unlink( ABSPATH . $file ); WP_CLI::log( 'File removed: ' . $file ); From 82532c01b2cca1da1ecd15abee03062a2b264e10 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 24 Jan 2016 13:33:58 -0800 Subject: [PATCH 4014/5359] Only display `$shortdesc` in man doc when present. Sometimes there may not be a short description available. --- templates/man.mustache | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/man.mustache b/templates/man.mustache index a42acbcc3..ea1ec7b93 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -2,10 +2,12 @@ {{name}} +{{#shortdesc}} ## DESCRIPTION {{shortdesc}} +{{/shortdesc}} ## SYNOPSIS {{synopsis}} From 515bb24012cdaecbc1b4253d59c9e424c3fe5eb3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jan 2016 11:27:48 -0800 Subject: [PATCH 4015/5359] Don't `exit` on premature success for `wp theme activate` This can kill other scripts calling the method directly. `return` is fine for our needs to stop command execution. --- php/commands/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 59f5fd20e..3f78830c1 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -131,7 +131,7 @@ public function activate( $args = array() ) { if ( 'active' === $this->get_status( $theme ) ) { WP_CLI::success( "The '$name' theme is already active." ); - exit; + return; } if ( $theme->get_stylesheet() != $theme->get_template() && ! $this->fetcher->get( $theme->get_template() ) ) { From db2c514421a0e3554b76f2846345fd2324f44e36 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jan 2016 16:49:36 -0800 Subject: [PATCH 4016/5359] Only clean up `wp core download` when WP was already present If we're downloading to an empty directory, skip the operation. --- features/core-download.feature | 4 ++-- php/commands/core.php | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/features/core-download.feature b/features/core-download.feature index 38ebaa5bf..f35c49f56 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -73,9 +73,9 @@ Feature: Download WordPress When I run `wp core download --version=4.4` Then the wp-includes/rest-api.php file should exist Then the wp-includes/class-wp-comment.php file should exist - And STDOUT should not contain: + And STDERR should not contain: """ - File removed: wp-content + Warning: Failed to find WordPress version. Please cleanup files manually. """ When I run `wp core download --version=4.3.2 --force` diff --git a/php/commands/core.php b/php/commands/core.php index efcd6875c..c8659f505 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -75,8 +75,9 @@ function check_update( $_, $assoc_args ) { public function download( $args, $assoc_args ) { $download_dir = ! empty( $assoc_args['path'] ) ? $assoc_args['path'] : ABSPATH; + $wordpress_present = is_readable( $download_dir . 'wp-load.php' ); - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && is_readable( $download_dir . 'wp-load.php' ) ) + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && $wordpress_present ) WP_CLI::error( 'WordPress files seem to already be present here.' ); if ( !is_dir( $download_dir ) ) { @@ -150,7 +151,9 @@ public function download( $args, $assoc_args ) { unlink($temp); } - $this->cleanup_extra_files( $from_version, $assoc_args['version'], $locale ); + if ( $wordpress_present ) { + $this->cleanup_extra_files( $from_version, $version, $locale ); + } WP_CLI::success( 'WordPress downloaded.' ); } From 7a75432280b668b9bc2fac26724e5d37914a8993 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Tue, 26 Jan 2016 10:01:41 -0200 Subject: [PATCH 4017/5359] Check if taxonomy exists before listing its terms --- features/term.feature | 6 ++++++ php/commands/term.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/features/term.feature b/features/term.feature index 03f2bbbb6..5efcc7c7f 100644 --- a/features/term.feature +++ b/features/term.feature @@ -49,6 +49,12 @@ Feature: Manage WordPress terms | name | Test term | | taxonomy | post_tag | + When I try `wp term list nonexistent_taxonomy` + Then STDERR should be: + """ + Error: Taxonomy nonexistent_taxonomy doesn't exist. + """ + Scenario: Creating/deleting a term When I run `wp term create post_tag 'Test delete term' --slug=test-delete --description='This is a test term to be deleted' --porcelain` Then STDOUT should be a number diff --git a/php/commands/term.php b/php/commands/term.php index 113a6620c..c54c7aa28 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -59,6 +59,12 @@ class Term_Command extends WP_CLI_Command { * @subcommand list */ public function list_( $args, $assoc_args ) { + foreach ( $args as $taxonomy ) { + if ( ! taxonomy_exists( $taxonomy ) ) { + WP_CLI::error( "Taxonomy $taxonomy doesn't exist." ); + } + } + $formatter = $this->get_formatter( $assoc_args ); $defaults = array( From 8a866fbae50af41b8b04c77fba056d4bddb61cfc Mon Sep 17 00:00:00 2001 From: Radu Dan <za_creature@yahoo.com> Date: Fri, 29 Jan 2016 22:41:38 +0200 Subject: [PATCH 4018/5359] PHP_BINARY may contain spaces --- php/commands/server.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index d82fc7be6..45a1f13c0 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -53,15 +53,21 @@ function __invoke( $_, $assoc_args ) { } } - $cmd = \WP_CLI\Utils\esc_cmd( PHP_BINARY . ' -S %s -t %s %s', + $cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s %s', + PHP_BINARY, $assoc_args['host'] . ':' . $assoc_args['port'], $docroot, \WP_CLI\Utils\extract_from_phar( WP_CLI_ROOT . '/php/router.php' ) ); $descriptors = array( STDIN, STDOUT, STDERR ); + + // https://bugs.php.net/bug.php?id=60181 + $options = array(); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') + $options["bypass_shell"] = TRUE; - exit( proc_close( proc_open( $cmd, $descriptors, $pipes ) ) ); + exit( proc_close( proc_open( $cmd, $descriptors, $pipes, NULL, NULL, $options ) ) ); } } From 370f50fdb5f2598939fea3a604ca2f934ffc1286 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 30 Jan 2016 01:49:41 -0800 Subject: [PATCH 4019/5359] Use `\WP_CLI\Utils\is_windows()` instead of dupe abstraction --- php/commands/server.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index 45a1f13c0..c13e917a4 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -61,11 +61,12 @@ function __invoke( $_, $assoc_args ) { ); $descriptors = array( STDIN, STDOUT, STDERR ); - + // https://bugs.php.net/bug.php?id=60181 $options = array(); - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') + if ( \WP_CLI\Utils\is_windows() ) { $options["bypass_shell"] = TRUE; + } exit( proc_close( proc_open( $cmd, $descriptors, $pipes, NULL, NULL, $options ) ) ); } From 2ad7b8e21faa9718a10052834320d31a04ee47ef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 30 Jan 2016 10:38:27 -0800 Subject: [PATCH 4020/5359] Fix `--skip_comments` flag for `wp export` --- features/export.feature | 57 ++++++++++++++++++++++++++++ php/export/class-wp-export-query.php | 9 ++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/features/export.feature b/features/export.feature index 3f201eea2..461ee86b8 100644 --- a/features/export.feature +++ b/features/export.feature @@ -146,6 +146,13 @@ Feature: Export content. Then STDOUT should be a number And save STDOUT as {POST_ID} + When I run `wp comment generate --count=2 --post_id={POST_ID}` + And I run `wp comment list --format=count` + Then STDOUT should contain: + """ + 3 + """ + When I run `wp export --post__in={POST_ID}` And save STDOUT 'Writing to file %s' as {EXPORT_FILE} @@ -161,6 +168,12 @@ Feature: Export content. 1 """ + When I run `wp comment list --format=count` + Then STDOUT should be: + """ + 2 + """ + Scenario: Export multiple posts, separated by spaces Given a WP install @@ -422,3 +435,47 @@ Feature: Export content. """ 000.xml """ + + Scenario: Export a site and skip the comments + Given a WP install + And I run `wp comment generate --post_id=1 --count=2` + And I run `wp plugin install wordpress-importer --activate` + + When I run `wp comment list --format=count` + Then STDOUT should contain: + """ + 3 + """ + + When I run `wp export --skip_comments` + And save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --format=count` + Then STDOUT should contain: + """ + 0 + """ + + When I run `wp comment list --format=count` + Then STDOUT should contain: + """ + 0 + """ + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --format=count` + Then STDOUT should contain: + """ + 1 + """ + + When I run `wp comment list --format=count` + Then STDOUT should contain: + """ + 0 + """ diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 4d271b48f..8cbbb89d1 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -127,7 +127,7 @@ public function exportify_post( $post ) { $post->is_sticky = is_sticky( $post->ID ) ? 1 : 0; $post->terms = self::get_terms_for_post( $post ); $post->meta = self::get_meta_for_post( $post ); - $post->comments = self::get_comments_for_post( $post ); + $post->comments = $this->get_comments_for_post( $post ); $GLOBALS['post'] = $previous_global_post; return $post; } @@ -353,8 +353,13 @@ private static function get_meta_for_post( $post ) { return $meta_for_export; } - private static function get_comments_for_post( $post ) { + private function get_comments_for_post( $post ) { global $wpdb; + + if ( $this->filters['skip_comments'] ) { + return array(); + } + $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); foreach( $comments as $comment ) { $meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) ); From c2fe1a8c1ee5ee72dcf54e30dbaa3ad1a08eee06 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 1 Feb 2016 13:01:39 -0800 Subject: [PATCH 4021/5359] Add example of how to run all due cron events Props @fjarrett --- php/commands/cron.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index ec04b6b78..af420e4e0 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -143,6 +143,11 @@ public function schedule( $args, $assoc_args ) { * * [--all] * : Run all hooks. + * + * ## EXAMPLES + * + * # Run all cron events due right now + * wp cron event run $( wp cron event list --fields=hook,next_run_relative --format=csv | awk -F, '$2=="now" {print $1}' ) */ public function run( $args, $assoc_args ) { From 2a4bfa9b4aefa0aad40d4fa5ce5e20fd0c5bce0e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 2 Feb 2016 10:06:00 -0800 Subject: [PATCH 4022/5359] Support for cleaning up files when ZIP is provided to `core update` Also bumps WP version in tests for latest release. --- features/core-check-update.feature | 8 ++++---- features/core-update.feature | 6 ++++-- php/commands/core.php | 12 +++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 7d9a3d2d5..10a650884 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -10,8 +10,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.1 | major | https://wordpress.org/wordpress-4.4.1.zip | - | 3.8.12 | minor | https://wordpress.org/wordpress-3.8.12.zip | + | 4.4.2 | major | https://wordpress.org/wordpress-4.4.2.zip | + | 3.8.13 | minor | https://wordpress.org/wordpress-3.8.13.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -22,7 +22,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.1 | major | https://wordpress.org/wordpress-4.4.1.zip | + | 4.4.2 | major | https://wordpress.org/wordpress-4.4.2.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -33,7 +33,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.12 | minor | https://wordpress.org/wordpress-3.8.12.zip | + | 3.8.13 | minor | https://wordpress.org/wordpress-3.8.13.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: diff --git a/features/core-update.feature b/features/core-update.feature index 6565f026b..ef52aa8ea 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -19,6 +19,8 @@ Feature: Update WordPress core """ Starting update... Unpacking the update... + Cleaning up files... + No files found that need cleaned up Success: WordPress updated successfully. """ @@ -38,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.12 + Updating to version 3.7.13 """ When I run `wp core update --minor` @@ -50,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.12 + 3.7.13 """ @less-than-php-7 diff --git a/php/commands/core.php b/php/commands/core.php index c8659f505..a2b341c81 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -982,9 +982,6 @@ function update( $args, $assoc_args ) { $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); unset( $GLOBALS['wp_cli_update_obj'] ); - $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); - $this->cleanup_extra_files( $from_version, $update->version, $locale ); - if ( is_wp_error($result) ) { $msg = WP_CLI::error_to_string( $result ); if ( 'up_to_date' != $result->get_error_code() ) { @@ -993,6 +990,15 @@ function update( $args, $assoc_args ) { WP_CLI::success( $msg ); } } else { + + if ( file_exists( ABSPATH . 'wp-includes/version.php' ) ) { + include( ABSPATH . 'wp-includes/version.php' ); + $to_version = $wp_version; + } + + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); + $this->cleanup_extra_files( $from_version, $to_version, $locale ); + WP_CLI::success( 'WordPress updated successfully.' ); } From 29b3aa05fd079e14c4894c8e4a20b8a553d64aa5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 04:57:07 -0800 Subject: [PATCH 4023/5359] Add a timer to individual events in `wp cron event run` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running multiple events at once, this makes it easier to see which are taking a long time. ``` salty-wordpress âžœ wordpress-develop.dev wp cron event run --all Executed the cron event 'wp_update_plugins' in 0.421s. Executed the cron event 'wp_update_themes' in 0.287s. Executed the cron event 'wp_version_check' in 1.315s. Executed the cron event 'update_network_counts' in 0.004s. Executed the cron event 'wp_scheduled_auto_draft_delete' in 0.004s. Success: Executed a total of 5 cron event(s). ``` --- features/cron.feature | 22 ++++++++++++++-------- php/commands/cron.php | 4 +++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 10dcf99dc..c54590851 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -72,10 +72,16 @@ Feature: Manage WP-Cron events and schedules | wp_cli_test_event_5 | Non-repeating | {"foo":"bar"} | When I run `wp cron event run wp_cli_test_event_5` - Then STDOUT should be: + Then STDOUT should contain: + """ + Executed the cron event 'wp_cli_test_event_5' + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_cli_test_event_5' + """ + And STDOUT should contain: """ - Executed the cron event 'wp_cli_test_event_5'. - Executed the cron event 'wp_cli_test_event_5'. Success: Executed a total of 2 cron event(s). """ @@ -187,11 +193,11 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event run wp_version_check wp_update_plugins` Then STDOUT should contain: """ - Executed the cron event 'wp_version_check'. + Executed the cron event 'wp_version_check' """ And STDOUT should contain: """ - Executed the cron event 'wp_update_plugins'. + Executed the cron event 'wp_update_plugins' """ And STDOUT should contain: """ @@ -201,15 +207,15 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event run --all` Then STDOUT should contain: """ - Executed the cron event 'wp_version_check'. + Executed the cron event 'wp_version_check' """ And STDOUT should contain: """ - Executed the cron event 'wp_update_plugins'. + Executed the cron event 'wp_update_plugins' """ And STDOUT should contain: """ - Executed the cron event 'wp_update_themes'. + Executed the cron event 'wp_update_themes' """ And STDOUT should contain: """ diff --git a/php/commands/cron.php b/php/commands/cron.php index af420e4e0..0cf9342fd 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -174,10 +174,12 @@ public function run( $args, $assoc_args ) { $executed = 0; foreach ( $events as $event ) { if ( in_array( $event->hook, $args ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + $start = microtime( true ); $result = self::run_event( $event ); + $total = round( microtime( true ) - $start, 3 ); if ( $result ) { $executed++; - WP_CLI::log( sprintf( "Executed the cron event '%s'.", $event->hook ) ); + WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); } else { WP_CLI::warning( sprintf( "Failed to the execute the cron event '%s'.", $event->hook ) ); } From 4ef41759e799e4d58a81fdf4feae1bb285564ace Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 05:18:21 -0800 Subject: [PATCH 4024/5359] Persist IPTC data in `wp media import` when missing title/caption --- features/media-import.feature | 28 +++++++++++++++++++++++++++- php/commands/media.php | 17 +++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/features/media-import.feature b/features/media-import.feature index 4f971b0d6..51a96b6fc 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -45,7 +45,7 @@ Feature: Manage WordPress attachments | path | url | | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --caption="My fabulous caption" --porcelain` Then save STDOUT as {ATTACHMENT_ID} When I run `wp post get {ATTACHMENT_ID} --field=title` @@ -53,3 +53,29 @@ Feature: Manage WordPress attachments """ My imported attachment """ + + When I run `wp post get {ATTACHMENT_ID} --field=excerpt` + Then STDOUT should be: + """ + My fabulous caption + """ + + Scenario: Import a file and persist its original metadata + Given download: + | path | url | + | {CACHE_DIR}/canola.jpg | http://wp-cli.org/behat-data/canola.jpg | + + When I run `wp media import {CACHE_DIR}/canola.jpg --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + + When I run `wp post get {ATTACHMENT_ID} --field=title` + Then STDOUT should be: + """ + A field of amazing canola + """ + + When I run `wp post get {ATTACHMENT_ID} --field=excerpt` + Then STDOUT should be: + """ + The description for the image + """ diff --git a/php/commands/media.php b/php/commands/media.php index 877fed9a6..fdd905bf2 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -165,6 +165,23 @@ function import( $args, $assoc_args = array() ) { 'post_content' => $assoc_args['desc'] ); + // use image exif/iptc data for title and caption defaults if possible + if ( empty( $post_array['post_title'] ) || empty( $post_array['post_excerpt'] ) ) { + // @codingStandardsIgnoreStart + $image_meta = @wp_read_image_metadata( $tempfile ); + error_log( var_export( $image_meta, true ) ); + // @codingStandardsIgnoreEnd + if ( ! empty( $image_meta ) ) { + if ( empty( $post_array['post_title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { + $post_array['post_title'] = $image_meta['title']; + } + + if ( empty( $post_array['post_excerpt'] ) && trim( $image_meta['caption'] ) ) { + $post_array['post_excerpt'] = $image_meta['caption']; + } + } + } + // Deletes the temporary file. $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); if ( is_wp_error( $success ) ) { From 82402216d4cc1f5b43172acbad011f591dc0bbcd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 05:19:54 -0800 Subject: [PATCH 4025/5359] Remove `error_log()` --- php/commands/media.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index fdd905bf2..1aa0d7730 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -169,7 +169,6 @@ function import( $args, $assoc_args = array() ) { if ( empty( $post_array['post_title'] ) || empty( $post_array['post_excerpt'] ) ) { // @codingStandardsIgnoreStart $image_meta = @wp_read_image_metadata( $tempfile ); - error_log( var_export( $image_meta, true ) ); // @codingStandardsIgnoreEnd if ( ! empty( $image_meta ) ) { if ( empty( $post_array['post_title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { From 80f75be8b28596d4d26bae3ec75cd86c1a03b5c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 05:23:39 -0800 Subject: [PATCH 4026/5359] If no IPTC data is present, use filename as title --- features/media-import.feature | 14 ++++++++++++++ php/commands/media.php | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/features/media-import.feature b/features/media-import.feature index 51a96b6fc..81a05db28 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -60,6 +60,20 @@ Feature: Manage WordPress attachments My fabulous caption """ + Scenario: Import a file and use its filename as the title + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import {CACHE_DIR}/large-image.jpg --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + + When I run `wp post get {ATTACHMENT_ID} --field=title` + Then STDOUT should be: + """ + large-image.jpg + """ + Scenario: Import a file and persist its original metadata Given download: | path | url | diff --git a/php/commands/media.php b/php/commands/media.php index 1aa0d7730..15cf3a80d 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -181,6 +181,10 @@ function import( $args, $assoc_args = array() ) { } } + if ( empty( $post_array['post_title'] ) ) { + $post_array['post_title'] = $file_array['name']; + } + // Deletes the temporary file. $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); if ( is_wp_error( $success ) ) { From a22c1d62c18d988b531b3485c1c6cb69b862ecb0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 05:34:29 -0800 Subject: [PATCH 4027/5359] Don't check translation updates when updating themes or plugins WP-CLI intends to be precise and atomic; this behavior is neither. --- php/WP_CLI/CommandWithUpgrade.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9b71ea1c7..f7da95183 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -11,12 +11,9 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $upgrade_transient; function __construct() { - // After updating plugins/themes also update translations by running the `core language update` command. + // Do not automatically check translations updates after updating plugins/themes. add_action( 'upgrader_process_complete', function() { remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); - if ( Utils\wp_version_compare( '4.0', '>=' ) ) { - \WP_CLI::run_command( array( 'core', 'language', 'update' ), array( 'dry-run' => false ) ); - } }, 1 ); } From d0fdf80fc37947c035bb3bbb5809e53ea6c9f4b8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 05:45:12 -0800 Subject: [PATCH 4028/5359] Support custom exit codes in `WP_CLI::error()` For instance: ``` WP_CLI::error( 'This is return code 5.', 5 ); ``` --- features/framework.feature | 41 ++++++++++++++++++++++++++++++++++++++ php/class-wp-cli.php | 6 ++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/features/framework.feature b/features/framework.feature index 0772cfb21..d79936e0d 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -107,3 +107,44 @@ Feature: Load WP-CLI """ foo """ + + Scenario: Use a custom error code with WP_CLI::error() + Given an empty directory + And a exit-normal.php file: + """ + <?php + WP_CLI::error( 'This is return code 1.' ); + """ + And a exit-higher.php file: + """ + <?php + WP_CLI::error( 'This is return code 5.', 5 ); + """ + And a no-exit.php file: + """ + <?php + WP_CLI::error( 'This has no exit.', false ); + WP_CLI::error( 'So I can use multiple lines.', false ); + """ + + When I try `wp --require=exit-normal.php` + Then the return code should be 1 + And STDERR should be: + """ + Error: This is return code 1. + """ + + When I try `wp --require=exit-higher.php` + Then the return code should be 5 + And STDERR should be: + """ + Error: This is return code 5. + """ + + When I try `wp --require=no-exit.php` + Then the return code should be 0 + And STDERR should be: + """ + Error: This has no exit. + Error: So I can use multiple lines. + """ diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9ca92e104..9db24d88c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -301,8 +301,10 @@ public static function error( $message, $exit = true ) { self::$logger->error( self::error_to_string( $message ) ); } - if ( $exit ) { - exit(1); + if ( true === $exit ) { + exit( 1 ); + } elseif ( is_int( $exit ) && $exit >= 1 ) { + exit( $exit ); } } From 375c56cbaff2fc68a0663d020df54c978eebac95 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 07:48:10 -0800 Subject: [PATCH 4029/5359] Introduce `wp package` for managing WP-CLI community commands Use `wp package browse` to view all available community commands. Install a specific command with `wp package install <namespace/package-name>`. List all installed packages with `wp package list`. Or, uninstall a package with `wp package uninstall` Packages are installed to their own Composer project in `~/.wp-cli/packages`. This can be changed by setting a `WP_CLI_PACKAGES_DIR` environment variable. --- .gitignore | 1 + composer.json | 3 +- composer.lock | 474 +++++++++++++++++-- features/bootstrap/FeatureContext.php | 3 +- features/package.feature | 31 ++ php/WP_CLI/ComposerIO.php | 27 ++ php/WP_CLI/PackageManagerEventSubscriber.php | 52 ++ php/WP_CLI/Runner.php | 10 + php/commands/package.php | 416 ++++++++++++++++ utils/make-phar.php | 6 +- 10 files changed, 976 insertions(+), 47 deletions(-) create mode 100644 features/package.feature create mode 100644 php/WP_CLI/ComposerIO.php create mode 100644 php/WP_CLI/PackageManagerEventSubscriber.php create mode 100644 php/commands/package.php diff --git a/.gitignore b/.gitignore index 27990f835..0d5a442ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ config.yml /cache +/packages /vendor /*.phar /phpunit.xml.dist diff --git a/composer.json b/composer.json index cfa9066ea..982a41a8d 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "symfony/dependency-injection": "2.7.*", "symfony/event-dispatcher": "2.7.*", "symfony/translation": "2.7.*", - "nb/oxymel": "0.1.0" + "nb/oxymel": "0.1.0", + "composer/composer": "1.0.0-alpha11" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 3968ddb0c..725ba48a5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,83 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "7359993f535213af66c2148ea27369b3", - "content-hash": "da7f9e8dee2ffe0f76e5ed64233ecda9", + "hash": "73c38df6a0ba5a0690655b528fadb0f3", + "content-hash": "c201c938374a2ff19d8f0388a49475ff", "packages": [ + { + "name": "composer/composer", + "version": "1.0.0-alpha11", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6", + "reference": "cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6", + "shasum": "" + }, + "require": { + "composer/semver": "^1.0", + "composer/spdx-licenses": "^1.0", + "justinrainbow/json-schema": "^1.4.4", + "php": "^5.3.2 || ^7.0", + "seld/cli-prompt": "^1.0", + "seld/jsonlint": "^1.0", + "seld/phar-utils": "^1.0", + "symfony/console": "^2.5 || ^3.0", + "symfony/filesystem": "^2.5 || ^3.0", + "symfony/finder": "^2.2 || ^3.0", + "symfony/process": "^2.1 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5", + "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives, and allows gzip compression of all internet traffic" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "time": "2015-11-14 16:21:07" + }, { "name": "composer/semver", "version": "1.0.0", @@ -68,6 +142,133 @@ ], "time": "2015-09-21 09:42:36" }, + { + "name": "composer/spdx-licenses", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "9e1c3926bb0842812967213d7c92827bc5883671" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/9e1c3926bb0842812967213d7c92827bc5883671", + "reference": "9e1c3926bb0842812967213d7c92827bc5883671", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "~2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "time": "2015-10-05 11:27:42" + }, + { + "name": "justinrainbow/json-schema", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341", + "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341", + "shasum": "" + }, + "require": { + "php": ">=5.3.29" + }, + "require-dev": { + "json-schema/json-schema-test-suite": "1.1.0", + "phpdocumentor/phpdocumentor": "~2", + "phpunit/phpunit": "~3.7" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2016-01-25 15:43:01" + }, { "name": "mustache/mustache", "version": "v2.9.0", @@ -296,18 +497,156 @@ ], "time": "2014-05-18 04:59:02" }, + { + "name": "seld/cli-prompt", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b27db1514f7d7bb7a366ad95d4eb2b17140a0691", + "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\CliPrompt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], + "time": "2016-01-09 17:55:27" + }, + { + "name": "seld/jsonlint", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "66834d3e3566bb5798db7294619388786ae99394" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", + "reference": "66834d3e3566bb5798db7294619388786ae99394", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "time": "2015-11-21 02:21:41" + }, + { + "name": "seld/phar-utils", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", + "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phra" + ], + "time": "2015-10-13 18:44:15" + }, { "name": "symfony/config", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "61973327bfb054f6f470de7be033a28b76c1dc20" + "reference": "fbd0083cd9dac06556bd1096deaa0295c18a7584" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/61973327bfb054f6f470de7be033a28b76c1dc20", - "reference": "61973327bfb054f6f470de7be033a28b76c1dc20", + "url": "https://api.github.com/repos/symfony/config/zipball/fbd0083cd9dac06556bd1096deaa0295c18a7584", + "reference": "fbd0083cd9dac06556bd1096deaa0295c18a7584", "shasum": "" }, "require": { @@ -344,20 +683,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2015-11-02 20:20:53" + "time": "2016-01-03 15:32:00" }, { "name": "symfony/console", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "16bb1cb86df43c90931df65f529e7ebd79636750" + "reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/16bb1cb86df43c90931df65f529e7ebd79636750", - "reference": "16bb1cb86df43c90931df65f529e7ebd79636750", + "url": "https://api.github.com/repos/symfony/console/zipball/d3fc138b6ed8f8074591821d3416d8f9c04d6ca6", + "reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6", "shasum": "" }, "require": { @@ -403,20 +742,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2015-11-18 09:54:26" + "time": "2016-01-14 08:26:43" }, { "name": "symfony/dependency-injection", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "7a201bf08c29e47075047cbb378724ad46dfe217" + "reference": "37dfddbf3791d79b46b11f610b39e90d622e7183" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a201bf08c29e47075047cbb378724ad46dfe217", - "reference": "7a201bf08c29e47075047cbb378724ad46dfe217", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/37dfddbf3791d79b46b11f610b39e90d622e7183", + "reference": "37dfddbf3791d79b46b11f610b39e90d622e7183", "shasum": "" }, "require": { @@ -465,20 +804,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2015-11-23 10:17:36" + "time": "2016-01-12 17:44:11" }, { "name": "symfony/event-dispatcher", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "7e2f9c31645680026c2372edf66f863fc7757af5" + "reference": "79493b6421786e5a0fc2d161410aa86f400bcaea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7e2f9c31645680026c2372edf66f863fc7757af5", - "reference": "7e2f9c31645680026c2372edf66f863fc7757af5", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/79493b6421786e5a0fc2d161410aa86f400bcaea", + "reference": "79493b6421786e5a0fc2d161410aa86f400bcaea", "shasum": "" }, "require": { @@ -525,20 +864,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2015-10-30 20:10:21" + "time": "2016-01-13 10:26:43" }, { "name": "symfony/filesystem", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d" + "reference": "78188c6971053ff8eaa00fa180c0747c296152f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e173509d7fdbbba3cf34d6d072f2073c0210c1d", - "reference": "8e173509d7fdbbba3cf34d6d072f2073c0210c1d", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/78188c6971053ff8eaa00fa180c0747c296152f6", + "reference": "78188c6971053ff8eaa00fa180c0747c296152f6", "shasum": "" }, "require": { @@ -574,20 +913,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2015-11-18 13:41:01" + "time": "2016-01-13 07:57:33" }, { "name": "symfony/finder", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9" + "reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a06a0c0ff7db3736a50d530c908cca547bf13da9", - "reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9", + "url": "https://api.github.com/repos/symfony/finder/zipball/d20ac81c81a67ab898b0c0afa435f3e9a7d460cf", + "reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf", "shasum": "" }, "require": { @@ -623,20 +962,69 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2015-10-30 20:10:21" + "time": "2016-01-14 08:26:43" + }, + { + "name": "symfony/process", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "dfecef47506179db2501430e732adbf3793099c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8", + "reference": "dfecef47506179db2501430e732adbf3793099c8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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:44:19" }, { "name": "symfony/translation", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f" + "reference": "8cbab8445ad4269427077ba02fff8718cb397e22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e4ecb9c3ba1304eaf24de15c2d7a428101c1982f", - "reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f", + "url": "https://api.github.com/repos/symfony/translation/zipball/8cbab8445ad4269427077ba02fff8718cb397e22", + "reference": "8cbab8445ad4269427077ba02fff8718cb397e22", "shasum": "" }, "require": { @@ -686,20 +1074,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2015-11-18 13:41:01" + "time": "2016-01-03 15:32:00" }, { "name": "symfony/yaml", - "version": "v2.7.7", + "version": "v2.7.9", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c" + "reference": "a91e8af3dcde226e00be2e1c068764eef7b4c153" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/4cfcd7a9fceba662b3c036b7d9a91f6197af046c", - "reference": "4cfcd7a9fceba662b3c036b7d9a91f6197af046c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a91e8af3dcde226e00be2e1c068764eef7b4c153", + "reference": "a91e8af3dcde226e00be2e1c068764eef7b4c153", "shasum": "" }, "require": { @@ -735,7 +1123,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2015-11-18 13:41:01" + "time": "2016-01-13 10:26:43" }, { "name": "wp-cli/php-cli-tools", @@ -1278,7 +1666,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "wp-cli/php-cli-tools": 20 + "composer/composer": 15 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 75e0e6fe4..4ca743bf8 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -45,7 +45,8 @@ private static function get_process_env_variables() { $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); $env = array( 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), - 'BEHAT_RUN' => 1 + 'BEHAT_RUN' => 1, + 'HOME' => '/tmp/wp-cli-home', ); if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { $env['WP_CLI_CONFIG_PATH'] = $config_path; diff --git a/features/package.feature b/features/package.feature new file mode 100644 index 000000000..ec40ebf7c --- /dev/null +++ b/features/package.feature @@ -0,0 +1,31 @@ +Feature: Manage WP-CLI packages + + Scenario: Package CRUD + Given an empty directory + + When I run `wp package browse` + Then STDOUT should contain: + """ + danielbachhuber/wp-cli-reset-post-date-command + """ + + When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` + Then STDERR should be empty + + When I run `wp help reset-post-date` + Then STDERR should be empty + + When I run `wp package list` + Then STDOUT should contain: + """ + danielbachhuber/wp-cli-reset-post-date-command + """ + + When I run `wp package uninstall danielbachhuber/wp-cli-reset-post-date-command` + Then STDERR should be empty + + When I run `wp package list` + Then STDOUT should not contain: + """ + danielbachhuber/wp-cli-reset-post-date-command + """ diff --git a/php/WP_CLI/ComposerIO.php b/php/WP_CLI/ComposerIO.php new file mode 100644 index 000000000..b4df56a7b --- /dev/null +++ b/php/WP_CLI/ComposerIO.php @@ -0,0 +1,27 @@ +<?php + +namespace WP_CLI; + +use \Composer\IO\NullIO; +use \WP_CLI; + +/** + * A Composer IO class so we can provide some level of interactivity from WP-CLI + */ +class ComposerIO extends NullIO { + + /** + * {@inheritDoc} + */ + public function isVerbose() { + return true; + } + + /** + * {@inheritDoc} + */ + public function write( $messages, $newline = true ) { + WP_CLI::log( " - " . strip_tags( $messages ) ); + } + +} diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php new file mode 100644 index 000000000..a4b3798e3 --- /dev/null +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -0,0 +1,52 @@ +<?php + +namespace WP_CLI; + +use \Composer\DependencyResolver\Rule; +use \Composer\EventDispatcher\Event; +use \Composer\EventDispatcher\EventSubscriberInterface; +use \Composer\Script\PackageEvent; +use \Composer\Script\ScriptEvents; +use \WP_CLI; + +/** + * A Composer Event subscriber so we can keep track of what's happening inside Composer + */ +class PackageManagerEventSubscriber implements EventSubscriberInterface { + + public static function getSubscribedEvents() { + + return array( + ScriptEvents::PRE_PACKAGE_INSTALL => 'pre_install', + ScriptEvents::POST_PACKAGE_INSTALL => 'post_install', + ); + } + + public static function pre_install( PackageEvent $event ) { + WP_CLI::log( ' - Installing package' ); + } + + public static function post_install( PackageEvent $event ) { + + $operation = $event->getOperation(); + $reason = $operation->getReason(); + if ( $reason instanceof Rule ) { + + switch ( $reason->getReason() ) { + + case Rule::RULE_PACKAGE_CONFLICT; + case Rule::RULE_PACKAGE_SAME_NAME: + case Rule::RULE_PACKAGE_REQUIRES: + $composer_error = $reason->getPrettyString(); + break; + + } + + if ( ! empty( $composer_error ) ) { + WP_CLI::log( sprintf( " - Error: %s", $composer_error ) ); + } + } + + } + +} diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 5c48e329b..2055cee95 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -609,6 +609,16 @@ public function start() { // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); + if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { + $package_autoload = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/vendor/autoload.php'; + } else { + $package_autoload = getenv( 'HOME' ) . '/.wp-cli/packages/vendor/autoload.php'; + } + + if ( file_exists( $package_autoload ) ) { + require_once $package_autoload; + } + if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { if ( ! file_exists( $path ) ) { diff --git a/php/commands/package.php b/php/commands/package.php new file mode 100644 index 000000000..6ebcb23b9 --- /dev/null +++ b/php/commands/package.php @@ -0,0 +1,416 @@ +<?php +use \Composer\Config; +use \Composer\Config\JsonConfigSource; +use \Composer\EventDispatcher\Event; +use \Composer\Factory; +use \Composer\IO\NullIO; +use \Composer\Installer; +use \Composer\Json\JsonFile; +use \Composer\Json\JsonManipulator; +use \Composer\Package; +use \Composer\Package\Version\VersionParser; +use \Composer\Repository; +use \Composer\Repository\CompositeRepository; +use \Composer\Repository\ComposerRepository; +use \Composer\Repository\RepositoryManager; +use \Composer\Util\Filesystem; +use \WP_CLI\ComposerIO; + +/** + * Manage WP-CLI community packages. + * + * @package WP-CLI + * + * @when before_wp_load + */ +class Package_Command extends WP_CLI_Command { + + // TODO: read from composer.json + const PACKAGE_INDEX_URL = 'http://wp-cli.org/package-index/'; + + private $fields = array( + 'name', + 'description', + 'authors', + 'version', + ); + + /** + * Browse available WP-CLI community packages. + * + * ## OPTIONS + * + * [--format=<format>] + * : Accepted values: table, json. Default: table + */ + public function browse( $_, $assoc_args ) { + $this->show_packages( $this->get_community_packages(), $assoc_args ); + } + + /** + * Install a WP-CLI community package. + * + * ## OPTIONS + * + * <package> + * : The name of the package to install. Can optionally contain a version constraint. + * + * ## EXAMPLES + * + * # install the latest development version + * wp package install wp-cli/server-command + * + * # install the latest stable version + * wp package install wp-cli/server-command:@stable + */ + public function install( $args, $assoc_args ) { + list( $package_name ) = $args; + + if ( false !== strpos( $package_name, ':' ) ) { + list( $package_name, $version ) = explode( ':', $package_name ); + } else { + $version = 'dev-master'; + } + + $package = $this->get_community_package_by_name( $package_name ); + if ( ! $package ) { + WP_CLI::error( "Invalid package." ); + } else { + WP_CLI::log( sprintf( "Installing %s (%s)", $package_name, $version ) ); + } + + $composer = $this->get_composer(); + $composer_json_obj = $this->get_composer_json(); + + // Add the 'require' to composer.json + WP_CLI::log( sprintf( "Updating %s to require the package...", $composer_json_obj->getPath() ) ); + $composer_backup = file_get_contents( $composer_json_obj->getPath() ); + $json_manipulator = new JsonManipulator( $composer_backup ); + $json_manipulator->addLink( 'require', $package_name, $version ); + file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); + $composer = $this->get_composer(); + + // Set up the EventSubscriber + $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber; + $composer->getEventDispatcher()->addSubscriber( $event_subscriber ); + + // Set up the installer + $install = Installer::create( new ComposerIO, $composer ); + $install->setUpdate( true ); // Installer class will only override composer.lock with this flag + + // Try running the installer, but revert composer.json if failed + WP_CLI::log( 'Using Composer to install the package...' ); + try { + $res = $install->run(); + } catch ( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + if ( 0 === $res ) { + WP_CLI::success( "Package installed successfully." ); + } else { + file_put_contents( $composer_json_obj->getPath(), $composer_backup ); + WP_CLI::error( "Package installation failed. Reverted composer.json" ); + } + } + + /** + * List installed WP-CLI community packages. + * + * ## OPTIONS + * + * [--format=<format>] + * : Accepted values: table, json. Default: table + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $this->show_packages( $this->get_installed_packages(), $assoc_args ); + } + + /** + * Uninstall a WP-CLI community package. + * + * ## OPTIONS + * + * <package> + * : The name of the package to uninstall. + */ + public function uninstall( $args ) { + list( $package_name ) = $args; + + $composer = $this->get_composer(); + if ( false === ( $package = $this->get_installed_package_by_name( $package_name ) ) ) { + WP_CLI::error( "Package not installed." ); + } + + $composer_json_obj = $this->get_composer_json(); + + // Remove the 'require' from composer.json + $json_path = $composer_json_obj->getPath(); + WP_CLI::log( sprintf( 'Removing require statement from %s', $json_path ) ); + $contents = file_get_contents( $json_path ); + $manipulator = new JsonManipulator( $contents ); + $manipulator->removeSubNode( 'require', $package_name ); + file_put_contents( $composer_json_obj->getPath(), $manipulator->getContents() ); + + // Delete the directory + $package_path = $composer->getConfig()->get( 'vendor-dir' ) . '/' . $package->getName(); + WP_CLI::log( sprintf( 'Deleting package directory %s', $package_path ) ); + $filesystem = new Filesystem; + $filesystem->removeDirectory( $package_path ); + + // Reset Composer and regenerate the auto-loader + $composer = $this->get_composer(); + WP_CLI::log( 'Regenerating Composer autoload.' ); + $this->regenerate_autoloader(); + + WP_CLI::success( "Uninstalled package." ); + } + + /** + * Check whether a package is a WP-CLI community package based + * on membership in our package index. + * + * @param object $package A package object + * @return bool + */ + private function is_community_package( $package ) { + return $this->package_index()->hasPackage( $package ); + } + + /** + * Get a Composer instance. + */ + private function get_composer() { + $composer_path = $this->get_composer_json_path(); + + // Composer's auto-load generating code makes some assumptions about where + // the 'vendor-dir' is, and where Composer is running from. + // Best to just pretend we're installing a package from ~/.wp-cli or similar + chdir( pathinfo( $composer_path, PATHINFO_DIRNAME ) ); + + try { + $composer = Factory::create( new NullIO, $composer_path ); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + $this->composer = $composer; + return $this->composer; + } + + /** + * Get all of the community packages. + * + * @return array + */ + private function get_community_packages() { + static $community_packages; + + if ( null === $community_packages ) { + $community_packages = $this->package_index()->getPackages(); + } + + return $community_packages; + } + + /** + * Get the package index instance + * + * We need to construct the instance manually, because there's no way to select + * a particular instance using $composer->getRepositoryManager() + * + * @return ComposerRepository + */ + private function package_index() { + static $package_index; + + if ( !$package_index ) { + $config = new Config(); + $config->merge(array('config' => array( + 'home' => dirname( $this->get_composer_json_path() ), + /* 'cache-dir' => $cacheDir */ + ))); + $config->setConfigSource( new JsonConfigSource( $this->get_composer_json() ) ); + + $package_index = new ComposerRepository( array( 'url' => self::PACKAGE_INDEX_URL ), new NullIO, $config ); + } + + return $package_index; + } + + /** + * Display a set of packages + * + * @param array + * @param array + */ + private function show_packages( $packages, $assoc_args ) { + $defaults = array( + 'fields' => implode( ',', $this->fields ), + 'format' => 'table' + ); + $assoc_args = array_merge( $defaults, $assoc_args ); + + $list = array(); + foreach ( $packages as $package ) { + $package_output = new stdClass; + $package_output->name = $package->getName(); + $package_output->description = $package->getDescription(); + $package_output->authors = implode( ',', array_column( (array) $package->getAuthors(), 'name' ) ); + $package_output->version = $package->getPrettyVersion(); + $list[$package_output->name] = $package_output; + } + + WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); + } + + /** + * Get a community package by its name. + */ + private function get_community_package_by_name( $package_name ) { + foreach( $this->get_community_packages() as $package ) { + if ( $package_name == $package->getName() ) + return $package; + } + return false; + } + + /** + * Get the installed community packages. + */ + private function get_installed_packages() { + $composer = $this->get_composer(); + $repo = $composer->getRepositoryManager()->getLocalRepository(); + + $installed_packages = array(); + foreach( $repo->getPackages() as $package ) { + + if ( ! $this->is_community_package( $package ) ) + continue; + + $installed_packages[] = $package; + } + + return $installed_packages; + } + + /** + * Get an installed package by its name. + */ + private function get_installed_package_by_name( $package_name ) { + foreach( $this->get_installed_packages() as $package ) { + if ( $package_name == $package->getName() ) + return $package; + } + return false; + } + + /** + * Check if the package name provided is already installed. + */ + private function is_package_installed( $package_name ) { + if ( $this->get_installed_package_by_name( $package_name ) ) + return true; + else + return false; + } + + /** + * Get the composer.json object + */ + private function get_composer_json() { + return new JsonFile( $this->get_composer_json_path() ); + } + + /** + * Get the path to composer.json + */ + private function get_composer_json_path() { + static $composer_path; + + if ( null === $composer_path ) { + + if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { + $composer_path = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/composer.json'; + } else { + $composer_path = getenv( 'HOME' ) . '/.wp-cli/packages/composer.json'; + } + + // `composer.json` and its directory might need to be created + if ( ! file_exists( $composer_path ) ) { + $this->create_default_composer_json( $composer_path ); + } + } + + return $composer_path; + } + + /** + * Create a default composer.json, should one not already exist + * + * @param string $composer_path Where the composer.json should be created + * @return true|WP_Error + */ + private function create_default_composer_json( $composer_path ) { + + $composer_dir = pathinfo( $composer_path, PATHINFO_DIRNAME ); + if ( ! is_dir( $composer_dir ) ) { + \WP_CLI\Process::create( WP_CLI\Utils\esc_cmd( 'mkdir -p %s', $composer_dir ) )->run(); + } + + if ( ! is_dir( $composer_dir ) ) { + WP_CLI::error( "Composer directory for packages couldn't be created." ); + } + + $json_file = new JsonFile( $composer_path ); + + $author = (object)array( + 'name' => 'WP-CLI', + 'email' => 'noreply@wpcli.org' + ); + + $repositories = (object)array( + 'wp-cli' => (object)array( + 'type' => 'composer', + 'url' => self::PACKAGE_INDEX_URL, + ), + ); + + $options = array( + 'name' => 'wp-cli/wp-cli-community-packages', + 'description' => 'Installed community packages used by WP-CLI', + 'authors' => array( $author ), + 'homepage' => self::PACKAGE_INDEX_URL, + 'require' => new stdClass, + 'require-dev' => new stdClass, + 'minimum-stability' => 'dev', + 'license' => 'MIT', + 'repositories' => $repositories, + ); + + try { + $json_file->write( $options ); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + return true; + } + + /** + * Regenerate the Composer autoloader + */ + private function regenerate_autoloader() { + $this->composer->getAutoloadGenerator()->dump( + $this->composer->getConfig(), + $this->composer->getRepositoryManager()->getLocalRepository(), + $this->composer->getPackage(), + $this->composer->getInstallationManager(), + 'composer' + ); + } +} + +WP_CLI::add_command( 'package', 'Package_Command' ); diff --git a/utils/make-phar.php b/utils/make-phar.php index 95e89f38e..3c3206416 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -69,11 +69,11 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/mustache') ->in(WP_CLI_ROOT . '/vendor/rmccue/requests') ->in(WP_CLI_ROOT . '/vendor/composer') - ->in(WP_CLI_ROOT . '/vendor/symfony/finder') + ->in(WP_CLI_ROOT . '/vendor/symfony') ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') - ->in(WP_CLI_ROOT . '/vendor/composer/semver') ->in(WP_CLI_ROOT . '/vendor/mustangostang') + ->in(WP_CLI_ROOT . '/vendor/justinrainbow/json-schema') ->exclude('test') ->exclude('tests') ->exclude('Tests') @@ -99,6 +99,8 @@ function set_file_contents( $phar, $path, $content ) { add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/LICENSE' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/composer-schema.json' ); add_file( $phar, WP_CLI_ROOT . '/utils/get-package-require-from-composer.php' ); add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); From 767d20af958f1f7481c1c2d1e181c5f56241780a Mon Sep 17 00:00:00 2001 From: Frank Staude <frank@staude.net> Date: Wed, 3 Feb 2016 17:23:41 +0100 Subject: [PATCH 4030/5359] Parameter sequence corrected for wp_create_user. We have a plugin in application that listens to the Hook wpmu_new_user. Here we noticed that the new user at the time still has no email. The problem was that the parameters are passed in the wrong order on wpmu_create_user. --- php/commands/user.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index a65b986ba..5d027f69f 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -289,7 +289,7 @@ public function create( $args, $assoc_args ) { if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { WP_CLI::error( $ret['errors'] ); } - $user_id = wpmu_create_user( $user->user_login, $user->user_email, $user->user_login, $user->user_pass ); + $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); if ( ! $user_id ) { WP_CLI::error( "Unknown error creating new user" ); } @@ -711,7 +711,7 @@ public function import_csv( $args, $assoc_args ) { WP_CLI::warning( $ret['errors'] ); continue; } - $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_email'], $new_user['user_pass'] ); + $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_pass'], $new_user['user_email'] ); if ( ! $user_id ) { WP_CLI::warning( "Unknown error creating new user" ); continue; From 05d7ec26c5e3ff6d98c97427f4fc244b08e8bbad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 08:53:54 -0800 Subject: [PATCH 4031/5359] Use symfony/process ~2.1 for compat with PHP 5.3 --- composer.json | 1 + composer.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 982a41a8d..a27fe7819 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "symfony/console": "2.7.*", "symfony/dependency-injection": "2.7.*", "symfony/event-dispatcher": "2.7.*", + "symfony/process": "~2.1", "symfony/translation": "2.7.*", "nb/oxymel": "0.1.0", "composer/composer": "1.0.0-alpha11" diff --git a/composer.lock b/composer.lock index 725ba48a5..75bb6618c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "73c38df6a0ba5a0690655b528fadb0f3", - "content-hash": "c201c938374a2ff19d8f0388a49475ff", + "hash": "be16eacf74b49e94af4974a9c8c2460e", + "content-hash": "5045f45078e9ea1cfb8087b858d377ac", "packages": [ { "name": "composer/composer", @@ -966,25 +966,25 @@ }, { "name": "symfony/process", - "version": "v3.0.2", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "dfecef47506179db2501430e732adbf3793099c8" + "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8", - "reference": "dfecef47506179db2501430e732adbf3793099c8", + "url": "https://api.github.com/repos/symfony/process/zipball/6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", + "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -1011,7 +1011,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-02-02 13:44:19" + "time": "2016-01-06 09:59:23" }, { "name": "symfony/translation", From b4e6f3ab88eda66cf0b55d9df829da1d30a668ce Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 09:14:38 -0800 Subject: [PATCH 4032/5359] Remove commented code --- php/commands/package.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 6ebcb23b9..86bedc5dd 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -25,7 +25,6 @@ */ class Package_Command extends WP_CLI_Command { - // TODO: read from composer.json const PACKAGE_INDEX_URL = 'http://wp-cli.org/package-index/'; private $fields = array( @@ -230,7 +229,6 @@ private function package_index() { $config = new Config(); $config->merge(array('config' => array( 'home' => dirname( $this->get_composer_json_path() ), - /* 'cache-dir' => $cacheDir */ ))); $config->setConfigSource( new JsonConfigSource( $this->get_composer_json() ) ); From 0d92faad1bf50338024dc064c149db14596d466e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 09:17:03 -0800 Subject: [PATCH 4033/5359] Add braces for coding standards --- php/commands/package.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 86bedc5dd..a63fe7e50 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -162,7 +162,7 @@ public function uninstall( $args ) { // Reset Composer and regenerate the auto-loader $composer = $this->get_composer(); WP_CLI::log( 'Regenerating Composer autoload.' ); - $this->regenerate_autoloader(); + $this->regenerate_autoloader( $composer ); WP_CLI::success( "Uninstalled package." ); } @@ -195,8 +195,7 @@ private function get_composer() { WP_CLI::error( $e->getMessage() ); } - $this->composer = $composer; - return $this->composer; + return $composer; } /** @@ -285,8 +284,9 @@ private function get_installed_packages() { $installed_packages = array(); foreach( $repo->getPackages() as $package ) { - if ( ! $this->is_community_package( $package ) ) + if ( ! $this->is_community_package( $package ) ) { continue; + } $installed_packages[] = $package; } @@ -299,8 +299,9 @@ private function get_installed_packages() { */ private function get_installed_package_by_name( $package_name ) { foreach( $this->get_installed_packages() as $package ) { - if ( $package_name == $package->getName() ) + if ( $package_name == $package->getName() ) { return $package; + } } return false; } @@ -309,10 +310,11 @@ private function get_installed_package_by_name( $package_name ) { * Check if the package name provided is already installed. */ private function is_package_installed( $package_name ) { - if ( $this->get_installed_package_by_name( $package_name ) ) + if ( $this->get_installed_package_by_name( $package_name ) ) { return true; - else + } else { return false; + } } /** @@ -400,12 +402,12 @@ private function create_default_composer_json( $composer_path ) { /** * Regenerate the Composer autoloader */ - private function regenerate_autoloader() { - $this->composer->getAutoloadGenerator()->dump( - $this->composer->getConfig(), - $this->composer->getRepositoryManager()->getLocalRepository(), - $this->composer->getPackage(), - $this->composer->getInstallationManager(), + private function regenerate_autoloader( $composer ) { + $composer->getAutoloadGenerator()->dump( + $composer->getConfig(), + $composer->getRepositoryManager()->getLocalRepository(), + $composer->getPackage(), + $composer->getInstallationManager(), 'composer' ); } From 029d6e1b087a484a48029891cbed548160fad3d2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 09:17:43 -0800 Subject: [PATCH 4034/5359] More braces --- php/commands/package.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index a63fe7e50..17d7a47e4 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -268,8 +268,9 @@ private function show_packages( $packages, $assoc_args ) { */ private function get_community_package_by_name( $package_name ) { foreach( $this->get_community_packages() as $package ) { - if ( $package_name == $package->getName() ) + if ( $package_name == $package->getName() ) { return $package; + } } return false; } From 781ed1135eec2df5d9ea33dde606b062bc2b1275 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 09:18:28 -0800 Subject: [PATCH 4035/5359] Warn if installation fails, so `composer.json` is reverted --- php/commands/package.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index 17d7a47e4..b4e801f11 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -102,7 +102,7 @@ public function install( $args, $assoc_args ) { try { $res = $install->run(); } catch ( Exception $e ) { - WP_CLI::error( $e->getMessage() ); + WP_CLI::warning( $e->getMessage() ); } if ( 0 === $res ) { From 9e8e0a5b31706474664abacef06ac1ee7d81a947 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 09:29:41 -0800 Subject: [PATCH 4036/5359] Retool `get_composer()` so we can warn when autoload isn't regenerated If the autoload isn't regenerated, it can brick someone's WP-CLI instance. At the very least, we should let them know they'll need to manually regenerate. --- php/commands/package.php | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index b4e801f11..5b951a22b 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -78,7 +78,11 @@ public function install( $args, $assoc_args ) { WP_CLI::log( sprintf( "Installing %s (%s)", $package_name, $version ) ); } - $composer = $this->get_composer(); + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } $composer_json_obj = $this->get_composer_json(); // Add the 'require' to composer.json @@ -87,7 +91,11 @@ public function install( $args, $assoc_args ) { $json_manipulator = new JsonManipulator( $composer_backup ); $json_manipulator->addLink( 'require', $package_name, $version ); file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); - $composer = $this->get_composer(); + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } // Set up the EventSubscriber $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber; @@ -138,7 +146,11 @@ public function list_( $args, $assoc_args ) { public function uninstall( $args ) { list( $package_name ) = $args; - $composer = $this->get_composer(); + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } if ( false === ( $package = $this->get_installed_package_by_name( $package_name ) ) ) { WP_CLI::error( "Package not installed." ); } @@ -160,8 +172,13 @@ public function uninstall( $args ) { $filesystem->removeDirectory( $package_path ); // Reset Composer and regenerate the auto-loader - $composer = $this->get_composer(); WP_CLI::log( 'Regenerating Composer autoload.' ); + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::warning( $e->getMessage() ); + WP_CLI::error( 'Composer autoload will need to be manually regenerated.' ); + } $this->regenerate_autoloader( $composer ); WP_CLI::success( "Uninstalled package." ); @@ -188,14 +205,7 @@ private function get_composer() { // the 'vendor-dir' is, and where Composer is running from. // Best to just pretend we're installing a package from ~/.wp-cli or similar chdir( pathinfo( $composer_path, PATHINFO_DIRNAME ) ); - - try { - $composer = Factory::create( new NullIO, $composer_path ); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - return $composer; + return Factory::create( new NullIO, $composer_path ); } /** @@ -279,7 +289,11 @@ private function get_community_package_by_name( $package_name ) { * Get the installed community packages. */ private function get_installed_packages() { - $composer = $this->get_composer(); + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } $repo = $composer->getRepositoryManager()->getLocalRepository(); $installed_packages = array(); From 8660b7d54c15462952424ac82fc27ba9767b952d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 10:00:49 -0800 Subject: [PATCH 4037/5359] Manage term meta with `wp term meta` --- features/term-meta.feature | 35 +++++++++++++++++++++++++++++++++++ php/commands/term.php | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 features/term-meta.feature diff --git a/features/term-meta.feature b/features/term-meta.feature new file mode 100644 index 000000000..fcc7b6581 --- /dev/null +++ b/features/term-meta.feature @@ -0,0 +1,35 @@ +Feature: Manage term custom fields + + @require-wp-4.4 + Scenario: Term meta CRUD + Given a WP install + + When I run `wp term meta add 1 foo 'bar'` + Then STDOUT should not be empty + + When I run `wp term meta get 1 foo` + Then STDOUT should be: + """ + bar + """ + + When I try `wp term meta get 999999 foo` + Then STDERR should be: + """ + Error: Could not find the term with ID 999999. + """ + + When I run `wp term meta set 1 foo '[ "1", "2" ]' --format=json` + Then STDOUT should not be empty + + When I run `wp term meta get 1 foo --format=json` + Then STDOUT should be: + """ + ["1","2"] + """ + + When I run `wp term meta delete 1 foo` + Then STDOUT should not be empty + + When I try `wp term meta get 1 foo` + Then the return code should be 1 diff --git a/php/commands/term.php b/php/commands/term.php index c54c7aa28..07061fc0f 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -411,5 +411,42 @@ private function get_formatter( &$assoc_args ) { } } +/** + * Manage term custom fields. + * + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * wp term meta set category 123 description "Mary is a WordPress developer." + */ +class Term_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'term'; + + /** + * Check that the term ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $term = get_term( $object_id ); + if ( ! $term ) { + WP_CLI::error( "Could not find the term with ID {$object_id}." ); + } + return $term->term_id; + } + +} + WP_CLI::add_command( 'term', 'Term_Command' ); +WP_CLI::add_command( 'term meta', 'Term_Meta_Command', array( + 'before_invoke' => function() { + if ( \WP_CLI\Utils\wp_version_compare( '4.4', '<' ) ) { + WP_CLI::error( "Requires WordPress 4.4 or greater." ); + } + }) +); From 0d29675d2d8e9181b8ae5bf531efe57c42c61ed3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 11:02:18 -0800 Subject: [PATCH 4038/5359] Fix deploys; `WP_CLI_BIN_DIR` is no longer set --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 9f942dffc..45de26a95 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -30,7 +30,7 @@ git config push.default "current" fname="phar/wp-cli-nightly.phar" -mv $WP_CLI_BIN_DIR/wp $fname +mv /tmp/wp-cli-phar/wp $fname chmod -x $fname md5sum $fname | cut -d ' ' -f 1 > $fname.md5 From e4a53e45604b2cec1967249ca330fd3f99f18675 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 12:02:55 -0800 Subject: [PATCH 4039/5359] Explain nuances of `wp core update --minor` WordPress doesn't follow semver, so `--minor` would take you from WP 4.3 to WP 4.3.3 instead of WP 4.4.2 --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index a2b341c81..6f589ff1d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -877,7 +877,7 @@ public function verify_checksums( $args, $assoc_args ) { * : Path to zip file to use, instead of downloading from wordpress.org. * * [--minor] - * : Only perform updates for minor releases. + * : Only perform updates for minor releases (e.g. update from WP 4.3 to 4.3.3 instead of 4.4.2). * * [--version=<version>] * : Update to a specific version, instead of to the latest version. From 2be9d54ebee5fd93962b98fee7c386f311a20716 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 12:07:03 -0800 Subject: [PATCH 4040/5359] Remove dead code in `Cron_Event_Command->run()` `Cron_Event_Command::run_event()` always returns true --- php/commands/cron.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 0cf9342fd..b369ad059 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -177,12 +177,8 @@ public function run( $args, $assoc_args ) { $start = microtime( true ); $result = self::run_event( $event ); $total = round( microtime( true ) - $start, 3 ); - if ( $result ) { - $executed++; - WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); - } else { - WP_CLI::warning( sprintf( "Failed to the execute the cron event '%s'.", $event->hook ) ); - } + $executed++; + WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); } } From c9c8dca23f6b71b24f4610a770b9d332195ee8b2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 3 Feb 2016 13:11:29 -0800 Subject: [PATCH 4041/5359] Revert "Revert "Revert "Permit failures on trunk""" This reverts commit e0b593e3135ce3bcb3594b2820be274b8078f151. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0174c6cd..81b0e2b1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,8 +16,6 @@ matrix: env: WP_VERSION=trunk - php: 7.0 env: WP_VERSION=latest - allow_failures: - - env: WP_VERSION=trunk before_script: ./ci/prepare.sh From 9090cf837b1982cd197e3d3a621b63b5a53b7d05 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 4 Feb 2016 15:29:34 -0800 Subject: [PATCH 4042/5359] Explain exit codes for `wp (theme|plugin) is-installed` --- php/commands/plugin.php | 3 +++ php/commands/theme.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 885f69fb9..c9a92fb85 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -534,6 +534,8 @@ function uninstall( $args, $assoc_args = array() ) { /** * Check if the plugin is installed. * + * Returns exit code 0 when installed, 1 when uninstalled. + * * ## OPTIONS * * <plugin> @@ -542,6 +544,7 @@ function uninstall( $args, $assoc_args = array() ) { * ## EXAMPLES * * wp plugin is-installed hello + * echo $? # displays 0 or 1 * * @subcommand is-installed */ diff --git a/php/commands/theme.php b/php/commands/theme.php index 3f78830c1..79d6c0817 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -485,6 +485,8 @@ function update( $args, $assoc_args ) { /** * Check if the theme is installed. * + * Returns exit code 0 when installed, 1 when uninstalled. + * * ## OPTIONS * * <theme> @@ -493,6 +495,7 @@ function update( $args, $assoc_args ) { * ## EXAMPLES * * wp theme is-installed twentytwelve + * echo $? # displays 0 or 1 * * @subcommand is-installed */ From 827fe5c546f5cc0e038f08bfe4de2eeb458a3425 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 10:54:29 +0000 Subject: [PATCH 4043/5359] Add json and csv formats to upgrade output --- php/WP_CLI/CommandWithUpgrade.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index f7da95183..9bee857de 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -282,7 +282,13 @@ protected function update_many( $args, $assoc_args ) { 'status' => $result[ $info['update_id'] ] !== null ? 'Updated' : 'Error', ); } - \WP_CLI\Utils\format_items( 'table', $status, array( 'name', 'old_version', 'new_version', 'status' ) ); + + $format = 'table'; + if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { + $format = $assoc_args['format']; + } + + \WP_CLI\Utils\format_items( $format, $status, array( 'name', 'old_version', 'new_version', 'status' ) ); } } } From 760bc9e6ae7546af4cd7107d1c585da87ef3dccf Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 10:54:38 +0000 Subject: [PATCH 4044/5359] Add tests --- features/theme.feature | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 42144d0cd..3b0239b24 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -249,3 +249,25 @@ Feature: Manage WordPress themes | name | status | | biker | active | | jolene | parent | + + Scenario: Check json and csv formats when updating a theme + Given a WP install + + When I run `wp theme update twentyfifteen --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update twentyfifteen --format=json` + Then STDOUT should contain: + """ + [{"name":"twentyfifteen","old_version":"1.0", + """ + + When I run `wp theme update twentyfifteen --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update twentyfifteen --format=csv` + Then STDOUT should contain: + """ + name,old_version,new_version,status + twentyfifteen,1.0, + """ From 07c1094b3ed8b3134dda46cefdd7f00370a00715 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 5 Feb 2016 05:27:23 -0800 Subject: [PATCH 4045/5359] Support `--format=yaml` when displaying structured data --- features/bootstrap/support.php | 22 +++++++++++++++ features/formatter.feature | 51 ++++++++++++++++++++++++++++++++++ features/steps/then.php | 10 +++++++ php/WP_CLI/Formatter.php | 5 ++++ php/class-wp-cli.php | 2 ++ php/commands/comment.php | 4 +-- php/commands/core.php | 2 +- php/commands/cron.php | 4 +-- php/commands/menu.php | 6 ++-- php/commands/package.php | 4 +-- php/commands/plugin.php | 6 ++-- php/commands/post-type.php | 4 +-- php/commands/post.php | 4 +-- php/commands/rewrite.php | 2 +- php/commands/role.php | 2 +- php/commands/sidebar.php | 2 +- php/commands/site.php | 2 +- php/commands/taxonomy.php | 4 +-- php/commands/term.php | 4 +-- php/commands/theme.php | 6 ++-- php/commands/user.php | 6 ++-- php/commands/widget.php | 2 +- 22 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 features/formatter.feature diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 9df27c18a..d5cc221e4 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -164,3 +164,25 @@ function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { return $expectedResult >= count( $expectedCSV ); } +/** + * Compare two strings containing YAML to ensure that @a $actualYaml contains at + * least what the YAML string @a $expectedYaml contains. + * + * @return whether or not @a $actualYaml contains @a $expectedJson + * @retval true @a $actualYaml contains @a $expectedJson + * @retval false @a $actualYaml does not contain @a $expectedJson + * + * @param[in] $actualYaml the YAML string to be tested + * @param[in] $expectedYaml the expected YAML string + */ +function checkThatYamlStringContainsYamlString( $actualYaml, $expectedYaml ) { + $actualValue = spyc_load( $actualYaml ); + $expectedValue = spyc_load( $expectedYaml ); + + if ( !$actualValue ) { + return false; + } + + return compareContents( $expectedValue, $actualValue ); +} + diff --git a/features/formatter.feature b/features/formatter.feature new file mode 100644 index 000000000..a34551b05 --- /dev/null +++ b/features/formatter.feature @@ -0,0 +1,51 @@ +Feature: Format output + + Scenario: Format output as YAML + Given an empty directory + And a output-yaml.php file: + """ + <?php + /** + * @when before_wp_load + */ + $output_yaml = function( $args ) { + $items = array( + array( + 'label' => 'Foo', + 'slug' => 'foo', + ), + array( + 'label' => 'Bar', + 'slug' => 'bar', + ), + ); + $assoc_args = array( 'format' => 'yaml', 'fields' => array( 'label', 'slug' ) ); + $formatter = new \WP_CLI\Formatter( $assoc_args ); + if ( 'all' === $args[0] ) { + $formatter->display_items( $items ); + } else if ( 'single' === $args[0] ) { + $formatter->display_item( $items[0] ); + } + }; + WP_CLI::add_command( 'yaml', $output_yaml ); + """ + + When I run `wp --require=output-yaml.php yaml all` + Then STDOUT should be YAML containing: + """ + --- + - + label: Foo + slug: foo + - + label: Bar + slug: bar + """ + + When I run `wp --require=output-yaml.php yaml single` + Then STDOUT should be YAML containing: + """ + --- + label: Foo + slug: foo + """ diff --git a/features/steps/then.php b/features/steps/then.php index f2e15fb32..f2889f5bf 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -113,6 +113,16 @@ function ( $world, TableNode $expected ) { } ); +$steps->Then( '/^STDOUT should be YAML containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->stdout; + $expected = $world->replace_variables( (string) $expected ); + + if ( !checkThatYamlStringContainsYamlString( $output, $expected ) ) { + throw new \Exception( $world->result ); + } +}); + $steps->Then( '/^(STDOUT|STDERR) should be empty$/', function ( $world, $stream ) { diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 31c4a169e..0a3cd4978 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -144,6 +144,10 @@ private function format( $items ) { echo json_encode( $out ); break; + case 'yaml': + echo \Spyc::YAMLDump( $items, 2, 0 ); + break; + default: \WP_CLI::error( 'Invalid format: ' . $this->args['format'] ); } @@ -237,6 +241,7 @@ private function show_multiple_fields( $data, $format ) { } break; + case 'yaml': case 'json': \WP_CLI::print_value( $data, array( 'format' => $format ) ); break; diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9db24d88c..1e360a40e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -384,6 +384,8 @@ public static function read_value( $raw_value, $assoc_args = array() ) { public static function print_value( $value, $assoc_args = array() ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { $value = json_encode( $value ); + } elseif ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'yaml' ) { + $value = Spyc::YAMLDump( $value, 2, 0 ); } elseif ( is_array( $value ) || is_object( $value ) ) { $value = var_export( $value ); } diff --git a/php/commands/comment.php b/php/commands/comment.php index 9524d9252..45a01d86f 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -140,7 +140,7 @@ public function generate( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * @@ -177,7 +177,7 @@ public function get( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/core.php b/php/commands/core.php index 6f589ff1d..541161cd5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -30,7 +30,7 @@ class Core_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] - * : Accepted values: table, csv, json. Default: table + * : Accepted values: table, csv, json, yaml. Default: table * * @subcommand check-update */ diff --git a/php/commands/cron.php b/php/commands/cron.php index b369ad059..ccc763485 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -23,7 +23,7 @@ class Cron_Event_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, json, csv, ids. Default: table. + * : Accepted values: table, json, csv, ids, yaml. Default: table. * * ## AVAILABLE FIELDS * @@ -407,7 +407,7 @@ class Cron_Schedule_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, json, csv, ids. Default: table. + * : Accepted values: table, json, csv, ids, yaml. Default: table. * * ## AVAILABLE FIELDS * diff --git a/php/commands/menu.php b/php/commands/menu.php index 33cfcf0fa..1c9e7e12b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -97,7 +97,7 @@ public function delete( $args, $_ ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -193,7 +193,7 @@ class Menu_Item_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -634,7 +634,7 @@ class Menu_Location_Command extends WP_CLI_Command { * List locations for the current theme. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/package.php b/php/commands/package.php index 5b951a22b..e85d8c8a1 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -40,7 +40,7 @@ class Package_Command extends WP_CLI_Command { * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv, yaml. Default: table */ public function browse( $_, $assoc_args ) { $this->show_packages( $this->get_community_packages(), $assoc_args ); @@ -127,7 +127,7 @@ public function install( $args, $assoc_args ) { * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * @subcommand list */ diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c9a92fb85..8290ce171 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -78,7 +78,7 @@ function status( $args ) { * **short_description**: Plugin's Short Description * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## EXAMPLES * @@ -460,7 +460,7 @@ function install( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Output list as table, json, CSV. Defaults to table. + * : Output list as table, json, CSV, yaml. Defaults to table. * * ## EXAMPLES * @@ -594,7 +594,7 @@ function delete( $args, $assoc_args = array() ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/post-type.php b/php/commands/post-type.php index d83ec398f..4fdff4600 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -30,7 +30,7 @@ class Post_Type_Command extends WP_CLI_Command { * : Limit the output to specific post type fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -76,7 +76,7 @@ public function list_( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * diff --git a/php/commands/post.php b/php/commands/post.php index 1fdafec57..61cbd0beb 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -164,7 +164,7 @@ protected function _edit( $content, $title ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * @@ -243,7 +243,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 02c0c1e17..d8dac74fc 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -151,7 +151,7 @@ public function structure( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to match,query,source. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## EXAMPLES * diff --git a/php/commands/role.php b/php/commands/role.php index 31b76cf95..de0b3c15b 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -21,7 +21,7 @@ class Role_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 0096d4a6c..53cb9c3ac 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -20,7 +20,7 @@ class Sidebar_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/site.php b/php/commands/site.php index 923abc580..70ead9dbc 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -371,7 +371,7 @@ private function _get_network( $network_id ) { * : Comma-separated list of fields to show. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index 7d34abe7e..addfb8c32 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -41,7 +41,7 @@ public function __construct() { * : Limit the output to specific taxonomy fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -95,7 +95,7 @@ public function list_( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * diff --git a/php/commands/term.php b/php/commands/term.php index 07061fc0f..049fa6515 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -34,7 +34,7 @@ class Term_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -169,7 +169,7 @@ public function create( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * diff --git a/php/commands/theme.php b/php/commands/theme.php index 79d6c0817..980967d7e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -72,7 +72,7 @@ function status( $args ) { * **description**: Theme Description * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## EXAMPLES * @@ -411,7 +411,7 @@ function install( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * @@ -557,7 +557,7 @@ function delete( $args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## AVAILABLE FIELDS * diff --git a/php/commands/user.php b/php/commands/user.php index 5d027f69f..bda3adcfb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -42,7 +42,7 @@ public function __construct() { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Accepted values: table, csv, json, count, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -138,7 +138,7 @@ public function list_( $args, $assoc_args ) { * : Get a specific subset of the user's fields. * * [--format=<format>] - * : Accepted values: table, json, csv. Default: table + * : Accepted values: table, json, csv, yaml. Default: table * * ## EXAMPLES * @@ -820,7 +820,7 @@ public function __construct() { * : The metadata key. * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Accepted values: table, json, yaml. Default: table */ public function get( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); diff --git a/php/commands/widget.php b/php/commands/widget.php index 3976272c9..fbc174beb 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -37,7 +37,7 @@ class Widget_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * From ea065f5539441423086798e4beeb161f482573d6 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 14:54:17 +0000 Subject: [PATCH 4046/5359] Don't output feedback if --format is json/csv --- php/WP_CLI/CommandWithUpgrade.php | 15 +++++++++------ php/WP_CLI/UpgraderSkin.php | 4 +++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9bee857de..26a3688b3 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -249,6 +249,7 @@ protected function update_many( $args, $assoc_args ) { $cache_manager->whitelist_package($item['update_package'], $this->item_type, $item['name'], $item['update_version']); } $upgrader = $this->get_upgrader( $assoc_args ); + $upgrader->cli_output_format = ! empty( $assoc_args['format'] ) ? $assoc_args['format'] : ''; $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); } @@ -258,12 +259,14 @@ protected function update_many( $args, $assoc_args ) { $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; - if ( $num_to_update == $num_updated ) { - \WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - \WP_CLI::warning( $line ); - } else { - \WP_CLI::error( $line ); + if ( empty( $assoc_args['format'] ) || ! in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { + if ( $num_to_update == $num_updated ) { + \WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + \WP_CLI::warning( $line ); + } else { + \WP_CLI::error( $line ); + } } if ( $num_to_update > 0 ) { diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php index aa56b4348..0fab75eb0 100644 --- a/php/WP_CLI/UpgraderSkin.php +++ b/php/WP_CLI/UpgraderSkin.php @@ -41,7 +41,9 @@ function feedback( $string ) { $string = str_replace( '…', '...', strip_tags( $string ) ); - \WP_CLI::line( $string ); + if ( empty( $this->upgrader->cli_output_format ) || ! in_array( $this->upgrader->cli_output_format, array( 'csv', 'json' ) ) ) { + \WP_CLI::line( $string ); + } } } From 5684576c609714f2c45edde5d21d6d813918de2e Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 14:54:42 +0000 Subject: [PATCH 4047/5359] Make --dry-run use the correct --format --- php/WP_CLI/CommandWithUpgrade.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 26a3688b3..9547e4c8f 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -232,10 +232,17 @@ protected function update_many( $args, $assoc_args ) { return; } - \WP_CLI::line( "Available {$this->item_type} updates:" ); - - \WP_CLI\Utils\format_items( 'table', $items_to_update, - array( 'name', 'status', 'version', 'update_version' ) ); + if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { + \WP_CLI\Utils\format_items( $assoc_args['format'], $items_to_update, array( 'name', 'status', 'version', 'update_version' ) ); + } else if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { + \WP_CLI::line( "Available {$this->item_type} updates:" ); + foreach( $items_to_update as $item_to_update => $info ) { + \WP_CLI::log( "{$info['title']} update from version {$info['version']} to version {$info['update_version']}" ); + } + } else { + \WP_CLI::line( "Available {$this->item_type} updates:" ); + \WP_CLI\Utils\format_items( 'table', $items_to_update, array( 'name', 'status', 'version', 'update_version' ) ); + } return; } From 98a99910c32fbc92b63e75a6c817a81e52220229 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 14:54:56 +0000 Subject: [PATCH 4048/5359] Add tests for --dry-run --- features/theme.feature | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 3b0239b24..0665eb33f 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -250,6 +250,38 @@ Feature: Manage WordPress themes | biker | active | | jolene | parent | + Scenario: When updating a theme --format should be the same when using --dry-run + Given a WP install + + When I run `wp theme update twentyfifteen --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update twentyfifteen --format=summary --dry-run` + Then STDOUT should contain: + """ + Available theme updates: + Twenty Fifteen update from version 1.0 to version + """ + + When I run `wp theme update twentyfifteen --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update twentyfifteen --format=json --dry-run` + Then STDOUT should contain: + """ + [{"name":"twentyfifteen","status":"inactive","version":"1.0", + """ + + When I run `wp theme update twentyfifteen --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update twentyfifteen --format=csv --dry-run` + Then STDOUT should contain: + """ + name,status,version,update_version + twentyfifteen,inactive,1.0, + """ + Scenario: Check json and csv formats when updating a theme Given a WP install From 9fff11456f73a7b493f7cb22742888e5c4457bef Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 16:23:05 +0000 Subject: [PATCH 4049/5359] Use quiet logger --- php/WP_CLI/CommandWithUpgrade.php | 20 +++++++++++--------- php/WP_CLI/UpgraderSkin.php | 4 +--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 9547e4c8f..e9b02249d 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -212,6 +212,11 @@ protected function get_upgrader( $assoc_args ) { protected function update_many( $args, $assoc_args ) { call_user_func( $this->upgrade_refresh ); + if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { + $logger = new \WP_CLI\Loggers\Quiet; + \WP_CLI::set_logger( $logger ); + } + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { \WP_CLI::error( "Please specify one or more {$this->item_type}s, or use --all." ); } @@ -256,7 +261,6 @@ protected function update_many( $args, $assoc_args ) { $cache_manager->whitelist_package($item['update_package'], $this->item_type, $item['name'], $item['update_version']); } $upgrader = $this->get_upgrader( $assoc_args ); - $upgrader->cli_output_format = ! empty( $assoc_args['format'] ) ? $assoc_args['format'] : ''; $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); } @@ -266,14 +270,12 @@ protected function update_many( $args, $assoc_args ) { $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; - if ( empty( $assoc_args['format'] ) || ! in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { - if ( $num_to_update == $num_updated ) { - \WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - \WP_CLI::warning( $line ); - } else { - \WP_CLI::error( $line ); - } + if ( $num_to_update == $num_updated ) { + \WP_CLI::success( $line ); + } else if ( $num_updated > 0 ) { + \WP_CLI::warning( $line ); + } else { + \WP_CLI::error( $line ); } if ( $num_to_update > 0 ) { diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php index 0fab75eb0..a0df91820 100644 --- a/php/WP_CLI/UpgraderSkin.php +++ b/php/WP_CLI/UpgraderSkin.php @@ -41,9 +41,7 @@ function feedback( $string ) { $string = str_replace( '…', '...', strip_tags( $string ) ); - if ( empty( $this->upgrader->cli_output_format ) || ! in_array( $this->upgrader->cli_output_format, array( 'csv', 'json' ) ) ) { - \WP_CLI::line( $string ); - } + \WP_CLI::log( $string ); } } From a4cc0634cd3d95fa89c7a4a6a54122ab953a1284 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 5 Feb 2016 16:24:46 +0000 Subject: [PATCH 4050/5359] Update tests --- features/theme.feature | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 0665eb33f..505062fc2 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -253,53 +253,53 @@ Feature: Manage WordPress themes Scenario: When updating a theme --format should be the same when using --dry-run Given a WP install - When I run `wp theme update twentyfifteen --version=1.0` + When I run `wp theme install --force twentytwelve --version=1.0` Then STDOUT should not be empty - When I run `wp theme update twentyfifteen --format=summary --dry-run` + When I run `wp theme list --name=twentytwelve --field=update_version` + And save STDOUT as {UPDATE_VERSION} + + When I run `wp theme update twentytwelve --format=summary --dry-run` Then STDOUT should contain: """ Available theme updates: - Twenty Fifteen update from version 1.0 to version + Twenty Twelve update from version 1.0 to version {UPDATE_VERSION} """ - When I run `wp theme update twentyfifteen --version=1.0` - Then STDOUT should not be empty - - When I run `wp theme update twentyfifteen --format=json --dry-run` - Then STDOUT should contain: + When I run `wp theme update twentytwelve --format=json --dry-run` + Then STDOUT should be JSON containing: """ - [{"name":"twentyfifteen","status":"inactive","version":"1.0", + [{"name":"twentytwelve","status":"inactive","version":"1.0","update_version":"{UPDATE_VERSION}"}] """ - When I run `wp theme update twentyfifteen --version=1.0` - Then STDOUT should not be empty - - When I run `wp theme update twentyfifteen --format=csv --dry-run` + When I run `wp theme update twentytwelve --format=csv --dry-run` Then STDOUT should contain: """ name,status,version,update_version - twentyfifteen,inactive,1.0, + twentytwelve,inactive,1.0,{UPDATE_VERSION} """ Scenario: Check json and csv formats when updating a theme Given a WP install - When I run `wp theme update twentyfifteen --version=1.0` + When I run `wp theme install --force twentytwelve --version=1.0` Then STDOUT should not be empty - When I run `wp theme update twentyfifteen --format=json` + When I run `wp theme list --name=twentytwelve --field=update_version` + And save STDOUT as {UPDATE_VERSION} + + When I run `wp theme update twentytwelve --format=json` Then STDOUT should contain: """ - [{"name":"twentyfifteen","old_version":"1.0", + [{"name":"twentytwelve","old_version":"1.0","new_version":"{UPDATE_VERSION}","status":"Updated"}] """ - When I run `wp theme update twentyfifteen --version=1.0` + When I run `wp theme install --force twentytwelve --version=1.0` Then STDOUT should not be empty - When I run `wp theme update twentyfifteen --format=csv` + When I run `wp theme update twentytwelve --format=csv` Then STDOUT should contain: """ name,old_version,new_version,status - twentyfifteen,1.0, + twentytwelve,1.0,{UPDATE_VERSION},Updated """ From af4500c3577091c30bcf94378059b8907ac4d3eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 5 Feb 2016 15:17:58 -0800 Subject: [PATCH 4051/5359] First pass at better documentation of public APIs --- php/class-wp-cli.php | 28 ++++++++++++++++++++++------ php/utils.php | 22 ++++++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1e360a40e..e1fc3025a 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -246,7 +246,10 @@ public static function add_command( $name, $callable, $args = array() ) { } /** - * Display a message in the CLI and end with a newline + * Display a message in the CLI and end with a newline. + * Ignores --quiet flag. To respect, use WP_CLI::log() + * + * @access public * * @param string $message */ @@ -257,6 +260,8 @@ public static function line( $message = '' ) { /** * Log an informational message. * + * @access public + * * @param string $message */ public static function log( $message ) { @@ -264,7 +269,9 @@ public static function log( $message ) { } /** - * Display a success in the CLI and end with a newline + * Display a success in the CLI and end with a newline. + * + * @access public * * @param string $message */ @@ -273,7 +280,10 @@ public static function success( $message ) { } /** - * Log debug information + * Log information when --debug flag is used. + * Helpful for optionally showing greater detail when needed. + * + * @access public * * @param string $message */ @@ -282,7 +292,9 @@ public static function debug( $message ) { } /** - * Display a warning in the CLI and end with a newline + * Display a warning in the CLI and end with a newline. + * + * @access public * * @param string $message */ @@ -291,7 +303,9 @@ public static function warning( $message ) { } /** - * Display an error in the CLI and end with a newline + * Display an error in the CLI and end with a newline. + * + * @access public * * @param string|WP_Error $message * @param bool $exit if true, the script will exit() @@ -309,7 +323,9 @@ public static function error( $message, $exit = true ) { } /** - * Display an error in the CLI and end with a newline + * Display an error in the CLI and end with a newline. + * + * @access public * * @param array $message each element from the array will be printed on its own line */ diff --git a/php/utils.php b/php/utils.php index 8cdc5dbe9..315eb31ca 100644 --- a/php/utils.php +++ b/php/utils.php @@ -241,6 +241,8 @@ function wp_version_compare( $since, $operator ) { /** * Output items in a table, JSON, CSV, ids, or the total count * + * @access public + * * @param string $format Format to use: 'table', 'json', 'csv', 'ids', 'count' * @param array $items Data to output * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list @@ -254,6 +256,8 @@ function format_items( $format, $items, $fields ) { /** * Write data as CSV to a given file. * + * @access public + * * @param resource $fd File descriptor * @param array $rows Array of rows to output * @param array $headers List of CSV columns (optional) @@ -542,7 +546,9 @@ function increment_version( $current_version, $new_version ) { } /** - * Compare two version strings to get the named semantic version + * Compare two version strings to get the named semantic version. + * + * @access public * * @param string $new_version * @param string $original_version @@ -569,18 +575,22 @@ function get_named_sem_ver( $new_version, $original_version ) { /** * Return the flag value or, if it's not set, the $default value. * - * @param array $args Arguments array. - * @param string $flag Flag to get the value. - * @param mixed $default Default value for the flag. Default: NULL + * @access public + * + * @param array $assoc_args Arguments array. + * @param string $flag Flag to get the value. + * @param mixed $default Default value for the flag. Default: NULL * @return mixed */ -function get_flag_value( $args, $flag, $default = null ) { - return isset( $args[ $flag ] ) ? $args[ $flag ] : $default; +function get_flag_value( $assoc_args, $flag, $default = null ) { + return isset( $assoc_args[ $flag ] ) ? $assoc_args[ $flag ] : $default; } /** * Get the temp directory, and let the user know if it isn't writable. * + * @access public + * * @return string */ function get_temp_dir() { From b88b38c20f6c089901a110582d0c2dc25200b2f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 8 Feb 2016 06:43:56 -0800 Subject: [PATCH 4052/5359] Don't colorize `format=table` by default More often than not, strings are accidentally colorized because they contain colorization tokens. Developers can still colorize their strings in advance, and include the colorized strings in their table. --- composer.json | 2 +- composer.lock | 15 ++++++++------- php/WP_CLI/Formatter.php | 13 ++++++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index a27fe7819..33a8b6f9a 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "0.11.0", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "mustangostang/spyc": "0.5.1", "composer/semver": "1.0.0", diff --git a/composer.lock b/composer.lock index 75bb6618c..e0301b534 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "be16eacf74b49e94af4974a9c8c2460e", - "content-hash": "5045f45078e9ea1cfb8087b858d377ac", + "hash": "78165aafa4140e764d4f1dc828752cce", + "content-hash": "7b6ae0fa1f96555e592ce2f48493a535", "packages": [ { "name": "composer/composer", @@ -1127,16 +1127,16 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "0.11.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "d0564da283585c7289e18877ed2f9c35c1b67013" + "reference": "5311a4b99103c0505db015a334be4952654d6e21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d0564da283585c7289e18877ed2f9c35c1b67013", - "reference": "d0564da283585c7289e18877ed2f9c35c1b67013", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/5311a4b99103c0505db015a334be4952654d6e21", + "reference": "5311a4b99103c0505db015a334be4952654d6e21", "shasum": "" }, "require": { @@ -1173,7 +1173,7 @@ "cli", "console" ], - "time": "2015-08-10 12:46:19" + "time": "2016-02-08 14:34:01" } ], "packages-dev": [ @@ -1666,6 +1666,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { + "wp-cli/php-cli-tools": 20, "composer/composer": 15 }, "prefer-stable": false, diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 0a3cd4978..87f81c8bb 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -263,13 +263,24 @@ private function show_multiple_fields( $data, $format ) { private static function show_table( $items, $fields ) { $table = new \cli\Table(); + $enabled = \cli\Colors::shouldColorize(); + if ( $enabled ) { + \cli\Colors::disable( true ); + } + $table->setHeaders( $fields ); foreach ( $items as $item ) { $table->addRow( array_values( \WP_CLI\Utils\pick_fields( $item, $fields ) ) ); } - $table->display(); + foreach( $table->getDisplayLines() as $line ) { + \WP_CLI::line( $line ); + } + + if ( $enabled ) { + \cli\Colors::enable( true ); + } } /** From 8dc3798991f5c2850babc091ff072ce44f47b7a2 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Mon, 8 Feb 2016 21:11:34 +0100 Subject: [PATCH 4053/5359] Avoid loading WordPress in `wp core verify-checksums` --- php/commands/core.php | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 541161cd5..71b4d8dbe 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -742,38 +742,57 @@ private static function get_clean_basedomain() { * @when before_wp_load */ public function version( $args = array(), $assoc_args = array() ) { - $versions_path = ABSPATH . 'wp-includes/version.php'; - - if ( !is_readable( $versions_path ) ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } - - include $versions_path; + $version = self::get_version(); // @codingStandardsIgnoreStart if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra' ) ) { - if ( preg_match( '/(\d)(\d+)-/', $tinymce_version, $match ) ) { + if ( preg_match( '/(\d)(\d+)-/', $version['tinymce'], $match ) ) { $human_readable_tiny_mce = $match[1] . '.' . $match[2]; } else { $human_readable_tiny_mce = ''; } echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( - 'wp-version' => $wp_version, - 'db-version' => $wp_db_version, + 'wp-version' => $version['wp'], + 'db-version' => $version['db'], 'mce-version' => ( $human_readable_tiny_mce ? - "$human_readable_tiny_mce ($tinymce_version)" - : $tinymce_version + "$human_readable_tiny_mce ({$version['tinymce']})" + : $version['tinymce'] ) ) ); } else { - WP_CLI::line( $wp_version ); + WP_CLI::line( $version['wp'] ); } // @codingStandardsIgnoreEnd } + /** + * Get version information from `wp-includes/version.php`. + * + * @return array { + * @type string $wp The WordPress version. + * @type int $db The WordPress DB revision. + * @type string $tinymce The TinyMCE version. + * } + */ + private static function get_version() { + $versions_path = ABSPATH . 'wp-includes/version.php'; + + if ( !is_readable( $versions_path ) ) { + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); + } + + include $versions_path; + + return array( + 'wp' => $wp_version, + 'db' => $wp_db_version, + 'tinymce' => $tinymce_version + ); + } + /** * Security copy of the core function with Requests - Gets the checksums for the given version of WordPress. * @@ -832,7 +851,7 @@ public function verify_checksums( $args, $assoc_args ) { } if ( empty( $wp_version ) ) { - WP_CLI::get_runner()->load_wordpress(); + $wp_version = self::get_version()['wp']; } $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); From 83470aa707ae1d849e3df713f76e63b3b3e50d6a Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Mon, 8 Feb 2016 21:44:50 +0100 Subject: [PATCH 4054/5359] =?UTF-8?q?Fix=20code=20syntax=20for=20prehistor?= =?UTF-8?q?ic=20PHP=20version=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/commands/core.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 71b4d8dbe..e624ed325 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -851,7 +851,8 @@ public function verify_checksums( $args, $assoc_args ) { } if ( empty( $wp_version ) ) { - $wp_version = self::get_version()['wp']; + $version = self::get_version(); + $wp_version = $version['wp']; } $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); From 0fe7d8653c66ece5a459a8fda481ad3ff4989192 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Mon, 8 Feb 2016 22:57:00 +0100 Subject: [PATCH 4055/5359] Automatically find locale from `wp-includes/version.php` --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index e624ed325..855b6d064 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -789,7 +789,8 @@ private static function get_version() { return array( 'wp' => $wp_version, 'db' => $wp_db_version, - 'tinymce' => $tinymce_version + 'tinymce' => $tinymce_version, + 'local_package' => $wp_local_package ); } @@ -853,6 +854,7 @@ public function verify_checksums( $args, $assoc_args ) { if ( empty( $wp_version ) ) { $version = self::get_version(); $wp_version = $version['wp']; + $wp_local_package = $version['local_package']; } $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); From c173123624978eabab4fa22ee455375703b9a5b0 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Mon, 8 Feb 2016 22:57:32 +0100 Subject: [PATCH 4056/5359] Update test for `wp core verify-checksums` without `wp-config.php` --- features/core-verify-checksums.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 055639275..8f74cd336 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -37,9 +37,9 @@ Feature: Validate checksums for WordPress install And I run `wp core download --version=4.3` When I try `wp core verify-checksums` - Then STDERR should contain: + Then STDOUT should be: """ - Error: wp-config.php not found. + Success: WordPress install verifies against checksums. """ When I run `wp core verify-checksums --version=4.3 --locale=en_US` From c8a36a1e62467c4e8bc3fd3c89934f100cfa18b4 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 00:39:16 +0100 Subject: [PATCH 4057/5359] Change `get_version` to `get_wp_details` and fix default value for `--locale` --- php/commands/core.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 855b6d064..b106d6061 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -742,7 +742,7 @@ private static function get_clean_basedomain() { * @when before_wp_load */ public function version( $args = array(), $assoc_args = array() ) { - $version = self::get_version(); + $version = self::get_wp_details(); // @codingStandardsIgnoreStart if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra' ) ) { @@ -775,7 +775,7 @@ public function version( $args = array(), $assoc_args = array() ) { * @type string $tinymce The TinyMCE version. * } */ - private static function get_version() { + private static function get_wp_details() { $versions_path = ABSPATH . 'wp-includes/version.php'; if ( !is_readable( $versions_path ) ) { @@ -852,9 +852,12 @@ public function verify_checksums( $args, $assoc_args ) { } if ( empty( $wp_version ) ) { - $version = self::get_version(); - $wp_version = $version['wp']; - $wp_local_package = $version['local_package']; + $details = self::get_wp_details(); + $wp_version = $details['wp']; + + if ( empty( $wp_local_package ) ) { + $wp_local_package = $details['local_package']; + } } $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); From 68d8cfa9caa19b0ab39a22ef707d4482b48a0cab Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 00:39:24 +0100 Subject: [PATCH 4058/5359] Fix documentation --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index b106d6061..1ea089d56 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -773,6 +773,7 @@ public function version( $args = array(), $assoc_args = array() ) { * @type string $wp The WordPress version. * @type int $db The WordPress DB revision. * @type string $tinymce The TinyMCE version. + * @type string $local_package The TinyMCE version. * } */ private static function get_wp_details() { From 4c813a3625bdfc7df226f17ae434b80c4226f9f1 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 00:40:11 +0100 Subject: [PATCH 4059/5359] Parse `wp-includes/version.php` instead of including it --- php/commands/core.php | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1ea089d56..08ec386fc 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -785,14 +785,42 @@ private static function get_wp_details() { "Pass --path=`path/to/wordpress` or run `wp core download`." ); } - include $versions_path; + $version_content = file_get_contents($versions_path, null, null, 6, 2048); - return array( - 'wp' => $wp_version, - 'db' => $wp_db_version, - 'tinymce' => $tinymce_version, - 'local_package' => $wp_local_package + $vars = array( + 'wp' => 'wp_version', + 'db' => 'wp_db_version', + 'tinymce' => 'tinymce_version', + 'local_package' => 'wp_local_package' ); + + $result = array(); + + foreach($vars as $key => $var) { + $result[$key] = self::find_var($var, $version_content); + } + + return $result; + } + + private static function find_var($key, $content) { + $start = strpos ($content, '$' . $key . ' = '); + + if( ! $start ) { + return ''; + } + + $start = $start + strlen($key) + 3; + $end = strpos($content, "\n", $start); + + $value = substr($content, $start, $end - $start); + $value = rtrim($value, ";"); + + if ($value[0] = "'" ) { + return trim($value, "'"); + } else { + return intval($value); + } } /** From 2d40fd6a375a6987c2fa0da1524e2b54d99c4e75 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 00:43:32 +0100 Subject: [PATCH 4060/5359] Fix test --- features/core-verify-checksums.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 8f74cd336..a27d2c354 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -36,7 +36,7 @@ Feature: Validate checksums for WordPress install Given an empty directory And I run `wp core download --version=4.3` - When I try `wp core verify-checksums` + When I run `wp core verify-checksums` Then STDOUT should be: """ Success: WordPress install verifies against checksums. From 7daa225095f70ddce19973fabacf005c6812bbc7 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 00:46:35 +0100 Subject: [PATCH 4061/5359] Fix coding style --- php/commands/core.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 08ec386fc..388c0aaf2 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -785,7 +785,7 @@ private static function get_wp_details() { "Pass --path=`path/to/wordpress` or run `wp core download`." ); } - $version_content = file_get_contents($versions_path, null, null, 6, 2048); + $version_content = file_get_contents( $versions_path, null, null, 6, 2048 ); $vars = array( 'wp' => 'wp_version', @@ -796,30 +796,30 @@ private static function get_wp_details() { $result = array(); - foreach($vars as $key => $var) { - $result[$key] = self::find_var($var, $version_content); + foreach( $vars as $key => $var ) { + $result[$key] = self::find_var( $var, $version_content ); } return $result; } - private static function find_var($key, $content) { - $start = strpos ($content, '$' . $key . ' = '); + private static function find_var( $key, $content ) { + $start = strpos( $content, '$' . $key . ' = ' ); if( ! $start ) { return ''; } - $start = $start + strlen($key) + 3; - $end = strpos($content, "\n", $start); + $start = $start + strlen( $key ) + 3; + $end = strpos( $content, "\n", $start ); - $value = substr($content, $start, $end - $start); - $value = rtrim($value, ";"); + $value = substr( $content, $start, $end - $start ); + $value = rtrim( $value, ";" ); - if ($value[0] = "'" ) { - return trim($value, "'"); + if ( $value[0] = "'" ) { + return trim( $value, "'" ); } else { - return intval($value); + return intval( $value ); } } From 12ae1be84e15c01013ac576b95e341e94f6a0cc3 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 01:27:32 +0100 Subject: [PATCH 4062/5359] Check if `$wp_local_package` is empty instead of set --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 388c0aaf2..fe0ab0d2d 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -889,7 +889,7 @@ public function verify_checksums( $args, $assoc_args ) { } } - $checksums = self::get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' ); + $checksums = self::get_core_checksums( $wp_version, ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); if ( ! is_array( $checksums ) ) { WP_CLI::error( "Couldn't get checksums from WordPress.org." ); From 16622647bb7bac4268fe375c3076937b0a572f47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Feb 2016 05:05:05 -0800 Subject: [PATCH 4063/5359] Add debug output for package loading --- php/WP_CLI/Runner.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2055cee95..3adde5022 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -616,7 +616,10 @@ public function start() { } if ( file_exists( $package_autoload ) ) { + WP_CLI::debug( 'Loading packages from: ' . $package_autoload ); require_once $package_autoload; + } else { + WP_CLI::debug( 'No package autoload found to load.' ); } if ( isset( $this->config['require'] ) ) { From e5c45d478dbdc144d48973b3115ab0c1a0361a71 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Feb 2016 05:26:12 -0800 Subject: [PATCH 4064/5359] Verify md5 hash when `wp core download` To permit offline use of the download cache, verification only happens when downloading a new copy of WordPress. --- features/core-download.feature | 10 ++++++++++ php/commands/core.php | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/features/core-download.feature b/features/core-download.feature index f35c49f56..c5f7f85f0 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -42,6 +42,16 @@ Feature: Download WordPress Error: Release not found. """ + Scenario: Verify release hash when downloading new version + Given an empty directory + + When I run `wp core download --version=4.4.1` + Then STDOUT should contain: + """ + md5 hash verified: 1907d1dbdac7a009d89224a516496b8d + Success: WordPress downloaded. + """ + Scenario: Core download to a directory specified by `--path` in custom command Given a WP install And a download-command.php file: diff --git a/php/commands/core.php b/php/commands/core.php index 541161cd5..d8024f3b1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -142,6 +142,18 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); } + $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); + if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); + } + + $md5_file = md5_file( $temp ); + if ( $md5_file === $md5_response->body ) { + WP_CLI::log( 'md5 hash verified: ' . $md5_file ); + } else { + WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})" ); + } + try { self::_extract( $temp, $download_dir ); } catch ( Exception $e ) { From 28091296c8d3b5a73423ef7a34632e285c2533e5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Feb 2016 06:15:53 -0800 Subject: [PATCH 4065/5359] Strict comparison is more precise --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d8024f3b1..92f20e460 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -138,12 +138,12 @@ public function download( $args, $assoc_args ) { $response = Utils\http_request( 'GET', $download_url, null, $headers, $options ); if ( 404 == $response->status_code ) { WP_CLI::error( "Release not found. Double-check locale or version." ); - } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { + } else if ( 20 !== substr( $response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); } $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); - if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + if ( 20 !== substr( $md5_response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); } From cd6580b05d38c38156388e1770ea7bab7acc837d Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 17:18:49 +0100 Subject: [PATCH 4066/5359] Clean, document and reorder `verify-checksums` methods --- php/commands/core.php | 202 ++++++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 98 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index fe0ab0d2d..50812cc2f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -742,118 +742,30 @@ private static function get_clean_basedomain() { * @when before_wp_load */ public function version( $args = array(), $assoc_args = array() ) { - $version = self::get_wp_details(); + $details = self::get_wp_details(); // @codingStandardsIgnoreStart if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra' ) ) { - if ( preg_match( '/(\d)(\d+)-/', $version['tinymce'], $match ) ) { + if ( preg_match( '/(\d)(\d+)-/', $details['tinymce_version'], $match ) ) { $human_readable_tiny_mce = $match[1] . '.' . $match[2]; } else { $human_readable_tiny_mce = ''; } echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( - 'wp-version' => $version['wp'], - 'db-version' => $version['db'], + 'wp-version' => $details['wp_version'], + 'db-version' => $details['wp_db_version'], 'mce-version' => ( $human_readable_tiny_mce ? - "$human_readable_tiny_mce ({$version['tinymce']})" - : $version['tinymce'] + "$human_readable_tiny_mce ({$details['tinymce_version']})" + : $details['tinymce_version'] ) ) ); } else { - WP_CLI::line( $version['wp'] ); + WP_CLI::line( $details['wp_version'] ); } // @codingStandardsIgnoreEnd } - /** - * Get version information from `wp-includes/version.php`. - * - * @return array { - * @type string $wp The WordPress version. - * @type int $db The WordPress DB revision. - * @type string $tinymce The TinyMCE version. - * @type string $local_package The TinyMCE version. - * } - */ - private static function get_wp_details() { - $versions_path = ABSPATH . 'wp-includes/version.php'; - - if ( !is_readable( $versions_path ) ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } - - $version_content = file_get_contents( $versions_path, null, null, 6, 2048 ); - - $vars = array( - 'wp' => 'wp_version', - 'db' => 'wp_db_version', - 'tinymce' => 'tinymce_version', - 'local_package' => 'wp_local_package' - ); - - $result = array(); - - foreach( $vars as $key => $var ) { - $result[$key] = self::find_var( $var, $version_content ); - } - - return $result; - } - - private static function find_var( $key, $content ) { - $start = strpos( $content, '$' . $key . ' = ' ); - - if( ! $start ) { - return ''; - } - - $start = $start + strlen( $key ) + 3; - $end = strpos( $content, "\n", $start ); - - $value = substr( $content, $start, $end - $start ); - $value = rtrim( $value, ";" ); - - if ( $value[0] = "'" ) { - return trim( $value, "'" ); - } else { - return intval( $value ); - } - } - - /** - * Security copy of the core function with Requests - Gets the checksums for the given version of WordPress. - * - * @param string $version Version string to query. - * @param string $locale Locale to query. - * @return bool|array False on failure. An array of checksums on success. - */ - private static function get_core_checksums( $version, $locale ) { - $url = 'https://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); - - $options = array( - 'timeout' => 30 - ); - - $headers = array( - 'Accept' => 'application/json' - ); - $response = Utils\http_request( 'GET', $url, null, $headers, $options ); - - if ( ! $response->success || 200 != $response->status_code ) - return false; - - $body = trim( $response->body ); - $body = json_decode( $body, true ); - - if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) - return false; - - return $body['checksums']; - } - /** * Verify WordPress files against WordPress.org's checksums. * @@ -882,14 +794,15 @@ public function verify_checksums( $args, $assoc_args ) { if ( empty( $wp_version ) ) { $details = self::get_wp_details(); - $wp_version = $details['wp']; + $wp_version = $details['wp_version']; if ( empty( $wp_local_package ) ) { - $wp_local_package = $details['local_package']; + $wp_local_package = $details['wp_local_package']; } } - $checksums = self::get_core_checksums( $wp_version, ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); + $checksums = self::get_core_checksums( $wp_version, + ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); if ( ! is_array( $checksums ) ) { WP_CLI::error( "Couldn't get checksums from WordPress.org." ); @@ -922,6 +835,99 @@ public function verify_checksums( $args, $assoc_args ) { } } + /** + * Get version information from `wp-includes/version.php`. + * + * @return array { + * @type string $wp_version The WordPress version. + * @type int $wp_db_version The WordPress DB revision. + * @type string $tinymce_version The TinyMCE version. + * @type string $wp_local_package The TinyMCE version. + * } + */ + private static function get_wp_details() { + $versions_path = ABSPATH . 'wp-includes/version.php'; + + if ( ! is_readable( $versions_path ) ) { + WP_CLI::error( + "This does not seem to be a WordPress install.\n" . + "Pass --path=`path/to/wordpress` or run `wp core download`." ); + } + + $version_content = file_get_contents( $versions_path, null, null, 6, 2048 ); + + $vars = [ 'wp_version', 'wp_db_version', 'tinymce_version', 'wp_local_package' ]; + $result = [ ]; + + foreach ( $vars as $var_name ) { + $result[ $var_name ] = self::find_var( $var_name, $version_content ); + } + + return $result; + } + + /** + * Search for the value assigned to variable `$var_name` in PHP code `$code`. + * + * This is equivalent to matching the `\$VAR_NAME = ([^;]+)` regular expression and returning + * the first match either as a `string` or as an `integer` (depending if it's surrounded by + * quotes or not). + * + * @param string $var_name Variable name to search for. + * @param string $code PHP code to search in. + * + * @return int|string|null + */ + private static function find_var( $var_name, $code ) { + $start = strpos( $code, '$' . $var_name . ' = ' ); + + if ( ! $start ) { + return null; + } + + $start = $start + strlen( $var_name ) + 3; + $end = strpos( $code, ";", $start ); + + $value = substr( $code, $start, $end - $start ); + + if ( $value[0] = "'" ) { + return trim( $value, "'" ); + } else { + return intval( $value ); + } + } + + /** + * Security copy of the core function with Requests - Gets the checksums for the given version of WordPress. + * + * @param string $version Version string to query. + * @param string $locale Locale to query. + * @return bool|array False on failure. An array of checksums on success. + */ + private static function get_core_checksums( $version, $locale ) { + $url = 'https://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); + + $options = array( + 'timeout' => 30 + ); + + $headers = array( + 'Accept' => 'application/json' + ); + $response = Utils\http_request( 'GET', $url, null, $headers, $options ); + + if ( ! $response->success || 200 != $response->status_code ) + return false; + + $body = trim( $response->body ); + $body = json_decode( $body, true ); + + if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) + return false; + + return $body['checksums']; + } + /** * Update WordPress. * From 87b5980576d8aabe66302b16b802ff5996b6829c Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 17:19:16 +0100 Subject: [PATCH 4067/5359] Add feature for `wp core version` --- features/core-version.feature | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 features/core-version.feature diff --git a/features/core-version.feature b/features/core-version.feature new file mode 100644 index 000000000..978c2960e --- /dev/null +++ b/features/core-version.feature @@ -0,0 +1,19 @@ +Feature: Find version for WordPress install + + Scenario: Verify core version + Given a WP install + And I run `wp core download --version=4.4.2 --force` + + When I run `wp core version` + Then STDOUT should be: + """ + 4.4.2 + """ + + When I run `wp core version --extra` + Then STDOUT should be: + """ + WordPress version: 4.4.2 + Database revision: 35700 + TinyMCE version: 4.208 (4208-20151113) + """ \ No newline at end of file From 34ca6b8e7ad54fa7646aa07d188700ba76fe8245 Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 17:53:22 +0100 Subject: [PATCH 4068/5359] Correct array syntax for PHP 5.3 --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 50812cc2f..de13e9395 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -856,8 +856,8 @@ private static function get_wp_details() { $version_content = file_get_contents( $versions_path, null, null, 6, 2048 ); - $vars = [ 'wp_version', 'wp_db_version', 'tinymce_version', 'wp_local_package' ]; - $result = [ ]; + $vars = array( 'wp_version', 'wp_db_version', 'tinymce_version', 'wp_local_package' ); + $result = array(); foreach ( $vars as $var_name ) { $result[ $var_name ] = self::find_var( $var_name, $version_content ); From 0566eb42cd1daf2b1484e3aaeb76481a2a5d9cae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Feb 2016 08:57:04 -0800 Subject: [PATCH 4069/5359] Revert "Strict comparison is more precise" This reverts commit 28091296c8d3b5a73423ef7a34632e285c2533e5. --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 92f20e460..d8024f3b1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -138,12 +138,12 @@ public function download( $args, $assoc_args ) { $response = Utils\http_request( 'GET', $download_url, null, $headers, $options ); if ( 404 == $response->status_code ) { WP_CLI::error( "Release not found. Double-check locale or version." ); - } else if ( 20 !== substr( $response->status_code, 0, 2 ) ) { + } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); } $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); - if ( 20 !== substr( $md5_response->status_code, 0, 2 ) ) { + if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); } From 7af8e2e44ca44abb8a02accd955e10fa52f2310e Mon Sep 17 00:00:00 2001 From: mbovel <matthieu@bovel.net> Date: Tue, 9 Feb 2016 18:18:59 +0100 Subject: [PATCH 4070/5359] Add newline --- features/core-version.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-version.feature b/features/core-version.feature index 978c2960e..3904c5b23 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -16,4 +16,4 @@ Feature: Find version for WordPress install WordPress version: 4.4.2 Database revision: 35700 TinyMCE version: 4.208 (4208-20151113) - """ \ No newline at end of file + """ From c39d284dcb50eab58190876d1c072aa2752475af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Feb 2016 10:14:37 -0800 Subject: [PATCH 4071/5359] Default title for `wp media import` images shouldn't include extension This better mirrors core's behavior. --- features/media-import.feature | 2 +- php/commands/media.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/media-import.feature b/features/media-import.feature index 81a05db28..a33e787db 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -71,7 +71,7 @@ Feature: Manage WordPress attachments When I run `wp post get {ATTACHMENT_ID} --field=title` Then STDOUT should be: """ - large-image.jpg + large-image """ Scenario: Import a file and persist its original metadata diff --git a/php/commands/media.php b/php/commands/media.php index 15cf3a80d..fd77715e4 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -182,7 +182,7 @@ function import( $args, $assoc_args = array() ) { } if ( empty( $post_array['post_title'] ) ) { - $post_array['post_title'] = $file_array['name']; + $post_array['post_title'] = preg_replace( '/\.[^.]+$/', '', basename( $file ) ); } // Deletes the temporary file. From 9e0ffbc901f90d0011e65852ef60de0c3360661b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Feb 2016 05:15:02 -0800 Subject: [PATCH 4072/5359] Failing test case for #2468 --- features/core-update.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/core-update.feature b/features/core-update.feature index ef52aa8ea..53db29ba2 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -193,3 +193,19 @@ Feature: Update WordPress core Then STDOUT should not be empty When I run `wp post create --post_title='Test post' --porcelain` Then STDOUT should be a number + + @less-than-php-7 + Scenario: Minor update on an unlocalized WordPress release + Given a WP install + + When I run `wp core download --version=4.0 --locale=es_ES --force` + Then STDOUT should contain: + """ + Success: WordPress downloaded. + """ + + When I run `wp core update --minor` + Then STDOUT should contain: + """ + Success: WordPress updated successfully + """ From ef24a31153aff410e552fd62e0e91e9c3ab40638 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Feb 2016 05:58:38 -0800 Subject: [PATCH 4073/5359] Use WP.org's download offer for minor updates Sometimes localized versions of WordPress don't have a minor release build, and we need to use the en_US partial instead. Also, when performing `wp core check-update`, don't list release files that don't exist. --- features/core-check-update.feature | 19 ++++++++++++++++ features/core-update.feature | 8 ++++++- php/commands/core.php | 36 ++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 10a650884..5fb91fe9e 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -40,3 +40,22 @@ Feature: Check for more recent versions """ 1 """ + + @less-than-php-7 + Scenario: No minor updates for an unlocalized WordPress release + Given a WP install + + When I run `wp core download --version=4.0 --locale=es_ES --force` + Then STDOUT should contain: + """ + Success: WordPress downloaded. + """ + + When I run `wp core check-update --minor` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 4.0.1 | minor | https://es.wordpress.org/wordpress-4.0.1-es_ES.zip | + And STDERR should contain: + """ + Warning: No release found for 4.0.10 (es_ES) + """ diff --git a/features/core-update.feature b/features/core-update.feature index 53db29ba2..93eec5bf9 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -197,6 +197,7 @@ Feature: Update WordPress core @less-than-php-7 Scenario: Minor update on an unlocalized WordPress release Given a WP install + And an empty cache When I run `wp core download --version=4.0 --locale=es_ES --force` Then STDOUT should contain: @@ -207,5 +208,10 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Success: WordPress updated successfully + Updating to version 4.0.10 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.10-partial-0.zip + """ + And STDOUT should contain: + """ + Success: WordPress updated successfully. """ diff --git a/php/commands/core.php b/php/commands/core.php index 4ec4592de..1424d2c3a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -976,16 +976,6 @@ function update( $args, $assoc_args ) { $update = $from_api = null; $upgrader = 'WP_CLI\\CoreUpgrader'; - if ( empty( $args[0] ) && empty( $assoc_args['version'] ) && \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) ) { - $updates = $this->get_updates( array( 'minor' => true ) ); - if ( ! empty( $updates ) ) { - $assoc_args['version'] = $updates[0]['version']; - } else { - WP_CLI::success( 'WordPress is at the latest minor release.' ); - return; - } - } - if ( ! empty( $args[0] ) ) { $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; @@ -1010,8 +1000,23 @@ function update( $args, $assoc_args ) { wp_version_check(); $from_api = get_site_transient( 'update_core' ); - if ( ! empty( $from_api->updates ) ) { - list( $update ) = $from_api->updates; + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) ) { + foreach( $from_api->updates as $offer ) { + $sem_ver = Utils\get_named_sem_ver( $offer->version, $wp_version ); + if ( ! $sem_ver || 'patch' !== $sem_ver ) { + continue; + } + $update = $offer; + break; + } + if ( empty( $update ) ) { + WP_CLI::success( 'WordPress is at the latest minor release.' ); + return; + } + } else { + if ( ! empty( $from_api->updates ) ) { + list( $update ) = $from_api->updates; + } } } else if ( \WP_CLI\Utils\wp_version_compare( $assoc_args['version'], '<' ) @@ -1224,6 +1229,13 @@ private function get_updates( $assoc_args ) { continue; } + $download_url = $this->get_download_url( $release_version, $locale ); + $response = Utils\http_request( 'HEAD', $download_url ); + if ( 20 != substr( $response->status_code, 0, 2 ) ) { + WP_CLI::warning( "No release found for {$release_version} ({$locale})" ); + continue; + } + $updates[ $update_type ] = array( 'version' => $release_version, 'update_type' => $update_type, From a8ec806d42a0006d0264e26acf3c2767c9e6dc51 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Feb 2016 06:13:40 -0800 Subject: [PATCH 4074/5359] Better idea: use core's versions API to check for updates We should've done this in the very beginning. Now lists the partial package for update when it's available --- features/core-check-update.feature | 18 +++++------- php/commands/core.php | 44 ++++++------------------------ 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 5fb91fe9e..600beba47 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,9 +9,9 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.4.2 | major | https://wordpress.org/wordpress-4.4.2.zip | - | 3.8.13 | minor | https://wordpress.org/wordpress-3.8.13.zip | + | version | update_type | package_url | + | 4.4.2 | major | https://downloads.wordpress.org/release/wordpress-4.4.2.zip | + | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -21,8 +21,8 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.4.2 | major | https://wordpress.org/wordpress-4.4.2.zip | + | version | update_type | package_url | + | 4.4.2 | major | https://downloads.wordpress.org/release/wordpress-4.4.2.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -33,7 +33,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.13 | minor | https://wordpress.org/wordpress-3.8.13.zip | + | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -54,8 +54,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.1 | minor | https://es.wordpress.org/wordpress-4.0.1-es_ES.zip | - And STDERR should contain: - """ - Warning: No release found for 4.0.10 (es_ES) - """ + | 4.0.10 | minor | https://downloads.wordpress.org/release/wordpress-4.0.10-partial-0.zip | diff --git a/php/commands/core.php b/php/commands/core.php index 1424d2c3a..6fc55c18e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1180,40 +1180,21 @@ private function get_download_url($version, $locale = 'en_US', $file_type = 'zip * Returns update information */ private function get_updates( $assoc_args ) { - global $wp_version; - $versions_path = ABSPATH . 'wp-includes/version.php'; - include $versions_path; - - $url = 'https://api.wordpress.org/core/stable-check/1.0/'; - - $options = array( - 'timeout' => 30 - ); - $headers = array( - 'Accept' => 'application/json' - ); - $response = Utils\http_request( 'GET', $url, $headers, $options ); - - if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( "Failed to get latest version list." ); + wp_version_check(); + $from_api = get_site_transient( 'update_core' ); + if ( ! $from_api ) { + return array(); } - $release_data = json_decode( $response->body ); - $release_versions = array_keys( (array) $release_data ); - usort( $release_versions, function( $a, $b ){ - return 1 === version_compare( $a, $b ); - }); - - $locale = get_locale(); $compare_version = str_replace( '-src', '', $GLOBALS['wp_version'] ); $updates = array( 'major' => false, 'minor' => false, ); - foreach ( $release_versions as $release_version ) { + foreach ( $from_api->updates as $offer ) { - $update_type = Utils\get_named_sem_ver( $release_version, $compare_version ); + $update_type = Utils\get_named_sem_ver( $offer->version, $compare_version ); if ( ! $update_type ) { continue; } @@ -1225,21 +1206,14 @@ private function get_updates( $assoc_args ) { $update_type = 'minor'; } - if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $release_version, $updates[ $update_type ]['version'] ) ) { - continue; - } - - $download_url = $this->get_download_url( $release_version, $locale ); - $response = Utils\http_request( 'HEAD', $download_url ); - if ( 20 != substr( $response->status_code, 0, 2 ) ) { - WP_CLI::warning( "No release found for {$release_version} ({$locale})" ); + if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $offer->version, $updates[ $update_type ]['version'] ) ) { continue; } $updates[ $update_type ] = array( - 'version' => $release_version, + 'version' => $offer->version, 'update_type' => $update_type, - 'package_url' => $this->get_download_url( $release_version, $locale ) + 'package_url' => ! empty( $offer->packages->partial ) ? $offer->packages->partial : $offer->packages->full, ); } From 19b35f9c6597af251fb115a06e577aaeb83ee0c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 12 Feb 2016 09:05:13 -0200 Subject: [PATCH 4075/5359] Add basic tests for `wp core download` --- features/core.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/features/core.feature b/features/core.feature index 13331c1c5..0bc830cd0 100644 --- a/features/core.feature +++ b/features/core.feature @@ -240,3 +240,23 @@ Feature: Manage WordPress installation """ Hello world! """ + + Scenario: Download WordPress + Given an empty directory + + When I run `wp core download` + Then STDOUT should contain: + """ + Success: WordPress downloaded. + """ + And the wp-settings.php file should exist + + Scenario: Don't download WordPress when files are already present + Given an empty directory + And WP files + + When I try `wp core download` + Then STDERR should be: + """ + Error: WordPress files seem to already be present here. + """ From 0f113a97d9159422590951437b41781eb0ed2d23 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 12 Feb 2016 09:08:54 -0200 Subject: [PATCH 4076/5359] Check for permission before downloading WordPress when running `wp core download` --- php/commands/core.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4ec4592de..4f815d392 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -86,6 +86,10 @@ public function download( $args, $assoc_args ) { WP_CLI::launch( Utils\esc_cmd( $mkdir, $download_dir ) ); } + if ( ! is_writable( $download_dir ) ) { + WP_CLI::error( sprintf( "%s is not writable by current user", $download_dir ) ); + } + $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); if ( isset( $assoc_args['version'] ) ) { From 6017a94f4ac668cbe242ae0712d10d4a56e55f80 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Fri, 12 Feb 2016 09:15:54 -0200 Subject: [PATCH 4077/5359] Check for permission before creating directory when running `wp core download` --- php/commands/core.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 4f815d392..ac61a2d28 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -80,7 +80,11 @@ public function download( $args, $assoc_args ) { if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && $wordpress_present ) WP_CLI::error( 'WordPress files seem to already be present here.' ); - if ( !is_dir( $download_dir ) ) { + if ( ! is_dir( $download_dir ) ) { + if ( ! is_writable( dirname( $download_dir ) ) ) { + WP_CLI::error( sprintf( "Insufficient permission to create directory %s", $download_dir ) ); + } + WP_CLI::log( sprintf( 'Creating directory %s', $download_dir ) ); $mkdir = \WP_CLI\Utils\is_windows() ? 'mkdir %s' : 'mkdir -p %s'; WP_CLI::launch( Utils\esc_cmd( $mkdir, $download_dir ) ); From 02e31d3009260d8d85e9da788c6d340aea02c9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 13 Feb 2016 01:07:06 +0100 Subject: [PATCH 4078/5359] Make PHP look leaner on GitHub --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index 71f819ca1..ddb90c301 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,7 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true indent_style = tab +indent_size = 4 [*.json,*.yml,*.feature] indent_style = space From b442a98ae7f9f7dadf3e2b549a5136bb721571fe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Feb 2016 04:40:44 -0800 Subject: [PATCH 4079/5359] Require WP 4.0 or greater for this step --- features/core-update.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-update.feature b/features/core-update.feature index 93eec5bf9..2cb55be5f 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -194,7 +194,7 @@ Feature: Update WordPress core When I run `wp post create --post_title='Test post' --porcelain` Then STDOUT should be a number - @less-than-php-7 + @less-than-php-7 @require-wp-4.0 Scenario: Minor update on an unlocalized WordPress release Given a WP install And an empty cache From c2b562295478b65da9e4380467ba9e44066b5046 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Feb 2016 08:47:21 -0800 Subject: [PATCH 4080/5359] Set default `indent_size=4` when scaffolding `.editorconfig` This makes indentation more readable in editors. --- templates/.editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/.editorconfig b/templates/.editorconfig index e1cc194eb..79207a40c 100644 --- a/templates/.editorconfig +++ b/templates/.editorconfig @@ -12,6 +12,7 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true indent_style = tab +indent_size = 4 [{.jshintrc,*.json,*.yml}] indent_style = space From 62ed490f3d070df285ed32ecc83305c0edb44a47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Feb 2016 08:49:01 -0800 Subject: [PATCH 4081/5359] Note: mu-plugins are still loaded with `--skip-plugins` flag --- php/config-spec.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 3fda4edff..cbaa958fd 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -31,10 +31,10 @@ 'skip-plugins' => array( 'runtime' => '[=<plugin>]', 'file' => '<list>', - 'desc' => 'Skip loading all or some plugins.', + 'desc' => 'Skip loading all or some plugins. Note: mu-plugins are still loaded.', 'default' => '', ), - + 'skip-themes' => array( 'runtime' => '[=<theme>]', 'file' => '<list>', From 30354ca5e6955e8d917793a594c3d2b5e58d004a Mon Sep 17 00:00:00 2001 From: Mark Jaquith <mark.github@txfx.net> Date: Thu, 18 Feb 2016 09:29:55 -0500 Subject: [PATCH 4082/5359] Avoid PHP Notice about undefined index Was getting this: > Notice: Undefined index: name in `/Users/mark/.composer/vendor/wp-cli/wp-cli/php/export/class-wp-export-query.php` on line `176` --- php/export/class-wp-export-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index 8cbbb89d1..e228fbfcd 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -173,7 +173,7 @@ private function post_type_where() { } // Multiple post types - if ( is_array( $post_types_filters['name'] ) ) { + if ( isset( $post_types_filters['name'] ) && is_array( $post_types_filters['name'] ) ) { $post_types = array(); foreach ( $post_types_filters['name'] as $post_type ) { if ( post_type_exists( $post_type ) ) { From e00ce0f69352e03ea2cbbe87cf19700378bb7fdd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Feb 2016 09:31:17 -0800 Subject: [PATCH 4083/5359] Add compatibility with WP 4.5 by loading `WP_Metadata_Lazyloader` Introduced in https://core.trac.wordpress.org/changeset/36566/ --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 000db74a5..975c59f59 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -160,6 +160,7 @@ Utils\maybe_require( '4.0', ABSPATH . WPINC . '/session.php' ); require( ABSPATH . WPINC . '/meta.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-meta-query.php' ); +Utils\maybe_require( '4.5-alpha-35776', ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php' ); require( ABSPATH . WPINC . '/general-template.php' ); require( ABSPATH . WPINC . '/link-template.php' ); require( ABSPATH . WPINC . '/author-template.php' ); From ec889e62ebbfbaadf196fa25bb4290994ed6f7ff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Feb 2016 12:21:54 -0800 Subject: [PATCH 4084/5359] Annotate public internal APIs with categories --- php/class-wp-cli.php | 62 +++++++++++++++++++++++++++++++++++--------- php/utils.php | 6 +++-- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e1fc3025a..d87cb5e2e 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -247,11 +247,13 @@ public static function add_command( $name, $callable, $args = array() ) { /** * Display a message in the CLI and end with a newline. - * Ignores --quiet flag. To respect, use WP_CLI::log() + * Ignores `--quiet` flag. To respect, use `WP_CLI::log()` * * @access public + * @category Output * - * @param string $message + * @param string $message Message to display to the end user. + * @return null */ public static function line( $message = '' ) { echo $message . "\n"; @@ -261,6 +263,7 @@ public static function line( $message = '' ) { * Log an informational message. * * @access public + * @category Output * * @param string $message */ @@ -272,6 +275,7 @@ public static function log( $message ) { * Display a success in the CLI and end with a newline. * * @access public + * @category Output * * @param string $message */ @@ -280,10 +284,13 @@ public static function success( $message ) { } /** - * Log information when --debug flag is used. - * Helpful for optionally showing greater detail when needed. + * Display debug message prefixed with "Debug: " when `--debug` is used. + * + * Helpful for optionally showing greater detail when needed. Debug message + * is written to STDERR, and includes script execution time. * * @access public + * @category Output * * @param string $message */ @@ -292,23 +299,49 @@ public static function debug( $message ) { } /** - * Display a warning in the CLI and end with a newline. + * Display warning message prefixed with "Warning: ". + * + * Warning message is written to STDERR. + * + * ``` + * # `wp plugin activate` skips activation when plugin is network active. + * $status = $this->get_status( $plugin->file ); + * // Network-active is the highest level of activation status + * if ( 'active-network' === $status ) { + * WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); + * continue; + * } + * ``` * * @access public + * @category Output * - * @param string $message + * @param string $message Message to write to STDERR. + * @return null */ public static function warning( $message ) { self::$logger->warning( self::error_to_string( $message ) ); } /** - * Display an error in the CLI and end with a newline. + * Display error message prefixed with "Error: " and exits script. + * + * Error message is written to STDERR. Defaults to halting + * script execution with return code 1. + * + * ``` + * # `wp cache flush` considers flush failure to be a fatal error. + * if ( false === wp_cache_flush() ) { + * WP_CLI::error( 'The object cache could not be flushed.' ); + * } + * ``` * * @access public + * @category Output * - * @param string|WP_Error $message - * @param bool $exit if true, the script will exit() + * @param string|WP_Error $message Message to write to STDERR. + * @param boolean|integer $exit True defaults to exit(1). + * @return null */ public static function error( $message, $exit = true ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { @@ -375,6 +408,9 @@ public static function get_value_from_arg_or_stdin( $args, $index ) { /** * Read a value, from various formats. * + * @access public + * @category Input + * * @param mixed $value * @param array $assoc_args */ @@ -432,12 +468,14 @@ public static function error_to_string( $errors ) { } /** - * Launch an external process that takes over I/O. + * Launch an arbitrary external process that takes over I/O. + * + * @access public + * @category Execution * * @param string Command to call * @param bool Whether to exit if the command returns an error status - * @param bool Whether to return an exit status (default) or detailed execution results - * + * @param bool Whether to return an exit status (default) or detailed execution results. * @return int|ProcessRun The command exit status, or a ProcessRun instance */ public static function launch( $command, $exit_on_error = true, $return_detailed = false ) { diff --git a/php/utils.php b/php/utils.php index 315eb31ca..a3152b1bf 100644 --- a/php/utils.php +++ b/php/utils.php @@ -239,13 +239,15 @@ function wp_version_compare( $since, $operator ) { } /** - * Output items in a table, JSON, CSV, ids, or the total count + * Render a collection of items as an ASCII table, JSON, CSV, YAML, list of ids, or count. * * @access public + * @category Output * - * @param string $format Format to use: 'table', 'json', 'csv', 'ids', 'count' + * @param string $format Format to use: 'table', 'json', 'csv', 'yaml', 'ids', 'count' * @param array $items Data to output * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list + * @return null */ function format_items( $format, $items, $fields ) { $assoc_args = compact( 'format', 'fields' ); From 7dcbfa306ce894f6a3f34f97681812fd01c66478 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Feb 2016 16:12:52 -0800 Subject: [PATCH 4085/5359] Round of edits and enhancements for public APIs --- php/class-wp-cli.php | 104 +++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 23 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d87cb5e2e..f5318b7e9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -246,8 +246,10 @@ public static function add_command( $name, $callable, $args = array() ) { } /** - * Display a message in the CLI and end with a newline. - * Ignores `--quiet` flag. To respect, use `WP_CLI::log()` + * Display informational message without prefix, and ignore `--quiet`. + * + * Message is written to STDOUT. `WP_CLI::log()` is typically recommended; + * `WP_CLI::line()` is included for historical compat. * * @access public * @category Output @@ -260,24 +262,46 @@ public static function line( $message = '' ) { } /** - * Log an informational message. + * Display informational message without prefix. + * + * Message is written to STDOUT, or discarded when `--quiet` flag is supplied. + * + * ``` + * # `wp cli update` lets user know of each step in the update process. + * WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); + * ``` * * @access public * @category Output * - * @param string $message + * @param string $message Message to write to STDOUT. */ public static function log( $message ) { self::$logger->info( $message ); } /** - * Display a success in the CLI and end with a newline. + * Display success message prefixed with "Success: ". + * + * Success message is written to STDOUT. + * + * Typically recommended to inform user of successful script conclusion. + * + * ``` + * # wp rewrite flush expects 'rewrite_rules' option to be set after flush. + * flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); + * if ( ! get_option( 'rewrite_rules' ) ) { + * WP_CLI::warning( "Rewrite rules are empty." ); + * } else { + * WP_CLI::success( 'Rewrite rules flushed.' ); + * } + * ``` * * @access public * @category Output * - * @param string $message + * @param string $message Message to write to STDOUT. + * @return null */ public static function success( $message ) { self::$logger->success( $message ); @@ -286,13 +310,30 @@ public static function success( $message ) { /** * Display debug message prefixed with "Debug: " when `--debug` is used. * - * Helpful for optionally showing greater detail when needed. Debug message - * is written to STDERR, and includes script execution time. + * Debug message is written to STDERR, and includes script execution time. + * + * Helpful for optionally showing greater detail when needed. Used throughout + * WP-CLI bootstrap process for easier debugging and profiling. + * + * ``` + * # Called in `WP_CLI\Runner::set_wp_root()`. + * private static function set_wp_root( $path ) { + * define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); + * WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH ); + * $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); + * } + * + * # Debug details only appear when `--debug` is used. + * # $ wp --debug + * # [...] + * # Debug: ABSPATH defined: /srv/www/wordpress-develop.dev/src/ (0.225s) + * ``` * * @access public * @category Output * - * @param string $message + * @param string $message Message to write to STDERR. + * @return null */ public static function debug( $message ) { self::$logger->debug( self::error_to_string( $message ) ); @@ -303,6 +344,9 @@ public static function debug( $message ) { * * Warning message is written to STDERR. * + * Use instead of `WP_CLI::debug()` when script execution should be permitted + * to continue. + * * ``` * # `wp plugin activate` skips activation when plugin is network active. * $status = $this->get_status( $plugin->file ); @@ -324,10 +368,13 @@ public static function warning( $message ) { } /** - * Display error message prefixed with "Error: " and exits script. + * Display error message prefixed with "Error: " and exit script. + * + * Error message is written to STDERR. Defaults to halting script execution + * with return code 1. * - * Error message is written to STDERR. Defaults to halting - * script execution with return code 1. + * Use `WP_CLI::warning()` instead when script execution should be permitted + * to continue. * * ``` * # `wp cache flush` considers flush failure to be a fatal error. @@ -470,13 +517,22 @@ public static function error_to_string( $errors ) { /** * Launch an arbitrary external process that takes over I/O. * + * ``` + * # `wp core download` falls back to the `tar` binary when PharData isn't available + * if ( ! class_exists( 'PharData' ) ) { + * $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; + * WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); + * return; + * } + * ``` + * * @access public * @category Execution * - * @param string Command to call - * @param bool Whether to exit if the command returns an error status - * @param bool Whether to return an exit status (default) or detailed execution results. - * @return int|ProcessRun The command exit status, or a ProcessRun instance + * @param string $command External process to launch. + * @param boolean $exit_on_error Whether to exit if the command returns an elevated return code. + * @param boolean $return_detailed Whether to return an exit status (default) or detailed execution results. + * @return int|ProcessRun The command exit status, or a ProcessRun object for full details. */ public static function launch( $command, $exit_on_error = true, $return_detailed = false ) { @@ -494,15 +550,17 @@ public static function launch( $command, $exit_on_error = true, $return_detailed } /** - * Launch another WP-CLI command using the runtime arguments for the current process + * Run a WP-CLI command in a new process reusing the current runtime arguments. * - * @param string Command to call - * @param array $args Positional arguments to use - * @param array $assoc_args Associative arguments to use - * @param bool Whether to exit if the command returns an error status - * @param bool Whether to return an exit status (default) or detailed execution results - * @param array $runtime_args Override one or more global args (path,url,user,allow-root) + * @access public + * @category Execution * + * @param string $command WP-CLI command to call. + * @param array $args Positional arguments to include when calling the command. + * @param array $assoc_args Associative arguments to include when calling the command. + * @param bool $exit_on_error Whether to exit if the command returns an elevated return code. + * @param bool $return_detailed Whether to return an exit status (default) or detailed execution results. + * @param array $runtime_args Override one or more global args (path,url,user,allow-root) * @return int|ProcessRun The command exit status, or a ProcessRun instance */ public static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false, $runtime_args = array() ) { From c8800cb2bc4e42725f3ec047ea57f38759799987 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 19 Feb 2016 04:03:17 -0800 Subject: [PATCH 4086/5359] Use more robust failed download checking in `wp cli update` Because `php file.xml` returns exit code `0`, we need to run a command where only WP-CLI will return the string we expect. --- features/cli.feature | 32 ++++++++++++++++++++++++++++++++ php/commands/cli.php | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/features/cli.feature b/features/cli.feature index 68ed68fde..081ed727b 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -32,6 +32,16 @@ Feature: `wp cli` tasks Given an empty directory And a new Phar with version "0.0.0" + When I run `{PHAR_PATH} --info` + Then STDOUT should contain: + """ + WP-CLI version + """ + And STDOUT should contain: + """ + 0.0.0 + """ + When I run `{PHAR_PATH} cli update --yes` Then STDOUT should contain: """ @@ -40,11 +50,27 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + When I run `{PHAR_PATH} --info` + Then STDOUT should contain: + """ + WP-CLI version + """ + And STDOUT should not contain: + """ + 0.0.0 + """ + @github-api Scenario: Patch update from 0.14.0 to 0.14.1 Given an empty directory And a new Phar with version "0.14.0" + When I run `{PHAR_PATH} --version` + Then STDOUT should be: + """ + WP-CLI 0.14.0 + """ + When I run `{PHAR_PATH} cli update --patch --yes` Then STDOUT should contain: """ @@ -53,6 +79,12 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + When I run `{PHAR_PATH} --version` + Then STDOUT should be: + """ + WP-CLI 0.14.1 + """ + @github-api Scenario: Not a patch update from 0.14.0 Given an empty directory diff --git a/php/commands/cli.php b/php/commands/cli.php index a021f6acd..f68e19d25 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -181,9 +181,9 @@ public function update( $_, $assoc_args ) { $allow_root = WP_CLI::get_runner()->config['allow-root'] ? '--allow-root' : ''; $php_binary = WP_CLI::get_php_binary(); - $process = WP_CLI\Process::create( "{$php_binary} $temp --version {$allow_root}" ); + $process = WP_CLI\Process::create( "{$php_binary} $temp --info {$allow_root}" ); $result = $process->run(); - if ( 0 !== $result->return_code ) { + if ( 0 !== $result->return_code || false === stripos( $result->stdout, 'WP-CLI version:' ) ) { $multi_line = explode( PHP_EOL, $result->stderr ); WP_CLI::error_multi_line( $multi_line ); WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli update again.' ); From 0c810fa84aa2ec2484aa1b19e6262acd512897bd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 19 Feb 2016 04:49:26 -0800 Subject: [PATCH 4087/5359] Fix fatal error when a dependency needs to be installed ``` PHP Catchable fatal error: Argument 1 passed to Composer\DependencyResolver\Rule::getPrettyString() must be an instance of Composer\DependencyResolver\Pool, none given, called in /home/vagrant/.wp-cli/php/WP_CLI/PackageManagerEventSubscriber.php on line 40 and defined in /home/vagrant/.wp-cli/vendor/composer/composer/src/Composer/DependencyResolver/Rule.php on line 161 ``` --- php/WP_CLI/PackageManagerEventSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index a4b3798e3..057013573 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -37,7 +37,7 @@ public static function post_install( PackageEvent $event ) { case Rule::RULE_PACKAGE_CONFLICT; case Rule::RULE_PACKAGE_SAME_NAME: case Rule::RULE_PACKAGE_REQUIRES: - $composer_error = $reason->getPrettyString(); + $composer_error = $reason->getPrettyString( $event->getPool() ); break; } From 50e4073a14a8859c662c0c73f416ddf19fd4252d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 07:29:42 -0800 Subject: [PATCH 4088/5359] Mark `WP_CLI\Utils\make_progress_bar()` as a public internal API. --- php/utils.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/php/utils.php b/php/utils.php index a3152b1bf..9f717d5bb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -408,6 +408,34 @@ function mustache_render( $template_name, $data ) { return $m->render( $template, $data ); } +/** + * Create a progress bar to display percent completion of a given operation. + * + * Progress bar is written to STDOUT, and disabled when command is piped. Progress + * advances with `$progress->tick()`, and completes with `$progress->finish()`. + * Process bar also indicates elapsed time and expected total time. + * + * ``` + * # `wp user generate` ticks progress bar each time a new user is created. + * # + * # $ wp user generate --count=500 + * # Generating users 22 % [=======> ] 0:05 / 0:23 + * + * $progress = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); + * for ( $i = 0; $i < $count; $i++ ) { + * // uses wp_insert_user() to insert the user + * $progress->tick(); + * } + * $progress->finish(); + * ``` + * + * @access public + * @category Output + * + * @param string $message Text to display before the progress bar. + * @param integer $count Total number of ticks to be performed. + * @return cli\progress\Bar|WP_CLI\NoOp + */ function make_progress_bar( $message, $count ) { if ( \cli\Shell::isPiped() ) return new \WP_CLI\NoOp; From 72f360cbf7fb1bb51a23ba8eff2e7756ddc69d59 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 18:26:57 -0800 Subject: [PATCH 4089/5359] Merge project config into global config when latter is already set --- features/config.feature | 38 +++++++++++++++++++++++++++++++++++++ php/WP_CLI/Configurator.php | 12 ++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/features/config.feature b/features/config.feature index 9702f8da7..86a01c1a6 100644 --- a/features/config.feature +++ b/features/config.feature @@ -271,6 +271,44 @@ Feature: Have a config file Error: Required file 'foo.php' doesn't exist (from runtime argument). """ + Scenario: Config inheritance + Given an empty directory + And a test-cmd.php file: + """ + <?php + $command = function( $_, $assoc_args ) { + echo json_encode( $assoc_args ); + }; + WP_CLI::add_command( 'test-cmd', $command, array( 'when' => 'before_wp_load' ) ); + """ + And a config.yml file: + """ + test-cmd: + foo: bar + apple: banana + apple: banana + """ + And a wp-cli.yml file: + """ + cli config: + merge: true + test-cmd: + bar: burrito + apple: apple + apple: apple + """ + + When I run `wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"bar":"burrito","apple":"apple"} + """ + When I run `WP_CLI_CONFIG_PATH=config.yml wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"foo":"bar","apple":"apple","bar":"burrito"} + """ + @require-wp-3.9 Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE Given a WP multisite install diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 21ae2ad3f..99d826d71 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -137,9 +137,17 @@ private function unmix_assoc_args( $mixed_args ) { * @param string $path Path to YAML file. */ public function merge_yml( $path ) { - foreach ( self::load_yml( $path ) as $key => $value ) { + $yaml = self::load_yml( $path ); + foreach ( $yaml as $key => $value ) { if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { - $this->extra_config[ $key ] = $value; + if ( isset( $this->extra_config[ $key ] ) + && ! empty( $yaml['cli config']['merge'] ) + && is_array( $this->extra_config[ $key ] ) + && is_array( $value ) ) { + $this->extra_config[ $key ] = array_merge( $this->extra_config[ $key ], $value ); + } else { + $this->extra_config[ $key ] = $value; + } } elseif ( $this->spec[ $key ]['multiple'] ) { self::arrayify( $value ); $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); From a35ff4b649a62ebf6282343d8c1e3511b351f165 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 18:52:13 -0800 Subject: [PATCH 4090/5359] Support inheritance in config files --- features/config.feature | 72 ++++++++++++++++++++++++++++++++++++- php/WP_CLI/Configurator.php | 3 ++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/features/config.feature b/features/config.feature index 86a01c1a6..22a1d23ae 100644 --- a/features/config.feature +++ b/features/config.feature @@ -271,7 +271,7 @@ Feature: Have a config file Error: Required file 'foo.php' doesn't exist (from runtime argument). """ - Scenario: Config inheritance + Scenario: Config inheritance from project to global Given an empty directory And a test-cmd.php file: """ @@ -309,6 +309,76 @@ Feature: Have a config file {"foo":"bar","apple":"apple","bar":"burrito"} """ + Given a wp-cli.yml file: + """ + cli config: + merge: false + test-cmd: + bar: burrito + apple: apple + apple: apple + """ + When I run `WP_CLI_CONFIG_PATH=config.yml wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"bar":"burrito","apple":"apple"} + """ + + Scenario: Config inheritance from local to project + Given an empty directory + And a test-cmd.php file: + """ + <?php + $command = function( $_, $assoc_args ) { + echo json_encode( $assoc_args ); + }; + WP_CLI::add_command( 'test-cmd', $command, array( 'when' => 'before_wp_load' ) ); + """ + And a wp-cli.yml file: + """ + test-cmd: + foo: bar + apple: banana + apple: banana + """ + + When I run `wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"foo":"bar","apple":"banana"} + """ + + Given a wp-cli.local.yml file: + """ + cli config: + inherit: wp-cli.yml + merge: true + test-cmd: + bar: burrito + apple: apple + apple: apple + """ + + When I run `wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"foo":"bar","apple":"apple","bar":"burrito"} + """ + + Given a wp-cli.local.yml file: + """ + test-cmd: + bar: burrito + apple: apple + apple: apple + """ + + When I run `wp --require=test-cmd.php test-cmd` + Then STDOUT should be JSON containing: + """ + {"bar":"burrito","apple":"apple"} + """ + @require-wp-3.9 Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE Given a WP multisite install diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 99d826d71..6d8ae2303 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -138,6 +138,9 @@ private function unmix_assoc_args( $mixed_args ) { */ public function merge_yml( $path ) { $yaml = self::load_yml( $path ); + if ( ! empty( $yaml['cli config']['inherit'] ) ) { + $this->merge_yml( $yaml['cli config']['inherit'] ); + } foreach ( $yaml as $key => $value ) { if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { if ( isset( $this->extra_config[ $key ] ) From 01655a9e9633e39f4ad4a6a6acb6ecba7796aac2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 19:28:56 -0800 Subject: [PATCH 4091/5359] Run help early for `wp core` commands used when core isn't yet installed While it would be more ideal to run help early _always_ when core isn't installed, we are unable to easily inspect the database for blog tables. This change permits `wp help core install` to be run when `wp-config.php` is created, but the database isn't yet configured. --- features/help.feature | 7 +++++++ php/WP_CLI/Runner.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/features/help.feature b/features/help.feature index fb066f603..79bb1eee7 100644 --- a/features/help.feature +++ b/features/help.feature @@ -37,6 +37,13 @@ Feature: Get help about WP-CLI commands wp core config """ + When I run `wp core config {CORE_CONFIG_SETTINGS}` + And I run `wp help core install` + Then STDOUT should contain: + """ + wp core install + """ + Scenario: Help for nonexistent commands Given a WP install diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3adde5022..af857ba09 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -664,7 +664,7 @@ public function start() { self::set_wp_root( $this->find_wp_root() ); // First try at showing man page - if ( 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() ) ) { + if ( 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() || 'core' === $this->arguments[1] && in_array( $this->arguments[2], array( 'config', 'install', 'multisite-install', 'verify-checksums', 'version' ) ) ) ) { $this->_run_command(); } From dda8e5c9e45a0f17332207af15dd8ab9cc9a2685 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 19:47:14 -0800 Subject: [PATCH 4092/5359] When running tests inside of a package, autoload composer.json files This is much easier than provisioning a Behat YML config and having to use that. --- features/bootstrap/FeatureContext.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4ca743bf8..da9e2aac2 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -12,6 +12,20 @@ if ( file_exists( __DIR__ . '/utils.php' ) ) { require_once __DIR__ . '/utils.php'; require_once __DIR__ . '/Process.php'; + $project_composer = dirname( dirname( dirname( __FILE__ ) ) ) . '/composer.json'; + if ( file_exists( $project_composer ) ) { + $composer = json_decode( file_get_contents( $project_composer ) ); + if ( ! empty( $composer->autoload->files ) ) { + $contents = 'require:' . PHP_EOL; + foreach( $composer->autoload->files as $file ) { + $contents .= ' - ' . dirname( dirname( dirname( __FILE__ ) ) ) . '/' . $file; + } + @mkdir( sys_get_temp_dir() . '/wp-cli-package-test/' ); + $project_config = sys_get_temp_dir() . '/wp-cli-package-test/config.yml'; + file_put_contents( $project_config, $contents ); + putenv( 'WP_CLI_CONFIG_PATH=' . $project_config ); + } + } // Inside WP-CLI } else { require_once __DIR__ . '/../../php/utils.php'; From 900befec21cc025f2802d1dc5dbae1ddff2d22ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 21:01:49 -0800 Subject: [PATCH 4093/5359] Add an inline code example for `Utils\format_items()` --- php/utils.php | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 9f717d5bb..e2e723ddc 100644 --- a/php/utils.php +++ b/php/utils.php @@ -241,12 +241,46 @@ function wp_version_compare( $since, $operator ) { /** * Render a collection of items as an ASCII table, JSON, CSV, YAML, list of ids, or count. * + * Given a collection of items with a consistent data structure: + * + * ``` + * $items = array( + * array( + * 'key' => 'foo', + * 'value' => 'bar', + * ) + * ); + * ``` + * + * Render `$items` easily render as an ASCII table: + * + * ``` + * WP_CLI\Utils\format_items( 'table', $items, array( 'key', 'value' ) ); + * + * # +-----+-------+ + * # | key | value | + * # +-----+-------+ + * # | foo | bar | + * # +-----+-------+ + * ``` + * + * Or render `$items` as YAML: + * + * ``` + * WP_CLI\Utils\format_items( 'yaml', $items, array( 'key', 'value' ) ); + * + * # --- + * # - + * # key: foo + * # value: bar + * ``` + * * @access public * @category Output * * @param string $format Format to use: 'table', 'json', 'csv', 'yaml', 'ids', 'count' - * @param array $items Data to output - * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list + * @param array $items An array of items to output. + * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list. * @return null */ function format_items( $format, $items, $fields ) { From 072871fd2647a339559186da7b98b5f9d4df8f48 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 20 Feb 2016 21:06:47 -0800 Subject: [PATCH 4094/5359] Fix typo in docs --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index e2e723ddc..4ecbf164d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -252,7 +252,7 @@ function wp_version_compare( $since, $operator ) { * ); * ``` * - * Render `$items` easily render as an ASCII table: + * Render `$items` as an ASCII table: * * ``` * WP_CLI\Utils\format_items( 'table', $items, array( 'key', 'value' ) ); From b444a2a028886c13e2d035f1e9f7837b9ef40a21 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Feb 2016 10:56:49 -0800 Subject: [PATCH 4095/5359] When scaffolding plugin, use `--plugin_author` value in `package.json` --- features/scaffold.feature | 8 +++++++- templates/plugin-packages.mustache | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 635cd4144..cc0316dbc 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -110,7 +110,7 @@ Feature: WordPress code scaffolding Given I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} - When I run `wp scaffold plugin hello-world` + When I run `wp scaffold plugin hello-world --plugin_author="Hello World Author"` Then STDOUT should not be empty And the {PLUGIN_DIR}/hello-world/.gitignore file should exist And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist @@ -124,6 +124,12 @@ Feature: WordPress code scaffolding node_modules/ """ + When I run `cat {PLUGIN_DIR}/hello-world/package.json` + Then STDOUT should be JSON containing: + """ + {"author":"Hello World Author"} + """ + Scenario: Scaffold a plugin by prompting Given a WP install And a session file: diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache index 657df4608..2554b9b2c 100644 --- a/templates/plugin-packages.mustache +++ b/templates/plugin-packages.mustache @@ -3,7 +3,7 @@ "name": "{{plugin_slug}}", "version": "0.0.0", "main": "Gruntfile.js", - "author": "YOUR NAME HERE", + "author": "{{plugin_author}}", "devDependencies": { "grunt": "^0.4.5", "grunt-wp-i18n": "^0.5.0", From d957dacd5a942f08469da03506cb9d641329dd12 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 24 Feb 2016 09:04:47 -0800 Subject: [PATCH 4096/5359] Use `_` to denote config config `_` is unlikely to ever be a command, and is colloquially understood to be "private" --- features/config.feature | 6 +++--- php/WP_CLI/Configurator.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/config.feature b/features/config.feature index 22a1d23ae..091c71116 100644 --- a/features/config.feature +++ b/features/config.feature @@ -290,7 +290,7 @@ Feature: Have a config file """ And a wp-cli.yml file: """ - cli config: + _: merge: true test-cmd: bar: burrito @@ -311,7 +311,7 @@ Feature: Have a config file Given a wp-cli.yml file: """ - cli config: + _: merge: false test-cmd: bar: burrito @@ -350,7 +350,7 @@ Feature: Have a config file Given a wp-cli.local.yml file: """ - cli config: + _: inherit: wp-cli.yml merge: true test-cmd: diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 6d8ae2303..8a92bf6bd 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -138,13 +138,13 @@ private function unmix_assoc_args( $mixed_args ) { */ public function merge_yml( $path ) { $yaml = self::load_yml( $path ); - if ( ! empty( $yaml['cli config']['inherit'] ) ) { - $this->merge_yml( $yaml['cli config']['inherit'] ); + if ( ! empty( $yaml['_']['inherit'] ) ) { + $this->merge_yml( $yaml['_']['inherit'] ); } foreach ( $yaml as $key => $value ) { if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { if ( isset( $this->extra_config[ $key ] ) - && ! empty( $yaml['cli config']['merge'] ) + && ! empty( $yaml['_']['merge'] ) && is_array( $this->extra_config[ $key ] ) && is_array( $value ) ) { $this->extra_config[ $key ] = array_merge( $this->extra_config[ $key ], $value ); From 0061c3d65923f25ff3e137135db6c3d6988341e9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 24 Feb 2016 14:29:15 -0800 Subject: [PATCH 4097/5359] Support emptying term meta with `wp site empty` --- php/commands/site.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 70ead9dbc..b86b144b3 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -87,6 +87,9 @@ private function _empty_taxonomies() { $wpdb->query( "TRUNCATE $wpdb->terms" ); $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); + if ( ! empty( $wpdb->termmeta ) ) { + $wpdb->query( "TRUNCATE $wpdb->termmeta" ); + } } /** From e73d1d563c0d852e8d3af46ccab55ef32b687c3b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 06:24:45 -0800 Subject: [PATCH 4098/5359] Mark `WP_CLI::add_command()` as public; improve docs --- php/class-wp-cli.php | 52 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index f5318b7e9..9b2f4964b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -163,15 +163,48 @@ public static function do_hook( $when ) { } /** - * Add a command to the wp-cli list of commands - * - * @param string $name The name of the command that will be used in the CLI - * @param string $callable The command implementation as a class, function or closure - * @param array $args An associative array with additional parameters: - * 'before_invoke' => callback to execute before invoking the command, - * 'shortdesc' => short description (80 char or less) for the command, - * 'synopsis' => the synopsis for the command (string or array) - * 'when' => execute callback on a named WP-CLI hook (e.g. before_wp_load) + * Register a command to WP-CLI. + * + * WP-CLI supports using any callable class, function, or closure as a + * command. `WP_CLI::add_command()` is used for both internal and + * third-party command registration. + * + * Command arguments are parsed from PHPDoc by default, but also can be + * supplied as an optional third argument during registration. + * + * ``` + * # Register a custom 'foo' command to output a supplied positional param. + * # + * # $ wp foo bar + * # Success: bar + * + * /** + * * My awesome closure command + * * + * * <message> + * * : An awesome message to display + * * + * * @when before_wp_load + * *\/ + * $foo = function( $args ) { + * WP_CLI::success( $args[0] ); + * }; + * WP_CLI::add_command( 'foo', $foo ); + * ``` + * + * @access public + * @category Registration + * + * @param string $name Name for the command (e.g. "post list" or "site empty"). + * @param string $callable Command implementation as a class, function or closure. + * @param array $args { + * Optional An associative array with additional registration parameters. + * 'before_invoke' => callback to execute before invoking the command, + * 'shortdesc' => short description (80 char or less) for the command, + * 'synopsis' => the synopsis for the command (string or array), + * 'when' => execute callback on a named WP-CLI hook (e.g. before_wp_load), + * } + * @return true True on success, hard error if registration failed. */ public static function add_command( $name, $callable, $args = array() ) { $valid = false; @@ -243,6 +276,7 @@ public static function add_command( $name, $callable, $args = array() ) { } $command->add_subcommand( $leaf_name, $leaf_command ); + return true; } /** From 3b97b4d6b72bf527e9b5ef3478e2c9ef573da6c4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 07:10:50 -0800 Subject: [PATCH 4099/5359] Failing test case for not persisting object when registering --- features/command.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/command.feature b/features/command.feature index c73f90622..4bd08e944 100644 --- a/features/command.feature +++ b/features/command.feature @@ -221,6 +221,36 @@ Feature: WP-CLI Commands Success: bar """ + Scenario: Use class with __invoke() passed as object + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Foo_Class { + + public function __construct( $message ) { + $this->message = $message; + } + + /** + * My awesome class method command + * + * @when before_wp_load + */ + function __invoke( $args ) { + WP_CLI::success( $this->message ); + } + } + $foo = new Foo_Class( 'bar' ); + WP_CLI::add_command( 'instantiated-command', $foo ); + """ + + When I run `wp --require=custom-cmd.php instantiated-command` + Then STDOUT should contain: + """ + bar + """ + Scenario: Use an invalid class method as a command Given an empty directory And a custom-cmd.php file: From 538efb2eeeb17c49ef873b3169977f6d33b8390b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 07:16:22 -0800 Subject: [PATCH 4100/5359] Fix registering instantiated object with `__invoke()` method When an instantiated object is passed, we should continue to use it. --- php/WP_CLI/Dispatcher/CommandFactory.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index bd3874117..5b05568c5 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -29,7 +29,8 @@ public static function create( $name, $callable, $parent ) { } else { $reflection = new \ReflectionClass( $callable ); if ( $reflection->hasMethod( '__invoke' ) ) { - $command = self::create_subcommand( $parent, $name, array( $reflection->name, '__invoke' ), + $class = is_object( $callable ) ? $callable : $reflection->name; + $command = self::create_subcommand( $parent, $name, array( $class, '__invoke' ), $reflection->getMethod( '__invoke' ) ); } else { $command = self::create_composite_command( $parent, $name, $reflection ); From 187f726d682c5b3e8453a89987fce57d3e29869d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 08:27:27 -0800 Subject: [PATCH 4101/5359] Ensure the failing test case would actually fail --- features/command.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/command.feature b/features/command.feature index 4bd08e944..2497e0f6f 100644 --- a/features/command.feature +++ b/features/command.feature @@ -250,6 +250,7 @@ Feature: WP-CLI Commands """ bar """ + And STDERR should be empty Scenario: Use an invalid class method as a command Given an empty directory From 47e62a004ff6c5659c10e8aa6184578ded35fc3d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 08:42:15 -0800 Subject: [PATCH 4102/5359] Prevent error notices when `$this->arguments` doesn't have array keys --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index af857ba09..6addd6403 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -664,7 +664,7 @@ public function start() { self::set_wp_root( $this->find_wp_root() ); // First try at showing man page - if ( 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() || 'core' === $this->arguments[1] && in_array( $this->arguments[2], array( 'config', 'install', 'multisite-install', 'verify-checksums', 'version' ) ) ) ) { + if ( ! empty( $this->arguments[0] ) && 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() || ( ! empty( $this->arguments[1] ) && ! empty( $this->arguments[2] ) && 'core' === $this->arguments[1] && in_array( $this->arguments[2], array( 'config', 'install', 'multisite-install', 'verify-checksums', 'version' ) ) ) ) ) { $this->_run_command(); } From 9abd5443c5f7c2f983c54a73a6f4dbcc34651b9c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 09:08:44 -0800 Subject: [PATCH 4103/5359] Register `$longdesc` from supplied arguments --- features/command.feature | 22 ++++++++++++++++++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 9 +++++++++ php/class-wp-cli.php | 13 ++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/features/command.feature b/features/command.feature index c73f90622..da5e47c2b 100644 --- a/features/command.feature +++ b/features/command.feature @@ -301,3 +301,25 @@ Feature: WP-CLI Commands """ My awesome function command """ + And STDOUT should contain: + """ + SYNOPSIS + """ + And STDOUT should contain: + """ + wp foo <message> --apple=<apple> [--meal=<meal>] + """ + And STDOUT should contain: + """ + OPTIONS + """ + And STDOUT should contain: + """ + <message> + An awesome message to display + """ + And STDOUT should contain: + """ + [--meal=<meal>] + A type of meal. + """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index 8ec1f5152..f9728b514 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -118,6 +118,15 @@ public function get_longdesc() { return $this->longdesc; } + /** + * Set the long description for this composite commmand + * + * @param string + */ + public function set_longdesc( $longdesc ) { + $this->longdesc = $longdesc; + } + /** * Get the synopsis for this composite command. * As a collection of subcommands, the composite diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9b2f4964b..de348bbfe 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -267,7 +267,18 @@ public static function add_command( $name, $callable, $args = array() ) { if ( is_string( $args['synopsis'] ) ) { $leaf_command->set_synopsis( $args['synopsis'] ); } else if ( is_array( $args['synopsis'] ) ) { - $leaf_command->set_synopsis( \WP_CLI\SynopsisParser::render( $args['synopsis'] ) ); + $synopsis = \WP_CLI\SynopsisParser::render( $args['synopsis'] ); + $leaf_command->set_synopsis( $synopsis ); + $long_desc = ''; + $bits = explode( ' ', $synopsis ); + foreach( $args['synopsis'] as $key => $arg ) { + $long_desc .= $bits[ $key ] . PHP_EOL . ': ' . $arg['description'] . PHP_EOL . PHP_EOL; + } + if ( ! empty( $long_desc ) ) { + $long_desc = rtrim( $long_desc, PHP_EOL ); + $long_desc = '## OPTIONS' . PHP_EOL . PHP_EOL . $long_desc; + $leaf_command->set_longdesc( $long_desc ); + } } } From e139266ccf302b9019f90c9807fce6667f87eedd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 09:26:25 -0800 Subject: [PATCH 4104/5359] Add `WP_CLI::add_hook()` and `WP_CLI::do_hook()` to internal API --- php/class-wp-cli.php | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9b2f4964b..04a6e40ee 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -139,7 +139,39 @@ public static function colorize( $string ) { } /** - * Schedule a callback to be executed at a certain point (before WP is loaded). + * Schedule a callback to be executed at a certain point. + * + * Hooks conceptually are very similar to WordPress actions. WP-CLI hooks + * are typically called before WordPress is loaded. + * + * WP-CLI hooks include: + * + * * 'before_invoke:<command>' - Just before a command is invoked. + * * 'after_invoke:<command>' - Just after a command is involved. + * * 'before_wp_load' - Just before the WP load process begins. + * * 'before_wp_config_load' - After wp-config.php has been located. + * * 'after_wp_config_load' - After wp-config.php has been loaded into scope. + * * 'after_wp_load' - Just after the WP load process has completed. + * + * WP-CLI commands can create their own hooks with `WP_CLI::do_hook()`. + * + * ``` + * # `wp network meta` confirms command is executing in multisite context. + * WP_CLI::add_command( 'network meta', 'Network_Meta_Command', array( + * 'before_invoke' => function () { + * if ( !is_multisite() ) { + * WP_CLI::error( 'This is not a multisite install.' ); + * } + * } + * ) ); + * ``` + * + * @access public + * @category Registration + * + * @param string $when Identifier for the hook. + * @param mixed $callback Callback to execute when hook is called. + * @return null */ public static function add_hook( $when, $callback ) { if ( in_array( $when, self::$hooks_passed ) ) @@ -149,7 +181,16 @@ public static function add_hook( $when, $callback ) { } /** - * Execute registered callbacks. + * Execute callbacks registered to a given hook. + * + * See `WP_CLI::add_hook()` for details on WP-CLI's internal hook system. + * Commands can provide and call their own hooks. + * + * @access public + * @category Registration + * + * @param string $when Identifier for the hook. + * @return null */ public static function do_hook( $when ) { self::$hooks_passed[] = $when; From eb4e0a613720e53c9e008c391d4cde4234364853 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 09:47:51 -0800 Subject: [PATCH 4105/5359] Always sort package lists alphabetically --- php/commands/package.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/package.php b/php/commands/package.php index e85d8c8a1..1845cdbaa 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -270,6 +270,7 @@ private function show_packages( $packages, $assoc_args ) { $list[$package_output->name] = $package_output; } + ksort( $list ); WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); } From 1fa1eb5089aace3609c2b57e0756dd4921627e73 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 09:50:06 -0800 Subject: [PATCH 4106/5359] Provide breathing room between author names --- php/commands/package.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index 1845cdbaa..b4dd6df08 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -265,7 +265,7 @@ private function show_packages( $packages, $assoc_args ) { $package_output = new stdClass; $package_output->name = $package->getName(); $package_output->description = $package->getDescription(); - $package_output->authors = implode( ',', array_column( (array) $package->getAuthors(), 'name' ) ); + $package_output->authors = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); $package_output->version = $package->getPrettyVersion(); $list[$package_output->name] = $package_output; } From 99ba8af0283061ccc8d61d60a1a229c58fb8d6de Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 13:29:45 -0800 Subject: [PATCH 4107/5359] Improve PHPDoc for `WP_CLI::error_multi_line()` --- php/class-wp-cli.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d8f9d5d06..d31dfc40f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -489,11 +489,14 @@ public static function error( $message, $exit = true ) { } /** - * Display an error in the CLI and end with a newline. + * Display a multi-line error message in a red box. Doesn't exit script. + * + * Error message is written to STDERR. * * @access public + * @category Output * - * @param array $message each element from the array will be printed on its own line + * @param array $message Multi-line error message to be displayed. */ public static function error_multi_line( $message_lines ) { if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) && is_array( $message_lines ) ) { From c31fff319f36b13dac62afcf7579580d52e15ee5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 13:30:18 -0800 Subject: [PATCH 4108/5359] Denote `WP_CLI::confirm()` as a public API --- php/class-wp-cli.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d31dfc40f..3fc49d1ae 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -506,6 +506,21 @@ public static function error_multi_line( $message_lines ) { /** * Ask for confirmation before running a destructive operation. + * + * If 'y' is provided to the question, the script execution continues. If + * 'n' or any other response is provided to the question, script exits. + * + * ``` + * # `wp db drop` asks for confirmation before dropping the database. + * + * WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); + * ``` + * + * @access public + * @category Input + * + * @param string $question Question to display before the prompt. + * @param array $assoc_args Skips prompt if 'yes' is provided. */ public static function confirm( $question, $assoc_args = array() ) { if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'yes' ) ) { From 48d0fe384e785475273945966fa7a6ec660f9e70 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 13:31:08 -0800 Subject: [PATCH 4109/5359] PHPDoc cleanup --- php/class-wp-cli.php | 4 ++-- php/utils.php | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3fc49d1ae..00407f9b9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -581,8 +581,8 @@ public static function read_value( $raw_value, $assoc_args = array() ) { /** * Display a value, in various formats * - * @param mixed $value - * @param array $assoc_args + * @param mixed $value Value to display. + * @param array $assoc_args Arguments passed to the command, determining format. */ public static function print_value( $value, $assoc_args = array() ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { diff --git a/php/utils.php b/php/utils.php index 4ecbf164d..597a4d19e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -639,7 +639,12 @@ function get_named_sem_ver( $new_version, $original_version ) { /** * Return the flag value or, if it's not set, the $default value. * + * Because flags can be negated (e.g. --no-quiet to negate --quiet), this + * function provides a safer alternative to using + * `isset( $assoc_args['quiet'] )` or similar. + * * @access public + * @category Input * * @param array $assoc_args Arguments array. * @param string $flag Flag to get the value. @@ -651,9 +656,10 @@ function get_flag_value( $assoc_args, $flag, $default = null ) { } /** - * Get the temp directory, and let the user know if it isn't writable. + * Get the system's temp directory. Warns user if it isn't writable. * * @access public + * @category System * * @return string */ From c261997fe22227141b990706866eca15c513c295 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 25 Feb 2016 13:31:19 -0800 Subject: [PATCH 4110/5359] Denote `WP_CLI::get_php_binary()` and `WP_CLI\Utils\http_request()` as internal APIs --- php/class-wp-cli.php | 4 ++++ php/utils.php | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 00407f9b9..a55ef8fc9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -696,8 +696,12 @@ public static function launch_self( $command, $args = array(), $assoc_args = arr /** * Get the path to the PHP binary used when executing WP-CLI. + * * Environment values permit specific binaries to be indicated. * + * @access public + * @category System + * * @return string */ public static function get_php_binary() { diff --git a/php/utils.php b/php/utils.php index 597a4d19e..d8b30f913 100644 --- a/php/utils.php +++ b/php/utils.php @@ -513,11 +513,24 @@ function replace_path_consts( $source, $path ) { } /** - * Make a HTTP request to a remote URL + * Make a HTTP request to a remote URL. * - * @param string $method - * @param string $url - * @param array $headers + * Wraps the Requests HTTP library to ensure every request includes a cert. + * + * ``` + * # `wp core download` verifies the hash for a downloaded WordPress archive + * + * $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); + * if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + * WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); + * } + * ``` + * + * @access public + * + * @param string $method HTTP method (GET, POST, DELETE, etc.) + * @param string $url URL to make the HTTP request to. + * @param array $headers Add specific headers to the request. * @param array $options * @return object */ From c172c8dfb1830d1bd73ac9ed649cf93289555c5f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 26 Feb 2016 07:08:39 -0800 Subject: [PATCH 4111/5359] Fix formatting of GLOBAL PARAMETERS when command has subcommands --- features/help.feature | 33 ++++++++++++++++++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 7 +++-- templates/man-params.mustache | 4 +++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/features/help.feature b/features/help.feature index 79bb1eee7..3f56c0ae2 100644 --- a/features/help.feature +++ b/features/help.feature @@ -174,3 +174,36 @@ Feature: Get help about WP-CLI commands """ test-extra """ + + Scenario: Help renders global parameters correctly + Given a WP install + + When I run `wp help import get` + Then STDOUT should contain: + """ + GLOBAL PARAMETERS + """ + And STDOUT should not contain: + """ + ## GLOBAL PARAMETERS + """ + + When I run `wp help option get` + Then STDOUT should contain: + """ + GLOBAL PARAMETERS + """ + And STDOUT should not contain: + """ + ## GLOBAL PARAMETERS + """ + + When I run `wp help option` + Then STDOUT should contain: + """ + GLOBAL PARAMETERS + """ + And STDOUT should not contain: + """ + ## GLOBAL PARAMETERS + """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index f9728b514..a4712a592 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -30,7 +30,6 @@ public function __construct( $parent, $name, $docparser ) { $this->shortdesc = $docparser->get_shortdesc(); $this->longdesc = $docparser->get_longdesc(); - $this->longdesc .= $this->get_global_params(); $this->docparser = $docparser; $when_to_invoke = $docparser->get_tag( 'when' ); @@ -115,7 +114,7 @@ public function set_shortdesc( $shortdesc ) { * @return string */ public function get_longdesc() { - return $this->longdesc; + return $this->longdesc . $this->get_global_params(); } /** @@ -278,6 +277,10 @@ protected function get_global_params( $root_command = false ) { ); } + if ( $this->get_subcommands() ) { + $binding['has_subcommands'] = true; + } + return Utils\mustache_render( 'man-params.mustache', $binding ); } } diff --git a/templates/man-params.mustache b/templates/man-params.mustache index 53ca9addc..d2786014e 100644 --- a/templates/man-params.mustache +++ b/templates/man-params.mustache @@ -2,6 +2,10 @@ {{/is_subcommand}} +{{#has_subcommands}} + + +{{/has_subcommands}} ## GLOBAL PARAMETERS {{#parameters}} From 00537c7c16b154ece035b24b312ae4d0f9dfcec1 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 2 Mar 2016 15:45:10 -0300 Subject: [PATCH 4112/5359] Add test for `wp comment delete --force` --- features/comment.feature | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/features/comment.feature b/features/comment.feature index f636f6087..2286a2345 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -28,7 +28,25 @@ Feature: Manage WordPress comments """ Success: Deleted comment {COMMENT_ID}. """ - + + When I run `wp comment get {COMMENT_ID} --field=comment_approved` + Then STDOUT should be: + """ + trash + """ + + When I run `wp comment delete {COMMENT_ID} --force` + Then STDOUT should be: + """ + Success: Deleted comment {COMMENT_ID}. + """ + + When I try `wp comment get {COMMENT_ID}` + Then STDERR should be: + """ + Error: Invalid comment ID. + """ + When I run `wp comment create --comment_post_ID=1` And I run `wp comment create --comment_post_ID=1` And I run `wp comment delete 3 4` From 5913d5c3feb8bf3d5d8ed2f3ccada3b00c032d8e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 2 Mar 2016 15:45:42 -0300 Subject: [PATCH 4113/5359] typo --- features/comment.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 2286a2345..0351c0eec 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -55,7 +55,7 @@ Feature: Manage WordPress comments Success: Deleted comment 3. Success: Deleted comment 4. """ - + Scenario: Get details about an existing comment When I run `wp comment get 1` Then STDOUT should be a table containing rows: @@ -91,7 +91,7 @@ Feature: Manage WordPress comments #comment-1 """ - Scenario: Count comments + Scenario: Count comments When I run `wp comment count 1` Then STDOUT should contain: """ From 387277b98c6844174463c04335402cfde4f16c8e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo <rodrigo@hacklab.com.br> Date: Wed, 2 Mar 2016 15:47:01 -0300 Subject: [PATCH 4114/5359] Differentiate output when moving comments to trash from output when deleting comments --- features/comment.feature | 6 +++--- php/commands/comment.php | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 0351c0eec..9a4fb0de2 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -26,7 +26,7 @@ Feature: Manage WordPress comments When I run `wp comment delete {COMMENT_ID}` Then STDOUT should be: """ - Success: Deleted comment {COMMENT_ID}. + Success: Trashed comment {COMMENT_ID}. """ When I run `wp comment get {COMMENT_ID} --field=comment_approved` @@ -52,8 +52,8 @@ Feature: Manage WordPress comments And I run `wp comment delete 3 4` Then STDOUT should be: """ - Success: Deleted comment 3. - Success: Deleted comment 4. + Success: Trashed comment 3. + Success: Trashed comment 4. """ Scenario: Get details about an existing comment diff --git a/php/commands/comment.php b/php/commands/comment.php index 45a01d86f..8c8b82a3b 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -247,10 +247,16 @@ public function list_( $_, $assoc_args ) { */ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { - $r = wp_delete_comment( $comment_id, \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + + $r = wp_delete_comment( $comment_id, $force ); if ( $r ) { - return array( 'success', "Deleted comment $comment_id." ); + if ( $force ) { + return array( 'success', "Deleted comment $comment_id." ); + } else { + return array( 'success', "Trashed comment $comment_id." ); + } } else { return array( 'error', "Failed deleting comment $comment_id" ); } From 1ac584ff021b6e3873799e7b302eb4d22ff2286b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 2 Mar 2016 11:11:58 -0800 Subject: [PATCH 4115/5359] Accommodate spaces in `ps -o ppid,pid,command` output Some shells format output differently. We can easily accommodate minor formatting changes, though. --- features/bootstrap/FeatureContext.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index da9e2aac2..d2248100c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -127,22 +127,24 @@ private static function terminate_proc( $proc ) { $master_pid = $status['pid']; - $output = `ps -o ppid,pid,command | grep ^$master_pid`; + $output = `ps -o ppid,pid,command | grep $master_pid`; - foreach ( explode( "\n", $output ) as $line ) { - if ( preg_match( '/^(\d+)\s+(\d+)/', $line, $matches ) ) { + foreach ( explode( PHP_EOL, $output ) as $line ) { + if ( preg_match( '/^\s+?(\d+)\s+(\d+)/', $line, $matches ) ) { $parent = $matches[1]; $child = $matches[2]; if ( $parent == $master_pid ) { - if ( ! posix_kill( $child, 9 ) ) { + if ( ! posix_kill( (int) $child, 9 ) ) { throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); } } } } - posix_kill( $master_pid, 9 ); + if ( ! posix_kill( (int) $master_pid, 9 ) ) { + throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); + } } public static function create_cache_dir() { From 2227de2940bf3a8077969d0299d147fea5cb1fc7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 2 Mar 2016 12:56:18 -0800 Subject: [PATCH 4116/5359] More precise regex --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index d2248100c..b6897e4fb 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -130,7 +130,7 @@ private static function terminate_proc( $proc ) { $output = `ps -o ppid,pid,command | grep $master_pid`; foreach ( explode( PHP_EOL, $output ) as $line ) { - if ( preg_match( '/^\s+?(\d+)\s+(\d+)/', $line, $matches ) ) { + if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) { $parent = $matches[1]; $child = $matches[2]; From 370a3cf43d5d5585934cc9108945f64ea96e0d74 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 05:20:13 -0800 Subject: [PATCH 4117/5359] Fix formatting of search-replace wildcard example Otherwise, the `*` is markdownified. --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c4088216b..f8c9ee318 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -38,7 +38,7 @@ class Search_Replace_Command extends WP_CLI_Command { * * [<table>...] * : List of database tables to restrict the replacement to. Wildcards are - * supported, e.g. 'wp_*_options' or 'wp_post*'. + * supported, e.g. `'wp_*_options'` or `'wp_post*'`. * * [--dry-run] * : Run the entire search/replace operation and show report, but don't save From 53e7c380b583fa7aba372aa647ddd6c125728756 Mon Sep 17 00:00:00 2001 From: Mark Kimsal <metrofindings@gmail.com> Date: Mon, 7 Mar 2016 12:49:25 -0500 Subject: [PATCH 4118/5359] Handle multi-column keys in search and replace The where clause was constructed without regard to handling multiple keys nor quoting values properly. The example table that the previous technique doesn't work with is wp_wp_super_edit_options which has a primary key on id and name. --- php/commands/search-replace.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c4088216b..85fb80ea3 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -288,7 +288,8 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { foreach ( $rows as $keys ) { $where_sql = ''; foreach( (array) $keys as $k => $v ) { - $where_sql .= "{$k}={$v}"; + if (strlen($where_sql)) $where_sql .= ' AND '; + $where_sql .= "{$k}='{$v}'"; } $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM {$table_sql} WHERE {$where_sql}" ); if ( '' === $col_value ) From 6b700a74cb05a2653d5ce4a21dd93540a0347b56 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 10:31:29 -0800 Subject: [PATCH 4119/5359] Add package directory path to `wp cli info` See #1564 --- features/cli-info.feature | 16 ++++++++++++++++ php/WP_CLI/Runner.php | 20 +++++++++++++++----- php/commands/cli.php | 2 ++ 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 features/cli-info.feature diff --git a/features/cli-info.feature b/features/cli-info.feature new file mode 100644 index 000000000..7d3fef346 --- /dev/null +++ b/features/cli-info.feature @@ -0,0 +1,16 @@ +Feature: Review CLI information + + Scenario: Get the path to the packages directory + Given an empty directory + + When I run `wp cli info --format=json` + Then STDOUT should be JSON containing: + """ + {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} + """ + + When I run `WP_CLI_PACKAGES_DIR=/tmp/packages wp cli info --format=json` + Then STDOUT should be JSON containing: + """ + {"wp_cli_packages_dir_path":"/tmp/packages/"} + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6addd6403..49f9f57d7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -118,6 +118,20 @@ private function get_project_config_path() { return $project_config_path; } + /** + * Get the path to the packages directory + * + * @return string + */ + public function get_packages_dir_path() { + if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { + $packages_dir = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/'; + } else { + $packages_dir = getenv( 'HOME' ) . '/.wp-cli/packages/'; + } + return $packages_dir; + } + /** * Attempts to find the path to the WP install inside index.php * @@ -609,11 +623,7 @@ public function start() { // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); - if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { - $package_autoload = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/vendor/autoload.php'; - } else { - $package_autoload = getenv( 'HOME' ) . '/.wp-cli/packages/vendor/autoload.php'; - } + $package_autoload = $this->get_packages_dir_path() . 'vendor/autoload.php'; if ( file_exists( $package_autoload ) ) { WP_CLI::debug( 'Loading packages from: ' . $package_autoload ); diff --git a/php/commands/cli.php b/php/commands/cli.php index f68e19d25..4c0d8b213 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -55,6 +55,7 @@ public function info( $_, $assoc_args ) { 'global_config_path' => $runner->global_config_path, 'project_config_path' => $runner->project_config_path, 'wp_cli_dir_path' => WP_CLI_ROOT, + 'wp_cli_packages_dir_path' => $runner->get_packages_dir_path(), 'wp_cli_version' => WP_CLI_VERSION, ); @@ -64,6 +65,7 @@ public function info( $_, $assoc_args ) { WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); WP_CLI::line( "WP-CLI root dir:\t" . WP_CLI_ROOT ); + WP_CLI::line( "WP-CLI packages dir:\t" . $runner->get_packages_dir_path() ); WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); From 46a4d83f9d632d032a3a052fcd064006c0710704 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 10:40:15 -0800 Subject: [PATCH 4120/5359] Prefer Git (and other VCS) when installing packages This will make it easier for users to become contributors. --- php/commands/package.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/package.php b/php/commands/package.php index b4dd6df08..df9ca3407 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -104,6 +104,7 @@ public function install( $args, $assoc_args ) { // Set up the installer $install = Installer::create( new ComposerIO, $composer ); $install->setUpdate( true ); // Installer class will only override composer.lock with this flag + $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. // Try running the installer, but revert composer.json if failed WP_CLI::log( 'Using Composer to install the package...' ); From c7175faf7ad144dcbe53a580d24b78f825861332 Mon Sep 17 00:00:00 2001 From: Mark Kimsal <metrofindings@gmail.com> Date: Mon, 7 Mar 2016 13:42:27 -0500 Subject: [PATCH 4121/5359] Feature test for multi-column key search-replace --- features/search-replace.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 0f98c95dc..99ec9b0c0 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -232,6 +232,18 @@ Feature: Do global search/replace """ And STDOUT should be empty + Scenario: Search and replace a table that has a multi-column primary key + Given a WP install + And I run `wp db query "CREATE TABLE wp_multicol ( "id" bigint(20) NOT NULL AUTO_INCREMENT,"name" varchar(60) NOT NULL,"value" text NOT NULL,PRIMARY KEY ("id","name"),UNIQUE KEY "name" ("name") ) ENGINE=InnoDB DEFAULT CHARSET=utf8 "` + And I run `wp db query "INSERT INTO wp_multicol VALUES (1, 'foo', 'bar')"` + And I run `wp db query "INSERT INTO wp_multicol VALUES (2, 'bar', 'foo')"` + + When I run `wp search-replace bar replaced wp_multicol` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_multicol | name | 1 | SQL | + | wp_multicol | value | 1 | SQL | + Scenario Outline: Large guid search/replace where replacement contains search (or not) Given a WP install And I run `wp option get siteurl` From 4abe4ebd755007cd4c220241a166b64ca6e592d4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 10:44:11 -0800 Subject: [PATCH 4122/5359] Quote example in `wp search-replace` instead of escaping Quotes are more friendly and understandable to end users. --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index f8c9ee318..9a2d1703f 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -87,7 +87,7 @@ class Search_Replace_Command extends WP_CLI_Command { * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production database into a local database - * wp search-replace --url=example.com example.com example.dev wp_\*_options + * wp search-replace --url=example.com example.com example.dev 'wp_*_options' * * # Search/replace to a SQL file without transforming the database * wp search-replace foo bar --export=database.sql From 9d37a5ca728e47fa179e9bd3bdd5b31782f6dbbe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 12:11:59 -0800 Subject: [PATCH 4123/5359] Support nightly builds with `wp cli check-update` If there are no major, minor, or patch updates available, let's assume the user is running a nightly build for the latest release. If they're running a nightly build for the latest release, we can compare their current hash to the latest nightly build hash. When they differ, we can assume the latest nightly build is more recent than the local copy. --- php/commands/cli.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index 4c0d8b213..a6e252990 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -274,6 +274,33 @@ private function get_updates( $assoc_args ) { return ! empty( $updates[ $type ] ) ? array( $updates[ $type ] ) : false; } } + + if ( empty( $updates ) && preg_match( '#-alpha-(.+)$#', WP_CLI_VERSION, $matches ) ) { + $url = 'https://api.github.com/repos/wp-cli/wp-cli/git/refs/heads/master'; + + $response = Utils\http_request( 'GET', $url, $headers, $options ); + + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( sprintf( "Failed to get master hash (HTTP code %d)", $response->status_code ) ); + } + + $latest_hash_data = json_decode( $response->body ); + $latest_short_hash = substr( $latest_hash_data->object->sha, 0, 7 ); + + if ( $latest_short_hash != $matches[1] ) { + $version_url = 'https://raw.githubusercontent.com/wp-cli/wp-cli/master/VERSION'; + $response = Utils\http_request( 'GET', $version_url ); + if ( ! $response->success || 200 !== $response->status_code ) { + WP_CLI::error( sprintf( "Failed to get current version (HTTP code %d)", $response->status_code ) ); + } + $updates['nightly'] = array( + 'version' => trim( $response->body ) . '-' . $latest_short_hash, + 'update_type' => 'nightly', + 'package_url' => 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar', + ); + } + } + return array_values( $updates ); } From 39960263196ecff386ccc44f37afe3a211e80843 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 12:20:21 -0800 Subject: [PATCH 4124/5359] Store nightly version on deploy When we want to reference the built version, this is easier than recreating it on our own. See https://github.com/wp-cli/wp-cli/pull/2536 --- ci/deploy.sh | 3 ++- ci/prepare.sh | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 45de26a95..b9b109b27 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -22,6 +22,7 @@ set -x echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts git clone git@github.com:wp-cli/builds.git +mv PHAR_BUILD_VERSION builds/phar/NIGHTLY_VERSION cd builds git config user.name "Travis CI" @@ -36,7 +37,7 @@ chmod -x $fname md5sum $fname | cut -d ' ' -f 1 > $fname.md5 sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 -git add $fname $fname.md5 $fname.sha512 +git add $fname $fname.md5 $fname.sha512 NIGHTLY_VERSION git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" git push diff --git a/ci/prepare.sh b/ci/prepare.sh index a64af0f67..f2fea77e5 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -27,6 +27,8 @@ else chmod +x $WP_CLI_BIN_DIR/wp fi +echo $CLI_VERSION > PHAR_BUILD_VERSION + # Install CodeSniffer things ./ci/prepare-codesniffer.sh From c8e580a9bd64769dfe7da4dc3ce2e07307b4bee6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 13:18:09 -0800 Subject: [PATCH 4125/5359] Make `wp package install` more verbose * Update `WP_CLI\ComposerIO` to write error messages too. * Display return code when Composer installer returns one. --- php/WP_CLI/ComposerIO.php | 14 +++++++++++++- php/commands/package.php | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/ComposerIO.php b/php/WP_CLI/ComposerIO.php index b4df56a7b..01197c922 100644 --- a/php/WP_CLI/ComposerIO.php +++ b/php/WP_CLI/ComposerIO.php @@ -21,7 +21,19 @@ public function isVerbose() { * {@inheritDoc} */ public function write( $messages, $newline = true ) { - WP_CLI::log( " - " . strip_tags( $messages ) ); + self::output_clean_message( $messages ); + } + + /** + * {@inheritDoc} + */ + public function writeError( $messages, $newline = true ) { + self::output_clean_message( $messages ); + } + + private static function output_clean_message( $message ) { + $message = preg_replace( '#<(https?)([^>]+)>#', '$1$2', $message ); + WP_CLI::log( strip_tags( trim( $message ) ) ); } } diff --git a/php/commands/package.php b/php/commands/package.php index df9ca3407..1141d9d8e 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -108,17 +108,19 @@ public function install( $args, $assoc_args ) { // Try running the installer, but revert composer.json if failed WP_CLI::log( 'Using Composer to install the package...' ); + WP_CLI::log( '---' ); try { $res = $install->run(); } catch ( Exception $e ) { WP_CLI::warning( $e->getMessage() ); } + WP_CLI::log( '---' ); if ( 0 === $res ) { WP_CLI::success( "Package installed successfully." ); } else { file_put_contents( $composer_json_obj->getPath(), $composer_backup ); - WP_CLI::error( "Package installation failed. Reverted composer.json" ); + WP_CLI::error( "Package installation failed (Composer return code {$res}). Reverted composer.json" ); } } From 8af196a26302d9359e62d5580eca8714b8791965 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 13:53:38 -0800 Subject: [PATCH 4126/5359] Add the proper path when including NIGHTLY_VERSION --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index b9b109b27..7a7dab192 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -37,7 +37,7 @@ chmod -x $fname md5sum $fname | cut -d ' ' -f 1 > $fname.md5 sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 -git add $fname $fname.md5 $fname.sha512 NIGHTLY_VERSION +git add $fname $fname.md5 $fname.sha512 phar/NIGHTLY_VERSION git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" git push From 1aff63bdf14f680e28077736e0fa8425570c29f3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 14:42:56 -0800 Subject: [PATCH 4127/5359] Use one HTTP request instead of two --- php/commands/cli.php | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index a6e252990..4446d5f80 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -276,25 +276,15 @@ private function get_updates( $assoc_args ) { } if ( empty( $updates ) && preg_match( '#-alpha-(.+)$#', WP_CLI_VERSION, $matches ) ) { - $url = 'https://api.github.com/repos/wp-cli/wp-cli/git/refs/heads/master'; - - $response = Utils\http_request( 'GET', $url, $headers, $options ); - + $version_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/NIGHTLY_VERSION'; + $response = Utils\http_request( 'GET', $version_url ); if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( sprintf( "Failed to get master hash (HTTP code %d)", $response->status_code ) ); + WP_CLI::error( sprintf( "Failed to get current nightly version (HTTP code %d)", $response->status_code ) ); } - - $latest_hash_data = json_decode( $response->body ); - $latest_short_hash = substr( $latest_hash_data->object->sha, 0, 7 ); - - if ( $latest_short_hash != $matches[1] ) { - $version_url = 'https://raw.githubusercontent.com/wp-cli/wp-cli/master/VERSION'; - $response = Utils\http_request( 'GET', $version_url ); - if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( sprintf( "Failed to get current version (HTTP code %d)", $response->status_code ) ); - } + $nightly_version = trim( $response->body ); + if ( WP_CLI_VERSION != $nightly_version ) { $updates['nightly'] = array( - 'version' => trim( $response->body ) . '-' . $latest_short_hash, + 'version' => $nightly_version, 'update_type' => 'nightly', 'package_url' => 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar', ); From 959b8c6b589580658756cc438e015c5dd9c519b1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 14:45:25 -0800 Subject: [PATCH 4128/5359] Coding standards for #2531 --- php/commands/search-replace.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c583bda7e..812258bad 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -288,7 +288,9 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { foreach ( $rows as $keys ) { $where_sql = ''; foreach( (array) $keys as $k => $v ) { - if (strlen($where_sql)) $where_sql .= ' AND '; + if ( strlen( $where_sql ) ) { + $where_sql .= ' AND '; + } $where_sql .= "{$k}='{$v}'"; } $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM {$table_sql} WHERE {$where_sql}" ); From dfd3cbcd2a37124a3d8f30aac5c499e2be48228f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 15:48:50 -0800 Subject: [PATCH 4129/5359] Nag user when there's an update to WP-CLI available Auto check update only happens when a user is driving WP-CLI, not a script. `WP_CLI_AUTO_CHECK_UPDATE_DAYS` environment variable can be used to change the number of days between checks (defaults to 1). `WP_CLI_DISABLE_AUTO_CHECK_UPDATE` can be used to disable the update check entirely. --- php/WP_CLI/Runner.php | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 49f9f57d7..a8467db9b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -675,6 +675,7 @@ public function start() { // First try at showing man page if ( ! empty( $this->arguments[0] ) && 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() || ( ! empty( $this->arguments[1] ) && ! empty( $this->arguments[2] ) && 'core' === $this->arguments[1] && in_array( $this->arguments[2], array( 'config', 'install', 'multisite-install', 'verify-checksums', 'version' ) ) ) ) ) { + $this->auto_check_update(); $this->_run_command(); } @@ -860,5 +861,62 @@ private function maybe_update_url_from_domain_constant() { } } + /** + * Check whether there's a WP-CLI update available, and suggest update if so. + */ + private function auto_check_update() { + + // `wp cli update` only works with Phars at this time. + if ( ! Utils\inside_phar() ) { + return; + } + + // Only check for update when a human is operating. + if ( ! function_exists( 'posix_isatty' ) || ! posix_isatty( STDOUT ) ) { + return; + } + + // Allow hosts and other providers to disable automatic check update. + if ( getenv( 'WP_CLI_DISABLE_AUTO_CHECK_UPDATE' ) ) { + return; + } + + // Permit configuration of number of days between checks. + $days_between_checks = getenv( 'WP_CLI_AUTO_CHECK_UPDATE_DAYS' ); + if ( false === $days_between_checks ) { + $days_between_checks = 1; + } + + $cache = WP_CLI::get_cache(); + $cache_key = 'wp-cli-update-check'; + // Bail early on the first check, so we don't always check on an unwritable cache. + if ( ! $cache->has( $cache_key ) ) { + $cache->write( $cache_key, time() ); + return; + } + + // Bail if last check is still within our update check time period. + $last_check = (int) $cache->read( $cache_key ); + if ( time() - ( 24 * 60 * 60 * $days_between_checks ) < $last_check ) { + return; + } + + // In case the operation fails, ensure the timestamp has been updated. + $cache->write( $cache_key, time() ); + + // Check whether any updates are available. + ob_start(); + WP_CLI::run_command( array( 'cli', 'check-update' ), array( 'format' => 'count' ) ); + $count = ob_get_clean(); + if ( ! $count ) { + return; + } + + // Looks like an update is available, so let's prompt to update. + WP_CLI::run_command( array( 'cli', 'update' ) ); + // If the Phar was replaced, we can't proceed with the original process. + exit; + } + } From 960754295940f136b3842e6e5d515b3c297dccba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 15:54:53 -0800 Subject: [PATCH 4130/5359] Bail early when the Phar isn't writable --- php/WP_CLI/Runner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a8467db9b..628a9a67f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -871,6 +871,12 @@ private function auto_check_update() { return; } + $existing_phar = realpath( $_SERVER['argv'][0] ); + // Phar needs to be writable to be easily updateable. + if ( ! is_writable( $existing_phar ) || ! is_writeable( dirname( $existing_phar ) ) ) { + return; + } + // Only check for update when a human is operating. if ( ! function_exists( 'posix_isatty' ) || ! posix_isatty( STDOUT ) ) { return; From 649ee18570fd460d74c5fddb02da1f4e34fcd4dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 16:00:16 -0800 Subject: [PATCH 4131/5359] PHAR_BUILD_VERSION shouldn't ever be committed to this repo [ci skip] --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0d5a442ae..6f4883762 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ config.yml +PHAR_BUILD_VERSION /cache /packages /vendor From aef52173f29fc9bc397b57cd54bb43c3d804641f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 16:09:17 -0800 Subject: [PATCH 4132/5359] Remove `wp scaffold package-tests` It's been broken in a while, and is now included in https://github.com/wp-cli/scaffold-package-command --- features/scaffold.feature | 74 -------------------- php/commands/scaffold.php | 105 ----------------------------- templates/.travis.package.yml | 24 ------- templates/install-package-tests.sh | 54 --------------- templates/load-wp-cli.feature | 10 --- utils/make-phar.php | 1 - 6 files changed, 268 deletions(-) delete mode 100644 templates/.travis.package.yml delete mode 100644 templates/install-package-tests.sh delete mode 100644 templates/load-wp-cli.feature diff --git a/features/scaffold.feature b/features/scaffold.feature index cc0316dbc..e7ddedaa8 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -219,80 +219,6 @@ Feature: WordPress code scaffolding executable """ - Scenario: Scaffold package tests - Given a WP install - Given a community-command/command.php file: - """ - <?php - """ - And a community-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "require": { - }, - "autoload": { - "files": [ "dictator.php" ] - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - And a invalid-command/command.php file: - """ - <?php - """ - - When I run `wp scaffold package-tests community-command` - Then STDOUT should not be empty - And the community-command/.travis.yml file should exist - And the community-command/bin/install-package-tests.sh file should exist - And the community-command/utils/behat-tags.php file should contain: - """ - require-wp - """ - And the community-command/utils/get-package-require-from-composer.php file should exist - And the community-command/features directory should contain: - """ - bootstrap - extra - load-wp-cli.feature - steps - """ - And the community-command/features/bootstrap directory should contain: - """ - FeatureContext.php - Process.php - support.php - utils.php - """ - And the community-command/features/steps directory should contain: - """ - given.php - then.php - when.php - """ - And the community-command/features/extra directory should contain: - """ - no-mail.php - """ - - When I run `wp eval "if ( is_executable( 'community-command/bin/install-package-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` - Then STDOUT should be: - """ - executable - """ - - When I try `wp scaffold package-tests invalid-command` - Then STDERR should be: - """ - Error: Invalid package directory. composer.json file must be present. - """ - Scenario: Scaffold starter code for a theme Given a WP install Given I run `wp theme path` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 1df51eb1b..ed2524c46 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -370,111 +370,6 @@ private function get_output_path( $assoc_args, $subdir ) { return $path; } - /** - * Generate files needed for writing Behat tests for your command. - * - * ## DESCRIPTION - * - * These are the files that are generated: - * - * * `.travis.yml` is the configuration file for Travis CI - * * `bin/install-package-tests.sh` will configure environment to run tests. Script expects WP_CLI_BIN_DIR and WP_CLI_CONFIG_PATH environment variables. - * * `features/load-wp-cli.feature` is a basic test to confirm WP-CLI can load. - * * `features/bootstrap`, `features/steps`, `features/extra` are Behat configuration files. - * * `utils/generate-package-require-from-composer.php` generates a test config.yml file from your package's composer.json - * - * ## ENVIRONMENT - * - * The `features/bootstrap/FeatureContext.php` file expects the WP_CLI_BIN_DIR and WP_CLI_CONFIG_PATH environment variables. - * - * WP-CLI Behat framework uses Behat ~2.5. - * - * ## OPTIONS - * - * <dir> - * : The package directory to generate tests for. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLE - * - * wp scaffold package-tests /path/to/command/dir/ - * - * @when before_wp_load - * @subcommand package-tests - */ - public function package_tests( $args, $assoc_args ) { - - list( $package_dir ) = $args; - - if ( is_file( $package_dir ) ) { - $package_dir = dirname( $package_dir ); - } else if ( is_dir( $package_dir ) ) { - $package_dir = rtrim( $package_dir, '/' ); - } - - if ( ! is_dir( $package_dir ) || ! file_exists( $package_dir . '/composer.json' ) ) { - WP_CLI::error( "Invalid package directory. composer.json file must be present." ); - } - - $package_dir .= '/'; - $bin_dir = $package_dir . 'bin/'; - $utils_dir = $package_dir . 'utils/'; - $features_dir = $package_dir . 'features/'; - $bootstrap_dir = $features_dir . 'bootstrap/'; - $steps_dir = $features_dir . 'steps/'; - $extra_dir = $features_dir . 'extra/'; - foreach ( array( $features_dir, $bootstrap_dir, $steps_dir, $extra_dir, $utils_dir, $bin_dir ) as $dir ) { - if ( ! is_dir( $dir ) ) { - Process::create( Utils\esc_cmd( 'mkdir %s', $dir ) )->run(); - } - } - - $to_copy = array( - 'templates/.travis.package.yml' => $package_dir, - 'templates/load-wp-cli.feature' => $features_dir, - 'templates/install-package-tests.sh' => $bin_dir, - 'features/bootstrap/FeatureContext.php' => $bootstrap_dir, - 'features/bootstrap/support.php' => $bootstrap_dir, - 'php/WP_CLI/Process.php' => $bootstrap_dir, - 'php/utils.php' => $bootstrap_dir, - 'ci/behat-tags.php' => $utils_dir, - 'utils/get-package-require-from-composer.php' => $utils_dir, - 'features/steps/given.php' => $steps_dir, - 'features/steps/when.php' => $steps_dir, - 'features/steps/then.php' => $steps_dir, - 'features/extra/no-mail.php' => $extra_dir, - ); - - $files_written = array(); - foreach ( $to_copy as $file => $dir ) { - // file_get_contents() works with Phar-archived files - $contents = file_get_contents( WP_CLI_ROOT . "/{$file}" ); - $file_path = $dir . basename( $file ); - $file_path = str_replace( array( '.travis.package.yml' ), array( '.travis.yml' ), $file_path ); - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_path, $force ); - if ( ! $should_write_file ) { - continue; - } - $files_written[] = $file_path; - - $result = Process::create( Utils\esc_cmd( 'touch %s', $file_path ) )->run(); - file_put_contents( $file_path, $contents ); - if ( 'templates/install-package-tests.sh' === $file ) { - Process::create( Utils\esc_cmd( 'chmod +x %s', $file_path ) )->run(); - } - } - $this->log_whether_files_written( - $files_written, - $skip_message = 'All package tests were skipped.', - $success_message = 'Created test files.' - ); - - } - /** * Generate starter code for a plugin. * diff --git a/templates/.travis.package.yml b/templates/.travis.package.yml deleted file mode 100644 index bb11edec4..000000000 --- a/templates/.travis.package.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: php - -notifications: - email: - on_success: never - on_failure: change - -branches: - only: - - master - -php: - - 5.3 - - 5.6 - -env: - global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - - WP_CLI_CONFIG_PATH=/tmp/wp-cli-phar/config.yml - -before_script: - - bash bin/install-package-tests.sh - -script: ./vendor/bin/behat diff --git a/templates/install-package-tests.sh b/templates/install-package-tests.sh deleted file mode 100644 index 37fa69525..000000000 --- a/templates/install-package-tests.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -PACKAGE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )" - -download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; - elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi -} - -install_wp_cli() { - - # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR - mkdir -p $WP_CLI_BIN_DIR - download https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp - chmod +x $WP_CLI_BIN_DIR/wp - -} - -set_package_context() { - - touch $WP_CLI_CONFIG_PATH - printf 'require:' > $WP_CLI_CONFIG_PATH - requires=$(php $PACKAGE_DIR/utils/get-package-require-from-composer.php composer.json) - for require in "${requires[@]}" - do - printf "\n%2s-%1s$PACKAGE_DIR/$require" >> $WP_CLI_CONFIG_PATH - done - printf "\n" >> $WP_CLI_CONFIG_PATH - -} - -download_behat() { - - cd $PACKAGE_DIR - download https://getcomposer.org/installer installer - php installer - php composer.phar require --dev behat/behat='~2.5' - -} - -install_db() { - mysql -e 'CREATE DATABASE IF NOT EXISTS wp_cli_test;' -uroot - mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot -} - -install_wp_cli -set_package_context -download_behat -install_db diff --git a/templates/load-wp-cli.feature b/templates/load-wp-cli.feature deleted file mode 100644 index 035b86730..000000000 --- a/templates/load-wp-cli.feature +++ /dev/null @@ -1,10 +0,0 @@ -Feature: Test that WP-CLI loads. - - Scenario: WP-CLI loads for your tests - Given a WP install - - When I run `wp eval 'echo "Hello world.";'` - Then STDOUT should contain: - """ - Hello world. - """ diff --git a/utils/make-phar.php b/utils/make-phar.php index 3c3206416..30c261c11 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -101,7 +101,6 @@ function set_file_contents( $phar, $path, $content ) { add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/LICENSE' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/composer-schema.json' ); -add_file( $phar, WP_CLI_ROOT . '/utils/get-package-require-from-composer.php' ); add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); set_file_contents( $phar, WP_CLI_ROOT . '/VERSION', $current_version ); From 0a04bc51a9bbb8eb6c0578f012686affbb3326e3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 7 Mar 2016 16:48:31 -0800 Subject: [PATCH 4133/5359] `wp package browse` should list all available versions --- php/commands/package.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 1141d9d8e..a0027b039 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -265,14 +265,24 @@ private function show_packages( $packages, $assoc_args ) { $list = array(); foreach ( $packages as $package ) { - $package_output = new stdClass; - $package_output->name = $package->getName(); - $package_output->description = $package->getDescription(); - $package_output->authors = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); - $package_output->version = $package->getPrettyVersion(); - $list[$package_output->name] = $package_output; + $name = $package->getName(); + if ( isset( $list[ $name ] ) ) { + $list[ $name ]->version[] = $package->getPrettyVersion(); + } else { + $package_output = new stdClass; + $package_output->name = $package->getName(); + $package_output->description = $package->getDescription(); + $package_output->authors = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); + $package_output->version = array( $package->getPrettyVersion() ); + $list[ $package_output->name ] = $package_output; + } } + $list = array_map( function( $package ){ + $package->version = implode( ', ', $package->version ); + return $package; + }, $list ); + ksort( $list ); WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); } From 4fe5c5a483cd4032a457881b76bba40bd9c0f559 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 12:40:16 -0800 Subject: [PATCH 4134/5359] Clean up `wp package` PHPDoc; support `--format=ids` --- php/commands/package.php | 43 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index a0027b039..2dc50ae0e 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -17,7 +17,7 @@ use \WP_CLI\ComposerIO; /** - * Manage WP-CLI community packages. + * Manage WP-CLI packages. * * @package WP-CLI * @@ -35,24 +35,26 @@ class Package_Command extends WP_CLI_Command { ); /** - * Browse available WP-CLI community packages. + * Browse WP-CLI packages available for installation. + * + * Lists packages available for installation from the [Package Index](http://wp-cli.org/package-index/). * * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Accepted values: table, json, csv, yaml, ids. Default: table. */ public function browse( $_, $assoc_args ) { $this->show_packages( $this->get_community_packages(), $assoc_args ); } /** - * Install a WP-CLI community package. + * Install a WP-CLI package. * * ## OPTIONS * - * <package> - * : The name of the package to install. Can optionally contain a version constraint. + * <name> + * : Name of the package to install. Can optionally contain a version constraint. * * ## EXAMPLES * @@ -125,12 +127,12 @@ public function install( $args, $assoc_args ) { } /** - * List installed WP-CLI community packages. + * List installed WP-CLI packages. * * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Accepted values: table, json, csv, yaml, ids. Default: table * * @subcommand list */ @@ -139,12 +141,12 @@ public function list_( $args, $assoc_args ) { } /** - * Uninstall a WP-CLI community package. + * Uninstall a WP-CLI package. * * ## OPTIONS * - * <package> - * : The name of the package to uninstall. + * <name> + * : Name of the package to uninstall. */ public function uninstall( $args ) { list( $package_name ) = $args; @@ -267,23 +269,26 @@ private function show_packages( $packages, $assoc_args ) { foreach ( $packages as $package ) { $name = $package->getName(); if ( isset( $list[ $name ] ) ) { - $list[ $name ]->version[] = $package->getPrettyVersion(); + $list[ $name ]['version'][] = $package->getPrettyVersion(); } else { - $package_output = new stdClass; - $package_output->name = $package->getName(); - $package_output->description = $package->getDescription(); - $package_output->authors = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); - $package_output->version = array( $package->getPrettyVersion() ); - $list[ $package_output->name ] = $package_output; + $package_output = array(); + $package_output['name'] = $package->getName(); + $package_output['description'] = $package->getDescription(); + $package_output['authors'] = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); + $package_output['version'] = array( $package->getPrettyVersion() ); + $list[ $package_output['name'] ] = $package_output; } } $list = array_map( function( $package ){ - $package->version = implode( ', ', $package->version ); + $package['version'] = implode( ', ', $package['version'] ); return $package; }, $list ); ksort( $list ); + if ( 'ids' === $assoc_args['format'] ) { + $list = array_keys( $list ); + } WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); } From 29cedaf6379e70463aae07e390346bfd12f9e0f5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 13:36:31 -0800 Subject: [PATCH 4135/5359] Move Contributing details to their own doc pages [ci skip] --- CONTRIBUTING.md | 72 +------------------------------------------------ 1 file changed, 1 insertion(+), 71 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 415dc8c24..1ceb46a61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,74 +1,4 @@ Contribute ========== -Setting up ----------- - -1. Clone this git repository on your local machine. -2. Install [Composer](https://getcomposer.org/) if you don't already have it. -2. Run `composer install` to fetch all the dependencies. -3. Run `./bin/wp --info` to test if everything was installed properly. - -Submitting patches ------------------- - -Whether you want to fix a bug or implement a new feature, the process is pretty much the same: - -0. [Search existing issues](https://github.com/wp-cli/wp-cli/issues); if you can't find anything related to what you want to work on, [open a new issue](https://github.com/wp-cli/wp-cli/wiki/Creating-Helpful-Bug-Reports) so that you can get some initial feedback. -1. [Fork](https://github.com/wp-cli/wp-cli/fork) the repository. -2. Create a branch for each issue you'd like to address. Commit your changes. -3. Push the code changes from your local clone to your fork. -4. Open a pull request. - -It doesn't matter if the code isn't perfect. The idea is to get it reviewed early and iterate on it. - -If you're adding a new feature, please add one or more functional tests for it in the `features/` directory. See below. - -Lastly, please follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). - -Running and writing tests -------------------------- - -There are two types of automated tests: - -* unit tests, implemented using [PHPUnit](http://phpunit.de/) -* functional tests, implemented using [Behat](http://behat.org) - -### Unit tests - -The unit test files are in the `tests/` directory. - -To run the unit tests, just execute: - -```bash -./vendor/bin/phpunit -``` - -### Functional tests - -The functional test files are in the `features/` directory. - -Before running the functional tests, you'll need a MySQL (or MariaDB) user called `wp_cli_test` with the password `password1` that has full privileges on the MySQL database `wp_cli_test`. Running the following as root in MySQL should do the trick: - -```sql -GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"; -``` - -Then, to run the entire test suite: - -```bash -./vendor/bin/behat --expand -``` - -Or to test a single feature: - -```bash -./vendor/bin/behat features/core.feature -``` - -More info can be found by using `./vendor/bin/behat --help`. - -Finally... ----------- - -Thanks! Hacking on WP-CLI should be fun. If you find any of this hard to figure out, let us know so we can improve our process or documentation! +Thanks in advance for helping to improve WP-CLI. To get started, please review our documentation on [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). From 460acdaf93ccccdeca6d2e7e17b33309735c7e4e Mon Sep 17 00:00:00 2001 From: jacobischwartz <jacob@schwambell.com> Date: Tue, 8 Mar 2016 16:01:35 -0600 Subject: [PATCH 4136/5359] Initial idea for carrying list of imported posts through to subsequent import files in a batch. --- php/commands/import.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/import.php b/php/commands/import.php index 40b9c31bf..16372d6bb 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -2,6 +2,8 @@ class Import_Command extends WP_CLI_Command { + var $processed_posts = array(); + /** * Import content from a WXR file. * @@ -69,6 +71,7 @@ public function __invoke( $args, $assoc_args ) { private function import_wxr( $file, $args ) { $wp_import = new WP_Import; + $wp_import->processed_posts = $this->processed_posts; $import_data = $wp_import->parse( $file ); if ( is_wp_error( $import_data ) ) return $import_data; @@ -138,6 +141,7 @@ private function import_wxr( $file, $args ) { } $wp_import->import( $file ); + $this->processed_posts = array_merge($this->processed_posts, $wp_import->processed_posts); return true; } From b87bd9174a1fb45b83c25df7feefc1341ff03b7f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 15:30:44 -0800 Subject: [PATCH 4137/5359] Failing test case for #2493 --- features/package-install.feature | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 features/package-install.feature diff --git a/features/package-install.feature b/features/package-install.feature new file mode 100644 index 000000000..d883aafd0 --- /dev/null +++ b/features/package-install.feature @@ -0,0 +1,20 @@ +Feature: Install WP-CLI packages + + Scenario: Install a package with 'wp-cli/wp-cli' as a dependency + Given a WP install + + When I run `wp package install sinebridge/wp-cli-about:v1.0.1` + Then STDOUT should contain: + """ + Success: Package installed + """ + And STDOUT should not contain: + """ + requires wp-cli/wp-cli + """ + + When I run `wp about` + Then STDOUT should contain: + """ + Site Information + """ From b86a90a476554dc66cfe4d4dced90e026f9f466e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 15:35:00 -0800 Subject: [PATCH 4138/5359] Use 'wp-cli/wp-cli' for the Composer project name in our package dir Apparently this causes Composer to skip 'wp-cli/wp-cli' as a dependency, which is exactly what we want. --- php/commands/package.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index 2dc50ae0e..27f14c317 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -91,6 +91,7 @@ public function install( $args, $assoc_args ) { WP_CLI::log( sprintf( "Updating %s to require the package...", $composer_json_obj->getPath() ) ); $composer_backup = file_get_contents( $composer_json_obj->getPath() ); $json_manipulator = new JsonManipulator( $composer_backup ); + $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); $json_manipulator->addLink( 'require', $package_name, $version ); file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); try { @@ -413,7 +414,7 @@ private function create_default_composer_json( $composer_path ) { ); $options = array( - 'name' => 'wp-cli/wp-cli-community-packages', + 'name' => 'wp-cli/wp-cli', 'description' => 'Installed community packages used by WP-CLI', 'authors' => array( $author ), 'homepage' => self::PACKAGE_INDEX_URL, From a279f661f29aade58b767b31983cb8673f67b315 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 16:30:30 -0800 Subject: [PATCH 4139/5359] Use `wp package path` to get the path of an installed package If you want to contribute to one, this is an easy way to dive in. --- php/commands/package.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index 27f14c317..8f7c65104 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -141,6 +141,31 @@ public function list_( $args, $assoc_args ) { $this->show_packages( $this->get_installed_packages(), $assoc_args ); } + /** + * Get the path to an installed WP-CLI package, or the package directory. + * + * If you want to contribute to a package, this is a great way to jump to it. + * + * ## OPTIONS + * + * [<name>] + * : Name of the package to get the directory for. + * + * ## EXAMPLES + * + * cd $(wp package path) + */ + function path( $args ) { + $packages_dir = WP_CLI::get_runner()->get_packages_dir_path(); + if ( ! empty( $args ) ) { + $packages_dir .= 'vendor/' . $args[0]; + if ( ! is_dir( $packages_dir ) ) { + WP_CLI::error( 'Invalid package name.' ); + } + } + WP_CLI::line( $packages_dir ); + } + /** * Uninstall a WP-CLI package. * From 0bcd2fe28131eee400ed4c9646944fa63fb2821d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Mar 2016 16:53:03 -0800 Subject: [PATCH 4140/5359] Newline is better formatting [ci skip] --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ceb46a61..e6bb879c5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,6 @@ Contribute ========== -Thanks in advance for helping to improve WP-CLI. To get started, please review our documentation on [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). +Thanks in advance for helping to improve WP-CLI. + +To get started, please review our documentation on [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). From b9a9e0144a6cf3a4befc4849472c37fba53df1ad Mon Sep 17 00:00:00 2001 From: Mike Pretzlaw <pretzlaw@gmail.com> Date: Wed, 9 Mar 2016 19:47:47 +0100 Subject: [PATCH 4141/5359] Bugfix: Vendor-dir is defined in the config-section The composer-vendor-dir can be defined in the config section of the composer.json. Unfortunately the utils.php looks up the vendor dir at another place. This commit fixes the flaw in ::get_vendor_paths(). --- php/utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index d8b30f913..67c709364 100644 --- a/php/utils.php +++ b/php/utils.php @@ -62,8 +62,8 @@ function get_vendor_paths() { $maybe_composer_json = WP_CLI_ROOT . '/../../../composer.json'; if ( file_exists( $maybe_composer_json ) && is_readable( $maybe_composer_json ) ) { $composer = json_decode( file_get_contents( $maybe_composer_json ) ); - if ( ! empty( $composer->{'vendor-dir'} ) ) { - array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->{'vendor-dir'} ); + if ( ! empty( $composer->config ) && ! empty( $composer->config->{'vendor-dir'} ) ) { + array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->config->{'vendor-dir'} ); } } return $vendor_paths; From 85e0813157bc3ceb117ce24b711c56d8e7fe9d2a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Mar 2016 05:04:26 -0800 Subject: [PATCH 4142/5359] Add WP REST API registration args to `scaffold (post-type|taxonomy)` These are pretty well-established now. --- templates/post_type.mustache | 3 +++ templates/taxonomy.mustache | 3 +++ 2 files changed, 6 insertions(+) diff --git a/templates/post_type.mustache b/templates/post_type.mustache index a86f73131..02f96e197 100644 --- a/templates/post_type.mustache +++ b/templates/post_type.mustache @@ -23,4 +23,7 @@ 'rewrite' => true, 'query_var' => true, 'menu_icon' => 'dashicons-{{dashicon}}', + 'show_in_rest' => true, + 'rest_base' => '{{slug}}', + 'rest_controller_class' => 'WP_REST_Posts_Controller', ) ); diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index e47807605..549c46ed2 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -30,4 +30,7 @@ 'not_found' => __( 'No {{label_plural}} found.', '{{textdomain}}' ), 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), ), + 'show_in_rest' => true, + 'rest_base' => '{{slug}}', + 'rest_controller_class' => 'WP_REST_Terms_Controller', ) ); From 2002b537dcfeccb9735df590757ebc3fdab06aa6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Mar 2016 17:08:45 -0800 Subject: [PATCH 4143/5359] Permit composer/semver >= 1.0 for greater flexibility --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 33a8b6f9a..7cae33f61 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "mustangostang/spyc": "0.5.1", - "composer/semver": "1.0.0", + "composer/semver": "~1.0", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", "symfony/finder": "2.7.*", From e5ff5d527d4282e57b114c31eda1b7451622864b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Mar 2016 17:09:41 -0800 Subject: [PATCH 4144/5359] Update Composer dependencies across the board --- composer.lock | 136 ++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/composer.lock b/composer.lock index e0301b534..2a6b72b4b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "78165aafa4140e764d4f1dc828752cce", - "content-hash": "7b6ae0fa1f96555e592ce2f48493a535", + "hash": "3ce120babd1d96753c754447b76336ab", + "content-hash": "f5581ba07d3403776f73de169913990d", "packages": [ { "name": "composer/composer", @@ -83,29 +83,29 @@ }, { "name": "composer/semver", - "version": "1.0.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba" + "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/d0e1ccc6d44ab318b758d709e19176037da6b1ba", - "reference": "d0e1ccc6d44ab318b758d709e19176037da6b1ba", + "url": "https://api.github.com/repos/composer/semver/zipball/df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", + "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "~2.3" + "phpunit/phpunit": "^4.5 || ^5.0.5", + "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.1-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -118,10 +118,6 @@ "MIT" ], "authors": [ - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com" - }, { "name": "Nils Adermann", "email": "naderman@naderman.de", @@ -131,6 +127,11 @@ "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" } ], "description": "Semver library that offers utilities, version constraint parsing and validation.", @@ -140,7 +141,7 @@ "validation", "versioning" ], - "time": "2015-09-21 09:42:36" + "time": "2016-02-25 22:23:39" }, { "name": "composer/spdx-licenses", @@ -271,16 +272,16 @@ }, { "name": "mustache/mustache", - "version": "v2.9.0", + "version": "v2.10.0", "source": { "type": "git", "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "c745b01956caf27d26b55a72a90aff56bc169cd6" + "reference": "0bb2f76e2f34a8864a32be34c4ec66274d76c05e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/c745b01956caf27d26b55a72a90aff56bc169cd6", - "reference": "c745b01956caf27d26b55a72a90aff56bc169cd6", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/0bb2f76e2f34a8864a32be34c4ec66274d76c05e", + "reference": "0bb2f76e2f34a8864a32be34c4ec66274d76c05e", "shasum": "" }, "require": { @@ -288,7 +289,7 @@ }, "require-dev": { "fabpot/php-cs-fixer": "~1.6", - "phpunit/phpunit": "~3.7|~4.0" + "phpunit/phpunit": "~3.7|~4.0|~5.0" }, "type": "library", "autoload": { @@ -313,7 +314,7 @@ "mustache", "templating" ], - "time": "2015-08-15 19:23:13" + "time": "2016-02-27 19:22:46" }, { "name": "mustangostang/spyc", @@ -637,22 +638,25 @@ }, { "name": "symfony/config", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "fbd0083cd9dac06556bd1096deaa0295c18a7584" + "reference": "833beea4b0bc083a5aea84b9cf725248a74aaaff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/fbd0083cd9dac06556bd1096deaa0295c18a7584", - "reference": "fbd0083cd9dac06556bd1096deaa0295c18a7584", + "url": "https://api.github.com/repos/symfony/config/zipball/833beea4b0bc083a5aea84b9cf725248a74aaaff", + "reference": "833beea4b0bc083a5aea84b9cf725248a74aaaff", "shasum": "" }, "require": { "php": ">=5.3.9", "symfony/filesystem": "~2.3" }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, "type": "library", "extra": { "branch-alias": { @@ -683,20 +687,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-01-03 15:32:00" + "time": "2016-02-22 16:12:29" }, { "name": "symfony/console", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6" + "reference": "ee91ec301cd88ee38ab14505025fe94bbc19a9c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d3fc138b6ed8f8074591821d3416d8f9c04d6ca6", - "reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6", + "url": "https://api.github.com/repos/symfony/console/zipball/ee91ec301cd88ee38ab14505025fe94bbc19a9c1", + "reference": "ee91ec301cd88ee38ab14505025fe94bbc19a9c1", "shasum": "" }, "require": { @@ -742,20 +746,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-01-14 08:26:43" + "time": "2016-02-28 16:19:47" }, { "name": "symfony/dependency-injection", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "37dfddbf3791d79b46b11f610b39e90d622e7183" + "reference": "157326648175d52326cd9b9e5f4fef207dc447f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/37dfddbf3791d79b46b11f610b39e90d622e7183", - "reference": "37dfddbf3791d79b46b11f610b39e90d622e7183", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/157326648175d52326cd9b9e5f4fef207dc447f9", + "reference": "157326648175d52326cd9b9e5f4fef207dc447f9", "shasum": "" }, "require": { @@ -804,20 +808,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-01-12 17:44:11" + "time": "2016-02-28 16:34:40" }, { "name": "symfony/event-dispatcher", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "79493b6421786e5a0fc2d161410aa86f400bcaea" + "reference": "b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/79493b6421786e5a0fc2d161410aa86f400bcaea", - "reference": "79493b6421786e5a0fc2d161410aa86f400bcaea", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce", + "reference": "b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce", "shasum": "" }, "require": { @@ -864,20 +868,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-01-13 10:26:43" + "time": "2016-01-27 05:09:39" }, { "name": "symfony/filesystem", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "78188c6971053ff8eaa00fa180c0747c296152f6" + "reference": "ce25d60462dd7088fca4feadba08321bee4273b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/78188c6971053ff8eaa00fa180c0747c296152f6", - "reference": "78188c6971053ff8eaa00fa180c0747c296152f6", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ce25d60462dd7088fca4feadba08321bee4273b4", + "reference": "ce25d60462dd7088fca4feadba08321bee4273b4", "shasum": "" }, "require": { @@ -913,20 +917,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-01-13 07:57:33" + "time": "2016-02-18 16:03:55" }, { "name": "symfony/finder", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf" + "reference": "addcb70b33affbca4f3979b0d000259b63dd6711" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d20ac81c81a67ab898b0c0afa435f3e9a7d460cf", - "reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf", + "url": "https://api.github.com/repos/symfony/finder/zipball/addcb70b33affbca4f3979b0d000259b63dd6711", + "reference": "addcb70b33affbca4f3979b0d000259b63dd6711", "shasum": "" }, "require": { @@ -962,20 +966,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-01-14 08:26:43" + "time": "2016-02-22 16:12:29" }, { "name": "symfony/process", - "version": "v2.8.2", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac" + "reference": "7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", - "reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac", + "url": "https://api.github.com/repos/symfony/process/zipball/7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe", + "reference": "7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe", "shasum": "" }, "require": { @@ -1011,20 +1015,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-01-06 09:59:23" + "time": "2016-02-02 13:33:15" }, { "name": "symfony/translation", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "8cbab8445ad4269427077ba02fff8718cb397e22" + "reference": "4c61cf815af17eee4cebf0e4c66f56a2f704cfd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/8cbab8445ad4269427077ba02fff8718cb397e22", - "reference": "8cbab8445ad4269427077ba02fff8718cb397e22", + "url": "https://api.github.com/repos/symfony/translation/zipball/4c61cf815af17eee4cebf0e4c66f56a2f704cfd8", + "reference": "4c61cf815af17eee4cebf0e4c66f56a2f704cfd8", "shasum": "" }, "require": { @@ -1074,20 +1078,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-01-03 15:32:00" + "time": "2016-02-01 20:45:15" }, { "name": "symfony/yaml", - "version": "v2.7.9", + "version": "v2.7.10", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "a91e8af3dcde226e00be2e1c068764eef7b4c153" + "reference": "fc0ad7a7450ed4434c9a397796a9f56199de2053" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/a91e8af3dcde226e00be2e1c068764eef7b4c153", - "reference": "a91e8af3dcde226e00be2e1c068764eef7b4c153", + "url": "https://api.github.com/repos/symfony/yaml/zipball/fc0ad7a7450ed4434c9a397796a9f56199de2053", + "reference": "fc0ad7a7450ed4434c9a397796a9f56199de2053", "shasum": "" }, "require": { @@ -1123,7 +1127,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-01-13 10:26:43" + "time": "2016-02-23 07:38:51" }, { "name": "wp-cli/php-cli-tools", From 04a6224bfe27a259fc75afe5cbd5e894e5b0c80f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Mar 2016 17:39:58 -0800 Subject: [PATCH 4145/5359] Failing test case for a bad command causing `wp package` failure --- features/package.feature | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/features/package.feature b/features/package.feature index ec40ebf7c..9effd8f3c 100644 --- a/features/package.feature +++ b/features/package.feature @@ -29,3 +29,20 @@ Feature: Manage WP-CLI packages """ danielbachhuber/wp-cli-reset-post-date-command """ + + Scenario: Run package commands early, before any bad code can break them + Given an empty directory + And a bad-command.php file: + """ + <?php + WP_CLI::error( "Doing it wrong." ); + """ + + When I try `wp --require=bad-command.php option` + Then STDERR should contain: + """ + Error: Doing it wrong. + """ + + When I run `wp --require=bad-command.php package list` + Then STDERR should be empty From 2b2a07071e72cf3f906d023279977b3f73ddb6fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Mar 2016 17:42:48 -0800 Subject: [PATCH 4146/5359] Run `wp package` commands before any packages are loaded If a user installs a bad package, we want them to be able to back out of it. --- php/WP_CLI/Runner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 628a9a67f..fe88ae9cb 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -619,6 +619,12 @@ public function start() { exit; } + // Protect 'package' commands from most of the runtime too + if ( 'package' === $this->arguments[0] ) { + $this->_run_command(); + exit; + } + // Load bundled commands early, so that they're forced to use the same // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); From 05ff88bf66c7276fc95cd80f9fa8f85547c55b2f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 07:43:29 -0800 Subject: [PATCH 4147/5359] Support registering `default` and `options` for positional/assoc args `default` fills the value when it isn't set. `options` validates the filled value against an enum of values. YAML for the win: ``` --volume=<number> : Sets the volume. --- default: 10 --- ``` --- features/command.feature | 115 +++++++++++++++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 44 +++++++++- php/WP_CLI/DocParser.php | 30 +++++++ php/class-wp-cli.php | 13 ++- tests/test-doc-parser.php | 41 ++++++++++ 5 files changed, 239 insertions(+), 4 deletions(-) diff --git a/features/command.feature b/features/command.feature index 92f640bbf..9e4ab00a5 100644 --- a/features/command.feature +++ b/features/command.feature @@ -354,3 +354,118 @@ Feature: WP-CLI Commands [--meal=<meal>] A type of meal. """ + + Scenario: Register a command with default and accepted arguments. + Given an empty directory + And a test-cmd.php file: + """ + <?php + /** + * An amazing command for managing burritos. + * + * [<bar>] + * : This is the bar argument. + * --- + * default: burrito + * --- + * + * [<shop>] + * : This is where you buy burritos. + * --- + * options: + * - left_coast_siesta + * - cha cha cha + * --- + * + * [--burrito=<burrito>] + * : This is the burrito argument. + * --- + * options: + * - beans + * - veggies + * --- + * + * @when before_wp_load + */ + $foo = function( $args, $assoc_args ) { + $out = array( + 'bar' => isset( $args[0] ) ? $args[0] : '', + 'shop' => isset( $args[1] ) ? $args[1] : '', + 'burrito' => isset( $assoc_args['burrito'] ) ? $assoc_args['burrito'] : '', + ); + WP_CLI::print_value( $out, array( 'format' => 'yaml' ) ); + }; + WP_CLI::add_command( 'foo', $foo ); + """ + + When I run `wp --require=test-cmd.php foo --help` + Then STDOUT should contain: + """ + [<bar>] + This is the bar argument. + --- + default: burrito + --- + """ + And STDOUT should contain: + """ + [--burrito=<burrito>] + This is the burrito argument. + --- + options: + - beans + - veggies + --- + """ + + When I run `wp --require=test-cmd.php foo` + Then STDOUT should be YAML containing: + """ + bar: burrito + shop: + burrito: + """ + + When I run `wp --require=test-cmd.php foo ''` + Then STDOUT should be YAML containing: + """ + bar: + shop: + burrito: + """ + + When I run `wp --require=test-cmd.php foo apple --burrito=veggies` + Then STDOUT should be YAML containing: + """ + bar: apple + shop: + burrito: veggies + """ + + When I try `wp --require=test-cmd.php foo apple --burrito=meat` + Then STDERR should contain: + """ + Error: Parameter errors: + Invalid value specified for 'burrito' (This is the burrito argument.) + """ + + When I try `wp --require=test-cmd.php foo apple --burrito=''` + Then STDERR should contain: + """ + Error: Parameter errors: + Invalid value specified for 'burrito' (This is the burrito argument.) + """ + + When I try `wp --require=test-cmd.php foo apple taco_del_mar` + Then STDERR should contain: + """ + Error: Invalid value specified for positional arg. + """ + + When I run `wp --require=test-cmd.php foo apple 'cha cha cha'` + Then STDOUT should be YAML containing: + """ + bar: apple + shop: cha cha cha + burrito: + """ diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 202d51e73..de5f629fd 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -252,9 +252,47 @@ private function validate_args( $args, $assoc_args, $extra_args ) { implode( ' ', $unknown_positionals ) ); } - list( $errors, $to_unset ) = $validator->validate_assoc( + $synopsis_spec = \WP_CLI\SynopsisParser::parse( $synopsis ); + $i = 0; + $errors = array( 'fatal' => array(), 'warning' => array() ); + foreach( $synopsis_spec as $spec ) { + if ( ! empty( $spec['repeating'] ) ) { + continue; + } + if ( 'positional' === $spec['type'] ) { + $spec_args = $this->docparser->get_arg_args( $spec['name'] ); + if ( ! isset( $args[ $i ] ) ) { + if ( isset( $spec_args['default'] ) ) { + $args[ $i ] = $spec_args['default']; + } + } + if ( isset( $args[ $i ] ) && isset( $spec_args['options'] ) ) { + if ( ! in_array( $args[ $i ], $spec_args['options'] ) ) { + \WP_CLI::error( 'Invalid value specified for positional arg.' ); + } + } + $i++; + } else if ( 'assoc' === $spec['type'] ) { + $spec_args = $this->docparser->get_param_args( $spec['name'] ); + if ( ! isset( $assoc_args[ $spec['name'] ] ) ) { + if ( isset( $spec_args['default'] ) ) { + $assoc_args[ $spec['name'] ] = $spec_args['default']; + } + } + if ( isset( $assoc_args[ $spec['name'] ] ) && isset( $spec_args['options'] ) ) { + if ( ! in_array( $assoc_args[ $spec['name'] ], $spec_args['options'] ) ) { + $errors['fatal'][ $spec['name'] ] = "Invalid value specified for '{$spec['name']}'"; + } + } + } + } + + list( $returned_errors, $to_unset ) = $validator->validate_assoc( array_merge( \WP_CLI::get_config(), $extra_args, $assoc_args ) ); + foreach( array( 'fatal', 'warning' ) as $error_type ) { + $errors[ $error_type ] = array_merge( $errors[ $error_type ], $returned_errors[ $error_type ] ); + } if ( $this->name != 'help' ) { foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { @@ -276,7 +314,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { array_map( '\\WP_CLI::warning', $errors['warning'] ); - return $to_unset; + return array( $to_unset, $args, $assoc_args, $extra_args ); } /** @@ -294,7 +332,7 @@ public function invoke( $args, $assoc_args, $extra_args ) { $prompted_once = true; } - $to_unset = $this->validate_args( $args, $assoc_args, $extra_args ); + list( $to_unset, $args, $assoc_args, $extra_args ) = $this->validate_args( $args, $assoc_args, $extra_args ); foreach ( $to_unset as $key ) { unset( $assoc_args[ $key ] ); diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 06d57d328..9249003f9 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -2,6 +2,8 @@ namespace WP_CLI; +use Spyc; + /** * Parse command attributes from its PHPdoc. * Used to determine execution characteristics (arguments, etc.). @@ -111,6 +113,19 @@ public function get_arg_desc( $name ) { } + /** + * Get the arguments for a given argument. + * + * @param string $name Argument's doc name. + * @return mixed|null + */ + public function get_arg_args( $name ) { + if ( preg_match( "/\[?<{$name}>.+(\n: (.+?)(\n|$))?\n---\n(.+)\n---/sU", $this->docComment, $matches ) ) { + return Spyc::YAMLLoadString( $matches[4] ); + } + return null; + } + /** * Get the description for a given parameter. * @@ -126,4 +141,19 @@ public function get_param_desc( $key ) { return ''; } + /** + * Get the arguments for a given parameter. + * + * @param string $key Parameter's key. + * @return mixed|null + */ + public function get_param_args( $key ) { + + if ( preg_match( "/\[?--{$key}=.+(\n: (.+?)(\n|$))?\n---\n(.+)\n---/sU", $this->docComment, $matches ) ) { + return Spyc::YAMLLoadString( $matches[4] ); + } + + return null; + } + } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index a55ef8fc9..ee48c2a96 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -313,7 +313,18 @@ public static function add_command( $name, $callable, $args = array() ) { $long_desc = ''; $bits = explode( ' ', $synopsis ); foreach( $args['synopsis'] as $key => $arg ) { - $long_desc .= $bits[ $key ] . PHP_EOL . ': ' . $arg['description'] . PHP_EOL . PHP_EOL; + $long_desc .= $bits[ $key ] . PHP_EOL . ': ' . $arg['description'] . PHP_EOL; + $yamlify = array(); + foreach( array( 'options', 'default' ) as $key ) { + if ( isset( $arg[ $key ] ) ) { + $yamlify[ $key ] = $arg[ $key ]; + } + } + if ( ! empty( $yamlify ) ) { + $long_desc .= \Spyc::YAMLDump( $yamlify ); + $long_desc .= '---' . PHP_EOL; + } + $long_desc .= PHP_EOL; } if ( ! empty( $long_desc ) ) { $long_desc = rtrim( $long_desc, PHP_EOL ); diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index 150a33158..ec91eed0b 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -94,5 +94,46 @@ function test_complete() { ; $this->assertEquals( $longdesc, $doc->get_longdesc() ); } + + public function test_desc_parses_yaml() { + $longdesc = <<<EOB +## OPTIONS + +<genre>... +: Start with one or more genres. +--- +options: + - rock + - electronic +default: rock +--- + +--volume=<number> +: Sets the volume. +--- +default: 10 +--- + +--artist=<artist-name> +: Limit to a specific artist. + +## EXAMPLES + +wp rock-on electronic --volume=11 + +EOB; + $doc = new DocParser( $longdesc ); + $this->assertEquals( 'Start with one or more genres.', $doc->get_arg_desc( 'genre' ) ); + $this->assertEquals( 'Sets the volume.', $doc->get_param_desc( 'volume' ) ); + $this->assertEquals( array( + 'options' => array( 'rock', 'electronic' ), + 'default' => 'rock', + ), $doc->get_arg_args( 'genre' ) ); + $this->assertEquals( array( + 'default' => 10, + ), $doc->get_param_args( 'volume' ) ); + $this->assertNull( $doc->get_param_args( 'artist' ) ); + } + } From d34940b479d8b8f0aec40ec7f445138ea4250ceb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 10:26:01 -0800 Subject: [PATCH 4148/5359] Validate options for repeating positional args --- features/command.feature | 8 +++++++- php/WP_CLI/Dispatcher/Subcommand.php | 18 ++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/features/command.feature b/features/command.feature index 9e4ab00a5..405ec8436 100644 --- a/features/command.feature +++ b/features/command.feature @@ -369,7 +369,7 @@ Feature: WP-CLI Commands * default: burrito * --- * - * [<shop>] + * [<shop>...] * : This is where you buy burritos. * --- * options: @@ -462,6 +462,12 @@ Feature: WP-CLI Commands Error: Invalid value specified for positional arg. """ + When I try `wp --require=test-cmd.php foo apple 'cha cha cha' taco_del_mar` + Then STDERR should contain: + """ + Error: Invalid value specified for positional arg. + """ + When I run `wp --require=test-cmd.php foo apple 'cha cha cha'` Then STDOUT should be YAML containing: """ diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index de5f629fd..34ac0900b 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -256,9 +256,6 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $i = 0; $errors = array( 'fatal' => array(), 'warning' => array() ); foreach( $synopsis_spec as $spec ) { - if ( ! empty( $spec['repeating'] ) ) { - continue; - } if ( 'positional' === $spec['type'] ) { $spec_args = $this->docparser->get_arg_args( $spec['name'] ); if ( ! isset( $args[ $i ] ) ) { @@ -266,9 +263,18 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $args[ $i ] = $spec_args['default']; } } - if ( isset( $args[ $i ] ) && isset( $spec_args['options'] ) ) { - if ( ! in_array( $args[ $i ], $spec_args['options'] ) ) { - \WP_CLI::error( 'Invalid value specified for positional arg.' ); + if ( isset( $spec_args['options'] ) ) { + if ( ! empty( $spec['repeating'] ) ) { + do { + if ( isset( $args[ $i ] ) && ! in_array( $args[ $i ], $spec_args['options'] ) ) { + \WP_CLI::error( 'Invalid value specified for positional arg.' ); + } + $i++; + } while ( isset( $args[ $i ] ) ); + } else { + if ( ! in_array( $args[ $i ], $spec_args['options'] ) ) { + \WP_CLI::error( 'Invalid value specified for positional arg.' ); + } } } $i++; From ab67e727909653c55aef649eb815d956ff538cef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 10:30:27 -0800 Subject: [PATCH 4149/5359] Add tests for `options` and `default` on dynamic registration Also, `default` makes sense to include before `options` --- features/command.feature | 15 +++++++++++++++ php/class-wp-cli.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/command.feature b/features/command.feature index 405ec8436..59015ad57 100644 --- a/features/command.feature +++ b/features/command.feature @@ -299,6 +299,7 @@ Feature: WP-CLI Commands 'name' => 'message', 'description' => 'An awesome message to display', 'optional' => false, + 'options' => array( 'hello', 'goodbye' ), ), array( 'type' => 'assoc', @@ -311,6 +312,8 @@ Feature: WP-CLI Commands 'name' => 'meal', 'description' => 'A type of meal.', 'optional' => true, + 'default' => 'breakfast', + 'options' => array( 'breakfast', 'lunch', 'dinner' ), ), ), ) ); @@ -348,11 +351,23 @@ Feature: WP-CLI Commands """ <message> An awesome message to display + --- + options: + - hello + - goodbye + --- """ And STDOUT should contain: """ [--meal=<meal>] A type of meal. + --- + default: breakfast + options: + - breakfast + - lunch + - dinner + --- """ Scenario: Register a command with default and accepted arguments. diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ee48c2a96..eee3cd4e4 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -315,7 +315,7 @@ public static function add_command( $name, $callable, $args = array() ) { foreach( $args['synopsis'] as $key => $arg ) { $long_desc .= $bits[ $key ] . PHP_EOL . ': ' . $arg['description'] . PHP_EOL; $yamlify = array(); - foreach( array( 'options', 'default' ) as $key ) { + foreach( array( 'default', 'options' ) as $key ) { if ( isset( $arg[ $key ] ) ) { $yamlify[ $key ] = $arg[ $key ]; } From 074c26bdf4484033ddcf5568c8436c249ba276b0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 11:24:35 -0800 Subject: [PATCH 4150/5359] Accommodate `$args` that isn't zero-indexed --- php/WP_CLI/Dispatcher/Subcommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 34ac0900b..faf4846b9 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -253,7 +253,8 @@ private function validate_args( $args, $assoc_args, $extra_args ) { } $synopsis_spec = \WP_CLI\SynopsisParser::parse( $synopsis ); - $i = 0; + reset( $args ); + $i = key( $args ); $errors = array( 'fatal' => array(), 'warning' => array() ); foreach( $synopsis_spec as $spec ) { if ( 'positional' === $spec['type'] ) { From 4a84de4b5f5441301ea3e2655c6913d5c5e92cba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 11:36:20 -0800 Subject: [PATCH 4151/5359] Revert "Accommodate `$args` that isn't zero-indexed" This reverts commit 074c26bdf4484033ddcf5568c8436c249ba276b0. --- php/WP_CLI/Dispatcher/Subcommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index faf4846b9..34ac0900b 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -253,8 +253,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { } $synopsis_spec = \WP_CLI\SynopsisParser::parse( $synopsis ); - reset( $args ); - $i = key( $args ); + $i = 0; $errors = array( 'fatal' => array(), 'warning' => array() ); foreach( $synopsis_spec as $spec ) { if ( 'positional' === $spec['type'] ) { From 9a43ec3f4d710c2151d63eb96ebbbecdd4d048fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Mar 2016 11:47:32 -0800 Subject: [PATCH 4152/5359] Update return signature, so we don't noop args for commands without synopsis --- php/WP_CLI/Dispatcher/Subcommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 34ac0900b..6b9eef078 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -228,8 +228,9 @@ private function prompt_args( $args, $assoc_args ) { */ private function validate_args( $args, $assoc_args, $extra_args ) { $synopsis = $this->get_synopsis(); - if ( !$synopsis ) - return array(); + if ( !$synopsis ) { + return array( array(), $args, $assoc_args, $extra_args ); + } $validator = new \WP_CLI\SynopsisValidator( $synopsis ); From 24e64a6f29c81cab2b3dac4e1d0245d8187e4a2f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Mar 2016 06:45:01 -0700 Subject: [PATCH 4153/5359] Only register `description` for a command when present Doing so prevents wonky formatting when `description` isn't set. --- php/class-wp-cli.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index eee3cd4e4..0847b95df 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -313,7 +313,10 @@ public static function add_command( $name, $callable, $args = array() ) { $long_desc = ''; $bits = explode( ' ', $synopsis ); foreach( $args['synopsis'] as $key => $arg ) { - $long_desc .= $bits[ $key ] . PHP_EOL . ': ' . $arg['description'] . PHP_EOL; + $long_desc .= $bits[ $key ] . PHP_EOL; + if ( ! empty( $arg['description'] ) ) { + $long_desc .= ': ' . $arg['description'] . PHP_EOL; + } $yamlify = array(); foreach( array( 'default', 'options' ) as $key ) { if ( isset( $arg[ $key ] ) ) { From d80e84a178cb59b7ea06836b04b2e945302e2735 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Mar 2016 07:11:08 -0700 Subject: [PATCH 4154/5359] Clean up `scaffold plugin-tests` docs; link to documentation page --- php/commands/scaffold.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ed2524c46..4cb86394d 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -466,14 +466,17 @@ function plugin( $args, $assoc_args ) { /** * Generate files needed for running PHPUnit tests. * - * ## DESCRIPTION + * ## OVERVIEW * - * These are the files that are generated: + * The following files are generated for your plugin by this command: * - * * `phpunit.xml.dist` is the configuration file for PHPUnit - * * `.travis.yml` is the configuration file for Travis CI - * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite - * * `tests/test-sample.php` is a sample file containing the actual tests + * * `phpunit.xml.dist` is the configuration file for PHPUnit. + * * `.travis.yml` is the configuration file for Travis CI. + * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. + * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. + * * `tests/test-sample.php` is a sample file containing the actual tests. + * + * Learn more from the [plugin unit tests documentation](http://wp-cli.org/docs/plugin-unit-tests/). * * ## ENVIRONMENT * From 1de81217c5c0b21cc6fbb14f323b3c1d3c10f377 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 13 Mar 2016 07:48:38 -0700 Subject: [PATCH 4155/5359] Use `--skip-packages` to skip loading installed packages A similar idea to `--skip-plugins`, if a package has gone awry, permit normal usage of WP-CLI. --- features/package.feature | 10 ++++++++++ php/WP_CLI/Runner.php | 16 ++++++++++------ php/config-spec.php | 7 +++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/features/package.feature b/features/package.feature index 9effd8f3c..9d0591f7c 100644 --- a/features/package.feature +++ b/features/package.feature @@ -15,6 +15,16 @@ Feature: Manage WP-CLI packages When I run `wp help reset-post-date` Then STDERR should be empty + When I try `wp --skip-packages --debug help reset-post-date` + Then STDERR should contain: + """ + Debug: Skipped loading packages. + """ + And STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ + When I run `wp package list` Then STDOUT should contain: """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index fe88ae9cb..cd16de114 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -629,13 +629,17 @@ public function start() { // APIs as non-bundled commands. Utils\load_command( $this->arguments[0] ); - $package_autoload = $this->get_packages_dir_path() . 'vendor/autoload.php'; - - if ( file_exists( $package_autoload ) ) { - WP_CLI::debug( 'Loading packages from: ' . $package_autoload ); - require_once $package_autoload; + $skip_packages = \WP_CLI::get_runner()->config['skip-packages']; + if ( true === $skip_packages ) { + WP_CLI::debug( 'Skipped loading packages.' ); } else { - WP_CLI::debug( 'No package autoload found to load.' ); + $package_autoload = $this->get_packages_dir_path() . 'vendor/autoload.php'; + if ( file_exists( $package_autoload ) ) { + WP_CLI::debug( 'Loading packages from: ' . $package_autoload ); + require_once $package_autoload; + } else { + WP_CLI::debug( 'No package autoload found to load.' ); + } } if ( isset( $this->config['require'] ) ) { diff --git a/php/config-spec.php b/php/config-spec.php index cbaa958fd..6e55a544c 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -42,6 +42,13 @@ 'default' => '', ), + 'skip-packages' => array( + 'runtime' => '', + 'file' => '<bool>', + 'desc' => 'Skip loading all installed packages.', + 'default' => false, + ), + 'require' => array( 'runtime' => '=<path>', 'file' => '<path>', From 1fb032ac29875aa863b744487f61da472304d2f1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 18 Mar 2016 05:59:46 -0700 Subject: [PATCH 4156/5359] Properly add `wp plugin search` fields to plugins_api() request They need to be supplied in the first place, and passed in a non-standard format. --- features/plugin-search.feature | 14 ++++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 7 ++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 features/plugin-search.feature diff --git a/features/plugin-search.feature b/features/plugin-search.feature new file mode 100644 index 000000000..00a78875b --- /dev/null +++ b/features/plugin-search.feature @@ -0,0 +1,14 @@ +Feature: Search WordPress.org plugins + + Scenario: Search for plugins with active_installs field + Given a WP install + + When I run `wp plugin search foo --fields=name,slug,active_installs --format=csv` + Then STDOUT should contain: + """ + Success: Showing + """ + And STDOUT should contain: + """ + name,slug,active_installs + """ diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e9b02249d..7cb1adb5b 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -407,15 +407,20 @@ protected function _search( $args, $assoc_args ) { $defaults = array( 'per-page' => 10, - 'fields' => array( 'name', 'slug', 'rating' ) + 'fields' => implode( ',', array( 'name', 'slug', 'rating' ) ), ); $assoc_args = array_merge( $defaults, $assoc_args ); + $fields = array(); + foreach( explode( ',', $assoc_args['fields'] ) as $field ) { + $fields[ $field ] = true; + } $formatter = $this->get_formatter( $assoc_args ); $api_args = array( 'per_page' => (int) $assoc_args['per-page'], 'search' => $term, + 'fields' => $fields, ); if ( 'plugin' == $this->item_type ) { From 860cdfc0e896eccb807ef69953c1acc557b8755b Mon Sep 17 00:00:00 2001 From: hinoue-work <wpuser@wp-cli-14.04> Date: Fri, 18 Mar 2016 20:42:33 +0000 Subject: [PATCH 4157/5359] Added support for page parameter. --- php/WP_CLI/CommandWithUpgrade.php | 2 ++ php/commands/plugin.php | 3 +++ 2 files changed, 5 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 7cb1adb5b..965d3e1d7 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -407,6 +407,7 @@ protected function _search( $args, $assoc_args ) { $defaults = array( 'per-page' => 10, + 'page' => 1, 'fields' => implode( ',', array( 'name', 'slug', 'rating' ) ), ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -419,6 +420,7 @@ protected function _search( $args, $assoc_args ) { $api_args = array( 'per_page' => (int) $assoc_args['per-page'], + 'page' => (int) $assoc_args['page'], 'search' => $term, 'fields' => $fields, ); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 8290ce171..a7fdcb5c6 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -53,6 +53,9 @@ function status( $args ) { * <search> * : The string to search for. * + * [--page=<page>] + * : Optional page to display. Defaults to 1. + * * [--per-page=<per-page>] * : Optional number of results to display. Defaults to 10. * From 656490380c8771d1e35de0a116891a8eed5ce6a6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 18 Mar 2016 15:32:08 -0700 Subject: [PATCH 4158/5359] Add `parent` as a potential status in `wp theme status` Fixes error notices when we're rendering the special case `parent` status. --- php/WP_CLI/CommandWithUpgrade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e9b02249d..b5b233f52 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -372,12 +372,14 @@ protected function get_update_info( $slug ) { 'active' => 'A', 'active-network' => 'N', 'must-use' => 'M', + 'parent' => 'P', ), 'long' => array( 'inactive' => 'Inactive', 'active' => 'Active', 'active-network' => 'Network Active', 'must-use' => 'Must Use', + 'parent' => 'Parent', ) ); @@ -391,6 +393,7 @@ private function get_color( $status ) { 'active' => '%g', 'active-network' => '%g', 'must-use' => '%c', + 'parent' => '%p', ); return $colors[ $status ]; From 4a3f43d8ba7fb83c4ab64e8408d4f21d29873b1d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 18 Mar 2016 15:37:40 -0700 Subject: [PATCH 4159/5359] Lock php-cli-tools to v0.11.1 --- composer.json | 2 +- composer.lock | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 7cae33f61..094e13868 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.2", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "~0.11.1", "mustache/mustache": "~2.4", "mustangostang/spyc": "0.5.1", "composer/semver": "~1.0", diff --git a/composer.lock b/composer.lock index 2a6b72b4b..7f71b981d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "3ce120babd1d96753c754447b76336ab", - "content-hash": "f5581ba07d3403776f73de169913990d", + "hash": "826f45f99932268bb0bd8d8ad99505db", + "content-hash": "2aa6852b8aa1adbdaa0bf5bf09014eed", "packages": [ { "name": "composer/composer", @@ -1131,7 +1131,7 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "dev-master", + "version": "v0.11.1", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", @@ -1670,7 +1670,6 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "wp-cli/php-cli-tools": 20, "composer/composer": 15 }, "prefer-stable": false, From cf5f75598f8bf292a0e5c44f6bf5ef6739daac5f Mon Sep 17 00:00:00 2001 From: jacobischwartz <jacob@schwambell.com> Date: Sat, 19 Mar 2016 13:01:46 -0500 Subject: [PATCH 4160/5359] Behat test for importer fix. Also, refinement to bug fix. --- features/import.feature | 60 ++++++++++++++++++++++++++++++++++++++++- php/commands/import.php | 2 +- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/features/import.feature b/features/import.feature index c975325b2..893b69b44 100644 --- a/features/import.feature +++ b/features/import.feature @@ -69,7 +69,7 @@ Feature: Import content. When I run `find export-* -type f | wc -l` Then STDOUT should be: """ - 2 + 2 """ When I run `wp plugin install wordpress-importer --activate` @@ -87,3 +87,61 @@ Feature: Import content. """ 100 """ + + Scenario: Export and import page and referencing menu item in separate files + Given a WP install + And I run `mkdir export` + + When I run `wp menu create "My Menu"` + And I run `wp menu item add-post my-menu 2` + And I run `wp menu item list my-menu --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp export --dir=export --post_type=page --filename_format=0.page.xml` + When I run `wp export --dir=export --post_type=nav_menu_item --filename_format=1.menu.xml` + Then STDOUT should not be empty + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp post list --post_type=nav_menu_item --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `find export -type f | wc -l` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDERR should not contain: + """ + Warning: + """ + + When I run `wp import export --authors=skip --skip=image_resize` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --post_type=nav_menu_item --format=count` + Then STDOUT should be: + """ + 1 + """ \ No newline at end of file diff --git a/php/commands/import.php b/php/commands/import.php index 16372d6bb..c0644e33a 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -141,7 +141,7 @@ private function import_wxr( $file, $args ) { } $wp_import->import( $file ); - $this->processed_posts = array_merge($this->processed_posts, $wp_import->processed_posts); + $this->processed_posts += $wp_import->processed_posts; return true; } From 93229c0ca3788ce0601519102086d849f7bc1421 Mon Sep 17 00:00:00 2001 From: jacobischwartz <jacob@schwambell.com> Date: Sat, 19 Mar 2016 18:14:41 -0500 Subject: [PATCH 4161/5359] Minor refinements to import automated testing. Minor formatting fixes & more explicit verification. --- features/import.feature | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/features/import.feature b/features/import.feature index 893b69b44..6d48cfdb2 100644 --- a/features/import.feature +++ b/features/import.feature @@ -66,10 +66,10 @@ Feature: Import content. 0 """ - When I run `find export-* -type f | wc -l` + When I run `find export-* -type f | wc -l | sed 's/^ *//'` Then STDOUT should be: """ - 2 + 2 """ When I run `wp plugin install wordpress-importer --activate` @@ -92,6 +92,7 @@ Feature: Import content. Given a WP install And I run `mkdir export` + # NOTE: The Hello World page ID is 2. When I run `wp menu create "My Menu"` And I run `wp menu item add-post my-menu 2` And I run `wp menu item list my-menu --format=count` @@ -101,7 +102,7 @@ Feature: Import content. """ When I run `wp export --dir=export --post_type=page --filename_format=0.page.xml` - When I run `wp export --dir=export --post_type=nav_menu_item --filename_format=1.menu.xml` + And I run `wp export --dir=export --post_type=nav_menu_item --filename_format=1.menu.xml` Then STDOUT should not be empty When I run `wp site empty --yes` @@ -119,10 +120,10 @@ Feature: Import content. 0 """ - When I run `find export -type f | wc -l` + When I run `find export -type f | wc -l | sed 's/^ *//'` Then STDOUT should be: """ - 2 + 2 """ When I run `wp plugin install wordpress-importer --activate` @@ -144,4 +145,16 @@ Feature: Import content. Then STDOUT should be: """ 1 - """ \ No newline at end of file + """ + + When I run `wp menu item list my-menu --fields=object --format=csv | sed -n '2p'` + Then STDOUT should be: + """ + page + """ + + When I run `wp menu item list my-menu --fields=object_id --format=csv | sed -n '2p'` + Then STDOUT should be: + """ + 2 + """ From 7f4db5f3f707a29c08e81d6d6e5945046a6f519d Mon Sep 17 00:00:00 2001 From: jacobischwartz <jacob@schwambell.com> Date: Sun, 20 Mar 2016 16:12:28 -0500 Subject: [PATCH 4162/5359] Add import scenario to demonstrate existing failures. WP 3.7.11 and PHP 7 both cause menu imports to fail. Also, switch from sed to "contain" syntax. --- features/import.feature | 88 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/features/import.feature b/features/import.feature index 6d48cfdb2..4e808d86e 100644 --- a/features/import.feature +++ b/features/import.feature @@ -66,8 +66,8 @@ Feature: Import content. 0 """ - When I run `find export-* -type f | wc -l | sed 's/^ *//'` - Then STDOUT should be: + When I run `find export-* -type f | wc -l` + Then STDOUT should contain: """ 2 """ @@ -88,6 +88,78 @@ Feature: Import content. 100 """ + Scenario: Export and import page and referencing menu item + # This will not work with WP 3.7.11 or PHP 7. + # PHP 7 issue: https://wordpress.org/support/topic/importer-fails-to-import-menu-items-in-php7 + Given a WP install + And I run `mkdir export` + + # NOTE: The Hello World page ID is 2. + When I run `wp menu create "My Menu"` + And I run `wp menu item add-post my-menu 2` + And I run `wp menu item list my-menu --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp export --dir=export` + Then STDOUT should not be empty + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp post list --post_type=nav_menu_item --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `find export -type f | wc -l` + Then STDOUT should contain: + """ + 1 + """ + + When I run `wp plugin install wordpress-importer --activate` + Then STDERR should not contain: + """ + Warning: + """ + + When I run `wp import export --authors=skip --skip=image_resize` + Then STDOUT should not be empty + + When I run `wp post list --post_type=page --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --post_type=nav_menu_item --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp menu item list my-menu --fields=object --format=csv` + Then STDOUT should contain: + """ + page + """ + + When I run `wp menu item list my-menu --fields=object_id --format=csv` + Then STDOUT should contain: + """ + 2 + """ + Scenario: Export and import page and referencing menu item in separate files Given a WP install And I run `mkdir export` @@ -120,8 +192,8 @@ Feature: Import content. 0 """ - When I run `find export -type f | wc -l | sed 's/^ *//'` - Then STDOUT should be: + When I run `find export -type f | wc -l` + Then STDOUT should contain: """ 2 """ @@ -147,14 +219,14 @@ Feature: Import content. 1 """ - When I run `wp menu item list my-menu --fields=object --format=csv | sed -n '2p'` - Then STDOUT should be: + When I run `wp menu item list my-menu --fields=object --format=csv` + Then STDOUT should contain: """ page """ - When I run `wp menu item list my-menu --fields=object_id --format=csv | sed -n '2p'` - Then STDOUT should be: + When I run `wp menu item list my-menu --fields=object_id --format=csv` + Then STDOUT should contain: """ 2 """ From fdddd176f20457dd5503d7bc1948fd72638d6dcc Mon Sep 17 00:00:00 2001 From: jacobischwartz <jacob@schwambell.com> Date: Sun, 20 Mar 2016 17:52:27 -0500 Subject: [PATCH 4163/5359] Excempt new scenarios from PHP7 & WP below v4. --- features/import.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/import.feature b/features/import.feature index 4e808d86e..54a06829b 100644 --- a/features/import.feature +++ b/features/import.feature @@ -88,6 +88,7 @@ Feature: Import content. 100 """ + @less-than-php-7 @require-wp-4.0 Scenario: Export and import page and referencing menu item # This will not work with WP 3.7.11 or PHP 7. # PHP 7 issue: https://wordpress.org/support/topic/importer-fails-to-import-menu-items-in-php7 @@ -160,6 +161,7 @@ Feature: Import content. 2 """ + @less-than-php-7 @require-wp-4.0 Scenario: Export and import page and referencing menu item in separate files Given a WP install And I run `mkdir export` From 83530139eb7819a66ce5fe5b4ed5a62561f41ab9 Mon Sep 17 00:00:00 2001 From: Gary Jones <gamajo@gamajo.com> Date: Mon, 21 Mar 2016 17:03:47 +0000 Subject: [PATCH 4164/5359] Add documentation to bootstrap template File and functions should be documented. --- templates/bootstrap.mustache | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index be86eeaea..fb44b6640 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -1,15 +1,25 @@ <?php +/** + * PHPUnit bootstrap file + * + * @package {{plugin_slug}} + */ $_tests_dir = getenv( 'WP_TESTS_DIR' ); if ( ! $_tests_dir ) { $_tests_dir = '/tmp/wordpress-tests-lib'; } +// Give access to tests_add_filter() function. require_once $_tests_dir . '/includes/functions.php'; +/** + * Manually load the plugin being tested. + */ function _manually_load_plugin() { require dirname( dirname( __FILE__ ) ) . '/{{plugin_slug}}.php'; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); +// Start up the WP testing environment. require $_tests_dir . '/includes/bootstrap.php'; From f7e3fef8bf068f471808ee3dbff06c7515d4e917 Mon Sep 17 00:00:00 2001 From: Gary Jones <gamajo@gamajo.com> Date: Mon, 21 Mar 2016 17:21:18 +0000 Subject: [PATCH 4165/5359] Add documentation to test-sample.php --- templates/test-sample.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/templates/test-sample.php b/templates/test-sample.php index 79ba8f9a2..0264e9ffd 100644 --- a/templates/test-sample.php +++ b/templates/test-sample.php @@ -1,9 +1,20 @@ <?php +/** + * Class SampleTest + * + * @package + */ +/** + * Sample test case. + */ class SampleTest extends WP_UnitTestCase { + /** + * A single example test. + */ function test_sample() { - // replace this with some actual testing code + // Replace this with some actual testing code. $this->assertTrue( true ); } } From cbb62985a742a24843a345ebd68318f9a2e71055 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Mar 2016 14:51:46 -0700 Subject: [PATCH 4166/5359] Update `.mailmap` for 0.23.0 --- .mailmap | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.mailmap b/.mailmap index 9f24a1a94..115f09c47 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,7 @@ 2ndkauboy <bernhard@kau-boys.de> Akeda Bagus <admin@gedex.web.id> Alex Mills <git@viper007bond.com> +Anant Shrivastava <anant@anantshri.info> Andreas Heigl <andreas@heigl.org> andreascreten <andreas@madewithlove.be> Andrew Patton <andrew@acusti.ca> @@ -34,23 +35,29 @@ dlh01 <david@alleyinteractive.com> drrobotnik <B@Brandons-Mac-Pro-4.local> Duncan Brown <duncanjbrown@gmail.com> dwightjack <marco.solazzi@gmail.com> +Eduardo Alencar <ealencar10@gmail.com> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> eugeneware <eugene@noblesamurai.com> Evan Mattson <me@aaemnnost.tv> francescolaffi <francesco.laffi@gmail.com> +Frank Staude <frank@staude.net> Frankie Jarrett <fjarrett@godaddy.com> future500 <ramon@future500.nl> +Gary Jones <gamajo@gamajo.com> getsource <mike.schroder@dreamhost.com> Gilbert Pellegrom <gilbert@pellegrom.me> glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> Grant McInnes <grant.mcinnes@eyesopen.ca> Greg Anderson <greg.1.anderson@greenknowe.org> +hina <hina@hinaloe.net> +hinoue-work <wpuser@wp-cli-14.04> Hiroshi Urabe <mail@torounit.com> Ian Dunn <ian@iandunn.name> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> +jacobischwartz <jacob@schwambell.com> Jan VoráÄek <jan@voracek.net> Jeff Gould <jrgould@gmail.com> jeichorn <joshua.eichorn@pagely.com> @@ -76,14 +83,19 @@ lackingpenguin <benjamin.j.brooks@gmail.com> leewillis77 <leewillis77@gmail.com> lkwdwrd <woodward.lucas@gmail.com> Marc Addeo <marcaddeo@gmail.com> +Marco <mcastelluccio@mozilla.com> marcoceppi <marco@ceppi.net> +Mark Jaquith <mark.github@txfx.net> +Mark Kimsal <metrofindings@gmail.com> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> mattheu <matthew@matth.eu> +mbovel <matthieu@bovel.net> mboynes <mboynes@alleyinteractive.com> mgburns <mgburns@bu.edu> mgburns <mike@grady-etc.com> Mihail Minkov <Mihail.Minkov.BG@gmail.com> +Mike Pretzlaw <pretzlaw@gmail.com> mikey dubs <mike@herebox.org> milesj <mileswjohnson@gmail.com> MiteshShah <Mitesh.Shah@rtCamp.com> @@ -107,9 +119,11 @@ oknoway <nate@oknoway.com> om4james <james@jamesc.id.au> om4james <james@om4.com.au> oneumyvakin <oneumyvakin@gmail.com> +Otto Kekäläinen <otto@seravo.fi> ozh <ozh@ozh.org> phh <phh@peytz.dk> Pippin Williamson <pippin@pippinsplugins.com> +Radu Dan <za_creature@yahoo.com> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> Robin Schneider <ypid@riseup.net> From 31b9c00c688b50d9654a00c4449e88d63593d5ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 22 Mar 2016 14:52:58 -0700 Subject: [PATCH 4167/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c648a65ef..ca222b7cf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.23.0-alpha +0.23.0 From 9cbbc6e3355a9484622e81bf4c86f99816495302 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Mar 2016 05:57:46 -0700 Subject: [PATCH 4168/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ca222b7cf..5d22270f2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.23.0 +0.24.0-alpha From 44ebeb299657746fd28328fa1b3b517c1373a57c Mon Sep 17 00:00:00 2001 From: Geo <geo.artemenko@gmail.com> Date: Wed, 23 Mar 2016 16:25:23 -0400 Subject: [PATCH 4169/5359] remove redundant period --- php/commands/help.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/help.php b/php/commands/help.php index 4894c54f3..7210df898 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -6,7 +6,7 @@ class Help_Command extends WP_CLI_Command { /** - * Get help on WP-CLI, or on a specific. command. + * Get help on WP-CLI, or on a specific command. * * [<command>...] * : Get help on a specific command. From 4d9ed2649d8b4b404d75fa8316c3614f68c4524f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Mar 2016 14:41:28 -0700 Subject: [PATCH 4170/5359] Clarify the `wp_blogs` table also needs to be replaced on MS --- php/commands/search-replace.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 812258bad..5de6afa3c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -86,8 +86,8 @@ class Search_Replace_Command extends WP_CLI_Command { * * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * - * # Turn your production database into a local database - * wp search-replace --url=example.com example.com example.dev 'wp_*_options' + * # Turn your production multisite database into a local dev database + * wp search-replace --url=example.com example.com example.dev 'wp_*_options' wp_blogs * * # Search/replace to a SQL file without transforming the database * wp search-replace foo bar --export=database.sql From 8eb904456f63364259e801ead16f254cbcec5cc6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Mar 2016 16:25:11 -0700 Subject: [PATCH 4171/5359] Use next significant release operators for Composer dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` local âžœ wp-cli git:(master) composer update Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/filesystem (v2.7.10) - Installing symfony/filesystem (v2.8.3) Downloading: 100% - Removing symfony/finder (v2.7.10) - Installing symfony/finder (v2.8.3) Downloading: 100% - Installing symfony/polyfill-mbstring (v1.1.1) Downloading: 100% - Removing symfony/console (v2.7.10) - Installing symfony/console (v2.8.3) Downloading: 100% - Removing composer/composer (1.0.0-alpha11) - Installing composer/composer (1.0.0-beta1) Downloading: 100% - Removing symfony/yaml (v2.7.10) - Installing symfony/yaml (v2.8.3) Downloading: 100% - Removing symfony/config (v2.7.10) - Installing symfony/config (v2.8.3) Downloading: 100% - Removing symfony/dependency-injection (v2.7.10) - Installing symfony/dependency-injection (v2.8.3) Downloading: 100% - Removing symfony/event-dispatcher (v2.7.10) - Installing symfony/event-dispatcher (v2.8.3) Downloading: 100% - Removing symfony/translation (v2.7.10) - Installing symfony/translation (v2.8.3) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.json | 22 +++--- composer.lock | 210 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 147 insertions(+), 85 deletions(-) diff --git a/composer.json b/composer.json index 094e13868..66efa52b3 100644 --- a/composer.json +++ b/composer.json @@ -11,21 +11,21 @@ "php": ">=5.3.2", "wp-cli/php-cli-tools": "~0.11.1", "mustache/mustache": "~2.4", - "mustangostang/spyc": "0.5.1", + "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", "ramsey/array_column": "~1.1", "rmccue/requests": "~1.6", - "symfony/finder": "2.7.*", - "symfony/yaml": "2.7.*", - "symfony/filesystem": "2.7.*", - "symfony/config": "2.7.*", - "symfony/console": "2.7.*", - "symfony/dependency-injection": "2.7.*", - "symfony/event-dispatcher": "2.7.*", + "symfony/finder": "~2.7", + "symfony/yaml": "~2.7", + "symfony/filesystem": "~2.7", + "symfony/config": "~2.7", + "symfony/console": "~2.7", + "symfony/dependency-injection": "~2.7", + "symfony/event-dispatcher": "~2.7", "symfony/process": "~2.1", - "symfony/translation": "2.7.*", - "nb/oxymel": "0.1.0", - "composer/composer": "1.0.0-alpha11" + "symfony/translation": "~2.7", + "nb/oxymel": "~0.1.0", + "composer/composer": "~1.0.0-beta" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 7f71b981d..3d9ba656d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "826f45f99932268bb0bd8d8ad99505db", - "content-hash": "2aa6852b8aa1adbdaa0bf5bf09014eed", + "hash": "486865db5310fe94efdc68e6f0bcd370", + "content-hash": "6b640d71d1ddb8f42c44dfc0b508b9ae", "packages": [ { "name": "composer/composer", - "version": "1.0.0-alpha11", + "version": "1.0.0-beta1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6" + "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6", - "reference": "cd9054ce2abd1d06ed0eb1244eba1b2c2af633b6", + "url": "https://api.github.com/repos/composer/composer/zipball/5cb2b522637a941d608c58bd522f3b2a7bda4a1c", + "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c", "shasum": "" }, "require": { "composer/semver": "^1.0", "composer/spdx-licenses": "^1.0", - "justinrainbow/json-schema": "^1.4.4", + "justinrainbow/json-schema": "^1.6", "php": "^5.3.2 || ^7.0", "seld/cli-prompt": "^1.0", - "seld/jsonlint": "^1.0", + "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", "symfony/console": "^2.5 || ^3.0", "symfony/filesystem": "^2.5 || ^3.0", @@ -40,7 +40,8 @@ }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", - "ext-zip": "Enabling the zip extension allows you to unzip archives, and allows gzip compression of all internet traffic" + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" }, "bin": [ "bin/composer" @@ -79,7 +80,7 @@ "dependency", "package" ], - "time": "2015-11-14 16:21:07" + "time": "2016-03-03 15:15:10" }, { "name": "composer/semver", @@ -638,21 +639,21 @@ }, { "name": "symfony/config", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "833beea4b0bc083a5aea84b9cf725248a74aaaff" + "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/833beea4b0bc083a5aea84b9cf725248a74aaaff", - "reference": "833beea4b0bc083a5aea84b9cf725248a74aaaff", + "url": "https://api.github.com/repos/symfony/config/zipball/0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", + "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", "shasum": "" }, "require": { "php": ">=5.3.9", - "symfony/filesystem": "~2.3" + "symfony/filesystem": "~2.3|~3.0.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -660,7 +661,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -687,29 +688,30 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-02-22 16:12:29" + "time": "2016-02-22 16:12:45" }, { "name": "symfony/console", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ee91ec301cd88ee38ab14505025fe94bbc19a9c1" + "reference": "56cc5caf051189720b8de974e4746090aaa10d44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ee91ec301cd88ee38ab14505025fe94bbc19a9c1", - "reference": "ee91ec301cd88ee38ab14505025fe94bbc19a9c1", + "url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44", + "reference": "56cc5caf051189720b8de974e4746090aaa10d44", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.1" + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" }, "suggest": { "psr/log": "For using the console logger", @@ -719,7 +721,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -746,20 +748,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:19:47" + "time": "2016-02-28 16:20:50" }, { "name": "symfony/dependency-injection", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "157326648175d52326cd9b9e5f4fef207dc447f9" + "reference": "62251761a7615435b22ccf562384c588b431be44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/157326648175d52326cd9b9e5f4fef207dc447f9", - "reference": "157326648175d52326cd9b9e5f4fef207dc447f9", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/62251761a7615435b22ccf562384c588b431be44", + "reference": "62251761a7615435b22ccf562384c588b431be44", "shasum": "" }, "require": { @@ -769,9 +771,9 @@ "symfony/expression-language": "<2.6" }, "require-dev": { - "symfony/config": "~2.2", - "symfony/expression-language": "~2.6", - "symfony/yaml": "~2.1" + "symfony/config": "~2.2|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/yaml": "~2.1|~3.0.0" }, "suggest": { "symfony/config": "", @@ -781,7 +783,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -808,20 +810,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:34:40" + "time": "2016-02-28 16:34:46" }, { "name": "symfony/event-dispatcher", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce" + "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce", - "reference": "b68c0348ba5b3927a6c8e413cc7d594f3ccff3ce", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/78c468665c9568c3faaa9c416a7134308f2d85c3", + "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3", "shasum": "" }, "require": { @@ -829,10 +831,10 @@ }, "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" + "symfony/config": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" }, "suggest": { "symfony/dependency-injection": "", @@ -841,7 +843,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -868,20 +870,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:09:39" + "time": "2016-01-27 05:14:19" }, { "name": "symfony/filesystem", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ce25d60462dd7088fca4feadba08321bee4273b4" + "reference": "65cb36b6539b1d446527d60457248f30d045464d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ce25d60462dd7088fca4feadba08321bee4273b4", - "reference": "ce25d60462dd7088fca4feadba08321bee4273b4", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/65cb36b6539b1d446527d60457248f30d045464d", + "reference": "65cb36b6539b1d446527d60457248f30d045464d", "shasum": "" }, "require": { @@ -890,7 +892,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -917,20 +919,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-02-18 16:03:55" + "time": "2016-02-22 15:02:30" }, { "name": "symfony/finder", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "addcb70b33affbca4f3979b0d000259b63dd6711" + "reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/addcb70b33affbca4f3979b0d000259b63dd6711", - "reference": "addcb70b33affbca4f3979b0d000259b63dd6711", + "url": "https://api.github.com/repos/symfony/finder/zipball/877bb4b16ea573cc8c024e9590888fcf7eb7e0f7", + "reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7", "shasum": "" }, "require": { @@ -939,7 +941,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -966,7 +968,66 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-02-22 16:12:29" + "time": "2016-02-22 16:12:45" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "1289d16209491b584839022f29257ad859b8532d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", + "reference": "1289d16209491b584839022f29257ad859b8532d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-01-20 09:13:37" }, { "name": "symfony/process", @@ -1019,29 +1080,30 @@ }, { "name": "symfony/translation", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "4c61cf815af17eee4cebf0e4c66f56a2f704cfd8" + "reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/4c61cf815af17eee4cebf0e4c66f56a2f704cfd8", - "reference": "4c61cf815af17eee4cebf0e4c66f56a2f704cfd8", + "url": "https://api.github.com/repos/symfony/translation/zipball/b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7", + "reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/config": "<2.7" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.7", - "symfony/intl": "~2.4", - "symfony/yaml": "~2.2" + "symfony/config": "~2.8", + "symfony/intl": "~2.4|~3.0.0", + "symfony/yaml": "~2.2|~3.0.0" }, "suggest": { "psr/log": "To use logging capability in translator", @@ -1051,7 +1113,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -1078,20 +1140,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-02-01 20:45:15" + "time": "2016-02-02 09:49:18" }, { "name": "symfony/yaml", - "version": "v2.7.10", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "fc0ad7a7450ed4434c9a397796a9f56199de2053" + "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/fc0ad7a7450ed4434c9a397796a9f56199de2053", - "reference": "fc0ad7a7450ed4434c9a397796a9f56199de2053", + "url": "https://api.github.com/repos/symfony/yaml/zipball/2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", + "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", "shasum": "" }, "require": { @@ -1100,7 +1162,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -1127,7 +1189,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-02-23 07:38:51" + "time": "2016-02-23 07:41:20" }, { "name": "wp-cli/php-cli-tools", @@ -1670,7 +1732,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "composer/composer": 15 + "composer/composer": 10 }, "prefer-stable": false, "prefer-lowest": false, From 9d70d2f8fd332073c0915341813072ed2d1aa691 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 04:21:40 -0700 Subject: [PATCH 4172/5359] Catch exceptions in a couple more places --- php/commands/package.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 8f7c65104..33eb33044 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -248,7 +248,11 @@ private function get_community_packages() { static $community_packages; if ( null === $community_packages ) { - $community_packages = $this->package_index()->getPackages(); + try { + $community_packages = $this->package_index()->getPackages(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } } return $community_packages; @@ -272,7 +276,11 @@ private function package_index() { ))); $config->setConfigSource( new JsonConfigSource( $this->get_composer_json() ) ); - $package_index = new ComposerRepository( array( 'url' => self::PACKAGE_INDEX_URL ), new NullIO, $config ); + try { + $package_index = new ComposerRepository( array( 'url' => self::PACKAGE_INDEX_URL ), new NullIO, $config ); + } catch ( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } } return $package_index; From 8b1eff834b660e66c9047f94a7b341f7d99ec71e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 04:24:29 -0700 Subject: [PATCH 4173/5359] Permit downloading Composer packages over http The Package Index is served over http, which we should probably change. For the time being, we need to unfatal the fatal. --- php/commands/package.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 33eb33044..0fde97e9f 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -271,9 +271,12 @@ private function package_index() { if ( !$package_index ) { $config = new Config(); - $config->merge(array('config' => array( - 'home' => dirname( $this->get_composer_json_path() ), - ))); + $config->merge( array( + 'config' => array( + 'secure-http' => false, + 'home' => dirname( $this->get_composer_json_path() ), + ) + )); $config->setConfigSource( new JsonConfigSource( $this->get_composer_json() ) ); try { From aee7928565567a9b347c5c86969b0adfe88481b4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 06:36:35 -0700 Subject: [PATCH 4174/5359] Use the proper method signature to prevent another fatal --- php/WP_CLI/ComposerIO.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/ComposerIO.php b/php/WP_CLI/ComposerIO.php index 01197c922..85afaf9ff 100644 --- a/php/WP_CLI/ComposerIO.php +++ b/php/WP_CLI/ComposerIO.php @@ -20,14 +20,14 @@ public function isVerbose() { /** * {@inheritDoc} */ - public function write( $messages, $newline = true ) { + public function write( $messages, $newline = true, $verbosity = self::NORMAL ) { self::output_clean_message( $messages ); } /** * {@inheritDoc} */ - public function writeError( $messages, $newline = true ) { + public function writeError( $messages, $newline = true, $verbosity = self::NORMAL ) { self::output_clean_message( $messages ); } From f79ba98346cbfaac5b2b0d286343ef6331118dff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 12:14:33 -0700 Subject: [PATCH 4175/5359] Define variable, for when `$install->run()` doesn't return a value --- php/commands/package.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/package.php b/php/commands/package.php index 0fde97e9f..3be813eb4 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -112,6 +112,7 @@ public function install( $args, $assoc_args ) { // Try running the installer, but revert composer.json if failed WP_CLI::log( 'Using Composer to install the package...' ); WP_CLI::log( '---' ); + $res = false; try { $res = $install->run(); } catch ( Exception $e ) { From a7d9f9a9793915a5e14f601251d5cd90e2168b82 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 12:16:43 -0700 Subject: [PATCH 4176/5359] Also set `secure-http=>false` for the packages composer.json See 8b1eff834b660e66c9047f94a7b341f7d99ec71e --- php/commands/package.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/package.php b/php/commands/package.php index 3be813eb4..5605a39c1 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -93,6 +93,7 @@ public function install( $args, $assoc_args ) { $json_manipulator = new JsonManipulator( $composer_backup ); $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); $json_manipulator->addLink( 'require', $package_name, $version ); + $json_manipulator->addConfigSetting( 'secure-http', false ); file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); try { $composer = $this->get_composer(); From d265824ed5f16c78a1a482fe240c151682eed1c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 12:31:26 -0700 Subject: [PATCH 4177/5359] Mark `WP_CLI::run_command()` public; clarify `::launch_self()` See https://github.com/wp-cli/scaffold-package-command/commit/7dc321c864893e5d2afda17471cd2a664a2968b5 --- php/WP_CLI/Runner.php | 3 +-- php/class-wp-cli.php | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cd16de114..43bde527a 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -300,8 +300,7 @@ public function find_command_to_run( $args ) { } /** - * Find the WP-CLI command to run given arguments, - * and invoke it. + * Find the WP-CLI command to run given arguments, and invoke it. * * @param array $args Positional arguments including command name * @param array $assoc_args diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0847b95df..7e2c1de3c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -670,6 +670,11 @@ public static function launch( $command, $exit_on_error = true, $return_detailed /** * Run a WP-CLI command in a new process reusing the current runtime arguments. * + * Note: While this command does persist a limited set of runtime arguments, + * it *does not* persist environment variables. Practically speaking, WP-CLI + * packages won't be loaded when using WP_CLI::launch_self() because the + * launched process doesn't have access to the current process $HOME. + * * @access public * @category Execution * @@ -745,13 +750,24 @@ public static function get_config( $key = null ) { } /** - * Run a given command within the current process using the same global parameters. + * Run a given command within the current process using the same global + * parameters. + * + * To run a command using a new process with the same global parameters, + * use WP_CLI::launch_self(). To run a command using a new process with + * different global parameters, use WP_CLI::launch(). + * + * ``` + * ob_start(); + * WP_CLI::run_command( array( 'cli', 'cmd-dump' ) ); + * $ret = ob_get_clean(); + * ``` * - * To run a command using a new process with the same global parameters, use WP_CLI::launch_self() - * To run a command using a new process with different global parameters, use WP_CLI::launch() + * @access public + * @category Execution * - * @param array - * @param array + * @param array $args Positional arguments including command name. + * @param array $assoc_args */ public static function run_command( $args, $assoc_args = array() ) { self::get_runner()->run_command( $args, $assoc_args ); From 54be268e9e6df19ba4ae399355e41b38f46ea88e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Mar 2016 14:57:17 -0700 Subject: [PATCH 4178/5359] Failing test case for arg/param arg parsing --- tests/test-doc-parser.php | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index ec91eed0b..41b43138d 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -135,5 +135,57 @@ public function test_desc_parses_yaml() { $this->assertNull( $doc->get_param_args( 'artist' ) ); } + public function test_desc_doesnt_parse_far_params_yaml() { + $longdesc = <<<EOB +## OPTIONS + +<hook> +: The name of the action or filter. + +[--format=<format>] +: List callbacks as a table, JSON, CSV, or YAML. +--- +default: table +options: + - table + - json + - csv + - yaml +--- +EOB; + $doc = new DocParser( $longdesc ); + $this->assertEquals( $doc->get_param_args( 'format' ), array( + 'default' => 'table', + 'options' => array( 'table', 'json', 'csv', 'yaml' ), + ) ); + $this->assertNull( $doc->get_arg_args( 'hook' ) ); + } + + public function test_desc_doesnt_parse_far_args_yaml() { + $longdesc = <<<EOB +## OPTIONS + +<hook> +: The name of the action or filter. + +<format> +: List callbacks as a table, JSON, CSV, or YAML. +--- +default: table +options: + - table + - json + - csv + - yaml +--- +EOB; + $doc = new DocParser( $longdesc ); + $this->assertEquals( $doc->get_arg_args( 'format' ), array( + 'default' => 'table', + 'options' => array( 'table', 'json', 'csv', 'yaml' ), + ) ); + $this->assertNull( $doc->get_arg_args( 'hook' ) ); + } + } From a7d86a3ea445d1a344f4e62a9db444e602cb1edc Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Fri, 25 Mar 2016 01:33:01 -0400 Subject: [PATCH 4179/5359] Fix plugin header formatting Currently the `@package` tag and the plugin name header are both formatted as `Plugin-name`. Logically, you'd expect the plugin name header to be formatted as `Plugin Name`, and according to the WordPress documentation standards the `@package` tag should be capitalized and separated by underscores (e.g. `Plugin_Name`). This commit fixes those issues. --- php/commands/scaffold.php | 7 +++++-- templates/plugin.mustache | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 1df51eb1b..d60fe821e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -515,11 +515,14 @@ public function package_tests( $args, $assoc_args ) { * */ function plugin( $args, $assoc_args ) { - $plugin_slug = $args[0]; + $plugin_slug = $args[0]; + $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); + $plugin_package = str_replace( ' ', '_', $plugin_name ); $data = wp_parse_args( $assoc_args, array( 'plugin_slug' => $plugin_slug, - 'plugin_name' => ucfirst( $plugin_slug ), + 'plugin_name' => $plugin_name, + 'plugin_package' => $plugin_package, 'plugin_description' => 'PLUGIN DESCRIPTION HERE', 'plugin_author' => 'YOUR NAME HERE', 'plugin_author_uri' => 'YOUR SITE HERE', diff --git a/templates/plugin.mustache b/templates/plugin.mustache index 1673f7357..c96eb303d 100644 --- a/templates/plugin.mustache +++ b/templates/plugin.mustache @@ -8,5 +8,5 @@ * Plugin URI: {{plugin_uri}} * Text Domain: {{textdomain}} * Domain Path: /languages - * @package {{plugin_name}} + * @package {{plugin_package}} */ From 345d80420e93d3be18926f2f8d7ce1d6b35e46a3 Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Fri, 25 Mar 2016 01:33:01 -0400 Subject: [PATCH 4180/5359] Fix plugin header formatting Currently the `@package` tag and the plugin name header are both formatted as `Plugin-name`. Logically, you'd expect the plugin name header to be formatted as `Plugin Name`, and according to the WordPress documentation standards the `@package` tag should be capitalized and separated by underscores (e.g. `Plugin_Name`). This commit fixes those issues. --- php/commands/scaffold.php | 7 +++++-- templates/plugin.mustache | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4cb86394d..4903b6ad4 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -410,11 +410,14 @@ private function get_output_path( $assoc_args, $subdir ) { * */ function plugin( $args, $assoc_args ) { - $plugin_slug = $args[0]; + $plugin_slug = $args[0]; + $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); + $plugin_package = str_replace( ' ', '_', $plugin_name ); $data = wp_parse_args( $assoc_args, array( 'plugin_slug' => $plugin_slug, - 'plugin_name' => ucfirst( $plugin_slug ), + 'plugin_name' => $plugin_name, + 'plugin_package' => $plugin_package, 'plugin_description' => 'PLUGIN DESCRIPTION HERE', 'plugin_author' => 'YOUR NAME HERE', 'plugin_author_uri' => 'YOUR SITE HERE', diff --git a/templates/plugin.mustache b/templates/plugin.mustache index 1673f7357..c96eb303d 100644 --- a/templates/plugin.mustache +++ b/templates/plugin.mustache @@ -8,5 +8,5 @@ * Plugin URI: {{plugin_uri}} * Text Domain: {{textdomain}} * Domain Path: /languages - * @package {{plugin_name}} + * @package {{plugin_package}} */ From 708bf6975a8fc9d57c3e9f2cc53dcf776c0f0722 Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Sat, 26 Mar 2016 14:34:40 -0400 Subject: [PATCH 4181/5359] Fix headers for other plugin files Updated the `@package` tags in `templates/bootstrap.mustache` and `templates/test-sample.php` --- templates/bootstrap.mustache | 2 +- templates/test-sample.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/templates/bootstrap.mustache b/templates/bootstrap.mustache index fb44b6640..05c21bf1e 100644 --- a/templates/bootstrap.mustache +++ b/templates/bootstrap.mustache @@ -2,7 +2,7 @@ /** * PHPUnit bootstrap file * - * @package {{plugin_slug}} + * @package {{plugin_package}} */ $_tests_dir = getenv( 'WP_TESTS_DIR' ); diff --git a/templates/test-sample.php b/templates/test-sample.php index 0264e9ffd..2e897d13d 100644 --- a/templates/test-sample.php +++ b/templates/test-sample.php @@ -2,7 +2,7 @@ /** * Class SampleTest * - * @package + * @package {{plugin_package}} */ /** @@ -18,4 +18,3 @@ function test_sample() { $this->assertTrue( true ); } } - From 27993ff60bc6928748f6503bb7fd2d473d43574f Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Sat, 26 Mar 2016 23:14:16 -0400 Subject: [PATCH 4182/5359] Update functional tests for new plugin header values --- features/scaffold.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index e7ddedaa8..dfe8ee71e 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -123,6 +123,14 @@ Feature: WordPress code scaffolding .DS_Store node_modules/ """ + And the {PLUGIN_DIR}/hello-world/hello-world.php should contain: + """ + * Plugin Name: Hello World + """ + And the {PLUGIN_DIR}/hello-world/hello-world.php should contain: + """ + * @package Hello_World + """ When I run `cat {PLUGIN_DIR}/hello-world/package.json` Then STDOUT should be JSON containing: @@ -206,6 +214,14 @@ Feature: WordPress code scaffolding """ require dirname( dirname( __FILE__ ) ) . '/hello-world.php'; """ + And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: + """ + * @package Hello World + """ + And the {PLUGIN_DIR}/hello-world/tests/test-sample.php file should contain: + """ + * @package Hello World + """ And the {PLUGIN_DIR}/hello-world/bin directory should contain: """ install-wp-tests.sh From bcb114c3314428fd94c4872ea0376bd176a7fa7c Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Sun, 27 Mar 2016 01:27:01 -0400 Subject: [PATCH 4183/5359] Fix missing `@package` in plugin test files Also fixed a couple of typos in `scaffold.feature` --- features/scaffold.feature | 4 ++-- php/commands/scaffold.php | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index dfe8ee71e..201db6568 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -216,11 +216,11 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: """ - * @package Hello World + * @package Hello_World """ And the {PLUGIN_DIR}/hello-world/tests/test-sample.php file should contain: """ - * @package Hello World + * @package Hello_World """ And the {PLUGIN_DIR}/hello-world/bin directory should contain: """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 4903b6ad4..60873ad79 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -528,6 +528,9 @@ function plugin_tests( $args, $assoc_args ) { WP_CLI::error( 'Invalid plugin specified.' ); } + $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); + $plugin_package = str_replace( ' ', '_', $plugin_name ); + $tests_dir = "$plugin_dir/tests"; $bin_dir = "$plugin_dir/bin"; @@ -549,16 +552,21 @@ function plugin_tests( $args, $assoc_args ) { } } + $plugin_data = array( + 'plugin_slug' => $plugin_slug, + 'plugin_package' => $plugin_package, + ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( - "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', compact( 'plugin_slug' ) ), - "$plugin_dir/.travis.yml" => Utils\mustache_render( '.travis.mustache', compact( 'wp_versions_to_test' ) ) + "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', $plugin_data ), + "$tests_dir/test-sample.php" => Utils\mustache_render( 'test-sample.php', $plugin_data ), + "$plugin_dir/.travis.yml" => Utils\mustache_render( '.travis.mustache', compact( 'wp_versions_to_test' ) ), ), $force ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, 'phpunit.xml.dist' => $plugin_dir, - 'test-sample.php' => $tests_dir, ); foreach ( $to_copy as $file => $dir ) { From 314ccebbbb9f72063e1fe77a29f891de618b21f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 27 Mar 2016 06:35:53 -0700 Subject: [PATCH 4184/5359] Use `is_callable()` in `WP_CLI:add_command()` This is much better than rolling our own equivalent logic --- php/class-wp-cli.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7e2c1de3c..17e66724b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -249,16 +249,12 @@ public static function do_hook( $when ) { */ public static function add_command( $name, $callable, $args = array() ) { $valid = false; - if ( is_object( $callable ) && ( $callable instanceof \Closure ) ) { - $valid = true; - } else if ( is_string( $callable ) && function_exists( $callable ) ) { + if ( is_callable( $callable ) ) { $valid = true; } else if ( is_string( $callable ) && class_exists( (string) $callable ) ) { $valid = true; } else if ( is_object( $callable ) ) { $valid = true; - } else if ( is_array( $callable ) && is_callable( $callable ) ) { - $valid = true; } if ( ! $valid ) { if ( is_array( $callable ) ) { From 90950a1ee1c23d3cb9221fcad0dd71a12ce7f7f5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Mar 2016 04:35:31 -0700 Subject: [PATCH 4185/5359] Rename test-sample.php to test-sample.mustache It's now a template --- php/commands/scaffold.php | 2 +- templates/{test-sample.php => test-sample.mustache} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename templates/{test-sample.php => test-sample.mustache} (100%) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 60873ad79..27a48e197 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -560,7 +560,7 @@ function plugin_tests( $args, $assoc_args ) { $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_written = $this->create_files( array( "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', $plugin_data ), - "$tests_dir/test-sample.php" => Utils\mustache_render( 'test-sample.php', $plugin_data ), + "$tests_dir/test-sample.php" => Utils\mustache_render( 'test-sample.mustache', $plugin_data ), "$plugin_dir/.travis.yml" => Utils\mustache_render( '.travis.mustache', compact( 'wp_versions_to_test' ) ), ), $force ); diff --git a/templates/test-sample.php b/templates/test-sample.mustache similarity index 100% rename from templates/test-sample.php rename to templates/test-sample.mustache From 867b0331b7e30beb508dd40f641a80aac1d9cfdc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Mar 2016 04:37:56 -0700 Subject: [PATCH 4186/5359] Fix assertions --- features/scaffold.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 201db6568..e7fd1fd23 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -123,11 +123,11 @@ Feature: WordPress code scaffolding .DS_Store node_modules/ """ - And the {PLUGIN_DIR}/hello-world/hello-world.php should contain: + And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: """ * Plugin Name: Hello World """ - And the {PLUGIN_DIR}/hello-world/hello-world.php should contain: + And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: """ * @package Hello_World """ From 15693aa98b041ed9b62ef0351abac3888b282d3a Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Mon, 28 Mar 2016 17:46:20 -0700 Subject: [PATCH 4187/5359] allow newlines in $prompt --- php/WP_CLI/REPL.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 576359ecc..0a14b3e42 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -80,18 +80,14 @@ private static function create_prompt_cmd( $prompt, $history_path ) { $prompt = escapeshellarg( $prompt ); $history_path = escapeshellarg( $history_path ); - $cmd = <<<BASH -set -f -history -r $history_path -LINE="" -read -re -p $prompt LINE -[ $? -eq 0 ] || exit -history -s "\$LINE" -history -w $history_path -echo \$LINE -BASH; - - $cmd = str_replace( "\n", '; ', $cmd ); + $cmd = "set -f; " + . "history -r $history_path; " + . "LINE=\"\"; " + . "read -re -p $prompt LINE; " + . "[ $? -eq 0 ] || exit; " + . "history -s \"\$LINE\"; " + . "history -w $history_path; " + . "echo \$LINE; "; return '/bin/bash -c ' . escapeshellarg( $cmd ); } From f82f244b823223f646cb31492e901dfa671f38ad Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Mon, 28 Mar 2016 17:46:52 -0700 Subject: [PATCH 4188/5359] add newline to REPL prompt --- php/commands/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 0bb052ff5..d0c39bd72 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -35,7 +35,7 @@ public function __invoke( $_, $assoc_args ) { if ( '\\Psy\\Shell' == $class ) { \Psy\Shell::debug(); } else { - $repl = new $class( 'wp> ' ); + $repl = new $class( "\nwp> " ); $repl->start(); } } From e89d03a03025ff477a0927c4eb7fb5af0a298a5a Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Tue, 29 Mar 2016 17:51:35 -0700 Subject: [PATCH 4189/5359] force set default timezone --- php/commands/package.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index 5605a39c1..e23040d15 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -238,6 +238,10 @@ private function get_composer() { // the 'vendor-dir' is, and where Composer is running from. // Best to just pretend we're installing a package from ~/.wp-cli or similar chdir( pathinfo( $composer_path, PATHINFO_DIRNAME ) ); + + // Prevent DateTime error/warning when no timezone set + date_default_timezone_set( @date_default_timezone_get() ); + return Factory::create( new NullIO, $composer_path ); } From f242229dd2b35b034a808efc4a5143c1b53d994a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Mar 2016 08:48:54 -0700 Subject: [PATCH 4190/5359] Explain what `wp cron test` actually does --- php/commands/cron.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index ccc763485..4b52d42a3 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -487,6 +487,13 @@ class Cron_Command extends WP_CLI_Command { /** * Test the WP Cron spawning system and report back its status. + * + * This command tests the spawning system by performing the following steps: + * * Checks to see if the `DISABLE_WP_CRON` constant is set; errors if true + * because WP-Cron is disabled. + * * Checks to see if the `ALTERNATE_WP_CRON` constant is set; warns if true + * * Attempts to spawn WP-Cron over HTTP; warns if non 200 response code is + * returned. */ public function test() { From 02b5b8cd54add1b2b0c370a386d5b23f5a7a0477 Mon Sep 17 00:00:00 2001 From: Mark Jaquith <mark.github@txfx.net> Date: Thu, 31 Mar 2016 22:43:38 -0400 Subject: [PATCH 4191/5359] Squash `wp export` notice about `skip_comments` 2ad7b8e21fa introduced a PHP notice because `$this->filters['skip_comments']` is checked, but it won't exist if the flag isn't set. --- php/export/class-wp-export-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/export/class-wp-export-query.php b/php/export/class-wp-export-query.php index e228fbfcd..6258d2169 100644 --- a/php/export/class-wp-export-query.php +++ b/php/export/class-wp-export-query.php @@ -356,7 +356,7 @@ private static function get_meta_for_post( $post ) { private function get_comments_for_post( $post ) { global $wpdb; - if ( $this->filters['skip_comments'] ) { + if ( isset( $this->filters['skip_comments'] ) ) { return array(); } From 4c6b3a75ddd77c1871ec1cf390eaa679d836c96a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Apr 2016 09:13:00 -0700 Subject: [PATCH 4192/5359] Use `--format=ids` with `wp (*) generate` output generated ids More helpful than a progress bar for chaining commands together: ``` wp user generate --format=ids | xargs -0 -d ' ' -I % wp user meta add % foo bar ``` --- features/comment-generate.feature | 17 ++++++++++++---- features/post-generate.feature | 11 +++++++++++ features/term-generate.feature | 14 +++++++++++++ features/user-generate.feature | 14 +++++++++++++ php/commands/comment.php | 33 +++++++++++++++++++++++++++---- php/commands/post.php | 27 ++++++++++++++++++++++--- php/commands/term.php | 27 ++++++++++++++++++++++--- php/commands/user.php | 28 +++++++++++++++++++++++--- 8 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 features/term-generate.feature create mode 100644 features/user-generate.feature diff --git a/features/comment-generate.feature b/features/comment-generate.feature index e3742ee9a..ee7cc72fd 100644 --- a/features/comment-generate.feature +++ b/features/comment-generate.feature @@ -1,8 +1,9 @@ Feature: Generate comments - Scenario: Generate a specific number of comments - Given a WP install + Background: + Given a WP install + Scenario: Generate a specific number of comments When I run `wp comment generate --count=20` And I run `wp comment list --format=count` Then STDOUT should be: @@ -11,8 +12,6 @@ Feature: Generate comments """ Scenario: Generate comments assigned to a specific post - Given a WP install - When I run `wp comment generate --count=4 --post_id=2` And I run `wp comment list --post_id=2 --format=count` Then STDOUT should be: @@ -25,3 +24,13 @@ Feature: Generate comments """ 1 """ + + Scenario: Generating comments and outputting ids + When I run `wp comment generate --count=1 --format=ids` + Then save STDOUT as {COMMENT_ID} + + When I run `wp comment update {COMMENT_ID} --comment_content="foo"` + Then STDOUT should contain: + """ + Success: + """ diff --git a/features/post-generate.feature b/features/post-generate.feature index 9a3e039c5..6dec688ab 100644 --- a/features/post-generate.feature +++ b/features/post-generate.feature @@ -31,3 +31,14 @@ Feature: Generate new WordPress posts """ 1 """ + + Scenario: Generating posts and outputting ids + When I run `wp post generate --count=1 --format=ids` + Then save STDOUT as {POST_ID} + + When I run `wp post update {POST_ID} --post_title="foo"` + Then STDOUT should contain: + """ + Success: + """ + diff --git a/features/term-generate.feature b/features/term-generate.feature new file mode 100644 index 000000000..58918ddfc --- /dev/null +++ b/features/term-generate.feature @@ -0,0 +1,14 @@ +Feature: Generate WP terms + + Background: + Given a WP install + + Scenario: Generating terms and outputting ids + When I run `wp term generate category --count=1 --format=ids` + Then save STDOUT as {TERM_ID} + + When I run `wp term update category {TERM_ID} --name="foo"` + Then STDOUT should contain: + """ + Success: + """ diff --git a/features/user-generate.feature b/features/user-generate.feature new file mode 100644 index 000000000..bf747d4a5 --- /dev/null +++ b/features/user-generate.feature @@ -0,0 +1,14 @@ +Feature: Generate WP users + + Background: + Given a WP install + + Scenario: Generating users and outputting ids + When I run `wp user generate --count=1 --format=ids` + Then save STDOUT as {USER_ID} + + When I run `wp user update {USER_ID} --display_name="foo"` + Then STDOUT should contain: + """ + Success: + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index 45a01d86f..3eb74fa30 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -99,6 +99,14 @@ public function update( $args, $assoc_args ) { * * [--post_id=<post-id>] * : Assign comments to a specific post. + * + * [--format=<format>] + * : Accepted values: progress, ids. Default: ids. + * + * ## EXAMPLES + * + * # Add meta to every generated comment + * wp comment generate --format=ids | xargs -0 -d ' ' -I % wp comment meta add % foo bar */ public function generate( $args, $assoc_args ) { @@ -108,20 +116,37 @@ public function generate( $args, $assoc_args ) { ); $assoc_args = array_merge( $defaults, $assoc_args ); - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); + $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); + + $notify = false; + if ( 'progress' === $format ) { + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); + } + $comment_count = wp_count_comments(); $total = (int )$comment_count->total_comments; $limit = $total + $assoc_args['count']; for ( $i = $total; $i < $limit; $i++ ) { - wp_insert_comment( array( + $comment_id = wp_insert_comment( array( 'comment_content' => "Comment {$i}", 'comment_post_ID' => $assoc_args['post_id'], ) ); - $notify->tick(); + if ( 'progress' === $format ) { + $notify->tick(); + } else if ( 'ids' === $format ) { + if ( 'ids' === $format ) { + echo $comment_id; + if ( $i < $limit - 1 ) { + echo ' '; + } + } + } } - $notify->finish(); + if ( 'progress' === $format ) { + $notify->finish(); + } } diff --git a/php/commands/post.php b/php/commands/post.php index 61cbd0beb..aa75dfd21 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -352,10 +352,16 @@ public function list_( $_, $assoc_args ) { * [--max_depth=<number>] * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 * + * [--format=<format>] + * : Accepted values: progress, ids. Default: ids. + * * ## EXAMPLES * * wp post generate --count=10 --post_type=page --post_date=1999-01-04 * curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 + * + * # Add meta to every generated post + * wp post generate --format=ids | xargs -0 -d ' ' -I % wp post meta add % foo bar */ public function generate( $args, $assoc_args ) { global $wpdb; @@ -394,7 +400,12 @@ public function generate( $args, $assoc_args ) { $limit = $count + $total; - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); + $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); + + $notify = false; + if ( 'progress' === $format ) { + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); + } $previous_post_id = 0; $current_depth = 1; @@ -433,11 +444,21 @@ public function generate( $args, $assoc_args ) { WP_CLI::warning( $post_id ); } else { $previous_post_id = $post_id; + if ( 'ids' === $format ) { + echo $post_id; + if ( $i < $limit - 1 ) { + echo ' '; + } + } } - $notify->tick(); + if ( 'progress' === $format ) { + $notify->tick(); + } + } + if ( 'progress' === $format ) { + $notify->finish(); } - $notify->finish(); // @codingStandardsIgnoreEnd } diff --git a/php/commands/term.php b/php/commands/term.php index 049fa6515..84ac9d61d 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -293,9 +293,15 @@ public function delete( $args ) { * [--max_depth=<number>] * : Generate child terms down to a certain depth. Default: 1 * + * [--format=<format>] + * : Accepted values: progress, ids. Default: ids. + * * ## EXAMPLES * * wp term generate --count=10 + * + * # Add meta to every generated term + * wp term generate category --format=ids | xargs -0 -d ' ' -I % wp term meta add % foo bar */ public function generate( $args, $assoc_args ) { global $wpdb; @@ -318,7 +324,12 @@ public function generate( $args, $assoc_args ) { $hierarchical = get_taxonomy( $taxonomy )->hierarchical; - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); + $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); + + $notify = false; + if ( 'progress' === $format ) { + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); + } $previous_term_id = 0; $current_parent = 0; @@ -359,15 +370,25 @@ public function generate( $args, $assoc_args ) { } else { $created[] = $term['term_id']; $previous_term_id = $term['term_id']; + if ( 'ids' === $format ) { + echo $term['term_id']; + if ( $i < $max_id + $count ) { + echo ' '; + } + } } - $notify->tick(); + if ( 'progress' === $format ) { + $notify->tick(); + } } wp_suspend_cache_invalidation( $suspend_cache_invalidation ); clean_term_cache( $created, $taxonomy ); - $notify->finish(); + if ( 'progress' === $format ) { + $notify->finish(); + } } /** diff --git a/php/commands/user.php b/php/commands/user.php index bda3adcfb..98c486150 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -366,6 +366,14 @@ public function update( $args, $assoc_args ) { * * [--role=<role>] * : The role of the generated users. Default: default role from WP + * + * [--format=<format>] + * : Accepted values: progress, ids. Default: ids. + * + * ## EXAMPLES + * + * # Add meta to every generated user + * wp user generate --format=ids | xargs -0 -d ' ' -I % wp user meta add % foo bar */ public function generate( $args, $assoc_args ) { global $blog_id; @@ -386,7 +394,12 @@ public function generate( $args, $assoc_args ) { $total = $user_count['total_users']; $limit = $assoc_args['count'] + $total; - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $assoc_args['count'] ); + $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); + + $notify = false; + if ( 'progress' === $format ) { + $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $assoc_args['count'] ); + } for ( $i = $total; $i < $limit; $i++ ) { $login = sprintf( 'user_%d_%d', $blog_id, $i ); @@ -405,10 +418,19 @@ public function generate( $args, $assoc_args ) { delete_user_option( $user_id, 'user_level' ); } - $notify->tick(); + if ( 'progress' === $format ) { + $notify->tick(); + } else if ( 'ids' === $format ) { + echo $user_id; + if ( $i < $limit - 1 ) { + echo ' '; + } + } } - $notify->finish(); + if ( 'progress' === $format ) { + $notify->finish(); + } } /** From 6597a6db5a773734a014b3015875ec3ad9b59aca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Apr 2016 09:16:55 -0700 Subject: [PATCH 4193/5359] Move tests to more sensible files --- features/term-generate.feature | 17 +++++++++++++++++ features/term.feature | 17 ----------------- features/user-generate.feature | 21 +++++++++++++++++++++ features/user.feature | 23 ----------------------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/features/term-generate.feature b/features/term-generate.feature index 58918ddfc..8da008a7b 100644 --- a/features/term-generate.feature +++ b/features/term-generate.feature @@ -3,6 +3,23 @@ Feature: Generate WP terms Background: Given a WP install + Scenario: Generating terms + When I run `wp term generate category --count=10` + And I run `wp term list category --format=count` + Then STDOUT should be: + """ + 11 + """ + + Scenario: Generating terms when terms already exist + When I run `wp term generate category --count=10` + And I run `wp term generate category --count=10` + And I run `wp term list category --format=count` + Then STDOUT should be: + """ + 21 + """ + Scenario: Generating terms and outputting ids When I run `wp term generate category --count=1 --format=ids` Then save STDOUT as {TERM_ID} diff --git a/features/term.feature b/features/term.feature index 5efcc7c7f..91781bdb9 100644 --- a/features/term.feature +++ b/features/term.feature @@ -75,23 +75,6 @@ Feature: Manage WordPress terms When I try the previous command again Then STDERR should not be empty - Scenario: Generating terms - When I run `wp term generate category --count=10` - And I run `wp term list category --format=count` - Then STDOUT should be: - """ - 11 - """ - - Scenario: Generating terms when terms already exist - When I run `wp term generate category --count=10` - And I run `wp term generate category --count=10` - And I run `wp term list category --format=count` - Then STDOUT should be: - """ - 21 - """ - Scenario: Term with a non-existent parent When I try `wp term create category Apple --parent=99 --porcelain` Then STDERR should be: diff --git a/features/user-generate.feature b/features/user-generate.feature index bf747d4a5..cbe263b3c 100644 --- a/features/user-generate.feature +++ b/features/user-generate.feature @@ -3,6 +3,27 @@ Feature: Generate WP users Background: Given a WP install + Scenario: Generating and deleting users + When I run `wp user list --role=editor --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp user generate --count=10 --role=editor` + And I run `wp user list --role=editor --format=count` + Then STDOUT should be: + """ + 10 + """ + + When I try `wp user list --field=ID | xargs wp user delete invalid-user --yes` + And I run `wp user list --format=count` + Then STDOUT should be: + """ + 0 + """ + Scenario: Generating users and outputting ids When I run `wp user generate --count=1 --format=ids` Then save STDOUT as {USER_ID} diff --git a/features/user.feature b/features/user.feature index 93a012bb1..3b8662b30 100644 --- a/features/user.feature +++ b/features/user.feature @@ -102,29 +102,6 @@ Feature: Manage WordPress users When I try `wp user get bobjones` Then STDERR should not be empty - Scenario: Generating and deleting users - Given a WP install - - When I run `wp user list --role=editor --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp user generate --count=10 --role=editor` - And I run `wp user list --role=editor --format=count` - Then STDOUT should be: - """ - 10 - """ - - When I try `wp user list --field=ID | xargs wp user delete invalid-user --yes` - And I run `wp user list --format=count` - Then STDOUT should be: - """ - 0 - """ - Scenario: Create new users on multisite Given a WP multisite install From c6d9601e6067d220297505748dfe43ccca7803d4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Apr 2016 09:25:40 -0700 Subject: [PATCH 4194/5359] Link to the documentation portal from the readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 35090ea9a..daf127aa0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ If you want to hack on WP-CLI, see [CONTRIBUTING.md](CONTRIBUTING.md). Where can I get more info? -------------------------- -For documentation and examples, check out [wp-cli.org](http://wp-cli.org/) and the [wiki](https://github.com/wp-cli/wp-cli/wiki). +For documentation and examples, check out [wp-cli.org](http://wp-cli.org/) and the [documentation portal](http://wp-cli.org/docs/). Also, WordPress Answers has a growing list of [WP-CLI related questions](http://wordpress.stackexchange.com/questions/tagged/wp-cli). @@ -23,7 +23,7 @@ I'm running into troubles, what can I do? ----------------------------------------- To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). -If you're reporting a bug, please also post the output from `wp --info`. +If you're reporting a bug, please include the output from `wp --info` and do your best to follow [bug reporting best practices](http://wp-cli.org/docs/bug-reports/). Credits ------- @@ -43,6 +43,6 @@ Who's behind this thing? * [Cristi Burcă](https://github.com/scribu) - previous maintainer * [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer -For more info, see [Governance](https://github.com/wp-cli/wp-cli/wiki/Governance). +For more info, see [Governance](http://wp-cli.org/docs/governance/). A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). From a57b13c2e322048a1e0023d16a7ed0a38988697f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Apr 2016 10:47:59 -0700 Subject: [PATCH 4195/5359] Expand upon `wp db *` docs; explicitly mark methods as public --- php/commands/db.php | 68 +++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index f8a7a281a..1d1900b44 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -8,9 +8,13 @@ class DB_Command extends WP_CLI_Command { /** - * Create the database, as specified in wp-config.php + * Create the database in MySQL. + * + * Runs `CREATE_DATABASE` MySQL statement using `DB_HOST`, `DB_NAME`, + * `DB_USER` and `DB_PASSWORD` database credentials specified in + * wp-config.php. */ - function create( $_, $assoc_args ) { + public function create( $_, $assoc_args ) { self::run_query( self::get_create_query() ); @@ -18,14 +22,18 @@ function create( $_, $assoc_args ) { } /** - * Delete the database. + * Delete the database in MySQL. + * + * Runs `DROP_DATABASE` MySQL statement using `DB_HOST`, `DB_NAME`, + * `DB_USER` and `DB_PASSWORD` database credentials specified in + * wp-config.php. * * ## OPTIONS * * [--yes] * : Answer yes to the confirmation message. */ - function drop( $_, $assoc_args ) { + public function drop( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); self::run_query( sprintf( 'DROP DATABASE `%s`', DB_NAME ) ); @@ -34,14 +42,18 @@ function drop( $_, $assoc_args ) { } /** - * Remove all tables from the database. + * Remove all tables from the database in MySQL. + * + * Runs `DROP_DATABASE` and `CREATE_DATABASE` MySQL statements using + * `DB_HOST`, `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials + * specified in wp-config.php. * * ## OPTIONS * * [--yes] * : Answer yes to the confirmation message. */ - function reset( $_, $assoc_args ) { + public function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); self::run_query( sprintf( 'DROP DATABASE IF EXISTS `%s`', DB_NAME ) ); @@ -51,9 +63,16 @@ function reset( $_, $assoc_args ) { } /** - * Optimize the database. + * Optimize the database in MySQL. + * + * Runs `mysqlcheck` utility with `--optimize=true` using `DB_HOST`, + * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials + * specified in wp-config.php. + * + * [See docs](http://dev.mysql.com/doc/refman/5.7/en/optimize-table.html) + * for more details on the `OPTIMIZE_TABLE` statement. */ - function optimize() { + public function optimize() { self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( 'optimize' => true, ) ); @@ -62,9 +81,16 @@ function optimize() { } /** - * Repair the database. + * Repair the database in MySQL. + * + * Runs `mysqlcheck` utility with `--repair=true` using `DB_HOST`, + * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials + * specified in wp-config.php. + * + * [See docs](http://dev.mysql.com/doc/refman/5.7/en/repair-table.html) for + * more details on the `REPAIR_TABLE` statement. */ - function repair() { + public function repair() { self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( 'repair' => true, ) ); @@ -73,18 +99,21 @@ function repair() { } /** - * Open a mysql console using the WordPress credentials. + * Open a MySQL console using credentials from wp-config.php * * @alias connect */ - function cli() { + public function cli() { self::run( 'mysql --no-defaults --no-auto-rehash', array( 'database' => DB_NAME ) ); } /** - * Execute a query against the database. + * Execute a MySQL query against the database. + * + * Executes an arbitrary MySQL query using `DB_HOST`, `DB_NAME`, `DB_USER` + * and `DB_PASSWORD` database credentials specified in wp-config.php. * * ## OPTIONS * @@ -99,7 +128,7 @@ function cli() { * # check all tables in the database * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" */ - function query( $args ) { + public function query( $args ) { $assoc_args = array( 'database' => DB_NAME ); @@ -113,7 +142,10 @@ function query( $args ) { } /** - * Exports the database to a file or to STDOUT. + * Exports the MySQL database to a file or to STDOUT. + * + * Runs `mysqldump` utility using `DB_HOST`, `DB_NAME`, `DB_USER` and + * `DB_PASSWORD` database credentials specified in wp-config.php. * * ## OPTIONS * @@ -170,14 +202,14 @@ function export( $args, $assoc_args ) { } /** - * Import database from a file or from STDIN. + * Import a MySQL database from a file or from STDIN. * * ## OPTIONS * * [<file>] * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. */ - function import( $args, $assoc_args ) { + public function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); if ( '-' === $result_file ) { @@ -206,7 +238,7 @@ function import( $args, $assoc_args ) { } /** - * List the database tables. + * List the MySQL database tables. * * Defaults to all tables registered to $wpdb. * From 3d529044ca0ce61cea8b859644ccfd10a60ff169 Mon Sep 17 00:00:00 2001 From: "pete@petenelson.com" <petenelson@fortress.local> Date: Fri, 1 Apr 2016 14:51:17 -0500 Subject: [PATCH 4196/5359] adds the 'term recount' CLI command to update the term count for taxonomies --- php/commands/term.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index 84ac9d61d..412c066f4 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -417,6 +417,36 @@ public function url( $args ) { } } + /** + * Recount the term_taxonomy count for one or more taxonomies. + * + * <taxonomy>... + * : One or more taxonomies to update + * + * ## EXAMPLES + * + * wp term recount category post_tag + * + * wp taxonomy list --field=name | xargs wp term recount + */ + public function recount( $args ) { + foreach( $args as $taxonomy ) { + + if ( ! taxonomy_exists( $taxonomy ) ) { + WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); + } else { + + $terms = get_terms( $taxonomy, array( 'hide_empty' => false ) ); + $term_taxonomy_ids = wp_list_pluck( $terms, 'term_taxonomy_id' ); + + wp_update_term_count( $term_taxonomy_ids, $taxonomy ); + + WP_CLI::success( sprintf( "Recounted %s.", $taxonomy ) ); + } + + } + } + private function maybe_make_child() { // 50% chance of making child term return ( mt_rand(1, 2) == 1 ); From 0e6e839836c46c7f13b01cfe4025d311ca784cf4 Mon Sep 17 00:00:00 2001 From: "pete@petenelson.com" <petenelson@fortress.local> Date: Fri, 1 Apr 2016 14:54:21 -0500 Subject: [PATCH 4197/5359] updated success and warning messages --- php/commands/term.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 412c066f4..4eca50e85 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -433,7 +433,7 @@ public function recount( $args ) { foreach( $args as $taxonomy ) { if ( ! taxonomy_exists( $taxonomy ) ) { - WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); + WP_CLI::warning( sprintf( "Taxonomy %s doesn't exist.", $taxonomy ) ); } else { $terms = get_terms( $taxonomy, array( 'hide_empty' => false ) ); @@ -441,7 +441,7 @@ public function recount( $args ) { wp_update_term_count( $term_taxonomy_ids, $taxonomy ); - WP_CLI::success( sprintf( "Recounted %s.", $taxonomy ) ); + WP_CLI::success( sprintf( "Updated %s term count", $taxonomy ) ); } } From 89e8ca1262ac4cc275d763795599e13e58e21c34 Mon Sep 17 00:00:00 2001 From: "pete@petenelson.com" <petenelson@fortress.local> Date: Fri, 1 Apr 2016 15:27:32 -0500 Subject: [PATCH 4198/5359] changed taxonomy warning to not be a contraction --- php/commands/term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index 4eca50e85..2d8c8548d 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -433,7 +433,7 @@ public function recount( $args ) { foreach( $args as $taxonomy ) { if ( ! taxonomy_exists( $taxonomy ) ) { - WP_CLI::warning( sprintf( "Taxonomy %s doesn't exist.", $taxonomy ) ); + WP_CLI::warning( sprintf( "Taxonomy %s does not exist.", $taxonomy ) ); } else { $terms = get_terms( $taxonomy, array( 'hide_empty' => false ) ); From 6ec21273a7b578127a0834f934f198cbf0fb881e Mon Sep 17 00:00:00 2001 From: "pete@petenelson.com" <petenelson@fortress.local> Date: Fri, 1 Apr 2016 15:28:03 -0500 Subject: [PATCH 4199/5359] added feature test for term recount with an invalid taxonomy --- features/term-recount.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 features/term-recount.feature diff --git a/features/term-recount.feature b/features/term-recount.feature new file mode 100644 index 000000000..de584effd --- /dev/null +++ b/features/term-recount.feature @@ -0,0 +1,13 @@ +Feature: Manage WordPress term recounts + + Background: + Given a WP install + + + Scenario: Term recount with an invalid taxonomy + When I try `wp term recount some-fake-taxonomy` + Then STDERR should be: + """ + Warning: Taxonomy some-fake-taxonomy does not exist. + """ + \ No newline at end of file From ff752afefe1d2738bad0af8a30e4720f2a798f4f Mon Sep 17 00:00:00 2001 From: "pete@petenelson.com" <petenelson@fortress.local> Date: Fri, 1 Apr 2016 15:30:27 -0500 Subject: [PATCH 4200/5359] added feature test for term recount with valid taxonomies --- features/term-recount.feature | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/features/term-recount.feature b/features/term-recount.feature index de584effd..bbb79458b 100644 --- a/features/term-recount.feature +++ b/features/term-recount.feature @@ -10,4 +10,18 @@ Feature: Manage WordPress term recounts """ Warning: Taxonomy some-fake-taxonomy does not exist. """ - \ No newline at end of file + + Scenario: Term recount with a valid taxonomy + When I try `wp term recount category` + Then STDOUT should be: + """ + Success: Updated category term count + """ + + Scenario: Term recount with a multiple taxonomies + When I try `wp term recount category post_tag` + Then STDOUT should be: + """ + Success: Updated category term count + Success: Updated post_tag term count + """ From fa3947c70c9946717bc81d29ed26ceb6add39a30 Mon Sep 17 00:00:00 2001 From: Pete Nelson <pete@petenelson.com> Date: Mon, 4 Apr 2016 08:21:35 -0500 Subject: [PATCH 4201/5359] added missing OPTIONS in term recount docblock --- php/commands/term.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index 2d8c8548d..82e95ef46 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -420,6 +420,8 @@ public function url( $args ) { /** * Recount the term_taxonomy count for one or more taxonomies. * + * ## OPTIONS + * * <taxonomy>... * : One or more taxonomies to update * From 9c236bdaf9a29fd99e0cfab83d6d58a9587125c4 Mon Sep 17 00:00:00 2001 From: Pete Nelson <pete@petenelson.com> Date: Mon, 4 Apr 2016 08:48:18 -0500 Subject: [PATCH 4202/5359] added a more detailed description of the term recount command --- php/commands/term.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index 82e95ef46..6437c0598 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -418,7 +418,16 @@ public function url( $args ) { } /** - * Recount the term_taxonomy count for one or more taxonomies. + * Updates the amount of terms in one or more taxonomies + * + * ## DESCRIPTION + * + * In instances where manual updates are made to the terms assigned to + * posts in the database, the number of posts associated with a term + * can become out-of-sync with the actual number of posts. + * + * This command runs wp_update_term_count() on the taxonomy's terms + * to bring the count back to the correct value. * * ## OPTIONS * From 54d8e0ec46c44452814217bda4084fc41cd706f5 Mon Sep 17 00:00:00 2001 From: Pete Nelson <pete@petenelson.com> Date: Mon, 4 Apr 2016 08:50:37 -0500 Subject: [PATCH 4203/5359] added missing OPTIONS to comment recount docblock --- php/commands/comment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index 3eb74fa30..de0eb534b 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -445,6 +445,8 @@ public function count( $args, $assoc_args ) { /** * Recount the comment_count value for one or more posts. * + * ## OPTIONS + * * <id>... * : IDs for one or more posts to update. */ From e19af4a46151382e5e5ef9ec7f33bf18d7ea703c Mon Sep 17 00:00:00 2001 From: Pete Nelson <pete@petenelson.com> Date: Mon, 4 Apr 2016 13:27:25 -0500 Subject: [PATCH 4204/5359] update Feature description for term recount test --- features/term-recount.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/term-recount.feature b/features/term-recount.feature index bbb79458b..b79b957ff 100644 --- a/features/term-recount.feature +++ b/features/term-recount.feature @@ -1,4 +1,4 @@ -Feature: Manage WordPress term recounts +Feature: Recount terms on a taxonomy Background: Given a WP install From a533f8b0ec797df5ebb202cde42a9a7259e112ea Mon Sep 17 00:00:00 2001 From: Pete Nelson <pete@petenelson.com> Date: Mon, 4 Apr 2016 18:16:45 -0500 Subject: [PATCH 4205/5359] added term recount test that forces an invalid term count and fixes it via the WP-CLI command --- features/term-recount.feature | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/features/term-recount.feature b/features/term-recount.feature index b79b957ff..03dad922b 100644 --- a/features/term-recount.feature +++ b/features/term-recount.feature @@ -25,3 +25,30 @@ Feature: Recount terms on a taxonomy Success: Updated category term count Success: Updated post_tag term count """ + + Scenario: Fixes an invalid term count for a taxonomy + When I run `wp term create category "Term Recount Category" --porcelain` + Then STDOUT should be a number + Then save STDOUT as {TERM_ID} + + When I run `wp post create --post_title='Term Recount Test' --post_status=publish --post_category={TERM_ID} --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp term get category {TERM_ID} --field=count` + Then STDOUT should be: + """ + 1 + """ + When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->term_taxonomy, array( "count" => 3 ), array( "term_id" => {TERM_ID} ) );'` + And I run `wp term get category {TERM_ID} --field=count` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp term recount category` + And I run `wp term get category {TERM_ID} --field=count` + """ + 1 + """ From 7423615d9c533107b0e69d67453a7f40ac626a70 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 05:10:16 -0700 Subject: [PATCH 4206/5359] Clean up docs for `wp term recount` --- php/commands/term.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 6437c0598..aeee574f0 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -418,9 +418,7 @@ public function url( $args ) { } /** - * Updates the amount of terms in one or more taxonomies - * - * ## DESCRIPTION + * Recalculate number of posts assigned to each term. * * In instances where manual updates are made to the terms assigned to * posts in the database, the number of posts associated with a term @@ -432,7 +430,7 @@ public function url( $args ) { * ## OPTIONS * * <taxonomy>... - * : One or more taxonomies to update + * : One or more taxonomies to recalculate. * * ## EXAMPLES * From 9b0f8ed5fec2bfbd42ae1560b0625e996a89f9f9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 05:29:05 -0700 Subject: [PATCH 4207/5359] Introduce `CompositeCommand->remove_subcommand()` This permits a subcommand to be de-registered from its parent. Also modifies the bootstrap process to always register commands, instead of lazyloading them based on command name. Packages and required commands are always loaded, so we should follow similar behavior with core commands. --- features/command.feature | 21 +++++++++++++++++++++ php/WP_CLI/Dispatcher/CompositeCommand.php | 13 +++++++++++++ php/WP_CLI/Dispatcher/RootCommand.php | 2 -- php/WP_CLI/Runner.php | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/features/command.feature b/features/command.feature index 59015ad57..781ebf6fb 100644 --- a/features/command.feature +++ b/features/command.feature @@ -490,3 +490,24 @@ Feature: WP-CLI Commands shop: cha cha cha burrito: """ + + Scenario: Removing a subcommand should remove it from the index + Given an empty directory + And a remove-comment.php file: + """ + <?php + $command = WP_CLI::get_root_command(); + $command->remove_subcommand( 'comment' ); + """ + + When I run `wp` + Then STDOUT should contain: + """ + Manage comments. + """ + + When I run `wp --require=remove-comment.php` + Then STDOUT should not contain: + """ + Manage comments. + """ diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php index a4712a592..53862245b 100644 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ b/php/WP_CLI/Dispatcher/CompositeCommand.php @@ -58,6 +58,19 @@ public function add_subcommand( $name, $command ) { $this->subcommands[ $name ] = $command; } + /** + * Remove a named subcommand from this composite command's set of contained + * subcommands + * + * @param string $name Represents how subcommand should be invoked + */ + public function remove_subcommand( $name ) { + if ( isset( $this->subcommands[ $name ] ) ) { + unset( $this->subcommands[ $name ] ); + } + } + + /** * Composite commands always contain subcommands. * diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php index fb730da07..0b720aea0 100644 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ b/php/WP_CLI/Dispatcher/RootCommand.php @@ -53,8 +53,6 @@ public function find_subcommand( &$args ) { * @return array */ public function get_subcommands() { - Utils\load_all_commands(); - return parent::get_subcommands(); } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 43bde527a..ee11655a9 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -626,7 +626,7 @@ public function start() { // Load bundled commands early, so that they're forced to use the same // APIs as non-bundled commands. - Utils\load_command( $this->arguments[0] ); + Utils\load_all_commands(); $skip_packages = \WP_CLI::get_runner()->config['skip-packages']; if ( true === $skip_packages ) { From 4c4efa938835d71527ebbfe7e8d77edd8a877a05 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 06:07:29 -0700 Subject: [PATCH 4208/5359] Mark `WP_CLI::colorize()` as a public API --- php/class-wp-cli.php | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 17e66724b..4e70d1edf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -134,6 +134,59 @@ public static function get_http_cache_manager() { return $http_cacher; } + /** + * Colorize a string for output. + * + * Yes, you too can change the color of command line text. For instance, + * here's how `WP_CLI::success()` colorizes "Success: " + * + * ``` + * WP_CLI::colorize( "%GSuccess:%n " ) + * ``` + * + * Uses `\cli\Colors::colorize()` to transform color tokens to display + * settings. Choose from the following tokens (and note 'reset'): + * + * * %y => ['color' => 'yellow'], + * * %g => ['color' => 'green'], + * * %b => ['color' => 'blue'], + * * %r => ['color' => 'red'], + * * %p => ['color' => 'magenta'], + * * %m => ['color' => 'magenta'], + * * %c => ['color' => 'cyan'], + * * %w => ['color' => 'grey'], + * * %k => ['color' => 'black'], + * * %n => ['color' => 'reset'], + * * %Y => ['color' => 'yellow', 'style' => 'bright'], + * * %G => ['color' => 'green', 'style' => 'bright'], + * * %B => ['color' => 'blue', 'style' => 'bright'], + * * %R => ['color' => 'red', 'style' => 'bright'], + * * %P => ['color' => 'magenta', 'style' => 'bright'], + * * %M => ['color' => 'magenta', 'style' => 'bright'], + * * %C => ['color' => 'cyan', 'style' => 'bright'], + * * %W => ['color' => 'grey', 'style' => 'bright'], + * * %K => ['color' => 'black', 'style' => 'bright'], + * * %N => ['color' => 'reset', 'style' => 'bright'], + * * %3 => ['background' => 'yellow'], + * * %2 => ['background' => 'green'], + * * %4 => ['background' => 'blue'], + * * %1 => ['background' => 'red'], + * * %5 => ['background' => 'magenta'], + * * %6 => ['background' => 'cyan'], + * * %7 => ['background' => 'grey'], + * * %0 => ['background' => 'black'], + * * %F => ['style' => 'blink'], + * * %U => ['style' => 'underline'], + * * %8 => ['style' => 'inverse'], + * * %9 => ['style' => 'bright'], + * * %_ => ['style' => 'bright') + * + * @access public + * @category Output + * + * @param string $string String to colorize for output, with color tokens. + * @return string Colorized string. + */ public static function colorize( $string ) { return \cli\Colors::colorize( $string, self::get_runner()->in_color() ); } From b766cb820d152d57b54d3f0bac774c951535734f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 13:45:19 -0700 Subject: [PATCH 4209/5359] Expected before actual --- tests/test-doc-parser.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index 41b43138d..90cd205c2 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -154,10 +154,10 @@ public function test_desc_doesnt_parse_far_params_yaml() { --- EOB; $doc = new DocParser( $longdesc ); - $this->assertEquals( $doc->get_param_args( 'format' ), array( + $this->assertEquals( array( 'default' => 'table', 'options' => array( 'table', 'json', 'csv', 'yaml' ), - ) ); + ), $doc->get_param_args( 'format' ) ); $this->assertNull( $doc->get_arg_args( 'hook' ) ); } @@ -180,10 +180,10 @@ public function test_desc_doesnt_parse_far_args_yaml() { --- EOB; $doc = new DocParser( $longdesc ); - $this->assertEquals( $doc->get_arg_args( 'format' ), array( + $this->assertEquals( array( 'default' => 'table', 'options' => array( 'table', 'json', 'csv', 'yaml' ), - ) ); + ), $doc->get_arg_args( 'format' ) ); $this->assertNull( $doc->get_arg_args( 'hook' ) ); } From 649b23fb596fe3746fb45bebfe8f6c664ca608ac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 15:08:52 -0700 Subject: [PATCH 4210/5359] Don't use regex to find the YAML doc --- php/WP_CLI/DocParser.php | 43 ++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index 9249003f9..b9ab93d19 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -120,10 +120,7 @@ public function get_arg_desc( $name ) { * @return mixed|null */ public function get_arg_args( $name ) { - if ( preg_match( "/\[?<{$name}>.+(\n: (.+?)(\n|$))?\n---\n(.+)\n---/sU", $this->docComment, $matches ) ) { - return Spyc::YAMLLoadString( $matches[4] ); - } - return null; + return $this->get_arg_or_param_args( "/\[?<{$name}>.*/" ); } /** @@ -148,11 +145,45 @@ public function get_param_desc( $key ) { * @return mixed|null */ public function get_param_args( $key ) { + return $this->get_arg_or_param_args( "/\[?--{$key}=.*/" ); + } - if ( preg_match( "/\[?--{$key}=.+(\n: (.+?)(\n|$))?\n---\n(.+)\n---/sU", $this->docComment, $matches ) ) { - return Spyc::YAMLLoadString( $matches[4] ); + /** + * Get the args for an arg or param + * + * @param string $regex Pattern to match against + * @return array|null Interpreted YAML document, or null. + */ + private function get_arg_or_param_args( $regex ) { + $bits = explode( PHP_EOL, $this->docComment ); + $within_arg = $within_doc = false; + $document = array(); + foreach( $bits as $bit ) { + if ( preg_match( $regex, $bit ) ) { + $within_arg = true; + } + + if ( $within_arg && $within_doc && '---' === $bit ) { + $within_doc = false; + } + + if ( $within_arg && ! $within_doc && '---' === $bit ) { + $within_doc = true; + } + + if ( $within_doc ) { + $document[] = $bit; + } + + if ( $within_arg && '' === $bit ) { + $within_arg = false; + break; + } } + if ( $document ) { + return Spyc::YAMLLoadString( implode( PHP_EOL, $document ) ); + } return null; } From 4648af607bdda3327220c98c055c4969b789fedd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Apr 2016 15:19:43 -0700 Subject: [PATCH 4211/5359] Ensure vendor libraries are available When Behat has been globally installed, our project autoload isn't always called. --- features/bootstrap/FeatureContext.php | 1 + 1 file changed, 1 insertion(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b6897e4fb..85748947b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -30,6 +30,7 @@ } else { require_once __DIR__ . '/../../php/utils.php'; require_once __DIR__ . '/../../php/WP_CLI/Process.php'; + require_once __DIR__ . '/../../vendor/autoload.php'; } /** From e2a977266479ecaf407026ef9bf5ee8291a04c13 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 10:47:48 +0100 Subject: [PATCH 4212/5359] Warn with verify-checksums when extra files exist in wp-admin or wp-includes --- php/commands/core.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 6f589ff1d..778bf8c6c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -861,6 +861,16 @@ public function verify_checksums( $args, $assoc_args ) { } } + $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'remove_wp_content_files_filter' ) ); + $core_files = $this->get_wp_core_files(); + $additional_files = array_diff( $core_files, $core_checksums_files ); + + if ( ! empty( $additional_files ) ) { + foreach ( $additional_files as $additional_file ) { + WP_CLI::warning( "File should not exist: {$additional_file}" ); + } + } + if ( ! $has_errors ) { WP_CLI::success( "WordPress install verifies against checksums." ); } else { @@ -868,6 +878,26 @@ public function verify_checksums( $args, $assoc_args ) { } } + private function get_wp_core_files() { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( ABSPATH, RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::CHILD_FIRST + ); + + $core_files = array(); + foreach ( $files as $file_info ) { + if ( $file_info->isFile() && 'wp-config.php' !== basename( $file_info->getPathname() ) && false === strpos( $file_info->getPathname(), 'wp-content/' ) ) { + $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); + } + } + + return $core_files; + } + + private function remove_wp_content_files_filter( $file ) { + return strpos( $file, 'wp-content/' ) === false; + } + /** * Update WordPress. * From cf13f4f91370b65e7f3a1582eba87c7566919124 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 10:48:10 +0100 Subject: [PATCH 4213/5359] Update tests --- features/core-verify-checksums.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 055639275..f71a52ebb 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -19,6 +19,7 @@ Feature: Validate checksums for WordPress install Then STDERR should be: """ Warning: File doesn't verify against checksum: readme.html + Warning: File should not exist: readme.html.bak Error: WordPress install doesn't verify against checksums. """ @@ -29,6 +30,7 @@ Feature: Validate checksums for WordPress install Then STDERR should be: """ Warning: File doesn't exist: readme.html + Warning: File should not exist: readme.html.bak Error: WordPress install doesn't verify against checksums. """ From 46b66508959603eb5c8703cf569c2b67280008a0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 8 Apr 2016 04:49:19 -0700 Subject: [PATCH 4214/5359] Update versions specified in `packages.json` --- templates/plugin-packages.mustache | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache index 2554b9b2c..fe7f05745 100644 --- a/templates/plugin-packages.mustache +++ b/templates/plugin-packages.mustache @@ -5,8 +5,8 @@ "main": "Gruntfile.js", "author": "{{plugin_author}}", "devDependencies": { - "grunt": "^0.4.5", - "grunt-wp-i18n": "^0.5.0", - "grunt-wp-readme-to-markdown": "~0.9.0" + "grunt": "~0.4.5", + "grunt-wp-i18n": "~0.5.0", + "grunt-wp-readme-to-markdown": "~1.0.0" } } From 7636f3c0c7b48a31c9cd6619743a0dee912f6554 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 13:51:07 +0100 Subject: [PATCH 4215/5359] Only check in wp-admin and wp-includes --- php/commands/core.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index ebabda3b4..e60505e79 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -848,7 +848,7 @@ public function verify_checksums( $args, $assoc_args ) { } } - $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'remove_wp_content_files_filter' ) ); + $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'only_core_files_filter' ) ); $core_files = $this->get_wp_core_files(); $additional_files = array_diff( $core_files, $core_checksums_files ); @@ -873,7 +873,7 @@ private function get_wp_core_files() { $core_files = array(); foreach ( $files as $file_info ) { - if ( $file_info->isFile() && 'wp-config.php' !== basename( $file_info->getPathname() ) && false === strpos( $file_info->getPathname(), 'wp-content/' ) ) { + if ( $file_info->isFile() && ( false !== strpos( $file_info->getPathname(), 'wp-admin/' ) || false !== strpos( $file_info->getPathname(), 'wp-includes/' ) ) ) { $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); } } @@ -881,8 +881,8 @@ private function get_wp_core_files() { return $core_files; } - private function remove_wp_content_files_filter( $file ) { - return strpos( $file, 'wp-content/' ) === false; + private function only_core_files_filter( $file ) { + return ( false !== strpos( $file, 'wp-admin/' ) || false !== strpos( $file, 'wp-includes/' ) ); } /** From 4dea7e0070d89dfc93d77fed2740b98a40351c58 Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 13:51:14 +0100 Subject: [PATCH 4216/5359] Update tests --- features/core-verify-checksums.feature | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index c2d98418c..7c7d5858f 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -19,7 +19,6 @@ Feature: Validate checksums for WordPress install Then STDERR should be: """ Warning: File doesn't verify against checksum: readme.html - Warning: File should not exist: readme.html.bak Error: WordPress install doesn't verify against checksums. """ @@ -30,7 +29,6 @@ Feature: Validate checksums for WordPress install Then STDERR should be: """ Warning: File doesn't exist: readme.html - Warning: File should not exist: readme.html.bak Error: WordPress install doesn't verify against checksums. """ @@ -65,3 +63,19 @@ Feature: Validate checksums for WordPress install """ Success: WordPress install verifies against checksums. """ + + Scenario: Verify core checksums with extra files + Given a WP install + + When I run `wp core update` + Then STDOUT should not be empty + + When I run `touch wp-includes/extra-file.txt` + Then the wp-includes/extra-file.txt file should exist + + When I run `wp core verify-checksums` + Then STDOUT should be: + """ + Warning: File should not exist: wp-includes/extra-file.txt + Success: WordPress install verifies against checksums. + """ From 7fa9e762bb02cd67f87de09dbee9683a449c3034 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 8 Apr 2016 06:31:44 -0700 Subject: [PATCH 4217/5359] Update Composer dependencies to their latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.3) - Installing symfony/yaml (v2.8.4) Downloading: 100% - Removing symfony/filesystem (v2.8.3) - Installing symfony/filesystem (v2.8.4) Downloading: 100% - Removing symfony/config (v2.8.3) - Installing symfony/config (v2.8.4) Downloading: 100% - Removing symfony/dependency-injection (v2.8.3) - Installing symfony/dependency-injection (v2.8.4) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.3) - Installing symfony/event-dispatcher (v2.8.4) Downloading: 100% - Removing symfony/translation (v2.8.3) - Installing symfony/translation (v2.8.4) Downloading: 100% - Removing symfony/process (v2.8.3) - Installing symfony/process (v2.8.4) Downloading: 100% - Removing symfony/finder (v2.8.3) - Installing symfony/finder (v2.8.4) Downloading: 100% - Removing symfony/console (v2.8.3) - Installing symfony/console (v2.8.4) Downloading: 100% - Removing composer/semver (1.3.0) - Installing composer/semver (1.4.0) Downloading: 100% - Removing composer/spdx-licenses (1.1.2) - Installing composer/spdx-licenses (1.1.3) Downloading: 100% - Removing composer/composer (1.0.0-beta1) - Installing composer/composer (1.0.0) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 126 +++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/composer.lock b/composer.lock index 3d9ba656d..2616ef216 100644 --- a/composer.lock +++ b/composer.lock @@ -9,16 +9,16 @@ "packages": [ { "name": "composer/composer", - "version": "1.0.0-beta1", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c" + "reference": "32df3aa8cdbdaa16df9491b5e672e81c87f94c78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/5cb2b522637a941d608c58bd522f3b2a7bda4a1c", - "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c", + "url": "https://api.github.com/repos/composer/composer/zipball/32df3aa8cdbdaa16df9491b5e672e81c87f94c78", + "reference": "32df3aa8cdbdaa16df9491b5e672e81c87f94c78", "shasum": "" }, "require": { @@ -80,20 +80,20 @@ "dependency", "package" ], - "time": "2016-03-03 15:15:10" + "time": "2016-04-05 12:27:26" }, { "name": "composer/semver", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747" + "reference": "84c47f3d8901440403217afc120683c7385aecb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", - "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", + "url": "https://api.github.com/repos/composer/semver/zipball/84c47f3d8901440403217afc120683c7385aecb8", + "reference": "84c47f3d8901440403217afc120683c7385aecb8", "shasum": "" }, "require": { @@ -142,28 +142,28 @@ "validation", "versioning" ], - "time": "2016-02-25 22:23:39" + "time": "2016-03-30 13:16:03" }, { "name": "composer/spdx-licenses", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "9e1c3926bb0842812967213d7c92827bc5883671" + "reference": "547659c3cacd3ccfe1b4714c2ff88cafc6b6793b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/9e1c3926bb0842812967213d7c92827bc5883671", - "reference": "9e1c3926bb0842812967213d7c92827bc5883671", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/547659c3cacd3ccfe1b4714c2ff88cafc6b6793b", + "reference": "547659c3cacd3ccfe1b4714c2ff88cafc6b6793b", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "~2.3" + "phpunit/phpunit": "^4.5 || ^5.0.5", + "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" }, "type": "library", "extra": { @@ -203,7 +203,7 @@ "spdx", "validator" ], - "time": "2015-10-05 11:27:42" + "time": "2016-03-25 10:57:10" }, { "name": "justinrainbow/json-schema", @@ -639,16 +639,16 @@ }, { "name": "symfony/config", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19" + "reference": "5273f4724dc5288fe7a33cb08077ab9852621f2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", - "reference": "0f8f94e6a32b5c480024eed5fa5cbd2790d0ad19", + "url": "https://api.github.com/repos/symfony/config/zipball/5273f4724dc5288fe7a33cb08077ab9852621f2c", + "reference": "5273f4724dc5288fe7a33cb08077ab9852621f2c", "shasum": "" }, "require": { @@ -688,20 +688,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-02-22 16:12:45" + "time": "2016-03-04 07:54:35" }, { "name": "symfony/console", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "56cc5caf051189720b8de974e4746090aaa10d44" + "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44", - "reference": "56cc5caf051189720b8de974e4746090aaa10d44", + "url": "https://api.github.com/repos/symfony/console/zipball/9a5aef5fc0d4eff86853d44202b02be8d5a20154", + "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154", "shasum": "" }, "require": { @@ -748,20 +748,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:20:50" + "time": "2016-03-17 09:19:04" }, { "name": "symfony/dependency-injection", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "62251761a7615435b22ccf562384c588b431be44" + "reference": "f7b4a498e679fa440b16facb934680a1527ed48c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/62251761a7615435b22ccf562384c588b431be44", - "reference": "62251761a7615435b22ccf562384c588b431be44", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f7b4a498e679fa440b16facb934680a1527ed48c", + "reference": "f7b4a498e679fa440b16facb934680a1527ed48c", "shasum": "" }, "require": { @@ -810,20 +810,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:34:46" + "time": "2016-03-21 07:27:21" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3" + "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/78c468665c9568c3faaa9c416a7134308f2d85c3", - "reference": "78c468665c9568c3faaa9c416a7134308f2d85c3", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/47d2d8cade9b1c3987573d2943bb9352536cdb87", + "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87", "shasum": "" }, "require": { @@ -870,20 +870,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:19" + "time": "2016-03-07 14:04:32" }, { "name": "symfony/filesystem", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "65cb36b6539b1d446527d60457248f30d045464d" + "reference": "f08ffdf229252cd2745558cb2112df43903bcae4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/65cb36b6539b1d446527d60457248f30d045464d", - "reference": "65cb36b6539b1d446527d60457248f30d045464d", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/f08ffdf229252cd2745558cb2112df43903bcae4", + "reference": "f08ffdf229252cd2745558cb2112df43903bcae4", "shasum": "" }, "require": { @@ -919,20 +919,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-02-22 15:02:30" + "time": "2016-03-27 10:20:16" }, { "name": "symfony/finder", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7" + "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/877bb4b16ea573cc8c024e9590888fcf7eb7e0f7", - "reference": "877bb4b16ea573cc8c024e9590888fcf7eb7e0f7", + "url": "https://api.github.com/repos/symfony/finder/zipball/ca24cf2cd4e3826f571e0067e535758e73807aa1", + "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1", "shasum": "" }, "require": { @@ -968,7 +968,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-02-22 16:12:45" + "time": "2016-03-10 10:53:53" }, { "name": "symfony/polyfill-mbstring", @@ -1031,16 +1031,16 @@ }, { "name": "symfony/process", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe" + "reference": "fb467471952ef5cf8497c029980e556b47545333" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe", - "reference": "7dedd5b60550f33dca16dd7e94ef8aca8b67bbfe", + "url": "https://api.github.com/repos/symfony/process/zipball/fb467471952ef5cf8497c029980e556b47545333", + "reference": "fb467471952ef5cf8497c029980e556b47545333", "shasum": "" }, "require": { @@ -1076,20 +1076,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-02-02 13:33:15" + "time": "2016-03-23 13:11:46" }, { "name": "symfony/translation", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7" + "reference": "d60b8e076d22953aabebeebda53bf334438e7aca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7", - "reference": "b7b4ebadd2b5e614ff7d2d6fc63e0ed0578909c7", + "url": "https://api.github.com/repos/symfony/translation/zipball/d60b8e076d22953aabebeebda53bf334438e7aca", + "reference": "d60b8e076d22953aabebeebda53bf334438e7aca", "shasum": "" }, "require": { @@ -1140,20 +1140,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-02-02 09:49:18" + "time": "2016-03-25 01:40:30" }, { "name": "symfony/yaml", - "version": "v2.8.3", + "version": "v2.8.4", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995" + "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", - "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", + "url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb", + "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb", "shasum": "" }, "require": { @@ -1189,7 +1189,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-02-23 07:41:20" + "time": "2016-03-04 07:54:35" }, { "name": "wp-cli/php-cli-tools", From c94e822a90e59d5a06646183d33b8cbe953a9b3b Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 15:44:37 +0100 Subject: [PATCH 4218/5359] Update test --- features/core-verify-checksums.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 7c7d5858f..1f817755a 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -70,7 +70,10 @@ Feature: Validate checksums for WordPress install When I run `wp core update` Then STDOUT should not be empty - When I run `touch wp-includes/extra-file.txt` + Given a wp-includes/extra-file.txt file: + """ + hello world + """ Then the wp-includes/extra-file.txt file should exist When I run `wp core verify-checksums` From 5bdd9f369127edc5ba36c81fe7092276e11d6d2d Mon Sep 17 00:00:00 2001 From: Gilbert Pellegrom <gilbert@pellegrom.me> Date: Fri, 8 Apr 2016 17:26:34 +0100 Subject: [PATCH 4219/5359] Fix test --- features/core-verify-checksums.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 1f817755a..5f40e66b7 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -77,8 +77,11 @@ Feature: Validate checksums for WordPress install Then the wp-includes/extra-file.txt file should exist When I run `wp core verify-checksums` - Then STDOUT should be: + Then STDERR should be: """ Warning: File should not exist: wp-includes/extra-file.txt + """ + And STDOUT should be: + """ Success: WordPress install verifies against checksums. """ From 2bec119c088616f5b225b162ed92dbce448ed8b1 Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Sun, 10 Apr 2016 15:50:49 -0400 Subject: [PATCH 4220/5359] Update `plugin.mustache` and `plugin-packages.mustache` Currently if you scaffold a child theme and a plugin, the plugin headers are formatted differently than the child theme headers. The plugin also uses a different version number `0.1-alpha`), which is itself different than the version used in the plugin's `package.json` (`0.0.0`). This commit normalizes the header formatting and updates the version numbers. --- templates/plugin-packages.mustache | 2 +- templates/plugin.mustache | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache index fe7f05745..84a60ca66 100644 --- a/templates/plugin-packages.mustache +++ b/templates/plugin-packages.mustache @@ -1,7 +1,7 @@ { "name": "{{plugin_slug}}", - "version": "0.0.0", + "version": "0.1.0", "main": "Gruntfile.js", "author": "{{plugin_author}}", "devDependencies": { diff --git a/templates/plugin.mustache b/templates/plugin.mustache index c96eb303d..fc502b67a 100644 --- a/templates/plugin.mustache +++ b/templates/plugin.mustache @@ -1,12 +1,13 @@ <?php /** - * Plugin Name: {{plugin_name}} - * Version: 0.1-alpha - * Description: {{plugin_description}} - * Author: {{plugin_author}} - * Author URI: {{plugin_author_uri}} - * Plugin URI: {{plugin_uri}} - * Text Domain: {{textdomain}} - * Domain Path: /languages - * @package {{plugin_package}} + * Plugin Name: {{plugin_name}} + * Plugin URI: {{plugin_uri}} + * Description: {{plugin_description}} + * Author: {{plugin_author}} + * Author URI: {{plugin_author_uri}} + * Text Domain: {{textdomain}} + * Domain Path: /languages + * Version: 0.1.0 + * + * @package {{plugin_package}} */ From 6ccf35d3269abcfce7e390c323b511f9540075fe Mon Sep 17 00:00:00 2001 From: Wes Moberly <wesm87@gmail.com> Date: Sun, 10 Apr 2016 18:27:28 -0400 Subject: [PATCH 4221/5359] Update functional tests --- features/plugin.feature | 6 +++--- features/scaffold.feature | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 65da74df6..063155a6c 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -42,7 +42,7 @@ Feature: Manage WordPress plugins Plugin Zombieland details: Name: Zombieland Status: Inactive - Version: 0.1-alpha + Version: 0.1.0 Author: YOUR NAME HERE Description: PLUGIN DESCRIPTION HERE """ @@ -61,8 +61,8 @@ Feature: Manage WordPress plugins When I run `wp plugin list` Then STDOUT should be a table containing rows: - | name | status | update | version | - | Zombieland | active | none | 0.1-alpha | + | name | status | update | version | + | Zombieland | active | none | 0.1.0 | When I try `wp plugin uninstall Zombieland` Then STDERR should contain: diff --git a/features/scaffold.feature b/features/scaffold.feature index e7fd1fd23..54c610039 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -125,11 +125,15 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: """ - * Plugin Name: Hello World + * Plugin Name: Hello World """ And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: """ - * @package Hello_World + * Version: 0.1.0 + """ + And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: + """ + * @package Hello_World """ When I run `cat {PLUGIN_DIR}/hello-world/package.json` @@ -137,6 +141,10 @@ Feature: WordPress code scaffolding """ {"author":"Hello World Author"} """ + And STDOUT should be JSON containing: + """ + {"version":"0.1.0"} + """ Scenario: Scaffold a plugin by prompting Given a WP install From ddcb81606ba86ddce421e5e3e8e27a7fdcd4acbd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Apr 2016 04:54:46 -0700 Subject: [PATCH 4222/5359] Failing test case for #2608 --- features/media-regenerate.feature | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index fb4f99be6..0981e41c8 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -144,3 +144,51 @@ Feature: Regenerate WordPress attachments """ Success: Finished regenerating all images. """ + + Scenario: Regenerate images which are missing globally-defined image sizes + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And I run `wp option update uploads_use_yearmonth_folders 0` + + When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + And the wp-content/uploads/large-image-100x100.jpg file should not exist + + Given a wp-content/mu-plugins/media-settings.php file: + """ + <?php + add_action( 'after_setup_theme', function(){ + add_image_size( 'test1', 100, 100, true ); + }); + """ + + When I run `wp media regenerate --only-missing --yes` + Then STDOUT should contain: + """ + Found 1 image to regenerate. + """ + And STDOUT should contain: + """ + Regenerated thumbnails for "My imported attachment" + """ + And STDOUT should contain: + """ + Success: Finished regenerating the image. + """ + And the wp-content/uploads/large-image-100x100.jpg file should exist + + When I run `wp media regenerate --only-missing --yes` + Then STDOUT should contain: + """ + Found 1 image to regenerate + """ + And STDOUT should contain: + """ + No thumbnail regeneration needed for "My imported attachment" + """ + And STDOUT should contain: + """ + Success: Finished regenerating the image. + """ + And the wp-content/uploads/large-image-100x100.jpg file should exist From d51edfd876bc33f868e05cbcd45ee292327b171d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Apr 2016 04:56:55 -0700 Subject: [PATCH 4223/5359] Consider image sizes missing when `sizes` doesn't have registered sizes Also considers image needing regeneration if `sizes` is empty (which means its missing all sizes). --- php/commands/media.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index fd77715e4..df37e7521 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -315,7 +315,11 @@ private function needs_regeneration( $att_id ) { $original_path = $dir_path . basename( $metadata['file'] ); if ( empty( $metadata['sizes'] ) ) { - return false; + return true; + } + + if ( array_diff( get_intermediate_image_sizes(), array_keys( $metadata['sizes'] ) ) ) { + return true; } foreach( $metadata['sizes'] as $size_info ) { From a129489450122aab942955ce95ec64271e2dc547 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Apr 2016 06:14:30 -0700 Subject: [PATCH 4224/5359] Run `before_invoke` and `after_invoke` callbacks on subcommands This appears to be an oversight from 6ae19150fe3263b5b19e1237c58b92f73d9eab15 that no one has noticed since. Keep calling the parent too, for backwards compat purposes. --- features/command.feature | 25 +++++++++++++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 10 ++++++++-- php/class-wp-cli.php | 7 +++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/features/command.feature b/features/command.feature index 781ebf6fb..dafbf3161 100644 --- a/features/command.feature +++ b/features/command.feature @@ -511,3 +511,28 @@ Feature: WP-CLI Commands """ Manage comments. """ + + Scenario: before_invoke should call subcommands + Given an empty directory + And a call-invoke.php file: + """ + <?php + /** + * @when before_wp_load + */ + WP_CLI::add_command( 'before invoke', function() { + WP_CLI::success( 'Invoked' ); + }, array( 'before_invoke' => function() { + WP_CLI::success( 'before invoke' ); + }, 'after_invoke' => function() { + WP_CLI::success( 'after invoke' ); + })); + """ + + When I run `wp --require=call-invoke.php before invoke` + Then STDOUT should contain: + """ + Success: before invoke + Success: Invoked + Success: after invoke + """ diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6b9eef078..97906b4df 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -2,6 +2,8 @@ namespace WP_CLI\Dispatcher; +use WP_CLI; + /** * A leaf node in the command tree. * @@ -346,11 +348,15 @@ public function invoke( $args, $assoc_args, $extra_args ) { } $path = get_path( $this->get_parent() ); - \WP_CLI::do_hook( 'before_invoke:' . implode( ' ', array_slice( $path, 1 ) ) ); + $parent = implode( ' ', array_slice( $path, 1 ) ); + $cmd = $parent . ' ' . $this->name; + WP_CLI::do_hook( "before_invoke:{$parent}" ); + WP_CLI::do_hook( "before_invoke:{$cmd}" ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); - \WP_CLI::do_hook( 'after_invoke:' . implode( ' ', array_slice( $path, 1 ) ) ); + WP_CLI::do_hook( "after_invoke:{$parent}" ); + WP_CLI::do_hook( "after_invoke:{$cmd}" ); } } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4e70d1edf..0de667fc0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -294,6 +294,7 @@ public static function do_hook( $when ) { * @param array $args { * Optional An associative array with additional registration parameters. * 'before_invoke' => callback to execute before invoking the command, + * 'after_invoke' => callback to execute after invoking the command, * 'shortdesc' => short description (80 char or less) for the command, * 'synopsis' => the synopsis for the command (string or array), * 'when' => execute callback on a named WP-CLI hook (e.g. before_wp_load), @@ -317,8 +318,10 @@ public static function add_command( $name, $callable, $args = array() ) { WP_CLI::error( sprintf( "Callable %s does not exist, and cannot be registered as `wp %s`.", json_encode( $callable ), $name ) ); } - if ( isset( $args['before_invoke'] ) ) { - self::add_hook( "before_invoke:$name", $args['before_invoke'] ); + foreach( array( 'before_invoke', 'after_invoke' ) as $when ) { + if ( isset( $args[ $when ] ) ) { + self::add_hook( "{$when}:{$name}", $args[ $when ] ); + } } $path = preg_split( '/\s+/', $name ); From 0e96864c180a0c3296be257dc126055b60ae565f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Apr 2016 07:16:34 -0700 Subject: [PATCH 4225/5359] Use `--debug=<group>` to limit debug output to a particular group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` salty-wordpress âžœ wordpress-develop.dev wp option get home --debug Debug (bootstrap): Using default global config: /home/vagrant/.wp-cli/config.yml (0.051s) Debug (bootstrap): Using project config: /srv/www/wordpress-develop.dev/wp-cli.yml (0.054s) Debug (bootstrap): Loading packages from: /home/vagrant/.wp-cli/packages/vendor/autoload.php (0.287s) Debug (bootstrap): Required file from config: /srv/www/wp-hook-command/command.php (0.428s) Debug (bootstrap): ABSPATH defined: /srv/www/wordpress-develop.dev/src/ (0.428s) Debug (bootstrap): Begin WordPress load (0.433s) Debug (bootstrap): wp-config.php path: /srv/www/wordpress-develop.dev/wp-config.php (0.436s) Debug (bootstrap): Loaded WordPress (1.307s) Debug: No schema title found for /, skipping REST command registration. (1.487s) Debug: No schema title found for /wp/v2, skipping REST command registration. (1.487s) Debug: No schema title found for /wp/v2/users/me, skipping REST command registration. (1.507s) Debug: No schema title found for /oembed/1.0, skipping REST command registration. (1.51s) Debug: No schema title found for /oembed/1.0/embed, skipping REST command registration. (1.51s) Debug: No schema title found for /wpx/v1, skipping REST command registration. (1.51s) Debug: No schema title found for /wpx/v1/page-templates, skipping REST command registration. (1.51s) Debug (bootstrap): Running command: option get (1.511s) http://wordpress-develop.dev salty-wordpress âžœ wordpress-develop.dev wp option get home --debug=bootstrap Debug: Using default global config: /home/vagrant/.wp-cli/config.yml (0.05s) Debug: Using project config: /srv/www/wordpress-develop.dev/wp-cli.yml (0.053s) Debug: Loading packages from: /home/vagrant/.wp-cli/packages/vendor/autoload.php (0.209s) Debug: Required file from config: /srv/www/wp-hook-command/command.php (0.298s) Debug: ABSPATH defined: /srv/www/wordpress-develop.dev/src/ (0.299s) Debug: Begin WordPress load (0.303s) Debug: wp-config.php path: /srv/www/wordpress-develop.dev/wp-config.php (0.306s) Debug: Loaded WordPress (1.105s) Debug: Running command: option get (1.304s) http://wordpress-develop.dev ``` --- features/config.feature | 52 +++++++++++++++++++++++++++++++++++++ php/WP_CLI/Loggers/Base.php | 18 ++++++++++--- php/WP_CLI/Runner.php | 22 ++++++++-------- php/class-wp-cli.php | 7 ++--- php/config-spec.php | 4 +-- 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/features/config.feature b/features/config.feature index 091c71116..7912d1d53 100644 --- a/features/config.feature +++ b/features/config.feature @@ -228,6 +228,58 @@ Feature: Have a config file Running command: option get """ + When I run `wp option get home --debug=bootstrap` + Then STDERR should contain: + """ + No readable global config found + """ + Then STDERR should contain: + """ + No project config found + """ + And STDERR should contain: + """ + Begin WordPress load + """ + And STDERR should contain: + """ + wp-config.php path: + """ + And STDERR should contain: + """ + Loaded WordPress + """ + And STDERR should contain: + """ + Running command: option get + """ + + When I run `wp option get home --debug=foo` + Then STDERR should not contain: + """ + No readable global config found + """ + Then STDERR should not contain: + """ + No project config found + """ + And STDERR should not contain: + """ + Begin WordPress load + """ + And STDERR should not contain: + """ + wp-config.php path: + """ + And STDERR should not contain: + """ + Loaded WordPress + """ + And STDERR should not contain: + """ + Running command: option get + """ + Scenario: Missing required files should not fatal WP-CLI Given an empty directory And a wp-cli.yml file: diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php index 2f36446ce..11b26e304 100644 --- a/php/WP_CLI/Loggers/Base.php +++ b/php/WP_CLI/Loggers/Base.php @@ -29,12 +29,22 @@ protected function get_runner() { * Write a message to STDERR, prefixed with "Debug: ". * * @param string $message Message to write. + * @param string $group Organize debug message to a specific group. */ - public function debug( $message ) { - if ( $this->get_runner()->config['debug'] ) { - $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); - $this->_line( "$message ({$time}s)", 'Debug', '%B', STDERR ); + public function debug( $message, $group = false ) { + $debug = $this->get_runner()->config['debug']; + if ( ! $debug ) { + return; } + if ( true !== $debug && $group !== $debug ) { + return; + } + $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); + $prefix = 'Debug'; + if ( $group && true === $debug ) { + $prefix = 'Debug (' . $group . ')'; + } + $this->_line( "$message ({$time}s)", $prefix, '%B', STDERR ); } /** diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ee11655a9..b8ec97b77 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -202,7 +202,7 @@ private function find_wp_root() { */ private static function set_wp_root( $path ) { define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); - WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH ); + WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH, 'bootstrap' ); $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); } @@ -321,7 +321,7 @@ public function run_command( $args, $assoc_args = array() ) { $extra_args = array(); } - WP_CLI::debug( 'Running command: ' . $name ); + WP_CLI::debug( 'Running command: ' . $name, 'bootstrap' ); try { $command->invoke( $final_args, $assoc_args, $extra_args ); } catch ( WP_CLI\Iterators\Exception $e ) { @@ -604,8 +604,8 @@ public function start() { $this->init_colorization(); $this->init_logger(); - WP_CLI::debug( $this->_global_config_path_debug ); - WP_CLI::debug( $this->_project_config_path_debug ); + WP_CLI::debug( $this->_global_config_path_debug, 'bootstrap' ); + WP_CLI::debug( $this->_project_config_path_debug, 'bootstrap' ); $this->check_root(); @@ -630,14 +630,14 @@ public function start() { $skip_packages = \WP_CLI::get_runner()->config['skip-packages']; if ( true === $skip_packages ) { - WP_CLI::debug( 'Skipped loading packages.' ); + WP_CLI::debug( 'Skipped loading packages.', 'bootstrap' ); } else { $package_autoload = $this->get_packages_dir_path() . 'vendor/autoload.php'; if ( file_exists( $package_autoload ) ) { - WP_CLI::debug( 'Loading packages from: ' . $package_autoload ); + WP_CLI::debug( 'Loading packages from: ' . $package_autoload, 'bootstrap' ); require_once $package_autoload; } else { - WP_CLI::debug( 'No package autoload found to load.' ); + WP_CLI::debug( 'No package autoload found to load.', 'bootstrap' ); } } @@ -664,7 +664,7 @@ public function start() { WP_CLI::error( sprintf( "Required file '%s' doesn't exist%s.", basename( $path ), $context ) ); } Utils\load_file( $path ); - WP_CLI::debug( 'Required file from config: ' . $path ); + WP_CLI::debug( 'Required file from config: ' . $path, 'bootstrap' ); } } @@ -771,7 +771,7 @@ public function load_wordpress() { $wp_cli_is_loaded = true; - WP_CLI::debug( 'Begin WordPress load' ); + WP_CLI::debug( 'Begin WordPress load', 'bootstrap' ); WP_CLI::do_hook( 'before_wp_load' ); $this->check_wp_version(); @@ -783,7 +783,7 @@ public function load_wordpress() { "Either create one manually or use `wp core config`." ); } - WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path ); + WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path, 'bootstrap' ); WP_CLI::do_hook( 'before_wp_config_load' ); // Load wp-config.php code, in the global scope @@ -818,7 +818,7 @@ public function load_wordpress() { self::set_user( $this->config ); } - WP_CLI::debug( 'Loaded WordPress' ); + WP_CLI::debug( 'Loaded WordPress', 'bootstrap' ); WP_CLI::do_hook( 'after_wp_load' ); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4e70d1edf..72f2433f5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -93,7 +93,7 @@ public static function get_cache() { * Set the context in which WP-CLI should be run */ public static function set_url( $url ) { - WP_CLI::debug( 'Set URL: ' . $url ); + WP_CLI::debug( 'Set URL: ' . $url, 'bootstrap' ); $url_parts = Utils\parse_url( $url ); self::set_url_params( $url_parts ); } @@ -482,10 +482,11 @@ public static function success( $message ) { * @category Output * * @param string $message Message to write to STDERR. + * @param string $group Organize debug message to a specific group. * @return null */ - public static function debug( $message ) { - self::$logger->debug( self::error_to_string( $message ) ); + public static function debug( $message, $group = false ) { + self::$logger->debug( self::error_to_string( $message ), $group ); } /** diff --git a/php/config-spec.php b/php/config-spec.php index 6e55a544c..84221c0f0 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -71,8 +71,8 @@ ), 'debug' => array( - 'runtime' => '', - 'file' => '<bool>', + 'runtime' => '[=<group>]', + 'file' => '<group>', 'default' => false, 'desc' => 'Show all PHP errors; add verbosity to WP-CLI bootstrap.', ), From c658f693e8f9ae110b18045ae3e0a1dbcada4054 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 11 Apr 2016 09:01:08 -0700 Subject: [PATCH 4226/5359] Fix test to expect new string --- features/package.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/package.feature b/features/package.feature index 9d0591f7c..daafbc4e7 100644 --- a/features/package.feature +++ b/features/package.feature @@ -18,7 +18,7 @@ Feature: Manage WP-CLI packages When I try `wp --skip-packages --debug help reset-post-date` Then STDERR should contain: """ - Debug: Skipped loading packages. + Debug (bootstrap): Skipped loading packages. """ And STDERR should contain: """ From 6e9cd2916359faa3a53dce495012c4410810074c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Apr 2016 06:05:51 -0700 Subject: [PATCH 4227/5359] Mention that custom database tables won't be emptied Doing so requires a bit of custom code. --- php/commands/site.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index b86b144b3..5778c16d5 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -122,6 +122,19 @@ private function _insert_default_terms() { /** * Empty a site of its content (posts, comments, and terms). * + * This command doesn't empty custom database tables by default. To do so, + * you'll need to hook into command execution: + * + * ``` + * WP_CLI::add_hook( 'after_invoke:site empty', function(){ + * global $wpdb; + * foreach( array( 'p2p', 'p2pmeta' ) as $table ) { + * $table = $wpdb->$table; + * $wpdb->query( "TRUNCATE $table" ); + * } + * }); + * ``` + * * ## OPTIONS * * [--uploads] From 6c76fde70220181f5c54c45d1067618320c092f4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Apr 2016 13:32:55 -0700 Subject: [PATCH 4228/5359] Lock to a specific version, so it doesn't break on new release --- features/core-download.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-download.feature b/features/core-download.feature index c5f7f85f0..0b5cd4bd3 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -28,7 +28,7 @@ Feature: Download WordPress Scenario: Localized install Given an empty directory And an empty cache - When I run `wp core download --locale=de_DE` + When I run `wp core download --version=4.4.2 --locale=de_DE` And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} Then the wp-settings.php file should exist And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist From 7b5c24e7696a3d1b630bbcd33744ca98e9f8c8ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Apr 2016 13:35:32 -0700 Subject: [PATCH 4229/5359] Update tests for WordPress 4.5 --- features/core-check-update.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 600beba47..c99d9beb2 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -10,7 +10,7 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.2 | major | https://downloads.wordpress.org/release/wordpress-4.4.2.zip | + | 4.5 | major | https://downloads.wordpress.org/release/wordpress-4.5.zip | | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | When I run `wp core check-update --format=count` @@ -22,7 +22,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.2 | major | https://downloads.wordpress.org/release/wordpress-4.4.2.zip | + | 4.5 | major | https://downloads.wordpress.org/release/wordpress-4.5.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: From fdbee85ed8a652bf0ca5fcac6bb14de2f69c5e71 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 04:09:49 -0700 Subject: [PATCH 4230/5359] Use backticks when mentioning hooks This prevents the comment from being rendered as HTML on the website. --- php/class-wp-cli.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 2994124cd..ad871ec16 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -199,12 +199,12 @@ public static function colorize( $string ) { * * WP-CLI hooks include: * - * * 'before_invoke:<command>' - Just before a command is invoked. - * * 'after_invoke:<command>' - Just after a command is involved. - * * 'before_wp_load' - Just before the WP load process begins. - * * 'before_wp_config_load' - After wp-config.php has been located. - * * 'after_wp_config_load' - After wp-config.php has been loaded into scope. - * * 'after_wp_load' - Just after the WP load process has completed. + * * `before_invoke:<command>` - Just before a command is invoked. + * * `after_invoke:<command>` - Just after a command is involved. + * * `before_wp_load` - Just before the WP load process begins. + * * `before_wp_config_load` - After wp-config.php has been located. + * * `after_wp_config_load` - After wp-config.php has been loaded into scope. + * * `after_wp_load` - Just after the WP load process has completed. * * WP-CLI commands can create their own hooks with `WP_CLI::do_hook()`. * From 639e52cfe417aa7f9cb728ee0f8566d8b8a891ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 07:40:19 -0700 Subject: [PATCH 4231/5359] Make `launch_editor_for_input()` usable without WordPress available Internalize the core logic of generating a random temp file. --- php/utils.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index 67c709364..62047f0eb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -338,12 +338,28 @@ function pick_fields( $item, $fields ) { * @return str|bool Edited text, if file is saved from editor * False, if no change to file */ -function launch_editor_for_input( $input, $title = 'WP-CLI' ) { - - $tmpfile = wp_tempnam( $title ); +function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { + + $tmpdir = get_temp_dir(); + + do { + $tmpfile = basename( $filename ); + $tmpfile = preg_replace( '|\.[^.]*$|', '', $tmpfile ); + $tmpfile .= '-' . substr( md5( rand() ), 0, 6 ); + $tmpfile = $tmpdir . $tmpfile . '.tmp'; + $fp = @fopen( $tmpfile, 'x' ); + if ( ! $fp && is_writable( $tmpdir ) && file_exists( $tmpfile ) ) { + $tmpfile = ''; + continue; + } + if ( $fp ) { + fclose( $fp ); + } + } while( ! $tmpfile ); - if ( !$tmpfile ) + if ( ! $tmpfile ) { \WP_CLI::error( 'Error creating temporary file.' ); + } $output = ''; file_put_contents( $tmpfile, $input ); From 4c8aff4d23c6fca93f784440bfe98b3dbddb7246 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 07:45:05 -0700 Subject: [PATCH 4232/5359] Mark `launch_editor_for_input()` a public internal API --- php/utils.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/utils.php b/php/utils.php index 62047f0eb..23d28b99d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -332,11 +332,13 @@ function pick_fields( $item, $fields ) { } /** - * Launch system's $EDITOR to edit text + * Launch system's $EDITOR for the user to edit some text. * - * @param str $content Text to edit (eg post content) - * @return str|bool Edited text, if file is saved from editor - * False, if no change to file + * @access public + * @category Input + * + * @param string $content Some form of text to edit (e.g. post content) + * @return string|bool Edited text, if file is saved from editor; false, if no change to file. */ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { From 03e8749eecfa8d403e103e5c280792fb97a564e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 16:43:16 -0700 Subject: [PATCH 4233/5359] Permit `wp cron (event|schedule) list` to output a single field --- php/commands/cron.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index 4b52d42a3..00d67f7df 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -22,6 +22,9 @@ class Cron_Event_Command extends WP_CLI_Command { * [--fields=<fields>] * : Limit the output to specific object fields. * + * [--field=<field>] + * : Prints the value of a single field for each event. + * * [--format=<format>] * : Accepted values: table, json, csv, ids, yaml. Default: table. * @@ -406,6 +409,9 @@ class Cron_Schedule_Command extends WP_CLI_Command { * [--fields=<fields>] * : Limit the output to specific object fields. * + * [--field=<field>] + * : Prints the value of a single field for each schedule. + * * [--format=<format>] * : Accepted values: table, json, csv, ids, yaml. Default: table. * From 5e94445a69a899d9eec2118ba2c7b242ba7144c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 17:10:11 -0700 Subject: [PATCH 4234/5359] Use `--due-now` to run all cron events due or overdue --- features/cron.feature | 49 ++++++++++++++++++++++++++++++++++++++++++- php/commands/cron.php | 23 ++++++++++++++------ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index c54590851..55092dbec 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -187,7 +187,7 @@ Feature: Manage WP-Cron events and schedules When I try `wp cron event run` Then STDERR should be: """ - Error: Please specify one or more cron events, or use --all. + Error: Please specify one or more cron events, or use --due-now/--all. """ When I run `wp cron event run wp_version_check wp_update_plugins` @@ -221,3 +221,50 @@ Feature: Manage WP-Cron events and schedules """ Success: Executed a total of """ + + Scenario: Run currently scheduled events + When I run `wp cron event run --all` + Then STDOUT should contain: + """ + Executed the cron event 'wp_version_check' + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_update_plugins' + """ + And STDOUT should contain: + """ + Executed the cron event 'wp_update_themes' + """ + And STDOUT should contain: + """ + Success: Executed a total of + """ + + When I run `wp cron event run --due-now` + Then STDOUT should contain: + """ + Executed a total of 0 cron event(s) + """ + + When I run `wp cron event schedule wp_cli_test_event_1 now hourly` + Then STDOUT should contain: + """ + Success: Scheduled event with hook 'wp_cli_test_event_1' + """ + + When I run `wp cron event run --due-now` + Then STDOUT should contain: + """ + Executed the cron event 'wp_cli_test_event_1' + """ + And STDOUT should contain: + """ + Executed a total of 1 cron event(s) + """ + + When I run `wp cron event run --due-now` + Then STDOUT should contain: + """ + Executed a total of 0 cron event(s) + """ diff --git a/php/commands/cron.php b/php/commands/cron.php index 4b52d42a3..c1c1e8e61 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -141,18 +141,21 @@ public function schedule( $args, $assoc_args ) { * [<hook>...] * : One or more hooks to run. * + * [--due-now] + * : Run all hooks due right now. + * * [--all] * : Run all hooks. * * ## EXAMPLES * * # Run all cron events due right now - * wp cron event run $( wp cron event list --fields=hook,next_run_relative --format=csv | awk -F, '$2=="now" {print $1}' ) + * wp cron event run --due-now */ public function run( $args, $assoc_args ) { - if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - WP_CLI::error( 'Please specify one or more cron events, or use --all.' ); + if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + WP_CLI::error( 'Please specify one or more cron events, or use --due-now/--all.' ); } $events = self::get_cron_events(); @@ -161,9 +164,17 @@ public function run( $args, $assoc_args ) { WP_CLI::error( $events ); } - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { + $due_events = array(); + foreach( $events as $event ) { + if ( time() >= $event->time ) { + $due_events[] = $event; + } + } + $events = $due_events; + } else if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $hooks = wp_list_pluck( $events, 'hook' ); + $due_events = array(); foreach( $args as $hook ) { if ( ! in_array( $hook, $hooks ) ) { WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); @@ -173,7 +184,7 @@ public function run( $args, $assoc_args ) { $executed = 0; foreach ( $events as $event ) { - if ( in_array( $event->hook, $args ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + if ( in_array( $event->hook, $args ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { $start = microtime( true ); $result = self::run_event( $event ); $total = round( microtime( true ) - $start, 3 ); From f57a13f283b0ef44a878662fcdc24c768f312825 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 13 Apr 2016 17:14:49 -0700 Subject: [PATCH 4235/5359] Remove the convoluted logic so it's more clear what's going on --- php/commands/cron.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index c1c1e8e61..b414b5586 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -180,17 +180,21 @@ public function run( $args, $assoc_args ) { WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); } } + foreach( $events as $event ) { + if ( in_array( $event->hook, $args ) ) { + $due_events[] = $event; + } + } + $events = $due_events; } $executed = 0; foreach ( $events as $event ) { - if ( in_array( $event->hook, $args ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) || \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { - $start = microtime( true ); - $result = self::run_event( $event ); - $total = round( microtime( true ) - $start, 3 ); - $executed++; - WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); - } + $start = microtime( true ); + $result = self::run_event( $event ); + $total = round( microtime( true ) - $start, 3 ); + $executed++; + WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); } $message = 'Executed a total of %d cron event(s).'; From 1e439adc530d624d2b0e32efcdf322c076b4f636 Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Wed, 13 Apr 2016 17:58:24 -0700 Subject: [PATCH 4236/5359] don't include newline in prompt --- php/commands/shell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index d0c39bd72..a4b8ebb3f 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -35,7 +35,7 @@ public function __invoke( $_, $assoc_args ) { if ( '\\Psy\\Shell' == $class ) { \Psy\Shell::debug(); } else { - $repl = new $class( "\nwp> " ); + $repl = new $class( "wp> " ); $repl->start(); } } From 6d84612c2e9ea3b2e3a2997d3c0b268a8a1c07bb Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Wed, 13 Apr 2016 18:04:37 -0700 Subject: [PATCH 4237/5359] always include a newline after non-null eval output --- php/WP_CLI/REPL.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 0a14b3e42..c9f2b27b9 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -21,7 +21,13 @@ public function start() { $line = rtrim( $line, ';' ) . ';'; if ( self::starts_with( self::non_expressions(), $line ) ) { + ob_start(); eval( $line ); + $out = ob_get_clean(); + if ( 0 < strlen ( $out ) ) { + $out = rtrim( $out, "\n" ) . "\n"; + } + fwrite( STDOUT, $out ); } else { if ( !self::starts_with( 'return', $line ) ) $line = 'return ' . $line; @@ -29,7 +35,8 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); var_dump( eval( $line ) ); - fwrite( STDOUT, ob_get_clean() ); + $out = rtrim( ob_get_clean(), "\n" ) . "\n"; + fwrite( STDOUT, $out ); } } } From 0f5dcf88ec5faa682a4e48c94f4c4828ab18fad1 Mon Sep 17 00:00:00 2001 From: Jeff Gould <jrgould@gmail.com> Date: Wed, 13 Apr 2016 18:52:29 -0700 Subject: [PATCH 4238/5359] denote return vs output of expressions --- php/WP_CLI/REPL.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index c9f2b27b9..4bb85ccf3 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -34,9 +34,14 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); - var_dump( eval( $line ) ); - $out = rtrim( ob_get_clean(), "\n" ) . "\n"; - fwrite( STDOUT, $out ); + $evl = eval( $line ); + $out = ob_get_clean(); + if ( 0 < strlen ( $out ) ) { + echo rtrim( $out, "\n" ) . "\n"; + } + echo "=> "; + var_dump( $evl ); + fwrite( STDOUT, ob_get_clean() ); } } } From f2454ba552678808df79529a1c1f7b226b20e2ad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 14 Apr 2016 07:56:52 -0700 Subject: [PATCH 4239/5359] Include more details about package management --- php/commands/package.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index e23040d15..461da96cf 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -19,6 +19,15 @@ /** * Manage WP-CLI packages. * + * WP-CLI packages are community-maintained projects built on WP-CLI. They can + * contain WP-CLI commands, but they can also just extend WP-CLI in some way. + * + * Installable packages are listed in the + * [Package Index](http://wp-cli.org/package-index/). + * + * Learn how to create your own command from the + * [Commands Cookbook](http://wp-cli.org/docs/commands-cookbook/) + * * @package WP-CLI * * @when before_wp_load From 107dbfd349b63cd3189830863bd0017bb27f6678 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 18 Apr 2016 04:53:00 -0700 Subject: [PATCH 4240/5359] Bump composer.json to use Composer 1.0.0 ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing seld/cli-prompt (1.0.1) - Installing seld/cli-prompt (1.0.2) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.json | 2 +- composer.lock | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 66efa52b3..dbb80f7fa 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "symfony/process": "~2.1", "symfony/translation": "~2.7", "nb/oxymel": "~0.1.0", - "composer/composer": "~1.0.0-beta" + "composer/composer": "~1.0.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 2616ef216..a11e79154 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "486865db5310fe94efdc68e6f0bcd370", - "content-hash": "6b640d71d1ddb8f42c44dfc0b508b9ae", + "hash": "7ea94f35bcaf09d491aba12444239a8a", + "content-hash": "81bc0608aece4400356ef972498724d4", "packages": [ { "name": "composer/composer", @@ -501,16 +501,16 @@ }, { "name": "seld/cli-prompt", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/cli-prompt.git", - "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691" + "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b27db1514f7d7bb7a366ad95d4eb2b17140a0691", - "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", + "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", "shasum": "" }, "require": { @@ -545,7 +545,7 @@ "input", "prompt" ], - "time": "2016-01-09 17:55:27" + "time": "2016-04-18 09:31:41" }, { "name": "seld/jsonlint", @@ -1731,9 +1731,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "composer/composer": 10 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 1b0061b255a31c20d48d529bd5f66392c0024f05 Mon Sep 17 00:00:00 2001 From: Akeda Bagus <admin@gedex.web.id> Date: Mon, 18 Apr 2016 22:45:18 +0700 Subject: [PATCH 4241/5359] Added field filtering in cron event list command. Resolves #2666. --- php/commands/cron.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index 20d8eb3fb..4f8a6a4f6 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -22,6 +22,9 @@ class Cron_Event_Command extends WP_CLI_Command { * [--fields=<fields>] * : Limit the output to specific object fields. * + * [--<field>=<value>] + * : Filter by one or more fields. + * * [--field=<field>] * : Prints the value of a single field for each event. * @@ -61,6 +64,15 @@ public function list_( $args, $assoc_args ) { $events = array(); } + foreach ( $events as $key => $event ) { + foreach ( $this->fields as $field ) { + if ( ! empty( $assoc_args[ $field ] ) && $event->{$field} !== $assoc_args[ $field ] ) { + unset( $events[ $key ] ); + break; + } + } + } + if ( 'ids' == $formatter->format ) { echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); } else { From 865a5525658f4b2170cfd27421b82805b4f8633e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 07:04:33 -0700 Subject: [PATCH 4242/5359] Catch `WP_Error` from `translations_api()` --- php/WP_CLI/CommandWithTranslation.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 277fb630e..d4735e9c3 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -342,6 +342,9 @@ protected function get_all_languages() { require_once ABSPATH . '/wp-admin/includes/translation-install.php'; $response = translations_api( $this->obj_type ); + if ( is_wp_error( $response ) ) { + WP_CLI::error( $response ); + } $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); $en_us = array( From 326009406bceaceefa73ceedc4235a1df146a6b1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 07:13:02 -0700 Subject: [PATCH 4243/5359] Increase minimum supported version to PHP 5.3.29 While WP-CLI may work with earlier versions, this is the minimum version we can support because 5.3.29 is the version available in Travis. --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index dbb80f7fa..f0281a185 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "bin/wp.bat", "bin/wp" ], "require": { - "php": ">=5.3.2", + "php": ">=5.3.29", "wp-cli/php-cli-tools": "~0.11.1", "mustache/mustache": "~2.4", "mustangostang/spyc": "~0.5", diff --git a/composer.lock b/composer.lock index a11e79154..0f3fca217 100644 --- a/composer.lock +++ b/composer.lock @@ -1735,7 +1735,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.3.2" + "php": ">=5.3.29" }, "platform-dev": [] } From c0d47fd4dcca9d3a851c7c01533bdfcc81028a93 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 07:16:48 -0700 Subject: [PATCH 4244/5359] Update to Composer v1.0.1 --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index a11e79154..0e5c70133 100644 --- a/composer.lock +++ b/composer.lock @@ -9,16 +9,16 @@ "packages": [ { "name": "composer/composer", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "32df3aa8cdbdaa16df9491b5e672e81c87f94c78" + "reference": "de0e25b0d494ace6b571a9205b82d017e5cb9257" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/32df3aa8cdbdaa16df9491b5e672e81c87f94c78", - "reference": "32df3aa8cdbdaa16df9491b5e672e81c87f94c78", + "url": "https://api.github.com/repos/composer/composer/zipball/de0e25b0d494ace6b571a9205b82d017e5cb9257", + "reference": "de0e25b0d494ace6b571a9205b82d017e5cb9257", "shasum": "" }, "require": { @@ -80,7 +80,7 @@ "dependency", "package" ], - "time": "2016-04-05 12:27:26" + "time": "2016-04-18 20:14:28" }, { "name": "composer/semver", From b2b019c26ee2eb9a35dd9debe3f904c69e5a56fe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 07:23:23 -0700 Subject: [PATCH 4245/5359] Add a functional test for `wp cron event list --<field>=<value>` --- features/cron.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/cron.feature b/features/cron.feature index 55092dbec..fbdfae4d5 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -21,6 +21,18 @@ Feature: Manage WP-Cron events and schedules 1 hour """ + When I run `wp cron event list --hook=wp_cli_test_event_1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp cron event list --hook=apple --format=count` + Then STDOUT should be: + """ + 0 + """ + When I run `wp cron event delete wp_cli_test_event_1` Then STDOUT should contain: """ From 2430bceb193686471cb5afe0de068e37ec6caea3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 11:11:46 -0700 Subject: [PATCH 4246/5359] Failing test case for #1981 --- features/rewrite.feature | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/features/rewrite.feature b/features/rewrite.feature index f5c22050d..ac033e6a3 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -59,15 +59,24 @@ Feature: Manage WordPress rewrites Success: Rewrite rules flushed. """ - Scenario: Generate .htaccess on hard flush + Scenario: Generate .htaccess on hard flush with a project config Given a WP install And a wp-cli.yml file: """ apache_modules: [mod_rewrite] """ - When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` - And I run `wp rewrite flush --hard` + When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` + Then the .htaccess file should exist + + Scenario: Generate .htaccess on hard flush with a global config + Given a WP install + And a config.yml file: + """ + apache_modules: [mod_rewrite] + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` Then the .htaccess file should exist Scenario: Error when trying to generate .htaccess on a multisite install From 2c309947675a73366543c47d976b619f39fbbfd3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Apr 2016 11:14:34 -0700 Subject: [PATCH 4247/5359] Persist global WP-CLI config when using WP_CLI::launch_self() Use of this method has a reasonable expectation that the launched process will mirror the existing process as closely as possible. Including the global WP-CLI config is necessary for mirroring the existing process. --- php/class-wp-cli.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ad871ec16..7d3d97099 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -758,10 +758,17 @@ public static function launch_self( $command, $args = array(), $assoc_args = arr $script_path = $GLOBALS['argv'][0]; + if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { + $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + } else { + $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; + } + $config_path = escapeshellarg( $config_path ); + $args = implode( ' ', array_map( 'escapeshellarg', $args ) ); $assoc_args = \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); - $full_command = "{$php_bin} {$script_path} {$command} {$args} {$assoc_args}"; + $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$command} {$args} {$assoc_args}"; return self::launch( $full_command, $exit_on_error, $return_detailed ); } From 255094c2ad2ab9ba7e6447bd12ef7dc040e3e01a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 09:43:29 -0700 Subject: [PATCH 4248/5359] Failing test case for calling `before_invoke` on top-level command --- features/command.feature | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/features/command.feature b/features/command.feature index dafbf3161..d28865f7f 100644 --- a/features/command.feature +++ b/features/command.feature @@ -520,13 +520,16 @@ Feature: WP-CLI Commands /** * @when before_wp_load */ - WP_CLI::add_command( 'before invoke', function() { + $before_invoke = function() { WP_CLI::success( 'Invoked' ); - }, array( 'before_invoke' => function() { + }; + $before_invoke_args = array( 'before_invoke' => function() { WP_CLI::success( 'before invoke' ); }, 'after_invoke' => function() { WP_CLI::success( 'after invoke' ); - })); + }); + WP_CLI::add_command( 'before invoke', $before_invoke, $before_invoke_args ); + WP_CLI::add_command( 'before-invoke', $before_invoke, $before_invoke_args ); """ When I run `wp --require=call-invoke.php before invoke` @@ -536,3 +539,11 @@ Feature: WP-CLI Commands Success: Invoked Success: after invoke """ + + When I run `wp --require=call-invoke.php before-invoke` + Then STDOUT should contain: + """ + Success: before invoke + Success: Invoked + Success: after invoke + """ From 2aa6b1857e3c3fbf35023ee4f69cade68a897e19 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 09:45:54 -0700 Subject: [PATCH 4249/5359] Ensure `before_invoke` and `after_invoke` are called on top-level commands too --- php/WP_CLI/Dispatcher/Subcommand.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 97906b4df..d8127a6b2 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -349,13 +349,18 @@ public function invoke( $args, $assoc_args, $extra_args ) { $path = get_path( $this->get_parent() ); $parent = implode( ' ', array_slice( $path, 1 ) ); - $cmd = $parent . ' ' . $this->name; - WP_CLI::do_hook( "before_invoke:{$parent}" ); + $cmd = $this->name; + if ( $parent ) { + WP_CLI::do_hook( "before_invoke:{$parent}" ); + $cmd = $parent . ' ' . $cmd; + } WP_CLI::do_hook( "before_invoke:{$cmd}" ); call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); - WP_CLI::do_hook( "after_invoke:{$parent}" ); + if ( $parent ) { + WP_CLI::do_hook( "after_invoke:{$parent}" ); + } WP_CLI::do_hook( "after_invoke:{$cmd}" ); } } From fcdc1e5cc7fc7001904471bbb5c1bd9d01264458 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 16:18:30 -0700 Subject: [PATCH 4250/5359] Update tests for WordPress 4.5.1 --- features/core-check-update.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index c99d9beb2..7750d6526 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -10,7 +10,7 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5 | major | https://downloads.wordpress.org/release/wordpress-4.5.zip | + | 4.5.1 | major | https://downloads.wordpress.org/release/wordpress-4.5.1.zip | | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | When I run `wp core check-update --format=count` @@ -22,7 +22,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5 | major | https://downloads.wordpress.org/release/wordpress-4.5.zip | + | 4.5.1 | major | https://downloads.wordpress.org/release/wordpress-4.5.1.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: From cc1befe4c4bf7f8c90294b44bb3be78cf431831a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 16:32:00 -0700 Subject: [PATCH 4251/5359] Only attempt to use `add_user_to_blog()` on multisite The function isn't available on a normal WordPress. --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 98c486150..ccd973a72 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -718,7 +718,7 @@ public function import_csv( $args, $assoc_args ) { $new_user['ID'] = $existing_user->ID; $user_id = wp_update_user( $new_user ); - if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && $new_user['role'] ) { + if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && is_multisite() && $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); WP_CLI::log( "{$existing_user->user_login} added as {$new_user['role']}." ); } From ea9b83a0239c38f952bceec1775e2151f5153c4e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 16:35:43 -0700 Subject: [PATCH 4252/5359] Define `DOING_CRON` before WordPress is loaded Some plugins make use of this constant to conditionally load code, which is a valid use case we should do our best to accommodate. --- php/WP_CLI/Runner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index b8ec97b77..8d13f2690 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -747,6 +747,10 @@ public function start() { define( 'WP_IMPORTING', true ); } + if ( $this->cmd_starts_with( array( 'cron', 'event', 'run' ) ) ) { + define( 'DOING_CRON', true ); + } + if ( $this->cmd_starts_with( array( 'plugin' ) ) ) { $GLOBALS['pagenow'] = 'plugins.php'; } From 6dbca8ae0f26d83cd5af7ceaa3d70f12ddf7e3d5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 26 Apr 2016 16:52:45 -0700 Subject: [PATCH 4253/5359] Don't erroneously try to (de)activate plugins with `--all` flag When the `--all` flag is provided, we should only try to activate plugins that aren't active, and deactivate plugins that are active. --- features/plugin.feature | 12 ++++++++++++ php/commands/plugin.php | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 063155a6c..acae9581b 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -262,6 +262,12 @@ Feature: Manage WordPress plugins Success: Plugin 'hello' activated. """ + When I run `wp plugin activate --all` + Then STDOUT should be: + """ + Success: All plugins are already activated. + """ + When I run `wp plugin list --field=status` Then STDOUT should be: """ @@ -277,6 +283,12 @@ Feature: Manage WordPress plugins Success: Plugin 'hello' deactivated. """ + When I run `wp plugin deactivate --all` + Then STDOUT should be: + """ + Success: All plugins are already deactivated. + """ + When I run `wp plugin list --field=status` Then STDOUT should be: """ diff --git a/php/commands/plugin.php b/php/commands/plugin.php index a7fdcb5c6..734e2fec6 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -157,15 +157,21 @@ protected function get_all_items() { */ function activate( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + if ( $all ) { $args = array_map( function( $file ){ return Utils\get_plugin_name( $file ); }, array_keys( get_plugins() ) ); } + $needing_activation = count( $args ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { $status = $this->get_status( $plugin->file ); + if ( $all && in_array( $status, array( 'active', 'active-network' ) ) ) { + $needing_activation--; + continue; + } // Network-active is the highest level of activation status if ( 'active-network' === $status ) { WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); @@ -187,6 +193,10 @@ function activate( $args, $assoc_args = array() ) { $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); } + if ( ! $needing_activation ) { + WP_CLI::success( 'All plugins are already activated.' ); + } + } /** @@ -216,9 +226,15 @@ function deactivate( $args, $assoc_args = array() ) { }, array_keys( get_plugins() ) ); } + $needing_deactivation = count( $args ); foreach ( $this->fetcher->get_many( $args ) as $plugin ) { $status = $this->get_status( $plugin->file ); + if ( $disable_all && ! in_array( $status, array( 'active', 'active-network' ) ) ) { + $needing_deactivation--; + continue; + } + // Network active plugins must be explicitly deactivated if ( ! $network_wide && 'active-network' === $status ) { WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); @@ -240,6 +256,11 @@ function deactivate( $args, $assoc_args = array() ) { } } + + if ( ! $needing_deactivation ) { + WP_CLI::success( 'All plugins are already deactivated.' ); + } + } /** From ebed88ab095856b584f6caf33af42f19a3f9dc6d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 12:54:16 -0700 Subject: [PATCH 4254/5359] Use a better next significant release operator; update to Composer 1.0.2 --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index f0281a185..8b2590b79 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "symfony/process": "~2.1", "symfony/translation": "~2.7", "nb/oxymel": "~0.1.0", - "composer/composer": "~1.0.0" + "composer/composer": "^1.0.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 3a8ed67d1..389c55967 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "7ea94f35bcaf09d491aba12444239a8a", - "content-hash": "81bc0608aece4400356ef972498724d4", + "hash": "f0bf52c59aa6e9fe44d6a611f8006a52", + "content-hash": "10cf19699e3fed767e31e1493a07c8f0", "packages": [ { "name": "composer/composer", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "de0e25b0d494ace6b571a9205b82d017e5cb9257" + "reference": "a083aa5e0c9b8ad989c622638aa380c1f88a68ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/de0e25b0d494ace6b571a9205b82d017e5cb9257", - "reference": "de0e25b0d494ace6b571a9205b82d017e5cb9257", + "url": "https://api.github.com/repos/composer/composer/zipball/a083aa5e0c9b8ad989c622638aa380c1f88a68ec", + "reference": "a083aa5e0c9b8ad989c622638aa380c1f88a68ec", "shasum": "" }, "require": { @@ -80,7 +80,7 @@ "dependency", "package" ], - "time": "2016-04-18 20:14:28" + "time": "2016-04-21 11:30:19" }, { "name": "composer/semver", From 4f3a36541fca3b68a9633d40ae23ce93c54f8b32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 14:09:53 -0700 Subject: [PATCH 4255/5359] Include a `.svnignore` when scaffolding a new plugin For authors intending to distribute to WordPress.org, this is a helpful starter template of exclusions. --- features/scaffold.feature | 5 +++++ php/commands/scaffold.php | 1 + templates/plugin-svnignore.mustache | 12 ++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 templates/plugin-svnignore.mustache diff --git a/features/scaffold.feature b/features/scaffold.feature index 54c610039..7c98f9cfe 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -123,6 +123,11 @@ Feature: WordPress code scaffolding .DS_Store node_modules/ """ + And the {PLUGIN_DIR}/hello-world/.svnignore file should contain: + """ + .git + .gitignore + """ And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: """ * Plugin Name: Hello World diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 27a48e197..ca566becc 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -446,6 +446,7 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), "$plugin_dir/.gitignore" => Utils\mustache_render( 'plugin-gitignore.mustache', $data ), + "$plugin_dir/.svnignore" => Utils\mustache_render( 'plugin-svnignore.mustache', $data ), "$plugin_dir/.editorconfig" => file_get_contents( WP_CLI_ROOT . "/templates/.editorconfig" ), ), $force ); diff --git a/templates/plugin-svnignore.mustache b/templates/plugin-svnignore.mustache new file mode 100644 index 000000000..e2aafda73 --- /dev/null +++ b/templates/plugin-svnignore.mustache @@ -0,0 +1,12 @@ +# A set of files you probably don't want in your WordPress.org distribution +.editorconfig +.git +.gitignore +.travis.yml +bin +composer.json +composer.lock +phpunit.xml +tests +vendor +node_modules From 7835f732bb37580ff25e212f2a49c1016b0e0cbe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 14:44:28 -0700 Subject: [PATCH 4256/5359] A few more files we don't want to include by default --- templates/plugin-svnignore.mustache | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/plugin-svnignore.mustache b/templates/plugin-svnignore.mustache index e2aafda73..7c2581b32 100644 --- a/templates/plugin-svnignore.mustache +++ b/templates/plugin-svnignore.mustache @@ -1,4 +1,5 @@ # A set of files you probably don't want in your WordPress.org distribution +.svnignore .editorconfig .git .gitignore @@ -6,7 +7,11 @@ bin composer.json composer.lock +Gruntfile.js +package.json phpunit.xml +phpunit.xml.dist +README.md tests vendor node_modules From e5561013950cccca23a0dd3a5d852f316dccd2ff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 15:20:19 -0700 Subject: [PATCH 4257/5359] Genuinely run test suite against built Phar file Apparently this hasn't been happening for a while --- ci/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/test.sh b/ci/test.sh index 930f2b4a5..3295945f0 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -2,6 +2,8 @@ set -ex +export WP_CLI_BIN_DIR=/tmp/wp-cli-phar + # Run the unit tests vendor/bin/phpunit From 2a24ea9f9c49db178f071d6df664dd5ac8d94a75 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 15:35:33 -0700 Subject: [PATCH 4258/5359] Better way of verifying the `wp` binary --- ci/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index 3295945f0..34233ebad 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -2,7 +2,7 @@ set -ex -export WP_CLI_BIN_DIR=/tmp/wp-cli-phar +$WP_CLI_BIN_DIR/wp --info # Run the unit tests vendor/bin/phpunit From 9d98f5c9f7607f234cefc12b0d992d3b59453568 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 15:41:39 -0700 Subject: [PATCH 4259/5359] Restore global `WP_CLI_BIN_DIR` env variable We can't set env variables in scripts. Unfortunately, this means the test suite hasn't been running against the Phar build for a while --- .travis.yml | 6 +++++- ci/prepare.sh | 2 -- ci/test.sh | 2 -- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 81b0e2b1d..b811927a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,10 @@ sudo: false language: php +env: + global: + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + matrix: include: - php: 5.3 @@ -11,7 +15,7 @@ matrix: - php: 5.6 env: WP_VERSION=latest - php: 5.6 - env: WP_VERSION=latest BUILD=git + env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' - php: 5.6 env: WP_VERSION=trunk - php: 7.0 diff --git a/ci/prepare.sh b/ci/prepare.sh index f2fea77e5..bbf2aa502 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -17,10 +17,8 @@ fi # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR if [[ $BUILD == 'git' ]] then - export WP_CLI_BIN_DIR=bin/wp echo $CLI_VERSION > VERSION else - export WP_CLI_BIN_DIR=/tmp/wp-cli-phar mkdir -p $WP_CLI_BIN_DIR php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet --version=$CLI_VERSION mv wp-cli.phar $WP_CLI_BIN_DIR/wp diff --git a/ci/test.sh b/ci/test.sh index 34233ebad..930f2b4a5 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -2,8 +2,6 @@ set -ex -$WP_CLI_BIN_DIR/wp --info - # Run the unit tests vendor/bin/phpunit From 4c7b3c7937241d18db088cce1defd6c237312944 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 15:44:32 -0700 Subject: [PATCH 4260/5359] Make it much easier to determine which `wp` binary we're running against --- features/bootstrap/FeatureContext.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 85748947b..4886aa75a 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -85,6 +85,10 @@ private static function cache_wp_files() { * @BeforeSuite */ public static function prepare( SuiteEvent $event ) { + $result = Process::create( 'wp cli info', null, self::get_process_env_variables() )->run_check(); + echo PHP_EOL; + echo $result->stdout; + echo PHP_EOL; self::cache_wp_files(); } From 312c3c8af754f97dd3a97ffce0cde6106d3973b2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 16:12:13 -0700 Subject: [PATCH 4261/5359] Include more dependencies the Phar build is expected to have --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 30c261c11..7bbf083e0 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -69,6 +69,7 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/mustache') ->in(WP_CLI_ROOT . '/vendor/rmccue/requests') ->in(WP_CLI_ROOT . '/vendor/composer') + ->in(WP_CLI_ROOT . '/vendor/seld') ->in(WP_CLI_ROOT . '/vendor/symfony') ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') From 8e4b55364b62a57eca19b8a84b7615a1fea78ee1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 28 Apr 2016 17:03:25 -0700 Subject: [PATCH 4262/5359] Include pem file that is occasionally needed by Composer --- utils/make-phar.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 7bbf083e0..219164bd6 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -101,6 +101,7 @@ function set_file_contents( $phar, $path, $content ) { add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/LICENSE' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/cacert.pem' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/composer-schema.json' ); add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); From 1de6e47fc87661584c8494b9431bb5ea64235c32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:26:25 -0700 Subject: [PATCH 4263/5359] Fix listing user meta associated with a given username All methods on this class need to replace a provided username / email address with the user id, which this method wasn't doing. --- features/user-meta.feature | 6 ++++++ php/commands/user.php | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/features/user-meta.feature b/features/user-meta.feature index 8d96312b2..4a8901ab4 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -69,3 +69,9 @@ Feature: Manage user custom fields | user_id | meta_key | meta_value | | 1 | nickname | admin | | 1 | foo | ["1","2"] | + + When I run `wp user meta list admin --keys=nickname,foo` + Then STDOUT should be a table containing rows: + | user_id | meta_key | meta_value | + | 1 | nickname | admin | + | 1 | foo | ["1","2"] | diff --git a/php/commands/user.php b/php/commands/user.php index ccd973a72..197326292 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -830,6 +830,30 @@ public function __construct() { $this->fetcher = new \WP_CLI\Fetchers\User; } + /** + * List all metadata associated with a user. + * + * ## OPTIONS + * + * <id> + * : ID for the object. + * + * [--keys=<keys>] + * : Limit output to metadata of specific keys. + * + * [--fields=<fields>] + * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::list_( $args, $assoc_args ); + } + /** * Get meta field value. * From bdeae3675d1db7c064d62080463553d1decbe1ba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:39:03 -0700 Subject: [PATCH 4264/5359] If comment was already trashed, then it will be deleted --- features/comment.feature | 12 ++++++++++++ php/commands/comment.php | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/features/comment.feature b/features/comment.feature index 9a4fb0de2..514b1e70a 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -56,6 +56,18 @@ Feature: Manage WordPress comments Success: Trashed comment 4. """ + When I run `wp comment delete 3` + Then STDOUT should be: + """ + Success: Deleted comment 3. + """ + + When I try `wp comment get 3` + Then STDERR should be: + """ + Error: Invalid comment ID. + """ + Scenario: Get details about an existing comment When I run `wp comment get 1` Then STDOUT should be a table containing rows: diff --git a/php/commands/comment.php b/php/commands/comment.php index 8c8b82a3b..b287a06f3 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -249,10 +249,11 @@ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); + $status = wp_get_comment_status( $comment_id ); $r = wp_delete_comment( $comment_id, $force ); if ( $r ) { - if ( $force ) { + if ( $force || 'trash' === $status ) { return array( 'success', "Deleted comment $comment_id." ); } else { return array( 'success', "Trashed comment $comment_id." ); From 8087e2ccac337e93c82952981e3e81292c5006f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:45:23 -0700 Subject: [PATCH 4265/5359] Clearly denote OPTIONS in `wp cache *` docs --- php/commands/cache.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/php/commands/cache.php b/php/commands/cache.php index 51df60802..299939980 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -16,6 +16,8 @@ class Cache_Command extends WP_CLI_Command { * * If a value already exists for the key, the value isn't added. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -45,6 +47,8 @@ public function add( $args, $assoc_args ) { /** * Decrement a value in the object cache. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -73,6 +77,8 @@ public function decr( $args, $assoc_args ) { /** * Remove a value from the object cache. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -112,6 +118,8 @@ public function flush( $args, $assoc_args ) { /** * Get a value from the object cache. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -135,6 +143,8 @@ public function get( $args, $assoc_args ) { /** * Increment a value in the object cache. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -163,6 +173,8 @@ public function incr( $args, $assoc_args ) { /** * Replace a value in the object cache, if the value already exists. * + * ## OPTIONS + * * <key> * : Cache key. * @@ -194,6 +206,8 @@ public function replace( $args, $assoc_args ) { /** * Set a value to the object cache, regardless of whether it already exists. * + * ## OPTIONS + * * <key> * : Cache key. * From 700d125689ed40a6ff9559346df934d30017d728 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:46:24 -0700 Subject: [PATCH 4266/5359] Clearly denote OPTIONS in `wp cap *` docs --- php/commands/cap.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cap.php b/php/commands/cap.php index 9330c2c9a..3f65b1f23 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -19,6 +19,8 @@ class Capabilities_Command extends WP_CLI_Command { /** * List capabilities for a given role. * + * ## OPTIONS + * * <role> * : Key for the role. * @@ -39,6 +41,8 @@ public function list_( $args ) { /** * Add capabilities to a given role. * + * ## OPTIONS + * * <role> * : Key for the role. * @@ -69,6 +73,8 @@ public function add( $args ) { /** * Remove capabilities from a given role. * + * ## OPTIONS + * * <role> * : Key for the role. * From 3ce23272f6c1da9e78f0d6d88a0886ecc36642a9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:48:22 -0700 Subject: [PATCH 4267/5359] Clarify that `wp core verify-checksums` doesn't actually load WP This behavior changed in the last release --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index e60505e79..7208c05ea 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -789,7 +789,9 @@ public function version( $args = array(), $assoc_args = array() ) { /** * Verify WordPress files against WordPress.org's checksums. * - * Specify version to verify checksums without loading WordPress. + * For security, avoids loading WordPress when verifying checksums. + * + * ## OPTIONS * * [--version=<version>] * : Verify checksums against a specific version of WordPress. From 800261159688cb30b278c98bb7ffe18102aa4fdd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:49:30 -0700 Subject: [PATCH 4268/5359] Clearly denote OPTIONS in `wp eval` docs --- php/commands/eval.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/eval.php b/php/commands/eval.php index f81a626da..11847ccfd 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -5,6 +5,8 @@ class Eval_Command extends WP_CLI_Command { /** * Execute arbitrary PHP code. * + * ## OPTIONS + * * <php-code> * : The code to execute, as a string. * From a18bf85eb9073b6ad29e70a6b73608ec64d8a71b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 04:51:52 -0700 Subject: [PATCH 4269/5359] Clearly denote OPTIONS in `wp menu *` docs --- php/commands/menu.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index 1c9e7e12b..b4272494f 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -31,6 +31,8 @@ class Menu_Command extends WP_CLI_Command { /** * Create a new menu * + * ## OPTIONS + * * <menu-name> * : A descriptive name for the menu * @@ -63,6 +65,8 @@ public function create( $args, $assoc_args ) { /** * Delete one or more menus * + * ## OPTIONS + * * <menu>... * : The name, slug, or term ID for the menu(s) * @@ -253,6 +257,8 @@ public function list_( $args, $assoc_args ) { /** * Add a post as a menu item * + * ## OPTIONS + * * <menu> * : The name, slug, or term ID for the menu * @@ -308,6 +314,8 @@ public function add_post( $args, $assoc_args ) { /** * Add a taxonomy term as a menu item * + * ## OPTIONS + * * <menu> * : The name, slug, or term ID for the menu * @@ -367,6 +375,8 @@ public function add_term( $args, $assoc_args ) { /** * Add a custom menu item * + * ## OPTIONS + * * <menu> * : The name, slug, or term ID for the menu * @@ -415,6 +425,8 @@ public function add_custom( $args, $assoc_args ) { /** * Update a menu item * + * ## OPTIONS + * * <db-id> * : Database ID for the menu item. * @@ -466,6 +478,8 @@ public function update( $args, $assoc_args ) { /** * Delete one or more items from a menu * + * ## OPTIONS + * * <db-id>... * : Database ID for the menu item(s). * @@ -633,6 +647,8 @@ class Menu_Location_Command extends WP_CLI_Command { /** * List locations for the current theme. * + * ## OPTIONS + * * [--format=<format>] * : Accepted values: table, csv, json, count, ids, yaml. Default: table * @@ -667,6 +683,8 @@ public function list_( $_, $assoc_args ) { /** * Assign a location to a menu * + * ## OPTIONS + * * <menu> * : The name, slug, or term ID for the menu * @@ -704,6 +722,8 @@ public function assign( $args, $_ ) { /** * Remove a location from a menu * + * ## OPTIONS + * * <menu> * : The name, slug, or term ID for the menu * From b51b05fc0b9146a920198615ba28db3d73fd111a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 29 Apr 2016 13:42:45 -0700 Subject: [PATCH 4270/5359] Document how to handle WP in subdirectory; add test to doc behavior --- features/core.feature | 60 +++++++++++++++++++++++++++++++++++++++++++ php/commands/core.php | 12 ++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/features/core.feature b/features/core.feature index 0bc830cd0..a0f2f54ec 100644 --- a/features/core.feature +++ b/features/core.feature @@ -260,3 +260,63 @@ Feature: Manage WordPress installation """ Error: WordPress files seem to already be present here. """ + + Scenario: Install WordPress in a subdirectory + Given an empty directory + And a wp-config.php file: + """ + <?php + // ** MySQL settings ** // + /** The name of the database for WordPress */ + define('DB_NAME', 'wp_cli_test'); + + /** MySQL database username */ + define('DB_USER', 'wp_cli_test'); + + /** MySQL database password */ + define('DB_PASSWORD', 'password1'); + + /** MySQL hostname */ + define('DB_HOST', '127.0.0.1'); + + /** Database Charset to use in creating database tables. */ + define('DB_CHARSET', 'utf8'); + + /** The Database Collate type. Don't change this if in doubt. */ + define('DB_COLLATE', ''); + + $table_prefix = 'wp_'; + + /* That's all, stop editing! Happy blogging. */ + + /** Absolute path to the WordPress directory. */ + if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + + /** Sets up WordPress vars and included files. */ + require_once(ABSPATH . 'wp-settings.php'); + """ + And a wp-cli.yml file: + """ + path: wp + """ + + When I run `wp core download` + Then the wp directory should exist + And the wp/wp-blog-header.php file should exist + + When I run `wp db create` + And I run `wp core install --url=wp.dev --title="WP Dev" --admin_user=wpcli --admin_password=wpcli --admin_email=wpcli@example.com` + Then STDOUT should not be empty + + When I run `wp option get home` + Then STDOUT should be: + """ + http://wp.dev + """ + + When I run `wp option get siteurl` + Then STDOUT should be: + """ + http://wp.dev + """ diff --git a/php/commands/core.php b/php/commands/core.php index 7208c05ea..4ef575507 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -414,7 +414,17 @@ public function is_installed( $_, $assoc_args ) { } /** - * Create the WordPress tables in the database. + * Runs the standard WordPress installation process. + * + * Creates the WordPress tables in the database using the URL, title, and + * default admin user details provided. Performs the famous 5 minute install + * in seconds or less. + * + * Note: if you've installed WordPress in a subdirectory, then you'll need + * to `wp option update siteurl` after `wp core install`. For instance, if + * WordPress is installed in the `/wp` directory and your domain is wp.dev, + * then you'll need to run `wp option update siteurl http://wp.dev/wp` for + * your WordPress install to function properly. * * ## OPTIONS * From c863051646da854b5d20a32ccbe60ff92f5206c7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 2 May 2016 16:11:58 -0700 Subject: [PATCH 4271/5359] Document how to import an attachment and assign multiple thumbnails --- php/commands/media.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index df37e7521..ddbf001b1 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -120,6 +120,12 @@ function regenerate( $args, $assoc_args = array() ) { * # Import a local image and set it to be the post thumbnail for a post * wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image * + * # Import a local image, but set it as the featured image for all posts + * # 1. Import the image and get its attachment ID + * * 2. Assign the attachment ID as the featured image for all posts + * ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)" + * wp post list --post_type=post --format=ids | xargs -0 -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID + * * # Import an image from the web * wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" */ From d601bf0989b4c1a2b87d9390cb14bf5748ce2816 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 3 May 2016 10:16:10 +0545 Subject: [PATCH 4272/5359] issue of taking only first digit from Comment ID --- php/commands/comment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 4031bcc79..a29f135b2 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -302,7 +302,7 @@ private function call( $args, $status, $success, $failure ) { } private function set_status( $args, $status, $success ) { - $comment = $this->fetcher->get_check( $args[0] ); + $comment = $this->fetcher->get_check( $args ); $r = wp_set_comment_status( $comment->comment_ID, $status, true ); From 656482e074e815b27f8f1d0a3674af7c80f1abe1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 3 May 2016 17:21:57 +0545 Subject: [PATCH 4273/5359] add test for comment issue --- features/comment.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 514b1e70a..bc5fa51c7 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -159,3 +159,33 @@ Feature: Manage WordPress comments """ 0 """ + + Scenario: Approving/unapproving comments with multidigit comment ID + Given I run `wp comment generate --count=10 --quiet` + And I run `wp comment create --porcelain` + And save STDOUT as {COMMENT_ID} + + When I run `wp comment unapprove {COMMENT_ID}` + Then STDOUT should contain: + """ + Unapproved comment {COMMENT_ID} + """ + + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 10 + """ + + When I run `wp comment approve {COMMENT_ID}` + Then STDOUT should contain: + """ + Approved comment {COMMENT_ID} + """ + + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 11 + """ + From a936bf6bf5d29a7f34aa793f9994c6f3359532b7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 3 May 2016 04:58:25 -0700 Subject: [PATCH 4274/5359] Ignore ambigious empty plugin and theme slugs when installing If a user supplies an empty slug, its likely a mistake. WP-CLI shouldn't proceeed to install the first result from WordPress.org --- features/plugin.feature | 13 +++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index acae9581b..ff89ccb2e 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -401,3 +401,16 @@ Feature: Manage WordPress plugins Then STDOUT should be a table containing rows: | name | version | | akismet | 2.6.0 | + + Scenario: Ignore empty slugs + Given a WP install + + When I run `wp plugin install ''` + Then STDERR should contain: + """ + Warning: Ignoring ambigious empty slug value. + """ + And STDOUT should not contain: + """ + Plugin installed successfully + """ diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e1c5dd0d7..561b2331d 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -2,6 +2,8 @@ namespace WP_CLI; +use WP_CLI; + abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $item_type; @@ -117,6 +119,12 @@ private function show_legend( $items ) { function install( $args, $assoc_args ) { foreach ( $args as $slug ) { + + if ( empty( $slug ) ) { + WP_CLI::warning( "Ignoring ambigious empty slug value." ); + continue; + } + $local_or_remote_zip_file = false; $result = false; From 43e313e90a7ab0caec2aff590c237aa93a3321e7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 3 May 2016 05:19:52 -0700 Subject: [PATCH 4275/5359] Prevent runaway memory usage by clearing object cache after each file --- php/commands/export.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/export.php b/php/commands/export.php index 8d5731df0..7d89b0a0a 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -94,6 +94,7 @@ public function __invoke( $_, $assoc_args ) { add_action( 'wp_export_new_file', function( $file_path ) { WP_CLI::log( sprintf( "Writing to file %s", $file_path ) ); + WP_CLI\Utils\wp_clear_object_cache(); } ); try { From 7e9159e5c81afbd2b5d3b2fd89722ae69d7e73d7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 3 May 2016 05:33:57 -0700 Subject: [PATCH 4276/5359] Failing test case for greedy parsing of args again --- tests/test-doc-parser.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php index 90cd205c2..c82ed4e69 100644 --- a/tests/test-doc-parser.php +++ b/tests/test-doc-parser.php @@ -97,6 +97,13 @@ function test_complete() { public function test_desc_parses_yaml() { $longdesc = <<<EOB +Play some music loudly + +``` +# Here's an example of how you might run the command +wp rock-on electronic --volume=11 +``` + ## OPTIONS <genre>... From 7bdc0a4a51a1dc6e07520145cd4c39efb8ac6f9b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 3 May 2016 05:35:42 -0700 Subject: [PATCH 4277/5359] Fix greedy parsing of command args, part two When an example is included at the beginning of the command, we need to make sure we don't match on example usage. --- php/WP_CLI/DocParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index b9ab93d19..7d3df5532 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -120,7 +120,7 @@ public function get_arg_desc( $name ) { * @return mixed|null */ public function get_arg_args( $name ) { - return $this->get_arg_or_param_args( "/\[?<{$name}>.*/" ); + return $this->get_arg_or_param_args( "/^\[?<{$name}>.*/" ); } /** @@ -145,7 +145,7 @@ public function get_param_desc( $key ) { * @return mixed|null */ public function get_param_args( $key ) { - return $this->get_arg_or_param_args( "/\[?--{$key}=.*/" ); + return $this->get_arg_or_param_args( "/^\[?--{$key}=.*/" ); } /** From 9dd7d2b0dac82a88ac9e420298b5a762c4904ac7 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 4 May 2016 10:38:52 +0545 Subject: [PATCH 4278/5359] fix command in comment feature test --- features/comment.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index bc5fa51c7..7bdad4fa2 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -171,7 +171,7 @@ Feature: Manage WordPress comments Unapproved comment {COMMENT_ID} """ - When I run `wp comment get --field=comment_approved {COMMENT_ID}` + When I run `wp comment list --format=count --status=approve` Then STDOUT should be: """ 10 @@ -183,7 +183,7 @@ Feature: Manage WordPress comments Approved comment {COMMENT_ID} """ - When I run `wp comment get --field=comment_approved {COMMENT_ID}` + When I run `wp comment list --format=count --status=approve` Then STDOUT should be: """ 11 From 3ea2c2ccc2e40b06e854683ffc7e9bc09fa52217 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 4 May 2016 11:16:40 +0545 Subject: [PATCH 4279/5359] remove all comments before test --- features/comment.feature | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/comment.feature b/features/comment.feature index 7bdad4fa2..ef11b422c 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -161,7 +161,8 @@ Feature: Manage WordPress comments """ Scenario: Approving/unapproving comments with multidigit comment ID - Given I run `wp comment generate --count=10 --quiet` + Given I run `wp comment delete $(wp comment list --field=ID)` + And I run `wp comment generate --count=10 --quiet` And I run `wp comment create --porcelain` And save STDOUT as {COMMENT_ID} From 25e62e4103637ba783e2472ad4fe693197be1918 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 4 May 2016 04:06:06 -0700 Subject: [PATCH 4280/5359] Interact with the Package Index over SSL More secure! More better! --- php/commands/package.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 461da96cf..4129c92fd 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -34,7 +34,7 @@ */ class Package_Command extends WP_CLI_Command { - const PACKAGE_INDEX_URL = 'http://wp-cli.org/package-index/'; + const PACKAGE_INDEX_URL = 'https://wp-cli.org/package-index/'; private $fields = array( 'name', @@ -102,7 +102,7 @@ public function install( $args, $assoc_args ) { $json_manipulator = new JsonManipulator( $composer_backup ); $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); $json_manipulator->addLink( 'require', $package_name, $version ); - $json_manipulator->addConfigSetting( 'secure-http', false ); + $json_manipulator->addConfigSetting( 'secure-http', true ); file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); try { $composer = $this->get_composer(); @@ -288,7 +288,7 @@ private function package_index() { $config = new Config(); $config->merge( array( 'config' => array( - 'secure-http' => false, + 'secure-http' => true, 'home' => dirname( $this->get_composer_json_path() ), ) )); From bfb51cffec980e8f823e83a64a3533e8809582bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 4 May 2016 09:01:46 -0700 Subject: [PATCH 4281/5359] Mention multisite rewrite rules will need to be added manually. --- php/commands/core.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4ef575507..4e23f1509 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -457,6 +457,9 @@ public function install( $args, $assoc_args ) { /** * Transform a single-site install into a multi-site install. * + * For those using WordPress with Apache, remember to update the `.htaccess` + * file with the appropriate multisite rewrite rules. + * * ## OPTIONS * * [--title=<network-title>] From 4b696f3cfb3479205feb3f81f904465b925a6965 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 11 May 2016 10:27:31 +0545 Subject: [PATCH 4282/5359] fix incorrect parameter in post-type list command doc --- php/commands/post-type.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post-type.php b/php/commands/post-type.php index 4fdff4600..ae73a2dd0 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -49,7 +49,7 @@ class Post_Type_Command extends WP_CLI_Command { * * wp post-type list --format=csv * - * wp post-type list --object-type=post --fields=name,public + * wp post-type list --capability_type=post --fields=name,public * * @subcommand list */ From 182d003d4bfc10be4cca4c854bac0e0ec1fc0d5e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 11 May 2016 04:08:32 -0700 Subject: [PATCH 4283/5359] Update tests for WP 4.5.2 --- features/core-check-update.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 7750d6526..ad3cf2a69 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -10,8 +10,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.1 | major | https://downloads.wordpress.org/release/wordpress-4.5.1.zip | - | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | + | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | + | 3.8.14 | minor | https://downloads.wordpress.org/release/wordpress-3.8.14-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -22,7 +22,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.1 | major | https://downloads.wordpress.org/release/wordpress-4.5.1.zip | + | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -33,7 +33,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.13 | minor | https://downloads.wordpress.org/release/wordpress-3.8.13-partial-0.zip | + | 3.8.14 | minor | https://downloads.wordpress.org/release/wordpress-3.8.14-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -54,4 +54,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.10 | minor | https://downloads.wordpress.org/release/wordpress-4.0.10-partial-0.zip | + | 4.0.11 | minor | https://downloads.wordpress.org/release/wordpress-4.0.11-partial-0.zip | From 3c1f28fa584366fb2d98179623bea587d4f261aa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 11 May 2016 04:32:19 -0700 Subject: [PATCH 4284/5359] Version bump for minor releases too --- features/core-update.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-update.feature b/features/core-update.feature index 2cb55be5f..ea20e1049 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.13 + Updating to version 3.7.14 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.13 + 3.7.14 """ @less-than-php-7 From a5a1426acfe1726f5750a53bcd354fe5c9aee11f Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 12 May 2016 13:53:13 +0545 Subject: [PATCH 4285/5359] display success message in dry run in search-replace --- features/search-replace.feature | 6 ++++++ php/commands/search-replace.php | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 99ec9b0c0..2fd3e14e8 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -216,6 +216,12 @@ Feature: Do global search/replace | Table | Column | Replacements | Type | | wp_posts | post_content | 1 | SQL | + When I run `wp search-replace '<a href="http://google.com">Google</a>' '<a href="http://apple.com">Apple</a>' --dry-run` + Then STDOUT should contain: + """ + 1 replacement(s) to be made. + """ + When I run `wp post get {POST_ID} --field=content` Then STDOUT should be: """ diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 5de6afa3c..7ab5f5173 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -207,6 +207,10 @@ public function __invoke( $args, $assoc_args ) { } WP_CLI::success( $success_message ); } + else { + $success_message = "$total replacement(s) to be made."; + WP_CLI::success( $success_message ); + } } private function php_export_table( $table, $old, $new ) { From 5f51f673370349097c0bf2e6db0246d9b90ce2ed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 12 May 2016 06:07:53 -0700 Subject: [PATCH 4286/5359] Failing test case for using supplied `default` and `options` --- features/command.feature | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/features/command.feature b/features/command.feature index d28865f7f..490b13c31 100644 --- a/features/command.feature +++ b/features/command.feature @@ -285,10 +285,10 @@ Feature: WP-CLI Commands And a custom-cmd.php file: """ <?php - function foo( $args ) { + function foo( $args, $assoc_args ) { $message = array_shift( $args ); WP_CLI::log( 'Message is: ' . $message ); - WP_CLI::success( $args[0] ); + WP_CLI::success( $assoc_args['meal'] ); } WP_CLI::add_command( 'foo', 'foo', array( 'shortdesc' => 'My awesome function command', @@ -370,6 +370,32 @@ Feature: WP-CLI Commands --- """ + When I try `wp foo nana --apple=fuji` + Then STDERR should contain: + """ + Error: Invalid value specified for positional arg. + """ + + When I try `wp foo hello --apple=fuji --meal=snack` + Then STDERR should contain: + """ + Invalid value specified for 'meal' (A type of meal.) + """ + + When I run `wp foo hello --apple=fuji` + Then STDOUT should be: + """ + Message is: hello + Success: breakfast + """ + + When I run `wp foo hello --apple=fuji --meal=dinner` + Then STDOUT should be: + """ + Message is: hello + Success: dinner + """ + Scenario: Register a command with default and accepted arguments. Given an empty directory And a test-cmd.php file: From 1fa689fd3da74c0b747a92f5cf3235998b94ecfa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 12 May 2016 12:43:38 -0700 Subject: [PATCH 4287/5359] Mock command PHPDoc so we can reparse it This enables `default` and `options` are used when supplied as the third argument to `WP_CLI::add_command()` At some point, this storing of command metadata in PHPdoc needs to be dealt with. But not yet. --- php/WP_CLI/Dispatcher/Subcommand.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index d8127a6b2..35d8922cb 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -258,9 +258,13 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $synopsis_spec = \WP_CLI\SynopsisParser::parse( $synopsis ); $i = 0; $errors = array( 'fatal' => array(), 'warning' => array() ); + $mock_doc = array( $this->get_shortdesc(), '' ); + $mock_doc = array_merge( $mock_doc, explode( PHP_EOL, $this->get_longdesc() ) ); + $mock_doc = '/**' . PHP_EOL . '* ' . implode( PHP_EOL . '* ', $mock_doc ) . PHP_EOL . '*/'; + $docparser = new \WP_CLI\DocParser( $mock_doc ); foreach( $synopsis_spec as $spec ) { if ( 'positional' === $spec['type'] ) { - $spec_args = $this->docparser->get_arg_args( $spec['name'] ); + $spec_args = $docparser->get_arg_args( $spec['name'] ); if ( ! isset( $args[ $i ] ) ) { if ( isset( $spec_args['default'] ) ) { $args[ $i ] = $spec_args['default']; @@ -282,7 +286,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { } $i++; } else if ( 'assoc' === $spec['type'] ) { - $spec_args = $this->docparser->get_param_args( $spec['name'] ); + $spec_args = $docparser->get_param_args( $spec['name'] ); if ( ! isset( $assoc_args[ $spec['name'] ] ) ) { if ( isset( $spec_args['default'] ) ) { $assoc_args[ $spec['name'] ] = $spec_args['default']; @@ -313,7 +317,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $out = 'Parameter errors:'; foreach ( $errors['fatal'] as $key => $error ) { $out .= "\n {$error}"; - if ( $desc = $this->docparser->get_param_desc( $key ) ) { + if ( $desc = $docparser->get_param_desc( $key ) ) { $out .= " ({$desc})"; } } From fc1797cfa3efe9e3a412c30e24c8d9474de6cd04 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 16:11:15 +0300 Subject: [PATCH 4288/5359] Extended insert format to search-replace SQL export --- php/commands/search-replace.php | 45 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7ab5f5173..0853258de 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -228,6 +228,8 @@ private function php_export_table( $table, $old, $new ) { $this->start_time = microtime( true ); WP_CLI::log( sprintf( 'Checking: %s', $table ) ); } + + $rows = array(); foreach ( new \WP_CLI\Iterators\Table( $args ) as $i => $row ) { $row_fields = array(); foreach( $all_columns as $col ) { @@ -241,8 +243,9 @@ private function php_export_table( $table, $old, $new ) { } $row_fields[ $col ] = $value; } - $this->write_sql_row_fields( $table, $row_fields ); + $rows[] = $row_fields; } + $this->write_sql_row_fields( $table, $rows ); $table_report = array(); $total_rows = $total_cols = 0; @@ -328,20 +331,33 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { return $count; } - private function write_sql_row_fields( $table, $row_fields ) { + private function write_sql_row_fields( $table, $rows ) { global $wpdb; - $sql = "INSERT INTO `$table` ("; - $sql .= join( ', ', array_map( - function ( $field ) { - return "`$field`"; - }, - array_keys( $row_fields ) - ) ); - $sql .= ') VALUES ('; - $sql .= join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ); - $sql .= ");\n"; - $sql = $wpdb->prepare( $sql, array_values( $row_fields ) ); - fwrite( $this->export_handle, $sql ); + + if(!empty($rows)) { + $sql = "INSERT INTO `$table` ("; + $sql .= join( ', ', array_map( + function ( $field ) { + return "`$field`"; + }, + array_keys( $rows[0] ) + ) ); + $sql .= ') VALUES '; + $sql .= "\n"; + + $values = array(); + $count = count( $rows ); // No comma to last row + foreach($rows as $row_fields) { + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')' . ($count-- > 1 ? ',' : ''); + $sql .= "\n"; + $values = array_merge( $values, array_values( $row_fields ) ); + } + + $sql .= ";\n"; + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); + } } private static function get_columns( $table ) { @@ -387,4 +403,3 @@ private static function esc_like( $old ) { } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); - From 8d80c06ce23a7d7fca7ec28f69bb207abc05c38d Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 17:03:35 +0300 Subject: [PATCH 4289/5359] Updated search-replace-export feature test --- features/search-replace-export.feature | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index e50bde0cc..630c73309 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -11,7 +11,11 @@ Feature: Search / replace with file export """ And STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.net', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + And STDOUT should contain: + """ + ('1', 'siteurl', 'http://example.net', 'yes') """ When I run `wp option get home` @@ -23,8 +27,12 @@ Feature: Search / replace with file export When I run `wp search-replace example.com example.net --skip-columns=option_value --export` Then STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES """ + And STDOUT should contain: + """ + ('1', 'siteurl', 'http://example.com', 'yes') + """ When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: From 3751db8ffa51230a02a271da79602dc523c353b4 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 17:28:44 +0300 Subject: [PATCH 4290/5359] Split insert queries into separate chunks --- php/commands/search-replace.php | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0853258de..7df844116 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -335,25 +335,40 @@ private function write_sql_row_fields( $table, $rows ) { global $wpdb; if(!empty($rows)) { - $sql = "INSERT INTO `$table` ("; - $sql .= join( ', ', array_map( + $insert = "INSERT INTO `$table` ("; + $insert .= join( ', ', array_map( function ( $field ) { return "`$field`"; }, array_keys( $rows[0] ) ) ); - $sql .= ') VALUES '; - $sql .= "\n"; + $insert .= ') VALUES '; + $insert .= "\n"; + $sql = $insert; $values = array(); - $count = count( $rows ); // No comma to last row + + $index = 1; + $count = count( $rows ); + $export_chunk_size = 50; // Amount of rows in one insert query + foreach($rows as $row_fields) { - $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')' . ($count-- > 1 ? ',' : ''); - $sql .= "\n"; + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; $values = array_merge( $values, array_values( $row_fields ) ); - } - $sql .= ";\n"; + if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + $sql .= ";\n"; + + if( $count > $index ) { + $sql .= $insert; + } + } else { + $sql .= ",\n"; + + } + + $index++; + } $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); From 8a9d2d4b455dd2ab5a0b34b7778da39a990ab9a7 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sat, 14 May 2016 20:49:31 +0900 Subject: [PATCH 4291/5359] fix #2711 --- features/post.feature | 8 +++++++- php/WP_CLI/Formatter.php | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index d9e5e0793..b503ccee3 100644 --- a/features/post.feature +++ b/features/post.feature @@ -100,7 +100,7 @@ Feature: Manage WordPress posts """ This is some bunkum. """ - + When I run `wp post url 1 {POST_ID}` Then STDOUT should be: """ @@ -176,6 +176,12 @@ Feature: Manage WordPress posts | Publish post | publish-post | publish | | Draft post | | draft | + When I run `wp post list --post_type='post' --fields="title, name, status" --format=csv` + Then STDOUT should be CSV containing: + | post_title | post_name | post_status | + | Publish post | publish-post | publish | + | Draft post | | draft | + When I run `wp post list --post__in={POST_ID} --format=count` Then STDOUT should be: """ diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 87f81c8bb..0b04ec5e8 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -40,6 +40,8 @@ public function __construct( &$assoc_args, $fields = null, $prefix = false ) { $format_args['fields'] = explode( ',', $format_args['fields'] ); } + $format_args['fields'] = array_map( 'trim', $format_args['fields'] ); + $this->args = $format_args; $this->prefix = $prefix; } From 66612c02ecbc69c1928c9566058ea6386707c999 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 15 May 2016 05:20:07 +0900 Subject: [PATCH 4292/5359] get wp version when scaffolding plugin --- features/scaffold.feature | 16 ++++++++++++++-- php/commands/scaffold.php | 15 ++++++++------- templates/plugin-readme.mustache | 6 +++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 7c98f9cfe..cc79744ae 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -109,6 +109,8 @@ Feature: WordPress code scaffolding Given a WP install Given I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} + Given I run `wp core version` + And save STDOUT as {WP_VERSION} When I run `wp scaffold plugin hello-world --plugin_author="Hello World Author"` Then STDOUT should not be empty @@ -140,6 +142,14 @@ Feature: WordPress code scaffolding """ * @package Hello_World """ + And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: + """ + Stable tag: 0.1.0 + """ + And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: + """ + Tested up to: {WP_VERSION} + """ When I run `cat {PLUGIN_DIR}/hello-world/package.json` Then STDOUT should be JSON containing: @@ -332,6 +342,8 @@ Feature: WordPress code scaffolding Scenario: Scaffold tests parses plugin readme.txt Given a WP install + When I run `wp core version` + Then save STDOUT as {WP_VERSION} When I run `wp plugin path` Then save STDOUT as {PLUGIN_DIR} @@ -343,8 +355,8 @@ Feature: WordPress code scaffolding """ env: - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=3.0.1 WP_MULTISITE=0 - - WP_VERSION=3.4 WP_MULTISITE=0 + - WP_VERSION=3.7 WP_MULTISITE=0 + - WP_VERSION={WP_VERSION} WP_MULTISITE=0 """ Scenario: Scaffold starter code for a theme and network enable it diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ca566becc..11bf1b910 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -415,13 +415,14 @@ function plugin( $args, $assoc_args ) { $plugin_package = str_replace( ' ', '_', $plugin_name ); $data = wp_parse_args( $assoc_args, array( - 'plugin_slug' => $plugin_slug, - 'plugin_name' => $plugin_name, - 'plugin_package' => $plugin_package, - 'plugin_description' => 'PLUGIN DESCRIPTION HERE', - 'plugin_author' => 'YOUR NAME HERE', - 'plugin_author_uri' => 'YOUR SITE HERE', - 'plugin_uri' => 'PLUGIN SITE HERE', + 'plugin_slug' => $plugin_slug, + 'plugin_name' => $plugin_name, + 'plugin_package' => $plugin_package, + 'plugin_description' => 'PLUGIN DESCRIPTION HERE', + 'plugin_author' => 'YOUR NAME HERE', + 'plugin_author_uri' => 'YOUR SITE HERE', + 'plugin_uri' => 'PLUGIN SITE HERE', + 'plugin_tested_up_to' => get_bloginfo('version'), ) ); $data['textdomain'] = $plugin_slug; diff --git a/templates/plugin-readme.mustache b/templates/plugin-readme.mustache index 44c117a68..6d6953479 100644 --- a/templates/plugin-readme.mustache +++ b/templates/plugin-readme.mustache @@ -2,9 +2,9 @@ Contributors: (this should be a list of wordpress.org userid's) Donate link: http://example.com/ Tags: comments, spam -Requires at least: 3.0.1 -Tested up to: 3.4 -Stable tag: 4.3 +Requires at least: 3.7 +Tested up to: {{plugin_tested_up_to}} +Stable tag: 0.1.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From b2545163c01931ac4e0dec652c66f34d0fb23a75 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Sun, 15 May 2016 20:57:46 +0300 Subject: [PATCH 4293/5359] Code structure improved --- php/commands/search-replace.php | 68 +++++++++++++++++---------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7df844116..64de7aafb 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -334,45 +334,47 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { private function write_sql_row_fields( $table, $rows ) { global $wpdb; - if(!empty($rows)) { - $insert = "INSERT INTO `$table` ("; - $insert .= join( ', ', array_map( - function ( $field ) { - return "`$field`"; - }, - array_keys( $rows[0] ) - ) ); - $insert .= ') VALUES '; - $insert .= "\n"; - - $sql = $insert; - $values = array(); - - $index = 1; - $count = count( $rows ); - $export_chunk_size = 50; // Amount of rows in one insert query - - foreach($rows as $row_fields) { - $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; - $values = array_merge( $values, array_values( $row_fields ) ); - - if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { - $sql .= ";\n"; - - if( $count > $index ) { - $sql .= $insert; - } - } else { - $sql .= ",\n"; + if(empty($rows)) { + return; + } + + $insert = "INSERT INTO `$table` ("; + $insert .= join( ', ', array_map( + function ( $field ) { + return "`$field`"; + }, + array_keys( $rows[0] ) + ) ); + $insert .= ') VALUES '; + $insert .= "\n"; + + $sql = $insert; + $values = array(); + $index = 1; + $count = count( $rows ); + $export_chunk_size = 50; // Amount of rows in one insert query + + foreach($rows as $row_fields) { + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; + $values = array_merge( $values, array_values( $row_fields ) ); + + if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + $sql .= ";\n"; + + if( $count > $index ) { + $sql .= $insert; } + } else { + $sql .= ",\n"; - $index++; } - $sql = $wpdb->prepare( $sql, array_values( $values ) ); - fwrite( $this->export_handle, $sql ); + $index++; } + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); } private static function get_columns( $table ) { From 7721029e16ba515d7613841a9b6b6f1dd318a5be Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 May 2016 04:22:07 -0700 Subject: [PATCH 4294/5359] Conditionally require `WP_HTTP_Requests_Response` for WP 4.6 compat --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 975c59f59..ba5c9243e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -208,6 +208,7 @@ Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-cookie.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-encoding.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-response.php' ); +Utils\maybe_require( '4.6-alpha-37438', ABSPATH . WPINC . '/class-wp-http-requests-response.php' ); require( ABSPATH . WPINC . '/widgets.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget-factory.php' ); From 4834764c453f74e74ffaa98df4399ded7e1cfef7 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 14:48:40 +0300 Subject: [PATCH 4295/5359] Updated tests --- features/search-replace-export.feature | 38 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index 630c73309..d5ff992c9 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -11,11 +11,16 @@ Feature: Search / replace with file export """ And STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('1', 'siteurl', 'http://example.net', 'yes'), + """ + And STDOUT should contain: + """ + ('51', 'blog_public', '1', 'yes'), """ And STDOUT should contain: """ - ('1', 'siteurl', 'http://example.net', 'yes') + ('50', 'upload_path', '', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES """ When I run `wp option get home` @@ -27,12 +32,16 @@ Feature: Search / replace with file export When I run `wp search-replace example.com example.net --skip-columns=option_value --export` Then STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('1', 'siteurl', 'http://example.com', 'yes'), + ('2', 'home', 'http://example.com', 'yes'), + """ + Then STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('51', 'blog_public', '1', 'yes'), + ('52', 'default_link_category', '2', 'yes'), """ - And STDOUT should contain: - """ - ('1', 'siteurl', 'http://example.com', 'yes') - """ When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: @@ -52,16 +61,17 @@ Feature: Search / replace with file export Scenario: Search / replace export to file Given a WP install - And I run `wp post generate --count=30` + And I run `wp post generate --count=100` + And I run `wp option add example_url http://example.com` When I run `wp search-replace example.com example.net --export=wordpress.sql` Then STDOUT should contain: """ - Success: Made 39 replacements and exported to wordpress.sql + Success: Made 110 replacements and exported to wordpress.sql """ And STDOUT should be a table containing rows: | Table | Column | Replacements | Type | - | wp_options | option_value | 5 | PHP | + | wp_options | option_value | 6 | PHP | When I run `wp option get home` Then STDOUT should be: @@ -85,10 +95,16 @@ Feature: Search / replace with file export http://example.net """ + When I run `wp option get example_url` + Then STDOUT should be: + """ + http://example.net + """ + When I run `wp post list --format=count` Then STDOUT should be: """ - 31 + 101 """ Scenario: Search / replace export to file with verbosity From da1d31bd0ec51ba79012b10943eedd9c4902c9ea Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 15:29:43 +0300 Subject: [PATCH 4296/5359] Improved performance --- php/commands/search-replace.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 64de7aafb..9af81577e 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -361,9 +361,13 @@ function ( $field ) { if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; - + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); + if( $count > $index ) { - $sql .= $insert; + $sql = $insert; + $values = array(); } } else { $sql .= ",\n"; @@ -372,9 +376,6 @@ function ( $field ) { $index++; } - - $sql = $wpdb->prepare( $sql, array_values( $values ) ); - fwrite( $this->export_handle, $sql ); } private static function get_columns( $table ) { From 45f308bd664526988f97e0a09280d5d74f5e24bb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 May 2016 11:19:32 -0700 Subject: [PATCH 4297/5359] Use `--ssh=<host>[:<path>]` to run commands on remote servers --- php/WP_CLI/Runner.php | 43 +++++++++++++++++++++++++++++++++++++++++++ php/config-spec.php | 6 ++++++ 2 files changed, 49 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8d13f2690..0b19a3fc8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -333,6 +333,44 @@ private function _run_command() { $this->run_command( $this->arguments, $this->assoc_args ); } + /** + * Perform a command against a remote server over SSH + */ + private function run_ssh_command( $ssh ) { + + $host = $ssh; + $path = ''; + if ( false !== ( $key = stripos( $host, ':' ) ) ) { + $path = substr( $host, $key + 1 ); + $host = substr( $host, 0, $key ); + } + + WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); + WP_CLI::debug( 'SSH path: ' . $path, 'bootstrap' ); + + $is_tty = function_exists( 'posix_isatty' ) && posix_isatty( STDOUT ); + + $wp_binary = 'wp'; + $wp_args = array_slice( $GLOBALS['argv'], 1 ); + $wp_path = $path ? sprintf( '--path=%s', $path ) : ''; + foreach( $wp_args as $k => $v ) { + if ( preg_match( '#--ssh=#', $v ) ) { + unset( $wp_args[ $k ] ); + } + } + $command = sprintf( + 'ssh -q %s %s %s', + escapeshellarg( $host ), + $is_tty ? '-t' : '-T', + escapeshellarg( $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', $wp_args ) ) + ); + + passthru( $command, $exit_code ); + if ( 0 !== $exit_code ) { + exit( $exit_code ); + } + } + /** * Check whether a given command is disabled by the config * @@ -668,6 +706,11 @@ public function start() { } } + if ( $this->config['ssh'] ) { + $this->run_ssh_command( $this->config['ssh'] ); + return; + } + // Show synopsis if it's a composite command. $r = $this->find_command_to_run( $this->arguments ); if ( is_array( $r ) ) { diff --git a/php/config-spec.php b/php/config-spec.php index 84221c0f0..b38f59584 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -7,6 +7,12 @@ 'desc' => 'Path to the WordPress files.', ), + 'ssh' => array( + 'runtime' => '=<ssh>', + 'file' => '<ssh>', + 'desc' => 'Perform operation against a remote server over SSH.', + ), + 'url' => array( 'runtime' => '=<url>', 'file' => '<url>', From d607efec83bf266808ccaf8473b80996e1f7760a Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 22:30:00 +0300 Subject: [PATCH 4298/5359] Flag to define number of rows in one INSERT query --- features/search-replace-export.feature | 14 ++++++++++++++ php/commands/search-replace.php | 18 ++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index d5ff992c9..da829ac89 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -43,6 +43,20 @@ Feature: Search / replace with file export ('52', 'default_link_category', '2', 'yes'), """ + When I run `wp search-replace example.com example.net --skip-columns=option_value --export --export_insert_size=5` + Then STDOUT should contain: + """ + ('5', 'users_can_register', '0', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + + When I run `wp search-replace example.com example.net --export --export_insert_size=text` + Then STDOUT should contain: + """ + ('50', 'upload_path', '', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: """ diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 9af81577e..8c12594f5 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -9,6 +9,7 @@ class Search_Replace_Command extends WP_CLI_Command { private $dry_run; private $export_handle = false; + private $export_insert_size; private $recurse_objects; private $regex; private $skip_columns; @@ -61,6 +62,9 @@ class Search_Replace_Command extends WP_CLI_Command { * : Write transformed data as SQL file instead of saving replacements to * the database. If <file> is not supplied, will output to STDOUT. * + * [--export_insert_size[=<rows>]] + * : Define number of rows in single INSERT statement when doing SQL export. + * * [--skip-columns=<columns>] * : Do not perform the replacement on specific columns. Use commas to * specify multiple columns. 'guid' is skipped by default. @@ -124,6 +128,12 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); } } + $export_insert_size = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export_insert_size' ); + if ( (int) $export_insert_size == $export_insert_size && $export_insert_size > 0 ) { + $this->export_insert_size = $export_insert_size; + } else { + $this->export_insert_size = 50; + } $php_only = true; } @@ -353,18 +363,18 @@ function ( $field ) { $index = 1; $count = count( $rows ); - $export_chunk_size = 50; // Amount of rows in one insert query + $export_insert_size = $this->export_insert_size; foreach($rows as $row_fields) { $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; $values = array_merge( $values, array_values( $row_fields ) ); - if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + if( ( $index % $export_insert_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; - + $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); - + if( $count > $index ) { $sql = $insert; $values = array(); From 2889fd337a6339661df7694562efd4f25510c4f7 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 22:34:56 +0300 Subject: [PATCH 4299/5359] Fixed tests for WP 3.7 Testing option rows was too specific. Insert statement creation is practically tested later by checking data inserted to database with that query. --- features/search-replace-export.feature | 9 --------- 1 file changed, 9 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index da829ac89..96c34cbb7 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -13,15 +13,6 @@ Feature: Search / replace with file export """ ('1', 'siteurl', 'http://example.net', 'yes'), """ - And STDOUT should contain: - """ - ('51', 'blog_public', '1', 'yes'), - """ - And STDOUT should contain: - """ - ('50', 'upload_path', '', 'yes'); - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - """ When I run `wp option get home` Then STDOUT should be: From c0ab1d83fb1c7a52687996d5c32fe7f3618a2216 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 May 2016 15:16:07 -0700 Subject: [PATCH 4300/5359] Rename to `.distignore` to imply use for generic distibution --- features/scaffold.feature | 2 +- php/commands/scaffold.php | 2 +- .../{plugin-svnignore.mustache => plugin-distignore.mustache} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename templates/{plugin-svnignore.mustache => plugin-distignore.mustache} (95%) diff --git a/features/scaffold.feature b/features/scaffold.feature index cc79744ae..9b52d6cd6 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -125,7 +125,7 @@ Feature: WordPress code scaffolding .DS_Store node_modules/ """ - And the {PLUGIN_DIR}/hello-world/.svnignore file should contain: + And the {PLUGIN_DIR}/hello-world/.distignore file should contain: """ .git .gitignore diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 11bf1b910..7f29542a6 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -447,7 +447,7 @@ function plugin( $args, $assoc_args ) { "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), "$plugin_dir/.gitignore" => Utils\mustache_render( 'plugin-gitignore.mustache', $data ), - "$plugin_dir/.svnignore" => Utils\mustache_render( 'plugin-svnignore.mustache', $data ), + "$plugin_dir/.distignore" => Utils\mustache_render( 'plugin-distignore.mustache', $data ), "$plugin_dir/.editorconfig" => file_get_contents( WP_CLI_ROOT . "/templates/.editorconfig" ), ), $force ); diff --git a/templates/plugin-svnignore.mustache b/templates/plugin-distignore.mustache similarity index 95% rename from templates/plugin-svnignore.mustache rename to templates/plugin-distignore.mustache index 7c2581b32..6a8b3da10 100644 --- a/templates/plugin-svnignore.mustache +++ b/templates/plugin-distignore.mustache @@ -1,5 +1,5 @@ # A set of files you probably don't want in your WordPress.org distribution -.svnignore +.distignore .editorconfig .git .gitignore From f7d80a97b290430bbe67031df730f798bbc3b047 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 16:11:15 +0300 Subject: [PATCH 4301/5359] Extended insert format to search-replace SQL export --- php/commands/search-replace.php | 45 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7ab5f5173..0853258de 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -228,6 +228,8 @@ private function php_export_table( $table, $old, $new ) { $this->start_time = microtime( true ); WP_CLI::log( sprintf( 'Checking: %s', $table ) ); } + + $rows = array(); foreach ( new \WP_CLI\Iterators\Table( $args ) as $i => $row ) { $row_fields = array(); foreach( $all_columns as $col ) { @@ -241,8 +243,9 @@ private function php_export_table( $table, $old, $new ) { } $row_fields[ $col ] = $value; } - $this->write_sql_row_fields( $table, $row_fields ); + $rows[] = $row_fields; } + $this->write_sql_row_fields( $table, $rows ); $table_report = array(); $total_rows = $total_cols = 0; @@ -328,20 +331,33 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { return $count; } - private function write_sql_row_fields( $table, $row_fields ) { + private function write_sql_row_fields( $table, $rows ) { global $wpdb; - $sql = "INSERT INTO `$table` ("; - $sql .= join( ', ', array_map( - function ( $field ) { - return "`$field`"; - }, - array_keys( $row_fields ) - ) ); - $sql .= ') VALUES ('; - $sql .= join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ); - $sql .= ");\n"; - $sql = $wpdb->prepare( $sql, array_values( $row_fields ) ); - fwrite( $this->export_handle, $sql ); + + if(!empty($rows)) { + $sql = "INSERT INTO `$table` ("; + $sql .= join( ', ', array_map( + function ( $field ) { + return "`$field`"; + }, + array_keys( $rows[0] ) + ) ); + $sql .= ') VALUES '; + $sql .= "\n"; + + $values = array(); + $count = count( $rows ); // No comma to last row + foreach($rows as $row_fields) { + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')' . ($count-- > 1 ? ',' : ''); + $sql .= "\n"; + $values = array_merge( $values, array_values( $row_fields ) ); + } + + $sql .= ";\n"; + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); + } } private static function get_columns( $table ) { @@ -387,4 +403,3 @@ private static function esc_like( $old ) { } WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); - From adf71bd4b059fc59ec0034af20474c75df7a5e58 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 17:03:35 +0300 Subject: [PATCH 4302/5359] Updated search-replace-export feature test --- features/search-replace-export.feature | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index e50bde0cc..630c73309 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -11,7 +11,11 @@ Feature: Search / replace with file export """ And STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.net', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + And STDOUT should contain: + """ + ('1', 'siteurl', 'http://example.net', 'yes') """ When I run `wp option get home` @@ -23,8 +27,12 @@ Feature: Search / replace with file export When I run `wp search-replace example.com example.net --skip-columns=option_value --export` Then STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES """ + And STDOUT should contain: + """ + ('1', 'siteurl', 'http://example.com', 'yes') + """ When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: From 6ca1e274be82247185d100263874d2255156b35f Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Fri, 13 May 2016 17:28:44 +0300 Subject: [PATCH 4303/5359] Split insert queries into separate chunks --- php/commands/search-replace.php | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 0853258de..7df844116 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -335,25 +335,40 @@ private function write_sql_row_fields( $table, $rows ) { global $wpdb; if(!empty($rows)) { - $sql = "INSERT INTO `$table` ("; - $sql .= join( ', ', array_map( + $insert = "INSERT INTO `$table` ("; + $insert .= join( ', ', array_map( function ( $field ) { return "`$field`"; }, array_keys( $rows[0] ) ) ); - $sql .= ') VALUES '; - $sql .= "\n"; + $insert .= ') VALUES '; + $insert .= "\n"; + $sql = $insert; $values = array(); - $count = count( $rows ); // No comma to last row + + $index = 1; + $count = count( $rows ); + $export_chunk_size = 50; // Amount of rows in one insert query + foreach($rows as $row_fields) { - $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')' . ($count-- > 1 ? ',' : ''); - $sql .= "\n"; + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; $values = array_merge( $values, array_values( $row_fields ) ); - } - $sql .= ";\n"; + if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + $sql .= ";\n"; + + if( $count > $index ) { + $sql .= $insert; + } + } else { + $sql .= ",\n"; + + } + + $index++; + } $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); From fd7b24a5d4c22e5f84bc2e1f516c5b1b67b11710 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sat, 14 May 2016 20:49:31 +0900 Subject: [PATCH 4304/5359] fix #2711 --- features/post.feature | 8 +++++++- php/WP_CLI/Formatter.php | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/post.feature b/features/post.feature index d9e5e0793..b503ccee3 100644 --- a/features/post.feature +++ b/features/post.feature @@ -100,7 +100,7 @@ Feature: Manage WordPress posts """ This is some bunkum. """ - + When I run `wp post url 1 {POST_ID}` Then STDOUT should be: """ @@ -176,6 +176,12 @@ Feature: Manage WordPress posts | Publish post | publish-post | publish | | Draft post | | draft | + When I run `wp post list --post_type='post' --fields="title, name, status" --format=csv` + Then STDOUT should be CSV containing: + | post_title | post_name | post_status | + | Publish post | publish-post | publish | + | Draft post | | draft | + When I run `wp post list --post__in={POST_ID} --format=count` Then STDOUT should be: """ diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 87f81c8bb..0b04ec5e8 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -40,6 +40,8 @@ public function __construct( &$assoc_args, $fields = null, $prefix = false ) { $format_args['fields'] = explode( ',', $format_args['fields'] ); } + $format_args['fields'] = array_map( 'trim', $format_args['fields'] ); + $this->args = $format_args; $this->prefix = $prefix; } From 2bbf4970a31330344d69628bb226036d6a1aa5a2 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 15 May 2016 05:20:07 +0900 Subject: [PATCH 4305/5359] get wp version when scaffolding plugin --- features/scaffold.feature | 16 ++++++++++++++-- php/commands/scaffold.php | 15 ++++++++------- templates/plugin-readme.mustache | 6 +++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 7c98f9cfe..cc79744ae 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -109,6 +109,8 @@ Feature: WordPress code scaffolding Given a WP install Given I run `wp plugin path` And save STDOUT as {PLUGIN_DIR} + Given I run `wp core version` + And save STDOUT as {WP_VERSION} When I run `wp scaffold plugin hello-world --plugin_author="Hello World Author"` Then STDOUT should not be empty @@ -140,6 +142,14 @@ Feature: WordPress code scaffolding """ * @package Hello_World """ + And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: + """ + Stable tag: 0.1.0 + """ + And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: + """ + Tested up to: {WP_VERSION} + """ When I run `cat {PLUGIN_DIR}/hello-world/package.json` Then STDOUT should be JSON containing: @@ -332,6 +342,8 @@ Feature: WordPress code scaffolding Scenario: Scaffold tests parses plugin readme.txt Given a WP install + When I run `wp core version` + Then save STDOUT as {WP_VERSION} When I run `wp plugin path` Then save STDOUT as {PLUGIN_DIR} @@ -343,8 +355,8 @@ Feature: WordPress code scaffolding """ env: - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=3.0.1 WP_MULTISITE=0 - - WP_VERSION=3.4 WP_MULTISITE=0 + - WP_VERSION=3.7 WP_MULTISITE=0 + - WP_VERSION={WP_VERSION} WP_MULTISITE=0 """ Scenario: Scaffold starter code for a theme and network enable it diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ca566becc..11bf1b910 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -415,13 +415,14 @@ function plugin( $args, $assoc_args ) { $plugin_package = str_replace( ' ', '_', $plugin_name ); $data = wp_parse_args( $assoc_args, array( - 'plugin_slug' => $plugin_slug, - 'plugin_name' => $plugin_name, - 'plugin_package' => $plugin_package, - 'plugin_description' => 'PLUGIN DESCRIPTION HERE', - 'plugin_author' => 'YOUR NAME HERE', - 'plugin_author_uri' => 'YOUR SITE HERE', - 'plugin_uri' => 'PLUGIN SITE HERE', + 'plugin_slug' => $plugin_slug, + 'plugin_name' => $plugin_name, + 'plugin_package' => $plugin_package, + 'plugin_description' => 'PLUGIN DESCRIPTION HERE', + 'plugin_author' => 'YOUR NAME HERE', + 'plugin_author_uri' => 'YOUR SITE HERE', + 'plugin_uri' => 'PLUGIN SITE HERE', + 'plugin_tested_up_to' => get_bloginfo('version'), ) ); $data['textdomain'] = $plugin_slug; diff --git a/templates/plugin-readme.mustache b/templates/plugin-readme.mustache index 44c117a68..6d6953479 100644 --- a/templates/plugin-readme.mustache +++ b/templates/plugin-readme.mustache @@ -2,9 +2,9 @@ Contributors: (this should be a list of wordpress.org userid's) Donate link: http://example.com/ Tags: comments, spam -Requires at least: 3.0.1 -Tested up to: 3.4 -Stable tag: 4.3 +Requires at least: 3.7 +Tested up to: {{plugin_tested_up_to}} +Stable tag: 0.1.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From 76ea245e146d3323c4f535522d146f2a054b7709 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Sun, 15 May 2016 20:57:46 +0300 Subject: [PATCH 4306/5359] Code structure improved --- php/commands/search-replace.php | 68 +++++++++++++++++---------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7df844116..64de7aafb 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -334,45 +334,47 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { private function write_sql_row_fields( $table, $rows ) { global $wpdb; - if(!empty($rows)) { - $insert = "INSERT INTO `$table` ("; - $insert .= join( ', ', array_map( - function ( $field ) { - return "`$field`"; - }, - array_keys( $rows[0] ) - ) ); - $insert .= ') VALUES '; - $insert .= "\n"; - - $sql = $insert; - $values = array(); - - $index = 1; - $count = count( $rows ); - $export_chunk_size = 50; // Amount of rows in one insert query - - foreach($rows as $row_fields) { - $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; - $values = array_merge( $values, array_values( $row_fields ) ); - - if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { - $sql .= ";\n"; - - if( $count > $index ) { - $sql .= $insert; - } - } else { - $sql .= ",\n"; + if(empty($rows)) { + return; + } + + $insert = "INSERT INTO `$table` ("; + $insert .= join( ', ', array_map( + function ( $field ) { + return "`$field`"; + }, + array_keys( $rows[0] ) + ) ); + $insert .= ') VALUES '; + $insert .= "\n"; + + $sql = $insert; + $values = array(); + $index = 1; + $count = count( $rows ); + $export_chunk_size = 50; // Amount of rows in one insert query + + foreach($rows as $row_fields) { + $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; + $values = array_merge( $values, array_values( $row_fields ) ); + + if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + $sql .= ";\n"; + + if( $count > $index ) { + $sql .= $insert; } + } else { + $sql .= ",\n"; - $index++; } - $sql = $wpdb->prepare( $sql, array_values( $values ) ); - fwrite( $this->export_handle, $sql ); + $index++; } + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); } private static function get_columns( $table ) { From a503bbddd18dfa5ec2e20e82f7f80c43bf4bd265 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 16 May 2016 04:22:07 -0700 Subject: [PATCH 4307/5359] Conditionally require `WP_HTTP_Requests_Response` for WP 4.6 compat --- php/wp-settings-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 975c59f59..ba5c9243e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -208,6 +208,7 @@ Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-cookie.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-encoding.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-response.php' ); +Utils\maybe_require( '4.6-alpha-37438', ABSPATH . WPINC . '/class-wp-http-requests-response.php' ); require( ABSPATH . WPINC . '/widgets.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget-factory.php' ); From f005f6152247be1a2acfda85efe0c503be99807a Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 14:48:40 +0300 Subject: [PATCH 4308/5359] Updated tests --- features/search-replace-export.feature | 38 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index 630c73309..d5ff992c9 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -11,11 +11,16 @@ Feature: Search / replace with file export """ And STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('1', 'siteurl', 'http://example.net', 'yes'), + """ + And STDOUT should contain: + """ + ('51', 'blog_public', '1', 'yes'), """ And STDOUT should contain: """ - ('1', 'siteurl', 'http://example.net', 'yes') + ('50', 'upload_path', '', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES """ When I run `wp option get home` @@ -27,12 +32,16 @@ Feature: Search / replace with file export When I run `wp search-replace example.com example.net --skip-columns=option_value --export` Then STDOUT should contain: """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('1', 'siteurl', 'http://example.com', 'yes'), + ('2', 'home', 'http://example.com', 'yes'), + """ + Then STDOUT should contain: + """ + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + ('51', 'blog_public', '1', 'yes'), + ('52', 'default_link_category', '2', 'yes'), """ - And STDOUT should contain: - """ - ('1', 'siteurl', 'http://example.com', 'yes') - """ When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: @@ -52,16 +61,17 @@ Feature: Search / replace with file export Scenario: Search / replace export to file Given a WP install - And I run `wp post generate --count=30` + And I run `wp post generate --count=100` + And I run `wp option add example_url http://example.com` When I run `wp search-replace example.com example.net --export=wordpress.sql` Then STDOUT should contain: """ - Success: Made 39 replacements and exported to wordpress.sql + Success: Made 110 replacements and exported to wordpress.sql """ And STDOUT should be a table containing rows: | Table | Column | Replacements | Type | - | wp_options | option_value | 5 | PHP | + | wp_options | option_value | 6 | PHP | When I run `wp option get home` Then STDOUT should be: @@ -85,10 +95,16 @@ Feature: Search / replace with file export http://example.net """ + When I run `wp option get example_url` + Then STDOUT should be: + """ + http://example.net + """ + When I run `wp post list --format=count` Then STDOUT should be: """ - 31 + 101 """ Scenario: Search / replace export to file with verbosity From e7ae1b6325129f4ef1fca2c03add0bc2091e2c35 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 15:29:43 +0300 Subject: [PATCH 4309/5359] Improved performance --- php/commands/search-replace.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 64de7aafb..9af81577e 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -361,9 +361,13 @@ function ( $field ) { if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; - + + $sql = $wpdb->prepare( $sql, array_values( $values ) ); + fwrite( $this->export_handle, $sql ); + if( $count > $index ) { - $sql .= $insert; + $sql = $insert; + $values = array(); } } else { $sql .= ",\n"; @@ -372,9 +376,6 @@ function ( $field ) { $index++; } - - $sql = $wpdb->prepare( $sql, array_values( $values ) ); - fwrite( $this->export_handle, $sql ); } private static function get_columns( $table ) { From f38fbc0da53a0b1f12b63b42aec2b258e967b78e Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 22:30:00 +0300 Subject: [PATCH 4310/5359] Flag to define number of rows in one INSERT query --- features/search-replace-export.feature | 14 ++++++++++++++ php/commands/search-replace.php | 18 ++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index d5ff992c9..da829ac89 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -43,6 +43,20 @@ Feature: Search / replace with file export ('52', 'default_link_category', '2', 'yes'), """ + When I run `wp search-replace example.com example.net --skip-columns=option_value --export --export_insert_size=5` + Then STDOUT should contain: + """ + ('5', 'users_can_register', '0', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + + When I run `wp search-replace example.com example.net --export --export_insert_size=text` + Then STDOUT should contain: + """ + ('50', 'upload_path', '', 'yes'); + INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES + """ + When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: """ diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 9af81577e..8c12594f5 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -9,6 +9,7 @@ class Search_Replace_Command extends WP_CLI_Command { private $dry_run; private $export_handle = false; + private $export_insert_size; private $recurse_objects; private $regex; private $skip_columns; @@ -61,6 +62,9 @@ class Search_Replace_Command extends WP_CLI_Command { * : Write transformed data as SQL file instead of saving replacements to * the database. If <file> is not supplied, will output to STDOUT. * + * [--export_insert_size[=<rows>]] + * : Define number of rows in single INSERT statement when doing SQL export. + * * [--skip-columns=<columns>] * : Do not perform the replacement on specific columns. Use commas to * specify multiple columns. 'guid' is skipped by default. @@ -124,6 +128,12 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); } } + $export_insert_size = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export_insert_size' ); + if ( (int) $export_insert_size == $export_insert_size && $export_insert_size > 0 ) { + $this->export_insert_size = $export_insert_size; + } else { + $this->export_insert_size = 50; + } $php_only = true; } @@ -353,18 +363,18 @@ function ( $field ) { $index = 1; $count = count( $rows ); - $export_chunk_size = 50; // Amount of rows in one insert query + $export_insert_size = $this->export_insert_size; foreach($rows as $row_fields) { $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; $values = array_merge( $values, array_values( $row_fields ) ); - if( ( $index % $export_chunk_size == 0 && $index > 0 ) || $index == $count ) { + if( ( $index % $export_insert_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; - + $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); - + if( $count > $index ) { $sql = $insert; $values = array(); From b438b95d5562d7163d4b1038e535c5c9b80a29f8 Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Mon, 16 May 2016 22:34:56 +0300 Subject: [PATCH 4311/5359] Fixed tests for WP 3.7 Testing option rows was too specific. Insert statement creation is practically tested later by checking data inserted to database with that query. --- features/search-replace-export.feature | 9 --------- 1 file changed, 9 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index da829ac89..96c34cbb7 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -13,15 +13,6 @@ Feature: Search / replace with file export """ ('1', 'siteurl', 'http://example.net', 'yes'), """ - And STDOUT should contain: - """ - ('51', 'blog_public', '1', 'yes'), - """ - And STDOUT should contain: - """ - ('50', 'upload_path', '', 'yes'); - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - """ When I run `wp option get home` Then STDOUT should be: From 2458a57d0ef8b29c32f09c4207ec33379e9e4a5b Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Tue, 17 May 2016 10:32:10 +0300 Subject: [PATCH 4312/5359] Fixed search replace export bug --- features/search-replace-export.feature | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature index 96c34cbb7..3730a98b1 100644 --- a/features/search-replace-export.feature +++ b/features/search-replace-export.feature @@ -25,29 +25,15 @@ Feature: Search / replace with file export """ INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES ('1', 'siteurl', 'http://example.com', 'yes'), - ('2', 'home', 'http://example.com', 'yes'), - """ - Then STDOUT should contain: - """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - ('51', 'blog_public', '1', 'yes'), - ('52', 'default_link_category', '2', 'yes'), """ - When I run `wp search-replace example.com example.net --skip-columns=option_value --export --export_insert_size=5` - Then STDOUT should contain: - """ - ('5', 'users_can_register', '0', 'yes'); - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - """ - - When I run `wp search-replace example.com example.net --export --export_insert_size=text` + When I run `wp search-replace example.com example.net --skip-columns=option_value --export --export_insert_size=1` Then STDOUT should contain: """ - ('50', 'upload_path', '', 'yes'); + ('1', 'siteurl', 'http://example.com', 'yes'); INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES """ - + When I run `wp search-replace foo bar --export | tail -n 1` Then STDOUT should not contain: """ From b788e52a384150b4cbd5c8ae0a8d28ba37f84e6b Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Wed, 18 May 2016 09:22:58 +0300 Subject: [PATCH 4313/5359] Better option handling --- php/commands/search-replace.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 8c12594f5..b6f285a1c 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -62,8 +62,10 @@ class Search_Replace_Command extends WP_CLI_Command { * : Write transformed data as SQL file instead of saving replacements to * the database. If <file> is not supplied, will output to STDOUT. * - * [--export_insert_size[=<rows>]] + * [--export_insert_size=<rows>] * : Define number of rows in single INSERT statement when doing SQL export. + * You might want to change this depending on your database configuration + * (e.g. if you need to do fewer queries). Default: 50 * * [--skip-columns=<columns>] * : Do not perform the replacement on specific columns. Use commas to @@ -128,7 +130,7 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); } } - $export_insert_size = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export_insert_size' ); + $export_insert_size = $assoc_args['export_insert_size']; if ( (int) $export_insert_size == $export_insert_size && $export_insert_size > 0 ) { $this->export_insert_size = $export_insert_size; } else { From e6c5aed5ca0519d3c55a66227322b0f6b55248de Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 18 May 2016 04:51:53 -0700 Subject: [PATCH 4314/5359] Remove `--config=<config>` as a runtime argument It's been broken since 7a1499e0a3683f9d51dc18d73d8b087685a9e318 (v0.13.0) --- php/WP_CLI/Runner.php | 5 +---- php/config-spec.php | 5 ----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8d13f2690..e8b1561c1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -68,10 +68,7 @@ private function do_early_invoke( $when ) { */ private function get_global_config_path() { - if ( isset( $runtime_config['config'] ) ) { - $config_path = $runtime_config['config']; - $this->_global_config_path_debug = 'Using global config from config runtime arg: ' . $config_path; - } else if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { + if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); $this->_global_config_path_debug = 'Using global config from WP_CLI_CONFIG_PATH env var: ' . $config_path; } else { diff --git a/php/config-spec.php b/php/config-spec.php index 84221c0f0..ff6fa851b 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -17,11 +17,6 @@ 'runtime' => '=<url>', ), - 'config' => array( - 'deprecated' => 'Use the WP_CLI_CONFIG_PATH environment variable instead.', - 'runtime' => '=<path>', - ), - 'user' => array( 'runtime' => '=<id|login|email>', 'file' => '<id|login|email>', From b580bbaa7610038a47cc7b2110611b76ab737f31 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 18 May 2016 05:31:18 -0700 Subject: [PATCH 4315/5359] Introduce `WP_CLI_SSH_PRE_CMD` for users to set up env as needed ``` WP_CLI::add_hook( 'before_ssh', function() { if ( $ssh = WP_CLI::get_runner()->config['ssh'] ) { list( $host, $path ) = explode( ':', $ssh ); switch( $host ) { case 'hb': putenv( 'WP_CLI_SSH_PRE_CMD=export PATH=$HOME/bin:$PATH' ); break; } } }); ``` --- php/WP_CLI/Runner.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0b19a3fc8..be27d5661 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -345,14 +345,20 @@ private function run_ssh_command( $ssh ) { $host = substr( $host, 0, $key ); } + WP_CLI::do_hook( 'before_ssh' ); + WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); WP_CLI::debug( 'SSH path: ' . $path, 'bootstrap' ); $is_tty = function_exists( 'posix_isatty' ) && posix_isatty( STDOUT ); + $pre_cmd = getenv( 'WP_CLI_SSH_PRE_CMD' ); + if ( $pre_cmd ) { + $pre_cmd = rtrim( $pre_cmd, ';' ) . '; '; + } $wp_binary = 'wp'; $wp_args = array_slice( $GLOBALS['argv'], 1 ); - $wp_path = $path ? sprintf( '--path=%s', $path ) : ''; + $wp_path = $path ? sprintf( '--path=%s', str_replace( '~', '$HOME', $path ) ) : ''; foreach( $wp_args as $k => $v ) { if ( preg_match( '#--ssh=#', $v ) ) { unset( $wp_args[ $k ] ); @@ -362,9 +368,11 @@ private function run_ssh_command( $ssh ) { 'ssh -q %s %s %s', escapeshellarg( $host ), $is_tty ? '-t' : '-T', - escapeshellarg( $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', $wp_args ) ) + escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', $wp_args ) ) ); + WP_CLI::debug( 'Running SSH command: ' . $command, 'bootstrap' ); + passthru( $command, $exit_code ); if ( 0 !== $exit_code ) { exit( $exit_code ); From 7c25f31f790bd512c6f8005a06a991ff2f2fc894 Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Wed, 18 May 2016 15:14:56 +0100 Subject: [PATCH 4316/5359] wp-cli/wp-cli#2760 Update readme with new format and fresh content --- README.md | 103 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index daf127aa0..9add684c7 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,89 @@ -WP-CLI -====== +# WP-CLI + +Command-line tools for managing WordPress installations. [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) -WP-CLI is a set of command-line tools for managing WordPress installations. +[Documentation](http://wp-cli.org/) + +Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) + +## Using + +This project aims to provide command-line support for any action you can perform in the WordPress admin and many you can't. So you can [install a plugin](http://wp-cli.org/commands/plugin/install/): + +` +$ wp plugin install rest-api +` + +And [activate it](http://wp-cli.org/commands/plugin/activate/): + +` +$ wp plugin activate rest-api +` + +View the [Quick Start](http://wp-cli.org/docs/quick-start/) guide or jump to the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. + +## Installing + +The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. + +Download the `[wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar)` using `wget` or `curl`. For example: + +`$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar` + +Check if it is working: + +`$ php wp-cli.phar --info` + +To use it from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: + +` +$ chmod +x wp-cli.phar +$ sudo mv wp-cli.phar /usr/local/bin/wp +` -Installing ------------- -If you just want to use WP-CLI, see <http://wp-cli.org/#install>. +If WP-CLI installed successfully, you should see something like this when you run `wp --info`: -If you want to hack on WP-CLI, see [CONTRIBUTING.md](CONTRIBUTING.md). +` +$ wp --info +PHP binary: /usr/bin/php5 +PHP version: 5.5.9-1ubuntu4.14 +php.ini used: /etc/php5/cli/php.ini +WP-CLI root dir: /home/wp-cli/.wp-cli +WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ +WP-CLI global config: /home/wp-cli/.wp-cli/config.yml +WP-CLI project config: +WP-CLI version: 0.23.0 +` -Where can I get more info? --------------------------- -For documentation and examples, check out [wp-cli.org](http://wp-cli.org/) and the [documentation portal](http://wp-cli.org/docs/). +Now that you've got WP-CLI, read the [Quick Start](http://wp-cli.org/docs/quick-start/) guide. Or view the [full installation guide](http://wp-cli.org/docs/installing/) with alternative installation methods. -Also, WordPress Answers has a growing list of [WP-CLI related questions](http://wordpress.stackexchange.com/questions/tagged/wp-cli). +## Support -If you want to receive an email for every single commit, you can subscribe to the [wp-cli-commits](https://groups.google.com/forum/?fromgroups=#!forum/wp-cli-commits) mailing list. +WP-CLI is a volunteer-led project and can't support every user individually. If you run into trouble, here are some places to look for help: -I'm running into troubles, what can I do? ------------------------------------------ -To suggest a feature, report a bug, or general discussion, visit the [issues section](https://github.com/wp-cli/wp-cli/issues). +- [Common issues and their fixes](http://wp-cli.org/docs/common-issues/) +- [Bug reports](http://wp-cli.org/docs/bug-reports/) +- [External resources](http://wp-cli.org/docs/external-resources/) -If you're reporting a bug, please include the output from `wp --info` and do your best to follow [bug reporting best practices](http://wp-cli.org/docs/bug-reports/). +## Extending + +Creating a custom WP-CLI command can be easier than it looks. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/). + +## Contributing + +Thanks for helping to improve WP-CLI. Please read about [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). + +### Contributors +* [Andreas Creten](https://github.com/andreascreten) - founder +* [Cristi Burcă](https://github.com/scribu) - previous maintainer +* [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer + +Read more about the project's [Governance](http://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). + +## Credits -Credits -------- Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: * [Drush](http://drush.ws/) for... a lot of things @@ -36,13 +93,3 @@ Besides the libraries defined in [composer.json](composer.json), we have used co * [WordPress-CLI-Exporter](https://github.com/Automattic/WordPress-CLI-Exporter) for `wp export` * [WordPress-CLI-Importer](https://github.com/Automattic/WordPress-CLI-Importer) for `wp import` * [wordpress-plugin-tests](https://github.com/benbalter/wordpress-plugin-tests/) for `wp scaffold plugin-tests` - -Who's behind this thing? ------------------------- -* [Andreas Creten](https://github.com/andreascreten) - founder -* [Cristi Burcă](https://github.com/scribu) - previous maintainer -* [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer - -For more info, see [Governance](http://wp-cli.org/docs/governance/). - -A complete list of contributors can be found [here](https://github.com/wp-cli/wp-cli/contributors). From 3a84c919afda48d0d3695db0bc647e3538f6839a Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Wed, 18 May 2016 15:18:41 +0100 Subject: [PATCH 4317/5359] wp-cli/wp-cli#2760 Mimic GitHub descriptions in docs link at the top of README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 9add684c7..3f3bacd6d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ # WP-CLI -Command-line tools for managing WordPress installations. +Command-line tools for managing WordPress installations. [http://wp-cli.org/](http://wp-cli.org/). [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) -[Documentation](http://wp-cli.org/) - Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) ## Using From 58ffdd38b9bb578a27d2047d60c8ee0fa9aa39b7 Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Wed, 18 May 2016 15:19:39 +0100 Subject: [PATCH 4318/5359] wp-cli/wp-cli#2760 Add credits to quick links in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f3bacd6d..3c16bc283 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Command-line tools for managing WordPress installations. [http://wp-cli.org/](ht [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) -Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) +Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) ## Using From 6f2e2d32778035857433d64f691580989be8d03f Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Wed, 18 May 2016 15:21:05 +0100 Subject: [PATCH 4319/5359] wp-cli/wp-cli#2760 Links can't be in code --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c16bc283..aed43a805 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ View the [Quick Start](http://wp-cli.org/docs/quick-start/) guide or jump to the The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. -Download the `[wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar)` using `wget` or `curl`. For example: +Download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) using `wget` or `curl`. For example: `$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar` From a266317f09e04fb606efdfba75fce12477186bc4 Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Wed, 18 May 2016 15:22:40 +0100 Subject: [PATCH 4320/5359] wp-cli/wp-cli#2760 Use triple ticks for code blocks --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index aed43a805..b5395b045 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,15 @@ Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | This project aims to provide command-line support for any action you can perform in the WordPress admin and many you can't. So you can [install a plugin](http://wp-cli.org/commands/plugin/install/): -` +``` $ wp plugin install rest-api -` +``` And [activate it](http://wp-cli.org/commands/plugin/activate/): -` +``` $ wp plugin activate rest-api -` +``` View the [Quick Start](http://wp-cli.org/docs/quick-start/) guide or jump to the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. @@ -28,22 +28,26 @@ The recommended way to install WP-CLI is to download the Phar build, mark it exe Download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) using `wget` or `curl`. For example: -`$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar` +``` +$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar +``` Check if it is working: -`$ php wp-cli.phar --info` +``` +$ php wp-cli.phar --info +``` To use it from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: -` +``` $ chmod +x wp-cli.phar $ sudo mv wp-cli.phar /usr/local/bin/wp -` +``` If WP-CLI installed successfully, you should see something like this when you run `wp --info`: -` +``` $ wp --info PHP binary: /usr/bin/php5 PHP version: 5.5.9-1ubuntu4.14 @@ -53,7 +57,7 @@ WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ WP-CLI global config: /home/wp-cli/.wp-cli/config.yml WP-CLI project config: WP-CLI version: 0.23.0 -` +``` Now that you've got WP-CLI, read the [Quick Start](http://wp-cli.org/docs/quick-start/) guide. Or view the [full installation guide](http://wp-cli.org/docs/installing/) with alternative installation methods. From f7cb087d32a0408806591da800ef928bf9be87b5 Mon Sep 17 00:00:00 2001 From: Patrick <phh@peytz.dk> Date: Wed, 18 May 2016 20:35:07 +0200 Subject: [PATCH 4321/5359] Update search-replace.php --- php/commands/search-replace.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 7ab5f5173..89d330624 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -91,6 +91,13 @@ class Search_Replace_Command extends WP_CLI_Command { * * # Search/replace to a SQL file without transforming the database * wp search-replace foo bar --export=database.sql + * + * # Search/replace production to development url (multisite compatible) + * if $(wp --url=http://example.com core is-installed --network); then + * wp search-replace --url=http://example.com 'http://example.com' 'http://example.dev' --recurse-objects --network --skip-columns=guid + * else + * wp search-replace 'http://example.com' 'http://example.dev' --recurse-objects --skip-columns=guid + * fi */ public function __invoke( $args, $assoc_args ) { global $wpdb; From 97667d970919c34db48c1486489666423e14f3e4 Mon Sep 17 00:00:00 2001 From: Patrick <phh@peytz.dk> Date: Wed, 18 May 2016 20:56:58 +0200 Subject: [PATCH 4322/5359] Update db.php --- php/commands/db.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/db.php b/php/commands/db.php index 1d1900b44..ef87f2b17 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -52,6 +52,10 @@ public function drop( $_, $assoc_args ) { * * [--yes] * : Answer yes to the confirmation message. + * + * ## EXAMPLES + * + * wp db reset --yes */ public function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); From 1195f8caf1d233e112d52db2a1d6e11f6d96fc15 Mon Sep 17 00:00:00 2001 From: Patrick <phh@peytz.dk> Date: Wed, 18 May 2016 21:14:52 +0200 Subject: [PATCH 4323/5359] Update db.php Output feedback message and add example for `wp db drop --yes` --- php/commands/db.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index ef87f2b17..6c87dcb24 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -32,6 +32,11 @@ public function create( $_, $assoc_args ) { * * [--yes] * : Answer yes to the confirmation message. + * + * ## EXAMPLES + * + * $ wp db drop --yes + * Success: Database dropped. */ public function drop( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); @@ -55,7 +60,8 @@ public function drop( $_, $assoc_args ) { * * ## EXAMPLES * - * wp db reset --yes + * $ wp db reset --yes + * Success: Database reset. */ public function reset( $_, $assoc_args ) { WP_CLI::confirm( "Are you sure you want to reset the database?", $assoc_args ); From ab6f75e7e768a2b21d8de0ec11e159942ea1ebfb Mon Sep 17 00:00:00 2001 From: Patrick <phh@peytz.dk> Date: Wed, 18 May 2016 21:43:58 +0200 Subject: [PATCH 4324/5359] Update search-replace.php Documentation: Tell that this is a bash script --- php/commands/search-replace.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 89d330624..ca07963d6 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -92,7 +92,8 @@ class Search_Replace_Command extends WP_CLI_Command { * # Search/replace to a SQL file without transforming the database * wp search-replace foo bar --export=database.sql * - * # Search/replace production to development url (multisite compatible) + * # Bash script: Search/replace production to development url (multisite compatible) + * #!/bin/bash * if $(wp --url=http://example.com core is-installed --network); then * wp search-replace --url=http://example.com 'http://example.com' 'http://example.dev' --recurse-objects --network --skip-columns=guid * else From aebd05781000e53b89376f800e9fc8129ca71a03 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 18 May 2016 13:40:55 -0700 Subject: [PATCH 4325/5359] Only display packages directory path when it exists This is more consistent with the other parameters displayed --- php/commands/cli.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 4446d5f80..be6d1bd61 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -49,13 +49,17 @@ public function info( $_, $assoc_args ) { $runner = WP_CLI::get_runner(); + $packages_dir = $runner->get_packages_dir_path(); + if ( ! is_dir( $packages_dir ) ) { + $packages_dir = null; + } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { $info = array( 'php_binary_path' => $php_bin, 'global_config_path' => $runner->global_config_path, 'project_config_path' => $runner->project_config_path, 'wp_cli_dir_path' => WP_CLI_ROOT, - 'wp_cli_packages_dir_path' => $runner->get_packages_dir_path(), + 'wp_cli_packages_dir_path' => $packages_dir, 'wp_cli_version' => WP_CLI_VERSION, ); @@ -65,7 +69,7 @@ public function info( $_, $assoc_args ) { WP_CLI::line( "PHP version:\t" . PHP_VERSION ); WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); WP_CLI::line( "WP-CLI root dir:\t" . WP_CLI_ROOT ); - WP_CLI::line( "WP-CLI packages dir:\t" . $runner->get_packages_dir_path() ); + WP_CLI::line( "WP-CLI packages dir:\t" . $packages_dir ); WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); From 8d7ac8abbee13cf407c300cfbabbbafdeaf9aad8 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 19 May 2016 05:55:12 +0900 Subject: [PATCH 4326/5359] Example: core update --- php/commands/core.php | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..e2d931a39 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1015,11 +1015,30 @@ private static function get_core_checksums( $version, $locale ) { * * ## EXAMPLES * - * wp core update - * - * wp core update --version=3.8 ../latest.zip - * - * wp core update --version=3.1 --force + * $ wp core update + * Updating to version 4.5.2 (en_US)... + * Downloading update from https://downloads.wordpress.org/release/wordpress-4.5.2-no-content.zip... + * Unpacking the update... + * Cleaning up files... + * No files found that need cleaned up + * Success: WordPress updated successfully. + * + * $ wp core update --version=3.8 ../latest.zip + * Updating to version 3.8 ()... + * Unpacking the update... + * Cleaning up files... + * File removed: wp-admin/js/tags-box.js + * ... + * File removed: wp-admin/js/updates.min. + * 377 files cleaned up + * Success: WordPress updated successfully. + * + * $ wp core update --version=3.1 --force + * Updating to version 3.1 (en_US)... + * Downloading update from https://wordpress.org/wordpress-3.1.zip... + * Unpacking the update... + * Warning: Failed to fetch checksums. Please cleanup files manually. + * Success: WordPress updated successfully. * * @alias upgrade */ From 9a63893cce9df98eb78fdddabd6343cd6780456a Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 19 May 2016 06:13:14 +0900 Subject: [PATCH 4327/5359] Example: core update-db --- php/commands/core.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..e9e16c48e 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1146,6 +1146,15 @@ function update( $args, $assoc_args ) { * [--dry-run] * : Compare database versions without performing the update. * + * ## EXAMPLES + * + * $ wp core update-db + * Success: WordPress database upgraded successfully from db version 36686 to 35700 + * + * $ wp core update-db --network + * WordPress database upgraded successfully from db version 35700 to 29630 on example.com/ + * Success: WordPress database upgraded on 123/123 sites + * * @subcommand update-db */ function update_db( $_, $assoc_args ) { From a823c0f1162817190a533ff3baab807dacf6ba61 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 19 May 2016 06:24:50 +0900 Subject: [PATCH 4328/5359] Example: core verify-checksums --- php/commands/core.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..529d7f008 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -812,6 +812,17 @@ public function version( $args = array(), $assoc_args = array() ) { * [--locale=<locale>] * : Verify checksums against a specific locale of WordPress. * + * ## EXAMPLES + * + * $ wp core verify-checksums + * Success: WordPress install verifies against checksums. + * + * $ wp core verify-checksums --version=4.0 + * Success: WordPress install verifies against checksums. + * + * $ wp core verify-checksums --locale=en_US + * Success: WordPress install verifies against checksums. + * * @when before_wp_load * * @subcommand verify-checksums From 390c273b0323864b0b16723282c0e80426813551 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 19 May 2016 06:42:26 +0900 Subject: [PATCH 4329/5359] Example: core version --- php/commands/core.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..f78be570a 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -772,6 +772,16 @@ private static function get_clean_basedomain() { * [--extra] * : Show extended version information. * + * ## EXAMPLES + * + * $ wp core version + * 4.5.2 + * + * $ wp core version --extra + * WordPress version: 4.5.2 + * Database revision: 36686 + * TinyMCE version: 4.310 (4310-20160418) + * * @when before_wp_load */ public function version( $args = array(), $assoc_args = array() ) { From 2efbc78866b08b45b9185c217e00fd61fd0dec56 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 18 May 2016 15:16:15 -0700 Subject: [PATCH 4330/5359] Update tests for aebd05781000e53b89376f800e9fc8129ca71a03 --- features/cli-info.feature | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/features/cli-info.feature b/features/cli-info.feature index 7d3fef346..e5911b1d5 100644 --- a/features/cli-info.feature +++ b/features/cli-info.feature @@ -6,11 +6,14 @@ Feature: Review CLI information When I run `wp cli info --format=json` Then STDOUT should be JSON containing: """ - {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} + {"wp_cli_packages_dir_path":null} """ - When I run `WP_CLI_PACKAGES_DIR=/tmp/packages wp cli info --format=json` + When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` + Then STDERR should be empty + + When I run `wp cli info --format=json` Then STDOUT should be JSON containing: """ - {"wp_cli_packages_dir_path":"/tmp/packages/"} + {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} """ From 5ec67432ef721c3a2e57a8cc5f73fea4864f700a Mon Sep 17 00:00:00 2001 From: Ville Vuorenmaa <villevuor@gmail.com> Date: Thu, 19 May 2016 09:56:40 +0300 Subject: [PATCH 4331/5359] Added some comments --- php/commands/search-replace.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index b6f285a1c..3403c7814 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -371,19 +371,25 @@ function ( $field ) { $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; $values = array_merge( $values, array_values( $row_fields ) ); + // Add new insert statement if needed. Before this we close the previous with semicolon and write statement to sql-file. + // "Statement break" is needed: + // 1. When the loop is running every nth time (where n is insert statement size, $export_index_size). Remainder is zero also on first round, so it have to be excluded. + // $index % $export_insert_size == 0 && $index > 0 + // 2. Or when the loop is running last time + // $index == $count if( ( $index % $export_insert_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); - + + // If there is still rows to loop, reset $sql and $values variables. if( $count > $index ) { $sql = $insert; $values = array(); } - } else { + } else { // Otherwise just add comma and new line $sql .= ",\n"; - } $index++; From 1c205a8f170cfdfddcd80ab86e01765eb6ba4c01 Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Thu, 19 May 2016 09:04:07 +0100 Subject: [PATCH 4332/5359] wp-cli/wp-cli#2760 Updates based on feedback. - Basic language and formatting adjustments - Adjust demonstration examples in Usage - Added summary of a command to Extending - Rename Contributors to Leadership - Added minimum requirements - Indicated support was available --- README.md | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b5395b045..67f8b8d9a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# WP-CLI +WP-CLI +====== -Command-line tools for managing WordPress installations. [http://wp-cli.org/](http://wp-cli.org/). +[WP-CLI](http://wp-cli.org/) is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser. [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) @@ -8,24 +9,40 @@ Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | ## Using -This project aims to provide command-line support for any action you can perform in the WordPress admin and many you can't. So you can [install a plugin](http://wp-cli.org/commands/plugin/install/): +The goal of WP-CLI is to provide a command-line interface for any action you can perform in the WordPress admin. The project also includes commands for many actions you can't perform in the WordPress admin. + +For instance, `wp plugin install` ([doc](http://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: ``` -$ wp plugin install rest-api +$ wp plugin install rest-api --activate +Installing WordPress REST API (Version 2) (2.0-beta13) +Downloading install package from https://downloads.wordpress.org/plugin/rest-api.2.0-beta13.zip... +Unpacking the package... +Installing the plugin... +Plugin installed successfully. +Activating 'rest-api'... +Success: Plugin 'rest-api' activated. ``` -And [activate it](http://wp-cli.org/commands/plugin/activate/): +`wp transient` ([doc](http://wp-cli.org/commands/transient/)) lets you delete one or all transients: ``` -$ wp plugin activate rest-api +$ wp transient delete-all +Success: 34 transients deleted from the database. ``` -View the [Quick Start](http://wp-cli.org/docs/quick-start/) guide or jump to the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. +For a complete introduction, the [Quick Start guide](http://wp-cli.org/docs/quick-start/). If you already feel comfortable with the basics, jump into the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. ## Installing The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. +Before you install though, please make sure your environment meets the minimum requirements: + +- UNIX-like environment (OS X, Linux, FreeBSD, Cygwin); limited support in Windows environment +- PHP 5.3.29 or later +- WordPress 3.7 or later + Download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) using `wget` or `curl`. For example: ``` @@ -63,21 +80,23 @@ Now that you've got WP-CLI, read the [Quick Start](http://wp-cli.org/docs/quick- ## Support -WP-CLI is a volunteer-led project and can't support every user individually. If you run into trouble, here are some places to look for help: +WP-CLI's project maintainers do their best to respond to all bug reports and configuration errors within reason and the constraints on their time. Before requesting help, please read to find a solution to your problem in the following resources: - [Common issues and their fixes](http://wp-cli.org/docs/common-issues/) -- [Bug reports](http://wp-cli.org/docs/bug-reports/) +- [Submit a bug report](http://wp-cli.org/docs/bug-reports/) - [External resources](http://wp-cli.org/docs/external-resources/) ## Extending -Creating a custom WP-CLI command can be easier than it looks. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/). +A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](http://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](http://wp-cli.org/commands/plugin/activate/)) is another. + +WP-CLI comes with dozens of commands. But it's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/) to learn more. ## Contributing Thanks for helping to improve WP-CLI. Please read about [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). -### Contributors +### Leadership * [Andreas Creten](https://github.com/andreascreten) - founder * [Cristi Burcă](https://github.com/scribu) - previous maintainer * [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer From 744fc7c34a1b9ab9ca325873e5aeb7559ca9185e Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Thu, 19 May 2016 09:07:29 +0100 Subject: [PATCH 4333/5359] wp-cli/wp-cli#2760 Add missing word in sentence --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 67f8b8d9a..f0c1ecc5e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ $ wp transient delete-all Success: 34 transients deleted from the database. ``` -For a complete introduction, the [Quick Start guide](http://wp-cli.org/docs/quick-start/). If you already feel comfortable with the basics, jump into the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. +For a complete introduction, read the [Quick Start guide](http://wp-cli.org/docs/quick-start/). If you already feel comfortable with the basics, jump into the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. ## Installing From e063b0d794397551f47fd2a3f0139bc634b82dfb Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 19 May 2016 23:33:31 +0900 Subject: [PATCH 4334/5359] add example of error --- php/commands/core.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 529d7f008..32ea90d10 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -823,6 +823,12 @@ public function version( $args = array(), $assoc_args = array() ) { * $ wp core verify-checksums --locale=en_US * Success: WordPress install verifies against checksums. * + * $ wp core verify-checksums --locale=ja + * Warning: File doesn't verify against checksum: wp-includes/version.php + * Warning: File doesn't verify against checksum: readme.html + * Warning: File doesn't verify against checksum: wp-config-sample.php + * Error: WordPress install doesn't verify against checksums. + * * @when before_wp_load * * @subcommand verify-checksums From e8f1039c39b117bbb2cead089f346e01dcf4561f Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 20 May 2016 00:12:47 +0900 Subject: [PATCH 4335/5359] Example: core multisite-convert --- php/commands/core.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..b27ad6337 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -472,6 +472,13 @@ public function install( $args, $assoc_args ) { * [--subdomains] * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. * + * ## EXAMPLES + * + * $ wp core multisite-convert + * Set up multisite database tables. + * Added multisite constants to wp-config.php. + * Success: Network installed. Don't forget to set up rewrite rules. + * * @subcommand multisite-convert * @alias install-network */ From 4ad1b14c1e42290cc0cbd4e8136041de41bb74bd Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 20 May 2016 00:25:10 +0900 Subject: [PATCH 4336/5359] Example: core multisite-install --- php/commands/core.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 4e23f1509..f0ddcb9d3 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -519,6 +519,16 @@ public function multisite_convert( $args, $assoc_args ) { * [--skip-email] * : Don't send an email notification to the new admin user. * + * ## EXAMPLES + * + * $ wp core multisite-install --title="Welcome to the WordPress" \ + * > --admin_user="admin" --admin_password="password" \ + * > --admin_email="user@example.com" + * Single site database tables already present. + * Set up multisite database tables. + * Added multisite constants to wp-config.php. + * Success: Network installed. Don't forget to set up rewrite rules. + * * @subcommand multisite-install */ public function multisite_install( $args, $assoc_args ) { From 818cbe49b8b3b58bbd8e2bfa657b12b87873a286 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 15:53:17 +0000 Subject: [PATCH 4337/5359] Example: plugin list #2769 --- php/commands/plugin.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..a70003147 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -639,10 +639,24 @@ function delete( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * wp plugin list --status=active --format=json + * $ wp plugin list --status=active --format=json + * [{"name":"dynamic-hostname","status":"active","update":"none","version":"0.4.2"},{"name":"tinymce-templates","status":"active","update":"none","version":"4.4.3"},{"name":"wp-multibyte-patch","status":"active","update":"none","version":"2.4"},{"name":"wp-total-hacks","status":"active","update":"none","version":"2.0.1"}] * * # List plugins on each site in a network - * wp site list --field=url | xargs -n 1 -I % wp plugin list --url=% + * $ wp site list --field=url | xargs -n 1 -I % wp plugin list --url=% + * +------------------------------+----------------+-----------+------------+ + * | name | status | update | version | + * +------------------------------+----------------+-----------+------------+ + * | akismet | active-network | none | 3.1.11 | + * | hello | inactive | none | 1.6 | + * +------------------------------+----------------+-----------+------------+ + * +------------------------------+----------------+-----------+------------+ + * | name | status | update | version | + * +------------------------------+----------------+-----------+------------+ + * | akismet | active-network | none | 3.1.11 | + * | hello | inactive | none | 1.6 | + * +------------------------------+----------------+-----------+------------+ + * * * @subcommand list */ From 5b9954e7e10f1039b1e753daaa6c23656ada8845 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 15:58:21 +0000 Subject: [PATCH 4338/5359] Example: plugin delete #2770 --- php/commands/plugin.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..32994bf61 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -590,10 +590,12 @@ function is_installed( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * wp plugin delete hello + * $ wp plugin delete hello + * Success: Deleted 'hello' plugin. * * # Delete inactive plugins - * wp plugin delete $(wp plugin list --status=inactive --field=name) + * $ wp plugin delete $(wp plugin list --status=inactive --field=name) + * Success: Deleted 'tinymce-templates' plugin. */ function delete( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { From 58bbdb3972bd97344613d739edb7fc5704ab16cb Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:03:43 +0000 Subject: [PATCH 4339/5359] Example: plugin path #2770 --- php/commands/plugin.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..ed72dfca6 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -301,7 +301,8 @@ function toggle( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * cd $(wp plugin path) + * $ cd $(wp plugin path) && pwd + * /var/www/wordpress/wp-content/plugins */ function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); From 9cab5f53042bfc2ebac86bd576050dc29f30f660 Mon Sep 17 00:00:00 2001 From: Shinichi Nishikawa <shinichi.nishikawa@gmail.com> Date: Fri, 20 May 2016 01:03:44 +0900 Subject: [PATCH 4340/5359] #2769 add example to cli update command document. --- php/commands/cli.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index be6d1bd61..d0b31dd41 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -135,6 +135,14 @@ public function check_update( $_, $assoc_args ) { * * [--yes] * : Do not prompt for confirmation + * + * ## EXAMPLES + * + * $ wp cli update + * You have version 0.23.0. Would you like to update to 0.23.1? [y/n] y + * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar... + * New version works. Proceeding to replace. + * Success: Updated WP-CLI to 0.23.1 */ public function update( $_, $assoc_args ) { if ( ! Utils\inside_phar() ) { From 277eda42f7252543126ed627a00cca2cabef35f4 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:14:14 +0000 Subject: [PATCH 4341/5359] Example: plugin update #2770 --- php/commands/plugin.php | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..e3d067a60 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -366,9 +366,34 @@ protected function install_from_repo( $slug, $assoc_args ) { * * ## EXAMPLES * - * wp plugin update bbpress --version=dev - * - * wp plugin update --all + * $ wp plugin update bbpress --version=dev + * Installing bbPress (Development Version) + * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.zip... + * Unpacking the package... + * Installing the plugin... + * Removing the old version of the plugin... + * Plugin updated successfully. + * + * $ wp plugin update --all + * Enabling Maintenance mode... + * Downloading update from https://downloads.wordpress.org/plugin/akismet.3.1.11.zip... + * Unpacking the update... + * Installing the latest version... + * Removing the old version of the plugin... + * Plugin updated successfully. + * Downloading update from https://downloads.wordpress.org/plugin/nginx-champuru.3.2.0.zip... + * Unpacking the update... + * Installing the latest version... + * Removing the old version of the plugin... + * Plugin updated successfully. + * Disabling Maintenance mode... + * Success: Updated 2/2 plugins. + * +------------------------+-------------+-------------+---------+ + * | name | old_version | new_version | status | + * +------------------------+-------------+-------------+---------+ + * | akismet | 3.1.3 | 3.1.11 | Updated | + * | nginx-cache-controller | 3.1.1 | 3.2.0 | Updated | + * +------------------------+-------------+-------------+---------+ * * @alias upgrade */ From 3984f650372eb1808952ba115e6cb3936c8c23f0 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:17:12 +0000 Subject: [PATCH 4342/5359] Example: plugin get #2770 --- php/commands/plugin.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..06b6502a9 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -488,7 +488,8 @@ function install( $args, $assoc_args ) { * * ## EXAMPLES * - * wp plugin get bbpress --format=json + * $ wp plugin get bbpress --format=json + * {"name":"bbpress","title":"bbPress","author":"The bbPress Contributors","version":"2.6-alpha","description":"bbPress is forum software with a twist from the creators of WordPress.","status":"active"} */ public function get( $args, $assoc_args ) { $plugin = $this->fetcher->get_check( $args[0] ); From 99a08721d56e3df2232c54ce546861303b3c712a Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:20:16 +0000 Subject: [PATCH 4343/5359] Example: plugin uninstall #2770 --- php/commands/plugin.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..96f174106 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -531,7 +531,8 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp plugin uninstall hello + * $ wp plugin uninstall hello + * Success: Uninstalled and deleted 'hello' plugin. */ function uninstall( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { From 99e96cd9cc31f96a88b6cb7406733fdd570ec480 Mon Sep 17 00:00:00 2001 From: Shinichi Nishikawa <shinichi.nishikawa@gmail.com> Date: Fri, 20 May 2016 01:20:50 +0900 Subject: [PATCH 4344/5359] Example: cli version --- php/commands/cli.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index be6d1bd61..ee9407454 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -43,6 +43,11 @@ public function version() { * * [--format=<format>] * : Accepted values: json + * + * ## EXAMPLES + * + * $ wp cli version + * WP-CLI 0.23.1 */ public function info( $_, $assoc_args ) { $php_bin = WP_CLI::get_php_binary(); From 7ca3799aa6870d4bf43f79f7c22c46a256df8ac3 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:38:09 +0000 Subject: [PATCH 4345/5359] Example: plugin search #2770 --- php/commands/plugin.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..d8bd16d41 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -85,9 +85,19 @@ function status( $args ) { * * ## EXAMPLES * - * wp plugin search dsgnwrks --per-page=20 --format=json - * - * wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings + * $ wp plugin search dsgnwrks --per-page=20 --format=json + * Success: Showing 3 of 3 plugins. + * [{"name":"DsgnWrks Instagram Importer Debug","slug":"dsgnwrks-instagram-importer-debug","rating":0},{"name":"DsgnWrks Instagram Importer","slug":"dsgnwrks-instagram-importer","rating":84},{"name":"DsgnWrks Twitter Importer","slug":"dsgnwrks-twitter-importer","rating":80}] + * + * $ wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings + * Success: Showing 3 of 3 plugins. + * +-----------------------------------+---------+-----------------------------------+--------+-------------+ + * | name | version | slug | rating | num_ratings | + * +-----------------------------------+---------+-----------------------------------+--------+-------------+ + * | DsgnWrks Instagram Importer Debug | 0.1.6 | dsgnwrks-instagram-importer-debug | 0 | 0 | + * | DsgnWrks Instagram Importer | 1.3.7 | dsgnwrks-instagram-importer | 84 | 23 | + * | DsgnWrks Twitter Importer | 1.1.1 | dsgnwrks-twitter-importer | 80 | 1 | + * +-----------------------------------+---------+-----------------------------------+--------+-------------+ */ public function search( $args, $assoc_args ) { parent::_search( $args, $assoc_args ); From f86d5b77553987874e78bdd1249f4d43cdd7f735 Mon Sep 17 00:00:00 2001 From: Shinichi Nishikawa <shinichi.nishikawa@gmail.com> Date: Fri, 20 May 2016 01:38:39 +0900 Subject: [PATCH 4346/5359] Example: option get --- php/commands/option.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index 6fd527429..787c1e808 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -28,6 +28,14 @@ class Option_Command extends WP_CLI_Command { * * [--format=<format>] * : Get value as var_export() or JSON. Default: var_export() + * + * ## EXAMPLES + * + * $ wp option get home + * http://example.com + * + * $ wp option get active_plugins --format=json + * {"0":"dynamically-dynamic-sidebar\/dynamically-dynamic-sidebar.php","1":"monster-widget\/monster-widget.php","2":"show-current-template\/show-current-template.php","3":"theme-check\/theme-check.php","5":"wordpress-importer\/wordpress-importer.php"} */ public function get( $args, $assoc_args ) { list( $key ) = $args; From 40379876ec591cadf0061473e0934af869a9a67f Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 19 May 2016 22:24:47 +0545 Subject: [PATCH 4347/5359] add example for transient delete-all command --- php/commands/transient.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index 09d05eb1c..78fad2593 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -133,6 +133,11 @@ public function delete_expired() { /** * Delete all transients. * + * ## EXAMPLES + * + * wp transient delete-all + * Success: 14 transients deleted from the database. + * * @subcommand delete-all */ public function delete_all() { From a8cc9be5941c5805963bafe1af826331b96f2ac3 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 19 May 2016 22:27:14 +0545 Subject: [PATCH 4348/5359] add missing dollar sign in command example --- php/commands/transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 78fad2593..3fc77dba4 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -135,7 +135,7 @@ public function delete_expired() { * * ## EXAMPLES * - * wp transient delete-all + * $ wp transient delete-all * Success: 14 transients deleted from the database. * * @subcommand delete-all From 1fb32b76b362191083366f6c264d11de08601d26 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:42:40 +0000 Subject: [PATCH 4349/5359] add Command Example: plugin toggle #2770 --- php/commands/plugin.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..c44029926 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -273,6 +273,14 @@ function deactivate( $args, $assoc_args = array() ) { * * [--network] * : If set, the plugin will be toggled for the entire multisite network. + * + * ## EXAMPLES + * + * $ wp plugin toggle akismet + * Success: Plugin 'akismet' deactivated. + * + * $ wp plugin toggle akismet + * Success: Plugin 'akismet' activated. */ function toggle( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); From 8f6cfd8685ee4ebf85fea53a5c2ec666b46ec2aa Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 19 May 2016 22:29:33 +0545 Subject: [PATCH 4350/5359] Add example for transient delete-expired --- php/commands/transient.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index 09d05eb1c..31ab2bff9 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -104,6 +104,11 @@ public function type() { /** * Delete all expired transients. * + * ## EXAMPLES + * + * $ wp transient delete-expired + * Success: 12 expired transients deleted from the database. + * * @subcommand delete-expired */ public function delete_expired() { From 3388d39693b0a7969b9389e7b27a9208a74b6d40 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Thu, 19 May 2016 16:50:55 +0000 Subject: [PATCH 4351/5359] Example:plugin install #2770 --- php/commands/plugin.php | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 734e2fec6..c55a5bec9 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -449,16 +449,36 @@ protected function filter_item_list( $items, $args ) { * ## EXAMPLES * * # Install the latest version from wordpress.org and activate - * wp plugin install bbpress --activate + * $ wp plugin install bbpress --activate + * Installing bbPress (2.5.9) + * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.2.5.9.zip... + * Using cached file '/home/vagrant/.wp-cli/cache/plugin/bbpress-2.5.9.zip'... + * Unpacking the package... + * Installing the plugin... + * Plugin installed successfully. + * Activating 'bbpress'... + * Success: Plugin 'bbpress' activated. * * # Install the development version from wordpress.org - * wp plugin install bbpress --version=dev + * $ wp plugin install bbpress --version=dev + * Installing bbPress (Development Version) + * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.zip... + * Unpacking the package... + * Installing the plugin... + * Plugin installed successfully. * * # Install from a local zip file - * wp plugin install ../my-plugin.zip + * $ wp plugin install ../my-plugin.zip + * Unpacking the package... + * Installing the plugin... + * Plugin installed successfully. * * # Install from a remote zip file - * wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * $ wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * Downloading install package from http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * Unpacking the package... + * Installing the plugin... + * Plugin installed successfully. */ function install( $args, $assoc_args ) { From f89a55bb27415ac88efa373050bf8468a489eb5a Mon Sep 17 00:00:00 2001 From: Shinichi Nishikawa <shinichi.nishikawa@gmail.com> Date: Fri, 20 May 2016 01:55:13 +0900 Subject: [PATCH 4352/5359] Example: taxonomy get --- php/commands/taxonomy.php | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index addfb8c32..3579ebbf6 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -99,7 +99,38 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp taxonomy get post_tag --format=json + * $ wp taxonomy get category + * +---------------+---------------------------------------------------+ + * | Field | Value | + * +---------------+---------------------------------------------------+ + * | name | category | + * | label | Categories | + * | description | | + * | object_type | ["post"] | + * | show_tagcloud | true | + * | hierarchical | true | + * | public | true | + * | labels | {"name":"Categories","singular_name":"Category"," | + * | | search_items":"Search Categories","popular_items" | + * | | :null,"all_items":"All Categories","parent_item": | + * | | "Parent Category","parent_item_colon":"Parent Cat | + * | | egory:","edit_item":"Edit Category","view_item":" | + * | | View Category","update_item":"Update Category","a | + * | | dd_new_item":"Add New Category","new_item_name":" | + * | | New Category Name","separate_items_with_commas":n | + * | | ull,"add_or_remove_items":null,"choose_from_most_ | + * | | used":null,"not_found":"No categories found.","no | + * | | _terms":"No categories","items_list_navigation":" | + * | | Categories list navigation","items_list":"Categor | + * | | ies list","menu_name":"Categories","name_admin_ba | + * | | r":"category"} | + * | cap | {"manage_terms":"manage_categories","edit_terms": | + * | | "manage_categories","delete_terms":"manage_catego | + * | | ries","assign_terms":"edit_posts"} | + * +---------------+---------------------------------------------------+ + * + * $ wp taxonomy get post_tag --field=cap + * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} */ public function get( $args, $assoc_args ) { $taxonomy = get_taxonomy( $args[0] ); From a30d40fba4df4f8fe17e75919df7b19e828dac89 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 20 May 2016 14:45:10 +0545 Subject: [PATCH 4353/5359] bail early in theme command if theme is broken or has error --- php/commands/theme.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..45ca6ea00 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -127,6 +127,12 @@ protected function get_status( $theme ) { public function activate( $args = array() ) { $theme = $this->fetcher->get_check( $args[0] ); + $errors = $theme->errors(); + if ( is_wp_error( $errors ) ) { + $message = $errors->get_error_message(); + WP_CLI::error( $message ); + } + $name = $theme->get('Name'); if ( 'active' === $this->get_status( $theme ) ) { @@ -420,6 +426,12 @@ function install( $args, $assoc_args ) { public function get( $args, $assoc_args ) { $theme = $this->fetcher->get_check( $args[0] ); + $errors = $theme->errors(); + if ( is_wp_error( $errors ) ) { + $message = $errors->get_error_message(); + WP_CLI::error( $message ); + } + // WP_Theme object employs magic getter, unfortunately $theme_vars = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', ); From 89e4a1bf8ba9da7cee2702a833fff194a02d508c Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 20 May 2016 22:05:31 +0545 Subject: [PATCH 4354/5359] add example for transient type command --- php/commands/transient.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index f41919170..6bbc32820 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -89,6 +89,11 @@ public function delete( $args, $assoc_args ) { /** * See whether the transients API is using an object cache or the options table. + * + * ## EXAMPLES + * + * $ wp transient type + * Transients are saved to the wp_options table. */ public function type() { global $_wp_using_ext_object_cache, $wpdb; From ecc58f2fe6233b633f1ea6df2bee930651704e46 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 20 May 2016 22:18:38 +0545 Subject: [PATCH 4355/5359] Add example for transient set command --- php/commands/transient.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index f41919170..44612e810 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -49,6 +49,11 @@ public function get( $args, $assoc_args ) { * * [--network] * : Set the transient value on the network, instead of single site. + * + * ## EXAMPLES + * + * $ wp transient set sample_key "test data" 3600 + * Success: Transient added. */ public function set( $args, $assoc_args ) { list( $key, $value ) = $args; From 2ebe89e5797a8516c5fa9cf39d5dc34bb98c067f Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 20 May 2016 22:25:20 +0545 Subject: [PATCH 4356/5359] Add example for transient get command --- php/commands/transient.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index f41919170..6174baeb6 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -20,6 +20,15 @@ class Transient_Command extends WP_CLI_Command { * * [--network] * : Get the value of the network transient, instead of the single site. + * + * ## EXAMPLES + * + * $ wp transient get sample_key + * test data + * + * $ wp transient get random_key + * Warning: Transient with key "random_key" is not set. + * */ public function get( $args, $assoc_args ) { list( $key ) = $args; From 147793d2e68906fa0ec7de696f82dc5c0657f9d5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 21 May 2016 21:00:17 +0545 Subject: [PATCH 4357/5359] fix doc in transient get command --- php/commands/transient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 6deb8c357..c19de7b6c 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -15,8 +15,8 @@ class Transient_Command extends WP_CLI_Command { * <key> * : Key for the transient. * - * [--json] - * : Format output as JSON. + * [--format=<format>] + * : Accepted values: table, json, csv, yaml. Default: table * * [--network] * : Get the value of the network transient, instead of the single site. From 2941fbe5fb94d09164f99a4dce43851a48d61805 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 21 May 2016 22:01:41 +0545 Subject: [PATCH 4358/5359] fix error message in theme activate scenario as message for broken theme is changed --- features/theme.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index 505062fc2..f6e2cb14c 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -236,7 +236,7 @@ Feature: Manage WordPress themes When I try `wp theme activate biker` Then STDERR should contain: """ - Error: The 'biker' theme cannot be activated without its parent, 'jolene'. + Error: The parent theme is missing. Please install the "jolene" parent theme. """ Scenario: List an active theme with its parent From ac00c9783e2424ecdf06f7b830c5bb542a31b9c9 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 21 May 2016 22:11:02 +0545 Subject: [PATCH 4359/5359] add scenario for add error message in theme get and theme activate --- features/theme.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index f6e2cb14c..6704bf24a 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -129,6 +129,22 @@ Feature: Manage WordPress themes | name | status | | p2 | active | + Scenario: Attempt to activate or fetch a broken theme + Given a WP install + And I run `mkdir -pv wp-content/themes/just-test-theme` + + When I try `wp theme activate just-test-theme` + Then STDERR should contain: + """ + Error: Stylesheet is missing. + """ + + When I try `wp theme get just-test-theme` + Then STDERR should contain: + """ + Error: Stylesheet is missing. + """ + Scenario: Enabling and disabling a theme Given a WP multisite install And I run `wp theme install jolene` From 257a708e314909e523d390731e5c772d17bd2842 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 21 May 2016 22:22:19 +0545 Subject: [PATCH 4360/5359] Example: transient delete --- php/commands/transient.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/transient.php b/php/commands/transient.php index 6deb8c357..44f8a8bbe 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -85,6 +85,11 @@ public function set( $args, $assoc_args ) { * * [--network] * : Delete the value of a network transient, instead of that on a single site. + * + * ## EXAMPLES + * + * $ wp transient delete sample_key + * Success: Transient deleted. */ public function delete( $args, $assoc_args ) { list( $key ) = $args; From 278ef5b9068bee74f38cf8b4d38190b4e7d28b53 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Sun, 22 May 2016 00:12:35 +0000 Subject: [PATCH 4361/5359] add one more space #2791 --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index d8bd16d41..26edd1318 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -87,7 +87,7 @@ function status( $args ) { * * $ wp plugin search dsgnwrks --per-page=20 --format=json * Success: Showing 3 of 3 plugins. - * [{"name":"DsgnWrks Instagram Importer Debug","slug":"dsgnwrks-instagram-importer-debug","rating":0},{"name":"DsgnWrks Instagram Importer","slug":"dsgnwrks-instagram-importer","rating":84},{"name":"DsgnWrks Twitter Importer","slug":"dsgnwrks-twitter-importer","rating":80}] + * [{"name":"DsgnWrks Instagram Importer Debug","slug":"dsgnwrks-instagram-importer-debug","rating":0},{"name":"DsgnWrks Instagram Importer","slug":"dsgnwrks-instagram-importer","rating":84},{"name":"DsgnWrks Twitter Importer","slug":"dsgnwrks-twitter-importer","rating":80}] * * $ wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings * Success: Showing 3 of 3 plugins. From af66de2cbc956ba32636b2f1138df14ac219ce16 Mon Sep 17 00:00:00 2001 From: Hidetaka Okamoto <kokkoku214@gmail.com> Date: Sun, 22 May 2016 09:17:40 +0900 Subject: [PATCH 4362/5359] fix Example indent #2794 --- php/commands/plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c44029926..b5bcdf2d7 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -277,10 +277,10 @@ function deactivate( $args, $assoc_args = array() ) { * ## EXAMPLES * * $ wp plugin toggle akismet - * Success: Plugin 'akismet' deactivated. + * Success: Plugin 'akismet' deactivated. * - * $ wp plugin toggle akismet - * Success: Plugin 'akismet' activated. + * $ wp plugin toggle akismet + * Success: Plugin 'akismet' activated. */ function toggle( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); From 0c4da059b907c3413c0a2032f150077286dfdabb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 10:20:18 +0545 Subject: [PATCH 4363/5359] Example: sidebar list --- php/commands/sidebar.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 53cb9c3ac..6f52022cf 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -40,7 +40,10 @@ class Sidebar_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp sidebar list --fields=name,id --format=csv + * $ wp sidebar list --fields=name,id --format=csv + * name,id + * "Widget Area",sidebar-1 + * "Inactive Widgets",wp_inactive_widgets * * @subcommand list */ From 6f8749fac2a0f5889717944633ec8199c5fa2e59 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 14:27:44 +0545 Subject: [PATCH 4364/5359] Example: theme status --- php/commands/theme.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..25123a07e 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -38,6 +38,15 @@ protected function get_upgrader_class( $force ) { * * [<theme>] * : A particular theme to show the status for. + * + * ## EXAMPLES + * + * $ wp theme status twentysixteen + * Theme twentysixteen details: + * Name: Twenty Sixteen + * Status: Inactive + * Version: 1.2 + * Author: the WordPress team */ function status( $args ) { parent::status( $args ); From ac3a58e5dad5515d5f4226eb296aef79767b4f6a Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 14:38:35 +0545 Subject: [PATCH 4365/5359] Example: theme search --- php/commands/theme.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..43e19abd4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -76,9 +76,18 @@ function status( $args ) { * * ## EXAMPLES * - * wp theme search automattic --per-page=20 - * - * wp theme search automattic --fields=name,version,slug,rating,num_ratings,description + * $ wp theme search photo --per-page=6 + * Success: Showing 6 of 203 themes. + * +----------------------+----------------------+--------+ + * | name | slug | rating | + * +----------------------+----------------------+--------+ + * | Photos | photos | 100 | + * | Infinite Photography | infinite-photography | 100 | + * | PhotoBook | photobook | 100 | + * | BG Photo Frame | bg-photo-frame | 0 | + * | fPhotography | fphotography | 0 | + * | Photo Perfect | photo-perfect | 98 | + * +----------------------+----------------------+--------+ */ public function search( $args, $assoc_args ) { parent::_search( $args, $assoc_args ); From 4579ba57b2be57a523d9fdca4cfb3694429824a5 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 14:42:55 +0545 Subject: [PATCH 4366/5359] Example: theme activate --- php/commands/theme.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..fb57f7e95 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -123,6 +123,11 @@ protected function get_status( $theme ) { * * <theme> * : The theme to activate. + * + * ## EXAMPLES + * + * $ wp theme activate twentysixteen + * Success: Switched to 'Twenty Sixteen' theme. */ public function activate( $args = array() ) { $theme = $this->fetcher->get_check( $args[0] ); From b83159cd9ef0719fcc8c9e72bcfaa092a0d98ae1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 14:52:34 +0545 Subject: [PATCH 4367/5359] Example: theme get --- php/commands/theme.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..7e5cca7a7 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -415,7 +415,14 @@ function install( $args, $assoc_args ) { * * ## EXAMPLES * - * wp theme get twentytwelve --format=json + * $ wp theme get twentysixteen --fields=name,title,version + * +---------+----------------+ + * | Field | Value | + * +---------+----------------+ + * | name | Twenty Sixteen | + * | title | Twenty Sixteen | + * | version | 1.2 | + * +---------+----------------+ */ public function get( $args, $assoc_args ) { $theme = $this->fetcher->get_check( $args[0] ); From 0dba5bb20889ae8bde3b1b6dda2748aefd0f7ce5 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 22 May 2016 14:57:27 +0545 Subject: [PATCH 4368/5359] Example: theme delete --- php/commands/theme.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 980967d7e..fda80015a 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -519,7 +519,8 @@ function is_installed( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * wp theme delete twentyeleven + * $ wp theme delete twentytwelve + * Success: Deleted 'twentytwelve' theme. * * @alias uninstall */ From 1d55131fe9e2146906b78aadccc8d5e6fa090276 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 15:52:27 +0545 Subject: [PATCH 4369/5359] Example: sidebar main class --- php/commands/sidebar.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 53cb9c3ac..0423cc823 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -2,6 +2,14 @@ /** * Manage sidebars. + * + * ## EXAMPLES + * + * # List sidebars + * $ wp sidebar list --fields=name,id --format=csv + * name,id + * "Widget Area",sidebar-1 + * "Inactive Widgets",wp_inactive_widgets */ class Sidebar_Command extends WP_CLI_Command { From da74d1ad05c930e86b07dc7ee2aadca4f41168ad Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 16:02:10 +0545 Subject: [PATCH 4370/5359] Examples for transient main class --- php/commands/transient.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index c19de7b6c..3221f8b78 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -5,7 +5,25 @@ * * ## EXAMPLES * - * wp transient set my_key my_value 300 + * # Set transient + * $ wp transient set sample_key "test data" 3600 + * Success: Transient added. + * + * # Get transient + * $ wp transient get sample_key + * test data + * + * # Delete transient + * $ wp transient delete sample_key + * Success: Transient deleted. + * + * # Delete expired transients + * $ wp transient delete-expired + * Success: 12 expired transients deleted from the database. + * + * # Delete all transients + * $ wp transient delete-all + * Success: 14 transients deleted from the database. */ class Transient_Command extends WP_CLI_Command { From 5a896b839b5e747f88c41c8156f053d8d022f7b8 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 17:29:20 +0545 Subject: [PATCH 4371/5359] Example: rewrite flush --- php/commands/rewrite.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d8dac74fc..2134a3dd0 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -24,6 +24,11 @@ class Rewrite_Command extends WP_CLI_Command { * * [--hard] * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. Works only on single site installs. + * + * ## EXAMPLES + * + * $ wp rewrite flush + * Success: Rewrite rules flushed. */ public function flush( $args, $assoc_args ) { // make sure we detect mod_rewrite if configured in apache_modules in config From 91b8b438b6ccfb993450a19bc658376902567a38 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 17:33:05 +0545 Subject: [PATCH 4372/5359] Example: rewrite structure --- php/commands/rewrite.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d8dac74fc..9591d1a2f 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -75,7 +75,8 @@ public function flush( $args, $assoc_args ) { * * ## EXAMPLES * - * wp rewrite structure '/%year%/%monthnum%/%postname%' + * $ wp rewrite structure '/%year%/%monthnum%/%postname%' + * Success: Rewrite structure set. */ public function structure( $args, $assoc_args ) { global $wp_rewrite; From 628e0f8d513eef8368c08509e2914c4e79a788ca Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 17:41:59 +0545 Subject: [PATCH 4373/5359] Example: rewrite list --- php/commands/rewrite.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d8dac74fc..c79e87acc 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -155,7 +155,13 @@ public function structure( $args, $assoc_args ) { * * ## EXAMPLES * - * wp rewrite list --format=csv + * $ wp rewrite list --format=csv + * match,query,source + * ^wp-json/?$,index.php?rest_route=/,other + * ^wp-json/(.*)?,index.php?rest_route=/$matches[1],other + * category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category + * category/(.+?)/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category + * category/(.+?)/embed/?$,index.php?category_name=$matches[1]&embed=true,category * * @subcommand list */ From 6421df0def2a422c466632c0d4753bfda6c6955c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 23 May 2016 17:52:13 +0545 Subject: [PATCH 4374/5359] Examples for rewrite commands --- php/commands/rewrite.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index d8dac74fc..9b2126be8 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -3,6 +3,25 @@ /** * Manage rewrite rules. * + * ## EXAMPLES + * + * # Flush rewrite rules + * $ wp rewrite flush + * Success: Rewrite rules flushed. + * + * # Update permalink structure + * $ wp rewrite structure '/%year%/%monthnum%/%postname%' + * Success: Rewrite structure set. + * + * # List rewrite rules + * $ wp rewrite list --format=csv + * match,query,source + * ^wp-json/?$,index.php?rest_route=/,other + * ^wp-json/(.*)?,index.php?rest_route=/$matches[1],other + * category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category + * category/(.+?)/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category + * category/(.+?)/embed/?$,index.php?category_name=$matches[1]&embed=true,category + * * @package wp-cli */ class Rewrite_Command extends WP_CLI_Command { From 0d9376399fa167ac8d57c1ee7f3f7f5ffb09d6c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 May 2016 07:40:47 -0700 Subject: [PATCH 4375/5359] Display error if theme directory exists but is errored --- features/theme.feature | 14 +++++++++++--- php/commands/theme.php | 7 +++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 6704bf24a..efad35776 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -131,20 +131,28 @@ Feature: Manage WordPress themes Scenario: Attempt to activate or fetch a broken theme Given a WP install - And I run `mkdir -pv wp-content/themes/just-test-theme` - When I try `wp theme activate just-test-theme` + When I run `mkdir -pv wp-content/themes/myth` + Then the wp-content/themes/myth directory should exist + + When I try `wp theme activate myth` Then STDERR should contain: """ Error: Stylesheet is missing. """ - When I try `wp theme get just-test-theme` + When I try `wp theme get myth` Then STDERR should contain: """ Error: Stylesheet is missing. """ + When I try `wp theme status myth` + Then STDERR should be: + """ + Error: Stylesheet is missing. + """ + Scenario: Enabling and disabling a theme Given a WP multisite install And I run `wp theme install jolene` diff --git a/php/commands/theme.php b/php/commands/theme.php index 1c89ac16a..2ff81bbf9 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -49,6 +49,13 @@ protected function get_upgrader_class( $force ) { * Author: the WordPress team */ function status( $args ) { + $theme = $this->fetcher->get_check( $args[0] ); + $errors = $theme->errors(); + if ( is_wp_error( $errors ) ) { + $message = $errors->get_error_message(); + WP_CLI::error( $message ); + } + parent::status( $args ); } From 6c44f2703a09e9507634ac8b020f715fe56855ba Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 23 May 2016 14:05:36 -0700 Subject: [PATCH 4376/5359] Add a test for expected behavior with `--force` --- features/theme.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index efad35776..5e6bf2a69 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -153,6 +153,12 @@ Feature: Manage WordPress themes Error: Stylesheet is missing. """ + When I run `wp theme install myth --force` + Then STDOUT should contain: + """ + Theme updated successfully. + """ + Scenario: Enabling and disabling a theme Given a WP multisite install And I run `wp theme install jolene` From 14b1408561bc6dfbf7adae875729ba48edeb3640 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Tue, 24 May 2016 01:31:44 +0000 Subject: [PATCH 4377/5359] Example: server #2770 --- php/commands/server.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index c13e917a4..ec6d0656c 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -21,10 +21,18 @@ class Server_Command extends WP_CLI_Command { * ## EXAMPLES * * # Make the instance available on any address (with port 8080) - * wp server --host=0.0.0.0 + * $ wp server --host=0.0.0.0 + * PHP 5.6.9 Development Server started at Tue May 24 01:27:11 2016 + * Listening on http://0.0.0.0:8080 + * Document root is / + * Press Ctrl-C to quit. * * # Run on port 80 (for multisite) - * sudo wp server --host=localhost.localdomain --port=80 + * $ sudo wp server --host=localhost.localdomain --port=80 + * PHP 5.6.9 Development Server started at Tue May 24 01:30:06 2016 + * Listening on http://localhost1.localdomain1:8080 + * Document root is / + * Press Ctrl-C to quit. * * @when before_wp_load */ From b312019df833d5d0eeeec0f2609af01f7c5270e6 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:04:17 +0545 Subject: [PATCH 4378/5359] Example: role list --- php/commands/role.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..9d5a0f07a 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -34,7 +34,13 @@ class Role_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp role list --fields=role --format=csv + * $ wp role list --fields=role --format=csv + * role + * administrator + * editor + * author + * contributor + * subscriber * * @subcommand list */ From 014387adb8e476085c5eed684383362992559bca Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:07:32 +0545 Subject: [PATCH 4379/5359] Example: role exists --- php/commands/role.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..23ebc09a9 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -69,7 +69,8 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp role exists editor + * $ wp role exists editor + * Success: Role with ID editor exists. */ public function exists( $args ) { global $wp_roles; From 75e23e3189b47dca2e1a96930be9a7cbee81a64a Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:13:49 +0545 Subject: [PATCH 4380/5359] Example: role create --- php/commands/role.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..17040efda 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -97,9 +97,13 @@ public function exists( $args ) { * * ## EXAMPLES * - * wp role create approver Approver + * # Create role for Approver + * $ wp role create approver Approver + * Success: Role with key approver created. * - * wp role create productadmin "Product Administrator" + * # Create role for Product Administrator + * $ wp role create productadmin "Product Administrator" + * Success: Role with key productadmin created. */ public function create( $args, $assoc_args ) { global $wp_roles; From 91134e08d49b2b02ac4fae6c8e6972778d6bfec8 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:16:43 +0545 Subject: [PATCH 4381/5359] Example: role delete --- php/commands/role.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..2fde4263d 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -147,9 +147,13 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp role delete approver + * # Delete approver role + * $ wp role delete approver + * Success: Role with key approver deleted. * + * # Delete productadmin role * wp role delete productadmin + * Success: Role with key productadmin deleted. */ public function delete( $args ) { global $wp_roles; From 8be776171d1963578c22ddd848bca51fb1077f58 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:20:26 +0545 Subject: [PATCH 4382/5359] Example: role reset --- php/commands/role.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..55ac198da 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -185,9 +185,13 @@ public function delete( $args ) { * * ## EXAMPLES * - * wp role reset administrator author contributor + * # Reset role + * $ wp role reset administrator author contributor + * Success: Reset 1/3 roles * - * wp role reset --all + * # Reset all default roles + * $ wp role reset --all + * Success: All default roles reset. */ public function reset( $args, $assoc_args ) { From 34b98de98a3e5eeeebf953d94d0c3acd5a8026a1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 09:33:44 +0545 Subject: [PATCH 4383/5359] Examples for role main class --- php/commands/role.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/php/commands/role.php b/php/commands/role.php index de0b3c15b..3f2dbe850 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -3,6 +3,33 @@ /** * Manage user roles. * + * ## EXAMPLES + * + * # List roles + * $ wp role list --fields=role --format=csv + * role + * administrator + * editor + * author + * contributor + * subscriber + * + * # Check if a role exists + * $ wp role exists editor + * Success: Role with ID editor exists. + * + * # Create role + * $ wp role create approver Approver + * Success: Role with key approver created. + * + * # Delete role + * $ wp role delete approver + * Success: Role with key approver deleted. + * + * # Reset role + * $ wp role reset administrator author contributor + * Success: Reset 3/3 roles + * * @package wp-cli */ class Role_Command extends WP_CLI_Command { From 6cf1d442f24519bcd6c081d5b1cedacff376c057 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 24 May 2016 11:39:42 +0545 Subject: [PATCH 4384/5359] Example: export command --- php/commands/export.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 7d89b0a0a..fa6f61673 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -59,12 +59,17 @@ class Export_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + * # Export posts published by the user between given start and end date + * $ wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + * Starting export process... + * Writing to file /tmp/staging.wordpress.2016-05-24.000.xml + * Success: All done with export. * - * wp export --dir=/tmp/ --post__in=123,124,125 - * - * # Export a random subset of content - * wp export --post__in=$(wp post list --post_type=post --orderby=rand --posts_per_page=8 --format=ids) + * # Export posts by IDs + * $ wp export --dir=/tmp/ --post__in=123,124,125 + * Starting export process... + * Writing to file /tmp/staging.wordpress.2016-05-24.000.xml + * Success: All done with export. */ public function __invoke( $_, $assoc_args ) { $defaults = array( From 5e90e8d810acdff2d3cd1e28a0208798bb0efd37 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 24 May 2016 22:45:03 +0545 Subject: [PATCH 4385/5359] Example: widget list --- php/commands/widget.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index fbc174beb..32442437a 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -52,7 +52,10 @@ class Widget_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp widget list sidebar-1 --fields=name --format=csv + * $ wp widget list sidebar-1 --fields=name,id --format=csv + * name,id + * meta,meta-5 + * search,search-3 * * @subcommand list */ From 372c246e15d47ddc009e2b32a8441aa3972cc40a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 24 May 2016 22:50:18 +0545 Subject: [PATCH 4386/5359] Example: widget add --- php/commands/widget.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index fbc174beb..5764b527a 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -90,7 +90,8 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp widget add calendar sidebar-1 2 --title="Calendar" + * $ wp widget add calendar sidebar-1 2 --title="Calendar" + * Success: Added widget to sidebar. * * @subcommand add */ From 6f7623ce5d11df07bff120bd30aaa9bcff067b97 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 24 May 2016 22:56:48 +0545 Subject: [PATCH 4387/5359] Example: widget update --- php/commands/widget.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index fbc174beb..89ab8b21d 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -140,7 +140,8 @@ public function add( $args, $assoc_args ) { * * ## EXAMPLES * - * wp widget update calendar-1 --title="Calendar" + * $ wp widget update calendar-1 --title="Our Calendar" + * Success: Widget updated. * * @subcommand update */ From 5227ccce1d5e109f5389b1d49c11efec33e3bbb5 Mon Sep 17 00:00:00 2001 From: Nate Wright <natew@notthisway.com> Date: Tue, 24 May 2016 21:01:11 +0100 Subject: [PATCH 4388/5359] wp-cli/wp-cli#2760 Minor language adjustments in readme --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f0c1ecc5e..810fe5ff9 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Activating 'rest-api'... Success: Plugin 'rest-api' activated. ``` -`wp transient` ([doc](http://wp-cli.org/commands/transient/)) lets you delete one or all transients: +Similarly, `wp transient` ([doc](http://wp-cli.org/commands/transient/)) lets you delete one or all transients: ``` $ wp transient delete-all @@ -35,7 +35,7 @@ For a complete introduction, read the [Quick Start guide](http://wp-cli.org/docs ## Installing -The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. +The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. See also our documentation on [alternative installation methods](http://wp-cli.org/docs/installing/). Before you install though, please make sure your environment meets the minimum requirements: @@ -76,11 +76,9 @@ WP-CLI project config: WP-CLI version: 0.23.0 ``` -Now that you've got WP-CLI, read the [Quick Start](http://wp-cli.org/docs/quick-start/) guide. Or view the [full installation guide](http://wp-cli.org/docs/installing/) with alternative installation methods. - ## Support -WP-CLI's project maintainers do their best to respond to all bug reports and configuration errors within reason and the constraints on their time. Before requesting help, please read to find a solution to your problem in the following resources: +WP-CLI's project maintainers do their best to respond to all bug reports and configuration errors within reason and the constraints on their volunteered time. Before requesting help, please read to find a solution to your problem in the following resources: - [Common issues and their fixes](http://wp-cli.org/docs/common-issues/) - [Submit a bug report](http://wp-cli.org/docs/bug-reports/) @@ -90,11 +88,11 @@ WP-CLI's project maintainers do their best to respond to all bug reports and con A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](http://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](http://wp-cli.org/commands/plugin/activate/)) is another. -WP-CLI comes with dozens of commands. But it's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/) to learn more. +WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/) to learn more. ## Contributing -Thanks for helping to improve WP-CLI. Please read about [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). +To get involved, please first read about [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). ### Leadership * [Andreas Creten](https://github.com/andreascreten) - founder From 13fcae51cb851c011e04cab20c7325e3a5dab970 Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 25 May 2016 00:07:43 +0100 Subject: [PATCH 4389/5359] Correct spelling of 'separate' in the `wp export` command docs. --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 7d89b0a0a..cbecab738 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -36,7 +36,7 @@ class Export_Command extends WP_CLI_Command { * comma. Defaults to all. * * [--post_type__not_in=<post-type>] - * : Export all post types except those identified. Seperate multiple post types + * : Export all post types except those identified. Separate multiple post types * with a comma. Defaults to none. * * [--post__in=<pid>] From 113382531f63f32a4ba158c396cc89c022bfc135 Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 25 May 2016 00:10:50 +0100 Subject: [PATCH 4390/5359] Display the default value for the `--max-file-size` flag in `wp export`. --- php/commands/export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/export.php b/php/commands/export.php index 7d89b0a0a..dedd36a74 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -21,7 +21,7 @@ class Export_Command extends WP_CLI_Command { * : Don't export comments. * * [--max_file_size=<MB>] - * : A single export file should have this many megabytes. + * : A single export file should have this many megabytes. Default: 15 * * ## FILTERS * From a85e434ca0113dbebf7d01832cb43fbf617ccbc6 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 25 May 2016 05:58:36 +0545 Subject: [PATCH 4391/5359] Example: widget move --- php/commands/widget.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index f23f50cf3..b60abd288 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -182,9 +182,13 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * wp widget move recent-comments-2 --position=2 + * # Change position of widget + * $ wp widget move recent-comments-2 --position=2 + * Success: Widget moved. * - * wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets + * # Move widget to Inactive Widgets + * $ wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets + * Success: Widget moved. * * @subcommand move */ From 023ebfea7864c8e31069941a9cbc88899118f12b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 25 May 2016 06:03:43 +0545 Subject: [PATCH 4392/5359] Example: widget deactivate --- php/commands/widget.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index f23f50cf3..6bcc765a9 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -223,7 +223,8 @@ public function move( $args, $assoc_args ) { * * ## EXAMPLES * - * wp widget deactivate recent-comments-2 + * $ wp widget deactivate recent-comments-2 + * Success: Widget(s) deactivated * * @subcommand deactivate */ From 94e5c9e7b37b5106ff735843f5132ea71b4680d2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 25 May 2016 06:06:49 +0545 Subject: [PATCH 4393/5359] Example: widget delete --- php/commands/widget.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index f23f50cf3..66fa35285 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -253,7 +253,8 @@ public function deactivate( $args, $assoc_args ) { * * ## EXAMPLES * - * wp widget delete recent-comments-2 + * $ wp widget delete recent-comments-2 + * Success: Widget(s) removed from sidebar. * * @subcommand delete */ From 0765dd90f122ebf761b19b49394003b54a03fde2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 25 May 2016 06:21:30 +0545 Subject: [PATCH 4394/5359] Examples for Widget main class --- php/commands/widget.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index f23f50cf3..cdf6b91e5 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -6,16 +6,25 @@ * ## EXAMPLES * * # List widgets on a given sidebar - * wp widget list sidebar-1 + * $ wp widget list sidebar-1 + * +----------+------------+----------+----------------------+ + * | name | id | position | options | + * +----------+------------+----------+----------------------+ + * | meta | meta-6 | 1 | {"title":"Meta"} | + * | calendar | calendar-2 | 2 | {"title":"Calendar"} | + * +----------+------------+----------+----------------------+ * * # Add a calendar widget to the second position on the sidebar - * wp widget add calendar sidebar-1 2 + * $ wp widget add calendar sidebar-1 2 + * Success: Added widget to sidebar. * * # Update option(s) associated with a given widget - * wp widget update calendar-1 --title="Calendar" + * $ wp widget update calendar-1 --title="Calendar" + * Success: Widget updated. * * # Delete one or more widgets entirely - * wp widget delete calendar-2 archive-1 + * $ wp widget delete calendar-2 archive-1 + * Success: Widget(s) removed from sidebar. */ class Widget_Command extends WP_CLI_Command { From 4f2fc72aca1703c6ed89963ad2b65f80b1c0d832 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 11:37:57 +0545 Subject: [PATCH 4395/5359] Example: cap list --- php/commands/cap.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index 3f65b1f23..b469fa167 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -26,8 +26,13 @@ class Capabilities_Command extends WP_CLI_Command { * * ## EXAMPLES * - * # Display alphabetical list of bbPress moderator capabilities - * wp cap list 'bbp_moderator' | sort + * # Display alphabetical list of Contributor capabilities + * $ wp cap list 'contributor' | sort + * delete_posts + * edit_posts + * level_0 + * level_1 + * read * * @subcommand list */ From 59a4ea226cfb082d0cfeda4570bd088f3883e95e Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 11:42:18 +0545 Subject: [PATCH 4396/5359] Example: cap add --- php/commands/cap.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cap.php b/php/commands/cap.php index 3f65b1f23..b3471529a 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -48,6 +48,12 @@ public function list_( $args ) { * * <cap>... * : One or more capabilities to add. + * + * ## EXAMPLES + * + * # Add 'spectate' capability to 'author' role + * $ wp cap add author spectate + * Success: Added 1 capabilities to 'author' role. */ public function add( $args ) { self::persistence_check(); From e9484f1e72fc58ff6dc42b17542a546e530ba799 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 11:45:44 +0545 Subject: [PATCH 4397/5359] Example: cap remove --- php/commands/cap.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cap.php b/php/commands/cap.php index 3f65b1f23..d76a828c9 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -80,6 +80,12 @@ public function add( $args ) { * * <cap>... * : One or more capabilities to remove. + * + * ## EXAMPLES + * + * # Remove 'spectate' capability from 'author' role + * $ wp cap remove author spectate + * Success: Removed 1 capabilities from 'author' role. */ public function remove( $args ) { self::persistence_check(); From 22cbf21a284df806285c24f1515645ad98c14c11 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 11:52:19 +0545 Subject: [PATCH 4398/5359] Examples for cap main class --- php/commands/cap.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index 3f65b1f23..fdeb1694f 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -6,13 +6,16 @@ * ## EXAMPLES * * # Add 'spectate' capability to 'author' role - * wp cap add 'author' 'spectate' + * $ wp cap add 'author' 'spectate' + * Success: Added 1 capabilities to 'author' role. * * # Add all caps from 'editor' role to 'author' role - * wp cap list 'editor' | xargs wp cap add 'author' + * $ wp cap list 'editor' | xargs wp cap add 'author' + * Success: Added 24 capabilities to 'author' role. * * # Remove all caps from 'editor' role that also appear in 'author' role * wp cap list 'author' | xargs wp cap remove 'editor' + * Success: Removed 34 capabilities from 'editor' role. */ class Capabilities_Command extends WP_CLI_Command { From 55a2a3289d24b97ec0d12766d4a7aa0f2a39c1a6 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 11:53:09 +0545 Subject: [PATCH 4399/5359] Add missing dollar sign in cap example --- php/commands/cap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index fdeb1694f..950c62667 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -14,7 +14,7 @@ * Success: Added 24 capabilities to 'author' role. * * # Remove all caps from 'editor' role that also appear in 'author' role - * wp cap list 'author' | xargs wp cap remove 'editor' + * $ wp cap list 'author' | xargs wp cap remove 'editor' * Success: Removed 34 capabilities from 'editor' role. */ class Capabilities_Command extends WP_CLI_Command { From 0d0a89ea7fa66739dbe01a6b36a5c206454f677c Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 25 May 2016 06:34:49 +0000 Subject: [PATCH 4400/5359] Add Example: cli check-update & cli param-dump, #2770 --- php/commands/cli.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index 5d81358a2..6c4f6ba1a 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -104,6 +104,11 @@ public function info( $_, $assoc_args ) { * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## EXAMPLES + * + * $ wp cli check-update + * Success: WP-CLI is at the latest version. + * * @subcommand check-update */ public function check_update( $_, $assoc_args ) { @@ -322,6 +327,11 @@ private function get_updates( $assoc_args ) { * [--format=<format>] * : Accepted values: var_export, json. Default: json. * + * ## EXAMPLES + * + * $ wp cli param-dump + * {"path":{"runtime":"=<path>","file":"<path>","synopsis":"","default":null,"multiple":false,"desc":"Path to the WordPress files."},"url":{"runtime":"=<url>","file":"<url>","synopsis":"","default":null,"multiple":false,"desc":"Pretend request came from given URL. In multisite, this argument is how the target site is specified."},"blog":{"runtime":"=<url>","file":false,"synopsis":"","default":null,"multiple":false,"deprecated":"Use --url instead."},"config":{"runtime":"=<path>","file":false,"synopsis":"","default":null,"multiple":false,"deprecated":"Use the WP_CLI_CONFIG_PATH environment variable instead."},"user":{"runtime":"=<id|login|email>","file":"<id|login|email>","synopsis":"","default":null,"multiple":false,"desc":"Set the WordPress user."},"skip-plugins":{"runtime":"[=<plugin>]","file":"<list>","synopsis":"","default":"","multiple":false,"desc":"Skip loading all or some plugins. Note: mu-plugins are still loaded."},"skip-themes":{"runtime":"[=<theme>]","file":"<list>","synopsis":"","default":"","multiple":false,"desc":"Skip loading all or some themes."},"skip-packages":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Skip loading all installed packages."},"require":{"runtime":"=<path>","file":"<path>","synopsis":"","default":[],"multiple":true,"desc":"Load PHP file before running the command (may be used more than once)."},"disabled_commands":{"runtime":false,"file":"<list>","synopsis":"","default":[],"multiple":false,"desc":"(Sub)commands to disable."},"color":{"runtime":true,"file":"<bool>","synopsis":"","default":"auto","multiple":false,"desc":"Whether to colorize the output."},"debug":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Show all PHP errors; add verbosity to WP-CLI bootstrap."},"prompt":{"runtime":"","file":false,"synopsis":"","default":false,"multiple":false,"desc":"Prompt the user to enter values for all command arguments."},"quiet":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Suppress informational messages."},"apache_modules":{"runtime":false,"file":"<list>","synopsis":"","default":[],"multiple":true,"desc":"List of Apache Modules that are to be reported as loaded."},"allow-root":{"runtime":"","file":false,"synopsis":"","default":null,"multiple":false,"hidden":true}} + * * @subcommand param-dump */ function param_dump( $_, $assoc_args ) { From ebe1008b2bb83290487139acaf77069dcb3646d1 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 25 May 2016 06:38:04 +0000 Subject: [PATCH 4401/5359] Add Example: eval , #2770 --- php/commands/eval.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/eval.php b/php/commands/eval.php index 11847ccfd..33250f8f1 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -17,7 +17,8 @@ class Eval_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp eval 'echo WP_CONTENT_DIR;' + * $ wp eval 'echo WP_CONTENT_DIR;' + * /var/www/wordpress/wp-content */ public function __invoke( $args, $assoc_args ) { From 1830263c6379f49c1cc0456785c1482c362338d3 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 25 May 2016 06:38:44 +0000 Subject: [PATCH 4402/5359] Add Example: eval with --skip-wordpress, #2770 --- php/commands/eval.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/eval.php b/php/commands/eval.php index 33250f8f1..12c2c85d7 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -19,6 +19,9 @@ class Eval_Command extends WP_CLI_Command { * * $ wp eval 'echo WP_CONTENT_DIR;' * /var/www/wordpress/wp-content + * + * $ wp eval 'echo rand();' --skip-wordpress + * 479620423 */ public function __invoke( $args, $assoc_args ) { From 124c00501f2c56288591a2064ecb088448599ba9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 17:39:43 +0545 Subject: [PATCH 4403/5359] introduce --format parameter in cap list --- php/commands/cap.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index f5f99d55a..e63eb1e21 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -19,6 +19,10 @@ */ class Capabilities_Command extends WP_CLI_Command { + private $fields = array( + 'name' + ); + /** * List capabilities for a given role. * @@ -27,6 +31,9 @@ class Capabilities_Command extends WP_CLI_Command { * <role> * : Key for the role. * + * [--format=<format>] + * : Accepted values: table, csv, json, count, yaml. Default: table + * * ## EXAMPLES * * # Display alphabetical list of Contributor capabilities @@ -39,11 +46,19 @@ class Capabilities_Command extends WP_CLI_Command { * * @subcommand list */ - public function list_( $args ) { + public function list_( $args, $assoc_args ) { $role_obj = self::get_role( $args[0] ); - foreach ( array_keys( $role_obj->capabilities ) as $cap ) - WP_CLI::line( $cap ); + $output_caps = array(); + foreach ( array_keys( $role_obj->capabilities ) as $cap ) { + $output_cap = new stdClass; + + $output_cap->name = $cap; + + $output_caps[] = $output_cap; + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_caps ); } /** From 26d1e3299c2947d7c1145b71b42826264fd935f0 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 25 May 2016 17:49:55 +0545 Subject: [PATCH 4404/5359] add test scenario for cap list --- features/roles.feature | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/features/roles.feature b/features/roles.feature index 53ac7046a..5e62fdc84 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -67,9 +67,10 @@ Feature: Manage WordPress roles | name | role | | Reporter | reporter | - When I run `wp cap list reporter` + When I run `wp cap list reporter --format=csv` Then STDOUT should be: """ + name upload_files edit_posts edit_published_posts @@ -81,3 +82,19 @@ Feature: Manage WordPress roles delete_posts delete_published_posts """ + + When I run `wp cap list reporter` + Then STDOUT should be a table containing rows: + """ + | name | + | upload_files | + | edit_posts | + | edit_published_posts | + | publish_posts | + | read | + | level_2 | + | level_1 | + | level_0 | + | delete_posts | + | delete_published_posts | + """ From 5a4abf0faf02c58e22ee7c160f4bfa3bfe92d1e7 Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 25 May 2016 15:01:10 +0100 Subject: [PATCH 4405/5359] Add a missing parameter to the example command for `wp term generate`. --- php/commands/term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index aeee574f0..c92fb8b26 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -298,7 +298,7 @@ public function delete( $args ) { * * ## EXAMPLES * - * wp term generate --count=10 + * wp term generate category --count=10 * * # Add meta to every generated term * wp term generate category --format=ids | xargs -0 -d ' ' -I % wp term meta add % foo bar From fdabde6bfdb6daa44060b7699d33a549a5ea8287 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 25 May 2016 15:00:24 +0000 Subject: [PATCH 4406/5359] Change Example: param-dump , #2770 --- php/commands/cli.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 6c4f6ba1a..ba8aa7df3 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -329,8 +329,19 @@ private function get_updates( $assoc_args ) { * * ## EXAMPLES * - * $ wp cli param-dump - * {"path":{"runtime":"=<path>","file":"<path>","synopsis":"","default":null,"multiple":false,"desc":"Path to the WordPress files."},"url":{"runtime":"=<url>","file":"<url>","synopsis":"","default":null,"multiple":false,"desc":"Pretend request came from given URL. In multisite, this argument is how the target site is specified."},"blog":{"runtime":"=<url>","file":false,"synopsis":"","default":null,"multiple":false,"deprecated":"Use --url instead."},"config":{"runtime":"=<path>","file":false,"synopsis":"","default":null,"multiple":false,"deprecated":"Use the WP_CLI_CONFIG_PATH environment variable instead."},"user":{"runtime":"=<id|login|email>","file":"<id|login|email>","synopsis":"","default":null,"multiple":false,"desc":"Set the WordPress user."},"skip-plugins":{"runtime":"[=<plugin>]","file":"<list>","synopsis":"","default":"","multiple":false,"desc":"Skip loading all or some plugins. Note: mu-plugins are still loaded."},"skip-themes":{"runtime":"[=<theme>]","file":"<list>","synopsis":"","default":"","multiple":false,"desc":"Skip loading all or some themes."},"skip-packages":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Skip loading all installed packages."},"require":{"runtime":"=<path>","file":"<path>","synopsis":"","default":[],"multiple":true,"desc":"Load PHP file before running the command (may be used more than once)."},"disabled_commands":{"runtime":false,"file":"<list>","synopsis":"","default":[],"multiple":false,"desc":"(Sub)commands to disable."},"color":{"runtime":true,"file":"<bool>","synopsis":"","default":"auto","multiple":false,"desc":"Whether to colorize the output."},"debug":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Show all PHP errors; add verbosity to WP-CLI bootstrap."},"prompt":{"runtime":"","file":false,"synopsis":"","default":false,"multiple":false,"desc":"Prompt the user to enter values for all command arguments."},"quiet":{"runtime":"","file":"<bool>","synopsis":"","default":false,"multiple":false,"desc":"Suppress informational messages."},"apache_modules":{"runtime":false,"file":"<list>","synopsis":"","default":[],"multiple":true,"desc":"List of Apache Modules that are to be reported as loaded."},"allow-root":{"runtime":"","file":false,"synopsis":"","default":null,"multiple":false,"hidden":true}} + * $ wp cli param-dump --format=var_export + * array ( + * 'path' => + * array ( + * 'runtime' => '=<path>', + * 'file' => '<path>', + * 'synopsis' => '', + * 'default' => NULL, + * 'multiple' => false, + * 'desc' => 'Path to the WordPress files.', + * ), + * 'url' => + * array ( * * @subcommand param-dump */ From 9705f0b0a08b19cc6f8bb7138a9e5897c3e54cd9 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 25 May 2016 23:43:16 +0545 Subject: [PATCH 4407/5359] fix testing of table output --- features/roles.feature | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 5e62fdc84..9f4764af8 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -86,15 +86,6 @@ Feature: Manage WordPress roles When I run `wp cap list reporter` Then STDOUT should be a table containing rows: """ - | name | - | upload_files | - | edit_posts | - | edit_published_posts | - | publish_posts | - | read | - | level_2 | - | level_1 | - | level_0 | - | delete_posts | - | delete_published_posts | + | name | + | upload_files | """ From 9f7f3cb2ed52e3085c69c146f1630d319e7248b5 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 09:18:49 +0545 Subject: [PATCH 4408/5359] Update doc for cap list as per new standard --- php/commands/cap.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index e63eb1e21..027eccd16 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -32,7 +32,17 @@ class Capabilities_Command extends WP_CLI_Command { * : Key for the role. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: list + * options: + * - list + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## EXAMPLES * From 40c21d52d0f33f071d9f7235d67b8c6ffb4149b1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 09:28:15 +0545 Subject: [PATCH 4409/5359] Display cap list in list by default --- php/commands/cap.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index 027eccd16..90db4a1d9 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -59,16 +59,23 @@ class Capabilities_Command extends WP_CLI_Command { public function list_( $args, $assoc_args ) { $role_obj = self::get_role( $args[0] ); - $output_caps = array(); - foreach ( array_keys( $role_obj->capabilities ) as $cap ) { - $output_cap = new stdClass; + if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'list' ) ) ) { + foreach ( array_keys( $role_obj->capabilities ) as $cap ) { + WP_CLI::line( $cap ); + } + } + else { + $output_caps = array(); + foreach ( array_keys( $role_obj->capabilities ) as $cap ) { + $output_cap = new stdClass; - $output_cap->name = $cap; + $output_cap->name = $cap; - $output_caps[] = $output_cap; + $output_caps[] = $output_cap; + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_caps ); } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_caps ); } /** From dc85b5d35d3311a946b9b72f62c14f774cc57c5d Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 09:37:39 +0545 Subject: [PATCH 4410/5359] Fix test of cap list for --format parameter --- features/roles.feature | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 9f4764af8..c4df0c907 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -67,10 +67,9 @@ Feature: Manage WordPress roles | name | role | | Reporter | reporter | - When I run `wp cap list reporter --format=csv` + When I run `wp cap list reporter` Then STDOUT should be: """ - name upload_files edit_posts edit_published_posts @@ -83,9 +82,8 @@ Feature: Manage WordPress roles delete_published_posts """ - When I run `wp cap list reporter` - Then STDOUT should be a table containing rows: + When I run `wp cap list reporter --format=count` + Then STDOUT should be: """ - | name | - | upload_files | + 10 """ From d33c8fa31b33f8b87fd864eb602671baacfdd203 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 10:09:56 +0545 Subject: [PATCH 4411/5359] Fix sniffer issue in cap list --- php/commands/cap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index 90db4a1d9..b89cea9d6 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -61,7 +61,7 @@ public function list_( $args, $assoc_args ) { if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'list' ) ) ) { foreach ( array_keys( $role_obj->capabilities ) as $cap ) { - WP_CLI::line( $cap ); + WP_CLI::line( $cap ); } } else { From fe1550f293723c8cd4782b252f7a1d7695c2339c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 12:57:18 +0545 Subject: [PATCH 4412/5359] Example: term list --- php/commands/term.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..9b01395aa 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -52,9 +52,24 @@ class Term_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp term list category --format=csv - * - * wp term list post_tag --fields=name,slug + * # List post categories + * $ wp term list category --format=csv + * term_id,term_taxonomy_id,name,slug,description,parent,count + * 2,2,aciform,aciform,,0,1 + * 3,3,antiquarianism,antiquarianism,,0,1 + * 4,4,arrangement,arrangement,,0,1 + * 5,5,asmodeus,asmodeus,,0,1 + * + * # List post tags + * $ wp term list post_tag --fields=name,slug + * +-----------+-------------+ + * | name | slug | + * +-----------+-------------+ + * | 8BIT | 8bit | + * | alignment | alignment-2 | + * | Articles | articles | + * | aside | aside | + * +-----------+-------------+ * * @subcommand list */ From b901da35e7e0990d1fc361d5a241d77a8859a384 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:01:05 +0545 Subject: [PATCH 4413/5359] Example: term create --- php/commands/term.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..6f7dea930 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -118,7 +118,8 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term create category Apple --description="A type of fruit" + * $ wp term create category Apple --description="A type of fruit" + * Success: Created category 199. */ public function create( $args, $assoc_args ) { From ac55695fc888a39207209092ac67cde49574a9b1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:03:52 +0545 Subject: [PATCH 4414/5359] Example: term get --- php/commands/term.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..e41c3dc7d 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -173,7 +173,8 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term get category 1 --format=json + * $ wp term get category 199 --format=json + * {"term_id":199,"name":"Apple","slug":"apple","term_group":0,"term_taxonomy_id":199,"taxonomy":"category","description":"A type of fruit","parent":0,"count":0,"filter":"raw"} */ public function get( $args, $assoc_args ) { From 0bd5fc8c702c0ae6046a1739b99703e5bd177844 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:07:20 +0545 Subject: [PATCH 4415/5359] Example: term update --- php/commands/term.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..27d2aa886 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -220,7 +220,8 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term update category 15 --name=Apple + * $ wp term update category 15 --name=Apple + * Success: Term updated. */ public function update( $args, $assoc_args ) { From b6072443ededc31a47194783ec7208c60dec3164 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:25:47 +0545 Subject: [PATCH 4416/5359] Example: term delete --- php/commands/term.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..9ab3540cc 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -260,8 +260,15 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * # delete all post tags - * wp term list post_tag --field=term_id | xargs wp term delete post_tag + * # Delete post category + * $ wp term delete category 15 + * Success: Deleted category 15. + * + * # Delete all post tags + * $ wp term list post_tag --field=term_id | xargs wp term delete post_tag + * Success: Deleted post_tag 159. + * Success: Deleted post_tag 160. + * Success: Deleted post_tag 161. */ public function delete( $args ) { $taxonomy = array_shift( $args ); From 78573a2c11412c9b2cf88d317eaa20f994fd1094 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:35:36 +0545 Subject: [PATCH 4417/5359] Example: term generate --- php/commands/term.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..6bd081628 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -298,10 +298,15 @@ public function delete( $args ) { * * ## EXAMPLES * - * wp term generate category --count=10 + * # Generate post categories + * $ wp term generate category --count=10 + * Generating terms 100% [=========] 0:02 / 0:02 * * # Add meta to every generated term - * wp term generate category --format=ids | xargs -0 -d ' ' -I % wp term meta add % foo bar + * $ wp term generate category --format=ids --count=3 | xargs -0 -d ' ' -I % wp term meta add % foo bar + * Success: Added custom field. + * Success: Added custom field. + * Success: Added custom field. */ public function generate( $args, $assoc_args ) { global $wpdb; From a6c06a3606318263aca029de8c911706342baa3a Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:41:48 +0545 Subject: [PATCH 4418/5359] Example: term url --- php/commands/term.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..2829a6178 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -404,9 +404,8 @@ public function generate( $args, $assoc_args ) { * * ## EXAMPLES * - * wp term url post_tag 123 - * - * wp term url post_tag 123 324 + * $ wp term url post_tag 123 + * http://example.com/tag/tips-and-tricks */ public function url( $args ) { $term_link = get_term_link( (int)$args[1], $args[0] ); From bdef6c5e13502bee300daba78dfec3251f35f519 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 13:49:21 +0545 Subject: [PATCH 4419/5359] Example: term recount --- php/commands/term.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..b325eb320 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -434,9 +434,18 @@ public function url( $args ) { * * ## EXAMPLES * - * wp term recount category post_tag - * - * wp taxonomy list --field=name | xargs wp term recount + * # Recount posts assigned to each categories and tags + * $ wp term recount category post_tag + * Success: Updated category term count + * Success: Updated post_tag term count + * + * # Recount all listed taxonomies + * $ wp taxonomy list --field=name | xargs wp term recount + * Success: Updated category term count + * Success: Updated post_tag term count + * Success: Updated nav_menu term count + * Success: Updated link_category term count + * Success: Updated post_format term count */ public function recount( $args ) { foreach( $args as $taxonomy ) { From 8b02d3c3fedc097a8b9f71bc8fdbaa2f574aa8ac Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 14:26:34 +0545 Subject: [PATCH 4420/5359] Example: term meta --- php/commands/term.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..8c3b164a6 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -481,7 +481,21 @@ private function get_formatter( &$assoc_args ) { * * ## EXAMPLES * - * wp term meta set category 123 description "Mary is a WordPress developer." + * # Set term meta + * $ wp term meta set 123 bio "Mary is a WordPress developer." + * Success: Updated custom field 'bio'. + * + * # Get term meta + * $ wp term meta get 123 bio + * Mary is a WordPress developer. + * + * # Update term meta + * $ wp term meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. + * + * # Delete term meta + * $ wp term meta delete 123 bio + * Success: Deleted custom field. */ class Term_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'term'; From acc8de086a3d559fcb362e38c62aa27a380dfb73 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 14:51:57 +0545 Subject: [PATCH 4421/5359] Accept multiple term IDs in term url --- php/commands/term.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c92fb8b26..9a275fb2a 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -409,11 +409,14 @@ public function generate( $args, $assoc_args ) { * wp term url post_tag 123 324 */ public function url( $args ) { - $term_link = get_term_link( (int)$args[1], $args[0] ); - if ( $term_link && ! is_wp_error( $term_link ) ) { - WP_CLI::line( $term_link ); - } else { - WP_CLI::error( "Invalid term." ); + $term_ids = array_slice( $args, 1 ); + foreach ( $term_ids as $term_id ) { + $term_link = get_term_link( (int)$term_id, $args[0] ); + if ( $term_link && ! is_wp_error( $term_link ) ) { + WP_CLI::line( $term_link ); + } else { + WP_CLI::warning( sprintf( "Invalid term %d.", $term_id ) ); + } } } From 5c5d624ddc08d7794a332bcbfa85e9100539ea1c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 14:55:22 +0545 Subject: [PATCH 4422/5359] Use string placeholder for error message in term url --- php/commands/term.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/term.php b/php/commands/term.php index 9a275fb2a..8df654367 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -415,7 +415,7 @@ public function url( $args ) { if ( $term_link && ! is_wp_error( $term_link ) ) { WP_CLI::line( $term_link ); } else { - WP_CLI::warning( sprintf( "Invalid term %d.", $term_id ) ); + WP_CLI::warning( sprintf( "Invalid term %s.", $term_id ) ); } } } From 9f054d090c9decfe24fc210a8dcb7dc2b226aaf4 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 15:37:25 +0545 Subject: [PATCH 4423/5359] Example: taxonomy list --- php/commands/taxonomy.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index 3579ebbf6..b7f988121 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -57,9 +57,24 @@ public function __construct() { * * ## EXAMPLES * - * wp taxonomy list --format=csv - * - * wp taxonomy list --object-type=post --fields=name,public + * # List all taxonomies + * $ wp taxonomy list --format=csv + * name,label,description,object_type,show_tagcloud,hierarchical,public + * category,Categories,,post,1,1,1 + * post_tag,Tags,,post,1,,1 + * nav_menu,"Navigation Menus",,nav_menu_item,,, + * link_category,"Link Categories",,link,1,, + * post_format,Format,,post,,,1 + * + * # List all taxonomies with 'post' object type + * $ wp taxonomy list --object_type=post --fields=name,public + * +-------------+--------+ + * | name | public | + * +-------------+--------+ + * | category | 1 | + * | post_tag | 1 | + * | post_format | 1 | + * +-------------+--------+ * * @subcommand list */ From 0364d523f87544ac035d51abfbe52692a3ae4e21 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Thu, 26 May 2016 12:09:43 +0200 Subject: [PATCH 4424/5359] Conditionally require `WP_Site_Query` and `WP_Term_Query` for WP 4.6 compat. --- php/wp-settings-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index ba5c9243e..b84f3e1d9 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -124,6 +124,7 @@ // Initialize multisite if enabled. if ( is_multisite() ) { + Utils\maybe_require( '4.6-alpha-37575', ABSPATH . WPINC . '/class-wp-site-query.php' ); require( ABSPATH . WPINC . '/ms-blogs.php' ); require( ABSPATH . WPINC . '/ms-settings.php' ); } elseif ( ! defined( 'MULTISITE' ) ) { @@ -192,6 +193,7 @@ require( ABSPATH . WPINC . '/script-loader.php' ); require( ABSPATH . WPINC . '/taxonomy.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-term.php' ); +Utils\maybe_require( '4.6-alpha-37575', ABSPATH . WPINC . '/class-wp-term-query.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-tax-query.php' ); require( ABSPATH . WPINC . '/update.php' ); require( ABSPATH . WPINC . '/canonical.php' ); From b9795d530016ba995e3b7c21e5f3c071a426a18f Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 16:03:40 +0545 Subject: [PATCH 4425/5359] Example: plugin status --- php/commands/plugin.php | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 917b25ae1..49966cc5b 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -40,6 +40,27 @@ protected function get_upgrader_class( $force ) { * * [<plugin>] * : A particular plugin to show the status for. + * + * ## EXAMPLES + * + * # Displays status of all plugins + * $ wp plugin status + * 5 installed plugins: + * I akismet 3.1.11 + * I easy-digital-downloads 2.5.16 + * A theme-check 20160523.1 + * I wen-logo-slider 2.0.3 + * M ns-pack 1.0.0 + * Legend: I = Inactive, A = Active, M = Must Use + * + * # Displays status of a plugin + * $ wp plugin status theme-check + * Plugin theme-check details: + * Name: Theme Check + * Status: Active + * Version: 20160523.1 + * Author: Otto42, pross + * Description: A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool! */ function status( $args ) { parent::status( $args ); @@ -456,7 +477,7 @@ protected function get_item_list() { continue; } foreach( $files as $file ) { - $items[ $file ]['name'] = str_replace( '.' . pathinfo( $file, PATHINFO_EXTENSION ), '', $file ); + $items[ $file ]['name'] = str_replace( '.' . pathinfo( $file, PATHINFO_EXTENSION ), '', $file ); } } @@ -786,12 +807,12 @@ private function _delete( $plugin ) { $path = path_join( WP_PLUGIN_DIR, $plugin_dir ); if ( \WP_CLI\Utils\is_windows() ) { - // Handles plugins that are not in own folders + // Handles plugins that are not in own folders // e.g. Hello Dolly -> plugins/hello.php - if ( is_file( $path ) ) { + if ( is_file( $path ) ) { $command = 'del /f /q '; } else { - $command = 'rd /s /q '; + $command = 'rd /s /q '; } $path = str_replace( "/", "\\", $path ); } else { From bdbf4d38742025304ea0c156957f3d31bbb7e1bb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 16:19:22 +0545 Subject: [PATCH 4426/5359] Example: media regenerate --- php/commands/media.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index ddbf001b1..cfde50747 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -26,11 +26,22 @@ class Media_Command extends WP_CLI_Command { * * ## EXAMPLES * - * # re-generate all thumbnails, without confirmation - * wp media regenerate --yes + * # Re-generate all thumbnails, without confirmation + * $ wp media regenerate --yes + * Found 3 images to regenerate. + * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). + * Regenerated thumbnails for "Boardwalk" (ID 757). + * Regenerated thumbnails for "Sunburst Over River" (ID 756). + * Success: Finished regenerating all images. * - * # re-generate all thumbnails that have IDs between 1000 and 2000 - * seq 1000 2000 | xargs wp media regenerate + * # Re-generate all thumbnails that have IDs between 1000 and 2000 + * $ seq 1000 2000 | xargs wp media regenerate + * Found 4 images to regenerate. + * Regenerated thumbnails for "Vertical Featured Image" (ID 1027). + * Regenerated thumbnails for "Horizontal Featured Image" (ID 1022). + * Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045). + * Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023). + * Success: Finished regenerating all images. */ function regenerate( $args, $assoc_args = array() ) { if ( empty( $args ) ) { From 44f32ab534d8dfe1addfde3a23c800dfc6d03baa Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 16:33:48 +0545 Subject: [PATCH 4427/5359] Example: media import --- php/commands/media.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index ddbf001b1..e2f6965f7 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -115,19 +115,25 @@ function regenerate( $args, $assoc_args = array() ) { * ## EXAMPLES * * # Import all jpgs in the current user's "Pictures" directory, not attached to any post - * wp media import ~/Pictures/**\/*.jpg + * $ wp media import ~/Pictures/**\/*.jpg + * Success: Imported file /home/person/Pictures/beautiful-youg-girl-in-ivy.jpg as attachment ID 1751. + * Success: Imported file /home/person/Pictures/fashion-girl.jpg as attachment ID 1752. * * # Import a local image and set it to be the post thumbnail for a post - * wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image + * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image + * Success: Imported file /home/person/Downloads/image.png as attachment ID 1753 and attached to post 123 as featured image. * * # Import a local image, but set it as the featured image for all posts * # 1. Import the image and get its attachment ID - * * 2. Assign the attachment ID as the featured image for all posts - * ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)" - * wp post list --post_type=post --format=ids | xargs -0 -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID + * # 2. Assign the attachment ID as the featured image for all posts + * $ ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)" + * $ wp post list --post_type=post --format=ids | xargs -0 -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID + * Success: Added custom field. + * Success: Added custom field. * * # Import an image from the web - * wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" + * $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" + * Success: Imported file http://s.wordpress.org/style/images/wp-header-logo.png as attachment ID 1755. */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( From e3c435d8862a01ebd595fa85f25d0c14aca3b075 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 16:37:50 +0545 Subject: [PATCH 4428/5359] Examples for media main class --- php/commands/media.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index ddbf001b1..937d3da26 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -3,6 +3,20 @@ /** * Manage attachments. * + * ## EXAMPLES + * + * # Re-generate all thumbnails, without confirmation + * $ wp media regenerate --yes + * Found 3 images to regenerate. + * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). + * Regenerated thumbnails for "Boardwalk" (ID 757). + * Regenerated thumbnails for "Sunburst Over River" (ID 756). + * Success: Finished regenerating all images. + * + * # Import a local image and set it to be the featured image for a post + * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image + * Success: Imported file /home/person/Downloads/image.png as attachment ID 1753 and attached to post 123 as featured image. + * * @package wp-cli */ class Media_Command extends WP_CLI_Command { From 32df792a12752165ee13b03cf01c8b45241eeea6 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 26 May 2016 17:28:32 +0545 Subject: [PATCH 4429/5359] Add tests for term url --- features/term.feature | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/features/term.feature b/features/term.feature index 91781bdb9..61b598328 100644 --- a/features/term.feature +++ b/features/term.feature @@ -92,3 +92,22 @@ Feature: Manage WordPress terms """ My Test Category """ + + Scenario: Fetch term url + When I run `wp term create category "First Category" --porcelain` + And save STDOUT as {TERM_ID_1} + And I run `wp term create category "Second Category" --porcelain` + And save STDOUT as {TERM_ID_2} + + When I run `wp term url category {TERM_ID_1}` + Then STDOUT should be: + """ + http://localhost:8001/category/first-category + """ + + When I run `wp term url category {TERM_ID_1} {TERM_ID_2}` + Then STDOUT should be: + """ + http://localhost:8001/category/first-category + http://localhost:8001/category/second-category + """ From 8b0f9ce01e15e8f8b1ccd51cfb36dd9a20543ba0 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 26 May 2016 21:03:37 +0545 Subject: [PATCH 4430/5359] Example: option add --- php/commands/option.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/option.php b/php/commands/option.php index 787c1e808..f35b358fc 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -68,7 +68,8 @@ public function get( $args, $assoc_args ) { * ## EXAMPLES * * # Create an option by reading a JSON file - * wp option add my_option --format=json < config.json + * $ wp option add my_option --format=json < config.json + * Success: Added 'my_option' option. */ public function add( $args, $assoc_args ) { $key = $args[0]; From 1b3ed1b687e4f8f024e416054f9c41288762aa04 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 26 May 2016 21:15:02 +0545 Subject: [PATCH 4431/5359] Example: option delete --- php/commands/option.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index 787c1e808..0552d9b03 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -239,6 +239,11 @@ public function update( $args, $assoc_args ) { * * <key> * : Key for the option. + * + * ## EXAMPLES + * + * $ wp option delete my_option + * Success: Deleted 'my_option' option. */ public function delete( $args ) { list( $key ) = $args; From 76a9d418bcf72080db92dfcea2982d74d90c720b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 26 May 2016 21:31:37 +0545 Subject: [PATCH 4432/5359] modify conditionals in cap list --- php/commands/cap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index b89cea9d6..0663f248e 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -59,7 +59,7 @@ class Capabilities_Command extends WP_CLI_Command { public function list_( $args, $assoc_args ) { $role_obj = self::get_role( $args[0] ); - if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'list' ) ) ) { + if ( 'list' === $assoc_args['format'] ) { foreach ( array_keys( $role_obj->capabilities ) as $cap ) { WP_CLI::line( $cap ); } From cf17c68d5c50aabdab152d2f20eee4916281135e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 26 May 2016 22:31:54 +0545 Subject: [PATCH 4433/5359] Revert export example after fixing aphostrophe error --- php/commands/export.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/export.php b/php/commands/export.php index fa6f61673..d0cbb238c 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -70,6 +70,13 @@ class Export_Command extends WP_CLI_Command { * Starting export process... * Writing to file /tmp/staging.wordpress.2016-05-24.000.xml * Success: All done with export. + * + * # Export a random subset of content + * $ wp export --post__in="$(wp post list --post_type=post --orderby=rand --posts_per_page=8 --format=ids)" + * Starting export process... + * Writing to file /var/www/example.com/public_html/staging.wordpress.2016-05-24.000.xml + * Success: All done with export. + * */ public function __invoke( $_, $assoc_args ) { $defaults = array( From 3bf657b8c5c7f747b0d935875c24ad0320e0f0e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 26 May 2016 16:25:11 -0700 Subject: [PATCH 4434/5359] Mention the WordPress.org Slack channel --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 810fe5ff9..ddda1de27 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,13 @@ WP-CLI version: 0.23.0 ## Support -WP-CLI's project maintainers do their best to respond to all bug reports and configuration errors within reason and the constraints on their volunteered time. Before requesting help, please read to find a solution to your problem in the following resources: +WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: - [Common issues and their fixes](http://wp-cli.org/docs/common-issues/) -- [Submit a bug report](http://wp-cli.org/docs/bug-reports/) -- [External resources](http://wp-cli.org/docs/external-resources/) +- [Best practices for submitting a bug report](http://wp-cli.org/docs/bug-reports/) +- [Documentation portal](http://wp-cli.org/docs/) + +If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). ## Extending From a55c0b903b113d9682f2310cbbb06fe72c9737c3 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:03:10 +0545 Subject: [PATCH 4435/5359] Example: comment create --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..ad0d69dc8 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -40,7 +40,8 @@ public function __construct() { * * ## EXAMPLES * - * wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" + * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" + * Success: Created comment 932. */ public function create( $args, $assoc_args ) { parent::_create( $args, $assoc_args, function ( $params ) { From bee565ad1a97a3a7d2f28cdc2b41e91e9179f6cd Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:06:39 +0545 Subject: [PATCH 4436/5359] Example: comment update --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..31c21ae4e 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -77,7 +77,8 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment update 123 --comment_author='That Guy' + * $ wp comment update 123 --comment_author='That Guy' + * Success: Updated comment 123. */ public function update( $args, $assoc_args ) { parent::_update( $args, $assoc_args, function ( $params ) { From 012a1a55db0dad0cbe7219baeed80f98c9e7ffa4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:16:20 +0545 Subject: [PATCH 4437/5359] Example: comment generate --- php/commands/comment.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..b79783533 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -106,7 +106,10 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * # Add meta to every generated comment - * wp comment generate --format=ids | xargs -0 -d ' ' -I % wp comment meta add % foo bar + * $ wp comment generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp comment meta add % foo bar + * Success: Added custom field. + * Success: Added custom field. + * Success: Added custom field. */ public function generate( $args, $assoc_args ) { From 76ee0c12c67e13a121eacfce2a5412661818a8bb Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:22:19 +0545 Subject: [PATCH 4438/5359] Example: comment get --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..6fdef366f 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -169,7 +169,8 @@ public function generate( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment get 1 --field=content + * $ wp comment get 21 --field=content + * Thanks for all the comments, everyone! */ public function get( $args, $assoc_args ) { $comment_id = (int)$args[0]; From aeeec5e1718338c8f290388f8674b319d21ca155 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:27:17 +0545 Subject: [PATCH 4439/5359] Example: comment delete --- php/commands/comment.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..50e262b58 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -266,9 +266,14 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * wp comment delete 1337 --force - * - * wp comment delete 1337 2341 --force + * # Delete comment + * $ wp comment delete 1337 --force + * Success: Deleted comment 1337. + * + * # Delete multiple comments + * $ wp comment delete 1337 2341 --force + * Success: Deleted comment 1337. + * Success: Deleted comment 2341. */ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { From 47df73a606d4912907fcf14e21532a494fc62ca4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:31:47 +0545 Subject: [PATCH 4440/5359] Example: comment trash --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..1f6b19776 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -323,7 +323,8 @@ private function set_status( $args, $status, $success ) { * * ## EXAMPLES * - * wp comment trash 1337 + * $ wp comment trash 1337 + * Success: Trashed comment 1337. */ public function trash( $args, $assoc_args ) { foreach( $args as $id ) { From e6b13d5888145b7486cb86f2b7389718fc44729a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:34:39 +0545 Subject: [PATCH 4441/5359] Example: comment untrash --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..ea39b811e 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -341,7 +341,8 @@ public function trash( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment untrash 1337 + * $ wp comment untrash 1337 + * Success: Untrashed comment 1337. */ public function untrash( $args, $assoc_args ) { foreach( $args as $id ) { From eae89a299cddede011144803c6fc7f3e00bdf90d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:40:23 +0545 Subject: [PATCH 4442/5359] Example: comment spam --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..5fa930fb4 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -359,7 +359,8 @@ public function untrash( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment spam 1337 + * $ wp comment spam 1337 + * Success: Marked as spam comment 1337. */ public function spam( $args, $assoc_args ) { foreach( $args as $id ) { From 11c6931056f61190008cad63bd9f4c9795febf86 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:42:44 +0545 Subject: [PATCH 4443/5359] Example: comment unspam --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..6996863be 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -377,7 +377,8 @@ public function spam( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment unspam 1337 + * $ wp comment unspam 1337 + * Success: Unspammed comment 1337. */ public function unspam( $args, $assoc_args ) { foreach( $args as $id ) { From d329d3b36fd0a5215a40e24cac0f38cbf322e542 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:46:07 +0545 Subject: [PATCH 4444/5359] Example: comment approve --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..244628c04 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -395,7 +395,8 @@ public function unspam( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment approve 1337 + * $ wp comment approve 1337 + * Success: Approved comment 1337 */ public function approve( $args, $assoc_args ) { foreach( $args as $id ) { From 3db9c15a5e4900578745468ae0338664e55f963d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:48:46 +0545 Subject: [PATCH 4445/5359] Example: comment unapprove --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..7f9733162 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -413,7 +413,8 @@ public function approve( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment unapprove 1337 + * $ wp comment unapprove 1337 + * Success: Unapproved comment 1337 */ public function unapprove( $args, $assoc_args ) { foreach( $args as $id ) { From bf8a386096de03bc63089350330fe555cdf33f34 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 06:56:33 +0545 Subject: [PATCH 4446/5359] Example: comment count --- php/commands/comment.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..a7e8956e0 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -431,8 +431,25 @@ public function unapprove( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment count - * wp comment count 42 + * # Count comments on whole blog + * $ wp comment count + * approved: 33 + * spam: 3 + * trash: 1 + * post-trashed: 0 + * all: 34 + * moderated: 1 + * total_comments: 37 + * + * # Count comments in a post + * $ wp comment count 42 + * approved: 19 + * spam: 0 + * trash: 0 + * post-trashed: 0 + * all: 19 + * moderated: 0 + * total_comments: 19 */ public function count( $args, $assoc_args ) { $post_id = \WP_CLI\Utils\get_flag_value( $args, 0, 0 ); From d0cc6d11e779169ef95f0f6d03d1bba6c68a0ed5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 07:07:20 +0545 Subject: [PATCH 4447/5359] Example: comment recount --- php/commands/comment.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..35b23aa5e 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -456,6 +456,11 @@ public function count( $args, $assoc_args ) { * * <id>... * : IDs for one or more posts to update. + * + * ## EXAMPLES + * + * $ wp comment recount 123 + * Updated post 123 comment count to 67 */ public function recount( $args ) { foreach( $args as $id ) { From 60141c24620184992acf33c04d8daa48293116f6 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 07:10:07 +0545 Subject: [PATCH 4448/5359] Example: comment status --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..1cd4e01de 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -479,7 +479,8 @@ public function recount( $args ) { * * ## EXAMPLES * - * wp comment status 1337 + * $ wp comment status 1337 + * approved */ public function status( $args, $assoc_args ) { list( $comment_id ) = $args; From 235937eb7cabe0d62cc0fa2ed538c30c787afd0a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 07:12:52 +0545 Subject: [PATCH 4449/5359] Example: comment exists --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..e6396bd76 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -503,7 +503,8 @@ public function status( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment exists 1337 + * $ wp comment exists 1337 + * Success: Comment with ID 1337 exists. */ public function exists( $args ) { if ( $this->fetcher->get( $args[0] ) ) { From 94ca05e48f8f6de229fe132fb108cf67e46426ab Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 27 May 2016 07:16:50 +0545 Subject: [PATCH 4450/5359] Example: comment url --- php/commands/comment.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a29f135b2..736e45071 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -521,7 +521,8 @@ public function exists( $args ) { * * ## EXAMPLES * - * wp comment url 123 + * $ wp comment url 123 + * http://example.com/about/page-with-comments/#comment-123 */ public function url( $args ) { parent::_url( $args, 'get_comment_link' ); From 33a28043c7fa57b0fdb8a437a28d83cc1153116e Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:11:33 +0000 Subject: [PATCH 4451/5359] add indent #2849 --- php/commands/cli.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index ba8aa7df3..c49b5d630 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -106,8 +106,8 @@ public function info( $_, $assoc_args ) { * * ## EXAMPLES * - * $ wp cli check-update - * Success: WP-CLI is at the latest version. + * $ wp cli check-update + * Success: WP-CLI is at the latest version. * * @subcommand check-update */ @@ -329,19 +329,19 @@ private function get_updates( $assoc_args ) { * * ## EXAMPLES * - * $ wp cli param-dump --format=var_export - * array ( - * 'path' => - * array ( - * 'runtime' => '=<path>', - * 'file' => '<path>', - * 'synopsis' => '', - * 'default' => NULL, - * 'multiple' => false, - * 'desc' => 'Path to the WordPress files.', - * ), - * 'url' => - * array ( + * $ wp cli param-dump --format=var_export + * array ( + * 'path' => + * array ( + * 'runtime' => '=<path>', + * 'file' => '<path>', + * 'synopsis' => '', + * 'default' => NULL, + * 'multiple' => false, + * 'desc' => 'Path to the WordPress files.', + * ), + * 'url' => + * array ( * * @subcommand param-dump */ From 6e7761c726ca9a1803ac15ae68cf5c769f1876a8 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:19:34 +0000 Subject: [PATCH 4452/5359] Example: site list, #2770 --- php/commands/site.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..1e8120930 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -413,7 +413,9 @@ private function _get_network( $network_id ) { * ## EXAMPLES * * # Output a simple list of site URLs - * wp site list --field=url + * $ wp site list --field=url + * http://example.com/ + * http://example.com/subdir/ * * @subcommand list */ From f679058304ee6b1c832f2fae26eab568249bbb57 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:25:48 +0000 Subject: [PATCH 4453/5359] Example: site deactivate, #2770 --- php/commands/site.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..bb0b4b0e0 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -527,7 +527,8 @@ public function activate( $args ) { * * ## EXAMPLES * - * wp site deactivate 123 + * $ wp site deactivate 123 + * Success: Site 123 deactivated. */ public function deactivate( $args ) { $this->update_site_status( $args, 'deleted', 1 ); From a7555d4153cac70504af2143370799c3fb2148fe Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:27:11 +0000 Subject: [PATCH 4454/5359] Example: site activate, #2770 --- php/commands/site.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..c7dfc974a 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -511,7 +511,8 @@ public function unarchive( $args ) { * * ## EXAMPLES * - * wp site activate 123 + * $ wp site activate 123 + * Success: Site 123 activated. */ public function activate( $args ) { $this->update_site_status( $args, 'deleted', 0 ); From ae5a92c3781f817c18aecd2d8c433fccbe7aad92 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:28:57 +0000 Subject: [PATCH 4455/5359] Example: site span & unspam, #2770 --- php/commands/site.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..ee0eb26ba 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -543,7 +543,8 @@ public function deactivate( $args ) { * * ## EXAMPLES * - * wp site spam 123 + * $ wp site spam 123 + * Success: Site 123 marked as spam. */ public function spam( $args ) { $this->update_site_status( $args, 'spam', 1 ); @@ -559,7 +560,8 @@ public function spam( $args ) { * * ## EXAMPLES * - * wp site unspam 123 + * $ wp site unspam 123 + * Success: Site 123 removed from spam. * * @subcommand unspam */ From e3abc278bcf6a2969228bf69a85956ff23491b77 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:32:00 +0000 Subject: [PATCH 4456/5359] Example: site archive & unarchive, #2770 --- php/commands/site.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..0df3bbdfc 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -479,7 +479,8 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * wp site archive 123 + * $ wp site archive 123 + * Success: Site 123 archived. */ public function archive( $args ) { $this->update_site_status( $args, 'archived', 1 ); @@ -495,7 +496,8 @@ public function archive( $args ) { * * ## EXAMPLES * - * wp site unarchive 123 + * $ wp site unarchive 123 + * Success: Site 123 unarchived. */ public function unarchive( $args ) { $this->update_site_status( $args, 'archived', 0 ); From b3ecaf96452da7648ad92ada746761bc401d40f5 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Fri, 27 May 2016 16:34:50 +0000 Subject: [PATCH 4457/5359] Example: site delete, #2770 --- php/commands/site.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 5778c16d5..b010e2e2d 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -197,6 +197,13 @@ public function _empty( $args, $assoc_args ) { * * [--keep-tables] * : Delete the blog from the list, but don't drop it's tables. + * + * ## EXAMPLES + * + * $ wp site delete 123 + * Are you sure you want to delete the http://www.example.com/example site? [y/n] y + * Success: The site at http://www.example.com/example was deleted. + * */ function delete( $args, $assoc_args ) { if ( !is_multisite() ) { From 43d312fc3ebd5cb464664e2979841eab4f977c07 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 07:21:03 +0545 Subject: [PATCH 4458/5359] fix strange test issue in term url --- features/term.feature | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/features/term.feature b/features/term.feature index 61b598328..d2e45f1ea 100644 --- a/features/term.feature +++ b/features/term.feature @@ -95,19 +95,19 @@ Feature: Manage WordPress terms Scenario: Fetch term url When I run `wp term create category "First Category" --porcelain` - And save STDOUT as {TERM_ID_1} + And save STDOUT as {TERM_ID} And I run `wp term create category "Second Category" --porcelain` - And save STDOUT as {TERM_ID_2} + And save STDOUT as {SECOND_TERM_ID} - When I run `wp term url category {TERM_ID_1}` + When I run `wp term url category {TERM_ID}` Then STDOUT should be: """ - http://localhost:8001/category/first-category + http://example.com/?cat=2 """ - When I run `wp term url category {TERM_ID_1} {TERM_ID_2}` + When I run `wp term url category {TERM_ID} {SECOND_TERM_ID}` Then STDOUT should be: """ - http://localhost:8001/category/first-category - http://localhost:8001/category/second-category + http://example.com/?cat=2 + http://example.com/?cat=3 """ From 64a764b0639d715454d1ede741ab9f38bb588e6b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 08:00:45 +0545 Subject: [PATCH 4459/5359] fix comment id issue in spam and unspam --- php/commands/comment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 34a912cc7..47891656e 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -301,7 +301,7 @@ public function delete( $args, $assoc_args ) { } private function call( $args, $status, $success, $failure ) { - list( $comment_id ) = $args; + $comment_id = absint( $args ); $func = sprintf( 'wp_%s_comment', $status ); @@ -395,7 +395,7 @@ public function spam( $args, $assoc_args ) { */ public function unspam( $args, $assoc_args ) { foreach( $args as $id ) { - $this->call( $args, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); + $this->call( $id, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); } } From b473ca695beea373a82e961e76f39c1090b7de32 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 08:04:39 +0545 Subject: [PATCH 4460/5359] add test for comment spam/unspam --- features/comment.feature | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index ef11b422c..12a28912d 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -190,3 +190,32 @@ Feature: Manage WordPress comments 11 """ + Scenario: Spam/unspam comments with multidigit comment ID + Given I run `wp comment delete $(wp comment list --field=ID)` + And I run `wp comment generate --count=10 --quiet` + And I run `wp comment create --porcelain` + And save STDOUT as {COMMENT_ID} + + When I run `wp comment spam {COMMENT_ID}` + Then STDOUT should contain: + """ + Marked as spam comment {COMMENT_ID}. + """ + + When I run `wp comment list --format=count --status=spam` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp comment unspam {COMMENT_ID}` + Then STDOUT should contain: + """ + Unspammed comment {COMMENT_ID}. + """ + + When I run `wp comment list --format=count --status=spam` + Then STDOUT should be: + """ + 0 + """ From 2512afdf71416d6810093fe25d6f29335f0d64b3 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 08:21:11 +0545 Subject: [PATCH 4461/5359] add test for comment trash/unstrash with multidigit comment ID --- features/comment.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 12a28912d..0eaacc004 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -219,3 +219,33 @@ Feature: Manage WordPress comments """ 0 """ + + Scenario: Trash/untrash comments with multidigit comment ID + Given I run `wp comment delete $(wp comment list --field=ID) --force` + And I run `wp comment generate --count=10 --quiet` + And I run `wp comment create --porcelain` + And save STDOUT as {COMMENT_ID} + + When I run `wp comment trash {COMMENT_ID}` + Then STDOUT should contain: + """ + Success: Trashed comment {COMMENT_ID}. + """ + + When I run `wp comment list --format=count --status=trash` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp comment untrash {COMMENT_ID}` + Then STDOUT should contain: + """ + Untrashed comment {COMMENT_ID}. + """ + + When I run `wp comment list --format=count --status=trash` + Then STDOUT should be: + """ + 0 + """ From 4784ac1f72cdc880e422fcadd252557e6e8a09e2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 10:23:01 +0545 Subject: [PATCH 4462/5359] Add more tests for scaffold child-theme --- features/scaffold.feature | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 9b52d6cd6..7ece65d81 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -9,6 +9,38 @@ Feature: WordPress code scaffolding When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com` Then STDOUT should not be empty And the {THEME_DIR}/zombieland/style.css file should exist + And the {THEME_DIR}/zombieland/functions.php file should exist + + Scenario: Scaffold a child theme with only --parent_theme parameter + Given a WP install + Given I run `wp theme path` + And save STDOUT as {THEME_DIR} + + When I run `wp scaffold child-theme hello-world --parent_theme=simple-life` + Then STDOUT should not be empty + And the {THEME_DIR}/hello-world/style.css file should exist + And the {THEME_DIR}/hello-world/style.css file should contain: + """ + Theme Name: Hello-world + """ + + Scenario: Scaffold a child theme with non existing parent theme and also activate parameter + Given a WP install + + When I try `wp scaffold child-theme hello-world --parent_theme=just-test --activate --quiet` + Then STDERR should contain: + """ + Error: The parent theme is missing. Please install the "just-test" parent theme. + """ + + Scenario: Scaffold a child theme with non existing parent theme and also network activate parameter + Given a WP install + + When I try `wp scaffold child-theme hello-world --parent_theme=just-test --enable-network --quiet` + Then STDERR should contain: + """ + Error: This is not a multisite install. + """ Scenario: Scaffold a child theme and network enable it Given a WP multisite install From b9c64f963361678c4f488ff99bc74122d6a4e4db Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 11:54:37 +0545 Subject: [PATCH 4463/5359] Example: comment list --- php/commands/comment.php | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 34a912cc7..b8b5f6045 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -235,11 +235,29 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp comment list --field=ID - * - * wp comment list --post_id=2 - * - * wp comment list --number=20 --status=approve + * # List comment IDs + * $ wp comment list --field=ID + * 22 + * 23 + * 24 + * + * # List comments of a post + * $ wp comment list --post_id=1 --fields=ID,comment_date,comment_author + * +------------+---------------------+----------------+ + * | comment_ID | comment_date | comment_author | + * +------------+---------------------+----------------+ + * | 1 | 2015-06-20 09:00:10 | Mr WordPress | + * +------------+---------------------+----------------+ + * + * # List approved comments + * $ wp comment list --number=3 --status=approve --fields=ID,comment_date,comment_author + * +------------+---------------------+----------------+ + * | comment_ID | comment_date | comment_author | + * +------------+---------------------+----------------+ + * | 1 | 2015-06-20 09:00:10 | Mr WordPress | + * | 30 | 2013-03-14 12:35:07 | John Doe | + * | 29 | 2013-03-14 11:56:08 | Jane Doe | + * +------------+---------------------+----------------+ * * @subcommand list */ From 016447447f3c053e0ccb5e03433f499a81a92a6e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:01:12 +0545 Subject: [PATCH 4464/5359] Examples for comment main --- php/commands/comment.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 34a912cc7..341421040 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -5,8 +5,22 @@ * * ## EXAMPLES * - * # delete all spam comments. - * wp comment delete $(wp comment list --status=spam --format=ids) + * # Create comment + * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" + * Success: Created comment 932. + * + * # Update comment + * $ wp comment update 123 --comment_author='That Guy' + * Success: Updated comment 123. + * + * # Delete comment + * $ wp comment delete 1337 --force + * Success: Deleted comment 1337. + * + * # Delete all spam comments. + * $ wp comment delete $(wp comment list --status=spam --format=ids) + * Success: Deleted comment 264. + * Success: Deleted comment 262. * * @package wp-cli */ From 00f94bfd25673ed8c15b5fa5cb4ae9d53f8423b5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:06:10 +0545 Subject: [PATCH 4465/5359] Examples for comment meta --- php/commands/comment.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index 34a912cc7..4be14dcfa 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -579,7 +579,21 @@ public function url( $args ) { * * ## EXAMPLES * - * wp comment meta set 123 description "Mary is a WordPress developer." + * # Set comment meta + * $ wp comment meta set 123 description "Mary is a WordPress developer." + * Success: Updated custom field 'description'. + * + * # Get comment meta + * $ wp comment meta get 123 description + * Mary is a WordPress developer. + * + * # Update comment meta + * $ wp comment meta update 123 description "Mary is an awesome WordPress developer." + * Success: Updated custom field 'description'. + * + * # Delete comment meta + * $ wp comment meta delete 123 description + * Success: Deleted custom field. */ class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'comment'; From d9335ebdb87989410b5dd7dd91220711cf014dfd Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:18:38 +0545 Subject: [PATCH 4466/5359] Examples for term main class --- php/commands/term.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index 58b9c1bc0..92119f5b0 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -2,6 +2,33 @@ /** * Manage terms. * + * ## EXAMPLES + * + * # Create term + * $ wp term create category Apple --description="A type of fruit" + * Success: Created category 199. + * + * # Get term + * $ wp term get category 199 --format=json --fields=term_id,name,slug,count + * {"term_id":199,"name":"Apple","slug":"apple","count":1} + * + * # Update term + * $ wp term update category 15 --name=Apple + * Success: Term updated. + * + * # Get term url + * $ wp term url post_tag 123 + * http://example.com/tag/tips-and-tricks + * + * # Delete post category + * $ wp term delete category 15 + * Success: Deleted category 15. + * + * # Recount posts assigned to each categories and tags + * $ wp term recount category post_tag + * Success: Updated category term count + * Success: Updated post_tag term count + * * @package wp-cli */ class Term_Command extends WP_CLI_Command { From ec381cc75f8d505ee12d9da4b12e264ccfa0b7ec Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:36:00 +0545 Subject: [PATCH 4467/5359] Examples for menu main class --- php/commands/menu.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..4afa70057 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -6,16 +6,25 @@ * ## EXAMPLES * * # Create a new menu - * wp menu create "My Menu" + * $ wp menu create "My Menu" + * Success: Created menu 200. * * # List existing menus - * wp menu list + * $ wp menu list + * +---------+----------+----------+-----------+-------+ + * | term_id | name | slug | locations | count | + * +---------+----------+----------+-----------+-------+ + * | 200 | My Menu | my-menu | | 0 | + * | 177 | Top Menu | top-menu | primary | 7 | + * +---------+----------+----------+-----------+-------+ * * # Create a new menu link item - * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain + * $ wp menu item add-custom my-menu Apple http://apple.com --porcelain + * 1922 * - * # Assign the 'primary-menu' menu to the 'primary' location - * wp menu location assign primary-menu primary + * # Assign the 'my-menu' menu to the 'primary' location + * $ wp menu location assign my-menu primary + * Success: Assigned location to menu. */ class Menu_Command extends WP_CLI_Command { From a30f3bc3023ba239b0b470e4d911906b7d13bf53 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:39:34 +0545 Subject: [PATCH 4468/5359] Example: menu create --- php/commands/menu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..3b7f86140 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -41,7 +41,8 @@ class Menu_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp menu create "My Menu" + * $ wp menu create "My Menu" + * Success: Created menu 200. */ public function create( $args, $assoc_args ) { From e93ff861e38c523c46ec0b59fb73747db70fe98e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:42:19 +0545 Subject: [PATCH 4469/5359] Example: menu list --- php/commands/menu.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..9c03a4f60 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -123,7 +123,13 @@ public function delete( $args, $_ ) { * * ## EXAMPLES * - * wp menu list + * $ wp menu list + * +---------+----------+----------+-----------+-------+ + * | term_id | name | slug | locations | count | + * +---------+----------+----------+-----------+-------+ + * | 200 | My Menu | my-menu | | 0 | + * | 177 | Top Menu | top-menu | primary | 7 | + * +---------+----------+----------+-----------+-------+ * * @subcommand list */ From 16dbc9cd58951f0f67e35f0c2bf5f09f6cd2aca1 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 12:44:39 +0545 Subject: [PATCH 4470/5359] Example: menu delete --- php/commands/menu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..5cd837939 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -72,7 +72,8 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu delete "My Menu" + * $ wp menu delete "My Menu" + * Success: Menu(s) deleted. */ public function delete( $args, $_ ) { From fedda19193124b8de97623d0a81754f52a667cb5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 15:43:40 +0545 Subject: [PATCH 4471/5359] Example: menu location list --- php/commands/menu.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..f5c0f3f5b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -661,7 +661,13 @@ class Menu_Location_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp menu location list + * $ wp menu location list + * +----------+-------------------+ + * | location | description | + * +----------+-------------------+ + * | primary | Primary Menu | + * | social | Social Links Menu | + * +----------+-------------------+ * * @subcommand list */ From 4906bd31254dbacd01cbc8f6dc6e3b2782adf55a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 15:46:39 +0545 Subject: [PATCH 4472/5359] Example: menu location assign --- php/commands/menu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..8b7bf4143 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -693,7 +693,8 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * wp menu location assign primary-menu primary + * $ wp menu location assign primary-menu primary + * Success: Assigned location to menu. * * @subcommand assign */ From 60a1a3665debad7d3c1f53fdd5d1d2706f512a8d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 15:54:37 +0545 Subject: [PATCH 4473/5359] Example: menu location remove --- php/commands/menu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index b4272494f..26e323b5b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -732,7 +732,8 @@ public function assign( $args, $_ ) { * * ## EXAMPLES * - * wp menu location remove primary-menu primary + * $ wp menu location remove primary-menu primary + * Success: Removed location from menu. * * @subcommand remove */ From 07069c9cf6ac2c4bbe4705423c02112e7b841f9e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 21:57:55 +0545 Subject: [PATCH 4474/5359] Example: theme enable --- php/commands/theme.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 2ff81bbf9..7ef8f1406 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -200,11 +200,17 @@ public function activate( $args = array() ) { * * ## EXAMPLES * - * wp theme enable twentythirteen + * # Enable theme + * $ wp theme enable twentysixteen + * Success: Enabled the 'Twenty Sixteen' theme. * - * wp theme enable twentythirteen --network + * # Network enable theme + * $ wp theme enable twentysixteen --network + * Success: Network enabled the 'Twenty Sixteen' theme. * - * wp theme enable twentythirteen --activate + * # Network enable and activate theme for current site + * $ wp theme enable twentysixteen --activate + * Success: Enabled the 'Twenty Sixteen' theme. */ public function enable( $args, $assoc_args ) { if ( ! is_multisite() ) { From 3f76e9f64aa0e3133d74b1cdb2862335ae27f112 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 28 May 2016 22:02:43 +0545 Subject: [PATCH 4475/5359] Add missing success message in theme enable with activate --- php/commands/theme.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 7ef8f1406..d2f3443e4 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -211,6 +211,7 @@ public function activate( $args = array() ) { * # Network enable and activate theme for current site * $ wp theme enable twentysixteen --activate * Success: Enabled the 'Twenty Sixteen' theme. + * Success: Switched to 'Twenty Sixteen' theme. */ public function enable( $args, $assoc_args ) { if ( ! is_multisite() ) { From d4575b938156465aef06d6f8af9913319fec8b8c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 31 May 2016 09:01:07 +0545 Subject: [PATCH 4476/5359] Add examples for db commands --- php/commands/db.php | 71 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 6c87dcb24..cb5afe820 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -13,6 +13,11 @@ class DB_Command extends WP_CLI_Command { * Runs `CREATE_DATABASE` MySQL statement using `DB_HOST`, `DB_NAME`, * `DB_USER` and `DB_PASSWORD` database credentials specified in * wp-config.php. + * + * ## EXAMPLES + * + * $ wp db create + * Success: Database created. */ public function create( $_, $assoc_args ) { @@ -32,7 +37,7 @@ public function create( $_, $assoc_args ) { * * [--yes] * : Answer yes to the confirmation message. - * + * * ## EXAMPLES * * $ wp db drop --yes @@ -57,7 +62,7 @@ public function drop( $_, $assoc_args ) { * * [--yes] * : Answer yes to the confirmation message. - * + * * ## EXAMPLES * * $ wp db reset --yes @@ -81,6 +86,11 @@ public function reset( $_, $assoc_args ) { * * [See docs](http://dev.mysql.com/doc/refman/5.7/en/optimize-table.html) * for more details on the `OPTIMIZE_TABLE` statement. + * + * ## EXAMPLES + * + * $ wp db optimize + * Success: Database optimized. */ public function optimize() { self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( @@ -99,6 +109,11 @@ public function optimize() { * * [See docs](http://dev.mysql.com/doc/refman/5.7/en/repair-table.html) for * more details on the `REPAIR_TABLE` statement. + * + * ## EXAMPLES + * + * $ wp db repair + * Success: Database repaired. */ public function repair() { self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( @@ -111,6 +126,12 @@ public function repair() { /** * Open a MySQL console using credentials from wp-config.php * + * ## EXAMPLES + * + * # Open MySQL console + * $ wp db cli + * mysql> + * * @alias connect */ public function cli() { @@ -132,11 +153,27 @@ public function cli() { * * ## EXAMPLES * - * # execute a query stored in a file + * # Execute a query stored in a file * wp db query < debug.sql * - * # check all tables in the database + * # Check all tables in the database * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" + * +---------------------------------------+-------+----------+----------+ + * | Table | Op | Msg_type | Msg_text | + * +---------------------------------------+-------+----------+----------+ + * | wordpress_dbase.wp_users | check | status | OK | + * | wordpress_dbase.wp_usermeta | check | status | OK | + * | wordpress_dbase.wp_posts | check | status | OK | + * | wordpress_dbase.wp_comments | check | status | OK | + * | wordpress_dbase.wp_links | check | status | OK | + * | wordpress_dbase.wp_options | check | status | OK | + * | wordpress_dbase.wp_postmeta | check | status | OK | + * | wordpress_dbase.wp_terms | check | status | OK | + * | wordpress_dbase.wp_term_taxonomy | check | status | OK | + * | wordpress_dbase.wp_term_relationships | check | status | OK | + * | wordpress_dbase.wp_termmeta | check | status | OK | + * | wordpress_dbase.wp_commentmeta | check | status | OK | + * +---------------------------------------+-------+----------+----------+ */ public function query( $args ) { $assoc_args = array( @@ -170,14 +207,21 @@ public function query( $args ) { * * ## EXAMPLES * - * wp db export --add-drop-table - * wp db export --tables=wp_options,wp_users + * # Export database with drop query included + * $ wp db export --add-drop-table + * Success: Exported to wordpress_dbase.sql + * + * # Export certain tables + * $ wp db export --tables=wp_options,wp_users + * Success: Exported to wordpress_dbase.sql * * # Export all tables matching a wildcard - * wp db export --tables=$(wp db tables 'wp_user*' --format=csv) + * $ wp db export --tables=$(wp db tables 'wp_user*' --format=csv) + * Success: Exported to wordpress_dbase.sql * * # Export all tables matching prefix - * wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) + * $ wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) + * Success: Exported to wordpress_dbase.sql * * @alias dump */ @@ -218,6 +262,11 @@ function export( $args, $assoc_args ) { * * [<file>] * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. + * + * ## EXAMPLES + * + * $ wp db import wordpress_dbase.sql + * Success: Imported from wordpress_dbase.sql */ public function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); @@ -275,10 +324,8 @@ public function import( $args, $assoc_args ) { * ## EXAMPLES * * # Export only tables for a single site - * wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) - * - * # Export all tables matching prefix - * wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) + * $ wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) + * Success: Exported to wordpress_dbase.sql */ function tables( $args, $assoc_args ) { From 86f996dee7aded45c87ec5c0880ce2332ab5a029 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 31 May 2016 16:15:59 +0545 Subject: [PATCH 4477/5359] Add examples for cron commands --- php/commands/cron.php | 56 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 4f8a6a4f6..d552661f6 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -49,9 +49,19 @@ class Cron_Event_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp cron event list - * - * wp cron event list --fields=hook,next_run --format=json + * # List scheduled cron events + * $ wp cron event list + * +-------------------+---------------------+---------------------+------------+ + * | hook | next_run_gmt | next_run_relative | recurrence | + * +-------------------+---------------------+---------------------+------------+ + * | wp_version_check | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | + * | wp_update_plugins | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | + * | wp_update_themes | 2016-05-31 22:15:14 | 11 hours 57 minutes | 12 hours | + * +-------------------+---------------------+---------------------+------------+ + * + * # List scheduled cron events in JSON + * $ wp cron event list --fields=hook,next_run --format=json + * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] * * @subcommand list */ @@ -100,11 +110,17 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp cron event schedule cron_test + * # Schedule a new cron event + * $ wp cron event schedule cron_test + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. * - * wp cron event schedule cron_test now hourly + * # Schedule new cron event with hourly recurrence + * $ wp cron event schedule cron_test now hourly + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:20:32 GMT. * - * wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 + * # Schedule new cron event and pass associative arguments + * $ wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 11:21:35 GMT. */ public function schedule( $args, $assoc_args ) { @@ -165,7 +181,8 @@ public function schedule( $args, $assoc_args ) { * ## EXAMPLES * * # Run all cron events due right now - * wp cron event run --due-now + * $ wp cron event run --due-now + * Success: Executed a total of 2 cron event(s). */ public function run( $args, $assoc_args ) { @@ -248,6 +265,12 @@ protected static function run_event( stdClass $event ) { * * <hook> * : The hook name + * + * ## EXAMPLES + * + * # Delete the next scheduled cron event + * $ wp cron event delete cron_test + * Success: Deleted 2 instances of the cron event 'cron_test' */ public function delete( $args, $assoc_args ) { @@ -454,9 +477,19 @@ class Cron_Schedule_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp cron schedule list + * # List available cron schedules + * $ wp cron schedule list + * +------------+-------------+----------+ + * | name | display | interval | + * +------------+-------------+----------+ + * | hourly | Once Hourly | 3600 | + * | twicedaily | Twice Daily | 43200 | + * | daily | Once Daily | 86400 | + * +------------+-------------+----------+ * - * wp cron schedule list --fields=name --format=ids + * # List id of available cron schedule + * $ wp cron schedule list --fields=name --format=ids + * hourly twicedaily daily * * @subcommand list */ @@ -527,6 +560,11 @@ class Cron_Command extends WP_CLI_Command { * * Checks to see if the `ALTERNATE_WP_CRON` constant is set; warns if true * * Attempts to spawn WP-Cron over HTTP; warns if non 200 response code is * returned. + * + * ## EXAMPLES + * + * $ wp cron test + * Success: WP-Cron spawning is working as expected. */ public function test() { From daf08407233c9c435ce41cdbb66255ad946ea2dd Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 31 May 2016 16:20:56 +0545 Subject: [PATCH 4478/5359] Examples for menu location commands --- php/commands/menu.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 1ba04d14d..095047a21 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -651,13 +651,21 @@ protected function get_formatter( &$assoc_args ) { * ## EXAMPLES * * # List available menu locations - * wp menu location list + * $ wp menu location list + * +----------+-------------------+ + * | location | description | + * +----------+-------------------+ + * | primary | Primary Menu | + * | social | Social Links Menu | + * +----------+-------------------+ * * # Assign the 'primary-menu' menu to the 'primary' location - * wp menu location assign primary-menu primary + * $ wp menu location assign primary-menu primary + * Success: Assigned location to menu. * * # Remove the 'primary-menu' menu from the 'primary' location - * wp menu location remove primary-menu primary + * $ wp menu location remove primary-menu primary + * Success: Removed location from menu. */ class Menu_Location_Command extends WP_CLI_Command { From 92b8cf91770541301a4e1c43818ccd8fb7ec6fe7 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 31 May 2016 16:41:23 +0545 Subject: [PATCH 4479/5359] Add examples for Menu Item main class --- php/commands/menu.php | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 1ba04d14d..6d3855f4e 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -187,10 +187,16 @@ protected function get_formatter( &$assoc_args ) { * ## EXAMPLES * * # Add an existing post to an existing menu - * wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * Success: Menu item added. * * # Create a new menu link item - * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain + * $ wp menu item add-custom sidebar-menu Apple http://apple.com + * Success: Menu item added. + * + * # Delete menu item + * $ wp menu item delete 45 + * Success: Menu item(s) deleted. */ class Menu_Item_Command extends WP_CLI_Command { @@ -241,7 +247,13 @@ class Menu_Item_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp menu item list <menu> + * $ wp menu item list main-menu + * +-------+-----------+-------------+---------------------------------+----------+ + * | db_id | type | title | link | position | + * +-------+-----------+-------------+---------------------------------+----------+ + * | 5 | custom | Home | http://example.com | 1 | + * | 6 | post_type | Sample Page | http://example.com/sample-page/ | 2 | + * +-------+-----------+-------------+---------------------------------+----------+ * * @subcommand list */ @@ -311,7 +323,8 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * Success: Menu item added. * * @subcommand add-post */ @@ -371,7 +384,8 @@ public function add_post( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item add-term sidebar-menu post_tag 24 + * $ wp menu item add-term sidebar-menu post_tag 24 + * Success: Menu item added. * * @subcommand add-term */ @@ -426,7 +440,8 @@ public function add_term( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain + * $ wp menu item add-custom sidebar-menu Apple http://apple.com + * Success: Menu item added. * * @subcommand add-custom */ @@ -473,7 +488,8 @@ public function add_custom( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 + * $ wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 + * Success: Menu item updated. * * @subcommand update */ @@ -502,7 +518,8 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * wp menu item delete 45 + * $ wp menu item delete 45 + * Success: Menu item(s) deleted. * * @subcommand delete */ From c25542260a960346342d9ca224e3ac823d85d7da Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 31 May 2016 06:00:02 -0700 Subject: [PATCH 4480/5359] Prevent pass by reference PHP notice --- php/WP_CLI/CommandWithTranslation.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index d4735e9c3..628f57f7f 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -176,9 +176,10 @@ public function update( $args, $assoc_args ) { } // Gets the translation data. - $translation = (object) reset( wp_list_filter( $all_languages, array( + $translation = wp_list_filter( $all_languages, array( 'language' => $update->language - ) ) ); + ) ); + $translation = (object) reset( $translation ); $update->Type = ucfirst( $update->type ); $update->Name = $name; From c3148b4d7a2794fd7e8814bc6b2b445ac46e52ea Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 20:19:40 +0545 Subject: [PATCH 4481/5359] Example: cron schedule --- php/commands/cron.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index d552661f6..1fe92de68 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -442,6 +442,18 @@ private function get_formatter( &$assoc_args ) { /** * Manage WP-Cron schedules. + * + * ## EXAMPLES + * + * # List available cron schedules + * $ wp cron schedule list + * +------------+-------------+----------+ + * | name | display | interval | + * +------------+-------------+----------+ + * | hourly | Once Hourly | 3600 | + * | twicedaily | Twice Daily | 43200 | + * | daily | Once Daily | 86400 | + * +------------+-------------+----------+ */ class Cron_Schedule_Command extends WP_CLI_Command { From b89175b19115bdc2790611f4d71f2fd3bb11e280 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 20:24:51 +0545 Subject: [PATCH 4482/5359] Example for main cron command --- php/commands/cron.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index d552661f6..ed9c498b2 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -548,6 +548,12 @@ private function get_formatter( &$assoc_args ) { /** * Manage WP-Cron events and schedules. + * + * ## EXAMPLES + * + * # Test WP Cron spawning system + * $ wp cron test + * Success: WP-Cron spawning is working as expected. */ class Cron_Command extends WP_CLI_Command { From 6a392cba4ca7f143e351478df6d2621e9d4f9a4d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 20:31:12 +0545 Subject: [PATCH 4483/5359] Examples for cron event main command class --- php/commands/cron.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index d552661f6..b34dfcd47 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -3,6 +3,24 @@ /** * Manage WP-Cron events. * + * ## EXAMPLES + * + * # Schedule a new cron event + * $ wp cron event schedule cron_test + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. + * + * # Run all cron events due right now + * $ wp cron event run --due-now + * Success: Executed a total of 2 cron event(s). + * + * # Delete the next scheduled cron event + * $ wp cron event delete cron_test + * Success: Deleted 2 instances of the cron event 'cron_test' + * + * # List scheduled cron events in JSON + * $ wp cron event list --fields=hook,next_run --format=json + * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] + * */ class Cron_Event_Command extends WP_CLI_Command { From 642be052ff7242e73c06cfd359d8a14876ec3d3b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 20:52:48 +0545 Subject: [PATCH 4484/5359] Add examples for subcommands of cli --- php/commands/cli.php | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index c49b5d630..ee8ac7b7e 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -7,6 +7,23 @@ /** * Get information about WP-CLI itself. * + * ## EXAMPLES + * + * # Display CLI version + * $ wp cli version + * WP-CLI 0.23.1 + * + * # Check for update + * $ wp cli check-update + * Success: WP-CLI is at the latest version. + * + * # Update CLI + * $ wp cli update + * You have version 0.23.0. Would you like to update to 0.23.1? [y/n] y + * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar... + * New version works. Proceeding to replace. + * Success: Updated WP-CLI to 0.23.1 + * * @when before_wp_load */ class CLI_Command extends WP_CLI_Command { @@ -31,6 +48,11 @@ private function command_to_array( $command ) { /** * Print WP-CLI version. + * + * ## EXAMPLES + * + * $ wp cli version + * WP-CLI 0.23.1 */ public function version() { WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); @@ -46,8 +68,15 @@ public function version() { * * ## EXAMPLES * - * $ wp cli version - * WP-CLI 0.23.1 + * $ wp cli info + * PHP binary: /usr/bin/php5 + * PHP version: 5.5.9-1ubuntu4.16 + * php.ini used: /etc/php5/cli/php.ini + * WP-CLI root dir: phar://wp-cli.phar + * WP-CLI packages dir: /home/person/.wp-cli/packages/ + * WP-CLI global config: + * WP-CLI project config: + * WP-CLI version: 0.23.1 */ public function info( $_, $assoc_args ) { $php_bin = WP_CLI::get_php_binary(); @@ -105,10 +134,19 @@ public function info( $_, $assoc_args ) { * : Accepted values: table, csv, json, count. Default: table * * ## EXAMPLES - * + * + * # Check for update * $ wp cli check-update * Success: WP-CLI is at the latest version. * + * # Check for update and new version is available + * $ wp cli check-update + * +---------+-------------+-------------------------------------------------------------------------------+ + * | version | update_type | package_url | + * +---------+-------------+-------------------------------------------------------------------------------+ + * | 0.23.1 | patch | https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar | + * +---------+-------------+-------------------------------------------------------------------------------+ + * * @subcommand check-update */ public function check_update( $_, $assoc_args ) { @@ -331,7 +369,7 @@ private function get_updates( $assoc_args ) { * * $ wp cli param-dump --format=var_export * array ( - * 'path' => + * 'path' => * array ( * 'runtime' => '=<path>', * 'file' => '<path>', @@ -340,7 +378,7 @@ private function get_updates( $assoc_args ) { * 'multiple' => false, * 'desc' => 'Path to the WordPress files.', * ), - * 'url' => + * 'url' => * array ( * * @subcommand param-dump @@ -371,6 +409,10 @@ function param_dump( $_, $assoc_args ) { /** * Dump the list of installed commands, as JSON. * + * # Dump the list of installed commands + * $ wp cli version + * {"name":"wp","description":"Manage WordPress through the command-line.","longdesc":"\n\n## GLOBAL PARAMETERS\n\n --path=<path>\n Path to the WordPress files.\n\n --ssh=<ssh>\n Perform operation against a remote server over SSH.\n\n --url=<url>\n Pretend request came from given URL. In multisite, this argument is how the target site is specified. \n\n --user=<id|login|email>\n + * * @subcommand cmd-dump */ public function cmd_dump() { From dd19031d709f8fcc3de2474f5f8375e8ca537460 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 20:54:42 +0545 Subject: [PATCH 4485/5359] fix error in command example in cli cmd-dump --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index ee8ac7b7e..c5ced77be 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -410,7 +410,7 @@ function param_dump( $_, $assoc_args ) { * Dump the list of installed commands, as JSON. * * # Dump the list of installed commands - * $ wp cli version + * $ wp cli cmd-dump * {"name":"wp","description":"Manage WordPress through the command-line.","longdesc":"\n\n## GLOBAL PARAMETERS\n\n --path=<path>\n Path to the WordPress files.\n\n --ssh=<ssh>\n Perform operation against a remote server over SSH.\n\n --url=<url>\n Pretend request came from given URL. In multisite, this argument is how the target site is specified. \n\n --user=<id|login|email>\n * * @subcommand cmd-dump From 0498beb8333bcc88f848e60960d4f5d87549ab7b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 31 May 2016 21:23:38 +0545 Subject: [PATCH 4486/5359] Examples for post-type commands --- php/commands/post-type.php | 42 ++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/php/commands/post-type.php b/php/commands/post-type.php index ae73a2dd0..c42a741ef 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -2,6 +2,23 @@ /** * Manage post types. * + * ## EXAMPLES + * + * # Get a post type + * $ wp post-type get page --fields=name,label,hierarchical --format=json + * {"name":"page","label":"Pages","hierarchical":true} + * + * # List post types with 'post' capability type + * $ wp post-type list --capability_type=post --fields=name,public + * +---------------+--------+ + * | name | public | + * +---------------+--------+ + * | post | 1 | + * | attachment | 1 | + * | revision | | + * | nav_menu_item | | + * +---------------+--------+ + * * @package wp-cli */ class Post_Type_Command extends WP_CLI_Command { @@ -47,9 +64,25 @@ class Post_Type_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp post-type list --format=csv - * - * wp post-type list --capability_type=post --fields=name,public + * # List registered post types + * $ wp post-type list --format=csv + * name,label,description,hierarchical,public,capability_type + * post,Posts,,,1,post + * page,Pages,,1,1,page + * attachment,Media,,,1,post + * revision,Revisions,,,,post + * nav_menu_item,"Navigation Menu Items",,,,post + * + * # List post types with 'post' capability type + * $ wp post-type list --capability_type=post --fields=name,public + * +---------------+--------+ + * | name | public | + * +---------------+--------+ + * | post | 1 | + * | attachment | 1 | + * | revision | | + * | nav_menu_item | | + * +---------------+--------+ * * @subcommand list */ @@ -80,7 +113,8 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post-type get page --format=json + * $ wp post-type get page --fields=name,label,hierarchical --format=json + * {"name":"page","label":"Pages","hierarchical":true} */ public function get( $args, $assoc_args ) { $post_type = get_post_type_object( $args[0] ); From a262a095555c2bef4a58db8cfa1ad4c20eaf12f1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 1 Jun 2016 08:40:13 +0545 Subject: [PATCH 4487/5359] Add examples for main db class --- php/commands/db.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index cb5afe820..265b74711 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -4,6 +4,23 @@ /** * Perform basic database operations. + * + * ## EXAMPLES + * + * # Create database + * $ wp db create + * Success: Database created. + * + * # Drop database + * $ wp db drop --yes + * Success: Database dropped. + * + * # Reset database + * $ wp db reset --yes + * Success: Database reset. + * + * # Execute a query stored in a file + * $ wp db query < debug.sql */ class DB_Command extends WP_CLI_Command { @@ -154,10 +171,10 @@ public function cli() { * ## EXAMPLES * * # Execute a query stored in a file - * wp db query < debug.sql + * $ wp db query < debug.sql * * # Check all tables in the database - * wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" + * $ wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" * +---------------------------------------+-------+----------+----------+ * | Table | Op | Msg_type | Msg_text | * +---------------------------------------+-------+----------+----------+ From b345f318b138145064486909ce936bd40c8a09e7 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 1 Jun 2016 08:58:46 +0545 Subject: [PATCH 4488/5359] Add examples for option commands --- php/commands/option.php | 57 +++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index f4c560354..432887964 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -10,13 +10,21 @@ * * ## EXAMPLES * - * wp option get siteurl + * # Get site URL + * $ wp option get siteurl + * http://example.com * - * wp option add my_option foobar + * # Add option + * $ wp option add my_option foobar + * Success: Added 'my_option' option. * - * wp option update my_option '{"foo": "bar"}' --format=json + * # Update option + * $ wp option update my_option '{"foo": "bar"}' --format=json + * Success: Updated 'my_option' option. * - * wp option delete my_option + * # Delete option + * $ wp option delete my_option + * Success: Deleted 'my_option' option. */ class Option_Command extends WP_CLI_Command { @@ -105,17 +113,6 @@ public function add( $args, $assoc_args ) { * [--format=<format>] * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. Accepted values: table, json, csv, count, total_bytes. Default: table * - * ## EXAMPLES - * - * # Get the total size of all autoload options - * wp option list --autoload=on --format=total_bytes - * - * # Find biggest transients - * wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail - * - * # List all options begining with "i2f_" - * wp option list --search "i2f_*" - * * ## AVAILABLE FIELDS * * This field will be displayed by default for each matching option: @@ -128,6 +125,29 @@ public function add( $args, $assoc_args ) { * * autoload * * size_bytes * + * ## EXAMPLES + * + * # Get the total size of all autoload options + * $ wp option list --autoload=on --format=total_bytes + * 33198 + * + * # Find biggest transients + * $ wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail + * option_name size_bytes + * _site_transient_timeout_theme_roots 10 + * _site_transient_theme_roots 76 + * _site_transient_update_themes 181 + * _site_transient_update_core 808 + * _site_transient_update_plugins 6645 + * + * # List all options begining with "i2f_" + * $ wp option list --search="i2f_*" + * +-------------+--------------+ + * | option_name | option_value | + * +-------------+--------------+ + * | i2f_version | 0.1.0 | + * +-------------+--------------+ + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -203,10 +223,13 @@ public function list_( $args, $assoc_args ) { * ## EXAMPLES * * # Update an option by reading from a file - * wp option update my_option < value.txt + * $ wp option update my_option < value.txt + * Success: Updated 'my_option' option. * * # Update one option on multiple sites using xargs - * wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} option update <key> <value>' + * $ wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} option update my_option my_value' + * Success: Updated 'my_option' option. + * Success: Updated 'my_option' option. * * @alias set */ From 6d4d1572401b3132557937e8b259ae83858f7491 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 1 Jun 2016 18:34:33 +0545 Subject: [PATCH 4489/5359] Example: network meta --- php/commands/network.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/network.php b/php/commands/network.php index 709c16b49..3b0c47ddb 100644 --- a/php/commands/network.php +++ b/php/commands/network.php @@ -13,8 +13,11 @@ * * ## EXAMPLES * - * # get a list of super-admins - * wp network meta get 1 site_admins + * # Get a list of super-admins + * $ wp network meta get 1 site_admins + * array ( + * 0 => 'supervisor', + * ) */ class Network_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'site'; From 090f6c8ecc931a32d39ea7380ec5bebcb2ee12d5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 1 Jun 2016 18:51:06 +0545 Subject: [PATCH 4490/5359] Add examples for plugin commands --- php/commands/plugin.php | 48 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 49966cc5b..30f941ba8 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -5,6 +5,31 @@ /** * Manage plugins. * + * ## EXAMPLES + * + * # Activate plugin + * $ wp plugin activate hello-dolly + * Success: Plugin 'hello-dolly' activated. + * + * # Deactivate plugin + * $ wp plugin deactivate hello-dolly + * Success: Plugin 'hello-dolly' deactivated. + * + * # Delete plugin + * $ wp plugin delete hello-dolly + * Success: Deleted 'hello-dolly' plugin. + * + * # Install the latest version from wordpress.org and activate + * $ wp plugin install bbpress --activate + * Installing bbPress (2.5.9) + * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.2.5.9.zip... + * Using cached file '/home/vagrant/.wp-cli/cache/plugin/bbpress-2.5.9.zip'... + * Unpacking the package... + * Installing the plugin... + * Plugin installed successfully. + * Activating 'bbpress'... + * Success: Plugin 'bbpress' activated. + * * @package wp-cli */ class Plugin_Command extends \WP_CLI\CommandWithUpgrade { @@ -185,6 +210,16 @@ protected function get_all_items() { * * [--network] * : If set, the plugin will be activated for the entire multisite network. + * + * ## EXAMPLES + * + * # Activate plugin + * $ wp plugin activate hello-dolly + * Success: Plugin 'hello-dolly' activated. + * + * # Activate plugin in entire multisite network + * $ wp plugin activate hello-dolly --network + * Success: Plugin 'hello-dolly' network activated. */ function activate( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); @@ -246,6 +281,12 @@ function activate( $args, $assoc_args = array() ) { * * [--network] * : If set, the plugin will be deactivated for the entire multisite network. + * + * ## EXAMPLES + * + * # Deactivate plugin + * $ wp plugin deactivate hello-dolly + * Success: Plugin 'hello-dolly' deactivated. */ function deactivate( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); @@ -654,8 +695,10 @@ function uninstall( $args, $assoc_args = array() ) { * * ## EXAMPLES * - * wp plugin is-installed hello - * echo $? # displays 0 or 1 + * # Check whether plugin is installed; exit status 0 if installed, otherwise 1 + * $ wp plugin is-installed hello-dolly + * $ echo $? + * 1 * * @subcommand is-installed */ @@ -677,6 +720,7 @@ function is_installed( $args, $assoc_args = array() ) { * * ## EXAMPLES * + * # Delete plugin * $ wp plugin delete hello * Success: Deleted 'hello' plugin. * From 6a63133f5cd4e9059382723885af815b19328d70 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 1 Jun 2016 20:42:10 +0545 Subject: [PATCH 4491/5359] Add examples for post commands --- php/commands/post.php | 125 +++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 25 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index aa75dfd21..856d04776 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -3,6 +3,20 @@ /** * Manage posts. * + * ## EXAMPLES + * + * # Create post + * $ wp post create --post_type=post --post_title='A sample post' + * Success: Created post 123. + * + * # Update post + * $ wp post update 123 --post_status=draft + * Success: Updated post 123. + * + * # Delete post + * $ wp post delete 123 + * Success: Trashed post 123. + * * @package wp-cli */ class Post_Command extends \WP_CLI\CommandWithDBObject { @@ -46,9 +60,13 @@ public function __construct() { * * ## EXAMPLES * - * wp post create --post_type=page --post_title='A future post' --post_status=future --post_date='2020-12-01 07:00:00' + * # Create post and schedule for future + * $ wp post create --post_type=page --post_title='A future post' --post_status=future --post_date='2020-12-01 07:00:00' + * Success: Created post 1921. * - * wp post create ./post-content.txt --post_category=201,345 --post_title='Post from file' + * # Create post with content from given file + * $ wp post create ./post-content.txt --post_category=201,345 --post_title='Post from file' + * Success: Created post 1922. */ public function create( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { @@ -96,7 +114,8 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post update 123 --post_name=something --post_status=draft + * $ wp post update 123 --post_name=something --post_status=draft + * Success: Updated post 123. */ public function update( $args, $assoc_args ) { @@ -129,7 +148,8 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post edit 123 + * # Launch system editor to edit post + * $ wp post edit 123 */ public function edit( $args, $_ ) { $post = $this->fetcher->get_check( $args[0] ); @@ -168,8 +188,8 @@ protected function _edit( $content, $title ) { * * ## EXAMPLES * - * # save the post content to a file - * wp post get 12 --field=content > file.txt + * # Save the post content to a file + * $ wp post get 123 --field=content > file.txt */ public function get( $args, $assoc_args ) { $post = $this->fetcher->get_check( $args[0] ); @@ -201,12 +221,19 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post delete 123 --force + * # Delete post skipping trash + * $ wp post delete 123 --force + * Success: Deleted post 123. * - * wp post delete $(wp post list --post_type='page' --format=ids) + * # Delete all pages + * $ wp post delete $(wp post list --post_type='page' --format=ids) + * Success: Trashed post 1164. + * Success: Trashed post 1186. * - * # delete all posts in the trash - * wp post delete $(wp post list --post_status=trash --format=ids) + * # Delete all posts in the trash + * $ wp post delete $(wp post list --post_status=trash --format=ids) + * Success: Trashed post 1268. + * Success: Trashed post 1294. */ public function delete( $args, $assoc_args ) { $defaults = array( @@ -280,15 +307,37 @@ public function delete( $args, $assoc_args ) { * * ## EXAMPLES * - * wp post list --field=ID - * - * wp post list --post_type=post --posts_per_page=5 --format=json - * - * wp post list --post_type=page --fields=post_title,post_status - * - * wp post list --post_type=page,post --format=ids - * - * wp post list --post__in=1,3 + * # List post + * $ wp post list --field=ID + * 568 + * 829 + * 1329 + * 1695 + * + * # List posts in JSON + * $ wp post list --post_type=post --posts_per_page=5 --format=json + * [{"ID":1,"post_title":"Hello world!","post_name":"hello-world","post_date":"2015-06-20 09:00:10","post_status":"publish"},{"ID":1178,"post_title":"Markup: HTML Tags and Formatting","post_name":"markup-html-tags-and-formatting","post_date":"2013-01-11 20:22:19","post_status":"draft"}] + * + * # List all pages + * $ wp post list --post_type=page --fields=post_title,post_status + * +-------------+-------------+ + * | post_title | post_status | + * +-------------+-------------+ + * | Sample Page | publish | + * +-------------+-------------+ + * + * # List ids of all pages and posts + * $ wp post list --post_type=page,post --format=ids + * 15 25 34 37 198 + * + * # List given posts + * $ wp post list --post__in=1,3 + * +----+--------------+-------------+---------------------+-------------+ + * | ID | post_title | post_name | post_date | post_status | + * +----+--------------+-------------+---------------------+-------------+ + * | 3 | Lorem Ipsum | lorem-ipsum | 2016-06-01 14:34:36 | publish | + * | 1 | Hello world! | hello-world | 2016-06-01 14:31:12 | publish | + * +----+--------------+-------------+---------------------+-------------+ * * @subcommand list */ @@ -357,11 +406,22 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * wp post generate --count=10 --post_type=page --post_date=1999-01-04 - * curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 + * # Generate posts + * $ wp post generate --count=10 --post_type=page --post_date=1999-01-04 + * Generating posts 100% [================================================] 0:01 / 0:04 + * + * # Generate posts with fetched content + * $ curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 + * % Total % Received % Xferd Average Speed Time Time Time Current + * Dload Upload Total Spent Left Speed + * 100 2509 100 2509 0 0 616 0 0:00:04 0:00:04 --:--:-- 616 + * Generating posts 100% [================================================] 0:01 / 0:04 * * # Add meta to every generated post - * wp post generate --format=ids | xargs -0 -d ' ' -I % wp post meta add % foo bar + * $ wp post generate --format=ids | xargs -0 -d ' ' -I % wp post meta add % foo bar + * Success: Added custom field. + * Success: Added custom field. + * Success: Added custom field. */ public function generate( $args, $assoc_args ) { global $wpdb; @@ -501,7 +561,21 @@ private function read_from_file_or_stdin( $arg ) { * * ## EXAMPLES * - * wp post meta set 123 _wp_page_template about.php + * # Set post meta + * $ wp post meta set 123 _wp_page_template about.php + * Success: Updated custom field '_wp_page_template'. + * + * # Get post meta + * $ wp post meta get 123 _wp_page_template + * about.php + * + * # Update post meta + * $ wp post meta update 123 _wp_page_template contact.php + * Success: Updated custom field '_wp_page_template'. + * + * # Delete post meta + * $ wp post meta delete 123 _wp_page_template + * Success: Deleted custom field. */ class Post_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'post'; @@ -521,10 +595,11 @@ protected function check_object_id( $object_id ) { /** * Manage post terms. * - * * ## EXAMPLES * - * wp post term set 123 test category + * # Set post terms + * $ wp post term set 123 test category + * Set terms. */ class Post_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'post'; From 7c0faf2b79aab738066fac294dca3a54180e01ab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 1 Jun 2016 16:29:01 -0700 Subject: [PATCH 4492/5359] Add more explicit tests for skip-plugins feature --- features/skip-plugins.feature | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/features/skip-plugins.feature b/features/skip-plugins.feature index 2dc828d8c..8105cc620 100644 --- a/features/skip-plugins.feature +++ b/features/skip-plugins.feature @@ -24,10 +24,10 @@ Feature: Skipping plugins """ # The specified plugin should still show up as an active plugin - When I run `wp --skip-plugins=akismet plugin status` + When I run `wp --skip-plugins=akismet plugin status akismet` Then STDOUT should contain: """ - akismet + Status: Active """ # The un-specified plugin should continue to be loaded @@ -85,3 +85,20 @@ Feature: Skipping plugins """ Call to undefined function hello_dolly() """ + + Scenario: Skip network active plugins + Given a WP multisite install + And I run `wp plugin deactivate akismet` + And I run `wp plugin activate --network akismet` + + When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` + Then STDOUT should be: + """ + false + """ From 2d5c1f8e6ad756b1a0a8ea353c56c1e22c001c60 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 2 Jun 2016 08:49:51 +0545 Subject: [PATCH 4493/5359] Add examples for package commands --- php/commands/package.php | 82 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 4129c92fd..bc7340280 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -28,6 +28,41 @@ * Learn how to create your own command from the * [Commands Cookbook](http://wp-cli.org/docs/commands-cookbook/) * + * ## EXAMPLES + * + * # List installed packages + * $ wp package list + * +-----------------------+------------------------------------------+---------+------------+ + * | name | description | authors | version | + * +-----------------------+------------------------------------------+---------+------------+ + * | wp-cli/server-command | Start a development server for WordPress | | dev-master | + * +-----------------------+------------------------------------------+---------+------------+ + * + * # Install the latest development version of the package + * $ wp package install wp-cli/server-command + * Installing wp-cli/server-command (dev-master) + * Updating /home/person/.wp-cli/packages/composer.json to require the package... + * Using Composer to install the package... + * --- + * Loading composer repositories with package information + * Updating dependencies + * Resolving dependencies through SAT + * Dependency resolution completed in 0.005 seconds + * Analyzed 732 packages to resolve dependencies + * Analyzed 1034 rules to resolve dependencies + * - Installing package + * Writing lock file + * Generating autoload files + * --- + * Success: Package installed successfully. + * + * # Uninstall package + * $ wp package uninstall wp-cli/server-command + * Removing require statement from /home/person/.wp-cli/packages/composer.json + * Deleting package directory /home/person/.wp-cli/packages/vendor/wp-cli/server-command + * Regenerating Composer autoload. + * Success: Uninstalled package. + * * @package WP-CLI * * @when before_wp_load @@ -67,11 +102,26 @@ public function browse( $_, $assoc_args ) { * * ## EXAMPLES * - * # install the latest development version - * wp package install wp-cli/server-command + * # Install the latest development version + * $ wp package install wp-cli/server-command + * Installing wp-cli/server-command (dev-master) + * Updating /home/person/.wp-cli/packages/composer.json to require the package... + * Using Composer to install the package... + * --- + * Loading composer repositories with package information + * Updating dependencies + * Resolving dependencies through SAT + * Dependency resolution completed in 0.005 seconds + * Analyzed 732 packages to resolve dependencies + * Analyzed 1034 rules to resolve dependencies + * - Installing package + * Writing lock file + * Generating autoload files + * --- + * Success: Package installed successfully. * - * # install the latest stable version - * wp package install wp-cli/server-command:@stable + * # Install the latest stable version + * $ wp package install wp-cli/server-command:@stable */ public function install( $args, $assoc_args ) { list( $package_name ) = $args; @@ -146,6 +196,15 @@ public function install( $args, $assoc_args ) { * [--format=<format>] * : Accepted values: table, json, csv, yaml, ids. Default: table * + * ## EXAMPLES + * + * $ wp package list + * +-----------------------+------------------------------------------+---------+------------+ + * | name | description | authors | version | + * +-----------------------+------------------------------------------+---------+------------+ + * | wp-cli/server-command | Start a development server for WordPress | | dev-master | + * +-----------------------+------------------------------------------+---------+------------+ + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -164,7 +223,12 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * cd $(wp package path) + * # Get package path + * $ wp package path + * /home/person/.wp-cli/packages/ + * + * # Change directory to package path + * $ cd $(wp package path) */ function path( $args ) { $packages_dir = WP_CLI::get_runner()->get_packages_dir_path(); @@ -184,6 +248,14 @@ function path( $args ) { * * <name> * : Name of the package to uninstall. + * + * ## EXAMPLES + * + * $ wp package uninstall wp-cli/server-command + * Removing require statement from /home/person/.wp-cli/packages/composer.json + * Deleting package directory /home/person/.wp-cli/packages/vendor/wp-cli/server-command + * Regenerating Composer autoload. + * Success: Uninstalled package. */ public function uninstall( $args ) { list( $package_name ) = $args; From 05130b40e74ccd29d01fa50fba95f8dceefe8e1e Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 2 Jun 2016 09:04:50 +0545 Subject: [PATCH 4494/5359] Add examples for site commands --- php/commands/site.php | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 6e754c002..d2971c588 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -3,6 +3,22 @@ /** * Perform site-wide operations. * + * ## EXAMPLES + * + * # Create site + * $ wp site create --slug=example + * Success: Site 3 created: www.example.com/example/ + * + * # Output a simple list of site URLs + * $ wp site list --field=url + * http://www.example.com/ + * http://www.example.com/subdir/ + * + * # Delete site + * $ wp site delete 123 + * Are you sure you want to delete the http://www.example.com/example site? [y/n] y + * Success: The site at http://www.example.com/example was deleted. + * * @package wp-cli */ class Site_Command extends \WP_CLI\CommandWithDBObject { @@ -143,6 +159,12 @@ private function _insert_default_terms() { * [--yes] * : Proceed to empty the site without a confirmation prompt. * + * ## EXAMPLES + * + * $ wp site empty + * Are you sure you want to empty the site at http://www.example.com of all posts, comments, and terms? [y/n] y + * Success: The site at http://www.example.com was emptied. + * * @subcommand empty */ public function _empty( $args, $assoc_args ) { @@ -203,7 +225,6 @@ public function _empty( $args, $assoc_args ) { * $ wp site delete 123 * Are you sure you want to delete the http://www.example.com/example site? [y/n] y * Success: The site at http://www.example.com/example was deleted. - * */ function delete( $args, $assoc_args ) { if ( !is_multisite() ) { @@ -255,6 +276,11 @@ function delete( $args, $assoc_args ) { * * [--porcelain] * : If set, only the site id will be output on success. + * + * ## EXAMPLES + * + * $ wp site create --slug=example + * Success: Site 3 created: www.example.com/example/ */ public function create( $_, $assoc_args ) { if ( !is_multisite() ) { @@ -421,8 +447,8 @@ private function _get_network( $network_id ) { * * # Output a simple list of site URLs * $ wp site list --field=url - * http://example.com/ - * http://example.com/subdir/ + * http://www.example.com/ + * http://www.example.com/subdir/ * * @subcommand list */ From 1bdddcfe4dbaf8c00cf9406dfa0d7642dae21ff9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 2 Jun 2016 14:38:35 +0545 Subject: [PATCH 4495/5359] Add examples for core commands --- php/commands/core.php | 67 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index a00cf63c0..38d912446 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -32,6 +32,15 @@ class Core_Command extends WP_CLI_Command { * [--format=<format>] * : Accepted values: table, csv, json, yaml. Default: table * + * ## EXAMPLES + * + * $ wp core check-update + * +---------+-------------+-------------------------------------------------------------+ + * | version | update_type | package_url | + * +---------+-------------+-------------------------------------------------------------+ + * | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | + * +---------+-------------+-------------------------------------------------------------+ + * * @subcommand check-update */ function check_update( $_, $assoc_args ) { @@ -68,7 +77,10 @@ function check_update( $_, $assoc_args ) { * * ## EXAMPLES * - * wp core download --locale=nl_NL + * $ wp core download --locale=nl_NL + * Downloading WordPress 4.5.2 (nl_NL)... + * md5 hash verified: c5366d05b521831dd0b29dfc386e56a5 + * Success: WordPress downloaded. * * @when before_wp_load */ @@ -318,13 +330,15 @@ private static function get_initial_locale() { * ## EXAMPLES * * # Standard wp-config.php file - * wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO + * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO + * Success: Generated wp-config.php file. * * # Enable WP_DEBUG and WP_DEBUG_LOG - * wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP - * define( 'WP_DEBUG', true ); - * define( 'WP_DEBUG_LOG', true ); - * PHP + * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP + * $ define( 'WP_DEBUG', true ); + * $ define( 'WP_DEBUG_LOG', true ); + * $ PHP + * Success: Generated wp-config.php file. */ public function config( $_, $assoc_args ) { global $wp_version; @@ -445,6 +459,11 @@ public function is_installed( $_, $assoc_args ) { * * [--skip-email] * : Don't send an email notification to the new admin user. + * + * ## EXAMPLES + * + * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_password=strongpassword --admin_email=info@example.com + * Success: WordPress installed successfully. */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { @@ -791,9 +810,11 @@ private static function get_clean_basedomain() { * * ## EXAMPLES * + * # Display the WordPress version * $ wp core version * 4.5.2 * + * # Display WordPress version along with other information * $ wp core version --extra * WordPress version: 4.5.2 * Database revision: 36686 @@ -841,15 +862,19 @@ public function version( $args = array(), $assoc_args = array() ) { * * ## EXAMPLES * + * # Verify checksums * $ wp core verify-checksums * Success: WordPress install verifies against checksums. * + * # Verify checksums for given WordPress version * $ wp core verify-checksums --version=4.0 * Success: WordPress install verifies against checksums. * + * # Verify checksums for given locale * $ wp core verify-checksums --locale=en_US * Success: WordPress install verifies against checksums. * + * # Verify checksums for given locale * $ wp core verify-checksums --locale=ja * Warning: File doesn't verify against checksum: wp-includes/version.php * Warning: File doesn't verify against checksum: readme.html @@ -1059,6 +1084,7 @@ private static function get_core_checksums( $version, $locale ) { * * ## EXAMPLES * + * # Update WordPress * $ wp core update * Updating to version 4.5.2 (en_US)... * Downloading update from https://downloads.wordpress.org/release/wordpress-4.5.2-no-content.zip... @@ -1067,6 +1093,7 @@ private static function get_core_checksums( $version, $locale ) { * No files found that need cleaned up * Success: WordPress updated successfully. * + * # Update WordPress to latest version of 3.8 release * $ wp core update --version=3.8 ../latest.zip * Updating to version 3.8 ()... * Unpacking the update... @@ -1077,6 +1104,7 @@ private static function get_core_checksums( $version, $locale ) { * 377 files cleaned up * Success: WordPress updated successfully. * + * # Update WordPress to 3.1 forcefully * $ wp core update --version=3.1 --force * Updating to version 3.1 (en_US)... * Downloading update from https://wordpress.org/wordpress-3.1.zip... @@ -1211,9 +1239,11 @@ function update( $args, $assoc_args ) { * * ## EXAMPLES * + * # Update the WordPress database * $ wp core update-db * Success: WordPress database upgraded successfully from db version 36686 to 35700 * + * # Update databases for all sites on a network * $ wp core update-db --network * WordPress database upgraded successfully from db version 35700 to 29630 on example.com/ * Success: WordPress database upgraded on 123/123 sites @@ -1402,6 +1432,31 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { WP_CLI::add_command( 'core', 'Core_Command' ); +/** + * Manage core language. + * + * ## EXAMPLES + * + * # Install language + * $ wp core language install nl_NL + * Success: Language installed. + * + * # Activate language + * $ wp core language activate nl_NL + * Success: Language activated. + * + * # Uninstall language + * $ wp core language uninstall nl_NL + * Success: Language uninstalled. + * + * # List installed languages + * $ wp core language list --status=installed + * +----------+--------------+-------------+-----------+-----------+---------------------+ + * | language | english_name | native_name | status | update | updated | + * +----------+--------------+-------------+-----------+-----------+---------------------+ + * | nl_NL | Dutch | Nederlands | installed | available | 2016-05-13 08:12:50 | + * +----------+--------------+-------------+-----------+-----------+---------------------+ + */ class Core_Language_Command extends WP_CLI\CommandWithTranslation { protected $obj_type = 'core'; From 75f3e45e47ff284e01dc36636fb1ac4daac60cee Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 2 Jun 2016 17:08:53 +0545 Subject: [PATCH 4496/5359] Add examples for scaffold commands --- php/commands/scaffold.php | 42 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 7f29542a6..795a28469 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -6,6 +6,21 @@ /** * Generate code for post types, taxonomies, etc. * + * ## EXAMPLES + * + * # Generate plugin + * $ wp scaffold plugin sample-plugin + * Success: Created plugin files. + * Success: Created test files. + * + * # Generate theme based on _s + * $ wp scaffold _s sample-theme --theme_name="Sample Theme" --author="John Doe" + * Success: Created theme 'Sample Theme'. + * + * # Generate code for post type registration in given theme + * $ wp scaffold post-type movie --label=Movie --theme=simple-life + * Success: Created /var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php + * * @package wp-cli */ class Scaffold_Command extends WP_CLI_Command { @@ -40,6 +55,11 @@ class Scaffold_Command extends WP_CLI_Command { * [--force] * : Overwrite files that already exist. * + * ## EXAMPLES + * + * $ wp scaffold post-type movie --label=Movie --theme=simple-life + * Success: Created /var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php + * * @subcommand post-type * * @alias cpt @@ -93,7 +113,8 @@ function post_type( $args, $assoc_args ) { * * ## EXAMPLES * - * wp scaffold taxonomy venue --post_types=event,presentation + * # Generate PHP code for registering a custom taxonomy and save in a file + * $ wp scaffold taxonomy venue --post_types=event,presentation > taxonomy.php * * @subcommand taxonomy * @@ -202,6 +223,10 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * [--force] * : Overwrite files that already exist. * + * ## EXAMPLES + * + * $ wp scaffold _s sample-theme --theme_name="Sample Theme" --author="John Doe" + * Success: Created theme 'Sample Theme'. */ function _s( $args, $assoc_args ) { @@ -307,6 +332,11 @@ function _s( $args, $assoc_args ) { * [--force] * : Overwrite files that already exist. * + * ## EXAMPLES + * + * $ wp scaffold child-theme sample-theme --parent_theme=twentysixteen + * Success: Created /var/www/example.com/public_html/wp-content/themes/sample-theme. + * * @subcommand child-theme */ function child_theme( $args, $assoc_args ) { @@ -408,6 +438,11 @@ private function get_output_path( $assoc_args, $subdir ) { * [--force] * : Overwrite files that already exist. * + * ## EXAMPLES + * + * $ wp scaffold plugin sample-plugin + * Success: Created plugin files. + * Success: Created test files. */ function plugin( $args, $assoc_args ) { $plugin_slug = $args[0]; @@ -499,9 +534,10 @@ function plugin( $args, $assoc_args ) { * [--force] * : Overwrite files that already exist. * - * ## EXAMPLE + * ## EXAMPLES * - * wp scaffold plugin-tests hello + * $ wp scaffold plugin-tests sample-plugin + * Success: Created test files. * * @subcommand plugin-tests */ From be9aa2c190fb486f504e115668584e44419739b1 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 2 Jun 2016 20:59:20 +0545 Subject: [PATCH 4497/5359] Examples for core main class --- php/commands/core.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 38d912446..f52846cd0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -6,6 +6,22 @@ /** * Download, install, update and otherwise manage WordPress proper. * + * ## EXAMPLES + * + * # Download WordPress core + * $ wp core download --locale=nl_NL + * Downloading WordPress 4.5.2 (nl_NL)... + * md5 hash verified: c5366d05b521831dd0b29dfc386e56a5 + * Success: WordPress downloaded. + * + * # Install WordPress + * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_password=strongpassword --admin_email=info@example.com + * Success: WordPress installed successfully. + * + * # Display the WordPress version + * $ wp core version + * 4.5.2 + * * @package wp-cli */ class Core_Command extends WP_CLI_Command { From c68b91e06febbd4a0c80967cfb82e858f79dd07c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 2 Jun 2016 14:02:08 -0700 Subject: [PATCH 4498/5359] Move `--skip-themes` feature to a filter, instead of wp-settings hack Introduces `Runner->add_wp_hook()` and `Runner->remove_wp_hook()` for adding actions and filters before `add_filter()` is defined. To ensure child themes can be skipped from loading, the `stylesheet` value is always checked. Filter is added late on `setup_theme` hook to noop TEMPLATEPATH and `STYLESHEETPATH`, and then removed early on `after_setup_theme` to ensure use of `get_template_directory()` still works as expected. Unfortunately, the downside is that the constants are defined incorrectly in this request, but hopefully this is an acceptable cost to the value of `--skip-themes`. --- features/skip-themes.feature | 54 ++++++++++++++ php/WP_CLI/Runner.php | 135 +++++++++++++++++++++++++++++++++++ php/wp-settings-cli.php | 10 ++- 3 files changed, 193 insertions(+), 6 deletions(-) diff --git a/features/skip-themes.feature b/features/skip-themes.feature index a285eec79..abfe6e2d3 100644 --- a/features/skip-themes.feature +++ b/features/skip-themes.feature @@ -46,6 +46,60 @@ Feature: Skipping themes false """ + Scenario: Skip parent and child themes + Given a WP install + And I run `wp theme install jolene biker` + + When I run `wp theme activate jolene` + When I run `wp eval 'var_export( function_exists( "jolene_setup" ) );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp --skip-themes=jolene eval 'var_export( function_exists( "jolene_setup" ) );'` + Then STDOUT should be: + """ + false + """ + + When I run `wp theme activate biker` + When I run `wp eval 'var_export( function_exists( "jolene_setup" ) );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp eval 'var_export( function_exists( "biker_setup" ) );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp --skip-themes=biker eval 'var_export( function_exists( "jolene_setup" ) );'` + Then STDOUT should be: + """ + false + """ + + When I run `wp --skip-themes=biker eval 'var_export( function_exists( "biker_setup" ) );'` + Then STDOUT should be: + """ + false + """ + + When I run `wp --skip-themes=biker eval 'echo get_template_directory();'` + Then STDOUT should contain: + """ + wp-content/themes/jolene + """ + + When I run `wp --skip-themes=biker eval 'echo get_stylesheet_directory();'` + Then STDOUT should contain: + """ + wp-content/themes/biker + """ + Scenario: Skipping multiple themes via config file Given a WP install And a wp-cli.yml file: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7b94d703e..f9e80df2b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -854,6 +854,9 @@ public function load_wordpress() { // Load WP-CLI utilities require WP_CLI_ROOT . '/php/utils-wp.php'; + // Set up WordPress bootstrap actions and filters + $this->setup_bootstrap_hooks(); + // Load Core, mu-plugins, plugins, themes etc. require WP_CLI_ROOT . '/php/wp-settings-cli.php'; @@ -922,6 +925,138 @@ private function maybe_update_url_from_domain_constant() { } } + /** + * Set up hooks meant to run during the WordPress bootstrap process + */ + private function setup_bootstrap_hooks() { + + if ( $this->config['skip-themes'] ) { + $this->add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); + } + + } + + /** + * Set up the filters to skip the loaded theme + */ + public function action_setup_theme_wp_cli_skip_themes() { + $wp_cli_filter_active_theme = function( $value ) { + $skipped_themes = WP_CLI::get_runner()->config['skip-themes']; + if ( true === $skipped_themes ) { + return ''; + } + if ( ! is_array( $skipped_themes ) ) { + $skipped_themes = explode( ',', $skipped_themes ); + } + // Always check against the stylesheet value + // This ensures a child theme can be skipped when template differs + if ( false !== stripos( current_filter(), 'option_template' ) ) { + $checked_value = get_option( 'stylesheet' ); + } else { + $checked_value = $value; + } + if ( '' === $checked_value || in_array( $checked_value, $skipped_themes ) ) { + return ''; + } + return $value; + }; + $hooks = array( + 'pre_option_template', + 'option_template', + 'pre_option_stylesheet', + 'option_stylesheet', + ); + foreach( $hooks as $hook ) { + add_filter( $hook, $wp_cli_filter_active_theme, 999 ); + } + // Clean up after the TEMPLATEPATH and STYLESHEETPATH constants are defined + $this->add_wp_hook( 'after_setup_theme', function() use ( $hooks, $wp_cli_filter_active_theme ) { + foreach( $hooks as $hook ) { + remove_filter( $hook, $wp_cli_filter_active_theme, 999 ); + } + }, 0 ); + } + + /** + * Add a callback to a WordPress action or filter + * + * Essentially add_filter() without needing access to add_filter() + */ + private function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { + global $wp_filter, $merged_filters; + $idx = $this->wp_hook_build_unique_id($tag, $function_to_add, $priority); + $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + unset( $merged_filters[ $tag ] ); + return true; + } + + /** + * Remove a callback from a WordPress action or filter + * + * Essentially remove_filter() without needing access to remove_filter() + */ + private function remove_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { + $function_to_remove = $this->wp_hook_build_unique_id( $tag, $function_to_remove, $priority ); + + $r = isset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); + + if ( true === $r ) { + unset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); + if ( empty( $GLOBALS['wp_filter'][ $tag ][ $priority ] ) ) { + unset( $GLOBALS['wp_filter'][ $tag ][ $priority ] ); + } + if ( empty( $GLOBALS['wp_filter'][ $tag ] ) ) { + $GLOBALS['wp_filter'][ $tag ] = array(); + } + unset( $GLOBALS['merged_filters'][ $tag ] ); + } + + return $r; + } + + /** + * Build Unique ID for storage and retrieval. + * + * Essentially _wp_filter_build_unique_id() without needing access to _wp_filter_build_unique_id() + */ + private function wp_hook_build_unique_id( $tag, $function, $priority ) { + global $wp_filter; + static $filter_id_count = 0; + + if ( is_string($function) ) + return $function; + + if ( is_object($function) ) { + // Closures are currently implemented as objects + $function = array( $function, '' ); + } else { + $function = (array) $function; + } + + if (is_object($function[0]) ) { + // Object Class Calling + if ( function_exists('spl_object_hash') ) { + return spl_object_hash($function[0]) . $function[1]; + } else { + $obj_idx = get_class($function[0]).$function[1]; + if ( !isset($function[0]->wp_filter_id) ) { + if ( false === $priority ) + return false; + $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; + $function[0]->wp_filter_id = $filter_id_count; + ++$filter_id_count; + } else { + $obj_idx .= $function[0]->wp_filter_id; + } + + return $obj_idx; + } + } elseif ( is_string( $function[0] ) ) { + // Static Calling + return $function[0] . '::' . $function[1]; + } + } + /** * Check whether there's a WP-CLI update available, and suggest update if so. */ diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index b84f3e1d9..1326e2495 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -383,12 +383,10 @@ function wp_is_mobile() { // Load the functions for the active theme, for both parent and child theme if applicable. global $pagenow; if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { - if ( !Utils\is_theme_skipped( TEMPLATEPATH ) ) { - if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) - include( STYLESHEETPATH . '/functions.php' ); - if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) - include( TEMPLATEPATH . '/functions.php' ); - } + if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) + include( STYLESHEETPATH . '/functions.php' ); + if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) + include( TEMPLATEPATH . '/functions.php' ); } do_action( 'after_setup_theme' ); From b3c9f8da3cf75585aa20874d340048588be66b32 Mon Sep 17 00:00:00 2001 From: Steven K Word <stevenword@gmail.com> Date: Thu, 2 Jun 2016 15:44:04 -0700 Subject: [PATCH 4499/5359] Adds support for PHP 5.5 Memcache extension --- php/utils-wp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index b4202dd84..c0a054f2f 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -152,7 +152,7 @@ function wp_get_cache_type() { } elseif ( isset( $wp_object_cache->mc ) ) { $is_memcache = true; foreach ( $wp_object_cache->mc as $bucket ) { - if ( ! is_a( $bucket, 'Memcache' ) ) + if ( ! is_a( $bucket, 'Memcache' ) && ! is_a( $bucket, 'Memcached' ) ) $is_memcache = false; } From fa98ca601536c268d2f7cad97609f72480f0c08c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 2 Jun 2016 15:53:24 -0700 Subject: [PATCH 4500/5359] Move `--skip-plugins` feature to a filter, instead of wp-settings hack Filters are added before the bootstrap process, to noop `wp_get_active_network_plugins()` and `wp_get_active_and_valid_plugins()`, and then removed early on `plugins_loaded` to ensure later use of `get_option( 'active_plugins' );` works as expected. Unfortunately, `get_options( 'active_plugins' );` will be inaccurate on the `muplugins_loaded` hook. Hopefully this will be an acceptable cost to being able to continue using `--skip-plugins`. --- php/WP_CLI/Runner.php | 40 ++++++++++++++++++++++++++++++++++++++++ php/wp-settings-cli.php | 16 ++++++---------- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index f9e80df2b..8cd84d8ea 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -930,12 +930,52 @@ private function maybe_update_url_from_domain_constant() { */ private function setup_bootstrap_hooks() { + if ( $this->config['skip-plugins'] ) { + $this->setup_skip_plugins_filters(); + } + if ( $this->config['skip-themes'] ) { $this->add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); } } + /** + * Set up the filters to skip the loaded plugins + */ + private function setup_skip_plugins_filters() { + $wp_cli_filter_active_plugins = function( $plugins ) use( $skip_plugins ) { + $skipped_plugins = WP_CLI::get_runner()->config['skip-plugins']; + if ( true === $skipped_plugins ) { + return array(); + } + if ( ! is_array( $plugins ) ) { + return $plugins; + } + foreach( $plugins as $key => $plugin ) { + if ( Utils\is_plugin_skipped( $plugin ) ) { + unset( $plugins[ $key ] ); + } + } + return array_values( $plugins ); + }; + + $hooks = array( + 'pre_site_option_active_sitewide_plugins', + 'site_option_active_sitewide_plugins', + 'pre_option_active_plugins', + 'option_active_plugins', + ); + foreach( $hooks as $hook ) { + $this->add_wp_hook( $hook, $wp_cli_filter_active_plugins, 999 ); + } + $this->add_wp_hook( 'plugins_loaded', function() use ( $hooks, $wp_cli_filter_active_plugins ) { + foreach( $hooks as $hook ) { + remove_filter( $hook, $wp_cli_filter_active_plugins, 999 ); + } + }, 0 ); + } + /** * Set up the filters to skip the loaded theme */ diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 1326e2495..56ab53530 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -247,11 +247,9 @@ // Load network activated plugins. if ( is_multisite() ) { foreach( wp_get_active_network_plugins() as $network_plugin ) { - if ( !Utils\is_plugin_skipped( $network_plugin ) ) { - if ( $symlinked_plugins_supported ) - wp_register_plugin_realpath( $network_plugin ); - include_once( $network_plugin ); - } + if ( $symlinked_plugins_supported ) + wp_register_plugin_realpath( $network_plugin ); + include_once( $network_plugin ); } unset( $network_plugin ); } @@ -284,11 +282,9 @@ function wp_is_mobile() { // Load active plugins. foreach ( wp_get_active_and_valid_plugins() as $plugin ) { - if ( !Utils\is_plugin_skipped( $plugin ) ) { - if ( $symlinked_plugins_supported ) - wp_register_plugin_realpath( $plugin ); - include_once( $plugin ); - } + if ( $symlinked_plugins_supported ) + wp_register_plugin_realpath( $plugin ); + include_once( $plugin ); } unset( $plugin, $symlinked_plugins_supported ); From 1eea29165b553cd0871160af740d4ee36c18efec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 2 Jun 2016 16:02:04 -0700 Subject: [PATCH 4501/5359] Load wp-includes/vars.php in wp-settings-cli.php It doesn't appear there is an actual reason not to. --- php/wp-settings-cli.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 1326e2495..6830d3814 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -267,12 +267,8 @@ // Define and enforce our SSL constants wp_ssl_constants( ); -// Don't create common globals, but we still need wp_is_mobile() and $pagenow -// require( ABSPATH . WPINC . '/vars.php' ); -$GLOBALS['pagenow'] = null; -function wp_is_mobile() { - return false; -} +// Create common globals. +require( ABSPATH . WPINC . '/vars.php' ); // Make taxonomies and posts available to plugins and themes. // @plugin authors: warning: these get registered again on the init hook. From 765f0b75d7a8ec7d19be24e8e21947cd1138fa50 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 08:47:19 +0545 Subject: [PATCH 4502/5359] Introduce format parameter for super-admin list command --- php/commands/super-admin.php | 70 ++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index c57d6be30..2537a326e 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -2,9 +2,28 @@ /** * List, add, and remove super admins from a network. + * + * ## EXAMPLES + * + * # List user with super-admin capabilities + * $ wp super-admin list + * supervisor + * administrator + * + * # Grant super-admin privileges to the user. + * $ wp super-admin add superadmin2 + * Success: Granted super-admin capabilities. + * + * # Revoke super-admin privileges to the user. + * $ wp super-admin remove superadmin2 + * Success: Revoked super-admin capabilities. */ class Super_Admin_Command extends WP_CLI_Command { + private $fields = array( + 'user_login' + ); + public function __construct() { $this->fetcher = new \WP_CLI\Fetchers\User; } @@ -12,12 +31,49 @@ public function __construct() { /** * Show a list of users with super-admin capabilities. * + * ## OPTIONS + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: list + * options: + * - list + * - table + * - csv + * - json + * - count + * - yaml + * --- + * + * ## EXAMPLES + * + * # List user with super-admin capabilities + * $ wp super-admin list + * supervisor + * administrator + * * @subcommand list */ public function _list( $_, $assoc_args ) { $super_admins = self::get_admins(); - foreach ( $super_admins as $user_login ) { - WP_CLI::line( $user_login ); + + if ( 'list' === $assoc_args['format'] ) { + foreach ( $super_admins as $user_login ) { + WP_CLI::line( $user_login ); + } + } + else { + $output_users = array(); + foreach ( $super_admins as $user_login ) { + $output_user = new stdClass; + + $output_user->user_login = $user_login; + + $output_users[] = $output_user; + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); + $formatter->display_items( $output_users ); } } @@ -26,6 +82,11 @@ public function _list( $_, $assoc_args ) { * * <user>... * : One or more user IDs, user emails, or user logins. + * + * ## EXAMPLES + * + * $ wp super-admin add superadmin2 + * Success: Granted super-admin capabilities. */ public function add( $args, $_ ) { @@ -66,6 +127,11 @@ public function add( $args, $_ ) { * * <user>... * : One or more user IDs, user emails, or user logins. + * + * ## EXAMPLES + * + * $ wp super-admin remove superadmin2 + * Success: Revoked super-admin capabilities. */ public function remove( $args, $_ ) { $users = $this->fetcher->get_many( $args ); From ac1e8cd6f1d4a10cae37f92012cdad9bece0d5d3 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 08:53:14 +0545 Subject: [PATCH 4503/5359] Add test for format parameter in super-admin list --- features/super-admin.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/super-admin.feature b/features/super-admin.feature index 656499e23..219b65033 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -30,9 +30,21 @@ Feature: Manage super admins associated with a multisite instance superadmin """ + When I run `wp super-admin list --format=table` + Then STDOUT should be a table containing rows: + | user_login | + | admin | + | superadmin | + When I run `wp super-admin remove admin` And I run `wp super-admin list` Then STDOUT should be: """ superadmin """ + + When I run `wp super-admin list --format=json` + Then STDOUT should be: + """ + [{"user_login":"superadmin"}] + """ From fc9b349fddf81e7311a6c0c08f826231fa2ff1d2 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 10:05:16 +0545 Subject: [PATCH 4504/5359] Examples for search-replace command --- php/commands/search-replace.php | 40 +++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 174de9ddf..89bd09daa 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -3,6 +3,30 @@ /** * Search and replace strings in the database. * + * ## EXAMPLES + * + * # Search and replace strings in the table + * $ wp search-replace foo bar wp_options + * +------------+--------------+--------------+------+ + * | Table | Column | Replacements | Type | + * +------------+--------------+--------------+------+ + * | wp_options | option_name | 2 | SQL | + * | wp_options | option_value | 0 | PHP | + * | wp_options | autoload | 0 | SQL | + * +------------+--------------+--------------+------+ + * Success: Made 2 replacements. + * + * # Run search/replace operation but dont save in database + * $ wp search-replace foo bar wp_options --dry-run + * +------------+--------------+--------------+------+ + * | Table | Column | Replacements | Type | + * +------------+--------------+--------------+------+ + * | wp_options | option_name | 2 | SQL | + * | wp_options | option_value | 0 | PHP | + * | wp_options | autoload | 0 | SQL | + * +------------+--------------+--------------+------+ + * Success: 2 replacement(s) to be made. + * * @package wp-cli */ class Search_Replace_Command extends WP_CLI_Command { @@ -88,16 +112,18 @@ class Search_Replace_Command extends WP_CLI_Command { * * ## EXAMPLES * - * wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid + * # Search and replace but skip one column + * $ wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid * - * wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run + * # Run search/replace operation but dont save in database + * $ wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production multisite database into a local dev database - * wp search-replace --url=example.com example.com example.dev 'wp_*_options' wp_blogs + * $ wp search-replace --url=example.com example.com example.dev 'wp_*_options' wp_blogs * * # Search/replace to a SQL file without transforming the database - * wp search-replace foo bar --export=database.sql - * + * $ wp search-replace foo bar --export=database.sql + * * # Bash script: Search/replace production to development url (multisite compatible) * #!/bin/bash * if $(wp --url=http://example.com core is-installed --network); then @@ -384,13 +410,13 @@ function ( $field ) { // 1. When the loop is running every nth time (where n is insert statement size, $export_index_size). Remainder is zero also on first round, so it have to be excluded. // $index % $export_insert_size == 0 && $index > 0 // 2. Or when the loop is running last time - // $index == $count + // $index == $count if( ( $index % $export_insert_size == 0 && $index > 0 ) || $index == $count ) { $sql .= ";\n"; $sql = $wpdb->prepare( $sql, array_values( $values ) ); fwrite( $this->export_handle, $sql ); - + // If there is still rows to loop, reset $sql and $values variables. if( $count > $index ) { $sql = $insert; From 2c695cfd9435042ec5ef35163667cc8531d83fc7 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 10:27:08 +0545 Subject: [PATCH 4505/5359] Add example for user term --- php/commands/user.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 197326292..3066a3dd5 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -950,17 +950,16 @@ private function replace_login_with_user_id( $args ) { /** * Manage user terms. * - * * ## EXAMPLES * + * # Set user terms * wp user term set 123 test category + * Set terms. */ class User_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'user'; } - WP_CLI::add_command( 'user', 'User_Command' ); WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); WP_CLI::add_command( 'user term', 'User_Term_Command' ); - From c9546220940e52ee941bf2c2614319baedb37702 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 10:43:45 +0545 Subject: [PATCH 4506/5359] Add examples for user meta commands --- php/commands/user.php | 61 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 3066a3dd5..645c1cceb 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -812,16 +812,29 @@ private static function wp_new_user_notification( $user_id, $password ) { /** * Manage user custom fields. * - * ## OPTIONS + * ## EXAMPLES * - * --format=json - * : Encode/decode values as JSON. + * # Add user meta + * $ wp user meta add 123 bio "Mary is an WordPress developer." + * Success: Added custom field. * - * ## EXAMPLES + * # List user meta + * $ wp user meta list 123 --keys=nickname,description,wp_capabilities + * +---------+-----------------+--------------------------------+ + * | user_id | meta_key | meta_value | + * +---------+-----------------+--------------------------------+ + * | 123 | nickname | supervisor | + * | 123 | description | Mary is a WordPress developer. | + * | 123 | wp_capabilities | {"administrator":true} | + * +---------+-----------------+--------------------------------+ * - * wp user meta set 123 description "Mary is a WordPress developer." + * # Update user meta + * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. * - * wp user meta update admin first_name "George" + * # Delete user meta + * $ wp user meta delete 123 bio + * Success: Deleted custom field. */ class User_Meta_Command extends \WP_CLI\CommandWithMeta { protected $meta_type = 'user'; @@ -847,6 +860,18 @@ public function __construct() { * [--format=<format>] * : Accepted values: table, csv, json, count. Default: table * + * ## EXAMPLES + * + * # List user meta + * $ wp user meta list 123 --keys=nickname,description,wp_capabilities + * +---------+-----------------+--------------------------------+ + * | user_id | meta_key | meta_value | + * +---------+-----------------+--------------------------------+ + * | 123 | nickname | supervisor | + * | 123 | description | Mary is a WordPress developer. | + * | 123 | wp_capabilities | {"administrator":true} | + * +---------+-----------------+--------------------------------+ + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -867,6 +892,12 @@ public function list_( $args, $assoc_args ) { * * [--format=<format>] * : Accepted values: table, json, yaml. Default: table + * + * ## EXAMPLES + * + * # Get user meta + * $ wp user meta get 123 bio + * Mary is an WordPress developer. */ public function get( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -884,6 +915,12 @@ public function get( $args, $assoc_args ) { * * [<value>] * : The value to delete. If omitted, all rows with key will deleted. + * + * ## EXAMPLES + * + * # Delete user meta + * $ wp user meta delete 123 bio + * Success: Deleted custom field. */ public function delete( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -904,6 +941,12 @@ public function delete( $args, $assoc_args ) { * * [--format=<format>] * : The serialization format for the value. Default is plaintext. + * + * ## EXAMPLES + * + * # Add user meta + * $ wp user meta add 123 bio "Mary is an WordPress developer." + * Success: Added custom field. */ public function add( $args, $assoc_args ) { $args = $this->replace_login_with_user_id( $args ); @@ -925,6 +968,12 @@ public function add( $args, $assoc_args ) { * [--format=<format>] * : The serialization format for the value. Default is plaintext. * + * ## EXAMPLES + * + * # Update user meta + * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. + * * @alias set */ public function update( $args, $assoc_args ) { From fd38aa2f845286b238810ba3e5278d712ad999fb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 3 Jun 2016 11:23:00 +0545 Subject: [PATCH 4507/5359] Add examples for user commands --- php/commands/user.php | 77 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 645c1cceb..5ab8b81aa 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -71,11 +71,18 @@ public function __construct() { * * ## EXAMPLES * - * wp user list --field=ID + * # List user IDs + * $ wp user list --field=ID + * 1 * - * wp user list --role=administrator --format=csv + * # List users with administrator role + * $ wp user list --role=administrator --format=csv + * ID,user_login,display_name,user_email,user_registered,roles + * 1,supervisor,supervisor,supervisor@gmail.com,"2016-06-03 04:37:00",administrator * - * wp user list --fields=display_name,user_email --format=json + * # List users with only given fields + * $ wp user list --fields=display_name,user_email --format=json + * [{"display_name":"supervisor","user_email":"supervisor@gmail.com"}] * * @subcommand list */ @@ -142,9 +149,12 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user get 12 --field=login + * # Get user + * $ wp user get 12 --field=login + * supervisor * - * wp user get bob --format=json > bob.json + * # Get user and export to JSON file + * $ wp user get bob --format=json > bob.json */ public function get( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); @@ -175,7 +185,8 @@ public function get( $args, $assoc_args ) { * ## EXAMPLES * * # Delete user 123 and reassign posts to user 567 - * wp user delete 123 --reassign=567 + * $ wp user delete 123 --reassign=567 + * Success: Removed user 123 from http://example.com */ public function delete( $args, $assoc_args ) { $network = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); @@ -247,7 +258,10 @@ public function delete( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user create bob bob@example.com --role=author + * # Create user + * $ wp user create bob bob@example.com --role=author + * Success: Created user 3. + * Password: k9**&I4vNH(& */ public function create( $args, $assoc_args ) { $user = new stdClass; @@ -340,7 +354,9 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user update 123 --display_name=Mary --user_pass=marypass + * # Update user + * $ wp user update 123 --display_name=Mary --user_pass=marypass + * Success: Updated user 1. */ public function update( $args, $assoc_args ) { if ( isset( $assoc_args['user_login'] ) ) { @@ -373,7 +389,10 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * # Add meta to every generated user - * wp user generate --format=ids | xargs -0 -d ' ' -I % wp user meta add % foo bar + * wp user generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp user meta add % foo bar + * Success: Added custom field. + * Success: Added custom field. + * Success: Added custom field. */ public function generate( $args, $assoc_args ) { global $blog_id; @@ -447,8 +466,8 @@ public function generate( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user set-role bob author - * wp user set-role 12 author + * $ wp user set-role 12 author + * Success: Added johndoe (12) to http://example.com as author * * @subcommand set-role */ @@ -481,8 +500,8 @@ public function set_role( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user add-role bob author - * wp user add-role 12 author + * $ wp user add-role 12 author + * Success: Added 'author' role for johndoe (12). * * @subcommand add-role */ @@ -511,8 +530,8 @@ public function add_role( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user remove-role bob - * wp user remove-role 12 editor + * $ wp user remove-role 12 author + * Success: Removed 'author' role for johndoe (12). * * @subcommand remove-role */ @@ -551,8 +570,13 @@ public function remove_role( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user add-cap john create_premium_item - * wp user add-cap 15 edit_product + * # Add a capability for a user + * $ wp user add-cap john create_premium_item + * Success: Added 'create_premium_item' capability for john (16). + * + * # Add a capability for a user + * $ wp user add-cap 15 edit_product + * Success: Added 'edit_product' capability for johndoe (15). * * @subcommand add-cap */ @@ -579,8 +603,8 @@ public function add_cap( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user remove-cap bob edit_themes - * wp user remove-cap 11 publish_newsletters + * $ wp user remove-cap 11 publish_newsletters + * Success: Removed 'publish_newsletters' cap for supervisor (11). * * @subcommand remove-cap */ @@ -604,8 +628,9 @@ public function remove_cap( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user list-caps admin - * wp user list-caps 21 + * $ wp user list-caps 21 + * edit_product + * create_premium_item * * @subcommand list-caps */ @@ -641,8 +666,14 @@ public function list_caps( $args, $assoc_args ) { * * ## EXAMPLES * - * wp user import-csv /path/to/users.csv - * wp user import-csv http://example.com/users.csv + * # Import users from local CSV file + * $ wp user import-csv /path/to/users.csv + * Success: bobjones created + * Success: newuser1 created + * Success: existinguser created + * + * # Import users from remote CSV file + * $wp user import-csv http://example.com/users.csv * * Sample users.csv file: * From a2c86d96f51c9e5afe64a1a545b0c56b4c790ecc Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Fri, 3 Jun 2016 11:25:51 +0200 Subject: [PATCH 4508/5359] Load plugin.php earlier in wp-settings-cli.php for 4.6 compat. See https://core.trac.wordpress.org/changeset/37588 and https://core.trac.wordpress.org/changeset/37626. --- php/wp-settings-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 1326e2495..a2e2cd995 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -15,6 +15,7 @@ // Include files required for initialization. require( ABSPATH . WPINC . '/load.php' ); require( ABSPATH . WPINC . '/default-constants.php' ); +require( ABSPATH . WPINC . '/plugin.php' ); /* * These can't be directly globalized in version.php. When updating, @@ -66,7 +67,6 @@ require( ABSPATH . WPINC . '/functions.php' ); require( ABSPATH . WPINC . '/class-wp.php' ); require( ABSPATH . WPINC . '/class-wp-error.php' ); -require( ABSPATH . WPINC . '/plugin.php' ); require( ABSPATH . WPINC . '/pomo/mo.php' ); // WP_CLI: Early hooks From 3c8da846d5bc5ed919e6c7589fe641e370973329 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 3 Jun 2016 04:09:03 -0700 Subject: [PATCH 4509/5359] Variable is no longer being passed --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8cd84d8ea..4a08c81b2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -944,7 +944,7 @@ private function setup_bootstrap_hooks() { * Set up the filters to skip the loaded plugins */ private function setup_skip_plugins_filters() { - $wp_cli_filter_active_plugins = function( $plugins ) use( $skip_plugins ) { + $wp_cli_filter_active_plugins = function( $plugins ) { $skipped_plugins = WP_CLI::get_runner()->config['skip-plugins']; if ( true === $skipped_plugins ) { return array(); From 41e72a9cf6b08d7be0342efa94759ae96949b368 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 3 Jun 2016 20:03:11 +0545 Subject: [PATCH 4510/5359] Add examples for User main class --- php/commands/user.php | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 5ab8b81aa..673cbbe75 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -3,6 +3,25 @@ /** * Manage users. * + * ## EXAMPLES + * + * # List user IDs + * $ wp user list --field=ID + * 1 + * + * # Create user + * $ wp user create bob bob@example.com --role=author + * Success: Created user 3. + * Password: k9**&I4vNH(& + * + * # Update user + * $ wp user update 123 --display_name=Mary --user_pass=marypass + * Success: Updated user 123. + * + * # Delete user 123 and reassign posts to user 567 + * $ wp user delete 123 --reassign=567 + * Success: Removed user 123 from http://example.com + * * @package wp-cli */ class User_Command extends \WP_CLI\CommandWithDBObject { @@ -356,7 +375,7 @@ public function create( $args, $assoc_args ) { * * # Update user * $ wp user update 123 --display_name=Mary --user_pass=marypass - * Success: Updated user 1. + * Success: Updated user 123. */ public function update( $args, $assoc_args ) { if ( isset( $assoc_args['user_login'] ) ) { @@ -389,7 +408,7 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * # Add meta to every generated user - * wp user generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp user meta add % foo bar + * $ wp user generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp user meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. @@ -673,7 +692,7 @@ public function list_caps( $args, $assoc_args ) { * Success: existinguser created * * # Import users from remote CSV file - * $wp user import-csv http://example.com/users.csv + * $ wp user import-csv http://example.com/users.csv * * Sample users.csv file: * @@ -1033,7 +1052,7 @@ private function replace_login_with_user_id( $args ) { * ## EXAMPLES * * # Set user terms - * wp user term set 123 test category + * $ wp user term set 123 test category * Set terms. */ class User_Term_Command extends \WP_CLI\CommandWithTerms { From a6fdbf59b11f6f3dee588e13381dd10f3b14b62c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 3 Jun 2016 07:33:38 -0700 Subject: [PATCH 4511/5359] Remove `$pagenow` definition in `\WP_CLI\Runner` Originally introduced in 58ea052de3090dc5738ef933fde2120ac39fe64e, it hasn't worked since dc8502de2d5fb39fe2430b4447633a171628adbb. The original issue this hack solved should just be addressed in the plugin. --- php/WP_CLI/Runner.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4a08c81b2..91bd336e3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -799,10 +799,6 @@ public function start() { define( 'DOING_CRON', true ); } - if ( $this->cmd_starts_with( array( 'plugin' ) ) ) { - $GLOBALS['pagenow'] = 'plugins.php'; - } - $this->load_wordpress(); $this->_run_command(); From d8402127aa3ce4732abfd518d082d3fc081c4ad7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 3 Jun 2016 12:57:32 -0700 Subject: [PATCH 4512/5359] Hook wp_die handler in \WP_CLI\Runner instead of wp-settings-cli.php It's not necessary to add the callback as a part of the WP bootstrap process, given the existing `\WP_CLI\Utils\replace_wp_die_handler()` erroneously removes a callback that doesn't exist --- features/db.feature | 12 +++++++++++- php/WP_CLI/Runner.php | 2 ++ php/wp-settings-cli.php | 1 - 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/features/db.feature b/features/db.feature index 373498951..046fd29d1 100644 --- a/features/db.feature +++ b/features/db.feature @@ -5,8 +5,18 @@ Feature: Perform database operations And WP files And wp-config.php + When I try `wp option get home` + Then STDOUT should be empty + And STDERR should be: + """ + Error: Can’t select database + """ + When I run `wp db create` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Database created. + """ When I try the previous command again Then the return code should be 1 diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 91bd336e3..10af1d3f0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -934,6 +934,8 @@ private function setup_bootstrap_hooks() { $this->add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); } + $this->add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); + } /** diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 9e80fa2d5..06628d9d7 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -70,7 +70,6 @@ require( ABSPATH . WPINC . '/pomo/mo.php' ); // WP_CLI: Early hooks -Utils\replace_wp_die_handler(); add_filter( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); if ( defined( 'WP_INSTALLING' ) && is_multisite() ) { $values = array( From 6ebe10c728530cfcb478dfd622caf513ff35a7b9 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 06:32:52 +0545 Subject: [PATCH 4513/5359] Add format parameter in list-caps --- php/commands/user.php | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index 673cbbe75..a775acccc 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -36,6 +36,10 @@ class User_Command extends \WP_CLI\CommandWithDBObject { 'roles' ); + private $cap_fields = array( + 'name' + ); + public function __construct() { $this->fetcher = new \WP_CLI\Fetchers\User; } @@ -645,6 +649,19 @@ public function remove_cap( $args, $assoc_args ) { * <user> * : User ID, user email, or login. * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: list + * options: + * - list + * - table + * - csv + * - json + * - count + * - yaml + * --- + * * ## EXAMPLES * * $ wp user list-caps 21 @@ -661,11 +678,34 @@ public function list_caps( $args, $assoc_args ) { $user_caps_list = $user->allcaps; + $active_user_cap_list = array(); + foreach ( $user_caps_list as $cap => $active ) { if ( $active ) { - \cli\line( $cap ); + $active_user_cap_list[] = $cap; + } + } + + if ( ! empty( $active_user_cap_list ) ) { + if ( 'list' === $assoc_args['format'] ) { + foreach ( $active_user_cap_list as $cap ) { + WP_CLI::line( $cap ); + } + } + else { + $output_caps = array(); + foreach ( $active_user_cap_list as $cap ) { + $output_cap = new stdClass; + + $output_cap->name = $cap; + + $output_caps[] = $output_cap; + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->cap_fields ); + $formatter->display_items( $output_caps ); } } + } } From 7c9b8ed3867d8c01b272a180b5e18a52593193d0 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 06:48:47 +0545 Subject: [PATCH 4514/5359] Add tests for format parameter in user list-caps --- features/user.feature | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/features/user.feature b/features/user.feature index 3b8662b30..72b78927c 100644 --- a/features/user.feature +++ b/features/user.feature @@ -169,7 +169,7 @@ Feature: Manage WordPress users Then STDOUT should be a table containing rows: | Field | Value | | roles | | - + Scenario: Managing user capabilities Given a WP install @@ -178,13 +178,13 @@ Feature: Manage WordPress users """ Success: Added 'edit_vip_product' capability for admin (1). """ - + And I run `wp user list-caps 1 | tail -n 1` Then STDOUT should be: """ edit_vip_product """ - + And I run `wp user remove-cap 1 edit_vip_product` Then STDOUT should be: """ @@ -238,3 +238,30 @@ Feature: Manage WordPress users """ testsubscriber """ + + Scenario: Listing user capabilities + Given a WP install + + When I run `wp user create bob bob@gmail.com --role=contributor` + And I run `wp user list-caps bob` + Then STDOUT should be: + """ + edit_posts + read + level_1 + level_0 + delete_posts + contributor + """ + + And I run `wp user list-caps bob --format=json` + Then STDOUT should be: + """ + [{"name":"edit_posts"},{"name":"read"},{"name":"level_1"},{"name":"level_0"},{"name":"delete_posts"},{"name":"contributor"}] + """ + + And I run `wp user list-caps bob --format=count` + Then STDOUT should be: + """ + 6 + """ From c6e7884808921698f45dac3c34cb351e597f90ac Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 06:52:42 +0545 Subject: [PATCH 4515/5359] fix intendation issue in test of user list-caps --- features/user.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/user.feature b/features/user.feature index 72b78927c..4ca85cc0c 100644 --- a/features/user.feature +++ b/features/user.feature @@ -247,11 +247,11 @@ Feature: Manage WordPress users Then STDOUT should be: """ edit_posts - read - level_1 - level_0 - delete_posts - contributor + read + level_1 + level_0 + delete_posts + contributor """ And I run `wp user list-caps bob --format=json` From e89f73dd698063e0b1bbd022dc416ce78e9a5bd2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 07:08:48 +0545 Subject: [PATCH 4516/5359] Improve docs in taxonomy commands --- php/commands/taxonomy.php | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index b7f988121..3abcba920 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -2,6 +2,22 @@ /** * Manage taxonomies. * + * ## EXAMPLES + * + * # List all taxonomies with 'post' object type + * $ wp taxonomy list --object_type=post --fields=name,public + * +-------------+--------+ + * | name | public | + * +-------------+--------+ + * | category | 1 | + * | post_tag | 1 | + * | post_format | 1 | + * +-------------+--------+ + * + * # Get capabilities of a taxonomy + * $ wp taxonomy get post_tag --field=cap + * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} + * * @package wp-cli */ class Taxonomy_Command extends WP_CLI_Command { @@ -41,7 +57,16 @@ public function __construct() { * : Limit the output to specific taxonomy fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -110,7 +135,15 @@ public function list_( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * From 64282b69d5821064ad97eb1e7b63b86eb8baf829 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 07:22:37 +0545 Subject: [PATCH 4517/5359] Improve format parameter docs in term commands --- php/commands/term.php | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index c24aefe7f..256584682 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -61,7 +61,16 @@ class Term_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -212,7 +221,15 @@ public function create( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -346,7 +363,13 @@ public function delete( $args ) { * : Generate child terms down to a certain depth. Default: 1 * * [--format=<format>] - * : Accepted values: progress, ids. Default: ids. + * : Render output in a particular format. + * --- + * default: progress + * options: + * - progress + * - ids + * --- * * ## EXAMPLES * From f3c166a8d4cfd96c8bfd4e07496abe64bef56f9b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 07:31:14 +0545 Subject: [PATCH 4518/5359] Improve doc for format parameter in transient command --- php/commands/transient.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 62190eb22..f0d34437d 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -34,7 +34,15 @@ class Transient_Command extends WP_CLI_Command { * : Key for the transient. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * [--network] * : Get the value of the network transient, instead of the single site. @@ -46,7 +54,6 @@ class Transient_Command extends WP_CLI_Command { * * $ wp transient get random_key * Warning: Transient with key "random_key" is not set. - * */ public function get( $args, $assoc_args ) { list( $key ) = $args; From 8477fde97e3cba9c369a145750f71982b1130d4c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 3 Jun 2016 20:17:26 -0700 Subject: [PATCH 4519/5359] Always expect UTF-8 for consistent behavior between PHP versions --- php/utils-wp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index c0a054f2f..be7a4e1a7 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -40,7 +40,7 @@ function wp_die_handler( $message ) { $message = $matches[1]; } - $message = html_entity_decode( $message ); + $message = html_entity_decode( $message, ENT_COMPAT, 'UTF-8' ); \WP_CLI::error( $message ); } From 361aea6bc7856d5c94b4da0c1f1d8effea62ccb5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 15:11:53 +0545 Subject: [PATCH 4520/5359] add ids paramter in format --- php/commands/term.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/term.php b/php/commands/term.php index 256584682..7eca69d9a 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -67,6 +67,7 @@ class Term_Command extends WP_CLI_Command { * options: * - table * - csv + * - ids * - json * - count * - yaml From 57904d6da5ac1b66cd9c3808ce61c592d1e8d8ce Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 15:27:27 +0545 Subject: [PATCH 4521/5359] Improve format parameter in post-type commands --- php/commands/post-type.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/php/commands/post-type.php b/php/commands/post-type.php index c42a741ef..73d96afa4 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -47,7 +47,16 @@ class Post_Type_Command extends WP_CLI_Command { * : Limit the output to specific post type fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -109,7 +118,15 @@ public function list_( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * From 0979a5f896eea1d6025efdad7e9a73f626a9b5ce Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 15:37:39 +0545 Subject: [PATCH 4522/5359] Improve format parameter doc in role command --- php/commands/role.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 0eb2bab51..cccd636bf 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -48,7 +48,17 @@ class Role_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- + * * * ## AVAILABLE FIELDS * From 2b9c5e50ebb85fc7b77f172161cacb3b19fb325d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 15:51:17 +0545 Subject: [PATCH 4523/5359] Improve format parameter doc in cli commands --- php/commands/cli.php | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index c5ced77be..ce2db05cc 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -64,7 +64,12 @@ public function version() { * ## OPTIONS * * [--format=<format>] - * : Accepted values: json + * : Render output in a particular format. + * --- + * default: json + * options: + * - json + * --- * * ## EXAMPLES * @@ -131,7 +136,15 @@ public function info( $_, $assoc_args ) { * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * --- * * ## EXAMPLES * @@ -363,7 +376,13 @@ private function get_updates( $assoc_args ) { * : Display current values also. * * [--format=<format>] - * : Accepted values: var_export, json. Default: json. + * : Render output in a particular format. + * --- + * default: json + * options: + * - var_export + * - json + * --- * * ## EXAMPLES * From 12b197dea15ec12535d83c05b672495ba5c0cc24 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 16:16:11 +0545 Subject: [PATCH 4524/5359] Improve format parameter doc in comment commands --- php/commands/comment.php | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index bb424ca06..10a6796a0 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -117,7 +117,13 @@ public function update( $args, $assoc_args ) { * : Assign comments to a specific post. * * [--format=<format>] - * : Accepted values: progress, ids. Default: ids. + * : Render output in a particular format. + * --- + * default: progress + * options: + * - progress + * - ids + * --- * * ## EXAMPLES * @@ -184,7 +190,15 @@ public function generate( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -222,7 +236,17 @@ public function get( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - ids + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * From bfc3819de5807a3fb20e8a73ab9e306c55cc9f48 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 4 Jun 2016 05:18:27 -0700 Subject: [PATCH 4525/5359] Move `ms_site_not_found` action inside of `WP_CLI\Runner` --- php/WP_CLI/Runner.php | 25 +++++++++++++++++++++++++ php/wp-settings-cli.php | 7 ------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 10af1d3f0..cf4cfa106 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -936,6 +936,13 @@ private function setup_bootstrap_hooks() { $this->add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); + // In a multisite install, die if unable to find site given in --url parameter + if ( $this->is_multisite() ) { + $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { + WP_CLI::error( "Site {$domain}{$path} not found." ); + }, 10, 3 ); + } + } /** @@ -1095,6 +1102,24 @@ private function wp_hook_build_unique_id( $tag, $function, $priority ) { } } + /** + * Whether or not this WordPress install is multisite. + * + * For use after wp-config.php has loaded, but before the rest of WordPress + * is loaded. + */ + private function is_multisite() { + if ( defined( 'MULTISITE' ) ) { + return MULTISITE; + } + + if ( defined( 'SUBDOMAIN_INSTALL' ) || defined( 'VHOST' ) || defined( 'SUNRISE' ) ) { + return true; + } + + return false; + } + /** * Check whether there's a WP-CLI update available, and suggest update if so. */ diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 06628d9d7..0f7572875 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -88,13 +88,6 @@ unset( $values, $key, $value ); } -// In a multisite install, die if unable to find site given in --url parameter -if ( is_multisite() ) { - add_action( 'ms_site_not_found', function( $current_site, $domain, $path ) { - WP_CLI::error( "Site {$domain}{$path} not found." ); - }, 10, 3 ); -} - // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From ae0b6fba9f1d335d8ac127a874b88627332f7106 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 4 Jun 2016 05:24:36 -0700 Subject: [PATCH 4526/5359] Move `wp_redirect` handler to Runner from wp-settings-cli.php --- features/framework.feature | 16 ++++++++++++++++ php/WP_CLI/Runner.php | 3 +++ php/wp-settings-cli.php | 1 - 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/features/framework.feature b/features/framework.feature index d79936e0d..d39e90c5f 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -148,3 +148,19 @@ Feature: Load WP-CLI Error: This has no exit. Error: So I can use multiple lines. """ + + Scenario: A plugin calling wp_redirect() shouldn't redirect + Given a WP install + And a wp-content/mu-plugins/redirect.php file: + """ + <?php + add_action( 'init', function(){ + wp_redirect( 'http://apple.com' ); + }); + """ + + When I try `wp option get home` + Then STDERR should contain: + """ + Warning: Some code is trying to do a URL redirect. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cf4cfa106..d5291c4bf 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -936,6 +936,9 @@ private function setup_bootstrap_hooks() { $this->add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); + // Prevent code from performing a redirect + $this->add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); + // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 0f7572875..e574ce91f 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -70,7 +70,6 @@ require( ABSPATH . WPINC . '/pomo/mo.php' ); // WP_CLI: Early hooks -add_filter( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); if ( defined( 'WP_INSTALLING' ) && is_multisite() ) { $values = array( 'ms_files_rewriting' => null, From c34f1334cdab158076f269173802db08e9e981fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 4 Jun 2016 05:43:54 -0700 Subject: [PATCH 4527/5359] Move filters for suppressing multisite installation warnings --- features/core.feature | 17 +++++++++++++++-- php/WP_CLI/Runner.php | 17 +++++++++++++++++ php/wp-settings-cli.php | 18 ------------------ 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/features/core.feature b/features/core.feature index a0f2f54ec..0f91b7b62 100644 --- a/features/core.feature +++ b/features/core.feature @@ -132,7 +132,13 @@ Feature: Manage WordPress installation Then the return code should be 1 When I run `wp core install-network --title='test network'` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Set up multisite database tables. + Added multisite constants to wp-config.php. + Success: Network installed. Don't forget to set up rewrite rules. + """ + And STDERR should be empty When I run `wp eval 'var_export( is_multisite() );'` Then STDOUT should be: @@ -159,7 +165,14 @@ Feature: Manage WordPress installation And a database When I run `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Created single site database tables. + Set up multisite database tables. + Added multisite constants to wp-config.php. + Success: Network installed. Don't forget to set up rewrite rules. + """ + And STDERR should be empty When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` Then STDOUT should be: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index d5291c4bf..50141bb09 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -939,6 +939,23 @@ private function setup_bootstrap_hooks() { // Prevent code from performing a redirect $this->add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); + // Get rid of warnings when converting single site to multisite + if ( defined( 'WP_INSTALLING' ) && $this->is_multisite() ) { + $values = array( + 'ms_files_rewriting' => null, + 'active_sitewide_plugins' => array(), + '_site_transient_update_core' => null, + '_site_transient_update_themes' => null, + '_site_transient_update_plugins' => null, + 'WPLANG' => '', + ); + foreach ( $values as $key => $value ) { + $this->add_wp_hook( "pre_site_option_$key", function () use ( $values, $key ) { + return $values[ $key ]; + } ); + } + } + // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index e574ce91f..9bbb77c42 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -69,24 +69,6 @@ require( ABSPATH . WPINC . '/class-wp-error.php' ); require( ABSPATH . WPINC . '/pomo/mo.php' ); -// WP_CLI: Early hooks -if ( defined( 'WP_INSTALLING' ) && is_multisite() ) { - $values = array( - 'ms_files_rewriting' => null, - 'active_sitewide_plugins' => array(), - '_site_transient_update_core' => null, - '_site_transient_update_themes' => null, - '_site_transient_update_plugins' => null, - 'WPLANG' => '', - ); - foreach ( $values as $key => $value ) { - add_filter( "pre_site_option_$key", function () use ( $values, $key ) { - return $values[ $key ]; - } ); - } - unset( $values, $key, $value ); -} - // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); From c1fdcb0ea17138fbe89a7a8062e4b13b1d98f242 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 4 Jun 2016 05:48:42 -0700 Subject: [PATCH 4528/5359] Skip `ms_site_check` when installing --- php/WP_CLI/Runner.php | 4 ++++ php/wp-settings-cli.php | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 50141bb09..6192de314 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -956,6 +956,10 @@ private function setup_bootstrap_hooks() { } } + if ( defined( 'WP_INSTALLING' ) ) { + $this->add_wp_hook( 'ms_site_check', '__return_true' ); + } + // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 9bbb77c42..76d9f7567 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -369,8 +369,7 @@ do_action( 'init' ); // Check site status -# if ( is_multisite() ) { // WP-CLI -if ( is_multisite() && !defined('WP_INSTALLING') ) { +if ( is_multisite() ) { if ( true !== ( $file = ms_site_check() ) ) { require( $file ); die(); From 49ed9a43f502dd352224668d3f7f28ba2926b4ae Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 4 Jun 2016 20:10:43 +0545 Subject: [PATCH 4529/5359] remove if empty condition check in list-caps --- php/commands/user.php | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index a775acccc..4db4b5482 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -686,24 +686,22 @@ public function list_caps( $args, $assoc_args ) { } } - if ( ! empty( $active_user_cap_list ) ) { - if ( 'list' === $assoc_args['format'] ) { - foreach ( $active_user_cap_list as $cap ) { - WP_CLI::line( $cap ); - } + if ( 'list' === $assoc_args['format'] ) { + foreach ( $active_user_cap_list as $cap ) { + WP_CLI::line( $cap ); } - else { - $output_caps = array(); - foreach ( $active_user_cap_list as $cap ) { - $output_cap = new stdClass; + } + else { + $output_caps = array(); + foreach ( $active_user_cap_list as $cap ) { + $output_cap = new stdClass; - $output_cap->name = $cap; + $output_cap->name = $cap; - $output_caps[] = $output_cap; - } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->cap_fields ); - $formatter->display_items( $output_caps ); + $output_caps[] = $output_cap; } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->cap_fields ); + $formatter->display_items( $output_caps ); } } From b312b063a271952aef9cc612f3b5e24ea0e20c9e Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 6 Jun 2016 11:25:35 +0545 Subject: [PATCH 4530/5359] Add examples for theme commands --- php/commands/theme.php | 95 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index d2f3443e4..5a9361e2a 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -3,6 +3,36 @@ /** * Manage themes. * + * ## EXAMPLES + * + * # Install the latest version from wordpress.org and activate + * $ wp theme install twentysixteen --activate + * Installing Twenty Sixteen (1.2) + * Downloading install package from http://downloads.wordpress.org/theme/twentysixteen.1.2.zip... + * Unpacking the package... + * Installing the theme... + * Theme installed successfully. + * Activating 'twentysixteen'... + * Success: Switched to 'Twenty Sixteen' theme. + * + * # Get theme + * $ wp theme get twentysixteen --fields=name,title,version + * +---------+----------------+ + * | Field | Value | + * +---------+----------------+ + * | name | Twenty Sixteen | + * | title | Twenty Sixteen | + * | version | 1.2 | + * +---------+----------------+ + * + * # Get status of theme + * $ wp theme status twentysixteen + * Theme twentysixteen details: + * Name: Twenty Sixteen + * Status: Active + * Version: 1.2 + * Author: the WordPress team + * * @package wp-cli */ class Theme_Command extends \WP_CLI\CommandWithUpgrade { @@ -257,9 +287,13 @@ public function enable( $args, $assoc_args ) { * * ## EXAMPLES * - * wp theme disable twentythirteen + * # Disable theme + * $ wp theme disable twentysixteen + * Success: Disabled the 'Twenty Sixteen' theme. * - * wp theme disable twentythirteen --network + * # Disable theme in network level + * $ wp theme disable twentysixteen --network + * Success: Network disabled the 'Twenty Sixteen' theme. */ public function disable( $args, $assoc_args ) { if ( ! is_multisite() ) { @@ -303,7 +337,12 @@ private function is_active_theme( $theme ) { * * ## EXAMPLES * - * cd $(wp theme path) + * # Get theme path + * $ wp theme path + * /var/www/example.com/public_html/wp-content/themes + * + * # Change directory to theme path + * $ cd $(wp theme path) */ public function path( $args, $assoc_args ) { if ( empty( $args ) ) { @@ -420,13 +459,20 @@ protected function filter_item_list( $items, $args ) { * ## EXAMPLES * * # Install the latest version from wordpress.org and activate - * wp theme install twentytwelve --activate + * $ wp theme install twentysixteen --activate + * Installing Twenty Sixteen (1.2) + * Downloading install package from http://downloads.wordpress.org/theme/twentysixteen.1.2.zip... + * Unpacking the package... + * Installing the theme... + * Theme installed successfully. + * Activating 'twentysixteen'... + * Success: Switched to 'Twenty Sixteen' theme. * * # Install from a local zip file - * wp theme install ../my-theme.zip + * $ wp theme install ../my-theme.zip * * # Install from a remote zip file - * wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef + * $ wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef */ function install( $args, $assoc_args ) { @@ -516,9 +562,28 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * wp theme update twentyeleven twentytwelve - * - * wp theme update --all + * # Update multiple themes + * $ wp theme update twentyfifteen twentysixteen + * Downloading update from https://downloads.wordpress.org/theme/twentyfifteen.1.5.zip... + * Unpacking the update... + * Installing the latest version... + * Removing the old version of the theme... + * Theme updated successfully. + * Downloading update from https://downloads.wordpress.org/theme/twentysixteen.1.2.zip... + * Unpacking the update... + * Installing the latest version... + * Removing the old version of the theme... + * Theme updated successfully. + * Success: Updated 2/2 themes. + * +---------------+-------------+-------------+---------+ + * | name | old_version | new_version | status | + * +---------------+-------------+-------------+---------+ + * | twentyfifteen | 1.4 | 1.5 | Updated | + * | twentysixteen | 1.1 | 1.2 | Updated | + * +---------------+-------------+-------------+---------+ + * + * # Update all themes + * $ wp theme update --all * * @alias upgrade */ @@ -550,8 +615,10 @@ function update( $args, $assoc_args ) { * * ## EXAMPLES * - * wp theme is-installed twentytwelve - * echo $? # displays 0 or 1 + * # Check whether theme is installed; exit status 0 if installed, otherwise 1 + * $ wp theme is-installed hello-dolly + * $ echo $? + * 1 * * @subcommand is-installed */ @@ -635,7 +702,11 @@ function delete( $args ) { * * ## EXAMPLES * - * wp theme list --status=inactive --format=csv + * # List themes + * $ wp theme list --status=inactive --format=csv + * name,status,update,version + * twentyfourteen,inactive,none,1.7 + * twentysixteen,inactive,available,1.1 * * @subcommand list */ From 873ffaa85a860488e293351427cae58a77ed462c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 6 Jun 2016 13:18:57 +0545 Subject: [PATCH 4531/5359] Add examples for theme mods commands --- php/commands/theme.php | 64 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 5a9361e2a..79380cfd0 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -718,6 +718,19 @@ public function list_( $_, $assoc_args ) { /** * Manage theme mods. * + * ## EXAMPLES + * + * # Set theme mod + * $ wp theme mod set background_color 000000 + * Success: Theme mod background_color set to 000000 + * + * # Get single theme mod in JSON format + * $ wp theme mod get background_color --format=json + * [{"key":"background_color","value":"dd3333"}] + * + * # Remove all theme mods + * $ wp theme mod remove --all + * Success: Theme mods removed. */ class Theme_Mod_command extends WP_CLI_Command { @@ -733,13 +746,38 @@ class Theme_Mod_command extends WP_CLI_Command { * : List all theme mods * * [--format=<format>] - * : Accepted values: table, json. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - json + * --- * * ## EXAMPLES * - * wp theme mod get --all - * wp theme mod get background_color --format=json - * wp theme mod get background_color header_textcolor + * # Get all theme mods + * $ wp theme mod get --all + * +------------------+---------+ + * | key | value | + * +------------------+---------+ + * | background_color | dd3333 | + * | link_color | #dd9933 | + * | main_text_color | #8224e3 | + * +------------------+---------+ + * + * # Get single theme mod in JSON format + * $ wp theme mod get background_color --format=json + * [{"key":"background_color","value":"dd3333"}] + * + * # Get multiple theme mods + * $ wp theme mod get background_color header_textcolor + * +------------------+--------+ + * | key | value | + * +------------------+--------+ + * | background_color | dd3333 | + * | header_textcolor | | + * +------------------+--------+ */ public function get( $args = array(), $assoc_args = array() ) { @@ -797,9 +835,17 @@ public function get( $args = array(), $assoc_args = array() ) { * * ## EXAMPLES * - * wp theme mod remove --all - * wp theme mod remove background_color - * wp theme mod remove background_color header_textcolor + * # Remove all theme mods + * $ wp theme mod remove --all + * Success: Theme mods removed. + * + * # Remove single theme mods + * $ wp theme mod remove background_color + * Success: 1 mods removed. + * + * # Remove multiple theme mods + * $ wp theme mod remove background_color header_textcolor + * Success: 2 mods removed. */ public function remove( $args = array(), $assoc_args = array() ) { @@ -834,7 +880,9 @@ public function remove( $args = array(), $assoc_args = array() ) { * * ## EXAMPLES * - * wp theme mod set background_color 000000 + * # Set theme mod + * $ wp theme mod set background_color 000000 + * Success: Theme mod background_color set to 000000 */ public function set( $args = array(), $assoc_args = array() ) { list( $mod, $value ) = $args; From 730f0d94fa64ead44349b74e5e95fee37971c8dd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 06:10:18 -0700 Subject: [PATCH 4532/5359] Treat `@[A-Za-z0-9-_]+` defined in `wp-cli.yml` as an alias More than one named alias can be registered. The matching alias will overload the global parameters it defines. --- php/WP_CLI/Configurator.php | 18 +++++++++++++++++- php/WP_CLI/Runner.php | 26 ++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 8a92bf6bd..d9921425a 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -24,6 +24,11 @@ class Configurator { */ private $extra_config = array(); + /** + * @var array $aliases Any aliases defined in config files. + */ + private $aliases = array(); + /** * @param string $path Path to config spec file. */ @@ -63,6 +68,15 @@ function get_spec() { return $this->spec; } + /** + * Get any aliases defined in config files. + * + * @return array + */ + function get_aliases() { + return $this->aliases; + } + /** * Splits a list of arguments into positional, associative and config. * @@ -142,7 +156,9 @@ public function merge_yml( $path ) { $this->merge_yml( $yaml['_']['inherit'] ); } foreach ( $yaml as $key => $value ) { - if ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { + if ( preg_match( '#@[A-Za-z0-9-_]+#', $key ) ) { + $this->aliases[ $key ] = $value; + } elseif ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { if ( isset( $this->extra_config[ $key ] ) && ! empty( $yaml['_']['merge'] ) && is_array( $this->extra_config[ $key ] ) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6192de314..ef2c323ae 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -17,6 +17,10 @@ class Runner { private $config, $extra_config; + private $alias; + + private $aliases; + private $arguments, $assoc_args; private $_early_invoke = array(); @@ -587,6 +591,14 @@ private function check_wp_version() { private function init_config() { $configurator = \WP_CLI::get_configurator(); + $argv = array_slice( $GLOBALS['argv'], 1 ); + + if ( ! empty( $argv[0] ) && preg_match( '#^@[A-Za-z0-9-_]+$#', $argv[0], $matches ) ) { + $this->alias = array_shift( $argv ); + } else { + $this->alias = null; + } + // File config { $this->global_config_path = $this->get_global_config_path(); @@ -602,8 +614,7 @@ private function init_config() { // Runtime config and args { - list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( - array_slice( $GLOBALS['argv'], 1 ) ); + list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( $args, $assoc_args ); @@ -612,6 +623,7 @@ private function init_config() { } list( $this->config, $this->extra_config ) = $configurator->to_array(); + $this->aliases = $configurator->get_aliases(); $this->_required_files['runtime'] = $this->config['require']; } @@ -642,6 +654,13 @@ private function check_root() { ); } + private function set_alias( $alias ) { + if ( ! array_key_exists( $alias, $this->aliases ) ) { + WP_CLI::error( "Alias '{$alias}' not found." ); + } + $this->config = array_merge( $this->config, $this->aliases[ $this->alias ] ); + } + public function start() { $this->init_config(); $this->init_colorization(); @@ -651,6 +670,9 @@ public function start() { WP_CLI::debug( $this->_project_config_path_debug, 'bootstrap' ); $this->check_root(); + if ( $this->alias ) { + $this->set_alias( $this->alias ); + } if ( empty( $this->arguments ) ) $this->arguments[] = 'help'; From 513e85bf345148df7db364ee714b02084ca2462c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 06:12:34 -0700 Subject: [PATCH 4533/5359] Tests for 730f0d9 --- features/aliases.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 features/aliases.feature diff --git a/features/aliases.feature b/features/aliases.feature new file mode 100644 index 000000000..2bd738e03 --- /dev/null +++ b/features/aliases.feature @@ -0,0 +1,28 @@ +Feature: Create shortcuts to specific WordPress installs + + Scenario: Alias for a path to a specific WP install + Given a WP install in 'testdir' + And a wp-cli.yml file: + """ + @testdir: + path: testdir + """ + + When I try `wp core is-installed` + Then STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ + And the return code should be 1 + + When I run `wp @testdir core is-installed` + Then the return code should be 0 + + Scenario: Error when invalid alias provided + Given an empty directory + + When I try `wp @test option get home` + Then STDERR should be: + """ + Error: Alias '@test' not found. + """ From 82c8dadcaeca22ce6ad54015907ad88ae33c4d8d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 06:26:24 -0700 Subject: [PATCH 4534/5359] Treat global params as local when alias is used --- features/aliases.feature | 24 ++++++++++++++++++++++++ php/WP_CLI/Runner.php | 9 ++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/features/aliases.feature b/features/aliases.feature index 2bd738e03..b8d9b9fbc 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -26,3 +26,27 @@ Feature: Create shortcuts to specific WordPress installs """ Error: Alias '@test' not found. """ + + Scenario: Treat global params as local when alias is used + Given a WP install in 'testdir' + And a wp-cli.yml file: + """ + @testdir: + path: testdir + """ + + When I run `wp @testdir option get home` + Then STDOUT should be: + """ + http://example.com + """ + + When I try `wp @testdir option get home --path=testdir` + Then STDERR should contain: + """ + Parameter errors: + """ + And STDERR should contain: + """ + unknown --path parameter + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ef2c323ae..f2e5c8cc9 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -658,7 +658,14 @@ private function set_alias( $alias ) { if ( ! array_key_exists( $alias, $this->aliases ) ) { WP_CLI::error( "Alias '{$alias}' not found." ); } - $this->config = array_merge( $this->config, $this->aliases[ $this->alias ] ); + $orig_config = $this->config; + $alias_config = $this->aliases[ $this->alias ]; + $this->config = array_merge( $orig_config, $alias_config ); + foreach( $alias_config as $key => $_ ) { + if ( isset( $orig_config[ $key ] ) && ! is_null( $orig_config[ $key ] ) ) { + $this->assoc_args[ $key ] = $orig_config[ $key ]; + } + } } public function start() { From 867438b9e79bba30ebf93c559dc22a0420434ad4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 06:57:55 -0700 Subject: [PATCH 4535/5359] Aliases are config parameters specific to the WP install, not WP-CLI runtime --- features/aliases.feature | 16 ++++++++++++++++ php/WP_CLI/Configurator.php | 12 +++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/features/aliases.feature b/features/aliases.feature index b8d9b9fbc..176eff1cf 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -50,3 +50,19 @@ Feature: Create shortcuts to specific WordPress installs """ unknown --path parameter """ + + Scenario: Support global params specific to the WordPress install, not WP-CLI generally + Given a WP install in 'testdir' + And a wp-cli.yml file: + """ + @testdir: + path: testdir + debug: true + """ + + When I run `wp @testdir option get home` + Then STDOUT should be: + """ + http://example.com + """ + And STDERR should be empty diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index d9921425a..d9cb9789a 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -157,7 +157,17 @@ public function merge_yml( $path ) { } foreach ( $yaml as $key => $value ) { if ( preg_match( '#@[A-Za-z0-9-_]+#', $key ) ) { - $this->aliases[ $key ] = $value; + $this->aliases[ $key ] = array(); + foreach( array( + 'user', + 'url', + 'path', + 'ssh', + ) as $i ) { + if ( isset( $value[ $i ] ) ) { + $this->aliases[ $key ][ $i ] = $value[ $i ]; + } + } } elseif ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { if ( isset( $this->extra_config[ $key ] ) && ! empty( $yaml['_']['merge'] ) From 00e03ec0858d9182170ca7b25c10465ecc40c481 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 07:05:51 -0700 Subject: [PATCH 4536/5359] Set current user on `init` early, instead of after wp-settings.php load This more closely mirrors WordPress' behavior, allowing the rest of `wp-settings.php` to operate under the expected user context. --- php/WP_CLI/Runner.php | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6192de314..e28e7f9c6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -204,21 +204,6 @@ private static function set_wp_root( $path ) { $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); } - /** - * Set a specific user context for WordPress. - * - * @param array $assoc_args - */ - private static function set_user( $assoc_args ) { - if ( isset( $assoc_args['user'] ) ) { - $fetcher = new \WP_CLI\Fetchers\User; - $user = $fetcher->get_check( $assoc_args['user'] ); - wp_set_current_user( $user->ID ); - } else { - kses_remove_filters(); - } - } - /** * Guess which URL context WP-CLI has been invoked under. * @@ -864,11 +849,6 @@ public function load_wordpress() { add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - // Handle --user parameter - if ( ! defined( 'WP_INSTALLING' ) ) { - self::set_user( $this->config ); - } - WP_CLI::debug( 'Loaded WordPress', 'bootstrap' ); WP_CLI::do_hook( 'after_wp_load' ); @@ -967,6 +947,20 @@ private function setup_bootstrap_hooks() { }, 10, 3 ); } + // Handle --user parameter + if ( ! defined( 'WP_INSTALLING' ) ) { + $config = $this->config; + $this->add_wp_hook( 'init', function() use ( $config ) { + if ( isset( $config['user'] ) ) { + $fetcher = new \WP_CLI\Fetchers\User; + $user = $fetcher->get_check( $config['user'] ); + wp_set_current_user( $user->ID ); + } else { + kses_remove_filters(); + } + }, 0 ); + } + } /** From 83524c81fff372d63fdac34e9776da2926107367 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 08:47:39 -0700 Subject: [PATCH 4537/5359] `kses_init` happens with default priority, so we need to do this after --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e28e7f9c6..e5832d36c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -956,7 +956,7 @@ private function setup_bootstrap_hooks() { $user = $fetcher->get_check( $config['user'] ); wp_set_current_user( $user->ID ); } else { - kses_remove_filters(); + add_action( 'init', 'kses_remove_filters', 11 ); } }, 0 ); } From 13667aad29a7528c63b01f718178c29fb40fa984 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 08:59:09 -0700 Subject: [PATCH 4538/5359] Add explicit test case for expected behavior of `--user` --- features/aliases.feature | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/features/aliases.feature b/features/aliases.feature index 176eff1cf..06ff9197b 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -27,7 +27,7 @@ Feature: Create shortcuts to specific WordPress installs Error: Alias '@test' not found. """ - Scenario: Treat global params as local when alias is used + Scenario: Treat global params as local when included in alias Given a WP install in 'testdir' And a wp-cli.yml file: """ @@ -51,6 +51,35 @@ Feature: Create shortcuts to specific WordPress installs unknown --path parameter """ + When I run `wp @testdir eval 'echo get_current_user_id();' --user=admin` + Then STDOUT should be: + """ + 1 + """ + + Given a wp-cli.yml file: + """ + @testdir: + path: testdir + user: admin + """ + + When I run `wp @testdir eval 'echo get_current_user_id();'` + Then STDOUT should be: + """ + 1 + """ + + When I try `wp @testdir eval 'echo get_current_user_id();' --user=admin` + Then STDERR should contain: + """ + Parameter errors: + """ + And STDERR should contain: + """ + unknown --user parameter + """ + Scenario: Support global params specific to the WordPress install, not WP-CLI generally Given a WP install in 'testdir' And a wp-cli.yml file: From 0f59dfbde0c561f1ee06becba1c23ca96d1299ff Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:00:59 +0545 Subject: [PATCH 4539/5359] Add csv and yaml for allowed values as format in theme mod get command --- php/commands/theme.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 79380cfd0..ea7785cce 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -752,6 +752,8 @@ class Theme_Mod_command extends WP_CLI_Command { * options: * - table * - json + * - csv + * - yaml * --- * * ## EXAMPLES From 359b7d6b7b0b76da337882261652a41ede3f55e4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:07:45 +0545 Subject: [PATCH 4540/5359] Add yaml as allowed parameter in cli check-update --- php/commands/cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index ce2db05cc..83749f4ce 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -144,6 +144,7 @@ public function info( $_, $assoc_args ) { * - csv * - json * - count + * - yaml * --- * * ## EXAMPLES From e9ecb8e69c71928f698d78bff07fe4f24a640b9c Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:11:50 +0545 Subject: [PATCH 4541/5359] Add list as default format in cli info command --- php/commands/cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 83749f4ce..05660833b 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -66,8 +66,9 @@ public function version() { * [--format=<format>] * : Render output in a particular format. * --- - * default: json + * default: list * options: + * - list * - json * --- * From 3922a9b15353b7f0e56fd9af9d48d8fc83afbb1b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 09:32:36 -0700 Subject: [PATCH 4542/5359] Fix PHP notice when installing a child theme `Plugin_Installer_Skin` and `Theme_Installer_Skin` both use a public `$api` class variable. We can safely define this too to prevent the error notice. --- php/WP_CLI/UpgraderSkin.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php index a0df91820..7af55981c 100644 --- a/php/WP_CLI/UpgraderSkin.php +++ b/php/WP_CLI/UpgraderSkin.php @@ -9,6 +9,8 @@ */ class UpgraderSkin extends \WP_Upgrader_Skin { + public $api; + function header() {} function footer() {} function bulk_header() {} From 9fd087ddfbbda553b8cd6ea5debcb99d4754e705 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:32:23 +0545 Subject: [PATCH 4543/5359] Add test for cli info without format parameter --- features/cli-info.feature | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/features/cli-info.feature b/features/cli-info.feature index e5911b1d5..1439a4977 100644 --- a/features/cli-info.feature +++ b/features/cli-info.feature @@ -17,3 +17,8 @@ Feature: Review CLI information """ {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} """ + And I run `wp cli info` + Then STDOUT should contain: + """ + WP-CLI packages dir: /tmp/wp-cli-home/.wp-cli/packages/ + """ From c9eda43712512548d1cd56ac170fe7c83725fba3 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:35:46 +0545 Subject: [PATCH 4544/5359] Separate when condition for cli info test --- features/cli-info.feature | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/cli-info.feature b/features/cli-info.feature index 1439a4977..ca455f642 100644 --- a/features/cli-info.feature +++ b/features/cli-info.feature @@ -17,7 +17,8 @@ Feature: Review CLI information """ {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} """ - And I run `wp cli info` + + When I run `wp cli info` Then STDOUT should contain: """ WP-CLI packages dir: /tmp/wp-cli-home/.wp-cli/packages/ From 3192ae065b06ce95af08d15faa035da8545af6d2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 6 Jun 2016 22:57:52 +0545 Subject: [PATCH 4545/5359] Default improvement in sidebar commands --- php/commands/sidebar.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index f71236059..874507396 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -28,7 +28,16 @@ class Sidebar_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * From 61393a833c98bbdb4df91b94eb009c8c19c80c29 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 11:00:14 -0700 Subject: [PATCH 4546/5359] Add explicit test for inheritance behavior --- features/aliases.feature | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index 06ff9197b..eb17625f6 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -95,3 +95,28 @@ Feature: Create shortcuts to specific WordPress installs http://example.com """ And STDERR should be empty + + Scenario: Defining a project alias completely overrides a global alias + Given a WP install in 'testdir' + And a config.yml file: + """ + @testdir: + path: testdir + """ + + When I run `WP_CLI_CONFIG_PATH=config.yml wp @testdir option get home` + Then STDOUT should be: + """ + http://example.com + """ + + Given a wp-cli.yml file: + """ + @testdir: + path: none-existent-install + """ + When I try `WP_CLI_CONFIG_PATH=config.yml wp @testdir option get home` + Then STDERR should contain: + """ + Error: This does not seem to be a WordPress install. + """ From 04ca01514e7601379e3d033fe9e7f91a4a375369 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 13:31:10 -0700 Subject: [PATCH 4547/5359] Escape ssh arguments to ensure they're quoted; include pretty version --- php/WP_CLI/Runner.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 13a042bfb..8de0b5219 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -350,16 +350,24 @@ private function run_ssh_command( $ssh ) { unset( $wp_args[ $k ] ); } } - $command = sprintf( + + $unescaped_command = sprintf( 'ssh -q %s %s %s', - escapeshellarg( $host ), + $host, $is_tty ? '-t' : '-T', - escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', $wp_args ) ) + $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ); - WP_CLI::debug( 'Running SSH command: ' . $command, 'bootstrap' ); + WP_CLI::debug( 'Running SSH command: ' . $unescaped_command, 'bootstrap' ); + + $escaped_command = sprintf( + 'ssh -q %s %s %s', + escapeshellarg( $host ), + $is_tty ? '-t' : '-T', + escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) + ); - passthru( $command, $exit_code ); + passthru( $escaped_command, $exit_code ); if ( 0 !== $exit_code ) { exit( $exit_code ); } From 7bca58052d316ada65c67c4baec115389eda5dd2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 16:44:37 -0700 Subject: [PATCH 4548/5359] Always permit CLI operations against sites, regardless of status When using WP-CLI without the `--user=<user>` argument, the expectation is that you can perform any operation, and those operations aren't run as any user. Even when the `--user=<user>` argument is provided, there's a reasonable assumption the CLI operation isn't meant to run into a capability check. --- features/site.feature | 17 +++++++++++++++++ php/WP_CLI/Runner.php | 5 ++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/features/site.feature b/features/site.feature index a6980b163..42c29ab52 100644 --- a/features/site.feature +++ b/features/site.feature @@ -257,3 +257,20 @@ Feature: Manage sites in a multisite installation """ Warning: You are not allowed to change the main site. """ + + Scenario: Permit CLI operations against archived and suspended sites + Given a WP multisite install + And I run `wp site create --slug=first --porcelain` + And save STDOUT as {FIRST_SITE} + + When I run `wp site archive {FIRST_SITE}` + Then STDOUT should be: + """ + Success: Site {FIRST_SITE} archived. + """ + + When I run `wp --url=example.com/first option get home` + Then STDOUT should be: + """ + http://example.com/first + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 13a042bfb..51773a8e7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -965,9 +965,8 @@ private function setup_bootstrap_hooks() { } } - if ( defined( 'WP_INSTALLING' ) ) { - $this->add_wp_hook( 'ms_site_check', '__return_true' ); - } + // Always permit operations against sites, regardless of status + $this->add_wp_hook( 'ms_site_check', '__return_true' ); // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { From fcd1c76b2806d3cf52d1bc5f67a9e88592120d48 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 6 Jun 2016 16:48:38 -0700 Subject: [PATCH 4549/5359] Fix PHPCS issue --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8de0b5219..5c435bdb5 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -353,7 +353,7 @@ private function run_ssh_command( $ssh ) { $unescaped_command = sprintf( 'ssh -q %s %s %s', - $host, + $host, $is_tty ? '-t' : '-T', $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ); From ee1d0a13739678a79e02107dd2f3c7ba8d8eac94 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 7 Jun 2016 09:14:55 +0545 Subject: [PATCH 4550/5359] Fix build error in test of cli info --- features/cli-info.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cli-info.feature b/features/cli-info.feature index ca455f642..b5cedc145 100644 --- a/features/cli-info.feature +++ b/features/cli-info.feature @@ -21,5 +21,5 @@ Feature: Review CLI information When I run `wp cli info` Then STDOUT should contain: """ - WP-CLI packages dir: /tmp/wp-cli-home/.wp-cli/packages/ + WP-CLI packages dir: """ From 5311f42423d467b6e003e0fb33ff714e3c3eaf86 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 7 Jun 2016 16:25:41 +0545 Subject: [PATCH 4551/5359] Improve doc in server command --- php/commands/server.php | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index ec6d0656c..c05ba5bac 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -1,5 +1,18 @@ <?php - +/** + * Launch PHP's built-in web server. + * + * ## EXAMPLES + * + * # Make the instance available on any address (with port 8080) + * $ wp server --host=0.0.0.0 + * PHP 5.6.9 Development Server started at Tue May 24 01:27:11 2016 + * Listening on http://0.0.0.0:8080 + * Document root is / + * Press Ctrl-C to quit. + * + * @package wp-cli + */ class Server_Command extends WP_CLI_Command { /** @@ -10,10 +23,16 @@ class Server_Command extends WP_CLI_Command { * ## OPTIONS * * [--host=<host>] - * : The hostname to bind the server to. Default: localhost + * : The hostname to bind the server to. + * --- + * default: localhost + * --- * * [--port=<port>] - * : The port number to bind the server to. Default: 8080 + * : The port number to bind the server to. + * --- + * default: 8080 + * --- * * [--docroot=<path>] * : The path to use as the document root. From e67f14db9c7b06f297d86440fb497fd03242e5db Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 7 Jun 2016 16:35:12 +0545 Subject: [PATCH 4552/5359] Example: shell command --- php/commands/shell.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index a4b8ebb3f..5fe7dfa6e 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -1,5 +1,15 @@ <?php - +/** + * Interactive PHP console. + * + * ## EXAMPLES + * + * # Start interactive PHP console + * $ wp shell + * wp> + * + * @package wp-cli + */ class Shell_Command extends \WP_CLI_Command { /** @@ -13,6 +23,12 @@ class Shell_Command extends \WP_CLI_Command { * * [--basic] * : Start in fail-safe mode, even if Boris is available. + * + * ## EXAMPLES + * + * # Start interactive PHP console + * $ wp shell + * wp> */ public function __invoke( $_, $assoc_args ) { $implementations = array( From 489f78950537d2c7e5094b85986b7b81eb148d79 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 8 Jun 2016 09:23:34 +0545 Subject: [PATCH 4553/5359] Example: core is-installed --- php/commands/core.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index f52846cd0..80a3eadae 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -422,6 +422,12 @@ public function config( $_, $assoc_args ) { * * ## EXAMPLES * + * # Check whether WordPress is installed; exit status 0 if installed, otherwise 1 + * $ wp core is-installed + * $ echo $? + * 1 + * + * # Bash script for checking whether WordPress is installed or not * if ! $(wp core is-installed); then * wp core install * fi From 5349e8c660e6456787151deee0762d50e062c927 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 8 Jun 2016 09:46:09 +0545 Subject: [PATCH 4554/5359] Improve doc in option commands --- php/commands/option.php | 57 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 432887964..a680fefd6 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -32,16 +32,25 @@ class Option_Command extends WP_CLI_Command { * Get an option. * * <key> - * : Key for the option + * : Key for the option. * * [--format=<format>] - * : Get value as var_export() or JSON. Default: var_export() + * : Get value in a particular format. + * --- + * default: var_export + * options: + * - var_export + * - json + * - yaml + * --- * * ## EXAMPLES * + * # Get option * $ wp option get home * http://example.com * + * # Get option in JSON format * $ wp option get active_plugins --format=json * {"0":"dynamically-dynamic-sidebar\/dynamically-dynamic-sidebar.php","1":"monster-widget\/monster-widget.php","2":"show-current-template\/show-current-template.php","3":"theme-check\/theme-check.php","5":"wordpress-importer\/wordpress-importer.php"} */ @@ -68,10 +77,22 @@ public function get( $args, $assoc_args ) { * : The value of the option to add. If ommited, the value is read from STDIN. * * [--format=<format>] - * : The serialization format for the value. Default is plaintext. + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- * * [--autoload=<autoload>] - * : Should this option be automatically loaded. Accepted values: yes, no. Default: yes + * : Should this option be automatically loaded. + * --- + * default: yes + * options: + * - yes + * - no + * --- * * ## EXAMPLES * @@ -111,7 +132,17 @@ public function add( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. Accepted values: table, json, csv, count, total_bytes. Default: table + * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. + * --- + * default: table + * options: + * - table + * - json + * - csv + * - count + * - yaml + * - total_bytes + * --- * * ## AVAILABLE FIELDS * @@ -215,10 +246,22 @@ public function list_( $args, $assoc_args ) { * : The new value. If ommited, the value is read from STDIN. * * [--autoload=<autoload>] - * : Requires WP 4.2. Should this option be automatically loaded. Accepted values: yes, no. Default: yes + * : Requires WP 4.2. Should this option be automatically loaded. + * --- + * default: yes + * options: + * - yes + * - no + * --- * * [--format=<format>] - * : The serialization format for the value. Default is plaintext. + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- * * ## EXAMPLES * From 64aaccbd002659b8aa693f7bfbbc1bfe4e72ab31 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 8 Jun 2016 20:46:57 +0545 Subject: [PATCH 4555/5359] Improve doc in rewrite commands --- php/commands/rewrite.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index bb0ecaafb..de7a62767 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -173,10 +173,22 @@ public function structure( $args, $assoc_args ) { * : Show rewrite rules from a particular source. * * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to match,query,source. + * : Limit the output to specific fields. + * --- + * default: match,query,source + * --- * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## EXAMPLES * From ba5f32bb3bafd4ef957ba5768a4a9b133666160d Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 8 Jun 2016 15:29:24 +0000 Subject: [PATCH 4556/5359] Example wp package browse, #2770 --- php/commands/package.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index bc7340280..63713095d 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -87,6 +87,27 @@ class Package_Command extends WP_CLI_Command { * * [--format=<format>] * : Accepted values: table, json, csv, yaml, ids. Default: table. + * + * ## EXAMPLES + * + * $ wp package browse --format=yaml + * --- + * 10up/mu-migration: + * name: 10up/mu-migration + * description: A set of WP-CLI commands to support the migration of single WordPress instances to multisite + * authors: Nícholas André + * version: dev-master, dev-develop + * aaemnnosttv/wp-cli-dotenv-command: + * name: aaemnnosttv/wp-cli-dotenv-command + * description: Dotenv commands for WP-CLI + * authors: Evan Mattson + * version: v0.1, v0.1-beta.1, v0.2, dev-master, dev-dev, dev-develop, dev-tests/behat + * aaemnnosttv/wp-cli-http-command: + * name: aaemnnosttv/wp-cli-http-command + * description: WP-CLI command for using the WordPress HTTP API + * authors: Evan Mattson + * version: dev-master + * */ public function browse( $_, $assoc_args ) { $this->show_packages( $this->get_community_packages(), $assoc_args ); From 2bd814bec4f345747117b88f2e820153141d67b6 Mon Sep 17 00:00:00 2001 From: hideokamoto <kokkoku214@gmail.com> Date: Wed, 8 Jun 2016 15:33:40 +0000 Subject: [PATCH 4557/5359] Example wp package path, #2770 --- php/commands/package.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index bc7340280..41e5021d3 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -228,7 +228,8 @@ public function list_( $args, $assoc_args ) { * /home/person/.wp-cli/packages/ * * # Change directory to package path - * $ cd $(wp package path) + * $ cd $(wp package path) && pwd + * /home/vagrant/.wp-cli/packages */ function path( $args ) { $packages_dir = WP_CLI::get_runner()->get_packages_dir_path(); From f19ea02ebb093195c309a622a75f6315713eb55c Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 11:56:02 +0545 Subject: [PATCH 4558/5359] Add trailing period in widget commands messages --- features/widget.feature | 5 ++++- php/commands/widget.php | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/widget.feature b/features/widget.feature index 610d963ea..51d746ae6 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -33,7 +33,10 @@ Feature: Manage widgets in WordPress sidebar Then STDOUT should not be empty When I run `wp widget deactivate meta-2` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Widget(s) deactivated. + """ When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: diff --git a/php/commands/widget.php b/php/commands/widget.php index ef4dcc347..6a7cf0c79 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -238,7 +238,7 @@ public function move( $args, $assoc_args ) { * ## EXAMPLES * * $ wp widget deactivate recent-comments-2 - * Success: Widget(s) deactivated + * Success: Widget(s) deactivated. * * @subcommand deactivate */ @@ -257,7 +257,7 @@ public function deactivate( $args, $assoc_args ) { } - WP_CLI::success( "Widget(s) deactivated" ); + WP_CLI::success( "Widget(s) deactivated." ); } /** From c111f6a730fe435c9fb9e4a2a31d50c4b9441cc5 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 12:10:22 +0545 Subject: [PATCH 4559/5359] Comment: add trailing period in messages --- features/comment-recount.feature | 2 +- php/commands/comment.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/comment-recount.feature b/features/comment-recount.feature index 5de768a0f..7208b97bd 100644 --- a/features/comment-recount.feature +++ b/features/comment-recount.feature @@ -21,5 +21,5 @@ Feature: Recount comments on a post When I run `wp comment recount 1` Then STDOUT should be: """ - Updated post 1 comment count to 3 + Updated post 1 comment count to 3. """ diff --git a/php/commands/comment.php b/php/commands/comment.php index 10a6796a0..56b1ad0b7 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -351,7 +351,7 @@ public function delete( $args, $assoc_args ) { return array( 'success', "Trashed comment $comment_id." ); } } else { - return array( 'error', "Failed deleting comment $comment_id" ); + return array( 'error', "Failed deleting comment $comment_id." ); } } ); } @@ -364,7 +364,7 @@ private function call( $args, $status, $success, $failure ) { if ( $func( $comment_id ) ) { WP_CLI::success( "$success comment $comment_id." ); } else { - WP_CLI::error( "$failure comment $comment_id" ); + WP_CLI::error( "$failure comment $comment_id." ); } } @@ -376,7 +376,7 @@ private function set_status( $args, $status, $success ) { if ( is_wp_error( $r ) ) { WP_CLI::error( $r ); } else { - WP_CLI::success( "$success comment $comment->comment_ID" ); + WP_CLI::success( "$success comment $comment->comment_ID." ); } } @@ -550,16 +550,16 @@ public function count( $args, $assoc_args ) { * ## EXAMPLES * * $ wp comment recount 123 - * Updated post 123 comment count to 67 + * Updated post 123 comment count to 67. */ public function recount( $args ) { foreach( $args as $id ) { wp_update_comment_count( $id ); $post = get_post( $id ); if ( $post ) { - WP_CLI::log( sprintf( "Updated post %d comment count to %d", $post->ID, $post->comment_count ) ); + WP_CLI::log( sprintf( "Updated post %d comment count to %d.", $post->ID, $post->comment_count ) ); } else { - WP_CLI::warning( sprintf( "Post %d doesn't exist", $post->ID ) ); + WP_CLI::warning( sprintf( "Post %d doesn't exist.", $post->ID ) ); } } } From 8660c2fc3af44f8a666e8ba1e57b448808629deb Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 12:23:36 +0545 Subject: [PATCH 4560/5359] CLI: add trailing period in messages --- features/cli.feature | 2 +- php/commands/cli.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/cli.feature b/features/cli.feature index 081ed727b..84046f49e 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -109,7 +109,7 @@ Feature: `wp cli` tasks When I run `{PHAR_PATH} cli update --nightly --yes` Then STDOUT should contain: """ - Success: Updated WP-CLI to the latest nightly release + Success: Updated WP-CLI to the latest nightly release. """ And STDERR should be empty diff --git a/php/commands/cli.php b/php/commands/cli.php index 05660833b..3e33904fa 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -215,9 +215,9 @@ public function update( $_, $assoc_args ) { $old_phar = realpath( $_SERVER['argv'][0] ); if ( ! is_writable( $old_phar ) ) { - WP_CLI::error( sprintf( "%s is not writable by current user", $old_phar ) ); + WP_CLI::error( sprintf( "%s is not writable by current user.", $old_phar ) ); } else if ( ! is_writeable( dirname( $old_phar ) ) ) { - WP_CLI::error( sprintf( "%s is not writable by current user", dirname( $old_phar ) ) ); + WP_CLI::error( sprintf( "%s is not writable by current user.", dirname( $old_phar ) ) ); } if ( isset( $assoc_args['nightly'] ) ) { @@ -271,7 +271,7 @@ public function update( $_, $assoc_args ) { $mode = fileperms( $old_phar ) & 511; if ( false === @chmod( $temp, $mode ) ) { - WP_CLI::error( sprintf( "Cannot chmod %s", $temp ) ); + WP_CLI::error( sprintf( "Cannot chmod %s.", $temp ) ); } class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class @@ -285,7 +285,7 @@ class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the } else { $updated_version = $newest['version']; } - WP_CLI::success( sprintf( 'Updated WP-CLI to %s', $updated_version ) ); + WP_CLI::success( sprintf( 'Updated WP-CLI to %s.', $updated_version ) ); } /** @@ -304,7 +304,7 @@ private function get_updates( $assoc_args ) { $response = Utils\http_request( 'GET', $url, $headers, $options ); if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d)", $response->status_code ) ); + WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d).", $response->status_code ) ); } $release_data = json_decode( $response->body ); From 7e256a3b4d306caccb4c47c7cb2807299be2937e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 16:21:55 +0545 Subject: [PATCH 4561/5359] Cron: add trailing period in command messages --- features/cron.feature | 4 ++-- php/commands/cron.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index fbdfae4d5..76b1ee0e8 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -122,7 +122,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event delete wp_cli_test_event_5` Then STDOUT should be: """ - Success: Deleted 2 instances of the cron event 'wp_cli_test_event_5' + Success: Deleted 2 instances of the cron event 'wp_cli_test_event_5'. """ When I run `wp cron event list` @@ -134,7 +134,7 @@ Feature: Manage WP-Cron events and schedules When I try `wp cron event delete wp_cli_test_event_5` Then STDERR should be: """ - Error: Invalid cron event 'wp_cli_test_event_5' + Error: Invalid cron event 'wp_cli_test_event_5'. """ Scenario: Scheduling and then running a re-occurring event diff --git a/php/commands/cron.php b/php/commands/cron.php index 297d950f9..6e531e6c8 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -177,7 +177,7 @@ public function schedule( $args, $assoc_args ) { if ( false !== $event ) { WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s GMT.", $hook, date( self::$time_format, $timestamp ) ) ); } else { - WP_CLI::error( 'Event not scheduled' ); + WP_CLI::error( 'Event not scheduled.' ); } } @@ -306,16 +306,16 @@ public function delete( $args, $assoc_args ) { if ( $result ) { $deleted++; } else { - WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'", $hook ) ); + WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'.", $hook ) ); } } } if ( $deleted ) { - $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'" : "Deleted %1\$d instances of the cron event '%2\$s'"; + $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'." : "Deleted %1\$d instances of the cron event '%2\$s'."; WP_CLI::success( sprintf( $message, $deleted, $hook ) ); } else { - WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); + WP_CLI::error( sprintf( "Invalid cron event '%s'.", $hook ) ); } } From aadd8c58ef4a2e570e13f3b289ba4273ce4dd0a4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 16:28:11 +0545 Subject: [PATCH 4562/5359] Transient: add trailing period in command messages --- php/commands/transient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index f0d34437d..3797d11fc 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -176,7 +176,7 @@ public function delete_expired() { if ( $count > 0 ) { WP_CLI::success( "$count expired transients deleted from the database." ); } else { - WP_CLI::success( "No expired transients found" ); + WP_CLI::success( "No expired transients found." ); } if ( $_wp_using_ext_object_cache ) { @@ -207,7 +207,7 @@ public function delete_all() { if ( $count > 0 ) { WP_CLI::success( "$count transients deleted from the database." ); } else { - WP_CLI::success( "No transients found" ); + WP_CLI::success( "No transients found." ); } if ( $_wp_using_ext_object_cache ) { From 8455c1c52f164c494ce4892cacffcba9e00821fb Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 16:35:00 +0545 Subject: [PATCH 4563/5359] Theme: add trailing period to theme commands messages --- features/theme-mod.feature | 2 +- php/commands/theme.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/theme-mod.feature b/features/theme-mod.feature index 7ef2115f7..61ac1d6aa 100644 --- a/features/theme-mod.feature +++ b/features/theme-mod.feature @@ -32,7 +32,7 @@ Feature: Manage WordPress theme mods When I run `wp theme mod set background_color 123456` Then STDOUT should be: """ - Success: Theme mod background_color set to 123456 + Success: Theme mod background_color set to 123456. """ Scenario: Removing theme mods diff --git a/php/commands/theme.php b/php/commands/theme.php index ea7785cce..54181962c 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -892,9 +892,9 @@ public function set( $args = array(), $assoc_args = array() ) { set_theme_mod( $mod, $value ); if ( $value == get_theme_mod( $mod ) ) { - WP_CLI::success( sprintf( "Theme mod %s set to %s", $mod, $value ) ); + WP_CLI::success( sprintf( "Theme mod %s set to %s.", $mod, $value ) ); } else { - WP_CLI::success( sprintf( "Could not update theme mod %s", $mod ) ); + WP_CLI::success( sprintf( "Could not update theme mod %s.", $mod ) ); } } From bf05d7d40a1b962bc36663c3696e9b2cccb63fea Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 11 Jun 2016 17:01:59 +0545 Subject: [PATCH 4564/5359] Improve default doc for widget commands --- php/commands/widget.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index ef4dcc347..8c10c7551 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -46,7 +46,17 @@ class Widget_Command extends WP_CLI_Command { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * From 560a472e99a86dbc46b25f16265d80efa5b56477 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 13 Jun 2016 05:20:54 -0700 Subject: [PATCH 4565/5359] Update Composer dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.7.11) - Installing symfony/yaml (v2.8.7) Downloading: 100% - Removing symfony/filesystem (v2.7.11) - Installing symfony/filesystem (v2.8.7) Downloading: 100% - Removing symfony/config (v2.7.11) - Installing symfony/config (v2.8.7) Downloading: 100% - Removing symfony/dependency-injection (v2.7.11) - Installing symfony/dependency-injection (v2.8.7) Downloading: 100% - Removing symfony/event-dispatcher (v2.7.11) - Installing symfony/event-dispatcher (v2.8.7) Downloading: 100% - Installing symfony/polyfill-mbstring (v1.2.0) Loading from cache - Removing symfony/translation (v2.7.11) - Installing symfony/translation (v2.8.7) Downloading: 100% - Installing psr/log (1.0.0) Loading from cache - Removing symfony/process (v2.8.4) - Installing symfony/process (v2.8.7) Downloading: 100% - Removing symfony/finder (v2.7.11) - Installing symfony/finder (v2.8.7) Downloading: 100% - Removing symfony/console (v2.7.11) - Installing symfony/console (v2.8.7) Downloading: 100% - Removing composer/spdx-licenses (1.1.3) - Installing composer/spdx-licenses (1.1.4) Downloading: 100% - Removing composer/semver (1.4.0) - Installing composer/semver (1.4.1) Downloading: 100% - Installing composer/ca-bundle (1.0.2) Downloading: 100% - Removing composer/composer (1.0.2) - Installing composer/composer (1.1.2) Downloading: 100% - Removing phpunit/php-timer (1.0.7) - Installing phpunit/php-timer (1.0.8) Loading from cache Writing lock file Generating autoload files ``` --- composer.lock | 243 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 171 insertions(+), 72 deletions(-) diff --git a/composer.lock b/composer.lock index 389c55967..ab7cf9aaa 100644 --- a/composer.lock +++ b/composer.lock @@ -8,24 +8,81 @@ "content-hash": "10cf19699e3fed767e31e1493a07c8f0", "packages": [ { - "name": "composer/composer", + "name": "composer/ca-bundle", "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "a2995e5fe351055f2c7630166af12ce8fd03edfc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/a2995e5fe351055f2c7630166af12ce8fd03edfc", + "reference": "a2995e5fe351055f2c7630166af12ce8fd03edfc", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "symfony/process": "^2.5 || ^3.0" + }, + "suggest": { + "symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2016-04-13 10:13:24" + }, + { + "name": "composer/composer", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "a083aa5e0c9b8ad989c622638aa380c1f88a68ec" + "reference": "b2cf67b1a575d7e648c742be2454339232ef32b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/a083aa5e0c9b8ad989c622638aa380c1f88a68ec", - "reference": "a083aa5e0c9b8ad989c622638aa380c1f88a68ec", + "url": "https://api.github.com/repos/composer/composer/zipball/b2cf67b1a575d7e648c742be2454339232ef32b2", + "reference": "b2cf67b1a575d7e648c742be2454339232ef32b2", "shasum": "" }, "require": { + "composer/ca-bundle": "^1.0", "composer/semver": "^1.0", "composer/spdx-licenses": "^1.0", "justinrainbow/json-schema": "^1.6", "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0", "seld/cli-prompt": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", @@ -49,7 +106,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -80,20 +137,20 @@ "dependency", "package" ], - "time": "2016-04-21 11:30:19" + "time": "2016-05-31 18:48:12" }, { "name": "composer/semver", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "84c47f3d8901440403217afc120683c7385aecb8" + "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/84c47f3d8901440403217afc120683c7385aecb8", - "reference": "84c47f3d8901440403217afc120683c7385aecb8", + "url": "https://api.github.com/repos/composer/semver/zipball/03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", + "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", "shasum": "" }, "require": { @@ -142,20 +199,20 @@ "validation", "versioning" ], - "time": "2016-03-30 13:16:03" + "time": "2016-06-02 09:04:51" }, { "name": "composer/spdx-licenses", - "version": "1.1.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "547659c3cacd3ccfe1b4714c2ff88cafc6b6793b" + "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/547659c3cacd3ccfe1b4714c2ff88cafc6b6793b", - "reference": "547659c3cacd3ccfe1b4714c2ff88cafc6b6793b", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/88c26372b1afac36d8db601cdf04ad8716f53d88", + "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88", "shasum": "" }, "require": { @@ -203,7 +260,7 @@ "spdx", "validator" ], - "time": "2016-03-25 10:57:10" + "time": "2016-05-04 12:27:30" }, { "name": "justinrainbow/json-schema", @@ -405,6 +462,44 @@ ], "time": "2013-02-24 15:01:54" }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, { "name": "ramsey/array_column", "version": "1.1.3", @@ -639,16 +734,16 @@ }, { "name": "symfony/config", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "5273f4724dc5288fe7a33cb08077ab9852621f2c" + "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/5273f4724dc5288fe7a33cb08077ab9852621f2c", - "reference": "5273f4724dc5288fe7a33cb08077ab9852621f2c", + "url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05", + "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05", "shasum": "" }, "require": { @@ -688,20 +783,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-03-04 07:54:35" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/console", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154" + "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9a5aef5fc0d4eff86853d44202b02be8d5a20154", - "reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154", + "url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", + "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", "shasum": "" }, "require": { @@ -748,20 +843,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-03-17 09:19:04" + "time": "2016-06-06 15:06:25" }, { "name": "symfony/dependency-injection", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f7b4a498e679fa440b16facb934680a1527ed48c" + "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f7b4a498e679fa440b16facb934680a1527ed48c", - "reference": "f7b4a498e679fa440b16facb934680a1527ed48c", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2d05009d890cf1139988ff059b5b2e0eb280ed13", + "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13", "shasum": "" }, "require": { @@ -777,6 +872,7 @@ }, "suggest": { "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", "symfony/yaml": "" }, @@ -810,20 +906,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-03-21 07:27:21" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87" + "reference": "2a6b8713f8bdb582058cfda463527f195b066110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/47d2d8cade9b1c3987573d2943bb9352536cdb87", - "reference": "47d2d8cade9b1c3987573d2943bb9352536cdb87", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110", + "reference": "2a6b8713f8bdb582058cfda463527f195b066110", "shasum": "" }, "require": { @@ -870,20 +966,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-03-07 14:04:32" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/filesystem", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "f08ffdf229252cd2745558cb2112df43903bcae4" + "reference": "dee379131dceed90a429e951546b33edfe7dccbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/f08ffdf229252cd2745558cb2112df43903bcae4", - "reference": "f08ffdf229252cd2745558cb2112df43903bcae4", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb", + "reference": "dee379131dceed90a429e951546b33edfe7dccbb", "shasum": "" }, "require": { @@ -919,20 +1015,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-03-27 10:20:16" + "time": "2016-04-12 18:01:21" }, { "name": "symfony/finder", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1" + "reference": "3ec095fab1800222732ca522a95dce8fa124007b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ca24cf2cd4e3826f571e0067e535758e73807aa1", - "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1", + "url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b", + "reference": "3ec095fab1800222732ca522a95dce8fa124007b", "shasum": "" }, "require": { @@ -968,20 +1064,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-03-10 10:53:53" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "1289d16209491b584839022f29257ad859b8532d" + "reference": "dff51f72b0706335131b00a7f49606168c582594" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", - "reference": "1289d16209491b584839022f29257ad859b8532d", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", "shasum": "" }, "require": { @@ -993,7 +1089,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -1027,20 +1123,20 @@ "portable", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/process", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "fb467471952ef5cf8497c029980e556b47545333" + "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/fb467471952ef5cf8497c029980e556b47545333", - "reference": "fb467471952ef5cf8497c029980e556b47545333", + "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c", + "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c", "shasum": "" }, "require": { @@ -1076,20 +1172,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-03-23 13:11:46" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/translation", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "d60b8e076d22953aabebeebda53bf334438e7aca" + "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/d60b8e076d22953aabebeebda53bf334438e7aca", - "reference": "d60b8e076d22953aabebeebda53bf334438e7aca", + "url": "https://api.github.com/repos/symfony/translation/zipball/8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1", + "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1", "shasum": "" }, "require": { @@ -1140,20 +1236,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-03-25 01:40:30" + "time": "2016-06-06 11:11:27" }, { "name": "symfony/yaml", - "version": "v2.8.4", + "version": "v2.8.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb" + "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb", - "reference": "584e52cb8f788a887553ba82db6caacb1d6260bb", + "url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34", + "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34", "shasum": "" }, "require": { @@ -1189,7 +1285,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-03-04 07:54:35" + "time": "2016-06-06 11:11:27" }, { "name": "wp-cli/php-cli-tools", @@ -1517,21 +1613,24 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.7", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, "type": "library", "autoload": { "classmap": [ @@ -1554,7 +1653,7 @@ "keywords": [ "timer" ], - "time": "2015-06-21 08:01:12" + "time": "2016-05-12 18:03:57" }, { "name": "phpunit/php-token-stream", From d5d2c58953e9935f84a6e7d748a5a8b258ddea35 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 13 Jun 2016 06:16:37 -0700 Subject: [PATCH 4566/5359] Ensure `PSR\Logger` is included --- utils/make-phar.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/make-phar.php b/utils/make-phar.php index 219164bd6..dca8ea61c 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -69,6 +69,7 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/mustache') ->in(WP_CLI_ROOT . '/vendor/rmccue/requests') ->in(WP_CLI_ROOT . '/vendor/composer') + ->in(WP_CLI_ROOT . '/vendor/psr') ->in(WP_CLI_ROOT . '/vendor/seld') ->in(WP_CLI_ROOT . '/vendor/symfony') ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') @@ -77,6 +78,7 @@ function set_file_contents( $phar, $path, $content ) { ->in(WP_CLI_ROOT . '/vendor/justinrainbow/json-schema') ->exclude('test') ->exclude('tests') + ->exclude('Test') ->exclude('Tests') ->exclude('php-cli-tools/examples') ; From 18be63d06613b72614f9be20491e0c68ee4dccbd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 13 Jun 2016 06:16:58 -0700 Subject: [PATCH 4567/5359] Add cacert.pem from its new directory --- utils/make-phar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/make-phar.php b/utils/make-phar.php index dca8ea61c..5370b482a 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -102,8 +102,8 @@ function set_file_contents( $phar, $path, $content ) { add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); +add_file( $phar, WP_CLI_ROOT . '/vendor/composer/ca-bundle/res/cacert.pem' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/LICENSE' ); -add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/cacert.pem' ); add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/composer-schema.json' ); add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); From bd3557eb3c2fb1352bd60599a075c6da79005c1a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 13 Jun 2016 20:38:34 +0545 Subject: [PATCH 4568/5359] Revert default doc change in rewrite list command --- php/commands/rewrite.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index de7a62767..13ffcd4df 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -173,10 +173,7 @@ public function structure( $args, $assoc_args ) { * : Show rewrite rules from a particular source. * * [--fields=<fields>] - * : Limit the output to specific fields. - * --- - * default: match,query,source - * --- + * : Limit the output to specific fields. Defaults to match,query,source. * * [--format=<format>] * : Render output in a particular format. From ddcdb38301b93bdeb58b9118cd11aa280d142ff0 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 14 Jun 2016 06:04:34 +0545 Subject: [PATCH 4569/5359] User: add missing trailing period in command messages --- php/commands/user.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 4db4b5482..b0f93dff4 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -233,7 +233,7 @@ public function delete( $args, $assoc_args ) { $message = "Deleted user $user_id."; } else { $r = wp_delete_user( $user_id, $reassign ); - $message = "Removed user $user_id from " . home_url(); + $message = "Removed user $user_id from " . home_url() . "."; } if ( $r ) { @@ -328,7 +328,7 @@ public function create( $args, $assoc_args ) { } $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); if ( ! $user_id ) { - WP_CLI::error( "Unknown error creating new user" ); + WP_CLI::error( "Unknown error creating new user." ); } $user->ID = $user_id; $user_id = wp_update_user( $user ); @@ -490,7 +490,7 @@ public function generate( $args, $assoc_args ) { * ## EXAMPLES * * $ wp user set-role 12 author - * Success: Added johndoe (12) to http://example.com as author + * Success: Added johndoe (12) to http://example.com as author. * * @subcommand set-role */ @@ -507,7 +507,7 @@ public function set_role( $args, $assoc_args ) { else $user->set_role( $role ); - WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}" ); + WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}." ); } /** @@ -576,7 +576,7 @@ public function remove_role( $args, $assoc_args ) { else $user->remove_all_caps(); - WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() ); + WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() . "." ); } } @@ -772,7 +772,7 @@ public function import_csv( $args, $assoc_args ) { $invalid_role = false; foreach( $roles as $role ) { if ( is_null( get_role( $role ) ) ) { - WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); $invalid_role = true; break; } @@ -785,7 +785,7 @@ public function import_csv( $args, $assoc_args ) { } else if ( 'none' === $new_user['role'] ) { $new_user['role'] = false; } elseif ( is_null( get_role( $new_user['role'] ) ) ) { - WP_CLI::warning( "{$new_user['user_login']} has an invalid role" ); + WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); continue; } @@ -798,7 +798,7 @@ public function import_csv( $args, $assoc_args ) { if ( $existing_user && \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-update' ) ) { - WP_CLI::log( "{$existing_user->user_login} exists and has been skipped" ); + WP_CLI::log( "{$existing_user->user_login} exists and has been skipped." ); continue; } else if ( $existing_user ) { @@ -823,7 +823,7 @@ public function import_csv( $args, $assoc_args ) { } $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_pass'], $new_user['user_email'] ); if ( ! $user_id ) { - WP_CLI::warning( "Unknown error creating new user" ); + WP_CLI::warning( "Unknown error creating new user." ); continue; } $new_user['ID'] = $user_id; @@ -856,9 +856,9 @@ public function import_csv( $args, $assoc_args ) { } if ( !empty( $existing_user ) ) { - WP_CLI::success( $new_user['user_login'] . " updated" ); + WP_CLI::success( $new_user['user_login'] . " updated." ); } else { - WP_CLI::success( $new_user['user_login'] . " created" ); + WP_CLI::success( $new_user['user_login'] . " created." ); } } } From 95ef4e42bed858dc673315a0e992730f19b442be Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 14 Jun 2016 06:11:24 +0545 Subject: [PATCH 4570/5359] Menu: add missing trailing period in command message --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 5381e1ba2..7959447a4 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -261,7 +261,7 @@ public function list_( $args, $assoc_args ) { $items = wp_get_nav_menu_items( $args[0] ); if ( false === $items || is_wp_error( $items ) ) { - WP_CLI::error( "Invalid menu" ); + WP_CLI::error( "Invalid menu." ); } // Correct position inconsistency and From 8d0b195dc3646d98581344482bc59da68dbbca8b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 14 Jun 2016 06:17:31 +0545 Subject: [PATCH 4571/5359] Role: add missing trailing period in command messages --- features/roles.feature | 8 ++++---- php/commands/role.php | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index c4df0c907..54631936d 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -20,27 +20,27 @@ Feature: Manage WordPress roles When I run `wp role reset author` Then STDOUT should be: """ - Success: Reset 0/1 roles + Success: Reset 0/1 roles. """ When I run `wp cap remove author read` And I run `wp role reset author` Then STDOUT should be: """ - Success: Reset 1/1 roles + Success: Reset 1/1 roles. """ When I run `wp role reset author editor` Then STDOUT should be: """ - Success: Reset 0/2 roles + Success: Reset 0/2 roles. """ When I run `wp cap remove author read` And I run `wp role reset author editor` Then STDOUT should be: """ - Success: Reset 1/2 roles + Success: Reset 1/2 roles. """ When I run `wp role reset --all` diff --git a/php/commands/role.php b/php/commands/role.php index cccd636bf..2df328bd4 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -59,7 +59,6 @@ class Role_Command extends WP_CLI_Command { * - yaml * --- * - * * ## AVAILABLE FIELDS * * These fields will be displayed by default for each role: @@ -239,7 +238,7 @@ public function delete( $args ) { * * # Reset role * $ wp role reset administrator author contributor - * Success: Reset 1/3 roles + * Success: Reset 1/3 roles. * * # Reset all default roles * $ wp role reset --all @@ -324,7 +323,7 @@ public function reset( $args, $assoc_args ) { } } - WP_CLI::success( "Reset $num_reset/$num_to_reset roles" ); + WP_CLI::success( "Reset $num_reset/$num_to_reset roles." ); } From 580eba28e07eed4c037673e5ee57b9cd0ae57abf Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 14 Jun 2016 06:27:48 +0545 Subject: [PATCH 4572/5359] Term: add missing trailing period in command messages --- features/term-recount.feature | 6 +++--- php/commands/term.php | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/features/term-recount.feature b/features/term-recount.feature index 03dad922b..59b4ad63e 100644 --- a/features/term-recount.feature +++ b/features/term-recount.feature @@ -15,15 +15,15 @@ Feature: Recount terms on a taxonomy When I try `wp term recount category` Then STDOUT should be: """ - Success: Updated category term count + Success: Updated category term count. """ Scenario: Term recount with a multiple taxonomies When I try `wp term recount category post_tag` Then STDOUT should be: """ - Success: Updated category term count - Success: Updated post_tag term count + Success: Updated category term count. + Success: Updated post_tag term count. """ Scenario: Fixes an invalid term count for a taxonomy diff --git a/php/commands/term.php b/php/commands/term.php index 7eca69d9a..8b784ca42 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -519,16 +519,16 @@ public function url( $args ) { * * # Recount posts assigned to each categories and tags * $ wp term recount category post_tag - * Success: Updated category term count - * Success: Updated post_tag term count + * Success: Updated category term count. + * Success: Updated post_tag term count. * * # Recount all listed taxonomies * $ wp taxonomy list --field=name | xargs wp term recount - * Success: Updated category term count - * Success: Updated post_tag term count - * Success: Updated nav_menu term count - * Success: Updated link_category term count - * Success: Updated post_format term count + * Success: Updated category term count. + * Success: Updated post_tag term count. + * Success: Updated nav_menu term count. + * Success: Updated link_category term count. + * Success: Updated post_format term count. */ public function recount( $args ) { foreach( $args as $taxonomy ) { @@ -542,7 +542,7 @@ public function recount( $args ) { wp_update_term_count( $term_taxonomy_ids, $taxonomy ); - WP_CLI::success( sprintf( "Updated %s term count", $taxonomy ) ); + WP_CLI::success( sprintf( "Updated %s term count.", $taxonomy ) ); } } From b9b5856667165d8eeba71074691c7b51eb258aaf Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 14 Jun 2016 06:43:15 +0545 Subject: [PATCH 4573/5359] Search-replace: add missing trailing period in command messages --- php/commands/search-replace.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 89bd09daa..a67790ded 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -305,7 +305,7 @@ private function php_export_table( $table, $old, $new ) { if ( $this->verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d columns and %d total rows affected using PHP (in %ss)', $total_cols, $total_rows, $time ) ); + WP_CLI::log( sprintf( '%d columns and %d total rows affected using PHP (in %ss).', $total_cols, $total_rows, $time ) ); } return array( $table_report, $total_rows ); @@ -322,7 +322,7 @@ private function sql_handle_col( $col, $table, $old, $new ) { if ( $this->verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected using SQL (in %ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected using SQL (in %ss).', $count, $time ) ); } return $count; } @@ -371,7 +371,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { if ( $this->verbose ) { $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected using PHP (in %ss)', $count, $time ) ); + WP_CLI::log( sprintf( '%d rows affected using PHP (in %ss).', $count, $time ) ); } return $count; From 61c36b9dc334d2feb968ee630acb9cd96a79bb87 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 14 Jun 2016 08:12:49 -0700 Subject: [PATCH 4574/5359] Ignore the current alias when handling `--ssh` The current alias isn't meant to be passed through to the remote server. --- php/WP_CLI/Runner.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index de6f29c02..d217a1940 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -345,6 +345,11 @@ private function run_ssh_command( $ssh ) { $wp_binary = 'wp'; $wp_args = array_slice( $GLOBALS['argv'], 1 ); $wp_path = $path ? sprintf( '--path=%s', str_replace( '~', '$HOME', $path ) ) : ''; + + if ( $this->alias && ! empty( $wp_args[0] ) && $this->alias === $wp_args[0] ) { + array_shift( $wp_args ); + } + foreach( $wp_args as $k => $v ) { if ( preg_match( '#--ssh=#', $v ) ) { unset( $wp_args[ $k ] ); From a2474cd0202ab46bb70eed988fbfb4ca8231d206 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 14 Jun 2016 08:28:41 -0700 Subject: [PATCH 4575/5359] Support for defining port with `--ssh` Example: ``` 192.168.50.10:2222:/srv/www/wordpress-develop.dev/src ``` --- php/WP_CLI/Runner.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index de6f29c02..6f98d47e0 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -324,11 +324,17 @@ private function _run_command() { */ private function run_ssh_command( $ssh ) { - $host = $ssh; - $path = ''; - if ( false !== ( $key = stripos( $host, ':' ) ) ) { - $path = substr( $host, $key + 1 ); - $host = substr( $host, 0, $key ); + $bits = explode( ':', $ssh ); + $host = $bits[0]; + $path = null; + $port = 22; + // host:path + if ( 2 === count( $bits ) ) { + $path = $bits[1]; + // host:port:path + } else if ( 3 === count( $bits ) ) { + $port = $bits[1]; + $path = $bits[2]; } WP_CLI::do_hook( 'before_ssh' ); @@ -352,7 +358,8 @@ private function run_ssh_command( $ssh ) { } $unescaped_command = sprintf( - 'ssh -q %s %s %s', + 'ssh -q -p %d %s %s %s', + $port, $host, $is_tty ? '-t' : '-T', $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) @@ -361,7 +368,8 @@ private function run_ssh_command( $ssh ) { WP_CLI::debug( 'Running SSH command: ' . $unescaped_command, 'bootstrap' ); $escaped_command = sprintf( - 'ssh -q %s %s %s', + 'ssh -q -p %d %s %s %s', + $port, escapeshellarg( $host ), $is_tty ? '-t' : '-T', escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) From 7d4bb965896c945587315be7d335fafad05456ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 14 Jun 2016 09:19:31 -0700 Subject: [PATCH 4576/5359] Only supply port when its provided This permits `ssh` to fall back to a value set in `~/.ssh/config` --- php/WP_CLI/Runner.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 6f98d47e0..4e88addc6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -327,7 +327,7 @@ private function run_ssh_command( $ssh ) { $bits = explode( ':', $ssh ); $host = $bits[0]; $path = null; - $port = 22; + $port = null; // host:path if ( 2 === count( $bits ) ) { $path = $bits[1]; @@ -358,8 +358,8 @@ private function run_ssh_command( $ssh ) { } $unescaped_command = sprintf( - 'ssh -q -p %d %s %s %s', - $port, + 'ssh -q %s%s %s %s', + $port ? '-p ' . (int) $port . ' ' : '', $host, $is_tty ? '-t' : '-T', $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) @@ -368,8 +368,8 @@ private function run_ssh_command( $ssh ) { WP_CLI::debug( 'Running SSH command: ' . $unescaped_command, 'bootstrap' ); $escaped_command = sprintf( - 'ssh -q -p %d %s %s %s', - $port, + 'ssh -q %s%s %s %s', + $port ? '-p ' . (int) $port . ' ' : '', escapeshellarg( $host ), $is_tty ? '-t' : '-T', escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) From 9c1aaa53374aedf3630475c5bd33fc6a11ce86ef Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 14 Jun 2016 09:51:12 -0700 Subject: [PATCH 4577/5359] Provide more verbosity when `--ssh` fails ``` $ wp --ssh=foo option get home Error: Cannot connect over SSH using provided configuration. ``` Unfortunately, it doesn't seem possible to capture the SSH error itself. `-o LogLevel=ERROR` still includes the "Connection closed" message. --- php/WP_CLI/Runner.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index de6f29c02..485c3eaf9 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -368,7 +368,9 @@ private function run_ssh_command( $ssh ) { ); passthru( $escaped_command, $exit_code ); - if ( 0 !== $exit_code ) { + if ( 255 === $exit_code ) { + WP_CLI::error( 'Cannot connect over SSH using provided configuration.', 255 ); + } else { exit( $exit_code ); } } From 072f4948d535d276f7e0d9700ae9092435ee9b32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 11:08:48 -0700 Subject: [PATCH 4578/5359] Use `WP_CLI::warning()` when a theme is already active This makes `wp theme activate` behave more consistently with `wp plugin activate` --- features/theme.feature | 6 +++--- php/commands/theme.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 5e6bf2a69..8c741b2d2 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -108,10 +108,10 @@ Feature: Manage WordPress themes Success: Switched to 'P2' theme. """ - When I run `wp theme activate p2` - Then STDOUT should be: + When I try `wp theme activate p2` + Then STDERR should be: """ - Success: The 'P2' theme is already active. + Warning: The 'P2' theme is already active. """ Scenario: Install a theme when the theme directory doesn't yet exist diff --git a/php/commands/theme.php b/php/commands/theme.php index 54181962c..36a144e07 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -196,7 +196,7 @@ public function activate( $args = array() ) { $name = $theme->get('Name'); if ( 'active' === $this->get_status( $theme ) ) { - WP_CLI::success( "The '$name' theme is already active." ); + WP_CLI::warning( "The '$name' theme is already active." ); return; } From e8d10b276f100925ebe2f75199639f100889265a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 11:31:31 -0700 Subject: [PATCH 4579/5359] Use a more URL-like format for `--ssh` --- php/WP_CLI/Runner.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0e08ba196..1a8c4287f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -324,22 +324,16 @@ private function _run_command() { */ private function run_ssh_command( $ssh ) { - $bits = explode( ':', $ssh ); - $host = $bits[0]; - $path = null; - $port = null; - // host:path - if ( 2 === count( $bits ) ) { - $path = $bits[1]; - // host:port:path - } else if ( 3 === count( $bits ) ) { - $port = $bits[1]; - $path = $bits[2]; - } - WP_CLI::do_hook( 'before_ssh' ); + // host:port/path/to/wordpress + preg_match( '#([^:/~]+)(:([\d]+))?((/|~)(.+))#', $ssh, $matches ); + $host = $matches[1] ? : null; + $port = $matches[3] ? : null; + $path = $matches[4] ? : null; + WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); + WP_CLI::debug( 'SSH port: ' . $port, 'bootstrap' ); WP_CLI::debug( 'SSH path: ' . $path, 'bootstrap' ); $is_tty = function_exists( 'posix_isatty' ) && posix_isatty( STDOUT ); From 24885857c3a1f1b251757c792af1fd5fe688d53b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 11:52:56 -0700 Subject: [PATCH 4580/5359] Add a dependency badge See https://github.com/wp-cli/wp-cli/issues/2996#issuecomment-226268372 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ddda1de27..914f640ad 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ WP-CLI [WP-CLI](http://wp-cli.org/) is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser. -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) + Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) From 1f42dcf312a45f3dd492ac88bcf6a4f16f4d26d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 12:04:55 -0700 Subject: [PATCH 4581/5359] Failing test case for maintenance mode --- features/framework.feature | 14 ++++++++++++++ php/wp-settings-cli.php | 3 +++ 2 files changed, 17 insertions(+) diff --git a/features/framework.feature b/features/framework.feature index d39e90c5f..93f12ad92 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -164,3 +164,17 @@ Feature: Load WP-CLI """ Warning: Some code is trying to do a URL redirect. """ + + Scenario: It should be possible to work on a site in maintenance mode + Given a WP install + And a .maintenance file: + """ + <?php + $upgrading = time(); + """ + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 76d9f7567..4cb3371cc 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -53,6 +53,9 @@ // Standardize $_SERVER variables across setups. wp_fix_server_vars(); +// Check if we're in maintenance mode. +wp_maintenance(); + // Start loading timer. timer_start(); From d210a1faa14990e954411086c93dc5576a90ef4c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 12:10:33 -0700 Subject: [PATCH 4582/5359] Run bypass_maintenance_mode filter early for compat with < WP 4.6 --- php/WP_CLI/Runner.php | 5 +++++ php/wp-settings-cli.php | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0e08ba196..d24da27f5 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -991,6 +991,11 @@ private function setup_bootstrap_hooks() { // Always permit operations against sites, regardless of status $this->add_wp_hook( 'ms_site_check', '__return_true' ); + // Always permit operations against WordPress, regardless of maintenance mode + $this->add_wp_hook( 'bypass_maintenance_mode', function() { + return true; + }); + // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 4cb3371cc..48f325f1e 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -54,7 +54,10 @@ wp_fix_server_vars(); // Check if we're in maintenance mode. -wp_maintenance(); +// WP-CLI: run bypass_maintenance_mode filter early for compat with < WP 4.6 +if ( ! apply_filters( 'bypass_maintenance_mode', false ) ) { + wp_maintenance(); +} // Start loading timer. timer_start(); From 13208df7ede1c25a6335fb9ed6697a99426a0bac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 14:41:30 -0700 Subject: [PATCH 4583/5359] Restore `advanced-cache.php` to `wp-settings-cli.php` Even though this will never be called, this ensures `wp-settings-cli.php` is in closer parity to `wp-settings.php` --- php/WP_CLI/Runner.php | 5 +++++ php/wp-settings-cli.php | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e8c03510f..4fc5a89e1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -990,6 +990,11 @@ private function setup_bootstrap_hooks() { return true; }); + // Never load advanced-cache.php drop-in when WP-CLI is operating + $this->add_wp_hook( 'bypass_advanced_cache', function() { + return true; + }); + // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 48f325f1e..c7f8f7928 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -65,6 +65,21 @@ // Check if we're in WP_DEBUG mode. Utils\wp_debug_mode(); +/** + * Bypass the loading of advanced-cache.php + * + * This filter should *NOT* be used by plugins. It is designed for non-web + * runtimes. If true is returned, advance-cache.php will never be loaded. + * + * @since 4.6.0 + * + * @param bool True to bypass advanced-cache.php + */ +if ( WP_CACHE && ! apply_filters( 'bypass_advanced_cache', false ) ) { + // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. + WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); +} + // Define WP_LANG_DIR if not set. wp_set_lang_dir(); From c8ee4c055fe3170dd1813f940d16206686c916af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 15:23:23 -0700 Subject: [PATCH 4584/5359] Move the APC cache check to `muplugins_loaded` Doing so mitigates our need to include it in a forked wp-settings-cli.php. There is minimal risk in performing the AYS check later in the bootstrap process. --- php/WP_CLI/Runner.php | 8 ++++++++ php/wp-settings-cli.php | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e8c03510f..68690a90d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -997,6 +997,14 @@ private function setup_bootstrap_hooks() { }, 10, 3 ); } + // The APC cache is not available on the command-line, so bail, to prevent cache poisoning + $this->add_wp_hook( 'muplugins_loaded', function() { + if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { + WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' ); + WP_CLI::confirm( 'Given the consequences, do you wish to continue?' ); + } + }, 0 ); + // Handle --user parameter if ( ! defined( 'WP_INSTALLING' ) ) { $config = $this->config; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 48f325f1e..8a787b35d 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -92,12 +92,6 @@ // Start the WordPress object cache, or an external object cache if the drop-in is present. wp_start_object_cache(); -// WP-CLI: the APC cache is not available on the command-line, so bail, to prevent cache poisoning -if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { - WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' ); - WP_CLI::confirm( 'Given the consequences, do you wish to continue?' ); -} - // Attach the default filters. require( ABSPATH . WPINC . '/default-filters.php' ); From dcea31fed83b53efbd65fa9e8c4ba9fe1327bb34 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 15:46:36 -0700 Subject: [PATCH 4585/5359] Abuse the `nocache_headers` filter to run our `Utils\wp_not_installed()` If `wp_not_installed()` identifies that WordPress isn't installed, it will call `nocache_headers()` before trying to redirect. Hijacking this particular filter lets WP-CLI exit with its own message before the redirect is called, and avoid having to maintain a forked `wp-settings-cli.php` --- features/core-config.feature | 9 +++++++++ php/WP_CLI/Runner.php | 5 +++++ php/wp-settings-cli.php | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/features/core-config.feature b/features/core-config.feature index d940433e5..7b445bf93 100644 --- a/features/core-config.feature +++ b/features/core-config.feature @@ -41,6 +41,15 @@ Feature: Manage wp-config Then the return code should be 1 And STDERR should not be empty + When I run `wp db create` + Then STDOUT should not be empty + + When I try `wp option get option home` + Then STDERR should contain: + """ + Error: The site you have requested is not installed + """ + Scenario: Configure with existing salts Given an empty directory And WP files diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index e8c03510f..5a522e4b7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -965,6 +965,11 @@ private function setup_bootstrap_hooks() { // Prevent code from performing a redirect $this->add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); + $this->add_wp_hook( 'nocache_headers', function( $headers ){ + Utils\wp_not_installed(); + return $headers; + }); + // Get rid of warnings when converting single site to multisite if ( defined( 'WP_INSTALLING' ) && $this->is_multisite() ) { $values = array( diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 48f325f1e..184341d61 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -120,7 +120,7 @@ require_once( ABSPATH . WPINC . '/l10n.php' ); // Run the installer if WordPress is not installed. -Utils\wp_not_installed(); +wp_not_installed(); // Load most of WordPress. require( ABSPATH . WPINC . '/class-wp-walker.php' ); From fe26b2f0a6955101c14f26f0cd8a360b4e1a8314 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 15 Jun 2016 16:34:01 -0700 Subject: [PATCH 4586/5359] Restore `wp_debug_mode()` call in `wp-settings-cli.php` We can use the new `bypass_debug_mode` filter to hook in our existing `WP_CLI\Utils\wp_debug_mode()` call, and make sure it just runs once --- php/WP_CLI/Runner.php | 13 +++++++++++++ php/wp-settings-cli.php | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4fc5a89e1..b36db1e5b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -990,6 +990,19 @@ private function setup_bootstrap_hooks() { return true; }); + // Use our own debug mode handling instead of WP core + $this->add_wp_hook( 'bypass_debug_mode', function( $ret ) { + static $did_once; + + // Sometimes called a second time in >= WP 4.6, prevent loop + if ( ! empty( $did_once ) ) { + return $ret; + } + Utils\wp_debug_mode(); + $did_once = true; + return true; + }); + // Never load advanced-cache.php drop-in when WP-CLI is operating $this->add_wp_hook( 'bypass_advanced_cache', function() { return true; diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index c7f8f7928..4466d9b81 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -62,8 +62,21 @@ // Start loading timer. timer_start(); -// Check if we're in WP_DEBUG mode. -Utils\wp_debug_mode(); +/** + * Bypass the debug mode check + * + * This filter should *NOT* be used by plugins. It is designed for non-web + * runtimes. Returning true causes the WP_DEBUG and related constants to + * not be checked and the default php values for errors will be used unless + * you take care to update them yourself. + * + * @since 4.6.0 + * + * @param bool True to bypass debug mode + */ +if ( ! apply_filters( 'bypass_debug_mode', false ) ){ + wp_debug_mode(); +} /** * Bypass the loading of advanced-cache.php From 4fcc52e9628d96c75e5342592c3622ae8d38a9f0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 16 Jun 2016 03:58:24 -0700 Subject: [PATCH 4587/5359] Perform dead db check earlier, by loading wpdb ourselves In doing so, we're causing wpdb to be loaded slightly earlier in the bootstrap process. --- php/WP_CLI/Runner.php | 8 ++++++++ php/utils-wp.php | 2 +- php/wp-settings-cli.php | 5 ----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 1a4d199ab..5682290d9 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1000,6 +1000,14 @@ private function setup_bootstrap_hooks() { } Utils\wp_debug_mode(); $did_once = true; + + // Check to see of wpdb is errored, instead of waiting for dead_db() + require_wp_db(); + global $wpdb; + if ( ! empty( $wpdb->error ) ) { + Utils\wp_die_handler( $wpdb->error ); + } + return true; }); diff --git a/php/utils-wp.php b/php/utils-wp.php index be7a4e1a7..e2c3a9738 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -32,7 +32,7 @@ function replace_wp_die_handler() { } function wp_die_handler( $message ) { - if ( is_wp_error( $message ) ) { + if ( $message instanceof \WP_Error ) { $message = $message->get_error_message(); } diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 700e756e0..d3308ece5 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -106,11 +106,6 @@ // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); -// WP-CLI: Handle db error ourselves, instead of waiting for dead_db() -global $wpdb; -if ( !empty( $wpdb->error ) ) - wp_die( $wpdb->error ); - // Set the database table prefix and the format specifiers for database table columns. // @codingStandardsIgnoreStart $GLOBALS['table_prefix'] = $table_prefix; From fc1a5cbfa98c13631ff4058c2f2a7ebdebbd2b46 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 16 Jun 2016 04:07:29 -0700 Subject: [PATCH 4588/5359] Ensure the nocache_headers filter runs pre WP 4.0 The call to `nocache_headers()` in `wp_not_installed()` was introduced in WP 4.0 --- php/wp-settings-cli.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 184341d61..9f261f4c4 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -119,6 +119,9 @@ // Load the L10n library. require_once( ABSPATH . WPINC . '/l10n.php' ); +// WP-CLI: Permit Utils\wp_not_installed() to run on < WP 4.0 +apply_filters( 'nocache_headers', array() ); + // Run the installer if WordPress is not installed. wp_not_installed(); From 001199054f258e9189d4d96f6b873f3abb6929bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 16 Jun 2016 08:08:12 -0700 Subject: [PATCH 4589/5359] Support only a host being provided to `--ssh=<ssh>` e.g. `wp --ssh=v` or `wp --ssh=prod` --- php/WP_CLI/Runner.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 83b28632c..a374a06a1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -326,11 +326,11 @@ private function run_ssh_command( $ssh ) { WP_CLI::do_hook( 'before_ssh' ); - // host:port/path/to/wordpress - preg_match( '#([^:/~]+)(:([\d]+))?((/|~)(.+))#', $ssh, $matches ); - $host = $matches[1] ? : null; - $port = $matches[3] ? : null; - $path = $matches[4] ? : null; + // host OR host/path/to/wordpress OR host:port/path/to/wordpress + preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $ssh, $matches ); + $host = isset( $matches[1] ) ? $matches[1] : null; + $port = isset( $matches[3] ) ? $matches[3] : null; + $path = isset( $matches[4] ) ? $matches[4] : null; WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); WP_CLI::debug( 'SSH port: ' . $port, 'bootstrap' ); From 5d44381c7ed73d44b744981982b3ccb4a0da18d6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 16 Jun 2016 15:59:06 -0700 Subject: [PATCH 4590/5359] Restore `defined( 'WP_INSTALLING' )` check in legacy wp-settings-cli.php This will prevent error notices when using WP-CLI against <WP 4.6 --- php/wp-settings-cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 6fc2a5e6c..f5c35b025 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -400,7 +400,8 @@ do_action( 'init' ); // Check site status -if ( is_multisite() ) { +# if ( is_multisite() ) { // WP-CLI +if ( is_multisite() && !defined('WP_INSTALLING') ) { if ( true !== ( $file = ms_site_check() ) ) { require( $file ); die(); From b376153b421852ce2410f44a4868a3b1b5e2a697 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 16 Jun 2016 16:03:15 -0700 Subject: [PATCH 4591/5359] Restore our custom dead db check; `nonce_headers` isn't called until WP4.0 We'll need this check in place for compatibility purposes --- php/wp-settings-cli.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index d3308ece5..700e756e0 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -106,6 +106,11 @@ // Include the wpdb class and, if present, a db.php database drop-in. require_wp_db(); +// WP-CLI: Handle db error ourselves, instead of waiting for dead_db() +global $wpdb; +if ( !empty( $wpdb->error ) ) + wp_die( $wpdb->error ); + // Set the database table prefix and the format specifiers for database table columns. // @codingStandardsIgnoreStart $GLOBALS['table_prefix'] = $table_prefix; From 196e69ebb51b6ede4bc7b8ff6635387a3d3b7e75 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 17 Jun 2016 05:01:50 -0700 Subject: [PATCH 4592/5359] Use `wp-settings.php` instead of `wp-settings-cli.php` for >=WP4.6 Maintaining a fork isn't a ton of fun. --- php/WP_CLI/Runner.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index bbcf0ab24..ec80b2594 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -575,6 +575,7 @@ private function check_wp_version() { "Pass --path=`path/to/wordpress` or run `wp core download`." ); } + global $wp_version; include ABSPATH . 'wp-includes/version.php'; $minimum_version = '3.7'; @@ -885,7 +886,11 @@ public function load_wordpress() { $this->setup_bootstrap_hooks(); // Load Core, mu-plugins, plugins, themes etc. - require WP_CLI_ROOT . '/php/wp-settings-cli.php'; + if ( Utils\wp_version_compare( '4.6-alpha-37575', '>=' ) ) { + require ABSPATH . 'wp-settings.php'; + } else { + require WP_CLI_ROOT . '/php/wp-settings-cli.php'; + } // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 @ini_set( 'memory_limit', -1 ); From d163d7af3914cdeb3f557614dfa3b0db9b7c826e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 17 Jun 2016 21:19:19 +0545 Subject: [PATCH 4593/5359] Add test for porcelain in db export --- features/db.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/db.feature b/features/db.feature index 046fd29d1..f355252ba 100644 --- a/features/db.feature +++ b/features/db.feature @@ -61,6 +61,18 @@ Feature: Perform database operations Success: Exported """ + When I run `wp db export /tmp/wp-cli-behat.sql --porcelain` + Then STDOUT should contain: + """ + /tmp/wp-cli-behat.sql + """ + + When I try `wp db export - --porcelain` + Then STDERR should contain: + """ + Porcelain is not allowed when output mode is STDOUT. + """ + When I run `wp db reset --yes` Then STDOUT should contain: """ From f0373fad06fb1d5acd4aa4c7b230b4b024b95fae Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 17 Jun 2016 21:19:37 +0545 Subject: [PATCH 4594/5359] Add porcelain parameter in db export --- php/commands/db.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index 265b74711..5acab0bc3 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -222,6 +222,9 @@ public function query( $args ) { * [--tables=<tables>] * : The comma separated list of specific tables to export. Excluding this parameter will export all tables in the database. * + * [--porcelain] + * : Output filename for the exported database. + * * ## EXAMPLES * * # Export database with drop query included @@ -245,6 +248,12 @@ public function query( $args ) { function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); $stdout = ( '-' === $result_file ); + $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); + + // Bail if both porcelain and STDOUT are set. + if ( $stdout && $porcelain ) { + WP_CLI::error( 'Porcelain is not allowed when output mode is STDOUT.' ); + } if ( ! $stdout ) { $assoc_args['result-file'] = $result_file; @@ -265,9 +274,17 @@ function export( $args, $assoc_args ) { $escaped_command = call_user_func_array( '\WP_CLI\Utils\esc_cmd', array_merge( array( $command ), $command_esc_args ) ); + // Remove parameters not needed for SQL run. + if ( isset( $assoc_args['porcelain'] ) ) { + unset( $assoc_args['porcelain'] ); + } + self::run( $escaped_command, $assoc_args ); - if ( ! $stdout ) { + if ( $porcelain ) { + WP_CLI::line( $result_file ); + } + else if ( ! $stdout ) { WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); } } From a2f0b9f6b3897352d7206d899b69957305bb7bdb Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 17 Jun 2016 22:06:31 +0545 Subject: [PATCH 4595/5359] Introduce field param in option list --- php/commands/option.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index a680fefd6..8f3c6d757 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -128,6 +128,9 @@ public function add( $args, $assoc_args ) { * [--autoload=<value>] * : Match only autoload options when value is on, and only not-autoload option when off. * + * [--field=<field>] + * : Prints the value of a single field. + * * [--fields=<fields>] * : Limit the output to specific object fields. * From 23f7c7c37f666ddccc268cee50f65670d7b29d29 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 17 Jun 2016 09:59:52 -0700 Subject: [PATCH 4596/5359] Rename filters to match what's in core Oops --- php/WP_CLI/Runner.php | 19 ++++++------------- php/utils-wp.php | 20 +++++++++++++++++++- php/wp-settings-cli.php | 6 +++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ec80b2594..8000d3d40 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -996,20 +996,13 @@ private function setup_bootstrap_hooks() { $this->add_wp_hook( 'ms_site_check', '__return_true' ); // Always permit operations against WordPress, regardless of maintenance mode - $this->add_wp_hook( 'bypass_maintenance_mode', function() { - return true; + $this->add_wp_hook( 'enable_maintenance_mode', function() { + return false; }); // Use our own debug mode handling instead of WP core - $this->add_wp_hook( 'bypass_debug_mode', function( $ret ) { - static $did_once; - - // Sometimes called a second time in >= WP 4.6, prevent loop - if ( ! empty( $did_once ) ) { - return $ret; - } + $this->add_wp_hook( 'enable_wp_debug_mode_checks', function( $ret ) { Utils\wp_debug_mode(); - $did_once = true; // Check to see of wpdb is errored, instead of waiting for dead_db() require_wp_db(); @@ -1018,12 +1011,12 @@ private function setup_bootstrap_hooks() { Utils\wp_die_handler( $wpdb->error ); } - return true; + return false; }); // Never load advanced-cache.php drop-in when WP-CLI is operating - $this->add_wp_hook( 'bypass_advanced_cache', function() { - return true; + $this->add_wp_hook( 'enable_loading_advanced_cache_dropin', function() { + return false; }); // In a multisite install, die if unable to find site given in --url parameter diff --git a/php/utils-wp.php b/php/utils-wp.php index e2c3a9738..dd08dfb84 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -19,7 +19,25 @@ function wp_debug_mode() { error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT ); } else { - \wp_debug_mode(); + if ( WP_DEBUG ) { + error_reporting( E_ALL ); + + if ( WP_DEBUG_DISPLAY ) + ini_set( 'display_errors', 1 ); + elseif ( null !== WP_DEBUG_DISPLAY ) + ini_set( 'display_errors', 0 ); + + if ( WP_DEBUG_LOG ) { + ini_set( 'log_errors', 1 ); + ini_set( 'error_log', WP_CONTENT_DIR . '/debug.log' ); + } + } else { + error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR ); + } + + if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) { + @ini_set( 'display_errors', 0 ); + } } // XDebug already sends errors to STDERR diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index f5c35b025..856e01b67 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -55,7 +55,7 @@ // Check if we're in maintenance mode. // WP-CLI: run bypass_maintenance_mode filter early for compat with < WP 4.6 -if ( ! apply_filters( 'bypass_maintenance_mode', false ) ) { +if ( apply_filters( 'enable_maintenance_mode', true ) ) { wp_maintenance(); } @@ -74,7 +74,7 @@ * * @param bool True to bypass debug mode */ -if ( ! apply_filters( 'bypass_debug_mode', false ) ){ +if ( apply_filters( 'enable_wp_debug_mode_checks', true ) ){ wp_debug_mode(); } @@ -88,7 +88,7 @@ * * @param bool True to bypass advanced-cache.php */ -if ( WP_CACHE && ! apply_filters( 'bypass_advanced_cache', false ) ) { +if ( WP_CACHE && apply_filters( 'enable_loading_advanced_cache_dropin', true ) ) { // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); } From fe8d1407dda661ed821ead57cbbd47fba56e5915 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 17 Jun 2016 10:02:53 -0700 Subject: [PATCH 4597/5359] Update PHPDoc correspondingly --- php/wp-settings-cli.php | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 856e01b67..1554221a8 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -54,7 +54,20 @@ wp_fix_server_vars(); // Check if we're in maintenance mode. -// WP-CLI: run bypass_maintenance_mode filter early for compat with < WP 4.6 +// WP-CLI: run enable_maintenance_mode filter early for compat with < WP 4.6 +/** + * Filters whether to enable maintenance mode. + * + * This filter runs before it can be used by plugins. It is designed for + * non-web runtimes. If this filter returns true, maintenance mode will be + * active and the request will end. If false, the request will be allowed to + * continue processing even if maintenance mode should be active. + * + * @since 4.6.0 + * + * @param bool $enable_checks Whether to enable maintenance mode. Default true. + * @param int $upgrading The timestamp set in the .maintenance file. + */ if ( apply_filters( 'enable_maintenance_mode', true ) ) { wp_maintenance(); } @@ -62,31 +75,33 @@ // Start loading timer. timer_start(); +// WP-CLI: run enable_wp_debug_mode_checks filter early for compat with < WP 4.6 /** - * Bypass the debug mode check + * Filters whether to allow the debug mode check to occur. * - * This filter should *NOT* be used by plugins. It is designed for non-web - * runtimes. Returning true causes the WP_DEBUG and related constants to - * not be checked and the default php values for errors will be used unless - * you take care to update them yourself. + * This filter runs before it can be used by plugins. It is designed for + * non-web run-times. Returning false causes the `WP_DEBUG` and related + * constants to not be checked and the default php values for errors + * will be used unless you take care to update them yourself. * * @since 4.6.0 * - * @param bool True to bypass debug mode + * @param bool $enable_debug_mode Whether to enable debug mode checks to occur. Default true. */ if ( apply_filters( 'enable_wp_debug_mode_checks', true ) ){ wp_debug_mode(); } /** - * Bypass the loading of advanced-cache.php + * Filters whether to enable loading of the advanced-cache.php drop-in. * - * This filter should *NOT* be used by plugins. It is designed for non-web - * runtimes. If true is returned, advance-cache.php will never be loaded. + * This filter runs before it can be used by plugins. It is designed for non-web + * run-times. If false is returned, advance-cache.php will never be loaded. * * @since 4.6.0 * - * @param bool True to bypass advanced-cache.php + * @param bool $enable_advanced_cache Whether to enable loading advanced-cache.php (if present). + * Default true. */ if ( WP_CACHE && apply_filters( 'enable_loading_advanced_cache_dropin', true ) ) { // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. From dc38f0834d6cd47f3c424e5ae2d357da81567f54 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 17 Jun 2016 10:20:22 -0700 Subject: [PATCH 4598/5359] Explicitly globalize `$wpdb` before wp-settings.php is called Because `wp-settings.php` doesn't globalize `$wpdb` itself, calling `wp-settings.php` inside of a class method means that `wp-includes/ms-settings.php` (which uses `$wpdb` but doesn't globalize it) will break unexpectedly. This problem was obscured originally because WP-CLI globalizes $wpdb, see b376153b421852ce2410f44a4868a3b1b5e2a697 --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8000d3d40..c871ed4eb 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -843,7 +843,7 @@ public function start() { public function load_wordpress() { static $wp_cli_is_loaded; // Globals not explicitly globalized in WordPress - global $site_id, $public, $current_site, $current_blog, $path, $shortcode_tags; + global $site_id, $wpdb, $public, $current_site, $current_blog, $path, $shortcode_tags; if ( ! empty( $wp_cli_is_loaded ) ) { return; From 684a4d877245fd43a86808a35de67f9358750ee4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 18 Jun 2016 06:03:17 +0545 Subject: [PATCH 4599/5359] Improve test for porcelain in db export command --- features/db.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/db.feature b/features/db.feature index f355252ba..338cdc935 100644 --- a/features/db.feature +++ b/features/db.feature @@ -61,16 +61,16 @@ Feature: Perform database operations Success: Exported """ - When I run `wp db export /tmp/wp-cli-behat.sql --porcelain` - Then STDOUT should contain: + When I run `wp db export wp-cli-behat.sql --porcelain` + Then STDOUT should be: """ - /tmp/wp-cli-behat.sql + wp-cli-behat.sql """ When I try `wp db export - --porcelain` - Then STDERR should contain: + Then STDERR should be: """ - Porcelain is not allowed when output mode is STDOUT. + Error: Porcelain is not allowed when output mode is STDOUT. """ When I run `wp db reset --yes` From 9cbbb8d6a3e61264dcfae6d5d7f46c6139b9827c Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 18 Jun 2016 06:26:48 +0545 Subject: [PATCH 4600/5359] Add example to use output of option list in option delete --- php/commands/option.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index 8f3c6d757..2da0138e3 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -182,6 +182,12 @@ public function add( $args, $assoc_args ) { * | i2f_version | 0.1.0 | * +-------------+--------------+ * + * # Delete all options begining with "theme_mods_" + * $ wp option list --search="theme_mods_*" --field=option_name | xargs -0 -d '\n' -I % wp option delete % + * Success: Deleted 'theme_mods_twentysixteen' option. + * Success: Deleted 'theme_mods_twentfifteen' option. + * Success: Deleted 'theme_mods_twentyfourteen' option. + * * @subcommand list */ public function list_( $args, $assoc_args ) { From 5b639f96ce802d4a75ece8f99f5677e891fa261e Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 18 Jun 2016 07:02:12 +0545 Subject: [PATCH 4601/5359] Media: add missing trailing period in command messages --- php/commands/media.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 25220bf08..a5f8aefd3 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -269,7 +269,7 @@ private function _make_copy( $path ) { $filename = $dir . wp_unique_filename( $dir, $filename ); if ( !copy( $path, $filename ) ) - WP_CLI::error( "Could not create temporary file for $path" ); + WP_CLI::error( "Could not create temporary file for $path." ); return $filename; } @@ -281,7 +281,7 @@ private function _process_regeneration( $id, $skip_delete = false, $only_missing $att_desc = sprintf( '"%1$s" (ID %2$d).', get_the_title( $id ), $id ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "Can't find $att_desc" ); + WP_CLI::warning( "Can't find $att_desc." ); return false; } @@ -304,10 +304,10 @@ private function _process_regeneration( $id, $skip_delete = false, $only_missing wp_update_attachment_metadata( $id, $metadata ); - WP_CLI::log( "Regenerated thumbnails for $att_desc" ); + WP_CLI::log( "Regenerated thumbnails for $att_desc." ); return true; } else { - WP_CLI::log( "No thumbnail regeneration needed for $att_desc" ); + WP_CLI::log( "No thumbnail regeneration needed for $att_desc." ); return true; } } From 0463b33a4b5b42cf76fea1c3a61dd2351a571871 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 18 Jun 2016 17:48:29 +0545 Subject: [PATCH 4602/5359] Export: add missing trailing period in command messages --- features/export.feature | 6 +++--- php/commands/export.php | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/features/export.feature b/features/export.feature index 461ee86b8..f9376c598 100644 --- a/features/export.feature +++ b/features/export.feature @@ -6,7 +6,7 @@ Feature: Export content. When I run `wp export` Then STDOUT should contain: """ - All done with export + All done with export. """ Scenario: Export argument validator @@ -27,13 +27,13 @@ Feature: Export content. When I try `wp export --start_date=invalid-date` Then STDERR should contain: """ - Warning: The start_date invalid-date is invalid + Warning: The start_date invalid-date is invalid. """ When I try `wp export --end_date=invalid-date` Then STDERR should contain: """ - Warning: The end_date invalid-date is invalid + Warning: The end_date invalid-date is invalid. """ Scenario: Export with post_type and post_status argument diff --git a/php/commands/export.php b/php/commands/export.php index 62720cce7..93a471271 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -171,7 +171,7 @@ private function check_dir( $path ) { if ( empty( $path ) ) { $path = getcwd(); } elseif ( !is_dir( $path ) ) { - WP_CLI::error( sprintf( "The directory %s does not exist", $path ) ); + WP_CLI::error( sprintf( "The directory %s does not exist.", $path ) ); return false; } @@ -186,7 +186,7 @@ private function check_start_date( $date ) { $time = strtotime( $date ); if ( !empty( $date ) && !$time ) { - WP_CLI::warning( sprintf( "The start_date %s is invalid", $date ) ); + WP_CLI::warning( sprintf( "The start_date %s is invalid.", $date ) ); return false; } $this->export_args['start_date'] = date( 'Y-m-d', $time ); @@ -199,7 +199,7 @@ private function check_end_date( $date ) { $time = strtotime( $date ); if ( !empty( $date ) && !$time ) { - WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) ); + WP_CLI::warning( sprintf( "The end_date %s is invalid.", $date ) ); return false; } $this->export_args['end_date'] = date( 'Y-m-d', $time ); @@ -257,7 +257,7 @@ private function check_post__in( $post__in ) { $separator = false !== stripos( $post__in, ' ' ) ? ' ' : ','; $post__in = array_unique( array_map( 'intval', explode( $separator, $post__in ) ) ); if ( empty( $post__in ) ) { - WP_CLI::warning( "post__in should be comma-separated post IDs" ); + WP_CLI::warning( "post__in should be comma-separated post IDs." ); return false; } // New exporter uses a different argument @@ -288,7 +288,7 @@ private function check_author( $author ) { $authors = get_users_of_blog(); if ( empty( $authors ) || is_wp_error( $authors ) ) { - WP_CLI::warning( sprintf( "Could not find any authors in this blog" ) ); + WP_CLI::warning( sprintf( "Could not find any authors in this blog." ) ); return false; } $hit = false; @@ -316,7 +316,7 @@ private function check_category( $category ) { $term = category_exists( $category ); if ( empty( $term ) || is_wp_error( $term ) ) { - WP_CLI::warning( sprintf( 'Could not find a category matching %s', $category ) ); + WP_CLI::warning( sprintf( 'Could not find a category matching %s.', $category ) ); return false; } $this->export_args['category'] = $category; @@ -329,7 +329,7 @@ private function check_post_status( $status ) { $stati = get_post_statuses(); if ( empty( $stati ) || is_wp_error( $stati ) ) { - WP_CLI::warning( 'Could not find any post stati' ); + WP_CLI::warning( 'Could not find any post stati.' ); return false; } @@ -346,7 +346,7 @@ private function check_skip_comments( $skip ) { return true; if ( (int) $skip <> 0 && (int) $skip <> 1 ) { - WP_CLI::warning( 'skip_comments needs to be 0 (no) or 1 (yes)' ); + WP_CLI::warning( 'skip_comments needs to be 0 (no) or 1 (yes).' ); return false; } $this->export_args['skip_comments'] = $skip; @@ -355,7 +355,7 @@ private function check_skip_comments( $skip ) { private function check_max_file_size( $size ) { if ( !is_numeric( $size ) ) { - WP_CLI::warning( sprintf( "max_file_size should be numeric", $size ) ); + WP_CLI::warning( sprintf( "max_file_size should be numeric.", $size ) ); return false; } From b878b9ef715f285c35b9f189f29134dbdd6cb79c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 20 Jun 2016 05:44:53 -0700 Subject: [PATCH 4603/5359] Introduce `WP_CLI\Utils\parse_ssh_url()` for parsing SSH URLs Includes unit tests for expected behavior --- php/WP_CLI/Runner.php | 8 +++---- php/utils.php | 37 ++++++++++++++++++++++++++++++ tests/test-utils.php | 53 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c871ed4eb..4ca445302 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -327,10 +327,10 @@ private function run_ssh_command( $ssh ) { WP_CLI::do_hook( 'before_ssh' ); // host OR host/path/to/wordpress OR host:port/path/to/wordpress - preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $ssh, $matches ); - $host = isset( $matches[1] ) ? $matches[1] : null; - $port = isset( $matches[3] ) ? $matches[3] : null; - $path = isset( $matches[4] ) ? $matches[4] : null; + $bits = Utils\parse_ssh_url( $ssh ); + $host = isset( $bits['host'] ) ? $bits['host'] : null; + $port = isset( $bits['port'] ) ? $bits['port'] : null; + $path = isset( $bits['path'] ) ? $bits['path'] : null; WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); WP_CLI::debug( 'SSH port: ' . $port, 'bootstrap' ); diff --git a/php/utils.php b/php/utils.php index 23d28b99d..6268dcbcb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -718,3 +718,40 @@ function get_temp_dir() { return $trailingslashit( $temp ); } + +/** + * Parse a SSH url for its host, port, and path. + * + * Similar to parse_url(), but adds support for defined SSH aliases. + * + * ``` + * host OR host/path/to/wordpress OR host:port/path/to/wordpress + * ``` + * + * @access public + * + * @return mixed + */ +function parse_ssh_url( $url, $component = -1 ) { + preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $url, $matches ); + $bits = array(); + foreach( array( + 1 => 'host', + 3 => 'port', + 4 => 'path', + ) as $i => $key ) { + if ( ! empty( $matches[ $i ] ) ) { + $bits[ $key ] = $matches[ $i ]; + } + } + switch ( $component ) { + case PHP_URL_HOST: + return isset( $bits['host'] ) ? $bits['host'] : null; + case PHP_URL_PATH: + return isset( $bits['path'] ) ? $bits['path'] : null; + case PHP_URL_PORT: + return isset( $bits['port'] ) ? $bits['port'] : null; + default: + return $bits; + } +} diff --git a/tests/test-utils.php b/tests/test-utils.php index 01bbc5101..deda16a62 100644 --- a/tests/test-utils.php +++ b/tests/test-utils.php @@ -44,5 +44,58 @@ public function testGetSemVer() { $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.1.1', $original_version ) ); } + public function testParseSSHUrl() { + $testcase = 'foo'; + $this->assertEquals( array( + 'host' => 'foo', + ), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( 'foo', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + + $testcase = 'foo.com'; + $this->assertEquals( array( + 'host' => 'foo.com', + ), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + + $testcase = 'foo.com:2222'; + $this->assertEquals( array( + 'host' => 'foo.com', + 'port' => 2222, + ), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( 2222, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + + $testcase = 'foo.com:2222/path/to/dir'; + $this->assertEquals( array( + 'host' => 'foo.com', + 'port' => 2222, + 'path' => '/path/to/dir', + ), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( 2222, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( '/path/to/dir', Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + + $testcase = 'foo.com~/path/to/dir'; + $this->assertEquals( array( + 'host' => 'foo.com', + 'path' => '~/path/to/dir', + ), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( '~/path/to/dir', Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + + // No host + $testcase = '~/path/to/dir'; + $this->assertEquals( array(), Utils\parse_ssh_url( $testcase ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); + $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); + } + } From 03a0e4b49d7b17d5e0a774ac60ddc680c88172d3 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 20 Jun 2016 22:15:18 +0545 Subject: [PATCH 4604/5359] Improved messages in db commands --- php/commands/db.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 5acab0bc3..57828e98b 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -229,19 +229,19 @@ public function query( $args ) { * * # Export database with drop query included * $ wp db export --add-drop-table - * Success: Exported to wordpress_dbase.sql + * Success: Exported to 'wordpress_dbase.sql'. * * # Export certain tables * $ wp db export --tables=wp_options,wp_users - * Success: Exported to wordpress_dbase.sql + * Success: Exported to 'wordpress_dbase.sql'. * * # Export all tables matching a wildcard * $ wp db export --tables=$(wp db tables 'wp_user*' --format=csv) - * Success: Exported to wordpress_dbase.sql + * Success: Exported to 'wordpress_dbase.sql'. * * # Export all tables matching prefix * $ wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) - * Success: Exported to wordpress_dbase.sql + * Success: Exported to 'wordpress_dbase.sql'. * * @alias dump */ @@ -285,7 +285,7 @@ function export( $args, $assoc_args ) { WP_CLI::line( $result_file ); } else if ( ! $stdout ) { - WP_CLI::success( sprintf( 'Exported to %s', $result_file ) ); + WP_CLI::success( sprintf( "Exported to '%s'.", $result_file ) ); } } @@ -300,7 +300,7 @@ function export( $args, $assoc_args ) { * ## EXAMPLES * * $ wp db import wordpress_dbase.sql - * Success: Imported from wordpress_dbase.sql + * Success: Imported from 'wordpress_dbase.sql'. */ public function import( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); @@ -327,7 +327,7 @@ public function import( $args, $assoc_args ) { 'database' => DB_NAME ), $descriptors ); - WP_CLI::success( sprintf( 'Imported from %s', $result_file ) ); + WP_CLI::success( sprintf( "Imported from '%s'.", $result_file ) ); } /** From edf4bfa04696e5362ebf618ad1c4afe1cbc9a845 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 20 Jun 2016 10:41:27 -0700 Subject: [PATCH 4605/5359] Ignore `wp-cli.local.yml` in plugin scaffold `.gitignore` This file is only ever meant for local development. --- templates/plugin-distignore.mustache | 1 + templates/plugin-gitignore.mustache | 1 + 2 files changed, 2 insertions(+) diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache index 6a8b3da10..36a11a63f 100644 --- a/templates/plugin-distignore.mustache +++ b/templates/plugin-distignore.mustache @@ -12,6 +12,7 @@ package.json phpunit.xml phpunit.xml.dist README.md +wp-cli.local.yml tests vendor node_modules diff --git a/templates/plugin-gitignore.mustache b/templates/plugin-gitignore.mustache index 646ac519e..d4a540553 100644 --- a/templates/plugin-gitignore.mustache +++ b/templates/plugin-gitignore.mustache @@ -1,2 +1,3 @@ .DS_Store +wp-cli.local.yml node_modules/ From ab13c6291cd2aa5888b5a02e1fd7f073512e7e72 Mon Sep 17 00:00:00 2001 From: voldemortensen <voldemortensen@users.noreply.github.com> Date: Mon, 20 Jun 2016 12:30:48 -0600 Subject: [PATCH 4606/5359] allow the author field to be selected in `wp theme list --fields=<field>` --- php/commands/theme.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/theme.php b/php/commands/theme.php index 36a144e07..a834768ec 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -411,6 +411,7 @@ protected function get_item_list() { 'update_id' => $theme->get_stylesheet(), 'title' => $theme->get('Name'), 'description' => $theme->get('Description'), + 'author' => $theme->get('Author'), ); if ( is_multisite() ) { From fa11a5b19c1aeb5a1c49a39b9fd4a6027043cfc2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 20 Jun 2016 11:43:15 -0700 Subject: [PATCH 4607/5359] Update tests for edf4bfa04696e5362ebf618ad1c4afe1cbc9a845 --- features/scaffold.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 7ece65d81..48409fb28 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -155,6 +155,7 @@ Feature: WordPress code scaffolding And the {PLUGIN_DIR}/hello-world/.gitignore file should contain: """ .DS_Store + wp-cli.local.yml node_modules/ """ And the {PLUGIN_DIR}/hello-world/.distignore file should contain: From 709c5fcffaa31ca3be2df3d7a721fd16ed336f97 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 21 Jun 2016 11:28:59 +0545 Subject: [PATCH 4608/5359] Add example for import and other doc improvement --- php/commands/import.php | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index c0644e33a..8ae820833 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -1,5 +1,21 @@ <?php +/** + * Manage imports. + * + * ## EXAMPLES + * + * # Import content from a WXR file + * $ wp import example.wordpress.2016-06-21.xml --authors=create + * Starting the import process... + * Processing post #1 ("Hello world!") (post_type: post) + * -- 1 of 1 + * -- Tue, 21 Jun 2016 05:31:12 +0000 + * -- Imported post as post_id #1 + * Success: Finished importing from 'example.wordpress.2016-06-21.xml' file. + * + * @package wp-cli + */ class Import_Command extends WP_CLI_Command { var $processed_posts = array(); @@ -17,6 +33,17 @@ class Import_Command extends WP_CLI_Command { * * [--skip=<data-type>] * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). + * + * ## EXAMPLES + * + * # Import content from a WXR file + * $ wp import example.wordpress.2016-06-21.xml --authors=create + * Starting the import process... + * Processing post #1 ("Hello world!") (post_type: post) + * -- 1 of 1 + * -- Tue, 21 Jun 2016 05:31:12 +0000 + * -- Imported post as post_id #1 + * Success: Finished importing from 'example.wordpress.2016-06-21.xml' file. */ public function __invoke( $args, $assoc_args ) { $defaults = array( @@ -51,7 +78,7 @@ public function __invoke( $args, $assoc_args ) { foreach ( $args as $file ) { if ( ! is_readable( $file ) ) { - WP_CLI::warning( "Can't read $file file." ); + WP_CLI::warning( "Can't read '$file' file." ); } $ret = $this->import_wxr( $file, $assoc_args ); @@ -60,7 +87,7 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( $ret ); } else { WP_CLI::log(''); // WXR import ends with HTML, so make sure message is on next line - WP_CLI::success( "Finished importing from $file file." ); + WP_CLI::success( "Finished importing from '$file' file." ); } } } From 5011ef171187ba1140c4a87efd443edce499b0b2 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 21 Jun 2016 21:21:09 +0545 Subject: [PATCH 4609/5359] Fix PHP notice in theme status --- php/commands/theme.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index a834768ec..b8b2cd83c 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -79,11 +79,13 @@ protected function get_upgrader_class( $force ) { * Author: the WordPress team */ function status( $args ) { - $theme = $this->fetcher->get_check( $args[0] ); - $errors = $theme->errors(); - if ( is_wp_error( $errors ) ) { - $message = $errors->get_error_message(); - WP_CLI::error( $message ); + if ( isset( $args[0] ) ) { + $theme = $this->fetcher->get_check( $args[0] ); + $errors = $theme->errors(); + if ( is_wp_error( $errors ) ) { + $message = $errors->get_error_message(); + WP_CLI::error( $message ); + } } parent::status( $args ); From ba458ccc632a874c8d2c054ae70dfbbf8bf54115 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 21 Jun 2016 21:56:32 +0545 Subject: [PATCH 4610/5359] Add scenario for theme status without theme parameter --- features/theme.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 8c741b2d2..dcf1343a1 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -50,6 +50,20 @@ Feature: Manage WordPress themes When I run `wp theme list` Then STDOUT should not be empty + Scenario: Checking theme status without theme parameter + Given a WP install + + When I run `wp theme install classic --activate` + And I run `wp theme list --field=name --status=inactive | xargs -0 -d '\n' -I % wp theme delete %` + And I run `wp theme status` + Then STDOUT should be: + """ + 1 installed theme: + A classic 1.6 + + Legend: A = Active + """ + Scenario: Install a theme, activate, then force install an older version of the theme Given a WP install From b9dcfdd0968498db4b78392d1f2fcb904ba9c958 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 21 Jun 2016 12:40:11 -0700 Subject: [PATCH 4611/5359] Update tests for WordPress 4.5.3 --- features/core-check-update.feature | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index ad3cf2a69..0b6a728ab 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -1,17 +1,16 @@ Feature: Check for more recent versions - @less-than-php-7 Scenario: Check for update via Version Check API Given a WP install - When I run `wp core download --version=3.8 --force` + When I run `wp core download --version=4.4 --force` Then STDOUT should not be empty When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | - | 3.8.14 | minor | https://downloads.wordpress.org/release/wordpress-3.8.14-partial-0.zip | + | 4.5.3 | major | https://downloads.wordpress.org/release/wordpress-4.5.3.zip | + | 4.4.4 | minor | https://downloads.wordpress.org/release/wordpress-4.4.4-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -22,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | + | 4.5.3 | major | https://downloads.wordpress.org/release/wordpress-4.5.3.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -33,7 +32,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 3.8.14 | minor | https://downloads.wordpress.org/release/wordpress-3.8.14-partial-0.zip | + | 4.4.4 | minor | https://downloads.wordpress.org/release/wordpress-4.4.4-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -54,4 +53,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.11 | minor | https://downloads.wordpress.org/release/wordpress-4.0.11-partial-0.zip | + | 4.0.12 | minor | https://downloads.wordpress.org/release/wordpress-4.0.12-partial-0.zip | From 6819c23c1943858b217e1b9a2fc721ba0073601c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 21 Jun 2016 13:29:25 -0700 Subject: [PATCH 4612/5359] Minor version updates too --- features/core-update.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/core-update.feature b/features/core-update.feature index ea20e1049..e4e3a49fc 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.14 + Updating to version 3.7.15 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.14 + 3.7.15 """ @less-than-php-7 @@ -208,8 +208,8 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 4.0.10 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.10-partial-0.zip + Updating to version 4.0.11 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.11-partial-0.zip """ And STDOUT should contain: """ From f39298e689fbd9e5bb199fc21573c29c6fb4c8bf Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 22 Jun 2016 15:21:15 +0545 Subject: [PATCH 4613/5359] Doc improvement in export command --- php/commands/export.php | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 93a471271..6278c3d2b 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -1,9 +1,23 @@ <?php +/** + * Manage exports. + * + * ## EXAMPLES + * + * # Export posts published by the user between given start and end date + * $ wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + * Starting export process... + * Writing to file /tmp/staging.wordpress.2016-05-24.000.xml + * Success: All done with export. + * + * @package wp-cli + */ class Export_Command extends WP_CLI_Command { /** - * Initialize the array of arguments that will be eventually be passed to export_wp + * Initialize the array of arguments that will be eventually be passed to export_wp. + * * @var array */ public $export_args = array(); @@ -21,7 +35,10 @@ class Export_Command extends WP_CLI_Command { * : Don't export comments. * * [--max_file_size=<MB>] - * : A single export file should have this many megabytes. Default: 15 + * : A single export file should have this many megabytes. + * --- + * default: 15 + * --- * * ## FILTERS * @@ -33,7 +50,10 @@ class Export_Command extends WP_CLI_Command { * * [--post_type=<post-type>] * : Export only posts with this post_type. Separate multiple post types with a - * comma. Defaults to all. + * comma. + * --- + * default: any + * --- * * [--post_type__not_in=<post-type>] * : Export all post types except those identified. Separate multiple post types @@ -76,7 +96,6 @@ class Export_Command extends WP_CLI_Command { * Starting export process... * Writing to file /var/www/example.com/public_html/staging.wordpress.2016-05-24.000.xml * Success: All done with export. - * */ public function __invoke( $_, $assoc_args ) { $defaults = array( @@ -171,7 +190,7 @@ private function check_dir( $path ) { if ( empty( $path ) ) { $path = getcwd(); } elseif ( !is_dir( $path ) ) { - WP_CLI::error( sprintf( "The directory %s does not exist.", $path ) ); + WP_CLI::error( sprintf( "The directory '%s' does not exist.", $path ) ); return false; } @@ -260,7 +279,7 @@ private function check_post__in( $post__in ) { WP_CLI::warning( "post__in should be comma-separated post IDs." ); return false; } - // New exporter uses a different argument + // New exporter uses a different argument. $this->export_args['post_ids'] = $post__in; return true; } @@ -272,7 +291,7 @@ private function check_start_id( $start_id ) { $start_id = intval( $start_id ); - // Post IDs must be greater than 0 + // Post IDs must be greater than 0. if ( 0 >= $start_id ) { WP_CLI::warning( sprintf( __( 'Invalid start ID: %d' ), $start_id ) ); return false; @@ -366,4 +385,3 @@ private function check_max_file_size( $size ) { } WP_CLI::add_command( 'export', 'Export_Command' ); - From 17563405b1a812e1f2b2ca0703521c30543e7fde Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 22 Jun 2016 16:39:29 +0545 Subject: [PATCH 4614/5359] Improve doc and command message in core commands --- features/core-update-db.feature | 10 ++++---- features/core-update.feature | 2 +- php/commands/core.php | 41 +++++++++++++++++++-------------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index f3abbe1ea..73a3b6862 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -8,13 +8,13 @@ Feature: Update core's database When I run `wp core update-db` Then STDOUT should contain: """ - Success: WordPress database upgraded successfully from db version 29630 to 30133 + Success: WordPress database upgraded successfully from db version 29630 to 30133. """ When I run `wp core update-db` Then STDOUT should contain: """ - Success: WordPress database already at latest db version 30133 + Success: WordPress database already at latest db version 30133. """ Scenario: Dry run update db on a single site @@ -26,7 +26,7 @@ Feature: Update core's database Then STDOUT should be: """ Performing a dry run, with no database modification. - Success: WordPress database upgraded successfully from db version 29630 to 30133 + Success: WordPress database upgraded successfully from db version 29630 to 30133. """ When I run `wp option get db_version` @@ -52,7 +52,7 @@ Feature: Update core's database When I run `wp core update-db --network` Then STDOUT should contain: """ - Success: WordPress database upgraded on 3/3 sites + Success: WordPress database upgraded on 3/3 sites. """ Scenario: Update db across network @@ -76,5 +76,5 @@ Feature: Update core's database """ And STDOUT should contain: """ - Success: WordPress database upgraded on 3/3 sites + Success: WordPress database upgraded on 3/3 sites. """ diff --git a/features/core-update.feature b/features/core-update.feature index e4e3a49fc..fff39612c 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -20,7 +20,7 @@ Feature: Update WordPress core Starting update... Unpacking the update... Cleaning up files... - No files found that need cleaned up + No files found that need cleaned up. Success: WordPress updated successfully. """ diff --git a/php/commands/core.php b/php/commands/core.php index 80a3eadae..b8ada4ea5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -46,7 +46,14 @@ class Core_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] - * : Accepted values: table, csv, json, yaml. Default: table + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -110,16 +117,16 @@ public function download( $args, $assoc_args ) { if ( ! is_dir( $download_dir ) ) { if ( ! is_writable( dirname( $download_dir ) ) ) { - WP_CLI::error( sprintf( "Insufficient permission to create directory %s", $download_dir ) ); + WP_CLI::error( sprintf( "Insufficient permission to create directory '%s'.", $download_dir ) ); } - WP_CLI::log( sprintf( 'Creating directory %s', $download_dir ) ); + WP_CLI::log( sprintf( "Creating directory '%s'.", $download_dir ) ); $mkdir = \WP_CLI\Utils\is_windows() ? 'mkdir %s' : 'mkdir -p %s'; WP_CLI::launch( Utils\esc_cmd( $mkdir, $download_dir ) ); } if ( ! is_writable( $download_dir ) ) { - WP_CLI::error( sprintf( "%s is not writable by current user", $download_dir ) ); + WP_CLI::error( sprintf( "'%s' is not writable by current user.", $download_dir ) ); } $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); @@ -175,19 +182,19 @@ public function download( $args, $assoc_args ) { if ( 404 == $response->status_code ) { WP_CLI::error( "Release not found. Double-check locale or version." ); } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})" ); + WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})." ); } $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); + WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); } $md5_file = md5_file( $temp ); if ( $md5_file === $md5_response->body ) { WP_CLI::log( 'md5 hash verified: ' . $md5_file ); } else { - WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})" ); + WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); } try { @@ -277,7 +284,7 @@ private static function _read( $url ) { if ( 200 === $response->status_code ) { return $response->body; } else { - WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})" ); + WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); } } @@ -347,14 +354,14 @@ private static function get_initial_locale() { * * # Standard wp-config.php file * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO - * Success: Generated wp-config.php file. + * Success: Generated 'wp-config.php' file. * * # Enable WP_DEBUG and WP_DEBUG_LOG * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP * $ define( 'WP_DEBUG', true ); * $ define( 'WP_DEBUG_LOG', true ); * $ PHP - * Success: Generated wp-config.php file. + * Success: Generated 'wp-config.php' file. */ public function config( $_, $assoc_args ) { global $wp_version; @@ -408,9 +415,9 @@ public function config( $_, $assoc_args ) { $bytes_written = file_put_contents( ABSPATH . 'wp-config.php', $out ); if ( ! $bytes_written ) { - WP_CLI::error( 'Could not create new wp-config.php file.' ); + WP_CLI::error( "Could not create new 'wp-config.php' file." ); } else { - WP_CLI::success( 'Generated wp-config.php file.' ); + WP_CLI::success( "Generated 'wp-config.php' file." ); } } @@ -1312,7 +1319,7 @@ function update_db( $_, $assoc_args ) { if ( ! $dry_run && $total && $success == $total ) { update_site_option( 'wpmu_upgrade_site', $wp_db_version ); } - WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites', $success, $total ) ); + WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); } else { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); $wp_current_db_version = __get_option( 'db_version' ); @@ -1320,9 +1327,9 @@ function update_db( $_, $assoc_args ) { if ( ! $dry_run ) { wp_upgrade(); } - WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}" ); + WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}." ); } else { - WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}" ); + WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}." ); } } } @@ -1443,9 +1450,9 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { } if ( $count ) { - WP_CLI::log( number_format( $count ) . ' files cleaned up' ); + WP_CLI::log( number_format( $count ) . ' files cleaned up.' ); } else { - WP_CLI::log( 'No files found that need cleaned up' ); + WP_CLI::log( 'No files found that need cleaned up.' ); } } } From bfb3512b127b8bb971f423bda701507ebb58b4ed Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 22 Jun 2016 17:39:55 +0545 Subject: [PATCH 4615/5359] Add missing count param in core check-update --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index b8ada4ea5..459e1e992 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -46,11 +46,13 @@ class Core_Command extends WP_CLI_Command { * : Limit the output to specific object fields. Defaults to version,update_type,package_url. * * [--format=<format>] + * : Render output in a particular format. * --- * default: table * options: * - table * - csv + * - count * - json * - yaml * --- From 6eca09b3172ab1a99e6046a51a0595ce66ddb483 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 23 Jun 2016 13:50:39 +0545 Subject: [PATCH 4616/5359] Wrap wp-config.php file name with quotes in command messages --- features/core-config.feature | 2 +- features/core.feature | 4 ++-- php/WP_CLI/Runner.php | 4 ++-- php/commands/core.php | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/core-config.feature b/features/core-config.feature index 7b445bf93..df7186bde 100644 --- a/features/core-config.feature +++ b/features/core-config.feature @@ -15,7 +15,7 @@ Feature: Manage wp-config Then the return code should be 1 And STDERR should be: """ - Error: wp-config.php not found. + Error: 'wp-config.php' not found. Either create one manually or use `wp core config`. """ diff --git a/features/core.feature b/features/core.feature index 0f91b7b62..87bebc383 100644 --- a/features/core.feature +++ b/features/core.feature @@ -135,7 +135,7 @@ Feature: Manage WordPress installation Then STDOUT should be: """ Set up multisite database tables. - Added multisite constants to wp-config.php. + Added multisite constants to 'wp-config.php'. Success: Network installed. Don't forget to set up rewrite rules. """ And STDERR should be empty @@ -169,7 +169,7 @@ Feature: Manage WordPress installation """ Created single site database tables. Set up multisite database tables. - Added multisite constants to wp-config.php. + Added multisite constants to 'wp-config.php'. Success: Network installed. Don't forget to set up rewrite rules. """ And STDERR should be empty diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4ca445302..08f9555f8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -784,7 +784,7 @@ public function start() { if ( !Utils\locate_wp_config() ) { WP_CLI::error( - "wp-config.php not found.\n" . + "'wp-config.php' not found.\n" . "Either create one manually or use `wp core config`." ); } @@ -859,7 +859,7 @@ public function load_wordpress() { $wp_config_path = Utils\locate_wp_config(); if ( ! $wp_config_path ) { WP_CLI::error( - "wp-config.php not found.\n" . + "'wp-config.php' not found.\n" . "Either create one manually or use `wp core config`." ); } diff --git a/php/commands/core.php b/php/commands/core.php index 459e1e992..688510373 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -763,9 +763,9 @@ private function _multisite_convert( $assoc_args ) { $wp_config_path = Utils\locate_wp_config(); if ( is_writable( $wp_config_path ) ) { self::modify_wp_config( $ms_config ); - WP_CLI::log( 'Added multisite constants to wp-config.php.' ); + WP_CLI::log( "Added multisite constants to 'wp-config.php'." ); } else { - WP_CLI::warning( 'Multisite constants could not be written to wp-config.php. You may need to add them manually:' ); + WP_CLI::warning( "Multisite constants could not be written to 'wp-config.php'. You may need to add them manually:" ); WP_CLI::log( $ms_config ); } } From e697d62d79c01c27958def53ba99fe42de574486 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 23 Jun 2016 17:13:24 +0545 Subject: [PATCH 4617/5359] Doc improvement in menu commands --- php/commands/menu.php | 150 +++++++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 59 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 7959447a4..5517d374a 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -1,7 +1,7 @@ <?php /** - * List, create, assign, and delete menus + * List, create, assign, and delete menus. * * ## EXAMPLES * @@ -25,6 +25,8 @@ * # Assign the 'my-menu' menu to the 'primary' location * $ wp menu location assign my-menu primary * Success: Assigned location to menu. + * + * @package wp-cli */ class Menu_Command extends WP_CLI_Command { @@ -38,12 +40,12 @@ class Menu_Command extends WP_CLI_Command { ); /** - * Create a new menu + * Create a new menu. * * ## OPTIONS * * <menu-name> - * : A descriptive name for the menu + * : A descriptive name for the menu. * * [--porcelain] * : Output just the new menu id. @@ -73,12 +75,12 @@ public function create( $args, $assoc_args ) { } /** - * Delete one or more menus + * Delete one or more menus. * * ## OPTIONS * * <menu>... - * : The name, slug, or term ID for the menu(s) + * : The name, slug, or term ID for the menu(s). * * ## EXAMPLES * @@ -112,7 +114,17 @@ public function delete( $args, $_ ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - ids + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -164,7 +176,7 @@ public function list_( $_, $assoc_args ) { } - // Normalize the data for some output formats + // Normalize the data for some output formats. if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { $menu->locations = implode( ',', $menu->locations ); } @@ -182,7 +194,7 @@ protected function get_formatter( &$assoc_args ) { } /** - * List, add, and delete items associated with a menu + * List, add, and delete items associated with a menu. * * ## EXAMPLES * @@ -209,18 +221,28 @@ class Menu_Item_Command extends WP_CLI_Command { ); /** - * Get a list of items associated with a menu + * Get a list of items associated with a menu. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * [--fields=<fields>] * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - ids + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -284,39 +306,39 @@ public function list_( $args, $assoc_args ) { } /** - * Add a post as a menu item + * Add a post as a menu item. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * <post-id> - * : Post ID to add to the menu + * : Post ID to add to the menu. * * [--title=<title>] - * : Set a custom title for the menu item + * : Set a custom title for the menu item. * * [--link=<link>] - * : Set a custom url for the menu item + * : Set a custom url for the menu item. * * [--description=<description>] - * : Set a custom description for the menu item + * : Set a custom description for the menu item. * * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item + * : Set a custom title attribute for the menu item. * * [--target=<target>] - * : Set a custom link target for the menu item + * : Set a custom link target for the menu item. * * [--classes=<classes>] - * : Set a custom link classes for the menu item + * : Set a custom link classes for the menu item. * * [--position=<position>] * : Specify the position of this menu item. * * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item + * : Make this menu item a child of another menu item. * * [--porcelain] * : Output just the new menu item id. @@ -342,42 +364,42 @@ public function add_post( $args, $assoc_args ) { } /** - * Add a taxonomy term as a menu item + * Add a taxonomy term as a menu item. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * <taxonomy> - * : Taxonomy of the term to be added + * : Taxonomy of the term to be added. * * <term-id> - * : Term ID of the term to be added + * : Term ID of the term to be added. * * [--title=<title>] - * : Set a custom title for the menu item + * : Set a custom title for the menu item. * * [--link=<link>] - * : Set a custom url for the menu item + * : Set a custom url for the menu item. * * [--description=<description>] - * : Set a custom description for the menu item + * : Set a custom description for the menu item. * * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item + * : Set a custom title attribute for the menu item. * * [--target=<target>] - * : Set a custom link target for the menu item + * : Set a custom link target for the menu item. * * [--classes=<classes>] - * : Set a custom link classes for the menu item + * : Set a custom link classes for the menu item. * * [--position=<position>] * : Specify the position of this menu item. * * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item + * : Make this menu item a child of another menu item. * * [--porcelain] * : Output just the new menu item id. @@ -404,36 +426,36 @@ public function add_term( $args, $assoc_args ) { } /** - * Add a custom menu item + * Add a custom menu item. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * <title> - * : Title for the link + * : Title for the link. * * <link> - * : Target URL for the link + * : Target URL for the link. * * [--description=<description>] - * : Set a custom description for the menu item + * : Set a custom description for the menu item. * * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item + * : Set a custom title attribute for the menu item. * * [--target=<target>] - * : Set a custom link target for the menu item + * : Set a custom link target for the menu item. * * [--classes=<classes>] - * : Set a custom link classes for the menu item + * : Set a custom link classes for the menu item. * * [--position=<position>] * : Specify the position of this menu item. * * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item + * : Make this menu item a child of another menu item. * * [--porcelain] * : Output just the new menu item id. @@ -455,7 +477,7 @@ public function add_custom( $args, $assoc_args ) { } /** - * Update a menu item + * Update a menu item. * * ## OPTIONS * @@ -463,28 +485,28 @@ public function add_custom( $args, $assoc_args ) { * : Database ID for the menu item. * * [--title=<title>] - * : Set a custom title for the menu item + * : Set a custom title for the menu item. * * [--link=<link>] - * : Set a custom url for the menu item + * : Set a custom url for the menu item. * * [--description=<description>] - * : Set a custom description for the menu item + * : Set a custom description for the menu item. * * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item + * : Set a custom title attribute for the menu item. * * [--target=<target>] - * : Set a custom link target for the menu item + * : Set a custom link target for the menu item. * * [--classes=<classes>] - * : Set a custom link classes for the menu item + * : Set a custom link classes for the menu item. * * [--position=<position>] * : Specify the position of this menu item. * * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item + * : Make this menu item a child of another menu item. * * ## EXAMPLES * @@ -495,7 +517,7 @@ public function add_custom( $args, $assoc_args ) { */ public function update( $args, $assoc_args ) { - // Shuffle the position of these + // Shuffle the position of these. $args[1] = $args[0]; $terms = get_the_terms( $args[1], 'nav_menu' ); if ( $terms && ! is_wp_error( $terms ) ) { @@ -509,7 +531,7 @@ public function update( $args, $assoc_args ) { } /** - * Delete one or more items from a menu + * Delete one or more items from a menu. * * ## OPTIONS * @@ -549,7 +571,7 @@ public function delete( $args, $_ ) { } /** - * Worker method to create new items or update existing ones + * Worker method to create new items or update existing ones. */ private function add_or_update_item( $method, $type, $args, $assoc_args ) { @@ -692,7 +714,17 @@ class Menu_Location_Command extends WP_CLI_Command { * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - ids + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -729,15 +761,15 @@ public function list_( $_, $assoc_args ) { } /** - * Assign a location to a menu + * Assign a location to a menu. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * <location> - * : Location's slug + * : Location's slug. * * ## EXAMPLES * @@ -769,15 +801,15 @@ public function assign( $args, $_ ) { } /** - * Remove a location from a menu + * Remove a location from a menu. * * ## OPTIONS * * <menu> - * : The name, slug, or term ID for the menu + * : The name, slug, or term ID for the menu. * * <location> - * : Location's slug + * : Location's slug. * * ## EXAMPLES * From 215f486c09b8994e2dbd0c059465af3d7c145e27 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 26 Jun 2016 10:19:29 +0200 Subject: [PATCH 4618/5359] Failing test case for #2852 --- features/formatter.feature | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/features/formatter.feature b/features/formatter.feature index a34551b05..aa1d67823 100644 --- a/features/formatter.feature +++ b/features/formatter.feature @@ -6,9 +6,17 @@ Feature: Format output """ <?php /** + * Output data as YAML + * + * <type> + * : Type of output. + * + * [--fields=<fields>] + * : Limit output to particular fields + * * @when before_wp_load */ - $output_yaml = function( $args ) { + $output_yaml = function( $args, $assoc_args ) { $items = array( array( 'label' => 'Foo', @@ -19,8 +27,13 @@ Feature: Format output 'slug' => 'bar', ), ); - $assoc_args = array( 'format' => 'yaml', 'fields' => array( 'label', 'slug' ) ); - $formatter = new \WP_CLI\Formatter( $assoc_args ); + $format_args = array( 'format' => 'yaml' ); + if ( isset( $assoc_args['fields'] ) ) { + $format_args['fields'] = explode( ',', $assoc_args['fields'] ); + } else { + $format_args['fields'] = array( 'label', 'slug' ); + } + $formatter = new \WP_CLI\Formatter( $format_args ); if ( 'all' === $args[0] ) { $formatter->display_items( $items ); } else if ( 'single' === $args[0] ) { @@ -42,6 +55,20 @@ Feature: Format output slug: bar """ + When I run `wp --require=output-yaml.php yaml all --fields=label` + Then STDOUT should be YAML containing: + """ + --- + - + label: Foo + - + label: Bar + """ + And STDOUT should not contain: + """ + slug: bar + """ + When I run `wp --require=output-yaml.php yaml single` Then STDOUT should be YAML containing: """ From 42f5d456cb532fc56628962ecc560601c7531758 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 26 Jun 2016 10:20:23 +0200 Subject: [PATCH 4619/5359] Ensure YAML formatter handles objects and `--fields=<fields>` arg --- php/WP_CLI/Formatter.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php index 0b04ec5e8..5ab4bb529 100644 --- a/php/WP_CLI/Formatter.php +++ b/php/WP_CLI/Formatter.php @@ -138,16 +138,17 @@ private function format( $items ) { break; case 'json': + case 'yaml': $out = array(); foreach ( $items as $item ) { $out[] = \WP_CLI\Utils\pick_fields( $item, $fields ); } - echo json_encode( $out ); - break; - - case 'yaml': - echo \Spyc::YAMLDump( $items, 2, 0 ); + if ( 'json' === $this->args['format'] ) { + echo json_encode( $out ); + } else if ( 'yaml' === $this->args['format'] ) { + echo \Spyc::YAMLDump( $out, 2, 0 ); + } break; default: From f4f314a758056f4fe41cd22ed4762f346f31c2f4 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sun, 26 Jun 2016 21:58:31 +0545 Subject: [PATCH 4620/5359] Improve default format in command doc in plugin file --- php/commands/plugin.php | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 30f941ba8..d27ae8ba9 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -100,10 +100,16 @@ function status( $args ) { * : The string to search for. * * [--page=<page>] - * : Optional page to display. Defaults to 1. + * : Optional page to display. + * --- + * default: 1 + * --- * * [--per-page=<per-page>] - * : Optional number of results to display. Defaults to 10. + * : Optional number of results to display. + * --- + * default: 10 + * --- * * [--field=<field>] * : Prints the value of a single field for each plugin. @@ -127,7 +133,16 @@ function status( $args ) { * **short_description**: Plugin's Short Description * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - count + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -610,7 +625,15 @@ function install( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Output list as table, json, CSV, yaml. Defaults to table. + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -751,7 +774,16 @@ function delete( $args, $assoc_args = array() ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - count + * - json + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -790,7 +822,6 @@ function delete( $args, $assoc_args = array() ) { * | hello | inactive | none | 1.6 | * +------------------------------+----------------+-----------+------------+ * - * * @subcommand list */ public function list_( $_, $assoc_args ) { From 172bee7a7af5419883c38e27b4fa8d2db88b9d64 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 02:38:53 -0700 Subject: [PATCH 4621/5359] Readme edits: https links; clarity See #2760 --- README.md | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 914f640ad..b81355121 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,30 @@ WP-CLI ====== -[WP-CLI](http://wp-cli.org/) is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser. +[WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. + +<div style=" + border: 1px solid #7AD03A; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + padding-left: 10px; + padding-right: 10px; +"> + <p><strong>A more RESTful WP-CLI</strong> aims to unlocking the potential of the WP REST API at the command line. Project backed by Pressed, Chris Lema, Human Made, Pagely, Pantheon and many others. <a href="https://wp-cli.org/restful/">Learn more →</a></p> +</div> [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) - Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) +For news and announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). + ## Using -The goal of WP-CLI is to provide a command-line interface for any action you can perform in the WordPress admin. The project also includes commands for many actions you can't perform in the WordPress admin. +WP-CLI's mission is to provide a command-line interface for any action you might want to perform in the WordPress dashboard. WP-CLI also includes commands for many things you can't do in the WordPress dashboard. -For instance, `wp plugin install` ([doc](http://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: +For instance, `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: ``` $ wp plugin install rest-api --activate @@ -25,32 +37,34 @@ Activating 'rest-api'... Success: Plugin 'rest-api' activated. ``` -Similarly, `wp transient` ([doc](http://wp-cli.org/commands/transient/)) lets you delete one or all transients: +Similarly, `wp transient` ([doc](https://wp-cli.org/commands/transient/)) lets you delete one or all transients: ``` $ wp transient delete-all Success: 34 transients deleted from the database. ``` -For a complete introduction, read the [Quick Start guide](http://wp-cli.org/docs/quick-start/). If you already feel comfortable with the basics, jump into the [complete list of commands](http://wp-cli.org/commands/) for managing themes and plugins, importing and exporting data, performing database search-replace operations and more. +For a complete introduction to WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). + +Already feel comfortable with the basics? Jump into the [complete list of commands](https://wp-cli.org/commands/) for detailed information on managing themes and plugins, importing and exporting data, performing database search-replace operations and more. ## Installing -The recommended way to install WP-CLI is to download the Phar build, mark it executable and place it in your PATH. See also our documentation on [alternative installation methods](http://wp-cli.org/docs/installing/). +We recommend installing WP-CLI through the Phar distribution mechanism: download the Phar build, mark it executable, and place it on your PATH. The complete instructions follow shortly. Should you need, see also our documentation on [alternative installation methods](https://wp-cli.org/docs/installing/). -Before you install though, please make sure your environment meets the minimum requirements: +Before installing WP-CLI, please make sure your environment meets the minimum requirements: - UNIX-like environment (OS X, Linux, FreeBSD, Cygwin); limited support in Windows environment - PHP 5.3.29 or later - WordPress 3.7 or later -Download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) using `wget` or `curl`. For example: +Once you've verified requirements, download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) file using `wget` or `curl`. For example: ``` $ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar ``` -Check if it is working: +Next, check if it is working: ``` $ php wp-cli.phar --info @@ -81,28 +95,29 @@ WP-CLI version: 0.23.0 WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: -- [Common issues and their fixes](http://wp-cli.org/docs/common-issues/) -- [Best practices for submitting a bug report](http://wp-cli.org/docs/bug-reports/) -- [Documentation portal](http://wp-cli.org/docs/) +- [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) +- [Best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) +- [Documentation portal](https://wp-cli.org/docs/) If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). ## Extending -A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](http://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](http://wp-cli.org/commands/plugin/activate/)) is another. +A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. -WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](http://wp-cli.org/docs/commands-cookbook/) to learn more. +WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. ## Contributing -To get involved, please first read about [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). +To get involved, please first read about [creating an issue](https://wp-cli.org/docs/bug-reports/) or [submitting a pull request](https://wp-cli.org/docs/pull-requests/). ### Leadership + * [Andreas Creten](https://github.com/andreascreten) - founder * [Cristi Burcă](https://github.com/scribu) - previous maintainer * [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer -Read more about the project's [Governance](http://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). +Read more about the project's [Governance](https://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). ## Credits From 24f16e435b80132fce809146b2067aa4fe4106dd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 03:35:07 -0700 Subject: [PATCH 4622/5359] Restructure intro so quick links don't get rendered as table See #2760 --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b81355121..248c65e0a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ WP-CLI [WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. +For news and announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). + +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) + <div style=" border: 1px solid #7AD03A; -webkit-border-radius: 5px; @@ -14,11 +18,7 @@ WP-CLI <p><strong>A more RESTful WP-CLI</strong> aims to unlocking the potential of the WP REST API at the command line. Project backed by Pressed, Chris Lema, Human Made, Pagely, Pantheon and many others. <a href="https://wp-cli.org/restful/">Learn more →</a></p> </div> -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) - -Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) - -For news and announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). +Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) ## Using From 6b792ac9f782946c01cf7589619db78371a9bda5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 03:47:27 -0700 Subject: [PATCH 4623/5359] Remaining edits to the README.md Fixes #2760 --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 248c65e0a..2c6b99631 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ WP-CLI [WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. -For news and announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). +To stay up to date, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) @@ -22,9 +22,7 @@ Quick links: [Using](#using) | [Installing](#installing) | [Support](# ## Using -WP-CLI's mission is to provide a command-line interface for any action you might want to perform in the WordPress dashboard. WP-CLI also includes commands for many things you can't do in the WordPress dashboard. - -For instance, `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: +WP-CLI's goal is to provide a command-line interface for any action you might want to perform in the WordPress admin. For instance, `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: ``` $ wp plugin install rest-api --activate @@ -37,20 +35,20 @@ Activating 'rest-api'... Success: Plugin 'rest-api' activated. ``` -Similarly, `wp transient` ([doc](https://wp-cli.org/commands/transient/)) lets you delete one or all transients: +WP-CLI also includes commands for many things you can't do in the WordPress admin. For example, `wp transient delete-all` ([doc](https://wp-cli.org/commands/transient/delete-all/)) lets you delete one or all transients: ``` $ wp transient delete-all Success: 34 transients deleted from the database. ``` -For a complete introduction to WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). +For a more complete introduction to using WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). Already feel comfortable with the basics? Jump into the [complete list of commands](https://wp-cli.org/commands/) for detailed information on managing themes and plugins, importing and exporting data, performing database search-replace operations and more. ## Installing -We recommend installing WP-CLI through the Phar distribution mechanism: download the Phar build, mark it executable, and place it on your PATH. The complete instructions follow shortly. Should you need, see also our documentation on [alternative installation methods](https://wp-cli.org/docs/installing/). +Downloading the Phar file is our recommended installation method. Should you need, see also our documentation on [alternative installation methods](https://wp-cli.org/docs/installing/). Before installing WP-CLI, please make sure your environment meets the minimum requirements: @@ -58,7 +56,7 @@ Before installing WP-CLI, please make sure your environment meets the minimum re - PHP 5.3.29 or later - WordPress 3.7 or later -Once you've verified requirements, download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) file using `wget` or `curl`. For example: +Once you've verified requirements, download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) file using `wget` or `curl`: ``` $ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar @@ -70,14 +68,14 @@ Next, check if it is working: $ php wp-cli.phar --info ``` -To use it from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: +To use WP-CLI from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: ``` $ chmod +x wp-cli.phar $ sudo mv wp-cli.phar /usr/local/bin/wp ``` -If WP-CLI installed successfully, you should see something like this when you run `wp --info`: +If WP-CLI was installed successfully, you should see something like this when you run `wp --info`: ``` $ wp --info @@ -91,6 +89,8 @@ WP-CLI project config: WP-CLI version: 0.23.0 ``` +You can update WP-CLI with `wp cli update` ([doc](https://wp-cli.org/commands/cli/update/)), or by repeating the installation steps. + ## Support WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: @@ -113,11 +113,11 @@ To get involved, please first read about [creating an issue](https://wp-cli.org/ ### Leadership -* [Andreas Creten](https://github.com/andreascreten) - founder -* [Cristi Burcă](https://github.com/scribu) - previous maintainer * [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer +* [Cristi Burcă](https://github.com/scribu) - previous maintainer +* [Andreas Creten](https://github.com/andreascreten) - founder -Read more about the project's [Governance](https://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). +Read more about the project's [governance](https://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). ## Credits From 658b03a78baf757bde085e323766cdfba6210757 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 27 Jun 2016 17:43:50 +0545 Subject: [PATCH 4624/5359] Improve default format in docs for cron commands --- php/commands/cron.php | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 6e531e6c8..d910434dc 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -15,12 +15,13 @@ * * # Delete the next scheduled cron event * $ wp cron event delete cron_test - * Success: Deleted 2 instances of the cron event 'cron_test' + * Success: Deleted 2 instances of the cron event 'cron_test'. * * # List scheduled cron events in JSON * $ wp cron event list --fields=hook,next_run --format=json * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] * + * @package wp-cli */ class Cron_Event_Command extends WP_CLI_Command { @@ -47,7 +48,16 @@ class Cron_Event_Command extends WP_CLI_Command { * : Prints the value of a single field for each event. * * [--format=<format>] - * : Accepted values: table, json, csv, ids, yaml. Default: table. + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -115,7 +125,7 @@ public function list_( $args, $assoc_args ) { * ## OPTIONS * * <hook> - * : The hook name + * : The hook name. * * [<next-run>] * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. @@ -282,13 +292,13 @@ protected static function run_event( stdClass $event ) { * ## OPTIONS * * <hook> - * : The hook name + * : The hook name. * * ## EXAMPLES * * # Delete the next scheduled cron event * $ wp cron event delete cron_test - * Success: Deleted 2 instances of the cron event 'cron_test' + * Success: Deleted 2 instances of the cron event 'cron_test'. */ public function delete( $args, $assoc_args ) { @@ -493,7 +503,16 @@ class Cron_Schedule_Command extends WP_CLI_Command { * : Prints the value of a single field for each schedule. * * [--format=<format>] - * : Accepted values: table, json, csv, ids, yaml. Default: table. + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - yaml + * --- * * ## AVAILABLE FIELDS * From 0b513daa831ddcd8e78e73a3f5019c4fd7fb616c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 07:16:14 -0700 Subject: [PATCH 4625/5359] Link to WP StackExchange and Github issue backlog for support --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2c6b99631..d5613e0ba 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ WP-CLI's maintainers and project contributors do their best to respond to all ne - [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) - [Best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) - [Documentation portal](https://wp-cli.org/docs/) +- [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) +- [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). From ab22ff0a721b96ff0683c6606e831f23b0db0249 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 07:43:39 -0700 Subject: [PATCH 4626/5359] Add Is it maintained? chicklets to README.md Fixes #2996 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5613e0ba..4349354b2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ WP-CLI To stay up to date, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") <div style=" border: 1px solid #7AD03A; From 655bc75cda9d0aa7a9d5fc0801d9fecc07352343 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Mon, 27 Jun 2016 20:57:09 +0545 Subject: [PATCH 4627/5359] Add count value for format in cron event list command --- php/commands/cron.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/cron.php b/php/commands/cron.php index d910434dc..f24587045 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -56,6 +56,7 @@ class Cron_Event_Command extends WP_CLI_Command { * - csv * - ids * - json + * - count * - yaml * --- * From 9e82c3c556023a46fb1fce015e5c694129b32c9c Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Mon, 27 Jun 2016 18:22:00 +0200 Subject: [PATCH 4628/5359] Add a test for the recently active plugin list. --- features/plugin.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index ff89ccb2e..21efa3181 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -73,6 +73,12 @@ Feature: Manage WordPress plugins When I run `wp plugin deactivate Zombieland` Then STDOUT should not be empty + When I run `wp option get recently_activated` + Then STDOUT should contain: + """ + Zombieland/Zombieland.php + """ + When I run `wp plugin uninstall Zombieland` Then STDOUT should contain: """ From fc95dabb413e26a134decca0e66c58d754d882ce Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 09:39:26 -0700 Subject: [PATCH 4629/5359] First pass at alias groups Given a `wp-cli.local.yml`: ``` @both: - @prod - @dev @prod: ssh: rc~/webapps/production @dev: ssh: v/srv/www/runcommand.dev ``` One can: ``` $ wp @both rewrite flush Success: Rewrite rules flushed. Success: Rewrite rules flushed. ``` --- features/aliases.feature | 44 +++++++++++++++++++++++++++++++++++++ php/WP_CLI/Configurator.php | 15 ++++++++++++- php/WP_CLI/Runner.php | 41 ++++++++++++++++++++++++++++++---- 3 files changed, 95 insertions(+), 5 deletions(-) diff --git a/features/aliases.feature b/features/aliases.feature index eb17625f6..1985a977d 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -120,3 +120,47 @@ Feature: Create shortcuts to specific WordPress installs """ Error: This does not seem to be a WordPress install. """ + + Scenario: Use a group of aliases to run a command against multiple installs + Given a WP install in 'subdir1' + And a WP install in 'subdir2' + And a wp-cli.yml file: + """ + @both: + - @subdir1 + - @subdir2 + @invalid: + - @subdir1 + - @subdir3 + @subdir1: + path: subdir1 + @subdir2: + path: subdir2 + """ + + When I run `wp @subdir1 option update home 'http://apple.com'` + And I run `wp @subdir1 option get home` + Then STDOUT should contain: + """ + http://apple.com + """ + + When I run `wp @subdir2 option update home 'http://google.com'` + And I run `wp @subdir2 option get home` + Then STDOUT should contain: + """ + http://google.com + """ + + When I try `wp @invalid option get home` + Then STDERR should be: + """ + Error: Group '@invalid' contains one or more invalid aliases: @subdir3 + """ + + When I run `wp @both option get home` + Then STDOUT should be: + """ + http://apple.com + http://google.com + """ diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index d9cb9789a..35063c2c8 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -155,9 +155,11 @@ public function merge_yml( $path ) { if ( ! empty( $yaml['_']['inherit'] ) ) { $this->merge_yml( $yaml['_']['inherit'] ); } + $alias_regex = '#^@[A-Za-z0-9-_]+$#'; foreach ( $yaml as $key => $value ) { - if ( preg_match( '#@[A-Za-z0-9-_]+#', $key ) ) { + if ( preg_match( $alias_regex, $key ) ) { $this->aliases[ $key ] = array(); + $is_alias = false; foreach( array( 'user', 'url', @@ -166,8 +168,19 @@ public function merge_yml( $path ) { ) as $i ) { if ( isset( $value[ $i ] ) ) { $this->aliases[ $key ][ $i ] = $value[ $i ]; + $is_alias = true; } } + // If it's not an alias, it might be a group of aliases + if ( ! $is_alias && is_array( $value ) ) { + $alias_group = array(); + foreach( $value as $i => $k ) { + if ( preg_match( $alias_regex, $k ) ) { + $alias_group[] = $k; + } + } + $this->aliases[ $key ] = $alias_group; + } } elseif ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { if ( isset( $this->extra_config[ $key ] ) && ! empty( $yaml['_']['merge'] ) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 08f9555f8..93763d939 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -657,10 +657,29 @@ private function check_root() { ); } - private function set_alias( $alias ) { - if ( ! array_key_exists( $alias, $this->aliases ) ) { - WP_CLI::error( "Alias '{$alias}' not found." ); + private function run_alias_group( $aliases ) { + $php_bin = WP_CLI::get_php_binary(); + + $script_path = $GLOBALS['argv'][0]; + + if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { + $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); + } else { + $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; } + $config_path = escapeshellarg( $config_path ); + + foreach( $aliases as $alias ) { + + $args = implode( ' ', array_map( 'escapeshellarg', $this->arguments ) ); + $assoc_args = Utils\assoc_args_to_str( $this->assoc_args ); + + $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$alias} {$args} {$assoc_args}"; + passthru( $full_command ); + } + } + + private function set_alias( $alias ) { $orig_config = $this->config; $alias_config = $this->aliases[ $this->alias ]; $this->config = array_merge( $orig_config, $alias_config ); @@ -681,7 +700,21 @@ public function start() { $this->check_root(); if ( $this->alias ) { - $this->set_alias( $this->alias ); + if ( ! array_key_exists( $this->alias, $this->aliases ) ) { + WP_CLI::error( "Alias '{$alias}' not found." ); + } + // Numerically indexed means a group of aliases + if ( isset( $this->aliases[ $this->alias ][0] ) ) { + $group_aliases = $this->aliases[ $this->alias ]; + $all_aliases = array_keys( $this->aliases ); + if ( $diff = array_diff( $group_aliases, $all_aliases ) ) { + WP_CLI::error( "Group '{$this->alias}' contains one or more invalid aliases: " . implode( ', ', $diff ) ); + } + $this->run_alias_group( $group_aliases ); + exit; + } else { + $this->set_alias( $this->alias ); + } } if ( empty( $this->arguments ) ) From 5198fd20c81905240153d56d3897361d508050a2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 27 Jun 2016 09:43:25 -0700 Subject: [PATCH 4630/5359] Fix failing test by using a valid variable --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 93763d939..4499b17d1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -701,7 +701,7 @@ public function start() { $this->check_root(); if ( $this->alias ) { if ( ! array_key_exists( $this->alias, $this->aliases ) ) { - WP_CLI::error( "Alias '{$alias}' not found." ); + WP_CLI::error( "Alias '{$this->alias}' not found." ); } // Numerically indexed means a group of aliases if ( isset( $this->aliases[ $this->alias ][0] ) ) { From 87b73575745167422e0e0895df07ad92af344384 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 28 Jun 2016 14:44:16 +0545 Subject: [PATCH 4631/5359] Add ids for format parameter in sidebar list --- php/commands/sidebar.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php index 874507396..19773c38a 100644 --- a/php/commands/sidebar.php +++ b/php/commands/sidebar.php @@ -35,6 +35,7 @@ class Sidebar_Command extends WP_CLI_Command { * - table * - csv * - json + * - ids * - count * - yaml * --- @@ -69,8 +70,15 @@ public function list_( $args, $assoc_args ) { \WP_CLI\Utils\wp_register_unused_sidebar(); + if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { + $sidebars = wp_list_pluck( $wp_registered_sidebars, 'id' ); + } + else { + $sidebars = $wp_registered_sidebars; + } + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $wp_registered_sidebars ); + $formatter->display_items( $sidebars ); } } From 7e12aba6f1d5976d5b1a14b0ba1f57e7ea9e2808 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 28 Jun 2016 14:53:58 +0545 Subject: [PATCH 4632/5359] Add test for ids in param in sidebar list command --- features/sidebar.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/sidebar.feature b/features/sidebar.feature index 1126cfa98..cf53186c5 100644 --- a/features/sidebar.feature +++ b/features/sidebar.feature @@ -10,3 +10,15 @@ Feature: Manage WordPress sidebars Then STDOUT should be a table containing rows: | name | id | | Sidebar | sidebar-1 | + + When I run `wp sidebar list --format=ids` + Then STDOUT should be: + """ + sidebar-1 wp_inactive_widgets + """ + + When I run `wp sidebar list --format=count` + Then STDOUT should be: + """ + 2 + """ From 27d6fee17d0e0685f19a3792f5acb7aba82340f9 Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Tue, 28 Jun 2016 21:10:27 +0200 Subject: [PATCH 4633/5359] Fix exception in menu list command if the format is ids #3074 The formatter could not iterate trough the WP_Term object. Now it the format is 'ids' all term_ids getting grabbed from the array and imploded in the display_items method --- php/commands/menu.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 5517d374a..8e8a1eee2 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -177,14 +177,19 @@ public function list_( $_, $assoc_args ) { } // Normalize the data for some output formats. - if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { + if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table') ) ) { $menu->locations = implode( ',', $menu->locations ); } } $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $menus ); + if ( 'ids' == $formatter->format ) { + $ids = array_column( $menus, 'term_id' ); + $formatter->display_items( $ids ); + } else { + $formatter->display_items( $menus ); + } } protected function get_formatter( &$assoc_args ) { From 7005f83929538fae33c29de104f3c886f800dade Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Tue, 28 Jun 2016 21:22:10 +0200 Subject: [PATCH 4634/5359] Fix formatting Add whitespace to match coding style --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 8e8a1eee2..d6744b37d 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -177,7 +177,7 @@ public function list_( $_, $assoc_args ) { } // Normalize the data for some output formats. - if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table') ) ) { + if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { $menu->locations = implode( ',', $menu->locations ); } } From 8a99f5558c6db2fdce9858abc34424aff4539cd3 Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Tue, 28 Jun 2016 21:51:40 +0200 Subject: [PATCH 4635/5359] Add feature test for wp menu item list with format ids --- features/menu.feature | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 194829d17..d75af3725 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -33,6 +33,13 @@ Feature: Manage WordPress menus 0 """ + When I run `wp menu create "First Menu"` + And I run `wp menu list --format=ids` + Then STDOUT should be: + """ + 5 + """ + Scenario: Assign / remove location from a menu When I run `wp theme install p2 --activate` From 7388bf543de5fc4ff6fec6af9ff9b6cf9d8dcce5 Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Tue, 28 Jun 2016 23:45:40 +0200 Subject: [PATCH 4636/5359] Change array_column to array_map method because of compatibility array_column() only accepts an array of objects since php 7.0 For compatibility reasons with lower php versions, used array_map instead --- php/commands/menu.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index d6744b37d..2ee952736 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -185,7 +185,11 @@ public function list_( $_, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); if ( 'ids' == $formatter->format ) { - $ids = array_column( $menus, 'term_id' ); + $ids = array_map( + function($o) { + return $o->term_id; + }, $menus + ); $formatter->display_items( $ids ); } else { $formatter->display_items( $menus ); From 452accdbbeda1faf1d4e1986e14e2af1b3577599 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 28 Jun 2016 17:07:27 -0700 Subject: [PATCH 4637/5359] Fix builds on WordPress trunk Mr WordPress is now some wapuu business --- features/comment.feature | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 0eaacc004..ad004d4b1 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -71,19 +71,19 @@ Feature: Manage WordPress comments Scenario: Get details about an existing comment When I run `wp comment get 1` Then STDOUT should be a table containing rows: - | Field | Value | - | comment_author | Mr WordPress | + | Field | Value | + | comment_author_url | https://wordpress.org/ | - When I run `wp comment get 1 --fields=comment_author,comment_author_email --format=json` - Then STDOUT should be: + When I run `wp comment get 1 --fields=comment_author_url,comment_author_email --format=json` + Then STDOUT should be JSON containing: """ - {"comment_author":"Mr WordPress","comment_author_email":""} + {"comment_author_url":"https://wordpress.org/","comment_author_email":""} """ - When I run `wp comment list --fields=comment_approved,comment_author` + When I run `wp comment list --fields=comment_approved,comment_author_url` Then STDOUT should be a table containing rows: - | comment_approved | comment_author | - | 1 | Mr WordPress | + | comment_approved | comment_author_url | + | 1 | https://wordpress.org/ | When I run `wp comment list --field=approved` Then STDOUT should be: From b6e4a62d889d9a9f1615d0529ed3d8ad99902180 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 13:40:13 +0545 Subject: [PATCH 4638/5359] Add reset subcommand for widget --- php/commands/widget.php | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/php/commands/widget.php b/php/commands/widget.php index 2ff89be75..0a412e18e 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -304,6 +304,75 @@ public function delete( $args, $assoc_args ) { WP_CLI::success( "Widget(s) removed from sidebar." ); } + /** + * Reset sidebar. + * + * Removes all widgets from the sidebar and place those to Inactive Widgets. + * + * [<sidebar-id>...] + * : One or more sidebars to reset. + * + * [--all] + * : If set, all sidebars will be reset. + * + * ## EXAMPLES + * + * # Reset a sidebar + * $ wp widget reset sidebar-1 + * Success: Sidebar 'sidebar-1' reset. + * + * # Reset multiple sidebars + * $ wp widget reset sidebar-1 sidebar-2 + * Success: Sidebar 'sidebar-1' reset. + * Success: Sidebar 'sidebar-2' reset. + */ + public function reset( $args, $assoc_args ) { + + global $wp_registered_sidebars; + + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); + + // Bail if no arguments and no all flag. + if ( ! $all && empty( $args ) ) { + WP_CLI::error( 'Please specify one or more sidebars, or use --all.' ); + } + + // Fetch all sidebars if all flag is set. + if ( $all ) { + $args = array_keys( $wp_registered_sidebars ); + } + + // Sidebar ID wp_inactive_widgets is reserved by WP core for inactive widgets. + if ( isset( $args['wp_inactive_widgets'] ) ) { + unset( $args['wp_inactive_widgets'] ); + } + + // Check if no registered sidebar. + if ( empty( $args ) ) { + WP_CLI::error( 'No sidebar registered.' ); + } + + foreach ( $args as $sidebar_id ) { + if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { + WP_CLI::warning( sprintf( 'Invalid sidebar: %s', $sidebar_id ) ); + continue; + } + + $widgets = $this->get_sidebar_widgets( $sidebar_id ); + if ( empty( $widgets ) ) { + WP_CLI::warning( sprintf( "'%s' is already empty.", $sidebar_id ) ); + } + else { + foreach ( $widgets as $widget ) { + $widget_id = $widget->id; + list( $name, $option_index, $new_sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); + $this->move_sidebar_widget( $widget_id, $new_sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); + } + WP_CLI::success( sprintf( "Sidebar '%s' reset.", $sidebar_id ) ); + } + } + } + /** * Check whether a sidebar is a valid sidebar * From c7567036d779b36df5111feb5491ed99a25035e6 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 14:05:17 +0545 Subject: [PATCH 4639/5359] Add test for widget reset command --- features/widget-reset.feature | 96 +++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 features/widget-reset.feature diff --git a/features/widget-reset.feature b/features/widget-reset.feature new file mode 100644 index 000000000..52a042961 --- /dev/null +++ b/features/widget-reset.feature @@ -0,0 +1,96 @@ +Feature: Reset widgets in WordPress sidebar + + Scenario: Reset sidebar + Given a WP install + + When I run `wp theme install twentysixteen --activate` + Then STDOUT should not be empty + + When I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + 6 + """ + + When I run `wp widget reset sidebar-1` + And I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I try `wp widget reset` + Then STDERR should be: + """ + Error: Please specify one or more sidebars, or use --all. + """ + + When I try `wp widget reset sidebar-1` + Then STDERR should be: + """ + Warning: 'sidebar-1' is already empty. + """ + + When I try `wp widget reset non-existing-sidebar-id` + Then STDERR should be: + """ + Warning: Invalid sidebar: non-existing-sidebar-id + """ + + When I run `wp widget add calendar sidebar-1 --title="Calendar"` + Then STDOUT should not be empty + And I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp widget add search sidebar-2 --title="Quick Search"` + Then STDOUT should not be empty + And I run `wp widget list sidebar-2 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp widget reset sidebar-1 sidebar-2` + And I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + 0 + """ + And I run `wp widget list sidebar-2 --format=count` + Then STDOUT should be: + """ + 0 + """ + + Scenario: Reset all sidebars + Given a WP install + + When I run `wp theme install twentysixteen --activate` + Then STDOUT should not be empty + + When I run `wp widget add calendar sidebar-1 --title="Calendar"` + Then STDOUT should not be empty + When I run `wp widget add search sidebar-2 --title="Quick Search"` + Then STDOUT should not be empty + When I run `wp widget add text sidebar-3 --title="Text"` + Then STDOUT should not be empty + + When I run `wp widget reset --all` + And I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + 0 + """ + And I run `wp widget list sidebar-2 --format=count` + Then STDOUT should be: + """ + 0 + """ + And I run `wp widget list sidebar-3 --format=count` + Then STDOUT should be: + """ + 0 + """ From 6e886da6eaa44d24a7ae08d26cec5c48afe9e50b Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 14:08:32 +0545 Subject: [PATCH 4640/5359] Add more examples for the command --- features/widget-reset.feature | 2 +- php/commands/widget.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 52a042961..2a9861175 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -1,4 +1,4 @@ -Feature: Reset widgets in WordPress sidebar +Feature: Reset WordPress sidebars Scenario: Reset sidebar Given a WP install diff --git a/php/commands/widget.php b/php/commands/widget.php index 0a412e18e..f401eaea0 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -325,6 +325,12 @@ public function delete( $args, $assoc_args ) { * $ wp widget reset sidebar-1 sidebar-2 * Success: Sidebar 'sidebar-1' reset. * Success: Sidebar 'sidebar-2' reset. + * + * # Reset all sidebars + * $ wp widget reset --all + * Success: Sidebar 'sidebar-1' reset. + * Success: Sidebar 'sidebar-2' reset. + * Success: Sidebar 'sidebar-3' reset. */ public function reset( $args, $assoc_args ) { From 7cfa5f056d6dc0e0e4ffa365798f8dd721134523 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 14:36:33 +0545 Subject: [PATCH 4641/5359] Improve test for widget reset --- features/widget-reset.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 2a9861175..83ddf39d5 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -94,3 +94,31 @@ Feature: Reset WordPress sidebars """ 0 """ + + Scenario: Testing movement of widgets while reset + Given a WP install + + When I run `wp theme install twentysixteen --activate` + Then STDOUT should not be empty + + When I run `wp widget add calendar sidebar-2 --title="Calendar"` + Then STDOUT should not be empty + And I run `wp widget add search sidebar-2 --title="Quick Search"` + Then STDOUT should not be empty + + When I run `wp widget list sidebar-2 --format=ids` + Then STDOUT should be: + """ + search-3 calendar-1 + """ + When I run `wp widget list wp_inactive_widgets --format=ids` + Then STDOUT should be empty + + When I run `wp widget reset sidebar-2` + And I run `wp widget list sidebar-2 --format=ids` + Then STDOUT should be empty + And I run `wp widget list wp_inactive_widgets --format=ids` + Then STDOUT should be: + """ + calendar-1 search-3 + """ From 703f64bb95258809c1072e73973b4feff7651e28 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 29 Jun 2016 03:20:05 -0700 Subject: [PATCH 4642/5359] Fix tests on all versions of WordPress by limiting the values tested Unfortunately, none of these are the same between WP versions --- features/comment.feature | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index ad004d4b1..62ca6cd24 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -71,19 +71,19 @@ Feature: Manage WordPress comments Scenario: Get details about an existing comment When I run `wp comment get 1` Then STDOUT should be a table containing rows: - | Field | Value | - | comment_author_url | https://wordpress.org/ | + | Field | Value | + | comment_approved | 1 | - When I run `wp comment get 1 --fields=comment_author_url,comment_author_email --format=json` + When I run `wp comment get 1 --fields=comment_approved,comment_author_email --format=json` Then STDOUT should be JSON containing: """ - {"comment_author_url":"https://wordpress.org/","comment_author_email":""} + {"comment_approved":"1","comment_author_email":""} """ - When I run `wp comment list --fields=comment_approved,comment_author_url` + When I run `wp comment list --fields=comment_approved` Then STDOUT should be a table containing rows: - | comment_approved | comment_author_url | - | 1 | https://wordpress.org/ | + | comment_approved | + | 1 | When I run `wp comment list --field=approved` Then STDOUT should be: From e93078e4bfa47b091315635148dd0f76d441cf93 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 16:38:34 +0545 Subject: [PATCH 4643/5359] Resolving issues from the PR review in widget reset --- features/widget-reset.feature | 7 ++++++- php/commands/widget.php | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 83ddf39d5..482bafd5a 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -28,7 +28,7 @@ Feature: Reset WordPress sidebars When I try `wp widget reset sidebar-1` Then STDERR should be: """ - Warning: 'sidebar-1' is already empty. + Warning: Sidebar 'sidebar-1' is already empty. """ When I try `wp widget reset non-existing-sidebar-id` @@ -94,6 +94,11 @@ Feature: Reset WordPress sidebars """ 0 """ + When I run `wp widget list wp_inactive_widgets --format=ids` + Then STDOUT should be: + """ + text-1 search-3 meta-2 categories-2 archives-2 recent-comments-2 recent-posts-2 search-2 calendar-1 + """ Scenario: Testing movement of widgets while reset Given a WP install diff --git a/php/commands/widget.php b/php/commands/widget.php index f401eaea0..1def3cb79 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -307,7 +307,7 @@ public function delete( $args, $assoc_args ) { /** * Reset sidebar. * - * Removes all widgets from the sidebar and place those to Inactive Widgets. + * Removes all widgets from the sidebar and places them in Inactive Widgets. * * [<sidebar-id>...] * : One or more sidebars to reset. @@ -366,7 +366,7 @@ public function reset( $args, $assoc_args ) { $widgets = $this->get_sidebar_widgets( $sidebar_id ); if ( empty( $widgets ) ) { - WP_CLI::warning( sprintf( "'%s' is already empty.", $sidebar_id ) ); + WP_CLI::warning( sprintf( "Sidebar '%s' is already empty.", $sidebar_id ) ); } else { foreach ( $widgets as $widget ) { From ff354272a5a938e58ad90334abd9792da2084c7d Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 29 Jun 2016 17:28:36 +0545 Subject: [PATCH 4644/5359] Use Twentytwelve theme in test of widget reset because 2016 wont run in WP 3.7 --- features/widget-reset.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 482bafd5a..4c2d84bdc 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -3,7 +3,7 @@ Feature: Reset WordPress sidebars Scenario: Reset sidebar Given a WP install - When I run `wp theme install twentysixteen --activate` + When I run `wp theme install twentytwelve --activate` Then STDOUT should not be empty When I run `wp widget list sidebar-1 --format=count` @@ -68,7 +68,7 @@ Feature: Reset WordPress sidebars Scenario: Reset all sidebars Given a WP install - When I run `wp theme install twentysixteen --activate` + When I run `wp theme install twentytwelve --activate` Then STDOUT should not be empty When I run `wp widget add calendar sidebar-1 --title="Calendar"` @@ -103,7 +103,7 @@ Feature: Reset WordPress sidebars Scenario: Testing movement of widgets while reset Given a WP install - When I run `wp theme install twentysixteen --activate` + When I run `wp theme install twentytwelve --activate` Then STDOUT should not be empty When I run `wp widget add calendar sidebar-2 --title="Calendar"` From 6b54065a43b6a1f5950df656a026264553937bcc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 29 Jun 2016 05:07:03 -0700 Subject: [PATCH 4645/5359] This email changed in 4.6 too, so lets ignore it --- features/comment.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 62ca6cd24..6fcbd88d4 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -74,10 +74,10 @@ Feature: Manage WordPress comments | Field | Value | | comment_approved | 1 | - When I run `wp comment get 1 --fields=comment_approved,comment_author_email --format=json` + When I run `wp comment get 1 --fields=comment_approved --format=json` Then STDOUT should be JSON containing: """ - {"comment_approved":"1","comment_author_email":""} + {"comment_approved":"1"} """ When I run `wp comment list --fields=comment_approved` From 4a4c0c724b3bf26e16689d08ec0564507845c13f Mon Sep 17 00:00:00 2001 From: roelveldhuizen <roel@inesta.nl> Date: Wed, 29 Jun 2016 17:38:37 +0200 Subject: [PATCH 4646/5359] #3069 resolve --- php/commands/plugin.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index d27ae8ba9..cd64229fb 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -335,6 +335,12 @@ function deactivate( $args, $assoc_args = array() ) { deactivate_plugins( $plugin->file, false, $network_wide ); + if (!is_network_admin()) { + update_option('recently_activated', array($plugin->file => time()) + (array)get_option('recently_activated')); + } else { + update_site_option('recently_activated', array($plugin->file => time()) + (array)get_site_option('recently_activated')); + } + $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uninstall' ) ) { From d8fee49e62593768eb8bbdf999f1c41086a4d10e Mon Sep 17 00:00:00 2001 From: Roel Veldhuizen <roel@inesta.nl> Date: Wed, 29 Jun 2016 21:35:26 +0200 Subject: [PATCH 4647/5359] updated CS --- php/commands/plugin.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index cd64229fb..7470ac7a8 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -335,10 +335,12 @@ function deactivate( $args, $assoc_args = array() ) { deactivate_plugins( $plugin->file, false, $network_wide ); - if (!is_network_admin()) { - update_option('recently_activated', array($plugin->file => time()) + (array)get_option('recently_activated')); + if ( ! is_network_admin() ) { + update_option('recently_activated', + array($plugin->file => time()) + (array)get_option('recently_activated')); } else { - update_site_option('recently_activated', array($plugin->file => time()) + (array)get_site_option('recently_activated')); + update_site_option('recently_activated', + array($plugin->file => time()) + (array)get_site_option('recently_activated')); } $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); From 61eab12d4de5e056c36320d2f117d6fc11d39836 Mon Sep 17 00:00:00 2001 From: Roel Veldhuizen <roel@inesta.nl> Date: Wed, 29 Jun 2016 21:37:02 +0200 Subject: [PATCH 4648/5359] updated CS --- php/commands/plugin.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 7470ac7a8..701a910a0 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -336,11 +336,11 @@ function deactivate( $args, $assoc_args = array() ) { deactivate_plugins( $plugin->file, false, $network_wide ); if ( ! is_network_admin() ) { - update_option('recently_activated', - array($plugin->file => time()) + (array)get_option('recently_activated')); + update_option( 'recently_activated', + array( $plugin->file => time() ) + (array) get_option('recently_activated') ); } else { - update_site_option('recently_activated', - array($plugin->file => time()) + (array)get_site_option('recently_activated')); + update_site_option( 'recently_activated', + array( $plugin->file => time() ) + (array) get_site_option('recently_activated') ); } $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); From 5834bac3b25fe1f88de9e7926bb137139e714b7c Mon Sep 17 00:00:00 2001 From: Roel Veldhuizen <roel@inesta.nl> Date: Wed, 29 Jun 2016 22:01:11 +0200 Subject: [PATCH 4649/5359] updated CS --- php/commands/plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 701a910a0..608c26129 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -337,10 +337,10 @@ function deactivate( $args, $assoc_args = array() ) { if ( ! is_network_admin() ) { update_option( 'recently_activated', - array( $plugin->file => time() ) + (array) get_option('recently_activated') ); + array( $plugin->file => time() ) + (array) get_option( 'recently_activated' ) ); } else { update_site_option( 'recently_activated', - array( $plugin->file => time() ) + (array) get_site_option('recently_activated') ); + array( $plugin->file => time() ) + (array) get_site_option( 'recently_activated' ) ); } $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); From 81b3ab60423f4ed81178cddaa354c8af45d722ff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 29 Jun 2016 16:14:09 -0700 Subject: [PATCH 4650/5359] Mention `wp cli update --nightly` in INSTALLING section --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4349354b2..1be31ccdd 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,8 @@ WP-CLI version: 0.23.0 You can update WP-CLI with `wp cli update` ([doc](https://wp-cli.org/commands/cli/update/)), or by repeating the installation steps. +Want to live life on the edge? Run `wp cli update --nightly` to use the latest nightly build of WP-CLI. The nightly build is more or less stable enough for you to use in your development environment, and always includes the latest and greatest WP-CLI features. + ## Support WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: From 982fd5438fe569a07d1c239400e00a3fedae1e60 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 29 Jun 2016 16:33:53 -0700 Subject: [PATCH 4651/5359] Mention internal API docs in extending See https://github.com/Nikschavan/revslider-search-replace/issues/2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1be31ccdd..993bc8d74 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ If you have a WordPress.org account, you may also consider joining the `#cli` ch A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. -WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. +WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](http://wp-cli.org/docs/internal-api/) to discovery a variety of helpful functions you can use in your custom WP-CLI command. ## Contributing From 9206d222312d4a6974698d83767aaa77bdf67d2c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 30 Jun 2016 04:42:00 -0700 Subject: [PATCH 4652/5359] Fix indentation on the test --- features/plugin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 21efa3181..1bbecf2bd 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -76,7 +76,7 @@ Feature: Manage WordPress plugins When I run `wp option get recently_activated` Then STDOUT should contain: """ - Zombieland/Zombieland.php + Zombieland/Zombieland.php """ When I run `wp plugin uninstall Zombieland` From c4ecf7297f4cb3c5c27e4f062e099628f3c26f82 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 30 Jun 2016 17:29:40 +0545 Subject: [PATCH 4653/5359] Improve doc and message in site commands --- php/commands/site.php | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index d2971c588..fd553e66f 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -16,8 +16,8 @@ * * # Delete site * $ wp site delete 123 - * Are you sure you want to delete the http://www.example.com/example site? [y/n] y - * Success: The site at http://www.example.com/example was deleted. + * Are you sure you want to delete the 'http://www.example.com/example' site? [y/n] y + * Success: The site at 'http://www.example.com/example' was deleted. * * @package wp-cli */ @@ -163,7 +163,7 @@ private function _insert_default_terms() { * * $ wp site empty * Are you sure you want to empty the site at http://www.example.com of all posts, comments, and terms? [y/n] y - * Success: The site at http://www.example.com was emptied. + * Success: The site at 'http://www.example.com' was emptied. * * @subcommand empty */ @@ -174,7 +174,7 @@ public function _empty( $args, $assoc_args ) { $upload_message = ', and delete its uploads directory'; } - WP_CLI::confirm( 'Are you sure you want to empty the site at ' . site_url() . ' of all posts, comments, and terms' . $upload_message . '?', $assoc_args ); + WP_CLI::confirm( "Are you sure you want to empty the site at '" . site_url() . "' of all posts, comments, and terms" . $upload_message . "?", $assoc_args ); $this->_empty_posts(); $this->_empty_comments(); @@ -200,7 +200,7 @@ public function _empty( $args, $assoc_args ) { rmdir( $upload_dir['basedir'] ); } - WP_CLI::success( 'The site at ' . site_url() . ' was emptied.' ); + WP_CLI::success( "The site at '" . site_url() . "' was emptied." ); } /** @@ -224,7 +224,7 @@ public function _empty( $args, $assoc_args ) { * * $ wp site delete 123 * Are you sure you want to delete the http://www.example.com/example site? [y/n] y - * Success: The site at http://www.example.com/example was deleted. + * Success: The site at 'http://www.example.com/example' was deleted. */ function delete( $args, $assoc_args ) { if ( !is_multisite() ) { @@ -247,11 +247,11 @@ function delete( $args, $assoc_args ) { WP_CLI::error( "Site not found." ); } - WP_CLI::confirm( "Are you sure you want to delete the $blog->siteurl site?", $assoc_args ); + WP_CLI::confirm( "Are you sure you want to delete the '$blog->siteurl' site?", $assoc_args ); wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'keep-tables' ) ); - WP_CLI::success( "The site at $blog->siteurl was deleted." ); + WP_CLI::success( "The site at '$blog->siteurl' was deleted." ); } /** @@ -420,7 +420,16 @@ private function _get_network( $network_id ) { * : Comma-separated list of fields to show. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - count + * - json + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -645,4 +654,3 @@ private function update_site_status( $ids, $pref, $value ) { } WP_CLI::add_command( 'site', 'Site_Command' ); - From cbc1e9cb4916bfb602b59226113416b862076156 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 30 Jun 2016 05:19:44 -0700 Subject: [PATCH 4654/5359] Ignore a few more files in the default `.distignore` --- templates/plugin-distignore.mustache | 4 ++++ templates/plugin-gitignore.mustache | 1 + 2 files changed, 5 insertions(+) diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache index 36a11a63f..79706582a 100644 --- a/templates/plugin-distignore.mustache +++ b/templates/plugin-distignore.mustache @@ -4,13 +4,17 @@ .git .gitignore .travis.yml +.DS_Store +Thumbs.db bin composer.json composer.lock Gruntfile.js package.json phpunit.xml +multisite.xml phpunit.xml.dist +phpcs.ruleset.xml README.md wp-cli.local.yml tests diff --git a/templates/plugin-gitignore.mustache b/templates/plugin-gitignore.mustache index d4a540553..20830a4a0 100644 --- a/templates/plugin-gitignore.mustache +++ b/templates/plugin-gitignore.mustache @@ -1,3 +1,4 @@ .DS_Store +Thumbs.db wp-cli.local.yml node_modules/ From 8dd9dcf07e36eae6b576908bd577224425545dcf Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 30 Jun 2016 21:24:12 +0900 Subject: [PATCH 4655/5359] fix missing param in example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 993bc8d74..27a62664d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Quick links: [Using](#using) | [Installing](#installing) | [Support](# ## Using -WP-CLI's goal is to provide a command-line interface for any action you might want to perform in the WordPress admin. For instance, `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: +WP-CLI's goal is to provide a command-line interface for any action you might want to perform in the WordPress admin. For instance, `wp plugin install --activate` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: ``` $ wp plugin install rest-api --activate From ebc763e52beb2062d92202f4fa37149b8f55c72d Mon Sep 17 00:00:00 2001 From: Rachel Baker <rachel@rachelbaker.me> Date: Thu, 30 Jun 2016 22:24:59 -0500 Subject: [PATCH 4656/5359] Update cli settings to include new files from WP 4.6 beta. Includes class-wp-network-query.php and class-wp-post-type.php files conditionally. --- php/wp-settings-cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php index 1554221a8..ab284d58b 100644 --- a/php/wp-settings-cli.php +++ b/php/wp-settings-cli.php @@ -141,6 +141,7 @@ // Initialize multisite if enabled. if ( is_multisite() ) { Utils\maybe_require( '4.6-alpha-37575', ABSPATH . WPINC . '/class-wp-site-query.php' ); + Utils\maybe_require( '4.6-alpha-37896', ABSPATH . WPINC . '/class-wp-network-query.php' ); require( ABSPATH . WPINC . '/ms-blogs.php' ); require( ABSPATH . WPINC . '/ms-settings.php' ); } elseif ( ! defined( 'MULTISITE' ) ) { @@ -187,6 +188,7 @@ require( ABSPATH . WPINC . '/post.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page-dropdown.php' ); +Utils\maybe_require( '4.6-alpha-37890', ABSPATH . WPINC . '/class-wp-post-type.php' ); Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-post.php' ); require( ABSPATH . WPINC . '/post-template.php' ); Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/revision.php' ); From 9f37cd366d2c018bcc4c8b86788a55cb3f27891f Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 1 Jul 2016 09:48:30 +0545 Subject: [PATCH 4657/5359] Fix grammar in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27a62664d..f895828c8 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ If you have a WordPress.org account, you may also consider joining the `#cli` ch A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. -WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](http://wp-cli.org/docs/internal-api/) to discovery a variety of helpful functions you can use in your custom WP-CLI command. +WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](http://wp-cli.org/docs/internal-api/) to discover a variety of helpful functions you can use in your custom WP-CLI command. ## Contributing From b6fb9f35b08bf40a72cb06f7ccf043b3cfd81fd2 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 1 Jul 2016 13:14:18 +0545 Subject: [PATCH 4658/5359] Improving test for site commands --- features/site-empty.feature | 20 ++++++++++++++++---- features/site.feature | 23 ++++++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/features/site-empty.feature b/features/site-empty.feature index 873dfdb22..2f5e49b80 100644 --- a/features/site-empty.feature +++ b/features/site-empty.feature @@ -17,13 +17,22 @@ Feature: Empty a WordPress site of its data """ When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` - Then STDOUT should not be empty + Then STDOUT should be: + """ + 4 + """ When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term'` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Created post_tag 2. + """ When I run `wp site empty --yes` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: The site at 'http://example.com' was emptied. + """ And the wp-content/uploads/large-image.jpg file should exist When I run `wp post list --format=ids` @@ -51,7 +60,10 @@ Feature: Empty a WordPress site of its data Then STDOUT should be empty When I run `wp --url=example.com/foo site empty --uploads --yes` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: The site at 'http://example.com/foo' was emptied. + """ And the wp-content/uploads/sites/2/large-image.jpg file should not exist When I run `wp --url=example.com/foo post list --format=ids` diff --git a/features/site.feature b/features/site.feature index 42c29ab52..46f5d9fa6 100644 --- a/features/site.feature +++ b/features/site.feature @@ -2,7 +2,7 @@ Feature: Manage sites in a multisite installation Scenario: Create a site Given a WP multisite install - + When I try `wp site create --slug=first --network_id=1000` Then STDERR should contain: """ @@ -48,7 +48,10 @@ Feature: Manage sites in a multisite installation """ When I run `wp site delete {SITE_ID} --yes` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: The site at 'http://example.com/first' was deleted. + """ When I try the previous command again Then the return code should be 1 @@ -76,21 +79,27 @@ Feature: Manage sites in a multisite installation Given a WP multisite install When I run `wp site create --slug=first` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: Site 2 created: example.com/first/ + """ When I run `wp site delete --slug=first --yes` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: The site at 'http://example.com/first' was deleted. + """ When I try the previous command again Then the return code should be 1 Scenario: Get site info Given a WP multisite install - + When I run `wp site create --slug=first --porcelain` Then STDOUT should be a number And save STDOUT as {SITE_ID} - + When I run `wp site url {SITE_ID}` Then STDOUT should be: """ @@ -152,7 +161,7 @@ Feature: Manage sites in a multisite installation | blog_id | archived | | {FIRST_SITE} | 0 | - When I run `wp site archive 1` + When I try `wp site archive 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. From 8ad8999af5fd6ba3617619d3406dd3ebe69f35c2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Jul 2016 03:49:59 -0700 Subject: [PATCH 4659/5359] Update tests for cbc1e9cb4916bfb602b59226113416b862076156 --- features/scaffold.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 48409fb28..733841eef 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -155,6 +155,7 @@ Feature: WordPress code scaffolding And the {PLUGIN_DIR}/hello-world/.gitignore file should contain: """ .DS_Store + Thumbs.db wp-cli.local.yml node_modules/ """ From 7cbdcd5f99195bbb0d32abad55f7b8c10892ac4d Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 1 Jul 2016 17:40:07 +0545 Subject: [PATCH 4660/5359] Allow ids value in format parameter in site list --- php/commands/site.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index fd553e66f..2ad634bfd 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -427,6 +427,7 @@ private function _get_network( $network_id ) { * - table * - csv * - count + * - ids * - json * - yaml * --- @@ -509,8 +510,16 @@ public function list_( $_, $assoc_args ) { return $blog; } ); - $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); - $formatter->display_items( $it ); + if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { + $sites = iterator_to_array( $it ); + $ids = wp_list_pluck( $sites, 'blog_id' ); + $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); + $formatter->display_items( $ids ); + } + else { + $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); + $formatter->display_items( $it ); + } } /** From 43a6712ba0dbe77f3f8badb4eb74f3ff1d997e56 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 1 Jul 2016 17:40:31 +0545 Subject: [PATCH 4661/5359] Add test for ids value in format parameter in site list --- features/site.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/site.feature b/features/site.feature index 46f5d9fa6..506c67946 100644 --- a/features/site.feature +++ b/features/site.feature @@ -21,6 +21,12 @@ Feature: Manage sites in a multisite installation | 1 | http://example.com/ | | 2 | http://first.example.com/ | + When I run `wp site list --format=ids` + Then STDOUT should be: + """ + 1 2 + """ + When I run `wp --url=first.example.com option get home` Then STDOUT should be: """ From 0898cbb6bbda238574ada292397c2c35a5241ebc Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Fri, 1 Jul 2016 18:21:54 +0200 Subject: [PATCH 4662/5359] Remove unsupported ids output of menu locations #3083 Menu locations doesn't have ids, so they can't be outputted --- php/commands/menu.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 2ee952736..7302f1efe 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -731,7 +731,6 @@ class Menu_Location_Command extends WP_CLI_Command { * - csv * - json * - count - * - ids * - yaml * --- * From 24e185e1642e0e93f140175578a1a420f6502e4a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Jul 2016 15:04:20 -0700 Subject: [PATCH 4663/5359] Introduce `wp cli alias` for listing available aliases --- features/aliases.feature | 21 +++++++++++++++++++++ php/commands/cli.php | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index 1985a977d..27bf71ba8 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -96,6 +96,27 @@ Feature: Create shortcuts to specific WordPress installs """ And STDERR should be empty + Scenario: List available aliases + Given an empty directory + And a wp-cli.yml file: + """ + @testdir: + path: testdir + """ + + When I run `wp cli alias` + Then STDOUT should be YAML containing: + """ + @testdir: + path: testdir + """ + + When I run `wp cli alias --format=json` + Then STDOUT should be JSON containing: + """ + {"@testdir":{"path":"testdir"}} + """ + Scenario: Defining a project alias completely overrides a global alias Given a WP install in 'testdir' And a config.yml file: diff --git a/php/commands/cli.php b/php/commands/cli.php index 3e33904fa..5d0d0b31a 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -457,6 +457,29 @@ public function completions( $_, $assoc_args ) { $compl->render(); } + /** + * List available aliases. + * + * Aliases are shorthand references to WordPress installs. For instance, + * '@dev' could refer to a development install and '@prod' could refer to + * a production install. This command gives you visibility in what + * registered aliases you have available. + * + * ## OPTIONS + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: yaml + * options: + * - yaml + * - json + * --- + */ + public function alias( $_, $assoc_args ) { + WP_CLI::print_value( WP_CLI::get_runner()->aliases, $assoc_args ); + } + /** * Get a string representing the type of update being checked for */ From 5b47ca11a19daa0b6d39e33690cddfbb089dceb8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Jul 2016 15:59:18 -0700 Subject: [PATCH 4664/5359] Improve our CONTRIBUTING.md with greater detail --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++---- README.md | 16 +++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6bb879c5..d6e523ee9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,30 @@ -Contribute -========== +Contributing +============ -Thanks in advance for helping to improve WP-CLI. +Welcome and thanks! -To get started, please review our documentation on [creating an issue](http://wp-cli.org/docs/bug-reports/) or [submitting a pull request](http://wp-cli.org/docs/pull-requests/). +We appreciate you taking the initiative to contribute to WP-CLI. It’s because of you, and the community around you, that WP-CLI is such a great project. + +**Contributing isn’t limited to just code.** We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. + +Please take a moment to read these guidelines at depth. Following the guidelines helps to communicate that you respect the time of the other contributors to the project. In turn, they’ll do their best to reciprocate that respect when working with you, across timezones and around the world. + +### Reporting a bug + +Think you’ve found a bug? We’d love for you to help us get it fixed. + +Before you create a new issue, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. You should also check our [documentation on common issues and their fixes](https://wp-cli.org/docs/common-issues/). + +Once you’ve done a bit of searching and discovered there isn’t an open or fixed issue for your bug, please [follow our guidelines for submitting a bug report](http://wp-cli.org/docs/bug-reports/) to make sure it gets addressed in a timely manner. + +### Creating a pull request + +Want to contribute a new feature? WP-CLI is a mature project, and already chock-full of useful functionality. Please first [open a new issue](https://github.com/wp-cli/wp-cli/issues/new) to discuss whether the feature is a good fit for WP-CLI core, or might be better suited as a [community package](https://wp-cli.org/package-index/). + +Once you've decided to commit the time to seeing your pull request through, please [follow our guidelines for creating a pull request](https://wp-cli.org/docs/pull-requests/) to make sure it's a pleasant experience. + +### Contributing in other ways + +Feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question, and we'll see if we can find an answer for it. + +Alternatively, if you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). diff --git a/README.md b/README.md index f895828c8..631917218 100644 --- a/README.md +++ b/README.md @@ -103,19 +103,29 @@ WP-CLI's maintainers and project contributors do their best to respond to all ne - [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) +If you can't find your answer in one of those existing resources, feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question. + If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). ## Extending A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. -WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](http://wp-cli.org/docs/internal-api/) to discover a variety of helpful functions you can use in your custom WP-CLI command. +WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](https://wp-cli.org/docs/internal-api/) to discover a variety of helpful functions you can use in your custom WP-CLI command. ## Contributing -To get involved, please first read about [creating an issue](https://wp-cli.org/docs/bug-reports/) or [submitting a pull request](https://wp-cli.org/docs/pull-requests/). +Welcome and thanks! + +We appreciate you taking the initiative to contribute to WP-CLI. It’s because of you, and the community around you, that WP-CLI is such a great project. + +**Contributing isn’t limited to just code.** We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. + +Please take a moment to [read these guidelines at depth](https://wp-cli.org/docs/contributing/). Following them helps to communicate that you respect the time of the other contributors to the project. In turn, they’ll do their best to reciprocate that respect when working with you, across timezones and around the world. + +## Leadership -### Leadership +WP-CLI is led by these individuals: * [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer * [Cristi Burcă](https://github.com/scribu) - previous maintainer From 2c2bdd3c69950539c1ec34c08b91e1a096d07444 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 1 Jul 2016 16:23:24 -0700 Subject: [PATCH 4665/5359] Update Composer dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing wp-cli/php-cli-tools (v0.11.1) - Installing wp-cli/php-cli-tools (dev-master 10cfa5b) Cloning 10cfa5bd978889c8050cd48d70d179d775c31827 - Removing symfony/yaml (v2.8.7) - Installing symfony/yaml (v2.8.8) Downloading: 100% - Removing symfony/filesystem (v2.8.7) - Installing symfony/filesystem (v2.8.8) Downloading: 100% - Removing symfony/config (v2.8.7) - Installing symfony/config (v2.8.8) Downloading: 100% - Removing symfony/dependency-injection (v2.8.7) - Installing symfony/dependency-injection (v2.8.8) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.7) - Installing symfony/event-dispatcher (v2.8.8) Downloading: 100% - Removing symfony/translation (v2.8.7) - Installing symfony/translation (v2.8.8) Downloading: 100% - Removing symfony/process (v2.8.7) - Installing symfony/process (v2.8.8) Downloading: 100% - Removing symfony/finder (v2.8.7) - Installing symfony/finder (v2.8.8) Downloading: 100% - Removing symfony/console (v2.8.7) - Installing symfony/console (v2.8.8) Downloading: 100% - Removing composer/composer (1.1.2) - Installing composer/composer (1.1.3) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.json | 2 +- composer.lock | 118 +++++++++++++++++++++++++------------------------- 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index 8b2590b79..9fabb1b8d 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.29", - "wp-cli/php-cli-tools": "~0.11.1", + "wp-cli/php-cli-tools": "dev-master", "mustache/mustache": "~2.4", "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", diff --git a/composer.lock b/composer.lock index ab7cf9aaa..a03775812 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "f0bf52c59aa6e9fe44d6a611f8006a52", - "content-hash": "10cf19699e3fed767e31e1493a07c8f0", + "hash": "38e11e275b2087dfb61f50d258712aef", + "content-hash": "a55b968d0d6754da376a5151b4222cbb", "packages": [ { "name": "composer/ca-bundle", @@ -64,16 +64,16 @@ }, { "name": "composer/composer", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "b2cf67b1a575d7e648c742be2454339232ef32b2" + "reference": "30ab6f1c1753267d181839142fafe022313c3c9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/b2cf67b1a575d7e648c742be2454339232ef32b2", - "reference": "b2cf67b1a575d7e648c742be2454339232ef32b2", + "url": "https://api.github.com/repos/composer/composer/zipball/30ab6f1c1753267d181839142fafe022313c3c9a", + "reference": "30ab6f1c1753267d181839142fafe022313c3c9a", "shasum": "" }, "require": { @@ -137,7 +137,7 @@ "dependency", "package" ], - "time": "2016-05-31 18:48:12" + "time": "2016-06-26 14:42:08" }, { "name": "composer/semver", @@ -734,16 +734,16 @@ }, { "name": "symfony/config", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05" + "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05", - "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05", + "url": "https://api.github.com/repos/symfony/config/zipball/0926e69411eba491803dbafb9f1f233e2ced58d0", + "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0", "shasum": "" }, "require": { @@ -783,20 +783,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:31:50" }, { "name": "symfony/console", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3" + "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", - "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", + "url": "https://api.github.com/repos/symfony/console/zipball/c392a6ec72f2122748032c2ad6870420561ffcfa", + "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa", "shasum": "" }, "require": { @@ -843,20 +843,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-06-06 15:06:25" + "time": "2016-06-29 07:02:14" }, { "name": "symfony/dependency-injection", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13" + "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2d05009d890cf1139988ff059b5b2e0eb280ed13", - "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2dd85de8216079d1360b2b14988cd5cdbbb49063", + "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063", "shasum": "" }, "require": { @@ -906,20 +906,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:31:50" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2a6b8713f8bdb582058cfda463527f195b066110" + "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110", - "reference": "2a6b8713f8bdb582058cfda463527f195b066110", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b180b70439dca70049b6b9b7e21d75e6e5d7aca9", + "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9", "shasum": "" }, "require": { @@ -966,20 +966,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/filesystem", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "dee379131dceed90a429e951546b33edfe7dccbb" + "reference": "7258ddd6f987053f21fa43d03430580ba54e6096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb", - "reference": "dee379131dceed90a429e951546b33edfe7dccbb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/7258ddd6f987053f21fa43d03430580ba54e6096", + "reference": "7258ddd6f987053f21fa43d03430580ba54e6096", "shasum": "" }, "require": { @@ -1015,20 +1015,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-04-12 18:01:21" + "time": "2016-06-29 05:31:50" }, { "name": "symfony/finder", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "3ec095fab1800222732ca522a95dce8fa124007b" + "reference": "bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b", - "reference": "3ec095fab1800222732ca522a95dce8fa124007b", + "url": "https://api.github.com/repos/symfony/finder/zipball/bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d", + "reference": "bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d", "shasum": "" }, "require": { @@ -1064,7 +1064,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/polyfill-mbstring", @@ -1127,16 +1127,16 @@ }, { "name": "symfony/process", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c" + "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c", - "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c", + "url": "https://api.github.com/repos/symfony/process/zipball/89f33c16796415ccfd8bb3cf8d520cbb79899bfe", + "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe", "shasum": "" }, "require": { @@ -1172,20 +1172,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/translation", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1" + "reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1", - "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1", + "url": "https://api.github.com/repos/symfony/translation/zipball/00334ef0b9317e5d7c7641a2b56671a1df23b7a0", + "reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0", "shasum": "" }, "require": { @@ -1236,20 +1236,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/yaml", - "version": "v2.8.7", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34" + "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34", - "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34", + "url": "https://api.github.com/repos/symfony/yaml/zipball/dba4bb5846798cd12f32e2d8f3f35d77045773c8", + "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8", "shasum": "" }, "require": { @@ -1285,20 +1285,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-06-06 11:11:27" + "time": "2016-06-29 05:29:29" }, { "name": "wp-cli/php-cli-tools", - "version": "v0.11.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "5311a4b99103c0505db015a334be4952654d6e21" + "reference": "10cfa5bd978889c8050cd48d70d179d775c31827" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/5311a4b99103c0505db015a334be4952654d6e21", - "reference": "5311a4b99103c0505db015a334be4952654d6e21", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/10cfa5bd978889c8050cd48d70d179d775c31827", + "reference": "10cfa5bd978889c8050cd48d70d179d775c31827", "shasum": "" }, "require": { @@ -1335,7 +1335,7 @@ "cli", "console" ], - "time": "2016-02-08 14:34:01" + "time": "2016-03-30 11:55:36" } ], "packages-dev": [ @@ -1830,7 +1830,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "wp-cli/php-cli-tools": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 71593a806d03c637b6a2dd36009593f5544bd868 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 2 Jul 2016 12:36:35 +0545 Subject: [PATCH 4666/5359] Improving doc and message in scaffold commands --- php/commands/scaffold.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 795a28469..30a2da1d6 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -34,7 +34,7 @@ class Scaffold_Command extends WP_CLI_Command { * : The internal name of the post type. * * [--label=<label>] - * : The text used to translate the update messages + * : The text used to translate the update messages. * * [--textdomain=<textdomain>] * : The textdomain to use for the labels. @@ -58,7 +58,7 @@ class Scaffold_Command extends WP_CLI_Command { * ## EXAMPLES * * $ wp scaffold post-type movie --label=Movie --theme=simple-life - * Success: Created /var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php + * Success: Created '/var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php'. * * @subcommand post-type * @@ -184,8 +184,8 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) $files_written = $this->create_files( array( $filename => $final_output ), $force ); $this->log_whether_files_written( $files_written, - $skip_message = "Skipped creating $filename", - $success_message = "Created $filename" + $skip_message = "Skipped creating '$filename'.", + $success_message = "Created '$filename'." ); } else { @@ -209,16 +209,16 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * : Enable the newly downloaded theme for the entire network. * * [--theme_name=<title>] - * : What to put in the 'Theme Name:' header in style.css + * : What to put in the 'Theme Name:' header in 'style.css'. * * [--author=<full-name>] - * : What to put in the 'Author:' header in style.css + * : What to put in the 'Author:' header in 'style.css'. * * [--author_uri=<uri>] - * : What to put in the 'Author URI:' header in style.css + * : What to put in the 'Author URI:' header in 'style.css'. * * [--sassify] - * : Include stylesheets as SASS + * : Include stylesheets as SASS. * * [--force] * : Overwrite files that already exist. @@ -309,19 +309,19 @@ function _s( $args, $assoc_args ) { * : The slug for the new child theme. * * --parent_theme=<slug> - * : What to put in the 'Template:' header in style.css + * : What to put in the 'Template:' header in 'style.css'. * * [--theme_name=<title>] - * : What to put in the 'Theme Name:' header in style.css + * : What to put in the 'Theme Name:' header in 'style.css'. * * [--author=<full-name>] - * : What to put in the 'Author:' header in style.css + * : What to put in the 'Author:' header in 'style.css'. * * [--author_uri=<uri>] - * : What to put in the 'Author URI:' header in style.css + * : What to put in the 'Author URI:' header in 'style.css'. * * [--theme_uri=<uri>] - * : What to put in the 'Theme URI:' header in style.css + * : What to put in the 'Theme URI:' header in 'style.css'. * * [--activate] * : Activate the newly created child theme. @@ -335,7 +335,7 @@ function _s( $args, $assoc_args ) { * ## EXAMPLES * * $ wp scaffold child-theme sample-theme --parent_theme=twentysixteen - * Success: Created /var/www/example.com/public_html/wp-content/themes/sample-theme. + * Success: Created '/var/www/example.com/public_html/wp-content/themes/sample-theme'. * * @subcommand child-theme */ @@ -367,7 +367,7 @@ function child_theme( $args, $assoc_args ) { $this->log_whether_files_written( $files_written, $skip_message = 'All theme files were skipped.', - $success_message = "Created $theme_dir." + $success_message = "Created '$theme_dir'." ); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { @@ -412,7 +412,7 @@ private function get_output_path( $assoc_args, $subdir ) { * : Put the new plugin in some arbitrary directory path. Plugin directory will be path plus supplied slug. * * [--plugin_name=<title>] - * : What to put in the 'Plugin Name:' header + * : What to put in the 'Plugin Name:' header. * * [--plugin_description=<description>] * : What to put in the 'Description:' header. @@ -617,7 +617,7 @@ function plugin_tests( $args, $assoc_args ) { $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", $file_name, true ); if ( 'install-wp-tests.sh' === $file ) { if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { - WP_CLI::warning( "Couldn't mark install-wp-tests.sh as executable." ); + WP_CLI::warning( "Couldn't mark 'install-wp-tests.sh' as executable." ); } } } @@ -655,7 +655,7 @@ private function prompt_if_files_will_be_overwritten( $filename, $force ) { return true; } - WP_CLI::warning( 'File already exists' ); + WP_CLI::warning( 'File already exists.' ); WP_CLI::log( $filename ); if ( ! $force ) { do { From 1463486b110df537056d1c5283f504c9bc109b3b Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 2 Jul 2016 12:47:28 +0545 Subject: [PATCH 4667/5359] Improving test for scaffold commands --- features/scaffold.feature | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 733841eef..8c0e6f661 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -7,9 +7,12 @@ Feature: WordPress code scaffolding And save STDOUT as {THEME_DIR} When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com` - Then STDOUT should not be empty - And the {THEME_DIR}/zombieland/style.css file should exist + Then the {THEME_DIR}/zombieland/style.css file should exist And the {THEME_DIR}/zombieland/functions.php file should exist + And STDOUT should be: + """ + Success: Created '{THEME_DIR}/zombieland'. + """ Scenario: Scaffold a child theme with only --parent_theme parameter Given a WP install @@ -62,6 +65,25 @@ Feature: WordPress code scaffolding When I run `wp scaffold post-type zombie --theme` Then the {STYLESHEETPATH}/post-types/zombie.php file should exist + And STDOUT should be: + """ + Success: Created '{STYLESHEETPATH}/post-types/zombie.php'. + """ + + When I run `wp scaffold post-type zombie` + Then STDOUT should contain: + """ + register_post_type( 'zombie' + """ + And STDOUT should contain: + """ + add_filter( 'post_updated_messages' + """ + When I run `wp scaffold post-type zombie --raw` + Then STDOUT should not contain: + """ + add_filter( 'post_updated_messages' + """ # Test for all flags but --label, --theme, --plugin and --raw @tax From 36cc14f7c6bc96dbf75fe27d47e16d9268376888 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 2 Jul 2016 14:19:05 +0545 Subject: [PATCH 4668/5359] Improving doc in post commands --- php/commands/post.php | 51 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index 856d04776..8a5a23c02 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -184,7 +184,15 @@ protected function _edit( $content, $title ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -270,7 +278,17 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -381,13 +399,22 @@ public function list_( $_, $assoc_args ) { * ## OPTIONS * * [--count=<number>] - * : How many posts to generate. Default: 100 + * : How many posts to generate? + * --- + * default: 100 + * --- * * [--post_type=<type>] - * : The type of the generated posts. Default: 'post' + * : The type of the generated posts. + * --- + * default: post + * --- * * [--post_status=<status>] - * : The status of the generated posts. Default: 'publish' + * : The status of the generated posts. + * --- + * default: publish + * --- * * [--post_author=<login>] * : The author of the generated posts. Default: none @@ -399,10 +426,19 @@ public function list_( $_, $assoc_args ) { * : If set, the command reads the post_content from STDIN. * * [--max_depth=<number>] - * : For hierarchical post types, generate child posts down to a certain depth. Default: 1 + * : For hierarchical post types, generate child posts down to a certain depth. + * --- + * default: 1 + * --- * * [--format=<format>] - * : Accepted values: progress, ids. Default: ids. + * : Render output in a particular format. + * --- + * default: progress + * options: + * - progress + * - ids + * --- * * ## EXAMPLES * @@ -618,4 +654,3 @@ protected function get_object_type() { WP_CLI::add_command( 'post', 'Post_Command' ); WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); WP_CLI::add_command( 'post term', 'Post_Term_Command' ); - From 5d34e2071da908079e3d13d07f27ab62db9fef7a Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Sat, 2 Jul 2016 15:48:48 +0200 Subject: [PATCH 4669/5359] Fix output of menu locations with format id #3083 --- php/commands/menu.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 2ee952736..a351c4630 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -766,7 +766,17 @@ public function list_( $_, $assoc_args ) { } $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); - $formatter->display_items( $location_objs ); + + if ( 'ids' == $formatter->format ) { + $ids = array_map( + function($o) { + return $o->location; + }, $location_objs + ); + $formatter->display_items( $ids ); + } else { + $formatter->display_items( $location_objs ); + } } /** From e3587108f9545c3fc58a9012d19d7411b1c77f4f Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Sat, 2 Jul 2016 15:53:49 +0200 Subject: [PATCH 4670/5359] Add tests for #3083 --- features/menu.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index d75af3725..3532450be 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -55,6 +55,12 @@ Feature: Manage WordPress menus | slug | locations | | primary-menu | primary | + When I run `wp menu location list --format=ids` + Then STDOUT should be: + """ + primary + """ + When I run `wp menu location remove primary-menu primary` And I run `wp menu list --fields=slug,locations` Then STDOUT should be a table containing rows: From e8e15a9782fcfd8c8c38beb5e062cfed2f9fcaf7 Mon Sep 17 00:00:00 2001 From: Jakub Juszczak <netghost03@gmail.com> Date: Sun, 3 Jul 2016 10:16:50 +0200 Subject: [PATCH 4671/5359] Add ids to supported output format for menu location list --- php/commands/menu.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/menu.php b/php/commands/menu.php index 6a5e479b8..2f1bf815c 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -732,6 +732,7 @@ class Menu_Location_Command extends WP_CLI_Command { * - json * - count * - yaml + * - ids * --- * * ## AVAILABLE FIELDS From e2e99bedbd8518c96dfb8983641b0124296fe259 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 3 Jul 2016 05:56:56 -0700 Subject: [PATCH 4672/5359] Register a magic `@all` alias This permits running a WP-CLI command against all registered aliases --- features/aliases.feature | 58 ++++++++++++++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 6 +++++ 2 files changed, 64 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index 27bf71ba8..cd0135b64 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -185,3 +185,61 @@ Feature: Create shortcuts to specific WordPress installs http://apple.com http://google.com """ + + Scenario: Register '@all' alias for running on one or more aliases + Given a WP install in 'subdir1' + And a WP install in 'subdir2' + And a wp-cli.yml file: + """ + @subdir1: + path: subdir1 + @subdir2: + path: subdir2 + """ + + When I run `wp @subdir1 option update home 'http://apple.com'` + And I run `wp @subdir1 option get home` + Then STDOUT should contain: + """ + http://apple.com + """ + + When I run `wp @subdir2 option update home 'http://google.com'` + And I run `wp @subdir2 option get home` + Then STDOUT should contain: + """ + http://google.com + """ + + When I run `wp @all option get home` + Then STDOUT should be: + """ + http://apple.com + http://google.com + """ + + Scenario: Don't register '@all' when its already set + Given a WP install in 'subdir1' + And a WP install in 'subdir2' + And a wp-cli.yml file: + """ + @all: + path: subdir1 + @subdir2: + path: subdir2 + """ + + When I run `wp @all option get home | wc -l` + Then STDOUT should be: + """ + 1 + """ + + Scenario: Error when '@all' is used without aliases defined + Given an empty directory + + When I try `wp @all option get home` + Then STDERR should be: + """ + Error: Cannot use '@all' when no aliases are registered. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 4499b17d1..81494257f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -627,6 +627,9 @@ private function init_config() { list( $this->config, $this->extra_config ) = $configurator->to_array(); $this->aliases = $configurator->get_aliases(); + if ( count( $this->aliases ) && ! isset( $this->aliases['@all'] ) ) { + $this->aliases['@all'] = array_keys( $this->aliases ); + } $this->_required_files['runtime'] = $this->config['require']; } @@ -700,6 +703,9 @@ public function start() { $this->check_root(); if ( $this->alias ) { + if ( '@all' === $this->alias && 0 === count( $this->aliases ) ) { + WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); + } if ( ! array_key_exists( $this->alias, $this->aliases ) ) { WP_CLI::error( "Alias '{$this->alias}' not found." ); } From 6670840b815c5aae44c533a9f809338a0356d466 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 4 Jul 2016 12:46:09 +0545 Subject: [PATCH 4673/5359] Temporary reversal of default doc and add more improvements --- features/post.feature | 2 +- php/commands/post.php | 21 +++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/features/post.feature b/features/post.feature index b503ccee3..d33e825b2 100644 --- a/features/post.feature +++ b/features/post.feature @@ -153,7 +153,7 @@ Feature: Manage WordPress posts When I try `wp post update {POST_ID} invalid-file.html` Then STDERR should be: """ - Error: Unable to read content from invalid-file.html. + Error: Unable to read content from 'invalid-file.html'. """ Scenario: Creating/listing posts diff --git a/php/commands/post.php b/php/commands/post.php index 8a5a23c02..d8f56700f 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -278,17 +278,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- + * Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * @@ -417,7 +407,10 @@ public function list_( $_, $assoc_args ) { * --- * * [--post_author=<login>] - * : The author of the generated posts. Default: none + * : The author of the generated posts. + * --- + * default: + * --- * * [--post_date=<yyyy-mm-dd>] * : The date of the generated posts. Default: current date @@ -487,7 +480,7 @@ public function generate( $args, $assoc_args ) { $post_content = file_get_contents( 'php://stdin' ); } - // Get the total number of posts + // Get the total number of posts. $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); $label = get_post_type_object( $post_type )->labels->singular_name; @@ -578,7 +571,7 @@ private function read_from_file_or_stdin( $arg ) { if ( $arg !== '-' ) { $readfile = $arg; if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) { - \WP_CLI::error( "Unable to read content from $readfile." ); + \WP_CLI::error( "Unable to read content from '$readfile'." ); } } else { $readfile = 'php://stdin'; From 4f6ae82da3aa81ff1a73ded26e43a6e3efa2e7ad Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 4 Jul 2016 12:48:10 +0545 Subject: [PATCH 4674/5359] Add missing colon in post list doc --- php/commands/post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index d8f56700f..bf3b03876 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -278,7 +278,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Accepted values: table, csv, json, count, ids, yaml. Default: table * * ## AVAILABLE FIELDS * From 746c0e06a133467fb421d730f561edf0c8bfbf41 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 4 Jul 2016 14:29:40 -0700 Subject: [PATCH 4675/5359] Restore tab completion documentation to README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 631917218..db835e169 100644 --- a/README.md +++ b/README.md @@ -89,10 +89,22 @@ WP-CLI project config: WP-CLI version: 0.23.0 ``` +### Updating + You can update WP-CLI with `wp cli update` ([doc](https://wp-cli.org/commands/cli/update/)), or by repeating the installation steps. Want to live life on the edge? Run `wp cli update --nightly` to use the latest nightly build of WP-CLI. The nightly build is more or less stable enough for you to use in your development environment, and always includes the latest and greatest WP-CLI features. +### Tab completions + +WP-CLI also comes with a tab completion script for Bash and ZSH. Just download [wp-completion.bash](https://github.com/wp-cli/wp-cli/raw/master/utils/wp-completion.bash) and source it from `~/.bash_profile`: + +``` +source /FULL/PATH/TO/wp-completion.bash +``` + +Don't forget to run `source ~/.bash_profile` afterwards. + ## Support WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: From 671bc7f6fea63f680fa405a62ccf0afe1fb975cf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 5 Jul 2016 13:28:58 -0700 Subject: [PATCH 4676/5359] Failing test case for #3101 --- features/command.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/features/command.feature b/features/command.feature index 490b13c31..f4f5aec2d 100644 --- a/features/command.feature +++ b/features/command.feature @@ -573,3 +573,14 @@ Feature: WP-CLI Commands Success: Invoked Success: after invoke """ + + Scenario: Default arguments should respect wp-cli.yml + Given a WP install + And a wp-cli.yml file: + """ + post list: + format: count + """ + + When I run `wp post list` + Then STDOUT should be a number From d7a219f3f555134e56e8e329e131eee93d45e456 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 5 Jul 2016 14:14:01 -0700 Subject: [PATCH 4677/5359] Respect wp-cli.yml default values when applying argument defaults Bug introduced in 05ff88bf66c7276fc95cd80f9fa8f85547c55b2f --- php/WP_CLI/Dispatcher/Subcommand.php | 2 +- php/commands/post.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 35d8922cb..1b18f9b2d 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -287,7 +287,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $i++; } else if ( 'assoc' === $spec['type'] ) { $spec_args = $docparser->get_param_args( $spec['name'] ); - if ( ! isset( $assoc_args[ $spec['name'] ] ) ) { + if ( ! isset( $assoc_args[ $spec['name'] ] ) && ! isset( $extra_args[ $spec['name'] ] ) ) { if ( isset( $spec_args['default'] ) ) { $assoc_args[ $spec['name'] ] = $spec_args['default']; } diff --git a/php/commands/post.php b/php/commands/post.php index bf3b03876..b84feb628 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -279,6 +279,16 @@ public function delete( $args, $assoc_args ) { * * [--format=<format>] * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * From 28eed6b5a8923dae69c01d0d665e6d613b748957 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 6 Jul 2016 05:01:22 -0700 Subject: [PATCH 4678/5359] Mention `good-first-issue` in CONTRIBUTING.md --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6e523ee9..427d6c260 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,6 +21,8 @@ Once you’ve done a bit of searching and discovered there isn’t an open or fi Want to contribute a new feature? WP-CLI is a mature project, and already chock-full of useful functionality. Please first [open a new issue](https://github.com/wp-cli/wp-cli/issues/new) to discuss whether the feature is a good fit for WP-CLI core, or might be better suited as a [community package](https://wp-cli.org/package-index/). +New to the WP-CLI codebase? Check out [issues labeled 'good-first-issue'](https://github.com/wp-cli/wp-cli/labels/good-first-issue) for a place to start. These issues are specially earmarked for new contributors. + Once you've decided to commit the time to seeing your pull request through, please [follow our guidelines for creating a pull request](https://wp-cli.org/docs/pull-requests/) to make sure it's a pleasant experience. ### Contributing in other ways From c992061b0b5c0afc43e1ec545586999a21c5793d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 05:49:38 -0700 Subject: [PATCH 4679/5359] Use `proc_open()` instead of `passthru()` to persist TTY mode --- php/WP_CLI/Runner.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 81494257f..0868086fc 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -678,7 +678,8 @@ private function run_alias_group( $aliases ) { $assoc_args = Utils\assoc_args_to_str( $this->assoc_args ); $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$alias} {$args} {$assoc_args}"; - passthru( $full_command ); + $proc = proc_open( $full_command, array( STDIN, STDOUT, STDERR ), $pipes ); + proc_close( $proc ); } } From acbf549f900835664fd306a88ffdb136ffb7edca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 06:00:32 -0700 Subject: [PATCH 4680/5359] Failing test case for #3104 --- features/cron.feature | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/features/cron.feature b/features/cron.feature index 76b1ee0e8..253938dd0 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -280,3 +280,27 @@ Feature: Manage WP-Cron events and schedules """ Executed a total of 0 cron event(s) """ + + Scenario: Don't trigger cron when ALTERNATE_WP_CRON is defined + Given a alternate-wp-cron.php file: + """ + <?php + define( 'ALTERNATE_WP_CRON', true ); + """ + And a wp-cli.yml file: + """ + require: + - alternate-wp-cron.php + """ + + When I run `wp eval 'var_export( ALTERNATE_WP_CRON );'` + Then STDOUT should be: + """ + true + """ + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ From 99dea0f3ad9ee848e2ccd10b2ce27d30a3da663c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 06:07:02 -0700 Subject: [PATCH 4681/5359] Don't trigger cron when ALTERNATE_WP_CRON is defined `ALTERNATE_WP_CRON` tries to redirect, which we can't handle. --- php/WP_CLI/Runner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 81494257f..fa6630ff2 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1014,6 +1014,13 @@ private function setup_bootstrap_hooks() { return $headers; }); + // ALTERNATE_WP_CRON might trigger a redirect, which we can't handle + if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { + $this->add_wp_hook( 'muplugins_loaded', function() { + remove_action( 'init', 'wp_cron' ); + }); + } + // Get rid of warnings when converting single site to multisite if ( defined( 'WP_INSTALLING' ) && $this->is_multisite() ) { $values = array( From 6d4aae0b164222b3c844ee9403e69767ced8f5be Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 07:14:56 -0700 Subject: [PATCH 4682/5359] Failing test case for #3029 --- features/config.feature | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/features/config.feature b/features/config.feature index 7912d1d53..bf68d258d 100644 --- a/features/config.feature +++ b/features/config.feature @@ -155,6 +155,20 @@ Feature: Have a config file And I run `grep WP_POST_REVISIONS wp-config.php` Then STDOUT should not be empty + Scenario: Persist positional parameters when defined in a config + Given a WP install + And a wp-cli.yml file: + """ + user create: + - examplejoe + - joe@example.com + user_pass: joe + role: administrator + """ + + When I run `wp user create` + Then STDOUT should not be empty + Scenario: Command-specific configs Given a WP install And a wp-cli.yml file: From dcae93f329695074623fdb67b24c4b88d49bbcca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 07:19:48 -0700 Subject: [PATCH 4683/5359] Appropriately handle positional arguments defined in wp-cli.yml --- features/config.feature | 6 ++++++ php/WP_CLI/Dispatcher/Subcommand.php | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/features/config.feature b/features/config.feature index bf68d258d..d5db20844 100644 --- a/features/config.feature +++ b/features/config.feature @@ -169,6 +169,12 @@ Feature: Have a config file When I run `wp user create` Then STDOUT should not be empty + When I run `wp user get examplejoe --field=roles` + Then STDOUT should contain: + """ + administrator + """ + Scenario: Command-specific configs Given a WP install And a wp-cli.yml file: diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 1b18f9b2d..507036c84 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -345,6 +345,15 @@ public function invoke( $args, $assoc_args, $extra_args ) { $prompted_once = true; } + $extra_positionals = array(); + foreach( $extra_args as $k => $v ) { + if ( is_numeric( $k ) ) { + $extra_positionals[ $k ] = $v; + unset( $extra_args[ $k ] ); + } + } + $args = array_merge( $extra_positionals, $args ); + list( $to_unset, $args, $assoc_args, $extra_args ) = $this->validate_args( $args, $assoc_args, $extra_args ); foreach ( $to_unset as $key ) { From 9a075572018b84fd9fb62e936addd4b8b6d7ecc9 Mon Sep 17 00:00:00 2001 From: Keanan Koppenhaver <keanan@doejo.com> Date: Thu, 7 Jul 2016 11:18:03 -0500 Subject: [PATCH 4684/5359] #2766 - Improving our documentation section of CONTRIBUTING.md --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 427d6c260..31094fe50 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,20 @@ New to the WP-CLI codebase? Check out [issues labeled 'good-first-issue'](https: Once you've decided to commit the time to seeing your pull request through, please [follow our guidelines for creating a pull request](https://wp-cli.org/docs/pull-requests/) to make sure it's a pleasant experience. +### Improving our documentation + +Just like WP-CLI itself, the [documentation](http://wp-cli.org/docs/) is a community effort. + +If you are looking to contribute and documentation is your strength, you can take a look at the currently open [documentation issues](https://github.com/wp-cli/wp-cli/issues?q=is%3Aopen+is%3Aissue+label%3Ascope%3Adocumentation) and see if you can tackle any of those. + +If you believe you’ve found an issue with the documentation, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. + +There are a few different types of documentation currently part of WP-CLI: + +Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. + +Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on Github](https://github.com/wp-cli/wp-cli.github.com). + ### Contributing in other ways Feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question, and we'll see if we can find an answer for it. From 8e57ce79a0e6969ccf23f54cb1ef0735c3bb0e32 Mon Sep 17 00:00:00 2001 From: Keanan Koppenhaver <keanan@doejo.com> Date: Thu, 7 Jul 2016 13:07:17 -0500 Subject: [PATCH 4685/5359] #2766 edits and clarification of improving documentation section of CONTRIBUTING.md --- CONTRIBUTING.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31094fe50..7b00ca3c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,17 +27,15 @@ Once you've decided to commit the time to seeing your pull request through, plea ### Improving our documentation -Just like WP-CLI itself, the [documentation](http://wp-cli.org/docs/) is a community effort. - If you are looking to contribute and documentation is your strength, you can take a look at the currently open [documentation issues](https://github.com/wp-cli/wp-cli/issues?q=is%3Aopen+is%3Aissue+label%3Ascope%3Adocumentation) and see if you can tackle any of those. If you believe you’ve found an issue with the documentation, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. There are a few different types of documentation currently part of WP-CLI: -Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. + * Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. The web documentation is generated from these files at the time of release, so you may not see your changes until the next release. -Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on Github](https://github.com/wp-cli/wp-cli.github.com). + * Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on Github](https://github.com/wp-cli/wp-cli.github.com). ### Contributing in other ways From 92142ca8e33aea7cfa62297d227551854d866f75 Mon Sep 17 00:00:00 2001 From: Keanan Koppenhaver <keanan@doejo.com> Date: Thu, 7 Jul 2016 13:15:37 -0500 Subject: [PATCH 4686/5359] #2766 - additional edits to improving docs section per @danielbachhuber feedback --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b00ca3c2..ec808eb1e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Once you've decided to commit the time to seeing your pull request through, plea ### Improving our documentation -If you are looking to contribute and documentation is your strength, you can take a look at the currently open [documentation issues](https://github.com/wp-cli/wp-cli/issues?q=is%3Aopen+is%3Aissue+label%3Ascope%3Adocumentation) and see if you can tackle any of those. +Is documentation your strength? Take a look at the currently open [documentation issues](https://github.com/wp-cli/wp-cli/issues?q=is%3Aopen+is%3Aissue+label%3Ascope%3Adocumentation) and see if you can tackle any of those. If you believe you’ve found an issue with the documentation, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. @@ -35,7 +35,8 @@ There are a few different types of documentation currently part of WP-CLI: * Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. The web documentation is generated from these files at the time of release, so you may not see your changes until the next release. - * Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on Github](https://github.com/wp-cli/wp-cli.github.com). + + * Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on GitHub](https://github.com/wp-cli/wp-cli.github.com). Any page that is part of this repository will have an 'Edit' link in the top right of the page which will take you to the corresponding file on GitHub. ### Contributing in other ways From 326dcb67dd337095163ac49a14d743385157a8c5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 12:11:16 -0700 Subject: [PATCH 4687/5359] Minor edits --- CONTRIBUTING.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec808eb1e..abdb2c539 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,12 +31,10 @@ Is documentation your strength? Take a look at the currently open [documentation If you believe you’ve found an issue with the documentation, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. -There are a few different types of documentation currently part of WP-CLI: +There are a couple different types of documentation currently part of WP-CLI: - * Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. The web documentation is generated from these files at the time of release, so you may not see your changes until the next release. - - - * Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) or [http://wp-cli.org/config/](http://wp-cli.org/config/)) can be edited by contributing to the [wp-cli.github.com repository on GitHub](https://github.com/wp-cli/wp-cli.github.com). Any page that is part of this repository will have an 'Edit' link in the top right of the page which will take you to the corresponding file on GitHub. +* Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. The web documentation is generated from these files at the time of release, so you may not see your changes until the next release. +* Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) can be edited by contributing to the [wp-cli.github.com repository on GitHub](https://github.com/wp-cli/wp-cli.github.com). You don't necessarily need to navigate the Github repo though; any page that is part of this repository will have an 'Edit' link in the top right of the page which will take you to the corresponding file on GitHub. ### Contributing in other ways From be55a9d8354dbd1da78529d0fe4a7cacfb43f983 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 7 Jul 2016 13:39:56 -0700 Subject: [PATCH 4688/5359] Note that 'url' isn't an available filter for `wp site list` The value on the site object is created on the fly, not stored in a database column. --- php/commands/site.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 2ad634bfd..e3459a542 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -411,7 +411,8 @@ private function _get_network( $network_id ) { * : The network to which the sites belong. * * [--<field>=<value>] - * : Filter by one or more fields. + * : Filter by one or more fields (see "Available Fields" section). However, + * 'url' isn't an available filter, because it's created from domain + path. * * [--field=<field>] * : Prints the value of a single field for each site. @@ -482,7 +483,7 @@ public function list_( $_, $assoc_args ) { $where = array(); $append = ''; - $site_cols = array( 'blog_id', 'url', 'last_updated', 'registered', 'site_id', 'domain', 'path', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ); + $site_cols = array( 'blog_id', 'last_updated', 'registered', 'site_id', 'domain', 'path', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ); foreach( $site_cols as $col ) { if ( isset( $assoc_args[ $col ] ) ) { $where[ $col ] = $assoc_args[ $col ]; From 9a2673bcfba9dcd835963029afa27f776a53176b Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 8 Jul 2016 09:49:50 +0545 Subject: [PATCH 4689/5359] Add doc for generated files in scaffold plugin command --- php/commands/scaffold.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 30a2da1d6..d83f792c8 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -403,6 +403,23 @@ private function get_output_path( $assoc_args, $subdir ) { /** * Generate starter code for a plugin. * + * ## OVERVIEW + * + * The following files are generated for your plugin by this command: + * + * * `plugin-slug.php` is the main PHP plugin file. + * * `readme.txt` is the readme file for the plugin. + * * `package.json` needed by NPM holds various metadata relevant to the project. + * * `Gruntfile.js` is the JS file containing Grunt tasks. + * * `phpunit.xml.dist` is the configuration file for PHPUnit. + * * `.editorconfig` is the configuration file for Editor. + * * `.gitignore` tells which files (or patterns) git should ignore. + * * `.distignore` tells which files and folders should be ignored in distribution. + * * `.travis.yml` is the configuration file for Travis CI. + * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. + * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. + * * `tests/test-sample.php` is a sample file containing the actual tests. + * * ## OPTIONS * * <slug> From 5281abac2db2ab4ccd853a7f02d78b9e2131db90 Mon Sep 17 00:00:00 2001 From: Stephen Harris <Stephen.Harris@gov.scot> Date: Fri, 8 Jul 2016 11:10:50 +0100 Subject: [PATCH 4690/5359] Support 'trunk' and 'nightly' version arguments for wp core download. - Modifies Core_Command::get_download_url() to interpret 'trunk' and 'nightly' versions - Core_Command::get_download_url() now conforms to WordPress coding standards - Adds support for downloading and extracting .zip files as nightly builds are own available in zip format. - wp core download --version=trunk is only supported if ZipArchive is present. --- php/commands/core.php | 79 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 688510373..2d882db90 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -134,7 +134,7 @@ public function download( $args, $assoc_args ) { $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); if ( isset( $assoc_args['version'] ) ) { - $version = $assoc_args['version']; + $version = strtolower( $assoc_args['version'] ); $download_url = $this->get_download_url($version, $locale, 'tar.gz'); } else { $offer = $this->get_download_offer( $locale ); @@ -154,8 +154,14 @@ public function download( $args, $assoc_args ) { WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $version, $locale ) ); + $path_parts = pathinfo( $download_url ); + $extension = 'tar.gz'; + if ( 'zip' === $path_parts['extension'] ) { + $extension = 'zip'; + } + $cache = WP_CLI::get_cache(); - $cache_key = "core/wordpress-{$version}-{$locale}.tar.gz"; + $cache_key = "core/wordpress-{$version}-{$locale}.{$extension}"; $cache_file = $cache->has($cache_key); $bad_cache = false; @@ -172,7 +178,7 @@ public function download( $args, $assoc_args ) { if ( ! $cache_file || $bad_cache ) { // We need to use a temporary file because piping from cURL to tar is flaky // on MinGW (and probably in other environments too). - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.tar.gz'; + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . ".{$extension}"; $headers = array('Accept' => 'application/json'); $options = array( @@ -187,16 +193,21 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})." ); } - $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); - if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); - } + if ( 'trunk' !== $version && 'nightly' !== $version ) { + $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); + if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); + } + + $md5_file = md5_file( $temp ); - $md5_file = md5_file( $temp ); - if ( $md5_file === $md5_response->body ) { - WP_CLI::log( 'md5 hash verified: ' . $md5_file ); + if ( $md5_file === $md5_response->body ) { + WP_CLI::log( 'md5 hash verified: ' . $md5_file ); + } else { + WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); + } } else { - WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); + WP_CLI::warning( 'md5 hash checks are not available for trunk downloads' ); } try { @@ -215,7 +226,20 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } - private static function _extract( $tarball, $dest ) { + private static function _extract( $tarball_or_zip, $dest ) { + $path_parts = pathinfo( $tarball_or_zip ); + + switch ( strtolower( $path_parts['extension'] ) ) { + case 'zip': + self::_extract_zip( $tarball_or_zip, $dest ); + break; + default; + self::_extract_tarball( $tarball_or_zip, $dest ); + break; + } + } + + private static function _extract_tarball( $tarball, $dest ) { if ( ! class_exists( 'PharData' ) ) { $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); @@ -235,6 +259,29 @@ private static function _extract( $tarball, $dest ) { self::_rmdir( dirname( $tempdir ) ); } + private static function _extract_zip( $zipfile, $dest ) { + if ( ! class_exists( 'ZipArchive' ) ) { + throw new \Exception( 'Extracting a zip file requires PharData' ); + } + $zip = new ZipArchive(); + $res = $zip->open( $zipfile ); + if ( true === $res ) { + $tempdir = implode( DIRECTORY_SEPARATOR, Array ( + dirname( $zipfile ), + basename( $zipfile, '.zip' ), + $zip->getNameIndex( 0 ) + ) ); + + $zip->extractTo( dirname( $tempdir ) ); + $zip->close(); + + self::_copy_overwrite_files( $tempdir, $dest ); + self::_rmdir( dirname( $tempdir ) ); + } else { + throw \Exception( $res ); + } + } + private static function _copy_overwrite_files( $source, $dest ) { $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), @@ -1344,9 +1391,11 @@ function update_db( $_, $assoc_args ) { * @param string $file_type * @return string */ - private function get_download_url($version, $locale = 'en_US', $file_type = 'zip') - { - if ('en_US' === $locale) { + private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { + + if ( 'trunk' === $version || 'nightly' === $version ) { + return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; + } elseif ( 'en_US' === $locale ) { $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; return $url; From 5bf475096604c0f41734650085cac3af9343add8 Mon Sep 17 00:00:00 2001 From: Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> Date: Fri, 8 Jul 2016 12:19:59 +0100 Subject: [PATCH 4691/5359] Add missing full top. --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 2d882db90..904596c56 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -207,7 +207,7 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); } } else { - WP_CLI::warning( 'md5 hash checks are not available for trunk downloads' ); + WP_CLI::warning( 'md5 hash checks are not available for trunk downloads.' ); } try { From b7423a62e01fa0c0d29aa61c0d0128cb7ad7359c Mon Sep 17 00:00:00 2001 From: Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> Date: Fri, 8 Jul 2016 12:20:27 +0100 Subject: [PATCH 4692/5359] Make 'nightly' an alias for 'trunk' --- php/commands/core.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 904596c56..ad766deed 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -135,6 +135,7 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { $version = strtolower( $assoc_args['version'] ); + $version = ( 'nightly' === $version ? 'trunk' : $version ); $download_url = $this->get_download_url($version, $locale, 'tar.gz'); } else { $offer = $this->get_download_offer( $locale ); @@ -193,7 +194,7 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})." ); } - if ( 'trunk' !== $version && 'nightly' !== $version ) { + if ( 'trunk' !== $version ) { $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); @@ -1393,7 +1394,7 @@ function update_db( $_, $assoc_args ) { */ private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { - if ( 'trunk' === $version || 'nightly' === $version ) { + if ( 'trunk' === $version ) { return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; } elseif ( 'en_US' === $locale ) { $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; From 9ec1d1425b9345fbe46be6c7cd17d53cf1e360db Mon Sep 17 00:00:00 2001 From: Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> Date: Fri, 8 Jul 2016 12:24:58 +0100 Subject: [PATCH 4693/5359] Add behat tests --- features/core-download.feature | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/features/core-download.feature b/features/core-download.feature index 0b5cd4bd3..c04c62d5e 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -95,3 +95,87 @@ Feature: Download WordPress """ File removed: wp-content """ + + Scenario: Installing trunk + Given an empty directory + And an empty cache + + When I run `wp core download --version=trunk` + Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip file should exist + And STDOUT should contain: + """ + Downloading WordPress trunk (en_US)... + """ + And STDERR should contain: + """ + Warning: md5 hash checks are not available for trunk downloads. + """ + And STDOUT should contain: + """ + Success: WordPress downloaded. + """ + + # test core zip cache + When I run `wp core download --version=trunk` + Then the wp-settings.php file should exist + And STDOUT should contain: + """ + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip'... + """ + + Scenario: Installing trunk over an existing install + Given an empty directory + And an empty cache + When I run `wp core download --version=4.5.3` + Then the wp-settings.php file should exist + When I run `wp core download --version=trunk --force` + Then STDERR should not contain: + """ + Warning: Failed to find WordPress version. Please cleanup files manually. + """ + And STDERR should contain: + """ + Warning: Failed to fetch checksums. Please cleanup files manually. + """ + And STDOUT should contain: + """ + Success: WordPress downloaded. + """ + + Scenario: Installing a version over trunk + Given an empty directory + And an empty cache + When I run `wp core download --version=trunk` + Then the wp-settings.php file should exist + And STDERR should not contain: + """ + Warning: Failed to find WordPress version. Please cleanup files manually. + """ + + When I run `wp core download --version=4.3.2 --force` + Then the wp-includes/rest-api.php file should not exist + And the wp-includes/class-wp-comment.php file should not exist + And STDOUT should not contain: + """ + File removed: wp-content + """ + + Scenario: Nightly is an alias for trunk + Given an empty directory + And an empty cache + When I run `wp core download --version=nightly` + Then the wp-settings.php file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip file should exist + And STDOUT should contain: + """ + Downloading WordPress trunk (en_US)... + """ + And STDERR should contain: + """ + Warning: md5 hash checks are not available for trunk downloads. + """ + And STDOUT should contain: + """ + Success: WordPress downloaded. + """ From 0ab81152272897737735ebcbce8cfa0655266ff4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 8 Jul 2016 04:51:39 -0700 Subject: [PATCH 4694/5359] Introduce `WP_CLI_STRICT_ARGS_MODE` for dealing with arg ambiguity Consider a command like: ``` wp widget add rss sidebar-1 1 --url="http://wp-cli.org/feed/" ``` Historically, the `--url=<url>` parameter has been treated like a global runtime argument, which has meant a command can't easily use it as its own. Now, using the `WP_CLI_STRICT_ARGS_MODE` will tell WP-CLI to treat any arguments before the command as global, and after the command as local. For instance: ``` WP_CLI_STRICT_ARGS_MODE=1 wp --url=wp.dev/site2 widget add rss sidebar-1 1 --url="http://wp-cli.org/feed/" ``` In this example, `--url=wp.dev/site2` is the global argument, setting WP-CLI to run against 'site2' on a WP multisite install. `--url="http://wp-cli.org/feed/"` is the local argument, setting the RSS feed widget with the proper URL. I've thought long and hard about making a breaking change, and enforcing strict args mode by default. At this point, I don't think it will ever be worth it, given the majority use case isn't impacted by it, and it's a better user experience to be able to supply arguments in an ambigious order. When you need to be strict, you can use the environment variable. --- features/flags.feature | 46 ++++++++++++++++++++++ php/WP_CLI/Configurator.php | 76 ++++++++++++++++++++++++++----------- tests/test-configurator.php | 16 +++++++- 3 files changed, 115 insertions(+), 23 deletions(-) diff --git a/features/flags.feature b/features/flags.feature index b521a65f1..e4aa8d91e 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -212,3 +212,49 @@ Feature: Global flags """ <file> """ + + Scenario: Use `WP_CLI_STRICT_ARGS_MODE` to distinguish between global and local args + Given an empty directory + And a cmd.php file: + """ + <?php + /** + * @when before_wp_load + * + * [--url=<url>] + * : URL passed to the callback. + */ + $cmd_test = function( $args, $assoc_args ) { + $url = WP_CLI::get_runner()->config['url'] ? ' ' . WP_CLI::get_runner()->config['url'] : ''; + WP_CLI::log( 'global:' . $url ); + $url = isset( $assoc_args['url'] ) ? ' ' . $assoc_args['url'] : ''; + WP_CLI::log( 'local:' . $url ); + }; + WP_CLI::add_command( 'cmd-test', $cmd_test ); + """ + And a wp-cli.yml file: + """ + require: + - cmd.php + """ + + When I run `wp cmd-test --url=foo.dev` + Then STDOUT should be: + """ + global: foo.dev + local: + """ + + When I run `WP_CLI_STRICT_ARGS_MODE=1 wp cmd-test --url=foo.dev` + Then STDOUT should be: + """ + global: + local: foo.dev + """ + + When I run `WP_CLI_STRICT_ARGS_MODE=1 wp --url=bar.dev cmd-test --url=foo.dev` + Then STDOUT should be: + """ + global: bar.dev + local: foo.dev + """ diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 35063c2c8..1e467e9d9 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -84,8 +84,8 @@ function get_aliases() { * @return array(array) */ public function parse_args( $arguments ) { - list( $positional_args, $mixed_args ) = self::extract_assoc( $arguments ); - list( $assoc_args, $runtime_config ) = $this->unmix_assoc_args( $mixed_args ); + list( $positional_args, $mixed_args, $global_assoc, $local_assoc ) = self::extract_assoc( $arguments ); + list( $assoc_args, $runtime_config ) = $this->unmix_assoc_args( $mixed_args, $global_assoc, $local_assoc ); return array( $positional_args, $assoc_args, $runtime_config ); } @@ -96,21 +96,35 @@ public function parse_args( $arguments ) { * @return array(array) */ public static function extract_assoc( $arguments ) { - $positional_args = $assoc_args = array(); + $positional_args = $assoc_args = $global_assoc = $local_assoc = array(); foreach ( $arguments as $arg ) { + $positional_arg = $assoc_arg = null; + if ( preg_match( '|^--no-([^=]+)$|', $arg, $matches ) ) { - $assoc_args[] = array( $matches[1], false ); + $assoc_arg = array( $matches[1], false ); } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $assoc_args[] = array( $matches[1], true ); + $assoc_arg = array( $matches[1], true ); } elseif ( preg_match( '|^--([^=]+)=(.*)|s', $arg, $matches ) ) { - $assoc_args[] = array( $matches[1], $matches[2] ); + $assoc_arg = array( $matches[1], $matches[2] ); } else { - $positional_args[] = $arg; + $positional = $arg; + } + + if ( ! is_null( $assoc_arg ) ) { + $assoc_args[] = $assoc_arg; + if ( count( $positional_args ) ) { + $local_assoc[] = $assoc_arg; + } else { + $global_assoc[] = $assoc_arg; + } + } else if ( ! is_null( $positional ) ) { + $positional_args[] = $positional; } + } - return array( $positional_args, $assoc_args ); + return array( $positional_args, $assoc_args, $global_assoc, $local_assoc ); } /** @@ -119,32 +133,50 @@ public static function extract_assoc( $arguments ) { * @param array $mixed_args * @return array */ - private function unmix_assoc_args( $mixed_args ) { + private function unmix_assoc_args( $mixed_args, $global_assoc = array(), $local_assoc = array() ) { $assoc_args = $runtime_config = array(); - foreach ( $mixed_args as $tmp ) { - list( $key, $value ) = $tmp; - - if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { - $details = $this->spec[ $key ]; - - if ( isset( $details['deprecated'] ) ) { - fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); + if ( getenv( 'WP_CLI_STRICT_ARGS_MODE' ) ) { + foreach( $global_assoc as $tmp ) { + list( $key, $value ) = $tmp; + if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { + $this->assoc_arg_to_runtime_config( $key, $value, $runtime_config ); } + } + foreach( $local_assoc as $tmp ) { + $assoc_args[ $tmp[0] ] = $tmp[1]; + } + } else { + foreach ( $mixed_args as $tmp ) { + list( $key, $value ) = $tmp; - if ( $details['multiple'] ) { - $runtime_config[ $key ][] = $value; + if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { + $this->assoc_arg_to_runtime_config( $key, $value, $runtime_config ); } else { - $runtime_config[ $key ] = $value; + $assoc_args[ $key ] = $value; } - } else { - $assoc_args[ $key ] = $value; } } return array( $assoc_args, $runtime_config ); } + /** + * Handle turning an $assoc_arg into a runtime arg. + */ + private function assoc_arg_to_runtime_config( $key, $value, &$runtime_config ) { + $details = $this->spec[ $key ]; + if ( isset( $details['deprecated'] ) ) { + fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); + } + + if ( $details['multiple'] ) { + $runtime_config[ $key ][] = $value; + } else { + $runtime_config[ $key ] = $value; + } + } + /** * Load a YAML file of parameters into scope. * diff --git a/tests/test-configurator.php b/tests/test-configurator.php index 55c291acb..ea13aaeb3 100644 --- a/tests/test-configurator.php +++ b/tests/test-configurator.php @@ -36,6 +36,20 @@ function testExtractAssocNoValue() { } + function testExtractAssocGlobalLocal() { + $args = Configurator::extract_assoc( array( '--url=foo.dev', '--path=wp', 'foo', '--bar=', '--baz=text', '--url=bar.dev' ) ); + + $this->assertCount( 1, $args[0] ); + $this->assertCount( 5, $args[1] ); + $this->assertCount( 2, $args[2] ); + $this->assertCount( 3, $args[3] ); + + $this->assertEquals( 'url', $args[2][0][0] ); + $this->assertEquals( 'foo.dev', $args[2][0][1] ); + $this->assertEquals( 'url', $args[3][2][0] ); + $this->assertEquals( 'bar.dev', $args[3][2][1] ); + } + function testExtractAssocDoubleDashInValue() { $args = Configurator::extract_assoc( array( '--test=text--text' ) ); @@ -48,4 +62,4 @@ function testExtractAssocDoubleDashInValue() { } -} \ No newline at end of file +} From 9eea025df9b69eab496b6c2a5dc3207a05702f4a Mon Sep 17 00:00:00 2001 From: Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> Date: Fri, 8 Jul 2016 13:12:28 +0100 Subject: [PATCH 4695/5359] Fix test: use --force on the second time of downloading --- features/core-download.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-download.feature b/features/core-download.feature index c04c62d5e..2973f91fd 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -117,7 +117,7 @@ Feature: Download WordPress """ # test core zip cache - When I run `wp core download --version=trunk` + When I run `wp core download --version=trunk --force` Then the wp-settings.php file should exist And STDOUT should contain: """ From c626c3755821da538e6f51ccb035863bb6077f80 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 8 Jul 2016 06:21:53 -0700 Subject: [PATCH 4696/5359] Register `--http=<url>` global parameter We don't register new global parameters often, but this one is needed for RESTful WP-CLI. --- features/flags.feature | 9 +++++++++ php/WP_CLI/Runner.php | 4 ++++ php/config-spec.php | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/features/flags.feature b/features/flags.feature index e4aa8d91e..53306d508 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -258,3 +258,12 @@ Feature: Global flags global: bar.dev local: foo.dev """ + + Scenario: Using --http=<url> requires wp-cli/restful + Given an empty directory + + When I try `wp --http=foo.dev` + Then STDERR should be: + """ + Error: RESTful WP-CLI needs to be installed. Try 'wp package install wp-cli/restful'. + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 69ec48bc8..7f53d592b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -756,6 +756,10 @@ public function start() { } } + if ( isset( $this->config['http'] ) && ! class_exists( '\WP_REST_CLI\Runner' ) ) { + WP_CLI::error( "RESTful WP-CLI needs to be installed. Try 'wp package install wp-cli/restful'." ); + } + if ( isset( $this->config['require'] ) ) { foreach ( $this->config['require'] as $path ) { if ( ! file_exists( $path ) ) { diff --git a/php/config-spec.php b/php/config-spec.php index c54c99dbf..b3112b2fb 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -13,6 +13,12 @@ 'desc' => 'Perform operation against a remote server over SSH.', ), + 'http' => array( + 'runtime' => '=<http>', + 'file' => '<http>', + 'desc' => 'Perform operation against a remote WordPress install over HTTP.', + ), + 'url' => array( 'runtime' => '=<url>', 'file' => '<url>', From f47f3b47bb14c25e7243bf052ae943c1172cd05e Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:47:51 +0100 Subject: [PATCH 4697/5359] Make 'nightly' rather than 'trunk' the canonical term for nightly builds. --- features/core-download.feature | 32 ++++++++++++++++---------------- php/commands/core.php | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/features/core-download.feature b/features/core-download.feature index 2973f91fd..1d6f556e9 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -96,20 +96,20 @@ Feature: Download WordPress File removed: wp-content """ - Scenario: Installing trunk + Scenario: Installing nightly Given an empty directory And an empty cache - When I run `wp core download --version=trunk` + When I run `wp core download --version=nightly` Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should exist And STDOUT should contain: """ - Downloading WordPress trunk (en_US)... + Downloading WordPress nightly (en_US)... """ And STDERR should contain: """ - Warning: md5 hash checks are not available for trunk downloads. + Warning: md5 hash checks are not available for nightly downloads. """ And STDOUT should contain: """ @@ -117,19 +117,19 @@ Feature: Download WordPress """ # test core zip cache - When I run `wp core download --version=trunk --force` + When I run `wp core download --version=nightly --force` Then the wp-settings.php file should exist And STDOUT should contain: """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip'... + Using cached file '{SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip'... """ - Scenario: Installing trunk over an existing install + Scenario: Installing nightly over an existing install Given an empty directory And an empty cache When I run `wp core download --version=4.5.3` Then the wp-settings.php file should exist - When I run `wp core download --version=trunk --force` + When I run `wp core download --version=nightly --force` Then STDERR should not contain: """ Warning: Failed to find WordPress version. Please cleanup files manually. @@ -143,10 +143,10 @@ Feature: Download WordPress Success: WordPress downloaded. """ - Scenario: Installing a version over trunk + Scenario: Installing a version over nightly Given an empty directory And an empty cache - When I run `wp core download --version=trunk` + When I run `wp core download --version=nightly` Then the wp-settings.php file should exist And STDERR should not contain: """ @@ -161,19 +161,19 @@ Feature: Download WordPress File removed: wp-content """ - Scenario: Nightly is an alias for trunk + Scenario: Trunk is an alias for nightly Given an empty directory And an empty cache - When I run `wp core download --version=nightly` + When I run `wp core download --version=trunk` Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-trunk-en_US.zip file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should exist And STDOUT should contain: """ - Downloading WordPress trunk (en_US)... + Downloading WordPress nightly (en_US)... """ And STDERR should contain: """ - Warning: md5 hash checks are not available for trunk downloads. + Warning: md5 hash checks are not available for nightly downloads. """ And STDOUT should contain: """ diff --git a/php/commands/core.php b/php/commands/core.php index ad766deed..c6aa6c64b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -135,7 +135,7 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { $version = strtolower( $assoc_args['version'] ); - $version = ( 'nightly' === $version ? 'trunk' : $version ); + $version = ( 'trunk' === $version ? 'nightly' : $version ); $download_url = $this->get_download_url($version, $locale, 'tar.gz'); } else { $offer = $this->get_download_offer( $locale ); @@ -194,7 +194,7 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})." ); } - if ( 'trunk' !== $version ) { + if ( 'nightly' !== $version ) { $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); @@ -208,7 +208,7 @@ public function download( $args, $assoc_args ) { WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); } } else { - WP_CLI::warning( 'md5 hash checks are not available for trunk downloads.' ); + WP_CLI::warning( 'md5 hash checks are not available for nightly downloads.' ); } try { @@ -1394,7 +1394,7 @@ function update_db( $_, $assoc_args ) { */ private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { - if ( 'trunk' === $version ) { + if ( 'nightly' === $version ) { return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; } elseif ( 'en_US' === $locale ) { $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; From b460dd14b50933a9631b531f6dfb642e6cf6e4a9 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:50:10 +0100 Subject: [PATCH 4698/5359] Correct error message --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index c6aa6c64b..c25340552 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -262,7 +262,7 @@ private static function _extract_tarball( $tarball, $dest ) { private static function _extract_zip( $zipfile, $dest ) { if ( ! class_exists( 'ZipArchive' ) ) { - throw new \Exception( 'Extracting a zip file requires PharData' ); + throw new \Exception( 'Extracting a zip file requires ZipArchive.' ); } $zip = new ZipArchive(); $res = $zip->open( $zipfile ); From d150a21ef07df5c0c7f6dc384f38d4bb84ba81b7 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:50:27 +0100 Subject: [PATCH 4699/5359] Add early check so we don't download a zip file if we can't unzip it. --- php/commands/core.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index c25340552..08dce97eb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -159,6 +159,9 @@ public function download( $args, $assoc_args ) { $extension = 'tar.gz'; if ( 'zip' === $path_parts['extension'] ) { $extension = 'zip'; + if ( ! class_exists( 'ZipArchive' ) ) { + WP_CLI::error( 'Extracting a zip file requires ZipArchive.' ); + } } $cache = WP_CLI::get_cache(); From dfd697b966689134fadb63186bd1a325847d3f21 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:55:36 +0100 Subject: [PATCH 4700/5359] When requesting the download url of the nightly build, always request a zip file as tarballs are not available. --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 08dce97eb..3736046e3 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -136,7 +136,9 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { $version = strtolower( $assoc_args['version'] ); $version = ( 'trunk' === $version ? 'nightly' : $version ); - $download_url = $this->get_download_url($version, $locale, 'tar.gz'); + //nightly builds are only avialable in .zip format + $ext = ( 'nightly' === $version ? 'zip' : 'tar.gz' ); + $download_url = $this->get_download_url( $version, $locale, $ext ); } else { $offer = $this->get_download_offer( $locale ); if ( !$offer ) { From a3bc8422b2d74849c22d4af1dca53add399cecbf Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:56:17 +0100 Subject: [PATCH 4701/5359] Respond with an error if a tarball is requested for the nightly version. --- php/commands/core.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 3736046e3..12cd9a5e1 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1400,7 +1400,11 @@ function update_db( $_, $assoc_args ) { private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { if ( 'nightly' === $version ) { - return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; + if ( 'zip' === $version ) { + return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; + } else { + WP_CLI::error( 'Nightly builds are only available in .zip format.' ); + } } elseif ( 'en_US' === $locale ) { $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; From 6cc9cf4caee21caa44cae1266d7f259988f98247 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 21:59:40 +0100 Subject: [PATCH 4702/5359] Give an error if an unknown extension is requested. --- php/commands/core.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 12cd9a5e1..1501d09a4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -234,14 +234,18 @@ public function download( $args, $assoc_args ) { private static function _extract( $tarball_or_zip, $dest ) { $path_parts = pathinfo( $tarball_or_zip ); + $extension = strtolower( $path_parts['extension'] ); - switch ( strtolower( $path_parts['extension'] ) ) { + switch ( $extension ) { case 'zip': self::_extract_zip( $tarball_or_zip, $dest ); break; - default; + case 'tar.gz': self::_extract_tarball( $tarball_or_zip, $dest ); break; + default; + WP_CLI::error( sprintf( 'Extension %s not supported.', $extension ) ); + break; } } From 32eb232ada3c3f37685be15f7a4265a682e71366 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 22:00:57 +0100 Subject: [PATCH 4703/5359] Split ifelse statement up for readability. --- php/commands/core.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 1501d09a4..cd34db2b0 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1409,7 +1409,9 @@ private function get_download_url( $version, $locale = 'en_US', $file_type = 'zi } else { WP_CLI::error( 'Nightly builds are only available in .zip format.' ); } - } elseif ( 'en_US' === $locale ) { + } + + if ( 'en_US' === $locale ) { $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; return $url; From b5754758b82ceee6713a79e6ebbeecc4ff199e11 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 22:37:28 +0100 Subject: [PATCH 4704/5359] Fix typo - check file type not version --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index cd34db2b0..11e89de27 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1404,7 +1404,7 @@ function update_db( $_, $assoc_args ) { private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { if ( 'nightly' === $version ) { - if ( 'zip' === $version ) { + if ( 'zip' === $file_type ) { return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; } else { WP_CLI::error( 'Nightly builds are only available in .zip format.' ); From 649719a96c5502d59f83608315ea10ad3ad10c31 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 22:41:13 +0100 Subject: [PATCH 4705/5359] If a non-default locale is selected for the nightly build, exit with an error. Adds test. --- features/core-download.feature | 11 +++++++++++ php/commands/core.php | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/features/core-download.feature b/features/core-download.feature index 1d6f556e9..a4fddfdb0 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -179,3 +179,14 @@ Feature: Download WordPress """ Success: WordPress downloaded. """ + + Scenario: Installing nightly for a non-default locale + Given an empty directory + And an empty cache + + When I try `wp core download --version=nightly --locale=de_DE` + Then the return code should be 1 + And STDERR should contain: + """ + Error: Nightly builds are only available for the en_US locale. + """ diff --git a/php/commands/core.php b/php/commands/core.php index 11e89de27..d9729eabf 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -148,6 +148,10 @@ public function download( $args, $assoc_args ) { $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); } + if ( 'nightly' === $version && 'en_US' !== $locale ) { + WP_CLI::error( 'Nightly builds are only available for the en_US locale.' ); + } + $from_version = ''; if ( file_exists( $download_dir . 'wp-includes/version.php' ) ) { global $wp_version; From e9d7d8326fb448cb14ca049cb0d2ad3e7678f203 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Fri, 8 Jul 2016 22:45:55 +0100 Subject: [PATCH 4706/5359] Check for extension type, and return an error if the extension is not supported. --- php/commands/core.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index d9729eabf..d234e3a63 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -238,19 +238,16 @@ public function download( $args, $assoc_args ) { private static function _extract( $tarball_or_zip, $dest ) { $path_parts = pathinfo( $tarball_or_zip ); - $extension = strtolower( $path_parts['extension'] ); - switch ( $extension ) { - case 'zip': - self::_extract_zip( $tarball_or_zip, $dest ); - break; - case 'tar.gz': - self::_extract_tarball( $tarball_or_zip, $dest ); - break; - default; - WP_CLI::error( sprintf( 'Extension %s not supported.', $extension ) ); - break; + if ( preg_match( '/\.zip$/', $tarball_or_zip ) ) { + return self::_extract_zip( $tarball_or_zip, $dest ); } + + if ( preg_match( '/\.tar\.gz$/', $tarball_or_zip ) ) { + return self::_extract_tarball( $tarball_or_zip, $dest ); + } + + WP_CLI::error( sprintf( 'Extension %s not supported.', $extension ) ); } private static function _extract_tarball( $tarball, $dest ) { From b9d3a69f558696a938815e9d33005dd8f1342605 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Sat, 9 Jul 2016 00:22:04 +0100 Subject: [PATCH 4707/5359] Fix typo --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index d234e3a63..20715a577 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -136,7 +136,7 @@ public function download( $args, $assoc_args ) { if ( isset( $assoc_args['version'] ) ) { $version = strtolower( $assoc_args['version'] ); $version = ( 'trunk' === $version ? 'nightly' : $version ); - //nightly builds are only avialable in .zip format + //nightly builds are only available in .zip format $ext = ( 'nightly' === $version ? 'zip' : 'tar.gz' ); $download_url = $this->get_download_url( $version, $locale, $ext ); } else { From bad34e07f0b19cc636990a44d27f85d0515a68b1 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Sat, 9 Jul 2016 00:30:57 +0100 Subject: [PATCH 4708/5359] Don't cache nightly builds --- features/core-download.feature | 7 +++---- php/commands/core.php | 7 +++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/features/core-download.feature b/features/core-download.feature index a4fddfdb0..f08adcf13 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -102,7 +102,7 @@ Feature: Download WordPress When I run `wp core download --version=nightly` Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should exist + And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should not exist And STDOUT should contain: """ Downloading WordPress nightly (en_US)... @@ -116,10 +116,10 @@ Feature: Download WordPress Success: WordPress downloaded. """ - # test core zip cache + # we shouldn't cache nightly builds When I run `wp core download --version=nightly --force` Then the wp-settings.php file should exist - And STDOUT should contain: + And STDOUT should not contain: """ Using cached file '{SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip'... """ @@ -166,7 +166,6 @@ Feature: Download WordPress And an empty cache When I run `wp core download --version=trunk` Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should exist And STDOUT should contain: """ Downloading WordPress nightly (en_US)... diff --git a/php/commands/core.php b/php/commands/core.php index 20715a577..daa5891ab 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -225,8 +225,11 @@ public function download( $args, $assoc_args ) { } catch ( Exception $e ) { WP_CLI::error( "Couldn't extract WordPress archive. " . $e->getMessage() ); } - $cache->import( $cache_key, $temp ); - unlink($temp); + + if ( 'nightly' !== $version ) { + $cache->import( $cache_key, $temp ); + } + unlink( $temp ); } if ( $wordpress_present ) { From da09c5a95702b086b036e3dd37e94e55fbff7c29 Mon Sep 17 00:00:00 2001 From: Stephen Harris <contact@stephenharris.info> Date: Sat, 9 Jul 2016 00:31:33 +0100 Subject: [PATCH 4709/5359] Add details of acceptable values to --version documentation --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index daa5891ab..40ac3ed3b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -95,7 +95,7 @@ function check_update( $_, $assoc_args ) { * : Select which language you want to download. * * [--version=<version>] - * : Select which version you want to download. + * : Select which version you want to download. Accepts a version number, 'latest' or 'nightly' * * [--force] * : Overwrites existing files, if present. From 2217ca9bc1febdac917ebb29cd7d06ee2cbbbecd Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Sat, 9 Jul 2016 16:16:48 +0530 Subject: [PATCH 4710/5359] Add verbosity to wp role reset fixes #3110 --- php/commands/role.php | 87 +++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 2df328bd4..6d4c95b0b 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -260,70 +260,75 @@ public function reset( $args, $assoc_args ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { foreach( $default_roles as $role ) { + $before[ $role ] = get_role( $role ); remove_role( $role ); + $args[]= $role; } populate_roles(); + } else { - WP_CLI::success( 'All default roles reset.' ); - return; - - } - - foreach( $args as $k => $role_key ) { - $key = array_search( $role_key, $default_roles ); - if ( false !== $key ) { - unset( $preserve[ $key ] ); - $before[ $role_key ] = get_role( $role_key ); - remove_role( $role_key ); - } else { - unset( $args[ $k ] ); + foreach ( $args as $k => $role_key ) { + $key = array_search( $role_key, $default_roles ); + if ( false !== $key ) { + unset( $preserve[ $key ] ); + $before[ $role_key ] = get_role( $role_key ); + remove_role( $role_key ); + } else { + unset( $args[ $k ] ); + } } - } - $num_to_reset = count( $args ); + $num_to_reset = count( $args ); - // no roles were unset, bail - if ( count( $default_roles ) == count( $preserve ) ) { - WP_CLI::error( 'Must specify a default role to reset.' ); - } + // no roles were unset, bail + if ( count( $default_roles ) == count( $preserve ) ) { + WP_CLI::error( 'Must specify a default role to reset.' ); + } - // for the roles we're not resetting - foreach( $preserve as $k => $role ) { - /* save roles - * if get_role is null - * save role name for re-removal - */ - $roleobj = get_role( $role ); - $preserve[$k] = is_null( $roleobj ) ? $role : $roleobj; + // for the roles we're not resetting + foreach ( $preserve as $k => $role ) { + /* save roles + * if get_role is null + * save role name for re-removal + */ + $roleobj = get_role( $role ); + $preserve[ $k ] = is_null( $roleobj ) ? $role : $roleobj; - remove_role( $role ); - } + remove_role( $role ); + } - // put back all default roles and capabilities - populate_roles(); + // put back all default roles and capabilities + populate_roles(); - // restore the preserved roles - foreach( $preserve as $k => $roleobj ) { - // re-remove after populating - if ( is_a( $roleobj, 'WP_Role' ) ) { - remove_role( $roleobj->name ); - add_role( $roleobj->name, ucwords( $roleobj->name ), $roleobj->capabilities ); - } else { - // when not an object, that means the role didn't exist before - remove_role( $roleobj ); + // restore the preserved roles + foreach ( $preserve as $k => $roleobj ) { + // re-remove after populating + if ( is_a( $roleobj, 'WP_Role' ) ) { + remove_role( $roleobj->name ); + add_role( $roleobj->name, ucwords( $roleobj->name ), $roleobj->capabilities ); + } else { + // when not an object, that means the role didn't exist before + remove_role( $roleobj ); + } } } $num_reset = 0; + $args = array_unique( $args ); foreach( $args as $role_key ) { $after[ $role_key ] = get_role( $role_key ); if ( $after[ $role_key ] != $before[ $role_key ] ) { ++$num_reset; + $after_cap_count = count( $after[ $role_key ]->capabilities ); + $before_cap_count = count( $before[ $role_key ]->capabilities ); + WP_CLI::log( "Restored {$after_cap_count} capabilities to and removed {$before_cap_count} capabilities from '{$role_key}' role." ); + } else { + WP_CLI::log( "No changes necessary for '{$role_key}' role." ); } } - WP_CLI::success( "Reset $num_reset/$num_to_reset roles." ); + WP_CLI::success( "Success: Role reset." ); } From fb74d0bb916dd3c884e403741c3282bdc7de57b3 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Sat, 9 Jul 2016 16:48:33 +0530 Subject: [PATCH 4711/5359] Success message update --- php/commands/role.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/role.php b/php/commands/role.php index 6d4c95b0b..10858f981 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -328,7 +328,7 @@ public function reset( $args, $assoc_args ) { } } - WP_CLI::success( "Success: Role reset." ); + WP_CLI::success( "Role reset." ); } From e3bbcd5ab5d9ebaf6169a08cac9b2ef11fed4ade Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Sat, 9 Jul 2016 16:54:32 +0530 Subject: [PATCH 4712/5359] Update test for roles feature --- features/roles.feature | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 54631936d..b714e309e 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -20,33 +20,44 @@ Feature: Manage WordPress roles When I run `wp role reset author` Then STDOUT should be: """ - Success: Reset 0/1 roles. + No changes necessary for 'author' role. + Success: Role reset. """ When I run `wp cap remove author read` And I run `wp role reset author` Then STDOUT should be: """ - Success: Reset 1/1 roles. + Restored 10 capabilities to and removed 9 capabilities from 'author' role. + Success: Role reset. """ When I run `wp role reset author editor` Then STDOUT should be: """ - Success: Reset 0/2 roles. + No changes necessary for 'author' role. + No changes necessary for 'editor' role. + Success: Role reset. """ When I run `wp cap remove author read` And I run `wp role reset author editor` Then STDOUT should be: """ - Success: Reset 1/2 roles. + Restored 10 capabilities to and removed 9 capabilities from 'author' role. + No changes necessary for 'editor' role. + Success: Role reset. """ When I run `wp role reset --all` Then STDOUT should be: """ - Success: All default roles reset. + No changes necessary for 'administrator' role. + No changes necessary for 'editor' role. + No changes necessary for 'author' role. + No changes necessary for 'contributor' role. + No changes necessary for 'subscriber' role. + Success: Role reset. """ Scenario: Cloning a role From 9db0bfb8689ad3ab071b42adc956b3d302e1e3a2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 9 Jul 2016 05:39:02 -0700 Subject: [PATCH 4713/5359] Use `wp core download --version=trunk` in Travis --- ci/prepare.sh | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index bbf2aa502..852e3f760 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -30,14 +30,7 @@ echo $CLI_VERSION > PHAR_BUILD_VERSION # Install CodeSniffer things ./ci/prepare-codesniffer.sh -if [[ $WP_VERSION == "trunk" ]] -then - wget https://wordpress.org/nightly-builds/wordpress-latest.zip - unzip wordpress-latest.zip - mv wordpress '/tmp/wp-cli-test core-download-cache/' -else - ./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' -fi +./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' ./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' From fa07924fa5390de5bd9ee0f7547f1da31e2ba364 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 9 Jul 2016 05:48:22 -0700 Subject: [PATCH 4714/5359] Support `--http=<url>` in an alias --- php/WP_CLI/Configurator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 1e467e9d9..26780faaa 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -197,6 +197,7 @@ public function merge_yml( $path ) { 'url', 'path', 'ssh', + 'http', ) as $i ) { if ( isset( $value[ $i ] ) ) { $this->aliases[ $key ][ $i ] = $value[ $i ]; From 68ced63e51c25e243622ca96e5d8474ff8ca714d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 9 Jul 2016 05:56:38 -0700 Subject: [PATCH 4715/5359] Permit managing packages and running `wp cli info` over SSH --- php/WP_CLI/Runner.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 7f53d592b..72d81494d 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -727,14 +727,16 @@ public function start() { if ( empty( $this->arguments ) ) $this->arguments[] = 'help'; - // Protect 'cli info' from most of the runtime - if ( 'cli' === $this->arguments[0] && ! empty( $this->arguments[1] ) && 'info' === $this->arguments[1] ) { + // Protect 'cli info' from most of the runtime, + // except when the command will be run over SSH + if ( 'cli' === $this->arguments[0] && ! empty( $this->arguments[1] ) && 'info' === $this->arguments[1] && ! $this->config['ssh'] ) { $this->_run_command(); exit; } - // Protect 'package' commands from most of the runtime too - if ( 'package' === $this->arguments[0] ) { + // Protect 'package' commands from most of the runtime too, + // except when the command will be run over SSH + if ( 'package' === $this->arguments[0] && ! $this->config['ssh'] ) { $this->_run_command(); exit; } From f54d7078174e5baccca102f99188bb92f383cb4c Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Sat, 9 Jul 2016 20:05:51 +0530 Subject: [PATCH 4716/5359] Update reset role to show number of roles affected --- features/roles.feature | 10 +++++----- php/commands/role.php | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index b714e309e..536dc8883 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -21,7 +21,7 @@ Feature: Manage WordPress roles Then STDOUT should be: """ No changes necessary for 'author' role. - Success: Role reset. + Success: Roles reset 0/1. """ When I run `wp cap remove author read` @@ -29,7 +29,7 @@ Feature: Manage WordPress roles Then STDOUT should be: """ Restored 10 capabilities to and removed 9 capabilities from 'author' role. - Success: Role reset. + Success: Role reset 1/1. """ When I run `wp role reset author editor` @@ -37,7 +37,7 @@ Feature: Manage WordPress roles """ No changes necessary for 'author' role. No changes necessary for 'editor' role. - Success: Role reset. + Success: Roles reset 0/2. """ When I run `wp cap remove author read` @@ -46,7 +46,7 @@ Feature: Manage WordPress roles """ Restored 10 capabilities to and removed 9 capabilities from 'author' role. No changes necessary for 'editor' role. - Success: Role reset. + Success: Role reset 1/2. """ When I run `wp role reset --all` @@ -57,7 +57,7 @@ Feature: Manage WordPress roles No changes necessary for 'author' role. No changes necessary for 'contributor' role. No changes necessary for 'subscriber' role. - Success: Role reset. + Success: Roles reset 0/5. """ Scenario: Cloning a role diff --git a/php/commands/role.php b/php/commands/role.php index 10858f981..419d7624c 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -257,6 +257,7 @@ public function reset( $args, $assoc_args ) { // get our default roles $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); + $before = array(); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { foreach( $default_roles as $role ) { @@ -278,8 +279,6 @@ public function reset( $args, $assoc_args ) { } } - $num_to_reset = count( $args ); - // no roles were unset, bail if ( count( $default_roles ) == count( $preserve ) ) { WP_CLI::error( 'Must specify a default role to reset.' ); @@ -291,7 +290,7 @@ public function reset( $args, $assoc_args ) { * if get_role is null * save role name for re-removal */ - $roleobj = get_role( $role ); + $roleobj = get_role( $role ); $preserve[ $k ] = is_null( $roleobj ) ? $role : $roleobj; remove_role( $role ); @@ -315,6 +314,7 @@ public function reset( $args, $assoc_args ) { $num_reset = 0; $args = array_unique( $args ); + $num_to_reset = count( $args ); foreach( $args as $role_key ) { $after[ $role_key ] = get_role( $role_key ); @@ -328,7 +328,7 @@ public function reset( $args, $assoc_args ) { } } - WP_CLI::success( "Role reset." ); + WP_CLI::success( _n( 'Role', 'Roles', $num_reset ). " reset {$num_reset}/{$num_to_reset}." ); } From 764488c2e21061833ce84539aa86a5c08dd60179 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sun, 10 Jul 2016 06:49:40 +0545 Subject: [PATCH 4717/5359] Adding more explanation in doc of scaffold plugin --- php/commands/scaffold.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index d83f792c8..c78c8ed1b 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -409,16 +409,19 @@ private function get_output_path( $assoc_args, $subdir ) { * * * `plugin-slug.php` is the main PHP plugin file. * * `readme.txt` is the readme file for the plugin. - * * `package.json` needed by NPM holds various metadata relevant to the project. - * * `Gruntfile.js` is the JS file containing Grunt tasks. - * * `phpunit.xml.dist` is the configuration file for PHPUnit. + * * `package.json` needed by NPM holds various metadata relevant to the project. Packages: `grunt`, `grunt-wp-i18n` and `grunt-wp-readme-to-markdown`. + * * `Gruntfile.js` is the JS file containing Grunt tasks. Tasks: `i18n` containing `addtextdomain` and `makepot`, `readme` containing `wp_readme_to_markdown`. * * `.editorconfig` is the configuration file for Editor. * * `.gitignore` tells which files (or patterns) git should ignore. * * `.distignore` tells which files and folders should be ignored in distribution. + * + * The following files are also generated if tests are not skipped using `--skip-tests`: + * + * * `phpunit.xml.dist` is the configuration file for PHPUnit. * * `.travis.yml` is the configuration file for Travis CI. * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. - * * `tests/test-sample.php` is a sample file containing the actual tests. + * * `tests/test-sample.php` is a sample file containing test cases. * * ## OPTIONS * From aa09c41f8c7d9d36f7b9b21ab0523f14b0ec5cc4 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Sun, 10 Jul 2016 22:33:55 +0530 Subject: [PATCH 4718/5359] Add more verbosity to role reset command --- features/roles.feature | 14 +++++++------- php/commands/role.php | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 536dc8883..65daa3024 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -21,15 +21,15 @@ Feature: Manage WordPress roles Then STDOUT should be: """ No changes necessary for 'author' role. - Success: Roles reset 0/1. + Success: Role didn't need resetting. """ When I run `wp cap remove author read` And I run `wp role reset author` Then STDOUT should be: """ - Restored 10 capabilities to and removed 9 capabilities from 'author' role. - Success: Role reset 1/1. + Restored 1 capabilities to and removed 0 capabilities from 'author' role. + Success: Role reset. """ When I run `wp role reset author editor` @@ -37,16 +37,16 @@ Feature: Manage WordPress roles """ No changes necessary for 'author' role. No changes necessary for 'editor' role. - Success: Roles reset 0/2. + Success: No roles needed resetting. """ When I run `wp cap remove author read` And I run `wp role reset author editor` Then STDOUT should be: """ - Restored 10 capabilities to and removed 9 capabilities from 'author' role. + Restored 1 capabilities to and removed 0 capabilities from 'author' role. No changes necessary for 'editor' role. - Success: Role reset 1/2. + Success: 1 of 2 roles reset. """ When I run `wp role reset --all` @@ -57,7 +57,7 @@ Feature: Manage WordPress roles No changes necessary for 'author' role. No changes necessary for 'contributor' role. No changes necessary for 'subscriber' role. - Success: Roles reset 0/5. + Success: No roles needed resetting. """ Scenario: Cloning a role diff --git a/php/commands/role.php b/php/commands/role.php index 419d7624c..16e37cf9c 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -320,16 +320,28 @@ public function reset( $args, $assoc_args ) { if ( $after[ $role_key ] != $before[ $role_key ] ) { ++$num_reset; - $after_cap_count = count( $after[ $role_key ]->capabilities ); - $before_cap_count = count( $before[ $role_key ]->capabilities ); - WP_CLI::log( "Restored {$after_cap_count} capabilities to and removed {$before_cap_count} capabilities from '{$role_key}' role." ); + $restored_cap = array_diff_key( $after[ $role_key ]->capabilities, $before[ $role_key ]->capabilities ); + $removed_cap = array_diff_key( $before[ $role_key ]->capabilities, $after[ $role_key ]->capabilities ); + $restored_cap_count = count( $restored_cap ); + $removed_cap_count = count( $removed_cap ); + WP_CLI::log( "Restored {$restored_cap_count} capabilities to and removed {$removed_cap_count} capabilities from '{$role_key}' role." ); } else { WP_CLI::log( "No changes necessary for '{$role_key}' role." ); } } - - WP_CLI::success( _n( 'Role', 'Roles', $num_reset ). " reset {$num_reset}/{$num_to_reset}." ); - + if ( $num_reset ) { + if ( 1 === count( $args ) ) { + WP_CLI::success( 'Role reset.' ); + } else { + WP_CLI::success( "{$num_reset} of {$num_to_reset} roles reset." ); + } + } else { + if ( 1 === count( $args ) ) { + WP_CLI::success( 'Role didn\'t need resetting.' ); + } else { + WP_CLI::success( 'No roles needed resetting.' ); + } + } } private static function persistence_check() { From f7426da64866c93fa8a34dec8b011d2ce1309b2f Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 11 Jul 2016 16:33:57 +0545 Subject: [PATCH 4719/5359] Improving doc and default value in core commands --- php/commands/core.php | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 40ac3ed3b..eafc38a57 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -318,7 +318,7 @@ private static function _copy_overwrite_files( $source, $dest ) { copy( $item, $dest_path ); } else { $error = 1; - WP_CLI::warning( 'Unable to copy ' . $iterator->getSubPathName() . ' to current directory.' ); + WP_CLI::warning( "Unable to copy '" . $iterator->getSubPathName() . "' to current directory." ); } } } @@ -390,16 +390,28 @@ private static function get_initial_locale() { * : Set the database user password. * * [--dbhost=<dbhost>] - * : Set the database host. Default: 'localhost' + * : Set the database host. + * --- + * default: localhost + * --- * * [--dbprefix=<dbprefix>] - * : Set the database table prefix. Default: 'wp_' + * : Set the database table prefix. + * --- + * default: wp_ + * --- * * [--dbcharset=<dbcharset>] - * : Set the database charset. Default: 'utf8' + * : Set the database charset. + * --- + * default: utf8 + * --- * * [--dbcollate=<dbcollate>] - * : Set the database collation. Default: '' + * : Set the database collation. + * --- + * default: + * --- * * [--locale=<locale>] * : Set the WPLANG constant. Defaults to $wp_local_package variable. @@ -488,7 +500,7 @@ public function config( $_, $assoc_args ) { * Determine if the WordPress tables are installed. * * [--network] - * : Check if this is a multisite install + * : Check if this is a multisite install. * * ## EXAMPLES * @@ -578,7 +590,9 @@ public function install( $args, $assoc_args ) { * * [--base=<url-path>] * : Base path after the domain name that each site url will start with. - * Default: '/' + * --- + * default: / + * --- * * [--subdomains] * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. @@ -617,7 +631,9 @@ public function multisite_convert( $args, $assoc_args ) { * * [--base=<url-path>] * : Base path after the domain name that each site url in the network will start with. - * Default: '/' + * --- + * default: / + * --- * * [--subdomains] * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. @@ -626,7 +642,10 @@ public function multisite_convert( $args, $assoc_args ) { * : The title of the new site. * * --admin_user=<username> - * : The name of the admin user. Default: 'admin' + * : The name of the admin user. + * --- + * default: admin + * --- * * --admin_password=<password> * : The password for the admin user. @@ -1333,7 +1352,7 @@ function update( $args, $assoc_args ) { * * # Update the WordPress database * $ wp core update-db - * Success: WordPress database upgraded successfully from db version 36686 to 35700 + * Success: WordPress database upgraded successfully from db version 36686 to 35700. * * # Update databases for all sites on a network * $ wp core update-db --network From a7243fa1ef06ff249b8bd9bda44286a2d892302f Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Mon, 11 Jul 2016 23:15:07 +0530 Subject: [PATCH 4720/5359] Role reset, custom role not affected verbosity add --- features/roles.feature | 40 ++++++++++++++++++++++++++++++++++++++++ php/commands/role.php | 17 +++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/features/roles.feature b/features/roles.feature index 65daa3024..2c6a9fb34 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -60,6 +60,46 @@ Feature: Manage WordPress roles Success: No roles needed resetting. """ + When I run `wp role create custom-role "Custom role" --clone=author` + And I run `wp role reset --all` + Then STDOUT should be: + """ + Custom role 'custom-role' not affected. + No changes necessary for 'administrator' role. + No changes necessary for 'editor' role. + No changes necessary for 'author' role. + No changes necessary for 'contributor' role. + No changes necessary for 'subscriber' role. + Success: No roles needed resetting. + """ + + When I try `wp role reset custom-role` + Then STDERR should contain: + """ + Error: Must specify a default role to reset. + """ + And STDOUT should contain: + """ + Custom role 'custom-role' not affected. + """ + + When I run `wp role reset custom-role author` + Then STDOUT should be: + """ + Custom role 'custom-role' not affected. + No changes necessary for 'author' role. + Success: Role didn't need resetting. + """ + + When I run `wp cap remove author read` + And I run `wp role reset custom-role author` + Then STDOUT should be: + """ + Custom role 'custom-role' not affected. + Restored 1 capabilities to and removed 0 capabilities from 'author' role. + Success: Role reset. + """ + Scenario: Cloning a role When I try `wp role create reporter Reporter --clone=no-role` Then STDERR should be: diff --git a/php/commands/role.php b/php/commands/role.php index 16e37cf9c..0be1a4116 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -255,6 +255,10 @@ public function reset( $args, $assoc_args ) { require_once( ABSPATH.'wp-admin/includes/schema.php' ); } + global $wp_roles; + $all_roles = array_keys( $wp_roles->roles ); + $preserve_args = $args; + // get our default roles $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); $before = array(); @@ -266,6 +270,12 @@ public function reset( $args, $assoc_args ) { $args[]= $role; } populate_roles(); + $not_affected_roles = array_diff( $all_roles, $default_roles ); + if ( ! empty( $not_affected_roles ) ) { + foreach ( $not_affected_roles as $not_affected_role ) { + WP_CLI::log( "Custom role '{$not_affected_role}' not affected." ); + } + } } else { foreach ( $args as $k => $role_key ) { @@ -279,6 +289,13 @@ public function reset( $args, $assoc_args ) { } } + $not_affected_roles = array_diff( $preserve_args, $default_roles ); + if ( ! empty( $not_affected_roles ) ) { + foreach ( $not_affected_roles as $not_affected_role ) { + WP_CLI::log( "Custom role '{$not_affected_role}' not affected." ); + } + } + // no roles were unset, bail if ( count( $default_roles ) == count( $preserve ) ) { WP_CLI::error( 'Must specify a default role to reset.' ); From 01a06102ef6dddaee153c15aadc1d559417ed394 Mon Sep 17 00:00:00 2001 From: andyexeter <palmer.andy@gmail.com> Date: Mon, 11 Jul 2016 19:29:15 +0100 Subject: [PATCH 4721/5359] Add include-columns flag to search-replace --- php/commands/search-replace.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index a67790ded..bc2bd8976 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -37,6 +37,7 @@ class Search_Replace_Command extends WP_CLI_Command { private $recurse_objects; private $regex; private $skip_columns; + private $include_columns; /** * Search/replace strings in the database. @@ -95,6 +96,10 @@ class Search_Replace_Command extends WP_CLI_Command { * : Do not perform the replacement on specific columns. Use commas to * specify multiple columns. 'guid' is skipped by default. * + * [--include-columns=<columns>] + * : Perform the replacement on specific columns. Use commas to + * specify multiple columns. + * * [--precise] * : Force the use of PHP (instead of SQL) which is more thorough, * but slower. @@ -145,6 +150,7 @@ public function __invoke( $args, $assoc_args ) { $this->regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); $this->skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); + $this->include_columns = array_filter( explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-columns' ) ) ); if ( $old === $new && ! $this->regex ) { WP_CLI::warning( "Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation." ); @@ -201,6 +207,10 @@ public function __invoke( $args, $assoc_args ) { } foreach ( $columns as $col ) { + if ( ! empty( $this->include_columns ) && ! in_array( $col, $this->include_columns ) ) { + continue; + } + if ( in_array( $col, $this->skip_columns ) ) { continue; } From 225254cc4606f715179387f5370f2c91acfbc9b2 Mon Sep 17 00:00:00 2001 From: andyexeter <palmer.andy@gmail.com> Date: Mon, 11 Jul 2016 19:34:09 +0100 Subject: [PATCH 4722/5359] Add functional test for include-columns flag of search-replace --- features/search-replace.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/search-replace.feature b/features/search-replace.feature index 2fd3e14e8..76705781d 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -15,6 +15,12 @@ Feature: Do global search/replace guid """ + When I run `wp search-replace foo bar --include-columns=post_content` + Then STDOUT should not contain: + """ + guid + """ + Scenario: Multisite search/replace Given a WP multisite install And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` From ae4898399c52a19429f5e0a7903a3d449fb20ea0 Mon Sep 17 00:00:00 2001 From: andyexeter <palmer.andy@gmail.com> Date: Mon, 11 Jul 2016 20:47:52 +0100 Subject: [PATCH 4723/5359] Add more explicit test for include-columns flag --- features/search-replace.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 76705781d..02cd30988 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -16,10 +16,10 @@ Feature: Do global search/replace """ When I run `wp search-replace foo bar --include-columns=post_content` - Then STDOUT should not contain: - """ - guid - """ + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_posts | post_content | 0 | SQL | + Scenario: Multisite search/replace Given a WP multisite install From 2ceb45341b52714e8f3e9d44da7cfa49c7c88ea8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Jul 2016 05:21:23 -0700 Subject: [PATCH 4724/5359] Add `--ci=<provider>` argument for plugin test scaffold First up: CircleCI, which has a free private build plan. --- features/scaffold.feature | 21 +++++++++++++++++- php/commands/scaffold.php | 22 +++++++++++++++---- templates/plugin-circle.mustache | 9 ++++++++ ...travis.mustache => plugin-travis.mustache} | 0 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 templates/plugin-circle.mustache rename templates/{.travis.mustache => plugin-travis.mustache} (100%) diff --git a/features/scaffold.feature b/features/scaffold.feature index 8c0e6f661..0e4796cdf 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -306,7 +306,11 @@ Feature: WordPress code scaffolding install-wp-tests.sh """ And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist - And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist + And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist + And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: + """ + script: phpunit + """ When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` Then STDOUT should be: @@ -314,6 +318,21 @@ Feature: WordPress code scaffolding executable """ + Scenario: Scaffold plugin tests with Circle as the provider + Given a WP install + And I run `wp scaffold plugin hello-world --skip-tests` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin-tests hello-world --ci=circle` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/circle.yml file should contain: + """ + version: 5.6.14 + """ + Scenario: Scaffold starter code for a theme Given a WP install Given I run `wp theme path` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c78c8ed1b..ec2b0d728 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -531,7 +531,7 @@ function plugin( $args, $assoc_args ) { * The following files are generated for your plugin by this command: * * * `phpunit.xml.dist` is the configuration file for PHPUnit. - * * `.travis.yml` is the configuration file for Travis CI. + * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. * * `tests/test-sample.php` is a sample file containing the actual tests. @@ -551,6 +551,15 @@ function plugin( $args, $assoc_args ) { * [--dir=<dirname>] * : Generate test files for a non-standard plugin path. If no plugin slug is specified, the directory name is used. * + * [--ci=<provider>] + * : Add a configuration file for a continuous integration provider. + * --- + * default: travis + * options: + * - travis + * - circle + * --- + * * [--force] * : Overwrite files that already exist. * @@ -616,11 +625,16 @@ function plugin_tests( $args, $assoc_args ) { ); $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_written = $this->create_files( array( + $files_to_create = array( "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', $plugin_data ), "$tests_dir/test-sample.php" => Utils\mustache_render( 'test-sample.mustache', $plugin_data ), - "$plugin_dir/.travis.yml" => Utils\mustache_render( '.travis.mustache', compact( 'wp_versions_to_test' ) ), - ), $force ); + ); + if ( 'travis' === $assoc_args['ci'] ) { + $files_to_create["$plugin_dir/.travis.yml"] = Utils\mustache_render( 'plugin-travis.mustache', compact( 'wp_versions_to_test' ) ); + } else if ( 'circle' === $assoc_args['ci'] ) { + $files_to_create["$plugin_dir/circle.yml"] = Utils\mustache_render( 'plugin-circle.mustache' ); + } + $files_written = $this->create_files( $files_to_create, $force ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache new file mode 100644 index 000000000..6f1ded776 --- /dev/null +++ b/templates/plugin-circle.mustache @@ -0,0 +1,9 @@ +machine: + php: + version: 5.6.14 + +test: + pre: + - bash bin/install-wp-tests.sh wordpress_test root '' localhost latest + override: + - phpunit diff --git a/templates/.travis.mustache b/templates/plugin-travis.mustache similarity index 100% rename from templates/.travis.mustache rename to templates/plugin-travis.mustache From fc1c1e888c8f05acdb2b9cedebedae2a283aa2a4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Jul 2016 09:31:38 -0700 Subject: [PATCH 4725/5359] Define alias regex in one place, and reuse This will prevent it from getting out of sync throughout the codebase. --- php/WP_CLI/Configurator.php | 10 +++++++--- php/WP_CLI/Runner.php | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 26780faaa..6c0e852f0 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -29,6 +29,11 @@ class Configurator { */ private $aliases = array(); + /** + * @var string ALIAS_REGEX Regex pattern used to define an alias + */ + const ALIAS_REGEX = '^@[A-Za-z0-9-_]+$'; + /** * @param string $path Path to config spec file. */ @@ -187,9 +192,8 @@ public function merge_yml( $path ) { if ( ! empty( $yaml['_']['inherit'] ) ) { $this->merge_yml( $yaml['_']['inherit'] ); } - $alias_regex = '#^@[A-Za-z0-9-_]+$#'; foreach ( $yaml as $key => $value ) { - if ( preg_match( $alias_regex, $key ) ) { + if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { $this->aliases[ $key ] = array(); $is_alias = false; foreach( array( @@ -208,7 +212,7 @@ public function merge_yml( $path ) { if ( ! $is_alias && is_array( $value ) ) { $alias_group = array(); foreach( $value as $i => $k ) { - if ( preg_match( $alias_regex, $k ) ) { + if ( preg_match( '#' . self::ALIAS_REGEX . '#', $k ) ) { $alias_group[] = $k; } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 72d81494d..d526256f3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -596,7 +596,7 @@ private function init_config() { $argv = array_slice( $GLOBALS['argv'], 1 ); - if ( ! empty( $argv[0] ) && preg_match( '#^@[A-Za-z0-9-_]+$#', $argv[0], $matches ) ) { + if ( ! empty( $argv[0] ) && preg_match( '#' . Configurator::ALIAS_REGEX . '#', $argv[0], $matches ) ) { $this->alias = array_shift( $argv ); } else { $this->alias = null; From 1d0abb829796c561cff3caa01d406a48e98d73e3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Jul 2016 15:18:49 -0700 Subject: [PATCH 4726/5359] Include example command in README.md It's better to show than tell. --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index db835e169..f0a466732 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,36 @@ If you have a WordPress.org account, you may also consider joining the `#cli` ch A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. +WP-CLI supports registering any callable class, function, or closure as a command. It reads usage details from the callback's PHPdoc. `WP_CLI::add_command()` ([doc](https://wp-cli.org/docs/internal-api/wp-cli-add-command/)) is used for both internal and third-party command registration. + +``` +/** + * Delete an option from the database. + * + * Returns an error if the option didn't exist. + * + * ## OPTIONS + * + * <key> + * : Key for the option. + * + * ## EXAMPLES + * + * $ wp option delete my_option + * Success: Deleted 'my_option' option. + */ +$delete_option_cmd = function( $args ) { + list( $key ) = $args; + + if ( ! delete_option( $key ) ) { + WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); + } else { + WP_CLI::success( "Deleted '$key' option." ); + } +}; +WP_CLI::add_command( 'option delete', $delete_option_cmd ); +``` + WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](https://wp-cli.org/docs/internal-api/) to discover a variety of helpful functions you can use in your custom WP-CLI command. ## Contributing From b4239a9aec86aa1603f702164b6fbfc827a515f0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Jul 2016 15:49:12 -0700 Subject: [PATCH 4727/5359] Add missing ## OPTIONS heading throughout --- php/commands/help.php | 2 ++ php/commands/option.php | 6 ++++++ php/commands/super-admin.php | 4 ++++ php/commands/transient.php | 6 ++++++ php/commands/user.php | 6 ++++++ php/commands/widget.php | 14 ++++++++++++++ 6 files changed, 38 insertions(+) diff --git a/php/commands/help.php b/php/commands/help.php index 7210df898..d07b2802c 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -8,6 +8,8 @@ class Help_Command extends WP_CLI_Command { /** * Get help on WP-CLI, or on a specific command. * + * ## OPTIONS + * * [<command>...] * : Get help on a specific command. * diff --git a/php/commands/option.php b/php/commands/option.php index 2da0138e3..2da6e107d 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -31,6 +31,8 @@ class Option_Command extends WP_CLI_Command { /** * Get an option. * + * ## OPTIONS + * * <key> * : Key for the option. * @@ -122,6 +124,8 @@ public function add( $args, $assoc_args ) { /** * List options. * + * ## OPTIONS + * * [--search=<pattern>] * : Use wildcards ( * and ? ) to match option name. * @@ -313,6 +317,8 @@ public function update( $args, $assoc_args ) { /** * Delete an option. * + * ## OPTIONS + * * <key> * : Key for the option. * diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 2537a326e..d0982a9c9 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -80,6 +80,8 @@ public function _list( $_, $assoc_args ) { /** * Grant super-admin privileges to one or more users. * + * ## OPTIONS + * * <user>... * : One or more user IDs, user emails, or user logins. * @@ -125,6 +127,8 @@ public function add( $args, $_ ) { /** * Revoke super-admin privileges to one or more users. * + * ## OPTIONS + * * <user>... * : One or more user IDs, user emails, or user logins. * diff --git a/php/commands/transient.php b/php/commands/transient.php index 3797d11fc..d68f4950c 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -30,6 +30,8 @@ class Transient_Command extends WP_CLI_Command { /** * Get a transient value. * + * ## OPTIONS + * * <key> * : Key for the transient. * @@ -72,6 +74,8 @@ public function get( $args, $assoc_args ) { /** * Set a transient value. <expiration> is the time until expiration, in seconds. * + * ## OPTIONS + * * <key> * : Key for the transient. * @@ -105,6 +109,8 @@ public function set( $args, $assoc_args ) { /** * Delete a transient value. * + * ## OPTIONS + * * <key> * : Key for the transient. * diff --git a/php/commands/user.php b/php/commands/user.php index b0f93dff4..9da51cec7 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -995,6 +995,8 @@ public function get( $args, $assoc_args ) { /** * Delete a meta field. * + * ## OPTIONS + * * <user> * : The user login, user email, or user ID of the user to delete metadata from. * @@ -1018,6 +1020,8 @@ public function delete( $args, $assoc_args ) { /** * Add a meta field. * + * ## OPTIONS + * * <user> * : The user login, user email, or user ID of the user to add metadata for. * @@ -1044,6 +1048,8 @@ public function add( $args, $assoc_args ) { /** * Update a meta field. * + * ## OPTIONS + * * <user> * : The user login, user email, or user ID of the user to update metadata for. * diff --git a/php/commands/widget.php b/php/commands/widget.php index 1def3cb79..5d4c47213 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -39,6 +39,8 @@ class Widget_Command extends WP_CLI_Command { /** * List widgets associated with a sidebar. * + * ## OPTIONS + * * <sidebar-id> * : ID for the corresponding sidebar. * @@ -98,6 +100,8 @@ public function list_( $args, $assoc_args ) { /** * Add a widget to a sidebar. * + * ## OPTIONS + * * <name> * : Widget name. * @@ -155,6 +159,8 @@ public function add( $args, $assoc_args ) { /** * Update a given widget's options. * + * ## OPTIONS + * * <widget-id> * : Unique ID for the widget * @@ -191,6 +197,8 @@ public function update( $args, $assoc_args ) { /** * Move a widget from one position on a sidebar to another. * + * ## OPTIONS + * * <widget-id> * : Unique ID for the widget * @@ -242,6 +250,8 @@ public function move( $args, $assoc_args ) { /** * Deactivate one or more widgets from an active sidebar. * + * ## OPTIONS + * * <widget-id>... * : Unique ID for the widget(s) * @@ -273,6 +283,8 @@ public function deactivate( $args, $assoc_args ) { /** * Delete one or more widgets from a sidebar. * + * ## OPTIONS + * * <widget-id>... * : Unique ID for the widget(s) * @@ -309,6 +321,8 @@ public function delete( $args, $assoc_args ) { * * Removes all widgets from the sidebar and places them in Inactive Widgets. * + * ## OPTIONS + * * [<sidebar-id>...] * : One or more sidebars to reset. * From 61fe48013f208877baebd4db1ea4132a1bfc29a5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 12 Jul 2016 15:55:17 -0700 Subject: [PATCH 4728/5359] Remove ## OPTIONS from meta classes These won't be rendered in the appropriate place. --- php/commands/network.php | 8 -------- php/commands/post.php | 5 ----- php/commands/term.php | 5 ----- 3 files changed, 18 deletions(-) diff --git a/php/commands/network.php b/php/commands/network.php index 3b0c47ddb..50905b567 100644 --- a/php/commands/network.php +++ b/php/commands/network.php @@ -3,14 +3,6 @@ /** * Manage network custom fields. * - * ## OPTIONS - * - * <id> - * : The network id (usually 1). - * - * --format=json - * : Encode/decode values as JSON. - * * ## EXAMPLES * * # Get a list of super-admins diff --git a/php/commands/post.php b/php/commands/post.php index b84feb628..890a7baa4 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -593,11 +593,6 @@ private function read_from_file_or_stdin( $arg ) { /** * Manage post custom fields. * - * ## OPTIONS - * - * [--format=json] - * : Encode/decode values as JSON. - * * ## EXAMPLES * * # Set post meta diff --git a/php/commands/term.php b/php/commands/term.php index 8b784ca42..c12b9fb54 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -566,11 +566,6 @@ private function get_formatter( &$assoc_args ) { /** * Manage term custom fields. * - * ## OPTIONS - * - * --format=json - * : Encode/decode values as JSON. - * * ## EXAMPLES * * # Set term meta From 4e3ffa3ebffd8818f3d76c248462b99e05198b10 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 13 Jul 2016 12:15:41 +0545 Subject: [PATCH 4729/5359] Add examples for cache commands --- php/commands/cache.php | 82 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index 299939980..b887cea95 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -3,11 +3,19 @@ /** * Manage the object cache. * + * Note: Persistent Object Caching is needed for these commands. + * * ## EXAMPLES * - * wp cache set my_key my_value my_group 300 + * # Set cache. + * $ wp cache set my_key my_value my_group 300 + * Success: Set object 'my_key' in group 'my_group'. + * + * # Get cache. + * $ wp cache get my_key my_group + * my_value * - * wp cache get my_key my_group + * @package wp-cli */ class Cache_Command extends WP_CLI_Command { @@ -28,7 +36,16 @@ class Cache_Command extends WP_CLI_Command { * : Method for grouping data within the cache which allows the same key to be used across groups. * * [<expiration>] - * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). + * : Define how long to keep the value, in seconds. `0` means as long as possible. + * --- + * default: 0 + * --- + * + * ## EXAMPLES + * + * # Add cache. + * $ wp cache add my_key my_group my_value 300 + * Success: Added object 'my_key' in group 'my_value'. */ public function add( $args, $assoc_args ) { list( $key, $value ) = $args; @@ -57,6 +74,12 @@ public function add( $args, $assoc_args ) { * * [<group>] * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * ## EXAMPLES + * + * # Decrease cache value. + * $ wp cache decr my_key 2 my_group + * 48 */ public function decr( $args, $assoc_args ) { $key = $args[0]; @@ -84,6 +107,12 @@ public function decr( $args, $assoc_args ) { * * [<group>] * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * ## EXAMPLES + * + * # Delete cache. + * $ wp cache delete my_key my_group + * Success: Object deleted. */ public function delete( $args, $assoc_args ) { $key = $args[0]; @@ -104,6 +133,12 @@ public function delete( $args, $assoc_args ) { * * For sites using a persistent object cache, because WordPress Multisite simply adds a blog id * to the cache key, flushing cache is typically a global operation. + * + * ## EXAMPLES + * + * # Flush cache. + * $ wp cache flush + * Success: The cache was flushed. */ public function flush( $args, $assoc_args ) { $value = wp_cache_flush(); @@ -125,6 +160,12 @@ public function flush( $args, $assoc_args ) { * * [<group>] * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * ## EXAMPLES + * + * # Get cache. + * $ wp cache get my_key my_group + * my_value */ public function get( $args, $assoc_args ) { $key = $args[0]; @@ -153,6 +194,12 @@ public function get( $args, $assoc_args ) { * * [<group>] * : Method for grouping data within the cache which allows the same key to be used across groups. + * + * ## EXAMPLES + * + * # Increase cache value. + * $ wp cache incr my_key 2 my_group + * 50 */ public function incr( $args, $assoc_args ) { $key = $args[0]; @@ -185,7 +232,16 @@ public function incr( $args, $assoc_args ) { * : Method for grouping data within the cache which allows the same key to be used across groups. * * [<expiration>] - * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). + * : Define how long to keep the value, in seconds. `0` means as long as possible. + * --- + * default: 0 + * --- + * + * ## EXAMPLES + * + * # Replace cache. + * $ wp cache replace my_key new_value my_group + * Success: Replaced object 'my_key' in group 'my_group'. */ public function replace( $args, $assoc_args ) { list( $key, $value ) = $args; @@ -218,7 +274,16 @@ public function replace( $args, $assoc_args ) { * : Method for grouping data within the cache which allows the same key to be used across groups. * * [<expiration>] - * : Define how long to keep the value, in seconds. Defaults to 0 (as long as possible). + * : Define how long to keep the value, in seconds. `0` means as long as possible. + * --- + * default: 0 + * --- + * + * ## EXAMPLES + * + * # Set cache. + * $ wp cache set my_key my_value my_group 300 + * Success: Set object 'my_key' in group 'my_group'. */ public function set( $args, $assoc_args ) { list( $key, $value ) = $args; @@ -242,6 +307,12 @@ public function set( $args, $assoc_args ) { * Note that the guesses made by this function are based on the WP_Object_Cache classes * that define the 3rd party object cache extension. Changes to those classes could render * problems with this function's ability to determine which object cache is being used. + * + * ## EXAMPLES + * + * # Check cache type. + * $ wp cache type + * Default */ public function type( $args, $assoc_args ) { $message = WP_CLI\Utils\wp_get_cache_type(); @@ -250,4 +321,3 @@ public function type( $args, $assoc_args ) { } WP_CLI::add_command( 'cache', 'Cache_Command' ); - From bf88da2240176d05a7d06aa537d70ab342c59375 Mon Sep 17 00:00:00 2001 From: "Peter J. Herrel" <peterherrel@gmail.com> Date: Wed, 13 Jul 2016 12:33:02 +0200 Subject: [PATCH 4730/5359] add example: delete users by role --- php/commands/user.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 9da51cec7..3b8dd2d23 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -210,6 +210,11 @@ public function get( $args, $assoc_args ) { * # Delete user 123 and reassign posts to user 567 * $ wp user delete 123 --reassign=567 * Success: Removed user 123 from http://example.com + * + * # Delete all contributors and reassign their posts to user 2 + * $ wp user delete $(wp user list --role=contributor --format=ids) --reassign=2 + * Success: Removed user 813 from http://example.com + * Success: Removed user 578 from http://example.com */ public function delete( $args, $assoc_args ) { $network = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); From 3967f23d0ed7064455776deacca923c82b7a4b47 Mon Sep 17 00:00:00 2001 From: Enrico Sorcinelli <enrico.sorcinelli@italiaonline.it> Date: Thu, 14 Jul 2016 12:16:37 +0200 Subject: [PATCH 4731/5359] Add forward slash in the end to --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 4f5335586..1d4880756 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -83,7 +83,7 @@ install_test_suite() { if [ ! -f wp-tests-config.php ]; then download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php From 5e1da5f9223816f3f056f981a0b7230d3a889d7d Mon Sep 17 00:00:00 2001 From: Enrico Sorcinelli <enrico.sorcinelli@italiaonline.it> Date: Thu, 14 Jul 2016 15:04:35 +0200 Subject: [PATCH 4732/5359] remove all forward slashes in the end from --- templates/install-wp-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 1d4880756..618bdf94c 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -83,6 +83,8 @@ install_test_suite() { if [ ! -f wp-tests-config.php ]; then download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + # remove all forward slashes in the end + WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php From ab6ee822692bb0edb68e5009b66a4a550ae4c734 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 14 Jul 2016 06:05:18 -0700 Subject: [PATCH 4733/5359] Make sure WordPress receives the slashed data it expects --- features/post.feature | 19 +++++++++++++++++++ php/commands/post.php | 2 ++ 2 files changed, 21 insertions(+) diff --git a/features/post.feature b/features/post.feature index d33e825b2..ec73f3da7 100644 --- a/features/post.feature +++ b/features/post.feature @@ -204,3 +204,22 @@ Feature: Manage WordPress posts """ [{"name":"Test Category"}] """ + + Scenario: Make sure WordPress receives the slashed data it expects + When I run `wp post create --post_title='My\Post' --porcelain` + Then save STDOUT as {POST_ID} + + When I run `wp post get {POST_ID} --field=title` + Then STDOUT should be: + """ + My\Post + """ + + When I run `wp post update {POST_ID} --post_content='var isEmailValid = /^\S+@\S+.\S+$/.test(email);'` + Then STDOUT should not be empty + + When I run `wp post get {POST_ID} --field=content` + Then STDOUT should be: + """ + var isEmailValid = /^\S+@\S+.\S+$/.test(email); + """ diff --git a/php/commands/post.php b/php/commands/post.php index 890a7baa4..c9744f904 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -86,6 +86,7 @@ public function create( $args, $assoc_args ) { $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); } + $assoc_args = wp_slash( $assoc_args ); parent::_create( $args, $assoc_args, function ( $params ) { return wp_insert_post( $params, true ); } ); @@ -133,6 +134,7 @@ public function update( $args, $assoc_args ) { $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); } + $assoc_args = wp_slash( $assoc_args ); parent::_update( $args, $assoc_args, function ( $params ) { return wp_update_post( $params, true ); } ); From ae3b310de1a6d5cbe84e8ddca6188c628464f5b2 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 15 Jul 2016 11:22:11 +0545 Subject: [PATCH 4734/5359] Pass slashed data for term --- php/commands/term.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/term.php b/php/commands/term.php index c12b9fb54..0bce81736 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -192,6 +192,8 @@ public function create( $args, $assoc_args ) { WP_CLI::error( 'Parent term does not exist.' ); } + $assoc_args = wp_slash( $assoc_args ); + $term = wp_slash( $term ); $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); if ( is_wp_error( $ret ) ) { @@ -302,6 +304,7 @@ public function update( $args, $assoc_args ) { unset( $assoc_args[$key] ); } + $assoc_args = wp_slash( $assoc_args ); $ret = wp_update_term( $term_id, $taxonomy, $assoc_args ); if ( is_wp_error( $ret ) ) From 2748d5a67b40cd1681f5fe50640b5b475760dde5 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 15 Jul 2016 11:25:07 +0545 Subject: [PATCH 4735/5359] Add test for slashed data in term create and update --- features/term.feature | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/features/term.feature b/features/term.feature index d2e45f1ea..82b0c4614 100644 --- a/features/term.feature +++ b/features/term.feature @@ -111,3 +111,34 @@ Feature: Manage WordPress terms http://example.com/?cat=2 http://example.com/?cat=3 """ + + Scenario: Make sure WordPress receives the slashed data it expects + When I run `wp term create category 'My\Term' --description='My\Term\Description' --porcelain` + Then save STDOUT as {TERM_ID} + + When I run `wp term get category {TERM_ID} --field=name` + Then STDOUT should be: + """ + My\Term + """ + + When I run `wp term get category {TERM_ID} --field=description` + Then STDOUT should be: + """ + My\Term\Description + """ + + When I run `wp term update category {TERM_ID} --name='My\New\Term' --description='var isEmailValid = /^\S+@\S+.\S+$/.test(email);'` + Then STDOUT should not be empty + + When I run `wp term get category {TERM_ID} --field=name` + Then STDOUT should be: + """ + My\New\Term + """ + + When I run `wp term get category {TERM_ID} --field=description` + Then STDOUT should be: + """ + var isEmailValid = /^\S+@\S+.\S+$/.test(email); + """ From 644292b0ae473f885dd8afd72b9eb9232b9c6d15 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 15 Jul 2016 14:01:55 -0700 Subject: [PATCH 4736/5359] Pass slashed data for creating and updating users --- features/user.feature | 21 +++++++++++++++++++++ php/commands/user.php | 3 +++ 2 files changed, 24 insertions(+) diff --git a/features/user.feature b/features/user.feature index 4ca85cc0c..e1b3fab15 100644 --- a/features/user.feature +++ b/features/user.feature @@ -265,3 +265,24 @@ Feature: Manage WordPress users """ 6 """ + + Scenario: Make sure WordPress receives the slashed data it expects + Given a WP install + + When I run `wp user create slasheduser slasheduser@example.com --display_name='My\User' --porcelain` + Then save STDOUT as {USER_ID} + + When I run `wp user get {USER_ID} --field=display_name` + Then STDOUT should be: + """ + My\User + """ + + When I run `wp user update {USER_ID} --display_name='My\New\User'` + Then STDOUT should not be empty + + When I run `wp user get {USER_ID} --field=display_name` + Then STDOUT should be: + """ + My\New\User + """ diff --git a/php/commands/user.php b/php/commands/user.php index 3b8dd2d23..7298023e9 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -295,6 +295,8 @@ public function create( $args, $assoc_args ) { $user = new stdClass; list( $user->user_login, $user->user_email ) = $args; + + $assoc_args = wp_slash( $assoc_args ); if ( username_exists( $user->user_login ) ) { WP_CLI::error( "The '{$user->user_login}' username is already registered." ); @@ -397,6 +399,7 @@ public function update( $args, $assoc_args ) { $user_ids[] = $user->ID; } + $assoc_args = wp_slash( $assoc_args ); parent::_update( $user_ids, $assoc_args, 'wp_update_user' ); } From 7c0c500cef6c515e62f3ccee2a4e890e282b3898 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 15 Jul 2016 14:15:12 -0700 Subject: [PATCH 4737/5359] Pass slashed data for creating and updating comments --- features/comment.feature | 19 +++++++++++++++++++ php/commands/comment.php | 2 ++ 2 files changed, 21 insertions(+) diff --git a/features/comment.feature b/features/comment.feature index 6fcbd88d4..b0058297e 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -249,3 +249,22 @@ Feature: Manage WordPress comments """ 0 """ + + Scenario: Make sure WordPress receives the slashed data it expects + When I run `wp comment create --comment_content='My\Comment' --porcelain` + Then save STDOUT as {COMMENT_ID} + + When I run `wp comment get {COMMENT_ID} --field=comment_content` + Then STDOUT should be: + """ + My\Comment + """ + + When I run `wp comment update {COMMENT_ID} --comment_content='My\New\Comment'` + Then STDOUT should not be empty + + When I run `wp comment get {COMMENT_ID} --field=comment_content` + Then STDOUT should be: + """ + My\New\Comment + """ diff --git a/php/commands/comment.php b/php/commands/comment.php index 56b1ad0b7..c153104a9 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -58,6 +58,7 @@ public function __construct() { * Success: Created comment 932. */ public function create( $args, $assoc_args ) { + $assoc_args = wp_slash( $assoc_args ); parent::_create( $args, $assoc_args, function ( $params ) { if ( isset( $params['comment_post_ID'] ) ) { $post_id = $params['comment_post_ID']; @@ -96,6 +97,7 @@ public function create( $args, $assoc_args ) { * Success: Updated comment 123. */ public function update( $args, $assoc_args ) { + $assoc_args = wp_slash( $assoc_args ); parent::_update( $args, $assoc_args, function ( $params ) { if ( !wp_update_comment( $params ) ) { return new WP_Error( 'Could not update comment.' ); From a5392f8c9e1b32fcedcedb3dfe0383f3a18a1aa7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 15 Jul 2016 15:11:41 -0700 Subject: [PATCH 4738/5359] Permit defining aliases at runtime This lets us pass the current alias through over SSH. I wish there was a better way to do this, but I think this is the best we have. I suppose it will let users with lots of WordPress installs to define aliases dynamically, instead of needing to write a file. --- php/WP_CLI/Configurator.php | 36 ++++++++++++++++++++++++++++-------- php/WP_CLI/Runner.php | 11 +++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 6c0e852f0..f259528d1 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -34,6 +34,17 @@ class Configurator { */ const ALIAS_REGEX = '^@[A-Za-z0-9-_]+$'; + /** + * @var array ALIAS_SPEC Arguments that can be used in an alias + */ + private static $alias_spec = array( + 'user', + 'url', + 'path', + 'ssh', + 'http', + ); + /** * @param string $path Path to config spec file. */ @@ -79,7 +90,22 @@ function get_spec() { * @return array */ function get_aliases() { - return $this->aliases; + if ( $runtime_alias = getenv( 'WP_CLI_RUNTIME_ALIAS' ) ) { + $returned_aliases = array(); + foreach( json_decode( $runtime_alias, true ) as $key => $value ) { + if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { + $returned_aliases[ $key ] = array(); + foreach( self::$alias_spec as $i ) { + if ( isset( $value[ $i ] ) ) { + $returned_aliases[ $key ][ $i ] = $value[ $i ]; + } + } + } + } + return $returned_aliases; + } else { + return $this->aliases; + } } /** @@ -196,13 +222,7 @@ public function merge_yml( $path ) { if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { $this->aliases[ $key ] = array(); $is_alias = false; - foreach( array( - 'user', - 'url', - 'path', - 'ssh', - 'http', - ) as $i ) { + foreach( self::$alias_spec as $i ) { if ( isset( $value[ $i ] ) ) { $this->aliases[ $key ][ $i ] = $value[ $i ]; $is_alias = true; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index d526256f3..3e0024d5e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -348,6 +348,17 @@ private function run_ssh_command( $ssh ) { if ( $this->alias && ! empty( $wp_args[0] ) && $this->alias === $wp_args[0] ) { array_shift( $wp_args ); + $runtime_alias = array(); + foreach( $this->aliases[ $this->alias ] as $key => $value ) { + if ( 'ssh' === $key ) { + continue; + } + $runtime_alias[ $key ] = $value; + } + if ( ! empty( $runtime_alias ) ) { + $encoded_alias = json_encode( array( $this->alias => $runtime_alias ) ); + $wp_binary = "WP_CLI_RUNTIME_ALIAS='{$encoded_alias}' {$wp_binary} {$this->alias}"; + } } foreach( $wp_args as $k => $v ) { From 5458d0037e47c765117accc7ba464a9e2884faca Mon Sep 17 00:00:00 2001 From: "nikhilc@bsf.io" <nikhilc@bsf.io> Date: Sat, 16 Jul 2016 12:52:35 +0530 Subject: [PATCH 4739/5359] add --ci=gitlab for wp scaffold plugin-tests --- features/scaffold.feature | 16 +++++++++++++++ php/commands/scaffold.php | 3 +++ templates/install-wp-tests.sh | 6 ++++++ templates/plugin-gitlab.mustache | 34 ++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 templates/plugin-gitlab.mustache diff --git a/features/scaffold.feature b/features/scaffold.feature index 0e4796cdf..81148c221 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -307,6 +307,7 @@ Feature: WordPress code scaffolding """ And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist + And the {PLUGIN_DIR}/hello-world/.gitlab-ci.yml file should not exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: """ script: phpunit @@ -333,6 +334,21 @@ Feature: WordPress code scaffolding version: 5.6.14 """ + Scenario: Scaffold plugin tests with Gitlab as the provider + Given a WP install + And I run `wp scaffold plugin hello-world --skip-tests` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin-tests hello-world --ci=gitlab` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/.gitlab-ci.yml file should contain: + """ + MYSQL_DATABASE + """ + Scenario: Scaffold starter code for a theme Given a WP install Given I run `wp theme path` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index ec2b0d728..96a9f2b90 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -558,6 +558,7 @@ function plugin( $args, $assoc_args ) { * options: * - travis * - circle + * - gitlab * --- * * [--force] @@ -633,6 +634,8 @@ function plugin_tests( $args, $assoc_args ) { $files_to_create["$plugin_dir/.travis.yml"] = Utils\mustache_render( 'plugin-travis.mustache', compact( 'wp_versions_to_test' ) ); } else if ( 'circle' === $assoc_args['ci'] ) { $files_to_create["$plugin_dir/circle.yml"] = Utils\mustache_render( 'plugin-circle.mustache' ); + } else if ( 'gitlab' === $assoc_args['ci'] ) { + $files_to_create["$plugin_dir/.gitlab-ci.yml"] = Utils\mustache_render( 'plugin-gitlab.mustache' ); } $files_written = $this->create_files( $files_to_create, $force ); diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 618bdf94c..55f6e9ac1 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -10,6 +10,7 @@ DB_USER=$2 DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-latest} +SKIP_DB_CREATE=${6:-false} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} @@ -95,6 +96,11 @@ install_test_suite() { } install_db() { + + if [ ${SKIP_DB_CREATE} = "true" ]; then + return 0 + fi + # parse DB_HOST for port or socket references local PARTS=(${DB_HOST//\:/ }) local DB_HOSTNAME=${PARTS[0]}; diff --git a/templates/plugin-gitlab.mustache b/templates/plugin-gitlab.mustache new file mode 100644 index 000000000..6e64d85fa --- /dev/null +++ b/templates/plugin-gitlab.mustache @@ -0,0 +1,34 @@ +variables: + # Configure mysql service (https://hub.docker.com/_/mysql/) + MYSQL_DATABASE: wordpress_tests + MYSQL_ROOT_PASSWORD: mysql + +before_script: + # Install dependencies + + # update the docker + - apt-get clean + - apt-get -yqq update + + # instll the required packages for the running CI tests + - apt-get -yqqf install zip unzip subversion mysql-client libmysqlclient-dev --fix-missing + + # PHP extensions + - docker-php-ext-enable mbstring mcrypt mysqli pdo_mysql intl gd zip bz2 + + # Set up WordPress tests + - bash bin/install-wp-tests.sh wordpress_tests root mysql mysql latest true + +PHPunit:PHP5.3:MySQL: + image: tetraweb/php:5.3 + services: + - mysql:5.6 + script: + - phpunit --configuration phpunit.xml.dist + +PHPunit:PHP5.6:MySQL: + image: tetraweb/php:5.6 + services: + - mysql:5.6 + script: + - phpunit --configuration phpunit.xml.dist \ No newline at end of file From 57735fc49e11de737b116a7df1674ed44f8f9b56 Mon Sep 17 00:00:00 2001 From: "nikhilc@bsf.io" <nikhilc@bsf.io> Date: Sat, 16 Jul 2016 13:20:03 +0530 Subject: [PATCH 4740/5359] adds default value to in Utils\mustache_render, fixes #3164 --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index 6268dcbcb..d2499de33 100644 --- a/php/utils.php +++ b/php/utils.php @@ -447,7 +447,7 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { * * IMPORTANT: Automatic HTML escaping is disabled! */ -function mustache_render( $template_name, $data ) { +function mustache_render( $template_name, $data = array() ) { if ( ! file_exists( $template_name ) ) $template_name = WP_CLI_ROOT . "/templates/$template_name"; From 4c9b2d6780ccbb6339f8af55be0163df9add423c Mon Sep 17 00:00:00 2001 From: "nikhilc@bsf.io" <nikhilc@bsf.io> Date: Sat, 16 Jul 2016 16:51:10 +0530 Subject: [PATCH 4741/5359] follow same coad style as previous --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 55f6e9ac1..8dd224e3a 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -10,7 +10,7 @@ DB_USER=$2 DB_PASS=$3 DB_HOST=${4-localhost} WP_VERSION=${5-latest} -SKIP_DB_CREATE=${6:-false} +SKIP_DB_CREATE=${6-false} WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} From 8814dc6508dc4d113c14717a607da47a1cb04db3 Mon Sep 17 00:00:00 2001 From: "nikhilc@bsf.io" <nikhilc@bsf.io> Date: Sat, 16 Jul 2016 16:56:41 +0530 Subject: [PATCH 4742/5359] update usage info for install-wp-tests.sh --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 8dd224e3a..cf709c276 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ $# -lt 3 ]; then - echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version]" + echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]" exit 1 fi From c7fb5d5a2fec62319b9b1b65db3623ae71a27b04 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 17 Jul 2016 10:34:39 +0545 Subject: [PATCH 4743/5359] Pass slashed site title in site create command --- php/commands/site.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/site.php b/php/commands/site.php index e3459a542..f9d9d9aa9 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -360,6 +360,7 @@ public function create( $_, $assoc_args ) { } $wpdb->hide_errors(); + $title = wp_slash( $title ); $id = wpmu_create_blog( $newdomain, $path, $title, $user_id, array( 'public' => $public ), $network->id ); $wpdb->show_errors(); if ( !is_wp_error( $id ) ) { From 5045280b416ab134fd05529fcd9ab0deab77dab0 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 17 Jul 2016 10:41:08 +0545 Subject: [PATCH 4744/5359] Add test for slashed site title in site create --- features/site.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/features/site.feature b/features/site.feature index 506c67946..4f3c9308c 100644 --- a/features/site.feature +++ b/features/site.feature @@ -289,3 +289,14 @@ Feature: Manage sites in a multisite installation """ http://example.com/first """ + + Scenario: Create site with title containing slash + Given a WP multisite install + And I run `wp site create --slug=mysite --title="My\Site"` + Then STDOUT should not be empty + + When I run `wp option get blogname --url=example.com/mysite` + Then STDOUT should be: + """ + My\Site + """ From 96e41b42c9bb79e86d72dbe57fbbd968f74b1a61 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sun, 17 Jul 2016 22:33:03 +0545 Subject: [PATCH 4745/5359] Command message improvement in super-admin --- php/commands/super-admin.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index d0982a9c9..4d2326845 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -17,6 +17,8 @@ * # Revoke super-admin privileges to the user. * $ wp super-admin remove superadmin2 * Success: Revoked super-admin capabilities. + * + * @package wp-cli */ class Super_Admin_Command extends WP_CLI_Command { @@ -101,12 +103,12 @@ public function add( $args, $_ ) { $user = get_user_by( 'login', $user_login ); if ( !$user ) { - WP_CLI::warning( "Couldn't find {$user_login} user." ); + WP_CLI::warning( "Couldn't find '{$user_login}' user." ); continue; } if ( in_array( $user->user_login, $super_admins ) ) { - WP_CLI::warning( "User {$user_login} already has super-admin capabilities." ); + WP_CLI::warning( "User '{$user_login}' already has super-admin capabilities." ); continue; } @@ -119,7 +121,7 @@ public function add( $args, $_ ) { if ( update_site_option( 'site_admins' , $super_admins ) ) { WP_CLI::success( 'Granted super-admin capabilities.' ); } else { - WP_CLI::error( 'Site options update failed!' ); + WP_CLI::error( 'Site options update failed.' ); } } } From c8805c9d2656ce19d9e7db8d0ea7a695de41c472 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sun, 17 Jul 2016 22:33:45 +0545 Subject: [PATCH 4746/5359] Fix test for changed command message in super-admin --- features/super-admin.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index 219b65033..05ff00f98 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -20,7 +20,7 @@ Feature: Manage super admins associated with a multisite instance When I run `wp super-admin add superadmin` Then STDERR should contain: """ - Warning: User superadmin already has super-admin capabilities. + Warning: User 'superadmin' already has super-admin capabilities. """ When I run `wp super-admin list` From c4f79ae84de40180924706d0a1a7076fd672f198 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sun, 17 Jul 2016 22:45:52 +0545 Subject: [PATCH 4747/5359] Doc improvement in package commands --- php/commands/package.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 58e9c80ba..471c8b969 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -86,7 +86,16 @@ class Package_Command extends WP_CLI_Command { * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json, csv, yaml, ids. Default: table. + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -215,7 +224,16 @@ public function install( $args, $assoc_args ) { * ## OPTIONS * * [--format=<format>] - * : Accepted values: table, json, csv, yaml, ids. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - yaml + * --- * * ## EXAMPLES * From a3928917034df1f9b6fed56c22d8a95808e70952 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 18 Jul 2016 12:53:06 +0545 Subject: [PATCH 4748/5359] Pass slashed data for importing media --- php/commands/media.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index a5f8aefd3..372e99bea 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -201,6 +201,7 @@ function import( $args, $assoc_args = array() ) { 'post_excerpt' => $assoc_args['caption'], 'post_content' => $assoc_args['desc'] ); + $post_array = wp_slash( $post_array ); // use image exif/iptc data for title and caption defaults if possible if ( empty( $post_array['post_title'] ) || empty( $post_array['post_excerpt'] ) ) { @@ -234,7 +235,7 @@ function import( $args, $assoc_args = array() ) { // Set alt text if ( $assoc_args['alt'] ) { - update_post_meta( $success, '_wp_attachment_image_alt', $assoc_args['alt'] ); + update_post_meta( $success, '_wp_attachment_image_alt', wp_slash( $assoc_args['alt'] ) ); } // Set as featured image, if --post_id and --featured_image are set From d3cf3d10d2999d9c65a6fd5d7ff6a981a46f59dc Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 18 Jul 2016 13:11:09 +0545 Subject: [PATCH 4749/5359] Add test for slashed data in media import --- features/media-import.feature | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/features/media-import.feature b/features/media-import.feature index a33e787db..7c0ec06fa 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -1,5 +1,5 @@ Feature: Manage WordPress attachments - + Background: Given a WP install @@ -93,3 +93,21 @@ Feature: Manage WordPress attachments """ The description for the image """ + + Scenario: Make sure WordPress receives the slashed data it expects + When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1 --title="My\Title" --caption="Caption\Here" --alt="Alt\Here" --desc="Desc\Here" --porcelain` + Then save STDOUT as {ATTACHMENT_ID} + + When I run `wp post get {ATTACHMENT_ID} --format=csv --fields=post_title,post_excerpt,post_content` + Then STDOUT should contain: + """ + post_content,"Desc\Here" + post_title,"My\Title" + post_excerpt,"Caption\Here" + """ + + When I run `wp post meta get {ATTACHMENT_ID} _wp_attachment_image_alt` + Then STDOUT should be: + """ + Alt\Here + """ From 6fed4225777cef122fe482ccd61adb01038af817 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 18 Jul 2016 13:21:03 +0545 Subject: [PATCH 4750/5359] Use single apostrophe in command in test for import media --- features/media-import.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/media-import.feature b/features/media-import.feature index 7c0ec06fa..591d0db69 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -95,7 +95,7 @@ Feature: Manage WordPress attachments """ Scenario: Make sure WordPress receives the slashed data it expects - When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1 --title="My\Title" --caption="Caption\Here" --alt="Alt\Here" --desc="Desc\Here" --porcelain` + When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1 --title='My\Title' --caption='Caption\Here' --alt='Alt\Here' --desc='Desc\Here' --porcelain` Then save STDOUT as {ATTACHMENT_ID} When I run `wp post get {ATTACHMENT_ID} --format=csv --fields=post_title,post_excerpt,post_content` From 570c3fc8cbd9fa30950b96664f60a232a4713a95 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 18 Jul 2016 17:05:28 +0545 Subject: [PATCH 4751/5359] Update success message for cron event run --- php/commands/cron.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index f24587045..9f7cdf741 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -211,7 +211,7 @@ public function schedule( $args, $assoc_args ) { * * # Run all cron events due right now * $ wp cron event run --due-now - * Success: Executed a total of 2 cron event(s). + * Success: Executed a total of 2 cron events. */ public function run( $args, $assoc_args ) { @@ -258,7 +258,7 @@ public function run( $args, $assoc_args ) { WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); } - $message = 'Executed a total of %d cron event(s).'; + $message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.'; WP_CLI::success( sprintf( $message, $executed ) ); } From d4246b21935f9d02464666b55d892762cb01f5d5 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 18 Jul 2016 17:19:30 +0545 Subject: [PATCH 4752/5359] Update test to reflect message changes in cron event run command --- features/cron.feature | 10 +++++----- php/commands/cron.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 253938dd0..75f43e046 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -94,7 +94,7 @@ Feature: Manage WP-Cron events and schedules """ And STDOUT should contain: """ - Success: Executed a total of 2 cron event(s). + Success: Executed a total of 2 cron events. """ When I run `wp cron event list` @@ -213,7 +213,7 @@ Feature: Manage WP-Cron events and schedules """ And STDOUT should contain: """ - Success: Executed a total of 2 cron event(s). + Success: Executed a total of 2 cron events. """ When I run `wp cron event run --all` @@ -256,7 +256,7 @@ Feature: Manage WP-Cron events and schedules When I run `wp cron event run --due-now` Then STDOUT should contain: """ - Executed a total of 0 cron event(s) + Executed a total of 0 cron events """ When I run `wp cron event schedule wp_cli_test_event_1 now hourly` @@ -272,13 +272,13 @@ Feature: Manage WP-Cron events and schedules """ And STDOUT should contain: """ - Executed a total of 1 cron event(s) + Executed a total of 1 cron event """ When I run `wp cron event run --due-now` Then STDOUT should contain: """ - Executed a total of 0 cron event(s) + Executed a total of 0 cron events """ Scenario: Don't trigger cron when ALTERNATE_WP_CRON is defined diff --git a/php/commands/cron.php b/php/commands/cron.php index 9f7cdf741..466ec34cf 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -11,7 +11,7 @@ * * # Run all cron events due right now * $ wp cron event run --due-now - * Success: Executed a total of 2 cron event(s). + * Success: Executed a total of 2 cron events. * * # Delete the next scheduled cron event * $ wp cron event delete cron_test From 748444af79da6bdc2c69b63e612571dad0d8d63f Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 19 Jul 2016 10:25:54 +0545 Subject: [PATCH 4753/5359] Fix issue of not listing duplicate cron events --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index 466ec34cf..a5e97f7c6 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -385,7 +385,7 @@ protected static function get_cron_events() { foreach ( $hooks as $hook => $hook_events ) { foreach ( $hook_events as $sig => $data ) { - $events["$hook-$sig"] = (object) array( + $events["$hook-$sig-$time"] = (object) array( 'hook' => $hook, 'time' => $time, 'sig' => $sig, From 1fdbf014a04031dc01fcd286d492a595faa5e8c1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 19 Jul 2016 10:40:19 +0545 Subject: [PATCH 4754/5359] Add test for listing duplicated cron events --- features/cron.feature | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/cron.feature b/features/cron.feature index 75f43e046..3f49d7cc4 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -304,3 +304,16 @@ Feature: Manage WP-Cron events and schedules """ http://example.com """ + + Scenario: Listing duplicated cron events + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 5 minutes'` + Then STDOUT should not be empty + + When I run `wp cron event schedule wp_cli_test_event_1 '+3 hour 5 minutes'` + Then STDOUT should not be empty + + When I run `wp cron event list --format=ids` + Then STDOUT should contain: + """ + wp_cli_test_event_1 wp_cli_test_event_1 + """ From fc8667100945fa104b796864cc277a738c63f953 Mon Sep 17 00:00:00 2001 From: "Peter J. Herrel" <peterherrel@gmail.com> Date: Wed, 20 Jul 2016 12:02:06 +0200 Subject: [PATCH 4755/5359] missing global namespace separator in CommandWithTranslation.php cf. https://github.com/wp-cli/wp-cli/issues/2670#issuecomment-233898650 --- php/WP_CLI/CommandWithTranslation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 628f57f7f..62710848d 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -344,7 +344,7 @@ protected function get_all_languages() { $response = translations_api( $this->obj_type ); if ( is_wp_error( $response ) ) { - WP_CLI::error( $response ); + \WP_CLI::error( $response ); } $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); From e1498ef5d113bfcebba432a48cc622dfe3bb88c5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jul 2016 05:57:32 -0700 Subject: [PATCH 4756/5359] Don't overload `--path` when path is provided in `--ssh` This approach was a bit hacky. Instead, a path provided as a part of `--ssh=<host>` means the command should be ultimately executed from that directory. --- php/WP_CLI/Runner.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 3e0024d5e..c70d449ce 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -342,9 +342,11 @@ private function run_ssh_command( $ssh ) { if ( $pre_cmd ) { $pre_cmd = rtrim( $pre_cmd, ';' ) . '; '; } + if ( $path ) { + $pre_cmd .= "cd {$path}; "; + } $wp_binary = 'wp'; $wp_args = array_slice( $GLOBALS['argv'], 1 ); - $wp_path = $path ? sprintf( '--path=%s', str_replace( '~', '$HOME', $path ) ) : ''; if ( $this->alias && ! empty( $wp_args[0] ) && $this->alias === $wp_args[0] ) { array_shift( $wp_args ); @@ -372,7 +374,7 @@ private function run_ssh_command( $ssh ) { $port ? '-p ' . (int) $port . ' ' : '', $host, $is_tty ? '-t' : '-T', - $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) + $pre_cmd . $wp_binary . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ); WP_CLI::debug( 'Running SSH command: ' . $unescaped_command, 'bootstrap' ); @@ -382,7 +384,7 @@ private function run_ssh_command( $ssh ) { $port ? '-p ' . (int) $port . ' ' : '', escapeshellarg( $host ), $is_tty ? '-t' : '-T', - escapeshellarg( $pre_cmd . $wp_binary . ' ' . $wp_path . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) + escapeshellarg( $pre_cmd . $wp_binary . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) ); passthru( $escaped_command, $exit_code ); From 5fdafbe85718d97c36ac8efa11ee3550ca53ec38 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 20 Jul 2016 16:24:45 -0700 Subject: [PATCH 4757/5359] Explain why Twitter isn't an appropriate support medium --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f0a466732..dfdc07e7a 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ WP-CLI's maintainers and project contributors do their best to respond to all ne If you can't find your answer in one of those existing resources, feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question. +Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. + If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). ## Extending From 7663c453d2e14980807fd128006c45892c132d4d Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 21 Jul 2016 15:54:10 +0545 Subject: [PATCH 4758/5359] Update message for search replace in dry run mode --- php/commands/search-replace.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index bc2bd8976..c8d11293b 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -25,7 +25,7 @@ * | wp_options | option_value | 0 | PHP | * | wp_options | autoload | 0 | SQL | * +------------+--------------+--------------+------+ - * Success: 2 replacement(s) to be made. + * Success: 2 replacements to be made. * * @package wp-cli */ @@ -264,8 +264,8 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::success( $success_message ); } else { - $success_message = "$total replacement(s) to be made."; - WP_CLI::success( $success_message ); + $success_message = ( 1 === $total ) ? '%d replacement to be made.' : '%d replacements to be made.'; + WP_CLI::success( sprintf( $success_message, $total ) ); } } From 0b95433cda3d1f0747045ddda1ba468090e4f286 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 21 Jul 2016 15:54:37 +0545 Subject: [PATCH 4759/5359] Fix test according to updated message in search replace in dry run mode --- features/search-replace.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 02cd30988..55b76ef39 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -225,7 +225,7 @@ Feature: Do global search/replace When I run `wp search-replace '<a href="http://google.com">Google</a>' '<a href="http://apple.com">Apple</a>' --dry-run` Then STDOUT should contain: """ - 1 replacement(s) to be made. + 1 replacement to be made. """ When I run `wp post get {POST_ID} --field=content` From 806597befb56c1164f0bd6b4e07e1bbfeca72ccb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 21 Jul 2016 16:12:24 +0545 Subject: [PATCH 4760/5359] Update success message for widget delete --- php/commands/widget.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 5d4c47213..bcc7f3705 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -297,23 +297,28 @@ public function deactivate( $args, $assoc_args ) { */ public function delete( $args, $assoc_args ) { + $count = 0; + foreach( $args as $widget_id ) { $this->validate_sidebar_widget( $widget_id ); - // Remove the widget's settings + // Remove the widget's settings. list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); $widget_options = $this->get_widget_options( $name ); unset( $widget_options[ $option_index ] ); $this->update_widget_options( $name, $widget_options ); - // Remove the widget from the sidebar + // Remove the widget from the sidebar. $all_widgets = $this->wp_get_sidebars_widgets(); unset( $all_widgets[ $sidebar_id ][ $sidebar_index ] ); $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); update_option( 'sidebars_widgets', $all_widgets ); + + $count++; } - WP_CLI::success( "Widget(s) removed from sidebar." ); + $success_message = ( 1 === $count ) ? '%d widget removed from sidebar.' : '%d widgets removed from sidebar.'; + WP_CLI::success( sprintf( $success_message, $count ) ); } /** From c229fbe8edb980104d07e5be02310828321d8be7 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 21 Jul 2016 16:13:01 +0545 Subject: [PATCH 4761/5359] Improve test to reflect updated message for widget delete --- features/widget.feature | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/widget.feature b/features/widget.feature index 51d746ae6..6bc3b259c 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -53,7 +53,10 @@ Feature: Manage widgets in WordPress sidebar | recent-comments | recent-comments-2 | 2 | When I run `wp widget delete archives-2 recent-posts-2` - Then STDOUT should not be empty + Then STDOUT should be: + """ + Success: 2 widgets removed from sidebar. + """ When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: From d3d0855f43bb6f0d4e01fdb58f288eae6d14532e Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 21 Jul 2016 17:08:39 +0545 Subject: [PATCH 4762/5359] Add example for cli completions command --- php/commands/cli.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 5d0d0b31a..3f9a61402 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -446,10 +446,17 @@ public function cmd_dump() { * ## OPTIONS * * --line=<line> - * : The current command line to be executed + * : The current command line to be executed. * * --point=<point> - * : The index to the current cursor position relative to the beginning of the command + * : The index to the current cursor position relative to the beginning of the command. + * + * ## EXAMPLES + * + * # Generate tab completion strings. + * $ wp cli completions --line='wp eva' --point=100 + * eval + * eval-file */ public function completions( $_, $assoc_args ) { $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); From a30fb4ce5983d1029b474295d07c843969efaa47 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 21 Jul 2016 09:47:16 -0700 Subject: [PATCH 4763/5359] Restore php-cli-tools to v0.11.1; update other dependencies --- composer.json | 2 +- composer.lock | 66 +++++++++++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 9fabb1b8d..8b2590b79 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.29", - "wp-cli/php-cli-tools": "dev-master", + "wp-cli/php-cli-tools": "~0.11.1", "mustache/mustache": "~2.4", "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", diff --git a/composer.lock b/composer.lock index a03775812..4cab63408 100644 --- a/composer.lock +++ b/composer.lock @@ -4,24 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "38e11e275b2087dfb61f50d258712aef", - "content-hash": "a55b968d0d6754da376a5151b4222cbb", + "hash": "f0bf52c59aa6e9fe44d6a611f8006a52", + "content-hash": "10cf19699e3fed767e31e1493a07c8f0", "packages": [ { "name": "composer/ca-bundle", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "a2995e5fe351055f2c7630166af12ce8fd03edfc" + "reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/a2995e5fe351055f2c7630166af12ce8fd03edfc", - "reference": "a2995e5fe351055f2c7630166af12ce8fd03edfc", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/5df9ed0ed0c9506ea6404a23450854e5df15cc12", + "reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12", "shasum": "" }, "require": { + "ext-openssl": "*", + "ext-pcre": "*", "php": "^5.3.2 || ^7.0" }, "require-dev": { @@ -60,27 +62,27 @@ "ssl", "tls" ], - "time": "2016-04-13 10:13:24" + "time": "2016-07-18 23:07:53" }, { "name": "composer/composer", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "30ab6f1c1753267d181839142fafe022313c3c9a" + "reference": "b49a006748a460f8dae6500ec80ed021501ce969" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/30ab6f1c1753267d181839142fafe022313c3c9a", - "reference": "30ab6f1c1753267d181839142fafe022313c3c9a", + "url": "https://api.github.com/repos/composer/composer/zipball/b49a006748a460f8dae6500ec80ed021501ce969", + "reference": "b49a006748a460f8dae6500ec80ed021501ce969", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", "composer/semver": "^1.0", "composer/spdx-licenses": "^1.0", - "justinrainbow/json-schema": "^1.6", + "justinrainbow/json-schema": "^1.6 || ^2.0", "php": "^5.3.2 || ^7.0", "psr/log": "^1.0", "seld/cli-prompt": "^1.0", @@ -93,7 +95,7 @@ }, "require-dev": { "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -106,7 +108,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -137,7 +139,7 @@ "dependency", "package" ], - "time": "2016-06-26 14:42:08" + "time": "2016-07-18 23:28:52" }, { "name": "composer/semver", @@ -264,25 +266,25 @@ }, { "name": "justinrainbow/json-schema", - "version": "1.6.1", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341" + "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341", - "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/6b2a33e6a768f96bdc2ead5600af0822eed17d67", + "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67", "shasum": "" }, "require": { - "php": ">=5.3.29" + "php": ">=5.3.3" }, "require-dev": { - "json-schema/json-schema-test-suite": "1.1.0", + "json-schema/json-schema-test-suite": "1.2.0", "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "~3.7" + "phpunit/phpunit": "^4.8.22" }, "bin": [ "bin/validate-json" @@ -290,7 +292,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -300,7 +302,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { @@ -326,7 +328,7 @@ "json", "schema" ], - "time": "2016-01-25 15:43:01" + "time": "2016-06-02 10:59:52" }, { "name": "mustache/mustache", @@ -1289,16 +1291,16 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "dev-master", + "version": "v0.11.1", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "10cfa5bd978889c8050cd48d70d179d775c31827" + "reference": "5311a4b99103c0505db015a334be4952654d6e21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/10cfa5bd978889c8050cd48d70d179d775c31827", - "reference": "10cfa5bd978889c8050cd48d70d179d775c31827", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/5311a4b99103c0505db015a334be4952654d6e21", + "reference": "5311a4b99103c0505db015a334be4952654d6e21", "shasum": "" }, "require": { @@ -1335,7 +1337,7 @@ "cli", "console" ], - "time": "2016-03-30 11:55:36" + "time": "2016-02-08 14:34:01" } ], "packages-dev": [ @@ -1830,9 +1832,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "wp-cli/php-cli-tools": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From f28b91f0f95911a3dbc6e695359527bd240dc212 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 22 Jul 2016 09:03:56 +0545 Subject: [PATCH 4764/5359] Making cron events array key more unique --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index a5e97f7c6..527b1100e 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -385,7 +385,7 @@ protected static function get_cron_events() { foreach ( $hooks as $hook => $hook_events ) { foreach ( $hook_events as $sig => $data ) { - $events["$hook-$sig-$time"] = (object) array( + $events["$hook-$sig".uniqid()] = (object) array( 'hook' => $hook, 'time' => $time, 'sig' => $sig, From 3352d6d08df4ed5f134283e1c556c1a5dfbd10cb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 22 Jul 2016 11:55:01 +0545 Subject: [PATCH 4765/5359] Fix test of cron event list for WP 3.7 --- features/cron.feature | 4 ++-- php/commands/cron.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/cron.feature b/features/cron.feature index 3f49d7cc4..f3f0f4d73 100644 --- a/features/cron.feature +++ b/features/cron.feature @@ -306,10 +306,10 @@ Feature: Manage WP-Cron events and schedules """ Scenario: Listing duplicated cron events - When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 5 minutes'` + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 5 minutes' hourly` Then STDOUT should not be empty - When I run `wp cron event schedule wp_cli_test_event_1 '+3 hour 5 minutes'` + When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 6 minutes' hourly` Then STDOUT should not be empty When I run `wp cron event list --format=ids` diff --git a/php/commands/cron.php b/php/commands/cron.php index 527b1100e..a5e97f7c6 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -385,7 +385,7 @@ protected static function get_cron_events() { foreach ( $hooks as $hook => $hook_events ) { foreach ( $hook_events as $sig => $data ) { - $events["$hook-$sig".uniqid()] = (object) array( + $events["$hook-$sig-$time"] = (object) array( 'hook' => $hook, 'time' => $time, 'sig' => $sig, From 771a7bf0af7ab0738ee3d09f17432b3953d5aeb7 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 23 Jul 2016 06:57:14 +0545 Subject: [PATCH 4766/5359] Remove associative array key for cron events list --- php/commands/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index a5e97f7c6..2995e1eef 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -385,7 +385,7 @@ protected static function get_cron_events() { foreach ( $hooks as $hook => $hook_events ) { foreach ( $hook_events as $sig => $data ) { - $events["$hook-$sig-$time"] = (object) array( + $events[] = (object) array( 'hook' => $hook, 'time' => $time, 'sig' => $sig, From 89b5d2ad39da9f405b4fe3964d58e6371ecdd682 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jul 2016 05:34:54 -0700 Subject: [PATCH 4767/5359] Register informational label for `@all`, instead of listing all aliases --- features/aliases.feature | 3 ++- php/WP_CLI/Runner.php | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/features/aliases.feature b/features/aliases.feature index cd0135b64..a801e8527 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -107,6 +107,7 @@ Feature: Create shortcuts to specific WordPress installs When I run `wp cli alias` Then STDOUT should be YAML containing: """ + @all: Run command against every registered alias. @testdir: path: testdir """ @@ -114,7 +115,7 @@ Feature: Create shortcuts to specific WordPress installs When I run `wp cli alias --format=json` Then STDOUT should be JSON containing: """ - {"@testdir":{"path":"testdir"}} + {"@all":"Run command against every registered alias.","@testdir":{"path":"testdir"}} """ Scenario: Defining a project alias completely overrides a global alias diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c70d449ce..edc25836c 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -641,7 +641,9 @@ private function init_config() { list( $this->config, $this->extra_config ) = $configurator->to_array(); $this->aliases = $configurator->get_aliases(); if ( count( $this->aliases ) && ! isset( $this->aliases['@all'] ) ) { - $this->aliases['@all'] = array_keys( $this->aliases ); + $this->aliases = array_reverse( $this->aliases ); + $this->aliases['@all'] = 'Run command against every registered alias.'; + $this->aliases = array_reverse( $this->aliases ); } $this->_required_files['runtime'] = $this->config['require']; } @@ -717,9 +719,17 @@ public function start() { $this->check_root(); if ( $this->alias ) { - if ( '@all' === $this->alias && 0 === count( $this->aliases ) ) { - WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); + if ( '@all' === $this->alias && is_string( $this->aliases['@all'] ) ) { + if ( 0 === count( $this->aliases ) ) { + WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); + } + $aliases = array_keys( $this->aliases ); + $k = array_search( '@all', $aliases ); + unset( $aliases[ $k ] ); + $this->run_alias_group( $aliases ); + exit; } + if ( ! array_key_exists( $this->alias, $this->aliases ) ) { WP_CLI::error( "Alias '{$this->alias}' not found." ); } From 28b58d93045bc43dcdd29f36abbeaf154525f428 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jul 2016 06:37:43 -0700 Subject: [PATCH 4768/5359] Make sure `@all` is set to prevent error notice --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index edc25836c..a4b2378f3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -719,7 +719,7 @@ public function start() { $this->check_root(); if ( $this->alias ) { - if ( '@all' === $this->alias && is_string( $this->aliases['@all'] ) ) { + if ( '@all' === $this->alias && isset( $this->aliases['@all'] ) && is_string( $this->aliases['@all'] ) ) { if ( 0 === count( $this->aliases ) ) { WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); } From 8fa9ea91266bef96d5d1bde6664bd8b45220a891 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jul 2016 11:59:36 -0700 Subject: [PATCH 4769/5359] Fix error message for no aliases registered --- php/WP_CLI/Runner.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a4b2378f3..d43a0bb7b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -719,10 +719,11 @@ public function start() { $this->check_root(); if ( $this->alias ) { - if ( '@all' === $this->alias && isset( $this->aliases['@all'] ) && is_string( $this->aliases['@all'] ) ) { - if ( 0 === count( $this->aliases ) ) { - WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); - } + if ( '@all' === $this->alias && ! isset( $this->aliases['@all'] ) ) { + WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); + } + + if ( '@all' === $this->alias && is_string( $this->aliases['@all'] ) ) { $aliases = array_keys( $this->aliases ); $k = array_search( '@all', $aliases ); unset( $aliases[ $k ] ); From 3a4c98e565ab7b0f6db67840172e738065fe7de6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 25 Jul 2016 13:58:44 -0700 Subject: [PATCH 4770/5359] Introduce `WP_CLI::add_wp_hook()` Aka `add_action()` without needing access to `add_action()`. --- php/WP_CLI/Runner.php | 112 ++++++------------------------------------ php/class-wp-cli.php | 67 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 96 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index c70d449ce..df93c599e 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1021,22 +1021,22 @@ private function setup_bootstrap_hooks() { } if ( $this->config['skip-themes'] ) { - $this->add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); + WP_CLI::add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); } - $this->add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); + WP_CLI::add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); // Prevent code from performing a redirect - $this->add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); + WP_CLI::add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); - $this->add_wp_hook( 'nocache_headers', function( $headers ){ + WP_CLI::add_wp_hook( 'nocache_headers', function( $headers ){ Utils\wp_not_installed(); return $headers; }); // ALTERNATE_WP_CRON might trigger a redirect, which we can't handle if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { - $this->add_wp_hook( 'muplugins_loaded', function() { + WP_CLI::add_wp_hook( 'muplugins_loaded', function() { remove_action( 'init', 'wp_cron' ); }); } @@ -1052,22 +1052,22 @@ private function setup_bootstrap_hooks() { 'WPLANG' => '', ); foreach ( $values as $key => $value ) { - $this->add_wp_hook( "pre_site_option_$key", function () use ( $values, $key ) { + WP_CLI::add_wp_hook( "pre_site_option_$key", function () use ( $values, $key ) { return $values[ $key ]; } ); } } // Always permit operations against sites, regardless of status - $this->add_wp_hook( 'ms_site_check', '__return_true' ); + WP_CLI::add_wp_hook( 'ms_site_check', '__return_true' ); // Always permit operations against WordPress, regardless of maintenance mode - $this->add_wp_hook( 'enable_maintenance_mode', function() { + WP_CLI::add_wp_hook( 'enable_maintenance_mode', function() { return false; }); // Use our own debug mode handling instead of WP core - $this->add_wp_hook( 'enable_wp_debug_mode_checks', function( $ret ) { + WP_CLI::add_wp_hook( 'enable_wp_debug_mode_checks', function( $ret ) { Utils\wp_debug_mode(); // Check to see of wpdb is errored, instead of waiting for dead_db() @@ -1081,19 +1081,19 @@ private function setup_bootstrap_hooks() { }); // Never load advanced-cache.php drop-in when WP-CLI is operating - $this->add_wp_hook( 'enable_loading_advanced_cache_dropin', function() { + WP_CLI::add_wp_hook( 'enable_loading_advanced_cache_dropin', function() { return false; }); // In a multisite install, die if unable to find site given in --url parameter if ( $this->is_multisite() ) { - $this->add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { + WP_CLI::add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { WP_CLI::error( "Site {$domain}{$path} not found." ); }, 10, 3 ); } // The APC cache is not available on the command-line, so bail, to prevent cache poisoning - $this->add_wp_hook( 'muplugins_loaded', function() { + WP_CLI::add_wp_hook( 'muplugins_loaded', function() { if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' ); WP_CLI::confirm( 'Given the consequences, do you wish to continue?' ); @@ -1103,7 +1103,7 @@ private function setup_bootstrap_hooks() { // Handle --user parameter if ( ! defined( 'WP_INSTALLING' ) ) { $config = $this->config; - $this->add_wp_hook( 'init', function() use ( $config ) { + WP_CLI::add_wp_hook( 'init', function() use ( $config ) { if ( isset( $config['user'] ) ) { $fetcher = new \WP_CLI\Fetchers\User; $user = $fetcher->get_check( $config['user'] ); @@ -1143,9 +1143,9 @@ private function setup_skip_plugins_filters() { 'option_active_plugins', ); foreach( $hooks as $hook ) { - $this->add_wp_hook( $hook, $wp_cli_filter_active_plugins, 999 ); + WP_CLI::add_wp_hook( $hook, $wp_cli_filter_active_plugins, 999 ); } - $this->add_wp_hook( 'plugins_loaded', function() use ( $hooks, $wp_cli_filter_active_plugins ) { + WP_CLI::add_wp_hook( 'plugins_loaded', function() use ( $hooks, $wp_cli_filter_active_plugins ) { foreach( $hooks as $hook ) { remove_filter( $hook, $wp_cli_filter_active_plugins, 999 ); } @@ -1186,93 +1186,13 @@ public function action_setup_theme_wp_cli_skip_themes() { add_filter( $hook, $wp_cli_filter_active_theme, 999 ); } // Clean up after the TEMPLATEPATH and STYLESHEETPATH constants are defined - $this->add_wp_hook( 'after_setup_theme', function() use ( $hooks, $wp_cli_filter_active_theme ) { + WP_CLI::add_wp_hook( 'after_setup_theme', function() use ( $hooks, $wp_cli_filter_active_theme ) { foreach( $hooks as $hook ) { remove_filter( $hook, $wp_cli_filter_active_theme, 999 ); } }, 0 ); } - /** - * Add a callback to a WordPress action or filter - * - * Essentially add_filter() without needing access to add_filter() - */ - private function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { - global $wp_filter, $merged_filters; - $idx = $this->wp_hook_build_unique_id($tag, $function_to_add, $priority); - $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); - unset( $merged_filters[ $tag ] ); - return true; - } - - /** - * Remove a callback from a WordPress action or filter - * - * Essentially remove_filter() without needing access to remove_filter() - */ - private function remove_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { - $function_to_remove = $this->wp_hook_build_unique_id( $tag, $function_to_remove, $priority ); - - $r = isset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); - - if ( true === $r ) { - unset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] ); - if ( empty( $GLOBALS['wp_filter'][ $tag ][ $priority ] ) ) { - unset( $GLOBALS['wp_filter'][ $tag ][ $priority ] ); - } - if ( empty( $GLOBALS['wp_filter'][ $tag ] ) ) { - $GLOBALS['wp_filter'][ $tag ] = array(); - } - unset( $GLOBALS['merged_filters'][ $tag ] ); - } - - return $r; - } - - /** - * Build Unique ID for storage and retrieval. - * - * Essentially _wp_filter_build_unique_id() without needing access to _wp_filter_build_unique_id() - */ - private function wp_hook_build_unique_id( $tag, $function, $priority ) { - global $wp_filter; - static $filter_id_count = 0; - - if ( is_string($function) ) - return $function; - - if ( is_object($function) ) { - // Closures are currently implemented as objects - $function = array( $function, '' ); - } else { - $function = (array) $function; - } - - if (is_object($function[0]) ) { - // Object Class Calling - if ( function_exists('spl_object_hash') ) { - return spl_object_hash($function[0]) . $function[1]; - } else { - $obj_idx = get_class($function[0]).$function[1]; - if ( !isset($function[0]->wp_filter_id) ) { - if ( false === $priority ) - return false; - $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; - $function[0]->wp_filter_id = $filter_id_count; - ++$filter_id_count; - } else { - $obj_idx .= $function[0]->wp_filter_id; - } - - return $obj_idx; - } - } elseif ( is_string( $function[0] ) ) { - // Static Calling - return $function[0] . '::' . $function[1]; - } - } - /** * Whether or not this WordPress install is multisite. * diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 7d3d97099..14024ac98 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -256,6 +256,73 @@ public static function do_hook( $when ) { } } + /** + * Add a callback to a WordPress action or filter. + * + * `add_action()` without needing access to `add_action()`. If WordPress is + * already loaded though, you should use `add_action()` (and `add_filter()`) + * instead. + * + * @access public + * @category Registration + * + * @param string $tag Named WordPress action or filter. + * @param mixed $function_to_add Callable to execute when the action or filter is evaluated. + * @param integer $priority Priority to add the callback as. + * @param integer $accepted_args Number of arguments to pass to callback. + * @return true + */ + public static function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { + global $wp_filter, $merged_filters; + $idx = self::wp_hook_build_unique_id( $tag, $function_to_add, $priority ); + $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + unset( $merged_filters[ $tag ] ); + return true; + } + + /** + * Build Unique ID for storage and retrieval. + * + * Essentially _wp_filter_build_unique_id() without needing access to _wp_filter_build_unique_id() + */ + private static function wp_hook_build_unique_id( $tag, $function, $priority ) { + global $wp_filter; + static $filter_id_count = 0; + + if ( is_string($function) ) + return $function; + + if ( is_object($function) ) { + // Closures are currently implemented as objects + $function = array( $function, '' ); + } else { + $function = (array) $function; + } + + if (is_object($function[0]) ) { + // Object Class Calling + if ( function_exists('spl_object_hash') ) { + return spl_object_hash($function[0]) . $function[1]; + } else { + $obj_idx = get_class($function[0]).$function[1]; + if ( !isset($function[0]->wp_filter_id) ) { + if ( false === $priority ) + return false; + $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; + $function[0]->wp_filter_id = $filter_id_count; + ++$filter_id_count; + } else { + $obj_idx .= $function[0]->wp_filter_id; + } + + return $obj_idx; + } + } elseif ( is_string( $function[0] ) ) { + // Static Calling + return $function[0] . '::' . $function[1]; + } + } + /** * Register a command to WP-CLI. * From d7ce2561eeeaf4385794e4c2632dcb6495be0b99 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 27 Jul 2016 16:17:18 +0545 Subject: [PATCH 4771/5359] Update success message for widget deactivate --- php/commands/widget.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index bcc7f3705..81a5fe476 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -24,7 +24,7 @@ * * # Delete one or more widgets entirely * $ wp widget delete calendar-2 archive-1 - * Success: Widget(s) removed from sidebar. + * Success: 2 widgets removed from sidebar. */ class Widget_Command extends WP_CLI_Command { @@ -258,12 +258,14 @@ public function move( $args, $assoc_args ) { * ## EXAMPLES * * $ wp widget deactivate recent-comments-2 - * Success: Widget(s) deactivated. + * Success: 1 widget deactivated. * * @subcommand deactivate */ public function deactivate( $args, $assoc_args ) { + $count = 0; + foreach( $args as $widget_id ) { $this->validate_sidebar_widget( $widget_id ); @@ -275,9 +277,12 @@ public function deactivate( $args, $assoc_args ) { $this->move_sidebar_widget( $widget_id, $sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); + $count++; + } - WP_CLI::success( "Widget(s) deactivated." ); + $success_message = ( 1 === $count ) ? '%d widget deactivated.' : '%d widgets deactivated.'; + WP_CLI::success( sprintf( $success_message, $count ) ); } /** @@ -291,7 +296,7 @@ public function deactivate( $args, $assoc_args ) { * ## EXAMPLES * * $ wp widget delete recent-comments-2 - * Success: Widget(s) removed from sidebar. + * Success: 1 widget removed from sidebar. * * @subcommand delete */ From f54b52628e183cbe319b52f1f6a3471cd280a31a Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 27 Jul 2016 16:17:49 +0545 Subject: [PATCH 4772/5359] Fix test to reflect update of message in widget deactivate --- features/widget.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/widget.feature b/features/widget.feature index 6bc3b259c..e5eb4609f 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -35,7 +35,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget deactivate meta-2` Then STDOUT should be: """ - Success: Widget(s) deactivated. + Success: 1 widget deactivated. """ When I run `wp widget list sidebar-1 --fields=name,id,position` From 69f81199adede2b5d890dd136b1474d81a363eb3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 27 Jul 2016 04:26:56 -0700 Subject: [PATCH 4773/5359] Update .mailmap --- .mailmap | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.mailmap b/.mailmap index 115f09c47..ff35d0d23 100644 --- a/.mailmap +++ b/.mailmap @@ -5,6 +5,7 @@ Anant Shrivastava <anant@anantshri.info> Andreas Heigl <andreas@heigl.org> andreascreten <andreas@madewithlove.be> Andrew Patton <andrew@acusti.ca> +andyexeter <palmer.andy@gmail.com> BA <kau@connecticum.de> bartaakos <akos@netpositive.hu> bendoh <ben@thinkoomph.com> @@ -36,8 +37,10 @@ drrobotnik <B@Brandons-Mac-Pro-4.local> Duncan Brown <duncanjbrown@gmail.com> dwightjack <marco.solazzi@gmail.com> Eduardo Alencar <ealencar10@gmail.com> +Enrico Sorcinelli <enrico.sorcinelli@italiaonline.it> ericandrewlewis <eric.andrew.lewis@gmail.com> ericmann <eric@eamann.com> +ernilambar <nilambar@outlook.com> eugeneware <eugene@noblesamurai.com> Evan Mattson <me@aaemnnost.tv> francescolaffi <francesco.laffi@gmail.com> @@ -45,12 +48,15 @@ Frank Staude <frank@staude.net> Frankie Jarrett <fjarrett@godaddy.com> future500 <ramon@future500.nl> Gary Jones <gamajo@gamajo.com> +Geo <geo.artemenko@gmail.com> getsource <mike.schroder@dreamhost.com> Gilbert Pellegrom <gilbert@pellegrom.me> glebis <glebis@gmail.com> goldenapples <ntaintor@janrain.com> Grant McInnes <grant.mcinnes@eyesopen.ca> Greg Anderson <greg.1.anderson@greenknowe.org> +hideokamoto <kokkoku214@gmail.com> +Hidetaka Okamoto <kokkoku214@gmail.com> hina <hina@hinaloe.net> hinoue-work <wpuser@wp-cli-14.04> Hiroshi Urabe <mail@torounit.com> @@ -58,6 +64,7 @@ Ian Dunn <ian@iandunn.name> itsananderson <will@itsananderson.com> j3lamp <j3lamp@gmail.com> jacobischwartz <jacob@schwambell.com> +Jakub Juszczak <netghost03@gmail.com> Jan VoráÄek <jan@voracek.net> Jeff Gould <jrgould@gmail.com> jeichorn <joshua.eichorn@pagely.com> @@ -66,6 +73,7 @@ jghazally <jeff@bigfish.co.uk> jghazally <jghazally@gmail.com> Jim Reevior <jim@thinkoomph.com> jmslbam <jmslbam@gmail.com> +John Blackbourn <john@johnblackbourn.com> johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> @@ -75,6 +83,7 @@ joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> JQ <JeyKeu@users.noreply.github.com> KDoole <dev@Kevins-iMac.local> +Keanan Koppenhaver <keanan@doejo.com> Keith Grennan <keith@nearlyfree.org> Kevin Doole <kdoole@farmmedia.com> Kevinlearynet <info@kevinleary.net> @@ -105,12 +114,15 @@ mwilliamson <michael.williamson@red-gate.com> mwilliamson <mike@zwobble.org> mwithheld <vhmark@gmail.com> nacin <andrewnacin@gmail.com> +Nate Wright <natew@notthisway.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> nickdaugherty <ndaugherty987@gmail.com> +nikhilc@bsf.io <nikhilc@bsf.io> nikolay <nikolay@users.noreply.github.com> nikolay <nikolaynkolev@gmail.com> Nilambar Sharma <ernilambar@users.noreply.github.com> +Nilambar Sharma <nilambar@outlook.com> nschoenholtz <noah@alleyinteractive.com> nullvariable <nullvariable@gmail.com> nyordanov <me@nyordanov.com> @@ -121,14 +133,20 @@ om4james <james@om4.com.au> oneumyvakin <oneumyvakin@gmail.com> Otto Kekäläinen <otto@seravo.fi> ozh <ozh@ozh.org> +Pete Nelson <pete@petenelson.com> +pete@petenelson.com <petenelson@fortress.local> +Peter J. Herrel <peterherrel@gmail.com> phh <phh@peytz.dk> Pippin Williamson <pippin@pippinsplugins.com> +Rachel Baker <rachel@rachelbaker.me> Radu Dan <za_creature@yahoo.com> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> Robin Schneider <ypid@riseup.net> rodrigoprimo <rodrigo@hacklab.com.br> rodrigoprimo <rodrigosprimo@gmail.com> +Roel Veldhuizen <roel@inesta.nl> +roelveldhuizen <roel@inesta.nl> roelven <roel@soundcloud.com> Ross Hattori <rhattori@saymedia.com> Ryan Hoover <ryanshoover@gmail.com> @@ -140,6 +158,7 @@ sboisvert <stephane.boisvert@automattic.com> scribu <mail@scribu.net> scribu <scribu@gmail.com> sebastiaandegeus <sebastiaan@hoppinger.com> +Shinichi Nishikawa <shinichi.nishikawa@gmail.com> sibprogrammer <ayuzhakov@parallels.com> simonwheatley <simonw@codeforthepeople.com> soulou <leo@soulou.fr> @@ -147,10 +166,14 @@ spacedmonkey <spacedmonkey2@gmail.com> SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> Stephen Edgar <stephen@netweb.com.au> +Stephen Harris <contact@stephenharris.info> +Stephen Harris <Stephen.Harris@gov.scot> +Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> Steve Grunwell <steve.grunwell@10up.com> Steve Grunwell <steve@stevegrunwell.com> Steve Grunwell <stevegrunwell@gmail.com> Steve Persch <steve.persch@pantheon.io> +Steven K Word <stevenword@gmail.com> stianlik <stianlik@gmail.com> svaj <chris@chrisbot.(none)> Svetoslav Marinov (Slavi) <slavi@orbisius.com> @@ -167,8 +190,12 @@ trepmal <trepmal@gmail.com> Tristan Penman <tristan@tristanpenman.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> +Utkarsh Patel <iamutkarsh@live.com> +Ville Vuorenmaa <villevuor@gmail.com> voldemortensen <voldemortensen@users.noreply.github.com> Wendell Júnior <wrnx00@gmail.com> +Wes Moberly <wesm87@gmail.com> +Wes Moberly <wesm87@users.noreply.github.com> westonruter <weston@x-team.com> westonruter <westonruter@gmail.com> William Turrell <william@wturrell.co.uk> From 90e747acba4347875b7dcb2a1f1f390117dbd01d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 27 Jul 2016 04:27:14 -0700 Subject: [PATCH 4774/5359] Version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5d22270f2..2094a100c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.24.0-alpha +0.24.0 From a5945813fecb0a2a11f97b1c445ba525c593cd2f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 27 Jul 2016 06:30:25 -0700 Subject: [PATCH 4775/5359] Version bump again --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2094a100c..4037ec065 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.24.0 +0.25.0-alpha From 01747d920d3bbfb34f1eefb73760ef1e1b0b48c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 28 Jul 2016 15:03:02 +0200 Subject: [PATCH 4776/5359] Support PHP 7 on Debian-based systems Fixes #3206 --- utils/wp-cli-updatedeb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index 955829564..d0acfa1b9 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -31,7 +31,7 @@ Architecture: all Maintainer: Daniel Bachhuber <daniel@handbuilt.co> Section: php Priority: optional -Depends: php5-cli, php5-mysql | php5-mysqlnd, mysql-client | mariadb-client +Depends: php5-cli | php7.0-cli, php5-mysql | php5-mysqlnd, mysql-client | mariadb-client Homepage: http://wp-cli.org/ Description: wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite From 8cba590cf01ef6abdfd153893e68a1e16d790e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 28 Jul 2016 20:59:04 +0200 Subject: [PATCH 4777/5359] Add support for php7.0-mysql as Debian dependency --- utils/wp-cli-updatedeb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index d0acfa1b9..ee222436c 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -31,7 +31,7 @@ Architecture: all Maintainer: Daniel Bachhuber <daniel@handbuilt.co> Section: php Priority: optional -Depends: php5-cli | php7.0-cli, php5-mysql | php5-mysqlnd, mysql-client | mariadb-client +Depends: php5-cli | php7.0-cli, php5-mysql | php5-mysqlnd | php7.0-mysql, mysql-client | mariadb-client Homepage: http://wp-cli.org/ Description: wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite From 20fcb462053c5116d9aaae5a7ca02b4c72e3cf2c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 29 Jul 2016 10:15:42 +0545 Subject: [PATCH 4778/5359] Update success message in theme mod remove --- php/commands/theme.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index b8b2cd83c..265843337 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -723,15 +723,15 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * # Set theme mod + * # Set theme mod. * $ wp theme mod set background_color 000000 * Success: Theme mod background_color set to 000000 * - * # Get single theme mod in JSON format + * # Get single theme mod in JSON format. * $ wp theme mod get background_color --format=json * [{"key":"background_color","value":"dd3333"}] * - * # Remove all theme mods + * # Remove all theme mods. * $ wp theme mod remove --all * Success: Theme mods removed. */ @@ -836,19 +836,19 @@ public function get( $args = array(), $assoc_args = array() ) { * : One or more mods to remove. * * [--all] - * : Remove all theme mods + * : Remove all theme mods. * * ## EXAMPLES * - * # Remove all theme mods + * # Remove all theme mods. * $ wp theme mod remove --all * Success: Theme mods removed. * - * # Remove single theme mods + * # Remove single theme mod. * $ wp theme mod remove background_color - * Success: 1 mods removed. + * Success: 1 mod removed. * - * # Remove multiple theme mods + * # Remove multiple theme mods. * $ wp theme mod remove background_color header_textcolor * Success: 2 mods removed. */ @@ -868,7 +868,9 @@ public function remove( $args = array(), $assoc_args = array() ) { remove_theme_mod( $mod ); } - WP_CLI::success( sprintf( '%d mods removed.', count( $args ) ) ); + $count = count( $args ); + $success_message = ( 1 === $count ) ? '%d mod removed.' : '%d mods removed.'; + WP_CLI::success( sprintf( $success_message, $count ) ); } From f73992e8a85b051f3657668a128d7402661aa846 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 29 Jul 2016 10:16:06 +0545 Subject: [PATCH 4779/5359] Fix test to reflect updated message in theme mod remove --- features/theme-mod.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/theme-mod.feature b/features/theme-mod.feature index 61ac1d6aa..1d014d491 100644 --- a/features/theme-mod.feature +++ b/features/theme-mod.feature @@ -53,7 +53,7 @@ Feature: Manage WordPress theme mods When I run `wp theme mod remove background_color` Then STDOUT should be: """ - Success: 1 mods removed. + Success: 1 mod removed. """ When I run `wp theme mod remove background_color header_textcolor` From bfc93da668f3ed05d0f22e0135cef2aebd559b96 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 29 Jul 2016 15:58:31 +0545 Subject: [PATCH 4780/5359] Update success message in menu item delete --- php/commands/menu.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 2f1bf815c..093713959 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -217,7 +217,7 @@ protected function get_formatter( &$assoc_args ) { * * # Delete menu item * $ wp menu item delete 45 - * Success: Menu item(s) deleted. + * Success: 1 menu item deleted. */ class Menu_Item_Command extends WP_CLI_Command { @@ -550,13 +550,15 @@ public function update( $args, $assoc_args ) { * ## EXAMPLES * * $ wp menu item delete 45 - * Success: Menu item(s) deleted. + * Success: 1 menu item deleted. * * @subcommand delete */ public function delete( $args, $_ ) { global $wpdb; + $count = 0; + foreach( $args as $arg ) { $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); @@ -574,8 +576,14 @@ public function delete( $args, $_ ) { } } + if ( false !== $ret ) { + $count++; + } + } - WP_CLI::success( "Menu item(s) deleted." ); + + $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; + WP_CLI::success( sprintf( $success_message, $count ) ); } From 48fa7bc6190c29fa9d12286bceb95860b903384d Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 29 Jul 2016 15:59:08 +0545 Subject: [PATCH 4781/5359] Fix test to reflect updated message in menu item delete --- features/menu.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/menu.feature b/features/menu.feature index 3532450be..157e149ac 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -124,6 +124,10 @@ Feature: Manage WordPress menus Then STDOUT should not be empty When I run `wp menu item delete {CUSTOM_ITEM_ID}` + Then STDOUT should be: + """ + Success: 1 menu item deleted. + """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: """ @@ -131,6 +135,10 @@ Feature: Manage WordPress menus """ When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` + Then STDOUT should be: + """ + Success: 2 menu items deleted. + """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: """ From bf974d246eb93af040004869ffce2e5d3b1a084b Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 29 Jul 2016 16:11:09 +0545 Subject: [PATCH 4782/5359] Add missing heading in doc of cli cmd-dump --- php/commands/cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/cli.php b/php/commands/cli.php index 3f9a61402..7441d2635 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -430,6 +430,8 @@ function param_dump( $_, $assoc_args ) { /** * Dump the list of installed commands, as JSON. * + * ## EXAMPLES + * * # Dump the list of installed commands * $ wp cli cmd-dump * {"name":"wp","description":"Manage WordPress through the command-line.","longdesc":"\n\n## GLOBAL PARAMETERS\n\n --path=<path>\n Path to the WordPress files.\n\n --ssh=<ssh>\n Perform operation against a remote server over SSH.\n\n --url=<url>\n Pretend request came from given URL. In multisite, this argument is how the target site is specified. \n\n --user=<id|login|email>\n From 8d0ea143a634623f47bb868e07a9e3d943d89d68 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 29 Jul 2016 22:08:21 +0900 Subject: [PATCH 4783/5359] improve help for ssh --- php/config-spec.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index c54c99dbf..5696a1aad 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -8,8 +8,8 @@ ), 'ssh' => array( - 'runtime' => '=<ssh>', - 'file' => '<ssh>', + 'runtime' => '=<user>[:<pass>]@<host>[:<port>]<path>', + 'file' => '<user>[:<pass>]@<host>[:<port>]<path>', 'desc' => 'Perform operation against a remote server over SSH.', ), @@ -108,4 +108,3 @@ ), ); - From 32c3d66876d0c59d4c21951c22904421e5ed2146 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Fri, 29 Jul 2016 23:28:22 +0900 Subject: [PATCH 4784/5359] remove :pass and some fix --- php/config-spec.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 7a10c1c75..7f6e4f877 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -8,8 +8,8 @@ ), 'ssh' => array( - 'runtime' => '=<user>[:<pass>]@<host>[:<port>]<path>', - 'file' => '<user>[:<pass>]@<host>[:<port>]<path>', + 'runtime' => '=[<user>]@<host>[:<port>][<path>]', + 'file' => '[<user>]@<host>[:<port>][<path>]', 'desc' => 'Perform operation against a remote server over SSH.', ), From 455211d54b771bdcd35e7a7eae2ab67632de56b4 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Sun, 31 Jul 2016 15:50:19 +0545 Subject: [PATCH 4785/5359] Add example for cli alias --- php/commands/cli.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 7441d2635..03e907acd 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -470,7 +470,7 @@ public function completions( $_, $assoc_args ) { * List available aliases. * * Aliases are shorthand references to WordPress installs. For instance, - * '@dev' could refer to a development install and '@prod' could refer to + * `@dev` could refer to a development install and `@prod` could refer to * a production install. This command gives you visibility in what * registered aliases you have available. * @@ -484,6 +484,20 @@ public function completions( $_, $assoc_args ) { * - yaml * - json * --- + * + * ## EXAMPLES + * + * # List all available aliases. + * $ wp cli alias + * --- + * @all: Run command against every registered alias. + * @prod: + * ssh: runcommand@runcommand.io~/webapps/production + * @dev: + * ssh: vagrant@192.168.50.10/srv/www/runcommand.dev + * @both: + * - @prod + * - @dev */ public function alias( $_, $assoc_args ) { WP_CLI::print_value( WP_CLI::get_runner()->aliases, $assoc_args ); From f04647998af6059f4140d25dc70c016cabf9c8f7 Mon Sep 17 00:00:00 2001 From: Rahul Prajapati <rahul.prajapati@rtcamp.com> Date: Tue, 2 Aug 2016 00:42:36 +0530 Subject: [PATCH 4786/5359] display default core language in "wp core version --extra". --- features/core-version.feature | 1 + php/commands/core.php | 7 ++++--- templates/versions.mustache | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/core-version.feature b/features/core-version.feature index 3904c5b23..6eecbfe99 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -16,4 +16,5 @@ Feature: Find version for WordPress install WordPress version: 4.4.2 Database revision: 35700 TinyMCE version: 4.208 (4208-20151113) + Language: en_US """ diff --git a/php/commands/core.php b/php/commands/core.php index eafc38a57..57e528958 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -945,9 +945,10 @@ public function version( $args = array(), $assoc_args = array() ) { } echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( - 'wp-version' => $details['wp_version'], - 'db-version' => $details['wp_db_version'], - 'mce-version' => ( $human_readable_tiny_mce ? + 'wp-version' => $details[ 'wp_version' ], + 'db-version' => $details[ 'wp_db_version' ], + 'local-package' => ! empty( $details[ 'wp_local_package' ] ) ? $details[ 'wp_local_package' ] : 'en_US', + 'mce-version' => ( $human_readable_tiny_mce ? "$human_readable_tiny_mce ({$details['tinymce_version']})" : $details['tinymce_version'] ) diff --git a/templates/versions.mustache b/templates/versions.mustache index 06c0e8ea9..c60551023 100644 --- a/templates/versions.mustache +++ b/templates/versions.mustache @@ -1,3 +1,4 @@ WordPress version: {{wp-version}} Database revision: {{db-version}} TinyMCE version: {{mce-version}} +Package Language: {{local-package}} From e98d0e78262d0285cbc82c0459dcde00aba5a805 Mon Sep 17 00:00:00 2001 From: Rahul Prajapati <rahul.prajapati@rtcamp.com> Date: Tue, 2 Aug 2016 00:56:56 +0530 Subject: [PATCH 4787/5359] Fixed issues: WPCS and testcase --- features/core-version.feature | 2 +- php/commands/core.php | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/features/core-version.feature b/features/core-version.feature index 6eecbfe99..42da49bb9 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -16,5 +16,5 @@ Feature: Find version for WordPress install WordPress version: 4.4.2 Database revision: 35700 TinyMCE version: 4.208 (4208-20151113) - Language: en_US + Package Language: en_US """ diff --git a/php/commands/core.php b/php/commands/core.php index 57e528958..ea6d1cfa4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -945,9 +945,12 @@ public function version( $args = array(), $assoc_args = array() ) { } echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( - 'wp-version' => $details[ 'wp_version' ], - 'db-version' => $details[ 'wp_db_version' ], - 'local-package' => ! empty( $details[ 'wp_local_package' ] ) ? $details[ 'wp_local_package' ] : 'en_US', + 'wp-version' => $details['wp_version'], + 'db-version' => $details['wp_db_version'], + 'local-package' => ( empty( $details['wp_local_package'] ) ? + 'en_US' + : $details['wp_local_package'] + ), 'mce-version' => ( $human_readable_tiny_mce ? "$human_readable_tiny_mce ({$details['tinymce_version']})" : $details['tinymce_version'] From f9ffd2ef9cfc7fbe639c1c749b65efc900e9c6dd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 2 Aug 2016 04:22:33 -0700 Subject: [PATCH 4788/5359] Fix backwards compat shim to only affect `wp site create --- features/site.feature | 3 +++ php/WP_CLI/Runner.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/features/site.feature b/features/site.feature index 4f3c9308c..03d62de2c 100644 --- a/features/site.feature +++ b/features/site.feature @@ -27,6 +27,9 @@ Feature: Manage sites in a multisite installation 1 2 """ + When I run `wp site list --site_id=2 --format=ids` + Then STDOUT should be empty + When I run `wp --url=first.example.com option get home` Then STDOUT should be: """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 592081b28..d73b8a079 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -471,8 +471,8 @@ private static function back_compat_conversions( $args, $assoc_args ) { unset( $assoc_args['admin_name'] ); } - // site --site_id= -> site --network_id= - if ( count( $args ) > 0 && 'site' == $args[0] && isset( $assoc_args['site_id'] ) ) { + // site create --site_id= -> site create --network_id= + if ( count( $args ) >= 2 && 'site' === $args[0] && 'create' === $args[1] && isset( $assoc_args['site_id'] ) ) { $assoc_args['network_id'] = $assoc_args['site_id']; unset( $assoc_args['site_id'] ); } From 6d973d8656279f65cc4679de783b092d06a0b3a0 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 2 Aug 2016 21:24:59 +0545 Subject: [PATCH 4789/5359] Update success message in menu delete command --- php/commands/menu.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 093713959..176e4530e 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -89,6 +89,8 @@ public function create( $args, $assoc_args ) { */ public function delete( $args, $_ ) { + $count = 0; + foreach( $args as $arg ) { $ret = wp_delete_nav_menu( $arg ); @@ -98,10 +100,16 @@ public function delete( $args, $_ ) { WP_CLI::warning( "Error deleting menu." ); } + else { + + $count++; + + } } - WP_CLI::success( "Menu(s) deleted." ); + $success_message = ( 1 === $count ) ? '%d menu deleted.' : '%d menus deleted.'; + WP_CLI::success( sprintf( $success_message, $count ) ); } From fa156bae4a09759d0fd5c36185be1f43eb48343a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 2 Aug 2016 21:25:43 +0545 Subject: [PATCH 4790/5359] Improve test to reflect message update in menu delete --- features/menu.feature | 60 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 157e149ac..1d26121c1 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -12,11 +12,15 @@ Feature: Manage WordPress menus | My Menu | my-menu | When I run `wp menu delete "My Menu"` + Then STDOUT should be: + """ + Success: 1 menu deleted. + """ And I run `wp menu list --format=count` Then STDOUT should be: - """ - 0 - """ + """ + 0 + """ When I run `wp menu create "First Menu"` And I run `wp menu create "Second Menu"` @@ -27,18 +31,22 @@ Feature: Manage WordPress menus | Second Menu | second-menu | When I run `wp menu delete "First Menu" "Second Menu"` + Then STDOUT should be: + """ + Success: 2 menus deleted. + """ And I run `wp menu list --format=count` Then STDOUT should be: - """ - 0 - """ + """ + 0 + """ When I run `wp menu create "First Menu"` And I run `wp menu list --format=ids` Then STDOUT should be: - """ - 5 - """ + """ + 5 + """ Scenario: Assign / remove location from a menu @@ -55,11 +63,11 @@ Feature: Manage WordPress menus | slug | locations | | primary-menu | primary | - When I run `wp menu location list --format=ids` - Then STDOUT should be: - """ - primary - """ + When I run `wp menu location list --format=ids` + Then STDOUT should be: + """ + primary + """ When I run `wp menu location remove primary-menu primary` And I run `wp menu list --fields=slug,locations` @@ -125,25 +133,25 @@ Feature: Manage WordPress menus When I run `wp menu item delete {CUSTOM_ITEM_ID}` Then STDOUT should be: - """ - Success: 1 menu item deleted. - """ + """ + Success: 1 menu item deleted. + """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: - """ - 2 - """ + """ + 2 + """ When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` Then STDOUT should be: - """ - Success: 2 menu items deleted. - """ + """ + Success: 2 menu items deleted. + """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: - """ - 0 - """ + """ + 0 + """ Scenario: Preserve grandparent item as ancestor of child item when parent item is removed. From f6ddbb175343406a6380e497d3002c10103b8638 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 2 Aug 2016 21:31:35 +0545 Subject: [PATCH 4791/5359] Update example doc in menu delete --- php/commands/menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 176e4530e..7fafe0676 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -85,7 +85,7 @@ public function create( $args, $assoc_args ) { * ## EXAMPLES * * $ wp menu delete "My Menu" - * Success: Menu(s) deleted. + * Success: 1 menu deleted. */ public function delete( $args, $_ ) { From 6fa817e4faf31e9c36ac213f2932615038e29285 Mon Sep 17 00:00:00 2001 From: Rahul Prajapati <rahul.prajapati@rtcamp.com> Date: Tue, 2 Aug 2016 22:52:05 +0530 Subject: [PATCH 4792/5359] Added language o/p in 'version --extra' command doc --- php/commands/core.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/core.php b/php/commands/core.php index ea6d1cfa4..377bd0003 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -930,6 +930,7 @@ private static function get_clean_basedomain() { * WordPress version: 4.5.2 * Database revision: 36686 * TinyMCE version: 4.310 (4310-20160418) + * Package Language: en_US * * @when before_wp_load */ From b419b8a5ee1f9800868f0b45dbfc6f9120e1f623 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 3 Aug 2016 20:24:45 +0545 Subject: [PATCH 4793/5359] Improve example in option list --- php/commands/option.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 2da6e107d..d15d47376 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -187,9 +187,9 @@ public function add( $args, $assoc_args ) { * +-------------+--------------+ * * # Delete all options begining with "theme_mods_" - * $ wp option list --search="theme_mods_*" --field=option_name | xargs -0 -d '\n' -I % wp option delete % + * $ wp option list --search="theme_mods_*" --field=option_name | xargs -I % wp option delete % * Success: Deleted 'theme_mods_twentysixteen' option. - * Success: Deleted 'theme_mods_twentfifteen' option. + * Success: Deleted 'theme_mods_twentyfifteen' option. * Success: Deleted 'theme_mods_twentyfourteen' option. * * @subcommand list From 52c2a58e81aff6f6cf1d8fa598955b2e3ea75c5a Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 3 Aug 2016 20:47:44 +0545 Subject: [PATCH 4794/5359] Improve example in plugin list command --- php/commands/plugin.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 608c26129..2a55e37a0 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -812,23 +812,24 @@ function delete( $args, $assoc_args = array() ) { * * ## EXAMPLES * + * # List active plugins on the site. * $ wp plugin list --status=active --format=json * [{"name":"dynamic-hostname","status":"active","update":"none","version":"0.4.2"},{"name":"tinymce-templates","status":"active","update":"none","version":"4.4.3"},{"name":"wp-multibyte-patch","status":"active","update":"none","version":"2.4"},{"name":"wp-total-hacks","status":"active","update":"none","version":"2.0.1"}] * - * # List plugins on each site in a network - * $ wp site list --field=url | xargs -n 1 -I % wp plugin list --url=% - * +------------------------------+----------------+-----------+------------+ - * | name | status | update | version | - * +------------------------------+----------------+-----------+------------+ - * | akismet | active-network | none | 3.1.11 | - * | hello | inactive | none | 1.6 | - * +------------------------------+----------------+-----------+------------+ - * +------------------------------+----------------+-----------+------------+ - * | name | status | update | version | - * +------------------------------+----------------+-----------+------------+ - * | akismet | active-network | none | 3.1.11 | - * | hello | inactive | none | 1.6 | - * +------------------------------+----------------+-----------+------------+ + * # List plugins on each site in a network. + * $ wp site list --field=url | xargs -I % wp plugin list --url=% + * +---------+----------------+--------+---------+ + * | name | status | update | version | + * +---------+----------------+--------+---------+ + * | akismet | active-network | none | 3.1.11 | + * | hello | inactive | none | 1.6 | + * +---------+----------------+--------+---------+ + * +---------+----------------+--------+---------+ + * | name | status | update | version | + * +---------+----------------+--------+---------+ + * | akismet | active-network | none | 3.1.11 | + * | hello | inactive | none | 1.6 | + * +---------+----------------+--------+---------+ * * @subcommand list */ From b1ee12b923c927eced71789bb635739b29a34263 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 3 Aug 2016 21:09:48 +0545 Subject: [PATCH 4795/5359] Improve doc for term generate command --- php/commands/term.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index 0bce81736..dc652d884 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -361,10 +361,16 @@ public function delete( $args ) { * : The taxonomy for the generated terms. * * [--count=<number>] - * : How many terms to generate. Default: 100 + * : How many terms to generate? + * --- + * default: 100 + * --- * * [--max_depth=<number>] - * : Generate child terms down to a certain depth. Default: 1 + * : Generate child terms down to a certain depth. + * --- + * default: 1 + * --- * * [--format=<format>] * : Render output in a particular format. @@ -377,12 +383,12 @@ public function delete( $args ) { * * ## EXAMPLES * - * # Generate post categories + * # Generate post categories. * $ wp term generate category --count=10 * Generating terms 100% [=========] 0:02 / 0:02 * - * # Add meta to every generated term - * $ wp term generate category --format=ids --count=3 | xargs -0 -d ' ' -I % wp term meta add % foo bar + * # Add meta to every generated term. + * $ wp term generate category --format=ids --count=3 | xargs -d ' ' -I % wp term meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. From 33840b025f8848a791460138a345ece52d1bea10 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Wed, 3 Aug 2016 21:23:35 +0545 Subject: [PATCH 4796/5359] Improve doc for post generate command --- php/commands/post.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index c9744f904..5c04292a2 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -447,19 +447,19 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * # Generate posts + * # Generate posts. * $ wp post generate --count=10 --post_type=page --post_date=1999-01-04 * Generating posts 100% [================================================] 0:01 / 0:04 * - * # Generate posts with fetched content + * # Generate posts with fetched content. * $ curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 * % Total % Received % Xferd Average Speed Time Time Time Current * Dload Upload Total Spent Left Speed * 100 2509 100 2509 0 0 616 0 0:00:04 0:00:04 --:--:-- 616 * Generating posts 100% [================================================] 0:01 / 0:04 * - * # Add meta to every generated post - * $ wp post generate --format=ids | xargs -0 -d ' ' -I % wp post meta add % foo bar + * # Add meta to every generated posts. + * $ wp post generate --format=ids | xargs -d ' ' -I % wp post meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. From 00732602bd8f5ac228788190dfb0307333784e8e Mon Sep 17 00:00:00 2001 From: Rahul Prajapati <rahul.prajapati@rtcamp.com> Date: Thu, 4 Aug 2016 01:10:57 +0530 Subject: [PATCH 4797/5359] added testcase for a non-en_US locale --- features/core-version.feature | 21 ++++++++++++++++++++- php/commands/core.php | 2 +- templates/versions.mustache | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/features/core-version.feature b/features/core-version.feature index 42da49bb9..b1bb640e9 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -16,5 +16,24 @@ Feature: Find version for WordPress install WordPress version: 4.4.2 Database revision: 35700 TinyMCE version: 4.208 (4208-20151113) - Package Language: en_US + Package language: en_US + """ + + Scenario: Installing WordPress for a non-default locale and verify core extended version information. + Given an empty directory + And an empty cache + + When I run `wp core download --version=4.4.2 --locale=de_DE` + Then STDOUT should be: + """ + Success: WordPress downloaded. + """ + + When I run `wp core version --extra` + Then STDOUT should be: + """ + WordPress version: 4.4.2 + Database revision: 35700 + TinyMCE version: 4.208 (4208-20151113) + Package language: de_DE """ diff --git a/php/commands/core.php b/php/commands/core.php index 377bd0003..16fc7363b 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -930,7 +930,7 @@ private static function get_clean_basedomain() { * WordPress version: 4.5.2 * Database revision: 36686 * TinyMCE version: 4.310 (4310-20160418) - * Package Language: en_US + * Package language: en_US * * @when before_wp_load */ diff --git a/templates/versions.mustache b/templates/versions.mustache index c60551023..a52954e82 100644 --- a/templates/versions.mustache +++ b/templates/versions.mustache @@ -1,4 +1,4 @@ WordPress version: {{wp-version}} Database revision: {{db-version}} TinyMCE version: {{mce-version}} -Package Language: {{local-package}} +Package language: {{local-package}} From 69362a65581d3a0b6f50089807eddc6ed7e4919b Mon Sep 17 00:00:00 2001 From: Travis Northcutt <travis@memberup.co> Date: Wed, 3 Aug 2016 12:59:11 -0700 Subject: [PATCH 4798/5359] Add zsh tab completion info Ref: https://github.com/eddiezane/lunchy/issues/57#issuecomment-121173592 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index dfdc07e7a..a9abb7805 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,14 @@ source /FULL/PATH/TO/wp-completion.bash Don't forget to run `source ~/.bash_profile` afterwards. +If using zsh for your shell, you may need to do the following: + +``` +autoload bashcompinit +bashcompinit +source /FULL/PATH/TO/wp-completion.bash +``` + ## Support WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: From 6811849db75a329e9aae84c587b149db0d96124d Mon Sep 17 00:00:00 2001 From: Travis Northcutt <travis@memberup.co> Date: Wed, 3 Aug 2016 13:24:08 -0700 Subject: [PATCH 4799/5359] Improve zsh tab completion instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9abb7805..304562bc4 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ source /FULL/PATH/TO/wp-completion.bash Don't forget to run `source ~/.bash_profile` afterwards. -If using zsh for your shell, you may need to do the following: +If using zsh for your shell, you may need to load and start `bashcompinit`: ``` autoload bashcompinit From 66ac53fe4ba6829b25993ba5d19b7056fe649a9c Mon Sep 17 00:00:00 2001 From: Travis Northcutt <travis@memberup.co> Date: Wed, 3 Aug 2016 13:30:31 -0700 Subject: [PATCH 4800/5359] Improve zsh tab completion instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 304562bc4..1a1b8fc30 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ source /FULL/PATH/TO/wp-completion.bash Don't forget to run `source ~/.bash_profile` afterwards. -If using zsh for your shell, you may need to load and start `bashcompinit`: +If using zsh for your shell, you may need to load and start `bashcompinit` before sourcing. Put the following in your `.zshrc`: ``` autoload bashcompinit From 045de368a7f5aed23e8b218ef92dde2dc3cc5ab7 Mon Sep 17 00:00:00 2001 From: Rahul Prajapati <rahul.prajapati@rtcamp.com> Date: Thu, 4 Aug 2016 02:24:18 +0530 Subject: [PATCH 4801/5359] Added testcase for a non-en_US locale. command : 'wp core version --extra' --- features/core-version.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core-version.feature b/features/core-version.feature index b1bb640e9..b46b47c30 100644 --- a/features/core-version.feature +++ b/features/core-version.feature @@ -24,7 +24,7 @@ Feature: Find version for WordPress install And an empty cache When I run `wp core download --version=4.4.2 --locale=de_DE` - Then STDOUT should be: + Then STDOUT should contain: """ Success: WordPress downloaded. """ From 66c2269731acf13acdcdbabafa0ae16002f807e1 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 4 Aug 2016 11:31:32 +0545 Subject: [PATCH 4802/5359] Improve doc for comment generate command --- php/commands/comment.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index c153104a9..22def3485 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -113,7 +113,10 @@ public function update( $args, $assoc_args ) { * ## OPTIONS * * [--count=<number>] - * : How many comments to generate. Default: 100 + * : How many comments to generate? + * --- + * default: 100 + * --- * * [--post_id=<post-id>] * : Assign comments to a specific post. @@ -129,8 +132,12 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * - * # Add meta to every generated comment - * $ wp comment generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp comment meta add % foo bar + * # Generate comments for the given post. + * $ wp comment generate --format=ids --count=3 --post_id=123 + * 138 139 140 + * + * # Add meta to every generated comment. + * $ wp comment generate --format=ids --count=3 | xargs -d ' ' -I % wp comment meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. From 40dacd27c97a328e244dbc7b4ac4579a14347a73 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 4 Aug 2016 11:36:50 +0545 Subject: [PATCH 4803/5359] Improve doc in user generate command --- php/commands/user.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index 7298023e9..b5a04c44c 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -295,7 +295,7 @@ public function create( $args, $assoc_args ) { $user = new stdClass; list( $user->user_login, $user->user_email ) = $args; - + $assoc_args = wp_slash( $assoc_args ); if ( username_exists( $user->user_login ) ) { @@ -409,18 +409,27 @@ public function update( $args, $assoc_args ) { * ## OPTIONS * * [--count=<number>] - * : How many users to generate. Default: 100 + * : How many users to generate? + * --- + * default: 100 + * --- * * [--role=<role>] * : The role of the generated users. Default: default role from WP * * [--format=<format>] - * : Accepted values: progress, ids. Default: ids. + * : Render output in a particular format. + * --- + * default: progress + * options: + * - progress + * - ids + * --- * * ## EXAMPLES * - * # Add meta to every generated user - * $ wp user generate --format=ids --count=3 | xargs -0 -d ' ' -I % wp user meta add % foo bar + * # Add meta to every generated users. + * $ wp user generate --format=ids --count=3 | xargs -d ' ' -I % wp user meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. From c61c1cec2ef2cd5d3c9e32a728ee80dcf7de3106 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 4 Aug 2016 15:03:18 +0900 Subject: [PATCH 4804/5359] #discussion_r73137910 --- php/config-spec.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/config-spec.php b/php/config-spec.php index 7f6e4f877..11c6fffbd 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -8,8 +8,8 @@ ), 'ssh' => array( - 'runtime' => '=[<user>]@<host>[:<port>][<path>]', - 'file' => '[<user>]@<host>[:<port>][<path>]', + 'runtime' => '=[<user>@]<host>[:<port>][<path>]', + 'file' => '[<user>@]<host>[:<port>][<path>]', 'desc' => 'Perform operation against a remote server over SSH.', ), From aae931d9de6d1a41128c4e60a48eaddd3716b152 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 4 Aug 2016 11:56:47 +0545 Subject: [PATCH 4805/5359] Improve doc in media import command --- php/commands/media.php | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 372e99bea..910658d37 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -5,7 +5,7 @@ * * ## EXAMPLES * - * # Re-generate all thumbnails, without confirmation + * # Re-generate all thumbnails, without confirmation. * $ wp media regenerate --yes * Found 3 images to regenerate. * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). @@ -13,9 +13,9 @@ * Regenerated thumbnails for "Sunburst Over River" (ID 756). * Success: Finished regenerating all images. * - * # Import a local image and set it to be the featured image for a post + * # Import a local image and set it to be the featured image for a post. * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image - * Success: Imported file /home/person/Downloads/image.png as attachment ID 1753 and attached to post 123 as featured image. + * Success: Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image. * * @package wp-cli */ @@ -117,48 +117,48 @@ function regenerate( $args, $assoc_args = array() ) { * downloaded to a temp file before being sideloaded. * * [--post_id=<post_id>] - * : ID of the post to attach the imported files to + * : ID of the post to attach the imported files to. * * [--title=<title>] - * : Attachment title (post title field) + * : Attachment title (post title field). * * [--caption=<caption>] - * : Caption for attachent (post excerpt field) + * : Caption for attachent (post excerpt field). * * [--alt=<alt_text>] - * : Alt text for image (saved as post meta) + * : Alt text for image (saved as post meta). * * [--desc=<description>] - * : "Description" field (post content) of attachment post + * : "Description" field (post content) of attachment post. * * [--featured_image] * : If set, set the imported image as the Featured Image of the post its attached to. * * [--porcelain] - * : Output just the new attachment id. + * : Output just the new attachment ID. * * ## EXAMPLES * - * # Import all jpgs in the current user's "Pictures" directory, not attached to any post + * # Import all jpgs in the current user's "Pictures" directory, not attached to any post. * $ wp media import ~/Pictures/**\/*.jpg - * Success: Imported file /home/person/Pictures/beautiful-youg-girl-in-ivy.jpg as attachment ID 1751. - * Success: Imported file /home/person/Pictures/fashion-girl.jpg as attachment ID 1752. + * Success: Imported file '/home/person/Pictures/beautiful-youg-girl-in-ivy.jpg' as attachment ID 1751. + * Success: Imported file '/home/person/Pictures/fashion-girl.jpg' as attachment ID 1752. * - * # Import a local image and set it to be the post thumbnail for a post + * # Import a local image and set it to be the post thumbnail for a post. * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image - * Success: Imported file /home/person/Downloads/image.png as attachment ID 1753 and attached to post 123 as featured image. + * Success: Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image. * - * # Import a local image, but set it as the featured image for all posts - * # 1. Import the image and get its attachment ID - * # 2. Assign the attachment ID as the featured image for all posts + * # Import a local image, but set it as the featured image for all posts. + * # 1. Import the image and get its attachment ID. + * # 2. Assign the attachment ID as the featured image for all posts. * $ ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)" - * $ wp post list --post_type=post --format=ids | xargs -0 -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID + * $ wp post list --post_type=post --format=ids | xargs -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID * Success: Added custom field. * Success: Added custom field. * - * # Import an image from the web + * # Import an image from the web. * $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" - * Success: Imported file http://s.wordpress.org/style/images/wp-header-logo.png as attachment ID 1755. + * Success: Imported file 'http://s.wordpress.org/style/images/wp-header-logo.png' as attachment ID 1755. */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( @@ -183,7 +183,7 @@ function import( $args, $assoc_args = array() ) { if ( empty( $is_file_remote ) ) { if ( !file_exists( $file ) ) { - WP_CLI::warning( "Unable to import file $file. Reason: File doesn't exist." ); + WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." ); break; } $tempfile = $this->_make_copy( $file ); @@ -227,7 +227,7 @@ function import( $args, $assoc_args = array() ) { $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); if ( is_wp_error( $success ) ) { WP_CLI::warning( sprintf( - 'Unable to import file %s. Reason: %s', + "Unable to import file '%s'. Reason: %s", $orig_filename, implode( ', ', $success->get_error_messages() ) ) ); continue; @@ -254,7 +254,7 @@ function import( $args, $assoc_args = array() ) { WP_CLI::line( $success ); } else { WP_CLI::success( sprintf( - 'Imported file %s as attachment ID %d%s.', + "Imported file '%s' as attachment ID %d%s.", $orig_filename, $success, $attachment_success_text ) ); } From 2c6314847ea6175407c729bb76c13c4ecc953315 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 4 Aug 2016 11:57:16 +0545 Subject: [PATCH 4806/5359] Update test to reflect change in media import --- features/media-import.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/media-import.feature b/features/media-import.feature index 591d0db69..57e3a90e4 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -7,21 +7,21 @@ Feature: Manage WordPress attachments When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ - Success: Imported file http://wp-cli.org/behat-data/codeispoetry.png + Success: Imported file 'http://wp-cli.org/behat-data/codeispoetry.png' """ Scenario: Fail to import missing image When I try `wp media import gobbledygook.png` Then STDERR should contain: """ - Unable to import file gobbledygook.png. Reason: File doesn't exist. + Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. """ Scenario: Fail to import missing image on Windows When I try `wp media import c:/path/gobbledygook.png` Then STDERR should contain: """ - Unable to import file c:/path/gobbledygook.png. Reason: File doesn't exist. + Unable to import file 'c:/path/gobbledygook.png'. Reason: File doesn't exist. """ Scenario: Import a file as attachment from a local image From 86f52f0c27179b8cfb02bc0bd3b475db53ad80fb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 4 Aug 2016 12:09:51 +0545 Subject: [PATCH 4807/5359] Fix xargs param in theme status test --- features/theme.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index dcf1343a1..04b4a9ea7 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -54,7 +54,7 @@ Feature: Manage WordPress themes Given a WP install When I run `wp theme install classic --activate` - And I run `wp theme list --field=name --status=inactive | xargs -0 -d '\n' -I % wp theme delete %` + And I run `wp theme list --field=name --status=inactive | xargs wp theme delete` And I run `wp theme status` Then STDOUT should be: """ From 9155dfdc07d8da9edff5959a1cfd97e641e55a8b Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 4 Aug 2016 16:53:09 +0900 Subject: [PATCH 4808/5359] improve doc for `wp core language` --- php/WP_CLI/CommandWithTranslation.php | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 62710848d..dbd2ffb4a 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -51,6 +51,16 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { * * version * * package * + * ## EXAMPLES + * + * $ wp core language list --fields=language,english_name,status + * +----------------+-------------------------+-------------+ + * | language | english_name | status | + * +----------------+-------------------------+-------------+ + * | ar | Arabic | uninstalled | + * | ary | Moroccan Arabic | uninstalled | + * | az | Azerbaijani | uninstalled | + * * @subcommand list */ public function list_( $args, $assoc_args ) { @@ -110,6 +120,11 @@ protected function sort_translations_callback( $a, $b ) { * [--activate] * : If set, the language will be activated immediately after install. * + * ## EXAMPLES + * + * $ wp core language install ja + * Success: Language installed. + * * @subcommand install */ public function install( $args, $assoc_args ) { @@ -142,6 +157,17 @@ public function install( $args, $assoc_args ) { * [--dry-run] * : Preview which translations would be updated. * + * ## EXAMPLES + * + * $ wp core language update + * Updating 'Japanese' translation for Akismet 3.1.11... + * Downloading translation from https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/ja.zip... + * Translation updated successfully. + * Updating 'Japanese' translation for Twenty Fifteen 1.5... + * Downloading translation from https://downloads.wordpress.org/translation/theme/twentyfifteen/1.5/ja.zip... + * Translation updated successfully. + * Success: Updated 2/2 translations. + * * @subcommand update */ public function update( $args, $assoc_args ) { @@ -237,6 +263,11 @@ public function update( $args, $assoc_args ) { * <language> * : Language code to activate. * + * ## EXAMPLES + * + * $ wp core language activate ja + * Success: Language activated. + * * @subcommand activate */ public function activate( $args, $assoc_args ) { @@ -367,6 +398,11 @@ protected function get_all_languages() { * <language> * : Language code to uninstall. * + * ## EXAMPLES + * + * $ wp core language uninstall ja + * Success: Language uninstalled. + * * @subcommand uninstall */ public function uninstall( $args, $assoc_args ) { From d24ca812482f8d1678656d61873b8cb4d4051baf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 4 Aug 2016 05:24:52 -0700 Subject: [PATCH 4809/5359] Fix behavior of autoload parameter for `wp option (add|update)` YAML interprets `yes` and `no` to be boolean values, which breaks the default value for the underlying command. Instead, we need to make sure these options are quoted. No default value is necessary because null is an acceptable default value. --- features/option.feature | 60 +++++++++++++++++++++++++++++++++++++++++ php/commands/option.php | 10 +++---- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/features/option.feature b/features/option.feature index cd44b4596..a122016b9 100644 --- a/features/option.feature +++ b/features/option.feature @@ -141,3 +141,63 @@ Feature: Manage WordPress options Then STDOUT should be a table containing rows: | option_name | option_value | autoload | | hello | island | yes | + + @require-wp-4.2 + Scenario: Managed autoloaded options + Given a WP install + + When I run `wp option add wp_autoload_1 enabled --autoload=yes` + Then STDOUT should be: + """ + Success: Added 'wp_autoload_1' option. + """ + And STDERR should be empty + + When I run `wp option add wp_autoload_2 implicit` + Then STDOUT should be: + """ + Success: Added 'wp_autoload_2' option. + """ + And STDERR should be empty + + When I run `wp option add wp_autoload_3 disabled --autoload=no` + Then STDOUT should be: + """ + Success: Added 'wp_autoload_3' option. + """ + And STDERR should be empty + + When I run `wp option list --search='wp_autoload*' --fields=option_name,option_value,autoload` + Then STDOUT should be a table containing rows: + | option_name | option_value | autoload | + | wp_autoload_1 | enabled | yes | + | wp_autoload_2 | implicit | yes | + | wp_autoload_3 | disabled | no | + + When I run `wp option update wp_autoload_1 disabled --autoload=no` + Then STDOUT should be: + """ + Success: Updated 'wp_autoload_1' option. + """ + And STDERR should be empty + + When I run `wp option update wp_autoload_2 implicit2` + Then STDOUT should be: + """ + Success: Updated 'wp_autoload_2' option. + """ + And STDERR should be empty + + When I run `wp option update wp_autoload_3 enabled --autoload=yes` + Then STDOUT should be: + """ + Success: Updated 'wp_autoload_3' option. + """ + And STDERR should be empty + + When I run `wp option list --search='wp_autoload*' --fields=option_name,option_value,autoload` + Then STDOUT should be a table containing rows: + | option_name | option_value | autoload | + | wp_autoload_1 | disabled | no | + | wp_autoload_2 | implicit2 | yes | + | wp_autoload_3 | enabled | yes | diff --git a/php/commands/option.php b/php/commands/option.php index 2da6e107d..6850ad409 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -90,10 +90,9 @@ public function get( $args, $assoc_args ) { * [--autoload=<autoload>] * : Should this option be automatically loaded. * --- - * default: yes * options: - * - yes - * - no + * - 'yes' + * - 'no' * --- * * ## EXAMPLES @@ -261,10 +260,9 @@ public function list_( $args, $assoc_args ) { * [--autoload=<autoload>] * : Requires WP 4.2. Should this option be automatically loaded. * --- - * default: yes * options: - * - yes - * - no + * - 'yes' + * - 'no' * --- * * [--format=<format>] From 78e7306d64c6edf6947b4deb379e019de02e4aeb Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 4 Aug 2016 21:17:57 +0545 Subject: [PATCH 4810/5359] Add command description in db import --- php/commands/db.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/db.php b/php/commands/db.php index 57828e98b..6dff55ea8 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -292,6 +292,11 @@ function export( $args, $assoc_args ) { /** * Import a MySQL database from a file or from STDIN. * + * Runs MySQL queries using `DB_HOST`, `DB_NAME`, `DB_USER` and + * `DB_PASSWORD` database credentials specified in wp-config.php. This + * does not create database by itself and only performs whatever tasks are + * defined in the SQL. + * * ## OPTIONS * * [<file>] @@ -299,6 +304,7 @@ function export( $args, $assoc_args ) { * * ## EXAMPLES * + * # Import MySQL from a file. * $ wp db import wordpress_dbase.sql * Success: Imported from 'wordpress_dbase.sql'. */ From 7793be6a314978c1fabe7efc911c5e8d8c6ff30d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 4 Aug 2016 08:59:03 -0700 Subject: [PATCH 4811/5359] Fix `--skip-plugins` for network-activated plugins Using `--skip-plugins=<slug>` should only disable that specific plugin, not all network-activated plugins. Also makes the tests a bit more comprehensive. --- features/skip-plugins.feature | 47 ++++++++++++++++++----------------- php/WP_CLI/Runner.php | 16 +++++++++--- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/features/skip-plugins.feature b/features/skip-plugins.feature index 8105cc620..98695933b 100644 --- a/features/skip-plugins.feature +++ b/features/skip-plugins.feature @@ -4,16 +4,10 @@ Feature: Skipping plugins Given a WP install And I run `wp plugin activate hello akismet` - When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` + When I run `wp eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` Then STDOUT should be: """ - true - """ - - When I run `wp eval 'var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - true + truetrue """ # The specified plugin should be skipped @@ -31,10 +25,10 @@ Feature: Skipping plugins """ # The un-specified plugin should continue to be loaded - When I run `wp --skip-plugins=akismet eval 'var_export( function_exists( "hello_dolly" ) );'` + When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` Then STDOUT should be: """ - true + falsetrue """ # Can specify multiple plugins to skip @@ -45,15 +39,10 @@ Feature: Skipping plugins """ # No plugins should be loaded when --skip-plugins doesn't have a value - When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );'` - Then STDOUT should be: - """ - false - """ - When I run `wp --skip-plugins eval 'var_export( function_exists( "hello_dolly" ) );'` + When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` Then STDOUT should be: """ - false + falsefalse """ Scenario: Skipping multiple plugins via config file @@ -88,17 +77,29 @@ Feature: Skipping plugins Scenario: Skip network active plugins Given a WP multisite install - And I run `wp plugin deactivate akismet` - And I run `wp plugin activate --network akismet` + And I run `wp plugin deactivate akismet hello` + And I run `wp plugin activate --network akismet hello` - When I run `wp eval 'var_export( defined("AKISMET_VERSION") );'` + When I run `wp eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` Then STDOUT should be: """ - true + truetrue """ - When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` + When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` Then STDOUT should be: """ - false + falsefalse + """ + + When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + falsetrue + """ + + When I run `wp --skip-plugins=hello eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` + Then STDOUT should be: + """ + truefalse """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 592081b28..7e0ed54a9 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1139,12 +1139,20 @@ private function setup_skip_plugins_filters() { if ( ! is_array( $plugins ) ) { return $plugins; } - foreach( $plugins as $key => $plugin ) { - if ( Utils\is_plugin_skipped( $plugin ) ) { - unset( $plugins[ $key ] ); + foreach( $plugins as $a => $b ) { + // active_sitewide_plugins stores plugin name as the key + if ( false !== strpos( current_filter(), 'active_sitewide_plugins' ) && Utils\is_plugin_skipped( $a ) ) { + unset( $plugins[ $a ] ); + // active_plugins stores plugin name as the value + } else if ( false !== strpos( current_filter(), 'active_plugins' ) && Utils\is_plugin_skipped( $b ) ) { + unset( $plugins[ $a ] ); } } - return array_values( $plugins ); + // Reindex because active_plugins expects a numeric index + if ( false !== strpos( current_filter(), 'active_plugins' ) ) { + $plugins = array_values( $plugins ); + } + return $plugins; }; $hooks = array( From 38d0abed9ee0d5f8edbd939abd4e1f56ca5facdf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 5 Aug 2016 11:27:31 -0700 Subject: [PATCH 4812/5359] Update README.md to indicate Github issues are no longer for support --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a1b8fc30..9f2eba0ed 100644 --- a/README.md +++ b/README.md @@ -115,15 +115,14 @@ source /FULL/PATH/TO/wp-completion.bash ## Support -WP-CLI's maintainers and project contributors do their best to respond to all new issues in a timely manner. To make the best use of their volunteered time, please first see if there may be an answer to your question in one of the following resources: +WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address the variety of questions users might have. Before filing your support request, please first see if there is an answer in one of the following resources: - [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) -- [Best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) - [Documentation portal](https://wp-cli.org/docs/) - [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) -If you can't find your answer in one of those existing resources, feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question. +If you can't find your answer at one of those links, the [WordPress StackExchange](http://wordpress.stackexchange.com/) is the best place for general support questions. For bug reports, please review [best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) before [creating a new issue](https://github.com/wp-cli/wp-cli/issues/new). Professional users may also consider [runcommand](https://runcommand.io/) for premium support. Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. From a694d603f5d8559195845001f0715597f669f699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Mon, 8 Aug 2016 01:00:38 +0200 Subject: [PATCH 4813/5359] Syntax highlight for README --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9f2eba0ed..1b26a6d4e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Quick links: [Using](#using) | [Installing](#installing) | [Support](# WP-CLI's goal is to provide a command-line interface for any action you might want to perform in the WordPress admin. For instance, `wp plugin install --activate` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: -``` +```bash $ wp plugin install rest-api --activate Installing WordPress REST API (Version 2) (2.0-beta13) Downloading install package from https://downloads.wordpress.org/plugin/rest-api.2.0-beta13.zip... @@ -37,7 +37,7 @@ Success: Plugin 'rest-api' activated. WP-CLI also includes commands for many things you can't do in the WordPress admin. For example, `wp transient delete-all` ([doc](https://wp-cli.org/commands/transient/delete-all/)) lets you delete one or all transients: -``` +```bash $ wp transient delete-all Success: 34 transients deleted from the database. ``` @@ -58,26 +58,26 @@ Before installing WP-CLI, please make sure your environment meets the minimum re Once you've verified requirements, download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) file using `wget` or `curl`: -``` +```bash $ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar ``` Next, check if it is working: -``` +```bash $ php wp-cli.phar --info ``` To use WP-CLI from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: -``` +```bash $ chmod +x wp-cli.phar $ sudo mv wp-cli.phar /usr/local/bin/wp ``` If WP-CLI was installed successfully, you should see something like this when you run `wp --info`: -``` +```bash $ wp --info PHP binary: /usr/bin/php5 PHP version: 5.5.9-1ubuntu4.14 @@ -99,7 +99,7 @@ Want to live life on the edge? Run `wp cli update --nightly` to use the latest n WP-CLI also comes with a tab completion script for Bash and ZSH. Just download [wp-completion.bash](https://github.com/wp-cli/wp-cli/raw/master/utils/wp-completion.bash) and source it from `~/.bash_profile`: -``` +```bash source /FULL/PATH/TO/wp-completion.bash ``` @@ -107,7 +107,7 @@ Don't forget to run `source ~/.bash_profile` afterwards. If using zsh for your shell, you may need to load and start `bashcompinit` before sourcing. Put the following in your `.zshrc`: -``` +```bash autoload bashcompinit bashcompinit source /FULL/PATH/TO/wp-completion.bash @@ -134,7 +134,7 @@ A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([d WP-CLI supports registering any callable class, function, or closure as a command. It reads usage details from the callback's PHPdoc. `WP_CLI::add_command()` ([doc](https://wp-cli.org/docs/internal-api/wp-cli-add-command/)) is used for both internal and third-party command registration. -``` +```php /** * Delete an option from the database. * From 6ac0df413086397cf6073d39e830779766b6d2fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Aug 2016 05:27:13 -0700 Subject: [PATCH 4814/5359] Update dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing mustache/mustache (v2.10.0) - Installing mustache/mustache (v2.11.1) Downloading: 100% - Removing symfony/finder (v2.8.8) - Installing symfony/finder (v2.8.9) Downloading: 100% - Removing symfony/yaml (v2.8.8) - Installing symfony/yaml (v2.8.9) Downloading: 100% - Removing symfony/filesystem (v2.8.8) - Installing symfony/filesystem (v2.8.9) Downloading: 100% - Removing symfony/config (v2.8.8) - Installing symfony/config (v2.8.9) Downloading: 100% - Removing symfony/console (v2.8.8) - Installing symfony/console (v2.8.9) Downloading: 100% - Removing symfony/dependency-injection (v2.8.8) - Installing symfony/dependency-injection (v2.8.9) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.8) - Installing symfony/event-dispatcher (v2.8.9) Downloading: 100% - Removing symfony/process (v2.8.8) - Installing symfony/process (v2.8.9) Downloading: 100% - Removing symfony/translation (v2.8.8) - Installing symfony/translation (v2.8.9) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 104 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/composer.lock b/composer.lock index 4cab63408..ede24ebab 100644 --- a/composer.lock +++ b/composer.lock @@ -332,23 +332,23 @@ }, { "name": "mustache/mustache", - "version": "v2.10.0", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "0bb2f76e2f34a8864a32be34c4ec66274d76c05e" + "reference": "a3f6d55996dd28b58f3a909d474189a3c1aa693f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/0bb2f76e2f34a8864a32be34c4ec66274d76c05e", - "reference": "0bb2f76e2f34a8864a32be34c4ec66274d76c05e", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/a3f6d55996dd28b58f3a909d474189a3c1aa693f", + "reference": "a3f6d55996dd28b58f3a909d474189a3c1aa693f", "shasum": "" }, "require": { "php": ">=5.2.4" }, "require-dev": { - "fabpot/php-cs-fixer": "~1.6", + "friendsofphp/php-cs-fixer": "~1.11", "phpunit/phpunit": "~3.7|~4.0|~5.0" }, "type": "library", @@ -374,7 +374,7 @@ "mustache", "templating" ], - "time": "2016-02-27 19:22:46" + "time": "2016-07-31 06:18:27" }, { "name": "mustangostang/spyc", @@ -736,16 +736,16 @@ }, { "name": "symfony/config", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0" + "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0926e69411eba491803dbafb9f1f233e2ced58d0", - "reference": "0926e69411eba491803dbafb9f1f233e2ced58d0", + "url": "https://api.github.com/repos/symfony/config/zipball/4275ef5b59f18959df0eee3991e9ca0cc208ffd4", + "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4", "shasum": "" }, "require": { @@ -785,20 +785,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:31:50" + "time": "2016-07-26 08:02:44" }, { "name": "symfony/console", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa" + "reference": "36e62335caca8a6e909c5c5bac4a8128149911c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c392a6ec72f2122748032c2ad6870420561ffcfa", - "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa", + "url": "https://api.github.com/repos/symfony/console/zipball/36e62335caca8a6e909c5c5bac4a8128149911c9", + "reference": "36e62335caca8a6e909c5c5bac4a8128149911c9", "shasum": "" }, "require": { @@ -845,20 +845,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-06-29 07:02:14" + "time": "2016-07-30 07:20:35" }, { "name": "symfony/dependency-injection", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063" + "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2dd85de8216079d1360b2b14988cd5cdbbb49063", - "reference": "2dd85de8216079d1360b2b14988cd5cdbbb49063", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f2b5a00d176f6a201dc430375c0ef37706ea3d12", + "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12", "shasum": "" }, "require": { @@ -870,7 +870,7 @@ "require-dev": { "symfony/config": "~2.2|~3.0.0", "symfony/expression-language": "~2.6|~3.0.0", - "symfony/yaml": "~2.1|~3.0.0" + "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7" }, "suggest": { "symfony/config": "", @@ -908,20 +908,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:31:50" + "time": "2016-07-30 07:20:35" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9" + "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b180b70439dca70049b6b9b7e21d75e6e5d7aca9", - "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8", + "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8", "shasum": "" }, "require": { @@ -968,20 +968,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:29:29" + "time": "2016-07-28 16:56:28" }, { "name": "symfony/filesystem", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7258ddd6f987053f21fa43d03430580ba54e6096" + "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7258ddd6f987053f21fa43d03430580ba54e6096", - "reference": "7258ddd6f987053f21fa43d03430580ba54e6096", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ab4c3f085c8f5a56536845bf985c4cef30bf75fd", + "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd", "shasum": "" }, "require": { @@ -1017,20 +1017,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:31:50" + "time": "2016-07-20 05:41:28" }, { "name": "symfony/finder", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d" + "reference": "60804d88691e4a73bbbb3035eb1d9f075c5c2c10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d", - "reference": "bf0506ef4e7778fd3f0f1f141ab5e8c1ef35dd7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/60804d88691e4a73bbbb3035eb1d9f075c5c2c10", + "reference": "60804d88691e4a73bbbb3035eb1d9f075c5c2c10", "shasum": "" }, "require": { @@ -1066,7 +1066,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:29:29" + "time": "2016-07-26 08:02:44" }, { "name": "symfony/polyfill-mbstring", @@ -1129,16 +1129,16 @@ }, { "name": "symfony/process", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe" + "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/89f33c16796415ccfd8bb3cf8d520cbb79899bfe", - "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe", + "url": "https://api.github.com/repos/symfony/process/zipball/d20332e43e8774ff8870b394f3dd6020cc7f8e0c", + "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c", "shasum": "" }, "require": { @@ -1174,20 +1174,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:29:29" + "time": "2016-07-28 11:13:19" }, { "name": "symfony/translation", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0" + "reference": "32b0c824da6df065f43b0c458dc505940e98a7f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/00334ef0b9317e5d7c7641a2b56671a1df23b7a0", - "reference": "00334ef0b9317e5d7c7641a2b56671a1df23b7a0", + "url": "https://api.github.com/repos/symfony/translation/zipball/32b0c824da6df065f43b0c458dc505940e98a7f1", + "reference": "32b0c824da6df065f43b0c458dc505940e98a7f1", "shasum": "" }, "require": { @@ -1238,20 +1238,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:29:29" + "time": "2016-07-30 07:20:35" }, { "name": "symfony/yaml", - "version": "v2.8.8", + "version": "v2.8.9", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8" + "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/dba4bb5846798cd12f32e2d8f3f35d77045773c8", - "reference": "dba4bb5846798cd12f32e2d8f3f35d77045773c8", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0ceab136f43ed9d3e97b3eea32a7855dc50c121d", + "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d", "shasum": "" }, "require": { @@ -1287,7 +1287,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:29:29" + "time": "2016-07-17 09:06:15" }, { "name": "wp-cli/php-cli-tools", From c24cce5f0f1f6cc82cbbae5dc0da946782ce8fe3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Aug 2016 06:36:18 -0700 Subject: [PATCH 4815/5359] Clarify that StackExchange isn't meant for general support --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1b26a6d4e..96c278035 100644 --- a/README.md +++ b/README.md @@ -115,18 +115,19 @@ source /FULL/PATH/TO/wp-completion.bash ## Support -WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address the variety of questions users might have. Before filing your support request, please first see if there is an answer in one of the following resources: +WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. First, look for an answer in one of the following resources: - [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) - [Documentation portal](https://wp-cli.org/docs/) - [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) +- [runcommand Excerpts](https://runcommand.io/excerpts/) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) -If you can't find your answer at one of those links, the [WordPress StackExchange](http://wordpress.stackexchange.com/) is the best place for general support questions. For bug reports, please review [best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) before [creating a new issue](https://github.com/wp-cli/wp-cli/issues/new). Professional users may also consider [runcommand](https://runcommand.io/) for premium support. +If you can't find your answer at one of those links, the [WordPress StackExchange](http://wordpress.stackexchange.com/) can be used for development-related WP-CLI questions. Or, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand](https://runcommand.io/) for premium support. -Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. +For bug reports, please review [best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) before [creating a new issue](https://github.com/wp-cli/wp-cli/issues/new). -If you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). +Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. ## Extending From 23e0f58be923b7e8d26396c8e55a704b5092a901 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Aug 2016 06:59:03 -0700 Subject: [PATCH 4816/5359] Include line about libre != gratis --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 96c278035..bf7c6ab06 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ For bug reports, please review [best practices for submitting a bug report](http Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. +Remember, libre != gratis; the open source license grants you the freedom to use and modify, but not commitments of other people's time. Please be respectful, and set your expectations accordingly. + ## Extending A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. From 7a274f09cdf288e505a7b20e969c1a8b2f30bf11 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 9 Aug 2016 07:05:06 -0700 Subject: [PATCH 4817/5359] First pass at an issue template --- .github/ISSUE_TEMPLATE | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE new file mode 100644 index 000000000..d255d8f7a --- /dev/null +++ b/.github/ISSUE_TEMPLATE @@ -0,0 +1,11 @@ +<!-- + +Thanks for taking the time to help improve WP-CLI! + +Found a bug or want to suggest an enhancement? Before submitting an issue, please review our best practices: http://wp-cli.org/docs/bug-reports/ + +Need help with something? Github issues aren't for general support questions, but there are other venues you can try: http://wp-cli.org/#support + +You can safely delete this comment. + +--> From 7329f7ffff67c2e626c7f392a2c7dd4b9051b27e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 05:05:52 -0700 Subject: [PATCH 4818/5359] Catch exceptions thrown by `RecursiveDirectoryIterator` --- php/commands/core.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 16fc7363b..fd212bb10 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1066,16 +1066,19 @@ public function verify_checksums( $args, $assoc_args ) { } private function get_wp_core_files() { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( ABSPATH, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - $core_files = array(); - foreach ( $files as $file_info ) { - if ( $file_info->isFile() && ( false !== strpos( $file_info->getPathname(), 'wp-admin/' ) || false !== strpos( $file_info->getPathname(), 'wp-includes/' ) ) ) { - $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); + try { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( ABSPATH, RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ( $files as $file_info ) { + if ( $file_info->isFile() && ( false !== strpos( $file_info->getPathname(), 'wp-admin/' ) || false !== strpos( $file_info->getPathname(), 'wp-includes/' ) ) ) { + $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); + } } + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); } return $core_files; From e7e11c0442104e0be82b994d8dfd8b737f3c2d79 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 05:17:24 -0700 Subject: [PATCH 4819/5359] Include adequate vertical spacing around inserted constants --- php/commands/core.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 16fc7363b..300fa55cd 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -901,6 +901,8 @@ private static function modify_wp_config( $content ) { list( $before, $after ) = explode( $token, file_get_contents( $wp_config_path ) ); + $content = PHP_EOL . PHP_EOL . trim( $content ) . PHP_EOL . PHP_EOL; + file_put_contents( $wp_config_path, $before . $content . $token . $after ); } From 8a2a7e0da240bb08ea22545ad31daca6f9820e07 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 05:30:50 -0700 Subject: [PATCH 4820/5359] When checking for additional files, only check core directories Core's `wp-admin/` and `wp-includes/` directories are immediately after ABSPATH. Don't flag files inside of `wp-admin/` and `wp-includes/` directories in plugins. --- features/core-verify-checksums.feature | 14 ++++++++++++++ php/commands/core.php | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 5f40e66b7..0721b897c 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -85,3 +85,17 @@ Feature: Validate checksums for WordPress install """ Success: WordPress install verifies against checksums. """ + + Scenario: Verify core checksums with a plugin that has wp-admin + Given a WP install + And a wp-content/plugins/akismet/wp-admin/extra-file.txt file: + """ + hello world + """ + + When I run `wp core verify-checksums` + Then STDOUT should be: + """ + Success: WordPress install verifies against checksums. + """ + And STDERR should be empty diff --git a/php/commands/core.php b/php/commands/core.php index 16fc7363b..a3a4dfb92 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1073,7 +1073,8 @@ private function get_wp_core_files() { $core_files = array(); foreach ( $files as $file_info ) { - if ( $file_info->isFile() && ( false !== strpos( $file_info->getPathname(), 'wp-admin/' ) || false !== strpos( $file_info->getPathname(), 'wp-includes/' ) ) ) { + $pathname = substr( $file_info->getPathname(), strlen( ABSPATH ) ); + if ( $file_info->isFile() && ( 0 === strpos( $pathname, 'wp-admin/' ) || 0 === strpos( $pathname, 'wp-includes/' ) ) ) { $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); } } @@ -1082,7 +1083,7 @@ private function get_wp_core_files() { } private function only_core_files_filter( $file ) { - return ( false !== strpos( $file, 'wp-admin/' ) || false !== strpos( $file, 'wp-includes/' ) ); + return ( 0 === strpos( $file, 'wp-admin/' ) || 0 === strpos( $file, 'wp-includes/' ) ); } /** From 6641cd9b70b34b8dc2e149044e56da7a2d7455d7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 05:41:53 -0700 Subject: [PATCH 4821/5359] Properly support registering an instantiated object as a command --- features/command.feature | 31 ++++++++++++++++++++++++ php/WP_CLI/Dispatcher/CommandFactory.php | 10 +++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/features/command.feature b/features/command.feature index f4f5aec2d..062737979 100644 --- a/features/command.feature +++ b/features/command.feature @@ -584,3 +584,34 @@ Feature: WP-CLI Commands When I run `wp post list` Then STDOUT should be a number + + Scenario: Use class passed as object + Given an empty directory + And a custom-cmd.php file: + """ + <?php + class Foo_Class { + + public function __construct( $message ) { + $this->message = $message; + } + + /** + * My awesome class method command + * + * @when before_wp_load + */ + function message( $args ) { + WP_CLI::success( $this->message ); + } + } + $foo = new Foo_Class( 'bar' ); + WP_CLI::add_command( 'instantiated-command', $foo ); + """ + + When I run `wp --require=custom-cmd.php instantiated-command message` + Then STDOUT should contain: + """ + bar + """ + And STDERR should be empty diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php index 5b05568c5..bd667fe05 100644 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ b/php/WP_CLI/Dispatcher/CommandFactory.php @@ -33,7 +33,7 @@ public static function create( $name, $callable, $parent ) { $command = self::create_subcommand( $parent, $name, array( $class, '__invoke' ), $reflection->getMethod( '__invoke' ) ); } else { - $command = self::create_composite_command( $parent, $name, $reflection ); + $command = self::create_composite_command( $parent, $name, $callable ); } } @@ -78,9 +78,10 @@ private static function create_subcommand( $parent, $name, $callable, $reflectio * * @param mixed $parent The new command's parent Root or Composite command * @param string $name Represents how the command should be invoked - * @param ReflectionClass $reflection + * @param mixed $callable */ - private static function create_composite_command( $parent, $name, $reflection ) { + private static function create_composite_command( $parent, $name, $callable ) { + $reflection = new \ReflectionClass( $callable ); $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); $container = new CompositeCommand( $parent, $name, $docparser ); @@ -89,7 +90,8 @@ private static function create_composite_command( $parent, $name, $reflection ) if ( !self::is_good_method( $method ) ) continue; - $subcommand = self::create_subcommand( $container, false, array( $reflection->name, $method->name ), $method ); + $class = is_object( $callable ) ? $callable : $reflection->name; + $subcommand = self::create_subcommand( $container, false, array( $class, $method->name ), $method ); $subcommand_name = $subcommand->get_name(); From 819c2caccf45dc05b0e2363871d2eb9788d464df Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 06:01:40 -0700 Subject: [PATCH 4822/5359] Indicate current file in WXR import progress indicator Doing so communicates the total count is of the current file, not all files. --- features/import.feature | 16 ++++++++++++++++ php/commands/import.php | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/features/import.feature b/features/import.feature index 54a06829b..7398920df 100644 --- a/features/import.feature +++ b/features/import.feature @@ -232,3 +232,19 @@ Feature: Import content. """ 2 """ + + Scenario: Indicate current file when importing + Given a WP install + And I run `wp plugin install --activate wordpress-importer` + + When I run `wp export --filename_format=wordpress.{n}.xml` + Then save STDOUT 'Writing to file %s' as {EXPORT_FILE} + + When I run `wp site empty --yes` + Then STDOUT should not be empty + + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should contain: + """ + -- 1 of 2 (in file wordpress.000.xml) + """ diff --git a/php/commands/import.php b/php/commands/import.php index 8ae820833..a2be901a8 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -167,6 +167,7 @@ private function import_wxr( $file, $args ) { add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_set_image_sizes' ) ); } + $GLOBALS['wp_cli_import_current_file'] = basename( $file ); $wp_import->import( $file ); $this->processed_posts += $wp_import->processed_posts; @@ -198,13 +199,13 @@ private function add_wxr_filters() { }, 10, 3 ); add_filter( 'wp_import_post_data_raw', function( $post ) { - global $wpcli_import_counts; + global $wpcli_import_counts, $wp_cli_import_current_file; $wpcli_import_counts['current_post']++; WP_CLI::log(''); WP_CLI::log(''); WP_CLI::log( sprintf( 'Processing post #%d ("%s") (post_type: %s)', $post['post_id'], $post['post_title'], $post['post_type'] ) ); - WP_CLI::log( sprintf( '-- %s of %s', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ) ) ); + WP_CLI::log( sprintf( '-- %s of %s (in file %s)', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ), $wp_cli_import_current_file ) ); WP_CLI::log( '-- ' . date( 'r' ) ); return $post; From b8ae92d19ca2b49b9d2e815e740af0a3c1dba06d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 06:15:37 -0700 Subject: [PATCH 4823/5359] Mark `WP_CLI::get_config()` as a public internal API --- php/class-wp-cli.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 14024ac98..c03140913 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -863,6 +863,18 @@ public static function get_php_binary() { return 'php'; } + /** + * Get values of global configuration parameters. + * + * Provides access to `--path=<path>`, `--url=<url>`, and other values of + * the [global configuration parameters](https://wp-cli.org/config/). + * + * @access public + * @category Input + * + * @param string $key Get value for a specific global configuration parameter. + * @return mixed + */ public static function get_config( $key = null ) { if ( null === $key ) { return self::get_runner()->config; From 0da7253566780cd07a2731ff45deae339ec95d28 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 06:21:35 -0700 Subject: [PATCH 4824/5359] Include an example --- php/class-wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index c03140913..8fc855687 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -869,6 +869,10 @@ public static function get_php_binary() { * Provides access to `--path=<path>`, `--url=<url>`, and other values of * the [global configuration parameters](https://wp-cli.org/config/). * + * ``` + * WP_CLI::log( 'The --url=<url> value is: ' . WP_CLI::get_config( 'url' ) ); + * ``` + * * @access public * @category Input * From b90ebf6130c9d5e7840280a7c51271167150bbeb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 10 Aug 2016 06:55:09 -0700 Subject: [PATCH 4825/5359] Warn when multisite constants can't be inserted into wp-config Multisite constants are injected based on a token. When the token can't be found, we should let the end user know, instead of erroneously inserting at the end of wp-config.php --- features/core.feature | 15 +++++++++++++++ php/commands/core.php | 13 ++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/features/core.feature b/features/core.feature index 87bebc383..1659b7184 100644 --- a/features/core.feature +++ b/features/core.feature @@ -333,3 +333,18 @@ Feature: Manage WordPress installation """ http://wp.dev """ + + Scenario: Warn when multisite constants can't be inserted into wp-config + Given a WP install + And I run `sed -i.bak "s/That's\sall/C'est tout/g" wp-config.php` + + When I run `wp core multisite-convert` + Then STDOUT should be: + """ + Set up multisite database tables. + Success: Network installed. Don't forget to set up rewrite rules. + """ + And STDERR should contain: + """ + Warning: Multisite constants could not be written to 'wp-config.php'. You may need to add them manually: + """ diff --git a/php/commands/core.php b/php/commands/core.php index 806d7fd2e..1f0ff1cb8 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -841,12 +841,10 @@ private function _multisite_convert( $assoc_args ) { EOT; $wp_config_path = Utils\locate_wp_config(); - if ( is_writable( $wp_config_path ) ) { - self::modify_wp_config( $ms_config ); + if ( is_writable( $wp_config_path ) && self::modify_wp_config( $ms_config ) ) { WP_CLI::log( "Added multisite constants to 'wp-config.php'." ); } else { - WP_CLI::warning( "Multisite constants could not be written to 'wp-config.php'. You may need to add them manually:" ); - WP_CLI::log( $ms_config ); + WP_CLI::warning( "Multisite constants could not be written to 'wp-config.php'. You may need to add them manually:" . PHP_EOL . $ms_config ); } } @@ -898,12 +896,17 @@ private static function modify_wp_config( $content ) { $wp_config_path = Utils\locate_wp_config(); $token = "/* That's all, stop editing!"; + $config_contents = file_get_contents( $wp_config_path ); + if ( false === strpos( $config_contents, $token ) ) { + return false; + } - list( $before, $after ) = explode( $token, file_get_contents( $wp_config_path ) ); + list( $before, $after ) = explode( $token, $config_contents ); $content = PHP_EOL . PHP_EOL . trim( $content ) . PHP_EOL . PHP_EOL; file_put_contents( $wp_config_path, $before . $content . $token . $after ); + return true; } private static function get_clean_basedomain() { From 3fc84c100c3e9cd0b3a829e2c599f277460cd657 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 11 Aug 2016 11:44:13 +0545 Subject: [PATCH 4826/5359] Passed slashed data in meta --- php/WP_CLI/CommandWithMeta.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 0e8a07a39..26c717c20 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -179,6 +179,7 @@ public function add( $args, $assoc_args ) { $object_id = $this->check_object_id( $object_id ); + $meta_value = wp_slash( $meta_value ); $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { @@ -221,6 +222,7 @@ public function update( $args, $assoc_args ) { if ( $meta_value === $old_value ) { WP_CLI::success( "Value passed for custom field '$meta_key' is unchanged." ); } else { + $meta_value = wp_slash( $meta_value ); $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); if ( $success ) { From 8281a5c44bdb856bb2a035fb7a79ac97c64a40eb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 11 Aug 2016 11:49:09 +0545 Subject: [PATCH 4827/5359] Update test to reflect change in slashed data --- features/post-meta.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/post-meta.feature b/features/post-meta.feature index a7eacd135..e8dd92da3 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -109,3 +109,33 @@ Feature: Manage post custom fields Then STDOUT should be a table containing rows: | post_id | meta_key | meta_value | | 1 | foo | | + + Scenario: Make sure WordPress receives the slashed data it expects in meta fields + Given a WP install + + When I run `wp post-meta add 1 foo 'My\Meta'` + Then STDOUT should not be empty + + When I run `wp post-meta get 1 foo` + Then STDOUT should be: + """ + My\Meta + """ + + When I run `wp post-meta update 1 foo 'My\New\Meta'` + Then STDOUT should be: + """ + Success: Updated custom field 'foo'. + """ + + When I run the previous command again + Then STDOUT should be: + """ + Success: Value passed for custom field 'foo' is unchanged. + """ + + When I run `wp post-meta get 1 foo` + Then STDOUT should be: + """ + My\New\Meta + """ From fead1145c11c95e3f2228267ace1a568c1cce89c Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Thu, 11 Aug 2016 15:20:32 +0400 Subject: [PATCH 4828/5359] sync package composer repository on install --- php/commands/package.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index 471c8b969..3f9628a1e 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -183,6 +183,14 @@ public function install( $args, $assoc_args ) { $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); $json_manipulator->addLink( 'require', $package_name, $version ); $json_manipulator->addConfigSetting( 'secure-http', true ); + + // If the composer file does not contain the current package index url, refresh the repository definition. + if ( false === strpos( $composer_backup, self::PACKAGE_INDEX_URL ) ) { + WP_CLI::log( 'Updating package index repository url...' ); + $json_manipulator->removeRepository( 'wp-cli' ); + $json_manipulator->addRepository( 'wp-cli', array( 'type' => 'composer', 'url' => self::PACKAGE_INDEX_URL ) ); + } + file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); try { $composer = $this->get_composer(); From d8b1ffd9a248fe7943bd822641849e4a7bb1241b Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Thu, 11 Aug 2016 15:26:53 +0400 Subject: [PATCH 4829/5359] no need to remove the repository first --- php/commands/package.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/commands/package.php b/php/commands/package.php index 3f9628a1e..5207f86dc 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -187,7 +187,6 @@ public function install( $args, $assoc_args ) { // If the composer file does not contain the current package index url, refresh the repository definition. if ( false === strpos( $composer_backup, self::PACKAGE_INDEX_URL ) ) { WP_CLI::log( 'Updating package index repository url...' ); - $json_manipulator->removeRepository( 'wp-cli' ); $json_manipulator->addRepository( 'wp-cli', array( 'type' => 'composer', 'url' => self::PACKAGE_INDEX_URL ) ); } From c53a137f40575e32632416131968af00d51244cc Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Thu, 11 Aug 2016 16:57:55 +0400 Subject: [PATCH 4830/5359] limit package index check to wp-cli repository only --- php/commands/package.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 5207f86dc..b281f7ecd 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -184,8 +184,9 @@ public function install( $args, $assoc_args ) { $json_manipulator->addLink( 'require', $package_name, $version ); $json_manipulator->addConfigSetting( 'secure-http', true ); - // If the composer file does not contain the current package index url, refresh the repository definition. - if ( false === strpos( $composer_backup, self::PACKAGE_INDEX_URL ) ) { + $composer_backup_decoded = json_decode( $composer_backup, true ); + // If the composer file does not contain the current package index repository, refresh the repository definition. + if ( empty( $composer_backup_decoded['repositories']['wp-cli']['url'] ) || self::PACKAGE_INDEX_URL != $composer_backup_decoded['repositories']['wp-cli']['url'] ) { WP_CLI::log( 'Updating package index repository url...' ); $json_manipulator->addRepository( 'wp-cli', array( 'type' => 'composer', 'url' => self::PACKAGE_INDEX_URL ) ); } From 10f9317ea397bd2f98e929505870de2951a3bdce Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Fri, 12 Aug 2016 01:20:24 +0400 Subject: [PATCH 4831/5359] add functional test for syncing package index on install --- features/package-install.feature | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/features/package-install.feature b/features/package-install.feature index d883aafd0..63061fd5a 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -1,5 +1,35 @@ Feature: Install WP-CLI packages + Scenario: Install a package with an old package index url in package composer.json + Given an empty directory + And a composer.json file: + """ + { + "repositories": { + "wp-cli": { + "type": "composer", + "url": "http://wp-cli.org/package-index/" + } + } + } + """ + When I run `rm -rf /tmp/wp-cli-package-install-test/ && mkdir /tmp/wp-cli-package-install-test/ && mv composer.json /tmp/wp-cli-package-install-test/` + Then the /tmp/wp-cli-package-install-test/composer.json file should exist + When I run `WP_CLI_PACKAGES_DIR=/tmp/wp-cli-package-install-test/ wp --info` + Then STDOUT should contain: + """ + WP-CLI packages dir: /tmp/wp-cli-package-install-test/ + """ + When I run `WP_CLI_PACKAGES_DIR=/tmp/wp-cli-package-install-test/ wp package install runcommand/hook` + Then the /tmp/wp-cli-package-install-test/composer.json file should contain: + """ + "url": "https://wp-cli.org/package-index/" + """ + And the /tmp/wp-cli-package-install-test/composer.json file should not contain: + """ + "url": "http://wp-cli.org/package-index/" + """ + Scenario: Install a package with 'wp-cli/wp-cli' as a dependency Given a WP install From a62cd6111eae548cfb2801c1c22532482ce97013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 12 Aug 2016 00:30:55 +0200 Subject: [PATCH 4832/5359] Typo in db optimize and in db repair's comment OPTIMIZE_TABLE is really OPTIMIZE TABLE --- php/commands/db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 6dff55ea8..9ca85213a 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -102,7 +102,7 @@ public function reset( $_, $assoc_args ) { * specified in wp-config.php. * * [See docs](http://dev.mysql.com/doc/refman/5.7/en/optimize-table.html) - * for more details on the `OPTIMIZE_TABLE` statement. + * for more details on the `OPTIMIZE TABLE` statement. * * ## EXAMPLES * @@ -125,7 +125,7 @@ public function optimize() { * specified in wp-config.php. * * [See docs](http://dev.mysql.com/doc/refman/5.7/en/repair-table.html) for - * more details on the `REPAIR_TABLE` statement. + * more details on the `REPAIR TABLE` statement. * * ## EXAMPLES * From 8a8ab62e9ee3e4689f30405b5e63af3337345fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 11 Aug 2016 22:37:10 +0000 Subject: [PATCH 4833/5359] Implement wp db check --- features/db.feature | 3 +++ php/commands/db.php | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/features/db.feature b/features/db.feature index 338cdc935..0fb875c3c 100644 --- a/features/db.feature +++ b/features/db.feature @@ -21,6 +21,9 @@ Feature: Perform database operations When I try the previous command again Then the return code should be 1 + When I run `wp db check` + Then STDOUT should not be empty + When I run `wp db optimize` Then STDOUT should not be empty diff --git a/php/commands/db.php b/php/commands/db.php index 6dff55ea8..4de397231 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -94,6 +94,29 @@ public function reset( $_, $assoc_args ) { WP_CLI::success( "Database reset." ); } + /** + * Check the database in MySQL. + * + * Runs `mysqlcheck` utility with `--check` using `DB_HOST`, + * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials + * specified in wp-config.php. + * + * [See docs](http://dev.mysql.com/doc/refman/5.7/en/check-table.html) + * for more details on the `CHECK TABLE` statement. + * + * ## EXAMPLES + * + * $ wp db check + * Success: Database checked. + */ + public function check() { + self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( + 'check' => true, + ) ); + + WP_CLI::success( "Database checked." ); + } + /** * Optimize the database in MySQL. * From fc24d9d71ac3b995157a782caac4fd061427ef64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 12 Aug 2016 00:44:58 +0200 Subject: [PATCH 4834/5359] Try Trusty on Travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b811927a5..670361dac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: trusty sudo: false language: php From 1c851b4a5984d3ee46997c25452103c353b043e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Thu, 11 Aug 2016 23:14:53 +0000 Subject: [PATCH 4835/5359] Improving wp db check test --- features/db.feature | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/features/db.feature b/features/db.feature index 0fb875c3c..f350d9c70 100644 --- a/features/db.feature +++ b/features/db.feature @@ -22,7 +22,21 @@ Feature: Perform database operations Then the return code should be 1 When I run `wp db check` - Then STDOUT should not be empty + Then STDOUT should be: + """ + wp_cli_test.wp_commentmeta OK + wp_cli_test.wp_comments OK + wp_cli_test.wp_links OK + wp_cli_test.wp_options OK + wp_cli_test.wp_postmeta OK + wp_cli_test.wp_posts OK + wp_cli_test.wp_term_relationships OK + wp_cli_test.wp_term_taxonomy OK + wp_cli_test.wp_termmeta OK + wp_cli_test.wp_terms OK + wp_cli_test.wp_usermeta OK + wp_cli_test.wp_users OK + """ When I run `wp db optimize` Then STDOUT should not be empty From 62aac0c2bb5c7fef170a0959202e39db51563ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Fri, 12 Aug 2016 00:32:42 +0000 Subject: [PATCH 4836/5359] Add missing success message to wp db check test --- features/db.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/db.feature b/features/db.feature index f350d9c70..dc520222e 100644 --- a/features/db.feature +++ b/features/db.feature @@ -36,6 +36,7 @@ Feature: Perform database operations wp_cli_test.wp_terms OK wp_cli_test.wp_usermeta OK wp_cli_test.wp_users OK + Success: Database checked. """ When I run `wp db optimize` From 9837de2e0193fbb9f8ff68aff9fff848f75def04 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Fri, 12 Aug 2016 11:34:20 +0400 Subject: [PATCH 4837/5359] clarify scenario verbiage to specify http --- features/package-install.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/package-install.feature b/features/package-install.feature index 63061fd5a..5efbb53bb 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -1,6 +1,6 @@ Feature: Install WP-CLI packages - Scenario: Install a package with an old package index url in package composer.json + Scenario: Install a package with an http package index url in package composer.json Given an empty directory And a composer.json file: """ From af4558137adb2d39843267c63bba0e75d48acee2 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Fri, 12 Aug 2016 11:36:41 +0400 Subject: [PATCH 4838/5359] clean up scripting in scenario a lot by using test dir --- features/package-install.feature | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 5efbb53bb..22138d6e2 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -13,19 +13,17 @@ Feature: Install WP-CLI packages } } """ - When I run `rm -rf /tmp/wp-cli-package-install-test/ && mkdir /tmp/wp-cli-package-install-test/ && mv composer.json /tmp/wp-cli-package-install-test/` - Then the /tmp/wp-cli-package-install-test/composer.json file should exist - When I run `WP_CLI_PACKAGES_DIR=/tmp/wp-cli-package-install-test/ wp --info` + When I run `WP_CLI_PACKAGES_DIR=. wp --info` Then STDOUT should contain: """ - WP-CLI packages dir: /tmp/wp-cli-package-install-test/ + WP-CLI packages dir: . """ - When I run `WP_CLI_PACKAGES_DIR=/tmp/wp-cli-package-install-test/ wp package install runcommand/hook` - Then the /tmp/wp-cli-package-install-test/composer.json file should contain: + When I run `WP_CLI_PACKAGES_DIR=. wp package install runcommand/hook` + Then the composer.json file should contain: """ "url": "https://wp-cli.org/package-index/" """ - And the /tmp/wp-cli-package-install-test/composer.json file should not contain: + And the composer.json file should not contain: """ "url": "http://wp-cli.org/package-index/" """ From 949d28a9303efde76c1bdf9a01421c5a71626acc Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" <j@jorgetorres.co> Date: Fri, 12 Aug 2016 08:53:23 -0500 Subject: [PATCH 4839/5359] Preserve case for --version argument in core download --- php/commands/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index da1ef5a53..97a1e6dc5 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -134,8 +134,8 @@ public function download( $args, $assoc_args ) { $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); if ( isset( $assoc_args['version'] ) ) { - $version = strtolower( $assoc_args['version'] ); - $version = ( 'trunk' === $version ? 'nightly' : $version ); + $version = $assoc_args['version']; + $version = ( in_array( strtolower( $version ), array( 'trunk', 'nightly' ) ) ? 'nightly' : $version ); //nightly builds are only available in .zip format $ext = ( 'nightly' === $version ? 'zip' : 'tar.gz' ); $download_url = $this->get_download_url( $version, $locale, $ext ); From d25d33f5f54f59526945de323d1f86942abd4c4c Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Fri, 12 Aug 2016 18:31:08 +0400 Subject: [PATCH 4840/5359] update package-install scenario --- features/package-install.feature | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 22138d6e2..7de721a82 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -2,7 +2,7 @@ Feature: Install WP-CLI packages Scenario: Install a package with an http package index url in package composer.json Given an empty directory - And a composer.json file: + And a packages/composer.json file: """ { "repositories": { @@ -13,17 +13,20 @@ Feature: Install WP-CLI packages } } """ - When I run `WP_CLI_PACKAGES_DIR=. wp --info` + When I run `WP_CLI_PACKAGES_DIR=$PWD/packages wp package install runcommand/hook --debug` Then STDOUT should contain: - """ - WP-CLI packages dir: . - """ - When I run `WP_CLI_PACKAGES_DIR=. wp package install runcommand/hook` - Then the composer.json file should contain: + """ + Updating package index repository url... + """ + And STDOUT should contain: + """ + Success: Package installed + """ + And the packages/composer.json file should contain: """ "url": "https://wp-cli.org/package-index/" """ - And the composer.json file should not contain: + And the packages/composer.json file should not contain: """ "url": "http://wp-cli.org/package-index/" """ From 1904d0d6e572fd309c6bb3286c8d2d8dd8fce4f3 Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" <j@jorgetorres.co> Date: Fri, 12 Aug 2016 10:21:35 -0500 Subject: [PATCH 4841/5359] Add functional test for downloading WP release candidate or beta versions --- features/core-download.feature | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/features/core-download.feature b/features/core-download.feature index f08adcf13..9b244e2bf 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -188,4 +188,25 @@ Feature: Download WordPress And STDERR should contain: """ Error: Nightly builds are only available for the en_US locale. - """ + """ + + Scenario: Installing a release candidate or beta version + Given an empty directory + And an empty cache + + # Test with incorrect case. + When I try `wp core download --version=4.6-rc2` + Then the return code should be 1 + Then STDERR should contain: + """ + Error: Release not found. + """ + + When I run `wp core download --version=4.6-RC2` + Then the wp-settings.php file should exist + And STDOUT should contain: + """ + Downloading WordPress 4.6-RC2 (en_US)... + md5 hash verified: 90c93a15092b2d5d4c960ec1fc183e07 + Success: WordPress downloaded. + """ From 47fedd9c04e6b8ee73fa49b86655fa574cb1b018 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Sat, 13 Aug 2016 13:32:29 +0400 Subject: [PATCH 4842/5359] update package-install scenario, should work now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - removed the subdirectory for the packages/composer.json which caused the test to hang indefinitely. - setup a local dummy package to “install†instead of the real one making the test a bit faster as well. --- features/package-install.feature | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 7de721a82..aad733af0 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -2,10 +2,14 @@ Feature: Install WP-CLI packages Scenario: Install a package with an http package index url in package composer.json Given an empty directory - And a packages/composer.json file: + And a composer.json file: """ { "repositories": { + "test" : { + "type": "path", + "url": "./dummy-package/" + }, "wp-cli": { "type": "composer", "url": "http://wp-cli.org/package-index/" @@ -13,7 +17,14 @@ Feature: Install WP-CLI packages } } """ - When I run `WP_CLI_PACKAGES_DIR=$PWD/packages wp package install runcommand/hook --debug` + And a dummy-package/composer.json file: + """ + { + "name": "wp-cli/restful", + "description": "This is a dummy package we will install instead of actually installing the real package. This prevents the test from hanging indefinitely for some reason, even though it passes. The 'name' must match a real package as it is checked against the package index." + } + """ + When I run `WP_CLI_PACKAGES_DIR=. wp package install wp-cli/restful --debug` Then STDOUT should contain: """ Updating package index repository url... @@ -22,11 +33,11 @@ Feature: Install WP-CLI packages """ Success: Package installed """ - And the packages/composer.json file should contain: + And the composer.json file should contain: """ "url": "https://wp-cli.org/package-index/" """ - And the packages/composer.json file should not contain: + And the composer.json file should not contain: """ "url": "http://wp-cli.org/package-index/" """ From 3a9b1666433d49676f1e3b7f6d37504f40cd5582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Sat, 13 Aug 2016 14:34:04 +0200 Subject: [PATCH 4843/5359] wp user meta list need a user ID not "an object ID" in the docblock --- php/commands/user.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index b5a04c44c..f0c5daa66 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -953,8 +953,8 @@ public function __construct() { * * ## OPTIONS * - * <id> - * : ID for the object. + * <user> + * : The user login, user email, or user ID of the user to get metadata for. * * [--keys=<keys>] * : Limit output to metadata of specific keys. From 8d3a612ebe96d2f6221775c7d59b9b983feaa3db Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 06:20:45 -0700 Subject: [PATCH 4844/5359] Example for how to forcefully re-install plugins --- php/commands/plugin.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 2a55e37a0..4c3fee9a7 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -608,6 +608,15 @@ protected function filter_item_list( $items, $args ) { * Unpacking the package... * Installing the plugin... * Plugin installed successfully. + * + * # Forcefully re-install all installed plugins + * $ wp plugin install $(wp plugin list --field=name) --force + * Installing Akismet (3.1.11) + * Downloading install package from https://downloads.wordpress.org/plugin/akismet.3.1.11.zip... + * Unpacking the package... + * Installing the plugin... + * Removing the old version of the plugin... + * Plugin updated successfully */ function install( $args, $assoc_args ) { From 88add32d888025d5c10dfd68d3d36127f980b44c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 06:34:53 -0700 Subject: [PATCH 4845/5359] Move `wp core language` class to its own file --- php/commands/core-language.php | 40 ++++++++++++++++++++++++++++++++++ php/commands/core.php | 39 --------------------------------- 2 files changed, 40 insertions(+), 39 deletions(-) create mode 100644 php/commands/core-language.php diff --git a/php/commands/core-language.php b/php/commands/core-language.php new file mode 100644 index 000000000..bc180132a --- /dev/null +++ b/php/commands/core-language.php @@ -0,0 +1,40 @@ +<?php + +/** + * Manage core language. + * + * ## EXAMPLES + * + * # Install language + * $ wp core language install nl_NL + * Success: Language installed. + * + * # Activate language + * $ wp core language activate nl_NL + * Success: Language activated. + * + * # Uninstall language + * $ wp core language uninstall nl_NL + * Success: Language uninstalled. + * + * # List installed languages + * $ wp core language list --status=installed + * +----------+--------------+-------------+-----------+-----------+---------------------+ + * | language | english_name | native_name | status | update | updated | + * +----------+--------------+-------------+-----------+-----------+---------------------+ + * | nl_NL | Dutch | Nederlands | installed | available | 2016-05-13 08:12:50 | + * +----------+--------------+-------------+-----------+-----------+---------------------+ + */ +class Core_Language_Command extends WP_CLI\CommandWithTranslation { + + protected $obj_type = 'core'; + +} + +WP_CLI::add_command( 'core language', 'Core_Language_Command', array( + 'before_invoke' => function() { + if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { + WP_CLI::error( "Requires WordPress 4.0 or greater." ); + } + }) +); diff --git a/php/commands/core.php b/php/commands/core.php index 97a1e6dc5..250bb3e20 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1564,42 +1564,3 @@ private function cleanup_extra_files( $version_from, $version_to, $locale ) { } WP_CLI::add_command( 'core', 'Core_Command' ); - -/** - * Manage core language. - * - * ## EXAMPLES - * - * # Install language - * $ wp core language install nl_NL - * Success: Language installed. - * - * # Activate language - * $ wp core language activate nl_NL - * Success: Language activated. - * - * # Uninstall language - * $ wp core language uninstall nl_NL - * Success: Language uninstalled. - * - * # List installed languages - * $ wp core language list --status=installed - * +----------+--------------+-------------+-----------+-----------+---------------------+ - * | language | english_name | native_name | status | update | updated | - * +----------+--------------+-------------+-----------+-----------+---------------------+ - * | nl_NL | Dutch | Nederlands | installed | available | 2016-05-13 08:12:50 | - * +----------+--------------+-------------+-----------+-----------+---------------------+ - */ -class Core_Language_Command extends WP_CLI\CommandWithTranslation { - - protected $obj_type = 'core'; - -} - -WP_CLI::add_command( 'core language', 'Core_Language_Command', array( - 'before_invoke' => function() { - if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { - WP_CLI::error( "Requires WordPress 4.0 or greater." ); - } - }) -); From a891dfbb437e36dafb187b6b92752bd4d3559641 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 06:38:43 -0700 Subject: [PATCH 4846/5359] Move `wp comment meta` class into its own file --- php/commands/comment-meta.php | 44 +++++++++++++++++++++++++++++++++++ php/commands/comment.php | 43 ---------------------------------- 2 files changed, 44 insertions(+), 43 deletions(-) create mode 100644 php/commands/comment-meta.php diff --git a/php/commands/comment-meta.php b/php/commands/comment-meta.php new file mode 100644 index 000000000..929c684f0 --- /dev/null +++ b/php/commands/comment-meta.php @@ -0,0 +1,44 @@ +<?php + +/** + * Manage comment custom fields. + * + * ## OPTIONS + * + * --format=json + * : Encode/decode values as JSON. + * + * ## EXAMPLES + * + * # Set comment meta + * $ wp comment meta set 123 description "Mary is a WordPress developer." + * Success: Updated custom field 'description'. + * + * # Get comment meta + * $ wp comment meta get 123 description + * Mary is a WordPress developer. + * + * # Update comment meta + * $ wp comment meta update 123 description "Mary is an awesome WordPress developer." + * Success: Updated custom field 'description'. + * + * # Delete comment meta + * $ wp comment meta delete 123 description + * Success: Deleted custom field. + */ +class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'comment'; + + /** + * Check that the comment ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $fetcher = new \WP_CLI\Fetchers\Comment; + $comment = $fetcher->get_check( $object_id ); + return $comment->comment_ID; + } +} + +WP_CLI::add_command( 'comment meta', 'Comment_Meta_Command' ); diff --git a/php/commands/comment.php b/php/commands/comment.php index 22def3485..a0ae3434f 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -635,47 +635,4 @@ public function url( $args ) { } } -/** - * Manage comment custom fields. - * - * ## OPTIONS - * - * --format=json - * : Encode/decode values as JSON. - * - * ## EXAMPLES - * - * # Set comment meta - * $ wp comment meta set 123 description "Mary is a WordPress developer." - * Success: Updated custom field 'description'. - * - * # Get comment meta - * $ wp comment meta get 123 description - * Mary is a WordPress developer. - * - * # Update comment meta - * $ wp comment meta update 123 description "Mary is an awesome WordPress developer." - * Success: Updated custom field 'description'. - * - * # Delete comment meta - * $ wp comment meta delete 123 description - * Success: Deleted custom field. - */ -class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'comment'; - - /** - * Check that the comment ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $fetcher = new \WP_CLI\Fetchers\Comment; - $comment = $fetcher->get_check( $object_id ); - return $comment->comment_ID; - } -} - WP_CLI::add_command( 'comment', 'Comment_Command' ); -WP_CLI::add_command( 'comment meta', 'Comment_Meta_Command' ); - From 96441665c995ad7b6911bcc99b36e75e94ddf898 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 06:44:35 -0700 Subject: [PATCH 4847/5359] Move `wp menu (item|location)` classes to their own files --- features/menu-item.feature | 111 ++++++ features/menu-location.feature | 31 ++ features/menu.feature | 134 ------- php/commands/menu-item.php | 502 +++++++++++++++++++++++++ php/commands/menu-location.php | 170 +++++++++ php/commands/menu.php | 669 --------------------------------- 6 files changed, 814 insertions(+), 803 deletions(-) create mode 100644 features/menu-item.feature create mode 100644 features/menu-location.feature create mode 100644 php/commands/menu-item.php create mode 100644 php/commands/menu-location.php diff --git a/features/menu-item.feature b/features/menu-item.feature new file mode 100644 index 000000000..0f0c514f5 --- /dev/null +++ b/features/menu-item.feature @@ -0,0 +1,111 @@ +Feature: Manage WordPress menu items + + Background: + Given a WP install + + Scenario: Add / update / remove items from a menu + + When I run `wp post create --post_title='Test post' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp post url {POST_ID}` + Then save STDOUT as {POST_LINK} + + When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` + Then STDOUT should be a number + And save STDOUT as {TERM_ID} + + When I run `wp term url post_tag {TERM_ID}` + Then save STDOUT as {TERM_LINK} + + When I run `wp menu create "Sidebar Menu"` + Then STDOUT should not be empty + + When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --description="Georgia peaches" --porcelain` + Then save STDOUT as {POST_ITEM_ID} + + When I run `wp menu item update {POST_ITEM_ID} --description="Washington Apples"` + Then STDOUT should be: + """ + Success: Menu item updated. + """ + + When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` + Then save STDOUT as {TERM_ITEM_ID} + + When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --parent-id={POST_ITEM_ID} --porcelain` + Then save STDOUT as {CUSTOM_ITEM_ID} + + When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` + Then STDOUT should be: + """ + Success: Menu item updated. + """ + + When I run `wp menu item update {TERM_ITEM_ID} --position=3` + Then STDOUT should be: + """ + Success: Menu item updated. + """ + + When I run `wp menu item list sidebar-menu --fields=type,title,description,position,link,menu_item_parent` + Then STDOUT should be a table containing rows: + | type | title | description | position | link | menu_item_parent | + | post_type | Custom Test Post | Washington Apples | 1 | {POST_LINK} | 0 | + | custom | WordPress | | 2 | http://wordpress.org | {POST_ITEM_ID} | + | taxonomy | Test term | | 3 | {TERM_LINK} | 0 | + + When I run `wp menu item list sidebar-menu --format=ids` + Then STDOUT should not be empty + + When I run `wp menu item delete {CUSTOM_ITEM_ID}` + Then STDOUT should be: + """ + Success: 1 menu item deleted. + """ + And I run `wp menu item list sidebar-menu --format=count` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` + Then STDOUT should be: + """ + Success: 2 menu items deleted. + """ + And I run `wp menu item list sidebar-menu --format=count` + Then STDOUT should be: + """ + 0 + """ + + Scenario: Preserve grandparent item as ancestor of child item when parent item is removed. + + When I run `wp menu create "Grandparent Test"` + Then STDOUT should not be empty + + When I run `wp menu item add-custom grandparent-test Grandparent http://example.com/grandparent --porcelain` + Then save STDOUT as {GRANDPARENT_ID} + + When I run `wp menu item add-custom grandparent-test Parent http://example.com/parent --porcelain --parent-id={GRANDPARENT_ID}` + Then save STDOUT as {PARENT_ID} + + When I run `wp menu item add-custom grandparent-test Child http://example.com/child --porcelain --parent-id={PARENT_ID}` + Then save STDOUT as {CHILD_ID} + + When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` + Then STDOUT should be a table containing rows: + | title | db_id | menu_item_parent | + | Grandparent | {GRANDPARENT_ID} | 0 | + | Parent | {PARENT_ID} | {GRANDPARENT_ID} | + | Child | {CHILD_ID} | {PARENT_ID} | + + When I run `wp menu item delete {PARENT_ID}` + + When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` + Then STDOUT should be a table containing rows: + | title | db_id | menu_item_parent | + | Grandparent | {GRANDPARENT_ID} | 0 | + | Child | {CHILD_ID} | {GRANDPARENT_ID} | diff --git a/features/menu-location.feature b/features/menu-location.feature new file mode 100644 index 000000000..e94dceee0 --- /dev/null +++ b/features/menu-location.feature @@ -0,0 +1,31 @@ +Feature: Manage WordPress menu locations + + Background: + Given a WP install + + Scenario: Assign / remove location from a menu + + When I run `wp theme install p2 --activate` + And I run `wp menu location list` + Then STDOUT should be a table containing rows: + | location | description | + | primary | Primary Menu | + + When I run `wp menu create "Primary Menu"` + And I run `wp menu location assign primary-menu primary` + And I run `wp menu list --fields=slug,locations` + Then STDOUT should be a table containing rows: + | slug | locations | + | primary-menu | primary | + + When I run `wp menu location list --format=ids` + Then STDOUT should be: + """ + primary + """ + + When I run `wp menu location remove primary-menu primary` + And I run `wp menu list --fields=slug,locations` + Then STDOUT should be a table containing rows: + | slug | locations | + | primary-menu | | diff --git a/features/menu.feature b/features/menu.feature index 1d26121c1..839bd4d08 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -47,137 +47,3 @@ Feature: Manage WordPress menus """ 5 """ - - Scenario: Assign / remove location from a menu - - When I run `wp theme install p2 --activate` - And I run `wp menu location list` - Then STDOUT should be a table containing rows: - | location | description | - | primary | Primary Menu | - - When I run `wp menu create "Primary Menu"` - And I run `wp menu location assign primary-menu primary` - And I run `wp menu list --fields=slug,locations` - Then STDOUT should be a table containing rows: - | slug | locations | - | primary-menu | primary | - - When I run `wp menu location list --format=ids` - Then STDOUT should be: - """ - primary - """ - - When I run `wp menu location remove primary-menu primary` - And I run `wp menu list --fields=slug,locations` - Then STDOUT should be a table containing rows: - | slug | locations | - | primary-menu | | - - Scenario: Add / update / remove items from a menu - - When I run `wp post create --post_title='Test post' --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp post url {POST_ID}` - Then save STDOUT as {POST_LINK} - - When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID} - - When I run `wp term url post_tag {TERM_ID}` - Then save STDOUT as {TERM_LINK} - - When I run `wp menu create "Sidebar Menu"` - Then STDOUT should not be empty - - When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --description="Georgia peaches" --porcelain` - Then save STDOUT as {POST_ITEM_ID} - - When I run `wp menu item update {POST_ITEM_ID} --description="Washington Apples"` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` - Then save STDOUT as {TERM_ITEM_ID} - - When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --parent-id={POST_ITEM_ID} --porcelain` - Then save STDOUT as {CUSTOM_ITEM_ID} - - When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item update {TERM_ITEM_ID} --position=3` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item list sidebar-menu --fields=type,title,description,position,link,menu_item_parent` - Then STDOUT should be a table containing rows: - | type | title | description | position | link | menu_item_parent | - | post_type | Custom Test Post | Washington Apples | 1 | {POST_LINK} | 0 | - | custom | WordPress | | 2 | http://wordpress.org | {POST_ITEM_ID} | - | taxonomy | Test term | | 3 | {TERM_LINK} | 0 | - - When I run `wp menu item list sidebar-menu --format=ids` - Then STDOUT should not be empty - - When I run `wp menu item delete {CUSTOM_ITEM_ID}` - Then STDOUT should be: - """ - Success: 1 menu item deleted. - """ - And I run `wp menu item list sidebar-menu --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` - Then STDOUT should be: - """ - Success: 2 menu items deleted. - """ - And I run `wp menu item list sidebar-menu --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Preserve grandparent item as ancestor of child item when parent item is removed. - - When I run `wp menu create "Grandparent Test"` - Then STDOUT should not be empty - - When I run `wp menu item add-custom grandparent-test Grandparent http://example.com/grandparent --porcelain` - Then save STDOUT as {GRANDPARENT_ID} - - When I run `wp menu item add-custom grandparent-test Parent http://example.com/parent --porcelain --parent-id={GRANDPARENT_ID}` - Then save STDOUT as {PARENT_ID} - - When I run `wp menu item add-custom grandparent-test Child http://example.com/child --porcelain --parent-id={PARENT_ID}` - Then save STDOUT as {CHILD_ID} - - When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` - Then STDOUT should be a table containing rows: - | title | db_id | menu_item_parent | - | Grandparent | {GRANDPARENT_ID} | 0 | - | Parent | {PARENT_ID} | {GRANDPARENT_ID} | - | Child | {CHILD_ID} | {PARENT_ID} | - - When I run `wp menu item delete {PARENT_ID}` - - When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` - Then STDOUT should be a table containing rows: - | title | db_id | menu_item_parent | - | Grandparent | {GRANDPARENT_ID} | 0 | - | Child | {CHILD_ID} | {GRANDPARENT_ID} | diff --git a/php/commands/menu-item.php b/php/commands/menu-item.php new file mode 100644 index 000000000..25d79529c --- /dev/null +++ b/php/commands/menu-item.php @@ -0,0 +1,502 @@ +<?php + +/** + * List, add, and delete items associated with a menu. + * + * ## EXAMPLES + * + * # Add an existing post to an existing menu + * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * Success: Menu item added. + * + * # Create a new menu link item + * $ wp menu item add-custom sidebar-menu Apple http://apple.com + * Success: Menu item added. + * + * # Delete menu item + * $ wp menu item delete 45 + * Success: 1 menu item deleted. + */ +class Menu_Item_Command extends WP_CLI_Command { + + protected $obj_fields = array( + 'db_id', + 'type', + 'title', + 'link', + 'position', + ); + + /** + * Get a list of items associated with a menu. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - ids + * - yaml + * --- + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each menu item: + * + * * db_id + * * type + * * title + * * link + * * position + * + * These fields are optionally available: + * + * * menu_item_parent + * * object_id + * * object + * * type + * * type_label + * * target + * * attr_title + * * description + * * classes + * * xfn + * + * ## EXAMPLES + * + * $ wp menu item list main-menu + * +-------+-----------+-------------+---------------------------------+----------+ + * | db_id | type | title | link | position | + * +-------+-----------+-------------+---------------------------------+----------+ + * | 5 | custom | Home | http://example.com | 1 | + * | 6 | post_type | Sample Page | http://example.com/sample-page/ | 2 | + * +-------+-----------+-------------+---------------------------------+----------+ + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + $items = wp_get_nav_menu_items( $args[0] ); + if ( false === $items || is_wp_error( $items ) ) { + WP_CLI::error( "Invalid menu." ); + } + + // Correct position inconsistency and + // protected `url` param in WP-CLI + $items = array_map( function( $item ) use ( $assoc_args ) { + $item->position = $item->menu_order; + $item->link = $item->url; + return $item; + }, $items ); + + if ( ! empty( $assoc_args['format'] ) && 'ids' == $assoc_args['format'] ) { + $items = array_map( function( $item ) { + return $item->db_id; + }, $items ); + } + + $formatter = $this->get_formatter( $assoc_args ); + $formatter->display_items( $items ); + + } + + /** + * Add a post as a menu item. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * <post-id> + * : Post ID to add to the menu. + * + * [--title=<title>] + * : Set a custom title for the menu item. + * + * [--link=<link>] + * : Set a custom url for the menu item. + * + * [--description=<description>] + * : Set a custom description for the menu item. + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item. + * + * [--target=<target>] + * : Set a custom link target for the menu item. + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item. + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item. + * + * [--porcelain] + * : Output just the new menu item id. + * + * ## EXAMPLES + * + * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" + * Success: Menu item added. + * + * @subcommand add-post + */ + public function add_post( $args, $assoc_args ) { + + $assoc_args['object-id'] = $args[1]; + unset( $args[1] ); + $post = get_post( $assoc_args['object-id'] ); + if ( ! $post ) { + WP_CLI::error( "Invalid post." ); + } + $assoc_args['object'] = $post->post_type; + + $this->add_or_update_item( 'add', 'post_type', $args, $assoc_args ); + } + + /** + * Add a taxonomy term as a menu item. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * <taxonomy> + * : Taxonomy of the term to be added. + * + * <term-id> + * : Term ID of the term to be added. + * + * [--title=<title>] + * : Set a custom title for the menu item. + * + * [--link=<link>] + * : Set a custom url for the menu item. + * + * [--description=<description>] + * : Set a custom description for the menu item. + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item. + * + * [--target=<target>] + * : Set a custom link target for the menu item. + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item. + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item. + * + * [--porcelain] + * : Output just the new menu item id. + * + * ## EXAMPLES + * + * $ wp menu item add-term sidebar-menu post_tag 24 + * Success: Menu item added. + * + * @subcommand add-term + */ + public function add_term( $args, $assoc_args ) { + + $assoc_args['object'] = $args[1]; + unset( $args[1] ); + $assoc_args['object-id'] = $args[2]; + unset( $args[2] ); + + if ( ! get_term_by( 'id', $assoc_args['object-id'], $assoc_args['object'] ) ) { + WP_CLI::error( "Invalid term." ); + } + + $this->add_or_update_item( 'add', 'taxonomy', $args, $assoc_args ); + } + + /** + * Add a custom menu item. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * <title> + * : Title for the link. + * + * <link> + * : Target URL for the link. + * + * [--description=<description>] + * : Set a custom description for the menu item. + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item. + * + * [--target=<target>] + * : Set a custom link target for the menu item. + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item. + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item. + * + * [--porcelain] + * : Output just the new menu item id. + * + * ## EXAMPLES + * + * $ wp menu item add-custom sidebar-menu Apple http://apple.com + * Success: Menu item added. + * + * @subcommand add-custom + */ + public function add_custom( $args, $assoc_args ) { + + $assoc_args['title'] = $args[1]; + unset( $args[1] ); + $assoc_args['link'] = $args[2]; + unset( $args[2] ); + $this->add_or_update_item( 'add', 'custom', $args, $assoc_args ); + } + + /** + * Update a menu item. + * + * ## OPTIONS + * + * <db-id> + * : Database ID for the menu item. + * + * [--title=<title>] + * : Set a custom title for the menu item. + * + * [--link=<link>] + * : Set a custom url for the menu item. + * + * [--description=<description>] + * : Set a custom description for the menu item. + * + * [--attr-title=<attr-title>] + * : Set a custom title attribute for the menu item. + * + * [--target=<target>] + * : Set a custom link target for the menu item. + * + * [--classes=<classes>] + * : Set a custom link classes for the menu item. + * + * [--position=<position>] + * : Specify the position of this menu item. + * + * [--parent-id=<parent-id>] + * : Make this menu item a child of another menu item. + * + * ## EXAMPLES + * + * $ wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 + * Success: Menu item updated. + * + * @subcommand update + */ + public function update( $args, $assoc_args ) { + + // Shuffle the position of these. + $args[1] = $args[0]; + $terms = get_the_terms( $args[1], 'nav_menu' ); + if ( $terms && ! is_wp_error( $terms ) ) { + $args[0] = (int)$terms[0]->term_id; + } else { + $args[0] = 0; + } + $type = get_post_meta( $args[1], '_menu_item_type', true ); + $this->add_or_update_item( 'update', $type, $args, $assoc_args ); + + } + + /** + * Delete one or more items from a menu. + * + * ## OPTIONS + * + * <db-id>... + * : Database ID for the menu item(s). + * + * ## EXAMPLES + * + * $ wp menu item delete 45 + * Success: 1 menu item deleted. + * + * @subcommand delete + */ + public function delete( $args, $_ ) { + global $wpdb; + + $count = 0; + + foreach( $args as $arg ) { + + $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); + $ret = wp_delete_post( $arg, true ); + if ( ! $ret ) { + WP_CLI::warning( "Couldn't delete menu item." ); + } else if ( $parent_menu_id ) { + $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); + if ( $children ) { + $children_query = $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %d WHERE meta_key = '_menu_item_menu_item_parent' AND meta_value=%s", $parent_menu_id, (int) $arg ); + $wpdb->query( $children_query ); + foreach( $children as $child ) { + clean_post_cache( $child ); + } + } + } + + if ( false !== $ret ) { + $count++; + } + + } + + $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + + } + + /** + * Worker method to create new items or update existing ones. + */ + private function add_or_update_item( $method, $type, $args, $assoc_args ) { + + $menu = $args[0]; + $menu_item_db_id = \WP_CLI\Utils\get_flag_value( $args, 1, 0 ); + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + // `url` is protected in WP-CLI, so we use `link` instead + $assoc_args['url'] = \WP_CLI\Utils\get_flag_value( $assoc_args, 'link' ); + + // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 + if ( 'update' == $method ) { + + $menu_item_obj = get_post( $menu_item_db_id ); + $menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj ); + + // Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140 + $position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order; + + $default_args = array( + 'position' => $position, + 'title' => $menu_item_obj->title, + 'url' => $menu_item_obj->url, + 'description' => $menu_item_obj->description, + 'object' => $menu_item_obj->object, + 'object-id' => $menu_item_obj->object_id, + 'parent-id' => $menu_item_obj->menu_item_parent, + 'attr-title' => $menu_item_obj->attr_title, + 'target' => $menu_item_obj->target, + 'classes' => implode( ' ', $menu_item_obj->classes ), // stored in the database as array + 'xfn' => $menu_item_obj->xfn, + 'status' => $menu_item_obj->post_status, + ); + + } else { + + $default_args = array( + 'position' => 0, + 'title' => '', + 'url' => '', + 'description' => '', + 'object' => '', + 'object-id' => 0, + 'parent-id' => 0, + 'attr-title' => '', + 'target' => '', + 'classes' => '', + 'xfn' => '', + // Core oddly defaults to 'draft' for create, + // and 'publish' for update + // Easiest to always work with publish + 'status' => 'publish', + ); + + } + + $menu_item_args = array(); + foreach( $default_args as $key => $default_value ) { + // wp_update_nav_menu_item() has a weird argument prefix + $new_key = 'menu-item-' . $key; + $menu_item_args[ $new_key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $default_value ); + } + + $menu_item_args['menu-item-type'] = $type; + $ret = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args ); + + if ( is_wp_error( $ret ) ) { + WP_CLI::error( $ret->get_error_message() ); + } else if ( ! $ret ) { + if ( 'add' == $method ) { + WP_CLI::error( "Couldn't add menu item." ); + } else if ( 'update' == $method ) { + WP_CLI::error( "Couldn't update menu item." ); + } + } else { + + /** + * Set the menu + * + * wp_update_nav_menu_item() *should* take care of this, but + * depends on wp_insert_post()'s "tax_input" argument, which + * is ignored if the user can't edit the taxonomy + * + * @see https://core.trac.wordpress.org/ticket/27113 + */ + if ( ! is_object_in_term( $ret, 'nav_menu', (int) $menu->term_id ) ) { + wp_set_object_terms( $ret, array( (int)$menu->term_id ), 'nav_menu' ); + } + + if ( 'add' == $method && ! empty( $assoc_args['porcelain'] ) ) { + WP_CLI::line( $ret ); + } else { + if ( 'add' == $method ) { + WP_CLI::success( "Menu item added." ); + } else if ( 'update' == $method ) { + WP_CLI::success( "Menu item updated." ); + } + } + } + + } + + protected function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields ); + } + +} + +WP_CLI::add_command( 'menu item', 'Menu_Item_Command' ); diff --git a/php/commands/menu-location.php b/php/commands/menu-location.php new file mode 100644 index 000000000..46e69f937 --- /dev/null +++ b/php/commands/menu-location.php @@ -0,0 +1,170 @@ +<?php + +/** + * Manage a menu's assignment to locations. + * + * ## EXAMPLES + * + * # List available menu locations + * $ wp menu location list + * +----------+-------------------+ + * | location | description | + * +----------+-------------------+ + * | primary | Primary Menu | + * | social | Social Links Menu | + * +----------+-------------------+ + * + * # Assign the 'primary-menu' menu to the 'primary' location + * $ wp menu location assign primary-menu primary + * Success: Assigned location to menu. + * + * # Remove the 'primary-menu' menu from the 'primary' location + * $ wp menu location remove primary-menu primary + * Success: Removed location from menu. + */ +class Menu_Location_Command extends WP_CLI_Command { + + /** + * List locations for the current theme. + * + * ## OPTIONS + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * - ids + * --- + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each location: + * + * * name + * * description + * + * ## EXAMPLES + * + * $ wp menu location list + * +----------+-------------------+ + * | location | description | + * +----------+-------------------+ + * | primary | Primary Menu | + * | social | Social Links Menu | + * +----------+-------------------+ + * + * @subcommand list + */ + public function list_( $_, $assoc_args ) { + + $locations = get_registered_nav_menus(); + $location_objs = array(); + foreach( $locations as $location => $description ) { + $location_obj = new \stdClass; + $location_obj->location = $location; + $location_obj->description = $description; + $location_objs[] = $location_obj; + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); + + if ( 'ids' == $formatter->format ) { + $ids = array_map( + function($o) { + return $o->location; + }, $location_objs + ); + $formatter->display_items( $ids ); + } else { + $formatter->display_items( $location_objs ); + } + } + + /** + * Assign a location to a menu. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * <location> + * : Location's slug. + * + * ## EXAMPLES + * + * $ wp menu location assign primary-menu primary + * Success: Assigned location to menu. + * + * @subcommand assign + */ + public function assign( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_registered_nav_menus(); + if ( ! array_key_exists( $location, $locations ) ) { + WP_CLI::error( "Invalid location." ); + } + + $locations = get_nav_menu_locations(); + $locations[ $location ] = $menu->term_id; + + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Assigned location to menu." ); + } + + /** + * Remove a location from a menu. + * + * ## OPTIONS + * + * <menu> + * : The name, slug, or term ID for the menu. + * + * <location> + * : Location's slug. + * + * ## EXAMPLES + * + * $ wp menu location remove primary-menu primary + * Success: Removed location from menu. + * + * @subcommand remove + */ + public function remove( $args, $_ ) { + + list( $menu, $location ) = $args; + + $menu = wp_get_nav_menu_object( $menu ); + if ( ! $menu || is_wp_error( $menu ) ) { + WP_CLI::error( "Invalid menu." ); + } + + $locations = get_nav_menu_locations(); + if ( \WP_CLI\Utils\get_flag_value( $locations, $location ) != $menu->term_id ) { + WP_CLI::error( "Menu isn't assigned to location." ); + } + + $locations[ $location ] = 0; + set_theme_mod( 'nav_menu_locations', $locations ); + + WP_CLI::success( "Removed location from menu." ); + + } + +} + +WP_CLI::add_command( 'menu location', 'Menu_Location_Command' ); diff --git a/php/commands/menu.php b/php/commands/menu.php index 7fafe0676..530e851c3 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -210,673 +210,4 @@ protected function get_formatter( &$assoc_args ) { } -/** - * List, add, and delete items associated with a menu. - * - * ## EXAMPLES - * - * # Add an existing post to an existing menu - * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" - * Success: Menu item added. - * - * # Create a new menu link item - * $ wp menu item add-custom sidebar-menu Apple http://apple.com - * Success: Menu item added. - * - * # Delete menu item - * $ wp menu item delete 45 - * Success: 1 menu item deleted. - */ -class Menu_Item_Command extends WP_CLI_Command { - - protected $obj_fields = array( - 'db_id', - 'type', - 'title', - 'link', - 'position', - ); - - /** - * Get a list of items associated with a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - ids - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each menu item: - * - * * db_id - * * type - * * title - * * link - * * position - * - * These fields are optionally available: - * - * * menu_item_parent - * * object_id - * * object - * * type - * * type_label - * * target - * * attr_title - * * description - * * classes - * * xfn - * - * ## EXAMPLES - * - * $ wp menu item list main-menu - * +-------+-----------+-------------+---------------------------------+----------+ - * | db_id | type | title | link | position | - * +-------+-----------+-------------+---------------------------------+----------+ - * | 5 | custom | Home | http://example.com | 1 | - * | 6 | post_type | Sample Page | http://example.com/sample-page/ | 2 | - * +-------+-----------+-------------+---------------------------------+----------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - $items = wp_get_nav_menu_items( $args[0] ); - if ( false === $items || is_wp_error( $items ) ) { - WP_CLI::error( "Invalid menu." ); - } - - // Correct position inconsistency and - // protected `url` param in WP-CLI - $items = array_map( function( $item ) use ( $assoc_args ) { - $item->position = $item->menu_order; - $item->link = $item->url; - return $item; - }, $items ); - - if ( ! empty( $assoc_args['format'] ) && 'ids' == $assoc_args['format'] ) { - $items = array_map( function( $item ) { - return $item->db_id; - }, $items ); - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $items ); - - } - - /** - * Add a post as a menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <post-id> - * : Post ID to add to the menu. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" - * Success: Menu item added. - * - * @subcommand add-post - */ - public function add_post( $args, $assoc_args ) { - - $assoc_args['object-id'] = $args[1]; - unset( $args[1] ); - $post = get_post( $assoc_args['object-id'] ); - if ( ! $post ) { - WP_CLI::error( "Invalid post." ); - } - $assoc_args['object'] = $post->post_type; - - $this->add_or_update_item( 'add', 'post_type', $args, $assoc_args ); - } - - /** - * Add a taxonomy term as a menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <taxonomy> - * : Taxonomy of the term to be added. - * - * <term-id> - * : Term ID of the term to be added. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-term sidebar-menu post_tag 24 - * Success: Menu item added. - * - * @subcommand add-term - */ - public function add_term( $args, $assoc_args ) { - - $assoc_args['object'] = $args[1]; - unset( $args[1] ); - $assoc_args['object-id'] = $args[2]; - unset( $args[2] ); - - if ( ! get_term_by( 'id', $assoc_args['object-id'], $assoc_args['object'] ) ) { - WP_CLI::error( "Invalid term." ); - } - - $this->add_or_update_item( 'add', 'taxonomy', $args, $assoc_args ); - } - - /** - * Add a custom menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <title> - * : Title for the link. - * - * <link> - * : Target URL for the link. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-custom sidebar-menu Apple http://apple.com - * Success: Menu item added. - * - * @subcommand add-custom - */ - public function add_custom( $args, $assoc_args ) { - - $assoc_args['title'] = $args[1]; - unset( $args[1] ); - $assoc_args['link'] = $args[2]; - unset( $args[2] ); - $this->add_or_update_item( 'add', 'custom', $args, $assoc_args ); - } - - /** - * Update a menu item. - * - * ## OPTIONS - * - * <db-id> - * : Database ID for the menu item. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * ## EXAMPLES - * - * $ wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 - * Success: Menu item updated. - * - * @subcommand update - */ - public function update( $args, $assoc_args ) { - - // Shuffle the position of these. - $args[1] = $args[0]; - $terms = get_the_terms( $args[1], 'nav_menu' ); - if ( $terms && ! is_wp_error( $terms ) ) { - $args[0] = (int)$terms[0]->term_id; - } else { - $args[0] = 0; - } - $type = get_post_meta( $args[1], '_menu_item_type', true ); - $this->add_or_update_item( 'update', $type, $args, $assoc_args ); - - } - - /** - * Delete one or more items from a menu. - * - * ## OPTIONS - * - * <db-id>... - * : Database ID for the menu item(s). - * - * ## EXAMPLES - * - * $ wp menu item delete 45 - * Success: 1 menu item deleted. - * - * @subcommand delete - */ - public function delete( $args, $_ ) { - global $wpdb; - - $count = 0; - - foreach( $args as $arg ) { - - $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); - $ret = wp_delete_post( $arg, true ); - if ( ! $ret ) { - WP_CLI::warning( "Couldn't delete menu item." ); - } else if ( $parent_menu_id ) { - $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); - if ( $children ) { - $children_query = $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %d WHERE meta_key = '_menu_item_menu_item_parent' AND meta_value=%s", $parent_menu_id, (int) $arg ); - $wpdb->query( $children_query ); - foreach( $children as $child ) { - clean_post_cache( $child ); - } - } - } - - if ( false !== $ret ) { - $count++; - } - - } - - $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - - } - - /** - * Worker method to create new items or update existing ones. - */ - private function add_or_update_item( $method, $type, $args, $assoc_args ) { - - $menu = $args[0]; - $menu_item_db_id = \WP_CLI\Utils\get_flag_value( $args, 1, 0 ); - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - // `url` is protected in WP-CLI, so we use `link` instead - $assoc_args['url'] = \WP_CLI\Utils\get_flag_value( $assoc_args, 'link' ); - - // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 - if ( 'update' == $method ) { - - $menu_item_obj = get_post( $menu_item_db_id ); - $menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj ); - - // Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140 - $position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order; - - $default_args = array( - 'position' => $position, - 'title' => $menu_item_obj->title, - 'url' => $menu_item_obj->url, - 'description' => $menu_item_obj->description, - 'object' => $menu_item_obj->object, - 'object-id' => $menu_item_obj->object_id, - 'parent-id' => $menu_item_obj->menu_item_parent, - 'attr-title' => $menu_item_obj->attr_title, - 'target' => $menu_item_obj->target, - 'classes' => implode( ' ', $menu_item_obj->classes ), // stored in the database as array - 'xfn' => $menu_item_obj->xfn, - 'status' => $menu_item_obj->post_status, - ); - - } else { - - $default_args = array( - 'position' => 0, - 'title' => '', - 'url' => '', - 'description' => '', - 'object' => '', - 'object-id' => 0, - 'parent-id' => 0, - 'attr-title' => '', - 'target' => '', - 'classes' => '', - 'xfn' => '', - // Core oddly defaults to 'draft' for create, - // and 'publish' for update - // Easiest to always work with publish - 'status' => 'publish', - ); - - } - - $menu_item_args = array(); - foreach( $default_args as $key => $default_value ) { - // wp_update_nav_menu_item() has a weird argument prefix - $new_key = 'menu-item-' . $key; - $menu_item_args[ $new_key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $default_value ); - } - - $menu_item_args['menu-item-type'] = $type; - $ret = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args ); - - if ( is_wp_error( $ret ) ) { - WP_CLI::error( $ret->get_error_message() ); - } else if ( ! $ret ) { - if ( 'add' == $method ) { - WP_CLI::error( "Couldn't add menu item." ); - } else if ( 'update' == $method ) { - WP_CLI::error( "Couldn't update menu item." ); - } - } else { - - /** - * Set the menu - * - * wp_update_nav_menu_item() *should* take care of this, but - * depends on wp_insert_post()'s "tax_input" argument, which - * is ignored if the user can't edit the taxonomy - * - * @see https://core.trac.wordpress.org/ticket/27113 - */ - if ( ! is_object_in_term( $ret, 'nav_menu', (int) $menu->term_id ) ) { - wp_set_object_terms( $ret, array( (int)$menu->term_id ), 'nav_menu' ); - } - - if ( 'add' == $method && ! empty( $assoc_args['porcelain'] ) ) { - WP_CLI::line( $ret ); - } else { - if ( 'add' == $method ) { - WP_CLI::success( "Menu item added." ); - } else if ( 'update' == $method ) { - WP_CLI::success( "Menu item updated." ); - } - } - } - - } - - protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields ); - } - -} - -/** - * Manage a menu's assignment to locations. - * - * ## EXAMPLES - * - * # List available menu locations - * $ wp menu location list - * +----------+-------------------+ - * | location | description | - * +----------+-------------------+ - * | primary | Primary Menu | - * | social | Social Links Menu | - * +----------+-------------------+ - * - * # Assign the 'primary-menu' menu to the 'primary' location - * $ wp menu location assign primary-menu primary - * Success: Assigned location to menu. - * - * # Remove the 'primary-menu' menu from the 'primary' location - * $ wp menu location remove primary-menu primary - * Success: Removed location from menu. - */ -class Menu_Location_Command extends WP_CLI_Command { - - /** - * List locations for the current theme. - * - * ## OPTIONS - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * - ids - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each location: - * - * * name - * * description - * - * ## EXAMPLES - * - * $ wp menu location list - * +----------+-------------------+ - * | location | description | - * +----------+-------------------+ - * | primary | Primary Menu | - * | social | Social Links Menu | - * +----------+-------------------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - - $locations = get_registered_nav_menus(); - $location_objs = array(); - foreach( $locations as $location => $description ) { - $location_obj = new \stdClass; - $location_obj->location = $location; - $location_obj->description = $description; - $location_objs[] = $location_obj; - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); - - if ( 'ids' == $formatter->format ) { - $ids = array_map( - function($o) { - return $o->location; - }, $location_objs - ); - $formatter->display_items( $ids ); - } else { - $formatter->display_items( $location_objs ); - } - } - - /** - * Assign a location to a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <location> - * : Location's slug. - * - * ## EXAMPLES - * - * $ wp menu location assign primary-menu primary - * Success: Assigned location to menu. - * - * @subcommand assign - */ - public function assign( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - $locations = get_registered_nav_menus(); - if ( ! array_key_exists( $location, $locations ) ) { - WP_CLI::error( "Invalid location." ); - } - - $locations = get_nav_menu_locations(); - $locations[ $location ] = $menu->term_id; - - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Assigned location to menu." ); - } - - /** - * Remove a location from a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <location> - * : Location's slug. - * - * ## EXAMPLES - * - * $ wp menu location remove primary-menu primary - * Success: Removed location from menu. - * - * @subcommand remove - */ - public function remove( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - $locations = get_nav_menu_locations(); - if ( \WP_CLI\Utils\get_flag_value( $locations, $location ) != $menu->term_id ) { - WP_CLI::error( "Menu isn't assigned to location." ); - } - - $locations[ $location ] = 0; - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Removed location from menu." ); - - } - - -} - WP_CLI::add_command( 'menu', 'Menu_Command' ); -WP_CLI::add_command( 'menu item', 'Menu_Item_Command' ); -WP_CLI::add_command( 'menu location', 'Menu_Location_Command' ); From c1d121b543e1bf862af0b958d603069065673e91 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 07:21:19 -0700 Subject: [PATCH 4848/5359] Failing test case for #3196 --- features/theme.feature | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/features/theme.feature b/features/theme.feature index 04b4a9ea7..59b1f48c2 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -347,3 +347,25 @@ Feature: Manage WordPress themes name,old_version,new_version,status twentytwelve,1.0,{UPDATE_VERSION},Updated """ + + Scenario: Automatically install parent theme for a child theme + Given a WP install + + When I try `wp theme status stargazer` + Then STDERR should contain: + """ + Error: The 'stargazer' theme could not be found. + """ + + When I run `wp theme install buntu` + Then STDOUT should contain: + """ + Successfully installed the parent theme, + """ + + When I run `wp theme status stargazer` + Then STDOUT should contain: + """ + Theme stargazer details: + """ + And STDERR should be empty From 0db84dfd0dc14f5088ddea3075856f044b48d63e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 07:32:15 -0700 Subject: [PATCH 4849/5359] Move `wp theme mod` class to its own file --- php/commands/theme-mod.php | 190 +++++++++++++++++++++++++++++++++++++ php/commands/theme.php | 189 ------------------------------------ 2 files changed, 190 insertions(+), 189 deletions(-) create mode 100644 php/commands/theme-mod.php diff --git a/php/commands/theme-mod.php b/php/commands/theme-mod.php new file mode 100644 index 000000000..00bb78262 --- /dev/null +++ b/php/commands/theme-mod.php @@ -0,0 +1,190 @@ +<?php + +/** + * Manage theme mods. + * + * ## EXAMPLES + * + * # Set theme mod. + * $ wp theme mod set background_color 000000 + * Success: Theme mod background_color set to 000000 + * + * # Get single theme mod in JSON format. + * $ wp theme mod get background_color --format=json + * [{"key":"background_color","value":"dd3333"}] + * + * # Remove all theme mods. + * $ wp theme mod remove --all + * Success: Theme mods removed. + */ +class Theme_Mod_command extends WP_CLI_Command { + + /** + * Get theme mod(s). + * + * ## OPTIONS + * + * [<mod>...] + * : One or more mods to get. + * + * [--all] + * : List all theme mods + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - json + * - csv + * - yaml + * --- + * + * ## EXAMPLES + * + * # Get all theme mods + * $ wp theme mod get --all + * +------------------+---------+ + * | key | value | + * +------------------+---------+ + * | background_color | dd3333 | + * | link_color | #dd9933 | + * | main_text_color | #8224e3 | + * +------------------+---------+ + * + * # Get single theme mod in JSON format + * $ wp theme mod get background_color --format=json + * [{"key":"background_color","value":"dd3333"}] + * + * # Get multiple theme mods + * $ wp theme mod get background_color header_textcolor + * +------------------+--------+ + * | key | value | + * +------------------+--------+ + * | background_color | dd3333 | + * | header_textcolor | | + * +------------------+--------+ + */ + public function get( $args = array(), $assoc_args = array() ) { + + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { + WP_CLI::error( "You must specify at least one mod or use --all." ); + } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + $args = array(); + } + + $list = array(); + $mods = get_theme_mods(); + if ( ! is_array( $mods ) ) { + // if no mods are set (perhaps new theme), make sure foreach still works + $mods = array(); + } + foreach ( $mods as $k => $v ) { + // if mods were given, skip the others + if ( ! empty( $args ) && ! in_array( $k, $args ) ) continue; + + if ( is_array( $v ) ) { + $list[] = array( 'key' => $k, 'value' => '=>' ); + foreach ( $v as $_k => $_v ) { + $list[] = array( 'key' => " $_k", 'value' => $_v ); + } + } else { + $list[] = array( 'key' => $k, 'value' => $v ); + } + + } + + // For unset mods, show blank value + foreach ( $args as $mod ) { + if ( ! isset( $mods[ $mod ] ) ) { + $list[] = array( 'key' => $mod, 'value' => '' ); + } + } + + $formatter = new \WP_CLI\Formatter( $assoc_args, array('key', 'value'), 'thememods' ); + $formatter->display_items( $list ); + + } + + /** + * Remove theme mod(s). + * + * ## OPTIONS + * + * [<mod>...] + * : One or more mods to remove. + * + * [--all] + * : Remove all theme mods. + * + * ## EXAMPLES + * + * # Remove all theme mods. + * $ wp theme mod remove --all + * Success: Theme mods removed. + * + * # Remove single theme mod. + * $ wp theme mod remove background_color + * Success: 1 mod removed. + * + * # Remove multiple theme mods. + * $ wp theme mod remove background_color header_textcolor + * Success: 2 mods removed. + */ + public function remove( $args = array(), $assoc_args = array() ) { + + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { + WP_CLI::error( "You must specify at least one mod or use --all." ); + } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + remove_theme_mods(); + WP_CLI::success( 'Theme mods removed.' ); + return; + } + + foreach ( $args as $mod ) { + remove_theme_mod( $mod ); + } + + $count = count( $args ); + $success_message = ( 1 === $count ) ? '%d mod removed.' : '%d mods removed.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + + } + + /** + * Set a theme mod. + * + * ## OPTIONS + * + * <mod> + * : The name of the theme mod to set or update. + * + * <value> + * : The new value. + * + * ## EXAMPLES + * + * # Set theme mod + * $ wp theme mod set background_color 000000 + * Success: Theme mod background_color set to 000000 + */ + public function set( $args = array(), $assoc_args = array() ) { + list( $mod, $value ) = $args; + + set_theme_mod( $mod, $value ); + + if ( $value == get_theme_mod( $mod ) ) { + WP_CLI::success( sprintf( "Theme mod %s set to %s.", $mod, $value ) ); + } else { + WP_CLI::success( sprintf( "Could not update theme mod %s.", $mod ) ); + } + } + +} + +WP_CLI::add_command( 'theme mod', 'Theme_Mod_Command' ); diff --git a/php/commands/theme.php b/php/commands/theme.php index 265843337..61dd798e6 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -718,193 +718,4 @@ public function list_( $_, $assoc_args ) { } } -/** - * Manage theme mods. - * - * ## EXAMPLES - * - * # Set theme mod. - * $ wp theme mod set background_color 000000 - * Success: Theme mod background_color set to 000000 - * - * # Get single theme mod in JSON format. - * $ wp theme mod get background_color --format=json - * [{"key":"background_color","value":"dd3333"}] - * - * # Remove all theme mods. - * $ wp theme mod remove --all - * Success: Theme mods removed. - */ -class Theme_Mod_command extends WP_CLI_Command { - - /** - * Get theme mod(s). - * - * ## OPTIONS - * - * [<mod>...] - * : One or more mods to get. - * - * [--all] - * : List all theme mods - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - json - * - csv - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get all theme mods - * $ wp theme mod get --all - * +------------------+---------+ - * | key | value | - * +------------------+---------+ - * | background_color | dd3333 | - * | link_color | #dd9933 | - * | main_text_color | #8224e3 | - * +------------------+---------+ - * - * # Get single theme mod in JSON format - * $ wp theme mod get background_color --format=json - * [{"key":"background_color","value":"dd3333"}] - * - * # Get multiple theme mods - * $ wp theme mod get background_color header_textcolor - * +------------------+--------+ - * | key | value | - * +------------------+--------+ - * | background_color | dd3333 | - * | header_textcolor | | - * +------------------+--------+ - */ - public function get( $args = array(), $assoc_args = array() ) { - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { - WP_CLI::error( "You must specify at least one mod or use --all." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - $args = array(); - } - - $list = array(); - $mods = get_theme_mods(); - if ( ! is_array( $mods ) ) { - // if no mods are set (perhaps new theme), make sure foreach still works - $mods = array(); - } - foreach ( $mods as $k => $v ) { - // if mods were given, skip the others - if ( ! empty( $args ) && ! in_array( $k, $args ) ) continue; - - if ( is_array( $v ) ) { - $list[] = array( 'key' => $k, 'value' => '=>' ); - foreach ( $v as $_k => $_v ) { - $list[] = array( 'key' => " $_k", 'value' => $_v ); - } - } else { - $list[] = array( 'key' => $k, 'value' => $v ); - } - - } - - // For unset mods, show blank value - foreach ( $args as $mod ) { - if ( ! isset( $mods[ $mod ] ) ) { - $list[] = array( 'key' => $mod, 'value' => '' ); - } - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, array('key', 'value'), 'thememods' ); - $formatter->display_items( $list ); - - } - - /** - * Remove theme mod(s). - * - * ## OPTIONS - * - * [<mod>...] - * : One or more mods to remove. - * - * [--all] - * : Remove all theme mods. - * - * ## EXAMPLES - * - * # Remove all theme mods. - * $ wp theme mod remove --all - * Success: Theme mods removed. - * - * # Remove single theme mod. - * $ wp theme mod remove background_color - * Success: 1 mod removed. - * - * # Remove multiple theme mods. - * $ wp theme mod remove background_color header_textcolor - * Success: 2 mods removed. - */ - public function remove( $args = array(), $assoc_args = array() ) { - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { - WP_CLI::error( "You must specify at least one mod or use --all." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - remove_theme_mods(); - WP_CLI::success( 'Theme mods removed.' ); - return; - } - - foreach ( $args as $mod ) { - remove_theme_mod( $mod ); - } - - $count = count( $args ); - $success_message = ( 1 === $count ) ? '%d mod removed.' : '%d mods removed.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - - } - - /** - * Set a theme mod. - * - * ## OPTIONS - * - * <mod> - * : The name of the theme mod to set or update. - * - * <value> - * : The new value. - * - * ## EXAMPLES - * - * # Set theme mod - * $ wp theme mod set background_color 000000 - * Success: Theme mod background_color set to 000000 - */ - public function set( $args = array(), $assoc_args = array() ) { - list( $mod, $value ) = $args; - - set_theme_mod( $mod, $value ); - - if ( $value == get_theme_mod( $mod ) ) { - WP_CLI::success( sprintf( "Theme mod %s set to %s.", $mod, $value ) ); - } else { - WP_CLI::success( sprintf( "Could not update theme mod %s.", $mod ) ); - } - } - -} - WP_CLI::add_command( 'theme', 'Theme_Command' ); -WP_CLI::add_command( 'theme mod', 'Theme_Mod_Command' ); - From 6c5a1cdada5b60a987148b269375d745ad845c7d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 16 Aug 2016 14:44:15 -0700 Subject: [PATCH 4850/5359] Update tests for WordPress 4.7 --- features/core-check-update.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 0b6a728ab..71c988588 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,7 +9,7 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.3 | major | https://downloads.wordpress.org/release/wordpress-4.5.3.zip | + | 4.6 | major | https://downloads.wordpress.org/release/wordpress-4.6.zip | | 4.4.4 | minor | https://downloads.wordpress.org/release/wordpress-4.4.4-partial-0.zip | When I run `wp core check-update --format=count` @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.5.3 | major | https://downloads.wordpress.org/release/wordpress-4.5.3.zip | + | 4.6 | major | https://downloads.wordpress.org/release/wordpress-4.6.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: From d56438bcd6d2d8b47641eba465aa284a45979ed4 Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 17 Aug 2016 01:33:44 +0100 Subject: [PATCH 4851/5359] Introduce `wp user session destroy-all` and `wp user session list` commands. --- php/commands/user.php | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index f0c5daa66..c7b41d641 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -1120,6 +1120,120 @@ class User_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'user'; } +/** + * Manage a user's sessions. + * + * ## EXAMPLES + * + */ +class User_Session_Command extends WP_CLI_Command { + + private $fields = array( + 'token', + 'login_time', + 'expiration_time', + 'ip', + 'ua', + ); + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + + /** + * Destroy all sessions for the given user. + * + * ## OPTIONS + * + * <user> + * : User ID, user email, or user login. + * + * ## EXAMPLES + * + * # Destroy a user's sessions + * $ wp user session destroy-all admin + * Success: Destroyed all sessions. + * + * @subcommand destroy-all + */ + public function destroy_all( $args, $assoc_args ) { + $user = $this->fetcher->get_check( $args[0] ); + $manager = WP_Session_Tokens::get_instance( $user->ID ); + $sessions = $manager->destroy_all(); + + WP_CLI::success( 'Destroyed all sessions.' ); + } + + /** + * List sessions for the given user. + * + * ## OPTIONS + * + * <user> + * : User ID, user email, or user login. + * + * [--fields=<fields>] + * : Limit the output to specific fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, yaml. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each session: + * + * * token + * * login_time + * * expiration_time + * * ip + * * ua + * + * These fields are optionally available: + * + * * expiration + * * login + * + * ## EXAMPLES + * + * # List a user's sessions + * $ wp user session list admin@example.com --format=csv + * login_time,expiration_time,ip,ua + * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $user = $this->fetcher->get_check( $args[0] ); + $formatter = $this->get_formatter( $assoc_args ); + $manager = WP_Session_Tokens::get_instance( $user->ID ); + + $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); + $get_sessions->setAccessible( true ); + $sessions = $get_sessions->invoke( $manager ); + + if ( 'ids' == $formatter->format ) { + echo implode( ' ', array_keys( $sessions ) ); + } else if ( 'count' === $formatter->format ) { + $formatter->display_items( $sessions ); + } else { + $it = array_map( function( $session, $token ) { + $session['token'] = $token; + $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); + $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); + return $session; + }, $sessions, array_keys( $sessions ) ); + + $formatter->display_items( $it ); + } + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields ); + } + +} + WP_CLI::add_command( 'user', 'User_Command' ); WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); WP_CLI::add_command( 'user term', 'User_Term_Command' ); +WP_CLI::add_command( 'user session', 'User_Session_Command' ); From 394115a7154d9b58f3b90cf9a551db9a0342a9d8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 04:40:45 -0700 Subject: [PATCH 4852/5359] Move `wp term meta` class to its own file --- php/commands/term-meta.php | 49 ++++++++++++++++++++++++++++++++++++++ php/commands/term.php | 47 ------------------------------------ 2 files changed, 49 insertions(+), 47 deletions(-) create mode 100644 php/commands/term-meta.php diff --git a/php/commands/term-meta.php b/php/commands/term-meta.php new file mode 100644 index 000000000..53483b79a --- /dev/null +++ b/php/commands/term-meta.php @@ -0,0 +1,49 @@ +<?php + +/** + * Manage term custom fields. + * + * ## EXAMPLES + * + * # Set term meta + * $ wp term meta set 123 bio "Mary is a WordPress developer." + * Success: Updated custom field 'bio'. + * + * # Get term meta + * $ wp term meta get 123 bio + * Mary is a WordPress developer. + * + * # Update term meta + * $ wp term meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. + * + * # Delete term meta + * $ wp term meta delete 123 bio + * Success: Deleted custom field. + */ +class Term_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'term'; + + /** + * Check that the term ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $term = get_term( $object_id ); + if ( ! $term ) { + WP_CLI::error( "Could not find the term with ID {$object_id}." ); + } + return $term->term_id; + } + +} + +WP_CLI::add_command( 'term meta', 'Term_Meta_Command', array( + 'before_invoke' => function() { + if ( \WP_CLI\Utils\wp_version_compare( '4.4', '<' ) ) { + WP_CLI::error( "Requires WordPress 4.4 or greater." ); + } + }) +); + diff --git a/php/commands/term.php b/php/commands/term.php index dc652d884..db759c135 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -572,51 +572,4 @@ private function get_formatter( &$assoc_args ) { } } -/** - * Manage term custom fields. - * - * ## EXAMPLES - * - * # Set term meta - * $ wp term meta set 123 bio "Mary is a WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Get term meta - * $ wp term meta get 123 bio - * Mary is a WordPress developer. - * - * # Update term meta - * $ wp term meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Delete term meta - * $ wp term meta delete 123 bio - * Success: Deleted custom field. - */ -class Term_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'term'; - - /** - * Check that the term ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $term = get_term( $object_id ); - if ( ! $term ) { - WP_CLI::error( "Could not find the term with ID {$object_id}." ); - } - return $term->term_id; - } - -} - WP_CLI::add_command( 'term', 'Term_Command' ); -WP_CLI::add_command( 'term meta', 'Term_Meta_Command', array( - 'before_invoke' => function() { - if ( \WP_CLI\Utils\wp_version_compare( '4.4', '<' ) ) { - WP_CLI::error( "Requires WordPress 4.4 or greater." ); - } - }) -); - From 98c188c263d87f37ab5909b148e589e15d0cef8b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 04:46:36 -0700 Subject: [PATCH 4853/5359] Move `wp cron (event|schedule)` classes to their own files --- php/commands/cron-event.php | 472 ++++++++++++++++++++++++++ php/commands/cron-schedule.php | 130 +++++++ php/commands/cron.php | 600 +-------------------------------- 3 files changed, 603 insertions(+), 599 deletions(-) create mode 100644 php/commands/cron-event.php create mode 100644 php/commands/cron-schedule.php diff --git a/php/commands/cron-event.php b/php/commands/cron-event.php new file mode 100644 index 000000000..b3903f557 --- /dev/null +++ b/php/commands/cron-event.php @@ -0,0 +1,472 @@ +<?php + +/** + * Manage WP-Cron events. + * + * ## EXAMPLES + * + * # Schedule a new cron event + * $ wp cron event schedule cron_test + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. + * + * # Run all cron events due right now + * $ wp cron event run --due-now + * Success: Executed a total of 2 cron events. + * + * # Delete the next scheduled cron event + * $ wp cron event delete cron_test + * Success: Deleted 2 instances of the cron event 'cron_test'. + * + * # List scheduled cron events in JSON + * $ wp cron event list --fields=hook,next_run --format=json + * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] + * + * @package wp-cli + */ +class Cron_Event_Command extends WP_CLI_Command { + + private $fields = array( + 'hook', + 'next_run_gmt', + 'next_run_relative', + 'recurrence', + ); + private static $time_format = 'Y-m-d H:i:s'; + + /** + * List scheduled cron events. + * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. + * + * [--<field>=<value>] + * : Filter by one or more fields. + * + * [--field=<field>] + * : Prints the value of a single field for each event. + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - count + * - yaml + * --- + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each cron event: + * * hook + * * next_run_gmt + * * next_run_relative + * * recurrence + * + * These fields are optionally available: + * * time + * * sig + * * args + * * schedule + * * interval + * * next_run + * + * ## EXAMPLES + * + * # List scheduled cron events + * $ wp cron event list + * +-------------------+---------------------+---------------------+------------+ + * | hook | next_run_gmt | next_run_relative | recurrence | + * +-------------------+---------------------+---------------------+------------+ + * | wp_version_check | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | + * | wp_update_plugins | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | + * | wp_update_themes | 2016-05-31 22:15:14 | 11 hours 57 minutes | 12 hours | + * +-------------------+---------------------+---------------------+------------+ + * + * # List scheduled cron events in JSON + * $ wp cron event list --fields=hook,next_run --format=json + * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); + + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + $events = array(); + } + + foreach ( $events as $key => $event ) { + foreach ( $this->fields as $field ) { + if ( ! empty( $assoc_args[ $field ] ) && $event->{$field} !== $assoc_args[ $field ] ) { + unset( $events[ $key ] ); + break; + } + } + } + + if ( 'ids' == $formatter->format ) { + echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); + } else { + $formatter->display_items( $events ); + } + + } + + /** + * Schedule a new cron event. + * + * ## OPTIONS + * + * <hook> + * : The hook name. + * + * [<next-run>] + * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. + * + * [<recurrence>] + * : How often the event should recur. See `wp cron schedule list` for available schedule names. Defaults to no recurrence. + * + * [--<field>=<value>] + * : Associative args for the event. + * + * ## EXAMPLES + * + * # Schedule a new cron event + * $ wp cron event schedule cron_test + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. + * + * # Schedule new cron event with hourly recurrence + * $ wp cron event schedule cron_test now hourly + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:20:32 GMT. + * + * # Schedule new cron event and pass associative arguments + * $ wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 + * Success: Scheduled event with hook 'cron_test' for 2016-05-31 11:21:35 GMT. + */ + public function schedule( $args, $assoc_args ) { + + $hook = $args[0]; + $next_run = \WP_CLI\Utils\get_flag_value( $args, 1, 'now' ); + $recurrence = \WP_CLI\Utils\get_flag_value( $args, 2, false ); + + if ( empty( $next_run ) ) { + $timestamp = time(); + } else if ( is_numeric( $next_run ) ) { + $timestamp = absint( $next_run ); + } else { + $timestamp = strtotime( $next_run ); + } + + if ( ! $timestamp ) { + WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $next_run ) ); + } + + if ( ! empty( $recurrence ) ) { + + $schedules = wp_get_schedules(); + + if ( ! isset( $schedules[$recurrence] ) ) { + WP_CLI::error( sprintf( "'%s' is not a valid schedule name for recurrence.", $recurrence ) ); + } + + $event = wp_schedule_event( $timestamp, $recurrence, $hook, $assoc_args ); + + } else { + + $event = wp_schedule_single_event( $timestamp, $hook, $assoc_args ); + + } + + if ( false !== $event ) { + WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s GMT.", $hook, date( self::$time_format, $timestamp ) ) ); + } else { + WP_CLI::error( 'Event not scheduled.' ); + } + + } + + /** + * Run the next scheduled cron event for the given hook. + * + * ## OPTIONS + * + * [<hook>...] + * : One or more hooks to run. + * + * [--due-now] + * : Run all hooks due right now. + * + * [--all] + * : Run all hooks. + * + * ## EXAMPLES + * + * # Run all cron events due right now + * $ wp cron event run --due-now + * Success: Executed a total of 2 cron events. + */ + public function run( $args, $assoc_args ) { + + if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + WP_CLI::error( 'Please specify one or more cron events, or use --due-now/--all.' ); + } + + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + WP_CLI::error( $events ); + } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { + $due_events = array(); + foreach( $events as $event ) { + if ( time() >= $event->time ) { + $due_events[] = $event; + } + } + $events = $due_events; + } else if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { + $hooks = wp_list_pluck( $events, 'hook' ); + $due_events = array(); + foreach( $args as $hook ) { + if ( ! in_array( $hook, $hooks ) ) { + WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); + } + } + foreach( $events as $event ) { + if ( in_array( $event->hook, $args ) ) { + $due_events[] = $event; + } + } + $events = $due_events; + } + + $executed = 0; + foreach ( $events as $event ) { + $start = microtime( true ); + $result = self::run_event( $event ); + $total = round( microtime( true ) - $start, 3 ); + $executed++; + WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); + } + + $message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.'; + WP_CLI::success( sprintf( $message, $executed ) ); + } + + /** + * Executes an event immediately. + * + * @param stdClass $event The event + * @return bool Whether the event was successfully executed or not. + */ + protected static function run_event( stdClass $event ) { + + if ( ! defined( 'DOING_CRON' ) ) { + define( 'DOING_CRON', true ); + } + + if ( $event->schedule != false ) { + $new_args = array( $event->time, $event->schedule, $event->hook, $event->args ); + call_user_func_array( 'wp_reschedule_event', $new_args ); + } + + wp_unschedule_event( $event->time, $event->hook, $event->args ); + + do_action_ref_array( $event->hook, $event->args ); + + return true; + + } + + /** + * Delete the next scheduled cron event for the given hook. + * + * ## OPTIONS + * + * <hook> + * : The hook name. + * + * ## EXAMPLES + * + * # Delete the next scheduled cron event + * $ wp cron event delete cron_test + * Success: Deleted 2 instances of the cron event 'cron_test'. + */ + public function delete( $args, $assoc_args ) { + + $hook = $args[0]; + $events = self::get_cron_events(); + + if ( is_wp_error( $events ) ) { + WP_CLI::error( $events ); + } + + $deleted = 0; + foreach ( $events as $event ) { + if ( $event->hook == $hook ) { + $result = self::delete_event( $event ); + if ( $result ) { + $deleted++; + } else { + WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'.", $hook ) ); + } + } + } + + if ( $deleted ) { + $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'." : "Deleted %1\$d instances of the cron event '%2\$s'."; + WP_CLI::success( sprintf( $message, $deleted, $hook ) ); + } else { + WP_CLI::error( sprintf( "Invalid cron event '%s'.", $hook ) ); + } + + } + + /** + * Deletes a cron event. + * + * @param stdClass $event The event + * @return bool Whether the event was successfully deleted or not. + */ + protected static function delete_event( stdClass $event ) { + $crons = _get_cron_array(); + + if ( ! isset( $crons[$event->time][$event->hook][$event->sig] ) ) { + return false; + } + + wp_unschedule_event( $event->time, $event->hook, $event->args ); + return true; + } + + /** + * Callback function to format a cron event. + * + * @param stdClass $event The event. + * @return stdClass The formatted event object. + */ + protected static function format_event( stdClass $event ) { + + $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), self::$time_format ); + $event->next_run_gmt = date( self::$time_format, $event->time ); + $event->next_run_relative = self::interval( $event->time - time() ); + $event->recurrence = ( $event->schedule ) ? self::interval( $event->interval ) : 'Non-repeating'; + + return $event; + } + + /** + * Fetch an array of scheduled cron events. + * + * @return array|WP_Error An array of event objects, or a WP_Error object if there are no events scheduled. + */ + protected static function get_cron_events() { + + $crons = _get_cron_array(); + $events = array(); + + if ( empty( $crons ) ) { + return new WP_Error( + 'no_events', + 'You currently have no scheduled cron events.' + ); + } + + foreach ( $crons as $time => $hooks ) { + foreach ( $hooks as $hook => $hook_events ) { + foreach ( $hook_events as $sig => $data ) { + + $events[] = (object) array( + 'hook' => $hook, + 'time' => $time, + 'sig' => $sig, + 'args' => $data['args'], + 'schedule' => $data['schedule'], + 'interval' => \WP_CLI\Utils\get_flag_value( $data, 'interval' ), + ); + + } + } + } + + $events = array_map( 'Cron_Event_Command::format_event', $events ); + + return $events; + + } + + /** + * Convert a time interval into human-readable format. + * + * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. + * + * @param int $since An interval of time in seconds + * @return string The interval in human readable format + */ + private static function interval( $since ) { + if ( $since <= 0 ) { + return 'now'; + } + + $since = absint( $since ); + + // array of time period chunks + $chunks = array( + array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), + array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), + array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), + array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), + array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), + array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), + array( 1 , \_n_noop( '%s second', '%s seconds' ) ), + ); + + // we only want to output two chunks of time here, eg: + // x years, xx months + // x days, xx hours + // so there's only two bits of calculation below: + + // step one: the first chunk + for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { + $seconds = $chunks[$i][0]; + $name = $chunks[$i][1]; + + // finding the biggest chunk (if the chunk fits, break) + if ( ( $count = floor( $since / $seconds ) ) != 0 ){ + break; + } + } + + // set output var + $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); + + // step two: the second chunk + if ( $i + 1 < $j ) { + $seconds2 = $chunks[$i + 1][0]; + $name2 = $chunks[$i + 1][1]; + + if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { + // add to output var + $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); + } + } + + return $output; + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'event' ); + } + +} + +WP_CLI::add_command( 'cron event', 'Cron_Event_Command' ); diff --git a/php/commands/cron-schedule.php b/php/commands/cron-schedule.php new file mode 100644 index 000000000..7c9661c0f --- /dev/null +++ b/php/commands/cron-schedule.php @@ -0,0 +1,130 @@ +<?php + +/** + * Manage WP-Cron schedules. + * + * ## EXAMPLES + * + * # List available cron schedules + * $ wp cron schedule list + * +------------+-------------+----------+ + * | name | display | interval | + * +------------+-------------+----------+ + * | hourly | Once Hourly | 3600 | + * | twicedaily | Twice Daily | 43200 | + * | daily | Once Daily | 86400 | + * +------------+-------------+----------+ + */ +class Cron_Schedule_Command extends WP_CLI_Command { + + private $fields = array( + 'name', + 'display', + 'interval', + ); + + /** + * List available cron schedules. + * + * ## OPTIONS + * + * [--fields=<fields>] + * : Limit the output to specific object fields. + * + * [--field=<field>] + * : Prints the value of a single field for each schedule. + * + * [--format=<format>] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - yaml + * --- + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each cron schedule: + * + * * name + * * display + * * interval + * + * There are no additional fields. + * + * ## EXAMPLES + * + * # List available cron schedules + * $ wp cron schedule list + * +------------+-------------+----------+ + * | name | display | interval | + * +------------+-------------+----------+ + * | hourly | Once Hourly | 3600 | + * | twicedaily | Twice Daily | 43200 | + * | daily | Once Daily | 86400 | + * +------------+-------------+----------+ + * + * # List id of available cron schedule + * $ wp cron schedule list --fields=name --format=ids + * hourly twicedaily daily + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $formatter = $this->get_formatter( $assoc_args ); + + $schedules = self::get_schedules(); + + if ( 'ids' == $formatter->format ) { + echo implode( ' ', wp_list_pluck( $schedules, 'name' ) ); + } else { + $formatter->display_items( $schedules ); + } + + } + + /** + * Callback function to format a cron schedule. + * + * @param array $schedule The schedule. + * @param string $name The schedule name. + * @return array The formatted schedule. + */ + protected static function format_schedule( array $schedule, $name ) { + $schedule['name'] = $name; + return $schedule; + } + + /** + * Return a list of the cron schedules sorted according to interval. + * + * @return array The array of cron schedules. Each schedule is itself an array. + */ + protected static function get_schedules() { + $schedules = wp_get_schedules(); + if ( !empty( $schedules ) ) { + uasort( $schedules, 'Cron_Schedule_Command::sort' ); + $schedules = array_map( 'Cron_Schedule_Command::format_schedule', $schedules, array_keys( $schedules ) ); + } + return $schedules; + } + + /** + * Callback function to sort the cron schedule array by interval. + * + */ + protected static function sort( array $a, array $b ) { + return $a['interval'] - $b['interval']; + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'schedule' ); + } + +} + +WP_CLI::add_command( 'cron schedule', 'Cron_Schedule_Command' ); diff --git a/php/commands/cron.php b/php/commands/cron.php index 2995e1eef..e87283355 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -1,601 +1,5 @@ <?php -/** - * Manage WP-Cron events. - * - * ## EXAMPLES - * - * # Schedule a new cron event - * $ wp cron event schedule cron_test - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. - * - * # Run all cron events due right now - * $ wp cron event run --due-now - * Success: Executed a total of 2 cron events. - * - * # Delete the next scheduled cron event - * $ wp cron event delete cron_test - * Success: Deleted 2 instances of the cron event 'cron_test'. - * - * # List scheduled cron events in JSON - * $ wp cron event list --fields=hook,next_run --format=json - * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] - * - * @package wp-cli - */ -class Cron_Event_Command extends WP_CLI_Command { - - private $fields = array( - 'hook', - 'next_run_gmt', - 'next_run_relative', - 'recurrence', - ); - private static $time_format = 'Y-m-d H:i:s'; - - /** - * List scheduled cron events. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--<field>=<value>] - * : Filter by one or more fields. - * - * [--field=<field>] - * : Prints the value of a single field for each event. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each cron event: - * * hook - * * next_run_gmt - * * next_run_relative - * * recurrence - * - * These fields are optionally available: - * * time - * * sig - * * args - * * schedule - * * interval - * * next_run - * - * ## EXAMPLES - * - * # List scheduled cron events - * $ wp cron event list - * +-------------------+---------------------+---------------------+------------+ - * | hook | next_run_gmt | next_run_relative | recurrence | - * +-------------------+---------------------+---------------------+------------+ - * | wp_version_check | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | - * | wp_update_plugins | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | - * | wp_update_themes | 2016-05-31 22:15:14 | 11 hours 57 minutes | 12 hours | - * +-------------------+---------------------+---------------------+------------+ - * - * # List scheduled cron events in JSON - * $ wp cron event list --fields=hook,next_run --format=json - * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - $events = array(); - } - - foreach ( $events as $key => $event ) { - foreach ( $this->fields as $field ) { - if ( ! empty( $assoc_args[ $field ] ) && $event->{$field} !== $assoc_args[ $field ] ) { - unset( $events[ $key ] ); - break; - } - } - } - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); - } else { - $formatter->display_items( $events ); - } - - } - - /** - * Schedule a new cron event. - * - * ## OPTIONS - * - * <hook> - * : The hook name. - * - * [<next-run>] - * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. - * - * [<recurrence>] - * : How often the event should recur. See `wp cron schedule list` for available schedule names. Defaults to no recurrence. - * - * [--<field>=<value>] - * : Associative args for the event. - * - * ## EXAMPLES - * - * # Schedule a new cron event - * $ wp cron event schedule cron_test - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. - * - * # Schedule new cron event with hourly recurrence - * $ wp cron event schedule cron_test now hourly - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:20:32 GMT. - * - * # Schedule new cron event and pass associative arguments - * $ wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 11:21:35 GMT. - */ - public function schedule( $args, $assoc_args ) { - - $hook = $args[0]; - $next_run = \WP_CLI\Utils\get_flag_value( $args, 1, 'now' ); - $recurrence = \WP_CLI\Utils\get_flag_value( $args, 2, false ); - - if ( empty( $next_run ) ) { - $timestamp = time(); - } else if ( is_numeric( $next_run ) ) { - $timestamp = absint( $next_run ); - } else { - $timestamp = strtotime( $next_run ); - } - - if ( ! $timestamp ) { - WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $next_run ) ); - } - - if ( ! empty( $recurrence ) ) { - - $schedules = wp_get_schedules(); - - if ( ! isset( $schedules[$recurrence] ) ) { - WP_CLI::error( sprintf( "'%s' is not a valid schedule name for recurrence.", $recurrence ) ); - } - - $event = wp_schedule_event( $timestamp, $recurrence, $hook, $assoc_args ); - - } else { - - $event = wp_schedule_single_event( $timestamp, $hook, $assoc_args ); - - } - - if ( false !== $event ) { - WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s GMT.", $hook, date( self::$time_format, $timestamp ) ) ); - } else { - WP_CLI::error( 'Event not scheduled.' ); - } - - } - - /** - * Run the next scheduled cron event for the given hook. - * - * ## OPTIONS - * - * [<hook>...] - * : One or more hooks to run. - * - * [--due-now] - * : Run all hooks due right now. - * - * [--all] - * : Run all hooks. - * - * ## EXAMPLES - * - * # Run all cron events due right now - * $ wp cron event run --due-now - * Success: Executed a total of 2 cron events. - */ - public function run( $args, $assoc_args ) { - - if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - WP_CLI::error( 'Please specify one or more cron events, or use --due-now/--all.' ); - } - - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - WP_CLI::error( $events ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { - $due_events = array(); - foreach( $events as $event ) { - if ( time() >= $event->time ) { - $due_events[] = $event; - } - } - $events = $due_events; - } else if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - $hooks = wp_list_pluck( $events, 'hook' ); - $due_events = array(); - foreach( $args as $hook ) { - if ( ! in_array( $hook, $hooks ) ) { - WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); - } - } - foreach( $events as $event ) { - if ( in_array( $event->hook, $args ) ) { - $due_events[] = $event; - } - } - $events = $due_events; - } - - $executed = 0; - foreach ( $events as $event ) { - $start = microtime( true ); - $result = self::run_event( $event ); - $total = round( microtime( true ) - $start, 3 ); - $executed++; - WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); - } - - $message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.'; - WP_CLI::success( sprintf( $message, $executed ) ); - } - - /** - * Executes an event immediately. - * - * @param stdClass $event The event - * @return bool Whether the event was successfully executed or not. - */ - protected static function run_event( stdClass $event ) { - - if ( ! defined( 'DOING_CRON' ) ) { - define( 'DOING_CRON', true ); - } - - if ( $event->schedule != false ) { - $new_args = array( $event->time, $event->schedule, $event->hook, $event->args ); - call_user_func_array( 'wp_reschedule_event', $new_args ); - } - - wp_unschedule_event( $event->time, $event->hook, $event->args ); - - do_action_ref_array( $event->hook, $event->args ); - - return true; - - } - - /** - * Delete the next scheduled cron event for the given hook. - * - * ## OPTIONS - * - * <hook> - * : The hook name. - * - * ## EXAMPLES - * - * # Delete the next scheduled cron event - * $ wp cron event delete cron_test - * Success: Deleted 2 instances of the cron event 'cron_test'. - */ - public function delete( $args, $assoc_args ) { - - $hook = $args[0]; - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - WP_CLI::error( $events ); - } - - $deleted = 0; - foreach ( $events as $event ) { - if ( $event->hook == $hook ) { - $result = self::delete_event( $event ); - if ( $result ) { - $deleted++; - } else { - WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'.", $hook ) ); - } - } - } - - if ( $deleted ) { - $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'." : "Deleted %1\$d instances of the cron event '%2\$s'."; - WP_CLI::success( sprintf( $message, $deleted, $hook ) ); - } else { - WP_CLI::error( sprintf( "Invalid cron event '%s'.", $hook ) ); - } - - } - - /** - * Deletes a cron event. - * - * @param stdClass $event The event - * @return bool Whether the event was successfully deleted or not. - */ - protected static function delete_event( stdClass $event ) { - $crons = _get_cron_array(); - - if ( ! isset( $crons[$event->time][$event->hook][$event->sig] ) ) { - return false; - } - - wp_unschedule_event( $event->time, $event->hook, $event->args ); - return true; - } - - /** - * Callback function to format a cron event. - * - * @param stdClass $event The event. - * @return stdClass The formatted event object. - */ - protected static function format_event( stdClass $event ) { - - $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), self::$time_format ); - $event->next_run_gmt = date( self::$time_format, $event->time ); - $event->next_run_relative = self::interval( $event->time - time() ); - $event->recurrence = ( $event->schedule ) ? self::interval( $event->interval ) : 'Non-repeating'; - - return $event; - } - - /** - * Fetch an array of scheduled cron events. - * - * @return array|WP_Error An array of event objects, or a WP_Error object if there are no events scheduled. - */ - protected static function get_cron_events() { - - $crons = _get_cron_array(); - $events = array(); - - if ( empty( $crons ) ) { - return new WP_Error( - 'no_events', - 'You currently have no scheduled cron events.' - ); - } - - foreach ( $crons as $time => $hooks ) { - foreach ( $hooks as $hook => $hook_events ) { - foreach ( $hook_events as $sig => $data ) { - - $events[] = (object) array( - 'hook' => $hook, - 'time' => $time, - 'sig' => $sig, - 'args' => $data['args'], - 'schedule' => $data['schedule'], - 'interval' => \WP_CLI\Utils\get_flag_value( $data, 'interval' ), - ); - - } - } - } - - $events = array_map( 'Cron_Event_Command::format_event', $events ); - - return $events; - - } - - /** - * Convert a time interval into human-readable format. - * - * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. - * - * @param int $since An interval of time in seconds - * @return string The interval in human readable format - */ - private static function interval( $since ) { - if ( $since <= 0 ) { - return 'now'; - } - - $since = absint( $since ); - - // array of time period chunks - $chunks = array( - array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), - array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), - array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), - array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), - array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), - array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), - array( 1 , \_n_noop( '%s second', '%s seconds' ) ), - ); - - // we only want to output two chunks of time here, eg: - // x years, xx months - // x days, xx hours - // so there's only two bits of calculation below: - - // step one: the first chunk - for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { - $seconds = $chunks[$i][0]; - $name = $chunks[$i][1]; - - // finding the biggest chunk (if the chunk fits, break) - if ( ( $count = floor( $since / $seconds ) ) != 0 ){ - break; - } - } - - // set output var - $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); - - // step two: the second chunk - if ( $i + 1 < $j ) { - $seconds2 = $chunks[$i + 1][0]; - $name2 = $chunks[$i + 1][1]; - - if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { - // add to output var - $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); - } - } - - return $output; - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'event' ); - } - -} - -/** - * Manage WP-Cron schedules. - * - * ## EXAMPLES - * - * # List available cron schedules - * $ wp cron schedule list - * +------------+-------------+----------+ - * | name | display | interval | - * +------------+-------------+----------+ - * | hourly | Once Hourly | 3600 | - * | twicedaily | Twice Daily | 43200 | - * | daily | Once Daily | 86400 | - * +------------+-------------+----------+ - */ -class Cron_Schedule_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'display', - 'interval', - ); - - /** - * List available cron schedules. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--field=<field>] - * : Prints the value of a single field for each schedule. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each cron schedule: - * - * * name - * * display - * * interval - * - * There are no additional fields. - * - * ## EXAMPLES - * - * # List available cron schedules - * $ wp cron schedule list - * +------------+-------------+----------+ - * | name | display | interval | - * +------------+-------------+----------+ - * | hourly | Once Hourly | 3600 | - * | twicedaily | Twice Daily | 43200 | - * | daily | Once Daily | 86400 | - * +------------+-------------+----------+ - * - * # List id of available cron schedule - * $ wp cron schedule list --fields=name --format=ids - * hourly twicedaily daily - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $schedules = self::get_schedules(); - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', wp_list_pluck( $schedules, 'name' ) ); - } else { - $formatter->display_items( $schedules ); - } - - } - - /** - * Callback function to format a cron schedule. - * - * @param array $schedule The schedule. - * @param string $name The schedule name. - * @return array The formatted schedule. - */ - protected static function format_schedule( array $schedule, $name ) { - $schedule['name'] = $name; - return $schedule; - } - - /** - * Return a list of the cron schedules sorted according to interval. - * - * @return array The array of cron schedules. Each schedule is itself an array. - */ - protected static function get_schedules() { - $schedules = wp_get_schedules(); - if ( !empty( $schedules ) ) { - uasort( $schedules, 'Cron_Schedule_Command::sort' ); - $schedules = array_map( 'Cron_Schedule_Command::format_schedule', $schedules, array_keys( $schedules ) ); - } - return $schedules; - } - - /** - * Callback function to sort the cron schedule array by interval. - * - */ - protected static function sort( array $a, array $b ) { - return $a['interval'] - $b['interval']; - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'schedule' ); - } - -} - /** * Manage WP-Cron events and schedules. * @@ -683,6 +87,4 @@ protected static function get_cron_spawn() { } -WP_CLI::add_command( 'cron', 'Cron_Command' ); -WP_CLI::add_command( 'cron event', 'Cron_Event_Command' ); -WP_CLI::add_command( 'cron schedule', 'Cron_Schedule_Command' ); +WP_CLI::add_command( 'cron', 'Cron_Command' ); From bc222cb75c241ca30c08f7cb042ea5d324f64fcf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 05:12:19 -0700 Subject: [PATCH 4854/5359] Use corrected updating text --- features/theme.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/theme.feature b/features/theme.feature index 59b1f48c2..1c5d7d6fd 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -360,7 +360,7 @@ Feature: Manage WordPress themes When I run `wp theme install buntu` Then STDOUT should contain: """ - Successfully installed the parent theme, + This theme requires a parent theme. Checking if it is installed """ When I run `wp theme status stargazer` From c0d8618b72215f8ddad4ea457460816fd1bb5b51 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 05:23:22 -0700 Subject: [PATCH 4855/5359] Manually clear `WP_Theme` cache Because we're checking whether the theme exists, `WP_Theme` is instantiated as a missing theme. Unless we manually clear the cache, the installer will later reference this bad cache value when trying to determine whether there's a parent theme to install too. --- php/commands/theme.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index 265843337..bf0fe83ed 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -372,9 +372,17 @@ protected function install_from_repo( $slug, $assoc_args ) { self::alter_api_response( $api, $assoc_args['version'] ); } - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && wp_get_theme( $slug )->exists() ) { - // We know this will fail, so avoid a needless download of the package. - return new WP_Error( 'already_installed', 'Theme already installed.' ); + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { + $theme = wp_get_theme( $slug ); + if ( $theme->exists() ) { + // We know this will fail, so avoid a needless download of the package. + return new WP_Error( 'already_installed', 'Theme already installed.' ); + } + // Clear cache so WP_Theme doesn't create a "missing theme" object. + $cache_hash = md5( $theme->theme_root . '/' . $theme->stylesheet ); + foreach( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key ) { + wp_cache_delete( $key . '-' . $cache_hash, 'themes' ); + } } WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); From 536f3813bf9e708bddf989077aa53d99ace154e6 Mon Sep 17 00:00:00 2001 From: veganista <liam@nanothree.net> Date: Wed, 17 Aug 2016 16:34:21 +0100 Subject: [PATCH 4856/5359] Update wp-config.mustache Updates config template to better match the WP generated one --- templates/wp-config.mustache | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 104a37946..7776f301e 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -1,5 +1,22 @@ <?php - +/** + * The base configuration for WordPress + * + * The wp-config.php creation script uses this file during the + * installation. You don't have to use the web site, you can + * copy this file to "wp-config.php" and fill in the values. + * + * This file contains the following configurations: + * + * * MySQL settings + * * Secret keys + * * Database table prefix + * * ABSPATH + * + * @link https://codex.wordpress.org/Editing_wp-config.php + * + * @package WordPress + */ // ** MySQL settings ** // /** The name of the database for WordPress */ @@ -20,10 +37,25 @@ define('DB_CHARSET', '{{dbcharset}}'); /** The Database Collate type. Don't change this if in doubt. */ define('DB_COLLATE', '{{dbcollate}}'); +/** + * Authentication Unique Keys and Salts. + * + * Change these to different unique phrases! + * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} + * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. + * + * @since 2.6.0 + */ {{#keys-and-salts}} {{keys-and-salts}} {{/keys-and-salts}} +/** + * WordPress Database Table prefix. + * + * You can have multiple installations in one database if you give each + * a unique prefix. Only numbers, letters, and underscores please! + */ $table_prefix = '{{dbprefix}}'; {{#add-wplang}} @@ -32,7 +64,6 @@ define('WPLANG', '{{locale}}'); {{extra-php}} - /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ From 539631df378d45866bd62289056e67b0c24713b2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 09:10:01 -0700 Subject: [PATCH 4857/5359] Remove branch names from directories created for Github-based ZIPs Ideally, we'd perform this transformation in the original unzip -> move process. However, it's not easily possible to hook into it. --- features/plugin-install.feature | 21 +++++++++++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 12 ++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 features/plugin-install.feature diff --git a/features/plugin-install.feature b/features/plugin-install.feature new file mode 100644 index 000000000..0971e2a04 --- /dev/null +++ b/features/plugin-install.feature @@ -0,0 +1,21 @@ +Feature: Install WordPress plugins + + Scenario: Branch names should be removed from Github projects + Given a WP install + + When I run `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip --activate` + Then STDOUT should contain: + """ + Downloading install package from https://github.com/runcommand/one-time-login/archive/master.zip + """ + And STDOUT should contain: + """ + Moved Github-based project from 'one-time-login-master' to 'one-time-login'. + """ + And STDOUT should contain: + """ + Plugin installed successfully. + """ + And STDERR should be empty + And the wp-content/plugins/one-time-login directory should exist + And the wp-content/plugins/one-time-login-master directory should not exist diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 561b2331d..6d2e3e54e 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -139,6 +139,18 @@ function install( $args, $assoc_args ) { if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { $slug = $file_upgrader->result['destination_name']; + // Remove the branch name from the director for Github URLs + if ( strpos( $local_or_remote_zip_file, '://' ) !== false + && 'github.com' === parse_url( $local_or_remote_zip_file, PHP_URL_HOST ) ) { + $branch_length = strlen( pathinfo( $local_or_remote_zip_file, PATHINFO_FILENAME ) ); + if ( $branch_length ) { + $new_path = substr( rtrim( $file_upgrader->result['destination'], '/' ), 0, - ( $branch_length + 1 ) ) . '/'; + if ( $GLOBALS['wp_filesystem']->move( $file_upgrader->result['destination'], $new_path ) ) { + $slug = basename( $new_path ); + WP_CLI::log( "Moved Github-based project from '" . basename( $file_upgrader->result['destination_name'] ) . "' to '" . $slug . "'." ); + } + } + } $result = true; } } else { From 33763117ab6b7ad41f935bb81fbf59465a189cb7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 17 Aug 2016 14:42:44 -0700 Subject: [PATCH 4858/5359] Run Behat in strict mode Doing so ensures any undefined steps will fail the build, instead of permitting it to pass --- ci/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index 930f2b4a5..ce5030ef7 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -8,7 +8,7 @@ vendor/bin/phpunit BEHAT_TAGS=$(php ci/behat-tags.php) # Run the functional tests -vendor/bin/behat --format progress $BEHAT_TAGS +vendor/bin/behat --format progress $BEHAT_TAGS --strict # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From eb99f8ddd8dfc7f4baec6eb34d708f58725f2840 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Aug 2016 06:09:34 -0700 Subject: [PATCH 4859/5359] Ensure tables are quoted to support all permitted characters --- php/WP_CLI/Iterators/Table.php | 2 +- php/commands/search-replace.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php index 472129ef8..c05c52ea9 100644 --- a/php/WP_CLI/Iterators/Table.php +++ b/php/WP_CLI/Iterators/Table.php @@ -52,7 +52,7 @@ function __construct( $args = array() ) { $fields = self::build_fields( $args['fields'] ); $conditions = self::build_where_conditions( $args['where'] ); $where_sql = $conditions ? " WHERE $conditions" : ''; - $query = "SELECT $fields FROM $table $where_sql {$args['append']}"; + $query = "SELECT $fields FROM `$table` $where_sql {$args['append']}"; parent::__construct( $query, $args['chunk_size'] ); } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index c8d11293b..ec65691f4 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -346,8 +346,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { $where = $this->regex ? '' : " WHERE `$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ); $primary_keys_sql = esc_sql( implode( ',', $primary_keys ) ); $col_sql = esc_sql( $col ); - $table_sql = esc_sql( $table ); - $rows = $wpdb->get_results( "SELECT {$primary_keys_sql} FROM {$table_sql}{$where}" ); + $rows = $wpdb->get_results( "SELECT {$primary_keys_sql} FROM `{$table}` {$where}" ); foreach ( $rows as $keys ) { $where_sql = ''; foreach( (array) $keys as $k => $v ) { @@ -356,7 +355,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { } $where_sql .= "{$k}='{$v}'"; } - $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM {$table_sql} WHERE {$where_sql}" ); + $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM `{$table}` WHERE {$where_sql}" ); if ( '' === $col_value ) continue; @@ -444,7 +443,7 @@ private static function get_columns( $table ) { global $wpdb; $primary_keys = $text_columns = $all_columns = array(); - foreach ( $wpdb->get_results( "DESCRIBE $table" ) as $col ) { + foreach ( $wpdb->get_results( "DESCRIBE `$table`" ) as $col ) { if ( 'PRI' === $col->Key ) { $primary_keys[] = $col->Field; } From 19695df6dc7e862e20e7cad7c99d816c0778d4f8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Aug 2016 06:21:04 -0700 Subject: [PATCH 4860/5359] Move `wp post (term|meta)` classes to their own files --- php/commands/post-meta.php | 39 ++++++++++++++++++++++++ php/commands/post-term.php | 26 ++++++++++++++++ php/commands/post.php | 61 -------------------------------------- 3 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 php/commands/post-meta.php create mode 100644 php/commands/post-term.php diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php new file mode 100644 index 000000000..868fbb9be --- /dev/null +++ b/php/commands/post-meta.php @@ -0,0 +1,39 @@ +<?php + +/** + * Manage post custom fields. + * + * ## EXAMPLES + * + * # Set post meta + * $ wp post meta set 123 _wp_page_template about.php + * Success: Updated custom field '_wp_page_template'. + * + * # Get post meta + * $ wp post meta get 123 _wp_page_template + * about.php + * + * # Update post meta + * $ wp post meta update 123 _wp_page_template contact.php + * Success: Updated custom field '_wp_page_template'. + * + * # Delete post meta + * $ wp post meta delete 123 _wp_page_template + * Success: Deleted custom field. + */ +class Post_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'post'; + + /** + * Check that the post ID exists + * + * @param int + */ + protected function check_object_id( $object_id ) { + $fetcher = new \WP_CLI\Fetchers\Post; + $post = $fetcher->get_check( $object_id ); + return $post->ID; + } +} + +WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); diff --git a/php/commands/post-term.php b/php/commands/post-term.php new file mode 100644 index 000000000..9c8c8f856 --- /dev/null +++ b/php/commands/post-term.php @@ -0,0 +1,26 @@ +<?php + +/** + * Manage post terms. + * + * ## EXAMPLES + * + * # Set post terms + * $ wp post term set 123 test category + * Set terms. + */ +class Post_Term_Command extends \WP_CLI\CommandWithTerms { + protected $obj_type = 'post'; + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\Post; + } + + protected function get_object_type() { + $post = $this->fetcher->get_check( $this->get_obj_id() ); + + return $post->post_type; + } +} + +WP_CLI::add_command( 'post term', 'Post_Term_Command' ); diff --git a/php/commands/post.php b/php/commands/post.php index 5c04292a2..a6a1410ef 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -592,65 +592,4 @@ private function read_from_file_or_stdin( $arg ) { } } -/** - * Manage post custom fields. - * - * ## EXAMPLES - * - * # Set post meta - * $ wp post meta set 123 _wp_page_template about.php - * Success: Updated custom field '_wp_page_template'. - * - * # Get post meta - * $ wp post meta get 123 _wp_page_template - * about.php - * - * # Update post meta - * $ wp post meta update 123 _wp_page_template contact.php - * Success: Updated custom field '_wp_page_template'. - * - * # Delete post meta - * $ wp post meta delete 123 _wp_page_template - * Success: Deleted custom field. - */ -class Post_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'post'; - - /** - * Check that the post ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $fetcher = new \WP_CLI\Fetchers\Post; - $post = $fetcher->get_check( $object_id ); - return $post->ID; - } -} - -/** - * Manage post terms. - * - * ## EXAMPLES - * - * # Set post terms - * $ wp post term set 123 test category - * Set terms. - */ -class Post_Term_Command extends \WP_CLI\CommandWithTerms { - protected $obj_type = 'post'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\Post; - } - - protected function get_object_type() { - $post = $this->fetcher->get_check( $this->get_obj_id() ); - - return $post->post_type; - } -} - WP_CLI::add_command( 'post', 'Post_Command' ); -WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); -WP_CLI::add_command( 'post term', 'Post_Term_Command' ); From f51fa55bd36852f70b210a043b94c7a8c3beca32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 18 Aug 2016 06:24:47 -0700 Subject: [PATCH 4861/5359] Move `wp user (term|meta)` classes to their own files --- php/commands/user-meta.php | 196 ++++++++++++++++++++++++++++++++++ php/commands/user-term.php | 16 +++ php/commands/user.php | 208 ------------------------------------- 3 files changed, 212 insertions(+), 208 deletions(-) create mode 100644 php/commands/user-meta.php create mode 100644 php/commands/user-term.php diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php new file mode 100644 index 000000000..112ce6b1f --- /dev/null +++ b/php/commands/user-meta.php @@ -0,0 +1,196 @@ +<?php + +/** + * Manage user custom fields. + * + * ## EXAMPLES + * + * # Add user meta + * $ wp user meta add 123 bio "Mary is an WordPress developer." + * Success: Added custom field. + * + * # List user meta + * $ wp user meta list 123 --keys=nickname,description,wp_capabilities + * +---------+-----------------+--------------------------------+ + * | user_id | meta_key | meta_value | + * +---------+-----------------+--------------------------------+ + * | 123 | nickname | supervisor | + * | 123 | description | Mary is a WordPress developer. | + * | 123 | wp_capabilities | {"administrator":true} | + * +---------+-----------------+--------------------------------+ + * + * # Update user meta + * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. + * + * # Delete user meta + * $ wp user meta delete 123 bio + * Success: Deleted custom field. + */ +class User_Meta_Command extends \WP_CLI\CommandWithMeta { + protected $meta_type = 'user'; + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + + /** + * List all metadata associated with a user. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to get metadata for. + * + * [--keys=<keys>] + * : Limit output to metadata of specific keys. + * + * [--fields=<fields>] + * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count. Default: table + * + * ## EXAMPLES + * + * # List user meta + * $ wp user meta list 123 --keys=nickname,description,wp_capabilities + * +---------+-----------------+--------------------------------+ + * | user_id | meta_key | meta_value | + * +---------+-----------------+--------------------------------+ + * | 123 | nickname | supervisor | + * | 123 | description | Mary is a WordPress developer. | + * | 123 | wp_capabilities | {"administrator":true} | + * +---------+-----------------+--------------------------------+ + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::list_( $args, $assoc_args ); + } + + /** + * Get meta field value. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to get metadata for. + * + * <key> + * : The metadata key. + * + * [--format=<format>] + * : Accepted values: table, json, yaml. Default: table + * + * ## EXAMPLES + * + * # Get user meta + * $ wp user meta get 123 bio + * Mary is an WordPress developer. + */ + public function get( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::get( $args, $assoc_args ); + } + + /** + * Delete a meta field. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to delete metadata from. + * + * <key> + * : The metadata key. + * + * [<value>] + * : The value to delete. If omitted, all rows with key will deleted. + * + * ## EXAMPLES + * + * # Delete user meta + * $ wp user meta delete 123 bio + * Success: Deleted custom field. + */ + public function delete( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::delete( $args, $assoc_args ); + } + + /** + * Add a meta field. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to add metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * + * ## EXAMPLES + * + * # Add user meta + * $ wp user meta add 123 bio "Mary is an WordPress developer." + * Success: Added custom field. + */ + public function add( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::add( $args, $assoc_args ); + } + + /** + * Update a meta field. + * + * ## OPTIONS + * + * <user> + * : The user login, user email, or user ID of the user to update metadata for. + * + * <key> + * : The metadata key. + * + * <value> + * : The new metadata value. + * + * [--format=<format>] + * : The serialization format for the value. Default is plaintext. + * + * ## EXAMPLES + * + * # Update user meta + * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." + * Success: Updated custom field 'bio'. + * + * @alias set + */ + public function update( $args, $assoc_args ) { + $args = $this->replace_login_with_user_id( $args ); + parent::update( $args, $assoc_args ); + } + + /** + * Replace user_login value with user ID + * user meta is a special case that also supports user_login + * + * @param array + * @return array + */ + private function replace_login_with_user_id( $args ) { + $user = $this->fetcher->get_check( $args[0] ); + $args[0] = $user->ID; + return $args; + } + +} + +WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); diff --git a/php/commands/user-term.php b/php/commands/user-term.php new file mode 100644 index 000000000..aa59e080c --- /dev/null +++ b/php/commands/user-term.php @@ -0,0 +1,16 @@ +<?php + +/** + * Manage user terms. + * + * ## EXAMPLES + * + * # Set user terms + * $ wp user term set 123 test category + * Set terms. + */ +class User_Term_Command extends \WP_CLI\CommandWithTerms { + protected $obj_type = 'user'; +} + +WP_CLI::add_command( 'user term', 'User_Term_Command' ); diff --git a/php/commands/user.php b/php/commands/user.php index f0c5daa66..c0cc95a20 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -914,212 +914,4 @@ private static function wp_new_user_notification( $user_id, $password ) { } -/** - * Manage user custom fields. - * - * ## EXAMPLES - * - * # Add user meta - * $ wp user meta add 123 bio "Mary is an WordPress developer." - * Success: Added custom field. - * - * # List user meta - * $ wp user meta list 123 --keys=nickname,description,wp_capabilities - * +---------+-----------------+--------------------------------+ - * | user_id | meta_key | meta_value | - * +---------+-----------------+--------------------------------+ - * | 123 | nickname | supervisor | - * | 123 | description | Mary is a WordPress developer. | - * | 123 | wp_capabilities | {"administrator":true} | - * +---------+-----------------+--------------------------------+ - * - * # Update user meta - * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Delete user meta - * $ wp user meta delete 123 bio - * Success: Deleted custom field. - */ -class User_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'user'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * List all metadata associated with a user. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to get metadata for. - * - * [--keys=<keys>] - * : Limit output to metadata of specific keys. - * - * [--fields=<fields>] - * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. - * - * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table - * - * ## EXAMPLES - * - * # List user meta - * $ wp user meta list 123 --keys=nickname,description,wp_capabilities - * +---------+-----------------+--------------------------------+ - * | user_id | meta_key | meta_value | - * +---------+-----------------+--------------------------------+ - * | 123 | nickname | supervisor | - * | 123 | description | Mary is a WordPress developer. | - * | 123 | wp_capabilities | {"administrator":true} | - * +---------+-----------------+--------------------------------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::list_( $args, $assoc_args ); - } - - /** - * Get meta field value. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to get metadata for. - * - * <key> - * : The metadata key. - * - * [--format=<format>] - * : Accepted values: table, json, yaml. Default: table - * - * ## EXAMPLES - * - * # Get user meta - * $ wp user meta get 123 bio - * Mary is an WordPress developer. - */ - public function get( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::get( $args, $assoc_args ); - } - - /** - * Delete a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to delete metadata from. - * - * <key> - * : The metadata key. - * - * [<value>] - * : The value to delete. If omitted, all rows with key will deleted. - * - * ## EXAMPLES - * - * # Delete user meta - * $ wp user meta delete 123 bio - * Success: Deleted custom field. - */ - public function delete( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::delete( $args, $assoc_args ); - } - - /** - * Add a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to add metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * [--format=<format>] - * : The serialization format for the value. Default is plaintext. - * - * ## EXAMPLES - * - * # Add user meta - * $ wp user meta add 123 bio "Mary is an WordPress developer." - * Success: Added custom field. - */ - public function add( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::add( $args, $assoc_args ); - } - - /** - * Update a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to update metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * [--format=<format>] - * : The serialization format for the value. Default is plaintext. - * - * ## EXAMPLES - * - * # Update user meta - * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * @alias set - */ - public function update( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::update( $args, $assoc_args ); - } - - /** - * Replace user_login value with user ID - * user meta is a special case that also supports user_login - * - * @param array - * @return array - */ - private function replace_login_with_user_id( $args ) { - $user = $this->fetcher->get_check( $args[0] ); - $args[0] = $user->ID; - return $args; - } - -} - -/** - * Manage user terms. - * - * ## EXAMPLES - * - * # Set user terms - * $ wp user term set 123 test category - * Set terms. - */ -class User_Term_Command extends \WP_CLI\CommandWithTerms { - protected $obj_type = 'user'; -} - WP_CLI::add_command( 'user', 'User_Command' ); -WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); -WP_CLI::add_command( 'user term', 'User_Term_Command' ); From df0995ed2d442efdfebd532f340979e7200c6730 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 18 Aug 2016 22:46:04 +0545 Subject: [PATCH 4862/5359] Improving doc in taxonomy commands --- php/commands/taxonomy.php | 57 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index 3abcba920..2608120b0 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -4,7 +4,7 @@ * * ## EXAMPLES * - * # List all taxonomies with 'post' object type + * # List all taxonomies with 'post' object type. * $ wp taxonomy list --object_type=post --fields=name,public * +-------------+--------+ * | name | public | @@ -14,7 +14,7 @@ * | post_format | 1 | * +-------------+--------+ * - * # Get capabilities of a taxonomy + * # Get capabilities of 'post_tag' taxonomy. * $ wp taxonomy get post_tag --field=cap * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} * @@ -45,6 +45,8 @@ public function __construct() { /** * List taxonomies. * + * Displays list of registered taxonomies. + * * ## OPTIONS * * [--<field>=<value>] @@ -82,7 +84,7 @@ public function __construct() { * * ## EXAMPLES * - * # List all taxonomies + * # List all taxonomies. * $ wp taxonomy list --format=csv * name,label,description,object_type,show_tagcloud,hierarchical,public * category,Categories,,post,1,1,1 @@ -91,7 +93,7 @@ public function __construct() { * link_category,"Link Categories",,link,1,, * post_format,Format,,post,,,1 * - * # List all taxonomies with 'post' object type + * # List all taxonomies with 'post' object type. * $ wp taxonomy list --object_type=post --fields=name,public * +-------------+--------+ * | name | public | @@ -121,12 +123,14 @@ public function list_( $args, $assoc_args ) { } /** - * Get a taxonomy + * Get a taxonomy. + * + * Displays detail of the taxonomy. * * ## OPTIONS * * <taxonomy> - * : Taxonomy slug + * : Taxonomy slug. * * [--field=<field>] * : Instead of returning the whole taxonomy, returns the value of a single field. @@ -147,36 +151,17 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * $ wp taxonomy get category - * +---------------+---------------------------------------------------+ - * | Field | Value | - * +---------------+---------------------------------------------------+ - * | name | category | - * | label | Categories | - * | description | | - * | object_type | ["post"] | - * | show_tagcloud | true | - * | hierarchical | true | - * | public | true | - * | labels | {"name":"Categories","singular_name":"Category"," | - * | | search_items":"Search Categories","popular_items" | - * | | :null,"all_items":"All Categories","parent_item": | - * | | "Parent Category","parent_item_colon":"Parent Cat | - * | | egory:","edit_item":"Edit Category","view_item":" | - * | | View Category","update_item":"Update Category","a | - * | | dd_new_item":"Add New Category","new_item_name":" | - * | | New Category Name","separate_items_with_commas":n | - * | | ull,"add_or_remove_items":null,"choose_from_most_ | - * | | used":null,"not_found":"No categories found.","no | - * | | _terms":"No categories","items_list_navigation":" | - * | | Categories list navigation","items_list":"Categor | - * | | ies list","menu_name":"Categories","name_admin_ba | - * | | r":"category"} | - * | cap | {"manage_terms":"manage_categories","edit_terms": | - * | | "manage_categories","delete_terms":"manage_catego | - * | | ries","assign_terms":"edit_posts"} | - * +---------------+---------------------------------------------------+ - * + * # Get details of `category` taxonomy. + * $ wp taxonomy get category --fields=name,label,object_type + * +-------------+------------+ + * | Field | Value | + * +-------------+------------+ + * | name | category | + * | label | Categories | + * | object_type | ["post"] | + * +-------------+------------+ + * + * # Get capabilities of 'post_tag' taxonomy. * $ wp taxonomy get post_tag --field=cap * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} */ From e3dc17050a82dc4553d8eb09e6381cc270ef8a62 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 07:03:54 -0700 Subject: [PATCH 4863/5359] Remove StackExchange mention because it's being misused --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf7c6ab06..7a70fd787 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ WP-CLI's maintainers and project contributors are volunteers, and have limited a - [runcommand Excerpts](https://runcommand.io/excerpts/) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) -If you can't find your answer at one of those links, the [WordPress StackExchange](http://wordpress.stackexchange.com/) can be used for development-related WP-CLI questions. Or, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand](https://runcommand.io/) for premium support. +If you can't find your answer at one of those links, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand](https://runcommand.io/) for premium support. For bug reports, please review [best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) before [creating a new issue](https://github.com/wp-cli/wp-cli/issues/new). From e54c4e2b11705d7c85455249ccc58c9132c571da Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 12:12:33 -0700 Subject: [PATCH 4864/5359] Support passing custom `.ini` file when launching the server --- php/commands/server.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index c05ba5bac..a2285045b 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -37,6 +37,9 @@ class Server_Command extends WP_CLI_Command { * [--docroot=<path>] * : The path to use as the document root. * + * [--config=<file>] + * : Configure the server with a specific .ini file. + * * ## EXAMPLES * * # Make the instance available on any address (with port 8080) @@ -53,6 +56,13 @@ class Server_Command extends WP_CLI_Command { * Document root is / * Press Ctrl-C to quit. * + * # Configure the server with a specific .ini file + * $ wp server --config=development.ini + * PHP 7.0.9 Development Server started at Mon Aug 22 12:09:04 2016 + * Listening on http://localhost:8080 + * Document root is / + * Press Ctrl-C to quit. + * * @when before_wp_load */ function __invoke( $_, $assoc_args ) { @@ -64,7 +74,8 @@ function __invoke( $_, $assoc_args ) { $defaults = array( 'host' => 'localhost', 'port' => 8080, - 'docroot' => false + 'docroot' => false, + 'config' => false, ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -80,10 +91,11 @@ function __invoke( $_, $assoc_args ) { } } - $cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s %s', + $cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s -c %s %s', PHP_BINARY, $assoc_args['host'] . ':' . $assoc_args['port'], $docroot, + $assoc_args['config'], \WP_CLI\Utils\extract_from_phar( WP_CLI_ROOT . '/php/router.php' ) ); From 162962ea2b42a4c585ba01fbcb2e4fe0a8809cfc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 13:16:26 -0700 Subject: [PATCH 4865/5359] Prevent email notifications when users are created Email notifications should only be sent when `--send-email` is provided. --- features/bootstrap/support.php | 6 ++++++ features/extra/no-mail.php | 5 +++-- features/steps/then.php | 9 +++++++++ features/steps/when.php | 8 ++++++++ features/user.feature | 9 +++++++++ php/commands/user.php | 5 +++++ 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index d5cc221e4..75ee5fbd3 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -8,6 +8,12 @@ function assertEquals( $expected, $actual ) { } } +function assertNotEquals( $expected, $actual ) { + if ( $expected == $actual ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + function assertNumeric( $actual ) { if ( !is_numeric( $actual ) ) { throw new Exception( "Actual value: " . var_export( $actual, true ) ); diff --git a/features/extra/no-mail.php b/features/extra/no-mail.php index ba222ad59..de7a42272 100644 --- a/features/extra/no-mail.php +++ b/features/extra/no-mail.php @@ -1,6 +1,7 @@ <?php -function wp_mail() { - // do nothing +function wp_mail( $to ) { + // Log for testing purposes + WP_CLI::log( "WP-CLI test suite: Sent email to {$to}." ); } diff --git a/features/steps/then.php b/features/steps/then.php index f2889f5bf..d1df934e4 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -190,3 +190,12 @@ function ( $world, $path, $type, $action, $expected = null ) { } ); +$steps->Then( '/^an email should (be sent|not be sent)$/', function( $world, $expected ) { + if ( 'be sent' === $expected ) { + assertNotEquals( 0, $world->email_sends ); + } else if ( 'not be sent' === $expected ) { + assertEquals( 0, $world->email_sends ); + } else { + throw new Exception( 'Invalid expectation' ); + } +}); diff --git a/features/steps/when.php b/features/steps/when.php index b0832493e..afe3f7a0d 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -14,6 +14,11 @@ function invoke_proc( $proc, $mode ) { return $proc->$method(); } +function capture_email_sends( $stdout ) { + $stdout = preg_replace( '#WP-CLI test suite: Sent email to.+\n?#', '', $stdout, -1, $email_sends ); + return array( $stdout, $email_sends ); +} + $steps->When( '/^I launch in the background `([^`]+)`$/', function ( $world, $cmd ) { $world->background_proc( $cmd ); @@ -24,6 +29,7 @@ function ( $world, $cmd ) { function ( $world, $mode, $cmd ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd ), $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); @@ -31,6 +37,7 @@ function ( $world, $mode, $cmd ) { function ( $world, $mode, $cmd, $subdir ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd, array(), $subdir ), $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); @@ -41,6 +48,7 @@ function ( $world, $mode ) { $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); $world->result = invoke_proc( $proc, $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); diff --git a/features/user.feature b/features/user.feature index e1b3fab15..750da9e38 100644 --- a/features/user.feature +++ b/features/user.feature @@ -286,3 +286,12 @@ Feature: Manage WordPress users """ My\New\User """ + + Scenario: Don't send user creation emails by default + Given a WP multisite install + + When I run `wp user create testuser2 testuser2@example.com` + Then an email should not be sent + + When I run `wp user create testuser3 testuser3@example.com --send-email` + Then an email should be sent diff --git a/php/commands/user.php b/php/commands/user.php index c0cc95a20..967f486af 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -328,6 +328,11 @@ public function create( $args, $assoc_args ) { $user->role = \WP_CLI\Utils\get_flag_value( $assoc_args, 'role', get_option('default_role') ); self::validate_role( $user->role ); + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { + add_filter( 'send_password_change_email', '__return_false' ); + add_filter( 'send_email_change_email', '__return_false' ); + } + if ( is_multisite() ) { $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { From 3ce2409f8de98292df14d27cccaddcaac3e1a9a8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 13:31:23 -0700 Subject: [PATCH 4866/5359] Use a less precise check `mysqlcheck` apparently doesn't output when STDOUT is piped --- features/db-check.feature | 11 +++++++++++ features/db.feature | 18 ------------------ 2 files changed, 11 insertions(+), 18 deletions(-) create mode 100644 features/db-check.feature diff --git a/features/db-check.feature b/features/db-check.feature new file mode 100644 index 000000000..d4b59c084 --- /dev/null +++ b/features/db-check.feature @@ -0,0 +1,11 @@ +Feature: Check the database + + Scenario: Run db check to check the database + Given a WP install + + When I run `wp db check` + Then STDOUT should contain: + """ + Success: Database checked. + """ + And STDERR should be empty diff --git a/features/db.feature b/features/db.feature index dc520222e..338cdc935 100644 --- a/features/db.feature +++ b/features/db.feature @@ -21,24 +21,6 @@ Feature: Perform database operations When I try the previous command again Then the return code should be 1 - When I run `wp db check` - Then STDOUT should be: - """ - wp_cli_test.wp_commentmeta OK - wp_cli_test.wp_comments OK - wp_cli_test.wp_links OK - wp_cli_test.wp_options OK - wp_cli_test.wp_postmeta OK - wp_cli_test.wp_posts OK - wp_cli_test.wp_term_relationships OK - wp_cli_test.wp_term_taxonomy OK - wp_cli_test.wp_termmeta OK - wp_cli_test.wp_terms OK - wp_cli_test.wp_usermeta OK - wp_cli_test.wp_users OK - Success: Database checked. - """ - When I run `wp db optimize` Then STDOUT should not be empty From 0785cdb48f391555d429a8af292373a23070bf8b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 14:17:31 -0700 Subject: [PATCH 4867/5359] Clarify the role of Github issues --- .github/ISSUE_TEMPLATE | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index d255d8f7a..cb4e8a83a 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -2,7 +2,7 @@ Thanks for taking the time to help improve WP-CLI! -Found a bug or want to suggest an enhancement? Before submitting an issue, please review our best practices: http://wp-cli.org/docs/bug-reports/ +Found a bug or want to suggest an enhancement to an existing command? Before creating an issue, please review our best practices: http://wp-cli.org/docs/bug-reports/ Need help with something? Github issues aren't for general support questions, but there are other venues you can try: http://wp-cli.org/#support diff --git a/README.md b/README.md index 7a70fd787..85d3be575 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ WP-CLI's maintainers and project contributors are volunteers, and have limited a If you can't find your answer at one of those links, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand](https://runcommand.io/) for premium support. -For bug reports, please review [best practices for submitting a bug report](https://wp-cli.org/docs/bug-reports/) before [creating a new issue](https://github.com/wp-cli/wp-cli/issues/new). +Github issues are meant for tracking enhancements and bugs of existing commands, not general support. Before submitting a bug report, please [review our best practices](https://wp-cli.org/docs/bug-reports/) to help ensure your issue is addressed in a timely manner. Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. From d6870493f6d26a9b0c66c84697025bc31dee3c81 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 14:23:51 -0700 Subject: [PATCH 4868/5359] Check that a particular table was rendered --- features/db-check.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/db-check.feature b/features/db-check.feature index d4b59c084..036dbf363 100644 --- a/features/db-check.feature +++ b/features/db-check.feature @@ -5,6 +5,10 @@ Feature: Check the database When I run `wp db check` Then STDOUT should contain: + """ + wp_cli_test.wp_users + """ + And STDOUT should contain: """ Success: Database checked. """ From 1a691f137d4e5ddb2cd6a9c1e37645b65a7a075a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 23 Aug 2016 01:11:37 +0200 Subject: [PATCH 4869/5359] DB Operations tests We were playing with an empty database. --- features/db.feature | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/db.feature b/features/db.feature index 338cdc935..d8aac1ed8 100644 --- a/features/db.feature +++ b/features/db.feature @@ -21,6 +21,9 @@ Feature: Perform database operations When I try the previous command again Then the return code should be 1 + Scenario: DB Operations + Given a WP install + When I run `wp db optimize` Then STDOUT should not be empty From d653923dcf6da9ac3ad0f7ec2baf00a6c1577d44 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 16:32:41 -0700 Subject: [PATCH 4870/5359] Add testcase for adding meta with JSON-formatted input --- features/comment-meta.feature | 22 ++++++++++++++++++++++ php/WP_CLI/CommandWithMeta.php | 16 ++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/features/comment-meta.feature b/features/comment-meta.feature index f1bb0abf3..12f459211 100644 --- a/features/comment-meta.feature +++ b/features/comment-meta.feature @@ -32,3 +32,25 @@ Feature: Manage comment custom fields When I try `wp comment-meta get 1 foo` Then the return code should be 1 + + Scenario: Add comment meta with JSON serialization + Given a WP install + + When I try `wp comment meta add 1 foo '-- hi'` + Then STDERR should be: + """ + Error: Parameter errors: + unknown -- hi parameter + """ + + When I run `wp comment meta add 1 foo '"-- hi"' --format=json` + Then STDOUT should contain: + """ + Success: + """ + + When I run `wp comment meta get 1 foo` + Then STDOUT should be: + """ + -- hi + """ diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 26c717c20..05746d005 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -169,7 +169,13 @@ public function delete( $args, $assoc_args ) { * : The value of the meta field. If ommited, the value is read from STDIN. * * [--format=<format>] - * : The serialization format for the value. Default is plaintext. + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- */ public function add( $args, $assoc_args ) { list( $object_id, $meta_key ) = $args; @@ -204,7 +210,13 @@ public function add( $args, $assoc_args ) { * : The new value. If ommited, the value is read from STDIN. * * [--format=<format>] - * : The serialization format for the value. Default is plaintext. + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- * * @alias set */ From bf704699f82fc0130e214ff5e37c8ddf029133a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 22 Aug 2016 16:51:39 -0700 Subject: [PATCH 4871/5359] Pass extra arguments through, a la `wp db export` --- features/db.feature | 10 ++++++++++ php/commands/db.php | 15 +++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/features/db.feature b/features/db.feature index 338cdc935..5f8d03c33 100644 --- a/features/db.feature +++ b/features/db.feature @@ -46,6 +46,16 @@ Feature: Perform database operations total """ + When I run `wp db query 'SELECT * FROM wp_options WHERE option_name="home"' --skip-column-names` + Then STDOUT should not contain: + """ + option_name + """ + And STDOUT should contain: + """ + home + """ + Scenario: DB export/import Given a WP install diff --git a/php/commands/db.php b/php/commands/db.php index 9ca85213a..a5efc0f1e 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -168,6 +168,9 @@ public function cli() { * [<sql>] * : A SQL query. If not passed, will try to read from STDIN. * + * [--<field>=<value>] + * : Extra arguments to pass to mysql. + * * ## EXAMPLES * * # Execute a query stored in a file @@ -191,11 +194,15 @@ public function cli() { * | wordpress_dbase.wp_termmeta | check | status | OK | * | wordpress_dbase.wp_commentmeta | check | status | OK | * +---------------------------------------+-------+----------+----------+ + * + * # Pass extra arguments through to MySQL + * $ wp db query 'SELECT * FROM wp_options WHERE option_name="home"' --skip-column-names + * +---+------+------------------------------+-----+ + * | 2 | home | http://wordpress-develop.dev | yes | + * +---+------+------------------------------+-----+ */ - public function query( $args ) { - $assoc_args = array( - 'database' => DB_NAME - ); + public function query( $args, $assoc_args ) { + $assoc_args['database'] = DB_NAME; // The query might come from STDIN if ( !empty( $args ) ) { From 3510d435ba80f046f6bbd501171adce775024b10 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 05:51:43 -0700 Subject: [PATCH 4872/5359] Consistent documentation for the `--format=<format>` argument --- php/commands/db.php | 8 +++++++- php/commands/post.php | 2 +- php/commands/theme.php | 32 +++++++++++++++++++++++++++++--- php/commands/user-meta.php | 21 +++++++++++++++++++-- php/commands/user.php | 22 ++++++++++++++++++++-- 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index c49950e4d..6ffd23435 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -389,7 +389,13 @@ public function import( $args, $assoc_args ) { * : List all tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --all-tables-with-prefix. * * [--format=<format>] - * : Accepted values: list, csv. Default: list + * : Render output in a particular format. + * --- + * default: list + * options: + * - list + * - csv + * --- * * ## EXAMPLES * diff --git a/php/commands/post.php b/php/commands/post.php index a6a1410ef..96e1ee81f 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -280,7 +280,7 @@ public function delete( $args, $assoc_args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, ids, yaml. Default: table + * : Render output in a particular format. * --- * default: table * options: diff --git a/php/commands/theme.php b/php/commands/theme.php index 176fe2d94..d6703462a 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -120,7 +120,16 @@ function status( $args ) { * **description**: Theme Description * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## EXAMPLES * @@ -511,7 +520,15 @@ function install( $args, $assoc_args ) { * : Limit the output to specific fields. Defaults to all fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * @@ -692,7 +709,16 @@ function delete( $args ) { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php index 112ce6b1f..fbc4e666c 100644 --- a/php/commands/user-meta.php +++ b/php/commands/user-meta.php @@ -49,7 +49,16 @@ public function __construct() { * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. * * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - count + * - yaml + * --- * * ## EXAMPLES * @@ -82,7 +91,15 @@ public function list_( $args, $assoc_args ) { * : The metadata key. * * [--format=<format>] - * : Accepted values: table, json, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * diff --git a/php/commands/user.php b/php/commands/user.php index 967f486af..79df0a05e 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -65,7 +65,17 @@ public function __construct() { * : Limit the output to specific object fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - ids + * - json + * - count + * - yaml + * --- * * ## AVAILABLE FIELDS * @@ -168,7 +178,15 @@ public function list_( $args, $assoc_args ) { * : Get a specific subset of the user's fields. * * [--format=<format>] - * : Accepted values: table, json, csv, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * --- * * ## EXAMPLES * From 3456ac97ebbfffb22bc499bf32f0f08108627523 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 06:07:16 -0700 Subject: [PATCH 4873/5359] Remove erroneous `## OPTIONS` from comment meta --- php/commands/comment-meta.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/php/commands/comment-meta.php b/php/commands/comment-meta.php index 929c684f0..f16853124 100644 --- a/php/commands/comment-meta.php +++ b/php/commands/comment-meta.php @@ -3,11 +3,6 @@ /** * Manage comment custom fields. * - * ## OPTIONS - * - * --format=json - * : Encode/decode values as JSON. - * * ## EXAMPLES * * # Set comment meta From 7a99e4f19ea583a3b3b7c7b648594e1b98ddc4a5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 10:29:37 -0700 Subject: [PATCH 4874/5359] Ensure `--format=<format>` only affects the format --- features/db-table.feature | 2 +- php/commands/db.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/features/db-table.feature b/features/db-table.feature index 8c8ab1bc0..7e83de05c 100644 --- a/features/db-table.feature +++ b/features/db-table.feature @@ -21,7 +21,7 @@ Feature: List database tables When I run `wp db tables --format=csv` Then STDOUT should contain: """ - wp_terms,wp_usermeta,wp_users + wp_users,wp_usermeta,wp_posts,wp_comments, """ When I run `wp db tables 'wp_post*' --format=csv` diff --git a/php/commands/db.php b/php/commands/db.php index 6ffd23435..465b0f316 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -405,13 +405,16 @@ public function import( $args, $assoc_args ) { */ function tables( $args, $assoc_args ) { + $format = WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ); + unset( $assoc_args['format'] ); + if ( empty( $args ) && empty( $assoc_args ) ) { $assoc_args['scope'] = 'all'; } $tables = WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); - if ( ! empty( $assoc_args['format'] ) && 'csv' === $assoc_args['format'] ) { + if ( 'csv' === $format ) { WP_CLI::line( implode( ',', $tables ) ); } else { foreach ( $tables as $table ) { From 86645fc0447f77bc7d08ee4df7b85d9539169f8d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 10:30:03 -0700 Subject: [PATCH 4875/5359] Rename feature file to match command name --- features/{db-table.feature => db-tables.feature} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename features/{db-table.feature => db-tables.feature} (100%) diff --git a/features/db-table.feature b/features/db-tables.feature similarity index 100% rename from features/db-table.feature rename to features/db-tables.feature From ded13b86bb0be4dbc1a327d87cc982b5db8019d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 13:29:33 -0700 Subject: [PATCH 4876/5359] Test installation against package with dependency --- features/package-install.feature | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/features/package-install.feature b/features/package-install.feature index aad733af0..c7b4803e0 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -60,3 +60,28 @@ Feature: Install WP-CLI packages """ Site Information """ + + @require-php-5.6 + Scenario: Install a package with a dependency + Given an empty directory + + When I run `wp package path` + Then save STDOUT as {PACKAGE_PATH} + + When I run `wp package install trendwerk/faker` + Then STDOUT should contain: + """ + Error: trendwerk/faker dev-master requires nelmio/alice + """ + And STDOUT should contain: + """ + Success: Package installed + """ + And the {PACKAGE_PATH}/vendor/trendwerk directory should contain: + """ + faker + """ + And the {PACKAGE_PATH}/vendor/nelmio directory should contain: + """ + alice + """ From c0f69d6476a8b86f21dd8096d0630d5dd1cb4eff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 13:29:47 -0700 Subject: [PATCH 4877/5359] Ensure WP-CLI package dir is cleaned up between tests --- features/bootstrap/FeatureContext.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 4886aa75a..350fc4cba 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -119,6 +119,11 @@ public function afterScenario( $event ) { } } + // Remove WP-CLI package directory + if ( isset( $this->variables['PACKAGE_PATH'] ) ) { + $this->proc( Utils\esc_cmd( 'rm -rf %s', $this->variables['PACKAGE_PATH'] ) )->run(); + } + foreach ( $this->running_procs as $proc ) { self::terminate_proc( $proc ); } From ac1b29e2125bd3981ce7fcfc07b3c9eb312258fe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 16:52:44 -0700 Subject: [PATCH 4878/5359] Failing test case for #3327 --- features/package-install.feature | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/features/package-install.feature b/features/package-install.feature index c7b4803e0..64cfc269e 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -85,3 +85,21 @@ Feature: Install WP-CLI packages """ alice """ + + When I run `wp package uninstall trendwerk/faker` + Then STDOUT should contain: + """ + Removing require statement + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + And the {PACKAGE_PATH}/vendor/trendwerk directory should not contain: + """ + faker + """ + And the {PACKAGE_PATH}/vendor/nelmio directory should not contain: + """ + alice + """ From c7ec71cf736b84e85052534faea7aaa002680f32 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 23 Aug 2016 17:01:53 -0700 Subject: [PATCH 4879/5359] Use the installer to uninstall, to ensure dependencies are removed accordingly --- features/package-install.feature | 18 +++++++++++--- php/commands/package.php | 42 ++++++++++++++------------------ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 64cfc269e..a2bcbbec7 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -86,6 +86,12 @@ Feature: Install WP-CLI packages alice """ + When I run `wp package list` + Then STDOUT should contain: + """ + trendwerk/faker + """ + When I run `wp package uninstall trendwerk/faker` Then STDOUT should contain: """ @@ -95,11 +101,17 @@ Feature: Install WP-CLI packages """ Success: Uninstalled package. """ - And the {PACKAGE_PATH}/vendor/trendwerk directory should not contain: + And the {PACKAGE_PATH}/vendor directory should not contain: """ - faker + trendwerk """ - And the {PACKAGE_PATH}/vendor/nelmio directory should not contain: + And the {PACKAGE_PATH}/vendor directory should not contain: """ alice """ + + When I run `wp package list` + Then STDOUT should not contain: + """ + trendwerk/faker + """ diff --git a/php/commands/package.php b/php/commands/package.php index b281f7ecd..1a03f1c3b 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -327,23 +327,30 @@ public function uninstall( $args ) { $manipulator->removeSubNode( 'require', $package_name ); file_put_contents( $composer_json_obj->getPath(), $manipulator->getContents() ); - // Delete the directory - $package_path = $composer->getConfig()->get( 'vendor-dir' ) . '/' . $package->getName(); - WP_CLI::log( sprintf( 'Deleting package directory %s', $package_path ) ); - $filesystem = new Filesystem; - $filesystem->removeDirectory( $package_path ); - - // Reset Composer and regenerate the auto-loader - WP_CLI::log( 'Regenerating Composer autoload.' ); try { $composer = $this->get_composer(); } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + // Set up the installer + $install = Installer::create( new NullIO, $composer ); + $install->setUpdate( true ); // Installer class will only override composer.lock with this flag + $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. + + WP_CLI::log( 'Removing package directories and regenerating autoloader...' ); + try { + $res = $install->run(); + } catch ( Exception $e ) { WP_CLI::warning( $e->getMessage() ); - WP_CLI::error( 'Composer autoload will need to be manually regenerated.' ); } - $this->regenerate_autoloader( $composer ); - WP_CLI::success( "Uninstalled package." ); + if ( 0 === $res ) { + WP_CLI::success( "Uninstalled package." ); + } else { + file_put_contents( $composer_json_obj->getPath(), $composer_backup ); + WP_CLI::error( "Package removal failed (Composer return code {$res})." ); + } } /** @@ -604,19 +611,6 @@ private function create_default_composer_json( $composer_path ) { return true; } - - /** - * Regenerate the Composer autoloader - */ - private function regenerate_autoloader( $composer ) { - $composer->getAutoloadGenerator()->dump( - $composer->getConfig(), - $composer->getRepositoryManager()->getLocalRepository(), - $composer->getPackage(), - $composer->getInstallationManager(), - 'composer' - ); - } } WP_CLI::add_command( 'package', 'Package_Command' ); From f38bb00bb479975bb53e031802b5b1f8ac726b76 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 24 Aug 2016 10:08:38 -0700 Subject: [PATCH 4880/5359] Ensure `wp core update-db --network --dry-run` is actually dry Updates messaging to ensure the message reflects whether or not `--dry-run` has been provided. --- features/core-update-db.feature | 12 +++++++++++- php/commands/core.php | 11 +++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 73a3b6862..88b48b7ce 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -26,7 +26,7 @@ Feature: Update core's database Then STDOUT should be: """ Performing a dry run, with no database modification. - Success: WordPress database upgraded successfully from db version 29630 to 30133. + Success: WordPress database will be upgraded from db version 29630 to 30133. """ When I run `wp option get db_version` @@ -57,6 +57,8 @@ Feature: Update core's database Scenario: Update db across network Given a WP multisite install + And I run `wp core download --version=4.1 --force` + And I run `wp option update db_version 29630` And I run `wp site create --slug=foo` And I run `wp site create --slug=bar` And I run `wp site create --slug=burrito --porcelain` @@ -74,6 +76,14 @@ Feature: Update core's database """ Performing a dry run, with no database modification. """ + And STDOUT should contain: + """ + WordPress database will be upgraded from db version + """ + And STDOUT should not contain: + """ + WordPress database upgraded successfully from db version + """ And STDOUT should contain: """ Success: WordPress database upgraded on 3/3 sites. diff --git a/php/commands/core.php b/php/commands/core.php index 250bb3e20..7568c2683 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1398,11 +1398,12 @@ function update_db( $_, $assoc_args ) { foreach( $it as $blog ) { $total++; $url = $blog->domain . $blog->path; - $process = WP_CLI::launch_self( 'core update-db', array(), array(), false, true, array( 'url' => $url, 'dry-run' => $dry_run ) ); + $process = WP_CLI::launch_self( 'core update-db', array(), array( 'dry-run' => $dry_run ), false, true, array( 'url' => $url ) ); if ( 0 == $process->return_code ) { // See if we can parse the stdout if ( preg_match( '#Success: (.+)#', $process->stdout, $matches ) ) { - $message = "{$matches[1]} on {$url}"; + $message = rtrim( $matches[1], '.' ); + $message = "{$message} on {$url}"; } else { $message = "Database upgraded successfully on {$url}"; } @@ -1420,10 +1421,12 @@ function update_db( $_, $assoc_args ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); $wp_current_db_version = __get_option( 'db_version' ); if ( $wp_db_version != $wp_current_db_version ) { - if ( ! $dry_run ) { + if ( $dry_run ) { + WP_CLI::success( "WordPress database will be upgraded from db version {$wp_current_db_version} to {$wp_db_version}." ); + } else { wp_upgrade(); + WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}." ); } - WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}." ); } else { WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}." ); } From f034ee707b5eabfe16afd6556ea2785115a1e868 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 29 Aug 2016 12:13:59 -0700 Subject: [PATCH 4881/5359] Fix error notice when `export_insert_size` isn't defined --- php/commands/search-replace.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ec65691f4..fe7ad99c9 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -170,11 +170,9 @@ public function __invoke( $args, $assoc_args ) { WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); } } - $export_insert_size = $assoc_args['export_insert_size']; + $export_insert_size = WP_CLI\Utils\get_flag_value( $assoc_args, 'export_insert_size', 50 ); if ( (int) $export_insert_size == $export_insert_size && $export_insert_size > 0 ) { $this->export_insert_size = $export_insert_size; - } else { - $this->export_insert_size = 50; } $php_only = true; } From da0a7a392da1e7508d7fd4805d91d048d3bf0400 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 29 Aug 2016 15:43:49 -0700 Subject: [PATCH 4882/5359] Hack in `rmccue/requests` at latest to address a breaking build WordPress trunk is dependent on features that haven't yet been formally released. --- composer.json | 2 +- composer.lock | 29 +++++++++++++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 8b2590b79..a917e9ffd 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", "ramsey/array_column": "~1.1", - "rmccue/requests": "~1.6", + "rmccue/requests" : "dev-master#fb5b51797ff881dd67f630cf9fd9e14b757a9e29 as 1.6.1", "symfony/finder": "~2.7", "symfony/yaml": "~2.7", "symfony/filesystem": "~2.7", diff --git a/composer.lock b/composer.lock index ede24ebab..2a4ab1c38 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "f0bf52c59aa6e9fe44d6a611f8006a52", - "content-hash": "10cf19699e3fed767e31e1493a07c8f0", + "hash": "6b2d9b856fd8d57162cccfed52b37977", + "content-hash": "48b37e62541cbdceec19bf202c77a9d1", "packages": [ { "name": "composer/ca-bundle", @@ -549,23 +549,23 @@ }, { "name": "rmccue/requests", - "version": "v1.6.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/rmccue/Requests.git", - "reference": "6aac485666c2955077d77b796bbdd25f0013a4ea" + "reference": "fb5b51797ff881dd67f630cf9fd9e14b757a9e29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rmccue/Requests/zipball/6aac485666c2955077d77b796bbdd25f0013a4ea", - "reference": "6aac485666c2955077d77b796bbdd25f0013a4ea", + "url": "https://api.github.com/repos/rmccue/Requests/zipball/fb5b51797ff881dd67f630cf9fd9e14b757a9e29", + "reference": "fb5b51797ff881dd67f630cf9fd9e14b757a9e29", "shasum": "" }, "require": { "php": ">=5.2" }, "require-dev": { - "satooshi/php-coveralls": "dev-master" + "requests/test-server": "dev-master" }, "type": "library", "autoload": { @@ -594,7 +594,7 @@ "iri", "sockets" ], - "time": "2014-05-18 04:59:02" + "time": "2016-08-18 01:24:21" }, { "name": "seld/cli-prompt", @@ -1830,9 +1830,18 @@ "time": "2013-01-13 10:24:48" } ], - "aliases": [], + "aliases": [ + { + "alias": "1.6.1", + "alias_normalized": "1.6.1.0", + "version": "9999999-dev", + "package": "rmccue/requests" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "rmccue/requests": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From f93e9c0d41b13eb0ac906a082c788c2b0ab2ea06 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 30 Aug 2016 08:39:40 -0700 Subject: [PATCH 4883/5359] Use PHP version specific to Trusty Circle is using Trusty by default on new projects --- templates/plugin-circle.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache index 6f1ded776..da9dba685 100644 --- a/templates/plugin-circle.mustache +++ b/templates/plugin-circle.mustache @@ -1,6 +1,6 @@ machine: php: - version: 5.6.14 + version: 5.6.22 test: pre: From e7095a32b520ba49631fa984b0c4c8318f4118e8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 30 Aug 2016 09:07:49 -0700 Subject: [PATCH 4884/5359] Ensure Subversion is installed as well; no longer available by default --- templates/plugin-circle.mustache | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache index da9dba685..75c0aebcb 100644 --- a/templates/plugin-circle.mustache +++ b/templates/plugin-circle.mustache @@ -2,6 +2,10 @@ machine: php: version: 5.6.22 +dependencies: + pre: + - sudo apt-get update; sudo apt-get install subversion + test: pre: - bash bin/install-wp-tests.sh wordpress_test root '' localhost latest From dc31088b9b0f6aa3cd22afa8f2f04ce9743463b1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 30 Aug 2016 10:32:38 -0700 Subject: [PATCH 4885/5359] Update PHP version in test --- features/scaffold.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 81148c221..102c866bd 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -331,7 +331,7 @@ Feature: WordPress code scaffolding And the {PLUGIN_DIR}/.travis.yml file should not exist And the {PLUGIN_DIR}/circle.yml file should contain: """ - version: 5.6.14 + version: 5.6.22 """ Scenario: Scaffold plugin tests with Gitlab as the provider From c2e386f1b181a23615278c25804304252b0eb232 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 1 Sep 2016 14:55:33 +0545 Subject: [PATCH 4886/5359] Display alias in man page --- php/commands/help.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/help.php b/php/commands/help.php index d07b2802c..73a2ee335 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -58,6 +58,12 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); + $alias = $command->get_alias(); + if ( $alias ) { + $out .= '## ALIAS' . PHP_EOL . PHP_EOL; + $out .= ' ' . $alias . PHP_EOL . PHP_EOL; + } + $longdesc = $command->get_longdesc(); if ( $longdesc ) { $out .= wordwrap( $longdesc, 90 ) . "\n"; From 3740f5ca5656c7fb5ae940adeab31b97fae830af Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 1 Sep 2016 21:17:02 +0545 Subject: [PATCH 4887/5359] Use mustache template to show alias --- php/commands/help.php | 11 +++++------ templates/man.mustache | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 73a2ee335..339f82fbd 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -58,12 +58,6 @@ private static function find_subcommand( $args ) { private static function show_help( $command ) { $out = self::get_initial_markdown( $command ); - $alias = $command->get_alias(); - if ( $alias ) { - $out .= '## ALIAS' . PHP_EOL . PHP_EOL; - $out .= ' ' . $alias . PHP_EOL . PHP_EOL; - } - $longdesc = $command->get_longdesc(); if ( $longdesc ) { $out .= wordwrap( $longdesc, 90 ) . "\n"; @@ -127,6 +121,11 @@ private static function get_initial_markdown( $command ) { $binding['synopsis'] = wordwrap( "$name " . $command->get_synopsis(), 79 ); + $alias = $command->get_alias(); + if ( $alias ) { + $binding['has-alias']['alias'] = $alias; + } + if ( $command->can_have_subcommands() ) { $binding['has-subcommands']['subcommands'] = self::render_subcommands( $command ); } diff --git a/templates/man.mustache b/templates/man.mustache index ea1ec7b93..934b21f1b 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -12,6 +12,12 @@ {{synopsis}} +{{#has-alias}} +## ALIAS + + {{alias}} + +{{/has-alias}} {{#has-subcommands}} ## SUBCOMMANDS From 821834513b78734711c44e45199c87ce946bddbe Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer <balbuf@users.noreply.github.com> Date: Thu, 1 Sep 2016 16:23:26 -0400 Subject: [PATCH 4888/5359] Correct reference of WP_CLI to use global namespace This line causes a fatal as it tries to find `WP_CLI\Utils\WP_CLI` as the class. --- php/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/utils.php b/php/utils.php index d2499de33..5c9ffcf81 100644 --- a/php/utils.php +++ b/php/utils.php @@ -713,7 +713,7 @@ function get_temp_dir() { } if ( ! @is_writable( $temp ) ) { - WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); + \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); } return $trailingslashit( $temp ); From e105ad21cb1ed7e4e0c46a69fad87d170c707ebc Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 2 Sep 2016 09:12:53 +0545 Subject: [PATCH 4889/5359] Remove unnecessary alias check --- php/commands/help.php | 2 +- templates/man.mustache | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/help.php b/php/commands/help.php index 339f82fbd..31344a0fe 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -123,7 +123,7 @@ private static function get_initial_markdown( $command ) { $alias = $command->get_alias(); if ( $alias ) { - $binding['has-alias']['alias'] = $alias; + $binding['alias'] = $alias; } if ( $command->can_have_subcommands() ) { diff --git a/templates/man.mustache b/templates/man.mustache index 934b21f1b..fbb2e9bd6 100644 --- a/templates/man.mustache +++ b/templates/man.mustache @@ -12,12 +12,12 @@ {{synopsis}} -{{#has-alias}} +{{#alias}} ## ALIAS {{alias}} -{{/has-alias}} +{{/alias}} {{#has-subcommands}} ## SUBCOMMANDS From ecb38768264db203c8a73f9f8ac1de99b557853b Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 2 Sep 2016 09:30:07 +0545 Subject: [PATCH 4890/5359] Add test scenario for alias in man page --- features/help.feature | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/features/help.feature b/features/help.feature index 3f56c0ae2..8c067afb9 100644 --- a/features/help.feature +++ b/features/help.feature @@ -46,14 +46,14 @@ Feature: Get help about WP-CLI commands Scenario: Help for nonexistent commands Given a WP install - + When I try `wp help non-existent-command` Then the return code should be 1 And STDERR should be: """ Error: 'non-existent-command' is not a registered wp command. """ - + When I try `wp help non-existent-command non-existent-subcommand` Then the return code should be 1 And STDERR should be: @@ -207,3 +207,20 @@ Feature: Get help about WP-CLI commands """ ## GLOBAL PARAMETERS """ + + Scenario: Display alias in man page + Given a WP install + + When I run `wp help plugin update` + Then STDOUT should contain: + """ + ALIAS + + upgrade + """ + + When I run `wp help plugin install` + Then STDOUT should not contain: + """ + ALIAS + """ From 41a99c90d41e8b3a5f4a1791e855c47fa0cbb197 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 2 Sep 2016 16:51:48 +0545 Subject: [PATCH 4891/5359] Add example in Eval class --- php/commands/eval.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/php/commands/eval.php b/php/commands/eval.php index 12c2c85d7..6995700e5 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -1,5 +1,18 @@ <?php +/** + * Execute arbitrary PHP code. + * + * ## EXAMPLES + * + * # Display WordPress content directory. + * $ wp eval 'echo WP_CONTENT_DIR;' + * /var/www/wordpress/wp-content + * + * # Generate a random number. + * $ wp eval 'echo rand();' --skip-wordpress + * 479620423 + */ class Eval_Command extends WP_CLI_Command { /** @@ -13,15 +26,17 @@ class Eval_Command extends WP_CLI_Command { * [--skip-wordpress] * : Execute code without loading WordPress. * - * @when before_wp_load - * * ## EXAMPLES * + * # Display WordPress content directory. * $ wp eval 'echo WP_CONTENT_DIR;' * /var/www/wordpress/wp-content * + * # Generate a random number. * $ wp eval 'echo rand();' --skip-wordpress * 479620423 + * + * @when before_wp_load */ public function __invoke( $args, $assoc_args ) { @@ -34,4 +49,3 @@ public function __invoke( $args, $assoc_args ) { } WP_CLI::add_command( 'eval', 'Eval_Command' ); - From 6d6981535c55b75f68c1edffc8c6e2448ce06ede Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 2 Sep 2016 09:45:44 -0700 Subject: [PATCH 4892/5359] Add a testcase that `wp plugin install` fails with invalid proxy deets --- features/plugin-install.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 0971e2a04..4221cdceb 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -19,3 +19,26 @@ Feature: Install WordPress plugins And STDERR should be empty And the wp-content/plugins/one-time-login directory should exist And the wp-content/plugins/one-time-login-master directory should not exist + + Scenario: Installing respects WP_PROXY_HOST and WP_PROXY_PORT + Given a WP install + And a invalid-proxy-details.php file: + """ + <?php + define( 'WP_PROXY_HOST', 'https://wp-cli.org' ); + define( 'WP_PROXY_PORT', '443' ); + """ + + When I try `wp --require=invalid-proxy-details.php plugin install edit-flow` + Then STDERR should contain: + """ + Warning: edit-flow: An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. + """ + And STDOUT should be empty + + When I run `wp plugin install edit-flow` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And STDERR should be empty From 28239b9c67c38fac7317f86fbfd21e28e703736b Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Sat, 3 Sep 2016 17:49:43 +0100 Subject: [PATCH 4893/5359] Move the user session command into its own file. --- php/commands/user-session.php | 116 ++++++++++++++++++++++++++++++++++ php/commands/user.php | 114 --------------------------------- 2 files changed, 116 insertions(+), 114 deletions(-) create mode 100644 php/commands/user-session.php diff --git a/php/commands/user-session.php b/php/commands/user-session.php new file mode 100644 index 000000000..69d0c1f2c --- /dev/null +++ b/php/commands/user-session.php @@ -0,0 +1,116 @@ +<?php + +/** + * Manage a user's sessions. + * + * ## EXAMPLES + * + */ +class User_Session_Command extends WP_CLI_Command { + + private $fields = array( + 'token', + 'login_time', + 'expiration_time', + 'ip', + 'ua', + ); + + public function __construct() { + $this->fetcher = new \WP_CLI\Fetchers\User; + } + + /** + * Destroy all sessions for the given user. + * + * ## OPTIONS + * + * <user> + * : User ID, user email, or user login. + * + * ## EXAMPLES + * + * # Destroy a user's sessions + * $ wp user session destroy-all admin + * Success: Destroyed all sessions. + * + * @subcommand destroy-all + */ + public function destroy_all( $args, $assoc_args ) { + $user = $this->fetcher->get_check( $args[0] ); + $manager = WP_Session_Tokens::get_instance( $user->ID ); + $sessions = $manager->destroy_all(); + + WP_CLI::success( 'Destroyed all sessions.' ); + } + + /** + * List sessions for the given user. + * + * ## OPTIONS + * + * <user> + * : User ID, user email, or user login. + * + * [--fields=<fields>] + * : Limit the output to specific fields. + * + * [--format=<format>] + * : Accepted values: table, csv, json, count, yaml. Default: table + * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each session: + * + * * token + * * login_time + * * expiration_time + * * ip + * * ua + * + * These fields are optionally available: + * + * * expiration + * * login + * + * ## EXAMPLES + * + * # List a user's sessions + * $ wp user session list admin@example.com --format=csv + * login_time,expiration_time,ip,ua + * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + $user = $this->fetcher->get_check( $args[0] ); + $formatter = $this->get_formatter( $assoc_args ); + $manager = WP_Session_Tokens::get_instance( $user->ID ); + + $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); + $get_sessions->setAccessible( true ); + $sessions = $get_sessions->invoke( $manager ); + + if ( 'ids' == $formatter->format ) { + echo implode( ' ', array_keys( $sessions ) ); + } else if ( 'count' === $formatter->format ) { + $formatter->display_items( $sessions ); + } else { + $it = array_map( function( $session, $token ) { + $session['token'] = $token; + $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); + $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); + return $session; + }, $sessions, array_keys( $sessions ) ); + + $formatter->display_items( $it ); + } + } + + private function get_formatter( &$assoc_args ) { + return new \WP_CLI\Formatter( $assoc_args, $this->fields ); + } + +} + +WP_CLI::add_command( 'user session', 'User_Session_Command' ); diff --git a/php/commands/user.php b/php/commands/user.php index c7b41d641..f0c5daa66 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -1120,120 +1120,6 @@ class User_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'user'; } -/** - * Manage a user's sessions. - * - * ## EXAMPLES - * - */ -class User_Session_Command extends WP_CLI_Command { - - private $fields = array( - 'token', - 'login_time', - 'expiration_time', - 'ip', - 'ua', - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * Destroy all sessions for the given user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * ## EXAMPLES - * - * # Destroy a user's sessions - * $ wp user session destroy-all admin - * Success: Destroyed all sessions. - * - * @subcommand destroy-all - */ - public function destroy_all( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $manager = WP_Session_Tokens::get_instance( $user->ID ); - $sessions = $manager->destroy_all(); - - WP_CLI::success( 'Destroyed all sessions.' ); - } - - /** - * List sessions for the given user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [--fields=<fields>] - * : Limit the output to specific fields. - * - * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each session: - * - * * token - * * login_time - * * expiration_time - * * ip - * * ua - * - * These fields are optionally available: - * - * * expiration - * * login - * - * ## EXAMPLES - * - * # List a user's sessions - * $ wp user session list admin@example.com --format=csv - * login_time,expiration_time,ip,ua - * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $formatter = $this->get_formatter( $assoc_args ); - $manager = WP_Session_Tokens::get_instance( $user->ID ); - - $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); - $get_sessions->setAccessible( true ); - $sessions = $get_sessions->invoke( $manager ); - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', array_keys( $sessions ) ); - } else if ( 'count' === $formatter->format ) { - $formatter->display_items( $sessions ); - } else { - $it = array_map( function( $session, $token ) { - $session['token'] = $token; - $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); - $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); - return $session; - }, $sessions, array_keys( $sessions ) ); - - $formatter->display_items( $it ); - } - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields ); - } - -} - WP_CLI::add_command( 'user', 'User_Command' ); WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); WP_CLI::add_command( 'user term', 'User_Term_Command' ); -WP_CLI::add_command( 'user session', 'User_Session_Command' ); From 72eaebbb1a40d3979fe1c2c633887abab186d288 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 7 Sep 2016 05:57:40 -0700 Subject: [PATCH 4894/5359] Split the `ProcessRun` class out to its own file --- php/WP_CLI/Process.php | 30 ------------------------------ php/WP_CLI/ProcessRun.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 php/WP_CLI/ProcessRun.php diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php index 5be6a0d36..74939c5d0 100644 --- a/php/WP_CLI/Process.php +++ b/php/WP_CLI/Process.php @@ -73,33 +73,3 @@ public function run_check() { return $r; } } - -/** - * Results of an executed command. - */ -class ProcessRun { - - /** - * @var array $props Properties of executed command. - */ - public function __construct( $props ) { - foreach ( $props as $key => $value ) { - $this->$key = $value; - } - } - - /** - * Return properties of executed command as a string. - * - * @return string - */ - public function __toString() { - $out = "$ $this->command\n"; - $out .= "$this->stdout\n$this->stderr"; - $out .= "cwd: $this->cwd\n"; - $out .= "exit status: $this->return_code"; - - return $out; - } - -} diff --git a/php/WP_CLI/ProcessRun.php b/php/WP_CLI/ProcessRun.php new file mode 100644 index 000000000..90af6fea3 --- /dev/null +++ b/php/WP_CLI/ProcessRun.php @@ -0,0 +1,31 @@ +<?php + +/** + * Results of an executed command. + */ +class ProcessRun { + + /** + * @var array $props Properties of executed command. + */ + public function __construct( $props ) { + foreach ( $props as $key => $value ) { + $this->$key = $value; + } + } + + /** + * Return properties of executed command as a string. + * + * @return string + */ + public function __toString() { + $out = "$ $this->command\n"; + $out .= "$this->stdout\n$this->stderr"; + $out .= "cwd: $this->cwd\n"; + $out .= "exit status: $this->return_code"; + + return $out; + } + +} From 3b254fddbfdc4593f7cfbb52dab83d72e8bcb5af Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 7 Sep 2016 07:11:45 -0700 Subject: [PATCH 4895/5359] Ensure this class is properly namespaced --- php/WP_CLI/ProcessRun.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/WP_CLI/ProcessRun.php b/php/WP_CLI/ProcessRun.php index 90af6fea3..4611cfbb6 100644 --- a/php/WP_CLI/ProcessRun.php +++ b/php/WP_CLI/ProcessRun.php @@ -1,5 +1,7 @@ <?php +namespace WP_CLI; + /** * Results of an executed command. */ From 40d6bff0e990a256b7f7c648fde9a184ecb698da Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 7 Sep 2016 10:22:58 -0700 Subject: [PATCH 4896/5359] Update test suite for WordPress 4.6.1 --- features/core-check-update.feature | 10 +++++----- features/core-update.feature | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 71c988588..ae17608db 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,8 +9,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.6 | major | https://downloads.wordpress.org/release/wordpress-4.6.zip | - | 4.4.4 | minor | https://downloads.wordpress.org/release/wordpress-4.4.4-partial-0.zip | + | 4.6.1 | major | https://downloads.wordpress.org/release/wordpress-4.6.1.zip | + | 4.4.5 | minor | https://downloads.wordpress.org/release/wordpress-4.4.5-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.6 | major | https://downloads.wordpress.org/release/wordpress-4.6.zip | + | 4.6.1 | major | https://downloads.wordpress.org/release/wordpress-4.6.1.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -32,7 +32,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.4 | minor | https://downloads.wordpress.org/release/wordpress-4.4.4-partial-0.zip | + | 4.4.5 | minor | https://downloads.wordpress.org/release/wordpress-4.4.5-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -53,4 +53,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.12 | minor | https://downloads.wordpress.org/release/wordpress-4.0.12-partial-0.zip | + | 4.0.13 | minor | https://downloads.wordpress.org/release/wordpress-4.0.13-partial-0.zip | diff --git a/features/core-update.feature b/features/core-update.feature index fff39612c..1d6be5f83 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.15 + Updating to version 3.7.16 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.15 + 3.7.16 """ @less-than-php-7 @@ -208,8 +208,8 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 4.0.11 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.11-partial-0.zip + Updating to version 4.0.13 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.13-partial-0.zip """ And STDOUT should contain: """ From b456ae75fba6ef6bd5892bcd977d005009029aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20HULARD?= <s.hulard@chstudio.fr> Date: Thu, 8 Sep 2016 12:44:24 +0200 Subject: [PATCH 4897/5359] Fix strict standard error about variable reference When ran the command `wp core language update` I got the following error : ``` PHP Strict standards: Only variables should be passed by reference in /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/CommandWithTranslation.php on line 169 PHP Stack trace: PHP 1. {main}() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/boot-fs.php:0 PHP 2. include() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/boot-fs.php:17 PHP 3. WP_CLI\Runner->start() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/wp-cli.php:21 PHP 4. WP_CLI\Runner->_run_command() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php:906 PHP 5. WP_CLI\Runner->run_command() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php:319 PHP 6. WP_CLI\Dispatcher\Subcommand->invoke() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Runner.php:312 PHP 7. call_user_func:{/Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/Subcommand.php:372}() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/Subcommand.php:372 PHP 8. WP_CLI\Dispatcher\CommandFactory::WP_CLI\Dispatcher\{closure}() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/Subcommand.php:372 PHP 9. call_user_func:{/Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/CommandFactory.php:67}() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/CommandFactory.php:67 PHP 10. WP_CLI\CommandWithTranslation->update() /Users/shulard/Sites/Clients/Cher Ami/schneider-life-is-on/vendor/wp-cli/wp-cli/php/WP_CLI/Dispatcher/CommandFactory.php:67 ``` It's about the `array_shift` call on the `get_plugins` function result directly. This commit fix that by introducing a transition variable. --- php/WP_CLI/CommandWithTranslation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index dbd2ffb4a..cba6ec757 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -192,7 +192,8 @@ public function update( $args, $assoc_args ) { // Formats the updates list. foreach ( $updates as $update ) { if ( 'plugin' == $update->type ) { - $plugin_data = array_shift( get_plugins( '/' . $update->slug ) ); + $plugins = get_plugins( '/' . $update->slug ); + $plugin_data = array_shift( $plugins ); $name = $plugin_data['Name']; } elseif ( 'theme' == $update->type ) { $theme_data = wp_get_theme( $update->slug ); From 1440d144e577e8be8c45128e362ab7dc147abaf3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 8 Sep 2016 09:02:43 -0700 Subject: [PATCH 4898/5359] Permit running test suite with `WP_VERSION` env variable Normally, WP-CLI pays attention to `WP_VERSION` as a part of the setup process. This makes it easier for developers running the test suite locally to use `WP_VERSION` too: ``` WP_VERSION=trunk behat features/skip-themes.feature ``` --- features/bootstrap/FeatureContext.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 350fc4cba..cdf82d78b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -77,7 +77,8 @@ private static function cache_wp_files() { if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) return; - $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); + $version = getenv( 'WP_VERSION' ) ? '--version=' . getenv( 'WP_VERSION' ) : ''; + $cmd = Utils\esc_cmd( 'wp core download --force --path=%s %s', self::$cache_dir, $version ); Process::create( $cmd, null, self::get_process_env_variables() )->run_check(); } From 798b8778ff34ffadfa27acc23250fae94945148d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 8 Sep 2016 10:13:10 -0700 Subject: [PATCH 4899/5359] If `add_filter()` is already available, use it in `WP_CLI::add_hook()` This gracefully lets WP-CLI use the tentative `WP_Hook` implementation in WP 4.7. Even if `WP_Hook` gets pulled, it's better to use `add_filter()` if it's available. --- features/skip-themes.feature | 17 +++++++++++++++++ php/class-wp-cli.php | 12 +++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/features/skip-themes.feature b/features/skip-themes.feature index abfe6e2d3..7a710c719 100644 --- a/features/skip-themes.feature +++ b/features/skip-themes.feature @@ -10,6 +10,7 @@ Feature: Skipping themes """ true """ + And STDERR should be empty # The specified theme should be skipped When I run `wp --skip-themes=default eval 'var_export( function_exists( "kubrick_head" ) );'` @@ -17,6 +18,7 @@ Feature: Skipping themes """ false """ + And STDERR should be empty # All themes should be skipped When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` @@ -24,6 +26,7 @@ Feature: Skipping themes """ false """ + And STDERR should be empty # Skip another theme When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` @@ -31,6 +34,7 @@ Feature: Skipping themes """ true """ + And STDERR should be empty # The specified theme should still show up as an active theme When I run `wp --skip-themes theme status default` @@ -38,6 +42,7 @@ Feature: Skipping themes """ Active """ + And STDERR should be empty # Skip several themes When I run `wp --skip-themes=classic,default eval 'var_export( function_exists( "kubrick_head" ) );'` @@ -45,6 +50,7 @@ Feature: Skipping themes """ false """ + And STDERR should be empty Scenario: Skip parent and child themes Given a WP install @@ -56,12 +62,14 @@ Feature: Skipping themes """ true """ + And STDERR should be empty When I run `wp --skip-themes=jolene eval 'var_export( function_exists( "jolene_setup" ) );'` Then STDOUT should be: """ false """ + And STDERR should be empty When I run `wp theme activate biker` When I run `wp eval 'var_export( function_exists( "jolene_setup" ) );'` @@ -69,36 +77,42 @@ Feature: Skipping themes """ true """ + And STDERR should be empty When I run `wp eval 'var_export( function_exists( "biker_setup" ) );'` Then STDOUT should be: """ true """ + And STDERR should be empty When I run `wp --skip-themes=biker eval 'var_export( function_exists( "jolene_setup" ) );'` Then STDOUT should be: """ false """ + And STDERR should be empty When I run `wp --skip-themes=biker eval 'var_export( function_exists( "biker_setup" ) );'` Then STDOUT should be: """ false """ + And STDERR should be empty When I run `wp --skip-themes=biker eval 'echo get_template_directory();'` Then STDOUT should contain: """ wp-content/themes/jolene """ + And STDERR should be empty When I run `wp --skip-themes=biker eval 'echo get_stylesheet_directory();'` Then STDOUT should contain: """ wp-content/themes/biker """ + And STDERR should be empty Scenario: Skipping multiple themes via config file Given a WP install @@ -117,6 +131,7 @@ Feature: Skipping themes """ A classic """ + And STDERR should be empty # The default theme should show up as an installed theme When I run `wp theme status` @@ -124,6 +139,7 @@ Feature: Skipping themes """ I default """ + And STDERR should be empty And I run `wp theme activate default` @@ -133,3 +149,4 @@ Feature: Skipping themes """ false """ + And STDERR should be empty diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 8fc855687..72073bf3f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -274,9 +274,15 @@ public static function do_hook( $when ) { */ public static function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { global $wp_filter, $merged_filters; - $idx = self::wp_hook_build_unique_id( $tag, $function_to_add, $priority ); - $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); - unset( $merged_filters[ $tag ] ); + + if ( function_exists( 'add_filter' ) ) { + add_filter( $tag, $function_to_add, $priority, $accepted_args ); + } else { + $idx = self::wp_hook_build_unique_id( $tag, $function_to_add, $priority ); + $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + unset( $merged_filters[ $tag ] ); + } + return true; } From 317ebaab08bc0826e757d88915c34472f9becf1b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 8 Sep 2016 15:55:02 -0700 Subject: [PATCH 4900/5359] Add testcase and docs for installing core with shared user tables * If the `user_login` already exists, then the new email address and password are ignored and the existing user is reused. * If the `user_login` doesn't exist, then a new user is created with the provided email address and password. --- features/core-install.feature | 154 ++++++++++++++++++++++++++++++++++ php/commands/core.php | 4 + 2 files changed, 158 insertions(+) create mode 100644 features/core-install.feature diff --git a/features/core-install.feature b/features/core-install.feature new file mode 100644 index 000000000..28adb8e20 --- /dev/null +++ b/features/core-install.feature @@ -0,0 +1,154 @@ +Feature: Install WordPress core + + Scenario: Two WordPress installs sharing the same user table won't update existing user + Given an empty directory + And WP files + And a WP install in 'second' + And a extra-config file: + """ + define( 'CUSTOM_USER_TABLE', 'secondusers' ); + define( 'CUSTOM_USER_META_TABLE', 'secondusermeta' ); + """ + + When I run `wp --path=second user create testadmin testadmin@example.org --role=administrator` + Then STDOUT should contain: + """ + Success: Created user 2. + """ + + When I run `wp --path=second db tables` + Then STDOUT should contain: + """ + secondposts + """ + And STDOUT should contain: + """ + secondusers + """ + + When I run `wp --path=second user list --field=user_login` + Then STDOUT should be: + """ + admin + testadmin + """ + + When I run `wp --path=second user get testadmin --field=user_pass` + Then save STDOUT as {ORIGINAL_PASSWORD} + + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` + Then STDOUT should be: + """ + Success: Generated 'wp-config.php' file. + """ + + When I run `wp core install --url=example.org --title=Test --admin_user=testadmin --admin_email=testadmin@example.com --admin_password=newpassword` + Then STDOUT should contain: + """ + Success: WordPress installed successfully. + """ + + When I run `wp user list --field=user_login` + Then STDOUT should be: + """ + admin + testadmin + """ + + When I run `wp user get testadmin --field=email` + Then STDOUT should be: + """ + testadmin@example.org + """ + + When I run `wp user get testadmin --field=user_pass` + Then STDOUT should be: + """ + {ORIGINAL_PASSWORD} + """ + + When I run `wp db tables` + Then STDOUT should contain: + """ + wp_posts + """ + And STDOUT should contain: + """ + secondusers + """ + And STDOUT should not contain: + """ + wp_users + """ + + Scenario: Two WordPress installs sharing the same user table will create new user + Given an empty directory + And WP files + And a WP install in 'second' + And a extra-config file: + """ + define( 'CUSTOM_USER_TABLE', 'secondusers' ); + define( 'CUSTOM_USER_META_TABLE', 'secondusermeta' ); + """ + + When I run `wp --path=second db tables` + Then STDOUT should contain: + """ + secondposts + """ + And STDOUT should contain: + """ + secondusers + """ + + When I run `wp --path=second user list --field=user_login` + Then STDOUT should be: + """ + admin + """ + + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` + Then STDOUT should be: + """ + Success: Generated 'wp-config.php' file. + """ + + When I run `wp core install --url=example.org --title=Test --admin_user=testadmin --admin_email=testadmin@example.com --admin_password=newpassword` + Then STDOUT should contain: + """ + Success: WordPress installed successfully. + """ + + When I run `wp user list --field=user_login` + Then STDOUT should be: + """ + admin + testadmin + """ + + When I run `wp --path=second user list --field=user_login` + Then STDOUT should be: + """ + admin + testadmin + """ + + When I run `wp user get testadmin --field=email` + Then STDOUT should be: + """ + testadmin@example.com + """ + + When I run `wp db tables` + Then STDOUT should contain: + """ + wp_posts + """ + And STDOUT should contain: + """ + secondusers + """ + And STDOUT should not contain: + """ + wp_users + """ diff --git a/php/commands/core.php b/php/commands/core.php index 7568c2683..74168b40f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -544,6 +544,10 @@ public function is_installed( $_, $assoc_args ) { * then you'll need to run `wp option update siteurl http://wp.dev/wp` for * your WordPress install to function properly. * + * Note: When using custom user tables (e.g. `CUSTOM_USER_TABLE`), the admin + * email and password are ignored if the user_login already exists. If the + * user_login doesn't exist, a new user will be created. + * * ## OPTIONS * * --url=<url> From c7bcb7b7b35de68e98c9ed4453959735ac4edcf2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 8 Sep 2016 16:26:36 -0700 Subject: [PATCH 4901/5359] Introduce `Site_Option_Command` for managing site options As it turns out, site options don't support autoload, so there's less of an opportunity for a common abstraction. --- features/site-option.feature | 126 +++++++++++++++ php/commands/site-option.php | 288 +++++++++++++++++++++++++++++++++++ 2 files changed, 414 insertions(+) create mode 100644 features/site-option.feature create mode 100644 php/commands/site-option.php diff --git a/features/site-option.feature b/features/site-option.feature new file mode 100644 index 000000000..b36b75638 --- /dev/null +++ b/features/site-option.feature @@ -0,0 +1,126 @@ +Feature: Manage WordPress site options + + Scenario: Site Option CRUD + Given a WP multisite install + + # String values + When I run `wp site option add str_opt 'bar'` + Then STDOUT should not be empty + + When I run `wp site option get str_opt` + Then STDOUT should be: + """ + bar + """ + + When I run `wp site option list` + Then STDOUT should not be empty + + When I run `wp site option list` + Then STDOUT should contain: + """ + str_opt bar + """ + + When I run `wp site option list --search='str_o*'` + Then STDOUT should be a table containing rows: + | meta_key | meta_value | + | str_opt | bar | + + When I run `wp site option list --search='str_o*' --format=total_bytes` + Then STDOUT should be: + """ + 3 + """ + + When I run `wp site option list` + Then STDOUT should contain: + """ + admin_user_id 1 + """ + + When I run `wp site option delete str_opt` + Then STDOUT should not be empty + + When I run `wp site option list` + Then STDOUT should not contain: + """ + str_opt bar + """ + + When I try `wp site option get str_opt` + Then the return code should be 1 + + # Integer values + When I run `wp site option update admin_user_id 2` + Then STDOUT should not be empty + + When I run `wp site option get admin_user_id` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp site option update admin_user_id 1` + Then STDOUT should contain: + """ + Success: Updated 'admin_user_id' site option. + """ + + When I run the previous command again + Then STDOUT should contain: + """ + Success: Value passed for 'admin_user_id' site option is unchanged. + """ + + When I run `wp site option get admin_user_id` + Then STDOUT should be: + """ + 1 + """ + + # JSON values + When I run `wp site option set json_opt '[ 1, 2 ]' --format=json` + Then STDOUT should not be empty + + When I run the previous command again + Then STDOUT should not be empty + + When I run `wp site option get json_opt --format=json` + Then STDOUT should be: + """ + [1,2] + """ + + # Reading from files + Given a value.json file: + """ + { + "foo": "bar", + "list": [1, 2, 3] + } + """ + When I run `wp site option set foo --format=json < value.json` + And I run `wp site option get foo --format=json` + Then STDOUT should be JSON containing: + """ + { + "foo": "bar", + "list": [1, 2, 3] + } + """ + + Scenario: Error on single install + Given a WP install + + When I try `wp site option get str_opt` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ + + When I try `wp site option add str_opt 'bar'` + Then STDERR should be: + """ + Error: This is not a multisite install. + """ diff --git a/php/commands/site-option.php b/php/commands/site-option.php new file mode 100644 index 000000000..a97b98f5b --- /dev/null +++ b/php/commands/site-option.php @@ -0,0 +1,288 @@ +<?php + +/** + * Manage site options. + * + * ## EXAMPLES + * + * # Get site registration + * $ wp site option get registration + * none + * + * # Add site option + * $ wp site option add my_option foobar + * Success: Added 'my_option' site option. + * + * # Update site option + * $ wp site option update my_option '{"foo": "bar"}' --format=json + * Success: Updated 'my_option' site option. + * + * # Delete site option + * $ wp site option delete my_option + * Success: Deleted 'my_option' site option. + */ +class Site_Option_Command extends WP_CLI_Command { + + /** + * Get a site option. + * + * ## OPTIONS + * + * <key> + * : Key for the site option. + * + * [--format=<format>] + * : Get value in a particular format. + * --- + * default: var_export + * options: + * - var_export + * - json + * - yaml + * --- + * + * ## EXAMPLES + * + * # Get site upload filetypes + * $ wp site option get upload_filetypes + * jpg jpeg png gif mov avi mpg + */ + public function get( $args, $assoc_args ) { + list( $key ) = $args; + + $value = get_site_option( $key ); + + if ( false === $value ) + die(1); + + WP_CLI::print_value( $value, $assoc_args ); + } + + /** + * Add a site option. + * + * ## OPTIONS + * + * <key> + * : The name of the site option to add. + * + * [<value>] + * : The value of the site option to add. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- + * + * ## EXAMPLES + * + * # Create a site option by reading a JSON file + * $ wp site option add my_option --format=json < config.json + * Success: Added 'my_option' site option. + */ + public function add( $args, $assoc_args ) { + $key = $args[0]; + + $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); + $value = WP_CLI::read_value( $value, $assoc_args ); + + if ( ! add_site_option( $key, $value ) ) { + WP_CLI::error( "Could not add site option '$key'. Does it already exist?" ); + } else { + WP_CLI::success( "Added '$key' site option." ); + } + } + + /** + * List site options. + * + * ## OPTIONS + * + * [--search=<pattern>] + * : Use wildcards ( * and ? ) to match option name. + * + * [--field=<field>] + * : Prints the value of a single field. + * + * [--fields=<fields>] + * : Limit the output to specific object fields. + * + * [--format=<format>] + * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. + * --- + * default: table + * options: + * - table + * - json + * - csv + * - count + * - yaml + * - total_bytes + * --- + * + * ## AVAILABLE FIELDS + * + * This field will be displayed by default for each matching option: + * + * * meta_key + * * meta_value + * + * These fields are optionally available: + * + * * meta_id + * * site_id + * * size_bytes + * + * ## EXAMPLES + * + * # List all site options begining with "i2f_" + * $ wp site option list --search="i2f_*" + * +-------------+--------------+ + * | meta_key | meta_value | + * +-------------+--------------+ + * | i2f_version | 0.1.0 | + * +-------------+--------------+ + * + * @subcommand list + */ + public function list_( $args, $assoc_args ) { + + global $wpdb; + $pattern = '%'; + $fields = array( 'meta_key', 'meta_value' ); + $size_query = ",LENGTH(meta_value) AS `size_bytes`"; + $autoload_query = ''; + + if ( isset( $assoc_args['search'] ) ) { + $pattern = self::esc_like( $assoc_args['search'] ); + // substitute wildcards + $pattern = str_replace( '*', '%', $pattern ); + $pattern = str_replace( '?', '_', $pattern ); + } + + if ( isset( $assoc_args['fields'] ) ) { + $fields = explode( ',', $assoc_args['fields'] ); + } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { + $fields = array( 'size_bytes' ); + $size_query = ",SUM(LENGTH(meta_value)) AS `size_bytes`"; + } + + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT `meta_id`, `site_id`, `meta_key`,`meta_value`" . $size_query + . " FROM `$wpdb->sitemeta` WHERE `meta_key` LIKE %s", + $pattern + ) + ); + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { + WP_CLI::line( $results[0]->size_bytes ); + } else { + $formatter = new \WP_CLI\Formatter( + $assoc_args, + $fields + ); + $formatter->display_items( $results ); + } + } + + /** + * Update a site option. + * + * ## OPTIONS + * + * <key> + * : The name of the site option to update. + * + * [<value>] + * : The new value. If ommited, the value is read from STDIN. + * + * [--format=<format>] + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- + * + * ## EXAMPLES + * + * # Update a site option by reading from a file + * $ wp site option update my_option < value.txt + * Success: Updated 'my_option' site option. + * + * @alias set + */ + public function update( $args, $assoc_args ) { + $key = $args[0]; + + $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); + $value = WP_CLI::read_value( $value, $assoc_args ); + + $value = sanitize_option( $key, $value ); + $old_value = sanitize_option( $key, get_site_option( $key ) ); + + if ( $value === $old_value && is_null( $autoload ) ) { + WP_CLI::success( "Value passed for '$key' site option is unchanged." ); + } else { + if ( update_site_option( $key, $value ) ) { + WP_CLI::success( "Updated '$key' site option." ); + } else { + WP_CLI::error( "Could not update site option '$key'." ); + } + } + } + + /** + * Delete a site option. + * + * ## OPTIONS + * + * <key> + * : Key for the site option. + * + * ## EXAMPLES + * + * $ wp site option delete my_option + * Success: Deleted 'my_option' site option. + */ + public function delete( $args ) { + list( $key ) = $args; + + if ( ! delete_site_option( $key ) ) { + WP_CLI::error( "Could not delete '$key' site option. Does it exist?" ); + } else { + WP_CLI::success( "Deleted '$key' site option." ); + } + } + + private static function esc_like( $old ) { + global $wpdb; + + // Remove notices in 4.0 and support backwards compatibility + if( method_exists( $wpdb, 'esc_like' ) ) { + // 4.0 + $old = $wpdb->esc_like( $old ); + } else { + // 3.9 or less + $old = like_escape( esc_sql( $old ) ); + } + + return $old; + } +} + +WP_CLI::add_command( 'site option', 'Site_Option_Command', array( + 'before_invoke' => function() { + if ( !is_multisite() ) { + WP_CLI::error( 'This is not a multisite install.' ); + } + } +) ); From d8a31534235e5023aa8aefcd73c060f898495aa4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 8 Sep 2016 16:56:37 -0700 Subject: [PATCH 4902/5359] If SQL regex triggers an error for some reason, fail back to PHP --- php/commands/search-replace.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index fe7ad99c9..14daa7e92 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -219,7 +219,12 @@ public function __invoke( $args, $assoc_args ) { } if ( ! $php_only && ! $this->regex ) { + $wpdb->last_error = ''; $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); + // When the regex triggers an error, we should fall back to PHP + if ( false !== strpos( $wpdb->last_error, 'ERROR 1139' ) ) { + $serialRow = true; + } } if ( $php_only || $this->regex || NULL !== $serialRow ) { From 61cef85009949af9e2cf441c370ac2fe050d4a8e Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 9 Sep 2016 17:11:41 +0545 Subject: [PATCH 4903/5359] Acceping paramter in transient delete command --- php/commands/transient.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index d68f4950c..2e823be1b 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -111,21 +111,36 @@ public function set( $args, $assoc_args ) { * * ## OPTIONS * - * <key> + * [<key>] * : Key for the transient. * * [--network] * : Delete the value of a network transient, instead of that on a single site. * + * [--all] + * : Delete all transients. + * + * [--expired] + * : Delete all expired transients. + * * ## EXAMPLES * * $ wp transient delete sample_key * Success: Transient deleted. */ public function delete( $args, $assoc_args ) { - list( $key ) = $args; + $key = ( ! empty( $args ) ) ? $args[0] : NULL; + + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); + $expired = \WP_CLI\Utils\get_flag_value( $assoc_args, 'expired' ); + + if ( ! $key ) { + WP_CLI::error( 'Transient key is required.' ); + } $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'delete_site_transient' : 'delete_transient'; + var_dump( $args ); return; + if ( $func( $key ) ) { WP_CLI::success( 'Transient deleted.' ); } else { @@ -166,7 +181,7 @@ public function type() { * * @subcommand delete-expired */ - public function delete_expired() { + private function delete_expired() { global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. @@ -200,7 +215,7 @@ public function delete_expired() { * * @subcommand delete-all */ - public function delete_all() { + private function delete_all() { global $wpdb, $_wp_using_ext_object_cache; // Always delete all transients from DB too. From d1aef6d0bc16e87b0843fa4befe9e4c99e375782 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 09:42:13 +0545 Subject: [PATCH 4904/5359] Call function as per flag --- php/commands/transient.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 2e823be1b..ed6ef4619 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -134,12 +134,20 @@ public function delete( $args, $assoc_args ) { $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); $expired = \WP_CLI\Utils\get_flag_value( $assoc_args, 'expired' ); + if ( true === $all ) { + $this->delete_all(); + return; + } + else if ( true === $expired ) { + $this->delete_expired(); + return; + } + if ( ! $key ) { - WP_CLI::error( 'Transient key is required.' ); + WP_CLI::error( 'Please specify transient key, or use --all or --expired.' ); } $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'delete_site_transient' : 'delete_transient'; - var_dump( $args ); return; if ( $func( $key ) ) { WP_CLI::success( 'Transient deleted.' ); From 26f96bab60ce5d4bc3b8c4d30877141c33a23a03 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 09:55:38 +0545 Subject: [PATCH 4905/5359] Add back compat shim in runner --- php/WP_CLI/Runner.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 031b1bd2e..2c3aa2dc6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -485,6 +485,18 @@ private static function back_compat_conversions( $args, $assoc_args ) { $assoc_args['all'] = true; } + // transient delete-expired -> transient delete --expired + if ( 'transient' === $args[0] && 'delete-expired' === $args[1] ) { + $args[1] = 'delete'; + $assoc_args['expired'] = true; + } + + // transient delete-all -> transient delete --all + if ( 'transient' === $args[0] && 'delete-all' === $args[1] ) { + $args[1] = 'delete'; + $assoc_args['all'] = true; + } + // plugin scaffold -> scaffold plugin if ( array( 'plugin', 'scaffold' ) == array_slice( $args, 0, 2 ) ) { list( $args[0], $args[1] ) = array( $args[1], $args[0] ); From ee50539b68696415465d10abd4cdd48ad5264b19 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 10:05:34 +0545 Subject: [PATCH 4906/5359] Update examples for transient delete --- php/commands/transient.php | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index ed6ef4619..06cff3ea6 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -5,24 +5,24 @@ * * ## EXAMPLES * - * # Set transient + * # Set transient. * $ wp transient set sample_key "test data" 3600 * Success: Transient added. * - * # Get transient + * # Get transient. * $ wp transient get sample_key * test data * - * # Delete transient + * # Delete transient. * $ wp transient delete sample_key * Success: Transient deleted. * - * # Delete expired transients - * $ wp transient delete-expired + * # Delete expired transients. + * $ wp transient delete --expired * Success: 12 expired transients deleted from the database. * - * # Delete all transients - * $ wp transient delete-all + * # Delete all transients. + * $ wp transient delete --all * Success: 14 transients deleted from the database. */ class Transient_Command extends WP_CLI_Command { @@ -125,8 +125,17 @@ public function set( $args, $assoc_args ) { * * ## EXAMPLES * + * # Delete transient. * $ wp transient delete sample_key * Success: Transient deleted. + * + * # Delete expired transients. + * $ wp transient delete --expired + * Success: 12 expired transients deleted from the database. + * + * # Delete all transients. + * $ wp transient delete --all + * Success: 14 transients deleted from the database. */ public function delete( $args, $assoc_args ) { $key = ( ! empty( $args ) ) ? $args[0] : NULL; @@ -181,13 +190,6 @@ public function type() { /** * Delete all expired transients. - * - * ## EXAMPLES - * - * $ wp transient delete-expired - * Success: 12 expired transients deleted from the database. - * - * @subcommand delete-expired */ private function delete_expired() { global $wpdb, $_wp_using_ext_object_cache; @@ -215,13 +217,6 @@ private function delete_expired() { /** * Delete all transients. - * - * ## EXAMPLES - * - * $ wp transient delete-all - * Success: 14 transients deleted from the database. - * - * @subcommand delete-all */ private function delete_all() { global $wpdb, $_wp_using_ext_object_cache; From 12bdb3631a9522d0ccbdcfb26cc6c8abddb0769d Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 14:20:43 +0545 Subject: [PATCH 4907/5359] Add check for args existance --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2c3aa2dc6..ca0f32f79 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -486,7 +486,7 @@ private static function back_compat_conversions( $args, $assoc_args ) { } // transient delete-expired -> transient delete --expired - if ( 'transient' === $args[0] && 'delete-expired' === $args[1] ) { + if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-expired' === $args[1] ) { $args[1] = 'delete'; $assoc_args['expired'] = true; } From 582d9a0886f183e4a172bf8afb1be53beb235551 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 14:59:28 +0545 Subject: [PATCH 4908/5359] Add missing args check --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index ca0f32f79..a292884a3 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -492,7 +492,7 @@ private static function back_compat_conversions( $args, $assoc_args ) { } // transient delete-all -> transient delete --all - if ( 'transient' === $args[0] && 'delete-all' === $args[1] ) { + if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-all' === $args[1] ) { $args[1] = 'delete'; $assoc_args['all'] = true; } From 4965eecc0c8d4d66f4951fb0e0d33772c0781fc8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 10 Sep 2016 06:52:15 -0700 Subject: [PATCH 4909/5359] Drop WP download and version check from prepare step This better ensures we always run the same code path on CI and locally --- ci/prepare.sh | 4 ---- features/bootstrap/FeatureContext.php | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ci/prepare.sh b/ci/prepare.sh index 852e3f760..b34f72660 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -30,9 +30,5 @@ echo $CLI_VERSION > PHAR_BUILD_VERSION # Install CodeSniffer things ./ci/prepare-codesniffer.sh -./bin/wp core download --version=$WP_VERSION --path='/tmp/wp-cli-test core-download-cache/' - -./bin/wp core version --path='/tmp/wp-cli-test core-download-cache/' - mysql -e 'CREATE DATABASE wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index cdf82d78b..cab27c640 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -91,6 +91,9 @@ public static function prepare( SuiteEvent $event ) { echo $result->stdout; echo PHP_EOL; self::cache_wp_files(); + $result = Process::create( Utils\esc_cmd( 'wp core version --path=%s', self::$cache_dir ) , null, self::get_process_env_variables() )->run_check(); + echo 'WordPress ' . $result->stdout; + echo PHP_EOL; } /** From 93ee0a18bcebf11192e8d71341992fdb976fb0b6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 10 Sep 2016 06:53:29 -0700 Subject: [PATCH 4910/5359] Fix Exception in test suite when no `WP_VERSION` is provided --- features/bootstrap/FeatureContext.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index cab27c640..b4a186e67 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -77,8 +77,10 @@ private static function cache_wp_files() { if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) return; - $version = getenv( 'WP_VERSION' ) ? '--version=' . getenv( 'WP_VERSION' ) : ''; - $cmd = Utils\esc_cmd( 'wp core download --force --path=%s %s', self::$cache_dir, $version ); + $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); + if ( getenv( 'WP_VERSION' ) ) { + $cmd .= Utils\esc_cmd( ' --version=%s', getenv( 'WP_VERSION' ) ); + } Process::create( $cmd, null, self::get_process_env_variables() )->run_check(); } From 26e2ed8525d0b7873da9894f2776fcfcd5274cc0 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Sat, 10 Sep 2016 20:31:12 +0545 Subject: [PATCH 4911/5359] Add more test for transient delete --- features/transient.feature | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/features/transient.feature b/features/transient.feature index fcbd9d8ea..064d4d883 100644 --- a/features/transient.feature +++ b/features/transient.feature @@ -54,3 +54,32 @@ Feature: Manage WordPress transient cache """ Success: Transient deleted. """ + + Scenario: Transient delete and other flags + Given a WP install + + When I try `wp transient delete` + Then STDERR should be: + """ + Error: Please specify transient key, or use --all or --expired. + """ + + When I run `wp transient set foo bar` + And I run `wp transient set foo2 bar2` + And I run `wp transient delete --all` + Then STDOUT should contain: + """ + transients deleted from the database. + """ + + When I try `wp transient get foo` + Then STDERR should be: + """ + Warning: Transient with key "foo" is not set. + """ + + When I try `wp transient get foo2` + Then STDERR should be: + """ + Warning: Transient with key "foo2" is not set. + """ From 7a59ff84208f4c1ebbc9db24f567741c915a0ff3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 13 Sep 2016 07:10:55 -0700 Subject: [PATCH 4912/5359] Permit updating language packs even when `en_US` is set as locale This makes `wp core language update` more useful to those with installed language packs. --- php/WP_CLI/CommandWithTranslation.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index cba6ec757..2b0adea2a 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -172,13 +172,6 @@ public function install( $args, $assoc_args ) { */ public function update( $args, $assoc_args ) { - // Ignore updates for the default locale. - if ( 'en_US' == get_locale() ) { - \WP_CLI::success( "Translations updates are not needed for the 'English (US)' locale." ); - - return; - } - $updates = $this->get_translation_updates(); if ( empty( $updates ) ) { \WP_CLI::success( 'Translations are up to date.' ); From 5e4e78bc9af17331aad06f4e27c63743ec0c42ad Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 13 Sep 2016 14:25:12 -0700 Subject: [PATCH 4913/5359] Properly assign `$composer_backup` when uninstalling This will permit the package to actually be uninstalled. --- php/commands/package.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 1a03f1c3b..23d0bb75b 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -322,8 +322,8 @@ public function uninstall( $args ) { // Remove the 'require' from composer.json $json_path = $composer_json_obj->getPath(); WP_CLI::log( sprintf( 'Removing require statement from %s', $json_path ) ); - $contents = file_get_contents( $json_path ); - $manipulator = new JsonManipulator( $contents ); + $composer_backup = file_get_contents( $composer_json_obj->getPath() ); + $manipulator = new JsonManipulator( $composer_backup ); $manipulator->removeSubNode( 'require', $package_name ); file_put_contents( $composer_json_obj->getPath(), $manipulator->getContents() ); @@ -339,6 +339,7 @@ public function uninstall( $args ) { $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. WP_CLI::log( 'Removing package directories and regenerating autoloader...' ); + $res = false; try { $res = $install->run(); } catch ( Exception $e ) { From 7562dc56f831b1129e142751b035104c7b15475b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 13 Sep 2016 15:23:11 -0700 Subject: [PATCH 4914/5359] Ensure the entire uploads directory is empty Builds an array of files and directories to be removed, then removes them. This ensures `RecursiveIteratorIterator` internal index isn't messed up as we remove files. --- php/commands/site.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index f9d9d9aa9..3fad43491 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -188,14 +188,24 @@ public function _empty( $args, $assoc_args ) { RecursiveIteratorIterator::CHILD_FIRST ); + $files_to_unlink = $directories_to_delete = array(); foreach ( $files as $fileinfo ) { $realpath = $fileinfo->getRealPath(); // Don't clobber subsites when operating on the main site if ( is_main_site() && false !== stripos( $realpath, '/sites/' ) ) { continue; } - $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; - $todo( $realpath ); + if ( $fileinfo->isDir() ) { + $directories_to_delete[] = $realpath; + } else { + $files_to_unlink[] = $realpath; + } + } + foreach( $files_to_unlink as $file ) { + unlink( $file ); + } + foreach( $directories_to_delete as $directory ) { + rmdir( $directory ); } rmdir( $upload_dir['basedir'] ); } From f2252ebc10c06884f94c2d22e950ae1ebe59eba7 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Wed, 14 Sep 2016 14:06:28 +0400 Subject: [PATCH 4915/5359] fix editorconfig pattern for 2 space rule --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index ddb90c301..e80de3fe1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,7 +14,7 @@ trim_trailing_whitespace = true indent_style = tab indent_size = 4 -[*.json,*.yml,*.feature] +[*.{json,yml,feature}] indent_style = space indent_size = 2 From a9d079f4c8a1ee715e033cc8354237507d59d4e2 Mon Sep 17 00:00:00 2001 From: Evan Mattson <me@aaemnnost.tv> Date: Wed, 14 Sep 2016 14:07:00 +0400 Subject: [PATCH 4916/5359] add editorconfig for composer.json --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index e80de3fe1..8ccb6afe7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,3 +18,6 @@ indent_size = 4 indent_style = space indent_size = 2 +[composer.json] +indent_style = space +indent_size = 4 From 5395de2d04808041e453b46771dda926a778efd6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 14 Sep 2016 09:46:09 -0700 Subject: [PATCH 4917/5359] Add testcase for failing `get_named_sem_ver()` with WP version numbers --- tests/test-utils.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test-utils.php b/tests/test-utils.php index deda16a62..b8fdd135f 100644 --- a/tests/test-utils.php +++ b/tests/test-utils.php @@ -44,6 +44,17 @@ public function testGetSemVer() { $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.1.1', $original_version ) ); } + public function testGetSemVerWP() { + $original_version = '3.0'; + $this->assertEmpty( Utils\get_named_sem_ver( '2.8', $original_version ) ); + $this->assertEmpty( Utils\get_named_sem_ver( '2.9.1', $original_version ) ); + $this->assertEquals( 'patch', Utils\get_named_sem_ver( '3.0.1', $original_version ) ); + $this->assertEquals( 'minor', Utils\get_named_sem_ver( '3.1', $original_version ) ); + $this->assertEquals( 'minor', Utils\get_named_sem_ver( '3.1.1', $original_version ) ); + $this->assertEquals( 'major', Utils\get_named_sem_ver( '4.0', $original_version ) ); + $this->assertEquals( 'major', Utils\get_named_sem_ver( '4.1.1', $original_version ) ); + } + public function testParseSSHUrl() { $testcase = 'foo'; $this->assertEquals( array( From 3854a90dd245226ff157b780ae7257ff6ed1d095 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 14 Sep 2016 09:48:57 -0700 Subject: [PATCH 4918/5359] Fix error notice when using `Utils\get_named_sem_ver()` with WP versions --- php/utils.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/php/utils.php b/php/utils.php index 5c9ffcf81..0332ad1bb 100644 --- a/php/utils.php +++ b/php/utils.php @@ -656,9 +656,16 @@ function get_named_sem_ver( $new_version, $original_version ) { } $parts = explode( '-', $original_version ); - list( $major, $minor, $patch ) = explode( '.', $parts[0] ); + $bits = explode( '.', $parts[0] ); + $major = $bits[0]; + if ( isset( $bits[1] ) ) { + $minor = $bits[1]; + } + if ( isset( $bits[2] ) ) { + $patch = $bits[2]; + } - if ( Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { + if ( ! is_null( $minor ) && Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { return 'patch'; } else if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { return 'minor'; From 649354ae046dd7a73a2c19691e355ee168f4e85a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 15 Sep 2016 05:40:49 -0700 Subject: [PATCH 4919/5359] Use a direct download link for bash completion --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85d3be575..993baa144 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Want to live life on the edge? Run `wp cli update --nightly` to use the latest n ### Tab completions -WP-CLI also comes with a tab completion script for Bash and ZSH. Just download [wp-completion.bash](https://github.com/wp-cli/wp-cli/raw/master/utils/wp-completion.bash) and source it from `~/.bash_profile`: +WP-CLI also comes with a tab completion script for Bash and ZSH. Just download [wp-completion.bash](https://raw.githubusercontent.com/wp-cli/wp-cli/master/utils/wp-completion.bash) and source it from `~/.bash_profile`: ```bash source /FULL/PATH/TO/wp-completion.bash From e9320d86c3e9c17f913dc7e93c66391e7bac7fb7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 15 Sep 2016 06:39:37 -0700 Subject: [PATCH 4920/5359] Support `--fields=<fields>` parameter for browsing and listing packages --- php/commands/package.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/commands/package.php b/php/commands/package.php index 23d0bb75b..73542b771 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -85,6 +85,9 @@ class Package_Command extends WP_CLI_Command { * * ## OPTIONS * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] * : Render output in a particular format. * --- @@ -231,6 +234,9 @@ public function install( $args, $assoc_args ) { * * ## OPTIONS * + * [--fields=<fields>] + * : Limit the output to specific fields. Defaults to all fields. + * * [--format=<format>] * : Render output in a particular format. * --- From c84bf18ad20e832fe364e8155cfb5b4c8cea4e3a Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 16 Sep 2016 10:16:49 +0100 Subject: [PATCH 4921/5359] Add a simple progress indicator to `wp media regenerate` --- php/commands/media.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 910658d37..051e37139 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -90,8 +90,8 @@ function regenerate( $args, $assoc_args = array() ) { _n( 'image', 'images', $count ) ) ); $errored = false; - foreach ( $images->posts as $id ) { - if ( ! $this->_process_regeneration( $id, $skip_delete, $only_missing ) ) { + foreach ( $images->posts as $number => $id ) { + if ( ! $this->_process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { $errored = true; } } @@ -275,7 +275,7 @@ private function _make_copy( $path ) { return $filename; } - private function _process_regeneration( $id, $skip_delete = false, $only_missing = false ) { + private function _process_regeneration( $id, $skip_delete = false, $only_missing = false, $progress = '' ) { $fullsizepath = get_attached_file( $id ); @@ -299,16 +299,16 @@ private function _process_regeneration( $id, $skip_delete = false, $only_missing } if ( empty( $metadata ) ) { - WP_CLI::warning( "Couldn't regenerate thumbnails for $att_desc." ); + WP_CLI::warning( "$progress Couldn't regenerate thumbnails for $att_desc." ); return false; } wp_update_attachment_metadata( $id, $metadata ); - WP_CLI::log( "Regenerated thumbnails for $att_desc." ); + WP_CLI::log( "$progress Regenerated thumbnails for $att_desc." ); return true; } else { - WP_CLI::log( "No thumbnail regeneration needed for $att_desc." ); + WP_CLI::log( "$progress No thumbnail regeneration needed for $att_desc." ); return true; } } From a6cea71f68e1871ededf059337e48bee7d536407 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 16 Sep 2016 11:43:39 +0100 Subject: [PATCH 4922/5359] `wp media regenerate`: update tests to reflect changes in output --- features/media-regenerate.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index 0981e41c8..ae81bf092 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -134,11 +134,11 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - No thumbnail regeneration needed for "My second imported attachment" + 1/2 No thumbnail regeneration needed for "My second imported attachment" """ And STDOUT should contain: """ - Regenerated thumbnails for "My imported attachment" + 2/2 Regenerated thumbnails for "My imported attachment" """ And STDOUT should contain: """ @@ -170,7 +170,7 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - Regenerated thumbnails for "My imported attachment" + 1/1 Regenerated thumbnails for "My imported attachment" """ And STDOUT should contain: """ @@ -185,7 +185,7 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - No thumbnail regeneration needed for "My imported attachment" + 1/1 No thumbnail regeneration needed for "My imported attachment" """ And STDOUT should contain: """ From 3eebbb863caf4f78da1e4aeb10d41006a05c12c9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 16 Sep 2016 16:55:31 +0545 Subject: [PATCH 4923/5359] Doc improvement in comment commands --- php/commands/comment.php | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index a0ae3434f..f16806964 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -5,15 +5,15 @@ * * ## EXAMPLES * - * # Create comment + * # Create comment. * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" * Success: Created comment 932. * - * # Update comment + * # Update comment. * $ wp comment update 123 --comment_author='That Guy' * Success: Updated comment 123. * - * # Delete comment + * # Delete comment. * $ wp comment delete 1337 --force * Success: Deleted comment 1337. * @@ -54,6 +54,7 @@ public function __construct() { * * ## EXAMPLES * + * # Create comment. * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" * Success: Created comment 932. */ @@ -93,6 +94,7 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * + * # Update comment. * $ wp comment update 123 --comment_author='That Guy' * Success: Updated comment 123. */ @@ -211,6 +213,7 @@ public function generate( $args, $assoc_args ) { * * ## EXAMPLES * + * # Get comment. * $ wp comment get 21 --field=content * Thanks for all the comments, everyone! */ @@ -282,13 +285,13 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * # List comment IDs + * # List comment IDs. * $ wp comment list --field=ID * 22 * 23 * 24 * - * # List comments of a post + * # List comments of a post. * $ wp comment list --post_id=1 --fields=ID,comment_date,comment_author * +------------+---------------------+----------------+ * | comment_ID | comment_date | comment_author | @@ -296,7 +299,7 @@ public function get( $args, $assoc_args ) { * | 1 | 2015-06-20 09:00:10 | Mr WordPress | * +------------+---------------------+----------------+ * - * # List approved comments + * # List approved comments. * $ wp comment list --number=3 --status=approve --fields=ID,comment_date,comment_author * +------------+---------------------+----------------+ * | comment_ID | comment_date | comment_author | @@ -337,11 +340,11 @@ public function list_( $_, $assoc_args ) { * * ## EXAMPLES * - * # Delete comment + * # Delete comment. * $ wp comment delete 1337 --force * Success: Deleted comment 1337. * - * # Delete multiple comments + * # Delete multiple comments. * $ wp comment delete 1337 2341 --force * Success: Deleted comment 1337. * Success: Deleted comment 2341. @@ -399,6 +402,7 @@ private function set_status( $args, $status, $success ) { * * ## EXAMPLES * + * # Trash comment. * $ wp comment trash 1337 * Success: Trashed comment 1337. */ @@ -418,6 +422,7 @@ public function trash( $args, $assoc_args ) { * * ## EXAMPLES * + * # Untrash comment. * $ wp comment untrash 1337 * Success: Untrashed comment 1337. */ @@ -437,6 +442,7 @@ public function untrash( $args, $assoc_args ) { * * ## EXAMPLES * + * # Spam comment. * $ wp comment spam 1337 * Success: Marked as spam comment 1337. */ @@ -456,6 +462,7 @@ public function spam( $args, $assoc_args ) { * * ## EXAMPLES * + * # Unspam comment. * $ wp comment unspam 1337 * Success: Unspammed comment 1337. */ @@ -475,8 +482,9 @@ public function unspam( $args, $assoc_args ) { * * ## EXAMPLES * + * # Approve comment. * $ wp comment approve 1337 - * Success: Approved comment 1337 + * Success: Approved comment 1337. */ public function approve( $args, $assoc_args ) { foreach( $args as $id ) { @@ -494,8 +502,9 @@ public function approve( $args, $assoc_args ) { * * ## EXAMPLES * + * # Unapprove comment. * $ wp comment unapprove 1337 - * Success: Unapproved comment 1337 + * Success: Unapproved comment 1337. */ public function unapprove( $args, $assoc_args ) { foreach( $args as $id ) { @@ -513,7 +522,7 @@ public function unapprove( $args, $assoc_args ) { * * ## EXAMPLES * - * # Count comments on whole blog + * # Count comments on whole blog. * $ wp comment count * approved: 33 * spam: 3 @@ -523,7 +532,7 @@ public function unapprove( $args, $assoc_args ) { * moderated: 1 * total_comments: 37 * - * # Count comments in a post + * # Count comments in a post. * $ wp comment count 42 * approved: 19 * spam: 0 @@ -558,6 +567,7 @@ public function count( $args, $assoc_args ) { * * ## EXAMPLES * + * # Recount comment for the post. * $ wp comment recount 123 * Updated post 123 comment count to 67. */ @@ -583,6 +593,7 @@ public function recount( $args ) { * * ## EXAMPLES * + * # Get status of comment. * $ wp comment status 1337 * approved */ @@ -608,6 +619,7 @@ public function status( $args, $assoc_args ) { * * ## EXAMPLES * + * # Check whether comment exists. * $ wp comment exists 1337 * Success: Comment with ID 1337 exists. */ @@ -618,7 +630,7 @@ public function exists( $args ) { } /** - * Get comment url + * Get comment URL. * * ## OPTIONS * @@ -627,6 +639,7 @@ public function exists( $args ) { * * ## EXAMPLES * + * # Get comment URL. * $ wp comment url 123 * http://example.com/about/page-with-comments/#comment-123 */ From c6314d0f95011b55dd7cc08a5523a40a6bfc9874 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 20 Sep 2016 17:14:30 +0545 Subject: [PATCH 4924/5359] Update command messages in role --- php/commands/role.php | 70 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index 0be1a4116..e08e09d1c 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -5,7 +5,7 @@ * * ## EXAMPLES * - * # List roles + * # List roles. * $ wp role list --fields=role --format=csv * role * administrator @@ -14,21 +14,21 @@ * contributor * subscriber * - * # Check if a role exists + * # Check if a role exists. * $ wp role exists editor - * Success: Role with ID editor exists. + * Success: Role with ID 'editor' exists. * - * # Create role + * # Create role. * $ wp role create approver Approver - * Success: Role with key approver created. + * Success: Role with key 'approver' created. * - * # Delete role + * # Delete role. * $ wp role delete approver - * Success: Role with key approver deleted. + * Success: Role with key 'approver' deleted. * - * # Reset role + * # Reset role. * $ wp role reset administrator author contributor - * Success: Reset 3/3 roles + * Success: Reset 3/3 roles. * * @package wp-cli */ @@ -70,6 +70,7 @@ class Role_Command extends WP_CLI_Command { * * ## EXAMPLES * + * # List roles. * $ wp role list --fields=role --format=csv * role * administrator @@ -100,7 +101,7 @@ public function list_( $args, $assoc_args ) { /** * Check if a role exists. * - * ##DESCRIPTION + * ## DESCRIPTION * * Will exit with status 0 if the role exists, 1 if it does not. * @@ -111,17 +112,18 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * + * # Check if a role exists. * $ wp role exists editor - * Success: Role with ID editor exists. + * Success: Role with ID 'editor' exists. */ public function exists( $args ) { global $wp_roles; if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - WP_CLI::error( "Role with ID $args[0] does not exist." ); + WP_CLI::error( "Role with ID '$args[0]' does not exist." ); } - WP_CLI::success( "Role with ID $args[0] exists." ); + WP_CLI::success( "Role with ID '$args[0]' exists." ); } /** @@ -140,13 +142,13 @@ public function exists( $args ) { * * ## EXAMPLES * - * # Create role for Approver + * # Create role for Approver. * $ wp role create approver Approver - * Success: Role with key approver created. + * Success: Role with key 'approver' created. * - * # Create role for Product Administrator + * # Create role for Product Administrator. * $ wp role create productadmin "Product Administrator" - * Success: Role with key productadmin created. + * Success: Role with key 'productadmin' created. */ public function create( $args, $assoc_args ) { global $wp_roles; @@ -175,9 +177,9 @@ public function create( $args, $assoc_args ) { foreach( $capabilities as $cap ) { $role_obj->add_cap( $cap ); } - WP_CLI::success( sprintf( "Role with key %s created. Cloned capabilities from %s.", $role_key, $assoc_args['clone'] ) ); + WP_CLI::success( sprintf( "Role with key '%s' created. Cloned capabilities from '%s'.", $role_key, $assoc_args['clone'] ) ); } else { - WP_CLI::success( sprintf( "Role with key %s created.", $role_key ) ); + WP_CLI::success( sprintf( "Role with key '%s' created.", $role_key ) ); } } else { WP_CLI::error( "Role couldn't be created." ); @@ -194,13 +196,13 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * - * # Delete approver role + * # Delete approver role. * $ wp role delete approver - * Success: Role with key approver deleted. + * Success: Role with key 'approver' deleted. * - * # Delete productadmin role + * # Delete productadmin role. * wp role delete productadmin - * Success: Role with key productadmin deleted. + * Success: Role with key 'productadmin' deleted. */ public function delete( $args ) { global $wp_roles; @@ -217,9 +219,9 @@ public function delete( $args ) { // Note: remove_role() doesn't indicate success or otherwise, so we have to // check ourselves if ( ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::success( sprintf( "Role with key %s deleted.", $role_key ) ); + WP_CLI::success( sprintf( "Role with key '%s' deleted.", $role_key ) ); else - WP_CLI::error( sprintf( "Role with key %s could not be deleted.", $role_key ) ); + WP_CLI::error( sprintf( "Role with key '%s' could not be deleted.", $role_key ) ); } @@ -236,11 +238,11 @@ public function delete( $args ) { * * ## EXAMPLES * - * # Reset role + * # Reset role. * $ wp role reset administrator author contributor * Success: Reset 1/3 roles. * - * # Reset all default roles + * # Reset all default roles. * $ wp role reset --all * Success: All default roles reset. */ @@ -259,7 +261,7 @@ public function reset( $args, $assoc_args ) { $all_roles = array_keys( $wp_roles->roles ); $preserve_args = $args; - // get our default roles + // Get our default roles. $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); $before = array(); @@ -296,12 +298,12 @@ public function reset( $args, $assoc_args ) { } } - // no roles were unset, bail + // No roles were unset, bail. if ( count( $default_roles ) == count( $preserve ) ) { WP_CLI::error( 'Must specify a default role to reset.' ); } - // for the roles we're not resetting + // For the roles we're not resetting. foreach ( $preserve as $k => $role ) { /* save roles * if get_role is null @@ -313,17 +315,17 @@ public function reset( $args, $assoc_args ) { remove_role( $role ); } - // put back all default roles and capabilities + // Put back all default roles and capabilities. populate_roles(); - // restore the preserved roles + // Restore the preserved roles. foreach ( $preserve as $k => $roleobj ) { - // re-remove after populating + // Re-remove after populating. if ( is_a( $roleobj, 'WP_Role' ) ) { remove_role( $roleobj->name ); add_role( $roleobj->name, ucwords( $roleobj->name ), $roleobj->capabilities ); } else { - // when not an object, that means the role didn't exist before + // When not an object, that means the role didn't exist before. remove_role( $roleobj ); } } From 489e3a21885a9597643d958be75b4f0e0cab64b0 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 20 Sep 2016 17:14:52 +0545 Subject: [PATCH 4925/5359] Update test to reflect message change in role commands --- features/roles.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 2c6a9fb34..03c25ef69 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -13,7 +13,7 @@ Feature: Manage WordPress roles When I run `wp role create reporter Reporter` Then STDOUT should be: """ - Success: Role with key reporter created. + Success: Role with key 'reporter' created. """ Scenario: Resetting a role @@ -110,7 +110,7 @@ Feature: Manage WordPress roles When I run `wp role create reporter Reporter --clone=author` Then STDOUT should be: """ - Success: Role with key reporter created. Cloned capabilities from author. + Success: Role with key 'reporter' created. Cloned capabilities from 'author'. """ When I run `wp role list` From eaed277a53b0eeaf72981152597a8eaceb621278 Mon Sep 17 00:00:00 2001 From: Brad Parbs <brad@bradparbs.com> Date: Tue, 20 Sep 2016 09:15:27 -0500 Subject: [PATCH 4926/5359] Update version of WP-CLI in README for example commands. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85d3be575..0ede78df5 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ WP-CLI root dir: /home/wp-cli/.wp-cli WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ WP-CLI global config: /home/wp-cli/.wp-cli/config.yml WP-CLI project config: -WP-CLI version: 0.23.0 +WP-CLI version: 0.24.1 ``` ### Updating From f98a6175b2e774e1f954d85ff3e0c28779def34e Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 21 Sep 2016 18:19:25 +0200 Subject: [PATCH 4927/5359] Use `get_blog_details()` for the site URL when creating a new site. This ensures that the correct site URL is returned when the `wpmu_new_blog` action is used to change site details. Fixes #3415. --- features/site.feature | 2 +- php/commands/site.php | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/features/site.feature b/features/site.feature index 03d62de2c..024c23322 100644 --- a/features/site.feature +++ b/features/site.feature @@ -90,7 +90,7 @@ Feature: Manage sites in a multisite installation When I run `wp site create --slug=first` Then STDOUT should be: """ - Success: Site 2 created: example.com/first/ + Success: Site 2 created: http://example.com/first/ """ When I run `wp site delete --slug=first --yes` diff --git a/php/commands/site.php b/php/commands/site.php index 3fad43491..b39e44b25 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -290,7 +290,7 @@ function delete( $args, $assoc_args ) { * ## EXAMPLES * * $ wp site create --slug=example - * Success: Site 3 created: www.example.com/example/ + * Success: Site 3 created: http://www.example.com/example/ */ public function create( $_, $assoc_args ) { if ( !is_multisite() ) { @@ -386,10 +386,12 @@ public function create( $_, $assoc_args ) { WP_CLI::error( $id->get_error_message() ); } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $id ); - else - WP_CLI::success( "Site $id created: $url" ); + } else { + $blog = get_blog_details( $blog_id ); + WP_CLI::success( "Site $id created: $blog->siteurl" ); + } } /** From d86956ff86f6520ba68c4a58117dca71c6e0a08a Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 21 Sep 2016 20:01:41 +0200 Subject: [PATCH 4928/5359] Move session fetching into its own helper method. --- php/commands/user-session.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 69d0c1f2c..c0b7d7cc0 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -86,27 +86,31 @@ public function list_( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); $formatter = $this->get_formatter( $assoc_args ); $manager = WP_Session_Tokens::get_instance( $user->ID ); - - $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); - $get_sessions->setAccessible( true ); - $sessions = $get_sessions->invoke( $manager ); + $sessions = $this->get_all_sessions( $manager ); if ( 'ids' == $formatter->format ) { echo implode( ' ', array_keys( $sessions ) ); } else if ( 'count' === $formatter->format ) { $formatter->display_items( $sessions ); } else { - $it = array_map( function( $session, $token ) { - $session['token'] = $token; - $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); - $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); - return $session; - }, $sessions, array_keys( $sessions ) ); - - $formatter->display_items( $it ); + $formatter->display_items( $sessions ); } } + protected function get_all_sessions( WP_Session_Tokens $manager ) { + $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); + $get_sessions->setAccessible( true ); + $sessions = $get_sessions->invoke( $manager ); + + array_walk( $sessions, function( & $session, $token ) { + $session['token'] = $token; + $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); + $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); + } ); + + return $sessions; + } + private function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->fields ); } From 3e6b1b32c3cbb5a0368dff872aa0b4abb24af556 Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 21 Sep 2016 20:01:50 +0200 Subject: [PATCH 4929/5359] Remove an unnecessary separate condition for displaying the session count. --- php/commands/user-session.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index c0b7d7cc0..be261528d 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -90,8 +90,6 @@ public function list_( $args, $assoc_args ) { if ( 'ids' == $formatter->format ) { echo implode( ' ', array_keys( $sessions ) ); - } else if ( 'count' === $formatter->format ) { - $formatter->display_items( $sessions ); } else { $formatter->display_items( $sessions ); } From 745b05cc8438861c502ea61a8a64fd24079f057c Mon Sep 17 00:00:00 2001 From: John Blackbourn <john@johnblackbourn.com> Date: Wed, 21 Sep 2016 20:02:33 +0200 Subject: [PATCH 4930/5359] Switch to `wp user session destroy` with flags for the session token or all sessions. --- php/commands/user-session.php | 66 +++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index be261528d..72ed12b9f 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -21,27 +21,67 @@ public function __construct() { } /** - * Destroy all sessions for the given user. + * Destroy a session for the given user. * * ## OPTIONS * * <user> * : User ID, user email, or user login. * + * [<token>] + * : The token of the session to destroy. Defaults to the most recently created session. + * + * [--all] + * : Destroy all of the user's sessions. + * * ## EXAMPLES * - * # Destroy a user's sessions - * $ wp user session destroy-all admin - * Success: Destroyed all sessions. + * # Destroy the most recent session of the given user + * $ wp user session destroy admin + * Success: Destroyed session. 3 sessions remaining. * - * @subcommand destroy-all + * # Destroy a specific session of the given user + * $ wp user session destroy admin e073ad8540a9c2... + * Success: Destroyed session. 2 sessions remaining. + * + * # Destroy all the sessions of the given user + * $ wp user session destroy admin --all + * Success: Destroyed all sessions. */ - public function destroy_all( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $manager = WP_Session_Tokens::get_instance( $user->ID ); - $sessions = $manager->destroy_all(); + public function destroy( $args, $assoc_args ) { + $user = $this->fetcher->get_check( $args[0] ); + $token = \WP_CLI\Utils\get_flag_value( $args, 1, null ); + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); + $manager = WP_Session_Tokens::get_instance( $user->ID ); - WP_CLI::success( 'Destroyed all sessions.' ); + if ( $token && $all ) { + WP_CLI::error( 'The --all flag cannot be specified along with a session token.' ); + } + + if ( $all ) { + $manager->destroy_all(); + $remaining = count( $manager->get_all() ); + WP_CLI::success( sprintf( 'Destroyed all sessions. %s remaining.', $remaining ) ); + return; + } + + $sessions = $this->get_all_sessions( $manager ); + + if ( ! $token ) { + if ( empty( $sessions ) ) { + WP_CLI::success( 'No sessions to destroy.' ); + } + $token = end( $sessions )['token']; + } + + if ( ! isset( $sessions[ $token ] ) ) { + WP_CLI::error( 'Session not found.' ); + } + + $this->destroy_session( $manager, $token ); + $remaining = count( $manager->get_all() ); + + WP_CLI::success( sprintf( 'Destroyed session. %s remaining.', $remaining ) ); } /** @@ -109,6 +149,12 @@ protected function get_all_sessions( WP_Session_Tokens $manager ) { return $sessions; } + protected function destroy_session( WP_Session_Tokens $manager, $token ) { + $update_session = new ReflectionMethod( $manager, 'update_session' ); + $update_session->setAccessible( true ); + return $update_session->invoke( $manager, $token, null ); + } + private function get_formatter( &$assoc_args ) { return new \WP_CLI\Formatter( $assoc_args, $this->fields ); } From 7fd350a4520029933da5da7cb0d311053fe3e02a Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 21 Sep 2016 20:10:31 +0200 Subject: [PATCH 4931/5359] Use correct variable for the site ID. --- php/commands/site.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/site.php b/php/commands/site.php index b39e44b25..438f26381 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -389,7 +389,7 @@ public function create( $_, $assoc_args ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $id ); } else { - $blog = get_blog_details( $blog_id ); + $blog = get_blog_details( $id ); WP_CLI::success( "Site $id created: $blog->siteurl" ); } } From ed70c32b0ce3ea557d2c3cd038666fa20cfba8ee Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 22 Sep 2016 13:59:52 +0545 Subject: [PATCH 4932/5359] Update installing message for package install command --- php/commands/package.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 73542b771..c15284e39 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -40,7 +40,7 @@ * * # Install the latest development version of the package * $ wp package install wp-cli/server-command - * Installing wp-cli/server-command (dev-master) + * Installing package wp-cli/server-command (dev-master) * Updating /home/person/.wp-cli/packages/composer.json to require the package... * Using Composer to install the package... * --- @@ -137,7 +137,7 @@ public function browse( $_, $assoc_args ) { * * # Install the latest development version * $ wp package install wp-cli/server-command - * Installing wp-cli/server-command (dev-master) + * Installing package wp-cli/server-command (dev-master) * Updating /home/person/.wp-cli/packages/composer.json to require the package... * Using Composer to install the package... * --- @@ -169,7 +169,7 @@ public function install( $args, $assoc_args ) { if ( ! $package ) { WP_CLI::error( "Invalid package." ); } else { - WP_CLI::log( sprintf( "Installing %s (%s)", $package_name, $version ) ); + WP_CLI::log( sprintf( "Installing package %s (%s)", $package_name, $version ) ); } try { From 40e79f657c7aadabbcf646c84c4c5334ecf062a2 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 22 Sep 2016 14:28:56 +0545 Subject: [PATCH 4933/5359] Change message from Error to Warning --- features/package-install.feature | 2 +- php/WP_CLI/PackageManagerEventSubscriber.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index a2bcbbec7..4f54fff4e 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -71,7 +71,7 @@ Feature: Install WP-CLI packages When I run `wp package install trendwerk/faker` Then STDOUT should contain: """ - Error: trendwerk/faker dev-master requires nelmio/alice + Warning: trendwerk/faker dev-master requires nelmio/alice """ And STDOUT should contain: """ diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index 057013573..3159d421e 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -43,7 +43,7 @@ public static function post_install( PackageEvent $event ) { } if ( ! empty( $composer_error ) ) { - WP_CLI::log( sprintf( " - Error: %s", $composer_error ) ); + WP_CLI::log( sprintf( " - Warning: %s", $composer_error ) ); } } From be0c26bc3f7c0f168ab2f45572b2454ca634f7d9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 22 Sep 2016 16:02:00 +0545 Subject: [PATCH 4934/5359] Doc improvements in cli commands --- php/commands/cli.php | 61 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 03e907acd..4a8c254e6 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -9,20 +9,20 @@ * * ## EXAMPLES * - * # Display CLI version + * # Display CLI version. * $ wp cli version - * WP-CLI 0.23.1 + * WP-CLI 0.24.1 * - * # Check for update + * # Check for update. * $ wp cli check-update * Success: WP-CLI is at the latest version. * - * # Update CLI + * # Update CLI. * $ wp cli update - * You have version 0.23.0. Would you like to update to 0.23.1? [y/n] y - * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar... + * You have version 0.24.0. Would you like to update to 0.24.1? [y/n] y + * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar... * New version works. Proceeding to replace. - * Success: Updated WP-CLI to 0.23.1 + * Success: Updated WP-CLI to 0.24.1. * * @when before_wp_load */ @@ -51,8 +51,9 @@ private function command_to_array( $command ) { * * ## EXAMPLES * + * # Display CLI version. * $ wp cli version - * WP-CLI 0.23.1 + * WP-CLI 0.24.1 */ public function version() { WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); @@ -74,6 +75,7 @@ public function version() { * * ## EXAMPLES * + * # Display various data about the CLI environment. * $ wp cli info * PHP binary: /usr/bin/php5 * PHP version: 5.5.9-1ubuntu4.16 @@ -82,7 +84,7 @@ public function version() { * WP-CLI packages dir: /home/person/.wp-cli/packages/ * WP-CLI global config: * WP-CLI project config: - * WP-CLI version: 0.23.1 + * WP-CLI version: 0.24.1 */ public function info( $_, $assoc_args ) { $php_bin = WP_CLI::get_php_binary(); @@ -122,13 +124,13 @@ public function info( $_, $assoc_args ) { * ## OPTIONS * * [--patch] - * : Only list patch updates + * : Only list patch updates. * * [--minor] - * : Only list minor updates + * : Only list minor updates. * * [--major] - * : Only list major updates + * : Only list major updates. * * [--field=<field>] * : Prints the value of a single field for each update. @@ -150,16 +152,16 @@ public function info( $_, $assoc_args ) { * * ## EXAMPLES * - * # Check for update + * # Check for update. * $ wp cli check-update * Success: WP-CLI is at the latest version. * - * # Check for update and new version is available + * # Check for update and new version is available. * $ wp cli check-update * +---------+-------------+-------------------------------------------------------------------------------+ * | version | update_type | package_url | * +---------+-------------+-------------------------------------------------------------------------------+ - * | 0.23.1 | patch | https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar | + * | 0.24.1 | patch | https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar | * +---------+-------------+-------------------------------------------------------------------------------+ * * @subcommand check-update @@ -185,27 +187,28 @@ public function check_update( $_, $assoc_args ) { * ## OPTIONS * * [--patch] - * : Only perform patch updates + * : Only perform patch updates. * * [--minor] - * : Only perform minor updates + * : Only perform minor updates. * * [--major] - * : Only perform major updates + * : Only perform major updates. * * [--nightly] * : Update to the latest built version of the master branch. Potentially unstable. * * [--yes] - * : Do not prompt for confirmation + * : Do not prompt for confirmation. * * ## EXAMPLES * + * # Update CLI. * $ wp cli update - * You have version 0.23.0. Would you like to update to 0.23.1? [y/n] y - * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.23.1/wp-cli-0.23.1.phar... + * You have version 0.24.0. Would you like to update to 0.24.1? [y/n] y + * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar... * New version works. Proceeding to replace. - * Success: Updated WP-CLI to 0.23.1 + * Success: Updated WP-CLI to 0.24.1. */ public function update( $_, $assoc_args ) { if ( ! Utils\inside_phar() ) { @@ -250,7 +253,7 @@ public function update( $_, $assoc_args ) { $headers = array(); $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'timeout' => 600, // 10 minutes ought to be enough for everybody. 'filename' => $temp ); @@ -274,7 +277,7 @@ public function update( $_, $assoc_args ) { WP_CLI::error( sprintf( "Cannot chmod %s.", $temp ) ); } - class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the file we no longer have access to this class + class_exists( '\cli\Colors' ); // This autoloads \cli\Colors - after we move the file we no longer have access to this class. if ( false === @rename( $temp, $old_phar ) ) { WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); @@ -289,7 +292,7 @@ class_exists( '\cli\Colors' ); // this autoloads \cli\Colors - after we move the } /** - * Returns update information + * Returns update information. */ private function get_updates( $assoc_args ) { $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; @@ -316,7 +319,7 @@ private function get_updates( $assoc_args ) { ); foreach ( $release_data as $release ) { - // get rid of leading "v" if there is one set + // Get rid of leading "v" if there is one set. $release_version = $release->tag_name; if ( 'v' === substr( $release_version, 0, 1 ) ) { $release_version = ltrim( $release_version, 'v' ); @@ -388,6 +391,7 @@ private function get_updates( $assoc_args ) { * * ## EXAMPLES * + * # Dump the list of global parameters. * $ wp cli param-dump --format=var_export * array ( * 'path' => @@ -432,7 +436,7 @@ function param_dump( $_, $assoc_args ) { * * ## EXAMPLES * - * # Dump the list of installed commands + * # Dump the list of installed commands. * $ wp cli cmd-dump * {"name":"wp","description":"Manage WordPress through the command-line.","longdesc":"\n\n## GLOBAL PARAMETERS\n\n --path=<path>\n Path to the WordPress files.\n\n --ssh=<ssh>\n Perform operation against a remote server over SSH.\n\n --url=<url>\n Pretend request came from given URL. In multisite, this argument is how the target site is specified. \n\n --user=<id|login|email>\n * @@ -504,7 +508,7 @@ public function alias( $_, $assoc_args ) { } /** - * Get a string representing the type of update being checked for + * Get a string representing the type of update being checked for. */ private function get_update_type_str( $assoc_args ) { $update_type = ' '; @@ -520,4 +524,3 @@ private function get_update_type_str( $assoc_args ) { } WP_CLI::add_command( 'cli', 'CLI_Command' ); - From f6a6f712e67f04465aa0b53b14d6b386b1eb3c73 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Thu, 22 Sep 2016 17:27:17 +0200 Subject: [PATCH 4935/5359] Don't expect a trailing slash. --- features/site.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/site.feature b/features/site.feature index 024c23322..c1cecbecf 100644 --- a/features/site.feature +++ b/features/site.feature @@ -90,7 +90,7 @@ Feature: Manage sites in a multisite installation When I run `wp site create --slug=first` Then STDOUT should be: """ - Success: Site 2 created: http://example.com/first/ + Success: Site 2 created: http://example.com/first """ When I run `wp site delete --slug=first --yes` From 01bebd9c9589721f7e96df9a0713fda647bc79e2 Mon Sep 17 00:00:00 2001 From: Nikolay Yordanov <me@nyordanov.com> Date: Fri, 23 Sep 2016 10:42:16 +0100 Subject: [PATCH 4936/5359] Make Media_Command::_process_regeneration() $progress argument required --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 051e37139..c3bf4b334 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -275,7 +275,7 @@ private function _make_copy( $path ) { return $filename; } - private function _process_regeneration( $id, $skip_delete = false, $only_missing = false, $progress = '' ) { + private function _process_regeneration( $id, $skip_delete = false, $only_missing = false, $progress ) { $fullsizepath = get_attached_file( $id ); From 0e91b011c026dd218dbcaa3aeb3860f5b6c1cd4c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 23 Sep 2016 04:49:54 -0700 Subject: [PATCH 4937/5359] Cleanup `Media_Command` methods * Remove unnecessary `_` prefix from private methods * Remove default argument values, because values are always passed --- php/commands/media.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index c3bf4b334..97fb39ebc 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -91,7 +91,7 @@ function regenerate( $args, $assoc_args = array() ) { $errored = false; foreach ( $images->posts as $number => $id ) { - if ( ! $this->_process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { + if ( ! $this->process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { $errored = true; } } @@ -186,7 +186,7 @@ function import( $args, $assoc_args = array() ) { WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." ); break; } - $tempfile = $this->_make_copy( $file ); + $tempfile = $this->make_copy( $file ); } else { $tempfile = download_url( $file ); } @@ -262,7 +262,7 @@ function import( $args, $assoc_args = array() ) { } // wp_tempnam() inexplicably forces a .tmp extension, which spoils MIME type detection - private function _make_copy( $path ) { + private function make_copy( $path ) { $dir = get_temp_dir(); $filename = basename( $path ); if ( empty( $filename ) ) @@ -275,7 +275,7 @@ private function _make_copy( $path ) { return $filename; } - private function _process_regeneration( $id, $skip_delete = false, $only_missing = false, $progress ) { + private function process_regeneration( $id, $skip_delete, $only_missing, $progress ) { $fullsizepath = get_attached_file( $id ); From 9cb32f54fcb3bc995eeb57d7246ad53cf0102c6c Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Fri, 23 Sep 2016 14:13:36 +0200 Subject: [PATCH 4938/5359] Add trailing slash to site URL in success messages --- features/site.feature | 6 +++--- php/commands/site.php | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/features/site.feature b/features/site.feature index c1cecbecf..4f1074343 100644 --- a/features/site.feature +++ b/features/site.feature @@ -59,7 +59,7 @@ Feature: Manage sites in a multisite installation When I run `wp site delete {SITE_ID} --yes` Then STDOUT should be: """ - Success: The site at 'http://example.com/first' was deleted. + Success: The site at 'http://example.com/first/' was deleted. """ When I try the previous command again @@ -90,13 +90,13 @@ Feature: Manage sites in a multisite installation When I run `wp site create --slug=first` Then STDOUT should be: """ - Success: Site 2 created: http://example.com/first + Success: Site 2 created: http://example.com/first/ """ When I run `wp site delete --slug=first --yes` Then STDOUT should be: """ - Success: The site at 'http://example.com/first' was deleted. + Success: The site at 'http://example.com/first/' was deleted. """ When I try the previous command again diff --git a/php/commands/site.php b/php/commands/site.php index 438f26381..2abb9424b 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -257,11 +257,13 @@ function delete( $args, $assoc_args ) { WP_CLI::error( "Site not found." ); } - WP_CLI::confirm( "Are you sure you want to delete the '$blog->siteurl' site?", $assoc_args ); + $site_url = trailingslashit( $blog->siteurl ); + + WP_CLI::confirm( "Are you sure you want to delete the '$site_url' site?", $assoc_args ); wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'keep-tables' ) ); - WP_CLI::success( "The site at '$blog->siteurl' was deleted." ); + WP_CLI::success( "The site at '$site_url' was deleted." ); } /** @@ -389,8 +391,8 @@ public function create( $_, $assoc_args ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $id ); } else { - $blog = get_blog_details( $id ); - WP_CLI::success( "Site $id created: $blog->siteurl" ); + $site_url = trailingslashit( get_site_url( $id ) ); + WP_CLI::success( "Site $id created: $site_url" ); } } From 427d3141b7b6331f813030b402050bd04e79eb4e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 23 Sep 2016 05:25:03 -0700 Subject: [PATCH 4939/5359] Ensure `ProcessRun` is loaded as a part of the test suite bootstrap --- features/bootstrap/FeatureContext.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b4a186e67..c9846ae4c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -12,6 +12,7 @@ if ( file_exists( __DIR__ . '/utils.php' ) ) { require_once __DIR__ . '/utils.php'; require_once __DIR__ . '/Process.php'; + require_once __DIR__ . '/ProcessRun.php'; $project_composer = dirname( dirname( dirname( __FILE__ ) ) ) . '/composer.json'; if ( file_exists( $project_composer ) ) { $composer = json_decode( file_get_contents( $project_composer ) ); @@ -30,6 +31,7 @@ } else { require_once __DIR__ . '/../../php/utils.php'; require_once __DIR__ . '/../../php/WP_CLI/Process.php'; + require_once __DIR__ . '/../../php/WP_CLI/ProcessRun.php'; require_once __DIR__ . '/../../vendor/autoload.php'; } From da917e02773654921d49c917cf25df963f493587 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 26 Sep 2016 16:39:06 +0545 Subject: [PATCH 4940/5359] Change installing message in composer dependency --- php/WP_CLI/PackageManagerEventSubscriber.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index 3159d421e..fb540ee89 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -23,7 +23,8 @@ public static function getSubscribedEvents() { } public static function pre_install( PackageEvent $event ) { - WP_CLI::log( ' - Installing package' ); + $operation_message = $event->getOperation()->__toString(); + WP_CLI::log( ' - ' . $operation_message ); } public static function post_install( PackageEvent $event ) { From 2926e7222b859c6b286e5984421fd1533ef7f4a4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 26 Sep 2016 16:22:27 -0700 Subject: [PATCH 4941/5359] Drop erroneous `@github-api` label on this scenario --- features/cli.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/cli.feature b/features/cli.feature index 84046f49e..38f3052e5 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -115,7 +115,6 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 - @github-api Scenario: Dump the list of global parameters with values Given a WP install From a42dc55db7a0753a8f4ea4589aa6295f0b2762e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 26 Sep 2016 16:29:25 -0700 Subject: [PATCH 4942/5359] Proxy Github API requests through `https://github-api.wp-cli.org` --- ci/behat-tags.php | 3 --- php/commands/cli.php | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 14e52e3e8..4e319b798 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -37,9 +37,6 @@ function version_tags( $prefix, $current, $operator = '<' ) { version_tags( 'less-than-php', PHP_VERSION, '>' ) ); -# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -$skip_tags[] = '@github-api'; - if ( !empty( $skip_tags ) ) { echo '--tags=~' . implode( '&&~', $skip_tags ); } diff --git a/php/commands/cli.php b/php/commands/cli.php index 4a8c254e6..cc87c5e95 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -295,7 +295,7 @@ class_exists( '\cli\Colors' ); // This autoloads \cli\Colors - after we move the * Returns update information. */ private function get_updates( $assoc_args ) { - $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; + $url = 'https://github-api.wp-cli.org/repos/wp-cli/wp-cli/releases'; $options = array( 'timeout' => 30 From 8dfabad6a438e81da461b67c17509a4b60f339e7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 27 Sep 2016 05:54:20 -0700 Subject: [PATCH 4943/5359] Update test with new global params --- features/cli.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cli.feature b/features/cli.feature index 38f3052e5..bd5216d95 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -121,7 +121,7 @@ Feature: `wp cli` tasks When I run `wp cli param-dump --with-values | grep -o '"current":' | uniq -c` Then STDOUT should be: """ - 15 "current": + 17 "current": """ And STDERR should be empty And the return code should be 0 From 8402b5a42bd1149a10fd92f7d154b763454e7782 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 27 Sep 2016 12:35:50 -0700 Subject: [PATCH 4944/5359] Send the headers in the proper argument --- php/commands/cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index cc87c5e95..4dd6ee1f4 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -304,7 +304,7 @@ private function get_updates( $assoc_args ) { $headers = array( 'Accept' => 'application/json' ); - $response = Utils\http_request( 'GET', $url, $headers, $options ); + $response = Utils\http_request( 'GET', $url, array(), $headers, $options ); if ( ! $response->success || 200 !== $response->status_code ) { WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d).", $response->status_code ) ); From b4d478fad137f8b65adf43a4dfce2f97d50be8f0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 27 Sep 2016 13:31:00 -0700 Subject: [PATCH 4945/5359] Provide more visibility into why this is failing --- ci/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index ce5030ef7..c75a9aa4c 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -8,7 +8,7 @@ vendor/bin/phpunit BEHAT_TAGS=$(php ci/behat-tags.php) # Run the functional tests -vendor/bin/behat --format progress $BEHAT_TAGS --strict +vendor/bin/behat --format progress $BEHAT_TAGS --strict --stop-on-failure # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From 27b12339edac58e9f4f014bed17ed21b4b190563 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 27 Sep 2016 14:02:27 -0700 Subject: [PATCH 4946/5359] Update dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.9) - Installing symfony/yaml (v2.8.11) Downloading: 100% - Removing symfony/filesystem (v2.8.9) - Installing symfony/filesystem (v2.8.11) Downloading: 100% - Removing symfony/config (v2.8.9) - Installing symfony/config (v2.8.11) Downloading: 100% - Removing symfony/dependency-injection (v2.8.9) - Installing symfony/dependency-injection (v2.8.11) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.9) - Installing symfony/event-dispatcher (v2.8.11) Loading from cache - Removing symfony/translation (v2.8.9) - Installing symfony/translation (v2.8.11) Downloading: 100% - Removing symfony/process (v2.8.9) - Installing symfony/process (v2.8.11) Downloading: 100% - Removing symfony/finder (v2.8.9) - Installing symfony/finder (v2.8.11) Downloading: 100% - Removing symfony/console (v2.8.9) - Installing symfony/console (v2.8.11) Downloading: 100% - Removing seld/jsonlint (1.4.0) - Installing seld/jsonlint (1.4.1) Downloading: 100% - Removing psr/log (1.0.0) - Installing psr/log (1.0.1) Downloading: 100% - Removing composer/semver (1.4.1) - Installing composer/semver (1.4.2) Downloading: 100% - Removing composer/ca-bundle (1.0.3) - Installing composer/ca-bundle (1.0.4) Downloading: 100% - Removing composer/composer (1.2.0) - Installing composer/composer (1.2.1) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 146 +++++++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 68 deletions(-) diff --git a/composer.lock b/composer.lock index 2a4ab1c38..51a476f45 100644 --- a/composer.lock +++ b/composer.lock @@ -9,16 +9,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12" + "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/5df9ed0ed0c9506ea6404a23450854e5df15cc12", - "reference": "5df9ed0ed0c9506ea6404a23450854e5df15cc12", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/ec21a59414b99501e723b63fd664aa8ead9c5680", + "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680", "shasum": "" }, "require": { @@ -27,6 +27,7 @@ "php": "^5.3.2 || ^7.0" }, "require-dev": { + "psr/log": "^1.0", "symfony/process": "^2.5 || ^3.0" }, "suggest": { @@ -62,20 +63,20 @@ "ssl", "tls" ], - "time": "2016-07-18 23:07:53" + "time": "2016-09-04 19:00:06" }, { "name": "composer/composer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "b49a006748a460f8dae6500ec80ed021501ce969" + "reference": "16422c4b1ac4286f7caecf5211136dc073191672" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/b49a006748a460f8dae6500ec80ed021501ce969", - "reference": "b49a006748a460f8dae6500ec80ed021501ce969", + "url": "https://api.github.com/repos/composer/composer/zipball/16422c4b1ac4286f7caecf5211136dc073191672", + "reference": "16422c4b1ac4286f7caecf5211136dc073191672", "shasum": "" }, "require": { @@ -139,20 +140,20 @@ "dependency", "package" ], - "time": "2016-07-18 23:28:52" + "time": "2016-09-12 09:27:20" }, { "name": "composer/semver", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98" + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", + "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", "shasum": "" }, "require": { @@ -201,7 +202,7 @@ "validation", "versioning" ], - "time": "2016-06-02 09:04:51" + "time": "2016-08-30 16:08:34" }, { "name": "composer/spdx-licenses", @@ -466,22 +467,30 @@ }, { "name": "psr/log", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "5277094ed527a1c4477177d102fe4c53551953e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", + "reference": "5277094ed527a1c4477177d102fe4c53551953e0", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "Psr\\Log\\": "" + "psr-4": { + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -495,12 +504,13 @@ } ], "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2016-09-19 16:02:08" }, { "name": "ramsey/array_column", @@ -646,16 +656,16 @@ }, { "name": "seld/jsonlint", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "66834d3e3566bb5798db7294619388786ae99394" + "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", - "reference": "66834d3e3566bb5798db7294619388786ae99394", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e827b5254d3e58c736ea2c5616710983d80b0b70", + "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70", "shasum": "" }, "require": { @@ -688,7 +698,7 @@ "parser", "validator" ], - "time": "2015-11-21 02:21:41" + "time": "2016-09-14 15:17:56" }, { "name": "seld/phar-utils", @@ -736,16 +746,16 @@ }, { "name": "symfony/config", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4" + "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4275ef5b59f18959df0eee3991e9ca0cc208ffd4", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4", + "url": "https://api.github.com/repos/symfony/config/zipball/005bf10c156335ede2e89fb9a9ee10a0b742bc84", + "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84", "shasum": "" }, "require": { @@ -785,20 +795,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-07-26 08:02:44" + "time": "2016-08-16 14:56:08" }, { "name": "symfony/console", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "36e62335caca8a6e909c5c5bac4a8128149911c9" + "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/36e62335caca8a6e909c5c5bac4a8128149911c9", - "reference": "36e62335caca8a6e909c5c5bac4a8128149911c9", + "url": "https://api.github.com/repos/symfony/console/zipball/3d3e4fa5f0614c8e45220e5de80332322e33bd90", + "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90", "shasum": "" }, "require": { @@ -845,20 +855,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:20:35" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/dependency-injection", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12" + "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f2b5a00d176f6a201dc430375c0ef37706ea3d12", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0a732a9cafc30e54077967da4d019e1d618a8cb9", + "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9", "shasum": "" }, "require": { @@ -908,11 +918,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:20:35" + "time": "2016-09-06 23:19:39" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -972,16 +982,16 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd" + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ab4c3f085c8f5a56536845bf985c4cef30bf75fd", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/44b499521defddf2eae17a18c811bbdae4f98bdf", + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf", "shasum": "" }, "require": { @@ -1017,20 +1027,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-07-20 05:41:28" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/finder", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "60804d88691e4a73bbbb3035eb1d9f075c5c2c10" + "reference": "bec5533e6ed650547d6ec8de4b541dc9929066f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/60804d88691e4a73bbbb3035eb1d9f075c5c2c10", - "reference": "60804d88691e4a73bbbb3035eb1d9f075c5c2c10", + "url": "https://api.github.com/repos/symfony/finder/zipball/bec5533e6ed650547d6ec8de4b541dc9929066f7", + "reference": "bec5533e6ed650547d6ec8de4b541dc9929066f7", "shasum": "" }, "require": { @@ -1066,7 +1076,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-07-26 08:02:44" + "time": "2016-08-26 11:57:43" }, { "name": "symfony/polyfill-mbstring", @@ -1129,16 +1139,16 @@ }, { "name": "symfony/process", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c" + "reference": "05a03ed27073638658cab9405d99a67dd1014987" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d20332e43e8774ff8870b394f3dd6020cc7f8e0c", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c", + "url": "https://api.github.com/repos/symfony/process/zipball/05a03ed27073638658cab9405d99a67dd1014987", + "reference": "05a03ed27073638658cab9405d99a67dd1014987", "shasum": "" }, "require": { @@ -1174,20 +1184,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-07-28 11:13:19" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/translation", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "32b0c824da6df065f43b0c458dc505940e98a7f1" + "reference": "bf0ff95faa9b6c0708efc1986255e3608d0ed3c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/32b0c824da6df065f43b0c458dc505940e98a7f1", - "reference": "32b0c824da6df065f43b0c458dc505940e98a7f1", + "url": "https://api.github.com/repos/symfony/translation/zipball/bf0ff95faa9b6c0708efc1986255e3608d0ed3c7", + "reference": "bf0ff95faa9b6c0708efc1986255e3608d0ed3c7", "shasum": "" }, "require": { @@ -1238,20 +1248,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:20:35" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/yaml", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d" + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0ceab136f43ed9d3e97b3eea32a7855dc50c121d", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e7540734bad981fe59f8ef14b6fc194ae9df8d9c", + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c", "shasum": "" }, "require": { @@ -1287,7 +1297,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-07-17 09:06:15" + "time": "2016-09-02 01:57:56" }, { "name": "wp-cli/php-cli-tools", From ba7d805ab83a884f3c11b16801acd2df33e2793d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 27 Sep 2016 14:44:52 -0700 Subject: [PATCH 4947/5359] Revert "Provide more visibility into why this is failing" This reverts commit b4d478fad137f8b65adf43a4dfce2f97d50be8f0. --- ci/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.sh b/ci/test.sh index c75a9aa4c..ce5030ef7 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -8,7 +8,7 @@ vendor/bin/phpunit BEHAT_TAGS=$(php ci/behat-tags.php) # Run the functional tests -vendor/bin/behat --format progress $BEHAT_TAGS --strict --stop-on-failure +vendor/bin/behat --format progress $BEHAT_TAGS --strict # Run CodeSniffer ./codesniffer/scripts/phpcs --standard=./ci/ php/ From fb971ec7352287665dbebd46db3a4fb5061744fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 28 Sep 2016 07:18:39 -0700 Subject: [PATCH 4948/5359] Use `--stable` to install or reinstall the latest stable version Skips the update check, so this both lets you roll back from `--nightly` or reinstall an existing stable copy. Updates docs too, which were completely incorrect. --- features/cli.feature | 37 +++++++++++++++++++++++++++++++++++++ php/commands/cli.php | 29 +++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/features/cli.feature b/features/cli.feature index bd5216d95..3e5797ea2 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -115,6 +115,43 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 + @github-api + Scenario: Install WP-CLI stable + Given an empty directory + And a new Phar with version "0.14.0" + And a session file: + """ + y + """ + + When I run `{PHAR_PATH} cli check-update --minor --field=version` + Then STDOUT should not be empty + And save STDOUT as {UPDATE_VERSION} + + When I run `{PHAR_PATH} cli update --stable < session` + Then STDOUT should contain: + """ + You have version 0.14.0. Would you like to update to the latest stable release? [y/n] + """ + And STDOUT should contain: + """ + Success: Updated WP-CLI to the latest stable release. + """ + And STDERR should be empty + And the return code should be 0 + + When I run `{PHAR_PATH} cli check-update` + Then STDOUT should be: + """ + Success: WP-CLI is at the latest version. + """ + + When I run `{PHAR_PATH} cli version` + Then STDOUT should be: + """ + WP-CLI {UPDATE_VERSION} + """ + Scenario: Dump the list of global parameters with values Given a WP install diff --git a/php/commands/cli.php b/php/commands/cli.php index 4dd6ee1f4..c49714c94 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -182,7 +182,19 @@ public function check_update( $_, $assoc_args ) { } /** - * Fetch most recent update matching the requirements. Returns the available versions if there are updates, or empty if no update available. + * Update WP-CLI. + * + * Default behavior is to check the releases API for a newer version, and + * prompt if one is available. + * + * Use `--stable` to install or reinstall the latest stable version. + * + * Use `--nightly` to install the latest built version of the master branch. + * While not recommended for production, nightly contains the latest and + * greatest, and should be stable enough for development and staging + * environments. + * + * Only works for the Phar installation mechanism. * * ## OPTIONS * @@ -195,6 +207,9 @@ public function check_update( $_, $assoc_args ) { * [--major] * : Only perform major updates. * + * [--stable] + * : Update to the latest stable release. Skips update check. + * * [--nightly] * : Update to the latest built version of the master branch. Potentially unstable. * @@ -223,12 +238,12 @@ public function update( $_, $assoc_args ) { WP_CLI::error( sprintf( "%s is not writable by current user.", dirname( $old_phar ) ) ); } - if ( isset( $assoc_args['nightly'] ) ) { - + if ( Utils\get_flag_value( $assoc_args, 'nightly' ) ) { WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest nightly?', WP_CLI_VERSION ), $assoc_args ); - $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar'; - + } else if ( Utils\get_flag_value( $assoc_args, 'stable' ) ) { + WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest stable release?', WP_CLI_VERSION ), $assoc_args ); + $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar'; } else { $updates = $this->get_updates( $assoc_args ); @@ -283,8 +298,10 @@ class_exists( '\cli\Colors' ); // This autoloads \cli\Colors - after we move the WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); } - if ( isset( $assoc_args['nightly'] ) ) { + if ( Utils\get_flag_value( $assoc_args, 'nightly' ) ) { $updated_version = 'the latest nightly release'; + } else if ( Utils\get_flag_value( $assoc_args, 'stable' ) ) { + $updated_version = 'the latest stable release'; } else { $updated_version = $newest['version']; } From 94be892c73bd02ee0d2391d1c6f427ef226a40e9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 28 Sep 2016 09:16:46 -0700 Subject: [PATCH 4949/5359] Don't run this test on PHP 7 There appears to be some problem with fetching updates in PHP 7 that likely isn't a problem with WP-CLI --- features/cli.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cli.feature b/features/cli.feature index 3e5797ea2..83fd15d63 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -115,7 +115,7 @@ Feature: `wp cli` tasks And STDERR should be empty And the return code should be 0 - @github-api + @github-api @less-than-php-7 Scenario: Install WP-CLI stable Given an empty directory And a new Phar with version "0.14.0" From 0465167e07accd31c4039c3a69bef2bfa068a97b Mon Sep 17 00:00:00 2001 From: Fabian Isele <uxdmm@student.kit.edu> Date: Fri, 30 Sep 2016 09:44:18 +0200 Subject: [PATCH 4950/5359] Dropping database if one exists if there is already a database, the script throws an error thereupon I inserted that check for existance and drop the database if necessary. --- templates/install-wp-tests.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index cf709c276..36b72893e 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -116,7 +116,13 @@ install_db() { EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" fi fi - + + # drop database if already exists + RESULT = `mysqlshow --user="$DB_USER" --password="$DB_PASS"$EXTRA --port $DB_SOCK_OR_PORT -h $DB_HOSTNAME $DB_NAME| grep -v Wildcard | grep -o $DB_NAME` + if [ "$RESULT" == "$DB_NAME" ] ; then + echo y | mysqladmin --user="$DB_USER" --password="$DB_PASS"$EXTRA --port $DB_SOCK_OR_PORT -h $DB_HOSTNAME DROP $DB_NAME + fi + # create database mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA } From 1ef43af367685eed53effe88e895b02a2a9c8ee1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 30 Sep 2016 05:14:38 -0700 Subject: [PATCH 4951/5359] Revert "Dropping database if one exists" --- templates/install-wp-tests.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 36b72893e..cf709c276 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -116,13 +116,7 @@ install_db() { EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" fi fi - - # drop database if already exists - RESULT = `mysqlshow --user="$DB_USER" --password="$DB_PASS"$EXTRA --port $DB_SOCK_OR_PORT -h $DB_HOSTNAME $DB_NAME| grep -v Wildcard | grep -o $DB_NAME` - if [ "$RESULT" == "$DB_NAME" ] ; then - echo y | mysqladmin --user="$DB_USER" --password="$DB_PASS"$EXTRA --port $DB_SOCK_OR_PORT -h $DB_HOSTNAME DROP $DB_NAME - fi - + # create database mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA } From fa2cdc458cadbbdc2e832f2e56604331b903b60e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 30 Sep 2016 05:47:47 -0700 Subject: [PATCH 4952/5359] Handle `dead_db()` error on `nocache_headers` filter WordPress conveniently calls `nocache_headers()` inside of `dead_db()`, which means we can swoop in and display the database error ourselves. `enable_wp_debug_mode_checks` is too early, because `wp_die()` isn't yet defined for `$wpdb` to call. --- features/framework.feature | 25 +++++++++++++++++++++++++ php/WP_CLI/Runner.php | 14 ++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/features/framework.feature b/features/framework.feature index 93f12ad92..83732a03e 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -178,3 +178,28 @@ Feature: Load WP-CLI """ http://example.com """ + + Scenario: Handle error when WordPress cannot connect to the database host + Given a WP install + And a wp-debug.php file: + """ + <?php + define( 'WP_DEBUG', true ); + """ + And a invalid-host.php file: + """ + <?php + define( 'DB_HOST', 'localghost' ); + """ + + When I try `wp --require=invalid-host.php option get home` + Then STDERR should contain: + """ + Error: Error establishing a database connection + """ + + When I try `wp --require=invalid-host.php --require=wp-debug.php option get home` + Then STDERR should contain: + """ + Error: Error establishing a database connection + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index a292884a3..cb6c1aa73 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1053,6 +1053,12 @@ private function setup_bootstrap_hooks() { WP_CLI::add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); WP_CLI::add_wp_hook( 'nocache_headers', function( $headers ){ + // WordPress might be calling nocache_headers() because of a dead db + global $wpdb; + if ( ! empty( $wpdb->error ) ) { + Utils\wp_die_handler( $wpdb->error ); + } + // Otherwise, WP might be calling nocache_headers() because WP isn't installed Utils\wp_not_installed(); return $headers; }); @@ -1092,14 +1098,6 @@ private function setup_bootstrap_hooks() { // Use our own debug mode handling instead of WP core WP_CLI::add_wp_hook( 'enable_wp_debug_mode_checks', function( $ret ) { Utils\wp_debug_mode(); - - // Check to see of wpdb is errored, instead of waiting for dead_db() - require_wp_db(); - global $wpdb; - if ( ! empty( $wpdb->error ) ) { - Utils\wp_die_handler( $wpdb->error ); - } - return false; }); From 721163be7f069b2fc355c1c3077757d6aef22603 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 30 Sep 2016 05:59:41 -0700 Subject: [PATCH 4953/5359] Add testcase to assert `wp db query` runs before WP loads --- features/db-query.feature | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 features/db-query.feature diff --git a/features/db-query.feature b/features/db-query.feature new file mode 100644 index 000000000..f8e3d4e82 --- /dev/null +++ b/features/db-query.feature @@ -0,0 +1,23 @@ +Feature: Query the database with WordPress' MySQL config + + Scenario: Database querying shouldn't load any plugins + Given a WP install + And a wp-content/mu-plugins/error.php file: + """ + <?php + WP_CLI::error( "Plugin loaded." ); + """ + + When I try `wp option get home` + Then STDERR should be: + """ + Error: Plugin loaded. + """ + + When I run `wp db query "SELECT COUNT(ID) FROM wp_posts;"` + Then STDOUT should be: + """ + COUNT(ID) + 2 + """ + And STDERR should be empty From 9858e856655222022f0fb2b346fd808d2bb4c9fc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 30 Sep 2016 08:26:10 -0700 Subject: [PATCH 4954/5359] Trim the message for better WP 3.7.11 compat --- php/utils-wp.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index dd08dfb84..416fa2851 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -54,6 +54,7 @@ function wp_die_handler( $message ) { $message = $message->get_error_message(); } + $message = trim( $message ); if ( preg_match( '|^\<h1>(.+?)</h1>|', $message, $matches ) ) { $message = $matches[1]; } From bddd3a1f810b055bdc2b882191632749c4101433 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 30 Sep 2016 15:07:40 -0700 Subject: [PATCH 4955/5359] Revert "Proxy Github API requests through `https://github-api.wp-cli.org`" --- ci/behat-tags.php | 3 +++ php/commands/cli.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 4e319b798..14e52e3e8 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -37,6 +37,9 @@ function version_tags( $prefix, $current, $operator = '<' ) { version_tags( 'less-than-php', PHP_VERSION, '>' ) ); +# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +$skip_tags[] = '@github-api'; + if ( !empty( $skip_tags ) ) { echo '--tags=~' . implode( '&&~', $skip_tags ); } diff --git a/php/commands/cli.php b/php/commands/cli.php index c49714c94..03996e886 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -312,7 +312,7 @@ class_exists( '\cli\Colors' ); // This autoloads \cli\Colors - after we move the * Returns update information. */ private function get_updates( $assoc_args ) { - $url = 'https://github-api.wp-cli.org/repos/wp-cli/wp-cli/releases'; + $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; $options = array( 'timeout' => 30 @@ -321,7 +321,7 @@ private function get_updates( $assoc_args ) { $headers = array( 'Accept' => 'application/json' ); - $response = Utils\http_request( 'GET', $url, array(), $headers, $options ); + $response = Utils\http_request( 'GET', $url, $headers, $options ); if ( ! $response->success || 200 !== $response->status_code ) { WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d).", $response->status_code ) ); From 29c1beb3754d63b22a009f10d047d2af63f36c17 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 3 Oct 2016 11:39:49 -0700 Subject: [PATCH 4956/5359] Fix uncaught exception when `wp_mail()` is used `SERVER_NAME` --- php/WP_CLI/Runner.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cb6c1aa73..552610663 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -1135,6 +1135,18 @@ private function setup_bootstrap_hooks() { }, 0 ); } + // Avoid uncaught exception when using wp_mail() without defined $_SERVER['SERVER_NAME'] + WP_CLI::add_wp_hook( 'wp_mail_from', function( $from_email ){ + if ( 'wordpress@' === $from_email ) { + $sitename = strtolower( parse_url( site_url(), PHP_URL_HOST ) ); + if ( substr( $sitename, 0, 4 ) == 'www.' ) { + $sitename = substr( $sitename, 4 ); + } + $from_email = 'wordpress@' . $sitename; + } + return $from_email; + }); + } /** From ac65baf66a81afc575711514e1897f7dd2d58079 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 3 Oct 2016 11:54:19 -0700 Subject: [PATCH 4957/5359] Failing test case for #3444 --- features/aliases.feature | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index a801e8527..d8992f6ed 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -244,3 +244,34 @@ Feature: Create shortcuts to specific WordPress installs """ Error: Cannot use '@all' when no aliases are registered. """ + + Scenario: Alias for a subsite of a multisite install + Given a WP multisite subdomain install + And a wp-cli.yml file: + """ + url: example.com + @subsite: + url: subsite.example.com + """ + + When I run `wp site create --slug=subsite` + Then STDOUT should not be empty + + When I run `wp option get siteurl` + Then STDOUT should be: + """ + http://example.com + """ + + When I run `wp @subsite option get siteurl` + Then STDOUT should be: + """ + http://subsite.example.com + """ + + When I try `wp @subsite option get siteurl --url=subsite.example.com` + Then STDERR should be: + """ + Error: Parameter errors: + unknown --url parameter + """ From 8e1630c4e1b84478a3cdda5b4f135ac437d57e6b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 3 Oct 2016 12:09:13 -0700 Subject: [PATCH 4958/5359] When an alias is used, WP-CLI should skip url, et al registered in config.yml --- php/WP_CLI/Configurator.php | 7 +++++-- php/WP_CLI/Runner.php | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index f259528d1..d9c0147c0 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -213,10 +213,10 @@ private function assoc_arg_to_runtime_config( $key, $value, &$runtime_config ) { * * @param string $path Path to YAML file. */ - public function merge_yml( $path ) { + public function merge_yml( $path, $current_alias = null ) { $yaml = self::load_yml( $path ); if ( ! empty( $yaml['_']['inherit'] ) ) { - $this->merge_yml( $yaml['_']['inherit'] ); + $this->merge_yml( $yaml['_']['inherit'], $current_alias ); } foreach ( $yaml as $key => $value ) { if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { @@ -251,6 +251,9 @@ public function merge_yml( $path ) { self::arrayify( $value ); $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); } else { + if ( $current_alias && in_array( $key, self::$alias_spec, true ) ) { + continue; + } $this->config[ $key ] = $value; } } diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index cb6c1aa73..a913d2541 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -632,10 +632,10 @@ private function init_config() { $this->global_config_path = $this->get_global_config_path(); $this->project_config_path = $this->get_project_config_path(); - $configurator->merge_yml( $this->global_config_path ); + $configurator->merge_yml( $this->global_config_path, $this->alias ); $config = $configurator->to_array(); $this->_required_files['global'] = $config[0]['require']; - $configurator->merge_yml( $this->project_config_path ); + $configurator->merge_yml( $this->project_config_path, $this->alias ); $config = $configurator->to_array(); $this->_required_files['project'] = $config[0]['require']; } From f8d8ebcc4d5d4f58b4e947aceab4a960394b4ed5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 3 Oct 2016 15:56:40 -0700 Subject: [PATCH 4959/5359] Fix behavior of installing Github-based projects when already installed If the plugin is already installed, then we should error and require the `--force` parameter to be used. --- features/plugin-install.feature | 18 +++++++++++++++++- php/WP_CLI/CommandWithUpgrade.php | 28 +++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 4221cdceb..cd9a42a6d 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -10,7 +10,7 @@ Feature: Install WordPress plugins """ And STDOUT should contain: """ - Moved Github-based project from 'one-time-login-master' to 'one-time-login'. + Renamed Github-based project from 'one-time-login-master' to 'one-time-login'. """ And STDOUT should contain: """ @@ -20,6 +20,22 @@ Feature: Install WordPress plugins And the wp-content/plugins/one-time-login directory should exist And the wp-content/plugins/one-time-login-master directory should not exist + When I try `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip` + Then STDERR should contain: + """ + Warning: Destination folder already exists + """ + And the wp-content/plugins/one-time-login directory should exist + And the wp-content/plugins/one-time-login-master directory should not exist + + When I run `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip --force` + Then STDOUT should contain: + """ + Plugin updated successfully. + """ + And the wp-content/plugins/one-time-login directory should exist + And the wp-content/plugins/one-time-login-master directory should not exist + Scenario: Installing respects WP_PROXY_HOST and WP_PROXY_PORT Given a WP install And a invalid-proxy-details.php file: diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 6d2e3e54e..fa3b59f3d 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -137,21 +137,31 @@ function install( $args, $assoc_args ) { // Install from local or remote zip file $file_upgrader = $this->get_upgrader( $assoc_args ); - if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { - $slug = $file_upgrader->result['destination_name']; - // Remove the branch name from the director for Github URLs - if ( strpos( $local_or_remote_zip_file, '://' ) !== false + $filter = false; + if ( strpos( $local_or_remote_zip_file, '://' ) !== false && 'github.com' === parse_url( $local_or_remote_zip_file, PHP_URL_HOST ) ) { + $filter = function( $source, $remote_source, $upgrader ) use ( $local_or_remote_zip_file ) { $branch_length = strlen( pathinfo( $local_or_remote_zip_file, PATHINFO_FILENAME ) ); if ( $branch_length ) { - $new_path = substr( rtrim( $file_upgrader->result['destination'], '/' ), 0, - ( $branch_length + 1 ) ) . '/'; - if ( $GLOBALS['wp_filesystem']->move( $file_upgrader->result['destination'], $new_path ) ) { - $slug = basename( $new_path ); - WP_CLI::log( "Moved Github-based project from '" . basename( $file_upgrader->result['destination_name'] ) . "' to '" . $slug . "'." ); + $new_path = substr( rtrim( $source, '/' ), 0, - ( $branch_length + 1 ) ) . '/'; + if ( $GLOBALS['wp_filesystem']->move( $source, $new_path ) ) { + WP_CLI::log( "Renamed Github-based project from '" . basename( $source ) . "' to '" . basename( $new_path ) . "'." ); + return $new_path; + } else { + return new \WP_CLI( 'wpcli_install_gitub', "Couldn't move Github-based project to appropriate directory." ); } } - } + return $source; + }; + add_filter( 'upgrader_source_selection', $filter, 10, 3 ); + } + + if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { + $slug = $file_upgrader->result['destination_name']; $result = true; + if ( $filter ) { + remove_filter( 'upgrader_source_selection', $filter, 10, 3 ); + } } } else { // Assume a plugin/theme slug from the WordPress.org repository has been specified From 7899a758217b5d130492ea9d0a981462e76d3cbb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 3 Oct 2016 16:14:38 -0700 Subject: [PATCH 4960/5359] Use `--no-transients` to ignore transients when listing options Or, if you want to list transients, use `wp option list --transients` --- features/option-list.feature | 33 +++++++++++++++++++++++++++++++++ php/commands/option.php | 29 ++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 features/option-list.feature diff --git a/features/option-list.feature b/features/option-list.feature new file mode 100644 index 000000000..3d3ddf552 --- /dev/null +++ b/features/option-list.feature @@ -0,0 +1,33 @@ +Feature: List WordPress options + + Scenario: Using the `--transients` flag + Given a WP install + And I run `wp transient set wp_transient_flag wp_transient_flag` + + When I run `wp option list --no-transients` + Then STDOUT should not contain: + """ + wp_transient_flag + """ + And STDOUT should not contain: + """ + _transient + """ + And STDOUT should contain: + """ + siteurl + """ + + When I run `wp option list --transients` + Then STDOUT should contain: + """ + wp_transient_flag + """ + And STDOUT should contain: + """ + _transient + """ + And STDOUT should not contain: + """ + siteurl + """ diff --git a/php/commands/option.php b/php/commands/option.php index 8c1848aac..390179f36 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Manage options. * @@ -131,6 +133,9 @@ public function add( $args, $assoc_args ) { * [--autoload=<value>] * : Match only autoload options when value is on, and only not-autoload option when off. * + * [--transients] + * : List only transients. Use `--no-transients` to ignore all transients. + * * [--field=<field>] * : Prints the value of a single field. * @@ -227,13 +232,23 @@ public function list_( $args, $assoc_args ) { } } - $results = $wpdb->get_results( - $wpdb->prepare( - "SELECT `option_name`,`option_value`,`autoload`" . $size_query - . " FROM `$wpdb->options` WHERE `option_name` LIKE %s" . $autoload_query, - $pattern - ) - ); + $transients_query = ''; + if ( true === Utils\get_flag_value( $assoc_args, 'transients', null ) ) { + $transients_query = " AND option_name LIKE '\_transient\_%' + OR option_name LIKE '\_site\_transient\_%'"; + } else if ( false === Utils\get_flag_value( $assoc_args, 'transients', null ) ) { + $transients_query = " AND option_name NOT LIKE '\_transient\_%' + AND option_name NOT LIKE '\_site\_transient\_%'"; + } + + $where = ''; + if ( $pattern ) { + $where .= $wpdb->prepare( "WHERE `option_name` LIKE %s", $pattern ); + } + $where .= $autoload_query . $transients_query; + + $results = $wpdb->get_results( "SELECT `option_name`,`option_value`,`autoload`" . $size_query + . " FROM `$wpdb->options` {$where}" ); if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { WP_CLI::line( $results[0]->size_bytes ); From 877fa4a5ad42da98e2d5672ba234bd6cd960fdc9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 5 Oct 2016 10:07:58 +0545 Subject: [PATCH 4961/5359] Add exclude parameter in option list --- php/commands/option.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/php/commands/option.php b/php/commands/option.php index 390179f36..04908ce39 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -130,6 +130,9 @@ public function add( $args, $assoc_args ) { * [--search=<pattern>] * : Use wildcards ( * and ? ) to match option name. * + * [--exclude=<pattern>] + * : Pattern to exclude. Use wildcards ( * and ? ) to match option name. + * * [--autoload=<value>] * : Match only autoload options when value is on, and only not-autoload option when off. * @@ -202,6 +205,7 @@ public function list_( $args, $assoc_args ) { global $wpdb; $pattern = '%'; + $exclude = ''; $fields = array( 'option_name', 'option_value' ); $size_query = ",LENGTH(option_value) AS `size_bytes`"; $autoload_query = ''; @@ -213,6 +217,12 @@ public function list_( $args, $assoc_args ) { $pattern = str_replace( '?', '_', $pattern ); } + if ( isset( $assoc_args['exclude'] ) ) { + $exclude = self::esc_like( $assoc_args['exclude'] ); + $exclude = str_replace( '*', '%', $exclude ); + $exclude = str_replace( '?', '_', $exclude ); + } + if ( isset( $assoc_args['fields'] ) ) { $fields = explode( ',', $assoc_args['fields'] ); } @@ -245,6 +255,10 @@ public function list_( $args, $assoc_args ) { if ( $pattern ) { $where .= $wpdb->prepare( "WHERE `option_name` LIKE %s", $pattern ); } + + if ( $exclude ) { + $where .= $wpdb->prepare( " AND `option_name` NOT LIKE %s", $exclude ); + } $where .= $autoload_query . $transients_query; $results = $wpdb->get_results( "SELECT `option_name`,`option_value`,`autoload`" . $size_query From 6802d988dbf950369de222862bcad220519523d9 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Wed, 5 Oct 2016 10:30:33 +0545 Subject: [PATCH 4962/5359] Add test for exclude pattern in option list --- features/option-list.feature | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/features/option-list.feature b/features/option-list.feature index 3d3ddf552..9d5b5bca9 100644 --- a/features/option-list.feature +++ b/features/option-list.feature @@ -31,3 +31,36 @@ Feature: List WordPress options """ siteurl """ + + Scenario: List option with exclude pattern + Given a WP install + + When I run `wp option add sample_test_field_one sample_test_field_value_one` + And I run `wp option add sample_test_field_two sample_test_field_value_two` + And I run `wp option list --search="sample_test_field_*" --format=csv` + Then STDOUT should be: + """ + option_name,option_value + sample_test_field_one,sample_test_field_value_one + sample_test_field_two,sample_test_field_value_two + """ + + When I run `wp option list --search="sample_test_field_*" --exclude="*field_one" --format=csv` + Then STDOUT should be: + """ + option_name,option_value + sample_test_field_two,sample_test_field_value_two + """ + + When I run `wp option list` + Then STDOUT should contain: + """ + sample_test_field_one + """ + + When I run `wp option list --exclude="sample_test_field_one"` + Then STDOUT should not contain: + """ + sample_test_field_one + """ + From 8a195d7fa90f28167219339bd59184657b51c390 Mon Sep 17 00:00:00 2001 From: Bernhard Kau <github@kau-boys.de> Date: Wed, 5 Oct 2016 15:08:00 +0200 Subject: [PATCH 4963/5359] updated the labels to match the ones for tags Those are the values that are defined in the CODEX as well. --- templates/taxonomy.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache index 549c46ed2..cb00da9d1 100644 --- a/templates/taxonomy.mustache +++ b/templates/taxonomy.mustache @@ -24,7 +24,7 @@ 'update_item' => __( 'Update {{label}}', '{{textdomain}}' ), 'add_new_item' => __( 'New {{label}}', '{{textdomain}}' ), 'new_item_name' => __( 'New {{label}}', '{{textdomain}}' ), - 'separate_items_with_commas' => __( '{{label_plural_ucfirst}} separated by comma', '{{textdomain}}' ), + 'separate_items_with_commas' => __( 'Separate {{label_plural}} with commas', '{{textdomain}}' ), 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), 'not_found' => __( 'No {{label_plural}} found.', '{{textdomain}}' ), From ead64014d4f9d59c19e493b05942a47e118f2bec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 10 Oct 2016 12:47:05 -0700 Subject: [PATCH 4964/5359] Use correct default user for MySQL on CircleCI See https://circleci.com/docs/build-image-precise/#databases --- templates/plugin-circle.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache index 75c0aebcb..33f6f7feb 100644 --- a/templates/plugin-circle.mustache +++ b/templates/plugin-circle.mustache @@ -8,6 +8,6 @@ dependencies: test: pre: - - bash bin/install-wp-tests.sh wordpress_test root '' localhost latest + - bash bin/install-wp-tests.sh wordpress_test ubuntu '' 127.0.0.1 latest override: - phpunit From 176900a04cecb59624c50daeb0140d0b0686a07d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 10 Oct 2016 16:20:29 -0700 Subject: [PATCH 4965/5359] Warn when `WP_CLI::launch()` ends up with `return_code=-1` --- php/class-wp-cli.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 72073bf3f..3be5e3901 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -783,6 +783,10 @@ public static function launch( $command, $exit_on_error = true, $return_detailed $proc = Process::create( $command ); $results = $proc->run(); + if ( -1 == $results->return_code ) { + self::warning( "Spawned process returned exit code {$results->return_code}, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); + } + if ( $results->return_code && $exit_on_error ) exit( $results->return_code ); From d8e6feea9857bf6e5a68f6f09ec750dacf63855a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 10 Oct 2016 16:34:01 -0700 Subject: [PATCH 4966/5359] Provide more verbosity in `wp_die()` handler This gives the end user more detail when a database connection fails, instead of a cryptic message. --- features/db.feature | 2 +- features/framework.feature | 4 ++-- php/utils-wp.php | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/features/db.feature b/features/db.feature index 5c33e6d00..ae97e5933 100644 --- a/features/db.feature +++ b/features/db.feature @@ -9,7 +9,7 @@ Feature: Perform database operations Then STDOUT should be empty And STDERR should be: """ - Error: Can’t select database + Error: Can’t select database. We were able to connect to the database server (which means your username and password is okay) but not able to select the `wp_cli_test` database. """ When I run `wp db create` diff --git a/features/framework.feature b/features/framework.feature index 83732a03e..701d0027c 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -195,11 +195,11 @@ Feature: Load WP-CLI When I try `wp --require=invalid-host.php option get home` Then STDERR should contain: """ - Error: Error establishing a database connection + Error: Error establishing a database connection. This either means that the username and password information in your `wp-config.php` file is incorrect or we can’t contact the database server at `localghost`. This could mean your host’s database server is down. """ When I try `wp --require=invalid-host.php --require=wp-debug.php option get home` Then STDERR should contain: """ - Error: Error establishing a database connection + Error: Error establishing a database connection. This either means that the username and password information in your `wp-config.php` file is incorrect or we can’t contact the database server at `localghost`. This could mean your host’s database server is down. """ diff --git a/php/utils-wp.php b/php/utils-wp.php index 416fa2851..2b5ffbd38 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -54,11 +54,20 @@ function wp_die_handler( $message ) { $message = $message->get_error_message(); } - $message = trim( $message ); - if ( preg_match( '|^\<h1>(.+?)</h1>|', $message, $matches ) ) { - $message = $matches[1]; + $original_message = $message = trim( $message ); + if ( preg_match( '|^\<h1>(.+?)</h1>|', $original_message, $matches ) ) { + $message = $matches[1] . '.'; + } + if ( preg_match( '|\<p>(.+?)</p>|', $original_message, $matches ) ) { + $message .= ' ' . $matches[1]; } + $search_replace = array( + '<code>' => '`', + '</code>' => '`', + ); + $message = str_replace( array_keys( $search_replace ), array_values( $search_replace ), $message ); + $message = strip_tags( $message ); $message = html_entity_decode( $message, ENT_COMPAT, 'UTF-8' ); \WP_CLI::error( $message ); From 111cb0cb14aedb6837d4f6173e655c8218742f6e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 10 Oct 2016 16:37:42 -0700 Subject: [PATCH 4967/5359] Update Composer dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/finder (v2.8.11) - Installing symfony/finder (v2.8.12) Downloading: 100% - Removing symfony/yaml (v2.8.11) - Installing symfony/yaml (v2.8.12) Loading from cache - Removing symfony/filesystem (v2.8.11) - Installing symfony/filesystem (v2.8.12) Loading from cache - Removing symfony/config (v2.8.11) - Installing symfony/config (v2.8.12) Downloading: 100% - Removing psr/log (1.0.1) - Installing psr/log (1.0.2) Downloading: 100% - Installing symfony/debug (v3.0.9) Downloading: 100% - Removing symfony/console (v2.8.11) - Installing symfony/console (v2.8.12) Downloading: 100% - Removing symfony/dependency-injection (v2.8.11) - Installing symfony/dependency-injection (v2.8.12) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.11) - Installing symfony/event-dispatcher (v2.8.12) Loading from cache - Removing symfony/process (v2.8.11) - Installing symfony/process (v2.8.12) Downloading: 100% - Removing symfony/translation (v2.8.11) - Installing symfony/translation (v2.8.12) Loading from cache - Removing composer/spdx-licenses (1.1.4) - Installing composer/spdx-licenses (1.1.5) Downloading: 100% - Updating rmccue/requests dev-master (fb5b517 => 0048f3c) Checking out 0048f3c0b33add0f924cf857961a2f02f4a802b6 Writing lock file Generating autoload files ``` --- composer.json | 2 +- composer.lock | 148 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 104 insertions(+), 46 deletions(-) diff --git a/composer.json b/composer.json index a917e9ffd..1aea359cd 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", "ramsey/array_column": "~1.1", - "rmccue/requests" : "dev-master#fb5b51797ff881dd67f630cf9fd9e14b757a9e29 as 1.6.1", + "rmccue/requests" : "dev-master#0048f3c0b33add0f924cf857961a2f02f4a802b6 as 1.6.1", "symfony/finder": "~2.7", "symfony/yaml": "~2.7", "symfony/filesystem": "~2.7", diff --git a/composer.lock b/composer.lock index 51a476f45..e8a9d8c68 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "6b2d9b856fd8d57162cccfed52b37977", - "content-hash": "48b37e62541cbdceec19bf202c77a9d1", + "hash": "d427b50385a540391ad0777d8e6748e8", + "content-hash": "58faa612d1d0340db0b65acd5aaa6183", "packages": [ { "name": "composer/ca-bundle", @@ -206,16 +206,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88" + "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/88c26372b1afac36d8db601cdf04ad8716f53d88", - "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/96c6a07b05b716e89a44529d060bc7f5c263cb13", + "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13", "shasum": "" }, "require": { @@ -263,7 +263,7 @@ "spdx", "validator" ], - "time": "2016-05-04 12:27:30" + "time": "2016-09-28 07:17:45" }, { "name": "justinrainbow/json-schema", @@ -467,16 +467,16 @@ }, { "name": "psr/log", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "5277094ed527a1c4477177d102fe4c53551953e0" + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", - "reference": "5277094ed527a1c4477177d102fe4c53551953e0", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, "require": { @@ -510,7 +510,7 @@ "psr", "psr-3" ], - "time": "2016-09-19 16:02:08" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/array_column", @@ -563,12 +563,12 @@ "source": { "type": "git", "url": "https://github.com/rmccue/Requests.git", - "reference": "fb5b51797ff881dd67f630cf9fd9e14b757a9e29" + "reference": "0048f3c0b33add0f924cf857961a2f02f4a802b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rmccue/Requests/zipball/fb5b51797ff881dd67f630cf9fd9e14b757a9e29", - "reference": "fb5b51797ff881dd67f630cf9fd9e14b757a9e29", + "url": "https://api.github.com/repos/rmccue/Requests/zipball/0048f3c0b33add0f924cf857961a2f02f4a802b6", + "reference": "0048f3c0b33add0f924cf857961a2f02f4a802b6", "shasum": "" }, "require": { @@ -604,7 +604,7 @@ "iri", "sockets" ], - "time": "2016-08-18 01:24:21" + "time": "2016-09-22 16:46:57" }, { "name": "seld/cli-prompt", @@ -746,16 +746,16 @@ }, { "name": "symfony/config", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84" + "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/005bf10c156335ede2e89fb9a9ee10a0b742bc84", - "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84", + "url": "https://api.github.com/repos/symfony/config/zipball/f8b1922bbda9d2ac86aecd649399040bce849fde", + "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde", "shasum": "" }, "require": { @@ -795,24 +795,25 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-08-16 14:56:08" + "time": "2016-09-14 20:31:12" }, { "name": "symfony/console", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90" + "reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3d3e4fa5f0614c8e45220e5de80332322e33bd90", - "reference": "3d3e4fa5f0614c8e45220e5de80332322e33bd90", + "url": "https://api.github.com/repos/symfony/console/zipball/d7a5a88178f94dcc29531ea4028ea614e35452d4", + "reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4", "shasum": "" }, "require": { "php": ">=5.3.9", + "symfony/debug": "~2.7,>=2.7.2|~3.0.0", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { @@ -855,20 +856,77 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-09-06 10:55:00" + "time": "2016-09-28 00:10:16" + }, + { + "name": "symfony/debug", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "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 Debug Component", + "homepage": "https://symfony.com", + "time": "2016-07-30 07:22:48" }, { "name": "symfony/dependency-injection", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9" + "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0a732a9cafc30e54077967da4d019e1d618a8cb9", - "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ee9ec9ac2b046462d341e9de7c4346142d335e75", + "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75", "shasum": "" }, "require": { @@ -918,11 +976,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-09-06 23:19:39" + "time": "2016-09-24 09:47:20" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -982,7 +1040,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -1031,16 +1089,16 @@ }, { "name": "symfony/finder", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "bec5533e6ed650547d6ec8de4b541dc9929066f7" + "reference": "bc24c8f5674c6f6841f2856b70e5d60784be5691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/bec5533e6ed650547d6ec8de4b541dc9929066f7", - "reference": "bec5533e6ed650547d6ec8de4b541dc9929066f7", + "url": "https://api.github.com/repos/symfony/finder/zipball/bc24c8f5674c6f6841f2856b70e5d60784be5691", + "reference": "bc24c8f5674c6f6841f2856b70e5d60784be5691", "shasum": "" }, "require": { @@ -1076,7 +1134,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-08-26 11:57:43" + "time": "2016-09-28 00:10:16" }, { "name": "symfony/polyfill-mbstring", @@ -1139,16 +1197,16 @@ }, { "name": "symfony/process", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "05a03ed27073638658cab9405d99a67dd1014987" + "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/05a03ed27073638658cab9405d99a67dd1014987", - "reference": "05a03ed27073638658cab9405d99a67dd1014987", + "url": "https://api.github.com/repos/symfony/process/zipball/024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f", + "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f", "shasum": "" }, "require": { @@ -1184,11 +1242,11 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-09-06 10:55:00" + "time": "2016-09-29 14:03:54" }, { "name": "symfony/translation", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", @@ -1252,7 +1310,7 @@ }, { "name": "symfony/yaml", - "version": "v2.8.11", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From 22ffdeef9b977ad372029f54fa0bde81a7c517e7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 11 Oct 2016 06:20:45 -0700 Subject: [PATCH 4968/5359] Fix PHPCS issue --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3be5e3901..1dc6a34e6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -784,7 +784,7 @@ public static function launch( $command, $exit_on_error = true, $return_detailed $results = $proc->run(); if ( -1 == $results->return_code ) { - self::warning( "Spawned process returned exit code {$results->return_code}, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); + self::warning( "Spawned process returned exit code {$results->return_code}, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); } if ( $results->return_code && $exit_on_error ) From 800f87d4e387fa707da9c6c499a8a86574e8e932 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 11 Oct 2016 06:25:38 -0700 Subject: [PATCH 4969/5359] Lock to symfony/debug that supports PHP 5.3 --- composer.json | 1 + composer.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 1aea359cd..e659e3b81 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "symfony/filesystem": "~2.7", "symfony/config": "~2.7", "symfony/console": "~2.7", + "symfony/debug": "~2.7", "symfony/dependency-injection": "~2.7", "symfony/event-dispatcher": "~2.7", "symfony/process": "~2.1", diff --git a/composer.lock b/composer.lock index e8a9d8c68..996c39d13 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d427b50385a540391ad0777d8e6748e8", - "content-hash": "58faa612d1d0340db0b65acd5aaa6183", + "hash": "4218a2e198b39594cc1f9500ebfdac42", + "content-hash": "ef98f5250ac1a487cdea910258300473", "packages": [ { "name": "composer/ca-bundle", @@ -860,33 +860,33 @@ }, { "name": "symfony/debug", - "version": "v3.0.9", + "version": "v2.8.12", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + "reference": "8c29235936a47473af16fb91c7c4b7b193c5693c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", - "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "url": "https://api.github.com/repos/symfony/debug/zipball/8c29235936a47473af16fb91c7c4b7b193c5693c", + "reference": "8c29235936a47473af16fb91c7c4b7b193c5693c", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": ">=5.3.9", "psr/log": "~1.0" }, "conflict": { "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" }, "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" + "symfony/class-loader": "~2.2|~3.0.0", + "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -913,7 +913,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/dependency-injection", From 2a12e9a1c4e57d1cf6543b1c2294b4a2132cc22c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 11 Oct 2016 06:34:42 -0700 Subject: [PATCH 4970/5359] Less precise check for WP 3.7.11 --- features/framework.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/framework.feature b/features/framework.feature index 701d0027c..3e1751e99 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -195,11 +195,11 @@ Feature: Load WP-CLI When I try `wp --require=invalid-host.php option get home` Then STDERR should contain: """ - Error: Error establishing a database connection. This either means that the username and password information in your `wp-config.php` file is incorrect or we can’t contact the database server at `localghost`. This could mean your host’s database server is down. + Error: Error establishing a database connection. """ When I try `wp --require=invalid-host.php --require=wp-debug.php option get home` Then STDERR should contain: """ - Error: Error establishing a database connection. This either means that the username and password information in your `wp-config.php` file is incorrect or we can’t contact the database server at `localghost`. This could mean your host’s database server is down. + Error: Error establishing a database connection. """ From c855b5f0cdf659de2c155297699cc96a8376ea84 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 11 Oct 2016 16:08:04 -0700 Subject: [PATCH 4971/5359] Use the latest version of PHPUnit on Travis, depending on PHP version --- templates/plugin-travis.mustache | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 38a8ae25a..e284e6027 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -25,5 +25,12 @@ matrix: before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION + - | + if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.0" ]]; then + composer global require "phpunit/phpunit=5.6.*" + else + composer global require "phpunit/phpunit=4.8.*" + fi + - export PATH="$HOME/.composer/vendor/bin:$PATH" script: phpunit From 072f6147bd77d7149c6856cdfceaa0d9ea179d1a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 12 Oct 2016 13:20:48 -0700 Subject: [PATCH 4972/5359] Ensure `wp core download --version=latest` produces versioned cache key --- features/core-download.feature | 15 +++++++++++++++ php/commands/core.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/core-download.feature b/features/core-download.feature index 9b244e2bf..33ef6217f 100644 --- a/features/core-download.feature +++ b/features/core-download.feature @@ -210,3 +210,18 @@ Feature: Download WordPress md5 hash verified: 90c93a15092b2d5d4c960ec1fc183e07 Success: WordPress downloaded. """ + + Scenario: Using --version=latest should produce a cache key of the version number, not 'latest' + Given an empty directory + And an empty cache + + When I run `wp core download --version=latest` + Then STDOUT should contain: + """ + Success: WordPress downloaded. + """ + + When I run `wp core version` + Then save STDOUT as {VERSION} + And the {SUITE_CACHE_DIR}/core/wordpress-latest-en_US.tar.gz file should not exist + And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist diff --git a/php/commands/core.php b/php/commands/core.php index 74168b40f..7e44795ea 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -133,7 +133,7 @@ public function download( $args, $assoc_args ) { $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); - if ( isset( $assoc_args['version'] ) ) { + if ( isset( $assoc_args['version'] ) && 'latest' !== $assoc_args['version'] ) { $version = $assoc_args['version']; $version = ( in_array( strtolower( $version ), array( 'trunk', 'nightly' ) ) ? 'nightly' : $version ); //nightly builds are only available in .zip format From 079e248b22eeee3edac15676924fd94a683a0ff3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 14 Oct 2016 05:31:00 -0700 Subject: [PATCH 4973/5359] Update Composer dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Updating rmccue/requests (dev-master 0048f3c => v1.7.0) Checking out 87932f52ffad70504d93f04f15690cf16a089546 Writing lock file Generating autoload files ``` --- composer.json | 2 +- composer.lock | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index e659e3b81..ef35d2ee8 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", "ramsey/array_column": "~1.1", - "rmccue/requests" : "dev-master#0048f3c0b33add0f924cf857961a2f02f4a802b6 as 1.6.1", + "rmccue/requests" : "~1.6", "symfony/finder": "~2.7", "symfony/yaml": "~2.7", "symfony/filesystem": "~2.7", diff --git a/composer.lock b/composer.lock index 996c39d13..977a97e13 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "4218a2e198b39594cc1f9500ebfdac42", - "content-hash": "ef98f5250ac1a487cdea910258300473", + "hash": "ce8fdbbf904758ec2297424e667a20c1", + "content-hash": "66db43f8d349f59c6dd42f72a8638b22", "packages": [ { "name": "composer/ca-bundle", @@ -559,16 +559,16 @@ }, { "name": "rmccue/requests", - "version": "dev-master", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/rmccue/Requests.git", - "reference": "0048f3c0b33add0f924cf857961a2f02f4a802b6" + "reference": "87932f52ffad70504d93f04f15690cf16a089546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rmccue/Requests/zipball/0048f3c0b33add0f924cf857961a2f02f4a802b6", - "reference": "0048f3c0b33add0f924cf857961a2f02f4a802b6", + "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546", + "reference": "87932f52ffad70504d93f04f15690cf16a089546", "shasum": "" }, "require": { @@ -604,7 +604,7 @@ "iri", "sockets" ], - "time": "2016-09-22 16:46:57" + "time": "2016-10-13 00:11:37" }, { "name": "seld/cli-prompt", @@ -1898,18 +1898,9 @@ "time": "2013-01-13 10:24:48" } ], - "aliases": [ - { - "alias": "1.6.1", - "alias_normalized": "1.6.1.0", - "version": "9999999-dev", - "package": "rmccue/requests" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "rmccue/requests": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From eecbcc5f6cbdb22fc50a88c443d7aab26b351c6a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 06:55:10 -0700 Subject: [PATCH 4974/5359] Support passing arguments to `WP_CLI::do_hook()` --- features/framework.feature | 21 +++++++++++++++++++++ php/class-wp-cli.php | 10 ++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/features/framework.feature b/features/framework.feature index 3e1751e99..636da1e6f 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -203,3 +203,24 @@ Feature: Load WP-CLI """ Error: Error establishing a database connection. """ + + Scenario: Allow WP_CLI hooks to pass arguments to callbacks + Given an empty directory + And a my-command.php file: + """ + <?php + + WP_CLI::add_hook( 'foo', function( $bar ){ + WP_CLI::log( $bar ); + }); + WP_CLI::add_command( 'my-command', function( $args ){ + WP_CLI::do_hook( 'foo', $args[0] ); + }, array( 'when' => 'before_wp_load' ) ); + """ + + When I run `wp --require=my-command.php my-command bar` + Then STDOUT should be: + """ + bar + """ + And STDERR should be empty diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 1dc6a34e6..ed5c36459 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -248,11 +248,17 @@ public static function add_hook( $when, $callback ) { public static function do_hook( $when ) { self::$hooks_passed[] = $when; - if ( !isset( self::$hooks[ $when ] ) ) + if ( !isset( self::$hooks[ $when ] ) ) { return; + } foreach ( self::$hooks[ $when ] as $callback ) { - call_user_func( $callback ); + if ( func_num_args() > 1 ) { + $args = array_slice( func_get_args(), 1 ); + call_user_func_array( $callback, $args ); + } else { + call_user_func( $callback ); + } } } From aba1586b63db91ca9f4154f5663ef1644684efd9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 07:06:12 -0700 Subject: [PATCH 4975/5359] Leave a comment as to why we're using Reflection --- php/commands/user-session.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 72ed12b9f..a8a18b48e 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -136,6 +136,7 @@ public function list_( $args, $assoc_args ) { } protected function get_all_sessions( WP_Session_Tokens $manager ) { + // Make the private session data accessible to WP-CLI $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); $get_sessions->setAccessible( true ); $sessions = $get_sessions->invoke( $manager ); From bc97b2df0f0306a435b8dfabd55d834d32807aec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 07:08:20 -0700 Subject: [PATCH 4976/5359] Fix PHP 5.3 fatal error --- php/commands/user-session.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index a8a18b48e..a65da4c36 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -71,7 +71,8 @@ public function destroy( $args, $assoc_args ) { if ( empty( $sessions ) ) { WP_CLI::success( 'No sessions to destroy.' ); } - $token = end( $sessions )['token']; + $last = end( $sessions ); + $token = $last['token']; } if ( ! isset( $sessions[ $token ] ) ) { From 8ef8e83a6952cecc55e546d5a2fd259bdad0be4f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 07:08:34 -0700 Subject: [PATCH 4977/5359] Transform to our newer options format --- php/commands/user-session.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index a65da4c36..0b422bb09 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -97,7 +97,17 @@ public function destroy( $args, $assoc_args ) { * : Limit the output to specific fields. * * [--format=<format>] - * : Accepted values: table, csv, json, count, yaml. Default: table + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - csv + * - json + * - yaml + * - count + * - ids + * --- * * ## AVAILABLE FIELDS * From 7240f2e44cc17182d79d7b59632990189af46e69 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 07:09:17 -0700 Subject: [PATCH 4978/5359] Add tests for user sessions, props @ernilambar --- features/user-session.feature | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 features/user-session.feature diff --git a/features/user-session.feature b/features/user-session.feature new file mode 100644 index 000000000..02ff727a8 --- /dev/null +++ b/features/user-session.feature @@ -0,0 +1,39 @@ +Feature: Manage user session + + Background: + Given a WP install + + Scenario: Destroy user sessions + When I run `wp eval 'wp_set_current_user(1);'` + And I run `wp eval 'wp_set_auth_cookie(1);'` + And I run `wp eval 'wp_set_current_user(1);'` + And I run `wp eval 'wp_set_auth_cookie(1);'` + And I run `wp user session list admin --format=count` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp user session destroy admin` + Then STDOUT should be: + """ + Success: Destroyed session. 1 remaining. + """ + + When I run `wp user session list admin --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp user session destroy admin --all` + Then STDOUT should be: + """ + Success: Destroyed all sessions. 0 remaining. + """ + + And I run `wp user session list admin --format=count` + Then STDOUT should be: + """ + 0 + """ From 1ba3ba7462bbe109f59d9b3cef3b2fa6bf21882a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 07:12:26 -0700 Subject: [PATCH 4979/5359] Add example for destroying all sessions for all users --- php/commands/user-session.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 0b422bb09..682f1736e 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -47,6 +47,11 @@ public function __construct() { * # Destroy all the sessions of the given user * $ wp user session destroy admin --all * Success: Destroyed all sessions. + * + * # Destroy all sessions for all users + * $ wp user list --field=ID | xargs wp user session destroy --all + * Success: Destroyed all sessions. 0 remaining. + * Success: Destroyed all sessions. 0 remaining. */ public function destroy( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); From 5c760a88fdfce7a1259eb07a177c4153ab9cdb2f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 15 Oct 2016 09:25:16 -0700 Subject: [PATCH 4980/5359] User sessions require >= WP 4.0 --- features/user-session.feature | 1 + php/commands/user-session.php | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/features/user-session.feature b/features/user-session.feature index 02ff727a8..27480e154 100644 --- a/features/user-session.feature +++ b/features/user-session.feature @@ -3,6 +3,7 @@ Feature: Manage user session Background: Given a WP install + @require-wp-4.0 Scenario: Destroy user sessions When I run `wp eval 'wp_set_current_user(1);'` And I run `wp eval 'wp_set_auth_cookie(1);'` diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 682f1736e..1e50aef82 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -178,4 +178,10 @@ private function get_formatter( &$assoc_args ) { } -WP_CLI::add_command( 'user session', 'User_Session_Command' ); +WP_CLI::add_command( 'user session', 'User_Session_Command', array( + 'before_invoke' => function() { + if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { + WP_CLI::error( "Requires WordPress 4.0 or greater." ); + } + }) +); From d503aff7d83bf90208877b548fe075b9358c2dd5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 16 Oct 2016 06:56:02 -0700 Subject: [PATCH 4981/5359] Log the current alias when executing an alias group This is helpful information for the end user. If the execution output is being passed to another system, the log can be disabled with `--quiet` --- features/aliases.feature | 9 +++++++++ php/WP_CLI/Runner.php | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/features/aliases.feature b/features/aliases.feature index d8992f6ed..32847ee9e 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -181,6 +181,15 @@ Feature: Create shortcuts to specific WordPress installs """ When I run `wp @both option get home` + Then STDOUT should be: + """ + @subdir1 + http://apple.com + @subdir2 + http://google.com + """ + + When I run `wp @both option get home --quiet` Then STDOUT should be: """ http://apple.com diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 9acc1d9bf..97aaf7be8 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -700,10 +700,9 @@ private function run_alias_group( $aliases ) { $config_path = escapeshellarg( $config_path ); foreach( $aliases as $alias ) { - + WP_CLI::log( $alias ); $args = implode( ' ', array_map( 'escapeshellarg', $this->arguments ) ); $assoc_args = Utils\assoc_args_to_str( $this->assoc_args ); - $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$alias} {$args} {$assoc_args}"; $proc = proc_open( $full_command, array( STDIN, STDOUT, STDERR ), $pipes ); proc_close( $proc ); From 33876d411807c547a86ac11f25cac799479f69b9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 16 Oct 2016 08:31:44 -0700 Subject: [PATCH 4982/5359] Update tests for new expected behavior of logging alias --- features/aliases.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index 32847ee9e..af9aa1c85 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -222,6 +222,15 @@ Feature: Create shortcuts to specific WordPress installs """ When I run `wp @all option get home` + Then STDOUT should be: + """ + @subdir1 + http://apple.com + @subdir2 + http://google.com + """ + + When I run `wp @all option get home --quiet` Then STDOUT should be: """ http://apple.com From 90f3c702c332c0f03400d16f7c585ad4dccae3bb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 16 Oct 2016 15:50:34 -0700 Subject: [PATCH 4983/5359] Add WordPress Coding Standards to newly-scaffolded plugins Installation for use in CI is essentially: ``` export PATH="$HOME/.composer/vendor/bin:$PATH" composer global require wp-coding-standards/wpcs phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs ``` --- features/scaffold.feature | 5 ++++- php/commands/scaffold.php | 1 + templates/phpcs.ruleset.xml | 10 ++++++++++ templates/plugin-circle.mustache | 6 ++++++ templates/plugin-travis.mustache | 9 +++++++-- 5 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 templates/phpcs.ruleset.xml diff --git a/features/scaffold.feature b/features/scaffold.feature index 102c866bd..2f829c550 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -306,11 +306,14 @@ Feature: WordPress code scaffolding install-wp-tests.sh """ And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist + And the {PLUGIN_DIR}/hello-world/phpcs.ruleset.xml file should exist And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist And the {PLUGIN_DIR}/hello-world/.gitlab-ci.yml file should not exist And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: """ - script: phpunit + script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') + - phpunit """ When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 96a9f2b90..eda6792f9 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -642,6 +642,7 @@ function plugin_tests( $args, $assoc_args ) { $to_copy = array( 'install-wp-tests.sh' => $bin_dir, 'phpunit.xml.dist' => $plugin_dir, + 'phpcs.ruleset.xml' => $plugin_dir, ); foreach ( $to_copy as $file => $dir ) { diff --git a/templates/phpcs.ruleset.xml b/templates/phpcs.ruleset.xml new file mode 100644 index 000000000..210c25a14 --- /dev/null +++ b/templates/phpcs.ruleset.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<ruleset name="WordPress Coding Standards for Plugins"> + <description>Generally-applicable sniffs for WordPress plugins</description> + + <rule ref="WordPress-Core" /> + <rule ref="WordPress-Docs" /> + + <exclude-pattern>*/node_modules/*</exclude-pattern> + <exclude-pattern>*/vendor/*</exclude-pattern> +</ruleset> diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache index 33f6f7feb..08647555e 100644 --- a/templates/plugin-circle.mustache +++ b/templates/plugin-circle.mustache @@ -1,6 +1,8 @@ machine: php: version: 5.6.22 + environment: + PATH: $HOME/.composer/vendor/bin:$PATH dependencies: pre: @@ -9,5 +11,9 @@ dependencies: test: pre: - bash bin/install-wp-tests.sh wordpress_test ubuntu '' 127.0.0.1 latest + - | + composer global require wp-coding-standards/wpcs + phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs override: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - phpunit diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index e284e6027..3fa9a0650 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -25,12 +25,17 @@ matrix: before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION + - export PATH="$HOME/.composer/vendor/bin:$PATH" - | if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.0" ]]; then composer global require "phpunit/phpunit=5.6.*" else composer global require "phpunit/phpunit=4.8.*" fi - - export PATH="$HOME/.composer/vendor/bin:$PATH" + - | + composer global require wp-coding-standards/wpcs + phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs -script: phpunit +script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') + - phpunit From 12b056c8de033a0cd913478a1c82abc021b2f5bb Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Mon, 17 Oct 2016 16:35:17 +0545 Subject: [PATCH 4984/5359] Add more example for media regenerate --- php/commands/media.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 97fb39ebc..4903cf85f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -36,11 +36,19 @@ class Media_Command extends WP_CLI_Command { * : Only generate thumbnails for images missing image sizes. * * [--yes] - * : Answer yes to the confirmation message. + * : Answer yes to the confirmation message. Confirmation only shows when no IDs passed as arguments. * * ## EXAMPLES * - * # Re-generate all thumbnails, without confirmation + * # Regenerate thumbnails for given attachment IDs. + * $ wp media regenerate 123 124 125 + * Found 3 images to regenerate. + * 1/3 Regenerated thumbnails for "Vertical Image" (ID 123).. + * 2/3 Regenerated thumbnails for "Horizontal Image" (ID 124).. + * 3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125).. + * Success: Finished regenerating all images. + * + * # Regenerate all thumbnails, without confirmation. * $ wp media regenerate --yes * Found 3 images to regenerate. * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). @@ -48,7 +56,7 @@ class Media_Command extends WP_CLI_Command { * Regenerated thumbnails for "Sunburst Over River" (ID 756). * Success: Finished regenerating all images. * - * # Re-generate all thumbnails that have IDs between 1000 and 2000 + * # Re-generate all thumbnails that have IDs between 1000 and 2000. * $ seq 1000 2000 | xargs wp media regenerate * Found 4 images to regenerate. * Regenerated thumbnails for "Vertical Featured Image" (ID 1027). From 55d2831439e0499089cce1a212776ea06e3040c9 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 18 Oct 2016 22:11:20 +0545 Subject: [PATCH 4985/5359] Update examples for media regenerate --- php/commands/media.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index 4903cf85f..e3529648f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -8,9 +8,9 @@ * # Re-generate all thumbnails, without confirmation. * $ wp media regenerate --yes * Found 3 images to regenerate. - * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). - * Regenerated thumbnails for "Boardwalk" (ID 757). - * Regenerated thumbnails for "Sunburst Over River" (ID 756). + * 1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). + * 2/3 Regenerated thumbnails for "Boardwalk" (ID 757). + * 3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756). * Success: Finished regenerating all images. * * # Import a local image and set it to be the featured image for a post. @@ -43,26 +43,26 @@ class Media_Command extends WP_CLI_Command { * # Regenerate thumbnails for given attachment IDs. * $ wp media regenerate 123 124 125 * Found 3 images to regenerate. - * 1/3 Regenerated thumbnails for "Vertical Image" (ID 123).. - * 2/3 Regenerated thumbnails for "Horizontal Image" (ID 124).. - * 3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125).. + * 1/3 Regenerated thumbnails for "Vertical Image" (ID 123). + * 2/3 Regenerated thumbnails for "Horizontal Image" (ID 124). + * 3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125). * Success: Finished regenerating all images. * * # Regenerate all thumbnails, without confirmation. * $ wp media regenerate --yes * Found 3 images to regenerate. - * Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). - * Regenerated thumbnails for "Boardwalk" (ID 757). - * Regenerated thumbnails for "Sunburst Over River" (ID 756). + * 1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). + * 2/3 Regenerated thumbnails for "Boardwalk" (ID 757). + * 3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756). * Success: Finished regenerating all images. * * # Re-generate all thumbnails that have IDs between 1000 and 2000. * $ seq 1000 2000 | xargs wp media regenerate * Found 4 images to regenerate. - * Regenerated thumbnails for "Vertical Featured Image" (ID 1027). - * Regenerated thumbnails for "Horizontal Featured Image" (ID 1022). - * Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045). - * Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023). + * 1/4 Regenerated thumbnails for "Vertical Featured Image" (ID 1027). + * 2/4 Regenerated thumbnails for "Horizontal Featured Image" (ID 1022). + * 3/4 Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045). + * 4/4 Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023). * Success: Finished regenerating all images. */ function regenerate( $args, $assoc_args = array() ) { @@ -287,7 +287,7 @@ private function process_regeneration( $id, $skip_delete, $only_missing, $progre $fullsizepath = get_attached_file( $id ); - $att_desc = sprintf( '"%1$s" (ID %2$d).', get_the_title( $id ), $id ); + $att_desc = sprintf( '"%1$s" (ID %2$d)', get_the_title( $id ), $id ); if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { WP_CLI::warning( "Can't find $att_desc." ); From f08ce956fea2251f0b6eba0b31f620bb64416e26 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 19 Oct 2016 13:01:59 -0700 Subject: [PATCH 4986/5359] Support `--ci=<provider>` when directly scaffolding a plugin Doing so avoids a second step of scaffolding plugin tests with a specific provider. --- features/scaffold.feature | 14 +++++++++++++- php/commands/scaffold.php | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 2f829c550..af4fe09ba 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -322,7 +322,19 @@ Feature: WordPress code scaffolding executable """ - Scenario: Scaffold plugin tests with Circle as the provider + Scenario: Scaffold plugin tests with Circle as the provider, part one + Given a WP install + And I run `wp scaffold plugin hello-world --ci=circle` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/circle.yml file should contain: + """ + version: 5.6.22 + """ + + Scenario: Scaffold plugin tests with Circle as the provider, part two Given a WP install And I run `wp scaffold plugin hello-world --skip-tests` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index eda6792f9..7068ce0b3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -449,6 +449,16 @@ private function get_output_path( $assoc_args, $subdir ) { * [--skip-tests] * : Don't generate files for unit testing. * + * [--ci=<provider>] + * : Choose a configuration file for a continuous integration provider. + * --- + * default: travis + * options: + * - travis + * - circle + * - gitlab + * --- + * * [--activate] * : Activate the newly generated plugin. * @@ -513,7 +523,7 @@ function plugin( $args, $assoc_args ) { ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { - WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir, 'force' => $force ) ); + WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir, 'ci' => $assoc_args['ci'], 'force' => $force ) ); } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { @@ -552,7 +562,7 @@ function plugin( $args, $assoc_args ) { * : Generate test files for a non-standard plugin path. If no plugin slug is specified, the directory name is used. * * [--ci=<provider>] - * : Add a configuration file for a continuous integration provider. + * : Choose a configuration file for a continuous integration provider. * --- * default: travis * options: From 8dcf167ad8ed939f5d5bbc2570171b9c2b5610bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 19 Oct 2016 13:02:58 -0700 Subject: [PATCH 4987/5359] Mention the `--ci=<provider>` args in the docs --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 7068ce0b3..58f4e00a3 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -418,7 +418,7 @@ private function get_output_path( $assoc_args, $subdir ) { * The following files are also generated if tests are not skipped using `--skip-tests`: * * * `phpunit.xml.dist` is the configuration file for PHPUnit. - * * `.travis.yml` is the configuration file for Travis CI. + * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. * * `tests/test-sample.php` is a sample file containing test cases. From 463dae6ac4b0d1a45ea500de924906b3b55a7cab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 19 Oct 2016 14:31:23 -0700 Subject: [PATCH 4988/5359] Update test for new `--ci=<provider>` argument --- features/scaffold.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index af4fe09ba..6f7901eb8 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -229,6 +229,7 @@ Feature: WordPress code scaffolding http://wp-cli.org http://wp-cli.org n + travis Y n n From 8d17ec5fd741f5bf459e6df654162009b7d64d6a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 19 Oct 2016 18:01:22 -0700 Subject: [PATCH 4989/5359] Only check `options` for a positional argument when a value is present If the positional is optional, we shouldn't enforce the value to be one of the defined options. Not passing a value is acceptable for optional arguments. --- features/command.feature | 51 ++++++++++++++++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/features/command.feature b/features/command.feature index 062737979..932a430ce 100644 --- a/features/command.feature +++ b/features/command.feature @@ -466,6 +466,7 @@ Feature: WP-CLI Commands shop: burrito: """ + And STDERR should be empty When I run `wp --require=test-cmd.php foo ''` Then STDOUT should be YAML containing: @@ -474,6 +475,7 @@ Feature: WP-CLI Commands shop: burrito: """ + And STDERR should be empty When I run `wp --require=test-cmd.php foo apple --burrito=veggies` Then STDOUT should be YAML containing: @@ -482,6 +484,7 @@ Feature: WP-CLI Commands shop: burrito: veggies """ + And STDERR should be empty When I try `wp --require=test-cmd.php foo apple --burrito=meat` Then STDERR should contain: @@ -516,6 +519,54 @@ Feature: WP-CLI Commands shop: cha cha cha burrito: """ + And STDERR should be empty + + Scenario: Register a command with default and accepted arguments, part two + Given an empty directory + And a test-cmd.php file: + """ + <?php + /** + * An amazing command for managing burritos. + * + * [<burrito>] + * : This is the bar argument. + * --- + * options: + * - beans + * - veggies + * --- + * + * @when before_wp_load + */ + $foo = function( $args, $assoc_args ) { + $out = array( + 'burrito' => isset( $args[0] ) ? $args[0] : '', + ); + WP_CLI::print_value( $out, array( 'format' => 'yaml' ) ); + }; + WP_CLI::add_command( 'foo', $foo ); + """ + + When I run `wp --require=test-cmd.php foo` + Then STDOUT should be YAML containing: + """ + burrito: + """ + And STDERR should be empty + + When I run `wp --require=test-cmd.php foo beans` + Then STDOUT should be YAML containing: + """ + burrito: beans + """ + And STDERR should be empty + + When I try `wp --require=test-cmd.php foo apple` + Then STDERR should be: + """ + Error: Invalid value specified for positional arg. + """ Scenario: Removing a subcommand should remove it from the index Given an empty directory diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 507036c84..6b832514a 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -279,7 +279,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $i++; } while ( isset( $args[ $i ] ) ); } else { - if ( ! in_array( $args[ $i ], $spec_args['options'] ) ) { + if ( isset( $args[ $i ] ) && ! in_array( $args[ $i ], $spec_args['options'] ) ) { \WP_CLI::error( 'Invalid value specified for positional arg.' ); } } From 13b495e4e7f00663aa7b69b7639cc28972c9746a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 20 Oct 2016 06:08:40 -0700 Subject: [PATCH 4990/5359] Support installing a WP-CLI package based on a Git URL `wp package list` will display all local packages now, not just those in the package index --- features/package-install.feature | 55 +++++++++++++++++++++++++++-- php/commands/package.php | 59 +++++++++++++++++++++----------- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 4f54fff4e..c24f774e3 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -86,10 +86,13 @@ Feature: Install WP-CLI packages alice """ - When I run `wp package list` - Then STDOUT should contain: + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | trendwerk/faker | + And STDOUT should not contain: """ - trendwerk/faker + nelmio/alice """ When I run `wp package uninstall trendwerk/faker` @@ -115,3 +118,49 @@ Feature: Install WP-CLI packages """ trendwerk/faker """ + + Scenario: Install a package from a Git URL + Given an empty directory + + When I run `wp package path` + Then save STDOUT as {PACKAGE_PATH} + + When I try `wp package install git@github.com:wp-cli.git` + Then STDERR should be: + """ + Error: Couldn't parse package name from expected path '<name>/<package>'. + """ + + When I run `wp package install git@github.com:wp-cli/google-sitemap-generator-cli.git` + Then STDOUT should contain: + """ + Installing package wp-cli/google-sitemap-generator-cli (dev-master) + Updating {PACKAGE_PATH}composer.json to require the package... + Registering git@github.com:wp-cli/google-sitemap-generator-cli.git as a VCS repository... + Using Composer to install the package... + """ + And STDOUT should contain: + """ + Success: Package installed successfully. + """ + + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | wp-cli/google-sitemap-generator-cli | + + When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` + Then STDOUT should contain: + """ + Removing require statement from {PACKAGE_PATH}composer.json + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + + When I run `wp package list --fields=name` + Then STDOUT should not contain: + """ + wp-cli/google-sitemap-generator-cli + """ diff --git a/php/commands/package.php b/php/commands/package.php index c15284e39..a97a11799 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -130,12 +130,13 @@ public function browse( $_, $assoc_args ) { * * ## OPTIONS * - * <name> - * : Name of the package to install. Can optionally contain a version constraint. + * <name|git> + * : Name or git URL for the package to install. Names can optionally + * include a version constraint (e.g. wp-cli/server-command:@stable) * * ## EXAMPLES * - * # Install the latest development version + * # Install the latest development version from the package index * $ wp package install wp-cli/server-command * Installing package wp-cli/server-command (dev-master) * Updating /home/person/.wp-cli/packages/composer.json to require the package... @@ -155,22 +156,34 @@ public function browse( $_, $assoc_args ) { * * # Install the latest stable version * $ wp package install wp-cli/server-command:@stable + * + * # Install a package hosted at a git URL + * $ wp package install git@github.com:runcommand/hook.git */ public function install( $args, $assoc_args ) { list( $package_name ) = $args; - if ( false !== strpos( $package_name, ':' ) ) { - list( $package_name, $version ) = explode( ':', $package_name ); + $git_package = false; + $version = 'dev-master'; + if ( '.git' === strtolower( substr( $package_name, -4, 4 ) ) ) { + $git_package = $package_name; + preg_match( '#([^:\/]+\/[^\/]+)\.git#', $package_name, $matches ); + if ( ! empty( $matches[1] ) ) { + $package_name = $matches[1]; + } else { + WP_CLI::error( "Couldn't parse package name from expected path '<name>/<package>'." ); + } } else { - $version = 'dev-master'; + if ( false !== strpos( $package_name, ':' ) ) { + list( $package_name, $version ) = explode( ':', $package_name ); + } + $package = $this->get_community_package_by_name( $package_name ); + if ( ! $package ) { + WP_CLI::error( "Invalid package." ); + } } - $package = $this->get_community_package_by_name( $package_name ); - if ( ! $package ) { - WP_CLI::error( "Invalid package." ); - } else { - WP_CLI::log( sprintf( "Installing package %s (%s)", $package_name, $version ) ); - } + WP_CLI::log( sprintf( "Installing package %s (%s)", $package_name, $version ) ); try { $composer = $this->get_composer(); @@ -187,6 +200,11 @@ public function install( $args, $assoc_args ) { $json_manipulator->addLink( 'require', $package_name, $version ); $json_manipulator->addConfigSetting( 'secure-http', true ); + if ( $git_package ) { + WP_CLI::log( sprintf( 'Registering %s as a VCS repository...', $git_package ) ); + $json_manipulator->addRepository( $package_name, array( 'type' => 'vcs', 'url' => $git_package ) ); + } + $composer_backup_decoded = json_decode( $composer_backup, true ); // If the composer file does not contain the current package index repository, refresh the repository definition. if ( empty( $composer_backup_decoded['repositories']['wp-cli']['url'] ) || self::PACKAGE_INDEX_URL != $composer_backup_decoded['repositories']['wp-cli']['url'] ) { @@ -500,17 +518,18 @@ private function get_installed_packages() { WP_CLI::error( $e->getMessage() ); } $repo = $composer->getRepositoryManager()->getLocalRepository(); - $installed_packages = array(); - foreach( $repo->getPackages() as $package ) { - - if ( ! $this->is_community_package( $package ) ) { - continue; + $existing = json_decode( file_get_contents( $this->get_composer_json_path() ), true ); + $installed_package_keys = ! empty( $existing['require'] ) ? array_keys( $existing['require'] ) : array(); + if ( empty( $installed_package_keys ) ) { + return array(); + } + $installed_packages = array(); + foreach( $repo->getCanonicalPackages() as $package ) { + if ( in_array( $package->getName(), $installed_package_keys, true ) ) { + $installed_packages[] = $package; } - - $installed_packages[] = $package; } - return $installed_packages; } From f83556ab8cb9f467195b9855365d014a03dc330d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 20 Oct 2016 07:04:13 -0700 Subject: [PATCH 4991/5359] Flag this with `@github-api` because auth is too flaky for CI --- features/package-install.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/package-install.feature b/features/package-install.feature index c24f774e3..411c4f65d 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -119,6 +119,7 @@ Feature: Install WP-CLI packages trendwerk/faker """ + @github-api Scenario: Install a package from a Git URL Given an empty directory From 69788c70475830fa0d01df1966313bfc028f1350 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 20 Oct 2016 08:49:20 -0700 Subject: [PATCH 4992/5359] Update media regenerate tests to use 125x125 image size TwentySeventeen now includes a 100x100 image size, which breaks our tests for a custom image size. --- features/media-regenerate.feature | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index ae81bf092..df8ce1ac0 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -18,14 +18,14 @@ Feature: Regenerate WordPress attachments """ <?php add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 100, 100, true ); + add_image_size( 'test1', 125, 125, true ); }); """ And I run `wp option update uploads_use_yearmonth_folders 0` When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist Given a wp-content/mu-plugins/media-settings.php file: """ @@ -39,7 +39,7 @@ Feature: Regenerate WordPress attachments """ Success: Finished regenerating the image. """ - And the wp-content/uploads/large-image-100x100.jpg file should not exist + And the wp-content/uploads/large-image-125x125.jpg file should not exist And the wp-content/uploads/large-image-200x200.jpg file should exist Scenario: Skip deletion of existing thumbnails when media is regenerated @@ -50,14 +50,14 @@ Feature: Regenerate WordPress attachments """ <?php add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 100, 100, true ); + add_image_size( 'test1', 125, 125, true ); }); """ And I run `wp option update uploads_use_yearmonth_folders 0` When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist Given a wp-content/mu-plugins/media-settings.php file: """ @@ -71,7 +71,7 @@ Feature: Regenerate WordPress attachments """ Success: Finished regenerating the image. """ - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist And the wp-content/uploads/large-image-200x200.jpg file should exist Scenario: Provide helpful error messages when media can't be regenerated @@ -82,14 +82,14 @@ Feature: Regenerate WordPress attachments """ <?php add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 100, 100, true ); + add_image_size( 'test1', 125, 125, true ); }); """ And I run `wp option update uploads_use_yearmonth_folders 0` When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist When I run `rm wp-content/uploads/large-image.jpg` Then STDOUT should be empty @@ -112,20 +112,20 @@ Feature: Regenerate WordPress attachments """ <?php add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 100, 100, true ); + add_image_size( 'test1', 125, 125, true ); }); """ And I run `wp option update uploads_use_yearmonth_folders 0` When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My second imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID2} - When I run `rm wp-content/uploads/large-image-100x100.jpg` - Then the wp-content/uploads/large-image-100x100.jpg file should not exist + When I run `rm wp-content/uploads/large-image-125x125.jpg` + Then the wp-content/uploads/large-image-125x125.jpg file should not exist When I run `wp media regenerate --only-missing --yes` Then STDOUT should contain: @@ -153,13 +153,13 @@ Feature: Regenerate WordPress attachments When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-100x100.jpg file should not exist + And the wp-content/uploads/large-image-125x125.jpg file should not exist Given a wp-content/mu-plugins/media-settings.php file: """ <?php add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 100, 100, true ); + add_image_size( 'test1', 125, 125, true ); }); """ @@ -176,7 +176,7 @@ Feature: Regenerate WordPress attachments """ Success: Finished regenerating the image. """ - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist When I run `wp media regenerate --only-missing --yes` Then STDOUT should contain: @@ -191,4 +191,4 @@ Feature: Regenerate WordPress attachments """ Success: Finished regenerating the image. """ - And the wp-content/uploads/large-image-100x100.jpg file should exist + And the wp-content/uploads/large-image-125x125.jpg file should exist From f08ba016653bb0a40f9bdfedf9e211e8cbc5263b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 20 Oct 2016 13:22:19 -0700 Subject: [PATCH 4993/5359] Support installing a WP-CLI package at a local path --- features/package-install.feature | 74 ++++++++++++++++++++++++++++++++ php/commands/package.php | 39 +++++++++++++++-- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 411c4f65d..7b74eb4f5 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -165,3 +165,77 @@ Feature: Install WP-CLI packages """ wp-cli/google-sitemap-generator-cli """ + + Scenario: Install a package at an existing path + Given an empty directory + And a path-command/command.php file: + """ + <?php + WP_CLI::add_command( 'community-command', function(){ + WP_CLI::success( "success!" ); + }, array( 'when' => 'before_wp_load' ) ); + """ + And a path-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "require": { + }, + "autoload": { + "files": [ "command.php" ] + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + + When I run `wp package path` + Then save STDOUT as {PACKAGE_PATH} + + When I run `pwd` + Then save STDOUT as {CURRENT_PATH} + + When I run `wp package install path-command` + Then STDOUT should contain: + """ + Installing package wp-cli/community-command (dev-master) + Updating {PACKAGE_PATH}composer.json to require the package... + Registering {CURRENT_PATH}/path-command as a path repository... + Using Composer to install the package... + """ + And STDOUT should contain: + """ + Success: Package installed successfully. + """ + + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | wp-cli/community-command | + + When I run `wp community-command` + Then STDOUT should be: + """ + Success: success! + """ + + When I run `wp package uninstall wp-cli/community-command` + Then STDOUT should contain: + """ + Removing require statement from {PACKAGE_PATH}composer.json + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + And the path-command directory should exist + + When I run `wp package list --fields=name` + Then STDOUT should not contain: + """ + wp-cli/community-command + """ diff --git a/php/commands/package.php b/php/commands/package.php index a97a11799..19bd5137e 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -15,6 +15,7 @@ use \Composer\Repository\RepositoryManager; use \Composer\Util\Filesystem; use \WP_CLI\ComposerIO; +use \WP_CLI\Utils; /** * Manage WP-CLI packages. @@ -128,11 +129,22 @@ public function browse( $_, $assoc_args ) { /** * Install a WP-CLI package. * + * Packages are required to be a valid Composer package, and can be + * specified as: + * + * * Package name from WP-CLI's package index. + * * Git URL accessible by the current shell user. + * * Path to a directory on the local machine. + * + * Note: When installing a local directory, WP-CLI simply registers a + * reference to the directory. If you move or delete the directory, WP-CLI's + * reference breaks. + * * ## OPTIONS * - * <name|git> - * : Name or git URL for the package to install. Names can optionally - * include a version constraint (e.g. wp-cli/server-command:@stable) + * <name|git|path> + * : Name, git URL, or directory path for the package to install. Names can + * optionally include a version constraint (e.g. wp-cli/server-command:@stable) * * ## EXAMPLES * @@ -163,7 +175,7 @@ public function browse( $_, $assoc_args ) { public function install( $args, $assoc_args ) { list( $package_name ) = $args; - $git_package = false; + $git_package = $dir_package = false; $version = 'dev-master'; if ( '.git' === strtolower( substr( $package_name, -4, 4 ) ) ) { $git_package = $package_name; @@ -173,6 +185,22 @@ public function install( $args, $assoc_args ) { } else { WP_CLI::error( "Couldn't parse package name from expected path '<name>/<package>'." ); } + } else if ( is_dir( $package_name ) && file_exists( $package_name . '/composer.json' ) ) { + $dir_package = $package_name; + if ( ! Utils\is_path_absolute( $dir_package ) ) { + $dir_package = getcwd() . DIRECTORY_SEPARATOR . $dir_package; + } + $composer_file = $dir_package . '/composer.json'; + $package_name = ''; + if ( file_exists( $composer_file ) ) { + $composer_data = json_decode( file_get_contents( $composer_file ), true ); + if ( ! empty( $composer_data['name'] ) ) { + $package_name = $composer_data['name']; + } + } + if ( empty( $package_name ) ) { + WP_CLI::error( "Invalid package." ); + } } else { if ( false !== strpos( $package_name, ':' ) ) { list( $package_name, $version ) = explode( ':', $package_name ); @@ -203,6 +231,9 @@ public function install( $args, $assoc_args ) { if ( $git_package ) { WP_CLI::log( sprintf( 'Registering %s as a VCS repository...', $git_package ) ); $json_manipulator->addRepository( $package_name, array( 'type' => 'vcs', 'url' => $git_package ) ); + } else if ( $dir_package ) { + WP_CLI::log( sprintf( 'Registering %s as a path repository...', $dir_package ) ); + $json_manipulator->addRepository( $package_name, array( 'type' => 'path', 'url' => $dir_package ) ); } $composer_backup_decoded = json_decode( $composer_backup, true ); From b6bcafe5a869707045438aade8ba7218482ced85 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 21 Oct 2016 07:08:36 -0700 Subject: [PATCH 4994/5359] Support for installing packages from zip archives ``` $ wp package install https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip $ wp package install google-sitemap-generator-cli.zip ``` Archives are extracted to `<packages-dir>/local/<package-name>`, and installed as a path repository. --- features/package-install.feature | 112 +++++++++++++++++++++++-- php/WP_CLI/Extractor.php | 138 +++++++++++++++++++++++++++++++ php/commands/core.php | 107 +----------------------- php/commands/package.php | 64 +++++++++++--- 4 files changed, 297 insertions(+), 124 deletions(-) create mode 100644 php/WP_CLI/Extractor.php diff --git a/features/package-install.feature b/features/package-install.feature index 7b74eb4f5..5f0a0216c 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -1,5 +1,9 @@ Feature: Install WP-CLI packages + Background: + When I run `wp package path` + Then save STDOUT as {PACKAGE_PATH} + Scenario: Install a package with an http package index url in package composer.json Given an empty directory And a composer.json file: @@ -65,9 +69,6 @@ Feature: Install WP-CLI packages Scenario: Install a package with a dependency Given an empty directory - When I run `wp package path` - Then save STDOUT as {PACKAGE_PATH} - When I run `wp package install trendwerk/faker` Then STDOUT should contain: """ @@ -123,9 +124,6 @@ Feature: Install WP-CLI packages Scenario: Install a package from a Git URL Given an empty directory - When I run `wp package path` - Then save STDOUT as {PACKAGE_PATH} - When I try `wp package install git@github.com:wp-cli.git` Then STDERR should be: """ @@ -150,6 +148,105 @@ Feature: Install WP-CLI packages | name | | wp-cli/google-sitemap-generator-cli | + When I run `wp google-sitemap` + Then STDOUT should contain: + """ + usage: wp google-sitemap rebuild + """ + + When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` + Then STDOUT should contain: + """ + Removing require statement from {PACKAGE_PATH}composer.json + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + + When I run `wp package list --fields=name` + Then STDOUT should not contain: + """ + wp-cli/google-sitemap-generator-cli + """ + + Scenario: Install a package in a local zip + Given an empty directory + And I run `wget -O google-sitemap-generator-cli.zip https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip` + + When I run `wp package install google-sitemap-generator-cli.zip` + Then STDOUT should contain: + """ + Installing package wp-cli/google-sitemap-generator-cli (dev-master) + Updating {PACKAGE_PATH}composer.json to require the package... + Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository... + Using Composer to install the package... + """ + And STDOUT should contain: + """ + Success: Package installed successfully. + """ + + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | wp-cli/google-sitemap-generator-cli | + + When I run `wp google-sitemap` + Then STDOUT should contain: + """ + usage: wp google-sitemap rebuild + """ + + When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` + Then STDOUT should contain: + """ + Removing require statement from {PACKAGE_PATH}composer.json + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + + When I run `wp package list --fields=name` + Then STDOUT should not contain: + """ + wp-cli/google-sitemap-generator-cli + """ + + Scenario: Install a package from a remote ZIP + Given an empty directory + + When I try `wp package install https://github.com/wp-cli/google-sitemap-generator.zip` + Then STDERR should be: + """ + Error: Couldn't download package. + """ + + When I run `wp package install https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip` + Then STDOUT should contain: + """ + Installing package wp-cli/google-sitemap-generator-cli (dev-master) + Updating {PACKAGE_PATH}composer.json to require the package... + Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository... + Using Composer to install the package... + """ + And STDOUT should contain: + """ + Success: Package installed successfully. + """ + + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | wp-cli/google-sitemap-generator-cli | + + When I run `wp google-sitemap` + Then STDOUT should contain: + """ + usage: wp google-sitemap rebuild + """ + When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` Then STDOUT should contain: """ @@ -193,9 +290,6 @@ Feature: Install WP-CLI packages } """ - When I run `wp package path` - Then save STDOUT as {PACKAGE_PATH} - When I run `pwd` Then save STDOUT as {CURRENT_PATH} diff --git a/php/WP_CLI/Extractor.php b/php/WP_CLI/Extractor.php new file mode 100644 index 000000000..defdc5127 --- /dev/null +++ b/php/WP_CLI/Extractor.php @@ -0,0 +1,138 @@ +<?php + +namespace WP_CLI; + +use Exception; +use PharData; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use WP_CLI; +use WP_CLI\Utils; +use ZipArchive; + +/** + * Extract a provided archive file. + */ +class Extractor { + + /** + * Extract the archive file to a specific destination. + * + * @param string $dest + */ + public static function extract( $tarball_or_zip, $dest ) { + if ( preg_match( '/\.zip$/', $tarball_or_zip ) ) { + return self::extract_zip( $tarball_or_zip, $dest ); + } + + if ( preg_match( '/\.tar\.gz$/', $tarball_or_zip ) ) { + return self::extract_tarball( $tarball_or_zip, $dest ); + } + throw new \Exception( 'Extension not supported.' ); + } + + /** + * Extract a ZIP file to a specific destination. + * + * @param string $zipfile + * @param string $dest + */ + private static function extract_zip( $zipfile, $dest ) { + if ( ! class_exists( 'ZipArchive' ) ) { + throw new Exception( 'Extracting a zip file requires ZipArchive.' ); + } + $zip = new ZipArchive(); + $res = $zip->open( $zipfile ); + if ( true === $res ) { + $tempdir = implode( DIRECTORY_SEPARATOR, Array ( + dirname( $zipfile ), + basename( $zipfile, '.zip' ), + $zip->getNameIndex( 0 ) + ) ); + + $zip->extractTo( dirname( $tempdir ) ); + $zip->close(); + + self::copy_overwrite_files( $tempdir, $dest ); + self::rmdir( dirname( $tempdir ) ); + } else { + throw Exception( $res ); + } + } + + /** + * Extract a tarball to a specific destination. + * + * @param string $tarball + * @param string $dest + */ + private static function extract_tarball( $tarball, $dest ) { + if ( ! class_exists( 'PharData' ) ) { + $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; + WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); + return; + } + $phar = new PharData( $tarball ); + $tempdir = implode( DIRECTORY_SEPARATOR, Array ( + dirname( $tarball ), + basename( $tarball, '.tar.gz' ), + $phar->getFileName() + ) ); + + $phar->extractTo( dirname( $tempdir ), null, true ); + + self::copy_overwrite_files( $tempdir, $dest ); + + self::rmdir( dirname( $tempdir ) ); + } + + public static function copy_overwrite_files( $source, $dest ) { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::SELF_FIRST); + + $error = 0; + + if ( ! is_dir( $dest ) ) { + mkdir( $dest, 0777, true ); + } + + foreach ( $iterator as $item ) { + + $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); + + if ( $item->isDir() ) { + if ( !is_dir( $dest_path ) ) { + mkdir( $dest_path ); + } + } else { + if ( file_exists( $dest_path ) && is_writable( $dest_path ) ) { + copy( $item, $dest_path ); + } elseif ( ! file_exists( $dest_path ) ) { + copy( $item, $dest_path ); + } else { + $error = 1; + WP_CLI::warning( "Unable to copy '" . $iterator->getSubPathName() . "' to current directory." ); + } + } + } + + if ( $error ) { + throw new Exception( 'There was an error overwriting existing files.' ); + } + } + + public static function rmdir( $dir ) { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ), + RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ( $files as $fileinfo ) { + $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; + $todo( $fileinfo->getRealPath() ); + } + rmdir( $dir ); + } + +} diff --git a/php/commands/core.php b/php/commands/core.php index 7e44795ea..063c4e3ac 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1,6 +1,7 @@ <?php use \Composer\Semver\Comparator; +use \WP_CLI\Extractor; use \WP_CLI\Utils; /** @@ -178,7 +179,7 @@ public function download( $args, $assoc_args ) { if ( $cache_file ) { WP_CLI::log( "Using cached file '$cache_file'..." ); try{ - self::_extract( $cache_file, $download_dir ); + Extractor::extract( $cache_file, $download_dir ); } catch ( Exception $e ) { WP_CLI::warning( "Extraction failed, downloading a new copy..." ); $bad_cache = true; @@ -221,7 +222,7 @@ public function download( $args, $assoc_args ) { } try { - self::_extract( $temp, $download_dir ); + Extractor::extract( $temp, $download_dir ); } catch ( Exception $e ) { WP_CLI::error( "Couldn't extract WordPress archive. " . $e->getMessage() ); } @@ -239,108 +240,6 @@ public function download( $args, $assoc_args ) { WP_CLI::success( 'WordPress downloaded.' ); } - private static function _extract( $tarball_or_zip, $dest ) { - $path_parts = pathinfo( $tarball_or_zip ); - - if ( preg_match( '/\.zip$/', $tarball_or_zip ) ) { - return self::_extract_zip( $tarball_or_zip, $dest ); - } - - if ( preg_match( '/\.tar\.gz$/', $tarball_or_zip ) ) { - return self::_extract_tarball( $tarball_or_zip, $dest ); - } - - WP_CLI::error( sprintf( 'Extension %s not supported.', $extension ) ); - } - - private static function _extract_tarball( $tarball, $dest ) { - if ( ! class_exists( 'PharData' ) ) { - $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; - WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); - return; - } - $phar = new PharData( $tarball ); - $tempdir = implode( DIRECTORY_SEPARATOR, Array ( - dirname( $tarball ), - basename( $tarball, '.tar.gz' ), - $phar->getFileName() - ) ); - - $phar->extractTo( dirname( $tempdir ), null, true ); - - self::_copy_overwrite_files( $tempdir, $dest ); - - self::_rmdir( dirname( $tempdir ) ); - } - - private static function _extract_zip( $zipfile, $dest ) { - if ( ! class_exists( 'ZipArchive' ) ) { - throw new \Exception( 'Extracting a zip file requires ZipArchive.' ); - } - $zip = new ZipArchive(); - $res = $zip->open( $zipfile ); - if ( true === $res ) { - $tempdir = implode( DIRECTORY_SEPARATOR, Array ( - dirname( $zipfile ), - basename( $zipfile, '.zip' ), - $zip->getNameIndex( 0 ) - ) ); - - $zip->extractTo( dirname( $tempdir ) ); - $zip->close(); - - self::_copy_overwrite_files( $tempdir, $dest ); - self::_rmdir( dirname( $tempdir ) ); - } else { - throw \Exception( $res ); - } - } - - private static function _copy_overwrite_files( $source, $dest ) { - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::SELF_FIRST); - - $error = 0; - - foreach ( $iterator as $item ) { - - $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); - - if ( $item->isDir() ) { - if ( !is_dir( $dest_path ) ) { - mkdir( $dest_path ); - } - } else { - if ( file_exists( $dest_path ) && is_writable( $dest_path ) ) { - copy( $item, $dest_path ); - } elseif ( ! file_exists( $dest_path ) ) { - copy( $item, $dest_path ); - } else { - $error = 1; - WP_CLI::warning( "Unable to copy '" . $iterator->getSubPathName() . "' to current directory." ); - } - } - } - - if ( $error ) { - WP_CLI::error( 'There was an error downloading all WordPress files.' ); - } - } - - private static function _rmdir( $dir ) { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ( $files as $fileinfo ) { - $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; - $todo( $fileinfo->getRealPath() ); - } - rmdir( $dir ); - } - private static function _read( $url ) { $headers = array('Accept' => 'application/json'); $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); diff --git a/php/commands/package.php b/php/commands/package.php index 19bd5137e..b24752eca 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -15,6 +15,7 @@ use \Composer\Repository\RepositoryManager; use \Composer\Util\Filesystem; use \WP_CLI\ComposerIO; +use \WP_CLI\Extractor; use \WP_CLI\Utils; /** @@ -185,22 +186,42 @@ public function install( $args, $assoc_args ) { } else { WP_CLI::error( "Couldn't parse package name from expected path '<name>/<package>'." ); } + } else if ( ( false !== strpos( $package_name, '://' ) && false !== stripos( $package_name, '.zip' ) ) + || ( pathinfo( $package_name, PATHINFO_EXTENSION ) === 'zip' && is_file( $package_name ) ) ) { + // Download the remote ZIP file to a temp directory + if ( false !== strpos( $package_name, '://' ) ) { + $temp = Utils\get_temp_dir() . uniqid('package_') . ".zip"; + $options = array( + 'timeout' => 600, + 'filename' => $temp + ); + $response = Utils\http_request( 'GET', $package_name, null, array(), $options ); + if ( 20 != substr( $response->status_code, 0, 2 ) ) { + WP_CLI::error( "Couldn't download package." ); + } + $package_name = $temp; + } + $dir_package = Utils\get_temp_dir() . uniqid( 'package_' ); + try { + // Extract the package to get the package name + Extractor::extract( $package_name, $dir_package ); + $package_name = self::get_package_name_from_dir_package( $dir_package ); + // Move to a location based on the package name + $local_dir = rtrim( WP_CLI::get_runner()->get_packages_dir_path(), '/' ) . '/local/'; + $actual_dir_package = $local_dir . str_replace( '/', '-', $package_name ); + Extractor::copy_overwrite_files( $dir_package, $actual_dir_package ); + Extractor::rmdir( $dir_package ); + // Behold, the extracted package + $dir_package = $actual_dir_package; + } catch ( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } } else if ( is_dir( $package_name ) && file_exists( $package_name . '/composer.json' ) ) { $dir_package = $package_name; if ( ! Utils\is_path_absolute( $dir_package ) ) { $dir_package = getcwd() . DIRECTORY_SEPARATOR . $dir_package; } - $composer_file = $dir_package . '/composer.json'; - $package_name = ''; - if ( file_exists( $composer_file ) ) { - $composer_data = json_decode( file_get_contents( $composer_file ), true ); - if ( ! empty( $composer_data['name'] ) ) { - $package_name = $composer_data['name']; - } - } - if ( empty( $package_name ) ) { - WP_CLI::error( "Invalid package." ); - } + $package_name = self::get_package_name_from_dir_package( $dir_package ); } else { if ( false !== strpos( $package_name, ':' ) ) { list( $package_name, $version ) = explode( ':', $package_name ); @@ -587,6 +608,27 @@ private function is_package_installed( $package_name ) { } } + /** + * Get the name of the package from the composer.json in a directory path + * + * @param string $dir_package + * @return string + */ + private static function get_package_name_from_dir_package( $dir_package ) { + $composer_file = $dir_package . '/composer.json'; + $package_name = ''; + if ( file_exists( $composer_file ) ) { + $composer_data = json_decode( file_get_contents( $composer_file ), true ); + if ( ! empty( $composer_data['name'] ) ) { + $package_name = $composer_data['name']; + } + } + if ( empty( $package_name ) ) { + WP_CLI::error( "Invalid package." ); + } + return $package_name; + } + /** * Get the composer.json object */ From 8ea8ef3085ce19662864834af2e35fa3edfe71aa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 21 Oct 2016 08:28:53 -0700 Subject: [PATCH 4995/5359] Update docs for installing from a .zip --- php/commands/package.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index b24752eca..d4f31c300 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -136,20 +136,25 @@ public function browse( $_, $assoc_args ) { * * Package name from WP-CLI's package index. * * Git URL accessible by the current shell user. * * Path to a directory on the local machine. + * * Local or remote .zip file. * - * Note: When installing a local directory, WP-CLI simply registers a + * When installing a local directory, WP-CLI simply registers a * reference to the directory. If you move or delete the directory, WP-CLI's * reference breaks. * + * When installing a .zip file, WP-CLI extracts the package to + * `~/.wp-cli/packages/local/<package-name>`. + * * ## OPTIONS * - * <name|git|path> - * : Name, git URL, or directory path for the package to install. Names can - * optionally include a version constraint (e.g. wp-cli/server-command:@stable) + * <name|git|path|zip> + * : Name, git URL, directory path, or .zip file for the package to install. + * Names can optionally include a version constraint + * (e.g. wp-cli/server-command:@stable). * * ## EXAMPLES * - * # Install the latest development version from the package index + * # Install the latest development version from the package index. * $ wp package install wp-cli/server-command * Installing package wp-cli/server-command (dev-master) * Updating /home/person/.wp-cli/packages/composer.json to require the package... @@ -167,11 +172,14 @@ public function browse( $_, $assoc_args ) { * --- * Success: Package installed successfully. * - * # Install the latest stable version + * # Install the latest stable version. * $ wp package install wp-cli/server-command:@stable * - * # Install a package hosted at a git URL + * # Install a package hosted at a git URL. * $ wp package install git@github.com:runcommand/hook.git + * + * # Install a package in a .zip file. + * $ wp package install google-sitemap-generator-cli.zip */ public function install( $args, $assoc_args ) { list( $package_name ) = $args; From 982e83cb83c8f310ad394b93623dbd2ce5984c20 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 21 Oct 2016 09:20:05 -0700 Subject: [PATCH 4996/5359] Drop RESTful WP-CLI from primary spot on the homepage --- README.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README.md b/README.md index 803a0ec32..98795c900 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,6 @@ To stay up to date, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [si [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") -<div style=" - border: 1px solid #7AD03A; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - padding-left: 10px; - padding-right: 10px; -"> - <p><strong>A more RESTful WP-CLI</strong> aims to unlocking the potential of the WP REST API at the command line. Project backed by Pressed, Chris Lema, Human Made, Pagely, Pantheon and many others. <a href="https://wp-cli.org/restful/">Learn more →</a></p> -</div> - Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) ## Using From be0567f84212a68dbe2a4d1afea1657c720af4c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 21 Oct 2016 09:20:20 -0700 Subject: [PATCH 4997/5359] `wp transient delete-all` is now `wp transient delete --all` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98795c900..58885a58f 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ Activating 'rest-api'... Success: Plugin 'rest-api' activated. ``` -WP-CLI also includes commands for many things you can't do in the WordPress admin. For example, `wp transient delete-all` ([doc](https://wp-cli.org/commands/transient/delete-all/)) lets you delete one or all transients: +WP-CLI also includes commands for many things you can't do in the WordPress admin. For example, `wp transient delete --all` ([doc](https://wp-cli.org/commands/transient/delete/)) lets you delete one or all transients: ```bash -$ wp transient delete-all +$ wp transient delete --all Success: 34 transients deleted from the database. ``` From 946cbc5742c26b260160ba4f3ef95c20fd0cf399 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 24 Oct 2016 06:10:25 +0900 Subject: [PATCH 4998/5359] bash completion supports ssh alias --- php/WP_CLI/Completions.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 63bacbae7..f40173e85 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -17,6 +17,15 @@ function __construct( $line ) { // last word is either empty or an incomplete subcommand $this->cur_word = end( $this->words ); + $is_alias = false; + if ( ! empty( $this->words[0] ) && preg_match( "/^@/", $this->words[0] ) ) { + array_shift( $this->words ); + // `wp @al` is false, but `wp @all ` is true. + if ( count( $this->words ) ) { + $is_alias = true; + } + } + $r = $this->get_command( $this->words ); if ( !is_array( $r ) ) { return; @@ -34,6 +43,13 @@ function __construct( $line ) { } if ( $command->can_have_subcommands() ) { + // add completion when command is `wp` and alias isn't set. + if ( "wp" === $command->get_name() && false === $is_alias ) { + $aliases = \WP_CLI::get_configurator()->get_aliases(); + foreach ( $aliases as $name => $_ ) { + $this->add( "$name " ); + } + } foreach ( $command->get_subcommands() as $name => $_ ) { $this->add( "$name " ); } @@ -100,4 +116,3 @@ public function render() { } } } - From 36b16d1a8d951e095c34ee7d6c80060ab170a5d3 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 24 Oct 2016 06:43:14 +0900 Subject: [PATCH 4999/5359] add feature for the `cli completion` --- features/cli-bash-completion.feature | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 features/cli-bash-completion.feature diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature new file mode 100644 index 000000000..069b58634 --- /dev/null +++ b/features/cli-bash-completion.feature @@ -0,0 +1,49 @@ +Feature: `wp cli completions` tasks + + Scenario: Bash Completion + Given an empty directory + And a wp-cli.yml file: + """ + @example: + ssh: example.com + """ + + When I run `wp cli completions --line="wp " --point=100` + Then STDOUT should contain: + """ + @example + """ + And STDOUT should contain: + """ + plugin + """ + And STDOUT should contain: + """ + server + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp @e" --point=100` + Then STDOUT should contain: + """ + @example + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp @example " --point=100` + Then STDOUT should not contain: + """ + @example + """ + And STDOUT should contain: + """ + core + """ + And STDOUT should contain: + """ + eval + """ + And STDERR should be empty + And the return code should be 0 From 5edaddd6bb432e4de39f90cde4b5986698e7d6de Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 24 Oct 2016 06:52:49 +0900 Subject: [PATCH 5000/5359] add tests for witout wp-cli.yml --- features/cli-bash-completion.feature | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 069b58634..8507f62e2 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -1,6 +1,21 @@ Feature: `wp cli completions` tasks - Scenario: Bash Completion + Scenario: Bash Completion without wp-cli.yml + Given an empty directory + + When I run `wp cli completions --line="wp " --point=100` + Then STDOUT should contain: + """ + plugin + """ + And STDOUT should contain: + """ + server + """ + And STDERR should be empty + And the return code should be 0 + + Scenario: Bash Completion with SSH aliases Given an empty directory And a wp-cli.yml file: """ From 907cf823d2f85a34e04c54c77ea188e4babb3782 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 24 Oct 2016 17:18:05 +0900 Subject: [PATCH 5001/5359] enables bash completion on `wp help` --- features/cli-bash-completion.feature | 56 ++++++++++++++++++++++++++++ php/WP_CLI/Completions.php | 6 ++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 8507f62e2..4590a6848 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -15,6 +15,42 @@ Feature: `wp cli completions` tasks And STDERR should be empty And the return code should be 0 + When I run `wp cli completions --line="wp core " --point=100` + Then STDOUT should contain: + """ + install + """ + And STDOUT should contain: + """ + update + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp help " --point=100` + Then STDOUT should contain: + """ + rewrite + """ + And STDOUT should contain: + """ + media + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp help core language " --point=100` + Then STDOUT should contain: + """ + install + """ + And STDOUT should contain: + """ + update + """ + And STDERR should be empty + And the return code should be 0 + Scenario: Bash Completion with SSH aliases Given an empty directory And a wp-cli.yml file: @@ -62,3 +98,23 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 + + When I run `wp cli completions --line="wp @example plugin " --point=100` + Then STDOUT should contain: + """ + list + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp help core language " --point=100` + Then STDOUT should contain: + """ + install + """ + And STDOUT should contain: + """ + update + """ + And STDERR should be empty + And the return code should be 0 diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index f40173e85..6fce933ec 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -18,12 +18,16 @@ function __construct( $line ) { $this->cur_word = end( $this->words ); $is_alias = false; + $is_help = false; if ( ! empty( $this->words[0] ) && preg_match( "/^@/", $this->words[0] ) ) { array_shift( $this->words ); // `wp @al` is false, but `wp @all ` is true. if ( count( $this->words ) ) { $is_alias = true; } + } elseif ( ! empty( $this->words[0] ) && 'help' === $this->words[0] ) { + array_shift( $this->words ); + $is_help = true; } $r = $this->get_command( $this->words ); @@ -44,7 +48,7 @@ function __construct( $line ) { if ( $command->can_have_subcommands() ) { // add completion when command is `wp` and alias isn't set. - if ( "wp" === $command->get_name() && false === $is_alias ) { + if ( "wp" === $command->get_name() && false === $is_alias && false == $is_help ) { $aliases = \WP_CLI::get_configurator()->get_aliases(); foreach ( $aliases as $name => $_ ) { $this->add( "$name " ); From 4ac11d3505beed7f15baf667d44c17abda741fc2 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Mon, 24 Oct 2016 19:48:08 +0900 Subject: [PATCH 5002/5359] add test --- features/cli-bash-completion.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 4590a6848..5f8f78a6e 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -118,3 +118,15 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 + + When I run `wp cli completions --line="wp help " --point=100` + Then STDOUT should not contain: + """ + @example + """ + And STDOUT should contain: + """ + post-type + """ + And STDERR should be empty + And the return code should be 0 From e42c917128631770151b9f9a0cc560605cde3740 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 25 Oct 2016 00:25:17 +0900 Subject: [PATCH 5003/5359] improve bash completion --- features/cli-bash-completion.feature | 32 ++++++++++++++++++++++++++++ php/WP_CLI/Completions.php | 3 +++ 2 files changed, 35 insertions(+) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 5f8f78a6e..0f0190527 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -51,6 +51,22 @@ Feature: `wp cli completions` tasks And STDERR should be empty And the return code should be 0 + When I run `wp cli completions --line="wp core" --point=100` + Then STDOUT should contain: + """ + core + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp core " --point=100` + Then STDOUT should contain: + """ + language + """ + And STDERR should be empty + And the return code should be 0 + Scenario: Bash Completion with SSH aliases Given an empty directory And a wp-cli.yml file: @@ -130,3 +146,19 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 + + When I run `wp cli completions --line="wp help core" --point=100` + Then STDOUT should contain: + """ + core + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp help core " --point=100` + Then STDOUT should contain: + """ + language + """ + And STDERR should be empty + And the return code should be 0 diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 6fce933ec..61a553f2b 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -16,6 +16,9 @@ function __construct( $line ) { // last word is either empty or an incomplete subcommand $this->cur_word = end( $this->words ); + if ( "" !== $this->cur_word ) { + array_pop( $this->words ); + } $is_alias = false; $is_help = false; From 60f75aee59dc054ea1f441250897acfd8b790cbb Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 25 Oct 2016 00:38:32 +0900 Subject: [PATCH 5004/5359] improve tests for bash completion --- features/cli-bash-completion.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 0f0190527..0d85a8b6a 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -15,6 +15,18 @@ Feature: `wp cli completions` tasks And STDERR should be empty And the return code should be 0 + When I run `wp cli completions --line="wp co" --point=100` + Then STDOUT should contain: + """ + comment + """ + And STDOUT should contain: + """ + core + """ + And STDERR should be empty + And the return code should be 0 + When I run `wp cli completions --line="wp core " --point=100` Then STDOUT should contain: """ From 7fe38c96f347396994b7b306558d634cc731e977 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 25 Oct 2016 02:15:03 +0900 Subject: [PATCH 5005/5359] bug fix on with the flags --- features/cli-bash-completion.feature | 35 ++++++++++++++++++++++++++++ features/flags.feature | 32 ------------------------- php/WP_CLI/Completions.php | 2 +- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 0d85a8b6a..d1c8a69bc 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -174,3 +174,38 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 + + Scenario: Generate completions + Given an empty directory + + When I run `wp cli completions --line='wp bogus-comand ' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp eva' --point=100` + Then STDOUT should contain: + """ + eval + """ + And STDOUT should contain: + """ + eval-file + """ + + When I run `wp cli completions --line='wp core config --dbname=' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` + Then STDOUT should not contain: + """ + --dbname= + """ + And STDOUT should contain: + """ + --extra-php + """ + + When I run `wp cli completions --line='wp media import ' --point=100` + Then STDOUT should contain: + """ + <file> + """ diff --git a/features/flags.feature b/features/flags.feature index 53306d508..8fd674429 100644 --- a/features/flags.feature +++ b/features/flags.feature @@ -181,38 +181,6 @@ Feature: Global flags [31;1mError: """ - Scenario: Generate completions - Given an empty directory - - When I run `wp cli completions --line='wp bogus-comand ' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp eva' --point=100` - Then STDOUT should be: - """ - eval - eval-file - """ - - When I run `wp cli completions --line='wp core config --dbname=' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` - Then STDOUT should not contain: - """ - --dbname= - """ - And STDOUT should contain: - """ - --extra-php - """ - - When I run `wp cli completions --line='wp media import ' --point=100` - Then STDOUT should contain: - """ - <file> - """ - Scenario: Use `WP_CLI_STRICT_ARGS_MODE` to distinguish between global and local args Given an empty directory And a cmd.php file: diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 61a553f2b..bcb05cfa2 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -16,7 +16,7 @@ function __construct( $line ) { // last word is either empty or an incomplete subcommand $this->cur_word = end( $this->words ); - if ( "" !== $this->cur_word ) { + if ( "" !== $this->cur_word && ! preg_match( "/^\-/", $this->cur_word ) ) { array_pop( $this->words ); } From 1c544f9cda8b3875e297c23917ea42f4420cf4d2 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Tue, 25 Oct 2016 02:35:29 +0900 Subject: [PATCH 5006/5359] tests for bash completion into a scenario --- features/cli-bash-completion.feature | 67 +++++++++++++--------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index d1c8a69bc..84dda519e 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -79,6 +79,38 @@ Feature: `wp cli completions` tasks And STDERR should be empty And the return code should be 0 + When I run `wp cli completions --line='wp bogus-comand ' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp eva' --point=100` + Then STDOUT should contain: + """ + eval + """ + And STDOUT should contain: + """ + eval-file + """ + + When I run `wp cli completions --line='wp core config --dbname=' --point=100` + Then STDOUT should be empty + + When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` + Then STDOUT should not contain: + """ + --dbname= + """ + And STDOUT should contain: + """ + --extra-php + """ + + When I run `wp cli completions --line='wp media import ' --point=100` + Then STDOUT should contain: + """ + <file> + """ + Scenario: Bash Completion with SSH aliases Given an empty directory And a wp-cli.yml file: @@ -174,38 +206,3 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 - - Scenario: Generate completions - Given an empty directory - - When I run `wp cli completions --line='wp bogus-comand ' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp eva' --point=100` - Then STDOUT should contain: - """ - eval - """ - And STDOUT should contain: - """ - eval-file - """ - - When I run `wp cli completions --line='wp core config --dbname=' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` - Then STDOUT should not contain: - """ - --dbname= - """ - And STDOUT should contain: - """ - --extra-php - """ - - When I run `wp cli completions --line='wp media import ' --point=100` - Then STDOUT should contain: - """ - <file> - """ From e6e968e212bd3fb353368e5fb53483109953c5e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 25 Oct 2016 04:59:01 -0700 Subject: [PATCH 5007/5359] Update `.mailmap` with new contributors --- .mailmap | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.mailmap b/.mailmap index ff35d0d23..4efa4897b 100644 --- a/.mailmap +++ b/.mailmap @@ -9,6 +9,7 @@ andyexeter <palmer.andy@gmail.com> BA <kau@connecticum.de> bartaakos <akos@netpositive.hu> bendoh <ben@thinkoomph.com> +Bernhard Kau <github@kau-boys.de> Bobby Walters <bobbymwalters@gmail.com> BoiteAWeb <juliobosk@gmail.com> boonebgorges <boonebgorges@gmail.com> @@ -43,6 +44,7 @@ ericmann <eric@eamann.com> ernilambar <nilambar@outlook.com> eugeneware <eugene@noblesamurai.com> Evan Mattson <me@aaemnnost.tv> +Fabian Isele <uxdmm@student.kit.edu> francescolaffi <francesco.laffi@gmail.com> Frank Staude <frank@staude.net> Frankie Jarrett <fjarrett@godaddy.com> @@ -78,6 +80,7 @@ johnbillion <johnbillion@gmail.com> johnpbloch <jbloch@John-Blochs-iMac.local> johnpbloch <johnpbloch@gmail.com> jonathanbardo <jonathanbardo@users.noreply.github.com> +Jorge A. Torres <j@jorgetorres.co> Josh Eaton <josh@josheaton.org> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> @@ -140,6 +143,7 @@ phh <phh@peytz.dk> Pippin Williamson <pippin@pippinsplugins.com> Rachel Baker <rachel@rachelbaker.me> Radu Dan <za_creature@yahoo.com> +Rahul Prajapati <rahul.prajapati@rtcamp.com> Rarst <contact@rarst.net> robertboloc <robertboloc@gmail.com> Robin Schneider <ypid@riseup.net> @@ -165,6 +169,7 @@ soulou <leo@soulou.fr> spacedmonkey <spacedmonkey2@gmail.com> SpikesDivZero <wesley.spikes@gmail.com> spuriousdata <spuriousdata@gmail.com> +Stephen Beemsterboer <balbuf@users.noreply.github.com> Stephen Edgar <stephen@netweb.com.au> Stephen Harris <contact@stephenharris.info> Stephen Harris <Stephen.Harris@gov.scot> @@ -175,6 +180,7 @@ Steve Grunwell <stevegrunwell@gmail.com> Steve Persch <steve.persch@pantheon.io> Steven K Word <stevenword@gmail.com> stianlik <stianlik@gmail.com> +Stéphane HULARD <s.hulard@chstudio.fr> svaj <chris@chrisbot.(none)> Svetoslav Marinov (Slavi) <slavi@orbisius.com> szepeviktor <viktor@szepe.net> @@ -186,11 +192,13 @@ tlovett1 <admin@taylorlovett.com> tollmanz <zack@zackdev.com> toszcze <toszcze@gmail.com> tott <tott@automattic.com> +Travis Northcutt <travis@memberup.co> trepmal <trepmal@gmail.com> Tristan Penman <tristan@tristanpenman.com> twisty <tim@brayshaw.com> twratajczak <tomasz.ratajczak@espeo.pl> Utkarsh Patel <iamutkarsh@live.com> +veganista <liam@nanothree.net> Ville Vuorenmaa <villevuor@gmail.com> voldemortensen <voldemortensen@users.noreply.github.com> Wendell Júnior <wrnx00@gmail.com> From 4d6f3db820b4248bdcd3069b9a9154ef8586d03f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 25 Oct 2016 05:02:51 -0700 Subject: [PATCH 5008/5359] Bump version to 0.25.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4037ec065..d21d277be 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.25.0-alpha +0.25.0 From 41e5e536361b6572576f7f54bdb2efce621c1e99 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 25 Oct 2016 12:16:42 -0700 Subject: [PATCH 5009/5359] Bump working version to v0.26.0-alpha The version that will never be released --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4037ec065..eae71f7ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.25.0-alpha +0.26.0-alpha From 7af9e43838b7e612cb708c5c45717ae6c50ddd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 25 Oct 2016 23:59:24 +0200 Subject: [PATCH 5010/5359] Proper coding style for wp-config We don't have to copy ugliness. --- templates/wp-config.mustache | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache index 7776f301e..265a925cc 100644 --- a/templates/wp-config.mustache +++ b/templates/wp-config.mustache @@ -20,22 +20,22 @@ // ** MySQL settings ** // /** The name of the database for WordPress */ -define('DB_NAME', '{{dbname}}'); +define( 'DB_NAME', '{{dbname}}' ); /** MySQL database username */ -define('DB_USER', '{{dbuser}}'); +define( 'DB_USER', '{{dbuser}}' ); /** MySQL database password */ -define('DB_PASSWORD', '{{dbpass}}'); +define( 'DB_PASSWORD', '{{dbpass}}' ); /** MySQL hostname */ -define('DB_HOST', '{{dbhost}}'); +define( 'DB_HOST', '{{dbhost}}' ); /** Database Charset to use in creating database tables. */ -define('DB_CHARSET', '{{dbcharset}}'); +define( 'DB_CHARSET', '{{dbcharset}}' ); /** The Database Collate type. Don't change this if in doubt. */ -define('DB_COLLATE', '{{dbcollate}}'); +define( 'DB_COLLATE', '{{dbcollate}}' ); /** * Authentication Unique Keys and Salts. @@ -59,7 +59,7 @@ define('DB_COLLATE', '{{dbcollate}}'); $table_prefix = '{{dbprefix}}'; {{#add-wplang}} -define('WPLANG', '{{locale}}'); +define( 'WPLANG', '{{locale}}' ); {{/add-wplang}} {{extra-php}} @@ -67,8 +67,8 @@ define('WPLANG', '{{locale}}'); /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ -if ( !defined('ABSPATH') ) - define('ABSPATH', dirname(__FILE__) . '/'); +if ( ! defined( 'ABSPATH' ) ) + define( 'ABSPATH', dirname( __FILE__ ) . '/' ); /** Sets up WordPress vars and included files. */ -require_once(ABSPATH . 'wp-settings.php'); +require_once ABSPATH . 'wp-settings.php'; From db0617fc058ddc34f0fec6e78908f2611b5bb4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 26 Oct 2016 00:21:24 +0200 Subject: [PATCH 5011/5359] Fix PHP-CLi dependency Linitian will complain as this deb is a cross-release package. `E: php-wpcli: php-script-but-no-phpX-cli-dep usr/bin/wp` --- utils/wp-cli-updatedeb.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index ee222436c..371c982e8 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -3,8 +3,8 @@ # Package wp-cli to be installed in Debian-compatible systems. # Only the phar file is included. # -# VERSION :0.2 -# DATE :2014-11-19 +# VERSION :0.2.1 +# DATE :2016-10-26 # AUTHOR :Viktor Szépe <viktor@szepe.net> # LICENSE :The MIT License (MIT) # URL :https://github.com/wp-cli/wp-cli/tree/master/utils @@ -31,7 +31,7 @@ Architecture: all Maintainer: Daniel Bachhuber <daniel@handbuilt.co> Section: php Priority: optional -Depends: php5-cli | php7.0-cli, php5-mysql | php5-mysqlnd | php7.0-mysql, mysql-client | mariadb-client +Depends: php5-cli (>= 5.3.29) | php-cli | php7-cli, php5-mysql | php5-mysqlnd | php7.0-mysql, mysql-client | mariadb-client Homepage: http://wp-cli.org/ Description: wp-cli is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite @@ -102,6 +102,9 @@ popd WPCLI_PKG="${PWD}/php-wpcli_${WPCLI_VER}_all.deb" fakeroot dpkg-deb --build "$DIR" "$WPCLI_PKG" || die 8 "Packaging failed" +# check package +lintian --display-info --display-experimental --pedantic --show-overrides php-wpcli_*_all.deb + # optional steps echo "sign it: dpkg-sig -k YOUR-KEY -s builder \"${WPCLI_PKG}\"" echo "include in your repo: pushd /var/www/REPO-DIR" From 4608c0bbacd3470d52c2715f8ef0f04240174018 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 25 Oct 2016 16:24:30 -0700 Subject: [PATCH 5012/5359] Update Composer dependencies ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing mustangostang/spyc (0.5.1) - Installing mustangostang/spyc (0.6.1) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 977a97e13..8e1cfb7cc 100644 --- a/composer.lock +++ b/composer.lock @@ -379,21 +379,24 @@ }, { "name": "mustangostang/spyc", - "version": "0.5.1", + "version": "0.6.1", "source": { "type": "git", "url": "https://github.com/mustangostang/spyc.git", - "reference": "dc4785b4d7227fd9905e086d499fb8abfadf9977" + "reference": "022532641d61d383fd3ae666982bd46e61e5915e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mustangostang/spyc/zipball/dc4785b4d7227fd9905e086d499fb8abfadf9977", - "reference": "dc4785b4d7227fd9905e086d499fb8abfadf9977", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/022532641d61d383fd3ae666982bd46e61e5915e", + "reference": "022532641d61d383fd3ae666982bd46e61e5915e", "shasum": "" }, "require": { "php": ">=5.3.1" }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, "type": "library", "extra": { "branch-alias": { @@ -407,7 +410,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT License" + "MIT" ], "authors": [ { @@ -422,7 +425,7 @@ "yaml", "yml" ], - "time": "2013-02-21 10:52:01" + "time": "2016-10-21 00:03:34" }, { "name": "nb/oxymel", From 72c5209e8175329c97f99ca036fdb01ffeb0d5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 26 Oct 2016 01:00:02 +0000 Subject: [PATCH 5013/5359] Adjust tests to WPCS wp-config --- features/core-config.feature | 2 +- features/db.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-config.feature b/features/core-config.feature index df7186bde..3b12dadd4 100644 --- a/features/core-config.feature +++ b/features/core-config.feature @@ -67,5 +67,5 @@ Feature: Manage wp-config When I run `wp core config {CORE_CONFIG_SETTINGS}` Then the wp-config.php file should contain: """ - define('WPLANG', ''); + define( 'WPLANG', '' ); """ diff --git a/features/db.feature b/features/db.feature index ae97e5933..c315dd10f 100644 --- a/features/db.feature +++ b/features/db.feature @@ -117,7 +117,7 @@ Feature: Perform database operations When I run `cat wp-config.php` Then STDOUT should contain: """ - define('DB_CHARSET', ''); + define( 'DB_CHARSET', '' ); """ When I run `wp db create` From db107cc7bb42dbfda028f30b831d99684c550a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 26 Oct 2016 17:06:45 +0000 Subject: [PATCH 5014/5359] Fix WPLANG checking on all WP versions --- features/core-config.feature | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/features/core-config.feature b/features/core-config.feature index 3b12dadd4..7bc199c25 100644 --- a/features/core-config.feature +++ b/features/core-config.feature @@ -32,10 +32,6 @@ Feature: Manage wp-config """ define( 'WP_DEBUG_LOG', true ); """ - And the wp-config.php file should not contain: - """ - define( 'WPLANG', '' ); - """ When I try the previous command again Then the return code should be 1 @@ -50,6 +46,20 @@ Feature: Manage wp-config Error: The site you have requested is not installed """ + @require-wp-4.0 + Scenario: No wp-config.php and WPLANG + Given an empty directory + And WP files + Given a wp-config-extra.php file: + """ + define( 'WP_DEBUG_LOG', true ); + """ + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` + Then the wp-config.php file should not contain: + """ + define( 'WPLANG', '' ); + """ + Scenario: Configure with existing salts Given an empty directory And WP files From c24fce79f7a276ae8ab17054f6ae8e03de76ea53 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 26 Oct 2016 14:53:18 -0700 Subject: [PATCH 5015/5359] Ensure `WP_INSTALLING` is set for `wp core update-db` Core's `wp-admin/upgrade.php` sets this constant, so we should too. --- features/core-update-db.feature | 16 ++++++++++++++++ php/WP_CLI/Runner.php | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 88b48b7ce..7ad9fc2f2 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -88,3 +88,19 @@ Feature: Update core's database """ Success: WordPress database upgraded on 3/3 sites. """ + + Scenario: Ensure update-db sets WP_INSTALLING constant + Given a WP install + And a before.php file: + """ + <?php + WP_CLI::add_hook( 'before_invoke:core update-db', function(){ + WP_CLI::log( 'WP_INSTALLING: ' . var_export( WP_INSTALLING, true ) ); + }); + """ + + When I run `wp --require=before.php core update-db` + Then STDOUT should contain: + """ + WP_INSTALLING: true + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 97aaf7be8..352c9b283 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -875,7 +875,8 @@ public function start() { exit; } - if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) ) { + if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) + || $this->cmd_starts_with( array( 'core', 'update-db' ) ) ) ) { define( 'WP_INSTALLING', true ); } From 7aa4cb4359a8542f29dcdf131b30f7299180ef09 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 26 Oct 2016 15:20:40 -0700 Subject: [PATCH 5016/5359] Support WP LCache as a cache type --- php/utils-wp.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index 2b5ffbd38..24a78b3a1 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -203,6 +203,10 @@ function wp_get_cache_type() { } elseif ( isset( $wp_object_cache->redis ) && is_a( $wp_object_cache->redis, 'Redis' ) ) { $message = 'Redis'; + // Test for WP LCache Object cache (https://github.com/lcache/wp-lcache) + } elseif ( isset( $wp_object_cache->lcache ) && is_a( $wp_object_cache->lcache, '\LCache\Integrated' ) ) { + $message = 'WP LCache'; + } else { $message = 'Unknown'; } From c8efe12d9ad67beb1eb089a0a4a14c6c0c2d4304 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 26 Oct 2016 16:33:21 -0700 Subject: [PATCH 5017/5359] Fix conditional. Fortunately, this caused a lot of tests to break. --- php/WP_CLI/Runner.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 352c9b283..34d60cdff 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -875,8 +875,8 @@ public function start() { exit; } - if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) - || $this->cmd_starts_with( array( 'core', 'update-db' ) ) ) ) { + if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) + || $this->cmd_starts_with( array( 'core', 'update-db' ) ) ) { define( 'WP_INSTALLING', true ); } From 61573353f7dafb78e6b532f21ed14a61341ae9d6 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 27 Oct 2016 10:41:47 +0900 Subject: [PATCH 5018/5359] add `phpcs.ruleset.xml` to the help --- php/commands/scaffold.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 58f4e00a3..c3c0b2f31 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -422,6 +422,7 @@ private function get_output_path( $assoc_args, $subdir ) { * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. * * `tests/test-sample.php` is a sample file containing test cases. + * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. * * ## OPTIONS * @@ -545,6 +546,7 @@ function plugin( $args, $assoc_args ) { * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. * * `tests/test-sample.php` is a sample file containing the actual tests. + * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. * * Learn more from the [plugin unit tests documentation](http://wp-cli.org/docs/plugin-unit-tests/). * From 01688cb51bfe9ac597a9c2346d6176a5134d0073 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 29 Oct 2016 06:20:42 -0700 Subject: [PATCH 5019/5359] Include a note specific to deleting users on multisite --- php/commands/user.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/user.php b/php/commands/user.php index 79df0a05e..ca0af0853 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -209,6 +209,10 @@ public function get( $args, $assoc_args ) { /** * Delete one or more users from the current site. * + * On multisite, `wp user delete` only removes the user from the current + * site. Include `--network` to also remove the user from the database, but + * make sure to reassign their posts prior to deleting the user. + * * ## OPTIONS * * <user>... From 812f2a09965540ce5661233d2a410a758a61bb1b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 29 Oct 2016 06:40:13 -0700 Subject: [PATCH 5020/5359] Add test case for formatting CSV with RTL language --- features/formatter.feature | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/features/formatter.feature b/features/formatter.feature index aa1d67823..c9986999a 100644 --- a/features/formatter.feature +++ b/features/formatter.feature @@ -76,3 +76,37 @@ Feature: Format output label: Foo slug: foo """ + + Scenario: Format data in RTL language + Given an empty directory + And a file.php file: + """ + <?php + $items = array( + array( + 'id' => 1, + 'language' => 'Afrikaans', + 'is_rtl' => 0, + ), + array( + 'id' => 2, + 'language' => 'العَرَبÙيَّة‎‎', + 'is_rtl' => 1, + ), + array( + 'id' => 3, + 'language' => 'English', + 'is_rtl' => 0, + ), + ); + $assoc_args = array( 'format' => 'csv' ); + $formatter = new WP_CLI\Formatter( $assoc_args, array( 'id', 'language', 'is_rtl' ) ); + $formatter->display_items( $items ); + """ + + When I run `wp eval-file file.php --skip-wordpress` + Then STDOUT should be CSV containing: + | id | language | is_rtl | + | 1 | Afrikaans | 0 | + | 2 | العَرَبÙيَّة‎‎ | 1 | + | 3 | English | 0 | From 4ef9f935019a8bbcbc925e99c271baea9726fe62 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 31 Oct 2016 06:16:21 -0700 Subject: [PATCH 5021/5359] Update LICENSE year to 2016 --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 1b2b49c65..d77c42171 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,7 +2,7 @@ All code in this repository, unless otherwise specified, is hereby licensed under the MIT Public License: ========================================================================================================= -Copyright (C) 2011-2013 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) +Copyright (C) 2011-2016 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 5bf1ab7ea5064b841001321b9b89bea07358a209 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Nov 2016 09:10:08 -0700 Subject: [PATCH 5022/5359] Add `wp cli aliases` alias It's annoying to accidentally type this and get an error. --- features/aliases.feature | 8 ++++++++ php/commands/cli.php | 2 ++ 2 files changed, 10 insertions(+) diff --git a/features/aliases.feature b/features/aliases.feature index af9aa1c85..2255d4756 100644 --- a/features/aliases.feature +++ b/features/aliases.feature @@ -112,6 +112,14 @@ Feature: Create shortcuts to specific WordPress installs path: testdir """ + When I run `wp cli aliases` + Then STDOUT should be YAML containing: + """ + @all: Run command against every registered alias. + @testdir: + path: testdir + """ + When I run `wp cli alias --format=json` Then STDOUT should be JSON containing: """ diff --git a/php/commands/cli.php b/php/commands/cli.php index 03996e886..73c3f53f5 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -519,6 +519,8 @@ public function completions( $_, $assoc_args ) { * @both: * - @prod * - @dev + * + * @alias aliases */ public function alias( $_, $assoc_args ) { WP_CLI::print_value( WP_CLI::get_runner()->aliases, $assoc_args ); From 073b749d6d9fcee11aaf6c3f8deb6329c6ab1c04 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Nov 2016 10:14:27 -0700 Subject: [PATCH 5023/5359] Call out runcommand premium support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58885a58f..3040016f1 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ WP-CLI's maintainers and project contributors are volunteers, and have limited a - [runcommand Excerpts](https://runcommand.io/excerpts/) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) -If you can't find your answer at one of those links, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand](https://runcommand.io/) for premium support. +If you can't find your answer at one of those links, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand premium support](https://runcommand.io/pricing/). Github issues are meant for tracking enhancements and bugs of existing commands, not general support. Before submitting a bug report, please [review our best practices](https://wp-cli.org/docs/bug-reports/) to help ensure your issue is addressed in a timely manner. From b634016234a4ecaa1d8b432e6df669df1194d0c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Nov 2016 10:16:53 -0700 Subject: [PATCH 5024/5359] Update current version in README to 0.25.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58885a58f..4b338acdf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ WP-CLI root dir: /home/wp-cli/.wp-cli WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ WP-CLI global config: /home/wp-cli/.wp-cli/config.yml WP-CLI project config: -WP-CLI version: 0.24.1 +WP-CLI version: 0.25.0 ``` ### Updating From a082912c191f59af11d7f38a458dd27d66036943 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 1 Nov 2016 14:21:28 -0700 Subject: [PATCH 5025/5359] Verify release hash when updating --- features/cli.feature | 22 +++++++++++++++++++--- php/commands/cli.php | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/features/cli.feature b/features/cli.feature index 83fd15d63..a26272c6b 100644 --- a/features/cli.feature +++ b/features/cli.feature @@ -44,6 +44,10 @@ Feature: `wp cli` tasks When I run `{PHAR_PATH} cli update --yes` Then STDOUT should contain: + """ + md5 hash verified: + """ + And STDOUT should contain: """ Success: """ @@ -73,9 +77,13 @@ Feature: `wp cli` tasks When I run `{PHAR_PATH} cli update --patch --yes` Then STDOUT should contain: - """ - Success: Updated WP-CLI to 0.14.1 - """ + """ + md5 hash verified: 3f5fa2fda8457a9a5dc9875f17a3716d + """ + And STDOUT should contain: + """ + Success: Updated WP-CLI to 0.14.1 + """ And STDERR should be empty And the return code should be 0 @@ -108,6 +116,10 @@ Feature: `wp cli` tasks When I run `{PHAR_PATH} cli update --nightly --yes` Then STDOUT should contain: + """ + md5 hash verified: + """ + And STDOUT should contain: """ Success: Updated WP-CLI to the latest nightly release. """ @@ -133,6 +145,10 @@ Feature: `wp cli` tasks """ You have version 0.14.0. Would you like to update to the latest stable release? [y/n] """ + And STDOUT should contain: + """ + md5 hash verified: + """ And STDOUT should contain: """ Success: Updated WP-CLI to the latest stable release. diff --git a/php/commands/cli.php b/php/commands/cli.php index 73c3f53f5..462a12812 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -241,9 +241,11 @@ public function update( $_, $assoc_args ) { if ( Utils\get_flag_value( $assoc_args, 'nightly' ) ) { WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest nightly?', WP_CLI_VERSION ), $assoc_args ); $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar'; + $md5_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar.md5'; } else if ( Utils\get_flag_value( $assoc_args, 'stable' ) ) { WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest stable release?', WP_CLI_VERSION ), $assoc_args ); $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar'; + $md5_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar.md5'; } else { $updates = $this->get_updates( $assoc_args ); @@ -259,7 +261,7 @@ public function update( $_, $assoc_args ) { WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); $download_url = $newest['package_url']; - + $md5_url = str_replace( '.phar', '.phar.md5', $download_url ); } WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); @@ -274,6 +276,18 @@ public function update( $_, $assoc_args ) { Utils\http_request( 'GET', $download_url, null, $headers, $options ); + $md5_response = Utils\http_request( 'GET', $md5_url ); + if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$md5_response->status_code})." ); + } + $md5_file = md5_file( $temp ); + $release_hash = trim( $md5_response->body ); + if ( $md5_file === $release_hash ) { + WP_CLI::log( 'md5 hash verified: ' . $release_hash ); + } else { + WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$release_hash})." ); + } + $allow_root = WP_CLI::get_runner()->config['allow-root'] ? '--allow-root' : ''; $php_binary = WP_CLI::get_php_binary(); $process = WP_CLI\Process::create( "{$php_binary} $temp --info {$allow_root}" ); From a42acc96d82f3dc1f9097383cf29a7735d079a25 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 2 Nov 2016 10:29:37 -0700 Subject: [PATCH 5026/5359] Ignore `.DS_Store` from git --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6f4883762..1e56307f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store config.yml PHAR_BUILD_VERSION /cache From b12d2f8ad6ece75755bc373c66f7c24d67270a63 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 3 Nov 2016 05:05:22 -0700 Subject: [PATCH 5027/5359] Use supplied version in package composer.json, instead of "dev-master" --- features/package-install.feature | 72 ++++++++++++++++++++++++++++++++ php/commands/package.php | 12 ++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index 5f0a0216c..ca15b1e93 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -333,3 +333,75 @@ Feature: Install WP-CLI packages """ wp-cli/community-command """ + + Scenario: Install a package at an existing path with a version constraint + Given an empty directory + And a path-command/command.php file: + """ + <?php + WP_CLI::add_command( 'community-command', function(){ + WP_CLI::success( "success!" ); + }, array( 'when' => 'before_wp_load' ) ); + """ + And a path-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "version": "0.2.0-beta", + "require": { + }, + "autoload": { + "files": [ "command.php" ] + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + + When I run `pwd` + Then save STDOUT as {CURRENT_PATH} + + When I run `wp package install path-command` + Then STDOUT should contain: + """ + Installing package wp-cli/community-command (0.2.0-beta) + Updating {PACKAGE_PATH}composer.json to require the package... + Registering {CURRENT_PATH}/path-command as a path repository... + Using Composer to install the package... + """ + And STDOUT should contain: + """ + Success: Package installed successfully. + """ + + When I run `wp package list --fields=name` + Then STDOUT should be a table containing rows: + | name | + | wp-cli/community-command | + + When I run `wp community-command` + Then STDOUT should be: + """ + Success: success! + """ + + When I run `wp package uninstall wp-cli/community-command` + Then STDOUT should contain: + """ + Removing require statement from {PACKAGE_PATH}composer.json + """ + And STDOUT should contain: + """ + Success: Uninstalled package. + """ + And the path-command directory should exist + + When I run `wp package list --fields=name` + Then STDOUT should not contain: + """ + wp-cli/community-command + """ diff --git a/php/commands/package.php b/php/commands/package.php index d4f31c300..da8470584 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -213,7 +213,7 @@ public function install( $args, $assoc_args ) { try { // Extract the package to get the package name Extractor::extract( $package_name, $dir_package ); - $package_name = self::get_package_name_from_dir_package( $dir_package ); + list( $package_name, $version ) = self::get_package_name_and_version_from_dir_package( $dir_package ); // Move to a location based on the package name $local_dir = rtrim( WP_CLI::get_runner()->get_packages_dir_path(), '/' ) . '/local/'; $actual_dir_package = $local_dir . str_replace( '/', '-', $package_name ); @@ -229,7 +229,7 @@ public function install( $args, $assoc_args ) { if ( ! Utils\is_path_absolute( $dir_package ) ) { $dir_package = getcwd() . DIRECTORY_SEPARATOR . $dir_package; } - $package_name = self::get_package_name_from_dir_package( $dir_package ); + list( $package_name, $version ) = self::get_package_name_and_version_from_dir_package( $dir_package ); } else { if ( false !== strpos( $package_name, ':' ) ) { list( $package_name, $version ) = explode( ':', $package_name ); @@ -622,19 +622,23 @@ private function is_package_installed( $package_name ) { * @param string $dir_package * @return string */ - private static function get_package_name_from_dir_package( $dir_package ) { + private static function get_package_name_and_version_from_dir_package( $dir_package ) { $composer_file = $dir_package . '/composer.json'; $package_name = ''; + $version = 'dev-master'; if ( file_exists( $composer_file ) ) { $composer_data = json_decode( file_get_contents( $composer_file ), true ); if ( ! empty( $composer_data['name'] ) ) { $package_name = $composer_data['name']; } + if ( ! empty( $composer_data['version'] ) ) { + $version = $composer_data['version']; + } } if ( empty( $package_name ) ) { WP_CLI::error( "Invalid package." ); } - return $package_name; + return array( $package_name, $version ); } /** From 7a1bee132dd1fd18a2310cb72e187532d1827d5b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 3 Nov 2016 05:08:28 -0700 Subject: [PATCH 5028/5359] Ignore distribution files in `.gitignore` and `.distignore` --- templates/plugin-distignore.mustache | 2 ++ templates/plugin-gitignore.mustache | 2 ++ 2 files changed, 4 insertions(+) diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache index 79706582a..9e304aa93 100644 --- a/templates/plugin-distignore.mustache +++ b/templates/plugin-distignore.mustache @@ -20,3 +20,5 @@ wp-cli.local.yml tests vendor node_modules +*.zip +*.tar.gz diff --git a/templates/plugin-gitignore.mustache b/templates/plugin-gitignore.mustache index 20830a4a0..833593b8d 100644 --- a/templates/plugin-gitignore.mustache +++ b/templates/plugin-gitignore.mustache @@ -2,3 +2,5 @@ Thumbs.db wp-cli.local.yml node_modules/ +*.zip +*.tar.gz From f6fd9f03d189fb6d0ac14b0be6078f3320c79b1c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 3 Nov 2016 09:02:57 -0700 Subject: [PATCH 5029/5359] Add roadmap link to index; mention officially supported version --- .github/ISSUE_TEMPLATE | 4 ++++ README.md | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index cb4e8a83a..af2e2f4bf 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -4,8 +4,12 @@ Thanks for taking the time to help improve WP-CLI! Found a bug or want to suggest an enhancement to an existing command? Before creating an issue, please review our best practices: http://wp-cli.org/docs/bug-reports/ +But first, make sure you're running the most recent version of WP-CLI! The current version is the only officially supported version. + Need help with something? Github issues aren't for general support questions, but there are other venues you can try: http://wp-cli.org/#support +Want to suggest a feature? Check out the roadmap for how feature development happens: https://wp-cli.org/docs/roadmap/ + You can safely delete this comment. --> diff --git a/README.md b/README.md index ce7b8b1dc..6c2a98ec9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ WP-CLI [WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. -To stay up to date, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). +For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. [![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") @@ -104,7 +104,9 @@ source /FULL/PATH/TO/wp-completion.bash ## Support -WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. First, look for an answer in one of the following resources: +WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. The [current version of WP-CLI](http://wp-cli.org/docs/roadmap/) is the only officially supported version. + +When looking for support, please first look for an answer in one of the following resources: - [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) - [Documentation portal](https://wp-cli.org/docs/) @@ -112,7 +114,7 @@ WP-CLI's maintainers and project contributors are volunteers, and have limited a - [runcommand Excerpts](https://runcommand.io/excerpts/) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) -If you can't find your answer at one of those links, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Professional users may also consider [runcommand premium support](https://runcommand.io/pricing/). +Need help with a project related to work? Professional users may want to consider [runcommand premium support](https://runcommand.io/pricing/). Alternatively, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Github issues are meant for tracking enhancements and bugs of existing commands, not general support. Before submitting a bug report, please [review our best practices](https://wp-cli.org/docs/bug-reports/) to help ensure your issue is addressed in a timely manner. From c341214ab51fcb333505e51bfb90ed212e70960b Mon Sep 17 00:00:00 2001 From: "Peter J. Herrel" <peterherrel@gmail.com> Date: Fri, 4 Nov 2016 11:25:44 +0100 Subject: [PATCH 5030/5359] wp post delete revisions success message When deleting revisions (e.g. `wp post delete $(wp post list --post_type='revision' --format=ids)`), the success message reads `Success: Trashed post {$post_id}`, which is incorrect. --- php/commands/post.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/commands/post.php b/php/commands/post.php index 96e1ee81f..e19423017 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -253,10 +253,11 @@ public function delete( $args, $assoc_args ) { parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { $status = get_post_status( $post_id ); + $post_type = get_post_type( $post_id ); $r = wp_delete_post( $post_id, $assoc_args['force'] ); if ( $r ) { - $action = $assoc_args['force'] || 'trash' === $status ? 'Deleted' : 'Trashed'; + $action = $assoc_args['force'] || 'trash' === $status || 'revision' === $post_type ? 'Deleted' : 'Trashed'; return array( 'success', "$action post $post_id." ); } else { From 44644672f5000157e8cfde75f28b7c8e29e1acec Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Nov 2016 06:00:19 -0700 Subject: [PATCH 5031/5359] Update Composer dependencies to latest ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.12) - Installing symfony/yaml (v2.8.13) Downloading: 100% - Removing symfony/filesystem (v2.8.12) - Installing symfony/filesystem (v2.8.13) Downloading: 100% - Removing symfony/config (v2.8.12) - Installing symfony/config (v2.8.13) Loading from cache - Removing symfony/debug (v2.8.12) - Installing symfony/debug (v2.8.13) Loading from cache - Removing symfony/dependency-injection (v2.8.12) - Installing symfony/dependency-injection (v2.8.13) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.12) - Installing symfony/event-dispatcher (v2.8.13) Downloading: 100% - Removing symfony/translation (v2.8.12) - Installing symfony/translation (v2.8.13) Downloading: 100% - Removing symfony/process (v2.8.12) - Installing symfony/process (v2.8.13) Loading from cache - Removing symfony/finder (v2.8.12) - Installing symfony/finder (v2.8.13) Loading from cache - Removing symfony/console (v2.8.12) - Installing symfony/console (v2.8.13) Downloading: 100% - Removing composer/ca-bundle (1.0.4) - Installing composer/ca-bundle (1.0.6) Downloading: 100% - Removing composer/composer (1.2.1) - Installing composer/composer (1.2.2) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 88 +++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/composer.lock b/composer.lock index 8e1cfb7cc..05501fd11 100644 --- a/composer.lock +++ b/composer.lock @@ -9,16 +9,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.0.4", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680" + "reference": "a795611394b3c05164fd0eb291b492b39339cba4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/ec21a59414b99501e723b63fd664aa8ead9c5680", - "reference": "ec21a59414b99501e723b63fd664aa8ead9c5680", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/a795611394b3c05164fd0eb291b492b39339cba4", + "reference": "a795611394b3c05164fd0eb291b492b39339cba4", "shasum": "" }, "require": { @@ -63,20 +63,20 @@ "ssl", "tls" ], - "time": "2016-09-04 19:00:06" + "time": "2016-11-02 18:11:27" }, { "name": "composer/composer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "16422c4b1ac4286f7caecf5211136dc073191672" + "reference": "5465af955800fa884a36f66ff65280584988efd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/16422c4b1ac4286f7caecf5211136dc073191672", - "reference": "16422c4b1ac4286f7caecf5211136dc073191672", + "url": "https://api.github.com/repos/composer/composer/zipball/5465af955800fa884a36f66ff65280584988efd0", + "reference": "5465af955800fa884a36f66ff65280584988efd0", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2016-09-12 09:27:20" + "time": "2016-11-03 16:43:15" }, { "name": "composer/semver", @@ -749,7 +749,7 @@ }, { "name": "symfony/config", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/config.git", @@ -802,16 +802,16 @@ }, { "name": "symfony/console", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4" + "reference": "7350016c8abcab897046f1aead2b766b84d3eff8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d7a5a88178f94dcc29531ea4028ea614e35452d4", - "reference": "d7a5a88178f94dcc29531ea4028ea614e35452d4", + "url": "https://api.github.com/repos/symfony/console/zipball/7350016c8abcab897046f1aead2b766b84d3eff8", + "reference": "7350016c8abcab897046f1aead2b766b84d3eff8", "shasum": "" }, "require": { @@ -859,11 +859,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-09-28 00:10:16" + "time": "2016-10-06 01:43:09" }, { "name": "symfony/debug", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -920,16 +920,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75" + "reference": "3d61c765daa1a5832f1d7c767f48886b8d8ea64c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ee9ec9ac2b046462d341e9de7c4346142d335e75", - "reference": "ee9ec9ac2b046462d341e9de7c4346142d335e75", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3d61c765daa1a5832f1d7c767f48886b8d8ea64c", + "reference": "3d61c765daa1a5832f1d7c767f48886b8d8ea64c", "shasum": "" }, "require": { @@ -979,20 +979,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-09-24 09:47:20" + "time": "2016-10-24 15:52:36" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8" + "reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8", - "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/25c576abd4e0f212e678fe8b2bd9a9a98c7ea934", + "reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934", "shasum": "" }, "require": { @@ -1039,20 +1039,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-07-28 16:56:28" + "time": "2016-10-13 01:43:15" }, { "name": "symfony/filesystem", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf" + "reference": "a3784111af9f95f102b6411548376e1ae7c93898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/44b499521defddf2eae17a18c811bbdae4f98bdf", - "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/a3784111af9f95f102b6411548376e1ae7c93898", + "reference": "a3784111af9f95f102b6411548376e1ae7c93898", "shasum": "" }, "require": { @@ -1088,11 +1088,11 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-09-06 10:55:00" + "time": "2016-10-18 04:28:30" }, { "name": "symfony/finder", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -1200,7 +1200,7 @@ }, { "name": "symfony/process", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -1249,16 +1249,16 @@ }, { "name": "symfony/translation", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bf0ff95faa9b6c0708efc1986255e3608d0ed3c7" + "reference": "cca6ff892355876534b01a927f789bac9601c935" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bf0ff95faa9b6c0708efc1986255e3608d0ed3c7", - "reference": "bf0ff95faa9b6c0708efc1986255e3608d0ed3c7", + "url": "https://api.github.com/repos/symfony/translation/zipball/cca6ff892355876534b01a927f789bac9601c935", + "reference": "cca6ff892355876534b01a927f789bac9601c935", "shasum": "" }, "require": { @@ -1309,20 +1309,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-09-06 10:55:00" + "time": "2016-10-18 04:28:30" }, { "name": "symfony/yaml", - "version": "v2.8.12", + "version": "v2.8.13", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c" + "reference": "396784cd06b91f3db576f248f2402d547a077787" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e7540734bad981fe59f8ef14b6fc194ae9df8d9c", - "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/396784cd06b91f3db576f248f2402d547a077787", + "reference": "396784cd06b91f3db576f248f2402d547a077787", "shasum": "" }, "require": { @@ -1358,7 +1358,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-09-02 01:57:56" + "time": "2016-10-21 20:59:10" }, { "name": "wp-cli/php-cli-tools", From 0e9540eccfe8c13f1bb3ccad2d8533199d416569 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 6 Nov 2016 06:23:08 -0800 Subject: [PATCH 5032/5359] Clarify docs in the `wp cache *` set of commands --- php/commands/cache.php | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/php/commands/cache.php b/php/commands/cache.php index b887cea95..dbed0ef34 100644 --- a/php/commands/cache.php +++ b/php/commands/cache.php @@ -3,7 +3,7 @@ /** * Manage the object cache. * - * Note: Persistent Object Caching is needed for these commands. + * Use a persistent object cache drop-in to persist cache values between requests. * * ## EXAMPLES * @@ -22,7 +22,8 @@ class Cache_Command extends WP_CLI_Command { /** * Add a value to the object cache. * - * If a value already exists for the key, the value isn't added. + * Errors if a value already exists for the key, which means the value can't + * be added. * * ## OPTIONS * @@ -64,6 +65,8 @@ public function add( $args, $assoc_args ) { /** * Decrement a value in the object cache. * + * Errors if the value can't be decremented. + * * ## OPTIONS * * <key> @@ -100,6 +103,8 @@ public function decr( $args, $assoc_args ) { /** * Remove a value from the object cache. * + * Errors if the value can't be deleted. + * * ## OPTIONS * * <key> @@ -131,8 +136,12 @@ public function delete( $args, $assoc_args ) { /** * Flush the object cache. * - * For sites using a persistent object cache, because WordPress Multisite simply adds a blog id - * to the cache key, flushing cache is typically a global operation. + * For WordPress multisite instances using a persistent object cache, + * flushing the object cache will typically flush the cache for all sites. + * Beware of the performance impact when flushing the object cache in + * production. + * + * Errors if the object cache can't be flushed. * * ## EXAMPLES * @@ -153,6 +162,8 @@ public function flush( $args, $assoc_args ) { /** * Get a value from the object cache. * + * Errors if the value doesn't exist. + * * ## OPTIONS * * <key> @@ -184,6 +195,8 @@ public function get( $args, $assoc_args ) { /** * Increment a value in the object cache. * + * Errors if the value can't be incremented. + * * ## OPTIONS * * <key> @@ -220,6 +233,8 @@ public function incr( $args, $assoc_args ) { /** * Replace a value in the object cache, if the value already exists. * + * Errors if the value can't be replaced. + * * ## OPTIONS * * <key> @@ -262,6 +277,8 @@ public function replace( $args, $assoc_args ) { /** * Set a value to the object cache, regardless of whether it already exists. * + * Errors if the value can't be set. + * * ## OPTIONS * * <key> @@ -304,9 +321,10 @@ public function set( $args, $assoc_args ) { /** * Attempts to determine which object cache is being used. * - * Note that the guesses made by this function are based on the WP_Object_Cache classes - * that define the 3rd party object cache extension. Changes to those classes could render - * problems with this function's ability to determine which object cache is being used. + * Note that the guesses made by this function are based on the + * WP_Object_Cache classes that define the 3rd party object cache extension. + * Changes to those classes could render problems with this function's + * ability to determine which object cache is being used. * * ## EXAMPLES * @@ -318,6 +336,7 @@ public function type( $args, $assoc_args ) { $message = WP_CLI\Utils\wp_get_cache_type(); WP_CLI::line( $message ); } + } WP_CLI::add_command( 'cache', 'Cache_Command' ); From 4990fa316be34237fe8bb74772b8d8cc11632c0f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 6 Nov 2016 06:38:56 -0800 Subject: [PATCH 5033/5359] Clarify docs in the `wp cli *` set of commands --- php/commands/cli.php | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/php/commands/cli.php b/php/commands/cli.php index 462a12812..3e7f5ee78 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -5,19 +5,19 @@ use \WP_CLI\Utils; /** - * Get information about WP-CLI itself. + * Manage WP-CLI itself. * * ## EXAMPLES * - * # Display CLI version. + * # Display the version currently installed. * $ wp cli version * WP-CLI 0.24.1 * - * # Check for update. + * # Check for updates to WP-CLI. * $ wp cli check-update * Success: WP-CLI is at the latest version. * - * # Update CLI. + * # Update WP-CLI to the latest stable release. * $ wp cli update * You have version 0.24.0. Would you like to update to 0.24.1? [y/n] y * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar... @@ -60,7 +60,20 @@ public function version() { } /** - * Print various data about the CLI environment. + * Print various details about the WP-CLI environment. + * + * Helpful for diagnostic purposes, this command shares: + * + * * PHP binary used. + * * PHP binary version. + * * php.ini configuration file used (which is typically different than web). + * * WP-CLI root dir: where WP-CLI is installed (if non-Phar install). + * * WP-CLI global config: where the global config YAML file is located. + * * WP-CLI project config: where the project config YAML file is located. + * * WP-CLI version: currently installed version. + * + * See [config docs](https://wp-cli.org/config/) for more details on global + * and project config YAML files. * * ## OPTIONS * @@ -119,7 +132,10 @@ public function info( $_, $assoc_args ) { } /** - * Check for update via Github API. Returns the available versions if there are updates, or empty if no update available. + * Check to see if there is a newer version of WP-CLI available. + * + * Queries the Github releases API. Returns available versions if there are + * updates available, or success message if using the latest release. * * ## OPTIONS * @@ -182,10 +198,10 @@ public function check_update( $_, $assoc_args ) { } /** - * Update WP-CLI. + * Update WP-CLI to the latest release. * - * Default behavior is to check the releases API for a newer version, and - * prompt if one is available. + * Default behavior is to check the releases API for the newest stable + * version, and prompt if one is available. * * Use `--stable` to install or reinstall the latest stable version. * @@ -502,7 +518,7 @@ public function completions( $_, $assoc_args ) { } /** - * List available aliases. + * List available WP-CLI aliases. * * Aliases are shorthand references to WordPress installs. For instance, * `@dev` could refer to a development install and `@prod` could refer to From b991f7fb76471d9fe52af97f3bd6faad245956d8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 6 Nov 2016 06:45:57 -0800 Subject: [PATCH 5034/5359] Clarify docs in the `wp db *` set of commands --- php/commands/db.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 465b0f316..5a8a88505 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -3,31 +3,31 @@ use \WP_CLI\Utils; /** - * Perform basic database operations. + * Perform basic database operations using credentials stored in wp-config.php * * ## EXAMPLES * - * # Create database + * # Create a new database. * $ wp db create * Success: Database created. * - * # Drop database + * # Drop an existing database. * $ wp db drop --yes * Success: Database dropped. * - * # Reset database + * # Reset the current database. * $ wp db reset --yes * Success: Database reset. * - * # Execute a query stored in a file + * # Execute a SQL query stored in a file. * $ wp db query < debug.sql */ class DB_Command extends WP_CLI_Command { /** - * Create the database in MySQL. + * Create a new database. * - * Runs `CREATE_DATABASE` MySQL statement using `DB_HOST`, `DB_NAME`, + * Runs `CREATE_DATABASE` SQL statement using `DB_HOST`, `DB_NAME`, * `DB_USER` and `DB_PASSWORD` database credentials specified in * wp-config.php. * @@ -44,9 +44,9 @@ public function create( $_, $assoc_args ) { } /** - * Delete the database in MySQL. + * Delete the existing database. * - * Runs `DROP_DATABASE` MySQL statement using `DB_HOST`, `DB_NAME`, + * Runs `DROP_DATABASE` SQL statement using `DB_HOST`, `DB_NAME`, * `DB_USER` and `DB_PASSWORD` database credentials specified in * wp-config.php. * @@ -69,9 +69,9 @@ public function drop( $_, $assoc_args ) { } /** - * Remove all tables from the database in MySQL. + * Remove all tables from the database. * - * Runs `DROP_DATABASE` and `CREATE_DATABASE` MySQL statements using + * Runs `DROP_DATABASE` and `CREATE_DATABASE` SQL statements using * `DB_HOST`, `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials * specified in wp-config.php. * @@ -95,7 +95,7 @@ public function reset( $_, $assoc_args ) { } /** - * Check the database in MySQL. + * Check the current status of the database. * * Runs `mysqlcheck` utility with `--check` using `DB_HOST`, * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials @@ -118,7 +118,7 @@ public function check() { } /** - * Optimize the database in MySQL. + * Optimize the database. * * Runs `mysqlcheck` utility with `--optimize=true` using `DB_HOST`, * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials @@ -141,7 +141,7 @@ public function optimize() { } /** - * Repair the database in MySQL. + * Repair the database. * * Runs `mysqlcheck` utility with `--repair=true` using `DB_HOST`, * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials @@ -181,9 +181,9 @@ public function cli() { } /** - * Execute a MySQL query against the database. + * Execute a SQL query against the database. * - * Executes an arbitrary MySQL query using `DB_HOST`, `DB_NAME`, `DB_USER` + * Executes an arbitrary SQL query using `DB_HOST`, `DB_NAME`, `DB_USER` * and `DB_PASSWORD` database credentials specified in wp-config.php. * * ## OPTIONS @@ -236,7 +236,7 @@ public function query( $args, $assoc_args ) { } /** - * Exports the MySQL database to a file or to STDOUT. + * Exports the database to a file or to STDOUT. * * Runs `mysqldump` utility using `DB_HOST`, `DB_NAME`, `DB_USER` and * `DB_PASSWORD` database credentials specified in wp-config.php. @@ -320,9 +320,9 @@ function export( $args, $assoc_args ) { } /** - * Import a MySQL database from a file or from STDIN. + * Import a database from a file or from STDIN. * - * Runs MySQL queries using `DB_HOST`, `DB_NAME`, `DB_USER` and + * Runs SQL queries using `DB_HOST`, `DB_NAME`, `DB_USER` and * `DB_PASSWORD` database credentials specified in wp-config.php. This * does not create database by itself and only performs whatever tasks are * defined in the SQL. @@ -367,9 +367,9 @@ public function import( $args, $assoc_args ) { } /** - * List the MySQL database tables. + * List the database tables. * - * Defaults to all tables registered to $wpdb. + * Defaults to all tables registered to the $wpdb database handler. * * ## OPTIONS * From 77da1b6cb87c4f1f93bb2578a9fb586ddd6a2ccf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 6 Nov 2016 11:01:43 -0800 Subject: [PATCH 5035/5359] Use `dist: trusty` on Travis It's newer and better. --- templates/plugin-travis.mustache | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 3fa9a0650..359d30d35 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -1,5 +1,7 @@ language: php +dist: trusty + notifications: email: on_success: never From 76e99cfa3acc84c9c72f44f2537b5ff2475da152 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Nov 2016 07:00:11 -0800 Subject: [PATCH 5036/5359] Use `--prompt=<assoc>` to prompt for specific associative args For instance: ``` wp core config --dbname=testing --dbuser=wp --prompt=dbpass < password.txt ``` This approach lets users avoid exposing secure data in bash history. --- features/core.feature | 20 ++++++++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 16 ++++++++++++++++ php/commands/core.php | 8 ++++++++ php/config-spec.php | 4 ++-- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/features/core.feature b/features/core.feature index 1659b7184..de3d601d0 100644 --- a/features/core.feature +++ b/features/core.feature @@ -66,6 +66,26 @@ Feature: Manage WordPress installation http://localhost:8001 """ + Scenario: Install WordPress by prompting for the admin email and password + Given an empty directory + And WP files + And wp-config.php + And a database + And a session file: + """ + wpcli + admin@example.com + """ + + When I run `wp core install --url=localhost:8001 --title=Test --admin_user=wpcli --prompt=admin_email,admin_password < session` + Then STDOUT should not be empty + + When I run `wp eval 'echo home_url();'` + Then STDOUT should be: + """ + http://localhost:8001 + """ + Scenario: Install WordPress with an https scheme Given an empty directory And WP files diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 6b832514a..4d394ff25 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -142,11 +142,27 @@ private function prompt_args( $args, $assoc_args ) { $spec = array_values( $spec ); + $prompt_args = WP_CLI::get_config( 'prompt' ); + if ( true !== $prompt_args ) { + $prompt_args = explode( ',', $prompt_args ); + } + // 'positional' arguments are positional (aka zero-indexed) // so $args needs to be reset before prompting for new arguments $args = array(); foreach( $spec as $key => $spec_arg ) { + // When prompting for specific arguments (e.g. --prompt=user_pass), + // ignore all arguments that don't match + if ( is_array( $prompt_args ) ) { + if ( 'assoc' !== $spec_arg['type'] ) { + continue; + } + if ( ! in_array( $spec_arg['name'], $prompt_args, true ) ) { + continue; + } + } + $current_prompt = ( $key + 1 ) . '/' . count( $spec ) . ' '; $default = ( $spec_arg['optional'] ) ? '' : false; diff --git a/php/commands/core.php b/php/commands/core.php index 063c4e3ac..e5a5b665f 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -336,6 +336,10 @@ private static function get_initial_locale() { * $ define( 'WP_DEBUG_LOG', true ); * $ PHP * Success: Generated 'wp-config.php' file. + * + * # Avoid disclosing password to bash history by reading from password.txt + * $ wp core config --dbname=testing --dbuser=wp --prompt=dbpass < password.txt + * Success: Generated 'wp-config.php' file. */ public function config( $_, $assoc_args ) { global $wp_version; @@ -469,8 +473,12 @@ public function is_installed( $_, $assoc_args ) { * * ## EXAMPLES * + * # Install WordPress in 5 seconds * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_password=strongpassword --admin_email=info@example.com * Success: WordPress installed successfully. + * + * # Install WordPress without disclosing admin_password to bash history + * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_email=info@example.com --prompt=admin_password < admin_password.txt */ public function install( $args, $assoc_args ) { if ( $this->_install( $assoc_args ) ) { diff --git a/php/config-spec.php b/php/config-spec.php index 11c6fffbd..63725e725 100644 --- a/php/config-spec.php +++ b/php/config-spec.php @@ -85,10 +85,10 @@ ), 'prompt' => array( - 'runtime' => '', + 'runtime' => '[=<assoc>]', 'file' => false, 'default' => false, - 'desc' => 'Prompt the user to enter values for all command arguments.', + 'desc' => 'Prompt the user to enter values for all command arguments, or a subset specified as comma-separated values.', ), 'quiet' => array( From 7d2e04cc1a3ff9202456c595640528dd4b960673 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Nov 2016 12:15:55 -0800 Subject: [PATCH 5037/5359] Default to a randomly generated password for `--admin_password=<pass>` This more closely mirrors WordPress' behavior of generating a default password for the admin user. --- features/core-install.feature | 34 ++++++++++++++++++++++++++++++++++ php/commands/core.php | 13 +++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/features/core-install.feature b/features/core-install.feature index 28adb8e20..32b1372f7 100644 --- a/features/core-install.feature +++ b/features/core-install.feature @@ -152,3 +152,37 @@ Feature: Install WordPress core """ wp_users """ + + Scenario: Install WordPress without specifying the admin password + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core install --url=localhost:8001 --title=Test --admin_user=wpcli --admin_email=wpcli@example.org` + Then STDOUT should contain: + """ + Admin password: + """ + And STDOUT should contain: + """ + Success: WordPress installed successfully. + """ + And STDERR should be empty + + Scenario: Install WordPress multisite without specifying the password + Given an empty directory + And WP files + And wp-config.php + And a database + + When I run `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com` + Then STDOUT should contain: + """ + Admin password: + """ + And STDOUT should contain: + """ + Success: Network installed. Don't forget to set up rewrite rules. + """ + And STDERR should be empty diff --git a/php/commands/core.php b/php/commands/core.php index e5a5b665f..d5ffb4e3c 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -462,8 +462,8 @@ public function is_installed( $_, $assoc_args ) { * --admin_user=<username> * : The name of the admin user. * - * --admin_password=<password> - * : The password for the admin user. + * [--admin_password=<password>] + * : The password for the admin user. Defaults to randomly generated string. * * --admin_email=<email> * : The email address for the admin user. @@ -558,8 +558,8 @@ public function multisite_convert( $args, $assoc_args ) { * default: admin * --- * - * --admin_password=<password> - * : The password for the admin user. + * [--admin_password=<password>] + * : The password for the admin user. Defaults to randomly generated string. * * --admin_email=<email> * : The email address for the admin user. @@ -664,6 +664,11 @@ function wp_new_blog_notification() { WP_CLI::set_url( $assoc_args['url'] ); } + if ( empty( $assoc_args['admin_password'] ) ) { + $assoc_args['admin_password'] = wp_generate_password(); + WP_CLI::log( "Admin password: {$assoc_args['admin_password']}" ); + } + $public = true; // @codingStandardsIgnoreStart From 61c5bf8f97357d7e1170ea70fcdb72548230599b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Nov 2016 17:07:48 -0800 Subject: [PATCH 5038/5359] Revert "Try Trusty on Travis" --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 670361dac..b811927a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ -dist: trusty sudo: false language: php From 1ef9c77266693424c198bb4ede317bde7594d271 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 8 Nov 2016 17:08:25 -0800 Subject: [PATCH 5039/5359] Revert "Use `dist: trusty` on Travis" --- templates/plugin-travis.mustache | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 359d30d35..3fa9a0650 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -1,7 +1,5 @@ language: php -dist: trusty - notifications: email: on_success: never From ea19e7a6f26582f504058595ff61864a78719ed5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 05:47:05 -0800 Subject: [PATCH 5040/5359] Add a basic command to update packages --- features/package-update.feature | 26 +++++++++++++++++ php/commands/package.php | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 features/package-update.feature diff --git a/features/package-update.feature b/features/package-update.feature new file mode 100644 index 000000000..67910ed66 --- /dev/null +++ b/features/package-update.feature @@ -0,0 +1,26 @@ +Feature: Update WP-CLI packages + + Background: + When I run `wp package path` + Then save STDOUT as {PACKAGE_PATH} + + Scenario: Updating WP-CLI packages runs successfully + Given an empty directory + + When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` + Then STDOUT should contain: + """ + Success: Package installed successfully. + """ + Then STDERR should be empty + + When I run `wp package update` + Then STDOUT should contain: + """ + Using Composer to update packages... + """ + And STDOUT should contain: + """ + Packages updated successfully. + """ + And STDERR should be empty diff --git a/php/commands/package.php b/php/commands/package.php index da8470584..976853d35 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -373,6 +373,56 @@ function path( $args ) { WP_CLI::line( $packages_dir ); } + /** + * Update all installed WP-CLI packages to their latest version. + * + * ## EXAMPLES + * + * $ wp package update + * Using Composer to update packages... + * --- + * Loading composer repositories with package information + * Updating dependencies + * Resolving dependencies through SAT + * Dependency resolution completed in 0.074 seconds + * Analyzed 1062 packages to resolve dependencies + * Analyzed 22383 rules to resolve dependencies + * Writing lock file + * Generating autoload files + * --- + * Success: Packages updated successfully. + */ + public function update() { + try { + $composer = $this->get_composer(); + } catch( Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + // Set up the EventSubscriber + $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber; + $composer->getEventDispatcher()->addSubscriber( $event_subscriber ); + + // Set up the installer + $install = Installer::create( new ComposerIO, $composer ); + $install->setUpdate( true ); // Installer class will only override composer.lock with this flag + $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. + WP_CLI::log( 'Using Composer to update packages...' ); + WP_CLI::log( '---' ); + $res = false; + try { + $res = $install->run(); + } catch ( Exception $e ) { + WP_CLI::warning( $e->getMessage() ); + } + WP_CLI::log( '---' ); + + if ( 0 === $res ) { + WP_CLI::success( "Packages updated successfully." ); + } else { + WP_CLI::error( "Failed to update packages (Composer return code {$res})." ); + } + } + /** * Uninstall a WP-CLI package. * From b806786e84614584e83aae0215ae20578e096561 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 05:47:41 -0800 Subject: [PATCH 5041/5359] Remove unused variable definition This block is used later in the method --- php/commands/package.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 976853d35..3aff25cfe 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -242,11 +242,6 @@ public function install( $args, $assoc_args ) { WP_CLI::log( sprintf( "Installing package %s (%s)", $package_name, $version ) ); - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } $composer_json_obj = $this->get_composer_json(); // Add the 'require' to composer.json From e80f69f042633b28e3c07ce56f4a0d7087e0361f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 05:54:39 -0800 Subject: [PATCH 5042/5359] Drop "successfully", which is implied from "Success:" --- features/package-install.feature | 10 +++++----- features/package-update.feature | 4 ++-- php/commands/package.php | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/features/package-install.feature b/features/package-install.feature index ca15b1e93..5f23e507d 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -140,7 +140,7 @@ Feature: Install WP-CLI packages """ And STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ When I run `wp package list --fields=name` @@ -184,7 +184,7 @@ Feature: Install WP-CLI packages """ And STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ When I run `wp package list --fields=name` @@ -233,7 +233,7 @@ Feature: Install WP-CLI packages """ And STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ When I run `wp package list --fields=name` @@ -303,7 +303,7 @@ Feature: Install WP-CLI packages """ And STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ When I run `wp package list --fields=name` @@ -375,7 +375,7 @@ Feature: Install WP-CLI packages """ And STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ When I run `wp package list --fields=name` diff --git a/features/package-update.feature b/features/package-update.feature index 67910ed66..a4b65f3cc 100644 --- a/features/package-update.feature +++ b/features/package-update.feature @@ -10,7 +10,7 @@ Feature: Update WP-CLI packages When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` Then STDOUT should contain: """ - Success: Package installed successfully. + Success: Package installed. """ Then STDERR should be empty @@ -21,6 +21,6 @@ Feature: Update WP-CLI packages """ And STDOUT should contain: """ - Packages updated successfully. + Packages updated. """ And STDERR should be empty diff --git a/php/commands/package.php b/php/commands/package.php index 3aff25cfe..7f0c85e6a 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -56,7 +56,7 @@ * Writing lock file * Generating autoload files * --- - * Success: Package installed successfully. + * Success: Package installed. * * # Uninstall package * $ wp package uninstall wp-cli/server-command @@ -170,7 +170,7 @@ public function browse( $_, $assoc_args ) { * Writing lock file * Generating autoload files * --- - * Success: Package installed successfully. + * Success: Package installed. * * # Install the latest stable version. * $ wp package install wp-cli/server-command:@stable @@ -295,7 +295,7 @@ public function install( $args, $assoc_args ) { WP_CLI::log( '---' ); if ( 0 === $res ) { - WP_CLI::success( "Package installed successfully." ); + WP_CLI::success( "Package installed." ); } else { file_put_contents( $composer_json_obj->getPath(), $composer_backup ); WP_CLI::error( "Package installation failed (Composer return code {$res}). Reverted composer.json" ); @@ -385,7 +385,7 @@ function path( $args ) { * Writing lock file * Generating autoload files * --- - * Success: Packages updated successfully. + * Success: Packages updated. */ public function update() { try { @@ -412,7 +412,7 @@ public function update() { WP_CLI::log( '---' ); if ( 0 === $res ) { - WP_CLI::success( "Packages updated successfully." ); + WP_CLI::success( "Packages updated." ); } else { WP_CLI::error( "Failed to update packages (Composer return code {$res})." ); } From 125e2f453596286450516b9b090cf77cd4f59576 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 06:29:43 -0800 Subject: [PATCH 5043/5359] Clarify docs in the `wp core *` set of commands --- php/commands/core.php | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index e5a5b665f..0d62993e6 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -5,7 +5,7 @@ use \WP_CLI\Utils; /** - * Download, install, update and otherwise manage WordPress proper. + * Download, install, update and manage a WordPress install. * * ## EXAMPLES * @@ -28,9 +28,10 @@ class Core_Command extends WP_CLI_Command { /** - * Check for update via Version Check API. + * Check for WordPress updates via Version Check API. * - * Lists the most recent versions when there are updates available, or success message when up to date. + * Lists the most recent versions when there are updates available, + * or success message when up to date. * * ## OPTIONS * @@ -87,6 +88,10 @@ function check_update( $_, $assoc_args ) { /** * Download core WordPress files. * + * Downloads and extracts WordPress core files to the specified path. Uses + * an archive file stored in cache if WordPress has been previously + * downloaded. + * * ## OPTIONS * * [--path=<path>] @@ -277,6 +282,9 @@ private static function get_initial_locale() { /** * Generate a wp-config.php file. * + * Creates a new wp-config.php with database constants, and verifies that + * the database constants are correct. + * * ## OPTIONS * * --dbname=<dbname> @@ -400,7 +408,11 @@ public function config( $_, $assoc_args ) { } /** - * Determine if the WordPress tables are installed. + * Check if WordPress is installed. + * + * Determines whether WordPress is installed by checking if the standard + * database tables are installed. Doesn't produce output; uses exit codes + * to communicate whether WordPress is installed. * * [--network] * : Check if this is a multisite install. @@ -489,7 +501,10 @@ public function install( $args, $assoc_args ) { } /** - * Transform a single-site install into a multi-site install. + * Transform a single-site install into a WordPress multisite install. + * + * Creates the multisite database tables, and adds the multisite constants + * to wp-config.php. * * For those using WordPress with Apache, remember to update the `.htaccess` * file with the appropriate multisite rewrite rules. @@ -533,7 +548,11 @@ public function multisite_convert( $args, $assoc_args ) { } /** - * Install multisite from scratch. + * Install WordPress multisite from scratch. + * + * Creates the WordPress tables in the database using the URL, title, and + * default admin user details provided. Then, creates the multisite tables + * in the database and adds multisite constants to the wp-config.php. * * ## OPTIONS * @@ -882,6 +901,9 @@ public function version( $args = array(), $assoc_args = array() ) { /** * Verify WordPress files against WordPress.org's checksums. * + * Downloads md5 checksums for the current version from WordPress.org, and + * compares those checksums against the currently installed files. + * * For security, avoids loading WordPress when verifying checksums. * * ## OPTIONS @@ -1099,7 +1121,9 @@ private static function get_core_checksums( $version, $locale ) { } /** - * Update WordPress. + * Update WordPress to a newer version. + * + * Defaults to updating WordPress to the latest version. * * ## OPTIONS * @@ -1265,7 +1289,7 @@ function update( $args, $assoc_args ) { } /** - * Update the WordPress database. + * Run the WordPress database update procedure. * * [--network] * : Update databases for all sites on a network From f5b80fe9b88b882066c2e54477114ef03c0e1a6a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 06:34:05 -0800 Subject: [PATCH 5044/5359] Clarify docs in the `wp cron *` set of commands --- php/commands/cron.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/php/commands/cron.php b/php/commands/cron.php index e87283355..03941849e 100644 --- a/php/commands/cron.php +++ b/php/commands/cron.php @@ -15,14 +15,16 @@ class Cron_Command extends WP_CLI_Command { * Test the WP Cron spawning system and report back its status. * * This command tests the spawning system by performing the following steps: + * * * Checks to see if the `DISABLE_WP_CRON` constant is set; errors if true * because WP-Cron is disabled. - * * Checks to see if the `ALTERNATE_WP_CRON` constant is set; warns if true + * * Checks to see if the `ALTERNATE_WP_CRON` constant is set; warns if true. * * Attempts to spawn WP-Cron over HTTP; warns if non 200 response code is * returned. * * ## EXAMPLES * + * # Cron test runs successfully. * $ wp cron test * Success: WP-Cron spawning is working as expected. */ @@ -56,8 +58,9 @@ public function test() { /** * Spawn a request to `wp-cron.php` and return the response. * - * This function is designed to mimic the functionality in `spawn_cron()` with the addition of returning - * the result of the `wp_remote_post()` request. + * This function is designed to mimic the functionality in `spawn_cron()` + * with the addition of returning the result of the `wp_remote_post()` + * request. * * @return WP_Error|array The response or WP_Error on failure. */ From 01233a9dd1870eae3d393ebfb09d8099aca728a0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 06:41:28 -0800 Subject: [PATCH 5045/5359] Clarify docs in the `wp comment *` set of commands --- php/commands/comment.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/php/commands/comment.php b/php/commands/comment.php index f16806964..7a5e029be 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -5,15 +5,15 @@ * * ## EXAMPLES * - * # Create comment. + * # Create a new comment. * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" * Success: Created comment 932. * - * # Update comment. + * # Update an existing comment. * $ wp comment update 123 --comment_author='That Guy' * Success: Updated comment 123. * - * # Delete comment. + * # Delete an existing comment. * $ wp comment delete 1337 --force * Success: Deleted comment 1337. * @@ -42,7 +42,7 @@ public function __construct() { } /** - * Insert a comment. + * Create a new comment. * * ## OPTIONS * @@ -110,7 +110,9 @@ public function update( $args, $assoc_args ) { } /** - * Generate comments. + * Generate some number of new dummy comments. + * + * Creates a specified number of new comments with dummy data. * * ## OPTIONS * @@ -187,7 +189,7 @@ public function generate( $args, $assoc_args ) { } /** - * Get a single comment. + * Get data of a single comment. * * ## OPTIONS * @@ -433,7 +435,7 @@ public function untrash( $args, $assoc_args ) { } /** - * Spam a comment. + * Mark a comment as spam. * * ## OPTIONS * @@ -453,7 +455,7 @@ public function spam( $args, $assoc_args ) { } /** - * Unspam a comment. + * Unmark a comment as spam. * * ## OPTIONS * @@ -558,7 +560,7 @@ public function count( $args, $assoc_args ) { } /** - * Recount the comment_count value for one or more posts. + * Recalculate the comment_count value for one or more posts. * * ## OPTIONS * @@ -612,6 +614,8 @@ public function status( $args, $assoc_args ) { /** * Verify whether a comment exists. * + * Displays a success message if the comment does exist. + * * ## OPTIONS * * <id> @@ -630,7 +634,7 @@ public function exists( $args ) { } /** - * Get comment URL. + * Get a comment's URL. * * ## OPTIONS * From 8a270c46c3318d901c1c0afab61e52df4c0b75d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 06:50:26 -0800 Subject: [PATCH 5046/5359] Clarify docs in the `wp option *` set of commands --- php/commands/option.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 04908ce39..12a486a42 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -31,7 +31,7 @@ class Option_Command extends WP_CLI_Command { /** - * Get an option. + * Get the value for an option. * * ## OPTIONS * @@ -70,7 +70,9 @@ public function get( $args, $assoc_args ) { } /** - * Add an option. + * Add a new option value. + * + * Errors if the option already exists. * * ## OPTIONS * @@ -123,7 +125,7 @@ public function add( $args, $assoc_args ) { } /** - * List options. + * List options and their values. * * ## OPTIONS * @@ -276,12 +278,12 @@ public function list_( $args, $assoc_args ) { } /** - * Update an option. + * Update an option value. * * ## OPTIONS * * <key> - * : The name of the option to add. + * : The name of the option to update. * * [<value>] * : The new value. If ommited, the value is read from STDIN. From f45b4b92c8e1f102884a8b46bfcfb0acc17f17ea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 06:57:24 -0800 Subject: [PATCH 5047/5359] Clarify docs in the `wp rewrite *` set of commands --- php/commands/rewrite.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 13ffcd4df..4803319cd 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -29,15 +29,15 @@ class Rewrite_Command extends WP_CLI_Command { /** * Flush rewrite rules. * - * ## DESCRIPTION - * * Resets WordPress' rewrite rules based on registered post types, etc. * * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module * to your wp-cli.yml or config.yml. For example: * - * `apache_modules: - * - mod_rewrite` + * ``` + * apache_modules: + * - mod_rewrite + * ``` * * ## OPTIONS * @@ -73,15 +73,16 @@ public function flush( $args, $assoc_args ) { /** * Update the permalink structure. * - * ## DESCRIPTION - * - * Updates the post permalink structure. + * Sets the post permalink structure to the specified pattern. * - * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module - * to your wp-cli.yml or config.yml. For example: + * To regenerate a .htaccess file with WP-CLI, you'll need to add + * the mod_rewrite module to your [WP-CLI config](http://wp-cli.org/config/). + * For example: * - * `apache_modules: - * - mod_rewrite` + * ``` + * apache_modules: + * - mod_rewrite + * ``` * * ## OPTIONS * @@ -162,7 +163,7 @@ public function structure( $args, $assoc_args ) { } /** - * Print current rewrite rules. + * Get a list of the current rewrite rules. * * ## OPTIONS * @@ -281,8 +282,10 @@ public function list_( $args, $assoc_args ) { * To get this to work with wp-cli you'll need to add the mod_rewrite module * to your config.yml. For example * + * ``` * apache_modules: * - mod_rewrite + * ``` * * If this isn't done then the .htaccess rewrite rules won't be flushed out * to disk. From 347ef5a7e75fc8f63821f2fde94f11c52fc81ba6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 07:00:35 -0800 Subject: [PATCH 5048/5359] Clarify docs in the `wp export` command --- php/commands/export.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/php/commands/export.php b/php/commands/export.php index 6278c3d2b..7e7bf7128 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -23,7 +23,11 @@ class Export_Command extends WP_CLI_Command { public $export_args = array(); /** - * Export content to a WXR file. + * Export WordPress content to a WXR file. + * + * Generates one or more WXR files containing authors, terms, posts, + * comments, and attachments. WXR files do not include site configuration + * (options) or the attachment files themselves. * * ## OPTIONS * @@ -32,7 +36,7 @@ class Export_Command extends WP_CLI_Command { * to current working directory. * * [--skip_comments] - * : Don't export comments. + * : Don't include comments in the WXR export file. * * [--max_file_size=<MB>] * : A single export file should have this many megabytes. From 24b8ab3b515cbc18bb0e4b7fbb7a680c70669e4f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 07:06:10 -0800 Subject: [PATCH 5049/5359] Drop duplicate header doc --- php/commands/eval.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/php/commands/eval.php b/php/commands/eval.php index 6995700e5..e459b9d1d 100644 --- a/php/commands/eval.php +++ b/php/commands/eval.php @@ -1,18 +1,5 @@ <?php -/** - * Execute arbitrary PHP code. - * - * ## EXAMPLES - * - * # Display WordPress content directory. - * $ wp eval 'echo WP_CONTENT_DIR;' - * /var/www/wordpress/wp-content - * - * # Generate a random number. - * $ wp eval 'echo rand();' --skip-wordpress - * 479620423 - */ class Eval_Command extends WP_CLI_Command { /** From 694f184e816e54c4318a5f0d822e88b096aa872e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 07:12:44 -0800 Subject: [PATCH 5050/5359] Clarify docs for the `wp theme *` set of commands --- php/commands/theme.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/php/commands/theme.php b/php/commands/theme.php index d6703462a..6107f8ebc 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -5,7 +5,7 @@ * * ## EXAMPLES * - * # Install the latest version from wordpress.org and activate + * # Install the latest version of a theme from wordpress.org and activate * $ wp theme install twentysixteen --activate * Installing Twenty Sixteen (1.2) * Downloading install package from http://downloads.wordpress.org/theme/twentysixteen.1.2.zip... @@ -15,7 +15,7 @@ * Activating 'twentysixteen'... * Success: Switched to 'Twenty Sixteen' theme. * - * # Get theme + * # Get details of an installed theme * $ wp theme get twentysixteen --fields=name,title,version * +---------+----------------+ * | Field | Value | @@ -78,7 +78,7 @@ protected function get_upgrader_class( $force ) { * Version: 1.2 * Author: the WordPress team */ - function status( $args ) { + public function status( $args ) { if ( isset( $args[0] ) ) { $theme = $this->fetcher->get_check( $args[0] ); $errors = $theme->errors(); @@ -92,7 +92,10 @@ function status( $args ) { } /** - * Search the wordpress.org theme repository. + * Search the WordPress.org theme directory. + * + * Displays themes in the WordPress.org theme directory matching a given + * search query. * * ## OPTIONS * @@ -225,7 +228,10 @@ public function activate( $args = array() ) { } /** - * Enable a theme in a multisite install. + * Enable a theme on a WordPress multisite install. + * + * Permits theme to be activated from the dashboard of a site on a WordPress + * multisite install. * * ## OPTIONS * @@ -284,7 +290,10 @@ public function enable( $args, $assoc_args ) { } /** - * Disable a theme in a multisite install. + * Disable a theme on a WordPress multisite install. + * + * Removes ability for a theme to be activated from the dashboard of a site + * on a WordPress multisite install. * * ## OPTIONS * @@ -506,7 +515,7 @@ function install( $args, $assoc_args ) { } /** - * Get a theme + * Get details about a theme. * * ## OPTIONS * @@ -663,6 +672,8 @@ function is_installed( $args, $assoc_args = array() ) { /** * Delete a theme. * + * Removes the theme from the filesystem. + * * ## OPTIONS * * <theme>... From 1c2bcb3c68747153049ea3cbc90daee91686fbf9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 07:21:18 -0800 Subject: [PATCH 5051/5359] Clarify docs for the `wp widget *` set of commands --- php/commands/widget.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 81a5fe476..494060115 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -100,6 +100,9 @@ public function list_( $args, $assoc_args ) { /** * Add a widget to a sidebar. * + * Creates a new widget entry in the database, and associates it with the + * sidebar. + * * ## OPTIONS * * <name> @@ -116,6 +119,7 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * + * # Add a new calendar widget to sidebar-1 with title "Calendar" * $ wp widget add calendar sidebar-1 2 --title="Calendar" * Success: Added widget to sidebar. * @@ -157,7 +161,7 @@ public function add( $args, $assoc_args ) { } /** - * Update a given widget's options. + * Update options for an existing widget. * * ## OPTIONS * @@ -169,6 +173,7 @@ public function add( $args, $assoc_args ) { * * ## EXAMPLES * + * # Change calendar-1 widget title to "Our Calendar" * $ wp widget update calendar-1 --title="Our Calendar" * Success: Widget updated. * @@ -195,7 +200,10 @@ public function update( $args, $assoc_args ) { } /** - * Move a widget from one position on a sidebar to another. + * Move the position of a widget. + * + * Changes the order of a widget in its existing sidebar, or moves it to a + * new sidebar. * * ## OPTIONS * @@ -250,6 +258,8 @@ public function move( $args, $assoc_args ) { /** * Deactivate one or more widgets from an active sidebar. * + * Moves widgets to Inactive Widgets. + * * ## OPTIONS * * <widget-id>... @@ -257,6 +267,7 @@ public function move( $args, $assoc_args ) { * * ## EXAMPLES * + * # Deactivate the recent-comments-2 widget. * $ wp widget deactivate recent-comments-2 * Success: 1 widget deactivated. * @@ -295,6 +306,7 @@ public function deactivate( $args, $assoc_args ) { * * ## EXAMPLES * + * # Delete the recent-comments-2 widget from its sidebar. * $ wp widget delete recent-comments-2 * Success: 1 widget removed from sidebar. * From cefe626e18058aa0196076d854c7732060e49990 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 9 Nov 2016 09:47:38 -0800 Subject: [PATCH 5052/5359] Drop assertions that fail on older versions of WP --- features/core-install.feature | 2 -- 1 file changed, 2 deletions(-) diff --git a/features/core-install.feature b/features/core-install.feature index 32b1372f7..c71244e8f 100644 --- a/features/core-install.feature +++ b/features/core-install.feature @@ -168,7 +168,6 @@ Feature: Install WordPress core """ Success: WordPress installed successfully. """ - And STDERR should be empty Scenario: Install WordPress multisite without specifying the password Given an empty directory @@ -185,4 +184,3 @@ Feature: Install WordPress core """ Success: Network installed. Don't forget to set up rewrite rules. """ - And STDERR should be empty From ee59a46335fa21a1f38cf005b94ab851974fa000 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 14:41:16 -0800 Subject: [PATCH 5053/5359] Clarify docs on `wp (post|user) term *` set of commands --- php/WP_CLI/CommandWithTerms.php | 14 +++++++++----- php/commands/post-term.php | 2 +- php/commands/user-term.php | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index bfae4653a..1a8c863e9 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -95,16 +95,16 @@ public function list_( $args, $assoc_args ) { /** - * Remove a term. + * Remove a term from an object. * * <id> * : The ID of the object. * * <taxonomy> - * : The name of the taxonomy type to deleted. + * : The name of the term's taxonomy. * * <term>... - * : The name of the term or terms to deleted. + * : The name of the term or terms to be removed from the object. */ public function remove( $args, $assoc_args ) { $object_id = array_shift( $args ); @@ -125,7 +125,9 @@ public function remove( $args, $assoc_args ) { } /** - * Add a term. Appends to existing set of terms on the object. + * Add a term to an object. + * + * Append the term to the existing set of terms on the object. * * <id> * : The ID of the object. @@ -155,7 +157,9 @@ public function add( $args, $assoc_args ) { } /** - * Set terms. Replaces existing terms on the object. + * Set object terms. + * + * Replaces existing terms on the object. * * <id> * : The ID of the object. diff --git a/php/commands/post-term.php b/php/commands/post-term.php index 9c8c8f856..6ca2f49af 100644 --- a/php/commands/post-term.php +++ b/php/commands/post-term.php @@ -7,7 +7,7 @@ * * # Set post terms * $ wp post term set 123 test category - * Set terms. + * Success: Set terms. */ class Post_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'post'; diff --git a/php/commands/user-term.php b/php/commands/user-term.php index aa59e080c..f5406dfc5 100644 --- a/php/commands/user-term.php +++ b/php/commands/user-term.php @@ -7,7 +7,7 @@ * * # Set user terms * $ wp user term set 123 test category - * Set terms. + * Success: Set terms. */ class User_Term_Command extends \WP_CLI\CommandWithTerms { protected $obj_type = 'user'; From 9c35b8253b907283484680835b170a559464c7fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 14:44:23 -0800 Subject: [PATCH 5054/5359] Remove unnecessary `wp_remove_object_terms()` private method Function was added in WP 3.6, and WP 3.7 is WP-CLI's minimum supported version. --- php/WP_CLI/CommandWithTerms.php | 85 +-------------------------------- 1 file changed, 1 insertion(+), 84 deletions(-) diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php index bfae4653a..b53e14362 100644 --- a/php/WP_CLI/CommandWithTerms.php +++ b/php/WP_CLI/CommandWithTerms.php @@ -115,7 +115,7 @@ public function remove( $args, $assoc_args ) { $this->taxonomy_exists( $taxonomy ); - $result = self::wp_remove_object_terms( $object_id, $terms, $taxonomy ); + $result = wp_remove_object_terms( $object_id, $terms, $taxonomy ); if ( ! is_wp_error( $result ) ) { WP_CLI::success( "Deleted term." ); @@ -184,89 +184,6 @@ public function set( $args, $assoc_args ) { } } - - /** - * Remove term(s) associated with a given object. - * - * - * @global wpdb $wpdb WordPress database abstraction object. - * - * @param int $object_id The ID of the object from which the terms will be removed. - * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove. - * @param array|string $taxonomy Taxonomy name. - * @return bool|WP_Error True on success, false or WP_Error on failure. - */ - private static function wp_remove_object_terms( $object_id, $terms, $taxonomy ) { - global $wpdb; - - // Remove notices in below 3.6 and support backwards compatibility - - if( function_exists( 'wp_remove_object_terms' ) ){ - return wp_remove_object_terms( $object_id, $terms, $taxonomy ); - } - - $object_id = (int) $object_id; - - if ( ! taxonomy_exists( $taxonomy ) ) { - return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) ); - } - - if ( ! is_array( $terms ) ) { - $terms = array( $terms ); - } - - $tt_ids = array(); - - foreach ( (array) $terms as $term ) { - if ( ! strlen( trim( $term ) ) ) { - continue; - } - - if ( ! $term_info = term_exists( $term, $taxonomy ) ) { - // Skip if a non-existent term ID is passed. - if ( is_int( $term ) ) { - continue; - } - } - - if ( is_wp_error( $term_info ) ) { - return $term_info; - } - - $tt_ids[] = $term_info['term_taxonomy_id']; - } - - if ( $tt_ids ) { - $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'"; - - /** - * Fires immediately before an object-term relationship is deleted. - * - * @since 2.9.0 - * - * @param int $object_id Object ID. - * @param array $tt_ids An array of term taxonomy IDs. - */ - do_action( 'delete_term_relationships', $object_id, $tt_ids ); - $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); - - /** - * Fires immediately after an object-term relationship is deleted. - * - * @since 2.9.0 - * - * @param int $object_id Object ID. - * @param array $tt_ids An array of term taxonomy IDs. - */ - do_action( 'deleted_term_relationships', $object_id, $tt_ids ); - wp_update_term_count( $tt_ids, $taxonomy ); - - return (bool) $deleted; - } - - return false; - } - /** * Check if taxonomy exists * From 8731f1ca77c0457750725a7bea861a06d365917e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 14:53:58 -0800 Subject: [PATCH 5055/5359] Clarify docs for `wp shell` --- php/commands/shell.php | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/php/commands/shell.php b/php/commands/shell.php index 5fe7dfa6e..113e793c2 100644 --- a/php/commands/shell.php +++ b/php/commands/shell.php @@ -1,23 +1,15 @@ <?php -/** - * Interactive PHP console. - * - * ## EXAMPLES - * - * # Start interactive PHP console - * $ wp shell - * wp> - * - * @package wp-cli - */ + class Shell_Command extends \WP_CLI_Command { /** * Interactive PHP console. * - * ## DESCRIPTION - * - * `wp shell` allows you to evaluate PHP statements and expressions interactively, from within a WordPress environment. This means that you have access to all the functions, classes and globals that you would have access to from inside a WordPress plugin, for example. + * `wp shell` allows you to evaluate PHP statements and expressions + * interactively, from within a WordPress environment. Type a bit of code, + * hit enter, and see the code execute right before you. Because WordPress + * is loaded, you have access to all the functions, classes and globals + * that you can use within a WordPress plugin, for example. * * ## OPTIONS * @@ -26,9 +18,10 @@ class Shell_Command extends \WP_CLI_Command { * * ## EXAMPLES * - * # Start interactive PHP console + * # Call get_bloginfo() to get the name of the site. * $ wp shell - * wp> + * wp> get_bloginfo( 'name' ); + * => string(6) "WP-CLI" */ public function __invoke( $_, $assoc_args ) { $implementations = array( From 393ca779b14efeb1ad567ff5484bfcbd51cad54a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 14:59:06 -0800 Subject: [PATCH 5056/5359] Clarify docs for the `wp role *` set of commands --- php/commands/role.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/php/commands/role.php b/php/commands/role.php index e08e09d1c..ea27f2290 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -14,19 +14,19 @@ * contributor * subscriber * - * # Check if a role exists. + * # Check to see if a role exists. * $ wp role exists editor * Success: Role with ID 'editor' exists. * - * # Create role. + * # Create a new role. * $ wp role create approver Approver * Success: Role with key 'approver' created. * - * # Delete role. + * # Delete an existing role. * $ wp role delete approver * Success: Role with key 'approver' deleted. * - * # Reset role. + * # Reset existing roles to their default capabilities. * $ wp role reset administrator author contributor * Success: Reset 3/3 roles. * @@ -101,9 +101,7 @@ public function list_( $args, $assoc_args ) { /** * Check if a role exists. * - * ## DESCRIPTION - * - * Will exit with status 0 if the role exists, 1 if it does not. + * Exits with return code 0 if the role exists, 1 if it does not. * * ## OPTIONS * From 17842357d24a5342be10b466a7acc10bbc083324 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 15:01:40 -0800 Subject: [PATCH 5057/5359] Clarify docs in `wp search-replace` --- php/commands/search-replace.php | 35 ++------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index 14daa7e92..bd59b4831 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -1,34 +1,5 @@ <?php -/** - * Search and replace strings in the database. - * - * ## EXAMPLES - * - * # Search and replace strings in the table - * $ wp search-replace foo bar wp_options - * +------------+--------------+--------------+------+ - * | Table | Column | Replacements | Type | - * +------------+--------------+--------------+------+ - * | wp_options | option_name | 2 | SQL | - * | wp_options | option_value | 0 | PHP | - * | wp_options | autoload | 0 | SQL | - * +------------+--------------+--------------+------+ - * Success: Made 2 replacements. - * - * # Run search/replace operation but dont save in database - * $ wp search-replace foo bar wp_options --dry-run - * +------------+--------------+--------------+------+ - * | Table | Column | Replacements | Type | - * +------------+--------------+--------------+------+ - * | wp_options | option_name | 2 | SQL | - * | wp_options | option_value | 0 | PHP | - * | wp_options | autoload | 0 | SQL | - * +------------+--------------+--------------+------+ - * Success: 2 replacements to be made. - * - * @package wp-cli - */ class Search_Replace_Command extends WP_CLI_Command { private $dry_run; @@ -42,10 +13,8 @@ class Search_Replace_Command extends WP_CLI_Command { /** * Search/replace strings in the database. * - * ## DESCRIPTION - * - * This command will searches through all rows in a selection of tables - * and replaces appearances of the first string with the second string. + * Searches through all rows in a selection of tables and replaces + * appearances of the first string with the second string. * * By default, the command uses tables registered to the $wpdb object. On * multisite, this will just be the tables for the current site unless From 41534b62ec81df30f9e99c9043e8091165ad1928 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 15:08:09 -0800 Subject: [PATCH 5058/5359] Clarify docs for `wp term *` set of commands --- php/commands/term.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/php/commands/term.php b/php/commands/term.php index db759c135..feafbe946 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -4,19 +4,19 @@ * * ## EXAMPLES * - * # Create term + * # Create a new term. * $ wp term create category Apple --description="A type of fruit" * Success: Created category 199. * - * # Get term + * # Get details about a term. * $ wp term get category 199 --format=json --fields=term_id,name,slug,count * {"term_id":199,"name":"Apple","slug":"apple","count":1} * - * # Update term + * # Update an existing term. * $ wp term update category 15 --name=Apple * Success: Term updated. * - * # Get term url + * # Get the term's URL. * $ wp term url post_tag 123 * http://example.com/tag/tips-and-tricks * @@ -146,7 +146,7 @@ public function list_( $args, $assoc_args ) { } /** - * Create a term. + * Create a new term. * * ## OPTIONS * @@ -170,6 +170,7 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * + * # Create a new category "Apple" with a description. * $ wp term create category Apple --description="A type of fruit" * Success: Created category 199. */ @@ -207,7 +208,7 @@ public function create( $args, $assoc_args ) { } /** - * Get a taxonomy term + * Get details about a term. * * ## OPTIONS * @@ -236,6 +237,7 @@ public function create( $args, $assoc_args ) { * * ## EXAMPLES * + * # Get details about a category with id 199. * $ wp term get category 199 --format=json * {"term_id":199,"name":"Apple","slug":"apple","term_group":0,"term_taxonomy_id":199,"taxonomy":"category","description":"A type of fruit","parent":0,"count":0,"filter":"raw"} */ @@ -260,7 +262,7 @@ public function get( $args, $assoc_args ) { } /** - * Update a term. + * Update an existing term. * * ## OPTIONS * @@ -284,6 +286,7 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * + * # Change category with id 15 to use the name "Apple" * $ wp term update category 15 --name=Apple * Success: Term updated. */ @@ -314,7 +317,9 @@ public function update( $args, $assoc_args ) { } /** - * Delete a term. + * Delete an existing term. + * + * Errors if the term doesn't exist, or there was a problem in deleting it. * * ## OPTIONS * @@ -355,6 +360,8 @@ public function delete( $args ) { /** * Generate some terms. * + * Creates a specified number of new terms with dummy data. + * * ## OPTIONS * * <taxonomy> @@ -482,7 +489,7 @@ public function generate( $args, $assoc_args ) { } /** - * Get term url + * Get a term's URL. * * ## OPTIONS * From 3297b8fb1db82dc64bd649510b46d06c24a21e69 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 16:18:28 -0800 Subject: [PATCH 5059/5359] Update docs for `wp user *` set of commands --- php/commands/user.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/php/commands/user.php b/php/commands/user.php index ca0af0853..536baf9c0 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -9,12 +9,12 @@ * $ wp user list --field=ID * 1 * - * # Create user + * # Create a new user. * $ wp user create bob bob@example.com --role=author * Success: Created user 3. * Password: k9**&I4vNH(& * - * # Update user + * # Update an existing user. * $ wp user update 123 --display_name=Mary --user_pass=marypass * Success: Updated user 123. * @@ -164,7 +164,7 @@ public function list_( $args, $assoc_args ) { } /** - * Get a single user. + * Get details about a user. * * ## OPTIONS * @@ -272,7 +272,7 @@ public function delete( $args, $assoc_args ) { } /** - * Create a user. + * Create a new user. * * ## OPTIONS * @@ -399,7 +399,7 @@ public function create( $args, $assoc_args ) { } /** - * Update a user. + * Update an existing user. * * ## OPTIONS * @@ -431,7 +431,9 @@ public function update( $args, $assoc_args ) { } /** - * Generate users. + * Generate some users. + * + * Creates a specified number of new users with dummy data. * * ## OPTIONS * @@ -520,7 +522,7 @@ public function generate( $args, $assoc_args ) { } /** - * Set the user role (for a particular blog). + * Set the user role. * * ## OPTIONS * @@ -625,7 +627,7 @@ public function remove_role( $args, $assoc_args ) { } /** - * Add a capability for a user. + * Add a capability to a user. * * ## OPTIONS * @@ -686,7 +688,7 @@ public function remove_cap( $args, $assoc_args ) { } /** - * List all user's capabilities. + * List all capabilities for a user. * * ## OPTIONS * @@ -754,6 +756,9 @@ public function list_caps( $args, $assoc_args ) { /** * Import users from a CSV file. * + * If the user already exists (matching the email address or login), then + * the user is updated unless the `--skip-update` flag is used. + * * ## OPTIONS * * <file> From 39ca11554a2dd2f4ad20ecb0aa92332eda09dadf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 16:22:35 -0800 Subject: [PATCH 5060/5359] Clarify docs for `wp server` --- php/commands/server.php | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index a2285045b..2989ebfc5 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -1,23 +1,11 @@ <?php -/** - * Launch PHP's built-in web server. - * - * ## EXAMPLES - * - * # Make the instance available on any address (with port 8080) - * $ wp server --host=0.0.0.0 - * PHP 5.6.9 Development Server started at Tue May 24 01:27:11 2016 - * Listening on http://0.0.0.0:8080 - * Document root is / - * Press Ctrl-C to quit. - * - * @package wp-cli - */ + class Server_Command extends WP_CLI_Command { /** * Launch PHP's built-in web server for this specific WordPress installation. * + * Uses `php -S` to launch a web server serving the WordPress webroot. * <http://php.net/manual/en/features.commandline.webserver.php> * * ## OPTIONS From 2aa268c74ebab0c1717f88fe4730770dfc6ecde6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 16:34:33 -0800 Subject: [PATCH 5061/5359] Clarify docs for `wp transient *` set of commands --- php/commands/transient.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/php/commands/transient.php b/php/commands/transient.php index 06cff3ea6..30bfe95af 100644 --- a/php/commands/transient.php +++ b/php/commands/transient.php @@ -72,7 +72,9 @@ public function get( $args, $assoc_args ) { } /** - * Set a transient value. <expiration> is the time until expiration, in seconds. + * Set a transient value. + * + * `<expiration>` is the time until expiration, in seconds. * * ## OPTIONS * @@ -170,7 +172,10 @@ public function delete( $args, $assoc_args ) { } /** - * See whether the transients API is using an object cache or the options table. + * Determine type of transients implementation. + * + * Indicates whether the transients API is using an object cache or the + * options table. * * ## EXAMPLES * From aa82d3fe213b61bca99e558c55f0478aa50add79 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 16:42:56 -0800 Subject: [PATCH 5062/5359] Clarify docs in `wp site *` set of commands --- php/commands/site.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/php/commands/site.php b/php/commands/site.php index 2abb9424b..13d4ba411 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -136,10 +136,16 @@ private function _insert_default_terms() { } /** - * Empty a site of its content (posts, comments, and terms). + * Empty a site of its content (posts, comments, terms, and meta). * - * This command doesn't empty custom database tables by default. To do so, - * you'll need to hook into command execution: + * Truncates posts, comments, and terms tables to empty a site of its + * content. Doesn't affect site configuration (options) or users. + * + * If running a persistent object cache, make sure to flush the cache + * after emptying the site, as the cache values will be invalid otherwise. + * + * To also empty custom database tables, you'll need to hook into command + * execution: * * ``` * WP_CLI::add_hook( 'after_invoke:site empty', function(){ @@ -539,7 +545,7 @@ public function list_( $_, $assoc_args ) { } /** - * Archive one or more sites + * Archive one or more sites. * * ## OPTIONS * @@ -556,7 +562,7 @@ public function archive( $args ) { } /** - * Unarchive one or more sites + * Unarchive one or more sites. * * ## OPTIONS * @@ -573,7 +579,7 @@ public function unarchive( $args ) { } /** - * Activate one or more sites + * Activate one or more sites. * * ## OPTIONS * @@ -590,7 +596,7 @@ public function activate( $args ) { } /** - * Deactivate one or more sites + * Deactivate one or more sites. * * ## OPTIONS * @@ -607,7 +613,7 @@ public function deactivate( $args ) { } /** - * Mark one or more sites as spam + * Mark one or more sites as spam. * * ## OPTIONS * @@ -624,7 +630,7 @@ public function spam( $args ) { } /** - * Remove one or more sites from spam + * Remove one or more sites from spam. * * ## OPTIONS * From e4cff3fbc1771fe112ecbf43663b9a7e5ddb973c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 16:57:03 -0800 Subject: [PATCH 5063/5359] Clarify docs for `wp core language *` set of commands --- php/WP_CLI/CommandWithTranslation.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 2b0adea2a..6cfe90aea 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -21,7 +21,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { ); /** - * List all languages available. + * List all available languages. * * [--field=<field>] * : Display the value of a single field @@ -53,6 +53,7 @@ abstract class CommandWithTranslation extends \WP_CLI_Command { * * ## EXAMPLES * + * # List language,english_name,status fields of available languages. * $ wp core language list --fields=language,english_name,status * +----------------+-------------------------+-------------+ * | language | english_name | status | @@ -114,6 +115,8 @@ protected function sort_translations_callback( $a, $b ) { /** * Install a given language. * + * Downloads the language pack from WordPress.org. + * * <language> * : Language code to install. * @@ -122,7 +125,8 @@ protected function sort_translations_callback( $a, $b ) { * * ## EXAMPLES * - * $ wp core language install ja + * # Install the Japanese language. + * $ wp core language install ja * Success: Language installed. * * @subcommand install @@ -152,7 +156,9 @@ public function install( $args, $assoc_args ) { } /** - * Updates the active translation of core, plugins, and themes. + * Update installed languages. + * + * Updates installed languages for core, plugins and themes. * * [--dry-run] * : Preview which translations would be updated. From b65c44193ae7738c48ab3a1e612e923f8b9b0402 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:07:30 -0800 Subject: [PATCH 5064/5359] Clarify docs for `wp scaffold *` set of commands --- php/commands/scaffold.php | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index c3c0b2f31..fa8c94ec4 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -4,11 +4,11 @@ use WP_CLI\Process; /** - * Generate code for post types, taxonomies, etc. + * Generate code for post types, taxonomies, plugins, child themes. etc. * * ## EXAMPLES * - * # Generate plugin + * # Generate a new plugin with unit tests * $ wp scaffold plugin sample-plugin * Success: Created plugin files. * Success: Created test files. @@ -57,6 +57,7 @@ class Scaffold_Command extends WP_CLI_Command { * * ## EXAMPLES * + * # Generate a 'movie' post type for the 'simple-life' theme * $ wp scaffold post-type movie --label=Movie --theme=simple-life * Success: Created '/var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php'. * @@ -64,7 +65,7 @@ class Scaffold_Command extends WP_CLI_Command { * * @alias cpt */ - function post_type( $args, $assoc_args ) { + public function post_type( $args, $assoc_args ) { if ( strlen( $args[0] ) > 20 ) { WP_CLI::error( "Post type slugs cannot exceed 20 characters in length." ); @@ -120,7 +121,7 @@ function post_type( $args, $assoc_args ) { * * @alias tax */ - function taxonomy( $args, $assoc_args ) { + public function taxonomy( $args, $assoc_args ) { $defaults = array( 'textdomain' => '', 'post_types' => "'post'" @@ -195,7 +196,9 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) } /** - * Generate starter code for a theme. + * Generate starter code for a theme based on _s. + * + * See the [Underscores website](http://underscores.me/) for more details. * * ## OPTIONS * @@ -225,10 +228,11 @@ private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) * * ## EXAMPLES * + * # Generate a theme with name "Sample Theme" and author "John Doe" * $ wp scaffold _s sample-theme --theme_name="Sample Theme" --author="John Doe" * Success: Created theme 'Sample Theme'. */ - function _s( $args, $assoc_args ) { + public function _s( $args, $assoc_args ) { $theme_slug = $args[0]; $theme_path = WP_CONTENT_DIR . "/themes"; @@ -301,7 +305,9 @@ function _s( $args, $assoc_args ) { } /** - * Generate empty child theme. + * Generate child theme based on an existing theme. + * + * Creates a child theme folder with `functions.php` and `style.css` files. * * ## OPTIONS * @@ -334,6 +340,7 @@ function _s( $args, $assoc_args ) { * * ## EXAMPLES * + * # Generate a 'sample-theme' child theme based on TwentySixteen * $ wp scaffold child-theme sample-theme --parent_theme=twentysixteen * Success: Created '/var/www/example.com/public_html/wp-content/themes/sample-theme'. * @@ -403,9 +410,7 @@ private function get_output_path( $assoc_args, $subdir ) { /** * Generate starter code for a plugin. * - * ## OVERVIEW - * - * The following files are generated for your plugin by this command: + * The following files are always generated: * * * `plugin-slug.php` is the main PHP plugin file. * * `readme.txt` is the readme file for the plugin. @@ -415,7 +420,7 @@ private function get_output_path( $assoc_args, $subdir ) { * * `.gitignore` tells which files (or patterns) git should ignore. * * `.distignore` tells which files and folders should be ignored in distribution. * - * The following files are also generated if tests are not skipped using `--skip-tests`: + * The following files are also included unless the `--skip-tests` is used: * * * `phpunit.xml.dist` is the configuration file for PHPUnit. * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. @@ -535,11 +540,9 @@ function plugin( $args, $assoc_args ) { } /** - * Generate files needed for running PHPUnit tests. - * - * ## OVERVIEW + * Generate files needed for running PHPUnit tests in a plugin. * - * The following files are generated for your plugin by this command: + * The following files are generated by default: * * * `phpunit.xml.dist` is the configuration file for PHPUnit. * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. @@ -578,6 +581,7 @@ function plugin( $args, $assoc_args ) { * * ## EXAMPLES * + * # Generate unit test files for plugin 'sample-plugin'. * $ wp scaffold plugin-tests sample-plugin * Success: Created test files. * From 27db70494608db094b11703dc852f76e3181aba5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:10:20 -0800 Subject: [PATCH 5065/5359] Clarify docs for `wp (post-type|taxonomy) *` set of commands --- php/commands/post-type.php | 7 ++++--- php/commands/taxonomy.php | 8 ++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/php/commands/post-type.php b/php/commands/post-type.php index 73d96afa4..4159c52ab 100644 --- a/php/commands/post-type.php +++ b/php/commands/post-type.php @@ -4,7 +4,7 @@ * * ## EXAMPLES * - * # Get a post type + * # Get details about a post type * $ wp post-type get page --fields=name,label,hierarchical --format=json * {"name":"page","label":"Pages","hierarchical":true} * @@ -33,7 +33,7 @@ class Post_Type_Command extends WP_CLI_Command { ); /** - * List post types. + * List registered post types. * * ## OPTIONS * @@ -104,7 +104,7 @@ public function list_( $args, $assoc_args ) { } /** - * Get a post type + * Get details about a registered post type. * * ## OPTIONS * @@ -130,6 +130,7 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * + * # Get details about the 'page' post type. * $ wp post-type get page --fields=name,label,hierarchical --format=json * {"name":"page","label":"Pages","hierarchical":true} */ diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php index 2608120b0..380fac575 100644 --- a/php/commands/taxonomy.php +++ b/php/commands/taxonomy.php @@ -43,9 +43,7 @@ public function __construct() { } /** - * List taxonomies. - * - * Displays list of registered taxonomies. + * List registered taxonomies. * * ## OPTIONS * @@ -123,9 +121,7 @@ public function list_( $args, $assoc_args ) { } /** - * Get a taxonomy. - * - * Displays detail of the taxonomy. + * Get details about a registered taxonomy. * * ## OPTIONS * From 4bac7af8431e11e160b0e9fe6f36e68f1eac8251 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:12:55 -0800 Subject: [PATCH 5066/5359] Clarify docs for `wp super-admin *` set of commands --- php/commands/super-admin.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index 4d2326845..ce46b6496 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -1,7 +1,7 @@ <?php /** - * List, add, and remove super admins from a network. + * Manage super admins on WordPress multisite. * * ## EXAMPLES * @@ -31,7 +31,7 @@ public function __construct() { } /** - * Show a list of users with super-admin capabilities. + * List users with super admin capabilities. * * ## OPTIONS * @@ -80,7 +80,7 @@ public function _list( $_, $assoc_args ) { } /** - * Grant super-admin privileges to one or more users. + * Grant super admin privileges to one or more users. * * ## OPTIONS * @@ -127,7 +127,7 @@ public function add( $args, $_ ) { } /** - * Revoke super-admin privileges to one or more users. + * Remove super admin privileges from one or more users. * * ## OPTIONS * From 9a8b1c22efe010215ecedaa10a2365b1276d0c3a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:17:50 -0800 Subject: [PATCH 5067/5359] Remove WP 3.6 compat code from `wp menu list` --- php/commands/menu.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/commands/menu.php b/php/commands/menu.php index 530e851c3..671bde8dd 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -169,10 +169,6 @@ public function list_( $_, $assoc_args ) { $menus = wp_get_nav_menus(); $menu_locations = get_nav_menu_locations(); - // < 3.6 $menu_locations could be false - if ( ! $menu_locations ) { - $menu_locations = array(); - } foreach( $menus as &$menu ) { $menu->locations = array(); From 85eeeb3a641c31d052e651841e5c37beacd80c1c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:21:15 -0800 Subject: [PATCH 5068/5359] Clarify docs for `wp theme mod *` set of commands --- php/commands/theme-mod.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/commands/theme-mod.php b/php/commands/theme-mod.php index 00bb78262..7cc4b9cee 100644 --- a/php/commands/theme-mod.php +++ b/php/commands/theme-mod.php @@ -5,7 +5,7 @@ * * ## EXAMPLES * - * # Set theme mod. + * # Set the 'background_color' theme mod to '000000'. * $ wp theme mod set background_color 000000 * Success: Theme mod background_color set to 000000 * @@ -20,7 +20,7 @@ class Theme_Mod_command extends WP_CLI_Command { /** - * Get theme mod(s). + * Get one or more theme mods. * * ## OPTIONS * @@ -110,7 +110,7 @@ public function get( $args = array(), $assoc_args = array() ) { } /** - * Remove theme mod(s). + * Remove one or more theme mods. * * ## OPTIONS * @@ -157,7 +157,7 @@ public function remove( $args = array(), $assoc_args = array() ) { } /** - * Set a theme mod. + * Set the value of a theme mod. * * ## OPTIONS * From 61c46b4256262f433db57b91728508951da49d73 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:27:15 -0800 Subject: [PATCH 5069/5359] Clarify docs for `wp import` --- php/commands/import.php | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/php/commands/import.php b/php/commands/import.php index a2be901a8..e621b58ed 100644 --- a/php/commands/import.php +++ b/php/commands/import.php @@ -1,21 +1,5 @@ <?php -/** - * Manage imports. - * - * ## EXAMPLES - * - * # Import content from a WXR file - * $ wp import example.wordpress.2016-06-21.xml --authors=create - * Starting the import process... - * Processing post #1 ("Hello world!") (post_type: post) - * -- 1 of 1 - * -- Tue, 21 Jun 2016 05:31:12 +0000 - * -- Imported post as post_id #1 - * Success: Finished importing from 'example.wordpress.2016-06-21.xml' file. - * - * @package wp-cli - */ class Import_Command extends WP_CLI_Command { var $processed_posts = array(); @@ -23,6 +7,9 @@ class Import_Command extends WP_CLI_Command { /** * Import content from a WXR file. * + * Provides a command line interface to the WordPress Importer plugin, for + * performing data migrations. + * * ## OPTIONS * * <file>... From 0af9471b7d4393e87619dbcbcfd2c152019d0ab4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:28:36 -0800 Subject: [PATCH 5070/5359] Clarify docs for `wp media *` set of commands --- php/commands/media.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/media.php b/php/commands/media.php index e3529648f..33d79bf19 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -22,7 +22,7 @@ class Media_Command extends WP_CLI_Command { /** - * Regenerate thumbnail(s). + * Regenerate thumbnails for one or more attachments. * * ## OPTIONS * @@ -115,7 +115,7 @@ function regenerate( $args, $assoc_args = array() ) { } /** - * Create attachments from local files or from URLs. + * Create attachments from local files or URLs. * * ## OPTIONS * From f8b7f4a9e31dea5577cfbd4bae5e089638659761 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:34:30 -0800 Subject: [PATCH 5071/5359] Clarify docs for `wp post *` set of commands --- php/commands/post.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/php/commands/post.php b/php/commands/post.php index e19423017..11c96fa8d 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -5,15 +5,15 @@ * * ## EXAMPLES * - * # Create post + * # Create a new post. * $ wp post create --post_type=post --post_title='A sample post' * Success: Created post 123. * - * # Update post + * # Update an existing post. * $ wp post update 123 --post_status=draft * Success: Updated post 123. * - * # Delete post + * # Delete an existing post. * $ wp post delete 123 * Success: Trashed post 123. * @@ -35,7 +35,7 @@ public function __construct() { } /** - * Create a post. + * Create a new post. * * ## OPTIONS * @@ -93,7 +93,7 @@ public function create( $args, $assoc_args ) { } /** - * Update one or more posts. + * Update one or more existing posts. * * ## OPTIONS * @@ -172,7 +172,7 @@ protected function _edit( $content, $title ) { } /** - * Get a post's content by ID. + * Get details about a post. * * ## OPTIONS * @@ -216,7 +216,7 @@ public function get( $args, $assoc_args ) { } /** - * Delete a post by ID. + * Delete an existing post. * * ## OPTIONS * @@ -399,6 +399,8 @@ public function list_( $_, $assoc_args ) { /** * Generate some posts. * + * Creates a specified number of new posts with dummy data. + * * ## OPTIONS * * [--count=<number>] From aa69326aa8c4dd01a9baf272a5ef2a7cd22a5dcd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 10 Nov 2016 17:38:37 -0800 Subject: [PATCH 5072/5359] Clarify docs for `wp plugin *` set of commands --- php/commands/plugin.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 4c3fee9a7..de195fd34 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -87,12 +87,15 @@ protected function get_upgrader_class( $force ) { * Author: Otto42, pross * Description: A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool! */ - function status( $args ) { + public function status( $args ) { parent::status( $args ); } /** - * Search the wordpress.org plugin repository. + * Search the WordPress.org plugin directory. + * + * Displays plugins in the WordPress.org plugin directory matching a given + * search query. * * ## OPTIONS * @@ -361,6 +364,9 @@ function deactivate( $args, $assoc_args = array() ) { /** * Toggle a plugin's activation state. * + * If the plugin is active, then it will be deactivated. If the plugin is + * inactive, then it will be activated. + * * ## OPTIONS * * <plugin>... @@ -628,7 +634,7 @@ function install( $args, $assoc_args ) { } /** - * Get a plugin. + * Get details about an installed plugin. * * ## OPTIONS * @@ -742,7 +748,7 @@ function uninstall( $args, $assoc_args = array() ) { * * @subcommand is-installed */ - function is_installed( $args, $assoc_args = array() ) { + public function is_installed( $args, $assoc_args = array() ) { if ( $this->fetcher->get( $args[0] ) ) { exit( 0 ); } else { @@ -768,7 +774,7 @@ function is_installed( $args, $assoc_args = array() ) { * $ wp plugin delete $(wp plugin list --status=inactive --field=name) * Success: Deleted 'tinymce-templates' plugin. */ - function delete( $args, $assoc_args = array() ) { + public function delete( $args, $assoc_args = array() ) { foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->_delete( $plugin ) ) { WP_CLI::success( "Deleted '{$plugin->name}' plugin." ); From 1889521b167ca43332a455904fbf615b86b3a87c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 11 Nov 2016 05:49:33 -0800 Subject: [PATCH 5073/5359] Introduce `wp scaffold theme-tests` for scaffolding theme unit tests --- features/scaffold-plugin-tests.feature | 95 +++++++++++++ features/scaffold-theme-tests.feature | 75 +++++++++++ features/scaffold.feature | 94 ------------- php/commands/scaffold.php | 125 ++++++++++++++---- ...rap.mustache => plugin-bootstrap.mustache} | 0 ...e.mustache => plugin-test-sample.mustache} | 0 templates/theme-bootstrap.mustache | 34 +++++ templates/theme-test-sample.mustache | 20 +++ 8 files changed, 320 insertions(+), 123 deletions(-) create mode 100644 features/scaffold-plugin-tests.feature create mode 100644 features/scaffold-theme-tests.feature rename templates/{bootstrap.mustache => plugin-bootstrap.mustache} (100%) rename templates/{test-sample.mustache => plugin-test-sample.mustache} (100%) create mode 100644 templates/theme-bootstrap.mustache create mode 100644 templates/theme-test-sample.mustache diff --git a/features/scaffold-plugin-tests.feature b/features/scaffold-plugin-tests.feature new file mode 100644 index 000000000..5932f0356 --- /dev/null +++ b/features/scaffold-plugin-tests.feature @@ -0,0 +1,95 @@ +Feature: Scaffold plugin unit tests + + Scenario: Scaffold plugin tests + Given a WP install + When I run `wp plugin path` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin hello-world --skip-tests` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist + And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist + And the {PLUGIN_DIR}/hello-world/readme.txt file should exist + And the {PLUGIN_DIR}/hello-world/tests directory should not exist + + When I run `wp scaffold plugin-tests hello-world` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/hello-world/tests directory should contain: + """ + bootstrap.php + test-sample.php + """ + And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: + """ + require dirname( dirname( __FILE__ ) ) . '/hello-world.php'; + """ + And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: + """ + * @package Hello_World + """ + And the {PLUGIN_DIR}/hello-world/tests/test-sample.php file should contain: + """ + * @package Hello_World + """ + And the {PLUGIN_DIR}/hello-world/bin directory should contain: + """ + install-wp-tests.sh + """ + And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist + And the {PLUGIN_DIR}/hello-world/phpcs.ruleset.xml file should exist + And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist + And the {PLUGIN_DIR}/hello-world/.gitlab-ci.yml file should not exist + And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: + """ + script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') + - phpunit + """ + + When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` + Then STDOUT should be: + """ + executable + """ + + Scenario: Scaffold plugin tests with Circle as the provider, part one + Given a WP install + And I run `wp scaffold plugin hello-world --ci=circle` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/circle.yml file should contain: + """ + version: 5.6.22 + """ + + Scenario: Scaffold plugin tests with Circle as the provider, part two + Given a WP install + And I run `wp scaffold plugin hello-world --skip-tests` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin-tests hello-world --ci=circle` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/circle.yml file should contain: + """ + version: 5.6.22 + """ + + Scenario: Scaffold plugin tests with Gitlab as the provider + Given a WP install + And I run `wp scaffold plugin hello-world --skip-tests` + + When I run `wp plugin path hello-world --dir` + Then save STDOUT as {PLUGIN_DIR} + + When I run `wp scaffold plugin-tests hello-world --ci=gitlab` + Then STDOUT should not be empty + And the {PLUGIN_DIR}/.travis.yml file should not exist + And the {PLUGIN_DIR}/.gitlab-ci.yml file should contain: + """ + MYSQL_DATABASE + """ diff --git a/features/scaffold-theme-tests.feature b/features/scaffold-theme-tests.feature new file mode 100644 index 000000000..e10bb3076 --- /dev/null +++ b/features/scaffold-theme-tests.feature @@ -0,0 +1,75 @@ +Feature: Scaffold theme unit tests + + Background: + Given a WP install + And I run `wp theme install p2` + And I run `wp scaffold child-theme p2child --parent_theme=p2` + + When I run `wp theme path` + Then save STDOUT as {THEME_DIR} + + Scenario: Scaffold theme tests + When I run `wp scaffold theme-tests p2child` + Then STDOUT should not be empty + And the {THEME_DIR}/p2child/tests directory should contain: + """ + bootstrap.php + test-sample.php + """ + And the {THEME_DIR}/p2child/tests/bootstrap.php file should contain: + """ + register_theme_directory( dirname( $theme_dir ) ); + """ + And the {THEME_DIR}/p2child/tests/bootstrap.php file should contain: + """ + * @package P2child + """ + And the {THEME_DIR}/p2child/tests/test-sample.php file should contain: + """ + * @package P2child + """ + And the {THEME_DIR}/p2child/bin directory should contain: + """ + install-wp-tests.sh + """ + And the {THEME_DIR}/p2child/phpunit.xml.dist file should exist + And the {THEME_DIR}/p2child/phpcs.ruleset.xml file should exist + And the {THEME_DIR}/p2child/circle.yml file should not exist + And the {THEME_DIR}/p2child/.gitlab-ci.yml file should not exist + And the {THEME_DIR}/p2child/.travis.yml file should contain: + """ + script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') + - phpunit + """ + + When I run `wp eval "if ( is_executable( '{THEME_DIR}/p2child/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` + Then STDOUT should be: + """ + executable + """ + + Scenario: Scaffold theme tests invalid theme + When I try `wp scaffold theme-tests p3child` + Then STDERR should be: + """ + Error: Invalid theme slug specified. + """ + + Scenario: Scaffold theme tests with Circle as the provider + When I run `wp scaffold theme-tests p2child --ci=circle` + Then STDOUT should not be empty + And the {THEME_DIR}/p2child/.travis.yml file should not exist + And the {THEME_DIR}/p2child/circle.yml file should contain: + """ + version: 5.6.22 + """ + + Scenario: Scaffold theme tests with Gitlab as the provider + When I run `wp scaffold theme-tests p2child --ci=gitlab` + Then STDOUT should not be empty + And the {THEME_DIR}/p2child/.travis.yml file should not exist + And the {THEME_DIR}/p2child/.gitlab-ci.yml file should contain: + """ + MYSQL_DATABASE + """ diff --git a/features/scaffold.feature b/features/scaffold.feature index 6f7901eb8..3b0e634bf 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -271,100 +271,6 @@ Feature: WordPress code scaffolding Plugin 'hello-world' network activated. """ - Scenario: Scaffold plugin tests - Given a WP install - When I run `wp plugin path` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin hello-world --skip-tests` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist - And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist - And the {PLUGIN_DIR}/hello-world/readme.txt file should exist - And the {PLUGIN_DIR}/hello-world/tests directory should not exist - - When I run `wp scaffold plugin-tests hello-world` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/tests directory should contain: - """ - bootstrap.php - test-sample.php - """ - And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: - """ - require dirname( dirname( __FILE__ ) ) . '/hello-world.php'; - """ - And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: - """ - * @package Hello_World - """ - And the {PLUGIN_DIR}/hello-world/tests/test-sample.php file should contain: - """ - * @package Hello_World - """ - And the {PLUGIN_DIR}/hello-world/bin directory should contain: - """ - install-wp-tests.sh - """ - And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist - And the {PLUGIN_DIR}/hello-world/phpcs.ruleset.xml file should exist - And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist - And the {PLUGIN_DIR}/hello-world/.gitlab-ci.yml file should not exist - And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: - """ - script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit - """ - - When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` - Then STDOUT should be: - """ - executable - """ - - Scenario: Scaffold plugin tests with Circle as the provider, part one - Given a WP install - And I run `wp scaffold plugin hello-world --ci=circle` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/circle.yml file should contain: - """ - version: 5.6.22 - """ - - Scenario: Scaffold plugin tests with Circle as the provider, part two - Given a WP install - And I run `wp scaffold plugin hello-world --skip-tests` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin-tests hello-world --ci=circle` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/circle.yml file should contain: - """ - version: 5.6.22 - """ - - Scenario: Scaffold plugin tests with Gitlab as the provider - Given a WP install - And I run `wp scaffold plugin hello-world --skip-tests` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin-tests hello-world --ci=gitlab` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/.gitlab-ci.yml file should contain: - """ - MYSQL_DATABASE - """ - Scenario: Scaffold starter code for a theme Given a WP install Given I run `wp theme path` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index fa8c94ec4..77b80bb02 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -587,44 +587,109 @@ function plugin( $args, $assoc_args ) { * * @subcommand plugin-tests */ - function plugin_tests( $args, $assoc_args ) { + public function plugin_tests( $args, $assoc_args ) { + $this->scaffold_plugin_theme_tests( $args, $assoc_args, 'plugin' ); + } + + /** + * Generate files needed for running PHPUnit tests in a theme. + * + * The following files are generated by default: + * + * * `phpunit.xml.dist` is the configuration file for PHPUnit. + * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. + * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. + * * `tests/bootstrap.php` is the file that makes the current theme active when running the test suite. + * * `tests/test-sample.php` is a sample file containing the actual tests. + * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. + * + * Learn more from the [plugin unit tests documentation](http://wp-cli.org/docs/plugin-unit-tests/). + * + * ## ENVIRONMENT + * + * The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment + * variable. + * + * ## OPTIONS + * + * [<theme>] + * : The name of the theme to generate test files for. + * + * [--dir=<dirname>] + * : Generate test files for a non-standard theme path. If no theme slug is specified, the directory name is used. + * + * [--ci=<provider>] + * : Choose a configuration file for a continuous integration provider. + * --- + * default: travis + * options: + * - travis + * - circle + * - gitlab + * --- + * + * [--force] + * : Overwrite files that already exist. + * + * ## EXAMPLES + * + * # Generate unit test files for theme 'twentysixteenchild'. + * $ wp scaffold theme-tests twentysixteenchild + * Success: Created test files. + * + * @subcommand theme-tests + */ + public function theme_tests( $args, $assoc_args ) { + $this->scaffold_plugin_theme_tests( $args, $assoc_args, 'theme' ); + } + + private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { $wp_filesystem = $this->init_wp_filesystem(); if ( ! empty( $args[0] ) ) { - $plugin_slug = $args[0]; - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - if ( empty( $assoc_args['dir'] ) && ! is_dir( $plugin_dir ) ) { - WP_CLI::error( 'Invalid plugin slug specified.' ); + $slug = $args[0]; + if ( 'theme' === $type ) { + $theme = wp_get_theme( $slug ); + if ( $theme->exists() ) { + $target_dir = $theme->get_stylesheet_directory(); + } else { + WP_CLI::error( "Invalid {$type} slug specified." ); + } + } else { + $target_dir = WP_PLUGIN_DIR . "/$slug"; + } + if ( empty( $assoc_args['dir'] ) && ! is_dir( $target_dir ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); } } if ( ! empty( $assoc_args['dir'] ) ) { - $plugin_dir = $assoc_args['dir']; - if ( ! is_dir( $plugin_dir ) ) { - WP_CLI::error( 'Invalid plugin directory specified.' ); + $target_dir = $assoc_args['dir']; + if ( ! is_dir( $target_dir ) ) { + WP_CLI::error( "Invalid {$type} directory specified." ); } - if ( empty( $plugin_slug ) ) { - $plugin_slug = basename( $plugin_dir ); + if ( empty( $slug ) ) { + $slug = basename( $target_dir ); } } - if ( empty( $plugin_slug ) || empty( $plugin_dir ) ) { - WP_CLI::error( 'Invalid plugin specified.' ); + if ( empty( $slug ) || empty( $target_dir ) ) { + WP_CLI::error( "Invalid {$type} specified." ); } - $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); - $plugin_package = str_replace( ' ', '_', $plugin_name ); + $name = ucwords( str_replace( '-', ' ', $slug ) ); + $package = str_replace( ' ', '_', $name ); - $tests_dir = "$plugin_dir/tests"; - $bin_dir = "$plugin_dir/bin"; + $tests_dir = "{$target_dir}/tests"; + $bin_dir = "{$target_dir}/bin"; $wp_filesystem->mkdir( $tests_dir ); $wp_filesystem->mkdir( $bin_dir ); $wp_versions_to_test = array('latest'); // Parse plugin readme.txt - if ( file_exists( $plugin_dir . '/readme.txt' ) ) { - $readme_content = file_get_contents( $plugin_dir . '/readme.txt' ); + if ( file_exists( $target_dir . '/readme.txt' ) ) { + $readme_content = file_get_contents( $target_dir . '/readme.txt' ); preg_match( '/Requires at least\:(.*)\n/m', $readme_content, $matches ); if ( isset( $matches[1] ) && $matches[1] ) { @@ -636,36 +701,38 @@ function plugin_tests( $args, $assoc_args ) { } } - $plugin_data = array( - 'plugin_slug' => $plugin_slug, - 'plugin_package' => $plugin_package, + $template_data = array( + "{$type}_slug" => $slug, + "{$type}_package" => $package, ); $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $files_to_create = array( - "$tests_dir/bootstrap.php" => Utils\mustache_render( 'bootstrap.mustache', $plugin_data ), - "$tests_dir/test-sample.php" => Utils\mustache_render( 'test-sample.mustache', $plugin_data ), + "$tests_dir/bootstrap.php" => Utils\mustache_render( "{$type}-bootstrap.mustache", $template_data ), + "$tests_dir/test-sample.php" => Utils\mustache_render( "{$type}-test-sample.mustache", $template_data ), ); if ( 'travis' === $assoc_args['ci'] ) { - $files_to_create["$plugin_dir/.travis.yml"] = Utils\mustache_render( 'plugin-travis.mustache', compact( 'wp_versions_to_test' ) ); + $files_to_create["{$target_dir}/.travis.yml"] = Utils\mustache_render( 'plugin-travis.mustache', compact( 'wp_versions_to_test' ) ); } else if ( 'circle' === $assoc_args['ci'] ) { - $files_to_create["$plugin_dir/circle.yml"] = Utils\mustache_render( 'plugin-circle.mustache' ); + $files_to_create["{$target_dir}/circle.yml"] = Utils\mustache_render( 'plugin-circle.mustache' ); } else if ( 'gitlab' === $assoc_args['ci'] ) { - $files_to_create["$plugin_dir/.gitlab-ci.yml"] = Utils\mustache_render( 'plugin-gitlab.mustache' ); + $files_to_create["{$target_dir}/.gitlab-ci.yml"] = Utils\mustache_render( 'plugin-gitlab.mustache' ); } $files_written = $this->create_files( $files_to_create, $force ); $to_copy = array( 'install-wp-tests.sh' => $bin_dir, - 'phpunit.xml.dist' => $plugin_dir, - 'phpcs.ruleset.xml' => $plugin_dir, + 'phpunit.xml.dist' => $target_dir, + 'phpcs.ruleset.xml' => $target_dir, ); foreach ( $to_copy as $file => $dir ) { $file_name = "$dir/$file"; $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_name, $force ); - if ( ! $should_write_file ) continue; + if ( ! $should_write_file ) { + continue; + } $files_written[] = $file_name; $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", $file_name, true ); diff --git a/templates/bootstrap.mustache b/templates/plugin-bootstrap.mustache similarity index 100% rename from templates/bootstrap.mustache rename to templates/plugin-bootstrap.mustache diff --git a/templates/test-sample.mustache b/templates/plugin-test-sample.mustache similarity index 100% rename from templates/test-sample.mustache rename to templates/plugin-test-sample.mustache diff --git a/templates/theme-bootstrap.mustache b/templates/theme-bootstrap.mustache new file mode 100644 index 000000000..82c81cfc0 --- /dev/null +++ b/templates/theme-bootstrap.mustache @@ -0,0 +1,34 @@ +<?php +/** + * PHPUnit bootstrap file + * + * @package {{theme_package}} + */ + +$_tests_dir = getenv( 'WP_TESTS_DIR' ); +if ( ! $_tests_dir ) { + $_tests_dir = '/tmp/wordpress-tests-lib'; +} + +// Give access to tests_add_filter() function. +require_once $_tests_dir . '/includes/functions.php'; + +function _register_theme() { + + $theme_dir = dirname( dirname( __FILE__ ) ); + $current_theme = basename( $theme_dir ); + + register_theme_directory( dirname( $theme_dir ) ); + + add_filter( 'pre_option_template', function() use ( $current_theme ) { + return $current_theme; + }); + add_filter( 'pre_option_stylesheet', function() use ( $current_theme ) { + return $current_theme; + }); +} +tests_add_filter( 'muplugins_loaded', '_register_theme' ); + + +// Start up the WP testing environment. +require $_tests_dir . '/includes/bootstrap.php'; diff --git a/templates/theme-test-sample.mustache b/templates/theme-test-sample.mustache new file mode 100644 index 000000000..ec78927c6 --- /dev/null +++ b/templates/theme-test-sample.mustache @@ -0,0 +1,20 @@ +<?php +/** + * Class SampleTest + * + * @package {{theme_package}} + */ + +/** + * Sample test case. + */ +class SampleTest extends WP_UnitTestCase { + + /** + * A single example test. + */ + function test_sample() { + // Replace this with some actual testing code. + $this->assertTrue( true ); + } +} From ca8cbc8ceaaf1e28456aa681c194b45213ded9aa Mon Sep 17 00:00:00 2001 From: "Toro_Unit (Hiroshi Urabe)" <mail@torounit.com> Date: Sat, 12 Nov 2016 04:39:37 +0900 Subject: [PATCH 5074/5359] checkout all in phpunit. --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index cf709c276..26df6217e 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -79,7 +79,7 @@ install_test_suite() { if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/ $WP_TESTS_DIR fi if [ ! -f wp-tests-config.php ]; then From 2acae079e40e09f8b919e22e60cb071a0b2cc257 Mon Sep 17 00:00:00 2001 From: "Toro_Unit (Hiroshi Urabe)" <mail@torounit.com> Date: Sat, 12 Nov 2016 05:11:00 +0900 Subject: [PATCH 5075/5359] revert change --- templates/install-wp-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index 26df6217e..cf709c276 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -79,7 +79,7 @@ install_test_suite() { if [ ! -d $WP_TESTS_DIR ]; then # set up testing suite mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/ $WP_TESTS_DIR + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes fi if [ ! -f wp-tests-config.php ]; then From ecfacbbb9bcbfb8cb16d87201a67af1186d6763f Mon Sep 17 00:00:00 2001 From: "Toro_Unit (Hiroshi Urabe)" <mail@torounit.com> Date: Sat, 12 Nov 2016 05:11:38 +0900 Subject: [PATCH 5076/5359] checkout phpunit/data --- templates/install-wp-tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh index cf709c276..73bb4c787 100644 --- a/templates/install-wp-tests.sh +++ b/templates/install-wp-tests.sh @@ -80,6 +80,7 @@ install_test_suite() { # set up testing suite mkdir -p $WP_TESTS_DIR svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data fi if [ ! -f wp-tests-config.php ]; then From 071467d6a09c1cd68d6261435aad7575c8522000 Mon Sep 17 00:00:00 2001 From: Patrick Karjala <pkarjala@gmail.com> Date: Tue, 15 Nov 2016 23:12:09 +0000 Subject: [PATCH 5077/5359] Fix issue with inaccurate password generation methodology when running wp core install. --- php/commands/core.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/php/commands/core.php b/php/commands/core.php index 6f6f69a5e..6ab16fa64 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -683,11 +683,6 @@ function wp_new_blog_notification() { WP_CLI::set_url( $assoc_args['url'] ); } - if ( empty( $assoc_args['admin_password'] ) ) { - $assoc_args['admin_password'] = wp_generate_password(); - WP_CLI::log( "Admin password: {$assoc_args['admin_password']}" ); - } - $public = true; // @codingStandardsIgnoreStart @@ -706,6 +701,10 @@ function wp_new_blog_notification() { WP_CLI::error( 'Installation produced database errors, and may have partially or completely failed.' ); } + if ( empty( $admin_password ) ) { + WP_CLI::log( "Admin password: {$result['password']}" ); + } + // Confirm the uploads directory exists $upload_dir = wp_upload_dir(); if ( ! empty( $upload_dir['error'] ) ) { From 9a3f3bf5299ddd7218734169345d27c795932862 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 16 Nov 2016 05:36:50 -0800 Subject: [PATCH 5078/5359] runcommand excerpts are now called tips --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c2a98ec9..c38e3e16d 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ When looking for support, please first look for an answer in one of the followin - [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) - [Documentation portal](https://wp-cli.org/docs/) - [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) -- [runcommand Excerpts](https://runcommand.io/excerpts/) +- [runcommand tips](https://runcommand.io/tips/) - [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) Need help with a project related to work? Professional users may want to consider [runcommand premium support](https://runcommand.io/pricing/). Alternatively, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. From baf52da273848f7832bd9a7fa5f41ae608814233 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 16 Nov 2016 05:47:34 -0800 Subject: [PATCH 5079/5359] Don't require `--allow-root` with `cli update`; clarify docs --- README.md | 2 ++ php/WP_CLI/Runner.php | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6c2a98ec9..3d0dc8b55 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ WP-CLI version: 0.25.0 You can update WP-CLI with `wp cli update` ([doc](https://wp-cli.org/commands/cli/update/)), or by repeating the installation steps. +If WP-CLI is owned by root or another system user, you'll need to run `sudo wp cli update`. + Want to live life on the edge? Run `wp cli update --nightly` to use the latest nightly build of WP-CLI. The nightly build is more or less stable enough for you to use in your development environment, and always includes the latest and greatest WP-CLI features. ### Tab completions diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 34d60cdff..98cf8325f 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -661,12 +661,18 @@ private function init_config() { } private function check_root() { - if ( $this->config['allow-root'] ) + if ( $this->config['allow-root'] ) { return; # they're aware of the risks! - if ( !function_exists( 'posix_geteuid') ) + } + if ( 'cli' === $this->arguments[0] && 'update' === $this->arguments[1] ) { + return; # make it easier to update root-owned copies + } + if ( !function_exists( 'posix_geteuid') ) { return; # posix functions not available - if ( posix_geteuid() !== 0 ) + } + if ( posix_geteuid() !== 0 ) { return; # not root + } WP_CLI::error( "YIKES! It looks like you're running this as root. You probably meant to " . From 2d05e655a68ab3f2ae72544e262869dcd5df6756 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 16 Nov 2016 08:27:12 -0800 Subject: [PATCH 5080/5359] Prevent error notices when `arguments` doesn't contain two items --- php/WP_CLI/Runner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 98cf8325f..0700d01ee 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -664,7 +664,7 @@ private function check_root() { if ( $this->config['allow-root'] ) { return; # they're aware of the risks! } - if ( 'cli' === $this->arguments[0] && 'update' === $this->arguments[1] ) { + if ( count( $this->arguments ) >= 2 && 'cli' === $this->arguments[0] && 'update' === $this->arguments[1] ) { return; # make it easier to update root-owned copies } if ( !function_exists( 'posix_geteuid') ) { From bd56bdbd7b8284e0c91390af85694b578c44db95 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 17 Nov 2016 23:27:51 +0900 Subject: [PATCH 5081/5359] add default value to $WP_CLI_BIN_DIR --- ci/prepare.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/prepare.sh b/ci/prepare.sh index b34f72660..5c6b10c4c 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -4,6 +4,8 @@ set -ex +WP_CLI_BIN_DIR=${WP_CLI_BIN_DIR-/tmp/wp-cli-phar} + composer install --no-interaction --prefer-source CLI_VERSION=$(head -n 1 VERSION) From 87dc91cf40ce2464b459d3da8ed4df20ed7a07eb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 06:29:38 -0800 Subject: [PATCH 5082/5359] Use return code 1 when one or more menus fails to delete --- features/menu.feature | 33 +++++++++++++++++++++++++++++++-- php/commands/menu.php | 31 ++++++++++++++++--------------- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/features/menu.feature b/features/menu.feature index 839bd4d08..c830aafb2 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -14,9 +14,12 @@ Feature: Manage WordPress menus When I run `wp menu delete "My Menu"` Then STDOUT should be: """ + Deleted menu 'My Menu'. Success: 1 menu deleted. """ - And I run `wp menu list --format=count` + And the return code should be 0 + + When I run `wp menu list --format=count` Then STDOUT should be: """ 0 @@ -33,9 +36,13 @@ Feature: Manage WordPress menus When I run `wp menu delete "First Menu" "Second Menu"` Then STDOUT should be: """ + Deleted menu 'First Menu'. + Deleted menu 'Second Menu'. Success: 2 menus deleted. """ - And I run `wp menu list --format=count` + And the return code should be 0 + + When I run `wp menu list --format=count` Then STDOUT should be: """ 0 @@ -47,3 +54,25 @@ Feature: Manage WordPress menus """ 5 """ + + Scenario: Errors when deleting menus + When I try `wp menu delete "Your menu"` + Then STDERR should be: + """ + Warning: Couldn't delete menu 'Your menu'. + Error: No menus deleted. + """ + + When I run `wp menu create "My Menu"` + And I run `wp menu list --fields=name,slug` + Then STDOUT should be a table containing rows: + | name | slug | + | My Menu | my-menu | + + When I try `wp menu delete "My Menu" "Your menu"` + Then STDERR should be: + """ + Warning: Couldn't delete menu 'Your menu'. + Error: Only 1 of 2 menus deleted. + """ + And the return code should be 1 diff --git a/php/commands/menu.php b/php/commands/menu.php index 671bde8dd..3867cb985 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -89,28 +89,29 @@ public function create( $args, $assoc_args ) { */ public function delete( $args, $_ ) { - $count = 0; - + $count = $errored = 0; foreach( $args as $arg ) { - $ret = wp_delete_nav_menu( $arg ); - if ( ! $ret || is_wp_error( $ret ) ) { - - WP_CLI::warning( "Error deleting menu." ); - - } - else { - + WP_CLI::warning( "Couldn't delete menu '{$arg}'." ); + $errored++; + } else { + WP_CLI::log( "Deleted menu '{$arg}'." ); $count++; - } - } - $success_message = ( 1 === $count ) ? '%d menu deleted.' : '%d menus deleted.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - + if ( $errored ) { + $arg_count = count( $args ); + if ( $count ) { + WP_CLI::error( sprintf( 'Only %d of %d menus deleted.', $count, $arg_count ) ); + } else { + WP_CLI::error( 'No menus deleted.' ); + } + } else { + $success_message = ( 1 === $count ) ? '%d menu deleted.' : '%d menus deleted.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + } } /** From 035ac3dd8f2dae0275feeafa90e6b8aac638f16e Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 06:37:06 -0800 Subject: [PATCH 5083/5359] Use return code 1 when one or more menu items fails to delete --- features/menu-item.feature | 23 +++++++++++++++++++++++ php/commands/menu-item.php | 20 +++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/features/menu-item.feature b/features/menu-item.feature index 0f0c514f5..055059ef2 100644 --- a/features/menu-item.feature +++ b/features/menu-item.feature @@ -109,3 +109,26 @@ Feature: Manage WordPress menu items | title | db_id | menu_item_parent | | Grandparent | {GRANDPARENT_ID} | 0 | | Child | {CHILD_ID} | {GRANDPARENT_ID} | + + Scenario: Error deleting one or more menu items + When I run `wp menu create "Sidebar Menu"` + Then STDOUT should not be empty + + When I try `wp menu item delete 99999999` + Then STDERR should be: + """ + Warning: Couldn't delete menu item 99999999. + Error: No menu items deleted. + """ + And the return code should be 1 + + When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` + Then save STDOUT as {CUSTOM_ITEM_ID} + + When I try `wp menu item delete {CUSTOM_ITEM_ID} 99999999` + Then STDERR should be: + """ + Warning: Couldn't delete menu item 99999999. + Error: Only 1 of 2 menu items deleted. + """ + And the return code should be 1 diff --git a/php/commands/menu-item.php b/php/commands/menu-item.php index 25d79529c..b6270a249 100644 --- a/php/commands/menu-item.php +++ b/php/commands/menu-item.php @@ -355,14 +355,15 @@ public function update( $args, $assoc_args ) { public function delete( $args, $_ ) { global $wpdb; - $count = 0; + $count = $errored = 0; foreach( $args as $arg ) { $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); $ret = wp_delete_post( $arg, true ); if ( ! $ret ) { - WP_CLI::warning( "Couldn't delete menu item." ); + WP_CLI::warning( "Couldn't delete menu item {$arg}." ); + $errored++; } else if ( $parent_menu_id ) { $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); if ( $children ) { @@ -374,14 +375,23 @@ public function delete( $args, $_ ) { } } - if ( false !== $ret ) { + if ( false != $ret ) { $count++; } } - $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; - WP_CLI::success( sprintf( $success_message, $count ) ); + if ( $errored ) { + $arg_count = count( $args ); + if ( $count ) { + WP_CLI::error( sprintf( 'Only %d of %d menu items deleted.', $count, $arg_count ) ); + } else { + WP_CLI::error( 'No menu items deleted.' ); + } + } else { + $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + } } From 40d07ffd5e9a991b7a3cfde925af1ffea4c4f3ea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 08:19:57 -0800 Subject: [PATCH 5084/5359] Use return code 1 when one or more super admins fails to add --- features/super-admin.feature | 31 +++++++++++++++++++++++++++++-- php/commands/super-admin.php | 31 ++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/features/super-admin.feature b/features/super-admin.feature index 05ff00f98..4c8b543d8 100644 --- a/features/super-admin.feature +++ b/features/super-admin.feature @@ -10,7 +10,13 @@ Feature: Manage super admins associated with a multisite instance """ When I run `wp super-admin add superadmin` - And I run `wp super-admin list` + Then STDOUT should be: + """ + Success: Granted super-admin capabilities to 1 user. + """ + And the return code should be 0 + + When I run `wp super-admin list` Then STDOUT should be: """ admin @@ -18,10 +24,15 @@ Feature: Manage super admins associated with a multisite instance """ When I run `wp super-admin add superadmin` - Then STDERR should contain: + Then STDERR should be: """ Warning: User 'superadmin' already has super-admin capabilities. """ + And STDOUT should be: + """ + Success: Super admins remain unchanged. + """ + And the return code should be 0 When I run `wp super-admin list` Then STDOUT should be: @@ -48,3 +59,19 @@ Feature: Manage super admins associated with a multisite instance """ [{"user_login":"superadmin"}] """ + + When I try `wp super-admin add noadmin` + Then STDERR should be: + """ + Warning: Invalid user ID, email or login: 'noadmin' + Error: Couldn't grant super-admin capabilities to 1 of 1 users. + """ + And the return code should be 1 + + When I try `wp super-admin add admin noadmin` + Then STDERR should be: + """ + Warning: Invalid user ID, email or login: 'noadmin' + Error: Only granted super-admin capabilities to 1 of 2 users. + """ + And the return code should be 1 diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php index ce46b6496..4c79be9f4 100644 --- a/php/commands/super-admin.php +++ b/php/commands/super-admin.php @@ -94,32 +94,41 @@ public function _list( $_, $assoc_args ) { */ public function add( $args, $_ ) { + $successes = $errors = 0; $users = $this->fetcher->get_many( $args ); + if ( count( $users ) != count( $args ) ) { + $errors = count( $args ) - count( $users ); + } $user_logins = wp_list_pluck( $users, 'user_login' ); $super_admins = self::get_admins(); $num_super_admins = count( $super_admins ); foreach ( $user_logins as $user_login ) { - $user = get_user_by( 'login', $user_login ); - - if ( !$user ) { - WP_CLI::warning( "Couldn't find '{$user_login}' user." ); - continue; - } - - if ( in_array( $user->user_login, $super_admins ) ) { + if ( in_array( $user_login, $super_admins ) ) { WP_CLI::warning( "User '{$user_login}' already has super-admin capabilities." ); continue; } - $super_admins[] = $user->user_login; + $super_admins[] = $user_login; + $successes++; } if ( $num_super_admins === count( $super_admins ) ) { - WP_CLI::log( 'No changes.' ); + if ( $errors ) { + $user_count = count( $args ); + WP_CLI::error( "Couldn't grant super-admin capabilities to {$errors} of {$user_count} users." ); + } else { + WP_CLI::success( 'Super admins remain unchanged.' ); + } } else { if ( update_site_option( 'site_admins' , $super_admins ) ) { - WP_CLI::success( 'Granted super-admin capabilities.' ); + if ( $errors ) { + $user_count = count( $args ); + WP_CLI::error( "Only granted super-admin capabilities to {$successes} of {$user_count} users." ); + } else { + $message = $successes > 1 ? 'users' : 'user'; + WP_CLI::success( "Granted super-admin capabilities to {$successes} {$message}." ); + } } else { WP_CLI::error( 'Site options update failed.' ); } From e7ff94f03861782ccf6fe05044e5113425743c00 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 08:40:59 -0800 Subject: [PATCH 5085/5359] Use return code 1 when one or more terms fail to delete --- features/term.feature | 27 +++++++++++++++++++++++++-- php/commands/term.php | 27 ++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/features/term.feature b/features/term.feature index 82b0c4614..de2f7b815 100644 --- a/features/term.feature +++ b/features/term.feature @@ -60,6 +60,10 @@ Feature: Manage WordPress terms Then STDOUT should be a number And save STDOUT as {TERM_ID} + When I run `wp term create post_tag 'Test delete term 2' --slug=test-two --description='This is a test term to be deleted' --porcelain` + Then STDOUT should be a number + And save STDOUT as {TERM_ID_TWO} + When I run `wp term get post_tag {TERM_ID} --field=slug --format=json` Then STDOUT should be: """ @@ -67,13 +71,32 @@ Feature: Manage WordPress terms """ When I run `wp term delete post_tag {TERM_ID}` - Then STDOUT should contain: + Then STDOUT should be: """ Deleted post_tag {TERM_ID}. + Success: Deleted 1 of 1 terms. """ + And the return code should be 0 When I try the previous command again - Then STDERR should not be empty + Then STDERR should be: + """ + Warning: post_tag {TERM_ID} doesn't exist. + Error: No terms deleted. + """ + And the return code should be 1 + + When I try `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` + Then STDOUT should be: + """ + Deleted post_tag {TERM_ID_TWO}. + """ + And STDERR should be: + """ + Warning: post_tag {TERM_ID} doesn't exist. + Error: Only deleted 1 of 2 terms. + """ + And the return code should be 1 Scenario: Term with a non-existent parent When I try `wp term create category Apple --parent=99 --porcelain` diff --git a/php/commands/term.php b/php/commands/term.php index feafbe946..455619663 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -333,28 +333,45 @@ public function update( $args, $assoc_args ) { * * # Delete post category * $ wp term delete category 15 - * Success: Deleted category 15. + * Deleted category 15. + * Success: Deleted 1 of 1 terms. * * # Delete all post tags * $ wp term list post_tag --field=term_id | xargs wp term delete post_tag - * Success: Deleted post_tag 159. - * Success: Deleted post_tag 160. - * Success: Deleted post_tag 161. + * Deleted post_tag 159. + * Deleted post_tag 160. + * Deleted post_tag 161. + * Success: Deleted 3 of 3 terms. */ public function delete( $args ) { $taxonomy = array_shift( $args ); + $successes = $errors = 0; foreach ( $args as $term_id ) { $ret = wp_delete_term( $term_id, $taxonomy ); if ( is_wp_error( $ret ) ) { WP_CLI::warning( $ret ); + $errors++; } else if ( $ret ) { - WP_CLI::success( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); + WP_CLI::log( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); + $successes++; } else { WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); + $errors++; } } + + if ( $errors ) { + if ( $successes ) { + $term_count = count( $args ); + WP_CLI::error( "Only deleted {$successes} of {$term_count} terms." ); + } else { + WP_CLI::error( "No terms deleted." ); + } + } else { + WP_CLI::success( "Deleted {$successes} of {$successes} terms." ); + } } /** From 36d0bebba6ff9857a7acfc91645bb7a792058ad9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 09:26:50 -0800 Subject: [PATCH 5086/5359] Use return code 1 when management of 1 or more widgets fails --- features/widget-reset.feature | 38 +++++++++++--- features/widget.feature | 97 +++++++++++++++++++++++++++++++++-- php/commands/widget.php | 78 ++++++++++++++++++++++------ 3 files changed, 186 insertions(+), 27 deletions(-) diff --git a/features/widget-reset.feature b/features/widget-reset.feature index 4c2d84bdc..f102ee377 100644 --- a/features/widget-reset.feature +++ b/features/widget-reset.feature @@ -30,16 +30,24 @@ Feature: Reset WordPress sidebars """ Warning: Sidebar 'sidebar-1' is already empty. """ + And STDOUT should be: + """ + Success: Sidebar already reset. + """ + And the return code should be 0 When I try `wp widget reset non-existing-sidebar-id` Then STDERR should be: """ Warning: Invalid sidebar: non-existing-sidebar-id + Error: No sidebars reset. """ + And the return code should be 1 When I run `wp widget add calendar sidebar-1 --title="Calendar"` Then STDOUT should not be empty - And I run `wp widget list sidebar-1 --format=count` + + When I run `wp widget list sidebar-1 --format=count` Then STDOUT should be: """ 1 @@ -47,19 +55,28 @@ Feature: Reset WordPress sidebars When I run `wp widget add search sidebar-2 --title="Quick Search"` Then STDOUT should not be empty - And I run `wp widget list sidebar-2 --format=count` + + When I run `wp widget list sidebar-2 --format=count` Then STDOUT should be: """ 1 """ - When I run `wp widget reset sidebar-1 sidebar-2` - And I run `wp widget list sidebar-1 --format=count` + When I try `wp widget reset sidebar-1 sidebar-2 non-existing-sidebar-id` + Then STDERR should be: + """ + Warning: Invalid sidebar: non-existing-sidebar-id + Error: Only reset 2 of 3 sidebars. + """ + And the return code should be 1 + + When I run `wp widget list sidebar-1 --format=count` Then STDOUT should be: """ 0 """ - And I run `wp widget list sidebar-2 --format=count` + + When I run `wp widget list sidebar-2 --format=count` Then STDOUT should be: """ 0 @@ -79,7 +96,16 @@ Feature: Reset WordPress sidebars Then STDOUT should not be empty When I run `wp widget reset --all` - And I run `wp widget list sidebar-1 --format=count` + Then STDOUT should be: + """ + Sidebar 'sidebar-1' reset. + Sidebar 'sidebar-2' reset. + Sidebar 'sidebar-3' reset. + Success: Reset 3 of 3 sidebars. + """ + And the return code should be 0 + + When I run `wp widget list sidebar-1 --format=count` Then STDOUT should be: """ 0 diff --git a/features/widget.feature b/features/widget.feature index e5eb4609f..1beb08bfc 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -1,11 +1,11 @@ Feature: Manage widgets in WordPress sidebar - Scenario: Widget CRUD + Background: Given a WP install - When I run `wp theme install p2 --activate` Then STDOUT should not be empty + Scenario: Widget CRUD When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: | name | id | position | @@ -34,9 +34,11 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget deactivate meta-2` Then STDOUT should be: - """ - Success: 1 widget deactivated. - """ + """ + Success: 1 widget deactivated. + """ + And STDERR should be empty + And the return code should be 0 When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: @@ -57,6 +59,8 @@ Feature: Manage widgets in WordPress sidebar """ Success: 2 widgets removed from sidebar. """ + And STDERR should be empty + And the return code should be 0 When I run `wp widget list sidebar-1 --fields=name,id,position` Then STDOUT should be a table containing rows: @@ -87,3 +91,86 @@ Feature: Manage widgets in WordPress sidebar Then STDOUT should be a table containing rows: | name | position | options | | calendar | 2 | {"title":"Calendar"} | + + Scenario: Validate sidebar widgets + When I try `wp widget update calendar-999` + Then STDERR should be: + """ + Error: Widget doesn't exist. + """ + And the return code should be 1 + + When I try `wp widget move calendar-999` + Then STDERR should be: + """ + Error: Widget doesn't exist. + """ + And the return code should be 1 + + Scenario: Return code is 0 when all widgets exist, deactivation + When I run `wp widget deactivate recent-posts-2` + Then STDOUT should be: + """ + Success: 1 widget deactivated. + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp widget deactivate search-2 archives-2` + Then STDOUT should be: + """ + Success: 2 widgets deactivated. + """ + And STDERR should be empty + And the return code should be 0 + + Scenario: Return code is 0 when all widgets exist, deletion + When I run `wp widget delete recent-posts-2` + Then STDOUT should be: + """ + Success: 1 widget removed from sidebar. + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp widget delete search-2 archives-2` + Then STDOUT should be: + """ + Success: 2 widgets removed from sidebar. + """ + And STDERR should be empty + And the return code should be 0 + + Scenario: Return code is 1 when 1 or more widgets doesn't exist, deactivation + When I try `wp widget deactivate calendar-999` + Then STDERR should be: + """ + Warning: Widget 'calendar-999' doesn't exist. + Error: No widgets deactivated. + """ + And the return code should be 1 + + When I try `wp widget deactivate recent-posts-2 calendar-999` + Then STDERR should be: + """ + Warning: Widget 'calendar-999' doesn't exist. + Error: Only deactivated 1 of 2 widgets. + """ + And the return code should be 1 + + Scenario: Return code is 1 when 1 or more widgets doesn't exist, deletion + When I try `wp widget delete calendar-999` + Then STDERR should be: + """ + Warning: Widget 'calendar-999' doesn't exist. + Error: No widgets removed from sidebar. + """ + And the return code should be 1 + + When I try `wp widget delete recent-posts-2 calendar-999` + Then STDERR should be: + """ + Warning: Widget 'calendar-999' doesn't exist. + Error: Only removed 1 of 2 widgets from sidebar. + """ + And the return code should be 1 diff --git a/php/commands/widget.php b/php/commands/widget.php index 494060115..14739c6a1 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -182,7 +182,9 @@ public function add( $args, $assoc_args ) { public function update( $args, $assoc_args ) { list( $widget_id ) = $args; - $this->validate_sidebar_widget( $widget_id ); + if ( ! $this->validate_sidebar_widget( $widget_id ) ) { + WP_CLI::error( "Widget doesn't exist." ); + } if ( empty( $assoc_args ) ) { WP_CLI::error( "No options specified to update." ); @@ -231,7 +233,9 @@ public function update( $args, $assoc_args ) { public function move( $args, $assoc_args ) { list( $widget_id ) = $args; - $this->validate_sidebar_widget( $widget_id ); + if ( ! $this->validate_sidebar_widget( $widget_id ) ) { + WP_CLI::error( "Widget doesn't exist." ); + } if ( empty( $assoc_args['position'] ) && empty( $assoc_args['sidebar-id'] ) ) { WP_CLI::error( "A new position or new sidebar must be specified." ); @@ -275,10 +279,14 @@ public function move( $args, $assoc_args ) { */ public function deactivate( $args, $assoc_args ) { - $count = 0; + $count = $errors = 0; foreach( $args as $widget_id ) { - $this->validate_sidebar_widget( $widget_id ); + if ( ! $this->validate_sidebar_widget( $widget_id ) ) { + WP_CLI::warning( "Widget '{$widget_id}' doesn't exist." ); + $errors++; + continue; + } list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); if ( 'wp_inactive_widgets' == $sidebar_id ) { @@ -292,8 +300,17 @@ public function deactivate( $args, $assoc_args ) { } - $success_message = ( 1 === $count ) ? '%d widget deactivated.' : '%d widgets deactivated.'; - WP_CLI::success( sprintf( $success_message, $count ) ); + if ( $errors ) { + if ( $count ) { + $widget_count = count( $args ); + WP_CLI::error( "Only deactivated {$count} of {$widget_count} widgets." ); + } else { + WP_CLI::error( "No widgets deactivated." ); + } + } else { + $success_message = ( 1 === $count ) ? '%d widget deactivated.' : '%d widgets deactivated.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + } } /** @@ -314,10 +331,14 @@ public function deactivate( $args, $assoc_args ) { */ public function delete( $args, $assoc_args ) { - $count = 0; + $count = $errors = 0; foreach( $args as $widget_id ) { - $this->validate_sidebar_widget( $widget_id ); + if ( ! $this->validate_sidebar_widget( $widget_id ) ) { + WP_CLI::warning( "Widget '{$widget_id}' doesn't exist." ); + $errors++; + continue; + } // Remove the widget's settings. list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); @@ -334,8 +355,17 @@ public function delete( $args, $assoc_args ) { $count++; } - $success_message = ( 1 === $count ) ? '%d widget removed from sidebar.' : '%d widgets removed from sidebar.'; - WP_CLI::success( sprintf( $success_message, $count ) ); + if ( $errors ) { + if ( $count ) { + $widget_count = count( $args ); + WP_CLI::error( "Only removed {$count} of {$widget_count} widgets from sidebar." ); + } else { + WP_CLI::error( "No widgets removed from sidebar." ); + } + } else { + $success_message = ( 1 === $count ) ? '%d widget removed from sidebar.' : '%d widgets removed from sidebar.'; + WP_CLI::success( sprintf( $success_message, $count ) ); + } } /** @@ -394,9 +424,11 @@ public function reset( $args, $assoc_args ) { WP_CLI::error( 'No sidebar registered.' ); } + $count = $errors = 0; foreach ( $args as $sidebar_id ) { if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { WP_CLI::warning( sprintf( 'Invalid sidebar: %s', $sidebar_id ) ); + $errors++; continue; } @@ -410,9 +442,27 @@ public function reset( $args, $assoc_args ) { list( $name, $option_index, $new_sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); $this->move_sidebar_widget( $widget_id, $new_sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); } - WP_CLI::success( sprintf( "Sidebar '%s' reset.", $sidebar_id ) ); + WP_CLI::log( sprintf( "Sidebar '%s' reset.", $sidebar_id ) ); + $count++; } } + + $sidebar_count = count( $args ); + if ( $errors ) { + if ( $count ) { + WP_CLI::error( "Only reset {$count} of {$sidebar_count} sidebars." ); + } else { + WP_CLI::error( 'No sidebars reset.' ); + } + } else { + if ( $count ) { + WP_CLI::success( "Reset {$count} of {$sidebar_count} sidebars." ); + } else { + $message = $sidebar_count > 1 ? 'Sidebars' : 'Sidebar'; + WP_CLI::success( "{$message} already reset." ); + } + } + } /** @@ -448,11 +498,7 @@ private function validate_sidebar_widget( $widget_id ) { } } - - if ( false === $widget_exists ) { - WP_CLI::error( "Specified widget isn't present on sidebar." ); - } - + return $widget_exists; } /** From 9f9f30b09bbfce8674cc7d89f25b363cd0358445 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 15:25:18 -0800 Subject: [PATCH 5087/5359] Introduce `WP_CLI\Utils\report_batch_operation_results()` A helper function for reporting the results of the same operation against multiple resources. --- features/menu-item.feature | 6 ++--- features/menu.feature | 6 ++--- features/plugin-install.feature | 38 ++++++++++++++++++++++++++ features/term.feature | 17 +++++++----- features/theme-install.feature | 39 +++++++++++++++++++++++++++ features/widget.feature | 16 +++++------ php/WP_CLI/CommandWithUpgrade.php | 14 ++++++++-- php/commands/menu-item.php | 19 ++++--------- php/commands/menu.php | 18 ++++--------- php/commands/term.php | 16 +++-------- php/commands/widget.php | 45 +++++-------------------------- php/utils.php | 37 +++++++++++++++++++++++++ 12 files changed, 170 insertions(+), 101 deletions(-) create mode 100644 features/theme-install.feature diff --git a/features/menu-item.feature b/features/menu-item.feature index 055059ef2..2507896bb 100644 --- a/features/menu-item.feature +++ b/features/menu-item.feature @@ -62,7 +62,7 @@ Feature: Manage WordPress menu items When I run `wp menu item delete {CUSTOM_ITEM_ID}` Then STDOUT should be: """ - Success: 1 menu item deleted. + Success: Deleted 1 of 1 menu items. """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: @@ -73,7 +73,7 @@ Feature: Manage WordPress menu items When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` Then STDOUT should be: """ - Success: 2 menu items deleted. + Success: Deleted 2 of 2 menu items. """ And I run `wp menu item list sidebar-menu --format=count` Then STDOUT should be: @@ -129,6 +129,6 @@ Feature: Manage WordPress menu items Then STDERR should be: """ Warning: Couldn't delete menu item 99999999. - Error: Only 1 of 2 menu items deleted. + Error: Only deleted 1 of 2 menu items. """ And the return code should be 1 diff --git a/features/menu.feature b/features/menu.feature index c830aafb2..95d179617 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -15,7 +15,7 @@ Feature: Manage WordPress menus Then STDOUT should be: """ Deleted menu 'My Menu'. - Success: 1 menu deleted. + Success: Deleted 1 of 1 menus. """ And the return code should be 0 @@ -38,7 +38,7 @@ Feature: Manage WordPress menus """ Deleted menu 'First Menu'. Deleted menu 'Second Menu'. - Success: 2 menus deleted. + Success: Deleted 2 of 2 menus. """ And the return code should be 0 @@ -73,6 +73,6 @@ Feature: Manage WordPress menus Then STDERR should be: """ Warning: Couldn't delete menu 'Your menu'. - Error: Only 1 of 2 menus deleted. + Error: Only deleted 1 of 2 menus. """ And the return code should be 1 diff --git a/features/plugin-install.feature b/features/plugin-install.feature index cd9a42a6d..dfba0d4df 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -58,3 +58,41 @@ Feature: Install WordPress plugins Plugin installed successfully. """ And STDERR should be empty + + Scenario: Return code is 1 when one or more plugin installations fail + Given a WP install + + When I try `wp plugin install user-switching user-switching-not-a-plugin` + Then STDERR should be: + """ + Warning: Couldn't find 'user-switching-not-a-plugin' in the WordPress.org plugin directory. + Error: Only installed 1 of 2 plugins. + """ + And STDOUT should contain: + """ + Installing User Switching + """ + And STDOUT should contain: + """ + Plugin installed successfully. + """ + And the return code should be 1 + + When I run `wp plugin install user-switching` + Then STDOUT should be: + """ + Success: Plugin already installed. + """ + And STDERR should be: + """ + Warning: user-switching: Plugin already installed. + """ + And the return code should be 0 + + When I try `wp plugin install user-switching-not-a-plugin` + Then STDERR should be: + """ + Warning: Couldn't find 'user-switching-not-a-plugin' in the WordPress.org plugin directory. + Error: No plugins installed. + """ + And the return code should be 1 diff --git a/features/term.feature b/features/term.feature index de2f7b815..20a5bc55d 100644 --- a/features/term.feature +++ b/features/term.feature @@ -78,25 +78,28 @@ Feature: Manage WordPress terms """ And the return code should be 0 - When I try the previous command again - Then STDERR should be: + When I run the previous command again + Then STDOUT should be: + """ + Success: Term already deleted. + """ + And STDERR should be: """ Warning: post_tag {TERM_ID} doesn't exist. - Error: No terms deleted. """ - And the return code should be 1 + And the return code should be 0 - When I try `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` + When I run `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` Then STDOUT should be: """ Deleted post_tag {TERM_ID_TWO}. + Success: Deleted 1 of 2 terms. """ And STDERR should be: """ Warning: post_tag {TERM_ID} doesn't exist. - Error: Only deleted 1 of 2 terms. """ - And the return code should be 1 + And the return code should be 0 Scenario: Term with a non-existent parent When I try `wp term create category Apple --parent=99 --porcelain` diff --git a/features/theme-install.feature b/features/theme-install.feature new file mode 100644 index 000000000..4a313b64f --- /dev/null +++ b/features/theme-install.feature @@ -0,0 +1,39 @@ +Feature: Install WordPress themes + + Scenario: Return code is 1 when one or more theme installations fail + Given a WP install + + When I try `wp theme install p2 p2-not-a-theme` + Then STDERR should be: + """ + Warning: Couldn't find 'p2-not-a-theme' in the WordPress.org theme directory. + Error: Only installed 1 of 2 themes. + """ + And STDOUT should contain: + """ + Installing P2 + """ + And STDOUT should contain: + """ + Theme installed successfully. + """ + And the return code should be 1 + + When I run `wp theme install p2` + Then STDOUT should be: + """ + Success: Theme already installed. + """ + And STDERR should be: + """ + Warning: p2: Theme already installed. + """ + And the return code should be 0 + + When I try `wp theme install p2-not-a-theme` + Then STDERR should be: + """ + Warning: Couldn't find 'p2-not-a-theme' in the WordPress.org theme directory. + Error: No themes installed. + """ + And the return code should be 1 diff --git a/features/widget.feature b/features/widget.feature index 1beb08bfc..4fbffa83a 100644 --- a/features/widget.feature +++ b/features/widget.feature @@ -35,7 +35,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget deactivate meta-2` Then STDOUT should be: """ - Success: 1 widget deactivated. + Success: Deactivated 1 of 1 widgets. """ And STDERR should be empty And the return code should be 0 @@ -57,7 +57,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget delete archives-2 recent-posts-2` Then STDOUT should be: """ - Success: 2 widgets removed from sidebar. + Success: Deleted 2 of 2 widgets. """ And STDERR should be empty And the return code should be 0 @@ -111,7 +111,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget deactivate recent-posts-2` Then STDOUT should be: """ - Success: 1 widget deactivated. + Success: Deactivated 1 of 1 widgets. """ And STDERR should be empty And the return code should be 0 @@ -119,7 +119,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget deactivate search-2 archives-2` Then STDOUT should be: """ - Success: 2 widgets deactivated. + Success: Deactivated 2 of 2 widgets. """ And STDERR should be empty And the return code should be 0 @@ -128,7 +128,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget delete recent-posts-2` Then STDOUT should be: """ - Success: 1 widget removed from sidebar. + Success: Deleted 1 of 1 widgets. """ And STDERR should be empty And the return code should be 0 @@ -136,7 +136,7 @@ Feature: Manage widgets in WordPress sidebar When I run `wp widget delete search-2 archives-2` Then STDOUT should be: """ - Success: 2 widgets removed from sidebar. + Success: Deleted 2 of 2 widgets. """ And STDERR should be empty And the return code should be 0 @@ -163,7 +163,7 @@ Feature: Manage widgets in WordPress sidebar Then STDERR should be: """ Warning: Widget 'calendar-999' doesn't exist. - Error: No widgets removed from sidebar. + Error: No widgets deleted. """ And the return code should be 1 @@ -171,6 +171,6 @@ Feature: Manage widgets in WordPress sidebar Then STDERR should be: """ Warning: Widget 'calendar-999' doesn't exist. - Error: Only removed 1 of 2 widgets from sidebar. + Error: Only deleted 1 of 2 widgets. """ And the return code should be 1 diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index fa3b59f3d..43cea27cd 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -118,6 +118,7 @@ private function show_legend( $items ) { function install( $args, $assoc_args ) { + $successes = $errors = 0; foreach ( $args as $slug ) { if ( empty( $slug ) ) { @@ -162,20 +163,28 @@ function install( $args, $assoc_args ) { if ( $filter ) { remove_filter( 'upgrader_source_selection', $filter, 10, 3 ); } + $successes++; + } else { + $errors++; } } else { // Assume a plugin/theme slug from the WordPress.org repository has been specified $result = $this->install_from_repo( $slug, $assoc_args ); if ( is_wp_error( $result ) ) { - $key = $result->get_error_code(); - if ( in_array( $result->get_error_code(), array( 'plugins_api_failed', 'themes_api_failed' ) ) + if ( in_array( $key, array( 'plugins_api_failed', 'themes_api_failed' ) ) && ! empty( $result->error_data[ $key ] ) && in_array( $result->error_data[ $key ], array( 'N;', 'b:0;' ) ) ) { \WP_CLI::warning( "Couldn't find '$slug' in the WordPress.org {$this->item_type} directory." ); + $errors++; } else { \WP_CLI::warning( "$slug: " . $result->get_error_message() ); + if ( 'already_installed' !== $key ) { + $errors++; + } } + } else { + $successes++; } } @@ -191,6 +200,7 @@ function install( $args, $assoc_args ) { } } } + Utils\report_batch_operation_results( $this->item_type, 'install', count( $args ), $successes, $errors ); } /** diff --git a/php/commands/menu-item.php b/php/commands/menu-item.php index b6270a249..2b6f04b94 100644 --- a/php/commands/menu-item.php +++ b/php/commands/menu-item.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * List, add, and delete items associated with a menu. * @@ -355,7 +357,7 @@ public function update( $args, $assoc_args ) { public function delete( $args, $_ ) { global $wpdb; - $count = $errored = 0; + $count = $errors = 0; foreach( $args as $arg ) { @@ -363,7 +365,7 @@ public function delete( $args, $_ ) { $ret = wp_delete_post( $arg, true ); if ( ! $ret ) { WP_CLI::warning( "Couldn't delete menu item {$arg}." ); - $errored++; + $errors++; } else if ( $parent_menu_id ) { $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); if ( $children ) { @@ -381,18 +383,7 @@ public function delete( $args, $_ ) { } - if ( $errored ) { - $arg_count = count( $args ); - if ( $count ) { - WP_CLI::error( sprintf( 'Only %d of %d menu items deleted.', $count, $arg_count ) ); - } else { - WP_CLI::error( 'No menu items deleted.' ); - } - } else { - $success_message = ( 1 === $count ) ? '%d menu item deleted.' : '%d menu items deleted.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - } - + Utils\report_batch_operation_results( 'menu item', 'delete', count( $args ), $count, $errors ); } /** diff --git a/php/commands/menu.php b/php/commands/menu.php index 3867cb985..2a51a307b 100644 --- a/php/commands/menu.php +++ b/php/commands/menu.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * List, create, assign, and delete menus. * @@ -89,29 +91,19 @@ public function create( $args, $assoc_args ) { */ public function delete( $args, $_ ) { - $count = $errored = 0; + $count = $errors = 0; foreach( $args as $arg ) { $ret = wp_delete_nav_menu( $arg ); if ( ! $ret || is_wp_error( $ret ) ) { WP_CLI::warning( "Couldn't delete menu '{$arg}'." ); - $errored++; + $errors++; } else { WP_CLI::log( "Deleted menu '{$arg}'." ); $count++; } } - if ( $errored ) { - $arg_count = count( $args ); - if ( $count ) { - WP_CLI::error( sprintf( 'Only %d of %d menus deleted.', $count, $arg_count ) ); - } else { - WP_CLI::error( 'No menus deleted.' ); - } - } else { - $success_message = ( 1 === $count ) ? '%d menu deleted.' : '%d menus deleted.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - } + Utils\report_batch_operation_results( 'menu', 'delete', count( $args ), $count, $errors ); } /** diff --git a/php/commands/term.php b/php/commands/term.php index 455619663..ffee4e0cf 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -1,4 +1,7 @@ <?php + +use WP_CLI\Utils; + /** * Manage terms. * @@ -358,20 +361,9 @@ public function delete( $args ) { $successes++; } else { WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); - $errors++; - } - } - - if ( $errors ) { - if ( $successes ) { - $term_count = count( $args ); - WP_CLI::error( "Only deleted {$successes} of {$term_count} terms." ); - } else { - WP_CLI::error( "No terms deleted." ); } - } else { - WP_CLI::success( "Deleted {$successes} of {$successes} terms." ); } + Utils\report_batch_operation_results( 'term', 'delete', count( $args ), $successes, $errors ); } /** diff --git a/php/commands/widget.php b/php/commands/widget.php index 14739c6a1..21cc8e5bf 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Manage sidebar widgets. * @@ -300,17 +302,7 @@ public function deactivate( $args, $assoc_args ) { } - if ( $errors ) { - if ( $count ) { - $widget_count = count( $args ); - WP_CLI::error( "Only deactivated {$count} of {$widget_count} widgets." ); - } else { - WP_CLI::error( "No widgets deactivated." ); - } - } else { - $success_message = ( 1 === $count ) ? '%d widget deactivated.' : '%d widgets deactivated.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - } + Utils\report_batch_operation_results( 'widget', 'deactivate', count( $args ), $count, $errors ); } /** @@ -325,7 +317,7 @@ public function deactivate( $args, $assoc_args ) { * * # Delete the recent-comments-2 widget from its sidebar. * $ wp widget delete recent-comments-2 - * Success: 1 widget removed from sidebar. + * Success: Deleted 1 of 1 widgets. * * @subcommand delete */ @@ -355,17 +347,7 @@ public function delete( $args, $assoc_args ) { $count++; } - if ( $errors ) { - if ( $count ) { - $widget_count = count( $args ); - WP_CLI::error( "Only removed {$count} of {$widget_count} widgets from sidebar." ); - } else { - WP_CLI::error( "No widgets removed from sidebar." ); - } - } else { - $success_message = ( 1 === $count ) ? '%d widget removed from sidebar.' : '%d widgets removed from sidebar.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - } + Utils\report_batch_operation_results( 'widget', 'delete', count( $args ), $count, $errors ); } /** @@ -447,22 +429,7 @@ public function reset( $args, $assoc_args ) { } } - $sidebar_count = count( $args ); - if ( $errors ) { - if ( $count ) { - WP_CLI::error( "Only reset {$count} of {$sidebar_count} sidebars." ); - } else { - WP_CLI::error( 'No sidebars reset.' ); - } - } else { - if ( $count ) { - WP_CLI::success( "Reset {$count} of {$sidebar_count} sidebars." ); - } else { - $message = $sidebar_count > 1 ? 'Sidebars' : 'Sidebar'; - WP_CLI::success( "{$message} already reset." ); - } - } - + Utils\report_batch_operation_results( 'sidebar', 'reset', count( $args ), $count, $errors ); } /** diff --git a/php/utils.php b/php/utils.php index 0332ad1bb..ff3a09ed6 100644 --- a/php/utils.php +++ b/php/utils.php @@ -6,6 +6,7 @@ use \Composer\Semver\Comparator; use \Composer\Semver\Semver; +use \WP_CLI; use \WP_CLI\Dispatcher; use \WP_CLI\Iterators\Transform; @@ -762,3 +763,39 @@ function parse_ssh_url( $url, $component = -1 ) { return $bits; } } + +/** + * Report the results of the same operation against multiple resources. + * + * @access public + * @category Input + * + * @param string $noun Resource being affected (e.g. plugin) + * @param string $verb Type of action happening to the noun (e.g. activate) + * @param integer $total Total number of resource being affected. + * @param integer $successes Number of successful operations. + * @param integer $failures Number of failures. + */ +function report_batch_operation_results( $noun, $verb, $total, $successes, $failures ) { + $plural_noun = $noun . 's'; + if ( in_array( $verb, array( 'reset' ), true ) ) { + $past_tense_verb = $verb; + } else { + $past_tense_verb = 'e' === substr( $verb, -1 ) ? $verb . 'd' : $verb . 'ed'; + } + $past_tense_verb_upper = ucfirst( $past_tense_verb ); + if ( $failures ) { + if ( $successes ) { + WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}." ); + } else { + WP_CLI::error( "No {$plural_noun} {$past_tense_verb}." ); + } + } else { + if ( $successes ) { + WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); + } else { + $message = count( $total ) > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); + WP_CLI::success( "{$message} already {$past_tense_verb}." ); + } + } +} From 6ba30bca91592cf4067b21556c775e421d9b8f83 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 16:05:10 -0800 Subject: [PATCH 5088/5359] Use return code 1 when importing or regenerating more than one image fails --- features/media-import.feature | 21 ++++++++++---- features/media-regenerate.feature | 21 ++++++-------- php/commands/media.php | 46 ++++++++++++++++++------------- php/commands/plugin.php | 2 ++ 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/features/media-import.feature b/features/media-import.feature index 57e3a90e4..552ec0f96 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -7,22 +7,30 @@ Feature: Manage WordPress attachments When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` Then STDOUT should contain: """ - Success: Imported file 'http://wp-cli.org/behat-data/codeispoetry.png' + Imported file 'http://wp-cli.org/behat-data/codeispoetry.png' + """ + And STDOUT should contain: + """ + Success: Imported 1 of 1 images. """ Scenario: Fail to import missing image When I try `wp media import gobbledygook.png` - Then STDERR should contain: + Then STDERR should be: """ - Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. + Warning: Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. + Error: No images imported. """ + And the return code should be 1 Scenario: Fail to import missing image on Windows When I try `wp media import c:/path/gobbledygook.png` - Then STDERR should contain: + Then STDERR should be: """ - Unable to import file 'c:/path/gobbledygook.png'. Reason: File doesn't exist. + Warning: Unable to import file 'c:/path/gobbledygook.png'. Reason: File doesn't exist. + Error: No images imported. """ + And the return code should be 1 Scenario: Import a file as attachment from a local image Given download: @@ -32,13 +40,14 @@ Feature: Manage WordPress attachments When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` Then STDOUT should contain: """ - Success: Imported file + Imported file """ And STDOUT should contain: """ and attached to post 1 as featured image """ And the {CACHE_DIR}/large-image.jpg file should exist + And the return code should be 0 Scenario: Import a file as an attachment but porcelain style Given download: diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index df8ce1ac0..b589389f8 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -37,7 +37,7 @@ Feature: Regenerate WordPress attachments When I run `wp media regenerate --yes` Then STDOUT should contain: """ - Success: Finished regenerating the image. + Success: Regenerated 1 of 1 images. """ And the wp-content/uploads/large-image-125x125.jpg file should not exist And the wp-content/uploads/large-image-200x200.jpg file should exist @@ -69,7 +69,7 @@ Feature: Regenerate WordPress attachments When I run `wp media regenerate --skip-delete --yes` Then STDOUT should contain: """ - Success: Finished regenerating the image. + Success: Regenerated 1 of 1 images. """ And the wp-content/uploads/large-image-125x125.jpg file should exist And the wp-content/uploads/large-image-200x200.jpg file should exist @@ -94,14 +94,11 @@ Feature: Regenerate WordPress attachments When I run `rm wp-content/uploads/large-image.jpg` Then STDOUT should be empty - When I run `wp media regenerate --yes` - Then STDOUT should contain: - """ - An error occurred with image regeneration. - """ - And STDERR should contain: + When I try `wp media regenerate --yes` + Then STDERR should be: """ - Warning: Can't find + Warning: Can't find "My imported attachment" (ID {ATTACHMENT_ID}). + Error: No images regenerated. """ Scenario: Only regenerate images which are missing sizes @@ -142,7 +139,7 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - Success: Finished regenerating all images. + Success: Regenerated 2 of 2 images """ Scenario: Regenerate images which are missing globally-defined image sizes @@ -174,7 +171,7 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - Success: Finished regenerating the image. + Success: Regenerated 1 of 1 images. """ And the wp-content/uploads/large-image-125x125.jpg file should exist @@ -189,6 +186,6 @@ Feature: Regenerate WordPress attachments """ And STDOUT should contain: """ - Success: Finished regenerating the image. + Success: Regenerated 1 of 1 images. """ And the wp-content/uploads/large-image-125x125.jpg file should exist diff --git a/php/commands/media.php b/php/commands/media.php index 33d79bf19..227079d8f 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Manage attachments. * @@ -11,7 +13,7 @@ * 1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). * 2/3 Regenerated thumbnails for "Boardwalk" (ID 757). * 3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756). - * Success: Finished regenerating all images. + * Success: Regenerated 3 of 3 images. * * # Import a local image and set it to be the featured image for a post. * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image @@ -46,7 +48,7 @@ class Media_Command extends WP_CLI_Command { * 1/3 Regenerated thumbnails for "Vertical Image" (ID 123). * 2/3 Regenerated thumbnails for "Horizontal Image" (ID 124). * 3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125). - * Success: Finished regenerating all images. + * Success: Regenerated 3 of 3 images. * * # Regenerate all thumbnails, without confirmation. * $ wp media regenerate --yes @@ -54,7 +56,7 @@ class Media_Command extends WP_CLI_Command { * 1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). * 2/3 Regenerated thumbnails for "Boardwalk" (ID 757). * 3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756). - * Success: Finished regenerating all images. + * Success: Regenerated 3 of 3 images. * * # Re-generate all thumbnails that have IDs between 1000 and 2000. * $ seq 1000 2000 | xargs wp media regenerate @@ -63,7 +65,7 @@ class Media_Command extends WP_CLI_Command { * 2/4 Regenerated thumbnails for "Horizontal Featured Image" (ID 1022). * 3/4 Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045). * 4/4 Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023). - * Success: Finished regenerating all images. + * Success: Regenerated 4 of 4 images. */ function regenerate( $args, $assoc_args = array() ) { if ( empty( $args ) ) { @@ -98,20 +100,16 @@ function regenerate( $args, $assoc_args = array() ) { _n( 'image', 'images', $count ) ) ); $errored = false; + $successes = $errors = 0; foreach ( $images->posts as $number => $id ) { - if ( ! $this->process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { - $errored = true; + if ( $this->process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { + $successes++; + } else { + $errors++; } } - if ( $errored ) { - WP_CLI::log( _n( 'An error occurred with image regeneration.', 'An error occurred regenerating one or more images.', $count ) ); - } else { - WP_CLI::success( sprintf( - 'Finished regenerating %1$s.', - _n('the image', 'all images', $count) - ) ); - } + Utils\report_batch_operation_results( 'image', 'regenerate', count( $images->posts ), $successes, $errors ); } /** @@ -149,12 +147,14 @@ function regenerate( $args, $assoc_args = array() ) { * * # Import all jpgs in the current user's "Pictures" directory, not attached to any post. * $ wp media import ~/Pictures/**\/*.jpg - * Success: Imported file '/home/person/Pictures/beautiful-youg-girl-in-ivy.jpg' as attachment ID 1751. - * Success: Imported file '/home/person/Pictures/fashion-girl.jpg' as attachment ID 1752. + * Imported file '/home/person/Pictures/beautiful-youg-girl-in-ivy.jpg' as attachment ID 1751. + * Imported file '/home/person/Pictures/fashion-girl.jpg' as attachment ID 1752. + * Success: Imported 2 of 2 images. * * # Import a local image and set it to be the post thumbnail for a post. * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image - * Success: Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image. + * Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image. + * Success: Imported 1 of 1 images. * * # Import a local image, but set it as the featured image for all posts. * # 1. Import the image and get its attachment ID. @@ -166,7 +166,8 @@ function regenerate( $args, $assoc_args = array() ) { * * # Import an image from the web. * $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" - * Success: Imported file 'http://s.wordpress.org/style/images/wp-header-logo.png' as attachment ID 1755. + * Imported file 'http://s.wordpress.org/style/images/wp-header-logo.png' as attachment ID 1755. + * Success: Imported 1 of 1 images. */ function import( $args, $assoc_args = array() ) { $assoc_args = wp_parse_args( $assoc_args, array( @@ -185,6 +186,7 @@ function import( $args, $assoc_args = array() ) { $assoc_args['post_id'] = false; } + $successes = $errors = 0; foreach ( $args as $file ) { $is_file_remote = parse_url( $file, PHP_URL_HOST ); $orig_filename = $file; @@ -192,6 +194,7 @@ function import( $args, $assoc_args = array() ) { if ( empty( $is_file_remote ) ) { if ( !file_exists( $file ) ) { WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." ); + $errors++; break; } $tempfile = $this->make_copy( $file ); @@ -238,6 +241,7 @@ function import( $args, $assoc_args = array() ) { "Unable to import file '%s'. Reason: %s", $orig_filename, implode( ', ', $success->get_error_messages() ) ) ); + $errors++; continue; } @@ -261,11 +265,15 @@ function import( $args, $assoc_args = array() ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $success ); } else { - WP_CLI::success( sprintf( + WP_CLI::log( sprintf( "Imported file '%s' as attachment ID %d%s.", $orig_filename, $success, $attachment_success_text ) ); } + $successes++; + } + if ( ! Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { + Utils\report_batch_operation_results( 'image', 'import', count( $args ), $successes, $errors ); } } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index de195fd34..c27b79d4e 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -386,6 +386,7 @@ function deactivate( $args, $assoc_args = array() ) { function toggle( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); + $successes = $errors = 0; foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->check_active( $plugin->file, $network_wide ) ) { $this->deactivate( array( $plugin->name ), $assoc_args ); @@ -393,6 +394,7 @@ function toggle( $args, $assoc_args = array() ) { $this->activate( array( $plugin->name ), $assoc_args ); } } + Utils\report_batch_operation_results( 'plugin', 'toggle', count( $args ), $successes, $errors ); } /** From 3bc58b195408d066126c9916932e34039993e921 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 17:16:08 -0800 Subject: [PATCH 5089/5359] Use `Utils\report_batch_operation_results()` for themes and plugins --- features/plugin-activate.feature | 35 ++++++++ features/plugin-deactivate.feature | 36 ++++++++ features/plugin-delete.feature | 25 ++++++ features/plugin-toggle.feature | 42 +++++++++ features/plugin-uninstall.feature | 37 ++++++++ features/plugin.feature | 83 ++++++++++++------ features/theme-delete.feature | 29 +++++++ features/upgradables.feature | 10 +-- php/WP_CLI/CommandWithUpgrade.php | 4 + php/commands/plugin.php | 132 ++++++++++++++++++++--------- php/commands/theme.php | 18 +++- php/utils.php | 2 +- 12 files changed, 377 insertions(+), 76 deletions(-) create mode 100644 features/plugin-activate.feature create mode 100644 features/plugin-deactivate.feature create mode 100644 features/plugin-delete.feature create mode 100644 features/plugin-toggle.feature create mode 100644 features/plugin-uninstall.feature create mode 100644 features/theme-delete.feature diff --git a/features/plugin-activate.feature b/features/plugin-activate.feature new file mode 100644 index 000000000..949168774 --- /dev/null +++ b/features/plugin-activate.feature @@ -0,0 +1,35 @@ +Feature: Activate WordPress plugins + + Background: + Given a WP install + + Scenario: Activate a plugin that's already installed + When I run `wp plugin activate akismet` + Then STDOUT should be: + """ + Plugin 'akismet' activated. + Success: Activated 1 of 1 plugins. + """ + And the return code should be 0 + + Scenario: Attempt to activate a plugin that's not installed + When I try `wp plugin activate edit-flow` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Error: No plugins activated. + """ + And the return code should be 1 + + When I try `wp plugin activate akismet hello edit-flow` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Error: Only activated 2 of 3 plugins. + """ + And STDOUT should be: + """ + Plugin 'akismet' activated. + Plugin 'hello' activated. + """ + And the return code should be 1 diff --git a/features/plugin-deactivate.feature b/features/plugin-deactivate.feature new file mode 100644 index 000000000..37b68dce7 --- /dev/null +++ b/features/plugin-deactivate.feature @@ -0,0 +1,36 @@ +Feature: Deactivate WordPress plugins + + Background: + Given a WP install + And I run `wp plugin activate akismet hello` + + Scenario: Deactivate a plugin that's already activated + When I run `wp plugin deactivate akismet` + Then STDOUT should be: + """ + Plugin 'akismet' deactivated. + Success: Deactivated 1 of 1 plugins. + """ + And the return code should be 0 + + Scenario: Attempt to deactivate a plugin that's not installed + When I try `wp plugin deactivate edit-flow` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Error: No plugins deactivated. + """ + And the return code should be 1 + + When I try `wp plugin deactivate akismet hello edit-flow` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Error: Only deactivated 2 of 3 plugins. + """ + And STDOUT should be: + """ + Plugin 'akismet' deactivated. + Plugin 'hello' deactivated. + """ + And the return code should be 1 diff --git a/features/plugin-delete.feature b/features/plugin-delete.feature new file mode 100644 index 000000000..c1e5fa7d9 --- /dev/null +++ b/features/plugin-delete.feature @@ -0,0 +1,25 @@ +Feature: Delete WordPress plugins + + Background: + Given a WP install + + Scenario: Delete an installed plugin + When I run `wp plugin delete akismet` + Then STDOUT should be: + """ + Deleted 'akismet' plugin. + Success: Deleted 1 of 1 plugins. + """ + And the return code should be 0 + + Scenario: Attempting to delete a plugin that doesn't exist + When I run `wp plugin delete edit-flow` + Then STDOUT should be: + """ + Success: Plugin already deleted. + """ + And STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + """ + And the return code should be 0 diff --git a/features/plugin-toggle.feature b/features/plugin-toggle.feature new file mode 100644 index 000000000..4c81bff92 --- /dev/null +++ b/features/plugin-toggle.feature @@ -0,0 +1,42 @@ +Feature: Toggle the activation status of a plugin + + Background: + Given a WP install + + Scenario: Toggle the status of a plugin + When I run `wp plugin toggle akismet` + Then STDOUT should be: + """ + Plugin 'akismet' activated. + Success: Toggled 1 of 1 plugins. + """ + + When I run `wp plugin toggle akismet` + Then STDOUT should be: + """ + Plugin 'akismet' deactivated. + Success: Toggled 1 of 1 plugins. + """ + + Scenario: Toggling the status of a plugin that doesn't exist + When I try `wp plugin toggle akismet edit-flow` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Error: Only toggled 1 of 2 plugins. + """ + And STDOUT should be: + """ + Plugin 'akismet' activated. + """ + And the return code should be 1 + + When I try `wp plugin toggle edit-flow co-authors-plus` + Then STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + Warning: The 'co-authors-plus' plugin could not be found. + Error: No plugins toggled. + """ + And STDOUT should be empty + And the return code should be 1 diff --git a/features/plugin-uninstall.feature b/features/plugin-uninstall.feature new file mode 100644 index 000000000..65646e8d0 --- /dev/null +++ b/features/plugin-uninstall.feature @@ -0,0 +1,37 @@ +Feature: Uninstall a WordPress plugin + + Background: + Given a WP install + + Scenario: Uninstall an installed plugin + When I run `wp plugin uninstall akismet` + Then STDOUT should be: + """ + Uninstalled and deleted 'akismet' plugin. + Success: Uninstalled 1 of 1 plugins. + """ + And the return code should be 0 + + Scenario: Attempting to uninstall a plugin that's activated + When I run `wp plugin activate akismet` + Then STDOUT should not be empty + + When I try `wp plugin uninstall akismet` + Then STDERR should be: + """ + Warning: The 'akismet' plugin is active. + Error: No plugins uninstalled. + """ + And the return code should be 0 + + Scenario: Attempting to uninstall a plugin that doesn't exist + When I run `wp plugin uninstall edit-flow` + Then STDOUT should be: + """ + Success: Plugin already uninstalled. + """ + And STDERR should be: + """ + Warning: The 'edit-flow' plugin could not be found. + """ + And the return code should be 0 diff --git a/features/plugin.feature b/features/plugin.feature index 1bbecf2bd..ef6bc7448 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -80,9 +80,10 @@ Feature: Manage WordPress plugins """ When I run `wp plugin uninstall Zombieland` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Uninstalled and deleted 'Zombieland' plugin. + Uninstalled and deleted 'Zombieland' plugin. + Success: Uninstalled 1 of 1 plugins. """ And the {PLUGIN_DIR}/zombieland file should not exist @@ -141,7 +142,8 @@ Feature: Manage WordPress plugins When I run `wp plugin activate network-only` Then STDOUT should be: """ - Success: Plugin 'network-only' activated. + Plugin 'network-only' activated. + Success: Activated 1 of 1 plugins. """ When I run `wp plugin status network-only` @@ -161,7 +163,8 @@ Feature: Manage WordPress plugins When I run `wp plugin activate network-only` Then STDOUT should be: """ - Success: Plugin 'network-only' network activated. + Plugin 'network-only' network activated. + Success: Activated 1 of 1 plugins. """ When I run `wp plugin status network-only` @@ -174,9 +177,10 @@ Feature: Manage WordPress plugins Given a WP multisite install When I run `wp plugin activate akismet` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Plugin 'akismet' activated. + Plugin 'akismet' activated. + Success: Activated 1 of 1 plugins. """ When I run `wp plugin list --fields=name,status` @@ -189,36 +193,54 @@ Feature: Manage WordPress plugins """ Warning: Plugin 'akismet' is already active. """ + And STDOUT should be: + """ + Success: Plugin already activated. + """ When I run `wp plugin activate akismet --network` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Plugin 'akismet' network activated. + Plugin 'akismet' network activated. + Success: Network activated 1 of 1 plugins. """ When I run `wp plugin activate akismet --network` - Then STDERR should contain: + Then STDERR should be: """ Warning: Plugin 'akismet' is already network active. """ + And STDOUT should be: + """ + Success: Plugin already network activated. + """ - When I run `wp plugin deactivate akismet` - Then STDERR should contain: + When I try `wp plugin deactivate akismet` + Then STDERR should be: """ Warning: Plugin 'akismet' is network active and must be deactivated with --network flag. + Error: No plugins deactivated. """ + And the return code should be 1 When I run `wp plugin deactivate akismet --network` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Plugin 'akismet' network deactivated. + Plugin 'akismet' network deactivated. + Success: Network deactivated 1 of 1 plugins. """ + And the return code should be 0 When I run `wp plugin deactivate akismet` - Then STDERR should contain: + Then STDERR should be: """ Warning: Plugin 'akismet' isn't active. """ + And STDOUT should be: + """ + Success: Plugin already deactivated. + """ + And the return code should be 0 Scenario: List plugins Given a WP install @@ -264,14 +286,15 @@ Feature: Manage WordPress plugins When I run `wp plugin activate --all` Then STDOUT should be: """ - Success: Plugin 'akismet' activated. - Success: Plugin 'hello' activated. + Plugin 'akismet' activated. + Plugin 'hello' activated. + Success: Activated 2 of 2 plugins. """ When I run `wp plugin activate --all` Then STDOUT should be: """ - Success: All plugins are already activated. + Success: Plugins already activated. """ When I run `wp plugin list --field=status` @@ -285,14 +308,15 @@ Feature: Manage WordPress plugins When I run `wp plugin deactivate --all` Then STDOUT should be: """ - Success: Plugin 'akismet' deactivated. - Success: Plugin 'hello' deactivated. + Plugin 'akismet' deactivated. + Plugin 'hello' deactivated. + Success: Deactivated 2 of 2 plugins. """ When I run `wp plugin deactivate --all` Then STDOUT should be: """ - Success: All plugins are already deactivated. + Success: Plugins already deactivated. """ When I run `wp plugin list --field=status` @@ -311,11 +335,12 @@ Feature: Manage WordPress plugins """ When I run `wp plugin deactivate akismet --uninstall` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Plugin 'akismet' deactivated. + Plugin 'akismet' deactivated. Uninstalling 'akismet'... - Success: Uninstalled and deleted 'akismet' plugin. + Uninstalled and deleted 'akismet' plugin. + Success: Deactivated 1 of 1 plugins. """ When I try `wp plugin get akismet` @@ -332,11 +357,12 @@ Feature: Manage WordPress plugins """ When I run `wp plugin uninstall akismet --deactivate` - Then STDOUT should contain: + Then STDOUT should be: """ Deactivating 'akismet'... - Success: Plugin 'akismet' deactivated. - Success: Uninstalled and deleted 'akismet' plugin. + Plugin 'akismet' deactivated. + Uninstalled and deleted 'akismet' plugin. + Success: Uninstalled 1 of 1 plugins. """ When I try `wp plugin get akismet` @@ -353,9 +379,10 @@ Feature: Manage WordPress plugins Then STDOUT should not be empty When I run `wp plugin uninstall akismet --skip-delete` - Then STDOUT should contain: + Then STDOUT should be: """ - Success: Ran uninstall procedure for + Ran uninstall procedure for 'akismet' plugin without deleting. + Success: Uninstalled 1 of 1 plugins. """ Scenario: Two plugins, one directory diff --git a/features/theme-delete.feature b/features/theme-delete.feature new file mode 100644 index 000000000..45a982c97 --- /dev/null +++ b/features/theme-delete.feature @@ -0,0 +1,29 @@ +Feature: Delete WordPress themes + + Background: + Given a WP install + And I run `wp theme install p2` + + Scenario: Delete an installed theme + When I run `wp theme delete p2` + Then STDOUT should be: + """ + Deleted 'p2' theme. + Success: Deleted 1 of 1 themes. + """ + And the return code should be 0 + + Scenario: Attempting to delete a theme that doesn't exist + When I run `wp theme delete p2` + Then STDOUT should not be empty + + When I run the previous command again + Then STDOUT should be: + """ + Success: Theme already deleted. + """ + And STDERR should be: + """ + Warning: The 'p2' theme could not be found. + """ + And the return code should be 0 diff --git a/features/upgradables.feature b/features/upgradables.feature index fd66e585d..e0caaa1df 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -95,7 +95,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> delete <item>` Then STDOUT should contain: """ - Success: Deleted '<item>' <type>. + Deleted '<item>' <type>. """ When I try `wp <type> status <item>` @@ -119,7 +119,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> delete <item>` Then STDOUT should contain: """ - Success: Deleted '<item>' <type>. + Deleted '<item>' <type>. """ And the <file_to_check> file should not exist @@ -135,7 +135,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> delete <item>` Then STDOUT should contain: """ - Success: Deleted '<item>' <type>. + Deleted '<item>' <type>. """ And the <file_to_check> file should not exist @@ -150,7 +150,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> delete <item>` Then STDOUT should contain: """ - Success: Deleted '<item>' <type>. + Deleted '<item>' <type>. """ And the <file_to_check> file should not exist @@ -165,7 +165,7 @@ Feature: Manage WordPress themes and plugins When I run `wp <type> delete <item>` Then STDOUT should contain: """ - Success: Deleted '<item>' <type>. + Deleted '<item>' <type>. """ And the <file_to_check> file should not exist diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 43cea27cd..e9becb998 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -12,6 +12,8 @@ abstract class CommandWithUpgrade extends \WP_CLI_Command { protected $upgrade_refresh; protected $upgrade_transient; + protected $chained_command = false; + function __construct() { // Do not automatically check translations updates after updating plugins/themes. add_action( 'upgrader_process_complete', function() { @@ -189,6 +191,7 @@ function install( $args, $assoc_args ) { } if ( $result ) { + $this->chained_command = true; if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate-network' ) ) { \WP_CLI::log( "Network-activating '$slug'..." ); $this->activate( array( $slug ), array( 'network' => true ) ); @@ -198,6 +201,7 @@ function install( $args, $assoc_args ) { \WP_CLI::log( "Activating '$slug'..." ); $this->activate( array( $slug ) ); } + $this->chained_command = false; } } Utils\report_batch_operation_results( $this->item_type, 'install', count( $args ), $successes, $errors ); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index c27b79d4e..a8aa01147 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -9,15 +9,18 @@ * * # Activate plugin * $ wp plugin activate hello-dolly - * Success: Plugin 'hello-dolly' activated. + * Plugin 'hello-dolly' activated. + * Success: Activated 1 of 1 plugins. * * # Deactivate plugin * $ wp plugin deactivate hello-dolly - * Success: Plugin 'hello-dolly' deactivated. + * Plugin 'hello-dolly' deactivated. + * Success: Deactivated 1 of 1 plugins. * * # Delete plugin * $ wp plugin delete hello-dolly - * Success: Deleted 'hello-dolly' plugin. + * Deleted 'hello-dolly' plugin. + * Success: Deleted 1 of 1 plugins. * * # Install the latest version from wordpress.org and activate * $ wp plugin install bbpress --activate @@ -28,7 +31,8 @@ * Installing the plugin... * Plugin installed successfully. * Activating 'bbpress'... - * Success: Plugin 'bbpress' activated. + * Plugin 'bbpress' activated. + * Success: Installed 1 of 1 plugins. * * @package wp-cli */ @@ -233,13 +237,15 @@ protected function get_all_items() { * * # Activate plugin * $ wp plugin activate hello-dolly - * Success: Plugin 'hello-dolly' activated. + * Plugin 'hello-dolly' activated. + * Success: Activated 1 of 1 plugins. * * # Activate plugin in entire multisite network * $ wp plugin activate hello-dolly --network - * Success: Plugin 'hello-dolly' network activated. + * Plugin 'hello-dolly' network activated. + * Success: Network activated 1 of 1 plugins. */ - function activate( $args, $assoc_args = array() ) { + public function activate( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); @@ -249,11 +255,14 @@ function activate( $args, $assoc_args = array() ) { }, array_keys( get_plugins() ) ); } - $needing_activation = count( $args ); - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + $successes = $errors = 0; + $plugins = $this->fetcher->get_many( $args ); + if ( count( $plugins ) < count( $args ) ) { + $errors = count( $args ) - count( $plugins ); + } + foreach ( $plugins as $plugin ) { $status = $this->get_status( $plugin->file ); if ( $all && in_array( $status, array( 'active', 'active-network' ) ) ) { - $needing_activation--; continue; } // Network-active is the highest level of activation status @@ -274,11 +283,13 @@ function activate( $args, $assoc_args = array() ) { activate_plugin( $plugin->file, '', $network_wide ); - $this->active_output( $plugin->name, $plugin->file, $network_wide, "activate" ); + $this->active_output( $plugin->name, $plugin->file, $network_wide, 'activate' ); + $successes++; } - if ( ! $needing_activation ) { - WP_CLI::success( 'All plugins are already activated.' ); + if ( ! $this->chained_command ) { + $verb = $network_wide ? 'network activate' : 'activate'; + Utils\report_batch_operation_results( 'plugin', $verb, count( $args ), $successes, $errors ); } } @@ -304,9 +315,10 @@ function activate( $args, $assoc_args = array() ) { * * # Deactivate plugin * $ wp plugin deactivate hello-dolly - * Success: Plugin 'hello-dolly' deactivated. + * Plugin 'hello-dolly' deactivated. + * Success: Deactivated 1 of 1 plugins. */ - function deactivate( $args, $assoc_args = array() ) { + public function deactivate( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); $disable_all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); @@ -316,18 +328,23 @@ function deactivate( $args, $assoc_args = array() ) { }, array_keys( get_plugins() ) ); } - $needing_deactivation = count( $args ); - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + $successes = $errors = 0; + $plugins = $this->fetcher->get_many( $args ); + if ( count( $plugins ) < count( $args ) ) { + $errors = count( $args ) - count( $plugins ); + } + + foreach ( $plugins as $plugin ) { $status = $this->get_status( $plugin->file ); if ( $disable_all && ! in_array( $status, array( 'active', 'active-network' ) ) ) { - $needing_deactivation--; continue; } // Network active plugins must be explicitly deactivated if ( ! $network_wide && 'active-network' === $status ) { WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); + $errors++; continue; } @@ -346,17 +363,21 @@ function deactivate( $args, $assoc_args = array() ) { array( $plugin->file => time() ) + (array) get_site_option( 'recently_activated' ) ); } - $this->active_output( $plugin->name, $plugin->file, $network_wide, "deactivate" ); + $this->active_output( $plugin->name, $plugin->file, $network_wide, 'deactivate' ); + $successes++; if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uninstall' ) ) { WP_CLI::log( "Uninstalling '{$plugin->name}'..." ); + $this->chained_command = true; $this->uninstall( array( $plugin->name ) ); + $this->chained_command = false; } } - if ( ! $needing_deactivation ) { - WP_CLI::success( 'All plugins are already deactivated.' ); + if ( ! $this->chained_command ) { + $verb = $network_wide ? 'network deactivate' : 'deactivate'; + Utils\report_batch_operation_results( 'plugin', $verb, count( $args ), $successes, $errors ); } } @@ -377,23 +398,34 @@ function deactivate( $args, $assoc_args = array() ) { * * ## EXAMPLES * + * # Akismet is currently activated * $ wp plugin toggle akismet - * Success: Plugin 'akismet' deactivated. + * Plugin 'akismet' deactivated. + * Success: Toggled 1 of 1 plugins. * + * # Akismet is currently deactivated * $ wp plugin toggle akismet - * Success: Plugin 'akismet' activated. + * Plugin 'akismet' activated. + * Success: Toggled 1 of 1 plugins. */ - function toggle( $args, $assoc_args = array() ) { + public function toggle( $args, $assoc_args = array() ) { $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); $successes = $errors = 0; - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + $plugins = $this->fetcher->get_many( $args ); + if ( count( $plugins ) < count( $args ) ) { + $errors = count( $args ) - count( $plugins ); + } + $this->chained_command = true; + foreach ( $plugins as $plugin ) { if ( $this->check_active( $plugin->file, $network_wide ) ) { $this->deactivate( array( $plugin->name ), $assoc_args ); } else { $this->activate( array( $plugin->name ), $assoc_args ); } + $successes++; } + $this->chained_command = false; Utils\report_batch_operation_results( 'plugin', 'toggle', count( $args ), $successes, $errors ); } @@ -415,7 +447,7 @@ function toggle( $args, $assoc_args = array() ) { * $ cd $(wp plugin path) && pwd * /var/www/wordpress/wp-content/plugins */ - function path( $args, $assoc_args ) { + public function path( $args, $assoc_args ) { $path = untrailingslashit( WP_PLUGIN_DIR ); if ( !empty( $args ) ) { @@ -594,7 +626,8 @@ protected function filter_item_list( $items, $args ) { * Installing the plugin... * Plugin installed successfully. * Activating 'bbpress'... - * Success: Plugin 'bbpress' activated. + * Plugin 'bbpress' activated. + * Success: Installed 1 of 1 plugins. * * # Install the development version from wordpress.org * $ wp plugin install bbpress --version=dev @@ -603,12 +636,14 @@ protected function filter_item_list( $items, $args ) { * Unpacking the package... * Installing the plugin... * Plugin installed successfully. + * Success: Installed 1 of 1 plugins. * * # Install from a local zip file * $ wp plugin install ../my-plugin.zip * Unpacking the package... * Installing the plugin... * Plugin installed successfully. + * Success: Installed 1 of 1 plugins. * * # Install from a remote zip file * $ wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef @@ -616,6 +651,7 @@ protected function filter_item_list( $items, $args ) { * Unpacking the package... * Installing the plugin... * Plugin installed successfully. + * Success: Installed 1 of 1 plugins. * * # Forcefully re-install all installed plugins * $ wp plugin install $(wp plugin list --field=name) --force @@ -625,8 +661,9 @@ protected function filter_item_list( $items, $args ) { * Installing the plugin... * Removing the old version of the plugin... * Plugin updated successfully + * Success: Installed 1 of 1 plugins. */ - function install( $args, $assoc_args ) { + public function install( $args, $assoc_args ) { if ( ! is_dir( WP_PLUGIN_DIR ) ) { wp_mkdir_p( WP_PLUGIN_DIR ); @@ -707,27 +744,37 @@ public function get( $args, $assoc_args ) { * ## EXAMPLES * * $ wp plugin uninstall hello - * Success: Uninstalled and deleted 'hello' plugin. + * Uninstalled and deleted 'hello' plugin. + * Success: Installed 1 of 1 plugins. */ - function uninstall( $args, $assoc_args = array() ) { - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { + public function uninstall( $args, $assoc_args = array() ) { + $successes = $errors = 0; + $plugins = $this->fetcher->get_many( $args ); + foreach ( $plugins as $plugin ) { if ( is_plugin_active( $plugin->file ) && ! WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { WP_CLI::warning( "The '{$plugin->name}' plugin is active." ); + $errors++; continue; } if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { WP_CLI::log( "Deactivating '{$plugin->name}'..." ); + $this->chained_command = true; $this->deactivate( array( $plugin->name ) ); + $this->chained_command = false; } uninstall_plugin( $plugin->file ); if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { - WP_CLI::success( "Uninstalled and deleted '$plugin->name' plugin." ); + WP_CLI::log( "Uninstalled and deleted '$plugin->name' plugin." ); } else { - WP_CLI::success( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); + WP_CLI::log( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); } + $successes++; + } + if ( ! $this->chained_command ) { + Utils\report_batch_operation_results( 'plugin', 'uninstall', count( $args ), $successes, $errors ); } } @@ -770,18 +817,27 @@ public function is_installed( $args, $assoc_args = array() ) { * * # Delete plugin * $ wp plugin delete hello - * Success: Deleted 'hello' plugin. + * Deleted 'hello' plugin. + * Success: Deleted 1 of 1 plugins. * * # Delete inactive plugins * $ wp plugin delete $(wp plugin list --status=inactive --field=name) - * Success: Deleted 'tinymce-templates' plugin. + * Deleted 'tinymce-templates' plugin. + * Success: Deleted 1 of 1 plugins. */ public function delete( $args, $assoc_args = array() ) { + $successes = $errors = 0; foreach ( $this->fetcher->get_many( $args ) as $plugin ) { if ( $this->_delete( $plugin ) ) { - WP_CLI::success( "Deleted '{$plugin->name}' plugin." ); + WP_CLI::log( "Deleted '{$plugin->name}' plugin." ); + $successes++; + } else { + $errors++; } } + if ( ! $this->chained_command ) { + Utils\report_batch_operation_results( 'plugin', 'delete', count( $args ), $successes, $errors ); + } } /** @@ -869,9 +925,9 @@ private function active_output( $name, $file, $network_wide, $action ) { if ( ( $action == "activate" ) ? $check : ! $check ) { if ( $network_wide ) - WP_CLI::success( "Plugin '{$name}' network {$action}d." ); + WP_CLI::log( "Plugin '{$name}' network {$action}d." ); else - WP_CLI::success( "Plugin '{$name}' {$action}d." ); + WP_CLI::log( "Plugin '{$name}' {$action}d." ); } else { WP_CLI::warning( "Could not {$action} the '{$name}' plugin." ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 6107f8ebc..6f7ef0041 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Manage themes. * @@ -659,7 +661,7 @@ function update( $args, $assoc_args ) { * * @subcommand is-installed */ - function is_installed( $args, $assoc_args = array() ) { + public function is_installed( $args, $assoc_args = array() ) { $theme = wp_get_theme( $args[0] ); if ( $theme->exists() ) { @@ -682,16 +684,19 @@ function is_installed( $args, $assoc_args = array() ) { * ## EXAMPLES * * $ wp theme delete twentytwelve - * Success: Deleted 'twentytwelve' theme. + * Deleted 'twentytwelve' theme. + * Success: Deleted 1 of 1 themes. * * @alias uninstall */ - function delete( $args ) { + public function delete( $args ) { + $successes = $errors = 0; foreach ( $this->fetcher->get_many( $args ) as $theme ) { $theme_slug = $theme->get_stylesheet(); if ( $this->is_active_theme( $theme ) ) { WP_CLI::warning( "Can't delete the currently active theme: $theme_slug" ); + $errors++; continue; } @@ -699,10 +704,15 @@ function delete( $args ) { if ( is_wp_error( $r ) ) { WP_CLI::warning( $r ); + $errors++; } else { - WP_CLI::success( "Deleted '$theme_slug' theme." ); + WP_CLI::log( "Deleted '$theme_slug' theme." ); + $successes++; } } + if ( ! $this->chained_command ) { + Utils\report_batch_operation_results( 'theme', 'delete', count( $args ), $successes, $errors ); + } } /** diff --git a/php/utils.php b/php/utils.php index ff3a09ed6..8bf939c2d 100644 --- a/php/utils.php +++ b/php/utils.php @@ -794,7 +794,7 @@ function report_batch_operation_results( $noun, $verb, $total, $successes, $fail if ( $successes ) { WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); } else { - $message = count( $total ) > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); + $message = $total > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); WP_CLI::success( "{$message} already {$past_tense_verb}." ); } } From 06432805ba80a22554d04865bd93bda9359690c6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 17:28:13 -0800 Subject: [PATCH 5090/5359] Use `Utils\report_batch_operation_results()` for plugin / theme updates --- features/theme.feature | 1 + php/WP_CLI/CommandWithUpgrade.php | 11 +---------- php/commands/plugin.php | 3 ++- php/commands/theme.php | 2 +- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 1c5d7d6fd..60d0c6c90 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -32,6 +32,7 @@ Feature: Manage WordPress themes Then STDERR should be: """ Warning: Can't delete the currently active theme: p2 + Error: No themes deleted. """ And STDOUT should be empty diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index e9becb998..4774e66ee 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -312,16 +312,6 @@ protected function update_many( $args, $assoc_args ) { $num_to_update = count( $items_to_update ); $num_updated = count( array_filter( $result ) ); - $line = "Updated $num_updated/$num_to_update {$this->item_type}s."; - - if ( $num_to_update == $num_updated ) { - \WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - \WP_CLI::warning( $line ); - } else { - \WP_CLI::error( $line ); - } - if ( $num_to_update > 0 ) { if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { foreach( $items_to_update as $item_to_update => $info ) { @@ -347,6 +337,7 @@ protected function update_many( $args, $assoc_args ) { \WP_CLI\Utils\format_items( $format, $status, array( 'name', 'old_version', 'new_version', 'status' ) ); } } + Utils\report_batch_operation_results( $this->item_type, 'update', $num_to_update, $num_updated, $num_to_update - $num_updated ); } protected function _list( $_, $assoc_args ) { diff --git a/php/commands/plugin.php b/php/commands/plugin.php index a8aa01147..d9031674f 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -517,6 +517,7 @@ protected function install_from_repo( $slug, $assoc_args ) { * Installing the plugin... * Removing the old version of the plugin... * Plugin updated successfully. + * Success: Updated 1 of 2 plugins. * * $ wp plugin update --all * Enabling Maintenance mode... @@ -531,13 +532,13 @@ protected function install_from_repo( $slug, $assoc_args ) { * Removing the old version of the plugin... * Plugin updated successfully. * Disabling Maintenance mode... - * Success: Updated 2/2 plugins. * +------------------------+-------------+-------------+---------+ * | name | old_version | new_version | status | * +------------------------+-------------+-------------+---------+ * | akismet | 3.1.3 | 3.1.11 | Updated | * | nginx-cache-controller | 3.1.1 | 3.2.0 | Updated | * +------------------------+-------------+-------------+---------+ + * Success: Updated 2 of 2 plugins. * * @alias upgrade */ diff --git a/php/commands/theme.php b/php/commands/theme.php index 6f7ef0041..3909f86cc 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -613,13 +613,13 @@ public function get( $args, $assoc_args ) { * Installing the latest version... * Removing the old version of the theme... * Theme updated successfully. - * Success: Updated 2/2 themes. * +---------------+-------------+-------------+---------+ * | name | old_version | new_version | status | * +---------------+-------------+-------------+---------+ * | twentyfifteen | 1.4 | 1.5 | Updated | * | twentysixteen | 1.1 | 1.2 | Updated | * +---------------+-------------+-------------+---------+ + * Success: Updated 2 of 2 themes. * * # Update all themes * $ wp theme update --all From 7ab66b0cfa81e8874c85d1561fb9d914e97ce0f9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 20 Nov 2016 18:44:57 -0800 Subject: [PATCH 5091/5359] Fix expected return code for test --- features/plugin-uninstall.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin-uninstall.feature b/features/plugin-uninstall.feature index 65646e8d0..5c6cbfd04 100644 --- a/features/plugin-uninstall.feature +++ b/features/plugin-uninstall.feature @@ -22,7 +22,7 @@ Feature: Uninstall a WordPress plugin Warning: The 'akismet' plugin is active. Error: No plugins uninstalled. """ - And the return code should be 0 + And the return code should be 1 Scenario: Attempting to uninstall a plugin that doesn't exist When I run `wp plugin uninstall edit-flow` From 8355a2457a3d823d844a2a1128bab634119654e1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 21 Nov 2016 05:58:12 -0800 Subject: [PATCH 5092/5359] Link to Shell Friends in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de3a9e7e1..982a4b439 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ $ wp transient delete --all Success: 34 transients deleted from the database. ``` -For a more complete introduction to using WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). +For a more complete introduction to using WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). Or, catch up with [shell friends](https://wp-cli.org/docs/shell-friends/) to learn about helpful command line utilities. Already feel comfortable with the basics? Jump into the [complete list of commands](https://wp-cli.org/commands/) for detailed information on managing themes and plugins, importing and exporting data, performing database search-replace operations and more. From f2006896b01126789a37cf24ebb0b68c70527647 Mon Sep 17 00:00:00 2001 From: Mark McEver <mark@fastmail.net> Date: Tue, 22 Nov 2016 16:04:25 -0600 Subject: [PATCH 5093/5359] Added support for the version of PHP that comes with Cygwin, in addition to the existing support for running standard PHP for Windows within Cygwin. Only in the latter case should we convert to the Windows path. --- bin/wp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bin/wp b/bin/wp index 25ea35d27..053e24227 100755 --- a/bin/wp +++ b/bin/wp @@ -22,14 +22,6 @@ while [ -h "$SELF_PATH" ]; do done cd "$ORIGDIR" -# Build the path to the root PHP file -SCRIPT_PATH="$(dirname "$SELF_PATH")/../php/boot-fs.php" - -case $(uname -a) in - CYGWIN*) - SCRIPT_PATH="$(cygpath -w -a -- "$SCRIPT_PATH")" ;; -esac - if [ ! -z "$WP_CLI_PHP" ] ; then # Use the WP_CLI_PHP environment variable if it is available. php="$WP_CLI_PHP" @@ -39,6 +31,13 @@ else php="`which php`" fi +# Build the path to the root PHP file +SCRIPT_PATH="$(dirname "$SELF_PATH")/../php/boot-fs.php" +case $("$php" -r "echo PHP_OS;") in + WINNT*) + SCRIPT_PATH="$(cygpath -w -a -- "$SCRIPT_PATH")" ;; +esac + # Pass in the path to php so that wp-cli knows which one # to use if it re-launches itself to run other commands. export WP_CLI_PHP_USED="$php" From a7e6608531bd0ae3dd06d05c8b017fa00e1b2e87 Mon Sep 17 00:00:00 2001 From: Joshua Priddle <jpriddle@me.com> Date: Tue, 22 Nov 2016 20:46:38 -0500 Subject: [PATCH 5094/5359] Use default php.ini when `wp server` is run without `--config=` --- php/commands/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/server.php b/php/commands/server.php index 2989ebfc5..af92cf2f2 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -63,7 +63,7 @@ function __invoke( $_, $assoc_args ) { 'host' => 'localhost', 'port' => 8080, 'docroot' => false, - 'config' => false, + 'config' => get_cfg_var( 'cfg_file_path' ) ); $assoc_args = array_merge( $defaults, $assoc_args ); From f45cec689c38411c6f05b7eef5bd8d6900d4db10 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 14:28:20 +0100 Subject: [PATCH 5095/5359] Initial support for cached language packs. --- php/WP_CLI/CommandWithTranslation.php | 7 ++- php/WP_CLI/LanguagePackUpgrader.php | 78 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 php/WP_CLI/LanguagePackUpgrader.php diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 6cfe90aea..8a9a24f1c 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -337,11 +337,10 @@ private function download_language_pack( $download ) { } $translation = (object) $translation; - require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - $skin = new \Automatic_Upgrader_Skin; - $upgrader = new \Language_Pack_Upgrader( $skin ); $translation->type = 'core'; - $result = $upgrader->upgrade( $translation, array( 'clear_update_cache' => false ) ); + + $upgrader = 'WP_CLI\\LanguagePackUpgrader'; + $result = Utils\get_upgrader( $upgrader )->upgrade( $translation, array( 'clear_update_cache' => false ) ); if ( is_wp_error( $result ) ) { return $result; diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php new file mode 100644 index 000000000..d981d5fd7 --- /dev/null +++ b/php/WP_CLI/LanguagePackUpgrader.php @@ -0,0 +1,78 @@ +<?php + +namespace WP_CLI; + +use WP_CLI; + +/** + * A Language Pack Upgrader class that caches the download, and uses cached if available + * + * @package wp-cli + */ +class LanguagePackUpgrader extends \Language_Pack_Upgrader { + + function download_package( $package ) { + + /** + * Filter whether to return the package. + * + * @since 3.7.0 + * + * @param bool $reply Whether to bail without returning the package. Default is false. + * @param string $package The package file name. + * @param object $this The WP_Upgrader instance. + */ + $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); + if ( false !== $reply ) + return $reply; + + if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote? + return $package; //must be a local file.. + + if ( empty( $package ) ) + return new WP_Error( 'no_package', $this->strings['no_package'] ); + + $language_update = $this->skin->language_update; + $type = $language_update->type; + $updated = strtotime( $language_update->updated ); + $version = $language_update->version; + $language = $language_update->language; + $ext = pathinfo( $package, PATHINFO_EXTENSION ); + + // todo: Slug for themes/plugins + + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.' . $ext; + + $cache = WP_CLI::get_cache(); + $cache_key = "translation/{$type}-{$version}-{$language}-{$updated}.{$ext}"; + $cache_file = $cache->has( $cache_key ); + + if ( $cache_file ) { + WP_CLI::log( "Using cached file '$cache_file'..." ); + copy( $cache_file, $temp ); + return $temp; + } else { + // We need to use a temporary file because piping from cURL to tar is flaky + // on MinGW (and probably in other environments too). + $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; + + $headers = array('Accept' => 'application/json'); + $options = array( + 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'filename' => $temp + ); + + $this->skin->feedback( 'downloading_package', $package ); + + /** @var \Requests_Response|null $req */ + $req = Utils\http_request( 'GET', $package, null, $headers, $options ); + if ( ! is_null( $req ) && $req->status_code !== 200 ) { + return new \WP_Error( 'download_failed', $this->strings['download_failed'] ); + } + $cache->import( $cache_key, $temp ); + return $temp; + } + + } + +} From 267c38852aa42656341d9aec5cd8dda2fc097e49 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 14:36:36 +0100 Subject: [PATCH 5096/5359] Add slug to the language pack cache key --- php/WP_CLI/LanguagePackUpgrader.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php index d981d5fd7..92881e6aa 100644 --- a/php/WP_CLI/LanguagePackUpgrader.php +++ b/php/WP_CLI/LanguagePackUpgrader.php @@ -34,17 +34,16 @@ function download_package( $package ) { $language_update = $this->skin->language_update; $type = $language_update->type; + $slug = $language_update->slug; $updated = strtotime( $language_update->updated ); $version = $language_update->version; $language = $language_update->language; $ext = pathinfo( $package, PATHINFO_EXTENSION ); - // todo: Slug for themes/plugins - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.' . $ext; $cache = WP_CLI::get_cache(); - $cache_key = "translation/{$type}-{$version}-{$language}-{$updated}.{$ext}"; + $cache_key = "translation/{$type}-{$slug}-{$version}-{$language}-{$updated}.{$ext}"; $cache_file = $cache->has( $cache_key ); if ( $cache_file ) { From 56418b0b6d2eed51a2c290018e983a4bf78d6d61 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 14:37:11 +0100 Subject: [PATCH 5097/5359] Use WP_CLI\LanguagePackUpgrader for updates --- php/WP_CLI/CommandWithTranslation.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 8a9a24f1c..13d324f94 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -221,17 +221,15 @@ public function update( $args, $assoc_args ) { return; } - require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - - $upgrader = new \Language_Pack_Upgrader( new \Automatic_Upgrader_Skin() ); - $results = array(); + $upgrader = 'WP_CLI\\LanguagePackUpgrader'; + $results = array(); // Update translations. foreach ( $updates as $update ) { \WP_CLI::line( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); \WP_CLI::line( "Downloading translation from {$update->package}..." ); - $result = $upgrader->upgrade( $update ); + $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); if ( $result ) { \WP_CLI::line( 'Translation updated successfully.' ); From 7c8a608582107d10f2959b0e8250c9f73b2c4844 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 14:39:03 +0100 Subject: [PATCH 5098/5359] In CoreUpgrader use global namespace for WP_Error. Prevents a fatal error if `$package` is empty. --- php/WP_CLI/CoreUpgrader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 9e18c1f64..d4f83d926 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -30,7 +30,7 @@ function download_package( $package ) { return $package; //must be a local file.. if ( empty( $package ) ) - return new WP_Error( 'no_package', $this->strings['no_package'] ); + return new \WP_Error( 'no_package', $this->strings['no_package'] ); $filename = pathinfo( $package, PATHINFO_FILENAME ); $ext = pathinfo( $package, PATHINFO_EXTENSION ); From 230b209a1d029e0548e87b7d7118d0942f956a1f Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 15:01:28 +0100 Subject: [PATCH 5099/5359] In `LanguagePackUpgrader` use global namespace for WP_Error. Prevents a fatal error if `$package` is empty. --- php/WP_CLI/LanguagePackUpgrader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php index 92881e6aa..18adc8670 100644 --- a/php/WP_CLI/LanguagePackUpgrader.php +++ b/php/WP_CLI/LanguagePackUpgrader.php @@ -30,7 +30,7 @@ function download_package( $package ) { return $package; //must be a local file.. if ( empty( $package ) ) - return new WP_Error( 'no_package', $this->strings['no_package'] ); + return new \WP_Error( 'no_package', $this->strings['no_package'] ); $language_update = $this->skin->language_update; $type = $language_update->type; From 9888a5a8bf5c6f2a616da1042f3cee817397b591 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 15:05:44 +0100 Subject: [PATCH 5100/5359] Avoid duplicated 'Downloading translation..' message --- php/WP_CLI/CommandWithTranslation.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 13d324f94..97a5a4222 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -227,7 +227,6 @@ public function update( $args, $assoc_args ) { // Update translations. foreach ( $updates as $update ) { \WP_CLI::line( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); - \WP_CLI::line( "Downloading translation from {$update->package}..." ); $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); From 324b18023af11a95131c8911739cd9b28db6acf3 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 15:09:56 +0100 Subject: [PATCH 5101/5359] Avoid duplicated translation update status messages --- php/WP_CLI/CommandWithTranslation.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 97a5a4222..f77f1d7b3 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -230,12 +230,6 @@ public function update( $args, $assoc_args ) { $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); - if ( $result ) { - \WP_CLI::line( 'Translation updated successfully.' ); - } else { - \WP_CLI::line( 'Translation update failed.' ); - } - $results[] = $result; } From e9ae83f3b3f40ef65f4406ec9af3bc4f70447b8c Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 15:21:38 +0100 Subject: [PATCH 5102/5359] Ensure the slug of a translation is always set --- php/WP_CLI/LanguagePackUpgrader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php index 18adc8670..95334a318 100644 --- a/php/WP_CLI/LanguagePackUpgrader.php +++ b/php/WP_CLI/LanguagePackUpgrader.php @@ -34,7 +34,7 @@ function download_package( $package ) { $language_update = $this->skin->language_update; $type = $language_update->type; - $slug = $language_update->slug; + $slug = empty( $language_update->slug ) ? 'default' : $language_update->slug; $updated = strtotime( $language_update->updated ); $version = $language_update->version; $language = $language_update->language; From 7f9ff01f5bae0e4a3100d207f23f321a30c1e9d4 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 15:29:44 +0100 Subject: [PATCH 5103/5359] Update tests for cached language packs --- features/core-language.feature | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/core-language.feature b/features/core-language.feature index e975c921c..1bf1211de 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -3,6 +3,7 @@ Feature: Manage translation files for a WordPress install @require-wp-4.0 Scenario: Core translation CRUD Given a WP install + And an empty cache When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: @@ -16,6 +17,8 @@ Feature: Manage translation files for a WordPress install And I run `wp core language install en_AU` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist + And the {SUITE_CACHE_DIR}/translation/core-default-([\d\.]+)-en_AU-([\d]+).zip file should exist + And the {SUITE_CACHE_DIR}/translation/core-default-([\d\.]+)-en_GB-([\d]+).zip file should exist And STDOUT should be: """ Success: Language installed. From b692925d8328cef8f34108c57951d639661381bd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Nov 2016 06:29:56 -0800 Subject: [PATCH 5104/5359] Deprecate `wp term url` in favor of `wp term list --field=url` --- features/term.feature | 7 +++++++ php/WP_CLI/Runner.php | 15 +++++++++++-- php/commands/term.php | 49 +++++++++++++++++-------------------------- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/features/term.feature b/features/term.feature index 20a5bc55d..a571564ef 100644 --- a/features/term.feature +++ b/features/term.feature @@ -138,6 +138,13 @@ Feature: Manage WordPress terms http://example.com/?cat=3 """ + When I run `wp term url category {SECOND_TERM_ID} {TERM_ID}` + Then STDOUT should be: + """ + http://example.com/?cat=3 + http://example.com/?cat=2 + """ + Scenario: Make sure WordPress receives the slashed data it expects When I run `wp term create category 'My\Term' --description='My\Term\Description' --porcelain` Then save STDOUT as {TERM_ID} diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 0700d01ee..8d496fce7 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -535,8 +535,8 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } - // (post|site) url --> (post|site) list --*__in --field=url - if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'site' ) ) && 'url' === $args[1] ) { + // (post|site|term) url --> (post|site) list --*__in --field=url + if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'site', 'term' ) ) && 'url' === $args[1] ) { switch ( $args[0] ) { case 'post': $post_ids = array_slice( $args, 2 ); @@ -552,6 +552,17 @@ private static function back_compat_conversions( $args, $assoc_args ) { $assoc_args['site__in'] = implode( ',', $site_ids ); $assoc_args['field'] = 'url'; break; + case 'term': + $taxonomy = ''; + if ( isset( $args[2] ) ) { + $taxonomy = $args[2]; + } + $term_ids = array_slice( $args, 3 ); + $args = array( 'term', 'list', $taxonomy ); + $assoc_args['include'] = implode( ',', $term_ids ); + $assoc_args['orderby'] = 'include'; + $assoc_args['field'] = 'url'; + break; } } diff --git a/php/commands/term.php b/php/commands/term.php index ffee4e0cf..0cf6a34fc 100644 --- a/php/commands/term.php +++ b/php/commands/term.php @@ -20,7 +20,7 @@ * Success: Term updated. * * # Get the term's URL. - * $ wp term url post_tag 123 + * $ wp term list post_tag --include=123 --field=url * http://example.com/tag/tips-and-tricks * * # Delete post category @@ -88,7 +88,9 @@ class Term_Command extends WP_CLI_Command { * * parent * * count * - * There are no optionally available fields. + * These fields are optionally available: + * + * * url * * ## EXAMPLES * @@ -130,6 +132,20 @@ public function list_( $args, $assoc_args ) { if ( ! empty( $assoc_args['term_id'] ) ) { $term = get_term_by( 'id', $assoc_args['term_id'], $args[0] ); $terms = array( $term ); + } else if ( ! empty( $assoc_args['include'] ) + && ! empty( $assoc_args['orderby'] ) + && 'include' === $assoc_args['orderby'] + && Utils\wp_version_compare( '4.7', '<' ) ) { + $terms = array(); + $term_ids = explode( ',', $assoc_args['include'] ); + foreach( $term_ids as $term_id ) { + $term = get_term_by( 'id', $term_id, $args[0] ); + if ( $term && ! is_wp_error( $term ) ) { + $terms[] = $term; + } else { + WP_CLI::warning( sprintf( "Invalid term %s.", $term_id ) ); + } + } } else { $terms = get_terms( $args, $assoc_args ); } @@ -137,6 +153,7 @@ public function list_( $args, $assoc_args ) { $terms = array_map( function( $term ){ $term->count = (int)$term->count; $term->parent = (int)$term->parent; + $term->url = get_term_link( $term ); return $term; }, $terms ); @@ -497,34 +514,6 @@ public function generate( $args, $assoc_args ) { } } - /** - * Get a term's URL. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy of the term(s) to get. - * - * <term-id>... - * : One or more IDs of terms to get the URL. - * - * ## EXAMPLES - * - * $ wp term url post_tag 123 - * http://example.com/tag/tips-and-tricks - */ - public function url( $args ) { - $term_ids = array_slice( $args, 1 ); - foreach ( $term_ids as $term_id ) { - $term_link = get_term_link( (int)$term_id, $args[0] ); - if ( $term_link && ! is_wp_error( $term_link ) ) { - WP_CLI::line( $term_link ); - } else { - WP_CLI::warning( sprintf( "Invalid term %s.", $term_id ) ); - } - } - } - /** * Recalculate number of posts assigned to each term. * From e6c06e6e84b160321b414052047bf6dcc54c0695 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Nov 2016 06:30:19 -0800 Subject: [PATCH 5105/5359] Add support for `wp user list --field=url` --- features/user.feature | 11 +++++++++++ php/commands/user.php | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/features/user.feature b/features/user.feature index 750da9e38..be744c1b8 100644 --- a/features/user.feature +++ b/features/user.feature @@ -295,3 +295,14 @@ Feature: Manage WordPress users When I run `wp user create testuser3 testuser3@example.com --send-email` Then an email should be sent + + Scenario: List URLs of one or more users + Given a WP install + And I run `wp user create bob bob@gmail.com --role=contributor` + + When I run `wp user list --include=1,2 --field=url` + Then STDOUT should be: + """ + http://example.com/?author=1 + http://example.com/?author=2 + """ diff --git a/php/commands/user.php b/php/commands/user.php index 536baf9c0..dd6a4d115 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -101,6 +101,7 @@ public function __construct() { * * cap_key * * allcaps * * filter + * * url * * ## EXAMPLES * @@ -155,7 +156,7 @@ public function list_( $args, $assoc_args ) { return $user; $user->roles = implode( ',', $user->roles ); - + $user->url = get_author_posts_url( $user->ID, $user->user_nicename ); return $user; } ); From 3fcc837369ba68fc27ca56f9a5303ae8322265d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Nov 2016 06:56:32 -0800 Subject: [PATCH 5106/5359] Deprecate `wp comment url` in favor of `wp comment list --field=url` --- features/comment.feature | 18 ++++++++++++++ php/WP_CLI/Runner.php | 11 +++++++-- php/commands/comment.php | 52 ++++++++++++++++++++++++---------------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index b0058297e..484c6e791 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -103,6 +103,24 @@ Feature: Manage WordPress comments #comment-1 """ + Scenario: List the URLs of comments + When I run `wp comment create --comment_post_ID=1 --porcelain` + Then save STDOUT as {COMMENT_ID} + + When I run `wp comment url 1 {COMMENT_ID}` + Then STDOUT should be: + """ + http://example.com/?p=1#comment-1 + http://example.com/?p=1#comment-{COMMENT_ID} + """ + + When I run `wp comment url {COMMENT_ID} 1` + Then STDOUT should be: + """ + http://example.com/?p=1#comment-{COMMENT_ID} + http://example.com/?p=1#comment-1 + """ + Scenario: Count comments When I run `wp comment count 1` Then STDOUT should contain: diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8d496fce7..2d404e12b 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -535,8 +535,8 @@ private static function back_compat_conversions( $args, $assoc_args ) { } } - // (post|site|term) url --> (post|site) list --*__in --field=url - if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'site', 'term' ) ) && 'url' === $args[1] ) { + // (post|comment|site|term) url --> (post|comment|site|term) list --*__in --field=url + if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'comment', 'site', 'term' ) ) && 'url' === $args[1] ) { switch ( $args[0] ) { case 'post': $post_ids = array_slice( $args, 2 ); @@ -546,6 +546,13 @@ private static function back_compat_conversions( $args, $assoc_args ) { $assoc_args['orderby'] = 'post__in'; $assoc_args['field'] = 'url'; break; + case 'comment': + $comment_ids = array_slice( $args, 2 ); + $args = array( 'comment', 'list' ); + $assoc_args['comment__in'] = implode( ',', $comment_ids ); + $assoc_args['orderby'] = 'comment__in'; + $assoc_args['field'] = 'url'; + break; case 'site': $site_ids = array_slice( $args, 2 ); $args = array( 'site', 'list' ); diff --git a/php/commands/comment.php b/php/commands/comment.php index 7a5e029be..c68a61cbd 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -1,5 +1,7 @@ <?php +use WP_CLI\Utils; + /** * Manage comments. * @@ -284,6 +286,7 @@ public function get( $args, $assoc_args ) { * * comment_type * * comment_parent * * user_id + * * url * * ## EXAMPLES * @@ -316,14 +319,39 @@ public function get( $args, $assoc_args ) { public function list_( $_, $assoc_args ) { $formatter = $this->get_formatter( $assoc_args ); - if ( 'ids' == $formatter->format ) + if ( 'ids' == $formatter->format ) { $assoc_args['fields'] = 'comment_ID'; + } - $query = new WP_Comment_Query(); - $comments = $query->query( $assoc_args ); + if ( ! empty( $assoc_args['comment__in'] ) ) { + $assoc_args['comment__in'] = explode( ',', $assoc_args['comment__in'] ); + } + + if ( ! empty( $assoc_args['comment__in'] ) + && ! empty( $assoc_args['orderby'] ) + && 'comment__in' === $assoc_args['orderby'] + && Utils\wp_version_compare( '4.4', '<' ) ) { + $comments = array(); + foreach( $assoc_args['comment__in'] as $comment_id ) { + $comment = get_comment( $comment_id ); + if ( $comment ) { + $comments[] = $comment; + } else { + WP_CLI::warning( sprintf( "Invalid comment %s.", $comment_id ) ); + } + } + } else { + $query = new WP_Comment_Query(); + $comments = $query->query( $assoc_args ); + } if ( 'ids' == $formatter->format ) { $comments = wp_list_pluck( $comments, 'comment_ID' ); + } else { + $comments = array_map( function( $comment ){ + $comment->url = get_comment_link( $comment->comment_ID ); + return $comment; + }, $comments ); } $formatter->display_items( $comments ); @@ -632,24 +660,6 @@ public function exists( $args ) { WP_CLI::success( "Comment with ID $args[0] exists." ); } } - - /** - * Get a comment's URL. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of comments to get the URL. - * - * ## EXAMPLES - * - * # Get comment URL. - * $ wp comment url 123 - * http://example.com/about/page-with-comments/#comment-123 - */ - public function url( $args ) { - parent::_url( $args, 'get_comment_link' ); - } } WP_CLI::add_command( 'comment', 'Comment_Command' ); From 3f2fe22f219102074f154b1206622a67df91ef5d Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 16:00:21 +0100 Subject: [PATCH 5107/5359] Change test case for cached language packs. `file should exist` doesn't support regex. --- features/core-language.feature | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/features/core-language.feature b/features/core-language.feature index 1bf1211de..7dfe5c043 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -17,12 +17,19 @@ Feature: Manage translation files for a WordPress install And I run `wp core language install en_AU` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist - And the {SUITE_CACHE_DIR}/translation/core-default-([\d\.]+)-en_AU-([\d]+).zip file should exist - And the {SUITE_CACHE_DIR}/translation/core-default-([\d\.]+)-en_GB-([\d]+).zip file should exist And STDOUT should be: """ Success: Language installed. """ + When I run `ls {SUITE_CACHE_DIR}/translation | grep core-default-` + Then STDOUT should contain: + """ + en_AU + """ + And STDOUT should contain: + """ + en_GB + """ When I try `wp core language install en_GB` Then STDERR should be: From 802e42a38741ef068aab01891c17c97307df00bd Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 16:08:36 +0100 Subject: [PATCH 5108/5359] Change STDOUT tests for language installs from "be" to "contain". This accommodates the now more verbose output of the commands due to the change of the upgrader skin. --- features/core-language.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-language.feature b/features/core-language.feature index 7dfe5c043..2e3bd97e2 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -17,7 +17,7 @@ Feature: Manage translation files for a WordPress install And I run `wp core language install en_AU` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist - And STDOUT should be: + And STDOUT should contain: """ Success: Language installed. """ @@ -120,7 +120,7 @@ Feature: Manage translation files for a WordPress install When I run `wp core language install --activate en_GB` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist - And STDOUT should be: + And STDOUT should contain: """ Success: Language installed. Success: Language activated. From 67d245acdcf96b9fad9e13464b647ab0d13d1250 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Wed, 23 Nov 2016 21:29:04 +0100 Subject: [PATCH 5109/5359] Code styling for WP_CLI\CoreUpgrader and WP_CLI\LanguagePackUpgrader. --- php/WP_CLI/CoreUpgrader.php | 39 ++++++++++++++++++----------- php/WP_CLI/LanguagePackUpgrader.php | 37 +++++++++++++++++---------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index d4f83d926..2ae9222e9 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -11,7 +11,16 @@ */ class CoreUpgrader extends \Core_Upgrader { - function download_package( $package ) { + /** + * Caches the download, and uses cached if available. + * + * @access public + * + * @param string $package The URI of the package. If this is the full path to an + * existing local file, it will be returned untouched. + * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. + */ + public function download_package( $package ) { /** * Filter whether to return the package. @@ -23,19 +32,23 @@ function download_package( $package ) { * @param object $this The WP_Upgrader instance. */ $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); - if ( false !== $reply ) + if ( false !== $reply ) { return $reply; + } - if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote? - return $package; //must be a local file.. + // Check if package is a local or remote file. Bail if it's local. + if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { + return $package; + } - if ( empty( $package ) ) + if ( empty( $package ) ) { return new \WP_Error( 'no_package', $this->strings['no_package'] ); + } $filename = pathinfo( $package, PATHINFO_FILENAME ); $ext = pathinfo( $package, PATHINFO_EXTENSION ); - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.' . $ext; + $temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.' . $ext; $cache = WP_CLI::get_cache(); $update = $GLOBALS['wp_cli_update_obj']; @@ -47,13 +60,13 @@ function download_package( $package ) { copy( $cache_file, $temp ); return $temp; } else { - // We need to use a temporary file because piping from cURL to tar is flaky - // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; - - $headers = array('Accept' => 'application/json'); + /* + * Download to a temporary file because piping from cURL to tar is flaky + * on MinGW (and probably in other environments too). + */ + $headers = array( 'Accept' => 'application/json' ); $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'timeout' => 600, // 10 minutes ought to be enough for everybody. 'filename' => $temp ); @@ -67,7 +80,5 @@ function download_package( $package ) { $cache->import( $cache_key, $temp ); return $temp; } - } - } diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php index 95334a318..f796c4e41 100644 --- a/php/WP_CLI/LanguagePackUpgrader.php +++ b/php/WP_CLI/LanguagePackUpgrader.php @@ -11,7 +11,16 @@ */ class LanguagePackUpgrader extends \Language_Pack_Upgrader { - function download_package( $package ) { + /** + * Caches the download, and uses cached if available. + * + * @access public + * + * @param string $package The URI of the package. If this is the full path to an + * existing local file, it will be returned untouched. + * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. + */ + public function download_package( $package ) { /** * Filter whether to return the package. @@ -23,14 +32,18 @@ function download_package( $package ) { * @param object $this The WP_Upgrader instance. */ $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); - if ( false !== $reply ) + if ( false !== $reply ) { return $reply; + } - if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote? - return $package; //must be a local file.. + // Check if package is a local or remote file. Bail if it's local. + if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { + return $package; + } - if ( empty( $package ) ) + if ( empty( $package ) ) { return new \WP_Error( 'no_package', $this->strings['no_package'] ); + } $language_update = $this->skin->language_update; $type = $language_update->type; @@ -51,13 +64,13 @@ function download_package( $package ) { copy( $cache_file, $temp ); return $temp; } else { - // We need to use a temporary file because piping from cURL to tar is flaky - // on MinGW (and probably in other environments too). - $temp = sys_get_temp_dir() . '/' . uniqid('wp_') . '.' . $ext; - - $headers = array('Accept' => 'application/json'); + /* + * Download to a temporary file because piping from cURL to tar is flaky + * on MinGW (and probably in other environments too). + */ + $headers = array( 'Accept' => 'application/json' ); $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody + 'timeout' => 600, // 10 minutes ought to be enough for everybody. 'filename' => $temp ); @@ -71,7 +84,5 @@ function download_package( $package ) { $cache->import( $cache_key, $temp ); return $temp; } - } - } From 277a50dce26990b0a8e59ce50402fbd5602562ae Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 23 Nov 2016 17:06:48 -0800 Subject: [PATCH 5110/5359] Ignore `circle.yml`, `.gitlab-ci.yml` and `behat.yml` in `.distignore` --- templates/plugin-distignore.mustache | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache index 9e304aa93..276de2d19 100644 --- a/templates/plugin-distignore.mustache +++ b/templates/plugin-distignore.mustache @@ -3,10 +3,13 @@ .editorconfig .git .gitignore +.gitlab-ci.yml .travis.yml .DS_Store Thumbs.db +behat.yml bin +circle.yml composer.json composer.lock Gruntfile.js From ed52007653c8679c53c8f90fb594c0a97be3e254 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 24 Nov 2016 16:33:34 +0545 Subject: [PATCH 5111/5359] Improve doc for cap commands --- php/commands/cap.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/php/commands/cap.php b/php/commands/cap.php index 0663f248e..c00001320 100644 --- a/php/commands/cap.php +++ b/php/commands/cap.php @@ -5,15 +5,15 @@ * * ## EXAMPLES * - * # Add 'spectate' capability to 'author' role + * # Add 'spectate' capability to 'author' role. * $ wp cap add 'author' 'spectate' - * Success: Added 1 capabilities to 'author' role. + * Success: Added 1 capability to 'author' role. * - * # Add all caps from 'editor' role to 'author' role + * # Add all caps from 'editor' role to 'author' role. * $ wp cap list 'editor' | xargs wp cap add 'author' * Success: Added 24 capabilities to 'author' role. * - * # Remove all caps from 'editor' role that also appear in 'author' role + * # Remove all caps from 'editor' role that also appear in 'author' role. * $ wp cap list 'author' | xargs wp cap remove 'editor' * Success: Removed 34 capabilities from 'editor' role. */ @@ -46,7 +46,7 @@ class Capabilities_Command extends WP_CLI_Command { * * ## EXAMPLES * - * # Display alphabetical list of Contributor capabilities + * # Display alphabetical list of Contributor capabilities. * $ wp cap list 'contributor' | sort * delete_posts * edit_posts @@ -91,9 +91,9 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * # Add 'spectate' capability to 'author' role + * # Add 'spectate' capability to 'author' role. * $ wp cap add author spectate - * Success: Added 1 capabilities to 'author' role. + * Success: Added 1 capability to 'author' role. */ public function add( $args ) { self::persistence_check(); @@ -113,7 +113,8 @@ public function add( $args ) { $count++; } - WP_CLI::success( sprintf( "Added %d capabilities to '%s' role." , $count, $role ) ); + $message = ( 1 === $count ) ? "Added %d capability to '%s' role." : "Added %d capabilities to '%s' role."; + WP_CLI::success( sprintf( $message, $count, $role ) ); } /** @@ -129,9 +130,9 @@ public function add( $args ) { * * ## EXAMPLES * - * # Remove 'spectate' capability from 'author' role + * # Remove 'spectate' capability from 'author' role. * $ wp cap remove author spectate - * Success: Removed 1 capabilities from 'author' role. + * Success: Removed 1 capability from 'author' role. */ public function remove( $args ) { self::persistence_check(); @@ -151,7 +152,8 @@ public function remove( $args ) { $count++; } - WP_CLI::success( sprintf( "Removed %d capabilities from '%s' role." , $count, $role ) ); + $message = ( 1 === $count ) ? "Removed %d capability from '%s' role." : "Removed %d capabilities from '%s' role."; + WP_CLI::success( sprintf( $message, $count, $role ) ); } private static function get_role( $role ) { From 6aa58bace4ffb260f4d74f8611d36f1ed3696c8b Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Thu, 24 Nov 2016 16:58:22 +0545 Subject: [PATCH 5112/5359] Improve role reset message --- features/roles.feature | 6 +++--- php/commands/role.php | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/features/roles.feature b/features/roles.feature index 03c25ef69..c288631ff 100644 --- a/features/roles.feature +++ b/features/roles.feature @@ -28,7 +28,7 @@ Feature: Manage WordPress roles And I run `wp role reset author` Then STDOUT should be: """ - Restored 1 capabilities to and removed 0 capabilities from 'author' role. + Restored 1 capability to and removed 0 capabilities from 'author' role. Success: Role reset. """ @@ -44,7 +44,7 @@ Feature: Manage WordPress roles And I run `wp role reset author editor` Then STDOUT should be: """ - Restored 1 capabilities to and removed 0 capabilities from 'author' role. + Restored 1 capability to and removed 0 capabilities from 'author' role. No changes necessary for 'editor' role. Success: 1 of 2 roles reset. """ @@ -96,7 +96,7 @@ Feature: Manage WordPress roles Then STDOUT should be: """ Custom role 'custom-role' not affected. - Restored 1 capabilities to and removed 0 capabilities from 'author' role. + Restored 1 capability to and removed 0 capabilities from 'author' role. Success: Role reset. """ diff --git a/php/commands/role.php b/php/commands/role.php index ea27f2290..7f352936b 100644 --- a/php/commands/role.php +++ b/php/commands/role.php @@ -341,7 +341,10 @@ public function reset( $args, $assoc_args ) { $removed_cap = array_diff_key( $before[ $role_key ]->capabilities, $after[ $role_key ]->capabilities ); $restored_cap_count = count( $restored_cap ); $removed_cap_count = count( $removed_cap ); - WP_CLI::log( "Restored {$restored_cap_count} capabilities to and removed {$removed_cap_count} capabilities from '{$role_key}' role." ); + $restored_text = ( 1 === $restored_cap_count ) ? '%d capability' : '%d capabilities'; + $removed_text = ( 1 === $removed_cap_count ) ? '%d capability' : '%d capabilities'; + $message = "Restored ". $restored_text . " to and removed " . $removed_text . " from '%s' role."; + WP_CLI::log( sprintf( $message, $restored_cap_count, $removed_cap_count, $role_key ) ); } else { WP_CLI::log( "No changes necessary for '{$role_key}' role." ); } From 2885d1226669e3568241d9ff0d6fb7b0017059d9 Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Thu, 24 Nov 2016 12:16:19 +0100 Subject: [PATCH 5113/5359] Use `html_entity_decode()` for decoding entities in upgrader strings. --- php/WP_CLI/UpgraderSkin.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php index 7af55981c..da6eb4c3b 100644 --- a/php/WP_CLI/UpgraderSkin.php +++ b/php/WP_CLI/UpgraderSkin.php @@ -42,6 +42,7 @@ function feedback( $string ) { return; $string = str_replace( '…', '...', strip_tags( $string ) ); + $string = html_entity_decode( $string, ENT_QUOTES, get_bloginfo( 'charset' ) ); \WP_CLI::log( $string ); } From 282c5c2530aa4271c19502b3a56fa1845b8c5a64 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 06:24:26 -0800 Subject: [PATCH 5114/5359] Add WP-CLI version to package manager's `composer.json` This one little trick lets Composer handle WP-CLI version constraints defined in a package's `composer.json` --- features/package-install.feature | 76 ++++++++++++++++++++++++++++++++ php/commands/package.php | 1 + 2 files changed, 77 insertions(+) diff --git a/features/package-install.feature b/features/package-install.feature index 5f23e507d..225b6a85d 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -405,3 +405,79 @@ Feature: Install WP-CLI packages """ wp-cli/community-command """ + + Scenario: Install a package requiring a WP-CLI version that doesn't match + Given an empty directory + And a new Phar with version "0.23.0" + And a path-command/command.php file: + """ + <?php + WP_CLI::add_command( 'community-command', function(){ + WP_CLI::success( "success!" ); + }, array( 'when' => 'before_wp_load' ) ); + """ + And a path-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "autoload": { + "files": [ "command.php" ] + }, + "require": { + "wp-cli/wp-cli": ">=0.24.0" + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + + When I try `{PHAR_PATH} package install path-command` + Then STDOUT should contain: + """ + wp-cli/community-command dev-master requires wp-cli/wp-cli >=0.24.0 + """ + And STDERR should contain: + """ + Error: Package installation failed + """ + And the return code should be 1 + + Scenario: Install a package requiring a WP-CLI version that does match + Given an empty directory + And a new Phar with version "0.23.0" + And a path-command/command.php file: + """ + <?php + WP_CLI::add_command( 'community-command', function(){ + WP_CLI::success( "success!" ); + }, array( 'when' => 'before_wp_load' ) ); + """ + And a path-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "autoload": { + "files": [ "command.php" ] + }, + "require": { + "wp-cli/wp-cli": ">=0.22.0" + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + + When I run `{PHAR_PATH} package install path-command` + Then STDOUT should contain: + """ + Success: Package installed. + """ + And the return code should be 0 diff --git a/php/commands/package.php b/php/commands/package.php index 7f0c85e6a..a07ea4f7c 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -249,6 +249,7 @@ public function install( $args, $assoc_args ) { $composer_backup = file_get_contents( $composer_json_obj->getPath() ); $json_manipulator = new JsonManipulator( $composer_backup ); $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); + $json_manipulator->addMainKey( 'version', WP_CLI_VERSION ); $json_manipulator->addLink( 'require', $package_name, $version ); $json_manipulator->addConfigSetting( 'secure-http', true ); From 6822ef4fd4cd9bdfc9e021427d4aefed86ed40c9 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Thu, 24 Nov 2016 21:32:14 +0545 Subject: [PATCH 5115/5359] Add tests for cap commands --- features/cap.feature | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 features/cap.feature diff --git a/features/cap.feature b/features/cap.feature new file mode 100644 index 000000000..4c5a1f87b --- /dev/null +++ b/features/cap.feature @@ -0,0 +1,73 @@ +Feature: Manage Cap + + Background: + Given a WP install + + Scenario: CRUD for cap + When I run `wp cap list contributor | sort` + Then STDOUT should be: + """ + delete_posts + edit_posts + level_0 + level_1 + read + """ + + When I run `wp cap add contributor spectate` + Then STDOUT should contain: + """ + Success: Added 1 capability to 'contributor' role. + """ + + When I run `wp cap add contributor behold observe` + Then STDOUT should contain: + """ + Success: Added 2 capabilities to 'contributor' role. + """ + + When I run `wp cap list contributor` + Then STDOUT should contain: + """ + spectate + """ + And STDOUT should contain: + """ + behold + """ + And STDOUT should contain: + """ + observe + """ + + When I run `wp cap remove contributor spectate` + Then STDOUT should contain: + """ + Success: Removed 1 capability from 'contributor' role. + """ + + When I run `wp cap remove contributor behold observe` + Then STDOUT should contain: + """ + Success: Removed 2 capabilities from 'contributor' role. + """ + + When I run `wp cap list contributor` + Then STDOUT should not contain: + """ + spectate + """ + And STDOUT should not contain: + """ + behold + """ + And STDOUT should not contain: + """ + observe + """ + + When I try `wp cap add role-not-available spectate` + Then STDERR should be: + """ + Error: 'role-not-available' role not found. + """ From 78e46d5b151eacbf4039fddb7f9ab7641f62d0d9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 08:28:28 -0800 Subject: [PATCH 5116/5359] First pass at `WP_CLI::runcommand()` --- features/runcommand.feature | 64 +++++++++++++++++++++++++++++++++++++ php/class-wp-cli.php | 45 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 features/runcommand.feature diff --git a/features/runcommand.feature b/features/runcommand.feature new file mode 100644 index 000000000..68a797522 --- /dev/null +++ b/features/runcommand.feature @@ -0,0 +1,64 @@ +Feature: Run a WP-CLI command + + Background: + Given a WP install + And a command.php file: + """ + <?php + /** + * Run a WP-CLI command with WP_CLI::runcommand(); + * + * ## OPTIONS + * + * <command> + * : Command to run, quoted. + * + * [--launch] + * : Launch a new process for the command. + * + * [--capture] + * : Capture and return output. + */ + WP_CLI::add_command( 'run', function( $args, $assoc_args ){ + $ret = WP_CLI::runcommand( $args[0], $assoc_args ); + WP_CLI::log( 'returned: ' . var_export( $ret, true ) ); + }); + """ + And a wp-cli.yml file: + """ + user: admin + require: + - command.php + """ + + Scenario: Run a WP-CLI command in the same process, rendering output + When I run `wp run 'option get home' --no-launch` + Then STDOUT should be: + """ + http://example.com + returned: NULL + """ + And the return code should be 0 + + When I run `wp --no-launch run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + Then STDOUT should be: + """ + admin + returned: NULL + """ + And the return code should be 0 + + Scenario: Run a WP-CLI command in the same process, capturing output + When I run `wp run --no-launch --capture 'option get home'` + Then STDOUT should be: + """ + returned: 'http://example.com' + """ + And the return code should be 0 + + When I run `wp --no-launch --capture run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + Then STDOUT should be: + """ + returned: 'admin' + """ + And the return code should be 0 diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index ed5c36459..fc6355b98 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -908,6 +908,51 @@ public static function get_config( $key = null ) { return self::get_runner()->config[ $key ]; } + /** + * Run a WP-CLI command. + * + * ``` + * $plugins = WP_CLI::run_command( 'plugin list' ); + * ``` + * + * @access public + * @category Execution + * + * @param string $command WP-CLI command to run, including arguments. + * @param array $options Configuration options for command execution. + * @return mixed + */ + public static function runcommand( $command, $options = array() ) { + $defaults = array( + 'launch' => true, // Launch a new process, or reuse the existing. + 'capture' => false, // Capture STDOUT, or render on the fly + ); + $options = array_merge( $defaults, $options ); + $retval = null; + if ( empty( $options['launch'] ) ) { + $configurator = self::get_configurator(); + preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $command, $matches ); + $argv = isset( $matches[0] ) ? $matches[0] : array(); + $argv = array_map( function( $arg ){ + foreach( array( '"', "'" ) as $char ) { + if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { + $arg = substr( $arg, 1, -1 ); + } + } + return $arg; + }, $argv ); + list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); + if ( ! empty( $options['capture'] ) ) { + ob_start(); + } + self::get_runner()->run_command( $args, $assoc_args ); + if ( ! empty( $options['capture'] ) ) { + $retval = trim( ob_get_clean() ); + } + } + return $retval; + } + /** * Run a given command within the current process using the same global * parameters. From 07a58fc2235a6f13264c3c0668cd66fe99d2595d Mon Sep 17 00:00:00 2001 From: Ned Zimmerman <ned@bight.ca> Date: Thu, 24 Nov 2016 14:27:37 -0400 Subject: [PATCH 5117/5359] Fix typo in \WP_CLI\CommandWithMeta docblocks. --- php/WP_CLI/CommandWithMeta.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php index 05746d005..2d8a8c5c0 100644 --- a/php/WP_CLI/CommandWithMeta.php +++ b/php/WP_CLI/CommandWithMeta.php @@ -166,7 +166,7 @@ public function delete( $args, $assoc_args ) { * : The name of the meta field to create. * * [<value>] - * : The value of the meta field. If ommited, the value is read from STDIN. + * : The value of the meta field. If omitted, the value is read from STDIN. * * [--format=<format>] * : The serialization format for the value. @@ -207,7 +207,7 @@ public function add( $args, $assoc_args ) { * : The name of the meta field to update. * * [<value>] - * : The new value. If ommited, the value is read from STDIN. + * : The new value. If omitted, the value is read from STDIN. * * [--format=<format>] * : The serialization format for the value. From 54de745282b7498e9cebe717055b190fb2943c5c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 10:49:20 -0800 Subject: [PATCH 5118/5359] Ensure Git short hash is stripped from Composer version --- features/package-install.feature | 54 ++++++++++++++++++++++++++++++++ php/commands/package.php | 11 ++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/features/package-install.feature b/features/package-install.feature index 225b6a85d..c7e35445f 100644 --- a/features/package-install.feature +++ b/features/package-install.feature @@ -446,6 +446,12 @@ Feature: Install WP-CLI packages """ And the return code should be 1 + When I run `cat {PACKAGE_PATH}composer.json` + Then STDOUT should contain: + """ + "version": "0.23.0", + """ + Scenario: Install a package requiring a WP-CLI version that does match Given an empty directory And a new Phar with version "0.23.0" @@ -481,3 +487,51 @@ Feature: Install WP-CLI packages Success: Package installed. """ And the return code should be 0 + + When I run `cat {PACKAGE_PATH}composer.json` + Then STDOUT should contain: + """ + "version": "0.23.0", + """ + + Scenario: Install a package requiring a WP-CLI alpha version that does match + Given an empty directory + And a new Phar with version "0.23.0-alpha-90ecad6" + And a path-command/command.php file: + """ + <?php + WP_CLI::add_command( 'community-command', function(){ + WP_CLI::success( "success!" ); + }, array( 'when' => 'before_wp_load' ) ); + """ + And a path-command/composer.json file: + """ + { + "name": "wp-cli/community-command", + "description": "A demo community command.", + "license": "MIT", + "minimum-stability": "dev", + "autoload": { + "files": [ "command.php" ] + }, + "require": { + "wp-cli/wp-cli": ">=0.22.0" + }, + "require-dev": { + "behat/behat": "~2.5" + } + } + """ + + When I run `{PHAR_PATH} package install path-command` + Then STDOUT should contain: + """ + Success: Package installed. + """ + And the return code should be 0 + + When I run `cat {PACKAGE_PATH}composer.json` + Then STDOUT should contain: + """ + "version": "0.23.0-alpha", + """ diff --git a/php/commands/package.php b/php/commands/package.php index a07ea4f7c..89a579978 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -249,7 +249,7 @@ public function install( $args, $assoc_args ) { $composer_backup = file_get_contents( $composer_json_obj->getPath() ); $json_manipulator = new JsonManipulator( $composer_backup ); $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); - $json_manipulator->addMainKey( 'version', WP_CLI_VERSION ); + $json_manipulator->addMainKey( 'version', self::get_wp_cli_version_composer() ); $json_manipulator->addLink( 'require', $package_name, $version ); $json_manipulator->addConfigSetting( 'secure-http', true ); @@ -717,6 +717,14 @@ private function get_composer_json_path() { return $composer_path; } + /** + * Get the WP-CLI version for composer.json + */ + private static function get_wp_cli_version_composer() { + preg_match( '#^[0-9\.]+(-(alpha|beta)[^-]{0,})?#', WP_CLI_VERSION, $matches ); + return isset( $matches[0] ) ? $matches[0] : ''; + } + /** * Create a default composer.json, should one not already exist * @@ -751,6 +759,7 @@ private function create_default_composer_json( $composer_path ) { $options = array( 'name' => 'wp-cli/wp-cli', 'description' => 'Installed community packages used by WP-CLI', + 'version' => self::get_wp_cli_version_composer(), 'authors' => array( $author ), 'homepage' => self::PACKAGE_INDEX_URL, 'require' => new stdClass, From 1003b59d0531df1a0a0b59ab50072ad2e721e0cb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 15:07:06 -0800 Subject: [PATCH 5119/5359] Introduce `Utils\parse_str_to_argv()` for parsing passed commands --- php/class-wp-cli.php | 11 +---------- php/utils.php | 24 ++++++++++++++++++++++++ tests/test-utils.php | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index fc6355b98..71ae179ca 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -931,16 +931,7 @@ public static function runcommand( $command, $options = array() ) { $retval = null; if ( empty( $options['launch'] ) ) { $configurator = self::get_configurator(); - preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $command, $matches ); - $argv = isset( $matches[0] ) ? $matches[0] : array(); - $argv = array_map( function( $arg ){ - foreach( array( '"', "'" ) as $char ) { - if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { - $arg = substr( $arg, 1, -1 ); - } - } - return $arg; - }, $argv ); + $argv = Utils\parse_str_to_argv( $command ); list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); if ( ! empty( $options['capture'] ) ) { ob_start(); diff --git a/php/utils.php b/php/utils.php index 8bf939c2d..537e71a8e 100644 --- a/php/utils.php +++ b/php/utils.php @@ -799,3 +799,27 @@ function report_batch_operation_results( $noun, $verb, $total, $successes, $fail } } } + +/** + * Parse a string of command line arguments into an $argv-esqe variable. + * + * @access public + * @category Input + * + * @param string $arguments + * @return array + */ +function parse_str_to_argv( $arguments ) { + preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $arguments, $matches ); + $argv = isset( $matches[0] ) ? $matches[0] : array(); + $argv = array_map( function( $arg ){ + foreach( array( '"', "'" ) as $char ) { + if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { + $arg = substr( $arg, 1, -1 ); + break; + } + } + return $arg; + }, $argv ); + return $argv; +} diff --git a/tests/test-utils.php b/tests/test-utils.php index b8fdd135f..358606913 100644 --- a/tests/test-utils.php +++ b/tests/test-utils.php @@ -108,5 +108,23 @@ public function testParseSSHUrl() { $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); } + public function testParseStrToArgv() { + $this->assertEquals( array(), Utils\parse_str_to_argv( '' ) ); + $this->assertEquals( array( + 'option', + 'get', + 'home', + ), Utils\parse_str_to_argv( 'option get home' ) ); + $this->assertEquals( array( + 'core', + 'download', + '--path=/var/www/', + ), Utils\parse_str_to_argv( 'core download --path=/var/www/' ) ); + $this->assertEquals( array( + 'eval', + 'echo wp_get_current_user()->user_login;', + ), Utils\parse_str_to_argv( 'eval "echo wp_get_current_user()->user_login;"' ) ); + } + } From 81812fbade3d923c76fa511305b7f13378fc5742 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 15:55:06 -0800 Subject: [PATCH 5120/5359] Support launching a new process in `WP_CLI::runcommand()` --- features/runcommand.feature | 22 ++++++++++++++------ php/class-wp-cli.php | 40 +++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index 68a797522..2d1822a10 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -31,8 +31,8 @@ Feature: Run a WP-CLI command - command.php """ - Scenario: Run a WP-CLI command in the same process, rendering output - When I run `wp run 'option get home' --no-launch` + Scenario Outline: Run a WP-CLI command and render output + When I run `wp <flag> run 'option get home'` Then STDOUT should be: """ http://example.com @@ -40,7 +40,7 @@ Feature: Run a WP-CLI command """ And the return code should be 0 - When I run `wp --no-launch run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + When I run `wp <flag> run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` Then STDOUT should be: """ admin @@ -48,17 +48,27 @@ Feature: Run a WP-CLI command """ And the return code should be 0 - Scenario: Run a WP-CLI command in the same process, capturing output - When I run `wp run --no-launch --capture 'option get home'` + Examples: + | flag | + | --no-launch | + | --launch | + + Scenario Outline: Run a WP-CLI command and capture output + When I run `wp run <flag> --capture 'option get home'` Then STDOUT should be: """ returned: 'http://example.com' """ And the return code should be 0 - When I run `wp --no-launch --capture run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + When I run `wp <flag> --capture run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` Then STDOUT should be: """ returned: 'admin' """ And the return code should be 0 + + Examples: + | flag | + | --no-launch | + | --launch | diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 71ae179ca..d2301b9c8 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -912,7 +912,7 @@ public static function get_config( $key = null ) { * Run a WP-CLI command. * * ``` - * $plugins = WP_CLI::run_command( 'plugin list' ); + * $plugins = WP_CLI::run_command( 'plugin list', array( 'capture' => true ) ); * ``` * * @access public @@ -928,16 +928,48 @@ public static function runcommand( $command, $options = array() ) { 'capture' => false, // Capture STDOUT, or render on the fly ); $options = array_merge( $defaults, $options ); + $launch = $options['launch']; + $capture = $options['capture']; $retval = null; - if ( empty( $options['launch'] ) ) { + if ( $launch ) { + if ( $capture ) { + $descriptors = array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + } else { + $descriptors = array( + 0 => STDIN, + 1 => STDOUT, + 2 => STDERR, + ); + } + + $php_bin = self::get_php_binary(); + $script_path = $GLOBALS['argv'][0]; + $runcommand = "{$php_bin} {$script_path} {$command}"; + + $env = array(); + $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), $env ); + + if ( $capture ) { + $stdout = stream_get_contents( $pipes[1] ); + fclose( $pipes[1] ); + $stderr = stream_get_contents( $pipes[2] ); + fclose( $pipes[2] ); + $retval = trim( $stdout ); + } + $return_code = proc_close( $proc ); + } else { $configurator = self::get_configurator(); $argv = Utils\parse_str_to_argv( $command ); list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); - if ( ! empty( $options['capture'] ) ) { + if ( $capture ) { ob_start(); } self::get_runner()->run_command( $args, $assoc_args ); - if ( ! empty( $options['capture'] ) ) { + if ( $capture ) { $retval = trim( ob_get_clean() ); } } From 36437c831e5965a22d1deee4b64ddb1deabca144 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 15:56:53 -0800 Subject: [PATCH 5121/5359] Ensure there aren't any warnings --- features/runcommand.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/runcommand.feature b/features/runcommand.feature index 2d1822a10..5255278d5 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -38,6 +38,7 @@ Feature: Run a WP-CLI command http://example.com returned: NULL """ + And STDERR should be empty And the return code should be 0 When I run `wp <flag> run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` @@ -46,6 +47,7 @@ Feature: Run a WP-CLI command admin returned: NULL """ + And STDERR should be empty And the return code should be 0 Examples: @@ -59,6 +61,7 @@ Feature: Run a WP-CLI command """ returned: 'http://example.com' """ + And STDERR should be empty And the return code should be 0 When I run `wp <flag> --capture run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` @@ -66,6 +69,7 @@ Feature: Run a WP-CLI command """ returned: 'admin' """ + And STDERR should be empty And the return code should be 0 Examples: From 0404d89222a77dfacf27409e2e38bac6960a6fda Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 24 Nov 2016 16:08:35 -0800 Subject: [PATCH 5122/5359] `--capture` makes more sense as `--return` --- features/runcommand.feature | 6 +++--- php/class-wp-cli.php | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index 5255278d5..251bd4c3f 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -16,7 +16,7 @@ Feature: Run a WP-CLI command * [--launch] * : Launch a new process for the command. * - * [--capture] + * [--return[=<return>]] * : Capture and return output. */ WP_CLI::add_command( 'run', function( $args, $assoc_args ){ @@ -56,7 +56,7 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Run a WP-CLI command and capture output - When I run `wp run <flag> --capture 'option get home'` + When I run `wp run <flag> --return 'option get home'` Then STDOUT should be: """ returned: 'http://example.com' @@ -64,7 +64,7 @@ Feature: Run a WP-CLI command And STDERR should be empty And the return code should be 0 - When I run `wp <flag> --capture run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + When I run `wp <flag> --return run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` Then STDOUT should be: """ returned: 'admin' diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index d2301b9c8..0946ffd73 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -912,7 +912,7 @@ public static function get_config( $key = null ) { * Run a WP-CLI command. * * ``` - * $plugins = WP_CLI::run_command( 'plugin list', array( 'capture' => true ) ); + * $plugins = WP_CLI::run_command( 'plugin list', array( 'return' => true ) ); * ``` * * @access public @@ -924,15 +924,15 @@ public static function get_config( $key = null ) { */ public static function runcommand( $command, $options = array() ) { $defaults = array( - 'launch' => true, // Launch a new process, or reuse the existing. - 'capture' => false, // Capture STDOUT, or render on the fly + 'launch' => true, // Launch a new process, or reuse the existing. + 'return' => false, // Capture and return output, or render in realtime. ); $options = array_merge( $defaults, $options ); $launch = $options['launch']; - $capture = $options['capture']; - $retval = null; + $should_return = $options['return']; + $return = null; if ( $launch ) { - if ( $capture ) { + if ( $should_return ) { $descriptors = array( 0 => STDIN, 1 => array( 'pipe', 'w' ), @@ -953,27 +953,27 @@ public static function runcommand( $command, $options = array() ) { $env = array(); $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), $env ); - if ( $capture ) { + if ( $should_return ) { $stdout = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); $stderr = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); - $retval = trim( $stdout ); + $return = trim( $stdout ); } $return_code = proc_close( $proc ); } else { $configurator = self::get_configurator(); $argv = Utils\parse_str_to_argv( $command ); list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); - if ( $capture ) { + if ( $should_return ) { ob_start(); } self::get_runner()->run_command( $args, $assoc_args ); - if ( $capture ) { - $retval = trim( ob_get_clean() ); + if ( $should_return ) { + $return = trim( ob_get_clean() ); } } - return $retval; + return $return; } /** From 407f219f0de15b8d7d8bd182d158d99bae66db43 Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Fri, 25 Nov 2016 16:48:12 +0545 Subject: [PATCH 5123/5359] Add examples for user session commands --- php/commands/user-session.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 1e50aef82..7855422ef 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -5,6 +5,16 @@ * * ## EXAMPLES * + * # List a user's sessions. + * $ wp user session list admin@example.com --format=csv + * login_time,expiration_time,ip,ua + * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." + * + * # Destroy the most recent session of the given user. + * $ wp user session destroy admin + * Success: Destroyed session. 3 sessions remaining. + * + * @package wp-cli */ class User_Session_Command extends WP_CLI_Command { @@ -36,19 +46,19 @@ public function __construct() { * * ## EXAMPLES * - * # Destroy the most recent session of the given user + * # Destroy the most recent session of the given user. * $ wp user session destroy admin * Success: Destroyed session. 3 sessions remaining. * - * # Destroy a specific session of the given user + * # Destroy a specific session of the given user. * $ wp user session destroy admin e073ad8540a9c2... * Success: Destroyed session. 2 sessions remaining. * - * # Destroy all the sessions of the given user + * # Destroy all the sessions of the given user. * $ wp user session destroy admin --all * Success: Destroyed all sessions. * - * # Destroy all sessions for all users + * # Destroy all sessions for all users. * $ wp user list --field=ID | xargs wp user session destroy --all * Success: Destroyed all sessions. 0 remaining. * Success: Destroyed all sessions. 0 remaining. @@ -131,7 +141,7 @@ public function destroy( $args, $assoc_args ) { * * ## EXAMPLES * - * # List a user's sessions + * # List a user's sessions. * $ wp user session list admin@example.com --format=csv * login_time,expiration_time,ip,ua * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." From e04ad6fe7e299268912f4288fdf3265d58216b2f Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 25 Nov 2016 21:21:10 +0545 Subject: [PATCH 5124/5359] Update success message for user session destroy in all mode --- php/commands/user-session.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/commands/user-session.php b/php/commands/user-session.php index 7855422ef..5d5445a7a 100644 --- a/php/commands/user-session.php +++ b/php/commands/user-session.php @@ -60,8 +60,8 @@ public function __construct() { * * # Destroy all sessions for all users. * $ wp user list --field=ID | xargs wp user session destroy --all - * Success: Destroyed all sessions. 0 remaining. - * Success: Destroyed all sessions. 0 remaining. + * Success: Destroyed all sessions. + * Success: Destroyed all sessions. */ public function destroy( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); @@ -75,8 +75,7 @@ public function destroy( $args, $assoc_args ) { if ( $all ) { $manager->destroy_all(); - $remaining = count( $manager->get_all() ); - WP_CLI::success( sprintf( 'Destroyed all sessions. %s remaining.', $remaining ) ); + WP_CLI::success( 'Destroyed all sessions.' ); return; } From 21c04f56e3c442e2426a5907043be8ee059c92ba Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Fri, 25 Nov 2016 21:21:41 +0545 Subject: [PATCH 5125/5359] Update test to reflect change in success message in user session destroy --- features/user-session.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/user-session.feature b/features/user-session.feature index 27480e154..c4a576eb2 100644 --- a/features/user-session.feature +++ b/features/user-session.feature @@ -30,7 +30,7 @@ Feature: Manage user session When I run `wp user session destroy admin --all` Then STDOUT should be: """ - Success: Destroyed all sessions. 0 remaining. + Success: Destroyed all sessions. """ And I run `wp user session list admin --format=count` From 1844d6abd4e8605d1a3da7c886f07b14598c6e5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 06:17:17 -0800 Subject: [PATCH 5126/5359] Require PHP 5.4 to prevent error notice failures --- features/runcommand.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/runcommand.feature b/features/runcommand.feature index 251bd4c3f..0b7cca99b 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -1,3 +1,4 @@ +@require-php-5.4 Feature: Run a WP-CLI command Background: From a160df6bb933d09b5504403e640d1b445c7934c3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 06:35:29 -0800 Subject: [PATCH 5127/5359] Pass WP-CLI environment variables through when launching new process --- features/runcommand.feature | 23 +++++++++++++++++++++++ php/class-wp-cli.php | 17 +++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/features/runcommand.feature b/features/runcommand.feature index 0b7cca99b..328144ecb 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -31,6 +31,12 @@ Feature: Run a WP-CLI command require: - command.php """ + And a config.yml file: + """ + user get: + 0: admin + field: user_email + """ Scenario Outline: Run a WP-CLI command and render output When I run `wp <flag> run 'option get home'` @@ -51,6 +57,15 @@ Feature: Run a WP-CLI command And STDERR should be empty And the return code should be 0 + When I run `WP_CLI_CONFIG_PATH=config.yml wp <flag> run 'user get'` + Then STDOUT should be: + """ + admin@example.com + returned: NULL + """ + And STDERR should be empty + And the return code should be 0 + Examples: | flag | | --no-launch | @@ -73,6 +88,14 @@ Feature: Run a WP-CLI command And STDERR should be empty And the return code should be 0 + When I run `WP_CLI_CONFIG_PATH=config.yml wp --return <flag> run 'user get'` + Then STDOUT should be: + """ + returned: 'admin@example.com' + """ + And STDERR should be empty + And the return code should be 0 + Examples: | flag | | --no-launch | diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 0946ffd73..6c37503b6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -950,7 +950,21 @@ public static function runcommand( $command, $options = array() ) { $script_path = $GLOBALS['argv'][0]; $runcommand = "{$php_bin} {$script_path} {$command}"; + $env_vars = array( + 'HOME', + 'WP_CLI_AUTO_CHECK_UPDATE_DAYS', + 'WP_CLI_CACHE_DIR', + 'WP_CLI_CONFIG_PATH', + 'WP_CLI_DISABLE_AUTO_CHECK_UPDATE', + 'WP_CLI_PACKAGES_DIR', + 'WP_CLI_PHP_USED', + 'WP_CLI_PHP', + 'WP_CLI_STRICT_ARGS_MODE', + ); $env = array(); + foreach( $env_vars as $var ) { + $env[ $var ] = getenv( $var ); + } $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), $env ); if ( $should_return ) { @@ -961,6 +975,9 @@ public static function runcommand( $command, $options = array() ) { $return = trim( $stdout ); } $return_code = proc_close( $proc ); + if ( -1 == $return_code ) { + self::warning( "Spawned process returned exit code -1, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); + } } else { $configurator = self::get_configurator(); $argv = Utils\parse_str_to_argv( $command ); From c986d65703209e2e00372e8089a6c5d118176a3c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 06:39:58 -0800 Subject: [PATCH 5128/5359] Add testcase that installed packages work --- features/runcommand.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/runcommand.feature b/features/runcommand.feature index 328144ecb..3e3dcefbd 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -100,3 +100,19 @@ Feature: Run a WP-CLI command | flag | | --no-launch | | --launch | + + Scenario Outline: Installed packages work as expected + When I run `wp package install wp-cli/scaffold-package-command` + Then STDERR should be empty + + When I run `wp <flag> run 'help scaffold package'` + Then STDOUT should contain: + """ + wp scaffold package <name> + """ + And STDERR should be empty + + Examples: + | flag | + | --no-launch | + | --launch | From 478d42d0955ac110785d752ea4b68b05cced32d3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 06:53:27 -0800 Subject: [PATCH 5129/5359] Support returning entire execution object, or specific items --- features/runcommand.feature | 28 +++++++++++++++++++++++ php/class-wp-cli.php | 45 +++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index 3e3dcefbd..e0d017b90 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -88,6 +88,34 @@ Feature: Run a WP-CLI command And STDERR should be empty And the return code should be 0 + When I run `wp <flag> --return=stderr run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + Then STDOUT should be: + """ + returned: '' + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp <flag> --return=return_code run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + Then STDOUT should be: + """ + returned: 0 + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp <flag> --return=all run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` + Then STDOUT should be: + """ + returned: array ( + 'stdout' => 'admin', + 'stderr' => '', + 'return_code' => 0, + ) + """ + And STDERR should be empty + And the return code should be 0 + When I run `WP_CLI_CONFIG_PATH=config.yml wp --return <flag> run 'user get'` Then STDOUT should be: """ diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 6c37503b6..dddd12be6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -929,10 +929,10 @@ public static function runcommand( $command, $options = array() ) { ); $options = array_merge( $defaults, $options ); $launch = $options['launch']; - $should_return = $options['return']; - $return = null; + $return = $options['return']; + $retval = null; if ( $launch ) { - if ( $should_return ) { + if ( $return ) { $descriptors = array( 0 => STDIN, 1 => array( 'pipe', 'w' ), @@ -967,30 +967,57 @@ public static function runcommand( $command, $options = array() ) { } $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), $env ); - if ( $should_return ) { + if ( $return ) { $stdout = stream_get_contents( $pipes[1] ); fclose( $pipes[1] ); $stderr = stream_get_contents( $pipes[2] ); fclose( $pipes[2] ); - $return = trim( $stdout ); } $return_code = proc_close( $proc ); if ( -1 == $return_code ) { self::warning( "Spawned process returned exit code -1, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); } + if ( true === $return || 'stdout' === $return ) { + $retval = trim( $stdout ); + } else if ( 'stderr' === $return ) { + $retval = trim( $stderr ); + } else if ( 'return_code' === $return ) { + $retval = $return_code; + } else if ( 'all' === $return ) { + $retval = array( + 'stdout' => trim( $stdout ), + 'stderr' => trim( $stderr ), + 'return_code' => $return_code, + ); + } } else { $configurator = self::get_configurator(); $argv = Utils\parse_str_to_argv( $command ); list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); - if ( $should_return ) { + if ( $return ) { ob_start(); } self::get_runner()->run_command( $args, $assoc_args ); - if ( $should_return ) { - $return = trim( ob_get_clean() ); + if ( $return ) { + $stdout = trim( ob_get_clean() ); + $stderr = ''; + $return_code = 0; + if ( true === $return || 'stdout' === $return ) { + $retval = trim( $stdout ); + } else if ( 'stderr' === $return ) { + $retval = trim( $stderr ); + } else if ( 'return_code' === $return ) { + $retval = $return_code; + } else if ( 'all' === $return ) { + $retval = array( + 'stdout' => trim( $stdout ), + 'stderr' => trim( $stderr ), + 'return_code' => $return_code, + ); + } } } - return $return; + return $retval; } /** From e7eea7dbb66177d285034127f07dd80575916282 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 07:04:25 -0800 Subject: [PATCH 5130/5359] Return an object, to replicate behavior of `::launch_self()` --- php/class-wp-cli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index dddd12be6..9ed87f2c7 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -984,7 +984,7 @@ public static function runcommand( $command, $options = array() ) { } else if ( 'return_code' === $return ) { $retval = $return_code; } else if ( 'all' === $return ) { - $retval = array( + $retval = (object) array( 'stdout' => trim( $stdout ), 'stderr' => trim( $stderr ), 'return_code' => $return_code, @@ -1009,7 +1009,7 @@ public static function runcommand( $command, $options = array() ) { } else if ( 'return_code' === $return ) { $retval = $return_code; } else if ( 'all' === $return ) { - $retval = array( + $retval = (object) array( 'stdout' => trim( $stdout ), 'stderr' => trim( $stderr ), 'return_code' => $return_code, From 438e377c147b4bf5a26ca8727d04785a8ff61c0d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 07:04:46 -0800 Subject: [PATCH 5131/5359] Use `WP_CLI::runcommand()` in `wp core update-db --network` --- features/core-update-db.feature | 2 +- php/commands/core.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 7ad9fc2f2..176024c19 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -55,7 +55,7 @@ Feature: Update core's database Success: WordPress database upgraded on 3/3 sites. """ - Scenario: Update db across network + Scenario: Update db across network, dry run Given a WP multisite install And I run `wp core download --version=4.1 --force` And I run `wp option update db_version 29630` diff --git a/php/commands/core.php b/php/commands/core.php index 6ab16fa64..bd068bbb7 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1337,7 +1337,11 @@ function update_db( $_, $assoc_args ) { foreach( $it as $blog ) { $total++; $url = $blog->domain . $blog->path; - $process = WP_CLI::launch_self( 'core update-db', array(), array( 'dry-run' => $dry_run ), false, true, array( 'url' => $url ) ); + $cmd = "--url={$url} core update-db"; + if ( $dry_run ) { + $cmd .= ' --dry-run'; + } + $process = WP_CLI::runcommand( $cmd, array( 'return' => 'all' ) ); if ( 0 == $process->return_code ) { // See if we can parse the stdout if ( preg_match( '#Success: (.+)#', $process->stdout, $matches ) ) { From 8a1bc6b540db6272f906b153e4aac746c68c1780 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 15:46:29 -0800 Subject: [PATCH 5132/5359] Cast as array for the purposes of the test --- features/runcommand.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/runcommand.feature b/features/runcommand.feature index e0d017b90..3ab2f544f 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -22,6 +22,7 @@ Feature: Run a WP-CLI command */ WP_CLI::add_command( 'run', function( $args, $assoc_args ){ $ret = WP_CLI::runcommand( $args[0], $assoc_args ); + $ret = is_object( $ret ) ? (array) $ret : $ret; WP_CLI::log( 'returned: ' . var_export( $ret, true ) ); }); """ From 46a9ac7f3b63522bf92cf41a524e5d7c219d8fe4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 15:53:31 -0800 Subject: [PATCH 5133/5359] Use `parse=json` to parse captured data as a particular format --- features/runcommand.feature | 18 ++++++++++++++++++ php/class-wp-cli.php | 8 +++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index 3ab2f544f..e2ccb0191 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -19,6 +19,9 @@ Feature: Run a WP-CLI command * * [--return[=<return>]] * : Capture and return output. + * + * [--parse=<format>] + * : Parse returned output as a particular format. */ WP_CLI::add_command( 'run', function( $args, $assoc_args ){ $ret = WP_CLI::runcommand( $args[0], $assoc_args ); @@ -130,6 +133,21 @@ Feature: Run a WP-CLI command | --no-launch | | --launch | + Scenario Outline: Use 'parse=json' to parse JSON output + When I run `wp run --return --parse=json <flag> 'user get admin --fields=user_login,user_email --format=json'` + Then STDOUT should be: + """ + returned: array ( + 'user_login' => 'admin', + 'user_email' => 'admin@example.com', + ) + """ + + Examples: + | flag | + | --no-launch | + | --launch | + Scenario Outline: Installed packages work as expected When I run `wp package install wp-cli/scaffold-package-command` Then STDERR should be empty diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 9ed87f2c7..b93374904 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -912,7 +912,7 @@ public static function get_config( $key = null ) { * Run a WP-CLI command. * * ``` - * $plugins = WP_CLI::run_command( 'plugin list', array( 'return' => true ) ); + * $plugins = WP_CLI::run_command( 'plugin list --format=json', array( 'return' => true ) ); * ``` * * @access public @@ -926,10 +926,12 @@ public static function runcommand( $command, $options = array() ) { $defaults = array( 'launch' => true, // Launch a new process, or reuse the existing. 'return' => false, // Capture and return output, or render in realtime. + 'parse' => false, // Parse returned output as a particular format. ); $options = array_merge( $defaults, $options ); $launch = $options['launch']; $return = $options['return']; + $parse = $options['parse']; $retval = null; if ( $launch ) { if ( $return ) { @@ -1017,6 +1019,10 @@ public static function runcommand( $command, $options = array() ) { } } } + if ( ( true === $return || 'stdout' === $return ) + && 'json' === $parse ) { + $retval = json_decode( $retval, true ); + } return $retval; } From 603889ecb48f415d5b305d9646c796913036f9ff Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 16:09:47 -0800 Subject: [PATCH 5134/5359] Ensure `::runcommand()` exits on error by default --- features/runcommand.feature | 14 ++++++++++++++ php/class-wp-cli.php | 10 +++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index e2ccb0191..f12eadc93 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -148,6 +148,20 @@ Feature: Run a WP-CLI command | --no-launch | | --launch | + Scenario Outline: Exit on error by default + When I try `wp run <flag> 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` + Then STDOUT should be empty + And STDERR should be: + """ + Error: 1 + """ + And the return code should be 1 + + Examples: + | flag | + | --no-launch | + | --launch | + Scenario Outline: Installed packages work as expected When I run `wp package install wp-cli/scaffold-package-command` Then STDERR should be empty diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b93374904..4d91266d6 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -924,12 +924,14 @@ public static function get_config( $key = null ) { */ public static function runcommand( $command, $options = array() ) { $defaults = array( - 'launch' => true, // Launch a new process, or reuse the existing. - 'return' => false, // Capture and return output, or render in realtime. - 'parse' => false, // Parse returned output as a particular format. + 'launch' => true, // Launch a new process, or reuse the existing. + 'exit_error' => true, // Exit on error by default. + 'return' => false, // Capture and return output, or render in realtime. + 'parse' => false, // Parse returned output as a particular format. ); $options = array_merge( $defaults, $options ); $launch = $options['launch']; + $exit_error = $options['exit_error']; $return = $options['return']; $parse = $options['parse']; $retval = null; @@ -978,6 +980,8 @@ public static function runcommand( $command, $options = array() ) { $return_code = proc_close( $proc ); if ( -1 == $return_code ) { self::warning( "Spawned process returned exit code -1, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); + } else if ( $return_code && $exit_error ) { + exit( $return_code ); } if ( true === $return || 'stdout' === $return ) { $retval = trim( $stdout ); From 025e4e80172c909396daafccf559455f5bd516de Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 16:12:39 -0800 Subject: [PATCH 5135/5359] Explicit error code assertions --- features/rewrite.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/rewrite.feature b/features/rewrite.feature index ac033e6a3..6d7fdccee 100644 --- a/features/rewrite.feature +++ b/features/rewrite.feature @@ -68,6 +68,7 @@ Feature: Manage WordPress rewrites When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` Then the .htaccess file should exist + And the return code should be 0 Scenario: Generate .htaccess on hard flush with a global config Given a WP install @@ -78,6 +79,7 @@ Feature: Manage WordPress rewrites When I run `WP_CLI_CONFIG_PATH=config.yml wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` Then the .htaccess file should exist + And the return code should be 0 Scenario: Error when trying to generate .htaccess on a multisite install Given a WP multisite install @@ -91,9 +93,11 @@ Feature: Manage WordPress rewrites """ Warning: WordPress can't generate .htaccess file for a multisite install. """ + And the return code should be 0 When I try `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` Then STDERR should contain: """ Warning: WordPress can't generate .htaccess file for a multisite install. """ + And the return code should be 0 From bf6c7c093b977bc84bd932d10c3ec4689a452c16 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 16:14:10 -0800 Subject: [PATCH 5136/5359] Use `::runcommand()` inside of `wp rewrite structure` --- php/commands/rewrite.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php index 4803319cd..c784a3d1e 100644 --- a/php/commands/rewrite.php +++ b/php/commands/rewrite.php @@ -146,14 +146,16 @@ public function structure( $args, $assoc_args ) { // Launch a new process to flush rewrites because core expects flush // to happen after rewrites are set $new_assoc_args = array(); + $cmd = 'rewrite flush'; if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ) { + $cmd .= ' --hard'; $new_assoc_args['hard'] = true; if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); } } - $process_run = WP_CLI::launch_self( 'rewrite flush', array(), $new_assoc_args, true, true, array( 'apache_modules', WP_CLI::get_config( 'apache_modules' ) ) ); + $process_run = WP_CLI::runcommand( $cmd ); if ( ! empty( $process_run->stderr ) ) { // Strip "Warning: " WP_CLI::warning( substr( $process_run->stderr, 9 ) ); From 1668a278dd14f2d29515c8af837e179201e17888 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 16:41:43 -0800 Subject: [PATCH 5137/5359] Permit overriding exit on error behavior in the same process --- features/runcommand.feature | 21 ++++++++ php/WP_CLI/ExitException.php | 5 ++ php/WP_CLI/Loggers/Execution.php | 84 ++++++++++++++++++++++++++++++++ php/class-wp-cli.php | 37 +++++++++++--- 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 php/WP_CLI/ExitException.php create mode 100644 php/WP_CLI/Loggers/Execution.php diff --git a/features/runcommand.feature b/features/runcommand.feature index f12eadc93..0977539a4 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -17,6 +17,9 @@ Feature: Run a WP-CLI command * [--launch] * : Launch a new process for the command. * + * [--exit_error] + * : Exit on error. + * * [--return[=<return>]] * : Capture and return output. * @@ -162,6 +165,24 @@ Feature: Run a WP-CLI command | --no-launch | | --launch | + Scenario Outline: Override erroring on exit + When I try `wp run <flag> --no-exit_error --return=all 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` + Then STDOUT should be: + """ + returned: array ( + 'stdout' => '', + 'stderr' => 'Error: 1', + 'return_code' => 1, + ) + """ + And STDERR should be empty + And the return code should be 0 + + Examples: + | flag | + | --no-launch | + | --launch | + Scenario Outline: Installed packages work as expected When I run `wp package install wp-cli/scaffold-package-command` Then STDERR should be empty diff --git a/php/WP_CLI/ExitException.php b/php/WP_CLI/ExitException.php new file mode 100644 index 000000000..8a86dc3e0 --- /dev/null +++ b/php/WP_CLI/ExitException.php @@ -0,0 +1,5 @@ +<?php + +namespace WP_CLI; + +class ExitException extends \Exception {} diff --git a/php/WP_CLI/Loggers/Execution.php b/php/WP_CLI/Loggers/Execution.php new file mode 100644 index 000000000..3b0ab7e79 --- /dev/null +++ b/php/WP_CLI/Loggers/Execution.php @@ -0,0 +1,84 @@ +<?php + +namespace WP_CLI\Loggers; + +/** + * Execution logger captures all STDOUT and STDERR writes + */ +class Execution extends Base { + + /** + * Captured writes to STDOUT. + */ + public $stdout = ''; + + /** + * Captured writes to STDERR. + */ + public $stderr = ''; + + /** + * Write an informational message to STDOUT. + * + * @param string $message Message to write. + */ + public function info( $message ) { + $this->write( 'STDOUT', $message . "\n" ); + } + + /** + * Write a success message, prefixed with "Success: ". + * + * @param string $message Message to write. + */ + public function success( $message ) { + $this->_line( $message, 'Success', '%G' ); + } + + /** + * Write a warning message to STDERR, prefixed with "Warning: ". + * + * @param string $message Message to write. + */ + public function warning( $message ) { + $this->_line( $message, 'Warning', '%C', 'STDERR' ); + } + + /** + * Write an message to STDERR, prefixed with "Error: ". + * + * @param string $message Message to write. + */ + public function error( $message ) { + $this->_line( $message, 'Error', '%R', 'STDERR' ); + } + + /** + * Similar to error( $message ), but outputs $message in a red box + * + * @param array $message Message to write. + */ + public function error_multi_line( $message_lines ) { + $message = implode( "\n", $message_lines ); + + $this->write( 'STDERR', \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); + $this->write( 'STDERR', \WP_CLI::colorize( "%R---------%n\n\n" ) ); + } + + /** + * Write a string to a resource. + * + * @param resource $handle Commonly STDOUT or STDERR. + * @param string $str Message to write. + */ + protected function write( $handle, $str ) { + switch( $handle ) { + case 'STDOUT': + $this->stdout .= $str; + break; + case 'STDERR': + $this->stderr .= $str; + break; + } + } +} diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4d91266d6..2b5a0577c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1,10 +1,11 @@ <?php -use \WP_CLI\Utils; +use \WP_CLI\ExitException; use \WP_CLI\Dispatcher; use \WP_CLI\FileCache; use \WP_CLI\Process; use \WP_CLI\WpHttpCacheManager; +use \WP_CLI\Utils; /** * Various utilities for WP-CLI commands. @@ -17,6 +18,8 @@ class WP_CLI { private static $hooks = array(), $hooks_passed = array(); + private static $capture_exit = false; + /** * Set the logger instance. * @@ -627,10 +630,18 @@ public static function error( $message, $exit = true ) { self::$logger->error( self::error_to_string( $message ) ); } + $return_code = false; if ( true === $exit ) { - exit( 1 ); + $return_code = 1; } elseif ( is_int( $exit ) && $exit >= 1 ) { - exit( $exit ); + $return_code = $exit; + } + + if ( $return_code ) { + if ( self::$capture_exit ) { + throw new ExitException( null, $return_code ); + } + exit( $return_code ); } } @@ -1003,11 +1014,22 @@ public static function runcommand( $command, $options = array() ) { if ( $return ) { ob_start(); } - self::get_runner()->run_command( $args, $assoc_args ); + if ( ! $exit_error ) { + self::$capture_exit = true; + $existing_logger = self::$logger; + self::$logger = new WP_CLI\Loggers\Execution; + } + try { + self::get_runner()->run_command( $args, $assoc_args ); + $return_code = 0; + } catch( ExitException $e ) { + $return_code = $e->getCode(); + } + $execution_logger = self::$logger; + self::$logger = $existing_logger; if ( $return ) { $stdout = trim( ob_get_clean() ); - $stderr = ''; - $return_code = 0; + $stderr = $execution_logger->stderr; if ( true === $return || 'stdout' === $return ) { $retval = trim( $stdout ); } else if ( 'stderr' === $return ) { @@ -1022,6 +1044,9 @@ public static function runcommand( $command, $options = array() ) { ); } } + if ( ! $exit_error ) { + self::$capture_exit = false; + } } if ( ( true === $return || 'stdout' === $return ) && 'json' === $parse ) { From 2b3f0d42aca64d41471ec26a5ce0037810381021 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 17:02:01 -0800 Subject: [PATCH 5138/5359] Update PHPDoc --- php/class-wp-cli.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 2b5a0577c..70f8110bf 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -817,6 +817,8 @@ public static function launch( $command, $exit_on_error = true, $return_detailed /** * Run a WP-CLI command in a new process reusing the current runtime arguments. * + * Use `WP_CLI::runcommand()` instead, which is easier to use and works better. + * * Note: While this command does persist a limited set of runtime arguments, * it *does not* persist environment variables. Practically speaking, WP-CLI * packages won't be loaded when using WP_CLI::launch_self() because the @@ -922,8 +924,20 @@ public static function get_config( $key = null ) { /** * Run a WP-CLI command. * + * Launch a new child process, or run the command in the current process. + * Optionally: + * * Prevent halting script execution on error. + * * Capture and return STDOUT, or full details about command execution. + * * Parse JSON output if the command rendered it. + * * ``` - * $plugins = WP_CLI::run_command( 'plugin list --format=json', array( 'return' => true ) ); + * $options = array( + * 'return' => true, // Return 'STDOUT'; use 'all' for full object. + * 'parse' => 'json' // Parse captured STDOUT to JSON array. + * 'launch' => false, // Reuse the current process. + * 'exit_error' => true, // Halt script execution on error. + * ); + * $plugins = WP_CLI::runcommand( 'plugin list --format=json', $options ); * ``` * * @access public @@ -1059,6 +1073,8 @@ public static function runcommand( $command, $options = array() ) { * Run a given command within the current process using the same global * parameters. * + * Use `WP_CLI::runcommand()` instead, which is easier to use and works better. + * * To run a command using a new process with the same global parameters, * use WP_CLI::launch_self(). To run a command using a new process with * different global parameters, use WP_CLI::launch(). From 7b2ce306b904a0fd9a4e4a059acea4bb022fa8a7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 17:24:19 -0800 Subject: [PATCH 5139/5359] Use `WP_CLI::halt()` to overload halting script execution --- features/runcommand.feature | 8 ++++++++ php/class-wp-cli.php | 17 +++++++++++++++++ php/commands/cli.php | 2 +- php/commands/core.php | 8 ++++---- php/commands/export.php | 2 +- php/commands/option.php | 5 +++-- php/commands/plugin.php | 4 ++-- php/commands/site-option.php | 5 +++-- php/commands/theme.php | 4 ++-- 9 files changed, 41 insertions(+), 14 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index 0977539a4..c9b3f26e5 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -178,6 +178,14 @@ Feature: Run a WP-CLI command And STDERR should be empty And the return code should be 0 + When I run `wp <flag> --no-exit_error run 'option get foo$bar'` + Then STDOUT should be: + """ + returned: NULL + """ + And STDERR should be empty + And the return code should be 0 + Examples: | flag | | --no-launch | diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 70f8110bf..54f7aab26 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -645,6 +645,23 @@ public static function error( $message, $exit = true ) { } } + /** + * Halt script execution with a specific return code. + * + * Permits script execution to be overloaded by `WP_CLI::runcommand()` + * + * @access public + * @category Output + * + * @param integer $return_code + */ + public static function halt( $return_code ) { + if ( self::$capture_exit ) { + throw new ExitException( null, $return_code ); + } + exit( $return_code ); + } + /** * Display a multi-line error message in a red box. Doesn't exit script. * diff --git a/php/commands/cli.php b/php/commands/cli.php index 3e7f5ee78..4bb76247d 100644 --- a/php/commands/cli.php +++ b/php/commands/cli.php @@ -269,7 +269,7 @@ public function update( $_, $assoc_args ) { if ( empty( $updates ) ) { $update_type = $this->get_update_type_str( $assoc_args ); WP_CLI::success( "WP-CLI is at the latest{$update_type}version." ); - exit(0); + return; } $newest = $updates[0]; diff --git a/php/commands/core.php b/php/commands/core.php index bd068bbb7..3abdda443 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -435,14 +435,14 @@ public function is_installed( $_, $assoc_args ) { if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { if ( is_blog_installed() && is_multisite() ) { - exit( 0 ); + WP_CLI::halt( 0 ); } else { - exit( 1 ); + WP_CLI::halt( 1 ); } } else if ( is_blog_installed() ) { - exit( 0 ); + WP_CLI::halt( 0 ); } else { - exit( 1 ); + WP_CLI::halt( 1 ); } } diff --git a/php/commands/export.php b/php/commands/export.php index 7e7bf7128..e85b0f9ee 100644 --- a/php/commands/export.php +++ b/php/commands/export.php @@ -186,7 +186,7 @@ private function validate_args( $args ) { } if ( $has_errors ) { - exit(1); + WP_CLI::halt(1); } } diff --git a/php/commands/option.php b/php/commands/option.php index 12a486a42..880212ed2 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -63,8 +63,9 @@ public function get( $args, $assoc_args ) { $value = get_option( $key ); - if ( false === $value ) - die(1); + if ( false === $value ) { + WP_CLI::halt( 1 ); + } WP_CLI::print_value( $value, $assoc_args ); } diff --git a/php/commands/plugin.php b/php/commands/plugin.php index d9031674f..2263bed76 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -800,9 +800,9 @@ public function uninstall( $args, $assoc_args = array() ) { */ public function is_installed( $args, $assoc_args = array() ) { if ( $this->fetcher->get( $args[0] ) ) { - exit( 0 ); + WP_CLI::halt( 0 ); } else { - exit( 1 ); + WP_CLI::halt( 1 ); } } diff --git a/php/commands/site-option.php b/php/commands/site-option.php index a97b98f5b..5ee1b3b06 100644 --- a/php/commands/site-option.php +++ b/php/commands/site-option.php @@ -52,8 +52,9 @@ public function get( $args, $assoc_args ) { $value = get_site_option( $key ); - if ( false === $value ) - die(1); + if ( false === $value ) { + WP_CLI::halt(1); + } WP_CLI::print_value( $value, $assoc_args ); } diff --git a/php/commands/theme.php b/php/commands/theme.php index 3909f86cc..94fef1ea2 100644 --- a/php/commands/theme.php +++ b/php/commands/theme.php @@ -665,9 +665,9 @@ public function is_installed( $args, $assoc_args = array() ) { $theme = wp_get_theme( $args[0] ); if ( $theme->exists() ) { - exit( 0 ); + WP_CLI::halt( 0 ); } else { - exit( 1 ); + WP_CLI::halt( 1 ); } } From a5ac336e95bd21741ad17f0f5e9c555c864065f7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sat, 26 Nov 2016 17:30:49 -0800 Subject: [PATCH 5140/5359] Only overload the logger when we want to return output --- php/class-wp-cli.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 54f7aab26..68f8efdd9 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1044,11 +1044,11 @@ public static function runcommand( $command, $options = array() ) { list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); if ( $return ) { ob_start(); + $existing_logger = self::$logger; + self::$logger = new WP_CLI\Loggers\Execution; } if ( ! $exit_error ) { self::$capture_exit = true; - $existing_logger = self::$logger; - self::$logger = new WP_CLI\Loggers\Execution; } try { self::get_runner()->run_command( $args, $assoc_args ); @@ -1056,9 +1056,9 @@ public static function runcommand( $command, $options = array() ) { } catch( ExitException $e ) { $return_code = $e->getCode(); } - $execution_logger = self::$logger; - self::$logger = $existing_logger; if ( $return ) { + $execution_logger = self::$logger; + self::$logger = $existing_logger; $stdout = trim( ob_get_clean() ); $stderr = $execution_logger->stderr; if ( true === $return || 'stdout' === $return ) { From e4b28984bc8534ddc57c165f1991c2cad755188c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 27 Nov 2016 06:22:59 -0800 Subject: [PATCH 5141/5359] Add a testcase for updating a package with a newer version --- features/package-update.feature | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/features/package-update.feature b/features/package-update.feature index a4b65f3cc..0da7ed3c7 100644 --- a/features/package-update.feature +++ b/features/package-update.feature @@ -24,3 +24,71 @@ Feature: Update WP-CLI packages Packages updated. """ And STDERR should be empty + + Scenario: Update a package with an update available + Given an empty directory + + When I run `wp package install wp-cli/scaffold-package-command:0.1.0` + Then STDOUT should contain: + """ + Installing package wp-cli/scaffold-package-command (0.1.0) + """ + And STDOUT should contain: + """ + Success: Package installed. + """ + + When I run `cat {PACKAGE_PATH}/composer.json` + Then STDOUT should contain: + """ + "wp-cli/scaffold-package-command": "0.1.0" + """ + + When I run `wp help scaffold package` + Then STDOUT should contain: + """ + wp scaffold package <name> + """ + + When I run `wp package update` + Then STDOUT should contain: + """ + Nothing to install or update + """ + And STDOUT should contain: + """ + Success: Packages updated. + """ + + When I run `sed -i.bak s/0.1.0/\>=0.1.0/g {PACKAGE_PATH}/composer.json` + Then the return code should be 0 + + When I run `cat {PACKAGE_PATH}/composer.json` + Then STDOUT should contain: + """ + "wp-cli/scaffold-package-command": ">=0.1.0" + """ + + When I run `wp package update` + Then STDOUT should not contain: + """ + Nothing to install or update + """ + And STDOUT should contain: + """ + Writing lock file + """ + And STDOUT should contain: + """ + Success: Packages updated. + """ + + When I run `wp package update` + Then STDOUT should contain: + """ + Nothing to install or update + """ + And STDOUT should contain: + """ + Success: Packages updated. + """ From fc872ce82a94dc4870ee91eddde114412469529d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 27 Nov 2016 06:50:55 -0800 Subject: [PATCH 5142/5359] Indicate when a package has an update available --- features/package-update.feature | 25 +++++++++--- php/commands/package.php | 69 +++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/features/package-update.feature b/features/package-update.feature index 0da7ed3c7..9af909119 100644 --- a/features/package-update.feature +++ b/features/package-update.feature @@ -60,6 +60,11 @@ Feature: Update WP-CLI packages Success: Packages updated. """ + When I run `wp package list --fields=name,update` + Then STDOUT should be a table containing rows: + | name | update | + | wp-cli/scaffold-package-command | none | + When I run `sed -i.bak s/0.1.0/\>=0.1.0/g {PACKAGE_PATH}/composer.json` Then the return code should be 0 @@ -69,12 +74,13 @@ Feature: Update WP-CLI packages "wp-cli/scaffold-package-command": ">=0.1.0" """ + When I run `wp package list --fields=name,update` + Then STDOUT should be a table containing rows: + | name | update | + | wp-cli/scaffold-package-command | available | + When I run `wp package update` - Then STDOUT should not contain: - """ - Nothing to install or update - """ - And STDOUT should contain: + Then STDOUT should contain: """ Writing lock file """ @@ -82,6 +88,15 @@ Feature: Update WP-CLI packages """ Success: Packages updated. """ + And STDOUT should not contain: + """ + Nothing to install or update + """ + + When I run `wp package list --fields=name,update` + Then STDOUT should be a table containing rows: + | name | update | + | wp-cli/scaffold-package-command | none | When I run `wp package update` Then STDOUT should contain: diff --git a/php/commands/package.php b/php/commands/package.php index 89a579978..57e362a02 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -1,6 +1,8 @@ <?php +use \Composer\Composer; use \Composer\Config; use \Composer\Config\JsonConfigSource; +use \Composer\DependencyResolver\Pool; use \Composer\EventDispatcher\Event; use \Composer\Factory; use \Composer\IO\NullIO; @@ -8,7 +10,10 @@ use \Composer\Json\JsonFile; use \Composer\Json\JsonManipulator; use \Composer\Package; +use \Composer\Package\BasePackage; +use \Composer\Package\PackageInterface; use \Composer\Package\Version\VersionParser; +use \Composer\Package\Version\VersionSelector; use \Composer\Repository; use \Composer\Repository\CompositeRepository; use \Composer\Repository\ComposerRepository; @@ -80,6 +85,8 @@ class Package_Command extends WP_CLI_Command { 'version', ); + private $pool = false; + /** * Browse WP-CLI packages available for installation. * @@ -124,7 +131,7 @@ class Package_Command extends WP_CLI_Command { * */ public function browse( $_, $assoc_args ) { - $this->show_packages( $this->get_community_packages(), $assoc_args ); + $this->show_packages( 'browse', $this->get_community_packages(), $assoc_args ); } /** @@ -335,7 +342,7 @@ public function install( $args, $assoc_args ) { * @subcommand list */ public function list_( $args, $assoc_args ) { - $this->show_packages( $this->get_installed_packages(), $assoc_args ); + $this->show_packages( 'list', $this->get_installed_packages(), $assoc_args ); } /** @@ -565,12 +572,17 @@ private function package_index() { /** * Display a set of packages * + * @param string $context * @param array * @param array */ - private function show_packages( $packages, $assoc_args ) { + private function show_packages( $context, $packages, $assoc_args ) { + $fields = $this->fields; + if ( 'list' === $context ) { + $fields[] = 'update'; + } $defaults = array( - 'fields' => implode( ',', $this->fields ), + 'fields' => implode( ',', $fields ), 'format' => 'table' ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -586,6 +598,14 @@ private function show_packages( $packages, $assoc_args ) { $package_output['description'] = $package->getDescription(); $package_output['authors'] = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); $package_output['version'] = array( $package->getPrettyVersion() ); + $update = 'none'; + if ( 'list' === $context ) { + $latest = $this->find_latest_package( $package, $this->get_composer(), null ); + if ( $latest ) { + $update = 'available'; + } + } + $package_output['update'] = $update; $list[ $package_output['name'] ] = $package_output; } } @@ -777,6 +797,47 @@ private function create_default_composer_json( $composer_path ) { return true; } + + /** + * Given a package, this finds the latest package matching it + * + * @param PackageInterface $package + * @param Composer $composer + * @param string $phpVersion + * @param bool $minorOnly + * + * @return PackageInterface|null + */ + private function find_latest_package( PackageInterface $package, Composer $composer, $phpVersion, $minorOnly = false ) { + // find the latest version allowed in this pool + $name = $package->getName(); + $versionSelector = new VersionSelector($this->get_pool($composer)); + $stability = $composer->getPackage()->getMinimumStability(); + $flags = $composer->getPackage()->getStabilityFlags(); + if (isset($flags[$name])) { + $stability = array_search($flags[$name], BasePackage::$stabilities, true); + } + $bestStability = $stability; + if ($composer->getPackage()->getPreferStable()) { + $bestStability = $package->getStability(); + } + $targetVersion = null; + if (0 === strpos($package->getVersion(), 'dev-')) { + $targetVersion = $package->getVersion(); + } + if ($targetVersion === null && $minorOnly) { + $targetVersion = '^' . $package->getVersion(); + } + return $versionSelector->findBestCandidate($name, $targetVersion, $phpVersion, $bestStability); + } + + private function get_pool( Composer $composer ) { + if (!$this->pool) { + $this->pool = new Pool($composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags()); + $this->pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories())); + } + return $this->pool; + } } WP_CLI::add_command( 'package', 'Package_Command' ); From 09dd104c16494e4a2a328ed20febac684f46f391 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 27 Nov 2016 07:00:06 -0800 Subject: [PATCH 5143/5359] Composer displays package update, even when it doesn't match constraint --- features/package-update.feature | 4 ++-- php/commands/package.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/package-update.feature b/features/package-update.feature index 9af909119..151d3301b 100644 --- a/features/package-update.feature +++ b/features/package-update.feature @@ -62,8 +62,8 @@ Feature: Update WP-CLI packages When I run `wp package list --fields=name,update` Then STDOUT should be a table containing rows: - | name | update | - | wp-cli/scaffold-package-command | none | + | name | update | + | wp-cli/scaffold-package-command | available | When I run `sed -i.bak s/0.1.0/\>=0.1.0/g {PACKAGE_PATH}/composer.json` Then the return code should be 0 diff --git a/php/commands/package.php b/php/commands/package.php index 57e362a02..18a8b4c82 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -601,7 +601,7 @@ private function show_packages( $context, $packages, $assoc_args ) { $update = 'none'; if ( 'list' === $context ) { $latest = $this->find_latest_package( $package, $this->get_composer(), null ); - if ( $latest ) { + if ( $latest && $latest->getFullPrettyVersion() !== $package->getFullPrettyVersion() ) { $update = 'available'; } } From 6ce6e3bf566bbcc51d7b358787b0ebc68f2c8e9b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Sun, 27 Nov 2016 08:59:48 -0800 Subject: [PATCH 5144/5359] Include `update_version` instead of `description` for installed packages --- php/commands/package.php | 53 ++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/php/commands/package.php b/php/commands/package.php index 18a8b4c82..01f15ecd8 100644 --- a/php/commands/package.php +++ b/php/commands/package.php @@ -78,13 +78,6 @@ class Package_Command extends WP_CLI_Command { const PACKAGE_INDEX_URL = 'https://wp-cli.org/package-index/'; - private $fields = array( - 'name', - 'description', - 'authors', - 'version', - ); - private $pool = false; /** @@ -109,6 +102,17 @@ class Package_Command extends WP_CLI_Command { * - yaml * --- * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each package: + * + * * name + * * description + * * authors + * * version + * + * There are no optionally available fields. + * * ## EXAMPLES * * $ wp package browse --format=yaml @@ -330,6 +334,20 @@ public function install( $args, $assoc_args ) { * - yaml * --- * + * ## AVAILABLE FIELDS + * + * These fields will be displayed by default for each package: + * + * * name + * * authors + * * version + * * update + * * update_version + * + * These fields are optionally available: + * + * * description + * * ## EXAMPLES * * $ wp package list @@ -577,12 +595,24 @@ private function package_index() { * @param array */ private function show_packages( $context, $packages, $assoc_args ) { - $fields = $this->fields; if ( 'list' === $context ) { - $fields[] = 'update'; + $default_fields = array( + 'name', + 'authors', + 'version', + 'update', + 'update_version', + ); + } else if ( 'browse' === $context ) { + $default_fields = array( + 'name', + 'description', + 'authors', + 'version', + ); } $defaults = array( - 'fields' => implode( ',', $fields ), + 'fields' => implode( ',', $default_fields ), 'format' => 'table' ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -599,13 +629,16 @@ private function show_packages( $context, $packages, $assoc_args ) { $package_output['authors'] = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); $package_output['version'] = array( $package->getPrettyVersion() ); $update = 'none'; + $update_version = ''; if ( 'list' === $context ) { $latest = $this->find_latest_package( $package, $this->get_composer(), null ); if ( $latest && $latest->getFullPrettyVersion() !== $package->getFullPrettyVersion() ) { $update = 'available'; + $update_version = $latest->getPrettyVersion(); } } $package_output['update'] = $update; + $package_output['update_version'] = $update_version; $list[ $package_output['name'] ] = $package_output; } } From 63d163734a231cf6aaf9721625b9fd6392692666 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 28 Nov 2016 16:06:46 -0800 Subject: [PATCH 5145/5359] Ensure all options tables are matched in examples Otherwise, the base site's options table won't be matched. --- php/commands/search-replace.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index bd59b4831..e442c04ba 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -33,7 +33,7 @@ class Search_Replace_Command extends WP_CLI_Command { * * [<table>...] * : List of database tables to restrict the replacement to. Wildcards are - * supported, e.g. `'wp_*_options'` or `'wp_post*'`. + * supported, e.g. `'wp_*options'` or `'wp_post*'`. * * [--dry-run] * : Run the entire search/replace operation and show report, but don't save @@ -93,7 +93,7 @@ class Search_Replace_Command extends WP_CLI_Command { * $ wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * * # Turn your production multisite database into a local dev database - * $ wp search-replace --url=example.com example.com example.dev 'wp_*_options' wp_blogs + * $ wp search-replace --url=example.com example.com example.dev 'wp_*options' wp_blogs * * # Search/replace to a SQL file without transforming the database * $ wp search-replace foo bar --export=database.sql From c4feda527468dedac22c7a29129b295e1f2e4c0c Mon Sep 17 00:00:00 2001 From: ernilambar <nilambar@outlook.com> Date: Tue, 29 Nov 2016 09:41:25 +0545 Subject: [PATCH 5146/5359] Doc improvements in option commands --- php/commands/option.php | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/php/commands/option.php b/php/commands/option.php index 880212ed2..8216d8e5e 100644 --- a/php/commands/option.php +++ b/php/commands/option.php @@ -5,28 +5,25 @@ /** * Manage options. * - * ## OPTIONS - * - * [--format=json] - * : Encode/decode values as JSON. - * * ## EXAMPLES * - * # Get site URL + * # Get site URL. * $ wp option get siteurl * http://example.com * - * # Add option + * # Add option. * $ wp option add my_option foobar * Success: Added 'my_option' option. * - * # Update option + * # Update option. * $ wp option update my_option '{"foo": "bar"}' --format=json * Success: Updated 'my_option' option. * - * # Delete option + * # Delete option. * $ wp option delete my_option * Success: Deleted 'my_option' option. + * + * @package wp-cli */ class Option_Command extends WP_CLI_Command { @@ -50,11 +47,11 @@ class Option_Command extends WP_CLI_Command { * * ## EXAMPLES * - * # Get option + * # Get option. * $ wp option get home * http://example.com * - * # Get option in JSON format + * # Get option in JSON format. * $ wp option get active_plugins --format=json * {"0":"dynamically-dynamic-sidebar\/dynamically-dynamic-sidebar.php","1":"monster-widget\/monster-widget.php","2":"show-current-template\/show-current-template.php","3":"theme-check\/theme-check.php","5":"wordpress-importer\/wordpress-importer.php"} */ @@ -102,7 +99,7 @@ public function get( $args, $assoc_args ) { * * ## EXAMPLES * - * # Create an option by reading a JSON file + * # Create an option by reading a JSON file. * $ wp option add my_option --format=json < config.json * Success: Added 'my_option' option. */ @@ -175,11 +172,11 @@ public function add( $args, $assoc_args ) { * * ## EXAMPLES * - * # Get the total size of all autoload options + * # Get the total size of all autoload options. * $ wp option list --autoload=on --format=total_bytes * 33198 * - * # Find biggest transients + * # Find biggest transients. * $ wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail * option_name size_bytes * _site_transient_timeout_theme_roots 10 @@ -188,7 +185,7 @@ public function add( $args, $assoc_args ) { * _site_transient_update_core 808 * _site_transient_update_plugins 6645 * - * # List all options begining with "i2f_" + * # List all options begining with "i2f_". * $ wp option list --search="i2f_*" * +-------------+--------------+ * | option_name | option_value | @@ -196,7 +193,7 @@ public function add( $args, $assoc_args ) { * | i2f_version | 0.1.0 | * +-------------+--------------+ * - * # Delete all options begining with "theme_mods_" + * # Delete all options begining with "theme_mods_". * $ wp option list --search="theme_mods_*" --field=option_name | xargs -I % wp option delete % * Success: Deleted 'theme_mods_twentysixteen' option. * Success: Deleted 'theme_mods_twentyfifteen' option. @@ -308,11 +305,11 @@ public function list_( $args, $assoc_args ) { * * ## EXAMPLES * - * # Update an option by reading from a file + * # Update an option by reading from a file. * $ wp option update my_option < value.txt * Success: Updated 'my_option' option. * - * # Update one option on multiple sites using xargs + * # Update one option on multiple sites using xargs. * $ wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} option update my_option my_value' * Success: Updated 'my_option' option. * Success: Updated 'my_option' option. @@ -354,6 +351,7 @@ public function update( $args, $assoc_args ) { * * ## EXAMPLES * + * # Delete an option. * $ wp option delete my_option * Success: Deleted 'my_option' option. */ From 18fea0785dbdcf564f615d64889ab7ed23f12b96 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Nov 2016 05:01:09 -0800 Subject: [PATCH 5147/5359] Persist runtime arguments when launching a new process --- features/runcommand.feature | 32 +++++++++++++++++++++++++++++++- php/class-wp-cli.php | 14 +++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index c9b3f26e5..f60b50f99 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -2,7 +2,7 @@ Feature: Run a WP-CLI command Background: - Given a WP install + Given an empty directory And a command.php file: """ <?php @@ -46,6 +46,8 @@ Feature: Run a WP-CLI command """ Scenario Outline: Run a WP-CLI command and render output + Given a WP install + When I run `wp <flag> run 'option get home'` Then STDOUT should be: """ @@ -79,6 +81,8 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Run a WP-CLI command and capture output + Given a WP install + When I run `wp run <flag> --return 'option get home'` Then STDOUT should be: """ @@ -137,6 +141,8 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Use 'parse=json' to parse JSON output + Given a WP install + When I run `wp run --return --parse=json <flag> 'user get admin --fields=user_login,user_email --format=json'` Then STDOUT should be: """ @@ -152,6 +158,8 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Exit on error by default + Given a WP install + When I try `wp run <flag> 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` Then STDOUT should be empty And STDERR should be: @@ -166,6 +174,8 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Override erroring on exit + Given a WP install + When I try `wp run <flag> --no-exit_error --return=all 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` Then STDOUT should be: """ @@ -192,6 +202,8 @@ Feature: Run a WP-CLI command | --launch | Scenario Outline: Installed packages work as expected + Given a WP install + When I run `wp package install wp-cli/scaffold-package-command` Then STDERR should be empty @@ -206,3 +218,21 @@ Feature: Run a WP-CLI command | flag | | --no-launch | | --launch | + + Scenario Outline: Persists global parameters when supplied interactively + Given a WP install in 'subdir' + + When I run `wp <flag> --path=subdir run 'rewrite structure "archives/%post_id%/" --path=subdir'` + Then STDOUT should be: + """ + Success: Rewrite rules flushed. + Success: Rewrite structure set. + returned: NULL + """ + And STDERR should be empty + And the return code should be 0 + + Examples: + | flag | + | --no-launch | + | --launch | diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 68f8efdd9..cb01825a0 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -994,7 +994,19 @@ public static function runcommand( $command, $options = array() ) { $php_bin = self::get_php_binary(); $script_path = $GLOBALS['argv'][0]; - $runcommand = "{$php_bin} {$script_path} {$command}"; + + // Persist runtime arguments unless they've been specified otherwise. + $configurator = \WP_CLI::get_configurator(); + $argv = array_slice( $GLOBALS['argv'], 1 ); + list( $_, $_, $runtime_config ) = $configurator->parse_args( $argv ); + foreach ( $runtime_config as $k => $v ) { + if ( preg_match( "|^--{$key}=?$|", $command ) ) { + unset( $runtime_config[ $k ] ); + } + } + $runtime_config = Utils\assoc_args_to_str( $runtime_config ); + + $runcommand = "{$php_bin} {$script_path} {$runtime_config} {$command}"; $env_vars = array( 'HOME', From dda825df21d01237eb04061b22defa23a699257a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Nov 2016 06:28:25 -0800 Subject: [PATCH 5148/5359] Apply backwards compat conversions when using the same process Doing so increases simularity between launching a new process and reusing an existing process. --- features/runcommand.feature | 17 +++++++++++++++++ php/WP_CLI/Runner.php | 10 +++++++--- php/class-wp-cli.php | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/features/runcommand.feature b/features/runcommand.feature index f60b50f99..9ca6402d7 100644 --- a/features/runcommand.feature +++ b/features/runcommand.feature @@ -236,3 +236,20 @@ Feature: Run a WP-CLI command | flag | | --no-launch | | --launch | + + Scenario Outline: Apply backwards compat conversions + Given a WP install + + When I run `wp <flag> run 'term url category 1'` + Then STDOUT should be: + """ + http://example.com/?cat=1 + returned: NULL + """ + And STDERR should be empty + And the return code should be 0 + + Examples: + | flag | + | --no-launch | + | --launch | diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 2d404e12b..5d52f72d6 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -288,10 +288,14 @@ public function find_command_to_run( $args ) { /** * Find the WP-CLI command to run given arguments, and invoke it. * - * @param array $args Positional arguments including command name - * @param array $assoc_args + * @param array $args Positional arguments including command name + * @param array $assoc_args Associative arguments for the command. + * @param array $options Configuration options for the function. */ - public function run_command( $args, $assoc_args = array() ) { + public function run_command( $args, $assoc_args = array(), $options = array() ) { + if ( ! empty( $options['back_compat_conversions'] ) ) { + list( $args, $assoc_args ) = self::back_compat_conversions( $args, $assoc_args ); + } $r = $this->find_command_to_run( $args ); if ( is_string( $r ) ) { WP_CLI::error( $r ); diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index cb01825a0..5eac16410 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1063,7 +1063,7 @@ public static function runcommand( $command, $options = array() ) { self::$capture_exit = true; } try { - self::get_runner()->run_command( $args, $assoc_args ); + self::get_runner()->run_command( $args, $assoc_args, array( 'back_compat_conversions' => true ) ); $return_code = 0; } catch( ExitException $e ) { $return_code = $e->getCode(); From 9bada270094a4cd2ad808c26f74915455ce5345b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Nov 2016 09:42:04 -0800 Subject: [PATCH 5149/5359] Bump stable version to 1.0.0 --- .mailmap | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 4efa4897b..8fcc7dc6b 100644 --- a/.mailmap +++ b/.mailmap @@ -84,6 +84,7 @@ Jorge A. Torres <j@jorgetorres.co> Josh Eaton <josh@josheaton.org> joshbetz <j@joshbetz.com> joshlevinson <joshalevinson@gmail.com> +Joshua Priddle <jpriddle@me.com> JQ <JeyKeu@users.noreply.github.com> KDoole <dev@Kevins-iMac.local> Keanan Koppenhaver <keanan@doejo.com> @@ -99,6 +100,7 @@ Marco <mcastelluccio@mozilla.com> marcoceppi <marco@ceppi.net> Mark Jaquith <mark.github@txfx.net> Mark Kimsal <metrofindings@gmail.com> +Mark McEver <mark@fastmail.net> matiskay <matiskay@gmail.com> mattes <matthias.kadenbach@gmail.com> mattheu <matthew@matth.eu> @@ -120,6 +122,7 @@ nacin <andrewnacin@gmail.com> Nate Wright <natew@notthisway.com> navitronic <adrian@navitronic.co.uk> nb <nb@nikolay.bg> +Ned Zimmerman <ned@bight.ca> nickdaugherty <ndaugherty987@gmail.com> nikhilc@bsf.io <nikhilc@bsf.io> nikolay <nikolay@users.noreply.github.com> @@ -136,6 +139,7 @@ om4james <james@om4.com.au> oneumyvakin <oneumyvakin@gmail.com> Otto Kekäläinen <otto@seravo.fi> ozh <ozh@ozh.org> +Patrick Karjala <pkarjala@gmail.com> Pete Nelson <pete@petenelson.com> pete@petenelson.com <petenelson@fortress.local> Peter J. Herrel <peterherrel@gmail.com> diff --git a/VERSION b/VERSION index eae71f7ff..3eefcb9dd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.26.0-alpha +1.0.0 From 6f5e33cf32ba22969e685fe556b89260bd26005f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 29 Nov 2016 22:39:07 +0100 Subject: [PATCH 5150/5359] Fix Lintian: package-contains-timestamped-gzip --- utils/wp-cli-updatedeb.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh index 371c982e8..27a81182c 100755 --- a/utils/wp-cli-updatedeb.sh +++ b/utils/wp-cli-updatedeb.sh @@ -3,7 +3,7 @@ # Package wp-cli to be installed in Debian-compatible systems. # Only the phar file is included. # -# VERSION :0.2.1 +# VERSION :0.2.2 # DATE :2016-10-26 # AUTHOR :Viktor Szépe <viktor@szepe.net> # LICENSE :The MIT License (MIT) @@ -63,7 +63,7 @@ fi if ! [ -r usr/share/doc/php-wpcli/changelog.gz ];then mkdir -p usr/share/doc/php-wpcli &> /dev/null echo "Changelog can be found in the blog: http://wp-cli.org/blog/" \ - | gzip -9 > usr/share/doc/php-wpcli/changelog.gz + | gzip -n -9 > usr/share/doc/php-wpcli/changelog.gz fi # minimal man page @@ -75,7 +75,7 @@ if ! [ -r usr/share/man/man1/wp.1.gz ];then } \ | sed 's/^\([A-Z ]\+\)$/.SH "\1"/' \ | sed 's/^ wp$/wp \\- A command line interface for WordPress/' \ - | gzip -9 > usr/share/man/man1/wp.1.gz + | gzip -n -9 > usr/share/man/man1/wp.1.gz fi # content dirs From f9cd0426327dc88061de98c2bcd58e3a3fd74b10 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 29 Nov 2016 13:56:24 -0800 Subject: [PATCH 5151/5359] Bump working version to 1.1.0-alpha --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3eefcb9dd..1c6f7dee7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.1.0-alpha From 4e285d7a758a1745da5b43af5e2f55de8a2c4087 Mon Sep 17 00:00:00 2001 From: Ramon van Belzen <Ramoonus@users.noreply.github.com> Date: Wed, 30 Nov 2016 08:03:46 +0100 Subject: [PATCH 5152/5359] travis-ci: include php 7.1 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index b811927a5..9dc1f041d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,8 @@ matrix: env: WP_VERSION=trunk - php: 7.0 env: WP_VERSION=latest + - php: 7.1 + env: WP_VERSION=latest before_script: ./ci/prepare.sh From 135ab3897c4c5ec079154870a20aec786bd36d28 Mon Sep 17 00:00:00 2001 From: Ramon van Belzen <Ramoonus@users.noreply.github.com> Date: Wed, 30 Nov 2016 08:05:39 +0100 Subject: [PATCH 5153/5359] travis-ci: cache composer --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b811927a5..d59388a85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ after_success: ./ci/deploy.sh cache: directories: - vendor + - $HOME/.composer/cache branches: only: From 88f0de1f04b7a8d6039760c09a1dae3db02dd2f2 Mon Sep 17 00:00:00 2001 From: Ramon van Belzen <Ramoonus@users.noreply.github.com> Date: Wed, 30 Nov 2016 17:44:03 +0100 Subject: [PATCH 5154/5359] travis: ignore php 7.1 failures --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9dc1f041d..de2d1a044 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,9 @@ matrix: env: WP_VERSION=latest - php: 7.1 env: WP_VERSION=latest + + allow_failures: + - php: 7.1 before_script: ./ci/prepare.sh From d7bedc5ab07e24ddf6564fef257aba49750ab87a Mon Sep 17 00:00:00 2001 From: Ramon van Belzen <Ramoonus@users.noreply.github.com> Date: Wed, 30 Nov 2016 17:53:44 +0100 Subject: [PATCH 5155/5359] Update .travis.yml fixing the lintworm --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index de2d1a044..597c6d4b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ env: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar matrix: + allow_failures: + - php: 7.1 include: - php: 5.3 env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master @@ -22,9 +24,6 @@ matrix: env: WP_VERSION=latest - php: 7.1 env: WP_VERSION=latest - - allow_failures: - - php: 7.1 before_script: ./ci/prepare.sh From 63bdc4716e54907fbef051492f33f9c8621e9b1e Mon Sep 17 00:00:00 2001 From: Stef Thoen <stef@baardbaard.nl> Date: Thu, 1 Dec 2016 09:18:46 +0100 Subject: [PATCH 5156/5359] Adds missing comma to runcommand documentation --- php/class-wp-cli.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 5eac16410..a4c58939b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -949,10 +949,10 @@ public static function get_config( $key = null ) { * * ``` * $options = array( - * 'return' => true, // Return 'STDOUT'; use 'all' for full object. - * 'parse' => 'json' // Parse captured STDOUT to JSON array. - * 'launch' => false, // Reuse the current process. - * 'exit_error' => true, // Halt script execution on error. + * 'return' => true, // Return 'STDOUT'; use 'all' for full object. + * 'parse' => 'json', // Parse captured STDOUT to JSON array. + * 'launch' => false, // Reuse the current process. + * 'exit_error' => true, // Halt script execution on error. * ); * $plugins = WP_CLI::runcommand( 'plugin list --format=json', $options ); * ``` From 94fcae034601f966eaca81872fa791e608cef0ab Mon Sep 17 00:00:00 2001 From: Miguel de Moura <migueldemoura@users.noreply.github.com> Date: Fri, 2 Dec 2016 00:59:46 +0000 Subject: [PATCH 5157/5359] Improve docs on the "site option" command Emphasize difference between "site option" and "option" --- php/commands/site-option.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/site-option.php b/php/commands/site-option.php index 5ee1b3b06..9d1a832a3 100644 --- a/php/commands/site-option.php +++ b/php/commands/site-option.php @@ -1,7 +1,7 @@ <?php /** - * Manage site options. + * Manage site options in a multisite install. * * ## EXAMPLES * From 46349379bea20daee11ac1ca925c82db5d572f2d Mon Sep 17 00:00:00 2001 From: Dominik Schilling <dominikschilling+git@gmail.com> Date: Fri, 2 Dec 2016 13:11:50 +0100 Subject: [PATCH 5158/5359] Add a blank line before the list in DocBlock of `WP_CLI::runcommand()`. --- php/class-wp-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index a4c58939b..79b6019f4 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -943,6 +943,7 @@ public static function get_config( $key = null ) { * * Launch a new child process, or run the command in the current process. * Optionally: + * * * Prevent halting script execution on error. * * Capture and return STDOUT, or full details about command execution. * * Parse JSON output if the command rendered it. From 433805b00449d5399002ed9ad2431daee8788755 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Sun, 4 Dec 2016 14:08:31 -0500 Subject: [PATCH 5159/5359] fix undefined variable --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 79b6019f4..4cd1d7ba3 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1001,7 +1001,7 @@ public static function runcommand( $command, $options = array() ) { $argv = array_slice( $GLOBALS['argv'], 1 ); list( $_, $_, $runtime_config ) = $configurator->parse_args( $argv ); foreach ( $runtime_config as $k => $v ) { - if ( preg_match( "|^--{$key}=?$|", $command ) ) { + if ( preg_match( "|^--{$k}=?$|", $command ) ) { unset( $runtime_config[ $k ] ); } } From 70e0be2f238ac59b4794cc3ef040ca0abdac268d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 5 Dec 2016 06:44:01 -0800 Subject: [PATCH 5160/5359] Detect W3 Total Cache object cache --- php/utils-wp.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index 24a78b3a1..0203c962f 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -207,6 +207,13 @@ function wp_get_cache_type() { } elseif ( isset( $wp_object_cache->lcache ) && is_a( $wp_object_cache->lcache, '\LCache\Integrated' ) ) { $message = 'WP LCache'; + } elseif( function_exists( 'w3_instance' ) ) { + $config = w3_instance( 'W3_Config' ); + if ( $config->get_boolean( 'objectcache.enabled' ) ) { + $message = 'W3TC ' . $config->get_string( 'objectcache.engine' ); + } else { + $message = 'Unknown'; + } } else { $message = 'Unknown'; } From a6387c329a1b9eacea1c3bd7974ec9c30b684b19 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 5 Dec 2016 06:46:26 -0800 Subject: [PATCH 5161/5359] Update Composer dependencies 12/5/2016 ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.13) - Installing symfony/yaml (v2.8.14) Downloading: 100% - Removing symfony/filesystem (v2.8.13) - Installing symfony/filesystem (v2.8.14) Loading from cache - Removing symfony/config (v2.8.13) - Installing symfony/config (v2.8.14) Downloading: 100% - Removing symfony/debug (v2.8.13) - Installing symfony/debug (v2.8.14) Downloading: 100% - Removing symfony/dependency-injection (v2.8.13) - Installing symfony/dependency-injection (v2.8.14) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.13) - Installing symfony/event-dispatcher (v2.8.14) Loading from cache - Removing symfony/polyfill-mbstring (v1.2.0) - Installing symfony/polyfill-mbstring (v1.3.0) Downloading: 100% - Removing symfony/translation (v2.8.13) - Installing symfony/translation (v2.8.14) Downloading: 100% - Removing symfony/process (v2.8.13) - Installing symfony/process (v2.8.14) Loading from cache - Removing symfony/finder (v2.8.13) - Installing symfony/finder (v2.8.14) Downloading: 100% - Removing symfony/console (v2.8.13) - Installing symfony/console (v2.8.14) Downloading: 100% - Removing seld/jsonlint (1.4.1) - Installing seld/jsonlint (1.5.0) Downloading: 100% - Removing composer/composer (1.2.2) - Installing composer/composer (1.2.3) Downloading: 100% - Removing phpunit/php-file-iterator (1.4.1) - Installing phpunit/php-file-iterator (1.4.2) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 118 +++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/composer.lock b/composer.lock index 05501fd11..ca226dec8 100644 --- a/composer.lock +++ b/composer.lock @@ -67,16 +67,16 @@ }, { "name": "composer/composer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "5465af955800fa884a36f66ff65280584988efd0" + "reference": "e7f19286a7e7f940950c9069a0f549d483c30ba7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/5465af955800fa884a36f66ff65280584988efd0", - "reference": "5465af955800fa884a36f66ff65280584988efd0", + "url": "https://api.github.com/repos/composer/composer/zipball/e7f19286a7e7f940950c9069a0f549d483c30ba7", + "reference": "e7f19286a7e7f940950c9069a0f549d483c30ba7", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2016-11-03 16:43:15" + "time": "2016-12-01 13:33:53" }, { "name": "composer/semver", @@ -659,16 +659,16 @@ }, { "name": "seld/jsonlint", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70" + "reference": "19495c181d6d53a0a13414154e52817e3b504189" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e827b5254d3e58c736ea2c5616710983d80b0b70", - "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/19495c181d6d53a0a13414154e52817e3b504189", + "reference": "19495c181d6d53a0a13414154e52817e3b504189", "shasum": "" }, "require": { @@ -701,7 +701,7 @@ "parser", "validator" ], - "time": "2016-09-14 15:17:56" + "time": "2016-11-14 17:59:58" }, { "name": "seld/phar-utils", @@ -749,16 +749,16 @@ }, { "name": "symfony/config", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde" + "reference": "1361bc4e66f97b6202ae83f4190e962c624b5e61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f8b1922bbda9d2ac86aecd649399040bce849fde", - "reference": "f8b1922bbda9d2ac86aecd649399040bce849fde", + "url": "https://api.github.com/repos/symfony/config/zipball/1361bc4e66f97b6202ae83f4190e962c624b5e61", + "reference": "1361bc4e66f97b6202ae83f4190e962c624b5e61", "shasum": "" }, "require": { @@ -798,20 +798,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-09-14 20:31:12" + "time": "2016-11-03 07:52:58" }, { "name": "symfony/console", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "7350016c8abcab897046f1aead2b766b84d3eff8" + "reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/7350016c8abcab897046f1aead2b766b84d3eff8", - "reference": "7350016c8abcab897046f1aead2b766b84d3eff8", + "url": "https://api.github.com/repos/symfony/console/zipball/a871ba00e0f604dceac64c56c27f99fbeaf4854e", + "reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e", "shasum": "" }, "require": { @@ -859,20 +859,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-10-06 01:43:09" + "time": "2016-11-15 23:02:12" }, { "name": "symfony/debug", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "8c29235936a47473af16fb91c7c4b7b193c5693c" + "reference": "62a68f640456f6761d752c62d81631428ef0d8a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/8c29235936a47473af16fb91c7c4b7b193c5693c", - "reference": "8c29235936a47473af16fb91c7c4b7b193c5693c", + "url": "https://api.github.com/repos/symfony/debug/zipball/62a68f640456f6761d752c62d81631428ef0d8a1", + "reference": "62a68f640456f6761d752c62d81631428ef0d8a1", "shasum": "" }, "require": { @@ -916,20 +916,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-09-06 10:55:00" + "time": "2016-11-15 12:53:17" }, { "name": "symfony/dependency-injection", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "3d61c765daa1a5832f1d7c767f48886b8d8ea64c" + "reference": "9d2c5033ca70ceade8d7584f997a9d3943f0fe5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3d61c765daa1a5832f1d7c767f48886b8d8ea64c", - "reference": "3d61c765daa1a5832f1d7c767f48886b8d8ea64c", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9d2c5033ca70ceade8d7584f997a9d3943f0fe5f", + "reference": "9d2c5033ca70ceade8d7584f997a9d3943f0fe5f", "shasum": "" }, "require": { @@ -979,11 +979,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-10-24 15:52:36" + "time": "2016-11-18 21:10:01" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -1043,7 +1043,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -1092,16 +1092,16 @@ }, { "name": "symfony/finder", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "bc24c8f5674c6f6841f2856b70e5d60784be5691" + "reference": "0023b024363dfc0cd21262e556f25a291fe8d7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/bc24c8f5674c6f6841f2856b70e5d60784be5691", - "reference": "bc24c8f5674c6f6841f2856b70e5d60784be5691", + "url": "https://api.github.com/repos/symfony/finder/zipball/0023b024363dfc0cd21262e556f25a291fe8d7fd", + "reference": "0023b024363dfc0cd21262e556f25a291fe8d7fd", "shasum": "" }, "require": { @@ -1137,20 +1137,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-09-28 00:10:16" + "time": "2016-11-03 07:52:58" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "dff51f72b0706335131b00a7f49606168c582594" + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", - "reference": "dff51f72b0706335131b00a7f49606168c582594", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", "shasum": "" }, "require": { @@ -1162,7 +1162,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1196,11 +1196,11 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/process", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -1249,16 +1249,16 @@ }, { "name": "symfony/translation", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "cca6ff892355876534b01a927f789bac9601c935" + "reference": "edbe67e8f729885b55421d5cc58223d48540df07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/cca6ff892355876534b01a927f789bac9601c935", - "reference": "cca6ff892355876534b01a927f789bac9601c935", + "url": "https://api.github.com/repos/symfony/translation/zipball/edbe67e8f729885b55421d5cc58223d48540df07", + "reference": "edbe67e8f729885b55421d5cc58223d48540df07", "shasum": "" }, "require": { @@ -1309,20 +1309,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-10-18 04:28:30" + "time": "2016-11-18 21:10:01" }, { "name": "symfony/yaml", - "version": "v2.8.13", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "396784cd06b91f3db576f248f2402d547a077787" + "reference": "befb26a3713c97af90d25dd12e75621ef14d91ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/396784cd06b91f3db576f248f2402d547a077787", - "reference": "396784cd06b91f3db576f248f2402d547a077787", + "url": "https://api.github.com/repos/symfony/yaml/zipball/befb26a3713c97af90d25dd12e75621ef14d91ff", + "reference": "befb26a3713c97af90d25dd12e75621ef14d91ff", "shasum": "" }, "require": { @@ -1358,7 +1358,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-10-21 20:59:10" + "time": "2016-11-14 16:15:57" }, { "name": "wp-cli/php-cli-tools", @@ -1598,16 +1598,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": { @@ -1641,7 +1641,7 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", From 16ee596a33e309c93ae12a46705089fbacc5a3f4 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 5 Dec 2016 07:05:44 -0800 Subject: [PATCH 5162/5359] Support passing modifiers to regex search-replace --- features/search-replace.feature | 25 +++++++++++++++++++++++++ php/WP_CLI/SearchReplacer.php | 5 +++-- php/commands/search-replace.php | 13 +++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/features/search-replace.feature b/features/search-replace.feature index 55b76ef39..e23581d38 100644 --- a/features/search-replace.feature +++ b/features/search-replace.feature @@ -310,3 +310,28 @@ Feature: Do global search/replace | input | | a:1:{s:3:"bar";s:3:"foo";} | | O:8:"stdClass":1:{s:1:"a";s:3:"foo";} | + + Scenario: Search replace with a regex flag + Given a WP install + + When I run `wp search-replace 'EXAMPLE.com' 'BAXAMPLE.com' wp_options --regex` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 0 | PHP | + + When I run `wp option get home` + Then STDOUT should be: + """ + http://example.com + """ + + When I run `wp search-replace 'EXAMPLE.com' 'BAXAMPLE.com' wp_options --regex --regex-flags=i` + Then STDOUT should be a table containing rows: + | Table | Column | Replacements | Type | + | wp_options | option_value | 5 | PHP | + + When I run `wp option get home` + Then STDOUT should be: + """ + http://BAXAMPLE.com + """ diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index d832ed2b3..c8f9b7577 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -13,11 +13,12 @@ class SearchReplacer { * @param string $to What we want it to be replaced with. * @param bool $recurse_objects Should objects be recursively replaced? */ - function __construct( $from, $to, $recurse_objects = false, $regex = false ) { + function __construct( $from, $to, $recurse_objects = false, $regex = false, $regex_flags = '' ) { $this->from = $from; $this->to = $to; $this->recurse_objects = $recurse_objects; $this->regex = $regex; + $this->regex_flags = $regex_flags; // Get the XDebug nesting level. Will be zero (no limit) if no value is set $this->max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); @@ -82,7 +83,7 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data else if ( is_string( $data ) ) { if ( $this->regex ) { - $data = preg_replace( "/$this->from/", $this->to, $data ); + $data = preg_replace( "/$this->from/$this->regex_flags", $this->to, $data ); } else { $data = str_replace( $this->from, $this->to, $data ); } diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index e442c04ba..ab57a1db0 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -7,6 +7,7 @@ class Search_Replace_Command extends WP_CLI_Command { private $export_insert_size; private $recurse_objects; private $regex; + private $regex_flags; private $skip_columns; private $include_columns; @@ -84,6 +85,9 @@ class Search_Replace_Command extends WP_CLI_Command { * : Runs the search using a regular expression. Warning: search-replace * will take about 15-20x longer when using --regex. * + * [--regex-flags=<regex-flags>] + * : Pass PCRE modifiers to regex search-replace (e.g. 'i' for case-insensitivity). + * * ## EXAMPLES * * # Search and replace but skip one column @@ -117,6 +121,7 @@ public function __invoke( $args, $assoc_args ) { $this->recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); $this->verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); $this->regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); + $this->regex_flags = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex-flags' ); $this->skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); $this->include_columns = array_filter( explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-columns' ) ) ); @@ -146,6 +151,10 @@ public function __invoke( $args, $assoc_args ) { $php_only = true; } + if ( $this->regex_flags ) { + $php_only = true; + } + // never mess with hashed passwords $this->skip_columns[] = 'user_pass'; @@ -250,7 +259,7 @@ private function php_export_table( $table, $old, $new ) { 'chunk_size' => $chunk_size ); - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex ); + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex, $this->regex_flags ); $col_counts = array_fill_keys( $all_columns, 0 ); if ( $this->verbose ) { $this->start_time = microtime( true ); @@ -313,7 +322,7 @@ private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { global $wpdb; $count = 0; - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex ); + $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex, $this->regex_flags ); $where = $this->regex ? '' : " WHERE `$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ); $primary_keys_sql = esc_sql( implode( ',', $primary_keys ) ); From b5df9222741abd8d2c95ff4c63346ff21ce5ab47 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 6 Dec 2016 21:21:03 +0545 Subject: [PATCH 5163/5359] Introduce field parameter for theme mod get --- php/commands/theme-mod.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/php/commands/theme-mod.php b/php/commands/theme-mod.php index 7cc4b9cee..22acea271 100644 --- a/php/commands/theme-mod.php +++ b/php/commands/theme-mod.php @@ -19,6 +19,11 @@ */ class Theme_Mod_command extends WP_CLI_Command { + private $fields = array( + 'key', + 'value' + ); + /** * Get one or more theme mods. * @@ -27,6 +32,9 @@ class Theme_Mod_command extends WP_CLI_Command { * [<mod>...] * : One or more mods to get. * + * [--field=<field>] + * : Returns the value of a single field. + * * [--all] * : List all theme mods * @@ -43,7 +51,7 @@ class Theme_Mod_command extends WP_CLI_Command { * * ## EXAMPLES * - * # Get all theme mods + * # Get all theme mods. * $ wp theme mod get --all * +------------------+---------+ * | key | value | @@ -53,11 +61,15 @@ class Theme_Mod_command extends WP_CLI_Command { * | main_text_color | #8224e3 | * +------------------+---------+ * - * # Get single theme mod in JSON format + * # Get single theme mod in JSON format. * $ wp theme mod get background_color --format=json * [{"key":"background_color","value":"dd3333"}] * - * # Get multiple theme mods + * # Get value of a single theme mod. + * $ wp theme mod get background_color --field=value + * dd3333 + * + * # Get multiple theme mods. * $ wp theme mod get background_color header_textcolor * +------------------+--------+ * | key | value | @@ -104,7 +116,7 @@ public function get( $args = array(), $assoc_args = array() ) { } } - $formatter = new \WP_CLI\Formatter( $assoc_args, array('key', 'value'), 'thememods' ); + $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields, 'thememods' ); $formatter->display_items( $list ); } From 45e106f71ab8e6f0756b0965d4780bb02c4c0138 Mon Sep 17 00:00:00 2001 From: Nilambar Sharma <nilambar@outlook.com> Date: Tue, 6 Dec 2016 21:29:19 +0545 Subject: [PATCH 5164/5359] Add test to reflect introduction of field in theme mod get --- features/theme-mod.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/theme-mod.feature b/features/theme-mod.feature index 1d014d491..270be05b4 100644 --- a/features/theme-mod.feature +++ b/features/theme-mod.feature @@ -19,6 +19,12 @@ Feature: Manage WordPress theme mods | key | value | | background_color | 123456 | + When I run `wp theme mod get background_color --field=value` + Then STDOUT should be: + """ + 123456 + """ + When I run `wp theme mod set background_color 123456` And I run `wp theme mod get background_color header_textcolor` Then STDOUT should be a table containing rows: From 4f909259bb8af1825f8445289cb782f94e056c68 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 10:31:08 -0800 Subject: [PATCH 5165/5359] Support `--version=(nightly|trunk)` for `wp core update` Don't ever cache it, however. --- features/core-update.feature | 19 +++++++++++++++++++ php/WP_CLI/CoreUpgrader.php | 6 ++++-- php/commands/core.php | 9 +++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/features/core-update.feature b/features/core-update.feature index 1d6be5f83..0fdd7deee 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -215,3 +215,22 @@ Feature: Update WordPress core """ Success: WordPress updated successfully. """ + + Scenario Outline: Use `--version=(nightly|trunk)` to update to the latest nightly version + Given a WP install + + When I run `wp core update --version=<version>` + Then STDOUT should contain: + """ + Updating to version nightly (en_US)... + Downloading update from https://wordpress.org/nightly-builds/wordpress-latest.zip... + """ + And STDOUT should contain: + """ + Success: WordPress updated successfully. + """ + + Examples: + | version | + | trunk | + | nightly | diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php index 2ae9222e9..c3ecad2d2 100644 --- a/php/WP_CLI/CoreUpgrader.php +++ b/php/WP_CLI/CoreUpgrader.php @@ -55,7 +55,7 @@ public function download_package( $package ) { $cache_key = "core/{$filename}-{$update->locale}.{$ext}"; $cache_file = $cache->has( $cache_key ); - if ( $cache_file ) { + if ( $cache_file && false === stripos( $package, 'https://wordpress.org/nightly-builds/' ) ) { WP_CLI::log( "Using cached file '$cache_file'..." ); copy( $cache_file, $temp ); return $temp; @@ -77,7 +77,9 @@ public function download_package( $package ) { if ( ! is_null( $req ) && $req->status_code !== 200 ) { return new \WP_Error( 'download_failed', $this->strings['download_failed'] ); } - $cache->import( $cache_key, $temp ); + if ( false === stripos( $package, 'https://wordpress.org/nightly-builds/' ) ) { + $cache->import( $cache_key, $temp ); + } return $temp; } } diff --git a/php/commands/core.php b/php/commands/core.php index 3abdda443..b6de91c19 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1178,12 +1178,16 @@ private static function get_core_checksums( $version, $locale ) { * * @alias upgrade */ - function update( $args, $assoc_args ) { + public function update( $args, $assoc_args ) { global $wp_version; $update = $from_api = null; $upgrader = 'WP_CLI\\CoreUpgrader'; + if ( 'trunk' === Utils\get_flag_value( $assoc_args, 'version' ) ) { + $assoc_args['version'] = 'nightly'; + } + if ( ! empty( $args[0] ) ) { $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; @@ -1228,7 +1232,8 @@ function update( $args, $assoc_args ) { } } else if ( \WP_CLI\Utils\wp_version_compare( $assoc_args['version'], '<' ) - || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { + || 'nightly' === $assoc_args['version'] + || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { $version = $assoc_args['version']; $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); From 4091640be22945370a2a424b055a5b8eb6454fa3 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 12:11:28 -0800 Subject: [PATCH 5166/5359] Update test suite for WordPress 4.7 --- features/core-check-update.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index ae17608db..6abfca4bb 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,7 +9,7 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.6.1 | major | https://downloads.wordpress.org/release/wordpress-4.6.1.zip | + | 4.7 | major | https://downloads.wordpress.org/release/wordpress-4.7.zip | | 4.4.5 | minor | https://downloads.wordpress.org/release/wordpress-4.4.5-partial-0.zip | When I run `wp core check-update --format=count` @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.6.1 | major | https://downloads.wordpress.org/release/wordpress-4.6.1.zip | + | 4.7 | major | https://downloads.wordpress.org/release/wordpress-4.7.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: From 3b1c0cf507ce087d8ba3424860ac2ec08f5d38c8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 13:50:30 -0800 Subject: [PATCH 5167/5359] Drop PHP 7.1 from allowed_failures --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5af398c02..b46b5e5e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ env: - WP_CLI_BIN_DIR=/tmp/wp-cli-phar matrix: - allow_failures: - - php: 7.1 include: - php: 5.3 env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master From b00cab994d2a424ac7d78cd781c10f6017d635b5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 15:22:25 -0800 Subject: [PATCH 5168/5359] Mention 'nightly` argument --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index b6de91c19..8fae93030 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1138,7 +1138,7 @@ private static function get_core_checksums( $version, $locale ) { * : Only perform updates for minor releases (e.g. update from WP 4.3 to 4.3.3 instead of 4.4.2). * * [--version=<version>] - * : Update to a specific version, instead of to the latest version. + * : Update to a specific version, instead of to the latest version. Alternatively accepts 'nightly'. * * [--force] * : Update even when installed WP version is greater than the requested version. From 61a809230974c0a405fda0a33f7d53401796c2bc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 17:27:27 -0800 Subject: [PATCH 5169/5359] Fix merge behavior when positionals passed and also defined in `wp-cli.yml` The passed positionals should take precedent over defaults defined in `wp-cli.yml` --- features/config.feature | 15 +++++++++++++++ php/WP_CLI/Dispatcher/Subcommand.php | 6 ++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/features/config.feature b/features/config.feature index d5db20844..a22572b56 100644 --- a/features/config.feature +++ b/features/config.feature @@ -175,6 +175,21 @@ Feature: Have a config file administrator """ + When I try `wp user create examplejane` + Then STDERR should be: + """ + Error: Sorry, that email address is already used! + """ + + When I run `wp user create examplejane jane@example.com` + Then STDOUT should not be empty + + When I run `wp user get examplejane --field=roles` + Then STDOUT should contain: + """ + administrator + """ + Scenario: Command-specific configs Given a WP install And a wp-cli.yml file: diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index 4d394ff25..2dd6b2750 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -364,11 +364,13 @@ public function invoke( $args, $assoc_args, $extra_args ) { $extra_positionals = array(); foreach( $extra_args as $k => $v ) { if ( is_numeric( $k ) ) { - $extra_positionals[ $k ] = $v; + if ( ! isset( $args[ $k ] ) ) { + $extra_positionals[ $k ] = $v; + } unset( $extra_args[ $k ] ); } } - $args = array_merge( $extra_positionals, $args ); + $args = $args + $extra_positionals; list( $to_unset, $args, $assoc_args, $extra_args ) = $this->validate_args( $args, $assoc_args, $extra_args ); From 878ecc4d7a61a6866be3bad59a24c45df12cd338 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 6 Dec 2016 17:30:04 -0800 Subject: [PATCH 5170/5359] Update version in `wp --info` example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 982a4b439..278deb47a 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ WP-CLI root dir: /home/wp-cli/.wp-cli WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ WP-CLI global config: /home/wp-cli/.wp-cli/config.yml WP-CLI project config: -WP-CLI version: 0.25.0 +WP-CLI version: 1.0.0 ``` ### Updating From d85190649e3c3513715bf0283308cf07686ab970 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 12 Dec 2016 06:08:01 -0800 Subject: [PATCH 5171/5359] Update `wpmu_upgrade_site` for all networks, not just current --- features/core-update-db.feature | 22 ++++++++++++++++++++++ php/commands/core.php | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/features/core-update-db.feature b/features/core-update-db.feature index 176024c19..cf4f315f5 100644 --- a/features/core-update-db.feature +++ b/features/core-update-db.feature @@ -37,6 +37,9 @@ Feature: Update core's database Scenario: Update db across network Given a WP multisite install + And I run `wp core download --version=4.1 --force` + And I run `wp option update db_version 29630` + And I run `wp site option update wpmu_upgrade_site 29630` And I run `wp site create --slug=foo` And I run `wp site create --slug=bar` And I run `wp site create --slug=burrito --porcelain` @@ -49,16 +52,26 @@ Feature: Update core's database And I run `wp site spam {TACO_ID}` And I run `wp site delete {PIZZA_ID} --yes` + When I run `wp site option get wpmu_upgrade_site` + Then save STDOUT as {UPDATE_VERSION} + When I run `wp core update-db --network` Then STDOUT should contain: """ Success: WordPress database upgraded on 3/3 sites. """ + When I run `wp site option get wpmu_upgrade_site` + Then STDOUT should not contain: + """ + {UPDATE_VERSION} + """ + Scenario: Update db across network, dry run Given a WP multisite install And I run `wp core download --version=4.1 --force` And I run `wp option update db_version 29630` + And I run `wp site option update wpmu_upgrade_site 29630` And I run `wp site create --slug=foo` And I run `wp site create --slug=bar` And I run `wp site create --slug=burrito --porcelain` @@ -71,6 +84,9 @@ Feature: Update core's database And I run `wp site spam {TACO_ID}` And I run `wp site delete {PIZZA_ID} --yes` + When I run `wp site option get wpmu_upgrade_site` + Then save STDOUT as {UPDATE_VERSION} + When I run `wp core update-db --network --dry-run` Then STDOUT should contain: """ @@ -89,6 +105,12 @@ Feature: Update core's database Success: WordPress database upgraded on 3/3 sites. """ + When I run `wp site option get wpmu_upgrade_site` + Then STDOUT should contain: + """ + {UPDATE_VERSION} + """ + Scenario: Ensure update-db sets WP_INSTALLING constant Given a WP install And a before.php file: diff --git a/php/commands/core.php b/php/commands/core.php index 8fae93030..b48a38fb2 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1339,8 +1339,10 @@ function update_db( $_, $assoc_args ) { ); $it = new \WP_CLI\Iterators\Table( $iterator_args ); $success = $total = 0; + $site_ids = array(); foreach( $it as $blog ) { $total++; + $site_ids[] = $blog->site_id; $url = $blog->domain . $blog->path; $cmd = "--url={$url} core update-db"; if ( $dry_run ) { @@ -1362,7 +1364,9 @@ function update_db( $_, $assoc_args ) { } } if ( ! $dry_run && $total && $success == $total ) { - update_site_option( 'wpmu_upgrade_site', $wp_db_version ); + foreach( array_unique( $site_ids ) as $site_id ) { + update_metadata( 'site', $site_id, 'wpmu_upgrade_site', $wp_db_version ); + } } WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); } else { From b839f6dfb3e1b6f5dc300853e263bf0d625a4cb7 Mon Sep 17 00:00:00 2001 From: Kailey Lampert <trepmal@gmail.com> Date: Tue, 13 Dec 2016 11:18:43 -0800 Subject: [PATCH 5172/5359] Just whitespace for consistent indentation --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 77b80bb02..3202c227c 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -462,7 +462,7 @@ private function get_output_path( $assoc_args, $subdir ) { * options: * - travis * - circle - * - gitlab + * - gitlab * --- * * [--activate] From 04290f650f451b8e627e1fb7aa404cbc7fa068e3 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 01:08:33 +0900 Subject: [PATCH 5173/5359] add validation for plugin/theme --- php/commands/scaffold.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 3202c227c..91a667e90 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -648,6 +648,9 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( ! empty( $args[0] ) ) { $slug = $args[0]; + if ( ! preg_match( "/^[a-zA-Z0-9\-_]+$/", $slug ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { From ee125adee4b0714fd8a42db9b5a0607bfc97a13b Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 02:00:29 +0900 Subject: [PATCH 5174/5359] ensure the target directory isn't wp-content/plugins or wp-content/themes --- features/scaffold-plugin-tests.feature | 9 +++++++++ features/scaffold-theme-tests.feature | 7 +++++++ php/commands/scaffold.php | 8 +++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/features/scaffold-plugin-tests.feature b/features/scaffold-plugin-tests.feature index 5932f0356..26dfebb41 100644 --- a/features/scaffold-plugin-tests.feature +++ b/features/scaffold-plugin-tests.feature @@ -93,3 +93,12 @@ Feature: Scaffold plugin unit tests """ MYSQL_DATABASE """ + + Scenario: Scaffold plugin tests with invalid slug + Given a WP install + + When I try `wp scaffold plugin-tests .` + Then STDERR should contain: + """ + Error: Invalid plugin slug specified. + """ diff --git a/features/scaffold-theme-tests.feature b/features/scaffold-theme-tests.feature index e10bb3076..ae4e8231a 100644 --- a/features/scaffold-theme-tests.feature +++ b/features/scaffold-theme-tests.feature @@ -73,3 +73,10 @@ Feature: Scaffold theme unit tests """ MYSQL_DATABASE """ + + Scenario: Scaffold theme tests with invalid slug + When I try `wp scaffold theme-tests .` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 91a667e90..05d051f43 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -648,9 +648,6 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( ! empty( $args[0] ) ) { $slug = $args[0]; - if ( ! preg_match( "/^[a-zA-Z0-9\-_]+$/", $slug ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { @@ -666,6 +663,11 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { } } + if ( ( 'plugin' === $type && realpath( $target_dir ) === WP_PLUGIN_DIR ) + || ( 'theme' === $type && realpath( $target_dir ) === WP_CONTENT_DIR . '/themes' ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } + if ( ! empty( $assoc_args['dir'] ) ) { $target_dir = $assoc_args['dir']; if ( ! is_dir( $target_dir ) ) { From 16499fb126aa596f98fe073d13361048eb168578 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 02:18:41 +0900 Subject: [PATCH 5175/5359] reject . and / --- php/commands/scaffold.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 05d051f43..717c4be2e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -648,6 +648,9 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( ! empty( $args[0] ) ) { $slug = $args[0]; + if ( preg_match( "#\.|\/#", $slug ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { @@ -663,11 +666,6 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { } } - if ( ( 'plugin' === $type && realpath( $target_dir ) === WP_PLUGIN_DIR ) - || ( 'theme' === $type && realpath( $target_dir ) === WP_CONTENT_DIR . '/themes' ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } - if ( ! empty( $assoc_args['dir'] ) ) { $target_dir = $assoc_args['dir']; if ( ! is_dir( $target_dir ) ) { From 548c869193c6b34c3151e37bdecd78910a9f21d5 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman <ned@bight.ca> Date: Wed, 14 Dec 2016 14:23:00 -0400 Subject: [PATCH 5176/5359] Add documentation for hidden 'wp site list' param. --- php/commands/site.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/commands/site.php b/php/commands/site.php index 13d4ba411..76f7a1085 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -435,6 +435,9 @@ private function _get_network( $network_id ) { * : Filter by one or more fields (see "Available Fields" section). However, * 'url' isn't an available filter, because it's created from domain + path. * + * [--site__in=<value>] + * : Only list the sites with these blog_id values (comma-separated). + * * [--field=<field>] * : Prints the value of a single field for each site. * From 6b5aa8917687a16c6a382f7e1e3750cb1b06e103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Wed, 14 Dec 2016 22:30:11 +0100 Subject: [PATCH 5177/5359] Point out where core update goes It took me long minutes to understand. --- php/commands/core.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index b48a38fb2..8143aaa27 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1190,6 +1190,7 @@ public function update( $args, $assoc_args ) { if ( ! empty( $args[0] ) ) { + // ZIP path or URL is given $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; $version = \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ); @@ -1209,6 +1210,7 @@ public function update( $args, $assoc_args ) { } else if ( empty( $assoc_args['version'] ) ) { + // Update to next release wp_version_check(); $from_api = get_site_transient( 'update_core' ); @@ -1235,6 +1237,7 @@ public function update( $args, $assoc_args ) { || 'nightly' === $assoc_args['version'] || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { + // Specific version is given $version = $assoc_args['version']; $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); @@ -1256,7 +1259,8 @@ public function update( $args, $assoc_args ) { } - if ( ! empty( $update ) && ( $update->version != $wp_version || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) ) { + if ( ! empty( $update ) + && ( $update->version != $wp_version || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) ) { require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); From 86cce4345d2ab6bfaba6e8f959759f8044454a65 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 13:49:14 +0900 Subject: [PATCH 5178/5359] use basename() and dirname() to check target dirctory --- features/scaffold-plugin-tests.feature | 6 ++++++ features/scaffold-theme-tests.feature | 8 ++++++++ php/commands/scaffold.php | 8 +++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/features/scaffold-plugin-tests.feature b/features/scaffold-plugin-tests.feature index 26dfebb41..723358393 100644 --- a/features/scaffold-plugin-tests.feature +++ b/features/scaffold-plugin-tests.feature @@ -102,3 +102,9 @@ Feature: Scaffold plugin unit tests """ Error: Invalid plugin slug specified. """ + + When I try `wp scaffold plugin-tests ../` + Then STDERR should contain: + """ + Error: Invalid plugin slug specified. + """ diff --git a/features/scaffold-theme-tests.feature b/features/scaffold-theme-tests.feature index ae4e8231a..c4919e860 100644 --- a/features/scaffold-theme-tests.feature +++ b/features/scaffold-theme-tests.feature @@ -75,8 +75,16 @@ Feature: Scaffold theme unit tests """ Scenario: Scaffold theme tests with invalid slug + When I try `wp scaffold theme-tests .` Then STDERR should contain: """ Error: Invalid theme slug specified. """ + + When I try `wp scaffold theme-tests ../` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ + diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 717c4be2e..8e72a2c8b 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -648,9 +648,6 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( ! empty( $args[0] ) ) { $slug = $args[0]; - if ( preg_match( "#\.|\/#", $slug ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { @@ -666,6 +663,11 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { } } + if ( ( "theme" === $type && 'themes' !== basename( dirname( realpath( $target_dir ) ) ) ) + || ( "plugin" === $type && 'plugins' !== basename( dirname( realpath( $target_dir ) ) ) ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } + if ( ! empty( $assoc_args['dir'] ) ) { $target_dir = $assoc_args['dir']; if ( ! is_dir( $target_dir ) ) { From 9fb03f130b3c1c8a5ab2e6a9106dca74bbb54d24 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 15:09:57 +0900 Subject: [PATCH 5179/5359] add tests for scaffold plugin/theme --- features/scaffold.feature | 13 ++++++++++++ php/commands/scaffold.php | 44 +++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/features/scaffold.feature b/features/scaffold.feature index 3b0e634bf..34d655eb7 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -271,6 +271,19 @@ Feature: WordPress code scaffolding Plugin 'hello-world' network activated. """ + Scenario: Scaffold a plugin with invalid slug + Given a WP install + When I try `wp scaffold plugin .` + Then STDERR should contain: + """ + Error: Invalid plugin slug specified. + """ + When I try `wp scaffold plugin ../` + Then STDERR should contain: + """ + Error: Invalid plugin slug specified. + """ + Scenario: Scaffold starter code for a theme Given a WP install Given I run `wp theme path` diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 8e72a2c8b..83c817a8a 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -246,6 +246,11 @@ public function _s( $args, $assoc_args ) { ) ); $_s_theme_path = "$theme_path/$data[theme_name]"; + + if ( ! $this->check_target_directory( "theme", $_s_theme_path ) ) { + WP_CLI::error( "Invalid theme slug specified." ); + } + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); $should_write_file = $this->prompt_if_files_will_be_overwritten( $_s_theme_path, $force ); if ( ! $should_write_file ) { @@ -360,7 +365,12 @@ function child_theme( $args, $assoc_args ) { $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; - $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; + $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; + + if ( ! $this->check_target_directory( "theme", $theme_dir ) ) { + WP_CLI::error( "Invalid theme slug specified." ); + } + $theme_style_path = "$theme_dir/style.css"; $theme_functions_path = "$theme_dir/functions.php"; @@ -506,6 +516,10 @@ function plugin( $args, $assoc_args ) { } else { $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; $this->maybe_create_plugins_dir(); + + if ( ! $this->check_target_directory( "plugin", $plugin_dir ) ) { + WP_CLI::error( "Invalid plugin slug specified." ); + } } $plugin_path = "$plugin_dir/$plugin_slug.php"; @@ -661,11 +675,9 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( empty( $assoc_args['dir'] ) && ! is_dir( $target_dir ) ) { WP_CLI::error( "Invalid {$type} slug specified." ); } - } - - if ( ( "theme" === $type && 'themes' !== basename( dirname( realpath( $target_dir ) ) ) ) - || ( "plugin" === $type && 'plugins' !== basename( dirname( realpath( $target_dir ) ) ) ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); + if ( ! $this->check_target_directory( $type, $target_dir ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } } if ( ! empty( $assoc_args['dir'] ) ) { @@ -754,6 +766,26 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { ); } + private function check_target_directory( $type, $target_dir ) { + if ( realpath( $target_dir ) ) { + $target_dir = realpath( $target_dir ); + } + + $parent_dir = dirname( $target_dir ); + + if ( "theme" === $type ) { + if ( WP_CONTENT_DIR . '/themes' === $parent_dir ) { + return true; + } + } elseif ( "plugin" === $type ) { + if ( WP_PLUGIN_DIR === $parent_dir ) { + return true; + } + } + + return false; + } + private function create_files( $files_and_contents, $force ) { $wp_filesystem = $this->init_wp_filesystem(); $wrote_files = array(); From 8bf636bf0a166bc36918dbd36f736cd937e3e070 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 15:23:42 +0900 Subject: [PATCH 5180/5359] add tests for themes --- features/scaffold.feature | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index 34d655eb7..ceaab08bf 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -54,6 +54,19 @@ Feature: WordPress code scaffolding Success: Network enabled the 'Zombieland' theme. """ + Scenario: Scaffold a child theme with invalid slug + Given a WP install + When I try `wp scaffold child-theme . --parent_theme=simple-life` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ + When I try `wp scaffold child-theme ../ --parent_theme=simple-life` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ + @tax @cpt Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme Given a WP install @@ -316,6 +329,19 @@ Feature: WordPress code scaffolding Success: Switched to 'Starter-theme' theme. """ + Scenario: Scaffold starter code for a theme with invalid slug + Given a WP install + When I try `wp scaffold _s .` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ + When I try `wp scaffold _s ../` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. + """ + Scenario: Scaffold plugin and tests for non-standard plugin directory Given a WP install From 4bb9d5a3cec887a7fcbc15e3ce6375fda58d02e3 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 15 Dec 2016 16:01:17 +0900 Subject: [PATCH 5181/5359] reject `.` and `..` from scaffold * --- php/commands/scaffold.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 83c817a8a..5c5347d96 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -239,6 +239,10 @@ public function _s( $args, $assoc_args ) { $url = "http://underscores.me"; $timeout = 30; + if ( in_array( $theme_slug, array( '.', '..' ) ) ) { + WP_CLI::error( "Invalid theme slug specified." ); + } + $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", @@ -354,6 +358,10 @@ public function _s( $args, $assoc_args ) { function child_theme( $args, $assoc_args ) { $theme_slug = $args[0]; + if ( in_array( $theme_slug, array( '.', '..' ) ) ) { + WP_CLI::error( "Invalid theme slug specified." ); + } + $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", @@ -495,6 +503,10 @@ function plugin( $args, $assoc_args ) { $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); $plugin_package = str_replace( ' ', '_', $plugin_name ); + if ( in_array( $plugin_slug, array( '.', '..' ) ) ) { + WP_CLI::error( "Invalid plugin slug specified." ); + } + $data = wp_parse_args( $assoc_args, array( 'plugin_slug' => $plugin_slug, 'plugin_name' => $plugin_name, @@ -662,6 +674,9 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { if ( ! empty( $args[0] ) ) { $slug = $args[0]; + if ( in_array( $slug, array( '.', '..' ) ) ) { + WP_CLI::error( "Invalid {$type} slug specified." ); + } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { From 2bfce8a831f8a29273cce6c80144f117a53984d0 Mon Sep 17 00:00:00 2001 From: Ramon van Belzen <Ramoonus@users.noreply.github.com> Date: Tue, 20 Dec 2016 08:25:43 +0100 Subject: [PATCH 5182/5359] update composer to 1.2 https://gemnasium.com/github.com/wp-cli/wp-cli --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ef35d2ee8..10d42fc8c 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "symfony/process": "~2.1", "symfony/translation": "~2.7", "nb/oxymel": "~0.1.0", - "composer/composer": "^1.0.0" + "composer/composer": "^1.2.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", From dd2bc6ed007849de7025ab271d3c6016e60a27ea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 20 Dec 2016 06:08:40 -0800 Subject: [PATCH 5183/5359] Also ignore `multisite.xml.dist` in distribution archives --- templates/plugin-distignore.mustache | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache index 276de2d19..35045412d 100644 --- a/templates/plugin-distignore.mustache +++ b/templates/plugin-distignore.mustache @@ -15,8 +15,9 @@ composer.lock Gruntfile.js package.json phpunit.xml -multisite.xml phpunit.xml.dist +multisite.xml +multisite.xml.dist phpcs.ruleset.xml README.md wp-cli.local.yml From 4421af4c93782242d27c10eef6a52a447c06940b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 20 Dec 2016 06:26:00 -0800 Subject: [PATCH 5184/5359] Update Composer dependencies (12/20/16) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.14) - Installing symfony/yaml (v2.8.15) Loading from cache - Removing symfony/filesystem (v2.8.14) - Installing symfony/filesystem (v2.8.15) Loading from cache - Removing symfony/config (v2.8.14) - Installing symfony/config (v2.8.15) Downloading: 100% - Removing symfony/debug (v2.8.14) - Installing symfony/debug (v2.8.15) Loading from cache - Removing symfony/dependency-injection (v2.8.14) - Installing symfony/dependency-injection (v2.8.15) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.14) - Installing symfony/event-dispatcher (v2.8.15) Loading from cache - Removing symfony/translation (v2.8.14) - Installing symfony/translation (v2.8.15) Loading from cache - Removing symfony/process (v2.8.14) - Installing symfony/process (v2.8.15) Downloading: 100% - Removing symfony/finder (v2.8.14) - Installing symfony/finder (v2.8.15) Downloading: 100% - Removing symfony/console (v2.8.14) - Installing symfony/console (v2.8.15) Downloading: 100% - Removing composer/composer (1.2.3) - Installing composer/composer (1.2.4) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 73 +++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/composer.lock b/composer.lock index ca226dec8..ada826660 100644 --- a/composer.lock +++ b/composer.lock @@ -67,16 +67,16 @@ }, { "name": "composer/composer", - "version": "1.2.3", + "version": "1.2.4", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "e7f19286a7e7f940950c9069a0f549d483c30ba7" + "reference": "7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e7f19286a7e7f940950c9069a0f549d483c30ba7", - "reference": "e7f19286a7e7f940950c9069a0f549d483c30ba7", + "url": "https://api.github.com/repos/composer/composer/zipball/7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0", + "reference": "7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2016-12-01 13:33:53" + "time": "2016-12-06 21:00:51" }, { "name": "composer/semver", @@ -749,22 +749,25 @@ }, { "name": "symfony/config", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "1361bc4e66f97b6202ae83f4190e962c624b5e61" + "reference": "b522856007b258f46d5ee35d3b7b235c11e76e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/1361bc4e66f97b6202ae83f4190e962c624b5e61", - "reference": "1361bc4e66f97b6202ae83f4190e962c624b5e61", + "url": "https://api.github.com/repos/symfony/config/zipball/b522856007b258f46d5ee35d3b7b235c11e76e86", + "reference": "b522856007b258f46d5ee35d3b7b235c11e76e86", "shasum": "" }, "require": { "php": ">=5.3.9", "symfony/filesystem": "~2.3|~3.0.0" }, + "require-dev": { + "symfony/yaml": "~2.7|~3.0.0" + }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" }, @@ -798,20 +801,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-11-03 07:52:58" + "time": "2016-12-10 08:21:45" }, { "name": "symfony/console", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e" + "reference": "d5643cd095e5e37d31e004bb2606b5dd7e96602f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a871ba00e0f604dceac64c56c27f99fbeaf4854e", - "reference": "a871ba00e0f604dceac64c56c27f99fbeaf4854e", + "url": "https://api.github.com/repos/symfony/console/zipball/d5643cd095e5e37d31e004bb2606b5dd7e96602f", + "reference": "d5643cd095e5e37d31e004bb2606b5dd7e96602f", "shasum": "" }, "require": { @@ -859,11 +862,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-11-15 23:02:12" + "time": "2016-12-06 11:59:35" }, { "name": "symfony/debug", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -920,16 +923,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "9d2c5033ca70ceade8d7584f997a9d3943f0fe5f" + "reference": "51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9d2c5033ca70ceade8d7584f997a9d3943f0fe5f", - "reference": "9d2c5033ca70ceade8d7584f997a9d3943f0fe5f", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7", + "reference": "51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7", "shasum": "" }, "require": { @@ -979,11 +982,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-11-18 21:10:01" + "time": "2016-12-08 14:41:31" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -1043,7 +1046,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -1092,16 +1095,16 @@ }, { "name": "symfony/finder", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0023b024363dfc0cd21262e556f25a291fe8d7fd" + "reference": "c0f10576335743b881ac1ed39d18c0fa66048775" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0023b024363dfc0cd21262e556f25a291fe8d7fd", - "reference": "0023b024363dfc0cd21262e556f25a291fe8d7fd", + "url": "https://api.github.com/repos/symfony/finder/zipball/c0f10576335743b881ac1ed39d18c0fa66048775", + "reference": "c0f10576335743b881ac1ed39d18c0fa66048775", "shasum": "" }, "require": { @@ -1137,7 +1140,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-11-03 07:52:58" + "time": "2016-12-13 09:38:12" }, { "name": "symfony/polyfill-mbstring", @@ -1200,16 +1203,16 @@ }, { "name": "symfony/process", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f" + "reference": "1a1bd056395540d0bc549d39818316513565d278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f", - "reference": "024de37f8a6b9e5e8244d9eb3fcf3e467dd2a93f", + "url": "https://api.github.com/repos/symfony/process/zipball/1a1bd056395540d0bc549d39818316513565d278", + "reference": "1a1bd056395540d0bc549d39818316513565d278", "shasum": "" }, "require": { @@ -1245,11 +1248,11 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-09-29 14:03:54" + "time": "2016-11-24 00:43:03" }, { "name": "symfony/translation", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", @@ -1313,7 +1316,7 @@ }, { "name": "symfony/yaml", - "version": "v2.8.14", + "version": "v2.8.15", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", From 08475e3d1b9d13f336d9c5253a773f0ae8252a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 20 Dec 2016 18:35:21 +0100 Subject: [PATCH 5185/5359] Plugin update from a remote zip file example From #3675 --- php/commands/plugin.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 2263bed76..472ed846a 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -654,6 +654,15 @@ protected function filter_item_list( $items, $args ) { * Plugin installed successfully. * Success: Installed 1 of 1 plugins. * + * # Update from a remote zip file + * wp plugin install https://github.com/envato/wp-envato-market/archive/master.zip --force + * Downloading install package from https://github.com/envato/wp-envato-market/archive/master.zip + * Unpacking the package... + * Installing the plugin... + * Renamed Github-based project from 'wp-envato-market-master' to 'wp-envato-market'. + * Plugin updated successfully + * Success: Installed 1 of 1 plugins. + * * # Forcefully re-install all installed plugins * $ wp plugin install $(wp plugin list --field=name) --force * Installing Akismet (3.1.11) From e7e4a5145f65f648cfb51c69e21690b1e65237f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= <viktor@szepe.net> Date: Tue, 20 Dec 2016 18:37:26 +0100 Subject: [PATCH 5186/5359] Missed the $ sign in Update from a remote zip file --- php/commands/plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/plugin.php b/php/commands/plugin.php index 472ed846a..f1dd9b744 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -655,7 +655,7 @@ protected function filter_item_list( $items, $args ) { * Success: Installed 1 of 1 plugins. * * # Update from a remote zip file - * wp plugin install https://github.com/envato/wp-envato-market/archive/master.zip --force + * $ wp plugin install https://github.com/envato/wp-envato-market/archive/master.zip --force * Downloading install package from https://github.com/envato/wp-envato-market/archive/master.zip * Unpacking the package... * Installing the plugin... From bb9e53c5c0bee89e374b4acec6188fb7fea7096b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 21 Dec 2016 11:40:57 -0800 Subject: [PATCH 5187/5359] Persist `PATH` when launching a child process The `PATH` can contain the path to a MySQL binary, which is important for connecting to the correct database. --- php/class-wp-cli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 4cd1d7ba3..66c80185b 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1011,6 +1011,7 @@ public static function runcommand( $command, $options = array() ) { $env_vars = array( 'HOME', + 'PATH', 'WP_CLI_AUTO_CHECK_UPDATE_DAYS', 'WP_CLI_CACHE_DIR', 'WP_CLI_CONFIG_PATH', From 3166f2a67e9fb1fa48e0fb8288855881c059e139 Mon Sep 17 00:00:00 2001 From: amq <amq@users.noreply.github.com> Date: Wed, 21 Dec 2016 23:29:26 +0100 Subject: [PATCH 5188/5359] Use .svg for the Travis badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 278deb47a..61cb211c3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ WP-CLI For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.png?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.svg?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) From 2f30f286b3c047570c8f0d69d8af7376841dcff8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 23 Dec 2016 07:11:56 -0800 Subject: [PATCH 5189/5359] Replicate core logic for creating `$newdomain` and `$path` This ensures path is respected when `$base` global isn't '/' --- features/site-create.feature | 46 ++++++++++++++++++++++++++++++++++++ php/commands/site.php | 14 +++++------ 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 features/site-create.feature diff --git a/features/site-create.feature b/features/site-create.feature new file mode 100644 index 000000000..c01656608 --- /dev/null +++ b/features/site-create.feature @@ -0,0 +1,46 @@ +Feature: Create a new site on a WP multisite + + Scenario: Respect defined `$base` in wp-config + Given an empty directory + And WP files + And a database + And a extra-config file: + """ + define( 'WP_ALLOW_MULTISITE', true ); + define( 'MULTISITE', true ); + define( 'SUBDOMAIN_INSTALL', false ); + $base = '/dev/'; + define( 'DOMAIN_CURRENT_SITE', 'localhost' ); + define( 'PATH_CURRENT_SITE', '/dev/' ); + define( 'SITE_ID_CURRENT_SITE', 1 ); + define( 'BLOG_ID_CURRENT_SITE', 1 ); + """ + + When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` + Then STDOUT should be: + """ + Success: Generated 'wp-config.php' file. + """ + + When I run `wp core multisite-install --url=localhost/dev/ --title=Test --admin_user=admin --admin_email=admin@example.org` + Then STDOUT should contain: + """ + Success: Network installed. Don't forget to set up rewrite rules. + """ + + When I run `wp site list --fields=blog_id,url` + Then STDOUT should be a table containing rows: + | blog_id | url | + | 1 | http://localhost/dev/ | + + When I run `wp site create --slug=newsite` + Then STDOUT should be: + """ + Success: Site 2 created: http://localhost/dev/newsite/ + """ + + When I run `wp site list --fields=blog_id,url` + Then STDOUT should be a table containing rows: + | blog_id | url | + | 1 | http://localhost/dev/ | + | 2 | http://localhost/dev/newsite/ | diff --git a/php/commands/site.php b/php/commands/site.php index 76f7a1085..433ce9cb2 100644 --- a/php/commands/site.php +++ b/php/commands/site.php @@ -356,13 +356,13 @@ public function create( $_, $assoc_args ) { } if ( is_subdomain_install() ) { - $path = '/'; - $url = $newdomain = $base.'.'.preg_replace( '|^www\.|', '', $network->domain ); - } - else { - $newdomain = $network->domain; - $path = '/' . trim( $base, '/' ) . '/'; - $url = $network->domain . $path; + $newdomain = $base . '.' . preg_replace( '|^www\.|', '', $current_site->domain ); + $path = $current_site->path; + $url = $newdomain; + } else { + $newdomain = $current_site->domain; + $path = $current_site->path . $base . '/'; + $url = $newdomain . $path; } $user_id = email_exists( $email ); From 37b7baec554f37fee025de70f73903b3401a4e25 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 23 Dec 2016 07:58:59 -0800 Subject: [PATCH 5190/5359] Ensure automatic parent theme installation uses http cacher It's a bit of a hack to put this in the upgrader feedback skin, but there isn't a clear action to hook into. --- features/theme-install.feature | 34 ++++++++++++++++++++++++++++++++++ php/WP_CLI/UpgraderSkin.php | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/features/theme-install.feature b/features/theme-install.feature index 4a313b64f..491d43781 100644 --- a/features/theme-install.feature +++ b/features/theme-install.feature @@ -37,3 +37,37 @@ Feature: Install WordPress themes Error: No themes installed. """ And the return code should be 1 + + Scenario: Ensure automatic parent theme installation uses http cacher + Given a WP install + And an empty cache + + When I run `wp theme install stargazer` + Then STDOUT should contain: + """ + Success: Installed 1 of 1 themes. + """ + And STDOUT should not contain: + """ + Using cached file + """ + + When I run `wp theme uninstall stargazer` + Then STDOUT should contain: + """ + Success: Deleted 1 of 1 themes. + """ + + When I run `wp theme install buntu` + Then STDOUT should contain: + """ + Success: Installed 1 of 1 themes. + """ + And STDOUT should contain: + """ + This theme requires a parent theme. + """ + And STDOUT should contain: + """ + Using cached file + """ diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php index da6eb4c3b..37f3019d5 100644 --- a/php/WP_CLI/UpgraderSkin.php +++ b/php/WP_CLI/UpgraderSkin.php @@ -28,6 +28,11 @@ function error( $error ) { } function feedback( $string ) { + + if ( 'parent_theme_prepare_install' === $string ) { + \WP_CLI::get_http_cache_manager()->whitelist_package( $this->api->download_link, 'theme', $this->api->slug, $this->api->version ); + } + if ( isset( $this->upgrader->strings[$string] ) ) $string = $this->upgrader->strings[$string]; From 0bbce2ec9199d2a7b4855a9720353ef49e2bc59f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 23 Dec 2016 15:21:26 -0800 Subject: [PATCH 5191/5359] Mention update lock behavior in core update docs --- php/commands/core.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/core.php b/php/commands/core.php index 8143aaa27..f6c3c2ffb 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -1129,6 +1129,10 @@ private static function get_core_checksums( $version, $locale ) { * * Defaults to updating WordPress to the latest version. * + * If you see "Error: Another update is currently in progress.", you may + * need to run `wp option delete core_updater.lock` after verifying another + * update isn't actually running. + * * ## OPTIONS * * [<zip>] From 4e76235aa46f4f0855575a8cbed79735ead7a45b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Mon, 26 Dec 2016 15:15:18 -0800 Subject: [PATCH 5192/5359] Ensure paths aren't backslashed when destination folder already exists --- features/plugin-install.feature | 15 +++++++++++++++ php/class-wp-cli.php | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index dfba0d4df..2caae2430 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -96,3 +96,18 @@ Feature: Install WordPress plugins Error: No plugins installed. """ And the return code should be 1 + + Scenario: Paths aren't backslashed when destination folder already exists + Given a WP install + + When I run `pwd` + Then save STDOUT as {WORKING_DIR} + + When I run `rm wp-content/plugins/akismet/akismet.php` + Then the return code should be 0 + + When I try `wp plugin install akismet` + Then STDERR should contain: + """ + Warning: Destination folder already exists. "{WORKING_DIR}/wp-content/plugins/akismet/" + """ diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 66c80185b..b9caba3df 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -781,10 +781,19 @@ public static function error_to_string( $errors ) { return $errors; } + // Only json_encode() the data when it needs it + $render_data = function( $data ) { + if ( is_array( $data ) || is_object( $data ) ) { + return json_encode( $data ); + } else { + return '"' . $data . '"'; + } + }; + if ( is_object( $errors ) && is_a( $errors, 'WP_Error' ) ) { foreach ( $errors->get_error_messages() as $message ) { if ( $errors->get_error_data() ) { - return $message . ' ' . json_encode( $errors->get_error_data() ); + return $message . ' ' . $render_data( $errors->get_error_data() ); } else { return $message; } From 9c098f82e10e1b561a12ac0fb851d76bed33fc6f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 28 Dec 2016 11:34:32 -0800 Subject: [PATCH 5193/5359] When globalizing `wp-config.php` vars, ensure local scope is globalized The previous implementation would only assign the value to the global variable, when the current context also needs to be considered global. --- features/framework.feature | 28 ++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/features/framework.feature b/features/framework.feature index 636da1e6f..26b653371 100644 --- a/features/framework.feature +++ b/features/framework.feature @@ -224,3 +224,31 @@ Feature: Load WP-CLI bar """ And STDERR should be empty + + Scenario: WP-CLI sets $table_prefix appropriately on multisite + Given a WP multisite install + And I run `wp site create --slug=first` + + When I run `wp eval 'global $table_prefix; echo $table_prefix;'` + Then STDOUT should be: + """ + wp_ + """ + + When I run `wp eval 'global $blog_id; echo $blog_id;'` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp --url=example.com/first eval 'global $table_prefix; echo $table_prefix;'` + Then STDOUT should be: + """ + wp_2_ + """ + + When I run `wp --url=example.com/first eval 'global $blog_id; echo $blog_id;'` + Then STDOUT should be: + """ + 2 + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 5d52f72d6..8a25eb466 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -983,7 +983,8 @@ public function load_wordpress() { if ( array_key_exists( $key, $wp_cli_original_defined_vars ) || 'wp_cli_original_defined_vars' === $key ) { continue; } - $GLOBALS[ $key ] = $var; + global $$key; + $$key = $var; } $this->maybe_update_url_from_domain_constant(); From ff960f39eb4c9fe4651a5500eb24704422bcb284 Mon Sep 17 00:00:00 2001 From: Mark McEver <mark@fastmail.net> Date: Wed, 28 Dec 2016 18:22:48 -0600 Subject: [PATCH 5194/5359] Made it possible to pass any arbitrary argument along to mysql when running "wp db cli" --- php/commands/db.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 5a8a88505..e4ed67150 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -174,10 +174,12 @@ public function repair() { * * @alias connect */ - public function cli() { - self::run( 'mysql --no-defaults --no-auto-rehash', array( - 'database' => DB_NAME - ) ); + public function cli( $args, $assoc_args ) { + if ( !isset( $assoc_args['database'] ) ) { + $assoc_args['database'] = DB_NAME; + } + + self::run( 'mysql --no-defaults --no-auto-rehash', $assoc_args ); } /** From 76cbc873db450aedff02f966f980171702ccf3f7 Mon Sep 17 00:00:00 2001 From: Mark McEver <mark@fastmail.net> Date: Wed, 28 Dec 2016 18:34:48 -0600 Subject: [PATCH 5195/5359] Made it possible to override the default character set on any db command --- php/commands/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/db.php b/php/commands/db.php index e4ed67150..f14e406e0 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -455,7 +455,7 @@ private static function run( $cmd, $assoc_args = array(), $descriptors = null ) 'pass' => DB_PASSWORD, ); - if ( defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { + if ( !isset( $assoc_args['default-character-set'] ) && defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { $required['default-character-set'] = constant( 'DB_CHARSET' ); } From ba8f171cc35d63df3d696afa0ac981ea0490a7ef Mon Sep 17 00:00:00 2001 From: Mark McEver <mark@fastmail.net> Date: Wed, 28 Dec 2016 20:33:52 -0600 Subject: [PATCH 5196/5359] Added unit tests for f200689 and ff960f3 --- php/commands/db.php | 6 ++- tests/commands/test-db.php | 77 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/commands/test-db.php diff --git a/php/commands/db.php b/php/commands/db.php index f14e406e0..6f90f630c 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -461,7 +461,11 @@ private static function run( $cmd, $assoc_args = array(), $descriptors = null ) $final_args = array_merge( $assoc_args, $required ); - Utils\run_mysql_command( $cmd, $final_args, $descriptors ); + static::run_mysql_command( $cmd, $final_args, $descriptors ); + } + + protected static function run_mysql_command( $cmd, $final_args, $descriptors ) { + Utils\run_mysql_command( $cmd, $final_args, $descriptors ); } } diff --git a/tests/commands/test-db.php b/tests/commands/test-db.php new file mode 100644 index 000000000..f92717567 --- /dev/null +++ b/tests/commands/test-db.php @@ -0,0 +1,77 @@ +<?php +$root = __DIR__ . '/../..'; +require_once "$root/vendor/autoload.php"; +require_once "$root/php/class-wp-cli.php"; +require_once "$root/php/class-wp-cli-command.php"; +require_once "$root/php/commands/db.php"; + +define( 'DB_NAME', 'test_db_name' ); +define( 'DB_HOST', 'test_db_host' ); +define( 'DB_USER', 'test_db_user' ); +define( 'DB_PASSWORD', 'test_db_password' ); + +class DBCommandTests extends PHPUnit_Framework_TestCase { + private $instance; + + function testCli() { + $expected_args = [ + 'database' => DB_NAME, + 'host' => DB_HOST, + 'user' => DB_USER, + 'pass' => DB_PASSWORD, + ]; + $this->assertCli( [], $expected_args ); + + $expected_args['database'] = 'some_other_database'; + $this->assertCli( ['database' => 'some_other_database'], $expected_args ); + $expected_args['database'] = DB_NAME; + + define( 'DB_CHARSET', 'some_charset' ); + $expected_args['default-character-set'] = 'some_charset'; + $args = $this->assertCli( [], $expected_args ); + + $expected_args['default-character-set'] = 'some_other_charset'; + $args = $this->assertCli( ['default-character-set' => 'some_other_charset'], $expected_args ); + } + + private function getInstance() { + if($this->instance == null){ + $this->instance = new TestCommandInstance(); + } + + return $this->instance; + } + + private function assertCli( $assoc_args, $expected_args ) { + $instance = $this->getInstance(); + + $instance->cli( [], $assoc_args ); + $this->assertEquals( 'mysql --no-defaults --no-auto-rehash', $instance->getLastCmd() ); + + $args = $instance->getLastArgs(); + $this->assertEquals( count( $expected_args ), count( $args ) ); + + foreach($expected_args as $key => $value){ + $this->assertEquals( $value, $args[$key] ); + } + } +} + +class TestCommandInstance extends DB_Command { + private static $lastCmd; + private static $lastArgs; + + protected static function run_mysql_command( $cmd, $final_args, $descriptors ) { + static::$lastCmd = $cmd; + static::$lastArgs = $final_args; + } + + public static function getLastCmd() { + return static::$lastCmd; + } + + public static function getLastArgs() { + return static::$lastArgs; + } +} + From b0f3e63fd64440f8ee658ac4b17c86b5d1e36a2d Mon Sep 17 00:00:00 2001 From: Mark McEver <mark@fastmail.net> Date: Wed, 28 Dec 2016 20:37:11 -0600 Subject: [PATCH 5197/5359] Added the "wp db cli" options documentation requested by Daniel --- php/commands/db.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/php/commands/db.php b/php/commands/db.php index 6f90f630c..50c932b44 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -166,6 +166,17 @@ public function repair() { /** * Open a MySQL console using credentials from wp-config.php * + * ## OPTIONS + * + * [--database=<database>] + * : Use a specific database. Defaults to DB_NAME. + * + * [--default-character-set=<character-set>] + * : Use a specific character set. Defaults to DB_CHARSET when defined. + * + * [--<field>=<value>] + * : Extra arguments to pass to the MySQL executable. + * * ## EXAMPLES * * # Open MySQL console From 79104fe9a22120b261236dba81628d1590df3a31 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 29 Dec 2016 19:44:06 +0900 Subject: [PATCH 5198/5359] add global parameters to completion --- php/WP_CLI/Completions.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index bcb05cfa2..13e40c5cd 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -41,6 +41,7 @@ function __construct( $line ) { list( $command, $args, $assoc_args ) = $r; $spec = SynopsisParser::parse( $command->get_synopsis() ); +// var_dump( \WP_CLI::get_configurator()->get_spec() ); foreach ( $spec as $arg ) { if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { @@ -78,6 +79,21 @@ function __construct( $line ) { $this->add( $opt ); } } + foreach ( $this->get_global_parameters() as $param => $runtime ) { + if ( isset( $assoc_args[ $param ] ) ) { + continue; + } + + $opt = "--{$param}"; + + if ( "" === $runtime ) { + $opt .= ' '; + } else { + $opt .= '='; + } + + $this->add( $opt ); + } } } @@ -107,6 +123,23 @@ private function get_command( $words ) { return array( $command, $args, $assoc_args ); } + private function get_global_parameters() + { + $params = array(); + foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { + if ( false === $details['runtime'] ) { + continue; + } elseif ( isset( $details['deprecated'] ) ) { + continue; + } elseif ( isset( $details['hidden'] ) ) { + continue; + } + $params[ $key ] = $details["runtime"]; + } + + return $params; + } + private function add( $opt ) { if ( $this->cur_word !== '' ) { if ( strpos( $opt, $this->cur_word ) !== 0 ) { From fde080bee55cbbee9694e17edce532e3af65fca1 Mon Sep 17 00:00:00 2001 From: miya0001 <miya@wpist.me> Date: Thu, 29 Dec 2016 20:20:32 +0900 Subject: [PATCH 5199/5359] add test for comptetion of global parameters --- PHP_Codesniffer-VariableAnalysis | 1 + codesniffer/.gitattributes | 10 + codesniffer/.gitignore | 2 + codesniffer/CodeSniffer.conf.dist | 9 + codesniffer/CodeSniffer.php | 2133 ++++++++++++ codesniffer/CodeSniffer/CLI.php | 877 +++++ .../CommentParser/AbstractDocElement.php | 353 ++ .../CommentParser/AbstractParser.php | 684 ++++ .../CommentParser/ClassCommentParser.php | 341 ++ .../CommentParser/CommentElement.php | 245 ++ .../CodeSniffer/CommentParser/DocElement.php | 104 + .../CommentParser/FunctionCommentParser.php | 212 ++ .../CommentParser/MemberCommentParser.php | 91 + .../CodeSniffer/CommentParser/PairElement.php | 171 + .../CommentParser/ParameterElement.php | 338 ++ .../CommentParser/ParserException.php | 71 + .../CommentParser/SingleElement.php | 171 + .../CodeSniffer/DocGenerators/Generator.php | 186 ++ .../CodeSniffer/DocGenerators/HTML.php | 294 ++ .../CodeSniffer/DocGenerators/Text.php | 267 ++ codesniffer/CodeSniffer/Exception.php | 33 + codesniffer/CodeSniffer/File.php | 2910 +++++++++++++++++ codesniffer/CodeSniffer/Report.php | 81 + codesniffer/CodeSniffer/Reporting.php | 315 ++ .../CodeSniffer/Reports/Checkstyle.php | 126 + codesniffer/CodeSniffer/Reports/Csv.php | 108 + codesniffer/CodeSniffer/Reports/Emacs.php | 108 + codesniffer/CodeSniffer/Reports/Full.php | 178 + codesniffer/CodeSniffer/Reports/Gitblame.php | 133 + codesniffer/CodeSniffer/Reports/Hgblame.php | 134 + codesniffer/CodeSniffer/Reports/Json.php | 114 + codesniffer/CodeSniffer/Reports/Junit.php | 148 + .../CodeSniffer/Reports/Notifysend.php | 262 ++ codesniffer/CodeSniffer/Reports/Source.php | 235 ++ codesniffer/CodeSniffer/Reports/Summary.php | 131 + codesniffer/CodeSniffer/Reports/Svnblame.php | 100 + .../CodeSniffer/Reports/VersionControl.php | 257 ++ codesniffer/CodeSniffer/Reports/Xml.php | 129 + codesniffer/CodeSniffer/Sniff.php | 93 + .../Standards/AbstractPatternSniff.php | 961 ++++++ .../Standards/AbstractScopeSniff.php | 201 ++ .../Standards/AbstractVariableSniff.php | 245 ++ .../Classes/DuplicateClassNameStandard.xml | 27 + .../CodeAnalysis/EmptyStatementStandard.xml | 23 + .../ForLoopShouldBeWhileLoopStandard.xml | 23 + .../ForLoopWithTestFunctionCallStandard.xml | 24 + .../JumbledIncrementerStandard.xml | 25 + .../UnconditionalIfStatementStandard.xml | 39 + .../UnnecessaryFinalModifierStandard.xml | 29 + .../UnusedFunctionParameterStandard.xml | 25 + .../UselessOverridingMethodStandard.xml | 32 + .../Generic/Docs/Commenting/FixmeStandard.xml | 25 + .../Generic/Docs/Commenting/TodoStandard.xml | 25 + .../InlineControlStructureStandard.xml | 22 + .../Generic/Docs/Debug/CSSLintStandard.xml | 19 + .../Docs/Debug/ClosureLinterStandard.xml | 19 + .../Generic/Docs/Debug/JSHintStandard.xml | 19 + .../Docs/Files/ByteOrderMarkStandard.xml | 7 + .../Docs/Files/EndFileNewlineStandard.xml | 7 + .../Docs/Files/EndFileNoNewlineStandard.xml | 7 + .../Generic/Docs/Files/InlineHTMLStandard.xml | 24 + .../Docs/Files/LineEndingsStandard.xml | 7 + .../Generic/Docs/Files/LineLengthStandard.xml | 7 + .../Docs/Files/LowercasedFilenameStandard.xml | 7 + .../Docs/Files/OneClassPerFileStandard.xml | 29 + .../Files/OneInterfacePerFileStandard.xml | 29 + .../DisallowMultipleStatementsStandard.xml | 20 + .../MultipleStatementAlignmentStandard.xml | 56 + .../Formatting/NoSpaceAfterCastStandard.xml | 19 + .../Formatting/SpaceAfterCastStandard.xml | 19 + .../CallTimePassByReferenceStandard.xml | 31 + .../FunctionCallArgumentSpacingStandard.xml | 39 + .../OpeningFunctionBraceBsdAllmanStandard.xml | 24 + ...gFunctionBraceKernighanRitchieStandard.xml | 24 + .../Metrics/CyclomaticComplexityStandard.xml | 7 + .../Docs/Metrics/NestingLevelStandard.xml | 7 + .../CamelCapsFunctionNameStandard.xml | 23 + .../ConstructorNameStandard.xml | 29 + .../UpperCaseConstantNameStandard.xml | 29 + .../CharacterBeforePHPOpeningTagStandard.xml | 22 + .../Docs/PHP/ClosingPHPTagStandard.xml | 22 + .../Docs/PHP/DeprecatedFunctionsStandard.xml | 19 + .../Docs/PHP/DisallowShortOpenTagStandard.xml | 7 + .../Docs/PHP/ForbiddenFunctionsStandard.xml | 19 + .../Docs/PHP/LowerCaseConstantStandard.xml | 23 + .../Docs/PHP/LowerCaseKeywordStandard.xml | 19 + .../Docs/PHP/NoSilencedErrorsStandard.xml | 23 + .../Generic/Docs/PHP/SAPIUsageStandard.xml | 23 + .../Docs/PHP/UpperCaseConstantStandard.xml | 23 + .../UnnecessaryStringConcatStandard.xml | 19 + .../SubversionPropertiesStandard.xml | 7 + .../DisallowSpaceIndentStandard.xml | 7 + .../WhiteSpace/DisallowTabIndentStandard.xml | 7 + .../Docs/WhiteSpace/ScopeIndentStandard.xml | 23 + .../Classes/DuplicateClassNameSniff.php | 129 + .../CodeAnalysis/EmptyStatementSniff.php | 128 + .../ForLoopShouldBeWhileLoopSniff.php | 104 + .../ForLoopWithTestFunctionCallSniff.php | 113 + .../CodeAnalysis/JumbledIncrementerSniff.php | 148 + .../UnconditionalIfStatementSniff.php | 106 + .../UnnecessaryFinalModifierSniff.php | 98 + .../UnusedFunctionParameterSniff.php | 187 ++ .../UselessOverridingMethodSniff.php | 180 + .../CodeAnalysis/VariableAnalysisSniff.php | 1498 +++++++++ .../Generic/Sniffs/Commenting/FixmeSniff.php | 92 + .../Generic/Sniffs/Commenting/TodoSniff.php | 90 + .../InlineControlStructureSniff.php | 120 + .../Generic/Sniffs/Debug/CSSLintSniff.php | 117 + .../Sniffs/Debug/ClosureLinterSniff.php | 139 + .../Generic/Sniffs/Debug/JSHintSniff.php | 109 + .../Sniffs/Files/ByteOrderMarkSniff.php | 93 + .../Sniffs/Files/EndFileNewlineSniff.php | 95 + .../Sniffs/Files/EndFileNoNewlineSniff.php | 95 + .../Generic/Sniffs/Files/InlineHTMLSniff.php | 74 + .../Generic/Sniffs/Files/LineEndingsSniff.php | 115 + .../Generic/Sniffs/Files/LineLengthSniff.php | 160 + .../Sniffs/Files/LowercasedFilenameSniff.php | 76 + .../Sniffs/Files/OneClassPerFileSniff.php | 64 + .../Sniffs/Files/OneInterfacePerFileSniff.php | 64 + .../DisallowMultipleStatementsSniff.php | 88 + .../MultipleStatementAlignmentSniff.php | 304 ++ .../Formatting/NoSpaceAfterCastSniff.php | 69 + .../Sniffs/Formatting/SpaceAfterCastSniff.php | 75 + .../CallTimePassByReferenceSniff.php | 151 + .../FunctionCallArgumentSpacingSniff.php | 141 + .../OpeningFunctionBraceBsdAllmanSniff.php | 121 + ...ningFunctionBraceKernighanRitchieSniff.php | 117 + .../Metrics/CyclomaticComplexitySniff.php | 129 + .../Sniffs/Metrics/NestingLevelSniff.php | 114 + .../CamelCapsFunctionNameSniff.php | 210 ++ .../ConstructorNameSniff.php | 106 + .../UpperCaseConstantNameSniff.php | 247 ++ .../PHP/CharacterBeforePHPOpeningTagSniff.php | 63 + .../Generic/Sniffs/PHP/ClosingPHPTagSniff.php | 64 + .../Sniffs/PHP/DeprecatedFunctionsSniff.php | 94 + .../Sniffs/PHP/DisallowShortOpenTagSniff.php | 85 + .../Sniffs/PHP/ForbiddenFunctionsSniff.php | 202 ++ .../Sniffs/PHP/LowerCaseConstantSniff.php | 107 + .../Sniffs/PHP/LowerCaseKeywordSniff.php | 137 + .../Sniffs/PHP/NoSilencedErrorsSniff.php | 81 + .../Generic/Sniffs/PHP/SAPIUsageSniff.php | 81 + .../Sniffs/PHP/UpperCaseConstantSniff.php | 98 + .../Strings/UnnecessaryStringConcatSniff.php | 125 + .../SubversionPropertiesSniff.php | 206 ++ .../WhiteSpace/DisallowSpaceIndentSniff.php | 86 + .../WhiteSpace/DisallowTabIndentSniff.php | 86 + .../Sniffs/WhiteSpace/ScopeIndentSniff.php | 437 +++ .../CodeSniffer/Standards/Generic/ruleset.xml | 4 + .../Standards/IncorrectPatternException.php | 35 + .../Sniffs/CSS/BrowserSpecificStylesSniff.php | 102 + .../Sniffs/Channels/ChannelExceptionSniff.php | 76 + .../Channels/DisallowSelfActionsSniff.php | 137 + .../Sniffs/Channels/IncludeOwnSystemSniff.php | 112 + .../Sniffs/Channels/IncludeSystemSniff.php | 341 ++ .../Sniffs/Channels/UnusedSystemSniff.php | 157 + .../Commenting/FunctionCommentSniff.php | 130 + .../MySource/Sniffs/Debug/DebugCodeSniff.php | 68 + .../Sniffs/Debug/FirebugConsoleSniff.php | 77 + .../Sniffs/Objects/AssignThisSniff.php | 94 + .../Objects/CreateWidgetTypeCallbackSniff.php | 228 ++ .../Sniffs/Objects/DisallowNewWidgetSniff.php | 72 + .../Sniffs/PHP/AjaxNullComparisonSniff.php | 113 + .../Sniffs/PHP/EvalObjectFactorySniff.php | 126 + .../Sniffs/PHP/GetRequestDataSniff.php | 119 + .../Sniffs/PHP/ReturnFunctionValueSniff.php | 76 + .../Sniffs/Strings/JoinStringsSniff.php | 88 + .../Standards/MySource/ruleset.xml | 18 + .../Docs/Classes/ClassDeclarationStandard.xml | 22 + .../Docs/Commenting/ClassCommentStandard.xml | 177 + .../Docs/Commenting/FileCommentStandard.xml | 286 ++ .../Commenting/FunctionCommentStandard.xml | 230 ++ .../Docs/Commenting/InlineCommentStandard.xml | 19 + .../ControlSignatureStandard.xml | 36 + .../MultiLineConditionStandard.xml | 60 + .../PEAR/Docs/Files/IncludingFileStandard.xml | 24 + .../PEAR/Docs/Files/LineLengthStandard.xml | 7 + .../MultiLineAssignmentStandard.xml | 35 + .../FunctionCallSignatureStandard.xml | 19 + .../Functions/FunctionDeclarationStandard.xml | 41 + .../Functions/ValidDefaultValueStandard.xml | 25 + .../ValidClassNameStandard.xml | 23 + .../ValidFunctionNameStandard.xml | 23 + .../ValidVariableNameStandard.xml | 29 + .../ObjectOperatorIndentStandard.xml | 39 + .../WhiteSpace/ScopeClosingBraceStandard.xml | 23 + .../Docs/WhiteSpace/ScopeIndentStandard.xml | 29 + .../Sniffs/Classes/ClassDeclarationSniff.php | 125 + .../Sniffs/Commenting/ClassCommentSniff.php | 233 ++ .../Sniffs/Commenting/FileCommentSniff.php | 797 +++++ .../Commenting/FunctionCommentSniff.php | 490 +++ .../Sniffs/Commenting/InlineCommentSniff.php | 70 + .../ControlSignatureSniff.php | 67 + .../MultiLineConditionSniff.php | 189 ++ .../PEAR/Sniffs/Files/IncludingFileSniff.php | 137 + .../Formatting/MultiLineAssignmentSniff.php | 120 + .../Functions/FunctionCallSignatureSniff.php | 335 ++ .../Functions/FunctionDeclarationSniff.php | 337 ++ .../Functions/ValidDefaultValueSniff.php | 108 + .../NamingConventions/ValidClassNameSniff.php | 115 + .../ValidFunctionNameSniff.php | 285 ++ .../ValidVariableNameSniff.php | 114 + .../WhiteSpace/ObjectOperatorIndentSniff.php | 174 + .../WhiteSpace/ScopeClosingBraceSniff.php | 147 + .../Sniffs/WhiteSpace/ScopeIndentSniff.php | 48 + .../CodeSniffer/Standards/PEAR/ruleset.xml | 39 + .../CodeSniffer/Standards/PHPCS/ruleset.xml | 27 + .../Docs/Classes/ClassDeclarationStandard.xml | 48 + .../PSR1/Docs/Files/SideEffectsStandard.xml | 27 + .../Sniffs/Classes/ClassDeclarationSniff.php | 78 + .../PSR1/Sniffs/Files/SideEffectsSniff.php | 226 ++ .../Methods/CamelCapsMethodNameSniff.php | 92 + .../CodeSniffer/Standards/PSR1/ruleset.xml | 45 + .../Docs/Classes/ClassDeclarationStandard.xml | 23 + .../Classes/PropertyDeclarationStandard.xml | 62 + .../ControlStructureSpacingStandard.xml | 23 + .../ElseIfDeclarationStandard.xml | 27 + .../SwitchDeclarationStandard.xml | 104 + .../Docs/Files/EndFileNewlineStandard.xml | 7 + .../Methods/MethodDeclarationStandard.xml | 51 + .../NamespaceDeclarationStandard.xml | 22 + .../Namespaces/UseDeclarationStandard.xml | 57 + .../Sniffs/Classes/ClassDeclarationSniff.php | 318 ++ .../Classes/PropertyDeclarationSniff.php | 115 + .../ControlStructureSpacingSniff.php | 91 + .../ElseIfDeclarationSniff.php | 68 + .../SwitchDeclarationSniff.php | 192 ++ .../PSR2/Sniffs/Files/EndFileNewlineSniff.php | 97 + .../Methods/FunctionCallSignatureSniff.php | 81 + .../Sniffs/Methods/MethodDeclarationSniff.php | 118 + .../Namespaces/NamespaceDeclarationSniff.php | 79 + .../Sniffs/Namespaces/UseDeclarationSniff.php | 139 + .../CodeSniffer/Standards/PSR2/ruleset.xml | 186 ++ .../Arrays/ArrayBracketSpacingStandard.xml | 19 + .../Docs/Arrays/ArrayDeclarationStandard.xml | 117 + .../LowercaseClassKeywordsStandard.xml | 23 + .../Classes/SelfMemberReferenceStandard.xml | 63 + .../DocCommentAlignmentStandard.xml | 39 + .../FunctionCommentThrowTagStandard.xml | 32 + .../ForEachLoopDeclarationStandard.xml | 39 + .../ForLoopDeclarationStandard.xml | 55 + .../LowercaseDeclarationStandard.xml | 23 + .../FunctionDuplicateArgumentStandard.xml | 23 + .../LowercaseFunctionKeywordsStandard.xml | 25 + .../Docs/Scope/StaticThisUsageStandard.xml | 31 + .../Docs/Strings/EchoedStringsStandard.xml | 19 + .../Docs/WhiteSpace/CastSpacingStandard.xml | 19 + .../FunctionOpeningBraceStandard.xml | 41 + .../LanguageConstructSpacingStandard.xml | 19 + .../ObjectOperatorSpacingStandard.xml | 19 + .../ScopeKeywordSpacingStandard.xml | 23 + .../WhiteSpace/SemicolonSpacingStandard.xml | 19 + .../Arrays/ArrayBracketSpacingSniff.php | 111 + .../Sniffs/Arrays/ArrayDeclarationSniff.php | 513 +++ .../ClassDefinitionClosingBraceSpaceSniff.php | 103 + .../CSS/ClassDefinitionNameSpacingSniff.php | 118 + .../ClassDefinitionOpeningBraceSpaceSniff.php | 118 + .../Squiz/Sniffs/CSS/ColonSpacingSniff.php | 101 + .../Sniffs/CSS/ColourDefinitionSniff.php | 93 + .../DisallowMultipleStyleDefinitionsSniff.php | 81 + .../CSS/DuplicateClassDefinitionSniff.php | 113 + .../CSS/DuplicateStyleDefinitionSniff.php | 93 + .../Sniffs/CSS/EmptyClassDefinitionSniff.php | 73 + .../Sniffs/CSS/EmptyStyleDefinitionSniff.php | 73 + .../Squiz/Sniffs/CSS/ForbiddenStylesSniff.php | 185 ++ .../Squiz/Sniffs/CSS/IndentationSniff.php | 128 + .../CSS/LowercaseStyleDefinitionSniff.php | 106 + .../Squiz/Sniffs/CSS/MissingColonSniff.php | 101 + .../Squiz/Sniffs/CSS/NamedColoursSniff.php | 107 + .../Squiz/Sniffs/CSS/OpacitySniff.php | 107 + .../Sniffs/CSS/SemicolonSpacingSniff.php | 81 + .../Squiz/Sniffs/CSS/ShorthandSizeSniff.php | 161 + .../Sniffs/Classes/ClassDeclarationSniff.php | 177 + .../Sniffs/Classes/ClassFileNameSniff.php | 86 + .../Sniffs/Classes/DuplicatePropertySniff.php | 100 + .../Classes/LowercaseClassKeywordsSniff.php | 85 + .../Classes/SelfMemberReferenceSniff.php | 171 + .../Sniffs/Classes/ValidClassNameSniff.php | 95 + .../CodeAnalysis/EmptyStatementSniff.php | 54 + .../Sniffs/Commenting/BlockCommentSniff.php | 246 ++ .../Sniffs/Commenting/ClassCommentSniff.php | 254 ++ .../ClosingDeclarationCommentSniff.php | 127 + .../Commenting/DocCommentAlignmentSniff.php | 151 + .../Commenting/EmptyCatchCommentSniff.php | 73 + .../Sniffs/Commenting/FileCommentSniff.php | 564 ++++ .../Commenting/FunctionCommentSniff.php | 818 +++++ .../FunctionCommentThrowTagSniff.php | 215 ++ .../Sniffs/Commenting/InlineCommentSniff.php | 272 ++ .../LongConditionClosingCommentSniff.php | 191 ++ .../Commenting/PostStatementCommentSniff.php | 103 + .../Commenting/VariableCommentSniff.php | 345 ++ .../ControlSignatureSniff.php | 70 + .../ElseIfDeclarationSniff.php | 67 + .../ForEachLoopDeclarationSniff.php | 144 + .../ForLoopDeclarationSniff.php | 143 + .../InlineIfDeclarationSniff.php | 136 + .../LowercaseDeclarationSniff.php | 86 + .../SwitchDeclarationSniff.php | 270 ++ .../Squiz/Sniffs/Debug/JSLintSniff.php | 107 + .../Sniffs/Debug/JavaScriptLintSniff.php | 110 + .../Squiz/Sniffs/Files/FileExtensionSniff.php | 89 + .../Formatting/OperatorBracketSniff.php | 254 ++ ...unctionDeclarationArgumentSpacingSniff.php | 300 ++ .../Functions/FunctionDeclarationSniff.php | 55 + .../FunctionDuplicateArgumentSniff.php | 81 + .../Sniffs/Functions/GlobalFunctionSniff.php | 78 + .../LowercaseFunctionKeywordsSniff.php | 81 + .../MultiLineFunctionDeclarationSniff.php | 140 + .../NamingConventions/ConstantCaseSniff.php | 65 + .../ValidFunctionNameSniff.php | 74 + .../ValidVariableNameSniff.php | 241 ++ .../DisallowObjectStringIndexSniff.php | 98 + .../Objects/ObjectInstantiationSniff.php | 83 + .../Sniffs/Objects/ObjectMemberCommaSniff.php | 84 + .../ComparisonOperatorUsageSniff.php | 210 ++ .../IncrementDecrementUsageSniff.php | 234 ++ .../Operators/ValidLogicalOperatorsSniff.php | 87 + .../Sniffs/PHP/CommentedOutCodeSniff.php | 228 ++ .../PHP/DisallowBooleanStatementSniff.php | 74 + .../PHP/DisallowComparisonAssignmentSniff.php | 125 + .../Sniffs/PHP/DisallowInlineIfSniff.php | 74 + .../PHP/DisallowMultipleAssignmentsSniff.php | 180 + .../Sniffs/PHP/DisallowObEndFlushSniff.php | 68 + .../PHP/DisallowSizeFunctionsInLoopsSniff.php | 127 + .../Sniffs/PHP/DiscouragedFunctionsSniff.php | 57 + .../Squiz/Sniffs/PHP/EmbeddedPhpSniff.php | 263 ++ .../Standards/Squiz/Sniffs/PHP/EvalSniff.php | 65 + .../Sniffs/PHP/ForbiddenFunctionsSniff.php | 71 + .../Squiz/Sniffs/PHP/GlobalKeywordSniff.php | 70 + .../Squiz/Sniffs/PHP/HeredocSniff.php | 68 + .../Squiz/Sniffs/PHP/InnerFunctionsSniff.php | 75 + .../Sniffs/PHP/LowercasePHPFunctionsSniff.php | 115 + .../Sniffs/PHP/NonExecutableCodeSniff.php | 272 ++ .../Sniffs/Scope/MemberVarScopeSniff.php | 90 + .../Squiz/Sniffs/Scope/MethodScopeSniff.php | 77 + .../Sniffs/Scope/StaticThisUsageSniff.php | 99 + .../Strings/ConcatenationSpacingSniff.php | 71 + .../Sniffs/Strings/DoubleQuoteUsageSniff.php | 135 + .../Sniffs/Strings/EchoedStringsSniff.php | 84 + .../Sniffs/WhiteSpace/CastSpacingSniff.php | 77 + .../ControlStructureSpacingSniff.php | 209 ++ .../FunctionClosingBraceSpaceSniff.php | 116 + .../FunctionOpeningBraceSpaceSniff.php | 127 + .../WhiteSpace/FunctionSpacingSniff.php | 193 ++ .../LanguageConstructSpacingSniff.php | 96 + .../LogicalOperatorSpacingSniff.php | 106 + .../WhiteSpace/MemberVarSpacingSniff.php | 120 + .../WhiteSpace/ObjectOperatorSpacingSniff.php | 76 + .../WhiteSpace/OperatorSpacingSniff.php | 220 ++ .../WhiteSpace/PropertyLabelSpacingSniff.php | 85 + .../WhiteSpace/ScopeClosingBraceSniff.php | 110 + .../WhiteSpace/ScopeKeywordSpacingSniff.php | 87 + .../WhiteSpace/SemicolonSpacingSniff.php | 86 + .../WhiteSpace/SuperfluousWhitespaceSniff.php | 231 ++ .../CodeSniffer/Standards/Squiz/ruleset.xml | 81 + .../Zend/Docs/Debug/CodeAnalyzerStandard.xml | 25 + .../Zend/Docs/Files/ClosingTagStandard.xml | 22 + .../ValidVariableNameStandard.xml | 37 + .../Zend/Sniffs/Debug/CodeAnalyzerSniff.php | 125 + .../Zend/Sniffs/Files/ClosingTagSniff.php | 84 + .../ValidVariableNameSniff.php | 252 ++ .../CodeSniffer/Standards/Zend/ruleset.xml | 32 + codesniffer/CodeSniffer/Tokenizers/CSS.php | 399 +++ codesniffer/CodeSniffer/Tokenizers/JS.php | 1149 +++++++ codesniffer/CodeSniffer/Tokenizers/PHP.php | 769 +++++ codesniffer/CodeSniffer/Tokens.php | 503 +++ codesniffer/README.markdown | 64 + codesniffer/composer.json | 58 + codesniffer/composer.lock | 21 + codesniffer/licence.txt | 24 + codesniffer/scripts/phpcs | 44 + codesniffer/scripts/phpcs-svn-pre-commit | 223 ++ codesniffer/scripts/phpcs.bat | 16 + codesniffer/vendor/autoload.php | 7 + codesniffer/vendor/composer/ClassLoader.php | 415 +++ codesniffer/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 257 ++ .../vendor/composer/autoload_namespaces.php | 9 + codesniffer/vendor/composer/autoload_psr4.php | 9 + codesniffer/vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 267 ++ codesniffer/vendor/composer/installed.json | 1 + features/cli-bash-completion.feature | 77 + php/WP_CLI/Completions.php | 4 +- 383 files changed, 52523 insertions(+), 2 deletions(-) create mode 160000 PHP_Codesniffer-VariableAnalysis create mode 100644 codesniffer/.gitattributes create mode 100644 codesniffer/.gitignore create mode 100644 codesniffer/CodeSniffer.conf.dist create mode 100644 codesniffer/CodeSniffer.php create mode 100644 codesniffer/CodeSniffer/CLI.php create mode 100644 codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php create mode 100644 codesniffer/CodeSniffer/CommentParser/AbstractParser.php create mode 100644 codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php create mode 100644 codesniffer/CodeSniffer/CommentParser/CommentElement.php create mode 100644 codesniffer/CodeSniffer/CommentParser/DocElement.php create mode 100644 codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php create mode 100644 codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php create mode 100644 codesniffer/CodeSniffer/CommentParser/PairElement.php create mode 100644 codesniffer/CodeSniffer/CommentParser/ParameterElement.php create mode 100644 codesniffer/CodeSniffer/CommentParser/ParserException.php create mode 100644 codesniffer/CodeSniffer/CommentParser/SingleElement.php create mode 100644 codesniffer/CodeSniffer/DocGenerators/Generator.php create mode 100644 codesniffer/CodeSniffer/DocGenerators/HTML.php create mode 100644 codesniffer/CodeSniffer/DocGenerators/Text.php create mode 100644 codesniffer/CodeSniffer/Exception.php create mode 100644 codesniffer/CodeSniffer/File.php create mode 100644 codesniffer/CodeSniffer/Report.php create mode 100644 codesniffer/CodeSniffer/Reporting.php create mode 100644 codesniffer/CodeSniffer/Reports/Checkstyle.php create mode 100644 codesniffer/CodeSniffer/Reports/Csv.php create mode 100644 codesniffer/CodeSniffer/Reports/Emacs.php create mode 100644 codesniffer/CodeSniffer/Reports/Full.php create mode 100644 codesniffer/CodeSniffer/Reports/Gitblame.php create mode 100644 codesniffer/CodeSniffer/Reports/Hgblame.php create mode 100644 codesniffer/CodeSniffer/Reports/Json.php create mode 100644 codesniffer/CodeSniffer/Reports/Junit.php create mode 100644 codesniffer/CodeSniffer/Reports/Notifysend.php create mode 100644 codesniffer/CodeSniffer/Reports/Source.php create mode 100644 codesniffer/CodeSniffer/Reports/Summary.php create mode 100644 codesniffer/CodeSniffer/Reports/Svnblame.php create mode 100644 codesniffer/CodeSniffer/Reports/VersionControl.php create mode 100644 codesniffer/CodeSniffer/Reports/Xml.php create mode 100644 codesniffer/CodeSniffer/Sniff.php create mode 100644 codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Generic/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/IncorrectPatternException.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/MySource/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php create mode 100644 codesniffer/CodeSniffer/Standards/Zend/ruleset.xml create mode 100644 codesniffer/CodeSniffer/Tokenizers/CSS.php create mode 100644 codesniffer/CodeSniffer/Tokenizers/JS.php create mode 100644 codesniffer/CodeSniffer/Tokenizers/PHP.php create mode 100644 codesniffer/CodeSniffer/Tokens.php create mode 100644 codesniffer/README.markdown create mode 100644 codesniffer/composer.json create mode 100644 codesniffer/composer.lock create mode 100644 codesniffer/licence.txt create mode 100755 codesniffer/scripts/phpcs create mode 100755 codesniffer/scripts/phpcs-svn-pre-commit create mode 100755 codesniffer/scripts/phpcs.bat create mode 100644 codesniffer/vendor/autoload.php create mode 100644 codesniffer/vendor/composer/ClassLoader.php create mode 100644 codesniffer/vendor/composer/LICENSE create mode 100644 codesniffer/vendor/composer/autoload_classmap.php create mode 100644 codesniffer/vendor/composer/autoload_namespaces.php create mode 100644 codesniffer/vendor/composer/autoload_psr4.php create mode 100644 codesniffer/vendor/composer/autoload_real.php create mode 100644 codesniffer/vendor/composer/autoload_static.php create mode 100644 codesniffer/vendor/composer/installed.json diff --git a/PHP_Codesniffer-VariableAnalysis b/PHP_Codesniffer-VariableAnalysis new file mode 160000 index 000000000..8a126e511 --- /dev/null +++ b/PHP_Codesniffer-VariableAnalysis @@ -0,0 +1 @@ +Subproject commit 8a126e5114725d3cf93db7aff404541e6e47da72 diff --git a/codesniffer/.gitattributes b/codesniffer/.gitattributes new file mode 100644 index 000000000..2dc5d9e17 --- /dev/null +++ b/codesniffer/.gitattributes @@ -0,0 +1,10 @@ +/tests export-ignore +/CodeSniffer/Standards/Generic/Tests export-ignore +/CodeSniffer/Standards/MySource/Tests export-ignore +/CodeSniffer/Standards/PEAR/Tests export-ignore +/CodeSniffer/Standards/PSR1/Tests export-ignore +/CodeSniffer/Standards/PSR2/Tests export-ignore +/CodeSniffer/Standards/Squiz/Tests export-ignore +/CodeSniffer/Standards/Zend/Tests export-ignore +.travis.yml export-ignore +package.xml export-ignore diff --git a/codesniffer/.gitignore b/codesniffer/.gitignore new file mode 100644 index 000000000..0974c5e03 --- /dev/null +++ b/codesniffer/.gitignore @@ -0,0 +1,2 @@ +/CodeSniffer.conf +.idea/* diff --git a/codesniffer/CodeSniffer.conf.dist b/codesniffer/CodeSniffer.conf.dist new file mode 100644 index 000000000..62dc395cf --- /dev/null +++ b/codesniffer/CodeSniffer.conf.dist @@ -0,0 +1,9 @@ +<?php + $phpCodeSnifferConfig = array ( + 'default_standard' => 'PSR2', + 'report_format' => 'summary', + 'show_warnings' => '0', + 'show_progress' => '1', + 'report_width' => '120', +) +?> diff --git a/codesniffer/CodeSniffer.php b/codesniffer/CodeSniffer.php new file mode 100644 index 000000000..8ab953e43 --- /dev/null +++ b/codesniffer/CodeSniffer.php @@ -0,0 +1,2133 @@ +<?php +/** + * PHP_CodeSniffer tokenises PHP code and detects violations of a + * defined set of coding standards. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +spl_autoload_register(array('PHP_CodeSniffer', 'autoload')); + +if (class_exists('PHP_CodeSniffer_Exception', true) === false) { + throw new Exception('Class PHP_CodeSniffer_Exception not found'); +} + +if (class_exists('PHP_CodeSniffer_File', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_File not found'); +} + +if (class_exists('PHP_CodeSniffer_Tokens', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Tokens not found'); +} + +if (class_exists('PHP_CodeSniffer_CLI', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CLI not found'); +} + +if (interface_exists('PHP_CodeSniffer_Sniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Interface PHP_CodeSniffer_Sniff not found'); +} + +/** + * PHP_CodeSniffer tokenises PHP code and detects violations of a + * defined set of coding standards. + * + * Standards are specified by classes that implement the PHP_CodeSniffer_Sniff + * interface. A sniff registers what token types it wishes to listen for, then + * PHP_CodeSniffer encounters that token, the sniff is invoked and passed + * information about where the token was found in the stack, and the token stack + * itself. + * + * Sniff files and their containing class must be prefixed with Sniff, and + * have an extension of .php. + * + * Multiple PHP_CodeSniffer operations can be performed by re-calling the + * process function with different parameters. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer +{ + + /** + * The current version. + * + * @var string + */ + const VERSION = '1.5.0RC4'; + + /** + * Package stability; either stable or beta. + * + * @var string + */ + const STABILITY = 'beta'; + + /** + * The file or directory that is currently being processed. + * + * @var string + */ + protected $file = ''; + + /** + * A cache of different token types, resolved into arrays. + * + * @var array() + * @see standardiseToken() + */ + private static $_resolveTokenCache = array(); + + /** + * The directories that the processed rulesets are in. + * + * This is declared static because it is also used in the + * autoloader to look for sniffs outside the PHPCS install. + * This way, standards designed to be installed inside PHPCS can + * also be used from outside the PHPCS Standards directory. + * + * @var string + */ + protected static $rulesetDirs = array(); + + /** + * The CLI object controlling the run. + * + * @var PHP_CodeSniffer_CLI + */ + public $cli = null; + + /** + * The Reporting object controlling report generation. + * + * @var PHP_CodeSniffer_Reporting + */ + public $reporting = null; + + /** + * An array of sniff objects that are being used to check files. + * + * @var array(PHP_CodeSniffer_Sniff) + */ + protected $listeners = array(); + + /** + * An array of sniffs that are being used to check files. + * + * @var array(string) + */ + protected $sniffs = array(); + + /** + * The listeners array, indexed by token type. + * + * @var array + */ + private $_tokenListeners = array(); + + /** + * An array of rules from the ruleset.xml file. + * + * It may be empty, indicating that the ruleset does not override + * any of the default sniff settings. + * + * @var array + */ + protected $ruleset = array(); + + /** + * An array of patterns to use for skipping files. + * + * @var array + */ + protected $ignorePatterns = array(); + + /** + * An array of extensions for files we will check. + * + * @var array + */ + public $allowedFileExtensions = array( + 'php' => 'PHP', + 'inc' => 'PHP', + 'js' => 'JS', + 'css' => 'CSS', + ); + + /** + * An array of variable types for param/var we will check. + * + * @var array(string) + */ + public static $allowedTypes = array( + 'array', + 'boolean', + 'float', + 'integer', + 'mixed', + 'object', + 'string', + 'resource', + 'callable', + ); + + + /** + * Constructs a PHP_CodeSniffer object. + * + * @param int $verbosity The verbosity level. + * 1: Print progress information. + * 2: Print tokenizer debug information. + * 3: Print sniff debug information. + * @param int $tabWidth The number of spaces each tab represents. + * If greater than zero, tabs will be replaced + * by spaces before testing each file. + * @param string $encoding The charset of the sniffed files. + * This is important for some reports that output + * with utf-8 encoding as you don't want it double + * encoding messages. + * @param bool $interactive If TRUE, will stop after each file with errors + * and wait for user input. + * + * @see process() + */ + public function __construct( + $verbosity=0, + $tabWidth=0, + $encoding='iso-8859-1', + $interactive=false + ) { + if (defined('PHP_CODESNIFFER_VERBOSITY') === false) { + define('PHP_CODESNIFFER_VERBOSITY', $verbosity); + } + + if (defined('PHP_CODESNIFFER_TAB_WIDTH') === false) { + define('PHP_CODESNIFFER_TAB_WIDTH', $tabWidth); + } + + if (defined('PHP_CODESNIFFER_ENCODING') === false) { + define('PHP_CODESNIFFER_ENCODING', $encoding); + } + + if (defined('PHP_CODESNIFFER_INTERACTIVE') === false) { + define('PHP_CODESNIFFER_INTERACTIVE', $interactive); + } + + if (defined('PHPCS_DEFAULT_ERROR_SEV') === false) { + define('PHPCS_DEFAULT_ERROR_SEV', 5); + } + + if (defined('PHPCS_DEFAULT_WARN_SEV') === false) { + define('PHPCS_DEFAULT_WARN_SEV', 5); + } + + // Set default CLI object in case someone is running us + // without using the command line script. + $this->cli = new PHP_CodeSniffer_CLI(); + $this->cli->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; + $this->cli->warningSeverity = PHPCS_DEFAULT_WARN_SEV; + $this->cli->dieOnUnknownArg = false; + + $this->reporting = new PHP_CodeSniffer_Reporting(); + + }//end __construct() + + + /** + * Autoload static method for loading classes and interfaces. + * + * @param string $className The name of the class or interface. + * + * @return void + */ + public static function autoload($className) + { + if (substr($className, 0, 4) === 'PHP_') { + $newClassName = substr($className, 4); + } else { + $newClassName = $className; + } + + $path = str_replace(array('_', '\\'), '/', $newClassName).'.php'; + + if (is_file(dirname(__FILE__).'/'.$path) === true) { + // Check standard file locations based on class name. + include dirname(__FILE__).'/'.$path; + } else if (is_file(dirname(__FILE__).'/CodeSniffer/Standards/'.$path) === true) { + // Check for included sniffs. + include dirname(__FILE__).'/CodeSniffer/Standards/'.$path; + } else { + // Check standard file locations based on the loaded rulesets. + foreach (self::$rulesetDirs as $rulesetDir) { + if (is_file(dirname($rulesetDir).'/'.$path) === true) { + include_once dirname($rulesetDir).'/'.$path; + return; + } + } + + // Everything else. + @include $path; + } + + }//end autoload() + + + /** + * Sets an array of file extensions that we will allow checking of. + * + * If the extension is one of the defaults, a specific tokenizer + * will be used. Otherwise, the PHP tokenizer will be used for + * all extensions passed. + * + * @param array $extensions An array of file extensions. + * + * @return void + */ + public function setAllowedFileExtensions(array $extensions) + { + $newExtensions = array(); + foreach ($extensions as $ext) { + if (isset($this->allowedFileExtensions[$ext]) === true) { + $newExtensions[$ext] = $this->allowedFileExtensions[$ext]; + } else { + $newExtensions[$ext] = 'PHP'; + } + } + + $this->allowedFileExtensions = $newExtensions; + + }//end setAllowedFileExtensions() + + + /** + * Sets an array of ignore patterns that we use to skip files and folders. + * + * Patterns are not case sensitive. + * + * @param array $patterns An array of ignore patterns. The pattern is the key + * and the value is either "absolute" or "relative", + * depending on how the pattern should be applied to a + * file path. + * + * @return void + */ + public function setIgnorePatterns(array $patterns) + { + $this->ignorePatterns = $patterns; + + }//end setIgnorePatterns() + + + /** + * Gets the array of ignore patterns. + * + * Optionally takes a listener to get ignore patterns specified + * for that sniff only. + * + * @param string $listener The listener to get patterns for. If NULL, all + * patterns are returned. + * + * @return array + */ + public function getIgnorePatterns($listener=null) + { + if ($listener === null) { + return $this->ignorePatterns; + } + + if (isset($this->ignorePatterns[$listener]) === true) { + return $this->ignorePatterns[$listener]; + } + + return array(); + + }//end getIgnorePatterns() + + + /** + * Sets the internal CLI object. + * + * @param object $cli The CLI object controlling the run. + * + * @return void + */ + public function setCli($cli) + { + $this->cli = $cli; + + }//end setCli() + + + /** + * Processes the files/directories that PHP_CodeSniffer was constructed with. + * + * @param string|array $files The files and directories to process. For + * directories, each sub directory will also + * be traversed for source files. + * @param string|array $standards The set of code sniffs we are testing + * against. + * @param array $restrictions The sniff codes to restrict the + * violations to. + * @param boolean $local If true, don't recurse into directories. + * + * @return void + * @throws PHP_CodeSniffer_Exception If files or standard are invalid. + */ + public function process($files, $standards, array $restrictions=array(), $local=false) + { + if (is_array($files) === false) { + $files = array($files); + } + + if (is_array($standards) === false) { + $standards = array($standards); + } + + // Reset the members. + $this->listeners = array(); + $this->sniffs = array(); + $this->ruleset = array(); + $this->_tokenListeners = array(); + self::$rulesetDirs = array(); + + // Ensure this option is enabled or else line endings will not always + // be detected properly for files created on a Mac with the /r line ending. + ini_set('auto_detect_line_endings', true); + + $sniffs = array(); + foreach ($standards as $standard) { + $installed = $this->getInstalledStandardPath($standard); + if ($installed !== null) { + $standard = $installed; + } else if (is_dir($standard) === true + && is_file(realpath($standard.'/ruleset.xml')) === true + ) { + $standard = realpath($standard.'/ruleset.xml'); + } + + if (PHP_CODESNIFFER_VERBOSITY === 1) { + $ruleset = simplexml_load_file($standard); + if ($ruleset !== false) { + $standardName = (string) $ruleset['name']; + } + + echo "Registering sniffs in the $standardName standard... "; + if (count($standards) > 1 || PHP_CODESNIFFER_VERBOSITY > 2) { + echo PHP_EOL; + } + } + + $sniffs = array_merge($sniffs, $this->processRuleset($standard)); + }//end foreach + + $sniffRestrictions = array(); + foreach ($restrictions as $sniffCode) { + $parts = explode('.', strtolower($sniffCode)); + $sniffRestrictions[] = $parts[0].'_sniffs_'.$parts[1].'_'.$parts[2].'sniff'; + } + + $this->registerSniffs($sniffs, $sniffRestrictions); + $this->populateTokenListeners(); + + if (PHP_CODESNIFFER_VERBOSITY === 1) { + $numSniffs = count($this->sniffs); + echo "DONE ($numSniffs sniffs registered)".PHP_EOL; + } + + // The SVN pre-commit calls process() to init the sniffs + // and ruleset so there may not be any files to process. + // But this has to come after that initial setup. + if (empty($files) === true) { + return; + } + + $cliValues = $this->cli->getCommandLineValues(); + $showProgress = $cliValues['showProgress']; + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Creating file list... '; + } + + $todo = $this->getFilesToProcess($files, $local); + $numFiles = count($todo); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo "DONE ($numFiles files in queue)".PHP_EOL; + } + + $numProcessed = 0; + $dots = 0; + $maxLength = strlen($numFiles); + $lastDir = ''; + foreach ($todo as $file) { + $this->file = $file; + $currDir = dirname($file); + if ($lastDir !== $currDir) { + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Changing into directory '.$currDir.PHP_EOL; + } + + $lastDir = $currDir; + } + + $phpcsFile = $this->processFile($file, null, $restrictions); + $numProcessed++; + + if (PHP_CODESNIFFER_VERBOSITY > 0 + || PHP_CODESNIFFER_INTERACTIVE === true + || $showProgress === false + ) { + continue; + } + + // Show progress information. + if ($phpcsFile === null) { + echo 'S'; + } else { + $errors = $phpcsFile->getErrorCount(); + $warnings = $phpcsFile->getWarningCount(); + if ($errors > 0) { + echo 'E'; + } else if ($warnings > 0) { + echo 'W'; + } else { + echo '.'; + } + } + + $dots++; + if ($dots === 60) { + $padding = ($maxLength - strlen($numProcessed)); + echo str_repeat(' ', $padding); + $percent = round($numProcessed / $numFiles * 100); + echo " $numProcessed / $numFiles ($percent%)".PHP_EOL; + $dots = 0; + } + }//end foreach + + if (PHP_CODESNIFFER_VERBOSITY === 0 + && PHP_CODESNIFFER_INTERACTIVE === false + && $showProgress === true + ) { + echo PHP_EOL.PHP_EOL; + } + + }//end process() + + + /** + * Processes a single ruleset and returns a list of the sniffs it represents. + * + * Rules founds within the ruleset are processed immediately, but sniff classes + * are not registered by this method. + * + * @param string $rulesetPath The path to a ruleset XML file. + * @param int $depth How many nested processing steps we are in. This + * is only used for debug output. + * + * @return array + * @throws PHP_CodeSniffer_Exception If the ruleset path is invalid. + */ + public function processRuleset($rulesetPath, $depth=0) + { + $rulesetPath = realpath($rulesetPath); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "Processing ruleset $rulesetPath".PHP_EOL; + } + + $ruleset = simplexml_load_file($rulesetPath); + if ($ruleset === false) { + throw new PHP_CodeSniffer_Exception("Ruleset $rulesetPath is not valid"); + } + + $ownSniffs = array(); + $includedSniffs = array(); + $excludedSniffs = array(); + + $rulesetDir = dirname($rulesetPath); + self::$rulesetDirs[] = $rulesetDir; + + if (is_dir($rulesetDir.'/Sniffs') === true) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\tAdding sniff files from \".../".basename($rulesetDir)."/Sniffs/\" directory".PHP_EOL; + } + + $ownSniffs = $this->_expandSniffDirectory($rulesetDir.'/Sniffs', $depth); + } + + foreach ($ruleset->rule as $rule) { + if (isset($rule['ref']) === false) { + continue; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\tProcessing rule \"".$rule['ref'].'"'.PHP_EOL; + } + + $includedSniffs = array_merge( + $includedSniffs, + $this->_expandRulesetReference($rule['ref'], $rulesetDir, $depth) + ); + + if (isset($rule->exclude) === true) { + foreach ($rule->exclude as $exclude) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\tExcluding rule \"".$exclude['name'].'"'.PHP_EOL; + } + + $excludedSniffs = array_merge( + $excludedSniffs, + $this->_expandRulesetReference($exclude['name'], $rulesetDir, ($depth + 1)) + ); + } + } + + $this->_processRule($rule, $depth); + }//end foreach + + // Process custom ignore pattern rules. + foreach ($ruleset->{'exclude-pattern'} as $pattern) { + if (isset($pattern['type']) === false) { + $pattern['type'] = 'absolute'; + } + + $this->ignorePatterns[(string) $pattern] = (string) $pattern['type']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t=> added global ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL; + } + } + + $includedSniffs = array_unique(array_merge($ownSniffs, $includedSniffs)); + $excludedSniffs = array_unique($excludedSniffs); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $included = count($includedSniffs); + $excluded = count($excludedSniffs); + echo str_repeat("\t", $depth); + echo "=> Ruleset processing complete; included $included sniffs and excluded $excluded".PHP_EOL; + } + + // Merge our own sniff list with our externally included + // sniff list, but filter out any excluded sniffs. + $files = array(); + foreach ($includedSniffs as $sniff) { + if (in_array($sniff, $excludedSniffs) === true) { + continue; + } else { + $files[] = realpath($sniff); + } + } + + return $files; + + }//end processRuleset() + + + /** + * Expands a directory into a list of sniff files within. + * + * @param string $directory The path to a directory. + * @param int $depth How many nested processing steps we are in. This + * is only used for debug output. + * + * @return array + */ + private function _expandSniffDirectory($directory, $depth=0) + { + $sniffs = array(); + + if (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') === true) { + $rdi = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::FOLLOW_SYMLINKS); + } else { + $rdi = new RecursiveDirectoryIterator($directory); + } + + $di = new RecursiveIteratorIterator($rdi, 0, RecursiveIteratorIterator::CATCH_GET_CHILD); + + foreach ($di as $file) { + $fileName = $file->getFilename(); + + // Skip hidden files. + if (substr($fileName, 0, 1) === '.') { + continue; + } + + // We are only interested in PHP and sniff files. + $fileParts = explode('.', $fileName); + if (array_pop($fileParts) !== 'php') { + continue; + } + + $basename = basename($fileName, '.php'); + if (substr($basename, -5) !== 'Sniff') { + continue; + } + + $path = $file->getPathname(); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> $path".PHP_EOL; + } + + $sniffs[] = $path; + }//end foreach + + return $sniffs; + + }//end _expandSniffDirectory() + + + /** + * Expands a ruleset reference into a list of sniff files. + * + * @param string $ref The reference from the ruleset XML file. + * @param string $rulesetDir The directory of the ruleset XML file, used to + * evaluate relative paths. + * @param int $depth How many nested processing steps we are in. This + * is only used for debug output. + * + * @return array + * @throws PHP_CodeSniffer_Exception If the reference is invalid. + */ + private function _expandRulesetReference($ref, $rulesetDir, $depth=0) + { + // Ignore internal sniffs codes as they are used to only + // hide and change internal messages. + if (substr($ref, 0, 9) === 'Internal.') { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t* ignoring internal sniff code *".PHP_EOL; + } + + return array(); + } + + // As sniffs can't begin with a full stop, assume references in + // this format are relative paths and attempt to convert them + // to absolute paths. If this fails, let the reference run through + // the normal checks and have it fail as normal. + if (substr($ref, 0, 1) === '.') { + $realpath = realpath($rulesetDir.'/'.$ref); + if ($realpath !== false) { + $ref = $realpath; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> $ref".PHP_EOL; + } + } + } + + if (is_dir($ref) === false && is_file($ref) === false) { + // See if this is a whole standard being referenced. + $path = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$ref); + if (is_dir($path) === true) { + $ref = $path; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> $ref".PHP_EOL; + } + } else { + // Work out the sniff path. + $parts = explode('.', $ref); + + if (count($parts) === 1) { + // A whole standard? + $path = ''; + } else if (count($parts) === 2) { + // A directory of sniffs? + $path = '/Sniffs/'.$parts[1]; + } else { + // A single sniff? + $path = '/Sniffs/'.$parts[1].'/'.$parts[2].'Sniff.php'; + } + + $newRef = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$parts[0].$path); + if ($newRef === false) { + // The sniff is not locally installed, so check if it is being + // referenced as a remote sniff outside the install. We do this + // by looking through all directories where we have found ruleset + // files before, looking for ones for this particular standard, + // and seeing if it is in there. + foreach (self::$rulesetDirs as $dir) { + if (basename($dir) !== $parts[0]) { + continue; + } + + $newRef = realpath($dir.$path); + + if ($newRef !== false) { + $ref = $newRef; + } + } + } else { + $ref = $newRef; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> $ref".PHP_EOL; + } + } + }//end if + + if (is_dir($ref) === true) { + if (is_file($ref.'/ruleset.xml') === true) { + // We are referencing an external coding standard. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t* rule is referencing a standard using directory name; processing *".PHP_EOL; + } + + return $this->processRuleset($ref.'/ruleset.xml', ($depth + 2)); + } else { + // We are referencing a whole directory of sniffs. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t* rule is referencing a directory of sniffs *".PHP_EOL; + echo str_repeat("\t", $depth); + echo "\t\tAdding sniff files from directory".PHP_EOL; + } + + return $this->_expandSniffDirectory($ref, ($depth + 1)); + } + } else { + if (is_file($ref) === false) { + $error = "Referenced sniff \"$ref\" does not exist"; + throw new PHP_CodeSniffer_Exception($error); + } + + if (substr($ref, -9) === 'Sniff.php') { + // A single sniff. + return array($ref); + } else { + // Assume an external ruleset.xml file. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t* rule is referencing a standard using ruleset path; processing *".PHP_EOL; + } + + return $this->processRuleset($ref, ($depth + 2)); + } + }//end if + + }//end _expandRulesetReference() + + + /** + * Processes a rule from a ruleset XML file, overriding built-in defaults. + * + * @param SimpleXMLElement $rule The rule object from a ruleset XML file. + * @param int $depth How many nested processing steps we are in. + * This is only used for debug output. + * + * @return void + */ + private function _processRule($rule, $depth=0) + { + $code = (string) $rule['ref']; + + // Custom severity. + if (isset($rule->severity) === true) { + if (isset($this->ruleset[$code]) === false) { + $this->ruleset[$code] = array(); + } + + $this->ruleset[$code]['severity'] = (int) $rule->severity; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> severity set to ".(int) $rule->severity.PHP_EOL; + } + } + + // Custom message type. + if (isset($rule->type) === true) { + if (isset($this->ruleset[$code]) === false) { + $this->ruleset[$code] = array(); + } + + $this->ruleset[$code]['type'] = (string) $rule->type; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> message type set to ".(string) $rule->type.PHP_EOL; + } + } + + // Custom message. + if (isset($rule->message) === true) { + if (isset($this->ruleset[$code]) === false) { + $this->ruleset[$code] = array(); + } + + $this->ruleset[$code]['message'] = (string) $rule->message; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> message set to ".(string) $rule->message.PHP_EOL; + } + } + + // Custom properties. + if (isset($rule->properties) === true) { + foreach ($rule->properties->property as $prop) { + if (isset($this->ruleset[$code]) === false) { + $this->ruleset[$code] = array( + 'properties' => array(), + ); + } else if (isset($this->ruleset[$code]['properties']) === false) { + $this->ruleset[$code]['properties'] = array(); + } + + $name = (string) $prop['name']; + if (isset($prop['type']) === true + && (string) $prop['type'] === 'array' + ) { + $value = (string) $prop['value']; + $this->ruleset[$code]['properties'][$name] = explode(',', $value); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> array property \"$name\" set to \"$value\"".PHP_EOL; + } + } else { + $this->ruleset[$code]['properties'][$name] = (string) $prop['value']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> property \"$name\" set to \"".(string) $prop['value'].'"'.PHP_EOL; + } + } + }//end foreach + }//end if + + // Ignore patterns. + foreach ($rule->{'exclude-pattern'} as $pattern) { + if (isset($this->ignorePatterns[$code]) === false) { + $this->ignorePatterns[$code] = array(); + } + + if (isset($pattern['type']) === false) { + $pattern['type'] = 'absolute'; + } + + $this->ignorePatterns[$code][(string) $pattern] = (string) $pattern['type']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> added sniff-specific ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL; + } + } + + }//end _processRule() + + + /** + * Loads and stores sniffs objects used for sniffing files. + * + * @param array $files Paths to the sniff files to register. + * @param array $restrictions The sniff class names to restrict the allowed + * listeners to. + * + * @return void + */ + public function registerSniffs($files, $restrictions) + { + $listeners = array(); + + foreach ($files as $file) { + // Work out where the position of /StandardName/Sniffs/... is + // so we can determine what the class will be called. + $sniffPos = strrpos($file, DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR); + if ($sniffPos === false) { + continue; + } + + $slashPos = strrpos(substr($file, 0, $sniffPos), DIRECTORY_SEPARATOR); + if ($slashPos === false) { + continue; + } + + $className = substr($file, ($slashPos + 1)); + $className = substr($className, 0, -4); + $className = str_replace(DIRECTORY_SEPARATOR, '_', $className); + + // If they have specified a list of sniffs to restrict to, check + // to see if this sniff is allowed. + if (empty($restrictions) === false + && in_array(strtolower($className), $restrictions) === false + ) { + continue; + } + + include_once $file; + + // Support the use of PHP namespaces. If the class name we included + // contains namespace separators instead of underscores, use this as the + // class name from now on. + $classNameNS = str_replace('_', '\\', $className); + if (class_exists($classNameNS, false) === true) { + $className = $classNameNS; + } + + $listeners[$className] = $className; + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + echo "Registered $className".PHP_EOL; + } + }//end foreach + + $this->sniffs = $listeners; + + }//end registerSniffs() + + + /** + * Populates the array of PHP_CodeSniffer_Sniff's for this file. + * + * @return void + * @throws PHP_CodeSniffer_Exception If sniff registration fails. + */ + public function populateTokenListeners() + { + // Construct a list of listeners indexed by token being listened for. + $this->_tokenListeners = array(); + + foreach ($this->sniffs as $listenerClass) { + // Work out the internal code for this sniff. Detect usage of namespace + // separators instead of underscores to support PHP namespaces. + if (strstr($listenerClass, '\\') === false) { + $parts = explode('_', $listenerClass); + } else { + $parts = explode('\\', $listenerClass); + } + + $code = $parts[0].'.'.$parts[2].'.'.$parts[3]; + $code = substr($code, 0, -5); + + $this->listeners[$listenerClass] = new $listenerClass(); + + // Set custom properties. + if (isset($this->ruleset[$code]['properties']) === true) { + foreach ($this->ruleset[$code]['properties'] as $name => $value) { + $this->setSniffProperty($listenerClass, $name, $value); + } + } + + $tokenizers = array('PHP'); + $vars = get_class_vars($listenerClass); + if (isset($vars['supportedTokenizers']) === true) { + $tokenizers = $vars['supportedTokenizers']; + } + + $tokens = $this->listeners[$listenerClass]->register(); + if (is_array($tokens) === false) { + $msg = "Sniff $listenerClass register() method must return an array"; + throw new PHP_CodeSniffer_Exception($msg); + } + + foreach ($tokens as $token) { + if (isset($this->_tokenListeners[$token]) === false) { + $this->_tokenListeners[$token] = array(); + } + + if (in_array($this->listeners[$listenerClass], $this->_tokenListeners[$token], true) === false) { + $this->_tokenListeners[$token][] = array( + 'listener' => $this->listeners[$listenerClass], + 'class' => $listenerClass, + 'tokenizers' => $tokenizers, + ); + } + } + }//end foreach + + }//end populateTokenListeners() + + + /** + * Set a single property for a sniff. + * + * @param string $listenerClass The class name of the sniff. + * @param string $name The name of the property to change. + * @param string $value The new value of the property. + * + * @return void + */ + public function setSniffProperty($listenerClass, $name, $value) + { + // Setting a property for a sniff we are not using. + if (isset($this->listeners[$listenerClass]) === false) { + return; + } + + $name = trim($name); + if (is_string($value) === true) { + $value = trim($value); + } + + // Special case for booleans. + if ($value === 'true') { + $value = true; + } else if ($value === 'false') { + $value = false; + } + + $this->listeners[$listenerClass]->$name = $value; + + }//end setSniffProperty() + + + /** + * Get a list of files that will be processed. + * + * If passed directories, this method will find all files within them. + * The method will also perform file extension and ignore pattern filtering. + * + * @param string $paths A list of file or directory paths to process. + * @param boolean $local If true, only process 1 level of files in directories + * + * @return array + * @throws Exception If there was an error opening a directory. + * @see shouldProcessFile() + */ + public function getFilesToProcess($paths, $local=false) + { + $files = array(); + + foreach ($paths as $path) { + if (is_dir($path) === true) { + if ($local === true) { + $di = new DirectoryIterator($path); + } else { + $di = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + 0, + RecursiveIteratorIterator::CATCH_GET_CHILD + ); + } + + foreach ($di as $file) { + // Check if the file exists after all symlinks are resolved. + $filePath = realpath($file->getPathname()); + if ($filePath === false) { + continue; + } + + if (is_dir($filePath) === true) { + continue; + } + + if ($this->shouldProcessFile($file->getPathname(), $path) === false) { + continue; + } + + $files[] = $file->getPathname(); + }//end foreach + } else { + if ($this->shouldIgnoreFile($path, dirname($path)) === true) { + continue; + } + + $files[] = $path; + }//end if + }//end foreach + + return $files; + + }//end getFilesToProcess() + + + /** + * Checks filtering rules to see if a file should be checked. + * + * Checks both file extension filters and path ignore filters. + * + * @param string $path The path to the file being checked. + * @param string $basedir The directory to use for relative path checks. + * + * @return bool + */ + public function shouldProcessFile($path, $basedir) + { + // Check that the file's extension is one we are checking. + // We are strict about checking the extension and we don't + // let files through with no extension or that start with a dot. + $fileName = basename($path); + $fileParts = explode('.', $fileName); + if ($fileParts[0] === $fileName || $fileParts[0] === '') { + return false; + } + + // Checking multi-part file extensions, so need to create a + // complete extension list and make sure one is allowed. + $extensions = array(); + array_shift($fileParts); + foreach ($fileParts as $part) { + $extensions[implode('.', $fileParts)] = 1; + array_shift($fileParts); + } + + $matches = array_intersect_key($extensions, $this->allowedFileExtensions); + if (empty($matches) === true) { + return false; + } + + // If the file's path matches one of our ignore patterns, skip it. + if ($this->shouldIgnoreFile($path, $basedir) === true) { + return false; + } + + return true; + + }//end shouldProcessFile() + + + /** + * Checks filtering rules to see if a file should be ignored. + * + * @param string $path The path to the file being checked. + * @param string $basedir The directory to use for relative path checks. + * + * @return bool + */ + public function shouldIgnoreFile($path, $basedir) + { + $relativePath = $path; + if (strpos($path, $basedir) === 0) { + // The +1 cuts off the directory separator as well. + $relativePath = substr($path, (strlen($basedir) + 1)); + } + + foreach ($this->ignorePatterns as $pattern => $type) { + if (is_array($pattern) === true) { + // A sniff specific ignore pattern. + continue; + } + + // Maintains backwards compatibility in case the ignore pattern does + // not have a relative/absolute value. + if (is_int($pattern) === true) { + $pattern = $type; + $type = 'absolute'; + } + + $replacements = array( + '\\,' => ',', + '*' => '.*', + ); + + // We assume a / directory separator, as do the exclude rules + // most developers write, so we need a special case for any system + // that is different. + if (DIRECTORY_SEPARATOR === '\\') { + $replacements['/'] = '\\\\'; + } + + $pattern = strtr($pattern, $replacements); + + if ($type === 'relative') { + $testPath = $relativePath; + } else { + $testPath = $path; + } + + if (preg_match("|{$pattern}|i", $testPath) === 1) { + return true; + } + }//end foreach + + return false; + + }//end shouldIgnoreFile() + + + /** + * Run the code sniffs over a single given file. + * + * Processes the file and runs the PHP_CodeSniffer sniffs to verify that it + * conforms with the standard. Returns the processed file object, or NULL + * if no file was processed due to error. + * + * @param string $file The file to process. + * @param string $contents The contents to parse. If NULL, the content + * is taken from the file system. + * @param array $restrictions The sniff codes to restrict the + * violations to. + * + * @return PHP_CodeSniffer_File + * @throws PHP_CodeSniffer_Exception If the file could not be processed. + * @see _processFile() + */ + public function processFile($file, $contents=null, $restrictions=array()) + { + if ($contents === null && file_exists($file) === false) { + throw new PHP_CodeSniffer_Exception("Source file $file does not exist"); + } + + $filePath = realpath($file); + if ($filePath === false) { + $filePath = $file; + } + + // Before we go and spend time tokenizing this file, just check + // to see if there is a tag up top to indicate that the whole + // file should be ignored. It must be on one of the first two lines. + $firstContent = $contents; + if ($contents === null && is_readable($filePath) === true) { + $handle = fopen($filePath, 'r'); + if ($handle !== false) { + $firstContent = fgets($handle); + $firstContent .= fgets($handle); + fclose($handle); + + if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false) { + // We are ignoring the whole file. + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Ignoring '.basename($filePath).PHP_EOL; + } + + return null; + } + } + }//end if + + try { + $phpcsFile = $this->_processFile($file, $contents, $restrictions); + } catch (Exception $e) { + $trace = $e->getTrace(); + + $filename = $trace[0]['args'][0]; + if (is_object($filename) === true + && get_class($filename) === 'PHP_CodeSniffer_File' + ) { + $filename = $filename->getFilename(); + } else if (is_numeric($filename) === true) { + // See if we can find the PHP_CodeSniffer_File object. + foreach ($trace as $data) { + if (isset($data['args'][0]) === true + && ($data['args'][0] instanceof PHP_CodeSniffer_File) === true + ) { + $filename = $data['args'][0]->getFilename(); + } + } + } else if (is_string($filename) === false) { + $filename = (string) $filename; + } + + $error = 'An error occurred during processing; checking has been aborted. The error message was: '.$e->getMessage(); + + $phpcsFile = new PHP_CodeSniffer_File( + $filename, + $this->_tokenListeners, + $this->allowedFileExtensions, + $this->ruleset, + $restrictions, + $this + ); + + $phpcsFile->addError($error, null); + }//end try + + $cliValues = $this->cli->getCommandLineValues(); + + if (PHP_CODESNIFFER_INTERACTIVE === false) { + // Cache the report data for this file so we can unset it to save memory. + $this->reporting->cacheFileReport($phpcsFile, $cliValues); + return $phpcsFile; + } + + /* + Running interactively. + Print the error report for the current file and then wait for user input. + */ + + // Get current violations and then clear the list to make sure + // we only print violations for a single file each time. + $numErrors = null; + while ($numErrors !== 0) { + $numErrors = ($phpcsFile->getErrorCount() + $phpcsFile->getWarningCount()); + if ($numErrors === 0) { + continue; + } + + $reportClass = $this->reporting->factory('full'); + $reportData = $this->reporting->prepareFileReport($phpcsFile); + $reportClass->generateFileReport($reportData, $cliValues['showSources'], $cliValues['reportWidth']); + + echo '<ENTER> to recheck, [s] to skip or [q] to quit : '; + $input = fgets(STDIN); + $input = trim($input); + + switch ($input) { + case 's': + break(2); + case 'q': + exit(0); + break; + default: + // Repopulate the sniffs because some of them save their state + // and only clear it when the file changes, but we are rechecking + // the same file. + $this->populateTokenListeners(); + $phpcsFile = $this->_processFile($file, $contents, $restrictions); + break; + } + }//end while + + return $phpcsFile; + + }//end processFile() + + + /** + * Process the sniffs for a single file. + * + * Does raw processing only. No interactive support or error checking. + * + * @param string $file The file to process. + * @param string $contents The contents to parse. If NULL, the content + * is taken from the file system. + * @param array $restrictions The sniff codes to restrict the + * violations to. + * + * @return PHP_CodeSniffer_File + * @see processFile() + */ + private function _processFile($file, $contents, $restrictions) + { + if (PHP_CODESNIFFER_VERBOSITY > 0) { + $startTime = time(); + echo 'Processing '.basename($file).' '; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo PHP_EOL; + } + } + + $phpcsFile = new PHP_CodeSniffer_File( + $file, + $this->_tokenListeners, + $this->allowedFileExtensions, + $this->ruleset, + $restrictions, + $this + ); + + $phpcsFile->start($contents); + $phpcsFile->cleanUp(); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + $timeTaken = (time() - $startTime); + if ($timeTaken === 0) { + echo 'DONE in < 1 second'; + } else if ($timeTaken === 1) { + echo 'DONE in 1 second'; + } else { + echo "DONE in $timeTaken seconds"; + } + + $errors = $phpcsFile->getErrorCount(); + $warnings = $phpcsFile->getWarningCount(); + echo " ($errors errors, $warnings warnings)".PHP_EOL; + } + + return $phpcsFile; + + }//end _processFile() + + + /** + * Generates documentation for a coding standard. + * + * @param string $standard The standard to generate docs for + * @param array $sniffs A list of sniffs to limit the docs to. + * @param string $generator The name of the generator class to use. + * + * @return void + */ + public function generateDocs($standard, array $sniffs=array(), $generator='Text') + { + if (class_exists('PHP_CodeSniffer_DocGenerators_'.$generator, true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_'.$generator.' not found'); + } + + $class = "PHP_CodeSniffer_DocGenerators_$generator"; + $generator = new $class($standard, $sniffs); + + $generator->generate(); + + }//end generateDocs() + + + /** + * Gets the array of PHP_CodeSniffer_Sniff's. + * + * @return array(PHP_CodeSniffer_Sniff) + */ + public function getSniffs() + { + return $this->listeners; + + }//end getSniffs() + + + /** + * Gets the array of PHP_CodeSniffer_Sniff's indexed by token type. + * + * @return array() + */ + public function getTokenSniffs() + { + return $this->_tokenListeners; + + }//end getTokenSniffs() + + + /** + * Takes a token produced from <code>token_get_all()</code> and produces a + * more uniform token. + * + * Note that this method also resolves T_STRING tokens into more discrete + * types, therefore there is no need to call resolveTstringToken() + * + * @param string|array $token The token to convert. + * + * @return array The new token. + */ + public static function standardiseToken($token) + { + if (is_array($token) === false) { + if (isset(self::$_resolveTokenCache[$token]) === true) { + $newToken = self::$_resolveTokenCache[$token]; + } else { + $newToken = self::resolveSimpleToken($token); + } + } else { + switch ($token[0]) { + case T_STRING: + // Some T_STRING tokens can be more specific. + $tokenType = strtolower($token[1]); + if (isset(self::$_resolveTokenCache[$tokenType]) === true) { + $newToken = self::$_resolveTokenCache[$tokenType]; + } else { + $newToken = self::resolveTstringToken($tokenType); + } + + break; + case T_CURLY_OPEN: + $newToken = array( + 'code' => T_OPEN_CURLY_BRACKET, + 'type' => 'T_OPEN_CURLY_BRACKET', + ); + break; + default: + $newToken = array( + 'code' => $token[0], + 'type' => token_name($token[0]), + ); + break; + }//end switch + + $newToken['content'] = $token[1]; + }//end if + + return $newToken; + + }//end standardiseToken() + + + /** + * Converts T_STRING tokens into more usable token names. + * + * The token should be produced using the token_get_all() function. + * Currently, not all T_STRING tokens are converted. + * + * @param string $token The T_STRING token to convert as constructed + * by token_get_all(). + * + * @return array The new token. + */ + public static function resolveTstringToken($token) + { + $newToken = array(); + switch ($token) { + case 'false': + $newToken['type'] = 'T_FALSE'; + break; + case 'true': + $newToken['type'] = 'T_TRUE'; + break; + case 'null': + $newToken['type'] = 'T_NULL'; + break; + case 'self': + $newToken['type'] = 'T_SELF'; + break; + case 'parent': + $newToken['type'] = 'T_PARENT'; + break; + default: + $newToken['type'] = 'T_STRING'; + break; + } + + $newToken['code'] = constant($newToken['type']); + + self::$_resolveTokenCache[$token] = $newToken; + return $newToken; + + }//end resolveTstringToken() + + + /** + * Converts simple tokens into a format that conforms to complex tokens + * produced by token_get_all(). + * + * Simple tokens are tokens that are not in array form when produced from + * token_get_all(). + * + * @param string $token The simple token to convert. + * + * @return array The new token in array format. + */ + public static function resolveSimpleToken($token) + { + $newToken = array(); + + switch ($token) { + case '{': + $newToken['type'] = 'T_OPEN_CURLY_BRACKET'; + break; + case '}': + $newToken['type'] = 'T_CLOSE_CURLY_BRACKET'; + break; + case '[': + $newToken['type'] = 'T_OPEN_SQUARE_BRACKET'; + break; + case ']': + $newToken['type'] = 'T_CLOSE_SQUARE_BRACKET'; + break; + case '(': + $newToken['type'] = 'T_OPEN_PARENTHESIS'; + break; + case ')': + $newToken['type'] = 'T_CLOSE_PARENTHESIS'; + break; + case ':': + $newToken['type'] = 'T_COLON'; + break; + case '.': + $newToken['type'] = 'T_STRING_CONCAT'; + break; + case '?': + $newToken['type'] = 'T_INLINE_THEN'; + break; + case ';': + $newToken['type'] = 'T_SEMICOLON'; + break; + case '=': + $newToken['type'] = 'T_EQUAL'; + break; + case '*': + $newToken['type'] = 'T_MULTIPLY'; + break; + case '/': + $newToken['type'] = 'T_DIVIDE'; + break; + case '+': + $newToken['type'] = 'T_PLUS'; + break; + case '-': + $newToken['type'] = 'T_MINUS'; + break; + case '%': + $newToken['type'] = 'T_MODULUS'; + break; + case '^': + $newToken['type'] = 'T_POWER'; + break; + case '&': + $newToken['type'] = 'T_BITWISE_AND'; + break; + case '|': + $newToken['type'] = 'T_BITWISE_OR'; + break; + case '<': + $newToken['type'] = 'T_LESS_THAN'; + break; + case '>': + $newToken['type'] = 'T_GREATER_THAN'; + break; + case '!': + $newToken['type'] = 'T_BOOLEAN_NOT'; + break; + case ',': + $newToken['type'] = 'T_COMMA'; + break; + case '@': + $newToken['type'] = 'T_ASPERAND'; + break; + case '$': + $newToken['type'] = 'T_DOLLAR'; + break; + case '`': + $newToken['type'] = 'T_BACKTICK'; + break; + default: + $newToken['type'] = 'T_NONE'; + break; + }//end switch + + $newToken['code'] = constant($newToken['type']); + $newToken['content'] = $token; + + self::$_resolveTokenCache[$token] = $newToken; + return $newToken; + + }//end resolveSimpleToken() + + + /** + * Returns true if the specified string is in the camel caps format. + * + * @param string $string The string the verify. + * @param boolean $classFormat If true, check to see if the string is in the + * class format. Class format strings must start + * with a capital letter and contain no + * underscores. + * @param boolean $public If true, the first character in the string + * must be an a-z character. If false, the + * character must be an underscore. This + * argument is only applicable if $classFormat + * is false. + * @param boolean $strict If true, the string must not have two capital + * letters next to each other. If false, a + * relaxed camel caps policy is used to allow + * for acronyms. + * + * @return boolean + */ + public static function isCamelCaps( + $string, + $classFormat=false, + $public=true, + $strict=true + ) { + // Check the first character first. + if ($classFormat === false) { + $legalFirstChar = ''; + if ($public === false) { + $legalFirstChar = '[_]'; + } + + if ($strict === false) { + // Can either start with a lowercase letter, or multiple uppercase + // in a row, representing an acronym. + $legalFirstChar .= '([A-Z]{2,}|[a-z])'; + } else { + $legalFirstChar .= '[a-z]'; + } + } else { + $legalFirstChar = '[A-Z]'; + } + + if (preg_match("/^$legalFirstChar/", $string) === 0) { + return false; + } + + // Check that the name only contains legal characters. + $legalChars = 'a-zA-Z0-9'; + if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) { + return false; + } + + if ($strict === true) { + // Check that there are not two capital letters next to each other. + $length = strlen($string); + $lastCharWasCaps = $classFormat; + + for ($i = 1; $i < $length; $i++) { + $ascii = ord($string{$i}); + if ($ascii >= 48 && $ascii <= 57) { + // The character is a number, so it cant be a capital. + $isCaps = false; + } else { + if (strtoupper($string{$i}) === $string{$i}) { + $isCaps = true; + } else { + $isCaps = false; + } + } + + if ($isCaps === true && $lastCharWasCaps === true) { + return false; + } + + $lastCharWasCaps = $isCaps; + } + }//end if + + return true; + + }//end isCamelCaps() + + + /** + * Returns true if the specified string is in the underscore caps format. + * + * @param string $string The string to verify. + * + * @return boolean + */ + public static function isUnderscoreName($string) + { + // If there are space in the name, it can't be valid. + if (strpos($string, ' ') !== false) { + return false; + } + + $validName = true; + $nameBits = explode('_', $string); + + if (preg_match('|^[A-Z]|', $string) === 0) { + // Name does not begin with a capital letter. + $validName = false; + } else { + foreach ($nameBits as $bit) { + if ($bit === '') { + continue; + } + + if ($bit{0} !== strtoupper($bit{0})) { + $validName = false; + break; + } + } + } + + return $validName; + + }//end isUnderscoreName() + + + /** + * Returns a valid variable type for param/var tag. + * + * If type is not one of the standard type, it must be a custom type. + * Returns the correct type name suggestion if type name is invalid. + * + * @param string $varType The variable type to process. + * + * @return string + */ + public static function suggestType($varType) + { + if ($varType === '') { + return ''; + } + + if (in_array($varType, self::$allowedTypes) === true) { + return $varType; + } else { + $lowerVarType = strtolower($varType); + switch ($lowerVarType) { + case 'bool': + return 'boolean'; + case 'double': + case 'real': + return 'float'; + case 'int': + return 'integer'; + case 'array()': + return 'array'; + }//end switch + + if (strpos($lowerVarType, 'array(') !== false) { + // Valid array declaration: + // array, array(type), array(type1 => type2). + $matches = array(); + $pattern = '/^array\(\s*([^\s^=^>]*)(\s*=>\s*(.*))?\s*\)/i'; + if (preg_match($pattern, $varType, $matches) !== 0) { + $type1 = ''; + if (isset($matches[1]) === true) { + $type1 = $matches[1]; + } + + $type2 = ''; + if (isset($matches[3]) === true) { + $type2 = $matches[3]; + } + + $type1 = self::suggestType($type1); + $type2 = self::suggestType($type2); + if ($type2 !== '') { + $type2 = ' => '.$type2; + } + + return "array($type1$type2)"; + } else { + return 'array'; + }//end if + } else if (in_array($lowerVarType, self::$allowedTypes) === true) { + // A valid type, but not lower cased. + return $lowerVarType; + } else { + // Must be a custom type name. + return $varType; + }//end if + }//end if + + }//end suggestType() + + + /** + * Get a list of all coding standards installed. + * + * Coding standards are directories located in the + * CodeSniffer/Standards directory. Valid coding standards + * include a Sniffs subdirectory. + * + * @param boolean $includeGeneric If true, the special "Generic" + * coding standard will be included + * if installed. + * @param string $standardsDir A specific directory to look for standards + * in. If not specified, PHP_CodeSniffer will + * look in its default location. + * + * @return array + * @see isInstalledStandard() + */ + public static function getInstalledStandards( + $includeGeneric=false, + $standardsDir='' + ) { + $installedStandards = array(); + + if ($standardsDir === '') { + $standardsDir = dirname(__FILE__).'/CodeSniffer/Standards'; + } + + $di = new DirectoryIterator($standardsDir); + foreach ($di as $file) { + if ($file->isDir() === true && $file->isDot() === false) { + $filename = $file->getFilename(); + + // Ignore the special "Generic" standard. + if ($includeGeneric === false && $filename === 'Generic') { + continue; + } + + // Valid coding standard dirs include a standard class. + $csFile = $file->getPathname().'/ruleset.xml'; + if (is_file($csFile) === true) { + // We found a coding standard directory. + $installedStandards[] = $filename; + } + } + } + + return $installedStandards; + + }//end getInstalledStandards() + + + /** + * Determine if a standard is installed. + * + * Coding standards are directories located in the + * CodeSniffer/Standards directory. Valid coding standards + * include a Sniffs subdirectory. + * + * @param string $standard The name of the coding standard. + * + * @return boolean + * @see getInstalledStandards() + */ + public static function isInstalledStandard($standard) + { + $path = self::getInstalledStandardPath($standard); + if ($path !== null) { + return true; + } else { + // This could be a custom standard, installed outside our + // standards directory. + $ruleset = rtrim($standard, ' /\\').DIRECTORY_SEPARATOR.'ruleset.xml'; + if (is_file($ruleset) === true) { + return true; + } + + // Might also be an actual ruleset file itself. + // If it has an XML extension, let's at least try it. + if (is_file($standard) === true + && substr(strtolower($standard), -4) === '.xml' + ) { + return true; + } + } + + return false; + + }//end isInstalledStandard() + + + /** + * Return the path of an installed coding standard. + * + * Coding standards are directories located in the + * CodeSniffer/Standards directory. Valid coding standards + * include a Sniffs subdirectory. + * + * @param string $standard The name of the coding standard. + * + * @return string|null + */ + public static function getInstalledStandardPath($standard) + { + $path = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$standard.'/ruleset.xml'); + if (is_file($path) === true) { + return $path; + } + + return null; + + }//end getInstalledStandardPath() + + + /** + * Get a single config value. + * + * Config data is stored in the data dir, in a file called + * CodeSniffer.conf. It is a simple PHP array. + * + * @param string $key The name of the config value. + * + * @return string + * @see setConfigData() + * @see getAllConfigData() + */ + public static function getConfigData($key) + { + $phpCodeSnifferConfig = self::getAllConfigData(); + + if ($phpCodeSnifferConfig === null) { + return null; + } + + if (isset($phpCodeSnifferConfig[$key]) === false) { + return null; + } + + return $phpCodeSnifferConfig[$key]; + + }//end getConfigData() + + + /** + * Set a single config value. + * + * Config data is stored in the data dir, in a file called + * CodeSniffer.conf. It is a simple PHP array. + * + * @param string $key The name of the config value. + * @param string|null $value The value to set. If null, the config + * entry is deleted, reverting it to the + * default value. + * @param boolean $temp Set this config data temporarily for this + * script run. This will not write the config + * data to the config file. + * + * @return boolean + * @see getConfigData() + * @throws PHP_CodeSniffer_Exception If the config file can not be written. + */ + public static function setConfigData($key, $value, $temp=false) + { + if ($temp === false) { + $configFile = dirname(__FILE__).'/CodeSniffer.conf'; + if (is_file($configFile) === false + && strpos('@data_dir@', '@data_dir') === false + ) { + // If data_dir was replaced, this is a PEAR install and we can + // use the PEAR data dir to store the conf file. + $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; + } + + if (is_file($configFile) === true + && is_writable($configFile) === false + ) { + $error = "Config file $configFile is not writable"; + throw new PHP_CodeSniffer_Exception($error); + } + } + + $phpCodeSnifferConfig = self::getAllConfigData(); + + if ($value === null) { + if (isset($phpCodeSnifferConfig[$key]) === true) { + unset($phpCodeSnifferConfig[$key]); + } + } else { + $phpCodeSnifferConfig[$key] = $value; + } + + if ($temp === false) { + $output = '<'.'?php'."\n".' $phpCodeSnifferConfig = '; + $output .= var_export($phpCodeSnifferConfig, true); + $output .= "\n?".'>'; + + if (file_put_contents($configFile, $output) === false) { + return false; + } + } + + $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig; + + return true; + + }//end setConfigData() + + + /** + * Get all config data in an array. + * + * @return string + * @see getConfigData() + */ + public static function getAllConfigData() + { + if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']) === true) { + return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']; + } + + $configFile = dirname(__FILE__).'/CodeSniffer.conf'; + if (is_file($configFile) === false) { + $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; + } + + if (is_file($configFile) === false) { + return null; + } + + include $configFile; + $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig; + return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']; + + }//end getAllConfigData() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CLI.php b/codesniffer/CodeSniffer/CLI.php new file mode 100644 index 000000000..dd45123b1 --- /dev/null +++ b/codesniffer/CodeSniffer/CLI.php @@ -0,0 +1,877 @@ +<?php +/** + * A class to process command line phpcs scripts. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (is_file(dirname(__FILE__).'/../CodeSniffer.php') === true) { + include_once dirname(__FILE__).'/../CodeSniffer.php'; +} else { + include_once 'PHP/CodeSniffer.php'; +} + +/** + * A class to process command line phpcs scripts. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CLI +{ + + /** + * An array of all values specified on the command line. + * + * @var array + */ + protected $values = array(); + + /** + * The minimum severity level errors must have to be displayed. + * + * @var bool + */ + public $errorSeverity = 0; + + /** + * The minimum severity level warnings must have to be displayed. + * + * @var bool + */ + public $warningSeverity = 0; + + /** + * Whether or not to kill the process when an unknown command line arg is found. + * + * If FALSE, arguments that are not command line options or file/directory paths + * will be ignored and execution will continue. + * + * @var bool + */ + public $dieOnUnknownArg = true; + + + /** + * Exits if the minimum requirements of PHP_CodSniffer are not met. + * + * @return array + */ + public function checkRequirements() + { + // Check the PHP version. + if (version_compare(PHP_VERSION, '5.1.2') === -1) { + echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL; + exit(2); + } + + if (extension_loaded('tokenizer') === false) { + echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL; + exit(2); + } + + }//end checkRequirements() + + + /** + * Get a list of default values for all possible command line arguments. + * + * @return array + */ + public function getDefaults() + { + // The default values for config settings. + $defaults['files'] = array(); + $defaults['standard'] = null; + $defaults['verbosity'] = 0; + $defaults['interactive'] = false; + $defaults['explain'] = false; + $defaults['local'] = false; + $defaults['showSources'] = false; + $defaults['extensions'] = array(); + $defaults['sniffs'] = array(); + $defaults['ignored'] = array(); + $defaults['reportFile'] = null; + $defaults['generator'] = ''; + $defaults['reports'] = array(); + $defaults['errorSeverity'] = null; + $defaults['warningSeverity'] = null; + + $reportFormat = PHP_CodeSniffer::getConfigData('report_format'); + if ($reportFormat !== null) { + $defaults['reports'][$reportFormat] = null; + } + + $tabWidth = PHP_CodeSniffer::getConfigData('tab_width'); + if ($tabWidth === null) { + $defaults['tabWidth'] = 0; + } else { + $defaults['tabWidth'] = (int) $tabWidth; + } + + $encoding = PHP_CodeSniffer::getConfigData('encoding'); + if ($encoding === null) { + $defaults['encoding'] = 'iso-8859-1'; + } else { + $defaults['encoding'] = strtolower($encoding); + } + + $severity = PHP_CodeSniffer::getConfigData('severity'); + if ($severity !== null) { + $defaults['errorSeverity'] = (int) $severity; + $defaults['warningSeverity'] = (int) $severity; + } + + $severity = PHP_CodeSniffer::getConfigData('error_severity'); + if ($severity !== null) { + $defaults['errorSeverity'] = (int) $severity; + } + + $severity = PHP_CodeSniffer::getConfigData('warning_severity'); + if ($severity !== null) { + $defaults['warningSeverity'] = (int) $severity; + } + + $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings'); + if ($showWarnings !== null) { + $showWarnings = (bool) $showWarnings; + if ($showWarnings === false) { + $defaults['warningSeverity'] = 0; + } + } + + $reportWidth = PHP_CodeSniffer::getConfigData('report_width'); + if ($reportWidth === null) { + $defaults['reportWidth'] = 80; + } else { + $defaults['reportWidth'] = (int) $reportWidth; + } + + $showProgress = PHP_CodeSniffer::getConfigData('show_progress'); + if ($showProgress === null) { + $defaults['showProgress'] = false; + } else { + $defaults['showProgress'] = (bool) $showProgress; + } + + return $defaults; + + }//end getDefaults() + + + /** + * Process the command line arguments and returns the values. + * + * @return array + */ + public function getCommandLineValues() + { + if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { + return array(); + } + + if (empty($this->values) === false) { + return $this->values; + } + + $values = $this->getDefaults(); + + for ($i = 1; $i < $_SERVER['argc']; $i++) { + $arg = $_SERVER['argv'][$i]; + if ($arg === '') { + continue; + } + + if ($arg{0} === '-') { + if ($arg === '-' || $arg === '--') { + // Empty argument, ignore it. + continue; + } + + if ($arg{1} === '-') { + $values + = $this->processLongArgument(substr($arg, 2), $i, $values); + } else { + $switches = str_split($arg); + foreach ($switches as $switch) { + if ($switch === '-') { + continue; + } + + $values = $this->processShortArgument($switch, $i, $values); + } + } + } else { + $values = $this->processUnknownArgument($arg, $i, $values); + }//end if + }//end for + + $this->values = $values; + return $values; + + }//end getCommandLineValues() + + + /** + * Processes a short (-e) command line argument. + * + * @param string $arg The command line argument. + * @param int $pos The position of the argument on the command line. + * @param array $values An array of values determined from CLI args. + * + * @return array The updated CLI values. + * @see getCommandLineValues() + */ + public function processShortArgument($arg, $pos, $values) + { + switch ($arg) { + case 'h': + case '?': + $this->printUsage(); + exit(0); + break; + case 'i' : + $this->printInstalledStandards(); + exit(0); + break; + case 'v' : + $values['verbosity']++; + break; + case 'l' : + $values['local'] = true; + break; + case 's' : + $values['showSources'] = true; + break; + case 'a' : + $values['interactive'] = true; + break; + case 'e': + $values['explain'] = true; + break; + case 'p' : + $values['showProgress'] = true; + break; + case 'd' : + $ini = explode('=', $_SERVER['argv'][($pos + 1)]); + $_SERVER['argv'][($pos + 1)] = ''; + if (isset($ini[1]) === true) { + ini_set($ini[0], $ini[1]); + } else { + ini_set($ini[0], true); + } + + break; + case 'n' : + $values['warningSeverity'] = 0; + break; + case 'w' : + $values['warningSeverity'] = null; + break; + default: + $values = $this->processUnknownArgument('-'.$arg, $pos, $values); + }//end switch + + return $values; + + }//end processShortArgument() + + + /** + * Processes a long (--example) command line argument. + * + * @param string $arg The command line argument. + * @param int $pos The position of the argument on the command line. + * @param array $values An array of values determined from CLI args. + * + * @return array The updated CLI values. + * @see getCommandLineValues() + */ + public function processLongArgument($arg, $pos, $values) + { + switch ($arg) { + case 'help': + $this->printUsage(); + exit(0); + break; + case 'version': + $phpcs = new PHP_CodeSniffer(); + echo 'PHP_CodeSniffer version '.$phpcs::VERSION.' ('.$phpcs::STABILITY.') '; + echo 'by Squiz (http://www.squiz.net)'.PHP_EOL; + exit(0); + break; + case 'config-set': + $key = $_SERVER['argv'][($pos + 1)]; + $value = $_SERVER['argv'][($pos + 2)]; + PHP_CodeSniffer::setConfigData($key, $value); + exit(0); + break; + case 'config-delete': + $key = $_SERVER['argv'][($pos + 1)]; + PHP_CodeSniffer::setConfigData($key, null); + exit(0); + break; + case 'config-show': + $data = PHP_CodeSniffer::getAllConfigData(); + print_r($data); + exit(0); + break; + default: + if (substr($arg, 0, 7) === 'sniffs=') { + $sniffs = substr($arg, 7); + $values['sniffs'] = explode(',', $sniffs); + } else if (substr($arg, 0, 12) === 'report-file=') { + $values['reportFile'] = realpath(substr($arg, 12)); + + // It may not exist and return false instead. + if ($values['reportFile'] === false) { + $values['reportFile'] = substr($arg, 12); + } + + if (is_dir($values['reportFile']) === true) { + echo 'ERROR: The specified report file path "'.$values['reportFile'].'" is a directory.'.PHP_EOL.PHP_EOL; + $this->printUsage(); + exit(2); + } + + $dir = dirname($values['reportFile']); + if (is_dir($dir) === false) { + echo 'ERROR: The specified report file path "'.$values['reportFile'].'" points to a non-existent directory.'.PHP_EOL.PHP_EOL; + $this->printUsage(); + exit(2); + } + + if ($dir === '.') { + // Passed report file is a filename in the current directory. + $values['reportFile'] = getcwd().'/'.basename($values['reportFile']); + } else { + $dir = realpath(getcwd().'/'.$dir); + if ($dir !== false) { + // Report file path is relative. + $values['reportFile'] = $dir.'/'.basename($values['reportFile']); + } + } + } else if (substr($arg, 0, 13) === 'report-width=') { + $values['reportWidth'] = (int) substr($arg, 13); + } else if (substr($arg, 0, 7) === 'report=' + || substr($arg, 0, 7) === 'report-' + ) { + if ($arg[6] === '-') { + // This is a report with file output. + $split = strpos($arg, '='); + if ($split === false) { + $report = substr($arg, 7); + $output = null; + } else { + $report = substr($arg, 7, ($split - 7)); + $output = substr($arg, ($split + 1)); + if ($output === false) { + $output = null; + } else { + $dir = dirname($output); + if ($dir === '.') { + // Passed report file is a filename in the current directory. + $output = getcwd().'/'.basename($output); + } else { + $dir = realpath(getcwd().'/'.$dir); + if ($dir !== false) { + // Report file path is relative. + $output = $dir.'/'.basename($output); + } + } + }//end if + }//end if + } else { + // This is a single report. + $report = substr($arg, 7); + $output = null; + } + + $validReports = array( + 'full', + 'xml', + 'json', + 'checkstyle', + 'junit', + 'csv', + 'emacs', + 'notifysend', + 'source', + 'summary', + 'svnblame', + 'gitblame', + 'hgblame', + ); + + if (in_array($report, $validReports) === false) { + echo 'ERROR: Report type "'.$report.'" not known.'.PHP_EOL; + exit(2); + } + + $values['reports'][$report] = $output; + } else if (substr($arg, 0, 9) === 'standard=') { + $values['standard'] = explode(',', substr($arg, 9)); + } else if (substr($arg, 0, 11) === 'extensions=') { + $values['extensions'] = explode(',', substr($arg, 11)); + } else if (substr($arg, 0, 9) === 'severity=') { + $values['errorSeverity'] = (int) substr($arg, 9); + $values['warningSeverity'] = $values['errorSeverity']; + } else if (substr($arg, 0, 15) === 'error-severity=') { + $values['errorSeverity'] = (int) substr($arg, 15); + } else if (substr($arg, 0, 17) === 'warning-severity=') { + $values['warningSeverity'] = (int) substr($arg, 17); + } else if (substr($arg, 0, 7) === 'ignore=') { + // Split the ignore string on commas, unless the comma is escaped + // using 1 or 3 slashes (\, or \\\,). + $ignored = preg_split( + '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/', + substr($arg, 7) + ); + foreach ($ignored as $pattern) { + $values['ignored'][$pattern] = 'absolute'; + } + } else if (substr($arg, 0, 10) === 'generator=') { + $values['generator'] = substr($arg, 10); + } else if (substr($arg, 0, 9) === 'encoding=') { + $values['encoding'] = strtolower(substr($arg, 9)); + } else if (substr($arg, 0, 10) === 'tab-width=') { + $values['tabWidth'] = (int) substr($arg, 10); + } else { + $values = $this->processUnknownArgument('--'.$arg, $pos, $values); + }//end if + + break; + }//end switch + + return $values; + + }//end processLongArgument() + + + /** + * Processes an unknown command line argument. + * + * Assumes all unknown arguments are files and folders to check. + * + * @param string $arg The command line argument. + * @param int $pos The position of the argument on the command line. + * @param array $values An array of values determined from CLI args. + * + * @return array The updated CLI values. + * @see getCommandLineValues() + */ + public function processUnknownArgument($arg, $pos, $values) + { + // We don't know about any additional switches; just files. + if ($arg{0} === '-') { + if ($this->dieOnUnknownArg === false) { + return $values; + } + + echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL; + $this->printUsage(); + exit(2); + } + + $file = realpath($arg); + if (file_exists($file) === false) { + if ($this->dieOnUnknownArg === false) { + return $values; + } + + echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL; + $this->printUsage(); + exit(2); + } else { + $values['files'][] = $file; + } + + return $values; + + }//end processUnknownArgument() + + + /** + * Runs PHP_CodeSniffer over files and directories. + * + * @param array $values An array of values determined from CLI args. + * + * @return int The number of error and warning messages shown. + * @see getCommandLineValues() + */ + public function process($values=array()) + { + if (empty($values) === true) { + $values = $this->getCommandLineValues(); + } + + if ($values['generator'] !== '') { + $phpcs = new PHP_CodeSniffer($values['verbosity']); + foreach ($values['standard'] as $standard) { + $phpcs->generateDocs( + $standard, + $values['files'], + $values['generator'] + ); + } + exit(0); + } + + // If no standard is supplied, get the default. + $values['standard'] = $this->validateStandard($values['standard']); + foreach ($values['standard'] as $standard) { + if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { + // They didn't select a valid coding standard, so help them + // out by letting them know which standards are installed. + echo 'ERROR: the "'.$standard.'" coding standard is not installed. '; + $this->printInstalledStandards(); + exit(2); + } + } + + if ($values['explain'] === true) { + foreach ($values['standard'] as $standard) { + $this->explainStandard($standard); + } + + exit(0); + } + + $fileContents = ''; + if (empty($values['files']) === true) { + // Check if they are passing in the file contents. + $handle = fopen('php://stdin', 'r'); + $fileContents = stream_get_contents($handle); + fclose($handle); + + if ($fileContents === '') { + // No files and no content passed in. + echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL; + $this->printUsage(); + exit(2); + } + } + + $phpcs = new PHP_CodeSniffer( + $values['verbosity'], + $values['tabWidth'], + $values['encoding'], + $values['interactive'] + ); + + // Set file extensions if they were specified. Otherwise, + // let PHP_CodeSniffer decide on the defaults. + if (empty($values['extensions']) === false) { + $phpcs->setAllowedFileExtensions($values['extensions']); + } + + // Set ignore patterns if they were specified. + if (empty($values['ignored']) === false) { + $phpcs->setIgnorePatterns($values['ignored']); + } + + // Set some convenience member vars. + if ($values['errorSeverity'] === null) { + $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; + } else { + $this->errorSeverity = $values['errorSeverity']; + } + + if ($values['warningSeverity'] === null) { + $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; + } else { + $this->warningSeverity = $values['warningSeverity']; + } + + if (empty($values['reports']) === true) { + $this->values['reports']['full'] = $values['reportFile']; + } + + $phpcs->setCli($this); + + $phpcs->process( + $values['files'], + $values['standard'], + $values['sniffs'], + $values['local'] + ); + + if ($fileContents !== '') { + $phpcs->processFile('STDIN', $fileContents); + } + + // Interactive runs don't require a final report and it doesn't really + // matter what the retun value is because we know it isn't being read + // by a script. + if ($values['interactive'] === true) { + return 0; + } + + return $this->printErrorReport( + $phpcs, + $values['reports'], + $values['showSources'], + $values['reportFile'], + $values['reportWidth'] + ); + + }//end process() + + + /** + * Prints the error report for the run. + * + * Note that this function may actually print multiple reports + * as the user may have specified a number of output formats. + * + * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing + * the errors. + * @param array $reports A list of reports to print. + * @param bool $showSources TRUE if report should show error sources + * (not used by all reports). + * @param string $reportFile A default file to log report output to. + * @param int $reportWidth How wide the screen reports should be. + * + * @return int The number of error and warning messages shown. + */ + public function printErrorReport( + PHP_CodeSniffer $phpcs, + $reports, + $showSources, + $reportFile, + $reportWidth + ) { + if (empty($reports) === true) { + $reports['full'] = $reportFile; + } + + $errors = 0; + $toScreen = false; + + foreach ($reports as $report => $output) { + if ($output === null) { + $output = $reportFile; + } + + if ($reportFile === null) { + $toScreen = true; + } + + // We don't add errors here because the number of + // errors reported by each report type will always be the + // same, so we really just need 1 number. + $errors = $phpcs->reporting->printReport( + $report, + $showSources, + $output, + $reportWidth + ); + } + + // Only print PHP_Timer output if no reports were + // printed to the screen so we don't put additional output + // in something like an XML report. If we are printing to screen, + // the report types would have already worked out who should + // print the timer info. + if ($toScreen === false + && PHP_CODESNIFFER_INTERACTIVE === false + && class_exists('PHP_Timer', false) === true + ) { + echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; + } + + // They should all return the same value, so it + // doesn't matter which return value we end up using. + return $errors; + + }//end printErrorReport() + + + /** + * Convert the passed standards into valid standards. + * + * Checks things like default values and case. + * + * @param array $standards The standards to validate. + * + * @return array + */ + public function validateStandard($standards) + { + if ($standards === null) { + // They did not supply a standard to use. + // Try to get the default from the config system. + $standard = PHP_CodeSniffer::getConfigData('default_standard'); + if ($standard === null) { + // Product default standard. + $standard = 'PEAR'; + } + + return array($standard); + } + + $cleaned = array(); + + // Check if the standard name is valid, or if the case is invalid. + $installedStandards = PHP_CodeSniffer::getInstalledStandards(); + foreach ($standards as $standard) { + foreach ($installedStandards as $validStandard) { + if (strtolower($standard) === strtolower($validStandard)) { + $standard = $validStandard; + break; + } + } + + $cleaned[] = $standard; + } + + return $cleaned; + + }//end validateStandard() + + + /** + * Prints a report showing the sniffs contained in a standard. + * + * @param string $standard The standard to validate. + * + * @return void + */ + public function explainStandard($standard) + { + $phpcs = new PHP_CodeSniffer(); + $phpcs->process(array(), $standard); + $sniffs = $phpcs->getSniffs(); + $sniffs = array_keys($sniffs); + sort($sniffs); + + ob_start(); + + $lastStandard = ''; + $lastCount = ''; + $sniffCount = count($sniffs); + $sniffs[] = '___'; + + echo PHP_EOL."The $standard standard contains $sniffCount sniffs".PHP_EOL; + + ob_start(); + + foreach ($sniffs as $sniff) { + $parts = explode('_', str_replace('\\', '_', $sniff)); + if ($lastStandard === '') { + $lastStandard = $parts[0]; + } + + if ($parts[0] !== $lastStandard) { + $sniffList = ob_get_contents(); + ob_end_clean(); + + echo PHP_EOL.$lastStandard.' ('.$lastCount.' sniffs)'.PHP_EOL; + echo str_repeat('-', strlen($lastStandard.$lastCount) + 10); + echo PHP_EOL; + echo $sniffList; + + $lastStandard = $parts[0]; + $lastCount = 0; + + ob_start(); + } + + echo ' '.$parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5).PHP_EOL; + $lastCount++; + }//end foreach + + ob_end_clean(); + + }//end explainStandard() + + + /** + * Prints out the usage information for this script. + * + * @return void + */ + public function printUsage() + { + echo 'Usage: phpcs [-nwlsaepvi] [-d key[=value]]'.PHP_EOL; + echo ' [--report=<report>] [--report-file=<reportfile>] [--report-<report>=<reportfile>] ...'.PHP_EOL; + echo ' [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>]'.PHP_EOL; + echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL; + echo ' [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL; + echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--encoding=<encoding>]'.PHP_EOL; + echo ' [--extensions=<extensions>] [--ignore=<patterns>] <file> ...'.PHP_EOL; + echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL; + echo ' -w Print both warnings and errors (on by default)'.PHP_EOL; + echo ' -l Local directory only, no recursion'.PHP_EOL; + echo ' -s Show sniff codes in all reports'.PHP_EOL; + echo ' -a Run interactively'.PHP_EOL; + echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL; + echo ' -p Show progress of the run'.PHP_EOL; + echo ' -v[v][v] Print verbose output'.PHP_EOL; + echo ' -i Show a list of installed coding standards'.PHP_EOL; + echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; + echo ' --help Print this help message'.PHP_EOL; + echo ' --version Print version information'.PHP_EOL; + echo ' <file> One or more files and/or directories to check'.PHP_EOL; + echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL; + echo ' (only valid if checking a directory)'.PHP_EOL; + echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL; + echo ' <encoding> The encoding of the files being checked (default is iso-8859-1)'.PHP_EOL; + echo ' <sniffs> A comma separated list of sniff codes to limit the check to'.PHP_EOL; + echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; + echo ' <severity> The minimum severity required to display an error or warning'.PHP_EOL; + echo ' <standard> The name or path of the coding standard to use'.PHP_EOL; + echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL; + echo ' <generator> The name of a doc generator to use'.PHP_EOL; + echo ' (forces doc generation instead of checking)'.PHP_EOL; + echo ' <report> Print either the "full", "xml", "checkstyle", "csv", "json"'.PHP_EOL; + echo ' "emacs", "source", "summary", "svnblame", "gitblame", "hgblame" or'.PHP_EOL; + echo ' "notifysend" report'.PHP_EOL; + echo ' (the "full" report is printed by default)'.PHP_EOL; + echo ' <reportfile> Write the report to the specified file path'.PHP_EOL; + echo ' <reportWidth> How many columns wide screen reports should be printed'.PHP_EOL; + + }//end printUsage() + + + /** + * Prints out a list of installed coding standards. + * + * @return void + */ + public function printInstalledStandards() + { + $installedStandards = PHP_CodeSniffer::getInstalledStandards(); + $numStandards = count($installedStandards); + + if ($numStandards === 0) { + echo 'No coding standards are installed.'.PHP_EOL; + } else { + $lastStandard = array_pop($installedStandards); + if ($numStandards === 1) { + echo "The only coding standard installed is $lastStandard".PHP_EOL; + } else { + $standardList = implode(', ', $installedStandards); + $standardList .= ' and '.$lastStandard; + echo 'The installed coding standards are '.$standardList.PHP_EOL; + } + } + + }//end printInstalledStandards() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php b/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php new file mode 100644 index 000000000..b804df232 --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php @@ -0,0 +1,353 @@ +<?php +/** + * A class to handle most of the parsing operations of a doc comment element. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (interface_exists('PHP_CodeSniffer_CommentParser_DocElement', true) === false) { + $error = 'Interface PHP_CodeSniffer_CommentParser_DocElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to handle most of the parsing operations of a doc comment element. + * + * Extending classes should implement the getSubElements method to return + * a list of elements that the doc comment element contains, in the order that + * they appear in the element. For example a function parameter element has a + * type, a variable name and a comment. It should therefore implement the method + * as follows: + * + * <code> + * protected function getSubElements() + * { + * return array( + * 'type', + * 'variable', + * 'comment', + * ); + * } + * </code> + * + * The processSubElement will be called for each of the sub elements to allow + * the extending class to process them. So for the parameter element we would + * have: + * + * <code> + * protected function processSubElement($name, $content, $whitespaceBefore) + * { + * if ($name === 'type') { + * echo 'The name of the variable was '.$content; + * } + * // Process other tags. + * } + * </code> + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_CommentParser_AbstractDocElement implements PHP_CodeSniffer_CommentParser_DocElement +{ + + /** + * The element previous to this element. + * + * @var PHP_CodeSniffer_CommentParser_DocElement + */ + protected $previousElement = null; + + /** + * The element proceeding this element. + * + * @var PHP_CodeSniffer_CommentParser_DocElement + */ + protected $nextElement = null; + + /** + * The whitespace the occurs after this element and its sub elements. + * + * @var string + */ + protected $afterWhitespace = ''; + + /** + * The tokens that comprise this element. + * + * @var array(string) + */ + protected $tokens = array(); + + /** + * The file this element is in. + * + * @var array(string) + */ + protected $phpcsFile = null; + + /** + * The tag that this element represents (omitting the @ symbol). + * + * @var string + */ + protected $tag = ''; + + + /** + * Constructs a Doc Element. + * + * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element + * that ocurred + * before this. + * @param array $tokens The tokens of + * this element. + * @param string $tag The doc + * element tag + * this element + * represents. + * @param PHP_CodeSniffer_File $phpcsFile The file that + * this element + * is in. + * + * @throws Exception If $previousElement in not a DocElement or if + * getSubElements() does not return an array. + */ + public function __construct( + $previousElement, + array $tokens, + $tag, + PHP_CodeSniffer_File $phpcsFile + ) { + if ($previousElement !== null + && ($previousElement instanceof PHP_CodeSniffer_CommentParser_DocElement) === false + ) { + $error = '$previousElement must be an instance of DocElement'; + throw new Exception($error); + } + + $this->phpcsFile = $phpcsFile; + + $this->previousElement = $previousElement; + if ($previousElement !== null) { + $this->previousElement->nextElement = $this; + } + + $this->tag = $tag; + $this->tokens = $tokens; + + $subElements = $this->getSubElements(); + + if (is_array($subElements) === false) { + throw new Exception('getSubElements() must return an array'); + } + + $whitespace = ''; + $currElem = 0; + $lastElement = ''; + $lastElementWhitespace = null; + $numSubElements = count($subElements); + + foreach ($this->tokens as $token) { + if (trim($token) === '') { + $whitespace .= $token; + } else { + if ($currElem < ($numSubElements - 1)) { + $element = $subElements[$currElem]; + $this->processSubElement($element, $token, $whitespace); + $whitespace = ''; + $currElem++; + } else { + if ($lastElementWhitespace === null) { + $lastElementWhitespace = $whitespace; + } + + $lastElement .= $whitespace.$token; + $whitespace = ''; + } + } + }//end foreach + + $lastElement = ltrim($lastElement); + $lastElementName = $subElements[($numSubElements - 1)]; + + // Process the last element in this tag. + $this->processSubElement( + $lastElementName, + $lastElement, + $lastElementWhitespace + ); + + $this->afterWhitespace = $whitespace; + + }//end __construct() + + + /** + * Returns the element that exists before this. + * + * @return PHP_CodeSniffer_CommentParser_DocElement + */ + public function getPreviousElement() + { + return $this->previousElement; + + }//end getPreviousElement() + + + /** + * Returns the element that exists after this. + * + * @return PHP_CodeSniffer_CommentParser_DocElement + */ + public function getNextElement() + { + return $this->nextElement; + + }//end getNextElement() + + + /** + * Returns the whitespace that exists before this element. + * + * @return string + */ + public function getWhitespaceBefore() + { + if ($this->previousElement !== null) { + return $this->previousElement->getWhitespaceAfter(); + } + + return ''; + + }//end getWhitespaceBefore() + + + /** + * Returns the whitespace that exists after this element. + * + * @return string + */ + public function getWhitespaceAfter() + { + return $this->afterWhitespace; + + }//end getWhitespaceAfter() + + + /** + * Returns the order that this element appears in the comment. + * + * @return int + */ + public function getOrder() + { + if ($this->previousElement === null) { + return 1; + } else { + return ($this->previousElement->getOrder() + 1); + } + + }//end getOrder() + + + /** + * Returns the tag that this element represents, ommiting the @ symbol. + * + * @return string + */ + public function getTag() + { + return $this->tag; + + }//end getTag() + + + /** + * Returns the raw content of this element, ommiting the tag. + * + * @return string + */ + public function getRawContent() + { + return implode('', $this->tokens); + + }//end getRawContent() + + + /** + * Returns the comment tokens. + * + * @return array + */ + public function getTokens() + { + return $this->tokens; + + }//end getTokens() + + + /** + * Returns the line in which this element first occured. + * + * @return int + */ + public function getLine() + { + if ($this->previousElement === null) { + // First element is on line one. + return 1; + } else { + $previousContent = $this->previousElement->getRawContent(); + $previousLine = $this->previousElement->getLine(); + + return ($previousLine + substr_count($previousContent, $this->phpcsFile->eolChar)); + } + + }//end getLine() + + + /** + * Returns the sub element names that make up this element in the order they + * appear in the element. + * + * @return array(string) + * @see processSubElement() + */ + abstract protected function getSubElements(); + + + /** + * Called to process each sub element as sepcified in the return value + * of getSubElements(). + * + * @param string $name The name of the element to process. + * @param string $content The content of the the element. + * @param string $whitespaceBefore The whitespace found before this element. + * + * @return void + * @see getSubElements() + */ + abstract protected function processSubElement( + $name, + $content, + $whitespaceBefore + ); + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/AbstractParser.php b/codesniffer/CodeSniffer/CommentParser/AbstractParser.php new file mode 100644 index 000000000..f7f6a653b --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/AbstractParser.php @@ -0,0 +1,684 @@ +<?php +/** + * Parses doc comments. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_CommentElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_CommentElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_ParserException', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_ParserException not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses doc comments. + * + * This abstract parser handles the following tags: + * + * <ul> + * <li>The short description and the long description</li> + * <li>@see</li> + * <li>@link</li> + * <li>@deprecated</li> + * <li>@since</li> + * </ul> + * + * Extending classes should implement the getAllowedTags() method to return the + * tags that they wish to process, omitting the tags that this base class + * processes. When one of these tags in encountered, the process<tag_name> + * method is called on that class. For example, if a parser's getAllowedTags() + * method returns \@param as one of its tags, the processParam method will be + * called so that the parser can process such a tag. + * + * The method is passed the tokens that comprise this tag. The tokens array + * includes the whitespace that exists between the tokens, as separate tokens. + * It's up to the method to create a element that implements the DocElement + * interface, which should be returned. The AbstractDocElement class is a helper + * class that can be used to handle most of the parsing of the tokens into their + * individual sub elements. It requires that you construct it with the element + * previous to the element currently being processed, which can be acquired + * with the protected $previousElement class member of this class. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_CommentParser_AbstractParser +{ + + /** + * The comment element that appears in the doc comment. + * + * @var PHP_CodeSniffer_CommentParser_CommentElement + */ + protected $comment = null; + + /** + * The string content of the comment. + * + * @var string + */ + protected $commentString = ''; + + /** + * The file that the comment exists in. + * + * @var PHP_CodeSniffer_File + */ + protected $phpcsFile = null; + + /** + * The word tokens that appear in the comment. + * + * Whitespace tokens also appear in this stack, but are separate tokens + * from words. + * + * @var array(string) + */ + protected $words = array(); + + /** + * An array of all tags found in the comment. + * + * @var array(string) + */ + protected $foundTags = array(); + + /** + * The previous doc element that was processed. + * + * null if the current element being processed is the first element in the + * doc comment. + * + * @var PHP_CodeSniffer_CommentParser_DocElement + */ + protected $previousElement = null; + + /** + * A list of see elements that appear in this doc comment. + * + * @var array(PHP_CodeSniffer_CommentParser_SingleElement) + */ + protected $sees = array(); + + /** + * A list of see elements that appear in this doc comment. + * + * @var array(PHP_CodeSniffer_CommentParser_SingleElement) + */ + protected $deprecated = null; + + /** + * A list of see elements that appear in this doc comment. + * + * @var array(PHP_CodeSniffer_CommentParser_SingleElement) + */ + protected $links = array(); + + /** + * A element to represent \@since tags. + * + * @var PHP_CodeSniffer_CommentParser_SingleElement + */ + protected $since = null; + + /** + * True if the comment has been parsed. + * + * @var boolean + */ + private $_hasParsed = false; + + /** + * The tags that this class can process. + * + * @var array(string) + */ + private static $_tags = array( + 'see' => false, + 'link' => false, + 'deprecated' => true, + 'since' => true, + ); + + /** + * An array of unknown tags. + * + * @var array(string) + */ + public $unknown = array(); + + /** + * The order of tags. + * + * @var array(string) + */ + public $orders = array(); + + + /** + * Constructs a Doc Comment Parser. + * + * @param string $comment The comment to parse. + * @param PHP_CodeSniffer_File $phpcsFile The file that this comment is in. + */ + public function __construct($comment, PHP_CodeSniffer_File $phpcsFile) + { + $this->commentString = $comment; + $this->phpcsFile = $phpcsFile; + + }//end __construct() + + + /** + * Initiates the parsing of the doc comment. + * + * @return void + * @throws PHP_CodeSniffer_CommentParser_ParserException If the parser finds a + * problem with the + * comment. + */ + public function parse() + { + if ($this->_hasParsed === false) { + $this->_parse($this->commentString); + } + + }//end parse() + + + /** + * Parse the comment. + * + * @param string $comment The doc comment to parse. + * + * @return void + * @see _parseWords() + */ + private function _parse($comment) + { + // Firstly, remove the comment tags and any stars from the left side. + $lines = explode($this->phpcsFile->eolChar, $comment); + foreach ($lines as &$line) { + $line = trim($line); + + if ($line !== '') { + if (substr($line, 0, 3) === '/**') { + $line = substr($line, 3); + } else if (substr($line, -2, 2) === '*/') { + $line = substr($line, 0, -2); + } else if ($line{0} === '*') { + $line = substr($line, 1); + } + + // Add the words to the stack, preserving newlines. Other parsers + // might be interested in the spaces between words, so tokenize + // spaces as well as separate tokens. + $flags = (PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $words = preg_split( + '|(\s+)|', + $line.$this->phpcsFile->eolChar, + -1, + $flags + ); + + $this->words = array_merge($this->words, $words); + }//end if + }//end foreach + + $this->_parseWords(); + + }//end _parse() + + + /** + * Parses each word within the doc comment. + * + * @return void + * @see _parse() + * @throws PHP_CodeSniffer_CommentParser_ParserException If more than the allowed + * number of occurences of + * a tag is found. + */ + private function _parseWords() + { + $allowedTags = (self::$_tags + $this->getAllowedTags()); + $allowedTagNames = array_keys($allowedTags); + $prevTagPos = false; + $wordWasEmpty = true; + + foreach ($this->words as $wordPos => $word) { + if (trim($word) !== '') { + $wordWasEmpty = false; + } + + if ($word{0} === '@') { + $tag = substr($word, 1); + + // Filter out @ tags in the comment description. + // A real comment tag should have whitespace and a newline before it. + if (isset($this->words[($wordPos - 1)]) === false + || trim($this->words[($wordPos - 1)]) !== '' + ) { + continue; + } + + if (isset($this->words[($wordPos - 2)]) === false + || $this->words[($wordPos - 2)] !== $this->phpcsFile->eolChar + ) { + continue; + } + + $this->foundTags[] = array( + 'tag' => $tag, + 'line' => $this->getLine($wordPos), + 'pos' => $wordPos, + ); + + if ($prevTagPos !== false) { + // There was a tag before this so let's process it. + $prevTag = substr($this->words[$prevTagPos], 1); + $this->parseTag($prevTag, $prevTagPos, ($wordPos - 1)); + } else { + // There must have been a comment before this tag, so + // let's process that. + $this->parseTag('comment', 0, ($wordPos - 1)); + } + + $prevTagPos = $wordPos; + + if (in_array($tag, $allowedTagNames) === false) { + // This is not a tag that we process, but let's check to + // see if it is a tag we know about. If we don't know about it, + // we add it to a list of unknown tags. + $knownTags = array( + 'abstract', + 'access', + 'example', + 'filesource', + 'global', + 'ignore', + 'internal', + 'name', + 'static', + 'staticvar', + 'todo', + 'tutorial', + 'uses', + 'package_version@', + ); + + if (in_array($tag, $knownTags) === false) { + $this->unknown[] = array( + 'tag' => $tag, + 'line' => $this->getLine($wordPos), + 'pos' => $wordPos, + ); + } + }//end if + }//end if + }//end foreach + + // Only process this tag if there was something to process. + if ($wordWasEmpty === false) { + if ($prevTagPos === false) { + // There must only be a comment in this doc comment. + $this->parseTag('comment', 0, count($this->words)); + } else { + // Process the last tag element. + $prevTag = substr($this->words[$prevTagPos], 1); + $numWords = count($this->words); + $endPos = $numWords; + + if ($prevTag === 'package' || $prevTag === 'subpackage') { + // These are single-word tags, so anything after a newline + // is really a comment. + for ($endPos = $prevTagPos; $endPos < $numWords; $endPos++) { + if (strpos($this->words[$endPos], $this->phpcsFile->eolChar) !== false) { + break; + } + } + } + + $this->parseTag($prevTag, $prevTagPos, $endPos); + + if ($endPos !== $numWords) { + // Process the final comment, if it is not empty. + $tokens = array_slice($this->words, ($endPos + 1), $numWords); + $content = implode('', $tokens); + if (trim($content) !== '') { + $this->parseTag('comment', ($endPos + 1), $numWords); + } + } + }//end if + }//end if + + }//end _parseWords() + + + /** + * Returns the line that the token exists on in the doc comment. + * + * @param int $tokenPos The position in the words stack to find the line + * number for. + * + * @return int + */ + protected function getLine($tokenPos) + { + $newlines = 0; + for ($i = 0; $i < $tokenPos; $i++) { + $newlines += substr_count($this->phpcsFile->eolChar, $this->words[$i]); + } + + return $newlines; + + }//end getLine() + + + /** + * Parses see tag element within the doc comment. + * + * @param array(string) $tokens The word tokens that comprise this element. + * + * @return DocElement The element that represents this see comment. + */ + protected function parseSee($tokens) + { + $see = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'see', + $this->phpcsFile + ); + + $this->sees[] = $see; + return $see; + + }//end parseSee() + + + /** + * Parses the comment element that appears at the top of the doc comment. + * + * @param array(string) $tokens The word tokens that comprise this element. + * + * @return DocElement The element that represents this comment element. + */ + protected function parseComment($tokens) + { + $this->comment = new PHP_CodeSniffer_CommentParser_CommentElement( + $this->previousElement, + $tokens, + $this->phpcsFile + ); + + return $this->comment; + + }//end parseComment() + + + /** + * Parses \@deprecated tags. + * + * @param array(string) $tokens The word tokens that comprise this element. + * + * @return DocElement The element that represents this deprecated tag. + */ + protected function parseDeprecated($tokens) + { + $this->deprecated = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'deprecated', + $this->phpcsFile + ); + + return $this->deprecated; + + }//end parseDeprecated() + + + /** + * Parses \@since tags. + * + * @param array(string) $tokens The word tokens that comprise this element. + * + * @return SingleElement The element that represents this since tag. + */ + protected function parseSince($tokens) + { + $this->since = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'since', + $this->phpcsFile + ); + + return $this->since; + + }//end parseSince() + + + /** + * Parses \@link tags. + * + * @param array(string) $tokens The word tokens that comprise this element. + * + * @return SingleElement The element that represents this link tag. + */ + protected function parseLink($tokens) + { + $link = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'link', + $this->phpcsFile + ); + + $this->links[] = $link; + return $link; + + }//end parseLink() + + + /** + * Returns the see elements that appear in this doc comment. + * + * @return array(SingleElement) + */ + public function getSees() + { + return $this->sees; + + }//end getSees() + + + /** + * Returns the comment element that appears at the top of this doc comment. + * + * @return CommentElement + */ + public function getComment() + { + return $this->comment; + + }//end getComment() + + + /** + * Returns the word list. + * + * @return array + */ + public function getWords() + { + return $this->words; + + }//end getWords() + + + /** + * Returns the list of found tags. + * + * @return array + */ + public function getTags() + { + return $this->foundTags; + + }//end getTags() + + + /** + * Returns the link elements found in this comment. + * + * Returns an empty array if no links are found in the comment. + * + * @return array(SingleElement) + */ + public function getLinks() + { + return $this->links; + + }//end getLinks() + + + /** + * Returns the deprecated element found in this comment. + * + * Returns null if no element exists in the comment. + * + * @return SingleElement + */ + public function getDeprecated() + { + return $this->deprecated; + + }//end getDeprecated() + + + /** + * Returns the since element found in this comment. + * + * Returns null if no element exists in the comment. + * + * @return SingleElement + */ + public function getSince() + { + return $this->since; + + }//end getSince() + + + /** + * Parses the specified tag. + * + * @param string $tag The tag name to parse (omitting the @ symbol from + * the tag) + * @param int $start The position in the word tokens where this element + * started. + * @param int $end The position in the word tokens where this element + * ended. + * + * @return void + * @throws Exception If the process method for the tag cannot be found. + */ + protected function parseTag($tag, $start, $end) + { + $tokens = array_slice($this->words, ($start + 1), ($end - $start)); + + $allowedTags = (self::$_tags + $this->getAllowedTags()); + $allowedTagNames = array_keys($allowedTags); + if ($tag === 'comment' || in_array($tag, $allowedTagNames) === true) { + $method = 'parse'.$tag; + if (method_exists($this, $method) === false) { + $error = 'Method '.$method.' must be implemented to process '.$tag.' tags'; + throw new Exception($error); + } + + $this->previousElement = $this->$method($tokens); + } else { + $this->previousElement = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + $tag, + $this->phpcsFile + ); + } + + $this->orders[] = $tag; + + if ($this->previousElement === null + || ($this->previousElement instanceof PHP_CodeSniffer_CommentParser_DocElement) === false + ) { + throw new Exception('Parse method must return a DocElement'); + } + + }//end parseTag() + + + /** + * Returns a list of tags that this comment parser allows for it's comment. + * + * Each tag should indicate if only one entry of this tag can exist in the + * comment by specifying true as the array value, or false if more than one + * is allowed. Each tag should omit the @ symbol. Only tags other than + * the standard tags should be returned. + * + * @return array(string => boolean) + */ + protected abstract function getAllowedTags(); + + + /** + * Returns the tag orders (index => tagName). + * + * @return array + */ + public function getTagOrders() + { + return $this->orders; + + }//end getTagOrders() + + + /** + * Returns the unknown tags. + * + * @return array + */ + public function getUnknown() + { + return $this->unknown; + + }//end getUnknown() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php b/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php new file mode 100644 index 000000000..9bbef0bf9 --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php @@ -0,0 +1,341 @@ +<?php +/** + * Parses Class doc comments. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_AbstractParser', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_AbstractParser not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses Class doc comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_ClassCommentParser extends PHP_CodeSniffer_CommentParser_AbstractParser +{ + + /** + * The package element of this class. + * + * @var SingleElement + */ + private $_package = null; + + /** + * The subpackage element of this class. + * + * @var SingleElement + */ + private $_subpackage = null; + + /** + * The version element of this class. + * + * @var SingleElement + */ + private $_version = null; + + /** + * The category element of this class. + * + * @var SingleElement + */ + private $_category = null; + + /** + * The copyright elements of this class. + * + * @var array(SingleElement) + */ + private $_copyrights = array(); + + /** + * The licence element of this class. + * + * @var PairElement + */ + private $_license = null; + + /** + * The author elements of this class. + * + * @var array(SingleElement) + */ + private $_authors = array(); + + + /** + * Returns the allowed tags withing a class comment. + * + * @return array(string => int) + */ + protected function getAllowedTags() + { + return array( + 'category' => false, + 'package' => true, + 'subpackage' => true, + 'author' => false, + 'copyright' => true, + 'license' => false, + 'version' => true, + ); + + }//end getAllowedTags() + + + /** + * Parses the license tag of this class comment. + * + * @param array $tokens The tokens that comprise this tag. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + protected function parseLicense($tokens) + { + $this->_license = new PHP_CodeSniffer_CommentParser_PairElement( + $this->previousElement, + $tokens, + 'license', + $this->phpcsFile + ); + + return $this->_license; + + }//end parseLicense() + + + /** + * Parses the copyright tags of this class comment. + * + * @param array $tokens The tokens that comprise this tag. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parseCopyright($tokens) + { + $copyright = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'copyright', + $this->phpcsFile + ); + + $this->_copyrights[] = $copyright; + return $copyright; + + }//end parseCopyright() + + + /** + * Parses the category tag of this class comment. + * + * @param array $tokens The tokens that comprise this tag. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parseCategory($tokens) + { + $this->_category = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'category', + $this->phpcsFile + ); + + return $this->_category; + + }//end parseCategory() + + + /** + * Parses the author tag of this class comment. + * + * @param array $tokens The tokens that comprise this tag. + * + * @return array(PHP_CodeSniffer_CommentParser_SingleElement) + */ + protected function parseAuthor($tokens) + { + $author = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'author', + $this->phpcsFile + ); + + $this->_authors[] = $author; + return $author; + + }//end parseAuthor() + + + /** + * Parses the version tag of this class comment. + * + * @param array $tokens The tokens that comprise this tag. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parseVersion($tokens) + { + $this->_version = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'version', + $this->phpcsFile + ); + + return $this->_version; + + }//end parseVersion() + + + /** + * Parses the package tag found in this test. + * + * @param array $tokens The tokens that comprise this var. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parsePackage($tokens) + { + $this->_package = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'package', + $this->phpcsFile + ); + + return $this->_package; + + }//end parsePackage() + + + /** + * Parses the package tag found in this test. + * + * @param array $tokens The tokens that comprise this var. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parseSubpackage($tokens) + { + $this->_subpackage = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'subpackage', + $this->phpcsFile + ); + + return $this->_subpackage; + + }//end parseSubpackage() + + + /** + * Returns the authors of this class comment. + * + * @return array(PHP_CodeSniffer_CommentParser_SingleElement) + */ + public function getAuthors() + { + return $this->_authors; + + }//end getAuthors() + + + /** + * Returns the version of this class comment. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + public function getVersion() + { + return $this->_version; + + }//end getVersion() + + + /** + * Returns the license of this class comment. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + public function getLicense() + { + return $this->_license; + + }//end getLicense() + + + /** + * Returns the copyrights of this class comment. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + public function getCopyrights() + { + return $this->_copyrights; + + }//end getCopyrights() + + + /** + * Returns the category of this class comment. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + public function getCategory() + { + return $this->_category; + + }//end getCategory() + + + /** + * Returns the package that this class belongs to. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + public function getPackage() + { + return $this->_package; + + }//end getPackage() + + + /** + * Returns the subpackage that this class belongs to. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + public function getSubpackage() + { + return $this->_subpackage; + + }//end getSubpackage() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/CommentElement.php b/codesniffer/CodeSniffer/CommentParser/CommentElement.php new file mode 100644 index 000000000..0a4e5547c --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/CommentElement.php @@ -0,0 +1,245 @@ +<?php +/** + * A class to represent Comments of a doc comment. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to represent Comments of a doc comment. + * + * Comments are in the following format. + * <code> + * /** <--this is the start of the comment. + * * This is a short comment description + * * + * * This is a long comment description + * * <-- this is the end of the comment + * * @return something + * {@/} + * </code> + * + * Note that the sentence before two newlines is assumed + * the short comment description. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_CommentElement extends PHP_CodeSniffer_CommentParser_SingleElement +{ + + + /** + * Constructs a PHP_CodeSniffer_CommentParser_CommentElement. + * + * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element + * that + * appears + * before this + * element. + * @param array $tokens The tokens + * that make + * up this + * element. + * @param PHP_CodeSniffer_File $phpcsFile The file + * that this + * element is + * in. + */ + public function __construct( + $previousElement, + $tokens, + PHP_CodeSniffer_File $phpcsFile + ) { + parent::__construct($previousElement, $tokens, 'comment', $phpcsFile); + + }//end __construct() + + + /** + * Returns the short comment description. + * + * @return string + * @see getLongComment() + */ + public function getShortComment() + { + $pos = $this->_getShortCommentEndPos(); + if ($pos === -1) { + return ''; + } + + return implode('', array_slice($this->tokens, 0, ($pos + 1))); + + }//end getShortComment() + + + /** + * Returns the last token position of the short comment description. + * + * @return int The last token position of the short comment description + * @see _getLongCommentStartPos() + */ + private function _getShortCommentEndPos() + { + $found = false; + $whiteSpace = array( + ' ', + "\t", + ); + + foreach ($this->tokens as $pos => $token) { + $token = str_replace($whiteSpace, '', $token); + if ($token === $this->phpcsFile->eolChar) { + if ($found === false) { + // Include newlines before short description. + continue; + } else { + if (isset($this->tokens[($pos + 1)]) === true) { + if ($this->tokens[($pos + 1)] === $this->phpcsFile->eolChar) { + return ($pos - 1); + } + } else { + return $pos; + } + } + } else { + $found = true; + } + }//end foreach + + return (count($this->tokens) - 1); + + }//end _getShortCommentEndPos() + + + /** + * Returns the long comment description. + * + * @return string + * @see getShortComment + */ + public function getLongComment() + { + $start = $this->_getLongCommentStartPos(); + if ($start === -1) { + return ''; + } + + return implode('', array_slice($this->tokens, $start)); + + }//end getLongComment() + + + /** + * Returns the start position of the long comment description. + * + * Returns -1 if there is no long comment. + * + * @return int The start position of the long comment description. + * @see _getShortCommentEndPos() + */ + private function _getLongCommentStartPos() + { + $pos = ($this->_getShortCommentEndPos() + 1); + if ($pos === (count($this->tokens) - 1)) { + return -1; + } + + $count = count($this->tokens); + for ($i = $pos; $i < $count; $i++) { + $content = trim($this->tokens[$i]); + if ($content !== '') { + if ($content{0} === '@') { + return -1; + } + + return $i; + } + } + + return -1; + + }//end _getLongCommentStartPos() + + + /** + * Returns the whitespace that exists between + * the short and the long comment description. + * + * @return string + */ + public function getWhiteSpaceBetween() + { + $endShort = ($this->_getShortCommentEndPos() + 1); + $startLong = ($this->_getLongCommentStartPos() - 1); + if ($startLong === -1) { + return ''; + } + + return implode( + '', + array_slice($this->tokens, $endShort, ($startLong - $endShort)) + ); + + }//end getWhiteSpaceBetween() + + + /** + * Returns the number of newlines that exist before the tags. + * + * @return int + */ + public function getNewlineAfter() + { + $long = $this->getLongComment(); + if ($long !== '') { + $long = rtrim($long, ' '); + $long = strrev($long); + $newlines = strspn($long, $this->phpcsFile->eolChar); + } else { + $endShort = ($this->_getShortCommentEndPos() + 1); + $after = implode('', array_slice($this->tokens, $endShort)); + $after = trim($after, ' '); + $newlines = strspn($after, $this->phpcsFile->eolChar); + } + + return ($newlines / strlen($this->phpcsFile->eolChar)); + + }//end getNewlineAfter() + + + /** + * Returns true if there is no comment. + * + * @return boolean + */ + public function isEmpty() + { + return (trim($this->getContent()) === ''); + + }//end isEmpty() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/DocElement.php b/codesniffer/CodeSniffer/CommentParser/DocElement.php new file mode 100644 index 000000000..134781413 --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/DocElement.php @@ -0,0 +1,104 @@ +<?php +/** + * A DocElement represents a logical element within a Doc Comment. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * A DocElement represents a logical element within a Doc Comment. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +interface PHP_CodeSniffer_CommentParser_DocElement +{ + + + /** + * Returns the name of the tag this element represents, omitting the @ symbol. + * + * @return string + */ + public function getTag(); + + + /** + * Returns the whitespace that exists before this element. + * + * @return string + * @see getWhitespaceAfter() + */ + public function getWhitespaceBefore(); + + + /** + * Returns the whitespace that exists after this element. + * + * @return string + * @see getWhitespaceBefore() + */ + public function getWhitespaceAfter(); + + + /** + * Returns the order that this element appears in the doc comment. + * + * The first element in the comment should have an order of 1. + * + * @return int + */ + public function getOrder(); + + + /** + * Returns the element that appears before this element. + * + * @return PHP_CodeSniffer_CommentParser_DocElement + * @see getNextElement() + */ + public function getPreviousElement(); + + + /** + * Returns the element that appears after this element. + * + * @return PHP_CodeSniffer_CommentParser_DocElement + * @see getPreviousElement() + */ + public function getNextElement(); + + + /** + * Returns the line that this element started on. + * + * @return int + */ + public function getLine(); + + + /** + * Returns the raw content of this element, omitting the tag. + * + * @return string + */ + public function getRawContent(); + + +}//end interface + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php b/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php new file mode 100644 index 000000000..bebac08fc --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php @@ -0,0 +1,212 @@ +<?php +/** + * Parses function doc comments. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_AbstractParser', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_AbstractParser not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_ParameterElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_ParameterElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_PairElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_PairElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses function doc comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_FunctionCommentParser extends PHP_CodeSniffer_CommentParser_AbstractParser +{ + + /** + * The parameter elements within this function comment. + * + * @var array(PHP_CodeSniffer_CommentParser_ParameterElement) + */ + private $_params = array(); + + /** + * The return element in this function comment. + * + * @var PHP_CodeSniffer_CommentParser_PairElement. + */ + private $_return = null; + + /** + * The throws element list for this function comment. + * + * @var array(PHP_CodeSniffer_CommentParser_PairElement) + */ + private $_throws = array(); + + + /** + * Constructs a PHP_CodeSniffer_CommentParser_FunctionCommentParser. + * + * @param string $comment The comment to parse. + * @param PHP_CodeSniffer_File $phpcsFile The file that this comment is in. + */ + public function __construct($comment, PHP_CodeSniffer_File $phpcsFile) + { + parent::__construct($comment, $phpcsFile); + + }//end __construct() + + + /** + * Parses parameter elements. + * + * @param array(string) $tokens The tokens that comprise this sub element. + * + * @return PHP_CodeSniffer_CommentParser_ParameterElement + */ + protected function parseParam($tokens) + { + $param = new PHP_CodeSniffer_CommentParser_ParameterElement( + $this->previousElement, + $tokens, + $this->phpcsFile + ); + + $this->_params[] = $param; + return $param; + + }//end parseParam() + + + /** + * Parses return elements. + * + * @param array(string) $tokens The tokens that comprise this sub element. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + protected function parseReturn($tokens) + { + $return = new PHP_CodeSniffer_CommentParser_PairElement( + $this->previousElement, + $tokens, + 'return', + $this->phpcsFile + ); + + $this->_return = $return; + return $return; + + }//end parseReturn() + + + /** + * Parses throws elements. + * + * @param array(string) $tokens The tokens that comprise this sub element. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + protected function parseThrows($tokens) + { + $throws = new PHP_CodeSniffer_CommentParser_PairElement( + $this->previousElement, + $tokens, + 'throws', + $this->phpcsFile + ); + + $this->_throws[] = $throws; + return $throws; + + }//end parseThrows() + + + /** + * Returns the parameter elements that this function comment contains. + * + * Returns an empty array if no parameter elements are contained within + * this function comment. + * + * @return array(PHP_CodeSniffer_CommentParser_ParameterElement) + */ + public function getParams() + { + return $this->_params; + + }//end getParams() + + + /** + * Returns the return element in this function comment. + * + * Returns null if no return element exists in the comment. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + public function getReturn() + { + return $this->_return; + + }//end getReturn() + + + /** + * Returns the throws elements in this function comment. + * + * Returns empty array if no throws elements in the comment. + * + * @return array(PHP_CodeSniffer_CommentParser_PairElement) + */ + public function getThrows() + { + return $this->_throws; + + }//end getThrows() + + + /** + * Returns the allowed tags that can exist in a function comment. + * + * @return array(string => boolean) + */ + protected function getAllowedTags() + { + return array( + 'param' => false, + 'return' => true, + 'throws' => false, + ); + + }//end getAllowedTags() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php b/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php new file mode 100644 index 000000000..125896b0c --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php @@ -0,0 +1,91 @@ +<?php +/** + * Parses class member comments. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses class member comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_MemberCommentParser extends PHP_CodeSniffer_CommentParser_ClassCommentParser +{ + + /** + * Represents a \@var tag in a member comment. + * + * @var PHP_CodeSniffer_CommentParser_SingleElement + */ + private $_var = null; + + + /** + * Parses Var tags. + * + * @param array $tokens The tokens that represent this tag. + * + * @return PHP_CodeSniffer_CommentParser_SingleElement + */ + protected function parseVar($tokens) + { + $this->_var = new PHP_CodeSniffer_CommentParser_SingleElement( + $this->previousElement, + $tokens, + 'var', + $this->phpcsFile + ); + + return $this->_var; + + }//end parseVar() + + + /** + * Returns the var tag found in the member comment. + * + * @return PHP_CodeSniffer_CommentParser_PairElement + */ + public function getVar() + { + return $this->_var; + + }//end getVar() + + + /** + * Returns the allowed tags for this parser. + * + * @return array + */ + protected function getAllowedTags() + { + return array('var' => true); + + }//end getAllowedTags() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/PairElement.php b/codesniffer/CodeSniffer/CommentParser/PairElement.php new file mode 100644 index 000000000..39e99769e --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/PairElement.php @@ -0,0 +1,171 @@ +<?php +/** + * A class to represent elements that have a value => comment format. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to represent elements that have a value => comment format. + * + * An example of a pair element tag is the \@throws as it has an exception type + * and a comment on the circumstance of when the exception is thrown. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_PairElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement +{ + + /** + * The value of the tag. + * + * @var string + */ + private $_value = ''; + + /** + * The comment of the tag. + * + * @var string + */ + private $_comment = ''; + + /** + * The whitespace that exists before the value elem. + * + * @var string + */ + private $_valueWhitespace = ''; + + /** + * The whitespace that exists before the comment elem. + * + * @var string + */ + private $_commentWhitespace = ''; + + + /** + * Constructs a PHP_CodeSniffer_CommentParser_PairElement doc tag. + * + * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element + * before this + * one. + * @param array $tokens The tokens + * that comprise + * this element. + * @param string $tag The tag that + * this element + * represents. + * @param PHP_CodeSniffer_File $phpcsFile The file that + * this element + * is in. + */ + public function __construct( + $previousElement, + $tokens, + $tag, + PHP_CodeSniffer_File $phpcsFile + ) { + parent::__construct($previousElement, $tokens, $tag, $phpcsFile); + + }//end __construct() + + + /** + * Returns the element names that this tag is comprised of, in the order + * that they appear in the tag. + * + * @return array(string) + * @see processSubElement() + */ + protected function getSubElements() + { + return array( + 'value', + 'comment', + ); + + }//end getSubElements() + + + /** + * Processes the sub element with the specified name. + * + * @param string $name The name of the sub element to process. + * @param string $content The content of this sub element. + * @param string $whitespaceBefore The whitespace that exists before the + * sub element. + * + * @return void + * @see getSubElements() + */ + protected function processSubElement($name, $content, $whitespaceBefore) + { + $element = '_'.$name; + $whitespace = $element.'Whitespace'; + $this->$element = $content; + $this->$whitespace = $whitespaceBefore; + + }//end processSubElement() + + + /** + * Returns the value of the tag. + * + * @return string + */ + public function getValue() + { + return $this->_value; + + }//end getValue() + + + /** + * Returns the comment associated with the value of this tag. + * + * @return string + */ + public function getComment() + { + return $this->_comment; + + }//end getComment() + + + /** + * Returns the whitespace before the content of this tag. + * + * @return string + */ + public function getWhitespaceBeforeValue() + { + return $this->_valueWhitespace; + + }//end getWhitespaceBeforeValue() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/ParameterElement.php b/codesniffer/CodeSniffer/CommentParser/ParameterElement.php new file mode 100644 index 000000000..d78552eed --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/ParameterElement.php @@ -0,0 +1,338 @@ +<?php +/** + * A class to represent param tags within a function comment. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to represent param tags within a function comment. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_ParameterElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement +{ + + /** + * The variable name of this parameter name, including the $ sign. + * + * @var string + */ + private $_varName = ''; + + /** + * The comment of this parameter tag. + * + * @var string + */ + private $_comment = ''; + + /** + * The variable type of this parameter tag. + * + * @var string + */ + private $_type = ''; + + /** + * The whitespace that exists before the variable name. + * + * @var string + */ + private $_varNameWhitespace = ''; + + /** + * The whitespace that exists before the comment. + * + * @var string + */ + private $_commentWhitespace = null; + + /** + * The whitespace that exists before the variable type. + * + * @var string + */ + private $_typeWhitespace = ''; + + + /** + * Constructs a PHP_CodeSniffer_CommentParser_ParameterElement. + * + * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element + * previous to + * this one. + * @param array $tokens The tokens + * that make up + * this element. + * @param PHP_CodeSniffer_File $phpcsFile The file that + * this element + * is in. + */ + public function __construct( + $previousElement, + $tokens, + PHP_CodeSniffer_File $phpcsFile + ) { + parent::__construct($previousElement, $tokens, 'param', $phpcsFile); + + // Handle special variable type: array(x => y). + $type = strtolower($this->_type); + if ($this->_varName === '=>' && strpos($type, 'array(') !== false) { + $rawContent = $this->getRawContent(); + $matches = array(); + $pattern = '/^(\s+)(array\(.*\))(\s+)(\$\S*)(\s+)(.*)/i'; + if (preg_match($pattern, $rawContent, $matches) !== 0) { + // Process the sub elements correctly for this special case. + if (count($matches) === 7) { + $this->processSubElement('type', $matches[2], $matches[1]); + $this->processSubElement('varName', $matches[4], $matches[3]); + $this->processSubElement('comment', $matches[6], $matches[5]); + } + } + } + + }//end __construct() + + + /** + * Returns the element names that this tag is comprised of, in the order + * that they appear in the tag. + * + * @return array(string) + * @see processSubElement() + */ + protected function getSubElements() + { + return array( + 'type', + 'varName', + 'comment', + ); + + }//end getSubElements() + + + /** + * Processes the sub element with the specified name. + * + * @param string $name The name of the sub element to process. + * @param string $content The content of this sub element. + * @param string $beforeWhitespace The whitespace that exists before the + * sub element. + * + * @return void + * @see getSubElements() + */ + protected function processSubElement($name, $content, $beforeWhitespace) + { + $element = '_'.$name; + $whitespace = $element.'Whitespace'; + $this->$element = $content; + $this->$whitespace = $beforeWhitespace; + + }//end processSubElement() + + + /** + * Returns the variable name that this parameter tag represents. + * + * @return string + */ + public function getVarName() + { + return $this->_varName; + + }//end getVarName() + + + /** + * Returns the variable type that this string represents. + * + * @return string + */ + public function getType() + { + return $this->_type; + + }//end getType() + + + /** + * Returns the comment of this comment for this parameter. + * + * @return string + */ + public function getComment() + { + return $this->_comment; + + }//end getComment() + + + /** + * Returns the whitespace before the variable type. + * + * @return string + * @see getWhiteSpaceBeforeVarName() + * @see getWhiteSpaceBeforeComment() + */ + public function getWhiteSpaceBeforeType() + { + return $this->_typeWhitespace; + + }//end getWhiteSpaceBeforeType() + + + /** + * Returns the whitespace before the variable name. + * + * @return string + * @see getWhiteSpaceBeforeComment() + * @see getWhiteSpaceBeforeType() + */ + public function getWhiteSpaceBeforeVarName() + { + return $this->_varNameWhitespace; + + }//end getWhiteSpaceBeforeVarName() + + + /** + * Returns the whitespace before the comment. + * + * @return string + * @see getWhiteSpaceBeforeVarName() + * @see getWhiteSpaceBeforeType() + */ + public function getWhiteSpaceBeforeComment() + { + return $this->_commentWhitespace; + + }//end getWhiteSpaceBeforeComment() + + + /** + * Returns the position of this parameter are it appears in the comment. + * + * This method differs from getOrder as it is only relative to method + * parameters. + * + * @return int + */ + public function getPosition() + { + if (($this->getPreviousElement() instanceof PHP_CodeSniffer_CommentParser_ParameterElement) === false) { + return 1; + } else { + return ($this->getPreviousElement()->getPosition() + 1); + } + + }//end getPosition() + + + /** + * Returns true if this parameter's variable aligns with the other's. + * + * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param + * to check + * alignment with. + * + * @return boolean + */ + public function alignsVariableWith( + PHP_CodeSniffer_CommentParser_ParameterElement $other + ) { + // Format is: + // @param type $variable Comment. + // @param <-a-><---b----> + // Compares the index before param variable. + $otherVar = (strlen($other->_type) + strlen($other->_varNameWhitespace)); + $thisVar = (strlen($this->_type) + strlen($this->_varNameWhitespace)); + if ($otherVar !== $thisVar) { + return false; + } + + return true; + + }//end alignsVariableWith() + + + /** + * Returns true if this parameter's comment aligns with the other's. + * + * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param + * to check + * alignment with. + * + * @return boolean + */ + public function alignsCommentWith( + PHP_CodeSniffer_CommentParser_ParameterElement $other + ) { + // Compares the index before param comment. + if (strlen($other->_commentWhitespace) === 0 && strlen($this->_commentWhitespace) === 0) { + return true; + } + + $otherComment + = (strlen($other->_varName) + strlen($other->_commentWhitespace)); + $thisComment + = (strlen($this->_varName) + strlen($this->_commentWhitespace)); + + if ($otherComment !== $thisComment) { + return false; + } + + return true; + + }//end alignsCommentWith() + + + /** + * Returns true if this parameter aligns with the other paramter. + * + * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param + * to check + * alignment with. + * + * @return boolean + */ + public function alignsWith(PHP_CodeSniffer_CommentParser_ParameterElement $other) + { + if ($this->alignsVariableWith($other) === false) { + return false; + } + + if ($this->alignsCommentWith($other) === false) { + return false; + } + + return true; + + }//end alignsWith() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/ParserException.php b/codesniffer/CodeSniffer/CommentParser/ParserException.php new file mode 100644 index 000000000..bc192f194 --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/ParserException.php @@ -0,0 +1,71 @@ +<?php +/** + * An exception to be thrown when a DocCommentParser finds an anomaly in a + * doc comment. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * An exception to be thrown when a DocCommentParser finds an anomaly in a + * doc comment. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_ParserException extends Exception +{ + + /** + * The line where the exception occurred, in relation to the doc comment. + * + * @var int + */ + private $_line = 0; + + + /** + * Constructs a DocCommentParserException. + * + * @param string $message The message of the exception. + * @param int $line The position in comment where the error occurred. + * A position of 0 indicates that the error occurred + * at the opening line of the doc comment. + */ + public function __construct($message, $line) + { + parent::__construct($message); + $this->_line = $line; + + }//end __construct() + + + /** + * Returns the line number within the comment where the exception occurred. + * + * @return int + */ + public function getLineWithinComment() + { + return $this->_line; + + }//end getLineWithinComment() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/CommentParser/SingleElement.php b/codesniffer/CodeSniffer/CommentParser/SingleElement.php new file mode 100644 index 000000000..1bf81e0f2 --- /dev/null +++ b/codesniffer/CodeSniffer/CommentParser/SingleElement.php @@ -0,0 +1,171 @@ +<?php +/** + * A class to represent single element doc tags. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to represent single element doc tags. + * + * A single element doc tag contains only one value after the tag itself. An + * example would be the \@package tag. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_CommentParser_SingleElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement +{ + + /** + * The content that exists after the tag. + * + * @var string + * @see getContent() + */ + protected $content = ''; + + /** + * The whitespace that exists before the content. + * + * @var string + * @see getWhitespaceBeforeContent() + */ + protected $contentWhitespace = ''; + + + /** + * Constructs a SingleElement doc tag. + * + * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element + * before this + * one. + * @param array $tokens The tokens + * that comprise + * this element. + * @param string $tag The tag that + * this element + * represents. + * @param PHP_CodeSniffer_File $phpcsFile The file that + * this element + * is in. + */ + public function __construct( + $previousElement, + $tokens, + $tag, + PHP_CodeSniffer_File $phpcsFile + ) { + parent::__construct($previousElement, $tokens, $tag, $phpcsFile); + + }//end __construct() + + + /** + * Returns the element names that this tag is comprised of, in the order + * that they appear in the tag. + * + * @return array(string) + * @see processSubElement() + */ + protected function getSubElements() + { + return array('content'); + + }//end getSubElements() + + + /** + * Processes the sub element with the specified name. + * + * @param string $name The name of the sub element to process. + * @param string $content The content of this sub element. + * @param string $whitespaceBefore The whitespace that exists before the + * sub element. + * + * @return void + * @see getSubElements() + */ + protected function processSubElement($name, $content, $whitespaceBefore) + { + $this->content = $content; + $this->contentWhitespace = $whitespaceBefore; + + }//end processSubElement() + + + /** + * Returns the content of this tag. + * + * @return string + */ + public function getContent() + { + return $this->content; + + }//end getContent() + + + /** + * Returns the whitespace before the content of this tag. + * + * @return string + */ + public function getWhitespaceBeforeContent() + { + return $this->contentWhitespace; + + }//end getWhitespaceBeforeContent() + + + /** + * Processes a content check for single doc element. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $commentStart The line number where + * the error occurs. + * @param string $docBlock Whether this is a file or + * class comment doc. + * + * @return void + */ + public function process( + PHP_CodeSniffer_File $phpcsFile, + $commentStart, + $docBlock + ) { + if ($this->content === '') { + $errorPos = ($commentStart + $this->getLine()); + $error = 'Content missing for %s tag in %s comment'; + $data = array( + $this->tag, + $docBlock, + ); + $phpcsFile->addError($error, $errorPos, 'EmptyTagContent', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/DocGenerators/Generator.php b/codesniffer/CodeSniffer/DocGenerators/Generator.php new file mode 100644 index 000000000..8cb38c605 --- /dev/null +++ b/codesniffer/CodeSniffer/DocGenerators/Generator.php @@ -0,0 +1,186 @@ +<?php +/** + * The base class for all PHP_CodeSniffer documentation generators. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * The base class for all PHP_CodeSniffer documentation generators. + * + * Documentation generators are used to print documentation about code sniffs + * in a standard. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_DocGenerators_Generator +{ + + /** + * The name of the coding standard we are generating docs for. + * + * @var string + */ + private $_standard = ''; + + /** + * An array of sniffs that we are limiting the generated docs to. + * + * If this array is empty, docs are generated for all sniffs in the + * supplied coding standard. + * + * @var string + */ + private $_sniffs = array(); + + + /** + * Constructs a PHP_CodeSniffer_DocGenerators_Generator object. + * + * @param string $standard The name of the coding standard to generate + * docs for. + * @param array $sniffs An array of sniffs that we are limiting the + * generated docs to. + * + * @see generate() + */ + public function __construct($standard, array $sniffs=array()) + { + $this->_standard = $standard; + $this->_sniffs = $sniffs; + + }//end __construct() + + + /** + * Retrieves the title of the sniff from the DOMNode supplied. + * + * @param DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @return string + */ + protected function getTitle(DOMNode $doc) + { + return $doc->getAttribute('title'); + + }//end getTitle() + + + /** + * Retrieves the name of the standard we are generating docs for. + * + * @return string + */ + protected function getStandard() + { + return $this->_standard; + + }//end getStandard() + + + /** + * Generates the documentation for a standard. + * + * It's probably wise for doc generators to override this method so they + * have control over how the docs are produced. Otherwise, the processSniff + * method should be overridden to output content for each sniff. + * + * @return void + * @see processSniff() + */ + public function generate() + { + $standardFiles = $this->getStandardFiles(); + + foreach ($standardFiles as $standard) { + $doc = new DOMDocument(); + $doc->load($standard); + $documentation = $doc->getElementsByTagName('documentation')->item(0); + $this->processSniff($documentation); + } + + }//end generate() + + + /** + * Returns a list of paths to XML standard files for all sniffs in a standard. + * + * Any sniffs that do not have an XML standard file are obviously not included + * in the returned array. If documentation is only being generated for some + * sniffs (ie. $this->_sniffs is not empty) then all others sniffs will + * be filtered from the results as well. + * + * @return array(string) + */ + protected function getStandardFiles() + { + $phpcs = new PHP_CodeSniffer(); + $sniffs = $phpcs->processRuleset($this->_standard); + + $standardFiles = array(); + foreach ($sniffs as $sniff) { + if (empty($this->_sniffs) === false) { + // We are limiting the docs to certain sniffs only, so filter + // out any unwanted sniffs. + $sniffName = substr($sniff, (strrpos($sniff, '/') + 1)); + $sniffName = substr($sniffName, 0, -9); + if (in_array($sniffName, $this->_sniffs) === false) { + continue; + } + } + + $standardFile = str_replace( + DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR, + $sniff + ); + $standardFile = str_replace('Sniff.php', 'Standard.xml', $standardFile); + + if (is_file($standardFile) === true) { + $standardFiles[] = $standardFile; + } + }//end foreach + + return $standardFiles; + + }//end getStandardFiles() + + + /** + * Process the documentation for a single sniff. + * + * Doc generators should override this function to produce output. + * + * @param DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @return void + * @see generate() + */ + protected function processSniff(DOMNode $doc) + { + + }//end processSniff() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/DocGenerators/HTML.php b/codesniffer/CodeSniffer/DocGenerators/HTML.php new file mode 100644 index 000000000..f379d9414 --- /dev/null +++ b/codesniffer/CodeSniffer/DocGenerators/HTML.php @@ -0,0 +1,294 @@ +<?php +/** + * A doc generator that outputs documentation in one big HTML file. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found'); +} + +/** + * A doc generator that outputs documentation in one big HTML file. + * + * Output is in one large HTML file and is designed for you to style with + * your own stylesheet. It contains a table of contents at the top with anchors + * to each sniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood <gsherwood@squiz.net> + * @author Marc McIntyre <mmcintyre@squiz.net> + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_DocGenerators_HTML extends PHP_CodeSniffer_DocGenerators_Generator +{ + + + /** + * Generates the documentation for a standard. + * + * @return void + * @see processSniff() + */ + public function generate() + { + ob_start(); + $this->printHeader(); + + $standardFiles = $this->getStandardFiles(); + $this->printToc($standardFiles); + + foreach ($standardFiles as $standard) { + $doc = new DOMDocument(); + $doc->load($standard); + $documentation = $doc->getElementsByTagName('documentation')->item(0); + $this->processSniff($documentation); + } + + $this->printFooter(); + + $content = ob_get_contents(); + ob_end_clean(); + + echo $content; + + }//end generate() + + + /** + * Print the header of the HTML page. + * + * @return void + */ + protected function printHeader() + { + $standard = $this->getStandard(); + echo '<html>'.PHP_EOL; + echo ' <head>'.PHP_EOL; + echo " <title>$standard Coding Standards".PHP_EOL; + echo ' '.PHP_EOL; + echo ' '.PHP_EOL; + echo ' '.PHP_EOL; + echo "

$standard Coding Standards

".PHP_EOL; + + }//end printHeader() + + + /** + * Print the table of contents for the standard. + * + * The TOC is just an unordered list of bookmarks to sniffs on the page. + * + * @param array $standardFiles An array of paths to the XML standard files. + * + * @return void + */ + protected function printToc($standardFiles) + { + echo '

Table of Contents

'.PHP_EOL; + echo '
    '.PHP_EOL; + + foreach ($standardFiles as $standard) { + $doc = new DOMDocument(); + $doc->load($standard); + $documentation = $doc->getElementsByTagName('documentation')->item(0); + $title = $this->getTitle($documentation); + echo '
  • $title
  • ".PHP_EOL; + } + + echo '
'.PHP_EOL; + + }//end printToc() + + + /** + * Print the footer of the HTML page. + * + * @return void + */ + protected function printFooter() + { + // Turn off strict errors so we don't get timezone warnings if people + // don't have their timezone set. + error_reporting(E_ALL); + echo '
'; + echo 'Documentation generated on '.date('r'); + echo ' by PHP_CodeSniffer @package_version@'; + echo '
'.PHP_EOL; + error_reporting(E_ALL | E_STRICT); + + echo ' '.PHP_EOL; + echo ''.PHP_EOL; + + }//end printFooter() + + + /** + * Process the documentation for a single sniff. + * + * @param DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @return void + */ + public function processSniff(DOMNode $doc) + { + $title = $this->getTitle($doc); + echo ' '.PHP_EOL; + echo "

$title

".PHP_EOL; + + foreach ($doc->childNodes as $node) { + if ($node->nodeName === 'standard') { + $this->printTextBlock($node); + } else if ($node->nodeName === 'code_comparison') { + $this->printCodeComparisonBlock($node); + } + } + + }//end processSniff() + + + /** + * Print a text block found in a standard. + * + * @param DOMNode $node The DOMNode object for the text block. + * + * @return void + */ + protected function printTextBlock($node) + { + $content = trim($node->nodeValue); + $content = htmlspecialchars($content); + + // Allow em tags only. + $content = str_replace('<em>', '', $content); + $content = str_replace('</em>', '', $content); + + echo "

$content

".PHP_EOL; + + }//end printTextBlock() + + + /** + * Print a code comparison block found in a standard. + * + * @param DOMNode $node The DOMNode object for the code comparison block. + * + * @return void + */ + protected function printCodeComparisonBlock($node) + { + $codeBlocks = $node->getElementsByTagName('code'); + + $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + $first = trim($codeBlocks->item(0)->nodeValue); + $first = str_replace('', $first); + $first = str_replace(' ', ' ', $first); + $first = str_replace('', '', $first); + $first = str_replace('', '', $first); + + $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + $second = trim($codeBlocks->item(1)->nodeValue); + $second = str_replace('', $second); + $second = str_replace(' ', ' ', $second); + $second = str_replace('', '', $second); + $second = str_replace('', '', $second); + + echo ' '.PHP_EOL; + echo ' '.PHP_EOL; + echo " ".PHP_EOL; + echo " ".PHP_EOL; + echo ' '.PHP_EOL; + echo ' '.PHP_EOL; + echo " ".PHP_EOL; + echo " ".PHP_EOL; + echo ' '.PHP_EOL; + echo '
$firstTitle$secondTitle
$first$second
'.PHP_EOL; + + }//end printCodeComparisonBlock() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/DocGenerators/Text.php b/codesniffer/CodeSniffer/DocGenerators/Text.php new file mode 100644 index 000000000..1134f0c49 --- /dev/null +++ b/codesniffer/CodeSniffer/DocGenerators/Text.php @@ -0,0 +1,267 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found'); +} + +/** + * A doc generator that outputs text-based documentation. + * + * Output is designed to be displayed in a terminal and is wrapped to 100 characters. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_DocGenerators_Text extends PHP_CodeSniffer_DocGenerators_Generator +{ + + + /** + * Process the documentation for a single sniff. + * + * @param DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @return void + */ + public function processSniff(DOMNode $doc) + { + $this->printTitle($doc); + + foreach ($doc->childNodes as $node) { + if ($node->nodeName === 'standard') { + $this->printTextBlock($node); + } else if ($node->nodeName === 'code_comparison') { + $this->printCodeComparisonBlock($node); + } + } + + }//end processSniff() + + + /** + * Prints the title area for a single sniff. + * + * @param DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @return void + */ + protected function printTitle(DOMNode $doc) + { + $title = $this->getTitle($doc); + $standard = $this->getStandard(); + + echo PHP_EOL; + echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); + echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL); + echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); + echo PHP_EOL.PHP_EOL; + + }//end printTitle() + + + /** + * Print a text block found in a standard. + * + * @param DOMNode $node The DOMNode object for the text block. + * + * @return void + */ + protected function printTextBlock($node) + { + $text = trim($node->nodeValue); + $text = str_replace('', '*', $text); + $text = str_replace('', '*', $text); + + $lines = array(); + $tempLine = ''; + $words = explode(' ', $text); + + foreach ($words as $word) { + if (strlen($tempLine.$word) >= 99) { + if (strlen($tempLine.$word) === 99) { + // Adding the extra space will push us to the edge + // so we are done. + $lines[] = $tempLine.$word; + $tempLine = ''; + } else if (strlen($tempLine.$word) === 100) { + // We are already at the edge, so we are done. + $lines[] = $tempLine.$word; + $tempLine = ''; + } else { + $lines[] = rtrim($tempLine); + $tempLine = $word.' '; + } + } else { + $tempLine .= $word.' '; + } + }//end foreach + + if ($tempLine !== '') { + $lines[] = rtrim($tempLine); + } + + echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL; + + }//end printTextBlock() + + + /** + * Print a code comparison block found in a standard. + * + * @param DOMNode $node The DOMNode object for the code comparison block. + * + * @return void + */ + protected function printCodeComparisonBlock($node) + { + $codeBlocks = $node->getElementsByTagName('code'); + $first = trim($codeBlocks->item(0)->nodeValue); + $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + + $firstTitleLines = array(); + $tempTitle = ''; + $words = explode(' ', $firstTitle); + + foreach ($words as $word) { + if (strlen($tempTitle.$word) >= 45) { + if (strlen($tempTitle.$word) === 45) { + // Adding the extra space will push us to the edge + // so we are done. + $firstTitleLines[] = $tempTitle.$word; + $tempTitle = ''; + } else if (strlen($tempTitle.$word) === 46) { + // We are already at the edge, so we are done. + $firstTitleLines[] = $tempTitle.$word; + $tempTitle = ''; + } else { + $firstTitleLines[] = $tempTitle; + $tempTitle = $word; + } + } else { + $tempTitle .= $word.' '; + } + }//end foreach + + if ($tempTitle !== '') { + $firstTitleLines[] = $tempTitle; + } + + $first = str_replace('', '', $first); + $first = str_replace('', '', $first); + $firstLines = explode("\n", $first); + + $second = trim($codeBlocks->item(1)->nodeValue); + $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + + $secondTitleLines = array(); + $tempTitle = ''; + $words = explode(' ', $secondTitle); + + foreach ($words as $word) { + if (strlen($tempTitle.$word) >= 45) { + if (strlen($tempTitle.$word) === 45) { + // Adding the extra space will push us to the edge + // so we are done. + $secondTitleLines[] = $tempTitle.$word; + $tempTitle = ''; + } else if (strlen($tempTitle.$word) === 46) { + // We are already at the edge, so we are done. + $secondTitleLines[] = $tempTitle.$word; + $tempTitle = ''; + } else { + $secondTitleLines[] = $tempTitle; + $tempTitle = $word; + } + } else { + $tempTitle .= $word.' '; + } + }//end foreach + + if ($tempTitle !== '') { + $secondTitleLines[] = $tempTitle; + } + + $second = str_replace('', '', $second); + $second = str_replace('', '', $second); + $secondLines = explode("\n", $second); + + $maxCodeLines = max(count($firstLines), count($secondLines)); + $maxTitleLines = max(count($firstTitleLines), count($secondTitleLines)); + + echo str_repeat('-', 41); + echo ' CODE COMPARISON '; + echo str_repeat('-', 42).PHP_EOL; + + for ($i = 0; $i < $maxTitleLines; $i++) { + if (isset($firstTitleLines[$i]) === true) { + $firstLineText = $firstTitleLines[$i]; + } else { + $firstLineText = ''; + } + + if (isset($secondTitleLines[$i]) === true) { + $secondLineText = $secondTitleLines[$i]; + } else { + $secondLineText = ''; + } + + echo '| '; + echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText))); + echo ' | '; + echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText))); + echo ' |'.PHP_EOL; + }//end for + + echo str_repeat('-', 100).PHP_EOL; + + for ($i = 0; $i < $maxCodeLines; $i++) { + if (isset($firstLines[$i]) === true) { + $firstLineText = $firstLines[$i]; + } else { + $firstLineText = ''; + } + + if (isset($secondLines[$i]) === true) { + $secondLineText = $secondLines[$i]; + } else { + $secondLineText = ''; + } + + echo '| '; + echo $firstLineText.str_repeat(' ', (47 - strlen($firstLineText))); + echo '| '; + echo $secondLineText.str_repeat(' ', (48 - strlen($secondLineText))); + echo '|'.PHP_EOL; + }//end for + + echo str_repeat('-', 100).PHP_EOL.PHP_EOL; + + }//end printCodeComparisonBlock() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Exception.php b/codesniffer/CodeSniffer/Exception.php new file mode 100644 index 000000000..4b03f3e56 --- /dev/null +++ b/codesniffer/CodeSniffer/Exception.php @@ -0,0 +1,33 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Exception extends Exception +{ + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/File.php b/codesniffer/CodeSniffer/File.php new file mode 100644 index 000000000..f45e307df --- /dev/null +++ b/codesniffer/CodeSniffer/File.php @@ -0,0 +1,2910 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * A PHP_CodeSniffer_File object represents a PHP source file and the tokens + * associated with it. + * + * It provides a means for traversing the token stack, along with + * other token related operations. If a PHP_CodeSniffer_Sniff finds and error or + * warning within a PHP_CodeSniffer_File, you can raise an error using the + * addError() or addWarning() methods. + * + * Token Information + * + * Each token within the stack contains information about itself: + * + * + * array( + * 'code' => 301, // the token type code (see token_get_all()) + * 'content' => 'if', // the token content + * 'type' => 'T_IF', // the token name + * 'line' => 56, // the line number when the token is located + * 'column' => 12, // the column in the line where this token + * // starts (starts from 1) + * 'level' => 2 // the depth a token is within the scopes open + * 'conditions' => array( // a list of scope condition token + * // positions => codes that + * 2 => 50, // openened the scopes that this token exists + * 9 => 353, // in (see conditional tokens section below) + * ), + * ); + * + * + * Conditional Tokens + * + * In addition to the standard token fields, conditions contain information to + * determine where their scope begins and ends: + * + * + * array( + * 'scope_condition' => 38, // the token position of the condition + * 'scope_opener' => 41, // the token position that started the scope + * 'scope_closer' => 70, // the token position that ended the scope + * ); + * + * + * The condition, the scope opener and the scope closer each contain this + * information. + * + * Parenthesis Tokens + * + * Each parenthesis token (T_OPEN_PARENTHESIS and T_CLOSE_PARENTHESIS) has a + * reference to their opening and closing parenthesis, one being itself, the + * other being its opposite. + * + * + * array( + * 'parenthesis_opener' => 34, + * 'parenthesis_closer' => 40, + * ); + * + * + * Some tokens can "own" a set of parenthesis. For example a T_FUNCTION token + * has parenthesis around its argument list. These tokens also have the + * parenthesis_opener and and parenthesis_closer indices. Not all parenthesis + * have owners, for example parenthesis used for arithmetic operations and + * function calls. The parenthesis tokens that have an owner have the following + * auxiliary array indices. + * + * + * array( + * 'parenthesis_opener' => 34, + * 'parenthesis_closer' => 40, + * 'parenthesis_owner' => 33, + * ); + * + * + * Each token within a set of parenthesis also has an array indice + * 'nested_parenthesis' which is an array of the + * left parenthesis => right parenthesis token positions. + * + * + * 'nested_parenthesis' => array( + * 12 => 15 + * 11 => 14 + * ); + * + * + * Extended Tokens + * + * PHP_CodeSniffer extends and augments some of the tokens created by + * token_get_all(). A full list of these tokens can be seen in the + * Tokens.php file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_File +{ + + /** + * The absolute path to the file associated with this object. + * + * @var string + */ + private $_file = ''; + + /** + * The EOL character this file uses. + * + * @var string + */ + public $eolChar = ''; + + /** + * The PHP_CodeSniffer object controlling this run. + * + * @var PHP_CodeSniffer + */ + public $phpcs = null; + + /** + * The tokenizer being used for this file. + * + * @var object + */ + public $tokenizer = null; + + /** + * The tokenizer being used for this file. + * + * @var string + */ + public $tokenizerType = 'PHP'; + + /** + * The number of tokens in this file. + * + * Stored here to save calling count() everywhere. + * + * @var int + */ + public $numTokens = 0; + + /** + * The tokens stack map. + * + * Note that the tokens in this array differ in format to the tokens + * produced by token_get_all(). Tokens are initially produced with + * token_get_all(), then augmented so that it's easier to process them. + * + * @var array() + * @see Tokens.php + */ + private $_tokens = array(); + + /** + * The errors raised from PHP_CodeSniffer_Sniffs. + * + * @var array() + * @see getErrors() + */ + private $_errors = array(); + + /** + * The warnings raised form PHP_CodeSniffer_Sniffs. + * + * @var array() + * @see getWarnings() + */ + private $_warnings = array(); + + /** + * Record the errors and warnings raised. + * + * @var bool + */ + private $_recordErrors = true; + + /** + * And array of lines being ignored by PHP_CodeSniffer. + * + * @var array() + */ + private $_ignoredLines = array(); + + /** + * The total number of errors raised. + * + * @var int + */ + private $_errorCount = 0; + + /** + * The total number of warnings raised. + * + * @var int + */ + private $_warningCount = 0; + + /** + * An array of sniffs listening to this file's processing. + * + * @var array(PHP_CodeSniffer_Sniff) + */ + private $_listeners = array(); + + /** + * The class name of the sniff currently processing the file. + * + * @var string + */ + private $_activeListener = ''; + + /** + * An array of sniffs being processed and how long they took. + * + * @var array() + */ + private $_listenerTimes = array(); + + /** + * An array of extensions mapping to the tokenizer to use. + * + * This value gets set by PHP_CodeSniffer when the object is created. + * + * @var array + */ + protected $tokenizers = array(); + + /** + * An array of rules from the ruleset.xml file. + * + * This value gets set by PHP_CodeSniffer when the object is created. + * It may be empty, indicating that the ruleset does not override + * any of the default sniff settings. + * + * @var array + */ + protected $ruleset = array(); + + /** + * An array of sniff codes to restrict violations to. + * + * This value gets set by PHP_CodeSniffer when the object is created. + * It may be empty, indicating that no fitering should take place. + * + * @var array + */ + protected $restrictions = array(); + + + /** + * Constructs a PHP_CodeSniffer_File. + * + * @param string $file The absolute path to the file to process. + * @param array(string) $listeners The initial listeners listening + * to processing of this file. + * @param array $tokenizers An array of extensions mapping + * to the tokenizer to use. + * @param array $ruleset An array of rules from the + * ruleset.xml file. + * @param array $restrictions An array of sniff codes to + * restrict violations to. + * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object controlling + * this run. + * + * @throws PHP_CodeSniffer_Exception If the register() method does + * not return an array. + */ + public function __construct( + $file, + array $listeners, + array $tokenizers, + array $ruleset, + array $restrictions, + PHP_CodeSniffer $phpcs + ) { + $this->_file = trim($file); + $this->_listeners = $listeners; + $this->tokenizers = $tokenizers; + $this->ruleset = $ruleset; + $this->restrictions = $restrictions; + $this->phpcs = $phpcs; + + $cliValues = $phpcs->cli->getCommandLineValues(); + if (isset($cliValues['showSources']) === true + && $cliValues['showSources'] !== true + && array_key_exists('summary', $cliValues['reports']) === true + && count($cliValues['reports']) === 1 + ) { + $this->_recordErrors = false; + } + + }//end __construct() + + + /** + * Sets the name of the currently active sniff. + * + * @param string $activeListener The class name of the current sniff. + * + * @return void + */ + public function setActiveListener($activeListener) + { + $this->_activeListener = $activeListener; + + }//end setActiveListener() + + + /** + * Adds a listener to the token stack that listens to the specific tokens. + * + * When PHP_CodeSniffer encounters on the the tokens specified in $tokens, + * it invokes the process method of the sniff. + * + * @param PHP_CodeSniffer_Sniff $listener The listener to add to the + * listener stack. + * @param array(int) $tokens The token types the listener wishes to + * listen to. + * + * @return void + */ + public function addTokenListener(PHP_CodeSniffer_Sniff $listener, array $tokens) + { + foreach ($tokens as $token) { + if (isset($this->_listeners[$token]) === false) { + $this->_listeners[$token] = array(); + } + + if (in_array($listener, $this->_listeners[$token], true) === false) { + $this->_listeners[$token][] = $listener; + } + } + + }//end addTokenListener() + + + /** + * Removes a listener from listening from the specified tokens. + * + * @param PHP_CodeSniffer_Sniff $listener The listener to remove from the + * listener stack. + * @param array(int) $tokens The token types the listener wishes to + * stop listen to. + * + * @return void + */ + public function removeTokenListener( + PHP_CodeSniffer_Sniff $listener, + array $tokens + ) { + foreach ($tokens as $token) { + if (isset($this->_listeners[$token]) === false) { + continue; + } + + if (in_array($listener, $this->_listeners[$token]) === true) { + foreach ($this->_listeners[$token] as $pos => $value) { + if ($value === $listener) { + unset($this->_listeners[$token][$pos]); + } + } + } + } + + }//end removeTokenListener() + + + /** + * Returns the token stack for this file. + * + * @return array() + */ + public function getTokens() + { + return $this->_tokens; + + }//end getTokens() + + + /** + * Starts the stack traversal and tells listeners when tokens are found. + * + * @param string $contents The contents to parse. If NULL, the content + * is taken from the file system. + * + * @return void + */ + public function start($contents=null) + { + $this->_parse($contents); + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + echo "\t*** START TOKEN PROCESSING ***".PHP_EOL; + } + + $foundCode = false; + $ignoring = false; + + // Foreach of the listeners that have registered to listen for this + // token, get them to process it. + foreach ($this->_tokens as $stackPtr => $token) { + // Check for ignored lines. + if ($token['code'] === T_COMMENT || $token['code'] === T_DOC_COMMENT) { + if (strpos($token['content'], '@codingStandardsIgnoreStart') !== false) { + $ignoring = true; + } else if (strpos($token['content'], '@codingStandardsIgnoreEnd') !== false) { + $ignoring = false; + // Ignore this comment too. + $this->_ignoredLines[$token['line']] = true; + } else if (strpos($token['content'], '@codingStandardsIgnoreFile') !== false) { + // Ignoring the whole file, just a little late. + $this->_errors = array(); + $this->_warnings = array(); + $this->_errorCount = 0; + $this->_warningCount = 0; + return; + } else if (strpos($token['content'], '@codingStandardsChangeSetting') !== false) { + $start = strpos($token['content'], '@codingStandardsChangeSetting'); + $comment = substr($token['content'], $start + 30); + $parts = explode(' ', $comment); + $sniffParts = explode('.', $parts[0]); + $listenerClass = $sniffParts[0].'_Sniffs_'.$sniffParts[1].'_'.$sniffParts[2].'Sniff'; + $this->phpcs->setSniffProperty($listenerClass, $parts[1], $parts[2]); + } + } + + if ($ignoring === true) { + $this->_ignoredLines[$token['line']] = true; + continue; + } + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + $type = $token['type']; + $content = str_replace($this->eolChar, '\n', $token['content']); + echo "\t\tProcess token $stackPtr: $type => $content".PHP_EOL; + } + + $tokenType = $token['code']; + if ($tokenType !== T_INLINE_HTML) { + $foundCode = true; + } + + if (isset($this->_listeners[$tokenType]) === false) { + continue; + } + + foreach ($this->_listeners[$tokenType] as $listenerData) { + // Make sure this sniff supports the tokenizer + // we are currently using. + $listener = $listenerData['listener']; + $class = $listenerData['class']; + + if (in_array($this->tokenizerType, $listenerData['tokenizers']) === false) { + continue; + } + + // If the file path matches one of our ignore patterns, skip it. + $parts = explode('_', str_replace('\\', '_', $class)); + if (isset($parts[3]) === true) { + $source = $parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5); + $patterns = $this->phpcs->getIgnorePatterns($source); + foreach ($patterns as $pattern => $type) { + // While there is support for a type of each pattern + // (absolute or relative) we don't actually support it here. + $replacements = array( + '\\,' => ',', + '*' => '.*', + ); + + $pattern = strtr($pattern, $replacements); + if (preg_match("|{$pattern}|i", $this->_file) === 1) { + continue(2); + } + } + } + + $this->setActiveListener($class); + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + $startTime = microtime(true); + echo "\t\t\tProcessing ".$this->_activeListener.'... '; + } + + $listener->process($this, $stackPtr); + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + $timeTaken = (microtime(true) - $startTime); + if (isset($this->_listenerTimes[$this->_activeListener]) === false) { + $this->_listenerTimes[$this->_activeListener] = 0; + } + + $this->_listenerTimes[$this->_activeListener] += $timeTaken; + + $timeTaken = round(($timeTaken), 4); + echo "DONE in $timeTaken seconds".PHP_EOL; + } + + $this->_activeListener = ''; + }//end foreach + }//end foreach + + // Remove errors and warnings for ignored lines. + foreach ($this->_ignoredLines as $line => $ignore) { + if (isset($this->_errors[$line]) === true) { + if ($this->_recordErrors === false) { + $this->_errorCount -= $this->_errors[$line]; + } else { + foreach ($this->_errors[$line] as $col => $errors) { + $this->_errorCount -= count($errors); + } + } + + unset($this->_errors[$line]); + } + + if (isset($this->_warnings[$line]) === true) { + if ($this->_recordErrors === false) { + $this->_errorCount -= $this->_warnings[$line]; + } else { + foreach ($this->_warnings[$line] as $col => $warnings) { + $this->_warningCount -= count($warnings); + } + } + + unset($this->_warnings[$line]); + } + }//end foreach + + if ($this->_recordErrors === false) { + $this->_errors = array(); + $this->_warnings = array(); + } + + // If short open tags are off but the file being checked uses + // short open tags, the whole content will be inline HTML + // and nothing will be checked. So try and handle this case. + if ($foundCode === false) { + $shortTags = (bool) ini_get('short_open_tag'); + if ($shortTags === false) { + $error = 'No PHP code was found in this file and short open tags are not allowed by this install of PHP. This file may be using short open tags but PHP does not allow them.'; + $this->addWarning($error, null, 'Internal.NoCodeFound'); + } + } + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + echo "\t*** END TOKEN PROCESSING ***".PHP_EOL; + } + + if (PHP_CODESNIFFER_VERBOSITY > 2) { + echo "\t*** START SNIFF PROCESSING REPORT ***".PHP_EOL; + + asort($this->_listenerTimes, SORT_NUMERIC); + $this->_listenerTimes = array_reverse($this->_listenerTimes, true); + foreach ($this->_listenerTimes as $listener => $timeTaken) { + echo "\t$listener: ".round(($timeTaken), 4).' secs'.PHP_EOL; + } + + echo "\t*** END SNIFF PROCESSING REPORT ***".PHP_EOL; + } + + }//end start() + + + /** + * Remove vars stored in this sniff that are no longer required. + * + * @return void + */ + public function cleanUp() + { + $this->_tokens = null; + $this->_listeners = null; + + }//end cleanUp() + + + /** + * Tokenizes the file and prepares it for the test run. + * + * @param string $contents The contents to parse. If NULL, the content + * is taken from the file system. + * + * @return void + */ + private function _parse($contents=null) + { + try { + $this->eolChar = self::detectLineEndings($this->_file, $contents); + } catch (PHP_CodeSniffer_Exception $e) { + $this->addWarning($e->getMessage(), null, 'Internal.DetectLineEndings'); + return; + } + + // Determine the tokenizer from the file extension. + $fileParts = explode('.', $this->_file); + $extension = array_pop($fileParts); + if (isset($this->tokenizers[$extension]) === true) { + $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->tokenizers[$extension]; + $this->tokenizerType = $this->tokenizers[$extension]; + } else { + // Revert to default. + $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->tokenizerType; + } + + $tokenizer = new $tokenizerClass(); + $this->tokenizer = $tokenizer; + + if ($contents === null) { + $contents = file_get_contents($this->_file); + } + + $this->_tokens = self::tokenizeString($contents, $tokenizer, $this->eolChar); + $this->numTokens = count($this->_tokens); + + // Check for mixed line endings as these can cause tokenizer errors and we + // should let the user know that the results they get may be incorrect. + // This is done by removing all backslashes, removing the newline char we + // detected, then converting newlines chars into text. If any backslashes + // are left at the end, we have additional newline chars in use. + $contents = str_replace('\\', '', $contents); + $contents = str_replace($this->eolChar, '', $contents); + $contents = str_replace("\n", '\n', $contents); + $contents = str_replace("\r", '\r', $contents); + if (strpos($contents, '\\') !== false) { + $error = 'File has mixed line endings; this may cause incorrect results'; + $this->addWarning($error, 0, 'Internal.LineEndings.Mixed'); + } + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + if ($this->numTokens === 0) { + $numLines = 0; + } else { + $numLines = $this->_tokens[($this->numTokens - 1)]['line']; + } + + echo "[$this->numTokens tokens in $numLines lines]... "; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo PHP_EOL; + } + } + + }//end _parse() + + + /** + * Opens a file and detects the EOL character being used. + * + * @param string $file The full path to the file. + * @param string $contents The contents to parse. If NULL, the content + * is taken from the file system. + * + * @return string + * @throws PHP_CodeSniffer_Exception If $file could not be opened. + */ + public static function detectLineEndings($file, $contents=null) + { + if ($contents === null) { + // Determine the newline character being used in this file. + // Will be either \r, \r\n or \n. + if (is_readable($file) === false) { + $error = 'Error opening file; file no longer exists or you do not have access to read the file'; + throw new PHP_CodeSniffer_Exception($error); + } else { + $handle = fopen($file, 'r'); + if ($handle === false) { + $error = 'Error opening file; could not auto-detect line endings'; + throw new PHP_CodeSniffer_Exception($error); + } + } + + $firstLine = fgets($handle); + fclose($handle); + + $eolChar = substr($firstLine, -1); + if ($eolChar === "\n") { + $secondLastChar = substr($firstLine, -2, 1); + if ($secondLastChar === "\r") { + $eolChar = "\r\n"; + } + } else if ($eolChar !== "\r") { + // Must not be an EOL char at the end of the line. + // Probably a one-line file, so assume \n as it really + // doesn't matter considering there are no newlines. + $eolChar = "\n"; + } + } else { + if (preg_match("/\r\n?|\n/", $contents, $matches) !== 1) { + // Assuming there are no newlines. + $eolChar = "\n"; + } else { + $eolChar = $matches[0]; + } + }//end if + + return $eolChar; + + }//end detectLineEndings() + + + /** + * Adds an error to the error stack. + * + * @param string $error The error message. + * @param int $stackPtr The stack position where the error occurred. + * @param string $code A violation code unique to the sniff message. + * @param array $data Replacements for the error message. + * @param int $severity The severity level for this error. A value of 0 + * will be converted into the default severity level. + * + * @return void + */ + public function addError($error, $stackPtr, $code='', $data=array(), $severity=0) + { + // Don't bother doing any processing if errors are just going to + // be hidden in the reports anyway. + if ($this->phpcs->cli->errorSeverity === 0) { + return; + } + + // Work out which sniff generated the error. + if (substr($code, 0, 9) === 'Internal.') { + // Any internal message. + $sniff = $code; + $sniffCode = $code; + } else { + $parts = explode('_', str_replace('\\', '_', $this->_activeListener)); + if (isset($parts[3]) === true) { + $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3]; + + // Remove "Sniff" from the end. + $sniff = substr($sniff, 0, -5); + } else { + $sniff = 'unknownSniff'; + } + + $sniffCode = $sniff; + if ($code !== '') { + $sniffCode .= '.'.$code; + } + }//end if + + // Make sure this message type is allowed based on the --sniffs + // command line argument values. + if (empty($this->restrictions) === false + && in_array($sniffCode, $this->restrictions) === false + && in_array($sniff, $this->restrictions) === false + ) { + return; + } + + // Make sure this message type has not been set to "warning". + if (isset($this->ruleset[$sniffCode]['type']) === true + && $this->ruleset[$sniffCode]['type'] === 'warning' + ) { + // Pass this off to the warning handler. + $this->addWarning($error, $stackPtr, $code, $data, $severity); + return; + } + + // Make sure we are interested in this severity level. + if (isset($this->ruleset[$sniffCode]['severity']) === true) { + $severity = $this->ruleset[$sniffCode]['severity']; + } else if ($severity === 0) { + $severity = PHPCS_DEFAULT_ERROR_SEV; + } + + if ($this->phpcs->cli->errorSeverity > $severity) { + return; + } + + // Make sure we are not ignoring this file. + $patterns = $this->phpcs->getIgnorePatterns($sniffCode); + foreach ($patterns as $pattern => $type) { + // While there is support for a type of each pattern + // (absolute or relative) we don't actually support it here. + $replacements = array( + '\\,' => ',', + '*' => '.*', + ); + + $pattern = strtr($pattern, $replacements); + if (preg_match("|{$pattern}|i", $this->_file) === 1) { + return; + } + } + + if ($stackPtr === null) { + $lineNum = 1; + $column = 1; + } else { + $lineNum = $this->_tokens[$stackPtr]['line']; + $column = $this->_tokens[$stackPtr]['column']; + } + + $this->_errorCount++; + if ($this->_recordErrors === false) { + if (isset($this->_errors[$lineNum]) === false) { + $this->_errors[$lineNum] = 0; + } + $this->_errors[$lineNum]++; + return; + } + + // Work out the warning message. + if (isset($this->ruleset[$sniffCode]['message']) === true) { + $error = $this->ruleset[$sniffCode]['message']; + } + + if (empty($data) === true) { + $message = $error; + } else { + $message = vsprintf($error, $data); + } + + if (isset($this->_errors[$lineNum]) === false) { + $this->_errors[$lineNum] = array(); + } + + if (isset($this->_errors[$lineNum][$column]) === false) { + $this->_errors[$lineNum][$column] = array(); + } + + $this->_errors[$lineNum][$column][] = array( + 'message' => $message, + 'source' => $sniffCode, + 'severity' => $severity, + ); + + }//end addError() + + + /** + * Adds an warning to the warning stack. + * + * @param string $warning The error message. + * @param int $stackPtr The stack position where the error occurred. + * @param string $code A violation code unique to the sniff message. + * @param array $data Replacements for the warning message. + * @param int $severity The severity level for this warning. A value of 0 + * will be converted into the default severity level. + * + * @return void + */ + public function addWarning($warning, $stackPtr, $code='', $data=array(), $severity=0) + { + // Don't bother doing any processing if warnings are just going to + // be hidden in the reports anyway. + if ($this->phpcs->cli->warningSeverity === 0) { + return; + } + + // Work out which sniff generated the warning. + if (substr($code, 0, 9) === 'Internal.') { + // Any internal message. + $sniff = $code; + $sniffCode = $code; + } else { + $parts = explode('_', str_replace('\\', '_', $this->_activeListener)); + if (isset($parts[3]) === true) { + $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3]; + + // Remove "Sniff" from the end. + $sniff = substr($sniff, 0, -5); + } else { + $sniff = 'unknownSniff'; + } + + $sniffCode = $sniff; + if ($code !== '') { + $sniffCode .= '.'.$code; + } + }//end if + + // Make sure this message type is allowed based on the --sniffs + // command line argument values. + if (empty($this->restrictions) === false + && in_array($sniffCode, $this->restrictions) === false + && in_array($sniff, $this->restrictions) === false + ) { + return; + } + + // Make sure this message type has not been set to "error". + if (isset($this->ruleset[$sniffCode]['type']) === true + && $this->ruleset[$sniffCode]['type'] === 'error' + ) { + // Pass this off to the error handler. + $this->addError($warning, $stackPtr, $code, $data, $severity); + return; + } + + // Make sure we are interested in this severity level. + if (isset($this->ruleset[$sniffCode]['severity']) === true) { + $severity = $this->ruleset[$sniffCode]['severity']; + } else if ($severity === 0) { + $severity = PHPCS_DEFAULT_WARN_SEV; + } + + if ($this->phpcs->cli->warningSeverity > $severity) { + return; + } + + // Make sure we are not ignoring this file. + $patterns = $this->phpcs->getIgnorePatterns($sniffCode); + foreach ($patterns as $pattern => $type) { + // While there is support for a type of each pattern + // (absolute or relative) we don't actually support it here. + $replacements = array( + '\\,' => ',', + '*' => '.*', + ); + + $pattern = strtr($pattern, $replacements); + if (preg_match("|{$pattern}|i", $this->_file) === 1) { + return; + } + } + + if ($stackPtr === null) { + $lineNum = 1; + $column = 1; + } else { + $lineNum = $this->_tokens[$stackPtr]['line']; + $column = $this->_tokens[$stackPtr]['column']; + } + + $this->_warningCount++; + if ($this->_recordErrors === false) { + if (isset($this->_warnings[$lineNum]) === false) { + $this->_warnings[$lineNum] = 0; + } + $this->_warnings[$lineNum]++; + return; + } + + // Work out the warning message. + if (isset($this->ruleset[$sniffCode]['message']) === true) { + $warning = $this->ruleset[$sniffCode]['message']; + } + + if (empty($data) === true) { + $message = $warning; + } else { + $message = vsprintf($warning, $data); + } + + if (isset($this->_warnings[$lineNum]) === false) { + $this->_warnings[$lineNum] = array(); + } + + if (isset($this->_warnings[$lineNum][$column]) === false) { + $this->_warnings[$lineNum][$column] = array(); + } + + $this->_warnings[$lineNum][$column][] = array( + 'message' => $message, + 'source' => $sniffCode, + 'severity' => $severity, + ); + + }//end addWarning() + + + /** + * Returns the number of errors raised. + * + * @return int + */ + public function getErrorCount() + { + return $this->_errorCount; + + }//end getErrorCount() + + + /** + * Returns the number of warnings raised. + * + * @return int + */ + public function getWarningCount() + { + return $this->_warningCount; + + }//end getWarningCount() + + + /** + * Returns the list of ignored lines. + * + * @return array + */ + public function getIgnoredLines() + { + return $this->_ignoredLines; + + }//end getIgnoredLines() + + + /** + * Returns the errors raised from processing this file. + * + * @return array + */ + public function getErrors() + { + return $this->_errors; + + }//end getErrors() + + + /** + * Returns the warnings raised from processing this file. + * + * @return array + */ + public function getWarnings() + { + return $this->_warnings; + + }//end getWarnings() + + + /** + * Returns the absolute filename of this file. + * + * @return string + */ + public function getFilename() + { + return $this->_file; + + }//end getFilename() + + + /** + * Creates an array of tokens when given some PHP code. + * + * Starts by using token_get_all() but does a lot of extra processing + * to insert information about the context of the token. + * + * @param string $string The string to tokenize. + * @param object $tokenizer A tokenizer class to use to tokenize the string. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return array + */ + public static function tokenizeString($string, $tokenizer, $eolChar='\n') + { + $tokens = $tokenizer->tokenizeString($string, $eolChar); + + self::_createLineMap($tokens, $tokenizer, $eolChar); + self::_createBracketMap($tokens, $tokenizer, $eolChar); + self::_createParenthesisMap($tokens, $tokenizer, $eolChar); + self::_createParenthesisNestingMap($tokens, $tokenizer, $eolChar); + self::_createScopeMap($tokens, $tokenizer, $eolChar); + + // If we know the width of each tab, convert tabs + // into spaces so sniffs can use one method of checking. + if (PHP_CODESNIFFER_TAB_WIDTH > 0) { + self::_convertTabs($tokens, $tokenizer, $eolChar); + } + + // Column map requires the line map to be complete. + self::_createColumnMap($tokens, $tokenizer, $eolChar); + self::_createLevelMap($tokens, $tokenizer, $eolChar); + + // Allow the tokenizer to do additional processing if required. + $tokenizer->processAdditional($tokens, $eolChar); + + return $tokens; + + }//end tokenizeString() + + + /** + * Creates a map of tokens => line numbers for each token. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createLineMap(&$tokens, $tokenizer, $eolChar) + { + $lineNumber = 1; + $count = count($tokens); + + for ($i = 0; $i < $count; $i++) { + $tokens[$i]['line'] = $lineNumber; + if ($tokens[$i]['content'] === '') { + continue; + } + + $lineNumber += substr_count($tokens[$i]['content'], $eolChar); + } + + }//end _createLineMap() + + + /** + * Converts tabs into spaces. + * + * Each tab can represent between 1 and $width spaces, so + * this cannot be a straight string replace. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _convertTabs(&$tokens, $tokenizer, $eolChar) + { + $currColumn = 1; + $count = count($tokens); + + for ($i = 0; $i < $count; $i++) { + $tokenContent = $tokens[$i]['content']; + + if (strpos($tokenContent, "\t") === false) { + // There are no tabs in this content. + $currColumn += strlen($tokenContent); + } else { + // We need to determine the length of each tab. + $tabs = preg_split( + "|(\t)|", + $tokenContent, + -1, + PREG_SPLIT_DELIM_CAPTURE + ); + + $tabNum = 0; + $tabsToSpaces = array(); + $newContent = ''; + + foreach ($tabs as $content) { + if ($content === '') { + continue; + } + + if (strpos($content, "\t") === false) { + // This piece of content is not a tab. + $currColumn += strlen($content); + $newContent .= $content; + } else { + $lastCurrColumn = $currColumn; + $tabNum++; + + // Move the pointer to the next tab stop. + if (($currColumn % PHP_CODESNIFFER_TAB_WIDTH) === 0) { + // This is the first tab, and we are already at a + // tab stop, so this tab counts as a single space. + $currColumn++; + } else { + $currColumn++; + while (($currColumn % PHP_CODESNIFFER_TAB_WIDTH) != 0) { + $currColumn++; + } + + $currColumn++; + } + + $length = ($currColumn - $lastCurrColumn); + $newContent .= str_repeat(' ', $length); + }//end if + }//end foreach + + $tokens[$i]['content'] = $newContent; + }//end if + + if (isset($tokens[($i + 1)]['line']) === true + && $tokens[($i + 1)]['line'] !== $tokens[$i]['line'] + ) { + $currColumn = 1; + } + }//end for + + }//end _convertTabs() + + + /** + * Creates a column map. + * + * The column map indicates where the token started on the line where it + * exists. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createColumnMap(&$tokens, $tokenizer, $eolChar) + { + $currColumn = 1; + $count = count($tokens); + + for ($i = 0; $i < $count; $i++) { + $tokens[$i]['column'] = $currColumn; + if (isset($tokens[($i + 1)]['line']) === true + && $tokens[($i + 1)]['line'] !== $tokens[$i]['line'] + ) { + $currColumn = 1; + } else { + $currColumn += strlen($tokens[$i]['content']); + } + } + + }//end _createColumnMap() + + + /** + * Creates a map for opening and closing of square brackets. + * + * Each bracket token (T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET) + * has a reference to their opening and closing bracket + * (bracket_opener and bracket_closer). + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createBracketMap(&$tokens, $tokenizer, $eolChar) + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START BRACKET MAP ***".PHP_EOL; + } + + $squareOpeners = array(); + $curlyOpeners = array(); + $numTokens = count($tokens); + + for ($i = 0; $i < $numTokens; $i++) { + switch ($tokens[$i]['code']) { + case T_OPEN_SQUARE_BRACKET: + $squareOpeners[] = $i; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($squareOpeners)); + echo str_repeat("\t", count($curlyOpeners)); + echo "=> Found square bracket opener at $i".PHP_EOL; + } + + break; + case T_OPEN_CURLY_BRACKET: + if (isset($tokens[$i]['scope_closer']) === false) { + $curlyOpeners[] = $i; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($squareOpeners)); + echo str_repeat("\t", count($curlyOpeners)); + echo "=> Found curly bracket opener at $i".PHP_EOL; + } + } + break; + case T_CLOSE_SQUARE_BRACKET: + if (empty($squareOpeners) === false) { + $opener = array_pop($squareOpeners); + $tokens[$i]['bracket_opener'] = $opener; + $tokens[$i]['bracket_closer'] = $i; + $tokens[$opener]['bracket_opener'] = $opener; + $tokens[$opener]['bracket_closer'] = $i; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($squareOpeners)); + echo str_repeat("\t", count($curlyOpeners)); + echo "\t=> Found square bracket closer at $i for $opener".PHP_EOL; + } + } + break; + case T_CLOSE_CURLY_BRACKET: + if (empty($curlyOpeners) === false + && isset($tokens[$i]['scope_opener']) === false + ) { + $opener = array_pop($curlyOpeners); + $tokens[$i]['bracket_opener'] = $opener; + $tokens[$i]['bracket_closer'] = $i; + $tokens[$opener]['bracket_opener'] = $opener; + $tokens[$opener]['bracket_closer'] = $i; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($squareOpeners)); + echo str_repeat("\t", count($curlyOpeners)); + echo "\t=> Found curly bracket closer at $i for $opener".PHP_EOL; + } + } + break; + default: + continue; + }//end switch + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END BRACKET MAP ***".PHP_EOL; + } + + }//end _createBracketMap() + + + /** + * Creates a map for opening and closing of parenthesis. + * + * Each parenthesis token (T_OPEN_PARENTHESIS and T_CLOSE_PARENTHESIS) has a + * reference to their opening and closing parenthesis (parenthesis_opener + * and parenthesis_closer). + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createParenthesisMap(&$tokens, $tokenizer, $eolChar) + { + $openers = array(); + $numTokens = count($tokens); + $openOwner = null; + + for ($i = 0; $i < $numTokens; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$parenthesisOpeners) === true) { + $tokens[$i]['parenthesis_opener'] = null; + $tokens[$i]['parenthesis_closer'] = null; + $tokens[$i]['parenthesis_owner'] = $i; + $openOwner = $i; + } else if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + $openers[] = $i; + $tokens[$i]['parenthesis_opener'] = $i; + if ($openOwner !== null) { + $tokens[$openOwner]['parenthesis_opener'] = $i; + $tokens[$i]['parenthesis_owner'] = $openOwner; + $openOwner = null; + } + } else if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { + // Did we set an owner for this set of parenthesis? + $numOpeners = count($openers); + if ($numOpeners !== 0) { + $opener = array_pop($openers); + if (isset($tokens[$opener]['parenthesis_owner']) === true) { + $owner = $tokens[$opener]['parenthesis_owner']; + + $tokens[$owner]['parenthesis_closer'] = $i; + $tokens[$i]['parenthesis_owner'] = $owner; + } + + $tokens[$i]['parenthesis_opener'] = $opener; + $tokens[$i]['parenthesis_closer'] = $i; + $tokens[$opener]['parenthesis_closer'] = $i; + } + }//end if + }//end for + + }//end _createParenthesisMap() + + + /** + * Creates a map for the parenthesis tokens that surround other tokens. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createParenthesisNestingMap( + &$tokens, + $tokenizer, + $eolChar + ) { + $numTokens = count($tokens); + $map = array(); + for ($i = 0; $i < $numTokens; $i++) { + if (isset($tokens[$i]['parenthesis_opener']) === true + && $i === $tokens[$i]['parenthesis_opener'] + ) { + if (empty($map) === false) { + $tokens[$i]['nested_parenthesis'] = $map; + } + + if (isset($tokens[$i]['parenthesis_closer']) === true) { + $map[$tokens[$i]['parenthesis_opener']] + = $tokens[$i]['parenthesis_closer']; + } + } else if (isset($tokens[$i]['parenthesis_closer']) === true + && $i === $tokens[$i]['parenthesis_closer'] + ) { + array_pop($map); + if (empty($map) === false) { + $tokens[$i]['nested_parenthesis'] = $map; + } + } else { + if (empty($map) === false) { + $tokens[$i]['nested_parenthesis'] = $map; + } + }//end if + }//end for + + }//end _createParenthesisNestingMap() + + + /** + * Creates a scope map of tokens that open scopes. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + * @see _recurseScopeMap() + */ + private static function _createScopeMap(&$tokens, $tokenizer, $eolChar) + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START SCOPE MAP ***".PHP_EOL; + } + + $numTokens = count($tokens); + for ($i = 0; $i < $numTokens; $i++) { + // Check to see if the current token starts a new scope. + if (isset($tokenizer->scopeOpeners[$tokens[$i]['code']]) === true) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$i]['type']; + $content = str_replace($eolChar, '\n', $tokens[$i]['content']); + echo "\tStart scope map at $i: $type => $content".PHP_EOL; + } + + $i = self::_recurseScopeMap( + $tokens, + $numTokens, + $tokenizer, + $eolChar, + $i + ); + } + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END SCOPE MAP ***".PHP_EOL; + } + + }//end _createScopeMap() + + + /** + * Recurses though the scope openers to build a scope map. + * + * @param array &$tokens The array of tokens to process. + * @param int $numTokens The size of the tokens array. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * @param int $stackPtr The position in the stack of the token that + * opened the scope (eg. an IF token or FOR token). + * @param int $depth How many scope levels down we are. + * @param int &$ignore How many curly braces we are ignoring. + * + * @return int The position in the stack that closed the scope. + */ + private static function _recurseScopeMap( + &$tokens, + $numTokens, + $tokenizer, + $eolChar, + $stackPtr, + $depth=1, + &$ignore=0 + ) { + $opener = null; + $currType = $tokens[$stackPtr]['code']; + $startLine = $tokens[$stackPtr]['line']; + + // We will need this to restore the value if we end up + // returning a token ID that causes our calling function to go back + // over already ignored braces. + $originalIgnore = $ignore; + + // If the start token for this scope opener is the same as + // the scope token, we have already found our opener. + if (in_array($currType, $tokenizer->scopeOpeners[$currType]['start']) === true) { + $opener = $stackPtr; + } + + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + $tokenType = $tokens[$i]['code']; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$i]['type']; + $content = str_replace($eolChar, '\n', $tokens[$i]['content']); + echo str_repeat("\t", $depth); + echo "Process token $i ["; + if ($opener !== null) { + echo "opener:$opener;"; + } + + if ($ignore > 0) { + echo "ignore=$ignore;"; + } + + echo "]: $type => $content".PHP_EOL; + } + + // Very special case for IF statements in PHP that can be defined without + // scope tokens. If an IF statement below this one has an opener but no + // keyword, the opener will be incorrectly assigned to this IF statement. + // E.g., if (1) 1; 1 ? (1 ? 1 : 1) : 1; + if (($currType === T_IF || $currType === T_ELSE) && $opener === null && $tokens[$i]['code'] === T_SEMICOLON) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Found semicolon before scope opener for $stackPtr ($type), bailing".PHP_EOL; + } + + return $i; + } + + // Is this an opening condition ? + if (isset($tokenizer->scopeOpeners[$tokenType]) === true) { + if ($opener === null) { + // Found another opening condition but still haven't + // found our opener, so we are never going to find one. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Couldn't find scope opener for $stackPtr ($type), bailing".PHP_EOL; + } + + return $stackPtr; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* token is an opening condition *'.PHP_EOL; + } + + $isShared + = ($tokenizer->scopeOpeners[$tokenType]['shared'] === true); + + if (isset($tokens[$i]['scope_condition']) === true) { + // We've been here before. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* already processed, skipping *'.PHP_EOL; + } + + if ($isShared === false + && isset($tokens[$i]['scope_closer']) === true + ) { + $i = $tokens[$i]['scope_closer']; + } + + continue; + } else if ($currType === $tokenType + && $isShared === false + && $opener === null + ) { + // We haven't yet found our opener, but we have found another + // scope opener which is the same type as us, and we don't + // share openers, so we will never find one. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* it was another token\'s opener, bailing *'.PHP_EOL; + } + + return $stackPtr; + } else { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* searching for opener *'.PHP_EOL; + } + + if (in_array(T_CLOSE_CURLY_BRACKET, $tokenizer->scopeOpeners[$tokenType]['end']) === true) { + $oldIgnore = $ignore; + $ignore = 0; + } + + $i = self::_recurseScopeMap( + $tokens, + $numTokens, + $tokenizer, + $eolChar, + $i, + ($depth + 1), + $ignore + ); + + if (in_array(T_CLOSE_CURLY_BRACKET, $tokenizer->scopeOpeners[$tokenType]['end']) === true) { + $ignore = $oldIgnore; + } + }//end if + }//end if + + if (in_array($tokenType, $tokenizer->scopeOpeners[$currType]['start']) === true + && $opener === null + ) { + if ($tokenType === T_OPEN_CURLY_BRACKET) { + // Make sure this is actually an opener and not a + // string offset (e.g., $var{0}). + for ($x = ($i - 1); $x > 0; $x--) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } else { + // If the first non-whitespace/comment token is a + // variable or object operator then this is an opener + // for a string offset and not a scope. + if ($tokens[$x]['code'] === T_VARIABLE + || $tokens[$x]['code'] === T_OBJECT_OPERATOR + ) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* ignoring curly brace *'.PHP_EOL; + } + + $ignore++; + }//end if + + break; + }//end if + }//end for + }//end if + + if ($ignore === 0) { + // We found the opening scope token for $currType. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Found scope opener for $stackPtr ($type)".PHP_EOL; + } + + $opener = $i; + } + } else if (in_array($tokenType, $tokenizer->scopeOpeners[$currType]['end']) === true + && $opener !== null + ) { + if ($ignore > 0 && $tokenType === T_CLOSE_CURLY_BRACKET) { + // The last opening bracket must have been for a string + // offset or alike, so let's ignore it. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* finished ignoring curly brace *'.PHP_EOL; + } + + $ignore--; + } else { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Found scope closer for $stackPtr ($type)".PHP_EOL; + } + + foreach (array($stackPtr, $opener, $i) as $token) { + $tokens[$token]['scope_condition'] = $stackPtr; + $tokens[$token]['scope_opener'] = $opener; + $tokens[$token]['scope_closer'] = $i; + } + + if ($tokenizer->scopeOpeners[$tokens[$stackPtr]['code']]['shared'] === true) { + // As we are going back to where we started originally, restore + // the ignore value back to its original value. + $ignore = $originalIgnore; + return $opener; + } else { + return $i; + } + }//end if + } else if ($tokenType === T_OPEN_PARENTHESIS) { + if (isset($tokens[$i]['parenthesis_owner']) === true) { + $owner = $tokens[$i]['parenthesis_owner']; + if (in_array($tokens[$owner]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true + && isset($tokens[$i]['parenthesis_closer']) === true + ) { + // If we get into here, then we opened a parenthesis for + // a scope (eg. an if or else if). We can just skip to + // the closing parenthesis. + $i = $tokens[$i]['parenthesis_closer']; + + // Update the start of the line so that when we check to see + // if the closing parenthesis is more than 3 lines away from + // the statement, we check from the closing parenthesis. + $startLine + = $tokens[$tokens[$i]['parenthesis_closer']]['line']; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* skipping parenthesis *'.PHP_EOL; + } + } + }//end if + } else if ($tokenType === T_OPEN_CURLY_BRACKET && $opener !== null) { + // We opened something that we don't have a scope opener for. + // Examples of this are curly brackets for string offsets etc. + // We want to ignore this so that we don't have an invalid scope + // map. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* ignoring curly brace *'.PHP_EOL; + } + + $ignore++; + } else if ($opener === null + && isset($tokenizer->scopeOpeners[$currType]) === true + ) { + // If we still haven't found the opener after 3 lines, + // we're not going to find it, unless we know it requires + // an opener (in which case we better keep looking) or the last + // token was empty (in which case we'll just confirm there is + // more code in this file and not just a big comment). + if ($tokens[$i]['line'] >= ($startLine + 3) + && in_array($tokens[($i - 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false + ) { + if ($tokenizer->scopeOpeners[$currType]['strict'] === true) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + $lines = ($tokens[$i]['line'] - $startLine); + echo str_repeat("\t", $depth); + echo "=> Still looking for $stackPtr ($type) scope opener after $lines lines".PHP_EOL; + } + } else { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Couldn't find scope opener for $stackPtr ($type), bailing".PHP_EOL; + } + + return $stackPtr; + } + } + } else if ($opener !== null + && $tokenType !== T_BREAK + && in_array($tokenType, $tokenizer->endScopeTokens) === true + ) { + if (isset($tokens[$i]['scope_condition']) === false) { + if ($ignore > 0) { + // We found the end token for the opener we were ignoring. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo '* finished ignoring curly brace *'.PHP_EOL; + } + + $ignore--; + } else { + // We found a token that closes the scope but it doesn't + // have a condition, so it belongs to another token and + // our token doesn't have a closer, so pretend this is + // the closer. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", $depth); + echo "=> Found (unexpected) scope closer for $stackPtr ($type)".PHP_EOL; + } + + foreach (array($stackPtr, $opener) as $token) { + $tokens[$token]['scope_condition'] = $stackPtr; + $tokens[$token]['scope_opener'] = $opener; + $tokens[$token]['scope_closer'] = $i; + } + + return ($i - 1); + }//end if + }//end if + }//end if + }//end for + + return $stackPtr; + + }//end _recurseScopeMap() + + + /** + * Constructs the level map. + * + * The level map adds a 'level' indice to each token which indicates the + * depth that a token within a set of scope blocks. It also adds a + * 'condition' indice which is an array of the scope conditions that opened + * each of the scopes - position 0 being the first scope opener. + * + * @param array &$tokens The array of tokens to process. + * @param object $tokenizer The tokenizer being used to process this file. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + private static function _createLevelMap(&$tokens, $tokenizer, $eolChar) + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START LEVEL MAP ***".PHP_EOL; + } + + $numTokens = count($tokens); + $level = 0; + $conditions = array(); + $lastOpener = null; + $openers = array(); + + for ($i = 0; $i < $numTokens; $i++) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$i]['type']; + $line = $tokens[$i]['line']; + $content = str_replace($eolChar, '\n', $tokens[$i]['content']); + echo str_repeat("\t", ($level + 1)); + echo "Process token $i on line $line [lvl:$level;"; + if (empty($conditions) !== true) { + $condString = 'conds;'; + foreach ($conditions as $condition) { + $condString .= token_name($condition).','; + } + + echo rtrim($condString, ',').';'; + } + + echo "]: $type => $content".PHP_EOL; + } + + $tokens[$i]['level'] = $level; + $tokens[$i]['conditions'] = $conditions; + + if (isset($tokens[$i]['scope_condition']) === true) { + // Check to see if this token opened the scope. + if ($tokens[$i]['scope_opener'] === $i) { + $stackPtr = $tokens[$i]['scope_condition']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", ($level + 1)); + echo "=> Found scope opener for $stackPtr ($type)".PHP_EOL; + } + + $stackPtr = $tokens[$i]['scope_condition']; + + // If we find a scope opener that has a shared closer, + // then we need to go back over the condition map that we + // just created and fix ourselves as we just added some + // conditions where there was none. This happens for T_CASE + // statements that are using the same break statement. + if ($lastOpener !== null && $tokens[$lastOpener]['scope_closer'] === $tokens[$i]['scope_closer']) { + // This opener shares its closer with the previous opener, + // but we still need to check if the two openers share their + // closer with each other directly (like CASE and DEFAULT) + // or if they are just sharing because one doesn't have a + // closer (like CASE with no BREAK using a SWITCHes closer). + $thisType = $tokens[$tokens[$i]['scope_condition']]['code']; + $opener = $tokens[$lastOpener]['scope_condition']; + + $isShared = in_array( + $tokens[$opener]['code'], + $tokenizer->scopeOpeners[$thisType]['with'] + ); + + $sameEnd = ($tokenizer->scopeOpeners[$thisType]['end'][0] === $tokenizer->scopeOpeners[$tokens[$opener]['code']]['end'][0]); + if ($isShared === true && $sameEnd === true) { + $badToken = $opener; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$badToken]['type']; + echo str_repeat("\t", ($level + 1)); + echo "* shared closer, cleaning up $badToken ($type) *".PHP_EOL; + } + + for ($x = $tokens[$i]['scope_condition']; $x <= $i; $x++) { + $oldConditions = $tokens[$x]['conditions']; + $oldLevel = $tokens[$x]['level']; + $tokens[$x]['level']--; + unset($tokens[$x]['conditions'][$badToken]); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$x]['type']; + $oldConds = ''; + foreach ($oldConditions as $condition) { + $oldConds .= token_name($condition).','; + } + + $oldConds = rtrim($oldConds, ','); + + $newConds = ''; + foreach ($tokens[$x]['conditions'] as $condition) { + $newConds .= token_name($condition).','; + } + + $newConds = rtrim($newConds, ','); + + $newLevel = $tokens[$x]['level']; + echo str_repeat("\t", ($level + 1)); + echo "* cleaned $x ($type) *".PHP_EOL; + echo str_repeat("\t", ($level + 2)); + echo "=> level changed from $oldLevel to $newLevel".PHP_EOL; + echo str_repeat("\t", ($level + 2)); + echo "=> conditions changed from $oldConds to $newConds".PHP_EOL; + }//end if + }//end for + + unset($conditions[$badToken]); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$badToken]['type']; + echo str_repeat("\t", ($level + 1)); + echo "* token $badToken ($type) removed from conditions array *".PHP_EOL; + } + + unset ($openers[$lastOpener]); + + $level--; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", ($level + 2)); + echo '* level decreased *'.PHP_EOL; + } + }//end if + }//end if + + $level++; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", ($level + 1)); + echo '* level increased *'.PHP_EOL; + } + + $conditions[$stackPtr] = $tokens[$stackPtr]['code']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$stackPtr]['type']; + echo str_repeat("\t", ($level + 1)); + echo "* token $stackPtr ($type) added to conditions array *".PHP_EOL; + } + + $lastOpener = $tokens[$i]['scope_opener']; + if ($lastOpener !== null) { + $openers[$lastOpener] = $lastOpener; + } + } else if ($tokens[$i]['scope_closer'] === $i) { + foreach (array_reverse($openers) as $opener) { + if ($tokens[$opener]['scope_closer'] === $i) { + $oldOpener = array_pop($openers); + if (empty($openers) === false) { + $lastOpener = array_pop($openers); + $openers[$lastOpener] = $lastOpener; + } else { + $lastOpener = null; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$oldOpener]['type']; + echo str_repeat("\t", ($level + 1)); + echo "=> Found scope closer for $oldOpener ($type)".PHP_EOL; + } + + $oldCondition = array_pop($conditions); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", ($level + 1)); + echo '* token '.token_name($oldCondition).' removed from conditions array *'.PHP_EOL; + } + + // Make sure this closer actually belongs to us. + // Either the condition also has to think this is the + // closer, or it has to allow sharing with us. + $condition + = $tokens[$tokens[$i]['scope_condition']]['code']; + if ($condition !== $oldCondition) { + if (in_array($condition, $tokenizer->scopeOpeners[$oldCondition]['with']) === false) { + $badToken = $tokens[$oldOpener]['scope_condition']; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = token_name($oldCondition); + echo str_repeat("\t", ($level + 1)); + echo "* scope closer was bad, cleaning up $badToken ($type) *".PHP_EOL; + } + + for ($x = ($oldOpener + 1); $x <= $i; $x++) { + $oldConditions = $tokens[$x]['conditions']; + $oldLevel = $tokens[$x]['level']; + $tokens[$x]['level']--; + unset($tokens[$x]['conditions'][$badToken]); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$x]['type']; + $oldConds = ''; + foreach ($oldConditions as $condition) { + $oldConds .= token_name($condition).','; + } + + $oldConds = rtrim($oldConds, ','); + + $newConds = ''; + foreach ($tokens[$x]['conditions'] as $condition) { + $newConds .= token_name($condition).','; + } + + $newConds = rtrim($newConds, ','); + + $newLevel = $tokens[$x]['level']; + echo str_repeat("\t", ($level + 1)); + echo "* cleaned $x ($type) *".PHP_EOL; + echo str_repeat("\t", ($level + 2)); + echo "=> level changed from $oldLevel to $newLevel".PHP_EOL; + echo str_repeat("\t", ($level + 2)); + echo "=> conditions changed from $oldConds to $newConds".PHP_EOL; + }//end if + }//end for + }//end if + }//end if + + $level--; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", ($level + 2)); + echo '* level decreased *'.PHP_EOL; + } + + $tokens[$i]['level'] = $level; + $tokens[$i]['conditions'] = $conditions; + }//end if + }//end foreach + }//end if + }//end if + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END LEVEL MAP ***".PHP_EOL; + } + + }//end _createLevelMap() + + + /** + * Returns the declaration names for T_CLASS, T_INTERFACE and T_FUNCTION tokens. + * + * @param int $stackPtr The position of the declaration token which + * declared the class, interface or function. + * + * @return string|null The name of the class, interface or function. + * or NULL if the function is a closure. + * @throws PHP_CodeSniffer_Exception If the specified token is not of type + * T_FUNCTION, T_CLASS or T_INTERFACE. + */ + public function getDeclarationName($stackPtr) + { + $tokenCode = $this->_tokens[$stackPtr]['code']; + if ($tokenCode !== T_FUNCTION + && $tokenCode !== T_CLASS + && $tokenCode !== T_INTERFACE + && $tokenCode !== T_TRAIT + ) { + throw new PHP_CodeSniffer_Exception('Token type is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); + } + + if ($tokenCode === T_FUNCTION + && $this->isAnonymousFunction($stackPtr) === true + ) { + return null; + } + + $token = $this->findNext(T_STRING, $stackPtr); + return $this->_tokens[$token]['content']; + + }//end getDeclarationName() + + + /** + * Check if the token at the specified position is a anonymous function. + * + * @param int $stackPtr The position of the declaration token which + * declared the class, interface or function. + * + * @return boolean + * @throws PHP_CodeSniffer_Exception If the specified token is not of type + * T_FUNCTION + */ + public function isAnonymousFunction($stackPtr) + { + $tokenCode = $this->_tokens[$stackPtr]['code']; + if ($tokenCode !== T_FUNCTION) { + throw new PHP_CodeSniffer_Exception('Token type is not T_FUNCTION'); + } + + if (isset($this->_tokens[$stackPtr]['parenthesis_opener']) === false) { + // Something is not right with this function. + return false; + } + + $name = $this->findNext(T_STRING, ($stackPtr + 1)); + if ($name === false) { + // No name found. + return true; + } + + $open = $this->_tokens[$stackPtr]['parenthesis_opener']; + if ($name > $open) { + return true; + } + + return false; + + }//end isAnonymousFunction() + + + /** + * Returns the method parameters for the specified T_FUNCTION token. + * + * Each parameter is in the following format: + * + * + * 0 => array( + * 'name' => '$var', // The variable name. + * 'pass_by_reference' => false, // Passed by reference. + * 'type_hint' => string, // Type hint for array or custom type + * ) + * + * + * Parameters with default values have and additional array indice of + * 'default' with the value of the default as a string. + * + * @param int $stackPtr The position in the stack of the T_FUNCTION token + * to acquire the parameters for. + * + * @return array() + * @throws PHP_CodeSniffer_Exception If the specified $stackPtr is not of + * type T_FUNCTION. + */ + public function getMethodParameters($stackPtr) + { + if ($this->_tokens[$stackPtr]['code'] !== T_FUNCTION) { + throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_FUNCTION'); + } + + $opener = $this->_tokens[$stackPtr]['parenthesis_opener']; + $closer = $this->_tokens[$stackPtr]['parenthesis_closer']; + + $vars = array(); + $currVar = null; + $defaultStart = null; + $paramCount = 0; + $passByReference = false; + $typeHint = ''; + + for ($i = ($opener + 1); $i <= $closer; $i++) { + // Check to see if this token has a parenthesis opener. If it does + // its likely to be an array, which might have arguments in it, which + // we cause problems in our parsing below, so lets just skip to the + // end of it. + if (isset($this->_tokens[$i]['parenthesis_opener']) === true) { + // Don't do this if it's the close parenthesis for the method. + if ($i !== $this->_tokens[$i]['parenthesis_closer']) { + $i = ($this->_tokens[$i]['parenthesis_closer'] + 1); + } + } + + switch ($this->_tokens[$i]['code']) { + case T_BITWISE_AND: + $passByReference = true; + break; + case T_VARIABLE: + $currVar = $i; + break; + case T_ARRAY_HINT: + case T_CALLABLE: + $typeHint = $this->_tokens[$i]['content']; + break; + case T_STRING: + // This is a string, so it may be a type hint, but it could + // also be a constant used as a default value. + $prevComma = $this->findPrevious(T_COMMA, $i, $opener); + if ($prevComma !== false) { + $nextEquals = $this->findNext(T_EQUAL, $prevComma, $i); + if ($nextEquals !== false) { + break; + } + } + + if ($defaultStart === null) { + $typeHint .= $this->_tokens[$i]['content']; + } + + break; + case T_NS_SEPARATOR: + // Part of a type hint or default value. + if ($defaultStart === null) { + $typeHint .= $this->_tokens[$i]['content']; + } + + break; + case T_CLOSE_PARENTHESIS: + case T_COMMA: + // If it's null, then there must be no parameters for this + // method. + if ($currVar === null) { + continue; + } + + $vars[$paramCount] = array(); + $vars[$paramCount]['name'] = $this->_tokens[$currVar]['content']; + + if ($defaultStart !== null) { + $vars[$paramCount]['default'] + = $this->getTokensAsString( + $defaultStart, + ($i - $defaultStart) + ); + } + + $vars[$paramCount]['pass_by_reference'] = $passByReference; + $vars[$paramCount]['type_hint'] = $typeHint; + + // Reset the vars, as we are about to process the next parameter. + $defaultStart = null; + $passByReference = false; + $typeHint = ''; + + $paramCount++; + break; + case T_EQUAL: + $defaultStart = ($i + 1); + break; + }//end switch + }//end for + + return $vars; + + }//end getMethodParameters() + + + /** + * Returns the visibility and implementation properties of a method. + * + * The format of the array is: + * + * array( + * 'scope' => 'public', // public private or protected + * 'scope_specified' => true, // true is scope keyword was found. + * 'is_abstract' => false, // true if the abstract keyword was found. + * 'is_final' => false, // true if the final keyword was found. + * 'is_static' => false, // true if the static keyword was found. + * 'is_closure' => false, // true if no name is found. + * ); + * + * + * @param int $stackPtr The position in the stack of the T_FUNCTION token to + * acquire the properties for. + * + * @return array + * @throws PHP_CodeSniffer_Exception If the specified position is not a + * T_FUNCTION token. + */ + public function getMethodProperties($stackPtr) + { + if ($this->_tokens[$stackPtr]['code'] !== T_FUNCTION) { + throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_FUNCTION'); + } + + $valid = array( + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_STATIC, + T_FINAL, + T_ABSTRACT, + T_WHITESPACE, + T_COMMENT, + T_DOC_COMMENT, + ); + + $scope = 'public'; + $scopeSpecified = false; + $isAbstract = false; + $isFinal = false; + $isStatic = false; + $isClosure = $this->isAnonymousFunction($stackPtr); + + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if (in_array($this->_tokens[$i]['code'], $valid) === false) { + break; + } + + switch ($this->_tokens[$i]['code']) { + case T_PUBLIC: + $scope = 'public'; + $scopeSpecified = true; + break; + case T_PRIVATE: + $scope = 'private'; + $scopeSpecified = true; + break; + case T_PROTECTED: + $scope = 'protected'; + $scopeSpecified = true; + break; + case T_ABSTRACT: + $isAbstract = true; + break; + case T_FINAL: + $isFinal = true; + break; + case T_STATIC: + $isStatic = true; + break; + }//end switch + }//end for + + return array( + 'scope' => $scope, + 'scope_specified' => $scopeSpecified, + 'is_abstract' => $isAbstract, + 'is_final' => $isFinal, + 'is_static' => $isStatic, + 'is_closure' => $isClosure, + ); + + }//end getMethodProperties() + + + /** + * Returns the visibility and implementation properties of the class member + * variable found at the specified position in the stack. + * + * The format of the array is: + * + * + * array( + * 'scope' => 'public', // public private or protected + * 'is_static' => false, // true if the static keyword was found. + * ); + * + * + * @param int $stackPtr The position in the stack of the T_VARIABLE token to + * acquire the properties for. + * + * @return array + * @throws PHP_CodeSniffer_Exception If the specified position is not a + * T_VARIABLE token, or if the position is not + * a class member variable. + */ + public function getMemberProperties($stackPtr) + { + if ($this->_tokens[$stackPtr]['code'] !== T_VARIABLE) { + throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_VARIABLE'); + } + + $conditions = array_keys($this->_tokens[$stackPtr]['conditions']); + $ptr = array_pop($conditions); + if (isset($this->_tokens[$ptr]) === false + || $this->_tokens[$ptr]['code'] !== T_CLASS + ) { + if (isset($this->_tokens[$ptr]) === true + && $this->_tokens[$ptr]['code'] === T_INTERFACE + ) { + // T_VARIABLEs in interfaces can actually be method arguments + // but they wont be seen as being inside the method because there + // are no scope openers and closers for abstract methods. If it is in + // parentheses, we can be pretty sure it is a method argument. + if (isset($this->_tokens[$stackPtr]['nested_parenthesis']) === false + || empty($this->_tokens[$stackPtr]['nested_parenthesis']) === true + ) { + $error = 'Possible parse error: interfaces may not include member vars'; + $this->addWarning($error, $stackPtr, 'Internal.ParseError.InterfaceHasMemberVar'); + return array(); + } + } else { + throw new PHP_CodeSniffer_Exception('$stackPtr is not a class member var'); + } + } + + $valid = array( + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_STATIC, + T_WHITESPACE, + T_COMMENT, + T_DOC_COMMENT, + T_VARIABLE, + T_COMMA, + ); + + $scope = 'public'; + $scopeSpecified = false; + $isStatic = false; + + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if (in_array($this->_tokens[$i]['code'], $valid) === false) { + break; + } + + switch ($this->_tokens[$i]['code']) { + case T_PUBLIC: + $scope = 'public'; + $scopeSpecified = true; + break; + case T_PRIVATE: + $scope = 'private'; + $scopeSpecified = true; + break; + case T_PROTECTED: + $scope = 'protected'; + $scopeSpecified = true; + break; + case T_STATIC: + $isStatic = true; + break; + } + }//end for + + return array( + 'scope' => $scope, + 'scope_specified' => $scopeSpecified, + 'is_static' => $isStatic, + ); + + }//end getMemberProperties() + + + /** + * Returns the visibility and implementation properties of a class. + * + * The format of the array is: + * + * array( + * 'is_abstract' => false, // true if the abstract keyword was found. + * 'is_final' => false, // true if the final keyword was found. + * ); + * + * + * @param int $stackPtr The position in the stack of the T_CLASS token to + * acquire the properties for. + * + * @return array + * @throws PHP_CodeSniffer_Exception If the specified position is not a + * T_CLASS token. + */ + public function getClassProperties($stackPtr) + { + if ($this->_tokens[$stackPtr]['code'] !== T_CLASS) { + throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_CLASS'); + } + + $valid = array( + T_FINAL, + T_ABSTRACT, + T_WHITESPACE, + T_COMMENT, + T_DOC_COMMENT, + ); + + $isAbstract = false; + $isFinal = false; + + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if (in_array($this->_tokens[$i]['code'], $valid) === false) { + break; + } + + switch ($this->_tokens[$i]['code']) { + case T_ABSTRACT: + $isAbstract = true; + break; + + case T_FINAL: + $isFinal = true; + break; + } + }//end for + + return array( + 'is_abstract' => $isAbstract, + 'is_final' => $isFinal, + ); + + }//end getClassProperties() + + + /** + * Determine if the passed token is a reference operator. + * + * Returns true if the specified token position represents a reference. + * Returns false if the token represents a bitwise operator. + * + * @param int $stackPtr The position of the T_BITWISE_AND token. + * + * @return boolean + */ + public function isReference($stackPtr) + { + if ($this->_tokens[$stackPtr]['code'] !== T_BITWISE_AND) { + return false; + } + + $tokenBefore = $this->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($stackPtr - 1), + null, + true + ); + + if ($this->_tokens[$tokenBefore]['code'] === T_FUNCTION) { + // Function returns a reference. + return true; + } + + if ($this->_tokens[$tokenBefore]['code'] === T_DOUBLE_ARROW) { + // Inside a foreach loop, this is a reference. + return true; + } + + if ($this->_tokens[$tokenBefore]['code'] === T_AS) { + // Inside a foreach loop, this is a reference. + return true; + } + + if (in_array($this->_tokens[$tokenBefore]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { + // This is directly after an assignment. It's a reference. Even if + // it is part of an operation, the other tests will handle it. + return true; + } + + if (isset($this->_tokens[$stackPtr]['nested_parenthesis']) === true) { + $brackets = $this->_tokens[$stackPtr]['nested_parenthesis']; + $lastBracket = array_pop($brackets); + if (isset($this->_tokens[$lastBracket]['parenthesis_owner']) === true) { + $owner = $this->_tokens[$this->_tokens[$lastBracket]['parenthesis_owner']]; + if ($owner['code'] === T_FUNCTION + || $owner['code'] === T_CLOSURE + || $owner['code'] === T_ARRAY + ) { + // Inside a function or array declaration, this is a reference. + return true; + } + } else { + $prev = $this->findPrevious( + array(T_WHITESPACE), + ($this->_tokens[$lastBracket]['parenthesis_opener'] - 1), + null, + true + ); + + if ($prev !== false && $this->_tokens[$prev]['code'] === T_USE) { + return true; + } + } + } + + $tokenAfter = $this->findNext( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($stackPtr + 1), + null, + true + ); + + if ($this->_tokens[$tokenAfter]['code'] === T_VARIABLE + && ($this->_tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS + || $this->_tokens[$tokenBefore]['code'] === T_COMMA) + ) { + return true; + } + + return false; + + }//end isReference() + + + /** + * Returns the content of the tokens from the specified start position in + * the token stack for the specified length. + * + * @param int $start The position to start from in the token stack. + * @param int $length The length of tokens to traverse from the start pos. + * + * @return string The token contents. + */ + public function getTokensAsString($start, $length) + { + $str = ''; + $end = ($start + $length); + if ($end > $this->numTokens) { + $end = $this->numTokens; + } + + for ($i = $start; $i < $end; $i++) { + $str .= $this->_tokens[$i]['content']; + } + + return $str; + + }//end getTokensAsString() + + + /** + * Returns the position of the next specified token(s). + * + * If a value is specified, the next token of the specified type(s) + * containing the specified value will be returned. + * + * Returns false if no token can be found. + * + * @param int|array $types The type(s) of tokens to search for. + * @param int $start The position to start searching from in the + * token stack. + * @param int $end The end position to fail if no token is found. + * if not specified or null, end will default to + * the start of the token stack. + * @param bool $exclude If true, find the next token that are NOT of + * the types specified in $types. + * @param string $value The value that the token(s) must be equal to. + * If value is omitted, tokens with any value will + * be returned. + * @param bool $local If true, tokens outside the current statement + * will not be checked. IE. checking will stop + * at the next semi-colon found. + * + * @return int | bool + * @see findNext() + */ + public function findPrevious( + $types, + $start, + $end=null, + $exclude=false, + $value=null, + $local=false + ) { + $types = (array) $types; + + if ($end === null) { + $end = 0; + } + + for ($i = $start; $i >= $end; $i--) { + $found = (bool) $exclude; + foreach ($types as $type) { + if ($this->_tokens[$i]['code'] === $type) { + $found = !$exclude; + break; + } + } + + if ($found === true) { + if ($value === null) { + return $i; + } else if ($this->_tokens[$i]['content'] === $value) { + return $i; + } + } + + if ($local === true && $this->_tokens[$i]['code'] === T_SEMICOLON) { + break; + } + }//end for + + return false; + + }//end findPrevious() + + + /** + * Returns the position of the next specified token(s). + * + * If a value is specified, the next token of the specified type(s) + * containing the specified value will be returned. + * + * Returns false if no token can be found. + * + * @param int|array $types The type(s) of tokens to search for. + * @param int $start The position to start searching from in the + * token stack. + * @param int $end The end position to fail if no token is found. + * if not specified or null, end will default to + * the end of the token stack. + * @param bool $exclude If true, find the next token that is NOT of + * a type specified in $types. + * @param string $value The value that the token(s) must be equal to. + * If value is omitted, tokens with any value will + * be returned. + * @param bool $local If true, tokens outside the current statement + * will not be checked. i.e., checking will stop + * at the next semi-colon found. + * + * @return int | bool + * @see findPrevious() + */ + public function findNext( + $types, + $start, + $end=null, + $exclude=false, + $value=null, + $local=false + ) { + $types = (array) $types; + + if ($end === null || $end > $this->numTokens) { + $end = $this->numTokens; + } + + for ($i = $start; $i < $end; $i++) { + $found = (bool) $exclude; + foreach ($types as $type) { + if ($this->_tokens[$i]['code'] === $type) { + $found = !$exclude; + break; + } + } + + if ($found === true) { + if ($value === null) { + return $i; + } else if ($this->_tokens[$i]['content'] === $value) { + return $i; + } + } + + if ($local === true && $this->_tokens[$i]['code'] === T_SEMICOLON) { + break; + } + }//end for + + return false; + + }//end findNext() + + + /** + * Returns the position of the first token on a line, matching given type. + * + * Returns false if no token can be found. + * + * @param int|array $types The type(s) of tokens to search for. + * @param int $start The position to start searching from in the + * token stack. The first token matching on + * this line before this token will be returned. + * @param bool $exclude If true, find the token that is NOT of + * the types specified in $types. + * @param string $value The value that the token must be equal to. + * If value is omitted, tokens with any value will + * be returned. + * + * @return int | bool + */ + public function findFirstOnLine($types, $start, $exclude=false, $value=null) + { + if (is_array($types) === false) { + $types = array($types); + } + + $foundToken = false; + + for ($i = $start; $i >= 0; $i--) { + if ($this->_tokens[$i]['line'] < $this->_tokens[$start]['line']) { + break; + } + + $found = $exclude; + foreach ($types as $type) { + if ($exclude === false) { + if ($this->_tokens[$i]['code'] === $type) { + $found = true; + break; + } + } else { + if ($this->_tokens[$i]['code'] === $type) { + $found = false; + break; + } + } + } + + if ($found === true) { + if ($value === null) { + $foundToken = $i; + } else if ($this->_tokens[$i]['content'] === $value) { + $foundToken = $i; + } + } + }//end for + + return $foundToken; + + }//end findFirstOnLine() + + + /** + * Determine if the passed token has a condition of one of the passed types. + * + * @param int $stackPtr The position of the token we are checking. + * @param int|array $types The type(s) of tokens to search for. + * + * @return boolean + */ + public function hasCondition($stackPtr, $types) + { + // Check for the existence of the token. + if (isset($this->_tokens[$stackPtr]) === false) { + return false; + } + + // Make sure the token has conditions. + if (isset($this->_tokens[$stackPtr]['conditions']) === false) { + return false; + } + + $types = (array) $types; + $conditions = $this->_tokens[$stackPtr]['conditions']; + + foreach ($types as $type) { + if (in_array($type, $conditions) === true) { + // We found a token with the required type. + return true; + } + } + + return false; + + }//end hasCondition() + + + /** + * Return the position of the condition for the passed token. + * + * Returns FALSE if the token does not have the condition. + * + * @param int $stackPtr The position of the token we are checking. + * @param int $type The type of token to search for. + * + * @return int + */ + public function getCondition($stackPtr, $type) + { + // Check for the existence of the token. + if (isset($this->_tokens[$stackPtr]) === false) { + return false; + } + + // Make sure the token has conditions. + if (isset($this->_tokens[$stackPtr]['conditions']) === false) { + return false; + } + + $conditions = $this->_tokens[$stackPtr]['conditions']; + foreach ($conditions as $token => $condition) { + if ($condition === $type) { + return $token; + } + } + + return false; + + }//end getCondition() + + + /** + * Returns the name of the class that the specified class extends. + * + * Returns FALSE on error or if there is no extended class name. + * + * @param int $stackPtr The stack position of the class. + * + * @return string + */ + public function findExtendedClassName($stackPtr) + { + // Check for the existence of the token. + if (isset($this->_tokens[$stackPtr]) === false) { + return false; + } + + if ($this->_tokens[$stackPtr]['code'] !== T_CLASS) { + return false; + } + + if (isset($this->_tokens[$stackPtr]['scope_closer']) === false) { + return false; + } + + $classCloserIndex = $this->_tokens[$stackPtr]['scope_closer']; + $extendsIndex = $this->findNext(T_EXTENDS, $stackPtr, $classCloserIndex); + if (false === $extendsIndex) { + return false; + } + + $find = array( + T_NS_SEPARATOR, + T_STRING, + T_WHITESPACE, + ); + + $end = $this->findNext($find, ($extendsIndex + 1), $classCloserIndex, true); + $name = $this->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1)); + $name = trim($name); + + if ($name === '') { + return false; + } + + return $name; + + }//end findExtendedClassName() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Report.php b/codesniffer/CodeSniffer/Report.php new file mode 100644 index 000000000..87f2044b2 --- /dev/null +++ b/codesniffer/CodeSniffer/Report.php @@ -0,0 +1,81 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Represents a PHP_CodeSniffer report. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +interface PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ); + + + /** + * Generate the actual report. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ); + + +}//end interface + +?> diff --git a/codesniffer/CodeSniffer/Reporting.php b/codesniffer/CodeSniffer/Reporting.php new file mode 100644 index 000000000..d5edbbc39 --- /dev/null +++ b/codesniffer/CodeSniffer/Reporting.php @@ -0,0 +1,315 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (is_file(dirname(__FILE__).'/../CodeSniffer.php') === true) { + include_once dirname(__FILE__).'/../CodeSniffer.php'; +} else { + include_once 'PHP/CodeSniffer.php'; +} + +/** + * A class to manage reporting. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reporting +{ + + /** + * Total number of files that contain errors or warnings. + * + * @var int + */ + public $totalFiles = 0; + + /** + * Total number of errors found during the run. + * + * @var int + */ + public $totalErrors = 0; + + /** + * Total number of warnings found during the run. + * + * @var int + */ + public $totalWarnings = 0; + + /** + * A list of reports that have written partial report output. + * + * @var array + */ + private $_cachedReports = array(); + + /** + * A cache of report objects. + * + * @var array + */ + private $_reports = array(); + + + /** + * Produce the appropriate report object based on $type parameter. + * + * @param string $type The type of the report. + * + * @return PHP_CodeSniffer_Report + * @throws PHP_CodeSniffer_Exception If report is not available. + */ + public function factory($type) + { + $type = ucfirst($type); + if (isset($this->_reports[$type]) === true) { + return $this->_reports[$type]; + } + + $filename = $type.'.php'; + $reportClassName = 'PHP_CodeSniffer_Reports_'.$type; + if (class_exists($reportClassName, true) === false) { + throw new PHP_CodeSniffer_Exception('Report type "'.$type.'" not found.'); + } + + $reportClass = new $reportClassName(); + if (false === ($reportClass instanceof PHP_CodeSniffer_Report)) { + throw new PHP_CodeSniffer_Exception('Class "'.$reportClassName.'" must implement the "PHP_CodeSniffer_Report" interface.'); + } + + $this->_reports[$type] = $reportClass; + return $this->_reports[$type]; + + }//end factory() + + + /** + * Actually generates the report. + * + * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed. + * @param array $cliValues An array of command line arguments. + * + * @return void + */ + public function cacheFileReport(PHP_CodeSniffer_File $phpcsFile, array $cliValues) + { + if (isset($cliValues['reports']) === false) { + // This happens during unit testing, or any time someone just wants + // the error data and not the printed report. + return; + } + + $reportData = $this->prepareFileReport($phpcsFile); + $errorsShown = false; + + foreach ($cliValues['reports'] as $report => $output) { + $reportClass = self::factory($report); + + ob_start(); + $result = $reportClass->generateFileReport($reportData, $cliValues['showSources'], $cliValues['reportWidth']); + if ($result === true) { + $errorsShown = true; + } + + $generatedReport = ob_get_contents(); + ob_end_clean(); + + if ($generatedReport !== '') { + $flags = FILE_APPEND; + if (in_array($report, $this->_cachedReports) === false) { + $this->_cachedReports[] = $report; + $flags = null; + } + + if ($output === null) { + if ($cliValues['reportFile'] !== null) { + $output = $cliValues['reportFile']; + } else { + $output = sys_get_temp_dir().'/phpcs-'.$report.'.tmp'; + } + } + + file_put_contents($output, $generatedReport, $flags); + } + }//end foreach + + if ($errorsShown === true) { + $this->totalFiles++; + $this->totalErrors += $reportData['errors']; + $this->totalWarnings += $reportData['warnings']; + } + + }//end cacheFileReport() + + + /** + * Actually generates the report. + * + * @param string $report Report type. + * @param boolean $showSources Show sources? + * @param string $reportFile Report file to generate. + * @param integer $reportWidth Report max width. + * + * @return integer + */ + public function printReport( + $report, + $showSources, + $reportFile='', + $reportWidth=80 + ) { + if ($this->totalFiles === 0) { + // No files generated errors. + return 0; + } + + $reportClass = self::factory($report); + + if ($reportFile !== null) { + $filename = $reportFile; + $toScreen = false; + ob_start(); + } else { + $filename = sys_get_temp_dir().'/phpcs-'.$report.'.tmp'; + $toScreen = true; + } + + if (file_exists($filename) === true) { + $reportCache = file_get_contents($filename); + } else { + $reportCache = ''; + } + + $reportClass->generate( + $reportCache, + $this->totalFiles, + $this->totalErrors, + $this->totalWarnings, + $showSources, + $reportWidth, + $toScreen + ); + + if ($reportFile !== null) { + $generatedReport = ob_get_contents(); + ob_end_clean(); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo $generatedReport; + } + + $generatedReport = trim($generatedReport); + file_put_contents($reportFile, $generatedReport.PHP_EOL); + } else if (file_exists($filename) === true) { + unlink($filename); + } + + return ($this->totalErrors + $this->totalWarnings); + + }//end printReport() + + + /** + * Pre-process and package violations for all files. + * + * Used by error reports to get a packaged list of all errors in each file. + * + * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed. + * + * @return array + */ + public function prepareFileReport(PHP_CodeSniffer_File $phpcsFile) + { + $report = array( + 'filename' => $phpcsFile->getFilename(), + 'errors' => $phpcsFile->getErrorCount(), + 'warnings' => $phpcsFile->getWarningCount(), + 'messages' => array(), + ); + + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Prefect score! + return $report; + } + + $errors = array(); + + // Merge errors and warnings. + foreach ($phpcsFile->getErrors() as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + $newErrors = array(); + foreach ($colErrors as $data) { + $newErrors[] = array( + 'message' => $data['message'], + 'source' => $data['source'], + 'severity' => $data['severity'], + 'type' => 'ERROR', + ); + } + + $errors[$line][$column] = $newErrors; + }//end foreach + + ksort($errors[$line]); + }//end foreach + + foreach ($phpcsFile->getWarnings() as $line => $lineWarnings) { + foreach ($lineWarnings as $column => $colWarnings) { + $newWarnings = array(); + foreach ($colWarnings as $data) { + $newWarnings[] = array( + 'message' => $data['message'], + 'source' => $data['source'], + 'severity' => $data['severity'], + 'type' => 'WARNING', + ); + } + + if (isset($errors[$line]) === false) { + $errors[$line] = array(); + } + + if (isset($errors[$line][$column]) === true) { + $errors[$line][$column] = array_merge( + $newWarnings, + $errors[$line][$column] + ); + } else { + $errors[$line][$column] = $newWarnings; + } + }//end foreach + + ksort($errors[$line]); + }//end foreach + + ksort($errors); + $report['messages'] = $errors; + return $report; + + }//end prepareFileReport() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Checkstyle.php b/codesniffer/CodeSniffer/Reports/Checkstyle.php new file mode 100644 index 000000000..ea5fa63e0 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Checkstyle.php @@ -0,0 +1,126 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checkstyle report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Checkstyle implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + $out = new XMLWriter; + $out->openMemory(); + $out->setIndent(true); + + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + $out->startElement('file'); + $out->writeAttribute('name', $report['filename']); + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $error['type'] = strtolower($error['type']); + if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { + $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); + } + + $out->startElement('error'); + $out->writeAttribute('line', $line); + $out->writeAttribute('column', $column); + $out->writeAttribute('severity', $error['type']); + $out->writeAttribute('message', $error['message']); + $out->writeAttribute('source', $error['source']); + $out->endElement(); + } + } + }//end foreach + + $out->endElement(); + echo $out->flush(); + + return true; + + }//end generateFileReport() + + + /** + * Prints all violations for processed files, in a Checkstyle format. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo ''.PHP_EOL; + echo ''.PHP_EOL; + echo $cachedData; + echo ''.PHP_EOL; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Csv.php b/codesniffer/CodeSniffer/Reports/Csv.php new file mode 100644 index 000000000..3bf1b2023 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Csv.php @@ -0,0 +1,108 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Csv report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Csv implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $filename = str_replace('"', '\"', $report['filename']); + $message = str_replace('"', '\"', $error['message']); + $type = strtolower($error['type']); + $source = $error['source']; + $severity = $error['severity']; + echo "\"$filename\",$line,$column,$type,\"$message\",$source,$severity".PHP_EOL; + } + } + } + + return true; + + }//end generateFileReport() + + + /** + * Generates a csv report. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo 'File,Line,Column,Type,Message,Source,Severity'.PHP_EOL; + echo $cachedData; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Emacs.php b/codesniffer/CodeSniffer/Reports/Emacs.php new file mode 100644 index 000000000..8229ec54a --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Emacs.php @@ -0,0 +1,108 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Emacs report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Emacs implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $message = $error['message']; + if ($showSources === true) { + $message .= ' ('.$error['source'].')'; + } + + $type = strtolower($error['type']); + echo $report['filename'].':'.$line.':'.$column.': '.$type.' - '.$message.PHP_EOL; + } + } + } + + return true; + + }//end generateFileReport() + + + /** + * Generates an emacs report. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo $cachedData; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Full.php b/codesniffer/CodeSniffer/Reports/Full.php new file mode 100644 index 000000000..738bcbf3f --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Full.php @@ -0,0 +1,178 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Full report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Full implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + $width = max($width, 70); + $file = $report['filename']; + + echo PHP_EOL.'FILE: '; + if (strlen($file) <= ($width - 9)) { + echo $file; + } else { + echo '...'.substr($file, (strlen($file) - ($width - 9))); + } + + echo PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + + echo 'FOUND '.$report['errors'].' ERROR(S) '; + if ($report['warnings'] > 0) { + echo 'AND '.$report['warnings'].' WARNING(S) '; + } + + echo 'AFFECTING '.count($report['messages']).' LINE(S)'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + + // Work out the max line number for formatting. + $maxLine = 0; + foreach ($report['messages'] as $line => $lineErrors) { + if ($line > $maxLine) { + $maxLine = $line; + } + } + + $maxLineLength = strlen($maxLine); + + // The length of the word ERROR or WARNING; used for padding. + if ($report['warnings'] > 0) { + $typeLength = 7; + } else { + $typeLength = 5; + } + + // The padding that all lines will require that are + // printing an error message overflow. + $paddingLine2 = str_repeat(' ', ($maxLineLength + 1)); + $paddingLine2 .= ' | '; + $paddingLine2 .= str_repeat(' ', $typeLength); + $paddingLine2 .= ' | '; + + // The maximum amount of space an error message can use. + $maxErrorSpace = ($width - strlen($paddingLine2) - 1); + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $message = $error['message']; + if ($showSources === true) { + $message .= ' ('.$error['source'].')'; + } + + // The padding that goes on the front of the line. + $padding = ($maxLineLength - strlen($line)); + $errorMsg = wordwrap( + $message, + $maxErrorSpace, + PHP_EOL.$paddingLine2 + ); + + echo ' '.str_repeat(' ', $padding).$line.' | '.$error['type']; + if ($error['type'] === 'ERROR') { + if ($report['warnings'] > 0) { + echo ' '; + } + } + + echo ' | '.$errorMsg.PHP_EOL; + }//end foreach + }//end foreach + }//end foreach + + echo str_repeat('-', $width).PHP_EOL.PHP_EOL; + return true; + + }//end generateFileReport() + + + /** + * Prints all errors and warnings for each file processed. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo $cachedData; + + if ($toScreen === true + && PHP_CODESNIFFER_INTERACTIVE === false + && class_exists('PHP_Timer', false) === true + ) { + echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; + } + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Gitblame.php b/codesniffer/CodeSniffer/Reports/Gitblame.php new file mode 100644 index 000000000..fd3fd449d --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Gitblame.php @@ -0,0 +1,133 @@ + + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Gitblame report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Ben Selby + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: 1.2.2 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Gitblame extends PHP_CodeSniffer_Reports_VersionControl +{ + + /** + * The name of the report we want in the output + * + * @var string + */ + protected $reportName = 'GIT'; + + + /** + * Extract the author from a blame line. + * + * @param string $line Line to parse. + * + * @return mixed string or false if impossible to recover. + */ + protected function getAuthor($line) + { + $blameParts = array(); + $line = preg_replace('|\s+|', ' ', $line); + preg_match( + '|\(.+[0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]+\)|', + $line, + $blameParts + ); + + if (isset($blameParts[0]) === false) { + return false; + } + + $parts = explode(' ', $blameParts[0]); + + if (count($parts) < 2) { + return false; + } + + $parts = array_slice($parts, 0, (count($parts) - 2)); + + return preg_replace('|\(|', '', implode($parts, ' ')); + + }//end getAuthor() + + + /** + * Gets the blame output. + * + * @param string $filename File to blame. + * + * @return array + */ + protected function getBlameContent($filename) + { + $cwd = getcwd(); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Getting GIT blame info for '.basename($filename).'... '; + } + + $fileParts = explode(DIRECTORY_SEPARATOR, $filename); + $found = false; + $location = ''; + while (empty($fileParts) === false) { + array_pop($fileParts); + $location = implode($fileParts, DIRECTORY_SEPARATOR); + if (is_dir($location.DIRECTORY_SEPARATOR.'.git') === true) { + $found = true; + break; + } + } + + if ($found === true) { + chdir($location); + } else { + echo 'ERROR: Could not locate .git directory '.PHP_EOL.PHP_EOL; + exit(2); + } + + $command = 'git blame --date=short "'.$filename.'"'; + $handle = popen($command, 'r'); + if ($handle === false) { + echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; + exit(2); + } + + $rawContent = stream_get_contents($handle); + fclose($handle); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'DONE'.PHP_EOL; + } + + $blames = explode("\n", $rawContent); + chdir($cwd); + + return $blames; + + }//end getBlameContent() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Hgblame.php b/codesniffer/CodeSniffer/Reports/Hgblame.php new file mode 100644 index 000000000..c69597e53 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Hgblame.php @@ -0,0 +1,134 @@ + + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Mercurial report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Ben Selby + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Hgblame extends PHP_CodeSniffer_Reports_VersionControl +{ + + /** + * The name of the report we want in the output + * + * @var string + */ + protected $reportName = 'MERCURIAL'; + + + /** + * Extract the author from a blame line. + * + * @param string $line Line to parse. + * + * @return mixed string or false if impossible to recover. + */ + protected function getAuthor($line) + { + $blameParts = array(); + $line = preg_replace('|\s+|', ' ', $line); + + preg_match( + '|(.+[0-9]{2}:[0-9]{2}:[0-9]{2}\s[0-9]{4}\s.[0-9]{4}:)|', + $line, + $blameParts + ); + + if (isset($blameParts[0]) === false) { + return false; + } + + $parts = explode(' ', $blameParts[0]); + + if (count($parts) < 6) { + return false; + } + + $parts = array_slice($parts, 0, (count($parts) - 6)); + + return trim(preg_replace('|<.+>|', '', implode($parts, ' '))); + + }//end getAuthor() + + + /** + * Gets the blame output. + * + * @param string $filename File to blame. + * + * @return array + */ + protected function getBlameContent($filename) + { + $cwd = getcwd(); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Getting MERCURIAL blame info for '.basename($filename).'... '; + } + + $fileParts = explode(DIRECTORY_SEPARATOR, $filename); + $found = false; + $location = ''; + while (empty($fileParts) === false) { + array_pop($fileParts); + $location = implode($fileParts, DIRECTORY_SEPARATOR); + if (is_dir($location.DIRECTORY_SEPARATOR.'.hg') === true) { + $found = true; + break; + } + } + + if ($found === true) { + chdir($location); + } else { + echo 'ERROR: Could not locate .hg directory '.PHP_EOL.PHP_EOL; + exit(2); + } + + $command = 'hg blame -u -d -v "'.$filename.'"'; + $handle = popen($command, 'r'); + if ($handle === false) { + echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; + exit(2); + } + + $rawContent = stream_get_contents($handle); + fclose($handle); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'DONE'.PHP_EOL; + } + + $blames = explode("\n", $rawContent); + chdir($cwd); + + return $blames; + + }//end getBlameContent() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Json.php b/codesniffer/CodeSniffer/Reports/Json.php new file mode 100644 index 000000000..0df413fcb --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Json.php @@ -0,0 +1,114 @@ + + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Json report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Jeffrey Fisher + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Json implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + + $filename = str_replace('"', '\"', $report['filename']); + $filename = str_replace('/', '\/', $report['filename']); + echo "\"$filename\":{"; + echo '"errors":'.$report['errors'].',"warnings":'.$report['warnings'].',"messages":['; + + $messages = ''; + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $error['message'] = str_replace('"', '\"', $error['message']); + $error['message'] = str_replace('/', '\/', $error['message']); + + $messages .= '{"message":"'.$error['message'].'",'; + $messages .= '"source":"'.$error['source'].'",'; + $messages .= '"severity":'.$error['severity'].','; + $messages .= '"type":"'.$error['type'].'",'; + $messages .= '"line":'.$line.',"column":'.$column.'},'; + } + } + } + + echo rtrim($messages, ','); + echo ']},'; + + return true; + + }//end generateFileReport() + + + /** + * Generates a JSON report. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo '{"totals":{"errors":'.$totalErrors.',"warnings":'.$totalWarnings.'},"files":{'; + echo rtrim($cachedData, ','); + echo "}}"; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Junit.php b/codesniffer/CodeSniffer/Reports/Junit.php new file mode 100644 index 000000000..888e70a82 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Junit.php @@ -0,0 +1,148 @@ + + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * JUnit report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Oleg Lobach + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Junit implements PHP_CodeSniffer_Report +{ + + /** + * A count of tests that have been performed. + * + * @var int + */ + private $_tests = 0; + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if (count($report['messages']) === 0) { + $this->_tests++; + } else { + $this->_tests += ($report['errors'] + $report['warnings']); + } + + $out = new XMLWriter; + $out->openMemory(); + $out->setIndent(true); + + $out->startElement('testsuite'); + $out->writeAttribute('name', $report['filename']); + + if (count($report['messages']) === 0) { + $out->writeAttribute('tests', 1); + $out->writeAttribute('failures', 0); + + $out->startElement('testcase'); + $out->writeAttribute('name', $report['filename']); + $out->endElement(); + } else { + $failures = ($report['errors'] + $report['warnings']); + $out->writeAttribute('tests', $failures); + $out->writeAttribute('failures', $failures); + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $out->startElement('testcase'); + $out->writeAttribute('name', $error['source'].' at '.$report['filename']." ($line:$column)"); + + $error['type'] = strtolower($error['type']); + if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { + $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); + } + + $out->startElement('failure'); + $out->writeAttribute('type', $error['type']); + $out->writeAttribute('message', $error['message']); + $out->endElement(); + + $out->endElement(); + } + } + } + }//end if + + $out->endElement(); + echo $out->flush(); + return true; + + }//end generateFileReport() + + + /** + * Prints all violations for processed files, in a proprietary XML format. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + $phpcs = new PHP_CodeSniffer; + $failures = ($totalErrors + $totalWarnings); + echo ''.PHP_EOL; + echo ''.PHP_EOL; + echo $cachedData; + echo ''.PHP_EOL; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Notifysend.php b/codesniffer/CodeSniffer/Reports/Notifysend.php new file mode 100644 index 000000000..2bde834c0 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Notifysend.php @@ -0,0 +1,262 @@ + + * @author Greg Sherwood + * @copyright 2012 Christian Weiske + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Notify-send report for PHP_CodeSniffer. + * + * Supported configuration parameters: + * - notifysend_path - Full path to notify-send cli command + * - notifysend_timeout - Timeout in milliseconds + * - notifysend_showok - Show "ok, all fine" messages (0/1) + * + * @category PHP + * @package PHP_CodeSniffer + * @author Christian Weiske + * @author Greg Sherwood + * @copyright 2012 Christian Weiske + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Notifysend implements PHP_CodeSniffer_Report +{ + + /** + * Notification timeout in milliseconds. + * + * @var integer + */ + protected $timeout = 3000; + + /** + * Path to notify-send command. + * + * @var string + */ + protected $path = 'notify-send'; + + /** + * Show "ok, all fine" messages. + * + * @var boolean + */ + protected $showOk = true; + + /** + * Version of installed notify-send executable. + * + * @var string + */ + protected $version = null; + + /** + * A record of the last file checked. + * + * This is used in case we only checked one file and need to print + * the name/path of the file. We wont have access to the checked file list + * after the run has been completed. + * + * @var string + */ + private $_lastCheckedFile = ''; + + + /** + * Load configuration data. + * + * @return void + */ + public function __construct() + { + $path = PHP_CodeSniffer::getConfigData('notifysend_path'); + if ($path !== null) { + $this->path = $path; + } + + $timeout = PHP_CodeSniffer::getConfigData('notifysend_timeout'); + if ($timeout !== null) { + $this->timeout = (int) $timeout; + } + + $showOk = PHP_CodeSniffer::getConfigData('notifysend_showok'); + if ($showOk !== null) { + $this->showOk = (boolean) $showOk; + } + + $this->version = str_replace( + 'notify-send ', + '', + exec($this->path . ' --version') + ); + + }//end __construct() + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + // We don't need to print anything, but we want this file counted + // in the total number of checked files even if it has no errors. + $this->_lastCheckedFile = $report['filename']; + return true; + + }//end generateFileReport() + + + /** + * Generates a summary of errors and warnings for each file processed. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + $msg = $this->generateMessage($totalFiles, $totalErrors, $totalWarnings); + if ($msg === null) { + if ($this->showOk === true) { + $this->notifyAllFine(); + } + } else { + $this->notifyErrors($msg); + } + + }//end generate() + + + /** + * Generate the error message to show to the user. + * + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * + * @return string Error message or NULL if no error/warning found. + */ + protected function generateMessage($totalFiles, $totalErrors, $totalWarnings) + { + if ($totalErrors === 0 && $totalWarnings === 0) { + // Nothing to print. + return null; + } + + $msg = ''; + if ($totalFiles > 1) { + $msg .= 'Checked '.$totalFiles.' files'.PHP_EOL; + } else { + $msg .= $this->_lastCheckedFile.PHP_EOL; + } + + if ($totalWarnings > 0) { + $msg .= $totalWarnings.' warnings'.PHP_EOL; + } + + if ($totalErrors > 0) { + $msg .= $totalErrors.' errors'.PHP_EOL; + } + + return $msg; + + }//end generateMessage() + + + /** + * Tell the user that all is fine and no error/warning has been found. + * + * @return void + */ + protected function notifyAllFine() + { + $cmd = $this->getBasicCommand(); + $cmd .= ' -i info'; + $cmd .= ' "PHP CodeSniffer: Ok"'; + $cmd .= ' "All fine"'; + exec($cmd); + + }//end notifyAllFine() + + + /** + * Tell the user that errors/warnings have been found. + * + * @param string $msg Message to display. + * + * @return void + */ + protected function notifyErrors($msg) + { + $cmd = $this->getBasicCommand(); + $cmd .= ' -i error'; + $cmd .= ' "PHP CodeSniffer: Error"'; + $cmd .= ' '.escapeshellarg(trim($msg)); + exec($cmd); + + }//end notifyErrors() + + + /** + * Generate and return the basic notify-send command string to execute. + * + * @return string Shell command with common parameters. + */ + protected function getBasicCommand() + { + $cmd = escapeshellcmd($this->path); + $cmd .= ' --category dev.validate'; + $cmd .= ' -h int:transient:1'; + $cmd .= ' -t '.(int) $this->timeout; + if (version_compare($this->version, '0.7.3', '>=') === true) { + $cmd .= ' -a phpcs'; + } + + return $cmd; + + }//end getBasicCommand() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Source.php b/codesniffer/CodeSniffer/Reports/Source.php new file mode 100644 index 000000000..9eaad3824 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Source.php @@ -0,0 +1,235 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Source report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Source implements PHP_CodeSniffer_Report +{ + + /** + * A cache of source stats collected during the run. + * + * @var array + */ + private $_sourceCache = array(); + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $source = $error['source']; + if (isset($this->_sourceCache[$source]) === false) { + $this->_sourceCache[$source] = 1; + } else { + $this->_sourceCache[$source]++; + } + } + } + } + + return true; + + }//end generateFileReport() + + + /** + * Prints the source of all errors and warnings. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + $width = max($width, 70); + + if (empty($this->_sourceCache) === true) { + // Nothing to show. + return; + } + + asort($this->_sourceCache); + $this->_sourceCache = array_reverse($this->_sourceCache); + + echo PHP_EOL.'PHP CODE SNIFFER VIOLATION SOURCE SUMMARY'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + if ($showSources === true) { + echo 'SOURCE'.str_repeat(' ', ($width - 11)).'COUNT'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + } else { + echo 'STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 40)).'COUNT'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + } + + foreach ($this->_sourceCache as $source => $count) { + if ($showSources === true) { + echo $source.str_repeat(' ', ($width - 5 - strlen($source))); + } else { + $parts = explode('.', $source); + + if (strlen($parts[0]) > 8) { + $parts[0] = substr($parts[0], 0, ((strlen($parts[0]) - 8) * -1)); + } + + echo $parts[0].str_repeat(' ', (10 - strlen($parts[0]))); + + $category = $this->makeFriendlyName($parts[1]); + if (strlen($category) > 18) { + $category = substr($category, 0, ((strlen($category) - 18) * -1)); + } + + echo $category.str_repeat(' ', (20 - strlen($category))); + + $sniff = $this->makeFriendlyName($parts[2]); + if (isset($parts[3]) === true) { + $name = $this->makeFriendlyName($parts[3]); + $name[0] = strtolower($name[0]); + $sniff .= ' '.$name; + } + + if (strlen($sniff) > ($width - 37)) { + $sniff = substr($sniff, 0, ($width - 37 - strlen($sniff))); + } + + echo $sniff.str_repeat(' ', ($width - 35 - strlen($sniff))); + }//end if + + echo $count.PHP_EOL; + }//end foreach + + echo str_repeat('-', $width).PHP_EOL; + echo 'A TOTAL OF '.($totalErrors + $totalWarnings).' SNIFF VIOLATION(S) '; + echo 'WERE FOUND IN '.count($this->_sourceCache).' SOURCE(S)'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL.PHP_EOL; + + if ($toScreen === true + && PHP_CODESNIFFER_INTERACTIVE === false + && class_exists('PHP_Timer', false) === true + ) { + echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; + } + + }//end generate() + + + /** + * Converts a camel caps name into a readable string. + * + * @param string $name The camel caps name to convert. + * + * @return string + */ + public function makeFriendlyName($name) + { + $friendlyName = ''; + $length = strlen($name); + + $lastWasUpper = false; + $lastWasNumeric = false; + for ($i = 0; $i < $length; $i++) { + if (is_numeric($name[$i]) === true) { + if ($lastWasNumeric === false) { + $friendlyName .= ' '; + } + + $lastWasUpper = false; + $lastWasNumeric = true; + } else { + $lastWasNumeric = false; + + $char = strtolower($name[$i]); + if ($char === $name[$i]) { + // Lowercase. + $lastWasUpper = false; + } else { + // Uppercase. + if ($lastWasUpper === false) { + $friendlyName .= ' '; + $next = $name[($i + 1)]; + if (strtolower($next) === $next) { + // Next char is lowercase so it is a word boundary. + $name[$i] = strtolower($name[$i]); + } + } + + $lastWasUpper = true; + } + }//end if + + $friendlyName .= $name[$i]; + }//end for + + $friendlyName = trim($friendlyName); + $friendlyName[0] = strtoupper($friendlyName[0]); + + return $friendlyName; + + }//end makeFriendlyName() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Summary.php b/codesniffer/CodeSniffer/Reports/Summary.php new file mode 100644 index 000000000..c928a7016 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Summary.php @@ -0,0 +1,131 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Summary report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Summary implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * If verbose output is enabled, results are shown for all files, even if + * they have no errors or warnings. If verbose output is disabled, we only + * show files that have at least one warning or error. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + if (PHP_CODESNIFFER_VERBOSITY === 0 + && $report['errors'] === 0 + && $report['warnings'] === 0 + ) { + // Nothing to print. + return false; + } + + $width = max($width, 70); + $file = $report['filename']; + + $padding = ($width - 18 - strlen($file)); + if ($padding < 0) { + $file = '...'.substr($file, (($padding * -1) + 3)); + $padding = 0; + } + + echo $file.str_repeat(' ', $padding).' '; + echo $report['errors']; + echo str_repeat(' ', (8 - strlen((string) $report['errors']))); + echo $report['warnings']; + echo PHP_EOL; + + return true; + + }//end generateFileReport() + + + /** + * Generates a summary of errors and warnings for each file processed. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + echo PHP_EOL.'PHP CODE SNIFFER REPORT SUMMARY'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + echo 'FILE'.str_repeat(' ', ($width - 20)).'ERRORS WARNINGS'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + + echo $cachedData; + + echo str_repeat('-', $width).PHP_EOL; + echo 'A TOTAL OF '.$totalErrors.' ERROR(S) '; + echo 'AND '.$totalWarnings.' WARNING(S) '; + + echo 'WERE FOUND IN '.$totalFiles.' FILE(S)'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL.PHP_EOL; + + if ($toScreen === true + && PHP_CODESNIFFER_INTERACTIVE === false + && class_exists('PHP_Timer', false) === true + ) { + echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; + } + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Svnblame.php b/codesniffer/CodeSniffer/Reports/Svnblame.php new file mode 100644 index 000000000..de06c7e13 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Svnblame.php @@ -0,0 +1,100 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Svnblame report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Svnblame extends PHP_CodeSniffer_Reports_VersionControl +{ + + /** + * The name of the report we want in the output + * + * @var string + */ + protected $reportName = 'SVN'; + + + /** + * Extract the author from a blame line. + * + * @param string $line Line to parse. + * + * @return mixed string or false if impossible to recover. + */ + protected function getAuthor($line) + { + $blameParts = array(); + preg_match('|\s*([^\s]+)\s+([^\s]+)|', $line, $blameParts); + + if (isset($blameParts[2]) === false) { + return false; + } + + return $blameParts[2]; + + }//end getAuthor() + + + /** + * Gets the blame output. + * + * @param string $filename File to blame. + * + * @return array + */ + protected function getBlameContent($filename) + { + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'Getting SVN blame info for '.basename($filename).'... '; + } + + $command = 'svn blame "'.$filename.'"'; + $handle = popen($command, 'r'); + if ($handle === false) { + echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; + exit(2); + } + + $rawContent = stream_get_contents($handle); + fclose($handle); + + if (PHP_CODESNIFFER_VERBOSITY > 0) { + echo 'DONE'.PHP_EOL; + } + + $blames = explode("\n", $rawContent); + + return $blames; + + }//end getBlameContent() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/VersionControl.php b/codesniffer/CodeSniffer/Reports/VersionControl.php new file mode 100644 index 000000000..93565c7b2 --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/VersionControl.php @@ -0,0 +1,257 @@ + + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Version control report base class for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Ben Selby + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: 1.2.2 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_Reports_VersionControl implements PHP_CodeSniffer_Report +{ + + /** + * The name of the report we want in the output. + * + * @var string + */ + protected $reportName = 'VERSION CONTROL'; + + /** + * A cache of author stats collected during the run. + * + * @var array + */ + private $_authorCache = array(); + + /** + * A cache of blame stats collected during the run. + * + * @var array + */ + private $_praiseCache = array(); + + /** + * A cache of source stats collected during the run. + * + * @var array + */ + private $_sourceCache = array(); + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + $blames = $this->getBlameContent($report['filename']); + + foreach ($report['messages'] as $line => $lineErrors) { + $author = $this->getAuthor($blames[($line - 1)]); + if ($author === false) { + continue; + } + + if (isset($this->_authorCache[$author]) === false) { + $this->_authorCache[$author] = 0; + $this->_praiseCache[$author] = array( + 'good' => 0, + 'bad' => 0, + ); + } + + $this->_praiseCache[$author]['bad']++; + + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $this->_authorCache[$author]++; + + if ($showSources === true) { + $source = $error['source']; + if (isset($this->_sourceCache[$author][$source]) === false) { + $this->_sourceCache[$author][$source] = 1; + } else { + $this->_sourceCache[$author][$source]++; + } + } + } + } + + unset($blames[($line - 1)]); + }//end foreach + + // No go through and give the authors some credit for + // all the lines that do not have errors. + foreach ($blames as $line) { + $author = $this->getAuthor($line); + if (false === $author) { + continue; + } + + if (isset($this->_authorCache[$author]) === false) { + // This author doesn't have any errors. + if (PHP_CODESNIFFER_VERBOSITY === 0) { + continue; + } + + $this->_authorCache[$author] = 0; + $this->_praiseCache[$author] = array( + 'good' => 0, + 'bad' => 0, + ); + } + + $this->_praiseCache[$author]['good']++; + }//end foreach + + return true; + + }//end generateFileReport() + + + /** + * Prints the author of all errors and warnings, as given by "version control blame". + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + $errorsShown = ($totalErrors + $totalWarnings); + if ($errorsShown === 0) { + // Nothing to show. + return; + } + + $width = max($width, 70); + arsort($this->_authorCache); + + echo PHP_EOL.'PHP CODE SNIFFER '.$this->reportName.' BLAME SUMMARY'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + if ($showSources === true) { + echo 'AUTHOR SOURCE'.str_repeat(' ', ($width - 43)).'(Author %) (Overall %) COUNT'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + } else { + echo 'AUTHOR'.str_repeat(' ', ($width - 34)).'(Author %) (Overall %) COUNT'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL; + } + + foreach ($this->_authorCache as $author => $count) { + if ($this->_praiseCache[$author]['good'] === 0) { + $percent = 0; + } else { + $total = ($this->_praiseCache[$author]['bad'] + $this->_praiseCache[$author]['good']); + $percent = round(($this->_praiseCache[$author]['bad'] / $total * 100), 2); + } + + $overallPercent = '('.round((($count / $errorsShown) * 100), 2).')'; + $authorPercent = '('.$percent.')'; + $line = str_repeat(' ', (6 - strlen($count))).$count; + $line = str_repeat(' ', (12 - strlen($overallPercent))).$overallPercent.$line; + $line = str_repeat(' ', (11 - strlen($authorPercent))).$authorPercent.$line; + $line = $author.str_repeat(' ', ($width - strlen($author) - strlen($line))).$line; + + echo $line.PHP_EOL; + + if ($showSources === true && isset($this->_sourceCache[$author]) === true) { + $errors = $this->_sourceCache[$author]; + asort($errors); + $errors = array_reverse($errors); + + foreach ($errors as $source => $count) { + if ($source === 'count') { + continue; + } + + $line = str_repeat(' ', (5 - strlen($count))).$count; + echo ' '.$source.str_repeat(' ', ($width - 14 - strlen($source))).$line.PHP_EOL; + } + } + }//end foreach + + echo str_repeat('-', $width).PHP_EOL; + echo 'A TOTAL OF '.$errorsShown.' SNIFF VIOLATION(S) '; + echo 'WERE COMMITTED BY '.count($this->_authorCache).' AUTHOR(S)'.PHP_EOL; + echo str_repeat('-', $width).PHP_EOL.PHP_EOL; + + if ($toScreen === true + && PHP_CODESNIFFER_INTERACTIVE === false + && class_exists('PHP_Timer', false) === true + ) { + echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; + } + + }//end generate() + + + /** + * Extract the author from a blame line. + * + * @param string $line Line to parse. + * + * @return mixed string or false if impossible to recover. + */ + abstract protected function getAuthor($line); + + + /** + * Gets the blame output. + * + * @param string $filename File to blame. + * + * @return array + */ + abstract protected function getBlameContent($filename); + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Reports/Xml.php b/codesniffer/CodeSniffer/Reports/Xml.php new file mode 100644 index 000000000..ce0671afe --- /dev/null +++ b/codesniffer/CodeSniffer/Reports/Xml.php @@ -0,0 +1,129 @@ + + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Xml report for PHP_CodeSniffer. + * + * PHP version 5 + * + * @category PHP + * @package PHP_CodeSniffer + * @author Gabriele Santini + * @author Greg Sherwood + * @copyright 2009 SQLI + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Reports_Xml implements PHP_CodeSniffer_Report +{ + + + /** + * Generate a partial report for a single processed file. + * + * Function should return TRUE if it printed or stored data about the file + * and FALSE if it ignored the file. Returning TRUE indicates that the file and + * its data should be counted in the grand totals. + * + * @param array $report Prepared report data. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * + * @return boolean + */ + public function generateFileReport( + $report, + $showSources=false, + $width=80 + ) { + $out = new XMLWriter; + $out->openMemory(); + $out->setIndent(true); + + if ($report['errors'] === 0 && $report['warnings'] === 0) { + // Nothing to print. + return false; + } + + $out->startElement('file'); + $out->writeAttribute('name', $report['filename']); + $out->writeAttribute('errors', $report['errors']); + $out->writeAttribute('warnings', $report['warnings']); + + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $colErrors) { + foreach ($colErrors as $error) { + $error['type'] = strtolower($error['type']); + if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { + $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); + } + + $out->startElement($error['type']); + $out->writeAttribute('line', $line); + $out->writeAttribute('column', $column); + $out->writeAttribute('source', $error['source']); + $out->writeAttribute('severity', $error['severity']); + $out->text($error['message']); + $out->endElement(); + } + } + }//end foreach + + $out->endElement(); + echo $out->flush(); + + return true; + + }//end generateFileReport() + + + /** + * Prints all violations for processed files, in a proprietary XML format. + * + * @param string $cachedData Any partial report data that was returned from + * generateFileReport during the run. + * @param int $totalFiles Total number of files processed during the run. + * @param int $totalErrors Total number of errors found during the run. + * @param int $totalWarnings Total number of warnings found during the run. + * @param boolean $showSources Show sources? + * @param int $width Maximum allowed line width. + * @param boolean $toScreen Is the report being printed to screen? + * + * @return void + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $showSources=false, + $width=80, + $toScreen=true + ) { + $phpcs = new PHP_CodeSniffer; + echo ''.PHP_EOL; + echo ''.PHP_EOL; + echo $cachedData; + echo ''.PHP_EOL; + + }//end generate() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Sniff.php b/codesniffer/CodeSniffer/Sniff.php new file mode 100644 index 000000000..426f020b2 --- /dev/null +++ b/codesniffer/CodeSniffer/Sniff.php @@ -0,0 +1,93 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Represents a PHP_CodeSniffer sniff for sniffing coding standards. + * + * A sniff registers what token types it wishes to listen for, then, when + * PHP_CodeSniffer encounters that token, the sniff is invoked and passed + * information about where the token was found in the stack, and the + * PHP_CodeSniffer file in which the token was found. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +interface PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * An example return value for a sniff that wants to listen for whitespace + * and any comments would be: + * + * + * return array( + * T_WHITESPACE, + * T_DOC_COMMENT, + * T_COMMENT, + * ); + * + * + * @return array(int) + * @see Tokens.php + */ + public function register(); + + + /** + * Called when one of the token types that this sniff is listening for + * is found. + * + * The stackPtr variable indicates where in the stack the token was found. + * A sniff can acquire information this token, along with all the other + * tokens within the stack by first acquiring the token stack: + * + * + * $tokens = $phpcsFile->getTokens(); + * echo 'Encountered a '.$tokens[$stackPtr]['type'].' token'; + * echo 'token information: '; + * print_r($tokens[$stackPtr]); + * + * + * If the sniff discovers an anomaly in the code, they can raise an error + * by calling addError() on the PHP_CodeSniffer_File object, specifying an error + * message and the position of the offending token: + * + * + * $phpcsFile->addError('Encountered an error', $stackPtr); + * + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the + * token was found. + * @param int $stackPtr The position in the PHP_CodeSniffer + * file's token stack where the token + * was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr); + + +}//end interface + +?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php b/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php new file mode 100644 index 000000000..ef7ded90e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php @@ -0,0 +1,961 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_IncorrectPatternException', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_IncorrectPatternException not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Processes pattern strings and checks that the code conforms to the pattern. + * + * This test essentially checks that code is correctly formatted with whitespace. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_Standards_AbstractPatternSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * If true, comments will be ignored if they are found in the code. + * + * @var boolean + */ + public $ignoreComments = false; + + /** + * The current file being checked. + * + * @var string + */ + protected $currFile = ''; + + /** + * The parsed patterns array. + * + * @var array + */ + private $_parsedPatterns = array(); + + /** + * Tokens that this sniff wishes to process outside of the patterns. + * + * @var array(int) + * @see registerSupplementary() + * @see processSupplementary() + */ + private $_supplementaryTokens = array(); + + /** + * Positions in the stack where errors have occurred. + * + * @var array() + */ + private $_errorPos = array(); + + + /** + * Constructs a PHP_CodeSniffer_Standards_AbstractPatternSniff. + * + * @param boolean $ignoreComments If true, comments will be ignored. + */ + public function __construct($ignoreComments=null) + { + // This is here for backwards compatibility. + if ($ignoreComments !== null) { + $this->ignoreComments = $ignoreComments; + } + + $this->_supplementaryTokens = $this->registerSupplementary(); + + }//end __construct() + + + /** + * Registers the tokens to listen to. + * + * Classes extending AbstractPatternTest should implement the + * getPatterns() method to register the patterns they wish to test. + * + * @return array(int) + * @see process() + */ + public final function register() + { + $listenTypes = array(); + $patterns = $this->getPatterns(); + + foreach ($patterns as $pattern) { + $parsedPattern = $this->_parse($pattern); + + // Find a token position in the pattern that we can use + // for a listener token. + $pos = $this->_getListenerTokenPos($parsedPattern); + $tokenType = $parsedPattern[$pos]['token']; + $listenTypes[] = $tokenType; + + $patternArray = array( + 'listen_pos' => $pos, + 'pattern' => $parsedPattern, + 'pattern_code' => $pattern, + ); + + if (isset($this->_parsedPatterns[$tokenType]) === false) { + $this->_parsedPatterns[$tokenType] = array(); + } + + $this->_parsedPatterns[$tokenType][] = $patternArray; + + }//end foreach + + return array_unique(array_merge($listenTypes, $this->_supplementaryTokens)); + + }//end register() + + + /** + * Returns the token types that the specified pattern is checking for. + * + * Returned array is in the format: + * + * array( + * T_WHITESPACE => 0, // 0 is the position where the T_WHITESPACE token + * // should occur in the pattern. + * ); + * + * + * @param array $pattern The parsed pattern to find the acquire the token + * types from. + * + * @return array(int => int) + */ + private function _getPatternTokenTypes($pattern) + { + $tokenTypes = array(); + foreach ($pattern as $pos => $patternInfo) { + if ($patternInfo['type'] === 'token') { + if (isset($tokenTypes[$patternInfo['token']]) === false) { + $tokenTypes[$patternInfo['token']] = $pos; + } + } + } + + return $tokenTypes; + + }//end _getPatternTokenTypes() + + + /** + * Returns the position in the pattern that this test should register as + * a listener for the pattern. + * + * @param array $pattern The pattern to acquire the listener for. + * + * @return int The postition in the pattern that this test should register + * as the listener. + * @throws PHP_CodeSniffer_Exception If we could not determine a token + * to listen for. + */ + private function _getListenerTokenPos($pattern) + { + $tokenTypes = $this->_getPatternTokenTypes($pattern); + $tokenCodes = array_keys($tokenTypes); + $token = PHP_CodeSniffer_Tokens::getHighestWeightedToken($tokenCodes); + + // If we could not get a token. + if ($token === false) { + $error = 'Could not determine a token to listen for'; + throw new PHP_CodeSniffer_Exception($error); + } + + return $tokenTypes[$token]; + + }//end _getListenerTokenPos() + + + /** + * Processes the test. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the + * token occured. + * @param int $stackPtr The postion in the tokens stack + * where the listening token type was + * found. + * + * @return void + * @see register() + */ + public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $file = $phpcsFile->getFilename(); + if ($this->currFile !== $file) { + // We have changed files, so clean up. + $this->_errorPos = array(); + $this->currFile = $file; + } + + $tokens = $phpcsFile->getTokens(); + + if (in_array($tokens[$stackPtr]['code'], $this->_supplementaryTokens) === true) { + $this->processSupplementary($phpcsFile, $stackPtr); + } + + $type = $tokens[$stackPtr]['code']; + + // If the type is not set, then it must have been a token registered + // with registerSupplementary(). + if (isset($this->_parsedPatterns[$type]) === false) { + return; + } + + $allErrors = array(); + + // Loop over each pattern that is listening to the current token type + // that we are processing. + foreach ($this->_parsedPatterns[$type] as $patternInfo) { + // If processPattern returns false, then the pattern that we are + // checking the code with must not be designed to check that code. + $errors = $this->processPattern($patternInfo, $phpcsFile, $stackPtr); + if ($errors === false) { + // The pattern didn't match. + continue; + } else if (empty($errors) === true) { + // The pattern matched, but there were no errors. + break; + } + + foreach ($errors as $stackPtr => $error) { + if (isset($this->_errorPos[$stackPtr]) === false) { + $this->_errorPos[$stackPtr] = true; + $allErrors[$stackPtr] = $error; + } + } + } + + foreach ($allErrors as $stackPtr => $error) { + $phpcsFile->addError($error, $stackPtr); + } + + }//end process() + + + /** + * Processes the pattern and verifies the code at $stackPtr. + * + * @param array $patternInfo Information about the pattern used + * for checking, which includes are + * parsed token representation of the + * pattern. + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the + * token occured. + * @param int $stackPtr The postion in the tokens stack where + * the listening token type was found. + * + * @return array(errors) + */ + protected function processPattern( + $patternInfo, + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $pattern = $patternInfo['pattern']; + $patternCode = $patternInfo['pattern_code']; + $errors = array(); + $found = ''; + + $ignoreTokens = array(T_WHITESPACE); + if ($this->ignoreComments === true) { + $ignoreTokens + = array_merge($ignoreTokens, PHP_CodeSniffer_Tokens::$commentTokens); + } + + $origStackPtr = $stackPtr; + $hasError = false; + + if ($patternInfo['listen_pos'] > 0) { + $stackPtr--; + + for ($i = ($patternInfo['listen_pos'] - 1); $i >= 0; $i--) { + if ($pattern[$i]['type'] === 'token') { + if ($pattern[$i]['token'] === T_WHITESPACE) { + if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { + $found = $tokens[$stackPtr]['content'].$found; + } + + // Only check the size of the whitespace if this is not + // the first token. We don't care about the size of + // leading whitespace, just that there is some. + if ($i !== 0) { + if ($tokens[$stackPtr]['content'] !== $pattern[$i]['value']) { + $hasError = true; + } + } + } else { + // Check to see if this important token is the same as the + // previous important token in the pattern. If it is not, + // then the pattern cannot be for this piece of code. + $prev = $phpcsFile->findPrevious( + $ignoreTokens, + $stackPtr, + null, + true + ); + + if ($prev === false + || $tokens[$prev]['code'] !== $pattern[$i]['token'] + ) { + return false; + } + + // If we skipped past some whitespace tokens, then add them + // to the found string. + $tokenContent = $phpcsFile->getTokensAsString( + ($prev + 1), + ($stackPtr - $prev - 1) + ); + + $found = $tokens[$prev]['content'].$tokenContent.$found; + + if (isset($pattern[($i - 1)]) === true + && $pattern[($i - 1)]['type'] === 'skip' + ) { + $stackPtr = $prev; + } else { + $stackPtr = ($prev - 1); + } + }//end if + } else if ($pattern[$i]['type'] === 'skip') { + // Skip to next piece of relevant code. + if ($pattern[$i]['to'] === 'parenthesis_closer') { + $to = 'parenthesis_opener'; + } else { + $to = 'scope_opener'; + } + + // Find the previous opener. + $next = $phpcsFile->findPrevious( + $ignoreTokens, + $stackPtr, + null, + true + ); + + if ($next === false || isset($tokens[$next][$to]) === false) { + // If there was not opener, then we must be + // using the wrong pattern. + return false; + } + + if ($to === 'parenthesis_opener') { + $found = '{'.$found; + } else { + $found = '('.$found; + } + + $found = '...'.$found; + + // Skip to the opening token. + $stackPtr = ($tokens[$next][$to] - 1); + } else if ($pattern[$i]['type'] === 'string') { + $found = 'abc'; + } else if ($pattern[$i]['type'] === 'newline') { + if ($this->ignoreComments === true + && in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true + ) { + $startComment = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$commentTokens, + ($stackPtr - 1), + null, + true + ); + + if ($tokens[$startComment]['line'] !== $tokens[($startComment + 1)]['line']) { + $startComment++; + } + + $tokenContent = $phpcsFile->getTokensAsString( + $startComment, + ($stackPtr - $startComment + 1) + ); + + $found = $tokenContent.$found; + $stackPtr = ($startComment - 1); + } + + if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { + if ($tokens[$stackPtr]['content'] !== $phpcsFile->eolChar) { + $found = $tokens[$stackPtr]['content'].$found; + + // This may just be an indent that comes after a newline + // so check the token before to make sure. If it is a newline, we + // can ignore the error here. + if (($tokens[($stackPtr - 1)]['content'] !== $phpcsFile->eolChar) + && ($this->ignoreComments === true && in_array($tokens[($stackPtr - 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === false) + ) { + $hasError = true; + } else { + $stackPtr--; + } + } else { + $found = 'EOL'.$found; + } + } else { + $found = $tokens[$stackPtr]['content'].$found; + $hasError = true; + } + + if ($hasError === false && $pattern[($i - 1)]['type'] !== 'newline') { + // Make sure they only have 1 newline. + $prev = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true); + if ($prev !== false && $tokens[$prev]['line'] !== $tokens[$stackPtr]['line']) { + $hasError = true; + } + } + }//end if + }//end for + }//end if + + $stackPtr = $origStackPtr; + $lastAddedStackPtr = null; + $patternLen = count($pattern); + + for ($i = $patternInfo['listen_pos']; $i < $patternLen; $i++) { + if ($pattern[$i]['type'] === 'token') { + if ($pattern[$i]['token'] === T_WHITESPACE) { + if ($this->ignoreComments === true) { + // If we are ignoring comments, check to see if this current + // token is a comment. If so skip it. + if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + continue; + } + + // If the next token is a comment, the we need to skip the + // current token as we should allow a space before a + // comment for readability. + if (in_array($tokens[($stackPtr + 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + continue; + } + } + + $tokenContent = ''; + if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { + if (isset($pattern[($i + 1)]) === false) { + // This is the last token in the pattern, so just compare + // the next token of content. + $tokenContent = $tokens[$stackPtr]['content']; + } else { + // Get all the whitespace to the next token. + $next = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$emptyTokens, + $stackPtr, + null, + true + ); + + $tokenContent = $phpcsFile->getTokensAsString( + $stackPtr, + ($next - $stackPtr) + ); + + $lastAddedStackPtr = $stackPtr; + $stackPtr = $next; + } + + if ($stackPtr !== $lastAddedStackPtr) { + $found .= $tokenContent; + } + } else { + if ($stackPtr !== $lastAddedStackPtr) { + $found .= $tokens[$stackPtr]['content']; + $lastAddedStackPtr = $stackPtr; + } + }//end if + + if (isset($pattern[($i + 1)]) === true + && $pattern[($i + 1)]['type'] === 'skip' + ) { + // The next token is a skip token, so we just need to make + // sure the whitespace we found has *at least* the + // whitespace required. + if (strpos($tokenContent, $pattern[$i]['value']) !== 0) { + $hasError = true; + } + } else { + if ($tokenContent !== $pattern[$i]['value']) { + $hasError = true; + } + } + } else { + // Check to see if this important token is the same as the + // next important token in the pattern. If it is not, then + // the pattern cannot be for this piece of code. + $next = $phpcsFile->findNext( + $ignoreTokens, + $stackPtr, + null, + true + ); + + if ($next === false + || $tokens[$next]['code'] !== $pattern[$i]['token'] + ) { + // The next important token did not match the pattern. + return false; + } + + if ($lastAddedStackPtr !== null) { + if (($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET + || $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) + && isset($tokens[$next]['scope_condition']) === true + && $tokens[$next]['scope_condition'] > $lastAddedStackPtr + ) { + // This is a brace, but the owner of it is after the current + // token, which means it does not belong to any token in + // our pattern. This means the pattern is not for us. + return false; + } + + if (($tokens[$next]['code'] === T_OPEN_PARENTHESIS + || $tokens[$next]['code'] === T_CLOSE_PARENTHESIS) + && isset($tokens[$next]['parenthesis_owner']) === true + && $tokens[$next]['parenthesis_owner'] > $lastAddedStackPtr + ) { + // This is a bracket, but the owner of it is after the current + // token, which means it does not belong to any token in + // our pattern. This means the pattern is not for us. + return false; + } + }//end if + + // If we skipped past some whitespace tokens, then add them + // to the found string. + if (($next - $stackPtr) > 0) { + $hasComment = false; + for ($j = $stackPtr; $j < $next; $j++) { + $found .= $tokens[$j]['content']; + if (in_array($tokens[$j]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + $hasComment = true; + } + } + + // If we are not ignoring comments, this additional + // whitespace or comment is not allowed. If we are + // ignoring comments, there needs to be at least one + // comment for this to be allowed. + if ($this->ignoreComments === false + || ($this->ignoreComments === true + && $hasComment === false) + ) { + $hasError = true; + } + + // Even when ignoring comments, we are not allowed to include + // newlines without the pattern specifying them, so + // everything should be on the same line. + if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { + $hasError = true; + } + }//end if + + if ($next !== $lastAddedStackPtr) { + $found .= $tokens[$next]['content']; + $lastAddedStackPtr = $next; + } + + if (isset($pattern[($i + 1)]) === true + && $pattern[($i + 1)]['type'] === 'skip' + ) { + $stackPtr = $next; + } else { + $stackPtr = ($next + 1); + } + }//end if + } else if ($pattern[$i]['type'] === 'skip') { + if ($pattern[$i]['to'] === 'unknown') { + $next = $phpcsFile->findNext( + $pattern[($i + 1)]['token'], + $stackPtr + ); + + if ($next === false) { + // Couldn't find the next token, sowe we must + // be using the wrong pattern. + return false; + } + + $found .= '...'; + $stackPtr = $next; + } else { + // Find the previous opener. + $next = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$blockOpeners, + $stackPtr + ); + + if ($next === false + || isset($tokens[$next][$pattern[$i]['to']]) === false + ) { + // If there was not opener, then we must + // be using the wrong pattern. + return false; + } + + $found .= '...'; + if ($pattern[$i]['to'] === 'parenthesis_closer') { + $found .= ')'; + } else { + $found .= '}'; + } + + // Skip to the closing token. + $stackPtr = ($tokens[$next][$pattern[$i]['to']] + 1); + }//end if + } else if ($pattern[$i]['type'] === 'string') { + if ($tokens[$stackPtr]['code'] !== T_STRING) { + $hasError = true; + } + + if ($stackPtr !== $lastAddedStackPtr) { + $found .= 'abc'; + $lastAddedStackPtr = $stackPtr; + } + + $stackPtr++; + } else if ($pattern[$i]['type'] === 'newline') { + // Find the next token that contains a newline character. + $newline = 0; + for ($j = $stackPtr; $j < $phpcsFile->numTokens; $j++) { + if (strpos($tokens[$j]['content'], $phpcsFile->eolChar) !== false) { + $newline = $j; + break; + } + } + + if ($newline === 0) { + // We didn't find a newline character in the rest of the file. + $next = ($phpcsFile->numTokens - 1); + $hasError = true; + } else { + if ($this->ignoreComments === false) { + // The newline character cannot be part of a comment. + if (in_array($tokens[$newline]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + $hasError = true; + } + } + + if ($newline === $stackPtr) { + $next = ($stackPtr + 1); + } else { + // Check that there were no significant tokens that we + // skipped over to find our newline character. + $next = $phpcsFile->findNext( + $ignoreTokens, + $stackPtr, + null, + true + ); + + if ($next < $newline) { + // We skipped a non-ignored token. + $hasError = true; + } else { + $next = ($newline + 1); + } + } + }//end if + + if ($stackPtr !== $lastAddedStackPtr) { + $found .= $phpcsFile->getTokensAsString( + $stackPtr, + ($next - $stackPtr) + ); + + $diff = ($next - $stackPtr); + $lastAddedStackPtr = ($next - 1); + } + + $stackPtr = $next; + }//end if + }//end for + + if ($hasError === true) { + $error = $this->prepareError($found, $patternCode); + $errors[$origStackPtr] = $error; + } + + return $errors; + + }//end processPattern() + + + /** + * Prepares an error for the specified patternCode. + * + * @param string $found The actual found string in the code. + * @param string $patternCode The expected pattern code. + * + * @return string The error message. + */ + protected function prepareError($found, $patternCode) + { + $found = str_replace("\r\n", '\n', $found); + $found = str_replace("\n", '\n', $found); + $found = str_replace("\r", '\n', $found); + $found = str_replace('EOL', '\n', $found); + $expected = str_replace('EOL', '\n', $patternCode); + + $error = "Expected \"$expected\"; found \"$found\""; + + return $error; + + }//end prepareError() + + + /** + * Returns the patterns that should be checked. + * + * @return array(string) + */ + protected abstract function getPatterns(); + + + /** + * Registers any supplementary tokens that this test might wish to process. + * + * A sniff may wish to register supplementary tests when it wishes to group + * an arbitary validation that cannot be performed using a pattern, with + * other pattern tests. + * + * @return array(int) + * @see processSupplementary() + */ + protected function registerSupplementary() + { + return array(); + + }//end registerSupplementary() + + + /** + * Processes any tokens registered with registerSupplementary(). + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where to + * process the skip. + * @param int $stackPtr The position in the tokens stack to + * process. + * + * @return void + * @see registerSupplementary() + */ + protected function processSupplementary( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + + }//end processSupplementary() + + + /** + * Parses a pattern string into an array of pattern steps. + * + * @param string $pattern The pattern to parse. + * + * @return array The parsed pattern array. + * @see _createSkipPattern() + * @see _createTokenPattern() + */ + private function _parse($pattern) + { + $patterns = array(); + $length = strlen($pattern); + $lastToken = 0; + $firstToken = 0; + + for ($i = 0; $i < $length; $i++) { + + $specialPattern = false; + $isLastChar = ($i === ($length - 1)); + $oldFirstToken = $firstToken; + + if (substr($pattern, $i, 3) === '...') { + // It's a skip pattern. The skip pattern requires the + // content of the token in the "from" position and the token + // to skip to. + $specialPattern = $this->_createSkipPattern($pattern, ($i - 1)); + $lastToken = ($i - $firstToken); + $firstToken = ($i + 3); + $i = ($i + 2); + + if ($specialPattern['to'] !== 'unknown') { + $firstToken++; + } + } else if (substr($pattern, $i, 3) === 'abc') { + $specialPattern = array('type' => 'string'); + $lastToken = ($i - $firstToken); + $firstToken = ($i + 3); + $i = ($i + 2); + } else if (substr($pattern, $i, 3) === 'EOL') { + $specialPattern = array('type' => 'newline'); + $lastToken = ($i - $firstToken); + $firstToken = ($i + 3); + $i = ($i + 2); + } + + if ($specialPattern !== false || $isLastChar === true) { + // If we are at the end of the string, don't worry about a limit. + if ($isLastChar === true) { + // Get the string from the end of the last skip pattern, if any, + // to the end of the pattern string. + $str = substr($pattern, $oldFirstToken); + } else { + // Get the string from the end of the last special pattern, + // if any, to the start of this special pattern. + if ($lastToken === 0) { + // Note that if the last special token was zero characters ago, + // there will be nothing to process so we can skip this bit. + // This happens if you have something like: EOL... in your pattern. + $str = ''; + } else { + $str = substr($pattern, $oldFirstToken, $lastToken); + } + } + + if ($str !== '') { + $tokenPatterns = $this->_createTokenPattern($str); + foreach ($tokenPatterns as $tokenPattern) { + $patterns[] = $tokenPattern; + } + } + + // Make sure we don't skip the last token. + if ($isLastChar === false && $i === ($length - 1)) { + $i--; + } + }//end if + + // Add the skip pattern *after* we have processed + // all the tokens from the end of the last skip pattern + // to the start of this skip pattern. + if ($specialPattern !== false) { + $patterns[] = $specialPattern; + } + }//end for + + return $patterns; + + }//end _parse() + + + /** + * Creates a skip pattern. + * + * @param string $pattern The pattern being parsed. + * @param string $from The token content that the skip pattern starts from. + * + * @return array The pattern step. + * @see _createTokenPattern() + * @see _parse() + */ + private function _createSkipPattern($pattern, $from) + { + $skip = array('type' => 'skip'); + + $nestedParenthesis = 0; + $nestedBraces = 0; + for ($start = $from; $start >= 0; $start--) { + switch ($pattern[$start]) { + case '(': + if ($nestedParenthesis === 0) { + $skip['to'] = 'parenthesis_closer'; + } + + $nestedParenthesis--; + break; + case '{': + if ($nestedBraces === 0) { + $skip['to'] = 'scope_closer'; + } + + $nestedBraces--; + break; + case '}': + $nestedBraces++; + break; + case ')': + $nestedParenthesis++; + break; + } + + if (isset($skip['to']) === true) { + break; + } + } + + if (isset($skip['to']) === false) { + $skip['to'] = 'unknown'; + } + + return $skip; + + }//end _createSkipPattern() + + + /** + * Creates a token pattern. + * + * @param string $str The tokens string that the pattern should match. + * + * @return array The pattern step. + * @see _createSkipPattern() + * @see _parse() + */ + private function _createTokenPattern($str) + { + // Don't add a space after the closing php tag as it will add a new + // whitespace token. + $tokens = token_get_all(''); + + // Remove the 'token', + 'token' => $patternInfo['code'], + 'value' => $patternInfo['content'], + ); + } + + return $patterns; + + }//end _createTokenPattern() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php b/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php new file mode 100644 index 000000000..b18f7583a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php @@ -0,0 +1,201 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * An AbstractScopeTest allows for tests that extend from this class to + * listen for tokens within a particular scope. + * + * Below is a test that listens to methods that exist only within classes: + * + * class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff + * { + * public function __construct() + * { + * parent::__construct(array(T_CLASS), array(T_FUNCTION)); + * } + * + * protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $) + * { + * $className = $phpcsFile->getDeclarationName($currScope); + * echo 'encountered a method within class '.$className; + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_Standards_AbstractScopeSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The token types that this test wishes to listen to within the scope. + * + * @var array + */ + private $_tokens = array(); + + /** + * The type of scope opener tokens that this test wishes to listen to. + * + * @var string + */ + private $_scopeTokens = array(); + + /** + * True if this test should fire on tokens outside of the scope. + * + * @var boolean + */ + private $_listenOutside = false; + + + /** + * Constructs a new AbstractScopeTest. + * + * @param array $scopeTokens The type of scope the test wishes to listen to. + * @param array $tokens The tokens that the test wishes to listen to + * within the scope. + * @param boolean $listenOutside If true this test will also alert the + * extending class when a token is found outside + * the scope, by calling the + * processTokenOutsideScope method. + * + * @see PHP_CodeSniffer.getValidScopeTokeners() + * @throws PHP_CodeSniffer_Exception If the specified tokens array is empty. + */ + public function __construct( + array $scopeTokens, + array $tokens, + $listenOutside=false + ) { + if (empty($scopeTokens) === true) { + $error = 'The scope tokens list cannot be empty'; + throw new PHP_CodeSniffer_Exception($error); + } + + if (empty($tokens) === true) { + $error = 'The tokens list cannot be empty'; + throw new PHP_CodeSniffer_Exception($error); + } + + $invalidScopeTokens = array_intersect($scopeTokens, $tokens); + if (empty($invalidScopeTokens) === false) { + $invalid = implode(', ', $invalidScopeTokens); + $error = "Scope tokens [$invalid] cant be in the tokens array"; + throw new PHP_CodeSniffer_Exception($error); + } + + $this->_listenOutside = $listenOutside; + $this->_scopeTokens = $scopeTokens; + $this->_tokens = $tokens; + + }//end __construct() + + + /** + * The method that is called to register the tokens this test wishes to + * listen to. + * + * DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register + * for the desired tokens and scope. + * + * @return array(int) + * @see __constructor() + */ + public final function register() + { + return $this->_tokens; + + }//end register() + + + /** + * Processes the tokens that this test is listening for. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position in the stack where this + * token was found. + * + * @return void + * @see processTokenWithinScope() + */ + public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $foundScope = false; + foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) { + if (in_array($code, $this->_scopeTokens) === true) { + $this->processTokenWithinScope($phpcsFile, $stackPtr, $scope); + $foundScope = true; + } + } + + if ($this->_listenOutside === true && $foundScope === false) { + $this->processTokenOutsideScope($phpcsFile, $stackPtr); + } + + }//end process() + + + /** + * Processes a token that is found within the scope that this test is + * listening to. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position in the stack where this + * token was found. + * @param int $currScope The position in the tokens array that + * opened the scope that this test is + * listening for. + * + * @return void + */ + protected abstract function processTokenWithinScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $currScope + ); + + + /** + * Processes a token that is found within the scope that this test is + * listening to. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position in the stack where this + * token was found. + * + * @return void + */ + protected function processTokenOutsideScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php b/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php new file mode 100644 index 000000000..75084534a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php @@ -0,0 +1,245 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * A class to find T_VARIABLE tokens. + * + * This class can distinguish between normal T_VARIABLE tokens, and those tokens + * that represent class members. If a class member is encountered, then then + * processMemberVar method is called so the extending class can process it. If + * the token is found to be a normal T_VARIABLE token, then processVariable is + * called. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +abstract class PHP_CodeSniffer_Standards_AbstractVariableSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * The end token of the current function that we are in. + * + * @var int + */ + private $_endFunction = -1; + + /** + * true if a function is currently open. + * + * @var boolean + */ + private $_functionOpen = false; + + /** + * The current PHP_CodeSniffer file that we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Constructs an AbstractVariableTest. + */ + public function __construct() + { + $scopes = array( + T_CLASS, + T_INTERFACE, + ); + + $listen = array( + T_FUNCTION, + T_VARIABLE, + T_DOUBLE_QUOTED_STRING, + T_HEREDOC, + ); + + parent::__construct($scopes, $listen, true); + + }//end __construct() + + + /** + * Processes the token in the specified PHP_CodeSniffer_File. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * @param array $currScope The current scope opener token. + * + * @return void + */ + protected final function processTokenWithinScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $currScope + ) { + if ($this->currentFile !== $phpcsFile) { + $this->currentFile = $phpcsFile; + $this->_functionOpen = false; + $this->_endFunction = -1; + } + + $tokens = $phpcsFile->getTokens(); + + if ($stackPtr > $this->_endFunction) { + $this->_functionOpen = false; + } + + if ($tokens[$stackPtr]['code'] === T_FUNCTION + && $this->_functionOpen === false + ) { + $this->_functionOpen = true; + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + + // If the function is abstract, or is in an interface, + // then set the end of the function to it's closing semicolon. + if ($methodProps['is_abstract'] === true + || $tokens[$currScope]['code'] === T_INTERFACE + ) { + $this->_endFunction + = $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr); + } else { + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + $error = 'Possible parse error: non-abstract method defined as abstract'; + $phpcsFile->addWarning($error, $stackPtr); + return; + } + + $this->_endFunction = $tokens[$stackPtr]['scope_closer']; + } + } + + if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING + || $tokens[$stackPtr]['code'] === T_HEREDOC + ) { + // Check to see if this string has a variable in it. + $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); + } + + return; + } + + if ($this->_functionOpen === true) { + if ($tokens[$stackPtr]['code'] === T_VARIABLE) { + $this->processVariable($phpcsFile, $stackPtr); + } + } else { + // What if we assign a member variable to another? + // ie. private $_count = $this->_otherCount + 1;. + $this->processMemberVar($phpcsFile, $stackPtr); + } + + }//end processTokenWithinScope() + + + /** + * Processes the token outside the scope in the file. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected final function processTokenOutsideScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + // These variables are not member vars. + if ($tokens[$stackPtr]['code'] === T_VARIABLE) { + $this->processVariable($phpcsFile, $stackPtr); + } else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING + || $tokens[$stackPtr]['code'] === T_HEREDOC + ) { + // Check to see if this string has a variable in it. + $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); + } + } + + }//end processTokenOutsideScope() + + + /** + * Called to process class member vars. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + abstract protected function processMemberVar( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ); + + + /** + * Called to process normal member vars. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + abstract protected function processVariable( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ); + + + /** + * Called to process variables found in double quoted strings or heredocs. + * + * Note that there may be more than one variable in the string, which will + * result only in one call for the string or one call per line for heredocs. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the double quoted + * string was found. + * + * @return void + */ + abstract protected function processVariableInString( + PHP_CodeSniffer_File + $phpcsFile, + $stackPtr + ); + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml new file mode 100644 index 000000000..4b0ec96d4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml @@ -0,0 +1,27 @@ + + + + + + + Foo +{ +} + ]]> + + + Foo +{ +} + +class Foo +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml new file mode 100644 index 000000000..2c6835d47 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + // do nothing +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml new file mode 100644 index 000000000..06f0b7a5b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml @@ -0,0 +1,23 @@ + + + + + + + $i = 0; $i < 10; $i++) { + echo "{$i}\n"; +} + ]]> + + + ;$test;) { + $test = doSomething(); +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml new file mode 100644 index 000000000..f40d94bb1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml @@ -0,0 +1,24 @@ + + + + + + + $end = count($foo); +for ($i = 0; $i < $end; $i++) { + echo $foo[$i]."\n"; +} + ]]> + + + count($foo); $i++) { + echo $foo[$i]."\n"; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml new file mode 100644 index 000000000..50f078288 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml @@ -0,0 +1,25 @@ + + + + + + + $i++) { + for ($j = 0; $j < 10; $j++) { + } +} + ]]> + + + $i++) { + for ($j = 0; $j < 10; $i++) { + } +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml new file mode 100644 index 000000000..b2eaabe79 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml @@ -0,0 +1,39 @@ + + + + + + + $test) { + $var = 1; +} + ]]> + + + true) { + $var = 1; +} + ]]> + + + + + $test) { + $var = 1; +} + ]]> + + + false) { + $var = 1; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml new file mode 100644 index 000000000..893674077 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml @@ -0,0 +1,29 @@ + + + + + + + + + + final function bar() + { + } +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml new file mode 100644 index 000000000..181dff4ee --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml @@ -0,0 +1,25 @@ + + + + + + + $a + $b + $c; +} + ]]> + + + $a + $b; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml new file mode 100644 index 000000000..ba8bd7e42 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml @@ -0,0 +1,32 @@ + + + + + + + $this->doSomethingElse(); + } +} + ]]> + + + parent::bar(); + } +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml new file mode 100644 index 000000000..451e5fb61 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Handle strange case +if ($test) { + $var = 1; +} + ]]> + + + FIXME: This needs to be fixed! +if ($test) { + $var = 1; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml new file mode 100644 index 000000000..c9c4fc061 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Handle strange case +if ($test) { + $var = 1; +} + ]]> + + + TODO: This needs to be fixed! +if ($test) { + $var = 1; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml new file mode 100644 index 000000000..06ae14b76 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml @@ -0,0 +1,22 @@ + + + + + + + { + $var = 1; +} + ]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml new file mode 100644 index 000000000..b57a97068 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml @@ -0,0 +1,19 @@ + + + + + + + %; } + ]]> + + + %; } + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml new file mode 100644 index 000000000..9df9aec48 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml @@ -0,0 +1,19 @@ + + + + + + + ]; + ]]> + + + ,]; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml new file mode 100644 index 000000000..7525e9e6b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml @@ -0,0 +1,19 @@ + + + + + + + var foo = 5; + ]]> + + + foo = 5; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml new file mode 100644 index 000000000..88591f925 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml new file mode 100644 index 000000000..aa757edc6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml new file mode 100644 index 000000000..227d5621a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml new file mode 100644 index 000000000..3fbf5024d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml @@ -0,0 +1,24 @@ + + + + + + + + + + some string here + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml new file mode 100644 index 000000000..db7d4cc32 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml new file mode 100644 index 000000000..31342e3c9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml new file mode 100644 index 000000000..a1be34cb0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml new file mode 100644 index 000000000..7b5857633 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml @@ -0,0 +1,29 @@ + + + + + + + class Foo +{ +} + ]]> + + + class Foo +{ +} + +class Bar +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml new file mode 100644 index 000000000..de975319a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml @@ -0,0 +1,29 @@ + + + + + + + interface Foo +{ +} + ]]> + + + interface Foo +{ +} + +interface Bar +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml new file mode 100644 index 000000000..f0d4490c3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml new file mode 100644 index 000000000..9369eebc1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml @@ -0,0 +1,56 @@ + + + + + + + = (1 + 2); +$veryLongVarName = 'string'; +$var = foo($bar, $baz, $quux); + ]]> + + + = (1 + 2); +$veryLongVarName = 'string'; +$var = foo($bar, $baz, $quux); + ]]> + + + + + + + + += 1; +$veryLongVarName = 1; + ]]> + + + += 1; +$veryLongVarName = 1; + ]]> + + + + + = 1; +$veryLongVarName -= 1; + ]]> + + + = 1; +$veryLongVarName -= 1; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml new file mode 100644 index 000000000..042e4f803 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + 1; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml new file mode 100644 index 000000000..75eba77cb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml @@ -0,0 +1,19 @@ + + + + + + + 1; + ]]> + + + 1; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml new file mode 100644 index 000000000..738998d43 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml @@ -0,0 +1,31 @@ + + + + + + + &$bar) +{ + $bar++; +} + +$baz = 1; +foo($baz); + ]]> + + + &$baz); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml new file mode 100644 index 000000000..9809844d8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml @@ -0,0 +1,39 @@ + + + + + + + $baz) +{ +} + ]]> + + + $baz) +{ +} + ]]> + + + + + = true) +{ +} + ]]> + + + =true) +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml new file mode 100644 index 000000000..414dc289e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml @@ -0,0 +1,24 @@ + + + + + + + { + ... +} + ]]> + + + { + ... +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml new file mode 100644 index 000000000..84c2bdd86 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml @@ -0,0 +1,24 @@ + + + + + + + { + ... +} + ]]> + + + { + ... +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml new file mode 100644 index 000000000..a928e7db1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml new file mode 100644 index 000000000..f66cd92c9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml new file mode 100644 index 000000000..f5345b712 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml @@ -0,0 +1,23 @@ + + + + + + + doSomething() +{ +} + ]]> + + + do_something() +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml new file mode 100644 index 000000000..9dfc175ff --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml @@ -0,0 +1,29 @@ + + + + + + + __construct() + { + } +} + ]]> + + + Foo() + { + } +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml new file mode 100644 index 000000000..6ef61b93c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml @@ -0,0 +1,29 @@ + + + + + + + FOO_CONSTANT', 'foo'); + +class FooClass +{ + const FOO_CONSTANT = 'foo'; +} + ]]> + + + Foo_Constant', 'foo'); + +class FooClass +{ + const foo_constant = 'foo'; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml new file mode 100644 index 000000000..df5a0eba4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml @@ -0,0 +1,22 @@ + + + + + + + + + + Beginning content + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml new file mode 100644 index 000000000..09afb2d75 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml @@ -0,0 +1,22 @@ + + + + + + + +echo 'Foo'; +?> + ]]> + + + +echo 'Foo'; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml new file mode 100644 index 000000000..33b803a75 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml @@ -0,0 +1,19 @@ + + + + + + + explode('a', $bar); + ]]> + + + split('a', $bar); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml new file mode 100644 index 000000000..8086ea271 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml @@ -0,0 +1,7 @@ + + + to delimit PHP code, not the shorthand. This is the most portable way to include PHP code on differing operating systems and setups. + ]]> + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml new file mode 100644 index 000000000..220e9a9b6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml @@ -0,0 +1,19 @@ + + + + + + + count($bar); + ]]> + + + sizeof($bar); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml new file mode 100644 index 000000000..ab607c54c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml @@ -0,0 +1,23 @@ + + + true, false and null constants must always be lowercase. + ]]> + + + + false || $var === null) { + $var = true; +} + ]]> + + + FALSE || $var === NULL) { + $var = TRUE; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml new file mode 100644 index 000000000..965742d94 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml @@ -0,0 +1,19 @@ + + + + + + + array(); + ]]> + + + Array(); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml new file mode 100644 index 000000000..6646f6747 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml @@ -0,0 +1,23 @@ + + + + + + + isset($foo) && $foo) { + echo "Hello\n"; +} + ]]> + + + @$foo) { + echo "Hello\n"; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml new file mode 100644 index 000000000..e74005ad1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml @@ -0,0 +1,23 @@ + + + + + + + PHP_SAPI === 'cli') { + echo "Hello, CLI user."; +} + ]]> + + + php_sapi_name() === 'cli') { + echo "Hello, CLI user."; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml new file mode 100644 index 000000000..26487347b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml @@ -0,0 +1,23 @@ + + + true, false and null constants must always be uppercase. + ]]> + + + + FALSE || $var === NULL) { + $var = TRUE; +} + ]]> + + + false || $var === null) { + $var = true; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml new file mode 100644 index 000000000..a4c9887b2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml new file mode 100644 index 000000000..f4f3e19cb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml new file mode 100644 index 000000000..2e399b34b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml new file mode 100644 index 000000000..7013ffd90 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml new file mode 100644 index 000000000..bdd36d498 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml @@ -0,0 +1,23 @@ + + + + + + + $var = 1; +} + ]]> + + + $var = 1; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php new file mode 100644 index 000000000..68d3f31f9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php @@ -0,0 +1,129 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reports errors if the same class or interface name is used in multiple files. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Classes_DuplicateClassNameSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * List of classes that have been found during checking. + * + * @var array + */ + public $foundClasses = array(); + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $namespace = ''; + $findTokens = array( + T_CLASS, + T_INTERFACE, + T_NAMESPACE, + T_CLOSE_TAG, + ); + + $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); + while ($stackPtr !== false) { + if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { + // We can stop here. The sniff will continue from the next open + // tag when PHPCS reaches that token, if there is one. + return; + } + + // Keep track of what namespace we are in. + if ($tokens[$stackPtr]['code'] === T_NAMESPACE) { + $nsEnd = $phpcsFile->findNext( + array( + T_NS_SEPARATOR, + T_STRING, + T_WHITESPACE, + ), + ($stackPtr + 1), + null, + true + ); + + $namespace = trim($phpcsFile->getTokensAsString(($stackPtr + 1), ($nsEnd - $stackPtr - 1))); + $stackPtr = $nsEnd; + } else { + $nameToken = $phpcsFile->findNext(T_STRING, $stackPtr); + $name = $tokens[$nameToken]['content']; + if ($namespace !== '') { + $name = $namespace.'\\'.$name; + } + + $compareName = strtolower($name); + if (isset($this->foundClasses[$compareName]) === true) { + $type = strtolower($tokens[$stackPtr]['content']); + $file = $this->foundClasses[$compareName]['file']; + $line = $this->foundClasses[$compareName]['line']; + $error = 'Duplicate %s name "%s" found; first defined in %s on line %s'; + $data = array( + $type, + $name, + $file, + $line, + ); + $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); + } else { + $this->foundClasses[$compareName] = array( + 'file' => $phpcsFile->getFilename(), + 'line' => $tokens[$stackPtr]['line'], + ); + } + } + + $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); + }//end while + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php new file mode 100644 index 000000000..340ec8b2d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php @@ -0,0 +1,128 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * This sniff class detected empty statement. + * + * This sniff implements the common algorithm for empty statement body detection. + * A body is considered as empty if it is completely empty or it only contains + * whitespace characters and|or comments. + * + * + * stmt { + * // foo + * } + * stmt (conditions) { + * // foo + * } + * + * + * Statements covered by this sniff are catch, do, else, + * elsif, for, foreach, if, switch, try + * and while. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_EmptyStatementSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * List of block tokens that this sniff covers. + * + * The key of this hash identifies the required token while the boolean + * value says mark an error or mark a warning. + * + * @var array + */ + protected $checkedTokens = array( + T_CATCH => false, + T_DO => true, + T_ELSE => true, + T_ELSEIF => true, + T_FOR => true, + T_FOREACH => true, + T_IF => true, + T_SWITCH => true, + T_TRY => true, + T_WHILE => true, + ); + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array_keys($this->checkedTokens); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip for-statements without body. + if (isset($token['scope_opener']) === false) { + return; + } + + $next = ++$token['scope_opener']; + $end = --$token['scope_closer']; + + $emptyBody = true; + for (; $next <= $end; ++$next) { + if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $emptyBody = false; + break; + } + } + + if ($emptyBody === true) { + // Get token identifier. + $name = $phpcsFile->getTokensAsString($stackPtr, 1); + $error = 'Empty %s statement detected'; + $data = array(strtoupper($name)); + if ($this->checkedTokens[$token['code']] === true) { + $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); + } else { + $phpcsFile->addWarning($error, $stackPtr, 'NotAllowedWarning', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php new file mode 100644 index 000000000..6ac4cb3ef --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php @@ -0,0 +1,104 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects for-loops that can be simplified to a while-loop. + * + * This rule is based on the PMD rule catalog. Detects for-loops that can be + * simplified as a while-loop. + * + * + * class Foo + * { + * public function bar($x) + * { + * for (;true;) true; // No Init or Update part, may as well be: while (true) + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_FOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip invalid statement. + if (isset($token['parenthesis_opener']) === false) { + return; + } + + $next = ++$token['parenthesis_opener']; + $end = --$token['parenthesis_closer']; + + $parts = array( + 0, + 0, + 0, + ); + $index = 0; + + for (; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + if ($code === T_SEMICOLON) { + ++$index; + } else if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + ++$parts[$index]; + } + } + + if ($parts[0] === 0 && $parts[2] === 0 && $parts[1] > 0) { + $error = 'This FOR loop can be simplified to a WHILE loop'; + $phpcsFile->addWarning($error, $stackPtr, 'CanSimplify'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php new file mode 100644 index 000000000..6ecfc63cb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php @@ -0,0 +1,113 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects for-loops that use a function call in the test expression. + * + * This rule is based on the PMD rule catalog. Detects for-loops that use a + * function call in the test expression. + * + * + * class Foo + * { + * public function bar($x) + * { + * $a = array(1, 2, 3, 4); + * for ($i = 0; $i < count($a); $i++) { + * $a[$i] *= $i; + * } + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_FOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip invalid statement. + if (isset($token['parenthesis_opener']) === false) { + return; + } + + $next = ++$token['parenthesis_opener']; + $end = --$token['parenthesis_closer']; + + $position = 0; + + for (; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + if ($code === T_SEMICOLON) { + ++$position; + } + + if ($position < 1) { + continue; + } else if ($position > 1) { + break; + } else if ($code !== T_VARIABLE && $code !== T_STRING) { + continue; + } + + // Find next non empty token, if it is a open curly brace we have a + // function call. + $index = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + + if ($tokens[$index]['code'] === T_OPEN_PARENTHESIS) { + $error = 'Avoid function calls in a FOR loop test part'; + $phpcsFile->addWarning($error, $stackPtr, 'NotAllowed'); + break; + } + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php new file mode 100644 index 000000000..6fadaefd7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php @@ -0,0 +1,148 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects incrementer jumbling in for loops. + * + * This rule is based on the PMD rule catalog. The jumbling incrementer sniff + * detects the usage of one and the same incrementer into an outer and an inner + * loop. Even it is intended this is confusing code. + * + * + * class Foo + * { + * public function bar($x) + * { + * for ($i = 0; $i < 10; $i++) + * { + * for ($k = 0; $k < 20; $i++) + * { + * echo 'Hello'; + * } + * } + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_FOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip for-loop without body. + if (isset($token['scope_opener']) === false) { + return; + } + + // Find incrementors for outer loop. + $outer = $this->findIncrementers($tokens, $token); + + // Skip if empty. + if (count($outer) === 0) { + return; + } + + // Find nested for loops. + $start = ++$token['scope_opener']; + $end = --$token['scope_closer']; + + for (; $start <= $end; ++$start) { + if ($tokens[$start]['code'] !== T_FOR) { + continue; + } + + $inner = $this->findIncrementers($tokens, $tokens[$start]); + $diff = array_intersect($outer, $inner); + + if (count($diff) !== 0) { + $error = 'Loop incrementor (%s) jumbling with inner loop'; + $data = array(join(', ', $diff)); + $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); + } + } + + }//end process() + + + /** + * Get all used variables in the incrementer part of a for statement. + * + * @param array(integer=>array) $tokens Array with all code sniffer tokens. + * @param array(string=>mixed) $token Current for loop token + * + * @return array(string) List of all found incrementer variables. + */ + protected function findIncrementers(array $tokens, array $token) + { + // Skip invalid statement. + if (isset($token['parenthesis_opener']) === false) { + return array(); + } + + $start = ++$token['parenthesis_opener']; + $end = --$token['parenthesis_closer']; + + $incrementers = array(); + $semicolons = 0; + for ($next = $start; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + if ($code === T_SEMICOLON) { + ++$semicolons; + } else if ($semicolons === 2 && $code === T_VARIABLE) { + $incrementers[] = $tokens[$next]['content']; + } + } + + return $incrementers; + + }//end findIncrementers() + + +}//end class + +?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php new file mode 100644 index 000000000..947a7f4fc --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php @@ -0,0 +1,106 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects unconditional if- and elseif-statements. + * + * This rule is based on the PMD rule catalog. The Unconditional If Statement + * sniff detects statement conditions that are only set to one of the constant + * values true or false + * + * + * class Foo + * { + * public function close() + * { + * if (true) + * { + * // ... + * } + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array( + T_IF, + T_ELSEIF, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip for-loop without body. + if (isset($token['parenthesis_opener']) === false) { + return; + } + + $next = ++$token['parenthesis_opener']; + $end = --$token['parenthesis_closer']; + + $goodCondition = false; + for (; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + + if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } else if ($code !== T_TRUE && $code !== T_FALSE) { + $goodCondition = true; + } + } + + if ($goodCondition === false) { + $error = 'Avoid IF statements that are always true or false'; + $phpcsFile->addWarning($error, $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php new file mode 100644 index 000000000..32e5c86ef --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php @@ -0,0 +1,98 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects unnecessary final modifiers inside of final classes. + * + * This rule is based on the PMD rule catalog. The Unnecessary Final Modifier + * sniff detects the use of the final modifier inside of a final class which + * is unnecessary. + * + * + * final class Foo + * { + * public final function bar() + * { + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_CLASS); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip for-statements without body. + if (isset($token['scope_opener']) === false) { + return; + } + + // Fetch previous token. + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + + // Skip for non final class. + if ($prev === false || $tokens[$prev]['code'] !== T_FINAL) { + return; + } + + $next = ++$token['scope_opener']; + $end = --$token['scope_closer']; + + for (; $next <= $end; ++$next) { + if ($tokens[$next]['code'] === T_FINAL) { + $error = 'Unnecessary FINAL modifier in FINAL class'; + $phpcsFile->addWarning($error, $next, 'Found'); + } + } + + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php new file mode 100644 index 000000000..15b9a41a2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php @@ -0,0 +1,187 @@ + + * @author Manuel Pichler + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks the for unused function parameters. + * + * This sniff checks that all function parameters are used in the function body. + * One exception is made for empty function bodies or function bodies that only + * contain comments. This could be useful for the classes that implement an + * interface that defines multiple methods but the implementation only needs some + * of them. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @author Greg Sherwood + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip broken function declarations. + if (isset($token['scope_opener']) === false || isset($token['parenthesis_opener']) === false) { + return; + } + + $params = array(); + foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { + $params[$param['name']] = $stackPtr; + } + + $next = ++$token['scope_opener']; + $end = --$token['scope_closer']; + + $foundContent = false; + + for (; $next <= $end; ++$next) { + $token = $tokens[$next]; + $code = $token['code']; + + // Ignorable tokens. + if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } + + if ($foundContent === false) { + // A throw statement as the first content indicates an interface method. + if ($code === T_THROW) { + return; + } + + // A return statement as the first content indicates an interface method. + if ($code === T_RETURN) { + $tmp = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + if ($tmp === false) { + return; + } + + // There is a return. + if ($tokens[$tmp]['code'] === T_SEMICOLON) { + return; + } + + $tmp = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($tmp + 1), null, true); + if ($tmp !== false && $tokens[$tmp]['code'] === T_SEMICOLON) { + // There is a return . + return; + } + }//end if + }//end if + + $foundContent = true; + + if ($code === T_VARIABLE && isset($params[$token['content']]) === true) { + unset($params[$token['content']]); + } else if ($code === T_DOLLAR) { + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); + if ($tokens[$nextToken]['code'] === T_OPEN_CURLY_BRACKET) { + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true); + if ($tokens[$nextToken]['code'] === T_STRING) { + $varContent = '$'.$tokens[$nextToken]['content']; + if (isset($params[$varContent]) === true) { + unset($params[$varContent]); + } + } + } + } else if ($code === T_DOUBLE_QUOTED_STRING + || $code === T_START_HEREDOC + || $code === T_START_NOWDOC + ) { + // Tokenize strings that can contain variables. + // Make sure the string is re-joined if it occurs over multiple lines. + $validTokens = array( + T_HEREDOC, + T_NOWDOC, + T_END_HEREDOC, + T_END_NOWDOC, + T_DOUBLE_QUOTED_STRING, + ); + $validTokens = array_merge($validTokens, PHP_CodeSniffer_Tokens::$emptyTokens); + + $content = $token['content']; + for ($i = ($next + 1); $i <= $end; $i++) { + if (in_array($tokens[$i]['code'], $validTokens) === true) { + $content .= $tokens[$i]['content']; + $next++; + } else { + break; + } + } + + $stringTokens = token_get_all(sprintf('', $content)); + foreach ($stringTokens as $stringPtr => $stringToken) { + if (is_array($stringToken) === false) { + continue; + } + + $varContent = ''; + if ($stringToken[0] === T_DOLLAR_OPEN_CURLY_BRACES) { + $varContent = '$'.$stringTokens[($stringPtr + 1)][1]; + } else if ($stringToken[0] === T_VARIABLE) { + $varContent = $stringToken[1]; + } + + if ($varContent !== '' && isset($params[$varContent]) === true) { + unset($params[$varContent]); + } + } + }//end if + }//end for + + if ($foundContent === true && count($params) > 0) { + foreach ($params as $paramName => $position) { + $error = 'The method parameter %s is never used'; + $data = array($paramName); + $phpcsFile->addWarning($error, $position, 'Found', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php new file mode 100644 index 000000000..59542f8b3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php @@ -0,0 +1,180 @@ + + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Detects unnecessary overridden methods that simply call their parent. + * + * This rule is based on the PMD rule catalog. The Useless Overriding Method + * sniff detects the use of methods that only call their parent classes's method + * with the same name and arguments. These methods are not required. + * + * + * class FooBar { + * public function __construct($a, $b) { + * parent::__construct($a, $b); + * } + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Manuel Pichler + * @copyright 2007-2008 Manuel Pichler. All rights reserved. + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return array(integer) + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Skip function without body. + if (isset($token['scope_opener']) === false) { + return; + } + + // Get function name. + $methodName = $phpcsFile->getDeclarationName($stackPtr); + + // Get all parameters from method signature. + $signature = array(); + foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { + $signature[] = $param['name']; + } + + $next = ++$token['scope_opener']; + $end = --$token['scope_closer']; + + for (; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + + if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } else if ($code === T_RETURN) { + continue; + } + + break; + } + + // Any token except 'parent' indicates correct code. + if ($tokens[$next]['code'] !== T_PARENT) { + return; + } + + // Find next non empty token index, should be double colon. + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + + // Skip for invalid code. + if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { + return; + } + + // Find next non empty token index, should be the function name. + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + + // Skip for invalid code or other method. + if ($next === false || $tokens[$next]['content'] !== $methodName) { + return; + } + + // Find next non empty token index, should be the open parenthesis. + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + + // Skip for invalid code. + if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $validParameterTypes = array( + T_VARIABLE, + T_LNUMBER, + T_CONSTANT_ENCAPSED_STRING, + ); + + $parameters = array(''); + $parenthesisCount = 1; + $count = count($tokens); + for (++$next; $next < $count; ++$next) { + $code = $tokens[$next]['code']; + + if ($code === T_OPEN_PARENTHESIS) { + ++$parenthesisCount; + } else if ($code === T_CLOSE_PARENTHESIS) { + --$parenthesisCount; + } else if ($parenthesisCount === 1 && $code === T_COMMA) { + $parameters[] = ''; + } else if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $parameters[(count($parameters) - 1)] .= $tokens[$next]['content']; + } + + if ($parenthesisCount === 0) { + break; + } + }//end for + + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); + if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { + return; + } + + // Check rest of the scope. + for (++$next; $next <= $end; ++$next) { + $code = $tokens[$next]['code']; + // Skip for any other content. + if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + return; + } + } + + $parameters = array_map('trim', $parameters); + $parameters = array_filter($parameters); + + if (count($parameters) === count($signature) && $parameters === $signature) { + $phpcsFile->addWarning('Useless method overriding detected', $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php new file mode 100644 index 000000000..e822ad34b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php @@ -0,0 +1,1498 @@ + + * @copyright 2011-2012 Sam Graham + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Holds details of a scope. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Sam Graham + * @copyright 2011-2012 Sam Graham + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class ScopeInfo { + public $owner; + public $opener; + public $closer; + public $variables = array(); + + function __construct($currScope) { + $this->owner = $currScope; + // TODO: extract opener/closer + } +} + +/** + * Holds details of a variable within a scope. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Sam Graham + * @copyright 2011 Sam Graham + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class VariableInfo { + public $name; + /** + * What scope the variable has: local, param, static, global, bound + */ + public $scopeType; + public $typeHint; + public $passByReference = false; + public $firstDeclared; + public $firstInitialized; + public $firstRead; + public $ignoreUnused = false; + + static $scopeTypeDescriptions = array( + 'local' => 'variable', + 'param' => 'function parameter', + 'static' => 'static variable', + 'global' => 'global variable', + 'bound' => 'bound variable', + ); + + function __construct($varName) { + $this->name = $varName; + } +} + +/** + * Checks the for undefined function variables. + * + * This sniff checks that all function variables + * are defined in the function body. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Sam Graham + * @copyright 2011 Sam Graham + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_CodeAnalysis_VariableAnalysisSniff implements PHP_CodeSniffer_Sniff +{ + /** + * The current phpcsFile being checked. + * + * @var phpcsFile + */ + protected $currentFile = null; + + /** + * A list of scopes encountered so far and the variables within them. + */ + private $_scopes = array(); + + /** + * A regexp for matching variable names in double-quoted strings. + */ + private $_double_quoted_variable_regexp = '|(? array(5), + 'addFunction' => array(3), + 'addTask' => array(3), + 'addTaskBackground' => array(3), + 'addTaskHigh' => array(3), + 'addTaskHighBackground' => array(3), + 'addTaskLow' => array(3), + 'addTaskLowBackground' => array(3), + 'addTaskStatus' => array(2), + 'apc_dec' => array(3), + 'apc_fetch' => array(2), + 'apc_inc' => array(3), + 'areConfusable' => array(3), + 'array_multisort' => array(1), + 'array_pop' => array(1), + 'array_push' => array(1), + 'array_replace' => array(1), + 'array_replace_recursive' => array(1, 2, 3, '...'), + 'array_shift' => array(1), + 'array_splice' => array(1), + 'array_unshift' => array(1), + 'array_walk' => array(1), + 'array_walk_recursive' => array(1), + 'arsort' => array(1), + 'asort' => array(1), + 'asort' => array(1), + 'bindColumn' => array(2), + 'bindParam' => array(2), + 'bind_param' => array(2, 3, '...'), + 'bind_result' => array(1, 2, '...'), + 'call_user_method' => array(2), + 'call_user_method_array' => array(2), + 'curl_multi_exec' => array(2), + 'curl_multi_info_read' => array(2), + 'current' => array(1), + 'dbplus_curr' => array(2), + 'dbplus_first' => array(2), + 'dbplus_info' => array(3), + 'dbplus_last' => array(2), + 'dbplus_next' => array(2), + 'dbplus_prev' => array(2), + 'dbplus_tremove' => array(3), + 'dns_get_record' => array(3, 4), + 'domxml_open_file' => array(3), + 'domxml_open_mem' => array(3), + 'each' => array(1), + 'enchant_dict_quick_check' => array(3), + 'end' => array(1), + 'ereg' => array(3), + 'eregi' => array(3), + 'exec' => array(2, 3), + 'exif_thumbnail' => array(1, 2, 3), + 'expect_expectl' => array(3), + 'extract' => array(1), + 'filter' => array(3), + 'flock' => array(2,3), + 'fscanf' => array(2, 3, '...'), + 'fsockopen' => array(3, 4), + 'ftp_alloc' => array(3), + 'get' => array(2, 3), + 'getByKey' => array(4), + 'getMulti' => array(2), + 'getMultiByKey' => array(3), + 'getimagesize' => array(2), + 'getmxrr' => array(2, 3), + 'gnupg_decryptverify' => array(3), + 'gnupg_verify' => array(4), + 'grapheme_extract' => array(5), + 'headers_sent' => array(1, 2), + 'http_build_url' => array(4), + 'http_get' => array(3), + 'http_head' => array(3), + 'http_negotiate_charset' => array(2), + 'http_negotiate_content_type' => array(2), + 'http_negotiate_language' => array(2), + 'http_post_data' => array(4), + 'http_post_fields' => array(5), + 'http_put_data' => array(4), + 'http_put_file' => array(4), + 'http_put_stream' => array(4), + 'http_request' => array(5), + 'isSuspicious' => array(2), + 'is_callable' => array(3), + 'key' => array(1), + 'krsort' => array(1), + 'ksort' => array(1), + 'ldap_get_option' => array(3), + 'ldap_parse_reference' => array(3), + 'ldap_parse_result' => array(3, 4, 5, 6), + 'localtime' => array(2), + 'm_completeauthorizations' => array(2), + 'maxdb_stmt_bind_param' => array(3, 4, '...'), + 'maxdb_stmt_bind_result' => array(2, 3, '...'), + 'mb_convert_variables' => array(3, 4, '...'), + 'mb_parse_str' => array(2), + 'mqseries_back' => array(2, 3), + 'mqseries_begin' => array(3, 4), + 'mqseries_close' => array(4, 5), + 'mqseries_cmit' => array(2, 3), + 'mqseries_conn' => array(2, 3, 4), + 'mqseries_connx' => array(2, 3, 4, 5), + 'mqseries_disc' => array(2, 3), + 'mqseries_get' => array(3, 4, 5, 6, 7, 8, 9), + 'mqseries_inq' => array(6, 8, 9, 10), + 'mqseries_open' => array(2, 4, 5, 6), + 'mqseries_put' => array(3, 4, 6, 7), + 'mqseries_put1' => array(2, 3, 4, 6, 7), + 'mqseries_set' => array(9, 10), + 'msg_receive' => array(3, 5, 8), + 'msg_send' => array(6), + 'mssql_bind' => array(3), + 'natcasesort' => array(1), + 'natsort' => array(1), + 'ncurses_color_content' => array(2, 3, 4), + 'ncurses_getmaxyx' => array(2, 3), + 'ncurses_getmouse' => array(1), + 'ncurses_getyx' => array(2, 3), + 'ncurses_instr' => array(1), + 'ncurses_mouse_trafo' => array(1, 2), + 'ncurses_mousemask' => array(2), + 'ncurses_pair_content' => array(2, 3), + 'ncurses_wmouse_trafo' => array(2, 3), + 'newt_button_bar' => array(1), + 'newt_form_run' => array(2), + 'newt_get_screen_size' => array(1, 2), + 'newt_grid_get_size' => array(2, 3), + 'newt_reflow_text' => array(5, 6), + 'newt_win_entries' => array(7), + 'newt_win_menu' => array(8), + 'next' => array(1), + 'oci_bind_array_by_name' => array(3), + 'oci_bind_by_name' => array(3), + 'oci_define_by_name' => array(3), + 'oci_fetch_all' => array(2), + 'ocifetchinto' => array(2), + 'odbc_fetch_into' => array(2), + 'openssl_csr_export' => array(2), + 'openssl_csr_new' => array(2), + 'openssl_open' => array(2), + 'openssl_pkcs12_export' => array(2), + 'openssl_pkcs12_read' => array(2), + 'openssl_pkey_export' => array(2), + 'openssl_private_decrypt' => array(2), + 'openssl_private_encrypt' => array(2), + 'openssl_public_decrypt' => array(2), + 'openssl_public_encrypt' => array(2), + 'openssl_random_pseudo_bytes' => array(2), + 'openssl_seal' => array(2, 3), + 'openssl_sign' => array(2), + 'openssl_x509_export' => array(2), + 'ovrimos_fetch_into' => array(2), + 'parse' => array(2,3), + 'parseCurrency' => array(2, 3), + 'parse_str' => array(2), + 'parsekit_compile_file' => array(2), + 'parsekit_compile_string' => array(2), + 'passthru' => array(2), + 'pcntl_sigprocmask' => array(3), + 'pcntl_sigtimedwait' => array(2), + 'pcntl_sigwaitinfo' => array(2), + 'pcntl_wait' => array(1), + 'pcntl_waitpid' => array(2), + 'pfsockopen' => array(3, 4), + 'php_check_syntax' => array(2), + 'poll' => array(1, 2, 3), + 'preg_filter' => array(5), + 'preg_match' => array(3), + 'preg_match_all' => array(3), + 'preg_replace' => array(5), + 'preg_replace_callback' => array(5), + 'prev' => array(1), + 'proc_open' => array(3), + 'query' => array(3), + 'queryExec' => array(2), + 'reset' => array(1), + 'rsort' => array(1), + 'settype' => array(1), + 'shuffle' => array(1), + 'similar_text' => array(3), + 'socket_create_pair' => array(4), + 'socket_getpeername' => array(2, 3), + 'socket_getsockname' => array(2, 3), + 'socket_recv' => array(2), + 'socket_recvfrom' => array(2, 5, 6), + 'socket_select' => array(1, 2, 3), + 'sort' => array(1), + 'sortWithSortKeys' => array(1), + 'sqlite_exec' => array(3), + 'sqlite_factory' => array(3), + 'sqlite_open' => array(3), + 'sqlite_popen' => array(3), + 'sqlite_query' => array(4), + 'sqlite_query' => array(4), + 'sqlite_unbuffered_query' => array(4), + 'sscanf' => array(3, '...'), + 'str_ireplace' => array(4), + 'str_replace' => array(4), + 'stream_open' => array(4), + 'stream_select' => array(1, 2, 3), + 'stream_socket_accept' => array(3), + 'stream_socket_client' => array(2, 3), + 'stream_socket_recvfrom' => array(4), + 'stream_socket_server' => array(2, 3), + 'system' => array(2), + 'uasort' => array(1), + 'uksort' => array(1), + 'unbufferedQuery' => array(3), + 'usort' => array(1), + 'wincache_ucache_dec' => array(3), + 'wincache_ucache_get' => array(2), + 'wincache_ucache_inc' => array(3), + 'xdiff_string_merge3' => array(4), + 'xdiff_string_patch' => array(4), + 'xml_parse_into_struct' => array(3, 4), + 'xml_set_object' => array(2), + 'xmlrpc_decode_request' => array(2), + 'xmlrpc_set_type' => array(1), + 'xslt_set_object' => array(2), + 'yaml_parse' => array(3), + 'yaml_parse_file' => array(3), + 'yaml_parse_url' => array(3), + 'yaz_ccl_parse' => array(3), + 'yaz_hits' => array(2), + 'yaz_scan_result' => array(2), + 'yaz_wait' => array(1), + ); + + /** + * Allows an install to extend the list of known pass-by-reference functions + * by defining generic.codeanalysis.variableanalysis.sitePassByRefFunctions. + */ + public $sitePassByRefFunctions = null; + + /** + * Allows exceptions in a catch block to be unused without provoking unused-var warning. + * Set generic.codeanalysis.variableanalysis.allowUnusedCaughtExceptions to a true value. + */ + public $allowUnusedCaughtExceptions = false; + + /** + * Allow function parameters to be unused without provoking unused-var warning. + * Set generic.codeanalysis.variableanalysis.allowUnusedFunctionParameters to a true value. + */ + public $allowUnusedFunctionParameters = false; + + /** + * A list of names of placeholder variables that you want to ignore from + * unused variable warnings, ie things like $junk. + */ + public $validUnusedVariableNames = null; + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() { + // Magic to modfy $_passByRefFunctions with any site-specific settings. + if (!empty($this->sitePassByRefFunctions)) { + foreach (preg_split('/\s+/', trim($this->sitePassByRefFunctions)) as $line) { + list ($function, $args) = explode(':', $line); + $this->_passByRefFunctions[$function] = explode(',', $args); + } + } + if (!empty($this->validUnusedVariableNames)) { + $this->validUnusedVariableNames = + preg_split('/\s+/', trim($this->validUnusedVariableNames)); + } + return array( + T_VARIABLE, + T_DOUBLE_QUOTED_STRING, + T_HEREDOC, + T_CLOSE_CURLY_BRACKET, + T_STRING, + ); + }//end register() + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + //if ($token['content'] == '$param') { + //echo "Found token on line {$token['line']}.\n" . print_r($token, true); + //} + + if ($this->currentFile !== $phpcsFile) { + $this->currentFile = $phpcsFile; + } + + if ($token['code'] === T_VARIABLE) { + return $this->processVariable($phpcsFile, $stackPtr); + } + if (($token['code'] === T_DOUBLE_QUOTED_STRING) || + ($token['code'] === T_HEREDOC)) { + return $this->processVariableInString($phpcsFile, $stackPtr); + } + if (($token['code'] === T_STRING) && ($token['content'] === 'compact')) { + return $this->processCompact($phpcsFile, $stackPtr); + } + if (($token['code'] === T_CLOSE_CURLY_BRACKET) && + isset($token['scope_condition'])) { + return $this->processScopeClose($phpcsFile, $token['scope_condition']); + } + } + + function normalizeVarName($varName) { + $varName = preg_replace('/[{}$]/', '', $varName); + return $varName; + } + + function scopeKey($currScope) { + if ($currScope === false) { + $currScope = 'file'; + } + return ($this->currentFile ? $this->currentFile->getFilename() : 'unknown file') . + ':' . $currScope; + } + + // Warning: this is an autovivifying get + function getScopeInfo($currScope, $autoCreate = true) { + $scopeKey = $this->scopeKey($currScope); + if (!isset($this->_scopes[$scopeKey])) { + if (!$autoCreate) { + return null; + } + $this->_scopes[$scopeKey] = new ScopeInfo($currScope); + } + return $this->_scopes[$scopeKey]; + } + + function getVariableInfo($varName, $currScope, $autoCreate = true) { + $scopeInfo = $this->getScopeInfo($currScope, $autoCreate); + if (!isset($scopeInfo->variables[$varName])) { + if (!$autoCreate) { + return null; + } + $scopeInfo->variables[$varName] = new VariableInfo($varName); + if ($this->validUnusedVariableNames && + in_array($varName, $this->validUnusedVariableNames)) { + $scopeInfo->variables[$varName]->ignoreUnused = true; + } + } + return $scopeInfo->variables[$varName]; + } + + function markVariableAssignment($varName, $stackPtr, $currScope) { + $varInfo = $this->getVariableInfo($varName, $currScope); + if (!isset($varInfo->scopeType)) { + $varInfo->scopeType = 'local'; + } + if (isset($varInfo->firstInitialized) && ($varInfo->firstInitialized <= $stackPtr)) { + return; + } + $varInfo->firstInitialized = $stackPtr; + } + + function markVariableDeclaration($varName, $scopeType, $typeHint, $stackPtr, $currScope, $permitMatchingRedeclaration = false) { + $varInfo = $this->getVariableInfo($varName, $currScope); + if (isset($varInfo->scopeType)) { + if (($permitMatchingRedeclaration === false) || + ($varInfo->scopeType !== $scopeType)) { + // Issue redeclaration/reuse warning + // Note: we check off scopeType not firstDeclared, this is so that + // we catch declarations that come after implicit declarations like + // use of a variable as a local. + $this->currentFile->addWarning( + "Redeclaration of %s %s as %s.", + $stackPtr, + 'VariableRedeclaration', + array( + VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], + "\${$varName}", + VariableInfo::$scopeTypeDescriptions[$scopeType], + ) + ); + } + } + $varInfo->scopeType = $scopeType; + if (isset($typeHint)) { + $varInfo->typeHint = $typeHint; + } + if (isset($varInfo->firstDeclared) && ($varInfo->firstDeclared <= $stackPtr)) { + return; + } + $varInfo->firstDeclared = $stackPtr; + } + + function markVariableRead($varName, $stackPtr, $currScope) { + $varInfo = $this->getVariableInfo($varName, $currScope); + if (isset($varInfo->firstRead) && ($varInfo->firstRead <= $stackPtr)) { + return; + } + $varInfo->firstRead = $stackPtr; + } + + function isVariableInitialized($varName, $stackPtr, $currScope) { + $varInfo = $this->getVariableInfo($varName, $currScope); + if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) { + return true; + } + return false; + } + + function isVariableUndefined($varName, $stackPtr, $currScope) { + $varInfo = $this->getVariableInfo($varName, $currScope, false); + if (isset($varInfo->firstDeclared) && $varInfo->firstDeclared <= $stackPtr) { + // TODO: do we want to check scopeType here? + return false; + } + if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) { + return false; + } + return true; + } + + function markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope) { + $this->markVariableRead($varName, $stackPtr, $currScope); + + if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) { + // We haven't been defined by this point. + $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr, + 'UndefinedVariable', + array("\${$varName}")); + } + return true; + } + + function findFunctionPrototype( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { + return false; + } + // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, + // so we look backwards from the opening bracket for the first thing that + // isn't a function name, reference sigil or whitespace and check if + // it's a function keyword. + $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND), + $openPtr - 1, null, true, null, true); + if (($functionPtr !== false) && + ($tokens[$functionPtr]['code'] === T_FUNCTION)) { + return $functionPtr; + } + return false; + } + + function findVariableScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + $in_class = false; + if (!empty($token['conditions'])) { + foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { + if (($scopeCode === T_FUNCTION) || ($scopeCode === T_CLOSURE)) { + return $scopePtr; + } + if (($scopeCode === T_CLASS) || ($scopeCode === T_INTERFACE)) { + $in_class = true; + } + } + } + + if (($scopePtr = $this->findFunctionPrototype($phpcsFile, $stackPtr)) !== false) { + return $scopePtr; + } + + if ($in_class) { + // Member var of a class, we don't care. + return false; + } + + // File scope, hmm, lets use first token of file? + return 0; + } + + function isNextThingAnAssign( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + + // Is the next non-whitespace an assignment? + $nextPtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true, null, true); + if ($nextPtr !== false) { + if ($tokens[$nextPtr]['code'] === T_EQUAL) { + return $nextPtr; + } + } + return false; + } + + function findWhereAssignExecuted( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + + // Write should be recorded at the next statement to ensure we treat + // the assign as happening after the RHS execution. + // eg: $var = $var + 1; -> RHS could still be undef. + // However, if we're within a bracketed expression, we take place at + // the closing bracket, if that's first. + // eg: echo (($var = 12) && ($var == 12)); + $semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1, null, false, null, true); + $closePtr = false; + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) !== false) { + if (isset($tokens[$openPtr]['parenthesis_closer'])) { + $closePtr = $tokens[$openPtr]['parenthesis_closer']; + } + } + + if ($semicolonPtr === false) { + if ($closePtr === false) { + // TODO: panic + return $stackPtr; + } + return $closePtr; + } + + if ($closePtr < $semicolonPtr) { + return $closePtr; + } + + return $semicolonPtr; + } + + function findContainingBrackets( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['nested_parenthesis'])) { + $openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']); + return end($openPtrs); + } + return false; + } + + + function findFunctionCall( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + + if ($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) { + // First non-whitespace thing and see if it's a T_STRING function name + $functionPtr = $phpcsFile->findPrevious(T_WHITESPACE, + $openPtr - 1, null, true, null, true); + if ($tokens[$functionPtr]['code'] === T_STRING) { + return $functionPtr; + } + } + return false; + } + + function findFunctionCallArguments( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + + // Slight hack: also allow this to find args for array constructor. + // TODO: probably should refactor into three functions: arg-finding and bracket-finding + if (($tokens[$stackPtr]['code'] !== T_STRING) && ($tokens[$stackPtr]['code'] !== T_ARRAY)) { + // Assume $stackPtr is something within the brackets, find our function call + if (($stackPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) { + return false; + } + } + + // $stackPtr is the function name, find our brackets after it + $openPtr = $phpcsFile->findNext(T_WHITESPACE, + $stackPtr + 1, null, true, null, true); + if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) { + return false; + } + + if (!isset($tokens[$openPtr]['parenthesis_closer'])) { + return false; + } + $closePtr = $tokens[$openPtr]['parenthesis_closer']; + + $argPtrs = array(); + $lastPtr = $openPtr; + $lastArgComma = $openPtr; + while (($nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr)) !== false) { + if ($this->findContainingBrackets($phpcsFile, $nextPtr) == $openPtr) { + // Comma is at our level of brackets, it's an argument delimiter. + array_push($argPtrs, range($lastArgComma + 1, $nextPtr - 1)); + $lastArgComma = $nextPtr; + } + $lastPtr = $nextPtr; + } + array_push($argPtrs, range($lastArgComma + 1, $closePtr - 1)); + + return $argPtrs; + } + + protected function checkForFunctionPrototype( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a function or closure parameter? + // It would be nice to get the list of function parameters from watching for + // T_FUNCTION, but AbstractVariableSniff and AbstractScopeSniff define everything + // we need to do that as private or final, so we have to do it this hackish way. + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { + return false; + } + + // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, + // so we look backwards from the opening bracket for the first thing that + // isn't a function name, reference sigil or whitespace and check if + // it's a function keyword. + $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND), + $openPtr - 1, null, true, null, true); + if (($functionPtr !== false) && + (($tokens[$functionPtr]['code'] === T_FUNCTION) || + ($tokens[$functionPtr]['code'] === T_CLOSURE))) { + // TODO: typeHint + $this->markVariableDeclaration($varName, 'param', null, $stackPtr, $functionPtr); + // Are we pass-by-reference? + $referencePtr = $phpcsFile->findPrevious(T_WHITESPACE, + $stackPtr - 1, null, true, null, true); + if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) { + $varInfo = $this->getVariableInfo($varName, $functionPtr); + $varInfo->passByReference = true; + } + // Are we optional with a default? + if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) { + $this->markVariableAssignment($varName, $stackPtr, $functionPtr); + } + return true; + } + + // Is it a use keyword? Use is both a read and a define, fun! + if (($functionPtr !== false) && ($tokens[$functionPtr]['code'] === T_USE)) { + $this->markVariableRead($varName, $stackPtr, $currScope); + if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) { + // We haven't been defined by this point. + $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr, + 'UndefinedVariable', + array("\${$varName}")); + return true; + } + // $functionPtr is at the use, we need the function keyword for start of scope. + $functionPtr = $phpcsFile->findPrevious(T_CLOSURE, + $functionPtr - 1, $currScope + 1, false, null, true); + if ($functionPtr !== false) { + // TODO: typeHints in use? + $this->markVariableDeclaration($varName, 'bound', null, $stackPtr, $functionPtr); + $this->markVariableAssignment($varName, $stackPtr, $functionPtr); + return true; + } + } + return false; + } + + protected function checkForCatchBlock( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a catch block parameter? + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { + return false; + } + + // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, + // so we look backwards from the opening bracket for the first thing that + // isn't a function name, reference sigil or whitespace and check if + // it's a function keyword. + $catchPtr = $phpcsFile->findPrevious(T_WHITESPACE, + $openPtr - 1, null, true, null, true); + if (($catchPtr !== false) && + ($tokens[$catchPtr]['code'] === T_CATCH)) { + // Scope of the exception var is actually the function, not just the catch block. + // TODO: typeHint + $this->markVariableDeclaration($varName, 'local', null, $stackPtr, $currScope, true); + $this->markVariableAssignment($varName, $stackPtr, $currScope); + if ($this->allowUnusedCaughtExceptions) { + $varInfo = $this->getVariableInfo($varName, $currScope); + $varInfo->ignoreUnused = true; + } + return true; + } + return false; + } + + protected function checkForThisWithinClass( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we $this within a class? + if (($varName != 'this') || empty($token['conditions'])) { + return false; + } + + foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { + // $this within a closure is invalid + // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. + if ($tokens[$scopePtr]['code'] === T_CLOSURE) { + return false; + } + if ($scopeCode === T_CLASS) { + return true; + } + } + + return false; + } + + protected function checkForSuperGlobal( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a superglobal variable? + if (in_array($varName, array( + 'GLOBALS', + '_SERVER', + '_GET', + '_POST', + '_FILES', + '_COOKIE', + '_SESSION', + '_REQUEST', + '_ENV', + 'argv', + 'argc', + ))) { + return true; + } + + return false; + } + + protected function checkForStaticMember( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a static member? + $doubleColonPtr = $stackPtr - 1; + if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) { + return false; + } + $classNamePtr = $stackPtr - 2; + if (($tokens[$classNamePtr]['code'] !== T_STRING) && + ($tokens[$classNamePtr]['code'] !== T_SELF) && + ($tokens[$classNamePtr]['code'] !== T_STATIC)) { + return false; + } + + // Are we refering to self:: outside a class? + // TODO: not sure this is our business or should be some other sniff. + if (($tokens[$classNamePtr]['code'] === T_SELF) || + ($tokens[$classNamePtr]['code'] === T_STATIC)) { + if ($tokens[$classNamePtr]['code'] === T_SELF) { + $err_class = 'SelfOutsideClass'; + $err_desc = 'self::'; + } else { + $err_class = 'StaticOutsideClass'; + $err_desc = 'static::'; + } + if (!empty($token['conditions'])) { + foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { + // self within a closure is invalid + // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. + if ($tokens[$scopePtr]['code'] === T_CLOSURE) { + $phpcsFile->addError("Use of {$err_desc}%s inside closure.", $stackPtr, + $err_class, + array("\${$varName}")); + return true; + } + if ($scopeCode === T_CLASS) { + return true; + } + } + } + $phpcsFile->addError("Use of {$err_desc}%s outside class definition.", $stackPtr, + $err_class, + array("\${$varName}")); + return true; + } + + return true; + } + + protected function checkForAssignment( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Is the next non-whitespace an assignment? + if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $stackPtr)) === false) { + return false; + } + + // Plain ol' assignment. Simpl(ish). + if (($writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr)) === false) { + $writtenPtr = $stackPtr; // I dunno + } + $this->markVariableAssignment($varName, $writtenPtr, $currScope); + return true; + } + + protected function checkForListAssignment( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // OK, are we within a list (...) construct? + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { + return false; + } + + $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, $openPtr - 1, null, true, null, true); + if (($prevPtr === false) || ($tokens[$prevPtr]['code'] !== T_LIST)) { + return false; + } + + // OK, we're a list (...) construct... are we being assigned to? + $closePtr = $tokens[$openPtr]['parenthesis_closer']; + if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $closePtr)) === false) { + return false; + } + + // Yes, we're being assigned. + $writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr); + $this->markVariableAssignment($varName, $writtenPtr, $currScope); + return true; + } + + protected function checkForGlobalDeclaration( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a global declaration? + // Search backwards for first token that isn't whitespace, comma or variable. + $globalPtr = $phpcsFile->findPrevious( + array(T_WHITESPACE, T_VARIABLE, T_COMMA), + $stackPtr - 1, null, true, null, true); + if (($globalPtr === false) || ($tokens[$globalPtr]['code'] !== T_GLOBAL)) { + return false; + } + + // It's a global declaration. + $this->markVariableDeclaration($varName, 'global', null, $stackPtr, $currScope); + return true; + } + + protected function checkForStaticDeclaration( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a static declaration? + // Static declarations are a bit more complicated than globals, since they + // can contain assignments. The assignment is compile-time however so can + // only be constant values, which makes life manageable. + // + // Just to complicate matters further, late static binding constants + // take the form static::CONSTANT and are invalid within static variable + // assignments, but we don't want to accidentally match their use of the + // static keyword. + // + // Valid values are: + // number T_MINUS T_LNUMBER T_DNUMBER + // string T_CONSTANT_ENCAPSED_STRING + // heredoc T_START_HEREDOC T_HEREDOC T_END_HEREDOC + // nowdoc T_START_NOWDOC T_NOWDOC T_END_NOWDOC + // define T_STRING + // class constant T_STRING T_DOUBLE_COLON T_STRING + // Search backwards for first token that isn't whitespace, comma, variable, + // equals, or on the list of assignable constant values above. + $staticPtr = $phpcsFile->findPrevious( + array( + T_WHITESPACE, T_VARIABLE, T_COMMA, T_EQUAL, + T_MINUS, T_LNUMBER, T_DNUMBER, + T_CONSTANT_ENCAPSED_STRING, + T_STRING, + T_DOUBLE_COLON, + T_START_HEREDOC, T_HEREDOC, T_END_HEREDOC, + T_START_NOWDOC, T_NOWDOC, T_END_NOWDOC, + ), + $stackPtr - 1, null, true, null, true); + if (($staticPtr === false) || ($tokens[$staticPtr]['code'] !== T_STATIC)) { + //if ($varName == 'static4') { + // echo "Failing token:\n" . print_r($tokens[$staticPtr], true); + //} + return false; + } + + // Is it a late static binding static::? + // If so, this isn't the static keyword we're looking for, but since + // static:: isn't allowed in a compile-time constant, we also know + // we can't be part of a static declaration anyway, so there's no + // need to look any further. + $lateStaticBindingPtr = $phpcsFile->findNext(T_WHITESPACE, $staticPtr + 1, null, true, null, true); + if (($lateStaticBindingPtr !== false) && ($tokens[$lateStaticBindingPtr]['code'] === T_DOUBLE_COLON)) { + return false; + } + + // It's a static declaration. + $this->markVariableDeclaration($varName, 'static', null, $stackPtr, $currScope); + if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) { + $this->markVariableAssignment($varName, $stackPtr, $currScope); + } + return true; + } + + protected function checkForForeachLoopVar( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a foreach loopvar? + if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { + return false; + } + + // Is there an 'as' token between us and the opening bracket? + if ($phpcsFile->findPrevious(T_AS, $stackPtr - 1, $openPtr) === false) { + return false; + } + + $this->markVariableAssignment($varName, $stackPtr, $currScope); + return true; + } + + protected function checkForPassByReferenceFunctionCall( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we pass-by-reference to known pass-by-reference function? + if (($functionPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) { + return false; + } + + // Is our function a known pass-by-reference function? + $functionName = $tokens[$functionPtr]['content']; + if (!isset($this->_passByRefFunctions[$functionName])) { + return false; + } + + $refArgs = $this->_passByRefFunctions[$functionName]; + + if (($argPtrs = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) === false) { + return false; + } + + // We're within a function call arguments list, find which arg we are. + $argPos = false; + foreach ($argPtrs as $idx => $ptrs) { + if (in_array($stackPtr, $ptrs)) { + $argPos = $idx + 1; + break; + } + } + if ($argPos === false) { + return false; + } + if (!in_array($argPos, $refArgs)) { + // Our arg wasn't mentioned explicitly, are we after an elipsis catch-all? + if (($elipsis = array_search('...', $refArgs)) === false) { + return false; + } + if ($argPos < $refArgs[$elipsis - 1]) { + return false; + } + } + + // Our argument position matches that of a pass-by-ref argument, + // check that we're the only part of the argument expression. + foreach ($argPtrs[$argPos - 1] as $ptr) { + if ($ptr === $stackPtr) { + continue; + } + if ($tokens[$ptr]['code'] !== T_WHITESPACE) { + return false; + } + } + + // Just us, we can mark it as a write. + $this->markVariableAssignment($varName, $stackPtr, $currScope); + // It's a read as well for purposes of used-variables. + $this->markVariableRead($varName, $stackPtr, $currScope); + return true; + } + + protected function checkForSymbolicObjectProperty( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $varName, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // Are we a symbolic object property/function derefeference? + // Search backwards for first token that isn't whitespace, is it a "->" operator? + $objectOperatorPtr = $phpcsFile->findPrevious( + T_WHITESPACE, + $stackPtr - 1, null, true, null, true); + if (($objectOperatorPtr === false) || ($tokens[$objectOperatorPtr]['code'] !== T_OBJECT_OPERATOR)) { + return false; + } + + $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); + return true; + } + + /** + * Called to process class member vars. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processMemberVar( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + // TODO: don't care for now + } + + /** + * Called to process normal member vars. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + $varName = $this->normalizeVarName($token['content']); + if (($currScope = $this->findVariableScope($phpcsFile, $stackPtr)) === false) { + return; + } + + //static $dump_token = false; + //if ($varName == 'property') { + // $dump_token = true; + //} + //if ($dump_token) { + // echo "Found variable {$varName} on line {$token['line']} in scope {$currScope}.\n" . print_r($token, true); + // echo "Prev:\n" . print_r($tokens[$stackPtr - 1], true); + //} + + // Determine if variable is being assigned or read. + + // Read methods that preempt assignment: + // Are we a $object->$property type symbolic reference? + + // Possible assignment methods: + // Is a mandatory function/closure parameter + // Is an optional function/closure parameter with non-null value + // Is closure use declaration of a variable defined within containing scope + // catch (...) block start + // $this within a class (but not within a closure). + // $GLOBALS, $_REQUEST, etc superglobals. + // $var part of class::$var static member + // Assignment via = + // Assignment via list (...) = + // Declares as a global + // Declares as a static + // Assignment via foreach (... as ...) { } + // Pass-by-reference to known pass-by-reference function + + // Are we a $object->$property type symbolic reference? + if ($this->checkForSymbolicObjectProperty($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a function or closure parameter? + if ($this->checkForFunctionPrototype($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a catch parameter? + if ($this->checkForCatchBlock($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we $this within a class? + if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a $GLOBALS, $_REQUEST, etc superglobal? + if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // $var part of class::$var static member + if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Is the next non-whitespace an assignment? + if ($this->checkForAssignment($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // OK, are we within a list (...) = construct? + if ($this->checkForListAssignment($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a global declaration? + if ($this->checkForGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a static declaration? + if ($this->checkForStaticDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we a foreach loopvar? + if ($this->checkForForeachLoopVar($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // Are we pass-by-reference to known pass-by-reference function? + if ($this->checkForPassByReferenceFunctionCall($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + + // OK, we don't appear to be a write to the var, assume we're a read. + $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); + } + + /** + * Called to process variables found in double quoted strings. + * + * Note that there may be more than one variable in the string, which will + * result only in one call for the string. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the double quoted + * string was found. + * + * @return void + */ + protected function processVariableInString( + PHP_CodeSniffer_File + $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + if (!preg_match_all($this->_double_quoted_variable_regexp, $token['content'], $matches)) { + return; + } + + $currScope = $this->findVariableScope($phpcsFile, $stackPtr); + foreach ($matches[1] as $varName) { + $varName = $this->normalizeVarName($varName); + // Are we $this within a class? + if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) { + continue; + } + if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) { + continue; + } + $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); + } + } + + protected function processCompactArguments( + PHP_CodeSniffer_File + $phpcsFile, + $stackPtr, + $arguments, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + foreach ($arguments as $argumentPtrs) { + $argumentPtrs = array_values(array_filter($argumentPtrs, + function ($argumentPtr) use ($tokens) { + return $tokens[$argumentPtr]['code'] !== T_WHITESPACE; + })); + if (empty($argumentPtrs)) { + continue; + } + if (!isset($tokens[$argumentPtrs[0]])) { + continue; + } + $argument_first_token = $tokens[$argumentPtrs[0]]; + if ($argument_first_token['code'] === T_ARRAY) { + // It's an array argument, recurse. + if (($array_arguments = $this->findFunctionCallArguments($phpcsFile, $argumentPtrs[0])) !== false) { + $this->processCompactArguments($phpcsFile, $stackPtr, $array_arguments, $currScope); + } + continue; + } + if (count($argumentPtrs) > 1) { + // Complex argument, we can't handle it, ignore. + continue; + } + if ($argument_first_token['code'] === T_CONSTANT_ENCAPSED_STRING) { + // Single-quoted string literal, ie compact('whatever'). + // Substr is to strip the enclosing single-quotes. + $varName = substr($argument_first_token['content'], 1, -1); + $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope); + continue; + } + if ($argument_first_token['code'] === T_DOUBLE_QUOTED_STRING) { + // Double-quoted string literal. + if (preg_match($this->_double_quoted_variable_regexp, $argument_first_token['content'])) { + // Bail if the string needs variable expansion, that's runtime stuff. + continue; + } + // Substr is to strip the enclosing double-quotes. + $varName = substr($argument_first_token['content'], 1, -1); + $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope); + continue; + } + } + } + + /** + * Called to process variables named in a call to compact(). + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position where the call to compact() + * was found. + * + * @return void + */ + protected function processCompact( + PHP_CodeSniffer_File + $phpcsFile, + $stackPtr + ) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + $currScope = $this->findVariableScope($phpcsFile, $stackPtr); + + if (($arguments = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) !== false) { + $this->processCompactArguments($phpcsFile, $stackPtr, $arguments, $currScope); + } + } + + /** + * Called to process the end of a scope. + * + * Note that although triggered by the closing curly brace of the scope, $stackPtr is + * the scope conditional, not the closing curly brace. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this + * token was found. + * @param int $stackPtr The position of the scope conditional. + * + * @return void + */ + protected function processScopeClose( + PHP_CodeSniffer_File + $phpcsFile, + $stackPtr + ) { + $scopeInfo = $this->getScopeInfo($stackPtr, false); + if (is_null($scopeInfo)) { + return; + } + foreach ($scopeInfo->variables as $varInfo) { + if ($varInfo->ignoreUnused || isset($varInfo->firstRead)) { + continue; + } + if ($this->allowUnusedFunctionParameters && $varInfo->scopeType == 'param') { + continue; + } + if ($varInfo->passByReference && isset($varInfo->firstInitialized)) { + // If we're pass-by-reference then it's a common pattern to + // use the variable to return data to the caller, so any + // assignment also counts as "variable use" for the purposes + // of "unused variable" warnings. + continue; + } + if (isset($varInfo->firstDeclared)) { + $phpcsFile->addWarning( + "Unused %s %s.", + $varInfo->firstDeclared, + 'UnusedVariable', + array( + VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], + "\${$varInfo->name}", + ) + ); + } + if (isset($varInfo->firstInitialized)) { + $phpcsFile->addWarning( + "Unused %s %s.", + $varInfo->firstInitialized, + 'UnusedVariable', + array( + VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], + "\${$varInfo->name}", + ) + ); + } + } + } +}//end class + +?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php new file mode 100644 index 000000000..56058a591 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php @@ -0,0 +1,92 @@ + + * @author Sam Graham + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Commenting_FixmeSniff. + * + * Warns about FIXME comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Sam Graham + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Commenting_FixmeSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$commentTokens; + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + $matches = array(); + if (preg_match('|[^a-z]+fixme[^a-z]+(.*)|i', $content, $matches) !== 0) { + // Clear whitespace and some common characters not required at + // the end of a fixme message to make the error more informative. + $type = 'CommentFound'; + $fixmeMessage = trim($matches[1]); + $fixmeMessage = trim($fixmeMessage, '[]().'); + $error = 'Comment refers to a FIXME task'; + $data = array($fixmeMessage); + if ($fixmeMessage !== '') { + $type = 'TaskFound'; + $error .= ' "%s"'; + } + + $phpcsFile->addError($error, $stackPtr, $type, $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php new file mode 100644 index 000000000..9ecee9cab --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php @@ -0,0 +1,90 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Commenting_TodoSniff. + * + * Warns about TODO comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Commenting_TodoSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$commentTokens; + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + $matches = array(); + if (preg_match('|[^a-z]+todo[^a-z]+(.*)|i', $content, $matches) !== 0) { + // Clear whitespace and some common characters not required at + // the end of a to-do message to make the warning more informative. + $type = 'CommentFound'; + $todoMessage = trim($matches[1]); + $todoMessage = trim($todoMessage, '[]().'); + $error = 'Comment refers to a TODO task'; + $data = array($todoMessage); + if ($todoMessage !== '') { + $type = 'TaskFound'; + $error .= ' "%s"'; + } + + $phpcsFile->addWarning($error, $stackPtr, $type, $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php new file mode 100644 index 000000000..10d7a766d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php @@ -0,0 +1,120 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_ControlStructures_InlineControlStructureSniff. + * + * Verifies that inline control statements are not present. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_ControlStructures_InlineControlStructureSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = true; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_ELSE, + T_FOREACH, + T_WHILE, + T_DO, + T_SWITCH, + T_FOR, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + // Ignore the ELSE in ELSE IF. We'll process the IF part later. + if (($tokens[$stackPtr]['code'] === T_ELSE) && ($tokens[($stackPtr + 2)]['code'] === T_IF)) { + return; + } + + if ($tokens[$stackPtr]['code'] === T_WHILE) { + // This could be from a DO WHILE, which doesn't have an opening brace. + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { + $brace = $tokens[$lastContent]; + if (isset($brace['scope_condition']) === true) { + $condition = $tokens[$brace['scope_condition']]; + if ($condition['code'] === T_DO) { + return; + } + } + } + } + + // This is a control structure without an opening brace, + // so it is an inline statement. + if ($this->error === true) { + $phpcsFile->addError('Inline control structures are not allowed', $stackPtr, 'NotAllowed'); + } else { + $phpcsFile->addWarning('Inline control structures are discouraged', $stackPtr, 'Discouraged'); + } + + return; + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php new file mode 100644 index 000000000..6f4ad49e1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php @@ -0,0 +1,117 @@ + + * @copyright 2013 Roman Levishchenko + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Debug_CSSLintSniff. + * + * Runs csslint on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Roman Levishchenko + * @copyright 2013 Roman Levishchenko + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Debug_CSSLintSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + + $csslintPath = PHP_CodeSniffer::getConfigData('csslint_path'); + if ($csslintPath === null) { + return; + } + + $cmd = $csslintPath.' '.escapeshellarg($fileName); + exec($cmd, $output, $retval); + + if (is_array($output) === false) { + return; + } + + $tokens = $phpcsFile->getTokens(); + $count = count($output); + + for ($i = 0; $i < $count; $i++) { + $matches = array(); + $numMatches = preg_match( + '/(error|warning) at line (\d+)/', + $output[$i], + $matches + ); + + if ($numMatches === 0) { + continue; + } + + $line = (int) $matches[2]; + $message = 'csslint says: '.$output[($i + 1)]; + // 1-st line is message with error line and error code. + // 2-nd error message. + // 3-d wrong line in file. + // 4-th empty line. + $i += 4; + + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] === $line) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); + } + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php new file mode 100644 index 000000000..c675ce04b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php @@ -0,0 +1,139 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Debug_ClosureLinterSniff. + * + * Runs gjslint on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Debug_ClosureLinterSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of error codes that should show errors. + * + * All other error codes will show warnings. + * + * @var int + */ + public $errorCodes = array(); + + /** + * A list of error codes to ignore. + * + * @var int + */ + public $ignoreCodes = array(); + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + * @throws PHP_CodeSniffer_Exception If jslint.js could not be run + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + + $lintPath = PHP_CodeSniffer::getConfigData('gjslint_path'); + if ($lintPath === null) { + return; + } + + $cmd = "$lintPath --nosummary --notime --unix_mode \"$fileName\""; + $msg = exec($cmd, $output, $retval); + + if (is_array($output) === false) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + foreach ($output as $finding) { + $matches = array(); + $numMatches = preg_match('/^(.*):([0-9]+):\(.*?([0-9]+)\)(.*)$/', $finding, $matches); + if ($numMatches === 0) { + continue; + } + + // Skip error codes we are ignoring. + $code = $matches[3]; + if (in_array($code, $this->ignoreCodes) === true) { + continue; + } + + $line = (int) $matches[2]; + $error = trim($matches[4]); + + // Find the token at the start of the line. + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] === $line) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $message = 'gjslint says: (%s) %s'; + $data = array( + $code, + $error, + ); + if (in_array($code, $this->errorCodes) === true) { + $phpcsFile->addError($message, $lineToken, 'ExternalToolError', $data); + } else { + $phpcsFile->addWarning($message, $lineToken, 'ExternalTool', $data); + } + } + }//end foreach + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php new file mode 100644 index 000000000..b0213cb83 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php @@ -0,0 +1,109 @@ + + * @author Alexander Wei§ + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Debug_JSHintSniff. + * + * Runs jshint.js on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Alexander Wei§ + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Debug_JSHintSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + * @throws PHP_CodeSniffer_Exception If jshint.js could not be run + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + + $rhinoPath = PHP_CodeSniffer::getConfigData('rhino_path'); + $jshintPath = PHP_CodeSniffer::getConfigData('jshint_path'); + if ($rhinoPath === null || $jshintPath === null) { + return; + } + + $cmd = "$rhinoPath \"$jshintPath\" \"$fileName\""; + $msg = exec($cmd, $output, $retval); + + if (is_array($output) === true) { + $tokens = $phpcsFile->getTokens(); + + foreach ($output as $finding) { + $matches = array(); + $numMatches = preg_match('/^(.+)\(.+:([0-9]+).*:[0-9]+\)$/', $finding, $matches); + if ($numMatches === 0) { + continue; + } + + $line = (int) $matches[2]; + $message = 'jshint says: '.trim($matches[1]); + + // Find the token at the start of the line. + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] === $line) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); + } + }//end foreach + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php new file mode 100644 index 000000000..9dcbfcdb1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php @@ -0,0 +1,93 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_ByteOrderMarkSniff. + * + * A simple sniff for detecting BOMs that may corrupt application work. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Piotr Karas + * @author Greg Sherwood + * @copyright 2010-2011 mediaSELF Sp. z o.o. + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + * @see http://en.wikipedia.org/wiki/Byte_order_mark + */ +class Generic_Sniffs_Files_ByteOrderMarkSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * List of supported BOM definitions. + * + * Use encoding names as keys and hex BOM representations as values. + * + * @var array + */ + public $bomDefinitions = array( + 'UTF-8' => 'efbbbf', + 'UTF-16 (BE)' => 'feff', + 'UTF-16 (LE)' => 'fffe', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_INLINE_HTML); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) + { + // The BOM will be the very first token in the file. + if ($stackPtr !== 0) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + foreach ($this->bomDefinitions as $bomName => $expectedBomHex) { + $bomByteLength = (strlen($expectedBomHex) / 2); + $htmlBomHex = bin2hex(substr($tokens[$stackPtr]['content'], 0, $bomByteLength)); + if ($htmlBomHex === $expectedBomHex) { + $errorData = array($bomName); + $error = 'File contains %s byte order mark, which may corrupt your application'; + $phpcsFile->addError($error, $stackPtr, 'Found', $errorData); + break; + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php new file mode 100644 index 000000000..cc56746e5 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php @@ -0,0 +1,95 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_EndFileNewlineSniff. + * + * Ensures the file ends with a newline character. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_EndFileNewlineSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + // Skip to the end of the file. + $tokens = $phpcsFile->getTokens(); + $stackPtr = ($phpcsFile->numTokens - 1); + + if ($phpcsFile->tokenizerType === 'JS') { + $stackPtr--; + } else if ($phpcsFile->tokenizerType === 'CSS') { + $stackPtr -= 2; + } + + $eolCharLen = strlen($phpcsFile->eolChar); + $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); + if ($lastChars !== $phpcsFile->eolChar) { + $error = 'File must end with a newline character'; + $phpcsFile->addError($error, $stackPtr, 'NotFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php new file mode 100644 index 000000000..cbc4e7f23 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php @@ -0,0 +1,95 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_EndFileNoNewlineSniff. + * + * Ensures the file does not end with a newline character. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_EndFileNoNewlineSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + // Skip to the end of the file. + $tokens = $phpcsFile->getTokens(); + $stackPtr = ($phpcsFile->numTokens - 1); + + if ($phpcsFile->tokenizerType === 'JS') { + $stackPtr--; + } else if ($phpcsFile->tokenizerType === 'CSS') { + $stackPtr -= 2; + } + + $eolCharLen = strlen($phpcsFile->eolChar); + $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); + if ($lastChars === $phpcsFile->eolChar) { + $error = 'File must not end with a newline character'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php new file mode 100644 index 000000000..6886808e5 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php @@ -0,0 +1,74 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_InlineHTMLSniff. + * + * Ensures the whole file is PHP only, with no whitespace or inline HTML anywhere + * in the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_InlineHTMLSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // Make sure this is the first open tag. + $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($previousOpenTag !== false) { + return; + } + + $inline = $phpcsFile->findNext(T_INLINE_HTML, 0); + if ($inline === false) { + return; + } + + $error = 'PHP files must only contain PHP code'; + $phpcsFile->addError($error, $inline, 'Found'); + + }//end process() + + +}//end class + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php new file mode 100644 index 000000000..0fd4ad3e8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php @@ -0,0 +1,115 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_LineEndingsSniff. + * + * Checks that end of line characters are correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_LineEndingsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + /** + * The valid EOL character. + * + * @var string + */ + public $eolChar = '\n'; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $found = $phpcsFile->eolChar; + $found = str_replace("\n", '\n', $found); + $found = str_replace("\r", '\r', $found); + + if ($found !== $this->eolChar) { + // Check for single line files without an EOL. This is a very special + // case and the EOL char is set to \n when this happens. + if ($found === '\n') { + $tokens = $phpcsFile->getTokens(); + $lastToken = ($phpcsFile->numTokens - 1); + if ($tokens[$lastToken]['line'] === 1 + && $tokens[$lastToken]['content'] !== "\n" + ) { + return; + } + } + + $error = 'End of line character is invalid; expected "%s" but found "%s"'; + $expected = $this->eolChar; + $expected = str_replace("\n", '\n', $expected); + $expected = str_replace("\r", '\r', $expected); + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'InvalidEOLChar', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php new file mode 100644 index 000000000..7674d72ef --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php @@ -0,0 +1,160 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_LineLengthSniff. + * + * Checks all lines in the file, and throws warnings if they are over 80 + * characters in length and errors if they are over 100. Both these + * figures can be changed by extending this sniff in your own standard. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_LineLengthSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The limit that the length of a line should not exceed. + * + * @var int + */ + public $lineLimit = 80; + + /** + * The limit that the length of a line must not exceed. + * + * Set to zero (0) to disable. + * + * @var int + */ + public $absoluteLineLimit = 100; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is the first open tag. + $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($previousOpenTag !== false) { + return; + } + + $tokenCount = 0; + $currentLineContent = ''; + $currentLine = 1; + + $trim = (strlen($phpcsFile->eolChar) * -1); + for (; $tokenCount < $phpcsFile->numTokens; $tokenCount++) { + if ($tokens[$tokenCount]['line'] === $currentLine) { + $currentLineContent .= $tokens[$tokenCount]['content']; + } else { + $currentLineContent = substr($currentLineContent, 0, $trim); + $this->checkLineLength($phpcsFile, ($tokenCount - 1), $currentLineContent); + $currentLineContent = $tokens[$tokenCount]['content']; + $currentLine++; + } + } + + $currentLineContent = substr($currentLineContent, 0, $trim); + $this->checkLineLength($phpcsFile, ($tokenCount - 1), $currentLineContent); + + }//end process() + + + /** + * Checks if a line is too long. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The token at the end of the line. + * @param string $lineContent The content of the line. + * + * @return void + */ + protected function checkLineLength(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $lineContent) + { + // If the content is a CVS or SVN id in a version tag, or it is + // a license tag with a name and URL, or it is an SVN URL, there + // is nothing the developer can do to shorten the line, + // so don't throw errors. + $regex = '~@license|@version[^\$]+\$Id|\$(Head)?URL[:\$]~'; + if (preg_match($regex, $lineContent) !== 0) { + return; + } + + if (PHP_CODESNIFFER_ENCODING !== 'iso-8859-1') { + // Not using the default encoding, so take a bit more care. + $lineLength = iconv_strlen($lineContent, PHP_CODESNIFFER_ENCODING); + if ($lineLength === false) { + // String contained invalid characters, so revert to default. + $lineLength = strlen($lineContent); + } + } else { + $lineLength = strlen($lineContent); + } + + if ($this->absoluteLineLimit > 0 + && $lineLength > $this->absoluteLineLimit + ) { + $data = array( + $this->absoluteLineLimit, + $lineLength, + ); + + $error = 'Line exceeds maximum limit of %s characters; contains %s characters'; + $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); + } else if ($lineLength > $this->lineLimit) { + $data = array( + $this->lineLimit, + $lineLength, + ); + + $warning = 'Line exceeds %s characters; contains %s characters'; + $phpcsFile->addWarning($warning, $stackPtr, 'TooLong', $data); + } + + }//end checkLineLength() + + +}//end class + diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php new file mode 100644 index 000000000..4ec0f75fa --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php @@ -0,0 +1,76 @@ + + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks that all file names are lowercased. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Andy Grunwald + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_LowercasedFilenameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $fileName = basename($phpcsFile->getFilename()); + $lowercaseFileName = strtolower($fileName); + if ($fileName !== $lowercaseFileName) { + $data = array( + $fileName, + $lowercaseFileName, + ); + $error = 'Filename "%s" doesn\'t match the expected filename "%s"'; + $phpcsFile->addError($error, $stackPtr, 'NotFound', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php new file mode 100644 index 000000000..9f3ccfe7c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php @@ -0,0 +1,64 @@ + + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks that only one class is declared per file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Andy Grunwald + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_OneClassPerFileSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLASS); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $nextClass = $phpcsFile->findNext($this->register(), ($stackPtr + 1)); + if ($nextClass !== false) { + $error = 'Only one class is allowed in a file'; + $phpcsFile->addError($error, $nextClass, 'MultipleFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php new file mode 100644 index 000000000..dd151f1f1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php @@ -0,0 +1,64 @@ + + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks that only one interface is declared per file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Andy Grunwald + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Files_OneInterfacePerFileSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_INTERFACE); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $nextInterface = $phpcsFile->findNext($this->register(), ($stackPtr + 1)); + if ($nextInterface !== false) { + $error = 'Only one interface is allowed in a file'; + $phpcsFile->addError($error, $nextInterface, 'MultipleFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php new file mode 100644 index 000000000..f783abd3e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php @@ -0,0 +1,88 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff. + * + * Ensures each statement is on a line by itself. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_SEMICOLON); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prev = $phpcsFile->findPrevious(T_SEMICOLON, ($stackPtr - 1)); + if ($prev === false) { + return; + } + + // Ignore multiple statements in a FOR condition. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + foreach ($tokens[$stackPtr]['nested_parenthesis'] as $bracket) { + if (isset($tokens[$bracket]['parenthesis_owner']) === false) { + // Probably a closure sitting inside a function call. + continue; + } + + $owner = $tokens[$bracket]['parenthesis_owner']; + if ($tokens[$owner]['code'] === T_FOR) { + return; + } + } + } + + if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { + $error = 'Each PHP statement must be on a line by itself'; + $phpcsFile->addError($error, $stackPtr, 'SameLine'); + return; + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php new file mode 100644 index 000000000..a0b966c54 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php @@ -0,0 +1,304 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff. + * + * Checks alignment of assignments. If there are multiple adjacent assignments, + * it will check that the equals signs of each assignment are aligned. It will + * display a warning to advise that the signs should be aligned. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = false; + + /** + * The maximum amount of padding before the alignment is ignored. + * + * If the amount of padding required to align this assignment with the + * surrounding assignments exceeds this number, the assignment will be + * ignored and no errors or warnings will be thrown. + * + * @var int + */ + public $maxPadding = 1000; + + /** + * If true, multi-line assignments are not checked. + * + * @var int + */ + public $ignoreMultiLine = false; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$assignmentTokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore assignments used in a condition, like an IF or FOR. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + foreach ($tokens[$stackPtr]['nested_parenthesis'] as $start => $end) { + if (isset($tokens[$start]['parenthesis_owner']) === true) { + return; + } + } + } + + /* + By this stage, it is known that there is an assignment on this line. + We only want to process the block once we reach the last assignment, + so we need to determine if there are more to follow. + */ + + // The assignment may span over multiple lines, so look for the + // end of the assignment so we can check assignment blocks correctly. + $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + + $nextAssign = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$assignmentTokens, + ($lineEnd + 1) + ); + + if ($nextAssign !== false) { + $isAssign = true; + if ($tokens[$nextAssign]['line'] === ($tokens[$lineEnd]['line'] + 1)) { + // Assignment may be in the same block as this one. Just make sure + // it is not used in a condition, like an IF or FOR. + if (isset($tokens[$nextAssign]['nested_parenthesis']) === true) { + foreach ($tokens[$nextAssign]['nested_parenthesis'] as $start => $end) { + if (isset($tokens[$start]['parenthesis_owner']) === true) { + // Not an assignment. + $isAssign = false; + break; + } + } + } + + if ($isAssign === true) { + return; + } + } + } + + // Getting here means that this is the last in a block of statements. + $assignments = array(); + $assignments[] = $stackPtr; + $prevAssignment = $stackPtr; + $lastLine = $tokens[$stackPtr]['line']; + + while (($prevAssignment = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$assignmentTokens, ($prevAssignment - 1))) !== false) { + + // We are not interested in double arrows as they assign values inside + // arrays and loops and do not use the same indentation rules. + if ($tokens[$prevAssignment]['code'] === T_DOUBLE_ARROW) { + continue; + } + + // The assignment's end token must be on the line directly + // above the current one to be in the same assignment block. + $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($prevAssignment + 1)); + + // And the end token must actually belong to this assignment. + $nextOpener = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$scopeOpeners, + ($prevAssignment + 1) + ); + + if ($nextOpener !== false && $nextOpener < $lineEnd) { + break; + } + + if ($tokens[$lineEnd]['line'] !== ($lastLine - 1)) { + break; + } + + // Make sure it is not assigned inside a condition (eg. IF, FOR). + if (isset($tokens[$prevAssignment]['nested_parenthesis']) === true) { + foreach ($tokens[$prevAssignment]['nested_parenthesis'] as $start => $end) { + if (isset($tokens[$start]['parenthesis_owner']) === true) { + break(2); + } + } + } + + $assignments[] = $prevAssignment; + $lastLine = $tokens[$prevAssignment]['line']; + }//end while + + $assignmentData = array(); + $maxAssignmentLength = 0; + $maxVariableLength = 0; + + foreach ($assignments as $assignment) { + $prev = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($assignment - 1), + null, + true + ); + + $endColumn = $tokens[($prev + 1)]['column']; + + if ($maxVariableLength < $endColumn) { + $maxVariableLength = $endColumn; + } + + if ($maxAssignmentLength < strlen($tokens[$assignment]['content'])) { + $maxAssignmentLength = strlen($tokens[$assignment]['content']); + } + + $assignmentData[$assignment] + = array( + 'variable_length' => $endColumn, + 'assignment_length' => strlen($tokens[$assignment]['content']), + ); + }//end foreach + + foreach ($assignmentData as $assignment => $data) { + if ($data['assignment_length'] === $maxAssignmentLength) { + if ($data['variable_length'] === $maxVariableLength) { + // The assignment is the longest possible, so the column that + // everything has to align to is based on it. + $column = ($maxVariableLength + 1); + break; + } else { + // The assignment token is the longest out of all of the + // assignments, but the variable name is not, so the column + // the start at can go back more to cover the space + // between the variable name and the assignment operator. + $column = ($maxVariableLength - ($maxAssignmentLength - 1) + 1); + } + } + } + + // Determine the actual position that each equals sign should be in. + foreach ($assignments as $assignment) { + // Actual column takes into account the length of the assignment operator. + $actualColumn = ($column + $maxAssignmentLength - strlen($tokens[$assignment]['content'])); + if ($tokens[$assignment]['column'] !== $actualColumn) { + $prev = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($assignment - 1), + null, + true + ); + + $expected = ($actualColumn - $tokens[($prev + 1)]['column']); + + if ($tokens[$assignment]['line'] !== $tokens[$prev]['line']) { + // Instead of working out how many spaces there are + // across new lines, the error message becomes more + // generic below. + $found = null; + } else { + $found = ($tokens[$assignment]['column'] - $tokens[($prev + 1)]['column']); + } + + // If the expected number of spaces for alignment exceeds the + // maxPadding rule, we just check for a single space as no + // alignment is required. + if ($expected > $this->maxPadding) { + if ($found === 1) { + continue; + } else { + $expected = 1; + } + } + + // Skip multi-line assignments if required. + if ($found === null && $this->ignoreMultiLine === true) { + continue; + } + + $expected .= ($expected === 1) ? ' space' : ' spaces'; + if ($found === null) { + $found = 'a new line'; + } else { + $found .= ($found === 1) ? ' space' : ' spaces'; + } + + if (count($assignments) === 1) { + $type = 'Incorrect'; + $error = 'Equals sign not aligned correctly; expected %s but found %s'; + } else { + $type = 'NotSame'; + $error = 'Equals sign not aligned with surrounding assignments; expected %s but found %s'; + } + + $errorData = array( + $expected, + $found, + ); + + if ($this->error === true) { + $phpcsFile->addError($error, $assignment, $type, $errorData); + } else { + $phpcsFile->addWarning($error, $assignment, $type.'Warning', $errorData); + } + }//end if + }//end foreach + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php new file mode 100644 index 000000000..0feb273e3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php @@ -0,0 +1,69 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Formatting_NoSpaceAfterCastSniff. + * + * Ensures there is no space after cast tokens. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Formatting_NoSpaceAfterCastSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$castTokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { + $error = 'A cast statement must not be followed by a space'; + $phpcsFile->addError($error, $stackPtr, 'SpaceFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php new file mode 100644 index 000000000..d8b37a817 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php @@ -0,0 +1,75 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Formatting_SpaceAfterCastSniff. + * + * Ensures there is a single space after cast tokens. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Formatting_SpaceAfterCastSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$castTokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $error = 'A cast statement must be followed by a single space'; + $phpcsFile->addError($error, $stackPtr, 'NoSpace'); + return; + } + + if ($tokens[($stackPtr + 1)]['content'] !== ' ') { + $error = 'A cast statement must be followed by a single space'; + $phpcsFile->addError($error, $stackPtr, 'TooMuchSpace'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php new file mode 100644 index 000000000..72aeb5380 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php @@ -0,0 +1,151 @@ + + * @copyright 2009 Florian Grandel + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Functions_CallTimePassByReferenceSniff. + * + * Ensures that variables are not passed by reference when calling a function. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Florian Grandel + * @copyright 2009 Florian Grandel + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Functions_CallTimePassByReferenceSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_STRING, + T_VARIABLE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Skip tokens that are the names of functions or classes + // within their definitions. For example: function myFunction... + // "myFunction" is T_STRING but we should skip because it is not a + // function or method *call*. + $functionName = $stackPtr; + $findTokens = array_merge( + PHP_CodeSniffer_Tokens::$emptyTokens, + array(T_BITWISE_AND) + ); + + $functionKeyword = $phpcsFile->findPrevious( + $findTokens, + ($stackPtr - 1), + null, + true + ); + + if ($tokens[$functionKeyword]['code'] === T_FUNCTION + || $tokens[$functionKeyword]['code'] === T_CLASS + ) { + return; + } + + // If the next non-whitespace token after the function or method call + // is not an opening parenthesis then it cant really be a *call*. + $openBracket = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($functionName + 1), + null, + true + ); + + if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + $nextSeparator = $openBracket; + while (($nextSeparator = $phpcsFile->findNext(T_VARIABLE, ($nextSeparator + 1), $closeBracket)) !== false) { + // Make sure the variable belongs directly to this function call + // and is not inside a nested function call or array. + $brackets = $tokens[$nextSeparator]['nested_parenthesis']; + $lastBracket = array_pop($brackets); + if ($lastBracket !== $closeBracket) { + continue; + } + + // Checking this: $value = my_function(...[*]$arg...). + $tokenBefore = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($nextSeparator - 1), + null, + true + ); + + if ($tokens[$tokenBefore]['code'] === T_BITWISE_AND) { + // Checking this: $value = my_function(...[*]&$arg...). + $tokenBefore = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($tokenBefore - 1), + null, + true + ); + + // We have to exclude all uses of T_BITWISE_AND that are not + // references. We use a blacklist approach as we prefer false + // positives to not identifying a pass-by-reference call at all. + // The blacklist may not yet be complete. + switch ($tokens[$tokenBefore]['code']) { + case T_VARIABLE: + case T_CLOSE_PARENTHESIS: + case T_LNUMBER: + // In these cases T_BITWISE_AND represents + // the bitwise and operator. + continue; + + default: + // T_BITWISE_AND represents a pass-by-reference. + $error = 'Call-time pass-by-reference calls are prohibited'; + $phpcsFile->addError($error, $tokenBefore, 'NotAllowed'); + break; + } + }//end if + }//end while + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php new file mode 100644 index 000000000..03618bec9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php @@ -0,0 +1,141 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff. + * + * Checks that calls to methods and functions are spaced correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Skip tokens that are the names of functions or classes + // within their definitions. For example: + // function myFunction... + // "myFunction" is T_STRING but we should skip because it is not a + // function or method *call*. + $functionName = $stackPtr; + $ignoreTokens = PHP_CodeSniffer_Tokens::$emptyTokens; + $ignoreTokens[] = T_BITWISE_AND; + $functionKeyword = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true); + if ($tokens[$functionKeyword]['code'] === T_FUNCTION || $tokens[$functionKeyword]['code'] === T_CLASS) { + return; + } + + // If the next non-whitespace token after the function or method call + // is not an opening parenthesis then it cant really be a *call*. + $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($functionName + 1), null, true); + if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + $nextSeparator = $openBracket; + while (($nextSeparator = $phpcsFile->findNext(array(T_COMMA, T_VARIABLE, T_CLOSURE), ($nextSeparator + 1), $closeBracket)) !== false) { + if ($tokens[$nextSeparator]['code'] === T_CLOSURE) { + $nextSeparator = $tokens[$nextSeparator]['scope_closer']; + continue; + } + + // Make sure the comma or variable belongs directly to this function call, + // and is not inside a nested function call or array. + $brackets = $tokens[$nextSeparator]['nested_parenthesis']; + $lastBracket = array_pop($brackets); + if ($lastBracket !== $closeBracket) { + continue; + } + + if ($tokens[$nextSeparator]['code'] === T_COMMA) { + if ($tokens[($nextSeparator - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before comma in function call'; + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeComma'); + } + + if ($tokens[($nextSeparator + 1)]['code'] !== T_WHITESPACE) { + $error = 'No space found after comma in function call'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterComma'); + } else { + // If there is a newline in the space, then the must be formatting + // each argument on a newline, which is valid, so ignore it. + if (strpos($tokens[($nextSeparator + 1)]['content'], $phpcsFile->eolChar) === false) { + $space = strlen($tokens[($nextSeparator + 1)]['content']); + if ($space > 1) { + $error = 'Expected 1 space after comma in function call; %s found'; + $data = array($space); + $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceAfterComma', $data); + } + } + } + } else { + // Token is a variable. + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextSeparator + 1), $closeBracket, true); + if ($nextToken !== false) { + if ($tokens[$nextToken]['code'] === T_EQUAL) { + if (($tokens[($nextToken - 1)]['code']) !== T_WHITESPACE) { + $error = 'Expected 1 space before = sign of default value'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeEquals'); + } + + if ($tokens[($nextToken + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after = sign of default value'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterEquals'); + } + } + } + }//end if + }//end while + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php new file mode 100644 index 000000000..f2df820a2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php @@ -0,0 +1,121 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff. + * + * Checks that the opening brace of a function is on the line after the + * function declaration. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return void + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + $openingBrace = $tokens[$stackPtr]['scope_opener']; + + // The end of the function occurs at the end of the argument list. Its + // like this because some people like to break long function declarations + // over multiple lines. + $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; + $braceLine = $tokens[$openingBrace]['line']; + + $lineDifference = ($braceLine - $functionLine); + + if ($lineDifference === 0) { + $error = 'Opening brace should be on a new line'; + $phpcsFile->addError($error, $openingBrace, 'BraceOnSameLine'); + return; + } + + if ($lineDifference > 1) { + $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; + $data = array(($lineDifference - 1)); + $phpcsFile->addError($error, $openingBrace, 'BraceSpacing', $data); + return; + } + + // We need to actually find the first piece of content on this line, + // as if this is a method with tokens before it (public, static etc) + // or an if with an else before it, then we need to start the scope + // checking from there, rather than the current token. + $lineStart = $stackPtr; + while (($lineStart = $phpcsFile->findPrevious(array(T_WHITESPACE), ($lineStart - 1), null, false)) !== false) { + if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { + break; + } + } + + // We found a new line, now go forward and find the first non-whitespace + // token. + $lineStart = $phpcsFile->findNext(array(T_WHITESPACE), $lineStart, null, true); + + // The opening brace is on the correct line, now it needs to be + // checked to be correctly indented. + $startColumn = $tokens[$lineStart]['column']; + $braceIndent = $tokens[$openingBrace]['column']; + + if ($braceIndent !== $startColumn) { + $error = 'Opening brace indented incorrectly; expected %s spaces, found %s'; + $data = array( + ($startColumn - 1), + ($braceIndent - 1), + ); + $phpcsFile->addError($error, $openingBrace, 'BraceIndent', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php new file mode 100644 index 000000000..5647a44f3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -0,0 +1,117 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff. + * + * Checks that the opening brace of a function is on the same line + * as the function declaration. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the tokens that this sniff wants to listen for. + * + * @return void + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + $openingBrace = $tokens[$stackPtr]['scope_opener']; + + // The end of the function occurs at the end of the argument list. Its + // like this because some people like to break long function declarations + // over multiple lines. + $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; + $braceLine = $tokens[$openingBrace]['line']; + + $lineDifference = ($braceLine - $functionLine); + + if ($lineDifference > 0) { + $error = 'Opening brace should be on the same line as the declaration'; + $phpcsFile->addError($error, $openingBrace, 'BraceOnNewLine'); + return; + } + + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + if ($tokens[($closeBracket + 1)]['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($tokens[($closeBracket + 1)]['content'] === "\t") { + $length = '\t'; + } else { + $length = strlen($tokens[($closeBracket + 1)]['content']); + } + + if ($length !== 1) { + $error = 'Expected 1 space after closing parenthesis; found %s'; + $data = array($length); + $phpcsFile->addError($error, $closeBracket, 'SpaceAfterBracket', $data); + return; + } + + $closeBrace = $tokens[$stackPtr]['scope_opener']; + if ($tokens[($closeBrace - 1)]['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($tokens[($closeBrace - 1)]['content'] === "\t") { + $length = '\t'; + } else { + $length = strlen($tokens[($closeBrace - 1)]['content']); + } + + if ($length !== 1) { + $error = 'Expected 1 space before opening brace; found %s'; + $data = array($length); + $phpcsFile->addError($error, $openingBrace, 'SpaceBeforeBrace', $data); + return; + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php new file mode 100644 index 000000000..69c60e20a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php @@ -0,0 +1,129 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks the cyclomatic complexity (McCabe) for functions. + * + * The cyclomatic complexity (also called McCabe code metrics) + * indicates the complexity within a function by counting + * the different paths the function includes. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Johann-Peter Hartmann + * @author Greg Sherwood + * @copyright 2007 Mayflower GmbH + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Metrics_CyclomaticComplexitySniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A complexity higher than this value will throw a warning. + * + * @var int + */ + public $complexity = 10; + + /** + * A complexity higer than this value will throw an error. + * + * @var int + */ + public $absoluteComplexity = 20; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + $tokens = $phpcsFile->getTokens(); + + // Ignore abstract methods. + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + // Detect start and end of this function definition. + $start = $tokens[$stackPtr]['scope_opener']; + $end = $tokens[$stackPtr]['scope_closer']; + + // Predicate nodes for PHP. + $find = array( + 'T_CASE', + 'T_DEFAULT', + 'T_CATCH', + 'T_IF', + 'T_FOR', + 'T_FOREACH', + 'T_WHILE', + 'T_DO', + 'T_ELSEIF', + ); + + $complexity = 1; + + // Iterate from start to end and count predicate nodes. + for ($i = ($start + 1); $i < $end; $i++) { + if (in_array($tokens[$i]['type'], $find) === true) { + $complexity++; + } + } + + if ($complexity > $this->absoluteComplexity) { + $error = 'Function\'s cyclomatic complexity (%s) exceeds allowed maximum of %s'; + $data = array( + $complexity, + $this->absoluteComplexity, + ); + $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); + } else if ($complexity > $this->complexity) { + $warning = 'Function\'s cyclomatic complexity (%s) exceeds %s; consider refactoring the function'; + $data = array( + $complexity, + $this->complexity, + ); + $phpcsFile->addWarning($warning, $stackPtr, 'TooHigh', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php new file mode 100644 index 000000000..2b95d8e5b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php @@ -0,0 +1,114 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks the nesting level for methods. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Johann-Peter Hartmann + * @author Greg Sherwood + * @copyright 2007 Mayflower GmbH + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Metrics_NestingLevelSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A nesting level than this value will throw a warning. + * + * @var int + */ + public $nestingLevel = 5; + + /** + * A nesting level than this value will throw an error. + * + * @var int + */ + public $absoluteNestingLevel = 10; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore abstract methods. + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + // Detect start and end of this function definition. + $start = $tokens[$stackPtr]['scope_opener']; + $end = $tokens[$stackPtr]['scope_closer']; + + $nestingLevel = 0; + + // Find the maximum nesting level of any token in the function. + for ($i = ($start + 1); $i < $end; $i++) { + $level = $tokens[$i]['level']; + if ($nestingLevel < $level) { + $nestingLevel = $level; + } + } + + // We subtract the nesting level of the function itself. + $nestingLevel = ($nestingLevel - $tokens[$stackPtr]['level'] - 1); + + if ($nestingLevel > $this->absoluteNestingLevel) { + $error = 'Function\'s nesting level (%s) exceeds allowed maximum of %s'; + $data = array( + $nestingLevel, + $this->absoluteNestingLevel, + ); + $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); + } else if ($nestingLevel > $this->nestingLevel) { + $warning = 'Function\'s nesting level (%s) exceeds %s; consider refactoring the function'; + $data = array( + $nestingLevel, + $this->nestingLevel, + ); + $phpcsFile->addWarning($warning, $stackPtr, 'TooHigh', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php new file mode 100644 index 000000000..d6a5eab1f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php @@ -0,0 +1,210 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff. + * + * Ensures method names are correct depending on whether they are public + * or private, and that functions are named correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * A list of all PHP magic methods. + * + * @var array + */ + protected $magicMethods = array( + 'construct', + 'destruct', + 'call', + 'callstatic', + 'get', + 'set', + 'isset', + 'unset', + 'sleep', + 'wakeup', + 'tostring', + 'set_state', + 'clone', + 'invoke', + 'call', + ); + + /** + * A list of all PHP non-magic methods starting with a double underscore. + * + * These come from PHP modules such as SOAPClient. + * + * @var array + */ + protected $methodsDoubleUnderscore = array( + 'soapcall', + 'getlastrequest', + 'getlastresponse', + 'getlastrequestheaders', + 'getlastresponseheaders', + 'getfunctions', + 'gettypes', + 'dorequest', + 'setcookie', + 'setlocation', + 'setsoapheaders', + ); + + /** + * A list of all PHP magic functions. + * + * @var array + */ + protected $magicFunctions = array('autoload'); + + /** + * If TRUE, the string must not have two capital letters next to each other. + * + * @var bool + */ + public $strict = true; + + + /** + * Constructs a Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes the tokens within the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * @param int $currScope The position of the current scope. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + $className = $phpcsFile->getDeclarationName($currScope); + $errorData = array($className.'::'.$methodName); + + // Is this a magic method. i.e., is prefixed with "__" ? + if (preg_match('|^__|', $methodName) !== 0) { + $magicPart = strtolower(substr($methodName, 2)); + if (in_array($magicPart, array_merge($this->magicMethods, $this->methodsDoubleUnderscore)) === false) { + $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; + $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData); + } + + return; + } + + // PHP4 constructors are allowed to break our rules. + if ($methodName === $className) { + return; + } + + // PHP4 destructors are allowed to break our rules. + if ($methodName === '_'.$className) { + return; + } + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + if (PHP_CodeSniffer::isCamelCaps($methodName, false, true, $this->strict) === false) { + if ($methodProps['scope_specified'] === true) { + $error = '%s method name "%s" is not in camel caps format'; + $data = array( + ucfirst($methodProps['scope']), + $errorData[0], + ); + $phpcsFile->addError($error, $stackPtr, 'ScopeNotCamelCaps', $data); + } else { + $error = 'Method name "%s" is not in camel caps format'; + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); + } + + return; + } + + }//end processTokenWithinScope() + + + /** + * Processes the tokens outside the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $functionName = $phpcsFile->getDeclarationName($stackPtr); + if ($functionName === null) { + // Ignore closures. + return; + } + + $errorData = array($functionName); + + // Is this a magic function. i.e., it is prefixed with "__". + if (preg_match('|^__|', $functionName) !== 0) { + $magicPart = strtolower(substr($functionName, 2)); + if (in_array($magicPart, $this->magicFunctions) === false) { + $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; + $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); + } + + return; + } + + if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, $this->strict) === false) { + $error = 'Function name "%s" is not in camel caps format'; + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); + } + + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php new file mode 100644 index 000000000..75109dabe --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php @@ -0,0 +1,106 @@ + + * @author Leif Wickland + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Generic_Sniffs_NamingConventions_ConstructorNameSniff. + * + * Favor PHP 5 constructor syntax, which uses "function __construct()". + * Avoid PHP 4 constructor syntax, which uses "function ClassName()". + * + * @category PHP + * @package PHP_CodeSniffer + * @author Leif Wickland + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_NamingConventions_ConstructorNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs the test with the tokens it wishes to listen for. + * + * @return void + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes this test when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $currScope A pointer to the start of the scope. + * + * @return void + */ + protected function processTokenWithinScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $currScope + ) { + $className = $phpcsFile->getDeclarationName($currScope); + $methodName = $phpcsFile->getDeclarationName($stackPtr); + + if (strcasecmp($methodName, $className) === 0) { + $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; + $phpcsFile->addError($error, $stackPtr, 'OldStyle'); + } else if (strcasecmp($methodName, '__construct') !== 0) { + // Not a constructor. + return; + } + + $tokens = $phpcsFile->getTokens(); + + $parentClassName = $phpcsFile->findExtendedClassName($currScope); + if ($parentClassName === false) { + return; + } + + // Stop if the constructor doesn't have a body, like when it is abstract. + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + return; + } + + $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; + $startIndex = $stackPtr; + while ($doubleColonIndex = $phpcsFile->findNext(array(T_DOUBLE_COLON), $startIndex, $endFunctionIndex)) { + if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING + && $tokens[($doubleColonIndex + 1)]['content'] === $parentClassName + ) { + $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; + $phpcsFile->addError($error, ($doubleColonIndex + 1), 'OldStyleCall'); + } + + $startIndex = ($doubleColonIndex + 1); + } + + }//end processTokenWithinScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php new file mode 100644 index 000000000..1cfac4fc0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -0,0 +1,247 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff. + * + * Ensures that constant names are all uppercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $constName = $tokens[$stackPtr]['content']; + + // If this token is in a heredoc, ignore it. + if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { + return; + } + + // Special case for PHP 5.5 class name resolution. + if (strtolower($constName) === 'class' + && $tokens[($stackPtr - 1)]['code'] === T_DOUBLE_COLON + ) { + return; + } + + // Special case for PHPUnit. + if ($constName === 'PHPUnit_MAIN_METHOD') { + return; + } + + // If the next non-whitespace token after this token + // is not an opening parenthesis then it is not a function call. + $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + $functionKeyword = $phpcsFile->findPrevious( + array( + T_WHITESPACE, + T_COMMA, + T_COMMENT, + T_STRING, + T_NS_SEPARATOR, + ), + ($stackPtr - 1), + null, + true + ); + + $declarations = array( + T_FUNCTION, + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_IMPLEMENTS, + T_EXTENDS, + T_INSTANCEOF, + T_NEW, + T_NAMESPACE, + T_USE, + T_AS, + T_GOTO, + T_INSTEADOF, + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + ); + + if (in_array($tokens[$functionKeyword]['code'], $declarations) === true) { + // This is just a declaration; no constants here. + return; + } + + if ($tokens[$functionKeyword]['code'] === T_CONST) { + // This is a class constant. + if (strtoupper($constName) !== $constName) { + $error = 'Class constants must be uppercase; expected %s but found %s'; + $data = array( + strtoupper($constName), + $constName, + ); + $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data); + } + + return; + } + + // Is this a class name? + $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$nextPtr]['code'] === T_DOUBLE_COLON) { + return; + } + + // Is this a namespace name? + if ($tokens[$nextPtr]['code'] === T_NS_SEPARATOR) { + return; + } + + // Is this an insteadof name? + if ($tokens[$nextPtr]['code'] === T_INSTEADOF) { + return; + } + + // Is this an as name? + if ($tokens[$nextPtr]['code'] === T_AS) { + return; + } + + // Is this a type hint? + if ($tokens[$nextPtr]['code'] === T_VARIABLE + || $phpcsFile->isReference($nextPtr) === true + ) { + return; + } + + // Is this a member var name? + $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { + return; + } + + // Is this a variable name, in the form ${varname} ? + if ($tokens[$prevPtr]['code'] === T_OPEN_CURLY_BRACKET) { + $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$nextPtr]['code'] === T_CLOSE_CURLY_BRACKET) { + return; + } + } + + // Is this a namespace name? + if ($tokens[$prevPtr]['code'] === T_NS_SEPARATOR) { + return; + } + + // Is this an instance of declare() + $prevPtrDeclare = $phpcsFile->findPrevious(array(T_WHITESPACE, T_OPEN_PARENTHESIS), ($stackPtr - 1), null, true); + if ($tokens[$prevPtrDeclare]['code'] === T_DECLARE) { + return; + } + + // Is this a goto label target? + if ($tokens[$nextPtr]['code'] === T_COLON) { + if (in_array($tokens[$prevPtr]['code'], array(T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_COLON), true)) { + return; + } + } + + // This is a real constant. + if (strtoupper($constName) !== $constName) { + $error = 'Constants must be uppercase; expected %s but found %s'; + $data = array( + strtoupper($constName), + $constName, + ); + $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); + } + + } else if (strtolower($constName) === 'define' || strtolower($constName) === 'constant') { + + /* + This may be a "define" or "constant" function call. + */ + + // Make sure this is not a method call. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR + || $tokens[$prev]['code'] === T_DOUBLE_COLON + ) { + return; + } + + // The next non-whitespace token must be the constant name. + $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); + if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { + return; + } + + $constName = $tokens[$constPtr]['content']; + + // Check for constants like self::CONSTANT. + $prefix = ''; + $splitPos = strpos($constName, '::'); + if ($splitPos !== false) { + $prefix = substr($constName, 0, ($splitPos + 2)); + $constName = substr($constName, ($splitPos + 2)); + } + + if (strtoupper($constName) !== $constName) { + $error = 'Constants must be uppercase; expected %s but found %s'; + $data = array( + $prefix.strtoupper($constName), + $prefix.$constName, + ); + $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); + } + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php new file mode 100644 index 000000000..a6873183b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php @@ -0,0 +1,63 @@ + + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks that the opening PHP tag is the first content in a file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Andy Grunwald + * @copyright 2010 Andy Grunwald + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + if ($stackPtr > 0) { + $error = 'The opening PHP tag must be the first content in the file'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php new file mode 100644 index 000000000..d49b5c24a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php @@ -0,0 +1,64 @@ + + * @copyright 2010 Stefano Kowalke + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Checks that open PHP tags are paired with closing tags. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Stefano Kowalke + * @copyright 2010 Stefano Kowalke + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_ClosingPHPTagSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $closeTag = $phpcsFile->findNext(T_CLOSE_TAG, $stackPtr); + if ($closeTag === false) { + $error = 'The PHP open tag does not have a corresponding PHP close tag'; + $phpcsFile->addError($error, $stackPtr, 'NotFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php new file mode 100644 index 000000000..04b19ba73 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php @@ -0,0 +1,94 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_DeprecatedFunctionsSniff. + * + * Discourages the use of deprecated functions that are kept in PHP for + * compatibility with older versions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Sebastian Bergmann + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_DeprecatedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff +{ + + /** + * A list of forbidden functions with their alternatives. + * + * The value is NULL if no alternative exists. IE, the + * function should just not be used. + * + * @var array(string => string|null) + */ + protected $forbiddenFunctions = array(); + + + /** + * Constructor. + * + * Uses the Reflection API to get a list of deprecated functions. + */ + public function __construct() + { + $functions = get_defined_functions(); + + foreach ($functions['internal'] as $functionName) { + $function = new ReflectionFunction($functionName); + + if ($function->isDeprecated() === true) { + $this->forbiddenFunctions[$functionName] = null; + } + } + + }//end __construct() + + + /** + * Generates the error or warning for this sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the forbidden function + * in the token array. + * @param string $function The name of the forbidden function. + * @param string $pattern The pattern used for the match. + * + * @return void + */ + protected function addError($phpcsFile, $stackPtr, $function, $pattern=null) + { + $data = array($function); + $error = 'Function %s() has been deprecated'; + $type = 'Deprecated'; + + if ($this->error === true) { + $phpcsFile->addError($error, $stackPtr, $type, $data); + } else { + $phpcsFile->addWarning($error, $stackPtr, $type, $data); + } + + }//end addError() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php new file mode 100644 index 000000000..6121a670b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php @@ -0,0 +1,85 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_DisallowShortOpenTagSniff. + * + * Makes sure that shorthand PHP open tags are not used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_DisallowShortOpenTagSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG, + T_OPEN_TAG_WITH_ECHO, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $openTag = $tokens[$stackPtr]; + + if ($openTag['content'] === 'addError($error, $stackPtr, 'Found', $data); + } + + if ($openTag['code'] === T_OPEN_TAG_WITH_ECHO) { + $nextVar = $tokens[$phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true)]; + $error = 'Short PHP opening tag used with echo; expected "addError($error, $stackPtr, 'EchoFound', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php new file mode 100644 index 000000000..82ff8502f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php @@ -0,0 +1,202 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_ForbiddenFunctionsSniff. + * + * Discourages the use of alias functions that are kept in PHP for compatibility + * with older versions. Can be used to forbid the use of any function. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_ForbiddenFunctionsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of forbidden functions with their alternatives. + * + * The value is NULL if no alternative exists. IE, the + * function should just not be used. + * + * @var array(string => string|null) + */ + protected $forbiddenFunctions = array( + 'sizeof' => 'count', + 'delete' => 'unset', + ); + + /** + * A cache of forbidden function names, for faster lookups. + * + * @var array(string) + */ + protected $forbiddenFunctionNames = array(); + + /** + * If true, forbidden functions will be considered regular expressions. + * + * @var bool + */ + protected $patternMatch = false; + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = true; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + // Everyone has had a chance to figure out what forbidden functions + // they want to check for, so now we can cache out the list. + $this->forbiddenFunctionNames = array_keys($this->forbiddenFunctions); + + if ($this->patternMatch === true) { + foreach ($this->forbiddenFunctionNames as $i => $name) { + $this->forbiddenFunctionNames[$i] = '/'.$name.'/i'; + } + } + + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $ignore = array( + T_DOUBLE_COLON, + T_OBJECT_OPERATOR, + T_FUNCTION, + T_CONST, + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_AS, + T_INSTEADOF, + ); + + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if (in_array($tokens[$prevToken]['code'], $ignore) === true) { + // Not a call to a PHP function. + return; + } + + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if (in_array($tokens[$nextToken]['code'], $ignore) === true) { + // Not a call to a PHP function. + return; + } + + $function = strtolower($tokens[$stackPtr]['content']); + $pattern = null; + + if ($this->patternMatch === true) { + $count = 0; + $pattern = preg_replace( + $this->forbiddenFunctionNames, + $this->forbiddenFunctionNames, + $function, + 1, + $count + ); + + if ($count === 0) { + return; + } + + // Remove the pattern delimiters and modifier. + $pattern = substr($pattern, 1, -2); + } else { + if (in_array($function, $this->forbiddenFunctionNames) === false) { + return; + } + } + + $this->addError($phpcsFile, $stackPtr, $function, $pattern); + + }//end process() + + + /** + * Generates the error or warning for this sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the forbidden function + * in the token array. + * @param string $function The name of the forbidden function. + * @param string $pattern The pattern used for the match. + * + * @return void + */ + protected function addError($phpcsFile, $stackPtr, $function, $pattern=null) + { + $data = array($function); + $error = 'The use of function %s() is '; + if ($this->error === true) { + $type = 'Found'; + $error .= 'forbidden'; + } else { + $type = 'Discouraged'; + $error .= 'discouraged'; + } + + if ($pattern === null) { + $pattern = $function; + } + + if ($this->forbiddenFunctions[$pattern] !== null) { + $type .= 'WithAlternative'; + $data[] = $this->forbiddenFunctions[$pattern]; + $error .= '; use %s() instead'; + } + + if ($this->error === true) { + $phpcsFile->addError($error, $stackPtr, $type, $data); + } else { + $phpcsFile->addWarning($error, $stackPtr, $type, $data); + } + + }//end addError() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php new file mode 100644 index 000000000..783607268 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php @@ -0,0 +1,107 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_LowerCaseConstantSniff. + * + * Checks that all uses of true, false and null are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_LowerCaseConstantSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_TRUE, + T_FALSE, + T_NULL, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Is this a member var name? + $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { + return; + } + + // Is this a class name? + if ($tokens[$prevPtr]['code'] === T_CLASS + || $tokens[$prevPtr]['code'] === T_EXTENDS + || $tokens[$prevPtr]['code'] === T_IMPLEMENTS + || $tokens[$prevPtr]['code'] === T_NEW + ) { + return; + } + + // Class or namespace? + if ($tokens[($stackPtr - 1)]['code'] === T_NS_SEPARATOR) { + return; + } + + $keyword = $tokens[$stackPtr]['content']; + if (strtolower($keyword) !== $keyword) { + $error = 'TRUE, FALSE and NULL must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtolower($keyword), + $keyword, + ); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php new file mode 100644 index 000000000..13083ce36 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php @@ -0,0 +1,137 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_LowerCaseKeywordSniff. + * + * Checks that all PHP keywords are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_LowerCaseKeywordSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_HALT_COMPILER, + T_ABSTRACT, + T_ARRAY, + T_AS, + T_BREAK, + T_CALLABLE, + T_CASE, + T_CATCH, + T_CLASS, + T_CLONE, + T_CONST, + T_CONTINUE, + T_DECLARE, + T_DEFAULT, + T_DO, + T_ECHO, + T_ELSE, + T_ELSEIF, + T_EMPTY, + T_ENDDECLARE, + T_ENDFOR, + T_ENDFOREACH, + T_ENDIF, + T_ENDSWITCH, + T_ENDWHILE, + T_EVAL, + T_EXIT, + T_EXTENDS, + T_FINAL, + T_FINALLY, + T_FOR, + T_FOREACH, + T_FUNCTION, + T_GLOBAL, + T_GOTO, + T_IF, + T_IMPLEMENTS, + T_INCLUDE, + T_INCLUDE_ONCE, + T_INSTANCEOF, + T_INSTEADOF, + T_INTERFACE, + T_ISSET, + T_LIST, + T_LOGICAL_AND, + T_LOGICAL_OR, + T_LOGICAL_XOR, + T_NAMESPACE, + T_NEW, + T_PRINT, + T_PRIVATE, + T_PROTECTED, + T_PUBLIC, + T_REQUIRE, + T_REQUIRE_ONCE, + T_RETURN, + T_STATIC, + T_SWITCH, + T_THROW, + T_TRAIT, + T_TRY, + T_UNSET, + T_USE, + T_VAR, + T_WHILE, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $keyword = $tokens[$stackPtr]['content']; + if (strtolower($keyword) !== $keyword) { + $error = 'PHP keywords must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtolower($keyword), + $keyword, + ); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php new file mode 100644 index 000000000..e26ad553b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -0,0 +1,81 @@ + + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_NoSilencedErrorsSniff. + * + * Throws an error or warning when any code prefixed with an asperand is encountered. + * + * + * if (@in_array($array, $needle)) + * { + * doSomething(); + * } + * + * + * @category PHP + * @package PHP_CodeSniffer + * @author Andy Brockhurst + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_NoSilencedErrorsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = false; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_ASPERAND); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $error = 'Silencing errors is forbidden'; + if ($this->error === true) { + $error = 'Silencing errors is forbidden'; + $phpcsFile->addError($error, $stackPtr, 'Forbidden'); + } else { + $error = 'Silencing errors is discouraged'; + $phpcsFile->addWarning($error, $stackPtr, 'Discouraged'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php new file mode 100644 index 000000000..1a5b338ad --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_SAPIUsageSniff. + * + * Ensures the PHP_SAPI constant is used instead of php_sapi_name(). + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_SAPIUsageSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $ignore = array( + T_DOUBLE_COLON, + T_OBJECT_OPERATOR, + T_FUNCTION, + T_CONST, + ); + + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if (in_array($tokens[$prevToken]['code'], $ignore) === true) { + // Not a call to a PHP function. + return; + } + + $function = strtolower($tokens[$stackPtr]['content']); + if ($function === 'php_sapi_name') { + $error = 'Use the PHP_SAPI constant instead of calling php_sapi_name()'; + $phpcsFile->addError($error, $stackPtr, 'FunctionFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php new file mode 100644 index 000000000..7adffffc9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php @@ -0,0 +1,98 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_PHP_UpperCaseConstantSniff. + * + * Checks that all uses of TRUE, FALSE and NULL are uppercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_PHP_UpperCaseConstantSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_TRUE, + T_FALSE, + T_NULL, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Is this a member var name? + $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { + return; + } + + // Is this a class name? + if ($tokens[$prevPtr]['code'] === T_CLASS + || $tokens[$prevPtr]['code'] === T_EXTENDS + || $tokens[$prevPtr]['code'] === T_IMPLEMENTS + || $tokens[$prevPtr]['code'] === T_NEW + ) { + return; + } + + // Class or namespace? + if ($tokens[($stackPtr - 1)]['code'] === T_NS_SEPARATOR) { + return; + } + + $keyword = $tokens[$stackPtr]['content']; + if (strtoupper($keyword) !== $keyword) { + $error = 'TRUE, FALSE and NULL must be uppercase; expected "%s" but found "%s"'; + $data = array( + strtoupper($keyword), + $keyword, + ); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php new file mode 100644 index 000000000..8033c1719 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php @@ -0,0 +1,125 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Strings_UnnecessaryStringConcatSniff. + * + * Checks that two strings are not concatenated together; suggests + * using one string instead. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_Strings_UnnecessaryStringConcatSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = true; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_STRING_CONCAT, + T_PLUS, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // Work out which type of file this is for. + $tokens = $phpcsFile->getTokens(); + if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT) { + if ($phpcsFile->tokenizerType === 'JS') { + return; + } + } else { + if ($phpcsFile->tokenizerType === 'PHP') { + return; + } + } + + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($prev === false || $next === false) { + return; + } + + $stringTokens = PHP_CodeSniffer_Tokens::$stringTokens; + if (in_array($tokens[$prev]['code'], $stringTokens) === true + && in_array($tokens[$next]['code'], $stringTokens) === true + ) { + if ($tokens[$prev]['content'][0] === $tokens[$next]['content'][0]) { + // Before we throw an error for PHP, allow strings to be + // combined if they would have < and ? next to each other because + // this trick is sometimes required in PHP strings. + if ($phpcsFile->tokenizerType === 'PHP') { + $prevChar = substr($tokens[$prev]['content'], -2, 1); + $nextChar = $tokens[$next]['content'][1]; + $combined = $prevChar.$nextChar; + if ($combined === '?'.'>' || $combined === '<'.'?') { + return; + } + } + + $error = 'String concat is not required here; use a single string instead'; + if ($this->error === true) { + $phpcsFile->addError($error, $stackPtr, 'Found'); + } else { + $phpcsFile->addWarning($error, $stackPtr, 'Found'); + } + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php new file mode 100644 index 000000000..6878f7f2f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php @@ -0,0 +1,206 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_VersionControl_SubversionPropertiesSniff. + * + * Tests that the correct Subversion properties are set. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Jack Bates + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_VersionControl_SubversionPropertiesSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The Subversion properties that should be set. + * + * Key of array is the SVN property and the value is the + * exact value the property should have or NULL if the + * property should just be set but the value is not fixed. + * + * @var array + */ + protected $properties = array( + 'svn:keywords' => 'Author Id Revision', + 'svn:eol-style' => 'native', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is the first PHP open tag so we don't process the + // same file twice. + $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($prevOpenTag !== false) { + return; + } + + $path = $phpcsFile->getFileName(); + $properties = $this->getProperties($path); + if ($properties === null) { + // Not under version control. + return; + } + + $allProperties = $properties + $this->properties; + foreach ($allProperties as $key => $value) { + if (isset($properties[$key]) === true + && isset($this->properties[$key]) === false + ) { + $error = 'Unexpected Subversion property "%s" = "%s"'; + $data = array( + $key, + $properties[$key], + ); + $phpcsFile->addError($error, $stackPtr, 'Unexpected', $data); + continue; + } + + if (isset($properties[$key]) === false + && isset($this->properties[$key]) === true + ) { + $error = 'Missing Subversion property "%s" = "%s"'; + $data = array( + $key, + $this->properties[$key], + ); + $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + continue; + } + + if ($properties[$key] !== null + && $properties[$key] !== $this->properties[$key] + ) { + $error = 'Subversion property "%s" = "%s" does not match "%s"'; + $data = array( + $key, + $properties[$key], + $this->properties[$key], + ); + $phpcsFile->addError($error, $stackPtr, 'NoMatch', $data); + } + }//end foreach + + }//end process() + + + /** + * Returns the Subversion properties which are actually set on a path. + * + * Returns NULL if the file is not under version control. + * + * @param string $path The path to return Subversion properties on. + * + * @return array + * @throws PHP_CodeSniffer_Exception If Subversion properties file could + * not be opened. + */ + protected function getProperties($path) + { + $properties = array(); + + $paths = array(); + $paths[] = dirname($path).'/.svn/props/'.basename($path).'.svn-work'; + $paths[] = dirname($path).'/.svn/prop-base/'.basename($path).'.svn-base'; + + $foundPath = false; + foreach ($paths as $path) { + if (file_exists($path) === true) { + $foundPath = true; + + $handle = fopen($path, 'r'); + if ($handle === false) { + $error = 'Error opening file; could not get Subversion properties'; + throw new PHP_CodeSniffer_Exception($error); + } + + while (feof($handle) === false) { + // Read a key length line. Might be END, though. + $buffer = trim(fgets($handle)); + + // Check for the end of the hash. + if ($buffer === 'END') { + break; + } + + // Now read that much into a buffer. + $key = fread($handle, substr($buffer, 2)); + + // Suck up extra newline after key data. + fgetc($handle); + + // Read a value length line. + $buffer = trim(fgets($handle)); + + // Now read that much into a buffer. + $length = substr($buffer, 2); + if ($length === '0') { + // Length of value is ZERO characters, so + // value is actually empty. + $value = ''; + } else { + $value = fread($handle, $length); + } + + // Suck up extra newline after value data. + fgetc($handle); + + $properties[$key] = $value; + }//end while + + fclose($handle); + }//end if + }//end foreach + + if ($foundPath === false) { + return null; + } + + return $properties; + + }//end getProperties() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php new file mode 100644 index 000000000..23f352545 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php @@ -0,0 +1,86 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff. + * + * Throws errors if spaces are used for indentation. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_WHITESPACE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is whitespace used for indentation. + $line = $tokens[$stackPtr]['line']; + if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) { + return; + } + + if (strpos($tokens[$stackPtr]['content'], ' ') !== false) { + // Space are considered ok if they are proceeded by tabs and not followed + // by tabs, as is the case with standard docblock comments. + $error = 'Tabs must be used to indent lines; spaces are not allowed'; + $phpcsFile->addError($error, $stackPtr, 'TabsUsed'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php new file mode 100644 index 000000000..5472c7d58 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php @@ -0,0 +1,86 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff. + * + * Throws errors if tabs are used for indentation. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_WHITESPACE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is whitespace used for indentation. + $line = $tokens[$stackPtr]['line']; + if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) { + return; + } + + if (strpos($tokens[$stackPtr]['content'], "\t") !== false) { + $error = 'Spaces must be used to indent lines; tabs are not allowed'; + $phpcsFile->addError($error, $stackPtr, 'TabsUsed'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php new file mode 100644 index 000000000..de7efb14c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php @@ -0,0 +1,437 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Whitespace_ScopeIndentSniff. + * + * Checks that control structures are structured correctly, and their content + * is indented correctly. This sniff will throw errors if tabs are used + * for indentation rather than spaces. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Generic_Sniffs_WhiteSpace_ScopeIndentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + /** + * Does the indent need to be exactly right. + * + * If TRUE, indent needs to be exactly $indent spaces. If FALSE, + * indent needs to be at least $indent spaces (but can be more). + * + * @var bool + */ + public $exact = false; + + /** + * List of tokens not needing to be checked for indentation. + * + * Useful to allow Sniffs based on this to easily ignore/skip some + * tokens from verification. For example, inline html sections + * or php open/close tags can escape from here and have their own + * rules elsewhere. + * + * @var array + */ + public $ignoreIndentationTokens = array(); + + /** + * Any scope openers that should not cause an indent. + * + * @var array(int) + */ + protected $nonIndentingScopes = array(); + + /** + * Stores the indent of the last PHP open tag we found. + * + * This value is used to calculate the expected indent of top level structures + * so we don't assume they are always at column 1. If PHP code is embedded inside + * HTML (etc.) code, then the starting column for that code may not be column 1. + * + * @var int + */ + private $_openTagIndent = 0; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + $tokens = PHP_CodeSniffer_Tokens::$scopeOpeners; + $tokens[] = T_OPEN_TAG; + return $tokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We only want to record the indent of open tags, not process them. + if ($tokens[$stackPtr]['code'] == T_OPEN_TAG) { + if (empty($tokens[$stackPtr]['conditions']) === true) { + // Only record top-level PHP tags. + $this->_openTagIndent = ($tokens[$stackPtr]['column'] - 1); + } + + return; + } + + // If this is an inline condition (ie. there is no scope opener), then + // return, as this is not a new scope. + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + if ($tokens[$stackPtr]['code'] === T_ELSE) { + $next = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($stackPtr + 1), + null, + true + ); + + // We will handle the T_IF token in another call to process. + if ($tokens[$next]['code'] === T_IF) { + return; + } + } + + // Find the first token on this line. + $firstToken = $stackPtr; + for ($i = $stackPtr; $i >= 0; $i--) { + // Record the first code token on the line. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $firstToken = $i; + } + + // It's the start of the line, so we've found our first php token. + if ($tokens[$i]['column'] === 1) { + break; + } + } + + // Based on the conditions that surround this token, determine the + // indent that we expect this current content to be. + $expectedIndent = $this->calculateExpectedIndent($tokens, $firstToken); + + // Don't process the first token if it is a closure because they have + // different indentation rules as they are often used as function arguments + // for multi-line function calls. But continue to process the content of the + // closure because it should be indented as normal. + if ($tokens[$firstToken]['code'] !== T_CLOSURE + && $tokens[$firstToken]['column'] !== $expectedIndent + ) { + // If the scope opener is a closure but it is not the first token on the + // line, then the first token may be a variable or array index as so + // should not require exact indentation unless the exact member var + // is set to TRUE. + $exact = true; + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + $exact = $this->exact; + } + + if ($exact === true || $tokens[$firstToken]['column'] < $expectedIndent) { + $error = 'Line indented incorrectly; expected %s spaces, found %s'; + $data = array( + ($expectedIndent - 1), + ($tokens[$firstToken]['column'] - 1), + ); + $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); + } + }//end if + + $scopeOpener = $tokens[$stackPtr]['scope_opener']; + $scopeCloser = $tokens[$stackPtr]['scope_closer']; + + // Some scopes are expected not to have indents. + if (in_array($tokens[$firstToken]['code'], $this->nonIndentingScopes) === false) { + $indent = ($expectedIndent + $this->indent); + } else { + $indent = $expectedIndent; + } + + $newline = false; + $commentOpen = false; + $inHereDoc = false; + + // Only loop over the content between the opening and closing brace, not + // the braces themselves. + for ($i = ($scopeOpener + 1); $i < $scopeCloser; $i++) { + + // If this token is another scope, skip it as it will be handled by + // another call to this sniff. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true) { + if (isset($tokens[$i]['scope_opener']) === true) { + $i = $tokens[$i]['scope_closer']; + + // If the scope closer is followed by a semi-colon, the semi-colon is part + // of the closer and should also be ignored. This most commonly happens with + // CASE statements that end with "break;", where we don't want to stop + // ignoring at the break, but rather at the semi-colon. + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true); + if ($tokens[$nextToken]['code'] === T_SEMICOLON) { + $i = $nextToken; + } + } else { + // If this token does not have a scope_opener indice, then + // it's probably an inline scope, so let's skip to the next + // semicolon. Inline scopes include inline if's, abstract + // methods etc. + $nextToken = $phpcsFile->findNext(T_SEMICOLON, $i, $scopeCloser); + if ($nextToken !== false) { + $i = $nextToken; + } + } + + continue; + }//end if + + // If this is a HEREDOC then we need to ignore it as the + // whitespace before the contents within the HEREDOC are + // considered part of the content. + if ($tokens[$i]['code'] === T_START_HEREDOC + || $tokens[$i]['code'] === T_START_NOWDOC + ) { + $inHereDoc = true; + continue; + } else if ($inHereDoc === true) { + if ($tokens[$i]['code'] === T_END_HEREDOC + || $tokens[$i]['code'] === T_END_NOWDOC + ) { + $inHereDoc = false; + } + + continue; + } + + if ($tokens[$i]['column'] === 1) { + // We started a newline. + $newline = true; + } + + if ($newline === true && $tokens[$i]['code'] !== T_WHITESPACE) { + // If we started a newline and we find a token that is not + // whitespace, then this must be the first token on the line that + // must be indented. + $newline = false; + $firstToken = $i; + + $column = $tokens[$firstToken]['column']; + + // Ignore the token for indentation if it's in the ignore list. + if (in_array($tokens[$firstToken]['code'], $this->ignoreIndentationTokens)) { + continue; + } + + // Special case for non-PHP code. + if ($tokens[$firstToken]['code'] === T_INLINE_HTML) { + $trimmedContentLength + = strlen(ltrim($tokens[$firstToken]['content'])); + if ($trimmedContentLength === 0) { + continue; + } + + $contentLength = strlen($tokens[$firstToken]['content']); + $column = ($contentLength - $trimmedContentLength + 1); + } + + // Check to see if this constant string spans multiple lines. + // If so, then make sure that the strings on lines other than the + // first line are indented appropriately, based on their whitespace. + if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { + if (in_array($tokens[($firstToken - 1)]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { + // If we find a string that directly follows another string + // then its just a string that spans multiple lines, so we + // don't need to check for indenting. + continue; + } + } + + // This is a special condition for T_DOC_COMMENT and C-style + // comments, which contain whitespace between each line. + if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + $content = trim($tokens[$firstToken]['content']); + if (preg_match('|^/\*|', $content) !== 0) { + // Check to see if the end of the comment is on the same line + // as the start of the comment. If it is, then we don't + // have to worry about opening a comment. + if (preg_match('|\*/$|', $content) === 0) { + // We don't have to calculate the column for the + // start of the comment as there is a whitespace + // token before it. + $commentOpen = true; + } + } else if ($commentOpen === true) { + if ($content === '') { + // We are in a comment, but this line has nothing on it + // so let's skip it. + continue; + } + + $contentLength = strlen($tokens[$firstToken]['content']); + $trimmedContentLength + = strlen(ltrim($tokens[$firstToken]['content'])); + + $column = ($contentLength - $trimmedContentLength + 1); + if (preg_match('|\*/$|', $content) !== 0) { + $commentOpen = false; + } + + // We are in a comment, so the indent does not have to + // be exact. The important thing is that the comment opens + // at the correct column and nothing sits closer to the left + // than that opening column. + if ($column > $indent) { + continue; + } + }//end if + }//end if + + // The token at the start of the line, needs to have its' column + // greater than the relative indent we set above. If it is less, + // an error should be shown. + if ($column !== $indent) { + if ($this->exact === true || $column < $indent) { + $type = 'IncorrectExact'; + $error = 'Line indented incorrectly; expected '; + if ($this->exact === false) { + $error .= 'at least '; + $type = 'Incorrect'; + } + + $error .= '%s spaces, found %s'; + $data = array( + ($indent - 1), + ($column - 1), + ); + $phpcsFile->addError($error, $firstToken, $type, $data); + } + }//end if + }//end if + }//end for + + }//end process() + + + /** + * Calculates the expected indent of a token. + * + * Returns the column at which the token should be indented to, so 1 means + * that the token should not be indented at all. + * + * @param array $tokens The stack of tokens for this file. + * @param int $stackPtr The position of the token to get indent for. + * + * @return int + */ + protected function calculateExpectedIndent(array $tokens, $stackPtr) + { + $conditionStack = array(); + + $inParenthesis = false; + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true + && empty($tokens[$stackPtr]['nested_parenthesis']) === false + ) { + $inParenthesis = true; + } + + // Empty conditions array (top level structure). + if (empty($tokens[$stackPtr]['conditions']) === true) { + if ($inParenthesis === true) { + // Wrapped in parenthesis means it is probably in a + // function call (like a closure) so we have to assume indent + // is correct here and someone else will check it more + // carefully in another sniff. + return $tokens[$stackPtr]['column']; + } else { + return ($this->_openTagIndent + 1); + } + } + + $indent = 0; + + $tokenConditions = $tokens[$stackPtr]['conditions']; + foreach ($tokenConditions as $id => $condition) { + // If it's not an indenting scope i.e., it's in our array of + // scopes that don't indent, skip it. + if (in_array($condition, $this->nonIndentingScopes) === true) { + continue; + } + + if ($condition === T_CLOSURE && $inParenthesis === true) { + // Closures cause problems with indents when they are + // used as function arguments because the code inside them + // is not technically inside the function yet, so the indent + // is always off by one. So instead, use the + // indent of the closure as the base value. + $lastContent = $id; + for ($i = ($id - 1); $i > 0; $i--) { + if ($tokens[$i]['line'] !== $tokens[$id]['line']) { + // Changed lines, so the last content we saw is what + // we want. + break; + } + + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $lastContent = $i; + } + } + + $indent = ($tokens[$lastContent]['column'] - 1); + } + + $indent += $this->indent; + }//end foreach + + // Increase by 1 to indiciate that the code should start at a specific column. + // E.g., code indented 4 spaces should start at column 5. + $indent++; + return $indent; + + }//end calculateExpectedIndent() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml b/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml new file mode 100644 index 000000000..aeb5545bf --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml @@ -0,0 +1,4 @@ + + + A collection of generic sniffs. This standard is not designed to be used to check code. + diff --git a/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php b/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php new file mode 100644 index 000000000..e574ce95f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php @@ -0,0 +1,35 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * An exception thrown if the pattern being processed is not supposed to be + * validating the code in question. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Standards_IncorrectPatternException extends Exception +{ + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php new file mode 100644 index 000000000..4c609d3d8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php @@ -0,0 +1,102 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * MySource_Sniffs_CSS_BrowserSpecificStylesSniff. + * + * Ensure that browser-specific styles are not used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_CSS_BrowserSpecificStylesSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + /** + * A list of specific stylesheet suffixes we allow. + * + * These stylesheets contain browser specific styles + * so this sniff ignore them files in the form: + * *_moz.css and *_ie7.css etc. + * + * @var array + */ + protected $specificStylesheets = array( + 'moz', + 'ie', + 'ie7', + 'ie8', + 'webkit', + ); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // Ignore files with browser-specific suffixes. + $filename = $phpcsFile->getFilename(); + $breakChar = strrpos($filename, '_'); + if ($breakChar !== false && substr($filename, -4) === '.css') { + $specific = substr($filename, ($breakChar + 1), -4); + if (in_array($specific, $this->specificStylesheets) === true) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + $content = $tokens[$stackPtr]['content']; + + if ($content{0} === '-') { + $error = 'Browser-specific styles are not allowed'; + $phpcsFile->addError($error, $stackPtr, 'ForbiddenStyle'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php new file mode 100644 index 000000000..695d0c479 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php @@ -0,0 +1,76 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that all action classes throw ChannelExceptions only. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Channels_ChannelExceptionSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_THROW); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = strtolower($phpcsFile->getFilename()); + $matches = array(); + if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|', $fileName, $matches) === 0) { + // This is not an actions.inc file. + return; + } + + $tokens = $phpcsFile->getTokens(); + + $exception = $phpcsFile->findNext(array(T_STRING, T_VARIABLE), ($stackPtr + 1)); + $exceptionName = $tokens[$exception]['content']; + + if ($exceptionName !== 'ChannelException') { + $data = array($exceptionName); + $error = 'Channel actions can only throw ChannelException; found "%s"'; + $phpcsFile->addError($error, $exception, 'WrongExceptionType', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php new file mode 100644 index 000000000..02ca97aa3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php @@ -0,0 +1,137 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that self and static are not used to call public methods in action classes. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Channels_DisallowSelfActionsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLASS); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We are not interested in abstract classes. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($prev !== false && $tokens[$prev]['code'] === T_ABSTRACT) { + return; + } + + // We are only interested in Action classes. + $classNameToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + $className = $tokens[$classNameToken]['content']; + if (substr($className, -7) !== 'Actions') { + return; + } + + $foundFunctions = array(); + $foundCalls = array(); + + // Find all static method calls in the form self::method() in the class. + $classEnd = $tokens[$stackPtr]['scope_closer']; + for ($i = ($classNameToken + 1); $i < $classEnd; $i++) { + if ($tokens[$i]['code'] !== T_DOUBLE_COLON) { + if ($tokens[$i]['code'] === T_FUNCTION) { + // Cache the function information. + $funcName = $phpcsFile->findNext(T_STRING, ($i + 1)); + $funcScope = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, ($i - 1)); + + $foundFunctions[$tokens[$funcName]['content']] = strtolower($tokens[$funcScope]['content']); + } + + continue; + } + + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), null, true); + if ($tokens[$prevToken]['content'] !== 'self' + && $tokens[$prevToken]['content'] !== 'static' + ) { + continue; + } + + $funcNameToken = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + if ($tokens[$funcNameToken]['code'] === T_VARIABLE) { + // We are only interested in function calls. + continue; + } + + $funcName = $tokens[$funcNameToken]['content']; + + // We've found the function, now we need to find it and see if it is + // public, private or protected. If it starts with an underscore we + // can assume it is private. + if ($funcName{0} === '_') { + continue; + } + + $foundCalls[$i] = array( + 'name' => $funcName, + 'type' => strtolower($tokens[$prevToken]['content']), + ); + }//end for + + $errorClassName = substr($className, 0, -7); + + foreach ($foundCalls as $token => $funcData) { + if (isset($foundFunctions[$funcData['name']]) === false) { + // Function was not in this class, might have come from the parent. + // Either way, we can't really check this. + continue; + } else if ($foundFunctions[$funcData['name']] === 'public') { + $type = $funcData['type']; + $error = "Static calls to public methods in Action classes must not use the $type keyword; use %s::%s() instead"; + $data = array( + $errorClassName, + $funcName, + ); + $phpcsFile->addError($error, $token, 'Found'.ucfirst($funcData['type']), $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php new file mode 100644 index 000000000..74963cee0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php @@ -0,0 +1,112 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that a system does not include itself. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Channels_IncludeOwnSystemSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_DOUBLE_COLON); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + $matches = array(); + if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|i', $fileName, $matches) === 0) { + // Not an actions file. + return; + } + + $ownClass = $matches[2]; + $tokens = $phpcsFile->getTokens(); + + $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 2), null, false, true); + $typeName = trim($tokens[$typeName]['content'], " '"); + switch (strtolower($tokens[($stackPtr + 1)]['content'])) { + case 'includesystem' : + $included = strtolower($typeName); + break; + case 'includeasset' : + $included = strtolower($typeName).'assettype'; + break; + case 'includewidget' : + $included = strtolower($typeName).'widgettype'; + break; + default: + return; + } + + if ($included === strtolower($ownClass)) { + $error = "You do not need to include \"%s\" from within the system's own actions file"; + $data = array($ownClass); + $phpcsFile->addError($error, $stackPtr, 'NotRequired', $data); + } + + }//end process() + + + /** + * Determines the included class name from given token. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param array $tokens The array of file tokens. + * @param int $stackPtr The position in the tokens array of the + * potentially included class. + * + * @return string + */ + protected function getIncludedClassFromToken( + PHP_CodeSniffer_File $phpcsFile, + array $tokens, + $stackPtr + ) { + + + return false; + + }//end getIncludedClassFromToken() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php new file mode 100644 index 000000000..c9c828f13 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php @@ -0,0 +1,341 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Ensures that systems, asset types and libs are included before they are used. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Channels_IncludeSystemSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * A list of classes that don't need to be included. + * + * @var array(string) + */ + private $_ignore = array( + 'self', + 'static', + 'parent', + 'channels', + 'basesystem', + 'dal', + 'init', + 'pdo', + 'util', + 'ziparchive', + 'phpunit_framework_assert', + 'abstractmysourceunittest', + 'abstractdatacleanunittest', + 'exception', + 'abstractwidgetwidgettype', + 'domdocument', + ); + + + /** + * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. + */ + public function __construct() + { + parent::__construct(array(T_FUNCTION), array(T_DOUBLE_COLON, T_EXTENDS), true); + + }//end __construct() + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param integer $stackPtr The position where the token was found. + * @param integer $currScope The current scope opener token. + * + * @return void + */ + protected function processTokenWithinScope( + PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $currScope + ) { + $tokens = $phpcsFile->getTokens(); + + // Determine the name of the class that the static function + // is being called on. + $classNameToken = $phpcsFile->findPrevious( + T_WHITESPACE, + ($stackPtr - 1), + null, + true + ); + + // Don't process class names represented by variables as this can be + // an inexact science. + if ($tokens[$classNameToken]['code'] === T_VARIABLE) { + return; + } + + $className = $tokens[$classNameToken]['content']; + if (in_array(strtolower($className), $this->_ignore) === true) { + return; + } + + $includedClasses = array(); + + $fileName = strtolower($phpcsFile->getFilename()); + $matches = array(); + if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|', $fileName, $matches) !== 0) { + // This is an actions file, which means we don't + // have to include the system in which it exists. + $includedClasses[] = $matches[2]; + + // Or a system it implements. + $class = $phpcsFile->getCondition($stackPtr, T_CLASS); + $implements = $phpcsFile->findNext(T_IMPLEMENTS, $class, ($class + 10)); + if ($implements !== false) { + $implementsClass = $phpcsFile->findNext(T_STRING, $implements); + $implementsClassName = strtolower($tokens[$implementsClass]['content']); + if (substr($implementsClassName, -7) === 'actions') { + $includedClasses[] = substr($implementsClassName, 0, -7); + } + } + } + + // Go searching for includeSystem and includeAsset calls within this + // function, or the inclusion of .inc files, which + // would be library files. + for ($i = ($currScope + 1); $i < $stackPtr; $i++) { + $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); + if ($name !== false) { + $includedClasses[] = $name; + // Special case for Widgets cause they are, well, special. + } else if (strtolower($tokens[$i]['content']) === 'includewidget') { + $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($i + 1)); + $typeName = trim($tokens[$typeName]['content'], " '"); + $includedClasses[] = strtolower($typeName).'widgettype'; + } + } + + // Now go searching for includeSystem, includeAsset or require/include + // calls outside our scope. If we are in a class, look outside the + // class. If we are not, look outside the function. + $condPtr = $currScope; + if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { + foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { + if ($condType === T_CLASS) { + break; + } + } + } + + for ($i = 0; $i < $condPtr; $i++) { + // Skip other scopes. + if (isset($tokens[$i]['scope_closer']) === true) { + $i = $tokens[$i]['scope_closer']; + continue; + } + + $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); + if ($name !== false) { + $includedClasses[] = $name; + } + } + + // If we are in a testing class, we might have also included + // some systems and classes in our setUp() method. + $setupFunction = null; + if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { + foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { + if ($condType === T_CLASS) { + // Is this is a testing class? + $name = $phpcsFile->findNext(T_STRING, $condPtr); + $name = $tokens[$name]['content']; + if (substr($name, -8) === 'UnitTest') { + // Look for a method called setUp(). + $end = $tokens[$condPtr]['scope_closer']; + $function = $phpcsFile->findNext(T_FUNCTION, ($condPtr + 1), $end); + while ($function !== false) { + $name = $phpcsFile->findNext(T_STRING, $function); + if ($tokens[$name]['content'] === 'setUp') { + $setupFunction = $function; + break; + } + + $function = $phpcsFile->findNext(T_FUNCTION, ($function + 1), $end); + } + } + } + }//end foreach + }//end if + + if ($setupFunction !== null) { + $start = ($tokens[$setupFunction]['scope_opener'] + 1); + $end = $tokens[$setupFunction]['scope_closer']; + for ($i = $start; $i < $end; $i++) { + $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); + if ($name !== false) { + $includedClasses[] = $name; + } + } + }//end if + + if (in_array(strtolower($className), $includedClasses) === false) { + $error = 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; + $data = array($className); + $phpcsFile->addError($error, $stackPtr, 'NotIncludedCall', $data); + } + + }//end processTokenWithinScope() + + + /** + * Processes a token within the scope that this test is listening to. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * this token was found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['code'] === T_EXTENDS) { + // Find the class name. + $classNameToken = $phpcsFile->findNext(T_STRING, ($stackPtr + 1)); + $className = $tokens[$classNameToken]['content']; + } else { + // Determine the name of the class that the static function + // is being called on. But don't process class names represented by + // variables as this can be an inexact science. + $classNameToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$classNameToken]['code'] === T_VARIABLE) { + return; + } + + $className = $tokens[$classNameToken]['content']; + } + + // Some systems are always available. + if (in_array(strtolower($className), $this->_ignore) === true) { + return; + } + + $includedClasses = array(); + + $fileName = strtolower($phpcsFile->getFilename()); + $matches = array(); + if (preg_match('|/systems/([^/]+)/([^/]+)?actions.inc$|', $fileName, $matches) !== 0) { + // This is an actions file, which means we don't + // have to include the system in which it exists + // We know the system from the path. + $includedClasses[] = $matches[1]; + } + + // Go searching for includeSystem, includeAsset or require/include + // calls outside our scope. + for ($i = 0; $i < $stackPtr; $i++) { + // Skip classes and functions as will we never get + // into their scopes when including this file, although + // we have a chance of getting into IF's, WHILE's etc. + $ignoreTokens = array( + T_CLASS, + T_INTERFACE, + T_FUNCTION, + ); + + if (in_array($tokens[$i]['code'], $ignoreTokens) === true + && isset($tokens[$i]['scope_closer']) === true + ) { + $i = $tokens[$i]['scope_closer']; + continue; + } + + $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); + if ($name !== false) { + $includedClasses[] = $name; + // Special case for Widgets cause they are, well, special. + } else if (strtolower($tokens[$i]['content']) === 'includewidget') { + $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($i + 1)); + $typeName = trim($tokens[$typeName]['content'], " '"); + $includedClasses[] = strtolower($typeName).'widgettype'; + } + }//end for + + if (in_array(strtolower($className), $includedClasses) === false) { + if ($tokens[$stackPtr]['code'] === T_EXTENDS) { + $error = 'Class extends non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; + $data = array($className); + $phpcsFile->addError($error, $stackPtr, 'NotIncludedExtends', $data); + } else { + $error = 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; + $data = array($className); + $phpcsFile->addError($error, $stackPtr, 'NotIncludedCall', $data); + } + } + + }//end processTokenOutsideScope() + + + /** + * Determines the included class name from given token. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param array $tokens The array of file tokens. + * @param int $stackPtr The position in the tokens array of the + * potentially included class. + * + * @return string + */ + protected function getIncludedClassFromToken( + PHP_CodeSniffer_File $phpcsFile, + array $tokens, + $stackPtr + ) { + if (strtolower($tokens[$stackPtr]['content']) === 'includesystem') { + $systemName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); + $systemName = trim($tokens[$systemName]['content'], " '"); + return strtolower($systemName); + } else if (strtolower($tokens[$stackPtr]['content']) === 'includeasset') { + $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); + $typeName = trim($tokens[$typeName]['content'], " '"); + return strtolower($typeName).'assettype'; + } else if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$includeTokens) === true) { + $filePath = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); + $filePath = $tokens[$filePath]['content']; + $filePath = trim($filePath, " '"); + $filePath = basename($filePath, '.inc'); + return strtolower($filePath); + } + + return false; + + }//end getIncludedClassFromToken() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php new file mode 100644 index 000000000..d2c93c7f6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php @@ -0,0 +1,157 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that systems and asset types are used if they are included. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Channels_UnusedSystemSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_DOUBLE_COLON); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check if this is a call to includeSystem, includeAsset or includeWidget. + $methodName = strtolower($tokens[($stackPtr + 1)]['content']); + if (in_array($methodName, array('includesystem', 'includeasset', 'includewidget')) === true) { + $systemName = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 3), null, true); + if ($systemName === false || $tokens[$systemName]['code'] !== T_CONSTANT_ENCAPSED_STRING) { + // Must be using a variable instead of a specific system name. + // We can't accurately check that. + return; + } + + $systemName = trim($tokens[$systemName]['content'], " '"); + } else { + return; + } + + if ($methodName === 'includeasset') { + $systemName .= 'assettype'; + } else if ($methodName === 'includewidget') { + $systemName .= 'widgettype'; + } + + $systemName = strtolower($systemName); + + // Now check if this system is used anywhere in this scope. + $level = $tokens[$stackPtr]['level']; + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['level'] < $level) { + // We have gone out of scope. + // If the original include was inside an IF statement that + // is checking if the system exists, check the outer scope + // as well. + if ($tokens[$stackPtr]['level'] === $level) { + // We are still in the base level, so this is the first + // time we have got here. + $conditions = array_keys($tokens[$stackPtr]['conditions']); + if (empty($conditions) === false) { + $cond = array_pop($conditions); + if ($tokens[$cond]['code'] === T_IF) { + $i = $tokens[$cond]['scope_closer']; + $level--; + continue; + } + } + } + + break; + }//end if + + $validTokens = array( + T_DOUBLE_COLON, + T_EXTENDS, + T_IMPLEMENTS, + ); + + if (in_array($tokens[$i]['code'], $validTokens) === false) { + continue; + } + + switch ($tokens[$i]['code']) { + case T_DOUBLE_COLON: + $usedName = strtolower($tokens[($i - 1)]['content']); + if ($usedName === $systemName) { + // The included system was used, so it is fine. + return; + } + + break; + case T_EXTENDS: + $classNameToken = $phpcsFile->findNext(T_STRING, ($i + 1)); + $className = strtolower($tokens[$classNameToken]['content']); + if ($className === $systemName) { + // The included system was used, so it is fine. + return; + } + + break; + case T_IMPLEMENTS: + $endImplements = $phpcsFile->findNext(array(T_EXTENDS, T_OPEN_CURLY_BRACKET), ($i + 1)); + for ($x = ($i + 1); $x < $endImplements; $x++) { + if ($tokens[$x]['code'] === T_STRING) { + $className = strtolower($tokens[$x]['content']); + if ($className === $systemName) { + // The included system was used, so it is fine. + return; + } + } + } + + break; + }//end switch + }//end for + + // If we get to here, the system was not use. + $error = 'Included system "%s" is never used'; + $data = array($systemName); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php new file mode 100644 index 000000000..0c707b369 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php @@ -0,0 +1,130 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Squiz_Sniffs_Commenting_FunctionCommentSniff', true) === false) { + $error = 'Class Squiz_Sniffs_Commenting_FunctionCommentSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses and verifies the doc comments for functions. + * + * Same as the Squiz standard, but adds support for API tags. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Commenting_FunctionCommentSniff extends Squiz_Sniffs_Commenting_FunctionCommentSniff +{ + + + /** + * Process a list of unknown tags. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processUnknownTags($commentStart, $commentEnd) + { + $unknownTags = $this->commentParser->getUnknown(); + $words = $this->commentParser->getWords(); + $hasApiTag = false; + $apiLength = 3; + foreach ($unknownTags as $errorTag) { + $pos = $errorTag['pos']; + if ($errorTag['tag'] === 'api') { + if ($hasApiTag === true) { + // We've come across an API tag already, which means + // we were not the first tag in the API list. + $error = 'The @api tag must come first in the @api tag list in a function comment'; + $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiNotFirst'); + } + + $hasApiTag = true; + + // There needs to be a blank line before the @api tag. + // So expect a single space before the tag, then 2 newlines before + // that, then some content. + if (trim($words[($pos - 2)]) !== '' + || strpos($words[($pos - 2)], $this->currentFile->eolChar) === false + || strpos($words[($pos - 3)], $this->currentFile->eolChar) === false + || trim($words[($pos - 4)]) === '' + ) { + $error = 'There must be one blank line before the @api tag in a function comment'; + $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiSpacing'); + } + } else if (substr($errorTag['tag'], 0, 4) === 'api-') { + $hasApiTag = true; + + $tagLength = strlen($errorTag['tag']); + if ($tagLength > $apiLength) { + $apiLength = $tagLength; + } + + if (trim($words[($pos - 2)]) !== '' + || strpos($words[($pos - 2)], $this->currentFile->eolChar) === false + || trim($words[($pos - 3)]) === '' + ) { + $error = 'There must be no blank line before the @%s tag in a function comment'; + $data = array($errorTag['tag']); + $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiTagSpacing', $data); + } + }//end if + }//end foreach + + if ($hasApiTag === true) { + // API tags must be the last tags in a function comment. + $order = $this->commentParser->getTagOrders(); + $lastTag = array_pop($order); + if ($lastTag !== 'api' + && substr($lastTag, 0, 4) !== 'api-' + ) { + $error = 'The @api tags must be the last tags in a function comment'; + $this->currentFile->addError($error, $commentEnd, 'ApiNotLast'); + } + + // Check API tag indenting. + foreach ($unknownTags as $errorTag) { + if ($errorTag['tag'] === 'api' + || substr($errorTag['tag'], 0, 4) === 'api-' + ) { + $expected = ($apiLength - strlen($errorTag['tag']) + 1); + $found = strlen($words[($errorTag['pos'] + 1)]); + if ($found !== $expected) { + $error = '@%s tag indented incorrectly; expected %s spaces but found %s'; + $data = array( + $errorTag['tag'], + $expected, + $found, + ); + $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiTagIndent', $data); + } + } + } + }//end if + + }//end processUnknownTags() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php new file mode 100644 index 000000000..628c9e580 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php @@ -0,0 +1,68 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Warns about the use of debug code. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Debug_DebugCodeSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_DOUBLE_COLON); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $className = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if (strtolower($tokens[$className]['content']) === 'debug') { + $method = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + $error = 'Call to debug function Debug::%s() must be removed'; + $data = array($tokens[$method]['content']); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php new file mode 100644 index 000000000..788dcea20 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php @@ -0,0 +1,77 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that console is not used for function or var names. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Debug_FirebugConsoleSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_STRING, + T_PROPERTY, + T_LABEL, + T_OBJECT, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (strtolower($tokens[$stackPtr]['content']) === 'console') { + $error = 'Variables, functions and labels must not be named "console"; name may conflict with Firebug internal variable'; + $phpcsFile->addError($error, $stackPtr, 'ConflictFound'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php new file mode 100644 index 000000000..7e438677c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php @@ -0,0 +1,94 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures this is not assigned to any other var but self. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Objects_AssignThisSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_THIS); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore this.something and other uses of "this" that are not + // direct assignments. + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] !== T_SEMICOLON) { + if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) { + return; + } + } + + // Something must be assigned to "this". + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] !== T_EQUAL) { + return; + } + + // A variable needs to be assigned to "this". + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($prev - 1), null, true); + if ($tokens[$prev]['code'] !== T_STRING) { + return; + } + + // We can only assign "this" to a var called "self". + if ($tokens[$prev]['content'] !== 'self' && $tokens[$prev]['content'] !== '_self') { + $error = 'Keyword "this" can only be assigned to a variable called "self" or "_self"'; + $phpcsFile->addError($error, $prev, 'NotSelf'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php new file mode 100644 index 000000000..f4049fe92 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php @@ -0,0 +1,228 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures the create() method of widget types properly uses callbacks. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OBJECT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $className = $tokens[$stackPtr]['content']; + if (substr(strtolower($className), -10) !== 'widgettype') { + return; + } + + // Search for a create method. + $start = ($tokens[$stackPtr]['scope_opener'] + 1); + $end = ($tokens[$stackPtr]['scope_closer'] - 1); + $create = $phpcsFile->findNext(T_PROPERTY, $start, $end, null, 'create'); + if ($create === false) { + return; + } + + $function = $phpcsFile->findNext(array(T_WHITESPACE, T_COLON), ($create + 1), null, true); + if ($tokens[$function]['code'] !== T_FUNCTION) { + continue; + } + + $start = ($tokens[$function]['scope_opener'] + 1); + $end = ($tokens[$function]['scope_closer'] - 1); + + // Check that the first argument is called "callback". + $arg = $phpcsFile->findNext(T_WHITESPACE, ($tokens[$function]['parenthesis_opener'] + 1), null, true); + if ($tokens[$arg]['content'] !== 'callback') { + $error = 'The first argument of the create() method of a widget type must be called "callback"'; + $phpcsFile->addError($error, $arg, 'FirstArgNotCallback'); + } + + /* + Look for return statements within the function. They cannot return + anything and must be preceded by the callback.call() line. The + callback itself must contain "self" or "this" as the first argument + and there needs to be a call to the callback function somewhere + in the create method. All calls to the callback function must be + followed by a return statement or the end of the method. + */ + + $foundCallback = false; + $passedCallback = false; + $nestedFunction = null; + for ($i = $start; $i <= $end; $i++) { + // Keep track of nested functions. + if ($nestedFunction !== null) { + if ($i === $nestedFunction) { + $nestedFunction = null; + continue; + } + } else if ($tokens[$i]['code'] === T_FUNCTION + && isset($tokens[$i]['scope_closer']) === true + ) { + $nestedFunction = $tokens[$i]['scope_closer']; + continue; + } + + if ($nestedFunction === null && $tokens[$i]['code'] === T_RETURN) { + // Make sure return statements are not returning anything. + if ($tokens[($i + 1)]['code'] !== T_SEMICOLON) { + $error = 'The create() method of a widget type must not return a value'; + $phpcsFile->addError($error, $i, 'ReturnValue'); + } + + continue; + } else if ($tokens[$i]['code'] !== T_STRING + || $tokens[$i]['content'] !== 'callback' + ) { + continue; + } + + // If this is the form "callback.call(" then it is a call + // to the callback function. + if ($tokens[($i + 1)]['code'] !== T_OBJECT_OPERATOR + || $tokens[($i + 2)]['content'] !== 'call' + || $tokens[($i + 3)]['code'] !== T_OPEN_PARENTHESIS + ) { + // One last chance; this might be the callback function + // being passed to another function, like this + // "this.init(something, callback, something)". + if (isset($tokens[$i]['nested_parenthesis']) === false) { + continue; + } + + // Just make sure those brackets dont belong to anyone, + // like an IF or FOR statement. + foreach ($tokens[$i]['nested_parenthesis'] as $bracket) { + if (isset($tokens[$bracket]['parenthesis_owner']) === true) { + continue(2); + } + } + + // Note that we use this endBracket down further when checking + // for a RETURN statement. + $endBracket = end($tokens[$i]['nested_parenthesis']); + $bracket = key($tokens[$i]['nested_parenthesis']); + + $prev = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($bracket - 1), + null, + true + ); + + if ($tokens[$prev]['code'] !== T_STRING) { + // This is not a function passing the callback. + continue; + } + + $passedCallback = true; + }//end if + + $foundCallback = true; + + if ($passedCallback === false) { + // The first argument must be "this" or "self". + $arg = $phpcsFile->findNext(T_WHITESPACE, ($i + 4), null, true); + if ($tokens[$arg]['content'] !== 'this' + && $tokens[$arg]['content'] !== 'self' + ) { + $error = 'The first argument passed to the callback function must be "this" or "self"'; + $phpcsFile->addError($error, $arg, 'FirstArgNotSelf'); + } + } + + // Now it must be followed by a return statement or the end of the function. + if ($passedCallback === false) { + $endBracket = $tokens[($i + 3)]['parenthesis_closer']; + } + + for ($next = $endBracket; $next <= $end; $next++) { + // Skip whitespace so we find the next content after the call. + if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } + + // Skip closing braces like END IF because it is not executable code. + if ($tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { + continue; + } + + // We don't care about anything on the current line, like a + // semicolon. It doesn't matter if there are other statements on the + // line because another sniff will check for those. + if ($tokens[$next]['line'] === $tokens[$endBracket]['line']) { + continue; + } + + break; + } + + if ($next !== $tokens[$function]['scope_closer'] + && $tokens[$next]['code'] !== T_RETURN + ) { + $error = 'The call to the callback function must be followed by a return statement if it is not the last statement in the create() method'; + $phpcsFile->addError($error, $i, 'NoReturn'); + } + }//end for + + if ($foundCallback === false) { + $error = 'The create() method of a widget type must call the callback function'; + $phpcsFile->addError($error, $create, 'CallbackNotCalled'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php new file mode 100644 index 000000000..59f828177 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php @@ -0,0 +1,72 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that widgets are not manually created. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Objects_DisallowNewWidgetSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_NEW); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $className = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$className]['code'] !== T_STRING) { + return; + } + + if (substr(strtolower($tokens[$className]['content']), -10) === 'widgettype') { + $widgetType = substr($tokens[$className]['content'], 0, -10); + $error = 'Manual creation of widget objects is banned; use Widget::getWidget(\'%s\'); instead'; + $data = array($widgetType); + $phpcsFile->addError($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php new file mode 100644 index 000000000..984e943ba --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php @@ -0,0 +1,113 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that values submitted via JS are not compared to NULL. + * + * jQuery 1.8 changed the behaviour of ajax requests so that null values are + * submitted as null= instead of null=null. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_PHP_AjaxNullComparisonSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure it is an API function. We know this by the doc comment. + $commentEnd = $phpcsFile->findPrevious(T_DOC_COMMENT, $stackPtr); + $commentStart = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true); + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart)); + if (strpos($comment, '* @api') === false) { + return; + } + + + // Find all the vars passed in as we are only interested in comparisons + // to NULL for these specific variables. + $foundVars = array(); + $open = $tokens[$stackPtr]['parenthesis_opener']; + $close = $tokens[$stackPtr]['parenthesis_closer']; + for ($i = ($open + 1); $i < $close; $i++) { + if ($tokens[$i]['code'] === T_VARIABLE) { + $foundVars[] = $tokens[$i]['content']; + } + } + + if (empty($foundVars) === true) { + return; + } + + $start = $tokens[$stackPtr]['scope_opener']; + $end = $tokens[$stackPtr]['scope_closer']; + for ($i = ($start + 1); $i < $end; $i++) { + if ($tokens[$i]['code'] !== T_VARIABLE + || in_array($tokens[$i]['content'], $foundVars) === false + ) { + continue; + } + + $operator = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + if ($tokens[$operator]['code'] !== T_IS_IDENTICAL + && $tokens[$operator]['code'] !== T_IS_NOT_IDENTICAL + ) { + continue; + } + + $nullValue = $phpcsFile->findNext(T_WHITESPACE, ($operator + 1), null, true); + if ($tokens[$nullValue]['code'] !== T_NULL) { + continue; + } + + $error = 'Values submitted via Ajax requests must not be compared directly to NULL; use empty() instead'; + $phpcsFile->addError($error, $nullValue, 'Found'); + }//end for + + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php new file mode 100644 index 000000000..176f81136 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php @@ -0,0 +1,126 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that eval() is not used to create objects. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_PHP_EvalObjectFactorySniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_EVAL); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + /* + We need to find all strings that will be in the eval + to determine if the "new" keyword is being used. + */ + + $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($stackPtr + 1)); + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + $strings = array(); + $vars = array(); + + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { + $strings[$i] = $tokens[$i]['content']; + } else if ($tokens[$i]['code'] === T_VARIABLE) { + $vars[$i] = $tokens[$i]['content']; + } + } + + /* + We now have some variables that we need to expand into + the strings that were assigned to them, if any. + */ + + foreach ($vars as $varPtr => $varName) { + while (($prev = $phpcsFile->findPrevious(T_VARIABLE, ($varPtr - 1))) !== false) { + // Make sure this is an assignment of the variable. That means + // it will be the first thing on the line. + $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($prev - 1), null, true); + if ($tokens[$prevContent]['line'] === $tokens[$prev]['line']) { + $varPtr = $prevContent; + continue; + } + + if ($tokens[$prev]['content'] !== $varName) { + // This variable has a different name. + $varPtr = $prevContent; + continue; + } + + // We found one. + break; + }//end while + + if ($prev !== false) { + // Find all strings on the line. + $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($prev + 1)); + for ($i = ($prev + 1); $i < $lineEnd; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { + $strings[$i] = $tokens[$i]['content']; + } + } + } + }//end foreach + + foreach ($strings as $string) { + // If the string has "new" in it, it is not allowed. + // We don't bother checking if the word "new" is echo'd + // because that is unlikely to happen. We assume the use + // of "new" is for object instantiation. + if (strstr($string, ' new ') !== false) { + $error = 'Do not use eval() to create objects dynamically; use reflection instead'; + $phpcsFile->addWarning($error, $stackPtr, 'Found'); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php new file mode 100644 index 000000000..0732e3f63 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php @@ -0,0 +1,119 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that getRequestData() is used to access super globals. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_PHP_GetRequestDataSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_VARIABLE); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $varName = $tokens[$stackPtr]['content']; + if ($varName !== '$_REQUEST' + && $varName !== '$_GET' + && $varName !== '$_POST' + && $varName !== '$_FILES' + ) { + return; + } + + // The only place these super globals can be accessed directly is + // in the getRequestData() method of the Security class. + $inClass = false; + foreach ($tokens[$stackPtr]['conditions'] as $i => $type) { + if ($tokens[$i]['code'] === T_CLASS) { + $className = $phpcsFile->findNext(T_STRING, $i); + $className = $tokens[$className]['content']; + if (strtolower($className) === 'security') { + $inClass = true; + } else { + // We don't have nested classes. + break; + } + } else if ($inClass === true && $tokens[$i]['code'] === T_FUNCTION) { + $funcName = $phpcsFile->findNext(T_STRING, $i); + $funcName = $tokens[$funcName]['content']; + if (strtolower($funcName) === 'getrequestdata') { + // This is valid. + return; + } else { + // We don't have nested functions. + break; + } + }//end if + }//end foreach + + // If we get to here, the super global was used incorrectly. + // First find out how it is being used. + $globalName = strtolower(substr($varName, 2)); + $usedVar = ''; + + $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$openBracket]['code'] === T_OPEN_SQUARE_BRACKET) { + $closeBracket = $tokens[$openBracket]['bracket_closer']; + $usedVar = $phpcsFile->getTokensAsString(($openBracket + 1), ($closeBracket - $openBracket - 1)); + } + + $type = 'SuperglobalAccessed'; + $error = 'The %s super global must not be accessed directly; use Security::getRequestData('; + $data = array($varName); + if ($usedVar !== '') { + $type .= 'WithVar'; + $error .= '%s, \'%s\''; + $data[] = $usedVar; + $data[] = $globalName; + } + + $error .= ') instead'; + $phpcsFile->addError($error, $stackPtr, $type, $data); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php new file mode 100644 index 000000000..7f41fe6c9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php @@ -0,0 +1,76 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Warns when function values are returned directly. + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_PHP_ReturnFunctionValueSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_RETURN); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $functionName = $phpcsFile->findNext(T_STRING, ($stackPtr + 1), null, false, null, true); + + while ($functionName !== false) { + // Check if this is really a function. + $bracket = $phpcsFile->findNext(T_WHITESPACE, ($functionName + 1), null, true); + if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { + // Not a function call. + $functionName = $phpcsFile->findNext(T_STRING, ($functionName + 1), null, false, null, true); + continue; + } + + $error = 'The result of a function call should be assigned to a variable before being returned'; + $phpcsFile->addWarning($error, $stackPtr, 'NotAssigned'); + break; + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php new file mode 100644 index 000000000..2d517afbd --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php @@ -0,0 +1,88 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that strings are not joined using array.join(). + * + * @category PHP + * @package PHP_CodeSniffer_MySource + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class MySource_Sniffs_Strings_JoinStringsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param integer $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content'] !== 'join') { + return; + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { + return; + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($prev - 1), null, true); + if ($tokens[$prev]['code'] === T_CLOSE_SQUARE_BRACKET) { + $opener = $tokens[$prev]['bracket_opener']; + if ($tokens[($opener - 1)]['code'] !== T_STRING) { + // This means the array is declared inline, like x = [a,b,c].join() + // and not elsewhere, like x = y[a].join() + // The first is not allowed while the second is. + $error = 'Joining strings using inline arrays is not allowed; use the + operator instead'; + $phpcsFile->addError($error, $stackPtr, 'ArrayNotAllowed'); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml b/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml new file mode 100644 index 000000000..fe7ae6662 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml @@ -0,0 +1,18 @@ + + + The MySource coding standard builds on the Squiz coding standard. Currently used for MySource Mini development. + + */Tests/* + */Oven/* + */data/* + */jquery.js + */jquery.*.js + */viper/* + DALConf.inc + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml new file mode 100644 index 000000000..b5d53fdf0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml @@ -0,0 +1,22 @@ + + + + + + + { +} + ]]> + + + { +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml new file mode 100644 index 000000000..fe8162000 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml @@ -0,0 +1,177 @@ + + + + + + + /** + * The Foo class. + */ +class Foo +{ +} + ]]> + + + + + + + + /** + * The Foo class. + */ +class Foo +{ +} + ]]> + + + + + + + + /** + * The Foo class. + */ +class Foo +{ +} + ]]> + + + /** + * The Foo class. + */ + +class Foo +{ +} + ]]> + + + + + The Foo class. + */ +class Foo +{ +} + ]]> + + + The Foo class. + */ +class Foo +{ +} + ]]> + + + + + + * A helper for the Bar class. + * + * @see Bar + */ +class Foo +{ +} + ]]> + + + + * + * A helper for the Bar class. + * + * + * @see Bar + */ +class Foo +{ +} + ]]> + + + + + + * @see Bar + */ +class Foo +{ +} + ]]> + + + + * + * @see Bar + */ +class Foo +{ +} + ]]> + + + + + Release: 1.0 + */ +class Foo +{ +} + ]]> + + + 1.0 + */ +class Foo +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml new file mode 100644 index 000000000..0d056eabb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml @@ -0,0 +1,286 @@ + + + + + + + /** + * Short description here. + * + * PHP version 5 + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + ]]> + + + + + Short description here. + * + * PHP version 5 + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + * Short description here. + * + * PHP version 5 + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + + * PHP version 5 + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + * + * PHP version 5 + * + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + + + + @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + @category Foo + * @category Bar + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + PHP version 5 + * + * @category Foo + * @package Foo_Helpers + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + @package Foo_Helpers + * @category Foo + * @author Marty McFly + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + + + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + + * @copyright 2013 Foo Inc. + * @license MIT License + * @link http://example.com + */ + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml new file mode 100644 index 000000000..d5cc175d8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml @@ -0,0 +1,230 @@ + + + + + + + /** + * Short description here. + * + * @return void + */ + function foo() + { + } + ]]> + + + + + + + + Short description here. + * + * @return void + */ + function foo() + { + } + ]]> + + + + * Short description here. + * + * @return void + */ + function foo() + { + } + ]]> + + + + + + * Long description here. + * + * @return void + */ + function foo() + { + } + ]]> + + + + * + * Long description here. + * + * + * @return void + */ + function foo() + { + } + ]]> + + + + + + * @return void + */ + function foo() + { + } + ]]> + + + + * + * @return void + */ + function foo() + { + } + ]]> + + + + + FooException + */ + function foo() + { + } + ]]> + + + @throws + */ + function foo() + { + } + ]]> + + + + + @return void + */ + function foo() + { + } + ]]> + + + + + + + + $foo Foo parameter + * @param string $bar Bar parameter + * @return void + */ + function foo($foo, $bar) + { + } + ]]> + + + $qux Bar parameter + * @return void + */ + function foo($foo, $bar) + { + } + ]]> + + + + + $foo Foo parameter + * @param string $bar Bar parameter + * @return void + */ + function foo($foo, $bar) + { + } + ]]> + + + $bar Bar parameter + * @param string $foo Foo parameter + * @return void + */ + function foo($foo, $bar) + { + } + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml new file mode 100644 index 000000000..53056e2a9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml @@ -0,0 +1,19 @@ + + + + + + + // A comment. + ]]> + + + # A comment. + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml new file mode 100644 index 000000000..ce430fb12 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml @@ -0,0 +1,36 @@ + + + + + + + ($foo) { +} + ]]> + + + ($foo){ +} + ]]> + + + + + { +} + ]]> + + + { +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml new file mode 100644 index 000000000..96d451dc4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml @@ -0,0 +1,60 @@ + + + + + + + && $bar +) { +} + ]]> + + + && $bar +) { +} + ]]> + + + + + && $bar +) { +} + ]]> + + + && + $bar +) { +} + ]]> + + + + + ) { +} + ]]> + + + ) { +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml new file mode 100644 index 000000000..6d115be76 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml @@ -0,0 +1,24 @@ + + + require_once. Anywhere you are conditionally including a class file (for example, factory methods), use include_once. Either of these will ensure that class files are included only once. They share the same file list, so you don't need to worry about mixing them - a file included with require_once will not be included again by include_once. + ]]> + + + include_once and require_once are statements, not functions. Parentheses should not surround the subject filename. + ]]> + + + + + + + ('PHP/CodeSniffer.php'); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml new file mode 100644 index 000000000..e4911ef3b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml new file mode 100644 index 000000000..e825c5533 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml @@ -0,0 +1,35 @@ + + + + + + + = $bar; + ]]> + + + = + $bar; + ]]> + + + + + = $bar; + ]]> + + + = $bar; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml new file mode 100644 index 000000000..f87422778 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + ( $bar, $baz, $quux ) ; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml new file mode 100644 index 000000000..c7951191e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml @@ -0,0 +1,41 @@ + + + + + + + () use ($bar) { +}; + ]]> + + + ()use($bar){ +}; + ]]> + + + + + $bar, + $baz +) { +}; + ]]> + + + $bar, +$baz) +{ +}; + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml new file mode 100644 index 000000000..56196cb62 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml @@ -0,0 +1,25 @@ + + + + + + + $persistent = false) +{ + ... +} + ]]> + + + $persistent = false, $dsn) +{ + ... +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml new file mode 100644 index 000000000..d16087919 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml new file mode 100644 index 000000000..60841dd4c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml new file mode 100644 index 000000000..4c707bdd1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml @@ -0,0 +1,29 @@ + + + + + + + publicVar; + protected $protectedVar; + private $_privateVar; +} + ]]> + + + _publicVar; + protected $_protectedVar; + private $privateVar; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml new file mode 100644 index 000000000..9dee905db --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml @@ -0,0 +1,39 @@ + + + + + + + ->bar() + ->baz(); + ]]> + + + -> + bar()-> + baz(); + ]]> + + + + + ->bar() + ->baz(); + ]]> + + + ->bar() +->baz(); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml new file mode 100644 index 000000000..c8d6e2748 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + } + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml new file mode 100644 index 000000000..fafa07ace --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml @@ -0,0 +1,29 @@ + + + + + + + if ($test) { + $var = 1; + } +} + ]]> + + + if ($test) { +$var = 1; +} +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php new file mode 100644 index 000000000..a0126461d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php @@ -0,0 +1,125 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Class Declaration Test. + * + * Checks the declaration of the class is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param integer $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $errorData = array($tokens[$stackPtr]['content']); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + $error = 'Possible parse error: %s missing opening or closing brace'; + $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $errorData); + return; + } + + $curlyBrace = $tokens[$stackPtr]['scope_opener']; + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($curlyBrace - 1), $stackPtr, true); + $classLine = $tokens[$lastContent]['line']; + $braceLine = $tokens[$curlyBrace]['line']; + if ($braceLine === $classLine) { + $error = 'Opening brace of a %s must be on the line after the definition'; + $phpcsFile->addError($error, $curlyBrace, 'OpenBraceNewLine', $errorData); + return; + } else if ($braceLine > ($classLine + 1)) { + $error = 'Opening brace of a %s must be on the line following the %s declaration; found %s line(s)'; + $data = array( + $tokens[$stackPtr]['content'], + $tokens[$stackPtr]['content'], + ($braceLine - $classLine - 1), + ); + $phpcsFile->addError($error, $curlyBrace, 'OpenBraceWrongLine', $data); + return; + } + + if ($tokens[($curlyBrace + 1)]['content'] !== $phpcsFile->eolChar) { + $error = 'Opening %s brace must be on a line by itself'; + $phpcsFile->addError($error, $curlyBrace, 'OpenBraceNotAlone', $errorData); + } + + if ($tokens[($curlyBrace - 1)]['code'] === T_WHITESPACE) { + $prevContent = $tokens[($curlyBrace - 1)]['content']; + if ($prevContent === $phpcsFile->eolChar) { + $spaces = 0; + } else { + $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); + $spaces = strlen($blankSpace); + } + + $expected = ($tokens[$stackPtr]['level'] * $this->indent); + if ($spaces !== $expected) { + $error = 'Expected %s spaces before opening brace; %s found'; + $data = array( + $expected, + $spaces, + ); + $phpcsFile->addError($error, $curlyBrace, 'SpaceBeforeBrace', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php new file mode 100644 index 000000000..265c4b7c3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php @@ -0,0 +1,233 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('PEAR_Sniffs_Commenting_FileCommentSniff', true) === false) { + $error = 'Class PEAR_Sniffs_Commenting_FileCommentSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses and verifies the doc comments for classes. + * + * Verifies that : + *
    + *
  • A doc comment exists.
  • + *
  • There is a blank newline after the short description.
  • + *
  • There is a blank newline between the long and short description.
  • + *
  • There is a blank newline between the long description and tags.
  • + *
  • Check the order of the tags.
  • + *
  • Check the indentation of each tag.
  • + *
  • Check required and optional tags and the format of their content.
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Commenting_ClassCommentSniff extends PEAR_Sniffs_Commenting_FileCommentSniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + $tokens = $phpcsFile->getTokens(); + $type = strtolower($tokens[$stackPtr]['content']); + $errorData = array($type); + $find = array( + T_ABSTRACT, + T_WHITESPACE, + T_FINAL, + ); + + // Extract the class comment docblock. + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); + + if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { + $error = 'You must use "/**" style comments for a %s comment'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle', $errorData); + return; + } else if ($commentEnd === false + || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT + ) { + $phpcsFile->addError('Missing %s doc comment', $stackPtr, 'Missing', $errorData); + return; + } + + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + + // Distinguish file and class comment. + $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1)); + if ($prevClassToken === false) { + // This is the first class token in this file, need extra checks. + $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true); + if ($prevNonComment !== false) { + $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1)); + if ($prevComment === false) { + // There is only 1 doc comment between open tag and class token. + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext( + T_WHITESPACE, + ($newlineToken + 1), + $stackPtr, + false, + $phpcsFile->eolChar + ); + + if ($newlineToken !== false) { + // Blank line between the class and the doc block. + // The doc block is most likely a file comment. + $error = 'Missing %s doc comment'; + $phpcsFile->addError($error, ($stackPtr + 1), 'Missing', $errorData); + return; + } + }//end if + }//end if + }//end if + }//end if + + $comment = $phpcsFile->getTokensAsString( + $commentStart, + ($commentEnd - $commentStart + 1) + ); + + // Parse the class comment.docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Doc comment is empty for %s'; + $phpcsFile->addError($error, $commentStart, 'Empty', $errorData); + return; + } + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before %s comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort', $errorData); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in %s comments'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingAfterShort', $errorData); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in %s comments'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags', $errorData); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Check each tag. + $this->processTags($commentStart, $commentEnd); + + }//end process() + + + /** + * Process the version tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processVersion($errorPos) + { + $version = $this->commentParser->getVersion(); + if ($version !== null) { + $content = $version->getContent(); + $matches = array(); + if (empty($content) === true) { + $error = 'Content missing for @version tag in doc comment'; + $this->currentFile->addError($error, $errorPos, 'EmptyVersion'); + } else if ((strstr($content, 'Release:') === false)) { + $error = 'Invalid version "%s" in doc comment; consider "Release: " instead'; + $data = array($content); + $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data); + } + } + + }//end processVersion() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php new file mode 100644 index 000000000..267dfe946 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php @@ -0,0 +1,797 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); +} + +/** + * Parses and verifies the doc comments for files. + * + * Verifies that : + *
    + *
  • A doc comment exists.
  • + *
  • There is a blank newline after the short description.
  • + *
  • There is a blank newline between the long and short description.
  • + *
  • There is a blank newline between the long description and tags.
  • + *
  • A PHP version is specified.
  • + *
  • Check the order of the tags.
  • + *
  • Check the indentation of each tag.
  • + *
  • Check required and optional tags and the format of their content.
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +class PEAR_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The header comment parser for the current file. + * + * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + /** + * Tags in correct order and related info. + * + * @var array + */ + protected $tags = array( + 'category' => array( + 'required' => true, + 'allow_multiple' => false, + 'order_text' => 'precedes @package', + ), + 'package' => array( + 'required' => true, + 'allow_multiple' => false, + 'order_text' => 'follows @category', + ), + 'subpackage' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @package', + ), + 'author' => array( + 'required' => true, + 'allow_multiple' => true, + 'order_text' => 'follows @subpackage (if used) or @package', + ), + 'copyright' => array( + 'required' => false, + 'allow_multiple' => true, + 'order_text' => 'follows @author', + ), + 'license' => array( + 'required' => true, + 'allow_multiple' => false, + 'order_text' => 'follows @copyright (if used) or @author', + ), + 'version' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @license', + ), + 'link' => array( + 'required' => true, + 'allow_multiple' => true, + 'order_text' => 'follows @version', + ), + 'see' => array( + 'required' => false, + 'allow_multiple' => true, + 'order_text' => 'follows @link', + ), + 'since' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @see (if used) or @link', + ), + 'deprecated' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @since (if used) or @see (if used) or @link', + ), + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + + // Find the next non whitespace token. + $commentStart + = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + + // Allow declare() statements at the top of the file. + if ($tokens[$commentStart]['code'] === T_DECLARE) { + $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($commentStart + 1)); + $commentStart + = $phpcsFile->findNext(T_WHITESPACE, ($semicolon + 1), null, true); + } + + // Ignore vim header. + if ($tokens[$commentStart]['code'] === T_COMMENT) { + if (strstr($tokens[$commentStart]['content'], 'vim:') !== false) { + $commentStart = $phpcsFile->findNext( + T_WHITESPACE, + ($commentStart + 1), + null, + true + ); + } + } + + $errorToken = ($stackPtr + 1); + if (isset($tokens[$errorToken]) === false) { + $errorToken--; + } + + if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) { + // We are only interested if this is the first open tag. + return; + } else if ($tokens[$commentStart]['code'] === T_COMMENT) { + $error = 'You must use "/**" style comments for a file comment'; + $phpcsFile->addError($error, $errorToken, 'WrongStyle'); + return; + } else if ($commentStart === false + || $tokens[$commentStart]['code'] !== T_DOC_COMMENT + ) { + $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); + return; + } else { + + // Extract the header comment docblock. + $commentEnd = $phpcsFile->findNext( + T_DOC_COMMENT, + ($commentStart + 1), + null, + true + ); + + $commentEnd--; + + // Check if there is only 1 doc comment between the + // open tag and class token. + $nextToken = array( + T_ABSTRACT, + T_CLASS, + T_FUNCTION, + T_DOC_COMMENT, + ); + + $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1)); + if ($commentNext !== false + && $tokens[$commentNext]['code'] !== T_DOC_COMMENT + ) { + // Found a class token right after comment doc block. + $newlineToken = $phpcsFile->findNext( + T_WHITESPACE, + ($commentEnd + 1), + $commentNext, + false, + $phpcsFile->eolChar + ); + + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext( + T_WHITESPACE, + ($newlineToken + 1), + $commentNext, + false, + $phpcsFile->eolChar + ); + + if ($newlineToken === false) { + // No blank line between the class token and the doc block. + // The doc block is most likely a class comment. + $error = 'Missing file doc comment'; + $phpcsFile->addError($error, $errorToken, 'Missing'); + return; + } + } + }//end if + + $comment = $phpcsFile->getTokensAsString( + $commentStart, + ($commentEnd - $commentStart + 1) + ); + + // Parse the header comment docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'File doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before file comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBefore'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in file comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'DescriptionSpacing'); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in file comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Check the PHP Version. + $this->processPHPVersion($commentStart, $commentEnd, $long); + + // Check each tag. + $this->processTags($commentStart, $commentEnd); + }//end if + + }//end process() + + + /** + * Check that the PHP version is specified. + * + * @param int $commentStart Position in the stack where the comment started. + * @param int $commentEnd Position in the stack where the comment ended. + * @param string $commentText The text of the function comment. + * + * @return void + */ + protected function processPHPVersion($commentStart, $commentEnd, $commentText) + { + if (strstr(strtolower($commentText), 'php version') === false) { + $error = 'PHP version not specified'; + $this->currentFile->addWarning($error, $commentEnd, 'MissingVersion'); + } + + }//end processPHPVersion() + + + /** + * Processes each required or optional tag. + * + * @param int $commentStart Position in the stack where the comment started. + * @param int $commentEnd Position in the stack where the comment ended. + * + * @return void + */ + protected function processTags($commentStart, $commentEnd) + { + $docBlock = (get_class($this) === 'PEAR_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; + $foundTags = $this->commentParser->getTagOrders(); + $orderIndex = 0; + $indentation = array(); + $longestTag = 0; + $errorPos = 0; + + foreach ($this->tags as $tag => $info) { + + // Required tag missing. + if ($info['required'] === true && in_array($tag, $foundTags) === false) { + $error = 'Missing @%s tag in %s comment'; + $data = array( + $tag, + $docBlock, + ); + $this->currentFile->addError($error, $commentEnd, 'MissingTag', $data); + continue; + } + + // Get the line number for current tag. + $tagName = ucfirst($tag); + if ($info['allow_multiple'] === true) { + $tagName .= 's'; + } + + $getMethod = 'get'.$tagName; + $tagElement = $this->commentParser->$getMethod(); + if (is_null($tagElement) === true || empty($tagElement) === true) { + continue; + } + + $errorPos = $commentStart; + if (is_array($tagElement) === false) { + $errorPos = ($commentStart + $tagElement->getLine()); + } + + // Get the tag order. + $foundIndexes = array_keys($foundTags, $tag); + + if (count($foundIndexes) > 1) { + // Multiple occurrence not allowed. + if ($info['allow_multiple'] === false) { + $error = 'Only 1 @%s tag is allowed in a %s comment'; + $data = array( + $tag, + $docBlock, + ); + $this->currentFile->addError($error, $errorPos, 'DuplicateTag', $data); + } else { + // Make sure same tags are grouped together. + $i = 0; + $count = $foundIndexes[0]; + foreach ($foundIndexes as $index) { + if ($index !== $count) { + $errorPosIndex + = ($errorPos + $tagElement[$i]->getLine()); + $error = '@%s tags must be grouped together'; + $data = array($tag); + $this->currentFile->addError($error, $errorPosIndex, 'TagsNotGrouped', $data); + } + + $i++; + $count++; + } + } + }//end if + + // Check tag order. + if ($foundIndexes[0] > $orderIndex) { + $orderIndex = $foundIndexes[0]; + } else { + if (is_array($tagElement) === true && empty($tagElement) === false) { + $errorPos += $tagElement[0]->getLine(); + } + + $error = 'The @%s tag is in the wrong order; the tag %s'; + $data = array( + $tag, + $info['order_text'], + ); + $this->currentFile->addError($error, $errorPos, 'WrongTagOrder', $data); + } + + // Store the indentation for checking. + $len = strlen($tag); + if ($len > $longestTag) { + $longestTag = $len; + } + + if (is_array($tagElement) === true) { + foreach ($tagElement as $key => $element) { + $indentation[] = array( + 'tag' => $tag, + 'space' => $this->getIndentation($tag, $element), + 'line' => $element->getLine(), + ); + } + } else { + $indentation[] = array( + 'tag' => $tag, + 'space' => $this->getIndentation($tag, $tagElement), + ); + } + + $method = 'process'.$tagName; + if (method_exists($this, $method) === true) { + // Process each tag if a method is defined. + call_user_func(array($this, $method), $errorPos); + } else { + if (is_array($tagElement) === true) { + foreach ($tagElement as $key => $element) { + $element->process( + $this->currentFile, + $commentStart, + $docBlock + ); + } + } else { + $tagElement->process( + $this->currentFile, + $commentStart, + $docBlock + ); + } + } + }//end foreach + + foreach ($indentation as $indentInfo) { + if ($indentInfo['space'] !== 0 + && $indentInfo['space'] !== ($longestTag + 1) + ) { + $expected = (($longestTag - strlen($indentInfo['tag'])) + 1); + $space = ($indentInfo['space'] - strlen($indentInfo['tag'])); + $error = '@%s tag comment indented incorrectly; expected %s spaces but found %s'; + $data = array( + $indentInfo['tag'], + $expected, + $space, + ); + + $getTagMethod = 'get'.ucfirst($indentInfo['tag']); + + if ($this->tags[$indentInfo['tag']]['allow_multiple'] === true) { + $line = $indentInfo['line']; + } else { + $tagElem = $this->commentParser->$getTagMethod(); + $line = $tagElem->getLine(); + } + + $this->currentFile->addError($error, ($commentStart + $line), 'TagIndent', $data); + } + } + + }//end processTags() + + + /** + * Get the indentation information of each tag. + * + * @param string $tagName The name of the + * doc comment + * element. + * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment + * element. + * + * @return void + */ + protected function getIndentation($tagName, $tagElement) + { + if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) { + if ($tagElement->getContent() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' ')); + } + } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) { + if ($tagElement->getValue() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' ')); + } + } + + return 0; + + }//end getIndentation() + + + /** + * Process the category tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processCategory($errorPos) + { + $category = $this->commentParser->getCategory(); + if ($category !== null) { + $content = $category->getContent(); + if ($content !== '') { + if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + $newContent = str_replace(' ', '_', $content); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = ucfirst($firstBit).'_'; + foreach ($nameBits as $bit) { + $newName .= ucfirst($bit).'_'; + } + + $error = 'Category name "%s" is not valid; consider "%s" instead'; + $validName = trim($newName, '_'); + $data = array( + $content, + $validName, + ); + $this->currentFile->addError($error, $errorPos, 'InvalidCategory', $data); + } + } else { + $error = '@category tag must contain a name'; + $this->currentFile->addError($error, $errorPos, 'EmptyCategory'); + } + } + + }//end processCategory() + + + /** + * Process the package tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processPackage($errorPos) + { + $package = $this->commentParser->getPackage(); + if ($package === null) { + return; + } + + $content = $package->getContent(); + if ($content === '') { + $error = '@package tag must contain a name'; + $this->currentFile->addError($error, $errorPos, 'EmptyPackage'); + return; + } + + if (PHP_CodeSniffer::isUnderscoreName($content) === true) { + return; + } + + $newContent = str_replace(' ', '_', $content); + $newContent = preg_replace('/[^A-Za-z_]/', '', $newContent); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $error = 'Package name "%s" is not valid; consider "%s" instead'; + $validName = trim($newName, '_'); + $data = array( + $content, + $validName, + ); + $this->currentFile->addError($error, $errorPos, 'InvalidPackage', $data); + + }//end processPackage() + + + /** + * Process the subpackage tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processSubpackage($errorPos) + { + $package = $this->commentParser->getSubpackage(); + if ($package !== null) { + $content = $package->getContent(); + if ($content !== '') { + if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + $newContent = str_replace(' ', '_', $content); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $error = 'Subpackage name "%s" is not valid; consider "%s" instead'; + $validName = trim($newName, '_'); + $data = array( + $content, + $validName, + ); + $this->currentFile->addError($error, $errorPos, 'InvalidSubpackage', $data); + } + } else { + $error = '@subpackage tag must contain a name'; + $this->currentFile->addError($error, $errorPos, 'EmptySubpackage'); + } + } + + }//end processSubpackage() + + + /** + * Process the author tag(s) that this header comment has. + * + * This function is different from other _process functions + * as $authors is an array of SingleElements, so we work out + * the errorPos for each element separately + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processAuthors($commentStart) + { + $authors = $this->commentParser->getAuthors(); + // Report missing return. + if (empty($authors) === false) { + foreach ($authors as $author) { + $errorPos = ($commentStart + $author->getLine()); + $content = $author->getContent(); + if ($content !== '') { + $local = '\da-zA-Z-_+'; + // Dot character cannot be the first or last character + // in the local-part. + $localMiddle = $local.'.\w'; + if (preg_match('/^([^<]*)\s+<(['.$local.'](['.$localMiddle.']*['.$local.'])*@[\da-zA-Z][-.\w]*[\da-zA-Z]\.[a-zA-Z]{2,7})>$/', $content) === 0) { + $error = 'Content of the @author tag must be in the form "Display Name "'; + $this->currentFile->addError($error, $errorPos, 'InvalidAuthors'); + } + } else { + $error = 'Content missing for @author tag in %s comment'; + $docBlock = (get_class($this) === 'PEAR_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; + $data = array($docBlock); + $this->currentFile->addError($error, $errorPos, 'EmptyAuthors', $data); + } + } + } + + }//end processAuthors() + + + /** + * Process the copyright tags. + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processCopyrights($commentStart) + { + $copyrights = $this->commentParser->getCopyrights(); + foreach ($copyrights as $copyright) { + $errorPos = ($commentStart + $copyright->getLine()); + $content = $copyright->getContent(); + if ($content !== '') { + $matches = array(); + if (preg_match('/^([0-9]{4})((.{1})([0-9]{4}))? (.+)$/', $content, $matches) !== 0) { + // Check earliest-latest year order. + if ($matches[3] !== '') { + if ($matches[3] !== '-') { + $error = 'A hyphen must be used between the earliest and latest year'; + $this->currentFile->addError($error, $errorPos, 'CopyrightHyphen'); + } + + if ($matches[4] !== '' && $matches[4] < $matches[1]) { + $error = "Invalid year span \"$matches[1]$matches[3]$matches[4]\" found; consider \"$matches[4]-$matches[1]\" instead"; + $this->currentFile->addWarning($error, $errorPos, 'InvalidCopyright'); + } + } + } else { + $error = '@copyright tag must contain a year and the name of the copyright holder'; + $this->currentFile->addError($error, $errorPos, 'EmptyCopyright'); + } + } else { + $error = '@copyright tag must contain a year and the name of the copyright holder'; + $this->currentFile->addError($error, $errorPos, 'EmptyCopyright'); + }//end if + }//end if + + }//end processCopyrights() + + + /** + * Process the license tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processLicense($errorPos) + { + $license = $this->commentParser->getLicense(); + if ($license !== null) { + $value = $license->getValue(); + $comment = $license->getComment(); + if ($value === '' || $comment === '') { + $error = '@license tag must contain a URL and a license name'; + $this->currentFile->addError($error, $errorPos, 'EmptyLicense'); + } + } + + }//end processLicense() + + + /** + * Process the version tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processVersion($errorPos) + { + $version = $this->commentParser->getVersion(); + if ($version !== null) { + $content = $version->getContent(); + $matches = array(); + if (empty($content) === true) { + $error = 'Content missing for @version tag in file comment'; + $this->currentFile->addError($error, $errorPos, 'EmptyVersion'); + } else if (strstr($content, 'CVS:') === false + && strstr($content, 'SVN:') === false + && strstr($content, 'GIT:') === false + ) { + $error = 'Invalid version "%s" in file comment; consider "CVS: " or "SVN: " or "GIT: " instead'; + $data = array($content); + $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data); + } + } + + }//end processVersion() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php new file mode 100644 index 000000000..41b175413 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php @@ -0,0 +1,490 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found'); +} + +/** + * Parses and verifies the doc comments for functions. + * + * Verifies that : + *
    + *
  • A comment exists
  • + *
  • There is a blank newline after the short description.
  • + *
  • There is a blank newline between the long and short description.
  • + *
  • There is a blank newline between the long description and tags.
  • + *
  • Parameter names represent those in the method.
  • + *
  • Parameter comments are in the correct order
  • + *
  • Parameter comments are complete
  • + *
  • A space is present before the first and after the last parameter
  • + *
  • A return type exists
  • + *
  • There must be one blank line between body and headline comments.
  • + *
  • Any throw tag must have an exception class.
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The name of the method that we are currently processing. + * + * @var string + */ + private $_methodName = ''; + + /** + * The position in the stack where the function token was found. + * + * @var int + */ + private $_functionToken = null; + + /** + * The position in the stack where the class token was found. + * + * @var int + */ + private $_classToken = null; + + /** + * The function comment parser for the current method. + * + * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $find = array( + T_COMMENT, + T_DOC_COMMENT, + T_CLASS, + T_FUNCTION, + T_OPEN_TAG, + ); + + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1)); + + if ($commentEnd === false) { + return; + } + + $this->currentFile = $phpcsFile; + $tokens = $phpcsFile->getTokens(); + + // If the token that we found was a class or a function, then this + // function has no doc comment. + $code = $tokens[$commentEnd]['code']; + + if ($code === T_COMMENT) { + $error = 'You must use "/**" style comments for a function comment'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + return; + } else if ($code !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); + return; + } + + // If there is any code between the function keyword and the doc block + // then the doc block is not for us. + $ignore = PHP_CodeSniffer_Tokens::$scopeModifiers; + $ignore[] = T_STATIC; + $ignore[] = T_WHITESPACE; + $ignore[] = T_ABSTRACT; + $ignore[] = T_FINAL; + $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); + if ($prevToken !== $commentEnd) { + $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); + return; + } + + $this->_functionToken = $stackPtr; + + $this->_classToken = null; + foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) { + if ($condition === T_CLASS || $condition === T_INTERFACE) { + $this->_classToken = $condPtr; + break; + } + } + + // If the first T_OPEN_TAG is right before the comment, it is probably + // a file comment. + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); + if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { + // Is this the first open tag? + if ($stackPtr === 0 || $phpcsFile->findPrevious(T_OPEN_TAG, ($prevToken - 1)) === false) { + $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); + return; + } + } + + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + $this->_methodName = $phpcsFile->getDeclarationName($stackPtr); + + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Function doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + $this->processParams($commentStart); + $this->processReturn($commentStart, $commentEnd); + $this->processThrows($commentStart); + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before function comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in function comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingAfterShort'); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $params = $this->commentParser->getTagOrders(); + if (count($params) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in function comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + }//end process() + + + /** + * Process any throw tags that this function comment has. + * + * @param int $commentStart The position in the stack where the + * comment started. + * + * @return void + */ + protected function processThrows($commentStart) + { + if (count($this->commentParser->getThrows()) === 0) { + return; + } + + foreach ($this->commentParser->getThrows() as $throw) { + + $exception = $throw->getValue(); + $errorPos = ($commentStart + $throw->getLine()); + + if ($exception === '') { + $error = '@throws tag must contain the exception class name'; + $this->currentFile->addError($error, $errorPos, 'EmptyThrows'); + } + } + + }//end processThrows() + + + /** + * Process the return comment of this function comment. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processReturn($commentStart, $commentEnd) + { + // Skip constructor and destructor. + $className = ''; + if ($this->_classToken !== null) { + $className = $this->currentFile->getDeclarationName($this->_classToken); + $className = strtolower(ltrim($className, '_')); + } + + $methodName = strtolower(ltrim($this->_methodName, '_')); + $isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct'); + + if ($isSpecialMethod === false && $methodName !== $className) { + // Report missing return tag. + if ($this->commentParser->getReturn() === null) { + $error = 'Missing @return tag in function comment'; + $this->currentFile->addError($error, $commentEnd, 'MissingReturn'); + } else if (trim($this->commentParser->getReturn()->getRawContent()) === '') { + $error = '@return tag is empty in function comment'; + $errorPos = ($commentStart + $this->commentParser->getReturn()->getLine()); + $this->currentFile->addError($error, $errorPos, 'EmptyReturn'); + } + } + + }//end processReturn() + + + /** + * Process the function parameter comments. + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processParams($commentStart) + { + $realParams = $this->currentFile->getMethodParameters($this->_functionToken); + + $params = $this->commentParser->getParams(); + $foundParams = array(); + + if (empty($params) === false) { + + $lastParm = (count($params) - 1); + if (substr_count($params[$lastParm]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) { + $error = 'Last parameter comment requires a blank newline after it'; + $errorPos = ($params[$lastParm]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos, 'SpacingAfterParams'); + } + + // Parameters must appear immediately after the comment. + if ($params[0]->getOrder() !== 2) { + $error = 'Parameters must appear immediately after the comment'; + $errorPos = ($params[0]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParams'); + } + + $previousParam = null; + $spaceBeforeVar = 10000; + $spaceBeforeComment = 10000; + $longestType = 0; + $longestVar = 0; + + foreach ($params as $param) { + + $paramComment = trim($param->getComment()); + $errorPos = ($param->getLine() + $commentStart); + + // Make sure that there is only one space before the var type. + if ($param->getWhitespaceBeforeType() !== ' ') { + $error = 'Expected 1 space before variable type'; + $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParamType'); + } + + $spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' '); + if ($spaceCount < $spaceBeforeVar) { + $spaceBeforeVar = $spaceCount; + $longestType = $errorPos; + } + + $spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' '); + + if ($spaceCount < $spaceBeforeComment && $paramComment !== '') { + $spaceBeforeComment = $spaceCount; + $longestVar = $errorPos; + } + + // Make sure they are in the correct order, + // and have the correct name. + $pos = $param->getPosition(); + + $paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]'; + + if ($previousParam !== null) { + $previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN'; + + // Check to see if the parameters align properly. + if ($param->alignsVariableWith($previousParam) === false) { + $error = 'The variable names for parameters %s (%s) and %s (%s) do not align'; + $data = array( + $previousName, + ($pos - 1), + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'ParameterNamesNotAligned', $data); + } + + if ($param->alignsCommentWith($previousParam) === false) { + $error = 'The comments for parameters %s (%s) and %s (%s) do not align'; + $data = array( + $previousName, + ($pos - 1), + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'ParameterCommentsNotAligned', $data); + } + }//end if + + // Make sure the names of the parameter comment matches the + // actual parameter. + if (isset($realParams[($pos - 1)]) === true) { + $realName = $realParams[($pos - 1)]['name']; + $foundParams[] = $realName; + + // Append ampersand to name if passing by reference. + if ($realParams[($pos - 1)]['pass_by_reference'] === true) { + $realName = '&'.$realName; + } + + if ($realName !== $paramName) { + $code = 'ParamNameNoMatch'; + $data = array( + $paramName, + $realName, + $pos, + ); + + $error = 'Doc comment for var %s does not match '; + if (strtolower($paramName) === strtolower($realName)) { + $error .= 'case of '; + $code = 'ParamNameNoCaseMatch'; + } + + $error .= 'actual variable name %s at position %s'; + + $this->currentFile->addError($error, $errorPos, $code, $data); + } + } else { + // We must have an extra parameter comment. + $error = 'Superfluous doc comment at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'ExtraParamComment'); + } + + if ($param->getVarName() === '') { + $error = 'Missing parameter name at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'MissingParamName'); + } + + if ($param->getType() === '') { + $error = 'Missing type at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'MissingParamType'); + } + + if ($paramComment === '') { + $error = 'Missing comment for param "%s" at position %s'; + $data = array( + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'MissingParamComment', $data); + } + + $previousParam = $param; + + }//end foreach + + if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest type'; + $this->currentFile->addError($error, $longestType, 'SpacingAfterLongType'); + } + + if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest variable name'; + $this->currentFile->addError($error, $longestVar, 'SpacingAfterLongName'); + } + + }//end if + + $realNames = array(); + foreach ($realParams as $realParam) { + $realNames[] = $realParam['name']; + } + + // Report and missing comments. + $diff = array_diff($realNames, $foundParams); + foreach ($diff as $neededParam) { + if (count($params) !== 0) { + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); + } else { + $errorPos = $commentStart; + } + + $error = 'Doc comment for "%s" missing'; + $data = array($neededParam); + $this->currentFile->addError($error, $errorPos, 'MissingParamTag', $data); + } + + }//end processParams() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php new file mode 100644 index 000000000..d5ed16d1e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php @@ -0,0 +1,70 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PHP_CodeSniffer_Sniffs_PEAR_Commenting_InlineCommentSniff. + * + * Checks that no perl-style comments are used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_COMMENT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content']{0} === '#') { + $error = 'Perl-style comments are not allowed. Use "// Comment."'; + $error .= ' or "/* comment */" instead.'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php new file mode 100644 index 000000000..7b91e6286 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php @@ -0,0 +1,67 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); +} + +/** + * Verifies that control statements conform to their coding standards. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff +{ + + /** + * If true, comments will be ignored if they are found in the code. + * + * @var boolean + */ + public $ignoreComments = true; + + + /** + * Returns the patterns that this test wishes to verify. + * + * @return array(string) + */ + protected function getPatterns() + { + return array( + 'do {EOL...} while (...);EOL', + 'while (...) {EOL', + 'for (...) {EOL', + 'if (...) {EOL', + 'foreach (...) {EOL', + '} else if (...) {EOL', + '} elseif (...) {EOL', + '} else {EOL', + 'do {EOL', + ); + + }//end getPatterns() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php new file mode 100644 index 000000000..be99d2cfa --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php @@ -0,0 +1,189 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_ControlStructures_MultiLineConditionSniff. + * + * Ensure multi-line IF conditions are defined correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_ControlStructures_MultiLineConditionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_ELSEIF, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We need to work out how far indented the if statement + // itself is, so we can work out how far to indent conditions. + $statementIndent = 0; + for ($i = ($stackPtr - 1); $i >= 0; $i--) { + if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { + $i++; + break; + } + } + + if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) { + $statementIndent = strlen($tokens[$i]['content']); + } + + // Each line between the parenthesis should be indented 4 spaces + // and start with an operator, unless the line is inside a + // function call, in which case it is ignored. + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + $lastLine = $tokens[$openBracket]['line']; + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + if ($tokens[$i]['line'] !== $lastLine) { + if ($tokens[$i]['line'] === $tokens[$closeBracket]['line']) { + $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true); + if ($next !== $closeBracket) { + // Closing bracket is on the same line as a condition. + $error = 'Closing parenthesis of a multi-line IF statement must be on a new line'; + $phpcsFile->addError($error, $i, 'CloseBracketNewLine'); + $expectedIndent = ($statementIndent + $this->indent); + } else { + // Closing brace needs to be indented to the same level + // as the function. + $expectedIndent = $statementIndent; + } + } else { + $expectedIndent = ($statementIndent + $this->indent); + } + + // We changed lines, so this should be a whitespace indent token. + if ($tokens[$i]['code'] !== T_WHITESPACE) { + $foundIndent = 0; + } else { + $foundIndent = strlen($tokens[$i]['content']); + } + + if ($expectedIndent !== $foundIndent) { + $error = 'Multi-line IF statement not indented correctly; expected %s spaces but found %s'; + $data = array( + $expectedIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $i, 'Alignment', $data); + } + + if ($tokens[$i]['line'] !== $tokens[$closeBracket]['line']) { + $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true); + if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$booleanOperators) === false) { + $error = 'Each line in a multi-line IF statement must begin with a boolean operator'; + $phpcsFile->addError($error, $i, 'StartWithBoolean'); + } + } + + $lastLine = $tokens[$i]['line']; + }//end if + + if ($tokens[$i]['code'] === T_STRING) { + $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + // This is a function call, so skip to the end as they + // have their own indentation rules. + $i = $tokens[$next]['parenthesis_closer']; + $lastLine = $tokens[$i]['line']; + continue; + } + } + }//end for + + // From here on, we are checking the spacing of the opening and closing + // braces. If this IF statement does not use braces, we end here. + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + return; + } + + // The opening brace needs to be one space away from the closing parenthesis. + if ($tokens[($closeBracket + 1)]['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($tokens[($closeBracket + 1)]['content'] === $phpcsFile->eolChar) { + $length = -1; + } else { + $length = strlen($tokens[($closeBracket + 1)]['content']); + } + + if ($length !== 1) { + $data = array($length); + $code = 'SpaceBeforeOpenBrace'; + + $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found '; + if ($length === -1) { + $error .= 'newline'; + $code = 'NewlineBeforeOpenBrace'; + } else { + $error .= '%s spaces'; + } + + $phpcsFile->addError($error, ($closeBracket + 1), $code, $data); + } + + // And just in case they do something funny before the brace... + $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true); + if ($next !== false + && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET + && $tokens[$next]['code'] !== T_COLON + ) { + $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement'; + $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php new file mode 100644 index 000000000..187061d34 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php @@ -0,0 +1,137 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Files_IncludingFileSniff. + * + * Checks that the include_once is used in conditional situations, and + * require_once is used elsewhere. Also checks that brackets do not surround + * the file being included. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Files_IncludingFileSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * Conditions that should use include_once + * + * @var array(int) + */ + private static $_conditions = array( + T_IF, + T_ELSE, + T_ELSEIF, + T_SWITCH, + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_INCLUDE_ONCE, + T_REQUIRE_ONCE, + T_REQUIRE, + T_INCLUDE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS) { + $error = '"%s" is a statement not a function; no parentheses are required'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $stackPtr, 'BracketsNotRequired', $data); + } + + $inCondition = (count($tokens[$stackPtr]['conditions']) !== 0) ? true : false; + + // Check to see if this including statement is within the parenthesis + // of a condition. If that's the case then we need to process it as being + // within a condition, as they are checking the return value. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + foreach ($tokens[$stackPtr]['nested_parenthesis'] as $left => $right) { + if (isset($tokens[$left]['parenthesis_owner']) === true) { + $inCondition = true; + } + } + } + + // Check to see if they are assigning the return value of this + // including call. If they are then they are probably checking it, so + // it's conditional. + $previous = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if (in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { + // The have assigned the return value to it, so its conditional. + $inCondition = true; + } + + $tokenCode = $tokens[$stackPtr]['code']; + if ($inCondition === true) { + // We are inside a conditional statement. We need an include_once. + if ($tokenCode === T_REQUIRE_ONCE) { + $error = 'File is being conditionally included; '; + $error .= 'use "include_once" instead'; + $phpcsFile->addError($error, $stackPtr, 'UseIncludeOnce'); + } else if ($tokenCode === T_REQUIRE) { + $error = 'File is being conditionally included; '; + $error .= 'use "include" instead'; + $phpcsFile->addError($error, $stackPtr, 'UseInclude'); + } + } else { + // We are unconditionally including, we need a require_once. + if ($tokenCode === T_INCLUDE_ONCE) { + $error = 'File is being unconditionally included; '; + $error .= 'use "require_once" instead'; + $phpcsFile->addError($error, $stackPtr, 'UseRequireOnce'); + } else if ($tokenCode === T_INCLUDE) { + $error = 'File is being unconditionally included; '; + $error .= 'use "require" instead'; + $phpcsFile->addError($error, $stackPtr, 'UseRequire'); + } + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php new file mode 100644 index 000000000..292964067 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php @@ -0,0 +1,120 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Formatting_MultiLineAssignmentSniff. + * + * If an assignment goes over two lines, ensure the equal sign is indented. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Formatting_MultiLineAssignmentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_EQUAL); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Equal sign can't be the last thing on the line. + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($next === false) { + // Bad assignment. + return; + } + + if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { + $error = 'Multi-line assignments must have the equal sign on the second line'; + $phpcsFile->addError($error, $stackPtr, 'EqualSignLine'); + return; + } + + // Make sure it is the first thing on the line, otherwise we ignore it. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), false, true); + if ($prev === false) { + // Bad assignment. + return; + } + + if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { + return; + } + + // Find the required indent based on the ident of the previous line. + $assignmentIndent = 0; + $prevLine = $tokens[$prev]['line']; + for ($i = ($prev - 1); $i >= 0; $i--) { + if ($tokens[$i]['line'] !== $prevLine) { + $i++; + break; + } + } + + if ($tokens[$i]['code'] === T_WHITESPACE) { + $assignmentIndent = strlen($tokens[$i]['content']); + } + + // Find the actual indent. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1)); + + $expectedIndent = ($assignmentIndent + $this->indent); + $foundIndent = strlen($tokens[$prev]['content']); + if ($foundIndent !== $expectedIndent) { + $error = 'Multi-line assignment not indented correctly; expected %s spaces but found %s'; + $data = array( + $expectedIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $stackPtr, 'Indent', $data); + } + + }//end process() + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php new file mode 100644 index 000000000..5001309a7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php @@ -0,0 +1,335 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Functions_FunctionCallSignatureSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Functions_FunctionCallSignatureSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + /** + * If TRUE, multiple arguments can be defined per line in a multi-line call. + * + * @var bool + */ + public $allowMultipleArguments = true; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Find the next non-empty token. + $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + + if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + // Not a function call. + return; + } + + if (isset($tokens[$openBracket]['parenthesis_closer']) === false) { + // Not a function call. + return; + } + + // Find the previous non-empty token. + $search = PHP_CodeSniffer_Tokens::$emptyTokens; + $search[] = T_BITWISE_AND; + $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true); + if ($tokens[$previous]['code'] === T_FUNCTION) { + // It's a function definition, not a function call. + return; + } + + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + if (($stackPtr + 1) !== $openBracket) { + // Checking this: $value = my_function[*](...). + $error = 'Space before opening parenthesis of function call prohibited'; + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeOpenBracket'); + } + + $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true); + if ($tokens[$next]['code'] === T_SEMICOLON) { + if (in_array($tokens[($closeBracket + 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $error = 'Space after closing parenthesis of function call prohibited'; + $phpcsFile->addError($error, $closeBracket, 'SpaceAfterCloseBracket'); + } + } + + // Check if this is a single line or multi-line function call. + if ($this->isMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens) === true) { + $this->processMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); + } else { + $this->processSingleLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); + } + + }//end process() + + + /** + * Processes single-line calls. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $openBracket The position of the opening bracket + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) + { + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) { + return true; + } + + return false; + + }//end isMultiLineCall() + + + /** + * Processes single-line calls. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $openBracket The position of the opening bracket + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function processSingleLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) + { + if ($tokens[($openBracket + 1)]['code'] === T_WHITESPACE) { + // Checking this: $value = my_function([*]...). + $error = 'Space after opening parenthesis of function call prohibited'; + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpenBracket'); + } + + $closer = $tokens[$openBracket]['parenthesis_closer']; + + if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) { + // Checking this: $value = my_function(...[*]). + $between = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); + + // Only throw an error if there is some content between the parenthesis. + // i.e., Checking for this: $value = my_function(). + // If there is no content, then we would have thrown an error in the + // previous IF statement because it would look like this: + // $value = my_function( ). + if ($between !== $closer) { + $error = 'Space before closing parenthesis of function call prohibited'; + $phpcsFile->addError($error, $closer, 'SpaceBeforeCloseBracket'); + } + } + + }//end processSingleLineCall() + + + /** + * Processes multi-line calls. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $openBracket The position of the openning bracket + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function processMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) + { + // We need to work out how far indented the function + // call itself is, so we can work out how far to + // indent the arguments. + $functionIndent = 0; + for ($i = ($stackPtr - 1); $i >= 0; $i--) { + if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { + $i++; + break; + } + } + + if ($tokens[$i]['code'] === T_WHITESPACE) { + $functionIndent = strlen($tokens[$i]['content']); + } + + // Each line between the parenthesis should be indented n spaces. + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + $lastLine = $tokens[$openBracket]['line']; + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + // Skip nested function calls. + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + $i = $tokens[$i]['parenthesis_closer']; + $lastLine = $tokens[$i]['line']; + continue; + } + + if ($tokens[$i]['line'] !== $lastLine) { + $lastLine = $tokens[$i]['line']; + + // Ignore heredoc indentation. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$heredocTokens) === true) { + continue; + } + + // Ignore multi-line string indentation. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { + if ($tokens[$i]['code'] === $tokens[($i - 1)]['code']) { + continue; + } + } + + // We changed lines, so this should be a whitespace indent token, but first make + // sure it isn't a blank line because we don't need to check indent unless there + // is actually some code to indent. + if ($tokens[$i]['code'] === T_WHITESPACE) { + $nextCode = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), ($closeBracket + 1), true); + if ($tokens[$nextCode]['line'] !== $lastLine) { + $error = 'Empty lines are not allowed in multi-line function calls'; + $phpcsFile->addError($error, $i, 'EmptyLine'); + continue; + } + } else { + $nextCode = $i; + } + + // Check if the next line contains an object operator, if so rely on + // the ObjectOperatorIndentSniff to test the indent. + if ($tokens[$nextCode]['type'] === 'T_OBJECT_OPERATOR') { + continue; + } + + if ($nextCode === $closeBracket) { + // Closing brace needs to be indented to the same level + // as the function call. + $expectedIndent = $functionIndent; + } else { + $expectedIndent = ($functionIndent + $this->indent); + } + + if ($tokens[$i]['code'] !== T_WHITESPACE) { + // Just check if it is a multi-line block comment. If so, we can + // calculate the indent from the whitespace before the content. + if ($tokens[$i]['code'] === T_COMMENT + && $tokens[($i - 1)]['code'] === T_COMMENT + ) { + $trimmed = ltrim($tokens[$i]['content']); + $foundIndent = (strlen($tokens[$i]['content']) - strlen($trimmed)); + } else { + $foundIndent = 0; + } + } else { + $foundIndent = strlen($tokens[$i]['content']); + } + + if ($expectedIndent !== $foundIndent) { + $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s'; + $data = array( + $expectedIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $i, 'Indent', $data); + } + }//end if + + // Skip the rest of a closure. + if ($tokens[$i]['code'] === T_CLOSURE) { + $i = $tokens[$i]['scope_closer']; + $lastLine = $tokens[$i]['line']; + continue; + } + + // Skip the rest of a short array. + if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) { + $i = $tokens[$i]['bracket_closer']; + $lastLine = $tokens[$i]['line']; + continue; + } + + if ($this->allowMultipleArguments === false && $tokens[$i]['code'] === T_COMMA) { + // Comma has to be the last token on the line. + $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), ($i + 1), $closeBracket, true); + if ($next !== false + && $tokens[$i]['line'] === $tokens[$next]['line'] + ) { + $error = 'Only one argument is allowed per line in a multi-line function call'; + $phpcsFile->addError($error, $next, 'MultipleArguments'); + } + } + }//end for + + if ($tokens[($openBracket + 1)]['content'] !== $phpcsFile->eolChar) { + $error = 'Opening parenthesis of a multi-line function call must be the last content on the line'; + $phpcsFile->addError($error, $stackPtr, 'ContentAfterOpenBracket'); + } + + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true); + if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { + $error = 'Closing parenthesis of a multi-line function call must be on a line by itself'; + $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); + } + + }//end processMultiLineCall() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php new file mode 100644 index 000000000..b46a7ee92 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php @@ -0,0 +1,337 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Functions_FunctionDeclarationSniff. + * + * Ensure single and multi-line function declarations are defined correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Functions_FunctionDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_FUNCTION, + T_CLOSURE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $spaces = 0; + if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { + $spaces = strlen($tokens[($stackPtr + 1)]['content']); + } + + if ($spaces !== 1) { + $error = 'Expected 1 space after FUNCTION keyword; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterFunction', $data); + } + + // Must be one space before and after USE keyword for closures. + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); + if ($use !== false) { + if ($tokens[($use + 1)]['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($tokens[($use + 1)]['content'] === "\t") { + $length = '\t'; + } else { + $length = strlen($tokens[($use + 1)]['content']); + } + + if ($length !== 1) { + $error = 'Expected 1 space after USE keyword; found %s'; + $data = array($length); + $phpcsFile->addError($error, $use, 'SpaceAfterUse', $data); + } + + if ($tokens[($use - 1)]['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($tokens[($use - 1)]['content'] === "\t") { + $length = '\t'; + } else { + $length = strlen($tokens[($use - 1)]['content']); + } + + if ($length !== 1) { + $error = 'Expected 1 space before USE keyword; found %s'; + $data = array($length); + $phpcsFile->addError($error, $use, 'SpaceBeforeUse', $data); + } + }//end if + }//end if + + // Check if this is a single line or multi-line declaration. + $singleLine = true; + if ($tokens[$openBracket]['line'] === $tokens[$closeBracket]['line']) { + // Closures may use the USE keyword and so be multi-line in this way. + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + if ($use !== false) { + // If the opening and closing parenthesis of the use statement + // are also on the same line, this is a single line declaration. + $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); + $close = $tokens[$open]['parenthesis_closer']; + if ($tokens[$open]['line'] !== $tokens[$close]['line']) { + $singleLine = false; + } + } + } + } else { + $singleLine = false; + } + + if ($singleLine === true) { + $this->processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens); + } else { + $this->processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens); + } + + }//end process() + + + /** + * Processes single-line declarations. + * + * Just uses the Generic BSD-Allman brace sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function processSingleLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) + { + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff not found'); + } + + $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff(); + } else { + if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff not found'); + } + + $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff(); + } + + $sniff->process($phpcsFile, $stackPtr); + + }//end processSingleLineDeclaration() + + + /** + * Processes mutli-line declarations. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) + { + // We need to work out how far indented the function + // declaration itself is, so we can work out how far to + // indent parameters. + $functionIndent = 0; + for ($i = ($stackPtr - 1); $i >= 0; $i--) { + if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { + $i++; + break; + } + } + + if ($tokens[$i]['code'] === T_WHITESPACE) { + $functionIndent = strlen($tokens[$i]['content']); + } + + // The closing parenthesis must be on a new line, even + // when checking abstract function definitions. + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + $prev = $phpcsFile->findPrevious( + T_WHITESPACE, + ($closeBracket - 1), + null, + true + ); + + if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) { + if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { + $error = 'The closing parenthesis of a multi-line function declaration must be on a new line'; + $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); + } + } + + // If this is a closure and is using a USE statement, the closing + // parenthesis we need to look at from now on is the closing parenthesis + // of the USE statement. + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); + if ($use !== false) { + $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); + $closeBracket = $tokens[$open]['parenthesis_closer']; + + $prev = $phpcsFile->findPrevious( + T_WHITESPACE, + ($closeBracket - 1), + null, + true + ); + + if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) { + if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { + $error = 'The closing parenthesis of a multi-line use declaration must be on a new line'; + $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); + } + } + }//end if + }//end if + + // Each line between the parenthesis should be indented 4 spaces. + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $lastLine = $tokens[$openBracket]['line']; + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + if ($tokens[$i]['line'] !== $lastLine) { + if ($i === $tokens[$stackPtr]['parenthesis_closer'] + || ($tokens[$i]['code'] === T_WHITESPACE + && (($i + 1) === $closeBracket + || ($i + 1) === $tokens[$stackPtr]['parenthesis_closer'])) + ) { + // Closing braces need to be indented to the same level + // as the function. + $expectedIndent = $functionIndent; + } else { + $expectedIndent = ($functionIndent + $this->indent); + } + + // We changed lines, so this should be a whitespace indent token. + if ($tokens[$i]['code'] !== T_WHITESPACE) { + $foundIndent = 0; + } else { + $foundIndent = strlen($tokens[$i]['content']); + } + + if ($expectedIndent !== $foundIndent) { + $error = 'Multi-line function declaration not indented correctly; expected %s spaces but found %s'; + $data = array( + $expectedIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $i, 'Indent', $data); + } + + $lastLine = $tokens[$i]['line']; + }//end if + + if ($tokens[$i]['code'] === T_ARRAY) { + // Skip arrays as they have their own indentation rules. + $i = $tokens[$i]['parenthesis_closer']; + $lastLine = $tokens[$i]['line']; + continue; + } + }//end for + + if (isset($tokens[$stackPtr]['scope_opener']) === true) { + // The openning brace needs to be one space away + // from the closing parenthesis. + $next = $tokens[($closeBracket + 1)]; + if ($next['code'] !== T_WHITESPACE) { + $length = 0; + } else if ($next['content'] === $phpcsFile->eolChar) { + $length = -1; + } else { + $length = strlen($next['content']); + } + + if ($length !== 1) { + $data = array($length); + $code = 'SpaceBeforeOpenBrace'; + + $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found '; + if ($length === -1) { + $error .= 'newline'; + $code = 'NewlineBeforeOpenBrace'; + } else { + $error .= '%s spaces'; + } + + $phpcsFile->addError($error, ($closeBracket + 1), $code, $data); + return; + } + + // And just in case they do something funny before the brace... + $next = $phpcsFile->findNext( + T_WHITESPACE, + ($closeBracket + 1), + null, + true + ); + + if ($next !== false && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET) { + $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration'; + $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace'); + } + }//end if + + }//end processMultiLineDeclaration() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php new file mode 100644 index 000000000..2b2f80fc8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php @@ -0,0 +1,108 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Functions_ValidDefaultValueSniff. + * + * A Sniff to ensure that parameters defined for a function that have a default + * value come at the end of the function signature. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_Functions_ValidDefaultValueSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $argStart = $tokens[$stackPtr]['parenthesis_opener']; + $argEnd = $tokens[$stackPtr]['parenthesis_closer']; + + // Flag for when we have found a default in our arg list. + // If there is a value without a default after this, it is an error. + $defaultFound = false; + + $nextArg = $argStart; + while (($nextArg = $phpcsFile->findNext(T_VARIABLE, ($nextArg + 1), $argEnd)) !== false) { + $argHasDefault = self::_argHasDefault($phpcsFile, $nextArg); + if (($argHasDefault === false) && ($defaultFound === true)) { + $error = 'Arguments with default values must be at the end of the argument list'; + $phpcsFile->addError($error, $nextArg, 'NotAtEnd'); + return; + } + + if ($argHasDefault === true) { + $defaultFound = true; + } + } + + }//end process() + + + /** + * Returns true if the passed argument has a default value. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $argPtr The position of the argument + * in the stack. + * + * @return bool + */ + private static function _argHasDefault(PHP_CodeSniffer_File $phpcsFile, $argPtr) + { + $tokens = $phpcsFile->getTokens(); + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($argPtr + 1), null, true); + if ($tokens[$nextToken]['code'] !== T_EQUAL) { + return false; + } + + return true; + + }//end _argHasDefault() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php new file mode 100644 index 000000000..b0f021f2b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php @@ -0,0 +1,115 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_NamingConventions_ValidClassNameSniff. + * + * Ensures class and interface names start with a capital letter + * and use _ separators. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_NamingConventions_ValidClassNameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $className = $phpcsFile->findNext(T_STRING, $stackPtr); + $name = trim($tokens[$className]['content']); + $errorData = array(ucfirst($tokens[$stackPtr]['content'])); + + // Make sure the first letter is a capital. + if (preg_match('|^[A-Z]|', $name) === 0) { + $error = '%s name must begin with a capital letter'; + $phpcsFile->addError($error, $stackPtr, 'StartWithCapital', $errorData); + } + + // Check that each new word starts with a capital as well, but don't + // check the first word, as it is checked above. + $validName = true; + $nameBits = explode('_', $name); + $firstBit = array_shift($nameBits); + foreach ($nameBits as $bit) { + if ($bit === '' || $bit{0} !== strtoupper($bit{0})) { + $validName = false; + break; + } + } + + if ($validName === false) { + // Strip underscores because they cause the suggested name + // to be incorrect. + $nameBits = explode('_', trim($name, '_')); + $firstBit = array_shift($nameBits); + if ($firstBit === '') { + $error = '%s name is not valid'; + $phpcsFile->addError($error, $stackPtr, 'Invalid', $errorData); + } else { + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + if ($bit !== '') { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + } + + $newName = rtrim($newName, '_'); + $error = '%s name is not valid; consider %s instead'; + $data = $errorData; + $data[] = $newName; + $phpcsFile->addError($error, $stackPtr, 'Invalid', $data); + } + }//end if + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php new file mode 100644 index 000000000..d016b5ff0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php @@ -0,0 +1,285 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff. + * + * Ensures method names are correct depending on whether they are public + * or private, and that functions are named correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * A list of all PHP magic methods. + * + * @var array + */ + protected $magicMethods = array( + 'construct', + 'destruct', + 'call', + 'callstatic', + 'get', + 'set', + 'isset', + 'unset', + 'sleep', + 'wakeup', + 'tostring', + 'set_state', + 'clone', + 'invoke', + 'call', + ); + + /** + * A list of all PHP magic functions. + * + * @var array + */ + protected $magicFunctions = array('autoload'); + + + /** + * Constructs a PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes the tokens within the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * @param int $currScope The position of the current scope. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + $className = $phpcsFile->getDeclarationName($currScope); + $errorData = array($className.'::'.$methodName); + + // Is this a magic method. i.e., is prefixed with "__" ? + if (preg_match('|^__|', $methodName) !== 0) { + $magicPart = strtolower(substr($methodName, 2)); + if (in_array($magicPart, $this->magicMethods) === false) { + $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; + $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData); + } + + return; + } + + // PHP4 constructors are allowed to break our rules. + if ($methodName === $className) { + return; + } + + // PHP4 destructors are allowed to break our rules. + if ($methodName === '_'.$className) { + return; + } + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + $isPublic = ($methodProps['scope'] === 'private') ? false : true; + $scope = $methodProps['scope']; + $scopeSpecified = $methodProps['scope_specified']; + + // If it's a private method, it must have an underscore on the front. + if ($isPublic === false && $methodName{0} !== '_') { + $error = 'Private method name "%s" must be prefixed with an underscore'; + $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData); + return; + } + + // If it's not a private method, it must not have an underscore on the front. + if ($isPublic === true && $scopeSpecified === true && $methodName{0} === '_') { + $error = '%s method name "%s" must not be prefixed with an underscore'; + $data = array( + ucfirst($scope), + $errorData[0], + ); + $phpcsFile->addError($error, $stackPtr, 'PublicUnderscore', $data); + return; + } + + // If the scope was specified on the method, then the method must be + // camel caps and an underscore should be checked for. If it wasn't + // specified, treat it like a public method and remove the underscore + // prefix if there is one because we cant determine if it is private or + // public. + $testMethodName = $methodName; + if ($scopeSpecified === false && $methodName{0} === '_') { + $testMethodName = substr($methodName, 1); + } + + if (PHP_CodeSniffer::isCamelCaps($testMethodName, false, $isPublic, false) === false) { + if ($scopeSpecified === true) { + $error = '%s method name "%s" is not in camel caps format'; + $data = array( + ucfirst($scope), + $errorData[0], + ); + $phpcsFile->addError($error, $stackPtr, 'ScopeNotCamelCaps', $data); + } else { + $error = 'Method name "%s" is not in camel caps format'; + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); + } + + return; + } + + }//end processTokenWithinScope() + + + /** + * Processes the tokens outside the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $functionName = $phpcsFile->getDeclarationName($stackPtr); + if ($functionName === null) { + // Ignore closures. + return; + } + + $errorData = array($functionName); + + // Is this a magic function. i.e., it is prefixed with "__". + if (preg_match('|^__|', $functionName) !== 0) { + $magicPart = strtolower(substr($functionName, 2)); + if (in_array($magicPart, $this->magicFunctions) === false) { + $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; + $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); + } + + return; + } + + // Function names can be in two parts; the package name and + // the function name. + $packagePart = ''; + $camelCapsPart = ''; + $underscorePos = strrpos($functionName, '_'); + if ($underscorePos === false) { + $camelCapsPart = $functionName; + } else { + $packagePart = substr($functionName, 0, $underscorePos); + $camelCapsPart = substr($functionName, ($underscorePos + 1)); + + // We don't care about _'s on the front. + $packagePart = ltrim($packagePart, '_'); + } + + // If it has a package part, make sure the first letter is a capital. + if ($packagePart !== '') { + if ($functionName{0} === '_') { + $error = 'Function name "%s" is invalid; only private methods should be prefixed with an underscore'; + $phpcsFile->addError($error, $stackPtr, 'FunctionUnderscore', $errorData); + return; + } + + if ($functionName{0} !== strtoupper($functionName{0})) { + $error = 'Function name "%s" is prefixed with a package name but does not begin with a capital letter'; + $phpcsFile->addError($error, $stackPtr, 'FunctionNoCapital', $errorData); + return; + } + } + + // If it doesn't have a camel caps part, it's not valid. + if (trim($camelCapsPart) === '') { + $error = 'Function name "%s" is not valid; name appears incomplete'; + $phpcsFile->addError($error, $stackPtr, 'FunctionInvalid', $errorData); + return; + } + + $validName = true; + $newPackagePart = $packagePart; + $newCamelCapsPart = $camelCapsPart; + + // Every function must have a camel caps part, so check that first. + if (PHP_CodeSniffer::isCamelCaps($camelCapsPart, false, true, false) === false) { + $validName = false; + $newCamelCapsPart = strtolower($camelCapsPart{0}).substr($camelCapsPart, 1); + } + + if ($packagePart !== '') { + // Check that each new word starts with a capital. + $nameBits = explode('_', $packagePart); + foreach ($nameBits as $bit) { + if ($bit{0} !== strtoupper($bit{0})) { + $newPackagePart = ''; + foreach ($nameBits as $bit) { + $newPackagePart .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $validName = false; + break; + } + } + } + + if ($validName === false) { + $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; + if ($newPackagePart === '') { + $newName = $newCamelCapsPart; + } else { + $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; + } + + $error = 'Function name "%s" is invalid; consider "%s" instead'; + $data = $errorData; + $data[] = $newName; + $phpcsFile->addError($error, $stackPtr, 'FunctionNameInvalid', $data); + } + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php new file mode 100644 index 000000000..1877ea93d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -0,0 +1,114 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * PEAR_Sniffs_NamingConventions_ValidVariableNameSniff. + * + * Checks the naming of member variables. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + + /** + * Processes class member variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $memberProps = $phpcsFile->getMemberProperties($stackPtr); + if (empty($memberProps) === true) { + return; + } + + $memberName = ltrim($tokens[$stackPtr]['content'], '$'); + $isPublic = ($memberProps['scope'] === 'private') ? false : true; + $scope = $memberProps['scope']; + $scopeSpecified = $memberProps['scope_specified']; + + // If it's a private member, it must have an underscore on the front. + if ($isPublic === false && $memberName{0} !== '_') { + $error = 'Private member variable "%s" must be prefixed with an underscore'; + $data = array($memberName); + $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); + return; + } + + // If it's not a private member, it must not have an underscore on the front. + if ($isPublic === true && $scopeSpecified === true && $memberName{0} === '_') { + $error = '%s member variable "%s" must not be prefixed with an underscore'; + $data = array( + ucfirst($scope), + $memberName, + ); + $phpcsFile->addError($error, $stackPtr, 'PublicUnderscore', $data); + return; + } + + }//end processMemberVar() + + + /** + * Processes normal variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariable() + + + /** + * Processes variables in double quoted strings. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php new file mode 100644 index 000000000..e77321444 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php @@ -0,0 +1,174 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff. + * + * Checks that object operators are indented 4 spaces if they are the first + * thing on a line. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OBJECT_OPERATOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is the first object operator in a chain of them. + $varToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($varToken === false || $tokens[$varToken]['code'] !== T_VARIABLE) { + return; + } + + // Make sure this is a chained call. + $next = $phpcsFile->findNext( + T_OBJECT_OPERATOR, + ($stackPtr + 1), + null, + false, + null, + true + ); + + if ($next === false) { + // Not a chained call. + return; + } + + // Determine correct indent. + for ($i = ($varToken - 1); $i >= 0; $i--) { + if ($tokens[$i]['line'] !== $tokens[$varToken]['line']) { + $i++; + break; + } + } + + $requiredIndent = 0; + if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) { + $requiredIndent = strlen($tokens[$i]['content']); + } + + $requiredIndent += $this->indent; + + // Determine the scope of the original object operator. + $origBrackets = null; + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $origBrackets = $tokens[$stackPtr]['nested_parenthesis']; + } + + $origConditions = null; + if (isset($tokens[$stackPtr]['conditions']) === true) { + $origConditions = $tokens[$stackPtr]['conditions']; + } + + // Check indentation of each object operator in the chain. + // If the first object operator is on a different line than + // the variable, make sure we check its indentation too. + if ($tokens[$stackPtr]['line'] > $tokens[$varToken]['line']) { + $next = $stackPtr; + } + + while ($next !== false) { + // Make sure it is in the same scope, otherwise don't check indent. + $brackets = null; + if (isset($tokens[$next]['nested_parenthesis']) === true) { + $brackets = $tokens[$next]['nested_parenthesis']; + } + + $conditions = null; + if (isset($tokens[$next]['conditions']) === true) { + $conditions = $tokens[$next]['conditions']; + } + + if ($origBrackets === $brackets && $origConditions === $conditions) { + // Make sure it starts a line, otherwise dont check indent. + $indent = $tokens[($next - 1)]; + if ($indent['code'] === T_WHITESPACE) { + if ($indent['line'] === $tokens[$next]['line']) { + $foundIndent = strlen($indent['content']); + } else { + $foundIndent = 0; + } + + if ($foundIndent !== $requiredIndent) { + $error = 'Object operator not indented correctly; expected %s spaces but found %s'; + $data = array( + $requiredIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $next, 'Incorrect', $data); + } + } + + // It cant be the last thing on the line either. + $content = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); + if ($tokens[$content]['line'] !== $tokens[$next]['line']) { + $error = 'Object operator must be at the start of the line, not the end'; + $phpcsFile->addError($error, $next, 'StartOfLine'); + } + }//end if + + $next = $phpcsFile->findNext( + T_OBJECT_OPERATOR, + ($next + 1), + null, + false, + null, + true + ); + }//end while + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php new file mode 100644 index 000000000..0541c290a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php @@ -0,0 +1,147 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PEAR_Sniffs_Whitespace_ScopeClosingBraceSniff. + * + * Checks that the closing braces of scopes are aligned correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$scopeOpeners; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If this is an inline condition (ie. there is no scope opener), then + // return, as this is not a new scope. + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + return; + } + + $scopeStart = $tokens[$stackPtr]['scope_opener']; + $scopeEnd = $tokens[$stackPtr]['scope_closer']; + + // If the scope closer doesn't think it belongs to this scope opener + // then the opener is sharing its closer ith other tokens. We only + // want to process the closer once, so skip this one. + if ($tokens[$scopeEnd]['scope_condition'] !== $stackPtr) { + return; + } + + // We need to actually find the first piece of content on this line, + // because if this is a method with tokens before it (public, static etc) + // or an if with an else before it, then we need to start the scope + // checking from there, rather than the current token. + $lineStart = ($stackPtr - 1); + for ($lineStart; $lineStart > 0; $lineStart--) { + if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { + break; + } + } + + // We found a new line, now go forward and find the first non-whitespace + // token. + $lineStart= $phpcsFile->findNext( + array(T_WHITESPACE), + ($lineStart + 1), + null, + true + ); + + $startColumn = $tokens[$lineStart]['column']; + + // Check that the closing brace is on it's own line. + $lastContent = $phpcsFile->findPrevious( + array(T_WHITESPACE), + ($scopeEnd - 1), + $scopeStart, + true + ); + + if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { + $error = 'Closing brace must be on a line by itself'; + $phpcsFile->addError($error, $scopeEnd, 'Line'); + return; + } + + // Check now that the closing brace is lined up correctly. + $braceIndent = $tokens[$scopeEnd]['column']; + if (in_array($tokens[$stackPtr]['code'], array(T_CASE, T_DEFAULT)) === true) { + // BREAK statements should be indented n spaces from the + // CASE or DEFAULT statement. + if ($braceIndent !== ($startColumn + $this->indent)) { + $error = 'Case breaking statement indented incorrectly; expected %s spaces, found %s'; + $data = array( + ($startColumn + $this->indent - 1), + ($braceIndent - 1), + ); + $phpcsFile->addError($error, $scopeEnd, 'BreakIdent', $data); + } + } else { + if ($braceIndent !== $startColumn) { + $error = 'Closing brace indented incorrectly; expected %s spaces, found %s'; + $data = array( + ($startColumn - 1), + ($braceIndent - 1), + ); + $phpcsFile->addError($error, $scopeEnd, 'Indent', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php new file mode 100644 index 000000000..20672f8be --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php @@ -0,0 +1,48 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_WhiteSpace_ScopeIndentSniff', true) === false) { + $error = 'Class Generic_Sniffs_WhiteSpace_ScopeIndentSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * PEAR_Sniffs_Whitespace_ScopeIndentSniff. + * + * Checks that control structures are structured correctly, and their content + * is indented correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PEAR_Sniffs_WhiteSpace_ScopeIndentSniff extends Generic_Sniffs_WhiteSpace_ScopeIndentSniff +{ + + /** + * Any scope openers that should not cause an indent. + * + * @var array(int) + */ + protected $nonIndentingScopes = array(T_SWITCH); + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml b/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml new file mode 100644 index 000000000..b6211b2ab --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml @@ -0,0 +1,39 @@ + + + The PEAR coding standard. + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml b/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml new file mode 100644 index 000000000..bb49252bf --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml @@ -0,0 +1,27 @@ + + + The coding standard for PHP_CodeSniffer itself. + */Tests/* + + + + + + + + + + + + + + + + + + + + 0 + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml new file mode 100644 index 000000000..eaae99b22 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml @@ -0,0 +1,48 @@ + + + + + + + class Bar { +} + ]]> + + + class Bar { +} + +class Baz { +} + ]]> + + + + + namespace Foo; + +class Bar { +} + ]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml new file mode 100644 index 000000000..0ed04a07d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml @@ -0,0 +1,27 @@ + + + + + + + + + + echo "Class Foo loaded." + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php new file mode 100644 index 000000000..a6fbf1fa3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php @@ -0,0 +1,78 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Class Declaration Test. + * + * Checks the declaration of the class is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR1_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param integer $stackPtr The position of the current token in + * the token stack. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE), ($stackPtr + 1)); + if ($nextClass !== false) { + $error = 'Each class must be in a file by itself'; + $phpcsFile->addError($error, $nextClass, 'MultipleClasses'); + } + + if (version_compare(PHP_VERSION, '5.3.0') >= 0) { + $namespace = $phpcsFile->findPrevious(T_NAMESPACE, ($stackPtr - 1)); + if ($namespace === false) { + $error = 'Each class must be in a namespace of at least one level (a top-level vendor name)'; + $phpcsFile->addError($error, $stackPtr, 'MissingNamespace'); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php new file mode 100644 index 000000000..8ae868e70 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php @@ -0,0 +1,226 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR1_Sniffs_Files_SideEffectsSniff. + * + * Ensures a file declare new symbols and causes no other side effects, or executes + * logic with side effects, but not both. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR1_Sniffs_Files_SideEffectsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the token stack. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + $result = $this->_searchForConflict($phpcsFile, 0, ($phpcsFile->numTokens - 1), $tokens); + + if ($result['symbol'] !== null && $result['effect'] !== null) { + $error = 'A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. The first symbol is defined on line %s and the first side effect is on line %s.'; + $data = array( + $tokens[$result['symbol']]['line'], + $tokens[$result['effect']]['line'], + ); + $phpcsFile->addWarning($error, 0, 'FoundWithSymbols', $data); + } + + }//end process() + + + /** + * Searches for symbol declarations and side effects. + * + * Returns the positions of both the first symbol declared and the first + * side effect in the file. A NULL value for either indicates nothing was + * found. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $start The token to start searching from. + * @param int $end The token to search to. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return array + */ + private function _searchForConflict(PHP_CodeSniffer_File $phpcsFile, $start, $end, $tokens) + { + $symbols = array( + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_FUNCTION, + ); + + $conditions = array( + T_IF, + T_ELSE, + T_ELSEIF, + ); + + $firstSymbol = null; + $firstEffect = null; + for ($i = $start; $i <= $end; $i++) { + // Ignore whitespace and comments. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } + + // Ignore PHP tags. + if ($tokens[$i]['code'] === T_OPEN_TAG + || $tokens[$i]['code'] === T_CLOSE_TAG + ) { + continue; + } + + // Ignore entire namespace, const and use statements. + if ($tokens[$i]['code'] === T_NAMESPACE) { + $next = $phpcsFile->findNext(array(T_SEMICOLON, T_OPEN_CURLY_BRACKET), ($i + 1)); + if ($next === false) { + $next = $i++; + } else if ($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET) { + $next = $tokens[$next]['bracket_closer']; + } + + $i = $next; + continue; + } else if ($tokens[$i]['code'] === T_USE + || $tokens[$i]['code'] === T_CONST + ) { + $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($i + 1)); + if ($semicolon !== false) { + $i = $semicolon; + } + + continue; + } + + // Ignore function/class prefixes. + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$methodPrefixes) === true) { + continue; + } + + // Detect and skip over symbols. + if (in_array($tokens[$i]['code'], $symbols) === true + && isset($tokens[$i]['scope_closer']) === true + ) { + if ($firstSymbol === null) { + $firstSymbol = $i; + } + + $i = $tokens[$i]['scope_closer']; + continue; + } else if ($tokens[$i]['code'] === T_STRING + && strtolower($tokens[$i]['content']) === 'define' + ) { + if ($firstSymbol === null) { + $firstSymbol = $i; + } + + $i = $phpcsFile->findNext(T_SEMICOLON, ($i + 1)); + continue; + } + + // Conditional statements are allowed in symbol files as long as the + // contents is only a symbol definition. So don't count these as effects + // in this case. + if (in_array($tokens[$i]['code'], $conditions) === true) { + if (isset($tokens[$i]['scope_opener']) === false) { + // Probably an "else if", so just ignore. + continue; + } + + $result = $this->_searchForConflict( + $phpcsFile, + ($tokens[$i]['scope_opener'] + 1), + ($tokens[$i]['scope_closer'] - 1), + $tokens + ); + + if ($result['symbol'] !== null) { + if ($firstSymbol === null) { + $firstSymbol = $result['symbol']; + } + + if ($result['effect'] !== null) { + // Found a conflict. + $firstEffect = $result['effect']; + break; + } + } + + if ($firstEffect === null) { + $firstEffect = $result['effect']; + } + + $i = $tokens[$i]['scope_closer']; + continue; + }//end if + + if ($firstEffect === null) { + $firstEffect = $i; + } + + if ($firstSymbol !== null) { + // We have a conflict we have to report, so no point continuing. + break; + } + }//end for + + return array( + 'symbol' => $firstSymbol, + 'effect' => $firstEffect, + ); + + }//end _searchForConflict() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php new file mode 100644 index 000000000..4a7b3250c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php @@ -0,0 +1,92 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * PSR1_Sniffs_Methods_CamelCapsMethodNameSniff. + * + * Ensures method names are defined using camel case. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR1_Sniffs_Methods_CamelCapsMethodNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * Constructs a PSR1_Sniffs_Methods_CamelCapsMethodNameSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes the tokens within the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * @param int $currScope The position of the current scope. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + $testName = ltrim($methodName, '_'); + if (PHP_CodeSniffer::isCamelCaps($testName, false, true, false) === false) { + $error = 'Method name "%s" is not in camel caps format'; + $className = $phpcsFile->getDeclarationName($currScope); + $errorData = array($className.'::'.$methodName); + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); + } + + }//end processTokenWithinScope() + + + /** + * Processes the tokens outside the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml b/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml new file mode 100644 index 000000000..8bc70151f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml @@ -0,0 +1,45 @@ + + + The PSR1 coding standard. + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml new file mode 100644 index 000000000..23ae34701 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml @@ -0,0 +1,23 @@ + + + + + + + class Foo +{ +} + ]]> + + + class Foo +{ +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml new file mode 100644 index 000000000..ab60a3b85 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml @@ -0,0 +1,62 @@ + + + + + + + bar; +} + ]]> + + + _bar; +} + ]]> + + + + + private $bar; +} + ]]> + + + var $bar; +} + ]]> + + + + + + + + $bar, $baz; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml new file mode 100644 index 000000000..dcbe98f5e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml @@ -0,0 +1,23 @@ + + + + + + + $foo) { + $var = 1; +} + ]]> + + + $foo ) { + $var = 1; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml new file mode 100644 index 000000000..a22dd1796 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml @@ -0,0 +1,27 @@ + + + + + + + elseif ($bar) { + $var = 2; +} + ]]> + + + else if ($bar) { + $var = 2; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml new file mode 100644 index 000000000..58b32a909 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml @@ -0,0 +1,104 @@ + + + + + + + case 'bar': + break; +} + ]]> + + + case 'bar': + break; +} + ]]> + + + + + 'bar': + break; +} + ]]> + + + 'bar': + break; +} + ]]> + + + + + : + break; + default: + break; +} + ]]> + + + : + break; + default : + break; +} + ]]> + + + + + break; +} + ]]> + + + break; +} + ]]> + + + + + // no break + default: + break; +} + ]]> + + + : + break; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml new file mode 100644 index 000000000..d6d3aad16 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml new file mode 100644 index 000000000..e45469e80 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml @@ -0,0 +1,51 @@ + + + + + + + bar() + { + } +} + ]]> + + + _bar() + { + } +} + ]]> + + + + + final public static function bar() + { + } +} + ]]> + + + static public final function bar() + { + } +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml new file mode 100644 index 000000000..1f4d389aa --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml @@ -0,0 +1,22 @@ + + + + + + + +use \Baz; + ]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml new file mode 100644 index 000000000..4082603ca --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml @@ -0,0 +1,57 @@ + + + + + + + + + + \Foo, \Bar; + ]]> + + + + + + + + + + + + + +class Baz +{ +} + ]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php new file mode 100644 index 000000000..06c5bc150 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php @@ -0,0 +1,318 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PEAR_Sniffs_Classes_ClassDeclarationSniff', true) === false) { + $error = 'Class PEAR_Sniffs_Classes_ClassDeclarationSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Class Declaration Test. + * + * Checks the declaration of the class and its inheritance is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Classes_ClassDeclarationSniff extends PEAR_Sniffs_Classes_ClassDeclarationSniff +{ + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We want all the errors from the PEAR standard, plus some of our own. + parent::process($phpcsFile, $stackPtr); + $this->processOpen($phpcsFile, $stackPtr); + $this->processClose($phpcsFile, $stackPtr); + + }//end process() + + + /** + * Processes the opening section of a class declaration. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function processOpen(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check alignment of the keyword and braces. + if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { + $prevContent = $tokens[($stackPtr - 1)]['content']; + if ($prevContent !== $phpcsFile->eolChar) { + $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); + $spaces = strlen($blankSpace); + + if (in_array($tokens[($stackPtr - 2)]['code'], array(T_ABSTRACT, T_FINAL)) === true + && $spaces !== 1 + ) { + $type = strtolower($tokens[$stackPtr]['content']); + $prevContent = strtolower($tokens[($stackPtr - 2)]['content']); + $error = 'Expected 1 space between %s and %s keywords; %s found'; + $data = array( + $prevContent, + $type, + $spaces, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeKeyword', $data); + } + } + }//end if + + // We'll need the indent of the class/interface declaration for later. + $classIndent = 0; + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { + continue; + } + + // We changed lines. + if ($tokens[($i + 1)]['code'] === T_WHITESPACE) { + $classIndent = strlen($tokens[($i + 1)]['content']); + } + + break; + } + + $keyword = $stackPtr; + $openingBrace = $tokens[$stackPtr]['scope_opener']; + $className = $phpcsFile->findNext(T_STRING, $stackPtr); + + $classOrInterface = strtolower($tokens[$keyword]['content']); + + // Spacing of the keyword. + $gap = $tokens[($stackPtr + 1)]['content']; + if (strlen($gap) !== 1) { + $found = strlen($gap); + $error = 'Expected 1 space between %s keyword and %s name; %s found'; + $data = array( + $classOrInterface, + $classOrInterface, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterKeyword', $data); + } + + // Check after the class/interface name. + $gap = $tokens[($className + 1)]['content']; + if (strlen($gap) !== 1) { + $found = strlen($gap); + $error = 'Expected 1 space after %s name; %s found'; + $data = array( + $classOrInterface, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterName', $data); + } + + // Check positions of the extends and implements keywords. + foreach (array('extends', 'implements') as $keywordType) { + $keyword = $phpcsFile->findNext(constant('T_'.strtoupper($keywordType)), ($stackPtr + 1), $openingBrace); + if ($keyword !== false) { + if ($tokens[$keyword]['line'] !== $tokens[$stackPtr]['line']) { + $error = 'The '.$keywordType.' keyword must be on the same line as the %s name'; + $data = array($classOrInterface); + $phpcsFile->addError($error, $keyword, ucfirst($keywordType).'Line', $data); + } else { + // Check the whitespace before. Whitespace after is checked + // later by looking at the whitespace before the first class name + // in the list. + $gap = strlen($tokens[($keyword - 1)]['content']); + if ($gap !== 1) { + $error = 'Expected 1 space before '.$keywordType.' keyword; %s found'; + $data = array($gap); + $phpcsFile->addError($error, $keyword, 'SpaceBefore'.ucfirst($keywordType), $data); + } + } + } + }//end foreach + + // Check each of the extends/implements class names. If the implements + // keywords is the last content on the line, it means we need to check for + // the multi-line implements format, so we do not include the class names + // from the implements list in the following check. + $implements = $phpcsFile->findNext(T_IMPLEMENTS, ($stackPtr + 1), $openingBrace); + $multiLineImplements = false; + if ($implements !== false) { + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($implements + 1), $openingBrace, true); + if ($tokens[$next]['line'] > $tokens[$implements]['line']) { + $multiLineImplements = true; + } + } + + $find = array( + T_STRING, + T_IMPLEMENTS, + ); + + $classNames = array(); + $nextClass = $phpcsFile->findNext($find, ($className + 2), ($openingBrace - 1)); + while ($nextClass !== false) { + $classNames[] = $nextClass; + $nextClass = $phpcsFile->findNext($find, ($nextClass + 1), ($openingBrace - 1)); + } + + $classCount = count($classNames); + $checkingImplements = false; + foreach ($classNames as $i => $className) { + if ($tokens[$className]['code'] == T_IMPLEMENTS) { + $checkingImplements = true; + continue; + } + + if ($checkingImplements === true + && $multiLineImplements === true + && ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR + || $tokens[($className - 2)]['code'] !== T_STRING) + ) { + $prev = $phpcsFile->findPrevious( + array( + T_NS_SEPARATOR, + T_WHITESPACE, + ), + ($className - 1), + $implements, + true + ); + + if ($tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) { + $error = 'Only one interface may be specified per line in a multi-line implements declaration'; + $phpcsFile->addError($error, $className, 'InterfaceSameLine'); + } else { + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($className - 1), $implements); + $found = strlen($tokens[$prev]['content']); + $expected = ($classIndent + $this->indent); + if ($found !== $expected) { + $error = 'Expected %s spaces before interface name; %s found'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $className, 'InterfaceWrongIndent', $data); + } + } + } else if ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR + || $tokens[($className - 2)]['code'] !== T_STRING + ) { + if ($tokens[($className - 1)]['code'] === T_COMMA + || ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR + && $tokens[($className - 2)]['code'] === T_COMMA) + ) { + $error = 'Expected 1 space before "%s"; 0 found'; + $data = array($tokens[$className]['content']); + $phpcsFile->addError($error, ($nextComma + 1), 'NoSpaceBeforeName', $data); + } else { + if ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR) { + $spaceBefore = strlen($tokens[($className - 2)]['content']); + } else { + $spaceBefore = strlen($tokens[($className - 1)]['content']); + } + + if ($spaceBefore !== 1) { + $error = 'Expected 1 space before "%s"; %s found'; + $data = array( + $tokens[$className]['content'], + $spaceBefore, + ); + $phpcsFile->addError($error, $className, 'SpaceBeforeName', $data); + } + }//end if + }//end if + + if ($tokens[($className + 1)]['code'] !== T_NS_SEPARATOR + && $tokens[($className + 1)]['code'] !== T_COMMA + ) { + if ($i !== ($classCount - 1)) { + // This is not the last class name, and the comma + // is not where we expect it to be. + if ($tokens[($className + 2)]['code'] !== T_IMPLEMENTS) { + $error = 'Expected 0 spaces between "%s" and comma; %s found'; + $data = array( + $tokens[$className]['content'], + strlen($tokens[($className + 1)]['content']), + ); + $phpcsFile->addError($error, $className, 'SpaceBeforeComma', $data); + } + } + + $nextComma = $phpcsFile->findNext(T_COMMA, $className); + } else { + $nextComma = ($className + 1); + } + }//end foreach + + }//end processOpen() + + + /** + * Processes the closing section of a class declaration. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function processClose(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check that the closing brace comes right after the code body. + $closeBrace = $tokens[$stackPtr]['scope_closer']; + $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true); + if ($prevContent !== $tokens[$stackPtr]['scope_opener'] + && $tokens[$prevContent]['line'] !== ($tokens[$closeBrace]['line'] - 1) + ) { + $error = 'The closing brace for the %s must go on the next line after the body'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $closeBrace, 'CloseBraceAfterBody', $data); + } + + // Check the closing brace is on it's own line, but allow + // for comments like "//end class". + $nextContent = $phpcsFile->findNext(T_COMMENT, ($closeBrace + 1), null, true); + if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar + && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line'] + ) { + $type = strtolower($tokens[$stackPtr]['content']); + $error = 'Closing %s brace must be on a line by itself'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data); + } + + }//end processClose() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php new file mode 100644 index 000000000..cb748c3be --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php @@ -0,0 +1,115 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +/** + * Verifies that properties are declared correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Classes_PropertyDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content'][1] === '_') { + $error = 'Property name "%s" should not be prefixed with an underscore to indicate visibility'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); + } + + // Detect multiple properties defined at the same time. Throw an error + // for this, but also only process the first property in the list so we don't + // repeat errors. + $find = PHP_CodeSniffer_Tokens::$scopeModifiers; + $find = array_merge($find, array(T_VARIABLE, T_VAR, T_SEMICOLON)); + $prev = $phpcsFile->findPrevious($find, ($stackPtr - 1)); + if ($tokens[$prev]['code'] === T_VARIABLE) { + return; + } + + if ($tokens[$prev]['code'] === T_VAR) { + $error = 'The var keyword must not be used to declare a property'; + $phpcsFile->addError($error, $stackPtr, 'VarUsed'); + } + + $next = $phpcsFile->findNext(array(T_VARIABLE, T_SEMICOLON), ($stackPtr + 1)); + if ($tokens[$next]['code'] === T_VARIABLE) { + $error = 'There must not be more than one property declared per statement'; + $phpcsFile->addError($error, $stackPtr, 'Multiple'); + } + + $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); + if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { + $error = 'Visibility must be declared on property "%s"'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $data); + } + + }//end processMemberVar() + + + /** + * Processes normal variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariable() + + + /** + * Processes variables in double quoted strings. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php new file mode 100644 index 000000000..7f2c70393 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php @@ -0,0 +1,91 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_WhiteSpace_ControlStructureSpacingSniff. + * + * Checks that control structures have the correct spacing around brackets. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_WHILE, + T_FOREACH, + T_FOR, + T_SWITCH, + T_DO, + T_ELSE, + T_ELSEIF, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { + $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; + $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; + if ($tokens[($parenOpener + 1)]['code'] === T_WHITESPACE) { + $gap = strlen($tokens[($parenOpener + 1)]['content']); + $error = 'Expected 0 spaces after opening bracket; %s found'; + $data = array($gap); + $phpcsFile->addError($error, ($parenOpener + 1), 'SpacingAfterOpenBrace', $data); + } + + if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line'] + && $tokens[($parenCloser - 1)]['code'] === T_WHITESPACE + ) { + $gap = strlen($tokens[($parenCloser - 1)]['content']); + $error = 'Expected 0 spaces before closing bracket; %s found'; + $data = array($gap); + $phpcsFile->addError($error, ($parenCloser - 1), 'SpaceBeforeCloseBrace', $data); + } + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php new file mode 100644 index 000000000..a4f598a50 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php @@ -0,0 +1,68 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff. + * + * Verifies that there are no else if statements. Elseif should be used instead. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_ELSE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === T_IF) { + $error = 'Usage of ELSE IF is discouraged; use ELSEIF instead'; + $phpcsFile->addWarning($error, $stackPtr, 'NotAllowed'); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php new file mode 100644 index 000000000..7ffbf5c49 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php @@ -0,0 +1,192 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff. + * + * Ensures all switch statements are defined correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_SWITCH); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We can't process SWITCH statements unless we know where they start and end. + if (isset($tokens[$stackPtr]['scope_opener']) === false + || isset($tokens[$stackPtr]['scope_closer']) === false + ) { + return; + } + + $switch = $tokens[$stackPtr]; + $nextCase = $stackPtr; + $caseAlignment = ($switch['column'] + $this->indent); + $caseCount = 0; + $foundDefault = false; + + while (($nextCase = $this->_findNextCase($phpcsFile, ($nextCase + 1), $switch['scope_closer'])) !== false) { + if ($tokens[$nextCase]['code'] === T_DEFAULT) { + $type = 'default'; + $foundDefault = true; + } else { + $type = 'case'; + $caseCount++; + } + + if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) { + $expected = strtolower($tokens[$nextCase]['content']); + $error = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + $expected, + $tokens[$nextCase]['content'], + ); + $phpcsFile->addError($error, $nextCase, $type.'NotLower', $data); + } + + if ($tokens[$nextCase]['column'] !== $caseAlignment) { + $error = strtoupper($type).' keyword must be indented '.$this->indent.' spaces from SWITCH keyword'; + $phpcsFile->addError($error, $nextCase, $type.'Indent'); + } + + if ($type === 'case' + && ($tokens[($nextCase + 1)]['code'] !== T_WHITESPACE + || $tokens[($nextCase + 1)]['content'] !== ' ') + ) { + $error = 'CASE keyword must be followed by a single space'; + $phpcsFile->addError($error, $nextCase, 'SpacingAfterCase'); + } + + $opener = $tokens[$nextCase]['scope_opener']; + if ($tokens[$opener]['code'] === T_COLON) { + if ($tokens[($opener - 1)]['code'] === T_WHITESPACE) { + $error = 'There must be no space before the colon in a '.strtoupper($type).' statement'; + $phpcsFile->addError($error, $nextCase, 'SpaceBeforeColon'.$type); + } + } else { + $error = strtoupper($type).' statements must not be defined using curly braces'; + $phpcsFile->addError($error, $nextCase, 'WrongOpener'.$type); + } + + $nextCloser = $tokens[$nextCase]['scope_closer']; + if ($tokens[$nextCloser]['scope_condition'] === $nextCase) { + // Only need to check some things once, even if the + // closer is shared between multiple case statements, or even + // the default case. + if ($tokens[$nextCloser]['column'] !== ($caseAlignment + $this->indent)) { + $error = 'Terminating statement must be indented to the same level as the CASE body'; + $phpcsFile->addError($error, $nextCloser, 'BreakIndent'); + } + } + + // We only want cases from here on in. + if ($type !== 'case') { + continue; + } + + $nextCode = $phpcsFile->findNext( + T_WHITESPACE, + ($tokens[$nextCase]['scope_opener'] + 1), + $nextCloser, + true + ); + + if ($tokens[$nextCode]['code'] !== T_CASE && $tokens[$nextCode]['code'] !== T_DEFAULT) { + // This case statement has content. If the next case or default comes + // before the closer, it means we dont have a terminating statement + // and instead need a comment. + $nextCode = $this->_findNextCase($phpcsFile, ($tokens[$nextCase]['scope_opener'] + 1), $nextCloser); + if ($nextCode !== false) { + $prevCode = $phpcsFile->findPrevious(T_WHITESPACE, ($nextCode - 1), $nextCase, true); + if ($tokens[$prevCode]['code'] !== T_COMMENT) { + $error = 'There must be a comment when fall-through is intentional in a non-empty case body'; + $phpcsFile->addError($error, $nextCase, 'TerminatingComment'); + } + } + } + }//end while + + }//end process() + + + /** + * Find the next CASE or DEFAULT statement from a point in the file. + * + * Note that nested switches are ignored. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position to start looking at. + * @param int $end The position to stop looking at. + * + * @return int | bool + */ + private function _findNextCase(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $end) + { + $tokens = $phpcsFile->getTokens(); + while (($stackPtr = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), $stackPtr, $end)) !== false) { + // Skip nested SWITCH statements; they are handled on their own. + if ($tokens[$stackPtr]['code'] === T_SWITCH) { + $stackPtr = $tokens[$stackPtr]['scope_closer']; + continue; + } + + break; + } + + return $stackPtr; + + }//end _findNextCase() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php new file mode 100644 index 000000000..755ebbed1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php @@ -0,0 +1,97 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Generic_Sniffs_Files_EndFileNewlineSniff. + * + * Ensures the file ends with a newline character. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Files_EndFileNewlineSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We are only interested if this is the first open tag and in a file + // that only contains PHP code. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(array(T_OPEN_TAG, T_INLINE_HTML), ($stackPtr - 1)) !== false) { + return; + } + } + + if ($phpcsFile->findNext(T_INLINE_HTML, ($stackPtr + 1)) !== false) { + return; + } + + // Skip to the end of the file. + $tokens = $phpcsFile->getTokens(); + $stackPtr = ($phpcsFile->numTokens - 1); + + // Hard-coding the expected \n in this sniff as it is PSR-2 specific and + // PSR-2 enforces the use of unix style newlines. + if (substr($tokens[$stackPtr]['content'], -1) !== "\n") { + $error = 'Expected 1 newline at end of file; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoneFound'); + return; + } + + // Go looking for the last non-empty line. + $lastLine = $tokens[$stackPtr]['line']; + while ($tokens[$stackPtr]['code'] === T_WHITESPACE) { + $stackPtr--; + } + + $lastCodeLine = $tokens[$stackPtr]['line']; + $blankLines = ($lastLine - $lastCodeLine); + if ($blankLines > 0) { + $error = 'Expected 1 blank line at end of file; %s found'; + $data = array($blankLines + 1); + $phpcsFile->addError($error, $stackPtr, 'TooMany', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php new file mode 100644 index 000000000..2a20939a4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_Methods_FunctionCallSignatureSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Methods_FunctionCallSignatureSniff extends PEAR_Sniffs_Functions_FunctionCallSignatureSniff +{ + + /** + * If TRUE, multiple arguments can be defined per line in a multi-line call. + * + * @var bool + */ + public $allowMultipleArguments = false; + + + /** + * Processes single-line calls. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param int $openBracket The position of the opening bracket + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) + { + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + $compareLine = $tokens[$openBracket]['line']; + + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + $i = $tokens[$i]['parenthesis_closer']; + $compareLine = $tokens[$i]['line']; + continue; + } else if ($tokens[$i]['code'] === T_CLOSURE) { + $i = $tokens[$i]['scope_closer']; + $compareLine = $tokens[$i]['line']; + continue; + } else if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) { + $i = $tokens[$i]['bracket_closer']; + $compareLine = $tokens[$i]['line']; + continue; + } + + if ($tokens[$i]['line'] !== $compareLine) { + return true; + } + }//end for + + return false; + + }//end isMultiLineCall() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php new file mode 100644 index 000000000..705dd4095 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php @@ -0,0 +1,118 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * PSR2_Sniffs_Methods_MethodDeclarationSniff. + * + * Checks that the method declaration is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Methods_MethodDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION)); + + }//end __construct() + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * @param int $currScope The current scope opener token. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $tokens = $phpcsFile->getTokens(); + + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + if ($methodName[0] === '_' && isset($methodName[1]) === true && $methodName[1] !== '_') { + $error = 'Method name "%s" should not be prefixed with an underscore to indicate visibility'; + $data = array($methodName); + $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); + } + + $visibility = 0; + $static = 0; + $abstract = 0; + $final = 0; + + $find = PHP_CodeSniffer_Tokens::$methodPrefixes; + $find[] = T_WHITESPACE; + $prev = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); + + $prefix = $stackPtr; + while (($prefix = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$methodPrefixes, ($prefix - 1), $prev)) !== false) { + switch ($tokens[$prefix]['code']) { + case T_STATIC: + $static = $prefix; + break; + case T_ABSTRACT: + $abstract = $prefix; + break; + case T_FINAL: + $final = $prefix; + break; + default: + $visibility = $prefix; + break; + } + } + + if ($static !== 0 && $static < $visibility) { + $error = 'The static declaration must come after the visibility declaration'; + $phpcsFile->addError($error, $static, 'StaticBeforeVisibility'); + } + + if ($visibility !== 0 && $final > $visibility) { + $error = 'The final declaration must precede the visibility declaration'; + $phpcsFile->addError($error, $final, 'FinalAfterVisibility'); + } + + if ($visibility !== 0 && $abstract > $visibility) { + $error = 'The abstract declaration must precede the visibility declaration'; + $phpcsFile->addError($error, $abstract, 'AbstractAfterVisibility'); + } + + }//end processTokenWithinScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php new file mode 100644 index 000000000..f805f675f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php @@ -0,0 +1,79 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff. + * + * Ensures namespaces are declared correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_NAMESPACE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { + continue; + } + + break; + } + + // The $i var now points to the first token on the line after the + // namespace declaration, which must be a blank line. + $next = $phpcsFile->findNext(T_WHITESPACE, $i, $phpcsFile->numTokens, true); + if ($tokens[$next]['line'] === $tokens[$i]['line']) { + $error = 'There must be one blank line after the namespace declaration'; + $phpcsFile->addError($error, $stackPtr, 'BlankLineAfter'); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php new file mode 100644 index 000000000..9e0467981 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php @@ -0,0 +1,139 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PSR2_Sniffs_Namespaces_UseDeclarationSniff. + * + * Ensures USE blocks are declared correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PSR2_Sniffs_Namespaces_UseDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_USE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + if ($this->_shouldIgnoreUse($phpcsFile, $stackPtr) === true) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + // Only one USE declaration allowed per statement. + $next = $phpcsFile->findNext(array(T_COMMA, T_SEMICOLON), ($stackPtr + 1)); + if ($tokens[$next]['code'] === T_COMMA) { + $error = 'There must be one USE keyword per declaration'; + $phpcsFile->addError($error, $stackPtr, 'MultipleDeclarations'); + } + + // Make sure this USE comes after the first namespace declaration. + $prev = $phpcsFile->findPrevious(T_NAMESPACE, ($stackPtr - 1)); + if ($prev !== false) { + $first = $phpcsFile->findNext(T_NAMESPACE, 1); + if ($prev !== $first) { + $error = 'USE declarations must go after the first namespace declaration'; + $phpcsFile->addError($error, $stackPtr, 'UseAfterNamespace'); + } + } + + // Only interested in the last USE statement from here onwards. + $nextUse = $phpcsFile->findNext(T_USE, ($stackPtr + 1)); + while ($this->_shouldIgnoreUse($phpcsFile, $nextUse) === true) { + $nextUse = $phpcsFile->findNext(T_USE, ($nextUse + 1)); + if ($nextUse === false) { + break; + } + } + + if ($nextUse !== false) { + return; + } + + $end = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + $next = $phpcsFile->findNext(T_WHITESPACE, ($end + 1), null, true); + $diff = ($tokens[$next]['line'] - $tokens[$end]['line'] - 1); + if ($diff !== 1) { + if ($diff < 0) { + $diff = 0; + } + + $error = 'There must be one blank line after the last USE statement; %s found;'; + $data = array($diff); + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterLastUse', $data); + } + + }//end process() + + + /** + * Check if this use statement is part of the namespace block. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + private function _shouldIgnoreUse(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore USE keywords inside closures. + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + return true; + } + + // Ignore USE keywords for traits. + if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_TRAIT)) === true) { + return true; + } + + return false; + + }//end _shouldIgnoreUse() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml b/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml new file mode 100644 index 000000000..c454d1266 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml @@ -0,0 +1,186 @@ + + + The PSR-2 coding standard. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml new file mode 100644 index 000000000..fc6ccbd6a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + ['bar']; +]]> + + + [ 'bar' ]; +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml new file mode 100644 index 000000000..4cdfa2b01 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml @@ -0,0 +1,117 @@ + + + + + + array keyword must be lowercase. + ]]> + + + + array('val1', 'val2'); + ]]> + + + Array('val1', 'val2'); + ]]> + + + + array keyword. + ]]> + + + + 'key1' => 'value1', + 'key2' => 'value2', + ); + ]]> + + + 'key1' => 'value1', + 'key2' => 'value2', + ); + ]]> + + + + array keyword. The closing parenthesis must be aligned with the start of the array keyword. + ]]> + + + + 'key1' => 'value1', + 'key2' => 'value2', + ); + ]]> + + + 'key1' => 'value1', + 'key2' => 'value2', +); + ]]> + + + + + + + + => 'ValueTen', + 'keyTwenty' => 'ValueTwenty', + ); + ]]> + + + => 'ValueTen', + 'keyTwenty' => 'ValueTwenty', + ); + ]]> + + + + + + + + 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ); + ]]> + + + 'value1', + 'key2' => 'value2', + 'key3' => 'value3' + ); + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml new file mode 100644 index 000000000..89fcb5de8 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml @@ -0,0 +1,23 @@ + + + + + + + final class Foo extends Bar +{ +} +]]> + + + Final Class Foo Extends Bar +{ +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml new file mode 100644 index 000000000..59d193ffd --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml @@ -0,0 +1,63 @@ + + + + + + + self::foo(); +]]> + + + SELF::foo(); +]]> + + + + + ::foo(); +]]> + + + :: foo(); +]]> + + + + + self::bar(); + } +} +]]> + + + Foo +{ + public static function bar() + { + } + + public static function baz() + { + Foo::bar(); + } +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml new file mode 100644 index 000000000..414b89a34 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml @@ -0,0 +1,39 @@ + + + + + + + * @see foo() + */ +]]> + + + * @see foo() +*/ +]]> + + + + + @see foo() + */ +]]> + + + @see foo() + */ +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml new file mode 100644 index 000000000..81df2e3fd --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml @@ -0,0 +1,32 @@ + + + + + + + @throws Exception all the time + * @return void + */ +function foo() +{ + throw new Exception('Danger!'); +} +]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml new file mode 100644 index 000000000..87c618137 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml @@ -0,0 +1,39 @@ + + + + + + + $foo as $bar => $baz) { + echo $baz; +} +]]> + + + $foo as $bar=>$baz ) { + echo $baz; +} +]]> + + + + + as $bar => $baz) { + echo $baz; +} +]]> + + + AS $bar => $baz) { + echo $baz; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml new file mode 100644 index 000000000..bbc439230 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml @@ -0,0 +1,55 @@ + + + + + + + $i = 0; $i < 10; $i++) { + echo $i; +} +]]> + + + $i = 0; $i < 10; $i++ ) { + echo $i; +} +]]> + + + + + ; $i < 10; $i++) { + echo $i; +} +]]> + + + ; $i < 10 ; $i++) { + echo $i; +} +]]> + + + + + $i < 10; $i++) { + echo $i; +} +]]> + + + $i < 10;$i++) { + echo $i; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml new file mode 100644 index 000000000..699f1f092 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml @@ -0,0 +1,23 @@ + + + + + + + if ($foo) { + $bar = true; +} +]]> + + + IF ($foo) { + $bar = true; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml new file mode 100644 index 000000000..a890aba68 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml @@ -0,0 +1,23 @@ + + + + + + + isset($foo)) { + echo $foo; +} +]]> + + + isSet($foo)) { + echo $foo; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml new file mode 100644 index 000000000..46e8a8f32 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml @@ -0,0 +1,25 @@ + + + + + + + function foo() +{ + return true; +} +]]> + + + FUNCTION foo() +{ + return true; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml new file mode 100644 index 000000000..3c97f54e6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml @@ -0,0 +1,31 @@ + + + + + + + static function bar() + { + return self::$staticMember; + } +} +]]> + + + static function bar() + { + return $this->$staticMember; + } +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml new file mode 100644 index 000000000..030f2a68c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml @@ -0,0 +1,19 @@ + + + + + + + "Hello"; +]]> + + + ("Hello"); +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml new file mode 100644 index 000000000..0fb195cb6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + int)'42'; +]]> + + + int )'42'; +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml new file mode 100644 index 000000000..d2bc26479 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml @@ -0,0 +1,41 @@ + + + + + + + { +} +]]> + + + { +} +]]> + + + + + return 42; +} +]]> + + + + return 42; +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml new file mode 100644 index 000000000..608bed0b4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + "hi"; +]]> + + + "hi"; +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml new file mode 100644 index 000000000..c6194d71f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml @@ -0,0 +1,19 @@ + + + ) should not have any space around it. + ]]> + + + + ->bar(); +]]> + + + -> bar(); +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml new file mode 100644 index 000000000..8cadf6692 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml @@ -0,0 +1,23 @@ + + + + + + + static function foo() +{ +} +]]> + + + static function foo() +{ +} +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml new file mode 100644 index 000000000..7b2279529 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + ; +]]> + + + ; +]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php new file mode 100644 index 000000000..00c0d0869 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php @@ -0,0 +1,111 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff. + * + * Ensure that there are no spaces around square brackets. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // PHP 5.4 introduced a shorthand array declaration syntax, so we need + // to ignore the these type of array declarations because this sniff is + // only dealing with array usage. + if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { + $openBracket = $stackPtr; + } else { + $openBracket = $tokens[$stackPtr]['bracket_opener']; + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($openBracket - 1), null, true); + if ($tokens[$prev]['code'] === T_EQUAL) { + return; + } + + // Square brackets can not have a space before them. + $prevType = $tokens[($stackPtr - 1)]['code']; + if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $nonSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 2), null, true); + $expected = $tokens[$nonSpace]['content'].$tokens[$stackPtr]['content']; + $found = $phpcsFile->getTokensAsString($nonSpace, ($stackPtr - $nonSpace)).$tokens[$stackPtr]['content']; + $error = 'Space found before square bracket; expected "%s" but found "%s"'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeBracket', $data); + } + + // Open square brackets can't ever have spaces after them. + if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { + $nextType = $tokens[($stackPtr + 1)]['code']; + if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $nonSpace = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 2), null, true); + $expected = $tokens[$stackPtr]['content'].$tokens[$nonSpace]['content']; + $found = $phpcsFile->getTokensAsString($stackPtr, ($nonSpace - $stackPtr + 1)); + $error = 'Space found after square bracket; expected "%s" but found "%s"'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterBracket', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php new file mode 100644 index 000000000..27938d3ab --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php @@ -0,0 +1,513 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * A test to ensure that arrays conform to the array coding standard. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Arrays_ArrayDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_ARRAY); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Array keyword should be lower case. + if (strtolower($tokens[$stackPtr]['content']) !== $tokens[$stackPtr]['content']) { + $error = 'Array keyword should be lower case; expected "array" but found "%s"'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $stackPtr, 'NotLowerCase', $data); + } + + $arrayStart = $tokens[$stackPtr]['parenthesis_opener']; + $arrayEnd = $tokens[$arrayStart]['parenthesis_closer']; + $keywordStart = $tokens[$stackPtr]['column']; + + if ($arrayStart != ($stackPtr + 1)) { + $error = 'There must be no space between the Array keyword and the opening parenthesis'; + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterKeyword'); + } + + // Check for empty arrays. + $content = $phpcsFile->findNext(array(T_WHITESPACE), ($arrayStart + 1), ($arrayEnd + 1), true); + if ($content === $arrayEnd) { + // Empty array, but if the brackets aren't together, there's a problem. + if (($arrayEnd - $arrayStart) !== 1) { + $error = 'Empty array declaration must have no space between the parentheses'; + $phpcsFile->addError($error, $stackPtr, 'SpaceInEmptyArray'); + + // We can return here because there is nothing else to check. All code + // below can assume that the array is not empty. + return; + } + } + + if ($tokens[$arrayStart]['line'] === $tokens[$arrayEnd]['line']) { + // Single line array. + // Check if there are multiple values. If so, then it has to be multiple lines + // unless it is contained inside a function call or condition. + $valueCount = 0; + $commas = array(); + for ($i = ($arrayStart + 1); $i < $arrayEnd; $i++) { + // Skip bracketed statements, like function calls. + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + $i = $tokens[$i]['parenthesis_closer']; + continue; + } + + if ($tokens[$i]['code'] === T_COMMA) { + // Before counting this comma, make sure we are not + // at the end of the array. + $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), $arrayEnd, true); + if ($next !== false) { + $valueCount++; + $commas[] = $i; + } else { + // There is a comma at the end of a single line array. + $error = 'Comma not allowed after last value in single-line array declaration'; + $phpcsFile->addError($error, $i, 'CommaAfterLast'); + } + } + } + + // Now check each of the double arrows (if any). + $nextArrow = $arrayStart; + while (($nextArrow = $phpcsFile->findNext(T_DOUBLE_ARROW, ($nextArrow + 1), $arrayEnd)) !== false) { + if ($tokens[($nextArrow - 1)]['code'] !== T_WHITESPACE) { + $content = $tokens[($nextArrow - 1)]['content']; + $error = 'Expected 1 space between "%s" and double arrow; 0 found'; + $data = array($content); + $phpcsFile->addError($error, $nextArrow, 'NoSpaceBeforeDoubleArrow', $data); + } else { + $spaceLength = strlen($tokens[($nextArrow - 1)]['content']); + if ($spaceLength !== 1) { + $content = $tokens[($nextArrow - 2)]['content']; + $error = 'Expected 1 space between "%s" and double arrow; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $nextArrow, 'SpaceBeforeDoubleArrow', $data); + } + } + + if ($tokens[($nextArrow + 1)]['code'] !== T_WHITESPACE) { + $content = $tokens[($nextArrow + 1)]['content']; + $error = 'Expected 1 space between double arrow and "%s"; 0 found'; + $data = array($content); + $phpcsFile->addError($error, $nextArrow, 'NoSpaceAfterDoubleArrow', $data); + } else { + $spaceLength = strlen($tokens[($nextArrow + 1)]['content']); + if ($spaceLength !== 1) { + $content = $tokens[($nextArrow + 2)]['content']; + $error = 'Expected 1 space between double arrow and "%s"; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $nextArrow, 'SpaceAfterDoubleArrow', $data); + } + } + }//end while + + if ($valueCount > 0) { + $conditionCheck = $phpcsFile->findPrevious(array(T_OPEN_PARENTHESIS, T_SEMICOLON), ($stackPtr - 1), null, false); + + if (($conditionCheck === false) || ($tokens[$conditionCheck]['line'] !== $tokens[$stackPtr]['line'])) { + $error = 'Array with multiple values cannot be declared on a single line'; + $phpcsFile->addError($error, $stackPtr, 'SingleLineNotAllowed'); + return; + } + + // We have a multiple value array that is inside a condition or + // function. Check its spacing is correct. + foreach ($commas as $comma) { + if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) { + $content = $tokens[($comma + 1)]['content']; + $error = 'Expected 1 space between comma and "%s"; 0 found'; + $data = array($content); + $phpcsFile->addError($error, $comma, 'NoSpaceAfterComma', $data); + } else { + $spaceLength = strlen($tokens[($comma + 1)]['content']); + if ($spaceLength !== 1) { + $content = $tokens[($comma + 2)]['content']; + $error = 'Expected 1 space between comma and "%s"; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $comma, 'SpaceAfterComma', $data); + } + } + + if ($tokens[($comma - 1)]['code'] === T_WHITESPACE) { + $content = $tokens[($comma - 2)]['content']; + $spaceLength = strlen($tokens[($comma - 1)]['content']); + $error = 'Expected 0 spaces between "%s" and comma; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $comma, 'SpaceBeforeComma', $data); + } + }//end foreach + }//end if + + return; + }//end if + + // Check the closing bracket is on a new line. + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($arrayEnd - 1), $arrayStart, true); + if ($tokens[$lastContent]['line'] !== ($tokens[$arrayEnd]['line'] - 1)) { + $error = 'Closing parenthesis of array declaration must be on a new line'; + $phpcsFile->addError($error, $arrayEnd, 'CloseBraceNewLine'); + } else if ($tokens[$arrayEnd]['column'] !== $keywordStart) { + // Check the closing bracket is lined up under the a in array. + $expected = $keywordStart; + $found = $tokens[$arrayEnd]['column']; + $error = 'Closing parenthesis not aligned correctly; expected %s space(s) but found %s'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $arrayEnd, 'CloseBraceNotAligned', $data); + } + + $nextToken = $stackPtr; + $lastComma = $stackPtr; + $keyUsed = false; + $singleUsed = false; + $lastToken = ''; + $indices = array(); + $maxLength = 0; + + // Find all the double arrows that reside in this scope. + while (($nextToken = $phpcsFile->findNext(array(T_DOUBLE_ARROW, T_COMMA, T_ARRAY), ($nextToken + 1), $arrayEnd)) !== false) { + $currentEntry = array(); + + if ($tokens[$nextToken]['code'] === T_ARRAY) { + // Let subsequent calls of this test handle nested arrays. + $indices[] = array('value' => $nextToken); + $nextToken = $tokens[$tokens[$nextToken]['parenthesis_opener']]['parenthesis_closer']; + continue; + } + + if ($tokens[$nextToken]['code'] === T_COMMA) { + $stackPtrCount = 0; + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $stackPtrCount = count($tokens[$stackPtr]['nested_parenthesis']); + } + + if (count($tokens[$nextToken]['nested_parenthesis']) > ($stackPtrCount + 1)) { + // This comma is inside more parenthesis than the ARRAY keyword, + // then there it is actually a comma used to separate arguments + // in a function call. + continue; + } + + if ($keyUsed === true && $lastToken === T_COMMA) { + $error = 'No key specified for array entry; first entry specifies key'; + $phpcsFile->addError($error, $nextToken, 'NoKeySpecified'); + return; + } + + if ($keyUsed === false) { + if ($tokens[($nextToken - 1)]['code'] === T_WHITESPACE) { + $content = $tokens[($nextToken - 2)]['content']; + $spaceLength = strlen($tokens[($nextToken - 1)]['content']); + $error = 'Expected 0 spaces between "%s" and comma; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $nextToken, 'SpaceBeforeComma', $data); + } + + // Find the value, which will be the first token on the line, + // excluding the leading whitespace. + $valueContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextToken - 1), null, true); + while ($tokens[$valueContent]['line'] === $tokens[$nextToken]['line']) { + if ($valueContent === $arrayStart) { + // Value must have been on the same line as the array + // parenthesis, so we have reached the start of the value. + break; + } + + $valueContent--; + } + + $valueContent = $phpcsFile->findNext(T_WHITESPACE, ($valueContent + 1), $nextToken, true); + $indices[] = array('value' => $valueContent); + $singleUsed = true; + }//end if + + $lastToken = T_COMMA; + continue; + }//end if + + if ($tokens[$nextToken]['code'] === T_DOUBLE_ARROW) { + if ($singleUsed === true) { + $error = 'Key specified for array entry; first entry has no key'; + $phpcsFile->addError($error, $nextToken, 'KeySpecified'); + return; + } + + $currentEntry['arrow'] = $nextToken; + $keyUsed = true; + + // Find the start of index that uses this double arrow. + $indexEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($nextToken - 1), $arrayStart, true); + $indexStart = $phpcsFile->findPrevious(T_WHITESPACE, $indexEnd, $arrayStart); + + if ($indexStart === false) { + $index = $indexEnd; + } else { + $index = ($indexStart + 1); + } + + $currentEntry['index'] = $index; + $currentEntry['index_content'] = $phpcsFile->getTokensAsString($index, ($indexEnd - $index + 1)); + + $indexLength = strlen($currentEntry['index_content']); + if ($maxLength < $indexLength) { + $maxLength = $indexLength; + } + + // Find the value of this index. + $nextContent = $phpcsFile->findNext(array(T_WHITESPACE), ($nextToken + 1), $arrayEnd, true); + $currentEntry['value'] = $nextContent; + $indices[] = $currentEntry; + $lastToken = T_DOUBLE_ARROW; + }//end if + }//end while + + // Check for mutli-line arrays that should be single-line. + $singleValue = false; + + if (empty($indices) === true) { + $singleValue = true; + } else if (count($indices) === 1 && $lastToken === T_COMMA) { + // There may be another array value without a comma. + $exclude = PHP_CodeSniffer_Tokens::$emptyTokens; + $exclude[] = T_COMMA; + $nextContent = $phpcsFile->findNext($exclude, ($indices[0]['value'] + 1), $arrayEnd, true); + if ($nextContent === false) { + $singleValue = true; + } + } + + if ($singleValue === true) { + // Array cannot be empty, so this is a multi-line array with + // a single value. It should be defined on single line. + $error = 'Multi-line array contains a single value; use single-line array instead'; + $phpcsFile->addError($error, $stackPtr, 'MultiLineNotAllowed'); + return; + } + + /* + This section checks for arrays that don't specify keys. + + Arrays such as: + array( + 'aaa', + 'bbb', + 'd', + ); + */ + + if ($keyUsed === false && empty($indices) === false) { + $count = count($indices); + $lastIndex = $indices[($count - 1)]['value']; + + $trailingContent = $phpcsFile->findPrevious(T_WHITESPACE, ($arrayEnd - 1), $lastIndex, true); + if ($tokens[$trailingContent]['code'] !== T_COMMA) { + $error = 'Comma required after last value in array declaration'; + $phpcsFile->addError($error, $trailingContent, 'NoCommaAfterLast'); + } + + foreach ($indices as $value) { + if (empty($value['value']) === true) { + // Array was malformed and we couldn't figure out + // the array value correctly, so we have to ignore it. + // Other parts of this sniff will correct the error. + continue; + } + + if ($tokens[($value['value'] - 1)]['code'] === T_WHITESPACE) { + // A whitespace token before this value means that the value + // was indented and not flush with the opening parenthesis. + if ($tokens[$value['value']]['column'] !== ($keywordStart + 1)) { + $error = 'Array value not aligned correctly; expected %s spaces but found %s'; + $data = array( + ($keywordStart + 1), + $tokens[$value['value']]['column'], + ); + $phpcsFile->addError($error, $value['value'], 'ValueNotAligned', $data); + } + } + } + }//end if + + /* + Below the actual indentation of the array is checked. + Errors will be thrown when a key is not aligned, when + a double arrow is not aligned, and when a value is not + aligned correctly. + If an error is found in one of the above areas, then errors + are not reported for the rest of the line to avoid reporting + spaces and columns incorrectly. Often fixing the first + problem will fix the other 2 anyway. + + For example: + + $a = array( + 'index' => '2', + ); + + In this array, the double arrow is indented too far, but this + will also cause an error in the value's alignment. If the arrow were + to be moved back one space however, then both errors would be fixed. + */ + + $numValues = count($indices); + + $indicesStart = ($keywordStart + 1); + $arrowStart = ($indicesStart + $maxLength + 1); + $valueStart = ($arrowStart + 3); + foreach ($indices as $index) { + if (isset($index['index']) === false) { + // Array value only. + if (($tokens[$index['value']]['line'] === $tokens[$stackPtr]['line']) && ($numValues > 1)) { + $error = 'The first value in a multi-value array must be on a new line'; + $phpcsFile->addError($error, $stackPtr, 'FirstValueNoNewline'); + } + + continue; + } + + if (($tokens[$index['index']]['line'] === $tokens[$stackPtr]['line'])) { + $error = 'The first index in a multi-value array must be on a new line'; + $phpcsFile->addError($error, $stackPtr, 'FirstIndexNoNewline'); + continue; + } + + if ($tokens[$index['index']]['column'] !== $indicesStart) { + $error = 'Array key not aligned correctly; expected %s spaces but found %s'; + $data = array( + ($indicesStart - 1), + ($tokens[$index['index']]['column'] - 1), + ); + $phpcsFile->addError($error, $index['index'], 'KeyNotAligned', $data); + continue; + } + + if ($tokens[$index['arrow']]['column'] !== $arrowStart) { + $expected = ($arrowStart - (strlen($index['index_content']) + $tokens[$index['index']]['column'])); + $found = ($tokens[$index['arrow']]['column'] - (strlen($index['index_content']) + $tokens[$index['index']]['column'])); + + $error = 'Array double arrow not aligned correctly; expected %s space(s) but found %s'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $index['arrow'], 'DoubleArrowNotAligned', $data); + continue; + } + + if ($tokens[$index['value']]['column'] !== $valueStart) { + $expected = ($valueStart - (strlen($tokens[$index['arrow']]['content']) + $tokens[$index['arrow']]['column'])); + $found = ($tokens[$index['value']]['column'] - (strlen($tokens[$index['arrow']]['content']) + $tokens[$index['arrow']]['column'])); + + $error = 'Array value not aligned correctly; expected %s space(s) but found %s'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $index['arrow'], 'ValueNotAligned', $data); + } + + // Check each line ends in a comma. + if ($tokens[$index['value']]['code'] !== T_ARRAY) { + $valueLine = $tokens[$index['value']]['line']; + $nextComma = false; + for ($i = ($index['value'] + 1); $i < $arrayEnd; $i++) { + // Skip bracketed statements, like function calls. + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + $i = $tokens[$i]['parenthesis_closer']; + $valueLine = $tokens[$i]['line']; + continue; + } + + if ($tokens[$i]['code'] === T_COMMA) { + $nextComma = $i; + break; + } + } + + if (($nextComma === false) || ($tokens[$nextComma]['line'] !== $valueLine)) { + $error = 'Each line in an array declaration must end in a comma'; + $phpcsFile->addError($error, $index['value'], 'NoComma'); + } + + // Check that there is no space before the comma. + if ($nextComma !== false && $tokens[($nextComma - 1)]['code'] === T_WHITESPACE) { + $content = $tokens[($nextComma - 2)]['content']; + $spaceLength = strlen($tokens[($nextComma - 1)]['content']); + $error = 'Expected 0 spaces between "%s" and comma; %s found'; + $data = array( + $content, + $spaceLength, + ); + $phpcsFile->addError($error, $nextComma, 'SpaceBeforeComma', $data); + } + } + }//end foreach + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php new file mode 100644 index 000000000..efd7703fe --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php @@ -0,0 +1,103 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff. + * + * Ensure there is a single blank line after the closing brace of a class definition. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_CLOSE_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($next === false) { + return; + } + + if ($tokens[$next]['code'] !== T_CLOSE_TAG) { + $found = (($tokens[$next]['line'] - $tokens[$stackPtr]['line']) - 1); + if ($found !== 1) { + $error = 'Expected one blank line after closing brace of class definition; %s found'; + $data = array($found); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterClose', $data); + } + } + + // Ignore nested style definitions from here on. The spacing before the closing brace + // (a single blank line) will be enforced by the above check, which ensures there is a + // blank line after the last nested class. + $found = $phpcsFile->findPrevious( + T_CLOSE_CURLY_BRACKET, + ($stackPtr - 1), + $tokens[$stackPtr]['bracket_opener'] + ); + if ($found !== false) { + return; + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($prev !== false && $tokens[$prev]['line'] !== ($tokens[$stackPtr]['line'] - 1)) { + $num = ($tokens[$stackPtr]['line'] - $tokens[$prev]['line'] - 1); + $error = 'Expected 0 blank lines before closing brace of class definition; %s found'; + $data = array($num); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php new file mode 100644 index 000000000..bce5c31dd --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php @@ -0,0 +1,118 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff. + * + * Ensure there are no blank lines between the names of classes/IDs. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Do not check nested style definitions as, for example, in @media style rules. + $nested = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1), $tokens[$stackPtr]['bracket_closer']); + if ($nested !== false) { + return; + } + + // Find the first blank line before this opening brace, unless we get + // to another style definition, comment or the start of the file. + $endTokens = array( + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + T_COMMENT, + T_DOC_COMMENT, + T_OPEN_TAG, + ); + + $foundContent = false; + $currentLine = $tokens[$stackPtr]['line']; + for ($i = ($stackPtr - 1); $i >= 0; $i--) { + if (in_array($tokens[$i]['code'], $endTokens) === true) { + break; + } + + if ($tokens[$i]['line'] === $currentLine) { + if ($tokens[$i]['code'] !== T_WHITESPACE) { + $foundContent = true; + } + + continue; + } + + // We changed lines. + if ($foundContent === false) { + // Before we throw an error, make sure we are not looking + // at a gap before the style definition. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, $i, null, true); + if ($prev !== false + && in_array($tokens[$prev]['code'], $endTokens) === false + ) { + $error = 'Blank lines are not allowed between class names'; + $phpcsFile->addError($error, ($i + 1), 'BlankLinesFound'); + } + break; + } + + $foundContent = false; + $currentLine = $tokens[$i]['line']; + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php new file mode 100644 index 000000000..dccc83580 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php @@ -0,0 +1,118 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff. + * + * Ensure there is a single space before the opening brace in a class definition + * and the content starts on the next line. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before opening brace of class definition; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoneBefore'); + } else { + $content = $tokens[($stackPtr - 1)]['content']; + if ($content !== ' ') { + $length = strlen($content); + if ($length === 1) { + $length = 'tab'; + } + + $error = 'Expected 1 space before opening brace of class definition; %s found'; + $data = array($length); + $phpcsFile->addError($error, $stackPtr, 'Before', $data); + } + }//end if + + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($next === false) { + return; + } + + // Check for nested class definitions. + $nested = false; + $found = $phpcsFile->findNext( + T_OPEN_CURLY_BRACKET, + ($stackPtr + 1), + $tokens[$stackPtr]['bracket_closer'] + ); + if ($found !== false) { + $nested = true; + } + + $foundLines = ($tokens[$next]['line'] - $tokens[$stackPtr]['line'] - 1); + if ($nested === true) { + if ($foundLines !== 1) { + $error = 'Expected 1 blank line after opening brace of nesting class definition; %s found'; + $data = array($foundLines); + $phpcsFile->addError($error, $stackPtr, 'AfterNesting', $data); + } + } else { + if ($foundLines !== 0) { + $error = 'Expected 0 blank lines after opening brace of class definition; %s found'; + $data = array($foundLines); + $phpcsFile->addError($error, $stackPtr, 'After', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php new file mode 100644 index 000000000..907a03964 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php @@ -0,0 +1,101 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ColonSpacingSniff. + * + * Ensure there is no space before a colon and one space after it. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ColonSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_COLON); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] !== T_STYLE) { + // The colon is not part of a style definition. + return; + } + + if ($tokens[$prev]['content'] === 'progid') { + // Special case for IE filters. + return; + } + + if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { + $error = 'There must be no space before a colon in a style definition'; + $phpcsFile->addError($error, $stackPtr, 'Before'); + } + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after colon in style definition; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoneAfter'); + } else { + $content = $tokens[($stackPtr + 1)]['content']; + if (strpos($content, $phpcsFile->eolChar) === false) { + $length = strlen($content); + if ($length !== 1) { + $error = 'Expected 1 space after colon in style definition; %s found'; + $data = array($length); + $phpcsFile->addError($error, $stackPtr, 'After', $data); + } + } else { + $error = 'Expected 1 space after colon in style definition; newline found'; + $phpcsFile->addError($error, $stackPtr, 'AfterNewline'); + } + }//end if + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php new file mode 100644 index 000000000..b860f0dac --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php @@ -0,0 +1,93 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ColourDefinitionSniff. + * + * Ensure colours are defined in upper-case and use shortcuts where possible. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ColourDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_COLOUR); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $colour = $tokens[$stackPtr]['content']; + + $expected = strtoupper($colour); + if ($colour !== $expected) { + $error = 'CSS colours must be defined in uppercase; expected %s but found %s'; + $data = array( + $expected, + $colour, + ); + $phpcsFile->addError($error, $stackPtr, 'NotUpper', $data); + } + + // Now check if shorthand can be used. + if (strlen($colour) !== 7) { + return; + } + + if ($colour{1} === $colour{2} && $colour{3} === $colour{4} && $colour{5} === $colour{6}) { + $expected = '#'.$colour{1}.$colour{3}.$colour{5}; + $error = 'CSS colours must use shorthand if available; expected %s but found %s'; + $data = array( + $expected, + $colour, + ); + $phpcsFile->addError($error, $stackPtr, 'Shorthand', $data); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php new file mode 100644 index 000000000..4e0c50be5 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff. + * + * Ensure that each style definition is on a line by itself. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $next = $phpcsFile->findNext(T_STYLE, ($stackPtr + 1)); + if ($next === false) { + return; + } + + if ($tokens[$next]['content'] === 'progid') { + // Special case for IE filters. + return; + } + + if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) { + $error = 'Each style definition must be on a line by itself'; + $phpcsFile->addError($error, $next, 'Found'); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php new file mode 100644 index 000000000..f35aa2770 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php @@ -0,0 +1,113 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff. + * + * Check for duplicate class definitions that can be merged into one. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Find the content of each class definition name. + $classNames = array(); + $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1)); + if ($next === false) { + // No class definitions in the file. + return; + } + + $find = array( + T_CLOSE_CURLY_BRACKET, + T_COMMENT, + T_OPEN_TAG, + ); + + while ($next !== false) { + $prev = $phpcsFile->findPrevious($find, ($next - 1)); + + // Create a sorted name for the class so we can compare classes + // even when the individual names are all over the place. + $name = ''; + for ($i = ($prev + 1); $i < $next; $i++) { + $name .= $tokens[$i]['content']; + } + + $name = trim($name); + $name = str_replace("\n", ' ', $name); + $name = preg_replace('|[\s]+|', ' ', $name); + $name = str_replace(', ', ',', $name); + + $names = explode(',', $name); + sort($names); + $name = implode(',', $names); + + if (isset($classNames[$name]) === true) { + $first = $classNames[$name]; + $error = 'Duplicate class definition found; first defined on line %s'; + $data = array($tokens[$first]['line']); + $phpcsFile->addError($error, $next, 'Found', $data); + } else { + $classNames[$name] = $next; + } + + $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($next + 1)); + }//end while + + }//end process() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php new file mode 100644 index 000000000..3171a349f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php @@ -0,0 +1,93 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff. + * + * Check for duplicate style definitions in the same class. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Find the content of each style definition name. + $end = $tokens[$stackPtr]['bracket_closer']; + $next = $phpcsFile->findNext(T_STYLE, ($stackPtr + 1), $end); + if ($next === false) { + // Class definition is empty. + return; + } + + $styleNames = array(); + + while ($next !== false) { + $name = $tokens[$next]['content']; + if (isset($styleNames[$name]) === true) { + $first = $styleNames[$name]; + $error = 'Duplicate style definition found; first defined on line %s'; + $data = array($tokens[$first]['line']); + $phpcsFile->addError($error, $next, 'Found', $data); + } else { + $styleNames[$name] = $next; + } + + $next = $phpcsFile->findNext(T_STYLE, ($next + 1), $end); + }//end while + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php new file mode 100644 index 000000000..047315e80 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php @@ -0,0 +1,73 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_EmptyClassDefinitionSniff. + * + * Ensure that class definitions are not empty. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_EmptyClassDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + + if ($next === false || $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { + $error = 'Class definition is empty'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php new file mode 100644 index 000000000..6bf53e7d5 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php @@ -0,0 +1,73 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff. + * + * Ensure that style definitions are not empty. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COLON), ($stackPtr + 1), null, true); + + if ($next === false || $tokens[$next]['code'] === T_SEMICOLON || $tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { + $error = 'Style definition is empty'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php new file mode 100644 index 000000000..65628066b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php @@ -0,0 +1,185 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ForbiddenStylesSniff. + * + * Bans the use of some styles, such as deprecated or browser-specific styles. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ForbiddenStylesSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + /** + * A list of forbidden styles with their alternatives. + * + * The value is NULL if no alternative exists. i.e., the + * function should just not be used. + * + * @var array(string => string|null) + */ + protected $forbiddenStyles = array( + '-moz-border-radius' => 'border-radius', + '-webkit-border-radius' => 'border-radius', + '-moz-border-radius-topleft' => 'border-top-left-radius', + '-moz-border-radius-topright' => 'border-top-right-radius', + '-moz-border-radius-bottomright' => 'border-bottom-right-radius', + '-moz-border-radius-bottomleft' => 'border-bottom-left-radius', + '-moz-box-shadow' => 'box-shadow', + '-webkit-box-shadow' => 'box-shadow', + ); + + /** + * A cache of forbidden style names, for faster lookups. + * + * @var array(string) + */ + protected $forbiddenStyleNames = array(); + + /** + * If true, forbidden styles will be considered regular expressions. + * + * @var bool + */ + protected $patternMatch = false; + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = true; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + $this->forbiddenStyleNames = array_keys($this->forbiddenStyles); + + if ($this->patternMatch === true) { + foreach ($this->forbiddenStyleNames as $i => $name) { + $this->forbiddenStyleNames[$i] = '/'.$name.'/i'; + } + } + + return array(T_STYLE); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $style = strtolower($tokens[$stackPtr]['content']); + $pattern = null; + + if ($this->patternMatch === true) { + $count = 0; + $pattern = preg_replace( + $this->forbiddenStyleNames, + $this->forbiddenStyleNames, + $style, + 1, + $count + ); + + if ($count === 0) { + return; + } + + // Remove the pattern delimiters and modifier. + $pattern = substr($pattern, 1, -2); + } else { + if (in_array($style, $this->forbiddenStyleNames) === false) { + return; + } + } + + $this->addError($phpcsFile, $stackPtr, $style, $pattern); + + }//end process() + + + /** + * Generates the error or warning for this sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the forbidden style + * in the token array. + * @param string $style The name of the forbidden style. + * @param string $pattern The pattern used for the match. + * + * @return void + */ + protected function addError($phpcsFile, $stackPtr, $style, $pattern=null) + { + $data = array($style); + $error = 'The use of style %s is '; + if ($this->error === true) { + $type = 'Found'; + $error .= 'forbidden'; + } else { + $type = 'Discouraged'; + $error .= 'discouraged'; + } + + if ($pattern === null) { + $pattern = $style; + } + + if ($this->forbiddenStyles[$pattern] !== null) { + $type .= 'WithAlternative'; + $data[] = $this->forbiddenStyles[$pattern]; + $error .= '; use %s instead'; + } + + if ($this->error === true) { + $phpcsFile->addError($error, $stackPtr, $type, $data); + } else { + $phpcsFile->addWarning($error, $stackPtr, $type, $data); + } + + }//end addError() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php new file mode 100644 index 000000000..8740acf1a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php @@ -0,0 +1,128 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_IndentationSniff. + * + * Ensures styles are indented 4 spaces. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_IndentationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $numTokens = (count($tokens) - 2); + $indentLevel = 0; + $nestingLevel = 0; + for ($i = 1; $i < $numTokens; $i++) { + if ($tokens[$i]['code'] === T_COMMENT) { + // Don't check the indent of comments. + continue; + } + + if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { + $indentLevel++; + + // Check for nested class definitions. + $found = $phpcsFile->findNext( + T_OPEN_CURLY_BRACKET, + ($i + 1), + $tokens[$i]['bracket_closer'] + ); + if ($found !== false) { + $nestingLevel = $indentLevel; + } + } else if ($tokens[($i + 1)]['code'] === T_CLOSE_CURLY_BRACKET) { + $indentLevel--; + } + + if ($tokens[$i]['column'] !== 1) { + continue; + } + + // We started a new line, so check indent. + if ($tokens[$i]['code'] === T_WHITESPACE) { + $content = str_replace($phpcsFile->eolChar, '', $tokens[$i]['content']); + $foundIndent = strlen($content); + } else { + $foundIndent = 0; + } + + $expectedIndent = ($indentLevel * $this->indent); + if ($expectedIndent > 0 + && strpos($tokens[$i]['content'], $phpcsFile->eolChar) !== false + ) { + if ($nestingLevel !== $indentLevel) { + $error = 'Blank lines are not allowed in class definitions'; + $phpcsFile->addError($error, $i, 'BlankLine'); + } + } else if ($foundIndent !== $expectedIndent) { + $error = 'Line indented incorrectly; expected %s spaces, found %s'; + $data = array( + $expectedIndent, + $foundIndent, + ); + $phpcsFile->addError($error, $i, 'Incorrect', $data); + } + }//end foreach + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php new file mode 100644 index 000000000..7eabd99a9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php @@ -0,0 +1,106 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff. + * + * Ensure that all style definitions are in lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $start = ($stackPtr + 1); + $end = ($tokens[$stackPtr]['bracket_closer'] - 1); + $inStyle = null; + + for ($i = $start; $i <= $end; $i++) { + // Skip nested definitions as they are checked individually. + if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { + $i = $tokens[$i]['bracket_closer']; + continue; + } + + if ($tokens[$i]['code'] === T_STYLE) { + $inStyle = $tokens[$i]['content']; + } + + if ($tokens[$i]['code'] === T_SEMICOLON) { + $inStyle = null; + } + + if ($inStyle === 'progid') { + // Special case for IE filters. + continue; + } + + if ($tokens[$i]['code'] === T_STYLE + || ($inStyle !== null + && $tokens[$i]['code'] === T_STRING) + ) { + $expected = strtolower($tokens[$i]['content']); + if ($expected !== $tokens[$i]['content']) { + $error = 'Style definitions must be lowercase; expected %s but found %s'; + $data = array( + $expected, + $tokens[$i]['content'], + ); + $phpcsFile->addError($error, $i, 'FoundUpper', $data); + } + } + }//end for + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php new file mode 100644 index 000000000..f5b02a1ae --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php @@ -0,0 +1,101 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_MissingColonSniff. + * + * Ensure that all style definitions have a colon. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_MissingColonSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_CURLY_BRACKET); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $lastLine = $tokens[$stackPtr]['line']; + $end = $tokens[$stackPtr]['bracket_closer']; + $endLine = $tokens[$end]['line']; + + // Do not check nested style definitions as, for example, in @media style rules. + $nested = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1), $end); + if ($nested !== false) { + return; + } + + $foundColon = false; + $foundString = false; + for ($i = ($stackPtr + 1); $i <= $end; $i++) { + if ($tokens[$i]['line'] !== $lastLine) { + // We changed lines. + if ($foundColon === false && $foundString !== false) { + // We didn't find a colon on the previous line. + $error = 'No style definition found on line; check for missing colon'; + $phpcsFile->addError($error, $foundString, 'Found'); + } + + $foundColon = false; + $foundString = false; + $lastLine = $tokens[$i]['line']; + } + + if ($tokens[$i]['code'] === T_STRING) { + $foundString = $i; + } else if ($tokens[$i]['code'] === T_COLON) { + $foundColon = $i; + } + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php new file mode 100644 index 000000000..66b1ab3b1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php @@ -0,0 +1,107 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_NamedColoursSniff. + * + * Ensure colour names are not used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_NamedColoursSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * A list of named colours. + * + * This is the list of standard colours defined in the CSS spec. + * + * @var array + */ + public $colourNames = array( + 'aqua', + 'black', + 'blue', + 'fuchsia', + 'gray', + 'green', + 'lime', + 'maroon', + 'navy', + 'olive', + 'orange', + 'purple', + 'red', + 'silver', + 'teal', + 'white', + 'yellow', + ); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr - 1)]['code'] === T_HASH + || $tokens[($stackPtr - 1)]['code'] === T_STRING_CONCAT + ) { + // Class name. + return; + } + + if (in_array(strtolower($tokens[$stackPtr]['content']), $this->colourNames) === true) { + $error = 'Named colours are forbidden; use hex, rgb, or rgba values instead'; + $phpcsFile->addError($error, $stackPtr, 'Forbidden'); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php new file mode 100644 index 000000000..52106e4a0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php @@ -0,0 +1,107 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_OpacitySniff. + * + * Ensure that opacity values start with a 0 if it is not a whole number. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_OpacitySniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content'] !== 'opacity') { + return; + } + + $next = $phpcsFile->findNext(array(T_COLON, T_WHITESPACE), ($stackPtr + 1), null, true); + $numbers = array( + T_DNUMBER, + T_LNUMBER, + ); + + if ($next === false || in_array($tokens[$next]['code'], $numbers) === false) { + return; + } + + $value = $tokens[$next]['content']; + if ($tokens[$next]['code'] === T_LNUMBER) { + if ($value !== '0' && $value !== '1') { + $error = 'Opacity values must be between 0 and 1'; + $phpcsFile->addError($error, $next, 'Invalid'); + } + } else { + if (strlen($value) > 3) { + $error = 'Opacity values must have a single value after the decimal point'; + $phpcsFile->addError($error, $next, 'SpacingAfterPoint'); + } else if ($value === '0.0' || $value === '1.0') { + $error = 'Opacity value does not require decimal point; use %s instead'; + $data = array($value{0}); + $phpcsFile->addError($error, $next, 'PointNotRequired', $data); + } else if ($value{0} === '.') { + $error = 'Opacity values must not start with a decimal point; use 0%s instead'; + $data = array($value); + $phpcsFile->addError($error, $next, 'StartWithPoint', $data); + } else if ($value{0} !== '0') { + $error = 'Opacity values must be between 0 and 1'; + $phpcsFile->addError($error, $next, 'Invalid'); + } + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php new file mode 100644 index 000000000..589375d7d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php @@ -0,0 +1,81 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_SemicolonSpacingSniff. + * + * Ensure each style definition has a semi-colon and it is spaced correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_SemicolonSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + if ($semicolon === false || $tokens[$semicolon]['line'] !== $tokens[$stackPtr]['line']) { + $error = 'Style definitions must end with a semicolon'; + $phpcsFile->addError($error, $stackPtr, 'NotAtEnd'); + return; + } + + if ($tokens[($semicolon - 1)]['code'] === T_WHITESPACE) { + $length = strlen($tokens[($semicolon - 1)]['content']); + $error = 'Expected 0 spaces before semicolon in style definition; %s found'; + $data = array($length); + $phpcsFile->addError($error, $stackPtr, 'SpaceFound', $data); + } + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php new file mode 100644 index 000000000..750f59f6e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php @@ -0,0 +1,161 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_CSS_ShorthandSizeSniff. + * + * Ensure sizes are defined using shorthand notation where possible, except in the + * case where shorthand becomes 3 values. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CSS_ShorthandSizeSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('CSS'); + + /** + * A list of styles that we shouldn't check. + * + * These have values that looks like sizes, but are not. + * + * @var array + */ + public $excludeStyles = array( + 'background-position', + 'box-shadow', + 'transform-origin', + '-webkit-transform-origin', + '-ms-transform-origin', + ); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_STYLE); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Some styles look like shorthand but are not actually a set of 4 sizes. + $style = strtolower($tokens[$stackPtr]['content']); + if (in_array($style, $this->excludeStyles) === true) { + return; + } + + // Get the whole style content. + $end = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + $content = $phpcsFile->getTokensAsString(($stackPtr + 1), ($end - $stackPtr - 1)); + $content = trim($content, ': '); + + // Account for a !important annotation. + if (substr($content, -10) === '!important') { + $content = substr($content, 0, -10); + $content = trim($content); + } + + // Check if this style value is a set of numbers with optional prefixes. + $content = preg_replace('/\s+/', ' ', $content); + $values = array(); + $num = preg_match_all( + '/([0-9]+)([a-zA-Z]{2}\s+|%\s+|\s+)/', + $content.' ', + $values, + PREG_SET_ORDER + ); + + // Only interested in styles that have multiple sizes defined. + if ($num < 2) { + return; + } + + // Rebuild the content we matched to ensure we got everything. + $matched = ''; + foreach ($values as $value) { + $matched .= $value[0]; + } + + if ($content !== trim($matched)) { + return; + } + + if ($num === 3) { + $expected = trim($content.' '.$values[1][1].$values[1][2]); + $error = 'Shorthand syntax not allowed here; use %s instead'; + $data = array($expected); + $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); + return; + } + + if ($num === 2) { + if ($values[0][0] !== $values[1][0]) { + // Both values are different, so it is already shorthand. + return; + } + } else if ($values[0][0] !== $values[2][0] || $values[1][0] !== $values[3][0]) { + // Can't shorthand this. + return; + } + + if ($values[0][0] === $values[1][0]) { + // All values are the same. + $expected = $values[0][0]; + } else { + $expected = $values[0][0].' '.$values[1][0]; + } + + $expected = preg_replace('/\s+/', ' ', trim($expected)); + + $error = 'Size definitions must use shorthand if available; expected "%s" but found "%s"'; + $data = array( + $expected, + $content, + ); + + $phpcsFile->addError($error, $stackPtr, 'NotUsed', $data); + + }//end process() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php new file mode 100644 index 000000000..04b894bb1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php @@ -0,0 +1,177 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PSR2_Sniffs_Classes_ClassDeclarationSniff', true) === false) { + $error = 'Class PSR2_Sniffs_Classes_ClassDeclarationSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Class Declaration Test. + * + * Checks the declaration of the class and its inheritance is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_ClassDeclarationSniff extends PSR2_Sniffs_Classes_ClassDeclarationSniff +{ + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We want all the errors from the PSR2 standard, plus some of our own. + parent::process($phpcsFile, $stackPtr); + + $tokens = $phpcsFile->getTokens(); + + // Check that this is the only class or interface in the file. + $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE), ($stackPtr + 1)); + if ($nextClass !== false) { + // We have another, so an error is thrown. + $error = 'Only one interface or class is allowed in a file'; + $phpcsFile->addError($error, $nextClass, 'MultipleClasses'); + } + + }//end process() + + + /** + * Processes the opening section of a class declaration. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function processOpen(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + parent::processOpen($phpcsFile, $stackPtr); + + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { + $prevContent = $tokens[($stackPtr - 1)]['content']; + if ($prevContent !== $phpcsFile->eolChar) { + $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); + $spaces = strlen($blankSpace); + + if (in_array($tokens[($stackPtr - 2)]['code'], array(T_ABSTRACT, T_FINAL)) === false) { + if ($spaces !== 0) { + $type = strtolower($tokens[$stackPtr]['content']); + $error = 'Expected 0 spaces before %s keyword; %s found'; + $data = array( + $type, + $spaces, + ); + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeKeyword', $data); + } + } + } + }//end if + + }//end processOpen() + + + /** + * Processes the closing section of a class declaration. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function processClose(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $closeBrace = $tokens[$stackPtr]['scope_closer']; + if ($tokens[($closeBrace - 1)]['code'] === T_WHITESPACE) { + $prevContent = $tokens[($closeBrace - 1)]['content']; + if ($prevContent !== $phpcsFile->eolChar) { + $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); + $spaces = strlen($blankSpace); + if ($spaces !== 0) { + if ($tokens[($closeBrace - 1)]['line'] !== $tokens[$closeBrace]['line']) { + $error = 'Expected 0 spaces before closing brace; newline found'; + $phpcsFile->addError($error, $closeBrace, 'NewLineBeforeCloseBrace'); + } else { + $error = 'Expected 0 spaces before closing brace; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $closeBrace, 'SpaceBeforeCloseBrace', $data); + } + } + } + } + + // Check that the closing brace has one blank line after it. + $nextContent = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), ($closeBrace + 1), null, true); + if ($nextContent === false) { + // No content found, so we reached the end of the file. + // That means there was no closing tag either. + $error = 'Closing brace of a %s must be followed by a blank line and then a closing PHP tag'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $closeBrace, 'EndFileAfterCloseBrace', $data); + } else { + $nextLine = $tokens[$nextContent]['line']; + $braceLine = $tokens[$closeBrace]['line']; + if ($braceLine === $nextLine) { + $error = 'Closing brace of a %s must be followed by a single blank line'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $closeBrace, 'NoNewlineAfterCloseBrace', $data); + } else if ($nextLine !== ($braceLine + 2)) { + $difference = ($nextLine - $braceLine - 1); + $error = 'Closing brace of a %s must be followed by a single blank line; found %s'; + $data = array( + $tokens[$stackPtr]['content'], + $difference, + ); + $phpcsFile->addError($error, $closeBrace, 'NewlinesAfterCloseBrace', $data); + } + }//end if + + // Check the closing brace is on it's own line, but allow + // for comments like "//end class". + $nextContent = $phpcsFile->findNext(T_COMMENT, ($closeBrace + 1), null, true); + if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line']) { + $type = strtolower($tokens[$stackPtr]['content']); + $error = 'Closing %s brace must be on a line by itself'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data); + } + + }//end processClose() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php new file mode 100644 index 000000000..a55185197 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php @@ -0,0 +1,86 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Classes_ClassFileNameSniff. + * + * Tests that the file name and the name of the class contained within the file + * match. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_ClassFileNameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fullPath = basename($phpcsFile->getFilename()); + $fileName = substr($fullPath, 0, strrpos($fullPath, '.')); + if ($fileName === '') { + // No filename probably means STDIN, so we can't do this check. + return; + } + + $tokens = $phpcsFile->getTokens(); + $decName = $phpcsFile->findNext(T_STRING, $stackPtr); + + if ($tokens[$decName]['content'] !== $fileName) { + $error = '%s name doesn\'t match filename; expected "%s %s"'; + $data = array( + ucfirst($tokens[$stackPtr]['content']), + $tokens[$stackPtr]['content'], + $fileName, + ); + $phpcsFile->addError($error, $stackPtr, 'NoMatch', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php new file mode 100644 index 000000000..1c1ace0c3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php @@ -0,0 +1,100 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Classes_DuplicatePropertySniff. + * + * Ensures JS classes don't contain duplicate property names. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_DuplicatePropertySniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OBJECT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $start = $tokens[$stackPtr]['scope_opener']; + $end = $tokens[$stackPtr]['scope_closer']; + + $properties = array(); + $wantedTokens = array( + T_PROPERTY, + T_OPEN_CURLY_BRACKET, + ); + + $next = $phpcsFile->findNext($wantedTokens, ($start + 1), $end); + while ($next !== false && $next < $end) { + // Skip nested objects. + if ($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET) { + $next = $tokens[$next]['bracket_closer']; + } else { + $propName = $tokens[$next]['content']; + if (isset($properties[$propName]) === true) { + $error = 'Duplicate property definition found for "%s"; previously defined on line %s'; + $data = array( + $propName, + $tokens[$properties[$propName]]['line'], + ); + $phpcsFile->addError($error, $next, 'Found', $data); + } + + $properties[$propName] = $next; + }//end if + + $next = $phpcsFile->findNext($wantedTokens, ($next + 1), $end); + }//end while + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php new file mode 100644 index 000000000..adb9a7309 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php @@ -0,0 +1,85 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff. + * + * Ensures all class keywords are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_EXTENDS, + T_IMPLEMENTS, + T_ABSTRACT, + T_FINAL, + T_VAR, + T_CONST, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + if ($content !== strtolower($content)) { + $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtoupper($content), + strtolower($content), + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php new file mode 100644 index 000000000..29f629ba2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php @@ -0,0 +1,171 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Tests self member references. + * + * Verifies that : + *
    + *
  • self:: is used instead of Self::
  • + *
  • self:: is used for local static member reference
  • + *
  • self:: is used instead of self ::
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_SelfMemberReferenceSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs a Squiz_Sniffs_Classes_SelfMemberReferenceSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS), array(T_DOUBLE_COLON)); + + }//end __construct() + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * @param int $currScope The current scope opener token. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $tokens = $phpcsFile->getTokens(); + + $className = ($stackPtr - 1); + if ($tokens[$className]['code'] === T_SELF) { + if (strtolower($tokens[$className]['content']) !== $tokens[$className]['content']) { + $error = 'Must use "self::" for local static member reference; found "%s::"'; + $data = array($tokens[$className]['content']); + $phpcsFile->addError($error, $className, 'IncorrectCase', $data); + return; + } + } else if ($tokens[$className]['code'] === T_STRING) { + // Make sure this is another class reference. + $declarationName = $phpcsFile->getDeclarationName($currScope); + $fullQualifiedClassName = $tokens[$className]['content']; + + // If the class is called with a namespace prefix, build fully qualified + // namespace calls for both current scope class and requested class. + if ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR) { + $declarationName = $this->getDeclarationNameWithNamespace($tokens, $className); + $declarationName = substr($declarationName, 1); + $fullQualifiedClassName = $this->getNamespaceOfScope($phpcsFile, $currScope); + $fullQualifiedClassName .= '\\'.$tokens[$className]['content']; + } + + if ($declarationName === $fullQualifiedClassName) { + // Class name is the same as the current class, which is not allowed + // except if being used inside a closure. + if ($phpcsFile->hasCondition($stackPtr, T_CLOSURE) === false) { + $error = 'Must use "self::" for local static member reference'; + $phpcsFile->addError($error, $className, 'NotUsed'); + return; + } + } + }//end if + + if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { + $found = strlen($tokens[($stackPtr - 1)]['content']); + $error = 'Expected 0 spaces before double colon; %s found'; + $data = array($found); + $phpcsFile->addError($error, $className, 'SpaceBefore', $data); + } + + if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { + $found = strlen($tokens[($stackPtr + 1)]['content']); + $error = 'Expected 0 spaces after double colon; %s found'; + $data = array($found); + $phpcsFile->addError($error, $className, 'SpaceAfter', $data); + } + + }//end processTokenWithinScope() + + + /** + * Returns the declaration names for classes/interfaces/functions with a namespace. + * + * @param array $tokens Token stack for this file + * @param int $stackPtr The position where the namespace building will start. + * + * @return string + */ + protected function getDeclarationNameWithNamespace(array $tokens, $stackPtr) + { + $nameParts = array(); + $currentPointer = $stackPtr; + while ($tokens[$currentPointer]['code'] === T_NS_SEPARATOR + || $tokens[$currentPointer]['code'] === T_STRING + ) { + $nameParts[] = $tokens[$currentPointer]['content']; + $currentPointer--; + } + + $nameParts = array_reverse($nameParts); + return implode('', $nameParts); + + }//end getDeclarationNameWithNamespace() + + + /** + * Returns the namespace declaration of a file. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the search for the + * namespace declaration will start. + * + * @return string + */ + protected function getNamespaceOfScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $namespace = '\\'; + $namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr); + + if ($namespaceDeclaration !== false) { + $endOfNamespaceDeclaration = $phpcsFile->findNext(T_SEMICOLON, $namespaceDeclaration); + $namespace = $this->getDeclarationNameWithNamespace( + $phpcsFile->getTokens(), + ($endOfNamespaceDeclaration - 1) + ); + } + + return $namespace; + + }//end getNamespaceOfScope + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php new file mode 100644 index 000000000..00baf9e1a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php @@ -0,0 +1,95 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Classes_ValidClassNameSniff. + * + * Ensures classes are in camel caps, and the first letter is capitalised + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Classes_ValidClassNameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + $error = 'Possible parse error: %s missing opening or closing brace'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data); + return; + } + + // Determine the name of the class or interface. Note that we cannot + // simply look for the first T_STRING because a class name + // starting with the number will be multiple tokens. + $opener = $tokens[$stackPtr]['scope_opener']; + $nameStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), $opener, true); + $nameEnd = $phpcsFile->findNext(T_WHITESPACE, $nameStart, $opener); + $name = trim($phpcsFile->getTokensAsString($nameStart, ($nameEnd - $nameStart))); + + // Check for camel caps format. + $valid = PHP_CodeSniffer::isCamelCaps($name, true, true, false); + if ($valid === false) { + $type = ucfirst($tokens[$stackPtr]['content']); + $error = '%s name "%s" is not in camel caps format'; + $data = array( + $type, + $name, + ); + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php new file mode 100644 index 000000000..7ea785618 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php @@ -0,0 +1,54 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_CodeAnalysis_EmptyStatementSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_CodeAnalysis_EmptyStatementSniff not found'); +} + +/** + * This sniff class detects empty statement. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff extends Generic_Sniffs_CodeAnalysis_EmptyStatementSniff +{ + + /** + * List of block tokens that this sniff covers. + * + * The key of this hash identifies the required token while the boolean + * value says mark an error or mark a warning. + * + * @var array + */ + protected $checkedTokens = array( + T_DO => true, + T_ELSE => true, + T_ELSEIF => true, + T_FOR => true, + T_FOREACH => true, + T_IF => true, + T_SWITCH => true, + T_WHILE => true, + ); + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php new file mode 100644 index 000000000..5eaaa6ae6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php @@ -0,0 +1,246 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_BlockCommentSniff. + * + * Verifies that block comments are used appropriately. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_BlockCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_COMMENT, + T_DOC_COMMENT, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If its an inline comment return. + if (substr($tokens[$stackPtr]['content'], 0, 2) !== '/*') { + return; + } + + // If this is a function/class/interface doc block comment, skip it. + // We are only interested in inline doc block comments. + if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) { + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + $ignore = array( + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_FUNCTION, + T_PUBLIC, + T_PRIVATE, + T_FINAL, + T_PROTECTED, + T_STATIC, + T_ABSTRACT, + T_CONST, + ); + if (in_array($tokens[$nextToken]['code'], $ignore) === true) { + return; + } + + $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { + return; + } + }//end if + + $commentLines = array($stackPtr); + $nextComment = $stackPtr; + $lastLine = $tokens[$stackPtr]['line']; + + // Construct the comment into an array. + while (($nextComment = $phpcsFile->findNext($tokens[$stackPtr]['code'], ($nextComment + 1), null, false)) !== false) { + if (($tokens[$nextComment]['line'] - 1) !== $lastLine) { + // Not part of the block. + break; + } + + $lastLine = $tokens[$nextComment]['line']; + $commentLines[] = $nextComment; + } + + if (count($commentLines) <= 2) { + // Small comment. Can't be right. + if (count($commentLines) === 1) { + $error = 'Single line block comment not allowed; use inline ("// text") comment instead'; + $phpcsFile->addError($error, $stackPtr, 'SingleLine'); + return; + } + + if (trim($tokens[$commentLines[1]]['content']) === '*/') { + if (trim($tokens[$stackPtr]['content']) === '/*') { + $error = 'Empty block comment not allowed'; + $phpcsFile->addError($error, $stackPtr, 'Empty'); + return; + } + } + } + + $content = trim($tokens[$stackPtr]['content']); + if ($content !== '/*' && $content !== '/**') { + $error = 'Block comment text must start on a new line'; + $phpcsFile->addError($error, $stackPtr, 'NoNewLine'); + return; + } + + $starColumn = ($tokens[$stackPtr]['column'] + 3); + + // Make sure first line isn't blank. + if (trim($tokens[$commentLines[1]]['content']) === '') { + $error = 'Empty line not allowed at start of comment'; + $phpcsFile->addError($error, $commentLines[1], 'HasEmptyLine'); + } else { + // Check indentation of first line. + $content = $tokens[$commentLines[1]]['content']; + $commentText = ltrim($content); + $leadingSpace = (strlen($content) - strlen($commentText)); + if ($leadingSpace !== $starColumn) { + $expected = $starColumn; + $expected .= ($starColumn === 1) ? ' space' : ' spaces'; + $data = array( + $expected, + $leadingSpace, + ); + + $error = 'First line of comment not aligned correctly; expected %s but found %s'; + $phpcsFile->addError($error, $commentLines[1], 'FirstLineIndent', $data); + } + + if (preg_match('|\p{Lu}|u', $commentText[0]) === 0) { + $error = 'Block comments must start with a capital letter'; + $phpcsFile->addError($error, $commentLines[1], 'NoCapital'); + } + } + + // Check that each line of the comment is indented past the star. + foreach ($commentLines as $line) { + $leadingSpace = (strlen($tokens[$line]['content']) - strlen(ltrim($tokens[$line]['content']))); + // First and last lines (comment opener and closer) are handled separately. + if ($line === $commentLines[(count($commentLines) - 1)] || $line === $commentLines[0]) { + continue; + } + + // First comment line was handled above. + if ($line === $commentLines[1]) { + continue; + } + + // If it's empty, continue. + if (trim($tokens[$line]['content']) === '') { + continue; + } + + if ($leadingSpace < $starColumn) { + $expected = $starColumn; + $expected .= ($starColumn === 1) ? ' space' : ' spaces'; + $data = array( + $expected, + $leadingSpace, + ); + + $error = 'Comment line indented incorrectly; expected at least %s but found %s'; + $phpcsFile->addError($error, $line, 'LineIndent', $data); + } + }//end foreach + + // Finally, test the last line is correct. + $lastIndex = (count($commentLines) - 1); + $content = trim($tokens[$commentLines[$lastIndex]]['content']); + if ($content !== '*/' && $content !== '**/') { + $error = 'Comment closer must be on a new line'; + $phpcsFile->addError($error, $commentLines[$lastIndex]); + } else { + $content = $tokens[$commentLines[$lastIndex]]['content']; + $commentText = ltrim($content); + $leadingSpace = (strlen($content) - strlen($commentText)); + if ($leadingSpace !== ($tokens[$stackPtr]['column'] - 1)) { + $expected = ($tokens[$stackPtr]['column'] - 1); + $expected .= ($expected === 1) ? ' space' : ' spaces'; + $data = array( + $expected, + $leadingSpace, + ); + + $error = 'Last line of comment aligned incorrectly; expected %s but found %s'; + $phpcsFile->addError($error, $commentLines[$lastIndex], 'LastLineIndent', $data); + } + + } + + // Check that the lines before and after this comment are blank. + $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if (isset($tokens[$contentBefore]['scope_closer']) === true + && $tokens[$contentBefore]['scope_opener'] === $contentBefore + ) { + if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) !== 1) { + $error = 'Empty line not required before block comment'; + $phpcsFile->addError($error, $stackPtr, 'HasEmptyLineBefore'); + } + } else { + if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) < 2) { + $error = 'Empty line required before block comment'; + $phpcsFile->addError($error, $stackPtr, 'NoEmptyLineBefore'); + } + } + + $commentCloser = $commentLines[$lastIndex]; + $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($commentCloser + 1), null, true); + if (($tokens[$contentAfter]['line'] - $tokens[$commentCloser]['line']) < 2) { + $error = 'Empty line required after block comment'; + $phpcsFile->addError($error, $commentCloser, 'NoEmptyLineAfter'); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php new file mode 100644 index 000000000..56742e30e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php @@ -0,0 +1,254 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); +} + +/** + * Parses and verifies the class doc comment. + * + * Verifies that : + *
    + *
  • A class doc comment exists.
  • + *
  • There is exactly one blank line before the class comment.
  • + *
  • Short description ends with a full stop.
  • + *
  • There is a blank line after the short description.
  • + *
  • Each paragraph of the long description ends with a full stop.
  • + *
  • There is a blank line between the description and the tags.
  • + *
  • Check the format of the since tag (x.x.x).
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_ClassCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLASS); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + $tokens = $phpcsFile->getTokens(); + $find = array( + T_ABSTRACT, + T_WHITESPACE, + T_FINAL, + ); + + // Extract the class comment docblock. + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); + + if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { + $phpcsFile->addError('You must use "/**" style comments for a class comment', $stackPtr, 'WrongStyle'); + return; + } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing class doc comment', $stackPtr, 'Missing'); + return; + } + + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + + // Distinguish file and class comment. + $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1)); + if ($prevClassToken === false) { + // This is the first class token in this file, need extra checks. + $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true); + if ($prevNonComment !== false) { + $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1)); + if ($prevComment === false) { + // There is only 1 doc comment between open tag and class token. + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $stackPtr, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + // Blank line between the class and the doc block. + // The doc block is most likely a file comment. + $phpcsFile->addError('Missing class doc comment', ($stackPtr + 1), 'Missing'); + return; + } + }//end if + }//end if + + // Exactly one blank line before the class comment. + $prevTokenEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); + if ($prevTokenEnd !== false) { + $blankLineBefore = 0; + for ($i = ($prevTokenEnd + 1); $i < $commentStart; $i++) { + if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) { + $blankLineBefore++; + } + } + + if ($blankLineBefore !== 2) { + $error = 'There must be exactly one blank line before the class comment'; + $phpcsFile->addError($error, ($commentStart - 1), 'SpacingBefore'); + } + } + + }//end if + }//end if + + $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + // Parse the class comment docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Class doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + // The first line of the comment should just be the /** code. + $eolPos = strpos($commentString, $phpcsFile->eolChar); + $firstLine = substr($commentString, 0, $eolPos); + if ($firstLine !== '/**') { + $error = 'The open comment tag must be the only content on the line'; + $phpcsFile->addError($error, $commentStart, 'SpacingAfterOpen'); + } + + // Check for a comment description. + $short = rtrim($comment->getShortComment(), $phpcsFile->eolChar); + if (trim($short) === '') { + $error = 'Missing short description in class doc comment'; + $phpcsFile->addError($error, $commentStart, 'MissingShort'); + return; + } + + // No extra newline before short description. + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before class comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in class comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); + } + + $newlineCount += $newlineBetween; + + $testLong = trim($long); + if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { + $error = 'Class comment long description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); + } + } + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in class comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Short description must be single line and end with a full stop. + $testShort = trim($short); + $lastChar = $testShort[(strlen($testShort) - 1)]; + if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { + $error = 'Class comment short description must be on a single line'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); + } + if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { + $error = 'Class comment short description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); + } + + if ($lastChar !== '.') { + $error = 'Class comment short description must end with a full stop'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); + } + + // No tags are allowed in the class comment. + $tags = $this->commentParser->getTags(); + foreach ($tags as $errorTag) { + $error = '@%s tag is not allowed in class comment'; + $data = array($errorTag['tag']); + $phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data); + } + + // The last content should be a newline and the content before + // that should not be blank. If there is more blank space + // then they have additional blank lines at the end of the comment. + $words = $this->commentParser->getWords(); + $lastPos = (count($words) - 1); + if (trim($words[($lastPos - 1)]) !== '' + || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false + || trim($words[($lastPos - 2)]) === '' + ) { + $error = 'Additional blank lines found at end of class comment'; + $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); + } + + }//end process() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php new file mode 100644 index 000000000..37583e8fe --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php @@ -0,0 +1,127 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff. + * + * Checks the //end ... comments on classes, interfaces and functions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_FUNCTION, + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens.. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['code'] === T_FUNCTION) { + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + + // Abstract methods do not require a closing comment. + if ($methodProps['is_abstract'] === true) { + return; + } + + // Closures do not require a closing comment. + if ($methodProps['is_closure'] === true) { + return; + } + + // If this function is in an interface then we don't require + // a closing comment. + if ($phpcsFile->hasCondition($stackPtr, T_INTERFACE) === true) { + return; + } + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + $error = 'Possible parse error: non-abstract method defined as abstract'; + $phpcsFile->addWarning($error, $stackPtr, 'Abstract'); + return; + } + + $decName = $phpcsFile->getDeclarationName($stackPtr); + $comment = '//end '.$decName.'()'; + } else if ($tokens[$stackPtr]['code'] === T_CLASS) { + $comment = '//end class'; + } else { + $comment = '//end interface'; + }//end if + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + $error = 'Possible parse error: %s missing opening or closing brace'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data); + return; + } + + $closingBracket = $tokens[$stackPtr]['scope_closer']; + + if ($closingBracket === null) { + // Possible inline structure. Other tests will handle it. + return; + } + + $error = 'Expected '.$comment; + if (isset($tokens[($closingBracket + 1)]) === false || $tokens[($closingBracket + 1)]['code'] !== T_COMMENT) { + $phpcsFile->addError($error, $closingBracket, 'Missing'); + return; + } + + if (rtrim($tokens[($closingBracket + 1)]['content']) !== $comment) { + $phpcsFile->addError($error, $closingBracket, 'Incorrect'); + return; + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php new file mode 100644 index 000000000..e5415ee18 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php @@ -0,0 +1,151 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_DocCommentAlignmentSniff. + * + * Tests that the stars in a doc comment align correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_DocCommentAlignmentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_DOC_COMMENT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We are only interested in function/class/interface doc block comments. + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + $ignore = array( + T_CLASS, + T_INTERFACE, + T_FUNCTION, + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_STATIC, + T_ABSTRACT, + ); + + if (in_array($tokens[$nextToken]['code'], $ignore) === false) { + // Could be a file comment. + $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prevToken]['code'] !== T_OPEN_TAG) { + return; + } + } + + // We only want to get the first comment in a block. If there is + // a comment on the line before this one, return. + $docComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($stackPtr - 1)); + if ($docComment !== false) { + if ($tokens[$docComment]['line'] === ($tokens[$stackPtr]['line'] - 1)) { + return; + } + } + + $comments = array($stackPtr); + $currentComment = $stackPtr; + $lastComment = $stackPtr; + while (($currentComment = $phpcsFile->findNext(T_DOC_COMMENT, ($currentComment + 1))) !== false) { + if ($tokens[$lastComment]['line'] === ($tokens[$currentComment]['line'] - 1)) { + $comments[] = $currentComment; + $lastComment = $currentComment; + } else { + break; + } + } + + // The $comments array now contains pointers to each token in the + // comment block. + $requiredColumn = strpos($tokens[$stackPtr]['content'], '*'); + $requiredColumn += $tokens[$stackPtr]['column']; + + foreach ($comments as $commentPointer) { + // Check the spacing after each asterisk. + $content = $tokens[$commentPointer]['content']; + $firstChar = substr($content, 0, 1); + $lastChar = substr($content, -1); + if ($firstChar !== '/' && $lastChar !== '/') { + $matches = array(); + preg_match('|^(\s+)?\*(\s+)?@|', $content, $matches); + if (empty($matches) === false) { + if (isset($matches[2]) === false) { + $error = 'Expected 1 space between asterisk and tag; 0 found'; + $phpcsFile->addError($error, $commentPointer, 'NoSpaceBeforeTag'); + } else { + $length = strlen($matches[2]); + if ($length !== 1) { + $error = 'Expected 1 space between asterisk and tag; %s found'; + $data = array($length); + $phpcsFile->addError($error, $commentPointer, 'SpaceBeforeTag', $data); + } + } + } + }//end foreach + + // Check the alignment of each asterisk. + $currentColumn = strpos($content, '*'); + $currentColumn += $tokens[$commentPointer]['column']; + + if ($currentColumn === $requiredColumn) { + // Star is aligned correctly. + continue; + } + + $error = 'Expected %s space(s) before asterisk; %s found'; + $data = array( + ($requiredColumn - 1), + ($currentColumn - 1), + ); + $phpcsFile->addError($error, $commentPointer, 'SpaceBeforeAsterisk', $data); + }//end foreach + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php new file mode 100644 index 000000000..3de6fc605 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php @@ -0,0 +1,73 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_EmptyCatchCommentSniff. + * + * Checks for empty Catch clause. Catch clause must at least have comment + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_EmptyCatchCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CATCH); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $scopeStart = $tokens[$stackPtr]['scope_opener']; + $firstContent = $phpcsFile->findNext(T_WHITESPACE, ($scopeStart + 1), $tokens[$stackPtr]['scope_closer'], true); + + if ($firstContent === false) { + $error = 'Empty CATCH statement must have a comment to explain why the exception is not handled'; + $phpcsFile->addError($error, $scopeStart, 'Missing'); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php new file mode 100644 index 000000000..a98ea472c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php @@ -0,0 +1,564 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); +} + +/** + * Parses and verifies the file doc comment. + * + * Verifies that : + *
    + *
  • A file doc comment exists.
  • + *
  • There is no blank line between the open tag and the file comment.
  • + *
  • Short description ends with a full stop.
  • + *
  • There is a blank line after the short description.
  • + *
  • Each paragraph of the long description ends with a full stop.
  • + *
  • There is a blank line between the description and the tags.
  • + *
  • Check the order, indentation and content of each tag.
  • + *
  • There is exactly one blank line after the file comment.
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +class Squiz_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * The header comment parser for the current file. + * + * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + + $errorToken = ($stackPtr + 1); + if (isset($tokens[$errorToken]) === false) { + $errorToken--; + } + + // Find the next non whitespace token. + $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + + if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) { + // We are only interested if this is the first open tag. + return; + } else if ($tokens[$commentStart]['code'] === T_COMMENT) { + $phpcsFile->addError('You must use "/**" style comments for a file comment', $errorToken, 'WrongStyle'); + return; + } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); + return; + } + + // Extract the header comment docblock. + $commentEnd = ($phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true) - 1); + + // Check if there is only 1 doc comment between the open tag and class token. + $nextToken = array( + T_ABSTRACT, + T_CLASS, + T_DOC_COMMENT, + ); + + $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1)); + if ($commentNext !== false && $tokens[$commentNext]['code'] !== T_DOC_COMMENT) { + // Found a class token right after comment doc block. + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $commentNext, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $commentNext, false, $phpcsFile->eolChar); + if ($newlineToken === false) { + // No blank line between the class token and the doc block. + // The doc block is most likely a class comment. + $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); + return; + } + } + } + + // No blank line between the open tag and the file comment. + $blankLineBefore = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, false, $phpcsFile->eolChar); + if ($blankLineBefore !== false && $blankLineBefore < $commentStart) { + $error = 'Extra newline found after the open tag'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen'); + } + + // Exactly one blank line after the file comment. + $nextTokenStart = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), null, true); + if ($nextTokenStart !== false) { + $blankLineAfter = 0; + for ($i = ($commentEnd + 1); $i < $nextTokenStart; $i++) { + if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) { + $blankLineAfter++; + } + } + + if ($blankLineAfter !== 2) { + $error = 'There must be exactly one blank line after the file comment'; + $phpcsFile->addError($error, ($commentEnd + 1), 'SpacingAfterComment'); + } + } + + $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + // Parse the header comment docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'Exception'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'File doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + // The first line of the comment should just be the /** code. + $eolPos = strpos($commentString, $phpcsFile->eolChar); + $firstLine = substr($commentString, 0, $eolPos); + if ($firstLine !== '/**') { + $error = 'The open comment tag must be the only content on the line'; + $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); + } + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before file comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in file comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); + } + + $newlineCount += $newlineBetween; + + $testLong = trim($long); + if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { + $error = 'File comment long description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); + } + }//end if + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in file comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Short description must be single line and end with a full stop. + $testShort = trim($short); + if ($testShort === '') { + $error = 'Missing short description in file comment'; + $phpcsFile->addError($error, ($commentStart + 1), 'MissingShort'); + } else { + $lastChar = $testShort[(strlen($testShort) - 1)]; + if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { + $error = 'File comment short description must be on a single line'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); + } + + if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { + $error = 'File comment short description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); + } + + if ($lastChar !== '.') { + $error = 'File comment short description must end with a full stop'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); + } + }//end if + + // Check each tag. + $this->processTags($commentStart, $commentEnd); + + // The last content should be a newline and the content before + // that should not be blank. If there is more blank space + // then they have additional blank lines at the end of the comment. + $words = $this->commentParser->getWords(); + $lastPos = (count($words) - 1); + if (trim($words[($lastPos - 1)]) !== '' + || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false + || trim($words[($lastPos - 2)]) === '' + ) { + $error = 'Additional blank lines found at end of file comment'; + $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); + } + + }//end process() + + + /** + * Processes each required or optional tag. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processTags($commentStart, $commentEnd) + { + // Required tags in correct order. + $tags = array( + 'package' => 'precedes @subpackage', + 'subpackage' => 'follows @package', + 'author' => 'follows @subpackage', + 'copyright' => 'follows @author', + ); + + $foundTags = $this->commentParser->getTagOrders(); + $errorPos = 0; + $orderIndex = 0; + $longestTag = 0; + $indentation = array(); + foreach ($tags as $tag => $orderText) { + + // Required tag missing. + if (in_array($tag, $foundTags) === false) { + $error = 'Missing @%s tag in file comment'; + $data = array($tag); + $this->currentFile->addError($error, $commentEnd, 'Missing'.ucfirst($tag).'Tag', $data); + continue; + } + + // Get the line number for current tag. + $tagName = ucfirst($tag); + if ($tagName === 'Author' || $tagName === 'Copyright') { + // These tags are different because they return an array. + $tagName .= 's'; + } + + // Work out the line number for this tag. + $getMethod = 'get'.$tagName; + $tagElement = $this->commentParser->$getMethod(); + if (is_null($tagElement) === true || empty($tagElement) === true) { + continue; + } else if (is_array($tagElement) === true && empty($tagElement) === false) { + $tagElement = $tagElement[0]; + } + + $errorPos = ($commentStart + $tagElement->getLine()); + + // Make sure there is no duplicate tag. + $foundIndexes = array_keys($foundTags, $tag); + if (count($foundIndexes) > 1) { + $error = 'Only 1 @%s tag is allowed in file comment'; + $data = array($tag); + $this->currentFile->addError($error, $errorPos, 'Duplicate'.ucfirst($tag).'Tag', $data); + } + + // Check tag order. + if ($foundIndexes[0] > $orderIndex) { + $orderIndex = $foundIndexes[0]; + } else { + $error = 'The @%s tag is in the wrong order; the tag %s'; + $data = array( + $tag, + $orderText, + ); + $this->currentFile->addError($error, $errorPos, ucfirst($tag).'TagOrder', $data); + } + + // Store the indentation of each tag. + $len = strlen($tag); + if ($len > $longestTag) { + $longestTag = $len; + } + + $indentation[] = array( + 'tag' => $tag, + 'errorPos' => $errorPos, + 'space' => $this->getIndentation($tag, $tagElement), + ); + + $method = 'process'.$tagName; + if (method_exists($this, $method) === true) { + // Process each tag if a method is defined. + call_user_func(array($this, $method), $errorPos); + } else { + $tagElement->process($this->currentFile, $commentStart, 'file'); + } + }//end foreach + + // Check tag indentation. + foreach ($indentation as $indentInfo) { + $tagName = ucfirst($indentInfo['tag']); + if ($tagName === 'Author') { + $tagName .= 's'; + } + + if ($indentInfo['space'] !== 0 && $indentInfo['space'] !== ($longestTag + 1)) { + $expected = ($longestTag - strlen($indentInfo['tag']) + 1); + $space = ($indentInfo['space'] - strlen($indentInfo['tag'])); + $error = '@%s tag comment indented incorrectly; expected %s spaces but found %s'; + $data = array( + $indentInfo['tag'], + $expected, + $space, + ); + $this->currentFile->addError($error, $indentInfo['errorPos'], ucfirst($indentInfo['tag']).'TagIndent', $data); + } + } + + }//end processTags() + + + /** + * Get the indentation information of each tag. + * + * @param string $tagName The name of the doc comment element. + * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment element. + * + * @return void + */ + protected function getIndentation($tagName, $tagElement) + { + if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) { + if ($tagElement->getContent() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' ')); + } + } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) { + if ($tagElement->getValue() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' ')); + } + } + + return 0; + + }//end getIndentation() + + + /** + * The package name must be camel-cased. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processPackage($errorPos) + { + $package = $this->commentParser->getPackage(); + if ($package !== null) { + $content = $package->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @package tag in file comment'; + $this->currentFile->addError($error, $errorPos, 'MissingPackage'); + } else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + // Package name must be properly camel-cased. + $nameBits = explode('_', str_replace(' ', '', $content)); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $error = 'Package name "%s" is not valid; consider "%s" instead'; + $data = array( + $content, + trim($newName, '_'), + ); + $this->currentFile->addError($error, $errorPos, 'IncorrectPackage', $data); + } else if (strpos($content, 'Squiz') === 0) { + // Package name must not start with Squiz. + $newName = substr($content, 5); + $error = 'Package name "%s" is not valid; consider "%s" instead'; + $data = array( + $content, + $newName, + ); + $this->currentFile->addError($error, $errorPos, 'SquizPackage', $data); + } + } + + }//end processPackage() + + + /** + * The subpackage name must be camel-cased. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processSubpackage($errorPos) + { + $subpackage = $this->commentParser->getSubpackage(); + if ($subpackage !== null) { + $content = $subpackage->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @subpackage tag in file comment'; + $this->currentFile->addError($error, $errorPos, 'MissingSubpackage'); + } else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + // Subpackage name must be properly camel-cased. + $nameBits = explode('_', $content); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $error = 'Subpackage name "%s" is not valid; consider "%s" instead'; + $data = array( + $content, + trim($newName, '_'), + ); + $this->currentFile->addError($error, $errorPos, 'IncorrectSubpackage', $data); + } + } + + }//end processSubpackage() + + + /** + * Author tag must be 'Squiz Pty Ltd '. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processAuthors($errorPos) + { + $authors = $this->commentParser->getAuthors(); + if (empty($authors) === false) { + $author = $authors[0]; + $content = $author->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @author tag in file comment'; + $this->currentFile->addError($error, $errorPos, 'MissingAuthor'); + } else if ($content !== 'Squiz Pty Ltd ') { + $error = 'Expected "Squiz Pty Ltd " for author tag'; + $this->currentFile->addError($error, $errorPos, 'IncorrectAuthor'); + } + } + + }//end processAuthors() + + + /** + * Copyright tag must be in the form '2006-YYYY Squiz Pty Ltd (ABN 77 084 670 600)'. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processCopyrights($errorPos) + { + $copyrights = $this->commentParser->getCopyrights(); + $copyright = $copyrights[0]; + + if ($copyright !== null) { + $content = $copyright->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @copyright tag in file comment'; + $this->currentFile->addError($error, $errorPos, 'MissingCopyright'); + + } else if (preg_match('/^([0-9]{4})(-[0-9]{4})? (Squiz Pty Ltd \(ABN 77 084 670 600\))$/', $content) === 0) { + $error = 'Expected "xxxx-xxxx Squiz Pty Ltd (ABN 77 084 670 600)" for copyright declaration'; + $this->currentFile->addError($error, $errorPos, 'IncorrectCopyright'); + } + } + + }//end processCopyrights() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php new file mode 100644 index 000000000..09d63e1f3 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php @@ -0,0 +1,818 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) { + $error = 'Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Parses and verifies the doc comments for functions. + * + * Verifies that : + *
    + *
  • A comment exists
  • + *
  • There is a blank newline after the short description
  • + *
  • There is a blank newline between the long and short description
  • + *
  • There is a blank newline between the long description and tags
  • + *
  • Parameter names represent those in the method
  • + *
  • Parameter comments are in the correct order
  • + *
  • Parameter comments are complete
  • + *
  • A type hint is provided for array and custom class
  • + *
  • Type hint matches the actual variable/class type
  • + *
  • A blank line is present before the first and after the last parameter
  • + *
  • A return type exists
  • + *
  • Any throw tag must have a comment
  • + *
  • The tag order and indentation are correct
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The name of the method that we are currently processing. + * + * @var string + */ + private $_methodName = ''; + + /** + * The position in the stack where the function token was found. + * + * @var int + */ + private $_functionToken = null; + + /** + * The position in the stack where the class token was found. + * + * @var int + */ + private $_classToken = null; + + /** + * The index of the current tag we are processing. + * + * @var int + */ + private $_tagIndex = 0; + + /** + * The function comment parser for the current method. + * + * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + $tokens = $phpcsFile->getTokens(); + + $find = array( + T_COMMENT, + T_DOC_COMMENT, + T_CLASS, + T_FUNCTION, + T_OPEN_TAG, + ); + + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1)); + + if ($commentEnd === false) { + return; + } + + // If the token that we found was a class or a function, then this + // function has no doc comment. + $code = $tokens[$commentEnd]['code']; + + if ($code === T_COMMENT) { + // The function might actually be missing a comment, and this last comment + // found is just commenting a bit of code on a line. So if it is not the + // only thing on the line, assume we found nothing. + $prevContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $commentEnd); + if ($tokens[$commentEnd]['line'] === $tokens[$commentEnd]['line']) { + $error = 'Missing function doc comment'; + $phpcsFile->addError($error, $stackPtr, 'Missing'); + } else { + $error = 'You must use "/**" style comments for a function comment'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + } + return; + } else if ($code !== T_DOC_COMMENT) { + $error = 'Missing function doc comment'; + $phpcsFile->addError($error, $stackPtr, 'Missing'); + return; + } else if (trim($tokens[$commentEnd]['content']) !== '*/') { + $error = 'You must use "*/" to end a function comment; found "%s"'; + $phpcsFile->addError($error, $commentEnd, 'WrongEnd', array(trim($tokens[$commentEnd]['content']))); + return; + } + + // If there is any code between the function keyword and the doc block + // then the doc block is not for us. + $ignore = PHP_CodeSniffer_Tokens::$scopeModifiers; + $ignore[] = T_STATIC; + $ignore[] = T_WHITESPACE; + $ignore[] = T_ABSTRACT; + $ignore[] = T_FINAL; + $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); + if ($prevToken !== $commentEnd) { + $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); + return; + } + + $this->_functionToken = $stackPtr; + + $this->_classToken = null; + foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) { + if ($condition === T_CLASS || $condition === T_INTERFACE) { + $this->_classToken = $condPtr; + break; + } + } + + // Find the first doc comment. + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + $this->_methodName = $phpcsFile->getDeclarationName($stackPtr); + + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($commentString, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Function doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + // The first line of the comment should just be the /** code. + $eolPos = strpos($commentString, $phpcsFile->eolChar); + $firstLine = substr($commentString, 0, $eolPos); + if ($firstLine !== '/**') { + $error = 'The open comment tag must be the only content on the line'; + $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); + } + + $this->processParams($commentStart, $commentEnd); + $this->processSees($commentStart); + $this->processReturn($commentStart, $commentEnd); + $this->processThrows($commentStart); + + // Check for a comment description. + $short = $comment->getShortComment(); + if (trim($short) === '') { + $error = 'Missing short description in function doc comment'; + $phpcsFile->addError($error, $commentStart, 'MissingShort'); + return; + } + + // No extra newline before short description. + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before function comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in function comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); + } + + $newlineCount += $newlineBetween; + + $testLong = trim($long); + if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { + $error = 'Function comment long description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); + } + }//end if + + // Exactly one blank line before tags. + $params = $this->commentParser->getTagOrders(); + if (count($params) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in function comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Short description must be single line and end with a full stop. + $testShort = trim($short); + $lastChar = $testShort[(strlen($testShort) - 1)]; + if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { + $error = 'Function comment short description must be on a single line'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); + } + + if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { + $error = 'Function comment short description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); + } + + if ($lastChar !== '.') { + $error = 'Function comment short description must end with a full stop'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); + } + + // Check for unknown/deprecated tags. + $this->processUnknownTags($commentStart, $commentEnd); + + // The last content should be a newline and the content before + // that should not be blank. If there is more blank space + // then they have additional blank lines at the end of the comment. + $words = $this->commentParser->getWords(); + $lastPos = (count($words) - 1); + if (trim($words[($lastPos - 1)]) !== '' + || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false + || trim($words[($lastPos - 2)]) === '' + ) { + $error = 'Additional blank lines found at end of function comment'; + $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); + } + + }//end process() + + + /** + * Process the see tags. + * + * @param int $commentStart The position in the stack where the comment started. + * + * @return void + */ + protected function processSees($commentStart) + { + $sees = $this->commentParser->getSees(); + if (empty($sees) === false) { + $tagOrder = $this->commentParser->getTagOrders(); + $index = array_keys($this->commentParser->getTagOrders(), 'see'); + foreach ($sees as $i => $see) { + $errorPos = ($commentStart + $see->getLine()); + $since = array_keys($tagOrder, 'since'); + if (count($since) === 1 && $this->_tagIndex !== 0) { + $this->_tagIndex++; + if ($index[$i] !== $this->_tagIndex) { + $error = 'The @see tag is in the wrong order; the tag precedes @return'; + $this->currentFile->addError($error, $errorPos, 'SeeOrder'); + } + } + + $content = $see->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @see tag in function comment'; + $this->currentFile->addError($error, $errorPos, 'EmptySee'); + continue; + } + + $spacing = substr_count($see->getWhitespaceBeforeContent(), ' '); + if ($spacing !== 4) { + $error = '@see tag indented incorrectly; expected 4 spaces but found %s'; + $data = array($spacing); + $this->currentFile->addError($error, $errorPos, 'SeeIndent', $data); + } + }//end foreach + }//end if + + }//end processSees() + + + /** + * Process the return comment of this function comment. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processReturn($commentStart, $commentEnd) + { + // Skip constructor and destructor. + $className = ''; + if ($this->_classToken !== null) { + $className = $this->currentFile->getDeclarationName($this->_classToken); + $className = strtolower(ltrim($className, '_')); + } + + $methodName = strtolower(ltrim($this->_methodName, '_')); + $isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct'); + $return = $this->commentParser->getReturn(); + + if ($isSpecialMethod === false && $methodName !== $className) { + if ($return !== null) { + $tagOrder = $this->commentParser->getTagOrders(); + $index = array_keys($tagOrder, 'return'); + $errorPos = ($commentStart + $return->getLine()); + $content = trim($return->getRawContent()); + + if (count($index) > 1) { + $error = 'Only 1 @return tag is allowed in function comment'; + $this->currentFile->addError($error, $errorPos, 'DuplicateReturn'); + return; + } + + $since = array_keys($tagOrder, 'since'); + if (count($since) === 1 && $this->_tagIndex !== 0) { + $this->_tagIndex++; + if ($index[0] !== $this->_tagIndex) { + $error = 'The @return tag is in the wrong order; the tag follows @see (if used)'; + $this->currentFile->addError($error, $errorPos, 'ReturnOrder'); + } + } + + if (empty($content) === true) { + $error = 'Return type missing for @return tag in function comment'; + $this->currentFile->addError($error, $errorPos, 'MissingReturnType'); + } else { + // Check return type (can be multiple, separated by '|'). + $typeNames = explode('|', $content); + $suggestedNames = array(); + foreach ($typeNames as $i => $typeName) { + $suggestedName = PHP_CodeSniffer::suggestType($typeName); + if (in_array($suggestedName, $suggestedNames) === false) { + $suggestedNames[] = $suggestedName; + } + } + + $suggestedType = implode('|', $suggestedNames); + if ($content !== $suggestedType) { + $error = 'Function return type "%s" is invalid'; + $data = array($content); + $this->currentFile->addError($error, $errorPos, 'InvalidReturn', $data); + } + + $tokens = $this->currentFile->getTokens(); + + // If the return type is void, make sure there is + // no return statement in the function. + if ($content === 'void') { + if (isset($tokens[$this->_functionToken]['scope_closer']) === true) { + $endToken = $tokens[$this->_functionToken]['scope_closer']; + + $tokens = $this->currentFile->getTokens(); + for ($returnToken = $this->_functionToken; $returnToken < $endToken; $returnToken++) { + if ($tokens[$returnToken]['code'] === T_CLOSURE) { + $returnToken = $tokens[$returnToken]['scope_closer']; + continue; + } + + if ($tokens[$returnToken]['code'] === T_RETURN) { + break; + } + } + + if ($returnToken !== $endToken) { + // If the function is not returning anything, just + // exiting, then there is no problem. + $semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true); + if ($tokens[$semicolon]['code'] !== T_SEMICOLON) { + $error = 'Function return type is void, but function contains return statement'; + $this->currentFile->addError($error, $errorPos, 'InvalidReturnVoid'); + } + } + } + } else if ($content !== 'mixed') { + // If return type is not void, there needs to be a + // returns statement somewhere in the function that + // returns something. + if (isset($tokens[$this->_functionToken]['scope_closer']) === true) { + $endToken = $tokens[$this->_functionToken]['scope_closer']; + $returnToken = $this->currentFile->findNext(T_RETURN, $this->_functionToken, $endToken); + if ($returnToken === false) { + $error = 'Function return type is not void, but function has no return statement'; + $this->currentFile->addError($error, $errorPos, 'InvalidNoReturn'); + } else { + $semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true); + if ($tokens[$semicolon]['code'] === T_SEMICOLON) { + $error = 'Function return type is not void, but function is returning void here'; + $this->currentFile->addError($error, $returnToken, 'InvalidReturnNotVoid'); + } + } + } + }//end if + + $spacing = substr_count($return->getWhitespaceBeforeValue(), ' '); + if ($spacing !== 1) { + $error = '@return tag indented incorrectly; expected 1 space but found %s'; + $data = array($spacing); + $this->currentFile->addError($error, $errorPos, 'ReturnIndent', $data); + } + }//end if + } else { + $error = 'Missing @return tag in function comment'; + $this->currentFile->addError($error, $commentEnd, 'MissingReturn'); + }//end if + + } else { + // No return tag for constructor and destructor. + if ($return !== null) { + $errorPos = ($commentStart + $return->getLine()); + $error = '@return tag is not required for constructor and destructor'; + $this->currentFile->addError($error, $errorPos, 'ReturnNotRequired'); + } + }//end if + + }//end processReturn() + + + /** + * Process any throw tags that this function comment has. + * + * @param int $commentStart The position in the stack where the comment started. + * + * @return void + */ + protected function processThrows($commentStart) + { + if (count($this->commentParser->getThrows()) === 0) { + return; + } + + $tagOrder = $this->commentParser->getTagOrders(); + $index = array_keys($this->commentParser->getTagOrders(), 'throws'); + + foreach ($this->commentParser->getThrows() as $i => $throw) { + $exception = $throw->getValue(); + $content = trim($throw->getComment()); + $errorPos = ($commentStart + $throw->getLine()); + if (empty($exception) === true) { + $error = 'Exception type and comment missing for @throws tag in function comment'; + $this->currentFile->addError($error, $errorPos, 'InvalidThrows'); + } else if (empty($content) === true) { + $error = 'Comment missing for @throws tag in function comment'; + $this->currentFile->addError($error, $errorPos, 'EmptyThrows'); + } else { + // Starts with a capital letter and ends with a fullstop. + $firstChar = $content{0}; + if (strtoupper($firstChar) !== $firstChar) { + $error = '@throws tag comment must start with a capital letter'; + $this->currentFile->addError($error, $errorPos, 'ThrowsNotCapital'); + } + + $lastChar = $content[(strlen($content) - 1)]; + if ($lastChar !== '.') { + $error = '@throws tag comment must end with a full stop'; + $this->currentFile->addError($error, $errorPos, 'ThrowsNoFullStop'); + } + } + + $since = array_keys($tagOrder, 'since'); + if (count($since) === 1 && $this->_tagIndex !== 0) { + $this->_tagIndex++; + if ($index[$i] !== $this->_tagIndex) { + $error = 'The @throws tag is in the wrong order; the tag follows @return'; + $this->currentFile->addError($error, $errorPos, 'ThrowsOrder'); + } + } + }//end foreach + + }//end processThrows() + + + /** + * Process the function parameter comments. + * + * @param int $commentStart The position in the stack where + * the comment started. + * @param int $commentEnd The position in the stack where + * the comment ended. + * + * @return void + */ + protected function processParams($commentStart, $commentEnd) + { + $realParams = $this->currentFile->getMethodParameters($this->_functionToken); + $params = $this->commentParser->getParams(); + $foundParams = array(); + + if (empty($params) === false) { + + if (substr_count($params[(count($params) - 1)]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) { + $error = 'Last parameter comment requires a blank newline after it'; + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos, 'SpacingAfterParams'); + } + + // Parameters must appear immediately after the comment. + if ($params[0]->getOrder() !== 2) { + $error = 'Parameters must appear immediately after the comment'; + $errorPos = ($params[0]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParams'); + } + + $previousParam = null; + $spaceBeforeVar = 10000; + $spaceBeforeComment = 10000; + $longestType = 0; + $longestVar = 0; + + foreach ($params as $param) { + + $paramComment = trim($param->getComment()); + $errorPos = ($param->getLine() + $commentStart); + + // Make sure that there is only one space before the var type. + if ($param->getWhitespaceBeforeType() !== ' ') { + $error = 'Expected 1 space before variable type'; + $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParamType'); + } + + $spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' '); + if ($spaceCount < $spaceBeforeVar) { + $spaceBeforeVar = $spaceCount; + $longestType = $errorPos; + } + + $spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' '); + + if ($spaceCount < $spaceBeforeComment && $paramComment !== '') { + $spaceBeforeComment = $spaceCount; + $longestVar = $errorPos; + } + + // Make sure they are in the correct order, and have the correct name. + $pos = $param->getPosition(); + $paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]'; + + if ($previousParam !== null) { + $previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN'; + + // Check to see if the parameters align properly. + if ($param->alignsVariableWith($previousParam) === false) { + $error = 'The variable names for parameters %s (%s) and %s (%s) do not align'; + $data = array( + $previousName, + ($pos - 1), + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'ParameterNamesNotAligned', $data); + } + + if ($param->alignsCommentWith($previousParam) === false) { + $error = 'The comments for parameters %s (%s) and %s (%s) do not align'; + $data = array( + $previousName, + ($pos - 1), + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'ParameterCommentsNotAligned', $data); + } + } + + // Variable must be one of the supported standard type. + $typeNames = explode('|', $param->getType()); + foreach ($typeNames as $typeName) { + $suggestedName = PHP_CodeSniffer::suggestType($typeName); + if ($typeName !== $suggestedName) { + $error = 'Expected "%s"; found "%s" for %s at position %s'; + $data = array( + $suggestedName, + $typeName, + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'IncorrectParamVarName', $data); + } else if (count($typeNames) === 1) { + // Check type hint for array and custom type. + $suggestedTypeHint = ''; + if (strpos($suggestedName, 'array') !== false) { + $suggestedTypeHint = 'array'; + } else if (strpos($suggestedName, 'callable') !== false) { + $suggestedTypeHint = 'callable'; + } else if (in_array($typeName, PHP_CodeSniffer::$allowedTypes) === false) { + $suggestedTypeHint = $suggestedName; + } + + if ($suggestedTypeHint !== '' && isset($realParams[($pos - 1)]) === true) { + $typeHint = $realParams[($pos - 1)]['type_hint']; + if ($typeHint === '') { + $error = 'Type hint "%s" missing for %s at position %s'; + $data = array( + $suggestedTypeHint, + $paramName, + $pos, + ); + $this->currentFile->addError($error, ($commentEnd + 2), 'TypeHintMissing', $data); + } else if ($typeHint !== $suggestedTypeHint) { + $error = 'Expected type hint "%s"; found "%s" for %s at position %s'; + $data = array( + $suggestedTypeHint, + $typeHint, + $paramName, + $pos, + ); + $this->currentFile->addError($error, ($commentEnd + 2), 'IncorrectTypeHint', $data); + } + } else if ($suggestedTypeHint === '' && isset($realParams[($pos - 1)]) === true) { + $typeHint = $realParams[($pos - 1)]['type_hint']; + if ($typeHint !== '') { + $error = 'Unknown type hint "%s" found for %s at position %s'; + $data = array( + $typeHint, + $paramName, + $pos, + ); + $this->currentFile->addError($error, ($commentEnd + 2), 'InvalidTypeHint', $data); + } + } + }//end if + }//end foreach + + // Make sure the names of the parameter comment matches the + // actual parameter. + if (isset($realParams[($pos - 1)]) === true) { + $realName = $realParams[($pos - 1)]['name']; + $foundParams[] = $realName; + + // Append ampersand to name if passing by reference. + if ($realParams[($pos - 1)]['pass_by_reference'] === true) { + $realName = '&'.$realName; + } + + if ($realName !== $paramName) { + $code = 'ParamNameNoMatch'; + $data = array( + $paramName, + $realName, + $pos, + ); + + $error = 'Doc comment for var %s does not match '; + if (strtolower($paramName) === strtolower($realName)) { + $error .= 'case of '; + $code = 'ParamNameNoCaseMatch'; + } + + $error .= 'actual variable name %s at position %s'; + + $this->currentFile->addError($error, $errorPos, $code, $data); + } + } else if (substr($paramName, -4) !== ',...') { + // We must have an extra parameter comment. + $error = 'Superfluous doc comment at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'ExtraParamComment'); + } + + if ($param->getVarName() === '') { + $error = 'Missing parameter name at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'MissingParamName'); + } + + if ($param->getType() === '') { + $error = 'Missing type at position '.$pos; + $this->currentFile->addError($error, $errorPos, 'MissingParamType'); + } + + if ($paramComment === '') { + $error = 'Missing comment for param "%s" at position %s'; + $data = array( + $paramName, + $pos, + ); + $this->currentFile->addError($error, $errorPos, 'MissingParamComment', $data); + } else { + // Param comments must start with a capital letter and + // end with the full stop. + $firstChar = $paramComment{0}; + if (preg_match('|\p{Lu}|u', $firstChar) === 0) { + $error = 'Param comment must start with a capital letter'; + $this->currentFile->addError($error, $errorPos, 'ParamCommentNotCapital'); + } + + $lastChar = $paramComment[(strlen($paramComment) - 1)]; + if ($lastChar !== '.') { + $error = 'Param comment must end with a full stop'; + $this->currentFile->addError($error, $errorPos, 'ParamCommentFullStop'); + } + } + + $previousParam = $param; + + }//end foreach + + if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest type'; + $this->currentFile->addError($error, $longestType, 'SpacingAfterLongType'); + } + + if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest variable name'; + $this->currentFile->addError($error, $longestVar, 'SpacingAfterLongName'); + } + + }//end if + + $realNames = array(); + foreach ($realParams as $realParam) { + $realNames[] = $realParam['name']; + } + + // Report missing comments. + $diff = array_diff($realNames, $foundParams); + foreach ($diff as $neededParam) { + if (count($params) !== 0) { + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); + } else { + $errorPos = $commentStart; + } + + $error = 'Doc comment for "%s" missing'; + $data = array($neededParam); + $this->currentFile->addError($error, $errorPos, 'MissingParamTag', $data); + } + + }//end processParams() + + + /** + * Process a list of unknown tags. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processUnknownTags($commentStart, $commentEnd) + { + + }//end processUnknownTags + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php new file mode 100644 index 000000000..eed031a86 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php @@ -0,0 +1,215 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Verifies that a @throws tag exists for a function that throws exceptions. + * Verifies the number of @throws tags and the number of throw tokens matches. + * Verifies the exception type. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs a Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff. + */ + public function __construct() + { + parent::__construct(array(T_FUNCTION), array(T_THROW)); + + }//end __construct() + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * @param int $currScope The current scope opener token. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + // Is this the first throw token within the current function scope? + // If so, we have to validate other throw tokens within the same scope. + $previousThrow = $phpcsFile->findPrevious(T_THROW, ($stackPtr - 1), $currScope); + if ($previousThrow !== false) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + $find = array( + T_COMMENT, + T_DOC_COMMENT, + T_CLASS, + T_FUNCTION, + T_OPEN_TAG, + ); + + $commentEnd = $phpcsFile->findPrevious($find, ($currScope - 1)); + + if ($commentEnd === false) { + return; + } + + if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { + // Function doesn't have a comment. Let someone else warn about that. + return; + } + + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); + return; + } + + // Find the position where the current function scope ends. + $currScopeEnd = 0; + if (isset($tokens[$currScope]['scope_closer']) === true) { + $currScopeEnd = $tokens[$currScope]['scope_closer']; + } + + // Find all the exception type token within the current scope. + $throwTokens = array(); + $currPos = $stackPtr; + if ($currScopeEnd !== 0) { + while ($currPos < $currScopeEnd && $currPos !== false) { + + /* + If we can't find a NEW, we are probably throwing + a variable, so we ignore it, but they still need to + provide at least one @throws tag, even through we + don't know the exception class. + */ + + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($currPos + 1), null, true); + if ($tokens[$nextToken]['code'] === T_NEW) { + $currException = $phpcsFile->findNext( + array( + T_NS_SEPARATOR, + T_STRING, + ), + $currPos, + $currScopeEnd, + false, + null, + true + ); + + if ($currException !== false) { + $endException = $phpcsFile->findNext( + array( + T_NS_SEPARATOR, + T_STRING, + ), + ($currException + 1), + $currScopeEnd, + true, + null, + true + ); + + if ($endException === false) { + $throwTokens[] = $tokens[$currException]['content']; + } else { + $throwTokens[] = $phpcsFile->getTokensAsString($currException, ($endException - $currException)); + } + }//end if + }//end if + + $currPos = $phpcsFile->findNext(T_THROW, ($currPos + 1), $currScopeEnd); + }//end while + }//end if + + // Only need one @throws tag for each type of exception thrown. + $throwTokens = array_unique($throwTokens); + sort($throwTokens); + + $throws = $this->commentParser->getThrows(); + if (empty($throws) === true) { + $error = 'Missing @throws tag in function comment'; + $phpcsFile->addError($error, $commentEnd, 'Missing'); + } else if (empty($throwTokens) === true) { + // If token count is zero, it means that only variables are being + // thrown, so we need at least one @throws tag (checked above). + // Nothing more to do. + return; + } else { + $throwTags = array(); + $lineNumber = array(); + foreach ($throws as $throw) { + $throwTags[] = $throw->getValue(); + $lineNumber[$throw->getValue()] = $throw->getLine(); + } + + $throwTags = array_unique($throwTags); + sort($throwTags); + + // Make sure @throws tag count matches throw token count. + $tokenCount = count($throwTokens); + $tagCount = count($throwTags); + if ($tokenCount !== $tagCount) { + $error = 'Expected %s @throws tag(s) in function comment; %s found'; + $data = array( + $tokenCount, + $tagCount, + ); + $phpcsFile->addError($error, $commentEnd, 'WrongNumber', $data); + return; + } else { + // Exception type in @throws tag must be thrown in the function. + foreach ($throwTags as $i => $throwTag) { + $errorPos = ($commentStart + $lineNumber[$throwTag]); + if (empty($throwTag) === false && $throwTag !== $throwTokens[$i]) { + $error = 'Expected "%s" but found "%s" for @throws tag exception'; + $data = array( + $throwTokens[$i], + $throwTag, + ); + $phpcsFile->addError($error, $errorPos, 'WrongType', $data); + } + } + } + }//end if + + }//end processTokenWithinScope() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php new file mode 100644 index 000000000..13669394b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php @@ -0,0 +1,272 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_InlineCommentSniff. + * + * Checks that there is adequate spacing between comments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_COMMENT, + T_DOC_COMMENT, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If this is a function/class/interface doc block comment, skip it. + // We are only interested in inline doc block comments, which are + // not allowed. + if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) { + $nextToken = $phpcsFile->findNext( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($stackPtr + 1), + null, + true + ); + + $ignore = array( + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_FUNCTION, + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_FINAL, + T_STATIC, + T_ABSTRACT, + T_CONST, + T_OBJECT, + T_PROPERTY, + ); + + if (in_array($tokens[$nextToken]['code'], $ignore) === true) { + return; + } else { + if ($phpcsFile->tokenizerType === 'JS') { + // We allow block comments if a function is being assigned + // to a variable. + $ignore = PHP_CodeSniffer_Tokens::$emptyTokens; + $ignore[] = T_EQUAL; + $ignore[] = T_STRING; + $ignore[] = T_OBJECT_OPERATOR; + $nextToken = $phpcsFile->findNext($ignore, ($nextToken + 1), null, true); + if ($tokens[$nextToken]['code'] === T_FUNCTION) { + return; + } + } + + $prevToken = $phpcsFile->findPrevious( + PHP_CodeSniffer_Tokens::$emptyTokens, + ($stackPtr - 1), + null, + true + ); + + if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { + return; + } + + // Only error once per comment. + if (substr($tokens[$stackPtr]['content'], 0, 3) === '/**') { + $error = 'Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead'; + $phpcsFile->addError($error, $stackPtr, 'DocBlock'); + } + }//end if + }//end if + + if ($tokens[$stackPtr]['content']{0} === '#') { + $error = 'Perl-style comments are not allowed; use "// Comment" instead'; + $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); + } + + // We don't want end of block comments. If the last comment is a closing + // curly brace. + $previousContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$previousContent]['line'] === $tokens[$stackPtr]['line']) { + if ($tokens[$previousContent]['code'] === T_CLOSE_CURLY_BRACKET) { + return; + } + + // Special case for JS files. + if ($tokens[$previousContent]['code'] === T_COMMA + || $tokens[$previousContent]['code'] === T_SEMICOLON + ) { + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($previousContent - 1), null, true); + if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { + return; + } + } + } + + $comment = rtrim($tokens[$stackPtr]['content']); + + // Only want inline comments. + if (substr($comment, 0, 2) !== '//') { + return; + } + + $spaceCount = 0; + for ($i = 2; $i < strlen($comment); $i++) { + if ($comment[$i] !== ' ') { + break; + } + + $spaceCount++; + } + + if ($spaceCount === 0) { + $error = 'No space before comment text; expected "// %s" but found "%s"'; + $data = array( + substr($comment, 2), + $comment, + ); + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore', $data); + } + + if ($spaceCount > 1) { + $error = '%s spaces found before inline comment line; use block comment if you need indentation'; + $data = array( + $spaceCount, + substr($comment, (2 + $spaceCount)), + $comment, + ); + $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); + } + + + // The below section determines if a comment block is correctly capitalised, + // and ends in a full-stop. It will find the last comment in a block, and + // work its way up. + $nextComment = $phpcsFile->findNext(array(T_COMMENT), ($stackPtr + 1), null, false); + + if (($nextComment !== false) && (($tokens[$nextComment]['line']) === ($tokens[$stackPtr]['line'] + 1))) { + return; + } + + $topComment = $stackPtr; + $lastComment = $stackPtr; + while (($topComment = $phpcsFile->findPrevious(array(T_COMMENT), ($lastComment - 1), null, false)) !== false) { + if ($tokens[$topComment]['line'] !== ($tokens[$lastComment]['line'] - 1)) { + break; + } + + $lastComment = $topComment; + } + + $topComment = $lastComment; + $commentText = ''; + + for ($i = $topComment; $i <= $stackPtr; $i++) { + if ($tokens[$i]['code'] === T_COMMENT) { + $commentText .= trim(substr($tokens[$i]['content'], 2)); + } + } + + if ($commentText === '') { + $error = 'Blank comments are not allowed'; + $phpcsFile->addError($error, $stackPtr, 'Empty'); + return; + } + + if (preg_match('|\p{Lu}|u', $commentText[0]) === 0) { + $error = 'Inline comments must start with a capital letter'; + $phpcsFile->addError($error, $topComment, 'NotCapital'); + } + + $commentCloser = $commentText[(strlen($commentText) - 1)]; + $acceptedClosers = array( + 'full-stops' => '.', + 'exclamation marks' => '!', + 'or question marks' => '?', + ); + + if (in_array($commentCloser, $acceptedClosers) === false) { + $error = 'Inline comments must end in %s'; + $ender = ''; + foreach ($acceptedClosers as $closerName => $symbol) { + $ender .= ' '.$closerName.','; + } + + $ender = rtrim($ender, ','); + $data = array($ender); + $phpcsFile->addError($error, $stackPtr, 'InvalidEndChar', $data); + } + + // Finally, the line below the last comment cannot be empty. + $start = false; + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['line'] === ($tokens[$stackPtr]['line'] + 1)) { + if ($tokens[$i]['code'] !== T_WHITESPACE) { + return; + } + } else if ($tokens[$i]['line'] > ($tokens[$stackPtr]['line'] + 1)) { + break; + } + } + + $error = 'There must be no blank line following an inline comment'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfter'); + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php new file mode 100644 index 000000000..b2a8f601d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php @@ -0,0 +1,191 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_LongConditionClosingCommentSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * The openers that we are interested in. + * + * @var array(int) + */ + private static $_openers = array( + T_SWITCH, + T_IF, + T_FOR, + T_FOREACH, + T_WHILE, + T_TRY, + T_CASE, + ); + + /** + * The length that a code block must be before + * requiring a closing comment. + * + * @var int + */ + protected $lineLimit = 20; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLOSE_CURLY_BRACKET); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_condition']) === false) { + // No scope condition. It is a function closer. + return; + } + + $startCondition = $tokens[$tokens[$stackPtr]['scope_condition']]; + $startBrace = $tokens[$tokens[$stackPtr]['scope_opener']]; + $endBrace = $tokens[$stackPtr]; + + // We are only interested in some code blocks. + if (in_array($startCondition['code'], self::$_openers) === false) { + return; + } + + if ($startCondition['code'] === T_IF) { + // If this is actually and ELSE IF, skip it as the brace + // will be checked by the original IF. + $else = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$stackPtr]['scope_condition'] - 1), null, true); + if ($tokens[$else]['code'] === T_ELSE) { + return; + } + + // IF statements that have an ELSE block need to use + // "end if" rather than "end else" or "end elseif". + do { + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$nextToken]['code'] === T_ELSE || $tokens[$nextToken]['code'] === T_ELSEIF) { + // Check for ELSE IF (2 tokens) as opposed to ELSEIF (1 token). + if ($tokens[$nextToken]['code'] === T_ELSE + && isset($tokens[$nextToken]['scope_closer']) === false + ) { + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true); + if ($tokens[$nextToken]['code'] !== T_IF + || isset($tokens[$nextToken]['scope_closer']) === false + ) { + // Not an ELSE IF or is an inline ELSE IF. + break; + } + } + + // The end brace becomes the ELSE's end brace. + $stackPtr = $tokens[$nextToken]['scope_closer']; + $endBrace = $tokens[$stackPtr]; + } else { + break; + } + } while (isset($tokens[$nextToken]['scope_closer']) === true); + }//end if + + if ($startCondition['code'] === T_TRY) { + // TRY statements need to check until the end of all CATCH statements. + do { + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$nextToken]['code'] === T_CATCH) { + // The end brace becomes the CATCH's end brace. + $stackPtr = $tokens[$nextToken]['scope_closer']; + $endBrace = $tokens[$stackPtr]; + } else { + break; + } + } while (isset($tokens[$nextToken]['scope_closer']) === true); + } + + $lineDifference = ($endBrace['line'] - $startBrace['line']); + + $expected = '//end '.$startCondition['content']; + $comment = $phpcsFile->findNext(array(T_COMMENT), $stackPtr, null, false); + + if (($comment === false) || ($tokens[$comment]['line'] !== $endBrace['line'])) { + if ($lineDifference >= $this->lineLimit) { + $error = 'End comment for long condition not found; expected "%s"'; + $data = array($expected); + $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + } + + return; + } + + if (($comment - $stackPtr) !== 1) { + $error = 'Space found before closing comment; expected "%s"'; + $data = array($expected); + $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); + } + + if (trim($tokens[$comment]['content']) !== $expected) { + $found = trim($tokens[$comment]['content']); + $error = 'Incorrect closing comment; expected "%s" but found "%s"'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'Invalid', $data); + return; + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php new file mode 100644 index 000000000..c71ded07a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php @@ -0,0 +1,103 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Commenting_PostStatementCommentSniff. + * + * Checks to ensure that there are no comments after statements. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Commenting_PostStatementCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_COMMENT); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { + return; + } + + $commentLine = $tokens[$stackPtr]['line']; + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + + if ($tokens[$lastContent]['line'] !== $commentLine) { + return; + } + + if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { + return; + } + + // Special case for JS files. + if ($tokens[$lastContent]['code'] === T_COMMA + || $tokens[$lastContent]['code'] === T_SEMICOLON + ) { + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($lastContent - 1), null, true); + if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { + return; + } + } + + $error = 'Comments may not appear after statements.'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php new file mode 100644 index 000000000..fd0501edb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php @@ -0,0 +1,345 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +if (class_exists('PHP_CodeSniffer_CommentParser_MemberCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_MemberCommentParser not found'); +} + +/** + * Parses and verifies the variable doc comment. + * + * Verifies that : + *
    + *
  • A variable doc comment exists.
  • + *
  • Short description ends with a full stop.
  • + *
  • There is a blank line after the short description.
  • + *
  • There is a blank line between the description and the tags.
  • + *
  • Check the order, indentation and content of each tag.
  • + *
+ * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +class Squiz_Sniffs_Commenting_VariableCommentSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + /** + * The header comment parser for the current file. + * + * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser + */ + protected $commentParser = null; + + + /** + * Called to process class member vars. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + $tokens = $phpcsFile->getTokens(); + $commentToken = array( + T_COMMENT, + T_DOC_COMMENT, + ); + + // Extract the var comment docblock. + $commentEnd = $phpcsFile->findPrevious($commentToken, ($stackPtr - 3)); + if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { + $phpcsFile->addError('You must use "/**" style comments for a variable comment', $stackPtr, 'WrongStyle'); + return; + } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing'); + return; + } else { + // Make sure the comment we have found belongs to us. + $commentFor = $phpcsFile->findNext(array(T_VARIABLE, T_CLASS, T_INTERFACE), ($commentEnd + 1)); + if ($commentFor !== $stackPtr) { + $phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing'); + return; + } + } + + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + // Parse the header comment docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_MemberCommentParser($commentString, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line, 'ErrorParsing'); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Variable doc comment is empty'; + $phpcsFile->addError($error, $commentStart, 'Empty'); + return; + } + + // The first line of the comment should just be the /** code. + $eolPos = strpos($commentString, $phpcsFile->eolChar); + $firstLine = substr($commentString, 0, $eolPos); + if ($firstLine !== '/**') { + $error = 'The open comment tag must be the only content on the line'; + $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); + } + + // Check for a comment description. + $short = $comment->getShortComment(); + $long = ''; + if (trim($short) === '') { + $error = 'Missing short description in variable doc comment'; + $phpcsFile->addError($error, $commentStart, 'MissingShort'); + $newlineCount = 1; + } else { + // No extra newline before short description. + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $error = 'Extra newline(s) found before variable comment short description'; + $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in variable comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); + } + + $newlineCount += $newlineBetween; + + $testLong = trim($long); + if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { + $error = 'Variable comment long description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); + } + }//end if + + // Short description must be single line and end with a full stop. + $testShort = trim($short); + $lastChar = $testShort[(strlen($testShort) - 1)]; + if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { + $error = 'Variable comment short description must be on a single line'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); + } + + if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { + $error = 'Variable comment short description must start with a capital letter'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); + } + + if ($lastChar !== '.') { + $error = 'Variable comment short description must end with a full stop'; + $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); + } + }//end if + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in variable comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Check for unknown/deprecated tags. + $unknownTags = $this->commentParser->getUnknown(); + foreach ($unknownTags as $errorTag) { + // Unknown tags are not parsed, do not process further. + $error = '@%s tag is not allowed in variable comment'; + $data = array($errorTag['tag']); + $phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data); + } + + // Check each tag. + $this->processVar($commentStart, $commentEnd); + $this->processSees($commentStart); + + // The last content should be a newline and the content before + // that should not be blank. If there is more blank space + // then they have additional blank lines at the end of the comment. + $words = $this->commentParser->getWords(); + $lastPos = (count($words) - 1); + if (trim($words[($lastPos - 1)]) !== '' + || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false + || trim($words[($lastPos - 2)]) === '' + ) { + $error = 'Additional blank lines found at end of variable comment'; + $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); + } + + }//end processMemberVar() + + + /** + * Process the var tag. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processVar($commentStart, $commentEnd) + { + $var = $this->commentParser->getVar(); + + if ($var !== null) { + $errorPos = ($commentStart + $var->getLine()); + $index = array_keys($this->commentParser->getTagOrders(), 'var'); + + if (count($index) > 1) { + $error = 'Only 1 @var tag is allowed in variable comment'; + $this->currentFile->addError($error, $errorPos, 'DuplicateVar'); + return; + } + + if ($index[0] !== 1) { + $error = 'The @var tag must be the first tag in a variable comment'; + $this->currentFile->addError($error, $errorPos, 'VarOrder'); + } + + $content = $var->getContent(); + if (empty($content) === true) { + $error = 'Var type missing for @var tag in variable comment'; + $this->currentFile->addError($error, $errorPos, 'MissingVarType'); + return; + } else { + $suggestedType = PHP_CodeSniffer::suggestType($content); + if ($content !== $suggestedType) { + $error = 'Expected "%s"; found "%s" for @var tag in variable comment'; + $data = array( + $suggestedType, + $content, + ); + $this->currentFile->addError($error, $errorPos, 'IncorrectVarType', $data); + } + } + + $spacing = substr_count($var->getWhitespaceBeforeContent(), ' '); + if ($spacing !== 1) { + $error = '@var tag indented incorrectly; expected 1 space but found %s'; + $data = array($spacing); + $this->currentFile->addError($error, $errorPos, 'VarIndent', $data); + } + } else { + $error = 'Missing @var tag in variable comment'; + $this->currentFile->addError($error, $commentEnd, 'MissingVar'); + }//end if + + }//end processVar() + + + /** + * Process the see tags. + * + * @param int $commentStart The position in the stack where the comment started. + * + * @return void + */ + protected function processSees($commentStart) + { + $sees = $this->commentParser->getSees(); + if (empty($sees) === false) { + foreach ($sees as $see) { + $errorPos = ($commentStart + $see->getLine()); + $content = $see->getContent(); + if (empty($content) === true) { + $error = 'Content missing for @see tag in variable comment'; + $this->currentFile->addError($error, $errorPos, 'EmptySees'); + continue; + } + + $spacing = substr_count($see->getWhitespaceBeforeContent(), ' '); + if ($spacing !== 1) { + $error = '@see tag indented incorrectly; expected 1 spaces but found %s'; + $data = array($spacing); + $this->currentFile->addError($error, $errorPos, 'SeesIndent', $data); + } + } + } + + }//end processSees() + + + /** + * Called to process a normal variable. + * + * Not required for this sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found. + * @param int $stackPtr The position where the double quoted + * string was found. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + + }//end processVariable() + + + /** + * Called to process variables found in double quoted strings. + * + * Not required for this sniff. + * + * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found. + * @param int $stackPtr The position where the double quoted + * string was found. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + + }//end processVariableInString() + + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php new file mode 100644 index 000000000..68b7b4a88 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php @@ -0,0 +1,70 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); +} + +/** + * Verifies that control statements conform to their coding standards. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns the patterns that this test wishes to verify. + * + * @return array(string) + */ + protected function getPatterns() + { + return array( + 'try {EOL...} catch (...) {EOL', + 'do {EOL...} while (...);EOL', + 'while (...) {EOL', + 'for (...) {EOL', + 'if (...) {EOL', + 'foreach (...) {EOL', + '} else if (...) {EOL', + '} elseif (...) {EOL', + '} else {EOL', + ); + + }//end getPatterns() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php new file mode 100644 index 000000000..ab61b5c34 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php @@ -0,0 +1,67 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff. + * + * Verifies that there are not elseif statements. The else and the if should + * be separated by a space. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_ELSEIF); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $error = 'Usage of ELSEIF not allowed; use ELSE IF instead'; + $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php new file mode 100644 index 000000000..02cb16447 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php @@ -0,0 +1,144 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff. + * + * Verifies that there is a space between each condition of foreach loops. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FOREACH); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); + $closingBracket = $tokens[$openingBracket]['parenthesis_closer']; + + if ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { + $error = 'Space found after opening bracket of FOREACH loop'; + $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpen'); + } + + if ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before closing bracket of FOREACH loop'; + $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeClose'); + } + + $asToken = $phpcsFile->findNext(T_AS, $openingBracket); + $content = $tokens[$asToken]['content']; + if ($content !== strtolower($content)) { + $expected = strtolower($content); + $error = 'AS keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + $expected, + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'AsNotLower', $data); + } + + $doubleArrow = $phpcsFile->findNext(T_DOUBLE_ARROW, $openingBracket, $closingBracket); + + if ($doubleArrow !== false) { + if ($tokens[($doubleArrow - 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before "=>"; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeArrow'); + } else { + if (strlen($tokens[($doubleArrow - 1)]['content']) !== 1) { + $spaces = strlen($tokens[($doubleArrow - 1)]['content']); + $error = 'Expected 1 space before "=>"; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeArrow', $data); + } + + } + + if ($tokens[($doubleArrow + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after "=>"; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterArrow'); + } else { + if (strlen($tokens[($doubleArrow + 1)]['content']) !== 1) { + $spaces = strlen($tokens[($doubleArrow + 1)]['content']); + $error = 'Expected 1 space after "=>"; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterArrow', $data); + } + + } + + }//end if + + if ($tokens[($asToken - 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before "as"; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeAs'); + } else { + if (strlen($tokens[($asToken - 1)]['content']) !== 1) { + $spaces = strlen($tokens[($asToken - 1)]['content']); + $error = 'Expected 1 space before "as"; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeAs', $data); + } + } + + if ($tokens[($asToken + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after "as"; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterAs'); + } else { + if (strlen($tokens[($asToken + 1)]['content']) !== 1) { + $spaces = strlen($tokens[($asToken + 1)]['content']); + $error = 'Expected 1 space after "as"; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterAs', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php new file mode 100644 index 000000000..1bfff2b50 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php @@ -0,0 +1,143 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff. + * + * Verifies that there is a space between each condition of for loops. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); + if ($openingBracket === false) { + $error = 'Possible parse error: no opening parenthesis for FOR keyword'; + $phpcsFile->addWarning($error, $stackPtr, 'NoOpenBracket'); + return; + } + + $closingBracket = $tokens[$openingBracket]['parenthesis_closer']; + + if ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { + $error = 'Space found after opening bracket of FOR loop'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen'); + } + + if ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before closing bracket of FOR loop'; + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose'); + } + + $firstSemicolon = $phpcsFile->findNext(T_SEMICOLON, $openingBracket, $closingBracket); + + // Check whitespace around each of the tokens. + if ($firstSemicolon !== false) { + if ($tokens[($firstSemicolon - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before first semicolon of FOR loop'; + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeFirst'); + } + + if ($tokens[($firstSemicolon + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after first semicolon of FOR loop; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterFirst'); + } else { + if (strlen($tokens[($firstSemicolon + 1)]['content']) !== 1) { + $spaces = strlen($tokens[($firstSemicolon + 1)]['content']); + $error = 'Expected 1 space after first semicolon of FOR loop; %s found'; + $data = array($spaces); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterFirst', $data); + } + } + + $secondSemicolon = $phpcsFile->findNext(T_SEMICOLON, ($firstSemicolon + 1)); + + if ($secondSemicolon !== false) { + if ($tokens[($secondSemicolon - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before second semicolon of FOR loop'; + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeSecond'); + } + + if (($secondSemicolon + 1) !== $closingBracket + && $tokens[($secondSemicolon + 1)]['code'] !== T_WHITESPACE + ) { + $error = 'Expected 1 space after second semicolon of FOR loop; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterSecond'); + } else { + if (strlen($tokens[($secondSemicolon + 1)]['content']) !== 1) { + $spaces = strlen($tokens[($secondSemicolon + 1)]['content']); + $data = array($spaces); + if (($secondSemicolon + 2) === $closingBracket) { + $error = 'Expected no space after second semicolon of FOR loop; %s found'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterSecondNoThird', $data); + } else { + $error = 'Expected 1 space after second semicolon of FOR loop; %s found'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterSecond', $data); + } + } + } + }//end if + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php new file mode 100644 index 000000000..0bde7ac2d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php @@ -0,0 +1,136 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff. + * + * Tests the spacing of shorthand IF statements. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_INLINE_THEN); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Find the opening bracket of the inline IF. + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if (isset($tokens[$i]['parenthesis_opener']) === true + && $tokens[$i]['parenthesis_opener'] < $i + ) { + $i = $tokens[$i]['parenthesis_opener']; + continue; + } + + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { + break; + } + } + + if ($i <= 0) { + // Could not find the beginning of the statement. Probably not + // wrapped with brackets, so assume it ends with a semicolon. + $statementEnd = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + } else { + $statementEnd = $tokens[$i]['parenthesis_closer']; + } + + // Make sure it's all on the same line. + if ($tokens[$statementEnd]['line'] !== $tokens[$stackPtr]['line']) { + $error = 'Inline shorthand IF statement must be declared on a single line'; + $phpcsFile->addError($error, $stackPtr, 'NotSingleLine'); + return; + } + + // Make sure there are spaces around the question mark. + $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$contentBefore]['code'] !== T_CLOSE_PARENTHESIS) { + $error = 'Inline shorthand IF statement requires brackets around comparison'; + $phpcsFile->addError($error, $stackPtr, 'NoBrackets'); + return; + } + + $spaceBefore = ($tokens[$stackPtr]['column'] - ($tokens[$contentBefore]['column'] + strlen($tokens[$contentBefore]['content']))); + if ($spaceBefore !== 1) { + $error = 'Inline shorthand IF statement requires 1 space before THEN; %s found'; + $data = array($spaceBefore); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeThen', $data); + } + + $spaceAfter = (($tokens[$contentAfter]['column']) - ($tokens[$stackPtr]['column'] + 1)); + if ($spaceAfter !== 1) { + $error = 'Inline shorthand IF statement requires 1 space after THEN; %s found'; + $data = array($spaceAfter); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterThen', $data); + } + + // Make sure the ELSE has the correct spacing. + $inlineElse = $phpcsFile->findNext(T_INLINE_ELSE, ($stackPtr + 1), $statementEnd, false); + $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($inlineElse - 1), null, true); + $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($inlineElse + 1), null, true); + + $spaceBefore = ($tokens[$inlineElse]['column'] - ($tokens[$contentBefore]['column'] + strlen($tokens[$contentBefore]['content']))); + if ($spaceBefore !== 1) { + $error = 'Inline shorthand IF statement requires 1 space before ELSE; %s found'; + $data = array($spaceBefore); + $phpcsFile->addError($error, $inlineElse, 'SpacingBeforeElse', $data); + } + + $spaceAfter = (($tokens[$contentAfter]['column']) - ($tokens[$inlineElse]['column'] + 1)); + if ($spaceAfter !== 1) { + $error = 'Inline shorthand IF statement requires 1 space after ELSE; %s found'; + $data = array($spaceAfter); + $phpcsFile->addError($error, $inlineElse, 'SpacingAfterElse', $data); + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php new file mode 100644 index 000000000..0e8eec8e4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php @@ -0,0 +1,86 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff. + * + * Ensures all control structure keywords are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_ELSE, + T_ELSEIF, + T_FOREACH, + T_FOR, + T_DO, + T_SWITCH, + T_WHILE, + T_TRY, + T_CATCH, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + if ($content !== strtolower($content)) { + $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtoupper($content), + strtolower($content), + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php new file mode 100644 index 000000000..b27aa530e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php @@ -0,0 +1,270 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff. + * + * Ensures all the breaks and cases are aligned correctly according to their + * parent switch's alignment and enforces other switch formatting. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * The number of spaces code should be indented. + * + * @var int + */ + public $indent = 4; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_SWITCH); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We can't process SWITCH statements unless we know where they start and end. + if (isset($tokens[$stackPtr]['scope_opener']) === false + || isset($tokens[$stackPtr]['scope_closer']) === false + ) { + return; + } + + $switch = $tokens[$stackPtr]; + $nextCase = $stackPtr; + $caseAlignment = ($switch['column'] + $this->indent); + $caseCount = 0; + $foundDefault = false; + + while (($nextCase = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), ($nextCase + 1), $switch['scope_closer'])) !== false) { + // Skip nested SWITCH statements; they are handled on their own. + if ($tokens[$nextCase]['code'] === T_SWITCH) { + $nextCase = $tokens[$nextCase]['scope_closer']; + continue; + } + + if ($tokens[$nextCase]['code'] === T_DEFAULT) { + $type = 'Default'; + $foundDefault = true; + } else { + $type = 'Case'; + $caseCount++; + } + + if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) { + $expected = strtolower($tokens[$nextCase]['content']); + $error = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + $expected, + $tokens[$nextCase]['content'], + ); + $phpcsFile->addError($error, $nextCase, $type.'NotLower', $data); + } + + if ($tokens[$nextCase]['column'] !== $caseAlignment) { + $error = strtoupper($type).' keyword must be indented '.$this->indent.' spaces from SWITCH keyword'; + $phpcsFile->addError($error, $nextCase, $type.'Indent'); + } + + if ($type === 'Case' + && ($tokens[($nextCase + 1)]['type'] !== 'T_WHITESPACE' + || $tokens[($nextCase + 1)]['content'] !== ' ') + ) { + $error = 'CASE keyword must be followed by a single space'; + $phpcsFile->addError($error, $nextCase, 'SpacingAfterCase'); + } + + $opener = $tokens[$nextCase]['scope_opener']; + if ($tokens[($opener - 1)]['type'] === 'T_WHITESPACE') { + $error = 'There must be no space before the colon in a '.strtoupper($type).' statement'; + $phpcsFile->addError($error, $nextCase, 'SpaceBeforeColon'.$type); + } + + $nextBreak = $tokens[$nextCase]['scope_closer']; + if ($tokens[$nextBreak]['code'] === T_BREAK + || $tokens[$nextBreak]['code'] === T_RETURN + || $tokens[$nextBreak]['code'] === T_CONTINUE + || $tokens[$nextBreak]['code'] === T_THROW + ) { + if ($tokens[$nextBreak]['scope_condition'] === $nextCase) { + // Only need to check a couple of things once, even if the + // break is shared between multiple case statements, or even + // the default case. + if ($tokens[$nextBreak]['column'] !== $caseAlignment) { + $error = 'Case breaking statement must be indented '.$this->indent.' spaces from SWITCH keyword'; + $phpcsFile->addError($error, $nextBreak, 'BreakIndent'); + } + + $breakLine = $tokens[$nextBreak]['line']; + $prevLine = 0; + for ($i = ($nextBreak - 1); $i > $stackPtr; $i--) { + if ($tokens[$i]['type'] !== 'T_WHITESPACE') { + $prevLine = $tokens[$i]['line']; + break; + } + } + + if ($prevLine !== ($breakLine - 1)) { + $error = 'Blank lines are not allowed before case breaking statements'; + $phpcsFile->addError($error, $nextBreak, 'SpacingBeforeBreak'); + } + + $breakLine = $tokens[$nextBreak]['line']; + $nextLine = $tokens[$tokens[$stackPtr]['scope_closer']]['line']; + $semicolon = $phpcsFile->findNext(T_SEMICOLON, $nextBreak); + for ($i = ($semicolon + 1); $i < $tokens[$stackPtr]['scope_closer']; $i++) { + if ($tokens[$i]['type'] !== 'T_WHITESPACE') { + $nextLine = $tokens[$i]['line']; + break; + } + } + + if ($type === 'Case') { + // Ensure the BREAK statement is followed by + // a single blank line, or the end switch brace. + if ($nextLine !== ($breakLine + 2) && $i !== $tokens[$stackPtr]['scope_closer']) { + $error = 'Case breaking statements must be followed by a single blank line'; + $phpcsFile->addError($error, $nextBreak, 'SpacingAfterBreak'); + } + } else { + // Ensure the BREAK statement is not followed by a blank line. + if ($nextLine !== ($breakLine + 1)) { + $error = 'Blank lines are not allowed after the DEFAULT case\'s breaking statement'; + $phpcsFile->addError($error, $nextBreak, 'SpacingAfterDefaultBreak'); + } + } + + $caseLine = $tokens[$nextCase]['line']; + $nextLine = $tokens[$nextBreak]['line']; + for ($i = ($opener + 1); $i < $nextBreak; $i++) { + if ($tokens[$i]['type'] !== 'T_WHITESPACE') { + $nextLine = $tokens[$i]['line']; + break; + } + } + + if ($nextLine !== ($caseLine + 1)) { + $error = 'Blank lines are not allowed after '.strtoupper($type).' statements'; + $phpcsFile->addError($error, $nextCase, 'SpacingAfter'.$type); + } + }//end if + + if ($tokens[$nextBreak]['code'] === T_BREAK) { + if ($type === 'Case') { + // Ensure empty CASE statements are not allowed. + // They must have some code content in them. A comment is not enough. + // But count RETURN statements as valid content if they also + // happen to close the CASE statement. + $foundContent = false; + for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) { + if ($tokens[$i]['code'] === T_CASE) { + $i = $tokens[$i]['scope_opener']; + continue; + } + + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $foundContent = true; + break; + } + } + + if ($foundContent === false) { + $error = 'Empty CASE statements are not allowed'; + $phpcsFile->addError($error, $nextCase, 'EmptyCase'); + } + } else { + // Ensure empty DEFAULT statements are not allowed. + // They must (at least) have a comment describing why + // the default case is being ignored. + $foundContent = false; + for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) { + if ($tokens[$i]['type'] !== 'T_WHITESPACE') { + $foundContent = true; + break; + } + } + + if ($foundContent === false) { + $error = 'Comment required for empty DEFAULT case'; + $phpcsFile->addError($error, $nextCase, 'EmptyDefault'); + } + }//end if + }//end if + } else if ($type === 'Default') { + $error = 'DEFAULT case must have a breaking statement'; + $phpcsFile->addError($error, $nextCase, 'DefaultNoBreak'); + }//end if + }//end while + + if ($foundDefault === false) { + $error = 'All SWITCH statements must contain a DEFAULT case'; + $phpcsFile->addError($error, $stackPtr, 'MissingDefault'); + } + + if ($tokens[$switch['scope_closer']]['column'] !== $switch['column']) { + $error = 'Closing brace of SWITCH statement must be aligned with SWITCH keyword'; + $phpcsFile->addError($error, $switch['scope_closer'], 'CloseBraceAlign'); + } + + if ($caseCount === 0) { + $error = 'SWITCH statements must contain at least one CASE statement'; + $phpcsFile->addError($error, $stackPtr, 'MissingCase'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php new file mode 100644 index 000000000..272b77ba5 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php @@ -0,0 +1,107 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Debug_JSLintSniff. + * + * Runs jslint.js on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Debug_JSLintSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + * @throws PHP_CodeSniffer_Exception If jslint.js could not be run + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + + $rhinoPath = PHP_CodeSniffer::getConfigData('rhino_path'); + $jslintPath = PHP_CodeSniffer::getConfigData('jslint_path'); + if ($rhinoPath === null || $jslintPath === null) { + return; + } + + $cmd = "$rhinoPath \"$jslintPath\" \"$fileName\""; + $msg = exec($cmd, $output, $retval); + + if (is_array($output) === true) { + $tokens = $phpcsFile->getTokens(); + + foreach ($output as $finding) { + $matches = array(); + $numMatches = preg_match('/Lint at line ([0-9]+).*:(.*)$/', $finding, $matches); + if ($numMatches === 0) { + continue; + } + + $line = (int) $matches[1]; + $message = 'jslint says: '.trim($matches[2]); + + // Find the token at the start of the line. + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] === $line) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); + } + }//end foreach + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php new file mode 100644 index 000000000..ab63962b7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php @@ -0,0 +1,110 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Debug_JavaScriptLintSniff. + * + * Runs JavaScript Lint on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Debug_JavaScriptLintSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $fileName = $phpcsFile->getFilename(); + + $jslPath = PHP_CodeSniffer::getConfigData('jsl_path'); + if (is_null($jslPath) === true) { + return; + } + + $cmd = '"'.$jslPath.'" -nologo -nofilelisting -nocontext -nosummary -output-format __LINE__:__ERROR__ -process "'.$fileName.'"'; + $msg = exec($cmd, $output, $retval); + + // $exitCode is the last line of $output if no error occurs, on error it + // is numeric. Try to handle various error conditions and provide useful + // error reporting. + if ($retval === 2 || $retval === 4) { + if (is_array($output) === true) { + $msg = join('\n', $output); + } + + throw new PHP_CodeSniffer_Exception("Failed invoking JavaScript Lint, retval was [$retval], output was [$msg]"); + } + + + if (is_array($output) === true) { + $tokens = $phpcsFile->getTokens(); + + foreach ($output as $finding) { + $split = strpos($finding, ':'); + $line = substr($finding, 0, $split); + $message = substr($finding, ($split + 1)); + + // Find the token at the start of the line. + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] == $line) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $phpcsFile->addWarning(trim($message), $ptr, 'ExternalTool'); + } + }//end foreach + }//end if + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php new file mode 100644 index 000000000..643487365 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php @@ -0,0 +1,89 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Files_FileExtensionSniff. + * + * Tests that the stars in a doc comment align correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Files_FileExtensionSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is the first PHP open tag so we don't process + // the same file twice. + $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($prevOpenTag !== false) { + return; + } + + $fileName = $phpcsFile->getFileName(); + $extension = substr($fileName, strrpos($fileName, '.')); + $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE, T_TRAIT), $stackPtr); + + if ($extension === '.php') { + if ($nextClass !== false) { + $error = '%s found in ".php" file; use ".inc" extension instead'; + $data = array(ucfirst($tokens[$nextClass]['content'])); + $phpcsFile->addError($error, $stackPtr, 'ClassFound', $data); + } + } else if ($extension === '.inc') { + if ($nextClass === false) { + $error = 'No interface or class found in ".inc" file; use ".php" extension instead'; + $phpcsFile->addError($error, $stackPtr, 'NoClass'); + } + } + + }//end process() + + +}//end class + + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php new file mode 100644 index 000000000..1cf288f5d --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php @@ -0,0 +1,254 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Formatting_OperationBracketSniff. + * + * Tests that all arithmetic operations are bracketed. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Formatting_OperatorBracketSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$operators; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($phpcsFile->tokenizerType === 'JS' && $tokens[$stackPtr]['code'] === T_PLUS) { + // JavaScript uses the plus operator for string concatenation as well + // so we cannot accurately determine if it is a string concat or addition. + // So just ignore it. + return; + } + + // If the & is a reference, then we don't want to check for brackets. + if ($tokens[$stackPtr]['code'] === T_BITWISE_AND && $phpcsFile->isReference($stackPtr) === true) { + return; + } + + // There is one instance where brackets aren't needed, which involves + // the minus sign being used to assign a negative number to a variable. + if ($tokens[$stackPtr]['code'] === T_MINUS) { + // Check to see if we are trying to return -n. + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_RETURN) { + return; + } + + $number = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$number]['code'] === T_LNUMBER || $tokens[$number]['code'] === T_DNUMBER) { + $previous = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($previous !== false) { + $isAssignment = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens); + $isEquality = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$equalityTokens); + $isComparison = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens); + if ($isAssignment === true || $isEquality === true || $isComparison === true) { + // This is a negative assignment or comparison. + // We need to check that the minus and the number are + // adjacent. + if (($number - $stackPtr) !== 1) { + $error = 'No space allowed between minus sign and number'; + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterMinus'); + } + + return; + } + } + } + }//end if + + $lastBracket = false; + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $parenthesis = array_reverse($tokens[$stackPtr]['nested_parenthesis'], true); + foreach ($parenthesis as $bracket => $endBracket) { + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($bracket - 1), null, true); + $prevCode = $tokens[$prevToken]['code']; + + if ($prevCode === T_ISSET) { + // This operation is inside an isset() call, but has + // no bracket of it's own. + break; + } + + if ($prevCode === T_STRING || $prevCode === T_SWITCH) { + // We allow very simple operations to not be bracketed. + // For example, ceil($one / $two). + $allowed = array( + T_VARIABLE, + T_LNUMBER, + T_DNUMBER, + T_STRING, + T_WHITESPACE, + T_THIS, + T_OBJECT_OPERATOR, + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + T_MODULUS, + ); + + for ($prev = ($stackPtr - 1); $prev > $bracket; $prev--) { + if (in_array($tokens[$prev]['code'], $allowed) === true) { + continue; + } + + if ($tokens[$prev]['code'] === T_CLOSE_PARENTHESIS) { + $prev = $tokens[$prev]['parenthesis_opener']; + } else { + break; + } + } + + if ($prev !== $bracket) { + break; + } + + for ($next = ($stackPtr + 1); $next < $endBracket; $next++) { + if (in_array($tokens[$next]['code'], $allowed) === true) { + continue; + } + + if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + $next = $tokens[$next]['parenthesis_closer']; + } else { + break; + } + } + + if ($next !== $endBracket) { + break; + } + }//end if + + if (in_array($prevCode, PHP_CodeSniffer_Tokens::$scopeOpeners) === true) { + // This operation is inside a control structure like FOREACH + // or IF, but has no bracket of it's own. + // The only control structure allowed to do this is SWITCH. + if ($prevCode !== T_SWITCH) { + break; + } + } + + if ($prevCode === T_OPEN_PARENTHESIS) { + // These are two open parenthesis in a row. If the current + // one doesn't enclose the operator, go to the previous one. + if ($endBracket < $stackPtr) { + continue; + } + } + + $lastBracket = $bracket; + break; + }//end foreach + }//end if + + if ($lastBracket === false) { + // It is not in a bracketed statement at all. + $previousToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true, null, true); + if ($previousToken !== false) { + // A list of tokens that indicate that the token is not + // part of an arithmetic operation. + $invalidTokens = array( + T_COMMA, + T_COLON, + T_OPEN_PARENTHESIS, + T_OPEN_SQUARE_BRACKET, + T_CASE, + ); + + if (in_array($tokens[$previousToken]['code'], $invalidTokens) === false) { + $error = 'Arithmetic operation must be bracketed'; + $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); + } + + return; + } + } else if ($tokens[$lastBracket]['parenthesis_closer'] < $stackPtr) { + // There are a set of brackets in front of it that don't include it. + $error = 'Arithmetic operation must be bracketed'; + $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); + return; + } else { + // We are enclosed in a set of bracket, so the last thing to + // check is that we are not also enclosed in square brackets + // like this: ($array[$index + 1]), which is invalid. + $brackets = array( + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + ); + + $squareBracket = $phpcsFile->findPrevious($brackets, ($stackPtr - 1), $lastBracket); + if ($squareBracket !== false && $tokens[$squareBracket]['code'] === T_OPEN_SQUARE_BRACKET) { + $closeSquareBracket = $phpcsFile->findNext($brackets, ($stackPtr + 1)); + if ($closeSquareBracket !== false && $tokens[$closeSquareBracket]['code'] === T_CLOSE_SQUARE_BRACKET) { + $error = 'Arithmetic operation must be bracketed'; + $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); + } + } + + return; + }//end if + + $lastAssignment = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$assignmentTokens, $stackPtr, null, false, null, true); + if ($lastAssignment !== false && $lastAssignment > $lastBracket) { + $error = 'Arithmetic operation must be bracketed'; + $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php new file mode 100644 index 000000000..c1bd69689 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php @@ -0,0 +1,300 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff. + * + * Checks that arguments in function declarations are spaced correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * How many spaces should surround the equals signs. + * + * @var int + */ + public $equalsSpacing = 0; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_FUNCTION, + T_CLOSURE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->equalsSpacing = (int) $this->equalsSpacing; + + $tokens = $phpcsFile->getTokens(); + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $this->processBracket($phpcsFile, $openBracket); + + if ($tokens[$stackPtr]['code'] === T_CLOSURE) { + $use = $phpcsFile->findNext(T_USE, ($tokens[$openBracket]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']); + if ($use !== false) { + $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null); + $this->processBracket($phpcsFile, $openBracket); + } + } + + }//end process() + + + /** + * Processes the contents of a single set of brackets. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $openBracket The position of the open bracket + * in the stack passed in $tokens. + * + * @return void + */ + public function processBracket(PHP_CodeSniffer_File $phpcsFile, $openBracket) + { + $tokens = $phpcsFile->getTokens(); + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + $multiLine = ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']); + + $nextParam = $openBracket; + $params = array(); + while (($nextParam = $phpcsFile->findNext(T_VARIABLE, ($nextParam + 1), $closeBracket)) !== false) { + + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextParam + 1), ($closeBracket + 1), true); + if ($nextToken === false) { + break; + } + + $nextCode = $tokens[$nextToken]['code']; + + if ($nextCode === T_EQUAL) { + // Check parameter default spacing. + $spacesBefore = 0; + if (($nextToken - $nextParam) > 1) { + $spacesBefore = strlen($tokens[($nextParam + 1)]['content']); + } + + if ($spacesBefore !== $this->equalsSpacing) { + $error = 'Incorrect spacing between argument "%s" and equals sign; expected '.$this->equalsSpacing.' but found %s'; + $data = array( + $tokens[$nextParam]['content'], + $spacesBefore, + ); + $phpcsFile->addError($error, $nextToken, 'SpaceBeforeEquals', $data); + } + + $spacesAfter = 0; + if ($tokens[($nextToken + 1)]['code'] === T_WHITESPACE) { + $spacesAfter = strlen($tokens[($nextToken + 1)]['content']); + } + + if ($spacesAfter !== $this->equalsSpacing) { + $error = 'Incorrect spacing between default value and equals sign for argument "%s"; expected '.$this->equalsSpacing.' but found %s'; + $data = array( + $tokens[$nextParam]['content'], + $spacesAfter, + ); + $phpcsFile->addError($error, $nextToken, 'SpaceAfterDefault', $data); + } + }//end if + + // Find and check the comma (if there is one). + $nextComma = $phpcsFile->findNext(T_COMMA, ($nextParam + 1), $closeBracket); + if ($nextComma !== false) { + // Comma found. + if ($tokens[($nextComma - 1)]['code'] === T_WHITESPACE) { + $error = 'Expected 0 spaces between argument "%s" and comma; %s found'; + $data = array( + $tokens[$nextParam]['content'], + strlen($tokens[($nextComma - 1)]['content']), + ); + $phpcsFile->addError($error, $nextToken, 'SpaceBeforeComma', $data); + } + } + + // Take references into account when expecting the + // location of whitespace. + if ($phpcsFile->isReference(($nextParam - 1)) === true) { + $whitespace = ($nextParam - 2); + } else { + $whitespace = ($nextParam - 1); + } + + if (empty($params) === false) { + // This is not the first argument in the function declaration. + $arg = $tokens[$nextParam]['content']; + + if ($tokens[$whitespace]['code'] === T_WHITESPACE) { + $gap = strlen($tokens[$whitespace]['content']); + + // Before we throw an error, make sure there is no type hint. + $comma = $phpcsFile->findPrevious(T_COMMA, ($nextParam - 1)); + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($comma + 1), null, true); + if ($phpcsFile->isReference($nextToken) === true) { + $nextToken++; + } + + if ($nextToken !== $nextParam) { + // There was a type hint, so check the spacing between + // the hint and the variable as well. + $hint = $tokens[$nextToken]['content']; + + if ($gap !== 1) { + $error = 'Expected 1 space between type hint and argument "%s"; %s found'; + $data = array( + $arg, + $gap, + ); + $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint', $data); + } + + if ($multiLine === false) { + if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space between comma and type hint "%s"; 0 found'; + $data = array($hint); + $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeHint', $data); + } else { + $gap = strlen($tokens[($comma + 1)]['content']); + if ($gap !== 1) { + $error = 'Expected 1 space between comma and type hint "%s"; %s found'; + $data = array( + $hint, + $gap, + ); + $phpcsFile->addError($error, $nextToken, 'SpacingBeforeHint', $data); + } + } + } + } else if ($gap !== 1) { + // Just make sure this is not actually an indent. + if ($tokens[$whitespace]['line'] === $tokens[($whitespace - 1)]['line']) { + $error = 'Expected 1 space between comma and argument "%s"; %s found'; + $data = array( + $arg, + $gap, + ); + $phpcsFile->addError($error, $nextToken, 'SpacingBeforeArg', $data); + } + }//end if + } else { + $error = 'Expected 1 space between comma and argument "%s"; 0 found'; + $data = array($arg); + $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeArg', $data); + }//end if + } else { + // First argument in function declaration. + if ($tokens[$whitespace]['code'] === T_WHITESPACE) { + $gap = strlen($tokens[$whitespace]['content']); + $arg = $tokens[$nextParam]['content']; + + // Before we throw an error, make sure there is no type hint. + $bracket = $phpcsFile->findPrevious(T_OPEN_PARENTHESIS, ($nextParam - 1)); + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($bracket + 1), null, true); + if ($phpcsFile->isReference($nextToken) === true) { + $nextToken++; + } + + if ($nextToken !== $nextParam) { + // There was a type hint, so check the spacing between + // the hint and the variable as well. + $hint = $tokens[$nextToken]['content']; + + if ($gap !== 1) { + $error = 'Expected 1 space between type hint and argument "%s"; %s found'; + $data = array( + $arg, + $gap, + ); + $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint', $data); + } + + if ($multiLine === false + && $tokens[($bracket + 1)]['code'] === T_WHITESPACE + ) { + $error = 'Expected 0 spaces between opening bracket and type hint "%s"; %s found'; + $data = array( + $hint, + strlen($tokens[($bracket + 1)]['content']), + ); + $phpcsFile->addError($error, $nextToken, 'SpacingAfterOpenHint', $data); + } + } else if ($multiLine === false) { + $error = 'Expected 0 spaces between opening bracket and argument "%s"; %s found'; + $data = array( + $arg, + $gap, + ); + $phpcsFile->addError($error, $nextToken, 'SpacingAfterOpen', $data); + } + }//end if + }//end if + + $params[] = $nextParam; + + }//end while + + if (empty($params) === true) { + // There are no parameters for this function. + if (($closeBracket - $openBracket) !== 1) { + $error = 'Expected 0 spaces between brackets of function declaration; %s found'; + $data = array(strlen($tokens[($closeBracket - 1)]['content'])); + $phpcsFile->addError($error, $openBracket, 'SpacingBetween', $data); + } + } else if ($multiLine === false + && $tokens[($closeBracket - 1)]['code'] === T_WHITESPACE + ) { + $lastParam = array_pop($params); + $error = 'Expected 0 spaces between argument "%s" and closing bracket; %s found'; + $data = array( + $tokens[$lastParam]['content'], + strlen($tokens[($closeBracket - 1)]['content']), + ); + $phpcsFile->addError($error, $closeBracket, 'SpacingBeforeClose', $data); + } + + }//end processBracket() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php new file mode 100644 index 000000000..ebc9879f2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php @@ -0,0 +1,55 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); +} + +/** + * Squiz_Sniffs_Functions_FunctionDeclarationSniff. + * + * Checks the function declaration is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_FunctionDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff +{ + + + /** + * Returns an array of patterns to check are correct. + * + * @return array + */ + protected function getPatterns() + { + return array( + 'function abc(...);', + 'abstract function abc(...);', + ); + + }//end getPatterns() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php new file mode 100644 index 000000000..fd87edc5f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php @@ -0,0 +1,81 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Functions_FunctionDuplicateArgumentSpacingSniff. + * + * Checks that duplicate arguments are not used in function declarations. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + + $foundVariables = array(); + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + if ($tokens[$i]['code'] === T_VARIABLE) { + $variable = $tokens[$i]['content']; + if (in_array($variable, $foundVariables) === true) { + $error = 'Variable "%s" appears more than once in function declaration'; + $data = array($variable); + $phpcsFile->addError($error, $i, 'Found', $data); + } else { + $foundVariables[] = $variable; + } + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php new file mode 100644 index 000000000..d13c8b546 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php @@ -0,0 +1,78 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Functions_GlobalFunctionSniff. + * + * Tests for functions outside of classes. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_GlobalFunctionSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (empty($tokens[$stackPtr]['conditions']) === true) { + $functionName = $phpcsFile->getDeclarationName($stackPtr); + if ($functionName === null) { + return; + } + + // Special exception for __autoload as it needs to be global. + if ($functionName !== '__autoload') { + $error = 'Consider putting global function "%s" in a static class'; + $data = array($functionName); + $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php new file mode 100644 index 000000000..c37e244c0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php @@ -0,0 +1,81 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff. + * + * Ensures all class keywords are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_FUNCTION, + T_PUBLIC, + T_PRIVATE, + T_PROTECTED, + T_STATIC, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + if ($content !== strtolower($content)) { + $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtoupper($content), + strtolower($content), + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php new file mode 100644 index 000000000..d5137f1a7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php @@ -0,0 +1,140 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PEAR_Sniffs_Functions_FunctionDeclarationSniff', true) === false) { + $error = 'Class PEAR_Sniffs_Functions_FunctionDeclarationSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff. + * + * Ensure single and multi-line function declarations are defined correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff extends PEAR_Sniffs_Functions_FunctionDeclarationSniff +{ + + + /** + * Processes multi-line declarations. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * + * @return void + */ + public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) + { + // We do everything the parent sniff does, and a bit more. + parent::processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens); + + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $this->processBracket($phpcsFile, $openBracket, $tokens, 'function'); + + if ($tokens[$stackPtr]['code'] !== T_CLOSURE) { + return; + } + + $use = $phpcsFile->findNext(T_USE, ($tokens[$stackPtr]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']); + if ($use === false) { + return; + } + + $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null); + $this->processBracket($phpcsFile, $openBracket, $tokens, 'use'); + + // Also check spacing. + if ($tokens[($use - 1)]['code'] === T_WHITESPACE) { + $gap = strlen($tokens[($use - 1)]['content']); + } else { + $gap = 0; + } + + }//end processMultiLineDeclaration() + + + /** + * Processes the contents of a single set of brackets. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $openBracket The position of the open bracket + * in the stack passed in $tokens. + * @param array $tokens The stack of tokens that make up + * the file. + * @param string $type The type of the token the brackets + * belong to (function or use). + * + * @return void + */ + public function processBracket(PHP_CodeSniffer_File $phpcsFile, $openBracket, $tokens, $type='function') + { + $errorPrefix = ''; + if ($type === 'use') { + $errorPrefix = 'Use'; + } + + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + // The open bracket should be the last thing on the line. + if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) { + $next = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); + if ($tokens[$next]['line'] !== ($tokens[$openBracket]['line'] + 1)) { + $error = 'The first parameter of a multi-line '.$type.' declaration must be on the line after the opening bracket'; + $phpcsFile->addError($error, $next, $errorPrefix.'FirstParamSpacing'); + } + } + + // Each line between the brackets should contain a single parameter. + $lastCommaLine = null; + for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { + // Skip brackets, like arrays, as they can contain commas. + if (isset($tokens[$i]['parenthesis_opener']) === true) { + $i = $tokens[$i]['parenthesis_closer']; + continue; + } + + if ($tokens[$i]['code'] === T_COMMA) { + if ($lastCommaLine !== null && $lastCommaLine === $tokens[$i]['line']) { + $error = 'Multi-line '.$type.' declarations must define one parameter per line'; + $phpcsFile->addError($error, $i, $errorPrefix.'OneParamPerLine'); + } else { + // Comma must be the last thing on the line. + $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + if ($tokens[$next]['line'] !== ($tokens[$i]['line'] + 1)) { + $error = 'Commas in multi-line '.$type.' declarations must be the last content on a line'; + $phpcsFile->addError($error, $next, $errorPrefix.'ContentAfterComma'); + } + } + + $lastCommaLine = $tokens[$i]['line']; + } + } + + }//end processBracket() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php new file mode 100644 index 000000000..664740b23 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php @@ -0,0 +1,65 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_PHP_LowerCaseConstantSniff', true) === false) { + $error = 'Class Generic_Sniffs_PHP_LowerCaseConstantSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +if (class_exists('Generic_Sniffs_PHP_UpperCaseConstantSniff', true) === false) { + $error = 'Class Generic_Sniffs_PHP_UpperCaseConstantSniff not found'; + throw new PHP_CodeSniffer_Exception($error); +} + +/** + * Squiz_Sniffs_NamingConventions_ConstantCaseSniff. + * + * Ensures TRUE, FALSE and NULL are uppercase for PHP and lowercase for JS. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_NamingConventions_ConstantCaseSniff extends Generic_Sniffs_PHP_LowerCaseConstantSniff +{ + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + if ($phpcsFile->tokenizerType === 'JS') { + parent::process($phpcsFile, $stackPtr); + } else { + $sniff = new Generic_Sniffs_PHP_UpperCaseConstantSniff; + $sniff->process($phpcsFile, $stackPtr); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php new file mode 100644 index 000000000..542bc21ad --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php @@ -0,0 +1,74 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff not found'); +} + +/** + * Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff. + * + * Ensures method names are correct depending on whether they are public + * or private, and that functions are named correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff extends PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff +{ + + + /** + * Processes the tokens outside the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $functionName = $phpcsFile->getDeclarationName($stackPtr); + if ($functionName === null) { + return; + } + + $errorData = array($functionName); + + // Does this function claim to be magical? + if (preg_match('|^__|', $functionName) !== 0) { + $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; + $phpcsFile->addError($error, $stackPtr, 'DoubleUnderscore', $errorData); + return; + } + + if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, false) === false) { + $error = 'Function name "%s" is not in camel caps format'; + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); + } + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php new file mode 100644 index 000000000..fff2089af --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -0,0 +1,241 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +/** + * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. + * + * Checks the naming of variables and member variables. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + /** + * Tokens to ignore so that we can find a DOUBLE_COLON. + * + * @var array + */ + private $_ignore = array( + T_WHITESPACE, + T_COMMENT, + ); + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $varName = ltrim($tokens[$stackPtr]['content'], '$'); + + $phpReservedVars = array( + '_SERVER', + '_GET', + '_POST', + '_REQUEST', + '_SESSION', + '_ENV', + '_COOKIE', + '_FILES', + 'GLOBALS', + ); + + // If it's a php reserved var, then its ok. + if (in_array($varName, $phpReservedVars) === true) { + return; + } + + $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); + if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { + // Check to see if we are using a variable from an object. + $var = $phpcsFile->findNext(array(T_WHITESPACE), ($objOperator + 1), null, true); + if ($tokens[$var]['code'] === T_STRING) { + $bracket = $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); + if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { + $objVarName = $tokens[$var]['content']; + + // There is no way for us to know if the var is public or + // private, so we have to ignore a leading underscore if there is + // one and just check the main part of the variable name. + $originalVarName = $objVarName; + if (substr($objVarName, 0, 1) === '_') { + $objVarName = substr($objVarName, 1); + } + + if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); + } + }//end if + }//end if + }//end if + + // There is no way for us to know if the var is public or private, + // so we have to ignore a leading underscore if there is one and just + // check the main part of the variable name. + $originalVarName = $varName; + if (substr($varName, 0, 1) === '_') { + $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); + if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { + // The variable lives within a class, and is referenced like + // this: MyClass::$_variable, so we don't know its scope. + $inClass = true; + } else { + $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)); + } + + if ($inClass === true) { + $varName = substr($varName, 1); + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); + } + + }//end processVariable() + + + /** + * Processes class member variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $varName = ltrim($tokens[$stackPtr]['content'], '$'); + $memberProps = $phpcsFile->getMemberProperties($stackPtr); + if (empty($memberProps) === true) { + // Couldn't get any info about this variable, which + // generally means it is invalid or possibly has a parse + // error. Any errors will be reported by the core, so + // we can ignore it. + return; + } + + $public = ($memberProps['scope'] !== 'private'); + $errorData = array($varName); + + if ($public === true) { + if (substr($varName, 0, 1) === '_') { + $error = '%s member variable "%s" must not contain a leading underscore'; + $data = array( + ucfirst($memberProps['scope']), + $errorData[0], + ); + $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); + return; + } + } else { + if (substr($varName, 0, 1) !== '_') { + $error = 'Private member variable "%s" must contain a leading underscore'; + $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData); + return; + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $phpcsFile->addError($error, $stackPtr, 'MemberNotCamelCaps', $errorData); + } + + }//end processMemberVar() + + + /** + * Processes the variable found within a double quoted string. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the double quoted + * string. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $phpReservedVars = array( + '_SERVER', + '_GET', + '_POST', + '_REQUEST', + '_SESSION', + '_ENV', + '_COOKIE', + '_FILES', + 'GLOBALS', + ); + if (preg_match_all('|[^\\\]\${?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { + foreach ($matches[1] as $varName) { + // If it's a php reserved var, then its ok. + if (in_array($varName, $phpReservedVars) === true) { + continue; + } + + // There is no way for us to know if the var is public or private, + // so we have to ignore a leading underscore if there is one and just + // check the main part of the variable name. + $originalVarName = $varName; + if (substr($varName, 0, 1) === '_') { + if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { + $varName = substr($varName, 1); + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { + $varName = $matches[0]; + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $stackPtr, 'StringNotCamelCaps', $data); + + } + } + }//end if + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php new file mode 100644 index 000000000..a28f75615 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php @@ -0,0 +1,98 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Ensures that object indexes are written in dot notation. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Sertan Danis + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_SQUARE_BRACKET); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check if the next non whitespace token is a string. + $index = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$index]['code'] !== T_CONSTANT_ENCAPSED_STRING) { + return; + } + + // Make sure it is the only thing in the square brackets. + $next = $phpcsFile->findNext(T_WHITESPACE, ($index + 1), null, true); + if ($tokens[$next]['code'] !== T_CLOSE_SQUARE_BRACKET) { + return; + } + + // Allow indexes that have dots in them because we can't write + // them in dot notation. + $content = trim($tokens[$index]['content'], '"\' '); + if (strpos($content, '.') !== false) { + return; + } + + // Also ignore reserved words. + if ($content === 'super') { + return; + } + + // Token before the opening square bracket cannot be a var name. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_STRING) { + $error = 'Object indexes must be written in dot notation'; + $phpcsFile->addError($error, $prev, 'Found'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php new file mode 100644 index 000000000..5f5ca55b7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php @@ -0,0 +1,83 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Objects_ObjectInstantiationSniff. + * + * Ensures objects are assigned to a variable when instantiated. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Objects_ObjectInstantiationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Registers the token types that this sniff wishes to listen to. + * + * @return array + */ + public function register() + { + return array(T_NEW); + + }//end register() + + + /** + * Process the tokens that this sniff is listening for. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $allowedTokens = PHP_CodeSniffer_Tokens::$emptyTokens; + $allowedTokens[] = T_BITWISE_AND; + + $prev = $phpcsFile->findPrevious($allowedTokens, ($stackPtr - 1), null, true); + + $allowedTokens = array( + T_EQUAL, + T_DOUBLE_ARROW, + T_THROW, + T_RETURN, + T_INLINE_THEN, + T_INLINE_ELSE, + ); + + if (in_array($tokens[$prev]['code'], $allowedTokens) === false) { + $error = 'New objects must be assigned to a variable'; + $phpcsFile->addError($error, $stackPtr, 'NotAssigned'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php new file mode 100644 index 000000000..e08a92079 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php @@ -0,0 +1,84 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Objects_ObjectInstantiationSniff. + * + * Ensures objects are assigned to a variable when instantiated. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Objects_ObjectMemberCommaSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Registers the token types that this sniff wishes to listen to. + * + * @return array + */ + public function register() + { + return array(T_CLOSE_CURLY_BRACKET); + + }//end register() + + + /** + * Process the tokens that this sniff is listening for. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Only interested in orphaned braces (which are objects) + // and object definitions. + if (isset($tokens[$stackPtr]['scope_condition']) === true) { + $condition = $tokens[$stackPtr]['scope_condition']; + if ($tokens[$condition]['code'] !== T_OBJECT) { + return; + } + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_COMMA) { + $error = 'Last member of object must not be followed by a comma'; + $phpcsFile->addError($error, $prev, 'Missing'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php new file mode 100644 index 000000000..db994b81e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php @@ -0,0 +1,210 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators. + * + * The use of === true is enforced over implicit true statements, + * for example: + * + * + * if ($a) + * { + * ... + * } + * + * + * should be: + * + * + * if ($a === true) + * { + * ... + * } + * + * + * It also enforces the use of === false over ! operators. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * A list of valid comparison operators. + * + * @var array + */ + private static $_validOps = array( + T_IS_IDENTICAL, + T_IS_NOT_IDENTICAL, + T_LESS_THAN, + T_GREATER_THAN, + T_IS_GREATER_OR_EQUAL, + T_IS_SMALLER_OR_EQUAL, + T_INSTANCEOF, + ); + + /** + * A list of invalid operators with their alternatives. + * + * @var array(int => string) + */ + private static $_invalidOps = array( + 'PHP' => array( + T_IS_EQUAL => '===', + T_IS_NOT_EQUAL => '!==', + T_BOOLEAN_NOT => '=== FALSE', + ), + 'JS' => array( + T_IS_EQUAL => '===', + T_IS_NOT_EQUAL => '!==', + ), + ); + + + /** + * Registers the token types that this sniff wishes to listen to. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_ELSEIF, + T_INLINE_THEN, + ); + + }//end register() + + + /** + * Process the tokens that this sniff is listening for. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where the token + * was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $tokenizer = $phpcsFile->tokenizerType; + + if ($tokens[$stackPtr]['code'] === T_INLINE_THEN) { + $end = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$end]['code'] !== T_CLOSE_PARENTHESIS) { + // This inline IF statement does not have its condition + // bracketed, so we need to guess where it starts. + for ($i = ($end - 1); $i >= 0; $i--) { + if ($tokens[$i]['code'] === T_SEMICOLON) { + // Stop here as we assume it is the end + // of the previous statement. + break; + } else if ($tokens[$i]['code'] === T_OPEN_TAG) { + // Stop here as this is the start of the file. + break; + } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET) { + // Stop if this is the closing brace of + // a code block. + if (isset($tokens[$i]['scope_opener']) === true) { + break; + } + } else if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { + // Stop if this is the opening brace of + // a code block. + if (isset($tokens[$i]['scope_closer']) === true) { + break; + } + } + }//end for + + $start = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true); + } else { + $start = $tokens[$end]['parenthesis_opener']; + } + } else { + $start = $tokens[$stackPtr]['parenthesis_opener']; + $end = $tokens[$stackPtr]['parenthesis_closer']; + } + + $requiredOps = 0; + $foundOps = 0; + + for ($i = $start; $i <= $end; $i++) { + $type = $tokens[$i]['code']; + if (in_array($type, array_keys(self::$_invalidOps[$tokenizer])) === true) { + $error = 'Operator %s prohibited; use %s instead'; + $data = array( + $tokens[$i]['content'], + self::$_invalidOps[$tokenizer][$type], + ); + $phpcsFile->addError($error, $i, 'NotAllowed', $data); + $foundOps++; + } else if (in_array($type, self::$_validOps) === true) { + $foundOps++; + } + + if ($phpcsFile->tokenizerType !== 'JS') { + if ($tokens[$i]['code'] === T_BOOLEAN_AND || $tokens[$i]['code'] === T_BOOLEAN_OR) { + $requiredOps++; + + // If we get to here and we have not found the right number of + // comparison operators, then we must have had an implicit + // true operation ie. if ($a) instead of the required + // if ($a === true), so let's add an error. + if ($requiredOps !== $foundOps) { + $error = 'Implicit true comparisons prohibited; use === TRUE instead'; + $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue'); + $foundOps++; + } + } + }//end if + }//end for + + $requiredOps++; + + if ($phpcsFile->tokenizerType !== 'JS') { + if ($foundOps < $requiredOps) { + $error = 'Implicit true comparisons prohibited; use === TRUE instead'; + $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue'); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php new file mode 100644 index 000000000..ec070d614 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php @@ -0,0 +1,234 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Operators_IncrementDecrementUsageSniff. + * + * Tests that the ++ operators are used when possible and not + * used when it makes the code confusing. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Operators_IncrementDecrementUsageSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_EQUAL, + T_PLUS_EQUAL, + T_MINUS_EQUAL, + T_INC, + T_DEC, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['code'] === T_INC || $tokens[$stackPtr]['code'] === T_DEC) { + $this->processIncDec($phpcsFile, $stackPtr); + } else { + $this->processAssignment($phpcsFile, $stackPtr); + } + + }//end process() + + + /** + * Checks to ensure increment and decrement operators are not confusing. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + protected function processIncDec(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Work out where the variable is so we know where to + // start looking for other operators. + if ($tokens[($stackPtr - 1)]['code'] === T_VARIABLE) { + $start = ($stackPtr + 1); + } else { + $start = ($stackPtr + 2); + } + + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $start, null, true); + if ($next === false) { + return; + } + + if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$arithmeticTokens) === true) { + $error = 'Increment and decrement operators cannot be used in an arithmetic operation'; + $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); + return; + } + + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($start - 3), null, true); + if ($prev === false) { + return; + } + + // Check if this is in a string concat. + if ($tokens[$next]['code'] === T_STRING_CONCAT || $tokens[$prev]['code'] === T_STRING_CONCAT) { + $error = 'Increment and decrement operators must be bracketed when used in string concatenation'; + $phpcsFile->addError($error, $stackPtr, 'NoBrackets'); + } + + }//end processIncDec() + + + /** + * Checks to ensure increment and decrement operators are used. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + protected function processAssignment(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $assignedVar = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + // Not an assignment, return. + if ($tokens[$assignedVar]['code'] !== T_VARIABLE) { + return; + } + + $statementEnd = $phpcsFile->findNext(array(T_SEMICOLON, T_CLOSE_PARENTHESIS, T_CLOSE_SQUARE_BRACKET, T_CLOSE_CURLY_BRACKET), $stackPtr); + + // If there is anything other than variables, numbers, spaces or operators we need to return. + $noiseTokens = $phpcsFile->findNext(array(T_LNUMBER, T_VARIABLE, T_WHITESPACE, T_PLUS, T_MINUS, T_OPEN_PARENTHESIS), ($stackPtr + 1), $statementEnd, true); + + if ($noiseTokens !== false) { + return; + } + + // If we are already using += or -=, we need to ignore + // the statement if a variable is being used. + if ($tokens[$stackPtr]['code'] !== T_EQUAL) { + $nextVar = $phpcsFile->findNext(T_VARIABLE, ($stackPtr + 1), $statementEnd); + if ($nextVar !== false) { + return; + } + } + + if ($tokens[$stackPtr]['code'] === T_EQUAL) { + $nextVar = ($stackPtr + 1); + $previousVariable = ($stackPtr + 1); + $variableCount = 0; + while (($nextVar = $phpcsFile->findNext(T_VARIABLE, ($nextVar + 1), $statementEnd)) !== false) { + $previousVariable = $nextVar; + $variableCount++; + } + + if ($variableCount !== 1) { + return; + } + + $nextVar = $previousVariable; + if ($tokens[$nextVar]['content'] !== $tokens[$assignedVar]['content']) { + return; + } + } + + // We have only one variable, and it's the same as what is being assigned, + // so we need to check what is being added or subtracted. + $nextNumber = ($stackPtr + 1); + $previousNumber = ($stackPtr + 1); + $numberCount = 0; + while (($nextNumber = $phpcsFile->findNext(array(T_LNUMBER), ($nextNumber + 1), $statementEnd, false)) !== false) { + $previousNumber = $nextNumber; + $numberCount++; + } + + if ($numberCount !== 1) { + return; + } + + $nextNumber = $previousNumber; + if ($tokens[$nextNumber]['content'] === '1') { + if ($tokens[$stackPtr]['code'] === T_EQUAL) { + $opToken = $phpcsFile->findNext(array(T_PLUS, T_MINUS), ($nextVar + 1), $statementEnd); + if ($opToken === false) { + // Operator was before the variable, like: + // $var = 1 + $var; + // So we ignore it. + return; + } + + $operator = $tokens[$opToken]['content']; + } else { + $operator = substr($tokens[$stackPtr]['content'], 0, 1); + } + + // If we are adding or subtracting negative value, the operator + // needs to be reversed. + if ($tokens[$stackPtr]['code'] !== T_EQUAL) { + $negative = $phpcsFile->findPrevious(T_MINUS, ($nextNumber - 1), $stackPtr); + if ($negative !== false) { + $operator = ($operator === '+') ? '-' : '+'; + } + } + + $expected = $tokens[$assignedVar]['content'].$operator.$operator; + $found = $phpcsFile->getTokensAsString($assignedVar, ($statementEnd - $assignedVar + 1)); + + if ($operator === '+') { + $error = 'Increment'; + } else { + $error = 'Decrement'; + } + + $error .= " operators should be used where possible; found \"$found\" but expected \"$expected\""; + $phpcsFile->addError($error, $stackPtr); + }//end if + + }//end processAssignment() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php new file mode 100644 index 000000000..3374e5523 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php @@ -0,0 +1,87 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff. + * + * Checks to ensure that the logical operators 'and' and 'or' are not used. + * Use the && and || operators instead. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_LOGICAL_AND, + T_LOGICAL_OR, + T_LOGICAL_XOR, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $replacements = array( + 'and' => '&&', + 'or' => '||', + 'xor' => '^', + ); + + $operator = strtolower($tokens[$stackPtr]['content']); + if (isset($replacements[$operator]) === false) { + return; + } + + $error = 'Logical operator "%s" is prohibited; use "%s" instead'; + $data = array( + $operator, + $replacements[$operator], + ); + $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php new file mode 100644 index 000000000..80de3c219 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php @@ -0,0 +1,228 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_CommentedOutCodeSniff. + * + * Warn about commented out code. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_CommentedOutCodeSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'CSS', + ); + + /** + * If a comment is more than $maxPercentage% code, a warning will be shown. + * + * @var int + */ + public $maxPercentage = 35; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$commentTokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Process whole comment blocks at once, so skip all but the first token. + if ($stackPtr > 0 && $tokens[$stackPtr]['code'] === $tokens[($stackPtr - 1)]['code']) { + return; + } + + // Ignore comments at the end of code blocks. + if (substr($tokens[$stackPtr]['content'], 0, 6) === '//end ') { + return; + } + + $content = ''; + if ($phpcsFile->tokenizerType === 'PHP') { + $content = 'numTokens; $i++) { + if ($tokens[$stackPtr]['code'] !== $tokens[$i]['code']) { + break; + } + + /* + Trim as much off the comment as possible so we don't + have additional whitespace tokens or comment tokens + */ + + $tokenContent = trim($tokens[$i]['content']); + + if (substr($tokenContent, 0, 2) === '//') { + $tokenContent = substr($tokenContent, 2); + } + + if (substr($tokenContent, 0, 1) === '#') { + $tokenContent = substr($tokenContent, 1); + } + + if (substr($tokenContent, 0, 3) === '/**') { + $tokenContent = substr($tokenContent, 3); + } + + if (substr($tokenContent, 0, 2) === '/*') { + $tokenContent = substr($tokenContent, 2); + } + + if (substr($tokenContent, -2) === '*/') { + $tokenContent = substr($tokenContent, 0, -2); + } + + if (substr($tokenContent, 0, 1) === '*') { + $tokenContent = substr($tokenContent, 1); + } + + $content .= $tokenContent.$phpcsFile->eolChar; + }//end for + + $content = trim($content); + + if ($phpcsFile->tokenizerType === 'PHP') { + $content .= ' ?>'; + } + + // Quite a few comments use multiple dashes, equals signs etc + // to frame comments and licence headers. + $content = preg_replace('/[-=*]+/', '-', $content); + + // Because we are not really parsing code, the tokenizer can throw all sorts + // of errors that don't mean anything, so ignore them. + $oldErrors = ini_get('error_reporting'); + ini_set('error_reporting', 0); + $stringTokens = PHP_CodeSniffer_File::tokenizeString($content, $phpcsFile->tokenizer, $phpcsFile->eolChar); + ini_set('error_reporting', $oldErrors); + + $emptyTokens = array( + T_WHITESPACE, + T_STRING, + T_STRING_CONCAT, + T_ENCAPSED_AND_WHITESPACE, + T_NONE, + ); + + $numTokens = count($stringTokens); + + /* + We know what the first two and last two tokens should be + (because we put them there) so ignore this comment if those + tokens were not parsed correctly. It obviously means this is not + valid code. + */ + + // First token is always the opening PHP tag. + if ($stringTokens[0]['code'] !== T_OPEN_TAG) { + return; + } + + // Last token is always the closing PHP tag, unless something went wrong. + if (isset($stringTokens[($numTokens - 1)]) === false + || $stringTokens[($numTokens - 1)]['code'] !== T_CLOSE_TAG + ) { + return; + } + + // Second last token is always whitespace or a comment, depending + // on the code inside the comment. + if (in_array($stringTokens[($numTokens - 2)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + return; + } + + $numComment = 0; + $numPossible = 0; + $numCode = 0; + + for ($i = 0; $i < $numTokens; $i++) { + if (in_array($stringTokens[$i]['code'], $emptyTokens) === true) { + // Looks like comment. + $numComment++; + } else if (in_array($stringTokens[$i]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) + || in_array($stringTokens[$i]['code'], PHP_CodeSniffer_Tokens::$arithmeticTokens) + ) { + // Commented out HTML/XML and other docs contain a lot of these + // characters, so it is best to not use them directly. + $numPossible++; + } else { + // Looks like code. + $numCode++; + } + } + + // We subtract 3 from the token number so we ignore the start/end tokens + // and their surrounding whitespace. We take 2 off the number of code + // tokens so we ignore the start/end tokens. + if ($numTokens > 3) { + $numTokens -= 3; + } + + if ($numCode >= 2) { + $numCode -= 2; + } + + $percentCode = ceil((($numCode / $numTokens) * 100)); + if ($percentCode > $this->maxPercentage) { + // Just in case. + $percentCode = min(100, $percentCode); + + $error = 'This comment is %s%% valid code; is this commented out code?'; + $data = array($percentCode); + $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php new file mode 100644 index 000000000..381bec292 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php @@ -0,0 +1,74 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_DisallowBooleanStatementSniff. + * + * Ensures that boolean operators are only used inside control structure conditions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowBooleanStatementSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$booleanOperators; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $foundOwner = false; + foreach ($tokens[$stackPtr]['nested_parenthesis'] as $open => $close) { + if (isset($tokens[$open]['parenthesis_owner']) === true) { + // Any owner means we are not just a simple statement. + return; + } + } + } + + $error = 'Boolean operators are not allowed outside of control structure conditions'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php new file mode 100644 index 000000000..25aa44586 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php @@ -0,0 +1,125 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff. + * + * Ensures that the value of a comparison is not assigned to a variable. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_EQUAL); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore default value assignments in function definitions. + $function = $phpcsFile->findPrevious(T_FUNCTION, ($stackPtr - 1)); + if ($function !== false) { + $opener = $tokens[$function]['parenthesis_opener']; + $closer = $tokens[$function]['parenthesis_closer']; + if ($opener < $stackPtr && $closer > $stackPtr) { + return; + } + } + + // Ignore values in array definitions. + $array = $phpcsFile->findNext( + T_ARRAY, + ($stackPtr + 1), + null, + false, + null, + true + ); + + if ($array !== false) { + return; + } + + // Ignore function calls. + $ignore = array( + T_STRING, + T_WHITESPACE, + T_OBJECT_OPERATOR, + ); + + $next = $phpcsFile->findNext($ignore, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS + && $tokens[($next - 1)]['code'] === T_STRING + ) { + // Code will look like: $var = myFunction( + // and will be ignored. + return; + } + + $endStatement = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); + if ($tokens[$stackPtr]['conditions'] !== $tokens[$endStatement]['conditions']) { + // This statement doesn't end with a semicolon, which is the case for + // the last expression in a for loop. + return; + } + + for ($i = ($stackPtr + 1); $i < $endStatement; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) === true) { + $error = 'The value of a comparison must not be assigned to a variable'; + $phpcsFile->addError($error, $stackPtr, 'AssignedComparison'); + break; + } + + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$booleanOperators) === true + || $tokens[$i]['code'] === T_BOOLEAN_NOT + ) { + $error = 'The value of a boolean operation must not be assigned to a variable'; + $phpcsFile->addError($error, $stackPtr, 'AssignedBool'); + break; + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php new file mode 100644 index 000000000..afc1acf28 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php @@ -0,0 +1,74 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Formatting_DisallowInlineIfSniff. + * + * Stops inline IF statements from being used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowInlineIfSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_INLINE_THEN); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $phpcsFile->addError('Inline IF statements are not allowed', $stackPtr, 'Found'); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php new file mode 100644 index 000000000..4873a5ed7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php @@ -0,0 +1,180 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff. + * + * Ensures that there is only one value assignment on a line, and that it is + * the first thing on the line. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_EQUAL); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Ignore default value assignments in function definitions. + $function = $phpcsFile->findPrevious(array(T_FUNCTION, T_CLOSURE), ($stackPtr - 1)); + if ($function !== false) { + $opener = $tokens[$function]['parenthesis_opener']; + $closer = $tokens[$function]['parenthesis_closer']; + if ($opener < $stackPtr && $closer > $stackPtr) { + return; + } + } + + /* + The general rule is: + Find an equal sign and go backwards along the line. If you hit an + end bracket, skip to the opening bracket. When you find a variable, + stop. That variable must be the first non-empty token on the line + or in the statement. If not, throw an error. + */ + + for ($varToken = ($stackPtr - 1); $varToken >= 0; $varToken--) { + // Skip brackets. + if (isset($tokens[$varToken]['parenthesis_opener']) === true && $tokens[$varToken]['parenthesis_opener'] < $varToken) { + $varToken = $tokens[$varToken]['parenthesis_opener']; + continue; + } + + if (isset($tokens[$varToken]['bracket_opener']) === true) { + $varToken = $tokens[$varToken]['bracket_opener']; + continue; + } + + if ($tokens[$varToken]['code'] === T_SEMICOLON) { + // We've reached the next statement, so we + // didn't find a variable. + return; + } + + if ($tokens[$varToken]['code'] === T_VARIABLE) { + // We found our variable. + break; + } + } + + if ($varToken <= 0) { + // Didn't find a variable. + return; + } + + // Deal with this type of variable: self::$var by setting the var + // token to be "self" rather than "$var". + if ($tokens[($varToken - 1)]['code'] === T_DOUBLE_COLON) { + $varToken = ($varToken - 2); + } + + // Deal with this type of variable: $obj->$var by setting the var + // token to be "$obj" rather than "$var". + if ($tokens[($varToken - 1)]['code'] === T_OBJECT_OPERATOR) { + $varToken = ($varToken - 2); + } + + // Deal with this type of variable: $$var by setting the var + // token to be "$" rather than "$var". + if ($tokens[($varToken - 1)]['content'] === '$') { + $varToken--; + } + + // Ignore member var definitions. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($varToken - 1), null, true); + if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$scopeModifiers) === true) { + return; + } + + if ($tokens[$prev]['code'] === T_STATIC) { + return; + } + + // Make sure this variable is the first thing in the statement. + $varLine = $tokens[$varToken]['line']; + $prevLine = 0; + for ($i = ($varToken - 1); $i >= 0; $i--) { + if ($tokens[$i]['code'] === T_SEMICOLON) { + // We reached the end of the statement. + return; + } + + if ($tokens[$i]['code'] === T_INLINE_THEN) { + // We reached the end of the inline THEN statement. + return; + } + + if ($tokens[$i]['code'] === T_INLINE_ELSE) { + // We reached the end of the inline ELSE statement. + return; + } + + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + $prevLine = $tokens[$i]['line']; + break; + } + } + + // Ignore the first part of FOR loops as we are allowed to + // assign variables there even though the variable is not the + // first thing on the line. Also ignore WHILE loops. + if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS && isset($tokens[$i]['parenthesis_owner']) === true) { + $owner = $tokens[$i]['parenthesis_owner']; + if ($tokens[$owner]['code'] === T_FOR || $tokens[$owner]['code'] === T_WHILE) { + return; + } + } + + if ($prevLine === $varLine) { + $error = 'Assignments must be the first block of code on a line'; + $phpcsFile->addError($error, $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php new file mode 100644 index 000000000..9350c6326 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php @@ -0,0 +1,68 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Formatting_DisallowObEndFlushSniff. + * + * Checks the indenting used when an ob_start() call occurs. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowObEndFlushSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content'] === 'ob_end_flush') { + $phpcsFile->addError('Use of ob_end_flush() is not allowed; use ob_get_contents() and ob_end_clean() instead', $stackPtr, 'Found'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php new file mode 100644 index 000000000..3aab1cee6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php @@ -0,0 +1,127 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff. + * + * Bans the use of size-based functions in loop conditions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * An array of functions we don't want in the condition of loops. + * + * @return array + */ + protected $forbiddenFunctions = array( + 'PHP' => array( + 'sizeof', + 'strlen', + 'count', + ), + 'JS' => array('length'), + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_WHILE, + T_FOR, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $tokenizer = $phpcsFile->tokenizerType; + $openBracket = $tokens[$stackPtr]['parenthesis_opener']; + $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; + + if ($tokens[$stackPtr]['code'] === T_FOR) { + // We only want to check the condition in FOR loops. + $start = $phpcsFile->findNext(T_SEMICOLON, ($openBracket + 1)); + $end = $phpcsFile->findPrevious(T_SEMICOLON, ($closeBracket - 1)); + } else { + $start = $openBracket; + $end = $closeBracket; + } + + for ($i = ($start + 1); $i < $end; $i++) { + if ($tokens[$i]['code'] === T_STRING && in_array($tokens[$i]['content'], $this->forbiddenFunctions[$tokenizer])) { + $functionName = $tokens[$i]['content']; + if ($tokenizer === 'JS') { + // Needs to be in the form object.function to be valid. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), null, true); + if ($prev === false || $tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { + continue; + } + + $functionName = 'object.'.$functionName; + } else { + // Make sure it isn't a member var. + if ($tokens[($i - 1)]['code'] === T_OBJECT_OPERATOR) { + continue; + } + + $functionName .= '()'; + } + + $error = 'The use of %s inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead'; + $data = array($functionName); + $phpcsFile->addError($error, $i, 'Found', $data); + }//end if + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php new file mode 100644 index 000000000..1689f996c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php @@ -0,0 +1,57 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found'); +} + +/** + * Squiz_Sniffs_PHP_DiscouragedFunctionsSniff. + * + * Discourages the use of debug functions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_DiscouragedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff +{ + + /** + * A list of forbidden functions with their alternatives. + * + * The value is NULL if no alternative exists. IE, the + * function should just not be used. + * + * @var array(string => string|null) + */ + protected $forbiddenFunctions = array( + 'error_log' => null, + 'print_r' => null, + ); + + /** + * If true, an error will be thrown; otherwise a warning. + * + * @var bool + */ + public $error = false; + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php new file mode 100644 index 000000000..bd975f0cb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php @@ -0,0 +1,263 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_EmbeddedPhpSniff. + * + * Checks the indentation of embedded PHP code segments. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_EmbeddedPhpSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If the close php tag is on the same line as the opening + // then we have an inline embedded PHP block. + $closeTag = $phpcsFile->findNext(array(T_CLOSE_TAG), $stackPtr); + if ($closeTag === false) { + return; + } + + if ($tokens[$stackPtr]['line'] !== $tokens[$closeTag]['line']) { + $this->_validateMultilineEmbeddedPhp($phpcsFile, $stackPtr); + } else { + $this->_validateInlineEmbeddedPhp($phpcsFile, $stackPtr); + } + + }//end process() + + + /** + * Validates embedded PHP that exists on multiple lines. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + private function _validateMultilineEmbeddedPhp(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($prevTag === false) { + // This is the first open tag. + return; + } + + // This isn't the first opening tag. + $closingTag = $phpcsFile->findNext(T_CLOSE_TAG, $stackPtr); + if ($closingTag === false) { + // No closing tag? Problem. + return; + } + + $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($closingTag + 1), $phpcsFile->numTokens, true); + if ($nextContent === false) { + // Final closing tag. It will be handled elsewhere. + return; + } + + // Make sure the lines are opening and closing on different lines. + if ($tokens[$stackPtr]['line'] === $tokens[$closingTag]['line']) { + return; + } + + // We have an opening and a closing tag, that lie within other content. + // They are also on different lines. + $firstContent = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), $closingTag, true); + if ($firstContent === false) { + $error = 'Empty embedded PHP tag found'; + $phpcsFile->addError($error, $stackPtr, 'Empty'); + return; + } + + // Check for a blank line at the top. + if ($tokens[$firstContent]['line'] > ($tokens[$stackPtr]['line'] + 1)) { + // Find a token on the blank line to throw the error on. + $i = $stackPtr; + do { + $i++; + } while ($tokens[$i]['line'] !== ($tokens[$stackPtr]['line'] + 1)); + + $error = 'Blank line found at start of embedded PHP content'; + $phpcsFile->addError($error, $i, 'SpacingBefore'); + } else if ($tokens[$firstContent]['line'] === $tokens[$stackPtr]['line']) { + $error = 'Opening PHP tag must be on a line by itself'; + $phpcsFile->addError($error, $stackPtr, 'ContentAfterOpen'); + } + + // Check the indent of the first line. + $startColumn = $tokens[$stackPtr]['column']; + $contentColumn = $tokens[$firstContent]['column']; + if ($contentColumn !== $startColumn) { + $error = 'First line of embedded PHP code must be indented %s spaces; %s found'; + $data = array( + $startColumn, + $contentColumn, + ); + $phpcsFile->addError($error, $firstContent, 'Indent', $data); + } + + // Check for a blank line at the bottom. + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closingTag - 1), ($stackPtr + 1), true); + if ($tokens[$lastContent]['line'] < ($tokens[$closingTag]['line'] - 1)) { + // Find a token on the blank line to throw the error on. + $i = $closingTag; + do { + $i--; + } while ($tokens[$i]['line'] !== ($tokens[$closingTag]['line'] - 1)); + + $error = 'Blank line found at end of embedded PHP content'; + $phpcsFile->addError($error, $i, 'SpacingAfter'); + } else if ($tokens[$lastContent]['line'] === $tokens[$closingTag]['line']) { + $error = 'Closing PHP tag must be on a line by itself'; + $phpcsFile->addError($error, $closingTag, 'ContentAfterEnd'); + } + + }//end _validateMultilineEmbeddedPhp() + + + /** + * Validates embedded PHP that exists on one line. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + private function _validateInlineEmbeddedPhp(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We only want one line PHP sections, so return if the closing tag is + // on the next line. + $closeTag = $phpcsFile->findNext(array(T_CLOSE_TAG), $stackPtr, null, false); + if ($tokens[$stackPtr]['line'] !== $tokens[$closeTag]['line']) { + return; + } + + // Check that there is one, and only one space at the start of the statement. + $firstContent = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); + + if ($firstContent === false || $tokens[$firstContent]['code'] === T_CLOSE_TAG) { + $error = 'Empty embedded PHP tag found'; + $phpcsFile->addError($error, $stackPtr, 'Empty'); + return; + } + + $leadingSpace = ''; + for ($i = ($stackPtr + 1); $i < $firstContent; $i++) { + $leadingSpace .= $tokens[$i]['content']; + } + + if (strlen($leadingSpace) >= 1) { + $error = 'Expected 1 space after opening PHP tag; %s found'; + $data = array((strlen($leadingSpace) + 1)); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen', $data); + } + + $semiColonCount = 0; + $semiColon = $stackPtr; + $lastSemiColon = $semiColon; + + while (($semiColon = $phpcsFile->findNext(array(T_SEMICOLON), ($semiColon + 1), $closeTag)) !== false) { + $lastSemiColon = $semiColon; + $semiColonCount++; + } + + $semiColon = $lastSemiColon; + $error = ''; + + // Make sure there is atleast 1 semicolon. + if ($semiColonCount === 0) { + $error = 'Inline PHP statement must end with a semicolon'; + $phpcsFile->addError($error, $stackPtr, 'NoSemicolon'); + return; + } + + // Make sure that there aren't more semicolons than are allowed. + if ($semiColonCount > 1) { + $error = 'Inline PHP statement must contain one statement per line; %s found'; + $data = array($semiColonCount); + $phpcsFile->addError($error, $stackPtr, 'MultipleStatements', $data); + } + + // The statement contains only 1 semicolon, now it must be spaced properly. + $whitespace = ''; + for ($i = ($semiColon + 1); $i < $closeTag; $i++) { + if ($tokens[$i]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before closing PHP tag; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeClose'); + return; + } + + $whitespace .= $tokens[$i]['content']; + } + + if (strlen($whitespace) === 1) { + return; + } + + if (strlen($whitespace) === 0) { + $error = 'Expected 1 space before closing PHP tag; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeClose'); + } else { + $error = 'Expected 1 space before closing PHP tag; %s found'; + $data = array(strlen($whitespace)); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose', $data); + } + + }//end _validateInlineEmbeddedPhp() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php new file mode 100644 index 000000000..05c2f397f --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php @@ -0,0 +1,65 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_EvalSniff. + * + * The use of eval() is discouraged. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_EvalSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_EVAL); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $error = 'Use of eval() is discouraged'; + $phpcsFile->addWarning($error, $stackPtr, 'Discouraged'); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php new file mode 100644 index 000000000..1bbdcaabe --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php @@ -0,0 +1,71 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found'); +} + +/** + * Squiz_Sniffs_PHP_ForbiddenFunctionsSniff. + * + * Discourages the use of alias functions that are kept in PHP for compatibility + * with older versions. Can be used to forbid the use of any function. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_ForbiddenFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff +{ + + /** + * A list of forbidden functions with their alternatives. + * + * The value is NULL if no alternative exists. IE, the + * function should just not be used. + * + * @var array(string => string|null) + */ + protected $forbiddenFunctions = array( + 'sizeof' => 'count', + 'delete' => 'unset', + 'print' => 'echo', + 'is_null' => null, + 'create_function' => null, + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + $tokens = parent::register(); + $tokens[] = T_PRINT; + return $tokens; + + }//end register() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php new file mode 100644 index 000000000..6b6887411 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php @@ -0,0 +1,70 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_GlobalKeywordSniff. + * + * Stops the usage of the "global" keyword. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_GlobalKeywordSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_GLOBAL); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $nextVar = $tokens[$phpcsFile->findNext(array(T_VARIABLE), $stackPtr)]; + $varName = str_replace('$', '', $nextVar['content']); + $error = 'Use of the "global" keyword is forbidden; use "$GLOBALS[\'%s\']" instead'; + $data = array($varName); + $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php new file mode 100644 index 000000000..165ad804b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php @@ -0,0 +1,68 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_HeredocSniff. + * + * Heredocs are prohibited. This test enforces that. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_HeredocSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_START_HEREDOC, + T_START_NOWDOC, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $error = 'Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead'; + $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php new file mode 100644 index 000000000..57f23b4e9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php @@ -0,0 +1,75 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_InnerFunctionsSniff. + * + * Ensures that functions within functions are never used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_InnerFunctionsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_EQUAL) { + // Ignore closures. + return; + } + + $error = 'The use of inner functions is forbidden'; + $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php new file mode 100644 index 000000000..fba533ce4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php @@ -0,0 +1,115 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff. + * + * Ensures all calls to inbuilt PHP functions are lowercase. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Make sure this is a function call. + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($next === false) { + // Not a function call. + return; + } + + if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { + // Not a function call. + return; + } + + $prev = $phpcsFile->findPrevious(array(T_WHITESPACE, T_BITWISE_AND), ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_FUNCTION) { + // Function declaration, not a function call. + return; + } + + if ($tokens[$prev]['code'] === T_NEW) { + // Object creation, not an inbuilt function. + return; + } + + if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR) { + // Not an inbuilt function. + return; + } + + if ($tokens[$prev]['code'] === T_DOUBLE_COLON) { + // Not an inbuilt function. + return; + } + + // Make sure it is an inbuilt PHP function. + // PHP_CodeSniffer doesn't include/require any files, so no + // user defined global functions can exist, except for + // PHP_CodeSniffer ones. + $content = $tokens[$stackPtr]['content']; + if (function_exists($content) === false) { + return; + } + + if ($content !== strtolower($content)) { + $error = 'Calls to inbuilt PHP functions must be lowercase; expected "%s" but found "%s"'; + $data = array( + strtolower($content), + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'CallUppercase', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php new file mode 100644 index 000000000..1f35bbcd0 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php @@ -0,0 +1,272 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_PHP_NonExecutableCodeSniff. + * + * Warns about code that can never been executed. This happens when a function + * returns before the code, or a break ends execution of a statement etc. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_PHP_NonExecutableCodeSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_BREAK, + T_CONTINUE, + T_RETURN, + T_THROW, + T_EXIT, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If this token is preceded with an "or", it only relates to one line + // and should be ignored. For example: fopen() or die(). + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_LOGICAL_OR) { + return; + } + + // Check if this token is actually part of a one-line IF or ELSE statement. + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { + $i = $tokens[$i]['parenthesis_opener']; + continue; + } else if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } + + break; + } + + if ($tokens[$i]['code'] === T_IF + || $tokens[$i]['code'] === T_ELSE + || $tokens[$i]['code'] === T_ELSEIF + ) { + return; + } + + if ($tokens[$stackPtr]['code'] === T_RETURN) { + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === T_SEMICOLON) { + $next = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); + if ($tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { + // If this is the closing brace of a function + // then this return statement doesn't return anything + // and is not required anyway. + $owner = $tokens[$next]['scope_condition']; + if ($tokens[$owner]['code'] === T_FUNCTION) { + $warning = 'Empty return statement not required here'; + $phpcsFile->addWarning($warning, $stackPtr, 'ReturnNotRequired'); + return; + } + } + } + } + + if (isset($tokens[$stackPtr]['scope_opener']) === true) { + $owner = $tokens[$stackPtr]['scope_condition']; + if ($tokens[$owner]['code'] === T_CASE || $tokens[$owner]['code'] === T_DEFAULT) { + // This token closes the scope of a CASE or DEFAULT statement + // so any code between this token and the next CASE, DEFAULT or + // end of SWITCH token will not be executable. + $next = $phpcsFile->findNext( + array( + T_CASE, + T_DEFAULT, + T_CLOSE_CURLY_BRACKET, + ), + ($stackPtr + 1) + ); + + if ($next !== false) { + $end = $phpcsFile->findNext(array(T_SEMICOLON), ($stackPtr + 1)); + $lastLine = $tokens[$end]['line']; + for ($i = ($stackPtr + 1); $i < $next; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + continue; + } + + $line = $tokens[$i]['line']; + if ($line > $lastLine) { + $type = substr($tokens[$stackPtr]['type'], 2); + $warning = 'Code after %s statement cannot be executed'; + $data = array($type); + $phpcsFile->addWarning($warning, $i, 'Unreachable', $data); + $lastLine = $line; + } + } + }//end if + + // That's all we have to check for these types of statements. + return; + } + }//end if + + // This token may be part of an inline condition. + // If we find a closing parenthesis that belongs to a condition + // we should ignore this token. + $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if (isset($tokens[$prev]['parenthesis_owner']) === true) { + $owner = $tokens[$prev]['parenthesis_owner']; + $ignore = array( + T_IF, + T_ELSE, + T_ELSEIF, + ); + if (in_array($tokens[$owner]['code'], $ignore) === true) { + return; + } + } + + $ourConditions = array_keys($tokens[$stackPtr]['conditions']); + + if (empty($ourConditions) === false) { + $condition = array_pop($ourConditions); + + if (isset($tokens[$condition]['scope_closer']) === false) { + return; + } + + // Special case for BREAK statements sitting directly inside SWITCH + // statements. If we get to this point, we know the BREAK is not being + // used to close a CASE statement, so it is most likely non-executable + // code itself (as is the case when you put return; break; at the end of + // a case). So we need to ignore this token. + if ($tokens[$condition]['code'] === T_SWITCH + && $tokens[$stackPtr]['code'] === T_BREAK + ) { + return; + } + + $closer = $tokens[$condition]['scope_closer']; + + // If the closer for our condition is shared with other openers, + // we will need to throw errors from this token to the next + // shared opener (if there is one), not to the scope closer. + $nextOpener = null; + for ($i = ($stackPtr + 1); $i < $closer; $i++) { + if (isset($tokens[$i]['scope_closer']) === true) { + if ($tokens[$i]['scope_closer'] === $closer) { + // We found an opener that shares the same + // closing token as us. + $nextOpener = $i; + break; + } + } + }//end for + + if ($nextOpener === null) { + $end = $closer; + } else { + $end = ($nextOpener - 1); + } + } else { + // This token is in the global scope. + if ($tokens[$stackPtr]['code'] === T_BREAK) { + return; + } + + // Throw an error for all lines until the end of the file. + $end = ($phpcsFile->numTokens - 1); + }//end if + + // Find the semicolon that ends this statement, skipping + // nested statements like FOR loops and closures. + for ($start = ($stackPtr + 1); $start < $phpcsFile->numTokens; $start++) { + if ($start === $end) { + break; + } + + if ($tokens[$start]['code'] === T_OPEN_PARENTHESIS) { + $start = $tokens[$start]['parenthesis_closer']; + continue; + } + + if ($tokens[$start]['code'] === T_OPEN_CURLY_BRACKET) { + $start = $tokens[$start]['bracket_closer']; + continue; + } + + if ($tokens[$start]['code'] === T_SEMICOLON) { + break; + } + }//end for + + $lastLine = $tokens[$start]['line']; + for ($i = ($start + 1); $i < $end; $i++) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true + || in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$bracketTokens) === true + ) { + continue; + } + + // Skip whole functions and classes/interfaces because they are not + // technically executed code, but rather declarations that may be used. + if ($tokens[$i]['code'] === T_FUNCTION + || $tokens[$i]['code'] === T_CLASS + || $tokens[$i]['code'] === T_INTERFACE + ) { + $i = $tokens[$i]['scope_closer']; + continue; + } + + $line = $tokens[$i]['line']; + if ($line > $lastLine) { + $type = substr($tokens[$stackPtr]['type'], 2); + $warning = 'Code after %s statement cannot be executed'; + $data = array($type); + $phpcsFile->addWarning($warning, $i, 'Unreachable', $data); + $lastLine = $line; + } + }//end for + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php new file mode 100644 index 000000000..f70b30286 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php @@ -0,0 +1,90 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +/** + * Verifies that class members have scope modifiers. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Scope_MemberVarScopeSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); + + if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { + $error = 'Scope modifier not specified for member variable "%s"'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + } + + }//end processMemberVar() + + + /** + * Processes normal variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariable() + + + /** + * Processes variables in double quoted strings. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php new file mode 100644 index 000000000..0bfec5289 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php @@ -0,0 +1,77 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * Verifies that class members have scope modifiers. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Scope_MethodScopeSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION)); + + }//end __construct() + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * @param int $currScope The current scope opener token. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $tokens = $phpcsFile->getTokens(); + + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Ignore closures. + return; + } + + $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); + if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { + $error = 'Visibility must be declared on method "%s"'; + $data = array($methodName); + $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + } + + }//end processTokenWithinScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php new file mode 100644 index 000000000..aab654789 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php @@ -0,0 +1,99 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * Squiz_Sniffs_Scope_StaticThisUsageSniff. + * + * Checks for usage of "$this" in static methods, which will cause + * runtime errors. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Scope_StaticThisUsageSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + + /** + * Constructs the test with the tokens it wishes to listen for. + * + * @return void + */ + public function __construct() + { + parent::__construct(array(T_CLASS), array(T_FUNCTION)); + + }//end __construct() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * @param int $currScope A pointer to the start of the scope. + * + * @return void + */ + public function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $tokens = $phpcsFile->getTokens(); + $function = $tokens[($stackPtr + 2)]; + + if ($function['code'] !== T_STRING) { + return; + } + + $functionName = $function['content']; + $classOpener = $tokens[$currScope]['scope_condition']; + $className = $tokens[($classOpener + 2)]['content']; + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + + if ($methodProps['is_static'] === true) { + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + // There is no scope opener or closer, so the function + // must be abstract. + return; + } + + $thisUsage = $stackPtr; + while (($thisUsage = $phpcsFile->findNext(array(T_VARIABLE), ($thisUsage + 1), $tokens[$stackPtr]['scope_closer'], false, '$this')) !== false) { + if ($thisUsage === false) { + return; + } + + $error = 'Usage of "$this" in static methods will cause runtime errors'; + $phpcsFile->addError($error, $thisUsage, 'Found'); + } + }//end if + + }//end processTokenWithinScope() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php new file mode 100644 index 000000000..68d858d97 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php @@ -0,0 +1,71 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Strings_ConcatenationSpacingSniff. + * + * Makes sure there are no spaces between the concatenation operator (.) and + * the strings being concatenated. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Strings_ConcatenationSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING_CONCAT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE + || $tokens[($stackPtr + 1)]['code'] === T_WHITESPACE + ) { + $message = 'Concat operator must not be surrounded by spaces'; + $phpcsFile->addError($message, $stackPtr, 'Missing'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php new file mode 100644 index 000000000..44bdd7ddf --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php @@ -0,0 +1,135 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Strings_DoubleQuoteUsageSniff. + * + * Makes sure that any use of Double Quotes ("") are warranted. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Strings_DoubleQuoteUsageSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CONSTANT_ENCAPSED_STRING, + T_DOUBLE_QUOTED_STRING, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // We are only interested in the first token in a multi-line string. + if ($tokens[$stackPtr]['code'] === $tokens[($stackPtr - 1)]['code']) { + return; + } + + $workingString = $tokens[$stackPtr]['content']; + $i = ($stackPtr + 1); + while ($tokens[$i]['code'] === $tokens[$stackPtr]['code']) { + $workingString .= $tokens[$i]['content']; + $i++; + } + + // Check if it's a double quoted string. + if (strpos($workingString, '"') === false) { + return; + } + + // Make sure it's not a part of a string started in a previous line. + // If it is, then we have already checked it. + if ($workingString[0] !== '"') { + return; + } + + // The use of variables in double quoted strings is not allowed. + if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING) { + $stringTokens = token_get_all('addError($error, $stackPtr, 'ContainsVar', $data); + } + } + + return; + }//end if + + // Work through the following tokens, in case this string is stretched + // over multiple Lines. + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['type'] !== 'T_CONSTANT_ENCAPSED_STRING') { + break; + } + + $workingString .= $tokens[$i]['content']; + } + + $allowedChars = array( + '\0', + '\n', + '\r', + '\f', + '\t', + '\v', + '\x', + '\'', + ); + + foreach ($allowedChars as $testChar) { + if (strpos($workingString, $testChar) !== false) { + return; + } + } + + $error = 'String %s does not require double quotes; use single quotes instead'; + $data = array($workingString); + $phpcsFile->addError($error, $stackPtr, 'NotRequired', $data); + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php new file mode 100644 index 000000000..2f4d283ee --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php @@ -0,0 +1,84 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Strings_EchoedStringsSniff. + * + * Makes sure that any strings that are "echoed" are not enclosed in brackets + * like a function call. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_Strings_EchoedStringsSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_ECHO); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $firstContent = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); + // If the first non-whitespace token is not an opening parenthesis, then we are not concerned. + if ($tokens[$firstContent]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $endOfStatement = $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr, null, false); + + // If the token before the semi-colon is not a closing parenthesis, then we are not concerned. + if ($tokens[($endOfStatement - 1)]['code'] !== T_CLOSE_PARENTHESIS) { + return; + } + + if (($phpcsFile->findNext(PHP_CodeSniffer_Tokens::$operators, $stackPtr, $endOfStatement, false)) === false) { + // There are no arithmetic operators in this. + $error = 'Echoed strings should not be bracketed'; + $phpcsFile->addError($error, $stackPtr, 'HasBracket'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php new file mode 100644 index 000000000..79da3af0e --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php @@ -0,0 +1,77 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_CastSpacingSniff. + * + * Ensure cast statements don't contain whitespace. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_CastSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$castTokens; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $content = $tokens[$stackPtr]['content']; + $expected = str_replace(' ', '', $content); + $expected = str_replace("\t", '', $expected); + + if ($content !== $expected) { + $error = 'Cast statements must not contain whitespace; expected "%s" but found "%s"'; + $data = array( + $expected, + $content, + ); + $phpcsFile->addError($error, $stackPtr, 'ContainsWhiteSpace', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php new file mode 100644 index 000000000..ecf6dfed7 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -0,0 +1,209 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff. + * + * Checks that control structures have the correct spacing around brackets. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_IF, + T_WHILE, + T_FOREACH, + T_FOR, + T_SWITCH, + T_DO, + T_ELSE, + T_ELSEIF, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + return; + } + + if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { + $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; + $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; + if ($tokens[($parenOpener + 1)]['code'] === T_WHITESPACE) { + $gap = strlen($tokens[($parenOpener + 1)]['content']); + $error = 'Expected 0 spaces after opening bracket; %s found'; + $data = array($gap); + $phpcsFile->addError($error, ($parenOpener + 1), 'SpacingAfterOpenBrace', $data); + } + + if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line'] + && $tokens[($parenCloser - 1)]['code'] === T_WHITESPACE + ) { + $gap = strlen($tokens[($parenCloser - 1)]['content']); + $error = 'Expected 0 spaces before closing bracket; %s found'; + $data = array($gap); + $phpcsFile->addError($error, ($parenCloser - 1), 'SpaceBeforeCloseBrace', $data); + } + }//end if + + $scopeOpener = $tokens[$stackPtr]['scope_opener']; + $scopeCloser = $tokens[$stackPtr]['scope_closer']; + + $firstContent = $phpcsFile->findNext( + T_WHITESPACE, + ($scopeOpener + 1), + null, + true + ); + + if ($tokens[$firstContent]['line'] !== ($tokens[$scopeOpener]['line'] + 1)) { + $error = 'Blank line found at start of control structure'; + $phpcsFile->addError($error, $scopeOpener, 'SpacingBeforeOpen'); + } + + $lastContent = $phpcsFile->findPrevious( + T_WHITESPACE, + ($scopeCloser - 1), + null, + true + ); + + if ($tokens[$lastContent]['line'] !== ($tokens[$scopeCloser]['line'] - 1)) { + $errorToken = $scopeCloser; + for ($i = ($scopeCloser - 1); $i > $lastContent; $i--) { + if ($tokens[$i]['line'] < $tokens[$scopeCloser]['line']) { + $errorToken = $i; + break; + } + } + + $error = 'Blank line found at end of control structure'; + $phpcsFile->addError($error, $errorToken, 'SpacingAfterClose'); + } + + $trailingContent = $phpcsFile->findNext( + T_WHITESPACE, + ($scopeCloser + 1), + null, + true + ); + + if ($tokens[$trailingContent]['code'] === T_ELSE) { + if ($tokens[$stackPtr]['code'] === T_IF) { + // IF with ELSE. + return; + } + } + + if ($tokens[$trailingContent]['code'] === T_COMMENT) { + if ($tokens[$trailingContent]['line'] === $tokens[$scopeCloser]['line']) { + if (substr($tokens[$trailingContent]['content'], 0, 5) === '//end') { + // There is an end comment, so we have to get the next piece + // of content. + $trailingContent = $phpcsFile->findNext( + T_WHITESPACE, + ($trailingContent + 1), + null, + true + ); + } + } + } + + // If this token is closing a CASE or DEFAULT, we don't need the + // blank line after this control structure. + if (isset($tokens[$trailingContent]['scope_condition']) === true) { + $condition = $tokens[$trailingContent]['scope_condition']; + if ($tokens[$condition]['code'] === T_CASE + || $tokens[$condition]['code'] === T_DEFAULT + ) { + return; + } + } + + if ($tokens[$trailingContent]['code'] === T_CLOSE_TAG) { + // At the end of the script or embedded code. + return; + } + + if ($tokens[$trailingContent]['code'] === T_CLOSE_CURLY_BRACKET) { + // Another control structure's closing brace. + if (isset($tokens[$trailingContent]['scope_condition']) === true) { + $owner = $tokens[$trailingContent]['scope_condition']; + if ($tokens[$owner]['code'] === T_FUNCTION) { + // The next content is the closing brace of a function + // so normal function rules apply and we can ignore it. + return; + } + } + + if ($tokens[$trailingContent]['line'] !== ($tokens[$scopeCloser]['line'] + 1)) { + $error = 'Blank line found after control structure'; + $phpcsFile->addError($error, $scopeCloser, 'LineAfterClose'); + } + } else { + if ($tokens[$trailingContent]['line'] === ($tokens[$scopeCloser]['line'] + 1)) { + $error = 'No blank line found after control structure'; + $phpcsFile->addError($error, $scopeCloser, 'NoLineAfterClose'); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php new file mode 100644 index 000000000..1ff04d789 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php @@ -0,0 +1,116 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff. + * + * Checks that there is one empty line before the closing brace of a function. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + // Probably an interface method. + return; + } + + $closeBrace = $tokens[$stackPtr]['scope_closer']; + $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true); + + // Special case for empty JS functions + if ($phpcsFile->tokenizerType === 'JS' && $prevContent === $tokens[$stackPtr]['scope_opener']) { + // In this case, the opening and closing brace must be + // right next to each other. + if ($tokens[$stackPtr]['scope_closer'] !== ($tokens[$stackPtr]['scope_opener'] + 1)) { + $error = 'The opening and closing braces of empty functions must be directly next to each other; e.g., function () {}'; + $phpcsFile->addError($error, $closeBrace, 'SpacingBetween'); + } + + return; + } + + $braceLine = $tokens[$closeBrace]['line']; + $prevLine = $tokens[$prevContent]['line']; + + $found = ($braceLine - $prevLine - 1); + if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + // Nested function. + if ($found < 0) { + $error = 'Closing brace of nested function must be on a new line'; + $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose'); + } else if ($found > 0) { + $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; + $data = array($found); + $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); + } + } else { + if ($found !== 1) { + $error = 'Expected 1 blank line before closing function brace; %s found'; + $data = array($found); + $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php new file mode 100644 index 000000000..e2c17fecb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php @@ -0,0 +1,127 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff. + * + * Checks that there is no empty line after the opening brace of a function. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_opener']) === false) { + // Probably an interface method. + return; + } + + $openBrace = $tokens[$stackPtr]['scope_opener']; + $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($openBrace + 1), null, true); + + if ($nextContent === $tokens[$stackPtr]['scope_closer']) { + // The next bit of content is the closing brace, so this + // is an empty function and should have a blank line + // between the opening and closing braces. + return; + } + + $braceLine = $tokens[$openBrace]['line']; + $nextLine = $tokens[$nextContent]['line']; + + $found = ($nextLine - $braceLine - 1); + if ($found > 0) { + $error = 'Expected 0 blank lines after opening function brace; %s found'; + $data = array($found); + $phpcsFile->addError($error, $openBrace, 'SpacingAfter', $data); + } + + if ($phpcsFile->tokenizerType === 'JS') { + // Do some additional checking before the function brace. + $nestedFunction = ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true); + + $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; + $lineDifference = ($braceLine - $functionLine); + + if ($nestedFunction === true) { + if ($lineDifference > 0) { + $error = 'Opening brace should be on the same line as the function keyword'; + $phpcsFile->addError($error, $openBrace, 'SpacingAfterNested'); + } + } else { + if ($lineDifference === 0) { + $error = 'Opening brace should be on a new line'; + $phpcsFile->addError($error, $openBrace, 'ContentBefore'); + return; + } + + if ($lineDifference > 1) { + $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; + $data = array(($lineDifference - 1)); + $phpcsFile->addError($error, $openBrace, 'SpacingBefore', $data); + return; + } + }//end if + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php new file mode 100644 index 000000000..6f53e17f4 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php @@ -0,0 +1,193 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff. + * + * Checks the separation between methods in a class or interface. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The number of blank lines between functions. + * + * @var int + */ + public $spacing = 2; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this sniff when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $this->spacing = (int) $this->spacing; + + /* + Check the number of blank lines + after the function. + */ + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + // Must be an interface method, so the closer is the semi-colon. + $closer = $phpcsFile->findNext(T_SEMICOLON, $stackPtr); + } else { + $closer = $tokens[$stackPtr]['scope_closer']; + } + + $nextLineToken = null; + for ($i = $closer; $i < $phpcsFile->numTokens; $i++) { + if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { + continue; + } else { + $nextLineToken = ($i + 1); + break; + } + } + + if (is_null($nextLineToken) === true) { + // Never found the next line, which means + // there are 0 blank lines after the function. + $foundLines = 0; + } else { + $nextContent = $phpcsFile->findNext(array(T_WHITESPACE), ($nextLineToken + 1), null, true); + if ($nextContent === false) { + // We are at the end of the file. + $foundLines = 0; + } else { + $foundLines = ($tokens[$nextContent]['line'] - $tokens[$nextLineToken]['line']); + } + } + + if ($foundLines !== $this->spacing) { + $error = 'Expected %s blank line'; + if ($this->spacing !== 1) { + $error .= 's'; + } + + $error .= ' after function; %s found'; + $data = array( + $this->spacing, + $foundLines, + ); + $phpcsFile->addError($error, $closer, 'After', $data); + } + + /* + Check the number of blank lines + before the function. + */ + + $prevLineToken = null; + for ($i = $stackPtr; $i > 0; $i--) { + if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { + continue; + } else { + $prevLineToken = $i; + break; + } + } + + if (is_null($prevLineToken) === true) { + // Never found the previous line, which means + // there are 0 blank lines before the function. + $foundLines = 0; + } else { + $prevContent = $phpcsFile->findPrevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevLineToken, null, true); + + // Before we throw an error, check that we are not throwing an error + // for another function. We don't want to error for no blank lines after + // the previous function and no blank lines before this one as well. + $currentLine = $tokens[$stackPtr]['line']; + $prevLine = ($tokens[$prevContent]['line'] - 1); + $i = ($stackPtr - 1); + $foundLines = 0; + while ($currentLine != $prevLine && $currentLine > 1 && $i > 0) { + if (isset($tokens[$i]['scope_condition']) === true) { + $scopeCondition = $tokens[$i]['scope_condition']; + if ($tokens[$scopeCondition]['code'] === T_FUNCTION) { + // Found a previous function. + return; + } + } else if ($tokens[$i]['code'] === T_FUNCTION) { + // Found another interface function. + return; + } + + $currentLine = $tokens[$i]['line']; + if ($currentLine === $prevLine) { + break; + } + + if ($tokens[($i - 1)]['line'] < $currentLine && $tokens[($i + 1)]['line'] > $currentLine) { + // This token is on a line by itself. If it is whitespace, the line is empty. + if ($tokens[$i]['code'] === T_WHITESPACE) { + $foundLines++; + } + } + + $i--; + }//end while + }//end if + + if ($foundLines !== $this->spacing) { + $error = 'Expected %s blank line'; + if ($this->spacing !== 1) { + $error .= 's'; + } + + $error .= ' before function; %s found'; + $data = array( + $this->spacing, + $foundLines, + ); + $phpcsFile->addError($error, $stackPtr, 'Before', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php new file mode 100644 index 000000000..d7888a3af --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php @@ -0,0 +1,96 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff. + * + * Ensures all language constructs (without brackets) contain a + * single space between themselves and their content. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_ECHO, + T_PRINT, + T_RETURN, + T_INCLUDE, + T_INCLUDE_ONCE, + T_REQUIRE, + T_REQUIRE_ONCE, + T_NEW, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] === T_SEMICOLON) { + // No content for this language construct. + return; + } + + if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { + $content = $tokens[($stackPtr + 1)]['content']; + $contentLength = strlen($content); + if ($contentLength !== 1) { + $error = 'Language constructs must be followed by a single space; expected 1 space but found %s'; + $data = array($contentLength); + $phpcsFile->addError($error, $stackPtr, 'IncorrectSingle', $data); + } + } else { + $error = 'Language constructs must be followed by a single space; expected "%s" but found "%s"'; + $data = array( + $tokens[$stackPtr]['content'].' '.$tokens[($stackPtr + 1)]['content'], + $tokens[$stackPtr]['content'].$tokens[($stackPtr + 1)]['content'], + ); + $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php new file mode 100644 index 000000000..804b59772 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php @@ -0,0 +1,106 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff. + * + * Verifies that operators have valid spacing surrounding them. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$booleanOperators; + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check there is one space before the operator. + if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before logical operator; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore'); + } else { + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$stackPtr]['line'] === $tokens[$prev]['line'] + && strlen($tokens[($stackPtr - 1)]['content']) !== 1 + ) { + $found = strlen($tokens[($stackPtr - 1)]['content']); + $error = 'Expected 1 space before logical operator; %s found'; + $data = array($found); + $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceBefore', $data); + } + } + + // Check there is one space after the operator. + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after logical operator; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter'); + } else { + $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($tokens[$stackPtr]['line'] === $tokens[$next]['line'] + && strlen($tokens[($stackPtr + 1)]['content']) !== 1 + ) { + $found = strlen($tokens[($stackPtr + 1)]['content']); + $error = 'Expected 1 space after logical operator; %s found'; + $data = array($found); + $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceAfter', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php new file mode 100644 index 000000000..a108c48e6 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php @@ -0,0 +1,120 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +/** + * Verifies that class members are spaced correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + + /** + * Processes the function tokens within the class. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // There needs to be 1 blank line before the var, not counting comments. + $prevLineToken = null; + for ($i = ($stackPtr - 1); $i > 0; $i--) { + if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + // Skip comments. + continue; + } else if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { + // Not the end of the line. + continue; + } else { + // If this is a WHITESPACE token, and the token right before + // it is a DOC_COMMENT, then it is just the newline after the + // member var's comment, and can be skipped. + if ($tokens[$i]['code'] === T_WHITESPACE && in_array($tokens[($i - 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { + continue; + } + + $prevLineToken = $i; + break; + } + } + + if (is_null($prevLineToken) === true) { + // Never found the previous line, which means + // there are 0 blank lines before the member var. + $foundLines = 0; + } else { + $prevContent = $phpcsFile->findPrevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevLineToken, null, true); + $foundLines = ($tokens[$prevLineToken]['line'] - $tokens[$prevContent]['line']); + }//end if + + if ($foundLines !== 1) { + $error = 'Expected 1 blank line before member var; %s found'; + $data = array($foundLines); + $phpcsFile->addError($error, $stackPtr, 'After', $data); + } + + }//end processMemberVar() + + + /** + * Processes normal variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariable() + + + /** + * Processes variables in double quoted strings. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. + * @param int $stackPtr The position where the token was found. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // We don't care about normal variables. + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php new file mode 100644 index 000000000..c70e0c5bb --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php @@ -0,0 +1,76 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff. + * + * Ensure there is no whitespace before a semicolon. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OBJECT_OPERATOR); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevType = $tokens[($stackPtr - 1)]['code']; + if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $error = 'Space found before object operator'; + $phpcsFile->addError($error, $stackPtr, 'Before'); + } + + $nextType = $tokens[($stackPtr + 1)]['code']; + if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $error = 'Space found after object operator'; + $phpcsFile->addError($error, $stackPtr, 'After'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php new file mode 100644 index 000000000..d84768b1a --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php @@ -0,0 +1,220 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff. + * + * Verifies that operators have valid spacing surrounding them. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + $comparison = PHP_CodeSniffer_Tokens::$comparisonTokens; + $operators = PHP_CodeSniffer_Tokens::$operators; + $assignment = PHP_CodeSniffer_Tokens::$assignmentTokens; + $inlineIf = array( + T_INLINE_THEN, + T_INLINE_ELSE, + ); + + return array_unique( + array_merge($comparison, $operators, $assignment, $inlineIf) + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Skip default values in function declarations. + if ($tokens[$stackPtr]['code'] === T_EQUAL + || $tokens[$stackPtr]['code'] === T_MINUS + ) { + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']); + $bracket = array_pop($parenthesis); + if (isset($tokens[$bracket]['parenthesis_owner']) === true) { + $function = $tokens[$bracket]['parenthesis_owner']; + if ($tokens[$function]['code'] === T_FUNCTION + || $tokens[$function]['code'] === T_CLOSURE + ) { + return; + } + } + } + } + + if ($tokens[$stackPtr]['code'] === T_EQUAL) { + // Skip for '=&' case. + if (isset($tokens[($stackPtr + 1)]) === true && $tokens[($stackPtr + 1)]['code'] === T_BITWISE_AND) { + return; + } + } + + if ($tokens[$stackPtr]['code'] === T_BITWISE_AND) { + // If it's not a reference, then we expect one space either side of the + // bitwise operator. + if ($phpcsFile->isReference($stackPtr) === true) { + return; + } + + // Check there is one space before the & operator. + if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space before "&" operator; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeAmp'); + } else { + if (strlen($tokens[($stackPtr - 1)]['content']) !== 1) { + $found = strlen($tokens[($stackPtr - 1)]['content']); + $error = 'Expected 1 space before "&" operator; %s found'; + $data = array($found); + $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeAmp', $data); + } + } + + // Check there is one space after the & operator. + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after "&" operator; 0 found'; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterAmp'); + } else { + if (strlen($tokens[($stackPtr + 1)]['content']) !== 1) { + $found = strlen($tokens[($stackPtr + 1)]['content']); + $error = 'Expected 1 space after "&" operator; %s found'; + $data = array($found); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfterAmp', $data); + } + } + + return; + }//end if + + if ($tokens[$stackPtr]['code'] === T_MINUS) { + // Check minus spacing, but make sure we aren't just assigning + // a minus value or returning one. + $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] === T_RETURN) { + // Just returning a negative value; eg. (return -1). + return; + } + + if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$operators) === true) { + // Just trying to operate on a negative value; eg. ($var * -1). + return; + } + + if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) === true) { + // Just trying to compare a negative value; eg. ($var === -1). + return; + } + + if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { + // Just trying to assign a negative value; eg. ($var = -1). + return; + } + + // A list of tokens that indicate that the token is not + // part of an arithmetic operation. + $invalidTokens = array( + T_COMMA, + T_OPEN_PARENTHESIS, + T_OPEN_SQUARE_BRACKET, + T_DOUBLE_ARROW, + T_COLON, + T_INLINE_THEN, + T_INLINE_ELSE, + T_CASE, + ); + + if (in_array($tokens[$prev]['code'], $invalidTokens) === true) { + // Just trying to use a negative value; eg. myFunction($var, -2). + return; + } + }//end if + + $operator = $tokens[$stackPtr]['content']; + + if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { + $error = "Expected 1 space before \"$operator\"; 0 found"; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore'); + } else if (strlen($tokens[($stackPtr - 1)]['content']) !== 1) { + // Don't throw an error for assignments, because other standards allow + // multiple spaces there to align multiple assignments. + if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === false) { + $found = strlen($tokens[($stackPtr - 1)]['content']); + $error = 'Expected 1 space before "%s"; %s found'; + $data = array( + $operator, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); + } + } + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $error = "Expected 1 space after \"$operator\"; 0 found"; + $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter'); + } else if (strlen($tokens[($stackPtr + 1)]['content']) !== 1) { + $found = strlen($tokens[($stackPtr + 1)]['content']); + $error = 'Expected 1 space after "%s"; %s found'; + $data = array( + $operator, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'SpacingAfter', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php new file mode 100644 index 000000000..1b5b06ab1 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php @@ -0,0 +1,85 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff. + * + * Ensures that the colon in a property or label definition has a single + * space after it and no space before it. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array('JS'); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_PROPERTY, + T_LABEL, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $colon = $phpcsFile->findNext(T_COLON, ($stackPtr + 1)); + + if ($colon !== ($stackPtr + 1)) { + $error = 'There must be no space before the colon in a property/label declaration'; + $phpcsFile->addError($error, $stackPtr, 'Before'); + } + + if ($tokens[($colon + 1)]['code'] !== T_WHITESPACE || $tokens[($colon + 1)]['content'] !== ' ') { + $error = 'There must be a single space after the colon in a property/label declaration'; + $phpcsFile->addError($error, $stackPtr, 'After'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php new file mode 100644 index 000000000..338806bac --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php @@ -0,0 +1,110 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_Whitespace_ScopeClosingBraceSniff. + * + * Checks that the closing braces of scopes are aligned correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$scopeOpeners; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If this is an inline condition (ie. there is no scope opener), then + // return, as this is not a new scope. + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + return; + } + + // We need to actually find the first piece of content on this line, + // as if this is a method with tokens before it (public, static etc) + // or an if with an else before it, then we need to start the scope + // checking from there, rather than the current token. + $lineStart = ($stackPtr - 1); + for ($lineStart; $lineStart > 0; $lineStart--) { + if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { + break; + } + } + + // We found a new line, now go forward and find the + // first non-whitespace token. + $lineStart = $phpcsFile->findNext(array(T_WHITESPACE), ($lineStart + 1), null, true); + + $startColumn = $tokens[$lineStart]['column']; + $scopeStart = $tokens[$stackPtr]['scope_opener']; + $scopeEnd = $tokens[$stackPtr]['scope_closer']; + + // Check that the closing brace is on it's own line. + $lastContent = $phpcsFile->findPrevious(array(T_WHITESPACE), ($scopeEnd - 1), $scopeStart, true); + if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { + $error = 'Closing brace must be on a line by itself'; + $phpcsFile->addError($error, $scopeEnd, 'ContentBefore'); + return; + } + + // Check now that the closing brace is lined up correctly. + $braceIndent = $tokens[$scopeEnd]['column']; + if (in_array($tokens[$stackPtr]['code'], array(T_CASE, T_DEFAULT)) === false) { + if ($braceIndent !== $startColumn) { + $error = 'Closing brace indented incorrectly; expected %s spaces, found %s'; + $data = array( + ($startColumn - 1), + ($braceIndent - 1), + ); + $phpcsFile->addError($error, $scopeEnd, 'Indent', $data); + } + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php new file mode 100644 index 000000000..76ae3b114 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php @@ -0,0 +1,87 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff. + * + * Ensure there is a single space after scope keywords. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + $register = PHP_CodeSniffer_Tokens::$scopeModifiers; + $register[] = T_STATIC; + return $register; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + + if ($tokens[$stackPtr]['code'] === T_STATIC + && ($tokens[$nextToken]['code'] === T_DOUBLE_COLON + || $tokens[$prevToken]['code'] === T_NEW) + ) { + // Late static binding, e.g., static:: OR new static() usage. + return; + } + + $nextToken = $tokens[($stackPtr + 1)]; + if ($nextToken['code'] !== T_WHITESPACE + || strlen($nextToken['content']) !== 1 + || $nextToken['content'] === $phpcsFile->eolChar + ) { + $error = 'Scope keyword "%s" must be followed by a single space'; + $data = array($tokens[$stackPtr]['content']); + $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php new file mode 100644 index 000000000..84b46e1bc --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php @@ -0,0 +1,86 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff. + * + * Ensure there is no whitespace before a semicolon. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + ); + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_SEMICOLON); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevType = $tokens[($stackPtr - 1)]['code']; + if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $nonSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 2), null, true); + $expected = $tokens[$nonSpace]['content'].';'; + $found = $phpcsFile->getTokensAsString($nonSpace, ($stackPtr - $nonSpace)).';'; + $error = 'Space found before semicolon; expected "%s" but found "%s"'; + $data = array( + $expected, + $found, + ); + $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php new file mode 100644 index 000000000..c653e7758 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php @@ -0,0 +1,231 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff. + * + * Checks that no whitespace proceeds the first content of the file, exists + * after the last content of the file, resides after content on any line, or + * are two empty lines in functions. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * A list of tokenizers this sniff supports. + * + * @var array + */ + public $supportedTokenizers = array( + 'PHP', + 'JS', + 'CSS', + ); + + /** + * If TRUE, whitespace rules are not checked for blank lines. + * + * Blank lines are those that contain only whitespace. + * + * @var boolean + */ + public $ignoreBlankLines = false; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_OPEN_TAG, + T_CLOSE_TAG, + T_WHITESPACE, + T_COMMENT, + ); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { + + /* + Check for start of file whitespace. + */ + + if ($phpcsFile->tokenizerType !== 'PHP') { + // The first token is always the open tag inserted when tokenizsed + // and the second token is always the first piece of content in + // the file. If the second token is whitespace, there was + // whitespace at the start of the file. + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + return; + } + } else { + // If its the first token, then there is no space. + if ($stackPtr === 0) { + return; + } + + for ($i = ($stackPtr - 1); $i >= 0; $i--) { + // If we find something that isn't inline html then there is something previous in the file. + if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { + return; + } + + // If we have ended up with inline html make sure it isn't just whitespace. + $tokenContent = trim($tokens[$i]['content']); + if ($tokenContent !== '') { + return; + } + } + }//end if + + $phpcsFile->addError('Additional whitespace found at start of file', $stackPtr, 'StartFile'); + + } else if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { + + /* + Check for end of file whitespace. + */ + + if ($phpcsFile->tokenizerType === 'JS') { + // The last token is always the close tag inserted when tokenized + // and the second last token is always the last piece of content in + // the file. If the second last token is whitespace, there was + // whitespace at the end of the file. + $stackPtr--; + } else if ($phpcsFile->tokenizerType === 'CSS') { + // The last two tokens are always the close tag and whitespace + // inserted when tokenizsed and the third last token is always the + // last piece of content in the file. If the third last token is + // whitespace, there was whitespace at the end of the file. + $stackPtr -= 2; + } + + if ($phpcsFile->tokenizerType === 'PHP') { + if (isset($tokens[($stackPtr + 1)]) === false) { + // The close PHP token is the last in the file. + return; + } + + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + // If we find something that isn't inline html then there + // is more to the file. + if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { + return; + } + + // If we have ended up with inline html make sure it + // isn't just whitespace. + $tokenContent = trim($tokens[$i]['content']); + if (empty($tokenContent) === false) { + return; + } + } + } else { + // The pointer is now looking at the last content in the file and + // not the fake PHP end tag the tokenizer inserted. + if ($tokens[$stackPtr]['code'] !== T_WHITESPACE) { + return; + } + + // Allow a single newline at the end of the last line in the file. + if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE + && $tokens[$stackPtr]['content'] === $phpcsFile->eolChar + ) { + return; + } + + } + + $phpcsFile->addError('Additional whitespace found at end of file', $stackPtr, 'EndFile'); + + } else { + + /* + Check for end of line whitespace. + */ + + // Ignore whitespace that is not at the end of a line. + if (strpos($tokens[$stackPtr]['content'], $phpcsFile->eolChar) === false) { + return; + } + + // Ignore blank lines if required. + if ($this->ignoreBlankLines === true + && $tokens[($stackPtr - 1)]['line'] !== $tokens[$stackPtr]['line'] + ) { + return; + } + + $tokenContent = rtrim($tokens[$stackPtr]['content'], $phpcsFile->eolChar); + if (empty($tokenContent) === false) { + if (preg_match('|^.*\s+$|', $tokenContent) !== 0) { + $phpcsFile->addError('Whitespace found at end of line', $stackPtr, 'EndLine'); + } + } + + /* + Check for multiple blanks lines in a function. + */ + + if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { + if ($tokens[($stackPtr - 1)]['line'] < $tokens[$stackPtr]['line'] && $tokens[($stackPtr - 2)]['line'] === $tokens[($stackPtr - 1)]['line']) { + // This is an empty line and the line before this one is not + // empty, so this could be the start of a multiple empty + // line block. + $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr, null, true); + $lines = $tokens[$next]['line'] - $tokens[$stackPtr]['line']; + if ($lines > 1) { + $error = 'Functions must not contain multiple empty lines in a row; found %s empty lines'; + $data = array($lines); + $phpcsFile->addError($error, $stackPtr, 'EmptyLines', $data); + } + } + } + + }//end if + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml b/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml new file mode 100644 index 000000000..d8f2dbd4c --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml @@ -0,0 +1,81 @@ + + + The Squiz coding standard. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %2$s + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml new file mode 100644 index 000000000..c462b4f8b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml @@ -0,0 +1,25 @@ + + + + + + + $bar + $baz; +} + ]]> + + + $bar + 2; +} + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml new file mode 100644 index 000000000..aa60b8ab9 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml @@ -0,0 +1,22 @@ + + + + + + + + + + ?> + ]]> + + + diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml new file mode 100644 index 000000000..5bcde4b84 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml @@ -0,0 +1,37 @@ + + + + + + + $testNumber = 1; + ]]> + + + $Test_Number = 1; + ]]> + + + + + _bar; +} + ]]> + + + + + + diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php new file mode 100644 index 000000000..293aecab2 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php @@ -0,0 +1,125 @@ + + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Zend_Sniffs_Debug_CodeAnalyzerSniff. + * + * Runs the Zend Code Analyzer (from Zend Studio) on the file. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Holger Kral + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Zend_Sniffs_Debug_CodeAnalyzerSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns the token types that this sniff is interested in. + * + * @return array(int) + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes the tokens that this sniff is interested in. + * + * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. + * @param int $stackPtr The position in the stack where + * the token was found. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + // Because we are analyzing the whole file in one step, execute this method + // only on first occurrence of a T_OPEN_TAG. + $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($prevOpenTag !== false) { + return; + } + + $fileName = $phpcsFile->getFilename(); + + $analyzerPath = PHP_CodeSniffer::getConfigData('zend_ca_path'); + if (is_null($analyzerPath) === true) { + return; + } + + // In the command, 2>&1 is important because the code analyzer sends its + // findings to stderr. $output normally contains only stdout, so using 2>&1 + // will pipe even stderr to stdout. + $cmd = $analyzerPath.' '.$fileName.' 2>&1'; + + // There is the possibility to pass "--ide" as an option to the analyzer. + // This would result in an output format which would be easier to parse. + // The problem here is that no cleartext error messages are returnwd; only + // error-code-labels. So for a start we go for cleartext output. + $exitCode = exec($cmd, $output, $retval); + + // $exitCode is the last line of $output if no error occures, on error it + // is numeric. Try to handle various error conditions and provide useful + // error reporting. + if (is_numeric($exitCode) === true && $exitCode > 0) { + if (is_array($output) === true) { + $msg = join('\n', $output); + } + + throw new PHP_CodeSniffer_Exception("Failed invoking ZendCodeAnalyzer, exitcode was [$exitCode], retval was [$retval], output was [$msg]"); + } + + if (is_array($output) === true) { + $tokens = $phpcsFile->getTokens(); + + foreach ($output as $finding) { + // The first two lines of analyzer output contain + // something like this: + // > Zend Code Analyzer 1.2.2 + // > Analyzing ... + // So skip these... + $res = preg_match("/^.+\(line ([0-9]+)\):(.+)$/", $finding, $regs); + if (empty($regs) === true || $res === false) { + continue; + } + + // Find the token at the start of the line. + $lineToken = null; + foreach ($tokens as $ptr => $info) { + if ($info['line'] == $regs[1]) { + $lineToken = $ptr; + break; + } + } + + if ($lineToken !== null) { + $phpcsFile->addWarning(trim($regs[2]), $ptr, 'ExternalTool'); + } + }//end foreach + }//end if + + }//end process() + +}//end class +?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php new file mode 100644 index 000000000..a30f106fe --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php @@ -0,0 +1,84 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Zend_Sniffs_Files_LineEndingsSniff. + * + * Checks that the file does not end with a closing tag. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Zend_Sniffs_Files_ClosingTagSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLOSE_TAG); + + }//end register() + + + /** + * Processes this sniff, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $next = $phpcsFile->findNext(T_INLINE_HTML, ($stackPtr + 1), null, true); + if ($next !== false) { + return; + } + + // We've found the last closing tag in the file so the only thing + // potentially remaining is inline HTML. Now we need to figure out + // whether or not it's just a bunch of whitespace. + $content = ''; + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + $content .= $tokens[$i]['content']; + } + + // Check if the remaining inline HTML is just whitespace. + $content = trim($content); + if (empty($content) === true) { + $error = 'A closing tag is not permitted at the end of a PHP file'; + $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); + } + + }//end process() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php new file mode 100644 index 000000000..27928c448 --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -0,0 +1,252 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); +} + +/** + * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. + * + * Checks the naming of variables and member variables. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Zend_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff +{ + + /** + * Tokens to ignore so that we can find a DOUBLE_COLON. + * + * @var array + */ + private $_ignore = array( + T_WHITESPACE, + T_COMMENT, + ); + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $varName = ltrim($tokens[$stackPtr]['content'], '$'); + + $phpReservedVars = array( + '_SERVER', + '_GET', + '_POST', + '_REQUEST', + '_SESSION', + '_ENV', + '_COOKIE', + '_FILES', + 'GLOBALS', + ); + + // If it's a php reserved var, then its ok. + if (in_array($varName, $phpReservedVars) === true) { + return; + } + + $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); + if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { + // Check to see if we are using a variable from an object. + $var = $phpcsFile->findNext(array(T_WHITESPACE), ($objOperator + 1), null, true); + if ($tokens[$var]['code'] === T_STRING) { + // Either a var name or a function call, so check for bracket. + $bracket = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); + + if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { + $objVarName = $tokens[$var]['content']; + + // There is no way for us to know if the var is public or private, + // so we have to ignore a leading underscore if there is one and just + // check the main part of the variable name. + $originalVarName = $objVarName; + if (substr($objVarName, 0, 1) === '_') { + $objVarName = substr($objVarName, 1); + } + + if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); + } else if (preg_match('|\d|', $objVarName)) { + $warning = 'Variable "%s" contains numbers but this is discouraged'; + $data = array($originalVarName); + $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); + } + }//end if + }//end if + }//end if + + // There is no way for us to know if the var is public or private, + // so we have to ignore a leading underscore if there is one and just + // check the main part of the variable name. + $originalVarName = $varName; + if (substr($varName, 0, 1) === '_') { + $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); + if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { + // The variable lives within a class, and is referenced like + // this: MyClass::$_variable, so we don't know its scope. + $inClass = true; + } else { + $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)); + } + + if ($inClass === true) { + $varName = substr($varName, 1); + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); + } else if (preg_match('|\d|', $varName)) { + $warning = 'Variable "%s" contains numbers but this is discouraged'; + $data = array($originalVarName); + $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); + } + + }//end processVariable() + + + /** + * Processes class member variables. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $varName = ltrim($tokens[$stackPtr]['content'], '$'); + $memberProps = $phpcsFile->getMemberProperties($stackPtr); + $public = ($memberProps['scope'] === 'public'); + + if ($public === true) { + if (substr($varName, 0, 1) === '_') { + $error = 'Public member variable "%s" must not contain a leading underscore'; + $data = array($varName); + $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); + return; + } + } else { + if (substr($varName, 0, 1) !== '_') { + $scope = ucfirst($memberProps['scope']); + $error = '%s member variable "%s" must contain a leading underscore'; + $data = array( + $scope, + $varName, + ); + $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); + return; + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($varName); + $phpcsFile->addError($error, $stackPtr, 'MemberVarNotCamelCaps', $data); + } else if (preg_match('|\d|', $varName)) { + $warning = 'Variable "%s" contains numbers but this is discouraged'; + $data = array($varName); + $phpcsFile->addWarning($warning, $stackPtr, 'MemberVarContainsNumbers', $data); + } + + }//end processMemberVar() + + + /** + * Processes the variable found within a double quoted string. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the double quoted + * string. + * + * @return void + */ + protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $phpReservedVars = array( + '_SERVER', + '_GET', + '_POST', + '_REQUEST', + '_SESSION', + '_ENV', + '_COOKIE', + '_FILES', + 'GLOBALS', + ); + + if (preg_match_all('|[^\\\]\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { + foreach ($matches[1] as $varName) { + // If it's a php reserved var, then its ok. + if (in_array($varName, $phpReservedVars) === true) { + continue; + } + + // There is no way for us to know if the var is public or private, + // so we have to ignore a leading underscore if there is one and just + // check the main part of the variable name. + $originalVarName = $varName; + if (substr($varName, 0, 1) === '_') { + if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { + $varName = substr($varName, 1); + } + } + + if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { + $varName = $matches[0]; + $error = 'Variable "%s" is not in valid camel caps format'; + $data = array($originalVarName); + $phpcsFile->addError($error, $stackPtr, 'StringVarNotCamelCaps', $data); + } else if (preg_match('|\d|', $varName)) { + $warning = 'Variable "%s" contains numbers but this is discouraged'; + $data = array($originalVarName); + $phpcsFile->addWarning($warning, $stackPtr, 'StringVarContainsNumbers', $data); + } + } + }//end if + + }//end processVariableInString() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml b/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml new file mode 100644 index 000000000..d3031512b --- /dev/null +++ b/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml @@ -0,0 +1,32 @@ + + + A coding standard based on an early Zend Framework coding standard. Note that this standard is out of date. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/codesniffer/CodeSniffer/Tokenizers/CSS.php b/codesniffer/CodeSniffer/Tokenizers/CSS.php new file mode 100644 index 000000000..bbc5c048b --- /dev/null +++ b/codesniffer/CodeSniffer/Tokenizers/CSS.php @@ -0,0 +1,399 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Tokenizers_PHP', true) === false) { + throw new Exception('Class PHP_CodeSniffer_Tokenizers_PHP not found'); +} + +/** + * Tokenizes CSS code. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Tokenizers_CSS extends PHP_CodeSniffer_Tokenizers_PHP +{ + + + /** + * Creates an array of tokens when given some CSS code. + * + * Uses the PHP tokenizer to do all the tricky work + * + * @param string $string The string to tokenize. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return array + */ + public function tokenizeString($string, $eolChar='\n') + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START CSS TOKENIZING ***".PHP_EOL; + } + + // If the content doesn't have an EOl char on the end, add one so + // the open and close tags we add are parsed correctly. + if (substr($string, 0, (strlen($eolChar) * -1)) !== $eolChar) { + $string .= $eolChar; + } + + $tokens = parent::tokenizeString('', $eolChar); + $finalTokens = array(); + + $newStackPtr = 0; + $numTokens = count($tokens); + $multiLineComment = false; + for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { + $token = $tokens[$stackPtr]; + + // CSS files don't have lists or break tags, so convert these to + // standard strings early so they can be converted into T_STYLE + // tokens and joined with other strings if needed. + if ($token['code'] === T_BREAK || $token['code'] === T_LIST) { + $token['type'] = 'T_STRING'; + $token['code'] = T_STRING; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $token['type']; + $content = str_replace($eolChar, '\n', $token['content']); + echo "\tProcess token $stackPtr: $type => $content".PHP_EOL; + } + + // Sometimes, there are PHP tags embedded in the code, which causes issues + // with how PHP tokenizeses the string. After the first closing tag is found, + // everything outside PHP tags is set as inline HTML tokens (1 for each line). + // So we need to go through and find these tokens so we can re-tokenize them. + if ($token['code'] === T_CLOSE_TAG && $stackPtr !== ($numTokens - 1)) { + $content = ''; + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t=> Found premature closing tag at $stackPtr".PHP_EOL; + $cleanContent = str_replace($eolChar, '\n', $content); + echo "\t\tcontent: $cleanContent".PHP_EOL; + $oldNumTokens = $numTokens; + } + + // Tokenize the string and remove the extra PHP tags we don't need. + $moreTokens = parent::tokenizeString($content, $eolChar); + array_shift($moreTokens); + array_pop($moreTokens); + array_pop($moreTokens); + + // Rebuild the tokens array. + array_splice($tokens, ($stackPtr + 1), ($x - $stackPtr), $moreTokens); + $numTokens = count($tokens); + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $count = count($moreTokens); + $diff = ($x - $stackPtr); + echo "\t\t* added $count tokens, replaced $diff; size changed from $oldNumTokens to $numTokens *".PHP_EOL; + } + }//end if + + if ($token['code'] === T_GOTO_LABEL) { + // Convert these back to T_STRING folowed by T_COLON so we can + // more easily process style definitions. + $finalTokens[$newStackPtr] = array( + 'type' => 'T_STRING', + 'code' => T_STRING, + 'content' => substr($token['content'], 0, -1), + ); + $newStackPtr++; + $finalTokens[$newStackPtr] = array( + 'type' => 'T_COLON', + 'code' => T_COLON, + 'content' => ':', + ); + $newStackPtr++; + continue; + } + + if ($token['code'] === T_FUNCTION) { + // There are no functions in CSS, so convert this to a string. + $finalTokens[$newStackPtr] = array( + 'type' => 'T_STRING', + 'code' => T_STRING, + 'content' => $token['content'], + ); + + $newStackPtr++; + continue; + } + + if ($token['code'] === T_COMMENT + && substr($token['content'], 0, 2) === '/*' + ) { + // Multi-line comment. Record it so we can ignore other + // comment tags until we get out of this one. + $multiLineComment = true; + } + + if ($token['code'] === T_COMMENT + && $multiLineComment === false + && (substr($token['content'], 0, 2) === '//' + || $token['content']{0} === '#') + ) { + $content = ltrim($token['content'], '#/'); + $commentTokens + = parent::tokenizeString('', $eolChar); + + // The first and last tokens are the open/close tags. + array_shift($commentTokens); + array_pop($commentTokens); + + if ($token['content']{0} === '#') { + // The # character is not a comment in CSS files, so + // determine what it means in this context. + $firstContent = $commentTokens[0]['content']; + + // If the first content is just a number, it is probably a + // colour like 8FB7DB, which PHP splits into 8 and FB7DB. + if (($commentTokens[0]['code'] === T_LNUMBER + || $commentTokens[0]['code'] === T_DNUMBER) + && $commentTokens[1]['code'] === T_STRING + ) { + $firstContent .= $commentTokens[1]['content']; + array_shift($commentTokens); + } + + // If the first content looks like a colour and not a class + // definition, join the tokens together. + if (preg_match('/^[ABCDEF0-9]+$/i', $firstContent) === 1 + && $commentTokens[1]['content'] !== '-' + ) { + array_shift($commentTokens); + // Work out what we trimmed off above and remember to re-add it. + $trimmed = substr($token['content'], 0, (strlen($token['content']) - strlen($content))); + $finalTokens[$newStackPtr] = array( + 'type' => 'T_COLOUR', + 'code' => T_COLOUR, + 'content' => $trimmed.$firstContent, + ); + } else { + $finalTokens[$newStackPtr] = array( + 'type' => 'T_HASH', + 'code' => T_HASH, + 'content' => '#', + ); + } + } else { + $finalTokens[$newStackPtr] = array( + 'type' => 'T_STRING', + 'code' => T_STRING, + 'content' => '//', + ); + }//end if + + $newStackPtr++; + + foreach ($commentTokens as $tokenData) { + if ($tokenData['code'] === T_COMMENT + && (substr($tokenData['content'], 0, 2) === '//' + || $tokenData['content']{0} === '#') + ) { + // This is a comment in a comment, so it needs + // to go through the whole process again. + $tokens[$stackPtr]['content'] = $tokenData['content']; + $stackPtr--; + break; + } + + $finalTokens[$newStackPtr] = $tokenData; + $newStackPtr++; + } + + continue; + }//end if + + if ($token['code'] === T_COMMENT + && substr($token['content'], -2) === '*/' + ) { + // Multi-line comment is done. + $multiLineComment = false; + } + + $finalTokens[$newStackPtr] = $token; + $newStackPtr++; + }//end for + + // A flag to indicate if we are inside a style definition, + // which is defined using curly braces. I'm assuming you can't + // have nested curly brackets. + $inStyleDef = false; + + $numTokens = count($finalTokens); + for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { + $token = $finalTokens[$stackPtr]; + + switch ($token['code']) { + case T_OPEN_CURLY_BRACKET: + $inStyleDef = true; + break; + case T_CLOSE_CURLY_BRACKET: + $inStyleDef = false; + break; + case T_MINUS: + // Minus signs are often used instead of spaces inside + // class names, IDs and styles. + if ($finalTokens[($stackPtr + 1)]['code'] === T_STRING) { + if ($finalTokens[($stackPtr - 1)]['code'] === T_STRING) { + $newContent = $finalTokens[($stackPtr - 1)]['content'].'-'.$finalTokens[($stackPtr + 1)]['content']; + + $finalTokens[($stackPtr - 1)]['content'] = $newContent; + unset($finalTokens[$stackPtr]); + unset($finalTokens[($stackPtr + 1)]); + $stackPtr -= 2; + } else { + $newContent = '-'.$finalTokens[($stackPtr + 1)]['content']; + + $finalTokens[($stackPtr + 1)]['content'] = $newContent; + unset($finalTokens[$stackPtr]); + $stackPtr--; + } + + $finalTokens = array_values($finalTokens); + $numTokens = count($finalTokens); + } else if ($finalTokens[($stackPtr + 1)]['code'] === T_LNUMBER) { + // They can also be used to provide negative numbers. + $finalTokens[($stackPtr + 1)]['content'] + = '-'.$finalTokens[($stackPtr + 1)]['content']; + unset($finalTokens[$stackPtr]); + + $finalTokens = array_values($finalTokens); + $numTokens = count($finalTokens); + } + + break; + case T_COLON: + // Only interested in colons that are defining styles. + if ($inStyleDef === false) { + break; + } + + for ($x = ($stackPtr - 1); $x >= 0; $x--) { + if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + $finalTokens[$x]['type'] = 'T_STYLE'; + $finalTokens[$x]['code'] = T_STYLE; + break; + case T_STRING: + if (strtolower($token['content']) === 'url') { + // Find the next content. + for ($x = ($stackPtr + 1); $x < $numTokens; $x++) { + if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + // Needs to be in the format "url(" for it to be a URL. + if ($finalTokens[$x]['code'] !== T_OPEN_PARENTHESIS) { + continue; + } + + // Make sure the content isn't empty. + for ($y = ($x + 1); $y < $numTokens; $y++) { + if (in_array($finalTokens[$y]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($finalTokens[$y]['code'] === T_CLOSE_PARENTHESIS) { + continue; + } + + // Join all the content together inside the url() statement. + $newContent = ''; + for ($i = ($x + 2); $i < $numTokens; $i++) { + if ($finalTokens[$i]['code'] === T_CLOSE_PARENTHESIS) { + break; + } + + $newContent .= $finalTokens[$i]['content']; + unset($finalTokens[$i]); + } + + // If the content inside the "url()" is in double quotes + // there will only be one token and so we don't have to do + // anything except change its type. If it is not empty, + // we need to do some token merging. + $finalTokens[($x + 1)]['type'] = 'T_URL'; + $finalTokens[($x + 1)]['code'] = T_URL; + + if ($newContent !== '') { + $finalTokens[($x + 1)]['content'] .= $newContent; + + $finalTokens = array_values($finalTokens); + $numTokens = count($finalTokens); + } + }//end if + + break; + default: + // Nothing special to be done with this token. + break; + }//end switch + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END CSS TOKENIZING ***".PHP_EOL; + } + + return $finalTokens; + + }//end tokenizeString() + + + /** + * Performs additional processing after main tokenizing. + * + * @param array &$tokens The array of tokens to process. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + public function processAdditional(&$tokens, $eolChar) + { + // We override this method because we don't want the PHP version to + // run during CSS processing because it is wasted processing time. + + }//end processAdditional() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Tokenizers/JS.php b/codesniffer/CodeSniffer/Tokenizers/JS.php new file mode 100644 index 000000000..8a6ade6d2 --- /dev/null +++ b/codesniffer/CodeSniffer/Tokenizers/JS.php @@ -0,0 +1,1149 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Tokenizes JS code. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Tokenizers_JS +{ + + /** + * A list of tokens that are allowed to open a scope. + * + * This array also contains information about what kind of token the scope + * opener uses to open and close the scope, if the token strictly requires + * an opener, if the token can share a scope closer, and who it can be shared + * with. An example of a token that shares a scope closer is a CASE scope. + * + * @var array + */ + public $scopeOpeners = array( + T_IF => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_TRY => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_CATCH => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_ELSE => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_FOR => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_FUNCTION => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_WHILE => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_DO => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_SWITCH => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_CASE => array( + 'start' => array(T_COLON), + 'end' => array( + T_BREAK, + T_RETURN, + T_CONTINUE, + T_THROW, + ), + 'strict' => true, + 'shared' => true, + 'with' => array( + T_DEFAULT, + T_CASE, + T_SWITCH, + ), + ), + T_DEFAULT => array( + 'start' => array(T_COLON), + 'end' => array( + T_BREAK, + T_RETURN, + T_CONTINUE, + T_THROW, + ), + 'strict' => true, + 'shared' => true, + 'with' => array( + T_CASE, + T_SWITCH, + ), + ), + ); + + /** + * A list of tokens that end the scope. + * + * This array is just a unique collection of the end tokens + * from the _scopeOpeners array. The data is duplicated here to + * save time during parsing of the file. + * + * @var array + */ + public $endScopeTokens = array( + T_CLOSE_CURLY_BRACKET, + T_BREAK, + ); + + /** + * A list of special JS tokens and their types. + * + * @var array + */ + protected $tokenValues = array( + 'function' => 'T_FUNCTION', + 'prototype' => 'T_PROTOTYPE', + 'try' => 'T_TRY', + 'catch' => 'T_CATCH', + 'return' => 'T_RETURN', + 'throw' => 'T_THROW', + 'break' => 'T_BREAK', + 'switch' => 'T_SWITCH', + 'continue' => 'T_CONTINUE', + 'if' => 'T_IF', + 'else' => 'T_ELSE', + 'do' => 'T_DO', + 'while' => 'T_WHILE', + 'for' => 'T_FOR', + 'var' => 'T_VAR', + 'case' => 'T_CASE', + 'default' => 'T_DEFAULT', + 'true' => 'T_TRUE', + 'false' => 'T_FALSE', + 'null' => 'T_NULL', + 'this' => 'T_THIS', + 'typeof' => 'T_TYPEOF', + '(' => 'T_OPEN_PARENTHESIS', + ')' => 'T_CLOSE_PARENTHESIS', + '{' => 'T_OPEN_CURLY_BRACKET', + '}' => 'T_CLOSE_CURLY_BRACKET', + '[' => 'T_OPEN_SQUARE_BRACKET', + ']' => 'T_CLOSE_SQUARE_BRACKET', + '?' => 'T_INLINE_THEN', + '.' => 'T_OBJECT_OPERATOR', + '+' => 'T_PLUS', + '-' => 'T_MINUS', + '*' => 'T_MULTIPLY', + '%' => 'T_MODULUS', + '/' => 'T_DIVIDE', + '^' => 'T_POWER', + ',' => 'T_COMMA', + ';' => 'T_SEMICOLON', + ':' => 'T_COLON', + '<' => 'T_LESS_THAN', + '>' => 'T_GREATER_THAN', + '<=' => 'T_IS_SMALLER_OR_EQUAL', + '>=' => 'T_IS_GREATER_OR_EQUAL', + '!' => 'T_BOOLEAN_NOT', + '||' => 'T_BOOLEAN_OR', + '&&' => 'T_BOOLEAN_AND', + '|' => 'T_BITWISE_OR', + '&' => 'T_BITWISE_AND', + '!=' => 'T_IS_NOT_EQUAL', + '!==' => 'T_IS_NOT_IDENTICAL', + '=' => 'T_EQUAL', + '==' => 'T_IS_EQUAL', + '===' => 'T_IS_IDENTICAL', + '-=' => 'T_MINUS_EQUAL', + '+=' => 'T_PLUS_EQUAL', + '*=' => 'T_MUL_EQUAL', + '/=' => 'T_DIV_EQUAL', + '%=' => 'T_MOD_EQUAL', + '++' => 'T_INC', + '--' => 'T_DEC', + '//' => 'T_COMMENT', + '/*' => 'T_COMMENT', + '/**' => 'T_DOC_COMMENT', + '*/' => 'T_COMMENT', + ); + + /** + * A list string delimiters. + * + * @var array + */ + protected $stringTokens = array( + '\'', + '"', + ); + + /** + * A list tokens that start and end comments. + * + * @var array + */ + protected $commentTokens = array( + '//' => null, + '/*' => '*/', + '/**' => '*/', + ); + + + /** + * Creates an array of tokens when given some PHP code. + * + * Starts by using token_get_all() but does a lot of extra processing + * to insert information about the context of the token. + * + * @param string $string The string to tokenize. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return array + */ + public function tokenizeString($string, $eolChar='\n') + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START JS TOKENIZING ***".PHP_EOL; + } + + $tokenTypes = array_keys($this->tokenValues); + + $maxTokenLength = 0; + foreach ($tokenTypes as $token) { + if (strlen($token) > $maxTokenLength) { + $maxTokenLength = strlen($token); + } + } + + $tokens = array(); + $inString = ''; + $stringChar = null; + $inComment = ''; + $buffer = ''; + $preStringBuffer = ''; + $cleanBuffer = false; + + $tokens[] = array( + 'code' => T_OPEN_TAG, + 'type' => 'T_OPEN_TAG', + 'content' => '', + ); + + // Convert newlines to single characters for ease of + // processing. We will change them back later. + $string = str_replace($eolChar, "\n", $string); + + $chars = str_split($string); + $numChars = count($chars); + for ($i = 0; $i < $numChars; $i++) { + $char = $chars[$i]; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $char); + $bufferContent = str_replace("\n", '\n', $buffer); + if ($inString !== '') { + echo "\t"; + } + + if ($inComment !== '') { + echo "\t"; + } + + echo "\tProcess char $i => $content (buffer: $bufferContent)".PHP_EOL; + } + + if ($inString === '' && $inComment === '' && $buffer !== '') { + // If the buffer only has whitespace and we are about to + // add a character, store the whitespace first. + if (trim($char) !== '' && trim($buffer) === '') { + $tokens[] = array( + 'code' => T_WHITESPACE, + 'type' => 'T_WHITESPACE', + 'content' => str_replace("\n", $eolChar, $buffer), + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $buffer); + echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL; + } + + $buffer = ''; + } + + // If the buffer is not whitespace and we are about to + // add a whitespace character, store the content first. + if ($inString === '' + && $inComment === '' + && trim($char) === '' + && trim($buffer) !== '' + ) { + $tokens[] = array( + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => str_replace("\n", $eolChar, $buffer), + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $buffer); + echo "\t=> Added token T_STRING ($content)".PHP_EOL; + } + + $buffer = ''; + } + }//end if + + // Process strings. + if ($inComment === '' && in_array($char, $this->stringTokens) === true) { + if ($inString === $char) { + // This could be the end of the string, but make sure it + // is not escaped first. + $escapes = 0; + for ($x = ($i - 1); $x >= 0; $x--) { + if ($chars[$x] !== '\\') { + break; + } + + $escapes++; + } + + if ($escapes === 0 || ($escapes % 2) === 0) { + // There is an even number escape chars, + // so this is not escaped, it is the end of the string. + $tokens[] = array( + 'code' => T_CONSTANT_ENCAPSED_STRING, + 'type' => 'T_CONSTANT_ENCAPSED_STRING', + 'content' => str_replace("\n", $eolChar, $buffer).$char, + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* found end of string *".PHP_EOL; + $content = str_replace("\n", '\n', $buffer.$char); + echo "\t=> Added token T_CONSTANT_ENCAPSED_STRING ($content)".PHP_EOL; + } + + $buffer = ''; + $preStringBuffer = ''; + $inString = ''; + $stringChar = null; + continue; + } + } else if ($inString === '') { + $inString = $char; + $stringChar = $i; + $preStringBuffer = $buffer; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* looking for string closer *".PHP_EOL; + } + }//end if + }//end if + + if ($inString !== '' && $char === "\n") { + // Unless this newline character is escaped, the string did not + // end before the end of the line, which means it probably + // wasn't a string at all (maybe a regex). + if ($chars[($i - 1)] !== '\\') { + $i = $stringChar; + $buffer = $preStringBuffer; + $preStringBuffer = ''; + $inString = ''; + $stringChar = null; + $char = $chars[$i]; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* found newline before end of string, bailing *".PHP_EOL; + } + } + } + + $buffer .= $char; + + // We don't look for special tokens inside strings, + // so if we are in a string, we can continue here now + // that the current char is in the buffer. + if ($inString !== '') { + continue; + } + + // Special case for T_DIVIDE which can actually be + // the start of a regular expression. + if ($char === '/') { + $regex = $this->getRegexToken( + $i, + $string, + $chars, + $tokens, + $eolChar + ); + + if ($regex !== null) { + $tokens[] = array( + 'code' => T_REGULAR_EXPRESSION, + 'type' => 'T_REGULAR_EXPRESSION', + 'content' => $regex['content'], + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $regex['content']); + echo "\t=> Added token T_REGULAR_EXPRESSION ($content)".PHP_EOL; + } + + $i = $regex['end']; + $buffer = ''; + $cleanBuffer = false; + continue; + } + }//end if + + // Check for known tokens, but ignore tokens found that are not at + // the end of a string, like FOR and this.FORmat. + if (in_array(strtolower($buffer), $tokenTypes) === true + && (preg_match('|[a-zA-z0-9_]|', $char) === 0 + || isset($chars[($i + 1)]) === false + || preg_match('|[a-zA-z0-9_]|', $chars[($i + 1)]) === 0) + ) { + $matchedToken = false; + $lookAheadLength = ($maxTokenLength - strlen($buffer)); + + if ($lookAheadLength > 0) { + // The buffer contains a token type, but we need + // to look ahead at the next chars to see if this is + // actually part of a larger token. For example, + // FOR and FOREACH. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* buffer possibly contains token, looking ahead $lookAheadLength chars *".PHP_EOL; + } + + $charBuffer = $buffer; + for ($x = 1; $x <= $lookAheadLength; $x++) { + if (isset($chars[($i + $x)]) === false) { + break; + } + + $charBuffer .= $chars[($i + $x)]; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $charBuffer); + echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL; + } + + if (in_array(strtolower($charBuffer), $tokenTypes) === true) { + // We've found something larger that matches + // so we can ignore this char. Except for 1 very specific + // case where a comment like /**/ needs to tokenize as + // T_COMMENT and not T_DOC_COMMENT. + $oldType = $this->tokenValues[strtolower($buffer)]; + $newType = $this->tokenValues[strtolower($charBuffer)]; + if ($oldType === 'T_COMMENT' + && $newType === 'T_DOC_COMMENT' + && $chars[($i + $x + 1)] === '/' + ) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* look ahead ignored T_DOC_COMMENT, continuing *".PHP_EOL; + } + } else { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* look ahead found more specific token ($newType), ignoring $i *".PHP_EOL; + } + + $matchedToken = true; + break; + } + } + }//end for + }//end if + + if ($matchedToken === false) { + if (PHP_CODESNIFFER_VERBOSITY > 1 && $lookAheadLength > 0) { + echo "\t\t* look ahead found nothing *".PHP_EOL; + } + + $value = $this->tokenValues[strtolower($buffer)]; + $tokens[] = array( + 'code' => constant($value), + 'type' => $value, + 'content' => $buffer, + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $buffer); + echo "\t=> Added token $value ($content)".PHP_EOL; + } + + $cleanBuffer = true; + }//end if + } else if (in_array(strtolower($char), $tokenTypes) === true) { + // No matter what token we end up using, we don't + // need the content in the buffer any more because we have + // found a valid token. + $newContent = substr(str_replace("\n", $eolChar, $buffer), 0, -1); + if ($newContent !== '') { + $tokens[] = array( + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => $newContent, + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', substr($buffer, 0, -1)); + echo "\t=> Added token T_STRING ($content)".PHP_EOL; + } + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* char is token, looking ahead ".($maxTokenLength - 1).' chars *'.PHP_EOL; + } + + // The char is a token type, but we need to look ahead at the + // next chars to see if this is actually part of a larger token. + // For example, = and ===. + $charBuffer = $char; + $matchedToken = false; + for ($x = 1; $x <= $maxTokenLength; $x++) { + if (isset($chars[($i + $x)]) === false) { + break; + } + + $charBuffer .= $chars[($i + $x)]; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $charBuffer); + echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL; + } + + if (in_array(strtolower($charBuffer), $tokenTypes) === true) { + // We've found something larger that matches + // so we can ignore this char. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $this->tokenValues[strtolower($charBuffer)]; + echo "\t\t* look ahead found more specific token ($type), ignoring $i *".PHP_EOL; + } + + $matchedToken = true; + break; + } + }//end for + + if ($matchedToken === false) { + $value = $this->tokenValues[strtolower($char)]; + $tokens[] = array( + 'code' => constant($value), + 'type' => $value, + 'content' => $char, + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* look ahead found nothing *".PHP_EOL; + $content = str_replace("\n", '\n', $char); + echo "\t=> Added token $value ($content)".PHP_EOL; + } + + $cleanBuffer = true; + } else { + $buffer = $char; + } + }//end if + + // Keep track of content inside comments. + if ($inComment === '' + && array_key_exists($buffer, $this->commentTokens) === true + ) { + // This is not really a comment if the content + // looks like \// (i.e., it is escaped). + if (isset($chars[($i - 2)]) === true && $chars[($i - 2)] === '\\') { + $lastToken = array_pop($tokens); + $lastContent = $lastToken['content']; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $value = $this->tokenValues[strtolower($lastContent)]; + $content = str_replace("\n", '\n', $lastContent); + echo "\t=> Removed token $value ($content)".PHP_EOL; + } + + $lastChars = str_split($lastContent); + $lastNumChars = count($lastChars); + for ($x = 0; $x < $lastNumChars; $x++) { + $lastChar = $lastChars[$x]; + $value = $this->tokenValues[strtolower($lastChar)]; + $tokens[] = array( + 'code' => constant($value), + 'type' => $value, + 'content' => $lastChar, + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $lastChar); + echo "\t=> Added token $value ($content)".PHP_EOL; + } + } + } else { + // We have started a comment. + $inComment = $buffer; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* looking for end of comment *".PHP_EOL; + } + } + } else if ($inComment !== '') { + if ($this->commentTokens[$inComment] === null) { + // Comment ends at the next newline. + if (strpos($buffer, "\n") !== false) { + $inComment = ''; + } + } else { + if ($this->commentTokens[$inComment] === $buffer) { + $inComment = ''; + } + } + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + if ($inComment === '') { + echo "\t\t* found end of comment *".PHP_EOL; + } + } + + if ($inComment === '' && $cleanBuffer === false) { + $tokens[] = array( + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => str_replace("\n", $eolChar, $buffer), + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $buffer); + echo "\t=> Added token T_STRING ($content)".PHP_EOL; + } + + $buffer = ''; + } + }//end if + + if ($cleanBuffer === true) { + $buffer = ''; + $cleanBuffer = false; + } + }//end foreach + + if (empty($buffer) === false) { + // Buffer contains whitespace from the end of the file. + $tokens[] = array( + 'code' => T_WHITESPACE, + 'type' => 'T_WHITESPACE', + 'content' => str_replace("\n", $eolChar, $buffer), + ); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace($eolChar, '\n', $buffer); + echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL; + } + } + + $tokens[] = array( + 'code' => T_CLOSE_TAG, + 'type' => 'T_CLOSE_TAG', + 'content' => '', + ); + + /* + Now that we have done some basic tokenizing, we need to + modify the tokens to join some together and split some apart + so they match what the PHP tokenizer does. + */ + + $finalTokens = array(); + $newStackPtr = 0; + $numTokens = count($tokens); + for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { + $token = $tokens[$stackPtr]; + + /* + Look for comments and join the tokens together. + */ + + if (array_key_exists($token['content'], $this->commentTokens) === true) { + $newContent = ''; + $tokenContent = $token['content']; + $endContent = $this->commentTokens[$tokenContent]; + while ($tokenContent !== $endContent) { + if ($endContent === null + && strpos($tokenContent, $eolChar) !== false + ) { + // A null end token means the comment ends at the end of + // the line so we look for newlines and split the token. + $tokens[$stackPtr]['content'] = substr( + $tokenContent, + (strpos($tokenContent, $eolChar) + strlen($eolChar)) + ); + + $tokenContent = substr( + $tokenContent, + 0, + (strpos($tokenContent, $eolChar) + strlen($eolChar)) + ); + + // If the substr failed, skip the token as the content + // will now be blank. + if ($tokens[$stackPtr]['content'] !== false) { + $stackPtr--; + } + + break; + }//end if + + $stackPtr++; + $newContent .= $tokenContent; + if (isset($tokens[$stackPtr]) === false) { + break; + } + + $tokenContent = $tokens[$stackPtr]['content']; + }//end while + + // Save the new content in the current token so + // the code below can chop it up on newlines. + $token['content'] = $newContent.$tokenContent; + }//end if + + /* + If this token has newlines in its content, split each line up + and create a new token for each line. We do this so it's easier + to ascertain where errors occur on a line. + Note that $token[1] is the token's content. + */ + + if (strpos($token['content'], $eolChar) !== false) { + $tokenLines = explode($eolChar, $token['content']); + $numLines = count($tokenLines); + + for ($i = 0; $i < $numLines; $i++) { + $newToken['content'] = $tokenLines[$i]; + if ($i === ($numLines - 1)) { + if ($tokenLines[$i] === '') { + break; + } + } else { + $newToken['content'] .= $eolChar; + } + + $newToken['type'] = $token['type']; + $newToken['code'] = $token['code']; + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + } + } else { + $finalTokens[$newStackPtr] = $token; + $newStackPtr++; + }//end if + + // Convert numbers, including decimals. + if ($token['code'] === T_STRING + || $token['code'] === T_OBJECT_OPERATOR + ) { + $newContent = ''; + $oldStackPtr = $stackPtr; + while (preg_match('|^[0-9\.]+$|', $tokens[$stackPtr]['content']) !== 0) { + $newContent .= $tokens[$stackPtr]['content']; + $stackPtr++; + } + + if ($newContent !== '' && $newContent !== '.') { + $finalTokens[($newStackPtr - 1)]['content'] = $newContent; + if (ctype_digit($newContent) === true) { + $finalTokens[($newStackPtr - 1)]['code'] + = constant('T_LNUMBER'); + $finalTokens[($newStackPtr - 1)]['type'] = 'T_LNUMBER'; + } else { + $finalTokens[($newStackPtr - 1)]['code'] + = constant('T_DNUMBER'); + $finalTokens[($newStackPtr - 1)]['type'] = 'T_DNUMBER'; + } + + $stackPtr--; + } else { + $stackPtr = $oldStackPtr; + } + }//end if + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END TOKENIZING ***".PHP_EOL; + } + + return $finalTokens; + + }//end tokenizeString() + + + /** + * Tokenizes a regular expression if one is found. + * + * If a regular expression is not found, NULL is returned. + * + * @param string $char The index of the possible regex start character. + * @param string $string The complete content of the string being tokenized. + * @param string $chars An array of characters being tokenized. + * @param string $tokens The current array of tokens found in the string. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + public function getRegexToken($char, $string, $chars, $tokens, $eolChar) + { + $beforeTokens = array( + T_EQUAL, + T_OPEN_PARENTHESIS, + T_RETURN, + T_BOOLEAN_OR, + T_BOOLEAN_AND, + T_BITWISE_OR, + T_BITWISE_AND, + T_COMMA, + T_COLON, + T_TYPEOF, + ); + + $afterTokens = array( + ',', + ')', + ';', + ' ', + '.', + $eolChar, + ); + + // Find the last non-whitespace token that was added + // to the tokens array. + $numTokens = count($tokens); + for ($prev = ($numTokens - 1); $prev >= 0; $prev--) { + if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if (in_array($tokens[$prev]['code'], $beforeTokens) === false) { + return null; + } + + // This is probably a regular expression, so look for the end of it. + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $content = str_replace("\n", '\n', $char); + echo "\t* token possibly starts a regular expression *".PHP_EOL; + } + + $numChars = count($chars); + for ($next = ($char + 1); $next < $numChars; $next++) { + if ($chars[$next] === '/') { + // Just make sure this is not escaped first. + if ($chars[($next - 1)] !== '\\') { + // In the simple form: /.../ so we found the end. + break; + } else if ($chars[($next - 2)] === '\\') { + // In the form: /...\\/ so we found the end. + break; + } + } else { + $possibleEolChar = substr($string, $next, strlen($eolChar)); + if ($possibleEolChar === $eolChar) { + // This is the last token on the line and regular + // expressions need to be defined on a single line, + // so this is not a regular expression. + break; + } + } + } + + if ($chars[$next] !== '/') { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t* could not find end of regular expression *".PHP_EOL; + } + + return null; + } + + while (preg_match('|[a-zA-Z]|', $chars[($next + 1)]) !== 0) { + // The token directly after the end of the regex can + // be modifiers like global and case insensitive + // (.e.g, /pattern/gi). + $next++; + } + + $regexEnd = $next; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t* found end of regular expression at token $regexEnd *".PHP_EOL; + } + + for ($next = ($next + 1); $next < $numChars; $next++) { + if ($chars[$next] !== ' ') { + break; + } else { + $possibleEolChar = substr($string, $next, strlen($eolChar)); + if ($possibleEolChar === $eolChar) { + // This is the last token on the line. + break; + } + } + } + + if (in_array($chars[$next], $afterTokens) === false) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t* tokens after regular expression do not look correct *".PHP_EOL; + } + + return null; + } + + // This is a regular expression, so join all the tokens together. + $content = ''; + for ($x = $char; $x <= $regexEnd; $x++) { + $content .= $chars[$x]; + } + + $token = array( + 'start' => $char, + 'end' => $regexEnd, + 'content' => $content, + ); + + return $token; + + }//end getRegexToken() + + + /** + * Performs additional processing after main tokenizing. + * + * This additional processing looks for properties, labels and objects. + * + * @param array &$tokens The array of tokens to process. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + public function processAdditional(&$tokens, $eolChar) + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START ADDITIONAL JS PROCESSING ***".PHP_EOL; + } + + $numTokens = count($tokens); + $classStack = array(); + + for ($i = 0; $i < $numTokens; $i++) { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$i]['type']; + $content = str_replace($eolChar, '\n', $tokens[$i]['content']); + echo str_repeat("\t", count($classStack)); + + echo "\tProcess token $i: $type => $content".PHP_EOL; + } + + if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET + && isset($tokens[$i]['scope_condition']) === false + ) { + $classStack[] = $i; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t=> Found property opener".PHP_EOL; + } + + // This could also be an object definition. + for ($x = ($i - 1); $x >= 0; $x--) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + // Non-whitespace content. + break; + } + } + + if ($tokens[$x]['code'] === T_EQUAL) { + for ($x--; $x >= 0; $x--) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($tokens[$x]['code'] === T_STRING + || $tokens[$x]['code'] === T_PROTOTYPE + ) { + // Find the first string in this definition. + // E.g., WantedString.DontWantThis.prototype + for ($x--; $x >= 0; $x--) { + $wantedTokens = array( + T_STRING, + T_PROTOTYPE, + T_OBJECT_OPERATOR, + ); + + if (in_array($tokens[$x]['code'], $wantedTokens) === false) { + $x++; + break; + } + } + + $closer = $tokens[$i]['bracket_closer']; + $tokens[$i]['scope_condition'] = $x; + $tokens[$i]['scope_closer'] = $closer; + $tokens[$closer]['scope_condition'] = $x; + $tokens[$closer]['scope_opener'] = $i; + $tokens[$x]['scope_opener'] = $i; + $tokens[$x]['scope_closer'] = $closer; + $tokens[$x]['code'] = T_OBJECT; + $tokens[$x]['type'] = 'T_OBJECT'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t* token $x converted from T_STRING to T_OBJECT *".PHP_EOL; + echo str_repeat("\t", count($classStack)); + echo "\t* set scope opener ($i) and closer ($closer) for token $x *".PHP_EOL; + } + }//end if + }//end if + } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET + && (isset($tokens[$i]['scope_condition']) === false + || $tokens[$tokens[$i]['scope_condition']]['code'] === T_OBJECT) + ) { + $opener = array_pop($classStack); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t\t=> Found property closer for $opener".PHP_EOL; + } + } else if ($tokens[$i]['code'] === T_COLON) { + // If it is a scope opener, it belongs to a + // DEFAULT or CASE statement. + if (isset($tokens[$i]['scope_condition']) === true) { + continue; + } + + // Make sure this is not part of an inline IF statement. + for ($x = ($i - 1); $x >= 0; $x--) { + if ($tokens[$x]['code'] === T_INLINE_THEN) { + $tokens[$i]['code'] = T_INLINE_ELSE; + $tokens[$i]['type'] = 'T_INLINE_ELSE'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t* token $i converted from T_COLON to T_INLINE_THEN *".PHP_EOL; + } + + continue(2); + } else if ($tokens[$x]['line'] < $tokens[$i]['line']) { + break; + } + } + + // The string to the left of the colon is either a property or label. + for ($label = ($i - 1); $label >= 0; $label--) { + if (in_array($tokens[$label]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($tokens[$label]['code'] !== T_STRING) { + continue; + } + + if (empty($classStack) === false) { + $tokens[$label]['code'] = T_PROPERTY; + $tokens[$label]['type'] = 'T_PROPERTY'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t* token $label converted from T_STRING to T_PROPERTY *".PHP_EOL; + } + + // If the net token after the colon is a curly brace, + // this property is actually an object, so we can give it + // and opener and closer. + for ($x = ($i + 1); $x < $numTokens; $x++) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($tokens[$x]['code'] === T_OPEN_CURLY_BRACKET) { + $closer = $tokens[$x]['bracket_closer']; + $tokens[$label]['scope_opener'] = $x; + $tokens[$label]['scope_closer'] = $closer; + $tokens[$x]['scope_condition'] = $label; + $tokens[$x]['scope_closer'] = $closer; + $tokens[$closer]['scope_condition'] = $label; + $tokens[$closer]['scope_opener'] = $x; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t* set scope opener ($x) and closer ($closer) for token $label *".PHP_EOL; + } + } + } else { + $tokens[$label]['code'] = T_LABEL; + $tokens[$label]['type'] = 'T_LABEL'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", count($classStack)); + echo "\t* token $label converted from T_STRING to T_LABEL *".PHP_EOL; + } + } + }//end if + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END ADDITIONAL JS PROCESSING ***".PHP_EOL; + } + + }//end processAdditional() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Tokenizers/PHP.php b/codesniffer/CodeSniffer/Tokenizers/PHP.php new file mode 100644 index 000000000..a1b9f45ce --- /dev/null +++ b/codesniffer/CodeSniffer/Tokenizers/PHP.php @@ -0,0 +1,769 @@ + + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Tokenizes PHP code. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Tokenizers_PHP +{ + + /** + * A list of tokens that are allowed to open a scope. + * + * This array also contains information about what kind of token the scope + * opener uses to open and close the scope, if the token strictly requires + * an opener, if the token can share a scope closer, and who it can be shared + * with. An example of a token that shares a scope closer is a CASE scope. + * + * @var array + */ + public $scopeOpeners = array( + T_IF => array( + 'start' => array( + T_OPEN_CURLY_BRACKET, + T_COLON, + ), + 'end' => array( + T_CLOSE_CURLY_BRACKET, + T_ENDIF, + ), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_TRY => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_CATCH => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_FINALLY => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_ELSE => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_ELSEIF => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_FOR => array( + 'start' => array( + T_OPEN_CURLY_BRACKET, + T_COLON, + ), + 'end' => array( + T_CLOSE_CURLY_BRACKET, + T_ENDFOR, + ), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_FOREACH => array( + 'start' => array( + T_OPEN_CURLY_BRACKET, + T_COLON, + ), + 'end' => array( + T_CLOSE_CURLY_BRACKET, + T_ENDFOREACH, + ), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_INTERFACE => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_FUNCTION => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_CLASS => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_TRAIT => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_NAMESPACE => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_WHILE => array( + 'start' => array( + T_OPEN_CURLY_BRACKET, + T_COLON, + ), + 'end' => array( + T_CLOSE_CURLY_BRACKET, + T_ENDWHILE, + ), + 'strict' => false, + 'shared' => false, + 'with' => array(), + ), + T_DO => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_SWITCH => array( + 'start' => array(T_OPEN_CURLY_BRACKET), + 'end' => array(T_CLOSE_CURLY_BRACKET), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + T_CASE => array( + 'start' => array( + T_COLON, + T_SEMICOLON, + ), + 'end' => array( + T_BREAK, + T_RETURN, + T_CONTINUE, + T_THROW, + ), + 'strict' => true, + 'shared' => true, + 'with' => array( + T_DEFAULT, + T_CASE, + T_SWITCH, + ), + ), + T_DEFAULT => array( + 'start' => array(T_COLON), + 'end' => array( + T_BREAK, + T_RETURN, + T_CONTINUE, + T_THROW, + ), + 'strict' => true, + 'shared' => true, + 'with' => array( + T_CASE, + T_SWITCH, + ), + ), + T_START_HEREDOC => array( + 'start' => array(T_START_HEREDOC), + 'end' => array(T_END_HEREDOC), + 'strict' => true, + 'shared' => false, + 'with' => array(), + ), + ); + + /** + * A list of tokens that end the scope. + * + * This array is just a unique collection of the end tokens + * from the _scopeOpeners array. The data is duplicated here to + * save time during parsing of the file. + * + * @var array + */ + public $endScopeTokens = array( + T_CLOSE_CURLY_BRACKET, + T_BREAK, + T_END_HEREDOC, + ); + + + /** + * Creates an array of tokens when given some PHP code. + * + * Starts by using token_get_all() but does a lot of extra processing + * to insert information about the context of the token. + * + * @param string $string The string to tokenize. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return array + */ + public function tokenizeString($string, $eolChar='\n') + { + $tokens = @token_get_all($string); + $finalTokens = array(); + + $newStackPtr = 0; + $numTokens = count($tokens); + + $insideInlineIf = false; + + for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { + $token = $tokens[$stackPtr]; + $tokenIsArray = is_array($token); + + /* + If we are using \r\n newline characters, the \r and \n are sometimes + split over two tokens. This normally occurs after comments. We need + to merge these two characters together so that our line endings are + consistent for all lines. + */ + + if ($tokenIsArray === true && substr($token[1], -1) === "\r") { + if (isset($tokens[($stackPtr + 1)]) === true + && is_array($tokens[($stackPtr + 1)]) === true + && $tokens[($stackPtr + 1)][1][0] === "\n" + ) { + $token[1] .= "\n"; + + if ($tokens[($stackPtr + 1)][1] === "\n") { + // The next token's content has been merged into this token, + // so we can skip it. + $stackPtr++; + } else { + $tokens[($stackPtr + 1)][1] + = substr($tokens[($stackPtr + 1)][1], 1); + } + } + }//end if + + /* + If this is a double quoted string, PHP will tokenise the whole + thing which causes problems with the scope map when braces are + within the string. So we need to merge the tokens together to + provide a single string. + */ + + if ($tokenIsArray === false && $token === '"') { + $tokenContent = '"'; + $nestedVars = array(); + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + $subTokenIsArray = is_array($tokens[$i]); + + if ($subTokenIsArray === true) { + $tokenContent .= $tokens[$i][1]; + if ($tokens[$i][1] === '{' + && $tokens[$i][0] !== T_ENCAPSED_AND_WHITESPACE + ) { + $nestedVars[] = $i; + } + } else { + $tokenContent .= $tokens[$i]; + if ($tokens[$i] === '}') { + array_pop($nestedVars); + } + } + + if ($subTokenIsArray === false + && $tokens[$i] === '"' + && empty($nestedVars) === true + ) { + // We found the other end of the double quoted string. + break; + } + } + + $stackPtr = $i; + + // Convert each line within the double quoted string to a + // new token, so it conforms with other multiple line tokens. + $tokenLines = explode($eolChar, $tokenContent); + $numLines = count($tokenLines); + $newToken = array(); + + for ($j = 0; $j < $numLines; $j++) { + $newToken['content'] = $tokenLines[$j]; + if ($j === ($numLines - 1)) { + if ($tokenLines[$j] === '') { + break; + } + } else { + $newToken['content'] .= $eolChar; + } + + $newToken['code'] = T_DOUBLE_QUOTED_STRING; + $newToken['type'] = 'T_DOUBLE_QUOTED_STRING'; + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + } + + // Continue, as we're done with this token. + continue; + }//end if + + /* + If this is a heredoc, PHP will tokenise the whole + thing which causes problems when heredocs don't + contain real PHP code, which is almost never. + We want to leave the start and end heredoc tokens + alone though. + */ + + if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) { + // Add the start heredoc token to the final array. + $finalTokens[$newStackPtr] + = PHP_CodeSniffer::standardiseToken($token); + + // Check if this is actually a nowdoc and use a different token + // to help the sniffs. + $nowdoc = false; + if ($token[1][3] === "'") { + $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC; + $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC'; + $nowdoc = true; + } + + $newStackPtr++; + + $tokenContent = ''; + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + $subTokenIsArray = is_array($tokens[$i]); + if ($subTokenIsArray === true + && $tokens[$i][0] === T_END_HEREDOC + ) { + // We found the other end of the heredoc. + break; + } + + if ($subTokenIsArray === true) { + $tokenContent .= $tokens[$i][1]; + } else { + $tokenContent .= $tokens[$i]; + } + } + + $stackPtr = $i; + + // Convert each line within the heredoc to a + // new token, so it conforms with other multiple line tokens. + $tokenLines = explode($eolChar, $tokenContent); + $numLines = count($tokenLines); + $newToken = array(); + + for ($j = 0; $j < $numLines; $j++) { + $newToken['content'] = $tokenLines[$j]; + if ($j === ($numLines - 1)) { + if ($tokenLines[$j] === '') { + break; + } + } else { + $newToken['content'] .= $eolChar; + } + + if ($nowdoc === true) { + $newToken['code'] = T_NOWDOC; + $newToken['type'] = 'T_NOWDOC'; + } else { + $newToken['code'] = T_HEREDOC; + $newToken['type'] = 'T_HEREDOC'; + } + + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + } + + // Add the end heredoc token to the final array. + $finalTokens[$newStackPtr] + = PHP_CodeSniffer::standardiseToken($tokens[$stackPtr]); + + if ($nowdoc === true) { + $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC; + $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC'; + $nowdoc = true; + } + + $newStackPtr++; + + // Continue, as we're done with this token. + continue; + }//end if + + /* + PHP doesn't assign a token to goto labels, so we have to. + These are just string tokens with a single colon after them. Double + colons are already tokenized and so don't interfere with this check. + But we do have to account for CASE statements, that look just like + goto labels. + */ + + if ($tokenIsArray === true + && $token[0] === T_STRING + && $tokens[($stackPtr + 1)] === ':' + && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM + ) { + $stopTokens = array( + T_CASE, + T_SEMICOLON, + T_OPEN_CURLY_BRACKET, + ); + + for ($x = ($newStackPtr - 2); $x > 0; $x--) { + if (in_array($finalTokens[$x]['code'], $stopTokens) === true) { + break; + } + } + + if ($finalTokens[$x]['code'] !== T_CASE) { + $finalTokens[$newStackPtr] = array( + 'content' => $token[1].':', + 'code' => T_GOTO_LABEL, + 'type' => 'T_GOTO_LABEL', + ); + $newStackPtr++; + $stackPtr++; + continue; + } + }//end if + + /* + If this token has newlines in its content, split each line up + and create a new token for each line. We do this so it's easier + to ascertain where errors occur on a line. + Note that $token[1] is the token's content. + */ + + if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) { + $tokenLines = explode($eolChar, $token[1]); + $numLines = count($tokenLines); + $tokenName = token_name($token[0]); + + for ($i = 0; $i < $numLines; $i++) { + $newToken['content'] = $tokenLines[$i]; + if ($i === ($numLines - 1)) { + if ($tokenLines[$i] === '') { + break; + } + } else { + $newToken['content'] .= $eolChar; + } + + $newToken['type'] = $tokenName; + $newToken['code'] = $token[0]; + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + } + } else { + $newToken = PHP_CodeSniffer::standardiseToken($token); + + // Convert colons that are actually the ELSE component of an + // inline IF statement. + if ($newToken['code'] === T_INLINE_THEN) { + $insideInlineIf = true; + } else if ($insideInlineIf === true && $newToken['code'] === T_COLON) { + $insideInlineIf = false; + $newToken['code'] = T_INLINE_ELSE; + $newToken['type'] = 'T_INLINE_ELSE'; + } + + // This is a special condition for T_ARRAY tokens used for + // type hinting function arguments as being arrays. We want to keep + // the parenthesis map clean, so let's tag these tokens as + // T_ARRAY_HINT. + if ($newToken['code'] === T_ARRAY) { + // Recalculate number of tokens. + $numTokens = count($tokens); + for ($i = $stackPtr; $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === false) { + if ($tokens[$i] === '(') { + break; + } + } else if ($tokens[$i][0] === T_VARIABLE) { + $newToken['code'] = T_ARRAY_HINT; + $newToken['type'] = 'T_ARRAY_HINT'; + break; + } + } + } + + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + }//end if + }//end for + + return $finalTokens; + + }//end tokenizeString() + + + /** + * Performs additional processing after main tokenizing. + * + * This additional processing checks for CASE statements that are using curly + * braces for scope openers and closers. It also turns some T_FUNCTION tokens + * into T_CLOSURE when they are not standard function definitions. It also + * detects short array syntax and converts those square brackets into new tokens. + * It also corrects some usage of the static and class keywords. + * + * @param array &$tokens The array of tokens to process. + * @param string $eolChar The EOL character to use for splitting strings. + * + * @return void + */ + public function processAdditional(&$tokens, $eolChar) + { + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL; + } + + $numTokens = count($tokens); + for ($i = ($numTokens - 1); $i >= 0; $i--) { + // Looking for functions that are actually closures. + if ($tokens[$i]['code'] === T_FUNCTION && isset($tokens[$i]['scope_opener']) === true) { + for ($x = ($i + 1); $x < $numTokens; $x++) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) { + $tokens[$i]['code'] = T_CLOSURE; + $tokens[$i]['type'] = 'T_CLOSURE'; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $tokens[$i]['line']; + echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL; + } + + for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) { + if (isset($tokens[$x]['conditions'][$i]) === false) { + continue; + } + + $tokens[$x]['conditions'][$i] = T_CLOSURE; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$x]['type']; + echo "\t\t* cleaned $x ($type) *".PHP_EOL; + } + } + } + + continue; + } else if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) { + // Unless there is a variable or a bracket before this token, + // it is the start of an array being defined using the short syntax. + for ($x = ($i - 1); $x > 0; $x--) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + $allowed = array( + T_CLOSE_SQUARE_BRACKET, + T_CLOSE_PARENTHESIS, + T_VARIABLE, + T_STRING, + ); + + if (in_array($tokens[$x]['code'], $allowed) === false) { + $tokens[$i]['code'] = T_OPEN_SHORT_ARRAY; + $tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY'; + + $closer = $tokens[$i]['bracket_closer']; + $tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY; + $tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY'; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $tokens[$i]['line']; + echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL; + $line = $tokens[$closer]['line']; + echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL; + } + } + + continue; + } else if ($tokens[$i]['code'] === T_STATIC) { + for ($x = ($i - 1); $x > 0; $x--) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + break; + } + } + + if ($tokens[$x]['code'] === T_INSTANCEOF) { + $tokens[$i]['code'] = T_STRING; + $tokens[$i]['type'] = 'T_STRING'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $tokens[$i]['line']; + echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL; + } + } + + continue; + } else if ($tokens[$i]['code'] === T_CLASS + && $tokens[($i - 1)]['code'] === T_DOUBLE_COLON + ) { + $tokens[$i]['code'] = T_STRING; + $tokens[$i]['type'] = 'T_STRING'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $tokens[$i]['line']; + echo "\t* token $i on line $line changed from T_CLASS to T_STRING".PHP_EOL; + } + }//end if + + if (($tokens[$i]['code'] !== T_CASE + && $tokens[$i]['code'] !== T_DEFAULT) + || isset($tokens[$i]['scope_opener']) === false + ) { + // Only interested in CASE and DEFAULT statements from here on in. + continue; + } + + $scopeOpener = $tokens[$i]['scope_opener']; + $scopeCloser = $tokens[$i]['scope_closer']; + + // If the first char after the opener is a curly brace + // and that brace has been ignored, it is actually + // opening this case statement and the opener and closer are + // probably set incorrectly. + for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) { + if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { + // Non-whitespace content. + break; + } + } + + if ($tokens[$x]['code'] === T_CASE) { + // Special case for multiple CASE statements that share the same + // closer. Because we are going backwards through the file, this next + // CASE statement is already fixed, so just use its closer and don't + // worry about fixing anything. + $newCloser = $tokens[$x]['scope_closer']; + $tokens[$i]['scope_closer'] = $newCloser; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $oldType = $tokens[$scopeCloser]['type']; + $newType = $tokens[$newCloser]['type']; + $line = $tokens[$i]['line']; + echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL; + } + + continue; + } + + if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET + || isset($tokens[$x]['scope_condition']) === true + ) { + // Not a CASE with a curly brace opener. + continue; + } + + // The closer for this CASE/DEFAULT should be the closing curly brace and + // not whatever it already is. The opener needs to be the opening curly + // brace so everything matches up. + $newCloser = $tokens[$x]['bracket_closer']; + $tokens[$i]['scope_closer'] = $newCloser; + $tokens[$x]['scope_closer'] = $newCloser; + $tokens[$i]['scope_opener'] = $x; + $tokens[$x]['scope_condition'] = $i; + $tokens[$newCloser]['scope_condition'] = $i; + $tokens[$newCloser]['scope_opener'] = $x; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $tokens[$i]['line']; + $tokenType = $tokens[$i]['type']; + + $oldType = $tokens[$scopeOpener]['type']; + $newType = $tokens[$x]['type']; + echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL; + + $oldType = $tokens[$scopeCloser]['type']; + $newType = $tokens[$newCloser]['type']; + echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL; + } + + // Now fix up all the tokens that think they are + // inside the CASE/DEFAULT statement when they are really outside. + for ($x = $newCloser; $x < $scopeCloser; $x++) { + foreach ($tokens[$x]['conditions'] as $num => $oldCond) { + if ($oldCond === $tokens[$i]['code']) { + $oldConditions = $tokens[$x]['conditions']; + unset($tokens[$x]['conditions'][$num]); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $type = $tokens[$x]['type']; + $oldConds = ''; + foreach ($oldConditions as $condition) { + $oldConds .= token_name($condition).','; + } + + $oldConds = rtrim($oldConds, ','); + + $newConds = ''; + foreach ($tokens[$x]['conditions'] as $condition) { + $newConds .= token_name($condition).','; + } + + $newConds = rtrim($newConds, ','); + + echo "\t\t* cleaned $x ($type) *".PHP_EOL; + echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL; + } + + break; + } + } + } + }//end for + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL; + } + + }//end processAdditional() + + +}//end class + +?> diff --git a/codesniffer/CodeSniffer/Tokens.php b/codesniffer/CodeSniffer/Tokens.php new file mode 100644 index 000000000..994a9196b --- /dev/null +++ b/codesniffer/CodeSniffer/Tokens.php @@ -0,0 +1,503 @@ + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +define('T_NONE', 0); +define('T_OPEN_CURLY_BRACKET', 1000); +define('T_CLOSE_CURLY_BRACKET', 1001); +define('T_OPEN_SQUARE_BRACKET', 1002); +define('T_CLOSE_SQUARE_BRACKET', 1003); +define('T_OPEN_PARENTHESIS', 1004); +define('T_CLOSE_PARENTHESIS', 1005); +define('T_COLON', 1006); +define('T_STRING_CONCAT', 1007); +define('T_INLINE_THEN', 1008); +define('T_INLINE_ELSE', 1009); +define('T_NULL', 1010); +define('T_FALSE', 1011); +define('T_TRUE', 1012); +define('T_SEMICOLON', 1013); +define('T_EQUAL', 1014); +define('T_MULTIPLY', 1015); +define('T_DIVIDE', 1016); +define('T_PLUS', 1017); +define('T_MINUS', 1018); +define('T_MODULUS', 1019); +define('T_POWER', 1020); +define('T_BITWISE_AND', 1021); +define('T_BITWISE_OR', 1022); +define('T_ARRAY_HINT', 1023); +define('T_GREATER_THAN', 1024); +define('T_LESS_THAN', 1025); +define('T_BOOLEAN_NOT', 1026); +define('T_SELF', 1027); +define('T_PARENT', 1028); +define('T_DOUBLE_QUOTED_STRING', 1029); +define('T_COMMA', 1030); +define('T_HEREDOC', 1031); +define('T_PROTOTYPE', 1032); +define('T_THIS', 1033); +define('T_REGULAR_EXPRESSION', 1034); +define('T_PROPERTY', 1035); +define('T_LABEL', 1036); +define('T_OBJECT', 1037); +define('T_COLOUR', 1038); +define('T_HASH', 1039); +define('T_URL', 1040); +define('T_STYLE', 1041); +define('T_ASPERAND', 1042); +define('T_DOLLAR', 1043); +define('T_TYPEOF', 1044); +define('T_CLOSURE', 1045); +define('T_BACKTICK', 1046); +define('T_START_NOWDOC', 1047); +define('T_NOWDOC', 1048); +define('T_END_NOWDOC', 1049); +define('T_OPEN_SHORT_ARRAY', 1050); +define('T_CLOSE_SHORT_ARRAY', 1051); +define('T_GOTO_LABEL', 1052); + +// Some PHP 5.3 tokens, replicated for lower versions. +if (defined('T_NAMESPACE') === false) { + define('T_NAMESPACE', 1053); +} + +if (defined('T_NS_SEPARATOR') === false) { + define('T_NS_SEPARATOR', 1054); +} + +if (defined('T_GOTO') === false) { + define('T_GOTO', 1055); +} + +// Some PHP 5.4 tokens, replicated for lower versions. +if (defined('T_TRAIT') === false) { + define('T_TRAIT', 1056); +} + +if (defined('T_INSTEADOF') === false) { + define('T_INSTEADOF', 1057); +} + +if (defined('T_CALLABLE') === false) { + define('T_CALLABLE', 1058); +} + +// Some PHP 5.5 tokens, replicated for lower versions. +if (defined('T_FINALLY') === false) { + define('T_FINALLY', 1059); +} + +/** + * The Tokens class contains weightings for tokens based on their + * probability of occurrence in a file. + * + * The less the chance of a high occurrence of an arbitrary token, the higher + * the weighting. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +final class PHP_CodeSniffer_Tokens +{ + + /** + * The token weightings. + * + * @var array(int => int) + */ + public static $weightings = array( + T_CLASS => 1000, + T_INTERFACE => 1000, + T_TRAIT => 1000, + T_NAMESPACE => 1000, + T_FUNCTION => 100, + T_CLOSURE => 100, + + /* + Conditions. + */ + + T_WHILE => 50, + T_FOR => 50, + T_FOREACH => 50, + T_IF => 50, + T_ELSE => 50, + T_ELSEIF => 50, + T_WHILE => 50, + T_DO => 50, + T_TRY => 50, + T_CATCH => 50, + T_SWITCH => 50, + + T_SELF => 25, + T_PARENT => 25, + + /* + Operators and arithmetic. + */ + + T_BITWISE_AND => 8, + T_BITWISE_OR => 8, + + T_MULTIPLY => 5, + T_DIVIDE => 5, + T_PLUS => 5, + T_MINUS => 5, + T_MODULUS => 5, + T_POWER => 5, + + T_EQUAL => 5, + T_AND_EQUAL => 5, + T_CONCAT_EQUAL => 5, + T_DIV_EQUAL => 5, + T_MINUS_EQUAL => 5, + T_MOD_EQUAL => 5, + T_MUL_EQUAL => 5, + T_OR_EQUAL => 5, + T_PLUS_EQUAL => 5, + T_XOR_EQUAL => 5, + + T_BOOLEAN_AND => 5, + T_BOOLEAN_OR => 5, + + /* + Equality. + */ + + T_IS_EQUAL => 5, + T_IS_NOT_EQUAL => 5, + T_IS_IDENTICAL => 5, + T_IS_NOT_IDENTICAL => 5, + T_IS_SMALLER_OR_EQUAL => 5, + T_IS_GREATER_OR_EQUAL => 5, + ); + + /** + * Tokens that represent assignments. + * + * @var array(int) + */ + public static $assignmentTokens = array( + T_EQUAL, + T_AND_EQUAL, + T_CONCAT_EQUAL, + T_DIV_EQUAL, + T_MINUS_EQUAL, + T_MOD_EQUAL, + T_MUL_EQUAL, + T_PLUS_EQUAL, + T_XOR_EQUAL, + T_DOUBLE_ARROW, + ); + + /** + * Tokens that represent equality comparisons. + * + * @var array(int) + */ + public static $equalityTokens = array( + T_IS_EQUAL, + T_IS_NOT_EQUAL, + T_IS_IDENTICAL, + T_IS_NOT_IDENTICAL, + T_IS_SMALLER_OR_EQUAL, + T_IS_GREATER_OR_EQUAL, + ); + + /** + * Tokens that represent comparison operator. + * + * @var array(int) + */ + public static $comparisonTokens = array( + T_IS_EQUAL, + T_IS_IDENTICAL, + T_IS_NOT_EQUAL, + T_IS_NOT_IDENTICAL, + T_LESS_THAN, + T_GREATER_THAN, + T_IS_SMALLER_OR_EQUAL, + T_IS_GREATER_OR_EQUAL, + ); + + /** + * Tokens that represent arithmetic operators. + * + * @var array(int) + */ + public static $arithmeticTokens = array( + T_PLUS, + T_MINUS, + T_MULTIPLY, + T_DIVIDE, + T_MODULUS, + ); + + /** + * Tokens that represent casting. + * + * @var array(int) + */ + public static $castTokens = array( + T_INT_CAST, + T_STRING_CAST, + T_DOUBLE_CAST, + T_ARRAY_CAST, + T_BOOL_CAST, + T_OBJECT_CAST, + T_UNSET_CAST, + ); + + /** + * Token types that open parenthesis. + * + * @var array(int) + */ + public static $parenthesisOpeners = array( + T_ARRAY, + T_FUNCTION, + T_CLOSURE, + T_WHILE, + T_FOR, + T_FOREACH, + T_SWITCH, + T_IF, + T_ELSEIF, + T_CATCH, + ); + + /** + * Tokens that are allowed to open scopes. + * + * @var array(int) + */ + public static $scopeOpeners = array( + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_NAMESPACE, + T_FUNCTION, + T_CLOSURE, + T_IF, + T_SWITCH, + T_CASE, + T_DEFAULT, + T_WHILE, + T_ELSE, + T_ELSEIF, + T_FOR, + T_FOREACH, + T_DO, + T_TRY, + T_CATCH, + ); + + /** + * Tokens that represent scope modifiers. + * + * @var array(int) + */ + public static $scopeModifiers = array( + T_PRIVATE, + T_PUBLIC, + T_PROTECTED, + ); + + /** + * Tokens that can prefix a method name + * + * @var array(int) + */ + public static $methodPrefixes = array( + T_PRIVATE, + T_PUBLIC, + T_PROTECTED, + T_ABSTRACT, + T_STATIC, + T_FINAL, + ); + + /** + * Tokens that perform operations. + * + * @var array(int) + */ + public static $operators = array( + T_MINUS, + T_PLUS, + T_MULTIPLY, + T_DIVIDE, + T_MODULUS, + T_POWER, + T_BITWISE_AND, + T_BITWISE_OR, + ); + + /** + * Tokens that perform boolean operations. + * + * @var array(int) + */ + public static $booleanOperators = array( + T_BOOLEAN_AND, + T_BOOLEAN_OR, + T_LOGICAL_AND, + T_LOGICAL_OR, + T_LOGICAL_XOR, + ); + + /** + * Tokens that open code blocks. + * + * @var array(int) + */ + public static $blockOpeners = array( + T_OPEN_CURLY_BRACKET, + T_OPEN_SQUARE_BRACKET, + T_OPEN_PARENTHESIS, + ); + + /** + * Tokens that don't represent code. + * + * @var array(int) + */ + public static $emptyTokens = array( + T_WHITESPACE, + T_COMMENT, + T_DOC_COMMENT, + ); + + /** + * Tokens that are comments. + * + * @var array(int) + */ + public static $commentTokens = array( + T_COMMENT, + T_DOC_COMMENT, + ); + + /** + * Tokens that represent strings. + * + * Note that T_STRINGS are NOT represented in this list. + * + * @var array(int) + */ + public static $stringTokens = array( + T_CONSTANT_ENCAPSED_STRING, + T_DOUBLE_QUOTED_STRING, + ); + + /** + * Tokens that represent brackets and parenthesis. + * + * @var array(int) + */ + public static $bracketTokens = array( + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + ); + + /** + * Tokens that include files. + * + * @var array(int) + */ + public static $includeTokens = array( + T_REQUIRE_ONCE, + T_REQUIRE, + T_INCLUDE_ONCE, + T_INCLUDE, + ); + + /** + * Tokens that make up a heredoc string. + * + * @var array(int) + */ + public static $heredocTokens = array( + T_START_HEREDOC, + T_END_HEREDOC, + T_HEREDOC, + ); + + + /** + * A PHP_CodeSniffer_Tokens class cannot be constructed. + * + * Only static calls are allowed. + */ + private function __construct() + { + + }//end __construct() + + + /** + * Returns the highest weighted token type. + * + * Tokens are weighted by their approximate frequency of appearance in code + * - the less frequently they appear in the code, the higher the weighting. + * For example T_CLASS tokens appear very infrequently in a file, and + * therefore have a high weighting. + * + * Returns false if there are no weightings for any of the specified tokens. + * + * @param array(int) $tokens The token types to get the highest weighted + * type for. + * + * @return int The highest weighted token. + */ + public static function getHighestWeightedToken(array $tokens) + { + $highest = -1; + $highestType = false; + + $weights = self::$weightings; + + foreach ($tokens as $token) { + if (isset($weights[$token]) === true) { + $weight = $weights[$token]; + } else { + $weight = 0; + } + + if ($weight > $highest) { + $highest = $weight; + $highestType = $token; + } + } + + return $highestType; + + }//end getHighestWeightedToken() + + +}//end class + +?> diff --git a/codesniffer/README.markdown b/codesniffer/README.markdown new file mode 100644 index 000000000..be787c280 --- /dev/null +++ b/codesniffer/README.markdown @@ -0,0 +1,64 @@ +About +----- + +PHP\_CodeSniffer is a PHP5 script that tokenises PHP, JavaScript and CSS files to detect violations of a defined coding standard. It is an essential development tool that ensures your code remains clean and consistent. It can also help prevent some common semantic errors made by developers. + +[![Build Status](https://secure.travis-ci.org/squizlabs/PHP_CodeSniffer.png?branch=master)](https://travis-ci.org/squizlabs/PHP_CodeSniffer) + +Requirements +------------ + +PHP\_CodeSniffer requires PHP version 5.1.2 or greater, although individual sniffs may have additional requirements such as external applications and scripts. See the [Configuration Options manual page](http://pear.php.net/manual/en/package.php.php-codesniffer.config-options.php) for a list of these requirements. + +The SVN pre-commit hook requires PHP version 5.2.4 or greater due to its use of the vertical whitespace character. + +Installation +------------ + +The easiest way to install PHP\_CodeSniffer is to use the PEAR installer. This will make the `phpcs` command immediately available for use. To install PHP\_CodeSniffer using the PEAR installer, first ensure you have [installed PEAR](http://pear.php.net/manual/en/installation.getting.php) and then run the following command: + + pear install PHP_CodeSniffer + +If you use [Composer](http://getcomposer.org/), include a dependency for `squizlabs/php_codesniffer` in your `composer.json` file. For example: + + { + "require": { + "squizlabs/php_codesniffer": "1.*" + } + } + +You will then be able to run PHP_CodeSniffer from the vendor bin directory: + + ./vendor/bin/phpcs -h + +You can also download the PHP\_CodeSniffer source and run the `phpcs` command directly from the GIT checkout: + + git clone git://github.com/squizlabs/PHP_CodeSniffer.git + cd PHP_CodeSniffer + php scripts/phpcs -h + +Documentation +------------- + +The documentation for PHP\_CodeSniffer is available on the [Github wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki). + +Information about upcoming features and releases is available on the [Squiz Labs blog](http://www.squizlabs.com/php-codesniffer). + +Contributing +------------- + +If you do contribute code to PHP\_CodeSniffer, please make sure it conforms to the PEAR coding standard and that the PHP\_CodeSniffer unit tests still pass. The easiest way to contribute is to work on a checkout of the repository, or your own fork, rather than an installed PEAR version. If you do this, you can run the following commands to check if everything is ready to submit: + + cd PHP_CodeSniffer + php scripts/phpcs --ignore=*/tests/* . -n + +Which should give you no output, indicating that there are no PEAR coding standard errors. And then: + + phpunit tests/AllTests.php + +Which should give you no failures or errors. You can ignore any skipped tests as these are for external tools. + +Issues +------ + +Bug reports and feature requests can be submitted on the [PEAR bug tracker](http://pear.php.net/package/PHP_CodeSniffer/bugs). diff --git a/codesniffer/composer.json b/codesniffer/composer.json new file mode 100644 index 000000000..7aba72862 --- /dev/null +++ b/codesniffer/composer.json @@ -0,0 +1,58 @@ +{ + "name": "squizlabs/php_codesniffer", + "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "type": "library", + "keywords": [ + "phpcs", + "standards" + ], + "homepage": "http://www.squizlabs.com/php-codesniffer", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name%5B%5D=PHP_CodeSniffer", + "source": "https://github.com/squizlabs/PHP_CodeSniffer" + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/CommentParser/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "suggest": { + "phpunit/php-timer": "dev-master" + }, + "require": { + "php": ">=5.1.2", + "ext-tokenizer": "*" + }, + "bin": [ + "scripts/phpcs" + ] +} diff --git a/codesniffer/composer.lock b/codesniffer/composer.lock new file mode 100644 index 000000000..c452ae778 --- /dev/null +++ b/codesniffer/composer.lock @@ -0,0 +1,21 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "95911e7f79b53c3f385f7f5197d51785", + "content-hash": "a79b48b1f1e644cec95679bb347dd34c", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.1.2", + "ext-tokenizer": "*" + }, + "platform-dev": [] +} diff --git a/codesniffer/licence.txt b/codesniffer/licence.txt new file mode 100644 index 000000000..f95432c87 --- /dev/null +++ b/codesniffer/licence.txt @@ -0,0 +1,24 @@ +Copyright (c) 2012, Squiz Pty Ltd (ABN 77 084 670 600) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Squiz Pty Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/codesniffer/scripts/phpcs b/codesniffer/scripts/phpcs new file mode 100755 index 000000000..839c70f23 --- /dev/null +++ b/codesniffer/scripts/phpcs @@ -0,0 +1,44 @@ +#!/usr/bin/env php + + * @author Marc McIntyre + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +error_reporting(E_ALL | E_STRICT); + +// Optionally use PHP_Timer to print time/memory stats for the run. +// Note that the reports are the ones who actually print the data +// as they decide if it is ok to print this data to screen. +@include_once 'PHP/Timer.php'; +if (class_exists('PHP_Timer', false) === true) { + PHP_Timer::start(); +} + +if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) { + include_once dirname(__FILE__).'/../CodeSniffer/CLI.php'; +} else { + include_once 'PHP/CodeSniffer/CLI.php'; +} + +$phpcs = new PHP_CodeSniffer_CLI(); +$phpcs->checkRequirements(); + +$numErrors = $phpcs->process(); +if ($numErrors === 0) { + exit(0); +} else { + exit(1); +} + +?> diff --git a/codesniffer/scripts/phpcs-svn-pre-commit b/codesniffer/scripts/phpcs-svn-pre-commit new file mode 100755 index 000000000..f15438b51 --- /dev/null +++ b/codesniffer/scripts/phpcs-svn-pre-commit @@ -0,0 +1,223 @@ +#!@php_bin@ + + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) { + include_once dirname(__FILE__).'/../CodeSniffer/CLI.php'; +} else { + include_once 'PHP/CodeSniffer/CLI.php'; +} + +define('PHP_CODESNIFFER_SVNLOOK', '/usr/bin/svnlook'); + + +/** + * A class to process command line options. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Jack Bates + * @author Greg Sherwood + * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_SVN_Hook extends PHP_CodeSniffer_CLI +{ + + + /** + * Get a list of default values for all possible command line arguments. + * + * @return array + */ + public function getDefaults() + { + $defaults = parent::getDefaults(); + + $defaults['svnArgs'] = array(); + return $defaults; + + }//end getDefaults() + + + /** + * Processes an unknown command line argument. + * + * All unknown args are sent to SVN commands. + * + * @param string $arg The command line argument. + * @param int $pos The position of the argument on the command line. + * @param array $values An array of values determined from CLI args. + * + * @return array The updated CLI values. + * @see getCommandLineValues() + */ + public function processUnknownArgument($arg, $pos, $values) + { + $values['svnArgs'][] = escapeshellarg($arg); + return $values; + + }//end processUnknownArgument() + + + /** + * Runs PHP_CodeSniffer over files are directories. + * + * @param array $values An array of values determined from CLI args. + * + * @return int The number of error and warning messages shown. + * @see getCommandLineValues() + */ + public function process($values=array()) + { + if (empty($values) === true) { + $values = parent::getCommandLineValues(); + } + + // Get list of files in this transaction. + $command = PHP_CODESNIFFER_SVNLOOK.' changed '.implode(' ', $values['svnArgs']); + $handle = popen($command, 'r'); + if ($handle === false) { + echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; + exit(2); + } + + $contents = stream_get_contents($handle); + fclose($handle); + + // Do not check deleted paths. + $contents = preg_replace('/^D.*/m', null, $contents); + + // Drop the four characters representing the action which precede the path on + // each line. + $contents = preg_replace('/^.{4}/m', null, $contents); + + $values['standard'] = $this->validateStandard($values['standard']); + foreach ($values['standard'] as $standard) { + if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { + // They didn't select a valid coding standard, so help them + // out by letting them know which standards are installed. + echo 'ERROR: the "'.$standard.'" coding standard is not installed. '; + $this->printInstalledStandards(); + exit(2); + } + } + + $phpcs = new PHP_CodeSniffer( + $values['verbosity'], + $values['tabWidth'], + $values['encoding'] + ); + + // Set file extensions if they were specified. Otherwise, + // let PHP_CodeSniffer decide on the defaults. + if (empty($values['extensions']) === false) { + $phpcs->setAllowedFileExtensions($values['extensions']); + } + + // Set ignore patterns if they were specified. + if (empty($values['ignored']) === false) { + $phpcs->setIgnorePatterns($values['ignored']); + } + + // Set some convenience member vars. + if ($values['errorSeverity'] === null) { + $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; + } else { + $this->errorSeverity = $values['errorSeverity']; + } + + if ($values['warningSeverity'] === null) { + $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; + } else { + $this->warningSeverity = $values['warningSeverity']; + } + + // Initialize PHP_CodeSniffer listeners but don't process any files. + $phpcs->setCli($this); + $phpcs->process(array(), $values['standard'], $values['sniffs']); + + // Need double quotes around the following regex beause the vertical whitespace + // char is not always treated correctly for whatever reason. + foreach (preg_split("/\v|\n/", $contents, -1, PREG_SPLIT_NO_EMPTY) as $path) { + // No need to process folders as each changed file is checked. + if (substr($path, -1) === '/') { + continue; + } + + // We need to check ignore rules ourself because they are + // not checked when processing a single file. + if ($phpcs->shouldProcessFile($path, dirname($path)) === false) { + continue; + } + + // Get the contents of each file, as it would be after this transaction. + $command = PHP_CODESNIFFER_SVNLOOK.' cat '.implode(' ', $values['svnArgs']).' '.escapeshellarg($path); + $handle = popen($command, 'r'); + if ($handle === false) { + echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; + exit(2); + } + + $contents = stream_get_contents($handle); + fclose($handle); + + $phpcs->processFile($path, $contents); + }//end foreach + + return $this->printErrorReport( + $phpcs, + $values['reports'], + $values['showSources'], + $values['reportFile'], + $values['reportWidth'] + ); + + }//end process() + + + /** + * Prints out the usage information for this script. + * + * @return void + */ + public function printUsage() + { + parent::printUsage(); + + echo PHP_EOL; + echo ' Each additional argument is passed to the `svnlook changed ...`'.PHP_EOL; + echo ' and `svnlook cat ...` commands. The report is printed on standard output,'.PHP_EOL; + echo ' however Subversion displays only standard error to the user, so in a'.PHP_EOL; + echo ' pre-commit hook, this script should be invoked as follows:'.PHP_EOL; + echo PHP_EOL; + echo ' '.basename($_SERVER['argv'][0]).' ... "$REPOS" -t "$TXN" >&2 || exit 1'.PHP_EOL; + + }//end printUsage() + + +}//end class + +$phpcs = new PHP_CodeSniffer_SVN_Hook(); +$phpcs->checkRequirements(); + +$numErrors = $phpcs->process(); +if ($numErrors !== 0) { + exit(1); +} + +?> diff --git a/codesniffer/scripts/phpcs.bat b/codesniffer/scripts/phpcs.bat new file mode 100755 index 000000000..8620015f8 --- /dev/null +++ b/codesniffer/scripts/phpcs.bat @@ -0,0 +1,16 @@ +@echo off +REM PHP_CodeSniffer tokenises PHP code and detects violations of a +REM defined set of coding standards. +REM +REM PHP version 5 +REM +REM @category PHP +REM @package PHP_CodeSniffer +REM @author Greg Sherwood +REM @author Marc McIntyre +REM @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) +REM @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence +REM @version CVS: $Id: phpcs.bat,v 1.3 2007-11-04 22:02:16 squiz Exp $ +REM @link http://pear.php.net/package/PHP_CodeSniffer + +"@php_bin@" -d auto_append_file="" -d auto_prepend_file="" -d include_path="'@php_dir@'" -f "@bin_dir@\phpcs" -- %* diff --git a/codesniffer/vendor/autoload.php b/codesniffer/vendor/autoload.php new file mode 100644 index 000000000..f566fcbce --- /dev/null +++ b/codesniffer/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/codesniffer/vendor/composer/LICENSE b/codesniffer/vendor/composer/LICENSE new file mode 100644 index 000000000..1a2812488 --- /dev/null +++ b/codesniffer/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) 2016 Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/codesniffer/vendor/composer/autoload_classmap.php b/codesniffer/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..b600b6037 --- /dev/null +++ b/codesniffer/vendor/composer/autoload_classmap.php @@ -0,0 +1,257 @@ + $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php', + 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php', + 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php', + 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php', + 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php', + 'Generic_Sniffs_Commenting_FixmeSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php', + 'Generic_Sniffs_Commenting_TodoSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php', + 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php', + 'Generic_Sniffs_Debug_CSSLintSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php', + 'Generic_Sniffs_Debug_ClosureLinterSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php', + 'Generic_Sniffs_Debug_JSHintSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php', + 'Generic_Sniffs_Files_ByteOrderMarkSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic_Sniffs_Files_EndFileNewlineSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php', + 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php', + 'Generic_Sniffs_Files_InlineHTMLSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php', + 'Generic_Sniffs_Files_LineEndingsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php', + 'Generic_Sniffs_Files_LineLengthSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php', + 'Generic_Sniffs_Files_LowercasedFilenameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php', + 'Generic_Sniffs_Files_OneClassPerFileSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php', + 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php', + 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php', + 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php', + 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php', + 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php', + 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php', + 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php', + 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php', + 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php', + 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php', + 'Generic_Sniffs_Metrics_NestingLevelSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php', + 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php', + 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php', + 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php', + 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php', + 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php', + 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php', + 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php', + 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php', + 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php', + 'Generic_Sniffs_PHP_SAPIUsageSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php', + 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php', + 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php', + 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php', + 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php', + 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php', + 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php', + 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php', + 'MySource_Sniffs_Channels_ChannelExceptionSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php', + 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php', + 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php', + 'MySource_Sniffs_Channels_IncludeSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php', + 'MySource_Sniffs_Channels_UnusedSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php', + 'MySource_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php', + 'MySource_Sniffs_Debug_DebugCodeSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php', + 'MySource_Sniffs_Debug_FirebugConsoleSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php', + 'MySource_Sniffs_Objects_AssignThisSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php', + 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php', + 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php', + 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php', + 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php', + 'MySource_Sniffs_PHP_GetRequestDataSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php', + 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php', + 'MySource_Sniffs_Strings_JoinStringsSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php', + 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php', + 'PEAR_Sniffs_Commenting_ClassCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php', + 'PEAR_Sniffs_Commenting_FileCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php', + 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php', + 'PEAR_Sniffs_Commenting_InlineCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php', + 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php', + 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php', + 'PEAR_Sniffs_Files_IncludingFileSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php', + 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php', + 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php', + 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php', + 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php', + 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php', + 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', + 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php', + 'PHP_CodeSniffer' => $baseDir . '/CodeSniffer.php', + 'PHP_CodeSniffer_CLI' => $baseDir . '/CodeSniffer/CLI.php', + 'PHP_CodeSniffer_CommentParser_AbstractDocElement' => $baseDir . '/CodeSniffer/CommentParser/AbstractDocElement.php', + 'PHP_CodeSniffer_CommentParser_AbstractParser' => $baseDir . '/CodeSniffer/CommentParser/AbstractParser.php', + 'PHP_CodeSniffer_CommentParser_ClassCommentParser' => $baseDir . '/CodeSniffer/CommentParser/ClassCommentParser.php', + 'PHP_CodeSniffer_CommentParser_CommentElement' => $baseDir . '/CodeSniffer/CommentParser/CommentElement.php', + 'PHP_CodeSniffer_CommentParser_DocElement' => $baseDir . '/CodeSniffer/CommentParser/DocElement.php', + 'PHP_CodeSniffer_CommentParser_FunctionCommentParser' => $baseDir . '/CodeSniffer/CommentParser/FunctionCommentParser.php', + 'PHP_CodeSniffer_CommentParser_MemberCommentParser' => $baseDir . '/CodeSniffer/CommentParser/MemberCommentParser.php', + 'PHP_CodeSniffer_CommentParser_PairElement' => $baseDir . '/CodeSniffer/CommentParser/PairElement.php', + 'PHP_CodeSniffer_CommentParser_ParameterElement' => $baseDir . '/CodeSniffer/CommentParser/ParameterElement.php', + 'PHP_CodeSniffer_CommentParser_ParserException' => $baseDir . '/CodeSniffer/CommentParser/ParserException.php', + 'PHP_CodeSniffer_CommentParser_SingleElement' => $baseDir . '/CodeSniffer/CommentParser/SingleElement.php', + 'PHP_CodeSniffer_DocGenerators_Generator' => $baseDir . '/CodeSniffer/DocGenerators/Generator.php', + 'PHP_CodeSniffer_DocGenerators_HTML' => $baseDir . '/CodeSniffer/DocGenerators/HTML.php', + 'PHP_CodeSniffer_DocGenerators_Text' => $baseDir . '/CodeSniffer/DocGenerators/Text.php', + 'PHP_CodeSniffer_Exception' => $baseDir . '/CodeSniffer/Exception.php', + 'PHP_CodeSniffer_File' => $baseDir . '/CodeSniffer/File.php', + 'PHP_CodeSniffer_Report' => $baseDir . '/CodeSniffer/Report.php', + 'PHP_CodeSniffer_Reporting' => $baseDir . '/CodeSniffer/Reporting.php', + 'PHP_CodeSniffer_Reports_Checkstyle' => $baseDir . '/CodeSniffer/Reports/Checkstyle.php', + 'PHP_CodeSniffer_Reports_Csv' => $baseDir . '/CodeSniffer/Reports/Csv.php', + 'PHP_CodeSniffer_Reports_Emacs' => $baseDir . '/CodeSniffer/Reports/Emacs.php', + 'PHP_CodeSniffer_Reports_Full' => $baseDir . '/CodeSniffer/Reports/Full.php', + 'PHP_CodeSniffer_Reports_Gitblame' => $baseDir . '/CodeSniffer/Reports/Gitblame.php', + 'PHP_CodeSniffer_Reports_Hgblame' => $baseDir . '/CodeSniffer/Reports/Hgblame.php', + 'PHP_CodeSniffer_Reports_Json' => $baseDir . '/CodeSniffer/Reports/Json.php', + 'PHP_CodeSniffer_Reports_Junit' => $baseDir . '/CodeSniffer/Reports/Junit.php', + 'PHP_CodeSniffer_Reports_Notifysend' => $baseDir . '/CodeSniffer/Reports/Notifysend.php', + 'PHP_CodeSniffer_Reports_Source' => $baseDir . '/CodeSniffer/Reports/Source.php', + 'PHP_CodeSniffer_Reports_Summary' => $baseDir . '/CodeSniffer/Reports/Summary.php', + 'PHP_CodeSniffer_Reports_Svnblame' => $baseDir . '/CodeSniffer/Reports/Svnblame.php', + 'PHP_CodeSniffer_Reports_VersionControl' => $baseDir . '/CodeSniffer/Reports/VersionControl.php', + 'PHP_CodeSniffer_Reports_Xml' => $baseDir . '/CodeSniffer/Reports/Xml.php', + 'PHP_CodeSniffer_Sniff' => $baseDir . '/CodeSniffer/Sniff.php', + 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => $baseDir . '/CodeSniffer/Standards/AbstractPatternSniff.php', + 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => $baseDir . '/CodeSniffer/Standards/AbstractScopeSniff.php', + 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => $baseDir . '/CodeSniffer/Standards/AbstractVariableSniff.php', + 'PHP_CodeSniffer_Standards_IncorrectPatternException' => $baseDir . '/CodeSniffer/Standards/IncorrectPatternException.php', + 'PHP_CodeSniffer_Tokenizers_CSS' => $baseDir . '/CodeSniffer/Tokenizers/CSS.php', + 'PHP_CodeSniffer_Tokenizers_JS' => $baseDir . '/CodeSniffer/Tokenizers/JS.php', + 'PHP_CodeSniffer_Tokenizers_PHP' => $baseDir . '/CodeSniffer/Tokenizers/PHP.php', + 'PHP_CodeSniffer_Tokens' => $baseDir . '/CodeSniffer/Tokens.php', + 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1_Sniffs_Files_SideEffectsSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php', + 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php', + 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', + 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php', + 'PSR2_Sniffs_Files_EndFileNewlineSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php', + 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php', + 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php', + 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php', + 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php', + 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php', + 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php', + 'Squiz_Sniffs_CSS_ColonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php', + 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php', + 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php', + 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php', + 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php', + 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php', + 'Squiz_Sniffs_CSS_IndentationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php', + 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_MissingColonSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php', + 'Squiz_Sniffs_CSS_NamedColoursSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php', + 'Squiz_Sniffs_CSS_OpacitySniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php', + 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php', + 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php', + 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php', + 'Squiz_Sniffs_Classes_ClassFileNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php', + 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php', + 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php', + 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php', + 'Squiz_Sniffs_Classes_ValidClassNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php', + 'Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php', + 'Squiz_Sniffs_Commenting_BlockCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php', + 'Squiz_Sniffs_Commenting_ClassCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php', + 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php', + 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php', + 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php', + 'Squiz_Sniffs_Commenting_FileCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php', + 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php', + 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php', + 'Squiz_Sniffs_Commenting_InlineCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php', + 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php', + 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php', + 'Squiz_Sniffs_Commenting_VariableCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php', + 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php', + 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php', + 'Squiz_Sniffs_Debug_JSLintSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php', + 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php', + 'Squiz_Sniffs_Files_FileExtensionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php', + 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php', + 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php', + 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php', + 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php', + 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php', + 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php', + 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php', + 'Squiz_Sniffs_NamingConventions_ConstantCaseSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php', + 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php', + 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php', + 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php', + 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php', + 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php', + 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php', + 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php', + 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php', + 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php', + 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php', + 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php', + 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php', + 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php', + 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php', + 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php', + 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php', + 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php', + 'Squiz_Sniffs_PHP_EvalSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php', + 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php', + 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php', + 'Squiz_Sniffs_PHP_HeredocSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php', + 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php', + 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php', + 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php', + 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php', + 'Squiz_Sniffs_Scope_MethodScopeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php', + 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php', + 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php', + 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php', + 'Squiz_Sniffs_Strings_EchoedStringsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php', + 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', + 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php', + 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php', + 'Zend_Sniffs_Files_ClosingTagSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php', + 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php', +); diff --git a/codesniffer/vendor/composer/autoload_namespaces.php b/codesniffer/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..b7fc0125d --- /dev/null +++ b/codesniffer/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ += 50600 && !defined('HHVM_VERSION'); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit139aa91c62d198426cb28d1274c47616::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/codesniffer/vendor/composer/autoload_static.php b/codesniffer/vendor/composer/autoload_static.php new file mode 100644 index 000000000..b582df499 --- /dev/null +++ b/codesniffer/vendor/composer/autoload_static.php @@ -0,0 +1,267 @@ + __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php', + 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php', + 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php', + 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php', + 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php', + 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php', + 'Generic_Sniffs_Commenting_FixmeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php', + 'Generic_Sniffs_Commenting_TodoSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php', + 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php', + 'Generic_Sniffs_Debug_CSSLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php', + 'Generic_Sniffs_Debug_ClosureLinterSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php', + 'Generic_Sniffs_Debug_JSHintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php', + 'Generic_Sniffs_Files_ByteOrderMarkSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php', + 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php', + 'Generic_Sniffs_Files_InlineHTMLSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php', + 'Generic_Sniffs_Files_LineEndingsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php', + 'Generic_Sniffs_Files_LineLengthSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php', + 'Generic_Sniffs_Files_LowercasedFilenameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php', + 'Generic_Sniffs_Files_OneClassPerFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php', + 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php', + 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php', + 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php', + 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php', + 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php', + 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php', + 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php', + 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php', + 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php', + 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php', + 'Generic_Sniffs_Metrics_NestingLevelSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php', + 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php', + 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php', + 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php', + 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php', + 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php', + 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php', + 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php', + 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php', + 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php', + 'Generic_Sniffs_PHP_SAPIUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php', + 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php', + 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php', + 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php', + 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php', + 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php', + 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php', + 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php', + 'MySource_Sniffs_Channels_ChannelExceptionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php', + 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php', + 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php', + 'MySource_Sniffs_Channels_IncludeSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php', + 'MySource_Sniffs_Channels_UnusedSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php', + 'MySource_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php', + 'MySource_Sniffs_Debug_DebugCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php', + 'MySource_Sniffs_Debug_FirebugConsoleSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php', + 'MySource_Sniffs_Objects_AssignThisSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php', + 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php', + 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php', + 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php', + 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php', + 'MySource_Sniffs_PHP_GetRequestDataSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php', + 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php', + 'MySource_Sniffs_Strings_JoinStringsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php', + 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php', + 'PEAR_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php', + 'PEAR_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php', + 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php', + 'PEAR_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php', + 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php', + 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php', + 'PEAR_Sniffs_Files_IncludingFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php', + 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php', + 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php', + 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php', + 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php', + 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php', + 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php', + 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', + 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php', + 'PHP_CodeSniffer' => __DIR__ . '/../..' . '/CodeSniffer.php', + 'PHP_CodeSniffer_CLI' => __DIR__ . '/../..' . '/CodeSniffer/CLI.php', + 'PHP_CodeSniffer_CommentParser_AbstractDocElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/AbstractDocElement.php', + 'PHP_CodeSniffer_CommentParser_AbstractParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/AbstractParser.php', + 'PHP_CodeSniffer_CommentParser_ClassCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ClassCommentParser.php', + 'PHP_CodeSniffer_CommentParser_CommentElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/CommentElement.php', + 'PHP_CodeSniffer_CommentParser_DocElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/DocElement.php', + 'PHP_CodeSniffer_CommentParser_FunctionCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/FunctionCommentParser.php', + 'PHP_CodeSniffer_CommentParser_MemberCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/MemberCommentParser.php', + 'PHP_CodeSniffer_CommentParser_PairElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/PairElement.php', + 'PHP_CodeSniffer_CommentParser_ParameterElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ParameterElement.php', + 'PHP_CodeSniffer_CommentParser_ParserException' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ParserException.php', + 'PHP_CodeSniffer_CommentParser_SingleElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/SingleElement.php', + 'PHP_CodeSniffer_DocGenerators_Generator' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/Generator.php', + 'PHP_CodeSniffer_DocGenerators_HTML' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/HTML.php', + 'PHP_CodeSniffer_DocGenerators_Text' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/Text.php', + 'PHP_CodeSniffer_Exception' => __DIR__ . '/../..' . '/CodeSniffer/Exception.php', + 'PHP_CodeSniffer_File' => __DIR__ . '/../..' . '/CodeSniffer/File.php', + 'PHP_CodeSniffer_Report' => __DIR__ . '/../..' . '/CodeSniffer/Report.php', + 'PHP_CodeSniffer_Reporting' => __DIR__ . '/../..' . '/CodeSniffer/Reporting.php', + 'PHP_CodeSniffer_Reports_Checkstyle' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Checkstyle.php', + 'PHP_CodeSniffer_Reports_Csv' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Csv.php', + 'PHP_CodeSniffer_Reports_Emacs' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Emacs.php', + 'PHP_CodeSniffer_Reports_Full' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Full.php', + 'PHP_CodeSniffer_Reports_Gitblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Gitblame.php', + 'PHP_CodeSniffer_Reports_Hgblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Hgblame.php', + 'PHP_CodeSniffer_Reports_Json' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Json.php', + 'PHP_CodeSniffer_Reports_Junit' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Junit.php', + 'PHP_CodeSniffer_Reports_Notifysend' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Notifysend.php', + 'PHP_CodeSniffer_Reports_Source' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Source.php', + 'PHP_CodeSniffer_Reports_Summary' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Summary.php', + 'PHP_CodeSniffer_Reports_Svnblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Svnblame.php', + 'PHP_CodeSniffer_Reports_VersionControl' => __DIR__ . '/../..' . '/CodeSniffer/Reports/VersionControl.php', + 'PHP_CodeSniffer_Reports_Xml' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Xml.php', + 'PHP_CodeSniffer_Sniff' => __DIR__ . '/../..' . '/CodeSniffer/Sniff.php', + 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractPatternSniff.php', + 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractScopeSniff.php', + 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractVariableSniff.php', + 'PHP_CodeSniffer_Standards_IncorrectPatternException' => __DIR__ . '/../..' . '/CodeSniffer/Standards/IncorrectPatternException.php', + 'PHP_CodeSniffer_Tokenizers_CSS' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/CSS.php', + 'PHP_CodeSniffer_Tokenizers_JS' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/JS.php', + 'PHP_CodeSniffer_Tokenizers_PHP' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/PHP.php', + 'PHP_CodeSniffer_Tokens' => __DIR__ . '/../..' . '/CodeSniffer/Tokens.php', + 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1_Sniffs_Files_SideEffectsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php', + 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php', + 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', + 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php', + 'PSR2_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php', + 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php', + 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php', + 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php', + 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php', + 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php', + 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php', + 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php', + 'Squiz_Sniffs_CSS_ColonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php', + 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php', + 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php', + 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php', + 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php', + 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php', + 'Squiz_Sniffs_CSS_IndentationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php', + 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php', + 'Squiz_Sniffs_CSS_MissingColonSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php', + 'Squiz_Sniffs_CSS_NamedColoursSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php', + 'Squiz_Sniffs_CSS_OpacitySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php', + 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php', + 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php', + 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php', + 'Squiz_Sniffs_Classes_ClassFileNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php', + 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php', + 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php', + 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php', + 'Squiz_Sniffs_Classes_ValidClassNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php', + 'Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php', + 'Squiz_Sniffs_Commenting_BlockCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php', + 'Squiz_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php', + 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php', + 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php', + 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php', + 'Squiz_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php', + 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php', + 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php', + 'Squiz_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php', + 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php', + 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php', + 'Squiz_Sniffs_Commenting_VariableCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php', + 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php', + 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php', + 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php', + 'Squiz_Sniffs_Debug_JSLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php', + 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php', + 'Squiz_Sniffs_Files_FileExtensionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php', + 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php', + 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php', + 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php', + 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php', + 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php', + 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php', + 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php', + 'Squiz_Sniffs_NamingConventions_ConstantCaseSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php', + 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php', + 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php', + 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php', + 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php', + 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php', + 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php', + 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php', + 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php', + 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php', + 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php', + 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php', + 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php', + 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php', + 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php', + 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php', + 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php', + 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php', + 'Squiz_Sniffs_PHP_EvalSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php', + 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php', + 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php', + 'Squiz_Sniffs_PHP_HeredocSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php', + 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php', + 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php', + 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php', + 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php', + 'Squiz_Sniffs_Scope_MethodScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php', + 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php', + 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php', + 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php', + 'Squiz_Sniffs_Strings_EchoedStringsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php', + 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php', + 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', + 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php', + 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php', + 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php', + 'Zend_Sniffs_Files_ClosingTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php', + 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->classMap = ComposerStaticInit139aa91c62d198426cb28d1274c47616::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/codesniffer/vendor/composer/installed.json b/codesniffer/vendor/composer/installed.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/codesniffer/vendor/composer/installed.json @@ -0,0 +1 @@ +[] diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 84dda519e..52c5fba3e 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -206,3 +206,80 @@ Feature: `wp cli completions` tasks """ And STDERR should be empty And the return code should be 0 + + Scenario: Bash Completion for global parameters + Given an empty directory + + When I run `wp cli completions --line="wp plugin list " --point=100` + Then STDOUT should contain: + """ + --path= + """ + And STDOUT should contain: + """ + --ssh= + """ + And STDOUT should contain: + """ + --http= + """ + And STDOUT should contain: + """ + --url= + """ + And STDOUT should contain: + """ + --user= + """ + And STDOUT should contain: + """ + --skip-plugins= + """ + And STDOUT should contain: + """ + --skip-themes= + """ + And STDOUT should contain: + """ + --skip-packages + """ + And STDOUT should contain: + """ + --require= + """ + And STDOUT should contain: + """ + --color + """ + And STDOUT should contain: + """ + --debug= + """ + And STDOUT should contain: + """ + --prompt= + """ + And STDOUT should contain: + """ + --quiet + """ + And STDOUT should not contain: + """ + --skip-packages= + """ + And STDOUT should not contain: + """ + --color= + """ + And STDOUT should not contain: + """ + --quiet= + """ + And STDERR should be empty + And the return code should be 0 + + When I run `wp cli completions --line="wp plugin list --path --p" --point=100` + Then STDOUT should contain: + """ + --prompt= + """ diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 13e40c5cd..235c9cefa 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -41,7 +41,6 @@ function __construct( $line ) { list( $command, $args, $assoc_args ) = $r; $spec = SynopsisParser::parse( $command->get_synopsis() ); -// var_dump( \WP_CLI::get_configurator()->get_spec() ); foreach ( $spec as $arg ) { if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { @@ -79,6 +78,7 @@ function __construct( $line ) { $this->add( $opt ); } } + foreach ( $this->get_global_parameters() as $param => $runtime ) { if ( isset( $assoc_args[ $param ] ) ) { continue; @@ -86,7 +86,7 @@ function __construct( $line ) { $opt = "--{$param}"; - if ( "" === $runtime ) { + if ( "" === $runtime || ! is_string( $runtime ) ) { $opt .= ' '; } else { $opt .= '='; From be692817872adb36cac54093ca45f58b44df81a7 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Thu, 29 Dec 2016 20:21:29 +0900 Subject: [PATCH 5200/5359] add /codesniffer to .gitignore --- .gitignore | 1 + codesniffer/.gitattributes | 10 - codesniffer/.gitignore | 2 - codesniffer/CodeSniffer.conf.dist | 9 - codesniffer/CodeSniffer.php | 2133 ------------ codesniffer/CodeSniffer/CLI.php | 877 ----- .../CommentParser/AbstractDocElement.php | 353 -- .../CommentParser/AbstractParser.php | 684 ---- .../CommentParser/ClassCommentParser.php | 341 -- .../CommentParser/CommentElement.php | 245 -- .../CodeSniffer/CommentParser/DocElement.php | 104 - .../CommentParser/FunctionCommentParser.php | 212 -- .../CommentParser/MemberCommentParser.php | 91 - .../CodeSniffer/CommentParser/PairElement.php | 171 - .../CommentParser/ParameterElement.php | 338 -- .../CommentParser/ParserException.php | 71 - .../CommentParser/SingleElement.php | 171 - .../CodeSniffer/DocGenerators/Generator.php | 186 -- .../CodeSniffer/DocGenerators/HTML.php | 294 -- .../CodeSniffer/DocGenerators/Text.php | 267 -- codesniffer/CodeSniffer/Exception.php | 33 - codesniffer/CodeSniffer/File.php | 2910 ----------------- codesniffer/CodeSniffer/Report.php | 81 - codesniffer/CodeSniffer/Reporting.php | 315 -- .../CodeSniffer/Reports/Checkstyle.php | 126 - codesniffer/CodeSniffer/Reports/Csv.php | 108 - codesniffer/CodeSniffer/Reports/Emacs.php | 108 - codesniffer/CodeSniffer/Reports/Full.php | 178 - codesniffer/CodeSniffer/Reports/Gitblame.php | 133 - codesniffer/CodeSniffer/Reports/Hgblame.php | 134 - codesniffer/CodeSniffer/Reports/Json.php | 114 - codesniffer/CodeSniffer/Reports/Junit.php | 148 - .../CodeSniffer/Reports/Notifysend.php | 262 -- codesniffer/CodeSniffer/Reports/Source.php | 235 -- codesniffer/CodeSniffer/Reports/Summary.php | 131 - codesniffer/CodeSniffer/Reports/Svnblame.php | 100 - .../CodeSniffer/Reports/VersionControl.php | 257 -- codesniffer/CodeSniffer/Reports/Xml.php | 129 - codesniffer/CodeSniffer/Sniff.php | 93 - .../Standards/AbstractPatternSniff.php | 961 ------ .../Standards/AbstractScopeSniff.php | 201 -- .../Standards/AbstractVariableSniff.php | 245 -- .../Classes/DuplicateClassNameStandard.xml | 27 - .../CodeAnalysis/EmptyStatementStandard.xml | 23 - .../ForLoopShouldBeWhileLoopStandard.xml | 23 - .../ForLoopWithTestFunctionCallStandard.xml | 24 - .../JumbledIncrementerStandard.xml | 25 - .../UnconditionalIfStatementStandard.xml | 39 - .../UnnecessaryFinalModifierStandard.xml | 29 - .../UnusedFunctionParameterStandard.xml | 25 - .../UselessOverridingMethodStandard.xml | 32 - .../Generic/Docs/Commenting/FixmeStandard.xml | 25 - .../Generic/Docs/Commenting/TodoStandard.xml | 25 - .../InlineControlStructureStandard.xml | 22 - .../Generic/Docs/Debug/CSSLintStandard.xml | 19 - .../Docs/Debug/ClosureLinterStandard.xml | 19 - .../Generic/Docs/Debug/JSHintStandard.xml | 19 - .../Docs/Files/ByteOrderMarkStandard.xml | 7 - .../Docs/Files/EndFileNewlineStandard.xml | 7 - .../Docs/Files/EndFileNoNewlineStandard.xml | 7 - .../Generic/Docs/Files/InlineHTMLStandard.xml | 24 - .../Docs/Files/LineEndingsStandard.xml | 7 - .../Generic/Docs/Files/LineLengthStandard.xml | 7 - .../Docs/Files/LowercasedFilenameStandard.xml | 7 - .../Docs/Files/OneClassPerFileStandard.xml | 29 - .../Files/OneInterfacePerFileStandard.xml | 29 - .../DisallowMultipleStatementsStandard.xml | 20 - .../MultipleStatementAlignmentStandard.xml | 56 - .../Formatting/NoSpaceAfterCastStandard.xml | 19 - .../Formatting/SpaceAfterCastStandard.xml | 19 - .../CallTimePassByReferenceStandard.xml | 31 - .../FunctionCallArgumentSpacingStandard.xml | 39 - .../OpeningFunctionBraceBsdAllmanStandard.xml | 24 - ...gFunctionBraceKernighanRitchieStandard.xml | 24 - .../Metrics/CyclomaticComplexityStandard.xml | 7 - .../Docs/Metrics/NestingLevelStandard.xml | 7 - .../CamelCapsFunctionNameStandard.xml | 23 - .../ConstructorNameStandard.xml | 29 - .../UpperCaseConstantNameStandard.xml | 29 - .../CharacterBeforePHPOpeningTagStandard.xml | 22 - .../Docs/PHP/ClosingPHPTagStandard.xml | 22 - .../Docs/PHP/DeprecatedFunctionsStandard.xml | 19 - .../Docs/PHP/DisallowShortOpenTagStandard.xml | 7 - .../Docs/PHP/ForbiddenFunctionsStandard.xml | 19 - .../Docs/PHP/LowerCaseConstantStandard.xml | 23 - .../Docs/PHP/LowerCaseKeywordStandard.xml | 19 - .../Docs/PHP/NoSilencedErrorsStandard.xml | 23 - .../Generic/Docs/PHP/SAPIUsageStandard.xml | 23 - .../Docs/PHP/UpperCaseConstantStandard.xml | 23 - .../UnnecessaryStringConcatStandard.xml | 19 - .../SubversionPropertiesStandard.xml | 7 - .../DisallowSpaceIndentStandard.xml | 7 - .../WhiteSpace/DisallowTabIndentStandard.xml | 7 - .../Docs/WhiteSpace/ScopeIndentStandard.xml | 23 - .../Classes/DuplicateClassNameSniff.php | 129 - .../CodeAnalysis/EmptyStatementSniff.php | 128 - .../ForLoopShouldBeWhileLoopSniff.php | 104 - .../ForLoopWithTestFunctionCallSniff.php | 113 - .../CodeAnalysis/JumbledIncrementerSniff.php | 148 - .../UnconditionalIfStatementSniff.php | 106 - .../UnnecessaryFinalModifierSniff.php | 98 - .../UnusedFunctionParameterSniff.php | 187 -- .../UselessOverridingMethodSniff.php | 180 - .../CodeAnalysis/VariableAnalysisSniff.php | 1498 --------- .../Generic/Sniffs/Commenting/FixmeSniff.php | 92 - .../Generic/Sniffs/Commenting/TodoSniff.php | 90 - .../InlineControlStructureSniff.php | 120 - .../Generic/Sniffs/Debug/CSSLintSniff.php | 117 - .../Sniffs/Debug/ClosureLinterSniff.php | 139 - .../Generic/Sniffs/Debug/JSHintSniff.php | 109 - .../Sniffs/Files/ByteOrderMarkSniff.php | 93 - .../Sniffs/Files/EndFileNewlineSniff.php | 95 - .../Sniffs/Files/EndFileNoNewlineSniff.php | 95 - .../Generic/Sniffs/Files/InlineHTMLSniff.php | 74 - .../Generic/Sniffs/Files/LineEndingsSniff.php | 115 - .../Generic/Sniffs/Files/LineLengthSniff.php | 160 - .../Sniffs/Files/LowercasedFilenameSniff.php | 76 - .../Sniffs/Files/OneClassPerFileSniff.php | 64 - .../Sniffs/Files/OneInterfacePerFileSniff.php | 64 - .../DisallowMultipleStatementsSniff.php | 88 - .../MultipleStatementAlignmentSniff.php | 304 -- .../Formatting/NoSpaceAfterCastSniff.php | 69 - .../Sniffs/Formatting/SpaceAfterCastSniff.php | 75 - .../CallTimePassByReferenceSniff.php | 151 - .../FunctionCallArgumentSpacingSniff.php | 141 - .../OpeningFunctionBraceBsdAllmanSniff.php | 121 - ...ningFunctionBraceKernighanRitchieSniff.php | 117 - .../Metrics/CyclomaticComplexitySniff.php | 129 - .../Sniffs/Metrics/NestingLevelSniff.php | 114 - .../CamelCapsFunctionNameSniff.php | 210 -- .../ConstructorNameSniff.php | 106 - .../UpperCaseConstantNameSniff.php | 247 -- .../PHP/CharacterBeforePHPOpeningTagSniff.php | 63 - .../Generic/Sniffs/PHP/ClosingPHPTagSniff.php | 64 - .../Sniffs/PHP/DeprecatedFunctionsSniff.php | 94 - .../Sniffs/PHP/DisallowShortOpenTagSniff.php | 85 - .../Sniffs/PHP/ForbiddenFunctionsSniff.php | 202 -- .../Sniffs/PHP/LowerCaseConstantSniff.php | 107 - .../Sniffs/PHP/LowerCaseKeywordSniff.php | 137 - .../Sniffs/PHP/NoSilencedErrorsSniff.php | 81 - .../Generic/Sniffs/PHP/SAPIUsageSniff.php | 81 - .../Sniffs/PHP/UpperCaseConstantSniff.php | 98 - .../Strings/UnnecessaryStringConcatSniff.php | 125 - .../SubversionPropertiesSniff.php | 206 -- .../WhiteSpace/DisallowSpaceIndentSniff.php | 86 - .../WhiteSpace/DisallowTabIndentSniff.php | 86 - .../Sniffs/WhiteSpace/ScopeIndentSniff.php | 437 --- .../CodeSniffer/Standards/Generic/ruleset.xml | 4 - .../Standards/IncorrectPatternException.php | 35 - .../Sniffs/CSS/BrowserSpecificStylesSniff.php | 102 - .../Sniffs/Channels/ChannelExceptionSniff.php | 76 - .../Channels/DisallowSelfActionsSniff.php | 137 - .../Sniffs/Channels/IncludeOwnSystemSniff.php | 112 - .../Sniffs/Channels/IncludeSystemSniff.php | 341 -- .../Sniffs/Channels/UnusedSystemSniff.php | 157 - .../Commenting/FunctionCommentSniff.php | 130 - .../MySource/Sniffs/Debug/DebugCodeSniff.php | 68 - .../Sniffs/Debug/FirebugConsoleSniff.php | 77 - .../Sniffs/Objects/AssignThisSniff.php | 94 - .../Objects/CreateWidgetTypeCallbackSniff.php | 228 -- .../Sniffs/Objects/DisallowNewWidgetSniff.php | 72 - .../Sniffs/PHP/AjaxNullComparisonSniff.php | 113 - .../Sniffs/PHP/EvalObjectFactorySniff.php | 126 - .../Sniffs/PHP/GetRequestDataSniff.php | 119 - .../Sniffs/PHP/ReturnFunctionValueSniff.php | 76 - .../Sniffs/Strings/JoinStringsSniff.php | 88 - .../Standards/MySource/ruleset.xml | 18 - .../Docs/Classes/ClassDeclarationStandard.xml | 22 - .../Docs/Commenting/ClassCommentStandard.xml | 177 - .../Docs/Commenting/FileCommentStandard.xml | 286 -- .../Commenting/FunctionCommentStandard.xml | 230 -- .../Docs/Commenting/InlineCommentStandard.xml | 19 - .../ControlSignatureStandard.xml | 36 - .../MultiLineConditionStandard.xml | 60 - .../PEAR/Docs/Files/IncludingFileStandard.xml | 24 - .../PEAR/Docs/Files/LineLengthStandard.xml | 7 - .../MultiLineAssignmentStandard.xml | 35 - .../FunctionCallSignatureStandard.xml | 19 - .../Functions/FunctionDeclarationStandard.xml | 41 - .../Functions/ValidDefaultValueStandard.xml | 25 - .../ValidClassNameStandard.xml | 23 - .../ValidFunctionNameStandard.xml | 23 - .../ValidVariableNameStandard.xml | 29 - .../ObjectOperatorIndentStandard.xml | 39 - .../WhiteSpace/ScopeClosingBraceStandard.xml | 23 - .../Docs/WhiteSpace/ScopeIndentStandard.xml | 29 - .../Sniffs/Classes/ClassDeclarationSniff.php | 125 - .../Sniffs/Commenting/ClassCommentSniff.php | 233 -- .../Sniffs/Commenting/FileCommentSniff.php | 797 ----- .../Commenting/FunctionCommentSniff.php | 490 --- .../Sniffs/Commenting/InlineCommentSniff.php | 70 - .../ControlSignatureSniff.php | 67 - .../MultiLineConditionSniff.php | 189 -- .../PEAR/Sniffs/Files/IncludingFileSniff.php | 137 - .../Formatting/MultiLineAssignmentSniff.php | 120 - .../Functions/FunctionCallSignatureSniff.php | 335 -- .../Functions/FunctionDeclarationSniff.php | 337 -- .../Functions/ValidDefaultValueSniff.php | 108 - .../NamingConventions/ValidClassNameSniff.php | 115 - .../ValidFunctionNameSniff.php | 285 -- .../ValidVariableNameSniff.php | 114 - .../WhiteSpace/ObjectOperatorIndentSniff.php | 174 - .../WhiteSpace/ScopeClosingBraceSniff.php | 147 - .../Sniffs/WhiteSpace/ScopeIndentSniff.php | 48 - .../CodeSniffer/Standards/PEAR/ruleset.xml | 39 - .../CodeSniffer/Standards/PHPCS/ruleset.xml | 27 - .../Docs/Classes/ClassDeclarationStandard.xml | 48 - .../PSR1/Docs/Files/SideEffectsStandard.xml | 27 - .../Sniffs/Classes/ClassDeclarationSniff.php | 78 - .../PSR1/Sniffs/Files/SideEffectsSniff.php | 226 -- .../Methods/CamelCapsMethodNameSniff.php | 92 - .../CodeSniffer/Standards/PSR1/ruleset.xml | 45 - .../Docs/Classes/ClassDeclarationStandard.xml | 23 - .../Classes/PropertyDeclarationStandard.xml | 62 - .../ControlStructureSpacingStandard.xml | 23 - .../ElseIfDeclarationStandard.xml | 27 - .../SwitchDeclarationStandard.xml | 104 - .../Docs/Files/EndFileNewlineStandard.xml | 7 - .../Methods/MethodDeclarationStandard.xml | 51 - .../NamespaceDeclarationStandard.xml | 22 - .../Namespaces/UseDeclarationStandard.xml | 57 - .../Sniffs/Classes/ClassDeclarationSniff.php | 318 -- .../Classes/PropertyDeclarationSniff.php | 115 - .../ControlStructureSpacingSniff.php | 91 - .../ElseIfDeclarationSniff.php | 68 - .../SwitchDeclarationSniff.php | 192 -- .../PSR2/Sniffs/Files/EndFileNewlineSniff.php | 97 - .../Methods/FunctionCallSignatureSniff.php | 81 - .../Sniffs/Methods/MethodDeclarationSniff.php | 118 - .../Namespaces/NamespaceDeclarationSniff.php | 79 - .../Sniffs/Namespaces/UseDeclarationSniff.php | 139 - .../CodeSniffer/Standards/PSR2/ruleset.xml | 186 -- .../Arrays/ArrayBracketSpacingStandard.xml | 19 - .../Docs/Arrays/ArrayDeclarationStandard.xml | 117 - .../LowercaseClassKeywordsStandard.xml | 23 - .../Classes/SelfMemberReferenceStandard.xml | 63 - .../DocCommentAlignmentStandard.xml | 39 - .../FunctionCommentThrowTagStandard.xml | 32 - .../ForEachLoopDeclarationStandard.xml | 39 - .../ForLoopDeclarationStandard.xml | 55 - .../LowercaseDeclarationStandard.xml | 23 - .../FunctionDuplicateArgumentStandard.xml | 23 - .../LowercaseFunctionKeywordsStandard.xml | 25 - .../Docs/Scope/StaticThisUsageStandard.xml | 31 - .../Docs/Strings/EchoedStringsStandard.xml | 19 - .../Docs/WhiteSpace/CastSpacingStandard.xml | 19 - .../FunctionOpeningBraceStandard.xml | 41 - .../LanguageConstructSpacingStandard.xml | 19 - .../ObjectOperatorSpacingStandard.xml | 19 - .../ScopeKeywordSpacingStandard.xml | 23 - .../WhiteSpace/SemicolonSpacingStandard.xml | 19 - .../Arrays/ArrayBracketSpacingSniff.php | 111 - .../Sniffs/Arrays/ArrayDeclarationSniff.php | 513 --- .../ClassDefinitionClosingBraceSpaceSniff.php | 103 - .../CSS/ClassDefinitionNameSpacingSniff.php | 118 - .../ClassDefinitionOpeningBraceSpaceSniff.php | 118 - .../Squiz/Sniffs/CSS/ColonSpacingSniff.php | 101 - .../Sniffs/CSS/ColourDefinitionSniff.php | 93 - .../DisallowMultipleStyleDefinitionsSniff.php | 81 - .../CSS/DuplicateClassDefinitionSniff.php | 113 - .../CSS/DuplicateStyleDefinitionSniff.php | 93 - .../Sniffs/CSS/EmptyClassDefinitionSniff.php | 73 - .../Sniffs/CSS/EmptyStyleDefinitionSniff.php | 73 - .../Squiz/Sniffs/CSS/ForbiddenStylesSniff.php | 185 -- .../Squiz/Sniffs/CSS/IndentationSniff.php | 128 - .../CSS/LowercaseStyleDefinitionSniff.php | 106 - .../Squiz/Sniffs/CSS/MissingColonSniff.php | 101 - .../Squiz/Sniffs/CSS/NamedColoursSniff.php | 107 - .../Squiz/Sniffs/CSS/OpacitySniff.php | 107 - .../Sniffs/CSS/SemicolonSpacingSniff.php | 81 - .../Squiz/Sniffs/CSS/ShorthandSizeSniff.php | 161 - .../Sniffs/Classes/ClassDeclarationSniff.php | 177 - .../Sniffs/Classes/ClassFileNameSniff.php | 86 - .../Sniffs/Classes/DuplicatePropertySniff.php | 100 - .../Classes/LowercaseClassKeywordsSniff.php | 85 - .../Classes/SelfMemberReferenceSniff.php | 171 - .../Sniffs/Classes/ValidClassNameSniff.php | 95 - .../CodeAnalysis/EmptyStatementSniff.php | 54 - .../Sniffs/Commenting/BlockCommentSniff.php | 246 -- .../Sniffs/Commenting/ClassCommentSniff.php | 254 -- .../ClosingDeclarationCommentSniff.php | 127 - .../Commenting/DocCommentAlignmentSniff.php | 151 - .../Commenting/EmptyCatchCommentSniff.php | 73 - .../Sniffs/Commenting/FileCommentSniff.php | 564 ---- .../Commenting/FunctionCommentSniff.php | 818 ----- .../FunctionCommentThrowTagSniff.php | 215 -- .../Sniffs/Commenting/InlineCommentSniff.php | 272 -- .../LongConditionClosingCommentSniff.php | 191 -- .../Commenting/PostStatementCommentSniff.php | 103 - .../Commenting/VariableCommentSniff.php | 345 -- .../ControlSignatureSniff.php | 70 - .../ElseIfDeclarationSniff.php | 67 - .../ForEachLoopDeclarationSniff.php | 144 - .../ForLoopDeclarationSniff.php | 143 - .../InlineIfDeclarationSniff.php | 136 - .../LowercaseDeclarationSniff.php | 86 - .../SwitchDeclarationSniff.php | 270 -- .../Squiz/Sniffs/Debug/JSLintSniff.php | 107 - .../Sniffs/Debug/JavaScriptLintSniff.php | 110 - .../Squiz/Sniffs/Files/FileExtensionSniff.php | 89 - .../Formatting/OperatorBracketSniff.php | 254 -- ...unctionDeclarationArgumentSpacingSniff.php | 300 -- .../Functions/FunctionDeclarationSniff.php | 55 - .../FunctionDuplicateArgumentSniff.php | 81 - .../Sniffs/Functions/GlobalFunctionSniff.php | 78 - .../LowercaseFunctionKeywordsSniff.php | 81 - .../MultiLineFunctionDeclarationSniff.php | 140 - .../NamingConventions/ConstantCaseSniff.php | 65 - .../ValidFunctionNameSniff.php | 74 - .../ValidVariableNameSniff.php | 241 -- .../DisallowObjectStringIndexSniff.php | 98 - .../Objects/ObjectInstantiationSniff.php | 83 - .../Sniffs/Objects/ObjectMemberCommaSniff.php | 84 - .../ComparisonOperatorUsageSniff.php | 210 -- .../IncrementDecrementUsageSniff.php | 234 -- .../Operators/ValidLogicalOperatorsSniff.php | 87 - .../Sniffs/PHP/CommentedOutCodeSniff.php | 228 -- .../PHP/DisallowBooleanStatementSniff.php | 74 - .../PHP/DisallowComparisonAssignmentSniff.php | 125 - .../Sniffs/PHP/DisallowInlineIfSniff.php | 74 - .../PHP/DisallowMultipleAssignmentsSniff.php | 180 - .../Sniffs/PHP/DisallowObEndFlushSniff.php | 68 - .../PHP/DisallowSizeFunctionsInLoopsSniff.php | 127 - .../Sniffs/PHP/DiscouragedFunctionsSniff.php | 57 - .../Squiz/Sniffs/PHP/EmbeddedPhpSniff.php | 263 -- .../Standards/Squiz/Sniffs/PHP/EvalSniff.php | 65 - .../Sniffs/PHP/ForbiddenFunctionsSniff.php | 71 - .../Squiz/Sniffs/PHP/GlobalKeywordSniff.php | 70 - .../Squiz/Sniffs/PHP/HeredocSniff.php | 68 - .../Squiz/Sniffs/PHP/InnerFunctionsSniff.php | 75 - .../Sniffs/PHP/LowercasePHPFunctionsSniff.php | 115 - .../Sniffs/PHP/NonExecutableCodeSniff.php | 272 -- .../Sniffs/Scope/MemberVarScopeSniff.php | 90 - .../Squiz/Sniffs/Scope/MethodScopeSniff.php | 77 - .../Sniffs/Scope/StaticThisUsageSniff.php | 99 - .../Strings/ConcatenationSpacingSniff.php | 71 - .../Sniffs/Strings/DoubleQuoteUsageSniff.php | 135 - .../Sniffs/Strings/EchoedStringsSniff.php | 84 - .../Sniffs/WhiteSpace/CastSpacingSniff.php | 77 - .../ControlStructureSpacingSniff.php | 209 -- .../FunctionClosingBraceSpaceSniff.php | 116 - .../FunctionOpeningBraceSpaceSniff.php | 127 - .../WhiteSpace/FunctionSpacingSniff.php | 193 -- .../LanguageConstructSpacingSniff.php | 96 - .../LogicalOperatorSpacingSniff.php | 106 - .../WhiteSpace/MemberVarSpacingSniff.php | 120 - .../WhiteSpace/ObjectOperatorSpacingSniff.php | 76 - .../WhiteSpace/OperatorSpacingSniff.php | 220 -- .../WhiteSpace/PropertyLabelSpacingSniff.php | 85 - .../WhiteSpace/ScopeClosingBraceSniff.php | 110 - .../WhiteSpace/ScopeKeywordSpacingSniff.php | 87 - .../WhiteSpace/SemicolonSpacingSniff.php | 86 - .../WhiteSpace/SuperfluousWhitespaceSniff.php | 231 -- .../CodeSniffer/Standards/Squiz/ruleset.xml | 81 - .../Zend/Docs/Debug/CodeAnalyzerStandard.xml | 25 - .../Zend/Docs/Files/ClosingTagStandard.xml | 22 - .../ValidVariableNameStandard.xml | 37 - .../Zend/Sniffs/Debug/CodeAnalyzerSniff.php | 125 - .../Zend/Sniffs/Files/ClosingTagSniff.php | 84 - .../ValidVariableNameSniff.php | 252 -- .../CodeSniffer/Standards/Zend/ruleset.xml | 32 - codesniffer/CodeSniffer/Tokenizers/CSS.php | 399 --- codesniffer/CodeSniffer/Tokenizers/JS.php | 1149 ------- codesniffer/CodeSniffer/Tokenizers/PHP.php | 769 ----- codesniffer/CodeSniffer/Tokens.php | 503 --- codesniffer/README.markdown | 64 - codesniffer/composer.json | 58 - codesniffer/composer.lock | 21 - codesniffer/licence.txt | 24 - codesniffer/scripts/phpcs | 44 - codesniffer/scripts/phpcs-svn-pre-commit | 223 -- codesniffer/scripts/phpcs.bat | 16 - codesniffer/vendor/autoload.php | 7 - codesniffer/vendor/composer/ClassLoader.php | 415 --- codesniffer/vendor/composer/LICENSE | 21 - .../vendor/composer/autoload_classmap.php | 257 -- .../vendor/composer/autoload_namespaces.php | 9 - codesniffer/vendor/composer/autoload_psr4.php | 9 - codesniffer/vendor/composer/autoload_real.php | 52 - .../vendor/composer/autoload_static.php | 267 -- codesniffer/vendor/composer/installed.json | 1 - 381 files changed, 1 insertion(+), 52443 deletions(-) delete mode 100644 codesniffer/.gitattributes delete mode 100644 codesniffer/.gitignore delete mode 100644 codesniffer/CodeSniffer.conf.dist delete mode 100644 codesniffer/CodeSniffer.php delete mode 100644 codesniffer/CodeSniffer/CLI.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/AbstractParser.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/CommentElement.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/DocElement.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/PairElement.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/ParameterElement.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/ParserException.php delete mode 100644 codesniffer/CodeSniffer/CommentParser/SingleElement.php delete mode 100644 codesniffer/CodeSniffer/DocGenerators/Generator.php delete mode 100644 codesniffer/CodeSniffer/DocGenerators/HTML.php delete mode 100644 codesniffer/CodeSniffer/DocGenerators/Text.php delete mode 100644 codesniffer/CodeSniffer/Exception.php delete mode 100644 codesniffer/CodeSniffer/File.php delete mode 100644 codesniffer/CodeSniffer/Report.php delete mode 100644 codesniffer/CodeSniffer/Reporting.php delete mode 100644 codesniffer/CodeSniffer/Reports/Checkstyle.php delete mode 100644 codesniffer/CodeSniffer/Reports/Csv.php delete mode 100644 codesniffer/CodeSniffer/Reports/Emacs.php delete mode 100644 codesniffer/CodeSniffer/Reports/Full.php delete mode 100644 codesniffer/CodeSniffer/Reports/Gitblame.php delete mode 100644 codesniffer/CodeSniffer/Reports/Hgblame.php delete mode 100644 codesniffer/CodeSniffer/Reports/Json.php delete mode 100644 codesniffer/CodeSniffer/Reports/Junit.php delete mode 100644 codesniffer/CodeSniffer/Reports/Notifysend.php delete mode 100644 codesniffer/CodeSniffer/Reports/Source.php delete mode 100644 codesniffer/CodeSniffer/Reports/Summary.php delete mode 100644 codesniffer/CodeSniffer/Reports/Svnblame.php delete mode 100644 codesniffer/CodeSniffer/Reports/VersionControl.php delete mode 100644 codesniffer/CodeSniffer/Reports/Xml.php delete mode 100644 codesniffer/CodeSniffer/Sniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Generic/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/IncorrectPatternException.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/MySource/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php delete mode 100644 codesniffer/CodeSniffer/Standards/Zend/ruleset.xml delete mode 100644 codesniffer/CodeSniffer/Tokenizers/CSS.php delete mode 100644 codesniffer/CodeSniffer/Tokenizers/JS.php delete mode 100644 codesniffer/CodeSniffer/Tokenizers/PHP.php delete mode 100644 codesniffer/CodeSniffer/Tokens.php delete mode 100644 codesniffer/README.markdown delete mode 100644 codesniffer/composer.json delete mode 100644 codesniffer/composer.lock delete mode 100644 codesniffer/licence.txt delete mode 100755 codesniffer/scripts/phpcs delete mode 100755 codesniffer/scripts/phpcs-svn-pre-commit delete mode 100755 codesniffer/scripts/phpcs.bat delete mode 100644 codesniffer/vendor/autoload.php delete mode 100644 codesniffer/vendor/composer/ClassLoader.php delete mode 100644 codesniffer/vendor/composer/LICENSE delete mode 100644 codesniffer/vendor/composer/autoload_classmap.php delete mode 100644 codesniffer/vendor/composer/autoload_namespaces.php delete mode 100644 codesniffer/vendor/composer/autoload_psr4.php delete mode 100644 codesniffer/vendor/composer/autoload_real.php delete mode 100644 codesniffer/vendor/composer/autoload_static.php delete mode 100644 codesniffer/vendor/composer/installed.json diff --git a/.gitignore b/.gitignore index 1e56307f8..ba2e83349 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ PHAR_BUILD_VERSION /vendor /*.phar /phpunit.xml.dist +/codesniffer diff --git a/codesniffer/.gitattributes b/codesniffer/.gitattributes deleted file mode 100644 index 2dc5d9e17..000000000 --- a/codesniffer/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -/tests export-ignore -/CodeSniffer/Standards/Generic/Tests export-ignore -/CodeSniffer/Standards/MySource/Tests export-ignore -/CodeSniffer/Standards/PEAR/Tests export-ignore -/CodeSniffer/Standards/PSR1/Tests export-ignore -/CodeSniffer/Standards/PSR2/Tests export-ignore -/CodeSniffer/Standards/Squiz/Tests export-ignore -/CodeSniffer/Standards/Zend/Tests export-ignore -.travis.yml export-ignore -package.xml export-ignore diff --git a/codesniffer/.gitignore b/codesniffer/.gitignore deleted file mode 100644 index 0974c5e03..000000000 --- a/codesniffer/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/CodeSniffer.conf -.idea/* diff --git a/codesniffer/CodeSniffer.conf.dist b/codesniffer/CodeSniffer.conf.dist deleted file mode 100644 index 62dc395cf..000000000 --- a/codesniffer/CodeSniffer.conf.dist +++ /dev/null @@ -1,9 +0,0 @@ - 'PSR2', - 'report_format' => 'summary', - 'show_warnings' => '0', - 'show_progress' => '1', - 'report_width' => '120', -) -?> diff --git a/codesniffer/CodeSniffer.php b/codesniffer/CodeSniffer.php deleted file mode 100644 index 8ab953e43..000000000 --- a/codesniffer/CodeSniffer.php +++ /dev/null @@ -1,2133 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -spl_autoload_register(array('PHP_CodeSniffer', 'autoload')); - -if (class_exists('PHP_CodeSniffer_Exception', true) === false) { - throw new Exception('Class PHP_CodeSniffer_Exception not found'); -} - -if (class_exists('PHP_CodeSniffer_File', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_File not found'); -} - -if (class_exists('PHP_CodeSniffer_Tokens', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Tokens not found'); -} - -if (class_exists('PHP_CodeSniffer_CLI', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CLI not found'); -} - -if (interface_exists('PHP_CodeSniffer_Sniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Interface PHP_CodeSniffer_Sniff not found'); -} - -/** - * PHP_CodeSniffer tokenises PHP code and detects violations of a - * defined set of coding standards. - * - * Standards are specified by classes that implement the PHP_CodeSniffer_Sniff - * interface. A sniff registers what token types it wishes to listen for, then - * PHP_CodeSniffer encounters that token, the sniff is invoked and passed - * information about where the token was found in the stack, and the token stack - * itself. - * - * Sniff files and their containing class must be prefixed with Sniff, and - * have an extension of .php. - * - * Multiple PHP_CodeSniffer operations can be performed by re-calling the - * process function with different parameters. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer -{ - - /** - * The current version. - * - * @var string - */ - const VERSION = '1.5.0RC4'; - - /** - * Package stability; either stable or beta. - * - * @var string - */ - const STABILITY = 'beta'; - - /** - * The file or directory that is currently being processed. - * - * @var string - */ - protected $file = ''; - - /** - * A cache of different token types, resolved into arrays. - * - * @var array() - * @see standardiseToken() - */ - private static $_resolveTokenCache = array(); - - /** - * The directories that the processed rulesets are in. - * - * This is declared static because it is also used in the - * autoloader to look for sniffs outside the PHPCS install. - * This way, standards designed to be installed inside PHPCS can - * also be used from outside the PHPCS Standards directory. - * - * @var string - */ - protected static $rulesetDirs = array(); - - /** - * The CLI object controlling the run. - * - * @var PHP_CodeSniffer_CLI - */ - public $cli = null; - - /** - * The Reporting object controlling report generation. - * - * @var PHP_CodeSniffer_Reporting - */ - public $reporting = null; - - /** - * An array of sniff objects that are being used to check files. - * - * @var array(PHP_CodeSniffer_Sniff) - */ - protected $listeners = array(); - - /** - * An array of sniffs that are being used to check files. - * - * @var array(string) - */ - protected $sniffs = array(); - - /** - * The listeners array, indexed by token type. - * - * @var array - */ - private $_tokenListeners = array(); - - /** - * An array of rules from the ruleset.xml file. - * - * It may be empty, indicating that the ruleset does not override - * any of the default sniff settings. - * - * @var array - */ - protected $ruleset = array(); - - /** - * An array of patterns to use for skipping files. - * - * @var array - */ - protected $ignorePatterns = array(); - - /** - * An array of extensions for files we will check. - * - * @var array - */ - public $allowedFileExtensions = array( - 'php' => 'PHP', - 'inc' => 'PHP', - 'js' => 'JS', - 'css' => 'CSS', - ); - - /** - * An array of variable types for param/var we will check. - * - * @var array(string) - */ - public static $allowedTypes = array( - 'array', - 'boolean', - 'float', - 'integer', - 'mixed', - 'object', - 'string', - 'resource', - 'callable', - ); - - - /** - * Constructs a PHP_CodeSniffer object. - * - * @param int $verbosity The verbosity level. - * 1: Print progress information. - * 2: Print tokenizer debug information. - * 3: Print sniff debug information. - * @param int $tabWidth The number of spaces each tab represents. - * If greater than zero, tabs will be replaced - * by spaces before testing each file. - * @param string $encoding The charset of the sniffed files. - * This is important for some reports that output - * with utf-8 encoding as you don't want it double - * encoding messages. - * @param bool $interactive If TRUE, will stop after each file with errors - * and wait for user input. - * - * @see process() - */ - public function __construct( - $verbosity=0, - $tabWidth=0, - $encoding='iso-8859-1', - $interactive=false - ) { - if (defined('PHP_CODESNIFFER_VERBOSITY') === false) { - define('PHP_CODESNIFFER_VERBOSITY', $verbosity); - } - - if (defined('PHP_CODESNIFFER_TAB_WIDTH') === false) { - define('PHP_CODESNIFFER_TAB_WIDTH', $tabWidth); - } - - if (defined('PHP_CODESNIFFER_ENCODING') === false) { - define('PHP_CODESNIFFER_ENCODING', $encoding); - } - - if (defined('PHP_CODESNIFFER_INTERACTIVE') === false) { - define('PHP_CODESNIFFER_INTERACTIVE', $interactive); - } - - if (defined('PHPCS_DEFAULT_ERROR_SEV') === false) { - define('PHPCS_DEFAULT_ERROR_SEV', 5); - } - - if (defined('PHPCS_DEFAULT_WARN_SEV') === false) { - define('PHPCS_DEFAULT_WARN_SEV', 5); - } - - // Set default CLI object in case someone is running us - // without using the command line script. - $this->cli = new PHP_CodeSniffer_CLI(); - $this->cli->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; - $this->cli->warningSeverity = PHPCS_DEFAULT_WARN_SEV; - $this->cli->dieOnUnknownArg = false; - - $this->reporting = new PHP_CodeSniffer_Reporting(); - - }//end __construct() - - - /** - * Autoload static method for loading classes and interfaces. - * - * @param string $className The name of the class or interface. - * - * @return void - */ - public static function autoload($className) - { - if (substr($className, 0, 4) === 'PHP_') { - $newClassName = substr($className, 4); - } else { - $newClassName = $className; - } - - $path = str_replace(array('_', '\\'), '/', $newClassName).'.php'; - - if (is_file(dirname(__FILE__).'/'.$path) === true) { - // Check standard file locations based on class name. - include dirname(__FILE__).'/'.$path; - } else if (is_file(dirname(__FILE__).'/CodeSniffer/Standards/'.$path) === true) { - // Check for included sniffs. - include dirname(__FILE__).'/CodeSniffer/Standards/'.$path; - } else { - // Check standard file locations based on the loaded rulesets. - foreach (self::$rulesetDirs as $rulesetDir) { - if (is_file(dirname($rulesetDir).'/'.$path) === true) { - include_once dirname($rulesetDir).'/'.$path; - return; - } - } - - // Everything else. - @include $path; - } - - }//end autoload() - - - /** - * Sets an array of file extensions that we will allow checking of. - * - * If the extension is one of the defaults, a specific tokenizer - * will be used. Otherwise, the PHP tokenizer will be used for - * all extensions passed. - * - * @param array $extensions An array of file extensions. - * - * @return void - */ - public function setAllowedFileExtensions(array $extensions) - { - $newExtensions = array(); - foreach ($extensions as $ext) { - if (isset($this->allowedFileExtensions[$ext]) === true) { - $newExtensions[$ext] = $this->allowedFileExtensions[$ext]; - } else { - $newExtensions[$ext] = 'PHP'; - } - } - - $this->allowedFileExtensions = $newExtensions; - - }//end setAllowedFileExtensions() - - - /** - * Sets an array of ignore patterns that we use to skip files and folders. - * - * Patterns are not case sensitive. - * - * @param array $patterns An array of ignore patterns. The pattern is the key - * and the value is either "absolute" or "relative", - * depending on how the pattern should be applied to a - * file path. - * - * @return void - */ - public function setIgnorePatterns(array $patterns) - { - $this->ignorePatterns = $patterns; - - }//end setIgnorePatterns() - - - /** - * Gets the array of ignore patterns. - * - * Optionally takes a listener to get ignore patterns specified - * for that sniff only. - * - * @param string $listener The listener to get patterns for. If NULL, all - * patterns are returned. - * - * @return array - */ - public function getIgnorePatterns($listener=null) - { - if ($listener === null) { - return $this->ignorePatterns; - } - - if (isset($this->ignorePatterns[$listener]) === true) { - return $this->ignorePatterns[$listener]; - } - - return array(); - - }//end getIgnorePatterns() - - - /** - * Sets the internal CLI object. - * - * @param object $cli The CLI object controlling the run. - * - * @return void - */ - public function setCli($cli) - { - $this->cli = $cli; - - }//end setCli() - - - /** - * Processes the files/directories that PHP_CodeSniffer was constructed with. - * - * @param string|array $files The files and directories to process. For - * directories, each sub directory will also - * be traversed for source files. - * @param string|array $standards The set of code sniffs we are testing - * against. - * @param array $restrictions The sniff codes to restrict the - * violations to. - * @param boolean $local If true, don't recurse into directories. - * - * @return void - * @throws PHP_CodeSniffer_Exception If files or standard are invalid. - */ - public function process($files, $standards, array $restrictions=array(), $local=false) - { - if (is_array($files) === false) { - $files = array($files); - } - - if (is_array($standards) === false) { - $standards = array($standards); - } - - // Reset the members. - $this->listeners = array(); - $this->sniffs = array(); - $this->ruleset = array(); - $this->_tokenListeners = array(); - self::$rulesetDirs = array(); - - // Ensure this option is enabled or else line endings will not always - // be detected properly for files created on a Mac with the /r line ending. - ini_set('auto_detect_line_endings', true); - - $sniffs = array(); - foreach ($standards as $standard) { - $installed = $this->getInstalledStandardPath($standard); - if ($installed !== null) { - $standard = $installed; - } else if (is_dir($standard) === true - && is_file(realpath($standard.'/ruleset.xml')) === true - ) { - $standard = realpath($standard.'/ruleset.xml'); - } - - if (PHP_CODESNIFFER_VERBOSITY === 1) { - $ruleset = simplexml_load_file($standard); - if ($ruleset !== false) { - $standardName = (string) $ruleset['name']; - } - - echo "Registering sniffs in the $standardName standard... "; - if (count($standards) > 1 || PHP_CODESNIFFER_VERBOSITY > 2) { - echo PHP_EOL; - } - } - - $sniffs = array_merge($sniffs, $this->processRuleset($standard)); - }//end foreach - - $sniffRestrictions = array(); - foreach ($restrictions as $sniffCode) { - $parts = explode('.', strtolower($sniffCode)); - $sniffRestrictions[] = $parts[0].'_sniffs_'.$parts[1].'_'.$parts[2].'sniff'; - } - - $this->registerSniffs($sniffs, $sniffRestrictions); - $this->populateTokenListeners(); - - if (PHP_CODESNIFFER_VERBOSITY === 1) { - $numSniffs = count($this->sniffs); - echo "DONE ($numSniffs sniffs registered)".PHP_EOL; - } - - // The SVN pre-commit calls process() to init the sniffs - // and ruleset so there may not be any files to process. - // But this has to come after that initial setup. - if (empty($files) === true) { - return; - } - - $cliValues = $this->cli->getCommandLineValues(); - $showProgress = $cliValues['showProgress']; - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Creating file list... '; - } - - $todo = $this->getFilesToProcess($files, $local); - $numFiles = count($todo); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo "DONE ($numFiles files in queue)".PHP_EOL; - } - - $numProcessed = 0; - $dots = 0; - $maxLength = strlen($numFiles); - $lastDir = ''; - foreach ($todo as $file) { - $this->file = $file; - $currDir = dirname($file); - if ($lastDir !== $currDir) { - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Changing into directory '.$currDir.PHP_EOL; - } - - $lastDir = $currDir; - } - - $phpcsFile = $this->processFile($file, null, $restrictions); - $numProcessed++; - - if (PHP_CODESNIFFER_VERBOSITY > 0 - || PHP_CODESNIFFER_INTERACTIVE === true - || $showProgress === false - ) { - continue; - } - - // Show progress information. - if ($phpcsFile === null) { - echo 'S'; - } else { - $errors = $phpcsFile->getErrorCount(); - $warnings = $phpcsFile->getWarningCount(); - if ($errors > 0) { - echo 'E'; - } else if ($warnings > 0) { - echo 'W'; - } else { - echo '.'; - } - } - - $dots++; - if ($dots === 60) { - $padding = ($maxLength - strlen($numProcessed)); - echo str_repeat(' ', $padding); - $percent = round($numProcessed / $numFiles * 100); - echo " $numProcessed / $numFiles ($percent%)".PHP_EOL; - $dots = 0; - } - }//end foreach - - if (PHP_CODESNIFFER_VERBOSITY === 0 - && PHP_CODESNIFFER_INTERACTIVE === false - && $showProgress === true - ) { - echo PHP_EOL.PHP_EOL; - } - - }//end process() - - - /** - * Processes a single ruleset and returns a list of the sniffs it represents. - * - * Rules founds within the ruleset are processed immediately, but sniff classes - * are not registered by this method. - * - * @param string $rulesetPath The path to a ruleset XML file. - * @param int $depth How many nested processing steps we are in. This - * is only used for debug output. - * - * @return array - * @throws PHP_CodeSniffer_Exception If the ruleset path is invalid. - */ - public function processRuleset($rulesetPath, $depth=0) - { - $rulesetPath = realpath($rulesetPath); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "Processing ruleset $rulesetPath".PHP_EOL; - } - - $ruleset = simplexml_load_file($rulesetPath); - if ($ruleset === false) { - throw new PHP_CodeSniffer_Exception("Ruleset $rulesetPath is not valid"); - } - - $ownSniffs = array(); - $includedSniffs = array(); - $excludedSniffs = array(); - - $rulesetDir = dirname($rulesetPath); - self::$rulesetDirs[] = $rulesetDir; - - if (is_dir($rulesetDir.'/Sniffs') === true) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\tAdding sniff files from \".../".basename($rulesetDir)."/Sniffs/\" directory".PHP_EOL; - } - - $ownSniffs = $this->_expandSniffDirectory($rulesetDir.'/Sniffs', $depth); - } - - foreach ($ruleset->rule as $rule) { - if (isset($rule['ref']) === false) { - continue; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\tProcessing rule \"".$rule['ref'].'"'.PHP_EOL; - } - - $includedSniffs = array_merge( - $includedSniffs, - $this->_expandRulesetReference($rule['ref'], $rulesetDir, $depth) - ); - - if (isset($rule->exclude) === true) { - foreach ($rule->exclude as $exclude) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\tExcluding rule \"".$exclude['name'].'"'.PHP_EOL; - } - - $excludedSniffs = array_merge( - $excludedSniffs, - $this->_expandRulesetReference($exclude['name'], $rulesetDir, ($depth + 1)) - ); - } - } - - $this->_processRule($rule, $depth); - }//end foreach - - // Process custom ignore pattern rules. - foreach ($ruleset->{'exclude-pattern'} as $pattern) { - if (isset($pattern['type']) === false) { - $pattern['type'] = 'absolute'; - } - - $this->ignorePatterns[(string) $pattern] = (string) $pattern['type']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t=> added global ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL; - } - } - - $includedSniffs = array_unique(array_merge($ownSniffs, $includedSniffs)); - $excludedSniffs = array_unique($excludedSniffs); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $included = count($includedSniffs); - $excluded = count($excludedSniffs); - echo str_repeat("\t", $depth); - echo "=> Ruleset processing complete; included $included sniffs and excluded $excluded".PHP_EOL; - } - - // Merge our own sniff list with our externally included - // sniff list, but filter out any excluded sniffs. - $files = array(); - foreach ($includedSniffs as $sniff) { - if (in_array($sniff, $excludedSniffs) === true) { - continue; - } else { - $files[] = realpath($sniff); - } - } - - return $files; - - }//end processRuleset() - - - /** - * Expands a directory into a list of sniff files within. - * - * @param string $directory The path to a directory. - * @param int $depth How many nested processing steps we are in. This - * is only used for debug output. - * - * @return array - */ - private function _expandSniffDirectory($directory, $depth=0) - { - $sniffs = array(); - - if (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') === true) { - $rdi = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::FOLLOW_SYMLINKS); - } else { - $rdi = new RecursiveDirectoryIterator($directory); - } - - $di = new RecursiveIteratorIterator($rdi, 0, RecursiveIteratorIterator::CATCH_GET_CHILD); - - foreach ($di as $file) { - $fileName = $file->getFilename(); - - // Skip hidden files. - if (substr($fileName, 0, 1) === '.') { - continue; - } - - // We are only interested in PHP and sniff files. - $fileParts = explode('.', $fileName); - if (array_pop($fileParts) !== 'php') { - continue; - } - - $basename = basename($fileName, '.php'); - if (substr($basename, -5) !== 'Sniff') { - continue; - } - - $path = $file->getPathname(); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> $path".PHP_EOL; - } - - $sniffs[] = $path; - }//end foreach - - return $sniffs; - - }//end _expandSniffDirectory() - - - /** - * Expands a ruleset reference into a list of sniff files. - * - * @param string $ref The reference from the ruleset XML file. - * @param string $rulesetDir The directory of the ruleset XML file, used to - * evaluate relative paths. - * @param int $depth How many nested processing steps we are in. This - * is only used for debug output. - * - * @return array - * @throws PHP_CodeSniffer_Exception If the reference is invalid. - */ - private function _expandRulesetReference($ref, $rulesetDir, $depth=0) - { - // Ignore internal sniffs codes as they are used to only - // hide and change internal messages. - if (substr($ref, 0, 9) === 'Internal.') { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t* ignoring internal sniff code *".PHP_EOL; - } - - return array(); - } - - // As sniffs can't begin with a full stop, assume references in - // this format are relative paths and attempt to convert them - // to absolute paths. If this fails, let the reference run through - // the normal checks and have it fail as normal. - if (substr($ref, 0, 1) === '.') { - $realpath = realpath($rulesetDir.'/'.$ref); - if ($realpath !== false) { - $ref = $realpath; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> $ref".PHP_EOL; - } - } - } - - if (is_dir($ref) === false && is_file($ref) === false) { - // See if this is a whole standard being referenced. - $path = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$ref); - if (is_dir($path) === true) { - $ref = $path; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> $ref".PHP_EOL; - } - } else { - // Work out the sniff path. - $parts = explode('.', $ref); - - if (count($parts) === 1) { - // A whole standard? - $path = ''; - } else if (count($parts) === 2) { - // A directory of sniffs? - $path = '/Sniffs/'.$parts[1]; - } else { - // A single sniff? - $path = '/Sniffs/'.$parts[1].'/'.$parts[2].'Sniff.php'; - } - - $newRef = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$parts[0].$path); - if ($newRef === false) { - // The sniff is not locally installed, so check if it is being - // referenced as a remote sniff outside the install. We do this - // by looking through all directories where we have found ruleset - // files before, looking for ones for this particular standard, - // and seeing if it is in there. - foreach (self::$rulesetDirs as $dir) { - if (basename($dir) !== $parts[0]) { - continue; - } - - $newRef = realpath($dir.$path); - - if ($newRef !== false) { - $ref = $newRef; - } - } - } else { - $ref = $newRef; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> $ref".PHP_EOL; - } - } - }//end if - - if (is_dir($ref) === true) { - if (is_file($ref.'/ruleset.xml') === true) { - // We are referencing an external coding standard. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t* rule is referencing a standard using directory name; processing *".PHP_EOL; - } - - return $this->processRuleset($ref.'/ruleset.xml', ($depth + 2)); - } else { - // We are referencing a whole directory of sniffs. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t* rule is referencing a directory of sniffs *".PHP_EOL; - echo str_repeat("\t", $depth); - echo "\t\tAdding sniff files from directory".PHP_EOL; - } - - return $this->_expandSniffDirectory($ref, ($depth + 1)); - } - } else { - if (is_file($ref) === false) { - $error = "Referenced sniff \"$ref\" does not exist"; - throw new PHP_CodeSniffer_Exception($error); - } - - if (substr($ref, -9) === 'Sniff.php') { - // A single sniff. - return array($ref); - } else { - // Assume an external ruleset.xml file. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t* rule is referencing a standard using ruleset path; processing *".PHP_EOL; - } - - return $this->processRuleset($ref, ($depth + 2)); - } - }//end if - - }//end _expandRulesetReference() - - - /** - * Processes a rule from a ruleset XML file, overriding built-in defaults. - * - * @param SimpleXMLElement $rule The rule object from a ruleset XML file. - * @param int $depth How many nested processing steps we are in. - * This is only used for debug output. - * - * @return void - */ - private function _processRule($rule, $depth=0) - { - $code = (string) $rule['ref']; - - // Custom severity. - if (isset($rule->severity) === true) { - if (isset($this->ruleset[$code]) === false) { - $this->ruleset[$code] = array(); - } - - $this->ruleset[$code]['severity'] = (int) $rule->severity; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> severity set to ".(int) $rule->severity.PHP_EOL; - } - } - - // Custom message type. - if (isset($rule->type) === true) { - if (isset($this->ruleset[$code]) === false) { - $this->ruleset[$code] = array(); - } - - $this->ruleset[$code]['type'] = (string) $rule->type; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> message type set to ".(string) $rule->type.PHP_EOL; - } - } - - // Custom message. - if (isset($rule->message) === true) { - if (isset($this->ruleset[$code]) === false) { - $this->ruleset[$code] = array(); - } - - $this->ruleset[$code]['message'] = (string) $rule->message; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> message set to ".(string) $rule->message.PHP_EOL; - } - } - - // Custom properties. - if (isset($rule->properties) === true) { - foreach ($rule->properties->property as $prop) { - if (isset($this->ruleset[$code]) === false) { - $this->ruleset[$code] = array( - 'properties' => array(), - ); - } else if (isset($this->ruleset[$code]['properties']) === false) { - $this->ruleset[$code]['properties'] = array(); - } - - $name = (string) $prop['name']; - if (isset($prop['type']) === true - && (string) $prop['type'] === 'array' - ) { - $value = (string) $prop['value']; - $this->ruleset[$code]['properties'][$name] = explode(',', $value); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> array property \"$name\" set to \"$value\"".PHP_EOL; - } - } else { - $this->ruleset[$code]['properties'][$name] = (string) $prop['value']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> property \"$name\" set to \"".(string) $prop['value'].'"'.PHP_EOL; - } - } - }//end foreach - }//end if - - // Ignore patterns. - foreach ($rule->{'exclude-pattern'} as $pattern) { - if (isset($this->ignorePatterns[$code]) === false) { - $this->ignorePatterns[$code] = array(); - } - - if (isset($pattern['type']) === false) { - $pattern['type'] = 'absolute'; - } - - $this->ignorePatterns[$code][(string) $pattern] = (string) $pattern['type']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> added sniff-specific ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL; - } - } - - }//end _processRule() - - - /** - * Loads and stores sniffs objects used for sniffing files. - * - * @param array $files Paths to the sniff files to register. - * @param array $restrictions The sniff class names to restrict the allowed - * listeners to. - * - * @return void - */ - public function registerSniffs($files, $restrictions) - { - $listeners = array(); - - foreach ($files as $file) { - // Work out where the position of /StandardName/Sniffs/... is - // so we can determine what the class will be called. - $sniffPos = strrpos($file, DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR); - if ($sniffPos === false) { - continue; - } - - $slashPos = strrpos(substr($file, 0, $sniffPos), DIRECTORY_SEPARATOR); - if ($slashPos === false) { - continue; - } - - $className = substr($file, ($slashPos + 1)); - $className = substr($className, 0, -4); - $className = str_replace(DIRECTORY_SEPARATOR, '_', $className); - - // If they have specified a list of sniffs to restrict to, check - // to see if this sniff is allowed. - if (empty($restrictions) === false - && in_array(strtolower($className), $restrictions) === false - ) { - continue; - } - - include_once $file; - - // Support the use of PHP namespaces. If the class name we included - // contains namespace separators instead of underscores, use this as the - // class name from now on. - $classNameNS = str_replace('_', '\\', $className); - if (class_exists($classNameNS, false) === true) { - $className = $classNameNS; - } - - $listeners[$className] = $className; - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - echo "Registered $className".PHP_EOL; - } - }//end foreach - - $this->sniffs = $listeners; - - }//end registerSniffs() - - - /** - * Populates the array of PHP_CodeSniffer_Sniff's for this file. - * - * @return void - * @throws PHP_CodeSniffer_Exception If sniff registration fails. - */ - public function populateTokenListeners() - { - // Construct a list of listeners indexed by token being listened for. - $this->_tokenListeners = array(); - - foreach ($this->sniffs as $listenerClass) { - // Work out the internal code for this sniff. Detect usage of namespace - // separators instead of underscores to support PHP namespaces. - if (strstr($listenerClass, '\\') === false) { - $parts = explode('_', $listenerClass); - } else { - $parts = explode('\\', $listenerClass); - } - - $code = $parts[0].'.'.$parts[2].'.'.$parts[3]; - $code = substr($code, 0, -5); - - $this->listeners[$listenerClass] = new $listenerClass(); - - // Set custom properties. - if (isset($this->ruleset[$code]['properties']) === true) { - foreach ($this->ruleset[$code]['properties'] as $name => $value) { - $this->setSniffProperty($listenerClass, $name, $value); - } - } - - $tokenizers = array('PHP'); - $vars = get_class_vars($listenerClass); - if (isset($vars['supportedTokenizers']) === true) { - $tokenizers = $vars['supportedTokenizers']; - } - - $tokens = $this->listeners[$listenerClass]->register(); - if (is_array($tokens) === false) { - $msg = "Sniff $listenerClass register() method must return an array"; - throw new PHP_CodeSniffer_Exception($msg); - } - - foreach ($tokens as $token) { - if (isset($this->_tokenListeners[$token]) === false) { - $this->_tokenListeners[$token] = array(); - } - - if (in_array($this->listeners[$listenerClass], $this->_tokenListeners[$token], true) === false) { - $this->_tokenListeners[$token][] = array( - 'listener' => $this->listeners[$listenerClass], - 'class' => $listenerClass, - 'tokenizers' => $tokenizers, - ); - } - } - }//end foreach - - }//end populateTokenListeners() - - - /** - * Set a single property for a sniff. - * - * @param string $listenerClass The class name of the sniff. - * @param string $name The name of the property to change. - * @param string $value The new value of the property. - * - * @return void - */ - public function setSniffProperty($listenerClass, $name, $value) - { - // Setting a property for a sniff we are not using. - if (isset($this->listeners[$listenerClass]) === false) { - return; - } - - $name = trim($name); - if (is_string($value) === true) { - $value = trim($value); - } - - // Special case for booleans. - if ($value === 'true') { - $value = true; - } else if ($value === 'false') { - $value = false; - } - - $this->listeners[$listenerClass]->$name = $value; - - }//end setSniffProperty() - - - /** - * Get a list of files that will be processed. - * - * If passed directories, this method will find all files within them. - * The method will also perform file extension and ignore pattern filtering. - * - * @param string $paths A list of file or directory paths to process. - * @param boolean $local If true, only process 1 level of files in directories - * - * @return array - * @throws Exception If there was an error opening a directory. - * @see shouldProcessFile() - */ - public function getFilesToProcess($paths, $local=false) - { - $files = array(); - - foreach ($paths as $path) { - if (is_dir($path) === true) { - if ($local === true) { - $di = new DirectoryIterator($path); - } else { - $di = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($path), - 0, - RecursiveIteratorIterator::CATCH_GET_CHILD - ); - } - - foreach ($di as $file) { - // Check if the file exists after all symlinks are resolved. - $filePath = realpath($file->getPathname()); - if ($filePath === false) { - continue; - } - - if (is_dir($filePath) === true) { - continue; - } - - if ($this->shouldProcessFile($file->getPathname(), $path) === false) { - continue; - } - - $files[] = $file->getPathname(); - }//end foreach - } else { - if ($this->shouldIgnoreFile($path, dirname($path)) === true) { - continue; - } - - $files[] = $path; - }//end if - }//end foreach - - return $files; - - }//end getFilesToProcess() - - - /** - * Checks filtering rules to see if a file should be checked. - * - * Checks both file extension filters and path ignore filters. - * - * @param string $path The path to the file being checked. - * @param string $basedir The directory to use for relative path checks. - * - * @return bool - */ - public function shouldProcessFile($path, $basedir) - { - // Check that the file's extension is one we are checking. - // We are strict about checking the extension and we don't - // let files through with no extension or that start with a dot. - $fileName = basename($path); - $fileParts = explode('.', $fileName); - if ($fileParts[0] === $fileName || $fileParts[0] === '') { - return false; - } - - // Checking multi-part file extensions, so need to create a - // complete extension list and make sure one is allowed. - $extensions = array(); - array_shift($fileParts); - foreach ($fileParts as $part) { - $extensions[implode('.', $fileParts)] = 1; - array_shift($fileParts); - } - - $matches = array_intersect_key($extensions, $this->allowedFileExtensions); - if (empty($matches) === true) { - return false; - } - - // If the file's path matches one of our ignore patterns, skip it. - if ($this->shouldIgnoreFile($path, $basedir) === true) { - return false; - } - - return true; - - }//end shouldProcessFile() - - - /** - * Checks filtering rules to see if a file should be ignored. - * - * @param string $path The path to the file being checked. - * @param string $basedir The directory to use for relative path checks. - * - * @return bool - */ - public function shouldIgnoreFile($path, $basedir) - { - $relativePath = $path; - if (strpos($path, $basedir) === 0) { - // The +1 cuts off the directory separator as well. - $relativePath = substr($path, (strlen($basedir) + 1)); - } - - foreach ($this->ignorePatterns as $pattern => $type) { - if (is_array($pattern) === true) { - // A sniff specific ignore pattern. - continue; - } - - // Maintains backwards compatibility in case the ignore pattern does - // not have a relative/absolute value. - if (is_int($pattern) === true) { - $pattern = $type; - $type = 'absolute'; - } - - $replacements = array( - '\\,' => ',', - '*' => '.*', - ); - - // We assume a / directory separator, as do the exclude rules - // most developers write, so we need a special case for any system - // that is different. - if (DIRECTORY_SEPARATOR === '\\') { - $replacements['/'] = '\\\\'; - } - - $pattern = strtr($pattern, $replacements); - - if ($type === 'relative') { - $testPath = $relativePath; - } else { - $testPath = $path; - } - - if (preg_match("|{$pattern}|i", $testPath) === 1) { - return true; - } - }//end foreach - - return false; - - }//end shouldIgnoreFile() - - - /** - * Run the code sniffs over a single given file. - * - * Processes the file and runs the PHP_CodeSniffer sniffs to verify that it - * conforms with the standard. Returns the processed file object, or NULL - * if no file was processed due to error. - * - * @param string $file The file to process. - * @param string $contents The contents to parse. If NULL, the content - * is taken from the file system. - * @param array $restrictions The sniff codes to restrict the - * violations to. - * - * @return PHP_CodeSniffer_File - * @throws PHP_CodeSniffer_Exception If the file could not be processed. - * @see _processFile() - */ - public function processFile($file, $contents=null, $restrictions=array()) - { - if ($contents === null && file_exists($file) === false) { - throw new PHP_CodeSniffer_Exception("Source file $file does not exist"); - } - - $filePath = realpath($file); - if ($filePath === false) { - $filePath = $file; - } - - // Before we go and spend time tokenizing this file, just check - // to see if there is a tag up top to indicate that the whole - // file should be ignored. It must be on one of the first two lines. - $firstContent = $contents; - if ($contents === null && is_readable($filePath) === true) { - $handle = fopen($filePath, 'r'); - if ($handle !== false) { - $firstContent = fgets($handle); - $firstContent .= fgets($handle); - fclose($handle); - - if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false) { - // We are ignoring the whole file. - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Ignoring '.basename($filePath).PHP_EOL; - } - - return null; - } - } - }//end if - - try { - $phpcsFile = $this->_processFile($file, $contents, $restrictions); - } catch (Exception $e) { - $trace = $e->getTrace(); - - $filename = $trace[0]['args'][0]; - if (is_object($filename) === true - && get_class($filename) === 'PHP_CodeSniffer_File' - ) { - $filename = $filename->getFilename(); - } else if (is_numeric($filename) === true) { - // See if we can find the PHP_CodeSniffer_File object. - foreach ($trace as $data) { - if (isset($data['args'][0]) === true - && ($data['args'][0] instanceof PHP_CodeSniffer_File) === true - ) { - $filename = $data['args'][0]->getFilename(); - } - } - } else if (is_string($filename) === false) { - $filename = (string) $filename; - } - - $error = 'An error occurred during processing; checking has been aborted. The error message was: '.$e->getMessage(); - - $phpcsFile = new PHP_CodeSniffer_File( - $filename, - $this->_tokenListeners, - $this->allowedFileExtensions, - $this->ruleset, - $restrictions, - $this - ); - - $phpcsFile->addError($error, null); - }//end try - - $cliValues = $this->cli->getCommandLineValues(); - - if (PHP_CODESNIFFER_INTERACTIVE === false) { - // Cache the report data for this file so we can unset it to save memory. - $this->reporting->cacheFileReport($phpcsFile, $cliValues); - return $phpcsFile; - } - - /* - Running interactively. - Print the error report for the current file and then wait for user input. - */ - - // Get current violations and then clear the list to make sure - // we only print violations for a single file each time. - $numErrors = null; - while ($numErrors !== 0) { - $numErrors = ($phpcsFile->getErrorCount() + $phpcsFile->getWarningCount()); - if ($numErrors === 0) { - continue; - } - - $reportClass = $this->reporting->factory('full'); - $reportData = $this->reporting->prepareFileReport($phpcsFile); - $reportClass->generateFileReport($reportData, $cliValues['showSources'], $cliValues['reportWidth']); - - echo ' to recheck, [s] to skip or [q] to quit : '; - $input = fgets(STDIN); - $input = trim($input); - - switch ($input) { - case 's': - break(2); - case 'q': - exit(0); - break; - default: - // Repopulate the sniffs because some of them save their state - // and only clear it when the file changes, but we are rechecking - // the same file. - $this->populateTokenListeners(); - $phpcsFile = $this->_processFile($file, $contents, $restrictions); - break; - } - }//end while - - return $phpcsFile; - - }//end processFile() - - - /** - * Process the sniffs for a single file. - * - * Does raw processing only. No interactive support or error checking. - * - * @param string $file The file to process. - * @param string $contents The contents to parse. If NULL, the content - * is taken from the file system. - * @param array $restrictions The sniff codes to restrict the - * violations to. - * - * @return PHP_CodeSniffer_File - * @see processFile() - */ - private function _processFile($file, $contents, $restrictions) - { - if (PHP_CODESNIFFER_VERBOSITY > 0) { - $startTime = time(); - echo 'Processing '.basename($file).' '; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo PHP_EOL; - } - } - - $phpcsFile = new PHP_CodeSniffer_File( - $file, - $this->_tokenListeners, - $this->allowedFileExtensions, - $this->ruleset, - $restrictions, - $this - ); - - $phpcsFile->start($contents); - $phpcsFile->cleanUp(); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - $timeTaken = (time() - $startTime); - if ($timeTaken === 0) { - echo 'DONE in < 1 second'; - } else if ($timeTaken === 1) { - echo 'DONE in 1 second'; - } else { - echo "DONE in $timeTaken seconds"; - } - - $errors = $phpcsFile->getErrorCount(); - $warnings = $phpcsFile->getWarningCount(); - echo " ($errors errors, $warnings warnings)".PHP_EOL; - } - - return $phpcsFile; - - }//end _processFile() - - - /** - * Generates documentation for a coding standard. - * - * @param string $standard The standard to generate docs for - * @param array $sniffs A list of sniffs to limit the docs to. - * @param string $generator The name of the generator class to use. - * - * @return void - */ - public function generateDocs($standard, array $sniffs=array(), $generator='Text') - { - if (class_exists('PHP_CodeSniffer_DocGenerators_'.$generator, true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_'.$generator.' not found'); - } - - $class = "PHP_CodeSniffer_DocGenerators_$generator"; - $generator = new $class($standard, $sniffs); - - $generator->generate(); - - }//end generateDocs() - - - /** - * Gets the array of PHP_CodeSniffer_Sniff's. - * - * @return array(PHP_CodeSniffer_Sniff) - */ - public function getSniffs() - { - return $this->listeners; - - }//end getSniffs() - - - /** - * Gets the array of PHP_CodeSniffer_Sniff's indexed by token type. - * - * @return array() - */ - public function getTokenSniffs() - { - return $this->_tokenListeners; - - }//end getTokenSniffs() - - - /** - * Takes a token produced from token_get_all() and produces a - * more uniform token. - * - * Note that this method also resolves T_STRING tokens into more discrete - * types, therefore there is no need to call resolveTstringToken() - * - * @param string|array $token The token to convert. - * - * @return array The new token. - */ - public static function standardiseToken($token) - { - if (is_array($token) === false) { - if (isset(self::$_resolveTokenCache[$token]) === true) { - $newToken = self::$_resolveTokenCache[$token]; - } else { - $newToken = self::resolveSimpleToken($token); - } - } else { - switch ($token[0]) { - case T_STRING: - // Some T_STRING tokens can be more specific. - $tokenType = strtolower($token[1]); - if (isset(self::$_resolveTokenCache[$tokenType]) === true) { - $newToken = self::$_resolveTokenCache[$tokenType]; - } else { - $newToken = self::resolveTstringToken($tokenType); - } - - break; - case T_CURLY_OPEN: - $newToken = array( - 'code' => T_OPEN_CURLY_BRACKET, - 'type' => 'T_OPEN_CURLY_BRACKET', - ); - break; - default: - $newToken = array( - 'code' => $token[0], - 'type' => token_name($token[0]), - ); - break; - }//end switch - - $newToken['content'] = $token[1]; - }//end if - - return $newToken; - - }//end standardiseToken() - - - /** - * Converts T_STRING tokens into more usable token names. - * - * The token should be produced using the token_get_all() function. - * Currently, not all T_STRING tokens are converted. - * - * @param string $token The T_STRING token to convert as constructed - * by token_get_all(). - * - * @return array The new token. - */ - public static function resolveTstringToken($token) - { - $newToken = array(); - switch ($token) { - case 'false': - $newToken['type'] = 'T_FALSE'; - break; - case 'true': - $newToken['type'] = 'T_TRUE'; - break; - case 'null': - $newToken['type'] = 'T_NULL'; - break; - case 'self': - $newToken['type'] = 'T_SELF'; - break; - case 'parent': - $newToken['type'] = 'T_PARENT'; - break; - default: - $newToken['type'] = 'T_STRING'; - break; - } - - $newToken['code'] = constant($newToken['type']); - - self::$_resolveTokenCache[$token] = $newToken; - return $newToken; - - }//end resolveTstringToken() - - - /** - * Converts simple tokens into a format that conforms to complex tokens - * produced by token_get_all(). - * - * Simple tokens are tokens that are not in array form when produced from - * token_get_all(). - * - * @param string $token The simple token to convert. - * - * @return array The new token in array format. - */ - public static function resolveSimpleToken($token) - { - $newToken = array(); - - switch ($token) { - case '{': - $newToken['type'] = 'T_OPEN_CURLY_BRACKET'; - break; - case '}': - $newToken['type'] = 'T_CLOSE_CURLY_BRACKET'; - break; - case '[': - $newToken['type'] = 'T_OPEN_SQUARE_BRACKET'; - break; - case ']': - $newToken['type'] = 'T_CLOSE_SQUARE_BRACKET'; - break; - case '(': - $newToken['type'] = 'T_OPEN_PARENTHESIS'; - break; - case ')': - $newToken['type'] = 'T_CLOSE_PARENTHESIS'; - break; - case ':': - $newToken['type'] = 'T_COLON'; - break; - case '.': - $newToken['type'] = 'T_STRING_CONCAT'; - break; - case '?': - $newToken['type'] = 'T_INLINE_THEN'; - break; - case ';': - $newToken['type'] = 'T_SEMICOLON'; - break; - case '=': - $newToken['type'] = 'T_EQUAL'; - break; - case '*': - $newToken['type'] = 'T_MULTIPLY'; - break; - case '/': - $newToken['type'] = 'T_DIVIDE'; - break; - case '+': - $newToken['type'] = 'T_PLUS'; - break; - case '-': - $newToken['type'] = 'T_MINUS'; - break; - case '%': - $newToken['type'] = 'T_MODULUS'; - break; - case '^': - $newToken['type'] = 'T_POWER'; - break; - case '&': - $newToken['type'] = 'T_BITWISE_AND'; - break; - case '|': - $newToken['type'] = 'T_BITWISE_OR'; - break; - case '<': - $newToken['type'] = 'T_LESS_THAN'; - break; - case '>': - $newToken['type'] = 'T_GREATER_THAN'; - break; - case '!': - $newToken['type'] = 'T_BOOLEAN_NOT'; - break; - case ',': - $newToken['type'] = 'T_COMMA'; - break; - case '@': - $newToken['type'] = 'T_ASPERAND'; - break; - case '$': - $newToken['type'] = 'T_DOLLAR'; - break; - case '`': - $newToken['type'] = 'T_BACKTICK'; - break; - default: - $newToken['type'] = 'T_NONE'; - break; - }//end switch - - $newToken['code'] = constant($newToken['type']); - $newToken['content'] = $token; - - self::$_resolveTokenCache[$token] = $newToken; - return $newToken; - - }//end resolveSimpleToken() - - - /** - * Returns true if the specified string is in the camel caps format. - * - * @param string $string The string the verify. - * @param boolean $classFormat If true, check to see if the string is in the - * class format. Class format strings must start - * with a capital letter and contain no - * underscores. - * @param boolean $public If true, the first character in the string - * must be an a-z character. If false, the - * character must be an underscore. This - * argument is only applicable if $classFormat - * is false. - * @param boolean $strict If true, the string must not have two capital - * letters next to each other. If false, a - * relaxed camel caps policy is used to allow - * for acronyms. - * - * @return boolean - */ - public static function isCamelCaps( - $string, - $classFormat=false, - $public=true, - $strict=true - ) { - // Check the first character first. - if ($classFormat === false) { - $legalFirstChar = ''; - if ($public === false) { - $legalFirstChar = '[_]'; - } - - if ($strict === false) { - // Can either start with a lowercase letter, or multiple uppercase - // in a row, representing an acronym. - $legalFirstChar .= '([A-Z]{2,}|[a-z])'; - } else { - $legalFirstChar .= '[a-z]'; - } - } else { - $legalFirstChar = '[A-Z]'; - } - - if (preg_match("/^$legalFirstChar/", $string) === 0) { - return false; - } - - // Check that the name only contains legal characters. - $legalChars = 'a-zA-Z0-9'; - if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) { - return false; - } - - if ($strict === true) { - // Check that there are not two capital letters next to each other. - $length = strlen($string); - $lastCharWasCaps = $classFormat; - - for ($i = 1; $i < $length; $i++) { - $ascii = ord($string{$i}); - if ($ascii >= 48 && $ascii <= 57) { - // The character is a number, so it cant be a capital. - $isCaps = false; - } else { - if (strtoupper($string{$i}) === $string{$i}) { - $isCaps = true; - } else { - $isCaps = false; - } - } - - if ($isCaps === true && $lastCharWasCaps === true) { - return false; - } - - $lastCharWasCaps = $isCaps; - } - }//end if - - return true; - - }//end isCamelCaps() - - - /** - * Returns true if the specified string is in the underscore caps format. - * - * @param string $string The string to verify. - * - * @return boolean - */ - public static function isUnderscoreName($string) - { - // If there are space in the name, it can't be valid. - if (strpos($string, ' ') !== false) { - return false; - } - - $validName = true; - $nameBits = explode('_', $string); - - if (preg_match('|^[A-Z]|', $string) === 0) { - // Name does not begin with a capital letter. - $validName = false; - } else { - foreach ($nameBits as $bit) { - if ($bit === '') { - continue; - } - - if ($bit{0} !== strtoupper($bit{0})) { - $validName = false; - break; - } - } - } - - return $validName; - - }//end isUnderscoreName() - - - /** - * Returns a valid variable type for param/var tag. - * - * If type is not one of the standard type, it must be a custom type. - * Returns the correct type name suggestion if type name is invalid. - * - * @param string $varType The variable type to process. - * - * @return string - */ - public static function suggestType($varType) - { - if ($varType === '') { - return ''; - } - - if (in_array($varType, self::$allowedTypes) === true) { - return $varType; - } else { - $lowerVarType = strtolower($varType); - switch ($lowerVarType) { - case 'bool': - return 'boolean'; - case 'double': - case 'real': - return 'float'; - case 'int': - return 'integer'; - case 'array()': - return 'array'; - }//end switch - - if (strpos($lowerVarType, 'array(') !== false) { - // Valid array declaration: - // array, array(type), array(type1 => type2). - $matches = array(); - $pattern = '/^array\(\s*([^\s^=^>]*)(\s*=>\s*(.*))?\s*\)/i'; - if (preg_match($pattern, $varType, $matches) !== 0) { - $type1 = ''; - if (isset($matches[1]) === true) { - $type1 = $matches[1]; - } - - $type2 = ''; - if (isset($matches[3]) === true) { - $type2 = $matches[3]; - } - - $type1 = self::suggestType($type1); - $type2 = self::suggestType($type2); - if ($type2 !== '') { - $type2 = ' => '.$type2; - } - - return "array($type1$type2)"; - } else { - return 'array'; - }//end if - } else if (in_array($lowerVarType, self::$allowedTypes) === true) { - // A valid type, but not lower cased. - return $lowerVarType; - } else { - // Must be a custom type name. - return $varType; - }//end if - }//end if - - }//end suggestType() - - - /** - * Get a list of all coding standards installed. - * - * Coding standards are directories located in the - * CodeSniffer/Standards directory. Valid coding standards - * include a Sniffs subdirectory. - * - * @param boolean $includeGeneric If true, the special "Generic" - * coding standard will be included - * if installed. - * @param string $standardsDir A specific directory to look for standards - * in. If not specified, PHP_CodeSniffer will - * look in its default location. - * - * @return array - * @see isInstalledStandard() - */ - public static function getInstalledStandards( - $includeGeneric=false, - $standardsDir='' - ) { - $installedStandards = array(); - - if ($standardsDir === '') { - $standardsDir = dirname(__FILE__).'/CodeSniffer/Standards'; - } - - $di = new DirectoryIterator($standardsDir); - foreach ($di as $file) { - if ($file->isDir() === true && $file->isDot() === false) { - $filename = $file->getFilename(); - - // Ignore the special "Generic" standard. - if ($includeGeneric === false && $filename === 'Generic') { - continue; - } - - // Valid coding standard dirs include a standard class. - $csFile = $file->getPathname().'/ruleset.xml'; - if (is_file($csFile) === true) { - // We found a coding standard directory. - $installedStandards[] = $filename; - } - } - } - - return $installedStandards; - - }//end getInstalledStandards() - - - /** - * Determine if a standard is installed. - * - * Coding standards are directories located in the - * CodeSniffer/Standards directory. Valid coding standards - * include a Sniffs subdirectory. - * - * @param string $standard The name of the coding standard. - * - * @return boolean - * @see getInstalledStandards() - */ - public static function isInstalledStandard($standard) - { - $path = self::getInstalledStandardPath($standard); - if ($path !== null) { - return true; - } else { - // This could be a custom standard, installed outside our - // standards directory. - $ruleset = rtrim($standard, ' /\\').DIRECTORY_SEPARATOR.'ruleset.xml'; - if (is_file($ruleset) === true) { - return true; - } - - // Might also be an actual ruleset file itself. - // If it has an XML extension, let's at least try it. - if (is_file($standard) === true - && substr(strtolower($standard), -4) === '.xml' - ) { - return true; - } - } - - return false; - - }//end isInstalledStandard() - - - /** - * Return the path of an installed coding standard. - * - * Coding standards are directories located in the - * CodeSniffer/Standards directory. Valid coding standards - * include a Sniffs subdirectory. - * - * @param string $standard The name of the coding standard. - * - * @return string|null - */ - public static function getInstalledStandardPath($standard) - { - $path = realpath(dirname(__FILE__).'/CodeSniffer/Standards/'.$standard.'/ruleset.xml'); - if (is_file($path) === true) { - return $path; - } - - return null; - - }//end getInstalledStandardPath() - - - /** - * Get a single config value. - * - * Config data is stored in the data dir, in a file called - * CodeSniffer.conf. It is a simple PHP array. - * - * @param string $key The name of the config value. - * - * @return string - * @see setConfigData() - * @see getAllConfigData() - */ - public static function getConfigData($key) - { - $phpCodeSnifferConfig = self::getAllConfigData(); - - if ($phpCodeSnifferConfig === null) { - return null; - } - - if (isset($phpCodeSnifferConfig[$key]) === false) { - return null; - } - - return $phpCodeSnifferConfig[$key]; - - }//end getConfigData() - - - /** - * Set a single config value. - * - * Config data is stored in the data dir, in a file called - * CodeSniffer.conf. It is a simple PHP array. - * - * @param string $key The name of the config value. - * @param string|null $value The value to set. If null, the config - * entry is deleted, reverting it to the - * default value. - * @param boolean $temp Set this config data temporarily for this - * script run. This will not write the config - * data to the config file. - * - * @return boolean - * @see getConfigData() - * @throws PHP_CodeSniffer_Exception If the config file can not be written. - */ - public static function setConfigData($key, $value, $temp=false) - { - if ($temp === false) { - $configFile = dirname(__FILE__).'/CodeSniffer.conf'; - if (is_file($configFile) === false - && strpos('@data_dir@', '@data_dir') === false - ) { - // If data_dir was replaced, this is a PEAR install and we can - // use the PEAR data dir to store the conf file. - $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; - } - - if (is_file($configFile) === true - && is_writable($configFile) === false - ) { - $error = "Config file $configFile is not writable"; - throw new PHP_CodeSniffer_Exception($error); - } - } - - $phpCodeSnifferConfig = self::getAllConfigData(); - - if ($value === null) { - if (isset($phpCodeSnifferConfig[$key]) === true) { - unset($phpCodeSnifferConfig[$key]); - } - } else { - $phpCodeSnifferConfig[$key] = $value; - } - - if ($temp === false) { - $output = '<'.'?php'."\n".' $phpCodeSnifferConfig = '; - $output .= var_export($phpCodeSnifferConfig, true); - $output .= "\n?".'>'; - - if (file_put_contents($configFile, $output) === false) { - return false; - } - } - - $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig; - - return true; - - }//end setConfigData() - - - /** - * Get all config data in an array. - * - * @return string - * @see getConfigData() - */ - public static function getAllConfigData() - { - if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']) === true) { - return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']; - } - - $configFile = dirname(__FILE__).'/CodeSniffer.conf'; - if (is_file($configFile) === false) { - $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf'; - } - - if (is_file($configFile) === false) { - return null; - } - - include $configFile; - $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig; - return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']; - - }//end getAllConfigData() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CLI.php b/codesniffer/CodeSniffer/CLI.php deleted file mode 100644 index dd45123b1..000000000 --- a/codesniffer/CodeSniffer/CLI.php +++ /dev/null @@ -1,877 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (is_file(dirname(__FILE__).'/../CodeSniffer.php') === true) { - include_once dirname(__FILE__).'/../CodeSniffer.php'; -} else { - include_once 'PHP/CodeSniffer.php'; -} - -/** - * A class to process command line phpcs scripts. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CLI -{ - - /** - * An array of all values specified on the command line. - * - * @var array - */ - protected $values = array(); - - /** - * The minimum severity level errors must have to be displayed. - * - * @var bool - */ - public $errorSeverity = 0; - - /** - * The minimum severity level warnings must have to be displayed. - * - * @var bool - */ - public $warningSeverity = 0; - - /** - * Whether or not to kill the process when an unknown command line arg is found. - * - * If FALSE, arguments that are not command line options or file/directory paths - * will be ignored and execution will continue. - * - * @var bool - */ - public $dieOnUnknownArg = true; - - - /** - * Exits if the minimum requirements of PHP_CodSniffer are not met. - * - * @return array - */ - public function checkRequirements() - { - // Check the PHP version. - if (version_compare(PHP_VERSION, '5.1.2') === -1) { - echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL; - exit(2); - } - - if (extension_loaded('tokenizer') === false) { - echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL; - exit(2); - } - - }//end checkRequirements() - - - /** - * Get a list of default values for all possible command line arguments. - * - * @return array - */ - public function getDefaults() - { - // The default values for config settings. - $defaults['files'] = array(); - $defaults['standard'] = null; - $defaults['verbosity'] = 0; - $defaults['interactive'] = false; - $defaults['explain'] = false; - $defaults['local'] = false; - $defaults['showSources'] = false; - $defaults['extensions'] = array(); - $defaults['sniffs'] = array(); - $defaults['ignored'] = array(); - $defaults['reportFile'] = null; - $defaults['generator'] = ''; - $defaults['reports'] = array(); - $defaults['errorSeverity'] = null; - $defaults['warningSeverity'] = null; - - $reportFormat = PHP_CodeSniffer::getConfigData('report_format'); - if ($reportFormat !== null) { - $defaults['reports'][$reportFormat] = null; - } - - $tabWidth = PHP_CodeSniffer::getConfigData('tab_width'); - if ($tabWidth === null) { - $defaults['tabWidth'] = 0; - } else { - $defaults['tabWidth'] = (int) $tabWidth; - } - - $encoding = PHP_CodeSniffer::getConfigData('encoding'); - if ($encoding === null) { - $defaults['encoding'] = 'iso-8859-1'; - } else { - $defaults['encoding'] = strtolower($encoding); - } - - $severity = PHP_CodeSniffer::getConfigData('severity'); - if ($severity !== null) { - $defaults['errorSeverity'] = (int) $severity; - $defaults['warningSeverity'] = (int) $severity; - } - - $severity = PHP_CodeSniffer::getConfigData('error_severity'); - if ($severity !== null) { - $defaults['errorSeverity'] = (int) $severity; - } - - $severity = PHP_CodeSniffer::getConfigData('warning_severity'); - if ($severity !== null) { - $defaults['warningSeverity'] = (int) $severity; - } - - $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings'); - if ($showWarnings !== null) { - $showWarnings = (bool) $showWarnings; - if ($showWarnings === false) { - $defaults['warningSeverity'] = 0; - } - } - - $reportWidth = PHP_CodeSniffer::getConfigData('report_width'); - if ($reportWidth === null) { - $defaults['reportWidth'] = 80; - } else { - $defaults['reportWidth'] = (int) $reportWidth; - } - - $showProgress = PHP_CodeSniffer::getConfigData('show_progress'); - if ($showProgress === null) { - $defaults['showProgress'] = false; - } else { - $defaults['showProgress'] = (bool) $showProgress; - } - - return $defaults; - - }//end getDefaults() - - - /** - * Process the command line arguments and returns the values. - * - * @return array - */ - public function getCommandLineValues() - { - if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { - return array(); - } - - if (empty($this->values) === false) { - return $this->values; - } - - $values = $this->getDefaults(); - - for ($i = 1; $i < $_SERVER['argc']; $i++) { - $arg = $_SERVER['argv'][$i]; - if ($arg === '') { - continue; - } - - if ($arg{0} === '-') { - if ($arg === '-' || $arg === '--') { - // Empty argument, ignore it. - continue; - } - - if ($arg{1} === '-') { - $values - = $this->processLongArgument(substr($arg, 2), $i, $values); - } else { - $switches = str_split($arg); - foreach ($switches as $switch) { - if ($switch === '-') { - continue; - } - - $values = $this->processShortArgument($switch, $i, $values); - } - } - } else { - $values = $this->processUnknownArgument($arg, $i, $values); - }//end if - }//end for - - $this->values = $values; - return $values; - - }//end getCommandLineValues() - - - /** - * Processes a short (-e) command line argument. - * - * @param string $arg The command line argument. - * @param int $pos The position of the argument on the command line. - * @param array $values An array of values determined from CLI args. - * - * @return array The updated CLI values. - * @see getCommandLineValues() - */ - public function processShortArgument($arg, $pos, $values) - { - switch ($arg) { - case 'h': - case '?': - $this->printUsage(); - exit(0); - break; - case 'i' : - $this->printInstalledStandards(); - exit(0); - break; - case 'v' : - $values['verbosity']++; - break; - case 'l' : - $values['local'] = true; - break; - case 's' : - $values['showSources'] = true; - break; - case 'a' : - $values['interactive'] = true; - break; - case 'e': - $values['explain'] = true; - break; - case 'p' : - $values['showProgress'] = true; - break; - case 'd' : - $ini = explode('=', $_SERVER['argv'][($pos + 1)]); - $_SERVER['argv'][($pos + 1)] = ''; - if (isset($ini[1]) === true) { - ini_set($ini[0], $ini[1]); - } else { - ini_set($ini[0], true); - } - - break; - case 'n' : - $values['warningSeverity'] = 0; - break; - case 'w' : - $values['warningSeverity'] = null; - break; - default: - $values = $this->processUnknownArgument('-'.$arg, $pos, $values); - }//end switch - - return $values; - - }//end processShortArgument() - - - /** - * Processes a long (--example) command line argument. - * - * @param string $arg The command line argument. - * @param int $pos The position of the argument on the command line. - * @param array $values An array of values determined from CLI args. - * - * @return array The updated CLI values. - * @see getCommandLineValues() - */ - public function processLongArgument($arg, $pos, $values) - { - switch ($arg) { - case 'help': - $this->printUsage(); - exit(0); - break; - case 'version': - $phpcs = new PHP_CodeSniffer(); - echo 'PHP_CodeSniffer version '.$phpcs::VERSION.' ('.$phpcs::STABILITY.') '; - echo 'by Squiz (http://www.squiz.net)'.PHP_EOL; - exit(0); - break; - case 'config-set': - $key = $_SERVER['argv'][($pos + 1)]; - $value = $_SERVER['argv'][($pos + 2)]; - PHP_CodeSniffer::setConfigData($key, $value); - exit(0); - break; - case 'config-delete': - $key = $_SERVER['argv'][($pos + 1)]; - PHP_CodeSniffer::setConfigData($key, null); - exit(0); - break; - case 'config-show': - $data = PHP_CodeSniffer::getAllConfigData(); - print_r($data); - exit(0); - break; - default: - if (substr($arg, 0, 7) === 'sniffs=') { - $sniffs = substr($arg, 7); - $values['sniffs'] = explode(',', $sniffs); - } else if (substr($arg, 0, 12) === 'report-file=') { - $values['reportFile'] = realpath(substr($arg, 12)); - - // It may not exist and return false instead. - if ($values['reportFile'] === false) { - $values['reportFile'] = substr($arg, 12); - } - - if (is_dir($values['reportFile']) === true) { - echo 'ERROR: The specified report file path "'.$values['reportFile'].'" is a directory.'.PHP_EOL.PHP_EOL; - $this->printUsage(); - exit(2); - } - - $dir = dirname($values['reportFile']); - if (is_dir($dir) === false) { - echo 'ERROR: The specified report file path "'.$values['reportFile'].'" points to a non-existent directory.'.PHP_EOL.PHP_EOL; - $this->printUsage(); - exit(2); - } - - if ($dir === '.') { - // Passed report file is a filename in the current directory. - $values['reportFile'] = getcwd().'/'.basename($values['reportFile']); - } else { - $dir = realpath(getcwd().'/'.$dir); - if ($dir !== false) { - // Report file path is relative. - $values['reportFile'] = $dir.'/'.basename($values['reportFile']); - } - } - } else if (substr($arg, 0, 13) === 'report-width=') { - $values['reportWidth'] = (int) substr($arg, 13); - } else if (substr($arg, 0, 7) === 'report=' - || substr($arg, 0, 7) === 'report-' - ) { - if ($arg[6] === '-') { - // This is a report with file output. - $split = strpos($arg, '='); - if ($split === false) { - $report = substr($arg, 7); - $output = null; - } else { - $report = substr($arg, 7, ($split - 7)); - $output = substr($arg, ($split + 1)); - if ($output === false) { - $output = null; - } else { - $dir = dirname($output); - if ($dir === '.') { - // Passed report file is a filename in the current directory. - $output = getcwd().'/'.basename($output); - } else { - $dir = realpath(getcwd().'/'.$dir); - if ($dir !== false) { - // Report file path is relative. - $output = $dir.'/'.basename($output); - } - } - }//end if - }//end if - } else { - // This is a single report. - $report = substr($arg, 7); - $output = null; - } - - $validReports = array( - 'full', - 'xml', - 'json', - 'checkstyle', - 'junit', - 'csv', - 'emacs', - 'notifysend', - 'source', - 'summary', - 'svnblame', - 'gitblame', - 'hgblame', - ); - - if (in_array($report, $validReports) === false) { - echo 'ERROR: Report type "'.$report.'" not known.'.PHP_EOL; - exit(2); - } - - $values['reports'][$report] = $output; - } else if (substr($arg, 0, 9) === 'standard=') { - $values['standard'] = explode(',', substr($arg, 9)); - } else if (substr($arg, 0, 11) === 'extensions=') { - $values['extensions'] = explode(',', substr($arg, 11)); - } else if (substr($arg, 0, 9) === 'severity=') { - $values['errorSeverity'] = (int) substr($arg, 9); - $values['warningSeverity'] = $values['errorSeverity']; - } else if (substr($arg, 0, 15) === 'error-severity=') { - $values['errorSeverity'] = (int) substr($arg, 15); - } else if (substr($arg, 0, 17) === 'warning-severity=') { - $values['warningSeverity'] = (int) substr($arg, 17); - } else if (substr($arg, 0, 7) === 'ignore=') { - // Split the ignore string on commas, unless the comma is escaped - // using 1 or 3 slashes (\, or \\\,). - $ignored = preg_split( - '/(?<=(?processUnknownArgument('--'.$arg, $pos, $values); - }//end if - - break; - }//end switch - - return $values; - - }//end processLongArgument() - - - /** - * Processes an unknown command line argument. - * - * Assumes all unknown arguments are files and folders to check. - * - * @param string $arg The command line argument. - * @param int $pos The position of the argument on the command line. - * @param array $values An array of values determined from CLI args. - * - * @return array The updated CLI values. - * @see getCommandLineValues() - */ - public function processUnknownArgument($arg, $pos, $values) - { - // We don't know about any additional switches; just files. - if ($arg{0} === '-') { - if ($this->dieOnUnknownArg === false) { - return $values; - } - - echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL; - $this->printUsage(); - exit(2); - } - - $file = realpath($arg); - if (file_exists($file) === false) { - if ($this->dieOnUnknownArg === false) { - return $values; - } - - echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL; - $this->printUsage(); - exit(2); - } else { - $values['files'][] = $file; - } - - return $values; - - }//end processUnknownArgument() - - - /** - * Runs PHP_CodeSniffer over files and directories. - * - * @param array $values An array of values determined from CLI args. - * - * @return int The number of error and warning messages shown. - * @see getCommandLineValues() - */ - public function process($values=array()) - { - if (empty($values) === true) { - $values = $this->getCommandLineValues(); - } - - if ($values['generator'] !== '') { - $phpcs = new PHP_CodeSniffer($values['verbosity']); - foreach ($values['standard'] as $standard) { - $phpcs->generateDocs( - $standard, - $values['files'], - $values['generator'] - ); - } - exit(0); - } - - // If no standard is supplied, get the default. - $values['standard'] = $this->validateStandard($values['standard']); - foreach ($values['standard'] as $standard) { - if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { - // They didn't select a valid coding standard, so help them - // out by letting them know which standards are installed. - echo 'ERROR: the "'.$standard.'" coding standard is not installed. '; - $this->printInstalledStandards(); - exit(2); - } - } - - if ($values['explain'] === true) { - foreach ($values['standard'] as $standard) { - $this->explainStandard($standard); - } - - exit(0); - } - - $fileContents = ''; - if (empty($values['files']) === true) { - // Check if they are passing in the file contents. - $handle = fopen('php://stdin', 'r'); - $fileContents = stream_get_contents($handle); - fclose($handle); - - if ($fileContents === '') { - // No files and no content passed in. - echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL; - $this->printUsage(); - exit(2); - } - } - - $phpcs = new PHP_CodeSniffer( - $values['verbosity'], - $values['tabWidth'], - $values['encoding'], - $values['interactive'] - ); - - // Set file extensions if they were specified. Otherwise, - // let PHP_CodeSniffer decide on the defaults. - if (empty($values['extensions']) === false) { - $phpcs->setAllowedFileExtensions($values['extensions']); - } - - // Set ignore patterns if they were specified. - if (empty($values['ignored']) === false) { - $phpcs->setIgnorePatterns($values['ignored']); - } - - // Set some convenience member vars. - if ($values['errorSeverity'] === null) { - $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; - } else { - $this->errorSeverity = $values['errorSeverity']; - } - - if ($values['warningSeverity'] === null) { - $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; - } else { - $this->warningSeverity = $values['warningSeverity']; - } - - if (empty($values['reports']) === true) { - $this->values['reports']['full'] = $values['reportFile']; - } - - $phpcs->setCli($this); - - $phpcs->process( - $values['files'], - $values['standard'], - $values['sniffs'], - $values['local'] - ); - - if ($fileContents !== '') { - $phpcs->processFile('STDIN', $fileContents); - } - - // Interactive runs don't require a final report and it doesn't really - // matter what the retun value is because we know it isn't being read - // by a script. - if ($values['interactive'] === true) { - return 0; - } - - return $this->printErrorReport( - $phpcs, - $values['reports'], - $values['showSources'], - $values['reportFile'], - $values['reportWidth'] - ); - - }//end process() - - - /** - * Prints the error report for the run. - * - * Note that this function may actually print multiple reports - * as the user may have specified a number of output formats. - * - * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing - * the errors. - * @param array $reports A list of reports to print. - * @param bool $showSources TRUE if report should show error sources - * (not used by all reports). - * @param string $reportFile A default file to log report output to. - * @param int $reportWidth How wide the screen reports should be. - * - * @return int The number of error and warning messages shown. - */ - public function printErrorReport( - PHP_CodeSniffer $phpcs, - $reports, - $showSources, - $reportFile, - $reportWidth - ) { - if (empty($reports) === true) { - $reports['full'] = $reportFile; - } - - $errors = 0; - $toScreen = false; - - foreach ($reports as $report => $output) { - if ($output === null) { - $output = $reportFile; - } - - if ($reportFile === null) { - $toScreen = true; - } - - // We don't add errors here because the number of - // errors reported by each report type will always be the - // same, so we really just need 1 number. - $errors = $phpcs->reporting->printReport( - $report, - $showSources, - $output, - $reportWidth - ); - } - - // Only print PHP_Timer output if no reports were - // printed to the screen so we don't put additional output - // in something like an XML report. If we are printing to screen, - // the report types would have already worked out who should - // print the timer info. - if ($toScreen === false - && PHP_CODESNIFFER_INTERACTIVE === false - && class_exists('PHP_Timer', false) === true - ) { - echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; - } - - // They should all return the same value, so it - // doesn't matter which return value we end up using. - return $errors; - - }//end printErrorReport() - - - /** - * Convert the passed standards into valid standards. - * - * Checks things like default values and case. - * - * @param array $standards The standards to validate. - * - * @return array - */ - public function validateStandard($standards) - { - if ($standards === null) { - // They did not supply a standard to use. - // Try to get the default from the config system. - $standard = PHP_CodeSniffer::getConfigData('default_standard'); - if ($standard === null) { - // Product default standard. - $standard = 'PEAR'; - } - - return array($standard); - } - - $cleaned = array(); - - // Check if the standard name is valid, or if the case is invalid. - $installedStandards = PHP_CodeSniffer::getInstalledStandards(); - foreach ($standards as $standard) { - foreach ($installedStandards as $validStandard) { - if (strtolower($standard) === strtolower($validStandard)) { - $standard = $validStandard; - break; - } - } - - $cleaned[] = $standard; - } - - return $cleaned; - - }//end validateStandard() - - - /** - * Prints a report showing the sniffs contained in a standard. - * - * @param string $standard The standard to validate. - * - * @return void - */ - public function explainStandard($standard) - { - $phpcs = new PHP_CodeSniffer(); - $phpcs->process(array(), $standard); - $sniffs = $phpcs->getSniffs(); - $sniffs = array_keys($sniffs); - sort($sniffs); - - ob_start(); - - $lastStandard = ''; - $lastCount = ''; - $sniffCount = count($sniffs); - $sniffs[] = '___'; - - echo PHP_EOL."The $standard standard contains $sniffCount sniffs".PHP_EOL; - - ob_start(); - - foreach ($sniffs as $sniff) { - $parts = explode('_', str_replace('\\', '_', $sniff)); - if ($lastStandard === '') { - $lastStandard = $parts[0]; - } - - if ($parts[0] !== $lastStandard) { - $sniffList = ob_get_contents(); - ob_end_clean(); - - echo PHP_EOL.$lastStandard.' ('.$lastCount.' sniffs)'.PHP_EOL; - echo str_repeat('-', strlen($lastStandard.$lastCount) + 10); - echo PHP_EOL; - echo $sniffList; - - $lastStandard = $parts[0]; - $lastCount = 0; - - ob_start(); - } - - echo ' '.$parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5).PHP_EOL; - $lastCount++; - }//end foreach - - ob_end_clean(); - - }//end explainStandard() - - - /** - * Prints out the usage information for this script. - * - * @return void - */ - public function printUsage() - { - echo 'Usage: phpcs [-nwlsaepvi] [-d key[=value]]'.PHP_EOL; - echo ' [--report=] [--report-file=] [--report-=] ...'.PHP_EOL; - echo ' [--report-width=] [--generator=] [--tab-width=]'.PHP_EOL; - echo ' [--severity=] [--error-severity=] [--warning-severity=]'.PHP_EOL; - echo ' [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL; - echo ' [--standard=] [--sniffs=] [--encoding=]'.PHP_EOL; - echo ' [--extensions=] [--ignore=] ...'.PHP_EOL; - echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL; - echo ' -w Print both warnings and errors (on by default)'.PHP_EOL; - echo ' -l Local directory only, no recursion'.PHP_EOL; - echo ' -s Show sniff codes in all reports'.PHP_EOL; - echo ' -a Run interactively'.PHP_EOL; - echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL; - echo ' -p Show progress of the run'.PHP_EOL; - echo ' -v[v][v] Print verbose output'.PHP_EOL; - echo ' -i Show a list of installed coding standards'.PHP_EOL; - echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL; - echo ' --help Print this help message'.PHP_EOL; - echo ' --version Print version information'.PHP_EOL; - echo ' One or more files and/or directories to check'.PHP_EOL; - echo ' A comma separated list of file extensions to check'.PHP_EOL; - echo ' (only valid if checking a directory)'.PHP_EOL; - echo ' A comma separated list of patterns to ignore files and directories'.PHP_EOL; - echo ' The encoding of the files being checked (default is iso-8859-1)'.PHP_EOL; - echo ' A comma separated list of sniff codes to limit the check to'.PHP_EOL; - echo ' (all sniffs must be part of the specified standard)'.PHP_EOL; - echo ' The minimum severity required to display an error or warning'.PHP_EOL; - echo ' The name or path of the coding standard to use'.PHP_EOL; - echo ' The number of spaces each tab represents'.PHP_EOL; - echo ' The name of a doc generator to use'.PHP_EOL; - echo ' (forces doc generation instead of checking)'.PHP_EOL; - echo ' Print either the "full", "xml", "checkstyle", "csv", "json"'.PHP_EOL; - echo ' "emacs", "source", "summary", "svnblame", "gitblame", "hgblame" or'.PHP_EOL; - echo ' "notifysend" report'.PHP_EOL; - echo ' (the "full" report is printed by default)'.PHP_EOL; - echo ' Write the report to the specified file path'.PHP_EOL; - echo ' How many columns wide screen reports should be printed'.PHP_EOL; - - }//end printUsage() - - - /** - * Prints out a list of installed coding standards. - * - * @return void - */ - public function printInstalledStandards() - { - $installedStandards = PHP_CodeSniffer::getInstalledStandards(); - $numStandards = count($installedStandards); - - if ($numStandards === 0) { - echo 'No coding standards are installed.'.PHP_EOL; - } else { - $lastStandard = array_pop($installedStandards); - if ($numStandards === 1) { - echo "The only coding standard installed is $lastStandard".PHP_EOL; - } else { - $standardList = implode(', ', $installedStandards); - $standardList .= ' and '.$lastStandard; - echo 'The installed coding standards are '.$standardList.PHP_EOL; - } - } - - }//end printInstalledStandards() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php b/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php deleted file mode 100644 index b804df232..000000000 --- a/codesniffer/CodeSniffer/CommentParser/AbstractDocElement.php +++ /dev/null @@ -1,353 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (interface_exists('PHP_CodeSniffer_CommentParser_DocElement', true) === false) { - $error = 'Interface PHP_CodeSniffer_CommentParser_DocElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to handle most of the parsing operations of a doc comment element. - * - * Extending classes should implement the getSubElements method to return - * a list of elements that the doc comment element contains, in the order that - * they appear in the element. For example a function parameter element has a - * type, a variable name and a comment. It should therefore implement the method - * as follows: - * - * - * protected function getSubElements() - * { - * return array( - * 'type', - * 'variable', - * 'comment', - * ); - * } - * - * - * The processSubElement will be called for each of the sub elements to allow - * the extending class to process them. So for the parameter element we would - * have: - * - * - * protected function processSubElement($name, $content, $whitespaceBefore) - * { - * if ($name === 'type') { - * echo 'The name of the variable was '.$content; - * } - * // Process other tags. - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_CommentParser_AbstractDocElement implements PHP_CodeSniffer_CommentParser_DocElement -{ - - /** - * The element previous to this element. - * - * @var PHP_CodeSniffer_CommentParser_DocElement - */ - protected $previousElement = null; - - /** - * The element proceeding this element. - * - * @var PHP_CodeSniffer_CommentParser_DocElement - */ - protected $nextElement = null; - - /** - * The whitespace the occurs after this element and its sub elements. - * - * @var string - */ - protected $afterWhitespace = ''; - - /** - * The tokens that comprise this element. - * - * @var array(string) - */ - protected $tokens = array(); - - /** - * The file this element is in. - * - * @var array(string) - */ - protected $phpcsFile = null; - - /** - * The tag that this element represents (omitting the @ symbol). - * - * @var string - */ - protected $tag = ''; - - - /** - * Constructs a Doc Element. - * - * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element - * that ocurred - * before this. - * @param array $tokens The tokens of - * this element. - * @param string $tag The doc - * element tag - * this element - * represents. - * @param PHP_CodeSniffer_File $phpcsFile The file that - * this element - * is in. - * - * @throws Exception If $previousElement in not a DocElement or if - * getSubElements() does not return an array. - */ - public function __construct( - $previousElement, - array $tokens, - $tag, - PHP_CodeSniffer_File $phpcsFile - ) { - if ($previousElement !== null - && ($previousElement instanceof PHP_CodeSniffer_CommentParser_DocElement) === false - ) { - $error = '$previousElement must be an instance of DocElement'; - throw new Exception($error); - } - - $this->phpcsFile = $phpcsFile; - - $this->previousElement = $previousElement; - if ($previousElement !== null) { - $this->previousElement->nextElement = $this; - } - - $this->tag = $tag; - $this->tokens = $tokens; - - $subElements = $this->getSubElements(); - - if (is_array($subElements) === false) { - throw new Exception('getSubElements() must return an array'); - } - - $whitespace = ''; - $currElem = 0; - $lastElement = ''; - $lastElementWhitespace = null; - $numSubElements = count($subElements); - - foreach ($this->tokens as $token) { - if (trim($token) === '') { - $whitespace .= $token; - } else { - if ($currElem < ($numSubElements - 1)) { - $element = $subElements[$currElem]; - $this->processSubElement($element, $token, $whitespace); - $whitespace = ''; - $currElem++; - } else { - if ($lastElementWhitespace === null) { - $lastElementWhitespace = $whitespace; - } - - $lastElement .= $whitespace.$token; - $whitespace = ''; - } - } - }//end foreach - - $lastElement = ltrim($lastElement); - $lastElementName = $subElements[($numSubElements - 1)]; - - // Process the last element in this tag. - $this->processSubElement( - $lastElementName, - $lastElement, - $lastElementWhitespace - ); - - $this->afterWhitespace = $whitespace; - - }//end __construct() - - - /** - * Returns the element that exists before this. - * - * @return PHP_CodeSniffer_CommentParser_DocElement - */ - public function getPreviousElement() - { - return $this->previousElement; - - }//end getPreviousElement() - - - /** - * Returns the element that exists after this. - * - * @return PHP_CodeSniffer_CommentParser_DocElement - */ - public function getNextElement() - { - return $this->nextElement; - - }//end getNextElement() - - - /** - * Returns the whitespace that exists before this element. - * - * @return string - */ - public function getWhitespaceBefore() - { - if ($this->previousElement !== null) { - return $this->previousElement->getWhitespaceAfter(); - } - - return ''; - - }//end getWhitespaceBefore() - - - /** - * Returns the whitespace that exists after this element. - * - * @return string - */ - public function getWhitespaceAfter() - { - return $this->afterWhitespace; - - }//end getWhitespaceAfter() - - - /** - * Returns the order that this element appears in the comment. - * - * @return int - */ - public function getOrder() - { - if ($this->previousElement === null) { - return 1; - } else { - return ($this->previousElement->getOrder() + 1); - } - - }//end getOrder() - - - /** - * Returns the tag that this element represents, ommiting the @ symbol. - * - * @return string - */ - public function getTag() - { - return $this->tag; - - }//end getTag() - - - /** - * Returns the raw content of this element, ommiting the tag. - * - * @return string - */ - public function getRawContent() - { - return implode('', $this->tokens); - - }//end getRawContent() - - - /** - * Returns the comment tokens. - * - * @return array - */ - public function getTokens() - { - return $this->tokens; - - }//end getTokens() - - - /** - * Returns the line in which this element first occured. - * - * @return int - */ - public function getLine() - { - if ($this->previousElement === null) { - // First element is on line one. - return 1; - } else { - $previousContent = $this->previousElement->getRawContent(); - $previousLine = $this->previousElement->getLine(); - - return ($previousLine + substr_count($previousContent, $this->phpcsFile->eolChar)); - } - - }//end getLine() - - - /** - * Returns the sub element names that make up this element in the order they - * appear in the element. - * - * @return array(string) - * @see processSubElement() - */ - abstract protected function getSubElements(); - - - /** - * Called to process each sub element as sepcified in the return value - * of getSubElements(). - * - * @param string $name The name of the element to process. - * @param string $content The content of the the element. - * @param string $whitespaceBefore The whitespace found before this element. - * - * @return void - * @see getSubElements() - */ - abstract protected function processSubElement( - $name, - $content, - $whitespaceBefore - ); - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/AbstractParser.php b/codesniffer/CodeSniffer/CommentParser/AbstractParser.php deleted file mode 100644 index f7f6a653b..000000000 --- a/codesniffer/CodeSniffer/CommentParser/AbstractParser.php +++ /dev/null @@ -1,684 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_CommentElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_CommentElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_ParserException', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_ParserException not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses doc comments. - * - * This abstract parser handles the following tags: - * - *
    - *
  • The short description and the long description
  • - *
  • @see
  • - *
  • @link
  • - *
  • @deprecated
  • - *
  • @since
  • - *
- * - * Extending classes should implement the getAllowedTags() method to return the - * tags that they wish to process, omitting the tags that this base class - * processes. When one of these tags in encountered, the process<tag_name> - * method is called on that class. For example, if a parser's getAllowedTags() - * method returns \@param as one of its tags, the processParam method will be - * called so that the parser can process such a tag. - * - * The method is passed the tokens that comprise this tag. The tokens array - * includes the whitespace that exists between the tokens, as separate tokens. - * It's up to the method to create a element that implements the DocElement - * interface, which should be returned. The AbstractDocElement class is a helper - * class that can be used to handle most of the parsing of the tokens into their - * individual sub elements. It requires that you construct it with the element - * previous to the element currently being processed, which can be acquired - * with the protected $previousElement class member of this class. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_CommentParser_AbstractParser -{ - - /** - * The comment element that appears in the doc comment. - * - * @var PHP_CodeSniffer_CommentParser_CommentElement - */ - protected $comment = null; - - /** - * The string content of the comment. - * - * @var string - */ - protected $commentString = ''; - - /** - * The file that the comment exists in. - * - * @var PHP_CodeSniffer_File - */ - protected $phpcsFile = null; - - /** - * The word tokens that appear in the comment. - * - * Whitespace tokens also appear in this stack, but are separate tokens - * from words. - * - * @var array(string) - */ - protected $words = array(); - - /** - * An array of all tags found in the comment. - * - * @var array(string) - */ - protected $foundTags = array(); - - /** - * The previous doc element that was processed. - * - * null if the current element being processed is the first element in the - * doc comment. - * - * @var PHP_CodeSniffer_CommentParser_DocElement - */ - protected $previousElement = null; - - /** - * A list of see elements that appear in this doc comment. - * - * @var array(PHP_CodeSniffer_CommentParser_SingleElement) - */ - protected $sees = array(); - - /** - * A list of see elements that appear in this doc comment. - * - * @var array(PHP_CodeSniffer_CommentParser_SingleElement) - */ - protected $deprecated = null; - - /** - * A list of see elements that appear in this doc comment. - * - * @var array(PHP_CodeSniffer_CommentParser_SingleElement) - */ - protected $links = array(); - - /** - * A element to represent \@since tags. - * - * @var PHP_CodeSniffer_CommentParser_SingleElement - */ - protected $since = null; - - /** - * True if the comment has been parsed. - * - * @var boolean - */ - private $_hasParsed = false; - - /** - * The tags that this class can process. - * - * @var array(string) - */ - private static $_tags = array( - 'see' => false, - 'link' => false, - 'deprecated' => true, - 'since' => true, - ); - - /** - * An array of unknown tags. - * - * @var array(string) - */ - public $unknown = array(); - - /** - * The order of tags. - * - * @var array(string) - */ - public $orders = array(); - - - /** - * Constructs a Doc Comment Parser. - * - * @param string $comment The comment to parse. - * @param PHP_CodeSniffer_File $phpcsFile The file that this comment is in. - */ - public function __construct($comment, PHP_CodeSniffer_File $phpcsFile) - { - $this->commentString = $comment; - $this->phpcsFile = $phpcsFile; - - }//end __construct() - - - /** - * Initiates the parsing of the doc comment. - * - * @return void - * @throws PHP_CodeSniffer_CommentParser_ParserException If the parser finds a - * problem with the - * comment. - */ - public function parse() - { - if ($this->_hasParsed === false) { - $this->_parse($this->commentString); - } - - }//end parse() - - - /** - * Parse the comment. - * - * @param string $comment The doc comment to parse. - * - * @return void - * @see _parseWords() - */ - private function _parse($comment) - { - // Firstly, remove the comment tags and any stars from the left side. - $lines = explode($this->phpcsFile->eolChar, $comment); - foreach ($lines as &$line) { - $line = trim($line); - - if ($line !== '') { - if (substr($line, 0, 3) === '/**') { - $line = substr($line, 3); - } else if (substr($line, -2, 2) === '*/') { - $line = substr($line, 0, -2); - } else if ($line{0} === '*') { - $line = substr($line, 1); - } - - // Add the words to the stack, preserving newlines. Other parsers - // might be interested in the spaces between words, so tokenize - // spaces as well as separate tokens. - $flags = (PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $words = preg_split( - '|(\s+)|', - $line.$this->phpcsFile->eolChar, - -1, - $flags - ); - - $this->words = array_merge($this->words, $words); - }//end if - }//end foreach - - $this->_parseWords(); - - }//end _parse() - - - /** - * Parses each word within the doc comment. - * - * @return void - * @see _parse() - * @throws PHP_CodeSniffer_CommentParser_ParserException If more than the allowed - * number of occurences of - * a tag is found. - */ - private function _parseWords() - { - $allowedTags = (self::$_tags + $this->getAllowedTags()); - $allowedTagNames = array_keys($allowedTags); - $prevTagPos = false; - $wordWasEmpty = true; - - foreach ($this->words as $wordPos => $word) { - if (trim($word) !== '') { - $wordWasEmpty = false; - } - - if ($word{0} === '@') { - $tag = substr($word, 1); - - // Filter out @ tags in the comment description. - // A real comment tag should have whitespace and a newline before it. - if (isset($this->words[($wordPos - 1)]) === false - || trim($this->words[($wordPos - 1)]) !== '' - ) { - continue; - } - - if (isset($this->words[($wordPos - 2)]) === false - || $this->words[($wordPos - 2)] !== $this->phpcsFile->eolChar - ) { - continue; - } - - $this->foundTags[] = array( - 'tag' => $tag, - 'line' => $this->getLine($wordPos), - 'pos' => $wordPos, - ); - - if ($prevTagPos !== false) { - // There was a tag before this so let's process it. - $prevTag = substr($this->words[$prevTagPos], 1); - $this->parseTag($prevTag, $prevTagPos, ($wordPos - 1)); - } else { - // There must have been a comment before this tag, so - // let's process that. - $this->parseTag('comment', 0, ($wordPos - 1)); - } - - $prevTagPos = $wordPos; - - if (in_array($tag, $allowedTagNames) === false) { - // This is not a tag that we process, but let's check to - // see if it is a tag we know about. If we don't know about it, - // we add it to a list of unknown tags. - $knownTags = array( - 'abstract', - 'access', - 'example', - 'filesource', - 'global', - 'ignore', - 'internal', - 'name', - 'static', - 'staticvar', - 'todo', - 'tutorial', - 'uses', - 'package_version@', - ); - - if (in_array($tag, $knownTags) === false) { - $this->unknown[] = array( - 'tag' => $tag, - 'line' => $this->getLine($wordPos), - 'pos' => $wordPos, - ); - } - }//end if - }//end if - }//end foreach - - // Only process this tag if there was something to process. - if ($wordWasEmpty === false) { - if ($prevTagPos === false) { - // There must only be a comment in this doc comment. - $this->parseTag('comment', 0, count($this->words)); - } else { - // Process the last tag element. - $prevTag = substr($this->words[$prevTagPos], 1); - $numWords = count($this->words); - $endPos = $numWords; - - if ($prevTag === 'package' || $prevTag === 'subpackage') { - // These are single-word tags, so anything after a newline - // is really a comment. - for ($endPos = $prevTagPos; $endPos < $numWords; $endPos++) { - if (strpos($this->words[$endPos], $this->phpcsFile->eolChar) !== false) { - break; - } - } - } - - $this->parseTag($prevTag, $prevTagPos, $endPos); - - if ($endPos !== $numWords) { - // Process the final comment, if it is not empty. - $tokens = array_slice($this->words, ($endPos + 1), $numWords); - $content = implode('', $tokens); - if (trim($content) !== '') { - $this->parseTag('comment', ($endPos + 1), $numWords); - } - } - }//end if - }//end if - - }//end _parseWords() - - - /** - * Returns the line that the token exists on in the doc comment. - * - * @param int $tokenPos The position in the words stack to find the line - * number for. - * - * @return int - */ - protected function getLine($tokenPos) - { - $newlines = 0; - for ($i = 0; $i < $tokenPos; $i++) { - $newlines += substr_count($this->phpcsFile->eolChar, $this->words[$i]); - } - - return $newlines; - - }//end getLine() - - - /** - * Parses see tag element within the doc comment. - * - * @param array(string) $tokens The word tokens that comprise this element. - * - * @return DocElement The element that represents this see comment. - */ - protected function parseSee($tokens) - { - $see = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'see', - $this->phpcsFile - ); - - $this->sees[] = $see; - return $see; - - }//end parseSee() - - - /** - * Parses the comment element that appears at the top of the doc comment. - * - * @param array(string) $tokens The word tokens that comprise this element. - * - * @return DocElement The element that represents this comment element. - */ - protected function parseComment($tokens) - { - $this->comment = new PHP_CodeSniffer_CommentParser_CommentElement( - $this->previousElement, - $tokens, - $this->phpcsFile - ); - - return $this->comment; - - }//end parseComment() - - - /** - * Parses \@deprecated tags. - * - * @param array(string) $tokens The word tokens that comprise this element. - * - * @return DocElement The element that represents this deprecated tag. - */ - protected function parseDeprecated($tokens) - { - $this->deprecated = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'deprecated', - $this->phpcsFile - ); - - return $this->deprecated; - - }//end parseDeprecated() - - - /** - * Parses \@since tags. - * - * @param array(string) $tokens The word tokens that comprise this element. - * - * @return SingleElement The element that represents this since tag. - */ - protected function parseSince($tokens) - { - $this->since = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'since', - $this->phpcsFile - ); - - return $this->since; - - }//end parseSince() - - - /** - * Parses \@link tags. - * - * @param array(string) $tokens The word tokens that comprise this element. - * - * @return SingleElement The element that represents this link tag. - */ - protected function parseLink($tokens) - { - $link = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'link', - $this->phpcsFile - ); - - $this->links[] = $link; - return $link; - - }//end parseLink() - - - /** - * Returns the see elements that appear in this doc comment. - * - * @return array(SingleElement) - */ - public function getSees() - { - return $this->sees; - - }//end getSees() - - - /** - * Returns the comment element that appears at the top of this doc comment. - * - * @return CommentElement - */ - public function getComment() - { - return $this->comment; - - }//end getComment() - - - /** - * Returns the word list. - * - * @return array - */ - public function getWords() - { - return $this->words; - - }//end getWords() - - - /** - * Returns the list of found tags. - * - * @return array - */ - public function getTags() - { - return $this->foundTags; - - }//end getTags() - - - /** - * Returns the link elements found in this comment. - * - * Returns an empty array if no links are found in the comment. - * - * @return array(SingleElement) - */ - public function getLinks() - { - return $this->links; - - }//end getLinks() - - - /** - * Returns the deprecated element found in this comment. - * - * Returns null if no element exists in the comment. - * - * @return SingleElement - */ - public function getDeprecated() - { - return $this->deprecated; - - }//end getDeprecated() - - - /** - * Returns the since element found in this comment. - * - * Returns null if no element exists in the comment. - * - * @return SingleElement - */ - public function getSince() - { - return $this->since; - - }//end getSince() - - - /** - * Parses the specified tag. - * - * @param string $tag The tag name to parse (omitting the @ symbol from - * the tag) - * @param int $start The position in the word tokens where this element - * started. - * @param int $end The position in the word tokens where this element - * ended. - * - * @return void - * @throws Exception If the process method for the tag cannot be found. - */ - protected function parseTag($tag, $start, $end) - { - $tokens = array_slice($this->words, ($start + 1), ($end - $start)); - - $allowedTags = (self::$_tags + $this->getAllowedTags()); - $allowedTagNames = array_keys($allowedTags); - if ($tag === 'comment' || in_array($tag, $allowedTagNames) === true) { - $method = 'parse'.$tag; - if (method_exists($this, $method) === false) { - $error = 'Method '.$method.' must be implemented to process '.$tag.' tags'; - throw new Exception($error); - } - - $this->previousElement = $this->$method($tokens); - } else { - $this->previousElement = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - $tag, - $this->phpcsFile - ); - } - - $this->orders[] = $tag; - - if ($this->previousElement === null - || ($this->previousElement instanceof PHP_CodeSniffer_CommentParser_DocElement) === false - ) { - throw new Exception('Parse method must return a DocElement'); - } - - }//end parseTag() - - - /** - * Returns a list of tags that this comment parser allows for it's comment. - * - * Each tag should indicate if only one entry of this tag can exist in the - * comment by specifying true as the array value, or false if more than one - * is allowed. Each tag should omit the @ symbol. Only tags other than - * the standard tags should be returned. - * - * @return array(string => boolean) - */ - protected abstract function getAllowedTags(); - - - /** - * Returns the tag orders (index => tagName). - * - * @return array - */ - public function getTagOrders() - { - return $this->orders; - - }//end getTagOrders() - - - /** - * Returns the unknown tags. - * - * @return array - */ - public function getUnknown() - { - return $this->unknown; - - }//end getUnknown() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php b/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php deleted file mode 100644 index 9bbef0bf9..000000000 --- a/codesniffer/CodeSniffer/CommentParser/ClassCommentParser.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_AbstractParser', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_AbstractParser not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses Class doc comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_ClassCommentParser extends PHP_CodeSniffer_CommentParser_AbstractParser -{ - - /** - * The package element of this class. - * - * @var SingleElement - */ - private $_package = null; - - /** - * The subpackage element of this class. - * - * @var SingleElement - */ - private $_subpackage = null; - - /** - * The version element of this class. - * - * @var SingleElement - */ - private $_version = null; - - /** - * The category element of this class. - * - * @var SingleElement - */ - private $_category = null; - - /** - * The copyright elements of this class. - * - * @var array(SingleElement) - */ - private $_copyrights = array(); - - /** - * The licence element of this class. - * - * @var PairElement - */ - private $_license = null; - - /** - * The author elements of this class. - * - * @var array(SingleElement) - */ - private $_authors = array(); - - - /** - * Returns the allowed tags withing a class comment. - * - * @return array(string => int) - */ - protected function getAllowedTags() - { - return array( - 'category' => false, - 'package' => true, - 'subpackage' => true, - 'author' => false, - 'copyright' => true, - 'license' => false, - 'version' => true, - ); - - }//end getAllowedTags() - - - /** - * Parses the license tag of this class comment. - * - * @param array $tokens The tokens that comprise this tag. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - protected function parseLicense($tokens) - { - $this->_license = new PHP_CodeSniffer_CommentParser_PairElement( - $this->previousElement, - $tokens, - 'license', - $this->phpcsFile - ); - - return $this->_license; - - }//end parseLicense() - - - /** - * Parses the copyright tags of this class comment. - * - * @param array $tokens The tokens that comprise this tag. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parseCopyright($tokens) - { - $copyright = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'copyright', - $this->phpcsFile - ); - - $this->_copyrights[] = $copyright; - return $copyright; - - }//end parseCopyright() - - - /** - * Parses the category tag of this class comment. - * - * @param array $tokens The tokens that comprise this tag. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parseCategory($tokens) - { - $this->_category = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'category', - $this->phpcsFile - ); - - return $this->_category; - - }//end parseCategory() - - - /** - * Parses the author tag of this class comment. - * - * @param array $tokens The tokens that comprise this tag. - * - * @return array(PHP_CodeSniffer_CommentParser_SingleElement) - */ - protected function parseAuthor($tokens) - { - $author = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'author', - $this->phpcsFile - ); - - $this->_authors[] = $author; - return $author; - - }//end parseAuthor() - - - /** - * Parses the version tag of this class comment. - * - * @param array $tokens The tokens that comprise this tag. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parseVersion($tokens) - { - $this->_version = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'version', - $this->phpcsFile - ); - - return $this->_version; - - }//end parseVersion() - - - /** - * Parses the package tag found in this test. - * - * @param array $tokens The tokens that comprise this var. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parsePackage($tokens) - { - $this->_package = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'package', - $this->phpcsFile - ); - - return $this->_package; - - }//end parsePackage() - - - /** - * Parses the package tag found in this test. - * - * @param array $tokens The tokens that comprise this var. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parseSubpackage($tokens) - { - $this->_subpackage = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'subpackage', - $this->phpcsFile - ); - - return $this->_subpackage; - - }//end parseSubpackage() - - - /** - * Returns the authors of this class comment. - * - * @return array(PHP_CodeSniffer_CommentParser_SingleElement) - */ - public function getAuthors() - { - return $this->_authors; - - }//end getAuthors() - - - /** - * Returns the version of this class comment. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - public function getVersion() - { - return $this->_version; - - }//end getVersion() - - - /** - * Returns the license of this class comment. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - public function getLicense() - { - return $this->_license; - - }//end getLicense() - - - /** - * Returns the copyrights of this class comment. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - public function getCopyrights() - { - return $this->_copyrights; - - }//end getCopyrights() - - - /** - * Returns the category of this class comment. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - public function getCategory() - { - return $this->_category; - - }//end getCategory() - - - /** - * Returns the package that this class belongs to. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - public function getPackage() - { - return $this->_package; - - }//end getPackage() - - - /** - * Returns the subpackage that this class belongs to. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - public function getSubpackage() - { - return $this->_subpackage; - - }//end getSubpackage() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/CommentElement.php b/codesniffer/CodeSniffer/CommentParser/CommentElement.php deleted file mode 100644 index 0a4e5547c..000000000 --- a/codesniffer/CodeSniffer/CommentParser/CommentElement.php +++ /dev/null @@ -1,245 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to represent Comments of a doc comment. - * - * Comments are in the following format. - * - * /** <--this is the start of the comment. - * * This is a short comment description - * * - * * This is a long comment description - * * <-- this is the end of the comment - * * @return something - * {@/} - * - * - * Note that the sentence before two newlines is assumed - * the short comment description. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_CommentElement extends PHP_CodeSniffer_CommentParser_SingleElement -{ - - - /** - * Constructs a PHP_CodeSniffer_CommentParser_CommentElement. - * - * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element - * that - * appears - * before this - * element. - * @param array $tokens The tokens - * that make - * up this - * element. - * @param PHP_CodeSniffer_File $phpcsFile The file - * that this - * element is - * in. - */ - public function __construct( - $previousElement, - $tokens, - PHP_CodeSniffer_File $phpcsFile - ) { - parent::__construct($previousElement, $tokens, 'comment', $phpcsFile); - - }//end __construct() - - - /** - * Returns the short comment description. - * - * @return string - * @see getLongComment() - */ - public function getShortComment() - { - $pos = $this->_getShortCommentEndPos(); - if ($pos === -1) { - return ''; - } - - return implode('', array_slice($this->tokens, 0, ($pos + 1))); - - }//end getShortComment() - - - /** - * Returns the last token position of the short comment description. - * - * @return int The last token position of the short comment description - * @see _getLongCommentStartPos() - */ - private function _getShortCommentEndPos() - { - $found = false; - $whiteSpace = array( - ' ', - "\t", - ); - - foreach ($this->tokens as $pos => $token) { - $token = str_replace($whiteSpace, '', $token); - if ($token === $this->phpcsFile->eolChar) { - if ($found === false) { - // Include newlines before short description. - continue; - } else { - if (isset($this->tokens[($pos + 1)]) === true) { - if ($this->tokens[($pos + 1)] === $this->phpcsFile->eolChar) { - return ($pos - 1); - } - } else { - return $pos; - } - } - } else { - $found = true; - } - }//end foreach - - return (count($this->tokens) - 1); - - }//end _getShortCommentEndPos() - - - /** - * Returns the long comment description. - * - * @return string - * @see getShortComment - */ - public function getLongComment() - { - $start = $this->_getLongCommentStartPos(); - if ($start === -1) { - return ''; - } - - return implode('', array_slice($this->tokens, $start)); - - }//end getLongComment() - - - /** - * Returns the start position of the long comment description. - * - * Returns -1 if there is no long comment. - * - * @return int The start position of the long comment description. - * @see _getShortCommentEndPos() - */ - private function _getLongCommentStartPos() - { - $pos = ($this->_getShortCommentEndPos() + 1); - if ($pos === (count($this->tokens) - 1)) { - return -1; - } - - $count = count($this->tokens); - for ($i = $pos; $i < $count; $i++) { - $content = trim($this->tokens[$i]); - if ($content !== '') { - if ($content{0} === '@') { - return -1; - } - - return $i; - } - } - - return -1; - - }//end _getLongCommentStartPos() - - - /** - * Returns the whitespace that exists between - * the short and the long comment description. - * - * @return string - */ - public function getWhiteSpaceBetween() - { - $endShort = ($this->_getShortCommentEndPos() + 1); - $startLong = ($this->_getLongCommentStartPos() - 1); - if ($startLong === -1) { - return ''; - } - - return implode( - '', - array_slice($this->tokens, $endShort, ($startLong - $endShort)) - ); - - }//end getWhiteSpaceBetween() - - - /** - * Returns the number of newlines that exist before the tags. - * - * @return int - */ - public function getNewlineAfter() - { - $long = $this->getLongComment(); - if ($long !== '') { - $long = rtrim($long, ' '); - $long = strrev($long); - $newlines = strspn($long, $this->phpcsFile->eolChar); - } else { - $endShort = ($this->_getShortCommentEndPos() + 1); - $after = implode('', array_slice($this->tokens, $endShort)); - $after = trim($after, ' '); - $newlines = strspn($after, $this->phpcsFile->eolChar); - } - - return ($newlines / strlen($this->phpcsFile->eolChar)); - - }//end getNewlineAfter() - - - /** - * Returns true if there is no comment. - * - * @return boolean - */ - public function isEmpty() - { - return (trim($this->getContent()) === ''); - - }//end isEmpty() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/DocElement.php b/codesniffer/CodeSniffer/CommentParser/DocElement.php deleted file mode 100644 index 134781413..000000000 --- a/codesniffer/CodeSniffer/CommentParser/DocElement.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * A DocElement represents a logical element within a Doc Comment. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -interface PHP_CodeSniffer_CommentParser_DocElement -{ - - - /** - * Returns the name of the tag this element represents, omitting the @ symbol. - * - * @return string - */ - public function getTag(); - - - /** - * Returns the whitespace that exists before this element. - * - * @return string - * @see getWhitespaceAfter() - */ - public function getWhitespaceBefore(); - - - /** - * Returns the whitespace that exists after this element. - * - * @return string - * @see getWhitespaceBefore() - */ - public function getWhitespaceAfter(); - - - /** - * Returns the order that this element appears in the doc comment. - * - * The first element in the comment should have an order of 1. - * - * @return int - */ - public function getOrder(); - - - /** - * Returns the element that appears before this element. - * - * @return PHP_CodeSniffer_CommentParser_DocElement - * @see getNextElement() - */ - public function getPreviousElement(); - - - /** - * Returns the element that appears after this element. - * - * @return PHP_CodeSniffer_CommentParser_DocElement - * @see getPreviousElement() - */ - public function getNextElement(); - - - /** - * Returns the line that this element started on. - * - * @return int - */ - public function getLine(); - - - /** - * Returns the raw content of this element, omitting the tag. - * - * @return string - */ - public function getRawContent(); - - -}//end interface - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php b/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php deleted file mode 100644 index bebac08fc..000000000 --- a/codesniffer/CodeSniffer/CommentParser/FunctionCommentParser.php +++ /dev/null @@ -1,212 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_AbstractParser', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_AbstractParser not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_ParameterElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_ParameterElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_PairElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_PairElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_SingleElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_SingleElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses function doc comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_FunctionCommentParser extends PHP_CodeSniffer_CommentParser_AbstractParser -{ - - /** - * The parameter elements within this function comment. - * - * @var array(PHP_CodeSniffer_CommentParser_ParameterElement) - */ - private $_params = array(); - - /** - * The return element in this function comment. - * - * @var PHP_CodeSniffer_CommentParser_PairElement. - */ - private $_return = null; - - /** - * The throws element list for this function comment. - * - * @var array(PHP_CodeSniffer_CommentParser_PairElement) - */ - private $_throws = array(); - - - /** - * Constructs a PHP_CodeSniffer_CommentParser_FunctionCommentParser. - * - * @param string $comment The comment to parse. - * @param PHP_CodeSniffer_File $phpcsFile The file that this comment is in. - */ - public function __construct($comment, PHP_CodeSniffer_File $phpcsFile) - { - parent::__construct($comment, $phpcsFile); - - }//end __construct() - - - /** - * Parses parameter elements. - * - * @param array(string) $tokens The tokens that comprise this sub element. - * - * @return PHP_CodeSniffer_CommentParser_ParameterElement - */ - protected function parseParam($tokens) - { - $param = new PHP_CodeSniffer_CommentParser_ParameterElement( - $this->previousElement, - $tokens, - $this->phpcsFile - ); - - $this->_params[] = $param; - return $param; - - }//end parseParam() - - - /** - * Parses return elements. - * - * @param array(string) $tokens The tokens that comprise this sub element. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - protected function parseReturn($tokens) - { - $return = new PHP_CodeSniffer_CommentParser_PairElement( - $this->previousElement, - $tokens, - 'return', - $this->phpcsFile - ); - - $this->_return = $return; - return $return; - - }//end parseReturn() - - - /** - * Parses throws elements. - * - * @param array(string) $tokens The tokens that comprise this sub element. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - protected function parseThrows($tokens) - { - $throws = new PHP_CodeSniffer_CommentParser_PairElement( - $this->previousElement, - $tokens, - 'throws', - $this->phpcsFile - ); - - $this->_throws[] = $throws; - return $throws; - - }//end parseThrows() - - - /** - * Returns the parameter elements that this function comment contains. - * - * Returns an empty array if no parameter elements are contained within - * this function comment. - * - * @return array(PHP_CodeSniffer_CommentParser_ParameterElement) - */ - public function getParams() - { - return $this->_params; - - }//end getParams() - - - /** - * Returns the return element in this function comment. - * - * Returns null if no return element exists in the comment. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - public function getReturn() - { - return $this->_return; - - }//end getReturn() - - - /** - * Returns the throws elements in this function comment. - * - * Returns empty array if no throws elements in the comment. - * - * @return array(PHP_CodeSniffer_CommentParser_PairElement) - */ - public function getThrows() - { - return $this->_throws; - - }//end getThrows() - - - /** - * Returns the allowed tags that can exist in a function comment. - * - * @return array(string => boolean) - */ - protected function getAllowedTags() - { - return array( - 'param' => false, - 'return' => true, - 'throws' => false, - ); - - }//end getAllowedTags() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php b/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php deleted file mode 100644 index 125896b0c..000000000 --- a/codesniffer/CodeSniffer/CommentParser/MemberCommentParser.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses class member comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_MemberCommentParser extends PHP_CodeSniffer_CommentParser_ClassCommentParser -{ - - /** - * Represents a \@var tag in a member comment. - * - * @var PHP_CodeSniffer_CommentParser_SingleElement - */ - private $_var = null; - - - /** - * Parses Var tags. - * - * @param array $tokens The tokens that represent this tag. - * - * @return PHP_CodeSniffer_CommentParser_SingleElement - */ - protected function parseVar($tokens) - { - $this->_var = new PHP_CodeSniffer_CommentParser_SingleElement( - $this->previousElement, - $tokens, - 'var', - $this->phpcsFile - ); - - return $this->_var; - - }//end parseVar() - - - /** - * Returns the var tag found in the member comment. - * - * @return PHP_CodeSniffer_CommentParser_PairElement - */ - public function getVar() - { - return $this->_var; - - }//end getVar() - - - /** - * Returns the allowed tags for this parser. - * - * @return array - */ - protected function getAllowedTags() - { - return array('var' => true); - - }//end getAllowedTags() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/PairElement.php b/codesniffer/CodeSniffer/CommentParser/PairElement.php deleted file mode 100644 index 39e99769e..000000000 --- a/codesniffer/CodeSniffer/CommentParser/PairElement.php +++ /dev/null @@ -1,171 +0,0 @@ - comment format. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to represent elements that have a value => comment format. - * - * An example of a pair element tag is the \@throws as it has an exception type - * and a comment on the circumstance of when the exception is thrown. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_PairElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement -{ - - /** - * The value of the tag. - * - * @var string - */ - private $_value = ''; - - /** - * The comment of the tag. - * - * @var string - */ - private $_comment = ''; - - /** - * The whitespace that exists before the value elem. - * - * @var string - */ - private $_valueWhitespace = ''; - - /** - * The whitespace that exists before the comment elem. - * - * @var string - */ - private $_commentWhitespace = ''; - - - /** - * Constructs a PHP_CodeSniffer_CommentParser_PairElement doc tag. - * - * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element - * before this - * one. - * @param array $tokens The tokens - * that comprise - * this element. - * @param string $tag The tag that - * this element - * represents. - * @param PHP_CodeSniffer_File $phpcsFile The file that - * this element - * is in. - */ - public function __construct( - $previousElement, - $tokens, - $tag, - PHP_CodeSniffer_File $phpcsFile - ) { - parent::__construct($previousElement, $tokens, $tag, $phpcsFile); - - }//end __construct() - - - /** - * Returns the element names that this tag is comprised of, in the order - * that they appear in the tag. - * - * @return array(string) - * @see processSubElement() - */ - protected function getSubElements() - { - return array( - 'value', - 'comment', - ); - - }//end getSubElements() - - - /** - * Processes the sub element with the specified name. - * - * @param string $name The name of the sub element to process. - * @param string $content The content of this sub element. - * @param string $whitespaceBefore The whitespace that exists before the - * sub element. - * - * @return void - * @see getSubElements() - */ - protected function processSubElement($name, $content, $whitespaceBefore) - { - $element = '_'.$name; - $whitespace = $element.'Whitespace'; - $this->$element = $content; - $this->$whitespace = $whitespaceBefore; - - }//end processSubElement() - - - /** - * Returns the value of the tag. - * - * @return string - */ - public function getValue() - { - return $this->_value; - - }//end getValue() - - - /** - * Returns the comment associated with the value of this tag. - * - * @return string - */ - public function getComment() - { - return $this->_comment; - - }//end getComment() - - - /** - * Returns the whitespace before the content of this tag. - * - * @return string - */ - public function getWhitespaceBeforeValue() - { - return $this->_valueWhitespace; - - }//end getWhitespaceBeforeValue() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/ParameterElement.php b/codesniffer/CodeSniffer/CommentParser/ParameterElement.php deleted file mode 100644 index d78552eed..000000000 --- a/codesniffer/CodeSniffer/CommentParser/ParameterElement.php +++ /dev/null @@ -1,338 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to represent param tags within a function comment. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_ParameterElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement -{ - - /** - * The variable name of this parameter name, including the $ sign. - * - * @var string - */ - private $_varName = ''; - - /** - * The comment of this parameter tag. - * - * @var string - */ - private $_comment = ''; - - /** - * The variable type of this parameter tag. - * - * @var string - */ - private $_type = ''; - - /** - * The whitespace that exists before the variable name. - * - * @var string - */ - private $_varNameWhitespace = ''; - - /** - * The whitespace that exists before the comment. - * - * @var string - */ - private $_commentWhitespace = null; - - /** - * The whitespace that exists before the variable type. - * - * @var string - */ - private $_typeWhitespace = ''; - - - /** - * Constructs a PHP_CodeSniffer_CommentParser_ParameterElement. - * - * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element - * previous to - * this one. - * @param array $tokens The tokens - * that make up - * this element. - * @param PHP_CodeSniffer_File $phpcsFile The file that - * this element - * is in. - */ - public function __construct( - $previousElement, - $tokens, - PHP_CodeSniffer_File $phpcsFile - ) { - parent::__construct($previousElement, $tokens, 'param', $phpcsFile); - - // Handle special variable type: array(x => y). - $type = strtolower($this->_type); - if ($this->_varName === '=>' && strpos($type, 'array(') !== false) { - $rawContent = $this->getRawContent(); - $matches = array(); - $pattern = '/^(\s+)(array\(.*\))(\s+)(\$\S*)(\s+)(.*)/i'; - if (preg_match($pattern, $rawContent, $matches) !== 0) { - // Process the sub elements correctly for this special case. - if (count($matches) === 7) { - $this->processSubElement('type', $matches[2], $matches[1]); - $this->processSubElement('varName', $matches[4], $matches[3]); - $this->processSubElement('comment', $matches[6], $matches[5]); - } - } - } - - }//end __construct() - - - /** - * Returns the element names that this tag is comprised of, in the order - * that they appear in the tag. - * - * @return array(string) - * @see processSubElement() - */ - protected function getSubElements() - { - return array( - 'type', - 'varName', - 'comment', - ); - - }//end getSubElements() - - - /** - * Processes the sub element with the specified name. - * - * @param string $name The name of the sub element to process. - * @param string $content The content of this sub element. - * @param string $beforeWhitespace The whitespace that exists before the - * sub element. - * - * @return void - * @see getSubElements() - */ - protected function processSubElement($name, $content, $beforeWhitespace) - { - $element = '_'.$name; - $whitespace = $element.'Whitespace'; - $this->$element = $content; - $this->$whitespace = $beforeWhitespace; - - }//end processSubElement() - - - /** - * Returns the variable name that this parameter tag represents. - * - * @return string - */ - public function getVarName() - { - return $this->_varName; - - }//end getVarName() - - - /** - * Returns the variable type that this string represents. - * - * @return string - */ - public function getType() - { - return $this->_type; - - }//end getType() - - - /** - * Returns the comment of this comment for this parameter. - * - * @return string - */ - public function getComment() - { - return $this->_comment; - - }//end getComment() - - - /** - * Returns the whitespace before the variable type. - * - * @return string - * @see getWhiteSpaceBeforeVarName() - * @see getWhiteSpaceBeforeComment() - */ - public function getWhiteSpaceBeforeType() - { - return $this->_typeWhitespace; - - }//end getWhiteSpaceBeforeType() - - - /** - * Returns the whitespace before the variable name. - * - * @return string - * @see getWhiteSpaceBeforeComment() - * @see getWhiteSpaceBeforeType() - */ - public function getWhiteSpaceBeforeVarName() - { - return $this->_varNameWhitespace; - - }//end getWhiteSpaceBeforeVarName() - - - /** - * Returns the whitespace before the comment. - * - * @return string - * @see getWhiteSpaceBeforeVarName() - * @see getWhiteSpaceBeforeType() - */ - public function getWhiteSpaceBeforeComment() - { - return $this->_commentWhitespace; - - }//end getWhiteSpaceBeforeComment() - - - /** - * Returns the position of this parameter are it appears in the comment. - * - * This method differs from getOrder as it is only relative to method - * parameters. - * - * @return int - */ - public function getPosition() - { - if (($this->getPreviousElement() instanceof PHP_CodeSniffer_CommentParser_ParameterElement) === false) { - return 1; - } else { - return ($this->getPreviousElement()->getPosition() + 1); - } - - }//end getPosition() - - - /** - * Returns true if this parameter's variable aligns with the other's. - * - * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param - * to check - * alignment with. - * - * @return boolean - */ - public function alignsVariableWith( - PHP_CodeSniffer_CommentParser_ParameterElement $other - ) { - // Format is: - // @param type $variable Comment. - // @param <-a-><---b----> - // Compares the index before param variable. - $otherVar = (strlen($other->_type) + strlen($other->_varNameWhitespace)); - $thisVar = (strlen($this->_type) + strlen($this->_varNameWhitespace)); - if ($otherVar !== $thisVar) { - return false; - } - - return true; - - }//end alignsVariableWith() - - - /** - * Returns true if this parameter's comment aligns with the other's. - * - * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param - * to check - * alignment with. - * - * @return boolean - */ - public function alignsCommentWith( - PHP_CodeSniffer_CommentParser_ParameterElement $other - ) { - // Compares the index before param comment. - if (strlen($other->_commentWhitespace) === 0 && strlen($this->_commentWhitespace) === 0) { - return true; - } - - $otherComment - = (strlen($other->_varName) + strlen($other->_commentWhitespace)); - $thisComment - = (strlen($this->_varName) + strlen($this->_commentWhitespace)); - - if ($otherComment !== $thisComment) { - return false; - } - - return true; - - }//end alignsCommentWith() - - - /** - * Returns true if this parameter aligns with the other paramter. - * - * @param PHP_CodeSniffer_CommentParser_ParameterElement $other The other param - * to check - * alignment with. - * - * @return boolean - */ - public function alignsWith(PHP_CodeSniffer_CommentParser_ParameterElement $other) - { - if ($this->alignsVariableWith($other) === false) { - return false; - } - - if ($this->alignsCommentWith($other) === false) { - return false; - } - - return true; - - }//end alignsWith() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/ParserException.php b/codesniffer/CodeSniffer/CommentParser/ParserException.php deleted file mode 100644 index bc192f194..000000000 --- a/codesniffer/CodeSniffer/CommentParser/ParserException.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * An exception to be thrown when a DocCommentParser finds an anomaly in a - * doc comment. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_ParserException extends Exception -{ - - /** - * The line where the exception occurred, in relation to the doc comment. - * - * @var int - */ - private $_line = 0; - - - /** - * Constructs a DocCommentParserException. - * - * @param string $message The message of the exception. - * @param int $line The position in comment where the error occurred. - * A position of 0 indicates that the error occurred - * at the opening line of the doc comment. - */ - public function __construct($message, $line) - { - parent::__construct($message); - $this->_line = $line; - - }//end __construct() - - - /** - * Returns the line number within the comment where the exception occurred. - * - * @return int - */ - public function getLineWithinComment() - { - return $this->_line; - - }//end getLineWithinComment() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/CommentParser/SingleElement.php b/codesniffer/CodeSniffer/CommentParser/SingleElement.php deleted file mode 100644 index 1bf81e0f2..000000000 --- a/codesniffer/CodeSniffer/CommentParser/SingleElement.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_AbstractDocElement', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_AbstractDocElement not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to represent single element doc tags. - * - * A single element doc tag contains only one value after the tag itself. An - * example would be the \@package tag. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_CommentParser_SingleElement extends PHP_CodeSniffer_CommentParser_AbstractDocElement -{ - - /** - * The content that exists after the tag. - * - * @var string - * @see getContent() - */ - protected $content = ''; - - /** - * The whitespace that exists before the content. - * - * @var string - * @see getWhitespaceBeforeContent() - */ - protected $contentWhitespace = ''; - - - /** - * Constructs a SingleElement doc tag. - * - * @param PHP_CodeSniffer_CommentParser_DocElement $previousElement The element - * before this - * one. - * @param array $tokens The tokens - * that comprise - * this element. - * @param string $tag The tag that - * this element - * represents. - * @param PHP_CodeSniffer_File $phpcsFile The file that - * this element - * is in. - */ - public function __construct( - $previousElement, - $tokens, - $tag, - PHP_CodeSniffer_File $phpcsFile - ) { - parent::__construct($previousElement, $tokens, $tag, $phpcsFile); - - }//end __construct() - - - /** - * Returns the element names that this tag is comprised of, in the order - * that they appear in the tag. - * - * @return array(string) - * @see processSubElement() - */ - protected function getSubElements() - { - return array('content'); - - }//end getSubElements() - - - /** - * Processes the sub element with the specified name. - * - * @param string $name The name of the sub element to process. - * @param string $content The content of this sub element. - * @param string $whitespaceBefore The whitespace that exists before the - * sub element. - * - * @return void - * @see getSubElements() - */ - protected function processSubElement($name, $content, $whitespaceBefore) - { - $this->content = $content; - $this->contentWhitespace = $whitespaceBefore; - - }//end processSubElement() - - - /** - * Returns the content of this tag. - * - * @return string - */ - public function getContent() - { - return $this->content; - - }//end getContent() - - - /** - * Returns the whitespace before the content of this tag. - * - * @return string - */ - public function getWhitespaceBeforeContent() - { - return $this->contentWhitespace; - - }//end getWhitespaceBeforeContent() - - - /** - * Processes a content check for single doc element. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $commentStart The line number where - * the error occurs. - * @param string $docBlock Whether this is a file or - * class comment doc. - * - * @return void - */ - public function process( - PHP_CodeSniffer_File $phpcsFile, - $commentStart, - $docBlock - ) { - if ($this->content === '') { - $errorPos = ($commentStart + $this->getLine()); - $error = 'Content missing for %s tag in %s comment'; - $data = array( - $this->tag, - $docBlock, - ); - $phpcsFile->addError($error, $errorPos, 'EmptyTagContent', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/DocGenerators/Generator.php b/codesniffer/CodeSniffer/DocGenerators/Generator.php deleted file mode 100644 index 8cb38c605..000000000 --- a/codesniffer/CodeSniffer/DocGenerators/Generator.php +++ /dev/null @@ -1,186 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * The base class for all PHP_CodeSniffer documentation generators. - * - * Documentation generators are used to print documentation about code sniffs - * in a standard. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_DocGenerators_Generator -{ - - /** - * The name of the coding standard we are generating docs for. - * - * @var string - */ - private $_standard = ''; - - /** - * An array of sniffs that we are limiting the generated docs to. - * - * If this array is empty, docs are generated for all sniffs in the - * supplied coding standard. - * - * @var string - */ - private $_sniffs = array(); - - - /** - * Constructs a PHP_CodeSniffer_DocGenerators_Generator object. - * - * @param string $standard The name of the coding standard to generate - * docs for. - * @param array $sniffs An array of sniffs that we are limiting the - * generated docs to. - * - * @see generate() - */ - public function __construct($standard, array $sniffs=array()) - { - $this->_standard = $standard; - $this->_sniffs = $sniffs; - - }//end __construct() - - - /** - * Retrieves the title of the sniff from the DOMNode supplied. - * - * @param DOMNode $doc The DOMNode object for the sniff. - * It represents the "documentation" tag in the XML - * standard file. - * - * @return string - */ - protected function getTitle(DOMNode $doc) - { - return $doc->getAttribute('title'); - - }//end getTitle() - - - /** - * Retrieves the name of the standard we are generating docs for. - * - * @return string - */ - protected function getStandard() - { - return $this->_standard; - - }//end getStandard() - - - /** - * Generates the documentation for a standard. - * - * It's probably wise for doc generators to override this method so they - * have control over how the docs are produced. Otherwise, the processSniff - * method should be overridden to output content for each sniff. - * - * @return void - * @see processSniff() - */ - public function generate() - { - $standardFiles = $this->getStandardFiles(); - - foreach ($standardFiles as $standard) { - $doc = new DOMDocument(); - $doc->load($standard); - $documentation = $doc->getElementsByTagName('documentation')->item(0); - $this->processSniff($documentation); - } - - }//end generate() - - - /** - * Returns a list of paths to XML standard files for all sniffs in a standard. - * - * Any sniffs that do not have an XML standard file are obviously not included - * in the returned array. If documentation is only being generated for some - * sniffs (ie. $this->_sniffs is not empty) then all others sniffs will - * be filtered from the results as well. - * - * @return array(string) - */ - protected function getStandardFiles() - { - $phpcs = new PHP_CodeSniffer(); - $sniffs = $phpcs->processRuleset($this->_standard); - - $standardFiles = array(); - foreach ($sniffs as $sniff) { - if (empty($this->_sniffs) === false) { - // We are limiting the docs to certain sniffs only, so filter - // out any unwanted sniffs. - $sniffName = substr($sniff, (strrpos($sniff, '/') + 1)); - $sniffName = substr($sniffName, 0, -9); - if (in_array($sniffName, $this->_sniffs) === false) { - continue; - } - } - - $standardFile = str_replace( - DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR, - $sniff - ); - $standardFile = str_replace('Sniff.php', 'Standard.xml', $standardFile); - - if (is_file($standardFile) === true) { - $standardFiles[] = $standardFile; - } - }//end foreach - - return $standardFiles; - - }//end getStandardFiles() - - - /** - * Process the documentation for a single sniff. - * - * Doc generators should override this function to produce output. - * - * @param DOMNode $doc The DOMNode object for the sniff. - * It represents the "documentation" tag in the XML - * standard file. - * - * @return void - * @see generate() - */ - protected function processSniff(DOMNode $doc) - { - - }//end processSniff() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/DocGenerators/HTML.php b/codesniffer/CodeSniffer/DocGenerators/HTML.php deleted file mode 100644 index f379d9414..000000000 --- a/codesniffer/CodeSniffer/DocGenerators/HTML.php +++ /dev/null @@ -1,294 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found'); -} - -/** - * A doc generator that outputs documentation in one big HTML file. - * - * Output is in one large HTML file and is designed for you to style with - * your own stylesheet. It contains a table of contents at the top with anchors - * to each sniff. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_DocGenerators_HTML extends PHP_CodeSniffer_DocGenerators_Generator -{ - - - /** - * Generates the documentation for a standard. - * - * @return void - * @see processSniff() - */ - public function generate() - { - ob_start(); - $this->printHeader(); - - $standardFiles = $this->getStandardFiles(); - $this->printToc($standardFiles); - - foreach ($standardFiles as $standard) { - $doc = new DOMDocument(); - $doc->load($standard); - $documentation = $doc->getElementsByTagName('documentation')->item(0); - $this->processSniff($documentation); - } - - $this->printFooter(); - - $content = ob_get_contents(); - ob_end_clean(); - - echo $content; - - }//end generate() - - - /** - * Print the header of the HTML page. - * - * @return void - */ - protected function printHeader() - { - $standard = $this->getStandard(); - echo ''.PHP_EOL; - echo ' '.PHP_EOL; - echo " $standard Coding Standards".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo "

$standard Coding Standards

".PHP_EOL; - - }//end printHeader() - - - /** - * Print the table of contents for the standard. - * - * The TOC is just an unordered list of bookmarks to sniffs on the page. - * - * @param array $standardFiles An array of paths to the XML standard files. - * - * @return void - */ - protected function printToc($standardFiles) - { - echo '

Table of Contents

'.PHP_EOL; - echo '
'.PHP_EOL; - - }//end printToc() - - - /** - * Print the footer of the HTML page. - * - * @return void - */ - protected function printFooter() - { - // Turn off strict errors so we don't get timezone warnings if people - // don't have their timezone set. - error_reporting(E_ALL); - echo '
'; - echo 'Documentation generated on '.date('r'); - echo ' by PHP_CodeSniffer @package_version@'; - echo '
'.PHP_EOL; - error_reporting(E_ALL | E_STRICT); - - echo ' '.PHP_EOL; - echo ''.PHP_EOL; - - }//end printFooter() - - - /** - * Process the documentation for a single sniff. - * - * @param DOMNode $doc The DOMNode object for the sniff. - * It represents the "documentation" tag in the XML - * standard file. - * - * @return void - */ - public function processSniff(DOMNode $doc) - { - $title = $this->getTitle($doc); - echo ' '.PHP_EOL; - echo "

$title

".PHP_EOL; - - foreach ($doc->childNodes as $node) { - if ($node->nodeName === 'standard') { - $this->printTextBlock($node); - } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); - } - } - - }//end processSniff() - - - /** - * Print a text block found in a standard. - * - * @param DOMNode $node The DOMNode object for the text block. - * - * @return void - */ - protected function printTextBlock($node) - { - $content = trim($node->nodeValue); - $content = htmlspecialchars($content); - - // Allow em tags only. - $content = str_replace('<em>', '', $content); - $content = str_replace('</em>', '', $content); - - echo "

$content

".PHP_EOL; - - }//end printTextBlock() - - - /** - * Print a code comparison block found in a standard. - * - * @param DOMNode $node The DOMNode object for the code comparison block. - * - * @return void - */ - protected function printCodeComparisonBlock($node) - { - $codeBlocks = $node->getElementsByTagName('code'); - - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); - $first = trim($codeBlocks->item(0)->nodeValue); - $first = str_replace('', $first); - $first = str_replace(' ', ' ', $first); - $first = str_replace('', '', $first); - $first = str_replace('', '', $first); - - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); - $second = trim($codeBlocks->item(1)->nodeValue); - $second = str_replace('', $second); - $second = str_replace(' ', ' ', $second); - $second = str_replace('', '', $second); - $second = str_replace('', '', $second); - - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo '
$firstTitle$secondTitle
$first$second
'.PHP_EOL; - - }//end printCodeComparisonBlock() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/DocGenerators/Text.php b/codesniffer/CodeSniffer/DocGenerators/Text.php deleted file mode 100644 index 1134f0c49..000000000 --- a/codesniffer/CodeSniffer/DocGenerators/Text.php +++ /dev/null @@ -1,267 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found'); -} - -/** - * A doc generator that outputs text-based documentation. - * - * Output is designed to be displayed in a terminal and is wrapped to 100 characters. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_DocGenerators_Text extends PHP_CodeSniffer_DocGenerators_Generator -{ - - - /** - * Process the documentation for a single sniff. - * - * @param DOMNode $doc The DOMNode object for the sniff. - * It represents the "documentation" tag in the XML - * standard file. - * - * @return void - */ - public function processSniff(DOMNode $doc) - { - $this->printTitle($doc); - - foreach ($doc->childNodes as $node) { - if ($node->nodeName === 'standard') { - $this->printTextBlock($node); - } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); - } - } - - }//end processSniff() - - - /** - * Prints the title area for a single sniff. - * - * @param DOMNode $doc The DOMNode object for the sniff. - * It represents the "documentation" tag in the XML - * standard file. - * - * @return void - */ - protected function printTitle(DOMNode $doc) - { - $title = $this->getTitle($doc); - $standard = $this->getStandard(); - - echo PHP_EOL; - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); - echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL); - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); - echo PHP_EOL.PHP_EOL; - - }//end printTitle() - - - /** - * Print a text block found in a standard. - * - * @param DOMNode $node The DOMNode object for the text block. - * - * @return void - */ - protected function printTextBlock($node) - { - $text = trim($node->nodeValue); - $text = str_replace('', '*', $text); - $text = str_replace('', '*', $text); - - $lines = array(); - $tempLine = ''; - $words = explode(' ', $text); - - foreach ($words as $word) { - if (strlen($tempLine.$word) >= 99) { - if (strlen($tempLine.$word) === 99) { - // Adding the extra space will push us to the edge - // so we are done. - $lines[] = $tempLine.$word; - $tempLine = ''; - } else if (strlen($tempLine.$word) === 100) { - // We are already at the edge, so we are done. - $lines[] = $tempLine.$word; - $tempLine = ''; - } else { - $lines[] = rtrim($tempLine); - $tempLine = $word.' '; - } - } else { - $tempLine .= $word.' '; - } - }//end foreach - - if ($tempLine !== '') { - $lines[] = rtrim($tempLine); - } - - echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL; - - }//end printTextBlock() - - - /** - * Print a code comparison block found in a standard. - * - * @param DOMNode $node The DOMNode object for the code comparison block. - * - * @return void - */ - protected function printCodeComparisonBlock($node) - { - $codeBlocks = $node->getElementsByTagName('code'); - $first = trim($codeBlocks->item(0)->nodeValue); - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); - - $firstTitleLines = array(); - $tempTitle = ''; - $words = explode(' ', $firstTitle); - - foreach ($words as $word) { - if (strlen($tempTitle.$word) >= 45) { - if (strlen($tempTitle.$word) === 45) { - // Adding the extra space will push us to the edge - // so we are done. - $firstTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else if (strlen($tempTitle.$word) === 46) { - // We are already at the edge, so we are done. - $firstTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else { - $firstTitleLines[] = $tempTitle; - $tempTitle = $word; - } - } else { - $tempTitle .= $word.' '; - } - }//end foreach - - if ($tempTitle !== '') { - $firstTitleLines[] = $tempTitle; - } - - $first = str_replace('', '', $first); - $first = str_replace('', '', $first); - $firstLines = explode("\n", $first); - - $second = trim($codeBlocks->item(1)->nodeValue); - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); - - $secondTitleLines = array(); - $tempTitle = ''; - $words = explode(' ', $secondTitle); - - foreach ($words as $word) { - if (strlen($tempTitle.$word) >= 45) { - if (strlen($tempTitle.$word) === 45) { - // Adding the extra space will push us to the edge - // so we are done. - $secondTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else if (strlen($tempTitle.$word) === 46) { - // We are already at the edge, so we are done. - $secondTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else { - $secondTitleLines[] = $tempTitle; - $tempTitle = $word; - } - } else { - $tempTitle .= $word.' '; - } - }//end foreach - - if ($tempTitle !== '') { - $secondTitleLines[] = $tempTitle; - } - - $second = str_replace('', '', $second); - $second = str_replace('', '', $second); - $secondLines = explode("\n", $second); - - $maxCodeLines = max(count($firstLines), count($secondLines)); - $maxTitleLines = max(count($firstTitleLines), count($secondTitleLines)); - - echo str_repeat('-', 41); - echo ' CODE COMPARISON '; - echo str_repeat('-', 42).PHP_EOL; - - for ($i = 0; $i < $maxTitleLines; $i++) { - if (isset($firstTitleLines[$i]) === true) { - $firstLineText = $firstTitleLines[$i]; - } else { - $firstLineText = ''; - } - - if (isset($secondTitleLines[$i]) === true) { - $secondLineText = $secondTitleLines[$i]; - } else { - $secondLineText = ''; - } - - echo '| '; - echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText))); - echo ' | '; - echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText))); - echo ' |'.PHP_EOL; - }//end for - - echo str_repeat('-', 100).PHP_EOL; - - for ($i = 0; $i < $maxCodeLines; $i++) { - if (isset($firstLines[$i]) === true) { - $firstLineText = $firstLines[$i]; - } else { - $firstLineText = ''; - } - - if (isset($secondLines[$i]) === true) { - $secondLineText = $secondLines[$i]; - } else { - $secondLineText = ''; - } - - echo '| '; - echo $firstLineText.str_repeat(' ', (47 - strlen($firstLineText))); - echo '| '; - echo $secondLineText.str_repeat(' ', (48 - strlen($secondLineText))); - echo '|'.PHP_EOL; - }//end for - - echo str_repeat('-', 100).PHP_EOL.PHP_EOL; - - }//end printCodeComparisonBlock() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Exception.php b/codesniffer/CodeSniffer/Exception.php deleted file mode 100644 index 4b03f3e56..000000000 --- a/codesniffer/CodeSniffer/Exception.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Exception extends Exception -{ - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/File.php b/codesniffer/CodeSniffer/File.php deleted file mode 100644 index f45e307df..000000000 --- a/codesniffer/CodeSniffer/File.php +++ /dev/null @@ -1,2910 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * A PHP_CodeSniffer_File object represents a PHP source file and the tokens - * associated with it. - * - * It provides a means for traversing the token stack, along with - * other token related operations. If a PHP_CodeSniffer_Sniff finds and error or - * warning within a PHP_CodeSniffer_File, you can raise an error using the - * addError() or addWarning() methods. - * - * Token Information - * - * Each token within the stack contains information about itself: - * - * - * array( - * 'code' => 301, // the token type code (see token_get_all()) - * 'content' => 'if', // the token content - * 'type' => 'T_IF', // the token name - * 'line' => 56, // the line number when the token is located - * 'column' => 12, // the column in the line where this token - * // starts (starts from 1) - * 'level' => 2 // the depth a token is within the scopes open - * 'conditions' => array( // a list of scope condition token - * // positions => codes that - * 2 => 50, // openened the scopes that this token exists - * 9 => 353, // in (see conditional tokens section below) - * ), - * ); - * - * - * Conditional Tokens - * - * In addition to the standard token fields, conditions contain information to - * determine where their scope begins and ends: - * - * - * array( - * 'scope_condition' => 38, // the token position of the condition - * 'scope_opener' => 41, // the token position that started the scope - * 'scope_closer' => 70, // the token position that ended the scope - * ); - * - * - * The condition, the scope opener and the scope closer each contain this - * information. - * - * Parenthesis Tokens - * - * Each parenthesis token (T_OPEN_PARENTHESIS and T_CLOSE_PARENTHESIS) has a - * reference to their opening and closing parenthesis, one being itself, the - * other being its opposite. - * - * - * array( - * 'parenthesis_opener' => 34, - * 'parenthesis_closer' => 40, - * ); - * - * - * Some tokens can "own" a set of parenthesis. For example a T_FUNCTION token - * has parenthesis around its argument list. These tokens also have the - * parenthesis_opener and and parenthesis_closer indices. Not all parenthesis - * have owners, for example parenthesis used for arithmetic operations and - * function calls. The parenthesis tokens that have an owner have the following - * auxiliary array indices. - * - * - * array( - * 'parenthesis_opener' => 34, - * 'parenthesis_closer' => 40, - * 'parenthesis_owner' => 33, - * ); - * - * - * Each token within a set of parenthesis also has an array indice - * 'nested_parenthesis' which is an array of the - * left parenthesis => right parenthesis token positions. - * - * - * 'nested_parenthesis' => array( - * 12 => 15 - * 11 => 14 - * ); - * - * - * Extended Tokens - * - * PHP_CodeSniffer extends and augments some of the tokens created by - * token_get_all(). A full list of these tokens can be seen in the - * Tokens.php file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_File -{ - - /** - * The absolute path to the file associated with this object. - * - * @var string - */ - private $_file = ''; - - /** - * The EOL character this file uses. - * - * @var string - */ - public $eolChar = ''; - - /** - * The PHP_CodeSniffer object controlling this run. - * - * @var PHP_CodeSniffer - */ - public $phpcs = null; - - /** - * The tokenizer being used for this file. - * - * @var object - */ - public $tokenizer = null; - - /** - * The tokenizer being used for this file. - * - * @var string - */ - public $tokenizerType = 'PHP'; - - /** - * The number of tokens in this file. - * - * Stored here to save calling count() everywhere. - * - * @var int - */ - public $numTokens = 0; - - /** - * The tokens stack map. - * - * Note that the tokens in this array differ in format to the tokens - * produced by token_get_all(). Tokens are initially produced with - * token_get_all(), then augmented so that it's easier to process them. - * - * @var array() - * @see Tokens.php - */ - private $_tokens = array(); - - /** - * The errors raised from PHP_CodeSniffer_Sniffs. - * - * @var array() - * @see getErrors() - */ - private $_errors = array(); - - /** - * The warnings raised form PHP_CodeSniffer_Sniffs. - * - * @var array() - * @see getWarnings() - */ - private $_warnings = array(); - - /** - * Record the errors and warnings raised. - * - * @var bool - */ - private $_recordErrors = true; - - /** - * And array of lines being ignored by PHP_CodeSniffer. - * - * @var array() - */ - private $_ignoredLines = array(); - - /** - * The total number of errors raised. - * - * @var int - */ - private $_errorCount = 0; - - /** - * The total number of warnings raised. - * - * @var int - */ - private $_warningCount = 0; - - /** - * An array of sniffs listening to this file's processing. - * - * @var array(PHP_CodeSniffer_Sniff) - */ - private $_listeners = array(); - - /** - * The class name of the sniff currently processing the file. - * - * @var string - */ - private $_activeListener = ''; - - /** - * An array of sniffs being processed and how long they took. - * - * @var array() - */ - private $_listenerTimes = array(); - - /** - * An array of extensions mapping to the tokenizer to use. - * - * This value gets set by PHP_CodeSniffer when the object is created. - * - * @var array - */ - protected $tokenizers = array(); - - /** - * An array of rules from the ruleset.xml file. - * - * This value gets set by PHP_CodeSniffer when the object is created. - * It may be empty, indicating that the ruleset does not override - * any of the default sniff settings. - * - * @var array - */ - protected $ruleset = array(); - - /** - * An array of sniff codes to restrict violations to. - * - * This value gets set by PHP_CodeSniffer when the object is created. - * It may be empty, indicating that no fitering should take place. - * - * @var array - */ - protected $restrictions = array(); - - - /** - * Constructs a PHP_CodeSniffer_File. - * - * @param string $file The absolute path to the file to process. - * @param array(string) $listeners The initial listeners listening - * to processing of this file. - * @param array $tokenizers An array of extensions mapping - * to the tokenizer to use. - * @param array $ruleset An array of rules from the - * ruleset.xml file. - * @param array $restrictions An array of sniff codes to - * restrict violations to. - * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object controlling - * this run. - * - * @throws PHP_CodeSniffer_Exception If the register() method does - * not return an array. - */ - public function __construct( - $file, - array $listeners, - array $tokenizers, - array $ruleset, - array $restrictions, - PHP_CodeSniffer $phpcs - ) { - $this->_file = trim($file); - $this->_listeners = $listeners; - $this->tokenizers = $tokenizers; - $this->ruleset = $ruleset; - $this->restrictions = $restrictions; - $this->phpcs = $phpcs; - - $cliValues = $phpcs->cli->getCommandLineValues(); - if (isset($cliValues['showSources']) === true - && $cliValues['showSources'] !== true - && array_key_exists('summary', $cliValues['reports']) === true - && count($cliValues['reports']) === 1 - ) { - $this->_recordErrors = false; - } - - }//end __construct() - - - /** - * Sets the name of the currently active sniff. - * - * @param string $activeListener The class name of the current sniff. - * - * @return void - */ - public function setActiveListener($activeListener) - { - $this->_activeListener = $activeListener; - - }//end setActiveListener() - - - /** - * Adds a listener to the token stack that listens to the specific tokens. - * - * When PHP_CodeSniffer encounters on the the tokens specified in $tokens, - * it invokes the process method of the sniff. - * - * @param PHP_CodeSniffer_Sniff $listener The listener to add to the - * listener stack. - * @param array(int) $tokens The token types the listener wishes to - * listen to. - * - * @return void - */ - public function addTokenListener(PHP_CodeSniffer_Sniff $listener, array $tokens) - { - foreach ($tokens as $token) { - if (isset($this->_listeners[$token]) === false) { - $this->_listeners[$token] = array(); - } - - if (in_array($listener, $this->_listeners[$token], true) === false) { - $this->_listeners[$token][] = $listener; - } - } - - }//end addTokenListener() - - - /** - * Removes a listener from listening from the specified tokens. - * - * @param PHP_CodeSniffer_Sniff $listener The listener to remove from the - * listener stack. - * @param array(int) $tokens The token types the listener wishes to - * stop listen to. - * - * @return void - */ - public function removeTokenListener( - PHP_CodeSniffer_Sniff $listener, - array $tokens - ) { - foreach ($tokens as $token) { - if (isset($this->_listeners[$token]) === false) { - continue; - } - - if (in_array($listener, $this->_listeners[$token]) === true) { - foreach ($this->_listeners[$token] as $pos => $value) { - if ($value === $listener) { - unset($this->_listeners[$token][$pos]); - } - } - } - } - - }//end removeTokenListener() - - - /** - * Returns the token stack for this file. - * - * @return array() - */ - public function getTokens() - { - return $this->_tokens; - - }//end getTokens() - - - /** - * Starts the stack traversal and tells listeners when tokens are found. - * - * @param string $contents The contents to parse. If NULL, the content - * is taken from the file system. - * - * @return void - */ - public function start($contents=null) - { - $this->_parse($contents); - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - echo "\t*** START TOKEN PROCESSING ***".PHP_EOL; - } - - $foundCode = false; - $ignoring = false; - - // Foreach of the listeners that have registered to listen for this - // token, get them to process it. - foreach ($this->_tokens as $stackPtr => $token) { - // Check for ignored lines. - if ($token['code'] === T_COMMENT || $token['code'] === T_DOC_COMMENT) { - if (strpos($token['content'], '@codingStandardsIgnoreStart') !== false) { - $ignoring = true; - } else if (strpos($token['content'], '@codingStandardsIgnoreEnd') !== false) { - $ignoring = false; - // Ignore this comment too. - $this->_ignoredLines[$token['line']] = true; - } else if (strpos($token['content'], '@codingStandardsIgnoreFile') !== false) { - // Ignoring the whole file, just a little late. - $this->_errors = array(); - $this->_warnings = array(); - $this->_errorCount = 0; - $this->_warningCount = 0; - return; - } else if (strpos($token['content'], '@codingStandardsChangeSetting') !== false) { - $start = strpos($token['content'], '@codingStandardsChangeSetting'); - $comment = substr($token['content'], $start + 30); - $parts = explode(' ', $comment); - $sniffParts = explode('.', $parts[0]); - $listenerClass = $sniffParts[0].'_Sniffs_'.$sniffParts[1].'_'.$sniffParts[2].'Sniff'; - $this->phpcs->setSniffProperty($listenerClass, $parts[1], $parts[2]); - } - } - - if ($ignoring === true) { - $this->_ignoredLines[$token['line']] = true; - continue; - } - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - $type = $token['type']; - $content = str_replace($this->eolChar, '\n', $token['content']); - echo "\t\tProcess token $stackPtr: $type => $content".PHP_EOL; - } - - $tokenType = $token['code']; - if ($tokenType !== T_INLINE_HTML) { - $foundCode = true; - } - - if (isset($this->_listeners[$tokenType]) === false) { - continue; - } - - foreach ($this->_listeners[$tokenType] as $listenerData) { - // Make sure this sniff supports the tokenizer - // we are currently using. - $listener = $listenerData['listener']; - $class = $listenerData['class']; - - if (in_array($this->tokenizerType, $listenerData['tokenizers']) === false) { - continue; - } - - // If the file path matches one of our ignore patterns, skip it. - $parts = explode('_', str_replace('\\', '_', $class)); - if (isset($parts[3]) === true) { - $source = $parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5); - $patterns = $this->phpcs->getIgnorePatterns($source); - foreach ($patterns as $pattern => $type) { - // While there is support for a type of each pattern - // (absolute or relative) we don't actually support it here. - $replacements = array( - '\\,' => ',', - '*' => '.*', - ); - - $pattern = strtr($pattern, $replacements); - if (preg_match("|{$pattern}|i", $this->_file) === 1) { - continue(2); - } - } - } - - $this->setActiveListener($class); - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - $startTime = microtime(true); - echo "\t\t\tProcessing ".$this->_activeListener.'... '; - } - - $listener->process($this, $stackPtr); - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - $timeTaken = (microtime(true) - $startTime); - if (isset($this->_listenerTimes[$this->_activeListener]) === false) { - $this->_listenerTimes[$this->_activeListener] = 0; - } - - $this->_listenerTimes[$this->_activeListener] += $timeTaken; - - $timeTaken = round(($timeTaken), 4); - echo "DONE in $timeTaken seconds".PHP_EOL; - } - - $this->_activeListener = ''; - }//end foreach - }//end foreach - - // Remove errors and warnings for ignored lines. - foreach ($this->_ignoredLines as $line => $ignore) { - if (isset($this->_errors[$line]) === true) { - if ($this->_recordErrors === false) { - $this->_errorCount -= $this->_errors[$line]; - } else { - foreach ($this->_errors[$line] as $col => $errors) { - $this->_errorCount -= count($errors); - } - } - - unset($this->_errors[$line]); - } - - if (isset($this->_warnings[$line]) === true) { - if ($this->_recordErrors === false) { - $this->_errorCount -= $this->_warnings[$line]; - } else { - foreach ($this->_warnings[$line] as $col => $warnings) { - $this->_warningCount -= count($warnings); - } - } - - unset($this->_warnings[$line]); - } - }//end foreach - - if ($this->_recordErrors === false) { - $this->_errors = array(); - $this->_warnings = array(); - } - - // If short open tags are off but the file being checked uses - // short open tags, the whole content will be inline HTML - // and nothing will be checked. So try and handle this case. - if ($foundCode === false) { - $shortTags = (bool) ini_get('short_open_tag'); - if ($shortTags === false) { - $error = 'No PHP code was found in this file and short open tags are not allowed by this install of PHP. This file may be using short open tags but PHP does not allow them.'; - $this->addWarning($error, null, 'Internal.NoCodeFound'); - } - } - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - echo "\t*** END TOKEN PROCESSING ***".PHP_EOL; - } - - if (PHP_CODESNIFFER_VERBOSITY > 2) { - echo "\t*** START SNIFF PROCESSING REPORT ***".PHP_EOL; - - asort($this->_listenerTimes, SORT_NUMERIC); - $this->_listenerTimes = array_reverse($this->_listenerTimes, true); - foreach ($this->_listenerTimes as $listener => $timeTaken) { - echo "\t$listener: ".round(($timeTaken), 4).' secs'.PHP_EOL; - } - - echo "\t*** END SNIFF PROCESSING REPORT ***".PHP_EOL; - } - - }//end start() - - - /** - * Remove vars stored in this sniff that are no longer required. - * - * @return void - */ - public function cleanUp() - { - $this->_tokens = null; - $this->_listeners = null; - - }//end cleanUp() - - - /** - * Tokenizes the file and prepares it for the test run. - * - * @param string $contents The contents to parse. If NULL, the content - * is taken from the file system. - * - * @return void - */ - private function _parse($contents=null) - { - try { - $this->eolChar = self::detectLineEndings($this->_file, $contents); - } catch (PHP_CodeSniffer_Exception $e) { - $this->addWarning($e->getMessage(), null, 'Internal.DetectLineEndings'); - return; - } - - // Determine the tokenizer from the file extension. - $fileParts = explode('.', $this->_file); - $extension = array_pop($fileParts); - if (isset($this->tokenizers[$extension]) === true) { - $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->tokenizers[$extension]; - $this->tokenizerType = $this->tokenizers[$extension]; - } else { - // Revert to default. - $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->tokenizerType; - } - - $tokenizer = new $tokenizerClass(); - $this->tokenizer = $tokenizer; - - if ($contents === null) { - $contents = file_get_contents($this->_file); - } - - $this->_tokens = self::tokenizeString($contents, $tokenizer, $this->eolChar); - $this->numTokens = count($this->_tokens); - - // Check for mixed line endings as these can cause tokenizer errors and we - // should let the user know that the results they get may be incorrect. - // This is done by removing all backslashes, removing the newline char we - // detected, then converting newlines chars into text. If any backslashes - // are left at the end, we have additional newline chars in use. - $contents = str_replace('\\', '', $contents); - $contents = str_replace($this->eolChar, '', $contents); - $contents = str_replace("\n", '\n', $contents); - $contents = str_replace("\r", '\r', $contents); - if (strpos($contents, '\\') !== false) { - $error = 'File has mixed line endings; this may cause incorrect results'; - $this->addWarning($error, 0, 'Internal.LineEndings.Mixed'); - } - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - if ($this->numTokens === 0) { - $numLines = 0; - } else { - $numLines = $this->_tokens[($this->numTokens - 1)]['line']; - } - - echo "[$this->numTokens tokens in $numLines lines]... "; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo PHP_EOL; - } - } - - }//end _parse() - - - /** - * Opens a file and detects the EOL character being used. - * - * @param string $file The full path to the file. - * @param string $contents The contents to parse. If NULL, the content - * is taken from the file system. - * - * @return string - * @throws PHP_CodeSniffer_Exception If $file could not be opened. - */ - public static function detectLineEndings($file, $contents=null) - { - if ($contents === null) { - // Determine the newline character being used in this file. - // Will be either \r, \r\n or \n. - if (is_readable($file) === false) { - $error = 'Error opening file; file no longer exists or you do not have access to read the file'; - throw new PHP_CodeSniffer_Exception($error); - } else { - $handle = fopen($file, 'r'); - if ($handle === false) { - $error = 'Error opening file; could not auto-detect line endings'; - throw new PHP_CodeSniffer_Exception($error); - } - } - - $firstLine = fgets($handle); - fclose($handle); - - $eolChar = substr($firstLine, -1); - if ($eolChar === "\n") { - $secondLastChar = substr($firstLine, -2, 1); - if ($secondLastChar === "\r") { - $eolChar = "\r\n"; - } - } else if ($eolChar !== "\r") { - // Must not be an EOL char at the end of the line. - // Probably a one-line file, so assume \n as it really - // doesn't matter considering there are no newlines. - $eolChar = "\n"; - } - } else { - if (preg_match("/\r\n?|\n/", $contents, $matches) !== 1) { - // Assuming there are no newlines. - $eolChar = "\n"; - } else { - $eolChar = $matches[0]; - } - }//end if - - return $eolChar; - - }//end detectLineEndings() - - - /** - * Adds an error to the error stack. - * - * @param string $error The error message. - * @param int $stackPtr The stack position where the error occurred. - * @param string $code A violation code unique to the sniff message. - * @param array $data Replacements for the error message. - * @param int $severity The severity level for this error. A value of 0 - * will be converted into the default severity level. - * - * @return void - */ - public function addError($error, $stackPtr, $code='', $data=array(), $severity=0) - { - // Don't bother doing any processing if errors are just going to - // be hidden in the reports anyway. - if ($this->phpcs->cli->errorSeverity === 0) { - return; - } - - // Work out which sniff generated the error. - if (substr($code, 0, 9) === 'Internal.') { - // Any internal message. - $sniff = $code; - $sniffCode = $code; - } else { - $parts = explode('_', str_replace('\\', '_', $this->_activeListener)); - if (isset($parts[3]) === true) { - $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3]; - - // Remove "Sniff" from the end. - $sniff = substr($sniff, 0, -5); - } else { - $sniff = 'unknownSniff'; - } - - $sniffCode = $sniff; - if ($code !== '') { - $sniffCode .= '.'.$code; - } - }//end if - - // Make sure this message type is allowed based on the --sniffs - // command line argument values. - if (empty($this->restrictions) === false - && in_array($sniffCode, $this->restrictions) === false - && in_array($sniff, $this->restrictions) === false - ) { - return; - } - - // Make sure this message type has not been set to "warning". - if (isset($this->ruleset[$sniffCode]['type']) === true - && $this->ruleset[$sniffCode]['type'] === 'warning' - ) { - // Pass this off to the warning handler. - $this->addWarning($error, $stackPtr, $code, $data, $severity); - return; - } - - // Make sure we are interested in this severity level. - if (isset($this->ruleset[$sniffCode]['severity']) === true) { - $severity = $this->ruleset[$sniffCode]['severity']; - } else if ($severity === 0) { - $severity = PHPCS_DEFAULT_ERROR_SEV; - } - - if ($this->phpcs->cli->errorSeverity > $severity) { - return; - } - - // Make sure we are not ignoring this file. - $patterns = $this->phpcs->getIgnorePatterns($sniffCode); - foreach ($patterns as $pattern => $type) { - // While there is support for a type of each pattern - // (absolute or relative) we don't actually support it here. - $replacements = array( - '\\,' => ',', - '*' => '.*', - ); - - $pattern = strtr($pattern, $replacements); - if (preg_match("|{$pattern}|i", $this->_file) === 1) { - return; - } - } - - if ($stackPtr === null) { - $lineNum = 1; - $column = 1; - } else { - $lineNum = $this->_tokens[$stackPtr]['line']; - $column = $this->_tokens[$stackPtr]['column']; - } - - $this->_errorCount++; - if ($this->_recordErrors === false) { - if (isset($this->_errors[$lineNum]) === false) { - $this->_errors[$lineNum] = 0; - } - $this->_errors[$lineNum]++; - return; - } - - // Work out the warning message. - if (isset($this->ruleset[$sniffCode]['message']) === true) { - $error = $this->ruleset[$sniffCode]['message']; - } - - if (empty($data) === true) { - $message = $error; - } else { - $message = vsprintf($error, $data); - } - - if (isset($this->_errors[$lineNum]) === false) { - $this->_errors[$lineNum] = array(); - } - - if (isset($this->_errors[$lineNum][$column]) === false) { - $this->_errors[$lineNum][$column] = array(); - } - - $this->_errors[$lineNum][$column][] = array( - 'message' => $message, - 'source' => $sniffCode, - 'severity' => $severity, - ); - - }//end addError() - - - /** - * Adds an warning to the warning stack. - * - * @param string $warning The error message. - * @param int $stackPtr The stack position where the error occurred. - * @param string $code A violation code unique to the sniff message. - * @param array $data Replacements for the warning message. - * @param int $severity The severity level for this warning. A value of 0 - * will be converted into the default severity level. - * - * @return void - */ - public function addWarning($warning, $stackPtr, $code='', $data=array(), $severity=0) - { - // Don't bother doing any processing if warnings are just going to - // be hidden in the reports anyway. - if ($this->phpcs->cli->warningSeverity === 0) { - return; - } - - // Work out which sniff generated the warning. - if (substr($code, 0, 9) === 'Internal.') { - // Any internal message. - $sniff = $code; - $sniffCode = $code; - } else { - $parts = explode('_', str_replace('\\', '_', $this->_activeListener)); - if (isset($parts[3]) === true) { - $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3]; - - // Remove "Sniff" from the end. - $sniff = substr($sniff, 0, -5); - } else { - $sniff = 'unknownSniff'; - } - - $sniffCode = $sniff; - if ($code !== '') { - $sniffCode .= '.'.$code; - } - }//end if - - // Make sure this message type is allowed based on the --sniffs - // command line argument values. - if (empty($this->restrictions) === false - && in_array($sniffCode, $this->restrictions) === false - && in_array($sniff, $this->restrictions) === false - ) { - return; - } - - // Make sure this message type has not been set to "error". - if (isset($this->ruleset[$sniffCode]['type']) === true - && $this->ruleset[$sniffCode]['type'] === 'error' - ) { - // Pass this off to the error handler. - $this->addError($warning, $stackPtr, $code, $data, $severity); - return; - } - - // Make sure we are interested in this severity level. - if (isset($this->ruleset[$sniffCode]['severity']) === true) { - $severity = $this->ruleset[$sniffCode]['severity']; - } else if ($severity === 0) { - $severity = PHPCS_DEFAULT_WARN_SEV; - } - - if ($this->phpcs->cli->warningSeverity > $severity) { - return; - } - - // Make sure we are not ignoring this file. - $patterns = $this->phpcs->getIgnorePatterns($sniffCode); - foreach ($patterns as $pattern => $type) { - // While there is support for a type of each pattern - // (absolute or relative) we don't actually support it here. - $replacements = array( - '\\,' => ',', - '*' => '.*', - ); - - $pattern = strtr($pattern, $replacements); - if (preg_match("|{$pattern}|i", $this->_file) === 1) { - return; - } - } - - if ($stackPtr === null) { - $lineNum = 1; - $column = 1; - } else { - $lineNum = $this->_tokens[$stackPtr]['line']; - $column = $this->_tokens[$stackPtr]['column']; - } - - $this->_warningCount++; - if ($this->_recordErrors === false) { - if (isset($this->_warnings[$lineNum]) === false) { - $this->_warnings[$lineNum] = 0; - } - $this->_warnings[$lineNum]++; - return; - } - - // Work out the warning message. - if (isset($this->ruleset[$sniffCode]['message']) === true) { - $warning = $this->ruleset[$sniffCode]['message']; - } - - if (empty($data) === true) { - $message = $warning; - } else { - $message = vsprintf($warning, $data); - } - - if (isset($this->_warnings[$lineNum]) === false) { - $this->_warnings[$lineNum] = array(); - } - - if (isset($this->_warnings[$lineNum][$column]) === false) { - $this->_warnings[$lineNum][$column] = array(); - } - - $this->_warnings[$lineNum][$column][] = array( - 'message' => $message, - 'source' => $sniffCode, - 'severity' => $severity, - ); - - }//end addWarning() - - - /** - * Returns the number of errors raised. - * - * @return int - */ - public function getErrorCount() - { - return $this->_errorCount; - - }//end getErrorCount() - - - /** - * Returns the number of warnings raised. - * - * @return int - */ - public function getWarningCount() - { - return $this->_warningCount; - - }//end getWarningCount() - - - /** - * Returns the list of ignored lines. - * - * @return array - */ - public function getIgnoredLines() - { - return $this->_ignoredLines; - - }//end getIgnoredLines() - - - /** - * Returns the errors raised from processing this file. - * - * @return array - */ - public function getErrors() - { - return $this->_errors; - - }//end getErrors() - - - /** - * Returns the warnings raised from processing this file. - * - * @return array - */ - public function getWarnings() - { - return $this->_warnings; - - }//end getWarnings() - - - /** - * Returns the absolute filename of this file. - * - * @return string - */ - public function getFilename() - { - return $this->_file; - - }//end getFilename() - - - /** - * Creates an array of tokens when given some PHP code. - * - * Starts by using token_get_all() but does a lot of extra processing - * to insert information about the context of the token. - * - * @param string $string The string to tokenize. - * @param object $tokenizer A tokenizer class to use to tokenize the string. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return array - */ - public static function tokenizeString($string, $tokenizer, $eolChar='\n') - { - $tokens = $tokenizer->tokenizeString($string, $eolChar); - - self::_createLineMap($tokens, $tokenizer, $eolChar); - self::_createBracketMap($tokens, $tokenizer, $eolChar); - self::_createParenthesisMap($tokens, $tokenizer, $eolChar); - self::_createParenthesisNestingMap($tokens, $tokenizer, $eolChar); - self::_createScopeMap($tokens, $tokenizer, $eolChar); - - // If we know the width of each tab, convert tabs - // into spaces so sniffs can use one method of checking. - if (PHP_CODESNIFFER_TAB_WIDTH > 0) { - self::_convertTabs($tokens, $tokenizer, $eolChar); - } - - // Column map requires the line map to be complete. - self::_createColumnMap($tokens, $tokenizer, $eolChar); - self::_createLevelMap($tokens, $tokenizer, $eolChar); - - // Allow the tokenizer to do additional processing if required. - $tokenizer->processAdditional($tokens, $eolChar); - - return $tokens; - - }//end tokenizeString() - - - /** - * Creates a map of tokens => line numbers for each token. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createLineMap(&$tokens, $tokenizer, $eolChar) - { - $lineNumber = 1; - $count = count($tokens); - - for ($i = 0; $i < $count; $i++) { - $tokens[$i]['line'] = $lineNumber; - if ($tokens[$i]['content'] === '') { - continue; - } - - $lineNumber += substr_count($tokens[$i]['content'], $eolChar); - } - - }//end _createLineMap() - - - /** - * Converts tabs into spaces. - * - * Each tab can represent between 1 and $width spaces, so - * this cannot be a straight string replace. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _convertTabs(&$tokens, $tokenizer, $eolChar) - { - $currColumn = 1; - $count = count($tokens); - - for ($i = 0; $i < $count; $i++) { - $tokenContent = $tokens[$i]['content']; - - if (strpos($tokenContent, "\t") === false) { - // There are no tabs in this content. - $currColumn += strlen($tokenContent); - } else { - // We need to determine the length of each tab. - $tabs = preg_split( - "|(\t)|", - $tokenContent, - -1, - PREG_SPLIT_DELIM_CAPTURE - ); - - $tabNum = 0; - $tabsToSpaces = array(); - $newContent = ''; - - foreach ($tabs as $content) { - if ($content === '') { - continue; - } - - if (strpos($content, "\t") === false) { - // This piece of content is not a tab. - $currColumn += strlen($content); - $newContent .= $content; - } else { - $lastCurrColumn = $currColumn; - $tabNum++; - - // Move the pointer to the next tab stop. - if (($currColumn % PHP_CODESNIFFER_TAB_WIDTH) === 0) { - // This is the first tab, and we are already at a - // tab stop, so this tab counts as a single space. - $currColumn++; - } else { - $currColumn++; - while (($currColumn % PHP_CODESNIFFER_TAB_WIDTH) != 0) { - $currColumn++; - } - - $currColumn++; - } - - $length = ($currColumn - $lastCurrColumn); - $newContent .= str_repeat(' ', $length); - }//end if - }//end foreach - - $tokens[$i]['content'] = $newContent; - }//end if - - if (isset($tokens[($i + 1)]['line']) === true - && $tokens[($i + 1)]['line'] !== $tokens[$i]['line'] - ) { - $currColumn = 1; - } - }//end for - - }//end _convertTabs() - - - /** - * Creates a column map. - * - * The column map indicates where the token started on the line where it - * exists. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createColumnMap(&$tokens, $tokenizer, $eolChar) - { - $currColumn = 1; - $count = count($tokens); - - for ($i = 0; $i < $count; $i++) { - $tokens[$i]['column'] = $currColumn; - if (isset($tokens[($i + 1)]['line']) === true - && $tokens[($i + 1)]['line'] !== $tokens[$i]['line'] - ) { - $currColumn = 1; - } else { - $currColumn += strlen($tokens[$i]['content']); - } - } - - }//end _createColumnMap() - - - /** - * Creates a map for opening and closing of square brackets. - * - * Each bracket token (T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET) - * has a reference to their opening and closing bracket - * (bracket_opener and bracket_closer). - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createBracketMap(&$tokens, $tokenizer, $eolChar) - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START BRACKET MAP ***".PHP_EOL; - } - - $squareOpeners = array(); - $curlyOpeners = array(); - $numTokens = count($tokens); - - for ($i = 0; $i < $numTokens; $i++) { - switch ($tokens[$i]['code']) { - case T_OPEN_SQUARE_BRACKET: - $squareOpeners[] = $i; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($squareOpeners)); - echo str_repeat("\t", count($curlyOpeners)); - echo "=> Found square bracket opener at $i".PHP_EOL; - } - - break; - case T_OPEN_CURLY_BRACKET: - if (isset($tokens[$i]['scope_closer']) === false) { - $curlyOpeners[] = $i; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($squareOpeners)); - echo str_repeat("\t", count($curlyOpeners)); - echo "=> Found curly bracket opener at $i".PHP_EOL; - } - } - break; - case T_CLOSE_SQUARE_BRACKET: - if (empty($squareOpeners) === false) { - $opener = array_pop($squareOpeners); - $tokens[$i]['bracket_opener'] = $opener; - $tokens[$i]['bracket_closer'] = $i; - $tokens[$opener]['bracket_opener'] = $opener; - $tokens[$opener]['bracket_closer'] = $i; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($squareOpeners)); - echo str_repeat("\t", count($curlyOpeners)); - echo "\t=> Found square bracket closer at $i for $opener".PHP_EOL; - } - } - break; - case T_CLOSE_CURLY_BRACKET: - if (empty($curlyOpeners) === false - && isset($tokens[$i]['scope_opener']) === false - ) { - $opener = array_pop($curlyOpeners); - $tokens[$i]['bracket_opener'] = $opener; - $tokens[$i]['bracket_closer'] = $i; - $tokens[$opener]['bracket_opener'] = $opener; - $tokens[$opener]['bracket_closer'] = $i; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($squareOpeners)); - echo str_repeat("\t", count($curlyOpeners)); - echo "\t=> Found curly bracket closer at $i for $opener".PHP_EOL; - } - } - break; - default: - continue; - }//end switch - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END BRACKET MAP ***".PHP_EOL; - } - - }//end _createBracketMap() - - - /** - * Creates a map for opening and closing of parenthesis. - * - * Each parenthesis token (T_OPEN_PARENTHESIS and T_CLOSE_PARENTHESIS) has a - * reference to their opening and closing parenthesis (parenthesis_opener - * and parenthesis_closer). - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createParenthesisMap(&$tokens, $tokenizer, $eolChar) - { - $openers = array(); - $numTokens = count($tokens); - $openOwner = null; - - for ($i = 0; $i < $numTokens; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$parenthesisOpeners) === true) { - $tokens[$i]['parenthesis_opener'] = null; - $tokens[$i]['parenthesis_closer'] = null; - $tokens[$i]['parenthesis_owner'] = $i; - $openOwner = $i; - } else if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - $openers[] = $i; - $tokens[$i]['parenthesis_opener'] = $i; - if ($openOwner !== null) { - $tokens[$openOwner]['parenthesis_opener'] = $i; - $tokens[$i]['parenthesis_owner'] = $openOwner; - $openOwner = null; - } - } else if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { - // Did we set an owner for this set of parenthesis? - $numOpeners = count($openers); - if ($numOpeners !== 0) { - $opener = array_pop($openers); - if (isset($tokens[$opener]['parenthesis_owner']) === true) { - $owner = $tokens[$opener]['parenthesis_owner']; - - $tokens[$owner]['parenthesis_closer'] = $i; - $tokens[$i]['parenthesis_owner'] = $owner; - } - - $tokens[$i]['parenthesis_opener'] = $opener; - $tokens[$i]['parenthesis_closer'] = $i; - $tokens[$opener]['parenthesis_closer'] = $i; - } - }//end if - }//end for - - }//end _createParenthesisMap() - - - /** - * Creates a map for the parenthesis tokens that surround other tokens. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createParenthesisNestingMap( - &$tokens, - $tokenizer, - $eolChar - ) { - $numTokens = count($tokens); - $map = array(); - for ($i = 0; $i < $numTokens; $i++) { - if (isset($tokens[$i]['parenthesis_opener']) === true - && $i === $tokens[$i]['parenthesis_opener'] - ) { - if (empty($map) === false) { - $tokens[$i]['nested_parenthesis'] = $map; - } - - if (isset($tokens[$i]['parenthesis_closer']) === true) { - $map[$tokens[$i]['parenthesis_opener']] - = $tokens[$i]['parenthesis_closer']; - } - } else if (isset($tokens[$i]['parenthesis_closer']) === true - && $i === $tokens[$i]['parenthesis_closer'] - ) { - array_pop($map); - if (empty($map) === false) { - $tokens[$i]['nested_parenthesis'] = $map; - } - } else { - if (empty($map) === false) { - $tokens[$i]['nested_parenthesis'] = $map; - } - }//end if - }//end for - - }//end _createParenthesisNestingMap() - - - /** - * Creates a scope map of tokens that open scopes. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - * @see _recurseScopeMap() - */ - private static function _createScopeMap(&$tokens, $tokenizer, $eolChar) - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START SCOPE MAP ***".PHP_EOL; - } - - $numTokens = count($tokens); - for ($i = 0; $i < $numTokens; $i++) { - // Check to see if the current token starts a new scope. - if (isset($tokenizer->scopeOpeners[$tokens[$i]['code']]) === true) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$i]['type']; - $content = str_replace($eolChar, '\n', $tokens[$i]['content']); - echo "\tStart scope map at $i: $type => $content".PHP_EOL; - } - - $i = self::_recurseScopeMap( - $tokens, - $numTokens, - $tokenizer, - $eolChar, - $i - ); - } - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END SCOPE MAP ***".PHP_EOL; - } - - }//end _createScopeMap() - - - /** - * Recurses though the scope openers to build a scope map. - * - * @param array &$tokens The array of tokens to process. - * @param int $numTokens The size of the tokens array. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * @param int $stackPtr The position in the stack of the token that - * opened the scope (eg. an IF token or FOR token). - * @param int $depth How many scope levels down we are. - * @param int &$ignore How many curly braces we are ignoring. - * - * @return int The position in the stack that closed the scope. - */ - private static function _recurseScopeMap( - &$tokens, - $numTokens, - $tokenizer, - $eolChar, - $stackPtr, - $depth=1, - &$ignore=0 - ) { - $opener = null; - $currType = $tokens[$stackPtr]['code']; - $startLine = $tokens[$stackPtr]['line']; - - // We will need this to restore the value if we end up - // returning a token ID that causes our calling function to go back - // over already ignored braces. - $originalIgnore = $ignore; - - // If the start token for this scope opener is the same as - // the scope token, we have already found our opener. - if (in_array($currType, $tokenizer->scopeOpeners[$currType]['start']) === true) { - $opener = $stackPtr; - } - - for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { - $tokenType = $tokens[$i]['code']; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$i]['type']; - $content = str_replace($eolChar, '\n', $tokens[$i]['content']); - echo str_repeat("\t", $depth); - echo "Process token $i ["; - if ($opener !== null) { - echo "opener:$opener;"; - } - - if ($ignore > 0) { - echo "ignore=$ignore;"; - } - - echo "]: $type => $content".PHP_EOL; - } - - // Very special case for IF statements in PHP that can be defined without - // scope tokens. If an IF statement below this one has an opener but no - // keyword, the opener will be incorrectly assigned to this IF statement. - // E.g., if (1) 1; 1 ? (1 ? 1 : 1) : 1; - if (($currType === T_IF || $currType === T_ELSE) && $opener === null && $tokens[$i]['code'] === T_SEMICOLON) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Found semicolon before scope opener for $stackPtr ($type), bailing".PHP_EOL; - } - - return $i; - } - - // Is this an opening condition ? - if (isset($tokenizer->scopeOpeners[$tokenType]) === true) { - if ($opener === null) { - // Found another opening condition but still haven't - // found our opener, so we are never going to find one. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Couldn't find scope opener for $stackPtr ($type), bailing".PHP_EOL; - } - - return $stackPtr; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* token is an opening condition *'.PHP_EOL; - } - - $isShared - = ($tokenizer->scopeOpeners[$tokenType]['shared'] === true); - - if (isset($tokens[$i]['scope_condition']) === true) { - // We've been here before. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* already processed, skipping *'.PHP_EOL; - } - - if ($isShared === false - && isset($tokens[$i]['scope_closer']) === true - ) { - $i = $tokens[$i]['scope_closer']; - } - - continue; - } else if ($currType === $tokenType - && $isShared === false - && $opener === null - ) { - // We haven't yet found our opener, but we have found another - // scope opener which is the same type as us, and we don't - // share openers, so we will never find one. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* it was another token\'s opener, bailing *'.PHP_EOL; - } - - return $stackPtr; - } else { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* searching for opener *'.PHP_EOL; - } - - if (in_array(T_CLOSE_CURLY_BRACKET, $tokenizer->scopeOpeners[$tokenType]['end']) === true) { - $oldIgnore = $ignore; - $ignore = 0; - } - - $i = self::_recurseScopeMap( - $tokens, - $numTokens, - $tokenizer, - $eolChar, - $i, - ($depth + 1), - $ignore - ); - - if (in_array(T_CLOSE_CURLY_BRACKET, $tokenizer->scopeOpeners[$tokenType]['end']) === true) { - $ignore = $oldIgnore; - } - }//end if - }//end if - - if (in_array($tokenType, $tokenizer->scopeOpeners[$currType]['start']) === true - && $opener === null - ) { - if ($tokenType === T_OPEN_CURLY_BRACKET) { - // Make sure this is actually an opener and not a - // string offset (e.g., $var{0}). - for ($x = ($i - 1); $x > 0; $x--) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } else { - // If the first non-whitespace/comment token is a - // variable or object operator then this is an opener - // for a string offset and not a scope. - if ($tokens[$x]['code'] === T_VARIABLE - || $tokens[$x]['code'] === T_OBJECT_OPERATOR - ) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* ignoring curly brace *'.PHP_EOL; - } - - $ignore++; - }//end if - - break; - }//end if - }//end for - }//end if - - if ($ignore === 0) { - // We found the opening scope token for $currType. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Found scope opener for $stackPtr ($type)".PHP_EOL; - } - - $opener = $i; - } - } else if (in_array($tokenType, $tokenizer->scopeOpeners[$currType]['end']) === true - && $opener !== null - ) { - if ($ignore > 0 && $tokenType === T_CLOSE_CURLY_BRACKET) { - // The last opening bracket must have been for a string - // offset or alike, so let's ignore it. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* finished ignoring curly brace *'.PHP_EOL; - } - - $ignore--; - } else { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Found scope closer for $stackPtr ($type)".PHP_EOL; - } - - foreach (array($stackPtr, $opener, $i) as $token) { - $tokens[$token]['scope_condition'] = $stackPtr; - $tokens[$token]['scope_opener'] = $opener; - $tokens[$token]['scope_closer'] = $i; - } - - if ($tokenizer->scopeOpeners[$tokens[$stackPtr]['code']]['shared'] === true) { - // As we are going back to where we started originally, restore - // the ignore value back to its original value. - $ignore = $originalIgnore; - return $opener; - } else { - return $i; - } - }//end if - } else if ($tokenType === T_OPEN_PARENTHESIS) { - if (isset($tokens[$i]['parenthesis_owner']) === true) { - $owner = $tokens[$i]['parenthesis_owner']; - if (in_array($tokens[$owner]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true - && isset($tokens[$i]['parenthesis_closer']) === true - ) { - // If we get into here, then we opened a parenthesis for - // a scope (eg. an if or else if). We can just skip to - // the closing parenthesis. - $i = $tokens[$i]['parenthesis_closer']; - - // Update the start of the line so that when we check to see - // if the closing parenthesis is more than 3 lines away from - // the statement, we check from the closing parenthesis. - $startLine - = $tokens[$tokens[$i]['parenthesis_closer']]['line']; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* skipping parenthesis *'.PHP_EOL; - } - } - }//end if - } else if ($tokenType === T_OPEN_CURLY_BRACKET && $opener !== null) { - // We opened something that we don't have a scope opener for. - // Examples of this are curly brackets for string offsets etc. - // We want to ignore this so that we don't have an invalid scope - // map. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* ignoring curly brace *'.PHP_EOL; - } - - $ignore++; - } else if ($opener === null - && isset($tokenizer->scopeOpeners[$currType]) === true - ) { - // If we still haven't found the opener after 3 lines, - // we're not going to find it, unless we know it requires - // an opener (in which case we better keep looking) or the last - // token was empty (in which case we'll just confirm there is - // more code in this file and not just a big comment). - if ($tokens[$i]['line'] >= ($startLine + 3) - && in_array($tokens[($i - 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false - ) { - if ($tokenizer->scopeOpeners[$currType]['strict'] === true) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - $lines = ($tokens[$i]['line'] - $startLine); - echo str_repeat("\t", $depth); - echo "=> Still looking for $stackPtr ($type) scope opener after $lines lines".PHP_EOL; - } - } else { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Couldn't find scope opener for $stackPtr ($type), bailing".PHP_EOL; - } - - return $stackPtr; - } - } - } else if ($opener !== null - && $tokenType !== T_BREAK - && in_array($tokenType, $tokenizer->endScopeTokens) === true - ) { - if (isset($tokens[$i]['scope_condition']) === false) { - if ($ignore > 0) { - // We found the end token for the opener we were ignoring. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo '* finished ignoring curly brace *'.PHP_EOL; - } - - $ignore--; - } else { - // We found a token that closes the scope but it doesn't - // have a condition, so it belongs to another token and - // our token doesn't have a closer, so pretend this is - // the closer. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", $depth); - echo "=> Found (unexpected) scope closer for $stackPtr ($type)".PHP_EOL; - } - - foreach (array($stackPtr, $opener) as $token) { - $tokens[$token]['scope_condition'] = $stackPtr; - $tokens[$token]['scope_opener'] = $opener; - $tokens[$token]['scope_closer'] = $i; - } - - return ($i - 1); - }//end if - }//end if - }//end if - }//end for - - return $stackPtr; - - }//end _recurseScopeMap() - - - /** - * Constructs the level map. - * - * The level map adds a 'level' indice to each token which indicates the - * depth that a token within a set of scope blocks. It also adds a - * 'condition' indice which is an array of the scope conditions that opened - * each of the scopes - position 0 being the first scope opener. - * - * @param array &$tokens The array of tokens to process. - * @param object $tokenizer The tokenizer being used to process this file. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - private static function _createLevelMap(&$tokens, $tokenizer, $eolChar) - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START LEVEL MAP ***".PHP_EOL; - } - - $numTokens = count($tokens); - $level = 0; - $conditions = array(); - $lastOpener = null; - $openers = array(); - - for ($i = 0; $i < $numTokens; $i++) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$i]['type']; - $line = $tokens[$i]['line']; - $content = str_replace($eolChar, '\n', $tokens[$i]['content']); - echo str_repeat("\t", ($level + 1)); - echo "Process token $i on line $line [lvl:$level;"; - if (empty($conditions) !== true) { - $condString = 'conds;'; - foreach ($conditions as $condition) { - $condString .= token_name($condition).','; - } - - echo rtrim($condString, ',').';'; - } - - echo "]: $type => $content".PHP_EOL; - } - - $tokens[$i]['level'] = $level; - $tokens[$i]['conditions'] = $conditions; - - if (isset($tokens[$i]['scope_condition']) === true) { - // Check to see if this token opened the scope. - if ($tokens[$i]['scope_opener'] === $i) { - $stackPtr = $tokens[$i]['scope_condition']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", ($level + 1)); - echo "=> Found scope opener for $stackPtr ($type)".PHP_EOL; - } - - $stackPtr = $tokens[$i]['scope_condition']; - - // If we find a scope opener that has a shared closer, - // then we need to go back over the condition map that we - // just created and fix ourselves as we just added some - // conditions where there was none. This happens for T_CASE - // statements that are using the same break statement. - if ($lastOpener !== null && $tokens[$lastOpener]['scope_closer'] === $tokens[$i]['scope_closer']) { - // This opener shares its closer with the previous opener, - // but we still need to check if the two openers share their - // closer with each other directly (like CASE and DEFAULT) - // or if they are just sharing because one doesn't have a - // closer (like CASE with no BREAK using a SWITCHes closer). - $thisType = $tokens[$tokens[$i]['scope_condition']]['code']; - $opener = $tokens[$lastOpener]['scope_condition']; - - $isShared = in_array( - $tokens[$opener]['code'], - $tokenizer->scopeOpeners[$thisType]['with'] - ); - - $sameEnd = ($tokenizer->scopeOpeners[$thisType]['end'][0] === $tokenizer->scopeOpeners[$tokens[$opener]['code']]['end'][0]); - if ($isShared === true && $sameEnd === true) { - $badToken = $opener; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$badToken]['type']; - echo str_repeat("\t", ($level + 1)); - echo "* shared closer, cleaning up $badToken ($type) *".PHP_EOL; - } - - for ($x = $tokens[$i]['scope_condition']; $x <= $i; $x++) { - $oldConditions = $tokens[$x]['conditions']; - $oldLevel = $tokens[$x]['level']; - $tokens[$x]['level']--; - unset($tokens[$x]['conditions'][$badToken]); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$x]['type']; - $oldConds = ''; - foreach ($oldConditions as $condition) { - $oldConds .= token_name($condition).','; - } - - $oldConds = rtrim($oldConds, ','); - - $newConds = ''; - foreach ($tokens[$x]['conditions'] as $condition) { - $newConds .= token_name($condition).','; - } - - $newConds = rtrim($newConds, ','); - - $newLevel = $tokens[$x]['level']; - echo str_repeat("\t", ($level + 1)); - echo "* cleaned $x ($type) *".PHP_EOL; - echo str_repeat("\t", ($level + 2)); - echo "=> level changed from $oldLevel to $newLevel".PHP_EOL; - echo str_repeat("\t", ($level + 2)); - echo "=> conditions changed from $oldConds to $newConds".PHP_EOL; - }//end if - }//end for - - unset($conditions[$badToken]); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$badToken]['type']; - echo str_repeat("\t", ($level + 1)); - echo "* token $badToken ($type) removed from conditions array *".PHP_EOL; - } - - unset ($openers[$lastOpener]); - - $level--; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", ($level + 2)); - echo '* level decreased *'.PHP_EOL; - } - }//end if - }//end if - - $level++; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", ($level + 1)); - echo '* level increased *'.PHP_EOL; - } - - $conditions[$stackPtr] = $tokens[$stackPtr]['code']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$stackPtr]['type']; - echo str_repeat("\t", ($level + 1)); - echo "* token $stackPtr ($type) added to conditions array *".PHP_EOL; - } - - $lastOpener = $tokens[$i]['scope_opener']; - if ($lastOpener !== null) { - $openers[$lastOpener] = $lastOpener; - } - } else if ($tokens[$i]['scope_closer'] === $i) { - foreach (array_reverse($openers) as $opener) { - if ($tokens[$opener]['scope_closer'] === $i) { - $oldOpener = array_pop($openers); - if (empty($openers) === false) { - $lastOpener = array_pop($openers); - $openers[$lastOpener] = $lastOpener; - } else { - $lastOpener = null; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$oldOpener]['type']; - echo str_repeat("\t", ($level + 1)); - echo "=> Found scope closer for $oldOpener ($type)".PHP_EOL; - } - - $oldCondition = array_pop($conditions); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", ($level + 1)); - echo '* token '.token_name($oldCondition).' removed from conditions array *'.PHP_EOL; - } - - // Make sure this closer actually belongs to us. - // Either the condition also has to think this is the - // closer, or it has to allow sharing with us. - $condition - = $tokens[$tokens[$i]['scope_condition']]['code']; - if ($condition !== $oldCondition) { - if (in_array($condition, $tokenizer->scopeOpeners[$oldCondition]['with']) === false) { - $badToken = $tokens[$oldOpener]['scope_condition']; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = token_name($oldCondition); - echo str_repeat("\t", ($level + 1)); - echo "* scope closer was bad, cleaning up $badToken ($type) *".PHP_EOL; - } - - for ($x = ($oldOpener + 1); $x <= $i; $x++) { - $oldConditions = $tokens[$x]['conditions']; - $oldLevel = $tokens[$x]['level']; - $tokens[$x]['level']--; - unset($tokens[$x]['conditions'][$badToken]); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$x]['type']; - $oldConds = ''; - foreach ($oldConditions as $condition) { - $oldConds .= token_name($condition).','; - } - - $oldConds = rtrim($oldConds, ','); - - $newConds = ''; - foreach ($tokens[$x]['conditions'] as $condition) { - $newConds .= token_name($condition).','; - } - - $newConds = rtrim($newConds, ','); - - $newLevel = $tokens[$x]['level']; - echo str_repeat("\t", ($level + 1)); - echo "* cleaned $x ($type) *".PHP_EOL; - echo str_repeat("\t", ($level + 2)); - echo "=> level changed from $oldLevel to $newLevel".PHP_EOL; - echo str_repeat("\t", ($level + 2)); - echo "=> conditions changed from $oldConds to $newConds".PHP_EOL; - }//end if - }//end for - }//end if - }//end if - - $level--; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", ($level + 2)); - echo '* level decreased *'.PHP_EOL; - } - - $tokens[$i]['level'] = $level; - $tokens[$i]['conditions'] = $conditions; - }//end if - }//end foreach - }//end if - }//end if - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END LEVEL MAP ***".PHP_EOL; - } - - }//end _createLevelMap() - - - /** - * Returns the declaration names for T_CLASS, T_INTERFACE and T_FUNCTION tokens. - * - * @param int $stackPtr The position of the declaration token which - * declared the class, interface or function. - * - * @return string|null The name of the class, interface or function. - * or NULL if the function is a closure. - * @throws PHP_CodeSniffer_Exception If the specified token is not of type - * T_FUNCTION, T_CLASS or T_INTERFACE. - */ - public function getDeclarationName($stackPtr) - { - $tokenCode = $this->_tokens[$stackPtr]['code']; - if ($tokenCode !== T_FUNCTION - && $tokenCode !== T_CLASS - && $tokenCode !== T_INTERFACE - && $tokenCode !== T_TRAIT - ) { - throw new PHP_CodeSniffer_Exception('Token type is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); - } - - if ($tokenCode === T_FUNCTION - && $this->isAnonymousFunction($stackPtr) === true - ) { - return null; - } - - $token = $this->findNext(T_STRING, $stackPtr); - return $this->_tokens[$token]['content']; - - }//end getDeclarationName() - - - /** - * Check if the token at the specified position is a anonymous function. - * - * @param int $stackPtr The position of the declaration token which - * declared the class, interface or function. - * - * @return boolean - * @throws PHP_CodeSniffer_Exception If the specified token is not of type - * T_FUNCTION - */ - public function isAnonymousFunction($stackPtr) - { - $tokenCode = $this->_tokens[$stackPtr]['code']; - if ($tokenCode !== T_FUNCTION) { - throw new PHP_CodeSniffer_Exception('Token type is not T_FUNCTION'); - } - - if (isset($this->_tokens[$stackPtr]['parenthesis_opener']) === false) { - // Something is not right with this function. - return false; - } - - $name = $this->findNext(T_STRING, ($stackPtr + 1)); - if ($name === false) { - // No name found. - return true; - } - - $open = $this->_tokens[$stackPtr]['parenthesis_opener']; - if ($name > $open) { - return true; - } - - return false; - - }//end isAnonymousFunction() - - - /** - * Returns the method parameters for the specified T_FUNCTION token. - * - * Each parameter is in the following format: - * - * - * 0 => array( - * 'name' => '$var', // The variable name. - * 'pass_by_reference' => false, // Passed by reference. - * 'type_hint' => string, // Type hint for array or custom type - * ) - * - * - * Parameters with default values have and additional array indice of - * 'default' with the value of the default as a string. - * - * @param int $stackPtr The position in the stack of the T_FUNCTION token - * to acquire the parameters for. - * - * @return array() - * @throws PHP_CodeSniffer_Exception If the specified $stackPtr is not of - * type T_FUNCTION. - */ - public function getMethodParameters($stackPtr) - { - if ($this->_tokens[$stackPtr]['code'] !== T_FUNCTION) { - throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_FUNCTION'); - } - - $opener = $this->_tokens[$stackPtr]['parenthesis_opener']; - $closer = $this->_tokens[$stackPtr]['parenthesis_closer']; - - $vars = array(); - $currVar = null; - $defaultStart = null; - $paramCount = 0; - $passByReference = false; - $typeHint = ''; - - for ($i = ($opener + 1); $i <= $closer; $i++) { - // Check to see if this token has a parenthesis opener. If it does - // its likely to be an array, which might have arguments in it, which - // we cause problems in our parsing below, so lets just skip to the - // end of it. - if (isset($this->_tokens[$i]['parenthesis_opener']) === true) { - // Don't do this if it's the close parenthesis for the method. - if ($i !== $this->_tokens[$i]['parenthesis_closer']) { - $i = ($this->_tokens[$i]['parenthesis_closer'] + 1); - } - } - - switch ($this->_tokens[$i]['code']) { - case T_BITWISE_AND: - $passByReference = true; - break; - case T_VARIABLE: - $currVar = $i; - break; - case T_ARRAY_HINT: - case T_CALLABLE: - $typeHint = $this->_tokens[$i]['content']; - break; - case T_STRING: - // This is a string, so it may be a type hint, but it could - // also be a constant used as a default value. - $prevComma = $this->findPrevious(T_COMMA, $i, $opener); - if ($prevComma !== false) { - $nextEquals = $this->findNext(T_EQUAL, $prevComma, $i); - if ($nextEquals !== false) { - break; - } - } - - if ($defaultStart === null) { - $typeHint .= $this->_tokens[$i]['content']; - } - - break; - case T_NS_SEPARATOR: - // Part of a type hint or default value. - if ($defaultStart === null) { - $typeHint .= $this->_tokens[$i]['content']; - } - - break; - case T_CLOSE_PARENTHESIS: - case T_COMMA: - // If it's null, then there must be no parameters for this - // method. - if ($currVar === null) { - continue; - } - - $vars[$paramCount] = array(); - $vars[$paramCount]['name'] = $this->_tokens[$currVar]['content']; - - if ($defaultStart !== null) { - $vars[$paramCount]['default'] - = $this->getTokensAsString( - $defaultStart, - ($i - $defaultStart) - ); - } - - $vars[$paramCount]['pass_by_reference'] = $passByReference; - $vars[$paramCount]['type_hint'] = $typeHint; - - // Reset the vars, as we are about to process the next parameter. - $defaultStart = null; - $passByReference = false; - $typeHint = ''; - - $paramCount++; - break; - case T_EQUAL: - $defaultStart = ($i + 1); - break; - }//end switch - }//end for - - return $vars; - - }//end getMethodParameters() - - - /** - * Returns the visibility and implementation properties of a method. - * - * The format of the array is: - * - * array( - * 'scope' => 'public', // public private or protected - * 'scope_specified' => true, // true is scope keyword was found. - * 'is_abstract' => false, // true if the abstract keyword was found. - * 'is_final' => false, // true if the final keyword was found. - * 'is_static' => false, // true if the static keyword was found. - * 'is_closure' => false, // true if no name is found. - * ); - * - * - * @param int $stackPtr The position in the stack of the T_FUNCTION token to - * acquire the properties for. - * - * @return array - * @throws PHP_CodeSniffer_Exception If the specified position is not a - * T_FUNCTION token. - */ - public function getMethodProperties($stackPtr) - { - if ($this->_tokens[$stackPtr]['code'] !== T_FUNCTION) { - throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_FUNCTION'); - } - - $valid = array( - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_STATIC, - T_FINAL, - T_ABSTRACT, - T_WHITESPACE, - T_COMMENT, - T_DOC_COMMENT, - ); - - $scope = 'public'; - $scopeSpecified = false; - $isAbstract = false; - $isFinal = false; - $isStatic = false; - $isClosure = $this->isAnonymousFunction($stackPtr); - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (in_array($this->_tokens[$i]['code'], $valid) === false) { - break; - } - - switch ($this->_tokens[$i]['code']) { - case T_PUBLIC: - $scope = 'public'; - $scopeSpecified = true; - break; - case T_PRIVATE: - $scope = 'private'; - $scopeSpecified = true; - break; - case T_PROTECTED: - $scope = 'protected'; - $scopeSpecified = true; - break; - case T_ABSTRACT: - $isAbstract = true; - break; - case T_FINAL: - $isFinal = true; - break; - case T_STATIC: - $isStatic = true; - break; - }//end switch - }//end for - - return array( - 'scope' => $scope, - 'scope_specified' => $scopeSpecified, - 'is_abstract' => $isAbstract, - 'is_final' => $isFinal, - 'is_static' => $isStatic, - 'is_closure' => $isClosure, - ); - - }//end getMethodProperties() - - - /** - * Returns the visibility and implementation properties of the class member - * variable found at the specified position in the stack. - * - * The format of the array is: - * - * - * array( - * 'scope' => 'public', // public private or protected - * 'is_static' => false, // true if the static keyword was found. - * ); - * - * - * @param int $stackPtr The position in the stack of the T_VARIABLE token to - * acquire the properties for. - * - * @return array - * @throws PHP_CodeSniffer_Exception If the specified position is not a - * T_VARIABLE token, or if the position is not - * a class member variable. - */ - public function getMemberProperties($stackPtr) - { - if ($this->_tokens[$stackPtr]['code'] !== T_VARIABLE) { - throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_VARIABLE'); - } - - $conditions = array_keys($this->_tokens[$stackPtr]['conditions']); - $ptr = array_pop($conditions); - if (isset($this->_tokens[$ptr]) === false - || $this->_tokens[$ptr]['code'] !== T_CLASS - ) { - if (isset($this->_tokens[$ptr]) === true - && $this->_tokens[$ptr]['code'] === T_INTERFACE - ) { - // T_VARIABLEs in interfaces can actually be method arguments - // but they wont be seen as being inside the method because there - // are no scope openers and closers for abstract methods. If it is in - // parentheses, we can be pretty sure it is a method argument. - if (isset($this->_tokens[$stackPtr]['nested_parenthesis']) === false - || empty($this->_tokens[$stackPtr]['nested_parenthesis']) === true - ) { - $error = 'Possible parse error: interfaces may not include member vars'; - $this->addWarning($error, $stackPtr, 'Internal.ParseError.InterfaceHasMemberVar'); - return array(); - } - } else { - throw new PHP_CodeSniffer_Exception('$stackPtr is not a class member var'); - } - } - - $valid = array( - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_STATIC, - T_WHITESPACE, - T_COMMENT, - T_DOC_COMMENT, - T_VARIABLE, - T_COMMA, - ); - - $scope = 'public'; - $scopeSpecified = false; - $isStatic = false; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (in_array($this->_tokens[$i]['code'], $valid) === false) { - break; - } - - switch ($this->_tokens[$i]['code']) { - case T_PUBLIC: - $scope = 'public'; - $scopeSpecified = true; - break; - case T_PRIVATE: - $scope = 'private'; - $scopeSpecified = true; - break; - case T_PROTECTED: - $scope = 'protected'; - $scopeSpecified = true; - break; - case T_STATIC: - $isStatic = true; - break; - } - }//end for - - return array( - 'scope' => $scope, - 'scope_specified' => $scopeSpecified, - 'is_static' => $isStatic, - ); - - }//end getMemberProperties() - - - /** - * Returns the visibility and implementation properties of a class. - * - * The format of the array is: - * - * array( - * 'is_abstract' => false, // true if the abstract keyword was found. - * 'is_final' => false, // true if the final keyword was found. - * ); - * - * - * @param int $stackPtr The position in the stack of the T_CLASS token to - * acquire the properties for. - * - * @return array - * @throws PHP_CodeSniffer_Exception If the specified position is not a - * T_CLASS token. - */ - public function getClassProperties($stackPtr) - { - if ($this->_tokens[$stackPtr]['code'] !== T_CLASS) { - throw new PHP_CodeSniffer_Exception('$stackPtr must be of type T_CLASS'); - } - - $valid = array( - T_FINAL, - T_ABSTRACT, - T_WHITESPACE, - T_COMMENT, - T_DOC_COMMENT, - ); - - $isAbstract = false; - $isFinal = false; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (in_array($this->_tokens[$i]['code'], $valid) === false) { - break; - } - - switch ($this->_tokens[$i]['code']) { - case T_ABSTRACT: - $isAbstract = true; - break; - - case T_FINAL: - $isFinal = true; - break; - } - }//end for - - return array( - 'is_abstract' => $isAbstract, - 'is_final' => $isFinal, - ); - - }//end getClassProperties() - - - /** - * Determine if the passed token is a reference operator. - * - * Returns true if the specified token position represents a reference. - * Returns false if the token represents a bitwise operator. - * - * @param int $stackPtr The position of the T_BITWISE_AND token. - * - * @return boolean - */ - public function isReference($stackPtr) - { - if ($this->_tokens[$stackPtr]['code'] !== T_BITWISE_AND) { - return false; - } - - $tokenBefore = $this->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($stackPtr - 1), - null, - true - ); - - if ($this->_tokens[$tokenBefore]['code'] === T_FUNCTION) { - // Function returns a reference. - return true; - } - - if ($this->_tokens[$tokenBefore]['code'] === T_DOUBLE_ARROW) { - // Inside a foreach loop, this is a reference. - return true; - } - - if ($this->_tokens[$tokenBefore]['code'] === T_AS) { - // Inside a foreach loop, this is a reference. - return true; - } - - if (in_array($this->_tokens[$tokenBefore]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { - // This is directly after an assignment. It's a reference. Even if - // it is part of an operation, the other tests will handle it. - return true; - } - - if (isset($this->_tokens[$stackPtr]['nested_parenthesis']) === true) { - $brackets = $this->_tokens[$stackPtr]['nested_parenthesis']; - $lastBracket = array_pop($brackets); - if (isset($this->_tokens[$lastBracket]['parenthesis_owner']) === true) { - $owner = $this->_tokens[$this->_tokens[$lastBracket]['parenthesis_owner']]; - if ($owner['code'] === T_FUNCTION - || $owner['code'] === T_CLOSURE - || $owner['code'] === T_ARRAY - ) { - // Inside a function or array declaration, this is a reference. - return true; - } - } else { - $prev = $this->findPrevious( - array(T_WHITESPACE), - ($this->_tokens[$lastBracket]['parenthesis_opener'] - 1), - null, - true - ); - - if ($prev !== false && $this->_tokens[$prev]['code'] === T_USE) { - return true; - } - } - } - - $tokenAfter = $this->findNext( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($stackPtr + 1), - null, - true - ); - - if ($this->_tokens[$tokenAfter]['code'] === T_VARIABLE - && ($this->_tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS - || $this->_tokens[$tokenBefore]['code'] === T_COMMA) - ) { - return true; - } - - return false; - - }//end isReference() - - - /** - * Returns the content of the tokens from the specified start position in - * the token stack for the specified length. - * - * @param int $start The position to start from in the token stack. - * @param int $length The length of tokens to traverse from the start pos. - * - * @return string The token contents. - */ - public function getTokensAsString($start, $length) - { - $str = ''; - $end = ($start + $length); - if ($end > $this->numTokens) { - $end = $this->numTokens; - } - - for ($i = $start; $i < $end; $i++) { - $str .= $this->_tokens[$i]['content']; - } - - return $str; - - }//end getTokensAsString() - - - /** - * Returns the position of the next specified token(s). - * - * If a value is specified, the next token of the specified type(s) - * containing the specified value will be returned. - * - * Returns false if no token can be found. - * - * @param int|array $types The type(s) of tokens to search for. - * @param int $start The position to start searching from in the - * token stack. - * @param int $end The end position to fail if no token is found. - * if not specified or null, end will default to - * the start of the token stack. - * @param bool $exclude If true, find the next token that are NOT of - * the types specified in $types. - * @param string $value The value that the token(s) must be equal to. - * If value is omitted, tokens with any value will - * be returned. - * @param bool $local If true, tokens outside the current statement - * will not be checked. IE. checking will stop - * at the next semi-colon found. - * - * @return int | bool - * @see findNext() - */ - public function findPrevious( - $types, - $start, - $end=null, - $exclude=false, - $value=null, - $local=false - ) { - $types = (array) $types; - - if ($end === null) { - $end = 0; - } - - for ($i = $start; $i >= $end; $i--) { - $found = (bool) $exclude; - foreach ($types as $type) { - if ($this->_tokens[$i]['code'] === $type) { - $found = !$exclude; - break; - } - } - - if ($found === true) { - if ($value === null) { - return $i; - } else if ($this->_tokens[$i]['content'] === $value) { - return $i; - } - } - - if ($local === true && $this->_tokens[$i]['code'] === T_SEMICOLON) { - break; - } - }//end for - - return false; - - }//end findPrevious() - - - /** - * Returns the position of the next specified token(s). - * - * If a value is specified, the next token of the specified type(s) - * containing the specified value will be returned. - * - * Returns false if no token can be found. - * - * @param int|array $types The type(s) of tokens to search for. - * @param int $start The position to start searching from in the - * token stack. - * @param int $end The end position to fail if no token is found. - * if not specified or null, end will default to - * the end of the token stack. - * @param bool $exclude If true, find the next token that is NOT of - * a type specified in $types. - * @param string $value The value that the token(s) must be equal to. - * If value is omitted, tokens with any value will - * be returned. - * @param bool $local If true, tokens outside the current statement - * will not be checked. i.e., checking will stop - * at the next semi-colon found. - * - * @return int | bool - * @see findPrevious() - */ - public function findNext( - $types, - $start, - $end=null, - $exclude=false, - $value=null, - $local=false - ) { - $types = (array) $types; - - if ($end === null || $end > $this->numTokens) { - $end = $this->numTokens; - } - - for ($i = $start; $i < $end; $i++) { - $found = (bool) $exclude; - foreach ($types as $type) { - if ($this->_tokens[$i]['code'] === $type) { - $found = !$exclude; - break; - } - } - - if ($found === true) { - if ($value === null) { - return $i; - } else if ($this->_tokens[$i]['content'] === $value) { - return $i; - } - } - - if ($local === true && $this->_tokens[$i]['code'] === T_SEMICOLON) { - break; - } - }//end for - - return false; - - }//end findNext() - - - /** - * Returns the position of the first token on a line, matching given type. - * - * Returns false if no token can be found. - * - * @param int|array $types The type(s) of tokens to search for. - * @param int $start The position to start searching from in the - * token stack. The first token matching on - * this line before this token will be returned. - * @param bool $exclude If true, find the token that is NOT of - * the types specified in $types. - * @param string $value The value that the token must be equal to. - * If value is omitted, tokens with any value will - * be returned. - * - * @return int | bool - */ - public function findFirstOnLine($types, $start, $exclude=false, $value=null) - { - if (is_array($types) === false) { - $types = array($types); - } - - $foundToken = false; - - for ($i = $start; $i >= 0; $i--) { - if ($this->_tokens[$i]['line'] < $this->_tokens[$start]['line']) { - break; - } - - $found = $exclude; - foreach ($types as $type) { - if ($exclude === false) { - if ($this->_tokens[$i]['code'] === $type) { - $found = true; - break; - } - } else { - if ($this->_tokens[$i]['code'] === $type) { - $found = false; - break; - } - } - } - - if ($found === true) { - if ($value === null) { - $foundToken = $i; - } else if ($this->_tokens[$i]['content'] === $value) { - $foundToken = $i; - } - } - }//end for - - return $foundToken; - - }//end findFirstOnLine() - - - /** - * Determine if the passed token has a condition of one of the passed types. - * - * @param int $stackPtr The position of the token we are checking. - * @param int|array $types The type(s) of tokens to search for. - * - * @return boolean - */ - public function hasCondition($stackPtr, $types) - { - // Check for the existence of the token. - if (isset($this->_tokens[$stackPtr]) === false) { - return false; - } - - // Make sure the token has conditions. - if (isset($this->_tokens[$stackPtr]['conditions']) === false) { - return false; - } - - $types = (array) $types; - $conditions = $this->_tokens[$stackPtr]['conditions']; - - foreach ($types as $type) { - if (in_array($type, $conditions) === true) { - // We found a token with the required type. - return true; - } - } - - return false; - - }//end hasCondition() - - - /** - * Return the position of the condition for the passed token. - * - * Returns FALSE if the token does not have the condition. - * - * @param int $stackPtr The position of the token we are checking. - * @param int $type The type of token to search for. - * - * @return int - */ - public function getCondition($stackPtr, $type) - { - // Check for the existence of the token. - if (isset($this->_tokens[$stackPtr]) === false) { - return false; - } - - // Make sure the token has conditions. - if (isset($this->_tokens[$stackPtr]['conditions']) === false) { - return false; - } - - $conditions = $this->_tokens[$stackPtr]['conditions']; - foreach ($conditions as $token => $condition) { - if ($condition === $type) { - return $token; - } - } - - return false; - - }//end getCondition() - - - /** - * Returns the name of the class that the specified class extends. - * - * Returns FALSE on error or if there is no extended class name. - * - * @param int $stackPtr The stack position of the class. - * - * @return string - */ - public function findExtendedClassName($stackPtr) - { - // Check for the existence of the token. - if (isset($this->_tokens[$stackPtr]) === false) { - return false; - } - - if ($this->_tokens[$stackPtr]['code'] !== T_CLASS) { - return false; - } - - if (isset($this->_tokens[$stackPtr]['scope_closer']) === false) { - return false; - } - - $classCloserIndex = $this->_tokens[$stackPtr]['scope_closer']; - $extendsIndex = $this->findNext(T_EXTENDS, $stackPtr, $classCloserIndex); - if (false === $extendsIndex) { - return false; - } - - $find = array( - T_NS_SEPARATOR, - T_STRING, - T_WHITESPACE, - ); - - $end = $this->findNext($find, ($extendsIndex + 1), $classCloserIndex, true); - $name = $this->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1)); - $name = trim($name); - - if ($name === '') { - return false; - } - - return $name; - - }//end findExtendedClassName() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Report.php b/codesniffer/CodeSniffer/Report.php deleted file mode 100644 index 87f2044b2..000000000 --- a/codesniffer/CodeSniffer/Report.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Represents a PHP_CodeSniffer report. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -interface PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ); - - - /** - * Generate the actual report. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ); - - -}//end interface - -?> diff --git a/codesniffer/CodeSniffer/Reporting.php b/codesniffer/CodeSniffer/Reporting.php deleted file mode 100644 index d5edbbc39..000000000 --- a/codesniffer/CodeSniffer/Reporting.php +++ /dev/null @@ -1,315 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (is_file(dirname(__FILE__).'/../CodeSniffer.php') === true) { - include_once dirname(__FILE__).'/../CodeSniffer.php'; -} else { - include_once 'PHP/CodeSniffer.php'; -} - -/** - * A class to manage reporting. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reporting -{ - - /** - * Total number of files that contain errors or warnings. - * - * @var int - */ - public $totalFiles = 0; - - /** - * Total number of errors found during the run. - * - * @var int - */ - public $totalErrors = 0; - - /** - * Total number of warnings found during the run. - * - * @var int - */ - public $totalWarnings = 0; - - /** - * A list of reports that have written partial report output. - * - * @var array - */ - private $_cachedReports = array(); - - /** - * A cache of report objects. - * - * @var array - */ - private $_reports = array(); - - - /** - * Produce the appropriate report object based on $type parameter. - * - * @param string $type The type of the report. - * - * @return PHP_CodeSniffer_Report - * @throws PHP_CodeSniffer_Exception If report is not available. - */ - public function factory($type) - { - $type = ucfirst($type); - if (isset($this->_reports[$type]) === true) { - return $this->_reports[$type]; - } - - $filename = $type.'.php'; - $reportClassName = 'PHP_CodeSniffer_Reports_'.$type; - if (class_exists($reportClassName, true) === false) { - throw new PHP_CodeSniffer_Exception('Report type "'.$type.'" not found.'); - } - - $reportClass = new $reportClassName(); - if (false === ($reportClass instanceof PHP_CodeSniffer_Report)) { - throw new PHP_CodeSniffer_Exception('Class "'.$reportClassName.'" must implement the "PHP_CodeSniffer_Report" interface.'); - } - - $this->_reports[$type] = $reportClass; - return $this->_reports[$type]; - - }//end factory() - - - /** - * Actually generates the report. - * - * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed. - * @param array $cliValues An array of command line arguments. - * - * @return void - */ - public function cacheFileReport(PHP_CodeSniffer_File $phpcsFile, array $cliValues) - { - if (isset($cliValues['reports']) === false) { - // This happens during unit testing, or any time someone just wants - // the error data and not the printed report. - return; - } - - $reportData = $this->prepareFileReport($phpcsFile); - $errorsShown = false; - - foreach ($cliValues['reports'] as $report => $output) { - $reportClass = self::factory($report); - - ob_start(); - $result = $reportClass->generateFileReport($reportData, $cliValues['showSources'], $cliValues['reportWidth']); - if ($result === true) { - $errorsShown = true; - } - - $generatedReport = ob_get_contents(); - ob_end_clean(); - - if ($generatedReport !== '') { - $flags = FILE_APPEND; - if (in_array($report, $this->_cachedReports) === false) { - $this->_cachedReports[] = $report; - $flags = null; - } - - if ($output === null) { - if ($cliValues['reportFile'] !== null) { - $output = $cliValues['reportFile']; - } else { - $output = sys_get_temp_dir().'/phpcs-'.$report.'.tmp'; - } - } - - file_put_contents($output, $generatedReport, $flags); - } - }//end foreach - - if ($errorsShown === true) { - $this->totalFiles++; - $this->totalErrors += $reportData['errors']; - $this->totalWarnings += $reportData['warnings']; - } - - }//end cacheFileReport() - - - /** - * Actually generates the report. - * - * @param string $report Report type. - * @param boolean $showSources Show sources? - * @param string $reportFile Report file to generate. - * @param integer $reportWidth Report max width. - * - * @return integer - */ - public function printReport( - $report, - $showSources, - $reportFile='', - $reportWidth=80 - ) { - if ($this->totalFiles === 0) { - // No files generated errors. - return 0; - } - - $reportClass = self::factory($report); - - if ($reportFile !== null) { - $filename = $reportFile; - $toScreen = false; - ob_start(); - } else { - $filename = sys_get_temp_dir().'/phpcs-'.$report.'.tmp'; - $toScreen = true; - } - - if (file_exists($filename) === true) { - $reportCache = file_get_contents($filename); - } else { - $reportCache = ''; - } - - $reportClass->generate( - $reportCache, - $this->totalFiles, - $this->totalErrors, - $this->totalWarnings, - $showSources, - $reportWidth, - $toScreen - ); - - if ($reportFile !== null) { - $generatedReport = ob_get_contents(); - ob_end_clean(); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo $generatedReport; - } - - $generatedReport = trim($generatedReport); - file_put_contents($reportFile, $generatedReport.PHP_EOL); - } else if (file_exists($filename) === true) { - unlink($filename); - } - - return ($this->totalErrors + $this->totalWarnings); - - }//end printReport() - - - /** - * Pre-process and package violations for all files. - * - * Used by error reports to get a packaged list of all errors in each file. - * - * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed. - * - * @return array - */ - public function prepareFileReport(PHP_CodeSniffer_File $phpcsFile) - { - $report = array( - 'filename' => $phpcsFile->getFilename(), - 'errors' => $phpcsFile->getErrorCount(), - 'warnings' => $phpcsFile->getWarningCount(), - 'messages' => array(), - ); - - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Prefect score! - return $report; - } - - $errors = array(); - - // Merge errors and warnings. - foreach ($phpcsFile->getErrors() as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - $newErrors = array(); - foreach ($colErrors as $data) { - $newErrors[] = array( - 'message' => $data['message'], - 'source' => $data['source'], - 'severity' => $data['severity'], - 'type' => 'ERROR', - ); - } - - $errors[$line][$column] = $newErrors; - }//end foreach - - ksort($errors[$line]); - }//end foreach - - foreach ($phpcsFile->getWarnings() as $line => $lineWarnings) { - foreach ($lineWarnings as $column => $colWarnings) { - $newWarnings = array(); - foreach ($colWarnings as $data) { - $newWarnings[] = array( - 'message' => $data['message'], - 'source' => $data['source'], - 'severity' => $data['severity'], - 'type' => 'WARNING', - ); - } - - if (isset($errors[$line]) === false) { - $errors[$line] = array(); - } - - if (isset($errors[$line][$column]) === true) { - $errors[$line][$column] = array_merge( - $newWarnings, - $errors[$line][$column] - ); - } else { - $errors[$line][$column] = $newWarnings; - } - }//end foreach - - ksort($errors[$line]); - }//end foreach - - ksort($errors); - $report['messages'] = $errors; - return $report; - - }//end prepareFileReport() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Checkstyle.php b/codesniffer/CodeSniffer/Reports/Checkstyle.php deleted file mode 100644 index ea5fa63e0..000000000 --- a/codesniffer/CodeSniffer/Reports/Checkstyle.php +++ /dev/null @@ -1,126 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checkstyle report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Checkstyle implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - $out = new XMLWriter; - $out->openMemory(); - $out->setIndent(true); - - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - $out->startElement('file'); - $out->writeAttribute('name', $report['filename']); - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $error['type'] = strtolower($error['type']); - if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { - $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); - } - - $out->startElement('error'); - $out->writeAttribute('line', $line); - $out->writeAttribute('column', $column); - $out->writeAttribute('severity', $error['type']); - $out->writeAttribute('message', $error['message']); - $out->writeAttribute('source', $error['source']); - $out->endElement(); - } - } - }//end foreach - - $out->endElement(); - echo $out->flush(); - - return true; - - }//end generateFileReport() - - - /** - * Prints all violations for processed files, in a Checkstyle format. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo ''.PHP_EOL; - echo ''.PHP_EOL; - echo $cachedData; - echo ''.PHP_EOL; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Csv.php b/codesniffer/CodeSniffer/Reports/Csv.php deleted file mode 100644 index 3bf1b2023..000000000 --- a/codesniffer/CodeSniffer/Reports/Csv.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Csv report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Csv implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $filename = str_replace('"', '\"', $report['filename']); - $message = str_replace('"', '\"', $error['message']); - $type = strtolower($error['type']); - $source = $error['source']; - $severity = $error['severity']; - echo "\"$filename\",$line,$column,$type,\"$message\",$source,$severity".PHP_EOL; - } - } - } - - return true; - - }//end generateFileReport() - - - /** - * Generates a csv report. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo 'File,Line,Column,Type,Message,Source,Severity'.PHP_EOL; - echo $cachedData; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Emacs.php b/codesniffer/CodeSniffer/Reports/Emacs.php deleted file mode 100644 index 8229ec54a..000000000 --- a/codesniffer/CodeSniffer/Reports/Emacs.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Emacs report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Emacs implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $message = $error['message']; - if ($showSources === true) { - $message .= ' ('.$error['source'].')'; - } - - $type = strtolower($error['type']); - echo $report['filename'].':'.$line.':'.$column.': '.$type.' - '.$message.PHP_EOL; - } - } - } - - return true; - - }//end generateFileReport() - - - /** - * Generates an emacs report. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo $cachedData; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Full.php b/codesniffer/CodeSniffer/Reports/Full.php deleted file mode 100644 index 738bcbf3f..000000000 --- a/codesniffer/CodeSniffer/Reports/Full.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Full report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Full implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - $width = max($width, 70); - $file = $report['filename']; - - echo PHP_EOL.'FILE: '; - if (strlen($file) <= ($width - 9)) { - echo $file; - } else { - echo '...'.substr($file, (strlen($file) - ($width - 9))); - } - - echo PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - - echo 'FOUND '.$report['errors'].' ERROR(S) '; - if ($report['warnings'] > 0) { - echo 'AND '.$report['warnings'].' WARNING(S) '; - } - - echo 'AFFECTING '.count($report['messages']).' LINE(S)'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - - // Work out the max line number for formatting. - $maxLine = 0; - foreach ($report['messages'] as $line => $lineErrors) { - if ($line > $maxLine) { - $maxLine = $line; - } - } - - $maxLineLength = strlen($maxLine); - - // The length of the word ERROR or WARNING; used for padding. - if ($report['warnings'] > 0) { - $typeLength = 7; - } else { - $typeLength = 5; - } - - // The padding that all lines will require that are - // printing an error message overflow. - $paddingLine2 = str_repeat(' ', ($maxLineLength + 1)); - $paddingLine2 .= ' | '; - $paddingLine2 .= str_repeat(' ', $typeLength); - $paddingLine2 .= ' | '; - - // The maximum amount of space an error message can use. - $maxErrorSpace = ($width - strlen($paddingLine2) - 1); - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $message = $error['message']; - if ($showSources === true) { - $message .= ' ('.$error['source'].')'; - } - - // The padding that goes on the front of the line. - $padding = ($maxLineLength - strlen($line)); - $errorMsg = wordwrap( - $message, - $maxErrorSpace, - PHP_EOL.$paddingLine2 - ); - - echo ' '.str_repeat(' ', $padding).$line.' | '.$error['type']; - if ($error['type'] === 'ERROR') { - if ($report['warnings'] > 0) { - echo ' '; - } - } - - echo ' | '.$errorMsg.PHP_EOL; - }//end foreach - }//end foreach - }//end foreach - - echo str_repeat('-', $width).PHP_EOL.PHP_EOL; - return true; - - }//end generateFileReport() - - - /** - * Prints all errors and warnings for each file processed. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo $cachedData; - - if ($toScreen === true - && PHP_CODESNIFFER_INTERACTIVE === false - && class_exists('PHP_Timer', false) === true - ) { - echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; - } - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Gitblame.php b/codesniffer/CodeSniffer/Reports/Gitblame.php deleted file mode 100644 index fd3fd449d..000000000 --- a/codesniffer/CodeSniffer/Reports/Gitblame.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Gitblame report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Ben Selby - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: 1.2.2 - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Gitblame extends PHP_CodeSniffer_Reports_VersionControl -{ - - /** - * The name of the report we want in the output - * - * @var string - */ - protected $reportName = 'GIT'; - - - /** - * Extract the author from a blame line. - * - * @param string $line Line to parse. - * - * @return mixed string or false if impossible to recover. - */ - protected function getAuthor($line) - { - $blameParts = array(); - $line = preg_replace('|\s+|', ' ', $line); - preg_match( - '|\(.+[0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]+\)|', - $line, - $blameParts - ); - - if (isset($blameParts[0]) === false) { - return false; - } - - $parts = explode(' ', $blameParts[0]); - - if (count($parts) < 2) { - return false; - } - - $parts = array_slice($parts, 0, (count($parts) - 2)); - - return preg_replace('|\(|', '', implode($parts, ' ')); - - }//end getAuthor() - - - /** - * Gets the blame output. - * - * @param string $filename File to blame. - * - * @return array - */ - protected function getBlameContent($filename) - { - $cwd = getcwd(); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Getting GIT blame info for '.basename($filename).'... '; - } - - $fileParts = explode(DIRECTORY_SEPARATOR, $filename); - $found = false; - $location = ''; - while (empty($fileParts) === false) { - array_pop($fileParts); - $location = implode($fileParts, DIRECTORY_SEPARATOR); - if (is_dir($location.DIRECTORY_SEPARATOR.'.git') === true) { - $found = true; - break; - } - } - - if ($found === true) { - chdir($location); - } else { - echo 'ERROR: Could not locate .git directory '.PHP_EOL.PHP_EOL; - exit(2); - } - - $command = 'git blame --date=short "'.$filename.'"'; - $handle = popen($command, 'r'); - if ($handle === false) { - echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; - exit(2); - } - - $rawContent = stream_get_contents($handle); - fclose($handle); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'DONE'.PHP_EOL; - } - - $blames = explode("\n", $rawContent); - chdir($cwd); - - return $blames; - - }//end getBlameContent() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Hgblame.php b/codesniffer/CodeSniffer/Reports/Hgblame.php deleted file mode 100644 index c69597e53..000000000 --- a/codesniffer/CodeSniffer/Reports/Hgblame.php +++ /dev/null @@ -1,134 +0,0 @@ - - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Mercurial report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Ben Selby - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Hgblame extends PHP_CodeSniffer_Reports_VersionControl -{ - - /** - * The name of the report we want in the output - * - * @var string - */ - protected $reportName = 'MERCURIAL'; - - - /** - * Extract the author from a blame line. - * - * @param string $line Line to parse. - * - * @return mixed string or false if impossible to recover. - */ - protected function getAuthor($line) - { - $blameParts = array(); - $line = preg_replace('|\s+|', ' ', $line); - - preg_match( - '|(.+[0-9]{2}:[0-9]{2}:[0-9]{2}\s[0-9]{4}\s.[0-9]{4}:)|', - $line, - $blameParts - ); - - if (isset($blameParts[0]) === false) { - return false; - } - - $parts = explode(' ', $blameParts[0]); - - if (count($parts) < 6) { - return false; - } - - $parts = array_slice($parts, 0, (count($parts) - 6)); - - return trim(preg_replace('|<.+>|', '', implode($parts, ' '))); - - }//end getAuthor() - - - /** - * Gets the blame output. - * - * @param string $filename File to blame. - * - * @return array - */ - protected function getBlameContent($filename) - { - $cwd = getcwd(); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Getting MERCURIAL blame info for '.basename($filename).'... '; - } - - $fileParts = explode(DIRECTORY_SEPARATOR, $filename); - $found = false; - $location = ''; - while (empty($fileParts) === false) { - array_pop($fileParts); - $location = implode($fileParts, DIRECTORY_SEPARATOR); - if (is_dir($location.DIRECTORY_SEPARATOR.'.hg') === true) { - $found = true; - break; - } - } - - if ($found === true) { - chdir($location); - } else { - echo 'ERROR: Could not locate .hg directory '.PHP_EOL.PHP_EOL; - exit(2); - } - - $command = 'hg blame -u -d -v "'.$filename.'"'; - $handle = popen($command, 'r'); - if ($handle === false) { - echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; - exit(2); - } - - $rawContent = stream_get_contents($handle); - fclose($handle); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'DONE'.PHP_EOL; - } - - $blames = explode("\n", $rawContent); - chdir($cwd); - - return $blames; - - }//end getBlameContent() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Json.php b/codesniffer/CodeSniffer/Reports/Json.php deleted file mode 100644 index 0df413fcb..000000000 --- a/codesniffer/CodeSniffer/Reports/Json.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Json report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Jeffrey Fisher - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Json implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - - $filename = str_replace('"', '\"', $report['filename']); - $filename = str_replace('/', '\/', $report['filename']); - echo "\"$filename\":{"; - echo '"errors":'.$report['errors'].',"warnings":'.$report['warnings'].',"messages":['; - - $messages = ''; - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $error['message'] = str_replace('"', '\"', $error['message']); - $error['message'] = str_replace('/', '\/', $error['message']); - - $messages .= '{"message":"'.$error['message'].'",'; - $messages .= '"source":"'.$error['source'].'",'; - $messages .= '"severity":'.$error['severity'].','; - $messages .= '"type":"'.$error['type'].'",'; - $messages .= '"line":'.$line.',"column":'.$column.'},'; - } - } - } - - echo rtrim($messages, ','); - echo ']},'; - - return true; - - }//end generateFileReport() - - - /** - * Generates a JSON report. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo '{"totals":{"errors":'.$totalErrors.',"warnings":'.$totalWarnings.'},"files":{'; - echo rtrim($cachedData, ','); - echo "}}"; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Junit.php b/codesniffer/CodeSniffer/Reports/Junit.php deleted file mode 100644 index 888e70a82..000000000 --- a/codesniffer/CodeSniffer/Reports/Junit.php +++ /dev/null @@ -1,148 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * JUnit report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Oleg Lobach - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Junit implements PHP_CodeSniffer_Report -{ - - /** - * A count of tests that have been performed. - * - * @var int - */ - private $_tests = 0; - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if (count($report['messages']) === 0) { - $this->_tests++; - } else { - $this->_tests += ($report['errors'] + $report['warnings']); - } - - $out = new XMLWriter; - $out->openMemory(); - $out->setIndent(true); - - $out->startElement('testsuite'); - $out->writeAttribute('name', $report['filename']); - - if (count($report['messages']) === 0) { - $out->writeAttribute('tests', 1); - $out->writeAttribute('failures', 0); - - $out->startElement('testcase'); - $out->writeAttribute('name', $report['filename']); - $out->endElement(); - } else { - $failures = ($report['errors'] + $report['warnings']); - $out->writeAttribute('tests', $failures); - $out->writeAttribute('failures', $failures); - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $out->startElement('testcase'); - $out->writeAttribute('name', $error['source'].' at '.$report['filename']." ($line:$column)"); - - $error['type'] = strtolower($error['type']); - if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { - $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); - } - - $out->startElement('failure'); - $out->writeAttribute('type', $error['type']); - $out->writeAttribute('message', $error['message']); - $out->endElement(); - - $out->endElement(); - } - } - } - }//end if - - $out->endElement(); - echo $out->flush(); - return true; - - }//end generateFileReport() - - - /** - * Prints all violations for processed files, in a proprietary XML format. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - $phpcs = new PHP_CodeSniffer; - $failures = ($totalErrors + $totalWarnings); - echo ''.PHP_EOL; - echo ''.PHP_EOL; - echo $cachedData; - echo ''.PHP_EOL; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Notifysend.php b/codesniffer/CodeSniffer/Reports/Notifysend.php deleted file mode 100644 index 2bde834c0..000000000 --- a/codesniffer/CodeSniffer/Reports/Notifysend.php +++ /dev/null @@ -1,262 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2012 Christian Weiske - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Notify-send report for PHP_CodeSniffer. - * - * Supported configuration parameters: - * - notifysend_path - Full path to notify-send cli command - * - notifysend_timeout - Timeout in milliseconds - * - notifysend_showok - Show "ok, all fine" messages (0/1) - * - * @category PHP - * @package PHP_CodeSniffer - * @author Christian Weiske - * @author Greg Sherwood - * @copyright 2012 Christian Weiske - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Notifysend implements PHP_CodeSniffer_Report -{ - - /** - * Notification timeout in milliseconds. - * - * @var integer - */ - protected $timeout = 3000; - - /** - * Path to notify-send command. - * - * @var string - */ - protected $path = 'notify-send'; - - /** - * Show "ok, all fine" messages. - * - * @var boolean - */ - protected $showOk = true; - - /** - * Version of installed notify-send executable. - * - * @var string - */ - protected $version = null; - - /** - * A record of the last file checked. - * - * This is used in case we only checked one file and need to print - * the name/path of the file. We wont have access to the checked file list - * after the run has been completed. - * - * @var string - */ - private $_lastCheckedFile = ''; - - - /** - * Load configuration data. - * - * @return void - */ - public function __construct() - { - $path = PHP_CodeSniffer::getConfigData('notifysend_path'); - if ($path !== null) { - $this->path = $path; - } - - $timeout = PHP_CodeSniffer::getConfigData('notifysend_timeout'); - if ($timeout !== null) { - $this->timeout = (int) $timeout; - } - - $showOk = PHP_CodeSniffer::getConfigData('notifysend_showok'); - if ($showOk !== null) { - $this->showOk = (boolean) $showOk; - } - - $this->version = str_replace( - 'notify-send ', - '', - exec($this->path . ' --version') - ); - - }//end __construct() - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - // We don't need to print anything, but we want this file counted - // in the total number of checked files even if it has no errors. - $this->_lastCheckedFile = $report['filename']; - return true; - - }//end generateFileReport() - - - /** - * Generates a summary of errors and warnings for each file processed. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - $msg = $this->generateMessage($totalFiles, $totalErrors, $totalWarnings); - if ($msg === null) { - if ($this->showOk === true) { - $this->notifyAllFine(); - } - } else { - $this->notifyErrors($msg); - } - - }//end generate() - - - /** - * Generate the error message to show to the user. - * - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * - * @return string Error message or NULL if no error/warning found. - */ - protected function generateMessage($totalFiles, $totalErrors, $totalWarnings) - { - if ($totalErrors === 0 && $totalWarnings === 0) { - // Nothing to print. - return null; - } - - $msg = ''; - if ($totalFiles > 1) { - $msg .= 'Checked '.$totalFiles.' files'.PHP_EOL; - } else { - $msg .= $this->_lastCheckedFile.PHP_EOL; - } - - if ($totalWarnings > 0) { - $msg .= $totalWarnings.' warnings'.PHP_EOL; - } - - if ($totalErrors > 0) { - $msg .= $totalErrors.' errors'.PHP_EOL; - } - - return $msg; - - }//end generateMessage() - - - /** - * Tell the user that all is fine and no error/warning has been found. - * - * @return void - */ - protected function notifyAllFine() - { - $cmd = $this->getBasicCommand(); - $cmd .= ' -i info'; - $cmd .= ' "PHP CodeSniffer: Ok"'; - $cmd .= ' "All fine"'; - exec($cmd); - - }//end notifyAllFine() - - - /** - * Tell the user that errors/warnings have been found. - * - * @param string $msg Message to display. - * - * @return void - */ - protected function notifyErrors($msg) - { - $cmd = $this->getBasicCommand(); - $cmd .= ' -i error'; - $cmd .= ' "PHP CodeSniffer: Error"'; - $cmd .= ' '.escapeshellarg(trim($msg)); - exec($cmd); - - }//end notifyErrors() - - - /** - * Generate and return the basic notify-send command string to execute. - * - * @return string Shell command with common parameters. - */ - protected function getBasicCommand() - { - $cmd = escapeshellcmd($this->path); - $cmd .= ' --category dev.validate'; - $cmd .= ' -h int:transient:1'; - $cmd .= ' -t '.(int) $this->timeout; - if (version_compare($this->version, '0.7.3', '>=') === true) { - $cmd .= ' -a phpcs'; - } - - return $cmd; - - }//end getBasicCommand() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Source.php b/codesniffer/CodeSniffer/Reports/Source.php deleted file mode 100644 index 9eaad3824..000000000 --- a/codesniffer/CodeSniffer/Reports/Source.php +++ /dev/null @@ -1,235 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Source report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Source implements PHP_CodeSniffer_Report -{ - - /** - * A cache of source stats collected during the run. - * - * @var array - */ - private $_sourceCache = array(); - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $source = $error['source']; - if (isset($this->_sourceCache[$source]) === false) { - $this->_sourceCache[$source] = 1; - } else { - $this->_sourceCache[$source]++; - } - } - } - } - - return true; - - }//end generateFileReport() - - - /** - * Prints the source of all errors and warnings. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - $width = max($width, 70); - - if (empty($this->_sourceCache) === true) { - // Nothing to show. - return; - } - - asort($this->_sourceCache); - $this->_sourceCache = array_reverse($this->_sourceCache); - - echo PHP_EOL.'PHP CODE SNIFFER VIOLATION SOURCE SUMMARY'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - if ($showSources === true) { - echo 'SOURCE'.str_repeat(' ', ($width - 11)).'COUNT'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - } else { - echo 'STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 40)).'COUNT'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - } - - foreach ($this->_sourceCache as $source => $count) { - if ($showSources === true) { - echo $source.str_repeat(' ', ($width - 5 - strlen($source))); - } else { - $parts = explode('.', $source); - - if (strlen($parts[0]) > 8) { - $parts[0] = substr($parts[0], 0, ((strlen($parts[0]) - 8) * -1)); - } - - echo $parts[0].str_repeat(' ', (10 - strlen($parts[0]))); - - $category = $this->makeFriendlyName($parts[1]); - if (strlen($category) > 18) { - $category = substr($category, 0, ((strlen($category) - 18) * -1)); - } - - echo $category.str_repeat(' ', (20 - strlen($category))); - - $sniff = $this->makeFriendlyName($parts[2]); - if (isset($parts[3]) === true) { - $name = $this->makeFriendlyName($parts[3]); - $name[0] = strtolower($name[0]); - $sniff .= ' '.$name; - } - - if (strlen($sniff) > ($width - 37)) { - $sniff = substr($sniff, 0, ($width - 37 - strlen($sniff))); - } - - echo $sniff.str_repeat(' ', ($width - 35 - strlen($sniff))); - }//end if - - echo $count.PHP_EOL; - }//end foreach - - echo str_repeat('-', $width).PHP_EOL; - echo 'A TOTAL OF '.($totalErrors + $totalWarnings).' SNIFF VIOLATION(S) '; - echo 'WERE FOUND IN '.count($this->_sourceCache).' SOURCE(S)'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL.PHP_EOL; - - if ($toScreen === true - && PHP_CODESNIFFER_INTERACTIVE === false - && class_exists('PHP_Timer', false) === true - ) { - echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; - } - - }//end generate() - - - /** - * Converts a camel caps name into a readable string. - * - * @param string $name The camel caps name to convert. - * - * @return string - */ - public function makeFriendlyName($name) - { - $friendlyName = ''; - $length = strlen($name); - - $lastWasUpper = false; - $lastWasNumeric = false; - for ($i = 0; $i < $length; $i++) { - if (is_numeric($name[$i]) === true) { - if ($lastWasNumeric === false) { - $friendlyName .= ' '; - } - - $lastWasUpper = false; - $lastWasNumeric = true; - } else { - $lastWasNumeric = false; - - $char = strtolower($name[$i]); - if ($char === $name[$i]) { - // Lowercase. - $lastWasUpper = false; - } else { - // Uppercase. - if ($lastWasUpper === false) { - $friendlyName .= ' '; - $next = $name[($i + 1)]; - if (strtolower($next) === $next) { - // Next char is lowercase so it is a word boundary. - $name[$i] = strtolower($name[$i]); - } - } - - $lastWasUpper = true; - } - }//end if - - $friendlyName .= $name[$i]; - }//end for - - $friendlyName = trim($friendlyName); - $friendlyName[0] = strtoupper($friendlyName[0]); - - return $friendlyName; - - }//end makeFriendlyName() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Summary.php b/codesniffer/CodeSniffer/Reports/Summary.php deleted file mode 100644 index c928a7016..000000000 --- a/codesniffer/CodeSniffer/Reports/Summary.php +++ /dev/null @@ -1,131 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Summary report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Summary implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * If verbose output is enabled, results are shown for all files, even if - * they have no errors or warnings. If verbose output is disabled, we only - * show files that have at least one warning or error. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - if (PHP_CODESNIFFER_VERBOSITY === 0 - && $report['errors'] === 0 - && $report['warnings'] === 0 - ) { - // Nothing to print. - return false; - } - - $width = max($width, 70); - $file = $report['filename']; - - $padding = ($width - 18 - strlen($file)); - if ($padding < 0) { - $file = '...'.substr($file, (($padding * -1) + 3)); - $padding = 0; - } - - echo $file.str_repeat(' ', $padding).' '; - echo $report['errors']; - echo str_repeat(' ', (8 - strlen((string) $report['errors']))); - echo $report['warnings']; - echo PHP_EOL; - - return true; - - }//end generateFileReport() - - - /** - * Generates a summary of errors and warnings for each file processed. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - echo PHP_EOL.'PHP CODE SNIFFER REPORT SUMMARY'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - echo 'FILE'.str_repeat(' ', ($width - 20)).'ERRORS WARNINGS'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - - echo $cachedData; - - echo str_repeat('-', $width).PHP_EOL; - echo 'A TOTAL OF '.$totalErrors.' ERROR(S) '; - echo 'AND '.$totalWarnings.' WARNING(S) '; - - echo 'WERE FOUND IN '.$totalFiles.' FILE(S)'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL.PHP_EOL; - - if ($toScreen === true - && PHP_CODESNIFFER_INTERACTIVE === false - && class_exists('PHP_Timer', false) === true - ) { - echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; - } - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Svnblame.php b/codesniffer/CodeSniffer/Reports/Svnblame.php deleted file mode 100644 index de06c7e13..000000000 --- a/codesniffer/CodeSniffer/Reports/Svnblame.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Svnblame report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Svnblame extends PHP_CodeSniffer_Reports_VersionControl -{ - - /** - * The name of the report we want in the output - * - * @var string - */ - protected $reportName = 'SVN'; - - - /** - * Extract the author from a blame line. - * - * @param string $line Line to parse. - * - * @return mixed string or false if impossible to recover. - */ - protected function getAuthor($line) - { - $blameParts = array(); - preg_match('|\s*([^\s]+)\s+([^\s]+)|', $line, $blameParts); - - if (isset($blameParts[2]) === false) { - return false; - } - - return $blameParts[2]; - - }//end getAuthor() - - - /** - * Gets the blame output. - * - * @param string $filename File to blame. - * - * @return array - */ - protected function getBlameContent($filename) - { - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'Getting SVN blame info for '.basename($filename).'... '; - } - - $command = 'svn blame "'.$filename.'"'; - $handle = popen($command, 'r'); - if ($handle === false) { - echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; - exit(2); - } - - $rawContent = stream_get_contents($handle); - fclose($handle); - - if (PHP_CODESNIFFER_VERBOSITY > 0) { - echo 'DONE'.PHP_EOL; - } - - $blames = explode("\n", $rawContent); - - return $blames; - - }//end getBlameContent() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/VersionControl.php b/codesniffer/CodeSniffer/Reports/VersionControl.php deleted file mode 100644 index 93565c7b2..000000000 --- a/codesniffer/CodeSniffer/Reports/VersionControl.php +++ /dev/null @@ -1,257 +0,0 @@ - - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Version control report base class for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Ben Selby - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: 1.2.2 - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_Reports_VersionControl implements PHP_CodeSniffer_Report -{ - - /** - * The name of the report we want in the output. - * - * @var string - */ - protected $reportName = 'VERSION CONTROL'; - - /** - * A cache of author stats collected during the run. - * - * @var array - */ - private $_authorCache = array(); - - /** - * A cache of blame stats collected during the run. - * - * @var array - */ - private $_praiseCache = array(); - - /** - * A cache of source stats collected during the run. - * - * @var array - */ - private $_sourceCache = array(); - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - $blames = $this->getBlameContent($report['filename']); - - foreach ($report['messages'] as $line => $lineErrors) { - $author = $this->getAuthor($blames[($line - 1)]); - if ($author === false) { - continue; - } - - if (isset($this->_authorCache[$author]) === false) { - $this->_authorCache[$author] = 0; - $this->_praiseCache[$author] = array( - 'good' => 0, - 'bad' => 0, - ); - } - - $this->_praiseCache[$author]['bad']++; - - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $this->_authorCache[$author]++; - - if ($showSources === true) { - $source = $error['source']; - if (isset($this->_sourceCache[$author][$source]) === false) { - $this->_sourceCache[$author][$source] = 1; - } else { - $this->_sourceCache[$author][$source]++; - } - } - } - } - - unset($blames[($line - 1)]); - }//end foreach - - // No go through and give the authors some credit for - // all the lines that do not have errors. - foreach ($blames as $line) { - $author = $this->getAuthor($line); - if (false === $author) { - continue; - } - - if (isset($this->_authorCache[$author]) === false) { - // This author doesn't have any errors. - if (PHP_CODESNIFFER_VERBOSITY === 0) { - continue; - } - - $this->_authorCache[$author] = 0; - $this->_praiseCache[$author] = array( - 'good' => 0, - 'bad' => 0, - ); - } - - $this->_praiseCache[$author]['good']++; - }//end foreach - - return true; - - }//end generateFileReport() - - - /** - * Prints the author of all errors and warnings, as given by "version control blame". - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - $errorsShown = ($totalErrors + $totalWarnings); - if ($errorsShown === 0) { - // Nothing to show. - return; - } - - $width = max($width, 70); - arsort($this->_authorCache); - - echo PHP_EOL.'PHP CODE SNIFFER '.$this->reportName.' BLAME SUMMARY'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - if ($showSources === true) { - echo 'AUTHOR SOURCE'.str_repeat(' ', ($width - 43)).'(Author %) (Overall %) COUNT'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - } else { - echo 'AUTHOR'.str_repeat(' ', ($width - 34)).'(Author %) (Overall %) COUNT'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL; - } - - foreach ($this->_authorCache as $author => $count) { - if ($this->_praiseCache[$author]['good'] === 0) { - $percent = 0; - } else { - $total = ($this->_praiseCache[$author]['bad'] + $this->_praiseCache[$author]['good']); - $percent = round(($this->_praiseCache[$author]['bad'] / $total * 100), 2); - } - - $overallPercent = '('.round((($count / $errorsShown) * 100), 2).')'; - $authorPercent = '('.$percent.')'; - $line = str_repeat(' ', (6 - strlen($count))).$count; - $line = str_repeat(' ', (12 - strlen($overallPercent))).$overallPercent.$line; - $line = str_repeat(' ', (11 - strlen($authorPercent))).$authorPercent.$line; - $line = $author.str_repeat(' ', ($width - strlen($author) - strlen($line))).$line; - - echo $line.PHP_EOL; - - if ($showSources === true && isset($this->_sourceCache[$author]) === true) { - $errors = $this->_sourceCache[$author]; - asort($errors); - $errors = array_reverse($errors); - - foreach ($errors as $source => $count) { - if ($source === 'count') { - continue; - } - - $line = str_repeat(' ', (5 - strlen($count))).$count; - echo ' '.$source.str_repeat(' ', ($width - 14 - strlen($source))).$line.PHP_EOL; - } - } - }//end foreach - - echo str_repeat('-', $width).PHP_EOL; - echo 'A TOTAL OF '.$errorsShown.' SNIFF VIOLATION(S) '; - echo 'WERE COMMITTED BY '.count($this->_authorCache).' AUTHOR(S)'.PHP_EOL; - echo str_repeat('-', $width).PHP_EOL.PHP_EOL; - - if ($toScreen === true - && PHP_CODESNIFFER_INTERACTIVE === false - && class_exists('PHP_Timer', false) === true - ) { - echo PHP_Timer::resourceUsage().PHP_EOL.PHP_EOL; - } - - }//end generate() - - - /** - * Extract the author from a blame line. - * - * @param string $line Line to parse. - * - * @return mixed string or false if impossible to recover. - */ - abstract protected function getAuthor($line); - - - /** - * Gets the blame output. - * - * @param string $filename File to blame. - * - * @return array - */ - abstract protected function getBlameContent($filename); - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Reports/Xml.php b/codesniffer/CodeSniffer/Reports/Xml.php deleted file mode 100644 index ce0671afe..000000000 --- a/codesniffer/CodeSniffer/Reports/Xml.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Xml report for PHP_CodeSniffer. - * - * PHP version 5 - * - * @category PHP - * @package PHP_CodeSniffer - * @author Gabriele Santini - * @author Greg Sherwood - * @copyright 2009 SQLI - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Reports_Xml implements PHP_CodeSniffer_Report -{ - - - /** - * Generate a partial report for a single processed file. - * - * Function should return TRUE if it printed or stored data about the file - * and FALSE if it ignored the file. Returning TRUE indicates that the file and - * its data should be counted in the grand totals. - * - * @param array $report Prepared report data. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * - * @return boolean - */ - public function generateFileReport( - $report, - $showSources=false, - $width=80 - ) { - $out = new XMLWriter; - $out->openMemory(); - $out->setIndent(true); - - if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Nothing to print. - return false; - } - - $out->startElement('file'); - $out->writeAttribute('name', $report['filename']); - $out->writeAttribute('errors', $report['errors']); - $out->writeAttribute('warnings', $report['warnings']); - - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { - foreach ($colErrors as $error) { - $error['type'] = strtolower($error['type']); - if (PHP_CODESNIFFER_ENCODING !== 'utf-8') { - $error['message'] = iconv(PHP_CODESNIFFER_ENCODING, 'utf-8', $error['message']); - } - - $out->startElement($error['type']); - $out->writeAttribute('line', $line); - $out->writeAttribute('column', $column); - $out->writeAttribute('source', $error['source']); - $out->writeAttribute('severity', $error['severity']); - $out->text($error['message']); - $out->endElement(); - } - } - }//end foreach - - $out->endElement(); - echo $out->flush(); - - return true; - - }//end generateFileReport() - - - /** - * Prints all violations for processed files, in a proprietary XML format. - * - * @param string $cachedData Any partial report data that was returned from - * generateFileReport during the run. - * @param int $totalFiles Total number of files processed during the run. - * @param int $totalErrors Total number of errors found during the run. - * @param int $totalWarnings Total number of warnings found during the run. - * @param boolean $showSources Show sources? - * @param int $width Maximum allowed line width. - * @param boolean $toScreen Is the report being printed to screen? - * - * @return void - */ - public function generate( - $cachedData, - $totalFiles, - $totalErrors, - $totalWarnings, - $showSources=false, - $width=80, - $toScreen=true - ) { - $phpcs = new PHP_CodeSniffer; - echo ''.PHP_EOL; - echo ''.PHP_EOL; - echo $cachedData; - echo ''.PHP_EOL; - - }//end generate() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Sniff.php b/codesniffer/CodeSniffer/Sniff.php deleted file mode 100644 index 426f020b2..000000000 --- a/codesniffer/CodeSniffer/Sniff.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Represents a PHP_CodeSniffer sniff for sniffing coding standards. - * - * A sniff registers what token types it wishes to listen for, then, when - * PHP_CodeSniffer encounters that token, the sniff is invoked and passed - * information about where the token was found in the stack, and the - * PHP_CodeSniffer file in which the token was found. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -interface PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * An example return value for a sniff that wants to listen for whitespace - * and any comments would be: - * - * - * return array( - * T_WHITESPACE, - * T_DOC_COMMENT, - * T_COMMENT, - * ); - * - * - * @return array(int) - * @see Tokens.php - */ - public function register(); - - - /** - * Called when one of the token types that this sniff is listening for - * is found. - * - * The stackPtr variable indicates where in the stack the token was found. - * A sniff can acquire information this token, along with all the other - * tokens within the stack by first acquiring the token stack: - * - * - * $tokens = $phpcsFile->getTokens(); - * echo 'Encountered a '.$tokens[$stackPtr]['type'].' token'; - * echo 'token information: '; - * print_r($tokens[$stackPtr]); - * - * - * If the sniff discovers an anomaly in the code, they can raise an error - * by calling addError() on the PHP_CodeSniffer_File object, specifying an error - * message and the position of the offending token: - * - * - * $phpcsFile->addError('Encountered an error', $stackPtr); - * - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the - * token was found. - * @param int $stackPtr The position in the PHP_CodeSniffer - * file's token stack where the token - * was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr); - - -}//end interface - -?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php b/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php deleted file mode 100644 index ef7ded90e..000000000 --- a/codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php +++ /dev/null @@ -1,961 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_IncorrectPatternException', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_IncorrectPatternException not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Processes pattern strings and checks that the code conforms to the pattern. - * - * This test essentially checks that code is correctly formatted with whitespace. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_Standards_AbstractPatternSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * If true, comments will be ignored if they are found in the code. - * - * @var boolean - */ - public $ignoreComments = false; - - /** - * The current file being checked. - * - * @var string - */ - protected $currFile = ''; - - /** - * The parsed patterns array. - * - * @var array - */ - private $_parsedPatterns = array(); - - /** - * Tokens that this sniff wishes to process outside of the patterns. - * - * @var array(int) - * @see registerSupplementary() - * @see processSupplementary() - */ - private $_supplementaryTokens = array(); - - /** - * Positions in the stack where errors have occurred. - * - * @var array() - */ - private $_errorPos = array(); - - - /** - * Constructs a PHP_CodeSniffer_Standards_AbstractPatternSniff. - * - * @param boolean $ignoreComments If true, comments will be ignored. - */ - public function __construct($ignoreComments=null) - { - // This is here for backwards compatibility. - if ($ignoreComments !== null) { - $this->ignoreComments = $ignoreComments; - } - - $this->_supplementaryTokens = $this->registerSupplementary(); - - }//end __construct() - - - /** - * Registers the tokens to listen to. - * - * Classes extending AbstractPatternTest should implement the - * getPatterns() method to register the patterns they wish to test. - * - * @return array(int) - * @see process() - */ - public final function register() - { - $listenTypes = array(); - $patterns = $this->getPatterns(); - - foreach ($patterns as $pattern) { - $parsedPattern = $this->_parse($pattern); - - // Find a token position in the pattern that we can use - // for a listener token. - $pos = $this->_getListenerTokenPos($parsedPattern); - $tokenType = $parsedPattern[$pos]['token']; - $listenTypes[] = $tokenType; - - $patternArray = array( - 'listen_pos' => $pos, - 'pattern' => $parsedPattern, - 'pattern_code' => $pattern, - ); - - if (isset($this->_parsedPatterns[$tokenType]) === false) { - $this->_parsedPatterns[$tokenType] = array(); - } - - $this->_parsedPatterns[$tokenType][] = $patternArray; - - }//end foreach - - return array_unique(array_merge($listenTypes, $this->_supplementaryTokens)); - - }//end register() - - - /** - * Returns the token types that the specified pattern is checking for. - * - * Returned array is in the format: - * - * array( - * T_WHITESPACE => 0, // 0 is the position where the T_WHITESPACE token - * // should occur in the pattern. - * ); - * - * - * @param array $pattern The parsed pattern to find the acquire the token - * types from. - * - * @return array(int => int) - */ - private function _getPatternTokenTypes($pattern) - { - $tokenTypes = array(); - foreach ($pattern as $pos => $patternInfo) { - if ($patternInfo['type'] === 'token') { - if (isset($tokenTypes[$patternInfo['token']]) === false) { - $tokenTypes[$patternInfo['token']] = $pos; - } - } - } - - return $tokenTypes; - - }//end _getPatternTokenTypes() - - - /** - * Returns the position in the pattern that this test should register as - * a listener for the pattern. - * - * @param array $pattern The pattern to acquire the listener for. - * - * @return int The postition in the pattern that this test should register - * as the listener. - * @throws PHP_CodeSniffer_Exception If we could not determine a token - * to listen for. - */ - private function _getListenerTokenPos($pattern) - { - $tokenTypes = $this->_getPatternTokenTypes($pattern); - $tokenCodes = array_keys($tokenTypes); - $token = PHP_CodeSniffer_Tokens::getHighestWeightedToken($tokenCodes); - - // If we could not get a token. - if ($token === false) { - $error = 'Could not determine a token to listen for'; - throw new PHP_CodeSniffer_Exception($error); - } - - return $tokenTypes[$token]; - - }//end _getListenerTokenPos() - - - /** - * Processes the test. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the - * token occured. - * @param int $stackPtr The postion in the tokens stack - * where the listening token type was - * found. - * - * @return void - * @see register() - */ - public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $file = $phpcsFile->getFilename(); - if ($this->currFile !== $file) { - // We have changed files, so clean up. - $this->_errorPos = array(); - $this->currFile = $file; - } - - $tokens = $phpcsFile->getTokens(); - - if (in_array($tokens[$stackPtr]['code'], $this->_supplementaryTokens) === true) { - $this->processSupplementary($phpcsFile, $stackPtr); - } - - $type = $tokens[$stackPtr]['code']; - - // If the type is not set, then it must have been a token registered - // with registerSupplementary(). - if (isset($this->_parsedPatterns[$type]) === false) { - return; - } - - $allErrors = array(); - - // Loop over each pattern that is listening to the current token type - // that we are processing. - foreach ($this->_parsedPatterns[$type] as $patternInfo) { - // If processPattern returns false, then the pattern that we are - // checking the code with must not be designed to check that code. - $errors = $this->processPattern($patternInfo, $phpcsFile, $stackPtr); - if ($errors === false) { - // The pattern didn't match. - continue; - } else if (empty($errors) === true) { - // The pattern matched, but there were no errors. - break; - } - - foreach ($errors as $stackPtr => $error) { - if (isset($this->_errorPos[$stackPtr]) === false) { - $this->_errorPos[$stackPtr] = true; - $allErrors[$stackPtr] = $error; - } - } - } - - foreach ($allErrors as $stackPtr => $error) { - $phpcsFile->addError($error, $stackPtr); - } - - }//end process() - - - /** - * Processes the pattern and verifies the code at $stackPtr. - * - * @param array $patternInfo Information about the pattern used - * for checking, which includes are - * parsed token representation of the - * pattern. - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the - * token occured. - * @param int $stackPtr The postion in the tokens stack where - * the listening token type was found. - * - * @return array(errors) - */ - protected function processPattern( - $patternInfo, - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $pattern = $patternInfo['pattern']; - $patternCode = $patternInfo['pattern_code']; - $errors = array(); - $found = ''; - - $ignoreTokens = array(T_WHITESPACE); - if ($this->ignoreComments === true) { - $ignoreTokens - = array_merge($ignoreTokens, PHP_CodeSniffer_Tokens::$commentTokens); - } - - $origStackPtr = $stackPtr; - $hasError = false; - - if ($patternInfo['listen_pos'] > 0) { - $stackPtr--; - - for ($i = ($patternInfo['listen_pos'] - 1); $i >= 0; $i--) { - if ($pattern[$i]['type'] === 'token') { - if ($pattern[$i]['token'] === T_WHITESPACE) { - if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { - $found = $tokens[$stackPtr]['content'].$found; - } - - // Only check the size of the whitespace if this is not - // the first token. We don't care about the size of - // leading whitespace, just that there is some. - if ($i !== 0) { - if ($tokens[$stackPtr]['content'] !== $pattern[$i]['value']) { - $hasError = true; - } - } - } else { - // Check to see if this important token is the same as the - // previous important token in the pattern. If it is not, - // then the pattern cannot be for this piece of code. - $prev = $phpcsFile->findPrevious( - $ignoreTokens, - $stackPtr, - null, - true - ); - - if ($prev === false - || $tokens[$prev]['code'] !== $pattern[$i]['token'] - ) { - return false; - } - - // If we skipped past some whitespace tokens, then add them - // to the found string. - $tokenContent = $phpcsFile->getTokensAsString( - ($prev + 1), - ($stackPtr - $prev - 1) - ); - - $found = $tokens[$prev]['content'].$tokenContent.$found; - - if (isset($pattern[($i - 1)]) === true - && $pattern[($i - 1)]['type'] === 'skip' - ) { - $stackPtr = $prev; - } else { - $stackPtr = ($prev - 1); - } - }//end if - } else if ($pattern[$i]['type'] === 'skip') { - // Skip to next piece of relevant code. - if ($pattern[$i]['to'] === 'parenthesis_closer') { - $to = 'parenthesis_opener'; - } else { - $to = 'scope_opener'; - } - - // Find the previous opener. - $next = $phpcsFile->findPrevious( - $ignoreTokens, - $stackPtr, - null, - true - ); - - if ($next === false || isset($tokens[$next][$to]) === false) { - // If there was not opener, then we must be - // using the wrong pattern. - return false; - } - - if ($to === 'parenthesis_opener') { - $found = '{'.$found; - } else { - $found = '('.$found; - } - - $found = '...'.$found; - - // Skip to the opening token. - $stackPtr = ($tokens[$next][$to] - 1); - } else if ($pattern[$i]['type'] === 'string') { - $found = 'abc'; - } else if ($pattern[$i]['type'] === 'newline') { - if ($this->ignoreComments === true - && in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true - ) { - $startComment = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$commentTokens, - ($stackPtr - 1), - null, - true - ); - - if ($tokens[$startComment]['line'] !== $tokens[($startComment + 1)]['line']) { - $startComment++; - } - - $tokenContent = $phpcsFile->getTokensAsString( - $startComment, - ($stackPtr - $startComment + 1) - ); - - $found = $tokenContent.$found; - $stackPtr = ($startComment - 1); - } - - if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { - if ($tokens[$stackPtr]['content'] !== $phpcsFile->eolChar) { - $found = $tokens[$stackPtr]['content'].$found; - - // This may just be an indent that comes after a newline - // so check the token before to make sure. If it is a newline, we - // can ignore the error here. - if (($tokens[($stackPtr - 1)]['content'] !== $phpcsFile->eolChar) - && ($this->ignoreComments === true && in_array($tokens[($stackPtr - 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === false) - ) { - $hasError = true; - } else { - $stackPtr--; - } - } else { - $found = 'EOL'.$found; - } - } else { - $found = $tokens[$stackPtr]['content'].$found; - $hasError = true; - } - - if ($hasError === false && $pattern[($i - 1)]['type'] !== 'newline') { - // Make sure they only have 1 newline. - $prev = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true); - if ($prev !== false && $tokens[$prev]['line'] !== $tokens[$stackPtr]['line']) { - $hasError = true; - } - } - }//end if - }//end for - }//end if - - $stackPtr = $origStackPtr; - $lastAddedStackPtr = null; - $patternLen = count($pattern); - - for ($i = $patternInfo['listen_pos']; $i < $patternLen; $i++) { - if ($pattern[$i]['type'] === 'token') { - if ($pattern[$i]['token'] === T_WHITESPACE) { - if ($this->ignoreComments === true) { - // If we are ignoring comments, check to see if this current - // token is a comment. If so skip it. - if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - continue; - } - - // If the next token is a comment, the we need to skip the - // current token as we should allow a space before a - // comment for readability. - if (in_array($tokens[($stackPtr + 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - continue; - } - } - - $tokenContent = ''; - if ($tokens[$stackPtr]['code'] === T_WHITESPACE) { - if (isset($pattern[($i + 1)]) === false) { - // This is the last token in the pattern, so just compare - // the next token of content. - $tokenContent = $tokens[$stackPtr]['content']; - } else { - // Get all the whitespace to the next token. - $next = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$emptyTokens, - $stackPtr, - null, - true - ); - - $tokenContent = $phpcsFile->getTokensAsString( - $stackPtr, - ($next - $stackPtr) - ); - - $lastAddedStackPtr = $stackPtr; - $stackPtr = $next; - } - - if ($stackPtr !== $lastAddedStackPtr) { - $found .= $tokenContent; - } - } else { - if ($stackPtr !== $lastAddedStackPtr) { - $found .= $tokens[$stackPtr]['content']; - $lastAddedStackPtr = $stackPtr; - } - }//end if - - if (isset($pattern[($i + 1)]) === true - && $pattern[($i + 1)]['type'] === 'skip' - ) { - // The next token is a skip token, so we just need to make - // sure the whitespace we found has *at least* the - // whitespace required. - if (strpos($tokenContent, $pattern[$i]['value']) !== 0) { - $hasError = true; - } - } else { - if ($tokenContent !== $pattern[$i]['value']) { - $hasError = true; - } - } - } else { - // Check to see if this important token is the same as the - // next important token in the pattern. If it is not, then - // the pattern cannot be for this piece of code. - $next = $phpcsFile->findNext( - $ignoreTokens, - $stackPtr, - null, - true - ); - - if ($next === false - || $tokens[$next]['code'] !== $pattern[$i]['token'] - ) { - // The next important token did not match the pattern. - return false; - } - - if ($lastAddedStackPtr !== null) { - if (($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET - || $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) - && isset($tokens[$next]['scope_condition']) === true - && $tokens[$next]['scope_condition'] > $lastAddedStackPtr - ) { - // This is a brace, but the owner of it is after the current - // token, which means it does not belong to any token in - // our pattern. This means the pattern is not for us. - return false; - } - - if (($tokens[$next]['code'] === T_OPEN_PARENTHESIS - || $tokens[$next]['code'] === T_CLOSE_PARENTHESIS) - && isset($tokens[$next]['parenthesis_owner']) === true - && $tokens[$next]['parenthesis_owner'] > $lastAddedStackPtr - ) { - // This is a bracket, but the owner of it is after the current - // token, which means it does not belong to any token in - // our pattern. This means the pattern is not for us. - return false; - } - }//end if - - // If we skipped past some whitespace tokens, then add them - // to the found string. - if (($next - $stackPtr) > 0) { - $hasComment = false; - for ($j = $stackPtr; $j < $next; $j++) { - $found .= $tokens[$j]['content']; - if (in_array($tokens[$j]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - $hasComment = true; - } - } - - // If we are not ignoring comments, this additional - // whitespace or comment is not allowed. If we are - // ignoring comments, there needs to be at least one - // comment for this to be allowed. - if ($this->ignoreComments === false - || ($this->ignoreComments === true - && $hasComment === false) - ) { - $hasError = true; - } - - // Even when ignoring comments, we are not allowed to include - // newlines without the pattern specifying them, so - // everything should be on the same line. - if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { - $hasError = true; - } - }//end if - - if ($next !== $lastAddedStackPtr) { - $found .= $tokens[$next]['content']; - $lastAddedStackPtr = $next; - } - - if (isset($pattern[($i + 1)]) === true - && $pattern[($i + 1)]['type'] === 'skip' - ) { - $stackPtr = $next; - } else { - $stackPtr = ($next + 1); - } - }//end if - } else if ($pattern[$i]['type'] === 'skip') { - if ($pattern[$i]['to'] === 'unknown') { - $next = $phpcsFile->findNext( - $pattern[($i + 1)]['token'], - $stackPtr - ); - - if ($next === false) { - // Couldn't find the next token, sowe we must - // be using the wrong pattern. - return false; - } - - $found .= '...'; - $stackPtr = $next; - } else { - // Find the previous opener. - $next = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$blockOpeners, - $stackPtr - ); - - if ($next === false - || isset($tokens[$next][$pattern[$i]['to']]) === false - ) { - // If there was not opener, then we must - // be using the wrong pattern. - return false; - } - - $found .= '...'; - if ($pattern[$i]['to'] === 'parenthesis_closer') { - $found .= ')'; - } else { - $found .= '}'; - } - - // Skip to the closing token. - $stackPtr = ($tokens[$next][$pattern[$i]['to']] + 1); - }//end if - } else if ($pattern[$i]['type'] === 'string') { - if ($tokens[$stackPtr]['code'] !== T_STRING) { - $hasError = true; - } - - if ($stackPtr !== $lastAddedStackPtr) { - $found .= 'abc'; - $lastAddedStackPtr = $stackPtr; - } - - $stackPtr++; - } else if ($pattern[$i]['type'] === 'newline') { - // Find the next token that contains a newline character. - $newline = 0; - for ($j = $stackPtr; $j < $phpcsFile->numTokens; $j++) { - if (strpos($tokens[$j]['content'], $phpcsFile->eolChar) !== false) { - $newline = $j; - break; - } - } - - if ($newline === 0) { - // We didn't find a newline character in the rest of the file. - $next = ($phpcsFile->numTokens - 1); - $hasError = true; - } else { - if ($this->ignoreComments === false) { - // The newline character cannot be part of a comment. - if (in_array($tokens[$newline]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - $hasError = true; - } - } - - if ($newline === $stackPtr) { - $next = ($stackPtr + 1); - } else { - // Check that there were no significant tokens that we - // skipped over to find our newline character. - $next = $phpcsFile->findNext( - $ignoreTokens, - $stackPtr, - null, - true - ); - - if ($next < $newline) { - // We skipped a non-ignored token. - $hasError = true; - } else { - $next = ($newline + 1); - } - } - }//end if - - if ($stackPtr !== $lastAddedStackPtr) { - $found .= $phpcsFile->getTokensAsString( - $stackPtr, - ($next - $stackPtr) - ); - - $diff = ($next - $stackPtr); - $lastAddedStackPtr = ($next - 1); - } - - $stackPtr = $next; - }//end if - }//end for - - if ($hasError === true) { - $error = $this->prepareError($found, $patternCode); - $errors[$origStackPtr] = $error; - } - - return $errors; - - }//end processPattern() - - - /** - * Prepares an error for the specified patternCode. - * - * @param string $found The actual found string in the code. - * @param string $patternCode The expected pattern code. - * - * @return string The error message. - */ - protected function prepareError($found, $patternCode) - { - $found = str_replace("\r\n", '\n', $found); - $found = str_replace("\n", '\n', $found); - $found = str_replace("\r", '\n', $found); - $found = str_replace('EOL', '\n', $found); - $expected = str_replace('EOL', '\n', $patternCode); - - $error = "Expected \"$expected\"; found \"$found\""; - - return $error; - - }//end prepareError() - - - /** - * Returns the patterns that should be checked. - * - * @return array(string) - */ - protected abstract function getPatterns(); - - - /** - * Registers any supplementary tokens that this test might wish to process. - * - * A sniff may wish to register supplementary tests when it wishes to group - * an arbitary validation that cannot be performed using a pattern, with - * other pattern tests. - * - * @return array(int) - * @see processSupplementary() - */ - protected function registerSupplementary() - { - return array(); - - }//end registerSupplementary() - - - /** - * Processes any tokens registered with registerSupplementary(). - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where to - * process the skip. - * @param int $stackPtr The position in the tokens stack to - * process. - * - * @return void - * @see registerSupplementary() - */ - protected function processSupplementary( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - - }//end processSupplementary() - - - /** - * Parses a pattern string into an array of pattern steps. - * - * @param string $pattern The pattern to parse. - * - * @return array The parsed pattern array. - * @see _createSkipPattern() - * @see _createTokenPattern() - */ - private function _parse($pattern) - { - $patterns = array(); - $length = strlen($pattern); - $lastToken = 0; - $firstToken = 0; - - for ($i = 0; $i < $length; $i++) { - - $specialPattern = false; - $isLastChar = ($i === ($length - 1)); - $oldFirstToken = $firstToken; - - if (substr($pattern, $i, 3) === '...') { - // It's a skip pattern. The skip pattern requires the - // content of the token in the "from" position and the token - // to skip to. - $specialPattern = $this->_createSkipPattern($pattern, ($i - 1)); - $lastToken = ($i - $firstToken); - $firstToken = ($i + 3); - $i = ($i + 2); - - if ($specialPattern['to'] !== 'unknown') { - $firstToken++; - } - } else if (substr($pattern, $i, 3) === 'abc') { - $specialPattern = array('type' => 'string'); - $lastToken = ($i - $firstToken); - $firstToken = ($i + 3); - $i = ($i + 2); - } else if (substr($pattern, $i, 3) === 'EOL') { - $specialPattern = array('type' => 'newline'); - $lastToken = ($i - $firstToken); - $firstToken = ($i + 3); - $i = ($i + 2); - } - - if ($specialPattern !== false || $isLastChar === true) { - // If we are at the end of the string, don't worry about a limit. - if ($isLastChar === true) { - // Get the string from the end of the last skip pattern, if any, - // to the end of the pattern string. - $str = substr($pattern, $oldFirstToken); - } else { - // Get the string from the end of the last special pattern, - // if any, to the start of this special pattern. - if ($lastToken === 0) { - // Note that if the last special token was zero characters ago, - // there will be nothing to process so we can skip this bit. - // This happens if you have something like: EOL... in your pattern. - $str = ''; - } else { - $str = substr($pattern, $oldFirstToken, $lastToken); - } - } - - if ($str !== '') { - $tokenPatterns = $this->_createTokenPattern($str); - foreach ($tokenPatterns as $tokenPattern) { - $patterns[] = $tokenPattern; - } - } - - // Make sure we don't skip the last token. - if ($isLastChar === false && $i === ($length - 1)) { - $i--; - } - }//end if - - // Add the skip pattern *after* we have processed - // all the tokens from the end of the last skip pattern - // to the start of this skip pattern. - if ($specialPattern !== false) { - $patterns[] = $specialPattern; - } - }//end for - - return $patterns; - - }//end _parse() - - - /** - * Creates a skip pattern. - * - * @param string $pattern The pattern being parsed. - * @param string $from The token content that the skip pattern starts from. - * - * @return array The pattern step. - * @see _createTokenPattern() - * @see _parse() - */ - private function _createSkipPattern($pattern, $from) - { - $skip = array('type' => 'skip'); - - $nestedParenthesis = 0; - $nestedBraces = 0; - for ($start = $from; $start >= 0; $start--) { - switch ($pattern[$start]) { - case '(': - if ($nestedParenthesis === 0) { - $skip['to'] = 'parenthesis_closer'; - } - - $nestedParenthesis--; - break; - case '{': - if ($nestedBraces === 0) { - $skip['to'] = 'scope_closer'; - } - - $nestedBraces--; - break; - case '}': - $nestedBraces++; - break; - case ')': - $nestedParenthesis++; - break; - } - - if (isset($skip['to']) === true) { - break; - } - } - - if (isset($skip['to']) === false) { - $skip['to'] = 'unknown'; - } - - return $skip; - - }//end _createSkipPattern() - - - /** - * Creates a token pattern. - * - * @param string $str The tokens string that the pattern should match. - * - * @return array The pattern step. - * @see _createSkipPattern() - * @see _parse() - */ - private function _createTokenPattern($str) - { - // Don't add a space after the closing php tag as it will add a new - // whitespace token. - $tokens = token_get_all(''); - - // Remove the 'token', - 'token' => $patternInfo['code'], - 'value' => $patternInfo['content'], - ); - } - - return $patterns; - - }//end _createTokenPattern() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php b/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php deleted file mode 100644 index b18f7583a..000000000 --- a/codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php +++ /dev/null @@ -1,201 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * An AbstractScopeTest allows for tests that extend from this class to - * listen for tokens within a particular scope. - * - * Below is a test that listens to methods that exist only within classes: - * - * class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff - * { - * public function __construct() - * { - * parent::__construct(array(T_CLASS), array(T_FUNCTION)); - * } - * - * protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $) - * { - * $className = $phpcsFile->getDeclarationName($currScope); - * echo 'encountered a method within class '.$className; - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_Standards_AbstractScopeSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The token types that this test wishes to listen to within the scope. - * - * @var array - */ - private $_tokens = array(); - - /** - * The type of scope opener tokens that this test wishes to listen to. - * - * @var string - */ - private $_scopeTokens = array(); - - /** - * True if this test should fire on tokens outside of the scope. - * - * @var boolean - */ - private $_listenOutside = false; - - - /** - * Constructs a new AbstractScopeTest. - * - * @param array $scopeTokens The type of scope the test wishes to listen to. - * @param array $tokens The tokens that the test wishes to listen to - * within the scope. - * @param boolean $listenOutside If true this test will also alert the - * extending class when a token is found outside - * the scope, by calling the - * processTokenOutsideScope method. - * - * @see PHP_CodeSniffer.getValidScopeTokeners() - * @throws PHP_CodeSniffer_Exception If the specified tokens array is empty. - */ - public function __construct( - array $scopeTokens, - array $tokens, - $listenOutside=false - ) { - if (empty($scopeTokens) === true) { - $error = 'The scope tokens list cannot be empty'; - throw new PHP_CodeSniffer_Exception($error); - } - - if (empty($tokens) === true) { - $error = 'The tokens list cannot be empty'; - throw new PHP_CodeSniffer_Exception($error); - } - - $invalidScopeTokens = array_intersect($scopeTokens, $tokens); - if (empty($invalidScopeTokens) === false) { - $invalid = implode(', ', $invalidScopeTokens); - $error = "Scope tokens [$invalid] cant be in the tokens array"; - throw new PHP_CodeSniffer_Exception($error); - } - - $this->_listenOutside = $listenOutside; - $this->_scopeTokens = $scopeTokens; - $this->_tokens = $tokens; - - }//end __construct() - - - /** - * The method that is called to register the tokens this test wishes to - * listen to. - * - * DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register - * for the desired tokens and scope. - * - * @return array(int) - * @see __constructor() - */ - public final function register() - { - return $this->_tokens; - - }//end register() - - - /** - * Processes the tokens that this test is listening for. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack where this - * token was found. - * - * @return void - * @see processTokenWithinScope() - */ - public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $foundScope = false; - foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) { - if (in_array($code, $this->_scopeTokens) === true) { - $this->processTokenWithinScope($phpcsFile, $stackPtr, $scope); - $foundScope = true; - } - } - - if ($this->_listenOutside === true && $foundScope === false) { - $this->processTokenOutsideScope($phpcsFile, $stackPtr); - } - - }//end process() - - - /** - * Processes a token that is found within the scope that this test is - * listening to. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack where this - * token was found. - * @param int $currScope The position in the tokens array that - * opened the scope that this test is - * listening for. - * - * @return void - */ - protected abstract function processTokenWithinScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $currScope - ); - - - /** - * Processes a token that is found within the scope that this test is - * listening to. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack where this - * token was found. - * - * @return void - */ - protected function processTokenOutsideScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - - }//end processTokenOutsideScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php b/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php deleted file mode 100644 index 75084534a..000000000 --- a/codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php +++ /dev/null @@ -1,245 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * A class to find T_VARIABLE tokens. - * - * This class can distinguish between normal T_VARIABLE tokens, and those tokens - * that represent class members. If a class member is encountered, then then - * processMemberVar method is called so the extending class can process it. If - * the token is found to be a normal T_VARIABLE token, then processVariable is - * called. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -abstract class PHP_CodeSniffer_Standards_AbstractVariableSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - /** - * The end token of the current function that we are in. - * - * @var int - */ - private $_endFunction = -1; - - /** - * true if a function is currently open. - * - * @var boolean - */ - private $_functionOpen = false; - - /** - * The current PHP_CodeSniffer file that we are processing. - * - * @var PHP_CodeSniffer_File - */ - protected $currentFile = null; - - - /** - * Constructs an AbstractVariableTest. - */ - public function __construct() - { - $scopes = array( - T_CLASS, - T_INTERFACE, - ); - - $listen = array( - T_FUNCTION, - T_VARIABLE, - T_DOUBLE_QUOTED_STRING, - T_HEREDOC, - ); - - parent::__construct($scopes, $listen, true); - - }//end __construct() - - - /** - * Processes the token in the specified PHP_CodeSniffer_File. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * @param array $currScope The current scope opener token. - * - * @return void - */ - protected final function processTokenWithinScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $currScope - ) { - if ($this->currentFile !== $phpcsFile) { - $this->currentFile = $phpcsFile; - $this->_functionOpen = false; - $this->_endFunction = -1; - } - - $tokens = $phpcsFile->getTokens(); - - if ($stackPtr > $this->_endFunction) { - $this->_functionOpen = false; - } - - if ($tokens[$stackPtr]['code'] === T_FUNCTION - && $this->_functionOpen === false - ) { - $this->_functionOpen = true; - - $methodProps = $phpcsFile->getMethodProperties($stackPtr); - - // If the function is abstract, or is in an interface, - // then set the end of the function to it's closing semicolon. - if ($methodProps['is_abstract'] === true - || $tokens[$currScope]['code'] === T_INTERFACE - ) { - $this->_endFunction - = $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr); - } else { - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - $error = 'Possible parse error: non-abstract method defined as abstract'; - $phpcsFile->addWarning($error, $stackPtr); - return; - } - - $this->_endFunction = $tokens[$stackPtr]['scope_closer']; - } - } - - if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING - || $tokens[$stackPtr]['code'] === T_HEREDOC - ) { - // Check to see if this string has a variable in it. - $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); - } - - return; - } - - if ($this->_functionOpen === true) { - if ($tokens[$stackPtr]['code'] === T_VARIABLE) { - $this->processVariable($phpcsFile, $stackPtr); - } - } else { - // What if we assign a member variable to another? - // ie. private $_count = $this->_otherCount + 1;. - $this->processMemberVar($phpcsFile, $stackPtr); - } - - }//end processTokenWithinScope() - - - /** - * Processes the token outside the scope in the file. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected final function processTokenOutsideScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - // These variables are not member vars. - if ($tokens[$stackPtr]['code'] === T_VARIABLE) { - $this->processVariable($phpcsFile, $stackPtr); - } else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING - || $tokens[$stackPtr]['code'] === T_HEREDOC - ) { - // Check to see if this string has a variable in it. - $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); - } - } - - }//end processTokenOutsideScope() - - - /** - * Called to process class member vars. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - abstract protected function processMemberVar( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ); - - - /** - * Called to process normal member vars. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - abstract protected function processVariable( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ); - - - /** - * Called to process variables found in double quoted strings or heredocs. - * - * Note that there may be more than one variable in the string, which will - * result only in one call for the string or one call per line for heredocs. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the double quoted - * string was found. - * - * @return void - */ - abstract protected function processVariableInString( - PHP_CodeSniffer_File - $phpcsFile, - $stackPtr - ); - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml deleted file mode 100644 index 4b0ec96d4..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - Foo -{ -} - ]]> - - - Foo -{ -} - -class Foo -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml deleted file mode 100644 index 2c6835d47..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/EmptyStatementStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - // do nothing -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml deleted file mode 100644 index 06f0b7a5b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopShouldBeWhileLoopStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - $i = 0; $i < 10; $i++) { - echo "{$i}\n"; -} - ]]> - - - ;$test;) { - $test = doSomething(); -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml deleted file mode 100644 index f40d94bb1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/ForLoopWithTestFunctionCallStandard.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - $end = count($foo); -for ($i = 0; $i < $end; $i++) { - echo $foo[$i]."\n"; -} - ]]> - - - count($foo); $i++) { - echo $foo[$i]."\n"; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml deleted file mode 100644 index 50f078288..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/JumbledIncrementerStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - $i++) { - for ($j = 0; $j < 10; $j++) { - } -} - ]]> - - - $i++) { - for ($j = 0; $j < 10; $i++) { - } -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml deleted file mode 100644 index b2eaabe79..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnconditionalIfStatementStandard.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - $test) { - $var = 1; -} - ]]> - - - true) { - $var = 1; -} - ]]> - - - - - $test) { - $var = 1; -} - ]]> - - - false) { - $var = 1; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml deleted file mode 100644 index 893674077..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnnecessaryFinalModifierStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - final function bar() - { - } -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml deleted file mode 100644 index 181dff4ee..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UnusedFunctionParameterStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - $a + $b + $c; -} - ]]> - - - $a + $b; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml deleted file mode 100644 index ba8bd7e42..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - $this->doSomethingElse(); - } -} - ]]> - - - parent::bar(); - } -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml deleted file mode 100644 index 451e5fb61..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/FixmeStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - Handle strange case -if ($test) { - $var = 1; -} - ]]> - - - FIXME: This needs to be fixed! -if ($test) { - $var = 1; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml deleted file mode 100644 index c9c4fc061..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Commenting/TodoStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - Handle strange case -if ($test) { - $var = 1; -} - ]]> - - - TODO: This needs to be fixed! -if ($test) { - $var = 1; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml deleted file mode 100644 index 06ae14b76..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/ControlStructures/InlineControlStructureStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - { - $var = 1; -} - ]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml deleted file mode 100644 index b57a97068..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/CSSLintStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - %; } - ]]> - - - %; } - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml deleted file mode 100644 index 9df9aec48..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/ClosureLinterStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - ]; - ]]> - - - ,]; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml deleted file mode 100644 index 7525e9e6b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Debug/JSHintStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - var foo = 5; - ]]> - - - foo = 5; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml deleted file mode 100644 index 88591f925..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/ByteOrderMarkStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml deleted file mode 100644 index aa757edc6..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNewlineStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml deleted file mode 100644 index 227d5621a..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/EndFileNoNewlineStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml deleted file mode 100644 index 3fbf5024d..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/InlineHTMLStandard.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - some string here - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml deleted file mode 100644 index db7d4cc32..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineEndingsStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml deleted file mode 100644 index 31342e3c9..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LineLengthStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml deleted file mode 100644 index a1be34cb0..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/LowercasedFilenameStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml deleted file mode 100644 index 7b5857633..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneClassPerFileStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - class Foo -{ -} - ]]> - - - class Foo -{ -} - -class Bar -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml deleted file mode 100644 index de975319a..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Files/OneInterfacePerFileStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - interface Foo -{ -} - ]]> - - - interface Foo -{ -} - -interface Bar -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml deleted file mode 100644 index f0d4490c3..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/DisallowMultipleStatementsStandard.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml deleted file mode 100644 index 9369eebc1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/MultipleStatementAlignmentStandard.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - = (1 + 2); -$veryLongVarName = 'string'; -$var = foo($bar, $baz, $quux); - ]]> - - - = (1 + 2); -$veryLongVarName = 'string'; -$var = foo($bar, $baz, $quux); - ]]> - - - - - - - - += 1; -$veryLongVarName = 1; - ]]> - - - += 1; -$veryLongVarName = 1; - ]]> - - - - - = 1; -$veryLongVarName -= 1; - ]]> - - - = 1; -$veryLongVarName -= 1; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml deleted file mode 100644 index 042e4f803..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - 1; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml deleted file mode 100644 index 75eba77cb..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Formatting/SpaceAfterCastStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - 1; - ]]> - - - 1; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml deleted file mode 100644 index 738998d43..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/CallTimePassByReferenceStandard.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - &$bar) -{ - $bar++; -} - -$baz = 1; -foo($baz); - ]]> - - - &$baz); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml deleted file mode 100644 index 9809844d8..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/FunctionCallArgumentSpacingStandard.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - $baz) -{ -} - ]]> - - - $baz) -{ -} - ]]> - - - - - = true) -{ -} - ]]> - - - =true) -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml deleted file mode 100644 index 414dc289e..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - { - ... -} - ]]> - - - { - ... -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml deleted file mode 100644 index 84c2bdd86..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - { - ... -} - ]]> - - - { - ... -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml deleted file mode 100644 index a928e7db1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/CyclomaticComplexityStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml deleted file mode 100644 index f66cd92c9..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Metrics/NestingLevelStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml deleted file mode 100644 index f5345b712..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/CamelCapsFunctionNameStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - doSomething() -{ -} - ]]> - - - do_something() -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml deleted file mode 100644 index 9dfc175ff..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/ConstructorNameStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - __construct() - { - } -} - ]]> - - - Foo() - { - } -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml deleted file mode 100644 index 6ef61b93c..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - FOO_CONSTANT', 'foo'); - -class FooClass -{ - const FOO_CONSTANT = 'foo'; -} - ]]> - - - Foo_Constant', 'foo'); - -class FooClass -{ - const foo_constant = 'foo'; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml deleted file mode 100644 index df5a0eba4..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - Beginning content - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml deleted file mode 100644 index 09afb2d75..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ClosingPHPTagStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -echo 'Foo'; -?> - ]]> - - - -echo 'Foo'; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml deleted file mode 100644 index 33b803a75..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DeprecatedFunctionsStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - explode('a', $bar); - ]]> - - - split('a', $bar); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml deleted file mode 100644 index 8086ea271..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/DisallowShortOpenTagStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - to delimit PHP code, not the shorthand. This is the most portable way to include PHP code on differing operating systems and setups. - ]]> - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml deleted file mode 100644 index 220e9a9b6..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/ForbiddenFunctionsStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - count($bar); - ]]> - - - sizeof($bar); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml deleted file mode 100644 index ab607c54c..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - true, false and null constants must always be lowercase. - ]]> - - - - false || $var === null) { - $var = true; -} - ]]> - - - FALSE || $var === NULL) { - $var = TRUE; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml deleted file mode 100644 index 965742d94..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/LowerCaseKeywordStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - array(); - ]]> - - - Array(); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml deleted file mode 100644 index 6646f6747..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/NoSilencedErrorsStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - isset($foo) && $foo) { - echo "Hello\n"; -} - ]]> - - - @$foo) { - echo "Hello\n"; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml deleted file mode 100644 index e74005ad1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - PHP_SAPI === 'cli') { - echo "Hello, CLI user."; -} - ]]> - - - php_sapi_name() === 'cli') { - echo "Hello, CLI user."; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml deleted file mode 100644 index 26487347b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - true, false and null constants must always be uppercase. - ]]> - - - - FALSE || $var === NULL) { - $var = TRUE; -} - ]]> - - - false || $var === null) { - $var = true; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml deleted file mode 100644 index a4c9887b2..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/Strings/UnnecessaryStringConcatStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml deleted file mode 100644 index f4f3e19cb..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml deleted file mode 100644 index 2e399b34b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowSpaceIndentStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml deleted file mode 100644 index 7013ffd90..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/DisallowTabIndentStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml b/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml deleted file mode 100644 index bdd36d498..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Docs/WhiteSpace/ScopeIndentStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - $var = 1; -} - ]]> - - - $var = 1; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php deleted file mode 100644 index 68d3f31f9..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Reports errors if the same class or interface name is used in multiple files. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Classes_DuplicateClassNameSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * List of classes that have been found during checking. - * - * @var array - */ - public $foundClasses = array(); - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $namespace = ''; - $findTokens = array( - T_CLASS, - T_INTERFACE, - T_NAMESPACE, - T_CLOSE_TAG, - ); - - $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); - while ($stackPtr !== false) { - if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { - // We can stop here. The sniff will continue from the next open - // tag when PHPCS reaches that token, if there is one. - return; - } - - // Keep track of what namespace we are in. - if ($tokens[$stackPtr]['code'] === T_NAMESPACE) { - $nsEnd = $phpcsFile->findNext( - array( - T_NS_SEPARATOR, - T_STRING, - T_WHITESPACE, - ), - ($stackPtr + 1), - null, - true - ); - - $namespace = trim($phpcsFile->getTokensAsString(($stackPtr + 1), ($nsEnd - $stackPtr - 1))); - $stackPtr = $nsEnd; - } else { - $nameToken = $phpcsFile->findNext(T_STRING, $stackPtr); - $name = $tokens[$nameToken]['content']; - if ($namespace !== '') { - $name = $namespace.'\\'.$name; - } - - $compareName = strtolower($name); - if (isset($this->foundClasses[$compareName]) === true) { - $type = strtolower($tokens[$stackPtr]['content']); - $file = $this->foundClasses[$compareName]['file']; - $line = $this->foundClasses[$compareName]['line']; - $error = 'Duplicate %s name "%s" found; first defined in %s on line %s'; - $data = array( - $type, - $name, - $file, - $line, - ); - $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); - } else { - $this->foundClasses[$compareName] = array( - 'file' => $phpcsFile->getFilename(), - 'line' => $tokens[$stackPtr]['line'], - ); - } - } - - $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); - }//end while - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php deleted file mode 100644 index 340ec8b2d..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php +++ /dev/null @@ -1,128 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * This sniff class detected empty statement. - * - * This sniff implements the common algorithm for empty statement body detection. - * A body is considered as empty if it is completely empty or it only contains - * whitespace characters and|or comments. - * - * - * stmt { - * // foo - * } - * stmt (conditions) { - * // foo - * } - * - * - * Statements covered by this sniff are catch, do, else, - * elsif, for, foreach, if, switch, try - * and while. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_EmptyStatementSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * List of block tokens that this sniff covers. - * - * The key of this hash identifies the required token while the boolean - * value says mark an error or mark a warning. - * - * @var array - */ - protected $checkedTokens = array( - T_CATCH => false, - T_DO => true, - T_ELSE => true, - T_ELSEIF => true, - T_FOR => true, - T_FOREACH => true, - T_IF => true, - T_SWITCH => true, - T_TRY => true, - T_WHILE => true, - ); - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array_keys($this->checkedTokens); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip for-statements without body. - if (isset($token['scope_opener']) === false) { - return; - } - - $next = ++$token['scope_opener']; - $end = --$token['scope_closer']; - - $emptyBody = true; - for (; $next <= $end; ++$next) { - if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $emptyBody = false; - break; - } - } - - if ($emptyBody === true) { - // Get token identifier. - $name = $phpcsFile->getTokensAsString($stackPtr, 1); - $error = 'Empty %s statement detected'; - $data = array(strtoupper($name)); - if ($this->checkedTokens[$token['code']] === true) { - $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); - } else { - $phpcsFile->addWarning($error, $stackPtr, 'NotAllowedWarning', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php deleted file mode 100644 index 6ac4cb3ef..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects for-loops that can be simplified to a while-loop. - * - * This rule is based on the PMD rule catalog. Detects for-loops that can be - * simplified as a while-loop. - * - * - * class Foo - * { - * public function bar($x) - * { - * for (;true;) true; // No Init or Update part, may as well be: while (true) - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_FOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip invalid statement. - if (isset($token['parenthesis_opener']) === false) { - return; - } - - $next = ++$token['parenthesis_opener']; - $end = --$token['parenthesis_closer']; - - $parts = array( - 0, - 0, - 0, - ); - $index = 0; - - for (; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - if ($code === T_SEMICOLON) { - ++$index; - } else if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - ++$parts[$index]; - } - } - - if ($parts[0] === 0 && $parts[2] === 0 && $parts[1] > 0) { - $error = 'This FOR loop can be simplified to a WHILE loop'; - $phpcsFile->addWarning($error, $stackPtr, 'CanSimplify'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php deleted file mode 100644 index 6ecfc63cb..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects for-loops that use a function call in the test expression. - * - * This rule is based on the PMD rule catalog. Detects for-loops that use a - * function call in the test expression. - * - * - * class Foo - * { - * public function bar($x) - * { - * $a = array(1, 2, 3, 4); - * for ($i = 0; $i < count($a); $i++) { - * $a[$i] *= $i; - * } - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_FOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip invalid statement. - if (isset($token['parenthesis_opener']) === false) { - return; - } - - $next = ++$token['parenthesis_opener']; - $end = --$token['parenthesis_closer']; - - $position = 0; - - for (; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - if ($code === T_SEMICOLON) { - ++$position; - } - - if ($position < 1) { - continue; - } else if ($position > 1) { - break; - } else if ($code !== T_VARIABLE && $code !== T_STRING) { - continue; - } - - // Find next non empty token, if it is a open curly brace we have a - // function call. - $index = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - - if ($tokens[$index]['code'] === T_OPEN_PARENTHESIS) { - $error = 'Avoid function calls in a FOR loop test part'; - $phpcsFile->addWarning($error, $stackPtr, 'NotAllowed'); - break; - } - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php deleted file mode 100644 index 6fadaefd7..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php +++ /dev/null @@ -1,148 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects incrementer jumbling in for loops. - * - * This rule is based on the PMD rule catalog. The jumbling incrementer sniff - * detects the usage of one and the same incrementer into an outer and an inner - * loop. Even it is intended this is confusing code. - * - * - * class Foo - * { - * public function bar($x) - * { - * for ($i = 0; $i < 10; $i++) - * { - * for ($k = 0; $k < 20; $i++) - * { - * echo 'Hello'; - * } - * } - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_FOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip for-loop without body. - if (isset($token['scope_opener']) === false) { - return; - } - - // Find incrementors for outer loop. - $outer = $this->findIncrementers($tokens, $token); - - // Skip if empty. - if (count($outer) === 0) { - return; - } - - // Find nested for loops. - $start = ++$token['scope_opener']; - $end = --$token['scope_closer']; - - for (; $start <= $end; ++$start) { - if ($tokens[$start]['code'] !== T_FOR) { - continue; - } - - $inner = $this->findIncrementers($tokens, $tokens[$start]); - $diff = array_intersect($outer, $inner); - - if (count($diff) !== 0) { - $error = 'Loop incrementor (%s) jumbling with inner loop'; - $data = array(join(', ', $diff)); - $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); - } - } - - }//end process() - - - /** - * Get all used variables in the incrementer part of a for statement. - * - * @param array(integer=>array) $tokens Array with all code sniffer tokens. - * @param array(string=>mixed) $token Current for loop token - * - * @return array(string) List of all found incrementer variables. - */ - protected function findIncrementers(array $tokens, array $token) - { - // Skip invalid statement. - if (isset($token['parenthesis_opener']) === false) { - return array(); - } - - $start = ++$token['parenthesis_opener']; - $end = --$token['parenthesis_closer']; - - $incrementers = array(); - $semicolons = 0; - for ($next = $start; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - if ($code === T_SEMICOLON) { - ++$semicolons; - } else if ($semicolons === 2 && $code === T_VARIABLE) { - $incrementers[] = $tokens[$next]['content']; - } - } - - return $incrementers; - - }//end findIncrementers() - - -}//end class - -?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php deleted file mode 100644 index 947a7f4fc..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php +++ /dev/null @@ -1,106 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects unconditional if- and elseif-statements. - * - * This rule is based on the PMD rule catalog. The Unconditional If Statement - * sniff detects statement conditions that are only set to one of the constant - * values true or false - * - * - * class Foo - * { - * public function close() - * { - * if (true) - * { - * // ... - * } - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array( - T_IF, - T_ELSEIF, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip for-loop without body. - if (isset($token['parenthesis_opener']) === false) { - return; - } - - $next = ++$token['parenthesis_opener']; - $end = --$token['parenthesis_closer']; - - $goodCondition = false; - for (; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - - if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } else if ($code !== T_TRUE && $code !== T_FALSE) { - $goodCondition = true; - } - } - - if ($goodCondition === false) { - $error = 'Avoid IF statements that are always true or false'; - $phpcsFile->addWarning($error, $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php deleted file mode 100644 index 32e5c86ef..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects unnecessary final modifiers inside of final classes. - * - * This rule is based on the PMD rule catalog. The Unnecessary Final Modifier - * sniff detects the use of the final modifier inside of a final class which - * is unnecessary. - * - * - * final class Foo - * { - * public final function bar() - * { - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_CLASS); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip for-statements without body. - if (isset($token['scope_opener']) === false) { - return; - } - - // Fetch previous token. - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - - // Skip for non final class. - if ($prev === false || $tokens[$prev]['code'] !== T_FINAL) { - return; - } - - $next = ++$token['scope_opener']; - $end = --$token['scope_closer']; - - for (; $next <= $end; ++$next) { - if ($tokens[$next]['code'] === T_FINAL) { - $error = 'Unnecessary FINAL modifier in FINAL class'; - $phpcsFile->addWarning($error, $next, 'Found'); - } - } - - }//end process() - - -}//end class - -?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php deleted file mode 100644 index 15b9a41a2..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php +++ /dev/null @@ -1,187 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks the for unused function parameters. - * - * This sniff checks that all function parameters are used in the function body. - * One exception is made for empty function bodies or function bodies that only - * contain comments. This could be useful for the classes that implement an - * interface that defines multiple methods but the implementation only needs some - * of them. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @author Greg Sherwood - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip broken function declarations. - if (isset($token['scope_opener']) === false || isset($token['parenthesis_opener']) === false) { - return; - } - - $params = array(); - foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { - $params[$param['name']] = $stackPtr; - } - - $next = ++$token['scope_opener']; - $end = --$token['scope_closer']; - - $foundContent = false; - - for (; $next <= $end; ++$next) { - $token = $tokens[$next]; - $code = $token['code']; - - // Ignorable tokens. - if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } - - if ($foundContent === false) { - // A throw statement as the first content indicates an interface method. - if ($code === T_THROW) { - return; - } - - // A return statement as the first content indicates an interface method. - if ($code === T_RETURN) { - $tmp = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - if ($tmp === false) { - return; - } - - // There is a return. - if ($tokens[$tmp]['code'] === T_SEMICOLON) { - return; - } - - $tmp = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($tmp + 1), null, true); - if ($tmp !== false && $tokens[$tmp]['code'] === T_SEMICOLON) { - // There is a return . - return; - } - }//end if - }//end if - - $foundContent = true; - - if ($code === T_VARIABLE && isset($params[$token['content']]) === true) { - unset($params[$token['content']]); - } else if ($code === T_DOLLAR) { - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); - if ($tokens[$nextToken]['code'] === T_OPEN_CURLY_BRACKET) { - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true); - if ($tokens[$nextToken]['code'] === T_STRING) { - $varContent = '$'.$tokens[$nextToken]['content']; - if (isset($params[$varContent]) === true) { - unset($params[$varContent]); - } - } - } - } else if ($code === T_DOUBLE_QUOTED_STRING - || $code === T_START_HEREDOC - || $code === T_START_NOWDOC - ) { - // Tokenize strings that can contain variables. - // Make sure the string is re-joined if it occurs over multiple lines. - $validTokens = array( - T_HEREDOC, - T_NOWDOC, - T_END_HEREDOC, - T_END_NOWDOC, - T_DOUBLE_QUOTED_STRING, - ); - $validTokens = array_merge($validTokens, PHP_CodeSniffer_Tokens::$emptyTokens); - - $content = $token['content']; - for ($i = ($next + 1); $i <= $end; $i++) { - if (in_array($tokens[$i]['code'], $validTokens) === true) { - $content .= $tokens[$i]['content']; - $next++; - } else { - break; - } - } - - $stringTokens = token_get_all(sprintf('', $content)); - foreach ($stringTokens as $stringPtr => $stringToken) { - if (is_array($stringToken) === false) { - continue; - } - - $varContent = ''; - if ($stringToken[0] === T_DOLLAR_OPEN_CURLY_BRACES) { - $varContent = '$'.$stringTokens[($stringPtr + 1)][1]; - } else if ($stringToken[0] === T_VARIABLE) { - $varContent = $stringToken[1]; - } - - if ($varContent !== '' && isset($params[$varContent]) === true) { - unset($params[$varContent]); - } - } - }//end if - }//end for - - if ($foundContent === true && count($params) > 0) { - foreach ($params as $paramName => $position) { - $error = 'The method parameter %s is never used'; - $data = array($paramName); - $phpcsFile->addWarning($error, $position, 'Found', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php deleted file mode 100644 index 59542f8b3..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Detects unnecessary overridden methods that simply call their parent. - * - * This rule is based on the PMD rule catalog. The Useless Overriding Method - * sniff detects the use of methods that only call their parent classes's method - * with the same name and arguments. These methods are not required. - * - * - * class FooBar { - * public function __construct($a, $b) { - * parent::__construct($a, $b); - * } - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Manuel Pichler - * @copyright 2007-2008 Manuel Pichler. All rights reserved. - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return array(integer) - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Skip function without body. - if (isset($token['scope_opener']) === false) { - return; - } - - // Get function name. - $methodName = $phpcsFile->getDeclarationName($stackPtr); - - // Get all parameters from method signature. - $signature = array(); - foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { - $signature[] = $param['name']; - } - - $next = ++$token['scope_opener']; - $end = --$token['scope_closer']; - - for (; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - - if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } else if ($code === T_RETURN) { - continue; - } - - break; - } - - // Any token except 'parent' indicates correct code. - if ($tokens[$next]['code'] !== T_PARENT) { - return; - } - - // Find next non empty token index, should be double colon. - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - - // Skip for invalid code. - if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { - return; - } - - // Find next non empty token index, should be the function name. - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - - // Skip for invalid code or other method. - if ($next === false || $tokens[$next]['content'] !== $methodName) { - return; - } - - // Find next non empty token index, should be the open parenthesis. - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - - // Skip for invalid code. - if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { - return; - } - - $validParameterTypes = array( - T_VARIABLE, - T_LNUMBER, - T_CONSTANT_ENCAPSED_STRING, - ); - - $parameters = array(''); - $parenthesisCount = 1; - $count = count($tokens); - for (++$next; $next < $count; ++$next) { - $code = $tokens[$next]['code']; - - if ($code === T_OPEN_PARENTHESIS) { - ++$parenthesisCount; - } else if ($code === T_CLOSE_PARENTHESIS) { - --$parenthesisCount; - } else if ($parenthesisCount === 1 && $code === T_COMMA) { - $parameters[] = ''; - } else if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $parameters[(count($parameters) - 1)] .= $tokens[$next]['content']; - } - - if ($parenthesisCount === 0) { - break; - } - }//end for - - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); - if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { - return; - } - - // Check rest of the scope. - for (++$next; $next <= $end; ++$next) { - $code = $tokens[$next]['code']; - // Skip for any other content. - if (in_array($code, PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - return; - } - } - - $parameters = array_map('trim', $parameters); - $parameters = array_filter($parameters); - - if (count($parameters) === count($signature) && $parameters === $signature) { - $phpcsFile->addWarning('Useless method overriding detected', $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php deleted file mode 100644 index e822ad34b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/VariableAnalysisSniff.php +++ /dev/null @@ -1,1498 +0,0 @@ - - * @copyright 2011-2012 Sam Graham - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Holds details of a scope. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sam Graham - * @copyright 2011-2012 Sam Graham - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class ScopeInfo { - public $owner; - public $opener; - public $closer; - public $variables = array(); - - function __construct($currScope) { - $this->owner = $currScope; - // TODO: extract opener/closer - } -} - -/** - * Holds details of a variable within a scope. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sam Graham - * @copyright 2011 Sam Graham - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class VariableInfo { - public $name; - /** - * What scope the variable has: local, param, static, global, bound - */ - public $scopeType; - public $typeHint; - public $passByReference = false; - public $firstDeclared; - public $firstInitialized; - public $firstRead; - public $ignoreUnused = false; - - static $scopeTypeDescriptions = array( - 'local' => 'variable', - 'param' => 'function parameter', - 'static' => 'static variable', - 'global' => 'global variable', - 'bound' => 'bound variable', - ); - - function __construct($varName) { - $this->name = $varName; - } -} - -/** - * Checks the for undefined function variables. - * - * This sniff checks that all function variables - * are defined in the function body. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sam Graham - * @copyright 2011 Sam Graham - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_CodeAnalysis_VariableAnalysisSniff implements PHP_CodeSniffer_Sniff -{ - /** - * The current phpcsFile being checked. - * - * @var phpcsFile - */ - protected $currentFile = null; - - /** - * A list of scopes encountered so far and the variables within them. - */ - private $_scopes = array(); - - /** - * A regexp for matching variable names in double-quoted strings. - */ - private $_double_quoted_variable_regexp = '|(? array(5), - 'addFunction' => array(3), - 'addTask' => array(3), - 'addTaskBackground' => array(3), - 'addTaskHigh' => array(3), - 'addTaskHighBackground' => array(3), - 'addTaskLow' => array(3), - 'addTaskLowBackground' => array(3), - 'addTaskStatus' => array(2), - 'apc_dec' => array(3), - 'apc_fetch' => array(2), - 'apc_inc' => array(3), - 'areConfusable' => array(3), - 'array_multisort' => array(1), - 'array_pop' => array(1), - 'array_push' => array(1), - 'array_replace' => array(1), - 'array_replace_recursive' => array(1, 2, 3, '...'), - 'array_shift' => array(1), - 'array_splice' => array(1), - 'array_unshift' => array(1), - 'array_walk' => array(1), - 'array_walk_recursive' => array(1), - 'arsort' => array(1), - 'asort' => array(1), - 'asort' => array(1), - 'bindColumn' => array(2), - 'bindParam' => array(2), - 'bind_param' => array(2, 3, '...'), - 'bind_result' => array(1, 2, '...'), - 'call_user_method' => array(2), - 'call_user_method_array' => array(2), - 'curl_multi_exec' => array(2), - 'curl_multi_info_read' => array(2), - 'current' => array(1), - 'dbplus_curr' => array(2), - 'dbplus_first' => array(2), - 'dbplus_info' => array(3), - 'dbplus_last' => array(2), - 'dbplus_next' => array(2), - 'dbplus_prev' => array(2), - 'dbplus_tremove' => array(3), - 'dns_get_record' => array(3, 4), - 'domxml_open_file' => array(3), - 'domxml_open_mem' => array(3), - 'each' => array(1), - 'enchant_dict_quick_check' => array(3), - 'end' => array(1), - 'ereg' => array(3), - 'eregi' => array(3), - 'exec' => array(2, 3), - 'exif_thumbnail' => array(1, 2, 3), - 'expect_expectl' => array(3), - 'extract' => array(1), - 'filter' => array(3), - 'flock' => array(2,3), - 'fscanf' => array(2, 3, '...'), - 'fsockopen' => array(3, 4), - 'ftp_alloc' => array(3), - 'get' => array(2, 3), - 'getByKey' => array(4), - 'getMulti' => array(2), - 'getMultiByKey' => array(3), - 'getimagesize' => array(2), - 'getmxrr' => array(2, 3), - 'gnupg_decryptverify' => array(3), - 'gnupg_verify' => array(4), - 'grapheme_extract' => array(5), - 'headers_sent' => array(1, 2), - 'http_build_url' => array(4), - 'http_get' => array(3), - 'http_head' => array(3), - 'http_negotiate_charset' => array(2), - 'http_negotiate_content_type' => array(2), - 'http_negotiate_language' => array(2), - 'http_post_data' => array(4), - 'http_post_fields' => array(5), - 'http_put_data' => array(4), - 'http_put_file' => array(4), - 'http_put_stream' => array(4), - 'http_request' => array(5), - 'isSuspicious' => array(2), - 'is_callable' => array(3), - 'key' => array(1), - 'krsort' => array(1), - 'ksort' => array(1), - 'ldap_get_option' => array(3), - 'ldap_parse_reference' => array(3), - 'ldap_parse_result' => array(3, 4, 5, 6), - 'localtime' => array(2), - 'm_completeauthorizations' => array(2), - 'maxdb_stmt_bind_param' => array(3, 4, '...'), - 'maxdb_stmt_bind_result' => array(2, 3, '...'), - 'mb_convert_variables' => array(3, 4, '...'), - 'mb_parse_str' => array(2), - 'mqseries_back' => array(2, 3), - 'mqseries_begin' => array(3, 4), - 'mqseries_close' => array(4, 5), - 'mqseries_cmit' => array(2, 3), - 'mqseries_conn' => array(2, 3, 4), - 'mqseries_connx' => array(2, 3, 4, 5), - 'mqseries_disc' => array(2, 3), - 'mqseries_get' => array(3, 4, 5, 6, 7, 8, 9), - 'mqseries_inq' => array(6, 8, 9, 10), - 'mqseries_open' => array(2, 4, 5, 6), - 'mqseries_put' => array(3, 4, 6, 7), - 'mqseries_put1' => array(2, 3, 4, 6, 7), - 'mqseries_set' => array(9, 10), - 'msg_receive' => array(3, 5, 8), - 'msg_send' => array(6), - 'mssql_bind' => array(3), - 'natcasesort' => array(1), - 'natsort' => array(1), - 'ncurses_color_content' => array(2, 3, 4), - 'ncurses_getmaxyx' => array(2, 3), - 'ncurses_getmouse' => array(1), - 'ncurses_getyx' => array(2, 3), - 'ncurses_instr' => array(1), - 'ncurses_mouse_trafo' => array(1, 2), - 'ncurses_mousemask' => array(2), - 'ncurses_pair_content' => array(2, 3), - 'ncurses_wmouse_trafo' => array(2, 3), - 'newt_button_bar' => array(1), - 'newt_form_run' => array(2), - 'newt_get_screen_size' => array(1, 2), - 'newt_grid_get_size' => array(2, 3), - 'newt_reflow_text' => array(5, 6), - 'newt_win_entries' => array(7), - 'newt_win_menu' => array(8), - 'next' => array(1), - 'oci_bind_array_by_name' => array(3), - 'oci_bind_by_name' => array(3), - 'oci_define_by_name' => array(3), - 'oci_fetch_all' => array(2), - 'ocifetchinto' => array(2), - 'odbc_fetch_into' => array(2), - 'openssl_csr_export' => array(2), - 'openssl_csr_new' => array(2), - 'openssl_open' => array(2), - 'openssl_pkcs12_export' => array(2), - 'openssl_pkcs12_read' => array(2), - 'openssl_pkey_export' => array(2), - 'openssl_private_decrypt' => array(2), - 'openssl_private_encrypt' => array(2), - 'openssl_public_decrypt' => array(2), - 'openssl_public_encrypt' => array(2), - 'openssl_random_pseudo_bytes' => array(2), - 'openssl_seal' => array(2, 3), - 'openssl_sign' => array(2), - 'openssl_x509_export' => array(2), - 'ovrimos_fetch_into' => array(2), - 'parse' => array(2,3), - 'parseCurrency' => array(2, 3), - 'parse_str' => array(2), - 'parsekit_compile_file' => array(2), - 'parsekit_compile_string' => array(2), - 'passthru' => array(2), - 'pcntl_sigprocmask' => array(3), - 'pcntl_sigtimedwait' => array(2), - 'pcntl_sigwaitinfo' => array(2), - 'pcntl_wait' => array(1), - 'pcntl_waitpid' => array(2), - 'pfsockopen' => array(3, 4), - 'php_check_syntax' => array(2), - 'poll' => array(1, 2, 3), - 'preg_filter' => array(5), - 'preg_match' => array(3), - 'preg_match_all' => array(3), - 'preg_replace' => array(5), - 'preg_replace_callback' => array(5), - 'prev' => array(1), - 'proc_open' => array(3), - 'query' => array(3), - 'queryExec' => array(2), - 'reset' => array(1), - 'rsort' => array(1), - 'settype' => array(1), - 'shuffle' => array(1), - 'similar_text' => array(3), - 'socket_create_pair' => array(4), - 'socket_getpeername' => array(2, 3), - 'socket_getsockname' => array(2, 3), - 'socket_recv' => array(2), - 'socket_recvfrom' => array(2, 5, 6), - 'socket_select' => array(1, 2, 3), - 'sort' => array(1), - 'sortWithSortKeys' => array(1), - 'sqlite_exec' => array(3), - 'sqlite_factory' => array(3), - 'sqlite_open' => array(3), - 'sqlite_popen' => array(3), - 'sqlite_query' => array(4), - 'sqlite_query' => array(4), - 'sqlite_unbuffered_query' => array(4), - 'sscanf' => array(3, '...'), - 'str_ireplace' => array(4), - 'str_replace' => array(4), - 'stream_open' => array(4), - 'stream_select' => array(1, 2, 3), - 'stream_socket_accept' => array(3), - 'stream_socket_client' => array(2, 3), - 'stream_socket_recvfrom' => array(4), - 'stream_socket_server' => array(2, 3), - 'system' => array(2), - 'uasort' => array(1), - 'uksort' => array(1), - 'unbufferedQuery' => array(3), - 'usort' => array(1), - 'wincache_ucache_dec' => array(3), - 'wincache_ucache_get' => array(2), - 'wincache_ucache_inc' => array(3), - 'xdiff_string_merge3' => array(4), - 'xdiff_string_patch' => array(4), - 'xml_parse_into_struct' => array(3, 4), - 'xml_set_object' => array(2), - 'xmlrpc_decode_request' => array(2), - 'xmlrpc_set_type' => array(1), - 'xslt_set_object' => array(2), - 'yaml_parse' => array(3), - 'yaml_parse_file' => array(3), - 'yaml_parse_url' => array(3), - 'yaz_ccl_parse' => array(3), - 'yaz_hits' => array(2), - 'yaz_scan_result' => array(2), - 'yaz_wait' => array(1), - ); - - /** - * Allows an install to extend the list of known pass-by-reference functions - * by defining generic.codeanalysis.variableanalysis.sitePassByRefFunctions. - */ - public $sitePassByRefFunctions = null; - - /** - * Allows exceptions in a catch block to be unused without provoking unused-var warning. - * Set generic.codeanalysis.variableanalysis.allowUnusedCaughtExceptions to a true value. - */ - public $allowUnusedCaughtExceptions = false; - - /** - * Allow function parameters to be unused without provoking unused-var warning. - * Set generic.codeanalysis.variableanalysis.allowUnusedFunctionParameters to a true value. - */ - public $allowUnusedFunctionParameters = false; - - /** - * A list of names of placeholder variables that you want to ignore from - * unused variable warnings, ie things like $junk. - */ - public $validUnusedVariableNames = null; - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() { - // Magic to modfy $_passByRefFunctions with any site-specific settings. - if (!empty($this->sitePassByRefFunctions)) { - foreach (preg_split('/\s+/', trim($this->sitePassByRefFunctions)) as $line) { - list ($function, $args) = explode(':', $line); - $this->_passByRefFunctions[$function] = explode(',', $args); - } - } - if (!empty($this->validUnusedVariableNames)) { - $this->validUnusedVariableNames = - preg_split('/\s+/', trim($this->validUnusedVariableNames)); - } - return array( - T_VARIABLE, - T_DOUBLE_QUOTED_STRING, - T_HEREDOC, - T_CLOSE_CURLY_BRACKET, - T_STRING, - ); - }//end register() - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - //if ($token['content'] == '$param') { - //echo "Found token on line {$token['line']}.\n" . print_r($token, true); - //} - - if ($this->currentFile !== $phpcsFile) { - $this->currentFile = $phpcsFile; - } - - if ($token['code'] === T_VARIABLE) { - return $this->processVariable($phpcsFile, $stackPtr); - } - if (($token['code'] === T_DOUBLE_QUOTED_STRING) || - ($token['code'] === T_HEREDOC)) { - return $this->processVariableInString($phpcsFile, $stackPtr); - } - if (($token['code'] === T_STRING) && ($token['content'] === 'compact')) { - return $this->processCompact($phpcsFile, $stackPtr); - } - if (($token['code'] === T_CLOSE_CURLY_BRACKET) && - isset($token['scope_condition'])) { - return $this->processScopeClose($phpcsFile, $token['scope_condition']); - } - } - - function normalizeVarName($varName) { - $varName = preg_replace('/[{}$]/', '', $varName); - return $varName; - } - - function scopeKey($currScope) { - if ($currScope === false) { - $currScope = 'file'; - } - return ($this->currentFile ? $this->currentFile->getFilename() : 'unknown file') . - ':' . $currScope; - } - - // Warning: this is an autovivifying get - function getScopeInfo($currScope, $autoCreate = true) { - $scopeKey = $this->scopeKey($currScope); - if (!isset($this->_scopes[$scopeKey])) { - if (!$autoCreate) { - return null; - } - $this->_scopes[$scopeKey] = new ScopeInfo($currScope); - } - return $this->_scopes[$scopeKey]; - } - - function getVariableInfo($varName, $currScope, $autoCreate = true) { - $scopeInfo = $this->getScopeInfo($currScope, $autoCreate); - if (!isset($scopeInfo->variables[$varName])) { - if (!$autoCreate) { - return null; - } - $scopeInfo->variables[$varName] = new VariableInfo($varName); - if ($this->validUnusedVariableNames && - in_array($varName, $this->validUnusedVariableNames)) { - $scopeInfo->variables[$varName]->ignoreUnused = true; - } - } - return $scopeInfo->variables[$varName]; - } - - function markVariableAssignment($varName, $stackPtr, $currScope) { - $varInfo = $this->getVariableInfo($varName, $currScope); - if (!isset($varInfo->scopeType)) { - $varInfo->scopeType = 'local'; - } - if (isset($varInfo->firstInitialized) && ($varInfo->firstInitialized <= $stackPtr)) { - return; - } - $varInfo->firstInitialized = $stackPtr; - } - - function markVariableDeclaration($varName, $scopeType, $typeHint, $stackPtr, $currScope, $permitMatchingRedeclaration = false) { - $varInfo = $this->getVariableInfo($varName, $currScope); - if (isset($varInfo->scopeType)) { - if (($permitMatchingRedeclaration === false) || - ($varInfo->scopeType !== $scopeType)) { - // Issue redeclaration/reuse warning - // Note: we check off scopeType not firstDeclared, this is so that - // we catch declarations that come after implicit declarations like - // use of a variable as a local. - $this->currentFile->addWarning( - "Redeclaration of %s %s as %s.", - $stackPtr, - 'VariableRedeclaration', - array( - VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], - "\${$varName}", - VariableInfo::$scopeTypeDescriptions[$scopeType], - ) - ); - } - } - $varInfo->scopeType = $scopeType; - if (isset($typeHint)) { - $varInfo->typeHint = $typeHint; - } - if (isset($varInfo->firstDeclared) && ($varInfo->firstDeclared <= $stackPtr)) { - return; - } - $varInfo->firstDeclared = $stackPtr; - } - - function markVariableRead($varName, $stackPtr, $currScope) { - $varInfo = $this->getVariableInfo($varName, $currScope); - if (isset($varInfo->firstRead) && ($varInfo->firstRead <= $stackPtr)) { - return; - } - $varInfo->firstRead = $stackPtr; - } - - function isVariableInitialized($varName, $stackPtr, $currScope) { - $varInfo = $this->getVariableInfo($varName, $currScope); - if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) { - return true; - } - return false; - } - - function isVariableUndefined($varName, $stackPtr, $currScope) { - $varInfo = $this->getVariableInfo($varName, $currScope, false); - if (isset($varInfo->firstDeclared) && $varInfo->firstDeclared <= $stackPtr) { - // TODO: do we want to check scopeType here? - return false; - } - if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) { - return false; - } - return true; - } - - function markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope) { - $this->markVariableRead($varName, $stackPtr, $currScope); - - if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) { - // We haven't been defined by this point. - $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr, - 'UndefinedVariable', - array("\${$varName}")); - } - return true; - } - - function findFunctionPrototype( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { - return false; - } - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND), - $openPtr - 1, null, true, null, true); - if (($functionPtr !== false) && - ($tokens[$functionPtr]['code'] === T_FUNCTION)) { - return $functionPtr; - } - return false; - } - - function findVariableScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - $in_class = false; - if (!empty($token['conditions'])) { - foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { - if (($scopeCode === T_FUNCTION) || ($scopeCode === T_CLOSURE)) { - return $scopePtr; - } - if (($scopeCode === T_CLASS) || ($scopeCode === T_INTERFACE)) { - $in_class = true; - } - } - } - - if (($scopePtr = $this->findFunctionPrototype($phpcsFile, $stackPtr)) !== false) { - return $scopePtr; - } - - if ($in_class) { - // Member var of a class, we don't care. - return false; - } - - // File scope, hmm, lets use first token of file? - return 0; - } - - function isNextThingAnAssign( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - - // Is the next non-whitespace an assignment? - $nextPtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true, null, true); - if ($nextPtr !== false) { - if ($tokens[$nextPtr]['code'] === T_EQUAL) { - return $nextPtr; - } - } - return false; - } - - function findWhereAssignExecuted( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - - // Write should be recorded at the next statement to ensure we treat - // the assign as happening after the RHS execution. - // eg: $var = $var + 1; -> RHS could still be undef. - // However, if we're within a bracketed expression, we take place at - // the closing bracket, if that's first. - // eg: echo (($var = 12) && ($var == 12)); - $semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1, null, false, null, true); - $closePtr = false; - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) !== false) { - if (isset($tokens[$openPtr]['parenthesis_closer'])) { - $closePtr = $tokens[$openPtr]['parenthesis_closer']; - } - } - - if ($semicolonPtr === false) { - if ($closePtr === false) { - // TODO: panic - return $stackPtr; - } - return $closePtr; - } - - if ($closePtr < $semicolonPtr) { - return $closePtr; - } - - return $semicolonPtr; - } - - function findContainingBrackets( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['nested_parenthesis'])) { - $openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']); - return end($openPtrs); - } - return false; - } - - - function findFunctionCall( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - - if ($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) { - // First non-whitespace thing and see if it's a T_STRING function name - $functionPtr = $phpcsFile->findPrevious(T_WHITESPACE, - $openPtr - 1, null, true, null, true); - if ($tokens[$functionPtr]['code'] === T_STRING) { - return $functionPtr; - } - } - return false; - } - - function findFunctionCallArguments( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - - // Slight hack: also allow this to find args for array constructor. - // TODO: probably should refactor into three functions: arg-finding and bracket-finding - if (($tokens[$stackPtr]['code'] !== T_STRING) && ($tokens[$stackPtr]['code'] !== T_ARRAY)) { - // Assume $stackPtr is something within the brackets, find our function call - if (($stackPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) { - return false; - } - } - - // $stackPtr is the function name, find our brackets after it - $openPtr = $phpcsFile->findNext(T_WHITESPACE, - $stackPtr + 1, null, true, null, true); - if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) { - return false; - } - - if (!isset($tokens[$openPtr]['parenthesis_closer'])) { - return false; - } - $closePtr = $tokens[$openPtr]['parenthesis_closer']; - - $argPtrs = array(); - $lastPtr = $openPtr; - $lastArgComma = $openPtr; - while (($nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr)) !== false) { - if ($this->findContainingBrackets($phpcsFile, $nextPtr) == $openPtr) { - // Comma is at our level of brackets, it's an argument delimiter. - array_push($argPtrs, range($lastArgComma + 1, $nextPtr - 1)); - $lastArgComma = $nextPtr; - } - $lastPtr = $nextPtr; - } - array_push($argPtrs, range($lastArgComma + 1, $closePtr - 1)); - - return $argPtrs; - } - - protected function checkForFunctionPrototype( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a function or closure parameter? - // It would be nice to get the list of function parameters from watching for - // T_FUNCTION, but AbstractVariableSniff and AbstractScopeSniff define everything - // we need to do that as private or final, so we have to do it this hackish way. - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { - return false; - } - - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND), - $openPtr - 1, null, true, null, true); - if (($functionPtr !== false) && - (($tokens[$functionPtr]['code'] === T_FUNCTION) || - ($tokens[$functionPtr]['code'] === T_CLOSURE))) { - // TODO: typeHint - $this->markVariableDeclaration($varName, 'param', null, $stackPtr, $functionPtr); - // Are we pass-by-reference? - $referencePtr = $phpcsFile->findPrevious(T_WHITESPACE, - $stackPtr - 1, null, true, null, true); - if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) { - $varInfo = $this->getVariableInfo($varName, $functionPtr); - $varInfo->passByReference = true; - } - // Are we optional with a default? - if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) { - $this->markVariableAssignment($varName, $stackPtr, $functionPtr); - } - return true; - } - - // Is it a use keyword? Use is both a read and a define, fun! - if (($functionPtr !== false) && ($tokens[$functionPtr]['code'] === T_USE)) { - $this->markVariableRead($varName, $stackPtr, $currScope); - if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) { - // We haven't been defined by this point. - $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr, - 'UndefinedVariable', - array("\${$varName}")); - return true; - } - // $functionPtr is at the use, we need the function keyword for start of scope. - $functionPtr = $phpcsFile->findPrevious(T_CLOSURE, - $functionPtr - 1, $currScope + 1, false, null, true); - if ($functionPtr !== false) { - // TODO: typeHints in use? - $this->markVariableDeclaration($varName, 'bound', null, $stackPtr, $functionPtr); - $this->markVariableAssignment($varName, $stackPtr, $functionPtr); - return true; - } - } - return false; - } - - protected function checkForCatchBlock( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a catch block parameter? - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { - return false; - } - - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $catchPtr = $phpcsFile->findPrevious(T_WHITESPACE, - $openPtr - 1, null, true, null, true); - if (($catchPtr !== false) && - ($tokens[$catchPtr]['code'] === T_CATCH)) { - // Scope of the exception var is actually the function, not just the catch block. - // TODO: typeHint - $this->markVariableDeclaration($varName, 'local', null, $stackPtr, $currScope, true); - $this->markVariableAssignment($varName, $stackPtr, $currScope); - if ($this->allowUnusedCaughtExceptions) { - $varInfo = $this->getVariableInfo($varName, $currScope); - $varInfo->ignoreUnused = true; - } - return true; - } - return false; - } - - protected function checkForThisWithinClass( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we $this within a class? - if (($varName != 'this') || empty($token['conditions'])) { - return false; - } - - foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { - // $this within a closure is invalid - // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. - if ($tokens[$scopePtr]['code'] === T_CLOSURE) { - return false; - } - if ($scopeCode === T_CLASS) { - return true; - } - } - - return false; - } - - protected function checkForSuperGlobal( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a superglobal variable? - if (in_array($varName, array( - 'GLOBALS', - '_SERVER', - '_GET', - '_POST', - '_FILES', - '_COOKIE', - '_SESSION', - '_REQUEST', - '_ENV', - 'argv', - 'argc', - ))) { - return true; - } - - return false; - } - - protected function checkForStaticMember( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a static member? - $doubleColonPtr = $stackPtr - 1; - if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) { - return false; - } - $classNamePtr = $stackPtr - 2; - if (($tokens[$classNamePtr]['code'] !== T_STRING) && - ($tokens[$classNamePtr]['code'] !== T_SELF) && - ($tokens[$classNamePtr]['code'] !== T_STATIC)) { - return false; - } - - // Are we refering to self:: outside a class? - // TODO: not sure this is our business or should be some other sniff. - if (($tokens[$classNamePtr]['code'] === T_SELF) || - ($tokens[$classNamePtr]['code'] === T_STATIC)) { - if ($tokens[$classNamePtr]['code'] === T_SELF) { - $err_class = 'SelfOutsideClass'; - $err_desc = 'self::'; - } else { - $err_class = 'StaticOutsideClass'; - $err_desc = 'static::'; - } - if (!empty($token['conditions'])) { - foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) { - // self within a closure is invalid - // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. - if ($tokens[$scopePtr]['code'] === T_CLOSURE) { - $phpcsFile->addError("Use of {$err_desc}%s inside closure.", $stackPtr, - $err_class, - array("\${$varName}")); - return true; - } - if ($scopeCode === T_CLASS) { - return true; - } - } - } - $phpcsFile->addError("Use of {$err_desc}%s outside class definition.", $stackPtr, - $err_class, - array("\${$varName}")); - return true; - } - - return true; - } - - protected function checkForAssignment( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Is the next non-whitespace an assignment? - if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $stackPtr)) === false) { - return false; - } - - // Plain ol' assignment. Simpl(ish). - if (($writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr)) === false) { - $writtenPtr = $stackPtr; // I dunno - } - $this->markVariableAssignment($varName, $writtenPtr, $currScope); - return true; - } - - protected function checkForListAssignment( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // OK, are we within a list (...) construct? - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { - return false; - } - - $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, $openPtr - 1, null, true, null, true); - if (($prevPtr === false) || ($tokens[$prevPtr]['code'] !== T_LIST)) { - return false; - } - - // OK, we're a list (...) construct... are we being assigned to? - $closePtr = $tokens[$openPtr]['parenthesis_closer']; - if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $closePtr)) === false) { - return false; - } - - // Yes, we're being assigned. - $writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr); - $this->markVariableAssignment($varName, $writtenPtr, $currScope); - return true; - } - - protected function checkForGlobalDeclaration( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a global declaration? - // Search backwards for first token that isn't whitespace, comma or variable. - $globalPtr = $phpcsFile->findPrevious( - array(T_WHITESPACE, T_VARIABLE, T_COMMA), - $stackPtr - 1, null, true, null, true); - if (($globalPtr === false) || ($tokens[$globalPtr]['code'] !== T_GLOBAL)) { - return false; - } - - // It's a global declaration. - $this->markVariableDeclaration($varName, 'global', null, $stackPtr, $currScope); - return true; - } - - protected function checkForStaticDeclaration( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a static declaration? - // Static declarations are a bit more complicated than globals, since they - // can contain assignments. The assignment is compile-time however so can - // only be constant values, which makes life manageable. - // - // Just to complicate matters further, late static binding constants - // take the form static::CONSTANT and are invalid within static variable - // assignments, but we don't want to accidentally match their use of the - // static keyword. - // - // Valid values are: - // number T_MINUS T_LNUMBER T_DNUMBER - // string T_CONSTANT_ENCAPSED_STRING - // heredoc T_START_HEREDOC T_HEREDOC T_END_HEREDOC - // nowdoc T_START_NOWDOC T_NOWDOC T_END_NOWDOC - // define T_STRING - // class constant T_STRING T_DOUBLE_COLON T_STRING - // Search backwards for first token that isn't whitespace, comma, variable, - // equals, or on the list of assignable constant values above. - $staticPtr = $phpcsFile->findPrevious( - array( - T_WHITESPACE, T_VARIABLE, T_COMMA, T_EQUAL, - T_MINUS, T_LNUMBER, T_DNUMBER, - T_CONSTANT_ENCAPSED_STRING, - T_STRING, - T_DOUBLE_COLON, - T_START_HEREDOC, T_HEREDOC, T_END_HEREDOC, - T_START_NOWDOC, T_NOWDOC, T_END_NOWDOC, - ), - $stackPtr - 1, null, true, null, true); - if (($staticPtr === false) || ($tokens[$staticPtr]['code'] !== T_STATIC)) { - //if ($varName == 'static4') { - // echo "Failing token:\n" . print_r($tokens[$staticPtr], true); - //} - return false; - } - - // Is it a late static binding static::? - // If so, this isn't the static keyword we're looking for, but since - // static:: isn't allowed in a compile-time constant, we also know - // we can't be part of a static declaration anyway, so there's no - // need to look any further. - $lateStaticBindingPtr = $phpcsFile->findNext(T_WHITESPACE, $staticPtr + 1, null, true, null, true); - if (($lateStaticBindingPtr !== false) && ($tokens[$lateStaticBindingPtr]['code'] === T_DOUBLE_COLON)) { - return false; - } - - // It's a static declaration. - $this->markVariableDeclaration($varName, 'static', null, $stackPtr, $currScope); - if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) { - $this->markVariableAssignment($varName, $stackPtr, $currScope); - } - return true; - } - - protected function checkForForeachLoopVar( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a foreach loopvar? - if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) { - return false; - } - - // Is there an 'as' token between us and the opening bracket? - if ($phpcsFile->findPrevious(T_AS, $stackPtr - 1, $openPtr) === false) { - return false; - } - - $this->markVariableAssignment($varName, $stackPtr, $currScope); - return true; - } - - protected function checkForPassByReferenceFunctionCall( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we pass-by-reference to known pass-by-reference function? - if (($functionPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) { - return false; - } - - // Is our function a known pass-by-reference function? - $functionName = $tokens[$functionPtr]['content']; - if (!isset($this->_passByRefFunctions[$functionName])) { - return false; - } - - $refArgs = $this->_passByRefFunctions[$functionName]; - - if (($argPtrs = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) === false) { - return false; - } - - // We're within a function call arguments list, find which arg we are. - $argPos = false; - foreach ($argPtrs as $idx => $ptrs) { - if (in_array($stackPtr, $ptrs)) { - $argPos = $idx + 1; - break; - } - } - if ($argPos === false) { - return false; - } - if (!in_array($argPos, $refArgs)) { - // Our arg wasn't mentioned explicitly, are we after an elipsis catch-all? - if (($elipsis = array_search('...', $refArgs)) === false) { - return false; - } - if ($argPos < $refArgs[$elipsis - 1]) { - return false; - } - } - - // Our argument position matches that of a pass-by-ref argument, - // check that we're the only part of the argument expression. - foreach ($argPtrs[$argPos - 1] as $ptr) { - if ($ptr === $stackPtr) { - continue; - } - if ($tokens[$ptr]['code'] !== T_WHITESPACE) { - return false; - } - } - - // Just us, we can mark it as a write. - $this->markVariableAssignment($varName, $stackPtr, $currScope); - // It's a read as well for purposes of used-variables. - $this->markVariableRead($varName, $stackPtr, $currScope); - return true; - } - - protected function checkForSymbolicObjectProperty( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $varName, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - // Are we a symbolic object property/function derefeference? - // Search backwards for first token that isn't whitespace, is it a "->" operator? - $objectOperatorPtr = $phpcsFile->findPrevious( - T_WHITESPACE, - $stackPtr - 1, null, true, null, true); - if (($objectOperatorPtr === false) || ($tokens[$objectOperatorPtr]['code'] !== T_OBJECT_OPERATOR)) { - return false; - } - - $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); - return true; - } - - /** - * Called to process class member vars. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processMemberVar( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - // TODO: don't care for now - } - - /** - * Called to process normal member vars. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariable( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - $varName = $this->normalizeVarName($token['content']); - if (($currScope = $this->findVariableScope($phpcsFile, $stackPtr)) === false) { - return; - } - - //static $dump_token = false; - //if ($varName == 'property') { - // $dump_token = true; - //} - //if ($dump_token) { - // echo "Found variable {$varName} on line {$token['line']} in scope {$currScope}.\n" . print_r($token, true); - // echo "Prev:\n" . print_r($tokens[$stackPtr - 1], true); - //} - - // Determine if variable is being assigned or read. - - // Read methods that preempt assignment: - // Are we a $object->$property type symbolic reference? - - // Possible assignment methods: - // Is a mandatory function/closure parameter - // Is an optional function/closure parameter with non-null value - // Is closure use declaration of a variable defined within containing scope - // catch (...) block start - // $this within a class (but not within a closure). - // $GLOBALS, $_REQUEST, etc superglobals. - // $var part of class::$var static member - // Assignment via = - // Assignment via list (...) = - // Declares as a global - // Declares as a static - // Assignment via foreach (... as ...) { } - // Pass-by-reference to known pass-by-reference function - - // Are we a $object->$property type symbolic reference? - if ($this->checkForSymbolicObjectProperty($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a function or closure parameter? - if ($this->checkForFunctionPrototype($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a catch parameter? - if ($this->checkForCatchBlock($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we $this within a class? - if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a $GLOBALS, $_REQUEST, etc superglobal? - if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // $var part of class::$var static member - if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Is the next non-whitespace an assignment? - if ($this->checkForAssignment($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // OK, are we within a list (...) = construct? - if ($this->checkForListAssignment($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a global declaration? - if ($this->checkForGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a static declaration? - if ($this->checkForStaticDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we a foreach loopvar? - if ($this->checkForForeachLoopVar($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // Are we pass-by-reference to known pass-by-reference function? - if ($this->checkForPassByReferenceFunctionCall($phpcsFile, $stackPtr, $varName, $currScope)) { - return; - } - - // OK, we don't appear to be a write to the var, assume we're a read. - $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); - } - - /** - * Called to process variables found in double quoted strings. - * - * Note that there may be more than one variable in the string, which will - * result only in one call for the string. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the double quoted - * string was found. - * - * @return void - */ - protected function processVariableInString( - PHP_CodeSniffer_File - $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - if (!preg_match_all($this->_double_quoted_variable_regexp, $token['content'], $matches)) { - return; - } - - $currScope = $this->findVariableScope($phpcsFile, $stackPtr); - foreach ($matches[1] as $varName) { - $varName = $this->normalizeVarName($varName); - // Are we $this within a class? - if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) { - continue; - } - if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) { - continue; - } - $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope); - } - } - - protected function processCompactArguments( - PHP_CodeSniffer_File - $phpcsFile, - $stackPtr, - $arguments, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - foreach ($arguments as $argumentPtrs) { - $argumentPtrs = array_values(array_filter($argumentPtrs, - function ($argumentPtr) use ($tokens) { - return $tokens[$argumentPtr]['code'] !== T_WHITESPACE; - })); - if (empty($argumentPtrs)) { - continue; - } - if (!isset($tokens[$argumentPtrs[0]])) { - continue; - } - $argument_first_token = $tokens[$argumentPtrs[0]]; - if ($argument_first_token['code'] === T_ARRAY) { - // It's an array argument, recurse. - if (($array_arguments = $this->findFunctionCallArguments($phpcsFile, $argumentPtrs[0])) !== false) { - $this->processCompactArguments($phpcsFile, $stackPtr, $array_arguments, $currScope); - } - continue; - } - if (count($argumentPtrs) > 1) { - // Complex argument, we can't handle it, ignore. - continue; - } - if ($argument_first_token['code'] === T_CONSTANT_ENCAPSED_STRING) { - // Single-quoted string literal, ie compact('whatever'). - // Substr is to strip the enclosing single-quotes. - $varName = substr($argument_first_token['content'], 1, -1); - $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope); - continue; - } - if ($argument_first_token['code'] === T_DOUBLE_QUOTED_STRING) { - // Double-quoted string literal. - if (preg_match($this->_double_quoted_variable_regexp, $argument_first_token['content'])) { - // Bail if the string needs variable expansion, that's runtime stuff. - continue; - } - // Substr is to strip the enclosing double-quotes. - $varName = substr($argument_first_token['content'], 1, -1); - $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope); - continue; - } - } - } - - /** - * Called to process variables named in a call to compact(). - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position where the call to compact() - * was found. - * - * @return void - */ - protected function processCompact( - PHP_CodeSniffer_File - $phpcsFile, - $stackPtr - ) { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - - $currScope = $this->findVariableScope($phpcsFile, $stackPtr); - - if (($arguments = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) !== false) { - $this->processCompactArguments($phpcsFile, $stackPtr, $arguments, $currScope); - } - } - - /** - * Called to process the end of a scope. - * - * Note that although triggered by the closing curly brace of the scope, $stackPtr is - * the scope conditional, not the closing curly brace. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this - * token was found. - * @param int $stackPtr The position of the scope conditional. - * - * @return void - */ - protected function processScopeClose( - PHP_CodeSniffer_File - $phpcsFile, - $stackPtr - ) { - $scopeInfo = $this->getScopeInfo($stackPtr, false); - if (is_null($scopeInfo)) { - return; - } - foreach ($scopeInfo->variables as $varInfo) { - if ($varInfo->ignoreUnused || isset($varInfo->firstRead)) { - continue; - } - if ($this->allowUnusedFunctionParameters && $varInfo->scopeType == 'param') { - continue; - } - if ($varInfo->passByReference && isset($varInfo->firstInitialized)) { - // If we're pass-by-reference then it's a common pattern to - // use the variable to return data to the caller, so any - // assignment also counts as "variable use" for the purposes - // of "unused variable" warnings. - continue; - } - if (isset($varInfo->firstDeclared)) { - $phpcsFile->addWarning( - "Unused %s %s.", - $varInfo->firstDeclared, - 'UnusedVariable', - array( - VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], - "\${$varInfo->name}", - ) - ); - } - if (isset($varInfo->firstInitialized)) { - $phpcsFile->addWarning( - "Unused %s %s.", - $varInfo->firstInitialized, - 'UnusedVariable', - array( - VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], - "\${$varInfo->name}", - ) - ); - } - } - } -}//end class - -?> \ No newline at end of file diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php deleted file mode 100644 index 56058a591..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @author Sam Graham - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Commenting_FixmeSniff. - * - * Warns about FIXME comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Sam Graham - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Commenting_FixmeSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$commentTokens; - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - $matches = array(); - if (preg_match('|[^a-z]+fixme[^a-z]+(.*)|i', $content, $matches) !== 0) { - // Clear whitespace and some common characters not required at - // the end of a fixme message to make the error more informative. - $type = 'CommentFound'; - $fixmeMessage = trim($matches[1]); - $fixmeMessage = trim($fixmeMessage, '[]().'); - $error = 'Comment refers to a FIXME task'; - $data = array($fixmeMessage); - if ($fixmeMessage !== '') { - $type = 'TaskFound'; - $error .= ' "%s"'; - } - - $phpcsFile->addError($error, $stackPtr, $type, $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php deleted file mode 100644 index 9ecee9cab..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Commenting_TodoSniff. - * - * Warns about TODO comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Commenting_TodoSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$commentTokens; - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - $matches = array(); - if (preg_match('|[^a-z]+todo[^a-z]+(.*)|i', $content, $matches) !== 0) { - // Clear whitespace and some common characters not required at - // the end of a to-do message to make the warning more informative. - $type = 'CommentFound'; - $todoMessage = trim($matches[1]); - $todoMessage = trim($todoMessage, '[]().'); - $error = 'Comment refers to a TODO task'; - $data = array($todoMessage); - if ($todoMessage !== '') { - $type = 'TaskFound'; - $error .= ' "%s"'; - } - - $phpcsFile->addWarning($error, $stackPtr, $type, $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php deleted file mode 100644 index 10d7a766d..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_ControlStructures_InlineControlStructureSniff. - * - * Verifies that inline control statements are not present. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_ControlStructures_InlineControlStructureSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = true; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_ELSE, - T_FOREACH, - T_WHILE, - T_DO, - T_SWITCH, - T_FOR, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - // Ignore the ELSE in ELSE IF. We'll process the IF part later. - if (($tokens[$stackPtr]['code'] === T_ELSE) && ($tokens[($stackPtr + 2)]['code'] === T_IF)) { - return; - } - - if ($tokens[$stackPtr]['code'] === T_WHILE) { - // This could be from a DO WHILE, which doesn't have an opening brace. - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { - $brace = $tokens[$lastContent]; - if (isset($brace['scope_condition']) === true) { - $condition = $tokens[$brace['scope_condition']]; - if ($condition['code'] === T_DO) { - return; - } - } - } - } - - // This is a control structure without an opening brace, - // so it is an inline statement. - if ($this->error === true) { - $phpcsFile->addError('Inline control structures are not allowed', $stackPtr, 'NotAllowed'); - } else { - $phpcsFile->addWarning('Inline control structures are discouraged', $stackPtr, 'Discouraged'); - } - - return; - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php deleted file mode 100644 index 6f4ad49e1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @copyright 2013 Roman Levishchenko - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Debug_CSSLintSniff. - * - * Runs csslint on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Roman Levishchenko - * @copyright 2013 Roman Levishchenko - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Debug_CSSLintSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - - $csslintPath = PHP_CodeSniffer::getConfigData('csslint_path'); - if ($csslintPath === null) { - return; - } - - $cmd = $csslintPath.' '.escapeshellarg($fileName); - exec($cmd, $output, $retval); - - if (is_array($output) === false) { - return; - } - - $tokens = $phpcsFile->getTokens(); - $count = count($output); - - for ($i = 0; $i < $count; $i++) { - $matches = array(); - $numMatches = preg_match( - '/(error|warning) at line (\d+)/', - $output[$i], - $matches - ); - - if ($numMatches === 0) { - continue; - } - - $line = (int) $matches[2]; - $message = 'csslint says: '.$output[($i + 1)]; - // 1-st line is message with error line and error code. - // 2-nd error message. - // 3-d wrong line in file. - // 4-th empty line. - $i += 4; - - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] === $line) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); - } - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php deleted file mode 100644 index c675ce04b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php +++ /dev/null @@ -1,139 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Debug_ClosureLinterSniff. - * - * Runs gjslint on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Debug_ClosureLinterSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of error codes that should show errors. - * - * All other error codes will show warnings. - * - * @var int - */ - public $errorCodes = array(); - - /** - * A list of error codes to ignore. - * - * @var int - */ - public $ignoreCodes = array(); - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - * @throws PHP_CodeSniffer_Exception If jslint.js could not be run - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - - $lintPath = PHP_CodeSniffer::getConfigData('gjslint_path'); - if ($lintPath === null) { - return; - } - - $cmd = "$lintPath --nosummary --notime --unix_mode \"$fileName\""; - $msg = exec($cmd, $output, $retval); - - if (is_array($output) === false) { - return; - } - - $tokens = $phpcsFile->getTokens(); - - foreach ($output as $finding) { - $matches = array(); - $numMatches = preg_match('/^(.*):([0-9]+):\(.*?([0-9]+)\)(.*)$/', $finding, $matches); - if ($numMatches === 0) { - continue; - } - - // Skip error codes we are ignoring. - $code = $matches[3]; - if (in_array($code, $this->ignoreCodes) === true) { - continue; - } - - $line = (int) $matches[2]; - $error = trim($matches[4]); - - // Find the token at the start of the line. - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] === $line) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $message = 'gjslint says: (%s) %s'; - $data = array( - $code, - $error, - ); - if (in_array($code, $this->errorCodes) === true) { - $phpcsFile->addError($message, $lineToken, 'ExternalToolError', $data); - } else { - $phpcsFile->addWarning($message, $lineToken, 'ExternalTool', $data); - } - } - }//end foreach - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php deleted file mode 100644 index b0213cb83..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php +++ /dev/null @@ -1,109 +0,0 @@ - - * @author Alexander Wei§ - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Debug_JSHintSniff. - * - * Runs jshint.js on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Alexander Wei§ - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Debug_JSHintSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - * @throws PHP_CodeSniffer_Exception If jshint.js could not be run - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - - $rhinoPath = PHP_CodeSniffer::getConfigData('rhino_path'); - $jshintPath = PHP_CodeSniffer::getConfigData('jshint_path'); - if ($rhinoPath === null || $jshintPath === null) { - return; - } - - $cmd = "$rhinoPath \"$jshintPath\" \"$fileName\""; - $msg = exec($cmd, $output, $retval); - - if (is_array($output) === true) { - $tokens = $phpcsFile->getTokens(); - - foreach ($output as $finding) { - $matches = array(); - $numMatches = preg_match('/^(.+)\(.+:([0-9]+).*:[0-9]+\)$/', $finding, $matches); - if ($numMatches === 0) { - continue; - } - - $line = (int) $matches[2]; - $message = 'jshint says: '.trim($matches[1]); - - // Find the token at the start of the line. - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] === $line) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); - } - }//end foreach - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php deleted file mode 100644 index 9dcbfcdb1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_ByteOrderMarkSniff. - * - * A simple sniff for detecting BOMs that may corrupt application work. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Piotr Karas - * @author Greg Sherwood - * @copyright 2010-2011 mediaSELF Sp. z o.o. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - * @see http://en.wikipedia.org/wiki/Byte_order_mark - */ -class Generic_Sniffs_Files_ByteOrderMarkSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * List of supported BOM definitions. - * - * Use encoding names as keys and hex BOM representations as values. - * - * @var array - */ - public $bomDefinitions = array( - 'UTF-8' => 'efbbbf', - 'UTF-16 (BE)' => 'feff', - 'UTF-16 (LE)' => 'fffe', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_INLINE_HTML); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) - { - // The BOM will be the very first token in the file. - if ($stackPtr !== 0) { - return; - } - - $tokens = $phpcsFile->getTokens(); - - foreach ($this->bomDefinitions as $bomName => $expectedBomHex) { - $bomByteLength = (strlen($expectedBomHex) / 2); - $htmlBomHex = bin2hex(substr($tokens[$stackPtr]['content'], 0, $bomByteLength)); - if ($htmlBomHex === $expectedBomHex) { - $errorData = array($bomName); - $error = 'File contains %s byte order mark, which may corrupt your application'; - $phpcsFile->addError($error, $stackPtr, 'Found', $errorData); - break; - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php deleted file mode 100644 index cc56746e5..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_EndFileNewlineSniff. - * - * Ensures the file ends with a newline character. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_EndFileNewlineSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - // Skip to the end of the file. - $tokens = $phpcsFile->getTokens(); - $stackPtr = ($phpcsFile->numTokens - 1); - - if ($phpcsFile->tokenizerType === 'JS') { - $stackPtr--; - } else if ($phpcsFile->tokenizerType === 'CSS') { - $stackPtr -= 2; - } - - $eolCharLen = strlen($phpcsFile->eolChar); - $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); - if ($lastChars !== $phpcsFile->eolChar) { - $error = 'File must end with a newline character'; - $phpcsFile->addError($error, $stackPtr, 'NotFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php deleted file mode 100644 index cbc4e7f23..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_EndFileNoNewlineSniff. - * - * Ensures the file does not end with a newline character. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_EndFileNoNewlineSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - // Skip to the end of the file. - $tokens = $phpcsFile->getTokens(); - $stackPtr = ($phpcsFile->numTokens - 1); - - if ($phpcsFile->tokenizerType === 'JS') { - $stackPtr--; - } else if ($phpcsFile->tokenizerType === 'CSS') { - $stackPtr -= 2; - } - - $eolCharLen = strlen($phpcsFile->eolChar); - $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); - if ($lastChars === $phpcsFile->eolChar) { - $error = 'File must not end with a newline character'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php deleted file mode 100644 index 6886808e5..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_InlineHTMLSniff. - * - * Ensures the whole file is PHP only, with no whitespace or inline HTML anywhere - * in the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_InlineHTMLSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // Make sure this is the first open tag. - $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($previousOpenTag !== false) { - return; - } - - $inline = $phpcsFile->findNext(T_INLINE_HTML, 0); - if ($inline === false) { - return; - } - - $error = 'PHP files must only contain PHP code'; - $phpcsFile->addError($error, $inline, 'Found'); - - }//end process() - - -}//end class - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php deleted file mode 100644 index 0fd4ad3e8..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_LineEndingsSniff. - * - * Checks that end of line characters are correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_LineEndingsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - /** - * The valid EOL character. - * - * @var string - */ - public $eolChar = '\n'; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - $found = $phpcsFile->eolChar; - $found = str_replace("\n", '\n', $found); - $found = str_replace("\r", '\r', $found); - - if ($found !== $this->eolChar) { - // Check for single line files without an EOL. This is a very special - // case and the EOL char is set to \n when this happens. - if ($found === '\n') { - $tokens = $phpcsFile->getTokens(); - $lastToken = ($phpcsFile->numTokens - 1); - if ($tokens[$lastToken]['line'] === 1 - && $tokens[$lastToken]['content'] !== "\n" - ) { - return; - } - } - - $error = 'End of line character is invalid; expected "%s" but found "%s"'; - $expected = $this->eolChar; - $expected = str_replace("\n", '\n', $expected); - $expected = str_replace("\r", '\r', $expected); - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'InvalidEOLChar', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php deleted file mode 100644 index 7674d72ef..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php +++ /dev/null @@ -1,160 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_LineLengthSniff. - * - * Checks all lines in the file, and throws warnings if they are over 80 - * characters in length and errors if they are over 100. Both these - * figures can be changed by extending this sniff in your own standard. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_LineLengthSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The limit that the length of a line should not exceed. - * - * @var int - */ - public $lineLimit = 80; - - /** - * The limit that the length of a line must not exceed. - * - * Set to zero (0) to disable. - * - * @var int - */ - public $absoluteLineLimit = 100; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is the first open tag. - $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($previousOpenTag !== false) { - return; - } - - $tokenCount = 0; - $currentLineContent = ''; - $currentLine = 1; - - $trim = (strlen($phpcsFile->eolChar) * -1); - for (; $tokenCount < $phpcsFile->numTokens; $tokenCount++) { - if ($tokens[$tokenCount]['line'] === $currentLine) { - $currentLineContent .= $tokens[$tokenCount]['content']; - } else { - $currentLineContent = substr($currentLineContent, 0, $trim); - $this->checkLineLength($phpcsFile, ($tokenCount - 1), $currentLineContent); - $currentLineContent = $tokens[$tokenCount]['content']; - $currentLine++; - } - } - - $currentLineContent = substr($currentLineContent, 0, $trim); - $this->checkLineLength($phpcsFile, ($tokenCount - 1), $currentLineContent); - - }//end process() - - - /** - * Checks if a line is too long. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The token at the end of the line. - * @param string $lineContent The content of the line. - * - * @return void - */ - protected function checkLineLength(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $lineContent) - { - // If the content is a CVS or SVN id in a version tag, or it is - // a license tag with a name and URL, or it is an SVN URL, there - // is nothing the developer can do to shorten the line, - // so don't throw errors. - $regex = '~@license|@version[^\$]+\$Id|\$(Head)?URL[:\$]~'; - if (preg_match($regex, $lineContent) !== 0) { - return; - } - - if (PHP_CODESNIFFER_ENCODING !== 'iso-8859-1') { - // Not using the default encoding, so take a bit more care. - $lineLength = iconv_strlen($lineContent, PHP_CODESNIFFER_ENCODING); - if ($lineLength === false) { - // String contained invalid characters, so revert to default. - $lineLength = strlen($lineContent); - } - } else { - $lineLength = strlen($lineContent); - } - - if ($this->absoluteLineLimit > 0 - && $lineLength > $this->absoluteLineLimit - ) { - $data = array( - $this->absoluteLineLimit, - $lineLength, - ); - - $error = 'Line exceeds maximum limit of %s characters; contains %s characters'; - $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); - } else if ($lineLength > $this->lineLimit) { - $data = array( - $this->lineLimit, - $lineLength, - ); - - $warning = 'Line exceeds %s characters; contains %s characters'; - $phpcsFile->addWarning($warning, $stackPtr, 'TooLong', $data); - } - - }//end checkLineLength() - - -}//end class - diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php deleted file mode 100644 index 4ec0f75fa..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks that all file names are lowercased. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Andy Grunwald - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_LowercasedFilenameSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - $fileName = basename($phpcsFile->getFilename()); - $lowercaseFileName = strtolower($fileName); - if ($fileName !== $lowercaseFileName) { - $data = array( - $fileName, - $lowercaseFileName, - ); - $error = 'Filename "%s" doesn\'t match the expected filename "%s"'; - $phpcsFile->addError($error, $stackPtr, 'NotFound', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php deleted file mode 100644 index 9f3ccfe7c..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks that only one class is declared per file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Andy Grunwald - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_OneClassPerFileSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CLASS); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $nextClass = $phpcsFile->findNext($this->register(), ($stackPtr + 1)); - if ($nextClass !== false) { - $error = 'Only one class is allowed in a file'; - $phpcsFile->addError($error, $nextClass, 'MultipleFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php deleted file mode 100644 index dd151f1f1..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks that only one interface is declared per file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Andy Grunwald - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Files_OneInterfacePerFileSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_INTERFACE); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $nextInterface = $phpcsFile->findNext($this->register(), ($stackPtr + 1)); - if ($nextInterface !== false) { - $error = 'Only one interface is allowed in a file'; - $phpcsFile->addError($error, $nextInterface, 'MultipleFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php deleted file mode 100644 index f783abd3e..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff. - * - * Ensures each statement is on a line by itself. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_SEMICOLON); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prev = $phpcsFile->findPrevious(T_SEMICOLON, ($stackPtr - 1)); - if ($prev === false) { - return; - } - - // Ignore multiple statements in a FOR condition. - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - foreach ($tokens[$stackPtr]['nested_parenthesis'] as $bracket) { - if (isset($tokens[$bracket]['parenthesis_owner']) === false) { - // Probably a closure sitting inside a function call. - continue; - } - - $owner = $tokens[$bracket]['parenthesis_owner']; - if ($tokens[$owner]['code'] === T_FOR) { - return; - } - } - } - - if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { - $error = 'Each PHP statement must be on a line by itself'; - $phpcsFile->addError($error, $stackPtr, 'SameLine'); - return; - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php deleted file mode 100644 index a0b966c54..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php +++ /dev/null @@ -1,304 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff. - * - * Checks alignment of assignments. If there are multiple adjacent assignments, - * it will check that the equals signs of each assignment are aligned. It will - * display a warning to advise that the signs should be aligned. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = false; - - /** - * The maximum amount of padding before the alignment is ignored. - * - * If the amount of padding required to align this assignment with the - * surrounding assignments exceeds this number, the assignment will be - * ignored and no errors or warnings will be thrown. - * - * @var int - */ - public $maxPadding = 1000; - - /** - * If true, multi-line assignments are not checked. - * - * @var int - */ - public $ignoreMultiLine = false; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$assignmentTokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore assignments used in a condition, like an IF or FOR. - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - foreach ($tokens[$stackPtr]['nested_parenthesis'] as $start => $end) { - if (isset($tokens[$start]['parenthesis_owner']) === true) { - return; - } - } - } - - /* - By this stage, it is known that there is an assignment on this line. - We only want to process the block once we reach the last assignment, - so we need to determine if there are more to follow. - */ - - // The assignment may span over multiple lines, so look for the - // end of the assignment so we can check assignment blocks correctly. - $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - - $nextAssign = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$assignmentTokens, - ($lineEnd + 1) - ); - - if ($nextAssign !== false) { - $isAssign = true; - if ($tokens[$nextAssign]['line'] === ($tokens[$lineEnd]['line'] + 1)) { - // Assignment may be in the same block as this one. Just make sure - // it is not used in a condition, like an IF or FOR. - if (isset($tokens[$nextAssign]['nested_parenthesis']) === true) { - foreach ($tokens[$nextAssign]['nested_parenthesis'] as $start => $end) { - if (isset($tokens[$start]['parenthesis_owner']) === true) { - // Not an assignment. - $isAssign = false; - break; - } - } - } - - if ($isAssign === true) { - return; - } - } - } - - // Getting here means that this is the last in a block of statements. - $assignments = array(); - $assignments[] = $stackPtr; - $prevAssignment = $stackPtr; - $lastLine = $tokens[$stackPtr]['line']; - - while (($prevAssignment = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$assignmentTokens, ($prevAssignment - 1))) !== false) { - - // We are not interested in double arrows as they assign values inside - // arrays and loops and do not use the same indentation rules. - if ($tokens[$prevAssignment]['code'] === T_DOUBLE_ARROW) { - continue; - } - - // The assignment's end token must be on the line directly - // above the current one to be in the same assignment block. - $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($prevAssignment + 1)); - - // And the end token must actually belong to this assignment. - $nextOpener = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$scopeOpeners, - ($prevAssignment + 1) - ); - - if ($nextOpener !== false && $nextOpener < $lineEnd) { - break; - } - - if ($tokens[$lineEnd]['line'] !== ($lastLine - 1)) { - break; - } - - // Make sure it is not assigned inside a condition (eg. IF, FOR). - if (isset($tokens[$prevAssignment]['nested_parenthesis']) === true) { - foreach ($tokens[$prevAssignment]['nested_parenthesis'] as $start => $end) { - if (isset($tokens[$start]['parenthesis_owner']) === true) { - break(2); - } - } - } - - $assignments[] = $prevAssignment; - $lastLine = $tokens[$prevAssignment]['line']; - }//end while - - $assignmentData = array(); - $maxAssignmentLength = 0; - $maxVariableLength = 0; - - foreach ($assignments as $assignment) { - $prev = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($assignment - 1), - null, - true - ); - - $endColumn = $tokens[($prev + 1)]['column']; - - if ($maxVariableLength < $endColumn) { - $maxVariableLength = $endColumn; - } - - if ($maxAssignmentLength < strlen($tokens[$assignment]['content'])) { - $maxAssignmentLength = strlen($tokens[$assignment]['content']); - } - - $assignmentData[$assignment] - = array( - 'variable_length' => $endColumn, - 'assignment_length' => strlen($tokens[$assignment]['content']), - ); - }//end foreach - - foreach ($assignmentData as $assignment => $data) { - if ($data['assignment_length'] === $maxAssignmentLength) { - if ($data['variable_length'] === $maxVariableLength) { - // The assignment is the longest possible, so the column that - // everything has to align to is based on it. - $column = ($maxVariableLength + 1); - break; - } else { - // The assignment token is the longest out of all of the - // assignments, but the variable name is not, so the column - // the start at can go back more to cover the space - // between the variable name and the assignment operator. - $column = ($maxVariableLength - ($maxAssignmentLength - 1) + 1); - } - } - } - - // Determine the actual position that each equals sign should be in. - foreach ($assignments as $assignment) { - // Actual column takes into account the length of the assignment operator. - $actualColumn = ($column + $maxAssignmentLength - strlen($tokens[$assignment]['content'])); - if ($tokens[$assignment]['column'] !== $actualColumn) { - $prev = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($assignment - 1), - null, - true - ); - - $expected = ($actualColumn - $tokens[($prev + 1)]['column']); - - if ($tokens[$assignment]['line'] !== $tokens[$prev]['line']) { - // Instead of working out how many spaces there are - // across new lines, the error message becomes more - // generic below. - $found = null; - } else { - $found = ($tokens[$assignment]['column'] - $tokens[($prev + 1)]['column']); - } - - // If the expected number of spaces for alignment exceeds the - // maxPadding rule, we just check for a single space as no - // alignment is required. - if ($expected > $this->maxPadding) { - if ($found === 1) { - continue; - } else { - $expected = 1; - } - } - - // Skip multi-line assignments if required. - if ($found === null && $this->ignoreMultiLine === true) { - continue; - } - - $expected .= ($expected === 1) ? ' space' : ' spaces'; - if ($found === null) { - $found = 'a new line'; - } else { - $found .= ($found === 1) ? ' space' : ' spaces'; - } - - if (count($assignments) === 1) { - $type = 'Incorrect'; - $error = 'Equals sign not aligned correctly; expected %s but found %s'; - } else { - $type = 'NotSame'; - $error = 'Equals sign not aligned with surrounding assignments; expected %s but found %s'; - } - - $errorData = array( - $expected, - $found, - ); - - if ($this->error === true) { - $phpcsFile->addError($error, $assignment, $type, $errorData); - } else { - $phpcsFile->addWarning($error, $assignment, $type.'Warning', $errorData); - } - }//end if - }//end foreach - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php deleted file mode 100644 index 0feb273e3..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Formatting_NoSpaceAfterCastSniff. - * - * Ensures there is no space after cast tokens. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Formatting_NoSpaceAfterCastSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$castTokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { - $error = 'A cast statement must not be followed by a space'; - $phpcsFile->addError($error, $stackPtr, 'SpaceFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php deleted file mode 100644 index d8b37a817..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Formatting_SpaceAfterCastSniff. - * - * Ensures there is a single space after cast tokens. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Formatting_SpaceAfterCastSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$castTokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $error = 'A cast statement must be followed by a single space'; - $phpcsFile->addError($error, $stackPtr, 'NoSpace'); - return; - } - - if ($tokens[($stackPtr + 1)]['content'] !== ' ') { - $error = 'A cast statement must be followed by a single space'; - $phpcsFile->addError($error, $stackPtr, 'TooMuchSpace'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php deleted file mode 100644 index 72aeb5380..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php +++ /dev/null @@ -1,151 +0,0 @@ - - * @copyright 2009 Florian Grandel - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Functions_CallTimePassByReferenceSniff. - * - * Ensures that variables are not passed by reference when calling a function. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Florian Grandel - * @copyright 2009 Florian Grandel - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Functions_CallTimePassByReferenceSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_STRING, - T_VARIABLE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Skip tokens that are the names of functions or classes - // within their definitions. For example: function myFunction... - // "myFunction" is T_STRING but we should skip because it is not a - // function or method *call*. - $functionName = $stackPtr; - $findTokens = array_merge( - PHP_CodeSniffer_Tokens::$emptyTokens, - array(T_BITWISE_AND) - ); - - $functionKeyword = $phpcsFile->findPrevious( - $findTokens, - ($stackPtr - 1), - null, - true - ); - - if ($tokens[$functionKeyword]['code'] === T_FUNCTION - || $tokens[$functionKeyword]['code'] === T_CLASS - ) { - return; - } - - // If the next non-whitespace token after the function or method call - // is not an opening parenthesis then it cant really be a *call*. - $openBracket = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($functionName + 1), - null, - true - ); - - if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { - return; - } - - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - - $nextSeparator = $openBracket; - while (($nextSeparator = $phpcsFile->findNext(T_VARIABLE, ($nextSeparator + 1), $closeBracket)) !== false) { - // Make sure the variable belongs directly to this function call - // and is not inside a nested function call or array. - $brackets = $tokens[$nextSeparator]['nested_parenthesis']; - $lastBracket = array_pop($brackets); - if ($lastBracket !== $closeBracket) { - continue; - } - - // Checking this: $value = my_function(...[*]$arg...). - $tokenBefore = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($nextSeparator - 1), - null, - true - ); - - if ($tokens[$tokenBefore]['code'] === T_BITWISE_AND) { - // Checking this: $value = my_function(...[*]&$arg...). - $tokenBefore = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($tokenBefore - 1), - null, - true - ); - - // We have to exclude all uses of T_BITWISE_AND that are not - // references. We use a blacklist approach as we prefer false - // positives to not identifying a pass-by-reference call at all. - // The blacklist may not yet be complete. - switch ($tokens[$tokenBefore]['code']) { - case T_VARIABLE: - case T_CLOSE_PARENTHESIS: - case T_LNUMBER: - // In these cases T_BITWISE_AND represents - // the bitwise and operator. - continue; - - default: - // T_BITWISE_AND represents a pass-by-reference. - $error = 'Call-time pass-by-reference calls are prohibited'; - $phpcsFile->addError($error, $tokenBefore, 'NotAllowed'); - break; - } - }//end if - }//end while - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php deleted file mode 100644 index 03618bec9..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php +++ /dev/null @@ -1,141 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff. - * - * Checks that calls to methods and functions are spaced correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Skip tokens that are the names of functions or classes - // within their definitions. For example: - // function myFunction... - // "myFunction" is T_STRING but we should skip because it is not a - // function or method *call*. - $functionName = $stackPtr; - $ignoreTokens = PHP_CodeSniffer_Tokens::$emptyTokens; - $ignoreTokens[] = T_BITWISE_AND; - $functionKeyword = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true); - if ($tokens[$functionKeyword]['code'] === T_FUNCTION || $tokens[$functionKeyword]['code'] === T_CLASS) { - return; - } - - // If the next non-whitespace token after the function or method call - // is not an opening parenthesis then it cant really be a *call*. - $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($functionName + 1), null, true); - if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { - return; - } - - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - - $nextSeparator = $openBracket; - while (($nextSeparator = $phpcsFile->findNext(array(T_COMMA, T_VARIABLE, T_CLOSURE), ($nextSeparator + 1), $closeBracket)) !== false) { - if ($tokens[$nextSeparator]['code'] === T_CLOSURE) { - $nextSeparator = $tokens[$nextSeparator]['scope_closer']; - continue; - } - - // Make sure the comma or variable belongs directly to this function call, - // and is not inside a nested function call or array. - $brackets = $tokens[$nextSeparator]['nested_parenthesis']; - $lastBracket = array_pop($brackets); - if ($lastBracket !== $closeBracket) { - continue; - } - - if ($tokens[$nextSeparator]['code'] === T_COMMA) { - if ($tokens[($nextSeparator - 1)]['code'] === T_WHITESPACE) { - $error = 'Space found before comma in function call'; - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeComma'); - } - - if ($tokens[($nextSeparator + 1)]['code'] !== T_WHITESPACE) { - $error = 'No space found after comma in function call'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterComma'); - } else { - // If there is a newline in the space, then the must be formatting - // each argument on a newline, which is valid, so ignore it. - if (strpos($tokens[($nextSeparator + 1)]['content'], $phpcsFile->eolChar) === false) { - $space = strlen($tokens[($nextSeparator + 1)]['content']); - if ($space > 1) { - $error = 'Expected 1 space after comma in function call; %s found'; - $data = array($space); - $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceAfterComma', $data); - } - } - } - } else { - // Token is a variable. - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextSeparator + 1), $closeBracket, true); - if ($nextToken !== false) { - if ($tokens[$nextToken]['code'] === T_EQUAL) { - if (($tokens[($nextToken - 1)]['code']) !== T_WHITESPACE) { - $error = 'Expected 1 space before = sign of default value'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeEquals'); - } - - if ($tokens[($nextToken + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after = sign of default value'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterEquals'); - } - } - } - }//end if - }//end while - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php deleted file mode 100644 index f2df820a2..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php +++ /dev/null @@ -1,121 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff. - * - * Checks that the opening brace of a function is on the line after the - * function declaration. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return void - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - $openingBrace = $tokens[$stackPtr]['scope_opener']; - - // The end of the function occurs at the end of the argument list. Its - // like this because some people like to break long function declarations - // over multiple lines. - $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; - $braceLine = $tokens[$openingBrace]['line']; - - $lineDifference = ($braceLine - $functionLine); - - if ($lineDifference === 0) { - $error = 'Opening brace should be on a new line'; - $phpcsFile->addError($error, $openingBrace, 'BraceOnSameLine'); - return; - } - - if ($lineDifference > 1) { - $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; - $data = array(($lineDifference - 1)); - $phpcsFile->addError($error, $openingBrace, 'BraceSpacing', $data); - return; - } - - // We need to actually find the first piece of content on this line, - // as if this is a method with tokens before it (public, static etc) - // or an if with an else before it, then we need to start the scope - // checking from there, rather than the current token. - $lineStart = $stackPtr; - while (($lineStart = $phpcsFile->findPrevious(array(T_WHITESPACE), ($lineStart - 1), null, false)) !== false) { - if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { - break; - } - } - - // We found a new line, now go forward and find the first non-whitespace - // token. - $lineStart = $phpcsFile->findNext(array(T_WHITESPACE), $lineStart, null, true); - - // The opening brace is on the correct line, now it needs to be - // checked to be correctly indented. - $startColumn = $tokens[$lineStart]['column']; - $braceIndent = $tokens[$openingBrace]['column']; - - if ($braceIndent !== $startColumn) { - $error = 'Opening brace indented incorrectly; expected %s spaces, found %s'; - $data = array( - ($startColumn - 1), - ($braceIndent - 1), - ); - $phpcsFile->addError($error, $openingBrace, 'BraceIndent', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php deleted file mode 100644 index 5647a44f3..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff. - * - * Checks that the opening brace of a function is on the same line - * as the function declaration. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the tokens that this sniff wants to listen for. - * - * @return void - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - $openingBrace = $tokens[$stackPtr]['scope_opener']; - - // The end of the function occurs at the end of the argument list. Its - // like this because some people like to break long function declarations - // over multiple lines. - $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; - $braceLine = $tokens[$openingBrace]['line']; - - $lineDifference = ($braceLine - $functionLine); - - if ($lineDifference > 0) { - $error = 'Opening brace should be on the same line as the declaration'; - $phpcsFile->addError($error, $openingBrace, 'BraceOnNewLine'); - return; - } - - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[($closeBracket + 1)]['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($tokens[($closeBracket + 1)]['content'] === "\t") { - $length = '\t'; - } else { - $length = strlen($tokens[($closeBracket + 1)]['content']); - } - - if ($length !== 1) { - $error = 'Expected 1 space after closing parenthesis; found %s'; - $data = array($length); - $phpcsFile->addError($error, $closeBracket, 'SpaceAfterBracket', $data); - return; - } - - $closeBrace = $tokens[$stackPtr]['scope_opener']; - if ($tokens[($closeBrace - 1)]['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($tokens[($closeBrace - 1)]['content'] === "\t") { - $length = '\t'; - } else { - $length = strlen($tokens[($closeBrace - 1)]['content']); - } - - if ($length !== 1) { - $error = 'Expected 1 space before opening brace; found %s'; - $data = array($length); - $phpcsFile->addError($error, $openingBrace, 'SpaceBeforeBrace', $data); - return; - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php deleted file mode 100644 index 69c60e20a..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks the cyclomatic complexity (McCabe) for functions. - * - * The cyclomatic complexity (also called McCabe code metrics) - * indicates the complexity within a function by counting - * the different paths the function includes. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Johann-Peter Hartmann - * @author Greg Sherwood - * @copyright 2007 Mayflower GmbH - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Metrics_CyclomaticComplexitySniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A complexity higher than this value will throw a warning. - * - * @var int - */ - public $complexity = 10; - - /** - * A complexity higer than this value will throw an error. - * - * @var int - */ - public $absoluteComplexity = 20; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - $tokens = $phpcsFile->getTokens(); - - // Ignore abstract methods. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - // Detect start and end of this function definition. - $start = $tokens[$stackPtr]['scope_opener']; - $end = $tokens[$stackPtr]['scope_closer']; - - // Predicate nodes for PHP. - $find = array( - 'T_CASE', - 'T_DEFAULT', - 'T_CATCH', - 'T_IF', - 'T_FOR', - 'T_FOREACH', - 'T_WHILE', - 'T_DO', - 'T_ELSEIF', - ); - - $complexity = 1; - - // Iterate from start to end and count predicate nodes. - for ($i = ($start + 1); $i < $end; $i++) { - if (in_array($tokens[$i]['type'], $find) === true) { - $complexity++; - } - } - - if ($complexity > $this->absoluteComplexity) { - $error = 'Function\'s cyclomatic complexity (%s) exceeds allowed maximum of %s'; - $data = array( - $complexity, - $this->absoluteComplexity, - ); - $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); - } else if ($complexity > $this->complexity) { - $warning = 'Function\'s cyclomatic complexity (%s) exceeds %s; consider refactoring the function'; - $data = array( - $complexity, - $this->complexity, - ); - $phpcsFile->addWarning($warning, $stackPtr, 'TooHigh', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php deleted file mode 100644 index 2b95d8e5b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks the nesting level for methods. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Johann-Peter Hartmann - * @author Greg Sherwood - * @copyright 2007 Mayflower GmbH - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Metrics_NestingLevelSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A nesting level than this value will throw a warning. - * - * @var int - */ - public $nestingLevel = 5; - - /** - * A nesting level than this value will throw an error. - * - * @var int - */ - public $absoluteNestingLevel = 10; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore abstract methods. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - // Detect start and end of this function definition. - $start = $tokens[$stackPtr]['scope_opener']; - $end = $tokens[$stackPtr]['scope_closer']; - - $nestingLevel = 0; - - // Find the maximum nesting level of any token in the function. - for ($i = ($start + 1); $i < $end; $i++) { - $level = $tokens[$i]['level']; - if ($nestingLevel < $level) { - $nestingLevel = $level; - } - } - - // We subtract the nesting level of the function itself. - $nestingLevel = ($nestingLevel - $tokens[$stackPtr]['level'] - 1); - - if ($nestingLevel > $this->absoluteNestingLevel) { - $error = 'Function\'s nesting level (%s) exceeds allowed maximum of %s'; - $data = array( - $nestingLevel, - $this->absoluteNestingLevel, - ); - $phpcsFile->addError($error, $stackPtr, 'MaxExceeded', $data); - } else if ($nestingLevel > $this->nestingLevel) { - $warning = 'Function\'s nesting level (%s) exceeds %s; consider refactoring the function'; - $data = array( - $nestingLevel, - $this->nestingLevel, - ); - $phpcsFile->addWarning($warning, $stackPtr, 'TooHigh', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php deleted file mode 100644 index d6a5eab1f..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php +++ /dev/null @@ -1,210 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff. - * - * Ensures method names are correct depending on whether they are public - * or private, and that functions are named correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - /** - * A list of all PHP magic methods. - * - * @var array - */ - protected $magicMethods = array( - 'construct', - 'destruct', - 'call', - 'callstatic', - 'get', - 'set', - 'isset', - 'unset', - 'sleep', - 'wakeup', - 'tostring', - 'set_state', - 'clone', - 'invoke', - 'call', - ); - - /** - * A list of all PHP non-magic methods starting with a double underscore. - * - * These come from PHP modules such as SOAPClient. - * - * @var array - */ - protected $methodsDoubleUnderscore = array( - 'soapcall', - 'getlastrequest', - 'getlastresponse', - 'getlastrequestheaders', - 'getlastresponseheaders', - 'getfunctions', - 'gettypes', - 'dorequest', - 'setcookie', - 'setlocation', - 'setsoapheaders', - ); - - /** - * A list of all PHP magic functions. - * - * @var array - */ - protected $magicFunctions = array('autoload'); - - /** - * If TRUE, the string must not have two capital letters next to each other. - * - * @var bool - */ - public $strict = true; - - - /** - * Constructs a Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); - - }//end __construct() - - - /** - * Processes the tokens within the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * @param int $currScope The position of the current scope. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $methodName = $phpcsFile->getDeclarationName($stackPtr); - if ($methodName === null) { - // Ignore closures. - return; - } - - $className = $phpcsFile->getDeclarationName($currScope); - $errorData = array($className.'::'.$methodName); - - // Is this a magic method. i.e., is prefixed with "__" ? - if (preg_match('|^__|', $methodName) !== 0) { - $magicPart = strtolower(substr($methodName, 2)); - if (in_array($magicPart, array_merge($this->magicMethods, $this->methodsDoubleUnderscore)) === false) { - $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; - $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData); - } - - return; - } - - // PHP4 constructors are allowed to break our rules. - if ($methodName === $className) { - return; - } - - // PHP4 destructors are allowed to break our rules. - if ($methodName === '_'.$className) { - return; - } - - $methodProps = $phpcsFile->getMethodProperties($stackPtr); - if (PHP_CodeSniffer::isCamelCaps($methodName, false, true, $this->strict) === false) { - if ($methodProps['scope_specified'] === true) { - $error = '%s method name "%s" is not in camel caps format'; - $data = array( - ucfirst($methodProps['scope']), - $errorData[0], - ); - $phpcsFile->addError($error, $stackPtr, 'ScopeNotCamelCaps', $data); - } else { - $error = 'Method name "%s" is not in camel caps format'; - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); - } - - return; - } - - }//end processTokenWithinScope() - - - /** - * Processes the tokens outside the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * - * @return void - */ - protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $functionName = $phpcsFile->getDeclarationName($stackPtr); - if ($functionName === null) { - // Ignore closures. - return; - } - - $errorData = array($functionName); - - // Is this a magic function. i.e., it is prefixed with "__". - if (preg_match('|^__|', $functionName) !== 0) { - $magicPart = strtolower(substr($functionName, 2)); - if (in_array($magicPart, $this->magicFunctions) === false) { - $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; - $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); - } - - return; - } - - if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, $this->strict) === false) { - $error = 'Function name "%s" is not in camel caps format'; - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); - } - - - }//end processTokenOutsideScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php deleted file mode 100644 index 75109dabe..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php +++ /dev/null @@ -1,106 +0,0 @@ - - * @author Leif Wickland - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Generic_Sniffs_NamingConventions_ConstructorNameSniff. - * - * Favor PHP 5 constructor syntax, which uses "function __construct()". - * Avoid PHP 4 constructor syntax, which uses "function ClassName()". - * - * @category PHP - * @package PHP_CodeSniffer - * @author Leif Wickland - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_NamingConventions_ConstructorNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs the test with the tokens it wishes to listen for. - * - * @return void - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true); - - }//end __construct() - - - /** - * Processes this test when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param int $currScope A pointer to the start of the scope. - * - * @return void - */ - protected function processTokenWithinScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $currScope - ) { - $className = $phpcsFile->getDeclarationName($currScope); - $methodName = $phpcsFile->getDeclarationName($stackPtr); - - if (strcasecmp($methodName, $className) === 0) { - $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; - $phpcsFile->addError($error, $stackPtr, 'OldStyle'); - } else if (strcasecmp($methodName, '__construct') !== 0) { - // Not a constructor. - return; - } - - $tokens = $phpcsFile->getTokens(); - - $parentClassName = $phpcsFile->findExtendedClassName($currScope); - if ($parentClassName === false) { - return; - } - - // Stop if the constructor doesn't have a body, like when it is abstract. - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - return; - } - - $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; - $startIndex = $stackPtr; - while ($doubleColonIndex = $phpcsFile->findNext(array(T_DOUBLE_COLON), $startIndex, $endFunctionIndex)) { - if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING - && $tokens[($doubleColonIndex + 1)]['content'] === $parentClassName - ) { - $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; - $phpcsFile->addError($error, ($doubleColonIndex + 1), 'OldStyleCall'); - } - - $startIndex = ($doubleColonIndex + 1); - } - - }//end processTokenWithinScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php deleted file mode 100644 index 1cfac4fc0..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ /dev/null @@ -1,247 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff. - * - * Ensures that constant names are all uppercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $constName = $tokens[$stackPtr]['content']; - - // If this token is in a heredoc, ignore it. - if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { - return; - } - - // Special case for PHP 5.5 class name resolution. - if (strtolower($constName) === 'class' - && $tokens[($stackPtr - 1)]['code'] === T_DOUBLE_COLON - ) { - return; - } - - // Special case for PHPUnit. - if ($constName === 'PHPUnit_MAIN_METHOD') { - return; - } - - // If the next non-whitespace token after this token - // is not an opening parenthesis then it is not a function call. - $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { - $functionKeyword = $phpcsFile->findPrevious( - array( - T_WHITESPACE, - T_COMMA, - T_COMMENT, - T_STRING, - T_NS_SEPARATOR, - ), - ($stackPtr - 1), - null, - true - ); - - $declarations = array( - T_FUNCTION, - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_IMPLEMENTS, - T_EXTENDS, - T_INSTANCEOF, - T_NEW, - T_NAMESPACE, - T_USE, - T_AS, - T_GOTO, - T_INSTEADOF, - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - ); - - if (in_array($tokens[$functionKeyword]['code'], $declarations) === true) { - // This is just a declaration; no constants here. - return; - } - - if ($tokens[$functionKeyword]['code'] === T_CONST) { - // This is a class constant. - if (strtoupper($constName) !== $constName) { - $error = 'Class constants must be uppercase; expected %s but found %s'; - $data = array( - strtoupper($constName), - $constName, - ); - $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data); - } - - return; - } - - // Is this a class name? - $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$nextPtr]['code'] === T_DOUBLE_COLON) { - return; - } - - // Is this a namespace name? - if ($tokens[$nextPtr]['code'] === T_NS_SEPARATOR) { - return; - } - - // Is this an insteadof name? - if ($tokens[$nextPtr]['code'] === T_INSTEADOF) { - return; - } - - // Is this an as name? - if ($tokens[$nextPtr]['code'] === T_AS) { - return; - } - - // Is this a type hint? - if ($tokens[$nextPtr]['code'] === T_VARIABLE - || $phpcsFile->isReference($nextPtr) === true - ) { - return; - } - - // Is this a member var name? - $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { - return; - } - - // Is this a variable name, in the form ${varname} ? - if ($tokens[$prevPtr]['code'] === T_OPEN_CURLY_BRACKET) { - $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$nextPtr]['code'] === T_CLOSE_CURLY_BRACKET) { - return; - } - } - - // Is this a namespace name? - if ($tokens[$prevPtr]['code'] === T_NS_SEPARATOR) { - return; - } - - // Is this an instance of declare() - $prevPtrDeclare = $phpcsFile->findPrevious(array(T_WHITESPACE, T_OPEN_PARENTHESIS), ($stackPtr - 1), null, true); - if ($tokens[$prevPtrDeclare]['code'] === T_DECLARE) { - return; - } - - // Is this a goto label target? - if ($tokens[$nextPtr]['code'] === T_COLON) { - if (in_array($tokens[$prevPtr]['code'], array(T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_COLON), true)) { - return; - } - } - - // This is a real constant. - if (strtoupper($constName) !== $constName) { - $error = 'Constants must be uppercase; expected %s but found %s'; - $data = array( - strtoupper($constName), - $constName, - ); - $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); - } - - } else if (strtolower($constName) === 'define' || strtolower($constName) === 'constant') { - - /* - This may be a "define" or "constant" function call. - */ - - // Make sure this is not a method call. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR - || $tokens[$prev]['code'] === T_DOUBLE_COLON - ) { - return; - } - - // The next non-whitespace token must be the constant name. - $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); - if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { - return; - } - - $constName = $tokens[$constPtr]['content']; - - // Check for constants like self::CONSTANT. - $prefix = ''; - $splitPos = strpos($constName, '::'); - if ($splitPos !== false) { - $prefix = substr($constName, 0, ($splitPos + 2)); - $constName = substr($constName, ($splitPos + 2)); - } - - if (strtoupper($constName) !== $constName) { - $error = 'Constants must be uppercase; expected %s but found %s'; - $data = array( - $prefix.strtoupper($constName), - $prefix.$constName, - ); - $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); - } - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php deleted file mode 100644 index a6873183b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks that the opening PHP tag is the first content in a file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Andy Grunwald - * @copyright 2010 Andy Grunwald - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - if ($stackPtr > 0) { - $error = 'The opening PHP tag must be the first content in the file'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php deleted file mode 100644 index d49b5c24a..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @copyright 2010 Stefano Kowalke - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Checks that open PHP tags are paired with closing tags. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Stefano Kowalke - * @copyright 2010 Stefano Kowalke - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_ClosingPHPTagSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $closeTag = $phpcsFile->findNext(T_CLOSE_TAG, $stackPtr); - if ($closeTag === false) { - $error = 'The PHP open tag does not have a corresponding PHP close tag'; - $phpcsFile->addError($error, $stackPtr, 'NotFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php deleted file mode 100644 index 04b19ba73..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php +++ /dev/null @@ -1,94 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_DeprecatedFunctionsSniff. - * - * Discourages the use of deprecated functions that are kept in PHP for - * compatibility with older versions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sebastian Bergmann - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_DeprecatedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff -{ - - /** - * A list of forbidden functions with their alternatives. - * - * The value is NULL if no alternative exists. IE, the - * function should just not be used. - * - * @var array(string => string|null) - */ - protected $forbiddenFunctions = array(); - - - /** - * Constructor. - * - * Uses the Reflection API to get a list of deprecated functions. - */ - public function __construct() - { - $functions = get_defined_functions(); - - foreach ($functions['internal'] as $functionName) { - $function = new ReflectionFunction($functionName); - - if ($function->isDeprecated() === true) { - $this->forbiddenFunctions[$functionName] = null; - } - } - - }//end __construct() - - - /** - * Generates the error or warning for this sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the forbidden function - * in the token array. - * @param string $function The name of the forbidden function. - * @param string $pattern The pattern used for the match. - * - * @return void - */ - protected function addError($phpcsFile, $stackPtr, $function, $pattern=null) - { - $data = array($function); - $error = 'Function %s() has been deprecated'; - $type = 'Deprecated'; - - if ($this->error === true) { - $phpcsFile->addError($error, $stackPtr, $type, $data); - } else { - $phpcsFile->addWarning($error, $stackPtr, $type, $data); - } - - }//end addError() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php deleted file mode 100644 index 6121a670b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_DisallowShortOpenTagSniff. - * - * Makes sure that shorthand PHP open tags are not used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_DisallowShortOpenTagSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_OPEN_TAG, - T_OPEN_TAG_WITH_ECHO, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $openTag = $tokens[$stackPtr]; - - if ($openTag['content'] === 'addError($error, $stackPtr, 'Found', $data); - } - - if ($openTag['code'] === T_OPEN_TAG_WITH_ECHO) { - $nextVar = $tokens[$phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true)]; - $error = 'Short PHP opening tag used with echo; expected "addError($error, $stackPtr, 'EchoFound', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php deleted file mode 100644 index 82ff8502f..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php +++ /dev/null @@ -1,202 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_ForbiddenFunctionsSniff. - * - * Discourages the use of alias functions that are kept in PHP for compatibility - * with older versions. Can be used to forbid the use of any function. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_ForbiddenFunctionsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of forbidden functions with their alternatives. - * - * The value is NULL if no alternative exists. IE, the - * function should just not be used. - * - * @var array(string => string|null) - */ - protected $forbiddenFunctions = array( - 'sizeof' => 'count', - 'delete' => 'unset', - ); - - /** - * A cache of forbidden function names, for faster lookups. - * - * @var array(string) - */ - protected $forbiddenFunctionNames = array(); - - /** - * If true, forbidden functions will be considered regular expressions. - * - * @var bool - */ - protected $patternMatch = false; - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = true; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - // Everyone has had a chance to figure out what forbidden functions - // they want to check for, so now we can cache out the list. - $this->forbiddenFunctionNames = array_keys($this->forbiddenFunctions); - - if ($this->patternMatch === true) { - foreach ($this->forbiddenFunctionNames as $i => $name) { - $this->forbiddenFunctionNames[$i] = '/'.$name.'/i'; - } - } - - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $ignore = array( - T_DOUBLE_COLON, - T_OBJECT_OPERATOR, - T_FUNCTION, - T_CONST, - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_AS, - T_INSTEADOF, - ); - - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if (in_array($tokens[$prevToken]['code'], $ignore) === true) { - // Not a call to a PHP function. - return; - } - - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if (in_array($tokens[$nextToken]['code'], $ignore) === true) { - // Not a call to a PHP function. - return; - } - - $function = strtolower($tokens[$stackPtr]['content']); - $pattern = null; - - if ($this->patternMatch === true) { - $count = 0; - $pattern = preg_replace( - $this->forbiddenFunctionNames, - $this->forbiddenFunctionNames, - $function, - 1, - $count - ); - - if ($count === 0) { - return; - } - - // Remove the pattern delimiters and modifier. - $pattern = substr($pattern, 1, -2); - } else { - if (in_array($function, $this->forbiddenFunctionNames) === false) { - return; - } - } - - $this->addError($phpcsFile, $stackPtr, $function, $pattern); - - }//end process() - - - /** - * Generates the error or warning for this sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the forbidden function - * in the token array. - * @param string $function The name of the forbidden function. - * @param string $pattern The pattern used for the match. - * - * @return void - */ - protected function addError($phpcsFile, $stackPtr, $function, $pattern=null) - { - $data = array($function); - $error = 'The use of function %s() is '; - if ($this->error === true) { - $type = 'Found'; - $error .= 'forbidden'; - } else { - $type = 'Discouraged'; - $error .= 'discouraged'; - } - - if ($pattern === null) { - $pattern = $function; - } - - if ($this->forbiddenFunctions[$pattern] !== null) { - $type .= 'WithAlternative'; - $data[] = $this->forbiddenFunctions[$pattern]; - $error .= '; use %s() instead'; - } - - if ($this->error === true) { - $phpcsFile->addError($error, $stackPtr, $type, $data); - } else { - $phpcsFile->addWarning($error, $stackPtr, $type, $data); - } - - }//end addError() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php deleted file mode 100644 index 783607268..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_LowerCaseConstantSniff. - * - * Checks that all uses of true, false and null are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_LowerCaseConstantSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_TRUE, - T_FALSE, - T_NULL, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Is this a member var name? - $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { - return; - } - - // Is this a class name? - if ($tokens[$prevPtr]['code'] === T_CLASS - || $tokens[$prevPtr]['code'] === T_EXTENDS - || $tokens[$prevPtr]['code'] === T_IMPLEMENTS - || $tokens[$prevPtr]['code'] === T_NEW - ) { - return; - } - - // Class or namespace? - if ($tokens[($stackPtr - 1)]['code'] === T_NS_SEPARATOR) { - return; - } - - $keyword = $tokens[$stackPtr]['content']; - if (strtolower($keyword) !== $keyword) { - $error = 'TRUE, FALSE and NULL must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtolower($keyword), - $keyword, - ); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php deleted file mode 100644 index 13083ce36..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php +++ /dev/null @@ -1,137 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_LowerCaseKeywordSniff. - * - * Checks that all PHP keywords are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_LowerCaseKeywordSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_HALT_COMPILER, - T_ABSTRACT, - T_ARRAY, - T_AS, - T_BREAK, - T_CALLABLE, - T_CASE, - T_CATCH, - T_CLASS, - T_CLONE, - T_CONST, - T_CONTINUE, - T_DECLARE, - T_DEFAULT, - T_DO, - T_ECHO, - T_ELSE, - T_ELSEIF, - T_EMPTY, - T_ENDDECLARE, - T_ENDFOR, - T_ENDFOREACH, - T_ENDIF, - T_ENDSWITCH, - T_ENDWHILE, - T_EVAL, - T_EXIT, - T_EXTENDS, - T_FINAL, - T_FINALLY, - T_FOR, - T_FOREACH, - T_FUNCTION, - T_GLOBAL, - T_GOTO, - T_IF, - T_IMPLEMENTS, - T_INCLUDE, - T_INCLUDE_ONCE, - T_INSTANCEOF, - T_INSTEADOF, - T_INTERFACE, - T_ISSET, - T_LIST, - T_LOGICAL_AND, - T_LOGICAL_OR, - T_LOGICAL_XOR, - T_NAMESPACE, - T_NEW, - T_PRINT, - T_PRIVATE, - T_PROTECTED, - T_PUBLIC, - T_REQUIRE, - T_REQUIRE_ONCE, - T_RETURN, - T_STATIC, - T_SWITCH, - T_THROW, - T_TRAIT, - T_TRY, - T_UNSET, - T_USE, - T_VAR, - T_WHILE, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $keyword = $tokens[$stackPtr]['content']; - if (strtolower($keyword) !== $keyword) { - $error = 'PHP keywords must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtolower($keyword), - $keyword, - ); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php deleted file mode 100644 index e26ad553b..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_NoSilencedErrorsSniff. - * - * Throws an error or warning when any code prefixed with an asperand is encountered. - * - * - * if (@in_array($array, $needle)) - * { - * doSomething(); - * } - * - * - * @category PHP - * @package PHP_CodeSniffer - * @author Andy Brockhurst - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_NoSilencedErrorsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = false; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_ASPERAND); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $error = 'Silencing errors is forbidden'; - if ($this->error === true) { - $error = 'Silencing errors is forbidden'; - $phpcsFile->addError($error, $stackPtr, 'Forbidden'); - } else { - $error = 'Silencing errors is discouraged'; - $phpcsFile->addWarning($error, $stackPtr, 'Discouraged'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php deleted file mode 100644 index 1a5b338ad..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_SAPIUsageSniff. - * - * Ensures the PHP_SAPI constant is used instead of php_sapi_name(). - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_SAPIUsageSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $ignore = array( - T_DOUBLE_COLON, - T_OBJECT_OPERATOR, - T_FUNCTION, - T_CONST, - ); - - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if (in_array($tokens[$prevToken]['code'], $ignore) === true) { - // Not a call to a PHP function. - return; - } - - $function = strtolower($tokens[$stackPtr]['content']); - if ($function === 'php_sapi_name') { - $error = 'Use the PHP_SAPI constant instead of calling php_sapi_name()'; - $phpcsFile->addError($error, $stackPtr, 'FunctionFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php deleted file mode 100644 index 7adffffc9..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_PHP_UpperCaseConstantSniff. - * - * Checks that all uses of TRUE, FALSE and NULL are uppercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_PHP_UpperCaseConstantSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_TRUE, - T_FALSE, - T_NULL, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Is this a member var name? - $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { - return; - } - - // Is this a class name? - if ($tokens[$prevPtr]['code'] === T_CLASS - || $tokens[$prevPtr]['code'] === T_EXTENDS - || $tokens[$prevPtr]['code'] === T_IMPLEMENTS - || $tokens[$prevPtr]['code'] === T_NEW - ) { - return; - } - - // Class or namespace? - if ($tokens[($stackPtr - 1)]['code'] === T_NS_SEPARATOR) { - return; - } - - $keyword = $tokens[$stackPtr]['content']; - if (strtoupper($keyword) !== $keyword) { - $error = 'TRUE, FALSE and NULL must be uppercase; expected "%s" but found "%s"'; - $data = array( - strtoupper($keyword), - $keyword, - ); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php deleted file mode 100644 index 8033c1719..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php +++ /dev/null @@ -1,125 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Strings_UnnecessaryStringConcatSniff. - * - * Checks that two strings are not concatenated together; suggests - * using one string instead. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_Strings_UnnecessaryStringConcatSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = true; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_STRING_CONCAT, - T_PLUS, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // Work out which type of file this is for. - $tokens = $phpcsFile->getTokens(); - if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT) { - if ($phpcsFile->tokenizerType === 'JS') { - return; - } - } else { - if ($phpcsFile->tokenizerType === 'PHP') { - return; - } - } - - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($prev === false || $next === false) { - return; - } - - $stringTokens = PHP_CodeSniffer_Tokens::$stringTokens; - if (in_array($tokens[$prev]['code'], $stringTokens) === true - && in_array($tokens[$next]['code'], $stringTokens) === true - ) { - if ($tokens[$prev]['content'][0] === $tokens[$next]['content'][0]) { - // Before we throw an error for PHP, allow strings to be - // combined if they would have < and ? next to each other because - // this trick is sometimes required in PHP strings. - if ($phpcsFile->tokenizerType === 'PHP') { - $prevChar = substr($tokens[$prev]['content'], -2, 1); - $nextChar = $tokens[$next]['content'][1]; - $combined = $prevChar.$nextChar; - if ($combined === '?'.'>' || $combined === '<'.'?') { - return; - } - } - - $error = 'String concat is not required here; use a single string instead'; - if ($this->error === true) { - $phpcsFile->addError($error, $stackPtr, 'Found'); - } else { - $phpcsFile->addWarning($error, $stackPtr, 'Found'); - } - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php deleted file mode 100644 index 6878f7f2f..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php +++ /dev/null @@ -1,206 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_VersionControl_SubversionPropertiesSniff. - * - * Tests that the correct Subversion properties are set. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Jack Bates - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_VersionControl_SubversionPropertiesSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The Subversion properties that should be set. - * - * Key of array is the SVN property and the value is the - * exact value the property should have or NULL if the - * property should just be set but the value is not fixed. - * - * @var array - */ - protected $properties = array( - 'svn:keywords' => 'Author Id Revision', - 'svn:eol-style' => 'native', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is the first PHP open tag so we don't process the - // same file twice. - $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($prevOpenTag !== false) { - return; - } - - $path = $phpcsFile->getFileName(); - $properties = $this->getProperties($path); - if ($properties === null) { - // Not under version control. - return; - } - - $allProperties = $properties + $this->properties; - foreach ($allProperties as $key => $value) { - if (isset($properties[$key]) === true - && isset($this->properties[$key]) === false - ) { - $error = 'Unexpected Subversion property "%s" = "%s"'; - $data = array( - $key, - $properties[$key], - ); - $phpcsFile->addError($error, $stackPtr, 'Unexpected', $data); - continue; - } - - if (isset($properties[$key]) === false - && isset($this->properties[$key]) === true - ) { - $error = 'Missing Subversion property "%s" = "%s"'; - $data = array( - $key, - $this->properties[$key], - ); - $phpcsFile->addError($error, $stackPtr, 'Missing', $data); - continue; - } - - if ($properties[$key] !== null - && $properties[$key] !== $this->properties[$key] - ) { - $error = 'Subversion property "%s" = "%s" does not match "%s"'; - $data = array( - $key, - $properties[$key], - $this->properties[$key], - ); - $phpcsFile->addError($error, $stackPtr, 'NoMatch', $data); - } - }//end foreach - - }//end process() - - - /** - * Returns the Subversion properties which are actually set on a path. - * - * Returns NULL if the file is not under version control. - * - * @param string $path The path to return Subversion properties on. - * - * @return array - * @throws PHP_CodeSniffer_Exception If Subversion properties file could - * not be opened. - */ - protected function getProperties($path) - { - $properties = array(); - - $paths = array(); - $paths[] = dirname($path).'/.svn/props/'.basename($path).'.svn-work'; - $paths[] = dirname($path).'/.svn/prop-base/'.basename($path).'.svn-base'; - - $foundPath = false; - foreach ($paths as $path) { - if (file_exists($path) === true) { - $foundPath = true; - - $handle = fopen($path, 'r'); - if ($handle === false) { - $error = 'Error opening file; could not get Subversion properties'; - throw new PHP_CodeSniffer_Exception($error); - } - - while (feof($handle) === false) { - // Read a key length line. Might be END, though. - $buffer = trim(fgets($handle)); - - // Check for the end of the hash. - if ($buffer === 'END') { - break; - } - - // Now read that much into a buffer. - $key = fread($handle, substr($buffer, 2)); - - // Suck up extra newline after key data. - fgetc($handle); - - // Read a value length line. - $buffer = trim(fgets($handle)); - - // Now read that much into a buffer. - $length = substr($buffer, 2); - if ($length === '0') { - // Length of value is ZERO characters, so - // value is actually empty. - $value = ''; - } else { - $value = fread($handle, $length); - } - - // Suck up extra newline after value data. - fgetc($handle); - - $properties[$key] = $value; - }//end while - - fclose($handle); - }//end if - }//end foreach - - if ($foundPath === false) { - return null; - } - - return $properties; - - }//end getProperties() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php deleted file mode 100644 index 23f352545..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff. - * - * Throws errors if spaces are used for indentation. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_WHITESPACE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is whitespace used for indentation. - $line = $tokens[$stackPtr]['line']; - if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) { - return; - } - - if (strpos($tokens[$stackPtr]['content'], ' ') !== false) { - // Space are considered ok if they are proceeded by tabs and not followed - // by tabs, as is the case with standard docblock comments. - $error = 'Tabs must be used to indent lines; spaces are not allowed'; - $phpcsFile->addError($error, $stackPtr, 'TabsUsed'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php deleted file mode 100644 index 5472c7d58..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff. - * - * Throws errors if tabs are used for indentation. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_WHITESPACE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is whitespace used for indentation. - $line = $tokens[$stackPtr]['line']; - if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] === $line) { - return; - } - - if (strpos($tokens[$stackPtr]['content'], "\t") !== false) { - $error = 'Spaces must be used to indent lines; tabs are not allowed'; - $phpcsFile->addError($error, $stackPtr, 'TabsUsed'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php b/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php deleted file mode 100644 index de7efb14c..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php +++ /dev/null @@ -1,437 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Whitespace_ScopeIndentSniff. - * - * Checks that control structures are structured correctly, and their content - * is indented correctly. This sniff will throw errors if tabs are used - * for indentation rather than spaces. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Generic_Sniffs_WhiteSpace_ScopeIndentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - /** - * Does the indent need to be exactly right. - * - * If TRUE, indent needs to be exactly $indent spaces. If FALSE, - * indent needs to be at least $indent spaces (but can be more). - * - * @var bool - */ - public $exact = false; - - /** - * List of tokens not needing to be checked for indentation. - * - * Useful to allow Sniffs based on this to easily ignore/skip some - * tokens from verification. For example, inline html sections - * or php open/close tags can escape from here and have their own - * rules elsewhere. - * - * @var array - */ - public $ignoreIndentationTokens = array(); - - /** - * Any scope openers that should not cause an indent. - * - * @var array(int) - */ - protected $nonIndentingScopes = array(); - - /** - * Stores the indent of the last PHP open tag we found. - * - * This value is used to calculate the expected indent of top level structures - * so we don't assume they are always at column 1. If PHP code is embedded inside - * HTML (etc.) code, then the starting column for that code may not be column 1. - * - * @var int - */ - private $_openTagIndent = 0; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - $tokens = PHP_CodeSniffer_Tokens::$scopeOpeners; - $tokens[] = T_OPEN_TAG; - return $tokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We only want to record the indent of open tags, not process them. - if ($tokens[$stackPtr]['code'] == T_OPEN_TAG) { - if (empty($tokens[$stackPtr]['conditions']) === true) { - // Only record top-level PHP tags. - $this->_openTagIndent = ($tokens[$stackPtr]['column'] - 1); - } - - return; - } - - // If this is an inline condition (ie. there is no scope opener), then - // return, as this is not a new scope. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - if ($tokens[$stackPtr]['code'] === T_ELSE) { - $next = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($stackPtr + 1), - null, - true - ); - - // We will handle the T_IF token in another call to process. - if ($tokens[$next]['code'] === T_IF) { - return; - } - } - - // Find the first token on this line. - $firstToken = $stackPtr; - for ($i = $stackPtr; $i >= 0; $i--) { - // Record the first code token on the line. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $firstToken = $i; - } - - // It's the start of the line, so we've found our first php token. - if ($tokens[$i]['column'] === 1) { - break; - } - } - - // Based on the conditions that surround this token, determine the - // indent that we expect this current content to be. - $expectedIndent = $this->calculateExpectedIndent($tokens, $firstToken); - - // Don't process the first token if it is a closure because they have - // different indentation rules as they are often used as function arguments - // for multi-line function calls. But continue to process the content of the - // closure because it should be indented as normal. - if ($tokens[$firstToken]['code'] !== T_CLOSURE - && $tokens[$firstToken]['column'] !== $expectedIndent - ) { - // If the scope opener is a closure but it is not the first token on the - // line, then the first token may be a variable or array index as so - // should not require exact indentation unless the exact member var - // is set to TRUE. - $exact = true; - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $exact = $this->exact; - } - - if ($exact === true || $tokens[$firstToken]['column'] < $expectedIndent) { - $error = 'Line indented incorrectly; expected %s spaces, found %s'; - $data = array( - ($expectedIndent - 1), - ($tokens[$firstToken]['column'] - 1), - ); - $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); - } - }//end if - - $scopeOpener = $tokens[$stackPtr]['scope_opener']; - $scopeCloser = $tokens[$stackPtr]['scope_closer']; - - // Some scopes are expected not to have indents. - if (in_array($tokens[$firstToken]['code'], $this->nonIndentingScopes) === false) { - $indent = ($expectedIndent + $this->indent); - } else { - $indent = $expectedIndent; - } - - $newline = false; - $commentOpen = false; - $inHereDoc = false; - - // Only loop over the content between the opening and closing brace, not - // the braces themselves. - for ($i = ($scopeOpener + 1); $i < $scopeCloser; $i++) { - - // If this token is another scope, skip it as it will be handled by - // another call to this sniff. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true) { - if (isset($tokens[$i]['scope_opener']) === true) { - $i = $tokens[$i]['scope_closer']; - - // If the scope closer is followed by a semi-colon, the semi-colon is part - // of the closer and should also be ignored. This most commonly happens with - // CASE statements that end with "break;", where we don't want to stop - // ignoring at the break, but rather at the semi-colon. - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true); - if ($tokens[$nextToken]['code'] === T_SEMICOLON) { - $i = $nextToken; - } - } else { - // If this token does not have a scope_opener indice, then - // it's probably an inline scope, so let's skip to the next - // semicolon. Inline scopes include inline if's, abstract - // methods etc. - $nextToken = $phpcsFile->findNext(T_SEMICOLON, $i, $scopeCloser); - if ($nextToken !== false) { - $i = $nextToken; - } - } - - continue; - }//end if - - // If this is a HEREDOC then we need to ignore it as the - // whitespace before the contents within the HEREDOC are - // considered part of the content. - if ($tokens[$i]['code'] === T_START_HEREDOC - || $tokens[$i]['code'] === T_START_NOWDOC - ) { - $inHereDoc = true; - continue; - } else if ($inHereDoc === true) { - if ($tokens[$i]['code'] === T_END_HEREDOC - || $tokens[$i]['code'] === T_END_NOWDOC - ) { - $inHereDoc = false; - } - - continue; - } - - if ($tokens[$i]['column'] === 1) { - // We started a newline. - $newline = true; - } - - if ($newline === true && $tokens[$i]['code'] !== T_WHITESPACE) { - // If we started a newline and we find a token that is not - // whitespace, then this must be the first token on the line that - // must be indented. - $newline = false; - $firstToken = $i; - - $column = $tokens[$firstToken]['column']; - - // Ignore the token for indentation if it's in the ignore list. - if (in_array($tokens[$firstToken]['code'], $this->ignoreIndentationTokens)) { - continue; - } - - // Special case for non-PHP code. - if ($tokens[$firstToken]['code'] === T_INLINE_HTML) { - $trimmedContentLength - = strlen(ltrim($tokens[$firstToken]['content'])); - if ($trimmedContentLength === 0) { - continue; - } - - $contentLength = strlen($tokens[$firstToken]['content']); - $column = ($contentLength - $trimmedContentLength + 1); - } - - // Check to see if this constant string spans multiple lines. - // If so, then make sure that the strings on lines other than the - // first line are indented appropriately, based on their whitespace. - if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { - if (in_array($tokens[($firstToken - 1)]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { - // If we find a string that directly follows another string - // then its just a string that spans multiple lines, so we - // don't need to check for indenting. - continue; - } - } - - // This is a special condition for T_DOC_COMMENT and C-style - // comments, which contain whitespace between each line. - if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - $content = trim($tokens[$firstToken]['content']); - if (preg_match('|^/\*|', $content) !== 0) { - // Check to see if the end of the comment is on the same line - // as the start of the comment. If it is, then we don't - // have to worry about opening a comment. - if (preg_match('|\*/$|', $content) === 0) { - // We don't have to calculate the column for the - // start of the comment as there is a whitespace - // token before it. - $commentOpen = true; - } - } else if ($commentOpen === true) { - if ($content === '') { - // We are in a comment, but this line has nothing on it - // so let's skip it. - continue; - } - - $contentLength = strlen($tokens[$firstToken]['content']); - $trimmedContentLength - = strlen(ltrim($tokens[$firstToken]['content'])); - - $column = ($contentLength - $trimmedContentLength + 1); - if (preg_match('|\*/$|', $content) !== 0) { - $commentOpen = false; - } - - // We are in a comment, so the indent does not have to - // be exact. The important thing is that the comment opens - // at the correct column and nothing sits closer to the left - // than that opening column. - if ($column > $indent) { - continue; - } - }//end if - }//end if - - // The token at the start of the line, needs to have its' column - // greater than the relative indent we set above. If it is less, - // an error should be shown. - if ($column !== $indent) { - if ($this->exact === true || $column < $indent) { - $type = 'IncorrectExact'; - $error = 'Line indented incorrectly; expected '; - if ($this->exact === false) { - $error .= 'at least '; - $type = 'Incorrect'; - } - - $error .= '%s spaces, found %s'; - $data = array( - ($indent - 1), - ($column - 1), - ); - $phpcsFile->addError($error, $firstToken, $type, $data); - } - }//end if - }//end if - }//end for - - }//end process() - - - /** - * Calculates the expected indent of a token. - * - * Returns the column at which the token should be indented to, so 1 means - * that the token should not be indented at all. - * - * @param array $tokens The stack of tokens for this file. - * @param int $stackPtr The position of the token to get indent for. - * - * @return int - */ - protected function calculateExpectedIndent(array $tokens, $stackPtr) - { - $conditionStack = array(); - - $inParenthesis = false; - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true - && empty($tokens[$stackPtr]['nested_parenthesis']) === false - ) { - $inParenthesis = true; - } - - // Empty conditions array (top level structure). - if (empty($tokens[$stackPtr]['conditions']) === true) { - if ($inParenthesis === true) { - // Wrapped in parenthesis means it is probably in a - // function call (like a closure) so we have to assume indent - // is correct here and someone else will check it more - // carefully in another sniff. - return $tokens[$stackPtr]['column']; - } else { - return ($this->_openTagIndent + 1); - } - } - - $indent = 0; - - $tokenConditions = $tokens[$stackPtr]['conditions']; - foreach ($tokenConditions as $id => $condition) { - // If it's not an indenting scope i.e., it's in our array of - // scopes that don't indent, skip it. - if (in_array($condition, $this->nonIndentingScopes) === true) { - continue; - } - - if ($condition === T_CLOSURE && $inParenthesis === true) { - // Closures cause problems with indents when they are - // used as function arguments because the code inside them - // is not technically inside the function yet, so the indent - // is always off by one. So instead, use the - // indent of the closure as the base value. - $lastContent = $id; - for ($i = ($id - 1); $i > 0; $i--) { - if ($tokens[$i]['line'] !== $tokens[$id]['line']) { - // Changed lines, so the last content we saw is what - // we want. - break; - } - - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $lastContent = $i; - } - } - - $indent = ($tokens[$lastContent]['column'] - 1); - } - - $indent += $this->indent; - }//end foreach - - // Increase by 1 to indiciate that the code should start at a specific column. - // E.g., code indented 4 spaces should start at column 5. - $indent++; - return $indent; - - }//end calculateExpectedIndent() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml b/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml deleted file mode 100644 index aeb5545bf..000000000 --- a/codesniffer/CodeSniffer/Standards/Generic/ruleset.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - A collection of generic sniffs. This standard is not designed to be used to check code. - diff --git a/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php b/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php deleted file mode 100644 index e574ce95f..000000000 --- a/codesniffer/CodeSniffer/Standards/IncorrectPatternException.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * An exception thrown if the pattern being processed is not supposed to be - * validating the code in question. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Standards_IncorrectPatternException extends Exception -{ - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php deleted file mode 100644 index 4c609d3d8..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php +++ /dev/null @@ -1,102 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * MySource_Sniffs_CSS_BrowserSpecificStylesSniff. - * - * Ensure that browser-specific styles are not used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_CSS_BrowserSpecificStylesSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - /** - * A list of specific stylesheet suffixes we allow. - * - * These stylesheets contain browser specific styles - * so this sniff ignore them files in the form: - * *_moz.css and *_ie7.css etc. - * - * @var array - */ - protected $specificStylesheets = array( - 'moz', - 'ie', - 'ie7', - 'ie8', - 'webkit', - ); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // Ignore files with browser-specific suffixes. - $filename = $phpcsFile->getFilename(); - $breakChar = strrpos($filename, '_'); - if ($breakChar !== false && substr($filename, -4) === '.css') { - $specific = substr($filename, ($breakChar + 1), -4); - if (in_array($specific, $this->specificStylesheets) === true) { - return; - } - } - - $tokens = $phpcsFile->getTokens(); - $content = $tokens[$stackPtr]['content']; - - if ($content{0} === '-') { - $error = 'Browser-specific styles are not allowed'; - $phpcsFile->addError($error, $stackPtr, 'ForbiddenStyle'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php deleted file mode 100644 index 695d0c479..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that all action classes throw ChannelExceptions only. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Channels_ChannelExceptionSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_THROW); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = strtolower($phpcsFile->getFilename()); - $matches = array(); - if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|', $fileName, $matches) === 0) { - // This is not an actions.inc file. - return; - } - - $tokens = $phpcsFile->getTokens(); - - $exception = $phpcsFile->findNext(array(T_STRING, T_VARIABLE), ($stackPtr + 1)); - $exceptionName = $tokens[$exception]['content']; - - if ($exceptionName !== 'ChannelException') { - $data = array($exceptionName); - $error = 'Channel actions can only throw ChannelException; found "%s"'; - $phpcsFile->addError($error, $exception, 'WrongExceptionType', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php deleted file mode 100644 index 02ca97aa3..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php +++ /dev/null @@ -1,137 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that self and static are not used to call public methods in action classes. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Channels_DisallowSelfActionsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CLASS); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We are not interested in abstract classes. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($prev !== false && $tokens[$prev]['code'] === T_ABSTRACT) { - return; - } - - // We are only interested in Action classes. - $classNameToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - $className = $tokens[$classNameToken]['content']; - if (substr($className, -7) !== 'Actions') { - return; - } - - $foundFunctions = array(); - $foundCalls = array(); - - // Find all static method calls in the form self::method() in the class. - $classEnd = $tokens[$stackPtr]['scope_closer']; - for ($i = ($classNameToken + 1); $i < $classEnd; $i++) { - if ($tokens[$i]['code'] !== T_DOUBLE_COLON) { - if ($tokens[$i]['code'] === T_FUNCTION) { - // Cache the function information. - $funcName = $phpcsFile->findNext(T_STRING, ($i + 1)); - $funcScope = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, ($i - 1)); - - $foundFunctions[$tokens[$funcName]['content']] = strtolower($tokens[$funcScope]['content']); - } - - continue; - } - - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), null, true); - if ($tokens[$prevToken]['content'] !== 'self' - && $tokens[$prevToken]['content'] !== 'static' - ) { - continue; - } - - $funcNameToken = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); - if ($tokens[$funcNameToken]['code'] === T_VARIABLE) { - // We are only interested in function calls. - continue; - } - - $funcName = $tokens[$funcNameToken]['content']; - - // We've found the function, now we need to find it and see if it is - // public, private or protected. If it starts with an underscore we - // can assume it is private. - if ($funcName{0} === '_') { - continue; - } - - $foundCalls[$i] = array( - 'name' => $funcName, - 'type' => strtolower($tokens[$prevToken]['content']), - ); - }//end for - - $errorClassName = substr($className, 0, -7); - - foreach ($foundCalls as $token => $funcData) { - if (isset($foundFunctions[$funcData['name']]) === false) { - // Function was not in this class, might have come from the parent. - // Either way, we can't really check this. - continue; - } else if ($foundFunctions[$funcData['name']] === 'public') { - $type = $funcData['type']; - $error = "Static calls to public methods in Action classes must not use the $type keyword; use %s::%s() instead"; - $data = array( - $errorClassName, - $funcName, - ); - $phpcsFile->addError($error, $token, 'Found'.ucfirst($funcData['type']), $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php deleted file mode 100644 index 74963cee0..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php +++ /dev/null @@ -1,112 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that a system does not include itself. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Channels_IncludeOwnSystemSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_DOUBLE_COLON); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - $matches = array(); - if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|i', $fileName, $matches) === 0) { - // Not an actions file. - return; - } - - $ownClass = $matches[2]; - $tokens = $phpcsFile->getTokens(); - - $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 2), null, false, true); - $typeName = trim($tokens[$typeName]['content'], " '"); - switch (strtolower($tokens[($stackPtr + 1)]['content'])) { - case 'includesystem' : - $included = strtolower($typeName); - break; - case 'includeasset' : - $included = strtolower($typeName).'assettype'; - break; - case 'includewidget' : - $included = strtolower($typeName).'widgettype'; - break; - default: - return; - } - - if ($included === strtolower($ownClass)) { - $error = "You do not need to include \"%s\" from within the system's own actions file"; - $data = array($ownClass); - $phpcsFile->addError($error, $stackPtr, 'NotRequired', $data); - } - - }//end process() - - - /** - * Determines the included class name from given token. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param array $tokens The array of file tokens. - * @param int $stackPtr The position in the tokens array of the - * potentially included class. - * - * @return string - */ - protected function getIncludedClassFromToken( - PHP_CodeSniffer_File $phpcsFile, - array $tokens, - $stackPtr - ) { - - - return false; - - }//end getIncludedClassFromToken() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php deleted file mode 100644 index c9c828f13..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Ensures that systems, asset types and libs are included before they are used. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Channels_IncludeSystemSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - /** - * A list of classes that don't need to be included. - * - * @var array(string) - */ - private $_ignore = array( - 'self', - 'static', - 'parent', - 'channels', - 'basesystem', - 'dal', - 'init', - 'pdo', - 'util', - 'ziparchive', - 'phpunit_framework_assert', - 'abstractmysourceunittest', - 'abstractdatacleanunittest', - 'exception', - 'abstractwidgetwidgettype', - 'domdocument', - ); - - - /** - * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. - */ - public function __construct() - { - parent::__construct(array(T_FUNCTION), array(T_DOUBLE_COLON, T_EXTENDS), true); - - }//end __construct() - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param integer $stackPtr The position where the token was found. - * @param integer $currScope The current scope opener token. - * - * @return void - */ - protected function processTokenWithinScope( - PHP_CodeSniffer_File $phpcsFile, - $stackPtr, - $currScope - ) { - $tokens = $phpcsFile->getTokens(); - - // Determine the name of the class that the static function - // is being called on. - $classNameToken = $phpcsFile->findPrevious( - T_WHITESPACE, - ($stackPtr - 1), - null, - true - ); - - // Don't process class names represented by variables as this can be - // an inexact science. - if ($tokens[$classNameToken]['code'] === T_VARIABLE) { - return; - } - - $className = $tokens[$classNameToken]['content']; - if (in_array(strtolower($className), $this->_ignore) === true) { - return; - } - - $includedClasses = array(); - - $fileName = strtolower($phpcsFile->getFilename()); - $matches = array(); - if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|', $fileName, $matches) !== 0) { - // This is an actions file, which means we don't - // have to include the system in which it exists. - $includedClasses[] = $matches[2]; - - // Or a system it implements. - $class = $phpcsFile->getCondition($stackPtr, T_CLASS); - $implements = $phpcsFile->findNext(T_IMPLEMENTS, $class, ($class + 10)); - if ($implements !== false) { - $implementsClass = $phpcsFile->findNext(T_STRING, $implements); - $implementsClassName = strtolower($tokens[$implementsClass]['content']); - if (substr($implementsClassName, -7) === 'actions') { - $includedClasses[] = substr($implementsClassName, 0, -7); - } - } - } - - // Go searching for includeSystem and includeAsset calls within this - // function, or the inclusion of .inc files, which - // would be library files. - for ($i = ($currScope + 1); $i < $stackPtr; $i++) { - $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); - if ($name !== false) { - $includedClasses[] = $name; - // Special case for Widgets cause they are, well, special. - } else if (strtolower($tokens[$i]['content']) === 'includewidget') { - $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($i + 1)); - $typeName = trim($tokens[$typeName]['content'], " '"); - $includedClasses[] = strtolower($typeName).'widgettype'; - } - } - - // Now go searching for includeSystem, includeAsset or require/include - // calls outside our scope. If we are in a class, look outside the - // class. If we are not, look outside the function. - $condPtr = $currScope; - if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { - foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { - if ($condType === T_CLASS) { - break; - } - } - } - - for ($i = 0; $i < $condPtr; $i++) { - // Skip other scopes. - if (isset($tokens[$i]['scope_closer']) === true) { - $i = $tokens[$i]['scope_closer']; - continue; - } - - $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); - if ($name !== false) { - $includedClasses[] = $name; - } - } - - // If we are in a testing class, we might have also included - // some systems and classes in our setUp() method. - $setupFunction = null; - if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { - foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { - if ($condType === T_CLASS) { - // Is this is a testing class? - $name = $phpcsFile->findNext(T_STRING, $condPtr); - $name = $tokens[$name]['content']; - if (substr($name, -8) === 'UnitTest') { - // Look for a method called setUp(). - $end = $tokens[$condPtr]['scope_closer']; - $function = $phpcsFile->findNext(T_FUNCTION, ($condPtr + 1), $end); - while ($function !== false) { - $name = $phpcsFile->findNext(T_STRING, $function); - if ($tokens[$name]['content'] === 'setUp') { - $setupFunction = $function; - break; - } - - $function = $phpcsFile->findNext(T_FUNCTION, ($function + 1), $end); - } - } - } - }//end foreach - }//end if - - if ($setupFunction !== null) { - $start = ($tokens[$setupFunction]['scope_opener'] + 1); - $end = $tokens[$setupFunction]['scope_closer']; - for ($i = $start; $i < $end; $i++) { - $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); - if ($name !== false) { - $includedClasses[] = $name; - } - } - }//end if - - if (in_array(strtolower($className), $includedClasses) === false) { - $error = 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; - $data = array($className); - $phpcsFile->addError($error, $stackPtr, 'NotIncludedCall', $data); - } - - }//end processTokenWithinScope() - - - /** - * Processes a token within the scope that this test is listening to. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * this token was found. - * - * @return void - */ - protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] === T_EXTENDS) { - // Find the class name. - $classNameToken = $phpcsFile->findNext(T_STRING, ($stackPtr + 1)); - $className = $tokens[$classNameToken]['content']; - } else { - // Determine the name of the class that the static function - // is being called on. But don't process class names represented by - // variables as this can be an inexact science. - $classNameToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$classNameToken]['code'] === T_VARIABLE) { - return; - } - - $className = $tokens[$classNameToken]['content']; - } - - // Some systems are always available. - if (in_array(strtolower($className), $this->_ignore) === true) { - return; - } - - $includedClasses = array(); - - $fileName = strtolower($phpcsFile->getFilename()); - $matches = array(); - if (preg_match('|/systems/([^/]+)/([^/]+)?actions.inc$|', $fileName, $matches) !== 0) { - // This is an actions file, which means we don't - // have to include the system in which it exists - // We know the system from the path. - $includedClasses[] = $matches[1]; - } - - // Go searching for includeSystem, includeAsset or require/include - // calls outside our scope. - for ($i = 0; $i < $stackPtr; $i++) { - // Skip classes and functions as will we never get - // into their scopes when including this file, although - // we have a chance of getting into IF's, WHILE's etc. - $ignoreTokens = array( - T_CLASS, - T_INTERFACE, - T_FUNCTION, - ); - - if (in_array($tokens[$i]['code'], $ignoreTokens) === true - && isset($tokens[$i]['scope_closer']) === true - ) { - $i = $tokens[$i]['scope_closer']; - continue; - } - - $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); - if ($name !== false) { - $includedClasses[] = $name; - // Special case for Widgets cause they are, well, special. - } else if (strtolower($tokens[$i]['content']) === 'includewidget') { - $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($i + 1)); - $typeName = trim($tokens[$typeName]['content'], " '"); - $includedClasses[] = strtolower($typeName).'widgettype'; - } - }//end for - - if (in_array(strtolower($className), $includedClasses) === false) { - if ($tokens[$stackPtr]['code'] === T_EXTENDS) { - $error = 'Class extends non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; - $data = array($className); - $phpcsFile->addError($error, $stackPtr, 'NotIncludedExtends', $data); - } else { - $error = 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; - $data = array($className); - $phpcsFile->addError($error, $stackPtr, 'NotIncludedCall', $data); - } - } - - }//end processTokenOutsideScope() - - - /** - * Determines the included class name from given token. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param array $tokens The array of file tokens. - * @param int $stackPtr The position in the tokens array of the - * potentially included class. - * - * @return string - */ - protected function getIncludedClassFromToken( - PHP_CodeSniffer_File $phpcsFile, - array $tokens, - $stackPtr - ) { - if (strtolower($tokens[$stackPtr]['content']) === 'includesystem') { - $systemName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); - $systemName = trim($tokens[$systemName]['content'], " '"); - return strtolower($systemName); - } else if (strtolower($tokens[$stackPtr]['content']) === 'includeasset') { - $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); - $typeName = trim($tokens[$typeName]['content'], " '"); - return strtolower($typeName).'assettype'; - } else if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$includeTokens) === true) { - $filePath = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, ($stackPtr + 1)); - $filePath = $tokens[$filePath]['content']; - $filePath = trim($filePath, " '"); - $filePath = basename($filePath, '.inc'); - return strtolower($filePath); - } - - return false; - - }//end getIncludedClassFromToken() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php deleted file mode 100644 index d2c93c7f6..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php +++ /dev/null @@ -1,157 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that systems and asset types are used if they are included. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Channels_UnusedSystemSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_DOUBLE_COLON); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Check if this is a call to includeSystem, includeAsset or includeWidget. - $methodName = strtolower($tokens[($stackPtr + 1)]['content']); - if (in_array($methodName, array('includesystem', 'includeasset', 'includewidget')) === true) { - $systemName = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 3), null, true); - if ($systemName === false || $tokens[$systemName]['code'] !== T_CONSTANT_ENCAPSED_STRING) { - // Must be using a variable instead of a specific system name. - // We can't accurately check that. - return; - } - - $systemName = trim($tokens[$systemName]['content'], " '"); - } else { - return; - } - - if ($methodName === 'includeasset') { - $systemName .= 'assettype'; - } else if ($methodName === 'includewidget') { - $systemName .= 'widgettype'; - } - - $systemName = strtolower($systemName); - - // Now check if this system is used anywhere in this scope. - $level = $tokens[$stackPtr]['level']; - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['level'] < $level) { - // We have gone out of scope. - // If the original include was inside an IF statement that - // is checking if the system exists, check the outer scope - // as well. - if ($tokens[$stackPtr]['level'] === $level) { - // We are still in the base level, so this is the first - // time we have got here. - $conditions = array_keys($tokens[$stackPtr]['conditions']); - if (empty($conditions) === false) { - $cond = array_pop($conditions); - if ($tokens[$cond]['code'] === T_IF) { - $i = $tokens[$cond]['scope_closer']; - $level--; - continue; - } - } - } - - break; - }//end if - - $validTokens = array( - T_DOUBLE_COLON, - T_EXTENDS, - T_IMPLEMENTS, - ); - - if (in_array($tokens[$i]['code'], $validTokens) === false) { - continue; - } - - switch ($tokens[$i]['code']) { - case T_DOUBLE_COLON: - $usedName = strtolower($tokens[($i - 1)]['content']); - if ($usedName === $systemName) { - // The included system was used, so it is fine. - return; - } - - break; - case T_EXTENDS: - $classNameToken = $phpcsFile->findNext(T_STRING, ($i + 1)); - $className = strtolower($tokens[$classNameToken]['content']); - if ($className === $systemName) { - // The included system was used, so it is fine. - return; - } - - break; - case T_IMPLEMENTS: - $endImplements = $phpcsFile->findNext(array(T_EXTENDS, T_OPEN_CURLY_BRACKET), ($i + 1)); - for ($x = ($i + 1); $x < $endImplements; $x++) { - if ($tokens[$x]['code'] === T_STRING) { - $className = strtolower($tokens[$x]['content']); - if ($className === $systemName) { - // The included system was used, so it is fine. - return; - } - } - } - - break; - }//end switch - }//end for - - // If we get to here, the system was not use. - $error = 'Included system "%s" is never used'; - $data = array($systemName); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php deleted file mode 100644 index 0c707b369..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php +++ /dev/null @@ -1,130 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Squiz_Sniffs_Commenting_FunctionCommentSniff', true) === false) { - $error = 'Class Squiz_Sniffs_Commenting_FunctionCommentSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses and verifies the doc comments for functions. - * - * Same as the Squiz standard, but adds support for API tags. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Commenting_FunctionCommentSniff extends Squiz_Sniffs_Commenting_FunctionCommentSniff -{ - - - /** - * Process a list of unknown tags. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processUnknownTags($commentStart, $commentEnd) - { - $unknownTags = $this->commentParser->getUnknown(); - $words = $this->commentParser->getWords(); - $hasApiTag = false; - $apiLength = 3; - foreach ($unknownTags as $errorTag) { - $pos = $errorTag['pos']; - if ($errorTag['tag'] === 'api') { - if ($hasApiTag === true) { - // We've come across an API tag already, which means - // we were not the first tag in the API list. - $error = 'The @api tag must come first in the @api tag list in a function comment'; - $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiNotFirst'); - } - - $hasApiTag = true; - - // There needs to be a blank line before the @api tag. - // So expect a single space before the tag, then 2 newlines before - // that, then some content. - if (trim($words[($pos - 2)]) !== '' - || strpos($words[($pos - 2)], $this->currentFile->eolChar) === false - || strpos($words[($pos - 3)], $this->currentFile->eolChar) === false - || trim($words[($pos - 4)]) === '' - ) { - $error = 'There must be one blank line before the @api tag in a function comment'; - $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiSpacing'); - } - } else if (substr($errorTag['tag'], 0, 4) === 'api-') { - $hasApiTag = true; - - $tagLength = strlen($errorTag['tag']); - if ($tagLength > $apiLength) { - $apiLength = $tagLength; - } - - if (trim($words[($pos - 2)]) !== '' - || strpos($words[($pos - 2)], $this->currentFile->eolChar) === false - || trim($words[($pos - 3)]) === '' - ) { - $error = 'There must be no blank line before the @%s tag in a function comment'; - $data = array($errorTag['tag']); - $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiTagSpacing', $data); - } - }//end if - }//end foreach - - if ($hasApiTag === true) { - // API tags must be the last tags in a function comment. - $order = $this->commentParser->getTagOrders(); - $lastTag = array_pop($order); - if ($lastTag !== 'api' - && substr($lastTag, 0, 4) !== 'api-' - ) { - $error = 'The @api tags must be the last tags in a function comment'; - $this->currentFile->addError($error, $commentEnd, 'ApiNotLast'); - } - - // Check API tag indenting. - foreach ($unknownTags as $errorTag) { - if ($errorTag['tag'] === 'api' - || substr($errorTag['tag'], 0, 4) === 'api-' - ) { - $expected = ($apiLength - strlen($errorTag['tag']) + 1); - $found = strlen($words[($errorTag['pos'] + 1)]); - if ($found !== $expected) { - $error = '@%s tag indented incorrectly; expected %s spaces but found %s'; - $data = array( - $errorTag['tag'], - $expected, - $found, - ); - $this->currentFile->addError($error, ($commentStart + $errorTag['line']), 'ApiTagIndent', $data); - } - } - } - }//end if - - }//end processUnknownTags() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php deleted file mode 100644 index 628c9e580..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Warns about the use of debug code. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Debug_DebugCodeSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_DOUBLE_COLON); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $className = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if (strtolower($tokens[$className]['content']) === 'debug') { - $method = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - $error = 'Call to debug function Debug::%s() must be removed'; - $data = array($tokens[$method]['content']); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php deleted file mode 100644 index 788dcea20..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that console is not used for function or var names. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Debug_FirebugConsoleSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_STRING, - T_PROPERTY, - T_LABEL, - T_OBJECT, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (strtolower($tokens[$stackPtr]['content']) === 'console') { - $error = 'Variables, functions and labels must not be named "console"; name may conflict with Firebug internal variable'; - $phpcsFile->addError($error, $stackPtr, 'ConflictFound'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php deleted file mode 100644 index 7e438677c..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php +++ /dev/null @@ -1,94 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures this is not assigned to any other var but self. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Objects_AssignThisSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_THIS); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore this.something and other uses of "this" that are not - // direct assignments. - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$next]['code'] !== T_SEMICOLON) { - if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) { - return; - } - } - - // Something must be assigned to "this". - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] !== T_EQUAL) { - return; - } - - // A variable needs to be assigned to "this". - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($prev - 1), null, true); - if ($tokens[$prev]['code'] !== T_STRING) { - return; - } - - // We can only assign "this" to a var called "self". - if ($tokens[$prev]['content'] !== 'self' && $tokens[$prev]['content'] !== '_self') { - $error = 'Keyword "this" can only be assigned to a variable called "self" or "_self"'; - $phpcsFile->addError($error, $prev, 'NotSelf'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php deleted file mode 100644 index f4049fe92..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php +++ /dev/null @@ -1,228 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures the create() method of widget types properly uses callbacks. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OBJECT); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $className = $tokens[$stackPtr]['content']; - if (substr(strtolower($className), -10) !== 'widgettype') { - return; - } - - // Search for a create method. - $start = ($tokens[$stackPtr]['scope_opener'] + 1); - $end = ($tokens[$stackPtr]['scope_closer'] - 1); - $create = $phpcsFile->findNext(T_PROPERTY, $start, $end, null, 'create'); - if ($create === false) { - return; - } - - $function = $phpcsFile->findNext(array(T_WHITESPACE, T_COLON), ($create + 1), null, true); - if ($tokens[$function]['code'] !== T_FUNCTION) { - continue; - } - - $start = ($tokens[$function]['scope_opener'] + 1); - $end = ($tokens[$function]['scope_closer'] - 1); - - // Check that the first argument is called "callback". - $arg = $phpcsFile->findNext(T_WHITESPACE, ($tokens[$function]['parenthesis_opener'] + 1), null, true); - if ($tokens[$arg]['content'] !== 'callback') { - $error = 'The first argument of the create() method of a widget type must be called "callback"'; - $phpcsFile->addError($error, $arg, 'FirstArgNotCallback'); - } - - /* - Look for return statements within the function. They cannot return - anything and must be preceded by the callback.call() line. The - callback itself must contain "self" or "this" as the first argument - and there needs to be a call to the callback function somewhere - in the create method. All calls to the callback function must be - followed by a return statement or the end of the method. - */ - - $foundCallback = false; - $passedCallback = false; - $nestedFunction = null; - for ($i = $start; $i <= $end; $i++) { - // Keep track of nested functions. - if ($nestedFunction !== null) { - if ($i === $nestedFunction) { - $nestedFunction = null; - continue; - } - } else if ($tokens[$i]['code'] === T_FUNCTION - && isset($tokens[$i]['scope_closer']) === true - ) { - $nestedFunction = $tokens[$i]['scope_closer']; - continue; - } - - if ($nestedFunction === null && $tokens[$i]['code'] === T_RETURN) { - // Make sure return statements are not returning anything. - if ($tokens[($i + 1)]['code'] !== T_SEMICOLON) { - $error = 'The create() method of a widget type must not return a value'; - $phpcsFile->addError($error, $i, 'ReturnValue'); - } - - continue; - } else if ($tokens[$i]['code'] !== T_STRING - || $tokens[$i]['content'] !== 'callback' - ) { - continue; - } - - // If this is the form "callback.call(" then it is a call - // to the callback function. - if ($tokens[($i + 1)]['code'] !== T_OBJECT_OPERATOR - || $tokens[($i + 2)]['content'] !== 'call' - || $tokens[($i + 3)]['code'] !== T_OPEN_PARENTHESIS - ) { - // One last chance; this might be the callback function - // being passed to another function, like this - // "this.init(something, callback, something)". - if (isset($tokens[$i]['nested_parenthesis']) === false) { - continue; - } - - // Just make sure those brackets dont belong to anyone, - // like an IF or FOR statement. - foreach ($tokens[$i]['nested_parenthesis'] as $bracket) { - if (isset($tokens[$bracket]['parenthesis_owner']) === true) { - continue(2); - } - } - - // Note that we use this endBracket down further when checking - // for a RETURN statement. - $endBracket = end($tokens[$i]['nested_parenthesis']); - $bracket = key($tokens[$i]['nested_parenthesis']); - - $prev = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($bracket - 1), - null, - true - ); - - if ($tokens[$prev]['code'] !== T_STRING) { - // This is not a function passing the callback. - continue; - } - - $passedCallback = true; - }//end if - - $foundCallback = true; - - if ($passedCallback === false) { - // The first argument must be "this" or "self". - $arg = $phpcsFile->findNext(T_WHITESPACE, ($i + 4), null, true); - if ($tokens[$arg]['content'] !== 'this' - && $tokens[$arg]['content'] !== 'self' - ) { - $error = 'The first argument passed to the callback function must be "this" or "self"'; - $phpcsFile->addError($error, $arg, 'FirstArgNotSelf'); - } - } - - // Now it must be followed by a return statement or the end of the function. - if ($passedCallback === false) { - $endBracket = $tokens[($i + 3)]['parenthesis_closer']; - } - - for ($next = $endBracket; $next <= $end; $next++) { - // Skip whitespace so we find the next content after the call. - if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } - - // Skip closing braces like END IF because it is not executable code. - if ($tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { - continue; - } - - // We don't care about anything on the current line, like a - // semicolon. It doesn't matter if there are other statements on the - // line because another sniff will check for those. - if ($tokens[$next]['line'] === $tokens[$endBracket]['line']) { - continue; - } - - break; - } - - if ($next !== $tokens[$function]['scope_closer'] - && $tokens[$next]['code'] !== T_RETURN - ) { - $error = 'The call to the callback function must be followed by a return statement if it is not the last statement in the create() method'; - $phpcsFile->addError($error, $i, 'NoReturn'); - } - }//end for - - if ($foundCallback === false) { - $error = 'The create() method of a widget type must call the callback function'; - $phpcsFile->addError($error, $create, 'CallbackNotCalled'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php deleted file mode 100644 index 59f828177..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that widgets are not manually created. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Objects_DisallowNewWidgetSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_NEW); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $className = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$className]['code'] !== T_STRING) { - return; - } - - if (substr(strtolower($tokens[$className]['content']), -10) === 'widgettype') { - $widgetType = substr($tokens[$className]['content'], 0, -10); - $error = 'Manual creation of widget objects is banned; use Widget::getWidget(\'%s\'); instead'; - $data = array($widgetType); - $phpcsFile->addError($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php deleted file mode 100644 index 984e943ba..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that values submitted via JS are not compared to NULL. - * - * jQuery 1.8 changed the behaviour of ajax requests so that null values are - * submitted as null= instead of null=null. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_PHP_AjaxNullComparisonSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure it is an API function. We know this by the doc comment. - $commentEnd = $phpcsFile->findPrevious(T_DOC_COMMENT, $stackPtr); - $commentStart = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true); - $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart)); - if (strpos($comment, '* @api') === false) { - return; - } - - - // Find all the vars passed in as we are only interested in comparisons - // to NULL for these specific variables. - $foundVars = array(); - $open = $tokens[$stackPtr]['parenthesis_opener']; - $close = $tokens[$stackPtr]['parenthesis_closer']; - for ($i = ($open + 1); $i < $close; $i++) { - if ($tokens[$i]['code'] === T_VARIABLE) { - $foundVars[] = $tokens[$i]['content']; - } - } - - if (empty($foundVars) === true) { - return; - } - - $start = $tokens[$stackPtr]['scope_opener']; - $end = $tokens[$stackPtr]['scope_closer']; - for ($i = ($start + 1); $i < $end; $i++) { - if ($tokens[$i]['code'] !== T_VARIABLE - || in_array($tokens[$i]['content'], $foundVars) === false - ) { - continue; - } - - $operator = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); - if ($tokens[$operator]['code'] !== T_IS_IDENTICAL - && $tokens[$operator]['code'] !== T_IS_NOT_IDENTICAL - ) { - continue; - } - - $nullValue = $phpcsFile->findNext(T_WHITESPACE, ($operator + 1), null, true); - if ($tokens[$nullValue]['code'] !== T_NULL) { - continue; - } - - $error = 'Values submitted via Ajax requests must not be compared directly to NULL; use empty() instead'; - $phpcsFile->addError($error, $nullValue, 'Found'); - }//end for - - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php deleted file mode 100644 index 176f81136..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php +++ /dev/null @@ -1,126 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that eval() is not used to create objects. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_PHP_EvalObjectFactorySniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_EVAL); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - /* - We need to find all strings that will be in the eval - to determine if the "new" keyword is being used. - */ - - $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($stackPtr + 1)); - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - - $strings = array(); - $vars = array(); - - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { - $strings[$i] = $tokens[$i]['content']; - } else if ($tokens[$i]['code'] === T_VARIABLE) { - $vars[$i] = $tokens[$i]['content']; - } - } - - /* - We now have some variables that we need to expand into - the strings that were assigned to them, if any. - */ - - foreach ($vars as $varPtr => $varName) { - while (($prev = $phpcsFile->findPrevious(T_VARIABLE, ($varPtr - 1))) !== false) { - // Make sure this is an assignment of the variable. That means - // it will be the first thing on the line. - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($prev - 1), null, true); - if ($tokens[$prevContent]['line'] === $tokens[$prev]['line']) { - $varPtr = $prevContent; - continue; - } - - if ($tokens[$prev]['content'] !== $varName) { - // This variable has a different name. - $varPtr = $prevContent; - continue; - } - - // We found one. - break; - }//end while - - if ($prev !== false) { - // Find all strings on the line. - $lineEnd = $phpcsFile->findNext(T_SEMICOLON, ($prev + 1)); - for ($i = ($prev + 1); $i < $lineEnd; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { - $strings[$i] = $tokens[$i]['content']; - } - } - } - }//end foreach - - foreach ($strings as $string) { - // If the string has "new" in it, it is not allowed. - // We don't bother checking if the word "new" is echo'd - // because that is unlikely to happen. We assume the use - // of "new" is for object instantiation. - if (strstr($string, ' new ') !== false) { - $error = 'Do not use eval() to create objects dynamically; use reflection instead'; - $phpcsFile->addWarning($error, $stackPtr, 'Found'); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php deleted file mode 100644 index 0732e3f63..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that getRequestData() is used to access super globals. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_PHP_GetRequestDataSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_VARIABLE); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $varName = $tokens[$stackPtr]['content']; - if ($varName !== '$_REQUEST' - && $varName !== '$_GET' - && $varName !== '$_POST' - && $varName !== '$_FILES' - ) { - return; - } - - // The only place these super globals can be accessed directly is - // in the getRequestData() method of the Security class. - $inClass = false; - foreach ($tokens[$stackPtr]['conditions'] as $i => $type) { - if ($tokens[$i]['code'] === T_CLASS) { - $className = $phpcsFile->findNext(T_STRING, $i); - $className = $tokens[$className]['content']; - if (strtolower($className) === 'security') { - $inClass = true; - } else { - // We don't have nested classes. - break; - } - } else if ($inClass === true && $tokens[$i]['code'] === T_FUNCTION) { - $funcName = $phpcsFile->findNext(T_STRING, $i); - $funcName = $tokens[$funcName]['content']; - if (strtolower($funcName) === 'getrequestdata') { - // This is valid. - return; - } else { - // We don't have nested functions. - break; - } - }//end if - }//end foreach - - // If we get to here, the super global was used incorrectly. - // First find out how it is being used. - $globalName = strtolower(substr($varName, 2)); - $usedVar = ''; - - $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$openBracket]['code'] === T_OPEN_SQUARE_BRACKET) { - $closeBracket = $tokens[$openBracket]['bracket_closer']; - $usedVar = $phpcsFile->getTokensAsString(($openBracket + 1), ($closeBracket - $openBracket - 1)); - } - - $type = 'SuperglobalAccessed'; - $error = 'The %s super global must not be accessed directly; use Security::getRequestData('; - $data = array($varName); - if ($usedVar !== '') { - $type .= 'WithVar'; - $error .= '%s, \'%s\''; - $data[] = $usedVar; - $data[] = $globalName; - } - - $error .= ') instead'; - $phpcsFile->addError($error, $stackPtr, $type, $data); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php deleted file mode 100644 index 7f41fe6c9..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Warns when function values are returned directly. - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_PHP_ReturnFunctionValueSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_RETURN); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $functionName = $phpcsFile->findNext(T_STRING, ($stackPtr + 1), null, false, null, true); - - while ($functionName !== false) { - // Check if this is really a function. - $bracket = $phpcsFile->findNext(T_WHITESPACE, ($functionName + 1), null, true); - if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { - // Not a function call. - $functionName = $phpcsFile->findNext(T_STRING, ($functionName + 1), null, false, null, true); - continue; - } - - $error = 'The result of a function call should be assigned to a variable before being returned'; - $phpcsFile->addWarning($error, $stackPtr, 'NotAssigned'); - break; - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php b/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php deleted file mode 100644 index 2d517afbd..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that strings are not joined using array.join(). - * - * @category PHP - * @package PHP_CodeSniffer_MySource - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class MySource_Sniffs_Strings_JoinStringsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param integer $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['content'] !== 'join') { - return; - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { - return; - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($prev - 1), null, true); - if ($tokens[$prev]['code'] === T_CLOSE_SQUARE_BRACKET) { - $opener = $tokens[$prev]['bracket_opener']; - if ($tokens[($opener - 1)]['code'] !== T_STRING) { - // This means the array is declared inline, like x = [a,b,c].join() - // and not elsewhere, like x = y[a].join() - // The first is not allowed while the second is. - $error = 'Joining strings using inline arrays is not allowed; use the + operator instead'; - $phpcsFile->addError($error, $stackPtr, 'ArrayNotAllowed'); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml b/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml deleted file mode 100644 index fe7ae6662..000000000 --- a/codesniffer/CodeSniffer/Standards/MySource/ruleset.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - The MySource coding standard builds on the Squiz coding standard. Currently used for MySource Mini development. - - */Tests/* - */Oven/* - */data/* - */jquery.js - */jquery.*.js - */viper/* - DALConf.inc - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml deleted file mode 100644 index b5d53fdf0..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - { -} - ]]> - - - { -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml deleted file mode 100644 index fe8162000..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/ClassCommentStandard.xml +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - /** - * The Foo class. - */ -class Foo -{ -} - ]]> - - - - - - - - /** - * The Foo class. - */ -class Foo -{ -} - ]]> - - - - - - - - /** - * The Foo class. - */ -class Foo -{ -} - ]]> - - - /** - * The Foo class. - */ - -class Foo -{ -} - ]]> - - - - - The Foo class. - */ -class Foo -{ -} - ]]> - - - The Foo class. - */ -class Foo -{ -} - ]]> - - - - - - * A helper for the Bar class. - * - * @see Bar - */ -class Foo -{ -} - ]]> - - - - * - * A helper for the Bar class. - * - * - * @see Bar - */ -class Foo -{ -} - ]]> - - - - - - * @see Bar - */ -class Foo -{ -} - ]]> - - - - * - * @see Bar - */ -class Foo -{ -} - ]]> - - - - - Release: 1.0 - */ -class Foo -{ -} - ]]> - - - 1.0 - */ -class Foo -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml deleted file mode 100644 index 0d056eabb..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - /** - * Short description here. - * - * PHP version 5 - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - ]]> - - - - - Short description here. - * - * PHP version 5 - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - * Short description here. - * - * PHP version 5 - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - - * PHP version 5 - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - * - * PHP version 5 - * - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - - - - @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - @category Foo - * @category Bar - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - PHP version 5 - * - * @category Foo - * @package Foo_Helpers - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - @package Foo_Helpers - * @category Foo - * @author Marty McFly - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - - - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - - * @copyright 2013 Foo Inc. - * @license MIT License - * @link http://example.com - */ - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml deleted file mode 100644 index d5cc175d8..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/FunctionCommentStandard.xml +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - /** - * Short description here. - * - * @return void - */ - function foo() - { - } - ]]> - - - - - - - - Short description here. - * - * @return void - */ - function foo() - { - } - ]]> - - - - * Short description here. - * - * @return void - */ - function foo() - { - } - ]]> - - - - - - * Long description here. - * - * @return void - */ - function foo() - { - } - ]]> - - - - * - * Long description here. - * - * - * @return void - */ - function foo() - { - } - ]]> - - - - - - * @return void - */ - function foo() - { - } - ]]> - - - - * - * @return void - */ - function foo() - { - } - ]]> - - - - - FooException - */ - function foo() - { - } - ]]> - - - @throws - */ - function foo() - { - } - ]]> - - - - - @return void - */ - function foo() - { - } - ]]> - - - - - - - - $foo Foo parameter - * @param string $bar Bar parameter - * @return void - */ - function foo($foo, $bar) - { - } - ]]> - - - $qux Bar parameter - * @return void - */ - function foo($foo, $bar) - { - } - ]]> - - - - - $foo Foo parameter - * @param string $bar Bar parameter - * @return void - */ - function foo($foo, $bar) - { - } - ]]> - - - $bar Bar parameter - * @param string $foo Foo parameter - * @return void - */ - function foo($foo, $bar) - { - } - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml deleted file mode 100644 index 53056e2a9..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Commenting/InlineCommentStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - // A comment. - ]]> - - - # A comment. - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml deleted file mode 100644 index ce430fb12..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/ControlSignatureStandard.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - ($foo) { -} - ]]> - - - ($foo){ -} - ]]> - - - - - { -} - ]]> - - - { -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml deleted file mode 100644 index 96d451dc4..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/ControlStructures/MultiLineConditionStandard.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - && $bar -) { -} - ]]> - - - && $bar -) { -} - ]]> - - - - - && $bar -) { -} - ]]> - - - && - $bar -) { -} - ]]> - - - - - ) { -} - ]]> - - - ) { -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml deleted file mode 100644 index 6d115be76..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/IncludingFileStandard.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - require_once. Anywhere you are conditionally including a class file (for example, factory methods), use include_once. Either of these will ensure that class files are included only once. They share the same file list, so you don't need to worry about mixing them - a file included with require_once will not be included again by include_once. - ]]> - - - include_once and require_once are statements, not functions. Parentheses should not surround the subject filename. - ]]> - - - - - - - ('PHP/CodeSniffer.php'); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml deleted file mode 100644 index e4911ef3b..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Files/LineLengthStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml deleted file mode 100644 index e825c5533..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Formatting/MultiLineAssignmentStandard.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - = $bar; - ]]> - - - = - $bar; - ]]> - - - - - = $bar; - ]]> - - - = $bar; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml deleted file mode 100644 index f87422778..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - ( $bar, $baz, $quux ) ; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml deleted file mode 100644 index c7951191e..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/FunctionDeclarationStandard.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - () use ($bar) { -}; - ]]> - - - ()use($bar){ -}; - ]]> - - - - - $bar, - $baz -) { -}; - ]]> - - - $bar, -$baz) -{ -}; - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml deleted file mode 100644 index 56196cb62..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - $persistent = false) -{ - ... -} - ]]> - - - $persistent = false, $dsn) -{ - ... -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml deleted file mode 100644 index d16087919..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml deleted file mode 100644 index 60841dd4c..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidFunctionNameStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml deleted file mode 100644 index 4c707bdd1..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/NamingConventions/ValidVariableNameStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - publicVar; - protected $protectedVar; - private $_privateVar; -} - ]]> - - - _publicVar; - protected $_protectedVar; - private $privateVar; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml deleted file mode 100644 index 9dee905db..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ObjectOperatorIndentStandard.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - ->bar() - ->baz(); - ]]> - - - -> - bar()-> - baz(); - ]]> - - - - - ->bar() - ->baz(); - ]]> - - - ->bar() -->baz(); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml deleted file mode 100644 index c8d6e2748..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeClosingBraceStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - } - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml b/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml deleted file mode 100644 index fafa07ace..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Docs/WhiteSpace/ScopeIndentStandard.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - if ($test) { - $var = 1; - } -} - ]]> - - - if ($test) { -$var = 1; -} -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php deleted file mode 100644 index a0126461d..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php +++ /dev/null @@ -1,125 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Class Declaration Test. - * - * Checks the declaration of the class is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param integer $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $errorData = array($tokens[$stackPtr]['content']); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - $error = 'Possible parse error: %s missing opening or closing brace'; - $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $errorData); - return; - } - - $curlyBrace = $tokens[$stackPtr]['scope_opener']; - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($curlyBrace - 1), $stackPtr, true); - $classLine = $tokens[$lastContent]['line']; - $braceLine = $tokens[$curlyBrace]['line']; - if ($braceLine === $classLine) { - $error = 'Opening brace of a %s must be on the line after the definition'; - $phpcsFile->addError($error, $curlyBrace, 'OpenBraceNewLine', $errorData); - return; - } else if ($braceLine > ($classLine + 1)) { - $error = 'Opening brace of a %s must be on the line following the %s declaration; found %s line(s)'; - $data = array( - $tokens[$stackPtr]['content'], - $tokens[$stackPtr]['content'], - ($braceLine - $classLine - 1), - ); - $phpcsFile->addError($error, $curlyBrace, 'OpenBraceWrongLine', $data); - return; - } - - if ($tokens[($curlyBrace + 1)]['content'] !== $phpcsFile->eolChar) { - $error = 'Opening %s brace must be on a line by itself'; - $phpcsFile->addError($error, $curlyBrace, 'OpenBraceNotAlone', $errorData); - } - - if ($tokens[($curlyBrace - 1)]['code'] === T_WHITESPACE) { - $prevContent = $tokens[($curlyBrace - 1)]['content']; - if ($prevContent === $phpcsFile->eolChar) { - $spaces = 0; - } else { - $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); - $spaces = strlen($blankSpace); - } - - $expected = ($tokens[$stackPtr]['level'] * $this->indent); - if ($spaces !== $expected) { - $error = 'Expected %s spaces before opening brace; %s found'; - $data = array( - $expected, - $spaces, - ); - $phpcsFile->addError($error, $curlyBrace, 'SpaceBeforeBrace', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php deleted file mode 100644 index 265c4b7c3..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php +++ /dev/null @@ -1,233 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('PEAR_Sniffs_Commenting_FileCommentSniff', true) === false) { - $error = 'Class PEAR_Sniffs_Commenting_FileCommentSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses and verifies the doc comments for classes. - * - * Verifies that : - *
    - *
  • A doc comment exists.
  • - *
  • There is a blank newline after the short description.
  • - *
  • There is a blank newline between the long and short description.
  • - *
  • There is a blank newline between the long description and tags.
  • - *
  • Check the order of the tags.
  • - *
  • Check the indentation of each tag.
  • - *
  • Check required and optional tags and the format of their content.
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Commenting_ClassCommentSniff extends PEAR_Sniffs_Commenting_FileCommentSniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - $tokens = $phpcsFile->getTokens(); - $type = strtolower($tokens[$stackPtr]['content']); - $errorData = array($type); - $find = array( - T_ABSTRACT, - T_WHITESPACE, - T_FINAL, - ); - - // Extract the class comment docblock. - $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); - - if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { - $error = 'You must use "/**" style comments for a %s comment'; - $phpcsFile->addError($error, $stackPtr, 'WrongStyle', $errorData); - return; - } else if ($commentEnd === false - || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT - ) { - $phpcsFile->addError('Missing %s doc comment', $stackPtr, 'Missing', $errorData); - return; - } - - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); - - // Distinguish file and class comment. - $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1)); - if ($prevClassToken === false) { - // This is the first class token in this file, need extra checks. - $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true); - if ($prevNonComment !== false) { - $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1)); - if ($prevComment === false) { - // There is only 1 doc comment between open tag and class token. - $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); - if ($newlineToken !== false) { - $newlineToken = $phpcsFile->findNext( - T_WHITESPACE, - ($newlineToken + 1), - $stackPtr, - false, - $phpcsFile->eolChar - ); - - if ($newlineToken !== false) { - // Blank line between the class and the doc block. - // The doc block is most likely a file comment. - $error = 'Missing %s doc comment'; - $phpcsFile->addError($error, ($stackPtr + 1), 'Missing', $errorData); - return; - } - }//end if - }//end if - }//end if - }//end if - - $comment = $phpcsFile->getTokensAsString( - $commentStart, - ($commentEnd - $commentStart + 1) - ); - - // Parse the class comment.docblock. - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'Doc comment is empty for %s'; - $phpcsFile->addError($error, $commentStart, 'Empty', $errorData); - return; - } - - // No extra newline before short description. - $short = $comment->getShortComment(); - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before %s comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort', $errorData); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in %s comments'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingAfterShort', $errorData); - } - - $newlineCount += $newlineBetween; - } - - // Exactly one blank line before tags. - $tags = $this->commentParser->getTagOrders(); - if (count($tags) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in %s comments'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags', $errorData); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Check each tag. - $this->processTags($commentStart, $commentEnd); - - }//end process() - - - /** - * Process the version tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processVersion($errorPos) - { - $version = $this->commentParser->getVersion(); - if ($version !== null) { - $content = $version->getContent(); - $matches = array(); - if (empty($content) === true) { - $error = 'Content missing for @version tag in doc comment'; - $this->currentFile->addError($error, $errorPos, 'EmptyVersion'); - } else if ((strstr($content, 'Release:') === false)) { - $error = 'Invalid version "%s" in doc comment; consider "Release: " instead'; - $data = array($content); - $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data); - } - } - - }//end processVersion() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php deleted file mode 100644 index 267dfe946..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php +++ /dev/null @@ -1,797 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); -} - -/** - * Parses and verifies the doc comments for files. - * - * Verifies that : - *
    - *
  • A doc comment exists.
  • - *
  • There is a blank newline after the short description.
  • - *
  • There is a blank newline between the long and short description.
  • - *
  • There is a blank newline between the long description and tags.
  • - *
  • A PHP version is specified.
  • - *
  • Check the order of the tags.
  • - *
  • Check the indentation of each tag.
  • - *
  • Check required and optional tags and the format of their content.
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -class PEAR_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The header comment parser for the current file. - * - * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser - */ - protected $commentParser = null; - - /** - * The current PHP_CodeSniffer_File object we are processing. - * - * @var PHP_CodeSniffer_File - */ - protected $currentFile = null; - - /** - * Tags in correct order and related info. - * - * @var array - */ - protected $tags = array( - 'category' => array( - 'required' => true, - 'allow_multiple' => false, - 'order_text' => 'precedes @package', - ), - 'package' => array( - 'required' => true, - 'allow_multiple' => false, - 'order_text' => 'follows @category', - ), - 'subpackage' => array( - 'required' => false, - 'allow_multiple' => false, - 'order_text' => 'follows @package', - ), - 'author' => array( - 'required' => true, - 'allow_multiple' => true, - 'order_text' => 'follows @subpackage (if used) or @package', - ), - 'copyright' => array( - 'required' => false, - 'allow_multiple' => true, - 'order_text' => 'follows @author', - ), - 'license' => array( - 'required' => true, - 'allow_multiple' => false, - 'order_text' => 'follows @copyright (if used) or @author', - ), - 'version' => array( - 'required' => false, - 'allow_multiple' => false, - 'order_text' => 'follows @license', - ), - 'link' => array( - 'required' => true, - 'allow_multiple' => true, - 'order_text' => 'follows @version', - ), - 'see' => array( - 'required' => false, - 'allow_multiple' => true, - 'order_text' => 'follows @link', - ), - 'since' => array( - 'required' => false, - 'allow_multiple' => false, - 'order_text' => 'follows @see (if used) or @link', - ), - 'deprecated' => array( - 'required' => false, - 'allow_multiple' => false, - 'order_text' => 'follows @since (if used) or @see (if used) or @link', - ), - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - $tokens = $phpcsFile->getTokens(); - - // Find the next non whitespace token. - $commentStart - = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - - // Allow declare() statements at the top of the file. - if ($tokens[$commentStart]['code'] === T_DECLARE) { - $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($commentStart + 1)); - $commentStart - = $phpcsFile->findNext(T_WHITESPACE, ($semicolon + 1), null, true); - } - - // Ignore vim header. - if ($tokens[$commentStart]['code'] === T_COMMENT) { - if (strstr($tokens[$commentStart]['content'], 'vim:') !== false) { - $commentStart = $phpcsFile->findNext( - T_WHITESPACE, - ($commentStart + 1), - null, - true - ); - } - } - - $errorToken = ($stackPtr + 1); - if (isset($tokens[$errorToken]) === false) { - $errorToken--; - } - - if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) { - // We are only interested if this is the first open tag. - return; - } else if ($tokens[$commentStart]['code'] === T_COMMENT) { - $error = 'You must use "/**" style comments for a file comment'; - $phpcsFile->addError($error, $errorToken, 'WrongStyle'); - return; - } else if ($commentStart === false - || $tokens[$commentStart]['code'] !== T_DOC_COMMENT - ) { - $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); - return; - } else { - - // Extract the header comment docblock. - $commentEnd = $phpcsFile->findNext( - T_DOC_COMMENT, - ($commentStart + 1), - null, - true - ); - - $commentEnd--; - - // Check if there is only 1 doc comment between the - // open tag and class token. - $nextToken = array( - T_ABSTRACT, - T_CLASS, - T_FUNCTION, - T_DOC_COMMENT, - ); - - $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1)); - if ($commentNext !== false - && $tokens[$commentNext]['code'] !== T_DOC_COMMENT - ) { - // Found a class token right after comment doc block. - $newlineToken = $phpcsFile->findNext( - T_WHITESPACE, - ($commentEnd + 1), - $commentNext, - false, - $phpcsFile->eolChar - ); - - if ($newlineToken !== false) { - $newlineToken = $phpcsFile->findNext( - T_WHITESPACE, - ($newlineToken + 1), - $commentNext, - false, - $phpcsFile->eolChar - ); - - if ($newlineToken === false) { - // No blank line between the class token and the doc block. - // The doc block is most likely a class comment. - $error = 'Missing file doc comment'; - $phpcsFile->addError($error, $errorToken, 'Missing'); - return; - } - } - }//end if - - $comment = $phpcsFile->getTokensAsString( - $commentStart, - ($commentEnd - $commentStart + 1) - ); - - // Parse the header comment docblock. - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'File doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - // No extra newline before short description. - $short = $comment->getShortComment(); - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before file comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBefore'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in file comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'DescriptionSpacing'); - } - - $newlineCount += $newlineBetween; - } - - // Exactly one blank line before tags. - $tags = $this->commentParser->getTagOrders(); - if (count($tags) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in file comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Check the PHP Version. - $this->processPHPVersion($commentStart, $commentEnd, $long); - - // Check each tag. - $this->processTags($commentStart, $commentEnd); - }//end if - - }//end process() - - - /** - * Check that the PHP version is specified. - * - * @param int $commentStart Position in the stack where the comment started. - * @param int $commentEnd Position in the stack where the comment ended. - * @param string $commentText The text of the function comment. - * - * @return void - */ - protected function processPHPVersion($commentStart, $commentEnd, $commentText) - { - if (strstr(strtolower($commentText), 'php version') === false) { - $error = 'PHP version not specified'; - $this->currentFile->addWarning($error, $commentEnd, 'MissingVersion'); - } - - }//end processPHPVersion() - - - /** - * Processes each required or optional tag. - * - * @param int $commentStart Position in the stack where the comment started. - * @param int $commentEnd Position in the stack where the comment ended. - * - * @return void - */ - protected function processTags($commentStart, $commentEnd) - { - $docBlock = (get_class($this) === 'PEAR_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; - $foundTags = $this->commentParser->getTagOrders(); - $orderIndex = 0; - $indentation = array(); - $longestTag = 0; - $errorPos = 0; - - foreach ($this->tags as $tag => $info) { - - // Required tag missing. - if ($info['required'] === true && in_array($tag, $foundTags) === false) { - $error = 'Missing @%s tag in %s comment'; - $data = array( - $tag, - $docBlock, - ); - $this->currentFile->addError($error, $commentEnd, 'MissingTag', $data); - continue; - } - - // Get the line number for current tag. - $tagName = ucfirst($tag); - if ($info['allow_multiple'] === true) { - $tagName .= 's'; - } - - $getMethod = 'get'.$tagName; - $tagElement = $this->commentParser->$getMethod(); - if (is_null($tagElement) === true || empty($tagElement) === true) { - continue; - } - - $errorPos = $commentStart; - if (is_array($tagElement) === false) { - $errorPos = ($commentStart + $tagElement->getLine()); - } - - // Get the tag order. - $foundIndexes = array_keys($foundTags, $tag); - - if (count($foundIndexes) > 1) { - // Multiple occurrence not allowed. - if ($info['allow_multiple'] === false) { - $error = 'Only 1 @%s tag is allowed in a %s comment'; - $data = array( - $tag, - $docBlock, - ); - $this->currentFile->addError($error, $errorPos, 'DuplicateTag', $data); - } else { - // Make sure same tags are grouped together. - $i = 0; - $count = $foundIndexes[0]; - foreach ($foundIndexes as $index) { - if ($index !== $count) { - $errorPosIndex - = ($errorPos + $tagElement[$i]->getLine()); - $error = '@%s tags must be grouped together'; - $data = array($tag); - $this->currentFile->addError($error, $errorPosIndex, 'TagsNotGrouped', $data); - } - - $i++; - $count++; - } - } - }//end if - - // Check tag order. - if ($foundIndexes[0] > $orderIndex) { - $orderIndex = $foundIndexes[0]; - } else { - if (is_array($tagElement) === true && empty($tagElement) === false) { - $errorPos += $tagElement[0]->getLine(); - } - - $error = 'The @%s tag is in the wrong order; the tag %s'; - $data = array( - $tag, - $info['order_text'], - ); - $this->currentFile->addError($error, $errorPos, 'WrongTagOrder', $data); - } - - // Store the indentation for checking. - $len = strlen($tag); - if ($len > $longestTag) { - $longestTag = $len; - } - - if (is_array($tagElement) === true) { - foreach ($tagElement as $key => $element) { - $indentation[] = array( - 'tag' => $tag, - 'space' => $this->getIndentation($tag, $element), - 'line' => $element->getLine(), - ); - } - } else { - $indentation[] = array( - 'tag' => $tag, - 'space' => $this->getIndentation($tag, $tagElement), - ); - } - - $method = 'process'.$tagName; - if (method_exists($this, $method) === true) { - // Process each tag if a method is defined. - call_user_func(array($this, $method), $errorPos); - } else { - if (is_array($tagElement) === true) { - foreach ($tagElement as $key => $element) { - $element->process( - $this->currentFile, - $commentStart, - $docBlock - ); - } - } else { - $tagElement->process( - $this->currentFile, - $commentStart, - $docBlock - ); - } - } - }//end foreach - - foreach ($indentation as $indentInfo) { - if ($indentInfo['space'] !== 0 - && $indentInfo['space'] !== ($longestTag + 1) - ) { - $expected = (($longestTag - strlen($indentInfo['tag'])) + 1); - $space = ($indentInfo['space'] - strlen($indentInfo['tag'])); - $error = '@%s tag comment indented incorrectly; expected %s spaces but found %s'; - $data = array( - $indentInfo['tag'], - $expected, - $space, - ); - - $getTagMethod = 'get'.ucfirst($indentInfo['tag']); - - if ($this->tags[$indentInfo['tag']]['allow_multiple'] === true) { - $line = $indentInfo['line']; - } else { - $tagElem = $this->commentParser->$getTagMethod(); - $line = $tagElem->getLine(); - } - - $this->currentFile->addError($error, ($commentStart + $line), 'TagIndent', $data); - } - } - - }//end processTags() - - - /** - * Get the indentation information of each tag. - * - * @param string $tagName The name of the - * doc comment - * element. - * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment - * element. - * - * @return void - */ - protected function getIndentation($tagName, $tagElement) - { - if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) { - if ($tagElement->getContent() !== '') { - return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' ')); - } - } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) { - if ($tagElement->getValue() !== '') { - return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' ')); - } - } - - return 0; - - }//end getIndentation() - - - /** - * Process the category tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processCategory($errorPos) - { - $category = $this->commentParser->getCategory(); - if ($category !== null) { - $content = $category->getContent(); - if ($content !== '') { - if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { - $newContent = str_replace(' ', '_', $content); - $nameBits = explode('_', $newContent); - $firstBit = array_shift($nameBits); - $newName = ucfirst($firstBit).'_'; - foreach ($nameBits as $bit) { - $newName .= ucfirst($bit).'_'; - } - - $error = 'Category name "%s" is not valid; consider "%s" instead'; - $validName = trim($newName, '_'); - $data = array( - $content, - $validName, - ); - $this->currentFile->addError($error, $errorPos, 'InvalidCategory', $data); - } - } else { - $error = '@category tag must contain a name'; - $this->currentFile->addError($error, $errorPos, 'EmptyCategory'); - } - } - - }//end processCategory() - - - /** - * Process the package tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processPackage($errorPos) - { - $package = $this->commentParser->getPackage(); - if ($package === null) { - return; - } - - $content = $package->getContent(); - if ($content === '') { - $error = '@package tag must contain a name'; - $this->currentFile->addError($error, $errorPos, 'EmptyPackage'); - return; - } - - if (PHP_CodeSniffer::isUnderscoreName($content) === true) { - return; - } - - $newContent = str_replace(' ', '_', $content); - $newContent = preg_replace('/[^A-Za-z_]/', '', $newContent); - $nameBits = explode('_', $newContent); - $firstBit = array_shift($nameBits); - $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; - foreach ($nameBits as $bit) { - $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - - $error = 'Package name "%s" is not valid; consider "%s" instead'; - $validName = trim($newName, '_'); - $data = array( - $content, - $validName, - ); - $this->currentFile->addError($error, $errorPos, 'InvalidPackage', $data); - - }//end processPackage() - - - /** - * Process the subpackage tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processSubpackage($errorPos) - { - $package = $this->commentParser->getSubpackage(); - if ($package !== null) { - $content = $package->getContent(); - if ($content !== '') { - if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { - $newContent = str_replace(' ', '_', $content); - $nameBits = explode('_', $newContent); - $firstBit = array_shift($nameBits); - $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; - foreach ($nameBits as $bit) { - $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - - $error = 'Subpackage name "%s" is not valid; consider "%s" instead'; - $validName = trim($newName, '_'); - $data = array( - $content, - $validName, - ); - $this->currentFile->addError($error, $errorPos, 'InvalidSubpackage', $data); - } - } else { - $error = '@subpackage tag must contain a name'; - $this->currentFile->addError($error, $errorPos, 'EmptySubpackage'); - } - } - - }//end processSubpackage() - - - /** - * Process the author tag(s) that this header comment has. - * - * This function is different from other _process functions - * as $authors is an array of SingleElements, so we work out - * the errorPos for each element separately - * - * @param int $commentStart The position in the stack where - * the comment started. - * - * @return void - */ - protected function processAuthors($commentStart) - { - $authors = $this->commentParser->getAuthors(); - // Report missing return. - if (empty($authors) === false) { - foreach ($authors as $author) { - $errorPos = ($commentStart + $author->getLine()); - $content = $author->getContent(); - if ($content !== '') { - $local = '\da-zA-Z-_+'; - // Dot character cannot be the first or last character - // in the local-part. - $localMiddle = $local.'.\w'; - if (preg_match('/^([^<]*)\s+<(['.$local.'](['.$localMiddle.']*['.$local.'])*@[\da-zA-Z][-.\w]*[\da-zA-Z]\.[a-zA-Z]{2,7})>$/', $content) === 0) { - $error = 'Content of the @author tag must be in the form "Display Name "'; - $this->currentFile->addError($error, $errorPos, 'InvalidAuthors'); - } - } else { - $error = 'Content missing for @author tag in %s comment'; - $docBlock = (get_class($this) === 'PEAR_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; - $data = array($docBlock); - $this->currentFile->addError($error, $errorPos, 'EmptyAuthors', $data); - } - } - } - - }//end processAuthors() - - - /** - * Process the copyright tags. - * - * @param int $commentStart The position in the stack where - * the comment started. - * - * @return void - */ - protected function processCopyrights($commentStart) - { - $copyrights = $this->commentParser->getCopyrights(); - foreach ($copyrights as $copyright) { - $errorPos = ($commentStart + $copyright->getLine()); - $content = $copyright->getContent(); - if ($content !== '') { - $matches = array(); - if (preg_match('/^([0-9]{4})((.{1})([0-9]{4}))? (.+)$/', $content, $matches) !== 0) { - // Check earliest-latest year order. - if ($matches[3] !== '') { - if ($matches[3] !== '-') { - $error = 'A hyphen must be used between the earliest and latest year'; - $this->currentFile->addError($error, $errorPos, 'CopyrightHyphen'); - } - - if ($matches[4] !== '' && $matches[4] < $matches[1]) { - $error = "Invalid year span \"$matches[1]$matches[3]$matches[4]\" found; consider \"$matches[4]-$matches[1]\" instead"; - $this->currentFile->addWarning($error, $errorPos, 'InvalidCopyright'); - } - } - } else { - $error = '@copyright tag must contain a year and the name of the copyright holder'; - $this->currentFile->addError($error, $errorPos, 'EmptyCopyright'); - } - } else { - $error = '@copyright tag must contain a year and the name of the copyright holder'; - $this->currentFile->addError($error, $errorPos, 'EmptyCopyright'); - }//end if - }//end if - - }//end processCopyrights() - - - /** - * Process the license tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processLicense($errorPos) - { - $license = $this->commentParser->getLicense(); - if ($license !== null) { - $value = $license->getValue(); - $comment = $license->getComment(); - if ($value === '' || $comment === '') { - $error = '@license tag must contain a URL and a license name'; - $this->currentFile->addError($error, $errorPos, 'EmptyLicense'); - } - } - - }//end processLicense() - - - /** - * Process the version tag. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processVersion($errorPos) - { - $version = $this->commentParser->getVersion(); - if ($version !== null) { - $content = $version->getContent(); - $matches = array(); - if (empty($content) === true) { - $error = 'Content missing for @version tag in file comment'; - $this->currentFile->addError($error, $errorPos, 'EmptyVersion'); - } else if (strstr($content, 'CVS:') === false - && strstr($content, 'SVN:') === false - && strstr($content, 'GIT:') === false - ) { - $error = 'Invalid version "%s" in file comment; consider "CVS: " or "SVN: " or "GIT: " instead'; - $data = array($content); - $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data); - } - } - - }//end processVersion() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php deleted file mode 100644 index 41b175413..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php +++ /dev/null @@ -1,490 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found'); -} - -/** - * Parses and verifies the doc comments for functions. - * - * Verifies that : - *
    - *
  • A comment exists
  • - *
  • There is a blank newline after the short description.
  • - *
  • There is a blank newline between the long and short description.
  • - *
  • There is a blank newline between the long description and tags.
  • - *
  • Parameter names represent those in the method.
  • - *
  • Parameter comments are in the correct order
  • - *
  • Parameter comments are complete
  • - *
  • A space is present before the first and after the last parameter
  • - *
  • A return type exists
  • - *
  • There must be one blank line between body and headline comments.
  • - *
  • Any throw tag must have an exception class.
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The name of the method that we are currently processing. - * - * @var string - */ - private $_methodName = ''; - - /** - * The position in the stack where the function token was found. - * - * @var int - */ - private $_functionToken = null; - - /** - * The position in the stack where the class token was found. - * - * @var int - */ - private $_classToken = null; - - /** - * The function comment parser for the current method. - * - * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser - */ - protected $commentParser = null; - - /** - * The current PHP_CodeSniffer_File object we are processing. - * - * @var PHP_CodeSniffer_File - */ - protected $currentFile = null; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $find = array( - T_COMMENT, - T_DOC_COMMENT, - T_CLASS, - T_FUNCTION, - T_OPEN_TAG, - ); - - $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1)); - - if ($commentEnd === false) { - return; - } - - $this->currentFile = $phpcsFile; - $tokens = $phpcsFile->getTokens(); - - // If the token that we found was a class or a function, then this - // function has no doc comment. - $code = $tokens[$commentEnd]['code']; - - if ($code === T_COMMENT) { - $error = 'You must use "/**" style comments for a function comment'; - $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); - return; - } else if ($code !== T_DOC_COMMENT) { - $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); - return; - } - - // If there is any code between the function keyword and the doc block - // then the doc block is not for us. - $ignore = PHP_CodeSniffer_Tokens::$scopeModifiers; - $ignore[] = T_STATIC; - $ignore[] = T_WHITESPACE; - $ignore[] = T_ABSTRACT; - $ignore[] = T_FINAL; - $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); - if ($prevToken !== $commentEnd) { - $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); - return; - } - - $this->_functionToken = $stackPtr; - - $this->_classToken = null; - foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) { - if ($condition === T_CLASS || $condition === T_INTERFACE) { - $this->_classToken = $condPtr; - break; - } - } - - // If the first T_OPEN_TAG is right before the comment, it is probably - // a file comment. - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); - if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { - // Is this the first open tag? - if ($stackPtr === 0 || $phpcsFile->findPrevious(T_OPEN_TAG, ($prevToken - 1)) === false) { - $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); - return; - } - } - - $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - $this->_methodName = $phpcsFile->getDeclarationName($stackPtr); - - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'Function doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - $this->processParams($commentStart); - $this->processReturn($commentStart, $commentEnd); - $this->processThrows($commentStart); - - // No extra newline before short description. - $short = $comment->getShortComment(); - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before function comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in function comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingAfterShort'); - } - - $newlineCount += $newlineBetween; - } - - // Exactly one blank line before tags. - $params = $this->commentParser->getTagOrders(); - if (count($params) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in function comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - }//end process() - - - /** - * Process any throw tags that this function comment has. - * - * @param int $commentStart The position in the stack where the - * comment started. - * - * @return void - */ - protected function processThrows($commentStart) - { - if (count($this->commentParser->getThrows()) === 0) { - return; - } - - foreach ($this->commentParser->getThrows() as $throw) { - - $exception = $throw->getValue(); - $errorPos = ($commentStart + $throw->getLine()); - - if ($exception === '') { - $error = '@throws tag must contain the exception class name'; - $this->currentFile->addError($error, $errorPos, 'EmptyThrows'); - } - } - - }//end processThrows() - - - /** - * Process the return comment of this function comment. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processReturn($commentStart, $commentEnd) - { - // Skip constructor and destructor. - $className = ''; - if ($this->_classToken !== null) { - $className = $this->currentFile->getDeclarationName($this->_classToken); - $className = strtolower(ltrim($className, '_')); - } - - $methodName = strtolower(ltrim($this->_methodName, '_')); - $isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct'); - - if ($isSpecialMethod === false && $methodName !== $className) { - // Report missing return tag. - if ($this->commentParser->getReturn() === null) { - $error = 'Missing @return tag in function comment'; - $this->currentFile->addError($error, $commentEnd, 'MissingReturn'); - } else if (trim($this->commentParser->getReturn()->getRawContent()) === '') { - $error = '@return tag is empty in function comment'; - $errorPos = ($commentStart + $this->commentParser->getReturn()->getLine()); - $this->currentFile->addError($error, $errorPos, 'EmptyReturn'); - } - } - - }//end processReturn() - - - /** - * Process the function parameter comments. - * - * @param int $commentStart The position in the stack where - * the comment started. - * - * @return void - */ - protected function processParams($commentStart) - { - $realParams = $this->currentFile->getMethodParameters($this->_functionToken); - - $params = $this->commentParser->getParams(); - $foundParams = array(); - - if (empty($params) === false) { - - $lastParm = (count($params) - 1); - if (substr_count($params[$lastParm]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) { - $error = 'Last parameter comment requires a blank newline after it'; - $errorPos = ($params[$lastParm]->getLine() + $commentStart); - $this->currentFile->addError($error, $errorPos, 'SpacingAfterParams'); - } - - // Parameters must appear immediately after the comment. - if ($params[0]->getOrder() !== 2) { - $error = 'Parameters must appear immediately after the comment'; - $errorPos = ($params[0]->getLine() + $commentStart); - $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParams'); - } - - $previousParam = null; - $spaceBeforeVar = 10000; - $spaceBeforeComment = 10000; - $longestType = 0; - $longestVar = 0; - - foreach ($params as $param) { - - $paramComment = trim($param->getComment()); - $errorPos = ($param->getLine() + $commentStart); - - // Make sure that there is only one space before the var type. - if ($param->getWhitespaceBeforeType() !== ' ') { - $error = 'Expected 1 space before variable type'; - $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParamType'); - } - - $spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' '); - if ($spaceCount < $spaceBeforeVar) { - $spaceBeforeVar = $spaceCount; - $longestType = $errorPos; - } - - $spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' '); - - if ($spaceCount < $spaceBeforeComment && $paramComment !== '') { - $spaceBeforeComment = $spaceCount; - $longestVar = $errorPos; - } - - // Make sure they are in the correct order, - // and have the correct name. - $pos = $param->getPosition(); - - $paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]'; - - if ($previousParam !== null) { - $previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN'; - - // Check to see if the parameters align properly. - if ($param->alignsVariableWith($previousParam) === false) { - $error = 'The variable names for parameters %s (%s) and %s (%s) do not align'; - $data = array( - $previousName, - ($pos - 1), - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'ParameterNamesNotAligned', $data); - } - - if ($param->alignsCommentWith($previousParam) === false) { - $error = 'The comments for parameters %s (%s) and %s (%s) do not align'; - $data = array( - $previousName, - ($pos - 1), - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'ParameterCommentsNotAligned', $data); - } - }//end if - - // Make sure the names of the parameter comment matches the - // actual parameter. - if (isset($realParams[($pos - 1)]) === true) { - $realName = $realParams[($pos - 1)]['name']; - $foundParams[] = $realName; - - // Append ampersand to name if passing by reference. - if ($realParams[($pos - 1)]['pass_by_reference'] === true) { - $realName = '&'.$realName; - } - - if ($realName !== $paramName) { - $code = 'ParamNameNoMatch'; - $data = array( - $paramName, - $realName, - $pos, - ); - - $error = 'Doc comment for var %s does not match '; - if (strtolower($paramName) === strtolower($realName)) { - $error .= 'case of '; - $code = 'ParamNameNoCaseMatch'; - } - - $error .= 'actual variable name %s at position %s'; - - $this->currentFile->addError($error, $errorPos, $code, $data); - } - } else { - // We must have an extra parameter comment. - $error = 'Superfluous doc comment at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'ExtraParamComment'); - } - - if ($param->getVarName() === '') { - $error = 'Missing parameter name at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'MissingParamName'); - } - - if ($param->getType() === '') { - $error = 'Missing type at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'MissingParamType'); - } - - if ($paramComment === '') { - $error = 'Missing comment for param "%s" at position %s'; - $data = array( - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'MissingParamComment', $data); - } - - $previousParam = $param; - - }//end foreach - - if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) { - $error = 'Expected 1 space after the longest type'; - $this->currentFile->addError($error, $longestType, 'SpacingAfterLongType'); - } - - if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { - $error = 'Expected 1 space after the longest variable name'; - $this->currentFile->addError($error, $longestVar, 'SpacingAfterLongName'); - } - - }//end if - - $realNames = array(); - foreach ($realParams as $realParam) { - $realNames[] = $realParam['name']; - } - - // Report and missing comments. - $diff = array_diff($realNames, $foundParams); - foreach ($diff as $neededParam) { - if (count($params) !== 0) { - $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); - } else { - $errorPos = $commentStart; - } - - $error = 'Doc comment for "%s" missing'; - $data = array($neededParam); - $this->currentFile->addError($error, $errorPos, 'MissingParamTag', $data); - } - - }//end processParams() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php deleted file mode 100644 index d5ed16d1e..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PHP_CodeSniffer_Sniffs_PEAR_Commenting_InlineCommentSniff. - * - * Checks that no perl-style comments are used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_COMMENT); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['content']{0} === '#') { - $error = 'Perl-style comments are not allowed. Use "// Comment."'; - $error .= ' or "/* comment */" instead.'; - $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php deleted file mode 100644 index 7b91e6286..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); -} - -/** - * Verifies that control statements conform to their coding standards. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff -{ - - /** - * If true, comments will be ignored if they are found in the code. - * - * @var boolean - */ - public $ignoreComments = true; - - - /** - * Returns the patterns that this test wishes to verify. - * - * @return array(string) - */ - protected function getPatterns() - { - return array( - 'do {EOL...} while (...);EOL', - 'while (...) {EOL', - 'for (...) {EOL', - 'if (...) {EOL', - 'foreach (...) {EOL', - '} else if (...) {EOL', - '} elseif (...) {EOL', - '} else {EOL', - 'do {EOL', - ); - - }//end getPatterns() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php deleted file mode 100644 index be99d2cfa..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php +++ /dev/null @@ -1,189 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_ControlStructures_MultiLineConditionSniff. - * - * Ensure multi-line IF conditions are defined correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_ControlStructures_MultiLineConditionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_ELSEIF, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We need to work out how far indented the if statement - // itself is, so we can work out how far to indent conditions. - $statementIndent = 0; - for ($i = ($stackPtr - 1); $i >= 0; $i--) { - if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { - $i++; - break; - } - } - - if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) { - $statementIndent = strlen($tokens[$i]['content']); - } - - // Each line between the parenthesis should be indented 4 spaces - // and start with an operator, unless the line is inside a - // function call, in which case it is ignored. - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - $lastLine = $tokens[$openBracket]['line']; - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - if ($tokens[$i]['line'] !== $lastLine) { - if ($tokens[$i]['line'] === $tokens[$closeBracket]['line']) { - $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true); - if ($next !== $closeBracket) { - // Closing bracket is on the same line as a condition. - $error = 'Closing parenthesis of a multi-line IF statement must be on a new line'; - $phpcsFile->addError($error, $i, 'CloseBracketNewLine'); - $expectedIndent = ($statementIndent + $this->indent); - } else { - // Closing brace needs to be indented to the same level - // as the function. - $expectedIndent = $statementIndent; - } - } else { - $expectedIndent = ($statementIndent + $this->indent); - } - - // We changed lines, so this should be a whitespace indent token. - if ($tokens[$i]['code'] !== T_WHITESPACE) { - $foundIndent = 0; - } else { - $foundIndent = strlen($tokens[$i]['content']); - } - - if ($expectedIndent !== $foundIndent) { - $error = 'Multi-line IF statement not indented correctly; expected %s spaces but found %s'; - $data = array( - $expectedIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $i, 'Alignment', $data); - } - - if ($tokens[$i]['line'] !== $tokens[$closeBracket]['line']) { - $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true); - if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$booleanOperators) === false) { - $error = 'Each line in a multi-line IF statement must begin with a boolean operator'; - $phpcsFile->addError($error, $i, 'StartWithBoolean'); - } - } - - $lastLine = $tokens[$i]['line']; - }//end if - - if ($tokens[$i]['code'] === T_STRING) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); - if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { - // This is a function call, so skip to the end as they - // have their own indentation rules. - $i = $tokens[$next]['parenthesis_closer']; - $lastLine = $tokens[$i]['line']; - continue; - } - } - }//end for - - // From here on, we are checking the spacing of the opening and closing - // braces. If this IF statement does not use braces, we end here. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return; - } - - // The opening brace needs to be one space away from the closing parenthesis. - if ($tokens[($closeBracket + 1)]['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($tokens[($closeBracket + 1)]['content'] === $phpcsFile->eolChar) { - $length = -1; - } else { - $length = strlen($tokens[($closeBracket + 1)]['content']); - } - - if ($length !== 1) { - $data = array($length); - $code = 'SpaceBeforeOpenBrace'; - - $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found '; - if ($length === -1) { - $error .= 'newline'; - $code = 'NewlineBeforeOpenBrace'; - } else { - $error .= '%s spaces'; - } - - $phpcsFile->addError($error, ($closeBracket + 1), $code, $data); - } - - // And just in case they do something funny before the brace... - $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true); - if ($next !== false - && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET - && $tokens[$next]['code'] !== T_COLON - ) { - $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement'; - $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php deleted file mode 100644 index 187061d34..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php +++ /dev/null @@ -1,137 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Files_IncludingFileSniff. - * - * Checks that the include_once is used in conditional situations, and - * require_once is used elsewhere. Also checks that brackets do not surround - * the file being included. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Files_IncludingFileSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * Conditions that should use include_once - * - * @var array(int) - */ - private static $_conditions = array( - T_IF, - T_ELSE, - T_ELSEIF, - T_SWITCH, - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_INCLUDE_ONCE, - T_REQUIRE_ONCE, - T_REQUIRE, - T_INCLUDE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS) { - $error = '"%s" is a statement not a function; no parentheses are required'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $stackPtr, 'BracketsNotRequired', $data); - } - - $inCondition = (count($tokens[$stackPtr]['conditions']) !== 0) ? true : false; - - // Check to see if this including statement is within the parenthesis - // of a condition. If that's the case then we need to process it as being - // within a condition, as they are checking the return value. - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - foreach ($tokens[$stackPtr]['nested_parenthesis'] as $left => $right) { - if (isset($tokens[$left]['parenthesis_owner']) === true) { - $inCondition = true; - } - } - } - - // Check to see if they are assigning the return value of this - // including call. If they are then they are probably checking it, so - // it's conditional. - $previous = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if (in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { - // The have assigned the return value to it, so its conditional. - $inCondition = true; - } - - $tokenCode = $tokens[$stackPtr]['code']; - if ($inCondition === true) { - // We are inside a conditional statement. We need an include_once. - if ($tokenCode === T_REQUIRE_ONCE) { - $error = 'File is being conditionally included; '; - $error .= 'use "include_once" instead'; - $phpcsFile->addError($error, $stackPtr, 'UseIncludeOnce'); - } else if ($tokenCode === T_REQUIRE) { - $error = 'File is being conditionally included; '; - $error .= 'use "include" instead'; - $phpcsFile->addError($error, $stackPtr, 'UseInclude'); - } - } else { - // We are unconditionally including, we need a require_once. - if ($tokenCode === T_INCLUDE_ONCE) { - $error = 'File is being unconditionally included; '; - $error .= 'use "require_once" instead'; - $phpcsFile->addError($error, $stackPtr, 'UseRequireOnce'); - } else if ($tokenCode === T_INCLUDE) { - $error = 'File is being unconditionally included; '; - $error .= 'use "require" instead'; - $phpcsFile->addError($error, $stackPtr, 'UseRequire'); - } - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php deleted file mode 100644 index 292964067..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Formatting_MultiLineAssignmentSniff. - * - * If an assignment goes over two lines, ensure the equal sign is indented. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Formatting_MultiLineAssignmentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_EQUAL); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Equal sign can't be the last thing on the line. - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($next === false) { - // Bad assignment. - return; - } - - if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { - $error = 'Multi-line assignments must have the equal sign on the second line'; - $phpcsFile->addError($error, $stackPtr, 'EqualSignLine'); - return; - } - - // Make sure it is the first thing on the line, otherwise we ignore it. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), false, true); - if ($prev === false) { - // Bad assignment. - return; - } - - if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { - return; - } - - // Find the required indent based on the ident of the previous line. - $assignmentIndent = 0; - $prevLine = $tokens[$prev]['line']; - for ($i = ($prev - 1); $i >= 0; $i--) { - if ($tokens[$i]['line'] !== $prevLine) { - $i++; - break; - } - } - - if ($tokens[$i]['code'] === T_WHITESPACE) { - $assignmentIndent = strlen($tokens[$i]['content']); - } - - // Find the actual indent. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1)); - - $expectedIndent = ($assignmentIndent + $this->indent); - $foundIndent = strlen($tokens[$prev]['content']); - if ($foundIndent !== $expectedIndent) { - $error = 'Multi-line assignment not indented correctly; expected %s spaces but found %s'; - $data = array( - $expectedIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $stackPtr, 'Indent', $data); - } - - }//end process() - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php deleted file mode 100644 index 5001309a7..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php +++ /dev/null @@ -1,335 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Functions_FunctionCallSignatureSniff. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Functions_FunctionCallSignatureSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - /** - * If TRUE, multiple arguments can be defined per line in a multi-line call. - * - * @var bool - */ - public $allowMultipleArguments = true; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Find the next non-empty token. - $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - - if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { - // Not a function call. - return; - } - - if (isset($tokens[$openBracket]['parenthesis_closer']) === false) { - // Not a function call. - return; - } - - // Find the previous non-empty token. - $search = PHP_CodeSniffer_Tokens::$emptyTokens; - $search[] = T_BITWISE_AND; - $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true); - if ($tokens[$previous]['code'] === T_FUNCTION) { - // It's a function definition, not a function call. - return; - } - - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - - if (($stackPtr + 1) !== $openBracket) { - // Checking this: $value = my_function[*](...). - $error = 'Space before opening parenthesis of function call prohibited'; - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeOpenBracket'); - } - - $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true); - if ($tokens[$next]['code'] === T_SEMICOLON) { - if (in_array($tokens[($closeBracket + 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $error = 'Space after closing parenthesis of function call prohibited'; - $phpcsFile->addError($error, $closeBracket, 'SpaceAfterCloseBracket'); - } - } - - // Check if this is a single line or multi-line function call. - if ($this->isMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens) === true) { - $this->processMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); - } else { - $this->processSingleLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); - } - - }//end process() - - - /** - * Processes single-line calls. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param int $openBracket The position of the opening bracket - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) - { - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) { - return true; - } - - return false; - - }//end isMultiLineCall() - - - /** - * Processes single-line calls. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param int $openBracket The position of the opening bracket - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function processSingleLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) - { - if ($tokens[($openBracket + 1)]['code'] === T_WHITESPACE) { - // Checking this: $value = my_function([*]...). - $error = 'Space after opening parenthesis of function call prohibited'; - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpenBracket'); - } - - $closer = $tokens[$openBracket]['parenthesis_closer']; - - if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) { - // Checking this: $value = my_function(...[*]). - $between = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); - - // Only throw an error if there is some content between the parenthesis. - // i.e., Checking for this: $value = my_function(). - // If there is no content, then we would have thrown an error in the - // previous IF statement because it would look like this: - // $value = my_function( ). - if ($between !== $closer) { - $error = 'Space before closing parenthesis of function call prohibited'; - $phpcsFile->addError($error, $closer, 'SpaceBeforeCloseBracket'); - } - } - - }//end processSingleLineCall() - - - /** - * Processes multi-line calls. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param int $openBracket The position of the openning bracket - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function processMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) - { - // We need to work out how far indented the function - // call itself is, so we can work out how far to - // indent the arguments. - $functionIndent = 0; - for ($i = ($stackPtr - 1); $i >= 0; $i--) { - if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { - $i++; - break; - } - } - - if ($tokens[$i]['code'] === T_WHITESPACE) { - $functionIndent = strlen($tokens[$i]['content']); - } - - // Each line between the parenthesis should be indented n spaces. - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - $lastLine = $tokens[$openBracket]['line']; - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - // Skip nested function calls. - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - $i = $tokens[$i]['parenthesis_closer']; - $lastLine = $tokens[$i]['line']; - continue; - } - - if ($tokens[$i]['line'] !== $lastLine) { - $lastLine = $tokens[$i]['line']; - - // Ignore heredoc indentation. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$heredocTokens) === true) { - continue; - } - - // Ignore multi-line string indentation. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { - if ($tokens[$i]['code'] === $tokens[($i - 1)]['code']) { - continue; - } - } - - // We changed lines, so this should be a whitespace indent token, but first make - // sure it isn't a blank line because we don't need to check indent unless there - // is actually some code to indent. - if ($tokens[$i]['code'] === T_WHITESPACE) { - $nextCode = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), ($closeBracket + 1), true); - if ($tokens[$nextCode]['line'] !== $lastLine) { - $error = 'Empty lines are not allowed in multi-line function calls'; - $phpcsFile->addError($error, $i, 'EmptyLine'); - continue; - } - } else { - $nextCode = $i; - } - - // Check if the next line contains an object operator, if so rely on - // the ObjectOperatorIndentSniff to test the indent. - if ($tokens[$nextCode]['type'] === 'T_OBJECT_OPERATOR') { - continue; - } - - if ($nextCode === $closeBracket) { - // Closing brace needs to be indented to the same level - // as the function call. - $expectedIndent = $functionIndent; - } else { - $expectedIndent = ($functionIndent + $this->indent); - } - - if ($tokens[$i]['code'] !== T_WHITESPACE) { - // Just check if it is a multi-line block comment. If so, we can - // calculate the indent from the whitespace before the content. - if ($tokens[$i]['code'] === T_COMMENT - && $tokens[($i - 1)]['code'] === T_COMMENT - ) { - $trimmed = ltrim($tokens[$i]['content']); - $foundIndent = (strlen($tokens[$i]['content']) - strlen($trimmed)); - } else { - $foundIndent = 0; - } - } else { - $foundIndent = strlen($tokens[$i]['content']); - } - - if ($expectedIndent !== $foundIndent) { - $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s'; - $data = array( - $expectedIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $i, 'Indent', $data); - } - }//end if - - // Skip the rest of a closure. - if ($tokens[$i]['code'] === T_CLOSURE) { - $i = $tokens[$i]['scope_closer']; - $lastLine = $tokens[$i]['line']; - continue; - } - - // Skip the rest of a short array. - if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) { - $i = $tokens[$i]['bracket_closer']; - $lastLine = $tokens[$i]['line']; - continue; - } - - if ($this->allowMultipleArguments === false && $tokens[$i]['code'] === T_COMMA) { - // Comma has to be the last token on the line. - $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), ($i + 1), $closeBracket, true); - if ($next !== false - && $tokens[$i]['line'] === $tokens[$next]['line'] - ) { - $error = 'Only one argument is allowed per line in a multi-line function call'; - $phpcsFile->addError($error, $next, 'MultipleArguments'); - } - } - }//end for - - if ($tokens[($openBracket + 1)]['content'] !== $phpcsFile->eolChar) { - $error = 'Opening parenthesis of a multi-line function call must be the last content on the line'; - $phpcsFile->addError($error, $stackPtr, 'ContentAfterOpenBracket'); - } - - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true); - if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { - $error = 'Closing parenthesis of a multi-line function call must be on a line by itself'; - $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); - } - - }//end processMultiLineCall() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php deleted file mode 100644 index b46a7ee92..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php +++ /dev/null @@ -1,337 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Functions_FunctionDeclarationSniff. - * - * Ensure single and multi-line function declarations are defined correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Functions_FunctionDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_FUNCTION, - T_CLOSURE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $spaces = 0; - if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { - $spaces = strlen($tokens[($stackPtr + 1)]['content']); - } - - if ($spaces !== 1) { - $error = 'Expected 1 space after FUNCTION keyword; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterFunction', $data); - } - - // Must be one space before and after USE keyword for closures. - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); - if ($use !== false) { - if ($tokens[($use + 1)]['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($tokens[($use + 1)]['content'] === "\t") { - $length = '\t'; - } else { - $length = strlen($tokens[($use + 1)]['content']); - } - - if ($length !== 1) { - $error = 'Expected 1 space after USE keyword; found %s'; - $data = array($length); - $phpcsFile->addError($error, $use, 'SpaceAfterUse', $data); - } - - if ($tokens[($use - 1)]['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($tokens[($use - 1)]['content'] === "\t") { - $length = '\t'; - } else { - $length = strlen($tokens[($use - 1)]['content']); - } - - if ($length !== 1) { - $error = 'Expected 1 space before USE keyword; found %s'; - $data = array($length); - $phpcsFile->addError($error, $use, 'SpaceBeforeUse', $data); - } - }//end if - }//end if - - // Check if this is a single line or multi-line declaration. - $singleLine = true; - if ($tokens[$openBracket]['line'] === $tokens[$closeBracket]['line']) { - // Closures may use the USE keyword and so be multi-line in this way. - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - if ($use !== false) { - // If the opening and closing parenthesis of the use statement - // are also on the same line, this is a single line declaration. - $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); - $close = $tokens[$open]['parenthesis_closer']; - if ($tokens[$open]['line'] !== $tokens[$close]['line']) { - $singleLine = false; - } - } - } - } else { - $singleLine = false; - } - - if ($singleLine === true) { - $this->processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens); - } else { - $this->processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens); - } - - }//end process() - - - /** - * Processes single-line declarations. - * - * Just uses the Generic BSD-Allman brace sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function processSingleLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) - { - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff not found'); - } - - $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff(); - } else { - if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff not found'); - } - - $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff(); - } - - $sniff->process($phpcsFile, $stackPtr); - - }//end processSingleLineDeclaration() - - - /** - * Processes mutli-line declarations. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) - { - // We need to work out how far indented the function - // declaration itself is, so we can work out how far to - // indent parameters. - $functionIndent = 0; - for ($i = ($stackPtr - 1); $i >= 0; $i--) { - if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { - $i++; - break; - } - } - - if ($tokens[$i]['code'] === T_WHITESPACE) { - $functionIndent = strlen($tokens[$i]['content']); - } - - // The closing parenthesis must be on a new line, even - // when checking abstract function definitions. - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - $prev = $phpcsFile->findPrevious( - T_WHITESPACE, - ($closeBracket - 1), - null, - true - ); - - if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) { - if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { - $error = 'The closing parenthesis of a multi-line function declaration must be on a new line'; - $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); - } - } - - // If this is a closure and is using a USE statement, the closing - // parenthesis we need to look at from now on is the closing parenthesis - // of the USE statement. - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); - if ($use !== false) { - $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); - $closeBracket = $tokens[$open]['parenthesis_closer']; - - $prev = $phpcsFile->findPrevious( - T_WHITESPACE, - ($closeBracket - 1), - null, - true - ); - - if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) { - if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { - $error = 'The closing parenthesis of a multi-line use declaration must be on a new line'; - $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine'); - } - } - }//end if - }//end if - - // Each line between the parenthesis should be indented 4 spaces. - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $lastLine = $tokens[$openBracket]['line']; - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - if ($tokens[$i]['line'] !== $lastLine) { - if ($i === $tokens[$stackPtr]['parenthesis_closer'] - || ($tokens[$i]['code'] === T_WHITESPACE - && (($i + 1) === $closeBracket - || ($i + 1) === $tokens[$stackPtr]['parenthesis_closer'])) - ) { - // Closing braces need to be indented to the same level - // as the function. - $expectedIndent = $functionIndent; - } else { - $expectedIndent = ($functionIndent + $this->indent); - } - - // We changed lines, so this should be a whitespace indent token. - if ($tokens[$i]['code'] !== T_WHITESPACE) { - $foundIndent = 0; - } else { - $foundIndent = strlen($tokens[$i]['content']); - } - - if ($expectedIndent !== $foundIndent) { - $error = 'Multi-line function declaration not indented correctly; expected %s spaces but found %s'; - $data = array( - $expectedIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $i, 'Indent', $data); - } - - $lastLine = $tokens[$i]['line']; - }//end if - - if ($tokens[$i]['code'] === T_ARRAY) { - // Skip arrays as they have their own indentation rules. - $i = $tokens[$i]['parenthesis_closer']; - $lastLine = $tokens[$i]['line']; - continue; - } - }//end for - - if (isset($tokens[$stackPtr]['scope_opener']) === true) { - // The openning brace needs to be one space away - // from the closing parenthesis. - $next = $tokens[($closeBracket + 1)]; - if ($next['code'] !== T_WHITESPACE) { - $length = 0; - } else if ($next['content'] === $phpcsFile->eolChar) { - $length = -1; - } else { - $length = strlen($next['content']); - } - - if ($length !== 1) { - $data = array($length); - $code = 'SpaceBeforeOpenBrace'; - - $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found '; - if ($length === -1) { - $error .= 'newline'; - $code = 'NewlineBeforeOpenBrace'; - } else { - $error .= '%s spaces'; - } - - $phpcsFile->addError($error, ($closeBracket + 1), $code, $data); - return; - } - - // And just in case they do something funny before the brace... - $next = $phpcsFile->findNext( - T_WHITESPACE, - ($closeBracket + 1), - null, - true - ); - - if ($next !== false && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET) { - $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration'; - $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace'); - } - }//end if - - }//end processMultiLineDeclaration() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php deleted file mode 100644 index 2b2f80fc8..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Functions_ValidDefaultValueSniff. - * - * A Sniff to ensure that parameters defined for a function that have a default - * value come at the end of the function signature. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_Functions_ValidDefaultValueSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $argStart = $tokens[$stackPtr]['parenthesis_opener']; - $argEnd = $tokens[$stackPtr]['parenthesis_closer']; - - // Flag for when we have found a default in our arg list. - // If there is a value without a default after this, it is an error. - $defaultFound = false; - - $nextArg = $argStart; - while (($nextArg = $phpcsFile->findNext(T_VARIABLE, ($nextArg + 1), $argEnd)) !== false) { - $argHasDefault = self::_argHasDefault($phpcsFile, $nextArg); - if (($argHasDefault === false) && ($defaultFound === true)) { - $error = 'Arguments with default values must be at the end of the argument list'; - $phpcsFile->addError($error, $nextArg, 'NotAtEnd'); - return; - } - - if ($argHasDefault === true) { - $defaultFound = true; - } - } - - }//end process() - - - /** - * Returns true if the passed argument has a default value. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $argPtr The position of the argument - * in the stack. - * - * @return bool - */ - private static function _argHasDefault(PHP_CodeSniffer_File $phpcsFile, $argPtr) - { - $tokens = $phpcsFile->getTokens(); - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($argPtr + 1), null, true); - if ($tokens[$nextToken]['code'] !== T_EQUAL) { - return false; - } - - return true; - - }//end _argHasDefault() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php deleted file mode 100644 index b0f021f2b..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_NamingConventions_ValidClassNameSniff. - * - * Ensures class and interface names start with a capital letter - * and use _ separators. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_NamingConventions_ValidClassNameSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $className = $phpcsFile->findNext(T_STRING, $stackPtr); - $name = trim($tokens[$className]['content']); - $errorData = array(ucfirst($tokens[$stackPtr]['content'])); - - // Make sure the first letter is a capital. - if (preg_match('|^[A-Z]|', $name) === 0) { - $error = '%s name must begin with a capital letter'; - $phpcsFile->addError($error, $stackPtr, 'StartWithCapital', $errorData); - } - - // Check that each new word starts with a capital as well, but don't - // check the first word, as it is checked above. - $validName = true; - $nameBits = explode('_', $name); - $firstBit = array_shift($nameBits); - foreach ($nameBits as $bit) { - if ($bit === '' || $bit{0} !== strtoupper($bit{0})) { - $validName = false; - break; - } - } - - if ($validName === false) { - // Strip underscores because they cause the suggested name - // to be incorrect. - $nameBits = explode('_', trim($name, '_')); - $firstBit = array_shift($nameBits); - if ($firstBit === '') { - $error = '%s name is not valid'; - $phpcsFile->addError($error, $stackPtr, 'Invalid', $errorData); - } else { - $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; - foreach ($nameBits as $bit) { - if ($bit !== '') { - $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - } - - $newName = rtrim($newName, '_'); - $error = '%s name is not valid; consider %s instead'; - $data = $errorData; - $data[] = $newName; - $phpcsFile->addError($error, $stackPtr, 'Invalid', $data); - } - }//end if - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php deleted file mode 100644 index d016b5ff0..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php +++ /dev/null @@ -1,285 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff. - * - * Ensures method names are correct depending on whether they are public - * or private, and that functions are named correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - /** - * A list of all PHP magic methods. - * - * @var array - */ - protected $magicMethods = array( - 'construct', - 'destruct', - 'call', - 'callstatic', - 'get', - 'set', - 'isset', - 'unset', - 'sleep', - 'wakeup', - 'tostring', - 'set_state', - 'clone', - 'invoke', - 'call', - ); - - /** - * A list of all PHP magic functions. - * - * @var array - */ - protected $magicFunctions = array('autoload'); - - - /** - * Constructs a PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); - - }//end __construct() - - - /** - * Processes the tokens within the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * @param int $currScope The position of the current scope. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $methodName = $phpcsFile->getDeclarationName($stackPtr); - if ($methodName === null) { - // Ignore closures. - return; - } - - $className = $phpcsFile->getDeclarationName($currScope); - $errorData = array($className.'::'.$methodName); - - // Is this a magic method. i.e., is prefixed with "__" ? - if (preg_match('|^__|', $methodName) !== 0) { - $magicPart = strtolower(substr($methodName, 2)); - if (in_array($magicPart, $this->magicMethods) === false) { - $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; - $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData); - } - - return; - } - - // PHP4 constructors are allowed to break our rules. - if ($methodName === $className) { - return; - } - - // PHP4 destructors are allowed to break our rules. - if ($methodName === '_'.$className) { - return; - } - - $methodProps = $phpcsFile->getMethodProperties($stackPtr); - $isPublic = ($methodProps['scope'] === 'private') ? false : true; - $scope = $methodProps['scope']; - $scopeSpecified = $methodProps['scope_specified']; - - // If it's a private method, it must have an underscore on the front. - if ($isPublic === false && $methodName{0} !== '_') { - $error = 'Private method name "%s" must be prefixed with an underscore'; - $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData); - return; - } - - // If it's not a private method, it must not have an underscore on the front. - if ($isPublic === true && $scopeSpecified === true && $methodName{0} === '_') { - $error = '%s method name "%s" must not be prefixed with an underscore'; - $data = array( - ucfirst($scope), - $errorData[0], - ); - $phpcsFile->addError($error, $stackPtr, 'PublicUnderscore', $data); - return; - } - - // If the scope was specified on the method, then the method must be - // camel caps and an underscore should be checked for. If it wasn't - // specified, treat it like a public method and remove the underscore - // prefix if there is one because we cant determine if it is private or - // public. - $testMethodName = $methodName; - if ($scopeSpecified === false && $methodName{0} === '_') { - $testMethodName = substr($methodName, 1); - } - - if (PHP_CodeSniffer::isCamelCaps($testMethodName, false, $isPublic, false) === false) { - if ($scopeSpecified === true) { - $error = '%s method name "%s" is not in camel caps format'; - $data = array( - ucfirst($scope), - $errorData[0], - ); - $phpcsFile->addError($error, $stackPtr, 'ScopeNotCamelCaps', $data); - } else { - $error = 'Method name "%s" is not in camel caps format'; - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); - } - - return; - } - - }//end processTokenWithinScope() - - - /** - * Processes the tokens outside the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * - * @return void - */ - protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $functionName = $phpcsFile->getDeclarationName($stackPtr); - if ($functionName === null) { - // Ignore closures. - return; - } - - $errorData = array($functionName); - - // Is this a magic function. i.e., it is prefixed with "__". - if (preg_match('|^__|', $functionName) !== 0) { - $magicPart = strtolower(substr($functionName, 2)); - if (in_array($magicPart, $this->magicFunctions) === false) { - $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; - $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); - } - - return; - } - - // Function names can be in two parts; the package name and - // the function name. - $packagePart = ''; - $camelCapsPart = ''; - $underscorePos = strrpos($functionName, '_'); - if ($underscorePos === false) { - $camelCapsPart = $functionName; - } else { - $packagePart = substr($functionName, 0, $underscorePos); - $camelCapsPart = substr($functionName, ($underscorePos + 1)); - - // We don't care about _'s on the front. - $packagePart = ltrim($packagePart, '_'); - } - - // If it has a package part, make sure the first letter is a capital. - if ($packagePart !== '') { - if ($functionName{0} === '_') { - $error = 'Function name "%s" is invalid; only private methods should be prefixed with an underscore'; - $phpcsFile->addError($error, $stackPtr, 'FunctionUnderscore', $errorData); - return; - } - - if ($functionName{0} !== strtoupper($functionName{0})) { - $error = 'Function name "%s" is prefixed with a package name but does not begin with a capital letter'; - $phpcsFile->addError($error, $stackPtr, 'FunctionNoCapital', $errorData); - return; - } - } - - // If it doesn't have a camel caps part, it's not valid. - if (trim($camelCapsPart) === '') { - $error = 'Function name "%s" is not valid; name appears incomplete'; - $phpcsFile->addError($error, $stackPtr, 'FunctionInvalid', $errorData); - return; - } - - $validName = true; - $newPackagePart = $packagePart; - $newCamelCapsPart = $camelCapsPart; - - // Every function must have a camel caps part, so check that first. - if (PHP_CodeSniffer::isCamelCaps($camelCapsPart, false, true, false) === false) { - $validName = false; - $newCamelCapsPart = strtolower($camelCapsPart{0}).substr($camelCapsPart, 1); - } - - if ($packagePart !== '') { - // Check that each new word starts with a capital. - $nameBits = explode('_', $packagePart); - foreach ($nameBits as $bit) { - if ($bit{0} !== strtoupper($bit{0})) { - $newPackagePart = ''; - foreach ($nameBits as $bit) { - $newPackagePart .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - - $validName = false; - break; - } - } - } - - if ($validName === false) { - $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; - if ($newPackagePart === '') { - $newName = $newCamelCapsPart; - } else { - $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; - } - - $error = 'Function name "%s" is invalid; consider "%s" instead'; - $data = $errorData; - $data[] = $newName; - $phpcsFile->addError($error, $stackPtr, 'FunctionNameInvalid', $data); - } - - }//end processTokenOutsideScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php deleted file mode 100644 index 1877ea93d..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * PEAR_Sniffs_NamingConventions_ValidVariableNameSniff. - * - * Checks the naming of member variables. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - - /** - * Processes class member variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $memberProps = $phpcsFile->getMemberProperties($stackPtr); - if (empty($memberProps) === true) { - return; - } - - $memberName = ltrim($tokens[$stackPtr]['content'], '$'); - $isPublic = ($memberProps['scope'] === 'private') ? false : true; - $scope = $memberProps['scope']; - $scopeSpecified = $memberProps['scope_specified']; - - // If it's a private member, it must have an underscore on the front. - if ($isPublic === false && $memberName{0} !== '_') { - $error = 'Private member variable "%s" must be prefixed with an underscore'; - $data = array($memberName); - $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); - return; - } - - // If it's not a private member, it must not have an underscore on the front. - if ($isPublic === true && $scopeSpecified === true && $memberName{0} === '_') { - $error = '%s member variable "%s" must not be prefixed with an underscore'; - $data = array( - ucfirst($scope), - $memberName, - ); - $phpcsFile->addError($error, $stackPtr, 'PublicUnderscore', $data); - return; - } - - }//end processMemberVar() - - - /** - * Processes normal variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariable() - - - /** - * Processes variables in double quoted strings. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php deleted file mode 100644 index e77321444..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php +++ /dev/null @@ -1,174 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff. - * - * Checks that object operators are indented 4 spaces if they are the first - * thing on a line. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OBJECT_OPERATOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is the first object operator in a chain of them. - $varToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($varToken === false || $tokens[$varToken]['code'] !== T_VARIABLE) { - return; - } - - // Make sure this is a chained call. - $next = $phpcsFile->findNext( - T_OBJECT_OPERATOR, - ($stackPtr + 1), - null, - false, - null, - true - ); - - if ($next === false) { - // Not a chained call. - return; - } - - // Determine correct indent. - for ($i = ($varToken - 1); $i >= 0; $i--) { - if ($tokens[$i]['line'] !== $tokens[$varToken]['line']) { - $i++; - break; - } - } - - $requiredIndent = 0; - if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) { - $requiredIndent = strlen($tokens[$i]['content']); - } - - $requiredIndent += $this->indent; - - // Determine the scope of the original object operator. - $origBrackets = null; - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $origBrackets = $tokens[$stackPtr]['nested_parenthesis']; - } - - $origConditions = null; - if (isset($tokens[$stackPtr]['conditions']) === true) { - $origConditions = $tokens[$stackPtr]['conditions']; - } - - // Check indentation of each object operator in the chain. - // If the first object operator is on a different line than - // the variable, make sure we check its indentation too. - if ($tokens[$stackPtr]['line'] > $tokens[$varToken]['line']) { - $next = $stackPtr; - } - - while ($next !== false) { - // Make sure it is in the same scope, otherwise don't check indent. - $brackets = null; - if (isset($tokens[$next]['nested_parenthesis']) === true) { - $brackets = $tokens[$next]['nested_parenthesis']; - } - - $conditions = null; - if (isset($tokens[$next]['conditions']) === true) { - $conditions = $tokens[$next]['conditions']; - } - - if ($origBrackets === $brackets && $origConditions === $conditions) { - // Make sure it starts a line, otherwise dont check indent. - $indent = $tokens[($next - 1)]; - if ($indent['code'] === T_WHITESPACE) { - if ($indent['line'] === $tokens[$next]['line']) { - $foundIndent = strlen($indent['content']); - } else { - $foundIndent = 0; - } - - if ($foundIndent !== $requiredIndent) { - $error = 'Object operator not indented correctly; expected %s spaces but found %s'; - $data = array( - $requiredIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $next, 'Incorrect', $data); - } - } - - // It cant be the last thing on the line either. - $content = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); - if ($tokens[$content]['line'] !== $tokens[$next]['line']) { - $error = 'Object operator must be at the start of the line, not the end'; - $phpcsFile->addError($error, $next, 'StartOfLine'); - } - }//end if - - $next = $phpcsFile->findNext( - T_OBJECT_OPERATOR, - ($next + 1), - null, - false, - null, - true - ); - }//end while - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php deleted file mode 100644 index 0541c290a..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php +++ /dev/null @@ -1,147 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PEAR_Sniffs_Whitespace_ScopeClosingBraceSniff. - * - * Checks that the closing braces of scopes are aligned correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$scopeOpeners; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If this is an inline condition (ie. there is no scope opener), then - // return, as this is not a new scope. - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - return; - } - - $scopeStart = $tokens[$stackPtr]['scope_opener']; - $scopeEnd = $tokens[$stackPtr]['scope_closer']; - - // If the scope closer doesn't think it belongs to this scope opener - // then the opener is sharing its closer ith other tokens. We only - // want to process the closer once, so skip this one. - if ($tokens[$scopeEnd]['scope_condition'] !== $stackPtr) { - return; - } - - // We need to actually find the first piece of content on this line, - // because if this is a method with tokens before it (public, static etc) - // or an if with an else before it, then we need to start the scope - // checking from there, rather than the current token. - $lineStart = ($stackPtr - 1); - for ($lineStart; $lineStart > 0; $lineStart--) { - if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { - break; - } - } - - // We found a new line, now go forward and find the first non-whitespace - // token. - $lineStart= $phpcsFile->findNext( - array(T_WHITESPACE), - ($lineStart + 1), - null, - true - ); - - $startColumn = $tokens[$lineStart]['column']; - - // Check that the closing brace is on it's own line. - $lastContent = $phpcsFile->findPrevious( - array(T_WHITESPACE), - ($scopeEnd - 1), - $scopeStart, - true - ); - - if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { - $error = 'Closing brace must be on a line by itself'; - $phpcsFile->addError($error, $scopeEnd, 'Line'); - return; - } - - // Check now that the closing brace is lined up correctly. - $braceIndent = $tokens[$scopeEnd]['column']; - if (in_array($tokens[$stackPtr]['code'], array(T_CASE, T_DEFAULT)) === true) { - // BREAK statements should be indented n spaces from the - // CASE or DEFAULT statement. - if ($braceIndent !== ($startColumn + $this->indent)) { - $error = 'Case breaking statement indented incorrectly; expected %s spaces, found %s'; - $data = array( - ($startColumn + $this->indent - 1), - ($braceIndent - 1), - ); - $phpcsFile->addError($error, $scopeEnd, 'BreakIdent', $data); - } - } else { - if ($braceIndent !== $startColumn) { - $error = 'Closing brace indented incorrectly; expected %s spaces, found %s'; - $data = array( - ($startColumn - 1), - ($braceIndent - 1), - ); - $phpcsFile->addError($error, $scopeEnd, 'Indent', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php b/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php deleted file mode 100644 index 20672f8be..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Generic_Sniffs_WhiteSpace_ScopeIndentSniff', true) === false) { - $error = 'Class Generic_Sniffs_WhiteSpace_ScopeIndentSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * PEAR_Sniffs_Whitespace_ScopeIndentSniff. - * - * Checks that control structures are structured correctly, and their content - * is indented correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PEAR_Sniffs_WhiteSpace_ScopeIndentSniff extends Generic_Sniffs_WhiteSpace_ScopeIndentSniff -{ - - /** - * Any scope openers that should not cause an indent. - * - * @var array(int) - */ - protected $nonIndentingScopes = array(T_SWITCH); - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml b/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml deleted file mode 100644 index b6211b2ab..000000000 --- a/codesniffer/CodeSniffer/Standards/PEAR/ruleset.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - The PEAR coding standard. - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml b/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml deleted file mode 100644 index bb49252bf..000000000 --- a/codesniffer/CodeSniffer/Standards/PHPCS/ruleset.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - The coding standard for PHP_CodeSniffer itself. - */Tests/* - - - - - - - - - - - - - - - - - - - - 0 - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml deleted file mode 100644 index eaae99b22..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Classes/ClassDeclarationStandard.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - class Bar { -} - ]]> - - - class Bar { -} - -class Baz { -} - ]]> - - - - - namespace Foo; - -class Bar { -} - ]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml b/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml deleted file mode 100644 index 0ed04a07d..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/Docs/Files/SideEffectsStandard.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - echo "Class Foo loaded." - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php deleted file mode 100644 index a6fbf1fa3..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Class Declaration Test. - * - * Checks the declaration of the class is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR1_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param integer $stackPtr The position of the current token in - * the token stack. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE), ($stackPtr + 1)); - if ($nextClass !== false) { - $error = 'Each class must be in a file by itself'; - $phpcsFile->addError($error, $nextClass, 'MultipleClasses'); - } - - if (version_compare(PHP_VERSION, '5.3.0') >= 0) { - $namespace = $phpcsFile->findPrevious(T_NAMESPACE, ($stackPtr - 1)); - if ($namespace === false) { - $error = 'Each class must be in a namespace of at least one level (a top-level vendor name)'; - $phpcsFile->addError($error, $stackPtr, 'MissingNamespace'); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php deleted file mode 100644 index 8ae868e70..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php +++ /dev/null @@ -1,226 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR1_Sniffs_Files_SideEffectsSniff. - * - * Ensures a file declare new symbols and causes no other side effects, or executes - * logic with side effects, but not both. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR1_Sniffs_Files_SideEffectsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the token stack. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - $tokens = $phpcsFile->getTokens(); - $result = $this->_searchForConflict($phpcsFile, 0, ($phpcsFile->numTokens - 1), $tokens); - - if ($result['symbol'] !== null && $result['effect'] !== null) { - $error = 'A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. The first symbol is defined on line %s and the first side effect is on line %s.'; - $data = array( - $tokens[$result['symbol']]['line'], - $tokens[$result['effect']]['line'], - ); - $phpcsFile->addWarning($error, 0, 'FoundWithSymbols', $data); - } - - }//end process() - - - /** - * Searches for symbol declarations and side effects. - * - * Returns the positions of both the first symbol declared and the first - * side effect in the file. A NULL value for either indicates nothing was - * found. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $start The token to start searching from. - * @param int $end The token to search to. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return array - */ - private function _searchForConflict(PHP_CodeSniffer_File $phpcsFile, $start, $end, $tokens) - { - $symbols = array( - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_FUNCTION, - ); - - $conditions = array( - T_IF, - T_ELSE, - T_ELSEIF, - ); - - $firstSymbol = null; - $firstEffect = null; - for ($i = $start; $i <= $end; $i++) { - // Ignore whitespace and comments. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } - - // Ignore PHP tags. - if ($tokens[$i]['code'] === T_OPEN_TAG - || $tokens[$i]['code'] === T_CLOSE_TAG - ) { - continue; - } - - // Ignore entire namespace, const and use statements. - if ($tokens[$i]['code'] === T_NAMESPACE) { - $next = $phpcsFile->findNext(array(T_SEMICOLON, T_OPEN_CURLY_BRACKET), ($i + 1)); - if ($next === false) { - $next = $i++; - } else if ($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET) { - $next = $tokens[$next]['bracket_closer']; - } - - $i = $next; - continue; - } else if ($tokens[$i]['code'] === T_USE - || $tokens[$i]['code'] === T_CONST - ) { - $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($i + 1)); - if ($semicolon !== false) { - $i = $semicolon; - } - - continue; - } - - // Ignore function/class prefixes. - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$methodPrefixes) === true) { - continue; - } - - // Detect and skip over symbols. - if (in_array($tokens[$i]['code'], $symbols) === true - && isset($tokens[$i]['scope_closer']) === true - ) { - if ($firstSymbol === null) { - $firstSymbol = $i; - } - - $i = $tokens[$i]['scope_closer']; - continue; - } else if ($tokens[$i]['code'] === T_STRING - && strtolower($tokens[$i]['content']) === 'define' - ) { - if ($firstSymbol === null) { - $firstSymbol = $i; - } - - $i = $phpcsFile->findNext(T_SEMICOLON, ($i + 1)); - continue; - } - - // Conditional statements are allowed in symbol files as long as the - // contents is only a symbol definition. So don't count these as effects - // in this case. - if (in_array($tokens[$i]['code'], $conditions) === true) { - if (isset($tokens[$i]['scope_opener']) === false) { - // Probably an "else if", so just ignore. - continue; - } - - $result = $this->_searchForConflict( - $phpcsFile, - ($tokens[$i]['scope_opener'] + 1), - ($tokens[$i]['scope_closer'] - 1), - $tokens - ); - - if ($result['symbol'] !== null) { - if ($firstSymbol === null) { - $firstSymbol = $result['symbol']; - } - - if ($result['effect'] !== null) { - // Found a conflict. - $firstEffect = $result['effect']; - break; - } - } - - if ($firstEffect === null) { - $firstEffect = $result['effect']; - } - - $i = $tokens[$i]['scope_closer']; - continue; - }//end if - - if ($firstEffect === null) { - $firstEffect = $i; - } - - if ($firstSymbol !== null) { - // We have a conflict we have to report, so no point continuing. - break; - } - }//end for - - return array( - 'symbol' => $firstSymbol, - 'effect' => $firstEffect, - ); - - }//end _searchForConflict() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php b/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php deleted file mode 100644 index 4a7b3250c..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * PSR1_Sniffs_Methods_CamelCapsMethodNameSniff. - * - * Ensures method names are defined using camel case. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR1_Sniffs_Methods_CamelCapsMethodNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - /** - * Constructs a PSR1_Sniffs_Methods_CamelCapsMethodNameSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE, T_TRAIT), array(T_FUNCTION), true); - - }//end __construct() - - - /** - * Processes the tokens within the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * @param int $currScope The position of the current scope. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $methodName = $phpcsFile->getDeclarationName($stackPtr); - if ($methodName === null) { - // Ignore closures. - return; - } - - $testName = ltrim($methodName, '_'); - if (PHP_CodeSniffer::isCamelCaps($testName, false, true, false) === false) { - $error = 'Method name "%s" is not in camel caps format'; - $className = $phpcsFile->getDeclarationName($currScope); - $errorData = array($className.'::'.$methodName); - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); - } - - }//end processTokenWithinScope() - - - /** - * Processes the tokens outside the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * - * @return void - */ - protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - - - }//end processTokenOutsideScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml b/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml deleted file mode 100644 index 8bc70151f..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR1/ruleset.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - The PSR1 coding standard. - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml deleted file mode 100644 index 23ae34701..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/ClassDeclarationStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - class Foo -{ -} - ]]> - - - class Foo -{ -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml deleted file mode 100644 index ab60a3b85..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Classes/PropertyDeclarationStandard.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - bar; -} - ]]> - - - _bar; -} - ]]> - - - - - private $bar; -} - ]]> - - - var $bar; -} - ]]> - - - - - - - - $bar, $baz; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml deleted file mode 100644 index dcbe98f5e..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ControlStructureSpacingStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - $foo) { - $var = 1; -} - ]]> - - - $foo ) { - $var = 1; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml deleted file mode 100644 index a22dd1796..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/ElseIfDeclarationStandard.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - elseif ($bar) { - $var = 2; -} - ]]> - - - else if ($bar) { - $var = 2; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml deleted file mode 100644 index 58b32a909..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - case 'bar': - break; -} - ]]> - - - case 'bar': - break; -} - ]]> - - - - - 'bar': - break; -} - ]]> - - - 'bar': - break; -} - ]]> - - - - - : - break; - default: - break; -} - ]]> - - - : - break; - default : - break; -} - ]]> - - - - - break; -} - ]]> - - - break; -} - ]]> - - - - - // no break - default: - break; -} - ]]> - - - : - break; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml deleted file mode 100644 index d6d3aad16..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Files/EndFileNewlineStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml deleted file mode 100644 index e45469e80..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - bar() - { - } -} - ]]> - - - _bar() - { - } -} - ]]> - - - - - final public static function bar() - { - } -} - ]]> - - - static public final function bar() - { - } -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml deleted file mode 100644 index 1f4d389aa..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/NamespaceDeclarationStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -use \Baz; - ]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml deleted file mode 100644 index 4082603ca..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Docs/Namespaces/UseDeclarationStandard.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - \Foo, \Bar; - ]]> - - - - - - - - - - - - - -class Baz -{ -} - ]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php deleted file mode 100644 index 06c5bc150..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php +++ /dev/null @@ -1,318 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PEAR_Sniffs_Classes_ClassDeclarationSniff', true) === false) { - $error = 'Class PEAR_Sniffs_Classes_ClassDeclarationSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Class Declaration Test. - * - * Checks the declaration of the class and its inheritance is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Classes_ClassDeclarationSniff extends PEAR_Sniffs_Classes_ClassDeclarationSniff -{ - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We want all the errors from the PEAR standard, plus some of our own. - parent::process($phpcsFile, $stackPtr); - $this->processOpen($phpcsFile, $stackPtr); - $this->processClose($phpcsFile, $stackPtr); - - }//end process() - - - /** - * Processes the opening section of a class declaration. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function processOpen(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Check alignment of the keyword and braces. - if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { - $prevContent = $tokens[($stackPtr - 1)]['content']; - if ($prevContent !== $phpcsFile->eolChar) { - $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); - $spaces = strlen($blankSpace); - - if (in_array($tokens[($stackPtr - 2)]['code'], array(T_ABSTRACT, T_FINAL)) === true - && $spaces !== 1 - ) { - $type = strtolower($tokens[$stackPtr]['content']); - $prevContent = strtolower($tokens[($stackPtr - 2)]['content']); - $error = 'Expected 1 space between %s and %s keywords; %s found'; - $data = array( - $prevContent, - $type, - $spaces, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeKeyword', $data); - } - } - }//end if - - // We'll need the indent of the class/interface declaration for later. - $classIndent = 0; - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { - continue; - } - - // We changed lines. - if ($tokens[($i + 1)]['code'] === T_WHITESPACE) { - $classIndent = strlen($tokens[($i + 1)]['content']); - } - - break; - } - - $keyword = $stackPtr; - $openingBrace = $tokens[$stackPtr]['scope_opener']; - $className = $phpcsFile->findNext(T_STRING, $stackPtr); - - $classOrInterface = strtolower($tokens[$keyword]['content']); - - // Spacing of the keyword. - $gap = $tokens[($stackPtr + 1)]['content']; - if (strlen($gap) !== 1) { - $found = strlen($gap); - $error = 'Expected 1 space between %s keyword and %s name; %s found'; - $data = array( - $classOrInterface, - $classOrInterface, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterKeyword', $data); - } - - // Check after the class/interface name. - $gap = $tokens[($className + 1)]['content']; - if (strlen($gap) !== 1) { - $found = strlen($gap); - $error = 'Expected 1 space after %s name; %s found'; - $data = array( - $classOrInterface, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterName', $data); - } - - // Check positions of the extends and implements keywords. - foreach (array('extends', 'implements') as $keywordType) { - $keyword = $phpcsFile->findNext(constant('T_'.strtoupper($keywordType)), ($stackPtr + 1), $openingBrace); - if ($keyword !== false) { - if ($tokens[$keyword]['line'] !== $tokens[$stackPtr]['line']) { - $error = 'The '.$keywordType.' keyword must be on the same line as the %s name'; - $data = array($classOrInterface); - $phpcsFile->addError($error, $keyword, ucfirst($keywordType).'Line', $data); - } else { - // Check the whitespace before. Whitespace after is checked - // later by looking at the whitespace before the first class name - // in the list. - $gap = strlen($tokens[($keyword - 1)]['content']); - if ($gap !== 1) { - $error = 'Expected 1 space before '.$keywordType.' keyword; %s found'; - $data = array($gap); - $phpcsFile->addError($error, $keyword, 'SpaceBefore'.ucfirst($keywordType), $data); - } - } - } - }//end foreach - - // Check each of the extends/implements class names. If the implements - // keywords is the last content on the line, it means we need to check for - // the multi-line implements format, so we do not include the class names - // from the implements list in the following check. - $implements = $phpcsFile->findNext(T_IMPLEMENTS, ($stackPtr + 1), $openingBrace); - $multiLineImplements = false; - if ($implements !== false) { - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($implements + 1), $openingBrace, true); - if ($tokens[$next]['line'] > $tokens[$implements]['line']) { - $multiLineImplements = true; - } - } - - $find = array( - T_STRING, - T_IMPLEMENTS, - ); - - $classNames = array(); - $nextClass = $phpcsFile->findNext($find, ($className + 2), ($openingBrace - 1)); - while ($nextClass !== false) { - $classNames[] = $nextClass; - $nextClass = $phpcsFile->findNext($find, ($nextClass + 1), ($openingBrace - 1)); - } - - $classCount = count($classNames); - $checkingImplements = false; - foreach ($classNames as $i => $className) { - if ($tokens[$className]['code'] == T_IMPLEMENTS) { - $checkingImplements = true; - continue; - } - - if ($checkingImplements === true - && $multiLineImplements === true - && ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR - || $tokens[($className - 2)]['code'] !== T_STRING) - ) { - $prev = $phpcsFile->findPrevious( - array( - T_NS_SEPARATOR, - T_WHITESPACE, - ), - ($className - 1), - $implements, - true - ); - - if ($tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) { - $error = 'Only one interface may be specified per line in a multi-line implements declaration'; - $phpcsFile->addError($error, $className, 'InterfaceSameLine'); - } else { - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($className - 1), $implements); - $found = strlen($tokens[$prev]['content']); - $expected = ($classIndent + $this->indent); - if ($found !== $expected) { - $error = 'Expected %s spaces before interface name; %s found'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $className, 'InterfaceWrongIndent', $data); - } - } - } else if ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR - || $tokens[($className - 2)]['code'] !== T_STRING - ) { - if ($tokens[($className - 1)]['code'] === T_COMMA - || ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR - && $tokens[($className - 2)]['code'] === T_COMMA) - ) { - $error = 'Expected 1 space before "%s"; 0 found'; - $data = array($tokens[$className]['content']); - $phpcsFile->addError($error, ($nextComma + 1), 'NoSpaceBeforeName', $data); - } else { - if ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR) { - $spaceBefore = strlen($tokens[($className - 2)]['content']); - } else { - $spaceBefore = strlen($tokens[($className - 1)]['content']); - } - - if ($spaceBefore !== 1) { - $error = 'Expected 1 space before "%s"; %s found'; - $data = array( - $tokens[$className]['content'], - $spaceBefore, - ); - $phpcsFile->addError($error, $className, 'SpaceBeforeName', $data); - } - }//end if - }//end if - - if ($tokens[($className + 1)]['code'] !== T_NS_SEPARATOR - && $tokens[($className + 1)]['code'] !== T_COMMA - ) { - if ($i !== ($classCount - 1)) { - // This is not the last class name, and the comma - // is not where we expect it to be. - if ($tokens[($className + 2)]['code'] !== T_IMPLEMENTS) { - $error = 'Expected 0 spaces between "%s" and comma; %s found'; - $data = array( - $tokens[$className]['content'], - strlen($tokens[($className + 1)]['content']), - ); - $phpcsFile->addError($error, $className, 'SpaceBeforeComma', $data); - } - } - - $nextComma = $phpcsFile->findNext(T_COMMA, $className); - } else { - $nextComma = ($className + 1); - } - }//end foreach - - }//end processOpen() - - - /** - * Processes the closing section of a class declaration. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function processClose(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Check that the closing brace comes right after the code body. - $closeBrace = $tokens[$stackPtr]['scope_closer']; - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true); - if ($prevContent !== $tokens[$stackPtr]['scope_opener'] - && $tokens[$prevContent]['line'] !== ($tokens[$closeBrace]['line'] - 1) - ) { - $error = 'The closing brace for the %s must go on the next line after the body'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $closeBrace, 'CloseBraceAfterBody', $data); - } - - // Check the closing brace is on it's own line, but allow - // for comments like "//end class". - $nextContent = $phpcsFile->findNext(T_COMMENT, ($closeBrace + 1), null, true); - if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar - && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line'] - ) { - $type = strtolower($tokens[$stackPtr]['content']); - $error = 'Closing %s brace must be on a line by itself'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data); - } - - }//end processClose() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php deleted file mode 100644 index cb748c3be..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -/** - * Verifies that properties are declared correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Classes_PropertyDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['content'][1] === '_') { - $error = 'Property name "%s" should not be prefixed with an underscore to indicate visibility'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); - } - - // Detect multiple properties defined at the same time. Throw an error - // for this, but also only process the first property in the list so we don't - // repeat errors. - $find = PHP_CodeSniffer_Tokens::$scopeModifiers; - $find = array_merge($find, array(T_VARIABLE, T_VAR, T_SEMICOLON)); - $prev = $phpcsFile->findPrevious($find, ($stackPtr - 1)); - if ($tokens[$prev]['code'] === T_VARIABLE) { - return; - } - - if ($tokens[$prev]['code'] === T_VAR) { - $error = 'The var keyword must not be used to declare a property'; - $phpcsFile->addError($error, $stackPtr, 'VarUsed'); - } - - $next = $phpcsFile->findNext(array(T_VARIABLE, T_SEMICOLON), ($stackPtr + 1)); - if ($tokens[$next]['code'] === T_VARIABLE) { - $error = 'There must not be more than one property declared per statement'; - $phpcsFile->addError($error, $stackPtr, 'Multiple'); - } - - $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); - if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { - $error = 'Visibility must be declared on property "%s"'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $data); - } - - }//end processMemberVar() - - - /** - * Processes normal variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariable() - - - /** - * Processes variables in double quoted strings. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php deleted file mode 100644 index 7f2c70393..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_WhiteSpace_ControlStructureSpacingSniff. - * - * Checks that control structures have the correct spacing around brackets. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_WHILE, - T_FOREACH, - T_FOR, - T_SWITCH, - T_DO, - T_ELSE, - T_ELSEIF, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { - $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; - $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[($parenOpener + 1)]['code'] === T_WHITESPACE) { - $gap = strlen($tokens[($parenOpener + 1)]['content']); - $error = 'Expected 0 spaces after opening bracket; %s found'; - $data = array($gap); - $phpcsFile->addError($error, ($parenOpener + 1), 'SpacingAfterOpenBrace', $data); - } - - if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line'] - && $tokens[($parenCloser - 1)]['code'] === T_WHITESPACE - ) { - $gap = strlen($tokens[($parenCloser - 1)]['content']); - $error = 'Expected 0 spaces before closing bracket; %s found'; - $data = array($gap); - $phpcsFile->addError($error, ($parenCloser - 1), 'SpaceBeforeCloseBrace', $data); - } - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php deleted file mode 100644 index a4f598a50..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff. - * - * Verifies that there are no else if statements. Elseif should be used instead. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_ELSE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$next]['code'] === T_IF) { - $error = 'Usage of ELSE IF is discouraged; use ELSEIF instead'; - $phpcsFile->addWarning($error, $stackPtr, 'NotAllowed'); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php deleted file mode 100644 index 7ffbf5c49..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php +++ /dev/null @@ -1,192 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff. - * - * Ensures all switch statements are defined correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_SWITCH); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We can't process SWITCH statements unless we know where they start and end. - if (isset($tokens[$stackPtr]['scope_opener']) === false - || isset($tokens[$stackPtr]['scope_closer']) === false - ) { - return; - } - - $switch = $tokens[$stackPtr]; - $nextCase = $stackPtr; - $caseAlignment = ($switch['column'] + $this->indent); - $caseCount = 0; - $foundDefault = false; - - while (($nextCase = $this->_findNextCase($phpcsFile, ($nextCase + 1), $switch['scope_closer'])) !== false) { - if ($tokens[$nextCase]['code'] === T_DEFAULT) { - $type = 'default'; - $foundDefault = true; - } else { - $type = 'case'; - $caseCount++; - } - - if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) { - $expected = strtolower($tokens[$nextCase]['content']); - $error = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - $expected, - $tokens[$nextCase]['content'], - ); - $phpcsFile->addError($error, $nextCase, $type.'NotLower', $data); - } - - if ($tokens[$nextCase]['column'] !== $caseAlignment) { - $error = strtoupper($type).' keyword must be indented '.$this->indent.' spaces from SWITCH keyword'; - $phpcsFile->addError($error, $nextCase, $type.'Indent'); - } - - if ($type === 'case' - && ($tokens[($nextCase + 1)]['code'] !== T_WHITESPACE - || $tokens[($nextCase + 1)]['content'] !== ' ') - ) { - $error = 'CASE keyword must be followed by a single space'; - $phpcsFile->addError($error, $nextCase, 'SpacingAfterCase'); - } - - $opener = $tokens[$nextCase]['scope_opener']; - if ($tokens[$opener]['code'] === T_COLON) { - if ($tokens[($opener - 1)]['code'] === T_WHITESPACE) { - $error = 'There must be no space before the colon in a '.strtoupper($type).' statement'; - $phpcsFile->addError($error, $nextCase, 'SpaceBeforeColon'.$type); - } - } else { - $error = strtoupper($type).' statements must not be defined using curly braces'; - $phpcsFile->addError($error, $nextCase, 'WrongOpener'.$type); - } - - $nextCloser = $tokens[$nextCase]['scope_closer']; - if ($tokens[$nextCloser]['scope_condition'] === $nextCase) { - // Only need to check some things once, even if the - // closer is shared between multiple case statements, or even - // the default case. - if ($tokens[$nextCloser]['column'] !== ($caseAlignment + $this->indent)) { - $error = 'Terminating statement must be indented to the same level as the CASE body'; - $phpcsFile->addError($error, $nextCloser, 'BreakIndent'); - } - } - - // We only want cases from here on in. - if ($type !== 'case') { - continue; - } - - $nextCode = $phpcsFile->findNext( - T_WHITESPACE, - ($tokens[$nextCase]['scope_opener'] + 1), - $nextCloser, - true - ); - - if ($tokens[$nextCode]['code'] !== T_CASE && $tokens[$nextCode]['code'] !== T_DEFAULT) { - // This case statement has content. If the next case or default comes - // before the closer, it means we dont have a terminating statement - // and instead need a comment. - $nextCode = $this->_findNextCase($phpcsFile, ($tokens[$nextCase]['scope_opener'] + 1), $nextCloser); - if ($nextCode !== false) { - $prevCode = $phpcsFile->findPrevious(T_WHITESPACE, ($nextCode - 1), $nextCase, true); - if ($tokens[$prevCode]['code'] !== T_COMMENT) { - $error = 'There must be a comment when fall-through is intentional in a non-empty case body'; - $phpcsFile->addError($error, $nextCase, 'TerminatingComment'); - } - } - } - }//end while - - }//end process() - - - /** - * Find the next CASE or DEFAULT statement from a point in the file. - * - * Note that nested switches are ignored. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position to start looking at. - * @param int $end The position to stop looking at. - * - * @return int | bool - */ - private function _findNextCase(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $end) - { - $tokens = $phpcsFile->getTokens(); - while (($stackPtr = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), $stackPtr, $end)) !== false) { - // Skip nested SWITCH statements; they are handled on their own. - if ($tokens[$stackPtr]['code'] === T_SWITCH) { - $stackPtr = $tokens[$stackPtr]['scope_closer']; - continue; - } - - break; - } - - return $stackPtr; - - }//end _findNextCase() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php deleted file mode 100644 index 755ebbed1..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Generic_Sniffs_Files_EndFileNewlineSniff. - * - * Ensures the file ends with a newline character. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Files_EndFileNewlineSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We are only interested if this is the first open tag and in a file - // that only contains PHP code. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(array(T_OPEN_TAG, T_INLINE_HTML), ($stackPtr - 1)) !== false) { - return; - } - } - - if ($phpcsFile->findNext(T_INLINE_HTML, ($stackPtr + 1)) !== false) { - return; - } - - // Skip to the end of the file. - $tokens = $phpcsFile->getTokens(); - $stackPtr = ($phpcsFile->numTokens - 1); - - // Hard-coding the expected \n in this sniff as it is PSR-2 specific and - // PSR-2 enforces the use of unix style newlines. - if (substr($tokens[$stackPtr]['content'], -1) !== "\n") { - $error = 'Expected 1 newline at end of file; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoneFound'); - return; - } - - // Go looking for the last non-empty line. - $lastLine = $tokens[$stackPtr]['line']; - while ($tokens[$stackPtr]['code'] === T_WHITESPACE) { - $stackPtr--; - } - - $lastCodeLine = $tokens[$stackPtr]['line']; - $blankLines = ($lastLine - $lastCodeLine); - if ($blankLines > 0) { - $error = 'Expected 1 blank line at end of file; %s found'; - $data = array($blankLines + 1); - $phpcsFile->addError($error, $stackPtr, 'TooMany', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php deleted file mode 100644 index 2a20939a4..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_Methods_FunctionCallSignatureSniff. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Methods_FunctionCallSignatureSniff extends PEAR_Sniffs_Functions_FunctionCallSignatureSniff -{ - - /** - * If TRUE, multiple arguments can be defined per line in a multi-line call. - * - * @var bool - */ - public $allowMultipleArguments = false; - - - /** - * Processes single-line calls. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param int $openBracket The position of the opening bracket - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) - { - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - $compareLine = $tokens[$openBracket]['line']; - - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - $i = $tokens[$i]['parenthesis_closer']; - $compareLine = $tokens[$i]['line']; - continue; - } else if ($tokens[$i]['code'] === T_CLOSURE) { - $i = $tokens[$i]['scope_closer']; - $compareLine = $tokens[$i]['line']; - continue; - } else if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) { - $i = $tokens[$i]['bracket_closer']; - $compareLine = $tokens[$i]['line']; - continue; - } - - if ($tokens[$i]['line'] !== $compareLine) { - return true; - } - }//end for - - return false; - - }//end isMultiLineCall() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php deleted file mode 100644 index 705dd4095..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * PSR2_Sniffs_Methods_MethodDeclarationSniff. - * - * Checks that the method declaration is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Methods_MethodDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION)); - - }//end __construct() - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * @param int $currScope The current scope opener token. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $tokens = $phpcsFile->getTokens(); - - $methodName = $phpcsFile->getDeclarationName($stackPtr); - if ($methodName === null) { - // Ignore closures. - return; - } - - if ($methodName[0] === '_' && isset($methodName[1]) === true && $methodName[1] !== '_') { - $error = 'Method name "%s" should not be prefixed with an underscore to indicate visibility'; - $data = array($methodName); - $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); - } - - $visibility = 0; - $static = 0; - $abstract = 0; - $final = 0; - - $find = PHP_CodeSniffer_Tokens::$methodPrefixes; - $find[] = T_WHITESPACE; - $prev = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); - - $prefix = $stackPtr; - while (($prefix = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$methodPrefixes, ($prefix - 1), $prev)) !== false) { - switch ($tokens[$prefix]['code']) { - case T_STATIC: - $static = $prefix; - break; - case T_ABSTRACT: - $abstract = $prefix; - break; - case T_FINAL: - $final = $prefix; - break; - default: - $visibility = $prefix; - break; - } - } - - if ($static !== 0 && $static < $visibility) { - $error = 'The static declaration must come after the visibility declaration'; - $phpcsFile->addError($error, $static, 'StaticBeforeVisibility'); - } - - if ($visibility !== 0 && $final > $visibility) { - $error = 'The final declaration must precede the visibility declaration'; - $phpcsFile->addError($error, $final, 'FinalAfterVisibility'); - } - - if ($visibility !== 0 && $abstract > $visibility) { - $error = 'The abstract declaration must precede the visibility declaration'; - $phpcsFile->addError($error, $abstract, 'AbstractAfterVisibility'); - } - - }//end processTokenWithinScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php deleted file mode 100644 index f805f675f..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php +++ /dev/null @@ -1,79 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff. - * - * Ensures namespaces are declared correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_NAMESPACE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { - continue; - } - - break; - } - - // The $i var now points to the first token on the line after the - // namespace declaration, which must be a blank line. - $next = $phpcsFile->findNext(T_WHITESPACE, $i, $phpcsFile->numTokens, true); - if ($tokens[$next]['line'] === $tokens[$i]['line']) { - $error = 'There must be one blank line after the namespace declaration'; - $phpcsFile->addError($error, $stackPtr, 'BlankLineAfter'); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php deleted file mode 100644 index 9e0467981..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php +++ /dev/null @@ -1,139 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * PSR2_Sniffs_Namespaces_UseDeclarationSniff. - * - * Ensures USE blocks are declared correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PSR2_Sniffs_Namespaces_UseDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_USE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - if ($this->_shouldIgnoreUse($phpcsFile, $stackPtr) === true) { - return; - } - - $tokens = $phpcsFile->getTokens(); - - // Only one USE declaration allowed per statement. - $next = $phpcsFile->findNext(array(T_COMMA, T_SEMICOLON), ($stackPtr + 1)); - if ($tokens[$next]['code'] === T_COMMA) { - $error = 'There must be one USE keyword per declaration'; - $phpcsFile->addError($error, $stackPtr, 'MultipleDeclarations'); - } - - // Make sure this USE comes after the first namespace declaration. - $prev = $phpcsFile->findPrevious(T_NAMESPACE, ($stackPtr - 1)); - if ($prev !== false) { - $first = $phpcsFile->findNext(T_NAMESPACE, 1); - if ($prev !== $first) { - $error = 'USE declarations must go after the first namespace declaration'; - $phpcsFile->addError($error, $stackPtr, 'UseAfterNamespace'); - } - } - - // Only interested in the last USE statement from here onwards. - $nextUse = $phpcsFile->findNext(T_USE, ($stackPtr + 1)); - while ($this->_shouldIgnoreUse($phpcsFile, $nextUse) === true) { - $nextUse = $phpcsFile->findNext(T_USE, ($nextUse + 1)); - if ($nextUse === false) { - break; - } - } - - if ($nextUse !== false) { - return; - } - - $end = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - $next = $phpcsFile->findNext(T_WHITESPACE, ($end + 1), null, true); - $diff = ($tokens[$next]['line'] - $tokens[$end]['line'] - 1); - if ($diff !== 1) { - if ($diff < 0) { - $diff = 0; - } - - $error = 'There must be one blank line after the last USE statement; %s found;'; - $data = array($diff); - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterLastUse', $data); - } - - }//end process() - - - /** - * Check if this use statement is part of the namespace block. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - private function _shouldIgnoreUse(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore USE keywords inside closures. - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { - return true; - } - - // Ignore USE keywords for traits. - if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_TRAIT)) === true) { - return true; - } - - return false; - - }//end _shouldIgnoreUse() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml b/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml deleted file mode 100644 index c454d1266..000000000 --- a/codesniffer/CodeSniffer/Standards/PSR2/ruleset.xml +++ /dev/null @@ -1,186 +0,0 @@ - - - The PSR-2 coding standard. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml deleted file mode 100644 index fc6ccbd6a..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayBracketSpacingStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - ['bar']; -]]> - - - [ 'bar' ]; -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml deleted file mode 100644 index 4cdfa2b01..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - array keyword must be lowercase. - ]]> - - - - array('val1', 'val2'); - ]]> - - - Array('val1', 'val2'); - ]]> - - - - array keyword. - ]]> - - - - 'key1' => 'value1', - 'key2' => 'value2', - ); - ]]> - - - 'key1' => 'value1', - 'key2' => 'value2', - ); - ]]> - - - - array keyword. The closing parenthesis must be aligned with the start of the array keyword. - ]]> - - - - 'key1' => 'value1', - 'key2' => 'value2', - ); - ]]> - - - 'key1' => 'value1', - 'key2' => 'value2', -); - ]]> - - - - - - - - => 'ValueTen', - 'keyTwenty' => 'ValueTwenty', - ); - ]]> - - - => 'ValueTen', - 'keyTwenty' => 'ValueTwenty', - ); - ]]> - - - - - - - - 'value1', - 'key2' => 'value2', - 'key3' => 'value3', - ); - ]]> - - - 'value1', - 'key2' => 'value2', - 'key3' => 'value3' - ); - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml deleted file mode 100644 index 89fcb5de8..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - final class Foo extends Bar -{ -} -]]> - - - Final Class Foo Extends Bar -{ -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml deleted file mode 100644 index 59d193ffd..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - self::foo(); -]]> - - - SELF::foo(); -]]> - - - - - ::foo(); -]]> - - - :: foo(); -]]> - - - - - self::bar(); - } -} -]]> - - - Foo -{ - public static function bar() - { - } - - public static function baz() - { - Foo::bar(); - } -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml deleted file mode 100644 index 414b89a34..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - * @see foo() - */ -]]> - - - * @see foo() -*/ -]]> - - - - - @see foo() - */ -]]> - - - @see foo() - */ -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml deleted file mode 100644 index 81df2e3fd..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - @throws Exception all the time - * @return void - */ -function foo() -{ - throw new Exception('Danger!'); -} -]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml deleted file mode 100644 index 87c618137..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - $foo as $bar => $baz) { - echo $baz; -} -]]> - - - $foo as $bar=>$baz ) { - echo $baz; -} -]]> - - - - - as $bar => $baz) { - echo $baz; -} -]]> - - - AS $bar => $baz) { - echo $baz; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml deleted file mode 100644 index bbc439230..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - $i = 0; $i < 10; $i++) { - echo $i; -} -]]> - - - $i = 0; $i < 10; $i++ ) { - echo $i; -} -]]> - - - - - ; $i < 10; $i++) { - echo $i; -} -]]> - - - ; $i < 10 ; $i++) { - echo $i; -} -]]> - - - - - $i < 10; $i++) { - echo $i; -} -]]> - - - $i < 10;$i++) { - echo $i; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml deleted file mode 100644 index 699f1f092..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - if ($foo) { - $bar = true; -} -]]> - - - IF ($foo) { - $bar = true; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml deleted file mode 100644 index a890aba68..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - isset($foo)) { - echo $foo; -} -]]> - - - isSet($foo)) { - echo $foo; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml deleted file mode 100644 index 46e8a8f32..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - function foo() -{ - return true; -} -]]> - - - FUNCTION foo() -{ - return true; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml deleted file mode 100644 index 3c97f54e6..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - static function bar() - { - return self::$staticMember; - } -} -]]> - - - static function bar() - { - return $this->$staticMember; - } -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml deleted file mode 100644 index 030f2a68c..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - "Hello"; -]]> - - - ("Hello"); -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml deleted file mode 100644 index 0fb195cb6..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - int)'42'; -]]> - - - int )'42'; -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml deleted file mode 100644 index d2bc26479..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - { -} -]]> - - - { -} -]]> - - - - - return 42; -} -]]> - - - - return 42; -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml deleted file mode 100644 index 608bed0b4..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - "hi"; -]]> - - - "hi"; -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml deleted file mode 100644 index c6194d71f..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - ) should not have any space around it. - ]]> - - - - ->bar(); -]]> - - - -> bar(); -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml deleted file mode 100644 index 8cadf6692..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - static function foo() -{ -} -]]> - - - static function foo() -{ -} -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml b/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml deleted file mode 100644 index 7b2279529..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - ; -]]> - - - ; -]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php deleted file mode 100644 index 00c0d0869..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff. - * - * Ensure that there are no spaces around square brackets. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // PHP 5.4 introduced a shorthand array declaration syntax, so we need - // to ignore the these type of array declarations because this sniff is - // only dealing with array usage. - if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { - $openBracket = $stackPtr; - } else { - $openBracket = $tokens[$stackPtr]['bracket_opener']; - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($openBracket - 1), null, true); - if ($tokens[$prev]['code'] === T_EQUAL) { - return; - } - - // Square brackets can not have a space before them. - $prevType = $tokens[($stackPtr - 1)]['code']; - if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $nonSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 2), null, true); - $expected = $tokens[$nonSpace]['content'].$tokens[$stackPtr]['content']; - $found = $phpcsFile->getTokensAsString($nonSpace, ($stackPtr - $nonSpace)).$tokens[$stackPtr]['content']; - $error = 'Space found before square bracket; expected "%s" but found "%s"'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeBracket', $data); - } - - // Open square brackets can't ever have spaces after them. - if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { - $nextType = $tokens[($stackPtr + 1)]['code']; - if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $nonSpace = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 2), null, true); - $expected = $tokens[$stackPtr]['content'].$tokens[$nonSpace]['content']; - $found = $phpcsFile->getTokensAsString($stackPtr, ($nonSpace - $stackPtr + 1)); - $error = 'Space found after square bracket; expected "%s" but found "%s"'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterBracket', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php deleted file mode 100644 index 27938d3ab..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php +++ /dev/null @@ -1,513 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * A test to ensure that arrays conform to the array coding standard. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Arrays_ArrayDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_ARRAY); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Array keyword should be lower case. - if (strtolower($tokens[$stackPtr]['content']) !== $tokens[$stackPtr]['content']) { - $error = 'Array keyword should be lower case; expected "array" but found "%s"'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $stackPtr, 'NotLowerCase', $data); - } - - $arrayStart = $tokens[$stackPtr]['parenthesis_opener']; - $arrayEnd = $tokens[$arrayStart]['parenthesis_closer']; - $keywordStart = $tokens[$stackPtr]['column']; - - if ($arrayStart != ($stackPtr + 1)) { - $error = 'There must be no space between the Array keyword and the opening parenthesis'; - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterKeyword'); - } - - // Check for empty arrays. - $content = $phpcsFile->findNext(array(T_WHITESPACE), ($arrayStart + 1), ($arrayEnd + 1), true); - if ($content === $arrayEnd) { - // Empty array, but if the brackets aren't together, there's a problem. - if (($arrayEnd - $arrayStart) !== 1) { - $error = 'Empty array declaration must have no space between the parentheses'; - $phpcsFile->addError($error, $stackPtr, 'SpaceInEmptyArray'); - - // We can return here because there is nothing else to check. All code - // below can assume that the array is not empty. - return; - } - } - - if ($tokens[$arrayStart]['line'] === $tokens[$arrayEnd]['line']) { - // Single line array. - // Check if there are multiple values. If so, then it has to be multiple lines - // unless it is contained inside a function call or condition. - $valueCount = 0; - $commas = array(); - for ($i = ($arrayStart + 1); $i < $arrayEnd; $i++) { - // Skip bracketed statements, like function calls. - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - $i = $tokens[$i]['parenthesis_closer']; - continue; - } - - if ($tokens[$i]['code'] === T_COMMA) { - // Before counting this comma, make sure we are not - // at the end of the array. - $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), $arrayEnd, true); - if ($next !== false) { - $valueCount++; - $commas[] = $i; - } else { - // There is a comma at the end of a single line array. - $error = 'Comma not allowed after last value in single-line array declaration'; - $phpcsFile->addError($error, $i, 'CommaAfterLast'); - } - } - } - - // Now check each of the double arrows (if any). - $nextArrow = $arrayStart; - while (($nextArrow = $phpcsFile->findNext(T_DOUBLE_ARROW, ($nextArrow + 1), $arrayEnd)) !== false) { - if ($tokens[($nextArrow - 1)]['code'] !== T_WHITESPACE) { - $content = $tokens[($nextArrow - 1)]['content']; - $error = 'Expected 1 space between "%s" and double arrow; 0 found'; - $data = array($content); - $phpcsFile->addError($error, $nextArrow, 'NoSpaceBeforeDoubleArrow', $data); - } else { - $spaceLength = strlen($tokens[($nextArrow - 1)]['content']); - if ($spaceLength !== 1) { - $content = $tokens[($nextArrow - 2)]['content']; - $error = 'Expected 1 space between "%s" and double arrow; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $nextArrow, 'SpaceBeforeDoubleArrow', $data); - } - } - - if ($tokens[($nextArrow + 1)]['code'] !== T_WHITESPACE) { - $content = $tokens[($nextArrow + 1)]['content']; - $error = 'Expected 1 space between double arrow and "%s"; 0 found'; - $data = array($content); - $phpcsFile->addError($error, $nextArrow, 'NoSpaceAfterDoubleArrow', $data); - } else { - $spaceLength = strlen($tokens[($nextArrow + 1)]['content']); - if ($spaceLength !== 1) { - $content = $tokens[($nextArrow + 2)]['content']; - $error = 'Expected 1 space between double arrow and "%s"; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $nextArrow, 'SpaceAfterDoubleArrow', $data); - } - } - }//end while - - if ($valueCount > 0) { - $conditionCheck = $phpcsFile->findPrevious(array(T_OPEN_PARENTHESIS, T_SEMICOLON), ($stackPtr - 1), null, false); - - if (($conditionCheck === false) || ($tokens[$conditionCheck]['line'] !== $tokens[$stackPtr]['line'])) { - $error = 'Array with multiple values cannot be declared on a single line'; - $phpcsFile->addError($error, $stackPtr, 'SingleLineNotAllowed'); - return; - } - - // We have a multiple value array that is inside a condition or - // function. Check its spacing is correct. - foreach ($commas as $comma) { - if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) { - $content = $tokens[($comma + 1)]['content']; - $error = 'Expected 1 space between comma and "%s"; 0 found'; - $data = array($content); - $phpcsFile->addError($error, $comma, 'NoSpaceAfterComma', $data); - } else { - $spaceLength = strlen($tokens[($comma + 1)]['content']); - if ($spaceLength !== 1) { - $content = $tokens[($comma + 2)]['content']; - $error = 'Expected 1 space between comma and "%s"; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $comma, 'SpaceAfterComma', $data); - } - } - - if ($tokens[($comma - 1)]['code'] === T_WHITESPACE) { - $content = $tokens[($comma - 2)]['content']; - $spaceLength = strlen($tokens[($comma - 1)]['content']); - $error = 'Expected 0 spaces between "%s" and comma; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $comma, 'SpaceBeforeComma', $data); - } - }//end foreach - }//end if - - return; - }//end if - - // Check the closing bracket is on a new line. - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($arrayEnd - 1), $arrayStart, true); - if ($tokens[$lastContent]['line'] !== ($tokens[$arrayEnd]['line'] - 1)) { - $error = 'Closing parenthesis of array declaration must be on a new line'; - $phpcsFile->addError($error, $arrayEnd, 'CloseBraceNewLine'); - } else if ($tokens[$arrayEnd]['column'] !== $keywordStart) { - // Check the closing bracket is lined up under the a in array. - $expected = $keywordStart; - $found = $tokens[$arrayEnd]['column']; - $error = 'Closing parenthesis not aligned correctly; expected %s space(s) but found %s'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $arrayEnd, 'CloseBraceNotAligned', $data); - } - - $nextToken = $stackPtr; - $lastComma = $stackPtr; - $keyUsed = false; - $singleUsed = false; - $lastToken = ''; - $indices = array(); - $maxLength = 0; - - // Find all the double arrows that reside in this scope. - while (($nextToken = $phpcsFile->findNext(array(T_DOUBLE_ARROW, T_COMMA, T_ARRAY), ($nextToken + 1), $arrayEnd)) !== false) { - $currentEntry = array(); - - if ($tokens[$nextToken]['code'] === T_ARRAY) { - // Let subsequent calls of this test handle nested arrays. - $indices[] = array('value' => $nextToken); - $nextToken = $tokens[$tokens[$nextToken]['parenthesis_opener']]['parenthesis_closer']; - continue; - } - - if ($tokens[$nextToken]['code'] === T_COMMA) { - $stackPtrCount = 0; - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $stackPtrCount = count($tokens[$stackPtr]['nested_parenthesis']); - } - - if (count($tokens[$nextToken]['nested_parenthesis']) > ($stackPtrCount + 1)) { - // This comma is inside more parenthesis than the ARRAY keyword, - // then there it is actually a comma used to separate arguments - // in a function call. - continue; - } - - if ($keyUsed === true && $lastToken === T_COMMA) { - $error = 'No key specified for array entry; first entry specifies key'; - $phpcsFile->addError($error, $nextToken, 'NoKeySpecified'); - return; - } - - if ($keyUsed === false) { - if ($tokens[($nextToken - 1)]['code'] === T_WHITESPACE) { - $content = $tokens[($nextToken - 2)]['content']; - $spaceLength = strlen($tokens[($nextToken - 1)]['content']); - $error = 'Expected 0 spaces between "%s" and comma; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $nextToken, 'SpaceBeforeComma', $data); - } - - // Find the value, which will be the first token on the line, - // excluding the leading whitespace. - $valueContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextToken - 1), null, true); - while ($tokens[$valueContent]['line'] === $tokens[$nextToken]['line']) { - if ($valueContent === $arrayStart) { - // Value must have been on the same line as the array - // parenthesis, so we have reached the start of the value. - break; - } - - $valueContent--; - } - - $valueContent = $phpcsFile->findNext(T_WHITESPACE, ($valueContent + 1), $nextToken, true); - $indices[] = array('value' => $valueContent); - $singleUsed = true; - }//end if - - $lastToken = T_COMMA; - continue; - }//end if - - if ($tokens[$nextToken]['code'] === T_DOUBLE_ARROW) { - if ($singleUsed === true) { - $error = 'Key specified for array entry; first entry has no key'; - $phpcsFile->addError($error, $nextToken, 'KeySpecified'); - return; - } - - $currentEntry['arrow'] = $nextToken; - $keyUsed = true; - - // Find the start of index that uses this double arrow. - $indexEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($nextToken - 1), $arrayStart, true); - $indexStart = $phpcsFile->findPrevious(T_WHITESPACE, $indexEnd, $arrayStart); - - if ($indexStart === false) { - $index = $indexEnd; - } else { - $index = ($indexStart + 1); - } - - $currentEntry['index'] = $index; - $currentEntry['index_content'] = $phpcsFile->getTokensAsString($index, ($indexEnd - $index + 1)); - - $indexLength = strlen($currentEntry['index_content']); - if ($maxLength < $indexLength) { - $maxLength = $indexLength; - } - - // Find the value of this index. - $nextContent = $phpcsFile->findNext(array(T_WHITESPACE), ($nextToken + 1), $arrayEnd, true); - $currentEntry['value'] = $nextContent; - $indices[] = $currentEntry; - $lastToken = T_DOUBLE_ARROW; - }//end if - }//end while - - // Check for mutli-line arrays that should be single-line. - $singleValue = false; - - if (empty($indices) === true) { - $singleValue = true; - } else if (count($indices) === 1 && $lastToken === T_COMMA) { - // There may be another array value without a comma. - $exclude = PHP_CodeSniffer_Tokens::$emptyTokens; - $exclude[] = T_COMMA; - $nextContent = $phpcsFile->findNext($exclude, ($indices[0]['value'] + 1), $arrayEnd, true); - if ($nextContent === false) { - $singleValue = true; - } - } - - if ($singleValue === true) { - // Array cannot be empty, so this is a multi-line array with - // a single value. It should be defined on single line. - $error = 'Multi-line array contains a single value; use single-line array instead'; - $phpcsFile->addError($error, $stackPtr, 'MultiLineNotAllowed'); - return; - } - - /* - This section checks for arrays that don't specify keys. - - Arrays such as: - array( - 'aaa', - 'bbb', - 'd', - ); - */ - - if ($keyUsed === false && empty($indices) === false) { - $count = count($indices); - $lastIndex = $indices[($count - 1)]['value']; - - $trailingContent = $phpcsFile->findPrevious(T_WHITESPACE, ($arrayEnd - 1), $lastIndex, true); - if ($tokens[$trailingContent]['code'] !== T_COMMA) { - $error = 'Comma required after last value in array declaration'; - $phpcsFile->addError($error, $trailingContent, 'NoCommaAfterLast'); - } - - foreach ($indices as $value) { - if (empty($value['value']) === true) { - // Array was malformed and we couldn't figure out - // the array value correctly, so we have to ignore it. - // Other parts of this sniff will correct the error. - continue; - } - - if ($tokens[($value['value'] - 1)]['code'] === T_WHITESPACE) { - // A whitespace token before this value means that the value - // was indented and not flush with the opening parenthesis. - if ($tokens[$value['value']]['column'] !== ($keywordStart + 1)) { - $error = 'Array value not aligned correctly; expected %s spaces but found %s'; - $data = array( - ($keywordStart + 1), - $tokens[$value['value']]['column'], - ); - $phpcsFile->addError($error, $value['value'], 'ValueNotAligned', $data); - } - } - } - }//end if - - /* - Below the actual indentation of the array is checked. - Errors will be thrown when a key is not aligned, when - a double arrow is not aligned, and when a value is not - aligned correctly. - If an error is found in one of the above areas, then errors - are not reported for the rest of the line to avoid reporting - spaces and columns incorrectly. Often fixing the first - problem will fix the other 2 anyway. - - For example: - - $a = array( - 'index' => '2', - ); - - In this array, the double arrow is indented too far, but this - will also cause an error in the value's alignment. If the arrow were - to be moved back one space however, then both errors would be fixed. - */ - - $numValues = count($indices); - - $indicesStart = ($keywordStart + 1); - $arrowStart = ($indicesStart + $maxLength + 1); - $valueStart = ($arrowStart + 3); - foreach ($indices as $index) { - if (isset($index['index']) === false) { - // Array value only. - if (($tokens[$index['value']]['line'] === $tokens[$stackPtr]['line']) && ($numValues > 1)) { - $error = 'The first value in a multi-value array must be on a new line'; - $phpcsFile->addError($error, $stackPtr, 'FirstValueNoNewline'); - } - - continue; - } - - if (($tokens[$index['index']]['line'] === $tokens[$stackPtr]['line'])) { - $error = 'The first index in a multi-value array must be on a new line'; - $phpcsFile->addError($error, $stackPtr, 'FirstIndexNoNewline'); - continue; - } - - if ($tokens[$index['index']]['column'] !== $indicesStart) { - $error = 'Array key not aligned correctly; expected %s spaces but found %s'; - $data = array( - ($indicesStart - 1), - ($tokens[$index['index']]['column'] - 1), - ); - $phpcsFile->addError($error, $index['index'], 'KeyNotAligned', $data); - continue; - } - - if ($tokens[$index['arrow']]['column'] !== $arrowStart) { - $expected = ($arrowStart - (strlen($index['index_content']) + $tokens[$index['index']]['column'])); - $found = ($tokens[$index['arrow']]['column'] - (strlen($index['index_content']) + $tokens[$index['index']]['column'])); - - $error = 'Array double arrow not aligned correctly; expected %s space(s) but found %s'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $index['arrow'], 'DoubleArrowNotAligned', $data); - continue; - } - - if ($tokens[$index['value']]['column'] !== $valueStart) { - $expected = ($valueStart - (strlen($tokens[$index['arrow']]['content']) + $tokens[$index['arrow']]['column'])); - $found = ($tokens[$index['value']]['column'] - (strlen($tokens[$index['arrow']]['content']) + $tokens[$index['arrow']]['column'])); - - $error = 'Array value not aligned correctly; expected %s space(s) but found %s'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $index['arrow'], 'ValueNotAligned', $data); - } - - // Check each line ends in a comma. - if ($tokens[$index['value']]['code'] !== T_ARRAY) { - $valueLine = $tokens[$index['value']]['line']; - $nextComma = false; - for ($i = ($index['value'] + 1); $i < $arrayEnd; $i++) { - // Skip bracketed statements, like function calls. - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - $i = $tokens[$i]['parenthesis_closer']; - $valueLine = $tokens[$i]['line']; - continue; - } - - if ($tokens[$i]['code'] === T_COMMA) { - $nextComma = $i; - break; - } - } - - if (($nextComma === false) || ($tokens[$nextComma]['line'] !== $valueLine)) { - $error = 'Each line in an array declaration must end in a comma'; - $phpcsFile->addError($error, $index['value'], 'NoComma'); - } - - // Check that there is no space before the comma. - if ($nextComma !== false && $tokens[($nextComma - 1)]['code'] === T_WHITESPACE) { - $content = $tokens[($nextComma - 2)]['content']; - $spaceLength = strlen($tokens[($nextComma - 1)]['content']); - $error = 'Expected 0 spaces between "%s" and comma; %s found'; - $data = array( - $content, - $spaceLength, - ); - $phpcsFile->addError($error, $nextComma, 'SpaceBeforeComma', $data); - } - } - }//end foreach - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php deleted file mode 100644 index efd7703fe..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff. - * - * Ensure there is a single blank line after the closing brace of a class definition. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_CLOSE_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($next === false) { - return; - } - - if ($tokens[$next]['code'] !== T_CLOSE_TAG) { - $found = (($tokens[$next]['line'] - $tokens[$stackPtr]['line']) - 1); - if ($found !== 1) { - $error = 'Expected one blank line after closing brace of class definition; %s found'; - $data = array($found); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterClose', $data); - } - } - - // Ignore nested style definitions from here on. The spacing before the closing brace - // (a single blank line) will be enforced by the above check, which ensures there is a - // blank line after the last nested class. - $found = $phpcsFile->findPrevious( - T_CLOSE_CURLY_BRACKET, - ($stackPtr - 1), - $tokens[$stackPtr]['bracket_opener'] - ); - if ($found !== false) { - return; - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($prev !== false && $tokens[$prev]['line'] !== ($tokens[$stackPtr]['line'] - 1)) { - $num = ($tokens[$stackPtr]['line'] - $tokens[$prev]['line'] - 1); - $error = 'Expected 0 blank lines before closing brace of class definition; %s found'; - $data = array($num); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php deleted file mode 100644 index bce5c31dd..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff. - * - * Ensure there are no blank lines between the names of classes/IDs. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Do not check nested style definitions as, for example, in @media style rules. - $nested = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1), $tokens[$stackPtr]['bracket_closer']); - if ($nested !== false) { - return; - } - - // Find the first blank line before this opening brace, unless we get - // to another style definition, comment or the start of the file. - $endTokens = array( - T_OPEN_CURLY_BRACKET, - T_CLOSE_CURLY_BRACKET, - T_COMMENT, - T_DOC_COMMENT, - T_OPEN_TAG, - ); - - $foundContent = false; - $currentLine = $tokens[$stackPtr]['line']; - for ($i = ($stackPtr - 1); $i >= 0; $i--) { - if (in_array($tokens[$i]['code'], $endTokens) === true) { - break; - } - - if ($tokens[$i]['line'] === $currentLine) { - if ($tokens[$i]['code'] !== T_WHITESPACE) { - $foundContent = true; - } - - continue; - } - - // We changed lines. - if ($foundContent === false) { - // Before we throw an error, make sure we are not looking - // at a gap before the style definition. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, $i, null, true); - if ($prev !== false - && in_array($tokens[$prev]['code'], $endTokens) === false - ) { - $error = 'Blank lines are not allowed between class names'; - $phpcsFile->addError($error, ($i + 1), 'BlankLinesFound'); - } - break; - } - - $foundContent = false; - $currentLine = $tokens[$i]['line']; - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php deleted file mode 100644 index dccc83580..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff. - * - * Ensure there is a single space before the opening brace in a class definition - * and the content starts on the next line. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before opening brace of class definition; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoneBefore'); - } else { - $content = $tokens[($stackPtr - 1)]['content']; - if ($content !== ' ') { - $length = strlen($content); - if ($length === 1) { - $length = 'tab'; - } - - $error = 'Expected 1 space before opening brace of class definition; %s found'; - $data = array($length); - $phpcsFile->addError($error, $stackPtr, 'Before', $data); - } - }//end if - - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($next === false) { - return; - } - - // Check for nested class definitions. - $nested = false; - $found = $phpcsFile->findNext( - T_OPEN_CURLY_BRACKET, - ($stackPtr + 1), - $tokens[$stackPtr]['bracket_closer'] - ); - if ($found !== false) { - $nested = true; - } - - $foundLines = ($tokens[$next]['line'] - $tokens[$stackPtr]['line'] - 1); - if ($nested === true) { - if ($foundLines !== 1) { - $error = 'Expected 1 blank line after opening brace of nesting class definition; %s found'; - $data = array($foundLines); - $phpcsFile->addError($error, $stackPtr, 'AfterNesting', $data); - } - } else { - if ($foundLines !== 0) { - $error = 'Expected 0 blank lines after opening brace of class definition; %s found'; - $data = array($foundLines); - $phpcsFile->addError($error, $stackPtr, 'After', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php deleted file mode 100644 index 907a03964..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ColonSpacingSniff. - * - * Ensure there is no space before a colon and one space after it. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ColonSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_COLON); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] !== T_STYLE) { - // The colon is not part of a style definition. - return; - } - - if ($tokens[$prev]['content'] === 'progid') { - // Special case for IE filters. - return; - } - - if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { - $error = 'There must be no space before a colon in a style definition'; - $phpcsFile->addError($error, $stackPtr, 'Before'); - } - - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after colon in style definition; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoneAfter'); - } else { - $content = $tokens[($stackPtr + 1)]['content']; - if (strpos($content, $phpcsFile->eolChar) === false) { - $length = strlen($content); - if ($length !== 1) { - $error = 'Expected 1 space after colon in style definition; %s found'; - $data = array($length); - $phpcsFile->addError($error, $stackPtr, 'After', $data); - } - } else { - $error = 'Expected 1 space after colon in style definition; newline found'; - $phpcsFile->addError($error, $stackPtr, 'AfterNewline'); - } - }//end if - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php deleted file mode 100644 index b860f0dac..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ColourDefinitionSniff. - * - * Ensure colours are defined in upper-case and use shortcuts where possible. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ColourDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_COLOUR); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $colour = $tokens[$stackPtr]['content']; - - $expected = strtoupper($colour); - if ($colour !== $expected) { - $error = 'CSS colours must be defined in uppercase; expected %s but found %s'; - $data = array( - $expected, - $colour, - ); - $phpcsFile->addError($error, $stackPtr, 'NotUpper', $data); - } - - // Now check if shorthand can be used. - if (strlen($colour) !== 7) { - return; - } - - if ($colour{1} === $colour{2} && $colour{3} === $colour{4} && $colour{5} === $colour{6}) { - $expected = '#'.$colour{1}.$colour{3}.$colour{5}; - $error = 'CSS colours must use shorthand if available; expected %s but found %s'; - $data = array( - $expected, - $colour, - ); - $phpcsFile->addError($error, $stackPtr, 'Shorthand', $data); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php deleted file mode 100644 index 4e0c50be5..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff. - * - * Ensure that each style definition is on a line by itself. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $next = $phpcsFile->findNext(T_STYLE, ($stackPtr + 1)); - if ($next === false) { - return; - } - - if ($tokens[$next]['content'] === 'progid') { - // Special case for IE filters. - return; - } - - if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) { - $error = 'Each style definition must be on a line by itself'; - $phpcsFile->addError($error, $next, 'Found'); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php deleted file mode 100644 index f35aa2770..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff. - * - * Check for duplicate class definitions that can be merged into one. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Find the content of each class definition name. - $classNames = array(); - $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1)); - if ($next === false) { - // No class definitions in the file. - return; - } - - $find = array( - T_CLOSE_CURLY_BRACKET, - T_COMMENT, - T_OPEN_TAG, - ); - - while ($next !== false) { - $prev = $phpcsFile->findPrevious($find, ($next - 1)); - - // Create a sorted name for the class so we can compare classes - // even when the individual names are all over the place. - $name = ''; - for ($i = ($prev + 1); $i < $next; $i++) { - $name .= $tokens[$i]['content']; - } - - $name = trim($name); - $name = str_replace("\n", ' ', $name); - $name = preg_replace('|[\s]+|', ' ', $name); - $name = str_replace(', ', ',', $name); - - $names = explode(',', $name); - sort($names); - $name = implode(',', $names); - - if (isset($classNames[$name]) === true) { - $first = $classNames[$name]; - $error = 'Duplicate class definition found; first defined on line %s'; - $data = array($tokens[$first]['line']); - $phpcsFile->addError($error, $next, 'Found', $data); - } else { - $classNames[$name] = $next; - } - - $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($next + 1)); - }//end while - - }//end process() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php deleted file mode 100644 index 3171a349f..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff. - * - * Check for duplicate style definitions in the same class. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Find the content of each style definition name. - $end = $tokens[$stackPtr]['bracket_closer']; - $next = $phpcsFile->findNext(T_STYLE, ($stackPtr + 1), $end); - if ($next === false) { - // Class definition is empty. - return; - } - - $styleNames = array(); - - while ($next !== false) { - $name = $tokens[$next]['content']; - if (isset($styleNames[$name]) === true) { - $first = $styleNames[$name]; - $error = 'Duplicate style definition found; first defined on line %s'; - $data = array($tokens[$first]['line']); - $phpcsFile->addError($error, $next, 'Found', $data); - } else { - $styleNames[$name] = $next; - } - - $next = $phpcsFile->findNext(T_STYLE, ($next + 1), $end); - }//end while - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php deleted file mode 100644 index 047315e80..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_EmptyClassDefinitionSniff. - * - * Ensure that class definitions are not empty. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_EmptyClassDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - - if ($next === false || $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { - $error = 'Class definition is empty'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php deleted file mode 100644 index 6bf53e7d5..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff. - * - * Ensure that style definitions are not empty. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COLON), ($stackPtr + 1), null, true); - - if ($next === false || $tokens[$next]['code'] === T_SEMICOLON || $tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { - $error = 'Style definition is empty'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php deleted file mode 100644 index 65628066b..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php +++ /dev/null @@ -1,185 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ForbiddenStylesSniff. - * - * Bans the use of some styles, such as deprecated or browser-specific styles. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ForbiddenStylesSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - /** - * A list of forbidden styles with their alternatives. - * - * The value is NULL if no alternative exists. i.e., the - * function should just not be used. - * - * @var array(string => string|null) - */ - protected $forbiddenStyles = array( - '-moz-border-radius' => 'border-radius', - '-webkit-border-radius' => 'border-radius', - '-moz-border-radius-topleft' => 'border-top-left-radius', - '-moz-border-radius-topright' => 'border-top-right-radius', - '-moz-border-radius-bottomright' => 'border-bottom-right-radius', - '-moz-border-radius-bottomleft' => 'border-bottom-left-radius', - '-moz-box-shadow' => 'box-shadow', - '-webkit-box-shadow' => 'box-shadow', - ); - - /** - * A cache of forbidden style names, for faster lookups. - * - * @var array(string) - */ - protected $forbiddenStyleNames = array(); - - /** - * If true, forbidden styles will be considered regular expressions. - * - * @var bool - */ - protected $patternMatch = false; - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = true; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - $this->forbiddenStyleNames = array_keys($this->forbiddenStyles); - - if ($this->patternMatch === true) { - foreach ($this->forbiddenStyleNames as $i => $name) { - $this->forbiddenStyleNames[$i] = '/'.$name.'/i'; - } - } - - return array(T_STYLE); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $style = strtolower($tokens[$stackPtr]['content']); - $pattern = null; - - if ($this->patternMatch === true) { - $count = 0; - $pattern = preg_replace( - $this->forbiddenStyleNames, - $this->forbiddenStyleNames, - $style, - 1, - $count - ); - - if ($count === 0) { - return; - } - - // Remove the pattern delimiters and modifier. - $pattern = substr($pattern, 1, -2); - } else { - if (in_array($style, $this->forbiddenStyleNames) === false) { - return; - } - } - - $this->addError($phpcsFile, $stackPtr, $style, $pattern); - - }//end process() - - - /** - * Generates the error or warning for this sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the forbidden style - * in the token array. - * @param string $style The name of the forbidden style. - * @param string $pattern The pattern used for the match. - * - * @return void - */ - protected function addError($phpcsFile, $stackPtr, $style, $pattern=null) - { - $data = array($style); - $error = 'The use of style %s is '; - if ($this->error === true) { - $type = 'Found'; - $error .= 'forbidden'; - } else { - $type = 'Discouraged'; - $error .= 'discouraged'; - } - - if ($pattern === null) { - $pattern = $style; - } - - if ($this->forbiddenStyles[$pattern] !== null) { - $type .= 'WithAlternative'; - $data[] = $this->forbiddenStyles[$pattern]; - $error .= '; use %s instead'; - } - - if ($this->error === true) { - $phpcsFile->addError($error, $stackPtr, $type, $data); - } else { - $phpcsFile->addWarning($error, $stackPtr, $type, $data); - } - - }//end addError() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php deleted file mode 100644 index 8740acf1a..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php +++ /dev/null @@ -1,128 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_IndentationSniff. - * - * Ensures styles are indented 4 spaces. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_IndentationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $numTokens = (count($tokens) - 2); - $indentLevel = 0; - $nestingLevel = 0; - for ($i = 1; $i < $numTokens; $i++) { - if ($tokens[$i]['code'] === T_COMMENT) { - // Don't check the indent of comments. - continue; - } - - if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { - $indentLevel++; - - // Check for nested class definitions. - $found = $phpcsFile->findNext( - T_OPEN_CURLY_BRACKET, - ($i + 1), - $tokens[$i]['bracket_closer'] - ); - if ($found !== false) { - $nestingLevel = $indentLevel; - } - } else if ($tokens[($i + 1)]['code'] === T_CLOSE_CURLY_BRACKET) { - $indentLevel--; - } - - if ($tokens[$i]['column'] !== 1) { - continue; - } - - // We started a new line, so check indent. - if ($tokens[$i]['code'] === T_WHITESPACE) { - $content = str_replace($phpcsFile->eolChar, '', $tokens[$i]['content']); - $foundIndent = strlen($content); - } else { - $foundIndent = 0; - } - - $expectedIndent = ($indentLevel * $this->indent); - if ($expectedIndent > 0 - && strpos($tokens[$i]['content'], $phpcsFile->eolChar) !== false - ) { - if ($nestingLevel !== $indentLevel) { - $error = 'Blank lines are not allowed in class definitions'; - $phpcsFile->addError($error, $i, 'BlankLine'); - } - } else if ($foundIndent !== $expectedIndent) { - $error = 'Line indented incorrectly; expected %s spaces, found %s'; - $data = array( - $expectedIndent, - $foundIndent, - ); - $phpcsFile->addError($error, $i, 'Incorrect', $data); - } - }//end foreach - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php deleted file mode 100644 index 7eabd99a9..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php +++ /dev/null @@ -1,106 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff. - * - * Ensure that all style definitions are in lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $start = ($stackPtr + 1); - $end = ($tokens[$stackPtr]['bracket_closer'] - 1); - $inStyle = null; - - for ($i = $start; $i <= $end; $i++) { - // Skip nested definitions as they are checked individually. - if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { - $i = $tokens[$i]['bracket_closer']; - continue; - } - - if ($tokens[$i]['code'] === T_STYLE) { - $inStyle = $tokens[$i]['content']; - } - - if ($tokens[$i]['code'] === T_SEMICOLON) { - $inStyle = null; - } - - if ($inStyle === 'progid') { - // Special case for IE filters. - continue; - } - - if ($tokens[$i]['code'] === T_STYLE - || ($inStyle !== null - && $tokens[$i]['code'] === T_STRING) - ) { - $expected = strtolower($tokens[$i]['content']); - if ($expected !== $tokens[$i]['content']) { - $error = 'Style definitions must be lowercase; expected %s but found %s'; - $data = array( - $expected, - $tokens[$i]['content'], - ); - $phpcsFile->addError($error, $i, 'FoundUpper', $data); - } - } - }//end for - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php deleted file mode 100644 index f5b02a1ae..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_MissingColonSniff. - * - * Ensure that all style definitions have a colon. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_MissingColonSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_CURLY_BRACKET); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $lastLine = $tokens[$stackPtr]['line']; - $end = $tokens[$stackPtr]['bracket_closer']; - $endLine = $tokens[$end]['line']; - - // Do not check nested style definitions as, for example, in @media style rules. - $nested = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, ($stackPtr + 1), $end); - if ($nested !== false) { - return; - } - - $foundColon = false; - $foundString = false; - for ($i = ($stackPtr + 1); $i <= $end; $i++) { - if ($tokens[$i]['line'] !== $lastLine) { - // We changed lines. - if ($foundColon === false && $foundString !== false) { - // We didn't find a colon on the previous line. - $error = 'No style definition found on line; check for missing colon'; - $phpcsFile->addError($error, $foundString, 'Found'); - } - - $foundColon = false; - $foundString = false; - $lastLine = $tokens[$i]['line']; - } - - if ($tokens[$i]['code'] === T_STRING) { - $foundString = $i; - } else if ($tokens[$i]['code'] === T_COLON) { - $foundColon = $i; - } - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php deleted file mode 100644 index 66b1ab3b1..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_NamedColoursSniff. - * - * Ensure colour names are not used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_NamedColoursSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * A list of named colours. - * - * This is the list of standard colours defined in the CSS spec. - * - * @var array - */ - public $colourNames = array( - 'aqua', - 'black', - 'blue', - 'fuchsia', - 'gray', - 'green', - 'lime', - 'maroon', - 'navy', - 'olive', - 'orange', - 'purple', - 'red', - 'silver', - 'teal', - 'white', - 'yellow', - ); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr - 1)]['code'] === T_HASH - || $tokens[($stackPtr - 1)]['code'] === T_STRING_CONCAT - ) { - // Class name. - return; - } - - if (in_array(strtolower($tokens[$stackPtr]['content']), $this->colourNames) === true) { - $error = 'Named colours are forbidden; use hex, rgb, or rgba values instead'; - $phpcsFile->addError($error, $stackPtr, 'Forbidden'); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php deleted file mode 100644 index 52106e4a0..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_OpacitySniff. - * - * Ensure that opacity values start with a 0 if it is not a whole number. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_OpacitySniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['content'] !== 'opacity') { - return; - } - - $next = $phpcsFile->findNext(array(T_COLON, T_WHITESPACE), ($stackPtr + 1), null, true); - $numbers = array( - T_DNUMBER, - T_LNUMBER, - ); - - if ($next === false || in_array($tokens[$next]['code'], $numbers) === false) { - return; - } - - $value = $tokens[$next]['content']; - if ($tokens[$next]['code'] === T_LNUMBER) { - if ($value !== '0' && $value !== '1') { - $error = 'Opacity values must be between 0 and 1'; - $phpcsFile->addError($error, $next, 'Invalid'); - } - } else { - if (strlen($value) > 3) { - $error = 'Opacity values must have a single value after the decimal point'; - $phpcsFile->addError($error, $next, 'SpacingAfterPoint'); - } else if ($value === '0.0' || $value === '1.0') { - $error = 'Opacity value does not require decimal point; use %s instead'; - $data = array($value{0}); - $phpcsFile->addError($error, $next, 'PointNotRequired', $data); - } else if ($value{0} === '.') { - $error = 'Opacity values must not start with a decimal point; use 0%s instead'; - $data = array($value); - $phpcsFile->addError($error, $next, 'StartWithPoint', $data); - } else if ($value{0} !== '0') { - $error = 'Opacity values must be between 0 and 1'; - $phpcsFile->addError($error, $next, 'Invalid'); - } - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php deleted file mode 100644 index 589375d7d..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_SemicolonSpacingSniff. - * - * Ensure each style definition has a semi-colon and it is spaced correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_SemicolonSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - if ($semicolon === false || $tokens[$semicolon]['line'] !== $tokens[$stackPtr]['line']) { - $error = 'Style definitions must end with a semicolon'; - $phpcsFile->addError($error, $stackPtr, 'NotAtEnd'); - return; - } - - if ($tokens[($semicolon - 1)]['code'] === T_WHITESPACE) { - $length = strlen($tokens[($semicolon - 1)]['content']); - $error = 'Expected 0 spaces before semicolon in style definition; %s found'; - $data = array($length); - $phpcsFile->addError($error, $stackPtr, 'SpaceFound', $data); - } - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php deleted file mode 100644 index 750f59f6e..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php +++ /dev/null @@ -1,161 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_CSS_ShorthandSizeSniff. - * - * Ensure sizes are defined using shorthand notation where possible, except in the - * case where shorthand becomes 3 values. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CSS_ShorthandSizeSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('CSS'); - - /** - * A list of styles that we shouldn't check. - * - * These have values that looks like sizes, but are not. - * - * @var array - */ - public $excludeStyles = array( - 'background-position', - 'box-shadow', - 'transform-origin', - '-webkit-transform-origin', - '-ms-transform-origin', - ); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_STYLE); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Some styles look like shorthand but are not actually a set of 4 sizes. - $style = strtolower($tokens[$stackPtr]['content']); - if (in_array($style, $this->excludeStyles) === true) { - return; - } - - // Get the whole style content. - $end = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - $content = $phpcsFile->getTokensAsString(($stackPtr + 1), ($end - $stackPtr - 1)); - $content = trim($content, ': '); - - // Account for a !important annotation. - if (substr($content, -10) === '!important') { - $content = substr($content, 0, -10); - $content = trim($content); - } - - // Check if this style value is a set of numbers with optional prefixes. - $content = preg_replace('/\s+/', ' ', $content); - $values = array(); - $num = preg_match_all( - '/([0-9]+)([a-zA-Z]{2}\s+|%\s+|\s+)/', - $content.' ', - $values, - PREG_SET_ORDER - ); - - // Only interested in styles that have multiple sizes defined. - if ($num < 2) { - return; - } - - // Rebuild the content we matched to ensure we got everything. - $matched = ''; - foreach ($values as $value) { - $matched .= $value[0]; - } - - if ($content !== trim($matched)) { - return; - } - - if ($num === 3) { - $expected = trim($content.' '.$values[1][1].$values[1][2]); - $error = 'Shorthand syntax not allowed here; use %s instead'; - $data = array($expected); - $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); - return; - } - - if ($num === 2) { - if ($values[0][0] !== $values[1][0]) { - // Both values are different, so it is already shorthand. - return; - } - } else if ($values[0][0] !== $values[2][0] || $values[1][0] !== $values[3][0]) { - // Can't shorthand this. - return; - } - - if ($values[0][0] === $values[1][0]) { - // All values are the same. - $expected = $values[0][0]; - } else { - $expected = $values[0][0].' '.$values[1][0]; - } - - $expected = preg_replace('/\s+/', ' ', trim($expected)); - - $error = 'Size definitions must use shorthand if available; expected "%s" but found "%s"'; - $data = array( - $expected, - $content, - ); - - $phpcsFile->addError($error, $stackPtr, 'NotUsed', $data); - - }//end process() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php deleted file mode 100644 index 04b894bb1..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php +++ /dev/null @@ -1,177 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PSR2_Sniffs_Classes_ClassDeclarationSniff', true) === false) { - $error = 'Class PSR2_Sniffs_Classes_ClassDeclarationSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Class Declaration Test. - * - * Checks the declaration of the class and its inheritance is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_ClassDeclarationSniff extends PSR2_Sniffs_Classes_ClassDeclarationSniff -{ - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We want all the errors from the PSR2 standard, plus some of our own. - parent::process($phpcsFile, $stackPtr); - - $tokens = $phpcsFile->getTokens(); - - // Check that this is the only class or interface in the file. - $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE), ($stackPtr + 1)); - if ($nextClass !== false) { - // We have another, so an error is thrown. - $error = 'Only one interface or class is allowed in a file'; - $phpcsFile->addError($error, $nextClass, 'MultipleClasses'); - } - - }//end process() - - - /** - * Processes the opening section of a class declaration. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function processOpen(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - parent::processOpen($phpcsFile, $stackPtr); - - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { - $prevContent = $tokens[($stackPtr - 1)]['content']; - if ($prevContent !== $phpcsFile->eolChar) { - $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); - $spaces = strlen($blankSpace); - - if (in_array($tokens[($stackPtr - 2)]['code'], array(T_ABSTRACT, T_FINAL)) === false) { - if ($spaces !== 0) { - $type = strtolower($tokens[$stackPtr]['content']); - $error = 'Expected 0 spaces before %s keyword; %s found'; - $data = array( - $type, - $spaces, - ); - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeKeyword', $data); - } - } - } - }//end if - - }//end processOpen() - - - /** - * Processes the closing section of a class declaration. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function processClose(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $closeBrace = $tokens[$stackPtr]['scope_closer']; - if ($tokens[($closeBrace - 1)]['code'] === T_WHITESPACE) { - $prevContent = $tokens[($closeBrace - 1)]['content']; - if ($prevContent !== $phpcsFile->eolChar) { - $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); - $spaces = strlen($blankSpace); - if ($spaces !== 0) { - if ($tokens[($closeBrace - 1)]['line'] !== $tokens[$closeBrace]['line']) { - $error = 'Expected 0 spaces before closing brace; newline found'; - $phpcsFile->addError($error, $closeBrace, 'NewLineBeforeCloseBrace'); - } else { - $error = 'Expected 0 spaces before closing brace; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $closeBrace, 'SpaceBeforeCloseBrace', $data); - } - } - } - } - - // Check that the closing brace has one blank line after it. - $nextContent = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), ($closeBrace + 1), null, true); - if ($nextContent === false) { - // No content found, so we reached the end of the file. - // That means there was no closing tag either. - $error = 'Closing brace of a %s must be followed by a blank line and then a closing PHP tag'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $closeBrace, 'EndFileAfterCloseBrace', $data); - } else { - $nextLine = $tokens[$nextContent]['line']; - $braceLine = $tokens[$closeBrace]['line']; - if ($braceLine === $nextLine) { - $error = 'Closing brace of a %s must be followed by a single blank line'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $closeBrace, 'NoNewlineAfterCloseBrace', $data); - } else if ($nextLine !== ($braceLine + 2)) { - $difference = ($nextLine - $braceLine - 1); - $error = 'Closing brace of a %s must be followed by a single blank line; found %s'; - $data = array( - $tokens[$stackPtr]['content'], - $difference, - ); - $phpcsFile->addError($error, $closeBrace, 'NewlinesAfterCloseBrace', $data); - } - }//end if - - // Check the closing brace is on it's own line, but allow - // for comments like "//end class". - $nextContent = $phpcsFile->findNext(T_COMMENT, ($closeBrace + 1), null, true); - if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line']) { - $type = strtolower($tokens[$stackPtr]['content']); - $error = 'Closing %s brace must be on a line by itself'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data); - } - - }//end processClose() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php deleted file mode 100644 index a55185197..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Classes_ClassFileNameSniff. - * - * Tests that the file name and the name of the class contained within the file - * match. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_ClassFileNameSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fullPath = basename($phpcsFile->getFilename()); - $fileName = substr($fullPath, 0, strrpos($fullPath, '.')); - if ($fileName === '') { - // No filename probably means STDIN, so we can't do this check. - return; - } - - $tokens = $phpcsFile->getTokens(); - $decName = $phpcsFile->findNext(T_STRING, $stackPtr); - - if ($tokens[$decName]['content'] !== $fileName) { - $error = '%s name doesn\'t match filename; expected "%s %s"'; - $data = array( - ucfirst($tokens[$stackPtr]['content']), - $tokens[$stackPtr]['content'], - $fileName, - ); - $phpcsFile->addError($error, $stackPtr, 'NoMatch', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php deleted file mode 100644 index 1c1ace0c3..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Classes_DuplicatePropertySniff. - * - * Ensures JS classes don't contain duplicate property names. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_DuplicatePropertySniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OBJECT); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $start = $tokens[$stackPtr]['scope_opener']; - $end = $tokens[$stackPtr]['scope_closer']; - - $properties = array(); - $wantedTokens = array( - T_PROPERTY, - T_OPEN_CURLY_BRACKET, - ); - - $next = $phpcsFile->findNext($wantedTokens, ($start + 1), $end); - while ($next !== false && $next < $end) { - // Skip nested objects. - if ($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET) { - $next = $tokens[$next]['bracket_closer']; - } else { - $propName = $tokens[$next]['content']; - if (isset($properties[$propName]) === true) { - $error = 'Duplicate property definition found for "%s"; previously defined on line %s'; - $data = array( - $propName, - $tokens[$properties[$propName]]['line'], - ); - $phpcsFile->addError($error, $next, 'Found', $data); - } - - $properties[$propName] = $next; - }//end if - - $next = $phpcsFile->findNext($wantedTokens, ($next + 1), $end); - }//end while - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php deleted file mode 100644 index adb9a7309..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff. - * - * Ensures all class keywords are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_EXTENDS, - T_IMPLEMENTS, - T_ABSTRACT, - T_FINAL, - T_VAR, - T_CONST, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - if ($content !== strtolower($content)) { - $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtoupper($content), - strtolower($content), - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php deleted file mode 100644 index 29f629ba2..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Tests self member references. - * - * Verifies that : - *
    - *
  • self:: is used instead of Self::
  • - *
  • self:: is used for local static member reference
  • - *
  • self:: is used instead of self ::
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_SelfMemberReferenceSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs a Squiz_Sniffs_Classes_SelfMemberReferenceSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS), array(T_DOUBLE_COLON)); - - }//end __construct() - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * @param int $currScope The current scope opener token. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $tokens = $phpcsFile->getTokens(); - - $className = ($stackPtr - 1); - if ($tokens[$className]['code'] === T_SELF) { - if (strtolower($tokens[$className]['content']) !== $tokens[$className]['content']) { - $error = 'Must use "self::" for local static member reference; found "%s::"'; - $data = array($tokens[$className]['content']); - $phpcsFile->addError($error, $className, 'IncorrectCase', $data); - return; - } - } else if ($tokens[$className]['code'] === T_STRING) { - // Make sure this is another class reference. - $declarationName = $phpcsFile->getDeclarationName($currScope); - $fullQualifiedClassName = $tokens[$className]['content']; - - // If the class is called with a namespace prefix, build fully qualified - // namespace calls for both current scope class and requested class. - if ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR) { - $declarationName = $this->getDeclarationNameWithNamespace($tokens, $className); - $declarationName = substr($declarationName, 1); - $fullQualifiedClassName = $this->getNamespaceOfScope($phpcsFile, $currScope); - $fullQualifiedClassName .= '\\'.$tokens[$className]['content']; - } - - if ($declarationName === $fullQualifiedClassName) { - // Class name is the same as the current class, which is not allowed - // except if being used inside a closure. - if ($phpcsFile->hasCondition($stackPtr, T_CLOSURE) === false) { - $error = 'Must use "self::" for local static member reference'; - $phpcsFile->addError($error, $className, 'NotUsed'); - return; - } - } - }//end if - - if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) { - $found = strlen($tokens[($stackPtr - 1)]['content']); - $error = 'Expected 0 spaces before double colon; %s found'; - $data = array($found); - $phpcsFile->addError($error, $className, 'SpaceBefore', $data); - } - - if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { - $found = strlen($tokens[($stackPtr + 1)]['content']); - $error = 'Expected 0 spaces after double colon; %s found'; - $data = array($found); - $phpcsFile->addError($error, $className, 'SpaceAfter', $data); - } - - }//end processTokenWithinScope() - - - /** - * Returns the declaration names for classes/interfaces/functions with a namespace. - * - * @param array $tokens Token stack for this file - * @param int $stackPtr The position where the namespace building will start. - * - * @return string - */ - protected function getDeclarationNameWithNamespace(array $tokens, $stackPtr) - { - $nameParts = array(); - $currentPointer = $stackPtr; - while ($tokens[$currentPointer]['code'] === T_NS_SEPARATOR - || $tokens[$currentPointer]['code'] === T_STRING - ) { - $nameParts[] = $tokens[$currentPointer]['content']; - $currentPointer--; - } - - $nameParts = array_reverse($nameParts); - return implode('', $nameParts); - - }//end getDeclarationNameWithNamespace() - - - /** - * Returns the namespace declaration of a file. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the search for the - * namespace declaration will start. - * - * @return string - */ - protected function getNamespaceOfScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $namespace = '\\'; - $namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr); - - if ($namespaceDeclaration !== false) { - $endOfNamespaceDeclaration = $phpcsFile->findNext(T_SEMICOLON, $namespaceDeclaration); - $namespace = $this->getDeclarationNameWithNamespace( - $phpcsFile->getTokens(), - ($endOfNamespaceDeclaration - 1) - ); - } - - return $namespace; - - }//end getNamespaceOfScope - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php deleted file mode 100644 index 00baf9e1a..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Classes_ValidClassNameSniff. - * - * Ensures classes are in camel caps, and the first letter is capitalised - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Classes_ValidClassNameSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - $error = 'Possible parse error: %s missing opening or closing brace'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data); - return; - } - - // Determine the name of the class or interface. Note that we cannot - // simply look for the first T_STRING because a class name - // starting with the number will be multiple tokens. - $opener = $tokens[$stackPtr]['scope_opener']; - $nameStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), $opener, true); - $nameEnd = $phpcsFile->findNext(T_WHITESPACE, $nameStart, $opener); - $name = trim($phpcsFile->getTokensAsString($nameStart, ($nameEnd - $nameStart))); - - // Check for camel caps format. - $valid = PHP_CodeSniffer::isCamelCaps($name, true, true, false); - if ($valid === false) { - $type = ucfirst($tokens[$stackPtr]['content']); - $error = '%s name "%s" is not in camel caps format'; - $data = array( - $type, - $name, - ); - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php deleted file mode 100644 index 7ea785618..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Generic_Sniffs_CodeAnalysis_EmptyStatementSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_CodeAnalysis_EmptyStatementSniff not found'); -} - -/** - * This sniff class detects empty statement. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff extends Generic_Sniffs_CodeAnalysis_EmptyStatementSniff -{ - - /** - * List of block tokens that this sniff covers. - * - * The key of this hash identifies the required token while the boolean - * value says mark an error or mark a warning. - * - * @var array - */ - protected $checkedTokens = array( - T_DO => true, - T_ELSE => true, - T_ELSEIF => true, - T_FOR => true, - T_FOREACH => true, - T_IF => true, - T_SWITCH => true, - T_WHILE => true, - ); - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php deleted file mode 100644 index 5eaaa6ae6..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php +++ /dev/null @@ -1,246 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_BlockCommentSniff. - * - * Verifies that block comments are used appropriately. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_BlockCommentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_COMMENT, - T_DOC_COMMENT, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If its an inline comment return. - if (substr($tokens[$stackPtr]['content'], 0, 2) !== '/*') { - return; - } - - // If this is a function/class/interface doc block comment, skip it. - // We are only interested in inline doc block comments. - if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) { - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - $ignore = array( - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_FUNCTION, - T_PUBLIC, - T_PRIVATE, - T_FINAL, - T_PROTECTED, - T_STATIC, - T_ABSTRACT, - T_CONST, - ); - if (in_array($tokens[$nextToken]['code'], $ignore) === true) { - return; - } - - $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { - return; - } - }//end if - - $commentLines = array($stackPtr); - $nextComment = $stackPtr; - $lastLine = $tokens[$stackPtr]['line']; - - // Construct the comment into an array. - while (($nextComment = $phpcsFile->findNext($tokens[$stackPtr]['code'], ($nextComment + 1), null, false)) !== false) { - if (($tokens[$nextComment]['line'] - 1) !== $lastLine) { - // Not part of the block. - break; - } - - $lastLine = $tokens[$nextComment]['line']; - $commentLines[] = $nextComment; - } - - if (count($commentLines) <= 2) { - // Small comment. Can't be right. - if (count($commentLines) === 1) { - $error = 'Single line block comment not allowed; use inline ("// text") comment instead'; - $phpcsFile->addError($error, $stackPtr, 'SingleLine'); - return; - } - - if (trim($tokens[$commentLines[1]]['content']) === '*/') { - if (trim($tokens[$stackPtr]['content']) === '/*') { - $error = 'Empty block comment not allowed'; - $phpcsFile->addError($error, $stackPtr, 'Empty'); - return; - } - } - } - - $content = trim($tokens[$stackPtr]['content']); - if ($content !== '/*' && $content !== '/**') { - $error = 'Block comment text must start on a new line'; - $phpcsFile->addError($error, $stackPtr, 'NoNewLine'); - return; - } - - $starColumn = ($tokens[$stackPtr]['column'] + 3); - - // Make sure first line isn't blank. - if (trim($tokens[$commentLines[1]]['content']) === '') { - $error = 'Empty line not allowed at start of comment'; - $phpcsFile->addError($error, $commentLines[1], 'HasEmptyLine'); - } else { - // Check indentation of first line. - $content = $tokens[$commentLines[1]]['content']; - $commentText = ltrim($content); - $leadingSpace = (strlen($content) - strlen($commentText)); - if ($leadingSpace !== $starColumn) { - $expected = $starColumn; - $expected .= ($starColumn === 1) ? ' space' : ' spaces'; - $data = array( - $expected, - $leadingSpace, - ); - - $error = 'First line of comment not aligned correctly; expected %s but found %s'; - $phpcsFile->addError($error, $commentLines[1], 'FirstLineIndent', $data); - } - - if (preg_match('|\p{Lu}|u', $commentText[0]) === 0) { - $error = 'Block comments must start with a capital letter'; - $phpcsFile->addError($error, $commentLines[1], 'NoCapital'); - } - } - - // Check that each line of the comment is indented past the star. - foreach ($commentLines as $line) { - $leadingSpace = (strlen($tokens[$line]['content']) - strlen(ltrim($tokens[$line]['content']))); - // First and last lines (comment opener and closer) are handled separately. - if ($line === $commentLines[(count($commentLines) - 1)] || $line === $commentLines[0]) { - continue; - } - - // First comment line was handled above. - if ($line === $commentLines[1]) { - continue; - } - - // If it's empty, continue. - if (trim($tokens[$line]['content']) === '') { - continue; - } - - if ($leadingSpace < $starColumn) { - $expected = $starColumn; - $expected .= ($starColumn === 1) ? ' space' : ' spaces'; - $data = array( - $expected, - $leadingSpace, - ); - - $error = 'Comment line indented incorrectly; expected at least %s but found %s'; - $phpcsFile->addError($error, $line, 'LineIndent', $data); - } - }//end foreach - - // Finally, test the last line is correct. - $lastIndex = (count($commentLines) - 1); - $content = trim($tokens[$commentLines[$lastIndex]]['content']); - if ($content !== '*/' && $content !== '**/') { - $error = 'Comment closer must be on a new line'; - $phpcsFile->addError($error, $commentLines[$lastIndex]); - } else { - $content = $tokens[$commentLines[$lastIndex]]['content']; - $commentText = ltrim($content); - $leadingSpace = (strlen($content) - strlen($commentText)); - if ($leadingSpace !== ($tokens[$stackPtr]['column'] - 1)) { - $expected = ($tokens[$stackPtr]['column'] - 1); - $expected .= ($expected === 1) ? ' space' : ' spaces'; - $data = array( - $expected, - $leadingSpace, - ); - - $error = 'Last line of comment aligned incorrectly; expected %s but found %s'; - $phpcsFile->addError($error, $commentLines[$lastIndex], 'LastLineIndent', $data); - } - - } - - // Check that the lines before and after this comment are blank. - $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if (isset($tokens[$contentBefore]['scope_closer']) === true - && $tokens[$contentBefore]['scope_opener'] === $contentBefore - ) { - if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) !== 1) { - $error = 'Empty line not required before block comment'; - $phpcsFile->addError($error, $stackPtr, 'HasEmptyLineBefore'); - } - } else { - if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) < 2) { - $error = 'Empty line required before block comment'; - $phpcsFile->addError($error, $stackPtr, 'NoEmptyLineBefore'); - } - } - - $commentCloser = $commentLines[$lastIndex]; - $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($commentCloser + 1), null, true); - if (($tokens[$contentAfter]['line'] - $tokens[$commentCloser]['line']) < 2) { - $error = 'Empty line required after block comment'; - $phpcsFile->addError($error, $commentCloser, 'NoEmptyLineAfter'); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php deleted file mode 100644 index 56742e30e..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php +++ /dev/null @@ -1,254 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); -} - -/** - * Parses and verifies the class doc comment. - * - * Verifies that : - *
    - *
  • A class doc comment exists.
  • - *
  • There is exactly one blank line before the class comment.
  • - *
  • Short description ends with a full stop.
  • - *
  • There is a blank line after the short description.
  • - *
  • Each paragraph of the long description ends with a full stop.
  • - *
  • There is a blank line between the description and the tags.
  • - *
  • Check the format of the since tag (x.x.x).
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_ClassCommentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CLASS); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - $tokens = $phpcsFile->getTokens(); - $find = array( - T_ABSTRACT, - T_WHITESPACE, - T_FINAL, - ); - - // Extract the class comment docblock. - $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); - - if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { - $phpcsFile->addError('You must use "/**" style comments for a class comment', $stackPtr, 'WrongStyle'); - return; - } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { - $phpcsFile->addError('Missing class doc comment', $stackPtr, 'Missing'); - return; - } - - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); - - // Distinguish file and class comment. - $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1)); - if ($prevClassToken === false) { - // This is the first class token in this file, need extra checks. - $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true); - if ($prevNonComment !== false) { - $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1)); - if ($prevComment === false) { - // There is only 1 doc comment between open tag and class token. - $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); - if ($newlineToken !== false) { - $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $stackPtr, false, $phpcsFile->eolChar); - if ($newlineToken !== false) { - // Blank line between the class and the doc block. - // The doc block is most likely a file comment. - $phpcsFile->addError('Missing class doc comment', ($stackPtr + 1), 'Missing'); - return; - } - }//end if - }//end if - - // Exactly one blank line before the class comment. - $prevTokenEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); - if ($prevTokenEnd !== false) { - $blankLineBefore = 0; - for ($i = ($prevTokenEnd + 1); $i < $commentStart; $i++) { - if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) { - $blankLineBefore++; - } - } - - if ($blankLineBefore !== 2) { - $error = 'There must be exactly one blank line before the class comment'; - $phpcsFile->addError($error, ($commentStart - 1), 'SpacingBefore'); - } - } - - }//end if - }//end if - - $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - - // Parse the class comment docblock. - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'Class doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - // The first line of the comment should just be the /** code. - $eolPos = strpos($commentString, $phpcsFile->eolChar); - $firstLine = substr($commentString, 0, $eolPos); - if ($firstLine !== '/**') { - $error = 'The open comment tag must be the only content on the line'; - $phpcsFile->addError($error, $commentStart, 'SpacingAfterOpen'); - } - - // Check for a comment description. - $short = rtrim($comment->getShortComment(), $phpcsFile->eolChar); - if (trim($short) === '') { - $error = 'Missing short description in class doc comment'; - $phpcsFile->addError($error, $commentStart, 'MissingShort'); - return; - } - - // No extra newline before short description. - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before class comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in class comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); - } - - $newlineCount += $newlineBetween; - - $testLong = trim($long); - if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { - $error = 'Class comment long description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); - } - } - - // Exactly one blank line before tags. - $tags = $this->commentParser->getTagOrders(); - if (count($tags) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in class comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Short description must be single line and end with a full stop. - $testShort = trim($short); - $lastChar = $testShort[(strlen($testShort) - 1)]; - if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { - $error = 'Class comment short description must be on a single line'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); - } - if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { - $error = 'Class comment short description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); - } - - if ($lastChar !== '.') { - $error = 'Class comment short description must end with a full stop'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); - } - - // No tags are allowed in the class comment. - $tags = $this->commentParser->getTags(); - foreach ($tags as $errorTag) { - $error = '@%s tag is not allowed in class comment'; - $data = array($errorTag['tag']); - $phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data); - } - - // The last content should be a newline and the content before - // that should not be blank. If there is more blank space - // then they have additional blank lines at the end of the comment. - $words = $this->commentParser->getWords(); - $lastPos = (count($words) - 1); - if (trim($words[($lastPos - 1)]) !== '' - || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false - || trim($words[($lastPos - 2)]) === '' - ) { - $error = 'Additional blank lines found at end of class comment'; - $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); - } - - }//end process() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php deleted file mode 100644 index 37583e8fe..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php +++ /dev/null @@ -1,127 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff. - * - * Checks the //end ... comments on classes, interfaces and functions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_FUNCTION, - T_CLASS, - T_INTERFACE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens.. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] === T_FUNCTION) { - - $methodProps = $phpcsFile->getMethodProperties($stackPtr); - - // Abstract methods do not require a closing comment. - if ($methodProps['is_abstract'] === true) { - return; - } - - // Closures do not require a closing comment. - if ($methodProps['is_closure'] === true) { - return; - } - - // If this function is in an interface then we don't require - // a closing comment. - if ($phpcsFile->hasCondition($stackPtr, T_INTERFACE) === true) { - return; - } - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - $error = 'Possible parse error: non-abstract method defined as abstract'; - $phpcsFile->addWarning($error, $stackPtr, 'Abstract'); - return; - } - - $decName = $phpcsFile->getDeclarationName($stackPtr); - $comment = '//end '.$decName.'()'; - } else if ($tokens[$stackPtr]['code'] === T_CLASS) { - $comment = '//end class'; - } else { - $comment = '//end interface'; - }//end if - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - $error = 'Possible parse error: %s missing opening or closing brace'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data); - return; - } - - $closingBracket = $tokens[$stackPtr]['scope_closer']; - - if ($closingBracket === null) { - // Possible inline structure. Other tests will handle it. - return; - } - - $error = 'Expected '.$comment; - if (isset($tokens[($closingBracket + 1)]) === false || $tokens[($closingBracket + 1)]['code'] !== T_COMMENT) { - $phpcsFile->addError($error, $closingBracket, 'Missing'); - return; - } - - if (rtrim($tokens[($closingBracket + 1)]['content']) !== $comment) { - $phpcsFile->addError($error, $closingBracket, 'Incorrect'); - return; - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php deleted file mode 100644 index e5415ee18..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php +++ /dev/null @@ -1,151 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_DocCommentAlignmentSniff. - * - * Tests that the stars in a doc comment align correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_DocCommentAlignmentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_DOC_COMMENT); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We are only interested in function/class/interface doc block comments. - $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); - $ignore = array( - T_CLASS, - T_INTERFACE, - T_FUNCTION, - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_STATIC, - T_ABSTRACT, - ); - - if (in_array($tokens[$nextToken]['code'], $ignore) === false) { - // Could be a file comment. - $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prevToken]['code'] !== T_OPEN_TAG) { - return; - } - } - - // We only want to get the first comment in a block. If there is - // a comment on the line before this one, return. - $docComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($stackPtr - 1)); - if ($docComment !== false) { - if ($tokens[$docComment]['line'] === ($tokens[$stackPtr]['line'] - 1)) { - return; - } - } - - $comments = array($stackPtr); - $currentComment = $stackPtr; - $lastComment = $stackPtr; - while (($currentComment = $phpcsFile->findNext(T_DOC_COMMENT, ($currentComment + 1))) !== false) { - if ($tokens[$lastComment]['line'] === ($tokens[$currentComment]['line'] - 1)) { - $comments[] = $currentComment; - $lastComment = $currentComment; - } else { - break; - } - } - - // The $comments array now contains pointers to each token in the - // comment block. - $requiredColumn = strpos($tokens[$stackPtr]['content'], '*'); - $requiredColumn += $tokens[$stackPtr]['column']; - - foreach ($comments as $commentPointer) { - // Check the spacing after each asterisk. - $content = $tokens[$commentPointer]['content']; - $firstChar = substr($content, 0, 1); - $lastChar = substr($content, -1); - if ($firstChar !== '/' && $lastChar !== '/') { - $matches = array(); - preg_match('|^(\s+)?\*(\s+)?@|', $content, $matches); - if (empty($matches) === false) { - if (isset($matches[2]) === false) { - $error = 'Expected 1 space between asterisk and tag; 0 found'; - $phpcsFile->addError($error, $commentPointer, 'NoSpaceBeforeTag'); - } else { - $length = strlen($matches[2]); - if ($length !== 1) { - $error = 'Expected 1 space between asterisk and tag; %s found'; - $data = array($length); - $phpcsFile->addError($error, $commentPointer, 'SpaceBeforeTag', $data); - } - } - } - }//end foreach - - // Check the alignment of each asterisk. - $currentColumn = strpos($content, '*'); - $currentColumn += $tokens[$commentPointer]['column']; - - if ($currentColumn === $requiredColumn) { - // Star is aligned correctly. - continue; - } - - $error = 'Expected %s space(s) before asterisk; %s found'; - $data = array( - ($requiredColumn - 1), - ($currentColumn - 1), - ); - $phpcsFile->addError($error, $commentPointer, 'SpaceBeforeAsterisk', $data); - }//end foreach - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php deleted file mode 100644 index 3de6fc605..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_EmptyCatchCommentSniff. - * - * Checks for empty Catch clause. Catch clause must at least have comment - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_EmptyCatchCommentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CATCH); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $scopeStart = $tokens[$stackPtr]['scope_opener']; - $firstContent = $phpcsFile->findNext(T_WHITESPACE, ($scopeStart + 1), $tokens[$stackPtr]['scope_closer'], true); - - if ($firstContent === false) { - $error = 'Empty CATCH statement must have a comment to explain why the exception is not handled'; - $phpcsFile->addError($error, $scopeStart, 'Missing'); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php deleted file mode 100644 index a98ea472c..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php +++ /dev/null @@ -1,564 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); -} - -/** - * Parses and verifies the file doc comment. - * - * Verifies that : - *
    - *
  • A file doc comment exists.
  • - *
  • There is no blank line between the open tag and the file comment.
  • - *
  • Short description ends with a full stop.
  • - *
  • There is a blank line after the short description.
  • - *
  • Each paragraph of the long description ends with a full stop.
  • - *
  • There is a blank line between the description and the tags.
  • - *
  • Check the order, indentation and content of each tag.
  • - *
  • There is exactly one blank line after the file comment.
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -class Squiz_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * The header comment parser for the current file. - * - * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser - */ - protected $commentParser = null; - - /** - * The current PHP_CodeSniffer_File object we are processing. - * - * @var PHP_CodeSniffer_File - */ - protected $currentFile = null; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - // We are only interested if this is the first open tag. - if ($stackPtr !== 0) { - if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { - return; - } - } - - $tokens = $phpcsFile->getTokens(); - - $errorToken = ($stackPtr + 1); - if (isset($tokens[$errorToken]) === false) { - $errorToken--; - } - - // Find the next non whitespace token. - $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - - if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) { - // We are only interested if this is the first open tag. - return; - } else if ($tokens[$commentStart]['code'] === T_COMMENT) { - $phpcsFile->addError('You must use "/**" style comments for a file comment', $errorToken, 'WrongStyle'); - return; - } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT) { - $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); - return; - } - - // Extract the header comment docblock. - $commentEnd = ($phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true) - 1); - - // Check if there is only 1 doc comment between the open tag and class token. - $nextToken = array( - T_ABSTRACT, - T_CLASS, - T_DOC_COMMENT, - ); - - $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1)); - if ($commentNext !== false && $tokens[$commentNext]['code'] !== T_DOC_COMMENT) { - // Found a class token right after comment doc block. - $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $commentNext, false, $phpcsFile->eolChar); - if ($newlineToken !== false) { - $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $commentNext, false, $phpcsFile->eolChar); - if ($newlineToken === false) { - // No blank line between the class token and the doc block. - // The doc block is most likely a class comment. - $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); - return; - } - } - } - - // No blank line between the open tag and the file comment. - $blankLineBefore = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, false, $phpcsFile->eolChar); - if ($blankLineBefore !== false && $blankLineBefore < $commentStart) { - $error = 'Extra newline found after the open tag'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen'); - } - - // Exactly one blank line after the file comment. - $nextTokenStart = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), null, true); - if ($nextTokenStart !== false) { - $blankLineAfter = 0; - for ($i = ($commentEnd + 1); $i < $nextTokenStart; $i++) { - if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) { - $blankLineAfter++; - } - } - - if ($blankLineAfter !== 2) { - $error = 'There must be exactly one blank line after the file comment'; - $phpcsFile->addError($error, ($commentEnd + 1), 'SpacingAfterComment'); - } - } - - $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - - // Parse the header comment docblock. - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'Exception'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'File doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - // The first line of the comment should just be the /** code. - $eolPos = strpos($commentString, $phpcsFile->eolChar); - $firstLine = substr($commentString, 0, $eolPos); - if ($firstLine !== '/**') { - $error = 'The open comment tag must be the only content on the line'; - $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); - } - - // No extra newline before short description. - $short = $comment->getShortComment(); - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before file comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in file comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); - } - - $newlineCount += $newlineBetween; - - $testLong = trim($long); - if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { - $error = 'File comment long description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); - } - }//end if - - // Exactly one blank line before tags. - $tags = $this->commentParser->getTagOrders(); - if (count($tags) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in file comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Short description must be single line and end with a full stop. - $testShort = trim($short); - if ($testShort === '') { - $error = 'Missing short description in file comment'; - $phpcsFile->addError($error, ($commentStart + 1), 'MissingShort'); - } else { - $lastChar = $testShort[(strlen($testShort) - 1)]; - if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { - $error = 'File comment short description must be on a single line'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); - } - - if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { - $error = 'File comment short description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); - } - - if ($lastChar !== '.') { - $error = 'File comment short description must end with a full stop'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); - } - }//end if - - // Check each tag. - $this->processTags($commentStart, $commentEnd); - - // The last content should be a newline and the content before - // that should not be blank. If there is more blank space - // then they have additional blank lines at the end of the comment. - $words = $this->commentParser->getWords(); - $lastPos = (count($words) - 1); - if (trim($words[($lastPos - 1)]) !== '' - || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false - || trim($words[($lastPos - 2)]) === '' - ) { - $error = 'Additional blank lines found at end of file comment'; - $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); - } - - }//end process() - - - /** - * Processes each required or optional tag. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processTags($commentStart, $commentEnd) - { - // Required tags in correct order. - $tags = array( - 'package' => 'precedes @subpackage', - 'subpackage' => 'follows @package', - 'author' => 'follows @subpackage', - 'copyright' => 'follows @author', - ); - - $foundTags = $this->commentParser->getTagOrders(); - $errorPos = 0; - $orderIndex = 0; - $longestTag = 0; - $indentation = array(); - foreach ($tags as $tag => $orderText) { - - // Required tag missing. - if (in_array($tag, $foundTags) === false) { - $error = 'Missing @%s tag in file comment'; - $data = array($tag); - $this->currentFile->addError($error, $commentEnd, 'Missing'.ucfirst($tag).'Tag', $data); - continue; - } - - // Get the line number for current tag. - $tagName = ucfirst($tag); - if ($tagName === 'Author' || $tagName === 'Copyright') { - // These tags are different because they return an array. - $tagName .= 's'; - } - - // Work out the line number for this tag. - $getMethod = 'get'.$tagName; - $tagElement = $this->commentParser->$getMethod(); - if (is_null($tagElement) === true || empty($tagElement) === true) { - continue; - } else if (is_array($tagElement) === true && empty($tagElement) === false) { - $tagElement = $tagElement[0]; - } - - $errorPos = ($commentStart + $tagElement->getLine()); - - // Make sure there is no duplicate tag. - $foundIndexes = array_keys($foundTags, $tag); - if (count($foundIndexes) > 1) { - $error = 'Only 1 @%s tag is allowed in file comment'; - $data = array($tag); - $this->currentFile->addError($error, $errorPos, 'Duplicate'.ucfirst($tag).'Tag', $data); - } - - // Check tag order. - if ($foundIndexes[0] > $orderIndex) { - $orderIndex = $foundIndexes[0]; - } else { - $error = 'The @%s tag is in the wrong order; the tag %s'; - $data = array( - $tag, - $orderText, - ); - $this->currentFile->addError($error, $errorPos, ucfirst($tag).'TagOrder', $data); - } - - // Store the indentation of each tag. - $len = strlen($tag); - if ($len > $longestTag) { - $longestTag = $len; - } - - $indentation[] = array( - 'tag' => $tag, - 'errorPos' => $errorPos, - 'space' => $this->getIndentation($tag, $tagElement), - ); - - $method = 'process'.$tagName; - if (method_exists($this, $method) === true) { - // Process each tag if a method is defined. - call_user_func(array($this, $method), $errorPos); - } else { - $tagElement->process($this->currentFile, $commentStart, 'file'); - } - }//end foreach - - // Check tag indentation. - foreach ($indentation as $indentInfo) { - $tagName = ucfirst($indentInfo['tag']); - if ($tagName === 'Author') { - $tagName .= 's'; - } - - if ($indentInfo['space'] !== 0 && $indentInfo['space'] !== ($longestTag + 1)) { - $expected = ($longestTag - strlen($indentInfo['tag']) + 1); - $space = ($indentInfo['space'] - strlen($indentInfo['tag'])); - $error = '@%s tag comment indented incorrectly; expected %s spaces but found %s'; - $data = array( - $indentInfo['tag'], - $expected, - $space, - ); - $this->currentFile->addError($error, $indentInfo['errorPos'], ucfirst($indentInfo['tag']).'TagIndent', $data); - } - } - - }//end processTags() - - - /** - * Get the indentation information of each tag. - * - * @param string $tagName The name of the doc comment element. - * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment element. - * - * @return void - */ - protected function getIndentation($tagName, $tagElement) - { - if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) { - if ($tagElement->getContent() !== '') { - return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' ')); - } - } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) { - if ($tagElement->getValue() !== '') { - return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' ')); - } - } - - return 0; - - }//end getIndentation() - - - /** - * The package name must be camel-cased. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processPackage($errorPos) - { - $package = $this->commentParser->getPackage(); - if ($package !== null) { - $content = $package->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @package tag in file comment'; - $this->currentFile->addError($error, $errorPos, 'MissingPackage'); - } else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { - // Package name must be properly camel-cased. - $nameBits = explode('_', str_replace(' ', '', $content)); - $firstBit = array_shift($nameBits); - $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; - foreach ($nameBits as $bit) { - $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - - $error = 'Package name "%s" is not valid; consider "%s" instead'; - $data = array( - $content, - trim($newName, '_'), - ); - $this->currentFile->addError($error, $errorPos, 'IncorrectPackage', $data); - } else if (strpos($content, 'Squiz') === 0) { - // Package name must not start with Squiz. - $newName = substr($content, 5); - $error = 'Package name "%s" is not valid; consider "%s" instead'; - $data = array( - $content, - $newName, - ); - $this->currentFile->addError($error, $errorPos, 'SquizPackage', $data); - } - } - - }//end processPackage() - - - /** - * The subpackage name must be camel-cased. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processSubpackage($errorPos) - { - $subpackage = $this->commentParser->getSubpackage(); - if ($subpackage !== null) { - $content = $subpackage->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @subpackage tag in file comment'; - $this->currentFile->addError($error, $errorPos, 'MissingSubpackage'); - } else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { - // Subpackage name must be properly camel-cased. - $nameBits = explode('_', $content); - $firstBit = array_shift($nameBits); - $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; - foreach ($nameBits as $bit) { - $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; - } - - $error = 'Subpackage name "%s" is not valid; consider "%s" instead'; - $data = array( - $content, - trim($newName, '_'), - ); - $this->currentFile->addError($error, $errorPos, 'IncorrectSubpackage', $data); - } - } - - }//end processSubpackage() - - - /** - * Author tag must be 'Squiz Pty Ltd '. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processAuthors($errorPos) - { - $authors = $this->commentParser->getAuthors(); - if (empty($authors) === false) { - $author = $authors[0]; - $content = $author->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @author tag in file comment'; - $this->currentFile->addError($error, $errorPos, 'MissingAuthor'); - } else if ($content !== 'Squiz Pty Ltd ') { - $error = 'Expected "Squiz Pty Ltd " for author tag'; - $this->currentFile->addError($error, $errorPos, 'IncorrectAuthor'); - } - } - - }//end processAuthors() - - - /** - * Copyright tag must be in the form '2006-YYYY Squiz Pty Ltd (ABN 77 084 670 600)'. - * - * @param int $errorPos The line number where the error occurs. - * - * @return void - */ - protected function processCopyrights($errorPos) - { - $copyrights = $this->commentParser->getCopyrights(); - $copyright = $copyrights[0]; - - if ($copyright !== null) { - $content = $copyright->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @copyright tag in file comment'; - $this->currentFile->addError($error, $errorPos, 'MissingCopyright'); - - } else if (preg_match('/^([0-9]{4})(-[0-9]{4})? (Squiz Pty Ltd \(ABN 77 084 670 600\))$/', $content) === 0) { - $error = 'Expected "xxxx-xxxx Squiz Pty Ltd (ABN 77 084 670 600)" for copyright declaration'; - $this->currentFile->addError($error, $errorPos, 'IncorrectCopyright'); - } - } - - }//end processCopyrights() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php deleted file mode 100644 index 09d63e1f3..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php +++ /dev/null @@ -1,818 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) { - $error = 'Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Parses and verifies the doc comments for functions. - * - * Verifies that : - *
    - *
  • A comment exists
  • - *
  • There is a blank newline after the short description
  • - *
  • There is a blank newline between the long and short description
  • - *
  • There is a blank newline between the long description and tags
  • - *
  • Parameter names represent those in the method
  • - *
  • Parameter comments are in the correct order
  • - *
  • Parameter comments are complete
  • - *
  • A type hint is provided for array and custom class
  • - *
  • Type hint matches the actual variable/class type
  • - *
  • A blank line is present before the first and after the last parameter
  • - *
  • A return type exists
  • - *
  • Any throw tag must have a comment
  • - *
  • The tag order and indentation are correct
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The name of the method that we are currently processing. - * - * @var string - */ - private $_methodName = ''; - - /** - * The position in the stack where the function token was found. - * - * @var int - */ - private $_functionToken = null; - - /** - * The position in the stack where the class token was found. - * - * @var int - */ - private $_classToken = null; - - /** - * The index of the current tag we are processing. - * - * @var int - */ - private $_tagIndex = 0; - - /** - * The function comment parser for the current method. - * - * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser - */ - protected $commentParser = null; - - /** - * The current PHP_CodeSniffer_File object we are processing. - * - * @var PHP_CodeSniffer_File - */ - protected $currentFile = null; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - - $tokens = $phpcsFile->getTokens(); - - $find = array( - T_COMMENT, - T_DOC_COMMENT, - T_CLASS, - T_FUNCTION, - T_OPEN_TAG, - ); - - $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1)); - - if ($commentEnd === false) { - return; - } - - // If the token that we found was a class or a function, then this - // function has no doc comment. - $code = $tokens[$commentEnd]['code']; - - if ($code === T_COMMENT) { - // The function might actually be missing a comment, and this last comment - // found is just commenting a bit of code on a line. So if it is not the - // only thing on the line, assume we found nothing. - $prevContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $commentEnd); - if ($tokens[$commentEnd]['line'] === $tokens[$commentEnd]['line']) { - $error = 'Missing function doc comment'; - $phpcsFile->addError($error, $stackPtr, 'Missing'); - } else { - $error = 'You must use "/**" style comments for a function comment'; - $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); - } - return; - } else if ($code !== T_DOC_COMMENT) { - $error = 'Missing function doc comment'; - $phpcsFile->addError($error, $stackPtr, 'Missing'); - return; - } else if (trim($tokens[$commentEnd]['content']) !== '*/') { - $error = 'You must use "*/" to end a function comment; found "%s"'; - $phpcsFile->addError($error, $commentEnd, 'WrongEnd', array(trim($tokens[$commentEnd]['content']))); - return; - } - - // If there is any code between the function keyword and the doc block - // then the doc block is not for us. - $ignore = PHP_CodeSniffer_Tokens::$scopeModifiers; - $ignore[] = T_STATIC; - $ignore[] = T_WHITESPACE; - $ignore[] = T_ABSTRACT; - $ignore[] = T_FINAL; - $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); - if ($prevToken !== $commentEnd) { - $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); - return; - } - - $this->_functionToken = $stackPtr; - - $this->_classToken = null; - foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) { - if ($condition === T_CLASS || $condition === T_INTERFACE) { - $this->_classToken = $condPtr; - break; - } - } - - // Find the first doc comment. - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - $this->_methodName = $phpcsFile->getDeclarationName($stackPtr); - - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($commentString, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'Function doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - // The first line of the comment should just be the /** code. - $eolPos = strpos($commentString, $phpcsFile->eolChar); - $firstLine = substr($commentString, 0, $eolPos); - if ($firstLine !== '/**') { - $error = 'The open comment tag must be the only content on the line'; - $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); - } - - $this->processParams($commentStart, $commentEnd); - $this->processSees($commentStart); - $this->processReturn($commentStart, $commentEnd); - $this->processThrows($commentStart); - - // Check for a comment description. - $short = $comment->getShortComment(); - if (trim($short) === '') { - $error = 'Missing short description in function doc comment'; - $phpcsFile->addError($error, $commentStart, 'MissingShort'); - return; - } - - // No extra newline before short description. - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before function comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in function comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); - } - - $newlineCount += $newlineBetween; - - $testLong = trim($long); - if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { - $error = 'Function comment long description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); - } - }//end if - - // Exactly one blank line before tags. - $params = $this->commentParser->getTagOrders(); - if (count($params) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in function comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Short description must be single line and end with a full stop. - $testShort = trim($short); - $lastChar = $testShort[(strlen($testShort) - 1)]; - if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { - $error = 'Function comment short description must be on a single line'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); - } - - if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { - $error = 'Function comment short description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); - } - - if ($lastChar !== '.') { - $error = 'Function comment short description must end with a full stop'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); - } - - // Check for unknown/deprecated tags. - $this->processUnknownTags($commentStart, $commentEnd); - - // The last content should be a newline and the content before - // that should not be blank. If there is more blank space - // then they have additional blank lines at the end of the comment. - $words = $this->commentParser->getWords(); - $lastPos = (count($words) - 1); - if (trim($words[($lastPos - 1)]) !== '' - || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false - || trim($words[($lastPos - 2)]) === '' - ) { - $error = 'Additional blank lines found at end of function comment'; - $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); - } - - }//end process() - - - /** - * Process the see tags. - * - * @param int $commentStart The position in the stack where the comment started. - * - * @return void - */ - protected function processSees($commentStart) - { - $sees = $this->commentParser->getSees(); - if (empty($sees) === false) { - $tagOrder = $this->commentParser->getTagOrders(); - $index = array_keys($this->commentParser->getTagOrders(), 'see'); - foreach ($sees as $i => $see) { - $errorPos = ($commentStart + $see->getLine()); - $since = array_keys($tagOrder, 'since'); - if (count($since) === 1 && $this->_tagIndex !== 0) { - $this->_tagIndex++; - if ($index[$i] !== $this->_tagIndex) { - $error = 'The @see tag is in the wrong order; the tag precedes @return'; - $this->currentFile->addError($error, $errorPos, 'SeeOrder'); - } - } - - $content = $see->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @see tag in function comment'; - $this->currentFile->addError($error, $errorPos, 'EmptySee'); - continue; - } - - $spacing = substr_count($see->getWhitespaceBeforeContent(), ' '); - if ($spacing !== 4) { - $error = '@see tag indented incorrectly; expected 4 spaces but found %s'; - $data = array($spacing); - $this->currentFile->addError($error, $errorPos, 'SeeIndent', $data); - } - }//end foreach - }//end if - - }//end processSees() - - - /** - * Process the return comment of this function comment. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processReturn($commentStart, $commentEnd) - { - // Skip constructor and destructor. - $className = ''; - if ($this->_classToken !== null) { - $className = $this->currentFile->getDeclarationName($this->_classToken); - $className = strtolower(ltrim($className, '_')); - } - - $methodName = strtolower(ltrim($this->_methodName, '_')); - $isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct'); - $return = $this->commentParser->getReturn(); - - if ($isSpecialMethod === false && $methodName !== $className) { - if ($return !== null) { - $tagOrder = $this->commentParser->getTagOrders(); - $index = array_keys($tagOrder, 'return'); - $errorPos = ($commentStart + $return->getLine()); - $content = trim($return->getRawContent()); - - if (count($index) > 1) { - $error = 'Only 1 @return tag is allowed in function comment'; - $this->currentFile->addError($error, $errorPos, 'DuplicateReturn'); - return; - } - - $since = array_keys($tagOrder, 'since'); - if (count($since) === 1 && $this->_tagIndex !== 0) { - $this->_tagIndex++; - if ($index[0] !== $this->_tagIndex) { - $error = 'The @return tag is in the wrong order; the tag follows @see (if used)'; - $this->currentFile->addError($error, $errorPos, 'ReturnOrder'); - } - } - - if (empty($content) === true) { - $error = 'Return type missing for @return tag in function comment'; - $this->currentFile->addError($error, $errorPos, 'MissingReturnType'); - } else { - // Check return type (can be multiple, separated by '|'). - $typeNames = explode('|', $content); - $suggestedNames = array(); - foreach ($typeNames as $i => $typeName) { - $suggestedName = PHP_CodeSniffer::suggestType($typeName); - if (in_array($suggestedName, $suggestedNames) === false) { - $suggestedNames[] = $suggestedName; - } - } - - $suggestedType = implode('|', $suggestedNames); - if ($content !== $suggestedType) { - $error = 'Function return type "%s" is invalid'; - $data = array($content); - $this->currentFile->addError($error, $errorPos, 'InvalidReturn', $data); - } - - $tokens = $this->currentFile->getTokens(); - - // If the return type is void, make sure there is - // no return statement in the function. - if ($content === 'void') { - if (isset($tokens[$this->_functionToken]['scope_closer']) === true) { - $endToken = $tokens[$this->_functionToken]['scope_closer']; - - $tokens = $this->currentFile->getTokens(); - for ($returnToken = $this->_functionToken; $returnToken < $endToken; $returnToken++) { - if ($tokens[$returnToken]['code'] === T_CLOSURE) { - $returnToken = $tokens[$returnToken]['scope_closer']; - continue; - } - - if ($tokens[$returnToken]['code'] === T_RETURN) { - break; - } - } - - if ($returnToken !== $endToken) { - // If the function is not returning anything, just - // exiting, then there is no problem. - $semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true); - if ($tokens[$semicolon]['code'] !== T_SEMICOLON) { - $error = 'Function return type is void, but function contains return statement'; - $this->currentFile->addError($error, $errorPos, 'InvalidReturnVoid'); - } - } - } - } else if ($content !== 'mixed') { - // If return type is not void, there needs to be a - // returns statement somewhere in the function that - // returns something. - if (isset($tokens[$this->_functionToken]['scope_closer']) === true) { - $endToken = $tokens[$this->_functionToken]['scope_closer']; - $returnToken = $this->currentFile->findNext(T_RETURN, $this->_functionToken, $endToken); - if ($returnToken === false) { - $error = 'Function return type is not void, but function has no return statement'; - $this->currentFile->addError($error, $errorPos, 'InvalidNoReturn'); - } else { - $semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true); - if ($tokens[$semicolon]['code'] === T_SEMICOLON) { - $error = 'Function return type is not void, but function is returning void here'; - $this->currentFile->addError($error, $returnToken, 'InvalidReturnNotVoid'); - } - } - } - }//end if - - $spacing = substr_count($return->getWhitespaceBeforeValue(), ' '); - if ($spacing !== 1) { - $error = '@return tag indented incorrectly; expected 1 space but found %s'; - $data = array($spacing); - $this->currentFile->addError($error, $errorPos, 'ReturnIndent', $data); - } - }//end if - } else { - $error = 'Missing @return tag in function comment'; - $this->currentFile->addError($error, $commentEnd, 'MissingReturn'); - }//end if - - } else { - // No return tag for constructor and destructor. - if ($return !== null) { - $errorPos = ($commentStart + $return->getLine()); - $error = '@return tag is not required for constructor and destructor'; - $this->currentFile->addError($error, $errorPos, 'ReturnNotRequired'); - } - }//end if - - }//end processReturn() - - - /** - * Process any throw tags that this function comment has. - * - * @param int $commentStart The position in the stack where the comment started. - * - * @return void - */ - protected function processThrows($commentStart) - { - if (count($this->commentParser->getThrows()) === 0) { - return; - } - - $tagOrder = $this->commentParser->getTagOrders(); - $index = array_keys($this->commentParser->getTagOrders(), 'throws'); - - foreach ($this->commentParser->getThrows() as $i => $throw) { - $exception = $throw->getValue(); - $content = trim($throw->getComment()); - $errorPos = ($commentStart + $throw->getLine()); - if (empty($exception) === true) { - $error = 'Exception type and comment missing for @throws tag in function comment'; - $this->currentFile->addError($error, $errorPos, 'InvalidThrows'); - } else if (empty($content) === true) { - $error = 'Comment missing for @throws tag in function comment'; - $this->currentFile->addError($error, $errorPos, 'EmptyThrows'); - } else { - // Starts with a capital letter and ends with a fullstop. - $firstChar = $content{0}; - if (strtoupper($firstChar) !== $firstChar) { - $error = '@throws tag comment must start with a capital letter'; - $this->currentFile->addError($error, $errorPos, 'ThrowsNotCapital'); - } - - $lastChar = $content[(strlen($content) - 1)]; - if ($lastChar !== '.') { - $error = '@throws tag comment must end with a full stop'; - $this->currentFile->addError($error, $errorPos, 'ThrowsNoFullStop'); - } - } - - $since = array_keys($tagOrder, 'since'); - if (count($since) === 1 && $this->_tagIndex !== 0) { - $this->_tagIndex++; - if ($index[$i] !== $this->_tagIndex) { - $error = 'The @throws tag is in the wrong order; the tag follows @return'; - $this->currentFile->addError($error, $errorPos, 'ThrowsOrder'); - } - } - }//end foreach - - }//end processThrows() - - - /** - * Process the function parameter comments. - * - * @param int $commentStart The position in the stack where - * the comment started. - * @param int $commentEnd The position in the stack where - * the comment ended. - * - * @return void - */ - protected function processParams($commentStart, $commentEnd) - { - $realParams = $this->currentFile->getMethodParameters($this->_functionToken); - $params = $this->commentParser->getParams(); - $foundParams = array(); - - if (empty($params) === false) { - - if (substr_count($params[(count($params) - 1)]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) { - $error = 'Last parameter comment requires a blank newline after it'; - $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); - $this->currentFile->addError($error, $errorPos, 'SpacingAfterParams'); - } - - // Parameters must appear immediately after the comment. - if ($params[0]->getOrder() !== 2) { - $error = 'Parameters must appear immediately after the comment'; - $errorPos = ($params[0]->getLine() + $commentStart); - $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParams'); - } - - $previousParam = null; - $spaceBeforeVar = 10000; - $spaceBeforeComment = 10000; - $longestType = 0; - $longestVar = 0; - - foreach ($params as $param) { - - $paramComment = trim($param->getComment()); - $errorPos = ($param->getLine() + $commentStart); - - // Make sure that there is only one space before the var type. - if ($param->getWhitespaceBeforeType() !== ' ') { - $error = 'Expected 1 space before variable type'; - $this->currentFile->addError($error, $errorPos, 'SpacingBeforeParamType'); - } - - $spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' '); - if ($spaceCount < $spaceBeforeVar) { - $spaceBeforeVar = $spaceCount; - $longestType = $errorPos; - } - - $spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' '); - - if ($spaceCount < $spaceBeforeComment && $paramComment !== '') { - $spaceBeforeComment = $spaceCount; - $longestVar = $errorPos; - } - - // Make sure they are in the correct order, and have the correct name. - $pos = $param->getPosition(); - $paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]'; - - if ($previousParam !== null) { - $previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN'; - - // Check to see if the parameters align properly. - if ($param->alignsVariableWith($previousParam) === false) { - $error = 'The variable names for parameters %s (%s) and %s (%s) do not align'; - $data = array( - $previousName, - ($pos - 1), - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'ParameterNamesNotAligned', $data); - } - - if ($param->alignsCommentWith($previousParam) === false) { - $error = 'The comments for parameters %s (%s) and %s (%s) do not align'; - $data = array( - $previousName, - ($pos - 1), - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'ParameterCommentsNotAligned', $data); - } - } - - // Variable must be one of the supported standard type. - $typeNames = explode('|', $param->getType()); - foreach ($typeNames as $typeName) { - $suggestedName = PHP_CodeSniffer::suggestType($typeName); - if ($typeName !== $suggestedName) { - $error = 'Expected "%s"; found "%s" for %s at position %s'; - $data = array( - $suggestedName, - $typeName, - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'IncorrectParamVarName', $data); - } else if (count($typeNames) === 1) { - // Check type hint for array and custom type. - $suggestedTypeHint = ''; - if (strpos($suggestedName, 'array') !== false) { - $suggestedTypeHint = 'array'; - } else if (strpos($suggestedName, 'callable') !== false) { - $suggestedTypeHint = 'callable'; - } else if (in_array($typeName, PHP_CodeSniffer::$allowedTypes) === false) { - $suggestedTypeHint = $suggestedName; - } - - if ($suggestedTypeHint !== '' && isset($realParams[($pos - 1)]) === true) { - $typeHint = $realParams[($pos - 1)]['type_hint']; - if ($typeHint === '') { - $error = 'Type hint "%s" missing for %s at position %s'; - $data = array( - $suggestedTypeHint, - $paramName, - $pos, - ); - $this->currentFile->addError($error, ($commentEnd + 2), 'TypeHintMissing', $data); - } else if ($typeHint !== $suggestedTypeHint) { - $error = 'Expected type hint "%s"; found "%s" for %s at position %s'; - $data = array( - $suggestedTypeHint, - $typeHint, - $paramName, - $pos, - ); - $this->currentFile->addError($error, ($commentEnd + 2), 'IncorrectTypeHint', $data); - } - } else if ($suggestedTypeHint === '' && isset($realParams[($pos - 1)]) === true) { - $typeHint = $realParams[($pos - 1)]['type_hint']; - if ($typeHint !== '') { - $error = 'Unknown type hint "%s" found for %s at position %s'; - $data = array( - $typeHint, - $paramName, - $pos, - ); - $this->currentFile->addError($error, ($commentEnd + 2), 'InvalidTypeHint', $data); - } - } - }//end if - }//end foreach - - // Make sure the names of the parameter comment matches the - // actual parameter. - if (isset($realParams[($pos - 1)]) === true) { - $realName = $realParams[($pos - 1)]['name']; - $foundParams[] = $realName; - - // Append ampersand to name if passing by reference. - if ($realParams[($pos - 1)]['pass_by_reference'] === true) { - $realName = '&'.$realName; - } - - if ($realName !== $paramName) { - $code = 'ParamNameNoMatch'; - $data = array( - $paramName, - $realName, - $pos, - ); - - $error = 'Doc comment for var %s does not match '; - if (strtolower($paramName) === strtolower($realName)) { - $error .= 'case of '; - $code = 'ParamNameNoCaseMatch'; - } - - $error .= 'actual variable name %s at position %s'; - - $this->currentFile->addError($error, $errorPos, $code, $data); - } - } else if (substr($paramName, -4) !== ',...') { - // We must have an extra parameter comment. - $error = 'Superfluous doc comment at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'ExtraParamComment'); - } - - if ($param->getVarName() === '') { - $error = 'Missing parameter name at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'MissingParamName'); - } - - if ($param->getType() === '') { - $error = 'Missing type at position '.$pos; - $this->currentFile->addError($error, $errorPos, 'MissingParamType'); - } - - if ($paramComment === '') { - $error = 'Missing comment for param "%s" at position %s'; - $data = array( - $paramName, - $pos, - ); - $this->currentFile->addError($error, $errorPos, 'MissingParamComment', $data); - } else { - // Param comments must start with a capital letter and - // end with the full stop. - $firstChar = $paramComment{0}; - if (preg_match('|\p{Lu}|u', $firstChar) === 0) { - $error = 'Param comment must start with a capital letter'; - $this->currentFile->addError($error, $errorPos, 'ParamCommentNotCapital'); - } - - $lastChar = $paramComment[(strlen($paramComment) - 1)]; - if ($lastChar !== '.') { - $error = 'Param comment must end with a full stop'; - $this->currentFile->addError($error, $errorPos, 'ParamCommentFullStop'); - } - } - - $previousParam = $param; - - }//end foreach - - if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) { - $error = 'Expected 1 space after the longest type'; - $this->currentFile->addError($error, $longestType, 'SpacingAfterLongType'); - } - - if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { - $error = 'Expected 1 space after the longest variable name'; - $this->currentFile->addError($error, $longestVar, 'SpacingAfterLongName'); - } - - }//end if - - $realNames = array(); - foreach ($realParams as $realParam) { - $realNames[] = $realParam['name']; - } - - // Report missing comments. - $diff = array_diff($realNames, $foundParams); - foreach ($diff as $neededParam) { - if (count($params) !== 0) { - $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); - } else { - $errorPos = $commentStart; - } - - $error = 'Doc comment for "%s" missing'; - $data = array($neededParam); - $this->currentFile->addError($error, $errorPos, 'MissingParamTag', $data); - } - - }//end processParams() - - - /** - * Process a list of unknown tags. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processUnknownTags($commentStart, $commentEnd) - { - - }//end processUnknownTags - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php deleted file mode 100644 index eed031a86..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php +++ /dev/null @@ -1,215 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Verifies that a @throws tag exists for a function that throws exceptions. - * Verifies the number of @throws tags and the number of throw tokens matches. - * Verifies the exception type. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs a Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff. - */ - public function __construct() - { - parent::__construct(array(T_FUNCTION), array(T_THROW)); - - }//end __construct() - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * @param int $currScope The current scope opener token. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - // Is this the first throw token within the current function scope? - // If so, we have to validate other throw tokens within the same scope. - $previousThrow = $phpcsFile->findPrevious(T_THROW, ($stackPtr - 1), $currScope); - if ($previousThrow !== false) { - return; - } - - $tokens = $phpcsFile->getTokens(); - - $find = array( - T_COMMENT, - T_DOC_COMMENT, - T_CLASS, - T_FUNCTION, - T_OPEN_TAG, - ); - - $commentEnd = $phpcsFile->findPrevious($find, ($currScope - 1)); - - if ($commentEnd === false) { - return; - } - - if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { - // Function doesn't have a comment. Let someone else warn about that. - return; - } - - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'FailedParse'); - return; - } - - // Find the position where the current function scope ends. - $currScopeEnd = 0; - if (isset($tokens[$currScope]['scope_closer']) === true) { - $currScopeEnd = $tokens[$currScope]['scope_closer']; - } - - // Find all the exception type token within the current scope. - $throwTokens = array(); - $currPos = $stackPtr; - if ($currScopeEnd !== 0) { - while ($currPos < $currScopeEnd && $currPos !== false) { - - /* - If we can't find a NEW, we are probably throwing - a variable, so we ignore it, but they still need to - provide at least one @throws tag, even through we - don't know the exception class. - */ - - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($currPos + 1), null, true); - if ($tokens[$nextToken]['code'] === T_NEW) { - $currException = $phpcsFile->findNext( - array( - T_NS_SEPARATOR, - T_STRING, - ), - $currPos, - $currScopeEnd, - false, - null, - true - ); - - if ($currException !== false) { - $endException = $phpcsFile->findNext( - array( - T_NS_SEPARATOR, - T_STRING, - ), - ($currException + 1), - $currScopeEnd, - true, - null, - true - ); - - if ($endException === false) { - $throwTokens[] = $tokens[$currException]['content']; - } else { - $throwTokens[] = $phpcsFile->getTokensAsString($currException, ($endException - $currException)); - } - }//end if - }//end if - - $currPos = $phpcsFile->findNext(T_THROW, ($currPos + 1), $currScopeEnd); - }//end while - }//end if - - // Only need one @throws tag for each type of exception thrown. - $throwTokens = array_unique($throwTokens); - sort($throwTokens); - - $throws = $this->commentParser->getThrows(); - if (empty($throws) === true) { - $error = 'Missing @throws tag in function comment'; - $phpcsFile->addError($error, $commentEnd, 'Missing'); - } else if (empty($throwTokens) === true) { - // If token count is zero, it means that only variables are being - // thrown, so we need at least one @throws tag (checked above). - // Nothing more to do. - return; - } else { - $throwTags = array(); - $lineNumber = array(); - foreach ($throws as $throw) { - $throwTags[] = $throw->getValue(); - $lineNumber[$throw->getValue()] = $throw->getLine(); - } - - $throwTags = array_unique($throwTags); - sort($throwTags); - - // Make sure @throws tag count matches throw token count. - $tokenCount = count($throwTokens); - $tagCount = count($throwTags); - if ($tokenCount !== $tagCount) { - $error = 'Expected %s @throws tag(s) in function comment; %s found'; - $data = array( - $tokenCount, - $tagCount, - ); - $phpcsFile->addError($error, $commentEnd, 'WrongNumber', $data); - return; - } else { - // Exception type in @throws tag must be thrown in the function. - foreach ($throwTags as $i => $throwTag) { - $errorPos = ($commentStart + $lineNumber[$throwTag]); - if (empty($throwTag) === false && $throwTag !== $throwTokens[$i]) { - $error = 'Expected "%s" but found "%s" for @throws tag exception'; - $data = array( - $throwTokens[$i], - $throwTag, - ); - $phpcsFile->addError($error, $errorPos, 'WrongType', $data); - } - } - } - }//end if - - }//end processTokenWithinScope() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php deleted file mode 100644 index 13669394b..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php +++ /dev/null @@ -1,272 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_InlineCommentSniff. - * - * Checks that there is adequate spacing between comments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_COMMENT, - T_DOC_COMMENT, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If this is a function/class/interface doc block comment, skip it. - // We are only interested in inline doc block comments, which are - // not allowed. - if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) { - $nextToken = $phpcsFile->findNext( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($stackPtr + 1), - null, - true - ); - - $ignore = array( - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_FUNCTION, - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_FINAL, - T_STATIC, - T_ABSTRACT, - T_CONST, - T_OBJECT, - T_PROPERTY, - ); - - if (in_array($tokens[$nextToken]['code'], $ignore) === true) { - return; - } else { - if ($phpcsFile->tokenizerType === 'JS') { - // We allow block comments if a function is being assigned - // to a variable. - $ignore = PHP_CodeSniffer_Tokens::$emptyTokens; - $ignore[] = T_EQUAL; - $ignore[] = T_STRING; - $ignore[] = T_OBJECT_OPERATOR; - $nextToken = $phpcsFile->findNext($ignore, ($nextToken + 1), null, true); - if ($tokens[$nextToken]['code'] === T_FUNCTION) { - return; - } - } - - $prevToken = $phpcsFile->findPrevious( - PHP_CodeSniffer_Tokens::$emptyTokens, - ($stackPtr - 1), - null, - true - ); - - if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { - return; - } - - // Only error once per comment. - if (substr($tokens[$stackPtr]['content'], 0, 3) === '/**') { - $error = 'Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead'; - $phpcsFile->addError($error, $stackPtr, 'DocBlock'); - } - }//end if - }//end if - - if ($tokens[$stackPtr]['content']{0} === '#') { - $error = 'Perl-style comments are not allowed; use "// Comment" instead'; - $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); - } - - // We don't want end of block comments. If the last comment is a closing - // curly brace. - $previousContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$previousContent]['line'] === $tokens[$stackPtr]['line']) { - if ($tokens[$previousContent]['code'] === T_CLOSE_CURLY_BRACKET) { - return; - } - - // Special case for JS files. - if ($tokens[$previousContent]['code'] === T_COMMA - || $tokens[$previousContent]['code'] === T_SEMICOLON - ) { - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($previousContent - 1), null, true); - if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { - return; - } - } - } - - $comment = rtrim($tokens[$stackPtr]['content']); - - // Only want inline comments. - if (substr($comment, 0, 2) !== '//') { - return; - } - - $spaceCount = 0; - for ($i = 2; $i < strlen($comment); $i++) { - if ($comment[$i] !== ' ') { - break; - } - - $spaceCount++; - } - - if ($spaceCount === 0) { - $error = 'No space before comment text; expected "// %s" but found "%s"'; - $data = array( - substr($comment, 2), - $comment, - ); - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore', $data); - } - - if ($spaceCount > 1) { - $error = '%s spaces found before inline comment line; use block comment if you need indentation'; - $data = array( - $spaceCount, - substr($comment, (2 + $spaceCount)), - $comment, - ); - $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); - } - - - // The below section determines if a comment block is correctly capitalised, - // and ends in a full-stop. It will find the last comment in a block, and - // work its way up. - $nextComment = $phpcsFile->findNext(array(T_COMMENT), ($stackPtr + 1), null, false); - - if (($nextComment !== false) && (($tokens[$nextComment]['line']) === ($tokens[$stackPtr]['line'] + 1))) { - return; - } - - $topComment = $stackPtr; - $lastComment = $stackPtr; - while (($topComment = $phpcsFile->findPrevious(array(T_COMMENT), ($lastComment - 1), null, false)) !== false) { - if ($tokens[$topComment]['line'] !== ($tokens[$lastComment]['line'] - 1)) { - break; - } - - $lastComment = $topComment; - } - - $topComment = $lastComment; - $commentText = ''; - - for ($i = $topComment; $i <= $stackPtr; $i++) { - if ($tokens[$i]['code'] === T_COMMENT) { - $commentText .= trim(substr($tokens[$i]['content'], 2)); - } - } - - if ($commentText === '') { - $error = 'Blank comments are not allowed'; - $phpcsFile->addError($error, $stackPtr, 'Empty'); - return; - } - - if (preg_match('|\p{Lu}|u', $commentText[0]) === 0) { - $error = 'Inline comments must start with a capital letter'; - $phpcsFile->addError($error, $topComment, 'NotCapital'); - } - - $commentCloser = $commentText[(strlen($commentText) - 1)]; - $acceptedClosers = array( - 'full-stops' => '.', - 'exclamation marks' => '!', - 'or question marks' => '?', - ); - - if (in_array($commentCloser, $acceptedClosers) === false) { - $error = 'Inline comments must end in %s'; - $ender = ''; - foreach ($acceptedClosers as $closerName => $symbol) { - $ender .= ' '.$closerName.','; - } - - $ender = rtrim($ender, ','); - $data = array($ender); - $phpcsFile->addError($error, $stackPtr, 'InvalidEndChar', $data); - } - - // Finally, the line below the last comment cannot be empty. - $start = false; - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['line'] === ($tokens[$stackPtr]['line'] + 1)) { - if ($tokens[$i]['code'] !== T_WHITESPACE) { - return; - } - } else if ($tokens[$i]['line'] > ($tokens[$stackPtr]['line'] + 1)) { - break; - } - } - - $error = 'There must be no blank line following an inline comment'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfter'); - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php deleted file mode 100644 index b2a8f601d..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_LongConditionClosingCommentSniff. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * The openers that we are interested in. - * - * @var array(int) - */ - private static $_openers = array( - T_SWITCH, - T_IF, - T_FOR, - T_FOREACH, - T_WHILE, - T_TRY, - T_CASE, - ); - - /** - * The length that a code block must be before - * requiring a closing comment. - * - * @var int - */ - protected $lineLimit = 20; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CLOSE_CURLY_BRACKET); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_condition']) === false) { - // No scope condition. It is a function closer. - return; - } - - $startCondition = $tokens[$tokens[$stackPtr]['scope_condition']]; - $startBrace = $tokens[$tokens[$stackPtr]['scope_opener']]; - $endBrace = $tokens[$stackPtr]; - - // We are only interested in some code blocks. - if (in_array($startCondition['code'], self::$_openers) === false) { - return; - } - - if ($startCondition['code'] === T_IF) { - // If this is actually and ELSE IF, skip it as the brace - // will be checked by the original IF. - $else = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$stackPtr]['scope_condition'] - 1), null, true); - if ($tokens[$else]['code'] === T_ELSE) { - return; - } - - // IF statements that have an ELSE block need to use - // "end if" rather than "end else" or "end elseif". - do { - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$nextToken]['code'] === T_ELSE || $tokens[$nextToken]['code'] === T_ELSEIF) { - // Check for ELSE IF (2 tokens) as opposed to ELSEIF (1 token). - if ($tokens[$nextToken]['code'] === T_ELSE - && isset($tokens[$nextToken]['scope_closer']) === false - ) { - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true); - if ($tokens[$nextToken]['code'] !== T_IF - || isset($tokens[$nextToken]['scope_closer']) === false - ) { - // Not an ELSE IF or is an inline ELSE IF. - break; - } - } - - // The end brace becomes the ELSE's end brace. - $stackPtr = $tokens[$nextToken]['scope_closer']; - $endBrace = $tokens[$stackPtr]; - } else { - break; - } - } while (isset($tokens[$nextToken]['scope_closer']) === true); - }//end if - - if ($startCondition['code'] === T_TRY) { - // TRY statements need to check until the end of all CATCH statements. - do { - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$nextToken]['code'] === T_CATCH) { - // The end brace becomes the CATCH's end brace. - $stackPtr = $tokens[$nextToken]['scope_closer']; - $endBrace = $tokens[$stackPtr]; - } else { - break; - } - } while (isset($tokens[$nextToken]['scope_closer']) === true); - } - - $lineDifference = ($endBrace['line'] - $startBrace['line']); - - $expected = '//end '.$startCondition['content']; - $comment = $phpcsFile->findNext(array(T_COMMENT), $stackPtr, null, false); - - if (($comment === false) || ($tokens[$comment]['line'] !== $endBrace['line'])) { - if ($lineDifference >= $this->lineLimit) { - $error = 'End comment for long condition not found; expected "%s"'; - $data = array($expected); - $phpcsFile->addError($error, $stackPtr, 'Missing', $data); - } - - return; - } - - if (($comment - $stackPtr) !== 1) { - $error = 'Space found before closing comment; expected "%s"'; - $data = array($expected); - $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); - } - - if (trim($tokens[$comment]['content']) !== $expected) { - $found = trim($tokens[$comment]['content']); - $error = 'Incorrect closing comment; expected "%s" but found "%s"'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'Invalid', $data); - return; - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php deleted file mode 100644 index c71ded07a..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Commenting_PostStatementCommentSniff. - * - * Checks to ensure that there are no comments after statements. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Commenting_PostStatementCommentSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_COMMENT); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { - return; - } - - $commentLine = $tokens[$stackPtr]['line']; - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - - if ($tokens[$lastContent]['line'] !== $commentLine) { - return; - } - - if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { - return; - } - - // Special case for JS files. - if ($tokens[$lastContent]['code'] === T_COMMA - || $tokens[$lastContent]['code'] === T_SEMICOLON - ) { - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($lastContent - 1), null, true); - if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { - return; - } - } - - $error = 'Comments may not appear after statements.'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php deleted file mode 100644 index fd0501edb..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php +++ /dev/null @@ -1,345 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -if (class_exists('PHP_CodeSniffer_CommentParser_MemberCommentParser', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_MemberCommentParser not found'); -} - -/** - * Parses and verifies the variable doc comment. - * - * Verifies that : - *
    - *
  • A variable doc comment exists.
  • - *
  • Short description ends with a full stop.
  • - *
  • There is a blank line after the short description.
  • - *
  • There is a blank line between the description and the tags.
  • - *
  • Check the order, indentation and content of each tag.
  • - *
- * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -class Squiz_Sniffs_Commenting_VariableCommentSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - /** - * The header comment parser for the current file. - * - * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser - */ - protected $commentParser = null; - - - /** - * Called to process class member vars. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->currentFile = $phpcsFile; - $tokens = $phpcsFile->getTokens(); - $commentToken = array( - T_COMMENT, - T_DOC_COMMENT, - ); - - // Extract the var comment docblock. - $commentEnd = $phpcsFile->findPrevious($commentToken, ($stackPtr - 3)); - if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { - $phpcsFile->addError('You must use "/**" style comments for a variable comment', $stackPtr, 'WrongStyle'); - return; - } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { - $phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing'); - return; - } else { - // Make sure the comment we have found belongs to us. - $commentFor = $phpcsFile->findNext(array(T_VARIABLE, T_CLASS, T_INTERFACE), ($commentEnd + 1)); - if ($commentFor !== $stackPtr) { - $phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing'); - return; - } - } - - $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); - $commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); - - // Parse the header comment docblock. - try { - $this->commentParser = new PHP_CodeSniffer_CommentParser_MemberCommentParser($commentString, $phpcsFile); - $this->commentParser->parse(); - } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { - $line = ($e->getLineWithinComment() + $commentStart); - $phpcsFile->addError($e->getMessage(), $line, 'ErrorParsing'); - return; - } - - $comment = $this->commentParser->getComment(); - if (is_null($comment) === true) { - $error = 'Variable doc comment is empty'; - $phpcsFile->addError($error, $commentStart, 'Empty'); - return; - } - - // The first line of the comment should just be the /** code. - $eolPos = strpos($commentString, $phpcsFile->eolChar); - $firstLine = substr($commentString, 0, $eolPos); - if ($firstLine !== '/**') { - $error = 'The open comment tag must be the only content on the line'; - $phpcsFile->addError($error, $commentStart, 'ContentAfterOpen'); - } - - // Check for a comment description. - $short = $comment->getShortComment(); - $long = ''; - if (trim($short) === '') { - $error = 'Missing short description in variable doc comment'; - $phpcsFile->addError($error, $commentStart, 'MissingShort'); - $newlineCount = 1; - } else { - // No extra newline before short description. - $newlineCount = 0; - $newlineSpan = strspn($short, $phpcsFile->eolChar); - if ($short !== '' && $newlineSpan > 0) { - $error = 'Extra newline(s) found before variable comment short description'; - $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort'); - } - - $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); - - // Exactly one blank line between short and long description. - $long = $comment->getLongComment(); - if (empty($long) === false) { - $between = $comment->getWhiteSpaceBetween(); - $newlineBetween = substr_count($between, $phpcsFile->eolChar); - if ($newlineBetween !== 2) { - $error = 'There must be exactly one blank line between descriptions in variable comment'; - $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween'); - } - - $newlineCount += $newlineBetween; - - $testLong = trim($long); - if (preg_match('|\p{Lu}|u', $testLong[0]) === 0) { - $error = 'Variable comment long description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital'); - } - }//end if - - // Short description must be single line and end with a full stop. - $testShort = trim($short); - $lastChar = $testShort[(strlen($testShort) - 1)]; - if (substr_count($testShort, $phpcsFile->eolChar) !== 0) { - $error = 'Variable comment short description must be on a single line'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine'); - } - - if (preg_match('|\p{Lu}|u', $testShort[0]) === 0) { - $error = 'Variable comment short description must start with a capital letter'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital'); - } - - if ($lastChar !== '.') { - $error = 'Variable comment short description must end with a full stop'; - $phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop'); - } - }//end if - - // Exactly one blank line before tags. - $tags = $this->commentParser->getTagOrders(); - if (count($tags) > 1) { - $newlineSpan = $comment->getNewlineAfter(); - if ($newlineSpan !== 2) { - $error = 'There must be exactly one blank line before the tags in variable comment'; - if ($long !== '') { - $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); - } - - $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags'); - $short = rtrim($short, $phpcsFile->eolChar.' '); - } - } - - // Check for unknown/deprecated tags. - $unknownTags = $this->commentParser->getUnknown(); - foreach ($unknownTags as $errorTag) { - // Unknown tags are not parsed, do not process further. - $error = '@%s tag is not allowed in variable comment'; - $data = array($errorTag['tag']); - $phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data); - } - - // Check each tag. - $this->processVar($commentStart, $commentEnd); - $this->processSees($commentStart); - - // The last content should be a newline and the content before - // that should not be blank. If there is more blank space - // then they have additional blank lines at the end of the comment. - $words = $this->commentParser->getWords(); - $lastPos = (count($words) - 1); - if (trim($words[($lastPos - 1)]) !== '' - || strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false - || trim($words[($lastPos - 2)]) === '' - ) { - $error = 'Additional blank lines found at end of variable comment'; - $this->currentFile->addError($error, $commentEnd, 'SpacingAfter'); - } - - }//end processMemberVar() - - - /** - * Process the var tag. - * - * @param int $commentStart The position in the stack where the comment started. - * @param int $commentEnd The position in the stack where the comment ended. - * - * @return void - */ - protected function processVar($commentStart, $commentEnd) - { - $var = $this->commentParser->getVar(); - - if ($var !== null) { - $errorPos = ($commentStart + $var->getLine()); - $index = array_keys($this->commentParser->getTagOrders(), 'var'); - - if (count($index) > 1) { - $error = 'Only 1 @var tag is allowed in variable comment'; - $this->currentFile->addError($error, $errorPos, 'DuplicateVar'); - return; - } - - if ($index[0] !== 1) { - $error = 'The @var tag must be the first tag in a variable comment'; - $this->currentFile->addError($error, $errorPos, 'VarOrder'); - } - - $content = $var->getContent(); - if (empty($content) === true) { - $error = 'Var type missing for @var tag in variable comment'; - $this->currentFile->addError($error, $errorPos, 'MissingVarType'); - return; - } else { - $suggestedType = PHP_CodeSniffer::suggestType($content); - if ($content !== $suggestedType) { - $error = 'Expected "%s"; found "%s" for @var tag in variable comment'; - $data = array( - $suggestedType, - $content, - ); - $this->currentFile->addError($error, $errorPos, 'IncorrectVarType', $data); - } - } - - $spacing = substr_count($var->getWhitespaceBeforeContent(), ' '); - if ($spacing !== 1) { - $error = '@var tag indented incorrectly; expected 1 space but found %s'; - $data = array($spacing); - $this->currentFile->addError($error, $errorPos, 'VarIndent', $data); - } - } else { - $error = 'Missing @var tag in variable comment'; - $this->currentFile->addError($error, $commentEnd, 'MissingVar'); - }//end if - - }//end processVar() - - - /** - * Process the see tags. - * - * @param int $commentStart The position in the stack where the comment started. - * - * @return void - */ - protected function processSees($commentStart) - { - $sees = $this->commentParser->getSees(); - if (empty($sees) === false) { - foreach ($sees as $see) { - $errorPos = ($commentStart + $see->getLine()); - $content = $see->getContent(); - if (empty($content) === true) { - $error = 'Content missing for @see tag in variable comment'; - $this->currentFile->addError($error, $errorPos, 'EmptySees'); - continue; - } - - $spacing = substr_count($see->getWhitespaceBeforeContent(), ' '); - if ($spacing !== 1) { - $error = '@see tag indented incorrectly; expected 1 spaces but found %s'; - $data = array($spacing); - $this->currentFile->addError($error, $errorPos, 'SeesIndent', $data); - } - } - } - - }//end processSees() - - - /** - * Called to process a normal variable. - * - * Not required for this sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found. - * @param int $stackPtr The position where the double quoted - * string was found. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - - }//end processVariable() - - - /** - * Called to process variables found in double quoted strings. - * - * Not required for this sniff. - * - * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found. - * @param int $stackPtr The position where the double quoted - * string was found. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - - }//end processVariableInString() - - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php deleted file mode 100644 index 68b7b4a88..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); -} - -/** - * Verifies that control statements conform to their coding standards. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns the patterns that this test wishes to verify. - * - * @return array(string) - */ - protected function getPatterns() - { - return array( - 'try {EOL...} catch (...) {EOL', - 'do {EOL...} while (...);EOL', - 'while (...) {EOL', - 'for (...) {EOL', - 'if (...) {EOL', - 'foreach (...) {EOL', - '} else if (...) {EOL', - '} elseif (...) {EOL', - '} else {EOL', - ); - - }//end getPatterns() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php deleted file mode 100644 index ab61b5c34..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff. - * - * Verifies that there are not elseif statements. The else and the if should - * be separated by a space. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_ELSEIF); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $error = 'Usage of ELSEIF not allowed; use ELSE IF instead'; - $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php deleted file mode 100644 index 02cb16447..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php +++ /dev/null @@ -1,144 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff. - * - * Verifies that there is a space between each condition of foreach loops. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FOREACH); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); - $closingBracket = $tokens[$openingBracket]['parenthesis_closer']; - - if ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { - $error = 'Space found after opening bracket of FOREACH loop'; - $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpen'); - } - - if ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { - $error = 'Space found before closing bracket of FOREACH loop'; - $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeClose'); - } - - $asToken = $phpcsFile->findNext(T_AS, $openingBracket); - $content = $tokens[$asToken]['content']; - if ($content !== strtolower($content)) { - $expected = strtolower($content); - $error = 'AS keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - $expected, - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'AsNotLower', $data); - } - - $doubleArrow = $phpcsFile->findNext(T_DOUBLE_ARROW, $openingBracket, $closingBracket); - - if ($doubleArrow !== false) { - if ($tokens[($doubleArrow - 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before "=>"; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeArrow'); - } else { - if (strlen($tokens[($doubleArrow - 1)]['content']) !== 1) { - $spaces = strlen($tokens[($doubleArrow - 1)]['content']); - $error = 'Expected 1 space before "=>"; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeArrow', $data); - } - - } - - if ($tokens[($doubleArrow + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after "=>"; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterArrow'); - } else { - if (strlen($tokens[($doubleArrow + 1)]['content']) !== 1) { - $spaces = strlen($tokens[($doubleArrow + 1)]['content']); - $error = 'Expected 1 space after "=>"; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterArrow', $data); - } - - } - - }//end if - - if ($tokens[($asToken - 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before "as"; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeAs'); - } else { - if (strlen($tokens[($asToken - 1)]['content']) !== 1) { - $spaces = strlen($tokens[($asToken - 1)]['content']); - $error = 'Expected 1 space before "as"; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeAs', $data); - } - } - - if ($tokens[($asToken + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after "as"; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterAs'); - } else { - if (strlen($tokens[($asToken + 1)]['content']) !== 1) { - $spaces = strlen($tokens[($asToken + 1)]['content']); - $error = 'Expected 1 space after "as"; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterAs', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php deleted file mode 100644 index 1bfff2b50..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php +++ /dev/null @@ -1,143 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff. - * - * Verifies that there is a space between each condition of for loops. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); - if ($openingBracket === false) { - $error = 'Possible parse error: no opening parenthesis for FOR keyword'; - $phpcsFile->addWarning($error, $stackPtr, 'NoOpenBracket'); - return; - } - - $closingBracket = $tokens[$openingBracket]['parenthesis_closer']; - - if ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { - $error = 'Space found after opening bracket of FOR loop'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen'); - } - - if ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { - $error = 'Space found before closing bracket of FOR loop'; - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose'); - } - - $firstSemicolon = $phpcsFile->findNext(T_SEMICOLON, $openingBracket, $closingBracket); - - // Check whitespace around each of the tokens. - if ($firstSemicolon !== false) { - if ($tokens[($firstSemicolon - 1)]['code'] === T_WHITESPACE) { - $error = 'Space found before first semicolon of FOR loop'; - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeFirst'); - } - - if ($tokens[($firstSemicolon + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after first semicolon of FOR loop; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterFirst'); - } else { - if (strlen($tokens[($firstSemicolon + 1)]['content']) !== 1) { - $spaces = strlen($tokens[($firstSemicolon + 1)]['content']); - $error = 'Expected 1 space after first semicolon of FOR loop; %s found'; - $data = array($spaces); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterFirst', $data); - } - } - - $secondSemicolon = $phpcsFile->findNext(T_SEMICOLON, ($firstSemicolon + 1)); - - if ($secondSemicolon !== false) { - if ($tokens[($secondSemicolon - 1)]['code'] === T_WHITESPACE) { - $error = 'Space found before second semicolon of FOR loop'; - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeSecond'); - } - - if (($secondSemicolon + 1) !== $closingBracket - && $tokens[($secondSemicolon + 1)]['code'] !== T_WHITESPACE - ) { - $error = 'Expected 1 space after second semicolon of FOR loop; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterSecond'); - } else { - if (strlen($tokens[($secondSemicolon + 1)]['content']) !== 1) { - $spaces = strlen($tokens[($secondSemicolon + 1)]['content']); - $data = array($spaces); - if (($secondSemicolon + 2) === $closingBracket) { - $error = 'Expected no space after second semicolon of FOR loop; %s found'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterSecondNoThird', $data); - } else { - $error = 'Expected 1 space after second semicolon of FOR loop; %s found'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterSecond', $data); - } - } - } - }//end if - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php deleted file mode 100644 index 0bde7ac2d..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php +++ /dev/null @@ -1,136 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff. - * - * Tests the spacing of shorthand IF statements. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_INLINE_THEN); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Find the opening bracket of the inline IF. - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($tokens[$i]['parenthesis_opener']) === true - && $tokens[$i]['parenthesis_opener'] < $i - ) { - $i = $tokens[$i]['parenthesis_opener']; - continue; - } - - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { - break; - } - } - - if ($i <= 0) { - // Could not find the beginning of the statement. Probably not - // wrapped with brackets, so assume it ends with a semicolon. - $statementEnd = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - } else { - $statementEnd = $tokens[$i]['parenthesis_closer']; - } - - // Make sure it's all on the same line. - if ($tokens[$statementEnd]['line'] !== $tokens[$stackPtr]['line']) { - $error = 'Inline shorthand IF statement must be declared on a single line'; - $phpcsFile->addError($error, $stackPtr, 'NotSingleLine'); - return; - } - - // Make sure there are spaces around the question mark. - $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$contentBefore]['code'] !== T_CLOSE_PARENTHESIS) { - $error = 'Inline shorthand IF statement requires brackets around comparison'; - $phpcsFile->addError($error, $stackPtr, 'NoBrackets'); - return; - } - - $spaceBefore = ($tokens[$stackPtr]['column'] - ($tokens[$contentBefore]['column'] + strlen($tokens[$contentBefore]['content']))); - if ($spaceBefore !== 1) { - $error = 'Inline shorthand IF statement requires 1 space before THEN; %s found'; - $data = array($spaceBefore); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeThen', $data); - } - - $spaceAfter = (($tokens[$contentAfter]['column']) - ($tokens[$stackPtr]['column'] + 1)); - if ($spaceAfter !== 1) { - $error = 'Inline shorthand IF statement requires 1 space after THEN; %s found'; - $data = array($spaceAfter); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterThen', $data); - } - - // Make sure the ELSE has the correct spacing. - $inlineElse = $phpcsFile->findNext(T_INLINE_ELSE, ($stackPtr + 1), $statementEnd, false); - $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($inlineElse - 1), null, true); - $contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($inlineElse + 1), null, true); - - $spaceBefore = ($tokens[$inlineElse]['column'] - ($tokens[$contentBefore]['column'] + strlen($tokens[$contentBefore]['content']))); - if ($spaceBefore !== 1) { - $error = 'Inline shorthand IF statement requires 1 space before ELSE; %s found'; - $data = array($spaceBefore); - $phpcsFile->addError($error, $inlineElse, 'SpacingBeforeElse', $data); - } - - $spaceAfter = (($tokens[$contentAfter]['column']) - ($tokens[$inlineElse]['column'] + 1)); - if ($spaceAfter !== 1) { - $error = 'Inline shorthand IF statement requires 1 space after ELSE; %s found'; - $data = array($spaceAfter); - $phpcsFile->addError($error, $inlineElse, 'SpacingAfterElse', $data); - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php deleted file mode 100644 index 0e8eec8e4..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff. - * - * Ensures all control structure keywords are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_ELSE, - T_ELSEIF, - T_FOREACH, - T_FOR, - T_DO, - T_SWITCH, - T_WHILE, - T_TRY, - T_CATCH, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - if ($content !== strtolower($content)) { - $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtoupper($content), - strtolower($content), - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php deleted file mode 100644 index b27aa530e..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php +++ /dev/null @@ -1,270 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff. - * - * Ensures all the breaks and cases are aligned correctly according to their - * parent switch's alignment and enforces other switch formatting. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * The number of spaces code should be indented. - * - * @var int - */ - public $indent = 4; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_SWITCH); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We can't process SWITCH statements unless we know where they start and end. - if (isset($tokens[$stackPtr]['scope_opener']) === false - || isset($tokens[$stackPtr]['scope_closer']) === false - ) { - return; - } - - $switch = $tokens[$stackPtr]; - $nextCase = $stackPtr; - $caseAlignment = ($switch['column'] + $this->indent); - $caseCount = 0; - $foundDefault = false; - - while (($nextCase = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), ($nextCase + 1), $switch['scope_closer'])) !== false) { - // Skip nested SWITCH statements; they are handled on their own. - if ($tokens[$nextCase]['code'] === T_SWITCH) { - $nextCase = $tokens[$nextCase]['scope_closer']; - continue; - } - - if ($tokens[$nextCase]['code'] === T_DEFAULT) { - $type = 'Default'; - $foundDefault = true; - } else { - $type = 'Case'; - $caseCount++; - } - - if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) { - $expected = strtolower($tokens[$nextCase]['content']); - $error = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - $expected, - $tokens[$nextCase]['content'], - ); - $phpcsFile->addError($error, $nextCase, $type.'NotLower', $data); - } - - if ($tokens[$nextCase]['column'] !== $caseAlignment) { - $error = strtoupper($type).' keyword must be indented '.$this->indent.' spaces from SWITCH keyword'; - $phpcsFile->addError($error, $nextCase, $type.'Indent'); - } - - if ($type === 'Case' - && ($tokens[($nextCase + 1)]['type'] !== 'T_WHITESPACE' - || $tokens[($nextCase + 1)]['content'] !== ' ') - ) { - $error = 'CASE keyword must be followed by a single space'; - $phpcsFile->addError($error, $nextCase, 'SpacingAfterCase'); - } - - $opener = $tokens[$nextCase]['scope_opener']; - if ($tokens[($opener - 1)]['type'] === 'T_WHITESPACE') { - $error = 'There must be no space before the colon in a '.strtoupper($type).' statement'; - $phpcsFile->addError($error, $nextCase, 'SpaceBeforeColon'.$type); - } - - $nextBreak = $tokens[$nextCase]['scope_closer']; - if ($tokens[$nextBreak]['code'] === T_BREAK - || $tokens[$nextBreak]['code'] === T_RETURN - || $tokens[$nextBreak]['code'] === T_CONTINUE - || $tokens[$nextBreak]['code'] === T_THROW - ) { - if ($tokens[$nextBreak]['scope_condition'] === $nextCase) { - // Only need to check a couple of things once, even if the - // break is shared between multiple case statements, or even - // the default case. - if ($tokens[$nextBreak]['column'] !== $caseAlignment) { - $error = 'Case breaking statement must be indented '.$this->indent.' spaces from SWITCH keyword'; - $phpcsFile->addError($error, $nextBreak, 'BreakIndent'); - } - - $breakLine = $tokens[$nextBreak]['line']; - $prevLine = 0; - for ($i = ($nextBreak - 1); $i > $stackPtr; $i--) { - if ($tokens[$i]['type'] !== 'T_WHITESPACE') { - $prevLine = $tokens[$i]['line']; - break; - } - } - - if ($prevLine !== ($breakLine - 1)) { - $error = 'Blank lines are not allowed before case breaking statements'; - $phpcsFile->addError($error, $nextBreak, 'SpacingBeforeBreak'); - } - - $breakLine = $tokens[$nextBreak]['line']; - $nextLine = $tokens[$tokens[$stackPtr]['scope_closer']]['line']; - $semicolon = $phpcsFile->findNext(T_SEMICOLON, $nextBreak); - for ($i = ($semicolon + 1); $i < $tokens[$stackPtr]['scope_closer']; $i++) { - if ($tokens[$i]['type'] !== 'T_WHITESPACE') { - $nextLine = $tokens[$i]['line']; - break; - } - } - - if ($type === 'Case') { - // Ensure the BREAK statement is followed by - // a single blank line, or the end switch brace. - if ($nextLine !== ($breakLine + 2) && $i !== $tokens[$stackPtr]['scope_closer']) { - $error = 'Case breaking statements must be followed by a single blank line'; - $phpcsFile->addError($error, $nextBreak, 'SpacingAfterBreak'); - } - } else { - // Ensure the BREAK statement is not followed by a blank line. - if ($nextLine !== ($breakLine + 1)) { - $error = 'Blank lines are not allowed after the DEFAULT case\'s breaking statement'; - $phpcsFile->addError($error, $nextBreak, 'SpacingAfterDefaultBreak'); - } - } - - $caseLine = $tokens[$nextCase]['line']; - $nextLine = $tokens[$nextBreak]['line']; - for ($i = ($opener + 1); $i < $nextBreak; $i++) { - if ($tokens[$i]['type'] !== 'T_WHITESPACE') { - $nextLine = $tokens[$i]['line']; - break; - } - } - - if ($nextLine !== ($caseLine + 1)) { - $error = 'Blank lines are not allowed after '.strtoupper($type).' statements'; - $phpcsFile->addError($error, $nextCase, 'SpacingAfter'.$type); - } - }//end if - - if ($tokens[$nextBreak]['code'] === T_BREAK) { - if ($type === 'Case') { - // Ensure empty CASE statements are not allowed. - // They must have some code content in them. A comment is not enough. - // But count RETURN statements as valid content if they also - // happen to close the CASE statement. - $foundContent = false; - for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) { - if ($tokens[$i]['code'] === T_CASE) { - $i = $tokens[$i]['scope_opener']; - continue; - } - - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $foundContent = true; - break; - } - } - - if ($foundContent === false) { - $error = 'Empty CASE statements are not allowed'; - $phpcsFile->addError($error, $nextCase, 'EmptyCase'); - } - } else { - // Ensure empty DEFAULT statements are not allowed. - // They must (at least) have a comment describing why - // the default case is being ignored. - $foundContent = false; - for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) { - if ($tokens[$i]['type'] !== 'T_WHITESPACE') { - $foundContent = true; - break; - } - } - - if ($foundContent === false) { - $error = 'Comment required for empty DEFAULT case'; - $phpcsFile->addError($error, $nextCase, 'EmptyDefault'); - } - }//end if - }//end if - } else if ($type === 'Default') { - $error = 'DEFAULT case must have a breaking statement'; - $phpcsFile->addError($error, $nextCase, 'DefaultNoBreak'); - }//end if - }//end while - - if ($foundDefault === false) { - $error = 'All SWITCH statements must contain a DEFAULT case'; - $phpcsFile->addError($error, $stackPtr, 'MissingDefault'); - } - - if ($tokens[$switch['scope_closer']]['column'] !== $switch['column']) { - $error = 'Closing brace of SWITCH statement must be aligned with SWITCH keyword'; - $phpcsFile->addError($error, $switch['scope_closer'], 'CloseBraceAlign'); - } - - if ($caseCount === 0) { - $error = 'SWITCH statements must contain at least one CASE statement'; - $phpcsFile->addError($error, $stackPtr, 'MissingCase'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php deleted file mode 100644 index 272b77ba5..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Debug_JSLintSniff. - * - * Runs jslint.js on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Debug_JSLintSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - * @throws PHP_CodeSniffer_Exception If jslint.js could not be run - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - - $rhinoPath = PHP_CodeSniffer::getConfigData('rhino_path'); - $jslintPath = PHP_CodeSniffer::getConfigData('jslint_path'); - if ($rhinoPath === null || $jslintPath === null) { - return; - } - - $cmd = "$rhinoPath \"$jslintPath\" \"$fileName\""; - $msg = exec($cmd, $output, $retval); - - if (is_array($output) === true) { - $tokens = $phpcsFile->getTokens(); - - foreach ($output as $finding) { - $matches = array(); - $numMatches = preg_match('/Lint at line ([0-9]+).*:(.*)$/', $finding, $matches); - if ($numMatches === 0) { - continue; - } - - $line = (int) $matches[1]; - $message = 'jslint says: '.trim($matches[2]); - - // Find the token at the start of the line. - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] === $line) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $phpcsFile->addWarning($message, $lineToken, 'ExternalTool'); - } - }//end foreach - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php deleted file mode 100644 index ab63962b7..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php +++ /dev/null @@ -1,110 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Debug_JavaScriptLintSniff. - * - * Runs JavaScript Lint on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Debug_JavaScriptLintSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $fileName = $phpcsFile->getFilename(); - - $jslPath = PHP_CodeSniffer::getConfigData('jsl_path'); - if (is_null($jslPath) === true) { - return; - } - - $cmd = '"'.$jslPath.'" -nologo -nofilelisting -nocontext -nosummary -output-format __LINE__:__ERROR__ -process "'.$fileName.'"'; - $msg = exec($cmd, $output, $retval); - - // $exitCode is the last line of $output if no error occurs, on error it - // is numeric. Try to handle various error conditions and provide useful - // error reporting. - if ($retval === 2 || $retval === 4) { - if (is_array($output) === true) { - $msg = join('\n', $output); - } - - throw new PHP_CodeSniffer_Exception("Failed invoking JavaScript Lint, retval was [$retval], output was [$msg]"); - } - - - if (is_array($output) === true) { - $tokens = $phpcsFile->getTokens(); - - foreach ($output as $finding) { - $split = strpos($finding, ':'); - $line = substr($finding, 0, $split); - $message = substr($finding, ($split + 1)); - - // Find the token at the start of the line. - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] == $line) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $phpcsFile->addWarning(trim($message), $ptr, 'ExternalTool'); - } - }//end foreach - }//end if - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php deleted file mode 100644 index 643487365..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php +++ /dev/null @@ -1,89 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Files_FileExtensionSniff. - * - * Tests that the stars in a doc comment align correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Files_FileExtensionSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is the first PHP open tag so we don't process - // the same file twice. - $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($prevOpenTag !== false) { - return; - } - - $fileName = $phpcsFile->getFileName(); - $extension = substr($fileName, strrpos($fileName, '.')); - $nextClass = $phpcsFile->findNext(array(T_CLASS, T_INTERFACE, T_TRAIT), $stackPtr); - - if ($extension === '.php') { - if ($nextClass !== false) { - $error = '%s found in ".php" file; use ".inc" extension instead'; - $data = array(ucfirst($tokens[$nextClass]['content'])); - $phpcsFile->addError($error, $stackPtr, 'ClassFound', $data); - } - } else if ($extension === '.inc') { - if ($nextClass === false) { - $error = 'No interface or class found in ".inc" file; use ".php" extension instead'; - $phpcsFile->addError($error, $stackPtr, 'NoClass'); - } - } - - }//end process() - - -}//end class - - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php deleted file mode 100644 index 1cf288f5d..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php +++ /dev/null @@ -1,254 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Formatting_OperationBracketSniff. - * - * Tests that all arithmetic operations are bracketed. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Formatting_OperatorBracketSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$operators; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($phpcsFile->tokenizerType === 'JS' && $tokens[$stackPtr]['code'] === T_PLUS) { - // JavaScript uses the plus operator for string concatenation as well - // so we cannot accurately determine if it is a string concat or addition. - // So just ignore it. - return; - } - - // If the & is a reference, then we don't want to check for brackets. - if ($tokens[$stackPtr]['code'] === T_BITWISE_AND && $phpcsFile->isReference($stackPtr) === true) { - return; - } - - // There is one instance where brackets aren't needed, which involves - // the minus sign being used to assign a negative number to a variable. - if ($tokens[$stackPtr]['code'] === T_MINUS) { - // Check to see if we are trying to return -n. - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_RETURN) { - return; - } - - $number = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$number]['code'] === T_LNUMBER || $tokens[$number]['code'] === T_DNUMBER) { - $previous = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($previous !== false) { - $isAssignment = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens); - $isEquality = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$equalityTokens); - $isComparison = in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens); - if ($isAssignment === true || $isEquality === true || $isComparison === true) { - // This is a negative assignment or comparison. - // We need to check that the minus and the number are - // adjacent. - if (($number - $stackPtr) !== 1) { - $error = 'No space allowed between minus sign and number'; - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterMinus'); - } - - return; - } - } - } - }//end if - - $lastBracket = false; - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $parenthesis = array_reverse($tokens[$stackPtr]['nested_parenthesis'], true); - foreach ($parenthesis as $bracket => $endBracket) { - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($bracket - 1), null, true); - $prevCode = $tokens[$prevToken]['code']; - - if ($prevCode === T_ISSET) { - // This operation is inside an isset() call, but has - // no bracket of it's own. - break; - } - - if ($prevCode === T_STRING || $prevCode === T_SWITCH) { - // We allow very simple operations to not be bracketed. - // For example, ceil($one / $two). - $allowed = array( - T_VARIABLE, - T_LNUMBER, - T_DNUMBER, - T_STRING, - T_WHITESPACE, - T_THIS, - T_OBJECT_OPERATOR, - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - T_MODULUS, - ); - - for ($prev = ($stackPtr - 1); $prev > $bracket; $prev--) { - if (in_array($tokens[$prev]['code'], $allowed) === true) { - continue; - } - - if ($tokens[$prev]['code'] === T_CLOSE_PARENTHESIS) { - $prev = $tokens[$prev]['parenthesis_opener']; - } else { - break; - } - } - - if ($prev !== $bracket) { - break; - } - - for ($next = ($stackPtr + 1); $next < $endBracket; $next++) { - if (in_array($tokens[$next]['code'], $allowed) === true) { - continue; - } - - if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { - $next = $tokens[$next]['parenthesis_closer']; - } else { - break; - } - } - - if ($next !== $endBracket) { - break; - } - }//end if - - if (in_array($prevCode, PHP_CodeSniffer_Tokens::$scopeOpeners) === true) { - // This operation is inside a control structure like FOREACH - // or IF, but has no bracket of it's own. - // The only control structure allowed to do this is SWITCH. - if ($prevCode !== T_SWITCH) { - break; - } - } - - if ($prevCode === T_OPEN_PARENTHESIS) { - // These are two open parenthesis in a row. If the current - // one doesn't enclose the operator, go to the previous one. - if ($endBracket < $stackPtr) { - continue; - } - } - - $lastBracket = $bracket; - break; - }//end foreach - }//end if - - if ($lastBracket === false) { - // It is not in a bracketed statement at all. - $previousToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true, null, true); - if ($previousToken !== false) { - // A list of tokens that indicate that the token is not - // part of an arithmetic operation. - $invalidTokens = array( - T_COMMA, - T_COLON, - T_OPEN_PARENTHESIS, - T_OPEN_SQUARE_BRACKET, - T_CASE, - ); - - if (in_array($tokens[$previousToken]['code'], $invalidTokens) === false) { - $error = 'Arithmetic operation must be bracketed'; - $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); - } - - return; - } - } else if ($tokens[$lastBracket]['parenthesis_closer'] < $stackPtr) { - // There are a set of brackets in front of it that don't include it. - $error = 'Arithmetic operation must be bracketed'; - $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); - return; - } else { - // We are enclosed in a set of bracket, so the last thing to - // check is that we are not also enclosed in square brackets - // like this: ($array[$index + 1]), which is invalid. - $brackets = array( - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - ); - - $squareBracket = $phpcsFile->findPrevious($brackets, ($stackPtr - 1), $lastBracket); - if ($squareBracket !== false && $tokens[$squareBracket]['code'] === T_OPEN_SQUARE_BRACKET) { - $closeSquareBracket = $phpcsFile->findNext($brackets, ($stackPtr + 1)); - if ($closeSquareBracket !== false && $tokens[$closeSquareBracket]['code'] === T_CLOSE_SQUARE_BRACKET) { - $error = 'Arithmetic operation must be bracketed'; - $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); - } - } - - return; - }//end if - - $lastAssignment = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$assignmentTokens, $stackPtr, null, false, null, true); - if ($lastAssignment !== false && $lastAssignment > $lastBracket) { - $error = 'Arithmetic operation must be bracketed'; - $phpcsFile->addError($error, $stackPtr, 'MissingBrackets'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php deleted file mode 100644 index c1bd69689..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php +++ /dev/null @@ -1,300 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff. - * - * Checks that arguments in function declarations are spaced correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * How many spaces should surround the equals signs. - * - * @var int - */ - public $equalsSpacing = 0; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_FUNCTION, - T_CLOSURE, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $this->equalsSpacing = (int) $this->equalsSpacing; - - $tokens = $phpcsFile->getTokens(); - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $this->processBracket($phpcsFile, $openBracket); - - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $use = $phpcsFile->findNext(T_USE, ($tokens[$openBracket]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']); - if ($use !== false) { - $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null); - $this->processBracket($phpcsFile, $openBracket); - } - } - - }//end process() - - - /** - * Processes the contents of a single set of brackets. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $openBracket The position of the open bracket - * in the stack passed in $tokens. - * - * @return void - */ - public function processBracket(PHP_CodeSniffer_File $phpcsFile, $openBracket) - { - $tokens = $phpcsFile->getTokens(); - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - $multiLine = ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']); - - $nextParam = $openBracket; - $params = array(); - while (($nextParam = $phpcsFile->findNext(T_VARIABLE, ($nextParam + 1), $closeBracket)) !== false) { - - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextParam + 1), ($closeBracket + 1), true); - if ($nextToken === false) { - break; - } - - $nextCode = $tokens[$nextToken]['code']; - - if ($nextCode === T_EQUAL) { - // Check parameter default spacing. - $spacesBefore = 0; - if (($nextToken - $nextParam) > 1) { - $spacesBefore = strlen($tokens[($nextParam + 1)]['content']); - } - - if ($spacesBefore !== $this->equalsSpacing) { - $error = 'Incorrect spacing between argument "%s" and equals sign; expected '.$this->equalsSpacing.' but found %s'; - $data = array( - $tokens[$nextParam]['content'], - $spacesBefore, - ); - $phpcsFile->addError($error, $nextToken, 'SpaceBeforeEquals', $data); - } - - $spacesAfter = 0; - if ($tokens[($nextToken + 1)]['code'] === T_WHITESPACE) { - $spacesAfter = strlen($tokens[($nextToken + 1)]['content']); - } - - if ($spacesAfter !== $this->equalsSpacing) { - $error = 'Incorrect spacing between default value and equals sign for argument "%s"; expected '.$this->equalsSpacing.' but found %s'; - $data = array( - $tokens[$nextParam]['content'], - $spacesAfter, - ); - $phpcsFile->addError($error, $nextToken, 'SpaceAfterDefault', $data); - } - }//end if - - // Find and check the comma (if there is one). - $nextComma = $phpcsFile->findNext(T_COMMA, ($nextParam + 1), $closeBracket); - if ($nextComma !== false) { - // Comma found. - if ($tokens[($nextComma - 1)]['code'] === T_WHITESPACE) { - $error = 'Expected 0 spaces between argument "%s" and comma; %s found'; - $data = array( - $tokens[$nextParam]['content'], - strlen($tokens[($nextComma - 1)]['content']), - ); - $phpcsFile->addError($error, $nextToken, 'SpaceBeforeComma', $data); - } - } - - // Take references into account when expecting the - // location of whitespace. - if ($phpcsFile->isReference(($nextParam - 1)) === true) { - $whitespace = ($nextParam - 2); - } else { - $whitespace = ($nextParam - 1); - } - - if (empty($params) === false) { - // This is not the first argument in the function declaration. - $arg = $tokens[$nextParam]['content']; - - if ($tokens[$whitespace]['code'] === T_WHITESPACE) { - $gap = strlen($tokens[$whitespace]['content']); - - // Before we throw an error, make sure there is no type hint. - $comma = $phpcsFile->findPrevious(T_COMMA, ($nextParam - 1)); - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($comma + 1), null, true); - if ($phpcsFile->isReference($nextToken) === true) { - $nextToken++; - } - - if ($nextToken !== $nextParam) { - // There was a type hint, so check the spacing between - // the hint and the variable as well. - $hint = $tokens[$nextToken]['content']; - - if ($gap !== 1) { - $error = 'Expected 1 space between type hint and argument "%s"; %s found'; - $data = array( - $arg, - $gap, - ); - $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint', $data); - } - - if ($multiLine === false) { - if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space between comma and type hint "%s"; 0 found'; - $data = array($hint); - $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeHint', $data); - } else { - $gap = strlen($tokens[($comma + 1)]['content']); - if ($gap !== 1) { - $error = 'Expected 1 space between comma and type hint "%s"; %s found'; - $data = array( - $hint, - $gap, - ); - $phpcsFile->addError($error, $nextToken, 'SpacingBeforeHint', $data); - } - } - } - } else if ($gap !== 1) { - // Just make sure this is not actually an indent. - if ($tokens[$whitespace]['line'] === $tokens[($whitespace - 1)]['line']) { - $error = 'Expected 1 space between comma and argument "%s"; %s found'; - $data = array( - $arg, - $gap, - ); - $phpcsFile->addError($error, $nextToken, 'SpacingBeforeArg', $data); - } - }//end if - } else { - $error = 'Expected 1 space between comma and argument "%s"; 0 found'; - $data = array($arg); - $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeArg', $data); - }//end if - } else { - // First argument in function declaration. - if ($tokens[$whitespace]['code'] === T_WHITESPACE) { - $gap = strlen($tokens[$whitespace]['content']); - $arg = $tokens[$nextParam]['content']; - - // Before we throw an error, make sure there is no type hint. - $bracket = $phpcsFile->findPrevious(T_OPEN_PARENTHESIS, ($nextParam - 1)); - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($bracket + 1), null, true); - if ($phpcsFile->isReference($nextToken) === true) { - $nextToken++; - } - - if ($nextToken !== $nextParam) { - // There was a type hint, so check the spacing between - // the hint and the variable as well. - $hint = $tokens[$nextToken]['content']; - - if ($gap !== 1) { - $error = 'Expected 1 space between type hint and argument "%s"; %s found'; - $data = array( - $arg, - $gap, - ); - $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint', $data); - } - - if ($multiLine === false - && $tokens[($bracket + 1)]['code'] === T_WHITESPACE - ) { - $error = 'Expected 0 spaces between opening bracket and type hint "%s"; %s found'; - $data = array( - $hint, - strlen($tokens[($bracket + 1)]['content']), - ); - $phpcsFile->addError($error, $nextToken, 'SpacingAfterOpenHint', $data); - } - } else if ($multiLine === false) { - $error = 'Expected 0 spaces between opening bracket and argument "%s"; %s found'; - $data = array( - $arg, - $gap, - ); - $phpcsFile->addError($error, $nextToken, 'SpacingAfterOpen', $data); - } - }//end if - }//end if - - $params[] = $nextParam; - - }//end while - - if (empty($params) === true) { - // There are no parameters for this function. - if (($closeBracket - $openBracket) !== 1) { - $error = 'Expected 0 spaces between brackets of function declaration; %s found'; - $data = array(strlen($tokens[($closeBracket - 1)]['content'])); - $phpcsFile->addError($error, $openBracket, 'SpacingBetween', $data); - } - } else if ($multiLine === false - && $tokens[($closeBracket - 1)]['code'] === T_WHITESPACE - ) { - $lastParam = array_pop($params); - $error = 'Expected 0 spaces between argument "%s" and closing bracket; %s found'; - $data = array( - $tokens[$lastParam]['content'], - strlen($tokens[($closeBracket - 1)]['content']), - ); - $phpcsFile->addError($error, $closeBracket, 'SpacingBeforeClose', $data); - } - - }//end processBracket() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php deleted file mode 100644 index ebc9879f2..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); -} - -/** - * Squiz_Sniffs_Functions_FunctionDeclarationSniff. - * - * Checks the function declaration is correct. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_FunctionDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff -{ - - - /** - * Returns an array of patterns to check are correct. - * - * @return array - */ - protected function getPatterns() - { - return array( - 'function abc(...);', - 'abstract function abc(...);', - ); - - }//end getPatterns() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php deleted file mode 100644 index fd87edc5f..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Functions_FunctionDuplicateArgumentSpacingSniff. - * - * Checks that duplicate arguments are not used in function declarations. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - - $foundVariables = array(); - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - if ($tokens[$i]['code'] === T_VARIABLE) { - $variable = $tokens[$i]['content']; - if (in_array($variable, $foundVariables) === true) { - $error = 'Variable "%s" appears more than once in function declaration'; - $data = array($variable); - $phpcsFile->addError($error, $i, 'Found', $data); - } else { - $foundVariables[] = $variable; - } - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php deleted file mode 100644 index d13c8b546..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Functions_GlobalFunctionSniff. - * - * Tests for functions outside of classes. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_GlobalFunctionSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (empty($tokens[$stackPtr]['conditions']) === true) { - $functionName = $phpcsFile->getDeclarationName($stackPtr); - if ($functionName === null) { - return; - } - - // Special exception for __autoload as it needs to be global. - if ($functionName !== '__autoload') { - $error = 'Consider putting global function "%s" in a static class'; - $data = array($functionName); - $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php deleted file mode 100644 index c37e244c0..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff. - * - * Ensures all class keywords are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_FUNCTION, - T_PUBLIC, - T_PRIVATE, - T_PROTECTED, - T_STATIC, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - if ($content !== strtolower($content)) { - $error = '%s keyword must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtoupper($content), - strtolower($content), - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'FoundUppercase', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php deleted file mode 100644 index d5137f1a7..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php +++ /dev/null @@ -1,140 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PEAR_Sniffs_Functions_FunctionDeclarationSniff', true) === false) { - $error = 'Class PEAR_Sniffs_Functions_FunctionDeclarationSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff. - * - * Ensure single and multi-line function declarations are defined correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff extends PEAR_Sniffs_Functions_FunctionDeclarationSniff -{ - - - /** - * Processes multi-line declarations. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * - * @return void - */ - public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) - { - // We do everything the parent sniff does, and a bit more. - parent::processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens); - - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $this->processBracket($phpcsFile, $openBracket, $tokens, 'function'); - - if ($tokens[$stackPtr]['code'] !== T_CLOSURE) { - return; - } - - $use = $phpcsFile->findNext(T_USE, ($tokens[$stackPtr]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']); - if ($use === false) { - return; - } - - $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null); - $this->processBracket($phpcsFile, $openBracket, $tokens, 'use'); - - // Also check spacing. - if ($tokens[($use - 1)]['code'] === T_WHITESPACE) { - $gap = strlen($tokens[($use - 1)]['content']); - } else { - $gap = 0; - } - - }//end processMultiLineDeclaration() - - - /** - * Processes the contents of a single set of brackets. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $openBracket The position of the open bracket - * in the stack passed in $tokens. - * @param array $tokens The stack of tokens that make up - * the file. - * @param string $type The type of the token the brackets - * belong to (function or use). - * - * @return void - */ - public function processBracket(PHP_CodeSniffer_File $phpcsFile, $openBracket, $tokens, $type='function') - { - $errorPrefix = ''; - if ($type === 'use') { - $errorPrefix = 'Use'; - } - - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - - // The open bracket should be the last thing on the line. - if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); - if ($tokens[$next]['line'] !== ($tokens[$openBracket]['line'] + 1)) { - $error = 'The first parameter of a multi-line '.$type.' declaration must be on the line after the opening bracket'; - $phpcsFile->addError($error, $next, $errorPrefix.'FirstParamSpacing'); - } - } - - // Each line between the brackets should contain a single parameter. - $lastCommaLine = null; - for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { - // Skip brackets, like arrays, as they can contain commas. - if (isset($tokens[$i]['parenthesis_opener']) === true) { - $i = $tokens[$i]['parenthesis_closer']; - continue; - } - - if ($tokens[$i]['code'] === T_COMMA) { - if ($lastCommaLine !== null && $lastCommaLine === $tokens[$i]['line']) { - $error = 'Multi-line '.$type.' declarations must define one parameter per line'; - $phpcsFile->addError($error, $i, $errorPrefix.'OneParamPerLine'); - } else { - // Comma must be the last thing on the line. - $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); - if ($tokens[$next]['line'] !== ($tokens[$i]['line'] + 1)) { - $error = 'Commas in multi-line '.$type.' declarations must be the last content on a line'; - $phpcsFile->addError($error, $next, $errorPrefix.'ContentAfterComma'); - } - } - - $lastCommaLine = $tokens[$i]['line']; - } - } - - }//end processBracket() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php deleted file mode 100644 index 664740b23..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Generic_Sniffs_PHP_LowerCaseConstantSniff', true) === false) { - $error = 'Class Generic_Sniffs_PHP_LowerCaseConstantSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -if (class_exists('Generic_Sniffs_PHP_UpperCaseConstantSniff', true) === false) { - $error = 'Class Generic_Sniffs_PHP_UpperCaseConstantSniff not found'; - throw new PHP_CodeSniffer_Exception($error); -} - -/** - * Squiz_Sniffs_NamingConventions_ConstantCaseSniff. - * - * Ensures TRUE, FALSE and NULL are uppercase for PHP and lowercase for JS. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_NamingConventions_ConstantCaseSniff extends Generic_Sniffs_PHP_LowerCaseConstantSniff -{ - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - if ($phpcsFile->tokenizerType === 'JS') { - parent::process($phpcsFile, $stackPtr); - } else { - $sniff = new Generic_Sniffs_PHP_UpperCaseConstantSniff; - $sniff->process($phpcsFile, $stackPtr); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php deleted file mode 100644 index 542bc21ad..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff not found'); -} - -/** - * Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff. - * - * Ensures method names are correct depending on whether they are public - * or private, and that functions are named correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff extends PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff -{ - - - /** - * Processes the tokens outside the scope. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being processed. - * @param int $stackPtr The position where this token was - * found. - * - * @return void - */ - protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $functionName = $phpcsFile->getDeclarationName($stackPtr); - if ($functionName === null) { - return; - } - - $errorData = array($functionName); - - // Does this function claim to be magical? - if (preg_match('|^__|', $functionName) !== 0) { - $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; - $phpcsFile->addError($error, $stackPtr, 'DoubleUnderscore', $errorData); - return; - } - - if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, false) === false) { - $error = 'Function name "%s" is not in camel caps format'; - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); - } - - }//end processTokenOutsideScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php deleted file mode 100644 index fff2089af..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ /dev/null @@ -1,241 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -/** - * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. - * - * Checks the naming of variables and member variables. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - /** - * Tokens to ignore so that we can find a DOUBLE_COLON. - * - * @var array - */ - private $_ignore = array( - T_WHITESPACE, - T_COMMENT, - ); - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $varName = ltrim($tokens[$stackPtr]['content'], '$'); - - $phpReservedVars = array( - '_SERVER', - '_GET', - '_POST', - '_REQUEST', - '_SESSION', - '_ENV', - '_COOKIE', - '_FILES', - 'GLOBALS', - ); - - // If it's a php reserved var, then its ok. - if (in_array($varName, $phpReservedVars) === true) { - return; - } - - $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); - if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { - // Check to see if we are using a variable from an object. - $var = $phpcsFile->findNext(array(T_WHITESPACE), ($objOperator + 1), null, true); - if ($tokens[$var]['code'] === T_STRING) { - $bracket = $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); - if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { - $objVarName = $tokens[$var]['content']; - - // There is no way for us to know if the var is public or - // private, so we have to ignore a leading underscore if there is - // one and just check the main part of the variable name. - $originalVarName = $objVarName; - if (substr($objVarName, 0, 1) === '_') { - $objVarName = substr($objVarName, 1); - } - - if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); - } - }//end if - }//end if - }//end if - - // There is no way for us to know if the var is public or private, - // so we have to ignore a leading underscore if there is one and just - // check the main part of the variable name. - $originalVarName = $varName; - if (substr($varName, 0, 1) === '_') { - $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); - if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { - // The variable lives within a class, and is referenced like - // this: MyClass::$_variable, so we don't know its scope. - $inClass = true; - } else { - $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)); - } - - if ($inClass === true) { - $varName = substr($varName, 1); - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); - } - - }//end processVariable() - - - /** - * Processes class member variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $varName = ltrim($tokens[$stackPtr]['content'], '$'); - $memberProps = $phpcsFile->getMemberProperties($stackPtr); - if (empty($memberProps) === true) { - // Couldn't get any info about this variable, which - // generally means it is invalid or possibly has a parse - // error. Any errors will be reported by the core, so - // we can ignore it. - return; - } - - $public = ($memberProps['scope'] !== 'private'); - $errorData = array($varName); - - if ($public === true) { - if (substr($varName, 0, 1) === '_') { - $error = '%s member variable "%s" must not contain a leading underscore'; - $data = array( - ucfirst($memberProps['scope']), - $errorData[0], - ); - $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); - return; - } - } else { - if (substr($varName, 0, 1) !== '_') { - $error = 'Private member variable "%s" must contain a leading underscore'; - $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData); - return; - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $phpcsFile->addError($error, $stackPtr, 'MemberNotCamelCaps', $errorData); - } - - }//end processMemberVar() - - - /** - * Processes the variable found within a double quoted string. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the double quoted - * string. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $phpReservedVars = array( - '_SERVER', - '_GET', - '_POST', - '_REQUEST', - '_SESSION', - '_ENV', - '_COOKIE', - '_FILES', - 'GLOBALS', - ); - if (preg_match_all('|[^\\\]\${?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { - foreach ($matches[1] as $varName) { - // If it's a php reserved var, then its ok. - if (in_array($varName, $phpReservedVars) === true) { - continue; - } - - // There is no way for us to know if the var is public or private, - // so we have to ignore a leading underscore if there is one and just - // check the main part of the variable name. - $originalVarName = $varName; - if (substr($varName, 0, 1) === '_') { - if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { - $varName = substr($varName, 1); - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { - $varName = $matches[0]; - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $stackPtr, 'StringNotCamelCaps', $data); - - } - } - }//end if - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php deleted file mode 100644 index a28f75615..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Ensures that object indexes are written in dot notation. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sertan Danis - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_SQUARE_BRACKET); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Check if the next non whitespace token is a string. - $index = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$index]['code'] !== T_CONSTANT_ENCAPSED_STRING) { - return; - } - - // Make sure it is the only thing in the square brackets. - $next = $phpcsFile->findNext(T_WHITESPACE, ($index + 1), null, true); - if ($tokens[$next]['code'] !== T_CLOSE_SQUARE_BRACKET) { - return; - } - - // Allow indexes that have dots in them because we can't write - // them in dot notation. - $content = trim($tokens[$index]['content'], '"\' '); - if (strpos($content, '.') !== false) { - return; - } - - // Also ignore reserved words. - if ($content === 'super') { - return; - } - - // Token before the opening square bracket cannot be a var name. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_STRING) { - $error = 'Object indexes must be written in dot notation'; - $phpcsFile->addError($error, $prev, 'Found'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php deleted file mode 100644 index 5f5ca55b7..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php +++ /dev/null @@ -1,83 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Objects_ObjectInstantiationSniff. - * - * Ensures objects are assigned to a variable when instantiated. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Objects_ObjectInstantiationSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Registers the token types that this sniff wishes to listen to. - * - * @return array - */ - public function register() - { - return array(T_NEW); - - }//end register() - - - /** - * Process the tokens that this sniff is listening for. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $allowedTokens = PHP_CodeSniffer_Tokens::$emptyTokens; - $allowedTokens[] = T_BITWISE_AND; - - $prev = $phpcsFile->findPrevious($allowedTokens, ($stackPtr - 1), null, true); - - $allowedTokens = array( - T_EQUAL, - T_DOUBLE_ARROW, - T_THROW, - T_RETURN, - T_INLINE_THEN, - T_INLINE_ELSE, - ); - - if (in_array($tokens[$prev]['code'], $allowedTokens) === false) { - $error = 'New objects must be assigned to a variable'; - $phpcsFile->addError($error, $stackPtr, 'NotAssigned'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php deleted file mode 100644 index e08a92079..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Objects_ObjectInstantiationSniff. - * - * Ensures objects are assigned to a variable when instantiated. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Objects_ObjectMemberCommaSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Registers the token types that this sniff wishes to listen to. - * - * @return array - */ - public function register() - { - return array(T_CLOSE_CURLY_BRACKET); - - }//end register() - - - /** - * Process the tokens that this sniff is listening for. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Only interested in orphaned braces (which are objects) - // and object definitions. - if (isset($tokens[$stackPtr]['scope_condition']) === true) { - $condition = $tokens[$stackPtr]['scope_condition']; - if ($tokens[$condition]['code'] !== T_OBJECT) { - return; - } - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_COMMA) { - $error = 'Last member of object must not be followed by a comma'; - $phpcsFile->addError($error, $prev, 'Missing'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php deleted file mode 100644 index db994b81e..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php +++ /dev/null @@ -1,210 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators. - * - * The use of === true is enforced over implicit true statements, - * for example: - * - * - * if ($a) - * { - * ... - * } - * - * - * should be: - * - * - * if ($a === true) - * { - * ... - * } - * - * - * It also enforces the use of === false over ! operators. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * A list of valid comparison operators. - * - * @var array - */ - private static $_validOps = array( - T_IS_IDENTICAL, - T_IS_NOT_IDENTICAL, - T_LESS_THAN, - T_GREATER_THAN, - T_IS_GREATER_OR_EQUAL, - T_IS_SMALLER_OR_EQUAL, - T_INSTANCEOF, - ); - - /** - * A list of invalid operators with their alternatives. - * - * @var array(int => string) - */ - private static $_invalidOps = array( - 'PHP' => array( - T_IS_EQUAL => '===', - T_IS_NOT_EQUAL => '!==', - T_BOOLEAN_NOT => '=== FALSE', - ), - 'JS' => array( - T_IS_EQUAL => '===', - T_IS_NOT_EQUAL => '!==', - ), - ); - - - /** - * Registers the token types that this sniff wishes to listen to. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_ELSEIF, - T_INLINE_THEN, - ); - - }//end register() - - - /** - * Process the tokens that this sniff is listening for. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where the token - * was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $tokenizer = $phpcsFile->tokenizerType; - - if ($tokens[$stackPtr]['code'] === T_INLINE_THEN) { - $end = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$end]['code'] !== T_CLOSE_PARENTHESIS) { - // This inline IF statement does not have its condition - // bracketed, so we need to guess where it starts. - for ($i = ($end - 1); $i >= 0; $i--) { - if ($tokens[$i]['code'] === T_SEMICOLON) { - // Stop here as we assume it is the end - // of the previous statement. - break; - } else if ($tokens[$i]['code'] === T_OPEN_TAG) { - // Stop here as this is the start of the file. - break; - } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET) { - // Stop if this is the closing brace of - // a code block. - if (isset($tokens[$i]['scope_opener']) === true) { - break; - } - } else if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) { - // Stop if this is the opening brace of - // a code block. - if (isset($tokens[$i]['scope_closer']) === true) { - break; - } - } - }//end for - - $start = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true); - } else { - $start = $tokens[$end]['parenthesis_opener']; - } - } else { - $start = $tokens[$stackPtr]['parenthesis_opener']; - $end = $tokens[$stackPtr]['parenthesis_closer']; - } - - $requiredOps = 0; - $foundOps = 0; - - for ($i = $start; $i <= $end; $i++) { - $type = $tokens[$i]['code']; - if (in_array($type, array_keys(self::$_invalidOps[$tokenizer])) === true) { - $error = 'Operator %s prohibited; use %s instead'; - $data = array( - $tokens[$i]['content'], - self::$_invalidOps[$tokenizer][$type], - ); - $phpcsFile->addError($error, $i, 'NotAllowed', $data); - $foundOps++; - } else if (in_array($type, self::$_validOps) === true) { - $foundOps++; - } - - if ($phpcsFile->tokenizerType !== 'JS') { - if ($tokens[$i]['code'] === T_BOOLEAN_AND || $tokens[$i]['code'] === T_BOOLEAN_OR) { - $requiredOps++; - - // If we get to here and we have not found the right number of - // comparison operators, then we must have had an implicit - // true operation ie. if ($a) instead of the required - // if ($a === true), so let's add an error. - if ($requiredOps !== $foundOps) { - $error = 'Implicit true comparisons prohibited; use === TRUE instead'; - $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue'); - $foundOps++; - } - } - }//end if - }//end for - - $requiredOps++; - - if ($phpcsFile->tokenizerType !== 'JS') { - if ($foundOps < $requiredOps) { - $error = 'Implicit true comparisons prohibited; use === TRUE instead'; - $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue'); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php deleted file mode 100644 index ec070d614..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Operators_IncrementDecrementUsageSniff. - * - * Tests that the ++ operators are used when possible and not - * used when it makes the code confusing. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Operators_IncrementDecrementUsageSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_EQUAL, - T_PLUS_EQUAL, - T_MINUS_EQUAL, - T_INC, - T_DEC, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] === T_INC || $tokens[$stackPtr]['code'] === T_DEC) { - $this->processIncDec($phpcsFile, $stackPtr); - } else { - $this->processAssignment($phpcsFile, $stackPtr); - } - - }//end process() - - - /** - * Checks to ensure increment and decrement operators are not confusing. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - protected function processIncDec(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Work out where the variable is so we know where to - // start looking for other operators. - if ($tokens[($stackPtr - 1)]['code'] === T_VARIABLE) { - $start = ($stackPtr + 1); - } else { - $start = ($stackPtr + 2); - } - - $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $start, null, true); - if ($next === false) { - return; - } - - if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$arithmeticTokens) === true) { - $error = 'Increment and decrement operators cannot be used in an arithmetic operation'; - $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); - return; - } - - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($start - 3), null, true); - if ($prev === false) { - return; - } - - // Check if this is in a string concat. - if ($tokens[$next]['code'] === T_STRING_CONCAT || $tokens[$prev]['code'] === T_STRING_CONCAT) { - $error = 'Increment and decrement operators must be bracketed when used in string concatenation'; - $phpcsFile->addError($error, $stackPtr, 'NoBrackets'); - } - - }//end processIncDec() - - - /** - * Checks to ensure increment and decrement operators are used. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - protected function processAssignment(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $assignedVar = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - // Not an assignment, return. - if ($tokens[$assignedVar]['code'] !== T_VARIABLE) { - return; - } - - $statementEnd = $phpcsFile->findNext(array(T_SEMICOLON, T_CLOSE_PARENTHESIS, T_CLOSE_SQUARE_BRACKET, T_CLOSE_CURLY_BRACKET), $stackPtr); - - // If there is anything other than variables, numbers, spaces or operators we need to return. - $noiseTokens = $phpcsFile->findNext(array(T_LNUMBER, T_VARIABLE, T_WHITESPACE, T_PLUS, T_MINUS, T_OPEN_PARENTHESIS), ($stackPtr + 1), $statementEnd, true); - - if ($noiseTokens !== false) { - return; - } - - // If we are already using += or -=, we need to ignore - // the statement if a variable is being used. - if ($tokens[$stackPtr]['code'] !== T_EQUAL) { - $nextVar = $phpcsFile->findNext(T_VARIABLE, ($stackPtr + 1), $statementEnd); - if ($nextVar !== false) { - return; - } - } - - if ($tokens[$stackPtr]['code'] === T_EQUAL) { - $nextVar = ($stackPtr + 1); - $previousVariable = ($stackPtr + 1); - $variableCount = 0; - while (($nextVar = $phpcsFile->findNext(T_VARIABLE, ($nextVar + 1), $statementEnd)) !== false) { - $previousVariable = $nextVar; - $variableCount++; - } - - if ($variableCount !== 1) { - return; - } - - $nextVar = $previousVariable; - if ($tokens[$nextVar]['content'] !== $tokens[$assignedVar]['content']) { - return; - } - } - - // We have only one variable, and it's the same as what is being assigned, - // so we need to check what is being added or subtracted. - $nextNumber = ($stackPtr + 1); - $previousNumber = ($stackPtr + 1); - $numberCount = 0; - while (($nextNumber = $phpcsFile->findNext(array(T_LNUMBER), ($nextNumber + 1), $statementEnd, false)) !== false) { - $previousNumber = $nextNumber; - $numberCount++; - } - - if ($numberCount !== 1) { - return; - } - - $nextNumber = $previousNumber; - if ($tokens[$nextNumber]['content'] === '1') { - if ($tokens[$stackPtr]['code'] === T_EQUAL) { - $opToken = $phpcsFile->findNext(array(T_PLUS, T_MINUS), ($nextVar + 1), $statementEnd); - if ($opToken === false) { - // Operator was before the variable, like: - // $var = 1 + $var; - // So we ignore it. - return; - } - - $operator = $tokens[$opToken]['content']; - } else { - $operator = substr($tokens[$stackPtr]['content'], 0, 1); - } - - // If we are adding or subtracting negative value, the operator - // needs to be reversed. - if ($tokens[$stackPtr]['code'] !== T_EQUAL) { - $negative = $phpcsFile->findPrevious(T_MINUS, ($nextNumber - 1), $stackPtr); - if ($negative !== false) { - $operator = ($operator === '+') ? '-' : '+'; - } - } - - $expected = $tokens[$assignedVar]['content'].$operator.$operator; - $found = $phpcsFile->getTokensAsString($assignedVar, ($statementEnd - $assignedVar + 1)); - - if ($operator === '+') { - $error = 'Increment'; - } else { - $error = 'Decrement'; - } - - $error .= " operators should be used where possible; found \"$found\" but expected \"$expected\""; - $phpcsFile->addError($error, $stackPtr); - }//end if - - }//end processAssignment() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php deleted file mode 100644 index 3374e5523..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff. - * - * Checks to ensure that the logical operators 'and' and 'or' are not used. - * Use the && and || operators instead. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_LOGICAL_AND, - T_LOGICAL_OR, - T_LOGICAL_XOR, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $replacements = array( - 'and' => '&&', - 'or' => '||', - 'xor' => '^', - ); - - $operator = strtolower($tokens[$stackPtr]['content']); - if (isset($replacements[$operator]) === false) { - return; - } - - $error = 'Logical operator "%s" is prohibited; use "%s" instead'; - $data = array( - $operator, - $replacements[$operator], - ); - $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php deleted file mode 100644 index 80de3c219..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php +++ /dev/null @@ -1,228 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_CommentedOutCodeSniff. - * - * Warn about commented out code. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_CommentedOutCodeSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'CSS', - ); - - /** - * If a comment is more than $maxPercentage% code, a warning will be shown. - * - * @var int - */ - public $maxPercentage = 35; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$commentTokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Process whole comment blocks at once, so skip all but the first token. - if ($stackPtr > 0 && $tokens[$stackPtr]['code'] === $tokens[($stackPtr - 1)]['code']) { - return; - } - - // Ignore comments at the end of code blocks. - if (substr($tokens[$stackPtr]['content'], 0, 6) === '//end ') { - return; - } - - $content = ''; - if ($phpcsFile->tokenizerType === 'PHP') { - $content = 'numTokens; $i++) { - if ($tokens[$stackPtr]['code'] !== $tokens[$i]['code']) { - break; - } - - /* - Trim as much off the comment as possible so we don't - have additional whitespace tokens or comment tokens - */ - - $tokenContent = trim($tokens[$i]['content']); - - if (substr($tokenContent, 0, 2) === '//') { - $tokenContent = substr($tokenContent, 2); - } - - if (substr($tokenContent, 0, 1) === '#') { - $tokenContent = substr($tokenContent, 1); - } - - if (substr($tokenContent, 0, 3) === '/**') { - $tokenContent = substr($tokenContent, 3); - } - - if (substr($tokenContent, 0, 2) === '/*') { - $tokenContent = substr($tokenContent, 2); - } - - if (substr($tokenContent, -2) === '*/') { - $tokenContent = substr($tokenContent, 0, -2); - } - - if (substr($tokenContent, 0, 1) === '*') { - $tokenContent = substr($tokenContent, 1); - } - - $content .= $tokenContent.$phpcsFile->eolChar; - }//end for - - $content = trim($content); - - if ($phpcsFile->tokenizerType === 'PHP') { - $content .= ' ?>'; - } - - // Quite a few comments use multiple dashes, equals signs etc - // to frame comments and licence headers. - $content = preg_replace('/[-=*]+/', '-', $content); - - // Because we are not really parsing code, the tokenizer can throw all sorts - // of errors that don't mean anything, so ignore them. - $oldErrors = ini_get('error_reporting'); - ini_set('error_reporting', 0); - $stringTokens = PHP_CodeSniffer_File::tokenizeString($content, $phpcsFile->tokenizer, $phpcsFile->eolChar); - ini_set('error_reporting', $oldErrors); - - $emptyTokens = array( - T_WHITESPACE, - T_STRING, - T_STRING_CONCAT, - T_ENCAPSED_AND_WHITESPACE, - T_NONE, - ); - - $numTokens = count($stringTokens); - - /* - We know what the first two and last two tokens should be - (because we put them there) so ignore this comment if those - tokens were not parsed correctly. It obviously means this is not - valid code. - */ - - // First token is always the opening PHP tag. - if ($stringTokens[0]['code'] !== T_OPEN_TAG) { - return; - } - - // Last token is always the closing PHP tag, unless something went wrong. - if (isset($stringTokens[($numTokens - 1)]) === false - || $stringTokens[($numTokens - 1)]['code'] !== T_CLOSE_TAG - ) { - return; - } - - // Second last token is always whitespace or a comment, depending - // on the code inside the comment. - if (in_array($stringTokens[($numTokens - 2)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - return; - } - - $numComment = 0; - $numPossible = 0; - $numCode = 0; - - for ($i = 0; $i < $numTokens; $i++) { - if (in_array($stringTokens[$i]['code'], $emptyTokens) === true) { - // Looks like comment. - $numComment++; - } else if (in_array($stringTokens[$i]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) - || in_array($stringTokens[$i]['code'], PHP_CodeSniffer_Tokens::$arithmeticTokens) - ) { - // Commented out HTML/XML and other docs contain a lot of these - // characters, so it is best to not use them directly. - $numPossible++; - } else { - // Looks like code. - $numCode++; - } - } - - // We subtract 3 from the token number so we ignore the start/end tokens - // and their surrounding whitespace. We take 2 off the number of code - // tokens so we ignore the start/end tokens. - if ($numTokens > 3) { - $numTokens -= 3; - } - - if ($numCode >= 2) { - $numCode -= 2; - } - - $percentCode = ceil((($numCode / $numTokens) * 100)); - if ($percentCode > $this->maxPercentage) { - // Just in case. - $percentCode = min(100, $percentCode); - - $error = 'This comment is %s%% valid code; is this commented out code?'; - $data = array($percentCode); - $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php deleted file mode 100644 index 381bec292..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_DisallowBooleanStatementSniff. - * - * Ensures that boolean operators are only used inside control structure conditions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowBooleanStatementSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$booleanOperators; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $foundOwner = false; - foreach ($tokens[$stackPtr]['nested_parenthesis'] as $open => $close) { - if (isset($tokens[$open]['parenthesis_owner']) === true) { - // Any owner means we are not just a simple statement. - return; - } - } - } - - $error = 'Boolean operators are not allowed outside of control structure conditions'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php deleted file mode 100644 index 25aa44586..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php +++ /dev/null @@ -1,125 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff. - * - * Ensures that the value of a comparison is not assigned to a variable. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_EQUAL); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore default value assignments in function definitions. - $function = $phpcsFile->findPrevious(T_FUNCTION, ($stackPtr - 1)); - if ($function !== false) { - $opener = $tokens[$function]['parenthesis_opener']; - $closer = $tokens[$function]['parenthesis_closer']; - if ($opener < $stackPtr && $closer > $stackPtr) { - return; - } - } - - // Ignore values in array definitions. - $array = $phpcsFile->findNext( - T_ARRAY, - ($stackPtr + 1), - null, - false, - null, - true - ); - - if ($array !== false) { - return; - } - - // Ignore function calls. - $ignore = array( - T_STRING, - T_WHITESPACE, - T_OBJECT_OPERATOR, - ); - - $next = $phpcsFile->findNext($ignore, ($stackPtr + 1), null, true); - if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS - && $tokens[($next - 1)]['code'] === T_STRING - ) { - // Code will look like: $var = myFunction( - // and will be ignored. - return; - } - - $endStatement = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1)); - if ($tokens[$stackPtr]['conditions'] !== $tokens[$endStatement]['conditions']) { - // This statement doesn't end with a semicolon, which is the case for - // the last expression in a for loop. - return; - } - - for ($i = ($stackPtr + 1); $i < $endStatement; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) === true) { - $error = 'The value of a comparison must not be assigned to a variable'; - $phpcsFile->addError($error, $stackPtr, 'AssignedComparison'); - break; - } - - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$booleanOperators) === true - || $tokens[$i]['code'] === T_BOOLEAN_NOT - ) { - $error = 'The value of a boolean operation must not be assigned to a variable'; - $phpcsFile->addError($error, $stackPtr, 'AssignedBool'); - break; - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php deleted file mode 100644 index afc1acf28..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Formatting_DisallowInlineIfSniff. - * - * Stops inline IF statements from being used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowInlineIfSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_INLINE_THEN); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $phpcsFile->addError('Inline IF statements are not allowed', $stackPtr, 'Found'); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php deleted file mode 100644 index 4873a5ed7..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff. - * - * Ensures that there is only one value assignment on a line, and that it is - * the first thing on the line. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_EQUAL); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Ignore default value assignments in function definitions. - $function = $phpcsFile->findPrevious(array(T_FUNCTION, T_CLOSURE), ($stackPtr - 1)); - if ($function !== false) { - $opener = $tokens[$function]['parenthesis_opener']; - $closer = $tokens[$function]['parenthesis_closer']; - if ($opener < $stackPtr && $closer > $stackPtr) { - return; - } - } - - /* - The general rule is: - Find an equal sign and go backwards along the line. If you hit an - end bracket, skip to the opening bracket. When you find a variable, - stop. That variable must be the first non-empty token on the line - or in the statement. If not, throw an error. - */ - - for ($varToken = ($stackPtr - 1); $varToken >= 0; $varToken--) { - // Skip brackets. - if (isset($tokens[$varToken]['parenthesis_opener']) === true && $tokens[$varToken]['parenthesis_opener'] < $varToken) { - $varToken = $tokens[$varToken]['parenthesis_opener']; - continue; - } - - if (isset($tokens[$varToken]['bracket_opener']) === true) { - $varToken = $tokens[$varToken]['bracket_opener']; - continue; - } - - if ($tokens[$varToken]['code'] === T_SEMICOLON) { - // We've reached the next statement, so we - // didn't find a variable. - return; - } - - if ($tokens[$varToken]['code'] === T_VARIABLE) { - // We found our variable. - break; - } - } - - if ($varToken <= 0) { - // Didn't find a variable. - return; - } - - // Deal with this type of variable: self::$var by setting the var - // token to be "self" rather than "$var". - if ($tokens[($varToken - 1)]['code'] === T_DOUBLE_COLON) { - $varToken = ($varToken - 2); - } - - // Deal with this type of variable: $obj->$var by setting the var - // token to be "$obj" rather than "$var". - if ($tokens[($varToken - 1)]['code'] === T_OBJECT_OPERATOR) { - $varToken = ($varToken - 2); - } - - // Deal with this type of variable: $$var by setting the var - // token to be "$" rather than "$var". - if ($tokens[($varToken - 1)]['content'] === '$') { - $varToken--; - } - - // Ignore member var definitions. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($varToken - 1), null, true); - if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$scopeModifiers) === true) { - return; - } - - if ($tokens[$prev]['code'] === T_STATIC) { - return; - } - - // Make sure this variable is the first thing in the statement. - $varLine = $tokens[$varToken]['line']; - $prevLine = 0; - for ($i = ($varToken - 1); $i >= 0; $i--) { - if ($tokens[$i]['code'] === T_SEMICOLON) { - // We reached the end of the statement. - return; - } - - if ($tokens[$i]['code'] === T_INLINE_THEN) { - // We reached the end of the inline THEN statement. - return; - } - - if ($tokens[$i]['code'] === T_INLINE_ELSE) { - // We reached the end of the inline ELSE statement. - return; - } - - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - $prevLine = $tokens[$i]['line']; - break; - } - } - - // Ignore the first part of FOR loops as we are allowed to - // assign variables there even though the variable is not the - // first thing on the line. Also ignore WHILE loops. - if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS && isset($tokens[$i]['parenthesis_owner']) === true) { - $owner = $tokens[$i]['parenthesis_owner']; - if ($tokens[$owner]['code'] === T_FOR || $tokens[$owner]['code'] === T_WHILE) { - return; - } - } - - if ($prevLine === $varLine) { - $error = 'Assignments must be the first block of code on a line'; - $phpcsFile->addError($error, $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php deleted file mode 100644 index 9350c6326..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Formatting_DisallowObEndFlushSniff. - * - * Checks the indenting used when an ob_start() call occurs. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowObEndFlushSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['content'] === 'ob_end_flush') { - $phpcsFile->addError('Use of ob_end_flush() is not allowed; use ob_get_contents() and ob_end_clean() instead', $stackPtr, 'Found'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php deleted file mode 100644 index 3aab1cee6..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php +++ /dev/null @@ -1,127 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff. - * - * Bans the use of size-based functions in loop conditions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * An array of functions we don't want in the condition of loops. - * - * @return array - */ - protected $forbiddenFunctions = array( - 'PHP' => array( - 'sizeof', - 'strlen', - 'count', - ), - 'JS' => array('length'), - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_WHILE, - T_FOR, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $tokenizer = $phpcsFile->tokenizerType; - $openBracket = $tokens[$stackPtr]['parenthesis_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - - if ($tokens[$stackPtr]['code'] === T_FOR) { - // We only want to check the condition in FOR loops. - $start = $phpcsFile->findNext(T_SEMICOLON, ($openBracket + 1)); - $end = $phpcsFile->findPrevious(T_SEMICOLON, ($closeBracket - 1)); - } else { - $start = $openBracket; - $end = $closeBracket; - } - - for ($i = ($start + 1); $i < $end; $i++) { - if ($tokens[$i]['code'] === T_STRING && in_array($tokens[$i]['content'], $this->forbiddenFunctions[$tokenizer])) { - $functionName = $tokens[$i]['content']; - if ($tokenizer === 'JS') { - // Needs to be in the form object.function to be valid. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), null, true); - if ($prev === false || $tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { - continue; - } - - $functionName = 'object.'.$functionName; - } else { - // Make sure it isn't a member var. - if ($tokens[($i - 1)]['code'] === T_OBJECT_OPERATOR) { - continue; - } - - $functionName .= '()'; - } - - $error = 'The use of %s inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead'; - $data = array($functionName); - $phpcsFile->addError($error, $i, 'Found', $data); - }//end if - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php deleted file mode 100644 index 1689f996c..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found'); -} - -/** - * Squiz_Sniffs_PHP_DiscouragedFunctionsSniff. - * - * Discourages the use of debug functions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_DiscouragedFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff -{ - - /** - * A list of forbidden functions with their alternatives. - * - * The value is NULL if no alternative exists. IE, the - * function should just not be used. - * - * @var array(string => string|null) - */ - protected $forbiddenFunctions = array( - 'error_log' => null, - 'print_r' => null, - ); - - /** - * If true, an error will be thrown; otherwise a warning. - * - * @var bool - */ - public $error = false; - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php deleted file mode 100644 index bd975f0cb..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php +++ /dev/null @@ -1,263 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_EmbeddedPhpSniff. - * - * Checks the indentation of embedded PHP code segments. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_EmbeddedPhpSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If the close php tag is on the same line as the opening - // then we have an inline embedded PHP block. - $closeTag = $phpcsFile->findNext(array(T_CLOSE_TAG), $stackPtr); - if ($closeTag === false) { - return; - } - - if ($tokens[$stackPtr]['line'] !== $tokens[$closeTag]['line']) { - $this->_validateMultilineEmbeddedPhp($phpcsFile, $stackPtr); - } else { - $this->_validateInlineEmbeddedPhp($phpcsFile, $stackPtr); - } - - }//end process() - - - /** - * Validates embedded PHP that exists on multiple lines. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - private function _validateMultilineEmbeddedPhp(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prevTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($prevTag === false) { - // This is the first open tag. - return; - } - - // This isn't the first opening tag. - $closingTag = $phpcsFile->findNext(T_CLOSE_TAG, $stackPtr); - if ($closingTag === false) { - // No closing tag? Problem. - return; - } - - $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($closingTag + 1), $phpcsFile->numTokens, true); - if ($nextContent === false) { - // Final closing tag. It will be handled elsewhere. - return; - } - - // Make sure the lines are opening and closing on different lines. - if ($tokens[$stackPtr]['line'] === $tokens[$closingTag]['line']) { - return; - } - - // We have an opening and a closing tag, that lie within other content. - // They are also on different lines. - $firstContent = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), $closingTag, true); - if ($firstContent === false) { - $error = 'Empty embedded PHP tag found'; - $phpcsFile->addError($error, $stackPtr, 'Empty'); - return; - } - - // Check for a blank line at the top. - if ($tokens[$firstContent]['line'] > ($tokens[$stackPtr]['line'] + 1)) { - // Find a token on the blank line to throw the error on. - $i = $stackPtr; - do { - $i++; - } while ($tokens[$i]['line'] !== ($tokens[$stackPtr]['line'] + 1)); - - $error = 'Blank line found at start of embedded PHP content'; - $phpcsFile->addError($error, $i, 'SpacingBefore'); - } else if ($tokens[$firstContent]['line'] === $tokens[$stackPtr]['line']) { - $error = 'Opening PHP tag must be on a line by itself'; - $phpcsFile->addError($error, $stackPtr, 'ContentAfterOpen'); - } - - // Check the indent of the first line. - $startColumn = $tokens[$stackPtr]['column']; - $contentColumn = $tokens[$firstContent]['column']; - if ($contentColumn !== $startColumn) { - $error = 'First line of embedded PHP code must be indented %s spaces; %s found'; - $data = array( - $startColumn, - $contentColumn, - ); - $phpcsFile->addError($error, $firstContent, 'Indent', $data); - } - - // Check for a blank line at the bottom. - $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closingTag - 1), ($stackPtr + 1), true); - if ($tokens[$lastContent]['line'] < ($tokens[$closingTag]['line'] - 1)) { - // Find a token on the blank line to throw the error on. - $i = $closingTag; - do { - $i--; - } while ($tokens[$i]['line'] !== ($tokens[$closingTag]['line'] - 1)); - - $error = 'Blank line found at end of embedded PHP content'; - $phpcsFile->addError($error, $i, 'SpacingAfter'); - } else if ($tokens[$lastContent]['line'] === $tokens[$closingTag]['line']) { - $error = 'Closing PHP tag must be on a line by itself'; - $phpcsFile->addError($error, $closingTag, 'ContentAfterEnd'); - } - - }//end _validateMultilineEmbeddedPhp() - - - /** - * Validates embedded PHP that exists on one line. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - private function _validateInlineEmbeddedPhp(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We only want one line PHP sections, so return if the closing tag is - // on the next line. - $closeTag = $phpcsFile->findNext(array(T_CLOSE_TAG), $stackPtr, null, false); - if ($tokens[$stackPtr]['line'] !== $tokens[$closeTag]['line']) { - return; - } - - // Check that there is one, and only one space at the start of the statement. - $firstContent = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); - - if ($firstContent === false || $tokens[$firstContent]['code'] === T_CLOSE_TAG) { - $error = 'Empty embedded PHP tag found'; - $phpcsFile->addError($error, $stackPtr, 'Empty'); - return; - } - - $leadingSpace = ''; - for ($i = ($stackPtr + 1); $i < $firstContent; $i++) { - $leadingSpace .= $tokens[$i]['content']; - } - - if (strlen($leadingSpace) >= 1) { - $error = 'Expected 1 space after opening PHP tag; %s found'; - $data = array((strlen($leadingSpace) + 1)); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen', $data); - } - - $semiColonCount = 0; - $semiColon = $stackPtr; - $lastSemiColon = $semiColon; - - while (($semiColon = $phpcsFile->findNext(array(T_SEMICOLON), ($semiColon + 1), $closeTag)) !== false) { - $lastSemiColon = $semiColon; - $semiColonCount++; - } - - $semiColon = $lastSemiColon; - $error = ''; - - // Make sure there is atleast 1 semicolon. - if ($semiColonCount === 0) { - $error = 'Inline PHP statement must end with a semicolon'; - $phpcsFile->addError($error, $stackPtr, 'NoSemicolon'); - return; - } - - // Make sure that there aren't more semicolons than are allowed. - if ($semiColonCount > 1) { - $error = 'Inline PHP statement must contain one statement per line; %s found'; - $data = array($semiColonCount); - $phpcsFile->addError($error, $stackPtr, 'MultipleStatements', $data); - } - - // The statement contains only 1 semicolon, now it must be spaced properly. - $whitespace = ''; - for ($i = ($semiColon + 1); $i < $closeTag; $i++) { - if ($tokens[$i]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before closing PHP tag; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeClose'); - return; - } - - $whitespace .= $tokens[$i]['content']; - } - - if (strlen($whitespace) === 1) { - return; - } - - if (strlen($whitespace) === 0) { - $error = 'Expected 1 space before closing PHP tag; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeClose'); - } else { - $error = 'Expected 1 space before closing PHP tag; %s found'; - $data = array(strlen($whitespace)); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeClose', $data); - } - - }//end _validateInlineEmbeddedPhp() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php deleted file mode 100644 index 05c2f397f..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_EvalSniff. - * - * The use of eval() is discouraged. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_EvalSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_EVAL); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $error = 'Use of eval() is discouraged'; - $phpcsFile->addWarning($error, $stackPtr, 'Discouraged'); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php deleted file mode 100644 index 1bbdcaabe..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('Generic_Sniffs_PHP_ForbiddenFunctionsSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_PHP_ForbiddenFunctionsSniff not found'); -} - -/** - * Squiz_Sniffs_PHP_ForbiddenFunctionsSniff. - * - * Discourages the use of alias functions that are kept in PHP for compatibility - * with older versions. Can be used to forbid the use of any function. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_ForbiddenFunctionsSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff -{ - - /** - * A list of forbidden functions with their alternatives. - * - * The value is NULL if no alternative exists. IE, the - * function should just not be used. - * - * @var array(string => string|null) - */ - protected $forbiddenFunctions = array( - 'sizeof' => 'count', - 'delete' => 'unset', - 'print' => 'echo', - 'is_null' => null, - 'create_function' => null, - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - $tokens = parent::register(); - $tokens[] = T_PRINT; - return $tokens; - - }//end register() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php deleted file mode 100644 index 6b6887411..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_GlobalKeywordSniff. - * - * Stops the usage of the "global" keyword. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_GlobalKeywordSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_GLOBAL); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $nextVar = $tokens[$phpcsFile->findNext(array(T_VARIABLE), $stackPtr)]; - $varName = str_replace('$', '', $nextVar['content']); - $error = 'Use of the "global" keyword is forbidden; use "$GLOBALS[\'%s\']" instead'; - $data = array($varName); - $phpcsFile->addError($error, $stackPtr, 'NotAllowed', $data); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php deleted file mode 100644 index 165ad804b..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_HeredocSniff. - * - * Heredocs are prohibited. This test enforces that. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_HeredocSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_START_HEREDOC, - T_START_NOWDOC, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $error = 'Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead'; - $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php deleted file mode 100644 index 57f23b4e9..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_InnerFunctionsSniff. - * - * Ensures that functions within functions are never used. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_InnerFunctionsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_EQUAL) { - // Ignore closures. - return; - } - - $error = 'The use of inner functions is forbidden'; - $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php deleted file mode 100644 index fba533ce4..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff. - * - * Ensures all calls to inbuilt PHP functions are lowercase. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Make sure this is a function call. - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($next === false) { - // Not a function call. - return; - } - - if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { - // Not a function call. - return; - } - - $prev = $phpcsFile->findPrevious(array(T_WHITESPACE, T_BITWISE_AND), ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_FUNCTION) { - // Function declaration, not a function call. - return; - } - - if ($tokens[$prev]['code'] === T_NEW) { - // Object creation, not an inbuilt function. - return; - } - - if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR) { - // Not an inbuilt function. - return; - } - - if ($tokens[$prev]['code'] === T_DOUBLE_COLON) { - // Not an inbuilt function. - return; - } - - // Make sure it is an inbuilt PHP function. - // PHP_CodeSniffer doesn't include/require any files, so no - // user defined global functions can exist, except for - // PHP_CodeSniffer ones. - $content = $tokens[$stackPtr]['content']; - if (function_exists($content) === false) { - return; - } - - if ($content !== strtolower($content)) { - $error = 'Calls to inbuilt PHP functions must be lowercase; expected "%s" but found "%s"'; - $data = array( - strtolower($content), - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'CallUppercase', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php deleted file mode 100644 index 1f35bbcd0..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php +++ /dev/null @@ -1,272 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_PHP_NonExecutableCodeSniff. - * - * Warns about code that can never been executed. This happens when a function - * returns before the code, or a break ends execution of a statement etc. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_PHP_NonExecutableCodeSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_BREAK, - T_CONTINUE, - T_RETURN, - T_THROW, - T_EXIT, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If this token is preceded with an "or", it only relates to one line - // and should be ignored. For example: fopen() or die(). - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_LOGICAL_OR) { - return; - } - - // Check if this token is actually part of a one-line IF or ELSE statement. - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { - $i = $tokens[$i]['parenthesis_opener']; - continue; - } else if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } - - break; - } - - if ($tokens[$i]['code'] === T_IF - || $tokens[$i]['code'] === T_ELSE - || $tokens[$i]['code'] === T_ELSEIF - ) { - return; - } - - if ($tokens[$stackPtr]['code'] === T_RETURN) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$next]['code'] === T_SEMICOLON) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); - if ($tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) { - // If this is the closing brace of a function - // then this return statement doesn't return anything - // and is not required anyway. - $owner = $tokens[$next]['scope_condition']; - if ($tokens[$owner]['code'] === T_FUNCTION) { - $warning = 'Empty return statement not required here'; - $phpcsFile->addWarning($warning, $stackPtr, 'ReturnNotRequired'); - return; - } - } - } - } - - if (isset($tokens[$stackPtr]['scope_opener']) === true) { - $owner = $tokens[$stackPtr]['scope_condition']; - if ($tokens[$owner]['code'] === T_CASE || $tokens[$owner]['code'] === T_DEFAULT) { - // This token closes the scope of a CASE or DEFAULT statement - // so any code between this token and the next CASE, DEFAULT or - // end of SWITCH token will not be executable. - $next = $phpcsFile->findNext( - array( - T_CASE, - T_DEFAULT, - T_CLOSE_CURLY_BRACKET, - ), - ($stackPtr + 1) - ); - - if ($next !== false) { - $end = $phpcsFile->findNext(array(T_SEMICOLON), ($stackPtr + 1)); - $lastLine = $tokens[$end]['line']; - for ($i = ($stackPtr + 1); $i < $next; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - continue; - } - - $line = $tokens[$i]['line']; - if ($line > $lastLine) { - $type = substr($tokens[$stackPtr]['type'], 2); - $warning = 'Code after %s statement cannot be executed'; - $data = array($type); - $phpcsFile->addWarning($warning, $i, 'Unreachable', $data); - $lastLine = $line; - } - } - }//end if - - // That's all we have to check for these types of statements. - return; - } - }//end if - - // This token may be part of an inline condition. - // If we find a closing parenthesis that belongs to a condition - // we should ignore this token. - $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if (isset($tokens[$prev]['parenthesis_owner']) === true) { - $owner = $tokens[$prev]['parenthesis_owner']; - $ignore = array( - T_IF, - T_ELSE, - T_ELSEIF, - ); - if (in_array($tokens[$owner]['code'], $ignore) === true) { - return; - } - } - - $ourConditions = array_keys($tokens[$stackPtr]['conditions']); - - if (empty($ourConditions) === false) { - $condition = array_pop($ourConditions); - - if (isset($tokens[$condition]['scope_closer']) === false) { - return; - } - - // Special case for BREAK statements sitting directly inside SWITCH - // statements. If we get to this point, we know the BREAK is not being - // used to close a CASE statement, so it is most likely non-executable - // code itself (as is the case when you put return; break; at the end of - // a case). So we need to ignore this token. - if ($tokens[$condition]['code'] === T_SWITCH - && $tokens[$stackPtr]['code'] === T_BREAK - ) { - return; - } - - $closer = $tokens[$condition]['scope_closer']; - - // If the closer for our condition is shared with other openers, - // we will need to throw errors from this token to the next - // shared opener (if there is one), not to the scope closer. - $nextOpener = null; - for ($i = ($stackPtr + 1); $i < $closer; $i++) { - if (isset($tokens[$i]['scope_closer']) === true) { - if ($tokens[$i]['scope_closer'] === $closer) { - // We found an opener that shares the same - // closing token as us. - $nextOpener = $i; - break; - } - } - }//end for - - if ($nextOpener === null) { - $end = $closer; - } else { - $end = ($nextOpener - 1); - } - } else { - // This token is in the global scope. - if ($tokens[$stackPtr]['code'] === T_BREAK) { - return; - } - - // Throw an error for all lines until the end of the file. - $end = ($phpcsFile->numTokens - 1); - }//end if - - // Find the semicolon that ends this statement, skipping - // nested statements like FOR loops and closures. - for ($start = ($stackPtr + 1); $start < $phpcsFile->numTokens; $start++) { - if ($start === $end) { - break; - } - - if ($tokens[$start]['code'] === T_OPEN_PARENTHESIS) { - $start = $tokens[$start]['parenthesis_closer']; - continue; - } - - if ($tokens[$start]['code'] === T_OPEN_CURLY_BRACKET) { - $start = $tokens[$start]['bracket_closer']; - continue; - } - - if ($tokens[$start]['code'] === T_SEMICOLON) { - break; - } - }//end for - - $lastLine = $tokens[$start]['line']; - for ($i = ($start + 1); $i < $end; $i++) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true - || in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$bracketTokens) === true - ) { - continue; - } - - // Skip whole functions and classes/interfaces because they are not - // technically executed code, but rather declarations that may be used. - if ($tokens[$i]['code'] === T_FUNCTION - || $tokens[$i]['code'] === T_CLASS - || $tokens[$i]['code'] === T_INTERFACE - ) { - $i = $tokens[$i]['scope_closer']; - continue; - } - - $line = $tokens[$i]['line']; - if ($line > $lastLine) { - $type = substr($tokens[$stackPtr]['type'], 2); - $warning = 'Code after %s statement cannot be executed'; - $data = array($type); - $phpcsFile->addWarning($warning, $i, 'Unreachable', $data); - $lastLine = $line; - } - }//end for - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php deleted file mode 100644 index f70b30286..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -/** - * Verifies that class members have scope modifiers. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Scope_MemberVarScopeSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); - - if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { - $error = 'Scope modifier not specified for member variable "%s"'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $stackPtr, 'Missing', $data); - } - - }//end processMemberVar() - - - /** - * Processes normal variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariable() - - - /** - * Processes variables in double quoted strings. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php deleted file mode 100644 index 0bfec5289..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * Verifies that class members have scope modifiers. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Scope_MethodScopeSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. - */ - public function __construct() - { - parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION)); - - }//end __construct() - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * @param int $currScope The current scope opener token. - * - * @return void - */ - protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $tokens = $phpcsFile->getTokens(); - - $methodName = $phpcsFile->getDeclarationName($stackPtr); - if ($methodName === null) { - // Ignore closures. - return; - } - - $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); - if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { - $error = 'Visibility must be declared on method "%s"'; - $data = array($methodName); - $phpcsFile->addError($error, $stackPtr, 'Missing', $data); - } - - }//end processTokenWithinScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php deleted file mode 100644 index aab654789..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); -} - -/** - * Squiz_Sniffs_Scope_StaticThisUsageSniff. - * - * Checks for usage of "$this" in static methods, which will cause - * runtime errors. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Scope_StaticThisUsageSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff -{ - - - /** - * Constructs the test with the tokens it wishes to listen for. - * - * @return void - */ - public function __construct() - { - parent::__construct(array(T_CLASS), array(T_FUNCTION)); - - }//end __construct() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * @param int $currScope A pointer to the start of the scope. - * - * @return void - */ - public function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) - { - $tokens = $phpcsFile->getTokens(); - $function = $tokens[($stackPtr + 2)]; - - if ($function['code'] !== T_STRING) { - return; - } - - $functionName = $function['content']; - $classOpener = $tokens[$currScope]['scope_condition']; - $className = $tokens[($classOpener + 2)]['content']; - - $methodProps = $phpcsFile->getMethodProperties($stackPtr); - - if ($methodProps['is_static'] === true) { - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - // There is no scope opener or closer, so the function - // must be abstract. - return; - } - - $thisUsage = $stackPtr; - while (($thisUsage = $phpcsFile->findNext(array(T_VARIABLE), ($thisUsage + 1), $tokens[$stackPtr]['scope_closer'], false, '$this')) !== false) { - if ($thisUsage === false) { - return; - } - - $error = 'Usage of "$this" in static methods will cause runtime errors'; - $phpcsFile->addError($error, $thisUsage, 'Found'); - } - }//end if - - }//end processTokenWithinScope() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php deleted file mode 100644 index 68d858d97..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Strings_ConcatenationSpacingSniff. - * - * Makes sure there are no spaces between the concatenation operator (.) and - * the strings being concatenated. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Strings_ConcatenationSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_STRING_CONCAT); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE - || $tokens[($stackPtr + 1)]['code'] === T_WHITESPACE - ) { - $message = 'Concat operator must not be surrounded by spaces'; - $phpcsFile->addError($message, $stackPtr, 'Missing'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php deleted file mode 100644 index 44bdd7ddf..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php +++ /dev/null @@ -1,135 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Strings_DoubleQuoteUsageSniff. - * - * Makes sure that any use of Double Quotes ("") are warranted. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Strings_DoubleQuoteUsageSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_CONSTANT_ENCAPSED_STRING, - T_DOUBLE_QUOTED_STRING, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // We are only interested in the first token in a multi-line string. - if ($tokens[$stackPtr]['code'] === $tokens[($stackPtr - 1)]['code']) { - return; - } - - $workingString = $tokens[$stackPtr]['content']; - $i = ($stackPtr + 1); - while ($tokens[$i]['code'] === $tokens[$stackPtr]['code']) { - $workingString .= $tokens[$i]['content']; - $i++; - } - - // Check if it's a double quoted string. - if (strpos($workingString, '"') === false) { - return; - } - - // Make sure it's not a part of a string started in a previous line. - // If it is, then we have already checked it. - if ($workingString[0] !== '"') { - return; - } - - // The use of variables in double quoted strings is not allowed. - if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING) { - $stringTokens = token_get_all('addError($error, $stackPtr, 'ContainsVar', $data); - } - } - - return; - }//end if - - // Work through the following tokens, in case this string is stretched - // over multiple Lines. - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['type'] !== 'T_CONSTANT_ENCAPSED_STRING') { - break; - } - - $workingString .= $tokens[$i]['content']; - } - - $allowedChars = array( - '\0', - '\n', - '\r', - '\f', - '\t', - '\v', - '\x', - '\'', - ); - - foreach ($allowedChars as $testChar) { - if (strpos($workingString, $testChar) !== false) { - return; - } - } - - $error = 'String %s does not require double quotes; use single quotes instead'; - $data = array($workingString); - $phpcsFile->addError($error, $stackPtr, 'NotRequired', $data); - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php deleted file mode 100644 index 2f4d283ee..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Strings_EchoedStringsSniff. - * - * Makes sure that any strings that are "echoed" are not enclosed in brackets - * like a function call. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_Strings_EchoedStringsSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_ECHO); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $firstContent = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); - // If the first non-whitespace token is not an opening parenthesis, then we are not concerned. - if ($tokens[$firstContent]['code'] !== T_OPEN_PARENTHESIS) { - return; - } - - $endOfStatement = $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr, null, false); - - // If the token before the semi-colon is not a closing parenthesis, then we are not concerned. - if ($tokens[($endOfStatement - 1)]['code'] !== T_CLOSE_PARENTHESIS) { - return; - } - - if (($phpcsFile->findNext(PHP_CodeSniffer_Tokens::$operators, $stackPtr, $endOfStatement, false)) === false) { - // There are no arithmetic operators in this. - $error = 'Echoed strings should not be bracketed'; - $phpcsFile->addError($error, $stackPtr, 'HasBracket'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php deleted file mode 100644 index 79da3af0e..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_CastSpacingSniff. - * - * Ensure cast statements don't contain whitespace. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_CastSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$castTokens; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $content = $tokens[$stackPtr]['content']; - $expected = str_replace(' ', '', $content); - $expected = str_replace("\t", '', $expected); - - if ($content !== $expected) { - $error = 'Cast statements must not contain whitespace; expected "%s" but found "%s"'; - $data = array( - $expected, - $content, - ); - $phpcsFile->addError($error, $stackPtr, 'ContainsWhiteSpace', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php deleted file mode 100644 index ecf6dfed7..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ /dev/null @@ -1,209 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff. - * - * Checks that control structures have the correct spacing around brackets. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_IF, - T_WHILE, - T_FOREACH, - T_FOR, - T_SWITCH, - T_DO, - T_ELSE, - T_ELSEIF, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - return; - } - - if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { - $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; - $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[($parenOpener + 1)]['code'] === T_WHITESPACE) { - $gap = strlen($tokens[($parenOpener + 1)]['content']); - $error = 'Expected 0 spaces after opening bracket; %s found'; - $data = array($gap); - $phpcsFile->addError($error, ($parenOpener + 1), 'SpacingAfterOpenBrace', $data); - } - - if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line'] - && $tokens[($parenCloser - 1)]['code'] === T_WHITESPACE - ) { - $gap = strlen($tokens[($parenCloser - 1)]['content']); - $error = 'Expected 0 spaces before closing bracket; %s found'; - $data = array($gap); - $phpcsFile->addError($error, ($parenCloser - 1), 'SpaceBeforeCloseBrace', $data); - } - }//end if - - $scopeOpener = $tokens[$stackPtr]['scope_opener']; - $scopeCloser = $tokens[$stackPtr]['scope_closer']; - - $firstContent = $phpcsFile->findNext( - T_WHITESPACE, - ($scopeOpener + 1), - null, - true - ); - - if ($tokens[$firstContent]['line'] !== ($tokens[$scopeOpener]['line'] + 1)) { - $error = 'Blank line found at start of control structure'; - $phpcsFile->addError($error, $scopeOpener, 'SpacingBeforeOpen'); - } - - $lastContent = $phpcsFile->findPrevious( - T_WHITESPACE, - ($scopeCloser - 1), - null, - true - ); - - if ($tokens[$lastContent]['line'] !== ($tokens[$scopeCloser]['line'] - 1)) { - $errorToken = $scopeCloser; - for ($i = ($scopeCloser - 1); $i > $lastContent; $i--) { - if ($tokens[$i]['line'] < $tokens[$scopeCloser]['line']) { - $errorToken = $i; - break; - } - } - - $error = 'Blank line found at end of control structure'; - $phpcsFile->addError($error, $errorToken, 'SpacingAfterClose'); - } - - $trailingContent = $phpcsFile->findNext( - T_WHITESPACE, - ($scopeCloser + 1), - null, - true - ); - - if ($tokens[$trailingContent]['code'] === T_ELSE) { - if ($tokens[$stackPtr]['code'] === T_IF) { - // IF with ELSE. - return; - } - } - - if ($tokens[$trailingContent]['code'] === T_COMMENT) { - if ($tokens[$trailingContent]['line'] === $tokens[$scopeCloser]['line']) { - if (substr($tokens[$trailingContent]['content'], 0, 5) === '//end') { - // There is an end comment, so we have to get the next piece - // of content. - $trailingContent = $phpcsFile->findNext( - T_WHITESPACE, - ($trailingContent + 1), - null, - true - ); - } - } - } - - // If this token is closing a CASE or DEFAULT, we don't need the - // blank line after this control structure. - if (isset($tokens[$trailingContent]['scope_condition']) === true) { - $condition = $tokens[$trailingContent]['scope_condition']; - if ($tokens[$condition]['code'] === T_CASE - || $tokens[$condition]['code'] === T_DEFAULT - ) { - return; - } - } - - if ($tokens[$trailingContent]['code'] === T_CLOSE_TAG) { - // At the end of the script or embedded code. - return; - } - - if ($tokens[$trailingContent]['code'] === T_CLOSE_CURLY_BRACKET) { - // Another control structure's closing brace. - if (isset($tokens[$trailingContent]['scope_condition']) === true) { - $owner = $tokens[$trailingContent]['scope_condition']; - if ($tokens[$owner]['code'] === T_FUNCTION) { - // The next content is the closing brace of a function - // so normal function rules apply and we can ignore it. - return; - } - } - - if ($tokens[$trailingContent]['line'] !== ($tokens[$scopeCloser]['line'] + 1)) { - $error = 'Blank line found after control structure'; - $phpcsFile->addError($error, $scopeCloser, 'LineAfterClose'); - } - } else { - if ($tokens[$trailingContent]['line'] === ($tokens[$scopeCloser]['line'] + 1)) { - $error = 'No blank line found after control structure'; - $phpcsFile->addError($error, $scopeCloser, 'NoLineAfterClose'); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php deleted file mode 100644 index 1ff04d789..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff. - * - * Checks that there is one empty line before the closing brace of a function. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - // Probably an interface method. - return; - } - - $closeBrace = $tokens[$stackPtr]['scope_closer']; - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true); - - // Special case for empty JS functions - if ($phpcsFile->tokenizerType === 'JS' && $prevContent === $tokens[$stackPtr]['scope_opener']) { - // In this case, the opening and closing brace must be - // right next to each other. - if ($tokens[$stackPtr]['scope_closer'] !== ($tokens[$stackPtr]['scope_opener'] + 1)) { - $error = 'The opening and closing braces of empty functions must be directly next to each other; e.g., function () {}'; - $phpcsFile->addError($error, $closeBrace, 'SpacingBetween'); - } - - return; - } - - $braceLine = $tokens[$closeBrace]['line']; - $prevLine = $tokens[$prevContent]['line']; - - $found = ($braceLine - $prevLine - 1); - if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - // Nested function. - if ($found < 0) { - $error = 'Closing brace of nested function must be on a new line'; - $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose'); - } else if ($found > 0) { - $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; - $data = array($found); - $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); - } - } else { - if ($found !== 1) { - $error = 'Expected 1 blank line before closing function brace; %s found'; - $data = array($found); - $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php deleted file mode 100644 index e2c17fecb..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php +++ /dev/null @@ -1,127 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff. - * - * Checks that there is no empty line after the opening brace of a function. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - // Probably an interface method. - return; - } - - $openBrace = $tokens[$stackPtr]['scope_opener']; - $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($openBrace + 1), null, true); - - if ($nextContent === $tokens[$stackPtr]['scope_closer']) { - // The next bit of content is the closing brace, so this - // is an empty function and should have a blank line - // between the opening and closing braces. - return; - } - - $braceLine = $tokens[$openBrace]['line']; - $nextLine = $tokens[$nextContent]['line']; - - $found = ($nextLine - $braceLine - 1); - if ($found > 0) { - $error = 'Expected 0 blank lines after opening function brace; %s found'; - $data = array($found); - $phpcsFile->addError($error, $openBrace, 'SpacingAfter', $data); - } - - if ($phpcsFile->tokenizerType === 'JS') { - // Do some additional checking before the function brace. - $nestedFunction = ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true); - - $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; - $lineDifference = ($braceLine - $functionLine); - - if ($nestedFunction === true) { - if ($lineDifference > 0) { - $error = 'Opening brace should be on the same line as the function keyword'; - $phpcsFile->addError($error, $openBrace, 'SpacingAfterNested'); - } - } else { - if ($lineDifference === 0) { - $error = 'Opening brace should be on a new line'; - $phpcsFile->addError($error, $openBrace, 'ContentBefore'); - return; - } - - if ($lineDifference > 1) { - $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; - $data = array(($lineDifference - 1)); - $phpcsFile->addError($error, $openBrace, 'SpacingBefore', $data); - return; - } - }//end if - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php deleted file mode 100644 index 6f53e17f4..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php +++ /dev/null @@ -1,193 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff. - * - * Checks the separation between methods in a class or interface. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * The number of blank lines between functions. - * - * @var int - */ - public $spacing = 2; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_FUNCTION); - - }//end register() - - - /** - * Processes this sniff when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $this->spacing = (int) $this->spacing; - - /* - Check the number of blank lines - after the function. - */ - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - // Must be an interface method, so the closer is the semi-colon. - $closer = $phpcsFile->findNext(T_SEMICOLON, $stackPtr); - } else { - $closer = $tokens[$stackPtr]['scope_closer']; - } - - $nextLineToken = null; - for ($i = $closer; $i < $phpcsFile->numTokens; $i++) { - if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { - continue; - } else { - $nextLineToken = ($i + 1); - break; - } - } - - if (is_null($nextLineToken) === true) { - // Never found the next line, which means - // there are 0 blank lines after the function. - $foundLines = 0; - } else { - $nextContent = $phpcsFile->findNext(array(T_WHITESPACE), ($nextLineToken + 1), null, true); - if ($nextContent === false) { - // We are at the end of the file. - $foundLines = 0; - } else { - $foundLines = ($tokens[$nextContent]['line'] - $tokens[$nextLineToken]['line']); - } - } - - if ($foundLines !== $this->spacing) { - $error = 'Expected %s blank line'; - if ($this->spacing !== 1) { - $error .= 's'; - } - - $error .= ' after function; %s found'; - $data = array( - $this->spacing, - $foundLines, - ); - $phpcsFile->addError($error, $closer, 'After', $data); - } - - /* - Check the number of blank lines - before the function. - */ - - $prevLineToken = null; - for ($i = $stackPtr; $i > 0; $i--) { - if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { - continue; - } else { - $prevLineToken = $i; - break; - } - } - - if (is_null($prevLineToken) === true) { - // Never found the previous line, which means - // there are 0 blank lines before the function. - $foundLines = 0; - } else { - $prevContent = $phpcsFile->findPrevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevLineToken, null, true); - - // Before we throw an error, check that we are not throwing an error - // for another function. We don't want to error for no blank lines after - // the previous function and no blank lines before this one as well. - $currentLine = $tokens[$stackPtr]['line']; - $prevLine = ($tokens[$prevContent]['line'] - 1); - $i = ($stackPtr - 1); - $foundLines = 0; - while ($currentLine != $prevLine && $currentLine > 1 && $i > 0) { - if (isset($tokens[$i]['scope_condition']) === true) { - $scopeCondition = $tokens[$i]['scope_condition']; - if ($tokens[$scopeCondition]['code'] === T_FUNCTION) { - // Found a previous function. - return; - } - } else if ($tokens[$i]['code'] === T_FUNCTION) { - // Found another interface function. - return; - } - - $currentLine = $tokens[$i]['line']; - if ($currentLine === $prevLine) { - break; - } - - if ($tokens[($i - 1)]['line'] < $currentLine && $tokens[($i + 1)]['line'] > $currentLine) { - // This token is on a line by itself. If it is whitespace, the line is empty. - if ($tokens[$i]['code'] === T_WHITESPACE) { - $foundLines++; - } - } - - $i--; - }//end while - }//end if - - if ($foundLines !== $this->spacing) { - $error = 'Expected %s blank line'; - if ($this->spacing !== 1) { - $error .= 's'; - } - - $error .= ' before function; %s found'; - $data = array( - $this->spacing, - $foundLines, - ); - $phpcsFile->addError($error, $stackPtr, 'Before', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php deleted file mode 100644 index d7888a3af..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff. - * - * Ensures all language constructs (without brackets) contain a - * single space between themselves and their content. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_ECHO, - T_PRINT, - T_RETURN, - T_INCLUDE, - T_INCLUDE_ONCE, - T_REQUIRE, - T_REQUIRE_ONCE, - T_NEW, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[($stackPtr + 1)]['code'] === T_SEMICOLON) { - // No content for this language construct. - return; - } - - if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { - $content = $tokens[($stackPtr + 1)]['content']; - $contentLength = strlen($content); - if ($contentLength !== 1) { - $error = 'Language constructs must be followed by a single space; expected 1 space but found %s'; - $data = array($contentLength); - $phpcsFile->addError($error, $stackPtr, 'IncorrectSingle', $data); - } - } else { - $error = 'Language constructs must be followed by a single space; expected "%s" but found "%s"'; - $data = array( - $tokens[$stackPtr]['content'].' '.$tokens[($stackPtr + 1)]['content'], - $tokens[$stackPtr]['content'].$tokens[($stackPtr + 1)]['content'], - ); - $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php deleted file mode 100644 index 804b59772..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php +++ /dev/null @@ -1,106 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff. - * - * Verifies that operators have valid spacing surrounding them. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$booleanOperators; - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Check there is one space before the operator. - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before logical operator; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore'); - } else { - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$stackPtr]['line'] === $tokens[$prev]['line'] - && strlen($tokens[($stackPtr - 1)]['content']) !== 1 - ) { - $found = strlen($tokens[($stackPtr - 1)]['content']); - $error = 'Expected 1 space before logical operator; %s found'; - $data = array($found); - $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceBefore', $data); - } - } - - // Check there is one space after the operator. - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after logical operator; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter'); - } else { - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($tokens[$stackPtr]['line'] === $tokens[$next]['line'] - && strlen($tokens[($stackPtr + 1)]['content']) !== 1 - ) { - $found = strlen($tokens[($stackPtr + 1)]['content']); - $error = 'Expected 1 space after logical operator; %s found'; - $data = array($found); - $phpcsFile->addError($error, $stackPtr, 'TooMuchSpaceAfter', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php deleted file mode 100644 index a108c48e6..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -/** - * Verifies that class members are spaced correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - - /** - * Processes the function tokens within the class. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // There needs to be 1 blank line before the var, not counting comments. - $prevLineToken = null; - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - // Skip comments. - continue; - } else if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) { - // Not the end of the line. - continue; - } else { - // If this is a WHITESPACE token, and the token right before - // it is a DOC_COMMENT, then it is just the newline after the - // member var's comment, and can be skipped. - if ($tokens[$i]['code'] === T_WHITESPACE && in_array($tokens[($i - 1)]['code'], PHP_CodeSniffer_Tokens::$commentTokens) === true) { - continue; - } - - $prevLineToken = $i; - break; - } - } - - if (is_null($prevLineToken) === true) { - // Never found the previous line, which means - // there are 0 blank lines before the member var. - $foundLines = 0; - } else { - $prevContent = $phpcsFile->findPrevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevLineToken, null, true); - $foundLines = ($tokens[$prevLineToken]['line'] - $tokens[$prevContent]['line']); - }//end if - - if ($foundLines !== 1) { - $error = 'Expected 1 blank line before member var; %s found'; - $data = array($foundLines); - $phpcsFile->addError($error, $stackPtr, 'After', $data); - } - - }//end processMemberVar() - - - /** - * Processes normal variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariable() - - - /** - * Processes variables in double quoted strings. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // We don't care about normal variables. - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php deleted file mode 100644 index c70e0c5bb..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff. - * - * Ensure there is no whitespace before a semicolon. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_OBJECT_OPERATOR); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prevType = $tokens[($stackPtr - 1)]['code']; - if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $error = 'Space found before object operator'; - $phpcsFile->addError($error, $stackPtr, 'Before'); - } - - $nextType = $tokens[($stackPtr + 1)]['code']; - if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $error = 'Space found after object operator'; - $phpcsFile->addError($error, $stackPtr, 'After'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php deleted file mode 100644 index d84768b1a..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php +++ /dev/null @@ -1,220 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Sniffs_Squiz_WhiteSpace_OperatorSpacingSniff. - * - * Verifies that operators have valid spacing surrounding them. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - $comparison = PHP_CodeSniffer_Tokens::$comparisonTokens; - $operators = PHP_CodeSniffer_Tokens::$operators; - $assignment = PHP_CodeSniffer_Tokens::$assignmentTokens; - $inlineIf = array( - T_INLINE_THEN, - T_INLINE_ELSE, - ); - - return array_unique( - array_merge($comparison, $operators, $assignment, $inlineIf) - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Skip default values in function declarations. - if ($tokens[$stackPtr]['code'] === T_EQUAL - || $tokens[$stackPtr]['code'] === T_MINUS - ) { - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']); - $bracket = array_pop($parenthesis); - if (isset($tokens[$bracket]['parenthesis_owner']) === true) { - $function = $tokens[$bracket]['parenthesis_owner']; - if ($tokens[$function]['code'] === T_FUNCTION - || $tokens[$function]['code'] === T_CLOSURE - ) { - return; - } - } - } - } - - if ($tokens[$stackPtr]['code'] === T_EQUAL) { - // Skip for '=&' case. - if (isset($tokens[($stackPtr + 1)]) === true && $tokens[($stackPtr + 1)]['code'] === T_BITWISE_AND) { - return; - } - } - - if ($tokens[$stackPtr]['code'] === T_BITWISE_AND) { - // If it's not a reference, then we expect one space either side of the - // bitwise operator. - if ($phpcsFile->isReference($stackPtr) === true) { - return; - } - - // Check there is one space before the & operator. - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space before "&" operator; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeAmp'); - } else { - if (strlen($tokens[($stackPtr - 1)]['content']) !== 1) { - $found = strlen($tokens[($stackPtr - 1)]['content']); - $error = 'Expected 1 space before "&" operator; %s found'; - $data = array($found); - $phpcsFile->addError($error, $stackPtr, 'SpacingBeforeAmp', $data); - } - } - - // Check there is one space after the & operator. - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space after "&" operator; 0 found'; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterAmp'); - } else { - if (strlen($tokens[($stackPtr + 1)]['content']) !== 1) { - $found = strlen($tokens[($stackPtr + 1)]['content']); - $error = 'Expected 1 space after "&" operator; %s found'; - $data = array($found); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfterAmp', $data); - } - } - - return; - }//end if - - if ($tokens[$stackPtr]['code'] === T_MINUS) { - // Check minus spacing, but make sure we aren't just assigning - // a minus value or returning one. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prev]['code'] === T_RETURN) { - // Just returning a negative value; eg. (return -1). - return; - } - - if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$operators) === true) { - // Just trying to operate on a negative value; eg. ($var * -1). - return; - } - - if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) === true) { - // Just trying to compare a negative value; eg. ($var === -1). - return; - } - - if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { - // Just trying to assign a negative value; eg. ($var = -1). - return; - } - - // A list of tokens that indicate that the token is not - // part of an arithmetic operation. - $invalidTokens = array( - T_COMMA, - T_OPEN_PARENTHESIS, - T_OPEN_SQUARE_BRACKET, - T_DOUBLE_ARROW, - T_COLON, - T_INLINE_THEN, - T_INLINE_ELSE, - T_CASE, - ); - - if (in_array($tokens[$prev]['code'], $invalidTokens) === true) { - // Just trying to use a negative value; eg. myFunction($var, -2). - return; - } - }//end if - - $operator = $tokens[$stackPtr]['content']; - - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) { - $error = "Expected 1 space before \"$operator\"; 0 found"; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore'); - } else if (strlen($tokens[($stackPtr - 1)]['content']) !== 1) { - // Don't throw an error for assignments, because other standards allow - // multiple spaces there to align multiple assignments. - if (in_array($tokens[$stackPtr]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === false) { - $found = strlen($tokens[($stackPtr - 1)]['content']); - $error = 'Expected 1 space before "%s"; %s found'; - $data = array( - $operator, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); - } - } - - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $error = "Expected 1 space after \"$operator\"; 0 found"; - $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter'); - } else if (strlen($tokens[($stackPtr + 1)]['content']) !== 1) { - $found = strlen($tokens[($stackPtr + 1)]['content']); - $error = 'Expected 1 space after "%s"; %s found'; - $data = array( - $operator, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'SpacingAfter', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php deleted file mode 100644 index 1b5b06ab1..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff. - * - * Ensures that the colon in a property or label definition has a single - * space after it and no space before it. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array('JS'); - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_PROPERTY, - T_LABEL, - ); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $colon = $phpcsFile->findNext(T_COLON, ($stackPtr + 1)); - - if ($colon !== ($stackPtr + 1)) { - $error = 'There must be no space before the colon in a property/label declaration'; - $phpcsFile->addError($error, $stackPtr, 'Before'); - } - - if ($tokens[($colon + 1)]['code'] !== T_WHITESPACE || $tokens[($colon + 1)]['content'] !== ' ') { - $error = 'There must be a single space after the colon in a property/label declaration'; - $phpcsFile->addError($error, $stackPtr, 'After'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php deleted file mode 100644 index 338806bac..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php +++ /dev/null @@ -1,110 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_Whitespace_ScopeClosingBraceSniff. - * - * Checks that the closing braces of scopes are aligned correctly. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return PHP_CodeSniffer_Tokens::$scopeOpeners; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // If this is an inline condition (ie. there is no scope opener), then - // return, as this is not a new scope. - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - return; - } - - // We need to actually find the first piece of content on this line, - // as if this is a method with tokens before it (public, static etc) - // or an if with an else before it, then we need to start the scope - // checking from there, rather than the current token. - $lineStart = ($stackPtr - 1); - for ($lineStart; $lineStart > 0; $lineStart--) { - if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { - break; - } - } - - // We found a new line, now go forward and find the - // first non-whitespace token. - $lineStart = $phpcsFile->findNext(array(T_WHITESPACE), ($lineStart + 1), null, true); - - $startColumn = $tokens[$lineStart]['column']; - $scopeStart = $tokens[$stackPtr]['scope_opener']; - $scopeEnd = $tokens[$stackPtr]['scope_closer']; - - // Check that the closing brace is on it's own line. - $lastContent = $phpcsFile->findPrevious(array(T_WHITESPACE), ($scopeEnd - 1), $scopeStart, true); - if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { - $error = 'Closing brace must be on a line by itself'; - $phpcsFile->addError($error, $scopeEnd, 'ContentBefore'); - return; - } - - // Check now that the closing brace is lined up correctly. - $braceIndent = $tokens[$scopeEnd]['column']; - if (in_array($tokens[$stackPtr]['code'], array(T_CASE, T_DEFAULT)) === false) { - if ($braceIndent !== $startColumn) { - $error = 'Closing brace indented incorrectly; expected %s spaces, found %s'; - $data = array( - ($startColumn - 1), - ($braceIndent - 1), - ); - $phpcsFile->addError($error, $scopeEnd, 'Indent', $data); - } - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php deleted file mode 100644 index 76ae3b114..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff. - * - * Ensure there is a single space after scope keywords. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - $register = PHP_CodeSniffer_Tokens::$scopeModifiers; - $register[] = T_STATIC; - return $register; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - - if ($tokens[$stackPtr]['code'] === T_STATIC - && ($tokens[$nextToken]['code'] === T_DOUBLE_COLON - || $tokens[$prevToken]['code'] === T_NEW) - ) { - // Late static binding, e.g., static:: OR new static() usage. - return; - } - - $nextToken = $tokens[($stackPtr + 1)]; - if ($nextToken['code'] !== T_WHITESPACE - || strlen($nextToken['content']) !== 1 - || $nextToken['content'] === $phpcsFile->eolChar - ) { - $error = 'Scope keyword "%s" must be followed by a single space'; - $data = array($tokens[$stackPtr]['content']); - $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php deleted file mode 100644 index 84b46e1bc..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff. - * - * Ensure there is no whitespace before a semicolon. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - ); - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_SEMICOLON); - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token - * in the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $prevType = $tokens[($stackPtr - 1)]['code']; - if (in_array($prevType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) { - $nonSpace = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 2), null, true); - $expected = $tokens[$nonSpace]['content'].';'; - $found = $phpcsFile->getTokensAsString($nonSpace, ($stackPtr - $nonSpace)).';'; - $error = 'Space found before semicolon; expected "%s" but found "%s"'; - $data = array( - $expected, - $found, - ); - $phpcsFile->addError($error, $stackPtr, 'Incorrect', $data); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php b/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php deleted file mode 100644 index c653e7758..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php +++ /dev/null @@ -1,231 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff. - * - * Checks that no whitespace proceeds the first content of the file, exists - * after the last content of the file, resides after content on any line, or - * are two empty lines in functions. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff implements PHP_CodeSniffer_Sniff -{ - - /** - * A list of tokenizers this sniff supports. - * - * @var array - */ - public $supportedTokenizers = array( - 'PHP', - 'JS', - 'CSS', - ); - - /** - * If TRUE, whitespace rules are not checked for blank lines. - * - * Blank lines are those that contain only whitespace. - * - * @var boolean - */ - public $ignoreBlankLines = false; - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array( - T_OPEN_TAG, - T_CLOSE_TAG, - T_WHITESPACE, - T_COMMENT, - ); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { - - /* - Check for start of file whitespace. - */ - - if ($phpcsFile->tokenizerType !== 'PHP') { - // The first token is always the open tag inserted when tokenizsed - // and the second token is always the first piece of content in - // the file. If the second token is whitespace, there was - // whitespace at the start of the file. - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - return; - } - } else { - // If its the first token, then there is no space. - if ($stackPtr === 0) { - return; - } - - for ($i = ($stackPtr - 1); $i >= 0; $i--) { - // If we find something that isn't inline html then there is something previous in the file. - if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { - return; - } - - // If we have ended up with inline html make sure it isn't just whitespace. - $tokenContent = trim($tokens[$i]['content']); - if ($tokenContent !== '') { - return; - } - } - }//end if - - $phpcsFile->addError('Additional whitespace found at start of file', $stackPtr, 'StartFile'); - - } else if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { - - /* - Check for end of file whitespace. - */ - - if ($phpcsFile->tokenizerType === 'JS') { - // The last token is always the close tag inserted when tokenized - // and the second last token is always the last piece of content in - // the file. If the second last token is whitespace, there was - // whitespace at the end of the file. - $stackPtr--; - } else if ($phpcsFile->tokenizerType === 'CSS') { - // The last two tokens are always the close tag and whitespace - // inserted when tokenizsed and the third last token is always the - // last piece of content in the file. If the third last token is - // whitespace, there was whitespace at the end of the file. - $stackPtr -= 2; - } - - if ($phpcsFile->tokenizerType === 'PHP') { - if (isset($tokens[($stackPtr + 1)]) === false) { - // The close PHP token is the last in the file. - return; - } - - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - // If we find something that isn't inline html then there - // is more to the file. - if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { - return; - } - - // If we have ended up with inline html make sure it - // isn't just whitespace. - $tokenContent = trim($tokens[$i]['content']); - if (empty($tokenContent) === false) { - return; - } - } - } else { - // The pointer is now looking at the last content in the file and - // not the fake PHP end tag the tokenizer inserted. - if ($tokens[$stackPtr]['code'] !== T_WHITESPACE) { - return; - } - - // Allow a single newline at the end of the last line in the file. - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE - && $tokens[$stackPtr]['content'] === $phpcsFile->eolChar - ) { - return; - } - - } - - $phpcsFile->addError('Additional whitespace found at end of file', $stackPtr, 'EndFile'); - - } else { - - /* - Check for end of line whitespace. - */ - - // Ignore whitespace that is not at the end of a line. - if (strpos($tokens[$stackPtr]['content'], $phpcsFile->eolChar) === false) { - return; - } - - // Ignore blank lines if required. - if ($this->ignoreBlankLines === true - && $tokens[($stackPtr - 1)]['line'] !== $tokens[$stackPtr]['line'] - ) { - return; - } - - $tokenContent = rtrim($tokens[$stackPtr]['content'], $phpcsFile->eolChar); - if (empty($tokenContent) === false) { - if (preg_match('|^.*\s+$|', $tokenContent) !== 0) { - $phpcsFile->addError('Whitespace found at end of line', $stackPtr, 'EndLine'); - } - } - - /* - Check for multiple blanks lines in a function. - */ - - if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { - if ($tokens[($stackPtr - 1)]['line'] < $tokens[$stackPtr]['line'] && $tokens[($stackPtr - 2)]['line'] === $tokens[($stackPtr - 1)]['line']) { - // This is an empty line and the line before this one is not - // empty, so this could be the start of a multiple empty - // line block. - $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr, null, true); - $lines = $tokens[$next]['line'] - $tokens[$stackPtr]['line']; - if ($lines > 1) { - $error = 'Functions must not contain multiple empty lines in a row; found %s empty lines'; - $data = array($lines); - $phpcsFile->addError($error, $stackPtr, 'EmptyLines', $data); - } - } - } - - }//end if - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml b/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml deleted file mode 100644 index d8f2dbd4c..000000000 --- a/codesniffer/CodeSniffer/Standards/Squiz/ruleset.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - The Squiz coding standard. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %2$s - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml deleted file mode 100644 index c462b4f8b..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Docs/Debug/CodeAnalyzerStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - $bar + $baz; -} - ]]> - - - $bar + 2; -} - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml deleted file mode 100644 index aa60b8ab9..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Docs/Files/ClosingTagStandard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - ?> - ]]> - - - diff --git a/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml b/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml deleted file mode 100644 index 5bcde4b84..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Docs/NamingConventions/ValidVariableNameStandard.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - $testNumber = 1; - ]]> - - - $Test_Number = 1; - ]]> - - - - - _bar; -} - ]]> - - - - - - diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php deleted file mode 100644 index 293aecab2..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php +++ /dev/null @@ -1,125 +0,0 @@ - - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Zend_Sniffs_Debug_CodeAnalyzerSniff. - * - * Runs the Zend Code Analyzer (from Zend Studio) on the file. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Holger Kral - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Zend_Sniffs_Debug_CodeAnalyzerSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns the token types that this sniff is interested in. - * - * @return array(int) - */ - public function register() - { - return array(T_OPEN_TAG); - - }//end register() - - - /** - * Processes the tokens that this sniff is interested in. - * - * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. - * @param int $stackPtr The position in the stack where - * the token was found. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - // Because we are analyzing the whole file in one step, execute this method - // only on first occurrence of a T_OPEN_TAG. - $prevOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); - if ($prevOpenTag !== false) { - return; - } - - $fileName = $phpcsFile->getFilename(); - - $analyzerPath = PHP_CodeSniffer::getConfigData('zend_ca_path'); - if (is_null($analyzerPath) === true) { - return; - } - - // In the command, 2>&1 is important because the code analyzer sends its - // findings to stderr. $output normally contains only stdout, so using 2>&1 - // will pipe even stderr to stdout. - $cmd = $analyzerPath.' '.$fileName.' 2>&1'; - - // There is the possibility to pass "--ide" as an option to the analyzer. - // This would result in an output format which would be easier to parse. - // The problem here is that no cleartext error messages are returnwd; only - // error-code-labels. So for a start we go for cleartext output. - $exitCode = exec($cmd, $output, $retval); - - // $exitCode is the last line of $output if no error occures, on error it - // is numeric. Try to handle various error conditions and provide useful - // error reporting. - if (is_numeric($exitCode) === true && $exitCode > 0) { - if (is_array($output) === true) { - $msg = join('\n', $output); - } - - throw new PHP_CodeSniffer_Exception("Failed invoking ZendCodeAnalyzer, exitcode was [$exitCode], retval was [$retval], output was [$msg]"); - } - - if (is_array($output) === true) { - $tokens = $phpcsFile->getTokens(); - - foreach ($output as $finding) { - // The first two lines of analyzer output contain - // something like this: - // > Zend Code Analyzer 1.2.2 - // > Analyzing ... - // So skip these... - $res = preg_match("/^.+\(line ([0-9]+)\):(.+)$/", $finding, $regs); - if (empty($regs) === true || $res === false) { - continue; - } - - // Find the token at the start of the line. - $lineToken = null; - foreach ($tokens as $ptr => $info) { - if ($info['line'] == $regs[1]) { - $lineToken = $ptr; - break; - } - } - - if ($lineToken !== null) { - $phpcsFile->addWarning(trim($regs[2]), $ptr, 'ExternalTool'); - } - }//end foreach - }//end if - - }//end process() - -}//end class -?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php deleted file mode 100644 index a30f106fe..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Zend_Sniffs_Files_LineEndingsSniff. - * - * Checks that the file does not end with a closing tag. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Zend_Sniffs_Files_ClosingTagSniff implements PHP_CodeSniffer_Sniff -{ - - - /** - * Returns an array of tokens this test wants to listen for. - * - * @return array - */ - public function register() - { - return array(T_CLOSE_TAG); - - }//end register() - - - /** - * Processes this sniff, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in - * the stack passed in $tokens. - * - * @return void - */ - public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $next = $phpcsFile->findNext(T_INLINE_HTML, ($stackPtr + 1), null, true); - if ($next !== false) { - return; - } - - // We've found the last closing tag in the file so the only thing - // potentially remaining is inline HTML. Now we need to figure out - // whether or not it's just a bunch of whitespace. - $content = ''; - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - $content .= $tokens[$i]['content']; - } - - // Check if the remaining inline HTML is just whitespace. - $content = trim($content); - if (empty($content) === true) { - $error = 'A closing tag is not permitted at the end of a PHP file'; - $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); - } - - }//end process() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php b/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php deleted file mode 100644 index 27928c448..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ /dev/null @@ -1,252 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) { - throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); -} - -/** - * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. - * - * Checks the naming of variables and member variables. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class Zend_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff -{ - - /** - * Tokens to ignore so that we can find a DOUBLE_COLON. - * - * @var array - */ - private $_ignore = array( - T_WHITESPACE, - T_COMMENT, - ); - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $varName = ltrim($tokens[$stackPtr]['content'], '$'); - - $phpReservedVars = array( - '_SERVER', - '_GET', - '_POST', - '_REQUEST', - '_SESSION', - '_ENV', - '_COOKIE', - '_FILES', - 'GLOBALS', - ); - - // If it's a php reserved var, then its ok. - if (in_array($varName, $phpReservedVars) === true) { - return; - } - - $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); - if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { - // Check to see if we are using a variable from an object. - $var = $phpcsFile->findNext(array(T_WHITESPACE), ($objOperator + 1), null, true); - if ($tokens[$var]['code'] === T_STRING) { - // Either a var name or a function call, so check for bracket. - $bracket = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); - - if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { - $objVarName = $tokens[$var]['content']; - - // There is no way for us to know if the var is public or private, - // so we have to ignore a leading underscore if there is one and just - // check the main part of the variable name. - $originalVarName = $objVarName; - if (substr($objVarName, 0, 1) === '_') { - $objVarName = substr($objVarName, 1); - } - - if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); - } else if (preg_match('|\d|', $objVarName)) { - $warning = 'Variable "%s" contains numbers but this is discouraged'; - $data = array($originalVarName); - $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); - } - }//end if - }//end if - }//end if - - // There is no way for us to know if the var is public or private, - // so we have to ignore a leading underscore if there is one and just - // check the main part of the variable name. - $originalVarName = $varName; - if (substr($varName, 0, 1) === '_') { - $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); - if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { - // The variable lives within a class, and is referenced like - // this: MyClass::$_variable, so we don't know its scope. - $inClass = true; - } else { - $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)); - } - - if ($inClass === true) { - $varName = substr($varName, 1); - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); - } else if (preg_match('|\d|', $varName)) { - $warning = 'Variable "%s" contains numbers but this is discouraged'; - $data = array($originalVarName); - $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); - } - - }//end processVariable() - - - /** - * Processes class member variables. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the - * stack passed in $tokens. - * - * @return void - */ - protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $varName = ltrim($tokens[$stackPtr]['content'], '$'); - $memberProps = $phpcsFile->getMemberProperties($stackPtr); - $public = ($memberProps['scope'] === 'public'); - - if ($public === true) { - if (substr($varName, 0, 1) === '_') { - $error = 'Public member variable "%s" must not contain a leading underscore'; - $data = array($varName); - $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); - return; - } - } else { - if (substr($varName, 0, 1) !== '_') { - $scope = ucfirst($memberProps['scope']); - $error = '%s member variable "%s" must contain a leading underscore'; - $data = array( - $scope, - $varName, - ); - $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); - return; - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($varName); - $phpcsFile->addError($error, $stackPtr, 'MemberVarNotCamelCaps', $data); - } else if (preg_match('|\d|', $varName)) { - $warning = 'Variable "%s" contains numbers but this is discouraged'; - $data = array($varName); - $phpcsFile->addWarning($warning, $stackPtr, 'MemberVarContainsNumbers', $data); - } - - }//end processMemberVar() - - - /** - * Processes the variable found within a double quoted string. - * - * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the double quoted - * string. - * - * @return void - */ - protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - $phpReservedVars = array( - '_SERVER', - '_GET', - '_POST', - '_REQUEST', - '_SESSION', - '_ENV', - '_COOKIE', - '_FILES', - 'GLOBALS', - ); - - if (preg_match_all('|[^\\\]\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { - foreach ($matches[1] as $varName) { - // If it's a php reserved var, then its ok. - if (in_array($varName, $phpReservedVars) === true) { - continue; - } - - // There is no way for us to know if the var is public or private, - // so we have to ignore a leading underscore if there is one and just - // check the main part of the variable name. - $originalVarName = $varName; - if (substr($varName, 0, 1) === '_') { - if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { - $varName = substr($varName, 1); - } - } - - if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { - $varName = $matches[0]; - $error = 'Variable "%s" is not in valid camel caps format'; - $data = array($originalVarName); - $phpcsFile->addError($error, $stackPtr, 'StringVarNotCamelCaps', $data); - } else if (preg_match('|\d|', $varName)) { - $warning = 'Variable "%s" contains numbers but this is discouraged'; - $data = array($originalVarName); - $phpcsFile->addWarning($warning, $stackPtr, 'StringVarContainsNumbers', $data); - } - } - }//end if - - }//end processVariableInString() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml b/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml deleted file mode 100644 index d3031512b..000000000 --- a/codesniffer/CodeSniffer/Standards/Zend/ruleset.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - A coding standard based on an early Zend Framework coding standard. Note that this standard is out of date. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/codesniffer/CodeSniffer/Tokenizers/CSS.php b/codesniffer/CodeSniffer/Tokenizers/CSS.php deleted file mode 100644 index bbc5c048b..000000000 --- a/codesniffer/CodeSniffer/Tokenizers/CSS.php +++ /dev/null @@ -1,399 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (class_exists('PHP_CodeSniffer_Tokenizers_PHP', true) === false) { - throw new Exception('Class PHP_CodeSniffer_Tokenizers_PHP not found'); -} - -/** - * Tokenizes CSS code. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Tokenizers_CSS extends PHP_CodeSniffer_Tokenizers_PHP -{ - - - /** - * Creates an array of tokens when given some CSS code. - * - * Uses the PHP tokenizer to do all the tricky work - * - * @param string $string The string to tokenize. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return array - */ - public function tokenizeString($string, $eolChar='\n') - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START CSS TOKENIZING ***".PHP_EOL; - } - - // If the content doesn't have an EOl char on the end, add one so - // the open and close tags we add are parsed correctly. - if (substr($string, 0, (strlen($eolChar) * -1)) !== $eolChar) { - $string .= $eolChar; - } - - $tokens = parent::tokenizeString('', $eolChar); - $finalTokens = array(); - - $newStackPtr = 0; - $numTokens = count($tokens); - $multiLineComment = false; - for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { - $token = $tokens[$stackPtr]; - - // CSS files don't have lists or break tags, so convert these to - // standard strings early so they can be converted into T_STYLE - // tokens and joined with other strings if needed. - if ($token['code'] === T_BREAK || $token['code'] === T_LIST) { - $token['type'] = 'T_STRING'; - $token['code'] = T_STRING; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $token['type']; - $content = str_replace($eolChar, '\n', $token['content']); - echo "\tProcess token $stackPtr: $type => $content".PHP_EOL; - } - - // Sometimes, there are PHP tags embedded in the code, which causes issues - // with how PHP tokenizeses the string. After the first closing tag is found, - // everything outside PHP tags is set as inline HTML tokens (1 for each line). - // So we need to go through and find these tokens so we can re-tokenize them. - if ($token['code'] === T_CLOSE_TAG && $stackPtr !== ($numTokens - 1)) { - $content = ''; - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t=> Found premature closing tag at $stackPtr".PHP_EOL; - $cleanContent = str_replace($eolChar, '\n', $content); - echo "\t\tcontent: $cleanContent".PHP_EOL; - $oldNumTokens = $numTokens; - } - - // Tokenize the string and remove the extra PHP tags we don't need. - $moreTokens = parent::tokenizeString($content, $eolChar); - array_shift($moreTokens); - array_pop($moreTokens); - array_pop($moreTokens); - - // Rebuild the tokens array. - array_splice($tokens, ($stackPtr + 1), ($x - $stackPtr), $moreTokens); - $numTokens = count($tokens); - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $count = count($moreTokens); - $diff = ($x - $stackPtr); - echo "\t\t* added $count tokens, replaced $diff; size changed from $oldNumTokens to $numTokens *".PHP_EOL; - } - }//end if - - if ($token['code'] === T_GOTO_LABEL) { - // Convert these back to T_STRING folowed by T_COLON so we can - // more easily process style definitions. - $finalTokens[$newStackPtr] = array( - 'type' => 'T_STRING', - 'code' => T_STRING, - 'content' => substr($token['content'], 0, -1), - ); - $newStackPtr++; - $finalTokens[$newStackPtr] = array( - 'type' => 'T_COLON', - 'code' => T_COLON, - 'content' => ':', - ); - $newStackPtr++; - continue; - } - - if ($token['code'] === T_FUNCTION) { - // There are no functions in CSS, so convert this to a string. - $finalTokens[$newStackPtr] = array( - 'type' => 'T_STRING', - 'code' => T_STRING, - 'content' => $token['content'], - ); - - $newStackPtr++; - continue; - } - - if ($token['code'] === T_COMMENT - && substr($token['content'], 0, 2) === '/*' - ) { - // Multi-line comment. Record it so we can ignore other - // comment tags until we get out of this one. - $multiLineComment = true; - } - - if ($token['code'] === T_COMMENT - && $multiLineComment === false - && (substr($token['content'], 0, 2) === '//' - || $token['content']{0} === '#') - ) { - $content = ltrim($token['content'], '#/'); - $commentTokens - = parent::tokenizeString('', $eolChar); - - // The first and last tokens are the open/close tags. - array_shift($commentTokens); - array_pop($commentTokens); - - if ($token['content']{0} === '#') { - // The # character is not a comment in CSS files, so - // determine what it means in this context. - $firstContent = $commentTokens[0]['content']; - - // If the first content is just a number, it is probably a - // colour like 8FB7DB, which PHP splits into 8 and FB7DB. - if (($commentTokens[0]['code'] === T_LNUMBER - || $commentTokens[0]['code'] === T_DNUMBER) - && $commentTokens[1]['code'] === T_STRING - ) { - $firstContent .= $commentTokens[1]['content']; - array_shift($commentTokens); - } - - // If the first content looks like a colour and not a class - // definition, join the tokens together. - if (preg_match('/^[ABCDEF0-9]+$/i', $firstContent) === 1 - && $commentTokens[1]['content'] !== '-' - ) { - array_shift($commentTokens); - // Work out what we trimmed off above and remember to re-add it. - $trimmed = substr($token['content'], 0, (strlen($token['content']) - strlen($content))); - $finalTokens[$newStackPtr] = array( - 'type' => 'T_COLOUR', - 'code' => T_COLOUR, - 'content' => $trimmed.$firstContent, - ); - } else { - $finalTokens[$newStackPtr] = array( - 'type' => 'T_HASH', - 'code' => T_HASH, - 'content' => '#', - ); - } - } else { - $finalTokens[$newStackPtr] = array( - 'type' => 'T_STRING', - 'code' => T_STRING, - 'content' => '//', - ); - }//end if - - $newStackPtr++; - - foreach ($commentTokens as $tokenData) { - if ($tokenData['code'] === T_COMMENT - && (substr($tokenData['content'], 0, 2) === '//' - || $tokenData['content']{0} === '#') - ) { - // This is a comment in a comment, so it needs - // to go through the whole process again. - $tokens[$stackPtr]['content'] = $tokenData['content']; - $stackPtr--; - break; - } - - $finalTokens[$newStackPtr] = $tokenData; - $newStackPtr++; - } - - continue; - }//end if - - if ($token['code'] === T_COMMENT - && substr($token['content'], -2) === '*/' - ) { - // Multi-line comment is done. - $multiLineComment = false; - } - - $finalTokens[$newStackPtr] = $token; - $newStackPtr++; - }//end for - - // A flag to indicate if we are inside a style definition, - // which is defined using curly braces. I'm assuming you can't - // have nested curly brackets. - $inStyleDef = false; - - $numTokens = count($finalTokens); - for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { - $token = $finalTokens[$stackPtr]; - - switch ($token['code']) { - case T_OPEN_CURLY_BRACKET: - $inStyleDef = true; - break; - case T_CLOSE_CURLY_BRACKET: - $inStyleDef = false; - break; - case T_MINUS: - // Minus signs are often used instead of spaces inside - // class names, IDs and styles. - if ($finalTokens[($stackPtr + 1)]['code'] === T_STRING) { - if ($finalTokens[($stackPtr - 1)]['code'] === T_STRING) { - $newContent = $finalTokens[($stackPtr - 1)]['content'].'-'.$finalTokens[($stackPtr + 1)]['content']; - - $finalTokens[($stackPtr - 1)]['content'] = $newContent; - unset($finalTokens[$stackPtr]); - unset($finalTokens[($stackPtr + 1)]); - $stackPtr -= 2; - } else { - $newContent = '-'.$finalTokens[($stackPtr + 1)]['content']; - - $finalTokens[($stackPtr + 1)]['content'] = $newContent; - unset($finalTokens[$stackPtr]); - $stackPtr--; - } - - $finalTokens = array_values($finalTokens); - $numTokens = count($finalTokens); - } else if ($finalTokens[($stackPtr + 1)]['code'] === T_LNUMBER) { - // They can also be used to provide negative numbers. - $finalTokens[($stackPtr + 1)]['content'] - = '-'.$finalTokens[($stackPtr + 1)]['content']; - unset($finalTokens[$stackPtr]); - - $finalTokens = array_values($finalTokens); - $numTokens = count($finalTokens); - } - - break; - case T_COLON: - // Only interested in colons that are defining styles. - if ($inStyleDef === false) { - break; - } - - for ($x = ($stackPtr - 1); $x >= 0; $x--) { - if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - $finalTokens[$x]['type'] = 'T_STYLE'; - $finalTokens[$x]['code'] = T_STYLE; - break; - case T_STRING: - if (strtolower($token['content']) === 'url') { - // Find the next content. - for ($x = ($stackPtr + 1); $x < $numTokens; $x++) { - if (in_array($finalTokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - // Needs to be in the format "url(" for it to be a URL. - if ($finalTokens[$x]['code'] !== T_OPEN_PARENTHESIS) { - continue; - } - - // Make sure the content isn't empty. - for ($y = ($x + 1); $y < $numTokens; $y++) { - if (in_array($finalTokens[$y]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($finalTokens[$y]['code'] === T_CLOSE_PARENTHESIS) { - continue; - } - - // Join all the content together inside the url() statement. - $newContent = ''; - for ($i = ($x + 2); $i < $numTokens; $i++) { - if ($finalTokens[$i]['code'] === T_CLOSE_PARENTHESIS) { - break; - } - - $newContent .= $finalTokens[$i]['content']; - unset($finalTokens[$i]); - } - - // If the content inside the "url()" is in double quotes - // there will only be one token and so we don't have to do - // anything except change its type. If it is not empty, - // we need to do some token merging. - $finalTokens[($x + 1)]['type'] = 'T_URL'; - $finalTokens[($x + 1)]['code'] = T_URL; - - if ($newContent !== '') { - $finalTokens[($x + 1)]['content'] .= $newContent; - - $finalTokens = array_values($finalTokens); - $numTokens = count($finalTokens); - } - }//end if - - break; - default: - // Nothing special to be done with this token. - break; - }//end switch - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END CSS TOKENIZING ***".PHP_EOL; - } - - return $finalTokens; - - }//end tokenizeString() - - - /** - * Performs additional processing after main tokenizing. - * - * @param array &$tokens The array of tokens to process. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - public function processAdditional(&$tokens, $eolChar) - { - // We override this method because we don't want the PHP version to - // run during CSS processing because it is wasted processing time. - - }//end processAdditional() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Tokenizers/JS.php b/codesniffer/CodeSniffer/Tokenizers/JS.php deleted file mode 100644 index 8a6ade6d2..000000000 --- a/codesniffer/CodeSniffer/Tokenizers/JS.php +++ /dev/null @@ -1,1149 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Tokenizes JS code. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Tokenizers_JS -{ - - /** - * A list of tokens that are allowed to open a scope. - * - * This array also contains information about what kind of token the scope - * opener uses to open and close the scope, if the token strictly requires - * an opener, if the token can share a scope closer, and who it can be shared - * with. An example of a token that shares a scope closer is a CASE scope. - * - * @var array - */ - public $scopeOpeners = array( - T_IF => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_TRY => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_CATCH => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_ELSE => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_FOR => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_FUNCTION => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_WHILE => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_DO => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_SWITCH => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_CASE => array( - 'start' => array(T_COLON), - 'end' => array( - T_BREAK, - T_RETURN, - T_CONTINUE, - T_THROW, - ), - 'strict' => true, - 'shared' => true, - 'with' => array( - T_DEFAULT, - T_CASE, - T_SWITCH, - ), - ), - T_DEFAULT => array( - 'start' => array(T_COLON), - 'end' => array( - T_BREAK, - T_RETURN, - T_CONTINUE, - T_THROW, - ), - 'strict' => true, - 'shared' => true, - 'with' => array( - T_CASE, - T_SWITCH, - ), - ), - ); - - /** - * A list of tokens that end the scope. - * - * This array is just a unique collection of the end tokens - * from the _scopeOpeners array. The data is duplicated here to - * save time during parsing of the file. - * - * @var array - */ - public $endScopeTokens = array( - T_CLOSE_CURLY_BRACKET, - T_BREAK, - ); - - /** - * A list of special JS tokens and their types. - * - * @var array - */ - protected $tokenValues = array( - 'function' => 'T_FUNCTION', - 'prototype' => 'T_PROTOTYPE', - 'try' => 'T_TRY', - 'catch' => 'T_CATCH', - 'return' => 'T_RETURN', - 'throw' => 'T_THROW', - 'break' => 'T_BREAK', - 'switch' => 'T_SWITCH', - 'continue' => 'T_CONTINUE', - 'if' => 'T_IF', - 'else' => 'T_ELSE', - 'do' => 'T_DO', - 'while' => 'T_WHILE', - 'for' => 'T_FOR', - 'var' => 'T_VAR', - 'case' => 'T_CASE', - 'default' => 'T_DEFAULT', - 'true' => 'T_TRUE', - 'false' => 'T_FALSE', - 'null' => 'T_NULL', - 'this' => 'T_THIS', - 'typeof' => 'T_TYPEOF', - '(' => 'T_OPEN_PARENTHESIS', - ')' => 'T_CLOSE_PARENTHESIS', - '{' => 'T_OPEN_CURLY_BRACKET', - '}' => 'T_CLOSE_CURLY_BRACKET', - '[' => 'T_OPEN_SQUARE_BRACKET', - ']' => 'T_CLOSE_SQUARE_BRACKET', - '?' => 'T_INLINE_THEN', - '.' => 'T_OBJECT_OPERATOR', - '+' => 'T_PLUS', - '-' => 'T_MINUS', - '*' => 'T_MULTIPLY', - '%' => 'T_MODULUS', - '/' => 'T_DIVIDE', - '^' => 'T_POWER', - ',' => 'T_COMMA', - ';' => 'T_SEMICOLON', - ':' => 'T_COLON', - '<' => 'T_LESS_THAN', - '>' => 'T_GREATER_THAN', - '<=' => 'T_IS_SMALLER_OR_EQUAL', - '>=' => 'T_IS_GREATER_OR_EQUAL', - '!' => 'T_BOOLEAN_NOT', - '||' => 'T_BOOLEAN_OR', - '&&' => 'T_BOOLEAN_AND', - '|' => 'T_BITWISE_OR', - '&' => 'T_BITWISE_AND', - '!=' => 'T_IS_NOT_EQUAL', - '!==' => 'T_IS_NOT_IDENTICAL', - '=' => 'T_EQUAL', - '==' => 'T_IS_EQUAL', - '===' => 'T_IS_IDENTICAL', - '-=' => 'T_MINUS_EQUAL', - '+=' => 'T_PLUS_EQUAL', - '*=' => 'T_MUL_EQUAL', - '/=' => 'T_DIV_EQUAL', - '%=' => 'T_MOD_EQUAL', - '++' => 'T_INC', - '--' => 'T_DEC', - '//' => 'T_COMMENT', - '/*' => 'T_COMMENT', - '/**' => 'T_DOC_COMMENT', - '*/' => 'T_COMMENT', - ); - - /** - * A list string delimiters. - * - * @var array - */ - protected $stringTokens = array( - '\'', - '"', - ); - - /** - * A list tokens that start and end comments. - * - * @var array - */ - protected $commentTokens = array( - '//' => null, - '/*' => '*/', - '/**' => '*/', - ); - - - /** - * Creates an array of tokens when given some PHP code. - * - * Starts by using token_get_all() but does a lot of extra processing - * to insert information about the context of the token. - * - * @param string $string The string to tokenize. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return array - */ - public function tokenizeString($string, $eolChar='\n') - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START JS TOKENIZING ***".PHP_EOL; - } - - $tokenTypes = array_keys($this->tokenValues); - - $maxTokenLength = 0; - foreach ($tokenTypes as $token) { - if (strlen($token) > $maxTokenLength) { - $maxTokenLength = strlen($token); - } - } - - $tokens = array(); - $inString = ''; - $stringChar = null; - $inComment = ''; - $buffer = ''; - $preStringBuffer = ''; - $cleanBuffer = false; - - $tokens[] = array( - 'code' => T_OPEN_TAG, - 'type' => 'T_OPEN_TAG', - 'content' => '', - ); - - // Convert newlines to single characters for ease of - // processing. We will change them back later. - $string = str_replace($eolChar, "\n", $string); - - $chars = str_split($string); - $numChars = count($chars); - for ($i = 0; $i < $numChars; $i++) { - $char = $chars[$i]; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $char); - $bufferContent = str_replace("\n", '\n', $buffer); - if ($inString !== '') { - echo "\t"; - } - - if ($inComment !== '') { - echo "\t"; - } - - echo "\tProcess char $i => $content (buffer: $bufferContent)".PHP_EOL; - } - - if ($inString === '' && $inComment === '' && $buffer !== '') { - // If the buffer only has whitespace and we are about to - // add a character, store the whitespace first. - if (trim($char) !== '' && trim($buffer) === '') { - $tokens[] = array( - 'code' => T_WHITESPACE, - 'type' => 'T_WHITESPACE', - 'content' => str_replace("\n", $eolChar, $buffer), - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $buffer); - echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL; - } - - $buffer = ''; - } - - // If the buffer is not whitespace and we are about to - // add a whitespace character, store the content first. - if ($inString === '' - && $inComment === '' - && trim($char) === '' - && trim($buffer) !== '' - ) { - $tokens[] = array( - 'code' => T_STRING, - 'type' => 'T_STRING', - 'content' => str_replace("\n", $eolChar, $buffer), - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $buffer); - echo "\t=> Added token T_STRING ($content)".PHP_EOL; - } - - $buffer = ''; - } - }//end if - - // Process strings. - if ($inComment === '' && in_array($char, $this->stringTokens) === true) { - if ($inString === $char) { - // This could be the end of the string, but make sure it - // is not escaped first. - $escapes = 0; - for ($x = ($i - 1); $x >= 0; $x--) { - if ($chars[$x] !== '\\') { - break; - } - - $escapes++; - } - - if ($escapes === 0 || ($escapes % 2) === 0) { - // There is an even number escape chars, - // so this is not escaped, it is the end of the string. - $tokens[] = array( - 'code' => T_CONSTANT_ENCAPSED_STRING, - 'type' => 'T_CONSTANT_ENCAPSED_STRING', - 'content' => str_replace("\n", $eolChar, $buffer).$char, - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* found end of string *".PHP_EOL; - $content = str_replace("\n", '\n', $buffer.$char); - echo "\t=> Added token T_CONSTANT_ENCAPSED_STRING ($content)".PHP_EOL; - } - - $buffer = ''; - $preStringBuffer = ''; - $inString = ''; - $stringChar = null; - continue; - } - } else if ($inString === '') { - $inString = $char; - $stringChar = $i; - $preStringBuffer = $buffer; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* looking for string closer *".PHP_EOL; - } - }//end if - }//end if - - if ($inString !== '' && $char === "\n") { - // Unless this newline character is escaped, the string did not - // end before the end of the line, which means it probably - // wasn't a string at all (maybe a regex). - if ($chars[($i - 1)] !== '\\') { - $i = $stringChar; - $buffer = $preStringBuffer; - $preStringBuffer = ''; - $inString = ''; - $stringChar = null; - $char = $chars[$i]; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* found newline before end of string, bailing *".PHP_EOL; - } - } - } - - $buffer .= $char; - - // We don't look for special tokens inside strings, - // so if we are in a string, we can continue here now - // that the current char is in the buffer. - if ($inString !== '') { - continue; - } - - // Special case for T_DIVIDE which can actually be - // the start of a regular expression. - if ($char === '/') { - $regex = $this->getRegexToken( - $i, - $string, - $chars, - $tokens, - $eolChar - ); - - if ($regex !== null) { - $tokens[] = array( - 'code' => T_REGULAR_EXPRESSION, - 'type' => 'T_REGULAR_EXPRESSION', - 'content' => $regex['content'], - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $regex['content']); - echo "\t=> Added token T_REGULAR_EXPRESSION ($content)".PHP_EOL; - } - - $i = $regex['end']; - $buffer = ''; - $cleanBuffer = false; - continue; - } - }//end if - - // Check for known tokens, but ignore tokens found that are not at - // the end of a string, like FOR and this.FORmat. - if (in_array(strtolower($buffer), $tokenTypes) === true - && (preg_match('|[a-zA-z0-9_]|', $char) === 0 - || isset($chars[($i + 1)]) === false - || preg_match('|[a-zA-z0-9_]|', $chars[($i + 1)]) === 0) - ) { - $matchedToken = false; - $lookAheadLength = ($maxTokenLength - strlen($buffer)); - - if ($lookAheadLength > 0) { - // The buffer contains a token type, but we need - // to look ahead at the next chars to see if this is - // actually part of a larger token. For example, - // FOR and FOREACH. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* buffer possibly contains token, looking ahead $lookAheadLength chars *".PHP_EOL; - } - - $charBuffer = $buffer; - for ($x = 1; $x <= $lookAheadLength; $x++) { - if (isset($chars[($i + $x)]) === false) { - break; - } - - $charBuffer .= $chars[($i + $x)]; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $charBuffer); - echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL; - } - - if (in_array(strtolower($charBuffer), $tokenTypes) === true) { - // We've found something larger that matches - // so we can ignore this char. Except for 1 very specific - // case where a comment like /**/ needs to tokenize as - // T_COMMENT and not T_DOC_COMMENT. - $oldType = $this->tokenValues[strtolower($buffer)]; - $newType = $this->tokenValues[strtolower($charBuffer)]; - if ($oldType === 'T_COMMENT' - && $newType === 'T_DOC_COMMENT' - && $chars[($i + $x + 1)] === '/' - ) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* look ahead ignored T_DOC_COMMENT, continuing *".PHP_EOL; - } - } else { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* look ahead found more specific token ($newType), ignoring $i *".PHP_EOL; - } - - $matchedToken = true; - break; - } - } - }//end for - }//end if - - if ($matchedToken === false) { - if (PHP_CODESNIFFER_VERBOSITY > 1 && $lookAheadLength > 0) { - echo "\t\t* look ahead found nothing *".PHP_EOL; - } - - $value = $this->tokenValues[strtolower($buffer)]; - $tokens[] = array( - 'code' => constant($value), - 'type' => $value, - 'content' => $buffer, - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $buffer); - echo "\t=> Added token $value ($content)".PHP_EOL; - } - - $cleanBuffer = true; - }//end if - } else if (in_array(strtolower($char), $tokenTypes) === true) { - // No matter what token we end up using, we don't - // need the content in the buffer any more because we have - // found a valid token. - $newContent = substr(str_replace("\n", $eolChar, $buffer), 0, -1); - if ($newContent !== '') { - $tokens[] = array( - 'code' => T_STRING, - 'type' => 'T_STRING', - 'content' => $newContent, - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', substr($buffer, 0, -1)); - echo "\t=> Added token T_STRING ($content)".PHP_EOL; - } - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* char is token, looking ahead ".($maxTokenLength - 1).' chars *'.PHP_EOL; - } - - // The char is a token type, but we need to look ahead at the - // next chars to see if this is actually part of a larger token. - // For example, = and ===. - $charBuffer = $char; - $matchedToken = false; - for ($x = 1; $x <= $maxTokenLength; $x++) { - if (isset($chars[($i + $x)]) === false) { - break; - } - - $charBuffer .= $chars[($i + $x)]; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $charBuffer); - echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL; - } - - if (in_array(strtolower($charBuffer), $tokenTypes) === true) { - // We've found something larger that matches - // so we can ignore this char. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $this->tokenValues[strtolower($charBuffer)]; - echo "\t\t* look ahead found more specific token ($type), ignoring $i *".PHP_EOL; - } - - $matchedToken = true; - break; - } - }//end for - - if ($matchedToken === false) { - $value = $this->tokenValues[strtolower($char)]; - $tokens[] = array( - 'code' => constant($value), - 'type' => $value, - 'content' => $char, - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* look ahead found nothing *".PHP_EOL; - $content = str_replace("\n", '\n', $char); - echo "\t=> Added token $value ($content)".PHP_EOL; - } - - $cleanBuffer = true; - } else { - $buffer = $char; - } - }//end if - - // Keep track of content inside comments. - if ($inComment === '' - && array_key_exists($buffer, $this->commentTokens) === true - ) { - // This is not really a comment if the content - // looks like \// (i.e., it is escaped). - if (isset($chars[($i - 2)]) === true && $chars[($i - 2)] === '\\') { - $lastToken = array_pop($tokens); - $lastContent = $lastToken['content']; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $value = $this->tokenValues[strtolower($lastContent)]; - $content = str_replace("\n", '\n', $lastContent); - echo "\t=> Removed token $value ($content)".PHP_EOL; - } - - $lastChars = str_split($lastContent); - $lastNumChars = count($lastChars); - for ($x = 0; $x < $lastNumChars; $x++) { - $lastChar = $lastChars[$x]; - $value = $this->tokenValues[strtolower($lastChar)]; - $tokens[] = array( - 'code' => constant($value), - 'type' => $value, - 'content' => $lastChar, - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $lastChar); - echo "\t=> Added token $value ($content)".PHP_EOL; - } - } - } else { - // We have started a comment. - $inComment = $buffer; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t\t* looking for end of comment *".PHP_EOL; - } - } - } else if ($inComment !== '') { - if ($this->commentTokens[$inComment] === null) { - // Comment ends at the next newline. - if (strpos($buffer, "\n") !== false) { - $inComment = ''; - } - } else { - if ($this->commentTokens[$inComment] === $buffer) { - $inComment = ''; - } - } - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - if ($inComment === '') { - echo "\t\t* found end of comment *".PHP_EOL; - } - } - - if ($inComment === '' && $cleanBuffer === false) { - $tokens[] = array( - 'code' => T_STRING, - 'type' => 'T_STRING', - 'content' => str_replace("\n", $eolChar, $buffer), - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $buffer); - echo "\t=> Added token T_STRING ($content)".PHP_EOL; - } - - $buffer = ''; - } - }//end if - - if ($cleanBuffer === true) { - $buffer = ''; - $cleanBuffer = false; - } - }//end foreach - - if (empty($buffer) === false) { - // Buffer contains whitespace from the end of the file. - $tokens[] = array( - 'code' => T_WHITESPACE, - 'type' => 'T_WHITESPACE', - 'content' => str_replace("\n", $eolChar, $buffer), - ); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace($eolChar, '\n', $buffer); - echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL; - } - } - - $tokens[] = array( - 'code' => T_CLOSE_TAG, - 'type' => 'T_CLOSE_TAG', - 'content' => '', - ); - - /* - Now that we have done some basic tokenizing, we need to - modify the tokens to join some together and split some apart - so they match what the PHP tokenizer does. - */ - - $finalTokens = array(); - $newStackPtr = 0; - $numTokens = count($tokens); - for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { - $token = $tokens[$stackPtr]; - - /* - Look for comments and join the tokens together. - */ - - if (array_key_exists($token['content'], $this->commentTokens) === true) { - $newContent = ''; - $tokenContent = $token['content']; - $endContent = $this->commentTokens[$tokenContent]; - while ($tokenContent !== $endContent) { - if ($endContent === null - && strpos($tokenContent, $eolChar) !== false - ) { - // A null end token means the comment ends at the end of - // the line so we look for newlines and split the token. - $tokens[$stackPtr]['content'] = substr( - $tokenContent, - (strpos($tokenContent, $eolChar) + strlen($eolChar)) - ); - - $tokenContent = substr( - $tokenContent, - 0, - (strpos($tokenContent, $eolChar) + strlen($eolChar)) - ); - - // If the substr failed, skip the token as the content - // will now be blank. - if ($tokens[$stackPtr]['content'] !== false) { - $stackPtr--; - } - - break; - }//end if - - $stackPtr++; - $newContent .= $tokenContent; - if (isset($tokens[$stackPtr]) === false) { - break; - } - - $tokenContent = $tokens[$stackPtr]['content']; - }//end while - - // Save the new content in the current token so - // the code below can chop it up on newlines. - $token['content'] = $newContent.$tokenContent; - }//end if - - /* - If this token has newlines in its content, split each line up - and create a new token for each line. We do this so it's easier - to ascertain where errors occur on a line. - Note that $token[1] is the token's content. - */ - - if (strpos($token['content'], $eolChar) !== false) { - $tokenLines = explode($eolChar, $token['content']); - $numLines = count($tokenLines); - - for ($i = 0; $i < $numLines; $i++) { - $newToken['content'] = $tokenLines[$i]; - if ($i === ($numLines - 1)) { - if ($tokenLines[$i] === '') { - break; - } - } else { - $newToken['content'] .= $eolChar; - } - - $newToken['type'] = $token['type']; - $newToken['code'] = $token['code']; - $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - } - } else { - $finalTokens[$newStackPtr] = $token; - $newStackPtr++; - }//end if - - // Convert numbers, including decimals. - if ($token['code'] === T_STRING - || $token['code'] === T_OBJECT_OPERATOR - ) { - $newContent = ''; - $oldStackPtr = $stackPtr; - while (preg_match('|^[0-9\.]+$|', $tokens[$stackPtr]['content']) !== 0) { - $newContent .= $tokens[$stackPtr]['content']; - $stackPtr++; - } - - if ($newContent !== '' && $newContent !== '.') { - $finalTokens[($newStackPtr - 1)]['content'] = $newContent; - if (ctype_digit($newContent) === true) { - $finalTokens[($newStackPtr - 1)]['code'] - = constant('T_LNUMBER'); - $finalTokens[($newStackPtr - 1)]['type'] = 'T_LNUMBER'; - } else { - $finalTokens[($newStackPtr - 1)]['code'] - = constant('T_DNUMBER'); - $finalTokens[($newStackPtr - 1)]['type'] = 'T_DNUMBER'; - } - - $stackPtr--; - } else { - $stackPtr = $oldStackPtr; - } - }//end if - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END TOKENIZING ***".PHP_EOL; - } - - return $finalTokens; - - }//end tokenizeString() - - - /** - * Tokenizes a regular expression if one is found. - * - * If a regular expression is not found, NULL is returned. - * - * @param string $char The index of the possible regex start character. - * @param string $string The complete content of the string being tokenized. - * @param string $chars An array of characters being tokenized. - * @param string $tokens The current array of tokens found in the string. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - public function getRegexToken($char, $string, $chars, $tokens, $eolChar) - { - $beforeTokens = array( - T_EQUAL, - T_OPEN_PARENTHESIS, - T_RETURN, - T_BOOLEAN_OR, - T_BOOLEAN_AND, - T_BITWISE_OR, - T_BITWISE_AND, - T_COMMA, - T_COLON, - T_TYPEOF, - ); - - $afterTokens = array( - ',', - ')', - ';', - ' ', - '.', - $eolChar, - ); - - // Find the last non-whitespace token that was added - // to the tokens array. - $numTokens = count($tokens); - for ($prev = ($numTokens - 1); $prev >= 0; $prev--) { - if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if (in_array($tokens[$prev]['code'], $beforeTokens) === false) { - return null; - } - - // This is probably a regular expression, so look for the end of it. - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = str_replace("\n", '\n', $char); - echo "\t* token possibly starts a regular expression *".PHP_EOL; - } - - $numChars = count($chars); - for ($next = ($char + 1); $next < $numChars; $next++) { - if ($chars[$next] === '/') { - // Just make sure this is not escaped first. - if ($chars[($next - 1)] !== '\\') { - // In the simple form: /.../ so we found the end. - break; - } else if ($chars[($next - 2)] === '\\') { - // In the form: /...\\/ so we found the end. - break; - } - } else { - $possibleEolChar = substr($string, $next, strlen($eolChar)); - if ($possibleEolChar === $eolChar) { - // This is the last token on the line and regular - // expressions need to be defined on a single line, - // so this is not a regular expression. - break; - } - } - } - - if ($chars[$next] !== '/') { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t* could not find end of regular expression *".PHP_EOL; - } - - return null; - } - - while (preg_match('|[a-zA-Z]|', $chars[($next + 1)]) !== 0) { - // The token directly after the end of the regex can - // be modifiers like global and case insensitive - // (.e.g, /pattern/gi). - $next++; - } - - $regexEnd = $next; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t* found end of regular expression at token $regexEnd *".PHP_EOL; - } - - for ($next = ($next + 1); $next < $numChars; $next++) { - if ($chars[$next] !== ' ') { - break; - } else { - $possibleEolChar = substr($string, $next, strlen($eolChar)); - if ($possibleEolChar === $eolChar) { - // This is the last token on the line. - break; - } - } - } - - if (in_array($chars[$next], $afterTokens) === false) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t* tokens after regular expression do not look correct *".PHP_EOL; - } - - return null; - } - - // This is a regular expression, so join all the tokens together. - $content = ''; - for ($x = $char; $x <= $regexEnd; $x++) { - $content .= $chars[$x]; - } - - $token = array( - 'start' => $char, - 'end' => $regexEnd, - 'content' => $content, - ); - - return $token; - - }//end getRegexToken() - - - /** - * Performs additional processing after main tokenizing. - * - * This additional processing looks for properties, labels and objects. - * - * @param array &$tokens The array of tokens to process. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - public function processAdditional(&$tokens, $eolChar) - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START ADDITIONAL JS PROCESSING ***".PHP_EOL; - } - - $numTokens = count($tokens); - $classStack = array(); - - for ($i = 0; $i < $numTokens; $i++) { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$i]['type']; - $content = str_replace($eolChar, '\n', $tokens[$i]['content']); - echo str_repeat("\t", count($classStack)); - - echo "\tProcess token $i: $type => $content".PHP_EOL; - } - - if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET - && isset($tokens[$i]['scope_condition']) === false - ) { - $classStack[] = $i; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t=> Found property opener".PHP_EOL; - } - - // This could also be an object definition. - for ($x = ($i - 1); $x >= 0; $x--) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - // Non-whitespace content. - break; - } - } - - if ($tokens[$x]['code'] === T_EQUAL) { - for ($x--; $x >= 0; $x--) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($tokens[$x]['code'] === T_STRING - || $tokens[$x]['code'] === T_PROTOTYPE - ) { - // Find the first string in this definition. - // E.g., WantedString.DontWantThis.prototype - for ($x--; $x >= 0; $x--) { - $wantedTokens = array( - T_STRING, - T_PROTOTYPE, - T_OBJECT_OPERATOR, - ); - - if (in_array($tokens[$x]['code'], $wantedTokens) === false) { - $x++; - break; - } - } - - $closer = $tokens[$i]['bracket_closer']; - $tokens[$i]['scope_condition'] = $x; - $tokens[$i]['scope_closer'] = $closer; - $tokens[$closer]['scope_condition'] = $x; - $tokens[$closer]['scope_opener'] = $i; - $tokens[$x]['scope_opener'] = $i; - $tokens[$x]['scope_closer'] = $closer; - $tokens[$x]['code'] = T_OBJECT; - $tokens[$x]['type'] = 'T_OBJECT'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t* token $x converted from T_STRING to T_OBJECT *".PHP_EOL; - echo str_repeat("\t", count($classStack)); - echo "\t* set scope opener ($i) and closer ($closer) for token $x *".PHP_EOL; - } - }//end if - }//end if - } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET - && (isset($tokens[$i]['scope_condition']) === false - || $tokens[$tokens[$i]['scope_condition']]['code'] === T_OBJECT) - ) { - $opener = array_pop($classStack); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t\t=> Found property closer for $opener".PHP_EOL; - } - } else if ($tokens[$i]['code'] === T_COLON) { - // If it is a scope opener, it belongs to a - // DEFAULT or CASE statement. - if (isset($tokens[$i]['scope_condition']) === true) { - continue; - } - - // Make sure this is not part of an inline IF statement. - for ($x = ($i - 1); $x >= 0; $x--) { - if ($tokens[$x]['code'] === T_INLINE_THEN) { - $tokens[$i]['code'] = T_INLINE_ELSE; - $tokens[$i]['type'] = 'T_INLINE_ELSE'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t* token $i converted from T_COLON to T_INLINE_THEN *".PHP_EOL; - } - - continue(2); - } else if ($tokens[$x]['line'] < $tokens[$i]['line']) { - break; - } - } - - // The string to the left of the colon is either a property or label. - for ($label = ($i - 1); $label >= 0; $label--) { - if (in_array($tokens[$label]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($tokens[$label]['code'] !== T_STRING) { - continue; - } - - if (empty($classStack) === false) { - $tokens[$label]['code'] = T_PROPERTY; - $tokens[$label]['type'] = 'T_PROPERTY'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t* token $label converted from T_STRING to T_PROPERTY *".PHP_EOL; - } - - // If the net token after the colon is a curly brace, - // this property is actually an object, so we can give it - // and opener and closer. - for ($x = ($i + 1); $x < $numTokens; $x++) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($tokens[$x]['code'] === T_OPEN_CURLY_BRACKET) { - $closer = $tokens[$x]['bracket_closer']; - $tokens[$label]['scope_opener'] = $x; - $tokens[$label]['scope_closer'] = $closer; - $tokens[$x]['scope_condition'] = $label; - $tokens[$x]['scope_closer'] = $closer; - $tokens[$closer]['scope_condition'] = $label; - $tokens[$closer]['scope_opener'] = $x; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t* set scope opener ($x) and closer ($closer) for token $label *".PHP_EOL; - } - } - } else { - $tokens[$label]['code'] = T_LABEL; - $tokens[$label]['type'] = 'T_LABEL'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", count($classStack)); - echo "\t* token $label converted from T_STRING to T_LABEL *".PHP_EOL; - } - } - }//end if - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END ADDITIONAL JS PROCESSING ***".PHP_EOL; - } - - }//end processAdditional() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Tokenizers/PHP.php b/codesniffer/CodeSniffer/Tokenizers/PHP.php deleted file mode 100644 index a1b9f45ce..000000000 --- a/codesniffer/CodeSniffer/Tokenizers/PHP.php +++ /dev/null @@ -1,769 +0,0 @@ - - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -/** - * Tokenizes PHP code. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_Tokenizers_PHP -{ - - /** - * A list of tokens that are allowed to open a scope. - * - * This array also contains information about what kind of token the scope - * opener uses to open and close the scope, if the token strictly requires - * an opener, if the token can share a scope closer, and who it can be shared - * with. An example of a token that shares a scope closer is a CASE scope. - * - * @var array - */ - public $scopeOpeners = array( - T_IF => array( - 'start' => array( - T_OPEN_CURLY_BRACKET, - T_COLON, - ), - 'end' => array( - T_CLOSE_CURLY_BRACKET, - T_ENDIF, - ), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_TRY => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_CATCH => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_FINALLY => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_ELSE => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_ELSEIF => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_FOR => array( - 'start' => array( - T_OPEN_CURLY_BRACKET, - T_COLON, - ), - 'end' => array( - T_CLOSE_CURLY_BRACKET, - T_ENDFOR, - ), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_FOREACH => array( - 'start' => array( - T_OPEN_CURLY_BRACKET, - T_COLON, - ), - 'end' => array( - T_CLOSE_CURLY_BRACKET, - T_ENDFOREACH, - ), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_INTERFACE => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_FUNCTION => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_CLASS => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_TRAIT => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_NAMESPACE => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_WHILE => array( - 'start' => array( - T_OPEN_CURLY_BRACKET, - T_COLON, - ), - 'end' => array( - T_CLOSE_CURLY_BRACKET, - T_ENDWHILE, - ), - 'strict' => false, - 'shared' => false, - 'with' => array(), - ), - T_DO => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_SWITCH => array( - 'start' => array(T_OPEN_CURLY_BRACKET), - 'end' => array(T_CLOSE_CURLY_BRACKET), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - T_CASE => array( - 'start' => array( - T_COLON, - T_SEMICOLON, - ), - 'end' => array( - T_BREAK, - T_RETURN, - T_CONTINUE, - T_THROW, - ), - 'strict' => true, - 'shared' => true, - 'with' => array( - T_DEFAULT, - T_CASE, - T_SWITCH, - ), - ), - T_DEFAULT => array( - 'start' => array(T_COLON), - 'end' => array( - T_BREAK, - T_RETURN, - T_CONTINUE, - T_THROW, - ), - 'strict' => true, - 'shared' => true, - 'with' => array( - T_CASE, - T_SWITCH, - ), - ), - T_START_HEREDOC => array( - 'start' => array(T_START_HEREDOC), - 'end' => array(T_END_HEREDOC), - 'strict' => true, - 'shared' => false, - 'with' => array(), - ), - ); - - /** - * A list of tokens that end the scope. - * - * This array is just a unique collection of the end tokens - * from the _scopeOpeners array. The data is duplicated here to - * save time during parsing of the file. - * - * @var array - */ - public $endScopeTokens = array( - T_CLOSE_CURLY_BRACKET, - T_BREAK, - T_END_HEREDOC, - ); - - - /** - * Creates an array of tokens when given some PHP code. - * - * Starts by using token_get_all() but does a lot of extra processing - * to insert information about the context of the token. - * - * @param string $string The string to tokenize. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return array - */ - public function tokenizeString($string, $eolChar='\n') - { - $tokens = @token_get_all($string); - $finalTokens = array(); - - $newStackPtr = 0; - $numTokens = count($tokens); - - $insideInlineIf = false; - - for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) { - $token = $tokens[$stackPtr]; - $tokenIsArray = is_array($token); - - /* - If we are using \r\n newline characters, the \r and \n are sometimes - split over two tokens. This normally occurs after comments. We need - to merge these two characters together so that our line endings are - consistent for all lines. - */ - - if ($tokenIsArray === true && substr($token[1], -1) === "\r") { - if (isset($tokens[($stackPtr + 1)]) === true - && is_array($tokens[($stackPtr + 1)]) === true - && $tokens[($stackPtr + 1)][1][0] === "\n" - ) { - $token[1] .= "\n"; - - if ($tokens[($stackPtr + 1)][1] === "\n") { - // The next token's content has been merged into this token, - // so we can skip it. - $stackPtr++; - } else { - $tokens[($stackPtr + 1)][1] - = substr($tokens[($stackPtr + 1)][1], 1); - } - } - }//end if - - /* - If this is a double quoted string, PHP will tokenise the whole - thing which causes problems with the scope map when braces are - within the string. So we need to merge the tokens together to - provide a single string. - */ - - if ($tokenIsArray === false && $token === '"') { - $tokenContent = '"'; - $nestedVars = array(); - for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { - $subTokenIsArray = is_array($tokens[$i]); - - if ($subTokenIsArray === true) { - $tokenContent .= $tokens[$i][1]; - if ($tokens[$i][1] === '{' - && $tokens[$i][0] !== T_ENCAPSED_AND_WHITESPACE - ) { - $nestedVars[] = $i; - } - } else { - $tokenContent .= $tokens[$i]; - if ($tokens[$i] === '}') { - array_pop($nestedVars); - } - } - - if ($subTokenIsArray === false - && $tokens[$i] === '"' - && empty($nestedVars) === true - ) { - // We found the other end of the double quoted string. - break; - } - } - - $stackPtr = $i; - - // Convert each line within the double quoted string to a - // new token, so it conforms with other multiple line tokens. - $tokenLines = explode($eolChar, $tokenContent); - $numLines = count($tokenLines); - $newToken = array(); - - for ($j = 0; $j < $numLines; $j++) { - $newToken['content'] = $tokenLines[$j]; - if ($j === ($numLines - 1)) { - if ($tokenLines[$j] === '') { - break; - } - } else { - $newToken['content'] .= $eolChar; - } - - $newToken['code'] = T_DOUBLE_QUOTED_STRING; - $newToken['type'] = 'T_DOUBLE_QUOTED_STRING'; - $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - } - - // Continue, as we're done with this token. - continue; - }//end if - - /* - If this is a heredoc, PHP will tokenise the whole - thing which causes problems when heredocs don't - contain real PHP code, which is almost never. - We want to leave the start and end heredoc tokens - alone though. - */ - - if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) { - // Add the start heredoc token to the final array. - $finalTokens[$newStackPtr] - = PHP_CodeSniffer::standardiseToken($token); - - // Check if this is actually a nowdoc and use a different token - // to help the sniffs. - $nowdoc = false; - if ($token[1][3] === "'") { - $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC; - $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC'; - $nowdoc = true; - } - - $newStackPtr++; - - $tokenContent = ''; - for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { - $subTokenIsArray = is_array($tokens[$i]); - if ($subTokenIsArray === true - && $tokens[$i][0] === T_END_HEREDOC - ) { - // We found the other end of the heredoc. - break; - } - - if ($subTokenIsArray === true) { - $tokenContent .= $tokens[$i][1]; - } else { - $tokenContent .= $tokens[$i]; - } - } - - $stackPtr = $i; - - // Convert each line within the heredoc to a - // new token, so it conforms with other multiple line tokens. - $tokenLines = explode($eolChar, $tokenContent); - $numLines = count($tokenLines); - $newToken = array(); - - for ($j = 0; $j < $numLines; $j++) { - $newToken['content'] = $tokenLines[$j]; - if ($j === ($numLines - 1)) { - if ($tokenLines[$j] === '') { - break; - } - } else { - $newToken['content'] .= $eolChar; - } - - if ($nowdoc === true) { - $newToken['code'] = T_NOWDOC; - $newToken['type'] = 'T_NOWDOC'; - } else { - $newToken['code'] = T_HEREDOC; - $newToken['type'] = 'T_HEREDOC'; - } - - $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - } - - // Add the end heredoc token to the final array. - $finalTokens[$newStackPtr] - = PHP_CodeSniffer::standardiseToken($tokens[$stackPtr]); - - if ($nowdoc === true) { - $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC; - $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC'; - $nowdoc = true; - } - - $newStackPtr++; - - // Continue, as we're done with this token. - continue; - }//end if - - /* - PHP doesn't assign a token to goto labels, so we have to. - These are just string tokens with a single colon after them. Double - colons are already tokenized and so don't interfere with this check. - But we do have to account for CASE statements, that look just like - goto labels. - */ - - if ($tokenIsArray === true - && $token[0] === T_STRING - && $tokens[($stackPtr + 1)] === ':' - && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM - ) { - $stopTokens = array( - T_CASE, - T_SEMICOLON, - T_OPEN_CURLY_BRACKET, - ); - - for ($x = ($newStackPtr - 2); $x > 0; $x--) { - if (in_array($finalTokens[$x]['code'], $stopTokens) === true) { - break; - } - } - - if ($finalTokens[$x]['code'] !== T_CASE) { - $finalTokens[$newStackPtr] = array( - 'content' => $token[1].':', - 'code' => T_GOTO_LABEL, - 'type' => 'T_GOTO_LABEL', - ); - $newStackPtr++; - $stackPtr++; - continue; - } - }//end if - - /* - If this token has newlines in its content, split each line up - and create a new token for each line. We do this so it's easier - to ascertain where errors occur on a line. - Note that $token[1] is the token's content. - */ - - if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) { - $tokenLines = explode($eolChar, $token[1]); - $numLines = count($tokenLines); - $tokenName = token_name($token[0]); - - for ($i = 0; $i < $numLines; $i++) { - $newToken['content'] = $tokenLines[$i]; - if ($i === ($numLines - 1)) { - if ($tokenLines[$i] === '') { - break; - } - } else { - $newToken['content'] .= $eolChar; - } - - $newToken['type'] = $tokenName; - $newToken['code'] = $token[0]; - $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - } - } else { - $newToken = PHP_CodeSniffer::standardiseToken($token); - - // Convert colons that are actually the ELSE component of an - // inline IF statement. - if ($newToken['code'] === T_INLINE_THEN) { - $insideInlineIf = true; - } else if ($insideInlineIf === true && $newToken['code'] === T_COLON) { - $insideInlineIf = false; - $newToken['code'] = T_INLINE_ELSE; - $newToken['type'] = 'T_INLINE_ELSE'; - } - - // This is a special condition for T_ARRAY tokens used for - // type hinting function arguments as being arrays. We want to keep - // the parenthesis map clean, so let's tag these tokens as - // T_ARRAY_HINT. - if ($newToken['code'] === T_ARRAY) { - // Recalculate number of tokens. - $numTokens = count($tokens); - for ($i = $stackPtr; $i < $numTokens; $i++) { - if (is_array($tokens[$i]) === false) { - if ($tokens[$i] === '(') { - break; - } - } else if ($tokens[$i][0] === T_VARIABLE) { - $newToken['code'] = T_ARRAY_HINT; - $newToken['type'] = 'T_ARRAY_HINT'; - break; - } - } - } - - $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - }//end if - }//end for - - return $finalTokens; - - }//end tokenizeString() - - - /** - * Performs additional processing after main tokenizing. - * - * This additional processing checks for CASE statements that are using curly - * braces for scope openers and closers. It also turns some T_FUNCTION tokens - * into T_CLOSURE when they are not standard function definitions. It also - * detects short array syntax and converts those square brackets into new tokens. - * It also corrects some usage of the static and class keywords. - * - * @param array &$tokens The array of tokens to process. - * @param string $eolChar The EOL character to use for splitting strings. - * - * @return void - */ - public function processAdditional(&$tokens, $eolChar) - { - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL; - } - - $numTokens = count($tokens); - for ($i = ($numTokens - 1); $i >= 0; $i--) { - // Looking for functions that are actually closures. - if ($tokens[$i]['code'] === T_FUNCTION && isset($tokens[$i]['scope_opener']) === true) { - for ($x = ($i + 1); $x < $numTokens; $x++) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) { - $tokens[$i]['code'] = T_CLOSURE; - $tokens[$i]['type'] = 'T_CLOSURE'; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $line = $tokens[$i]['line']; - echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL; - } - - for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) { - if (isset($tokens[$x]['conditions'][$i]) === false) { - continue; - } - - $tokens[$x]['conditions'][$i] = T_CLOSURE; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$x]['type']; - echo "\t\t* cleaned $x ($type) *".PHP_EOL; - } - } - } - - continue; - } else if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) { - // Unless there is a variable or a bracket before this token, - // it is the start of an array being defined using the short syntax. - for ($x = ($i - 1); $x > 0; $x--) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - $allowed = array( - T_CLOSE_SQUARE_BRACKET, - T_CLOSE_PARENTHESIS, - T_VARIABLE, - T_STRING, - ); - - if (in_array($tokens[$x]['code'], $allowed) === false) { - $tokens[$i]['code'] = T_OPEN_SHORT_ARRAY; - $tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY'; - - $closer = $tokens[$i]['bracket_closer']; - $tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY; - $tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY'; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $line = $tokens[$i]['line']; - echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL; - $line = $tokens[$closer]['line']; - echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL; - } - } - - continue; - } else if ($tokens[$i]['code'] === T_STATIC) { - for ($x = ($i - 1); $x > 0; $x--) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - break; - } - } - - if ($tokens[$x]['code'] === T_INSTANCEOF) { - $tokens[$i]['code'] = T_STRING; - $tokens[$i]['type'] = 'T_STRING'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $line = $tokens[$i]['line']; - echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL; - } - } - - continue; - } else if ($tokens[$i]['code'] === T_CLASS - && $tokens[($i - 1)]['code'] === T_DOUBLE_COLON - ) { - $tokens[$i]['code'] = T_STRING; - $tokens[$i]['type'] = 'T_STRING'; - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $line = $tokens[$i]['line']; - echo "\t* token $i on line $line changed from T_CLASS to T_STRING".PHP_EOL; - } - }//end if - - if (($tokens[$i]['code'] !== T_CASE - && $tokens[$i]['code'] !== T_DEFAULT) - || isset($tokens[$i]['scope_opener']) === false - ) { - // Only interested in CASE and DEFAULT statements from here on in. - continue; - } - - $scopeOpener = $tokens[$i]['scope_opener']; - $scopeCloser = $tokens[$i]['scope_closer']; - - // If the first char after the opener is a curly brace - // and that brace has been ignored, it is actually - // opening this case statement and the opener and closer are - // probably set incorrectly. - for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) { - if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) { - // Non-whitespace content. - break; - } - } - - if ($tokens[$x]['code'] === T_CASE) { - // Special case for multiple CASE statements that share the same - // closer. Because we are going backwards through the file, this next - // CASE statement is already fixed, so just use its closer and don't - // worry about fixing anything. - $newCloser = $tokens[$x]['scope_closer']; - $tokens[$i]['scope_closer'] = $newCloser; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $oldType = $tokens[$scopeCloser]['type']; - $newType = $tokens[$newCloser]['type']; - $line = $tokens[$i]['line']; - echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL; - } - - continue; - } - - if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET - || isset($tokens[$x]['scope_condition']) === true - ) { - // Not a CASE with a curly brace opener. - continue; - } - - // The closer for this CASE/DEFAULT should be the closing curly brace and - // not whatever it already is. The opener needs to be the opening curly - // brace so everything matches up. - $newCloser = $tokens[$x]['bracket_closer']; - $tokens[$i]['scope_closer'] = $newCloser; - $tokens[$x]['scope_closer'] = $newCloser; - $tokens[$i]['scope_opener'] = $x; - $tokens[$x]['scope_condition'] = $i; - $tokens[$newCloser]['scope_condition'] = $i; - $tokens[$newCloser]['scope_opener'] = $x; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $line = $tokens[$i]['line']; - $tokenType = $tokens[$i]['type']; - - $oldType = $tokens[$scopeOpener]['type']; - $newType = $tokens[$x]['type']; - echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL; - - $oldType = $tokens[$scopeCloser]['type']; - $newType = $tokens[$newCloser]['type']; - echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL; - } - - // Now fix up all the tokens that think they are - // inside the CASE/DEFAULT statement when they are really outside. - for ($x = $newCloser; $x < $scopeCloser; $x++) { - foreach ($tokens[$x]['conditions'] as $num => $oldCond) { - if ($oldCond === $tokens[$i]['code']) { - $oldConditions = $tokens[$x]['conditions']; - unset($tokens[$x]['conditions'][$num]); - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = $tokens[$x]['type']; - $oldConds = ''; - foreach ($oldConditions as $condition) { - $oldConds .= token_name($condition).','; - } - - $oldConds = rtrim($oldConds, ','); - - $newConds = ''; - foreach ($tokens[$x]['conditions'] as $condition) { - $newConds .= token_name($condition).','; - } - - $newConds = rtrim($newConds, ','); - - echo "\t\t* cleaned $x ($type) *".PHP_EOL; - echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL; - } - - break; - } - } - } - }//end for - - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL; - } - - }//end processAdditional() - - -}//end class - -?> diff --git a/codesniffer/CodeSniffer/Tokens.php b/codesniffer/CodeSniffer/Tokens.php deleted file mode 100644 index 994a9196b..000000000 --- a/codesniffer/CodeSniffer/Tokens.php +++ /dev/null @@ -1,503 +0,0 @@ - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -define('T_NONE', 0); -define('T_OPEN_CURLY_BRACKET', 1000); -define('T_CLOSE_CURLY_BRACKET', 1001); -define('T_OPEN_SQUARE_BRACKET', 1002); -define('T_CLOSE_SQUARE_BRACKET', 1003); -define('T_OPEN_PARENTHESIS', 1004); -define('T_CLOSE_PARENTHESIS', 1005); -define('T_COLON', 1006); -define('T_STRING_CONCAT', 1007); -define('T_INLINE_THEN', 1008); -define('T_INLINE_ELSE', 1009); -define('T_NULL', 1010); -define('T_FALSE', 1011); -define('T_TRUE', 1012); -define('T_SEMICOLON', 1013); -define('T_EQUAL', 1014); -define('T_MULTIPLY', 1015); -define('T_DIVIDE', 1016); -define('T_PLUS', 1017); -define('T_MINUS', 1018); -define('T_MODULUS', 1019); -define('T_POWER', 1020); -define('T_BITWISE_AND', 1021); -define('T_BITWISE_OR', 1022); -define('T_ARRAY_HINT', 1023); -define('T_GREATER_THAN', 1024); -define('T_LESS_THAN', 1025); -define('T_BOOLEAN_NOT', 1026); -define('T_SELF', 1027); -define('T_PARENT', 1028); -define('T_DOUBLE_QUOTED_STRING', 1029); -define('T_COMMA', 1030); -define('T_HEREDOC', 1031); -define('T_PROTOTYPE', 1032); -define('T_THIS', 1033); -define('T_REGULAR_EXPRESSION', 1034); -define('T_PROPERTY', 1035); -define('T_LABEL', 1036); -define('T_OBJECT', 1037); -define('T_COLOUR', 1038); -define('T_HASH', 1039); -define('T_URL', 1040); -define('T_STYLE', 1041); -define('T_ASPERAND', 1042); -define('T_DOLLAR', 1043); -define('T_TYPEOF', 1044); -define('T_CLOSURE', 1045); -define('T_BACKTICK', 1046); -define('T_START_NOWDOC', 1047); -define('T_NOWDOC', 1048); -define('T_END_NOWDOC', 1049); -define('T_OPEN_SHORT_ARRAY', 1050); -define('T_CLOSE_SHORT_ARRAY', 1051); -define('T_GOTO_LABEL', 1052); - -// Some PHP 5.3 tokens, replicated for lower versions. -if (defined('T_NAMESPACE') === false) { - define('T_NAMESPACE', 1053); -} - -if (defined('T_NS_SEPARATOR') === false) { - define('T_NS_SEPARATOR', 1054); -} - -if (defined('T_GOTO') === false) { - define('T_GOTO', 1055); -} - -// Some PHP 5.4 tokens, replicated for lower versions. -if (defined('T_TRAIT') === false) { - define('T_TRAIT', 1056); -} - -if (defined('T_INSTEADOF') === false) { - define('T_INSTEADOF', 1057); -} - -if (defined('T_CALLABLE') === false) { - define('T_CALLABLE', 1058); -} - -// Some PHP 5.5 tokens, replicated for lower versions. -if (defined('T_FINALLY') === false) { - define('T_FINALLY', 1059); -} - -/** - * The Tokens class contains weightings for tokens based on their - * probability of occurrence in a file. - * - * The less the chance of a high occurrence of an arbitrary token, the higher - * the weighting. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Greg Sherwood - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -final class PHP_CodeSniffer_Tokens -{ - - /** - * The token weightings. - * - * @var array(int => int) - */ - public static $weightings = array( - T_CLASS => 1000, - T_INTERFACE => 1000, - T_TRAIT => 1000, - T_NAMESPACE => 1000, - T_FUNCTION => 100, - T_CLOSURE => 100, - - /* - Conditions. - */ - - T_WHILE => 50, - T_FOR => 50, - T_FOREACH => 50, - T_IF => 50, - T_ELSE => 50, - T_ELSEIF => 50, - T_WHILE => 50, - T_DO => 50, - T_TRY => 50, - T_CATCH => 50, - T_SWITCH => 50, - - T_SELF => 25, - T_PARENT => 25, - - /* - Operators and arithmetic. - */ - - T_BITWISE_AND => 8, - T_BITWISE_OR => 8, - - T_MULTIPLY => 5, - T_DIVIDE => 5, - T_PLUS => 5, - T_MINUS => 5, - T_MODULUS => 5, - T_POWER => 5, - - T_EQUAL => 5, - T_AND_EQUAL => 5, - T_CONCAT_EQUAL => 5, - T_DIV_EQUAL => 5, - T_MINUS_EQUAL => 5, - T_MOD_EQUAL => 5, - T_MUL_EQUAL => 5, - T_OR_EQUAL => 5, - T_PLUS_EQUAL => 5, - T_XOR_EQUAL => 5, - - T_BOOLEAN_AND => 5, - T_BOOLEAN_OR => 5, - - /* - Equality. - */ - - T_IS_EQUAL => 5, - T_IS_NOT_EQUAL => 5, - T_IS_IDENTICAL => 5, - T_IS_NOT_IDENTICAL => 5, - T_IS_SMALLER_OR_EQUAL => 5, - T_IS_GREATER_OR_EQUAL => 5, - ); - - /** - * Tokens that represent assignments. - * - * @var array(int) - */ - public static $assignmentTokens = array( - T_EQUAL, - T_AND_EQUAL, - T_CONCAT_EQUAL, - T_DIV_EQUAL, - T_MINUS_EQUAL, - T_MOD_EQUAL, - T_MUL_EQUAL, - T_PLUS_EQUAL, - T_XOR_EQUAL, - T_DOUBLE_ARROW, - ); - - /** - * Tokens that represent equality comparisons. - * - * @var array(int) - */ - public static $equalityTokens = array( - T_IS_EQUAL, - T_IS_NOT_EQUAL, - T_IS_IDENTICAL, - T_IS_NOT_IDENTICAL, - T_IS_SMALLER_OR_EQUAL, - T_IS_GREATER_OR_EQUAL, - ); - - /** - * Tokens that represent comparison operator. - * - * @var array(int) - */ - public static $comparisonTokens = array( - T_IS_EQUAL, - T_IS_IDENTICAL, - T_IS_NOT_EQUAL, - T_IS_NOT_IDENTICAL, - T_LESS_THAN, - T_GREATER_THAN, - T_IS_SMALLER_OR_EQUAL, - T_IS_GREATER_OR_EQUAL, - ); - - /** - * Tokens that represent arithmetic operators. - * - * @var array(int) - */ - public static $arithmeticTokens = array( - T_PLUS, - T_MINUS, - T_MULTIPLY, - T_DIVIDE, - T_MODULUS, - ); - - /** - * Tokens that represent casting. - * - * @var array(int) - */ - public static $castTokens = array( - T_INT_CAST, - T_STRING_CAST, - T_DOUBLE_CAST, - T_ARRAY_CAST, - T_BOOL_CAST, - T_OBJECT_CAST, - T_UNSET_CAST, - ); - - /** - * Token types that open parenthesis. - * - * @var array(int) - */ - public static $parenthesisOpeners = array( - T_ARRAY, - T_FUNCTION, - T_CLOSURE, - T_WHILE, - T_FOR, - T_FOREACH, - T_SWITCH, - T_IF, - T_ELSEIF, - T_CATCH, - ); - - /** - * Tokens that are allowed to open scopes. - * - * @var array(int) - */ - public static $scopeOpeners = array( - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_NAMESPACE, - T_FUNCTION, - T_CLOSURE, - T_IF, - T_SWITCH, - T_CASE, - T_DEFAULT, - T_WHILE, - T_ELSE, - T_ELSEIF, - T_FOR, - T_FOREACH, - T_DO, - T_TRY, - T_CATCH, - ); - - /** - * Tokens that represent scope modifiers. - * - * @var array(int) - */ - public static $scopeModifiers = array( - T_PRIVATE, - T_PUBLIC, - T_PROTECTED, - ); - - /** - * Tokens that can prefix a method name - * - * @var array(int) - */ - public static $methodPrefixes = array( - T_PRIVATE, - T_PUBLIC, - T_PROTECTED, - T_ABSTRACT, - T_STATIC, - T_FINAL, - ); - - /** - * Tokens that perform operations. - * - * @var array(int) - */ - public static $operators = array( - T_MINUS, - T_PLUS, - T_MULTIPLY, - T_DIVIDE, - T_MODULUS, - T_POWER, - T_BITWISE_AND, - T_BITWISE_OR, - ); - - /** - * Tokens that perform boolean operations. - * - * @var array(int) - */ - public static $booleanOperators = array( - T_BOOLEAN_AND, - T_BOOLEAN_OR, - T_LOGICAL_AND, - T_LOGICAL_OR, - T_LOGICAL_XOR, - ); - - /** - * Tokens that open code blocks. - * - * @var array(int) - */ - public static $blockOpeners = array( - T_OPEN_CURLY_BRACKET, - T_OPEN_SQUARE_BRACKET, - T_OPEN_PARENTHESIS, - ); - - /** - * Tokens that don't represent code. - * - * @var array(int) - */ - public static $emptyTokens = array( - T_WHITESPACE, - T_COMMENT, - T_DOC_COMMENT, - ); - - /** - * Tokens that are comments. - * - * @var array(int) - */ - public static $commentTokens = array( - T_COMMENT, - T_DOC_COMMENT, - ); - - /** - * Tokens that represent strings. - * - * Note that T_STRINGS are NOT represented in this list. - * - * @var array(int) - */ - public static $stringTokens = array( - T_CONSTANT_ENCAPSED_STRING, - T_DOUBLE_QUOTED_STRING, - ); - - /** - * Tokens that represent brackets and parenthesis. - * - * @var array(int) - */ - public static $bracketTokens = array( - T_OPEN_CURLY_BRACKET, - T_CLOSE_CURLY_BRACKET, - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, - ); - - /** - * Tokens that include files. - * - * @var array(int) - */ - public static $includeTokens = array( - T_REQUIRE_ONCE, - T_REQUIRE, - T_INCLUDE_ONCE, - T_INCLUDE, - ); - - /** - * Tokens that make up a heredoc string. - * - * @var array(int) - */ - public static $heredocTokens = array( - T_START_HEREDOC, - T_END_HEREDOC, - T_HEREDOC, - ); - - - /** - * A PHP_CodeSniffer_Tokens class cannot be constructed. - * - * Only static calls are allowed. - */ - private function __construct() - { - - }//end __construct() - - - /** - * Returns the highest weighted token type. - * - * Tokens are weighted by their approximate frequency of appearance in code - * - the less frequently they appear in the code, the higher the weighting. - * For example T_CLASS tokens appear very infrequently in a file, and - * therefore have a high weighting. - * - * Returns false if there are no weightings for any of the specified tokens. - * - * @param array(int) $tokens The token types to get the highest weighted - * type for. - * - * @return int The highest weighted token. - */ - public static function getHighestWeightedToken(array $tokens) - { - $highest = -1; - $highestType = false; - - $weights = self::$weightings; - - foreach ($tokens as $token) { - if (isset($weights[$token]) === true) { - $weight = $weights[$token]; - } else { - $weight = 0; - } - - if ($weight > $highest) { - $highest = $weight; - $highestType = $token; - } - } - - return $highestType; - - }//end getHighestWeightedToken() - - -}//end class - -?> diff --git a/codesniffer/README.markdown b/codesniffer/README.markdown deleted file mode 100644 index be787c280..000000000 --- a/codesniffer/README.markdown +++ /dev/null @@ -1,64 +0,0 @@ -About ------ - -PHP\_CodeSniffer is a PHP5 script that tokenises PHP, JavaScript and CSS files to detect violations of a defined coding standard. It is an essential development tool that ensures your code remains clean and consistent. It can also help prevent some common semantic errors made by developers. - -[![Build Status](https://secure.travis-ci.org/squizlabs/PHP_CodeSniffer.png?branch=master)](https://travis-ci.org/squizlabs/PHP_CodeSniffer) - -Requirements ------------- - -PHP\_CodeSniffer requires PHP version 5.1.2 or greater, although individual sniffs may have additional requirements such as external applications and scripts. See the [Configuration Options manual page](http://pear.php.net/manual/en/package.php.php-codesniffer.config-options.php) for a list of these requirements. - -The SVN pre-commit hook requires PHP version 5.2.4 or greater due to its use of the vertical whitespace character. - -Installation ------------- - -The easiest way to install PHP\_CodeSniffer is to use the PEAR installer. This will make the `phpcs` command immediately available for use. To install PHP\_CodeSniffer using the PEAR installer, first ensure you have [installed PEAR](http://pear.php.net/manual/en/installation.getting.php) and then run the following command: - - pear install PHP_CodeSniffer - -If you use [Composer](http://getcomposer.org/), include a dependency for `squizlabs/php_codesniffer` in your `composer.json` file. For example: - - { - "require": { - "squizlabs/php_codesniffer": "1.*" - } - } - -You will then be able to run PHP_CodeSniffer from the vendor bin directory: - - ./vendor/bin/phpcs -h - -You can also download the PHP\_CodeSniffer source and run the `phpcs` command directly from the GIT checkout: - - git clone git://github.com/squizlabs/PHP_CodeSniffer.git - cd PHP_CodeSniffer - php scripts/phpcs -h - -Documentation -------------- - -The documentation for PHP\_CodeSniffer is available on the [Github wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki). - -Information about upcoming features and releases is available on the [Squiz Labs blog](http://www.squizlabs.com/php-codesniffer). - -Contributing -------------- - -If you do contribute code to PHP\_CodeSniffer, please make sure it conforms to the PEAR coding standard and that the PHP\_CodeSniffer unit tests still pass. The easiest way to contribute is to work on a checkout of the repository, or your own fork, rather than an installed PEAR version. If you do this, you can run the following commands to check if everything is ready to submit: - - cd PHP_CodeSniffer - php scripts/phpcs --ignore=*/tests/* . -n - -Which should give you no output, indicating that there are no PEAR coding standard errors. And then: - - phpunit tests/AllTests.php - -Which should give you no failures or errors. You can ignore any skipped tests as these are for external tools. - -Issues ------- - -Bug reports and feature requests can be submitted on the [PEAR bug tracker](http://pear.php.net/package/PHP_CodeSniffer/bugs). diff --git a/codesniffer/composer.json b/codesniffer/composer.json deleted file mode 100644 index 7aba72862..000000000 --- a/codesniffer/composer.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "squizlabs/php_codesniffer", - "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "type": "library", - "keywords": [ - "phpcs", - "standards" - ], - "homepage": "http://www.squizlabs.com/php-codesniffer", - "license": "BSD-3-Clause", - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "support": { - "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name%5B%5D=PHP_CodeSniffer", - "source": "https://github.com/squizlabs/PHP_CodeSniffer" - }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/CommentParser/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, - "suggest": { - "phpunit/php-timer": "dev-master" - }, - "require": { - "php": ">=5.1.2", - "ext-tokenizer": "*" - }, - "bin": [ - "scripts/phpcs" - ] -} diff --git a/codesniffer/composer.lock b/codesniffer/composer.lock deleted file mode 100644 index c452ae778..000000000 --- a/codesniffer/composer.lock +++ /dev/null @@ -1,21 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "95911e7f79b53c3f385f7f5197d51785", - "content-hash": "a79b48b1f1e644cec95679bb347dd34c", - "packages": [], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.1.2", - "ext-tokenizer": "*" - }, - "platform-dev": [] -} diff --git a/codesniffer/licence.txt b/codesniffer/licence.txt deleted file mode 100644 index f95432c87..000000000 --- a/codesniffer/licence.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2012, Squiz Pty Ltd (ABN 77 084 670 600) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Squiz Pty Ltd nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/codesniffer/scripts/phpcs b/codesniffer/scripts/phpcs deleted file mode 100755 index 839c70f23..000000000 --- a/codesniffer/scripts/phpcs +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env php - - * @author Marc McIntyre - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -error_reporting(E_ALL | E_STRICT); - -// Optionally use PHP_Timer to print time/memory stats for the run. -// Note that the reports are the ones who actually print the data -// as they decide if it is ok to print this data to screen. -@include_once 'PHP/Timer.php'; -if (class_exists('PHP_Timer', false) === true) { - PHP_Timer::start(); -} - -if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) { - include_once dirname(__FILE__).'/../CodeSniffer/CLI.php'; -} else { - include_once 'PHP/CodeSniffer/CLI.php'; -} - -$phpcs = new PHP_CodeSniffer_CLI(); -$phpcs->checkRequirements(); - -$numErrors = $phpcs->process(); -if ($numErrors === 0) { - exit(0); -} else { - exit(1); -} - -?> diff --git a/codesniffer/scripts/phpcs-svn-pre-commit b/codesniffer/scripts/phpcs-svn-pre-commit deleted file mode 100755 index f15438b51..000000000 --- a/codesniffer/scripts/phpcs-svn-pre-commit +++ /dev/null @@ -1,223 +0,0 @@ -#!@php_bin@ - - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) { - include_once dirname(__FILE__).'/../CodeSniffer/CLI.php'; -} else { - include_once 'PHP/CodeSniffer/CLI.php'; -} - -define('PHP_CODESNIFFER_SVNLOOK', '/usr/bin/svnlook'); - - -/** - * A class to process command line options. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Jack Bates - * @author Greg Sherwood - * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - * @version Release: @package_version@ - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class PHP_CodeSniffer_SVN_Hook extends PHP_CodeSniffer_CLI -{ - - - /** - * Get a list of default values for all possible command line arguments. - * - * @return array - */ - public function getDefaults() - { - $defaults = parent::getDefaults(); - - $defaults['svnArgs'] = array(); - return $defaults; - - }//end getDefaults() - - - /** - * Processes an unknown command line argument. - * - * All unknown args are sent to SVN commands. - * - * @param string $arg The command line argument. - * @param int $pos The position of the argument on the command line. - * @param array $values An array of values determined from CLI args. - * - * @return array The updated CLI values. - * @see getCommandLineValues() - */ - public function processUnknownArgument($arg, $pos, $values) - { - $values['svnArgs'][] = escapeshellarg($arg); - return $values; - - }//end processUnknownArgument() - - - /** - * Runs PHP_CodeSniffer over files are directories. - * - * @param array $values An array of values determined from CLI args. - * - * @return int The number of error and warning messages shown. - * @see getCommandLineValues() - */ - public function process($values=array()) - { - if (empty($values) === true) { - $values = parent::getCommandLineValues(); - } - - // Get list of files in this transaction. - $command = PHP_CODESNIFFER_SVNLOOK.' changed '.implode(' ', $values['svnArgs']); - $handle = popen($command, 'r'); - if ($handle === false) { - echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; - exit(2); - } - - $contents = stream_get_contents($handle); - fclose($handle); - - // Do not check deleted paths. - $contents = preg_replace('/^D.*/m', null, $contents); - - // Drop the four characters representing the action which precede the path on - // each line. - $contents = preg_replace('/^.{4}/m', null, $contents); - - $values['standard'] = $this->validateStandard($values['standard']); - foreach ($values['standard'] as $standard) { - if (PHP_CodeSniffer::isInstalledStandard($standard) === false) { - // They didn't select a valid coding standard, so help them - // out by letting them know which standards are installed. - echo 'ERROR: the "'.$standard.'" coding standard is not installed. '; - $this->printInstalledStandards(); - exit(2); - } - } - - $phpcs = new PHP_CodeSniffer( - $values['verbosity'], - $values['tabWidth'], - $values['encoding'] - ); - - // Set file extensions if they were specified. Otherwise, - // let PHP_CodeSniffer decide on the defaults. - if (empty($values['extensions']) === false) { - $phpcs->setAllowedFileExtensions($values['extensions']); - } - - // Set ignore patterns if they were specified. - if (empty($values['ignored']) === false) { - $phpcs->setIgnorePatterns($values['ignored']); - } - - // Set some convenience member vars. - if ($values['errorSeverity'] === null) { - $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; - } else { - $this->errorSeverity = $values['errorSeverity']; - } - - if ($values['warningSeverity'] === null) { - $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; - } else { - $this->warningSeverity = $values['warningSeverity']; - } - - // Initialize PHP_CodeSniffer listeners but don't process any files. - $phpcs->setCli($this); - $phpcs->process(array(), $values['standard'], $values['sniffs']); - - // Need double quotes around the following regex beause the vertical whitespace - // char is not always treated correctly for whatever reason. - foreach (preg_split("/\v|\n/", $contents, -1, PREG_SPLIT_NO_EMPTY) as $path) { - // No need to process folders as each changed file is checked. - if (substr($path, -1) === '/') { - continue; - } - - // We need to check ignore rules ourself because they are - // not checked when processing a single file. - if ($phpcs->shouldProcessFile($path, dirname($path)) === false) { - continue; - } - - // Get the contents of each file, as it would be after this transaction. - $command = PHP_CODESNIFFER_SVNLOOK.' cat '.implode(' ', $values['svnArgs']).' '.escapeshellarg($path); - $handle = popen($command, 'r'); - if ($handle === false) { - echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; - exit(2); - } - - $contents = stream_get_contents($handle); - fclose($handle); - - $phpcs->processFile($path, $contents); - }//end foreach - - return $this->printErrorReport( - $phpcs, - $values['reports'], - $values['showSources'], - $values['reportFile'], - $values['reportWidth'] - ); - - }//end process() - - - /** - * Prints out the usage information for this script. - * - * @return void - */ - public function printUsage() - { - parent::printUsage(); - - echo PHP_EOL; - echo ' Each additional argument is passed to the `svnlook changed ...`'.PHP_EOL; - echo ' and `svnlook cat ...` commands. The report is printed on standard output,'.PHP_EOL; - echo ' however Subversion displays only standard error to the user, so in a'.PHP_EOL; - echo ' pre-commit hook, this script should be invoked as follows:'.PHP_EOL; - echo PHP_EOL; - echo ' '.basename($_SERVER['argv'][0]).' ... "$REPOS" -t "$TXN" >&2 || exit 1'.PHP_EOL; - - }//end printUsage() - - -}//end class - -$phpcs = new PHP_CodeSniffer_SVN_Hook(); -$phpcs->checkRequirements(); - -$numErrors = $phpcs->process(); -if ($numErrors !== 0) { - exit(1); -} - -?> diff --git a/codesniffer/scripts/phpcs.bat b/codesniffer/scripts/phpcs.bat deleted file mode 100755 index 8620015f8..000000000 --- a/codesniffer/scripts/phpcs.bat +++ /dev/null @@ -1,16 +0,0 @@ -@echo off -REM PHP_CodeSniffer tokenises PHP code and detects violations of a -REM defined set of coding standards. -REM -REM PHP version 5 -REM -REM @category PHP -REM @package PHP_CodeSniffer -REM @author Greg Sherwood -REM @author Marc McIntyre -REM @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600) -REM @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence -REM @version CVS: $Id: phpcs.bat,v 1.3 2007-11-04 22:02:16 squiz Exp $ -REM @link http://pear.php.net/package/PHP_CodeSniffer - -"@php_bin@" -d auto_append_file="" -d auto_prepend_file="" -d include_path="'@php_dir@'" -f "@bin_dir@\phpcs" -- %* diff --git a/codesniffer/vendor/autoload.php b/codesniffer/vendor/autoload.php deleted file mode 100644 index f566fcbce..000000000 --- a/codesniffer/vendor/autoload.php +++ /dev/null @@ -1,7 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - // PSR-4 - private $prefixLengthsPsr4 = array(); - private $prefixDirsPsr4 = array(); - private $fallbackDirsPsr4 = array(); - - // PSR-0 - private $prefixesPsr0 = array(); - private $fallbackDirsPsr0 = array(); - - private $useIncludePath = false; - private $classMap = array(); - private $classMapAuthoritative = false; - private $missingClasses = array(); - - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); - } - - return array(); - } - - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - } - - /** - * Unregisters this instance as an autoloader. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - includeFile($file); - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 - if ('\\' == $class[0]) { - $class = substr($class, 1); - } - - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach ($this->prefixDirsPsr4[$prefix] as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } -} - -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; -} diff --git a/codesniffer/vendor/composer/LICENSE b/codesniffer/vendor/composer/LICENSE deleted file mode 100644 index 1a2812488..000000000 --- a/codesniffer/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) 2016 Nils Adermann, Jordi Boggiano - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/codesniffer/vendor/composer/autoload_classmap.php b/codesniffer/vendor/composer/autoload_classmap.php deleted file mode 100644 index b600b6037..000000000 --- a/codesniffer/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,257 +0,0 @@ - $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', - 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php', - 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php', - 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php', - 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php', - 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php', - 'Generic_Sniffs_Commenting_FixmeSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php', - 'Generic_Sniffs_Commenting_TodoSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php', - 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php', - 'Generic_Sniffs_Debug_CSSLintSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php', - 'Generic_Sniffs_Debug_ClosureLinterSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php', - 'Generic_Sniffs_Debug_JSHintSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php', - 'Generic_Sniffs_Files_ByteOrderMarkSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php', - 'Generic_Sniffs_Files_EndFileNewlineSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php', - 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php', - 'Generic_Sniffs_Files_InlineHTMLSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php', - 'Generic_Sniffs_Files_LineEndingsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php', - 'Generic_Sniffs_Files_LineLengthSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php', - 'Generic_Sniffs_Files_LowercasedFilenameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php', - 'Generic_Sniffs_Files_OneClassPerFileSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php', - 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php', - 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php', - 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php', - 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php', - 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php', - 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php', - 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php', - 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php', - 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php', - 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php', - 'Generic_Sniffs_Metrics_NestingLevelSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php', - 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php', - 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php', - 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', - 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php', - 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php', - 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php', - 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', - 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php', - 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php', - 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php', - 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php', - 'Generic_Sniffs_PHP_SAPIUsageSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php', - 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php', - 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php', - 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php', - 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php', - 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php', - 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => $baseDir . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php', - 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php', - 'MySource_Sniffs_Channels_ChannelExceptionSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php', - 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php', - 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php', - 'MySource_Sniffs_Channels_IncludeSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php', - 'MySource_Sniffs_Channels_UnusedSystemSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php', - 'MySource_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php', - 'MySource_Sniffs_Debug_DebugCodeSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php', - 'MySource_Sniffs_Debug_FirebugConsoleSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php', - 'MySource_Sniffs_Objects_AssignThisSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php', - 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php', - 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php', - 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php', - 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php', - 'MySource_Sniffs_PHP_GetRequestDataSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php', - 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php', - 'MySource_Sniffs_Strings_JoinStringsSniff' => $baseDir . '/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php', - 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php', - 'PEAR_Sniffs_Commenting_ClassCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php', - 'PEAR_Sniffs_Commenting_FileCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php', - 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php', - 'PEAR_Sniffs_Commenting_InlineCommentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php', - 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php', - 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php', - 'PEAR_Sniffs_Files_IncludingFileSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php', - 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php', - 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php', - 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php', - 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php', - 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php', - 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', - 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => $baseDir . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php', - 'PHP_CodeSniffer' => $baseDir . '/CodeSniffer.php', - 'PHP_CodeSniffer_CLI' => $baseDir . '/CodeSniffer/CLI.php', - 'PHP_CodeSniffer_CommentParser_AbstractDocElement' => $baseDir . '/CodeSniffer/CommentParser/AbstractDocElement.php', - 'PHP_CodeSniffer_CommentParser_AbstractParser' => $baseDir . '/CodeSniffer/CommentParser/AbstractParser.php', - 'PHP_CodeSniffer_CommentParser_ClassCommentParser' => $baseDir . '/CodeSniffer/CommentParser/ClassCommentParser.php', - 'PHP_CodeSniffer_CommentParser_CommentElement' => $baseDir . '/CodeSniffer/CommentParser/CommentElement.php', - 'PHP_CodeSniffer_CommentParser_DocElement' => $baseDir . '/CodeSniffer/CommentParser/DocElement.php', - 'PHP_CodeSniffer_CommentParser_FunctionCommentParser' => $baseDir . '/CodeSniffer/CommentParser/FunctionCommentParser.php', - 'PHP_CodeSniffer_CommentParser_MemberCommentParser' => $baseDir . '/CodeSniffer/CommentParser/MemberCommentParser.php', - 'PHP_CodeSniffer_CommentParser_PairElement' => $baseDir . '/CodeSniffer/CommentParser/PairElement.php', - 'PHP_CodeSniffer_CommentParser_ParameterElement' => $baseDir . '/CodeSniffer/CommentParser/ParameterElement.php', - 'PHP_CodeSniffer_CommentParser_ParserException' => $baseDir . '/CodeSniffer/CommentParser/ParserException.php', - 'PHP_CodeSniffer_CommentParser_SingleElement' => $baseDir . '/CodeSniffer/CommentParser/SingleElement.php', - 'PHP_CodeSniffer_DocGenerators_Generator' => $baseDir . '/CodeSniffer/DocGenerators/Generator.php', - 'PHP_CodeSniffer_DocGenerators_HTML' => $baseDir . '/CodeSniffer/DocGenerators/HTML.php', - 'PHP_CodeSniffer_DocGenerators_Text' => $baseDir . '/CodeSniffer/DocGenerators/Text.php', - 'PHP_CodeSniffer_Exception' => $baseDir . '/CodeSniffer/Exception.php', - 'PHP_CodeSniffer_File' => $baseDir . '/CodeSniffer/File.php', - 'PHP_CodeSniffer_Report' => $baseDir . '/CodeSniffer/Report.php', - 'PHP_CodeSniffer_Reporting' => $baseDir . '/CodeSniffer/Reporting.php', - 'PHP_CodeSniffer_Reports_Checkstyle' => $baseDir . '/CodeSniffer/Reports/Checkstyle.php', - 'PHP_CodeSniffer_Reports_Csv' => $baseDir . '/CodeSniffer/Reports/Csv.php', - 'PHP_CodeSniffer_Reports_Emacs' => $baseDir . '/CodeSniffer/Reports/Emacs.php', - 'PHP_CodeSniffer_Reports_Full' => $baseDir . '/CodeSniffer/Reports/Full.php', - 'PHP_CodeSniffer_Reports_Gitblame' => $baseDir . '/CodeSniffer/Reports/Gitblame.php', - 'PHP_CodeSniffer_Reports_Hgblame' => $baseDir . '/CodeSniffer/Reports/Hgblame.php', - 'PHP_CodeSniffer_Reports_Json' => $baseDir . '/CodeSniffer/Reports/Json.php', - 'PHP_CodeSniffer_Reports_Junit' => $baseDir . '/CodeSniffer/Reports/Junit.php', - 'PHP_CodeSniffer_Reports_Notifysend' => $baseDir . '/CodeSniffer/Reports/Notifysend.php', - 'PHP_CodeSniffer_Reports_Source' => $baseDir . '/CodeSniffer/Reports/Source.php', - 'PHP_CodeSniffer_Reports_Summary' => $baseDir . '/CodeSniffer/Reports/Summary.php', - 'PHP_CodeSniffer_Reports_Svnblame' => $baseDir . '/CodeSniffer/Reports/Svnblame.php', - 'PHP_CodeSniffer_Reports_VersionControl' => $baseDir . '/CodeSniffer/Reports/VersionControl.php', - 'PHP_CodeSniffer_Reports_Xml' => $baseDir . '/CodeSniffer/Reports/Xml.php', - 'PHP_CodeSniffer_Sniff' => $baseDir . '/CodeSniffer/Sniff.php', - 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => $baseDir . '/CodeSniffer/Standards/AbstractPatternSniff.php', - 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => $baseDir . '/CodeSniffer/Standards/AbstractScopeSniff.php', - 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => $baseDir . '/CodeSniffer/Standards/AbstractVariableSniff.php', - 'PHP_CodeSniffer_Standards_IncorrectPatternException' => $baseDir . '/CodeSniffer/Standards/IncorrectPatternException.php', - 'PHP_CodeSniffer_Tokenizers_CSS' => $baseDir . '/CodeSniffer/Tokenizers/CSS.php', - 'PHP_CodeSniffer_Tokenizers_JS' => $baseDir . '/CodeSniffer/Tokenizers/JS.php', - 'PHP_CodeSniffer_Tokenizers_PHP' => $baseDir . '/CodeSniffer/Tokenizers/PHP.php', - 'PHP_CodeSniffer_Tokens' => $baseDir . '/CodeSniffer/Tokens.php', - 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php', - 'PSR1_Sniffs_Files_SideEffectsSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php', - 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => $baseDir . '/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', - 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php', - 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php', - 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php', - 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', - 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php', - 'PSR2_Sniffs_Files_EndFileNewlineSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php', - 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php', - 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php', - 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php', - 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php', - 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php', - 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php', - 'Squiz_Sniffs_CSS_ColonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php', - 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php', - 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php', - 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php', - 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php', - 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php', - 'Squiz_Sniffs_CSS_IndentationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php', - 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_MissingColonSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php', - 'Squiz_Sniffs_CSS_NamedColoursSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php', - 'Squiz_Sniffs_CSS_OpacitySniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php', - 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php', - 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php', - 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php', - 'Squiz_Sniffs_Classes_ClassFileNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php', - 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php', - 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php', - 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php', - 'Squiz_Sniffs_Classes_ValidClassNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php', - 'Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php', - 'Squiz_Sniffs_Commenting_BlockCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php', - 'Squiz_Sniffs_Commenting_ClassCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php', - 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php', - 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php', - 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php', - 'Squiz_Sniffs_Commenting_FileCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php', - 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php', - 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php', - 'Squiz_Sniffs_Commenting_InlineCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php', - 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php', - 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php', - 'Squiz_Sniffs_Commenting_VariableCommentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php', - 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php', - 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php', - 'Squiz_Sniffs_Debug_JSLintSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php', - 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php', - 'Squiz_Sniffs_Files_FileExtensionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php', - 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php', - 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php', - 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php', - 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php', - 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php', - 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php', - 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php', - 'Squiz_Sniffs_NamingConventions_ConstantCaseSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php', - 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php', - 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php', - 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php', - 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php', - 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php', - 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php', - 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php', - 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php', - 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php', - 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php', - 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php', - 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php', - 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php', - 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php', - 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php', - 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php', - 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php', - 'Squiz_Sniffs_PHP_EvalSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php', - 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php', - 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php', - 'Squiz_Sniffs_PHP_HeredocSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php', - 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php', - 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php', - 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php', - 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php', - 'Squiz_Sniffs_Scope_MethodScopeSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php', - 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php', - 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php', - 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php', - 'Squiz_Sniffs_Strings_EchoedStringsSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php', - 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', - 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => $baseDir . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php', - 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php', - 'Zend_Sniffs_Files_ClosingTagSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php', - 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => $baseDir . '/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php', -); diff --git a/codesniffer/vendor/composer/autoload_namespaces.php b/codesniffer/vendor/composer/autoload_namespaces.php deleted file mode 100644 index b7fc0125d..000000000 --- a/codesniffer/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,9 +0,0 @@ -= 50600 && !defined('HHVM_VERSION'); - if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit139aa91c62d198426cb28d1274c47616::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - } - - $loader->register(true); - - return $loader; - } -} diff --git a/codesniffer/vendor/composer/autoload_static.php b/codesniffer/vendor/composer/autoload_static.php deleted file mode 100644 index b582df499..000000000 --- a/codesniffer/vendor/composer/autoload_static.php +++ /dev/null @@ -1,267 +0,0 @@ - __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', - 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php', - 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php', - 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php', - 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php', - 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php', - 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php', - 'Generic_Sniffs_Commenting_FixmeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php', - 'Generic_Sniffs_Commenting_TodoSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php', - 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php', - 'Generic_Sniffs_Debug_CSSLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php', - 'Generic_Sniffs_Debug_ClosureLinterSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php', - 'Generic_Sniffs_Debug_JSHintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php', - 'Generic_Sniffs_Files_ByteOrderMarkSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php', - 'Generic_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php', - 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php', - 'Generic_Sniffs_Files_InlineHTMLSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php', - 'Generic_Sniffs_Files_LineEndingsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php', - 'Generic_Sniffs_Files_LineLengthSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php', - 'Generic_Sniffs_Files_LowercasedFilenameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php', - 'Generic_Sniffs_Files_OneClassPerFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php', - 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php', - 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php', - 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php', - 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php', - 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php', - 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php', - 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php', - 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php', - 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php', - 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php', - 'Generic_Sniffs_Metrics_NestingLevelSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php', - 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php', - 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php', - 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', - 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php', - 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php', - 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php', - 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', - 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php', - 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php', - 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php', - 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php', - 'Generic_Sniffs_PHP_SAPIUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php', - 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php', - 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php', - 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php', - 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php', - 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php', - 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php', - 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php', - 'MySource_Sniffs_Channels_ChannelExceptionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/ChannelExceptionSniff.php', - 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php', - 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php', - 'MySource_Sniffs_Channels_IncludeSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php', - 'MySource_Sniffs_Channels_UnusedSystemSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php', - 'MySource_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php', - 'MySource_Sniffs_Debug_DebugCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php', - 'MySource_Sniffs_Debug_FirebugConsoleSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php', - 'MySource_Sniffs_Objects_AssignThisSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php', - 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php', - 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php', - 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php', - 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php', - 'MySource_Sniffs_PHP_GetRequestDataSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php', - 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php', - 'MySource_Sniffs_Strings_JoinStringsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php', - 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php', - 'PEAR_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php', - 'PEAR_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php', - 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php', - 'PEAR_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php', - 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php', - 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php', - 'PEAR_Sniffs_Files_IncludingFileSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php', - 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php', - 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php', - 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php', - 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php', - 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php', - 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php', - 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', - 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php', - 'PHP_CodeSniffer' => __DIR__ . '/../..' . '/CodeSniffer.php', - 'PHP_CodeSniffer_CLI' => __DIR__ . '/../..' . '/CodeSniffer/CLI.php', - 'PHP_CodeSniffer_CommentParser_AbstractDocElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/AbstractDocElement.php', - 'PHP_CodeSniffer_CommentParser_AbstractParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/AbstractParser.php', - 'PHP_CodeSniffer_CommentParser_ClassCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ClassCommentParser.php', - 'PHP_CodeSniffer_CommentParser_CommentElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/CommentElement.php', - 'PHP_CodeSniffer_CommentParser_DocElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/DocElement.php', - 'PHP_CodeSniffer_CommentParser_FunctionCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/FunctionCommentParser.php', - 'PHP_CodeSniffer_CommentParser_MemberCommentParser' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/MemberCommentParser.php', - 'PHP_CodeSniffer_CommentParser_PairElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/PairElement.php', - 'PHP_CodeSniffer_CommentParser_ParameterElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ParameterElement.php', - 'PHP_CodeSniffer_CommentParser_ParserException' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/ParserException.php', - 'PHP_CodeSniffer_CommentParser_SingleElement' => __DIR__ . '/../..' . '/CodeSniffer/CommentParser/SingleElement.php', - 'PHP_CodeSniffer_DocGenerators_Generator' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/Generator.php', - 'PHP_CodeSniffer_DocGenerators_HTML' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/HTML.php', - 'PHP_CodeSniffer_DocGenerators_Text' => __DIR__ . '/../..' . '/CodeSniffer/DocGenerators/Text.php', - 'PHP_CodeSniffer_Exception' => __DIR__ . '/../..' . '/CodeSniffer/Exception.php', - 'PHP_CodeSniffer_File' => __DIR__ . '/../..' . '/CodeSniffer/File.php', - 'PHP_CodeSniffer_Report' => __DIR__ . '/../..' . '/CodeSniffer/Report.php', - 'PHP_CodeSniffer_Reporting' => __DIR__ . '/../..' . '/CodeSniffer/Reporting.php', - 'PHP_CodeSniffer_Reports_Checkstyle' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Checkstyle.php', - 'PHP_CodeSniffer_Reports_Csv' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Csv.php', - 'PHP_CodeSniffer_Reports_Emacs' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Emacs.php', - 'PHP_CodeSniffer_Reports_Full' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Full.php', - 'PHP_CodeSniffer_Reports_Gitblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Gitblame.php', - 'PHP_CodeSniffer_Reports_Hgblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Hgblame.php', - 'PHP_CodeSniffer_Reports_Json' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Json.php', - 'PHP_CodeSniffer_Reports_Junit' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Junit.php', - 'PHP_CodeSniffer_Reports_Notifysend' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Notifysend.php', - 'PHP_CodeSniffer_Reports_Source' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Source.php', - 'PHP_CodeSniffer_Reports_Summary' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Summary.php', - 'PHP_CodeSniffer_Reports_Svnblame' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Svnblame.php', - 'PHP_CodeSniffer_Reports_VersionControl' => __DIR__ . '/../..' . '/CodeSniffer/Reports/VersionControl.php', - 'PHP_CodeSniffer_Reports_Xml' => __DIR__ . '/../..' . '/CodeSniffer/Reports/Xml.php', - 'PHP_CodeSniffer_Sniff' => __DIR__ . '/../..' . '/CodeSniffer/Sniff.php', - 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractPatternSniff.php', - 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractScopeSniff.php', - 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/AbstractVariableSniff.php', - 'PHP_CodeSniffer_Standards_IncorrectPatternException' => __DIR__ . '/../..' . '/CodeSniffer/Standards/IncorrectPatternException.php', - 'PHP_CodeSniffer_Tokenizers_CSS' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/CSS.php', - 'PHP_CodeSniffer_Tokenizers_JS' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/JS.php', - 'PHP_CodeSniffer_Tokenizers_PHP' => __DIR__ . '/../..' . '/CodeSniffer/Tokenizers/PHP.php', - 'PHP_CodeSniffer_Tokens' => __DIR__ . '/../..' . '/CodeSniffer/Tokens.php', - 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php', - 'PSR1_Sniffs_Files_SideEffectsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php', - 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', - 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php', - 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php', - 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php', - 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', - 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php', - 'PSR2_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php', - 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php', - 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php', - 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php', - 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php', - 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php', - 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php', - 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php', - 'Squiz_Sniffs_CSS_ColonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php', - 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php', - 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php', - 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php', - 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php', - 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php', - 'Squiz_Sniffs_CSS_IndentationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php', - 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php', - 'Squiz_Sniffs_CSS_MissingColonSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php', - 'Squiz_Sniffs_CSS_NamedColoursSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php', - 'Squiz_Sniffs_CSS_OpacitySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php', - 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php', - 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php', - 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php', - 'Squiz_Sniffs_Classes_ClassFileNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php', - 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php', - 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php', - 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php', - 'Squiz_Sniffs_Classes_ValidClassNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php', - 'Squiz_Sniffs_CodeAnalysis_EmptyStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/CodeAnalysis/EmptyStatementSniff.php', - 'Squiz_Sniffs_Commenting_BlockCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php', - 'Squiz_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php', - 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php', - 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php', - 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php', - 'Squiz_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php', - 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php', - 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php', - 'Squiz_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php', - 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php', - 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php', - 'Squiz_Sniffs_Commenting_VariableCommentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php', - 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php', - 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php', - 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php', - 'Squiz_Sniffs_Debug_JSLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php', - 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php', - 'Squiz_Sniffs_Files_FileExtensionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php', - 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php', - 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php', - 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php', - 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php', - 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php', - 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php', - 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php', - 'Squiz_Sniffs_NamingConventions_ConstantCaseSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php', - 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php', - 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php', - 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php', - 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php', - 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php', - 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php', - 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php', - 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php', - 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php', - 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php', - 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php', - 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php', - 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php', - 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php', - 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php', - 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php', - 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php', - 'Squiz_Sniffs_PHP_EvalSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php', - 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php', - 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php', - 'Squiz_Sniffs_PHP_HeredocSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php', - 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php', - 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php', - 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php', - 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php', - 'Squiz_Sniffs_Scope_MethodScopeSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php', - 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php', - 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php', - 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php', - 'Squiz_Sniffs_Strings_EchoedStringsSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php', - 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php', - 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php', - 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php', - 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php', - 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php', - 'Zend_Sniffs_Files_ClosingTagSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php', - 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/../..' . '/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->classMap = ComposerStaticInit139aa91c62d198426cb28d1274c47616::$classMap; - - }, null, ClassLoader::class); - } -} diff --git a/codesniffer/vendor/composer/installed.json b/codesniffer/vendor/composer/installed.json deleted file mode 100644 index fe51488c7..000000000 --- a/codesniffer/vendor/composer/installed.json +++ /dev/null @@ -1 +0,0 @@ -[] From 298ea3063e310022a45189992249b168105f1588 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Thu, 29 Dec 2016 20:30:00 +0900 Subject: [PATCH 5201/5359] remove PHP_Codesniffer-VariableAnalysis --- .gitignore | 1 + PHP_Codesniffer-VariableAnalysis | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 160000 PHP_Codesniffer-VariableAnalysis diff --git a/.gitignore b/.gitignore index ba2e83349..bf98b40a3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ PHAR_BUILD_VERSION /*.phar /phpunit.xml.dist /codesniffer +/PHP_Codesniffer-VariableAnalysis diff --git a/PHP_Codesniffer-VariableAnalysis b/PHP_Codesniffer-VariableAnalysis deleted file mode 160000 index 8a126e511..000000000 --- a/PHP_Codesniffer-VariableAnalysis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8a126e5114725d3cf93db7aff404541e6e47da72 From 01b43e120b15dbe706b9aaa0587711352594232c Mon Sep 17 00:00:00 2001 From: miya0001 Date: Thu, 29 Dec 2016 22:49:32 +0900 Subject: [PATCH 5202/5359] fit to coding style --- php/WP_CLI/Completions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 235c9cefa..06e9ed50e 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -123,8 +123,7 @@ private function get_command( $words ) { return array( $command, $args, $assoc_args ); } - private function get_global_parameters() - { + private function get_global_parameters() { $params = array(); foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { if ( false === $details['runtime'] ) { From 6154dcab40027ebcb9e7ffb92b5767c00661594a Mon Sep 17 00:00:00 2001 From: miya0001 Date: Thu, 29 Dec 2016 23:02:17 +0900 Subject: [PATCH 5203/5359] add feature that checks duplicated parameter --- features/cli-bash-completion.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index 52c5fba3e..c63ff5efd 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -283,3 +283,7 @@ Feature: `wp cli completions` tasks """ --prompt= """ + Then STDOUT should not contain: + """ + --path + """ From 0aeba7939aa36085863605e08c8a0dba2d77e273 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Thu, 29 Dec 2016 23:38:44 +0900 Subject: [PATCH 5204/5359] add global param like --[no-]color to bash completion --- features/cli-bash-completion.feature | 10 ++++++++++ php/WP_CLI/Completions.php | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature index c63ff5efd..2f18cbc04 100644 --- a/features/cli-bash-completion.feature +++ b/features/cli-bash-completion.feature @@ -251,6 +251,10 @@ Feature: `wp cli completions` tasks """ --color """ + And STDOUT should contain: + """ + --no-color + """ And STDOUT should contain: """ --debug= @@ -287,3 +291,9 @@ Feature: `wp cli completions` tasks """ --path """ + + When I run `wp cli completions --line="wp plugin list --no-color" --point=100` + Then STDOUT should not contain: + """ + --no-color + """ diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php index 06e9ed50e..17484dd42 100644 --- a/php/WP_CLI/Completions.php +++ b/php/WP_CLI/Completions.php @@ -134,6 +134,11 @@ private function get_global_parameters() { continue; } $params[ $key ] = $details["runtime"]; + + // Add additional option like `--[no-]color`. + if ( true === $details["runtime"] ) { + $params[ "no-" . $key ] = ''; + } } return $params; From b01d48c7e8353a89e7ac1668dd30ea69f99944b9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 29 Dec 2016 08:04:19 -0800 Subject: [PATCH 5205/5359] Update Composer dependencies (12/29/16) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing justinrainbow/json-schema (2.0.5) - Installing justinrainbow/json-schema (4.1.0) Downloading: 100% - Removing composer/composer (1.2.4) - Installing composer/composer (1.3.0) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/composer.lock b/composer.lock index ada826660..e28fde9b8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ce8fdbbf904758ec2297424e667a20c1", - "content-hash": "66db43f8d349f59c6dd42f72a8638b22", + "hash": "26a79764e47184c9c96e4a395e7300cc", + "content-hash": "44729ff3377aebb57316ab4ddbc370a9", "packages": [ { "name": "composer/ca-bundle", @@ -67,32 +67,32 @@ }, { "name": "composer/composer", - "version": "1.2.4", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0" + "reference": "e53f9e5381e70f76e098136343e27d92601eade7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0", - "reference": "7895e4a7e0e05b06e0ebfae96fc154c6a2ba75f0", + "url": "https://api.github.com/repos/composer/composer/zipball/e53f9e5381e70f76e098136343e27d92601eade7", + "reference": "e53f9e5381e70f76e098136343e27d92601eade7", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", "composer/semver": "^1.0", "composer/spdx-licenses": "^1.0", - "justinrainbow/json-schema": "^1.6 || ^2.0", + "justinrainbow/json-schema": "^1.6 || ^2.0 || ^3.0 || ^4.0", "php": "^5.3.2 || ^7.0", "psr/log": "^1.0", "seld/cli-prompt": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.5 || ^3.0", - "symfony/filesystem": "^2.5 || ^3.0", - "symfony/finder": "^2.2 || ^3.0", - "symfony/process": "^2.1 || ^3.0" + "symfony/console": "^2.7 || ^3.0", + "symfony/filesystem": "^2.7 || ^3.0", + "symfony/finder": "^2.7 || ^3.0", + "symfony/process": "^2.7 || ^3.0" }, "require-dev": { "phpunit/phpunit": "^4.5 || ^5.0.5", @@ -109,7 +109,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2016-12-06 21:00:51" + "time": "2016-12-23 23:47:04" }, { "name": "composer/semver", @@ -267,16 +267,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "2.0.5", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67" + "reference": "d39c56a46b3ebe1f3696479966cd2b9f50aaa24f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/6b2a33e6a768f96bdc2ead5600af0822eed17d67", - "reference": "6b2a33e6a768f96bdc2ead5600af0822eed17d67", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/d39c56a46b3ebe1f3696479966cd2b9f50aaa24f", + "reference": "d39c56a46b3ebe1f3696479966cd2b9f50aaa24f", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -329,7 +329,7 @@ "json", "schema" ], - "time": "2016-06-02 10:59:52" + "time": "2016-12-22 16:43:46" }, { "name": "mustache/mustache", From a03f0a1a36c165ed02e03fde9e9ebabc8772ffcc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 29 Dec 2016 14:56:56 -0800 Subject: [PATCH 5206/5359] Fix PHP notice from the wrong type hint --- php/WP_CLI/PackageManagerEventSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index fb540ee89..9d671eb56 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -5,7 +5,7 @@ use \Composer\DependencyResolver\Rule; use \Composer\EventDispatcher\Event; use \Composer\EventDispatcher\EventSubscriberInterface; -use \Composer\Script\PackageEvent; +use \Composer\Installer\PackageEvent; use \Composer\Script\ScriptEvents; use \WP_CLI; From 97cfc16a2604bc8f78c80888943af47b7e86c482 Mon Sep 17 00:00:00 2001 From: Eduardo Pittol Date: Fri, 30 Dec 2016 02:47:28 -0200 Subject: [PATCH 5207/5359] Set the path global parameter as docroot in server command The default internal server docroot must be the path directory set as global parameter or in the configuration file. --- php/commands/server.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/commands/server.php b/php/commands/server.php index af92cf2f2..5f751d096 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -23,7 +23,8 @@ class Server_Command extends WP_CLI_Command { * --- * * [--docroot=] - * : The path to use as the document root. + * : The path to use as the document root. If the path global parameter is + * set, the default value is it. * * [--config=] * : Configure the server with a specific .ini file. @@ -62,7 +63,7 @@ function __invoke( $_, $assoc_args ) { $defaults = array( 'host' => 'localhost', 'port' => 8080, - 'docroot' => false, + 'docroot' => ! is_null( WP_CLI::get_runner()->config['path'] ) ? WP_CLI::get_runner()->config['path'] : false, 'config' => get_cfg_var( 'cfg_file_path' ) ); $assoc_args = array_merge( $defaults, $assoc_args ); From e2f3accb2a771d053ee4edcca1026d01409bbded Mon Sep 17 00:00:00 2001 From: miya0001 Date: Mon, 2 Jan 2017 02:21:38 +0900 Subject: [PATCH 5208/5359] allow dot in aliases --- php/WP_CLI/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index d9c0147c0..434ac37bf 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -32,7 +32,7 @@ class Configurator { /** * @var string ALIAS_REGEX Regex pattern used to define an alias */ - const ALIAS_REGEX = '^@[A-Za-z0-9-_]+$'; + const ALIAS_REGEX = '^@[A-Za-z0-9-_\.]+$'; /** * @var array ALIAS_SPEC Arguments that can be used in an alias From 13719357e349d07633ccae4186b0e119c0fde384 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Mon, 2 Jan 2017 02:25:51 +0900 Subject: [PATCH 5209/5359] allow '-' in aliases --- php/WP_CLI/Configurator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 434ac37bf..ce1dce901 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -32,7 +32,7 @@ class Configurator { /** * @var string ALIAS_REGEX Regex pattern used to define an alias */ - const ALIAS_REGEX = '^@[A-Za-z0-9-_\.]+$'; + const ALIAS_REGEX = '^@[A-Za-z0-9-_\.\-]+$'; /** * @var array ALIAS_SPEC Arguments that can be used in an alias From 36d94998415efb8de45b6d0143d57a51c3aa85ab Mon Sep 17 00:00:00 2001 From: miya0001 Date: Tue, 3 Jan 2017 10:10:56 +0900 Subject: [PATCH 5210/5359] add `--force` option to `core config` --- features/core-config.feature | 18 ++++++++++++++++++ php/commands/core.php | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/features/core-config.feature b/features/core-config.feature index 7bc199c25..f4fbfeec1 100644 --- a/features/core-config.feature +++ b/features/core-config.feature @@ -79,3 +79,21 @@ Feature: Manage wp-config """ define( 'WPLANG', '' ); """ + + When I try `wp core config {CORE_CONFIG_SETTINGS}` + Then the return code should be 1 + And STDERR should contain: + """ + Error: The 'wp-config.php' file already exists. + """ + + When I run `wp core config {CORE_CONFIG_SETTINGS} --locale=ja --force` + Then the return code should be 0 + And STDOUT should contain: + """ + Success: Generated 'wp-config.php' file. + """ + And the wp-config.php file should contain: + """ + define( 'WPLANG', 'ja' ); + """ diff --git a/php/commands/core.php b/php/commands/core.php index f6c3c2ffb..43449c5f4 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -332,6 +332,9 @@ private static function get_initial_locale() { * [--skip-check] * : If set, the database connection is not checked. * + * [--force] + * : If set, the database connection is not checked. + * * ## EXAMPLES * * # Standard wp-config.php file @@ -351,7 +354,7 @@ private static function get_initial_locale() { */ public function config( $_, $assoc_args ) { global $wp_version; - if ( Utils\locate_wp_config() ) { + if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && Utils\locate_wp_config() ) { WP_CLI::error( "The 'wp-config.php' file already exists." ); } From 0656f374f792c05752d51e73b1787920d54163f9 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Tue, 3 Jan 2017 10:14:02 +0900 Subject: [PATCH 5211/5359] update doc comment --- php/commands/core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/core.php b/php/commands/core.php index 43449c5f4..ecb593f00 100644 --- a/php/commands/core.php +++ b/php/commands/core.php @@ -333,7 +333,7 @@ private static function get_initial_locale() { * : If set, the database connection is not checked. * * [--force] - * : If set, the database connection is not checked. + * : Overwrites existing files, if present. * * ## EXAMPLES * From a4c8c9da1ed502c97b5685258885aa85d6c8a319 Mon Sep 17 00:00:00 2001 From: Kailey Lampert Date: Mon, 2 Jan 2017 19:41:57 -0800 Subject: [PATCH 5212/5359] Matching bracket fix in docs --- php/class-wp-cli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index b9caba3df..595371a6f 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -182,7 +182,7 @@ public static function get_http_cache_manager() { * * %U => ['style' => 'underline'], * * %8 => ['style' => 'inverse'], * * %9 => ['style' => 'bright'], - * * %_ => ['style' => 'bright') + * * %_ => ['style' => 'bright'] * * @access public * @category Output From 9573cfc11c6b19dd5eaf34e4dfde0a71967e96fa Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 4 Jan 2017 06:23:44 -0800 Subject: [PATCH 5213/5359] Failing test case for #3656 --- tests/test-search-replace.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php index 6b5cd27de..c08a8a475 100644 --- a/tests/test-search-replace.php +++ b/tests/test-search-replace.php @@ -37,6 +37,20 @@ function testArrayLoop() { $this->assertEquals( 'bar', $new_array['prop'] ); } + function testArraySameValues() { + $old_array = array( + 'prop1' => array( + 'foo', + ), + 'prop2' => array( + 'foo', + ), + ); + $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); + $this->assertEquals( 'bar', $new_array['prop1'][0] ); + $this->assertEquals( 'bar', $new_array['prop2'][0] ); + } + function testMixedObjectArrayLoop() { $old_object = new stdClass(); $old_object->prop = 'foo'; From 5dd78946bf7d6adf5e188a85d30baa49092e08c0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 4 Jan 2017 16:00:19 -0800 Subject: [PATCH 5214/5359] Failed attempt at detecting the reference to itself --- php/WP_CLI/SearchReplacer.php | 54 ++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index c8f9b7577..a3c6b21e9 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -56,8 +56,25 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data if ( is_array( $data ) || is_object( $data ) ) { // If we've seen this exact object or array before, short circuit + // Avoid infinite loops when there's a cycle if ( in_array( $data, $visited_data, true ) ) { - return $data; // Avoid infinite loops when there's a cycle + if ( is_object( $data ) ) { + return $data; + } + // Only short-circuit when the array is passed by reference + if ( is_array( $data ) ) { + $k = array_search( $data, $visited_data ); + $existing_data = $visited_data[ $k ]; + if ( self::check_arrays_referenced( $data, $existing_data ) ) { + return $data; + } + // Now check to see if any child values are references + foreach( $existing_data as $i => $j ) { + if ( self::check_arrays_referenced( $data, $j ) ) { + return $data; + } + } + } } // Add this data to the list of $visited_data[] = $data; @@ -98,5 +115,40 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data return $data; } + + /** + * Check if two arrays are a reference to one another + * + * @param $var1 array + * @param $var2 array + * @return boolean + */ + private static function check_arrays_referenced( $var1, $var2 ) { + $same = false; + if ( ! is_array( $var1 ) + || ! is_array( $var2 ) + || $var1 !== $var2 ) { + return $same; + } + // Detect when an array is a reference + // by assigning a value to a key that doesn't yet + // exist and seeing if the original array is modified + // Unfortunately, there isn't a better way to detect + // references in PHP. + do { + $k = uniqid( 'is_ref_', true ); + } while( array_key_exists( $k, $var1 ) ); + $test_data = uniqid( 'is_ref_data_', true ); + $var1[ $k ] = &$test_data; + // This looks like a reference, so short circuit early + if ( array_key_exists( $k, $var2 ) + && $var2[ $k ] === $var1[ $k ] ) { + $same = true; + } + // Wasn't a reference, so let's clean the original data + unset( $var1[ $k ] ); + return $same; + } + } From 0e1fa37afaa3633223d2e257e60e312fa8791b7a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 4 Jan 2017 17:20:25 -0800 Subject: [PATCH 5215/5359] An amazingly hacky way to detect self-referential recursion --- php/WP_CLI/SearchReplacer.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index a3c6b21e9..4e50fe8ed 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -68,10 +68,17 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data if ( self::check_arrays_referenced( $data, $existing_data ) ) { return $data; } - // Now check to see if any child values are references - foreach( $existing_data as $i => $j ) { - if ( self::check_arrays_referenced( $data, $j ) ) { - return $data; + // Check to see if any child values are going to cause + // recursion. If so, assume $data is storing a reference + // to itself + foreach( $data as $k => $v ) { + if ( $v === $data ) { + ob_start(); + var_dump( $v ); + $export = ob_get_clean(); + if ( stripos( $export, '*RECURSION*' ) ) { + return $data; + } } } } From 813bbaef6108bba2cb54270e837701eab6e2c716 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 5 Jan 2017 05:38:46 -0800 Subject: [PATCH 5216/5359] Bail if array has already been processed and PHP detects recursion Ideally, we'd be more precise than this. Reference variables are such an edge case, particularly because we're processing database data, that I think this is sufficient. --- php/WP_CLI/SearchReplacer.php | 54 +++-------------------------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index 4e50fe8ed..610e19463 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -63,24 +63,12 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data } // Only short-circuit when the array is passed by reference if ( is_array( $data ) ) { - $k = array_search( $data, $visited_data ); - $existing_data = $visited_data[ $k ]; - if ( self::check_arrays_referenced( $data, $existing_data ) ) { + ob_start(); + print_r( $data ); + $test = ob_get_clean(); + if ( preg_match( '#\*RECURSION\*#', $test ) ) { return $data; } - // Check to see if any child values are going to cause - // recursion. If so, assume $data is storing a reference - // to itself - foreach( $data as $k => $v ) { - if ( $v === $data ) { - ob_start(); - var_dump( $v ); - $export = ob_get_clean(); - if ( stripos( $export, '*RECURSION*' ) ) { - return $data; - } - } - } } } // Add this data to the list of @@ -123,39 +111,5 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data return $data; } - /** - * Check if two arrays are a reference to one another - * - * @param $var1 array - * @param $var2 array - * @return boolean - */ - private static function check_arrays_referenced( $var1, $var2 ) { - $same = false; - if ( ! is_array( $var1 ) - || ! is_array( $var2 ) - || $var1 !== $var2 ) { - return $same; - } - // Detect when an array is a reference - // by assigning a value to a key that doesn't yet - // exist and seeing if the original array is modified - // Unfortunately, there isn't a better way to detect - // references in PHP. - do { - $k = uniqid( 'is_ref_', true ); - } while( array_key_exists( $k, $var1 ) ); - $test_data = uniqid( 'is_ref_data_', true ); - $var1[ $k ] = &$test_data; - // This looks like a reference, so short circuit early - if ( array_key_exists( $k, $var2 ) - && $var2[ $k ] === $var1[ $k ] ) { - $same = true; - } - // Wasn't a reference, so let's clean the original data - unset( $var1[ $k ] ); - return $same; - } - } From 4930b95983c79f58397f4eca2e6833290589d973 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 5 Jan 2017 06:04:15 -0800 Subject: [PATCH 5217/5359] Prevent error notice from `wp_guess_url()` when core isn't installed WordPress 4.7 attempts to log a user in after installing. Included in this was a change to `wp_cookie_constants()` such that it uses `wp_guess_url()` to set the default `COOKIEHASH`, instead of an empty string. Because CLI doesn't use cookies, we can prevent this notice by setting `COOKIEHASH` earlier. --- php/WP_CLI/Runner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 8a25eb466..45e65aa47 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -990,6 +990,12 @@ public function load_wordpress() { $this->maybe_update_url_from_domain_constant(); WP_CLI::do_hook( 'after_wp_config_load' ); + // Prevent error notice from wp_guess_url() when core isn't installed + if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) + && ! defined( 'COOKIEHASH' ) ) { + define( 'COOKIEHASH', md5( 'wp-cli' ) ); + } + // Load WP-CLI utilities require WP_CLI_ROOT . '/php/utils-wp.php'; From 69c978b38e5264eaf3824e7fc4bb2c3ece95b7fe Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 5 Jan 2017 06:44:20 -0800 Subject: [PATCH 5218/5359] Introduce a Behat step for replacing a string in a file This is more useful than using `sed` --- features/core-verify-checksums.feature | 5 +++-- features/core.feature | 2 +- features/steps/given.php | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature index 0721b897c..6c73cff5e 100644 --- a/features/core-verify-checksums.feature +++ b/features/core-verify-checksums.feature @@ -12,8 +12,9 @@ Feature: Validate checksums for WordPress install Success: WordPress install verifies against checksums. """ - When I run `sed -i.bak s/WordPress/Wordpress/g readme.html` - Then STDERR should be empty + Scenario: Core checksums don't verify + Given a WP install + And "WordPress" replaced with "Wordpress" in the readme.html file When I try `wp core verify-checksums` Then STDERR should be: diff --git a/features/core.feature b/features/core.feature index de3d601d0..3e98de5bc 100644 --- a/features/core.feature +++ b/features/core.feature @@ -356,7 +356,7 @@ Feature: Manage WordPress installation Scenario: Warn when multisite constants can't be inserted into wp-config Given a WP install - And I run `sed -i.bak "s/That's\sall/C'est tout/g" wp-config.php` + And "That's all" replaced with "C'est tout" in the wp-config.php file When I run `wp core multisite-convert` Then STDOUT should be: diff --git a/features/steps/given.php b/features/steps/given.php index 017d1a5d8..0c027e758 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -25,6 +25,13 @@ function ( $world, $path, PyStringNode $content ) { } ); +$steps->Given( '/^"([^"]+)" replaced with "([^"]+)" in the ([^\s]+) file$/', function( $world, $search, $replace, $path ) { + $full_path = $world->variables['RUN_DIR'] . "/$path"; + $contents = file_get_contents( $full_path ); + $contents = str_replace( $search, $replace, $contents ); + file_put_contents( $full_path, $contents ); +}); + $steps->Given( '/^WP files$/', function ( $world ) { $world->download_wp(); From 29be5438463cc8a7310bd0d87f9a9ccb43f4e65a Mon Sep 17 00:00:00 2001 From: James Nylen Date: Fri, 6 Jan 2017 05:21:37 -0600 Subject: [PATCH 5219/5359] Back out #3708 except for the test --- php/WP_CLI/SearchReplacer.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index 610e19463..c8f9b7577 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -56,20 +56,8 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data if ( is_array( $data ) || is_object( $data ) ) { // If we've seen this exact object or array before, short circuit - // Avoid infinite loops when there's a cycle if ( in_array( $data, $visited_data, true ) ) { - if ( is_object( $data ) ) { - return $data; - } - // Only short-circuit when the array is passed by reference - if ( is_array( $data ) ) { - ob_start(); - print_r( $data ); - $test = ob_get_clean(); - if ( preg_match( '#\*RECURSION\*#', $test ) ) { - return $data; - } - } + return $data; // Avoid infinite loops when there's a cycle } // Add this data to the list of $visited_data[] = $data; @@ -110,6 +98,5 @@ private function _run( $data, $serialised, $recursion_level = 0, &$visited_data return $data; } - } From ff107850faa7a087303fb07d56b37181801b7035 Mon Sep 17 00:00:00 2001 From: James Nylen Date: Fri, 6 Jan 2017 05:35:21 -0600 Subject: [PATCH 5220/5359] Fix search-replace cycle detection --- php/WP_CLI/SearchReplacer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php index c8f9b7577..1db298198 100644 --- a/php/WP_CLI/SearchReplacer.php +++ b/php/WP_CLI/SearchReplacer.php @@ -42,7 +42,7 @@ function run( $data, $serialised = false ) { * @param int $recursion_level Current recursion depth within the original data. * @param array $visited_data Data that has been seen in previous recursion iterations. */ - private function _run( $data, $serialised, $recursion_level = 0, &$visited_data = array() ) { + private function _run( $data, $serialised, $recursion_level = 0, $visited_data = array() ) { // some unseriliased data cannot be re-serialised eg. SimpleXMLElements try { From 87381caf3121bd2d967d31d83f5a64130dc48187 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Fri, 6 Jan 2017 07:26:56 -0800 Subject: [PATCH 5221/5359] Explicitly set default cache group as 'default' WordPress' object cache treats an empty cache group as 'default'. WP-CLI should make this behavior more explicit. --- features/cache.feature | 134 +++++++++++++++++++++++++++++++++++++++++ php/commands/cache.php | 77 ++++++++++++----------- 2 files changed, 171 insertions(+), 40 deletions(-) create mode 100644 features/cache.feature diff --git a/features/cache.feature b/features/cache.feature new file mode 100644 index 000000000..472f28d19 --- /dev/null +++ b/features/cache.feature @@ -0,0 +1,134 @@ +Feature: Managed the WordPress object cache + + Scenario: Default group is 'default' + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + ] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * [] * : Define how long to keep the value, in seconds. `0` means as long as possible. @@ -49,11 +52,7 @@ class Cache_Command extends WP_CLI_Command { * Success: Added object 'my_key' in group 'my_value'. */ public function add( $args, $assoc_args ) { - list( $key, $value ) = $args; - - $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - - $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); + list( $key, $value, $group, $expiration ) = $args; if ( ! wp_cache_add( $key, $value, $group, $expiration ) ) { WP_CLI::error( "Could not add object '$key' in group '$group'. Does it already exist?" ); @@ -73,10 +72,16 @@ public function add( $args, $assoc_args ) { * : Cache key. * * [] - * : The amount by which to decrement the item's value. Default is 1. + * : The amount by which to decrement the item's value. + * --- + * default: 1 + * --- * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * ## EXAMPLES * @@ -85,12 +90,7 @@ public function add( $args, $assoc_args ) { * 48 */ public function decr( $args, $assoc_args ) { - $key = $args[0]; - - $offset = \WP_CLI\Utils\get_flag_value( $args, 1, 1 ); - - $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - + list( $key, $offset, $group ) = $args; $value = wp_cache_decr( $key, $offset, $group ); if ( false === $value ) { @@ -112,6 +112,9 @@ public function decr( $args, $assoc_args ) { * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * ## EXAMPLES * @@ -120,10 +123,7 @@ public function decr( $args, $assoc_args ) { * Success: Object deleted. */ public function delete( $args, $assoc_args ) { - $key = $args[0]; - - $group = \WP_CLI\Utils\get_flag_value( $args, 1, '' ); - + list( $key, $group ) = $args; $result = wp_cache_delete( $key, $group ); if ( false === $result ) { @@ -171,6 +171,9 @@ public function flush( $args, $assoc_args ) { * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * ___ * * ## EXAMPLES * @@ -179,10 +182,7 @@ public function flush( $args, $assoc_args ) { * my_value */ public function get( $args, $assoc_args ) { - $key = $args[0]; - - $group = \WP_CLI\Utils\get_flag_value( $args, 1, '' ); - + list( $key, $group ) = $args; $value = wp_cache_get( $key, $group ); if ( false === $value ) { @@ -203,10 +203,16 @@ public function get( $args, $assoc_args ) { * : Cache key. * * [] - * : The amount by which to increment the item's value. Default is 1. + * : The amount by which to increment the item's value. + * --- + * default: 1 + * --- * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * ## EXAMPLES * @@ -215,12 +221,7 @@ public function get( $args, $assoc_args ) { * 50 */ public function incr( $args, $assoc_args ) { - $key = $args[0]; - - $offset = \WP_CLI\Utils\get_flag_value( $args, 1, 1 ); - - $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - + list( $key, $offset, $group ) = $args; $value = wp_cache_incr( $key, $offset, $group ); if ( false === $value ) { @@ -245,6 +246,9 @@ public function incr( $args, $assoc_args ) { * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * [] * : Define how long to keep the value, in seconds. `0` means as long as possible. @@ -259,16 +263,11 @@ public function incr( $args, $assoc_args ) { * Success: Replaced object 'my_key' in group 'my_group'. */ public function replace( $args, $assoc_args ) { - list( $key, $value ) = $args; - - $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - - $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); - + list( $key, $value, $group, $expiration ) = $args; $result = wp_cache_replace( $key, $value, $group, $expiration ); if ( false === $result ) { - WP_CLI::error( "Could not replace object '$key' in group '$group'. Does it already exist?" ); + WP_CLI::error( "Could not replace object '$key' in group '$group'. Does it not exist?" ); } WP_CLI::success( "Replaced object '$key' in group '$group'." ); @@ -289,6 +288,9 @@ public function replace( $args, $assoc_args ) { * * [] * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- * * [] * : Define how long to keep the value, in seconds. `0` means as long as possible. @@ -303,12 +305,7 @@ public function replace( $args, $assoc_args ) { * Success: Set object 'my_key' in group 'my_group'. */ public function set( $args, $assoc_args ) { - list( $key, $value ) = $args; - - $group = \WP_CLI\Utils\get_flag_value( $args, 2, '' ); - - $expiration = \WP_CLI\Utils\get_flag_value( $args, 3, 0 ); - + list( $key, $value, $group, $expiration ) = $args; $result = wp_cache_set( $key, $value, $group, $expiration ); if ( false === $result ) { From 83720eeb7df9bf4bc11d3d4d1e16bca2812e9432 Mon Sep 17 00:00:00 2001 From: metodiew Date: Mon, 9 Jan 2017 15:19:13 +0200 Subject: [PATCH 5222/5359] Fix the user delete example in the documentation. Fixes #3719 --- php/commands/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/user.php b/php/commands/user.php index dd6a4d115..909181b50 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -235,7 +235,7 @@ public function get( $args, $assoc_args ) { * Success: Removed user 123 from http://example.com * * # Delete all contributors and reassign their posts to user 2 - * $ wp user delete $(wp user list --role=contributor --format=ids) --reassign=2 + * $ wp user delete $(wp user list --role=contributor --field=ID) --reassign=2 * Success: Removed user 813 from http://example.com * Success: Removed user 578 from http://example.com */ From 8c31ef3b1538f2b19304f9bb8f36458102c9f274 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 9 Jan 2017 06:00:21 -0800 Subject: [PATCH 5223/5359] Update Composer dependencies (1/9/2017) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing composer/composer (1.3.0) - Installing composer/composer (1.3.1) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index e28fde9b8..3f1ebec83 100644 --- a/composer.lock +++ b/composer.lock @@ -67,16 +67,16 @@ }, { "name": "composer/composer", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "e53f9e5381e70f76e098136343e27d92601eade7" + "reference": "91dbca556764dcece45e1ba3aab14de2deaa9fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e53f9e5381e70f76e098136343e27d92601eade7", - "reference": "e53f9e5381e70f76e098136343e27d92601eade7", + "url": "https://api.github.com/repos/composer/composer/zipball/91dbca556764dcece45e1ba3aab14de2deaa9fec", + "reference": "91dbca556764dcece45e1ba3aab14de2deaa9fec", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2016-12-23 23:47:04" + "time": "2017-01-07 17:08:51" }, { "name": "composer/semver", From 777073a95f5dbc95628b597f2f8cb75c9fed6af5 Mon Sep 17 00:00:00 2001 From: Ross Wintle Date: Tue, 10 Jan 2017 14:18:53 +0000 Subject: [PATCH 5224/5359] Add check for invalid theme slug in wp scaffold _s --- php/commands/scaffold.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 5c5347d96..083fada56 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -243,6 +243,10 @@ public function _s( $args, $assoc_args ) { WP_CLI::error( "Invalid theme slug specified." ); } + if ( ! preg_match( '/^[a-z_]\w+$/i', str_replace( '-', '_', $theme_slug ) ) ) { + WP_CLI::error( "Invalid theme slug specified." ); + } + $data = wp_parse_args( $assoc_args, array( 'theme_name' => ucfirst( $theme_slug ), 'author' => "Me", From d9057015efbad8679d951f97192f76624941bdb9 Mon Sep 17 00:00:00 2001 From: Ross Wintle Date: Tue, 10 Jan 2017 14:43:40 +0000 Subject: [PATCH 5225/5359] Improved error message for invalid theme slug check. --- php/commands/scaffold.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 083fada56..321a9b259 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -244,7 +244,7 @@ public function _s( $args, $assoc_args ) { } if ( ! preg_match( '/^[a-z_]\w+$/i', str_replace( '-', '_', $theme_slug ) ) ) { - WP_CLI::error( "Invalid theme slug specified." ); + WP_CLI::error( "Invalid theme slug specified. Theme slugs can only contain letters, numbers, underscores and hyphens, and can only start with a letter or underscore." ); } $data = wp_parse_args( $assoc_args, array( From d03ada793af08b1e7a8028b290444f977fef719d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 11 Jan 2017 11:15:33 -0800 Subject: [PATCH 5226/5359] Support CSV for `role__in` and `role__not_in` arguments --- features/user-list.feature | 28 ++++++++++++++++++++++++++++ php/commands/user.php | 7 +++++++ 2 files changed, 35 insertions(+) create mode 100644 features/user-list.feature diff --git a/features/user-list.feature b/features/user-list.feature new file mode 100644 index 000000000..44856eb01 --- /dev/null +++ b/features/user-list.feature @@ -0,0 +1,28 @@ +Feature: List WordPress users + + @require-wp-4.4 + Scenario: List users of specific roles + Given a WP install + And I run `wp user create bobjones bob@example.com --role=author` + And I run `wp user create sally sally@example.com --role=editor` + + When I run `wp user list --field=user_login` + Then STDOUT should be: + """ + admin + bobjones + sally + """ + + When I run `wp user list --role__in=administrator,editor --field=user_login` + Then STDOUT should be: + """ + admin + sally + """ + + When I run `wp user list --role__not_in=administrator,editor --field=user_login` + Then STDOUT should be: + """ + bobjones + """ diff --git a/php/commands/user.php b/php/commands/user.php index 909181b50..4dba841cd 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -144,6 +144,13 @@ public function list_( $args, $assoc_args ) { } $assoc_args['count_total'] = false; + + foreach( $assoc_args as $k => $v ) { + if ( false !== strpos( $k, '__' ) ) { + $assoc_args[ $k ] = explode( ',', $v ); + } + } + $users = get_users( $assoc_args ); if ( 'ids' == $formatter->format ) { From eda030d511d17586b81e004cd8bc6d4861d23422 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 11 Jan 2017 12:15:56 -0800 Subject: [PATCH 5227/5359] Update tests for WordPress 4.7.1 --- features/core-check-update.feature | 10 +++++----- features/core-update.feature | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 6abfca4bb..36c5b6cf4 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,8 +9,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7 | major | https://downloads.wordpress.org/release/wordpress-4.7.zip | - | 4.4.5 | minor | https://downloads.wordpress.org/release/wordpress-4.4.5-partial-0.zip | + | 4.7.1 | major | https://downloads.wordpress.org/release/wordpress-4.7.1.zip | + | 4.4.6 | minor | https://downloads.wordpress.org/release/wordpress-4.4.6-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7 | major | https://downloads.wordpress.org/release/wordpress-4.7.zip | + | 4.7.1 | major | https://downloads.wordpress.org/release/wordpress-4.7.1.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -32,7 +32,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.5 | minor | https://downloads.wordpress.org/release/wordpress-4.4.5-partial-0.zip | + | 4.4.6 | minor | https://downloads.wordpress.org/release/wordpress-4.4.6-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -53,4 +53,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.13 | minor | https://downloads.wordpress.org/release/wordpress-4.0.13-partial-0.zip | + | 4.0.14 | minor | https://downloads.wordpress.org/release/wordpress-4.0.14-partial-0.zip | diff --git a/features/core-update.feature b/features/core-update.feature index 0fdd7deee..8b2305414 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.16 + Updating to version 3.7.17 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.16 + 3.7.17 """ @less-than-php-7 @@ -208,8 +208,8 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 4.0.13 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.13-partial-0.zip + Updating to version 4.0.14 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.14-partial-0.zip """ And STDOUT should contain: """ From b12cbffb8ee7a725b698f829fdf9baa438a77d1f Mon Sep 17 00:00:00 2001 From: Ross Wintle Date: Wed, 11 Jan 2017 22:41:59 +0000 Subject: [PATCH 5228/5359] Added functional test for new invalid slug check --- features/scaffold.feature | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/features/scaffold.feature b/features/scaffold.feature index ceaab08bf..4e09bb223 100644 --- a/features/scaffold.feature +++ b/features/scaffold.feature @@ -341,6 +341,11 @@ Feature: WordPress code scaffolding """ Error: Invalid theme slug specified. """ + When I try `wp scaffold _s 1themestartingwithnumber` + Then STDERR should contain: + """ + Error: Invalid theme slug specified. Theme slugs can only contain letters, numbers, underscores and hyphens, and can only start with a letter or underscore. + """ Scenario: Scaffold plugin and tests for non-standard plugin directory Given a WP install From b3ff023633cb4eb8fb5f666209605effb4b53812 Mon Sep 17 00:00:00 2001 From: Brian Geihsler Date: Wed, 11 Jan 2017 21:36:55 -0800 Subject: [PATCH 5229/5359] Fix runcommand's proc_open to inherit parent environment This fixes #3729. proc_open will inherit the parent environment if you pass NULL for the environment parameter (http://php.net/manual/en/function.proc-open.php). I've verified that this works properly by testing this fix against my wp-config that contained environment variables. --- php/class-wp-cli.php | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 595371a6f..3b69d4107 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -1018,23 +1018,7 @@ public static function runcommand( $command, $options = array() ) { $runcommand = "{$php_bin} {$script_path} {$runtime_config} {$command}"; - $env_vars = array( - 'HOME', - 'PATH', - 'WP_CLI_AUTO_CHECK_UPDATE_DAYS', - 'WP_CLI_CACHE_DIR', - 'WP_CLI_CONFIG_PATH', - 'WP_CLI_DISABLE_AUTO_CHECK_UPDATE', - 'WP_CLI_PACKAGES_DIR', - 'WP_CLI_PHP_USED', - 'WP_CLI_PHP', - 'WP_CLI_STRICT_ARGS_MODE', - ); - $env = array(); - foreach( $env_vars as $var ) { - $env[ $var ] = getenv( $var ); - } - $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), $env ); + $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), NULL ); if ( $return ) { $stdout = stream_get_contents( $pipes[1] ); @@ -1155,4 +1139,3 @@ public static function addCommand( $name, $class ) { self::add_command( $name, $class ); } } - From ff68f05e2f071ff5751202a6ab4f7568b903cfc7 Mon Sep 17 00:00:00 2001 From: Ross Wintle Date: Thu, 12 Jan 2017 15:23:36 +0000 Subject: [PATCH 5230/5359] Remove statement in docs that search-replace skips 'guid' column by default. It doesn't. --- php/commands/search-replace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index ab57a1db0..cb9c56cad 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -64,7 +64,7 @@ class Search_Replace_Command extends WP_CLI_Command { * * [--skip-columns=] * : Do not perform the replacement on specific columns. Use commas to - * specify multiple columns. 'guid' is skipped by default. + * specify multiple columns. * * [--include-columns=] * : Perform the replacement on specific columns. Use commas to From da6a0142c1374d39c15be188a81b6b8d0009e32d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 14 Jan 2017 22:45:14 -0800 Subject: [PATCH 5231/5359] Opt-in to container-based infrastructure for plugin Travis CI template config See https://docs.travis-ci.com/user/migrating-from-legacy/ --- templates/plugin-travis.mustache | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 3fa9a0650..9533150dc 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -1,3 +1,5 @@ +sudo: false + language: php notifications: From 8b44d9044c21a7972e55c5fd64eb24bc906b3314 Mon Sep 17 00:00:00 2001 From: Dominik Schilling Date: Mon, 16 Jan 2017 14:42:38 +0100 Subject: [PATCH 5232/5359] Remove unused/undefined autoload variables in site option command --- php/commands/site-option.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php/commands/site-option.php b/php/commands/site-option.php index 9d1a832a3..c829737e7 100644 --- a/php/commands/site-option.php +++ b/php/commands/site-option.php @@ -156,7 +156,6 @@ public function list_( $args, $assoc_args ) { $pattern = '%'; $fields = array( 'meta_key', 'meta_value' ); $size_query = ",LENGTH(meta_value) AS `size_bytes`"; - $autoload_query = ''; if ( isset( $assoc_args['search'] ) ) { $pattern = self::esc_like( $assoc_args['search'] ); @@ -230,7 +229,7 @@ public function update( $args, $assoc_args ) { $value = sanitize_option( $key, $value ); $old_value = sanitize_option( $key, get_site_option( $key ) ); - if ( $value === $old_value && is_null( $autoload ) ) { + if ( $value === $old_value ) { WP_CLI::success( "Value passed for '$key' site option is unchanged." ); } else { if ( update_site_option( $key, $value ) ) { From aa1bdc6dcec72a598cb2d2ab014d8dbb92d3bc78 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 16 Jan 2017 16:51:48 -0800 Subject: [PATCH 5233/5359] Use `process_csv_arguments_to_arrays()` to process `__` CSV into arrays --- features/comment-list.feature | 31 ++++++++++++++++++++++++++++++ features/post.feature | 8 ++++++++ php/WP_CLI/CommandWithDBObject.php | 15 +++++++++++++++ php/commands/comment.php | 4 +--- php/commands/post.php | 9 +++------ php/commands/user.php | 8 +------- 6 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 features/comment-list.feature diff --git a/features/comment-list.feature b/features/comment-list.feature new file mode 100644 index 000000000..aa40beb57 --- /dev/null +++ b/features/comment-list.feature @@ -0,0 +1,31 @@ +Feature: List WordPress comments + + @require-wp-4.1 + Scenario: Filter comments based on `comment__in` and `comment__not_in` + Given a WP install + + When I run `wp comment create --comment_post_ID=1 --porcelain` + Then save STDOUT as {COMMENT_ID} + + When I run `wp comment list --comment__in=1,{COMMENT_ID} --format=ids --orderby=comment_ID --order=ASC` + Then STDOUT should be: + """ + 1 {COMMENT_ID} + """ + + When I run `wp comment list --comment__in=1 --format=ids --orderby=comment_ID --order=ASC` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp comment list --comment__not_in=1,{COMMENT_ID} --format=ids --orderby=comment_ID --order=ASC` + Then STDOUT should be: + """ + """ + + When I run `wp comment list --comment__not_in=1 --format=ids --orderby=comment_ID --order=ASC` + Then STDOUT should be: + """ + {COMMENT_ID} + """ diff --git a/features/post.feature b/features/post.feature index ec73f3da7..406b9a76c 100644 --- a/features/post.feature +++ b/features/post.feature @@ -194,6 +194,14 @@ Feature: Manage WordPress posts Sample Page """ + When I run `wp post list --post_type=any --fields=post_title,post_name,post_status --format=csv --orderby=post_title --order=ASC` + Then STDOUT should be CSV containing: + | post_title | post_name | post_status | + | Draft post | | draft | + | Hello world! | hello-world | publish | + | Publish post | publish-post | publish | + | Sample Page | sample-page | publish | + Scenario: Update categories on a post When I run `wp term create category "Test Category" --porcelain` Then save STDOUT as {TERM_ID} diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php index 0702956a4..f8655a287 100644 --- a/php/WP_CLI/CommandWithDBObject.php +++ b/php/WP_CLI/CommandWithDBObject.php @@ -82,6 +82,21 @@ protected function _update( $args, $assoc_args, $callback ) { exit( $status ); } + /** + * Transforms arguments with '__' from CSV into expected arrays + * + * @param array $assoc_args + * @return array + */ + protected static function process_csv_arguments_to_arrays( $assoc_args ) { + foreach( $assoc_args as $k => $v ) { + if ( false !== strpos( $k, '__' ) ) { + $assoc_args[ $k ] = explode( ',', $v ); + } + } + return $assoc_args; + } + /** * Delete a given database object. * Exits with status. diff --git a/php/commands/comment.php b/php/commands/comment.php index c68a61cbd..8dd283b5a 100644 --- a/php/commands/comment.php +++ b/php/commands/comment.php @@ -323,9 +323,7 @@ public function list_( $_, $assoc_args ) { $assoc_args['fields'] = 'comment_ID'; } - if ( ! empty( $assoc_args['comment__in'] ) ) { - $assoc_args['comment__in'] = explode( ',', $assoc_args['comment__in'] ); - } + $assoc_args = self::process_csv_arguments_to_arrays( $assoc_args ); if ( ! empty( $assoc_args['comment__in'] ) && ! empty( $assoc_args['orderby'] ) diff --git a/php/commands/post.php b/php/commands/post.php index 11c96fa8d..15746263e 100644 --- a/php/commands/post.php +++ b/php/commands/post.php @@ -370,12 +370,9 @@ public function list_( $_, $assoc_args ) { 'post_status' => 'any', ); $query_args = array_merge( $defaults, $assoc_args ); - - foreach ( $query_args as $key => $query_arg ) { - if ( false !== strpos( $key, '__' ) - || ( 'post_type' == $key && 'any' != $query_arg ) ) { - $query_args[$key] = explode( ',', $query_arg ); - } + $query_args = self::process_csv_arguments_to_arrays( $query_args ); + if ( isset( $query_args['post_type'] ) && 'any' !== $query_args['post_type'] ) { + $query_args['post_type'] = explode( ',', $query_args['post_type'] ); } if ( 'ids' == $formatter->format ) { diff --git a/php/commands/user.php b/php/commands/user.php index 4dba841cd..c53e04235 100644 --- a/php/commands/user.php +++ b/php/commands/user.php @@ -144,13 +144,7 @@ public function list_( $args, $assoc_args ) { } $assoc_args['count_total'] = false; - - foreach( $assoc_args as $k => $v ) { - if ( false !== strpos( $k, '__' ) ) { - $assoc_args[ $k ] = explode( ',', $v ); - } - } - + $assoc_args = self::process_csv_arguments_to_arrays( $assoc_args ); $users = get_users( $assoc_args ); if ( 'ids' == $formatter->format ) { From c2892dd8e1e4063b090c70822765e77312318fbf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 16 Jan 2017 17:20:17 -0800 Subject: [PATCH 5234/5359] Remove unnecessary PHPUnit test --- tests/commands/test-db.php | 77 -------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 tests/commands/test-db.php diff --git a/tests/commands/test-db.php b/tests/commands/test-db.php deleted file mode 100644 index f92717567..000000000 --- a/tests/commands/test-db.php +++ /dev/null @@ -1,77 +0,0 @@ - DB_NAME, - 'host' => DB_HOST, - 'user' => DB_USER, - 'pass' => DB_PASSWORD, - ]; - $this->assertCli( [], $expected_args ); - - $expected_args['database'] = 'some_other_database'; - $this->assertCli( ['database' => 'some_other_database'], $expected_args ); - $expected_args['database'] = DB_NAME; - - define( 'DB_CHARSET', 'some_charset' ); - $expected_args['default-character-set'] = 'some_charset'; - $args = $this->assertCli( [], $expected_args ); - - $expected_args['default-character-set'] = 'some_other_charset'; - $args = $this->assertCli( ['default-character-set' => 'some_other_charset'], $expected_args ); - } - - private function getInstance() { - if($this->instance == null){ - $this->instance = new TestCommandInstance(); - } - - return $this->instance; - } - - private function assertCli( $assoc_args, $expected_args ) { - $instance = $this->getInstance(); - - $instance->cli( [], $assoc_args ); - $this->assertEquals( 'mysql --no-defaults --no-auto-rehash', $instance->getLastCmd() ); - - $args = $instance->getLastArgs(); - $this->assertEquals( count( $expected_args ), count( $args ) ); - - foreach($expected_args as $key => $value){ - $this->assertEquals( $value, $args[$key] ); - } - } -} - -class TestCommandInstance extends DB_Command { - private static $lastCmd; - private static $lastArgs; - - protected static function run_mysql_command( $cmd, $final_args, $descriptors ) { - static::$lastCmd = $cmd; - static::$lastArgs = $final_args; - } - - public static function getLastCmd() { - return static::$lastCmd; - } - - public static function getLastArgs() { - return static::$lastArgs; - } -} - From 352d3772539ff62e5e01bc342729c4cc0a8f55d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 16 Jan 2017 17:21:26 -0800 Subject: [PATCH 5235/5359] Remove unnecessary abstraction --- php/commands/db.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index 50c932b44..b4135652a 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -471,13 +471,9 @@ private static function run( $cmd, $assoc_args = array(), $descriptors = null ) } $final_args = array_merge( $assoc_args, $required ); - - static::run_mysql_command( $cmd, $final_args, $descriptors ); + Utils\run_mysql_command( $cmd, $final_args, $descriptors ); } - protected static function run_mysql_command( $cmd, $final_args, $descriptors ) { - Utils\run_mysql_command( $cmd, $final_args, $descriptors ); - } } WP_CLI::add_command( 'db', 'DB_Command' ); From 5623bdff579d31df440ed3a7488c16c77481c98b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 16 Jan 2017 17:22:23 -0800 Subject: [PATCH 5236/5359] Coding standards --- php/commands/db.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index b4135652a..ee420fde3 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -170,13 +170,13 @@ public function repair() { * * [--database=] * : Use a specific database. Defaults to DB_NAME. - * + * * [--default-character-set=] * : Use a specific character set. Defaults to DB_CHARSET when defined. - * + * * [--=] * : Extra arguments to pass to the MySQL executable. - * + * * ## EXAMPLES * * # Open MySQL console @@ -186,7 +186,7 @@ public function repair() { * @alias connect */ public function cli( $args, $assoc_args ) { - if ( !isset( $assoc_args['database'] ) ) { + if ( ! isset( $assoc_args['database'] ) ) { $assoc_args['database'] = DB_NAME; } @@ -466,7 +466,8 @@ private static function run( $cmd, $assoc_args = array(), $descriptors = null ) 'pass' => DB_PASSWORD, ); - if ( !isset( $assoc_args['default-character-set'] ) && defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { + if ( ! isset( $assoc_args['default-character-set'] ) + && defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { $required['default-character-set'] = constant( 'DB_CHARSET' ); } From e1ab7c51e3f3537e18ab065eec219a0f72c3dbcb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 16 Jan 2017 17:26:01 -0800 Subject: [PATCH 5237/5359] Explicitly mark these public --- php/commands/db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index ee420fde3..29fbc680b 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -288,7 +288,7 @@ public function query( $args, $assoc_args ) { * * @alias dump */ - function export( $args, $assoc_args ) { + public function export( $args, $assoc_args ) { $result_file = $this->get_file_name( $args ); $stdout = ( '-' === $result_file ); $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); @@ -416,7 +416,7 @@ public function import( $args, $assoc_args ) { * $ wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) * Success: Exported to wordpress_dbase.sql */ - function tables( $args, $assoc_args ) { + public function tables( $args, $assoc_args ) { $format = WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ); unset( $assoc_args['format'] ); From 0bd66190295291e5a08af01e049092a42b102619 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 18 Jan 2017 12:32:44 -0800 Subject: [PATCH 5238/5359] Pass `$wp_version` through to `translations_api()` This is needed for WordPress to report the correct language download file. --- features/core-language.feature | 11 +++++++++++ php/WP_CLI/CommandWithTranslation.php | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/features/core-language.feature b/features/core-language.feature index 2e3bd97e2..5541494bd 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -144,3 +144,14 @@ Feature: Manage translation files for a WordPress install """ Warning: The 'en_GB' language is active. """ + + @require-wp-4.0 + Scenario: Ensure correct language is installed for WP version + Given a WP install + And I run `wp core download --version=4.5.3 --force` + + When I run `wp core language install nl_NL` + Then STDOUT should contain: + """ + Downloading translation from https://downloads.wordpress.org/translation/core/4.5.3 + """ diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index f77f1d7b3..98d56aadc 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -362,8 +362,9 @@ protected function get_installed_languages() { */ protected function get_all_languages() { require_once ABSPATH . '/wp-admin/includes/translation-install.php'; + require ABSPATH . WPINC . '/version.php'; - $response = translations_api( $this->obj_type ); + $response = translations_api( $this->obj_type, array( 'version' => $wp_version ) ); if ( is_wp_error( $response ) ) { \WP_CLI::error( $response ); } From 1115ac344d3eada6b5c0c827b5f5bde56c051f2b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Fri, 20 Jan 2017 11:00:48 -0800 Subject: [PATCH 5239/5359] Document how to list tables of a specific site --- php/commands/db.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/php/commands/db.php b/php/commands/db.php index 29fbc680b..cca84fbc8 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -412,6 +412,18 @@ public function import( $args, $assoc_args ) { * * ## EXAMPLES * + * # List tables for a single site, without shared tables like 'wp_users' + * $ wp db tables --scope=blog --url=sub.example.com + * wp_3_posts + * wp_3_comments + * wp_3_options + * wp_3_postmeta + * wp_3_terms + * wp_3_term_taxonomy + * wp_3_term_relationships + * wp_3_termmeta + * wp_3_commentmeta + * * # Export only tables for a single site * $ wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) * Success: Exported to wordpress_dbase.sql From d4f72a428dffdc24562698e8067c0c45066c431a Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Fri, 20 Jan 2017 16:26:21 -0500 Subject: [PATCH 5240/5359] Continue on to next file instead of breaking --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 227079d8f..3fcf8c552 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -195,7 +195,7 @@ function import( $args, $assoc_args = array() ) { if ( !file_exists( $file ) ) { WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." ); $errors++; - break; + continue; } $tempfile = $this->make_copy( $file ); } else { From afc32fb7fc40771a17315dc8122cfaf470a4833b Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Fri, 20 Jan 2017 16:30:55 -0500 Subject: [PATCH 5241/5359] Check the return value of download_url() for possible WP_Error --- php/commands/media.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index 3fcf8c552..f463fcb3b 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -200,6 +200,14 @@ function import( $args, $assoc_args = array() ) { $tempfile = $this->make_copy( $file ); } else { $tempfile = download_url( $file ); + if ( is_wp_error( $tempfile ) ) { + WP_CLI::warning( sprintf( + "Unable to import file '%s'. Reason: %s", + $file, implode( ', ', $success->get_error_messages() ) + ) ); + $errors++; + continue; + } } $file_array = array( From cf0cbbb023634d5a4b785307ec9faade0738439e Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Fri, 20 Jan 2017 16:34:11 -0500 Subject: [PATCH 5242/5359] Ensure error with --porcelain returns non-zero exit code --- php/commands/media.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php/commands/media.php b/php/commands/media.php index f463fcb3b..3c616d599 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -282,6 +282,8 @@ function import( $args, $assoc_args = array() ) { } if ( ! Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { Utils\report_batch_operation_results( 'image', 'import', count( $args ), $successes, $errors ); + } elseif ( $errors ) { + WP_CLI::halt( 1 ); } } From 8a5053fe470926b815531b2e7bf2cb31b9ddec03 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 23 Jan 2017 06:52:08 -0800 Subject: [PATCH 5243/5359] Support PHP 7.1 when scaffolding `.travis.yml` --- templates/plugin-travis.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 9533150dc..82c399e8d 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -29,8 +29,8 @@ before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION - export PATH="$HOME/.composer/vendor/bin:$PATH" - | - if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.0" ]]; then - composer global require "phpunit/phpunit=5.6.*" + if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then + composer global require "phpunit/phpunit=5.7.*" else composer global require "phpunit/phpunit=4.8.*" fi From bd957e8e52b6eeb92eaf342442d4ebbcc45c7834 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 23 Jan 2017 14:43:06 -0800 Subject: [PATCH 5244/5359] Treat null result from `install_from_repo()` as an error Because `null` doesn't give us any data to display, let's assume the error was already reported by the upgrader skin. --- php/WP_CLI/CommandWithUpgrade.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 4774e66ee..937ceb09d 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -173,7 +173,9 @@ function install( $args, $assoc_args ) { // Assume a plugin/theme slug from the WordPress.org repository has been specified $result = $this->install_from_repo( $slug, $assoc_args ); - if ( is_wp_error( $result ) ) { + if ( is_null( $result ) ) { + $errors++; + } elseif ( is_wp_error( $result ) ) { $key = $result->get_error_code(); if ( in_array( $key, array( 'plugins_api_failed', 'themes_api_failed' ) ) && ! empty( $result->error_data[ $key ] ) && in_array( $result->error_data[ $key ], array( 'N;', 'b:0;' ) ) ) { From 0062c345fe6d518f7ffb91f8e45d64779bbf4266 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 23 Jan 2017 14:49:17 -0800 Subject: [PATCH 5245/5359] Append a random hash to generated `.sql` file Doing so helps to mitigate database files from being web-accessible at predictable URLs. --- php/commands/db.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index cca84fbc8..1e2da91e9 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -449,8 +449,10 @@ public function tables( $args, $assoc_args ) { } private function get_file_name( $args ) { - if ( empty( $args ) ) - return sprintf( '%s.sql', DB_NAME ); + if ( empty( $args ) ) { + $hash = substr( md5( mt_rand() ), 0, 7 ); + return sprintf( '%s-%s.sql', DB_NAME, $hash ); + } return $args[0]; } From 6cdfd82a1e5efb97e87ca4ced4ccd796c55d2f0a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 24 Jan 2017 05:51:42 -0800 Subject: [PATCH 5246/5359] Support 'application/pdf' for WordPress 4.7+ WordPress 4.7 includes support for PDF image thumbnails, so we should regenerate them too. --- php/commands/media.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 227079d8f..b54cc1474 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -78,10 +78,14 @@ function regenerate( $args, $assoc_args = array() ) { $skip_delete = true; } + $mime_types = array( 'image' ); + if ( Utils\wp_version_compare( '4.7', '>=' ) ) { + $mime_types[] = 'application/pdf'; + } $query_args = array( 'post_type' => 'attachment', 'post__in' => $args, - 'post_mime_type' => 'image', + 'post_mime_type' => $mime_types, 'post_status' => 'any', 'posts_per_page' => -1, 'fields' => 'ids' From a0e78f488c028fee6c85dee5455b6480503632d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 24 Jan 2017 06:07:57 -0800 Subject: [PATCH 5247/5359] Add `--site_id=` filter to `wp site option list` --- features/site-option.feature | 27 +++++++++++++++++++++++++++ php/commands/site-option.php | 20 ++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/features/site-option.feature b/features/site-option.feature index b36b75638..fdd393217 100644 --- a/features/site-option.feature +++ b/features/site-option.feature @@ -124,3 +124,30 @@ Feature: Manage WordPress site options """ Error: This is not a multisite install. """ + + Scenario: Filter options by `--site_id` + Given a WP multisite install + + When I run `wp db query "INSERT INTO wp_sitemeta (site_id,meta_key,meta_value) VALUES (2,'wp_cli_test_option','foobar');"` + Then the return code should be 0 + + When I run `wp site option list` + Then STDOUT should contain: + """ + wp_cli_test_option + """ + And STDERR should be empty + + When I run `wp site option list --site_id=1` + Then STDOUT should not contain: + """ + wp_cli_test_option + """ + And STDERR should be empty + + When I run `wp site option list --site_id=2` + Then STDOUT should contain: + """ + wp_cli_test_option + """ + And STDERR should be empty diff --git a/php/commands/site-option.php b/php/commands/site-option.php index c829737e7..96b1230eb 100644 --- a/php/commands/site-option.php +++ b/php/commands/site-option.php @@ -1,5 +1,7 @@ ] * : Use wildcards ( * and ? ) to match option name. * + * [--site_id=] + * : Limit options to those of a particular site id. + * * [--field=] * : Prints the value of a single field. * @@ -173,14 +178,17 @@ public function list_( $args, $assoc_args ) { $size_query = ",SUM(LENGTH(meta_value)) AS `size_bytes`"; } - $results = $wpdb->get_results( - $wpdb->prepare( - "SELECT `meta_id`, `site_id`, `meta_key`,`meta_value`" . $size_query - . " FROM `$wpdb->sitemeta` WHERE `meta_key` LIKE %s", - $pattern - ) + $query = $wpdb->prepare( + "SELECT `meta_id`, `site_id`, `meta_key`,`meta_value`" . $size_query + . " FROM `$wpdb->sitemeta` WHERE `meta_key` LIKE %s", + $pattern ); + if ( $site_id = Utils\get_flag_value( $assoc_args, 'site_id' ) ) { + $query .= $wpdb->prepare( ' AND site_id=%d', $site_id ); + } + $results = $wpdb->get_results( $query ); + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { WP_CLI::line( $results[0]->size_bytes ); } else { From 6302579a8b34a1a87fbc86cf3c618d4f77c48284 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 24 Jan 2017 06:21:36 -0800 Subject: [PATCH 5248/5359] Only append random hash to `wp export` file `wp import` should continue to attempt to import `{DB_NAME}.sql` when no other value is provided --- features/db-export.feature | 21 +++++++++++++++++++++ features/db-import.feature | 13 +++++++++++++ php/commands/db.php | 22 +++++++++++----------- 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 features/db-export.feature create mode 100644 features/db-import.feature diff --git a/features/db-export.feature b/features/db-export.feature new file mode 100644 index 000000000..4028b0466 --- /dev/null +++ b/features/db-export.feature @@ -0,0 +1,21 @@ +Feature: Export a WordPress database + + Scenario: Database exports with random hash applied + Given a WP install + + When I run `wp db export --porcelain` + Then STDOUT should contain: + """ + wp_cli_test- + """ + And the wp_cli_test.sql file should not exist + + Scenario: Database export to a specified file path + Given a WP install + + When I run `wp db export wp_cli_test.sql --porcelain` + Then STDOUT should contain: + """ + wp_cli_test.sql + """ + And the wp_cli_test.sql file should exist diff --git a/features/db-import.feature b/features/db-import.feature new file mode 100644 index 000000000..c6912ba72 --- /dev/null +++ b/features/db-import.feature @@ -0,0 +1,13 @@ +Feature: Import a WordPress database + + Scenario: Import from database name path by default + Given a WP install + + When I run `wp db export wp_cli_test.sql` + Then the wp_cli_test.sql file should exist + + When I run `wp db import` + Then STDOUT should be: + """ + Success: Imported from 'wp_cli_test.sql'. + """ diff --git a/php/commands/db.php b/php/commands/db.php index 1e2da91e9..dc20a6b99 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -289,7 +289,12 @@ public function query( $args, $assoc_args ) { * @alias dump */ public function export( $args, $assoc_args ) { - $result_file = $this->get_file_name( $args ); + if ( ! empty( $args[0] ) ) { + $result_file = $args[0]; + } else { + $hash = substr( md5( mt_rand() ), 0, 7 ); + $result_file = sprintf( '%s-%s.sql', DB_NAME, $hash );; + } $stdout = ( '-' === $result_file ); $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); @@ -352,7 +357,11 @@ public function export( $args, $assoc_args ) { * Success: Imported from 'wordpress_dbase.sql'. */ public function import( $args, $assoc_args ) { - $result_file = $this->get_file_name( $args ); + if ( ! empty( $args[0] ) ) { + $result_file = $args[0]; + } else { + $result_file = sprintf( '%s.sql', DB_NAME ); + } if ( '-' === $result_file ) { $descriptors = array( @@ -448,15 +457,6 @@ public function tables( $args, $assoc_args ) { } } - private function get_file_name( $args ) { - if ( empty( $args ) ) { - $hash = substr( md5( mt_rand() ), 0, 7 ); - return sprintf( '%s-%s.sql', DB_NAME, $hash ); - } - - return $args[0]; - } - private static function get_create_query() { $create_query = sprintf( 'CREATE DATABASE `%s`', DB_NAME ); From 76c3607df0837a79bbb623d3ffa59950d8e8a507 Mon Sep 17 00:00:00 2001 From: Nikhil Chavan Date: Tue, 24 Jan 2017 20:07:43 +0530 Subject: [PATCH 5249/5359] update gitlab ci template to run phpcs tests --- templates/plugin-gitlab.mustache | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/plugin-gitlab.mustache b/templates/plugin-gitlab.mustache index 6e64d85fa..1e30cc5f6 100644 --- a/templates/plugin-gitlab.mustache +++ b/templates/plugin-gitlab.mustache @@ -19,11 +19,17 @@ before_script: # Set up WordPress tests - bash bin/install-wp-tests.sh wordpress_tests root mysql mysql latest true + # Install PHPCS and WPCS + - composer global require "squizlabs/php_codesniffer=*" + - composer global require "wp-coding-standards/wpcs" + - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs + PHPunit:PHP5.3:MySQL: image: tetraweb/php:5.3 services: - mysql:5.6 script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - phpunit --configuration phpunit.xml.dist PHPunit:PHP5.6:MySQL: @@ -31,4 +37,5 @@ PHPunit:PHP5.6:MySQL: services: - mysql:5.6 script: + - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - phpunit --configuration phpunit.xml.dist \ No newline at end of file From 16a4c12dcf0227468f1b6c5b262f9d3f6db528bf Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 25 Jan 2017 05:34:47 -0800 Subject: [PATCH 5250/5359] Don't attempt to rename ZIPs uploaded to GitHub's releases page Also fixes incorrect use of `WP_Error` --- features/plugin-install.feature | 15 +++++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 2caae2430..cee9ad74e 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -36,6 +36,21 @@ Feature: Install WordPress plugins And the wp-content/plugins/one-time-login directory should exist And the wp-content/plugins/one-time-login-master directory should not exist + Scenario: Don't attempt to rename ZIPs uploaded to GitHub's releases page + Given a WP install + + When I run `wp plugin install https://github.com/danielbachhuber/one-time-login/releases/download/v0.1.2/one-time-login.0.1.2.zip` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And STDOUT should not contain: + """ + Renamed Github-based project from + """ + And STDERR should be empty + And the wp-content/plugins/one-time-login directory should exist + Scenario: Installing respects WP_PROXY_HOST and WP_PROXY_PORT Given a WP install And a invalid-proxy-details.php file: diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 937ceb09d..fb7e83082 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -144,6 +144,10 @@ function install( $args, $assoc_args ) { if ( strpos( $local_or_remote_zip_file, '://' ) !== false && 'github.com' === parse_url( $local_or_remote_zip_file, PHP_URL_HOST ) ) { $filter = function( $source, $remote_source, $upgrader ) use ( $local_or_remote_zip_file ) { + // Don't attempt to rename ZIPs uploaded to the releases page + if ( preg_match( '#github\.com/([^/]+)/([^/]+)/releases/download/#', $local_or_remote_zip_file ) ) { + return $source; + } $branch_length = strlen( pathinfo( $local_or_remote_zip_file, PATHINFO_FILENAME ) ); if ( $branch_length ) { $new_path = substr( rtrim( $source, '/' ), 0, - ( $branch_length + 1 ) ) . '/'; @@ -151,7 +155,7 @@ function install( $args, $assoc_args ) { WP_CLI::log( "Renamed Github-based project from '" . basename( $source ) . "' to '" . basename( $new_path ) . "'." ); return $new_path; } else { - return new \WP_CLI( 'wpcli_install_gitub', "Couldn't move Github-based project to appropriate directory." ); + return new \WP_Error( 'wpcli_install_gitub', "Couldn't move Github-based project to appropriate directory." ); } } return $source; From 3c84fdebcc0d188fc9d6f77a33847154197b36e2 Mon Sep 17 00:00:00 2001 From: inderpreet99 Date: Wed, 25 Jan 2017 14:23:02 -0500 Subject: [PATCH 5251/5359] Update docs with search-replace regex example and note. --- php/commands/search-replace.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php index cb9c56cad..5a468be6d 100644 --- a/php/commands/search-replace.php +++ b/php/commands/search-replace.php @@ -82,8 +82,8 @@ class Search_Replace_Command extends WP_CLI_Command { * : Prints rows to the console as they're updated. * * [--regex] - * : Runs the search using a regular expression. Warning: search-replace - * will take about 15-20x longer when using --regex. + * : Runs the search using a regular expression (without delimiters). + * Warning: search-replace will take about 15-20x longer when using --regex. * * [--regex-flags=] * : Pass PCRE modifiers to regex search-replace (e.g. 'i' for case-insensitivity). @@ -96,6 +96,9 @@ class Search_Replace_Command extends WP_CLI_Command { * # Run search/replace operation but dont save in database * $ wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run * + * # Run case-insensitive regex search/replace operation (slow) + * $ wp search-replace '\[foo id="([0-9]+)"' '[bar id="\1"' --regex --regex-flags='i' + * * # Turn your production multisite database into a local dev database * $ wp search-replace --url=example.com example.com example.dev 'wp_*options' wp_blogs * From bb6901b0af4fa37ff5c1413b2f4c77cd760ef3f2 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 25 Jan 2017 13:20:24 -0800 Subject: [PATCH 5252/5359] Run help for `wp db *` set of commands at same point as command This will enable `wp help db import` to be run when WordPress has been downloaded, a `wp-config.php` has been created, but WordPress hasn't yet been installed. --- features/db-import.feature | 38 ++++++++++++++++++++++++++++++++++++++ php/WP_CLI/Runner.php | 3 ++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/features/db-import.feature b/features/db-import.feature index c6912ba72..948e2b7ed 100644 --- a/features/db-import.feature +++ b/features/db-import.feature @@ -11,3 +11,41 @@ Feature: Import a WordPress database """ Success: Imported from 'wp_cli_test.sql'. """ + + Scenario: Help runs properly at various points of a functional WP install + Given an empty directory + + When I run `wp help db import` + Then STDOUT should contain: + """ + wp db import + """ + + When I run `wp core download` + Then STDOUT should not be empty + And the wp-config-sample.php file should exist + + When I run `wp help db import` + Then STDOUT should contain: + """ + wp db import + """ + + When I run `wp core config {CORE_CONFIG_SETTINGS}` + Then STDOUT should not be empty + And the wp-config.php file should exist + + When I run `wp help db import` + Then STDOUT should contain: + """ + wp db import + """ + + When I run `wp db create` + Then STDOUT should not be empty + + When I run `wp help db import` + Then STDOUT should contain: + """ + wp db import + """ diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 45e65aa47..584dd46dd 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -897,7 +897,8 @@ public function start() { "Either create one manually or use `wp core config`." ); } - if ( $this->cmd_starts_with( array( 'db' ) ) && !$this->cmd_starts_with( array( 'db', 'tables' ) ) ) { + if ( ( $this->cmd_starts_with( array( 'db' ) ) || $this->cmd_starts_with( array( 'help', 'db' ) ) ) + && ! $this->cmd_starts_with( array( 'db', 'tables' ) ) ) { eval( $this->get_wp_config_code() ); $this->_run_command(); exit; From 27ce445aff682616ea2548a5705aa374969b2d43 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 26 Jan 2017 14:12:29 -0800 Subject: [PATCH 5253/5359] Update tests for WordPress 4.7.2 --- features/core-check-update.feature | 10 +++++----- features/core-update.feature | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index 36c5b6cf4..d7903c37d 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,8 +9,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7.1 | major | https://downloads.wordpress.org/release/wordpress-4.7.1.zip | - | 4.4.6 | minor | https://downloads.wordpress.org/release/wordpress-4.4.6-partial-0.zip | + | 4.7.2 | major | https://downloads.wordpress.org/release/wordpress-4.7.2.zip | + | 4.4.7 | minor | https://downloads.wordpress.org/release/wordpress-4.4.7-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7.1 | major | https://downloads.wordpress.org/release/wordpress-4.7.1.zip | + | 4.7.2 | major | https://downloads.wordpress.org/release/wordpress-4.7.2.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -32,7 +32,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.6 | minor | https://downloads.wordpress.org/release/wordpress-4.4.6-partial-0.zip | + | 4.4.7 | minor | https://downloads.wordpress.org/release/wordpress-4.4.7-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -53,4 +53,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.14 | minor | https://downloads.wordpress.org/release/wordpress-4.0.14-partial-0.zip | + | 4.0.15 | minor | https://downloads.wordpress.org/release/wordpress-4.0.15-partial-0.zip | diff --git a/features/core-update.feature b/features/core-update.feature index 8b2305414..9206ef169 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.17 + Updating to version 3.7.18 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.17 + 3.7.18 """ @less-than-php-7 @@ -208,8 +208,8 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 4.0.14 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.14-partial-0.zip + Updating to version 4.0.15 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.15-partial-0.zip """ And STDOUT should contain: """ From e20de30af97e0b8f25b2bca4c32489af73692020 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 30 Jan 2017 10:54:04 -0800 Subject: [PATCH 5254/5359] Update Composer dependencies (1/30/2017) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/yaml (v2.8.15) - Installing symfony/yaml (v2.8.16) Downloading: 100% - Removing symfony/filesystem (v2.8.15) - Installing symfony/filesystem (v2.8.16) Downloading: 100% - Removing symfony/config (v2.8.15) - Installing symfony/config (v2.8.16) Downloading: 100% - Removing symfony/debug (v2.8.15) - Installing symfony/debug (v2.8.16) Downloading: 100% - Removing symfony/dependency-injection (v2.8.15) - Installing symfony/dependency-injection (v2.8.16) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.15) - Installing symfony/event-dispatcher (v2.8.16) Downloading: 100% - Removing symfony/translation (v2.8.15) - Installing symfony/translation (v2.8.16) Downloading: 100% - Removing symfony/process (v2.8.15) - Installing symfony/process (v2.8.16) Downloading: 100% - Removing symfony/finder (v2.8.15) - Installing symfony/finder (v2.8.16) Downloading: 100% - Removing symfony/console (v2.8.15) - Installing symfony/console (v2.8.16) Downloading: 100% - Removing composer/composer (1.3.1) - Installing composer/composer (1.3.2) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 110 +++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/composer.lock b/composer.lock index 3f1ebec83..54a1b0a4a 100644 --- a/composer.lock +++ b/composer.lock @@ -67,16 +67,16 @@ }, { "name": "composer/composer", - "version": "1.3.1", + "version": "1.3.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "91dbca556764dcece45e1ba3aab14de2deaa9fec" + "reference": "e7569edb4a5eadcbb2e4ad5ed753282260f281df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/91dbca556764dcece45e1ba3aab14de2deaa9fec", - "reference": "91dbca556764dcece45e1ba3aab14de2deaa9fec", + "url": "https://api.github.com/repos/composer/composer/zipball/e7569edb4a5eadcbb2e4ad5ed753282260f281df", + "reference": "e7569edb4a5eadcbb2e4ad5ed753282260f281df", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ "dependency", "package" ], - "time": "2017-01-07 17:08:51" + "time": "2017-01-27 17:23:42" }, { "name": "composer/semver", @@ -749,16 +749,16 @@ }, { "name": "symfony/config", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "b522856007b258f46d5ee35d3b7b235c11e76e86" + "reference": "4537f2413348fe271c2c4b09da219ed615d79f9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/b522856007b258f46d5ee35d3b7b235c11e76e86", - "reference": "b522856007b258f46d5ee35d3b7b235c11e76e86", + "url": "https://api.github.com/repos/symfony/config/zipball/4537f2413348fe271c2c4b09da219ed615d79f9c", + "reference": "4537f2413348fe271c2c4b09da219ed615d79f9c", "shasum": "" }, "require": { @@ -801,20 +801,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-12-10 08:21:45" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/console", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d5643cd095e5e37d31e004bb2606b5dd7e96602f" + "reference": "2e18b8903d9c498ba02e1dfa73f64d4894bb6912" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d5643cd095e5e37d31e004bb2606b5dd7e96602f", - "reference": "d5643cd095e5e37d31e004bb2606b5dd7e96602f", + "url": "https://api.github.com/repos/symfony/console/zipball/2e18b8903d9c498ba02e1dfa73f64d4894bb6912", + "reference": "2e18b8903d9c498ba02e1dfa73f64d4894bb6912", "shasum": "" }, "require": { @@ -862,20 +862,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-12-06 11:59:35" + "time": "2017-01-08 20:43:03" }, { "name": "symfony/debug", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "62a68f640456f6761d752c62d81631428ef0d8a1" + "reference": "567681e2c4e5431704e884e4be25a95fd900770f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/62a68f640456f6761d752c62d81631428ef0d8a1", - "reference": "62a68f640456f6761d752c62d81631428ef0d8a1", + "url": "https://api.github.com/repos/symfony/debug/zipball/567681e2c4e5431704e884e4be25a95fd900770f", + "reference": "567681e2c4e5431704e884e4be25a95fd900770f", "shasum": "" }, "require": { @@ -919,20 +919,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-11-15 12:53:17" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/dependency-injection", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7" + "reference": "b75356611675364607d697f314850d9d870a84aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7", - "reference": "51a7b5385fb0f42e5edbdb2cfbad1a011ecdaee7", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b75356611675364607d697f314850d9d870a84aa", + "reference": "b75356611675364607d697f314850d9d870a84aa", "shasum": "" }, "require": { @@ -982,20 +982,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-12-08 14:41:31" + "time": "2017-01-10 14:27:01" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934" + "reference": "74877977f90fb9c3e46378d5764217c55f32df34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/25c576abd4e0f212e678fe8b2bd9a9a98c7ea934", - "reference": "25c576abd4e0f212e678fe8b2bd9a9a98c7ea934", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/74877977f90fb9c3e46378d5764217c55f32df34", + "reference": "74877977f90fb9c3e46378d5764217c55f32df34", "shasum": "" }, "require": { @@ -1042,20 +1042,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-10-13 01:43:15" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/filesystem", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "a3784111af9f95f102b6411548376e1ae7c93898" + "reference": "5b77d49ab76e5b12743b359ef4b4a712e6f5360d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/a3784111af9f95f102b6411548376e1ae7c93898", - "reference": "a3784111af9f95f102b6411548376e1ae7c93898", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/5b77d49ab76e5b12743b359ef4b4a712e6f5360d", + "reference": "5b77d49ab76e5b12743b359ef4b4a712e6f5360d", "shasum": "" }, "require": { @@ -1091,20 +1091,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-10-18 04:28:30" + "time": "2017-01-08 20:43:03" }, { "name": "symfony/finder", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "c0f10576335743b881ac1ed39d18c0fa66048775" + "reference": "355fccac526522dc5fca8ecf0e62749a149f3b8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/c0f10576335743b881ac1ed39d18c0fa66048775", - "reference": "c0f10576335743b881ac1ed39d18c0fa66048775", + "url": "https://api.github.com/repos/symfony/finder/zipball/355fccac526522dc5fca8ecf0e62749a149f3b8b", + "reference": "355fccac526522dc5fca8ecf0e62749a149f3b8b", "shasum": "" }, "require": { @@ -1140,7 +1140,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-12-13 09:38:12" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/polyfill-mbstring", @@ -1203,16 +1203,16 @@ }, { "name": "symfony/process", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "1a1bd056395540d0bc549d39818316513565d278" + "reference": "ebb3c2abe0940a703f08e0cbe373f62d97d40231" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1a1bd056395540d0bc549d39818316513565d278", - "reference": "1a1bd056395540d0bc549d39818316513565d278", + "url": "https://api.github.com/repos/symfony/process/zipball/ebb3c2abe0940a703f08e0cbe373f62d97d40231", + "reference": "ebb3c2abe0940a703f08e0cbe373f62d97d40231", "shasum": "" }, "require": { @@ -1248,20 +1248,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-11-24 00:43:03" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/translation", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "edbe67e8f729885b55421d5cc58223d48540df07" + "reference": "b4ac4a393f6970cc157fba17be537380de396a86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/edbe67e8f729885b55421d5cc58223d48540df07", - "reference": "edbe67e8f729885b55421d5cc58223d48540df07", + "url": "https://api.github.com/repos/symfony/translation/zipball/b4ac4a393f6970cc157fba17be537380de396a86", + "reference": "b4ac4a393f6970cc157fba17be537380de396a86", "shasum": "" }, "require": { @@ -1312,20 +1312,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-11-18 21:10:01" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/yaml", - "version": "v2.8.15", + "version": "v2.8.16", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "befb26a3713c97af90d25dd12e75621ef14d91ff" + "reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/befb26a3713c97af90d25dd12e75621ef14d91ff", - "reference": "befb26a3713c97af90d25dd12e75621ef14d91ff", + "url": "https://api.github.com/repos/symfony/yaml/zipball/dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2", + "reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2", "shasum": "" }, "require": { @@ -1361,7 +1361,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-11-14 16:15:57" + "time": "2017-01-03 13:49:52" }, { "name": "wp-cli/php-cli-tools", From 52617ba54557b38256ccdf0a66d49936e189281c Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Tue, 31 Jan 2017 22:45:45 -0500 Subject: [PATCH 5255/5359] Fix variable name --- php/commands/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/media.php b/php/commands/media.php index 3c616d599..d738b69b3 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -203,7 +203,7 @@ function import( $args, $assoc_args = array() ) { if ( is_wp_error( $tempfile ) ) { WP_CLI::warning( sprintf( "Unable to import file '%s'. Reason: %s", - $file, implode( ', ', $success->get_error_messages() ) + $file, implode( ', ', $tempfile->get_error_messages() ) ) ); $errors++; continue; From 25443e77d5eb967ab71b17c218fcd3fe1a7b7d11 Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Tue, 31 Jan 2017 23:02:46 -0500 Subject: [PATCH 5256/5359] Add functional tests --- features/media-import.feature | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/features/media-import.feature b/features/media-import.feature index 552ec0f96..971694c18 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -120,3 +120,39 @@ Feature: Manage WordPress attachments """ Alt\Here """ + + Scenario: Import multiple images + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + + When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' {CACHE_DIR}/large-image.jpg` + Then STDOUT should contain: + """ + Success: Imported 2 of 2 images. + """ + + Scenario: Fail to import one image but continue trying the next + When I try `wp media import gobbledygook.png 'http://wp-cli.org/behat-data/codeispoetry.png'` + Then STDERR should contain: + """ + Error: Only imported 1 of 2 images. + """ + And the return code should be 1 + + Scenario: Fail when download_url() fails + When I try `wp media import 'http://wp-cli.org/404'` + Then STDERR should be: + """ + Warning: Unable to import file 'http://wp-cli.org/404'. Reason: Not Found + Error: No images imported. + """ + And the return code should be 1 + + Scenario: Return a non-zero exit code when encountering an error in --porcelain mode + When I try `wp media import gobbledygook.png --porcelain` + Then STDERR should contain: + """ + Error: No images imported. + """ + And the return code should be 1 From 36c49bc53c8ceb089446669d32e395cf30b82001 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Feb 2017 04:24:56 -0800 Subject: [PATCH 5257/5359] Update `.mailmap` with latest contributors --- .mailmap | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.mailmap b/.mailmap index 8fcc7dc6b..5c94560fc 100644 --- a/.mailmap +++ b/.mailmap @@ -20,12 +20,14 @@ Brandon Kraft Brian MacKinney builtbylane c10b10 +c10b10 Chris Montgomery clemens-tolboom conatus Corey Worrell ctayloroomphinc cyberhobo +daithi-coombes dangardner Daniel Bachhuber danielbachhuber @@ -38,10 +40,12 @@ drrobotnik Duncan Brown dwightjack Eduardo Alencar +eliorivero Enrico Sorcinelli ericandrewlewis ericmann ernilambar +erwanlr eugeneware Evan Mattson Fabian Isele @@ -54,6 +58,7 @@ Geo getsource Gilbert Pellegrom glebis +goldenapples goldenapples Grant McInnes Greg Anderson @@ -68,6 +73,7 @@ j3lamp jacobischwartz Jakub Juszczak Jan VoráÄek +Japh Jeff Gould jeichorn Jeremy Pry @@ -84,8 +90,10 @@ Jorge A. Torres Josh Eaton joshbetz joshlevinson +joshstoik1 Joshua Priddle JQ +jtsternberg KDoole Keanan Koppenhaver Keith Grennan @@ -104,6 +112,7 @@ Mark McEver matiskay mattes mattheu +MattiaG mbovel mboynes mgburns @@ -115,6 +124,7 @@ milesj MiteshShah miya0001 Morgan Estes +mpeshev mwilliamson mwilliamson mwithheld @@ -145,6 +155,7 @@ pete@petenelson.com Peter J. Herrel phh Pippin Williamson +QWp6t Rachel Baker Radu Dan Rahul Prajapati @@ -169,6 +180,7 @@ sebastiaandegeus Shinichi Nishikawa sibprogrammer simonwheatley +smhmic soulou spacedmonkey SpikesDivZero @@ -193,6 +205,8 @@ tddewey thisislawatts tiagohillebrandt tlovett1 +tolgap +tollmanz tollmanz toszcze tott @@ -202,6 +216,7 @@ Tristan Penman twisty twratajczak Utkarsh Patel +Veered veganista Ville Vuorenmaa voldemortensen @@ -212,6 +227,7 @@ westonruter westonruter William Turrell willmot +wojsmol wopr42 yivi yivi From 22ed2ac1bf9a80ffc1b4dcb03b695b339afd2acc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Feb 2017 04:25:46 -0800 Subject: [PATCH 5258/5359] Bump latest version in project README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61cb211c3..e5c63bb28 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ WP-CLI root dir: /home/wp-cli/.wp-cli WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ WP-CLI global config: /home/wp-cli/.wp-cli/config.yml WP-CLI project config: -WP-CLI version: 1.0.0 +WP-CLI version: 1.1.0 ``` ### Updating From 6c5cec854d1a642a6c0d0679dc09f8309a6e2671 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Feb 2017 04:29:54 -0800 Subject: [PATCH 5259/5359] Bump version to 1.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1c6f7dee7..9084fa2f7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0-alpha +1.1.0 From 82e91b774b19957008012628ffe5790e2041b92a Mon Sep 17 00:00:00 2001 From: Stephen Beemsterboer Date: Wed, 1 Feb 2017 09:47:14 -0500 Subject: [PATCH 5260/5359] Fix test - look for the correct err message --- features/media-import.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/media-import.feature b/features/media-import.feature index 971694c18..058a31733 100644 --- a/features/media-import.feature +++ b/features/media-import.feature @@ -153,6 +153,6 @@ Feature: Manage WordPress attachments When I try `wp media import gobbledygook.png --porcelain` Then STDERR should contain: """ - Error: No images imported. + Warning: Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. """ And the return code should be 1 From 0e0278ce07ae2a64573b033591ff3480111c4669 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Feb 2017 10:21:30 -0800 Subject: [PATCH 5261/5359] Bump working version to 1.2.0-alpha --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9084fa2f7..8864779ee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.2.0-alpha From be7df991c94c009549cb8eaba4d473f3883d2aa3 Mon Sep 17 00:00:00 2001 From: lichtscheu Date: Wed, 1 Feb 2017 21:19:01 +0100 Subject: [PATCH 5262/5359] Update LICENSE year to 2017 --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index d77c42171..06311927d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,7 +2,7 @@ All code in this repository, unless otherwise specified, is hereby licensed under the MIT Public License: ========================================================================================================= -Copyright (C) 2011-2016 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) +Copyright (C) 2011-2017 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 6854be14001ea66f585028b3d8f8353cb725f9de Mon Sep 17 00:00:00 2001 From: Timothy Guan-tin Chien Date: Sun, 5 Feb 2017 11:34:15 +0800 Subject: [PATCH 5263/5359] HTTPS everywhere on README.md This avoids partial insecure warning on https://wp-cli.org/ . I've updated all the outbound links to HTTPS as well. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e5c63bb28..749a65578 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ WP-CLI [WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. -For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](http://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. +For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](https://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.svg?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](http://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") +[![Build Status](https://travis-ci.org/wp-cli/wp-cli.svg?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](https://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) @@ -106,7 +106,7 @@ source /FULL/PATH/TO/wp-completion.bash ## Support -WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. The [current version of WP-CLI](http://wp-cli.org/docs/roadmap/) is the only officially supported version. +WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. The [current version of WP-CLI](https://wp-cli.org/docs/roadmap/) is the only officially supported version. When looking for support, please first look for an answer in one of the following resources: @@ -114,7 +114,7 @@ When looking for support, please first look for an answer in one of the followin - [Documentation portal](https://wp-cli.org/docs/) - [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) - [runcommand tips](https://runcommand.io/tips/) -- [WordPress StackExchange forums](http://wordpress.stackexchange.com/questions/tagged/wp-cli) +- [WordPress StackExchange forums](https://wordpress.stackexchange.com/questions/tagged/wp-cli) Need help with a project related to work? Professional users may want to consider [runcommand premium support](https://runcommand.io/pricing/). Alternatively, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. @@ -184,9 +184,9 @@ Read more about the project's [governance](https://wp-cli.org/docs/governance/) Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: -* [Drush](http://drush.ws/) for... a lot of things -* [wpshell](http://code.trac.wordpress.org/browser/wpshell) for `wp shell` -* [Regenerate Thumbnails](http://wordpress.org/plugins/regenerate-thumbnails/) for `wp media regenerate` +* [Drush](https://github.com/drush-ops/drush) for... a lot of things +* [wpshell](https://code.trac.wordpress.org/browser/wpshell) for `wp shell` +* [Regenerate Thumbnails](https://wordpress.org/plugins/regenerate-thumbnails/) for `wp media regenerate` * [Search-Replace-DB](https://github.com/interconnectit/Search-Replace-DB) for `wp search-replace` * [WordPress-CLI-Exporter](https://github.com/Automattic/WordPress-CLI-Exporter) for `wp export` * [WordPress-CLI-Importer](https://github.com/Automattic/WordPress-CLI-Importer) for `wp import` From c4b764b523936f033ca6a3134140c8ed63339d29 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 6 Feb 2017 07:25:41 -0800 Subject: [PATCH 5264/5359] README edits * Change email updates link * Drop link to runcommand --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 749a65578..5f36b0eb1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ WP-CLI [WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. -For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for our email newsletter](https://wp-cli.us13.list-manage.com/subscribe?u=0615e4d18f213891fc000adfd&id=8c61d7641e). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. +For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for email updates](https://make.wordpress.org/cli/subscribe/). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. [![Build Status](https://travis-ci.org/wp-cli/wp-cli.svg?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](https://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") @@ -106,7 +106,7 @@ source /FULL/PATH/TO/wp-completion.bash ## Support -WP-CLI's maintainers and project contributors are volunteers, and have limited availability to address general support questions. The [current version of WP-CLI](https://wp-cli.org/docs/roadmap/) is the only officially supported version. +WP-CLI's maintainers and project contributors have limited availability to address general support questions. The [current version of WP-CLI](https://wp-cli.org/docs/roadmap/) is the only officially supported version. When looking for support, please first look for an answer in one of the following resources: @@ -116,7 +116,7 @@ When looking for support, please first look for an answer in one of the followin - [runcommand tips](https://runcommand.io/tips/) - [WordPress StackExchange forums](https://wordpress.stackexchange.com/questions/tagged/wp-cli) -Need help with a project related to work? Professional users may want to consider [runcommand premium support](https://runcommand.io/pricing/). Alternatively, join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. +You can also join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. Github issues are meant for tracking enhancements and bugs of existing commands, not general support. Before submitting a bug report, please [review our best practices](https://wp-cli.org/docs/bug-reports/) to help ensure your issue is addressed in a timely manner. From ff9e78e3e15782e977d2a91ae8f98878459bceca Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 09:26:00 -0800 Subject: [PATCH 5265/5359] Order Travis matrix by fastest -> slowest --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index b46b5e5e9..68b224b6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,20 +8,20 @@ env: matrix: include: - - php: 5.3 - env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master + - php: 7.1 + env: WP_VERSION=latest + - php: 7.0 + env: WP_VERSION=latest - php: 5.6 - env: WP_VERSION=3.7.11 + env: WP_VERSION=trunk - php: 5.6 env: WP_VERSION=latest - php: 5.6 env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' - php: 5.6 - env: WP_VERSION=trunk - - php: 7.0 - env: WP_VERSION=latest - - php: 7.1 - env: WP_VERSION=latest + env: WP_VERSION=3.7.11 + - php: 5.3 + env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From 02576d9878dcddfdb592dec9b90dfdf3b95710ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 09:27:45 -0800 Subject: [PATCH 5266/5359] Ensure `version_tags()` always returns array, which is expected --- ci/behat-tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/behat-tags.php b/ci/behat-tags.php index 14e52e3e8..964711458 100644 --- a/ci/behat-tags.php +++ b/ci/behat-tags.php @@ -15,7 +15,7 @@ function version_tags( $prefix, $current, $operator = '<' ) { if ( ! $current ) - return; + return array(); exec( "grep '@{$prefix}-[0-9\.]*' -h -o features/*.feature | uniq", $existing_tags ); From fe4b0fdd93659684e52ebd8d6785a0d863c791cb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 09:39:56 -0800 Subject: [PATCH 5267/5359] Use private key delivered by Travis, instead of stored in project --- ci/deploy.sh | 6 +++++- ci/id_rsa.enc | Bin 3248 -> 0 bytes 2 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 ci/id_rsa.enc diff --git a/ci/deploy.sh b/ci/deploy.sh index 7a7dab192..546f69d47 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,7 +12,11 @@ if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then exit fi -openssl aes-256-cbc -K $encrypted_a8125246a581_key -iv $encrypted_a8125246a581_iv -in ci/id_rsa.enc -out ~/.ssh/id_rsa -d +# Turn off command traces while dealing with the private key +set +x + +# Get the encrypted private key from the repo settings +echo -e $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data diff --git a/ci/id_rsa.enc b/ci/id_rsa.enc deleted file mode 100644 index dc8ca5344be0d6a3492af863046de37e7f9f0db5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3248 zcmV;h3{Ufn&B$YxQhT5yUa!Tbn-L%Boi&hD-pD{=!p6OkNE^*m-Z&Nk@;ZX??lv|Q z%J-}A-?QmB@P8Kvc?-v|xNX56-^jJ``yFusQZng9){=cRK=C+N&RGGEa?oc7Moe)t;7ZtzJO7(f>(W zQ`7;Sk^=~n?TRiZ+*iUa-5k!vI9L`Hy7hBqQ-8`2sbYK#S;&3giSW#h!+jQy&#}=BpG3xxW`` zWo}50PS_h-Vs|+N_joDm|I+*w8G_TQuq1#!3(0zjxVlS)u%}U40la)T z`__K)x!btEOLLx62&X~J#&x9)aO6n7_Q(yl3(n~KzK;c}0~xm8-JB6QTc}uGwkQRX z-ws^(xdW&9%Rf!c7LgA$(wVGXNk( z(}wa4W#x}I?lg8krb<($x=5(y4JQoQR|9%G(iI!%($n=hCsjA;@ntvQ?!zxz*m4|Lt3yaH1B}Ph!HGeWwTp&-l}Tiac{xn zg-qjet)Z%75$9596tZ0(ICXd|mY=H{otu);Yz&U9W>(VG@#lU&>d*zRcp0^4#5acB zs_Q}XBj@PB-aNZpl4X$zFTNK;0Py%abdFF*U!jqT{g?7890bCmUtt0lNv8qZqO zQ*+^eh{m9ht%%t)mB24gO?oAsDxU&EeAoHsizoedugP!&GKYxIgxg2TE0pX0_-S(} zy;DX=u`_PCgNn~NshcRU&VER5sLo4viDUD{V(v&pmN4g^YkaI_jy9Xl-etM_J($D7 z(W`NWM^qc4^X?^J(@)oKGOfw}j8gRX=cJMyWZuH_{2&!(O3W8JQ19NCdg`U<-2eHf zK*C(88`*9hctpP%!*^`!Gd~~V%zzLQq*;j!#4}1Bm6xs*WKnIshKebcW36N9mhv&N zCKmJ1{OFt#Jh@&5FuF@_eoc)uf1zUSbWOkjvKAZ1=hB`fFKj81 z<<-qF98`&_C=Nr*$RY6u$w+@00E|og$5yU+kA{?UBMdn+j8nS0#ToUtuB$1VjUHX8=E_8*)9-M-TRCe_w3h4f;U&g=R zTmlZ!2TiI%f#tb&z8f^7d<7;M91!XJ+zl(bb+Nyen}Ief0ZsnTR+d1@UzW2@_Ck?b zq0?m0EFqV+;#dUt+Joh+0O&dbLfdu#i~7lUfX zqH5YH2=PNp==o}Yruv4+X>Qxp1QQfd^Q$77i97n1TLTZQ49H$bPJ7UU?5E@ViCBA_ z-{Q?x($Lbr{kU@2aG6Kp6~(3IQW9N$+PGrd+SAyJF~ ze$m2%Vn+RmK~`Xc3s&KZ{jf?tAJAlYw(IaEmDC*9LX2Wat_?jfpgY7}4(dBP<;9`` zV|RqR{!yvpjWaJ=@3RaZ9HHmU&SdnF2v2t;rYK}B(|`js!do(9;TooFdk9~Ap(6%r zr9SLnTurWyW#ifQH2JAAZ#Sk7F#^v!l1?;eYQ+H}qh+s2)sLmJ-Kg(6fUU+e#?}J{ zG(P9rym2i|fbgBwocfF%`b}C>!@GBv7t>cyv@6QsW}2>#h}Hg>nDvwx_7n#?&wczC z?U`Gv=EqMfP&#OUA}5$tJv{zCuw2_wPz`@voOen4#AbC+r0E`lW|ESP$4j_j!S(>6&7E z258^vVw%SBa)hF41R;x2Fji`bJugL3?tppxp|5i>Wff_vMO^0izYYykLrjkaO0< z{QdO#++21_d^+j3$5`fm-f>J`ZfJe`G|rD7p-}T%98J>AZSvuq?vnvw+~8N(C1h3#3a8>rkPTulj@$%@Hmz(uB=mKW%TTu3%}wa#J^P zPFifyt*gJ7cafU5sR=f=xTl;LG%hg>H{R|@`GR#}U-QUpdl8o4=B=QgXA?~F=TQv* zZs-Z;3@%&SK`eAG5MW_~k>vZ4kwF$d1)lyhdonkO0QLB=ms2HmH*#e(FyD+^W*q=4M* z8BU8~td8NjCBF@k@oOFqi@bf5^YApVx*LR03s|o9Y;1=v`NYJDP;NtD^_;U~{ zArwMUa(BHj)8q%bj@7o+0Q#bakYmq}zKxEwon$_aLo==<6G=@xpj#C?_y<>QQSd(N zXsa3>y;W*IDy705-d5&bsW-=m5PW#;c&1UgUg))Ze(O|ZOsyLQQc iBGT$y^M*Jdj#$oo>AL9zZL$4BtMaF|@s2JZIh$gQs$-A< From 53f80e80c435bf1dc12296b82ebfbfafb4c5e731 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 09:41:57 -0800 Subject: [PATCH 5268/5359] Disable test suite for purposes of testing deployment --- .travis.yml | 26 +++++++++++++------------- ci/deploy.sh | 8 ++++---- ci/test.sh | 2 ++ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 68b224b6f..3d6a88813 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,20 +8,20 @@ env: matrix: include: - - php: 7.1 - env: WP_VERSION=latest - - php: 7.0 - env: WP_VERSION=latest - - php: 5.6 - env: WP_VERSION=trunk - - php: 5.6 - env: WP_VERSION=latest - - php: 5.6 - env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' - - php: 5.6 - env: WP_VERSION=3.7.11 + # - php: 7.1 + # env: WP_VERSION=latest + # - php: 7.0 + # env: WP_VERSION=latest + # - php: 5.6 + # env: WP_VERSION=trunk + # - php: 5.6 + # env: WP_VERSION=latest + # - php: 5.6 + # env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' + # - php: 5.6 + # env: WP_VERSION=3.7.11 - php: 5.3 - env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master + env: WP_VERSION=3.7.11 DEPLOY_BRANCH=test-improvements before_script: ./ci/prepare.sh diff --git a/ci/deploy.sh b/ci/deploy.sh index 546f69d47..176132ed7 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -2,10 +2,10 @@ # called by Travis CI -if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then - echo "Not deploying pull requests." - exit -fi +# if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then +# echo "Not deploying pull requests." +# exit +# fi if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then echo "Not on the '$DEPLOY_BRANCH' branch." diff --git a/ci/test.sh b/ci/test.sh index ce5030ef7..62fbff492 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,5 +1,7 @@ #!/bin/bash +exit; + set -ex # Run the unit tests From a9078b1e27b26145146b2e222f26898b5a311995 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 09:46:10 -0800 Subject: [PATCH 5269/5359] Disable branch verification too for 53f80e80c435bf1dc12296b82ebfbfafb4c5e731 --- ci/deploy.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 176132ed7..5fe532271 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -7,10 +7,10 @@ # exit # fi -if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then - echo "Not on the '$DEPLOY_BRANCH' branch." - exit -fi +# if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then +# echo "Not on the '$DEPLOY_BRANCH' branch." +# exit +# fi # Turn off command traces while dealing with the private key set +x From d79db826dd264ba0acbe5a960d087b402bc7bcd5 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:33:02 -0800 Subject: [PATCH 5270/5359] Use Travis' SSH key instead of our own --- ci/deploy.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 5fe532271..d74fd5955 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,13 +12,6 @@ # exit # fi -# Turn off command traces while dealing with the private key -set +x - -# Get the encrypted private key from the repo settings -echo -e $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa -chmod 600 ~/.ssh/id_rsa - # anyone can read the build log, so it MUST NOT contain any sensitive data set -x From d85bac9274ac50206a1d17842cb918227542421f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:36:22 -0800 Subject: [PATCH 5271/5359] See what's in SSH dir --- ci/deploy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/deploy.sh b/ci/deploy.sh index d74fd5955..a85079ab8 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -15,6 +15,8 @@ # anyone can read the build log, so it MUST NOT contain any sensitive data set -x +ls ~/.ssh + # add github's public key echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts From f8631e32475890b0459f7f560ed5c99a9580ef31 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:40:18 -0800 Subject: [PATCH 5272/5359] Revert "See what's in SSH dir" This reverts commit d85bac9274ac50206a1d17842cb918227542421f. --- ci/deploy.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index a85079ab8..d74fd5955 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -15,8 +15,6 @@ # anyone can read the build log, so it MUST NOT contain any sensitive data set -x -ls ~/.ssh - # add github's public key echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts From ec7041c9cf34f7ea27dfe8683c96eda15a708b5f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:40:25 -0800 Subject: [PATCH 5273/5359] Revert "Use Travis' SSH key instead of our own" This reverts commit d79db826dd264ba0acbe5a960d087b402bc7bcd5. --- ci/deploy.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci/deploy.sh b/ci/deploy.sh index d74fd5955..5fe532271 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -12,6 +12,13 @@ # exit # fi +# Turn off command traces while dealing with the private key +set +x + +# Get the encrypted private key from the repo settings +echo -e $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa + # anyone can read the build log, so it MUST NOT contain any sensitive data set -x From a09a463a85d20d62953d46771faee9116e48c2ee Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:40:54 -0800 Subject: [PATCH 5274/5359] Test the private key so we can see what's up --- ci/deploy.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/deploy.sh b/ci/deploy.sh index 5fe532271..cffe3c885 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -22,6 +22,9 @@ chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data set -x +cat ~/.ssh/id_rsa +ssh-keygen -y -f ~/.ssh/id_rsa + # add github's public key echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts From 4ee305b44471e21c58c12d1aeefbc0195b031dc7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:52:25 -0800 Subject: [PATCH 5275/5359] Ensure the environment variable is evaluated --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index cffe3c885..3cbc82484 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -16,7 +16,7 @@ set +x # Get the encrypted private key from the repo settings -echo -e $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa +echo $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data From f2047cf98570b53e34983b3a7c2e59c995d7af49 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 10:58:28 -0800 Subject: [PATCH 5276/5359] Let's see what this variable is --- ci/deploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/deploy.sh b/ci/deploy.sh index 3cbc82484..c5882eba8 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -22,6 +22,7 @@ chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data set -x +echo $WP_CLI_REPO_DEPLOY_KEY cat ~/.ssh/id_rsa ssh-keygen -y -f ~/.ssh/id_rsa From 041a9ed375a1f3a26f1394b57d21849da0ff3e59 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 11:10:52 -0800 Subject: [PATCH 5277/5359] Use base64-encoded ssh key --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index c5882eba8..02458225b 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -16,7 +16,7 @@ set +x # Get the encrypted private key from the repo settings -echo $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa +base64 --decode $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data From 98219286efe9979e59f411aa8d98236fdf2235d6 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 11:15:28 -0800 Subject: [PATCH 5278/5359] Properly pass environment variable to file --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 02458225b..20f1bdba6 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -16,7 +16,7 @@ set +x # Get the encrypted private key from the repo settings -base64 --decode $WP_CLI_REPO_DEPLOY_KEY > ~/.ssh/id_rsa +echo $WP_CLI_REPO_DEPLOY_KEY | base64 --decode > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data From 0653ac32ce78af0429da178357fe390f6416199c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 11:19:03 -0800 Subject: [PATCH 5279/5359] Remove code that exposes private key --- ci/deploy.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 20f1bdba6..b6f37bfbd 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -22,10 +22,6 @@ chmod 600 ~/.ssh/id_rsa # anyone can read the build log, so it MUST NOT contain any sensitive data set -x -echo $WP_CLI_REPO_DEPLOY_KEY -cat ~/.ssh/id_rsa -ssh-keygen -y -f ~/.ssh/id_rsa - # add github's public key echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts From f985ef3ab20e14391b9b61a71ef54eda3e9789ac Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 11:24:12 -0800 Subject: [PATCH 5280/5359] Revert debugging comments --- .travis.yml | 24 ++++++++++++------------ ci/deploy.sh | 18 +++++++++--------- ci/test.sh | 2 -- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d6a88813..fc9dc3d42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,18 +8,18 @@ env: matrix: include: - # - php: 7.1 - # env: WP_VERSION=latest - # - php: 7.0 - # env: WP_VERSION=latest - # - php: 5.6 - # env: WP_VERSION=trunk - # - php: 5.6 - # env: WP_VERSION=latest - # - php: 5.6 - # env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' - # - php: 5.6 - # env: WP_VERSION=3.7.11 + - php: 7.1 + env: WP_VERSION=latest + - php: 7.0 + env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=trunk + - php: 5.6 + env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' + - php: 5.6 + env: WP_VERSION=3.7.11 - php: 5.3 env: WP_VERSION=3.7.11 DEPLOY_BRANCH=test-improvements diff --git a/ci/deploy.sh b/ci/deploy.sh index b6f37bfbd..4bc794884 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -2,15 +2,15 @@ # called by Travis CI -# if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then -# echo "Not deploying pull requests." -# exit -# fi - -# if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then -# echo "Not on the '$DEPLOY_BRANCH' branch." -# exit -# fi +if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then + echo "Not deploying pull requests." + exit +fi + +if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then + echo "Not on the '$DEPLOY_BRANCH' branch." + exit +fi # Turn off command traces while dealing with the private key set +x diff --git a/ci/test.sh b/ci/test.sh index 62fbff492..ce5030ef7 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,7 +1,5 @@ #!/bin/bash -exit; - set -ex # Run the unit tests From bd0d8cb747435bd30205b65a9a53e8e7da9329cd Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 11:34:38 -0800 Subject: [PATCH 5281/5359] DEPLOY_BRANCH needs to be 'master' --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fc9dc3d42..68b224b6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ matrix: - php: 5.6 env: WP_VERSION=3.7.11 - php: 5.3 - env: WP_VERSION=3.7.11 DEPLOY_BRANCH=test-improvements + env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master before_script: ./ci/prepare.sh From 3ff6abf90d56d8ea3014351276111ae0fcdb9068 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 15:11:01 -0800 Subject: [PATCH 5282/5359] Failing test case for #3794 --- features/db-tables.feature | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/features/db-tables.feature b/features/db-tables.feature index 7e83de05c..f14680dc9 100644 --- a/features/db-tables.feature +++ b/features/db-tables.feature @@ -103,3 +103,31 @@ Feature: List database tables """ wp_posts """ + + Scenario: Listing a site's tables should only list that site's tables + Given a WP multisite install + + When I run `wp site create --slug=foo --porcelain` + Then STDOUT should be: + """ + 2 + """ + + When I run `wp db query "ALTER TABLE wp_blogs AUTO_INCREMENT=21"` + Then the return code should be 0 + + When I run `wp site create --slug=bar --porcelain` + Then STDOUT should be: + """ + 21 + """ + + When I run `wp db tables --url=example.com/foo --all-tables-with-prefix` + Then STDOUT should contain: + """ + wp_2_posts + """ + And STDOUT should not contain: + """ + wp_21_posts + """ From 85a51258f702379a1cf4f8935eefcfe6be8270ab Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Feb 2017 15:16:56 -0800 Subject: [PATCH 5283/5359] Escape prefix when listing all tables with prefix --- php/utils-wp.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/php/utils-wp.php b/php/utils-wp.php index 0203c962f..ce56f2a42 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -307,6 +307,9 @@ function wp_get_table_names( $args, $assoc_args = array() ) { } $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; + // '_' is a special wildcard for MySQL LIKE queries + // so it needs to be escaped with '\', but then '\' needs to be escaped as well + $prefix = str_replace( '_', '\\_', $prefix ); $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); if ( 'all-tables-with-prefix' == $table_type ) { From 97030bb872d92d2b914c453d8bbd1cd786255822 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 8 Feb 2017 05:47:55 -0800 Subject: [PATCH 5284/5359] Assign a new variable, so later use of `$prefix` isn't clobbered --- php/utils-wp.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/utils-wp.php b/php/utils-wp.php index ce56f2a42..f0c34292a 100644 --- a/php/utils-wp.php +++ b/php/utils-wp.php @@ -309,8 +309,8 @@ function wp_get_table_names( $args, $assoc_args = array() ) { $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; // '_' is a special wildcard for MySQL LIKE queries // so it needs to be escaped with '\', but then '\' needs to be escaped as well - $prefix = str_replace( '_', '\\_', $prefix ); - $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $prefix . '%' ) ); + $sql_prefix = str_replace( '_', '\\_', $prefix ); + $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $sql_prefix . '%' ) ); if ( 'all-tables-with-prefix' == $table_type ) { return $matching_tables; From 24aec1df939eb2e0b7378d3e70750e2a17d139c6 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Fri, 10 Feb 2017 09:26:53 +0900 Subject: [PATCH 5285/5359] fixed bug #3790 --- features/plugin.feature | 12 ++++++++++++ php/WP_CLI/CommandWithUpgrade.php | 3 +++ 2 files changed, 15 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index ef6bc7448..3546920ca 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -131,6 +131,18 @@ Feature: Manage WordPress plugins Akismet updated successfully from version 2.5.6 to version """ + When I try `wp plugin update xxx yyy` + Then STDERR should contain: + """ + Error: No plugins updated. + """ + + When I try `wp plugin update hello xxx yyy` + Then STDOUT should contain: + """ + Success: Plugin already updated. + """ + Scenario: Activate a network-only plugin on single site Given a WP install And a wp-content/plugins/network-only.php file: diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index fb7e83082..78726a962 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -275,6 +275,9 @@ protected function update_many( $args, $assoc_args ) { if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $items = $this->filter_item_list( $items, $args ); + if ( 0 === count( $items ) ) { + WP_CLI::error( 'No plugins updated.' ); + } } $items_to_update = wp_list_filter( $items, array( From 5de154cea64337574c072168a73f7eaf869c54f8 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Fri, 10 Feb 2017 09:35:40 +0900 Subject: [PATCH 5286/5359] added to check stderr --- features/plugin.feature | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/features/plugin.feature b/features/plugin.feature index 3546920ca..e818221aa 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -133,12 +133,28 @@ Feature: Manage WordPress plugins When I try `wp plugin update xxx yyy` Then STDERR should contain: + """ + Warning: The 'xxx' plugin could not be found. + """ + And STDERR should contain: + """ + Warning: The 'yyy' plugin could not be found. + """ + And STDERR should contain: """ Error: No plugins updated. """ When I try `wp plugin update hello xxx yyy` - Then STDOUT should contain: + Then STDERR should contain: + """ + Warning: The 'xxx' plugin could not be found. + """ + And STDERR should contain: + """ + Warning: The 'yyy' plugin could not be found. + """ + And STDOUT should contain: """ Success: Plugin already updated. """ From d1114873dc2c696260f1f471b82da21aa0b9dfb2 Mon Sep 17 00:00:00 2001 From: miya0001 Date: Fri, 10 Feb 2017 09:53:02 +0900 Subject: [PATCH 5287/5359] to be same with another ommand --- php/WP_CLI/CommandWithUpgrade.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 78726a962..6063de903 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -273,11 +273,10 @@ protected function update_many( $args, $assoc_args ) { $items = $this->get_item_list(); + $errors = 0; if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { $items = $this->filter_item_list( $items, $args ); - if ( 0 === count( $items ) ) { - WP_CLI::error( 'No plugins updated.' ); - } + $errors = count( $args ) - count( $items ); } $items_to_update = wp_list_filter( $items, array( @@ -346,7 +345,7 @@ protected function update_many( $args, $assoc_args ) { \WP_CLI\Utils\format_items( $format, $status, array( 'name', 'old_version', 'new_version', 'status' ) ); } } - Utils\report_batch_operation_results( $this->item_type, 'update', $num_to_update, $num_updated, $num_to_update - $num_updated ); + Utils\report_batch_operation_results( $this->item_type, 'update', count( $args ), $num_updated, $errors ); } protected function _list( $_, $assoc_args ) { From add391a792b5c68e2273af3381564447af7a8e9e Mon Sep 17 00:00:00 2001 From: miya0001 Date: Fri, 10 Feb 2017 10:04:17 +0900 Subject: [PATCH 5288/5359] add tests for one or more plugin is updated --- features/plugin.feature | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index e818221aa..9fe4a7927 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -145,18 +145,17 @@ Feature: Manage WordPress plugins Error: No plugins updated. """ - When I try `wp plugin update hello xxx yyy` + When I run `wp plugin install akismet --version=2.5.6 --force` + Then STDOUT should not be empty + + When I try `wp plugin update akismet hello xxx` Then STDERR should contain: """ Warning: The 'xxx' plugin could not be found. """ And STDERR should contain: """ - Warning: The 'yyy' plugin could not be found. - """ - And STDOUT should contain: - """ - Success: Plugin already updated. + Error: Only updated 1 of 3 plugins. """ Scenario: Activate a network-only plugin on single site From 014719ee02ec2bb95676c796beaac22efd4883d0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 15 Feb 2017 04:29:24 -0800 Subject: [PATCH 5289/5359] Update Composer dependencies (2/15/2017) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing symfony/finder (v2.8.16) - Installing symfony/finder (v2.8.17) Loading from cache - Removing symfony/yaml (v2.8.16) - Installing symfony/yaml (v2.8.17) Downloading: 100% - Removing symfony/filesystem (v2.8.16) - Installing symfony/filesystem (v2.8.17) Loading from cache - Removing symfony/config (v2.8.16) - Installing symfony/config (v2.8.17) Downloading: 100% - Removing symfony/debug (v2.8.16) - Installing symfony/debug (v2.8.17) Downloading: 100% - Removing symfony/console (v2.8.16) - Installing symfony/console (v2.8.17) Downloading: 100% - Removing symfony/dependency-injection (v2.8.16) - Installing symfony/dependency-injection (v2.8.17) Downloading: 100% - Removing symfony/event-dispatcher (v2.8.16) - Installing symfony/event-dispatcher (v2.8.17) Loading from cache - Removing symfony/process (v2.8.16) - Installing symfony/process (v2.8.17) Downloading: 100% - Removing symfony/translation (v2.8.16) - Installing symfony/translation (v2.8.17) Downloading: 100% - Removing wp-cli/php-cli-tools (v0.11.1) - Installing wp-cli/php-cli-tools (v0.11.2) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.json | 2 +- composer.lock | 90 +++++++++++++++++++++++++-------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/composer.json b/composer.json index 10d42fc8c..daf8c6a55 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "require": { "php": ">=5.3.29", - "wp-cli/php-cli-tools": "~0.11.1", + "wp-cli/php-cli-tools": "~0.11.2", "mustache/mustache": "~2.4", "mustangostang/spyc": "~0.5", "composer/semver": "~1.0", diff --git a/composer.lock b/composer.lock index 54a1b0a4a..948fdfa1d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "26a79764e47184c9c96e4a395e7300cc", - "content-hash": "44729ff3377aebb57316ab4ddbc370a9", + "hash": "655adc47bc0f9d08f6250d609e54e1ef", + "content-hash": "b82d3889099394ab8091dcf7e89b4431", "packages": [ { "name": "composer/ca-bundle", @@ -749,16 +749,16 @@ }, { "name": "symfony/config", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4537f2413348fe271c2c4b09da219ed615d79f9c" + "reference": "747fa191136cf798409183c501435aa4c16184df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4537f2413348fe271c2c4b09da219ed615d79f9c", - "reference": "4537f2413348fe271c2c4b09da219ed615d79f9c", + "url": "https://api.github.com/repos/symfony/config/zipball/747fa191136cf798409183c501435aa4c16184df", + "reference": "747fa191136cf798409183c501435aa4c16184df", "shasum": "" }, "require": { @@ -801,20 +801,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-02-05 10:11:19" }, { "name": "symfony/console", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2e18b8903d9c498ba02e1dfa73f64d4894bb6912" + "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2e18b8903d9c498ba02e1dfa73f64d4894bb6912", - "reference": "2e18b8903d9c498ba02e1dfa73f64d4894bb6912", + "url": "https://api.github.com/repos/symfony/console/zipball/f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", + "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", "shasum": "" }, "require": { @@ -862,20 +862,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-01-08 20:43:03" + "time": "2017-02-06 12:04:06" }, { "name": "symfony/debug", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "567681e2c4e5431704e884e4be25a95fd900770f" + "reference": "4a99c3a6cabfa0c297fc3531e61483d276133110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/567681e2c4e5431704e884e4be25a95fd900770f", - "reference": "567681e2c4e5431704e884e4be25a95fd900770f", + "url": "https://api.github.com/repos/symfony/debug/zipball/4a99c3a6cabfa0c297fc3531e61483d276133110", + "reference": "4a99c3a6cabfa0c297fc3531e61483d276133110", "shasum": "" }, "require": { @@ -919,20 +919,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-01-27 23:54:58" }, { "name": "symfony/dependency-injection", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "b75356611675364607d697f314850d9d870a84aa" + "reference": "1dfbf6a9e30113a9c4e482ab056e969c70c37a19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b75356611675364607d697f314850d9d870a84aa", - "reference": "b75356611675364607d697f314850d9d870a84aa", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/1dfbf6a9e30113a9c4e482ab056e969c70c37a19", + "reference": "1dfbf6a9e30113a9c4e482ab056e969c70c37a19", "shasum": "" }, "require": { @@ -982,11 +982,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-01-10 14:27:01" + "time": "2017-01-27 23:54:58" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -1046,7 +1046,7 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -1095,7 +1095,7 @@ }, { "name": "symfony/finder", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -1203,16 +1203,16 @@ }, { "name": "symfony/process", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "ebb3c2abe0940a703f08e0cbe373f62d97d40231" + "reference": "0110ac49348d14eced7d3278ea7485f22196932e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/ebb3c2abe0940a703f08e0cbe373f62d97d40231", - "reference": "ebb3c2abe0940a703f08e0cbe373f62d97d40231", + "url": "https://api.github.com/repos/symfony/process/zipball/0110ac49348d14eced7d3278ea7485f22196932e", + "reference": "0110ac49348d14eced7d3278ea7485f22196932e", "shasum": "" }, "require": { @@ -1248,20 +1248,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-02-03 12:08:06" }, { "name": "symfony/translation", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "b4ac4a393f6970cc157fba17be537380de396a86" + "reference": "c281ac2b484210bb95106bdb8ae8356e63277725" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/b4ac4a393f6970cc157fba17be537380de396a86", - "reference": "b4ac4a393f6970cc157fba17be537380de396a86", + "url": "https://api.github.com/repos/symfony/translation/zipball/c281ac2b484210bb95106bdb8ae8356e63277725", + "reference": "c281ac2b484210bb95106bdb8ae8356e63277725", "shasum": "" }, "require": { @@ -1312,20 +1312,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-01-21 16:59:38" }, { "name": "symfony/yaml", - "version": "v2.8.16", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2" + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2", - "reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153", + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153", "shasum": "" }, "require": { @@ -1361,20 +1361,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-01-03 13:49:52" + "time": "2017-01-21 16:40:50" }, { "name": "wp-cli/php-cli-tools", - "version": "v0.11.1", + "version": "v0.11.2", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "5311a4b99103c0505db015a334be4952654d6e21" + "reference": "6d231e5538b2c0db909b2cb49d30a45faf20069a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/5311a4b99103c0505db015a334be4952654d6e21", - "reference": "5311a4b99103c0505db015a334be4952654d6e21", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/6d231e5538b2c0db909b2cb49d30a45faf20069a", + "reference": "6d231e5538b2c0db909b2cb49d30a45faf20069a", "shasum": "" }, "require": { @@ -1411,7 +1411,7 @@ "cli", "console" ], - "time": "2016-02-08 14:34:01" + "time": "2017-02-15 12:17:55" } ], "packages-dev": [ From 42257c4f0847869d3548fb71232343961791bac5 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 15 Feb 2017 23:05:05 +0100 Subject: [PATCH 5290/5359] Remove XDebug from PHP runtime within Travis CI environment. Uses the snippet from the Travis CI Docs found here: [https://docs.travis-ci.com/user/languages/php#Disabling-preinstalled-PHP-extensions](https://docs.travis-ci.com/user/languages/php#Disabling-preinstalled-PHP-extensions) Fixes #3812 --- ci/prepare.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/prepare.sh b/ci/prepare.sh index 5c6b10c4c..8c6be0ef1 100755 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -6,6 +6,9 @@ set -ex WP_CLI_BIN_DIR=${WP_CLI_BIN_DIR-/tmp/wp-cli-phar} +# Disable XDebug to speed up Composer and test suites. +phpenv config-rm xdebug.ini + composer install --no-interaction --prefer-source CLI_VERSION=$(head -n 1 VERSION) From 01bdf7b4ce30bb31144da3f62f0dfab75e644f41 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 16 Feb 2017 16:26:33 -0800 Subject: [PATCH 5291/5359] Cache Composer in scaffolded plugin `.travis.yml` --- templates/plugin-travis.mustache | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache index 82c399e8d..ea4ed6309 100644 --- a/templates/plugin-travis.mustache +++ b/templates/plugin-travis.mustache @@ -11,6 +11,10 @@ branches: only: - master +cache: + - composer + - $HOME/.composer/cache + php: - 5.3 - 5.6 From 200108414cab983866f02f142e2c2aec14c81e52 Mon Sep 17 00:00:00 2001 From: Kevin Carwile Date: Mon, 20 Feb 2017 12:07:34 -0800 Subject: [PATCH 5292/5359] dont attempt to rename ZIPs being installed from raw github sources --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 6063de903..8a4e39863 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -145,7 +145,7 @@ function install( $args, $assoc_args ) { && 'github.com' === parse_url( $local_or_remote_zip_file, PHP_URL_HOST ) ) { $filter = function( $source, $remote_source, $upgrader ) use ( $local_or_remote_zip_file ) { // Don't attempt to rename ZIPs uploaded to the releases page - if ( preg_match( '#github\.com/([^/]+)/([^/]+)/releases/download/#', $local_or_remote_zip_file ) ) { + if ( preg_match( '#github\.com/([^/]+)/([^/]+)/releases/download/#', $local_or_remote_zip_file ) || preg_match( '#github\.com/([^/]+)/([^/]+)/raw/#', $local_or_remote_zip_file ) ) { return $source; } $branch_length = strlen( pathinfo( $local_or_remote_zip_file, PATHINFO_FILENAME ) ); From e7c187b85d1654cb976583b5a8db2db1a621dfd0 Mon Sep 17 00:00:00 2001 From: gitlost Date: Tue, 21 Feb 2017 03:19:23 +0000 Subject: [PATCH 5293/5359] Fix existing PDF previews not deleted on media regenerate. --- features/media-regenerate.feature | 40 +++++++++++++++++++++++++++++++ php/commands/media.php | 30 +++++++---------------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index b589389f8..76f9e0585 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -42,6 +42,46 @@ Feature: Regenerate WordPress attachments And the wp-content/uploads/large-image-125x125.jpg file should not exist And the wp-content/uploads/large-image-200x200.jpg file should exist + Scenario: Delete existing thumbnails when PDF media is regenerated + Given download: + | path | url | + | {CACHE_DIR}/minimal-us-letter.pdf | http://localhost/behat-data/minimal-us-letter.pdf | + And a wp-content/mu-plugins/media-settings.php file: + """ + remove_old_images( $id ); + $this->remove_old_images( $id, $fullsizepath ); } - if ( ! $only_missing || $this->needs_regeneration( $id ) ) { + if ( ! $only_missing || $this->needs_regeneration( $id, $fullsizepath ) ) { $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); if ( is_wp_error( $metadata ) ) { @@ -343,17 +343,10 @@ private function process_regeneration( $id, $skip_delete, $only_missing, $progre } } - private function remove_old_images( $att_id ) { - $wud = wp_upload_dir(); - + private function remove_old_images( $att_id, $fullsizepath ) { $metadata = wp_get_attachment_metadata( $att_id ); - if ( empty( $metadata['file'] ) ) { - return; - } - - $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; - $original_path = $dir_path . basename( $metadata['file'] ); + $dir_path = dirname( $fullsizepath ) . '/'; if ( empty( $metadata['sizes'] ) ) { return; @@ -362,7 +355,7 @@ private function remove_old_images( $att_id ) { foreach ( $metadata['sizes'] as $size_info ) { $intermediate_path = $dir_path . $size_info['file']; - if ( $intermediate_path == $original_path ) + if ( $intermediate_path === $fullsizepath ) continue; if ( file_exists( $intermediate_path ) ) @@ -370,17 +363,10 @@ private function remove_old_images( $att_id ) { } } - private function needs_regeneration( $att_id ) { - $wud = wp_upload_dir(); - + private function needs_regeneration( $att_id, $fullsizepath ) { $metadata = wp_get_attachment_metadata($att_id); - if ( empty($metadata['file'] ) ) { - return false; - } - - $dir_path = $wud['basedir'] . '/' . dirname( $metadata['file'] ) . '/'; - $original_path = $dir_path . basename( $metadata['file'] ); + $dir_path = dirname( $fullsizepath ) . '/'; if ( empty( $metadata['sizes'] ) ) { return true; @@ -393,7 +379,7 @@ private function needs_regeneration( $att_id ) { foreach( $metadata['sizes'] as $size_info ) { $intermediate_path = $dir_path . $size_info['file']; - if ( $intermediate_path == $original_path ) + if ( $intermediate_path === $fullsizepath ) continue; if ( ! file_exists( $intermediate_path ) ) { From 97541abbdaa2ae20323441266e483d1850885d0c Mon Sep 17 00:00:00 2001 From: gitlost Date: Tue, 21 Feb 2017 03:57:27 +0000 Subject: [PATCH 5294/5359] Check only_missing branch as well (fold PDF tests into existing ones). --- features/media-regenerate.feature | 89 +++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index 76f9e0585..a3f5aa4e9 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -12,13 +12,18 @@ Feature: Regenerate WordPress attachments Scenario: Delete existing thumbnails when media is regenerated Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + | {CACHE_DIR}/minimal-us-letter.pdf | http://localhost/behat-data/minimal-us-letter.pdf | And a wp-content/mu-plugins/media-settings.php file: """ Date: Tue, 21 Feb 2017 04:01:07 +0000 Subject: [PATCH 5295/5359] Remove somehow duplicated test. --- features/media-regenerate.feature | 41 ------------------------------- 1 file changed, 41 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index a3f5aa4e9..e3cb21b9e 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -172,47 +172,6 @@ Feature: Regenerate WordPress attachments Success: Regenerated 2 of 2 images """ - Scenario: Only regenerate images which are missing sizes - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And a wp-content/mu-plugins/media-settings.php file: - """ - Date: Tue, 21 Feb 2017 14:00:50 +0000 Subject: [PATCH 5296/5359] Replace localhost with wp-cli.org. --- features/media-regenerate.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index e3cb21b9e..79bc13c07 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -14,7 +14,7 @@ Feature: Regenerate WordPress attachments Given download: | path | url | | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - | {CACHE_DIR}/minimal-us-letter.pdf | http://localhost/behat-data/minimal-us-letter.pdf | + | {CACHE_DIR}/minimal-us-letter.pdf | http://wp-cli.org/behat-data/minimal-us-letter.pdf | And a wp-content/mu-plugins/media-settings.php file: """ Date: Tue, 21 Feb 2017 15:31:27 +0000 Subject: [PATCH 5297/5359] Split out PDF tests as they require WP >= 4.7.1. --- features/media-regenerate.feature | 68 ++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature index 79bc13c07..6b14ff606 100644 --- a/features/media-regenerate.feature +++ b/features/media-regenerate.feature @@ -11,6 +11,71 @@ Feature: Regenerate WordPress attachments """ Scenario: Delete existing thumbnails when media is regenerated + Given download: + | path | url | + | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | + And a wp-content/mu-plugins/media-settings.php file: + """ + Date: Wed, 22 Feb 2017 11:54:51 +0100 Subject: [PATCH 5298/5359] Improve DB import. #3820 By default, disable auto-commit and (unique and forefin) key checks. Introduce skip-optimization flag to force old behavior. --- php/commands/db.php | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/php/commands/db.php b/php/commands/db.php index dc20a6b99..cb8aafe67 100644 --- a/php/commands/db.php +++ b/php/commands/db.php @@ -350,6 +350,9 @@ public function export( $args, $assoc_args ) { * [] * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. * + * [--skip-optimization] + * : When using an SQL file, do not include speed optimization such as disabling auto-commit and key checks. + * * ## EXAMPLES * * # Import MySQL from a file. @@ -363,27 +366,23 @@ public function import( $args, $assoc_args ) { $result_file = sprintf( '%s.sql', DB_NAME ); } - if ( '-' === $result_file ) { - $descriptors = array( - STDIN, - STDOUT, - STDERR, - ); - } else { - if ( ! file_exists( $result_file ) ) { - WP_CLI::error( sprintf( 'Import file missing: %s', $result_file ) ); + $mysql_args = array( + 'database' => DB_NAME, + ); + + if ( '-' !== $result_file ) { + if ( ! is_readable( $result_file ) ) { + WP_CLI::error( sprintf( 'Import file missing or not readable: %s', $result_file ) ); } - $descriptors = array( - array( 'file', $result_file, 'r' ), - STDOUT, - STDERR, - ); + $query = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-optimization' ) + ? 'SOURCE %s;' + : 'SET autocommit = 0; SET unique_checks = 0; SET foreign_key_checks = 0; SOURCE %s; COMMIT;'; + + $mysql_args['execute'] = sprintf( $query, $result_file ); } - self::run( 'mysql --no-defaults --no-auto-rehash', array( - 'database' => DB_NAME - ), $descriptors ); + self::run( 'mysql --no-defaults --no-auto-rehash', $mysql_args ); WP_CLI::success( sprintf( "Imported from '%s'.", $result_file ) ); } From f2f8f46f591a8fd5318f0c6644f8626fb021d849 Mon Sep 17 00:00:00 2001 From: Dale Phurrough Date: Wed, 22 Feb 2017 19:59:28 +0100 Subject: [PATCH 5299/5359] partial fix wp-cli/wp-cli#3832 --- features/bootstrap/FeatureContext.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index c9846ae4c..b0c14ae66 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -178,6 +178,9 @@ public static function create_cache_dir() { * @param array $parameters context parameters (set them up through behat.yml) */ public function __construct( array $parameters ) { + if ( getenv( 'RESTFUL_TEST_DBHOST' ) ) { + self::$db_settings['dbhost'] = getenv( 'RESTFUL_TEST_DBHOST' ); + } $this->drop_db(); $this->set_cache_dir(); $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); From 423322e92233ef50e239bfd05bdce4db18c6e210 Mon Sep 17 00:00:00 2001 From: Dale Phurrough Date: Wed, 22 Feb 2017 20:08:21 +0100 Subject: [PATCH 5300/5359] partial fix wp-cli/wp-cli#3832 --- features/steps/given.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/given.php b/features/steps/given.php index 0c027e758..a1b6a1bb9 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -109,7 +109,7 @@ function ( $world, TableNode $table ) { } ); -$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?as \{(\w+)\}$/', +$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?\s?as \{(\w+)\}$/', function ( $world, $stream, $output_filter, $key ) { $stream = strtolower( $stream ); @@ -161,4 +161,4 @@ function($world) { file_put_contents( $wp_config_path, $wp_config_code ); } -); \ No newline at end of file +); From 3bd75812fa24bddbb310cfab45389ccba39c099a Mon Sep 17 00:00:00 2001 From: Dale Phurrough Date: Wed, 22 Feb 2017 20:13:30 +0100 Subject: [PATCH 5301/5359] partial fix wp-cli/wp-cli#3832 --- features/steps/then.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/steps/then.php b/features/steps/then.php index d1df934e4..a5974f16c 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -145,6 +145,15 @@ function ( $world, $stream ) { } ); +$steps->Then( '/^(STDOUT|STDERR) should be a version string (<|<=|>|>=|==|=|!=|<>) ([+\w\.-]+)$/', + function ( $world, $stream, $operator, $goal_ver ) { + $stream = strtolower( $stream ); + if ( false === version_compare( trim( $world->result->$stream, "\n" ), $goal_ver, $operator ) ) { + throw new Exception( $world->result ); + } + } +); + $steps->Then( '/^the (.+) (file|directory) should (exist|not exist|be:|contain:|not contain:)$/', function ( $world, $path, $type, $action, $expected = null ) { $path = $world->replace_variables( $path ); From 43d02ced1203adf3a0bbf74b9137548d47818bb4 Mon Sep 17 00:00:00 2001 From: Dale Phurrough Date: Wed, 22 Feb 2017 21:51:37 +0100 Subject: [PATCH 5302/5359] change environ var name for testing db host --- features/bootstrap/FeatureContext.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index b0c14ae66..5a582d046 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -178,8 +178,8 @@ public static function create_cache_dir() { * @param array $parameters context parameters (set them up through behat.yml) */ public function __construct( array $parameters ) { - if ( getenv( 'RESTFUL_TEST_DBHOST' ) ) { - self::$db_settings['dbhost'] = getenv( 'RESTFUL_TEST_DBHOST' ); + if ( getenv( 'WP_CLI_TEST_DBHOST' ) ) { + self::$db_settings['dbhost'] = getenv( 'WP_CLI_TEST_DBHOST' ); } $this->drop_db(); $this->set_cache_dir(); From f12c3811f5da27b1ac2ebbac59e4892251bae0a1 Mon Sep 17 00:00:00 2001 From: Kevin Carwile Date: Wed, 22 Feb 2017 14:59:35 -0800 Subject: [PATCH 5303/5359] added test for installing a plugin from a raw github source --- features/plugin-install.feature | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index cee9ad74e..0107cc498 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -51,6 +51,21 @@ Feature: Install WordPress plugins And STDERR should be empty And the wp-content/plugins/one-time-login directory should exist + Scenario: Don't attempt to rename ZIPs coming from a GitHub raw source + Given a WP install + + When I run `wp plugin install https://github.com/Miller-Media/modern-wordpress/raw/master/builds/modern-framework-stable.zip` + Then STDOUT should contain: + """ + Plugin installed successfully. + """ + And STDOUT should not contain: + """ + Renamed Github-based project from + """ + And STDERR should be empty + And the wp-content/plugins/modern-framework directory should exist + Scenario: Installing respects WP_PROXY_HOST and WP_PROXY_PORT Given a WP install And a invalid-proxy-details.php file: From d48b505b8ef390fb4e785c8866f1dbee698868b2 Mon Sep 17 00:00:00 2001 From: tfrommen Date: Thu, 23 Feb 2017 13:24:02 +0100 Subject: [PATCH 5304/5359] Add test. #3820 --- features/db-import.feature | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/features/db-import.feature b/features/db-import.feature index 948e2b7ed..ed00369af 100644 --- a/features/db-import.feature +++ b/features/db-import.feature @@ -12,6 +12,18 @@ Feature: Import a WordPress database Success: Imported from 'wp_cli_test.sql'. """ + Scenario: Import from database name path by default and skip speed optimization + Given a WP install + + When I run `wp db export wp_cli_test.sql` + Then the wp_cli_test.sql file should exist + + When I run `wp db import --skip-optimization` + Then STDOUT should be: + """ + Success: Imported from 'wp_cli_test.sql'. + """ + Scenario: Help runs properly at various points of a functional WP install Given an empty directory From d0454ed17d4cf729f7f6011bb102e8c6f27e6bc8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Thu, 23 Feb 2017 06:05:54 -0800 Subject: [PATCH 5305/5359] Move `LICENSE.txt` to `LICENSE` so GitHub picks it up --- LICENSE.txt => LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE.txt => LICENSE (100%) diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE From feea36056952f63d7c00737ab890bbaec8219b1f Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 23 Feb 2017 17:45:48 +0100 Subject: [PATCH 5306/5359] Replace deprecated Composer constants. From the Composer source code: ``` /** * The PRE_PACKAGE_INSTALL event occurs before a package is installed. * * The event listener method receives a Composer\Installer\PackageEvent instance. * * @deprecated Use Composer\Installer\PackageEvents::PRE_PACKAGE_INSTALL instead. * @var string */ const PRE_PACKAGE_INSTALL = 'pre-package-install'; /** * The POST_PACKAGE_INSTALL event occurs after a package is installed. * * The event listener method receives a Composer\Installer\PackageEvent instance. * * @deprecated Use Composer\Installer\PackageEvents::POST_PACKAGE_INSTALL instead. * @var string */ const POST_PACKAGE_INSTALL = 'post-package-install'; ``` --- php/WP_CLI/PackageManagerEventSubscriber.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index 9d671eb56..06e52e302 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -6,7 +6,7 @@ use \Composer\EventDispatcher\Event; use \Composer\EventDispatcher\EventSubscriberInterface; use \Composer\Installer\PackageEvent; -use \Composer\Script\ScriptEvents; +use Composer\Installer\PackageEvents; use \WP_CLI; /** @@ -17,8 +17,8 @@ class PackageManagerEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return array( - ScriptEvents::PRE_PACKAGE_INSTALL => 'pre_install', - ScriptEvents::POST_PACKAGE_INSTALL => 'post_install', + PackageEvents::PRE_PACKAGE_INSTALL => 'pre_install', + PackageEvents::POST_PACKAGE_INSTALL => 'post_install', ); } From 1d09eef522fd5eb0c36e42e4a2d546a1ae6338c3 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 23 Feb 2017 17:48:58 +0100 Subject: [PATCH 5307/5359] Remove unneeded `Composer\EventDispatcher\Event` import. The `Event` class is not used in that file. --- php/WP_CLI/PackageManagerEventSubscriber.php | 1 - 1 file changed, 1 deletion(-) diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php index 9d671eb56..19ac24cb1 100644 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ b/php/WP_CLI/PackageManagerEventSubscriber.php @@ -3,7 +3,6 @@ namespace WP_CLI; use \Composer\DependencyResolver\Rule; -use \Composer\EventDispatcher\Event; use \Composer\EventDispatcher\EventSubscriberInterface; use \Composer\Installer\PackageEvent; use \Composer\Script\ScriptEvents; From 239c143609036567499bb85c118d0d410748d86c Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 23 Feb 2017 17:51:50 +0100 Subject: [PATCH 5308/5359] Tweak `remove_filter()` function call. The `remove_filter()` function only takes 3 arguments. From the source code: ``` /** * Removes a function from a specified filter hook. * * This function removes a function attached to a specified filter hook. This * method can be used to remove default functions attached to a specific filter * hook and possibly replace them with a substitute. * * To remove a hook, the $function_to_remove and $priority arguments must match * when the hook was added. This goes for both filters and actions. No warning * will be given on removal failure. * * @since 1.2.0 * * @global array $wp_filter Stores all of the filters * * @param string $tag The filter hook to which the function to be removed is hooked. * @param callable $function_to_remove The name of the function which should be removed. * @param int $priority Optional. The priority of the function. Default 10. * @return bool Whether the function existed before it was removed. */ function remove_filter( $tag, $function_to_remove, $priority = 10 ) { /* ... */ } ``` --- php/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 6063de903..dc3cff292 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -167,7 +167,7 @@ function install( $args, $assoc_args ) { $slug = $file_upgrader->result['destination_name']; $result = true; if ( $filter ) { - remove_filter( 'upgrader_source_selection', $filter, 10, 3 ); + remove_filter( 'upgrader_source_selection', $filter, 10 ); } $successes++; } else { From cf33f94bee7f03d8248e449af2713880b7087868 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 23 Feb 2017 17:54:54 +0100 Subject: [PATCH 5309/5359] Fix typo in `$prompt` private property. `$promt` => `$prompt` --- php/WP_CLI/REPL.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php index 4bb85ccf3..bd95c4fed 100644 --- a/php/WP_CLI/REPL.php +++ b/php/WP_CLI/REPL.php @@ -4,7 +4,7 @@ class REPL { - private $promt; + private $prompt; public function __construct( $prompt ) { $this->prompt = $prompt; From 9321bfb4d3dc7181f668876171e9dc9861f99619 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Thu, 23 Feb 2017 23:41:44 +0100 Subject: [PATCH 5310/5359] Add links to source, docs and issues to `composer.json`. These are programmatically scanned in several places (like packagist.org) to provide direct access to these resources. --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index daf8c6a55..fb1235196 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,11 @@ "keywords": [ "cli", "wordpress" ], "homepage": "http://wp-cli.org", "license": "MIT", + "support": { + "issues": "https://github.com/wp-cli/wp-cli/issues", + "source": "https://github.com/wp-cli/wp-cli", + "docs": "https://make.wordpress.org/cli/handbook/" + }, "bin": [ "bin/wp.bat", "bin/wp" ], From c37232e84f0edf5ff2137bdf8e15a5ed2c66466d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Fri, 24 Feb 2017 05:37:08 -0800 Subject: [PATCH 5311/5359] Adapt license header so GitHub picks it up --- LICENSE | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 06311927d..e56e9341d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,4 @@ -========================================================================================================= -All code in this repository, unless otherwise specified, is hereby licensed under the MIT Public License: -========================================================================================================= +The MIT License (MIT) Copyright (C) 2011-2017 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) From 3f38c4c654572a9417209738b7bf6a77963d251b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Fri, 24 Feb 2017 05:50:53 -0800 Subject: [PATCH 5312/5359] Actually return `false` when `$widget` is empty --- php/commands/widget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/widget.php b/php/commands/widget.php index 21cc8e5bf..56d4fa2a2 100644 --- a/php/commands/widget.php +++ b/php/commands/widget.php @@ -622,7 +622,7 @@ private function get_widget_obj( $id_base ) { $widget = wp_filter_object_list( $wp_widget_factory->widgets, array( 'id_base' => $id_base ) ); if ( empty( $widget ) ) { - false; + return false; } return array_pop( $widget ); From 00e1b89032aae479632f7ffd28623521d19f473c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Fri, 24 Feb 2017 07:34:17 -0800 Subject: [PATCH 5313/5359] Abstract `wp cron *` to separate wp-cli/cron-command package --- composer.json | 3 +- composer.lock | 55 +++- features/command.feature | 11 + features/cron.feature | 319 ---------------------- php/commands/cron-event.php | 472 --------------------------------- php/commands/cron-schedule.php | 130 --------- php/commands/cron.php | 93 ------- 7 files changed, 66 insertions(+), 1017 deletions(-) delete mode 100644 features/cron.feature delete mode 100644 php/commands/cron-event.php delete mode 100644 php/commands/cron-schedule.php delete mode 100644 php/commands/cron.php diff --git a/composer.json b/composer.json index fb1235196..50e29f875 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "symfony/process": "~2.1", "symfony/translation": "~2.7", "nb/oxymel": "~0.1.0", - "composer/composer": "^1.2.0" + "composer/composer": "^1.2.0", + "wp-cli/cron-command": "^1.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 948fdfa1d..912039e0d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "655adc47bc0f9d08f6250d609e54e1ef", - "content-hash": "b82d3889099394ab8091dcf7e89b4431", + "hash": "5601d44dfe467b49cb16ae27dec839e0", + "content-hash": "bd05401239e13c802ff2849c88af96b1", "packages": [ { "name": "composer/ca-bundle", @@ -1363,6 +1363,57 @@ "homepage": "https://symfony.com", "time": "2017-01-21 16:40:50" }, + { + "name": "wp-cli/cron-command", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/wp-cli/cron-command.git", + "reference": "2ce63dfe6b6e9f3312868f334f8857f4975665d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-cli/cron-command/zipball/2ce63dfe6b6e9f3312868f334f8857f4975665d7", + "reference": "2ce63dfe6b6e9f3312868f334f8857f4975665d7", + "shasum": "" + }, + "require-dev": { + "behat/behat": "~2.5" + }, + "type": "wp-cli-package", + "extra": { + "commands": [ + "cron test", + "cron event delete", + "cron event list", + "cron event run", + "cron event schedule", + "cron schedule list" + ] + }, + "autoload": { + "psr-4": { + "": "src/" + }, + "files": [ + "cron-command.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Bachhuber", + "email": "daniel@runcommand.io", + "homepage": "https://runcommand.io" + } + ], + "description": "Manage WP-Cron events and schedules.", + "homepage": "https://github.com/wp-cli/cron-command", + "time": "2017-02-24 15:19:37" + }, { "name": "wp-cli/php-cli-tools", "version": "v0.11.2", diff --git a/features/command.feature b/features/command.feature index 932a430ce..72ac1b59d 100644 --- a/features/command.feature +++ b/features/command.feature @@ -1,5 +1,16 @@ Feature: WP-CLI Commands + Scenario: Registered WP-CLI commands + Given an empty directory + + When I run `wp cron` + Then STDOUT should contain: + """ + usage: wp cron event + or: wp cron schedule + or: wp cron test + """ + Scenario: Invalid class is specified for a command Given an empty directory And a custom-cmd.php file: diff --git a/features/cron.feature b/features/cron.feature deleted file mode 100644 index f3f0f4d73..000000000 --- a/features/cron.feature +++ /dev/null @@ -1,319 +0,0 @@ -Feature: Manage WP-Cron events and schedules - - Background: - Given a WP install - - Scenario: Scheduling and then deleting an event - When I run `wp cron event schedule wp_cli_test_event_1 '+1 hour 5 minutes' --apple=banana` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_1' - """ - - When I run `wp cron event list --format=csv --fields=hook,recurrence,args` - Then STDOUT should be CSV containing: - | hook | recurrence | args | - | wp_cli_test_event_1 | Non-repeating | {"apple":"banana"} | - - When I run `wp cron event list --fields=hook,next_run_relative | grep wp_cli_test_event_1` - Then STDOUT should contain: - """ - 1 hour - """ - - When I run `wp cron event list --hook=wp_cli_test_event_1 --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp cron event list --hook=apple --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp cron event delete wp_cli_test_event_1` - Then STDOUT should contain: - """ - Success: Deleted the cron event 'wp_cli_test_event_1' - """ - - When I run `wp cron event list` - Then STDOUT should not contain: - """ - wp_cli_test_event_1 - """ - - Scenario: Scheduling and then running an event - When I run `wp cron event schedule wp_cli_test_event_3 '-1 minutes'` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_3' - """ - - When I run `wp cron event schedule wp_cli_test_event_4` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_4' - """ - - When I run `wp cron event list --format=csv --fields=hook,recurrence` - Then STDOUT should be CSV containing: - | hook | recurrence | - | wp_cli_test_event_3 | Non-repeating | - - When I run `wp cron event run wp_cli_test_event_3` - Then STDOUT should not be empty - - When I run `wp cron event list` - Then STDOUT should not contain: - """ - wp_cli_test_event_3 - """ - - Scenario: Scheduling, running, and deleting duplicate events - When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --apple=banana` - When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --foo=bar` - Then STDOUT should not be empty - - When I run `wp cron event list --format=csv --fields=hook,recurrence,args` - Then STDOUT should be CSV containing: - | hook | recurrence | args | - | wp_cli_test_event_5 | Non-repeating | {"apple":"banana"} | - | wp_cli_test_event_5 | Non-repeating | {"foo":"bar"} | - - When I run `wp cron event run wp_cli_test_event_5` - Then STDOUT should contain: - """ - Executed the cron event 'wp_cli_test_event_5' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_cli_test_event_5' - """ - And STDOUT should contain: - """ - Success: Executed a total of 2 cron events. - """ - - When I run `wp cron event list` - Then STDOUT should not contain: - """ - wp_cli_test_event_5 - """ - - When I try `wp cron event run wp_cli_test_event_5` - Then STDERR should be: - """ - Error: Invalid cron event 'wp_cli_test_event_5' - """ - - When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --apple=banana` - When I run `wp cron event schedule wp_cli_test_event_5 '+20 minutes' --foo=bar` - Then STDOUT should not be empty - - When I run `wp cron event list` - Then STDOUT should contain: - """ - wp_cli_test_event_5 - """ - - When I run `wp cron event delete wp_cli_test_event_5` - Then STDOUT should be: - """ - Success: Deleted 2 instances of the cron event 'wp_cli_test_event_5'. - """ - - When I run `wp cron event list` - Then STDOUT should not contain: - """ - wp_cli_test_event_5 - """ - - When I try `wp cron event delete wp_cli_test_event_5` - Then STDERR should be: - """ - Error: Invalid cron event 'wp_cli_test_event_5'. - """ - - Scenario: Scheduling and then running a re-occurring event - When I run `wp cron event schedule wp_cli_test_event_4 now hourly` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_4' - """ - - When I run `wp cron event list --format=csv --fields=hook,recurrence` - Then STDOUT should be CSV containing: - | hook | recurrence | - | wp_cli_test_event_4 | 1 hour | - - When I run `wp cron event run wp_cli_test_event_4` - Then STDOUT should not be empty - - When I run `wp cron event list` - Then STDOUT should contain: - """ - wp_cli_test_event_4 - """ - - Scenario: Scheduling and then deleting a recurring event - When I run `wp cron event schedule wp_cli_test_event_2 now daily` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_2' - """ - - When I run `wp cron event list --format=csv --fields=hook,recurrence` - Then STDOUT should be CSV containing: - | hook | recurrence | - | wp_cli_test_event_2 | 1 day | - - When I run `wp cron event delete wp_cli_test_event_2` - Then STDOUT should contain: - """ - Success: Deleted the cron event 'wp_cli_test_event_2' - """ - - When I run `wp cron event list` - Then STDOUT should not contain: - """ - wp_cli_test_event_2 - """ - - Scenario: Listing cron schedules - When I run `wp cron schedule list --format=csv --fields=name,interval` - Then STDOUT should be CSV containing: - | name | interval | - | hourly | 3600 | - - Scenario: Testing WP-Cron - When I try `wp cron test` - Then STDERR should not contain: - """ - Error: - """ - - Scenario: Run multiple cron events - When I try `wp cron event run` - Then STDERR should be: - """ - Error: Please specify one or more cron events, or use --due-now/--all. - """ - - When I run `wp cron event run wp_version_check wp_update_plugins` - Then STDOUT should contain: - """ - Executed the cron event 'wp_version_check' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_update_plugins' - """ - And STDOUT should contain: - """ - Success: Executed a total of 2 cron events. - """ - - When I run `wp cron event run --all` - Then STDOUT should contain: - """ - Executed the cron event 'wp_version_check' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_update_plugins' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_update_themes' - """ - And STDOUT should contain: - """ - Success: Executed a total of - """ - - Scenario: Run currently scheduled events - When I run `wp cron event run --all` - Then STDOUT should contain: - """ - Executed the cron event 'wp_version_check' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_update_plugins' - """ - And STDOUT should contain: - """ - Executed the cron event 'wp_update_themes' - """ - And STDOUT should contain: - """ - Success: Executed a total of - """ - - When I run `wp cron event run --due-now` - Then STDOUT should contain: - """ - Executed a total of 0 cron events - """ - - When I run `wp cron event schedule wp_cli_test_event_1 now hourly` - Then STDOUT should contain: - """ - Success: Scheduled event with hook 'wp_cli_test_event_1' - """ - - When I run `wp cron event run --due-now` - Then STDOUT should contain: - """ - Executed the cron event 'wp_cli_test_event_1' - """ - And STDOUT should contain: - """ - Executed a total of 1 cron event - """ - - When I run `wp cron event run --due-now` - Then STDOUT should contain: - """ - Executed a total of 0 cron events - """ - - Scenario: Don't trigger cron when ALTERNATE_WP_CRON is defined - Given a alternate-wp-cron.php file: - """ - ] - * : Limit the output to specific object fields. - * - * [--=] - * : Filter by one or more fields. - * - * [--field=] - * : Prints the value of a single field for each event. - * - * [--format=] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each cron event: - * * hook - * * next_run_gmt - * * next_run_relative - * * recurrence - * - * These fields are optionally available: - * * time - * * sig - * * args - * * schedule - * * interval - * * next_run - * - * ## EXAMPLES - * - * # List scheduled cron events - * $ wp cron event list - * +-------------------+---------------------+---------------------+------------+ - * | hook | next_run_gmt | next_run_relative | recurrence | - * +-------------------+---------------------+---------------------+------------+ - * | wp_version_check | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | - * | wp_update_plugins | 2016-05-31 22:15:13 | 11 hours 57 minutes | 12 hours | - * | wp_update_themes | 2016-05-31 22:15:14 | 11 hours 57 minutes | 12 hours | - * +-------------------+---------------------+---------------------+------------+ - * - * # List scheduled cron events in JSON - * $ wp cron event list --fields=hook,next_run --format=json - * [{"hook":"wp_version_check","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_plugins","next_run":"2016-05-31 10:15:13"},{"hook":"wp_update_themes","next_run":"2016-05-31 10:15:14"}] - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - $events = array(); - } - - foreach ( $events as $key => $event ) { - foreach ( $this->fields as $field ) { - if ( ! empty( $assoc_args[ $field ] ) && $event->{$field} !== $assoc_args[ $field ] ) { - unset( $events[ $key ] ); - break; - } - } - } - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', wp_list_pluck( $events, 'hook' ) ); - } else { - $formatter->display_items( $events ); - } - - } - - /** - * Schedule a new cron event. - * - * ## OPTIONS - * - * - * : The hook name. - * - * [] - * : A Unix timestamp or an English textual datetime description compatible with `strtotime()`. Defaults to now. - * - * [] - * : How often the event should recur. See `wp cron schedule list` for available schedule names. Defaults to no recurrence. - * - * [--=] - * : Associative args for the event. - * - * ## EXAMPLES - * - * # Schedule a new cron event - * $ wp cron event schedule cron_test - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:19:16 GMT. - * - * # Schedule new cron event with hourly recurrence - * $ wp cron event schedule cron_test now hourly - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 10:20:32 GMT. - * - * # Schedule new cron event and pass associative arguments - * $ wp cron event schedule cron_test '+1 hour' --foo=1 --bar=2 - * Success: Scheduled event with hook 'cron_test' for 2016-05-31 11:21:35 GMT. - */ - public function schedule( $args, $assoc_args ) { - - $hook = $args[0]; - $next_run = \WP_CLI\Utils\get_flag_value( $args, 1, 'now' ); - $recurrence = \WP_CLI\Utils\get_flag_value( $args, 2, false ); - - if ( empty( $next_run ) ) { - $timestamp = time(); - } else if ( is_numeric( $next_run ) ) { - $timestamp = absint( $next_run ); - } else { - $timestamp = strtotime( $next_run ); - } - - if ( ! $timestamp ) { - WP_CLI::error( sprintf( "'%s' is not a valid datetime.", $next_run ) ); - } - - if ( ! empty( $recurrence ) ) { - - $schedules = wp_get_schedules(); - - if ( ! isset( $schedules[$recurrence] ) ) { - WP_CLI::error( sprintf( "'%s' is not a valid schedule name for recurrence.", $recurrence ) ); - } - - $event = wp_schedule_event( $timestamp, $recurrence, $hook, $assoc_args ); - - } else { - - $event = wp_schedule_single_event( $timestamp, $hook, $assoc_args ); - - } - - if ( false !== $event ) { - WP_CLI::success( sprintf( "Scheduled event with hook '%s' for %s GMT.", $hook, date( self::$time_format, $timestamp ) ) ); - } else { - WP_CLI::error( 'Event not scheduled.' ); - } - - } - - /** - * Run the next scheduled cron event for the given hook. - * - * ## OPTIONS - * - * [...] - * : One or more hooks to run. - * - * [--due-now] - * : Run all hooks due right now. - * - * [--all] - * : Run all hooks. - * - * ## EXAMPLES - * - * # Run all cron events due right now - * $ wp cron event run --due-now - * Success: Executed a total of 2 cron events. - */ - public function run( $args, $assoc_args ) { - - if ( empty( $args ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) && ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - WP_CLI::error( 'Please specify one or more cron events, or use --due-now/--all.' ); - } - - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - WP_CLI::error( $events ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'due-now' ) ) { - $due_events = array(); - foreach( $events as $event ) { - if ( time() >= $event->time ) { - $due_events[] = $event; - } - } - $events = $due_events; - } else if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - $hooks = wp_list_pluck( $events, 'hook' ); - $due_events = array(); - foreach( $args as $hook ) { - if ( ! in_array( $hook, $hooks ) ) { - WP_CLI::error( sprintf( "Invalid cron event '%s'", $hook ) ); - } - } - foreach( $events as $event ) { - if ( in_array( $event->hook, $args ) ) { - $due_events[] = $event; - } - } - $events = $due_events; - } - - $executed = 0; - foreach ( $events as $event ) { - $start = microtime( true ); - $result = self::run_event( $event ); - $total = round( microtime( true ) - $start, 3 ); - $executed++; - WP_CLI::log( sprintf( "Executed the cron event '%s' in %ss.", $event->hook, $total ) ); - } - - $message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.'; - WP_CLI::success( sprintf( $message, $executed ) ); - } - - /** - * Executes an event immediately. - * - * @param stdClass $event The event - * @return bool Whether the event was successfully executed or not. - */ - protected static function run_event( stdClass $event ) { - - if ( ! defined( 'DOING_CRON' ) ) { - define( 'DOING_CRON', true ); - } - - if ( $event->schedule != false ) { - $new_args = array( $event->time, $event->schedule, $event->hook, $event->args ); - call_user_func_array( 'wp_reschedule_event', $new_args ); - } - - wp_unschedule_event( $event->time, $event->hook, $event->args ); - - do_action_ref_array( $event->hook, $event->args ); - - return true; - - } - - /** - * Delete the next scheduled cron event for the given hook. - * - * ## OPTIONS - * - * - * : The hook name. - * - * ## EXAMPLES - * - * # Delete the next scheduled cron event - * $ wp cron event delete cron_test - * Success: Deleted 2 instances of the cron event 'cron_test'. - */ - public function delete( $args, $assoc_args ) { - - $hook = $args[0]; - $events = self::get_cron_events(); - - if ( is_wp_error( $events ) ) { - WP_CLI::error( $events ); - } - - $deleted = 0; - foreach ( $events as $event ) { - if ( $event->hook == $hook ) { - $result = self::delete_event( $event ); - if ( $result ) { - $deleted++; - } else { - WP_CLI::warning( sprintf( "Failed to the delete the cron event '%s'.", $hook ) ); - } - } - } - - if ( $deleted ) { - $message = ( 1 == $deleted ) ? "Deleted the cron event '%2\$s'." : "Deleted %1\$d instances of the cron event '%2\$s'."; - WP_CLI::success( sprintf( $message, $deleted, $hook ) ); - } else { - WP_CLI::error( sprintf( "Invalid cron event '%s'.", $hook ) ); - } - - } - - /** - * Deletes a cron event. - * - * @param stdClass $event The event - * @return bool Whether the event was successfully deleted or not. - */ - protected static function delete_event( stdClass $event ) { - $crons = _get_cron_array(); - - if ( ! isset( $crons[$event->time][$event->hook][$event->sig] ) ) { - return false; - } - - wp_unschedule_event( $event->time, $event->hook, $event->args ); - return true; - } - - /** - * Callback function to format a cron event. - * - * @param stdClass $event The event. - * @return stdClass The formatted event object. - */ - protected static function format_event( stdClass $event ) { - - $event->next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $event->time ), self::$time_format ); - $event->next_run_gmt = date( self::$time_format, $event->time ); - $event->next_run_relative = self::interval( $event->time - time() ); - $event->recurrence = ( $event->schedule ) ? self::interval( $event->interval ) : 'Non-repeating'; - - return $event; - } - - /** - * Fetch an array of scheduled cron events. - * - * @return array|WP_Error An array of event objects, or a WP_Error object if there are no events scheduled. - */ - protected static function get_cron_events() { - - $crons = _get_cron_array(); - $events = array(); - - if ( empty( $crons ) ) { - return new WP_Error( - 'no_events', - 'You currently have no scheduled cron events.' - ); - } - - foreach ( $crons as $time => $hooks ) { - foreach ( $hooks as $hook => $hook_events ) { - foreach ( $hook_events as $sig => $data ) { - - $events[] = (object) array( - 'hook' => $hook, - 'time' => $time, - 'sig' => $sig, - 'args' => $data['args'], - 'schedule' => $data['schedule'], - 'interval' => \WP_CLI\Utils\get_flag_value( $data, 'interval' ), - ); - - } - } - } - - $events = array_map( 'Cron_Event_Command::format_event', $events ); - - return $events; - - } - - /** - * Convert a time interval into human-readable format. - * - * Similar to WordPress' built-in `human_time_diff()` but returns two time period chunks instead of just one. - * - * @param int $since An interval of time in seconds - * @return string The interval in human readable format - */ - private static function interval( $since ) { - if ( $since <= 0 ) { - return 'now'; - } - - $since = absint( $since ); - - // array of time period chunks - $chunks = array( - array( 60 * 60 * 24 * 365 , \_n_noop( '%s year', '%s years' ) ), - array( 60 * 60 * 24 * 30 , \_n_noop( '%s month', '%s months' ) ), - array( 60 * 60 * 24 * 7, \_n_noop( '%s week', '%s weeks' ) ), - array( 60 * 60 * 24 , \_n_noop( '%s day', '%s days' ) ), - array( 60 * 60 , \_n_noop( '%s hour', '%s hours' ) ), - array( 60 , \_n_noop( '%s minute', '%s minutes' ) ), - array( 1 , \_n_noop( '%s second', '%s seconds' ) ), - ); - - // we only want to output two chunks of time here, eg: - // x years, xx months - // x days, xx hours - // so there's only two bits of calculation below: - - // step one: the first chunk - for ( $i = 0, $j = count( $chunks ); $i < $j; $i++ ) { - $seconds = $chunks[$i][0]; - $name = $chunks[$i][1]; - - // finding the biggest chunk (if the chunk fits, break) - if ( ( $count = floor( $since / $seconds ) ) != 0 ){ - break; - } - } - - // set output var - $output = sprintf( \_n( $name[0], $name[1], $count ), $count ); - - // step two: the second chunk - if ( $i + 1 < $j ) { - $seconds2 = $chunks[$i + 1][0]; - $name2 = $chunks[$i + 1][1]; - - if ( ( $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 ) ) != 0 ) { - // add to output var - $output .= ' ' . sprintf( \_n( $name2[0], $name2[1], $count2 ), $count2 ); - } - } - - return $output; - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'event' ); - } - -} - -WP_CLI::add_command( 'cron event', 'Cron_Event_Command' ); diff --git a/php/commands/cron-schedule.php b/php/commands/cron-schedule.php deleted file mode 100644 index 7c9661c0f..000000000 --- a/php/commands/cron-schedule.php +++ /dev/null @@ -1,130 +0,0 @@ -] - * : Limit the output to specific object fields. - * - * [--field=] - * : Prints the value of a single field for each schedule. - * - * [--format=] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each cron schedule: - * - * * name - * * display - * * interval - * - * There are no additional fields. - * - * ## EXAMPLES - * - * # List available cron schedules - * $ wp cron schedule list - * +------------+-------------+----------+ - * | name | display | interval | - * +------------+-------------+----------+ - * | hourly | Once Hourly | 3600 | - * | twicedaily | Twice Daily | 43200 | - * | daily | Once Daily | 86400 | - * +------------+-------------+----------+ - * - * # List id of available cron schedule - * $ wp cron schedule list --fields=name --format=ids - * hourly twicedaily daily - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $schedules = self::get_schedules(); - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', wp_list_pluck( $schedules, 'name' ) ); - } else { - $formatter->display_items( $schedules ); - } - - } - - /** - * Callback function to format a cron schedule. - * - * @param array $schedule The schedule. - * @param string $name The schedule name. - * @return array The formatted schedule. - */ - protected static function format_schedule( array $schedule, $name ) { - $schedule['name'] = $name; - return $schedule; - } - - /** - * Return a list of the cron schedules sorted according to interval. - * - * @return array The array of cron schedules. Each schedule is itself an array. - */ - protected static function get_schedules() { - $schedules = wp_get_schedules(); - if ( !empty( $schedules ) ) { - uasort( $schedules, 'Cron_Schedule_Command::sort' ); - $schedules = array_map( 'Cron_Schedule_Command::format_schedule', $schedules, array_keys( $schedules ) ); - } - return $schedules; - } - - /** - * Callback function to sort the cron schedule array by interval. - * - */ - protected static function sort( array $a, array $b ) { - return $a['interval'] - $b['interval']; - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'schedule' ); - } - -} - -WP_CLI::add_command( 'cron schedule', 'Cron_Schedule_Command' ); diff --git a/php/commands/cron.php b/php/commands/cron.php deleted file mode 100644 index 03941849e..000000000 --- a/php/commands/cron.php +++ /dev/null @@ -1,93 +0,0 @@ -get_error_message() ) ); - } - - $code = wp_remote_retrieve_response_code( $spawn ); - $message = wp_remote_retrieve_response_message( $spawn ); - - if ( 200 === $code ) { - WP_CLI::success( 'WP-Cron spawning is working as expected.' ); - } else { - WP_CLI::warning( sprintf( 'WP-Cron spawn succeeded but returned HTTP status code: %1$s %2$s', $code, $message ) ); - } - - } - - /** - * Spawn a request to `wp-cron.php` and return the response. - * - * This function is designed to mimic the functionality in `spawn_cron()` - * with the addition of returning the result of the `wp_remote_post()` - * request. - * - * @return WP_Error|array The response or WP_Error on failure. - */ - protected static function get_cron_spawn() { - - $sslverify = \WP_CLI\Utils\wp_version_compare( 4.0, '<' ); - $doing_wp_cron = sprintf( '%.22F', microtime( true ) ); - - $cron_request = apply_filters( 'cron_request', array( - 'url' => site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron ), - 'key' => $doing_wp_cron, - 'args' => array( - 'timeout' => 3, - 'blocking' => true, - 'sslverify' => apply_filters( 'https_local_ssl_verify', $sslverify ) - ) - ) ); - - # Enforce a blocking request in case something that's hooked onto the 'cron_request' filter sets it to false - $cron_request['args']['blocking'] = true; - - $result = wp_remote_post( $cron_request['url'], $cron_request['args'] ); - - return $result; - - } - -} - -WP_CLI::add_command( 'cron', 'Cron_Command' ); From 7c38a429bde660f75cc7bc7e75c3e9d064c6abf3 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Fri, 24 Feb 2017 22:57:14 -0600 Subject: [PATCH 5314/5359] Don't exit in lang install if lang is already installed --- php/WP_CLI/CommandWithTranslation.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 98d56aadc..518ac90a1 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -138,19 +138,20 @@ public function install( $args, $assoc_args ) { $available = $this->get_installed_languages(); if ( in_array( $language_code, $available ) ) { - \WP_CLI::warning( "Language already installed." ); - exit; - } - - $response = $this->download_language_pack( $language_code ); - if ( ! is_wp_error( $response ) ) { - \WP_CLI::success( "Language installed." ); + \WP_CLI::warning( "Language '{$language_code}' already installed." ); + \WP_CLI::success( "Language already installed." ); + } else { + $response = $this->download_language_pack( $language_code ); - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - $this->activate( array( $language_code ), array() ); + if ( is_wp_error( $response ) ) { + \WP_CLI::error( $response ); + } else { + \WP_CLI::success( "Language installed." ); } - } else { - \WP_CLI::error( $response ); + } + + if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { + $this->activate( array( $language_code ), array() ); } } From 2854f3bc70d24ae0fd77c3450dfe03a5364596b0 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Fri, 24 Feb 2017 22:58:21 -0600 Subject: [PATCH 5315/5359] Warn on activation when lang is already active --- php/WP_CLI/CommandWithTranslation.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 518ac90a1..6d35a7278 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -276,6 +276,13 @@ public function activate( $args, $assoc_args ) { $language_code = ''; } + if ( $language_code === get_locale() ) { + \WP_CLI::warning( "Language '{$language_code}' is already active." ); + \WP_CLI::success( "Language already activated." ); + + return; + } + update_option( 'WPLANG', $language_code ); \WP_CLI::success( "Language activated." ); } From 58603863bff9b4bf2e7fbc0990086194b76fa485 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Fri, 24 Feb 2017 23:03:58 -0600 Subject: [PATCH 5316/5359] Add functional tests --- features/core-language.feature | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/features/core-language.feature b/features/core-language.feature index 5541494bd..b0fa61ebd 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -21,6 +21,7 @@ Feature: Manage translation files for a WordPress install """ Success: Language installed. """ + When I run `ls {SUITE_CACHE_DIR}/translation | grep core-default-` Then STDOUT should contain: """ @@ -31,10 +32,14 @@ Feature: Manage translation files for a WordPress install en_GB """ - When I try `wp core language install en_GB` - Then STDERR should be: + When I try `wp core language install en_AU` + Then STDERR should contain: """ - Warning: Language already installed. + Warning: Language 'en_AU' already installed. + """ + And STDOUT should contain: + """ + Success: Language already installed. """ When I run `wp core language list --fields=language,english_name,status` @@ -83,6 +88,16 @@ Feature: Manage translation files for a WordPress install | az | Azerbaijani | uninstalled | | en_GB | English (UK) | active | + When I run `wp core language install en_AU --activate` + Then STDERR should contain: + """ + Warning: Language 'en_AU' already installed. + """ + And STDOUT should contain: + """ + Success: Language activated. + """ + When I run `wp core language activate en_US` Then STDOUT should be: """ @@ -96,7 +111,6 @@ Feature: Manage translation files for a WordPress install | en_US | English (United States) | active | | en_GB | English (UK) | installed | - When I try `wp core language activate invalid_lang` Then STDERR should be: """ @@ -117,7 +131,7 @@ Feature: Manage translation files for a WordPress install Error: Language not installed. """ - When I run `wp core language install --activate en_GB` + When I run `wp core language install en_GB --activate` Then the wp-content/languages/admin-en_GB.po file should exist And the wp-content/languages/en_GB.po file should exist And STDOUT should contain: From f9c9b44be8340e370fb17dff28c1f64f8964ef49 Mon Sep 17 00:00:00 2001 From: Frankie Jarrett Date: Fri, 24 Feb 2017 23:47:41 -0600 Subject: [PATCH 5317/5359] Simplify messages --- features/core-language.feature | 16 +++++++++++----- php/WP_CLI/CommandWithTranslation.php | 4 +--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/features/core-language.feature b/features/core-language.feature index b0fa61ebd..d83121777 100644 --- a/features/core-language.feature +++ b/features/core-language.feature @@ -21,6 +21,7 @@ Feature: Manage translation files for a WordPress install """ Success: Language installed. """ + And STDERR should be empty When I run `ls {SUITE_CACHE_DIR}/translation | grep core-default-` Then STDOUT should contain: @@ -33,14 +34,10 @@ Feature: Manage translation files for a WordPress install """ When I try `wp core language install en_AU` - Then STDERR should contain: + Then STDERR should be: """ Warning: Language 'en_AU' already installed. """ - And STDOUT should contain: - """ - Success: Language already installed. - """ When I run `wp core language list --fields=language,english_name,status` Then STDOUT should be a table containing rows: @@ -98,6 +95,14 @@ Feature: Manage translation files for a WordPress install Success: Language activated. """ + When I run `wp core language install en_AU --activate` + Then STDERR should contain: + """ + Warning: Language 'en_AU' already installed. + Warning: Language 'en_AU' already active. + """ + And STDOUT should be empty + When I run `wp core language activate en_US` Then STDOUT should be: """ @@ -139,6 +144,7 @@ Feature: Manage translation files for a WordPress install Success: Language installed. Success: Language activated. """ + And STDERR should be empty When I try `wp core language install invalid_lang` Then STDERR should be: diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php index 6d35a7278..a6670ca6a 100644 --- a/php/WP_CLI/CommandWithTranslation.php +++ b/php/WP_CLI/CommandWithTranslation.php @@ -139,7 +139,6 @@ public function install( $args, $assoc_args ) { if ( in_array( $language_code, $available ) ) { \WP_CLI::warning( "Language '{$language_code}' already installed." ); - \WP_CLI::success( "Language already installed." ); } else { $response = $this->download_language_pack( $language_code ); @@ -277,8 +276,7 @@ public function activate( $args, $assoc_args ) { } if ( $language_code === get_locale() ) { - \WP_CLI::warning( "Language '{$language_code}' is already active." ); - \WP_CLI::success( "Language already activated." ); + \WP_CLI::warning( "Language '{$language_code}' already active." ); return; } From 9248e4ce04bbc279052586df142e36052046cdbf Mon Sep 17 00:00:00 2001 From: "Peter J. Herrel" Date: Sat, 25 Feb 2017 23:06:16 +0100 Subject: [PATCH 5318/5359] Improve `wp menu location assign` command --- features/menu-location.feature | 20 ++++++++++++++++++++ php/commands/menu-location.php | 12 ++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/features/menu-location.feature b/features/menu-location.feature index e94dceee0..eea7a699d 100644 --- a/features/menu-location.feature +++ b/features/menu-location.feature @@ -29,3 +29,23 @@ Feature: Manage WordPress menu locations Then STDOUT should be a table containing rows: | slug | locations | | primary-menu | | + + When I try `wp menu location assign secondary-menu secondary` + Then STDERR should be: + """ + Error: Invalid menu secondary-menu. + """ + + When I run `wp menu create "Secondary Menu"` + And I try `wp menu location assign secondary-menu secondary` + Then STDERR should be: + """ + Error: Invalid location secondary. + """ + + When I run `wp menu location assign secondary-menu primary` + And I run `wp menu list --fields=slug,locations` + Then STDOUT should be a table containing rows: + | slug | locations | + | primary-menu | | + | secondary-menu | primary | diff --git a/php/commands/menu-location.php b/php/commands/menu-location.php index 46e69f937..1caf4b85a 100644 --- a/php/commands/menu-location.php +++ b/php/commands/menu-location.php @@ -108,22 +108,22 @@ public function assign( $args, $_ ) { list( $menu, $location ) = $args; - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); + $menu_obj = wp_get_nav_menu_object( $menu ); + if ( ! $menu_obj ) { + WP_CLI::error( "Invalid menu $menu." ); } $locations = get_registered_nav_menus(); if ( ! array_key_exists( $location, $locations ) ) { - WP_CLI::error( "Invalid location." ); + WP_CLI::error( "Invalid location $location." ); } $locations = get_nav_menu_locations(); - $locations[ $location ] = $menu->term_id; + $locations[ $location ] = $menu_obj->term_id; set_theme_mod( 'nav_menu_locations', $locations ); - WP_CLI::success( "Assigned location to menu." ); + WP_CLI::success( "Assigned location $location to menu $menu." ); } /** From 6b94db113b19d10eb8f0455329f105bbdf0299ff Mon Sep 17 00:00:00 2001 From: "Peter J. Herrel" Date: Sun, 26 Feb 2017 00:26:06 +0100 Subject: [PATCH 5319/5359] update example, tweak test --- features/menu-location.feature | 7 ++++++- php/commands/menu-location.php | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/features/menu-location.feature b/features/menu-location.feature index eea7a699d..766fa6443 100644 --- a/features/menu-location.feature +++ b/features/menu-location.feature @@ -44,7 +44,12 @@ Feature: Manage WordPress menu locations """ When I run `wp menu location assign secondary-menu primary` - And I run `wp menu list --fields=slug,locations` + Then STDOUT should be: + """ + Success: Assigned location primary to menu secondary-menu. + """ + + When I run `wp menu list --fields=slug,locations` Then STDOUT should be a table containing rows: | slug | locations | | primary-menu | | diff --git a/php/commands/menu-location.php b/php/commands/menu-location.php index 1caf4b85a..63fd3a9e9 100644 --- a/php/commands/menu-location.php +++ b/php/commands/menu-location.php @@ -100,7 +100,7 @@ function($o) { * ## EXAMPLES * * $ wp menu location assign primary-menu primary - * Success: Assigned location to menu. + * Success: Assigned location primary to menu primary-menu. * * @subcommand assign */ From f475f10e70996198f1997f0f520763b45b0548fb Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 27 Feb 2017 07:59:08 -0800 Subject: [PATCH 5320/5359] Update Composer dependencies (2/27/2017) ``` Loading composer repositories with package information Updating dependencies (including require-dev) - Removing mustangostang/spyc (0.6.1) - Installing mustangostang/spyc (0.6.2) Downloading: 100% - Removing phpunit/php-timer (1.0.8) - Installing phpunit/php-timer (1.0.9) Downloading: 100% Writing lock file Generating autoload files ``` --- composer.lock | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 912039e0d..8a02e4a33 100644 --- a/composer.lock +++ b/composer.lock @@ -379,16 +379,16 @@ }, { "name": "mustangostang/spyc", - "version": "0.6.1", + "version": "0.6.2", "source": { "type": "git", "url": "https://github.com/mustangostang/spyc.git", - "reference": "022532641d61d383fd3ae666982bd46e61e5915e" + "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mustangostang/spyc/zipball/022532641d61d383fd3ae666982bd46e61e5915e", - "reference": "022532641d61d383fd3ae666982bd46e61e5915e", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", + "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", "shasum": "" }, "require": { @@ -425,7 +425,7 @@ "yaml", "yml" ], - "time": "2016-10-21 00:03:34" + "time": "2017-02-24 16:06:33" }, { "name": "nb/oxymel", @@ -1740,25 +1740,30 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.8", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4|~5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -1780,7 +1785,7 @@ "keywords": [ "timer" ], - "time": "2016-05-12 18:03:57" + "time": "2017-02-26 11:10:40" }, { "name": "phpunit/php-token-stream", From 91fb81017cb27d91e01ffee057b785e82f03bfee Mon Sep 17 00:00:00 2001 From: Matthieu Bovel Date: Tue, 28 Feb 2017 00:21:58 +0100 Subject: [PATCH 5321/5359] Add missing line break Before: ``` require: - file1.php - file2.php ``` After: ``` require: - file1.php - file2.php ``` --- features/bootstrap/FeatureContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 5a582d046..cc72cc02c 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -19,7 +19,7 @@ if ( ! empty( $composer->autoload->files ) ) { $contents = 'require:' . PHP_EOL; foreach( $composer->autoload->files as $file ) { - $contents .= ' - ' . dirname( dirname( dirname( __FILE__ ) ) ) . '/' . $file; + $contents .= ' - ' . dirname( dirname( dirname( __FILE__ ) ) ) . '/' . $file . PHP_EOL; } @mkdir( sys_get_temp_dir() . '/wp-cli-package-test/' ); $project_config = sys_get_temp_dir() . '/wp-cli-package-test/config.yml'; From b34eeda6ecf8f2a97164c5212937cdfe1d6e77dc Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 28 Feb 2017 05:32:38 -0800 Subject: [PATCH 5322/5359] Abstract `wp import` to a separate wp-cli/import-command package --- composer.json | 3 +- composer.lock | 50 ++++- features/command.feature | 6 + features/import.feature | 250 ----------------------- php/commands/import.php | 420 --------------------------------------- 5 files changed, 56 insertions(+), 673 deletions(-) delete mode 100644 features/import.feature delete mode 100644 php/commands/import.php diff --git a/composer.json b/composer.json index 50e29f875..90b07169c 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "symfony/translation": "~2.7", "nb/oxymel": "~0.1.0", "composer/composer": "^1.2.0", - "wp-cli/cron-command": "^1.0" + "wp-cli/cron-command": "^1.0", + "wp-cli/import-command": "^1.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 8a02e4a33..2550684fa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "5601d44dfe467b49cb16ae27dec839e0", - "content-hash": "bd05401239e13c802ff2849c88af96b1", + "hash": "5c7a0459426738b69a74843e91fde8d8", + "content-hash": "cd620dac551c58f96174173297545d0d", "packages": [ { "name": "composer/ca-bundle", @@ -1414,6 +1414,52 @@ "homepage": "https://github.com/wp-cli/cron-command", "time": "2017-02-24 15:19:37" }, + { + "name": "wp-cli/import-command", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/wp-cli/import-command.git", + "reference": "2be58f14961284ae701a2519b62da211ffedf83d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-cli/import-command/zipball/2be58f14961284ae701a2519b62da211ffedf83d", + "reference": "2be58f14961284ae701a2519b62da211ffedf83d", + "shasum": "" + }, + "require-dev": { + "behat/behat": "~2.5" + }, + "type": "wp-cli-package", + "extra": { + "commands": [ + "import" + ] + }, + "autoload": { + "psr-4": { + "": "src/" + }, + "files": [ + "import-command.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Bachhuber", + "email": "daniel@runcommand.io", + "homepage": "https://runcommand.io" + } + ], + "description": "Import content from a WXR file.", + "homepage": "https://github.com/wp-cli/import-command", + "time": "2017-02-28 13:24:43" + }, { "name": "wp-cli/php-cli-tools", "version": "v0.11.2", diff --git a/features/command.feature b/features/command.feature index 72ac1b59d..13166db4b 100644 --- a/features/command.feature +++ b/features/command.feature @@ -11,6 +11,12 @@ Feature: WP-CLI Commands or: wp cron test """ + When I run `wp import --help` + Then STDOUT should contain: + """ + wp import ... --authors= + """ + Scenario: Invalid class is specified for a command Given an empty directory And a custom-cmd.php file: diff --git a/features/import.feature b/features/import.feature deleted file mode 100644 index 7398920df..000000000 --- a/features/import.feature +++ /dev/null @@ -1,250 +0,0 @@ -Feature: Import content. - - Scenario: Basic export then import - Given a WP install - And I run `wp post generate --post_type=post --count=3` - And I run `wp post generate --post_type=page --count=2` - When I run `wp post list --post_type=any --format=count` - Then STDOUT should be: - """ - 7 - """ - - When I run `wp export` - And save STDOUT 'Writing to file %s' as {EXPORT_FILE} - - When I run `wp site empty --yes` - Then STDOUT should not be empty - - When I run `wp post list --post_type=any --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: - """ - Warning: - """ - - When I run `wp import {EXPORT_FILE} --authors=skip` - Then STDOUT should not be empty - - When I run `wp post list --post_type=any --format=count` - Then STDOUT should be: - """ - 7 - """ - - When I run `wp import {EXPORT_FILE} --authors=skip --skip=image_resize` - Then STDOUT should not be empty - - Scenario: Export and import a directory of files - Given a WP install - And I run `mkdir export-posts` - And I run `mkdir export-pages` - - When I run `wp post generate --count=49` - When I run `wp post generate --post_type=page --count=49` - And I run `wp post list --post_type=post,page --format=count` - Then STDOUT should be: - """ - 100 - """ - - When I run `wp export --dir=export-posts --post_type=post` - When I run `wp export --dir=export-pages --post_type=page` - Then STDOUT should not be empty - - When I run `wp site empty --yes` - Then STDOUT should not be empty - - When I run `wp post list --post_type=post,page --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `find export-* -type f | wc -l` - Then STDOUT should contain: - """ - 2 - """ - - When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: - """ - Warning: - """ - - When I run `wp import export-posts --authors=skip --skip=image_resize` - And I run `wp import export-pages --authors=skip --skip=image_resize` - Then STDOUT should not be empty - - When I run `wp post list --post_type=post,page --format=count` - Then STDOUT should be: - """ - 100 - """ - - @less-than-php-7 @require-wp-4.0 - Scenario: Export and import page and referencing menu item - # This will not work with WP 3.7.11 or PHP 7. - # PHP 7 issue: https://wordpress.org/support/topic/importer-fails-to-import-menu-items-in-php7 - Given a WP install - And I run `mkdir export` - - # NOTE: The Hello World page ID is 2. - When I run `wp menu create "My Menu"` - And I run `wp menu item add-post my-menu 2` - And I run `wp menu item list my-menu --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp export --dir=export` - Then STDOUT should not be empty - - When I run `wp site empty --yes` - Then STDOUT should not be empty - - When I run `wp post list --post_type=page --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp post list --post_type=nav_menu_item --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `find export -type f | wc -l` - Then STDOUT should contain: - """ - 1 - """ - - When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: - """ - Warning: - """ - - When I run `wp import export --authors=skip --skip=image_resize` - Then STDOUT should not be empty - - When I run `wp post list --post_type=page --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp post list --post_type=nav_menu_item --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp menu item list my-menu --fields=object --format=csv` - Then STDOUT should contain: - """ - page - """ - - When I run `wp menu item list my-menu --fields=object_id --format=csv` - Then STDOUT should contain: - """ - 2 - """ - - @less-than-php-7 @require-wp-4.0 - Scenario: Export and import page and referencing menu item in separate files - Given a WP install - And I run `mkdir export` - - # NOTE: The Hello World page ID is 2. - When I run `wp menu create "My Menu"` - And I run `wp menu item add-post my-menu 2` - And I run `wp menu item list my-menu --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp export --dir=export --post_type=page --filename_format=0.page.xml` - And I run `wp export --dir=export --post_type=nav_menu_item --filename_format=1.menu.xml` - Then STDOUT should not be empty - - When I run `wp site empty --yes` - Then STDOUT should not be empty - - When I run `wp post list --post_type=page --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp post list --post_type=nav_menu_item --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `find export -type f | wc -l` - Then STDOUT should contain: - """ - 2 - """ - - When I run `wp plugin install wordpress-importer --activate` - Then STDERR should not contain: - """ - Warning: - """ - - When I run `wp import export --authors=skip --skip=image_resize` - Then STDOUT should not be empty - - When I run `wp post list --post_type=page --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp post list --post_type=nav_menu_item --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp menu item list my-menu --fields=object --format=csv` - Then STDOUT should contain: - """ - page - """ - - When I run `wp menu item list my-menu --fields=object_id --format=csv` - Then STDOUT should contain: - """ - 2 - """ - - Scenario: Indicate current file when importing - Given a WP install - And I run `wp plugin install --activate wordpress-importer` - - When I run `wp export --filename_format=wordpress.{n}.xml` - Then save STDOUT 'Writing to file %s' as {EXPORT_FILE} - - When I run `wp site empty --yes` - Then STDOUT should not be empty - - When I run `wp import {EXPORT_FILE} --authors=skip` - Then STDOUT should contain: - """ - -- 1 of 2 (in file wordpress.000.xml) - """ diff --git a/php/commands/import.php b/php/commands/import.php deleted file mode 100644 index e621b58ed..000000000 --- a/php/commands/import.php +++ /dev/null @@ -1,420 +0,0 @@ -... - * : Path to one or more valid WXR files for importing. Directories are also accepted. - * - * --authors= - * : How the author mapping should be handled. Options are 'create', 'mapping.csv', or 'skip'. The first will create any non-existent users from the WXR file. The second will read author mapping associations from a CSV, or create a CSV for editing if the file path doesn't exist. The CSV requires two columns, and a header row like "old_user_login,new_user_login". The last option will skip any author mapping. - * - * [--skip=] - * : Skip importing specific data. Supported options are: 'attachment' and 'image_resize' (skip time-consuming thumbnail generation). - * - * ## EXAMPLES - * - * # Import content from a WXR file - * $ wp import example.wordpress.2016-06-21.xml --authors=create - * Starting the import process... - * Processing post #1 ("Hello world!") (post_type: post) - * -- 1 of 1 - * -- Tue, 21 Jun 2016 05:31:12 +0000 - * -- Imported post as post_id #1 - * Success: Finished importing from 'example.wordpress.2016-06-21.xml' file. - */ - public function __invoke( $args, $assoc_args ) { - $defaults = array( - 'authors' => null, - 'skip' => array(), - ); - $assoc_args = wp_parse_args( $assoc_args, $defaults ); - - if ( ! is_array( $assoc_args['skip'] ) ) { - $assoc_args['skip'] = explode( ',', $assoc_args['skip'] ); - } - - $importer = $this->is_importer_available(); - if ( is_wp_error( $importer ) ) { - WP_CLI::error( $importer ); - } - - $this->add_wxr_filters(); - - WP_CLI::log( 'Starting the import process...' ); - - $new_args = array(); - foreach( $args as $arg ) { - if ( is_dir( $arg ) ) { - $files = glob( rtrim( $arg, '/' ) . '/*.{wxr,xml}', GLOB_BRACE ); - $new_args = array_merge( $new_args, $files ); - } else { - $new_args[] = $arg; - } - } - $args = $new_args; - - foreach ( $args as $file ) { - if ( ! is_readable( $file ) ) { - WP_CLI::warning( "Can't read '$file' file." ); - } - - $ret = $this->import_wxr( $file, $assoc_args ); - - if ( is_wp_error( $ret ) ) { - WP_CLI::error( $ret ); - } else { - WP_CLI::log(''); // WXR import ends with HTML, so make sure message is on next line - WP_CLI::success( "Finished importing from '$file' file." ); - } - } - } - - /** - * Import a WXR file - */ - private function import_wxr( $file, $args ) { - - $wp_import = new WP_Import; - $wp_import->processed_posts = $this->processed_posts; - $import_data = $wp_import->parse( $file ); - if ( is_wp_error( $import_data ) ) - return $import_data; - - // Prepare the data to be used in process_author_mapping(); - $wp_import->get_authors_from_import( $import_data ); - - // We no longer need the original data, so unset to avoid using excess - // memory. - unset( $import_data ); - - $author_data = array(); - foreach ( $wp_import->authors as $wxr_author ) { - $author = new \stdClass; - // Always in the WXR - $author->user_login = $wxr_author['author_login']; - - // Should be in the WXR; no guarantees - if ( isset ( $wxr_author['author_email'] ) ) { - $author->user_email = $wxr_author['author_email']; - } - if ( isset( $wxr_author['author_display_name'] ) ) - $author->display_name = $wxr_author['author_display_name']; - if ( isset( $wxr_author['author_first_name'] ) ) - $author->first_name = $wxr_author['author_first_name']; - if ( isset( $wxr_author['author_last_name'] ) ) - $author->last_name = $wxr_author['author_last_name']; - - $author_data[] = $author; - } - - // Build the author mapping - $author_mapping = $this->process_author_mapping( $args['authors'], $author_data ); - if ( is_wp_error( $author_mapping ) ) - return $author_mapping; - - $author_in = wp_list_pluck( $author_mapping, 'old_user_login' ); - $author_out = wp_list_pluck( $author_mapping, 'new_user_login' ); - unset( $author_mapping, $author_data ); - - // $user_select needs to be an array of user IDs - $user_select = array(); - $invalid_user_select = array(); - foreach ( $author_out as $author_login ) { - $user = get_user_by( 'login', $author_login ); - if ( $user ) - $user_select[] = $user->ID; - else - $invalid_user_select[] = $author_login; - } - if ( ! empty( $invalid_user_select ) ) - return new WP_Error( 'invalid-author-mapping', sprintf( "These user_logins are invalid: %s", implode( ',', $invalid_user_select ) ) ); - - unset( $author_out ); - - // Drive the import - $wp_import->fetch_attachments = !in_array( 'attachment', $args['skip'] ); - $_GET = array( 'import' => 'wordpress', 'step' => 2 ); - $_POST = array( - 'imported_authors' => $author_in, - 'user_map' => $user_select, - 'fetch_attachments' => $wp_import->fetch_attachments, - ); - - if ( in_array( 'image_resize', $args['skip'] ) ) { - add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_set_image_sizes' ) ); - } - - $GLOBALS['wp_cli_import_current_file'] = basename( $file ); - $wp_import->import( $file ); - $this->processed_posts += $wp_import->processed_posts; - - return true; - } - - public function filter_set_image_sizes( $sizes ) { - // Return null here to prevent the core image resizing logic from running. - return null; - } - - /** - * Useful verbosity filters for the WXR importer - */ - private function add_wxr_filters() { - - add_filter( 'wp_import_posts', function( $posts ) { - global $wpcli_import_counts; - $wpcli_import_counts['current_post'] = 0; - $wpcli_import_counts['total_posts'] = count( $posts ); - return $posts; - }, 10 ); - - add_filter( 'wp_import_post_comments', function( $comments, $post_id, $post ) { - global $wpcli_import_counts; - $wpcli_import_counts['current_comment'] = 0; - $wpcli_import_counts['total_comments'] = count( $comments ); - return $comments; - }, 10, 3 ); - - add_filter( 'wp_import_post_data_raw', function( $post ) { - global $wpcli_import_counts, $wp_cli_import_current_file; - - $wpcli_import_counts['current_post']++; - WP_CLI::log(''); - WP_CLI::log(''); - WP_CLI::log( sprintf( 'Processing post #%d ("%s") (post_type: %s)', $post['post_id'], $post['post_title'], $post['post_type'] ) ); - WP_CLI::log( sprintf( '-- %s of %s (in file %s)', number_format( $wpcli_import_counts['current_post'] ), number_format( $wpcli_import_counts['total_posts'] ), $wp_cli_import_current_file ) ); - WP_CLI::log( '-- ' . date( 'r' ) ); - - return $post; - } ); - - add_action( 'wp_import_insert_post', function( $post_id, $original_post_ID, $post, $postdata ) { - global $wpcli_import_counts; - if ( is_wp_error( $post_id ) ) { - WP_CLI::warning( "-- Error importing post: " . $post_id->get_error_code() ); - } else { - WP_CLI::log( "-- Imported post as post_id #{$post_id}" ); - } - - if ( $wpcli_import_counts['current_post'] % 500 === 0 ) { - WP_CLI\Utils\wp_clear_object_cache(); - WP_CLI::log( "-- Cleared object cache." ); - } - - }, 10, 4 ); - - add_action( 'wp_import_insert_term', function( $t, $import_term, $post_id, $post ) { - WP_CLI::log( "-- Created term \"{$import_term['name']}\"" ); - }, 10, 4 ); - - add_action( 'wp_import_set_post_terms', function( $tt_ids, $term_ids, $taxonomy, $post_id, $post ) { - WP_CLI::log( "-- Added terms (" . implode( ',', $term_ids ) .") for taxonomy \"{$taxonomy}\"" ); - }, 10, 5 ); - - add_action( 'wp_import_insert_comment', function( $comment_id, $comment, $comment_post_ID, $post ) { - global $wpcli_import_counts; - $wpcli_import_counts['current_comment']++; - WP_CLI::log( sprintf( '-- Added comment #%d (%s of %s)', $comment_id, number_format( $wpcli_import_counts['current_comment'] ), number_format( $wpcli_import_counts['total_comments'] ) ) ); - }, 10, 4 ); - - add_action( 'import_post_meta', function( $post_id, $key, $value ) { - WP_CLI::log( "-- Added post_meta $key" ); - }, 10, 3 ); - - } - - /** - * Is the requested importer available? - */ - private function is_importer_available() { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - - if ( class_exists( 'WP_Import' ) ) { - return true; - } - - $plugins = get_plugins(); - $wordpress_importer = 'wordpress-importer/wordpress-importer.php'; - if ( array_key_exists( $wordpress_importer, $plugins ) ) - $error_msg = "WordPress Importer needs to be activated. Try 'wp plugin activate wordpress-importer'."; - else - $error_msg = "WordPress Importer needs to be installed. Try 'wp plugin install wordpress-importer --activate'."; - - return new WP_Error( 'importer-missing', $error_msg ); - } - - /** - * Process how the authors should be mapped - * - * @param string $authors_arg The `--author` argument originally passed to command - * @param array $author_data An array of WP_User-esque author objects - * @return array|WP_Error $author_mapping Author mapping array if successful, WP_Error if something bad happened - */ - private function process_author_mapping( $authors_arg, $author_data ) { - - // Provided an author mapping file (method checks validity) - if ( file_exists( $authors_arg ) ) - return $this->read_author_mapping_file( $authors_arg ); - - // Provided a file reference, but the file doesn't yet exist - if ( false !== stripos( $authors_arg, '.csv' ) ) - return $this->create_author_mapping_file( $authors_arg, $author_data ); - - switch( $authors_arg ) { - // Create authors if they don't yet exist; maybe match on email or user_login - case 'create': - return $this->create_authors_for_mapping( $author_data ); - break; - // Skip any sort of author mapping - case 'skip': - return array(); - break; - default: - return new WP_Error( 'invalid-argument', "'authors' argument is invalid." ); - } - } - - /** - * Read an author mapping file - */ - private function read_author_mapping_file( $file ) { - $author_mapping = array(); - - foreach ( new \WP_CLI\Iterators\CSV( $file ) as $i => $author ) { - if ( ! array_key_exists( 'old_user_login', $author ) || ! array_key_exists( 'new_user_login', $author ) ) - return new WP_Error( 'invalid-author-mapping', "Author mapping file isn't properly formatted." ); - - $author_mapping[] = $author; - } - - return $author_mapping; - } - - /** - * Create an author mapping file, based on provided author data - * - * @return WP_Error The file was just now created, so some action needs to be taken - */ - private function create_author_mapping_file( $file, $author_data ) { - - if ( touch( $file ) ) { - $author_mapping = array(); - foreach ( $author_data as $author ) { - $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $this->suggest_user( $author->user_login, $author->user_email ), - ); - } - $file_resource = fopen( $file, 'w' ); - \WP_CLI\utils\write_csv( $file_resource, $author_mapping, array( 'old_user_login', 'new_user_login' ) ); - return new WP_Error( 'author-mapping-error', sprintf( "Please update author mapping file before continuing: %s", $file ) ); - } else { - return new WP_Error( 'author-mapping-error', "Couldn't create author mapping file." ); - } - } - - /** - * Create users if they don't exist, and build an author mapping file - */ - private function create_authors_for_mapping( $author_data ) { - - $author_mapping = array(); - foreach ( $author_data as $author ) { - - if ( isset( $author->user_email ) ) { - if ( $user = get_user_by( 'email', $author->user_email ) ) { - $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $user->user_login, - ); - continue; - } - } - - if ( $user = get_user_by( 'login', $author->user_login ) ) { - $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $user->user_login, - ); - continue; - } - - $user = array( - 'user_login' => '', - 'user_email' => '', - 'user_pass' => wp_generate_password(), - ); - $user = array_merge( $user, (array)$author ); - $user_id = wp_insert_user( $user ); - if ( is_wp_error( $user_id ) ) - return $user_id; - - $user = get_user_by( 'id', $user_id ); - $author_mapping[] = array( - 'old_user_login' => $author->user_login, - 'new_user_login' => $user->user_login, - ); - } - return $author_mapping; - - } - - /** - * Suggest a blog user based on the levenshtein distance - */ - private function suggest_user( $author_user_login, $author_user_email = '' ) { - - if ( ! isset( $this->blog_users ) ) - $this->blog_users = get_users(); - - $shortest = -1; - $shortestavg = array(); - - $threshold = floor( ( strlen( $author_user_login ) / 100 ) * 10 ); // 10 % of the strlen are valid - $closest = ''; - foreach ( $this->blog_users as $user ) { - // Before we resort to an algorithm, let's try for an exact match - if ( $author_user_email && $user->user_email == $author_user_email ) - return $user->user_login; - - $levs = array(); - $levs[] = levenshtein( $author_user_login, $user->display_name ); - $levs[] = levenshtein( $author_user_login, $user->user_login ); - $levs[] = levenshtein( $author_user_login, $user->user_email ); - $email_parts = explode( "@", $user->user_email ); - $email_login = array_shift( $email_parts ); - $levs[] = levenshtein( $author_user_login, $email_login ); - rsort( $levs ); - $lev = array_pop( $levs ); - if ( 0 == $lev ) { - $closest = $user->user_login; - $shortest = 0; - break; - } - - if ( ( $lev <= $shortest || $shortest < 0 ) && $lev <= $threshold ) { - $closest = $user->user_login; - $shortest = $lev; - } - $shortestavg[] = $lev; - } - // in case all usernames have a common pattern - if ( $shortest > ( array_sum( $shortestavg ) / count( $shortestavg ) ) ) - return ''; - return $closest; - } - -} - -WP_CLI::add_command( 'import', 'Import_Command' ); - From 016cc57d7ac4cad4e4b561a34115d945bae97c09 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 28 Feb 2017 07:32:29 -0800 Subject: [PATCH 5323/5359] Introduce `WP_CLI\Utils\basename()` for locale-independent basename() --- php/WP_CLI/CommandWithUpgrade.php | 3 ++- php/WP_CLI/Extractor.php | 4 ++-- php/WP_CLI/Runner.php | 6 +++--- php/commands/media.php | 6 +++--- php/commands/plugin.php | 2 +- php/commands/scaffold.php | 2 +- php/utils.php | 13 +++++++++++++ 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php index 5c472acad..b82baadff 100755 --- a/php/WP_CLI/CommandWithUpgrade.php +++ b/php/WP_CLI/CommandWithUpgrade.php @@ -3,6 +3,7 @@ namespace WP_CLI; use WP_CLI; +use WP_CLI\Utils; abstract class CommandWithUpgrade extends \WP_CLI_Command { @@ -152,7 +153,7 @@ function install( $args, $assoc_args ) { if ( $branch_length ) { $new_path = substr( rtrim( $source, '/' ), 0, - ( $branch_length + 1 ) ) . '/'; if ( $GLOBALS['wp_filesystem']->move( $source, $new_path ) ) { - WP_CLI::log( "Renamed Github-based project from '" . basename( $source ) . "' to '" . basename( $new_path ) . "'." ); + WP_CLI::log( "Renamed Github-based project from '" . Utils\basename( $source ) . "' to '" . Utils\basename( $new_path ) . "'." ); return $new_path; } else { return new \WP_Error( 'wpcli_install_gitub', "Couldn't move Github-based project to appropriate directory." ); diff --git a/php/WP_CLI/Extractor.php b/php/WP_CLI/Extractor.php index defdc5127..5d99c78ac 100644 --- a/php/WP_CLI/Extractor.php +++ b/php/WP_CLI/Extractor.php @@ -46,7 +46,7 @@ private static function extract_zip( $zipfile, $dest ) { if ( true === $res ) { $tempdir = implode( DIRECTORY_SEPARATOR, Array ( dirname( $zipfile ), - basename( $zipfile, '.zip' ), + Utils\basename( $zipfile, '.zip' ), $zip->getNameIndex( 0 ) ) ); @@ -75,7 +75,7 @@ private static function extract_tarball( $tarball, $dest ) { $phar = new PharData( $tarball ); $tempdir = implode( DIRECTORY_SEPARATOR, Array ( dirname( $tarball ), - basename( $tarball, '.tar.gz' ), + Utils\basename( $tarball, '.tar.gz' ), $phar->getFileName() ) ); diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 584dd46dd..4b76a4820 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -833,10 +833,10 @@ public function start() { if ( in_array( $path, $this->_required_files[ $scope ] ) ) { switch ( $scope ) { case 'global': - $context = ' (from global ' . basename( $this->global_config_path ) . ')'; + $context = ' (from global ' . Utils\basename( $this->global_config_path ) . ')'; break; case 'project': - $context = ' (from project\'s ' . basename( $this->project_config_path ) . ')'; + $context = ' (from project\'s ' . Utils\basename( $this->project_config_path ) . ')'; break; case 'runtime': $context = ' (from runtime argument)'; @@ -845,7 +845,7 @@ public function start() { break; } } - WP_CLI::error( sprintf( "Required file '%s' doesn't exist%s.", basename( $path ), $context ) ); + WP_CLI::error( sprintf( "Required file '%s' doesn't exist%s.", Utils\basename( $path ), $context ) ); } Utils\load_file( $path ); WP_CLI::debug( 'Required file from config: ' . $path, 'bootstrap' ); diff --git a/php/commands/media.php b/php/commands/media.php index 61ba18408..989049312 100644 --- a/php/commands/media.php +++ b/php/commands/media.php @@ -216,7 +216,7 @@ function import( $args, $assoc_args = array() ) { $file_array = array( 'tmp_name' => $tempfile, - 'name' => basename( $file ) + 'name' => Utils\basename( $file ) ); $post_array= array( @@ -243,7 +243,7 @@ function import( $args, $assoc_args = array() ) { } if ( empty( $post_array['post_title'] ) ) { - $post_array['post_title'] = preg_replace( '/\.[^.]+$/', '', basename( $file ) ); + $post_array['post_title'] = preg_replace( '/\.[^.]+$/', '', Utils\basename( $file ) ); } // Deletes the temporary file. @@ -294,7 +294,7 @@ function import( $args, $assoc_args = array() ) { // wp_tempnam() inexplicably forces a .tmp extension, which spoils MIME type detection private function make_copy( $path ) { $dir = get_temp_dir(); - $filename = basename( $path ); + $filename = Utils\basename( $path ); if ( empty( $filename ) ) $filename = time(); diff --git a/php/commands/plugin.php b/php/commands/plugin.php index f1dd9b744..def295062 100644 --- a/php/commands/plugin.php +++ b/php/commands/plugin.php @@ -961,7 +961,7 @@ protected function get_status( $file ) { */ private function get_details( $file ) { $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); - $plugin_file = basename( $file ); + $plugin_file = Utils\basename( $file ); return $plugin_folder[$plugin_file]; } diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php index 321a9b259..f76fc8f4e 100644 --- a/php/commands/scaffold.php +++ b/php/commands/scaffold.php @@ -705,7 +705,7 @@ private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { WP_CLI::error( "Invalid {$type} directory specified." ); } if ( empty( $slug ) ) { - $slug = basename( $target_dir ); + $slug = Utils\basename( $target_dir ); } } diff --git a/php/utils.php b/php/utils.php index 537e71a8e..d476dc1e8 100644 --- a/php/utils.php +++ b/php/utils.php @@ -823,3 +823,16 @@ function parse_str_to_argv( $arguments ) { }, $argv ); return $argv; } + +/** + * Locale-independent version of basename() + * + * @access public + * + * @param string $path + * @param string $suffix + * @return string + */ +function basename( $path, $suffix = '' ) { + return urldecode( \basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) ); +} From 73d1e0003165d9516be95073216c8e0901a7b07c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Mar 2017 05:58:56 -0800 Subject: [PATCH 5324/5359] Abstract `wp db *` to wp-cli/db-command --- composer.json | 3 +- composer.lock | 60 +++++- php/commands/db.php | 494 -------------------------------------------- 3 files changed, 60 insertions(+), 497 deletions(-) delete mode 100644 php/commands/db.php diff --git a/composer.json b/composer.json index 90b07169c..df14abba6 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "nb/oxymel": "~0.1.0", "composer/composer": "^1.2.0", "wp-cli/cron-command": "^1.0", - "wp-cli/import-command": "^1.0" + "wp-cli/import-command": "^1.0", + "wp-cli/db-command": "^1.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 2550684fa..2a77910d8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "5c7a0459426738b69a74843e91fde8d8", - "content-hash": "cd620dac551c58f96174173297545d0d", + "hash": "2ebc3345df3d26361e0a93947bca316b", + "content-hash": "5f3ecc01d37dfd3898c3ea902630540c", "packages": [ { "name": "composer/ca-bundle", @@ -1414,6 +1414,62 @@ "homepage": "https://github.com/wp-cli/cron-command", "time": "2017-02-24 15:19:37" }, + { + "name": "wp-cli/db-command", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/wp-cli/db-command.git", + "reference": "63c346740519c85dbdc158b1fc716f5ef37ac6ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-cli/db-command/zipball/63c346740519c85dbdc158b1fc716f5ef37ac6ee", + "reference": "63c346740519c85dbdc158b1fc716f5ef37ac6ee", + "shasum": "" + }, + "require-dev": { + "behat/behat": "~2.5" + }, + "type": "wp-cli-package", + "extra": { + "commands": [ + "db create", + "db drop", + "db reset", + "db check", + "db optimize", + "db repair", + "db cli", + "db query", + "db export", + "db import", + "db tables" + ] + }, + "autoload": { + "psr-4": { + "": "src/" + }, + "files": [ + "db-command.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Bachhuber", + "email": "daniel@runcommand.io", + "homepage": "https://runcommand.io" + } + ], + "description": "Perform basic database operations using credentials stored in wp-config.php.", + "homepage": "https://github.com/wp-cli/db-command", + "time": "2017-03-01 13:55:17" + }, { "name": "wp-cli/import-command", "version": "v1.0.0", diff --git a/php/commands/db.php b/php/commands/db.php deleted file mode 100644 index cb8aafe67..000000000 --- a/php/commands/db.php +++ /dev/null @@ -1,494 +0,0 @@ - true, - ) ); - - WP_CLI::success( "Database checked." ); - } - - /** - * Optimize the database. - * - * Runs `mysqlcheck` utility with `--optimize=true` using `DB_HOST`, - * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials - * specified in wp-config.php. - * - * [See docs](http://dev.mysql.com/doc/refman/5.7/en/optimize-table.html) - * for more details on the `OPTIMIZE TABLE` statement. - * - * ## EXAMPLES - * - * $ wp db optimize - * Success: Database optimized. - */ - public function optimize() { - self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( - 'optimize' => true, - ) ); - - WP_CLI::success( "Database optimized." ); - } - - /** - * Repair the database. - * - * Runs `mysqlcheck` utility with `--repair=true` using `DB_HOST`, - * `DB_NAME`, `DB_USER` and `DB_PASSWORD` database credentials - * specified in wp-config.php. - * - * [See docs](http://dev.mysql.com/doc/refman/5.7/en/repair-table.html) for - * more details on the `REPAIR TABLE` statement. - * - * ## EXAMPLES - * - * $ wp db repair - * Success: Database repaired. - */ - public function repair() { - self::run( Utils\esc_cmd( 'mysqlcheck --no-defaults %s', DB_NAME ), array( - 'repair' => true, - ) ); - - WP_CLI::success( "Database repaired." ); - } - - /** - * Open a MySQL console using credentials from wp-config.php - * - * ## OPTIONS - * - * [--database=] - * : Use a specific database. Defaults to DB_NAME. - * - * [--default-character-set=] - * : Use a specific character set. Defaults to DB_CHARSET when defined. - * - * [--=] - * : Extra arguments to pass to the MySQL executable. - * - * ## EXAMPLES - * - * # Open MySQL console - * $ wp db cli - * mysql> - * - * @alias connect - */ - public function cli( $args, $assoc_args ) { - if ( ! isset( $assoc_args['database'] ) ) { - $assoc_args['database'] = DB_NAME; - } - - self::run( 'mysql --no-defaults --no-auto-rehash', $assoc_args ); - } - - /** - * Execute a SQL query against the database. - * - * Executes an arbitrary SQL query using `DB_HOST`, `DB_NAME`, `DB_USER` - * and `DB_PASSWORD` database credentials specified in wp-config.php. - * - * ## OPTIONS - * - * [] - * : A SQL query. If not passed, will try to read from STDIN. - * - * [--=] - * : Extra arguments to pass to mysql. - * - * ## EXAMPLES - * - * # Execute a query stored in a file - * $ wp db query < debug.sql - * - * # Check all tables in the database - * $ wp db query "CHECK TABLE $(wp db tables | paste -s -d',');" - * +---------------------------------------+-------+----------+----------+ - * | Table | Op | Msg_type | Msg_text | - * +---------------------------------------+-------+----------+----------+ - * | wordpress_dbase.wp_users | check | status | OK | - * | wordpress_dbase.wp_usermeta | check | status | OK | - * | wordpress_dbase.wp_posts | check | status | OK | - * | wordpress_dbase.wp_comments | check | status | OK | - * | wordpress_dbase.wp_links | check | status | OK | - * | wordpress_dbase.wp_options | check | status | OK | - * | wordpress_dbase.wp_postmeta | check | status | OK | - * | wordpress_dbase.wp_terms | check | status | OK | - * | wordpress_dbase.wp_term_taxonomy | check | status | OK | - * | wordpress_dbase.wp_term_relationships | check | status | OK | - * | wordpress_dbase.wp_termmeta | check | status | OK | - * | wordpress_dbase.wp_commentmeta | check | status | OK | - * +---------------------------------------+-------+----------+----------+ - * - * # Pass extra arguments through to MySQL - * $ wp db query 'SELECT * FROM wp_options WHERE option_name="home"' --skip-column-names - * +---+------+------------------------------+-----+ - * | 2 | home | http://wordpress-develop.dev | yes | - * +---+------+------------------------------+-----+ - */ - public function query( $args, $assoc_args ) { - $assoc_args['database'] = DB_NAME; - - // The query might come from STDIN - if ( !empty( $args ) ) { - $assoc_args['execute'] = $args[0]; - } - - self::run( 'mysql --no-defaults --no-auto-rehash', $assoc_args ); - } - - /** - * Exports the database to a file or to STDOUT. - * - * Runs `mysqldump` utility using `DB_HOST`, `DB_NAME`, `DB_USER` and - * `DB_PASSWORD` database credentials specified in wp-config.php. - * - * ## OPTIONS - * - * [] - * : The name of the SQL file to export. If '-', then outputs to STDOUT. If omitted, it will be '{dbname}.sql'. - * - * [--=] - * : Extra arguments to pass to mysqldump - * - * [--tables=] - * : The comma separated list of specific tables to export. Excluding this parameter will export all tables in the database. - * - * [--porcelain] - * : Output filename for the exported database. - * - * ## EXAMPLES - * - * # Export database with drop query included - * $ wp db export --add-drop-table - * Success: Exported to 'wordpress_dbase.sql'. - * - * # Export certain tables - * $ wp db export --tables=wp_options,wp_users - * Success: Exported to 'wordpress_dbase.sql'. - * - * # Export all tables matching a wildcard - * $ wp db export --tables=$(wp db tables 'wp_user*' --format=csv) - * Success: Exported to 'wordpress_dbase.sql'. - * - * # Export all tables matching prefix - * $ wp db export --tables=$(wp db tables --all-tables-with-prefix --format=csv) - * Success: Exported to 'wordpress_dbase.sql'. - * - * @alias dump - */ - public function export( $args, $assoc_args ) { - if ( ! empty( $args[0] ) ) { - $result_file = $args[0]; - } else { - $hash = substr( md5( mt_rand() ), 0, 7 ); - $result_file = sprintf( '%s-%s.sql', DB_NAME, $hash );; - } - $stdout = ( '-' === $result_file ); - $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); - - // Bail if both porcelain and STDOUT are set. - if ( $stdout && $porcelain ) { - WP_CLI::error( 'Porcelain is not allowed when output mode is STDOUT.' ); - } - - if ( ! $stdout ) { - $assoc_args['result-file'] = $result_file; - } - - $command = 'mysqldump --no-defaults %s'; - $command_esc_args = array( DB_NAME ); - - if ( isset( $assoc_args['tables'] ) ) { - $tables = explode( ',', trim( $assoc_args['tables'], ',' ) ); - unset( $assoc_args['tables'] ); - $command .= ' --tables'; - foreach ( $tables as $table ) { - $command .= ' %s'; - $command_esc_args[] = trim( $table ); - } - } - - $escaped_command = call_user_func_array( '\WP_CLI\Utils\esc_cmd', array_merge( array( $command ), $command_esc_args ) ); - - // Remove parameters not needed for SQL run. - if ( isset( $assoc_args['porcelain'] ) ) { - unset( $assoc_args['porcelain'] ); - } - - self::run( $escaped_command, $assoc_args ); - - if ( $porcelain ) { - WP_CLI::line( $result_file ); - } - else if ( ! $stdout ) { - WP_CLI::success( sprintf( "Exported to '%s'.", $result_file ) ); - } - } - - /** - * Import a database from a file or from STDIN. - * - * Runs SQL queries using `DB_HOST`, `DB_NAME`, `DB_USER` and - * `DB_PASSWORD` database credentials specified in wp-config.php. This - * does not create database by itself and only performs whatever tasks are - * defined in the SQL. - * - * ## OPTIONS - * - * [] - * : The name of the SQL file to import. If '-', then reads from STDIN. If omitted, it will look for '{dbname}.sql'. - * - * [--skip-optimization] - * : When using an SQL file, do not include speed optimization such as disabling auto-commit and key checks. - * - * ## EXAMPLES - * - * # Import MySQL from a file. - * $ wp db import wordpress_dbase.sql - * Success: Imported from 'wordpress_dbase.sql'. - */ - public function import( $args, $assoc_args ) { - if ( ! empty( $args[0] ) ) { - $result_file = $args[0]; - } else { - $result_file = sprintf( '%s.sql', DB_NAME ); - } - - $mysql_args = array( - 'database' => DB_NAME, - ); - - if ( '-' !== $result_file ) { - if ( ! is_readable( $result_file ) ) { - WP_CLI::error( sprintf( 'Import file missing or not readable: %s', $result_file ) ); - } - - $query = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-optimization' ) - ? 'SOURCE %s;' - : 'SET autocommit = 0; SET unique_checks = 0; SET foreign_key_checks = 0; SOURCE %s; COMMIT;'; - - $mysql_args['execute'] = sprintf( $query, $result_file ); - } - - self::run( 'mysql --no-defaults --no-auto-rehash', $mysql_args ); - - WP_CLI::success( sprintf( "Imported from '%s'.", $result_file ) ); - } - - /** - * List the database tables. - * - * Defaults to all tables registered to the $wpdb database handler. - * - * ## OPTIONS - * - * [...] - * : List tables based on wildcard search, e.g. 'wp_*_options' or 'wp_post?'. - * - * [--scope=] - * : Can be all, global, ms_global, blog, or old tables. Defaults to all. - * - * [--network] - * : List all the tables in a multisite install. Overrides --scope=. - * - * [--all-tables-with-prefix] - * : List all tables that match the table prefix even if not registered on $wpdb. Overrides --network. - * - * [--all-tables] - * : List all tables in the database, regardless of the prefix, and even if not registered on $wpdb. Overrides --all-tables-with-prefix. - * - * [--format=] - * : Render output in a particular format. - * --- - * default: list - * options: - * - list - * - csv - * --- - * - * ## EXAMPLES - * - * # List tables for a single site, without shared tables like 'wp_users' - * $ wp db tables --scope=blog --url=sub.example.com - * wp_3_posts - * wp_3_comments - * wp_3_options - * wp_3_postmeta - * wp_3_terms - * wp_3_term_taxonomy - * wp_3_term_relationships - * wp_3_termmeta - * wp_3_commentmeta - * - * # Export only tables for a single site - * $ wp db export --tables=$(wp db tables --url=sub.example.com --format=csv) - * Success: Exported to wordpress_dbase.sql - */ - public function tables( $args, $assoc_args ) { - - $format = WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ); - unset( $assoc_args['format'] ); - - if ( empty( $args ) && empty( $assoc_args ) ) { - $assoc_args['scope'] = 'all'; - } - - $tables = WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); - - if ( 'csv' === $format ) { - WP_CLI::line( implode( ',', $tables ) ); - } else { - foreach ( $tables as $table ) { - WP_CLI::line( $table ); - } - } - } - - private static function get_create_query() { - - $create_query = sprintf( 'CREATE DATABASE `%s`', DB_NAME ); - if ( defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { - $create_query .= sprintf( ' DEFAULT CHARSET `%s`', constant( 'DB_CHARSET' ) ); - } - if ( defined( 'DB_COLLATE' ) && constant( 'DB_COLLATE' ) ) { - $create_query .= sprintf( ' DEFAULT COLLATE `%s`', constant( 'DB_COLLATE' ) ); - } - return $create_query; - } - - private static function run_query( $query ) { - self::run( 'mysql --no-defaults --no-auto-rehash', array( 'execute' => $query ) ); - } - - private static function run( $cmd, $assoc_args = array(), $descriptors = null ) { - $required = array( - 'host' => DB_HOST, - 'user' => DB_USER, - 'pass' => DB_PASSWORD, - ); - - if ( ! isset( $assoc_args['default-character-set'] ) - && defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) { - $required['default-character-set'] = constant( 'DB_CHARSET' ); - } - - $final_args = array_merge( $assoc_args, $required ); - Utils\run_mysql_command( $cmd, $final_args, $descriptors ); - } - -} - -WP_CLI::add_command( 'db', 'DB_Command' ); - From b026725da785bfbf2897354fe37bfc7d5a2aac9f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 1 Mar 2017 06:01:08 -0800 Subject: [PATCH 5325/5359] Tests are now handled by the package's test suite --- features/db-check.feature | 15 ---- features/db-export.feature | 21 ----- features/db-import.feature | 63 -------------- features/db-query.feature | 23 ----- features/db-tables.feature | 133 ---------------------------- features/db.feature | 173 ------------------------------------- 6 files changed, 428 deletions(-) delete mode 100644 features/db-check.feature delete mode 100644 features/db-export.feature delete mode 100644 features/db-import.feature delete mode 100644 features/db-query.feature delete mode 100644 features/db-tables.feature delete mode 100644 features/db.feature diff --git a/features/db-check.feature b/features/db-check.feature deleted file mode 100644 index 036dbf363..000000000 --- a/features/db-check.feature +++ /dev/null @@ -1,15 +0,0 @@ -Feature: Check the database - - Scenario: Run db check to check the database - Given a WP install - - When I run `wp db check` - Then STDOUT should contain: - """ - wp_cli_test.wp_users - """ - And STDOUT should contain: - """ - Success: Database checked. - """ - And STDERR should be empty diff --git a/features/db-export.feature b/features/db-export.feature deleted file mode 100644 index 4028b0466..000000000 --- a/features/db-export.feature +++ /dev/null @@ -1,21 +0,0 @@ -Feature: Export a WordPress database - - Scenario: Database exports with random hash applied - Given a WP install - - When I run `wp db export --porcelain` - Then STDOUT should contain: - """ - wp_cli_test- - """ - And the wp_cli_test.sql file should not exist - - Scenario: Database export to a specified file path - Given a WP install - - When I run `wp db export wp_cli_test.sql --porcelain` - Then STDOUT should contain: - """ - wp_cli_test.sql - """ - And the wp_cli_test.sql file should exist diff --git a/features/db-import.feature b/features/db-import.feature deleted file mode 100644 index ed00369af..000000000 --- a/features/db-import.feature +++ /dev/null @@ -1,63 +0,0 @@ -Feature: Import a WordPress database - - Scenario: Import from database name path by default - Given a WP install - - When I run `wp db export wp_cli_test.sql` - Then the wp_cli_test.sql file should exist - - When I run `wp db import` - Then STDOUT should be: - """ - Success: Imported from 'wp_cli_test.sql'. - """ - - Scenario: Import from database name path by default and skip speed optimization - Given a WP install - - When I run `wp db export wp_cli_test.sql` - Then the wp_cli_test.sql file should exist - - When I run `wp db import --skip-optimization` - Then STDOUT should be: - """ - Success: Imported from 'wp_cli_test.sql'. - """ - - Scenario: Help runs properly at various points of a functional WP install - Given an empty directory - - When I run `wp help db import` - Then STDOUT should contain: - """ - wp db import - """ - - When I run `wp core download` - Then STDOUT should not be empty - And the wp-config-sample.php file should exist - - When I run `wp help db import` - Then STDOUT should contain: - """ - wp db import - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS}` - Then STDOUT should not be empty - And the wp-config.php file should exist - - When I run `wp help db import` - Then STDOUT should contain: - """ - wp db import - """ - - When I run `wp db create` - Then STDOUT should not be empty - - When I run `wp help db import` - Then STDOUT should contain: - """ - wp db import - """ diff --git a/features/db-query.feature b/features/db-query.feature deleted file mode 100644 index f8e3d4e82..000000000 --- a/features/db-query.feature +++ /dev/null @@ -1,23 +0,0 @@ -Feature: Query the database with WordPress' MySQL config - - Scenario: Database querying shouldn't load any plugins - Given a WP install - And a wp-content/mu-plugins/error.php file: - """ - Date: Wed, 1 Mar 2017 06:05:05 -0800 Subject: [PATCH 5326/5359] Add a basic test that `wp db` exists --- features/command.feature | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/command.feature b/features/command.feature index 13166db4b..f71917f55 100644 --- a/features/command.feature +++ b/features/command.feature @@ -11,6 +11,12 @@ Feature: WP-CLI Commands or: wp cron test """ + When I run `wp db` + Then STDOUT should contain: + """ + or: wp db cli + """ + When I run `wp import --help` Then STDOUT should contain: """ From 0e528def9999469200de834ca3629efc7c669206 Mon Sep 17 00:00:00 2001 From: "Stephen J. Carnam" Date: Thu, 2 Mar 2017 00:10:57 -0800 Subject: [PATCH 5327/5359] Fix allowing env. values to permit specific binary Per the function comment "Environment values permit specific binaries to be indicated". Currently not possible as PHP_BINARY ***always*** present as defined constant (which can NEVER be overridden unless one uses runkit_extension; dated, not supported) --- php/class-wp-cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 3b69d4107..e2696d75c 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -906,15 +906,15 @@ public static function launch_self( $command, $args = array(), $assoc_args = arr * @return string */ public static function get_php_binary() { - if ( defined( 'PHP_BINARY' ) ) - return PHP_BINARY; - if ( getenv( 'WP_CLI_PHP_USED' ) ) return getenv( 'WP_CLI_PHP_USED' ); if ( getenv( 'WP_CLI_PHP' ) ) return getenv( 'WP_CLI_PHP' ); + if ( defined( 'PHP_BINARY' ) ) + return PHP_BINARY; + return 'php'; } From 3f82519150fef0f5050711d0e8747b7ddd56f3c1 Mon Sep 17 00:00:00 2001 From: "Stephen J. Carnam" Date: Thu, 2 Mar 2017 00:32:31 -0800 Subject: [PATCH 5328/5359] Permit WP_CLI_PHP environment variable Like with other commands, info, update, run command, utilize WP_CLI::get_php_binary() in lieu of fixed PHP_BINARY constant. --- php/commands/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/commands/server.php b/php/commands/server.php index 5f751d096..8d6dd7e01 100644 --- a/php/commands/server.php +++ b/php/commands/server.php @@ -81,7 +81,7 @@ function __invoke( $_, $assoc_args ) { } $cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s -c %s %s', - PHP_BINARY, + WP_CLI::get_php_binary(), $assoc_args['host'] . ':' . $assoc_args['port'], $docroot, $assoc_args['config'], From a0b251930d851fcaa28178f28f349a3fb4d38379 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Tue, 7 Mar 2017 11:03:50 -0800 Subject: [PATCH 5329/5359] Update tests for WordPress 4.7.3 --- features/core-check-update.feature | 10 +++++----- features/core-update.feature | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/features/core-check-update.feature b/features/core-check-update.feature index d7903c37d..7d85c597c 100644 --- a/features/core-check-update.feature +++ b/features/core-check-update.feature @@ -9,8 +9,8 @@ Feature: Check for more recent versions When I run `wp core check-update` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7.2 | major | https://downloads.wordpress.org/release/wordpress-4.7.2.zip | - | 4.4.7 | minor | https://downloads.wordpress.org/release/wordpress-4.4.7-partial-0.zip | + | 4.7.3 | major | https://downloads.wordpress.org/release/wordpress-4.7.3.zip | + | 4.4.8 | minor | https://downloads.wordpress.org/release/wordpress-4.4.8-partial-0.zip | When I run `wp core check-update --format=count` Then STDOUT should be: @@ -21,7 +21,7 @@ Feature: Check for more recent versions When I run `wp core check-update --major` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.7.2 | major | https://downloads.wordpress.org/release/wordpress-4.7.2.zip | + | 4.7.3 | major | https://downloads.wordpress.org/release/wordpress-4.7.3.zip | When I run `wp core check-update --major --format=count` Then STDOUT should be: @@ -32,7 +32,7 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.4.7 | minor | https://downloads.wordpress.org/release/wordpress-4.4.7-partial-0.zip | + | 4.4.8 | minor | https://downloads.wordpress.org/release/wordpress-4.4.8-partial-0.zip | When I run `wp core check-update --minor --format=count` Then STDOUT should be: @@ -53,4 +53,4 @@ Feature: Check for more recent versions When I run `wp core check-update --minor` Then STDOUT should be a table containing rows: | version | update_type | package_url | - | 4.0.15 | minor | https://downloads.wordpress.org/release/wordpress-4.0.15-partial-0.zip | + | 4.0.16 | minor | https://downloads.wordpress.org/release/wordpress-4.0.16-partial-0.zip | diff --git a/features/core-update.feature b/features/core-update.feature index 9206ef169..ea6b8c0c9 100644 --- a/features/core-update.feature +++ b/features/core-update.feature @@ -40,7 +40,7 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 3.7.18 + Updating to version 3.7.19 """ When I run `wp core update --minor` @@ -52,7 +52,7 @@ Feature: Update WordPress core When I run `wp core version` Then STDOUT should be: """ - 3.7.18 + 3.7.19 """ @less-than-php-7 @@ -208,8 +208,8 @@ Feature: Update WordPress core When I run `wp core update --minor` Then STDOUT should contain: """ - Updating to version 4.0.15 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.15-partial-0.zip + Updating to version 4.0.16 (en_US)... + Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.16-partial-0.zip """ And STDOUT should contain: """ From 8eb13d9d7d353da0780a5ca84284ccc1bcda1b4e Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 8 Mar 2017 12:13:17 +0100 Subject: [PATCH 5330/5359] Add `roave/security-advisories` as a development dependency. This prevents adding Composer dependencies with known security vulnerabilities. Resolves #3842 --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index df14abba6..9ac173326 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ }, "require-dev": { "phpunit/phpunit": "3.7.*", - "behat/behat": "2.5.*" + "behat/behat": "2.5.*", + "roave/security-advisories": "dev-master" }, "suggest": { "psy/psysh": "Enhanced `wp shell` functionality" From 7770b10fd53f9aaf6621a837559d3b39ba88d839 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Wed, 8 Mar 2017 12:14:21 +0100 Subject: [PATCH 5331/5359] Update Composer lock file after inclusion of the `roave/security-advisories` package. Note: This commit includes additional changes becauase Composer has changed the timestamp format for the lock file. --- composer.lock | 218 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 177 insertions(+), 41 deletions(-) diff --git a/composer.lock b/composer.lock index 2a77910d8..4340293ce 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2ebc3345df3d26361e0a93947bca316b", - "content-hash": "5f3ecc01d37dfd3898c3ea902630540c", + "content-hash": "7d6bf48fe871612177b44a551ce94066", "packages": [ { "name": "composer/ca-bundle", @@ -63,7 +62,7 @@ "ssl", "tls" ], - "time": "2016-11-02 18:11:27" + "time": "2016-11-02T18:11:27+00:00" }, { "name": "composer/composer", @@ -140,7 +139,7 @@ "dependency", "package" ], - "time": "2017-01-27 17:23:42" + "time": "2017-01-27T17:23:42+00:00" }, { "name": "composer/semver", @@ -202,7 +201,7 @@ "validation", "versioning" ], - "time": "2016-08-30 16:08:34" + "time": "2016-08-30T16:08:34+00:00" }, { "name": "composer/spdx-licenses", @@ -263,7 +262,7 @@ "spdx", "validator" ], - "time": "2016-09-28 07:17:45" + "time": "2016-09-28T07:17:45+00:00" }, { "name": "justinrainbow/json-schema", @@ -329,7 +328,7 @@ "json", "schema" ], - "time": "2016-12-22 16:43:46" + "time": "2016-12-22T16:43:46+00:00" }, { "name": "mustache/mustache", @@ -375,7 +374,7 @@ "mustache", "templating" ], - "time": "2016-07-31 06:18:27" + "time": "2016-07-31T06:18:27+00:00" }, { "name": "mustangostang/spyc", @@ -425,7 +424,7 @@ "yaml", "yml" ], - "time": "2017-02-24 16:06:33" + "time": "2017-02-24T16:06:33+00:00" }, { "name": "nb/oxymel", @@ -466,7 +465,7 @@ "keywords": [ "xml" ], - "time": "2013-02-24 15:01:54" + "time": "2013-02-24T15:01:54+00:00" }, { "name": "psr/log", @@ -513,7 +512,7 @@ "psr", "psr-3" ], - "time": "2016-10-10 12:19:37" + "time": "2016-10-10T12:19:37+00:00" }, { "name": "ramsey/array_column", @@ -558,7 +557,7 @@ "array_column", "column" ], - "time": "2015-03-20 22:07:39" + "time": "2015-03-20T22:07:39+00:00" }, { "name": "rmccue/requests", @@ -607,7 +606,7 @@ "iri", "sockets" ], - "time": "2016-10-13 00:11:37" + "time": "2016-10-13T00:11:37+00:00" }, { "name": "seld/cli-prompt", @@ -655,7 +654,7 @@ "input", "prompt" ], - "time": "2016-04-18 09:31:41" + "time": "2016-04-18T09:31:41+00:00" }, { "name": "seld/jsonlint", @@ -701,7 +700,7 @@ "parser", "validator" ], - "time": "2016-11-14 17:59:58" + "time": "2016-11-14T17:59:58+00:00" }, { "name": "seld/phar-utils", @@ -745,7 +744,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13 18:44:15" + "time": "2015-10-13T18:44:15+00:00" }, { "name": "symfony/config", @@ -801,7 +800,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-02-05 10:11:19" + "time": "2017-02-05T10:11:19+00:00" }, { "name": "symfony/console", @@ -862,7 +861,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-02-06 12:04:06" + "time": "2017-02-06T12:04:06+00:00" }, { "name": "symfony/debug", @@ -919,7 +918,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-01-27 23:54:58" + "time": "2017-01-27T23:54:58+00:00" }, { "name": "symfony/dependency-injection", @@ -982,7 +981,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-01-27 23:54:58" + "time": "2017-01-27T23:54:58+00:00" }, { "name": "symfony/event-dispatcher", @@ -1042,7 +1041,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-01-02T20:30:24+00:00" }, { "name": "symfony/filesystem", @@ -1091,7 +1090,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-01-08 20:43:03" + "time": "2017-01-08T20:43:03+00:00" }, { "name": "symfony/finder", @@ -1140,7 +1139,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-01-02 20:30:24" + "time": "2017-01-02T20:30:24+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1199,7 +1198,7 @@ "portable", "shim" ], - "time": "2016-11-14 01:06:16" + "time": "2016-11-14T01:06:16+00:00" }, { "name": "symfony/process", @@ -1248,7 +1247,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-02-03 12:08:06" + "time": "2017-02-03T12:08:06+00:00" }, { "name": "symfony/translation", @@ -1312,7 +1311,7 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2017-01-21 16:59:38" + "time": "2017-01-21T16:59:38+00:00" }, { "name": "symfony/yaml", @@ -1361,7 +1360,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-01-21 16:40:50" + "time": "2017-01-21T16:40:50+00:00" }, { "name": "wp-cli/cron-command", @@ -1412,7 +1411,7 @@ ], "description": "Manage WP-Cron events and schedules.", "homepage": "https://github.com/wp-cli/cron-command", - "time": "2017-02-24 15:19:37" + "time": "2017-02-24T15:19:37+00:00" }, { "name": "wp-cli/db-command", @@ -1468,7 +1467,7 @@ ], "description": "Perform basic database operations using credentials stored in wp-config.php.", "homepage": "https://github.com/wp-cli/db-command", - "time": "2017-03-01 13:55:17" + "time": "2017-03-01T13:55:17+00:00" }, { "name": "wp-cli/import-command", @@ -1514,7 +1513,7 @@ ], "description": "Import content from a WXR file.", "homepage": "https://github.com/wp-cli/import-command", - "time": "2017-02-28 13:24:43" + "time": "2017-02-28T13:24:43+00:00" }, { "name": "wp-cli/php-cli-tools", @@ -1564,7 +1563,7 @@ "cli", "console" ], - "time": "2017-02-15 12:17:55" + "time": "2017-02-15T12:17:55+00:00" } ], "packages-dev": [ @@ -1628,7 +1627,7 @@ "Behat", "Symfony2" ], - "time": "2015-06-01 09:37:55" + "time": "2015-06-01T09:37:55+00:00" }, { "name": "behat/gherkin", @@ -1689,7 +1688,7 @@ "Symfony2", "parser" ], - "time": "2013-10-15 11:22:17" + "time": "2013-10-15T11:22:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1750,7 +1749,7 @@ "testing", "xunit" ], - "time": "2014-09-02 10:13:14" + "time": "2014-09-02T10:13:14+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1797,7 +1796,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03 07:40:28" + "time": "2016-10-03T07:40:28+00:00" }, { "name": "phpunit/php-text-template", @@ -1838,7 +1837,7 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", @@ -1887,7 +1886,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26 11:10:40" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", @@ -1937,7 +1936,7 @@ "keywords": [ "tokenizer" ], - "time": "2014-03-03 05:10:30" + "time": "2014-03-03T05:10:30+00:00" }, { "name": "phpunit/phpunit", @@ -2010,7 +2009,7 @@ "testing", "xunit" ], - "time": "2014-10-17 09:04:17" + "time": "2014-10-17T09:04:17+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -2059,12 +2058,149 @@ "mock", "xunit" ], - "time": "2013-01-13 10:24:48" + "time": "2013-01-13T10:24:48+00:00" + }, + { + "name": "roave/security-advisories", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "73603e2e613ddc14e2e11ec6da4e837bf0a2149a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/73603e2e613ddc14e2e11ec6da4e837bf0a2149a", + "reference": "73603e2e613ddc14e2e11ec6da4e837bf0a2149a", + "shasum": "" + }, + "conflict": { + "adodb/adodb-php": "<5.20.6", + "amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4", + "aws/aws-sdk-php": ">=3,<3.2.1", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=3,<3.0.15|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=1.3,<1.3.18|>=2.7,<2.7.6|>=3.1,<3.1.4", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<2.1", + "codeigniter/framework": "<=3.0.6", + "composer/composer": "<=1.0.0-alpha11", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2.11,<3.5.15", + "doctrine/annotations": ">=1,<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<=0.7.1", + "doctrine/mongodb-odm": ">=1,<1.0.2", + "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", + "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=8,<8.2.3", + "drupal/drupal": ">=8,<8.2.3", + "firebase/php-jwt": "<2", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "gregwar/rst": "<1.0.3", + "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", + "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", + "joomla/session": "<1.3.1", + "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", + "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", + "magento/magento1ee": ">=1.9,<1.14.3.2", + "magento/magento2ce": ">=2,<2.2", + "monolog/monolog": ">=1.8,<1.12", + "namshi/jose": "<2.2", + "oro/crm": ">=1.7,<1.7.4", + "oro/platform": ">=1.7,<1.7.4", + "phpmailer/phpmailer": ">=5,<5.2.22", + "pusher/pusher-php-server": "<2.2.1", + "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "shopware/shopware": "<4.4|>=5,<5.2.16", + "silverstripe/cms": ">=3.1,<3.1.11|>=3,<=3.0.11", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": ">=3,<3.3", + "silverstripe/userforms": "<3", + "simplesamlphp/saml2": "<1.8.1|>=1.9,<1.9.1|>=1.10,<1.10.3|>=2,<2.3.3", + "simplesamlphp/simplesamlphp": "<1.14.11", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "socalnick/scn-social-auth": "<1.15.2", + "squizlabs/php_codesniffer": ">=1,<2.8.1", + "swiftmailer/swiftmailer": ">=4,<5.4.5", + "symfony/dependency-injection": ">=2,<2.0.17", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.7", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", + "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", + "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", + "symfony/routing": ">=2,<2.0.19", + "symfony/security": ">=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9", + "symfony/security-core": ">=2.8,<2.8.6|>=3,<3.0.6|>=2.4,<2.6.13|>=2.7,<2.7.9", + "symfony/security-http": ">=2.4,<2.7.13|>=2.3,<2.3.41|>=2.8,<2.8.6|>=3,<3.0.6", + "symfony/serializer": ">=2,<2.0.11", + "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6", + "symfony/translation": ">=2,<2.0.17", + "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "thelia/backoffice-default-template": ">=2.1,<2.1.2", + "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "twig/twig": "<1.20", + "typo3/cms": ">=6.2,<6.2.30|>=8,<8.6.1|>=7,<7.6.16", + "typo3/flow": ">=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5|>=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "willdurand/js-translation-bundle": "<2.1.1", + "yiisoft/yii": ">=1.1.14,<1.1.15", + "yiisoft/yii2": "<2.0.5", + "yiisoft/yii2-bootstrap": "<2.0.4", + "yiisoft/yii2-dev": "<2.0.4", + "yiisoft/yii2-gii": "<2.0.4", + "yiisoft/yii2-jui": "<2.0.4", + "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", + "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-diactoros": ">=1,<1.0.4", + "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", + "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", + "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-validator": ">=2.3,<2.3.6", + "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", + "zendframework/zendframework1": "<1.12.20", + "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendxml": ">=1,<1.0.1", + "zf-commons/zfc-user": "<1.2.2", + "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", + "zfr/zfr-oauth2-server-module": "<0.1.2" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" + } + ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "time": "2017-03-02T15:23:30+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "roave/security-advisories": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 3fa796ddeeb6d5829e22c119985257466c1154a8 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Wed, 8 Mar 2017 05:33:49 -0800 Subject: [PATCH 5332/5359] Abstract `wp media *` to wp-cli/media-command --- composer.json | 3 +- composer.lock | 49 ++++- php/commands/media.php | 401 ----------------------------------------- 3 files changed, 50 insertions(+), 403 deletions(-) delete mode 100644 php/commands/media.php diff --git a/composer.json b/composer.json index 9ac173326..35b632f9d 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "composer/composer": "^1.2.0", "wp-cli/cron-command": "^1.0", "wp-cli/import-command": "^1.0", - "wp-cli/db-command": "^1.0" + "wp-cli/db-command": "^1.0", + "wp-cli/media-command": "^1.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/composer.lock b/composer.lock index 4340293ce..47144fe9c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "7d6bf48fe871612177b44a551ce94066", + "content-hash": "973e07d9736ed27c9e352cb651db3a46", "packages": [ { "name": "composer/ca-bundle", @@ -1515,6 +1515,53 @@ "homepage": "https://github.com/wp-cli/import-command", "time": "2017-02-28T13:24:43+00:00" }, + { + "name": "wp-cli/media-command", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/wp-cli/media-command.git", + "reference": "fa12bf77a0c0f4af934750175eb75b4b358d399c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wp-cli/media-command/zipball/fa12bf77a0c0f4af934750175eb75b4b358d399c", + "reference": "fa12bf77a0c0f4af934750175eb75b4b358d399c", + "shasum": "" + }, + "require-dev": { + "behat/behat": "~2.5" + }, + "type": "wp-cli-package", + "extra": { + "commands": [ + "media import", + "media regenerate" + ] + }, + "autoload": { + "psr-4": { + "": "src/" + }, + "files": [ + "media-command.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Bachhuber", + "email": "daniel@runcommand.io", + "homepage": "https://runcommand.io" + } + ], + "description": "Manage attachments.", + "homepage": "https://github.com/wp-cli/media-command", + "time": "2017-03-08T13:17:43+00:00" + }, { "name": "wp-cli/php-cli-tools", "version": "v0.11.2", diff --git a/php/commands/media.php b/php/commands/media.php deleted file mode 100644 index 989049312..000000000 --- a/php/commands/media.php +++ /dev/null @@ -1,401 +0,0 @@ -...] - * : One or more IDs of the attachments to regenerate. - * - * [--skip-delete] - * : Skip deletion of the original thumbnails. If your thumbnails are linked from sources outside your control, it's likely best to leave them around. Defaults to false. - * - * [--only-missing] - * : Only generate thumbnails for images missing image sizes. - * - * [--yes] - * : Answer yes to the confirmation message. Confirmation only shows when no IDs passed as arguments. - * - * ## EXAMPLES - * - * # Regenerate thumbnails for given attachment IDs. - * $ wp media regenerate 123 124 125 - * Found 3 images to regenerate. - * 1/3 Regenerated thumbnails for "Vertical Image" (ID 123). - * 2/3 Regenerated thumbnails for "Horizontal Image" (ID 124). - * 3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125). - * Success: Regenerated 3 of 3 images. - * - * # Regenerate all thumbnails, without confirmation. - * $ wp media regenerate --yes - * Found 3 images to regenerate. - * 1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760). - * 2/3 Regenerated thumbnails for "Boardwalk" (ID 757). - * 3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756). - * Success: Regenerated 3 of 3 images. - * - * # Re-generate all thumbnails that have IDs between 1000 and 2000. - * $ seq 1000 2000 | xargs wp media regenerate - * Found 4 images to regenerate. - * 1/4 Regenerated thumbnails for "Vertical Featured Image" (ID 1027). - * 2/4 Regenerated thumbnails for "Horizontal Featured Image" (ID 1022). - * 3/4 Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045). - * 4/4 Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023). - * Success: Regenerated 4 of 4 images. - */ - function regenerate( $args, $assoc_args = array() ) { - if ( empty( $args ) ) { - WP_CLI::confirm( 'Do you really want to regenerate all images?', $assoc_args ); - } - - $skip_delete = \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ); - $only_missing = \WP_CLI\Utils\get_flag_value( $assoc_args, 'only-missing' ); - if ( $only_missing ) { - $skip_delete = true; - } - - $mime_types = array( 'image' ); - if ( Utils\wp_version_compare( '4.7', '>=' ) ) { - $mime_types[] = 'application/pdf'; - } - $query_args = array( - 'post_type' => 'attachment', - 'post__in' => $args, - 'post_mime_type' => $mime_types, - 'post_status' => 'any', - 'posts_per_page' => -1, - 'fields' => 'ids' - ); - - $images = new WP_Query( $query_args ); - - $count = $images->post_count; - - if ( !$count ) { - WP_CLI::warning( 'No images found.' ); - return; - } - - WP_CLI::log( sprintf( 'Found %1$d %2$s to regenerate.', $count, - _n( 'image', 'images', $count ) ) ); - - $errored = false; - $successes = $errors = 0; - foreach ( $images->posts as $number => $id ) { - if ( $this->process_regeneration( $id, $skip_delete, $only_missing, ( $number + 1 ) . '/' . $count ) ) { - $successes++; - } else { - $errors++; - } - } - - Utils\report_batch_operation_results( 'image', 'regenerate', count( $images->posts ), $successes, $errors ); - } - - /** - * Create attachments from local files or URLs. - * - * ## OPTIONS - * - * ... - * : Path to file or files to be imported. Supports the glob(3) capabilities of the current shell. - * If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be - * downloaded to a temp file before being sideloaded. - * - * [--post_id=] - * : ID of the post to attach the imported files to. - * - * [--title=] - * : Attachment title (post title field). - * - * [--caption=<caption>] - * : Caption for attachent (post excerpt field). - * - * [--alt=<alt_text>] - * : Alt text for image (saved as post meta). - * - * [--desc=<description>] - * : "Description" field (post content) of attachment post. - * - * [--featured_image] - * : If set, set the imported image as the Featured Image of the post its attached to. - * - * [--porcelain] - * : Output just the new attachment ID. - * - * ## EXAMPLES - * - * # Import all jpgs in the current user's "Pictures" directory, not attached to any post. - * $ wp media import ~/Pictures/**\/*.jpg - * Imported file '/home/person/Pictures/beautiful-youg-girl-in-ivy.jpg' as attachment ID 1751. - * Imported file '/home/person/Pictures/fashion-girl.jpg' as attachment ID 1752. - * Success: Imported 2 of 2 images. - * - * # Import a local image and set it to be the post thumbnail for a post. - * $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image - * Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image. - * Success: Imported 1 of 1 images. - * - * # Import a local image, but set it as the featured image for all posts. - * # 1. Import the image and get its attachment ID. - * # 2. Assign the attachment ID as the featured image for all posts. - * $ ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)" - * $ wp post list --post_type=post --format=ids | xargs -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID - * Success: Added custom field. - * Success: Added custom field. - * - * # Import an image from the web. - * $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing" - * Imported file 'http://s.wordpress.org/style/images/wp-header-logo.png' as attachment ID 1755. - * Success: Imported 1 of 1 images. - */ - function import( $args, $assoc_args = array() ) { - $assoc_args = wp_parse_args( $assoc_args, array( - 'title' => '', - 'caption' => '', - 'alt' => '', - 'desc' => '', - ) ); - - if ( isset( $assoc_args['post_id'] ) ) { - if ( !get_post( $assoc_args['post_id'] ) ) { - WP_CLI::warning( "Invalid --post_id" ); - $assoc_args['post_id'] = false; - } - } else { - $assoc_args['post_id'] = false; - } - - $successes = $errors = 0; - foreach ( $args as $file ) { - $is_file_remote = parse_url( $file, PHP_URL_HOST ); - $orig_filename = $file; - - if ( empty( $is_file_remote ) ) { - if ( !file_exists( $file ) ) { - WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." ); - $errors++; - continue; - } - $tempfile = $this->make_copy( $file ); - } else { - $tempfile = download_url( $file ); - if ( is_wp_error( $tempfile ) ) { - WP_CLI::warning( sprintf( - "Unable to import file '%s'. Reason: %s", - $file, implode( ', ', $tempfile->get_error_messages() ) - ) ); - $errors++; - continue; - } - } - - $file_array = array( - 'tmp_name' => $tempfile, - 'name' => Utils\basename( $file ) - ); - - $post_array= array( - 'post_title' => $assoc_args['title'], - 'post_excerpt' => $assoc_args['caption'], - 'post_content' => $assoc_args['desc'] - ); - $post_array = wp_slash( $post_array ); - - // use image exif/iptc data for title and caption defaults if possible - if ( empty( $post_array['post_title'] ) || empty( $post_array['post_excerpt'] ) ) { - // @codingStandardsIgnoreStart - $image_meta = @wp_read_image_metadata( $tempfile ); - // @codingStandardsIgnoreEnd - if ( ! empty( $image_meta ) ) { - if ( empty( $post_array['post_title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { - $post_array['post_title'] = $image_meta['title']; - } - - if ( empty( $post_array['post_excerpt'] ) && trim( $image_meta['caption'] ) ) { - $post_array['post_excerpt'] = $image_meta['caption']; - } - } - } - - if ( empty( $post_array['post_title'] ) ) { - $post_array['post_title'] = preg_replace( '/\.[^.]+$/', '', Utils\basename( $file ) ); - } - - // Deletes the temporary file. - $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array ); - if ( is_wp_error( $success ) ) { - WP_CLI::warning( sprintf( - "Unable to import file '%s'. Reason: %s", - $orig_filename, implode( ', ', $success->get_error_messages() ) - ) ); - $errors++; - continue; - } - - // Set alt text - if ( $assoc_args['alt'] ) { - update_post_meta( $success, '_wp_attachment_image_alt', wp_slash( $assoc_args['alt'] ) ); - } - - // Set as featured image, if --post_id and --featured_image are set - if ( $assoc_args['post_id'] && \WP_CLI\Utils\get_flag_value( $assoc_args, 'featured_image' ) ) { - update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success ); - } - - $attachment_success_text = ''; - if ( $assoc_args['post_id'] ) { - $attachment_success_text = " and attached to post {$assoc_args['post_id']}"; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'featured_image' ) ) - $attachment_success_text .= ' as featured image'; - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { - WP_CLI::line( $success ); - } else { - WP_CLI::log( sprintf( - "Imported file '%s' as attachment ID %d%s.", - $orig_filename, $success, $attachment_success_text - ) ); - } - $successes++; - } - if ( ! Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { - Utils\report_batch_operation_results( 'image', 'import', count( $args ), $successes, $errors ); - } elseif ( $errors ) { - WP_CLI::halt( 1 ); - } - } - - // wp_tempnam() inexplicably forces a .tmp extension, which spoils MIME type detection - private function make_copy( $path ) { - $dir = get_temp_dir(); - $filename = Utils\basename( $path ); - if ( empty( $filename ) ) - $filename = time(); - - $filename = $dir . wp_unique_filename( $dir, $filename ); - if ( !copy( $path, $filename ) ) - WP_CLI::error( "Could not create temporary file for $path." ); - - return $filename; - } - - private function process_regeneration( $id, $skip_delete, $only_missing, $progress ) { - - $fullsizepath = get_attached_file( $id ); - - $att_desc = sprintf( '"%1$s" (ID %2$d)', get_the_title( $id ), $id ); - - if ( false === $fullsizepath || !file_exists( $fullsizepath ) ) { - WP_CLI::warning( "Can't find $att_desc." ); - return false; - } - - if ( ! $skip_delete ) { - $this->remove_old_images( $id, $fullsizepath ); - } - - if ( ! $only_missing || $this->needs_regeneration( $id, $fullsizepath ) ) { - - $metadata = wp_generate_attachment_metadata( $id, $fullsizepath ); - if ( is_wp_error( $metadata ) ) { - WP_CLI::warning( $metadata->get_error_message() ); - return false; - } - - if ( empty( $metadata ) ) { - WP_CLI::warning( "$progress Couldn't regenerate thumbnails for $att_desc." ); - return false; - } - - wp_update_attachment_metadata( $id, $metadata ); - - WP_CLI::log( "$progress Regenerated thumbnails for $att_desc." ); - return true; - } else { - WP_CLI::log( "$progress No thumbnail regeneration needed for $att_desc." ); - return true; - } - } - - private function remove_old_images( $att_id, $fullsizepath ) { - $metadata = wp_get_attachment_metadata( $att_id ); - - $dir_path = dirname( $fullsizepath ) . '/'; - - if ( empty( $metadata['sizes'] ) ) { - return; - } - - foreach ( $metadata['sizes'] as $size_info ) { - $intermediate_path = $dir_path . $size_info['file']; - - if ( $intermediate_path === $fullsizepath ) - continue; - - if ( file_exists( $intermediate_path ) ) - unlink( $intermediate_path ); - } - } - - private function needs_regeneration( $att_id, $fullsizepath ) { - $metadata = wp_get_attachment_metadata($att_id); - - $dir_path = dirname( $fullsizepath ) . '/'; - - if ( empty( $metadata['sizes'] ) ) { - return true; - } - - if ( array_diff( get_intermediate_image_sizes(), array_keys( $metadata['sizes'] ) ) ) { - return true; - } - - foreach( $metadata['sizes'] as $size_info ) { - $intermediate_path = $dir_path . $size_info['file']; - - if ( $intermediate_path === $fullsizepath ) - continue; - - if ( ! file_exists( $intermediate_path ) ) { - return true; - } - } - return false; - } -} - -WP_CLI::add_command( 'media', 'Media_Command', array( - 'before_invoke' => function () { - if ( !wp_image_editor_supports() ) { - WP_CLI::error( 'No support for generating images found. ' . - 'Please install the Imagick or GD PHP extensions.' ); - } - } -) ); - From 6ac36574b2ebd3455b063a89a5d5cc09e04cec5d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 8 Mar 2017 05:37:37 -0800 Subject: [PATCH 5333/5359] Tests are now handled by the package's test suite --- features/command.feature | 6 + features/media-import.feature | 158 ---------------- features/media-regenerate.feature | 287 ------------------------------ 3 files changed, 6 insertions(+), 445 deletions(-) delete mode 100644 features/media-import.feature delete mode 100644 features/media-regenerate.feature diff --git a/features/command.feature b/features/command.feature index f71917f55..d22a8c5d8 100644 --- a/features/command.feature +++ b/features/command.feature @@ -23,6 +23,12 @@ Feature: WP-CLI Commands wp import <file>... --authors=<authors> """ + When I run `wp media` + Then STDOUT should contain: + """ + or: wp media regenerate + """ + Scenario: Invalid class is specified for a command Given an empty directory And a custom-cmd.php file: diff --git a/features/media-import.feature b/features/media-import.feature deleted file mode 100644 index 058a31733..000000000 --- a/features/media-import.feature +++ /dev/null @@ -1,158 +0,0 @@ -Feature: Manage WordPress attachments - - Background: - Given a WP install - - Scenario: Import image from remote URL - When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1` - Then STDOUT should contain: - """ - Imported file 'http://wp-cli.org/behat-data/codeispoetry.png' - """ - And STDOUT should contain: - """ - Success: Imported 1 of 1 images. - """ - - Scenario: Fail to import missing image - When I try `wp media import gobbledygook.png` - Then STDERR should be: - """ - Warning: Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. - Error: No images imported. - """ - And the return code should be 1 - - Scenario: Fail to import missing image on Windows - When I try `wp media import c:/path/gobbledygook.png` - Then STDERR should be: - """ - Warning: Unable to import file 'c:/path/gobbledygook.png'. Reason: File doesn't exist. - Error: No images imported. - """ - And the return code should be 1 - - Scenario: Import a file as attachment from a local image - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1 --featured_image` - Then STDOUT should contain: - """ - Imported file - """ - And STDOUT should contain: - """ - and attached to post 1 as featured image - """ - And the {CACHE_DIR}/large-image.jpg file should exist - And the return code should be 0 - - Scenario: Import a file as an attachment but porcelain style - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --caption="My fabulous caption" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - - When I run `wp post get {ATTACHMENT_ID} --field=title` - Then STDOUT should be: - """ - My imported attachment - """ - - When I run `wp post get {ATTACHMENT_ID} --field=excerpt` - Then STDOUT should be: - """ - My fabulous caption - """ - - Scenario: Import a file and use its filename as the title - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - - When I run `wp post get {ATTACHMENT_ID} --field=title` - Then STDOUT should be: - """ - large-image - """ - - Scenario: Import a file and persist its original metadata - Given download: - | path | url | - | {CACHE_DIR}/canola.jpg | http://wp-cli.org/behat-data/canola.jpg | - - When I run `wp media import {CACHE_DIR}/canola.jpg --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - - When I run `wp post get {ATTACHMENT_ID} --field=title` - Then STDOUT should be: - """ - A field of amazing canola - """ - - When I run `wp post get {ATTACHMENT_ID} --field=excerpt` - Then STDOUT should be: - """ - The description for the image - """ - - Scenario: Make sure WordPress receives the slashed data it expects - When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' --post_id=1 --title='My\Title' --caption='Caption\Here' --alt='Alt\Here' --desc='Desc\Here' --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - - When I run `wp post get {ATTACHMENT_ID} --format=csv --fields=post_title,post_excerpt,post_content` - Then STDOUT should contain: - """ - post_content,"Desc\Here" - post_title,"My\Title" - post_excerpt,"Caption\Here" - """ - - When I run `wp post meta get {ATTACHMENT_ID} _wp_attachment_image_alt` - Then STDOUT should be: - """ - Alt\Here - """ - - Scenario: Import multiple images - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import 'http://wp-cli.org/behat-data/codeispoetry.png' {CACHE_DIR}/large-image.jpg` - Then STDOUT should contain: - """ - Success: Imported 2 of 2 images. - """ - - Scenario: Fail to import one image but continue trying the next - When I try `wp media import gobbledygook.png 'http://wp-cli.org/behat-data/codeispoetry.png'` - Then STDERR should contain: - """ - Error: Only imported 1 of 2 images. - """ - And the return code should be 1 - - Scenario: Fail when download_url() fails - When I try `wp media import 'http://wp-cli.org/404'` - Then STDERR should be: - """ - Warning: Unable to import file 'http://wp-cli.org/404'. Reason: Not Found - Error: No images imported. - """ - And the return code should be 1 - - Scenario: Return a non-zero exit code when encountering an error in --porcelain mode - When I try `wp media import gobbledygook.png --porcelain` - Then STDERR should contain: - """ - Warning: Unable to import file 'gobbledygook.png'. Reason: File doesn't exist. - """ - And the return code should be 1 diff --git a/features/media-regenerate.feature b/features/media-regenerate.feature deleted file mode 100644 index 6b14ff606..000000000 --- a/features/media-regenerate.feature +++ /dev/null @@ -1,287 +0,0 @@ -Feature: Regenerate WordPress attachments - - Background: - Given a WP install - - Scenario: Regenerate all images while none exists - When I try `wp media regenerate --yes` - Then STDERR should contain: - """ - No images found. - """ - - Scenario: Delete existing thumbnails when media is regenerated - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - Given a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 200, 200, true ); - }); - """ - When I run `wp media regenerate --yes` - Then STDOUT should contain: - """ - Success: Regenerated 1 of 1 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should not exist - And the wp-content/uploads/large-image-200x200.jpg file should exist - - Scenario: Skip deletion of existing thumbnails when media is regenerated - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - Given a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 200, 200, true ); - }); - """ - When I run `wp media regenerate --skip-delete --yes` - Then STDOUT should contain: - """ - Success: Regenerated 1 of 1 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should exist - And the wp-content/uploads/large-image-200x200.jpg file should exist - - @require-wp-4.7.1 - Scenario: Delete existing thumbnails when media including PDF is regenerated - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - | {CACHE_DIR}/minimal-us-letter.pdf | http://wp-cli.org/behat-data/minimal-us-letter.pdf | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - add_filter( 'fallback_intermediate_image_sizes', function( $fallback_sizes ){ - $fallback_sizes[] = 'test1'; - return $fallback_sizes; - }); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - When I run `wp media import {CACHE_DIR}/minimal-us-letter.pdf --title="My imported PDF attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID2} - And the wp-content/uploads/minimal-us-letter-125x125.jpg file should exist - - Given a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 200, 200, true ); - add_filter( 'fallback_intermediate_image_sizes', function( $fallback_sizes ){ - $fallback_sizes[] = 'test1'; - return $fallback_sizes; - }); - }); - """ - When I run `wp media regenerate --yes` - Then STDOUT should contain: - """ - Success: Regenerated 2 of 2 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should not exist - And the wp-content/uploads/large-image-200x200.jpg file should exist - And the wp-content/uploads/minimal-us-letter-125x125.jpg file should not exist - And the wp-content/uploads/minimal-us-letter-200x200.jpg file should exist - - @require-wp-4.7.1 - Scenario: Skip deletion of existing thumbnails when media including PDF is regenerated - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - | {CACHE_DIR}/minimal-us-letter.pdf | http://wp-cli.org/behat-data/minimal-us-letter.pdf | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - add_filter( 'fallback_intermediate_image_sizes', function( $fallback_sizes ){ - $fallback_sizes[] = 'test1'; - return $fallback_sizes; - }); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - When I run `wp media import {CACHE_DIR}/minimal-us-letter.pdf --title="My imported PDF attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID2} - And the wp-content/uploads/minimal-us-letter-125x125.jpg file should exist - - Given a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 200, 200, true ); - add_filter( 'fallback_intermediate_image_sizes', function( $fallback_sizes ){ - $fallback_sizes[] = 'test1'; - return $fallback_sizes; - }); - }); - """ - When I run `wp media regenerate --skip-delete --yes` - Then STDOUT should contain: - """ - Success: Regenerated 2 of 2 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should exist - And the wp-content/uploads/large-image-200x200.jpg file should exist - And the wp-content/uploads/minimal-us-letter-125x125.jpg file should exist - And the wp-content/uploads/minimal-us-letter-200x200.jpg file should exist - - Scenario: Provide helpful error messages when media can't be regenerated - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - When I run `rm wp-content/uploads/large-image.jpg` - Then STDOUT should be empty - - When I try `wp media regenerate --yes` - Then STDERR should be: - """ - Warning: Can't find "My imported attachment" (ID {ATTACHMENT_ID}). - Error: No images regenerated. - """ - - Scenario: Only regenerate images which are missing sizes - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - }); - """ - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should exist - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My second imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID2} - - When I run `rm wp-content/uploads/large-image-125x125.jpg` - Then the wp-content/uploads/large-image-125x125.jpg file should not exist - - When I run `wp media regenerate --only-missing --yes` - Then STDOUT should contain: - """ - Found 2 images to regenerate. - """ - And STDOUT should contain: - """ - 1/2 No thumbnail regeneration needed for "My second imported attachment" - """ - And STDOUT should contain: - """ - 2/2 Regenerated thumbnails for "My imported attachment" - """ - And STDOUT should contain: - """ - Success: Regenerated 2 of 2 images - """ - - Scenario: Regenerate images which are missing globally-defined image sizes - Given download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - And I run `wp option update uploads_use_yearmonth_folders 0` - - When I run `wp media import {CACHE_DIR}/large-image.jpg --title="My imported attachment" --porcelain` - Then save STDOUT as {ATTACHMENT_ID} - And the wp-content/uploads/large-image-125x125.jpg file should not exist - - Given a wp-content/mu-plugins/media-settings.php file: - """ - <?php - add_action( 'after_setup_theme', function(){ - add_image_size( 'test1', 125, 125, true ); - }); - """ - - When I run `wp media regenerate --only-missing --yes` - Then STDOUT should contain: - """ - Found 1 image to regenerate. - """ - And STDOUT should contain: - """ - 1/1 Regenerated thumbnails for "My imported attachment" - """ - And STDOUT should contain: - """ - Success: Regenerated 1 of 1 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should exist - - When I run `wp media regenerate --only-missing --yes` - Then STDOUT should contain: - """ - Found 1 image to regenerate - """ - And STDOUT should contain: - """ - 1/1 No thumbnail regeneration needed for "My imported attachment" - """ - And STDOUT should contain: - """ - Success: Regenerated 1 of 1 images. - """ - And the wp-content/uploads/large-image-125x125.jpg file should exist From 8a554329e1791817022f0f1f6b4611913cc79c8a Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 8 Mar 2017 05:48:25 -0800 Subject: [PATCH 5334/5359] Clarify that `WP_CLI::runcommand()` launches a new process by default --- php/class-wp-cli.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index e2696d75c..f9b7bcab5 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -950,9 +950,10 @@ public static function get_config( $key = null ) { /** * Run a WP-CLI command. * - * Launch a new child process, or run the command in the current process. + * Launches a new child process to run a specified WP-CLI command. * Optionally: * + * * Run the command in an existing process. * * Prevent halting script execution on error. * * Capture and return STDOUT, or full details about command execution. * * Parse JSON output if the command rendered it. From 3c029bb2ab39b6ae175e0ff174aa261448867ad7 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 8 Mar 2017 16:52:29 -0800 Subject: [PATCH 5335/5359] Remove WP-CLI files unrelated to `wp export` --- .editorconfig | 23 - .gitattributes | 2 - .github/ISSUE_TEMPLATE | 15 - .gitignore | 10 - .mailmap | 234 -- .travis.yml | 44 - CONTRIBUTING.md | 43 - LICENSE | 21 - README.md | 193 -- VERSION | 1 - bin/wp | 45 - bin/wp.bat | 2 - ci/behat-tags.php | 46 - ci/deploy.sh | 47 - ci/prepare-codesniffer.sh | 6 - ci/prepare.sh | 39 - ci/ruleset.xml | 17 - ci/test.sh | 14 - composer.json | 52 - composer.lock | 2257 ------------------ features/aliases.feature | 303 --- features/bootstrap/FeatureContext.php | 345 --- features/bootstrap/support.php | 194 -- features/cache.feature | 134 -- features/cap.feature | 73 - features/cli-bash-completion.feature | 299 --- features/cli-info.feature | 25 - features/cli.feature | 180 -- features/command.feature | 697 ------ features/comment-generate.feature | 36 - features/comment-list.feature | 31 - features/comment-meta.feature | 56 - features/comment-recount.feature | 25 - features/comment.feature | 288 --- features/config.feature | 536 ----- features/core-check-update.feature | 56 - features/core-config.feature | 99 - features/core-download.feature | 227 -- features/core-install.feature | 186 -- features/core-language.feature | 177 -- features/core-update-db.feature | 128 - features/core-update.feature | 236 -- features/core-verify-checksums.feature | 102 - features/core-version.feature | 39 - features/core.feature | 370 --- features/eval.feature | 57 - features/extra/no-mail.php | 7 - features/flags.feature | 237 -- features/formatter.feature | 112 - features/framework.feature | 254 -- features/help.feature | 226 -- features/menu-item.feature | 134 -- features/menu-location.feature | 56 - features/menu.feature | 78 - features/network-meta.feature | 17 - features/option-list.feature | 66 - features/option.feature | 203 -- features/package-install.feature | 537 ----- features/package-update.feature | 109 - features/package.feature | 58 - features/plugin-activate.feature | 35 - features/plugin-deactivate.feature | 36 - features/plugin-delete.feature | 25 - features/plugin-install.feature | 143 -- features/plugin-search.feature | 14 - features/plugin-toggle.feature | 42 - features/plugin-uninstall.feature | 37 - features/plugin-update.feature | 35 - features/plugin.feature | 476 ---- features/post-generate.feature | 44 - features/post-meta.feature | 141 -- features/post-term.feature | 105 - features/post-type.feature | 24 - features/post.feature | 233 -- features/rewrite.feature | 103 - features/roles.feature | 140 -- features/runcommand.feature | 255 -- features/scaffold-plugin-tests.feature | 110 - features/scaffold-theme-tests.feature | 90 - features/scaffold.feature | 455 ---- features/search-replace-export.feature | 195 -- features/search-replace.feature | 337 --- features/server.feature | 16 - features/shell.feature | 42 - features/sidebar.feature | 24 - features/site-create.feature | 46 - features/site-empty.feature | 70 - features/site-option.feature | 153 -- features/site.feature | 305 --- features/skip-plugins.feature | 105 - features/skip-themes.feature | 152 -- features/steps/given.php | 164 -- features/steps/then.php | 210 -- features/steps/when.php | 54 - features/super-admin.feature | 77 - features/taxonomy.feature | 31 - features/term-generate.feature | 31 - features/term-meta.feature | 35 - features/term-recount.feature | 54 - features/term.feature | 177 -- features/theme-delete.feature | 29 - features/theme-install.feature | 73 - features/theme-mod.feature | 69 - features/theme.feature | 372 --- features/transient.feature | 85 - features/upgradables.feature | 187 -- features/user-generate.feature | 35 - features/user-import-csv.feature | 134 -- features/user-list.feature | 28 - features/user-meta.feature | 77 - features/user-session.feature | 40 - features/user-term.feature | 115 - features/user.feature | 308 --- features/validation.feature | 48 - features/widget-reset.feature | 155 -- features/widget.feature | 176 -- php/WP_CLI/CommandWithDBObject.php | 193 -- php/WP_CLI/CommandWithMeta.php | 273 --- php/WP_CLI/CommandWithTerms.php | 244 -- php/WP_CLI/CommandWithTranslation.php | 474 ---- php/WP_CLI/CommandWithUpgrade.php | 501 ---- php/WP_CLI/Completions.php | 162 -- php/WP_CLI/ComposerIO.php | 39 - php/WP_CLI/Configurator.php | 333 --- php/WP_CLI/CoreUpgrader.php | 86 - php/WP_CLI/DestructivePluginUpgrader.php | 18 - php/WP_CLI/DestructiveThemeUpgrader.php | 18 - php/WP_CLI/Dispatcher/CommandFactory.php | 114 - php/WP_CLI/Dispatcher/CompositeCommand.php | 300 --- php/WP_CLI/Dispatcher/RootCommand.php | 59 - php/WP_CLI/Dispatcher/Subcommand.php | 398 --- php/WP_CLI/DocParser.php | 190 -- php/WP_CLI/ExitException.php | 5 - php/WP_CLI/Extractor.php | 138 -- php/WP_CLI/Fetchers/Base.php | 56 - php/WP_CLI/Fetchers/Comment.php | 32 - php/WP_CLI/Fetchers/Plugin.php | 33 - php/WP_CLI/Fetchers/Post.php | 25 - php/WP_CLI/Fetchers/Site.php | 45 - php/WP_CLI/Fetchers/Theme.php | 31 - php/WP_CLI/Fetchers/User.php | 33 - php/WP_CLI/FileCache.php | 335 --- php/WP_CLI/Formatter.php | 334 --- php/WP_CLI/Iterators/CSV.php | 76 - php/WP_CLI/Iterators/Exception.php | 6 - php/WP_CLI/Iterators/Query.php | 127 - php/WP_CLI/Iterators/Table.php | 85 - php/WP_CLI/Iterators/Transform.php | 26 - php/WP_CLI/LanguagePackUpgrader.php | 88 - php/WP_CLI/Loggers/Base.php | 73 - php/WP_CLI/Loggers/Execution.php | 84 - php/WP_CLI/Loggers/Quiet.php | 57 - php/WP_CLI/Loggers/Regular.php | 79 - php/WP_CLI/NoOp.php | 18 - php/WP_CLI/NonDestructiveCoreUpgrader.php | 15 - php/WP_CLI/PackageManagerEventSubscriber.php | 52 - php/WP_CLI/Process.php | 75 - php/WP_CLI/ProcessRun.php | 33 - php/WP_CLI/REPL.php | 117 - php/WP_CLI/Runner.php | 1355 ----------- php/WP_CLI/SearchReplacer.php | 102 - php/WP_CLI/SynopsisParser.php | 157 -- php/WP_CLI/SynopsisValidator.php | 163 -- php/WP_CLI/UpgraderSkin.php | 55 - php/WP_CLI/WpHttpCacheManager.php | 129 - php/boot-fs.php | 18 - php/boot-phar.php | 6 - php/class-wp-cli-command.php | 12 - php/class-wp-cli.php | 1142 --------- php/commands/cache.php | 339 --- php/commands/cap.php | 179 -- php/commands/cli.php | 575 ----- php/commands/comment-meta.php | 39 - php/commands/comment.php | 663 ----- php/commands/core-language.php | 40 - php/commands/core.php | 1532 ------------ php/commands/eval-file.php | 45 - php/commands/eval.php | 38 - php/commands/help.php | 171 -- php/commands/menu-item.php | 503 ---- php/commands/menu-location.php | 170 -- php/commands/menu.php | 202 -- php/commands/network.php | 25 - php/commands/option.php | 384 --- php/commands/package.php | 876 ------- php/commands/plugin.php | 993 -------- php/commands/post-meta.php | 39 - php/commands/post-term.php | 26 - php/commands/post-type.php | 173 -- php/commands/post.php | 595 ----- php/commands/rewrite.php | 312 --- php/commands/role.php | 375 --- php/commands/scaffold.php | 987 -------- php/commands/search-replace.php | 468 ---- php/commands/server.php | 104 - php/commands/shell.php | 54 - php/commands/sidebar.php | 86 - php/commands/site-option.php | 296 --- php/commands/site.php | 690 ------ php/commands/super-admin.php | 173 -- php/commands/taxonomy.php | 201 -- php/commands/term-meta.php | 49 - php/commands/term.php | 580 ----- php/commands/theme-mod.php | 202 -- php/commands/theme.php | 776 ------ php/commands/transient.php | 250 -- php/commands/user-meta.php | 213 -- php/commands/user-session.php | 196 -- php/commands/user-term.php | 16 - php/commands/user.php | 951 -------- php/commands/widget.php | 654 ----- php/config-spec.php | 116 - php/dispatcher.php | 20 - php/router.php | 112 - php/utils-wp.php | 358 --- php/utils.php | 838 ------- php/wp-cli.php | 21 - php/wp-settings-cli.php | 439 ---- phpunit.xml.dist | 11 - templates/.editorconfig | 22 - templates/child_theme.mustache | 9 - templates/child_theme_functions.mustache | 12 - templates/install-wp-tests.sh | 127 - templates/man-params.mustache | 18 - templates/man.mustache | 28 - templates/phpcs.ruleset.xml | 10 - templates/phpunit.xml.dist | 14 - templates/plugin-bootstrap.mustache | 25 - templates/plugin-circle.mustache | 19 - templates/plugin-distignore.mustache | 28 - templates/plugin-gitignore.mustache | 6 - templates/plugin-gitlab.mustache | 41 - templates/plugin-gruntfile.mustache | 53 - templates/plugin-packages.mustache | 12 - templates/plugin-readme.mustache | 114 - templates/plugin-status.mustache | 6 - templates/plugin-test-sample.mustache | 20 - templates/plugin-travis.mustache | 47 - templates/plugin.mustache | 13 - templates/post_type.mustache | 29 - templates/post_type_extended.mustache | 32 - templates/taxonomy.mustache | 36 - templates/taxonomy_extended.mustache | 6 - templates/theme-bootstrap.mustache | 34 - templates/theme-status.mustache | 5 - templates/theme-test-sample.mustache | 20 - templates/versions.mustache | 4 - templates/wp-config.mustache | 74 - tests/bootstrap.php | 5 - tests/test-arg-validation.php | 64 - tests/test-configurator.php | 65 - tests/test-doc-parser.php | 198 -- tests/test-logging.php | 52 - tests/test-search-replace.php | 86 - tests/test-synopsis.php | 175 -- tests/test-utils.php | 130 - utils/amp-paths.txt | 5 - utils/contrib-list | 30 - utils/convert-docs.php | 27 - utils/find-php | 19 - utils/get-package-require-from-composer.php | 23 - utils/make-phar-spec.php | 30 - utils/make-phar.php | 124 - utils/test-phar-download | 11 - utils/update-phar | 50 - utils/wp-cli-updatedeb.sh | 111 - utils/wp-completion.bash | 23 - 267 files changed, 44722 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .gitattributes delete mode 100644 .github/ISSUE_TEMPLATE delete mode 100644 .gitignore delete mode 100644 .mailmap delete mode 100644 .travis.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 VERSION delete mode 100755 bin/wp delete mode 100755 bin/wp.bat delete mode 100644 ci/behat-tags.php delete mode 100755 ci/deploy.sh delete mode 100755 ci/prepare-codesniffer.sh delete mode 100755 ci/prepare.sh delete mode 100644 ci/ruleset.xml delete mode 100755 ci/test.sh delete mode 100644 composer.json delete mode 100644 composer.lock delete mode 100644 features/aliases.feature delete mode 100644 features/bootstrap/FeatureContext.php delete mode 100644 features/bootstrap/support.php delete mode 100644 features/cache.feature delete mode 100644 features/cap.feature delete mode 100644 features/cli-bash-completion.feature delete mode 100644 features/cli-info.feature delete mode 100644 features/cli.feature delete mode 100644 features/command.feature delete mode 100644 features/comment-generate.feature delete mode 100644 features/comment-list.feature delete mode 100644 features/comment-meta.feature delete mode 100644 features/comment-recount.feature delete mode 100644 features/comment.feature delete mode 100644 features/config.feature delete mode 100644 features/core-check-update.feature delete mode 100644 features/core-config.feature delete mode 100644 features/core-download.feature delete mode 100644 features/core-install.feature delete mode 100644 features/core-language.feature delete mode 100644 features/core-update-db.feature delete mode 100644 features/core-update.feature delete mode 100644 features/core-verify-checksums.feature delete mode 100644 features/core-version.feature delete mode 100644 features/core.feature delete mode 100644 features/eval.feature delete mode 100644 features/extra/no-mail.php delete mode 100644 features/flags.feature delete mode 100644 features/formatter.feature delete mode 100644 features/framework.feature delete mode 100644 features/help.feature delete mode 100644 features/menu-item.feature delete mode 100644 features/menu-location.feature delete mode 100644 features/menu.feature delete mode 100644 features/network-meta.feature delete mode 100644 features/option-list.feature delete mode 100644 features/option.feature delete mode 100644 features/package-install.feature delete mode 100644 features/package-update.feature delete mode 100644 features/package.feature delete mode 100644 features/plugin-activate.feature delete mode 100644 features/plugin-deactivate.feature delete mode 100644 features/plugin-delete.feature delete mode 100644 features/plugin-install.feature delete mode 100644 features/plugin-search.feature delete mode 100644 features/plugin-toggle.feature delete mode 100644 features/plugin-uninstall.feature delete mode 100644 features/plugin-update.feature delete mode 100644 features/plugin.feature delete mode 100644 features/post-generate.feature delete mode 100644 features/post-meta.feature delete mode 100644 features/post-term.feature delete mode 100644 features/post-type.feature delete mode 100644 features/post.feature delete mode 100644 features/rewrite.feature delete mode 100644 features/roles.feature delete mode 100644 features/runcommand.feature delete mode 100644 features/scaffold-plugin-tests.feature delete mode 100644 features/scaffold-theme-tests.feature delete mode 100644 features/scaffold.feature delete mode 100644 features/search-replace-export.feature delete mode 100644 features/search-replace.feature delete mode 100644 features/server.feature delete mode 100644 features/shell.feature delete mode 100644 features/sidebar.feature delete mode 100644 features/site-create.feature delete mode 100644 features/site-empty.feature delete mode 100644 features/site-option.feature delete mode 100644 features/site.feature delete mode 100644 features/skip-plugins.feature delete mode 100644 features/skip-themes.feature delete mode 100644 features/steps/given.php delete mode 100644 features/steps/then.php delete mode 100644 features/steps/when.php delete mode 100644 features/super-admin.feature delete mode 100644 features/taxonomy.feature delete mode 100644 features/term-generate.feature delete mode 100644 features/term-meta.feature delete mode 100644 features/term-recount.feature delete mode 100644 features/term.feature delete mode 100644 features/theme-delete.feature delete mode 100644 features/theme-install.feature delete mode 100644 features/theme-mod.feature delete mode 100644 features/theme.feature delete mode 100644 features/transient.feature delete mode 100644 features/upgradables.feature delete mode 100644 features/user-generate.feature delete mode 100644 features/user-import-csv.feature delete mode 100644 features/user-list.feature delete mode 100644 features/user-meta.feature delete mode 100644 features/user-session.feature delete mode 100644 features/user-term.feature delete mode 100644 features/user.feature delete mode 100644 features/validation.feature delete mode 100644 features/widget-reset.feature delete mode 100644 features/widget.feature delete mode 100644 php/WP_CLI/CommandWithDBObject.php delete mode 100644 php/WP_CLI/CommandWithMeta.php delete mode 100644 php/WP_CLI/CommandWithTerms.php delete mode 100644 php/WP_CLI/CommandWithTranslation.php delete mode 100755 php/WP_CLI/CommandWithUpgrade.php delete mode 100644 php/WP_CLI/Completions.php delete mode 100644 php/WP_CLI/ComposerIO.php delete mode 100644 php/WP_CLI/Configurator.php delete mode 100644 php/WP_CLI/CoreUpgrader.php delete mode 100644 php/WP_CLI/DestructivePluginUpgrader.php delete mode 100644 php/WP_CLI/DestructiveThemeUpgrader.php delete mode 100644 php/WP_CLI/Dispatcher/CommandFactory.php delete mode 100644 php/WP_CLI/Dispatcher/CompositeCommand.php delete mode 100644 php/WP_CLI/Dispatcher/RootCommand.php delete mode 100644 php/WP_CLI/Dispatcher/Subcommand.php delete mode 100644 php/WP_CLI/DocParser.php delete mode 100644 php/WP_CLI/ExitException.php delete mode 100644 php/WP_CLI/Extractor.php delete mode 100644 php/WP_CLI/Fetchers/Base.php delete mode 100644 php/WP_CLI/Fetchers/Comment.php delete mode 100644 php/WP_CLI/Fetchers/Plugin.php delete mode 100644 php/WP_CLI/Fetchers/Post.php delete mode 100644 php/WP_CLI/Fetchers/Site.php delete mode 100644 php/WP_CLI/Fetchers/Theme.php delete mode 100644 php/WP_CLI/Fetchers/User.php delete mode 100644 php/WP_CLI/FileCache.php delete mode 100644 php/WP_CLI/Formatter.php delete mode 100644 php/WP_CLI/Iterators/CSV.php delete mode 100644 php/WP_CLI/Iterators/Exception.php delete mode 100644 php/WP_CLI/Iterators/Query.php delete mode 100644 php/WP_CLI/Iterators/Table.php delete mode 100644 php/WP_CLI/Iterators/Transform.php delete mode 100644 php/WP_CLI/LanguagePackUpgrader.php delete mode 100644 php/WP_CLI/Loggers/Base.php delete mode 100644 php/WP_CLI/Loggers/Execution.php delete mode 100644 php/WP_CLI/Loggers/Quiet.php delete mode 100644 php/WP_CLI/Loggers/Regular.php delete mode 100644 php/WP_CLI/NoOp.php delete mode 100644 php/WP_CLI/NonDestructiveCoreUpgrader.php delete mode 100644 php/WP_CLI/PackageManagerEventSubscriber.php delete mode 100644 php/WP_CLI/Process.php delete mode 100644 php/WP_CLI/ProcessRun.php delete mode 100644 php/WP_CLI/REPL.php delete mode 100644 php/WP_CLI/Runner.php delete mode 100644 php/WP_CLI/SearchReplacer.php delete mode 100644 php/WP_CLI/SynopsisParser.php delete mode 100644 php/WP_CLI/SynopsisValidator.php delete mode 100644 php/WP_CLI/UpgraderSkin.php delete mode 100644 php/WP_CLI/WpHttpCacheManager.php delete mode 100644 php/boot-fs.php delete mode 100644 php/boot-phar.php delete mode 100644 php/class-wp-cli-command.php delete mode 100644 php/class-wp-cli.php delete mode 100644 php/commands/cache.php delete mode 100644 php/commands/cap.php delete mode 100644 php/commands/cli.php delete mode 100644 php/commands/comment-meta.php delete mode 100644 php/commands/comment.php delete mode 100644 php/commands/core-language.php delete mode 100644 php/commands/core.php delete mode 100644 php/commands/eval-file.php delete mode 100644 php/commands/eval.php delete mode 100644 php/commands/help.php delete mode 100644 php/commands/menu-item.php delete mode 100644 php/commands/menu-location.php delete mode 100644 php/commands/menu.php delete mode 100644 php/commands/network.php delete mode 100644 php/commands/option.php delete mode 100644 php/commands/package.php delete mode 100644 php/commands/plugin.php delete mode 100644 php/commands/post-meta.php delete mode 100644 php/commands/post-term.php delete mode 100644 php/commands/post-type.php delete mode 100644 php/commands/post.php delete mode 100644 php/commands/rewrite.php delete mode 100644 php/commands/role.php delete mode 100644 php/commands/scaffold.php delete mode 100644 php/commands/search-replace.php delete mode 100644 php/commands/server.php delete mode 100644 php/commands/shell.php delete mode 100644 php/commands/sidebar.php delete mode 100644 php/commands/site-option.php delete mode 100644 php/commands/site.php delete mode 100644 php/commands/super-admin.php delete mode 100644 php/commands/taxonomy.php delete mode 100644 php/commands/term-meta.php delete mode 100644 php/commands/term.php delete mode 100644 php/commands/theme-mod.php delete mode 100644 php/commands/theme.php delete mode 100644 php/commands/transient.php delete mode 100644 php/commands/user-meta.php delete mode 100644 php/commands/user-session.php delete mode 100644 php/commands/user-term.php delete mode 100644 php/commands/user.php delete mode 100644 php/commands/widget.php delete mode 100644 php/config-spec.php delete mode 100644 php/dispatcher.php delete mode 100644 php/router.php delete mode 100644 php/utils-wp.php delete mode 100644 php/utils.php delete mode 100644 php/wp-cli.php delete mode 100644 php/wp-settings-cli.php delete mode 100644 phpunit.xml.dist delete mode 100644 templates/.editorconfig delete mode 100644 templates/child_theme.mustache delete mode 100644 templates/child_theme_functions.mustache delete mode 100644 templates/install-wp-tests.sh delete mode 100644 templates/man-params.mustache delete mode 100644 templates/man.mustache delete mode 100644 templates/phpcs.ruleset.xml delete mode 100644 templates/phpunit.xml.dist delete mode 100644 templates/plugin-bootstrap.mustache delete mode 100644 templates/plugin-circle.mustache delete mode 100644 templates/plugin-distignore.mustache delete mode 100644 templates/plugin-gitignore.mustache delete mode 100644 templates/plugin-gitlab.mustache delete mode 100644 templates/plugin-gruntfile.mustache delete mode 100644 templates/plugin-packages.mustache delete mode 100644 templates/plugin-readme.mustache delete mode 100644 templates/plugin-status.mustache delete mode 100644 templates/plugin-test-sample.mustache delete mode 100644 templates/plugin-travis.mustache delete mode 100644 templates/plugin.mustache delete mode 100644 templates/post_type.mustache delete mode 100644 templates/post_type_extended.mustache delete mode 100644 templates/taxonomy.mustache delete mode 100644 templates/taxonomy_extended.mustache delete mode 100644 templates/theme-bootstrap.mustache delete mode 100644 templates/theme-status.mustache delete mode 100644 templates/theme-test-sample.mustache delete mode 100644 templates/versions.mustache delete mode 100644 templates/wp-config.mustache delete mode 100644 tests/bootstrap.php delete mode 100644 tests/test-arg-validation.php delete mode 100644 tests/test-configurator.php delete mode 100644 tests/test-doc-parser.php delete mode 100644 tests/test-logging.php delete mode 100644 tests/test-search-replace.php delete mode 100644 tests/test-synopsis.php delete mode 100644 tests/test-utils.php delete mode 100644 utils/amp-paths.txt delete mode 100755 utils/contrib-list delete mode 100644 utils/convert-docs.php delete mode 100755 utils/find-php delete mode 100644 utils/get-package-require-from-composer.php delete mode 100644 utils/make-phar-spec.php delete mode 100644 utils/make-phar.php delete mode 100755 utils/test-phar-download delete mode 100755 utils/update-phar delete mode 100755 utils/wp-cli-updatedeb.sh delete mode 100644 utils/wp-completion.bash diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 8ccb6afe7..000000000 --- a/.editorconfig +++ /dev/null @@ -1,23 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org - -# WordPress Coding Standards -# http://make.wordpress.org/core/handbook/coding-standards/ - -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_style = tab -indent_size = 4 - -[*.{json,yml,feature}] -indent_style = space -indent_size = 2 - -[composer.json] -indent_style = space -indent_size = 4 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index a5666637c..000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform EOL normalization -* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index af2e2f4bf..000000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,15 +0,0 @@ -<!-- - -Thanks for taking the time to help improve WP-CLI! - -Found a bug or want to suggest an enhancement to an existing command? Before creating an issue, please review our best practices: http://wp-cli.org/docs/bug-reports/ - -But first, make sure you're running the most recent version of WP-CLI! The current version is the only officially supported version. - -Need help with something? Github issues aren't for general support questions, but there are other venues you can try: http://wp-cli.org/#support - -Want to suggest a feature? Check out the roadmap for how feature development happens: https://wp-cli.org/docs/roadmap/ - -You can safely delete this comment. - ---> diff --git a/.gitignore b/.gitignore deleted file mode 100644 index bf98b40a3..000000000 --- a/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store -config.yml -PHAR_BUILD_VERSION -/cache -/packages -/vendor -/*.phar -/phpunit.xml.dist -/codesniffer -/PHP_Codesniffer-VariableAnalysis diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 5c94560fc..000000000 --- a/.mailmap +++ /dev/null @@ -1,234 +0,0 @@ -2ndkauboy <bernhard@kau-boys.de> -Akeda Bagus <admin@gedex.web.id> -Alex Mills <git@viper007bond.com> -Anant Shrivastava <anant@anantshri.info> -Andreas Heigl <andreas@heigl.org> -andreascreten <andreas@madewithlove.be> -Andrew Patton <andrew@acusti.ca> -andyexeter <palmer.andy@gmail.com> -BA <kau@connecticum.de> -bartaakos <akos@netpositive.hu> -bendoh <ben@thinkoomph.com> -Bernhard Kau <github@kau-boys.de> -Bobby Walters <bobbymwalters@gmail.com> -BoiteAWeb <juliobosk@gmail.com> -boonebgorges <boonebgorges@gmail.com> -Borek Bernard <borekb@gmail.com> -borekb <borekb@gmail.com> -Brad Parbs <brad@bradparbs.com> -Brandon Kraft <public@brandonkraft.com> -Brian MacKinney <brian@getpantheon.com> -builtbylane <lanegoldberg@gmail.com> -c10b10 <alex.ciobica@gmail.com> -c10b10 <alex.ciobica@gmail.com> -Chris Montgomery <chris@montchr.io> -clemens-tolboom <clemens@build2be.com> -conatus <alex@recordsonribs.com> -Corey Worrell <proskater55@gmail.com> -ctayloroomphinc <ctaylor@thinkoomph.com> -cyberhobo <dylan.k.kuhn@gmail.com> -daithi-coombes <webeire@gmail.com> -dangardner <dan@web.nearest.to> -Daniel Bachhuber <daniel.bachhuber@fusion.net> -danielbachhuber <d@danielbachhuber.com> -danielbachhuber <daniel@handbuilt.co> -danielbachhuber <danielbachhuber@gmail.com> -Dave Leach <dave@dmleach.com> -dd32 <contact-atlassian@dd32.id.au> -dlh01 <david@alleyinteractive.com> -drrobotnik <B@Brandons-Mac-Pro-4.local> -Duncan Brown <duncanjbrown@gmail.com> -dwightjack <marco.solazzi@gmail.com> -Eduardo Alencar <ealencar10@gmail.com> -eliorivero <eliorivero@gmail.com> -Enrico Sorcinelli <enrico.sorcinelli@italiaonline.it> -ericandrewlewis <eric.andrew.lewis@gmail.com> -ericmann <eric@eamann.com> -ernilambar <nilambar@outlook.com> -erwanlr <erwan.lr@gmail.com> -eugeneware <eugene@noblesamurai.com> -Evan Mattson <me@aaemnnost.tv> -Fabian Isele <uxdmm@student.kit.edu> -francescolaffi <francesco.laffi@gmail.com> -Frank Staude <frank@staude.net> -Frankie Jarrett <fjarrett@godaddy.com> -future500 <ramon@future500.nl> -Gary Jones <gamajo@gamajo.com> -Geo <geo.artemenko@gmail.com> -getsource <mike.schroder@dreamhost.com> -Gilbert Pellegrom <gilbert@pellegrom.me> -glebis <glebis@gmail.com> -goldenapples <goldenapplesdesign@gmail.com> -goldenapples <ntaintor@janrain.com> -Grant McInnes <grant.mcinnes@eyesopen.ca> -Greg Anderson <greg.1.anderson@greenknowe.org> -hideokamoto <kokkoku214@gmail.com> -Hidetaka Okamoto <kokkoku214@gmail.com> -hina <hina@hinaloe.net> -hinoue-work <wpuser@wp-cli-14.04> -Hiroshi Urabe <mail@torounit.com> -Ian Dunn <ian@iandunn.name> -itsananderson <will@itsananderson.com> -j3lamp <j3lamp@gmail.com> -jacobischwartz <jacob@schwambell.com> -Jakub Juszczak <netghost03@gmail.com> -Jan VoráÄek <jan@voracek.net> -Japh <japhie@gmail.com> -Jeff Gould <jrgould@gmail.com> -jeichorn <joshua.eichorn@pagely.com> -Jeremy Pry <jeremy.pry@gmail.com> -jghazally <jeff@bigfish.co.uk> -jghazally <jghazally@gmail.com> -Jim Reevior <jim@thinkoomph.com> -jmslbam <jmslbam@gmail.com> -John Blackbourn <john@johnblackbourn.com> -johnbillion <johnbillion@gmail.com> -johnpbloch <jbloch@John-Blochs-iMac.local> -johnpbloch <johnpbloch@gmail.com> -jonathanbardo <jonathanbardo@users.noreply.github.com> -Jorge A. Torres <j@jorgetorres.co> -Josh Eaton <josh@josheaton.org> -joshbetz <j@joshbetz.com> -joshlevinson <joshalevinson@gmail.com> -joshstoik1 <joshstoik@gmail.com> -Joshua Priddle <jpriddle@me.com> -JQ <JeyKeu@users.noreply.github.com> -jtsternberg <me@jtsternberg.com> -KDoole <dev@Kevins-iMac.local> -Keanan Koppenhaver <keanan@doejo.com> -Keith Grennan <keith@nearlyfree.org> -Kevin Doole <kdoole@farmmedia.com> -Kevinlearynet <info@kevinleary.net> -kidfiction <ejdanderson@gmail.com> -lackingpenguin <benjamin.j.brooks@gmail.com> -leewillis77 <leewillis77@gmail.com> -lkwdwrd <woodward.lucas@gmail.com> -Marc Addeo <marcaddeo@gmail.com> -Marco <mcastelluccio@mozilla.com> -marcoceppi <marco@ceppi.net> -Mark Jaquith <mark.github@txfx.net> -Mark Kimsal <metrofindings@gmail.com> -Mark McEver <mark@fastmail.net> -matiskay <matiskay@gmail.com> -mattes <matthias.kadenbach@gmail.com> -mattheu <matthew@matth.eu> -MattiaG <bots@mattiaghedin.it> -mbovel <matthieu@bovel.net> -mboynes <mboynes@alleyinteractive.com> -mgburns <mgburns@bu.edu> -mgburns <mike@grady-etc.com> -Mihail Minkov <Mihail.Minkov.BG@gmail.com> -Mike Pretzlaw <pretzlaw@gmail.com> -mikey dubs <mike@herebox.org> -milesj <mileswjohnson@gmail.com> -MiteshShah <Mitesh.Shah@rtCamp.com> -miya0001 <miya@wpist.me> -Morgan Estes <morgan.estes@gmail.com> -mpeshev <mario@peshev.net> -mwilliamson <michael.williamson@red-gate.com> -mwilliamson <mike@zwobble.org> -mwithheld <vhmark@gmail.com> -nacin <andrewnacin@gmail.com> -Nate Wright <natew@notthisway.com> -navitronic <adrian@navitronic.co.uk> -nb <nb@nikolay.bg> -Ned Zimmerman <ned@bight.ca> -nickdaugherty <ndaugherty987@gmail.com> -nikhilc@bsf.io <nikhilc@bsf.io> -nikolay <nikolay@users.noreply.github.com> -nikolay <nikolaynkolev@gmail.com> -Nilambar Sharma <ernilambar@users.noreply.github.com> -Nilambar Sharma <nilambar@outlook.com> -nschoenholtz <noah@alleyinteractive.com> -nullvariable <nullvariable@gmail.com> -nyordanov <me@nyordanov.com> -ocean90 <dominikschilling+git@gmail.com> -oknoway <nate@oknoway.com> -om4james <james@jamesc.id.au> -om4james <james@om4.com.au> -oneumyvakin <oneumyvakin@gmail.com> -Otto Kekäläinen <otto@seravo.fi> -ozh <ozh@ozh.org> -Patrick Karjala <pkarjala@gmail.com> -Pete Nelson <pete@petenelson.com> -pete@petenelson.com <petenelson@fortress.local> -Peter J. Herrel <peterherrel@gmail.com> -phh <phh@peytz.dk> -Pippin Williamson <pippin@pippinsplugins.com> -QWp6t <QWp6t+github@xpdnc.org> -Rachel Baker <rachel@rachelbaker.me> -Radu Dan <za_creature@yahoo.com> -Rahul Prajapati <rahul.prajapati@rtcamp.com> -Rarst <contact@rarst.net> -robertboloc <robertboloc@gmail.com> -Robin Schneider <ypid@riseup.net> -rodrigoprimo <rodrigo@hacklab.com.br> -rodrigoprimo <rodrigosprimo@gmail.com> -Roel Veldhuizen <roel@inesta.nl> -roelveldhuizen <roel@inesta.nl> -roelven <roel@soundcloud.com> -Ross Hattori <rhattori@saymedia.com> -Ryan Hoover <ryanshoover@gmail.com> -Ryan McCue <me@ryanmccue.info> -Ryan Williams <ryrowi@gmail.com> -ryanduff <ryan@fusionized.com> -santagada <santagada@gmail.com> -sboisvert <stephane.boisvert@automattic.com> -scribu <mail@scribu.net> -scribu <scribu@gmail.com> -sebastiaandegeus <sebastiaan@hoppinger.com> -Shinichi Nishikawa <shinichi.nishikawa@gmail.com> -sibprogrammer <ayuzhakov@parallels.com> -simonwheatley <simonw@codeforthepeople.com> -smhmic <smhmic@gmail.com> -soulou <leo@soulou.fr> -spacedmonkey <spacedmonkey2@gmail.com> -SpikesDivZero <wesley.spikes@gmail.com> -spuriousdata <spuriousdata@gmail.com> -Stephen Beemsterboer <balbuf@users.noreply.github.com> -Stephen Edgar <stephen@netweb.com.au> -Stephen Harris <contact@stephenharris.info> -Stephen Harris <Stephen.Harris@gov.scot> -Stephen Harris <Stephen.Harris@scotland.gsi.gov.uk> -Steve Grunwell <steve.grunwell@10up.com> -Steve Grunwell <steve@stevegrunwell.com> -Steve Grunwell <stevegrunwell@gmail.com> -Steve Persch <steve.persch@pantheon.io> -Steven K Word <stevenword@gmail.com> -stianlik <stianlik@gmail.com> -Stéphane HULARD <s.hulard@chstudio.fr> -svaj <chris@chrisbot.(none)> -Svetoslav Marinov (Slavi) <slavi@orbisius.com> -szepeviktor <viktor@szepe.net> -taupecat <tracy@taupecat.com> -tddewey <td@tddewey.com> -thisislawatts <luke@thisis.la> -tiagohillebrandt <tiagohillebrandt@ubuntu.com> -tlovett1 <admin@taylorlovett.com> -tolgap <tolga@hoppinger.com> -tollmanz <tollmanz@gmail.com> -tollmanz <zack@zackdev.com> -toszcze <toszcze@gmail.com> -tott <tott@automattic.com> -Travis Northcutt <travis@memberup.co> -trepmal <trepmal@gmail.com> -Tristan Penman <tristan@tristanpenman.com> -twisty <tim@brayshaw.com> -twratajczak <tomasz.ratajczak@espeo.pl> -Utkarsh Patel <iamutkarsh@live.com> -Veered <lucashansne@gmail.com> -veganista <liam@nanothree.net> -Ville Vuorenmaa <villevuor@gmail.com> -voldemortensen <voldemortensen@users.noreply.github.com> -Wendell Júnior <wrnx00@gmail.com> -Wes Moberly <wesm87@gmail.com> -Wes Moberly <wesm87@users.noreply.github.com> -westonruter <weston@x-team.com> -westonruter <westonruter@gmail.com> -William Turrell <william@wturrell.co.uk> -willmot <tom@humanmade.co.uk> -wojsmol <wojsmol@wp.pl> -wopr42 <john@zippykid.com> -yivi <ivan@ojiva.es> -yivi <ivan@yivoff.com> -ziz <justin@crowdfavorite.com> diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 68b224b6f..000000000 --- a/.travis.yml +++ /dev/null @@ -1,44 +0,0 @@ -sudo: false - -language: php - -env: - global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar - -matrix: - include: - - php: 7.1 - env: WP_VERSION=latest - - php: 7.0 - env: WP_VERSION=latest - - php: 5.6 - env: WP_VERSION=trunk - - php: 5.6 - env: WP_VERSION=latest - - php: 5.6 - env: WP_VERSION=latest BUILD=git WP_CLI_BIN_DIR='' - - php: 5.6 - env: WP_VERSION=3.7.11 - - php: 5.3 - env: WP_VERSION=3.7.11 DEPLOY_BRANCH=master - -before_script: ./ci/prepare.sh - -script: ./ci/test.sh - -after_success: ./ci/deploy.sh - -cache: - directories: - - vendor - - $HOME/.composer/cache - -branches: - only: - - master - -notifications: - email: - on_success: never - on_failure: change diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index abdb2c539..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,43 +0,0 @@ -Contributing -============ - -Welcome and thanks! - -We appreciate you taking the initiative to contribute to WP-CLI. It’s because of you, and the community around you, that WP-CLI is such a great project. - -**Contributing isn’t limited to just code.** We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. - -Please take a moment to read these guidelines at depth. Following the guidelines helps to communicate that you respect the time of the other contributors to the project. In turn, they’ll do their best to reciprocate that respect when working with you, across timezones and around the world. - -### Reporting a bug - -Think you’ve found a bug? We’d love for you to help us get it fixed. - -Before you create a new issue, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. You should also check our [documentation on common issues and their fixes](https://wp-cli.org/docs/common-issues/). - -Once you’ve done a bit of searching and discovered there isn’t an open or fixed issue for your bug, please [follow our guidelines for submitting a bug report](http://wp-cli.org/docs/bug-reports/) to make sure it gets addressed in a timely manner. - -### Creating a pull request - -Want to contribute a new feature? WP-CLI is a mature project, and already chock-full of useful functionality. Please first [open a new issue](https://github.com/wp-cli/wp-cli/issues/new) to discuss whether the feature is a good fit for WP-CLI core, or might be better suited as a [community package](https://wp-cli.org/package-index/). - -New to the WP-CLI codebase? Check out [issues labeled 'good-first-issue'](https://github.com/wp-cli/wp-cli/labels/good-first-issue) for a place to start. These issues are specially earmarked for new contributors. - -Once you've decided to commit the time to seeing your pull request through, please [follow our guidelines for creating a pull request](https://wp-cli.org/docs/pull-requests/) to make sure it's a pleasant experience. - -### Improving our documentation - -Is documentation your strength? Take a look at the currently open [documentation issues](https://github.com/wp-cli/wp-cli/issues?q=is%3Aopen+is%3Aissue+label%3Ascope%3Adocumentation) and see if you can tackle any of those. - -If you believe you’ve found an issue with the documentation, you should [search existing issues](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version of WP-CLI. - -There are a couple different types of documentation currently part of WP-CLI: - -* Documentation for individual WP-CLI commands (anything underneath [http://wp-cli.org/commands](http://wp-cli.org/commands)) is contained in the PHPDoc for each command. This means that to edit the documentation for a command, you will need to edit the file that actually provides the functionality for that command. The web documentation is generated from these files at the time of release, so you may not see your changes until the next release. -* Individual documentation pages (anything under [http://wp-cli.org/docs/](http://wp-cli.org/docs/) can be edited by contributing to the [wp-cli.github.com repository on GitHub](https://github.com/wp-cli/wp-cli.github.com). You don't necessarily need to navigate the Github repo though; any page that is part of this repository will have an 'Edit' link in the top right of the page which will take you to the corresponding file on GitHub. - -### Contributing in other ways - -Feel free to [create an issue](https://github.com/wp-cli/wp-cli/issues/new) with your question, and we'll see if we can find an answer for it. - -Alternatively, if you have a WordPress.org account, you may also consider joining the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/). diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e56e9341d..000000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2011-2017 WP-CLI Development Group (https://github.com/wp-cli/wp-cli/contributors) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 5f36b0eb1..000000000 --- a/README.md +++ /dev/null @@ -1,193 +0,0 @@ -WP-CLI -====== - -[WP-CLI](https://wp-cli.org/) is a set of command-line tools for managing [WordPress](https://wordpress.org/) installations. You can update plugins, configure multisite installs and much more, without using a web browser. - -For announcements, follow [@wpcli on Twitter](https://twitter.com/wpcli) or [sign up for email updates](https://make.wordpress.org/cli/subscribe/). [Check out the roadmap](https://wp-cli.org/docs/roadmap/) for an overview of what's planned for upcoming releases. - -[![Build Status](https://travis-ci.org/wp-cli/wp-cli.svg?branch=master)](https://travis-ci.org/wp-cli/wp-cli) [![Dependency Status](https://gemnasium.com/badges/github.com/wp-cli/wp-cli.svg)](https://gemnasium.com/github.com/wp-cli/wp-cli) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Average time to resolve an issue") [![Percentage of issues still open](https://isitmaintained.com/badge/open/wp-cli/wp-cli.svg)](https://isitmaintained.com/project/wp-cli/wp-cli "Percentage of issues still open") - -Quick links: [Using](#using) | [Installing](#installing) | [Support](#support) | [Extending](#extending) | [Contributing](#contributing) | [Credits](#credits) - -## Using - -WP-CLI's goal is to provide a command-line interface for any action you might want to perform in the WordPress admin. For instance, `wp plugin install --activate` ([doc](https://wp-cli.org/commands/plugin/install/)) lets you install and activate a WordPress plugin: - -```bash -$ wp plugin install rest-api --activate -Installing WordPress REST API (Version 2) (2.0-beta13) -Downloading install package from https://downloads.wordpress.org/plugin/rest-api.2.0-beta13.zip... -Unpacking the package... -Installing the plugin... -Plugin installed successfully. -Activating 'rest-api'... -Success: Plugin 'rest-api' activated. -``` - -WP-CLI also includes commands for many things you can't do in the WordPress admin. For example, `wp transient delete --all` ([doc](https://wp-cli.org/commands/transient/delete/)) lets you delete one or all transients: - -```bash -$ wp transient delete --all -Success: 34 transients deleted from the database. -``` - -For a more complete introduction to using WP-CLI, read the [Quick Start guide](https://wp-cli.org/docs/quick-start/). Or, catch up with [shell friends](https://wp-cli.org/docs/shell-friends/) to learn about helpful command line utilities. - -Already feel comfortable with the basics? Jump into the [complete list of commands](https://wp-cli.org/commands/) for detailed information on managing themes and plugins, importing and exporting data, performing database search-replace operations and more. - -## Installing - -Downloading the Phar file is our recommended installation method. Should you need, see also our documentation on [alternative installation methods](https://wp-cli.org/docs/installing/). - -Before installing WP-CLI, please make sure your environment meets the minimum requirements: - -- UNIX-like environment (OS X, Linux, FreeBSD, Cygwin); limited support in Windows environment -- PHP 5.3.29 or later -- WordPress 3.7 or later - -Once you've verified requirements, download the [wp-cli.phar](https://raw.github.com/wp-cli/builds/gh-pages/phar/wp-cli.phar) file using `wget` or `curl`: - -```bash -$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -``` - -Next, check if it is working: - -```bash -$ php wp-cli.phar --info -``` - -To use WP-CLI from the command line by typing `wp`, make the file executable and move it to somewhere in your PATH. For example: - -```bash -$ chmod +x wp-cli.phar -$ sudo mv wp-cli.phar /usr/local/bin/wp -``` - -If WP-CLI was installed successfully, you should see something like this when you run `wp --info`: - -```bash -$ wp --info -PHP binary: /usr/bin/php5 -PHP version: 5.5.9-1ubuntu4.14 -php.ini used: /etc/php5/cli/php.ini -WP-CLI root dir: /home/wp-cli/.wp-cli -WP-CLI packages dir: /home/wp-cli/.wp-cli/packages/ -WP-CLI global config: /home/wp-cli/.wp-cli/config.yml -WP-CLI project config: -WP-CLI version: 1.1.0 -``` - -### Updating - -You can update WP-CLI with `wp cli update` ([doc](https://wp-cli.org/commands/cli/update/)), or by repeating the installation steps. - -If WP-CLI is owned by root or another system user, you'll need to run `sudo wp cli update`. - -Want to live life on the edge? Run `wp cli update --nightly` to use the latest nightly build of WP-CLI. The nightly build is more or less stable enough for you to use in your development environment, and always includes the latest and greatest WP-CLI features. - -### Tab completions - -WP-CLI also comes with a tab completion script for Bash and ZSH. Just download [wp-completion.bash](https://raw.githubusercontent.com/wp-cli/wp-cli/master/utils/wp-completion.bash) and source it from `~/.bash_profile`: - -```bash -source /FULL/PATH/TO/wp-completion.bash -``` - -Don't forget to run `source ~/.bash_profile` afterwards. - -If using zsh for your shell, you may need to load and start `bashcompinit` before sourcing. Put the following in your `.zshrc`: - -```bash -autoload bashcompinit -bashcompinit -source /FULL/PATH/TO/wp-completion.bash -``` - -## Support - -WP-CLI's maintainers and project contributors have limited availability to address general support questions. The [current version of WP-CLI](https://wp-cli.org/docs/roadmap/) is the only officially supported version. - -When looking for support, please first look for an answer in one of the following resources: - -- [Common issues and their fixes](https://wp-cli.org/docs/common-issues/) -- [Documentation portal](https://wp-cli.org/docs/) -- [Open or closed issues on Github](https://github.com/wp-cli/wp-cli/issues?utf8=%E2%9C%93&q=is%3Aissue) -- [runcommand tips](https://runcommand.io/tips/) -- [WordPress StackExchange forums](https://wordpress.stackexchange.com/questions/tagged/wp-cli) - -You can also join the `#cli` channel on the [WordPress.org Slack organization](https://make.wordpress.org/chat/) to see if a community member might have an answer for you. - -Github issues are meant for tracking enhancements and bugs of existing commands, not general support. Before submitting a bug report, please [review our best practices](https://wp-cli.org/docs/bug-reports/) to help ensure your issue is addressed in a timely manner. - -Please do not ask support questions on Twitter. Twitter isn't an acceptable venue for support because: 1) it's hard to hold conversations in under 140 characters, and 2) Twitter isn't a place where someone with your same question can search for an answer in a prior conversation. - -Remember, libre != gratis; the open source license grants you the freedom to use and modify, but not commitments of other people's time. Please be respectful, and set your expectations accordingly. - -## Extending - -A **command** is an atomic unit of WP-CLI functionality. `wp plugin install` ([doc](https://wp-cli.org/commands/plugin/install/)) is one command. `wp plugin activate` ([doc](https://wp-cli.org/commands/plugin/activate/)) is another. - -WP-CLI supports registering any callable class, function, or closure as a command. It reads usage details from the callback's PHPdoc. `WP_CLI::add_command()` ([doc](https://wp-cli.org/docs/internal-api/wp-cli-add-command/)) is used for both internal and third-party command registration. - -```php -/** - * Delete an option from the database. - * - * Returns an error if the option didn't exist. - * - * ## OPTIONS - * - * <key> - * : Key for the option. - * - * ## EXAMPLES - * - * $ wp option delete my_option - * Success: Deleted 'my_option' option. - */ -$delete_option_cmd = function( $args ) { - list( $key ) = $args; - - if ( ! delete_option( $key ) ) { - WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); - } else { - WP_CLI::success( "Deleted '$key' option." ); - } -}; -WP_CLI::add_command( 'option delete', $delete_option_cmd ); -``` - -WP-CLI comes with dozens of commands. It's easier than it looks to create a custom WP-CLI command. Read the [commands cookbook](https://wp-cli.org/docs/commands-cookbook/) to learn more. Browse the [internal API docs](https://wp-cli.org/docs/internal-api/) to discover a variety of helpful functions you can use in your custom WP-CLI command. - -## Contributing - -Welcome and thanks! - -We appreciate you taking the initiative to contribute to WP-CLI. It’s because of you, and the community around you, that WP-CLI is such a great project. - -**Contributing isn’t limited to just code.** We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. - -Please take a moment to [read these guidelines at depth](https://wp-cli.org/docs/contributing/). Following them helps to communicate that you respect the time of the other contributors to the project. In turn, they’ll do their best to reciprocate that respect when working with you, across timezones and around the world. - -## Leadership - -WP-CLI is led by these individuals: - -* [Daniel Bachhuber](https://github.com/danielbachhuber/) - current maintainer -* [Cristi Burcă](https://github.com/scribu) - previous maintainer -* [Andreas Creten](https://github.com/andreascreten) - founder - -Read more about the project's [governance](https://wp-cli.org/docs/governance/) and view a [complete list of contributors](https://github.com/wp-cli/wp-cli/contributors). - -## Credits - -Besides the libraries defined in [composer.json](composer.json), we have used code or ideas from the following projects: - -* [Drush](https://github.com/drush-ops/drush) for... a lot of things -* [wpshell](https://code.trac.wordpress.org/browser/wpshell) for `wp shell` -* [Regenerate Thumbnails](https://wordpress.org/plugins/regenerate-thumbnails/) for `wp media regenerate` -* [Search-Replace-DB](https://github.com/interconnectit/Search-Replace-DB) for `wp search-replace` -* [WordPress-CLI-Exporter](https://github.com/Automattic/WordPress-CLI-Exporter) for `wp export` -* [WordPress-CLI-Importer](https://github.com/Automattic/WordPress-CLI-Importer) for `wp import` -* [wordpress-plugin-tests](https://github.com/benbalter/wordpress-plugin-tests/) for `wp scaffold plugin-tests` diff --git a/VERSION b/VERSION deleted file mode 100644 index 8864779ee..000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.2.0-alpha diff --git a/bin/wp b/bin/wp deleted file mode 100755 index 053e24227..000000000 --- a/bin/wp +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env sh -# -# This wrapper script has been adapted from the equivalent drush wrapper -# and 99.9% of all credit should go to the authors of that project: -# http://drupal.org/project/drush -# And 0.09% to the author of this project: -# https://github.com/88mph/wpadmin/blob/master/wpadmin.php - -# Get the absolute path of this executable -ORIGDIR="$(pwd)" -SELF_PATH="$(cd -P -- "$(dirname -- "$0")" && pwd -P)" && SELF_PATH="$SELF_PATH/$(basename -- "$0")" - -# Resolve symlinks - this is the equivalent of "readlink -f", but also works with non-standard OS X readlink. -while [ -h "$SELF_PATH" ]; do - # 1) cd to directory of the symlink - # 2) cd to the directory of where the symlink points - # 3) Get the pwd - # 4) Append the basename - DIR="$(dirname -- "$SELF_PATH")" - SYM="$(readlink "$SELF_PATH")" - SELF_PATH="$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")" -done -cd "$ORIGDIR" - -if [ ! -z "$WP_CLI_PHP" ] ; then - # Use the WP_CLI_PHP environment variable if it is available. - php="$WP_CLI_PHP" -else - # Default to using the php that we find on the PATH. - # Note that we need the full path to php here for Dreamhost, which behaves oddly. See http://drupal.org/node/662926 - php="`which php`" -fi - -# Build the path to the root PHP file -SCRIPT_PATH="$(dirname "$SELF_PATH")/../php/boot-fs.php" -case $("$php" -r "echo PHP_OS;") in - WINNT*) - SCRIPT_PATH="$(cygpath -w -a -- "$SCRIPT_PATH")" ;; -esac - -# Pass in the path to php so that wp-cli knows which one -# to use if it re-launches itself to run other commands. -export WP_CLI_PHP_USED="$php" - -exec "$php" $WP_CLI_PHP_ARGS "$SCRIPT_PATH" "$@" diff --git a/bin/wp.bat b/bin/wp.bat deleted file mode 100755 index 59f953440..000000000 --- a/bin/wp.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -php "%~dp0../php/boot-fs.php" %* \ No newline at end of file diff --git a/ci/behat-tags.php b/ci/behat-tags.php deleted file mode 100644 index 964711458..000000000 --- a/ci/behat-tags.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Generate a list of tags to skip during the test run. - * - * Require a minimum version of WordPress: - * - * @require-wp-4.0 - * Scenario: Core translation CRUD - * - * Then use in bash script: - * - * BEHAT_TAGS=$(php behat-tags.php) - * vendor/bin/behat --format progress $BEHAT_TAGS - */ - -function version_tags( $prefix, $current, $operator = '<' ) { - if ( ! $current ) - return array(); - - exec( "grep '@{$prefix}-[0-9\.]*' -h -o features/*.feature | uniq", $existing_tags ); - - $skip_tags = array(); - - foreach ( $existing_tags as $tag ) { - $compare = str_replace( "@{$prefix}-", '', $tag ); - if ( version_compare( $current, $compare, $operator ) ) { - $skip_tags[] = $tag; - } - } - - return $skip_tags; -} - -$skip_tags = array_merge( - version_tags( 'require-wp', getenv( 'WP_VERSION' ), '<' ), - version_tags( 'require-php', PHP_VERSION, '<' ), - version_tags( 'less-than-php', PHP_VERSION, '>' ) -); - -# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -$skip_tags[] = '@github-api'; - -if ( !empty( $skip_tags ) ) { - echo '--tags=~' . implode( '&&~', $skip_tags ); -} - diff --git a/ci/deploy.sh b/ci/deploy.sh deleted file mode 100755 index 4bc794884..000000000 --- a/ci/deploy.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# called by Travis CI - -if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then - echo "Not deploying pull requests." - exit -fi - -if [[ "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]]; then - echo "Not on the '$DEPLOY_BRANCH' branch." - exit -fi - -# Turn off command traces while dealing with the private key -set +x - -# Get the encrypted private key from the repo settings -echo $WP_CLI_REPO_DEPLOY_KEY | base64 --decode > ~/.ssh/id_rsa -chmod 600 ~/.ssh/id_rsa - -# anyone can read the build log, so it MUST NOT contain any sensitive data -set -x - -# add github's public key -echo "|1|qPmmP7LVZ7Qbpk7AylmkfR0FApQ=|WUy1WS3F4qcr3R5Sc728778goPw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts - -git clone git@github.com:wp-cli/builds.git -mv PHAR_BUILD_VERSION builds/phar/NIGHTLY_VERSION -cd builds - -git config user.name "Travis CI" -git config user.email "travis@travis-ci.org" -git config push.default "current" - -fname="phar/wp-cli-nightly.phar" - -mv /tmp/wp-cli-phar/wp $fname -chmod -x $fname - -md5sum $fname | cut -d ' ' -f 1 > $fname.md5 -sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 - -git add $fname $fname.md5 $fname.sha512 phar/NIGHTLY_VERSION -git commit -m "phar build: $TRAVIS_REPO_SLUG@$TRAVIS_COMMIT" - -git push diff --git a/ci/prepare-codesniffer.sh b/ci/prepare-codesniffer.sh deleted file mode 100755 index a5f5fa874..000000000 --- a/ci/prepare-codesniffer.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -composer create-project squizlabs/php_codesniffer:1.5.0RC4 codesniffer - -git clone https://github.com/illusori/PHP_Codesniffer-VariableAnalysis.git -cd PHP_Codesniffer-VariableAnalysis -./install.sh -d ../codesniffer/CodeSniffer diff --git a/ci/prepare.sh b/ci/prepare.sh deleted file mode 100755 index 8c6be0ef1..000000000 --- a/ci/prepare.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# called by Travis CI - -set -ex - -WP_CLI_BIN_DIR=${WP_CLI_BIN_DIR-/tmp/wp-cli-phar} - -# Disable XDebug to speed up Composer and test suites. -phpenv config-rm xdebug.ini - -composer install --no-interaction --prefer-source - -CLI_VERSION=$(head -n 1 VERSION) -if [[ $CLI_VERSION == *"-alpha"* ]] -then - GIT_HASH=$(git rev-parse HEAD) - GIT_SHORT_HASH=${GIT_HASH:0:7} - CLI_VERSION="$CLI_VERSION-$GIT_SHORT_HASH" -fi - -# the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR -if [[ $BUILD == 'git' ]] -then - echo $CLI_VERSION > VERSION -else - mkdir -p $WP_CLI_BIN_DIR - php -dphar.readonly=0 utils/make-phar.php wp-cli.phar --quiet --version=$CLI_VERSION - mv wp-cli.phar $WP_CLI_BIN_DIR/wp - chmod +x $WP_CLI_BIN_DIR/wp -fi - -echo $CLI_VERSION > PHAR_BUILD_VERSION - -# Install CodeSniffer things -./ci/prepare-codesniffer.sh - -mysql -e 'CREATE DATABASE wp_cli_test;' -uroot -mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot diff --git a/ci/ruleset.xml b/ci/ruleset.xml deleted file mode 100644 index 8208bd2a5..000000000 --- a/ci/ruleset.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0"?> -<ruleset name="WP-CLI"> - <description>WP-CLI coding standards.</description> - - <exclude-pattern>php/Spyc.php</exclude-pattern> - - <rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/> - <rule ref="Generic.Files.EndFileNewline"/> - - <rule ref="Generic.CodeAnalysis.VariableAnalysis"> - <exclude name="Generic.CodeAnalysis.VariableAnalysis.UnusedVariable"/> - - <properties> - <property name="allowUnusedFunctionParameters" value="1"/> - </properties> - </rule> -</ruleset> diff --git a/ci/test.sh b/ci/test.sh deleted file mode 100755 index ce5030ef7..000000000 --- a/ci/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -ex - -# Run the unit tests -vendor/bin/phpunit - -BEHAT_TAGS=$(php ci/behat-tags.php) - -# Run the functional tests -vendor/bin/behat --format progress $BEHAT_TAGS --strict - -# Run CodeSniffer -./codesniffer/scripts/phpcs --standard=./ci/ php/ diff --git a/composer.json b/composer.json deleted file mode 100644 index 35b632f9d..000000000 --- a/composer.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "wp-cli/wp-cli", - "description": "A command line interface for WordPress", - "keywords": [ "cli", "wordpress" ], - "homepage": "http://wp-cli.org", - "license": "MIT", - "support": { - "issues": "https://github.com/wp-cli/wp-cli/issues", - "source": "https://github.com/wp-cli/wp-cli", - "docs": "https://make.wordpress.org/cli/handbook/" - }, - "bin": [ - "bin/wp.bat", "bin/wp" - ], - "require": { - "php": ">=5.3.29", - "wp-cli/php-cli-tools": "~0.11.2", - "mustache/mustache": "~2.4", - "mustangostang/spyc": "~0.5", - "composer/semver": "~1.0", - "ramsey/array_column": "~1.1", - "rmccue/requests" : "~1.6", - "symfony/finder": "~2.7", - "symfony/yaml": "~2.7", - "symfony/filesystem": "~2.7", - "symfony/config": "~2.7", - "symfony/console": "~2.7", - "symfony/debug": "~2.7", - "symfony/dependency-injection": "~2.7", - "symfony/event-dispatcher": "~2.7", - "symfony/process": "~2.1", - "symfony/translation": "~2.7", - "nb/oxymel": "~0.1.0", - "composer/composer": "^1.2.0", - "wp-cli/cron-command": "^1.0", - "wp-cli/import-command": "^1.0", - "wp-cli/db-command": "^1.0", - "wp-cli/media-command": "^1.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*", - "behat/behat": "2.5.*", - "roave/security-advisories": "dev-master" - }, - "suggest": { - "psy/psysh": "Enhanced `wp shell` functionality" - }, - "autoload": { - "psr-0": { "WP_CLI": "php" }, - "classmap": [ "php/export" ] - } -} diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 47144fe9c..000000000 --- a/composer.lock +++ /dev/null @@ -1,2257 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "content-hash": "973e07d9736ed27c9e352cb651db3a46", - "packages": [ - { - "name": "composer/ca-bundle", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "a795611394b3c05164fd0eb291b492b39339cba4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/a795611394b3c05164fd0eb291b492b39339cba4", - "reference": "a795611394b3c05164fd0eb291b492b39339cba4", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "ext-pcre": "*", - "php": "^5.3.2 || ^7.0" - }, - "require-dev": { - "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0" - }, - "suggest": { - "symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\CaBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": [ - "cabundle", - "cacert", - "certificate", - "ssl", - "tls" - ], - "time": "2016-11-02T18:11:27+00:00" - }, - { - "name": "composer/composer", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/composer.git", - "reference": "e7569edb4a5eadcbb2e4ad5ed753282260f281df" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e7569edb4a5eadcbb2e4ad5ed753282260f281df", - "reference": "e7569edb4a5eadcbb2e4ad5ed753282260f281df", - "shasum": "" - }, - "require": { - "composer/ca-bundle": "^1.0", - "composer/semver": "^1.0", - "composer/spdx-licenses": "^1.0", - "justinrainbow/json-schema": "^1.6 || ^2.0 || ^3.0 || ^4.0", - "php": "^5.3.2 || ^7.0", - "psr/log": "^1.0", - "seld/cli-prompt": "^1.0", - "seld/jsonlint": "^1.4", - "seld/phar-utils": "^1.0", - "symfony/console": "^2.7 || ^3.0", - "symfony/filesystem": "^2.7 || ^3.0", - "symfony/finder": "^2.7 || ^3.0", - "symfony/process": "^2.7 || ^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" - }, - "suggest": { - "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", - "ext-zip": "Enabling the zip extension allows you to unzip archives", - "ext-zlib": "Allow gzip compression of HTTP requests" - }, - "bin": [ - "bin/composer" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\": "src/Composer" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", - "homepage": "https://getcomposer.org/", - "keywords": [ - "autoload", - "dependency", - "package" - ], - "time": "2017-01-27T17:23:42+00:00" - }, - { - "name": "composer/semver", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "time": "2016-08-30T16:08:34+00:00" - }, - { - "name": "composer/spdx-licenses", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/composer/spdx-licenses.git", - "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/96c6a07b05b716e89a44529d060bc7f5c263cb13", - "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Spdx\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "SPDX licenses list and validation library.", - "keywords": [ - "license", - "spdx", - "validator" - ], - "time": "2016-09-28T07:17:45+00:00" - }, - { - "name": "justinrainbow/json-schema", - "version": "4.1.0", - "source": { - "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "d39c56a46b3ebe1f3696479966cd2b9f50aaa24f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/d39c56a46b3ebe1f3696479966cd2b9f50aaa24f", - "reference": "d39c56a46b3ebe1f3696479966cd2b9f50aaa24f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "json-schema/json-schema-test-suite": "1.2.0", - "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "^4.8.22" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "time": "2016-12-22T16:43:46+00:00" - }, - { - "name": "mustache/mustache", - "version": "v2.11.1", - "source": { - "type": "git", - "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "a3f6d55996dd28b58f3a909d474189a3c1aa693f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/a3f6d55996dd28b58f3a909d474189a3c1aa693f", - "reference": "a3f6d55996dd28b58f3a909d474189a3c1aa693f", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~1.11", - "phpunit/phpunit": "~3.7|~4.0|~5.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Mustache": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" - } - ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", - "keywords": [ - "mustache", - "templating" - ], - "time": "2016-07-31T06:18:27+00:00" - }, - { - "name": "mustangostang/spyc", - "version": "0.6.2", - "source": { - "type": "git", - "url": "https://github.com/mustangostang/spyc.git", - "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mustangostang/spyc/zipball/23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", - "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", - "shasum": "" - }, - "require": { - "php": ">=5.3.1" - }, - "require-dev": { - "phpunit/phpunit": "4.3.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5.x-dev" - } - }, - "autoload": { - "files": [ - "Spyc.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "mustangostang", - "email": "vlad.andersen@gmail.com" - } - ], - "description": "A simple YAML loader/dumper class for PHP", - "homepage": "https://github.com/mustangostang/spyc/", - "keywords": [ - "spyc", - "yaml", - "yml" - ], - "time": "2017-02-24T16:06:33+00:00" - }, - { - "name": "nb/oxymel", - "version": "v0.1.0", - "source": { - "type": "git", - "url": "https://github.com/nb/oxymel.git", - "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nb/oxymel/zipball/cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", - "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "type": "library", - "autoload": { - "psr-0": { - "Oxymel": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nikolay Bachiyski", - "email": "nb@nikolay.bg", - "homepage": "http://extrapolate.me/" - } - ], - "description": "A sweet XML builder", - "homepage": "https://github.com/nb/oxymel", - "keywords": [ - "xml" - ], - "time": "2013-02-24T15:01:54+00:00" - }, - { - "name": "psr/log", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-10-10T12:19:37+00:00" - }, - { - "name": "ramsey/array_column", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/ramsey/array_column.git", - "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/array_column/zipball/f8e52eb28e67eb50e613b451dd916abcf783c1db", - "reference": "f8e52eb28e67eb50e613b451dd916abcf783c1db", - "shasum": "" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "0.8.*", - "phpunit/phpunit": "~4.5", - "satooshi/php-coveralls": "0.6.*", - "squizlabs/php_codesniffer": "~2.2" - }, - "type": "library", - "autoload": { - "files": [ - "src/array_column.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ben Ramsey", - "homepage": "http://benramsey.com" - } - ], - "description": "Provides functionality for array_column() to projects using PHP earlier than version 5.5.", - "homepage": "https://github.com/ramsey/array_column", - "keywords": [ - "array", - "array_column", - "column" - ], - "time": "2015-03-20T22:07:39+00:00" - }, - { - "name": "rmccue/requests", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/rmccue/Requests.git", - "reference": "87932f52ffad70504d93f04f15690cf16a089546" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546", - "reference": "87932f52ffad70504d93f04f15690cf16a089546", - "shasum": "" - }, - "require": { - "php": ">=5.2" - }, - "require-dev": { - "requests/test-server": "dev-master" - }, - "type": "library", - "autoload": { - "psr-0": { - "Requests": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Ryan McCue", - "homepage": "http://ryanmccue.info" - } - ], - "description": "A HTTP library written in PHP, for human beings.", - "homepage": "http://github.com/rmccue/Requests", - "keywords": [ - "curl", - "fsockopen", - "http", - "idna", - "ipv6", - "iri", - "sockets" - ], - "time": "2016-10-13T00:11:37+00:00" - }, - { - "name": "seld/cli-prompt", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/cli-prompt.git", - "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", - "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Seld\\CliPrompt\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", - "keywords": [ - "cli", - "console", - "hidden", - "input", - "prompt" - ], - "time": "2016-04-18T09:31:41+00:00" - }, - { - "name": "seld/jsonlint", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "19495c181d6d53a0a13414154e52817e3b504189" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/19495c181d6d53a0a13414154e52817e3b504189", - "reference": "19495c181d6d53a0a13414154e52817e3b504189", - "shasum": "" - }, - "require": { - "php": "^5.3 || ^7.0" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "time": "2016-11-14T17:59:58+00:00" - }, - { - "name": "seld/phar-utils", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Seld\\PharUtils\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "PHAR file format utilities, for when PHP phars you up", - "keywords": [ - "phra" - ], - "time": "2015-10-13T18:44:15+00:00" - }, - { - "name": "symfony/config", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "747fa191136cf798409183c501435aa4c16184df" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/747fa191136cf798409183c501435aa4c16184df", - "reference": "747fa191136cf798409183c501435aa4c16184df", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/filesystem": "~2.3|~3.0.0" - }, - "require-dev": { - "symfony/yaml": "~2.7|~3.0.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "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 Config Component", - "homepage": "https://symfony.com", - "time": "2017-02-05T10:11:19+00:00" - }, - { - "name": "symfony/console", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", - "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/debug": "~2.7,>=2.7.2|~3.0.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1|~3.0.0", - "symfony/process": "~2.1|~3.0.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "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 Console Component", - "homepage": "https://symfony.com", - "time": "2017-02-06T12:04:06+00:00" - }, - { - "name": "symfony/debug", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "4a99c3a6cabfa0c297fc3531e61483d276133110" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/4a99c3a6cabfa0c297fc3531e61483d276133110", - "reference": "4a99c3a6cabfa0c297fc3531e61483d276133110", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/class-loader": "~2.2|~3.0.0", - "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2|~3.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "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 Debug Component", - "homepage": "https://symfony.com", - "time": "2017-01-27T23:54:58+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "1dfbf6a9e30113a9c4e482ab056e969c70c37a19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/1dfbf6a9e30113a9c4e482ab056e969c70c37a19", - "reference": "1dfbf6a9e30113a9c4e482ab056e969c70c37a19", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "conflict": { - "symfony/expression-language": "<2.6" - }, - "require-dev": { - "symfony/config": "~2.2|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "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 DependencyInjection Component", - "homepage": "https://symfony.com", - "time": "2017-01-27T23:54:58+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "74877977f90fb9c3e46378d5764217c55f32df34" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/74877977f90fb9c3e46378d5764217c55f32df34", - "reference": "74877977f90fb9c3e46378d5764217c55f32df34", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0,>=2.0.5|~3.0.0", - "symfony/dependency-injection": "~2.6|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/stopwatch": "~2.3|~3.0.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-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": "2017-01-02T20:30:24+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "5b77d49ab76e5b12743b359ef4b4a712e6f5360d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/5b77d49ab76e5b12743b359ef4b4a712e6f5360d", - "reference": "5b77d49ab76e5b12743b359ef4b4a712e6f5360d", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "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 Filesystem Component", - "homepage": "https://symfony.com", - "time": "2017-01-08T20:43:03+00:00" - }, - { - "name": "symfony/finder", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "355fccac526522dc5fca8ecf0e62749a149f3b8b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/355fccac526522dc5fca8ecf0e62749a149f3b8b", - "reference": "355fccac526522dc5fca8ecf0e62749a149f3b8b", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-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": "2017-01-02T20:30:24+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2016-11-14T01:06:16+00:00" - }, - { - "name": "symfony/process", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "0110ac49348d14eced7d3278ea7485f22196932e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0110ac49348d14eced7d3278ea7485f22196932e", - "reference": "0110ac49348d14eced7d3278ea7485f22196932e", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-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": "2017-02-03T12:08:06+00:00" - }, - { - "name": "symfony/translation", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "c281ac2b484210bb95106bdb8ae8356e63277725" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/c281ac2b484210bb95106bdb8ae8356e63277725", - "reference": "c281ac2b484210bb95106bdb8ae8356e63277725", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/config": "<2.7" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8", - "symfony/intl": "~2.4|~3.0.0", - "symfony/yaml": "~2.2|~3.0.0" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "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 Translation Component", - "homepage": "https://symfony.com", - "time": "2017-01-21T16:59:38+00:00" - }, - { - "name": "symfony/yaml", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153", - "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "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 Yaml Component", - "homepage": "https://symfony.com", - "time": "2017-01-21T16:40:50+00:00" - }, - { - "name": "wp-cli/cron-command", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/cron-command.git", - "reference": "2ce63dfe6b6e9f3312868f334f8857f4975665d7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/cron-command/zipball/2ce63dfe6b6e9f3312868f334f8857f4975665d7", - "reference": "2ce63dfe6b6e9f3312868f334f8857f4975665d7", - "shasum": "" - }, - "require-dev": { - "behat/behat": "~2.5" - }, - "type": "wp-cli-package", - "extra": { - "commands": [ - "cron test", - "cron event delete", - "cron event list", - "cron event run", - "cron event schedule", - "cron schedule list" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "cron-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Manage WP-Cron events and schedules.", - "homepage": "https://github.com/wp-cli/cron-command", - "time": "2017-02-24T15:19:37+00:00" - }, - { - "name": "wp-cli/db-command", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/db-command.git", - "reference": "63c346740519c85dbdc158b1fc716f5ef37ac6ee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/db-command/zipball/63c346740519c85dbdc158b1fc716f5ef37ac6ee", - "reference": "63c346740519c85dbdc158b1fc716f5ef37ac6ee", - "shasum": "" - }, - "require-dev": { - "behat/behat": "~2.5" - }, - "type": "wp-cli-package", - "extra": { - "commands": [ - "db create", - "db drop", - "db reset", - "db check", - "db optimize", - "db repair", - "db cli", - "db query", - "db export", - "db import", - "db tables" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "db-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Perform basic database operations using credentials stored in wp-config.php.", - "homepage": "https://github.com/wp-cli/db-command", - "time": "2017-03-01T13:55:17+00:00" - }, - { - "name": "wp-cli/import-command", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/import-command.git", - "reference": "2be58f14961284ae701a2519b62da211ffedf83d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/import-command/zipball/2be58f14961284ae701a2519b62da211ffedf83d", - "reference": "2be58f14961284ae701a2519b62da211ffedf83d", - "shasum": "" - }, - "require-dev": { - "behat/behat": "~2.5" - }, - "type": "wp-cli-package", - "extra": { - "commands": [ - "import" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "import-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Import content from a WXR file.", - "homepage": "https://github.com/wp-cli/import-command", - "time": "2017-02-28T13:24:43+00:00" - }, - { - "name": "wp-cli/media-command", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/media-command.git", - "reference": "fa12bf77a0c0f4af934750175eb75b4b358d399c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/media-command/zipball/fa12bf77a0c0f4af934750175eb75b4b358d399c", - "reference": "fa12bf77a0c0f4af934750175eb75b4b358d399c", - "shasum": "" - }, - "require-dev": { - "behat/behat": "~2.5" - }, - "type": "wp-cli-package", - "extra": { - "commands": [ - "media import", - "media regenerate" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "media-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Manage attachments.", - "homepage": "https://github.com/wp-cli/media-command", - "time": "2017-03-08T13:17:43+00:00" - }, - { - "name": "wp-cli/php-cli-tools", - "version": "v0.11.2", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "6d231e5538b2c0db909b2cb49d30a45faf20069a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/6d231e5538b2c0db909b2cb49d30a45faf20069a", - "reference": "6d231e5538b2c0db909b2cb49d30a45faf20069a", - "shasum": "" - }, - "require": { - "php": ">= 5.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "cli": "lib/" - }, - "files": [ - "lib/cli/cli.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "James Logsdon", - "email": "jlogsdon@php.net", - "role": "Developer" - }, - { - "name": "Daniel Bachhuber", - "email": "daniel@handbuilt.co", - "role": "Maintainer" - } - ], - "description": "Console utilities for PHP", - "homepage": "http://github.com/wp-cli/php-cli-tools", - "keywords": [ - "cli", - "console" - ], - "time": "2017-02-15T12:17:55+00:00" - } - ], - "packages-dev": [ - { - "name": "behat/behat", - "version": "v2.5.5", - "source": { - "type": "git", - "url": "https://github.com/Behat/Behat.git", - "reference": "c1e48826b84669c97a1efa78459aedfdcdcf2120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/c1e48826b84669c97a1efa78459aedfdcdcf2120", - "reference": "c1e48826b84669c97a1efa78459aedfdcdcf2120", - "shasum": "" - }, - "require": { - "behat/gherkin": "~2.3.0", - "php": ">=5.3.1", - "symfony/config": "~2.3", - "symfony/console": "~2.0", - "symfony/dependency-injection": "~2.0", - "symfony/event-dispatcher": "~2.0", - "symfony/finder": "~2.0", - "symfony/translation": "~2.3", - "symfony/yaml": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~3.7.19" - }, - "suggest": { - "behat/mink-extension": "for integration with Mink testing framework", - "behat/symfony2-extension": "for integration with Symfony2 web framework", - "behat/yii-extension": "for integration with Yii web framework" - }, - "bin": [ - "bin/behat" - ], - "type": "library", - "autoload": { - "psr-0": { - "Behat\\Behat": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Scenario-oriented BDD framework for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "Symfony2" - ], - "time": "2015-06-01T09:37:55+00:00" - }, - { - "name": "behat/gherkin", - "version": "v2.3.5", - "source": { - "type": "git", - "url": "https://github.com/Behat/Gherkin.git", - "reference": "2b33963da5525400573560c173ab5c9c057e1852" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/2b33963da5525400573560c173ab5c9c057e1852", - "reference": "2b33963da5525400573560c173ab5c9c057e1852", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/finder": "~2.0" - }, - "require-dev": { - "symfony/config": "~2.0", - "symfony/translation": "~2.0", - "symfony/yaml": "~2.0" - }, - "suggest": { - "symfony/config": "If you want to use Config component to manage resources", - "symfony/translation": "If you want to use Symfony2 translations adapter", - "symfony/yaml": "If you want to parse features, represented in YAML files" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "2.2-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Gherkin": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Gherkin DSL parser for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "DSL", - "Symfony2", - "parser" - ], - "time": "2013-10-15T11:22:17+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "1.2.18", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.2.0@stable", - "phpunit/php-token-stream": ">=1.1.3,<1.3.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@dev" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2014-09-02T10:13:14+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2016-10-03T07:40:28+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2014-03-03T05:10:30+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "3.7.38", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpunit/php-code-coverage": "~1.2", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.1", - "phpunit/php-timer": "~1.0", - "phpunit/phpunit-mock-objects": "~1.2", - "symfony/yaml": "~2.0" - }, - "require-dev": { - "pear-pear.php.net/pear": "1.9.4" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2014-10-17T09:04:17+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2013-01-13T10:24:48+00:00" - }, - { - "name": "roave/security-advisories", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "73603e2e613ddc14e2e11ec6da4e837bf0a2149a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/73603e2e613ddc14e2e11ec6da4e837bf0a2149a", - "reference": "73603e2e613ddc14e2e11ec6da4e837bf0a2149a", - "shasum": "" - }, - "conflict": { - "adodb/adodb-php": "<5.20.6", - "amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=3,<3.0.15|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=1.3,<1.3.18|>=2.7,<2.7.6|>=3.1,<3.1.4", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<2.1", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1.0.0-alpha11", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2.11,<3.5.15", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=8,<8.2.3", - "drupal/drupal": ">=8,<8.2.3", - "firebase/php-jwt": "<2", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", - "joomla/session": "<1.3.1", - "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", - "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/magento2ce": ">=2,<2.2", - "monolog/monolog": ">=1.8,<1.12", - "namshi/jose": "<2.2", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "phpmailer/phpmailer": ">=5,<5.2.22", - "pusher/pusher-php-server": "<2.2.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "shopware/shopware": "<4.4|>=5,<5.2.16", - "silverstripe/cms": ">=3.1,<3.1.11|>=3,<=3.0.11", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.3", - "silverstripe/userforms": "<3", - "simplesamlphp/saml2": "<1.8.1|>=1.9,<1.9.1|>=1.10,<1.10.3|>=2,<2.3.3", - "simplesamlphp/simplesamlphp": "<1.14.11", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "socalnick/scn-social-auth": "<1.15.2", - "squizlabs/php_codesniffer": ">=1,<2.8.1", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "symfony/dependency-injection": ">=2,<2.0.17", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.7", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", - "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9", - "symfony/security-core": ">=2.8,<2.8.6|>=3,<3.0.6|>=2.4,<2.6.13|>=2.7,<2.7.9", - "symfony/security-http": ">=2.4,<2.7.13|>=2.3,<2.3.41|>=2.8,<2.8.6|>=3,<3.0.6", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6", - "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", - "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.30|>=8,<8.6.1|>=7,<7.6.16", - "typo3/flow": ">=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5|>=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", - "willdurand/js-translation-bundle": "<2.1.1", - "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.5", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.4", - "yiisoft/yii2-gii": "<2.0.4", - "yiisoft/yii2-jui": "<2.0.4", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-diactoros": ">=1,<1.0.4", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2017-03-02T15:23:30+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "roave/security-advisories": 20 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.3.29" - }, - "platform-dev": [] -} diff --git a/features/aliases.feature b/features/aliases.feature deleted file mode 100644 index 2255d4756..000000000 --- a/features/aliases.feature +++ /dev/null @@ -1,303 +0,0 @@ -Feature: Create shortcuts to specific WordPress installs - - Scenario: Alias for a path to a specific WP install - Given a WP install in 'testdir' - And a wp-cli.yml file: - """ - @testdir: - path: testdir - """ - - When I try `wp core is-installed` - Then STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - And the return code should be 1 - - When I run `wp @testdir core is-installed` - Then the return code should be 0 - - Scenario: Error when invalid alias provided - Given an empty directory - - When I try `wp @test option get home` - Then STDERR should be: - """ - Error: Alias '@test' not found. - """ - - Scenario: Treat global params as local when included in alias - Given a WP install in 'testdir' - And a wp-cli.yml file: - """ - @testdir: - path: testdir - """ - - When I run `wp @testdir option get home` - Then STDOUT should be: - """ - http://example.com - """ - - When I try `wp @testdir option get home --path=testdir` - Then STDERR should contain: - """ - Parameter errors: - """ - And STDERR should contain: - """ - unknown --path parameter - """ - - When I run `wp @testdir eval 'echo get_current_user_id();' --user=admin` - Then STDOUT should be: - """ - 1 - """ - - Given a wp-cli.yml file: - """ - @testdir: - path: testdir - user: admin - """ - - When I run `wp @testdir eval 'echo get_current_user_id();'` - Then STDOUT should be: - """ - 1 - """ - - When I try `wp @testdir eval 'echo get_current_user_id();' --user=admin` - Then STDERR should contain: - """ - Parameter errors: - """ - And STDERR should contain: - """ - unknown --user parameter - """ - - Scenario: Support global params specific to the WordPress install, not WP-CLI generally - Given a WP install in 'testdir' - And a wp-cli.yml file: - """ - @testdir: - path: testdir - debug: true - """ - - When I run `wp @testdir option get home` - Then STDOUT should be: - """ - http://example.com - """ - And STDERR should be empty - - Scenario: List available aliases - Given an empty directory - And a wp-cli.yml file: - """ - @testdir: - path: testdir - """ - - When I run `wp cli alias` - Then STDOUT should be YAML containing: - """ - @all: Run command against every registered alias. - @testdir: - path: testdir - """ - - When I run `wp cli aliases` - Then STDOUT should be YAML containing: - """ - @all: Run command against every registered alias. - @testdir: - path: testdir - """ - - When I run `wp cli alias --format=json` - Then STDOUT should be JSON containing: - """ - {"@all":"Run command against every registered alias.","@testdir":{"path":"testdir"}} - """ - - Scenario: Defining a project alias completely overrides a global alias - Given a WP install in 'testdir' - And a config.yml file: - """ - @testdir: - path: testdir - """ - - When I run `WP_CLI_CONFIG_PATH=config.yml wp @testdir option get home` - Then STDOUT should be: - """ - http://example.com - """ - - Given a wp-cli.yml file: - """ - @testdir: - path: none-existent-install - """ - When I try `WP_CLI_CONFIG_PATH=config.yml wp @testdir option get home` - Then STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - - Scenario: Use a group of aliases to run a command against multiple installs - Given a WP install in 'subdir1' - And a WP install in 'subdir2' - And a wp-cli.yml file: - """ - @both: - - @subdir1 - - @subdir2 - @invalid: - - @subdir1 - - @subdir3 - @subdir1: - path: subdir1 - @subdir2: - path: subdir2 - """ - - When I run `wp @subdir1 option update home 'http://apple.com'` - And I run `wp @subdir1 option get home` - Then STDOUT should contain: - """ - http://apple.com - """ - - When I run `wp @subdir2 option update home 'http://google.com'` - And I run `wp @subdir2 option get home` - Then STDOUT should contain: - """ - http://google.com - """ - - When I try `wp @invalid option get home` - Then STDERR should be: - """ - Error: Group '@invalid' contains one or more invalid aliases: @subdir3 - """ - - When I run `wp @both option get home` - Then STDOUT should be: - """ - @subdir1 - http://apple.com - @subdir2 - http://google.com - """ - - When I run `wp @both option get home --quiet` - Then STDOUT should be: - """ - http://apple.com - http://google.com - """ - - Scenario: Register '@all' alias for running on one or more aliases - Given a WP install in 'subdir1' - And a WP install in 'subdir2' - And a wp-cli.yml file: - """ - @subdir1: - path: subdir1 - @subdir2: - path: subdir2 - """ - - When I run `wp @subdir1 option update home 'http://apple.com'` - And I run `wp @subdir1 option get home` - Then STDOUT should contain: - """ - http://apple.com - """ - - When I run `wp @subdir2 option update home 'http://google.com'` - And I run `wp @subdir2 option get home` - Then STDOUT should contain: - """ - http://google.com - """ - - When I run `wp @all option get home` - Then STDOUT should be: - """ - @subdir1 - http://apple.com - @subdir2 - http://google.com - """ - - When I run `wp @all option get home --quiet` - Then STDOUT should be: - """ - http://apple.com - http://google.com - """ - - Scenario: Don't register '@all' when its already set - Given a WP install in 'subdir1' - And a WP install in 'subdir2' - And a wp-cli.yml file: - """ - @all: - path: subdir1 - @subdir2: - path: subdir2 - """ - - When I run `wp @all option get home | wc -l` - Then STDOUT should be: - """ - 1 - """ - - Scenario: Error when '@all' is used without aliases defined - Given an empty directory - - When I try `wp @all option get home` - Then STDERR should be: - """ - Error: Cannot use '@all' when no aliases are registered. - """ - - Scenario: Alias for a subsite of a multisite install - Given a WP multisite subdomain install - And a wp-cli.yml file: - """ - url: example.com - @subsite: - url: subsite.example.com - """ - - When I run `wp site create --slug=subsite` - Then STDOUT should not be empty - - When I run `wp option get siteurl` - Then STDOUT should be: - """ - http://example.com - """ - - When I run `wp @subsite option get siteurl` - Then STDOUT should be: - """ - http://subsite.example.com - """ - - When I try `wp @subsite option get siteurl --url=subsite.example.com` - Then STDERR should be: - """ - Error: Parameter errors: - unknown --url parameter - """ diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php deleted file mode 100644 index cc72cc02c..000000000 --- a/features/bootstrap/FeatureContext.php +++ /dev/null @@ -1,345 +0,0 @@ -<?php - -use Behat\Behat\Context\ClosuredContextInterface, - Behat\Behat\Context\TranslatedContextInterface, - Behat\Behat\Context\BehatContext, - Behat\Behat\Event\SuiteEvent; - -use \WP_CLI\Process; -use \WP_CLI\Utils; - -// Inside a community package -if ( file_exists( __DIR__ . '/utils.php' ) ) { - require_once __DIR__ . '/utils.php'; - require_once __DIR__ . '/Process.php'; - require_once __DIR__ . '/ProcessRun.php'; - $project_composer = dirname( dirname( dirname( __FILE__ ) ) ) . '/composer.json'; - if ( file_exists( $project_composer ) ) { - $composer = json_decode( file_get_contents( $project_composer ) ); - if ( ! empty( $composer->autoload->files ) ) { - $contents = 'require:' . PHP_EOL; - foreach( $composer->autoload->files as $file ) { - $contents .= ' - ' . dirname( dirname( dirname( __FILE__ ) ) ) . '/' . $file . PHP_EOL; - } - @mkdir( sys_get_temp_dir() . '/wp-cli-package-test/' ); - $project_config = sys_get_temp_dir() . '/wp-cli-package-test/config.yml'; - file_put_contents( $project_config, $contents ); - putenv( 'WP_CLI_CONFIG_PATH=' . $project_config ); - } - } -// Inside WP-CLI -} else { - require_once __DIR__ . '/../../php/utils.php'; - require_once __DIR__ . '/../../php/WP_CLI/Process.php'; - require_once __DIR__ . '/../../php/WP_CLI/ProcessRun.php'; - require_once __DIR__ . '/../../vendor/autoload.php'; -} - -/** - * Features context. - */ -class FeatureContext extends BehatContext implements ClosuredContextInterface { - - private static $cache_dir, $suite_cache_dir; - - private static $db_settings = array( - 'dbname' => 'wp_cli_test', - 'dbuser' => 'wp_cli_test', - 'dbpass' => 'password1', - 'dbhost' => '127.0.0.1', - ); - - private $running_procs = array(); - - public $variables = array(); - - /** - * Get the environment variables required for launched `wp` processes - * @beforeSuite - */ - private static function get_process_env_variables() { - // Ensure we're using the expected `wp` binary - $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); - $env = array( - 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), - 'BEHAT_RUN' => 1, - 'HOME' => '/tmp/wp-cli-home', - ); - if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { - $env['WP_CLI_CONFIG_PATH'] = $config_path; - } - return $env; - } - - // We cache the results of `wp core download` to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests - private static function cache_wp_files() { - self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test core-download-cache'; - - if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) - return; - - $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); - if ( getenv( 'WP_VERSION' ) ) { - $cmd .= Utils\esc_cmd( ' --version=%s', getenv( 'WP_VERSION' ) ); - } - Process::create( $cmd, null, self::get_process_env_variables() )->run_check(); - } - - /** - * @BeforeSuite - */ - public static function prepare( SuiteEvent $event ) { - $result = Process::create( 'wp cli info', null, self::get_process_env_variables() )->run_check(); - echo PHP_EOL; - echo $result->stdout; - echo PHP_EOL; - self::cache_wp_files(); - $result = Process::create( Utils\esc_cmd( 'wp core version --path=%s', self::$cache_dir ) , null, self::get_process_env_variables() )->run_check(); - echo 'WordPress ' . $result->stdout; - echo PHP_EOL; - } - - /** - * @AfterSuite - */ - public static function afterSuite( SuiteEvent $event ) { - if ( self::$suite_cache_dir ) { - Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ), null, self::get_process_env_variables() )->run(); - } - } - - /** - * @BeforeScenario - */ - public function beforeScenario( $event ) { - $this->variables['SRC_DIR'] = realpath( __DIR__ . '/../..' ); - } - - /** - * @AfterScenario - */ - public function afterScenario( $event ) { - if ( isset( $this->variables['RUN_DIR'] ) ) { - // remove altered WP install, unless there's an error - if ( $event->getResult() < 4 ) { - $this->proc( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); - } - } - - // Remove WP-CLI package directory - if ( isset( $this->variables['PACKAGE_PATH'] ) ) { - $this->proc( Utils\esc_cmd( 'rm -rf %s', $this->variables['PACKAGE_PATH'] ) )->run(); - } - - foreach ( $this->running_procs as $proc ) { - self::terminate_proc( $proc ); - } - } - - /** - * Terminate a process and any of its children. - */ - private static function terminate_proc( $proc ) { - $status = proc_get_status( $proc ); - - $master_pid = $status['pid']; - - $output = `ps -o ppid,pid,command | grep $master_pid`; - - foreach ( explode( PHP_EOL, $output ) as $line ) { - if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) { - $parent = $matches[1]; - $child = $matches[2]; - - if ( $parent == $master_pid ) { - if ( ! posix_kill( (int) $child, 9 ) ) { - throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); - } - } - } - } - - if ( ! posix_kill( (int) $master_pid, 9 ) ) { - throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); - } - } - - public static function create_cache_dir() { - self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); - mkdir( self::$suite_cache_dir ); - return self::$suite_cache_dir; - } - - /** - * Initializes context. - * Every scenario gets it's own context object. - * - * @param array $parameters context parameters (set them up through behat.yml) - */ - public function __construct( array $parameters ) { - if ( getenv( 'WP_CLI_TEST_DBHOST' ) ) { - self::$db_settings['dbhost'] = getenv( 'WP_CLI_TEST_DBHOST' ); - } - $this->drop_db(); - $this->set_cache_dir(); - $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); - } - - public function getStepDefinitionResources() { - return glob( __DIR__ . '/../steps/*.php' ); - } - - public function getHookDefinitionResources() { - return array(); - } - - public function replace_variables( $str ) { - return preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); - } - - private function _replace_var( $matches ) { - $cmd = $matches[0]; - - foreach ( array_slice( $matches, 1 ) as $key ) { - $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); - } - - return $cmd; - } - - public function create_run_dir() { - if ( !isset( $this->variables['RUN_DIR'] ) ) { - $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); - mkdir( $this->variables['RUN_DIR'] ); - } - } - - public function build_phar( $version = 'same' ) { - $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; - - $this->proc( Utils\esc_cmd( - 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', - __DIR__ . '/../../utils/make-phar.php', - $this->variables['PHAR_PATH'], - $version - ) )->run_check(); - } - - private function set_cache_dir() { - $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - $this->proc( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); - $this->variables['CACHE_DIR'] = $path; - } - - private static function run_sql( $sql ) { - Utils\run_mysql_command( 'mysql --no-defaults', array( - 'execute' => $sql, - 'host' => self::$db_settings['dbhost'], - 'user' => self::$db_settings['dbuser'], - 'pass' => self::$db_settings['dbpass'], - ) ); - } - - public function create_db() { - $dbname = self::$db_settings['dbname']; - self::run_sql( "CREATE DATABASE IF NOT EXISTS $dbname" ); - } - - public function drop_db() { - $dbname = self::$db_settings['dbname']; - self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); - } - - public function proc( $command, $assoc_args = array(), $path = '' ) { - if ( !empty( $assoc_args ) ) - $command .= Utils\assoc_args_to_str( $assoc_args ); - - $env = self::get_process_env_variables(); - if ( isset( $this->variables['SUITE_CACHE_DIR'] ) ) { - $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; - } - - if ( isset( $this->variables['RUN_DIR'] ) ) { - $cwd = "{$this->variables['RUN_DIR']}/{$path}"; - } else { - $cwd = null; - } - - return Process::create( $command, $cwd, $env ); - } - - /** - * Start a background process. Will automatically be closed when the tests finish. - */ - public function background_proc( $cmd ) { - $descriptors = array( - 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); - - $proc = proc_open( $cmd, $descriptors, $pipes, $this->variables['RUN_DIR'], self::get_process_env_variables() ); - - sleep(1); - - $status = proc_get_status( $proc ); - - if ( !$status['running'] ) { - throw new RuntimeException( stream_get_contents( $pipes[2] ) ); - } else { - $this->running_procs[] = $proc; - } - } - - public function move_files( $src, $dest ) { - rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); - } - - public function add_line_to_wp_config( &$wp_config_code, $line ) { - $token = "/* That's all, stop editing!"; - - $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); - } - - public function download_wp( $subdir = '' ) { - $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; - - if ( $subdir ) { - mkdir( $dest_dir ); - } - - $this->proc( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); - - // disable emailing - mkdir( $dest_dir . '/wp-content/mu-plugins' ); - copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); - } - - public function create_config( $subdir = '' ) { - $params = self::$db_settings; - $params['dbprefix'] = $subdir ?: 'wp_'; - - $params['skip-salts'] = true; - $this->proc( 'wp core config', $params, $subdir )->run_check(); - } - - public function install_wp( $subdir = '' ) { - $this->create_db(); - $this->create_run_dir(); - $this->download_wp( $subdir ); - - $this->create_config( $subdir ); - - $install_args = array( - 'url' => 'http://example.com', - 'title' => 'WP CLI Site', - 'admin_user' => 'admin', - 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' - ); - - $this->proc( 'wp core install', $install_args, $subdir )->run_check(); - } -} - diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php deleted file mode 100644 index 75ee5fbd3..000000000 --- a/features/bootstrap/support.php +++ /dev/null @@ -1,194 +0,0 @@ -<?php - -// Utility functions used by Behat steps - -function assertEquals( $expected, $actual ) { - if ( $expected != $actual ) { - throw new Exception( "Actual value: " . var_export( $actual, true ) ); - } -} - -function assertNotEquals( $expected, $actual ) { - if ( $expected == $actual ) { - throw new Exception( "Actual value: " . var_export( $actual, true ) ); - } -} - -function assertNumeric( $actual ) { - if ( !is_numeric( $actual ) ) { - throw new Exception( "Actual value: " . var_export( $actual, true ) ); - } -} - -function assertNotNumeric( $actual ) { - if ( is_numeric( $actual ) ) { - throw new Exception( "Actual value: " . var_export( $actual, true ) ); - } -} - -function checkString( $output, $expected, $action, $message = false ) { - switch ( $action ) { - - case 'be': - $r = $expected === rtrim( $output, "\n" ); - break; - - case 'contain': - $r = false !== strpos( $output, $expected ); - break; - - case 'not contain': - $r = false === strpos( $output, $expected ); - break; - - default: - throw new Behat\Behat\Exception\PendingException(); - } - - if ( !$r ) { - if ( false === $message ) - $message = $output; - throw new Exception( $message ); - } -} - -function compareTables( $expected_rows, $actual_rows, $output ) { - // the first row is the header and must be present - if ( $expected_rows[0] != $actual_rows[0] ) { - throw new \Exception( $output ); - } - - unset( $actual_rows[0] ); - unset( $expected_rows[0] ); - - $missing_rows = array_diff( $expected_rows, $actual_rows ); - if ( !empty( $missing_rows ) ) { - throw new \Exception( $output ); - } -} - -function compareContents( $expected, $actual ) { - if ( gettype( $expected ) != gettype( $actual ) ) { - return false; - } - - if ( is_object( $expected ) ) { - foreach ( get_object_vars( $expected ) as $name => $value ) { - if ( ! compareContents( $value, $actual->$name ) ) - return false; - } - } else if ( is_array( $expected ) ) { - foreach ( $expected as $key => $value ) { - if ( ! compareContents( $value, $actual[$key] ) ) - return false; - } - } else { - return $expected === $actual; - } - - return true; -} - -/** - * Compare two strings containing JSON to ensure that @a $actualJson contains at - * least what the JSON string @a $expectedJson contains. - * - * @return whether or not @a $actualJson contains @a $expectedJson - * @retval true @a $actualJson contains @a $expectedJson - * @retval false @a $actualJson does not contain @a $expectedJson - * - * @param[in] $actualJson the JSON string to be tested - * @param[in] $expectedJson the expected JSON string - * - * Examples: - * expected: {'a':1,'array':[1,3,5]} - * - * 1 ) - * actual: {'a':1,'b':2,'c':3,'array':[1,2,3,4,5]} - * return: true - * - * 2 ) - * actual: {'b':2,'c':3,'array':[1,2,3,4,5]} - * return: false - * element 'a' is missing from the root object - * - * 3 ) - * actual: {'a':0,'b':2,'c':3,'array':[1,2,3,4,5]} - * return: false - * the value of element 'a' is not 1 - * - * 4 ) - * actual: {'a':1,'b':2,'c':3,'array':[1,2,4,5]} - * return: false - * the contents of 'array' does not include 3 - */ -function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { - $actualValue = json_decode( $actualJson ); - $expectedValue = json_decode( $expectedJson ); - - if ( !$actualValue ) { - return false; - } - - return compareContents( $expectedValue, $actualValue ); -} - -/** - * Compare two strings to confirm $actualCSV contains $expectedCSV - * Both strings are expected to have headers for their CSVs. - * $actualCSV must match all data rows in $expectedCSV - * - * @param string A CSV string - * @param array A nested array of values - * @return bool Whether $actualCSV contains $expectedCSV - */ -function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { - $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); - - if ( empty( $actualCSV ) ) - return false; - - // Each sample must have headers - $actualHeaders = array_values( array_shift( $actualCSV ) ); - $expectedHeaders = array_values( array_shift( $expectedCSV ) ); - - // Each expectedCSV must exist somewhere in actualCSV in the proper column - $expectedResult = 0; - foreach ( $expectedCSV as $expected_row ) { - $expected_row = array_combine( $expectedHeaders, $expected_row ); - foreach ( $actualCSV as $actual_row ) { - - if ( count( $actualHeaders ) != count( $actual_row ) ) - continue; - - $actual_row = array_intersect_key( array_combine( $actualHeaders, $actual_row ), $expected_row ); - if ( $actual_row == $expected_row ) - $expectedResult++; - } - } - - return $expectedResult >= count( $expectedCSV ); -} - -/** - * Compare two strings containing YAML to ensure that @a $actualYaml contains at - * least what the YAML string @a $expectedYaml contains. - * - * @return whether or not @a $actualYaml contains @a $expectedJson - * @retval true @a $actualYaml contains @a $expectedJson - * @retval false @a $actualYaml does not contain @a $expectedJson - * - * @param[in] $actualYaml the YAML string to be tested - * @param[in] $expectedYaml the expected YAML string - */ -function checkThatYamlStringContainsYamlString( $actualYaml, $expectedYaml ) { - $actualValue = spyc_load( $actualYaml ); - $expectedValue = spyc_load( $expectedYaml ); - - if ( !$actualValue ) { - return false; - } - - return compareContents( $expectedValue, $actualValue ); -} - diff --git a/features/cache.feature b/features/cache.feature deleted file mode 100644 index 472f28d19..000000000 --- a/features/cache.feature +++ /dev/null @@ -1,134 +0,0 @@ -Feature: Managed the WordPress object cache - - Scenario: Default group is 'default' - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - <?php - $set_foo = function(){ - wp_cache_set( 'foo', 'bar' ); - }; - $set_foo_value = function() { - wp_cache_set( 'foo', 2 ); - }; - $log_foo_value = function() { - WP_CLI::log( var_export( wp_cache_get( 'foo' ), true ) ); - }; - WP_CLI::add_hook( 'before_invoke:cache get', $set_foo ); - WP_CLI::add_hook( 'before_invoke:cache delete', $set_foo ); - WP_CLI::add_hook( 'before_invoke:cache add', $set_foo ); - WP_CLI::add_hook( 'before_invoke:cache incr', $set_foo_value ); - WP_CLI::add_hook( 'before_invoke:cache decr', $set_foo_value ); - WP_CLI::add_hook( 'after_invoke:cache set', $log_foo_value ); - WP_CLI::add_hook( 'before_invoke:cache replace', $set_foo_value ); - """ - - When I run `wp cache get foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp cache get bar` - Then STDERR should be: - """ - Error: Object with key 'bar' and group 'default' not found. - """ - - When I try `wp cache get bar burrito` - Then STDERR should be: - """ - Error: Object with key 'bar' and group 'burrito' not found. - """ - - When I run `wp cache delete foo` - Then STDOUT should be: - """ - Success: Object deleted. - """ - - When I try `wp cache delete bar` - Then STDERR should be: - """ - Error: The object was not deleted. - """ - - When I try `wp cache add foo bar` - Then STDERR should be: - """ - Error: Could not add object 'foo' in group 'default'. Does it already exist? - """ - - When I run `wp cache add bar burrito` - Then STDOUT should be: - """ - Success: Added object 'bar' in group 'default'. - """ - - When I run `wp cache add bar foo burrito` - Then STDOUT should be: - """ - Success: Added object 'bar' in group 'burrito'. - """ - - When I run `wp cache incr foo` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp cache incr foo 2` - Then STDOUT should be: - """ - 4 - """ - - When I try `wp cache incr bar` - Then STDERR should be: - """ - Error: The value was not incremented. - """ - - When I run `wp cache decr foo` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp cache decr foo 2` - Then STDOUT should be: - """ - 0 - """ - - When I try `wp cache decr bar` - Then STDERR should be: - """ - Error: The value was not decremented. - """ - - When I run `wp cache set foo bar` - Then STDOUT should be: - """ - Success: Set object 'foo' in group 'default'. - 'bar' - """ - - When I run `wp cache set burrito foo bar` - Then STDOUT should be: - """ - Success: Set object 'burrito' in group 'bar'. - false - """ - - When I run `wp cache replace foo burrito` - Then STDOUT should be: - """ - Success: Replaced object 'foo' in group 'default'. - """ - - When I try `wp cache replace bar burrito foo` - Then STDERR should be: - """ - Error: Could not replace object 'bar' in group 'foo'. Does it not exist? - """ diff --git a/features/cap.feature b/features/cap.feature deleted file mode 100644 index 4c5a1f87b..000000000 --- a/features/cap.feature +++ /dev/null @@ -1,73 +0,0 @@ -Feature: Manage Cap - - Background: - Given a WP install - - Scenario: CRUD for cap - When I run `wp cap list contributor | sort` - Then STDOUT should be: - """ - delete_posts - edit_posts - level_0 - level_1 - read - """ - - When I run `wp cap add contributor spectate` - Then STDOUT should contain: - """ - Success: Added 1 capability to 'contributor' role. - """ - - When I run `wp cap add contributor behold observe` - Then STDOUT should contain: - """ - Success: Added 2 capabilities to 'contributor' role. - """ - - When I run `wp cap list contributor` - Then STDOUT should contain: - """ - spectate - """ - And STDOUT should contain: - """ - behold - """ - And STDOUT should contain: - """ - observe - """ - - When I run `wp cap remove contributor spectate` - Then STDOUT should contain: - """ - Success: Removed 1 capability from 'contributor' role. - """ - - When I run `wp cap remove contributor behold observe` - Then STDOUT should contain: - """ - Success: Removed 2 capabilities from 'contributor' role. - """ - - When I run `wp cap list contributor` - Then STDOUT should not contain: - """ - spectate - """ - And STDOUT should not contain: - """ - behold - """ - And STDOUT should not contain: - """ - observe - """ - - When I try `wp cap add role-not-available spectate` - Then STDERR should be: - """ - Error: 'role-not-available' role not found. - """ diff --git a/features/cli-bash-completion.feature b/features/cli-bash-completion.feature deleted file mode 100644 index 2f18cbc04..000000000 --- a/features/cli-bash-completion.feature +++ /dev/null @@ -1,299 +0,0 @@ -Feature: `wp cli completions` tasks - - Scenario: Bash Completion without wp-cli.yml - Given an empty directory - - When I run `wp cli completions --line="wp " --point=100` - Then STDOUT should contain: - """ - plugin - """ - And STDOUT should contain: - """ - server - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp co" --point=100` - Then STDOUT should contain: - """ - comment - """ - And STDOUT should contain: - """ - core - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp core " --point=100` - Then STDOUT should contain: - """ - install - """ - And STDOUT should contain: - """ - update - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help " --point=100` - Then STDOUT should contain: - """ - rewrite - """ - And STDOUT should contain: - """ - media - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help core language " --point=100` - Then STDOUT should contain: - """ - install - """ - And STDOUT should contain: - """ - update - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp core" --point=100` - Then STDOUT should contain: - """ - core - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp core " --point=100` - Then STDOUT should contain: - """ - language - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line='wp bogus-comand ' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp eva' --point=100` - Then STDOUT should contain: - """ - eval - """ - And STDOUT should contain: - """ - eval-file - """ - - When I run `wp cli completions --line='wp core config --dbname=' --point=100` - Then STDOUT should be empty - - When I run `wp cli completions --line='wp core config --dbname=foo ' --point=100` - Then STDOUT should not contain: - """ - --dbname= - """ - And STDOUT should contain: - """ - --extra-php - """ - - When I run `wp cli completions --line='wp media import ' --point=100` - Then STDOUT should contain: - """ - <file> - """ - - Scenario: Bash Completion with SSH aliases - Given an empty directory - And a wp-cli.yml file: - """ - @example: - ssh: example.com - """ - - When I run `wp cli completions --line="wp " --point=100` - Then STDOUT should contain: - """ - @example - """ - And STDOUT should contain: - """ - plugin - """ - And STDOUT should contain: - """ - server - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp @e" --point=100` - Then STDOUT should contain: - """ - @example - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp @example " --point=100` - Then STDOUT should not contain: - """ - @example - """ - And STDOUT should contain: - """ - core - """ - And STDOUT should contain: - """ - eval - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp @example plugin " --point=100` - Then STDOUT should contain: - """ - list - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help core language " --point=100` - Then STDOUT should contain: - """ - install - """ - And STDOUT should contain: - """ - update - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help " --point=100` - Then STDOUT should not contain: - """ - @example - """ - And STDOUT should contain: - """ - post-type - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help core" --point=100` - Then STDOUT should contain: - """ - core - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp help core " --point=100` - Then STDOUT should contain: - """ - language - """ - And STDERR should be empty - And the return code should be 0 - - Scenario: Bash Completion for global parameters - Given an empty directory - - When I run `wp cli completions --line="wp plugin list " --point=100` - Then STDOUT should contain: - """ - --path= - """ - And STDOUT should contain: - """ - --ssh= - """ - And STDOUT should contain: - """ - --http= - """ - And STDOUT should contain: - """ - --url= - """ - And STDOUT should contain: - """ - --user= - """ - And STDOUT should contain: - """ - --skip-plugins= - """ - And STDOUT should contain: - """ - --skip-themes= - """ - And STDOUT should contain: - """ - --skip-packages - """ - And STDOUT should contain: - """ - --require= - """ - And STDOUT should contain: - """ - --color - """ - And STDOUT should contain: - """ - --no-color - """ - And STDOUT should contain: - """ - --debug= - """ - And STDOUT should contain: - """ - --prompt= - """ - And STDOUT should contain: - """ - --quiet - """ - And STDOUT should not contain: - """ - --skip-packages= - """ - And STDOUT should not contain: - """ - --color= - """ - And STDOUT should not contain: - """ - --quiet= - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp cli completions --line="wp plugin list --path --p" --point=100` - Then STDOUT should contain: - """ - --prompt= - """ - Then STDOUT should not contain: - """ - --path - """ - - When I run `wp cli completions --line="wp plugin list --no-color" --point=100` - Then STDOUT should not contain: - """ - --no-color - """ diff --git a/features/cli-info.feature b/features/cli-info.feature deleted file mode 100644 index b5cedc145..000000000 --- a/features/cli-info.feature +++ /dev/null @@ -1,25 +0,0 @@ -Feature: Review CLI information - - Scenario: Get the path to the packages directory - Given an empty directory - - When I run `wp cli info --format=json` - Then STDOUT should be JSON containing: - """ - {"wp_cli_packages_dir_path":null} - """ - - When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` - Then STDERR should be empty - - When I run `wp cli info --format=json` - Then STDOUT should be JSON containing: - """ - {"wp_cli_packages_dir_path":"/tmp/wp-cli-home/.wp-cli/packages/"} - """ - - When I run `wp cli info` - Then STDOUT should contain: - """ - WP-CLI packages dir: - """ diff --git a/features/cli.feature b/features/cli.feature deleted file mode 100644 index a26272c6b..000000000 --- a/features/cli.feature +++ /dev/null @@ -1,180 +0,0 @@ -Feature: `wp cli` tasks - - Scenario: Ability to set a custom version when building - Given an empty directory - And save the {SRC_DIR}/VERSION file as {TRUE_VERSION} - And a new Phar with version "1.2.3" - - When I run `{PHAR_PATH} cli version` - Then STDOUT should be: - """ - WP-CLI 1.2.3 - """ - And the {SRC_DIR}/VERSION file should be: - """ - {TRUE_VERSION} - """ - - @github-api - Scenario: Check for updates - Given an empty directory - And a new Phar with version "0.0.0" - - When I run `{PHAR_PATH} cli check-update` - Then STDOUT should contain: - """ - package_url - """ - And STDERR should be empty - - @github-api - Scenario: Do WP-CLI Update - Given an empty directory - And a new Phar with version "0.0.0" - - When I run `{PHAR_PATH} --info` - Then STDOUT should contain: - """ - WP-CLI version - """ - And STDOUT should contain: - """ - 0.0.0 - """ - - When I run `{PHAR_PATH} cli update --yes` - Then STDOUT should contain: - """ - md5 hash verified: - """ - And STDOUT should contain: - """ - Success: - """ - And STDERR should be empty - And the return code should be 0 - - When I run `{PHAR_PATH} --info` - Then STDOUT should contain: - """ - WP-CLI version - """ - And STDOUT should not contain: - """ - 0.0.0 - """ - - @github-api - Scenario: Patch update from 0.14.0 to 0.14.1 - Given an empty directory - And a new Phar with version "0.14.0" - - When I run `{PHAR_PATH} --version` - Then STDOUT should be: - """ - WP-CLI 0.14.0 - """ - - When I run `{PHAR_PATH} cli update --patch --yes` - Then STDOUT should contain: - """ - md5 hash verified: 3f5fa2fda8457a9a5dc9875f17a3716d - """ - And STDOUT should contain: - """ - Success: Updated WP-CLI to 0.14.1 - """ - And STDERR should be empty - And the return code should be 0 - - When I run `{PHAR_PATH} --version` - Then STDOUT should be: - """ - WP-CLI 0.14.1 - """ - - @github-api - Scenario: Not a patch update from 0.14.0 - Given an empty directory - And a new Phar with version "0.14.0" - - When I run `{PHAR_PATH} cli update --no-patch --yes` - Then STDOUT should contain: - """ - Success: - """ - And STDOUT should not contain: - """ - 0.14.1 - """ - And STDERR should be empty - And the return code should be 0 - - Scenario: Install WP-CLI nightly - Given an empty directory - And a new Phar with version "0.14.0" - - When I run `{PHAR_PATH} cli update --nightly --yes` - Then STDOUT should contain: - """ - md5 hash verified: - """ - And STDOUT should contain: - """ - Success: Updated WP-CLI to the latest nightly release. - """ - - And STDERR should be empty - And the return code should be 0 - - @github-api @less-than-php-7 - Scenario: Install WP-CLI stable - Given an empty directory - And a new Phar with version "0.14.0" - And a session file: - """ - y - """ - - When I run `{PHAR_PATH} cli check-update --minor --field=version` - Then STDOUT should not be empty - And save STDOUT as {UPDATE_VERSION} - - When I run `{PHAR_PATH} cli update --stable < session` - Then STDOUT should contain: - """ - You have version 0.14.0. Would you like to update to the latest stable release? [y/n] - """ - And STDOUT should contain: - """ - md5 hash verified: - """ - And STDOUT should contain: - """ - Success: Updated WP-CLI to the latest stable release. - """ - And STDERR should be empty - And the return code should be 0 - - When I run `{PHAR_PATH} cli check-update` - Then STDOUT should be: - """ - Success: WP-CLI is at the latest version. - """ - - When I run `{PHAR_PATH} cli version` - Then STDOUT should be: - """ - WP-CLI {UPDATE_VERSION} - """ - - Scenario: Dump the list of global parameters with values - Given a WP install - - When I run `wp cli param-dump --with-values | grep -o '"current":' | uniq -c` - Then STDOUT should be: - """ - 17 "current": - """ - And STDERR should be empty - And the return code should be 0 diff --git a/features/command.feature b/features/command.feature deleted file mode 100644 index d22a8c5d8..000000000 --- a/features/command.feature +++ /dev/null @@ -1,697 +0,0 @@ -Feature: WP-CLI Commands - - Scenario: Registered WP-CLI commands - Given an empty directory - - When I run `wp cron` - Then STDOUT should contain: - """ - usage: wp cron event <command> - or: wp cron schedule <command> - or: wp cron test - """ - - When I run `wp db` - Then STDOUT should contain: - """ - or: wp db cli - """ - - When I run `wp import --help` - Then STDOUT should contain: - """ - wp import <file>... --authors=<authors> - """ - - When I run `wp media` - Then STDOUT should contain: - """ - or: wp media regenerate - """ - - Scenario: Invalid class is specified for a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - - WP_CLI::add_command( 'command example', 'Non_Existent_Class' ); - """ - - When I try `wp --require=custom-cmd.php help` - Then the return code should be 1 - And STDERR should contain: - """ - Callable "Non_Existent_Class" does not exist, and cannot be registered as `wp command example`. - """ - - Scenario: Invalid subcommand of valid command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - /** - * @when before_wp_load - */ - class Custom_Command_Class extends WP_CLI_Command { - - public function valid() { - WP_CLI::success( 'Hello world' ); - } - - } - WP_CLI::add_command( 'command', 'Custom_Command_Class' ); - """ - - When I try `wp --require=custom-cmd.php command invalid` - Then STDERR should be: - """ - Error: 'invalid' is not a registered subcommand of 'command'. See 'wp help command'. - """ - - Scenario: Use a closure as a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - /** - * My awesome closure command - * - * <message> - * : An awesome message to display - * - * @when before_wp_load - */ - $foo = function( $args ) { - WP_CLI::success( $args[0] ); - }; - WP_CLI::add_command( 'foo', $foo ); - """ - - When I run `wp --require=custom-cmd.php help` - Then STDOUT should contain: - """ - foo - """ - - When I run `wp --require=custom-cmd.php help foo` - Then STDOUT should contain: - """ - My awesome closure command - """ - - When I try `wp --require=custom-cmd.php foo bar --burrito` - Then STDERR should contain: - """ - unknown --burrito parameter - """ - - When I run `wp --require=custom-cmd.php foo bar` - Then STDOUT should contain: - """ - Success: bar - """ - - Scenario: Use a function as a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - /** - * My awesome function command - * - * <message> - * : An awesome message to display - * - * @when before_wp_load - */ - function foo( $args ) { - WP_CLI::success( $args[0] ); - } - WP_CLI::add_command( 'foo', 'foo' ); - """ - - When I run `wp --require=custom-cmd.php help` - Then STDOUT should contain: - """ - foo - """ - - When I run `wp --require=custom-cmd.php help foo` - Then STDOUT should contain: - """ - My awesome function command - """ - - When I try `wp --require=custom-cmd.php foo bar --burrito` - Then STDERR should contain: - """ - unknown --burrito parameter - """ - - When I run `wp --require=custom-cmd.php foo bar` - Then STDOUT should contain: - """ - Success: bar - """ - - Scenario: Use a class method as a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Foo_Class extends WP_CLI_Command { - - public function __construct( $prefix ) { - $this->prefix = $prefix; - } - /** - * My awesome class method command - * - * <message> - * : An awesome message to display - * - * @when before_wp_load - */ - function foo( $args ) { - WP_CLI::success( $this->prefix . ':' . $args[0] ); - } - } - $foo = new Foo_Class( 'boo' ); - WP_CLI::add_command( 'foo', array( $foo, 'foo' ) ); - """ - - When I run `wp --require=custom-cmd.php help` - Then STDOUT should contain: - """ - foo - """ - - When I run `wp --require=custom-cmd.php help foo` - Then STDOUT should contain: - """ - My awesome class method command - """ - - When I try `wp --require=custom-cmd.php foo bar --burrito` - Then STDERR should contain: - """ - unknown --burrito parameter - """ - - When I run `wp --require=custom-cmd.php foo bar` - Then STDOUT should contain: - """ - Success: boo:bar - """ - - Scenario: Use a class method as a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Foo_Class extends WP_CLI_Command { - /** - * My awesome class method command - * - * <message> - * : An awesome message to display - * - * @when before_wp_load - */ - function foo( $args ) { - WP_CLI::success( $args[0] ); - } - } - WP_CLI::add_command( 'foo', array( 'Foo_Class', 'foo' ) ); - """ - - When I run `wp --require=custom-cmd.php help` - Then STDOUT should contain: - """ - foo - """ - - When I run `wp --require=custom-cmd.php help foo` - Then STDOUT should contain: - """ - My awesome class method command - """ - - When I try `wp --require=custom-cmd.php foo bar --burrito` - Then STDERR should contain: - """ - unknown --burrito parameter - """ - - When I run `wp --require=custom-cmd.php foo bar` - Then STDOUT should contain: - """ - Success: bar - """ - - Scenario: Use class with __invoke() passed as object - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Foo_Class { - - public function __construct( $message ) { - $this->message = $message; - } - - /** - * My awesome class method command - * - * @when before_wp_load - */ - function __invoke( $args ) { - WP_CLI::success( $this->message ); - } - } - $foo = new Foo_Class( 'bar' ); - WP_CLI::add_command( 'instantiated-command', $foo ); - """ - - When I run `wp --require=custom-cmd.php instantiated-command` - Then STDOUT should contain: - """ - bar - """ - And STDERR should be empty - - Scenario: Use an invalid class method as a command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Foo_Class extends WP_CLI_Command { - /** - * My awesome class method command - * - * <message> - * : An awesome message to display - * - * @when before_wp_load - */ - function foo( $args ) { - WP_CLI::success( $args[0] ); - } - } - $foo = new Foo_Class; - WP_CLI::add_command( 'bar', array( $foo, 'bar' ) ); - """ - - When I try `wp --require=custom-cmd.php bar` - Then STDERR should contain: - """ - Error: Callable ["Foo_Class","bar"] does not exist, and cannot be registered as `wp bar`. - """ - - Scenario: Register a synopsis for a given command - Given an empty directory - And a custom-cmd.php file: - """ - <?php - function foo( $args, $assoc_args ) { - $message = array_shift( $args ); - WP_CLI::log( 'Message is: ' . $message ); - WP_CLI::success( $assoc_args['meal'] ); - } - WP_CLI::add_command( 'foo', 'foo', array( - 'shortdesc' => 'My awesome function command', - 'when' => 'before_wp_load', - 'synopsis' => array( - array( - 'type' => 'positional', - 'name' => 'message', - 'description' => 'An awesome message to display', - 'optional' => false, - 'options' => array( 'hello', 'goodbye' ), - ), - array( - 'type' => 'assoc', - 'name' => 'apple', - 'description' => 'A type of fruit.', - 'optional' => false, - ), - array( - 'type' => 'assoc', - 'name' => 'meal', - 'description' => 'A type of meal.', - 'optional' => true, - 'default' => 'breakfast', - 'options' => array( 'breakfast', 'lunch', 'dinner' ), - ), - ), - ) ); - """ - And a wp-cli.yml file: - """ - require: - - custom-cmd.php - """ - - When I try `wp foo` - Then STDOUT should contain: - """ - usage: wp foo <message> --apple=<apple> [--meal=<meal>] - """ - - When I run `wp help foo` - Then STDOUT should contain: - """ - My awesome function command - """ - And STDOUT should contain: - """ - SYNOPSIS - """ - And STDOUT should contain: - """ - wp foo <message> --apple=<apple> [--meal=<meal>] - """ - And STDOUT should contain: - """ - OPTIONS - """ - And STDOUT should contain: - """ - <message> - An awesome message to display - --- - options: - - hello - - goodbye - --- - """ - And STDOUT should contain: - """ - [--meal=<meal>] - A type of meal. - --- - default: breakfast - options: - - breakfast - - lunch - - dinner - --- - """ - - When I try `wp foo nana --apple=fuji` - Then STDERR should contain: - """ - Error: Invalid value specified for positional arg. - """ - - When I try `wp foo hello --apple=fuji --meal=snack` - Then STDERR should contain: - """ - Invalid value specified for 'meal' (A type of meal.) - """ - - When I run `wp foo hello --apple=fuji` - Then STDOUT should be: - """ - Message is: hello - Success: breakfast - """ - - When I run `wp foo hello --apple=fuji --meal=dinner` - Then STDOUT should be: - """ - Message is: hello - Success: dinner - """ - - Scenario: Register a command with default and accepted arguments. - Given an empty directory - And a test-cmd.php file: - """ - <?php - /** - * An amazing command for managing burritos. - * - * [<bar>] - * : This is the bar argument. - * --- - * default: burrito - * --- - * - * [<shop>...] - * : This is where you buy burritos. - * --- - * options: - * - left_coast_siesta - * - cha cha cha - * --- - * - * [--burrito=<burrito>] - * : This is the burrito argument. - * --- - * options: - * - beans - * - veggies - * --- - * - * @when before_wp_load - */ - $foo = function( $args, $assoc_args ) { - $out = array( - 'bar' => isset( $args[0] ) ? $args[0] : '', - 'shop' => isset( $args[1] ) ? $args[1] : '', - 'burrito' => isset( $assoc_args['burrito'] ) ? $assoc_args['burrito'] : '', - ); - WP_CLI::print_value( $out, array( 'format' => 'yaml' ) ); - }; - WP_CLI::add_command( 'foo', $foo ); - """ - - When I run `wp --require=test-cmd.php foo --help` - Then STDOUT should contain: - """ - [<bar>] - This is the bar argument. - --- - default: burrito - --- - """ - And STDOUT should contain: - """ - [--burrito=<burrito>] - This is the burrito argument. - --- - options: - - beans - - veggies - --- - """ - - When I run `wp --require=test-cmd.php foo` - Then STDOUT should be YAML containing: - """ - bar: burrito - shop: - burrito: - """ - And STDERR should be empty - - When I run `wp --require=test-cmd.php foo ''` - Then STDOUT should be YAML containing: - """ - bar: - shop: - burrito: - """ - And STDERR should be empty - - When I run `wp --require=test-cmd.php foo apple --burrito=veggies` - Then STDOUT should be YAML containing: - """ - bar: apple - shop: - burrito: veggies - """ - And STDERR should be empty - - When I try `wp --require=test-cmd.php foo apple --burrito=meat` - Then STDERR should contain: - """ - Error: Parameter errors: - Invalid value specified for 'burrito' (This is the burrito argument.) - """ - - When I try `wp --require=test-cmd.php foo apple --burrito=''` - Then STDERR should contain: - """ - Error: Parameter errors: - Invalid value specified for 'burrito' (This is the burrito argument.) - """ - - When I try `wp --require=test-cmd.php foo apple taco_del_mar` - Then STDERR should contain: - """ - Error: Invalid value specified for positional arg. - """ - - When I try `wp --require=test-cmd.php foo apple 'cha cha cha' taco_del_mar` - Then STDERR should contain: - """ - Error: Invalid value specified for positional arg. - """ - - When I run `wp --require=test-cmd.php foo apple 'cha cha cha'` - Then STDOUT should be YAML containing: - """ - bar: apple - shop: cha cha cha - burrito: - """ - And STDERR should be empty - - Scenario: Register a command with default and accepted arguments, part two - Given an empty directory - And a test-cmd.php file: - """ - <?php - /** - * An amazing command for managing burritos. - * - * [<burrito>] - * : This is the bar argument. - * --- - * options: - * - beans - * - veggies - * --- - * - * @when before_wp_load - */ - $foo = function( $args, $assoc_args ) { - $out = array( - 'burrito' => isset( $args[0] ) ? $args[0] : '', - ); - WP_CLI::print_value( $out, array( 'format' => 'yaml' ) ); - }; - WP_CLI::add_command( 'foo', $foo ); - """ - - When I run `wp --require=test-cmd.php foo` - Then STDOUT should be YAML containing: - """ - burrito: - """ - And STDERR should be empty - - When I run `wp --require=test-cmd.php foo beans` - Then STDOUT should be YAML containing: - """ - burrito: beans - """ - And STDERR should be empty - - When I try `wp --require=test-cmd.php foo apple` - Then STDERR should be: - """ - Error: Invalid value specified for positional arg. - """ - - Scenario: Removing a subcommand should remove it from the index - Given an empty directory - And a remove-comment.php file: - """ - <?php - $command = WP_CLI::get_root_command(); - $command->remove_subcommand( 'comment' ); - """ - - When I run `wp` - Then STDOUT should contain: - """ - Manage comments. - """ - - When I run `wp --require=remove-comment.php` - Then STDOUT should not contain: - """ - Manage comments. - """ - - Scenario: before_invoke should call subcommands - Given an empty directory - And a call-invoke.php file: - """ - <?php - /** - * @when before_wp_load - */ - $before_invoke = function() { - WP_CLI::success( 'Invoked' ); - }; - $before_invoke_args = array( 'before_invoke' => function() { - WP_CLI::success( 'before invoke' ); - }, 'after_invoke' => function() { - WP_CLI::success( 'after invoke' ); - }); - WP_CLI::add_command( 'before invoke', $before_invoke, $before_invoke_args ); - WP_CLI::add_command( 'before-invoke', $before_invoke, $before_invoke_args ); - """ - - When I run `wp --require=call-invoke.php before invoke` - Then STDOUT should contain: - """ - Success: before invoke - Success: Invoked - Success: after invoke - """ - - When I run `wp --require=call-invoke.php before-invoke` - Then STDOUT should contain: - """ - Success: before invoke - Success: Invoked - Success: after invoke - """ - - Scenario: Default arguments should respect wp-cli.yml - Given a WP install - And a wp-cli.yml file: - """ - post list: - format: count - """ - - When I run `wp post list` - Then STDOUT should be a number - - Scenario: Use class passed as object - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Foo_Class { - - public function __construct( $message ) { - $this->message = $message; - } - - /** - * My awesome class method command - * - * @when before_wp_load - */ - function message( $args ) { - WP_CLI::success( $this->message ); - } - } - $foo = new Foo_Class( 'bar' ); - WP_CLI::add_command( 'instantiated-command', $foo ); - """ - - When I run `wp --require=custom-cmd.php instantiated-command message` - Then STDOUT should contain: - """ - bar - """ - And STDERR should be empty diff --git a/features/comment-generate.feature b/features/comment-generate.feature deleted file mode 100644 index ee7cc72fd..000000000 --- a/features/comment-generate.feature +++ /dev/null @@ -1,36 +0,0 @@ -Feature: Generate comments - - Background: - Given a WP install - - Scenario: Generate a specific number of comments - When I run `wp comment generate --count=20` - And I run `wp comment list --format=count` - Then STDOUT should be: - """ - 21 - """ - - Scenario: Generate comments assigned to a specific post - When I run `wp comment generate --count=4 --post_id=2` - And I run `wp comment list --post_id=2 --format=count` - Then STDOUT should be: - """ - 4 - """ - - When I run `wp comment list --post_id=1 --format=count` - Then STDOUT should be: - """ - 1 - """ - - Scenario: Generating comments and outputting ids - When I run `wp comment generate --count=1 --format=ids` - Then save STDOUT as {COMMENT_ID} - - When I run `wp comment update {COMMENT_ID} --comment_content="foo"` - Then STDOUT should contain: - """ - Success: - """ diff --git a/features/comment-list.feature b/features/comment-list.feature deleted file mode 100644 index aa40beb57..000000000 --- a/features/comment-list.feature +++ /dev/null @@ -1,31 +0,0 @@ -Feature: List WordPress comments - - @require-wp-4.1 - Scenario: Filter comments based on `comment__in` and `comment__not_in` - Given a WP install - - When I run `wp comment create --comment_post_ID=1 --porcelain` - Then save STDOUT as {COMMENT_ID} - - When I run `wp comment list --comment__in=1,{COMMENT_ID} --format=ids --orderby=comment_ID --order=ASC` - Then STDOUT should be: - """ - 1 {COMMENT_ID} - """ - - When I run `wp comment list --comment__in=1 --format=ids --orderby=comment_ID --order=ASC` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment list --comment__not_in=1,{COMMENT_ID} --format=ids --orderby=comment_ID --order=ASC` - Then STDOUT should be: - """ - """ - - When I run `wp comment list --comment__not_in=1 --format=ids --orderby=comment_ID --order=ASC` - Then STDOUT should be: - """ - {COMMENT_ID} - """ diff --git a/features/comment-meta.feature b/features/comment-meta.feature deleted file mode 100644 index 12f459211..000000000 --- a/features/comment-meta.feature +++ /dev/null @@ -1,56 +0,0 @@ -Feature: Manage comment custom fields - - Scenario: Comment meta CRUD - Given a WP install - - When I run `wp comment-meta add 1 foo 'bar'` - Then STDOUT should not be empty - - When I run `wp comment-meta get 1 foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp comment meta get 999999 foo` - Then STDERR should be: - """ - Error: Could not find the comment with ID 999999. - """ - - When I run `wp comment-meta set 1 foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run `wp comment-meta get 1 foo --format=json` - Then STDOUT should be: - """ - ["1","2"] - """ - - When I run `wp comment-meta delete 1 foo` - Then STDOUT should not be empty - - When I try `wp comment-meta get 1 foo` - Then the return code should be 1 - - Scenario: Add comment meta with JSON serialization - Given a WP install - - When I try `wp comment meta add 1 foo '-- hi'` - Then STDERR should be: - """ - Error: Parameter errors: - unknown -- hi parameter - """ - - When I run `wp comment meta add 1 foo '"-- hi"' --format=json` - Then STDOUT should contain: - """ - Success: - """ - - When I run `wp comment meta get 1 foo` - Then STDOUT should be: - """ - -- hi - """ diff --git a/features/comment-recount.feature b/features/comment-recount.feature deleted file mode 100644 index 7208b97bd..000000000 --- a/features/comment-recount.feature +++ /dev/null @@ -1,25 +0,0 @@ -Feature: Recount comments on a post - - Scenario: Recount comments on a post - Given a WP install - - When I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` - And I run `wp comment create --comment_post_ID=1 --comment_approved=1 --porcelain` - And I run `wp post get 1 --field=comment_count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) );'` - And I run `wp post get 1 --field=comment_count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment recount 1` - Then STDOUT should be: - """ - Updated post 1 comment count to 3. - """ diff --git a/features/comment.feature b/features/comment.feature deleted file mode 100644 index 484c6e791..000000000 --- a/features/comment.feature +++ /dev/null @@ -1,288 +0,0 @@ -Feature: Manage WordPress comments - - Background: - Given a WP install - - Scenario: Creating/updating/deleting comments - When I run `wp comment create --comment_post_ID=1 --comment_content='Hello' --comment_author='Billy' --porcelain` - Then STDOUT should be a number - And save STDOUT as {COMMENT_ID} - - When I run `wp comment exists {COMMENT_ID}` - Then STDOUT should be: - """ - Success: Comment with ID {COMMENT_ID} exists. - """ - - When I run `wp comment update {COMMENT_ID} --comment_author='Johnny'` - Then STDOUT should not be empty - - When I run `wp comment get {COMMENT_ID} --field=author` - Then STDOUT should be: - """ - Johnny - """ - - When I run `wp comment delete {COMMENT_ID}` - Then STDOUT should be: - """ - Success: Trashed comment {COMMENT_ID}. - """ - - When I run `wp comment get {COMMENT_ID} --field=comment_approved` - Then STDOUT should be: - """ - trash - """ - - When I run `wp comment delete {COMMENT_ID} --force` - Then STDOUT should be: - """ - Success: Deleted comment {COMMENT_ID}. - """ - - When I try `wp comment get {COMMENT_ID}` - Then STDERR should be: - """ - Error: Invalid comment ID. - """ - - When I run `wp comment create --comment_post_ID=1` - And I run `wp comment create --comment_post_ID=1` - And I run `wp comment delete 3 4` - Then STDOUT should be: - """ - Success: Trashed comment 3. - Success: Trashed comment 4. - """ - - When I run `wp comment delete 3` - Then STDOUT should be: - """ - Success: Deleted comment 3. - """ - - When I try `wp comment get 3` - Then STDERR should be: - """ - Error: Invalid comment ID. - """ - - Scenario: Get details about an existing comment - When I run `wp comment get 1` - Then STDOUT should be a table containing rows: - | Field | Value | - | comment_approved | 1 | - - When I run `wp comment get 1 --fields=comment_approved --format=json` - Then STDOUT should be JSON containing: - """ - {"comment_approved":"1"} - """ - - When I run `wp comment list --fields=comment_approved` - Then STDOUT should be a table containing rows: - | comment_approved | - | 1 | - - When I run `wp comment list --field=approved` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment list --format=ids` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment url 1` - Then STDOUT should contain: - """ - #comment-1 - """ - - Scenario: List the URLs of comments - When I run `wp comment create --comment_post_ID=1 --porcelain` - Then save STDOUT as {COMMENT_ID} - - When I run `wp comment url 1 {COMMENT_ID}` - Then STDOUT should be: - """ - http://example.com/?p=1#comment-1 - http://example.com/?p=1#comment-{COMMENT_ID} - """ - - When I run `wp comment url {COMMENT_ID} 1` - Then STDOUT should be: - """ - http://example.com/?p=1#comment-{COMMENT_ID} - http://example.com/?p=1#comment-1 - """ - - Scenario: Count comments - When I run `wp comment count 1` - Then STDOUT should contain: - """ - approved: 1 - """ - And STDOUT should contain: - """ - moderated: 0 - """ - And STDOUT should contain: - """ - total_comments: 1 - """ - - When I run `wp comment count` - Then STDOUT should contain: - """ - approved: 1 - """ - And STDOUT should contain: - """ - moderated: 0 - """ - And STDOUT should contain: - """ - total_comments: 1 - """ - - Scenario: Approving/unapproving comments - Given I run `wp comment create --comment_post_ID=1 --comment_approved=0 --porcelain` - And save STDOUT as {COMMENT_ID} - - When I run `wp comment approve {COMMENT_ID}` - Then STDOUT should contain: - """ - Approved comment {COMMENT_ID} - """ - - When I run `wp comment get --field=comment_approved {COMMENT_ID}` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment unapprove {COMMENT_ID}` - Then STDOUT should contain: - """ - Unapproved comment {COMMENT_ID} - """ - - When I run `wp comment get --field=comment_approved {COMMENT_ID}` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Approving/unapproving comments with multidigit comment ID - Given I run `wp comment delete $(wp comment list --field=ID)` - And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` - And save STDOUT as {COMMENT_ID} - - When I run `wp comment unapprove {COMMENT_ID}` - Then STDOUT should contain: - """ - Unapproved comment {COMMENT_ID} - """ - - When I run `wp comment list --format=count --status=approve` - Then STDOUT should be: - """ - 10 - """ - - When I run `wp comment approve {COMMENT_ID}` - Then STDOUT should contain: - """ - Approved comment {COMMENT_ID} - """ - - When I run `wp comment list --format=count --status=approve` - Then STDOUT should be: - """ - 11 - """ - - Scenario: Spam/unspam comments with multidigit comment ID - Given I run `wp comment delete $(wp comment list --field=ID)` - And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` - And save STDOUT as {COMMENT_ID} - - When I run `wp comment spam {COMMENT_ID}` - Then STDOUT should contain: - """ - Marked as spam comment {COMMENT_ID}. - """ - - When I run `wp comment list --format=count --status=spam` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment unspam {COMMENT_ID}` - Then STDOUT should contain: - """ - Unspammed comment {COMMENT_ID}. - """ - - When I run `wp comment list --format=count --status=spam` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Trash/untrash comments with multidigit comment ID - Given I run `wp comment delete $(wp comment list --field=ID) --force` - And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` - And save STDOUT as {COMMENT_ID} - - When I run `wp comment trash {COMMENT_ID}` - Then STDOUT should contain: - """ - Success: Trashed comment {COMMENT_ID}. - """ - - When I run `wp comment list --format=count --status=trash` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp comment untrash {COMMENT_ID}` - Then STDOUT should contain: - """ - Untrashed comment {COMMENT_ID}. - """ - - When I run `wp comment list --format=count --status=trash` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Make sure WordPress receives the slashed data it expects - When I run `wp comment create --comment_content='My\Comment' --porcelain` - Then save STDOUT as {COMMENT_ID} - - When I run `wp comment get {COMMENT_ID} --field=comment_content` - Then STDOUT should be: - """ - My\Comment - """ - - When I run `wp comment update {COMMENT_ID} --comment_content='My\New\Comment'` - Then STDOUT should not be empty - - When I run `wp comment get {COMMENT_ID} --field=comment_content` - Then STDOUT should be: - """ - My\New\Comment - """ diff --git a/features/config.feature b/features/config.feature deleted file mode 100644 index a22572b56..000000000 --- a/features/config.feature +++ /dev/null @@ -1,536 +0,0 @@ -Feature: Have a config file - - Scenario: No config file - Given a WP install - - When I run `wp --info` - Then STDOUT should not contain: - """ - wp-cli.yml - """ - - When I run `wp core is-installed` from 'wp-content' - Then STDOUT should be empty - - Scenario: Config file in WP Root - Given a WP install - And a sample.php file: - """ - <?php - """ - And a wp-cli.yml file: - """ - require: sample.php - """ - - When I run `wp --info` - Then STDOUT should contain: - """ - wp-cli.yml - """ - - When I run `wp core is-installed` - Then STDOUT should be empty - - When I run `wp` from 'wp-content' - Then STDOUT should not be empty - - Scenario: WP in a subdirectory - Given a WP install in 'core' - And a wp-cli.yml file: - """ - path: core - """ - - When I run `wp --info` - Then STDOUT should contain: - """ - wp-cli.yml - """ - - When I run `wp core is-installed` - Then STDOUT should be empty - - When I run `wp core is-installed` from 'core/wp-content' - Then STDOUT should be empty - - When I run `mkdir -p other/subdir` - And I run `wp core is-installed` from 'other/subdir' - Then STDOUT should be empty - - Scenario: WP in a subdirectory (autodetected) - Given a WP install in 'core' - - Given an index.php file: - """ - require('./core/wp-blog-header.php'); - """ - When I run `wp core is-installed` - Then STDOUT should be empty - - Given an index.php file: - """ - require dirname(__FILE__) . '/core/wp-blog-header.php'; - """ - When I run `wp core is-installed` - Then STDOUT should be empty - - When I run `mkdir -p other/subdir` - And I run `echo '<?php // Silence is golden' > other/subdir/index.php` - And I run `wp core is-installed` from 'other/subdir' - Then STDOUT should be empty - - Scenario: Nested installs - Given a WP install - And a WP install in 'subsite' - And a wp-cli.yml file: - """ - """ - - When I run `wp --info` from 'subsite' - Then STDOUT should not contain: - """ - wp-cli.yml - """ - - Scenario: Disabled commands - Given a WP install - And a config.yml file: - """ - disabled_commands: - - eval-file - - core multisite-convert - """ - - When I run `WP_CLI_CONFIG_PATH=config.yml wp` - Then STDOUT should not contain: - """ - eval-file - """ - - When I try `WP_CLI_CONFIG_PATH=config.yml wp help eval-file` - Then STDERR should be: - """ - Error: The 'eval-file' command has been disabled from the config file. - """ - - When I run `WP_CLI_CONFIG_PATH=config.yml wp core` - Then STDOUT should not contain: - """ - or: wp core multisite-convert - """ - - When I run `WP_CLI_CONFIG_PATH=config.yml wp help core` - Then STDOUT should not contain: - """ - multisite-convert - """ - - When I try `WP_CLI_CONFIG_PATH=config.yml wp core multisite-convert` - Then STDERR should contain: - """ - command has been disabled - """ - - When I try `WP_CLI_CONFIG_PATH=config.yml wp help core multisite-convert` - Then STDERR should contain: - """ - Error: The 'core multisite-convert' command has been disabled from the config file. - """ - - Scenario: 'core config' parameters - Given an empty directory - And WP files - And a wp-cli.yml file: - """ - core config: - dbname: wordpress - dbuser: root - extra-php: | - define( 'WP_DEBUG', true ); - define( 'WP_POST_REVISIONS', 50 ); - """ - - When I run `wp core config --skip-check` - And I run `grep WP_POST_REVISIONS wp-config.php` - Then STDOUT should not be empty - - Scenario: Persist positional parameters when defined in a config - Given a WP install - And a wp-cli.yml file: - """ - user create: - - examplejoe - - joe@example.com - user_pass: joe - role: administrator - """ - - When I run `wp user create` - Then STDOUT should not be empty - - When I run `wp user get examplejoe --field=roles` - Then STDOUT should contain: - """ - administrator - """ - - When I try `wp user create examplejane` - Then STDERR should be: - """ - Error: Sorry, that email address is already used! - """ - - When I run `wp user create examplejane jane@example.com` - Then STDOUT should not be empty - - When I run `wp user get examplejane --field=roles` - Then STDOUT should contain: - """ - administrator - """ - - Scenario: Command-specific configs - Given a WP install - And a wp-cli.yml file: - """ - eval: - foo: bar - post list: - format: count - """ - - # Arbitrary values should be passed, without warnings - When I run `wp eval 'echo json_encode( $assoc_args );'` - Then STDOUT should be JSON containing: - """ - {"foo": "bar"} - """ - - # CLI args should trump config values - When I run `wp post list` - Then STDOUT should be a number - When I run `wp post list --format=json` - Then STDOUT should not be a number - - Scenario: Required files should not be loaded twice - Given an empty directory - And a custom-file.php file: - """ - <?php - define( 'FOOBUG', 'BAR' ); - """ - And a test-dir/config.yml file: - """ - require: - - ../custom-file.php - """ - And a wp-cli.yml file: - """ - require: - - custom-file.php - """ - - When I run `WP_CLI_CONFIG_PATH=test-dir/config.yml wp help` - Then STDERR should be empty - - Scenario: Load WordPress with `--debug` - Given a WP install - - When I run `wp option get home --debug` - Then STDERR should contain: - """ - No readable global config found - """ - Then STDERR should contain: - """ - No project config found - """ - And STDERR should contain: - """ - Begin WordPress load - """ - And STDERR should contain: - """ - wp-config.php path: - """ - And STDERR should contain: - """ - Loaded WordPress - """ - And STDERR should contain: - """ - Running command: option get - """ - - When I run `wp option get home --debug=bootstrap` - Then STDERR should contain: - """ - No readable global config found - """ - Then STDERR should contain: - """ - No project config found - """ - And STDERR should contain: - """ - Begin WordPress load - """ - And STDERR should contain: - """ - wp-config.php path: - """ - And STDERR should contain: - """ - Loaded WordPress - """ - And STDERR should contain: - """ - Running command: option get - """ - - When I run `wp option get home --debug=foo` - Then STDERR should not contain: - """ - No readable global config found - """ - Then STDERR should not contain: - """ - No project config found - """ - And STDERR should not contain: - """ - Begin WordPress load - """ - And STDERR should not contain: - """ - wp-config.php path: - """ - And STDERR should not contain: - """ - Loaded WordPress - """ - And STDERR should not contain: - """ - Running command: option get - """ - - Scenario: Missing required files should not fatal WP-CLI - Given an empty directory - And a wp-cli.yml file: - """ - require: - - missing-file.php - """ - - When I try `wp help` - Then STDERR should contain: - """ - Error: Required file 'missing-file.php' doesn't exist (from project's wp-cli.yml). - """ - - When I run `wp cli info` - Then STDOUT should not be empty - - When I run `wp --info` - Then STDOUT should not be empty - - Scenario: Missing required file in global config - Given an empty directory - And a config.yml file: - """ - require: - - /foo/baz.php - """ - - When I try `WP_CLI_CONFIG_PATH=config.yml wp help` - Then STDERR should contain: - """ - Error: Required file 'baz.php' doesn't exist (from global config.yml). - """ - - Scenario: Missing required file as runtime argument - Given an empty directory - - When I try `wp help --require=foo.php` - Then STDERR should contain: - """ - Error: Required file 'foo.php' doesn't exist (from runtime argument). - """ - - Scenario: Config inheritance from project to global - Given an empty directory - And a test-cmd.php file: - """ - <?php - $command = function( $_, $assoc_args ) { - echo json_encode( $assoc_args ); - }; - WP_CLI::add_command( 'test-cmd', $command, array( 'when' => 'before_wp_load' ) ); - """ - And a config.yml file: - """ - test-cmd: - foo: bar - apple: banana - apple: banana - """ - And a wp-cli.yml file: - """ - _: - merge: true - test-cmd: - bar: burrito - apple: apple - apple: apple - """ - - When I run `wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"bar":"burrito","apple":"apple"} - """ - When I run `WP_CLI_CONFIG_PATH=config.yml wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"foo":"bar","apple":"apple","bar":"burrito"} - """ - - Given a wp-cli.yml file: - """ - _: - merge: false - test-cmd: - bar: burrito - apple: apple - apple: apple - """ - When I run `WP_CLI_CONFIG_PATH=config.yml wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"bar":"burrito","apple":"apple"} - """ - - Scenario: Config inheritance from local to project - Given an empty directory - And a test-cmd.php file: - """ - <?php - $command = function( $_, $assoc_args ) { - echo json_encode( $assoc_args ); - }; - WP_CLI::add_command( 'test-cmd', $command, array( 'when' => 'before_wp_load' ) ); - """ - And a wp-cli.yml file: - """ - test-cmd: - foo: bar - apple: banana - apple: banana - """ - - When I run `wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"foo":"bar","apple":"banana"} - """ - - Given a wp-cli.local.yml file: - """ - _: - inherit: wp-cli.yml - merge: true - test-cmd: - bar: burrito - apple: apple - apple: apple - """ - - When I run `wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"foo":"bar","apple":"apple","bar":"burrito"} - """ - - Given a wp-cli.local.yml file: - """ - test-cmd: - bar: burrito - apple: apple - apple: apple - """ - - When I run `wp --require=test-cmd.php test-cmd` - Then STDOUT should be JSON containing: - """ - {"bar":"burrito","apple":"apple"} - """ - - @require-wp-3.9 - Scenario: WordPress install with local dev DOMAIN_CURRENT_SITE - Given a WP multisite install - And a local-dev.php file: - """ - <?php - define( 'DOMAIN_CURRENT_SITE', 'example.dev' ); - """ - And a wp-config.php file: - """ -<?php -if ( file_exists( __DIR__ . '/local-dev.php' ) ) { - require_once __DIR__ . '/local-dev.php'; -} - -// ** MySQL settings ** // -/** The name of the database for WordPress */ -define('DB_NAME', 'wp_cli_test'); - -/** MySQL database username */ -define('DB_USER', 'wp_cli_test'); - -/** MySQL database password */ -define('DB_PASSWORD', 'password1'); - -/** MySQL hostname */ -define('DB_HOST', '127.0.0.1'); - -/** Database Charset to use in creating database tables. */ -define('DB_CHARSET', 'utf8'); - -/** The Database Collate type. Don't change this if in doubt. */ -define('DB_COLLATE', ''); - -$table_prefix = 'wp_'; - -define( 'WP_ALLOW_MULTISITE', true ); -define('MULTISITE', true); -define('SUBDOMAIN_INSTALL', false); -$base = '/'; -if ( ! defined( 'DOMAIN_CURRENT_SITE' ) ) { - define('DOMAIN_CURRENT_SITE', 'example.com'); -} -define('PATH_CURRENT_SITE', '/'); -define('SITE_ID_CURRENT_SITE', 1); -define('BLOG_ID_CURRENT_SITE', 1); - -/* That's all, stop editing! Happy blogging. */ - -/** Absolute path to the WordPress directory. */ -if ( !defined('ABSPATH') ) - define('ABSPATH', dirname(__FILE__) . '/'); - -/** Sets up WordPress vars and included files. */ -require_once(ABSPATH . 'wp-settings.php'); - """ - - When I try `wp option get home` - Then STDERR should be: - """ - Error: Site example.dev/ not found. - """ - - When I run `wp option get home --url=example.com` - Then STDOUT should be: - """ - http://example.com - """ diff --git a/features/core-check-update.feature b/features/core-check-update.feature deleted file mode 100644 index 7d85c597c..000000000 --- a/features/core-check-update.feature +++ /dev/null @@ -1,56 +0,0 @@ -Feature: Check for more recent versions - - Scenario: Check for update via Version Check API - Given a WP install - - When I run `wp core download --version=4.4 --force` - Then STDOUT should not be empty - - When I run `wp core check-update` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.7.3 | major | https://downloads.wordpress.org/release/wordpress-4.7.3.zip | - | 4.4.8 | minor | https://downloads.wordpress.org/release/wordpress-4.4.8-partial-0.zip | - - When I run `wp core check-update --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp core check-update --major` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.7.3 | major | https://downloads.wordpress.org/release/wordpress-4.7.3.zip | - - When I run `wp core check-update --major --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp core check-update --minor` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.4.8 | minor | https://downloads.wordpress.org/release/wordpress-4.4.8-partial-0.zip | - - When I run `wp core check-update --minor --format=count` - Then STDOUT should be: - """ - 1 - """ - - @less-than-php-7 - Scenario: No minor updates for an unlocalized WordPress release - Given a WP install - - When I run `wp core download --version=4.0 --locale=es_ES --force` - Then STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - When I run `wp core check-update --minor` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 4.0.16 | minor | https://downloads.wordpress.org/release/wordpress-4.0.16-partial-0.zip | diff --git a/features/core-config.feature b/features/core-config.feature deleted file mode 100644 index f4fbfeec1..000000000 --- a/features/core-config.feature +++ /dev/null @@ -1,99 +0,0 @@ -Feature: Manage wp-config - - Scenario: No wp-config.php - Given an empty directory - And WP files - - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp core version` - Then STDOUT should not be empty - - When I try `wp core install` - Then the return code should be 1 - And STDERR should be: - """ - Error: 'wp-config.php' not found. - Either create one manually or use `wp core config`. - """ - - Given a wp-config-extra.php file: - """ - define( 'WP_DEBUG_LOG', true ); - """ - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` - Then the wp-config.php file should contain: - """ - define('AUTH_SALT', - """ - And the wp-config.php file should contain: - """ - define( 'WP_DEBUG_LOG', true ); - """ - - When I try the previous command again - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp db create` - Then STDOUT should not be empty - - When I try `wp option get option home` - Then STDERR should contain: - """ - Error: The site you have requested is not installed - """ - - @require-wp-4.0 - Scenario: No wp-config.php and WPLANG - Given an empty directory - And WP files - Given a wp-config-extra.php file: - """ - define( 'WP_DEBUG_LOG', true ); - """ - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` - Then the wp-config.php file should not contain: - """ - define( 'WPLANG', '' ); - """ - - Scenario: Configure with existing salts - Given an empty directory - And WP files - - When I run `wp core config {CORE_CONFIG_SETTINGS} --skip-salts --extra-php < /dev/null` - Then the wp-config.php file should not contain: - """ - define('AUTH_SALT', - """ - - Scenario: Define WPLANG when running WP < 4.0 - Given an empty directory - And I run `wp core download --version=3.9 --force` - - When I run `wp core config {CORE_CONFIG_SETTINGS}` - Then the wp-config.php file should contain: - """ - define( 'WPLANG', '' ); - """ - - When I try `wp core config {CORE_CONFIG_SETTINGS}` - Then the return code should be 1 - And STDERR should contain: - """ - Error: The 'wp-config.php' file already exists. - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS} --locale=ja --force` - Then the return code should be 0 - And STDOUT should contain: - """ - Success: Generated 'wp-config.php' file. - """ - And the wp-config.php file should contain: - """ - define( 'WPLANG', 'ja' ); - """ diff --git a/features/core-download.feature b/features/core-download.feature deleted file mode 100644 index 33ef6217f..000000000 --- a/features/core-download.feature +++ /dev/null @@ -1,227 +0,0 @@ -Feature: Download WordPress - - Scenario: Empty dir - Given an empty directory - And an empty cache - - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp core download` - And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} - Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist - - When I run `mkdir inner` - And I run `cd inner && wp core download` - Then the inner/wp-settings.php file should exist - - # test core tarball cache - When I run `wp core download --force` - Then the wp-settings.php file should exist - And STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz'... - """ - - Scenario: Localized install - Given an empty directory - And an empty cache - When I run `wp core download --version=4.4.2 --locale=de_DE` - And save STDOUT 'Downloading WordPress ([\d\.]+)' as {VERSION} - Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist - - Scenario: Catch download of non-existent WP version - Given an empty directory - - When I try `wp core download --version=4.1.0 --force` - Then STDERR should contain: - """ - Error: Release not found. - """ - - Scenario: Verify release hash when downloading new version - Given an empty directory - - When I run `wp core download --version=4.4.1` - Then STDOUT should contain: - """ - md5 hash verified: 1907d1dbdac7a009d89224a516496b8d - Success: WordPress downloaded. - """ - - Scenario: Core download to a directory specified by `--path` in custom command - Given a WP install - And a download-command.php file: - """ - <?php - class Download_Command extends WP_CLI_Command { - public function __invoke() { - WP_CLI::run_command( array( 'core', 'download' ), array( 'path' => 'src/' ) ); - } - } - WP_CLI::add_command( 'custom-download', 'Download_Command' ); - """ - - When I run `wp --require=download-command.php custom-download` - Then STDOUT should not be empty - And the src directory should contain: - """ - wp-load.php - """ - - When I try `wp --require=download-command.php custom-download` - Then STDERR should be: - """ - Error: WordPress files seem to already be present here. - """ - - Scenario: Make sure files are cleaned up - Given an empty directory - When I run `wp core download --version=4.4` - Then the wp-includes/rest-api.php file should exist - Then the wp-includes/class-wp-comment.php file should exist - And STDERR should not contain: - """ - Warning: Failed to find WordPress version. Please cleanup files manually. - """ - - When I run `wp core download --version=4.3.2 --force` - Then the wp-includes/rest-api.php file should not exist - Then the wp-includes/class-wp-comment.php file should not exist - And STDOUT should not contain: - """ - File removed: wp-content - """ - - Scenario: Installing nightly - Given an empty directory - And an empty cache - - When I run `wp core download --version=nightly` - Then the wp-settings.php file should exist - And the {SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip file should not exist - And STDOUT should contain: - """ - Downloading WordPress nightly (en_US)... - """ - And STDERR should contain: - """ - Warning: md5 hash checks are not available for nightly downloads. - """ - And STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - # we shouldn't cache nightly builds - When I run `wp core download --version=nightly --force` - Then the wp-settings.php file should exist - And STDOUT should not contain: - """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-nightly-en_US.zip'... - """ - - Scenario: Installing nightly over an existing install - Given an empty directory - And an empty cache - When I run `wp core download --version=4.5.3` - Then the wp-settings.php file should exist - When I run `wp core download --version=nightly --force` - Then STDERR should not contain: - """ - Warning: Failed to find WordPress version. Please cleanup files manually. - """ - And STDERR should contain: - """ - Warning: Failed to fetch checksums. Please cleanup files manually. - """ - And STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - Scenario: Installing a version over nightly - Given an empty directory - And an empty cache - When I run `wp core download --version=nightly` - Then the wp-settings.php file should exist - And STDERR should not contain: - """ - Warning: Failed to find WordPress version. Please cleanup files manually. - """ - - When I run `wp core download --version=4.3.2 --force` - Then the wp-includes/rest-api.php file should not exist - And the wp-includes/class-wp-comment.php file should not exist - And STDOUT should not contain: - """ - File removed: wp-content - """ - - Scenario: Trunk is an alias for nightly - Given an empty directory - And an empty cache - When I run `wp core download --version=trunk` - Then the wp-settings.php file should exist - And STDOUT should contain: - """ - Downloading WordPress nightly (en_US)... - """ - And STDERR should contain: - """ - Warning: md5 hash checks are not available for nightly downloads. - """ - And STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - Scenario: Installing nightly for a non-default locale - Given an empty directory - And an empty cache - - When I try `wp core download --version=nightly --locale=de_DE` - Then the return code should be 1 - And STDERR should contain: - """ - Error: Nightly builds are only available for the en_US locale. - """ - - Scenario: Installing a release candidate or beta version - Given an empty directory - And an empty cache - - # Test with incorrect case. - When I try `wp core download --version=4.6-rc2` - Then the return code should be 1 - Then STDERR should contain: - """ - Error: Release not found. - """ - - When I run `wp core download --version=4.6-RC2` - Then the wp-settings.php file should exist - And STDOUT should contain: - """ - Downloading WordPress 4.6-RC2 (en_US)... - md5 hash verified: 90c93a15092b2d5d4c960ec1fc183e07 - Success: WordPress downloaded. - """ - - Scenario: Using --version=latest should produce a cache key of the version number, not 'latest' - Given an empty directory - And an empty cache - - When I run `wp core download --version=latest` - Then STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - When I run `wp core version` - Then save STDOUT as {VERSION} - And the {SUITE_CACHE_DIR}/core/wordpress-latest-en_US.tar.gz file should not exist - And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-en_US.tar.gz file should exist diff --git a/features/core-install.feature b/features/core-install.feature deleted file mode 100644 index c71244e8f..000000000 --- a/features/core-install.feature +++ /dev/null @@ -1,186 +0,0 @@ -Feature: Install WordPress core - - Scenario: Two WordPress installs sharing the same user table won't update existing user - Given an empty directory - And WP files - And a WP install in 'second' - And a extra-config file: - """ - define( 'CUSTOM_USER_TABLE', 'secondusers' ); - define( 'CUSTOM_USER_META_TABLE', 'secondusermeta' ); - """ - - When I run `wp --path=second user create testadmin testadmin@example.org --role=administrator` - Then STDOUT should contain: - """ - Success: Created user 2. - """ - - When I run `wp --path=second db tables` - Then STDOUT should contain: - """ - secondposts - """ - And STDOUT should contain: - """ - secondusers - """ - - When I run `wp --path=second user list --field=user_login` - Then STDOUT should be: - """ - admin - testadmin - """ - - When I run `wp --path=second user get testadmin --field=user_pass` - Then save STDOUT as {ORIGINAL_PASSWORD} - - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` - Then STDOUT should be: - """ - Success: Generated 'wp-config.php' file. - """ - - When I run `wp core install --url=example.org --title=Test --admin_user=testadmin --admin_email=testadmin@example.com --admin_password=newpassword` - Then STDOUT should contain: - """ - Success: WordPress installed successfully. - """ - - When I run `wp user list --field=user_login` - Then STDOUT should be: - """ - admin - testadmin - """ - - When I run `wp user get testadmin --field=email` - Then STDOUT should be: - """ - testadmin@example.org - """ - - When I run `wp user get testadmin --field=user_pass` - Then STDOUT should be: - """ - {ORIGINAL_PASSWORD} - """ - - When I run `wp db tables` - Then STDOUT should contain: - """ - wp_posts - """ - And STDOUT should contain: - """ - secondusers - """ - And STDOUT should not contain: - """ - wp_users - """ - - Scenario: Two WordPress installs sharing the same user table will create new user - Given an empty directory - And WP files - And a WP install in 'second' - And a extra-config file: - """ - define( 'CUSTOM_USER_TABLE', 'secondusers' ); - define( 'CUSTOM_USER_META_TABLE', 'secondusermeta' ); - """ - - When I run `wp --path=second db tables` - Then STDOUT should contain: - """ - secondposts - """ - And STDOUT should contain: - """ - secondusers - """ - - When I run `wp --path=second user list --field=user_login` - Then STDOUT should be: - """ - admin - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` - Then STDOUT should be: - """ - Success: Generated 'wp-config.php' file. - """ - - When I run `wp core install --url=example.org --title=Test --admin_user=testadmin --admin_email=testadmin@example.com --admin_password=newpassword` - Then STDOUT should contain: - """ - Success: WordPress installed successfully. - """ - - When I run `wp user list --field=user_login` - Then STDOUT should be: - """ - admin - testadmin - """ - - When I run `wp --path=second user list --field=user_login` - Then STDOUT should be: - """ - admin - testadmin - """ - - When I run `wp user get testadmin --field=email` - Then STDOUT should be: - """ - testadmin@example.com - """ - - When I run `wp db tables` - Then STDOUT should contain: - """ - wp_posts - """ - And STDOUT should contain: - """ - secondusers - """ - And STDOUT should not contain: - """ - wp_users - """ - - Scenario: Install WordPress without specifying the admin password - Given an empty directory - And WP files - And wp-config.php - And a database - - When I run `wp core install --url=localhost:8001 --title=Test --admin_user=wpcli --admin_email=wpcli@example.org` - Then STDOUT should contain: - """ - Admin password: - """ - And STDOUT should contain: - """ - Success: WordPress installed successfully. - """ - - Scenario: Install WordPress multisite without specifying the password - Given an empty directory - And WP files - And wp-config.php - And a database - - When I run `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com` - Then STDOUT should contain: - """ - Admin password: - """ - And STDOUT should contain: - """ - Success: Network installed. Don't forget to set up rewrite rules. - """ diff --git a/features/core-language.feature b/features/core-language.feature deleted file mode 100644 index d83121777..000000000 --- a/features/core-language.feature +++ /dev/null @@ -1,177 +0,0 @@ -Feature: Manage translation files for a WordPress install - - @require-wp-4.0 - Scenario: Core translation CRUD - Given a WP install - And an empty cache - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_US | English (United States) | active | - | en_GB | English (UK) | uninstalled | - - When I run `wp core language install en_GB` - And I run `wp core language install en_AU` - Then the wp-content/languages/admin-en_GB.po file should exist - And the wp-content/languages/en_GB.po file should exist - And STDOUT should contain: - """ - Success: Language installed. - """ - And STDERR should be empty - - When I run `ls {SUITE_CACHE_DIR}/translation | grep core-default-` - Then STDOUT should contain: - """ - en_AU - """ - And STDOUT should contain: - """ - en_GB - """ - - When I try `wp core language install en_AU` - Then STDERR should be: - """ - Warning: Language 'en_AU' already installed. - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_GB | English (UK) | installed | - - When I run `wp core language activate en_GB` - Then STDOUT should be: - """ - Success: Language activated. - """ - - When I run `wp core language list --fields=language,english_name,update` - Then STDOUT should be a table containing rows: - | language | english_name | update | - | ar | Arabic | none | - | az | Azerbaijani | none | - | en_AU | English (Australia) | available | - | en_US | English (United States) | none | - | en_GB | English (UK) | available | - - When I run `wp core language update --dry-run` - Then save STDOUT 'Available (\d+) translations updates' as {UPDATES} - - When I run `wp core language update` - Then STDOUT should contain: - """ - Success: Updated {UPDATES}/{UPDATES} translations. - """ - And the wp-content/languages/plugins directory should exist - And the wp-content/languages/themes directory should exist - - When I run `wp core language list --field=language --status=active` - Then STDOUT should be: - """ - en_GB - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | az | Azerbaijani | uninstalled | - | en_GB | English (UK) | active | - - When I run `wp core language install en_AU --activate` - Then STDERR should contain: - """ - Warning: Language 'en_AU' already installed. - """ - And STDOUT should contain: - """ - Success: Language activated. - """ - - When I run `wp core language install en_AU --activate` - Then STDERR should contain: - """ - Warning: Language 'en_AU' already installed. - Warning: Language 'en_AU' already active. - """ - And STDOUT should be empty - - When I run `wp core language activate en_US` - Then STDOUT should be: - """ - Success: Language activated. - """ - - When I run `wp core language list --fields=language,english_name,status` - Then STDOUT should be a table containing rows: - | language | english_name | status | - | ar | Arabic | uninstalled | - | en_US | English (United States) | active | - | en_GB | English (UK) | installed | - - When I try `wp core language activate invalid_lang` - Then STDERR should be: - """ - Error: Language not installed. - """ - - When I run `wp core language uninstall en_GB` - Then the wp-content/languages/admin-en_GB.po file should not exist - And the wp-content/languages/en_GB.po file should not exist - And STDOUT should be: - """ - Success: Language uninstalled. - """ - - When I try `wp core language uninstall en_GB` - Then STDERR should be: - """ - Error: Language not installed. - """ - - When I run `wp core language install en_GB --activate` - Then the wp-content/languages/admin-en_GB.po file should exist - And the wp-content/languages/en_GB.po file should exist - And STDOUT should contain: - """ - Success: Language installed. - Success: Language activated. - """ - And STDERR should be empty - - When I try `wp core language install invalid_lang` - Then STDERR should be: - """ - Error: Language 'invalid_lang' not found. - """ - - @require-wp-4.0 - Scenario: Don't allow active language to be uninstalled - Given a WP install - - When I run `wp core language install en_GB --activate` - Then STDOUT should not be empty - - When I try `wp core language uninstall en_GB` - Then STDERR should be: - """ - Warning: The 'en_GB' language is active. - """ - - @require-wp-4.0 - Scenario: Ensure correct language is installed for WP version - Given a WP install - And I run `wp core download --version=4.5.3 --force` - - When I run `wp core language install nl_NL` - Then STDOUT should contain: - """ - Downloading translation from https://downloads.wordpress.org/translation/core/4.5.3 - """ diff --git a/features/core-update-db.feature b/features/core-update-db.feature deleted file mode 100644 index cf4f315f5..000000000 --- a/features/core-update-db.feature +++ /dev/null @@ -1,128 +0,0 @@ -Feature: Update core's database - - Scenario: Update db on a single site - Given a WP install - And I run `wp core download --version=4.1 --force` - And I run `wp option update db_version 29630` - - When I run `wp core update-db` - Then STDOUT should contain: - """ - Success: WordPress database upgraded successfully from db version 29630 to 30133. - """ - - When I run `wp core update-db` - Then STDOUT should contain: - """ - Success: WordPress database already at latest db version 30133. - """ - - Scenario: Dry run update db on a single site - Given a WP install - And I run `wp core download --version=4.1 --force` - And I run `wp option update db_version 29630` - - When I run `wp core update-db --dry-run` - Then STDOUT should be: - """ - Performing a dry run, with no database modification. - Success: WordPress database will be upgraded from db version 29630 to 30133. - """ - - When I run `wp option get db_version` - Then STDOUT should be: - """ - 29630 - """ - - Scenario: Update db across network - Given a WP multisite install - And I run `wp core download --version=4.1 --force` - And I run `wp option update db_version 29630` - And I run `wp site option update wpmu_upgrade_site 29630` - And I run `wp site create --slug=foo` - And I run `wp site create --slug=bar` - And I run `wp site create --slug=burrito --porcelain` - And save STDOUT as {BURRITO_ID} - And I run `wp site create --slug=taco --porcelain` - And save STDOUT as {TACO_ID} - And I run `wp site create --slug=pizza --porcelain` - And save STDOUT as {PIZZA_ID} - And I run `wp site archive {BURRITO_ID}` - And I run `wp site spam {TACO_ID}` - And I run `wp site delete {PIZZA_ID} --yes` - - When I run `wp site option get wpmu_upgrade_site` - Then save STDOUT as {UPDATE_VERSION} - - When I run `wp core update-db --network` - Then STDOUT should contain: - """ - Success: WordPress database upgraded on 3/3 sites. - """ - - When I run `wp site option get wpmu_upgrade_site` - Then STDOUT should not contain: - """ - {UPDATE_VERSION} - """ - - Scenario: Update db across network, dry run - Given a WP multisite install - And I run `wp core download --version=4.1 --force` - And I run `wp option update db_version 29630` - And I run `wp site option update wpmu_upgrade_site 29630` - And I run `wp site create --slug=foo` - And I run `wp site create --slug=bar` - And I run `wp site create --slug=burrito --porcelain` - And save STDOUT as {BURRITO_ID} - And I run `wp site create --slug=taco --porcelain` - And save STDOUT as {TACO_ID} - And I run `wp site create --slug=pizza --porcelain` - And save STDOUT as {PIZZA_ID} - And I run `wp site archive {BURRITO_ID}` - And I run `wp site spam {TACO_ID}` - And I run `wp site delete {PIZZA_ID} --yes` - - When I run `wp site option get wpmu_upgrade_site` - Then save STDOUT as {UPDATE_VERSION} - - When I run `wp core update-db --network --dry-run` - Then STDOUT should contain: - """ - Performing a dry run, with no database modification. - """ - And STDOUT should contain: - """ - WordPress database will be upgraded from db version - """ - And STDOUT should not contain: - """ - WordPress database upgraded successfully from db version - """ - And STDOUT should contain: - """ - Success: WordPress database upgraded on 3/3 sites. - """ - - When I run `wp site option get wpmu_upgrade_site` - Then STDOUT should contain: - """ - {UPDATE_VERSION} - """ - - Scenario: Ensure update-db sets WP_INSTALLING constant - Given a WP install - And a before.php file: - """ - <?php - WP_CLI::add_hook( 'before_invoke:core update-db', function(){ - WP_CLI::log( 'WP_INSTALLING: ' . var_export( WP_INSTALLING, true ) ); - }); - """ - - When I run `wp --require=before.php core update-db` - Then STDOUT should contain: - """ - WP_INSTALLING: true - """ diff --git a/features/core-update.feature b/features/core-update.feature deleted file mode 100644 index ea6b8c0c9..000000000 --- a/features/core-update.feature +++ /dev/null @@ -1,236 +0,0 @@ -Feature: Update WordPress core - - @less-than-php-7 - Scenario: Update from a ZIP file - Given a WP install - - When I run `wp core download --version=3.8 --force` - Then STDOUT should not be empty - - When I run `wp eval 'echo $GLOBALS["wp_version"];'` - Then STDOUT should be: - """ - 3.8 - """ - - When I run `wget http://wordpress.org/wordpress-3.9.zip --quiet` - And I run `wp core update wordpress-3.9.zip` - Then STDOUT should be: - """ - Starting update... - Unpacking the update... - Cleaning up files... - No files found that need cleaned up. - Success: WordPress updated successfully. - """ - - When I run `wp eval 'echo $GLOBALS["wp_version"];'` - Then STDOUT should be: - """ - 3.9 - """ - - @less-than-php-7 - Scenario: Update to the latest minor release - Given a WP install - - When I run `wp core download --version=3.7.9 --force` - Then STDOUT should not be empty - - When I run `wp core update --minor` - Then STDOUT should contain: - """ - Updating to version 3.7.19 - """ - - When I run `wp core update --minor` - Then STDOUT should be: - """ - Success: WordPress is at the latest minor release. - """ - - When I run `wp core version` - Then STDOUT should be: - """ - 3.7.19 - """ - - @less-than-php-7 - Scenario: Core update from cache - Given a WP install - And an empty cache - - When I run `wp core update --version=3.8.1 --force` - Then STDOUT should not contain: - """ - Using cached file - """ - And STDOUT should contain: - """ - Downloading - """ - - When I run `wp core update --version=3.9 --force` - Then STDOUT should not be empty - - When I run `wp core update --version=3.8.1 --force` - Then STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/core/wordpress-3.8.1-en_US.zip'... - """ - And STDOUT should not contain: - """ - Downloading - """ - - Scenario: Don't run update when up-to-date - Given a WP install - And I run `wp core update` - - When I run `wp core update` - Then STDOUT should contain: - """ - WordPress is up to date - """ - And STDOUT should not contain: - """ - Updating - """ - - When I run `wp core update --force` - Then STDOUT should contain: - """ - Updating - """ - - Scenario: Ensure cached partial upgrades aren't used in full upgrade - Given a WP install - And an empty cache - And a wp-content/mu-plugins/upgrade-override.php file: - """ - <?php - add_filter( 'pre_site_transient_update_core', function(){ - return (object) array( - 'updates' => array( - (object) array( - 'response' => 'autoupdate', - 'download' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', - 'locale' => 'en_US', - 'packages' => (object) array( - 'full' => 'https://downloads.wordpress.org/release/wordpress-4.2.4.zip', - 'no_content' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-no-content.zip', - 'new_bundled' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-new-bundled.zip', - 'partial' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-partial-1.zip', - 'rollback' => 'https://downloads.wordpress.org/release/wordpress-4.2.4-rollback-1.zip', - ), - 'current' => '4.2.4', - 'version' => '4.2.4', - 'php_version' => '5.2.4', - 'mysql_version' => '5.0', - 'new_bundled' => '4.1', - 'partial_version' => '4.2.1', - 'support_email' => 'updatehelp42@wordpress.org', - 'new_files' => '', - ), - ), - ); - }); - """ - - When I run `wp core download --version=4.2.1 --force` - And I run `wp core update` - Then STDOUT should not be empty - And the {SUITE_CACHE_DIR}/core directory should contain: - """ - wordpress-4.2.1-en_US.tar.gz - wordpress-4.2.4-partial-1-en_US.zip - """ - - When I run `wp core download --version=4.1.1 --force` - And I run `wp core update` - And I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - And the {SUITE_CACHE_DIR}/core directory should contain: - """ - wordpress-4.1.1-en_US.tar.gz - wordpress-4.2.1-en_US.tar.gz - wordpress-4.2.4-no-content-en_US.zip - wordpress-4.2.4-partial-1-en_US.zip - """ - - Scenario: Make sure files are cleaned up - Given a WP install - When I run `wp core update --version=4.4 --force` - Then the wp-includes/rest-api.php file should exist - Then the wp-includes/class-wp-comment.php file should exist - And STDOUT should not contain: - """ - File removed: wp-content - """ - - When I run `wp core update --version=4.3.2 --force` - Then the wp-includes/rest-api.php file should not exist - Then the wp-includes/class-wp-comment.php file should not exist - Then STDOUT should contain: - """ - File removed: wp-includes/class-walker-comment.php - File removed: wp-includes/class-wp-network.php - File removed: wp-includes/embed-template.php - File removed: wp-includes/class-wp-comment.php - File removed: wp-includes/class-wp-http-response.php - File removed: wp-includes/class-walker-category-dropdown.php - File removed: wp-includes/rest-api.php - """ - And STDOUT should not contain: - """ - File removed: wp-content - """ - - When I run `wp option add str_opt 'bar'` - Then STDOUT should not be empty - When I run `wp post create --post_title='Test post' --porcelain` - Then STDOUT should be a number - - @less-than-php-7 @require-wp-4.0 - Scenario: Minor update on an unlocalized WordPress release - Given a WP install - And an empty cache - - When I run `wp core download --version=4.0 --locale=es_ES --force` - Then STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - When I run `wp core update --minor` - Then STDOUT should contain: - """ - Updating to version 4.0.16 (en_US)... - Descargando paquete de instalación desde https://downloads.wordpress.org/release/wordpress-4.0.16-partial-0.zip - """ - And STDOUT should contain: - """ - Success: WordPress updated successfully. - """ - - Scenario Outline: Use `--version=(nightly|trunk)` to update to the latest nightly version - Given a WP install - - When I run `wp core update --version=<version>` - Then STDOUT should contain: - """ - Updating to version nightly (en_US)... - Downloading update from https://wordpress.org/nightly-builds/wordpress-latest.zip... - """ - And STDOUT should contain: - """ - Success: WordPress updated successfully. - """ - - Examples: - | version | - | trunk | - | nightly | diff --git a/features/core-verify-checksums.feature b/features/core-verify-checksums.feature deleted file mode 100644 index 6c73cff5e..000000000 --- a/features/core-verify-checksums.feature +++ /dev/null @@ -1,102 +0,0 @@ -Feature: Validate checksums for WordPress install - - Scenario: Verify core checksums - Given a WP install - - When I run `wp core update` - Then STDOUT should not be empty - - When I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - Scenario: Core checksums don't verify - Given a WP install - And "WordPress" replaced with "Wordpress" in the readme.html file - - When I try `wp core verify-checksums` - Then STDERR should be: - """ - Warning: File doesn't verify against checksum: readme.html - Error: WordPress install doesn't verify against checksums. - """ - - When I run `rm readme.html` - Then STDERR should be empty - - When I try `wp core verify-checksums` - Then STDERR should be: - """ - Warning: File doesn't exist: readme.html - Error: WordPress install doesn't verify against checksums. - """ - - Scenario: Verify core checksums without loading WordPress - Given an empty directory - And I run `wp core download --version=4.3` - - When I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - When I run `wp core verify-checksums --version=4.3 --locale=en_US` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - When I try `wp core verify-checksums --version=4.2 --locale=en_US` - Then STDERR should contain: - """ - Error: WordPress install doesn't verify against checksums. - """ - - Scenario: Verify core checksums for a non US local - Given a WP install - And I run `wp core download --locale=en_GB --version=4.3.1 --force` - - When I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - Scenario: Verify core checksums with extra files - Given a WP install - - When I run `wp core update` - Then STDOUT should not be empty - - Given a wp-includes/extra-file.txt file: - """ - hello world - """ - Then the wp-includes/extra-file.txt file should exist - - When I run `wp core verify-checksums` - Then STDERR should be: - """ - Warning: File should not exist: wp-includes/extra-file.txt - """ - And STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - - Scenario: Verify core checksums with a plugin that has wp-admin - Given a WP install - And a wp-content/plugins/akismet/wp-admin/extra-file.txt file: - """ - hello world - """ - - When I run `wp core verify-checksums` - Then STDOUT should be: - """ - Success: WordPress install verifies against checksums. - """ - And STDERR should be empty diff --git a/features/core-version.feature b/features/core-version.feature deleted file mode 100644 index b46b47c30..000000000 --- a/features/core-version.feature +++ /dev/null @@ -1,39 +0,0 @@ -Feature: Find version for WordPress install - - Scenario: Verify core version - Given a WP install - And I run `wp core download --version=4.4.2 --force` - - When I run `wp core version` - Then STDOUT should be: - """ - 4.4.2 - """ - - When I run `wp core version --extra` - Then STDOUT should be: - """ - WordPress version: 4.4.2 - Database revision: 35700 - TinyMCE version: 4.208 (4208-20151113) - Package language: en_US - """ - - Scenario: Installing WordPress for a non-default locale and verify core extended version information. - Given an empty directory - And an empty cache - - When I run `wp core download --version=4.4.2 --locale=de_DE` - Then STDOUT should contain: - """ - Success: WordPress downloaded. - """ - - When I run `wp core version --extra` - Then STDOUT should be: - """ - WordPress version: 4.4.2 - Database revision: 35700 - TinyMCE version: 4.208 (4208-20151113) - Package language: de_DE - """ diff --git a/features/core.feature b/features/core.feature deleted file mode 100644 index 3e98de5bc..000000000 --- a/features/core.feature +++ /dev/null @@ -1,370 +0,0 @@ -Feature: Manage WordPress installation - - Scenario: Database doesn't exist - Given an empty directory - And WP files - And wp-config.php - - When I try `wp core is-installed` - Then the return code should be 1 - And STDERR should not be empty - - When I run `wp db create` - Then STDOUT should not be empty - - Scenario: Database tables not installed - Given an empty directory - And WP files - And wp-config.php - And a database - - When I try `wp core is-installed` - Then the return code should be 1 - - When I try `wp core is-installed --network` - Then the return code should be 1 - - When I try `wp core install` - Then the return code should be 1 - And STDERR should contain: - """ - missing --url parameter (The address of the new site.) - """ - - When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should not be empty - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - http://localhost:8001 - """ - - When I try `wp core is-installed --network` - Then the return code should be 1 - - Scenario: Install WordPress by prompting - Given an empty directory - And WP files - And wp-config.php - And a database - And a session file: - """ - localhost:8001 - Test - wpcli - wpcli - admin@example.com - """ - - When I run `wp core install --prompt < session` - Then STDOUT should not be empty - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - http://localhost:8001 - """ - - Scenario: Install WordPress by prompting for the admin email and password - Given an empty directory - And WP files - And wp-config.php - And a database - And a session file: - """ - wpcli - admin@example.com - """ - - When I run `wp core install --url=localhost:8001 --title=Test --admin_user=wpcli --prompt=admin_email,admin_password < session` - Then STDOUT should not be empty - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - http://localhost:8001 - """ - - Scenario: Install WordPress with an https scheme - Given an empty directory - And WP files - And wp-config.php - And a database - - When I run `wp core install --url='https://localhost' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then the return code should be 0 - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - https://localhost - """ - - Scenario: Install WordPress with an https scheme and non-standard port - Given an empty directory - And WP files - And wp-config.php - And a database - - When I run `wp core install --url='https://localhost:8443' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then the return code should be 0 - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - https://localhost:8443 - """ - - Scenario: Full install - Given a WP install - - When I run `wp core is-installed` - Then STDOUT should be empty - And the wp-content/uploads directory should exist - - When I run `wp eval 'var_export( is_admin() );'` - Then STDOUT should be: - """ - false - """ - - When I run `wp eval 'var_export( function_exists( 'media_handle_upload' ) );'` - Then STDOUT should be: - """ - true - """ - - # Can complain that it's already installed, but don't exit with an error code - When I try `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then the return code should be 0 - - Scenario: Convert install to multisite - Given a WP install - - When I run `wp eval 'var_export( is_multisite() );'` - Then STDOUT should be: - """ - false - """ - - When I try `wp core is-installed --network` - Then the return code should be 1 - - When I run `wp core install-network --title='test network'` - Then STDOUT should be: - """ - Set up multisite database tables. - Added multisite constants to 'wp-config.php'. - Success: Network installed. Don't forget to set up rewrite rules. - """ - And STDERR should be empty - - When I run `wp eval 'var_export( is_multisite() );'` - Then STDOUT should be: - """ - true - """ - - When I run `wp core is-installed --network` - Then the return code should be 0 - - When I try `wp core install-network --title='test network'` - Then the return code should be 1 - - When I run `wp network meta get 1 upload_space_check_disabled` - Then STDOUT should be: - """ - 1 - """ - - Scenario: Install multisite from scratch - Given an empty directory - And WP files - And wp-config.php - And a database - - When I run `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should be: - """ - Created single site database tables. - Set up multisite database tables. - Added multisite constants to 'wp-config.php'. - Success: Network installed. Don't forget to set up rewrite rules. - """ - And STDERR should be empty - - When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` - Then STDOUT should be: - """ - foobar.org - """ - - # Can complain that it's already installed, but don't exit with an error code - When I try `wp core multisite-install --url=foobar.org --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then the return code should be 0 - - When I run `wp network meta get 1 upload_space_check_disabled` - Then STDOUT should be: - """ - 1 - """ - - Scenario: Install multisite from scratch, with MULTISITE already set in wp-config.php - Given a WP multisite install - And I run `wp db reset --yes` - - When I try `wp core is-installed` - Then the return code should be 1 - - When I run `wp core multisite-install --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should not be empty - - When I run `wp eval 'echo $GLOBALS["current_site"]->domain;'` - Then STDOUT should be: - """ - example.com - """ - - Scenario: Install multisite with subdomains on localhost - Given an empty directory - And WP files - And wp-config.php - And a database - - When I try `wp core multisite-install --url=http://localhost/ --title=Test --admin_user=wpcli --admin_email=admin@example.com --admin_password=1 --subdomains` - Then STDERR should contain: - """ - Error: Multisite with subdomains cannot be configured when domain is 'localhost'. - """ - - Scenario: Custom wp-content directory - Given a WP install - And a custom wp-content directory - - When I run `wp plugin status hello` - Then STDOUT should not be empty - - Scenario: User defined in wp-cli.yml - Given an empty directory - And WP files - And wp-config.php - And a database - And a wp-cli.yml file: - """ - user: wpcli - """ - - When I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should not be empty - - When I run `wp eval 'echo home_url();'` - Then STDOUT should be: - """ - http://localhost:8001 - """ - - Scenario: Test output in a multisite install with custom base path - Given a WP install - - When I run `wp core multisite-convert --title=Test --base=/test/` - And I run `wp post list` - Then STDOUT should contain: - """ - Hello world! - """ - - Scenario: Download WordPress - Given an empty directory - - When I run `wp core download` - Then STDOUT should contain: - """ - Success: WordPress downloaded. - """ - And the wp-settings.php file should exist - - Scenario: Don't download WordPress when files are already present - Given an empty directory - And WP files - - When I try `wp core download` - Then STDERR should be: - """ - Error: WordPress files seem to already be present here. - """ - - Scenario: Install WordPress in a subdirectory - Given an empty directory - And a wp-config.php file: - """ - <?php - // ** MySQL settings ** // - /** The name of the database for WordPress */ - define('DB_NAME', 'wp_cli_test'); - - /** MySQL database username */ - define('DB_USER', 'wp_cli_test'); - - /** MySQL database password */ - define('DB_PASSWORD', 'password1'); - - /** MySQL hostname */ - define('DB_HOST', '127.0.0.1'); - - /** Database Charset to use in creating database tables. */ - define('DB_CHARSET', 'utf8'); - - /** The Database Collate type. Don't change this if in doubt. */ - define('DB_COLLATE', ''); - - $table_prefix = 'wp_'; - - /* That's all, stop editing! Happy blogging. */ - - /** Absolute path to the WordPress directory. */ - if ( !defined('ABSPATH') ) - define('ABSPATH', dirname(__FILE__) . '/'); - - /** Sets up WordPress vars and included files. */ - require_once(ABSPATH . 'wp-settings.php'); - """ - And a wp-cli.yml file: - """ - path: wp - """ - - When I run `wp core download` - Then the wp directory should exist - And the wp/wp-blog-header.php file should exist - - When I run `wp db create` - And I run `wp core install --url=wp.dev --title="WP Dev" --admin_user=wpcli --admin_password=wpcli --admin_email=wpcli@example.com` - Then STDOUT should not be empty - - When I run `wp option get home` - Then STDOUT should be: - """ - http://wp.dev - """ - - When I run `wp option get siteurl` - Then STDOUT should be: - """ - http://wp.dev - """ - - Scenario: Warn when multisite constants can't be inserted into wp-config - Given a WP install - And "That's all" replaced with "C'est tout" in the wp-config.php file - - When I run `wp core multisite-convert` - Then STDOUT should be: - """ - Set up multisite database tables. - Success: Network installed. Don't forget to set up rewrite rules. - """ - And STDERR should contain: - """ - Warning: Multisite constants could not be written to 'wp-config.php'. You may need to add them manually: - """ diff --git a/features/eval.feature b/features/eval.feature deleted file mode 100644 index c8308b67b..000000000 --- a/features/eval.feature +++ /dev/null @@ -1,57 +0,0 @@ -Feature: Evaluating PHP code and files. - - Scenario: Basics - Given a WP install - - When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));'` - Then STDOUT should contain: - """ - bool(true) - """ - - Given a script.php file: - """ - <?php - WP_CLI::line( implode( ' ', $args ) ); - """ - - When I run `wp eval-file script.php foo bar` - Then STDOUT should contain: - """ - foo bar - """ - - Scenario: Eval without WordPress install - Given an empty directory - - When I try `wp eval 'var_dump(defined("WP_CONTENT_DIR"));'` - Then STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - - When I run `wp eval 'var_dump(defined("WP_CONTENT_DIR"));' --skip-wordpress` - Then STDOUT should contain: - """ - bool(false) - """ - - Scenario: Eval file without WordPress install - Given an empty directory - And a script.php file: - """ - <?php - var_dump(defined("WP_CONTENT_DIR")); - """ - - When I try `wp eval-file script.php` - Then STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - - When I run `wp eval-file script.php --skip-wordpress` - Then STDOUT should contain: - """ - bool(false) - """ diff --git a/features/extra/no-mail.php b/features/extra/no-mail.php deleted file mode 100644 index de7a42272..000000000 --- a/features/extra/no-mail.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -function wp_mail( $to ) { - // Log for testing purposes - WP_CLI::log( "WP-CLI test suite: Sent email to {$to}." ); -} - diff --git a/features/flags.feature b/features/flags.feature deleted file mode 100644 index 8fd674429..000000000 --- a/features/flags.feature +++ /dev/null @@ -1,237 +0,0 @@ -Feature: Global flags - - Scenario: Setting the URL - Given a WP install - - When I run `wp --url=localhost:8001 eval 'echo json_encode( $_SERVER );'` - Then STDOUT should be JSON containing: - """ - { - "HTTP_HOST": "localhost:8001", - "SERVER_NAME": "localhost", - "SERVER_PORT": "8001" - } - """ - - Scenario: Setting the URL on multisite - Given a WP multisite install - And I run `wp site create --slug=foo` - - When I run `wp --url=example.com/foo option get home` - Then STDOUT should be: - """ - http://example.com/foo - """ - - @require-wp-3.9 - Scenario: Invalid URL - Given a WP multisite install - - When I try `wp post list --url=invalid.example.com` - Then STDERR should be: - """ - Error: Site invalid.example.com not found. - """ - - Scenario: Quiet run - Given a WP install - - When I try `wp non-existing-command --quiet` - Then the return code should be 1 - And STDERR should be: - """ - Error: 'non-existing-command' is not a registered wp command. See 'wp help'. - """ - - Scenario: Debug run - Given a WP install - - When I run `wp eval 'echo CONST_WITHOUT_QUOTES;'` - Then STDOUT should be: - """ - CONST_WITHOUT_QUOTES - """ - - When I try `wp eval 'echo CONST_WITHOUT_QUOTES;' --debug` - Then the return code should be 0 - And STDOUT should be: - """ - CONST_WITHOUT_QUOTES - """ - And STDERR should contain: - """ - Use of undefined constant CONST_WITHOUT_QUOTES - """ - - Scenario: Setting the WP user - Given a WP install - - When I run `wp eval 'echo (int) is_user_logged_in();'` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp --user=admin eval 'echo wp_get_current_user()->user_login;'` - Then STDOUT should be: - """ - admin - """ - - When I run `wp --user=admin@example.com eval 'echo wp_get_current_user()->user_login;'` - Then STDOUT should be: - """ - admin - """ - - When I try `wp --user=non-existing-user eval 'echo wp_get_current_user()->user_login;'` - Then the return code should be 1 - And STDERR should be: - """ - Error: Invalid user ID, email or login: 'non-existing-user' - """ - - Scenario: Using a custom logger - Given an empty directory - And a custom-logger.php file: - """ - <?php - class Dummy_Logger { - - function __call( $method, $args ) { - echo "log: called '$method' method"; - } - } - - WP_CLI::set_logger( new Dummy_Logger ); - """ - - When I try `wp --require=custom-logger.php is-installed` - Then STDOUT should contain: - """ - log: called 'error' method - """ - - Scenario: Using --require - Given an empty directory - And a custom-cmd.php file: - """ - <?php - /** - * @when before_wp_load - */ - class Test_Command extends WP_CLI_Command { - - function req( $args, $assoc_args ) { - WP_CLI::line( $args[0] ); - } - } - - WP_CLI::add_command( 'test', 'Test_Command' ); - """ - - And a foo.php file: - """ - <?php echo basename(__FILE__) . "\n"; - """ - - And a bar.php file: - """ - <?php echo basename(__FILE__) . "\n"; - """ - - And a wp-cli.yml file: - """ - require: - - foo.php - - bar.php - """ - - And a wp-cli2.yml file: - """ - require: custom-cmd.php - """ - - When I run `wp --require=custom-cmd.php test req 'This is a custom command.'` - Then STDOUT should be: - """ - foo.php - bar.php - This is a custom command. - """ - - When I run `WP_CLI_CONFIG_PATH=wp-cli2.yml wp test req 'This is a custom command.'` - Then STDOUT should contain: - """ - This is a custom command. - """ - - Scenario: Enabling/disabling color - Given a WP install - - When I try `wp --no-color non-existent-command` - Then STDERR should be: - """ - Error: 'non-existent-command' is not a registered wp command. See 'wp help'. - """ - - When I try `wp --color non-existent-command` - Then STDERR should contain: - """ - [31;1mError: - """ - - Scenario: Use `WP_CLI_STRICT_ARGS_MODE` to distinguish between global and local args - Given an empty directory - And a cmd.php file: - """ - <?php - /** - * @when before_wp_load - * - * [--url=<url>] - * : URL passed to the callback. - */ - $cmd_test = function( $args, $assoc_args ) { - $url = WP_CLI::get_runner()->config['url'] ? ' ' . WP_CLI::get_runner()->config['url'] : ''; - WP_CLI::log( 'global:' . $url ); - $url = isset( $assoc_args['url'] ) ? ' ' . $assoc_args['url'] : ''; - WP_CLI::log( 'local:' . $url ); - }; - WP_CLI::add_command( 'cmd-test', $cmd_test ); - """ - And a wp-cli.yml file: - """ - require: - - cmd.php - """ - - When I run `wp cmd-test --url=foo.dev` - Then STDOUT should be: - """ - global: foo.dev - local: - """ - - When I run `WP_CLI_STRICT_ARGS_MODE=1 wp cmd-test --url=foo.dev` - Then STDOUT should be: - """ - global: - local: foo.dev - """ - - When I run `WP_CLI_STRICT_ARGS_MODE=1 wp --url=bar.dev cmd-test --url=foo.dev` - Then STDOUT should be: - """ - global: bar.dev - local: foo.dev - """ - - Scenario: Using --http=<url> requires wp-cli/restful - Given an empty directory - - When I try `wp --http=foo.dev` - Then STDERR should be: - """ - Error: RESTful WP-CLI needs to be installed. Try 'wp package install wp-cli/restful'. - """ diff --git a/features/formatter.feature b/features/formatter.feature deleted file mode 100644 index c9986999a..000000000 --- a/features/formatter.feature +++ /dev/null @@ -1,112 +0,0 @@ -Feature: Format output - - Scenario: Format output as YAML - Given an empty directory - And a output-yaml.php file: - """ - <?php - /** - * Output data as YAML - * - * <type> - * : Type of output. - * - * [--fields=<fields>] - * : Limit output to particular fields - * - * @when before_wp_load - */ - $output_yaml = function( $args, $assoc_args ) { - $items = array( - array( - 'label' => 'Foo', - 'slug' => 'foo', - ), - array( - 'label' => 'Bar', - 'slug' => 'bar', - ), - ); - $format_args = array( 'format' => 'yaml' ); - if ( isset( $assoc_args['fields'] ) ) { - $format_args['fields'] = explode( ',', $assoc_args['fields'] ); - } else { - $format_args['fields'] = array( 'label', 'slug' ); - } - $formatter = new \WP_CLI\Formatter( $format_args ); - if ( 'all' === $args[0] ) { - $formatter->display_items( $items ); - } else if ( 'single' === $args[0] ) { - $formatter->display_item( $items[0] ); - } - }; - WP_CLI::add_command( 'yaml', $output_yaml ); - """ - - When I run `wp --require=output-yaml.php yaml all` - Then STDOUT should be YAML containing: - """ - --- - - - label: Foo - slug: foo - - - label: Bar - slug: bar - """ - - When I run `wp --require=output-yaml.php yaml all --fields=label` - Then STDOUT should be YAML containing: - """ - --- - - - label: Foo - - - label: Bar - """ - And STDOUT should not contain: - """ - slug: bar - """ - - When I run `wp --require=output-yaml.php yaml single` - Then STDOUT should be YAML containing: - """ - --- - label: Foo - slug: foo - """ - - Scenario: Format data in RTL language - Given an empty directory - And a file.php file: - """ - <?php - $items = array( - array( - 'id' => 1, - 'language' => 'Afrikaans', - 'is_rtl' => 0, - ), - array( - 'id' => 2, - 'language' => 'العَرَبÙيَّة‎‎', - 'is_rtl' => 1, - ), - array( - 'id' => 3, - 'language' => 'English', - 'is_rtl' => 0, - ), - ); - $assoc_args = array( 'format' => 'csv' ); - $formatter = new WP_CLI\Formatter( $assoc_args, array( 'id', 'language', 'is_rtl' ) ); - $formatter->display_items( $items ); - """ - - When I run `wp eval-file file.php --skip-wordpress` - Then STDOUT should be CSV containing: - | id | language | is_rtl | - | 1 | Afrikaans | 0 | - | 2 | العَرَبÙيَّة‎‎ | 1 | - | 3 | English | 0 | diff --git a/features/framework.feature b/features/framework.feature deleted file mode 100644 index 26b653371..000000000 --- a/features/framework.feature +++ /dev/null @@ -1,254 +0,0 @@ -Feature: Load WP-CLI - - Scenario: A plugin calling wp_signon() shouldn't fatal - Given a WP install - And I run `wp user create testuser test@example.org --user_pass=testuser` - And a wp-content/mu-plugins/test.php file: - """ - <?php - add_action( 'plugins_loaded', function(){ - wp_signon( array( 'user_login' => 'testuser', 'user_password' => 'testuser' ) ); - }); - """ - - When I run `wp option get home` - Then STDOUT should not be empty - - Scenario: A command loaded before WordPress then calls WordPress to load - Given a WP install - And a custom-cmd.php file: - """ - <?php - class Load_WordPress_Command_Class extends WP_CLI_Command { - - /** - * @when before_wp_load - */ - public function __invoke() { - if ( ! function_exists( 'update_option' ) ) { - WP_CLI::log( 'WordPress not loaded.' ); - } - WP_CLI::get_runner()->load_wordpress(); - if ( function_exists( 'update_option' ) ) { - WP_CLI::log( 'WordPress loaded!' ); - } - WP_CLI::get_runner()->load_wordpress(); - WP_CLI::log( 'load_wordpress() can safely be called twice.' ); - } - - } - WP_CLI::add_command( 'load-wordpress', 'Load_WordPress_Command_Class' ); - """ - - When I run `wp --require=custom-cmd.php load-wordpress` - Then STDOUT should be: - """ - WordPress not loaded. - WordPress loaded! - load_wordpress() can safely be called twice. - """ - - Scenario: A command loaded before WordPress then calls WordPress to load, but WP doesn't exist - Given an empty directory - And a custom-cmd.php file: - """ - <?php - class Load_WordPress_Command_Class extends WP_CLI_Command { - - /** - * @when before_wp_load - */ - public function __invoke() { - if ( ! function_exists( 'update_option' ) ) { - WP_CLI::log( 'WordPress not loaded.' ); - } - WP_CLI::get_runner()->load_wordpress(); - if ( function_exists( 'update_option' ) ) { - WP_CLI::log( 'WordPress loaded!' ); - } - WP_CLI::get_runner()->load_wordpress(); - WP_CLI::log( 'load_wordpress() can safely be called twice.' ); - } - - } - WP_CLI::add_command( 'load-wordpress', 'Load_WordPress_Command_Class' ); - """ - - When I try `wp --require=custom-cmd.php load-wordpress` - Then STDOUT should be: - """ - WordPress not loaded. - """ - And STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - - Scenario: Globalize global variables in wp-config.php - Given an empty directory - And WP files - And a wp-config-extra.php file: - """ - $redis_server = 'foo'; - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < wp-config-extra.php` - Then the wp-config.php file should contain: - """ - $redis_server = 'foo'; - """ - - When I run `wp db create` - And I run `wp core install --url='localhost:8001' --title='Test' --admin_user=wpcli --admin_email=admin@example.com --admin_password=1` - Then STDOUT should not be empty - - When I run `wp eval 'echo $GLOBALS["redis_server"];'` - Then STDOUT should be: - """ - foo - """ - - Scenario: Use a custom error code with WP_CLI::error() - Given an empty directory - And a exit-normal.php file: - """ - <?php - WP_CLI::error( 'This is return code 1.' ); - """ - And a exit-higher.php file: - """ - <?php - WP_CLI::error( 'This is return code 5.', 5 ); - """ - And a no-exit.php file: - """ - <?php - WP_CLI::error( 'This has no exit.', false ); - WP_CLI::error( 'So I can use multiple lines.', false ); - """ - - When I try `wp --require=exit-normal.php` - Then the return code should be 1 - And STDERR should be: - """ - Error: This is return code 1. - """ - - When I try `wp --require=exit-higher.php` - Then the return code should be 5 - And STDERR should be: - """ - Error: This is return code 5. - """ - - When I try `wp --require=no-exit.php` - Then the return code should be 0 - And STDERR should be: - """ - Error: This has no exit. - Error: So I can use multiple lines. - """ - - Scenario: A plugin calling wp_redirect() shouldn't redirect - Given a WP install - And a wp-content/mu-plugins/redirect.php file: - """ - <?php - add_action( 'init', function(){ - wp_redirect( 'http://apple.com' ); - }); - """ - - When I try `wp option get home` - Then STDERR should contain: - """ - Warning: Some code is trying to do a URL redirect. - """ - - Scenario: It should be possible to work on a site in maintenance mode - Given a WP install - And a .maintenance file: - """ - <?php - $upgrading = time(); - """ - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.com - """ - - Scenario: Handle error when WordPress cannot connect to the database host - Given a WP install - And a wp-debug.php file: - """ - <?php - define( 'WP_DEBUG', true ); - """ - And a invalid-host.php file: - """ - <?php - define( 'DB_HOST', 'localghost' ); - """ - - When I try `wp --require=invalid-host.php option get home` - Then STDERR should contain: - """ - Error: Error establishing a database connection. - """ - - When I try `wp --require=invalid-host.php --require=wp-debug.php option get home` - Then STDERR should contain: - """ - Error: Error establishing a database connection. - """ - - Scenario: Allow WP_CLI hooks to pass arguments to callbacks - Given an empty directory - And a my-command.php file: - """ - <?php - - WP_CLI::add_hook( 'foo', function( $bar ){ - WP_CLI::log( $bar ); - }); - WP_CLI::add_command( 'my-command', function( $args ){ - WP_CLI::do_hook( 'foo', $args[0] ); - }, array( 'when' => 'before_wp_load' ) ); - """ - - When I run `wp --require=my-command.php my-command bar` - Then STDOUT should be: - """ - bar - """ - And STDERR should be empty - - Scenario: WP-CLI sets $table_prefix appropriately on multisite - Given a WP multisite install - And I run `wp site create --slug=first` - - When I run `wp eval 'global $table_prefix; echo $table_prefix;'` - Then STDOUT should be: - """ - wp_ - """ - - When I run `wp eval 'global $blog_id; echo $blog_id;'` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp --url=example.com/first eval 'global $table_prefix; echo $table_prefix;'` - Then STDOUT should be: - """ - wp_2_ - """ - - When I run `wp --url=example.com/first eval 'global $blog_id; echo $blog_id;'` - Then STDOUT should be: - """ - 2 - """ diff --git a/features/help.feature b/features/help.feature deleted file mode 100644 index 8c067afb9..000000000 --- a/features/help.feature +++ /dev/null @@ -1,226 +0,0 @@ -Feature: Get help about WP-CLI commands - - Scenario: Help for internal commands - Given an empty directory - - When I run `wp help` - Then STDOUT should not be empty - - When I run `wp help core` - Then STDOUT should not be empty - - When I run `wp help core download` - Then STDOUT should not be empty - - When I run `wp help help` - Then STDOUT should not be empty - - When I run `wp help help` - Then STDOUT should contain: - """ - GLOBAL PARAMETERS - """ - - When I run `wp post list --post_type=post --posts_per_page=5 --help` - Then STDOUT should contain: - """ - wp post list - """ - - Scenario: Help when WordPress is downloaded but not installed - Given an empty directory - - When I run `wp core download` - And I run `wp help core config` - Then STDOUT should contain: - """ - wp core config - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS}` - And I run `wp help core install` - Then STDOUT should contain: - """ - wp core install - """ - - Scenario: Help for nonexistent commands - Given a WP install - - When I try `wp help non-existent-command` - Then the return code should be 1 - And STDERR should be: - """ - Error: 'non-existent-command' is not a registered wp command. - """ - - When I try `wp help non-existent-command non-existent-subcommand` - Then the return code should be 1 - And STDERR should be: - """ - Error: 'non-existent-command non-existent-subcommand' is not a registered wp command. - """ - - Scenario: Help for third-party commands - Given a WP install - And a wp-content/plugins/test-cli/command.php file: - """ - <?php - // Plugin Name: Test CLI Help - - class Test_Help extends WP_CLI_Command { - /** - * A dummy command. - */ - function __invoke() {} - } - - WP_CLI::add_command( 'test-help', 'Test_Help' ); - """ - And I run `wp plugin activate test-cli` - - When I run `wp help` - Then STDOUT should contain: - """ - A dummy command. - """ - - When I run `wp help test-help` - Then STDOUT should contain: - """ - wp test-help - """ - - Scenario: Help for incomplete commands - Given an empty directory - - When I run `wp core` - Then STDOUT should contain: - """ - usage: wp core - """ - - Scenario: Help for commands with magic methods - Given a WP install - And a wp-content/plugins/test-cli/command.php file: - """ - <?php - // Plugin Name: Test CLI Help - - class Test_Magic_Methods extends WP_CLI_Command { - /** - * A dummy command. - * - * @subcommand my-command - */ - function my_command() {} - - /** - * Magic methods should not appear as commands - */ - function __construct() {} - function __destruct() {} - function __call( $name, $arguments ) {} - function __get( $key ) {} - function __set( $key, $value ) {} - function __isset( $key ) {} - function __unset( $key ) {} - function __sleep() {} - function __wakeup() {} - function __toString() {} - function __set_state() {} - function __clone() {} - function __debugInfo() {} - } - - WP_CLI::add_command( 'test-magic-methods', 'Test_Magic_Methods' ); - """ - And I run `wp plugin activate test-cli` - - When I run `wp test-magic-methods` - Then STDOUT should contain: - """ - usage: wp test-magic-methods my-command - """ - And STDOUT should not contain: - """ - __destruct - """ - - Scenario: Help for commands loaded into existing namespaces - Given a WP install - And a wp-content/plugins/test-cli/command.php file: - """ - <?php - // Plugin Name: Test CLI Extra Site Command - - class Test_CLI_Extra_Site_Command extends WP_CLI_Command { - - /** - * A dummy command. - * - * @subcommand my-command - */ - function my_command() {} - - } - - WP_CLI::add_command( 'site test-extra', 'Test_CLI_Extra_Site_Command' ); - """ - And I run `wp plugin activate test-cli` - - When I run `wp help site` - Then STDOUT should contain: - """ - test-extra - """ - - Scenario: Help renders global parameters correctly - Given a WP install - - When I run `wp help import get` - Then STDOUT should contain: - """ - GLOBAL PARAMETERS - """ - And STDOUT should not contain: - """ - ## GLOBAL PARAMETERS - """ - - When I run `wp help option get` - Then STDOUT should contain: - """ - GLOBAL PARAMETERS - """ - And STDOUT should not contain: - """ - ## GLOBAL PARAMETERS - """ - - When I run `wp help option` - Then STDOUT should contain: - """ - GLOBAL PARAMETERS - """ - And STDOUT should not contain: - """ - ## GLOBAL PARAMETERS - """ - - Scenario: Display alias in man page - Given a WP install - - When I run `wp help plugin update` - Then STDOUT should contain: - """ - ALIAS - - upgrade - """ - - When I run `wp help plugin install` - Then STDOUT should not contain: - """ - ALIAS - """ diff --git a/features/menu-item.feature b/features/menu-item.feature deleted file mode 100644 index 2507896bb..000000000 --- a/features/menu-item.feature +++ /dev/null @@ -1,134 +0,0 @@ -Feature: Manage WordPress menu items - - Background: - Given a WP install - - Scenario: Add / update / remove items from a menu - - When I run `wp post create --post_title='Test post' --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp post url {POST_ID}` - Then save STDOUT as {POST_LINK} - - When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID} - - When I run `wp term url post_tag {TERM_ID}` - Then save STDOUT as {TERM_LINK} - - When I run `wp menu create "Sidebar Menu"` - Then STDOUT should not be empty - - When I run `wp menu item add-post sidebar-menu {POST_ID} --title="Custom Test Post" --description="Georgia peaches" --porcelain` - Then save STDOUT as {POST_ITEM_ID} - - When I run `wp menu item update {POST_ITEM_ID} --description="Washington Apples"` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item add-term sidebar-menu post_tag {TERM_ID} --porcelain` - Then save STDOUT as {TERM_ITEM_ID} - - When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --parent-id={POST_ITEM_ID} --porcelain` - Then save STDOUT as {CUSTOM_ITEM_ID} - - When I run `wp menu item update {CUSTOM_ITEM_ID} --title=WordPress --link='http://wordpress.org' --target=_blank --position=2` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item update {TERM_ITEM_ID} --position=3` - Then STDOUT should be: - """ - Success: Menu item updated. - """ - - When I run `wp menu item list sidebar-menu --fields=type,title,description,position,link,menu_item_parent` - Then STDOUT should be a table containing rows: - | type | title | description | position | link | menu_item_parent | - | post_type | Custom Test Post | Washington Apples | 1 | {POST_LINK} | 0 | - | custom | WordPress | | 2 | http://wordpress.org | {POST_ITEM_ID} | - | taxonomy | Test term | | 3 | {TERM_LINK} | 0 | - - When I run `wp menu item list sidebar-menu --format=ids` - Then STDOUT should not be empty - - When I run `wp menu item delete {CUSTOM_ITEM_ID}` - Then STDOUT should be: - """ - Success: Deleted 1 of 1 menu items. - """ - And I run `wp menu item list sidebar-menu --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp menu item delete {POST_ITEM_ID} {TERM_ITEM_ID}` - Then STDOUT should be: - """ - Success: Deleted 2 of 2 menu items. - """ - And I run `wp menu item list sidebar-menu --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Preserve grandparent item as ancestor of child item when parent item is removed. - - When I run `wp menu create "Grandparent Test"` - Then STDOUT should not be empty - - When I run `wp menu item add-custom grandparent-test Grandparent http://example.com/grandparent --porcelain` - Then save STDOUT as {GRANDPARENT_ID} - - When I run `wp menu item add-custom grandparent-test Parent http://example.com/parent --porcelain --parent-id={GRANDPARENT_ID}` - Then save STDOUT as {PARENT_ID} - - When I run `wp menu item add-custom grandparent-test Child http://example.com/child --porcelain --parent-id={PARENT_ID}` - Then save STDOUT as {CHILD_ID} - - When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` - Then STDOUT should be a table containing rows: - | title | db_id | menu_item_parent | - | Grandparent | {GRANDPARENT_ID} | 0 | - | Parent | {PARENT_ID} | {GRANDPARENT_ID} | - | Child | {CHILD_ID} | {PARENT_ID} | - - When I run `wp menu item delete {PARENT_ID}` - - When I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent` - Then STDOUT should be a table containing rows: - | title | db_id | menu_item_parent | - | Grandparent | {GRANDPARENT_ID} | 0 | - | Child | {CHILD_ID} | {GRANDPARENT_ID} | - - Scenario: Error deleting one or more menu items - When I run `wp menu create "Sidebar Menu"` - Then STDOUT should not be empty - - When I try `wp menu item delete 99999999` - Then STDERR should be: - """ - Warning: Couldn't delete menu item 99999999. - Error: No menu items deleted. - """ - And the return code should be 1 - - When I run `wp menu item add-custom sidebar-menu Apple http://apple.com --porcelain` - Then save STDOUT as {CUSTOM_ITEM_ID} - - When I try `wp menu item delete {CUSTOM_ITEM_ID} 99999999` - Then STDERR should be: - """ - Warning: Couldn't delete menu item 99999999. - Error: Only deleted 1 of 2 menu items. - """ - And the return code should be 1 diff --git a/features/menu-location.feature b/features/menu-location.feature deleted file mode 100644 index 766fa6443..000000000 --- a/features/menu-location.feature +++ /dev/null @@ -1,56 +0,0 @@ -Feature: Manage WordPress menu locations - - Background: - Given a WP install - - Scenario: Assign / remove location from a menu - - When I run `wp theme install p2 --activate` - And I run `wp menu location list` - Then STDOUT should be a table containing rows: - | location | description | - | primary | Primary Menu | - - When I run `wp menu create "Primary Menu"` - And I run `wp menu location assign primary-menu primary` - And I run `wp menu list --fields=slug,locations` - Then STDOUT should be a table containing rows: - | slug | locations | - | primary-menu | primary | - - When I run `wp menu location list --format=ids` - Then STDOUT should be: - """ - primary - """ - - When I run `wp menu location remove primary-menu primary` - And I run `wp menu list --fields=slug,locations` - Then STDOUT should be a table containing rows: - | slug | locations | - | primary-menu | | - - When I try `wp menu location assign secondary-menu secondary` - Then STDERR should be: - """ - Error: Invalid menu secondary-menu. - """ - - When I run `wp menu create "Secondary Menu"` - And I try `wp menu location assign secondary-menu secondary` - Then STDERR should be: - """ - Error: Invalid location secondary. - """ - - When I run `wp menu location assign secondary-menu primary` - Then STDOUT should be: - """ - Success: Assigned location primary to menu secondary-menu. - """ - - When I run `wp menu list --fields=slug,locations` - Then STDOUT should be a table containing rows: - | slug | locations | - | primary-menu | | - | secondary-menu | primary | diff --git a/features/menu.feature b/features/menu.feature deleted file mode 100644 index 95d179617..000000000 --- a/features/menu.feature +++ /dev/null @@ -1,78 +0,0 @@ -Feature: Manage WordPress menus - - Background: - Given a WP install - - Scenario: Menu CRUD operations - - When I run `wp menu create "My Menu"` - And I run `wp menu list --fields=name,slug` - Then STDOUT should be a table containing rows: - | name | slug | - | My Menu | my-menu | - - When I run `wp menu delete "My Menu"` - Then STDOUT should be: - """ - Deleted menu 'My Menu'. - Success: Deleted 1 of 1 menus. - """ - And the return code should be 0 - - When I run `wp menu list --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp menu create "First Menu"` - And I run `wp menu create "Second Menu"` - And I run `wp menu list --fields=name,slug` - Then STDOUT should be a table containing rows: - | name | slug | - | First Menu | first-menu | - | Second Menu | second-menu | - - When I run `wp menu delete "First Menu" "Second Menu"` - Then STDOUT should be: - """ - Deleted menu 'First Menu'. - Deleted menu 'Second Menu'. - Success: Deleted 2 of 2 menus. - """ - And the return code should be 0 - - When I run `wp menu list --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp menu create "First Menu"` - And I run `wp menu list --format=ids` - Then STDOUT should be: - """ - 5 - """ - - Scenario: Errors when deleting menus - When I try `wp menu delete "Your menu"` - Then STDERR should be: - """ - Warning: Couldn't delete menu 'Your menu'. - Error: No menus deleted. - """ - - When I run `wp menu create "My Menu"` - And I run `wp menu list --fields=name,slug` - Then STDOUT should be a table containing rows: - | name | slug | - | My Menu | my-menu | - - When I try `wp menu delete "My Menu" "Your menu"` - Then STDERR should be: - """ - Warning: Couldn't delete menu 'Your menu'. - Error: Only deleted 1 of 2 menus. - """ - And the return code should be 1 diff --git a/features/network-meta.feature b/features/network-meta.feature deleted file mode 100644 index f81c3b1b5..000000000 --- a/features/network-meta.feature +++ /dev/null @@ -1,17 +0,0 @@ -Feature: Manage network-wide custom fields. - - Scenario: Non-multisite - Given a WP install - - When I try `wp network-meta` - Then STDOUT should contain: - """ - usage: wp network meta - """ - - When I try `wp network-meta get 1 site_admins` - Then STDOUT should be empty - And STDERR should contain: - """ - This is not a multisite install. - """ diff --git a/features/option-list.feature b/features/option-list.feature deleted file mode 100644 index 9d5b5bca9..000000000 --- a/features/option-list.feature +++ /dev/null @@ -1,66 +0,0 @@ -Feature: List WordPress options - - Scenario: Using the `--transients` flag - Given a WP install - And I run `wp transient set wp_transient_flag wp_transient_flag` - - When I run `wp option list --no-transients` - Then STDOUT should not contain: - """ - wp_transient_flag - """ - And STDOUT should not contain: - """ - _transient - """ - And STDOUT should contain: - """ - siteurl - """ - - When I run `wp option list --transients` - Then STDOUT should contain: - """ - wp_transient_flag - """ - And STDOUT should contain: - """ - _transient - """ - And STDOUT should not contain: - """ - siteurl - """ - - Scenario: List option with exclude pattern - Given a WP install - - When I run `wp option add sample_test_field_one sample_test_field_value_one` - And I run `wp option add sample_test_field_two sample_test_field_value_two` - And I run `wp option list --search="sample_test_field_*" --format=csv` - Then STDOUT should be: - """ - option_name,option_value - sample_test_field_one,sample_test_field_value_one - sample_test_field_two,sample_test_field_value_two - """ - - When I run `wp option list --search="sample_test_field_*" --exclude="*field_one" --format=csv` - Then STDOUT should be: - """ - option_name,option_value - sample_test_field_two,sample_test_field_value_two - """ - - When I run `wp option list` - Then STDOUT should contain: - """ - sample_test_field_one - """ - - When I run `wp option list --exclude="sample_test_field_one"` - Then STDOUT should not contain: - """ - sample_test_field_one - """ - diff --git a/features/option.feature b/features/option.feature deleted file mode 100644 index a122016b9..000000000 --- a/features/option.feature +++ /dev/null @@ -1,203 +0,0 @@ -Feature: Manage WordPress options - - Scenario: Option CRUD - Given a WP install - - # String values - When I run `wp option add str_opt 'bar'` - Then STDOUT should not be empty - - When I run `wp option get str_opt` - Then STDOUT should be: - """ - bar - """ - - When I run `wp option list` - Then STDOUT should not be empty - - When I run `wp option list` - Then STDOUT should contain: - """ - str_opt bar - """ - - When I run `wp option list --autoload=off` - Then STDOUT should not contain: - """ - str_opt bar - """ - - When I run `wp option list --search='str_o*'` - Then STDOUT should be a table containing rows: - | option_name | option_value | - | str_opt | bar | - - When I run `wp option list --search='str_o*' --format=total_bytes` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp option list` - Then STDOUT should contain: - """ - home http://example.com - """ - - When I run `wp option add auto_opt --autoload=no 'bar'` - Then STDOUT should not be empty - - When I run `wp option list --search='auto_opt' --autoload` - Then STDOUT should not be empty - - When I run `wp option list | grep -q "str_opt"` - Then the return code should be 0 - - When I run `wp option delete str_opt` - Then STDOUT should not be empty - - When I run `wp option list` - Then STDOUT should not contain: - """ - str_opt bar - """ - - When I try `wp option get str_opt` - Then the return code should be 1 - - # Integer values - When I run `wp option update blog_public 1` - Then STDOUT should not be empty - - When I run `wp option update blog_public 0` - Then STDOUT should contain: - """ - Success: Updated 'blog_public' option. - """ - - When I run the previous command again - Then STDOUT should contain: - """ - Success: Value passed for 'blog_public' option is unchanged. - """ - - When I run `wp option get blog_public` - Then STDOUT should be: - """ - 0 - """ - - - # JSON values - When I run `wp option set json_opt '[ 1, 2 ]' --format=json` - Then STDOUT should not be empty - - When I run the previous command again - Then STDOUT should not be empty - - When I run `wp option get json_opt --format=json` - Then STDOUT should be: - """ - [1,2] - """ - - - # Reading from files - Given a value.json file: - """ - { - "foo": "bar", - "list": [1, 2, 3] - } - """ - When I run `wp option set foo --format=json < value.json` - And I run `wp option get foo --format=json` - Then STDOUT should be JSON containing: - """ - { - "foo": "bar", - "list": [1, 2, 3] - } - """ - - @require-wp-4.2 - Scenario: Update autoload value for custom option - Given a WP install - And I run `wp option add hello world --autoload=no` - - When I run `wp option update hello universe` - Then STDOUT should not be empty - - When I run `wp option list --search='hello' --fields=option_name,option_value,autoload` - Then STDOUT should be a table containing rows: - | option_name | option_value | autoload | - | hello | universe | no | - - When I run `wp option update hello island --autoload=yes` - Then STDOUT should not be empty - - When I run `wp option list --search='hello' --fields=option_name,option_value,autoload` - Then STDOUT should be a table containing rows: - | option_name | option_value | autoload | - | hello | island | yes | - - @require-wp-4.2 - Scenario: Managed autoloaded options - Given a WP install - - When I run `wp option add wp_autoload_1 enabled --autoload=yes` - Then STDOUT should be: - """ - Success: Added 'wp_autoload_1' option. - """ - And STDERR should be empty - - When I run `wp option add wp_autoload_2 implicit` - Then STDOUT should be: - """ - Success: Added 'wp_autoload_2' option. - """ - And STDERR should be empty - - When I run `wp option add wp_autoload_3 disabled --autoload=no` - Then STDOUT should be: - """ - Success: Added 'wp_autoload_3' option. - """ - And STDERR should be empty - - When I run `wp option list --search='wp_autoload*' --fields=option_name,option_value,autoload` - Then STDOUT should be a table containing rows: - | option_name | option_value | autoload | - | wp_autoload_1 | enabled | yes | - | wp_autoload_2 | implicit | yes | - | wp_autoload_3 | disabled | no | - - When I run `wp option update wp_autoload_1 disabled --autoload=no` - Then STDOUT should be: - """ - Success: Updated 'wp_autoload_1' option. - """ - And STDERR should be empty - - When I run `wp option update wp_autoload_2 implicit2` - Then STDOUT should be: - """ - Success: Updated 'wp_autoload_2' option. - """ - And STDERR should be empty - - When I run `wp option update wp_autoload_3 enabled --autoload=yes` - Then STDOUT should be: - """ - Success: Updated 'wp_autoload_3' option. - """ - And STDERR should be empty - - When I run `wp option list --search='wp_autoload*' --fields=option_name,option_value,autoload` - Then STDOUT should be a table containing rows: - | option_name | option_value | autoload | - | wp_autoload_1 | disabled | no | - | wp_autoload_2 | implicit2 | yes | - | wp_autoload_3 | enabled | yes | diff --git a/features/package-install.feature b/features/package-install.feature deleted file mode 100644 index c7e35445f..000000000 --- a/features/package-install.feature +++ /dev/null @@ -1,537 +0,0 @@ -Feature: Install WP-CLI packages - - Background: - When I run `wp package path` - Then save STDOUT as {PACKAGE_PATH} - - Scenario: Install a package with an http package index url in package composer.json - Given an empty directory - And a composer.json file: - """ - { - "repositories": { - "test" : { - "type": "path", - "url": "./dummy-package/" - }, - "wp-cli": { - "type": "composer", - "url": "http://wp-cli.org/package-index/" - } - } - } - """ - And a dummy-package/composer.json file: - """ - { - "name": "wp-cli/restful", - "description": "This is a dummy package we will install instead of actually installing the real package. This prevents the test from hanging indefinitely for some reason, even though it passes. The 'name' must match a real package as it is checked against the package index." - } - """ - When I run `WP_CLI_PACKAGES_DIR=. wp package install wp-cli/restful --debug` - Then STDOUT should contain: - """ - Updating package index repository url... - """ - And STDOUT should contain: - """ - Success: Package installed - """ - And the composer.json file should contain: - """ - "url": "https://wp-cli.org/package-index/" - """ - And the composer.json file should not contain: - """ - "url": "http://wp-cli.org/package-index/" - """ - - Scenario: Install a package with 'wp-cli/wp-cli' as a dependency - Given a WP install - - When I run `wp package install sinebridge/wp-cli-about:v1.0.1` - Then STDOUT should contain: - """ - Success: Package installed - """ - And STDOUT should not contain: - """ - requires wp-cli/wp-cli - """ - - When I run `wp about` - Then STDOUT should contain: - """ - Site Information - """ - - @require-php-5.6 - Scenario: Install a package with a dependency - Given an empty directory - - When I run `wp package install trendwerk/faker` - Then STDOUT should contain: - """ - Warning: trendwerk/faker dev-master requires nelmio/alice - """ - And STDOUT should contain: - """ - Success: Package installed - """ - And the {PACKAGE_PATH}/vendor/trendwerk directory should contain: - """ - faker - """ - And the {PACKAGE_PATH}/vendor/nelmio directory should contain: - """ - alice - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | trendwerk/faker | - And STDOUT should not contain: - """ - nelmio/alice - """ - - When I run `wp package uninstall trendwerk/faker` - Then STDOUT should contain: - """ - Removing require statement - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - And the {PACKAGE_PATH}/vendor directory should not contain: - """ - trendwerk - """ - And the {PACKAGE_PATH}/vendor directory should not contain: - """ - alice - """ - - When I run `wp package list` - Then STDOUT should not contain: - """ - trendwerk/faker - """ - - @github-api - Scenario: Install a package from a Git URL - Given an empty directory - - When I try `wp package install git@github.com:wp-cli.git` - Then STDERR should be: - """ - Error: Couldn't parse package name from expected path '<name>/<package>'. - """ - - When I run `wp package install git@github.com:wp-cli/google-sitemap-generator-cli.git` - Then STDOUT should contain: - """ - Installing package wp-cli/google-sitemap-generator-cli (dev-master) - Updating {PACKAGE_PATH}composer.json to require the package... - Registering git@github.com:wp-cli/google-sitemap-generator-cli.git as a VCS repository... - Using Composer to install the package... - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | wp-cli/google-sitemap-generator-cli | - - When I run `wp google-sitemap` - Then STDOUT should contain: - """ - usage: wp google-sitemap rebuild - """ - - When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` - Then STDOUT should contain: - """ - Removing require statement from {PACKAGE_PATH}composer.json - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - - When I run `wp package list --fields=name` - Then STDOUT should not contain: - """ - wp-cli/google-sitemap-generator-cli - """ - - Scenario: Install a package in a local zip - Given an empty directory - And I run `wget -O google-sitemap-generator-cli.zip https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip` - - When I run `wp package install google-sitemap-generator-cli.zip` - Then STDOUT should contain: - """ - Installing package wp-cli/google-sitemap-generator-cli (dev-master) - Updating {PACKAGE_PATH}composer.json to require the package... - Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository... - Using Composer to install the package... - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | wp-cli/google-sitemap-generator-cli | - - When I run `wp google-sitemap` - Then STDOUT should contain: - """ - usage: wp google-sitemap rebuild - """ - - When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` - Then STDOUT should contain: - """ - Removing require statement from {PACKAGE_PATH}composer.json - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - - When I run `wp package list --fields=name` - Then STDOUT should not contain: - """ - wp-cli/google-sitemap-generator-cli - """ - - Scenario: Install a package from a remote ZIP - Given an empty directory - - When I try `wp package install https://github.com/wp-cli/google-sitemap-generator.zip` - Then STDERR should be: - """ - Error: Couldn't download package. - """ - - When I run `wp package install https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip` - Then STDOUT should contain: - """ - Installing package wp-cli/google-sitemap-generator-cli (dev-master) - Updating {PACKAGE_PATH}composer.json to require the package... - Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository... - Using Composer to install the package... - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | wp-cli/google-sitemap-generator-cli | - - When I run `wp google-sitemap` - Then STDOUT should contain: - """ - usage: wp google-sitemap rebuild - """ - - When I run `wp package uninstall wp-cli/google-sitemap-generator-cli` - Then STDOUT should contain: - """ - Removing require statement from {PACKAGE_PATH}composer.json - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - - When I run `wp package list --fields=name` - Then STDOUT should not contain: - """ - wp-cli/google-sitemap-generator-cli - """ - - Scenario: Install a package at an existing path - Given an empty directory - And a path-command/command.php file: - """ - <?php - WP_CLI::add_command( 'community-command', function(){ - WP_CLI::success( "success!" ); - }, array( 'when' => 'before_wp_load' ) ); - """ - And a path-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "require": { - }, - "autoload": { - "files": [ "command.php" ] - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - - When I run `pwd` - Then save STDOUT as {CURRENT_PATH} - - When I run `wp package install path-command` - Then STDOUT should contain: - """ - Installing package wp-cli/community-command (dev-master) - Updating {PACKAGE_PATH}composer.json to require the package... - Registering {CURRENT_PATH}/path-command as a path repository... - Using Composer to install the package... - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | wp-cli/community-command | - - When I run `wp community-command` - Then STDOUT should be: - """ - Success: success! - """ - - When I run `wp package uninstall wp-cli/community-command` - Then STDOUT should contain: - """ - Removing require statement from {PACKAGE_PATH}composer.json - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - And the path-command directory should exist - - When I run `wp package list --fields=name` - Then STDOUT should not contain: - """ - wp-cli/community-command - """ - - Scenario: Install a package at an existing path with a version constraint - Given an empty directory - And a path-command/command.php file: - """ - <?php - WP_CLI::add_command( 'community-command', function(){ - WP_CLI::success( "success!" ); - }, array( 'when' => 'before_wp_load' ) ); - """ - And a path-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "version": "0.2.0-beta", - "require": { - }, - "autoload": { - "files": [ "command.php" ] - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - - When I run `pwd` - Then save STDOUT as {CURRENT_PATH} - - When I run `wp package install path-command` - Then STDOUT should contain: - """ - Installing package wp-cli/community-command (0.2.0-beta) - Updating {PACKAGE_PATH}composer.json to require the package... - Registering {CURRENT_PATH}/path-command as a path repository... - Using Composer to install the package... - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `wp package list --fields=name` - Then STDOUT should be a table containing rows: - | name | - | wp-cli/community-command | - - When I run `wp community-command` - Then STDOUT should be: - """ - Success: success! - """ - - When I run `wp package uninstall wp-cli/community-command` - Then STDOUT should contain: - """ - Removing require statement from {PACKAGE_PATH}composer.json - """ - And STDOUT should contain: - """ - Success: Uninstalled package. - """ - And the path-command directory should exist - - When I run `wp package list --fields=name` - Then STDOUT should not contain: - """ - wp-cli/community-command - """ - - Scenario: Install a package requiring a WP-CLI version that doesn't match - Given an empty directory - And a new Phar with version "0.23.0" - And a path-command/command.php file: - """ - <?php - WP_CLI::add_command( 'community-command', function(){ - WP_CLI::success( "success!" ); - }, array( 'when' => 'before_wp_load' ) ); - """ - And a path-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "autoload": { - "files": [ "command.php" ] - }, - "require": { - "wp-cli/wp-cli": ">=0.24.0" - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - - When I try `{PHAR_PATH} package install path-command` - Then STDOUT should contain: - """ - wp-cli/community-command dev-master requires wp-cli/wp-cli >=0.24.0 - """ - And STDERR should contain: - """ - Error: Package installation failed - """ - And the return code should be 1 - - When I run `cat {PACKAGE_PATH}composer.json` - Then STDOUT should contain: - """ - "version": "0.23.0", - """ - - Scenario: Install a package requiring a WP-CLI version that does match - Given an empty directory - And a new Phar with version "0.23.0" - And a path-command/command.php file: - """ - <?php - WP_CLI::add_command( 'community-command', function(){ - WP_CLI::success( "success!" ); - }, array( 'when' => 'before_wp_load' ) ); - """ - And a path-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "autoload": { - "files": [ "command.php" ] - }, - "require": { - "wp-cli/wp-cli": ">=0.22.0" - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - - When I run `{PHAR_PATH} package install path-command` - Then STDOUT should contain: - """ - Success: Package installed. - """ - And the return code should be 0 - - When I run `cat {PACKAGE_PATH}composer.json` - Then STDOUT should contain: - """ - "version": "0.23.0", - """ - - Scenario: Install a package requiring a WP-CLI alpha version that does match - Given an empty directory - And a new Phar with version "0.23.0-alpha-90ecad6" - And a path-command/command.php file: - """ - <?php - WP_CLI::add_command( 'community-command', function(){ - WP_CLI::success( "success!" ); - }, array( 'when' => 'before_wp_load' ) ); - """ - And a path-command/composer.json file: - """ - { - "name": "wp-cli/community-command", - "description": "A demo community command.", - "license": "MIT", - "minimum-stability": "dev", - "autoload": { - "files": [ "command.php" ] - }, - "require": { - "wp-cli/wp-cli": ">=0.22.0" - }, - "require-dev": { - "behat/behat": "~2.5" - } - } - """ - - When I run `{PHAR_PATH} package install path-command` - Then STDOUT should contain: - """ - Success: Package installed. - """ - And the return code should be 0 - - When I run `cat {PACKAGE_PATH}composer.json` - Then STDOUT should contain: - """ - "version": "0.23.0-alpha", - """ diff --git a/features/package-update.feature b/features/package-update.feature deleted file mode 100644 index 151d3301b..000000000 --- a/features/package-update.feature +++ /dev/null @@ -1,109 +0,0 @@ -Feature: Update WP-CLI packages - - Background: - When I run `wp package path` - Then save STDOUT as {PACKAGE_PATH} - - Scenario: Updating WP-CLI packages runs successfully - Given an empty directory - - When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` - Then STDOUT should contain: - """ - Success: Package installed. - """ - Then STDERR should be empty - - When I run `wp package update` - Then STDOUT should contain: - """ - Using Composer to update packages... - """ - And STDOUT should contain: - """ - Packages updated. - """ - And STDERR should be empty - - Scenario: Update a package with an update available - Given an empty directory - - When I run `wp package install wp-cli/scaffold-package-command:0.1.0` - Then STDOUT should contain: - """ - Installing package wp-cli/scaffold-package-command (0.1.0) - """ - And STDOUT should contain: - """ - Success: Package installed. - """ - - When I run `cat {PACKAGE_PATH}/composer.json` - Then STDOUT should contain: - """ - "wp-cli/scaffold-package-command": "0.1.0" - """ - - When I run `wp help scaffold package` - Then STDOUT should contain: - """ - wp scaffold package <name> - """ - - When I run `wp package update` - Then STDOUT should contain: - """ - Nothing to install or update - """ - And STDOUT should contain: - """ - Success: Packages updated. - """ - - When I run `wp package list --fields=name,update` - Then STDOUT should be a table containing rows: - | name | update | - | wp-cli/scaffold-package-command | available | - - When I run `sed -i.bak s/0.1.0/\>=0.1.0/g {PACKAGE_PATH}/composer.json` - Then the return code should be 0 - - When I run `cat {PACKAGE_PATH}/composer.json` - Then STDOUT should contain: - """ - "wp-cli/scaffold-package-command": ">=0.1.0" - """ - - When I run `wp package list --fields=name,update` - Then STDOUT should be a table containing rows: - | name | update | - | wp-cli/scaffold-package-command | available | - - When I run `wp package update` - Then STDOUT should contain: - """ - Writing lock file - """ - And STDOUT should contain: - """ - Success: Packages updated. - """ - And STDOUT should not contain: - """ - Nothing to install or update - """ - - When I run `wp package list --fields=name,update` - Then STDOUT should be a table containing rows: - | name | update | - | wp-cli/scaffold-package-command | none | - - When I run `wp package update` - Then STDOUT should contain: - """ - Nothing to install or update - """ - And STDOUT should contain: - """ - Success: Packages updated. - """ diff --git a/features/package.feature b/features/package.feature deleted file mode 100644 index daafbc4e7..000000000 --- a/features/package.feature +++ /dev/null @@ -1,58 +0,0 @@ -Feature: Manage WP-CLI packages - - Scenario: Package CRUD - Given an empty directory - - When I run `wp package browse` - Then STDOUT should contain: - """ - danielbachhuber/wp-cli-reset-post-date-command - """ - - When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command` - Then STDERR should be empty - - When I run `wp help reset-post-date` - Then STDERR should be empty - - When I try `wp --skip-packages --debug help reset-post-date` - Then STDERR should contain: - """ - Debug (bootstrap): Skipped loading packages. - """ - And STDERR should contain: - """ - Error: This does not seem to be a WordPress install. - """ - - When I run `wp package list` - Then STDOUT should contain: - """ - danielbachhuber/wp-cli-reset-post-date-command - """ - - When I run `wp package uninstall danielbachhuber/wp-cli-reset-post-date-command` - Then STDERR should be empty - - When I run `wp package list` - Then STDOUT should not contain: - """ - danielbachhuber/wp-cli-reset-post-date-command - """ - - Scenario: Run package commands early, before any bad code can break them - Given an empty directory - And a bad-command.php file: - """ - <?php - WP_CLI::error( "Doing it wrong." ); - """ - - When I try `wp --require=bad-command.php option` - Then STDERR should contain: - """ - Error: Doing it wrong. - """ - - When I run `wp --require=bad-command.php package list` - Then STDERR should be empty diff --git a/features/plugin-activate.feature b/features/plugin-activate.feature deleted file mode 100644 index 949168774..000000000 --- a/features/plugin-activate.feature +++ /dev/null @@ -1,35 +0,0 @@ -Feature: Activate WordPress plugins - - Background: - Given a WP install - - Scenario: Activate a plugin that's already installed - When I run `wp plugin activate akismet` - Then STDOUT should be: - """ - Plugin 'akismet' activated. - Success: Activated 1 of 1 plugins. - """ - And the return code should be 0 - - Scenario: Attempt to activate a plugin that's not installed - When I try `wp plugin activate edit-flow` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Error: No plugins activated. - """ - And the return code should be 1 - - When I try `wp plugin activate akismet hello edit-flow` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Error: Only activated 2 of 3 plugins. - """ - And STDOUT should be: - """ - Plugin 'akismet' activated. - Plugin 'hello' activated. - """ - And the return code should be 1 diff --git a/features/plugin-deactivate.feature b/features/plugin-deactivate.feature deleted file mode 100644 index 37b68dce7..000000000 --- a/features/plugin-deactivate.feature +++ /dev/null @@ -1,36 +0,0 @@ -Feature: Deactivate WordPress plugins - - Background: - Given a WP install - And I run `wp plugin activate akismet hello` - - Scenario: Deactivate a plugin that's already activated - When I run `wp plugin deactivate akismet` - Then STDOUT should be: - """ - Plugin 'akismet' deactivated. - Success: Deactivated 1 of 1 plugins. - """ - And the return code should be 0 - - Scenario: Attempt to deactivate a plugin that's not installed - When I try `wp plugin deactivate edit-flow` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Error: No plugins deactivated. - """ - And the return code should be 1 - - When I try `wp plugin deactivate akismet hello edit-flow` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Error: Only deactivated 2 of 3 plugins. - """ - And STDOUT should be: - """ - Plugin 'akismet' deactivated. - Plugin 'hello' deactivated. - """ - And the return code should be 1 diff --git a/features/plugin-delete.feature b/features/plugin-delete.feature deleted file mode 100644 index c1e5fa7d9..000000000 --- a/features/plugin-delete.feature +++ /dev/null @@ -1,25 +0,0 @@ -Feature: Delete WordPress plugins - - Background: - Given a WP install - - Scenario: Delete an installed plugin - When I run `wp plugin delete akismet` - Then STDOUT should be: - """ - Deleted 'akismet' plugin. - Success: Deleted 1 of 1 plugins. - """ - And the return code should be 0 - - Scenario: Attempting to delete a plugin that doesn't exist - When I run `wp plugin delete edit-flow` - Then STDOUT should be: - """ - Success: Plugin already deleted. - """ - And STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - """ - And the return code should be 0 diff --git a/features/plugin-install.feature b/features/plugin-install.feature deleted file mode 100644 index 0107cc498..000000000 --- a/features/plugin-install.feature +++ /dev/null @@ -1,143 +0,0 @@ -Feature: Install WordPress plugins - - Scenario: Branch names should be removed from Github projects - Given a WP install - - When I run `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip --activate` - Then STDOUT should contain: - """ - Downloading install package from https://github.com/runcommand/one-time-login/archive/master.zip - """ - And STDOUT should contain: - """ - Renamed Github-based project from 'one-time-login-master' to 'one-time-login'. - """ - And STDOUT should contain: - """ - Plugin installed successfully. - """ - And STDERR should be empty - And the wp-content/plugins/one-time-login directory should exist - And the wp-content/plugins/one-time-login-master directory should not exist - - When I try `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip` - Then STDERR should contain: - """ - Warning: Destination folder already exists - """ - And the wp-content/plugins/one-time-login directory should exist - And the wp-content/plugins/one-time-login-master directory should not exist - - When I run `wp plugin install https://github.com/runcommand/one-time-login/archive/master.zip --force` - Then STDOUT should contain: - """ - Plugin updated successfully. - """ - And the wp-content/plugins/one-time-login directory should exist - And the wp-content/plugins/one-time-login-master directory should not exist - - Scenario: Don't attempt to rename ZIPs uploaded to GitHub's releases page - Given a WP install - - When I run `wp plugin install https://github.com/danielbachhuber/one-time-login/releases/download/v0.1.2/one-time-login.0.1.2.zip` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And STDOUT should not contain: - """ - Renamed Github-based project from - """ - And STDERR should be empty - And the wp-content/plugins/one-time-login directory should exist - - Scenario: Don't attempt to rename ZIPs coming from a GitHub raw source - Given a WP install - - When I run `wp plugin install https://github.com/Miller-Media/modern-wordpress/raw/master/builds/modern-framework-stable.zip` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And STDOUT should not contain: - """ - Renamed Github-based project from - """ - And STDERR should be empty - And the wp-content/plugins/modern-framework directory should exist - - Scenario: Installing respects WP_PROXY_HOST and WP_PROXY_PORT - Given a WP install - And a invalid-proxy-details.php file: - """ - <?php - define( 'WP_PROXY_HOST', 'https://wp-cli.org' ); - define( 'WP_PROXY_PORT', '443' ); - """ - - When I try `wp --require=invalid-proxy-details.php plugin install edit-flow` - Then STDERR should contain: - """ - Warning: edit-flow: An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. - """ - And STDOUT should be empty - - When I run `wp plugin install edit-flow` - Then STDOUT should contain: - """ - Plugin installed successfully. - """ - And STDERR should be empty - - Scenario: Return code is 1 when one or more plugin installations fail - Given a WP install - - When I try `wp plugin install user-switching user-switching-not-a-plugin` - Then STDERR should be: - """ - Warning: Couldn't find 'user-switching-not-a-plugin' in the WordPress.org plugin directory. - Error: Only installed 1 of 2 plugins. - """ - And STDOUT should contain: - """ - Installing User Switching - """ - And STDOUT should contain: - """ - Plugin installed successfully. - """ - And the return code should be 1 - - When I run `wp plugin install user-switching` - Then STDOUT should be: - """ - Success: Plugin already installed. - """ - And STDERR should be: - """ - Warning: user-switching: Plugin already installed. - """ - And the return code should be 0 - - When I try `wp plugin install user-switching-not-a-plugin` - Then STDERR should be: - """ - Warning: Couldn't find 'user-switching-not-a-plugin' in the WordPress.org plugin directory. - Error: No plugins installed. - """ - And the return code should be 1 - - Scenario: Paths aren't backslashed when destination folder already exists - Given a WP install - - When I run `pwd` - Then save STDOUT as {WORKING_DIR} - - When I run `rm wp-content/plugins/akismet/akismet.php` - Then the return code should be 0 - - When I try `wp plugin install akismet` - Then STDERR should contain: - """ - Warning: Destination folder already exists. "{WORKING_DIR}/wp-content/plugins/akismet/" - """ diff --git a/features/plugin-search.feature b/features/plugin-search.feature deleted file mode 100644 index 00a78875b..000000000 --- a/features/plugin-search.feature +++ /dev/null @@ -1,14 +0,0 @@ -Feature: Search WordPress.org plugins - - Scenario: Search for plugins with active_installs field - Given a WP install - - When I run `wp plugin search foo --fields=name,slug,active_installs --format=csv` - Then STDOUT should contain: - """ - Success: Showing - """ - And STDOUT should contain: - """ - name,slug,active_installs - """ diff --git a/features/plugin-toggle.feature b/features/plugin-toggle.feature deleted file mode 100644 index 4c81bff92..000000000 --- a/features/plugin-toggle.feature +++ /dev/null @@ -1,42 +0,0 @@ -Feature: Toggle the activation status of a plugin - - Background: - Given a WP install - - Scenario: Toggle the status of a plugin - When I run `wp plugin toggle akismet` - Then STDOUT should be: - """ - Plugin 'akismet' activated. - Success: Toggled 1 of 1 plugins. - """ - - When I run `wp plugin toggle akismet` - Then STDOUT should be: - """ - Plugin 'akismet' deactivated. - Success: Toggled 1 of 1 plugins. - """ - - Scenario: Toggling the status of a plugin that doesn't exist - When I try `wp plugin toggle akismet edit-flow` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Error: Only toggled 1 of 2 plugins. - """ - And STDOUT should be: - """ - Plugin 'akismet' activated. - """ - And the return code should be 1 - - When I try `wp plugin toggle edit-flow co-authors-plus` - Then STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - Warning: The 'co-authors-plus' plugin could not be found. - Error: No plugins toggled. - """ - And STDOUT should be empty - And the return code should be 1 diff --git a/features/plugin-uninstall.feature b/features/plugin-uninstall.feature deleted file mode 100644 index 5c6cbfd04..000000000 --- a/features/plugin-uninstall.feature +++ /dev/null @@ -1,37 +0,0 @@ -Feature: Uninstall a WordPress plugin - - Background: - Given a WP install - - Scenario: Uninstall an installed plugin - When I run `wp plugin uninstall akismet` - Then STDOUT should be: - """ - Uninstalled and deleted 'akismet' plugin. - Success: Uninstalled 1 of 1 plugins. - """ - And the return code should be 0 - - Scenario: Attempting to uninstall a plugin that's activated - When I run `wp plugin activate akismet` - Then STDOUT should not be empty - - When I try `wp plugin uninstall akismet` - Then STDERR should be: - """ - Warning: The 'akismet' plugin is active. - Error: No plugins uninstalled. - """ - And the return code should be 1 - - Scenario: Attempting to uninstall a plugin that doesn't exist - When I run `wp plugin uninstall edit-flow` - Then STDOUT should be: - """ - Success: Plugin already uninstalled. - """ - And STDERR should be: - """ - Warning: The 'edit-flow' plugin could not be found. - """ - And the return code should be 0 diff --git a/features/plugin-update.feature b/features/plugin-update.feature deleted file mode 100644 index 7144cccae..000000000 --- a/features/plugin-update.feature +++ /dev/null @@ -1,35 +0,0 @@ -Feature: Update WordPress plugins - - Scenario: Updating plugin with invalid version shouldn't remove the old version - Given a WP install - - When I run `wp plugin install akismet --version=2.5.6 --force` - Then STDOUT should not be empty - - When I run `wp plugin list --name=akismet --field=update_version` - Then STDOUT should not be empty - And save STDOUT as {UPDATE_VERSION} - - When I run `wp plugin list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | inactive | available | 2.5.6 | - - When I try `wp plugin update akismet --version=2.9.0` - Then STDERR should be: - """ - Error: Can't find the requested plugin's version 2.9.0 in the WordPress.org plugin repository (HTTP code 404). - """ - - When I run `wp plugin list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | inactive | available | 2.5.6 | - - When I run `wp plugin update akismet` - Then STDOUT should not be empty - - When I run `wp plugin list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | inactive | none | {UPDATE_VERSION} | diff --git a/features/plugin.feature b/features/plugin.feature deleted file mode 100644 index 9fe4a7927..000000000 --- a/features/plugin.feature +++ /dev/null @@ -1,476 +0,0 @@ -Feature: Manage WordPress plugins - - Scenario: Create, activate and check plugin status - Given a WP install - And I run `wp plugin path` - And save STDOUT as {PLUGIN_DIR} - - When I run `wp plugin scaffold --skip-tests plugin1` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/plugin1/plugin1.php file should exist - And the {PLUGIN_DIR}/zombieland/phpunit.xml.dist file should not exist - - When I run `wp plugin path plugin1` - Then STDOUT should be: - """ - {PLUGIN_DIR}/plugin1/plugin1.php - """ - - When I run `wp plugin path plugin1 --dir` - Then STDOUT should be: - """ - {PLUGIN_DIR}/plugin1 - """ - - When I run `wp plugin scaffold Zombieland` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/Zombieland/Zombieland.php file should exist - And the {PLUGIN_DIR}/Zombieland/phpunit.xml.dist file should exist - - # Ensure case sensitivity - When I try `wp plugin status zombieLand` - Then STDERR should contain: - """ - The 'zombieLand' plugin could not be found. - """ - - # Check that the inner-plugin is not picked up - When I run `mv {PLUGIN_DIR}/plugin1 {PLUGIN_DIR}/Zombieland/` - And I run `wp plugin status Zombieland` - Then STDOUT should contain: - """ - Plugin Zombieland details: - Name: Zombieland - Status: Inactive - Version: 0.1.0 - Author: YOUR NAME HERE - Description: PLUGIN DESCRIPTION HERE - """ - - When I run `wp plugin activate Zombieland` - Then STDOUT should not be empty - - When I run `wp plugin status Zombieland` - Then STDOUT should contain: - """ - Status: Active - """ - - When I run `wp plugin status` - Then STDOUT should not be empty - - When I run `wp plugin list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | Zombieland | active | none | 0.1.0 | - - When I try `wp plugin uninstall Zombieland` - Then STDERR should contain: - """ - The 'Zombieland' plugin is active. - """ - - When I run `wp plugin deactivate Zombieland` - Then STDOUT should not be empty - - When I run `wp option get recently_activated` - Then STDOUT should contain: - """ - Zombieland/Zombieland.php - """ - - When I run `wp plugin uninstall Zombieland` - Then STDOUT should be: - """ - Uninstalled and deleted 'Zombieland' plugin. - Success: Uninstalled 1 of 1 plugins. - """ - And the {PLUGIN_DIR}/zombieland file should not exist - - When I try the previous command again - Then STDERR should contain: - """ - The 'Zombieland' plugin could not be found. - """ - - Scenario: Install a plugin, activate, then force install an older version of the plugin - Given a WP install - - When I run `wp plugin install akismet --version=2.5.7 --force` - Then STDOUT should not be empty - - When I run `wp plugin list --name=akismet --field=update_version` - Then STDOUT should not be empty - And save STDOUT as {UPDATE_VERSION} - - When I run `wp plugin list --fields=name,status,update,version,update_version` - Then STDOUT should be a table containing rows: - | name | status | update | version | update_version | - | akismet | inactive | available | 2.5.7 | {UPDATE_VERSION} | - - When I run `wp plugin activate akismet` - Then STDOUT should not be empty - - When I run `wp plugin install akismet --version=2.5.6 --force` - Then STDOUT should not be empty - - When I run `wp plugin list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | akismet | active | available | 2.5.6 | - - When I try `wp plugin update` - Then STDERR should be: - """ - Error: Please specify one or more plugins, or use --all. - """ - - When I run `wp plugin update --all --format=summary | grep 'updated successfully from'` - Then STDOUT should contain: - """ - Akismet updated successfully from version 2.5.6 to version - """ - - When I try `wp plugin update xxx yyy` - Then STDERR should contain: - """ - Warning: The 'xxx' plugin could not be found. - """ - And STDERR should contain: - """ - Warning: The 'yyy' plugin could not be found. - """ - And STDERR should contain: - """ - Error: No plugins updated. - """ - - When I run `wp plugin install akismet --version=2.5.6 --force` - Then STDOUT should not be empty - - When I try `wp plugin update akismet hello xxx` - Then STDERR should contain: - """ - Warning: The 'xxx' plugin could not be found. - """ - And STDERR should contain: - """ - Error: Only updated 1 of 3 plugins. - """ - - Scenario: Activate a network-only plugin on single site - Given a WP install - And a wp-content/plugins/network-only.php file: - """ - // Plugin Name: Example Plugin - // Network: true - """ - - When I run `wp plugin activate network-only` - Then STDOUT should be: - """ - Plugin 'network-only' activated. - Success: Activated 1 of 1 plugins. - """ - - When I run `wp plugin status network-only` - Then STDOUT should contain: - """ - Status: Active - """ - - Scenario: Activate a network-only plugin on multisite - Given a WP multisite install - And a wp-content/plugins/network-only.php file: - """ - // Plugin Name: Example Plugin - // Network: true - """ - - When I run `wp plugin activate network-only` - Then STDOUT should be: - """ - Plugin 'network-only' network activated. - Success: Activated 1 of 1 plugins. - """ - - When I run `wp plugin status network-only` - Then STDOUT should contain: - """ - Status: Network Active - """ - - Scenario: Network activate a plugin - Given a WP multisite install - - When I run `wp plugin activate akismet` - Then STDOUT should be: - """ - Plugin 'akismet' activated. - Success: Activated 1 of 1 plugins. - """ - - When I run `wp plugin list --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | akismet | active | - - When I run `wp plugin activate akismet` - Then STDERR should contain: - """ - Warning: Plugin 'akismet' is already active. - """ - And STDOUT should be: - """ - Success: Plugin already activated. - """ - - When I run `wp plugin activate akismet --network` - Then STDOUT should be: - """ - Plugin 'akismet' network activated. - Success: Network activated 1 of 1 plugins. - """ - - When I run `wp plugin activate akismet --network` - Then STDERR should be: - """ - Warning: Plugin 'akismet' is already network active. - """ - And STDOUT should be: - """ - Success: Plugin already network activated. - """ - - When I try `wp plugin deactivate akismet` - Then STDERR should be: - """ - Warning: Plugin 'akismet' is network active and must be deactivated with --network flag. - Error: No plugins deactivated. - """ - And the return code should be 1 - - When I run `wp plugin deactivate akismet --network` - Then STDOUT should be: - """ - Plugin 'akismet' network deactivated. - Success: Network deactivated 1 of 1 plugins. - """ - And the return code should be 0 - - When I run `wp plugin deactivate akismet` - Then STDERR should be: - """ - Warning: Plugin 'akismet' isn't active. - """ - And STDOUT should be: - """ - Success: Plugin already deactivated. - """ - And the return code should be 0 - - Scenario: List plugins - Given a WP install - - When I run `wp plugin activate akismet hello` - Then STDOUT should not be empty - - When I run `wp plugin list --status=inactive --field=name` - Then STDOUT should be empty - - When I run `wp plugin list --status=active --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | akismet | active | - - Scenario: Install a plugin when directory doesn't yet exist - Given a WP install - - When I run `rm -rf wp-content/plugins` - And I run `if test -d wp-content/plugins; then echo "fail"; fi` - Then STDOUT should be empty - - When I run `wp plugin install akismet --activate` - Then STDOUT should not be empty - - When I run `wp plugin list --status=active --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | akismet | active | - - Scenario: Plugin name with HTML entities - Given a WP install - - When I run `wp plugin install debug-bar-list-dependencies` - Then STDOUT should contain: - """ - Installing Debug Bar List Script & Style Dependencies - """ - - Scenario: Enable and disable all plugins - Given a WP install - - When I run `wp plugin activate --all` - Then STDOUT should be: - """ - Plugin 'akismet' activated. - Plugin 'hello' activated. - Success: Activated 2 of 2 plugins. - """ - - When I run `wp plugin activate --all` - Then STDOUT should be: - """ - Success: Plugins already activated. - """ - - When I run `wp plugin list --field=status` - Then STDOUT should be: - """ - active - active - must-use - """ - - When I run `wp plugin deactivate --all` - Then STDOUT should be: - """ - Plugin 'akismet' deactivated. - Plugin 'hello' deactivated. - Success: Deactivated 2 of 2 plugins. - """ - - When I run `wp plugin deactivate --all` - Then STDOUT should be: - """ - Success: Plugins already deactivated. - """ - - When I run `wp plugin list --field=status` - Then STDOUT should be: - """ - inactive - inactive - must-use - """ - - Scenario: Deactivate and uninstall a plugin, part one - Given a WP install - And these installed and active plugins: - """ - akismet - """ - - When I run `wp plugin deactivate akismet --uninstall` - Then STDOUT should be: - """ - Plugin 'akismet' deactivated. - Uninstalling 'akismet'... - Uninstalled and deleted 'akismet' plugin. - Success: Deactivated 1 of 1 plugins. - """ - - When I try `wp plugin get akismet` - Then STDERR should be: - """ - Error: The 'akismet' plugin could not be found. - """ - - Scenario: Deactivate and uninstall a plugin, part two - Given a WP install - And these installed and active plugins: - """ - akismet - """ - - When I run `wp plugin uninstall akismet --deactivate` - Then STDOUT should be: - """ - Deactivating 'akismet'... - Plugin 'akismet' deactivated. - Uninstalled and deleted 'akismet' plugin. - Success: Uninstalled 1 of 1 plugins. - """ - - When I try `wp plugin get akismet` - Then STDERR should be: - """ - Error: The 'akismet' plugin could not be found. - """ - - - Scenario: Uninstall a plugin without deleting - Given a WP install - - When I run `wp plugin install akismet --version=2.5.7 --force` - Then STDOUT should not be empty - - When I run `wp plugin uninstall akismet --skip-delete` - Then STDOUT should be: - """ - Ran uninstall procedure for 'akismet' plugin without deleting. - Success: Uninstalled 1 of 1 plugins. - """ - - Scenario: Two plugins, one directory - Given a WP install - And a wp-content/plugins/handbook/handbook.php file: - """ - <?php - /** - * Plugin Name: Handbook - * Description: Features for a handbook, complete with glossary and table of contents - * Author: Nacin - */ - """ - And a wp-content/plugins/handbook/functionality-for-pages.php file: - """ - <?php - /** - * Plugin Name: Handbook Functionality for Pages - * Description: Adds handbook-like table of contents to all Pages for a site. Covers Table of Contents and the "watch this page" widget - * Author: Nacin - */ - """ - - When I run `wp plugin list --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | handbook/handbook | inactive | - | handbook/functionality-for-pages | inactive | - - When I run `wp plugin activate handbook/functionality-for-pages` - Then STDOUT should not be empty - - When I run `wp plugin list --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | handbook/handbook | inactive | - | handbook/functionality-for-pages | active | - - Scenario: Install a plugin, then update to a specific version of that plugin - Given a WP install - - When I run `wp plugin install akismet --version=2.5.7 --force` - Then STDOUT should not be empty - - When I run `wp plugin update akismet --version=2.6.0` - Then STDOUT should not be empty - - When I run `wp plugin list --fields=name,version` - Then STDOUT should be a table containing rows: - | name | version | - | akismet | 2.6.0 | - - Scenario: Ignore empty slugs - Given a WP install - - When I run `wp plugin install ''` - Then STDERR should contain: - """ - Warning: Ignoring ambigious empty slug value. - """ - And STDOUT should not contain: - """ - Plugin installed successfully - """ diff --git a/features/post-generate.feature b/features/post-generate.feature deleted file mode 100644 index 6dec688ab..000000000 --- a/features/post-generate.feature +++ /dev/null @@ -1,44 +0,0 @@ -Feature: Generate new WordPress posts - - Background: - Given a WP install - - Scenario: Generating posts - When I run `echo "Content generated by wp post generate" | wp post generate --count=1 --post_content` - And I run `wp post list --field=post_content` - Then STDOUT should contain: - """ - Content generated by wp post generate - """ - And STDERR should be empty - - Scenario: Generating posts by a specific author - - When I run `wp user create dummyuser dummy@example.com --porcelain` - Then save STDOUT as {AUTHOR_ID} - - When I run `wp post generate --post_author={AUTHOR_ID} --post_type=post --count=16` - And I run `wp post list --post_type=post --author={AUTHOR_ID} --format=count` - Then STDOUT should contain: - """ - 16 - """ - - Scenario: Generating pages - When I run `wp post generate --post_type=page --max_depth=10` - And I run `wp post list --post_type=page --field=post_parent` - Then STDOUT should contain: - """ - 1 - """ - - Scenario: Generating posts and outputting ids - When I run `wp post generate --count=1 --format=ids` - Then save STDOUT as {POST_ID} - - When I run `wp post update {POST_ID} --post_title="foo"` - Then STDOUT should contain: - """ - Success: - """ - diff --git a/features/post-meta.feature b/features/post-meta.feature deleted file mode 100644 index e8dd92da3..000000000 --- a/features/post-meta.feature +++ /dev/null @@ -1,141 +0,0 @@ -Feature: Manage post custom fields - - Scenario: Postmeta CRUD - Given a WP install - - When I run `wp post-meta add 1 foo 'bar'` - Then STDOUT should not be empty - - When I run `wp post-meta get 1 foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp post meta get 999999 foo` - Then STDERR should be: - """ - Error: Could not find the post with ID 999999. - """ - - When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run the previous command again - Then STDOUT should be: - """ - Success: Value passed for custom field 'foo' is unchanged. - """ - - When I run `wp post-meta get 1 foo --format=json` - Then STDOUT should be: - """ - ["1","2"] - """ - - When I run `echo 'via STDIN' | wp post-meta set 1 foo` - And I run `wp post-meta get 1 foo` - Then STDOUT should be: - """ - via STDIN - """ - - When I run `wp post-meta delete 1 foo` - Then STDOUT should not be empty - - When I try `wp post-meta get 1 foo` - Then the return code should be 1 - - Scenario: List post meta - Given a WP install - - When I run `wp post meta add 1 apple banana` - And I run `wp post meta add 1 apple banana` - Then STDOUT should not be empty - - When I run `wp post meta set 1 banana '["apple", "apple"]' --format=json` - Then STDOUT should not be empty - - When I run `wp post meta list 1` - Then STDOUT should be a table containing rows: - | post_id | meta_key | meta_value | - | 1 | apple | banana | - | 1 | apple | banana | - | 1 | banana | ["apple","apple"] | - - Scenario: Delete all post meta - Given a WP install - - When I run `wp post meta add 1 apple banana` - And I run `wp post meta add 1 _foo banana` - Then STDOUT should not be empty - - When I run `wp post meta list 1 --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I try `wp post meta delete 1` - Then STDERR should be: - """ - Error: Please specify a meta key, or use the --all flag. - """ - - When I run `wp post meta delete 1 --all` - Then STDOUT should contain: - """ - Deleted 'apple' custom field. - Deleted '_foo' custom field. - Success: Deleted all custom fields. - """ - - When I run `wp post meta list 1 --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: List post meta with a null value - Given a WP install - And a setup.php file: - """ - <?php - update_post_meta( 1, 'foo', NULL ); - """ - And I run `wp eval-file setup.php` - - When I run `wp post meta list 1` - Then STDOUT should be a table containing rows: - | post_id | meta_key | meta_value | - | 1 | foo | | - - Scenario: Make sure WordPress receives the slashed data it expects in meta fields - Given a WP install - - When I run `wp post-meta add 1 foo 'My\Meta'` - Then STDOUT should not be empty - - When I run `wp post-meta get 1 foo` - Then STDOUT should be: - """ - My\Meta - """ - - When I run `wp post-meta update 1 foo 'My\New\Meta'` - Then STDOUT should be: - """ - Success: Updated custom field 'foo'. - """ - - When I run the previous command again - Then STDOUT should be: - """ - Success: Value passed for custom field 'foo' is unchanged. - """ - - When I run `wp post-meta get 1 foo` - Then STDOUT should be: - """ - My\New\Meta - """ diff --git a/features/post-term.feature b/features/post-term.feature deleted file mode 100644 index 94893c427..000000000 --- a/features/post-term.feature +++ /dev/null @@ -1,105 +0,0 @@ -Feature: Manage post term - - Scenario: Postterm CRUD - Given a WP install - - When I run `wp post term add 1 category foo` - Then STDOUT should be: - """ - Success: Added term. - """ - - When I run `wp post term list 1 category --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | foo | foo | category | - - When I run `wp post term add 1 category bar` - Then STDOUT should be: - """ - Success: Added term. - """ - - When I run `wp post term list 1 category --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | foo | foo | category | - | bar | bar | category | - - When I run `wp post term list 1 category --format=ids` - Then STDOUT should be: - """ - 3 2 1 - """ - - When I try `wp post term list 1 foo2` - Then STDERR should be: - """ - Error: Invalid taxonomy foo2. - """ - - When I run `wp post term set 1 category new` - Then STDOUT should be: - """ - Success: Set terms. - """ - - When I run `wp post term list 1 category --fields=name,slug,taxonomy --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp post term remove 1 category new` - Then STDOUT should be: - """ - Success: Deleted term. - """ - - When I run `wp post term list 1 category --fields=name,slug,taxonomy --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Multiple post term - Given a WP install - - When I run `wp post term add 1 category apple` - And I run `wp post term add 1 category apple` - Then STDOUT should be: - """ - Success: Added term. - """ - - When I run `wp post term set 1 category apple1 apple2` - Then STDOUT should be: - """ - Success: Set terms. - """ - - When I run `wp post term list 1 category --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | apple1 | apple1 | category | - | apple2 | apple2 | category | - - Scenario: Invalid Post ID - Given a WP install - - When I try `wp post term add 99999 category boo` - Then the return code should be 1 - And STDERR should be: - """ - Error: Could not find the post with ID 99999. - """ - - Scenario: Postterm Add invalid tax - Given a WP install - - When I try `wp post term add 1 foo2 boo` - Then the return code should be 1 - And STDERR should be: - """ - Error: Invalid taxonomy foo2. - """ diff --git a/features/post-type.feature b/features/post-type.feature deleted file mode 100644 index 08f2a1f61..000000000 --- a/features/post-type.feature +++ /dev/null @@ -1,24 +0,0 @@ -Feature: Manage WordPress post types - - Background: - Given a WP install - - Scenario: Listing post types - When I run `wp post-type list --format=csv` - Then STDOUT should be CSV containing: - | name | label | description | hierarchical | public | capability_type | - | post | Posts | | | 1 | post | - | page | Pages | | 1 | 1 | page | - - Scenario: Get a post type - When I try `wp post-type get invalid-post-type` - Then STDERR should be: - """ - Error: Post type invalid-post-type doesn't exist. - """ - - When I run `wp post-type get page` - Then STDOUT should be a table containing rows: - | Field | Value | - | name | page | - | label | Pages | diff --git a/features/post.feature b/features/post.feature deleted file mode 100644 index 406b9a76c..000000000 --- a/features/post.feature +++ /dev/null @@ -1,233 +0,0 @@ -Feature: Manage WordPress posts - - Background: - Given a WP install - - Scenario: Creating/updating/deleting posts - When I run `wp post create --post_title='Test post' --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp post update {POST_ID} --post_title='Updated post'` - Then STDOUT should be: - """ - Success: Updated post {POST_ID}. - """ - - When I run `wp post delete {POST_ID}` - Then STDOUT should be: - """ - Success: Trashed post {POST_ID}. - """ - - When I run the previous command again - Then STDOUT should be: - """ - Success: Deleted post {POST_ID}. - """ - - When I try the previous command again - Then the return code should be 1 - - Scenario: Creating/getting/editing posts - Given a content.html file: - """ - This is some content. - - <script> - alert('This should not be stripped.'); - </script> - """ - And a create-post.sh file: - """ - cat content.html | wp post create --post_title='Test post' --post_excerpt="A multiline - excerpt" --porcelain - - """ - - When I run `bash create-post.sh` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp post get --field=excerpt {POST_ID}` - Then STDOUT should be: - """ - A multiline - excerpt - """ - - When I run `wp post get --field=content {POST_ID} | diff -Bu content.html -` - Then STDOUT should be empty - - When I run `wp post get --format=table {POST_ID}` - Then STDOUT should be a table containing rows: - | Field | Value | - | ID | {POST_ID} | - | post_title | Test post | - | post_name | | - | post_type | post | - - When I run `wp post get {POST_ID} --format=csv --fields=post_title,type | wc -l` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp post get --format=json {POST_ID}` - Then STDOUT should be JSON containing: - """ - { - "ID": {POST_ID}, - "post_title": "Test post" - } - """ - - When I try `EDITOR='ex -i NONE -c q!' wp post edit {POST_ID}` - Then STDERR should contain: - """ - No change made to post content. - """ - And the return code should be 0 - - When I try `EDITOR='ex -i NONE -c %s/content/bunkum -c wq' wp post edit {POST_ID}` - Then STDERR should be empty - Then STDOUT should contain: - """ - Updated post {POST_ID}. - """ - - When I run `wp post get --field=content {POST_ID}` - Then STDOUT should contain: - """ - This is some bunkum. - """ - - When I run `wp post url 1 {POST_ID}` - Then STDOUT should be: - """ - http://example.com/?p=1 - http://example.com/?p=3 - """ - - Scenario: Update a post from file or STDIN - Given a content.html file: - """ - Oh glorious CLI - """ - And a content-2.html file: - """ - Let it be the weekend - """ - - When I run `wp post create --post_title="Testing update via STDIN" --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `cat content.html | wp post update {POST_ID} -` - Then STDOUT should contain: - """ - Success: Updated post {POST_ID} - """ - - When I run `wp post get --field=post_content {POST_ID}` - Then STDOUT should be: - """ - Oh glorious CLI - """ - - When I run `wp post create --post_title="Testing update via STDIN. Again!" --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID_TWO} - - When I run `wp post update {POST_ID} {POST_ID_TWO} content-2.html` - Then STDOUT should contain: - """ - Success: Updated post {POST_ID_TWO} - """ - - When I run `wp post get --field=post_content {POST_ID_TWO}` - Then STDOUT should be: - """ - Let it be the weekend - """ - - When I try `wp post update {POST_ID} invalid-file.html` - Then STDERR should be: - """ - Error: Unable to read content from 'invalid-file.html'. - """ - - Scenario: Creating/listing posts - When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp post create --post_title='Draft post' --post_content='Draft post content' --post_status='draft' --porcelain` - Then STDOUT should be a number - - When I run `wp post list --post_type='post' --fields=post_title,post_name,post_status --format=csv` - Then STDOUT should be CSV containing: - | post_title | post_name | post_status | - | Publish post | publish-post | publish | - | Draft post | | draft | - - When I run `wp post list --post_type='post' --fields=title,name,status --format=csv` - Then STDOUT should be CSV containing: - | post_title | post_name | post_status | - | Publish post | publish-post | publish | - | Draft post | | draft | - - When I run `wp post list --post_type='post' --fields="title, name, status" --format=csv` - Then STDOUT should be CSV containing: - | post_title | post_name | post_status | - | Publish post | publish-post | publish | - | Draft post | | draft | - - When I run `wp post list --post__in={POST_ID} --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp post list --post_type='page' --field=title` - Then STDOUT should be: - """ - Sample Page - """ - - When I run `wp post list --post_type=any --fields=post_title,post_name,post_status --format=csv --orderby=post_title --order=ASC` - Then STDOUT should be CSV containing: - | post_title | post_name | post_status | - | Draft post | | draft | - | Hello world! | hello-world | publish | - | Publish post | publish-post | publish | - | Sample Page | sample-page | publish | - - Scenario: Update categories on a post - When I run `wp term create category "Test Category" --porcelain` - Then save STDOUT as {TERM_ID} - - When I run `wp post update 1 --post_category={TERM_ID}` - And I run `wp post term list 1 category --format=json --fields=name` - Then STDOUT should be: - """ - [{"name":"Test Category"}] - """ - - Scenario: Make sure WordPress receives the slashed data it expects - When I run `wp post create --post_title='My\Post' --porcelain` - Then save STDOUT as {POST_ID} - - When I run `wp post get {POST_ID} --field=title` - Then STDOUT should be: - """ - My\Post - """ - - When I run `wp post update {POST_ID} --post_content='var isEmailValid = /^\S+@\S+.\S+$/.test(email);'` - Then STDOUT should not be empty - - When I run `wp post get {POST_ID} --field=content` - Then STDOUT should be: - """ - var isEmailValid = /^\S+@\S+.\S+$/.test(email); - """ diff --git a/features/rewrite.feature b/features/rewrite.feature deleted file mode 100644 index 6d7fdccee..000000000 --- a/features/rewrite.feature +++ /dev/null @@ -1,103 +0,0 @@ -Feature: Manage WordPress rewrites - - Scenario: Change site permastructs - Given a WP install - - When I run `wp rewrite structure /blog/%year%/%monthnum%/%day%/%postname%/ --category-base=section --tag-base=topic` - And I run `wp option get permalink_structure` - Then STDOUT should contain: - """ - /blog/%year%/%monthnum%/%day%/%postname%/ - """ - - When I run `wp option get category_base` - Then STDOUT should contain: - """ - section - """ - - When I run `wp option get tag_base` - Then STDOUT should contain: - """ - topic - """ - - When I run `wp rewrite list --format=csv` - Then STDOUT should be CSV containing: - | match | query | source | - | blog/[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}/[^/]+/attachment/([^/]+)/trackback/?$ | index.php?attachment=$matches[1]&tb=1 | post | - | topic/([^/]+)/?$ | index.php?tag=$matches[1] | post_tag | - | section/(.+?)/?$ | index.php?category_name=$matches[1] | category | - - When I run `wp rewrite list --match=/topic/apple/ --format=csv --fields=match,query` - Then STDOUT should be CSV containing: - | match | query | - | topic/([^/]+)/?$ | index.php?tag=$matches[1] | - And STDOUT should not contain: - """ - source - """ - - Scenario: Missing permalink_structure - Given a WP install - - When I run `wp option delete permalink_structure` - And I try `wp option get permalink_structure` - Then STDOUT should be empty - - When I try `wp rewrite flush` - Then STDERR should contain: - """ - Warning: Rewrite rules are empty, possibly because of a missing permalink_structure option. - """ - And STDOUT should be empty - - When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/` - Then I run `wp rewrite flush` - Then STDOUT should be: - """ - Success: Rewrite rules flushed. - """ - - Scenario: Generate .htaccess on hard flush with a project config - Given a WP install - And a wp-cli.yml file: - """ - apache_modules: [mod_rewrite] - """ - - When I run `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` - Then the .htaccess file should exist - And the return code should be 0 - - Scenario: Generate .htaccess on hard flush with a global config - Given a WP install - And a config.yml file: - """ - apache_modules: [mod_rewrite] - """ - - When I run `WP_CLI_CONFIG_PATH=config.yml wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` - Then the .htaccess file should exist - And the return code should be 0 - - Scenario: Error when trying to generate .htaccess on a multisite install - Given a WP multisite install - And a wp-cli.yml file: - """ - apache_modules: [mod_rewrite] - """ - - When I try `wp rewrite flush --hard` - Then STDERR should be: - """ - Warning: WordPress can't generate .htaccess file for a multisite install. - """ - And the return code should be 0 - - When I try `wp rewrite structure /%year%/%monthnum%/%day%/%postname%/ --hard` - Then STDERR should contain: - """ - Warning: WordPress can't generate .htaccess file for a multisite install. - """ - And the return code should be 0 diff --git a/features/roles.feature b/features/roles.feature deleted file mode 100644 index c288631ff..000000000 --- a/features/roles.feature +++ /dev/null @@ -1,140 +0,0 @@ -Feature: Manage WordPress roles - - Background: - Given a WP install - - Scenario: Role CRUD operations - When I run `wp role list` - Then STDOUT should be a table containing rows: - | name | role | - | Subscriber | subscriber | - | Editor | editor | - - When I run `wp role create reporter Reporter` - Then STDOUT should be: - """ - Success: Role with key 'reporter' created. - """ - - Scenario: Resetting a role - When I run `wp role reset author` - Then STDOUT should be: - """ - No changes necessary for 'author' role. - Success: Role didn't need resetting. - """ - - When I run `wp cap remove author read` - And I run `wp role reset author` - Then STDOUT should be: - """ - Restored 1 capability to and removed 0 capabilities from 'author' role. - Success: Role reset. - """ - - When I run `wp role reset author editor` - Then STDOUT should be: - """ - No changes necessary for 'author' role. - No changes necessary for 'editor' role. - Success: No roles needed resetting. - """ - - When I run `wp cap remove author read` - And I run `wp role reset author editor` - Then STDOUT should be: - """ - Restored 1 capability to and removed 0 capabilities from 'author' role. - No changes necessary for 'editor' role. - Success: 1 of 2 roles reset. - """ - - When I run `wp role reset --all` - Then STDOUT should be: - """ - No changes necessary for 'administrator' role. - No changes necessary for 'editor' role. - No changes necessary for 'author' role. - No changes necessary for 'contributor' role. - No changes necessary for 'subscriber' role. - Success: No roles needed resetting. - """ - - When I run `wp role create custom-role "Custom role" --clone=author` - And I run `wp role reset --all` - Then STDOUT should be: - """ - Custom role 'custom-role' not affected. - No changes necessary for 'administrator' role. - No changes necessary for 'editor' role. - No changes necessary for 'author' role. - No changes necessary for 'contributor' role. - No changes necessary for 'subscriber' role. - Success: No roles needed resetting. - """ - - When I try `wp role reset custom-role` - Then STDERR should contain: - """ - Error: Must specify a default role to reset. - """ - And STDOUT should contain: - """ - Custom role 'custom-role' not affected. - """ - - When I run `wp role reset custom-role author` - Then STDOUT should be: - """ - Custom role 'custom-role' not affected. - No changes necessary for 'author' role. - Success: Role didn't need resetting. - """ - - When I run `wp cap remove author read` - And I run `wp role reset custom-role author` - Then STDOUT should be: - """ - Custom role 'custom-role' not affected. - Restored 1 capability to and removed 0 capabilities from 'author' role. - Success: Role reset. - """ - - Scenario: Cloning a role - When I try `wp role create reporter Reporter --clone=no-role` - Then STDERR should be: - """ - Error: 'no-role' role not found. - """ - - When I run `wp role create reporter Reporter --clone=author` - Then STDOUT should be: - """ - Success: Role with key 'reporter' created. Cloned capabilities from 'author'. - """ - - When I run `wp role list` - Then STDOUT should be a table containing rows: - | name | role | - | Reporter | reporter | - - When I run `wp cap list reporter` - Then STDOUT should be: - """ - upload_files - edit_posts - edit_published_posts - publish_posts - read - level_2 - level_1 - level_0 - delete_posts - delete_published_posts - """ - - When I run `wp cap list reporter --format=count` - Then STDOUT should be: - """ - 10 - """ diff --git a/features/runcommand.feature b/features/runcommand.feature deleted file mode 100644 index 9ca6402d7..000000000 --- a/features/runcommand.feature +++ /dev/null @@ -1,255 +0,0 @@ -@require-php-5.4 -Feature: Run a WP-CLI command - - Background: - Given an empty directory - And a command.php file: - """ - <?php - /** - * Run a WP-CLI command with WP_CLI::runcommand(); - * - * ## OPTIONS - * - * <command> - * : Command to run, quoted. - * - * [--launch] - * : Launch a new process for the command. - * - * [--exit_error] - * : Exit on error. - * - * [--return[=<return>]] - * : Capture and return output. - * - * [--parse=<format>] - * : Parse returned output as a particular format. - */ - WP_CLI::add_command( 'run', function( $args, $assoc_args ){ - $ret = WP_CLI::runcommand( $args[0], $assoc_args ); - $ret = is_object( $ret ) ? (array) $ret : $ret; - WP_CLI::log( 'returned: ' . var_export( $ret, true ) ); - }); - """ - And a wp-cli.yml file: - """ - user: admin - require: - - command.php - """ - And a config.yml file: - """ - user get: - 0: admin - field: user_email - """ - - Scenario Outline: Run a WP-CLI command and render output - Given a WP install - - When I run `wp <flag> run 'option get home'` - Then STDOUT should be: - """ - http://example.com - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` - Then STDOUT should be: - """ - admin - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - When I run `WP_CLI_CONFIG_PATH=config.yml wp <flag> run 'user get'` - Then STDOUT should be: - """ - admin@example.com - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Run a WP-CLI command and capture output - Given a WP install - - When I run `wp run <flag> --return 'option get home'` - Then STDOUT should be: - """ - returned: 'http://example.com' - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> --return run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` - Then STDOUT should be: - """ - returned: 'admin' - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> --return=stderr run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` - Then STDOUT should be: - """ - returned: '' - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> --return=return_code run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` - Then STDOUT should be: - """ - returned: 0 - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> --return=all run 'eval "echo wp_get_current_user()->user_login . PHP_EOL;"'` - Then STDOUT should be: - """ - returned: array ( - 'stdout' => 'admin', - 'stderr' => '', - 'return_code' => 0, - ) - """ - And STDERR should be empty - And the return code should be 0 - - When I run `WP_CLI_CONFIG_PATH=config.yml wp --return <flag> run 'user get'` - Then STDOUT should be: - """ - returned: 'admin@example.com' - """ - And STDERR should be empty - And the return code should be 0 - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Use 'parse=json' to parse JSON output - Given a WP install - - When I run `wp run --return --parse=json <flag> 'user get admin --fields=user_login,user_email --format=json'` - Then STDOUT should be: - """ - returned: array ( - 'user_login' => 'admin', - 'user_email' => 'admin@example.com', - ) - """ - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Exit on error by default - Given a WP install - - When I try `wp run <flag> 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` - Then STDOUT should be empty - And STDERR should be: - """ - Error: 1 - """ - And the return code should be 1 - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Override erroring on exit - Given a WP install - - When I try `wp run <flag> --no-exit_error --return=all 'eval "WP_CLI::error( var_export( get_current_user_id(), true ) );"'` - Then STDOUT should be: - """ - returned: array ( - 'stdout' => '', - 'stderr' => 'Error: 1', - 'return_code' => 1, - ) - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp <flag> --no-exit_error run 'option get foo$bar'` - Then STDOUT should be: - """ - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Installed packages work as expected - Given a WP install - - When I run `wp package install wp-cli/scaffold-package-command` - Then STDERR should be empty - - When I run `wp <flag> run 'help scaffold package'` - Then STDOUT should contain: - """ - wp scaffold package <name> - """ - And STDERR should be empty - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Persists global parameters when supplied interactively - Given a WP install in 'subdir' - - When I run `wp <flag> --path=subdir run 'rewrite structure "archives/%post_id%/" --path=subdir'` - Then STDOUT should be: - """ - Success: Rewrite rules flushed. - Success: Rewrite structure set. - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - Examples: - | flag | - | --no-launch | - | --launch | - - Scenario Outline: Apply backwards compat conversions - Given a WP install - - When I run `wp <flag> run 'term url category 1'` - Then STDOUT should be: - """ - http://example.com/?cat=1 - returned: NULL - """ - And STDERR should be empty - And the return code should be 0 - - Examples: - | flag | - | --no-launch | - | --launch | diff --git a/features/scaffold-plugin-tests.feature b/features/scaffold-plugin-tests.feature deleted file mode 100644 index 723358393..000000000 --- a/features/scaffold-plugin-tests.feature +++ /dev/null @@ -1,110 +0,0 @@ -Feature: Scaffold plugin unit tests - - Scenario: Scaffold plugin tests - Given a WP install - When I run `wp plugin path` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin hello-world --skip-tests` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist - And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist - And the {PLUGIN_DIR}/hello-world/readme.txt file should exist - And the {PLUGIN_DIR}/hello-world/tests directory should not exist - - When I run `wp scaffold plugin-tests hello-world` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/tests directory should contain: - """ - bootstrap.php - test-sample.php - """ - And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: - """ - require dirname( dirname( __FILE__ ) ) . '/hello-world.php'; - """ - And the {PLUGIN_DIR}/hello-world/tests/bootstrap.php file should contain: - """ - * @package Hello_World - """ - And the {PLUGIN_DIR}/hello-world/tests/test-sample.php file should contain: - """ - * @package Hello_World - """ - And the {PLUGIN_DIR}/hello-world/bin directory should contain: - """ - install-wp-tests.sh - """ - And the {PLUGIN_DIR}/hello-world/phpunit.xml.dist file should exist - And the {PLUGIN_DIR}/hello-world/phpcs.ruleset.xml file should exist - And the {PLUGIN_DIR}/hello-world/circle.yml file should not exist - And the {PLUGIN_DIR}/hello-world/.gitlab-ci.yml file should not exist - And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: - """ - script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit - """ - - When I run `wp eval "if ( is_executable( '{PLUGIN_DIR}/hello-world/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` - Then STDOUT should be: - """ - executable - """ - - Scenario: Scaffold plugin tests with Circle as the provider, part one - Given a WP install - And I run `wp scaffold plugin hello-world --ci=circle` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/circle.yml file should contain: - """ - version: 5.6.22 - """ - - Scenario: Scaffold plugin tests with Circle as the provider, part two - Given a WP install - And I run `wp scaffold plugin hello-world --skip-tests` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin-tests hello-world --ci=circle` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/circle.yml file should contain: - """ - version: 5.6.22 - """ - - Scenario: Scaffold plugin tests with Gitlab as the provider - Given a WP install - And I run `wp scaffold plugin hello-world --skip-tests` - - When I run `wp plugin path hello-world --dir` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin-tests hello-world --ci=gitlab` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/.travis.yml file should not exist - And the {PLUGIN_DIR}/.gitlab-ci.yml file should contain: - """ - MYSQL_DATABASE - """ - - Scenario: Scaffold plugin tests with invalid slug - Given a WP install - - When I try `wp scaffold plugin-tests .` - Then STDERR should contain: - """ - Error: Invalid plugin slug specified. - """ - - When I try `wp scaffold plugin-tests ../` - Then STDERR should contain: - """ - Error: Invalid plugin slug specified. - """ diff --git a/features/scaffold-theme-tests.feature b/features/scaffold-theme-tests.feature deleted file mode 100644 index c4919e860..000000000 --- a/features/scaffold-theme-tests.feature +++ /dev/null @@ -1,90 +0,0 @@ -Feature: Scaffold theme unit tests - - Background: - Given a WP install - And I run `wp theme install p2` - And I run `wp scaffold child-theme p2child --parent_theme=p2` - - When I run `wp theme path` - Then save STDOUT as {THEME_DIR} - - Scenario: Scaffold theme tests - When I run `wp scaffold theme-tests p2child` - Then STDOUT should not be empty - And the {THEME_DIR}/p2child/tests directory should contain: - """ - bootstrap.php - test-sample.php - """ - And the {THEME_DIR}/p2child/tests/bootstrap.php file should contain: - """ - register_theme_directory( dirname( $theme_dir ) ); - """ - And the {THEME_DIR}/p2child/tests/bootstrap.php file should contain: - """ - * @package P2child - """ - And the {THEME_DIR}/p2child/tests/test-sample.php file should contain: - """ - * @package P2child - """ - And the {THEME_DIR}/p2child/bin directory should contain: - """ - install-wp-tests.sh - """ - And the {THEME_DIR}/p2child/phpunit.xml.dist file should exist - And the {THEME_DIR}/p2child/phpcs.ruleset.xml file should exist - And the {THEME_DIR}/p2child/circle.yml file should not exist - And the {THEME_DIR}/p2child/.gitlab-ci.yml file should not exist - And the {THEME_DIR}/p2child/.travis.yml file should contain: - """ - script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit - """ - - When I run `wp eval "if ( is_executable( '{THEME_DIR}/p2child/bin/install-wp-tests.sh' ) ) { echo 'executable'; } else { exit( 1 ); }"` - Then STDOUT should be: - """ - executable - """ - - Scenario: Scaffold theme tests invalid theme - When I try `wp scaffold theme-tests p3child` - Then STDERR should be: - """ - Error: Invalid theme slug specified. - """ - - Scenario: Scaffold theme tests with Circle as the provider - When I run `wp scaffold theme-tests p2child --ci=circle` - Then STDOUT should not be empty - And the {THEME_DIR}/p2child/.travis.yml file should not exist - And the {THEME_DIR}/p2child/circle.yml file should contain: - """ - version: 5.6.22 - """ - - Scenario: Scaffold theme tests with Gitlab as the provider - When I run `wp scaffold theme-tests p2child --ci=gitlab` - Then STDOUT should not be empty - And the {THEME_DIR}/p2child/.travis.yml file should not exist - And the {THEME_DIR}/p2child/.gitlab-ci.yml file should contain: - """ - MYSQL_DATABASE - """ - - Scenario: Scaffold theme tests with invalid slug - - When I try `wp scaffold theme-tests .` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - - When I try `wp scaffold theme-tests ../` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - diff --git a/features/scaffold.feature b/features/scaffold.feature deleted file mode 100644 index 4e09bb223..000000000 --- a/features/scaffold.feature +++ /dev/null @@ -1,455 +0,0 @@ -Feature: WordPress code scaffolding - - @theme - Scenario: Scaffold a child theme - Given a WP install - Given I run `wp theme path` - And save STDOUT as {THEME_DIR} - - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com` - Then the {THEME_DIR}/zombieland/style.css file should exist - And the {THEME_DIR}/zombieland/functions.php file should exist - And STDOUT should be: - """ - Success: Created '{THEME_DIR}/zombieland'. - """ - - Scenario: Scaffold a child theme with only --parent_theme parameter - Given a WP install - Given I run `wp theme path` - And save STDOUT as {THEME_DIR} - - When I run `wp scaffold child-theme hello-world --parent_theme=simple-life` - Then STDOUT should not be empty - And the {THEME_DIR}/hello-world/style.css file should exist - And the {THEME_DIR}/hello-world/style.css file should contain: - """ - Theme Name: Hello-world - """ - - Scenario: Scaffold a child theme with non existing parent theme and also activate parameter - Given a WP install - - When I try `wp scaffold child-theme hello-world --parent_theme=just-test --activate --quiet` - Then STDERR should contain: - """ - Error: The parent theme is missing. Please install the "just-test" parent theme. - """ - - Scenario: Scaffold a child theme with non existing parent theme and also network activate parameter - Given a WP install - - When I try `wp scaffold child-theme hello-world --parent_theme=just-test --enable-network --quiet` - Then STDERR should contain: - """ - Error: This is not a multisite install. - """ - - Scenario: Scaffold a child theme and network enable it - Given a WP multisite install - - When I run `wp scaffold child-theme zombieland --parent_theme=umbrella --theme_name=Zombieland --author=Tallahassee --author_uri=http://www.wp-cli.org --theme_uri=http://www.zombieland.com --enable-network` - Then STDOUT should contain: - """ - Success: Network enabled the 'Zombieland' theme. - """ - - Scenario: Scaffold a child theme with invalid slug - Given a WP install - When I try `wp scaffold child-theme . --parent_theme=simple-life` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - When I try `wp scaffold child-theme ../ --parent_theme=simple-life` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - - @tax @cpt - Scenario: Scaffold a Custom Taxonomy and Custom Post Type and write it to active theme - Given a WP install - Given I run `wp eval 'echo STYLESHEETPATH;'` - And save STDOUT as {STYLESHEETPATH} - - When I run `wp scaffold taxonomy zombie-speed --theme` - Then the {STYLESHEETPATH}/taxonomies/zombie-speed.php file should exist - - When I run `wp scaffold post-type zombie --theme` - Then the {STYLESHEETPATH}/post-types/zombie.php file should exist - And STDOUT should be: - """ - Success: Created '{STYLESHEETPATH}/post-types/zombie.php'. - """ - - When I run `wp scaffold post-type zombie` - Then STDOUT should contain: - """ - register_post_type( 'zombie' - """ - And STDOUT should contain: - """ - add_filter( 'post_updated_messages' - """ - When I run `wp scaffold post-type zombie --raw` - Then STDOUT should not contain: - """ - add_filter( 'post_updated_messages' - """ - - # Test for all flags but --label, --theme, --plugin and --raw - @tax - Scenario: Scaffold a Custom Taxonomy and attach it to CPTs including one that is prefixed and has a text domain - Given a WP install - When I run `wp scaffold taxonomy zombie-speed --post_types="prefix-zombie,wraith" --textdomain=zombieland` - Then STDOUT should contain: - """ - __( 'Zombie speeds' - """ - And STDOUT should contain: - """ - array( 'prefix-zombie', 'wraith' ) - """ - And STDOUT should contain: - """ - __( 'Zombie speeds', 'zombieland' - """ - - @tax - Scenario: Scaffold a Custom Taxonomy with label "Speed" - Given a WP install - When I run `wp scaffold taxonomy zombie-speed --label="Speed"` - Then STDOUT should contain: - """ - __( 'Speeds' - """ - And STDOUT should contain: - """ - _x( 'Speed', 'taxonomy general name', - """ - - # Test for all flags but --label, --theme, --plugin and --raw - @cpt - Scenario: Scaffold a Custom Post Type - Given a WP install - When I run `wp scaffold post-type zombie --textdomain=zombieland` - Then STDOUT should contain: - """ - __( 'Zombies' - """ - And STDOUT should contain: - """ - __( 'Zombies', 'zombieland' - """ - And STDOUT should contain: - """ - 'menu_icon' => 'dashicons-admin-post', - """ - - Scenario: CPT slug is too long - Given a WP install - When I try `wp scaffold post-type slugiswaytoolonginfact` - Then STDERR should be: - """ - Error: Post type slugs cannot exceed 20 characters in length. - """ - - @cpt - Scenario: Scaffold a Custom Post Type with label - Given a WP install - When I run `wp scaffold post-type zombie --label="Brain eater"` - Then STDOUT should contain: - """ - __( 'Brain eaters' - """ - - Scenario: Scaffold a Custom Post Type with dashicon - Given a WP install - When I run `wp scaffold post-type zombie --dashicon="art"` - Then STDOUT should contain: - """ - 'menu_icon' => 'dashicons-art', - """ - - Scenario: Scaffold a plugin - Given a WP install - Given I run `wp plugin path` - And save STDOUT as {PLUGIN_DIR} - Given I run `wp core version` - And save STDOUT as {WP_VERSION} - - When I run `wp scaffold plugin hello-world --plugin_author="Hello World Author"` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/.gitignore file should exist - And the {PLUGIN_DIR}/hello-world/.editorconfig file should exist - And the {PLUGIN_DIR}/hello-world/hello-world.php file should exist - And the {PLUGIN_DIR}/hello-world/readme.txt file should exist - And the {PLUGIN_DIR}/hello-world/package.json file should exist - And the {PLUGIN_DIR}/hello-world/Gruntfile.js file should exist - And the {PLUGIN_DIR}/hello-world/.gitignore file should contain: - """ - .DS_Store - Thumbs.db - wp-cli.local.yml - node_modules/ - """ - And the {PLUGIN_DIR}/hello-world/.distignore file should contain: - """ - .git - .gitignore - """ - And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: - """ - * Plugin Name: Hello World - """ - And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: - """ - * Version: 0.1.0 - """ - And the {PLUGIN_DIR}/hello-world/hello-world.php file should contain: - """ - * @package Hello_World - """ - And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: - """ - Stable tag: 0.1.0 - """ - And the {PLUGIN_DIR}/hello-world/readme.txt file should contain: - """ - Tested up to: {WP_VERSION} - """ - - When I run `cat {PLUGIN_DIR}/hello-world/package.json` - Then STDOUT should be JSON containing: - """ - {"author":"Hello World Author"} - """ - And STDOUT should be JSON containing: - """ - {"version":"0.1.0"} - """ - - Scenario: Scaffold a plugin by prompting - Given a WP install - And a session file: - """ - hello-world - - Hello World - An awesome introductory plugin for WordPress - WP-CLI - http://wp-cli.org - http://wp-cli.org - n - travis - Y - n - n - """ - - When I run `wp scaffold plugin --prompt < session` - Then STDOUT should not be empty - And the wp-content/plugins/hello-world/hello-world.php file should exist - And the wp-content/plugins/hello-world/readme.txt file should exist - And the wp-content/plugins/hello-world/tests directory should exist - - When I run `wp plugin status hello-world` - Then STDOUT should contain: - """ - Status: Active - """ - And STDOUT should contain: - """ - Name: Hello World - """ - And STDOUT should contain: - """ - Description: An awesome introductory plugin for WordPress - """ - - Scenario: Scaffold a plugin and activate it - Given a WP install - When I run `wp scaffold plugin hello-world --activate` - Then STDOUT should contain: - """ - Plugin 'hello-world' activated. - """ - - Scenario: Scaffold a plugin and network activate it - Given a WP multisite install - When I run `wp scaffold plugin hello-world --activate-network` - Then STDOUT should contain: - """ - Plugin 'hello-world' network activated. - """ - - Scenario: Scaffold a plugin with invalid slug - Given a WP install - When I try `wp scaffold plugin .` - Then STDERR should contain: - """ - Error: Invalid plugin slug specified. - """ - When I try `wp scaffold plugin ../` - Then STDERR should contain: - """ - Error: Invalid plugin slug specified. - """ - - Scenario: Scaffold starter code for a theme - Given a WP install - Given I run `wp theme path` - And save STDOUT as {THEME_DIR} - - When I run `wp scaffold _s starter-theme` - Then STDOUT should contain: - """ - Success: Created theme 'Starter-theme'. - """ - And the {THEME_DIR}/starter-theme/style.css file should exist - - Scenario: Scaffold starter code for a theme with sass - Given a WP install - Given I run `wp theme path` - And save STDOUT as {THEME_DIR} - - When I run `wp scaffold _s starter-theme --sassify` - Then STDOUT should contain: - """ - Success: Created theme 'Starter-theme'. - """ - And the {THEME_DIR}/starter-theme/sass directory should exist - - Scenario: Scaffold starter code for a theme and activate it - Given a WP install - When I run `wp scaffold _s starter-theme --activate` - Then STDOUT should contain: - """ - Success: Switched to 'Starter-theme' theme. - """ - - Scenario: Scaffold starter code for a theme with invalid slug - Given a WP install - When I try `wp scaffold _s .` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - When I try `wp scaffold _s ../` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. - """ - When I try `wp scaffold _s 1themestartingwithnumber` - Then STDERR should contain: - """ - Error: Invalid theme slug specified. Theme slugs can only contain letters, numbers, underscores and hyphens, and can only start with a letter or underscore. - """ - - Scenario: Scaffold plugin and tests for non-standard plugin directory - Given a WP install - - When I run `wp scaffold plugin custom-plugin --dir=wp-content/mu-plugins --skip-tests` - Then STDOUT should not be empty - And the wp-content/mu-plugins/custom-plugin/custom-plugin.php file should exist - And the wp-content/mu-plugins/custom-plugin/tests directory should not exist - - When I try `wp scaffold plugin-tests --dir=wp-content/mu-plugins/incorrect-custom-plugin` - Then STDERR should contain: - """ - Error: Invalid plugin directory specified. - """ - - When I run `wp scaffold plugin-tests --dir=wp-content/mu-plugins/custom-plugin` - Then STDOUT should contain: - """ - Success: Created test files. - """ - And the wp-content/mu-plugins/custom-plugin/tests directory should exist - And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should exist - And the wp-content/mu-plugins/custom-plugin/tests/bootstrap.php file should contain: - """ - require dirname( dirname( __FILE__ ) ) . '/custom-plugin.php'; - """ - - Scenario: Scaffold tests for a plugin with a different slug than plugin directory - Given a WP install - And a wp-content/mu-plugins/custom-plugin2/custom-plugin-slug.php file: - """ - <?php - /** - * Plugin Name: Handbook - * Description: Features for a handbook, complete with glossary and table of contents - * Author: Nacin - */ - """ - - When I run `wp scaffold plugin-tests custom-plugin-slug --dir=wp-content/mu-plugins/custom-plugin2` - Then STDOUT should contain: - """ - Success: Created test files. - """ - And the wp-content/mu-plugins/custom-plugin2/tests directory should exist - And the wp-content/mu-plugins/custom-plugin2/tests/bootstrap.php file should exist - And the wp-content/mu-plugins/custom-plugin2/tests/bootstrap.php file should contain: - """ - require dirname( dirname( __FILE__ ) ) . '/custom-plugin-slug.php'; - """ - - Scenario: Scaffold tests parses plugin readme.txt - Given a WP install - When I run `wp core version` - Then save STDOUT as {WP_VERSION} - When I run `wp plugin path` - Then save STDOUT as {PLUGIN_DIR} - - When I run `wp scaffold plugin hello-world` - Then STDOUT should not be empty - And the {PLUGIN_DIR}/hello-world/readme.txt file should exist - And the {PLUGIN_DIR}/hello-world/.travis.yml file should exist - And the {PLUGIN_DIR}/hello-world/.travis.yml file should contain: - """ - env: - - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=3.7 WP_MULTISITE=0 - - WP_VERSION={WP_VERSION} WP_MULTISITE=0 - """ - - Scenario: Scaffold starter code for a theme and network enable it - Given a WP multisite install - When I run `wp scaffold _s starter-theme --enable-network` - Then STDOUT should contain: - """ - Success: Network enabled the 'Starter-theme' theme. - """ - - Scenario: Scaffold starter code for a theme, but can't unzip theme files - Given a WP install - And a misconfigured WP_CONTENT_DIR constant directory - When I try `wp scaffold _s starter-theme` - Then STDERR should contain: - """ - Error: Could not decompress your theme files - """ - - Scenario: Overwrite existing files - Given a WP install - When I run `wp scaffold plugin test` - And I run `wp scaffold plugin test --force` - Then STDERR should contain: - """ - already exists - """ - And STDOUT should contain: - """ - Replacing - """ - Scenario: Scaffold tests for invalid plugin directory - Given a WP install - - When I try `wp scaffold plugin-tests incorrect-custom-plugin` - Then STDERR should contain: - """ - Error: Invalid plugin slug specified. - """ diff --git a/features/search-replace-export.feature b/features/search-replace-export.feature deleted file mode 100644 index 3730a98b1..000000000 --- a/features/search-replace-export.feature +++ /dev/null @@ -1,195 +0,0 @@ -Feature: Search / replace with file export - - Scenario: Search / replace export to STDOUT - Given a WP install - - When I run `wp search-replace example.com example.net --export` - Then STDOUT should contain: - """ - DROP TABLE IF EXISTS `wp_commentmeta`; - CREATE TABLE `wp_commentmeta` - """ - And STDOUT should contain: - """ - ('1', 'siteurl', 'http://example.net', 'yes'), - """ - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.com - """ - - When I run `wp search-replace example.com example.net --skip-columns=option_value --export` - Then STDOUT should contain: - """ - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - ('1', 'siteurl', 'http://example.com', 'yes'), - """ - - When I run `wp search-replace example.com example.net --skip-columns=option_value --export --export_insert_size=1` - Then STDOUT should contain: - """ - ('1', 'siteurl', 'http://example.com', 'yes'); - INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`) VALUES - """ - - When I run `wp search-replace foo bar --export | tail -n 1` - Then STDOUT should not contain: - """ - Success: Made - """ - - When I run `wp search-replace example.com example.net --export > wordpress.sql` - And I run `wp db import wordpress.sql` - Then STDOUT should not be empty - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.net - """ - - Scenario: Search / replace export to file - Given a WP install - And I run `wp post generate --count=100` - And I run `wp option add example_url http://example.com` - - When I run `wp search-replace example.com example.net --export=wordpress.sql` - Then STDOUT should contain: - """ - Success: Made 110 replacements and exported to wordpress.sql - """ - And STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 6 | PHP | - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.com - """ - - When I run `wp site empty --yes` - And I run `wp post list --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp db import wordpress.sql` - Then STDOUT should not be empty - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.net - """ - - When I run `wp option get example_url` - Then STDOUT should be: - """ - http://example.net - """ - - When I run `wp post list --format=count` - Then STDOUT should be: - """ - 101 - """ - - Scenario: Search / replace export to file with verbosity - Given a WP install - - When I run `wp search-replace example.com example.net --export=wordpress.sql --verbose` - Then STDOUT should contain: - """ - Checking: wp_posts - """ - And STDOUT should contain: - """ - Checking: wp_options - """ - - Scenario: Search / replace export with dry-run - Given a WP install - - When I try `wp search-replace example.com example.net --export --dry-run` - Then STDERR should be: - """ - Error: You cannot supply --dry-run and --export at the same time. - """ - - Scenario: Search / replace shouldn't affect primary key - Given a WP install - And I run `wp post create --post_title=foo --porcelain` - Then save STDOUT as {POST_ID} - - When I run `wp option update {POST_ID} foo` - And I run `wp option get {POST_ID}` - Then STDOUT should be: - """ - foo - """ - - When I run `wp search-replace {POST_ID} 99999999 --export=wordpress.sql` - And I run `wp db import wordpress.sql` - Then STDOUT should not be empty - - When I run `wp post get {POST_ID} --field=title` - Then STDOUT should be: - """ - foo - """ - - When I try `wp option get {POST_ID}` - Then STDOUT should be empty - - When I run `wp option get 99999999` - Then STDOUT should be: - """ - foo - """ - - Scenario: Search / replace export invalid file - Given a WP install - - When I try `wp search-replace example.com example.net --export=foo/bar.sql` - Then STDERR should contain: - """ - Error: Unable to open "foo/bar.sql" for writing. - """ - - Scenario: Search / replace specific table - Given a WP install - - When I run `wp post create --post_title=foo --porcelain` - Then save STDOUT as {POST_ID} - - When I run `wp option update bar foo` - Then STDOUT should not be empty - - When I run `wp search-replace foo burrito wp_posts --export=wordpress.sql --verbose` - Then STDOUT should contain: - """ - Checking: wp_posts - """ - And STDOUT should contain: - """ - Success: Made 1 replacements and exported to wordpress.sql. - """ - - When I run `wp db import wordpress.sql` - Then STDOUT should not be empty - - When I run `wp post get {POST_ID} --field=title` - Then STDOUT should be: - """ - burrito - """ - - When I run `wp option get bar` - Then STDOUT should be: - """ - foo - """ diff --git a/features/search-replace.feature b/features/search-replace.feature deleted file mode 100644 index e23581d38..000000000 --- a/features/search-replace.feature +++ /dev/null @@ -1,337 +0,0 @@ -Feature: Do global search/replace - - Scenario: Basic search/replace - Given a WP install - - When I run `wp search-replace foo bar` - Then STDOUT should contain: - """ - guid - """ - - When I run `wp search-replace foo bar --skip-columns=guid` - Then STDOUT should not contain: - """ - guid - """ - - When I run `wp search-replace foo bar --include-columns=post_content` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_posts | post_content | 0 | SQL | - - - Scenario: Multisite search/replace - Given a WP multisite install - And I run `wp site create --slug="foo" --title="foo" --email="foo@example.com"` - And I run `wp search-replace foo bar --network` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_2_posts | guid | 2 | SQL | - | wp_blogs | path | 1 | SQL | - - Scenario: Don't run on unregistered tables by default - Given a WP install - And I run `wp db query "CREATE TABLE wp_awesome ( id int(11) unsigned NOT NULL AUTO_INCREMENT, awesome_stuff TEXT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` - - When I run `wp search-replace foo bar` - Then STDOUT should not contain: - """ - wp_awesome - """ - - When I run `wp search-replace foo bar --all-tables-with-prefix` - Then STDOUT should contain: - """ - wp_awesome - """ - - Scenario: Run on unregistered, unprefixed tables with --all-tables flag - Given a WP install - And I run `wp db query "CREATE TABLE awesome_table ( id int(11) unsigned NOT NULL AUTO_INCREMENT, awesome_stuff TEXT, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;"` - - When I run `wp search-replace foo bar` - Then STDOUT should not contain: - """ - awesome_table - """ - - When I run `wp search-replace foo bar --all-tables` - Then STDOUT should contain: - """ - awesome_table - """ - - Scenario: Run on all tables matching string with wildcard - Given a WP install - - When I run `wp option set bar foo` - And I run `wp option get bar` - Then STDOUT should be: - """ - foo - """ - - When I run `wp post create --post_title=bar --porcelain` - Then save STDOUT as {POST_ID} - - When I run `wp post meta add {POST_ID} foo bar` - Then STDOUT should not be empty - - When I run `wp search-replace bar burrito wp_post\?` - And STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_posts | post_title | 1 | SQL | - And STDOUT should not contain: - """ - wp_options - """ - - When I run `wp post get {POST_ID} --field=title` - Then STDOUT should be: - """ - burrito - """ - - When I run `wp post meta get {POST_ID} foo` - Then STDOUT should be: - """ - bar - """ - - When I run `wp option get bar` - Then STDOUT should be: - """ - foo - """ - - When I try `wp search-replace foo burrito wp_opt\*on` - Then STDERR should be: - """ - Error: Couldn't find any tables matching: wp_opt*on - """ - - When I run `wp search-replace foo burrito wp_opt\* wp_postme\*` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 1 | PHP | - | wp_postmeta | meta_key | 1 | SQL | - And STDOUT should not contain: - """ - wp_posts - """ - - When I run `wp option get bar` - Then STDOUT should be: - """ - burrito - """ - - When I run `wp post meta get {POST_ID} burrito` - Then STDOUT should be: - """ - bar - """ - - Scenario: Quiet search/replace - Given a WP install - - When I run `wp search-replace foo bar --quiet` - Then STDOUT should be empty - - Scenario: Verbose search/replace - Given a WP install - And I run `wp post create --post_title='Replace this text' --porcelain` - And save STDOUT as {POSTID} - - When I run `wp search-replace 'Replace' 'Replaced' --verbose` - Then STDOUT should contain: - """ - Checking: wp_posts.post_title - 1 rows affected - """ - - When I run `wp search-replace 'Replace' 'Replaced' --verbose --precise` - Then STDOUT should contain: - """ - Checking: wp_posts.post_title - 1 rows affected - """ - - Scenario: Regex search/replace - Given a WP install - When I run `wp search-replace '(Hello)\s(world)' '$2, $1' --regex` - Then STDOUT should contain: - """ - wp_posts - """ - When I run `wp post list --fields=post_title` - Then STDOUT should contain: - """ - world, Hello - """ - - Scenario: Search and replace within theme mods - Given a WP install - And a setup-theme-mod.php file: - """ - <?php - set_theme_mod( 'header_image_data', (object) array( 'url' => 'http://subdomain.example.com/foo.jpg' ) ); - """ - And I run `wp eval-file setup-theme-mod.php` - - When I run `wp theme mod get header_image_data` - Then STDOUT should be a table containing rows: - | key | value | - | header_image_data | {"url":"http:\/\/subdomain.example.com\/foo.jpg"} | - - When I run `wp search-replace subdomain.example.com example.com --no-recurse-objects` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 0 | PHP | - - When I run `wp search-replace subdomain.example.com example.com` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 1 | PHP | - - When I run `wp theme mod get header_image_data` - Then STDOUT should be a table containing rows: - | key | value | - | header_image_data | {"url":"http:\/\/example.com\/foo.jpg"} | - - Scenario: Search and replace with quoted strings - Given a WP install - - When I run `wp post create --post_content='<a href="http://apple.com">Apple</a>' --porcelain` - Then save STDOUT as {POST_ID} - - When I run `wp post get {POST_ID} --field=content` - Then STDOUT should be: - """ - <a href="http://apple.com">Apple</a> - """ - - When I run `wp search-replace '<a href="http://apple.com">Apple</a>' '<a href="http://google.com">Google</a>' --dry-run` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_posts | post_content | 1 | SQL | - - When I run `wp search-replace '<a href="http://apple.com">Apple</a>' '<a href="http://google.com">Google</a>'` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_posts | post_content | 1 | SQL | - - When I run `wp search-replace '<a href="http://google.com">Google</a>' '<a href="http://apple.com">Apple</a>' --dry-run` - Then STDOUT should contain: - """ - 1 replacement to be made. - """ - - When I run `wp post get {POST_ID} --field=content` - Then STDOUT should be: - """ - <a href="http://google.com">Google</a> - """ - - Scenario: Search and replace with the same terms - Given a WP install - - When I run `wp search-replace foo foo` - Then STDERR should be: - """ - Warning: Replacement value 'foo' is identical to search value 'foo'. Skipping operation. - """ - And STDOUT should be empty - - Scenario: Search and replace a table that has a multi-column primary key - Given a WP install - And I run `wp db query "CREATE TABLE wp_multicol ( "id" bigint(20) NOT NULL AUTO_INCREMENT,"name" varchar(60) NOT NULL,"value" text NOT NULL,PRIMARY KEY ("id","name"),UNIQUE KEY "name" ("name") ) ENGINE=InnoDB DEFAULT CHARSET=utf8 "` - And I run `wp db query "INSERT INTO wp_multicol VALUES (1, 'foo', 'bar')"` - And I run `wp db query "INSERT INTO wp_multicol VALUES (2, 'bar', 'foo')"` - - When I run `wp search-replace bar replaced wp_multicol` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_multicol | name | 1 | SQL | - | wp_multicol | value | 1 | SQL | - - Scenario Outline: Large guid search/replace where replacement contains search (or not) - Given a WP install - And I run `wp option get siteurl` - And save STDOUT as {SITEURL} - And I run `wp post generate --count=20` - - When I run `wp search-replace <flags> {SITEURL} <replacement>` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_posts | guid | 22 | SQL | - - Examples: - | replacement | flags | - | {SITEURL}/subdir | | - | http://newdomain.com | | - | http://newdomain.com | --dry-run | - - Scenario Outline: Choose replacement method (PHP or MySQL/MariaDB) given proper flags or data. - Given a WP install - And I run `wp option get siteurl` - And save STDOUT as {SITEURL} - When I run `wp search-replace <flags> {SITEURL} http://wordpress.org` - - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 2 | <serial> | - | wp_posts | post_title | 0 | <noserial> | - - Examples: - | flags | serial | noserial | - | | PHP | SQL | - | --precise | PHP | PHP | - - Scenario Outline: Ensure search and replace uses PHP (precise) mode when serialized data is found - Given a WP install - And I run `wp post create --post_content='<input>' --porcelain` - And save STDOUT as {CONTROLPOST} - And I run `wp search-replace --precise foo bar` - And I run `wp post get {CONTROLPOST} --field=content` - And save STDOUT as {CONTROL} - And I run `wp post create --post_content='<input>' --porcelain` - And save STDOUT as {TESTPOST} - And I run `wp search-replace foo bar` - - When I run `wp post get {TESTPOST} --field=content` - Then STDOUT should be: - """ - {CONTROL} - """ - - Examples: - | input | - | a:1:{s:3:"bar";s:3:"foo";} | - | O:8:"stdClass":1:{s:1:"a";s:3:"foo";} | - - Scenario: Search replace with a regex flag - Given a WP install - - When I run `wp search-replace 'EXAMPLE.com' 'BAXAMPLE.com' wp_options --regex` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 0 | PHP | - - When I run `wp option get home` - Then STDOUT should be: - """ - http://example.com - """ - - When I run `wp search-replace 'EXAMPLE.com' 'BAXAMPLE.com' wp_options --regex --regex-flags=i` - Then STDOUT should be a table containing rows: - | Table | Column | Replacements | Type | - | wp_options | option_value | 5 | PHP | - - When I run `wp option get home` - Then STDOUT should be: - """ - http://BAXAMPLE.com - """ diff --git a/features/server.feature b/features/server.feature deleted file mode 100644 index 0a0100685..000000000 --- a/features/server.feature +++ /dev/null @@ -1,16 +0,0 @@ -@require-php-5.4 -Feature: Serve WordPress locally - - Scenario: Vanilla install - Given a WP install - And I launch in the background `wp server --host=localhost --port=8181` - - When I run `curl -sS localhost:8181` - Then STDOUT should contain: - """ - Just another WordPress site - """ - - When I run `curl -sS localhost:8181/license.txt > /tmp/license.txt` - And I run `cmp /tmp/license.txt license.txt` - Then STDOUT should be empty diff --git a/features/shell.feature b/features/shell.feature deleted file mode 100644 index 03dd6cb3e..000000000 --- a/features/shell.feature +++ /dev/null @@ -1,42 +0,0 @@ -Feature: WordPress REPL - - Scenario: Blank session - Given a WP install - - When I run `wp shell < /dev/null` - - When I run `wp shell --basic < /dev/null` - Then STDOUT should be empty - - Scenario: Persistent environment - Given a WP install - And a session file: - """ - function is_empty_string( $str ) { return strlen( $str ) == 0; } - $a = get_option('home'); - is_empty_string( $a ); - """ - - When I run `wp shell --basic < session` - Then STDOUT should contain: - """ - bool(false) - """ - - Scenario: Multiline support (basic) - Given a WP install - And a session file: - """ - function is_empty_string( $str ) { \ - return strlen( $str ) == 0; \ - } - - function_exists( 'is_empty_string' ); - """ - - When I run `wp shell --basic < session` - Then STDOUT should contain: - """ - bool(true) - """ - diff --git a/features/sidebar.feature b/features/sidebar.feature deleted file mode 100644 index cf53186c5..000000000 --- a/features/sidebar.feature +++ /dev/null @@ -1,24 +0,0 @@ -Feature: Manage WordPress sidebars - - Scenario: List available sidebars - Given a WP install - - When I run `wp theme install p2 --activate` - Then STDOUT should not be empty - - When I run `wp sidebar list --fields=name,id` - Then STDOUT should be a table containing rows: - | name | id | - | Sidebar | sidebar-1 | - - When I run `wp sidebar list --format=ids` - Then STDOUT should be: - """ - sidebar-1 wp_inactive_widgets - """ - - When I run `wp sidebar list --format=count` - Then STDOUT should be: - """ - 2 - """ diff --git a/features/site-create.feature b/features/site-create.feature deleted file mode 100644 index c01656608..000000000 --- a/features/site-create.feature +++ /dev/null @@ -1,46 +0,0 @@ -Feature: Create a new site on a WP multisite - - Scenario: Respect defined `$base` in wp-config - Given an empty directory - And WP files - And a database - And a extra-config file: - """ - define( 'WP_ALLOW_MULTISITE', true ); - define( 'MULTISITE', true ); - define( 'SUBDOMAIN_INSTALL', false ); - $base = '/dev/'; - define( 'DOMAIN_CURRENT_SITE', 'localhost' ); - define( 'PATH_CURRENT_SITE', '/dev/' ); - define( 'SITE_ID_CURRENT_SITE', 1 ); - define( 'BLOG_ID_CURRENT_SITE', 1 ); - """ - - When I run `wp core config {CORE_CONFIG_SETTINGS} --extra-php < extra-config` - Then STDOUT should be: - """ - Success: Generated 'wp-config.php' file. - """ - - When I run `wp core multisite-install --url=localhost/dev/ --title=Test --admin_user=admin --admin_email=admin@example.org` - Then STDOUT should contain: - """ - Success: Network installed. Don't forget to set up rewrite rules. - """ - - When I run `wp site list --fields=blog_id,url` - Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | http://localhost/dev/ | - - When I run `wp site create --slug=newsite` - Then STDOUT should be: - """ - Success: Site 2 created: http://localhost/dev/newsite/ - """ - - When I run `wp site list --fields=blog_id,url` - Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | http://localhost/dev/ | - | 2 | http://localhost/dev/newsite/ | diff --git a/features/site-empty.feature b/features/site-empty.feature deleted file mode 100644 index 2f5e49b80..000000000 --- a/features/site-empty.feature +++ /dev/null @@ -1,70 +0,0 @@ -Feature: Empty a WordPress site of its data - - Scenario: Empty a site - Given a WP install - And I run `wp option update uploads_use_yearmonth_folders 0` - And download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp media import {CACHE_DIR}/large-image.jpg --post_id=1` - Then the wp-content/uploads/large-image.jpg file should exist - - When I try `wp site url 1` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` - Then STDOUT should be: - """ - 4 - """ - - When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term'` - Then STDOUT should be: - """ - Success: Created post_tag 2. - """ - - When I run `wp site empty --yes` - Then STDOUT should be: - """ - Success: The site at 'http://example.com' was emptied. - """ - And the wp-content/uploads/large-image.jpg file should exist - - When I run `wp post list --format=ids` - Then STDOUT should be empty - - When I run `wp term list post_tag --format=ids` - Then STDOUT should be empty - - Scenario: Empty a site and its uploads directory - Given a WP multisite install - And I run `wp site create --slug=foo` - And I run `wp --url=example.com/foo option update uploads_use_yearmonth_folders 0` - And download: - | path | url | - | {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg | - - When I run `wp --url=example.com/foo media import {CACHE_DIR}/large-image.jpg --post_id=1` - Then the wp-content/uploads/sites/2/large-image.jpg file should exist - - When I run `wp site empty --uploads --yes` - Then STDOUT should not be empty - And the wp-content/uploads/sites/2/large-image.jpg file should exist - - When I run `wp post list --format=ids` - Then STDOUT should be empty - - When I run `wp --url=example.com/foo site empty --uploads --yes` - Then STDOUT should be: - """ - Success: The site at 'http://example.com/foo' was emptied. - """ - And the wp-content/uploads/sites/2/large-image.jpg file should not exist - - When I run `wp --url=example.com/foo post list --format=ids` - Then STDOUT should be empty diff --git a/features/site-option.feature b/features/site-option.feature deleted file mode 100644 index fdd393217..000000000 --- a/features/site-option.feature +++ /dev/null @@ -1,153 +0,0 @@ -Feature: Manage WordPress site options - - Scenario: Site Option CRUD - Given a WP multisite install - - # String values - When I run `wp site option add str_opt 'bar'` - Then STDOUT should not be empty - - When I run `wp site option get str_opt` - Then STDOUT should be: - """ - bar - """ - - When I run `wp site option list` - Then STDOUT should not be empty - - When I run `wp site option list` - Then STDOUT should contain: - """ - str_opt bar - """ - - When I run `wp site option list --search='str_o*'` - Then STDOUT should be a table containing rows: - | meta_key | meta_value | - | str_opt | bar | - - When I run `wp site option list --search='str_o*' --format=total_bytes` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp site option list` - Then STDOUT should contain: - """ - admin_user_id 1 - """ - - When I run `wp site option delete str_opt` - Then STDOUT should not be empty - - When I run `wp site option list` - Then STDOUT should not contain: - """ - str_opt bar - """ - - When I try `wp site option get str_opt` - Then the return code should be 1 - - # Integer values - When I run `wp site option update admin_user_id 2` - Then STDOUT should not be empty - - When I run `wp site option get admin_user_id` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp site option update admin_user_id 1` - Then STDOUT should contain: - """ - Success: Updated 'admin_user_id' site option. - """ - - When I run the previous command again - Then STDOUT should contain: - """ - Success: Value passed for 'admin_user_id' site option is unchanged. - """ - - When I run `wp site option get admin_user_id` - Then STDOUT should be: - """ - 1 - """ - - # JSON values - When I run `wp site option set json_opt '[ 1, 2 ]' --format=json` - Then STDOUT should not be empty - - When I run the previous command again - Then STDOUT should not be empty - - When I run `wp site option get json_opt --format=json` - Then STDOUT should be: - """ - [1,2] - """ - - # Reading from files - Given a value.json file: - """ - { - "foo": "bar", - "list": [1, 2, 3] - } - """ - When I run `wp site option set foo --format=json < value.json` - And I run `wp site option get foo --format=json` - Then STDOUT should be JSON containing: - """ - { - "foo": "bar", - "list": [1, 2, 3] - } - """ - - Scenario: Error on single install - Given a WP install - - When I try `wp site option get str_opt` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - When I try `wp site option add str_opt 'bar'` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - Scenario: Filter options by `--site_id` - Given a WP multisite install - - When I run `wp db query "INSERT INTO wp_sitemeta (site_id,meta_key,meta_value) VALUES (2,'wp_cli_test_option','foobar');"` - Then the return code should be 0 - - When I run `wp site option list` - Then STDOUT should contain: - """ - wp_cli_test_option - """ - And STDERR should be empty - - When I run `wp site option list --site_id=1` - Then STDOUT should not contain: - """ - wp_cli_test_option - """ - And STDERR should be empty - - When I run `wp site option list --site_id=2` - Then STDOUT should contain: - """ - wp_cli_test_option - """ - And STDERR should be empty diff --git a/features/site.feature b/features/site.feature deleted file mode 100644 index 4f1074343..000000000 --- a/features/site.feature +++ /dev/null @@ -1,305 +0,0 @@ -Feature: Manage sites in a multisite installation - - Scenario: Create a site - Given a WP multisite install - - When I try `wp site create --slug=first --network_id=1000` - Then STDERR should contain: - """ - Network with id 1000 does not exist. - """ - - Scenario: Create a subdomain site - Given a WP multisite subdomain install - - When I run `wp site create --slug=first` - Then STDOUT should not be empty - - When I run `wp site list --fields=blog_id,url` - Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | http://example.com/ | - | 2 | http://first.example.com/ | - - When I run `wp site list --format=ids` - Then STDOUT should be: - """ - 1 2 - """ - - When I run `wp site list --site_id=2 --format=ids` - Then STDOUT should be empty - - When I run `wp --url=first.example.com option get home` - Then STDOUT should be: - """ - http://first.example.com - """ - - Scenario: Delete a site by id - Given a WP multisite subdirectory install - - When I run `wp site create --slug=first --porcelain` - Then STDOUT should be a number - And save STDOUT as {SITE_ID} - - When I run `wp site list --fields=blog_id,url` - Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | http://example.com/ | - | 2 | http://example.com/first/ | - - When I run `wp site list --field=url` - Then STDOUT should be: - """ - http://example.com/ - http://example.com/first/ - """ - - When I run `wp site delete {SITE_ID} --yes` - Then STDOUT should be: - """ - Success: The site at 'http://example.com/first/' was deleted. - """ - - When I try the previous command again - Then the return code should be 1 - - Scenario: Filter site list - Given a WP multisite install - - When I run `wp site create --slug=first --porcelain` - Then STDOUT should be a number - And save STDOUT as {SITE_ID} - - When I run `wp site list --fields=blog_id,url` - Then STDOUT should be a table containing rows: - | blog_id | url | - | 1 | http://example.com/ | - | 2 | http://example.com/first/ | - - When I run `wp site list --field=url --blog_id=2` - Then STDOUT should be: - """ - http://example.com/first/ - """ - - Scenario: Delete a site by slug - Given a WP multisite install - - When I run `wp site create --slug=first` - Then STDOUT should be: - """ - Success: Site 2 created: http://example.com/first/ - """ - - When I run `wp site delete --slug=first --yes` - Then STDOUT should be: - """ - Success: The site at 'http://example.com/first/' was deleted. - """ - - When I try the previous command again - Then the return code should be 1 - - Scenario: Get site info - Given a WP multisite install - - When I run `wp site create --slug=first --porcelain` - Then STDOUT should be a number - And save STDOUT as {SITE_ID} - - When I run `wp site url {SITE_ID}` - Then STDOUT should be: - """ - http://example.com/first/ - """ - - When I run `wp site create --slug=second --porcelain` - Then STDOUT should be a number - And save STDOUT as {SECOND_ID} - - When I run `wp site url {SECOND_ID} {SITE_ID}` - Then STDOUT should be: - """ - http://example.com/second/ - http://example.com/first/ - """ - - Scenario: Archive/unarchive a site - Given a WP multisite install - And I run `wp site create --slug=first --porcelain` - And save STDOUT as {FIRST_SITE} - And I run `wp site create --slug=second --porcelain` - And save STDOUT as {SECOND_SITE} - - When I run `wp site archive {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} archived. - """ - - When I run `wp site list --fields=blog_id,archived` - Then STDOUT should be a table containing rows: - | blog_id | archived | - | {FIRST_SITE} | 1 | - - When I run `wp site archive {FIRST_SITE} {SECOND_SITE}` - Then STDERR should be: - """ - Warning: Site {FIRST_SITE} already archived. - """ - And STDOUT should be: - """ - Success: Site {SECOND_SITE} archived. - """ - - When I run `wp site list --fields=blog_id,archived` - Then STDOUT should be a table containing rows: - | blog_id | archived | - | {FIRST_SITE} | 1 | - - When I run `wp site unarchive {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} unarchived. - """ - - When I run `wp site list --fields=blog_id,archived` - Then STDOUT should be a table containing rows: - | blog_id | archived | - | {FIRST_SITE} | 0 | - - When I try `wp site archive 1` - Then STDERR should be: - """ - Warning: You are not allowed to change the main site. - """ - - Scenario: Activate/deactivate a site - Given a WP multisite install - And I run `wp site create --slug=first --porcelain` - And save STDOUT as {FIRST_SITE} - And I run `wp site create --slug=second --porcelain` - And save STDOUT as {SECOND_SITE} - - When I run `wp site deactivate {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} deactivated. - """ - - When I run `wp site list --fields=blog_id,deleted` - Then STDOUT should be a table containing rows: - | blog_id | deleted | - | {FIRST_SITE} | 1 | - - When I run `wp site deactivate {FIRST_SITE} {SECOND_SITE}` - Then STDERR should be: - """ - Warning: Site {FIRST_SITE} already deactivated. - """ - And STDOUT should be: - """ - Success: Site {SECOND_SITE} deactivated. - """ - - When I run `wp site list --fields=blog_id,deleted` - Then STDOUT should be a table containing rows: - | blog_id | deleted | - | {FIRST_SITE} | 1 | - - When I run `wp site activate {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} activated. - """ - - When I run `wp site list --fields=blog_id,deleted` - Then STDOUT should be a table containing rows: - | blog_id | deleted | - | {FIRST_SITE} | 0 | - - When I run `wp site deactivate 1` - Then STDERR should be: - """ - Warning: You are not allowed to change the main site. - """ - - Scenario: Mark/remove a site from spam - Given a WP multisite install - And I run `wp site create --slug=first --porcelain` - And save STDOUT as {FIRST_SITE} - And I run `wp site create --slug=second --porcelain` - And save STDOUT as {SECOND_SITE} - - When I run `wp site spam {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} marked as spam. - """ - - When I run `wp site list --fields=blog_id,spam` - Then STDOUT should be a table containing rows: - | blog_id | spam | - | {FIRST_SITE} | 1 | - - When I run `wp site spam {FIRST_SITE} {SECOND_SITE}` - Then STDERR should be: - """ - Warning: Site {FIRST_SITE} already marked as spam. - """ - And STDOUT should be: - """ - Success: Site {SECOND_SITE} marked as spam. - """ - - When I run `wp site list --fields=blog_id,spam` - Then STDOUT should be a table containing rows: - | blog_id | spam | - | {FIRST_SITE} | 1 | - - When I run `wp site unspam {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} removed from spam. - """ - - When I run `wp site list --fields=blog_id,spam` - Then STDOUT should be a table containing rows: - | blog_id | spam | - | {FIRST_SITE} | 0 | - - When I run `wp site spam 1` - Then STDERR should be: - """ - Warning: You are not allowed to change the main site. - """ - - Scenario: Permit CLI operations against archived and suspended sites - Given a WP multisite install - And I run `wp site create --slug=first --porcelain` - And save STDOUT as {FIRST_SITE} - - When I run `wp site archive {FIRST_SITE}` - Then STDOUT should be: - """ - Success: Site {FIRST_SITE} archived. - """ - - When I run `wp --url=example.com/first option get home` - Then STDOUT should be: - """ - http://example.com/first - """ - - Scenario: Create site with title containing slash - Given a WP multisite install - And I run `wp site create --slug=mysite --title="My\Site"` - Then STDOUT should not be empty - - When I run `wp option get blogname --url=example.com/mysite` - Then STDOUT should be: - """ - My\Site - """ diff --git a/features/skip-plugins.feature b/features/skip-plugins.feature deleted file mode 100644 index 98695933b..000000000 --- a/features/skip-plugins.feature +++ /dev/null @@ -1,105 +0,0 @@ -Feature: Skipping plugins - - Scenario: Skipping plugins via global flag - Given a WP install - And I run `wp plugin activate hello akismet` - - When I run `wp eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - truetrue - """ - - # The specified plugin should be skipped - When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );'` - Then STDOUT should be: - """ - false - """ - - # The specified plugin should still show up as an active plugin - When I run `wp --skip-plugins=akismet plugin status akismet` - Then STDOUT should contain: - """ - Status: Active - """ - - # The un-specified plugin should continue to be loaded - When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - falsetrue - """ - - # Can specify multiple plugins to skip - When I try `wp eval --skip-plugins=hello,akismet 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - # No plugins should be loaded when --skip-plugins doesn't have a value - When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - falsefalse - """ - - Scenario: Skipping multiple plugins via config file - Given a WP install - And a wp-cli.yml file: - """ - skip-plugins: - - hello - - akismet - """ - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skipping all plugins via config file - Given a WP install - And a wp-cli.yml file: - """ - skip-plugins: true - """ - - When I run `wp plugin activate hello` - And I try `wp eval 'echo hello_dolly();'` - Then STDERR should contain: - """ - Call to undefined function hello_dolly() - """ - - Scenario: Skip network active plugins - Given a WP multisite install - And I run `wp plugin deactivate akismet hello` - And I run `wp plugin activate --network akismet hello` - - When I run `wp eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - truetrue - """ - - When I run `wp --skip-plugins eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - falsefalse - """ - - When I run `wp --skip-plugins=akismet eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - falsetrue - """ - - When I run `wp --skip-plugins=hello eval 'var_export( defined("AKISMET_VERSION") );var_export( function_exists( "hello_dolly" ) );'` - Then STDOUT should be: - """ - truefalse - """ diff --git a/features/skip-themes.feature b/features/skip-themes.feature deleted file mode 100644 index 7a710c719..000000000 --- a/features/skip-themes.feature +++ /dev/null @@ -1,152 +0,0 @@ -Feature: Skipping themes - - Scenario: Skipping themes via global flag - Given a WP install - And I run `wp theme install classic` - And I run `wp theme install default --activate` - - When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - true - """ - And STDERR should be empty - - # The specified theme should be skipped - When I run `wp --skip-themes=default eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - # All themes should be skipped - When I run `wp --skip-themes eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - # Skip another theme - When I run `wp --skip-themes=classic eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - true - """ - And STDERR should be empty - - # The specified theme should still show up as an active theme - When I run `wp --skip-themes theme status default` - Then STDOUT should contain: - """ - Active - """ - And STDERR should be empty - - # Skip several themes - When I run `wp --skip-themes=classic,default eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - Scenario: Skip parent and child themes - Given a WP install - And I run `wp theme install jolene biker` - - When I run `wp theme activate jolene` - When I run `wp eval 'var_export( function_exists( "jolene_setup" ) );'` - Then STDOUT should be: - """ - true - """ - And STDERR should be empty - - When I run `wp --skip-themes=jolene eval 'var_export( function_exists( "jolene_setup" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - When I run `wp theme activate biker` - When I run `wp eval 'var_export( function_exists( "jolene_setup" ) );'` - Then STDOUT should be: - """ - true - """ - And STDERR should be empty - - When I run `wp eval 'var_export( function_exists( "biker_setup" ) );'` - Then STDOUT should be: - """ - true - """ - And STDERR should be empty - - When I run `wp --skip-themes=biker eval 'var_export( function_exists( "jolene_setup" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - When I run `wp --skip-themes=biker eval 'var_export( function_exists( "biker_setup" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty - - When I run `wp --skip-themes=biker eval 'echo get_template_directory();'` - Then STDOUT should contain: - """ - wp-content/themes/jolene - """ - And STDERR should be empty - - When I run `wp --skip-themes=biker eval 'echo get_stylesheet_directory();'` - Then STDOUT should contain: - """ - wp-content/themes/biker - """ - And STDERR should be empty - - Scenario: Skipping multiple themes via config file - Given a WP install - And a wp-cli.yml file: - """ - skip-themes: - - classic - - default - """ - And I run `wp theme install classic --activate` - And I run `wp theme install default` - - # The classic theme should show up as an active theme - When I run `wp theme status` - Then STDOUT should contain: - """ - A classic - """ - And STDERR should be empty - - # The default theme should show up as an installed theme - When I run `wp theme status` - Then STDOUT should contain: - """ - I default - """ - And STDERR should be empty - - And I run `wp theme activate default` - - # The default theme should be skipped - When I run `wp eval 'var_export( function_exists( "kubrick_head" ) );'` - Then STDOUT should be: - """ - false - """ - And STDERR should be empty diff --git a/features/steps/given.php b/features/steps/given.php deleted file mode 100644 index a1b6a1bb9..000000000 --- a/features/steps/given.php +++ /dev/null @@ -1,164 +0,0 @@ -<?php - -use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode, - WP_CLI\Process; - -$steps->Given( '/^an empty directory$/', - function ( $world ) { - $world->create_run_dir(); - } -); - -$steps->Given( '/^an empty cache/', - function ( $world ) { - $world->variables['SUITE_CACHE_DIR'] = FeatureContext::create_cache_dir(); - } -); - -$steps->Given( '/^an? ([^\s]+) file:$/', - function ( $world, $path, PyStringNode $content ) { - $content = (string) $content . "\n"; - $full_path = $world->variables['RUN_DIR'] . "/$path"; - Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); - file_put_contents( $full_path, $content ); - } -); - -$steps->Given( '/^"([^"]+)" replaced with "([^"]+)" in the ([^\s]+) file$/', function( $world, $search, $replace, $path ) { - $full_path = $world->variables['RUN_DIR'] . "/$path"; - $contents = file_get_contents( $full_path ); - $contents = str_replace( $search, $replace, $contents ); - file_put_contents( $full_path, $contents ); -}); - -$steps->Given( '/^WP files$/', - function ( $world ) { - $world->download_wp(); - } -); - -$steps->Given( '/^wp-config\.php$/', - function ( $world ) { - $world->create_config(); - } -); - -$steps->Given( '/^a database$/', - function ( $world ) { - $world->create_db(); - } -); - -$steps->Given( '/^a WP install$/', - function ( $world ) { - $world->install_wp(); - } -); - -$steps->Given( "/^a WP install in '([^\s]+)'$/", - function ( $world, $subdir ) { - $world->install_wp( $subdir ); - } -); - -$steps->Given( '/^a WP multisite (subdirectory|subdomain)?\s?install$/', - function ( $world, $type = 'subdirectory' ) { - $world->install_wp(); - $subdomains = ! empty( $type ) && 'subdomain' === $type ? 1 : 0; - $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network', 'subdomains' => $subdomains ) )->run_check(); - } -); - -$steps->Given( '/^these installed and active plugins:$/', - function( $world, $stream ) { - $plugins = implode( ' ', array_map( 'trim', explode( PHP_EOL, (string)$stream ) ) ); - $world->proc( "wp plugin install $plugins --activate" )->run_check(); - } -); - -$steps->Given( '/^a custom wp-content directory$/', - function ( $world ) { - $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; - - $wp_config_code = file_get_contents( $wp_config_path ); - - $world->move_files( 'wp-content', 'my-content' ); - $world->add_line_to_wp_config( $wp_config_code, - "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); - - $world->move_files( 'my-content/plugins', 'my-plugins' ); - $world->add_line_to_wp_config( $wp_config_code, - "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); - - file_put_contents( $wp_config_path, $wp_config_code ); - } -); - -$steps->Given( '/^download:$/', - function ( $world, TableNode $table ) { - foreach ( $table->getHash() as $row ) { - $path = $world->replace_variables( $row['path'] ); - if ( file_exists( $path ) ) { - // assume it's the same file and skip re-download - continue; - } - - Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); - } - } -); - -$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?\s?as \{(\w+)\}$/', - function ( $world, $stream, $output_filter, $key ) { - - $stream = strtolower( $stream ); - - if ( $output_filter ) { - $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; - if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) - $output = array_pop( $matches ); - else - $output = ''; - } else { - $output = $world->result->$stream; - } - $world->variables[ $key ] = trim( $output, "\n" ); - } -); - -$steps->Given( '/^a new Phar(?: with version "([^"]+)")$/', - function ( $world, $version ) { - $world->build_phar( $version ); - } -); - -$steps->Given( '/^save the (.+) file ([\'].+[^\'])?as \{(\w+)\}$/', - function ( $world, $filepath, $output_filter, $key ) { - $full_file = file_get_contents( $world->replace_variables( $filepath ) ); - - if ( $output_filter ) { - $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; - if ( false !== preg_match( $output_filter, $full_file, $matches ) ) - $output = array_pop( $matches ); - else - $output = ''; - } else { - $output = $full_file; - } - $world->variables[ $key ] = trim( $output, "\n" ); - } -); - -$steps->Given('/^a misconfigured WP_CONTENT_DIR constant directory$/', - function($world) { - $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; - - $wp_config_code = file_get_contents( $wp_config_path ); - - $world->add_line_to_wp_config( $wp_config_code, - "define( 'WP_CONTENT_DIR', '' );" ); - - file_put_contents( $wp_config_path, $wp_config_code ); - } -); diff --git a/features/steps/then.php b/features/steps/then.php deleted file mode 100644 index a5974f16c..000000000 --- a/features/steps/then.php +++ /dev/null @@ -1,210 +0,0 @@ -<?php - -use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode; - -$steps->Then( '/^the return code should be (\d+)$/', - function ( $world, $return_code ) { - if ( $return_code != $world->result->return_code ) { - throw new RuntimeException( $world->result ); - } - } -); - -$steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', - function ( $world, $stream, $action, PyStringNode $expected ) { - - $stream = strtolower( $stream ); - - $expected = $world->replace_variables( (string) $expected ); - - checkString( $world->result->$stream, $expected, $action, $world->result ); - } -); - -$steps->Then( '/^(STDOUT|STDERR) should be a number$/', - function ( $world, $stream ) { - - $stream = strtolower( $stream ); - - assertNumeric( trim( $world->result->$stream, "\n" ) ); - } -); - -$steps->Then( '/^(STDOUT|STDERR) should not be a number$/', - function ( $world, $stream ) { - - $stream = strtolower( $stream ); - - assertNotNumeric( trim( $world->result->$stream, "\n" ) ); - } -); - -$steps->Then( '/^STDOUT should be a table containing rows:$/', - function ( $world, TableNode $expected ) { - $output = $world->result->stdout; - $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); - - $expected_rows = array(); - foreach ( $expected->getRows() as $row ) { - $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); - } - - compareTables( $expected_rows, $actual_rows, $output ); - } -); - -$steps->Then( '/^STDOUT should end with a table containing rows:$/', - function ( $world, TableNode $expected ) { - $output = $world->result->stdout; - $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); - - $expected_rows = array(); - foreach ( $expected->getRows() as $row ) { - $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); - } - - $start = array_search( $expected_rows[0], $actual_rows ); - - if ( false === $start ) - throw new \Exception( $world->result ); - - compareTables( $expected_rows, array_slice( $actual_rows, $start ), $output ); - } -); - -$steps->Then( '/^STDOUT should be JSON containing:$/', - function ( $world, PyStringNode $expected ) { - $output = $world->result->stdout; - $expected = $world->replace_variables( (string) $expected ); - - if ( !checkThatJsonStringContainsJsonString( $output, $expected ) ) { - throw new \Exception( $world->result ); - } -}); - -$steps->Then( '/^STDOUT should be a JSON array containing:$/', - function ( $world, PyStringNode $expected ) { - $output = $world->result->stdout; - $expected = $world->replace_variables( (string) $expected ); - - $actualValues = json_decode( $output ); - $expectedValues = json_decode( $expected ); - - $missing = array_diff( $expectedValues, $actualValues ); - if ( !empty( $missing ) ) { - throw new \Exception( $world->result ); - } -}); - -$steps->Then( '/^STDOUT should be CSV containing:$/', - function ( $world, TableNode $expected ) { - $output = $world->result->stdout; - - $expected_rows = $expected->getRows(); - foreach ( $expected as &$row ) { - foreach ( $row as &$value ) { - $value = $world->replace_variables( $value ); - } - } - - if ( ! checkThatCsvStringContainsValues( $output, $expected_rows ) ) - throw new \Exception( $world->result ); - } -); - -$steps->Then( '/^STDOUT should be YAML containing:$/', - function ( $world, PyStringNode $expected ) { - $output = $world->result->stdout; - $expected = $world->replace_variables( (string) $expected ); - - if ( !checkThatYamlStringContainsYamlString( $output, $expected ) ) { - throw new \Exception( $world->result ); - } -}); - -$steps->Then( '/^(STDOUT|STDERR) should be empty$/', - function ( $world, $stream ) { - - $stream = strtolower( $stream ); - - if ( !empty( $world->result->$stream ) ) { - throw new \Exception( $world->result ); - } - } -); - -$steps->Then( '/^(STDOUT|STDERR) should not be empty$/', - function ( $world, $stream ) { - - $stream = strtolower( $stream ); - - if ( '' === rtrim( $world->result->$stream, "\n" ) ) { - throw new Exception( $world->result ); - } - } -); - -$steps->Then( '/^(STDOUT|STDERR) should be a version string (<|<=|>|>=|==|=|!=|<>) ([+\w\.-]+)$/', - function ( $world, $stream, $operator, $goal_ver ) { - $stream = strtolower( $stream ); - if ( false === version_compare( trim( $world->result->$stream, "\n" ), $goal_ver, $operator ) ) { - throw new Exception( $world->result ); - } - } -); - -$steps->Then( '/^the (.+) (file|directory) should (exist|not exist|be:|contain:|not contain:)$/', - function ( $world, $path, $type, $action, $expected = null ) { - $path = $world->replace_variables( $path ); - - // If it's a relative path, make it relative to the current test dir - if ( '/' !== $path[0] ) - $path = $world->variables['RUN_DIR'] . "/$path"; - - if ( 'file' == $type ) { - $test = 'file_exists'; - } else if ( 'directory' == $type ) { - $test = 'is_dir'; - } - - switch ( $action ) { - case 'exist': - if ( ! $test( $path ) ) { - throw new Exception( $world->result ); - } - break; - case 'not exist': - if ( $test( $path ) ) { - throw new Exception( $world->result ); - } - break; - default: - if ( ! $test( $path ) ) { - throw new Exception( "$path doesn't exist." ); - } - $action = substr( $action, 0, -1 ); - $expected = $world->replace_variables( (string) $expected ); - if ( 'file' == $type ) { - $contents = file_get_contents( $path ); - } else if ( 'directory' == $type ) { - $files = glob( rtrim( $path, '/' ) . '/*' ); - foreach( $files as &$file ) { - $file = str_replace( $path . '/', '', $file ); - } - $contents = implode( PHP_EOL, $files ); - } - checkString( $contents, $expected, $action ); - } - } -); - -$steps->Then( '/^an email should (be sent|not be sent)$/', function( $world, $expected ) { - if ( 'be sent' === $expected ) { - assertNotEquals( 0, $world->email_sends ); - } else if ( 'not be sent' === $expected ) { - assertEquals( 0, $world->email_sends ); - } else { - throw new Exception( 'Invalid expectation' ); - } -}); diff --git a/features/steps/when.php b/features/steps/when.php deleted file mode 100644 index afe3f7a0d..000000000 --- a/features/steps/when.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -use Behat\Gherkin\Node\PyStringNode, - Behat\Gherkin\Node\TableNode, - WP_CLI\Process; - -function invoke_proc( $proc, $mode ) { - $map = array( - 'run' => 'run_check', - 'try' => 'run' - ); - $method = $map[ $mode ]; - - return $proc->$method(); -} - -function capture_email_sends( $stdout ) { - $stdout = preg_replace( '#WP-CLI test suite: Sent email to.+\n?#', '', $stdout, -1, $email_sends ); - return array( $stdout, $email_sends ); -} - -$steps->When( '/^I launch in the background `([^`]+)`$/', - function ( $world, $cmd ) { - $world->background_proc( $cmd ); - } -); - -$steps->When( '/^I (run|try) `([^`]+)`$/', - function ( $world, $mode, $cmd ) { - $cmd = $world->replace_variables( $cmd ); - $world->result = invoke_proc( $world->proc( $cmd ), $mode ); - list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); - } -); - -$steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", - function ( $world, $mode, $cmd, $subdir ) { - $cmd = $world->replace_variables( $cmd ); - $world->result = invoke_proc( $world->proc( $cmd, array(), $subdir ), $mode ); - list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); - } -); - -$steps->When( '/^I (run|try) the previous command again$/', - function ( $world, $mode ) { - if ( !isset( $world->result ) ) - throw new \Exception( 'No previous command.' ); - - $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); - $world->result = invoke_proc( $proc, $mode ); - list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); - } -); - diff --git a/features/super-admin.feature b/features/super-admin.feature deleted file mode 100644 index 4c8b543d8..000000000 --- a/features/super-admin.feature +++ /dev/null @@ -1,77 +0,0 @@ -Feature: Manage super admins associated with a multisite instance - - Scenario: Add, list, and remove super admins. - Given a WP multisite install - When I run `wp user create superadmin superadmin@example.com` - And I run `wp super-admin list` - Then STDOUT should be: - """ - admin - """ - - When I run `wp super-admin add superadmin` - Then STDOUT should be: - """ - Success: Granted super-admin capabilities to 1 user. - """ - And the return code should be 0 - - When I run `wp super-admin list` - Then STDOUT should be: - """ - admin - superadmin - """ - - When I run `wp super-admin add superadmin` - Then STDERR should be: - """ - Warning: User 'superadmin' already has super-admin capabilities. - """ - And STDOUT should be: - """ - Success: Super admins remain unchanged. - """ - And the return code should be 0 - - When I run `wp super-admin list` - Then STDOUT should be: - """ - admin - superadmin - """ - - When I run `wp super-admin list --format=table` - Then STDOUT should be a table containing rows: - | user_login | - | admin | - | superadmin | - - When I run `wp super-admin remove admin` - And I run `wp super-admin list` - Then STDOUT should be: - """ - superadmin - """ - - When I run `wp super-admin list --format=json` - Then STDOUT should be: - """ - [{"user_login":"superadmin"}] - """ - - When I try `wp super-admin add noadmin` - Then STDERR should be: - """ - Warning: Invalid user ID, email or login: 'noadmin' - Error: Couldn't grant super-admin capabilities to 1 of 1 users. - """ - And the return code should be 1 - - When I try `wp super-admin add admin noadmin` - Then STDERR should be: - """ - Warning: Invalid user ID, email or login: 'noadmin' - Error: Only granted super-admin capabilities to 1 of 2 users. - """ - And the return code should be 1 diff --git a/features/taxonomy.feature b/features/taxonomy.feature deleted file mode 100644 index e2d75c316..000000000 --- a/features/taxonomy.feature +++ /dev/null @@ -1,31 +0,0 @@ -Feature: Manage WordPress taxonomies - - Background: - Given a WP install - - @require-wp-3.7 - Scenario: Listing taxonomies - When I run `wp taxonomy list --format=csv` - Then STDOUT should be CSV containing: - | name | label | description | object_type | show_tagcloud | hierarchical | public | - | category | Categories | | post | 1 | 1 | 1 | - | post_tag | Tags | | post | 1 | | 1 | - - When I run `wp taxonomy list --object_type=link --format=csv` - Then STDOUT should be CSV containing: - | name | label | description | object_type | show_tagcloud | hierarchical | public | - | link_category | Link Categories | | link | | | | - - Scenario: Get taxonomy - When I try `wp taxonomy get invalid-taxonomy` - Then STDERR should be: - """ - Error: Taxonomy invalid-taxonomy doesn't exist. - """ - - When I run `wp taxonomy get category` - Then STDOUT should be a table containing rows: - | Field | Value | - | name | category | - | object_type | ["post"] | - | label | Categories | diff --git a/features/term-generate.feature b/features/term-generate.feature deleted file mode 100644 index 8da008a7b..000000000 --- a/features/term-generate.feature +++ /dev/null @@ -1,31 +0,0 @@ -Feature: Generate WP terms - - Background: - Given a WP install - - Scenario: Generating terms - When I run `wp term generate category --count=10` - And I run `wp term list category --format=count` - Then STDOUT should be: - """ - 11 - """ - - Scenario: Generating terms when terms already exist - When I run `wp term generate category --count=10` - And I run `wp term generate category --count=10` - And I run `wp term list category --format=count` - Then STDOUT should be: - """ - 21 - """ - - Scenario: Generating terms and outputting ids - When I run `wp term generate category --count=1 --format=ids` - Then save STDOUT as {TERM_ID} - - When I run `wp term update category {TERM_ID} --name="foo"` - Then STDOUT should contain: - """ - Success: - """ diff --git a/features/term-meta.feature b/features/term-meta.feature deleted file mode 100644 index fcc7b6581..000000000 --- a/features/term-meta.feature +++ /dev/null @@ -1,35 +0,0 @@ -Feature: Manage term custom fields - - @require-wp-4.4 - Scenario: Term meta CRUD - Given a WP install - - When I run `wp term meta add 1 foo 'bar'` - Then STDOUT should not be empty - - When I run `wp term meta get 1 foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp term meta get 999999 foo` - Then STDERR should be: - """ - Error: Could not find the term with ID 999999. - """ - - When I run `wp term meta set 1 foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run `wp term meta get 1 foo --format=json` - Then STDOUT should be: - """ - ["1","2"] - """ - - When I run `wp term meta delete 1 foo` - Then STDOUT should not be empty - - When I try `wp term meta get 1 foo` - Then the return code should be 1 diff --git a/features/term-recount.feature b/features/term-recount.feature deleted file mode 100644 index 59b4ad63e..000000000 --- a/features/term-recount.feature +++ /dev/null @@ -1,54 +0,0 @@ -Feature: Recount terms on a taxonomy - - Background: - Given a WP install - - - Scenario: Term recount with an invalid taxonomy - When I try `wp term recount some-fake-taxonomy` - Then STDERR should be: - """ - Warning: Taxonomy some-fake-taxonomy does not exist. - """ - - Scenario: Term recount with a valid taxonomy - When I try `wp term recount category` - Then STDOUT should be: - """ - Success: Updated category term count. - """ - - Scenario: Term recount with a multiple taxonomies - When I try `wp term recount category post_tag` - Then STDOUT should be: - """ - Success: Updated category term count. - Success: Updated post_tag term count. - """ - - Scenario: Fixes an invalid term count for a taxonomy - When I run `wp term create category "Term Recount Category" --porcelain` - Then STDOUT should be a number - Then save STDOUT as {TERM_ID} - - When I run `wp post create --post_title='Term Recount Test' --post_status=publish --post_category={TERM_ID} --porcelain` - Then STDOUT should be a number - And save STDOUT as {POST_ID} - - When I run `wp term get category {TERM_ID} --field=count` - Then STDOUT should be: - """ - 1 - """ - When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->term_taxonomy, array( "count" => 3 ), array( "term_id" => {TERM_ID} ) );'` - And I run `wp term get category {TERM_ID} --field=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp term recount category` - And I run `wp term get category {TERM_ID} --field=count` - """ - 1 - """ diff --git a/features/term.feature b/features/term.feature deleted file mode 100644 index a571564ef..000000000 --- a/features/term.feature +++ /dev/null @@ -1,177 +0,0 @@ -Feature: Manage WordPress terms - - Background: - Given a WP install - - Scenario: Creating/listing a term - When I run `wp term create post_tag 'Test term' --slug=test --description='This is a test term' --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID} - - When I try the previous command again - Then STDERR should not be empty - - When I run `wp term list post_tag --format=json` - Then STDOUT should be JSON containing: - """ - [{ - "name": "Test term", - "slug":"test", - "description":"This is a test term", - "parent":0, - "count":0 - }] - """ - - When I run `wp term list post_tag --fields=name,slug --format=csv` - Then STDOUT should be CSV containing: - | name | slug | - | Test term | test | - - When I run `wp term create category 'Test category' --slug=test-category --description='This is a test category'` - Then STDOUT should not be empty - - When I run `wp term list post_tag category --fields=name,slug --format=csv` - Then STDOUT should be CSV containing: - | name | slug | - | Test term | test | - | Test category | test-category | - - When I run `wp term get post_tag {TERM_ID}` - Then STDOUT should be a table containing rows: - | Field | Value | - | term_id | {TERM_ID} | - | name | Test term | - - When I run `wp term get post_tag {TERM_ID} --format=csv --fields=name,taxonomy` - Then STDOUT should be CSV containing: - | Field | Value | - | name | Test term | - | taxonomy | post_tag | - - When I try `wp term list nonexistent_taxonomy` - Then STDERR should be: - """ - Error: Taxonomy nonexistent_taxonomy doesn't exist. - """ - - Scenario: Creating/deleting a term - When I run `wp term create post_tag 'Test delete term' --slug=test-delete --description='This is a test term to be deleted' --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID} - - When I run `wp term create post_tag 'Test delete term 2' --slug=test-two --description='This is a test term to be deleted' --porcelain` - Then STDOUT should be a number - And save STDOUT as {TERM_ID_TWO} - - When I run `wp term get post_tag {TERM_ID} --field=slug --format=json` - Then STDOUT should be: - """ - "test-delete" - """ - - When I run `wp term delete post_tag {TERM_ID}` - Then STDOUT should be: - """ - Deleted post_tag {TERM_ID}. - Success: Deleted 1 of 1 terms. - """ - And the return code should be 0 - - When I run the previous command again - Then STDOUT should be: - """ - Success: Term already deleted. - """ - And STDERR should be: - """ - Warning: post_tag {TERM_ID} doesn't exist. - """ - And the return code should be 0 - - When I run `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` - Then STDOUT should be: - """ - Deleted post_tag {TERM_ID_TWO}. - Success: Deleted 1 of 2 terms. - """ - And STDERR should be: - """ - Warning: post_tag {TERM_ID} doesn't exist. - """ - And the return code should be 0 - - Scenario: Term with a non-existent parent - When I try `wp term create category Apple --parent=99 --porcelain` - Then STDERR should be: - """ - Error: Parent term does not exist. - """ - - Scenario: Filter terms by term_id - When I run `wp term generate category --count=10` - And I run `wp term create category "My Test Category" --porcelain` - And save STDOUT as {TERM_ID} - - When I run `wp term list category --term_id={TERM_ID} --field=name` - Then STDOUT should be: - """ - My Test Category - """ - - Scenario: Fetch term url - When I run `wp term create category "First Category" --porcelain` - And save STDOUT as {TERM_ID} - And I run `wp term create category "Second Category" --porcelain` - And save STDOUT as {SECOND_TERM_ID} - - When I run `wp term url category {TERM_ID}` - Then STDOUT should be: - """ - http://example.com/?cat=2 - """ - - When I run `wp term url category {TERM_ID} {SECOND_TERM_ID}` - Then STDOUT should be: - """ - http://example.com/?cat=2 - http://example.com/?cat=3 - """ - - When I run `wp term url category {SECOND_TERM_ID} {TERM_ID}` - Then STDOUT should be: - """ - http://example.com/?cat=3 - http://example.com/?cat=2 - """ - - Scenario: Make sure WordPress receives the slashed data it expects - When I run `wp term create category 'My\Term' --description='My\Term\Description' --porcelain` - Then save STDOUT as {TERM_ID} - - When I run `wp term get category {TERM_ID} --field=name` - Then STDOUT should be: - """ - My\Term - """ - - When I run `wp term get category {TERM_ID} --field=description` - Then STDOUT should be: - """ - My\Term\Description - """ - - When I run `wp term update category {TERM_ID} --name='My\New\Term' --description='var isEmailValid = /^\S+@\S+.\S+$/.test(email);'` - Then STDOUT should not be empty - - When I run `wp term get category {TERM_ID} --field=name` - Then STDOUT should be: - """ - My\New\Term - """ - - When I run `wp term get category {TERM_ID} --field=description` - Then STDOUT should be: - """ - var isEmailValid = /^\S+@\S+.\S+$/.test(email); - """ diff --git a/features/theme-delete.feature b/features/theme-delete.feature deleted file mode 100644 index 45a982c97..000000000 --- a/features/theme-delete.feature +++ /dev/null @@ -1,29 +0,0 @@ -Feature: Delete WordPress themes - - Background: - Given a WP install - And I run `wp theme install p2` - - Scenario: Delete an installed theme - When I run `wp theme delete p2` - Then STDOUT should be: - """ - Deleted 'p2' theme. - Success: Deleted 1 of 1 themes. - """ - And the return code should be 0 - - Scenario: Attempting to delete a theme that doesn't exist - When I run `wp theme delete p2` - Then STDOUT should not be empty - - When I run the previous command again - Then STDOUT should be: - """ - Success: Theme already deleted. - """ - And STDERR should be: - """ - Warning: The 'p2' theme could not be found. - """ - And the return code should be 0 diff --git a/features/theme-install.feature b/features/theme-install.feature deleted file mode 100644 index 491d43781..000000000 --- a/features/theme-install.feature +++ /dev/null @@ -1,73 +0,0 @@ -Feature: Install WordPress themes - - Scenario: Return code is 1 when one or more theme installations fail - Given a WP install - - When I try `wp theme install p2 p2-not-a-theme` - Then STDERR should be: - """ - Warning: Couldn't find 'p2-not-a-theme' in the WordPress.org theme directory. - Error: Only installed 1 of 2 themes. - """ - And STDOUT should contain: - """ - Installing P2 - """ - And STDOUT should contain: - """ - Theme installed successfully. - """ - And the return code should be 1 - - When I run `wp theme install p2` - Then STDOUT should be: - """ - Success: Theme already installed. - """ - And STDERR should be: - """ - Warning: p2: Theme already installed. - """ - And the return code should be 0 - - When I try `wp theme install p2-not-a-theme` - Then STDERR should be: - """ - Warning: Couldn't find 'p2-not-a-theme' in the WordPress.org theme directory. - Error: No themes installed. - """ - And the return code should be 1 - - Scenario: Ensure automatic parent theme installation uses http cacher - Given a WP install - And an empty cache - - When I run `wp theme install stargazer` - Then STDOUT should contain: - """ - Success: Installed 1 of 1 themes. - """ - And STDOUT should not contain: - """ - Using cached file - """ - - When I run `wp theme uninstall stargazer` - Then STDOUT should contain: - """ - Success: Deleted 1 of 1 themes. - """ - - When I run `wp theme install buntu` - Then STDOUT should contain: - """ - Success: Installed 1 of 1 themes. - """ - And STDOUT should contain: - """ - This theme requires a parent theme. - """ - And STDOUT should contain: - """ - Using cached file - """ diff --git a/features/theme-mod.feature b/features/theme-mod.feature deleted file mode 100644 index 270be05b4..000000000 --- a/features/theme-mod.feature +++ /dev/null @@ -1,69 +0,0 @@ -Feature: Manage WordPress theme mods - - Scenario: Getting theme mods - Given a WP install - - When I run `wp theme mod get --all` - Then STDOUT should be a table containing rows: - | key | value | - - When I try `wp theme mod get` - Then STDERR should contain: - """ - You must specify at least one mod or use --all. - """ - - When I run `wp theme mod set background_color 123456` - And I run `wp theme mod get --all` - Then STDOUT should be a table containing rows: - | key | value | - | background_color | 123456 | - - When I run `wp theme mod get background_color --field=value` - Then STDOUT should be: - """ - 123456 - """ - - When I run `wp theme mod set background_color 123456` - And I run `wp theme mod get background_color header_textcolor` - Then STDOUT should be a table containing rows: - | key | value | - | background_color | 123456 | - | header_textcolor | | - - Scenario: Setting theme mods - Given a WP install - - When I run `wp theme mod set background_color 123456` - Then STDOUT should be: - """ - Success: Theme mod background_color set to 123456. - """ - - Scenario: Removing theme mods - Given a WP install - - When I run `wp theme mod remove --all` - Then STDOUT should be: - """ - Success: Theme mods removed. - """ - - When I try `wp theme mod remove` - Then STDERR should contain: - """ - You must specify at least one mod or use --all. - """ - - When I run `wp theme mod remove background_color` - Then STDOUT should be: - """ - Success: 1 mod removed. - """ - - When I run `wp theme mod remove background_color header_textcolor` - Then STDOUT should be: - """ - Success: 2 mods removed. - """ diff --git a/features/theme.feature b/features/theme.feature deleted file mode 100644 index 60d0c6c90..000000000 --- a/features/theme.feature +++ /dev/null @@ -1,372 +0,0 @@ -Feature: Manage WordPress themes - - Scenario: Installing and deleting theme - Given a WP install - - When I run `wp theme install p2` - Then STDOUT should not be empty - - When I run `wp theme status p2` - Then STDOUT should contain: - """ - Theme p2 details: - Name: P2 - """ - - When I run `wp theme path p2` - Then STDOUT should contain: - """ - /themes/p2/style.css - """ - - When I run `wp option get stylesheet` - Then save STDOUT as {PREVIOUS_THEME} - - When I run `wp theme activate p2` - Then STDOUT should contain: - """ - Success: Switched to 'P2' theme. - """ - - When I try `wp theme delete p2` - Then STDERR should be: - """ - Warning: Can't delete the currently active theme: p2 - Error: No themes deleted. - """ - And STDOUT should be empty - - When I run `wp theme activate {PREVIOUS_THEME}` - Then STDOUT should not be empty - - When I run `wp theme delete p2` - Then STDOUT should not be empty - - When I try the previous command again - Then STDERR should contain: - """ - The 'p2' theme could not be found. - """ - - When I run `wp theme list` - Then STDOUT should not be empty - - Scenario: Checking theme status without theme parameter - Given a WP install - - When I run `wp theme install classic --activate` - And I run `wp theme list --field=name --status=inactive | xargs wp theme delete` - And I run `wp theme status` - Then STDOUT should be: - """ - 1 installed theme: - A classic 1.6 - - Legend: A = Active - """ - - Scenario: Install a theme, activate, then force install an older version of the theme - Given a WP install - - When I run `wp theme install p2 --version=1.4.2` - Then STDOUT should not be empty - - When I run `wp theme list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | p2 | inactive | available | 1.4.2 | - - When I run `wp theme activate p2` - Then STDOUT should not be empty - - When I run `wp theme install p2 --version=1.4.1 --force` - Then STDOUT should not be empty - - When I run `wp theme list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | p2 | active | available | 1.4.1 | - - When I try `wp theme update` - Then STDERR should be: - """ - Error: Please specify one or more themes, or use --all. - """ - - When I run `wp theme update --all --format=summary | grep 'updated successfully from'` - Then STDOUT should contain: - """ - P2 updated successfully from version 1.4.1 to version - """ - - Scenario: Get the path of an installed theme - Given a WP install - - When I run `wp theme install p2` - Then STDOUT should not be empty - - When I run `wp theme path p2 --dir` - Then STDOUT should contain: - """ - wp-content/themes/p2 - """ - - Scenario: Activate an already active theme - Given a WP install - - When I run `wp theme install p2` - Then STDOUT should not be empty - - When I run `wp theme activate p2` - Then STDOUT should be: - """ - Success: Switched to 'P2' theme. - """ - - When I try `wp theme activate p2` - Then STDERR should be: - """ - Warning: The 'P2' theme is already active. - """ - - Scenario: Install a theme when the theme directory doesn't yet exist - Given a WP install - - When I run `rm -rf wp-content/themes` - And I run `if test -d wp-content/themes; then echo "fail"; fi` - Then STDOUT should be empty - - When I run `wp theme install p2 --activate` - Then STDOUT should not be empty - - When I run `wp theme list --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | p2 | active | - - Scenario: Attempt to activate or fetch a broken theme - Given a WP install - - When I run `mkdir -pv wp-content/themes/myth` - Then the wp-content/themes/myth directory should exist - - When I try `wp theme activate myth` - Then STDERR should contain: - """ - Error: Stylesheet is missing. - """ - - When I try `wp theme get myth` - Then STDERR should contain: - """ - Error: Stylesheet is missing. - """ - - When I try `wp theme status myth` - Then STDERR should be: - """ - Error: Stylesheet is missing. - """ - - When I run `wp theme install myth --force` - Then STDOUT should contain: - """ - Theme updated successfully. - """ - - Scenario: Enabling and disabling a theme - Given a WP multisite install - And I run `wp theme install jolene` - And I run `wp theme install biker` - - When I try `wp option get allowedthemes` - Then the return code should be 1 - And STDERR should be empty - - When I run `wp theme enable biker` - Then STDOUT should contain: - """ - Success: Enabled the 'Biker' theme. - """ - - When I run `wp option get allowedthemes` - Then STDOUT should contain: - """ - 'biker' => true - """ - - When I run `wp theme disable biker` - Then STDOUT should contain: - """ - Success: Disabled the 'Biker' theme. - """ - - When I run `wp option get allowedthemes` - Then STDOUT should not contain: - """ - 'biker' => true - """ - - When I run `wp theme enable biker --activate` - Then STDOUT should contain: - """ - Success: Enabled the 'Biker' theme. - Success: Switched to 'Biker' theme. - """ - - When I run `wp network-meta get 1 allowedthemes` - Then STDOUT should not contain: - """ - 'biker' => true - """ - - When I run `wp theme enable biker --network` - Then STDOUT should contain: - """ - Success: Network enabled the 'Biker' theme. - """ - - When I run `wp network-meta get 1 allowedthemes` - Then STDOUT should contain: - """ - 'biker' => true - """ - - When I run `wp theme disable biker --network` - Then STDOUT should contain: - """ - Success: Network disabled the 'Biker' theme. - """ - - When I run `wp network-meta get 1 allowedthemes` - Then STDOUT should not contain: - """ - 'biker' => true - """ - - Scenario: Enabling and disabling a theme without multisite - Given a WP install - - When I try `wp theme enable p2` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - When I try `wp theme disable p2` - Then STDERR should be: - """ - Error: This is not a multisite install. - """ - - Scenario: Install a theme, then update to a specific version of that theme - Given a WP install - - When I run `wp theme install p2 --version=1.4.1` - Then STDOUT should not be empty - - When I run `wp theme update p2 --version=1.4.2` - Then STDOUT should not be empty - - When I run `wp theme list --fields=name,version` - Then STDOUT should be a table containing rows: - | name | version | - | p2 | 1.4.2 | - - Scenario: Install and attempt to activate a child theme without its parent - Given a WP install - And I run `wp theme install biker` - And I run `rm -rf wp-content/themes/jolene` - - When I try `wp theme activate biker` - Then STDERR should contain: - """ - Error: The parent theme is missing. Please install the "jolene" parent theme. - """ - - Scenario: List an active theme with its parent - Given a WP install - And I run `wp theme install jolene` - And I run `wp theme install --activate biker` - - When I run `wp theme list --fields=name,status` - Then STDOUT should be a table containing rows: - | name | status | - | biker | active | - | jolene | parent | - - Scenario: When updating a theme --format should be the same when using --dry-run - Given a WP install - - When I run `wp theme install --force twentytwelve --version=1.0` - Then STDOUT should not be empty - - When I run `wp theme list --name=twentytwelve --field=update_version` - And save STDOUT as {UPDATE_VERSION} - - When I run `wp theme update twentytwelve --format=summary --dry-run` - Then STDOUT should contain: - """ - Available theme updates: - Twenty Twelve update from version 1.0 to version {UPDATE_VERSION} - """ - - When I run `wp theme update twentytwelve --format=json --dry-run` - Then STDOUT should be JSON containing: - """ - [{"name":"twentytwelve","status":"inactive","version":"1.0","update_version":"{UPDATE_VERSION}"}] - """ - - When I run `wp theme update twentytwelve --format=csv --dry-run` - Then STDOUT should contain: - """ - name,status,version,update_version - twentytwelve,inactive,1.0,{UPDATE_VERSION} - """ - - Scenario: Check json and csv formats when updating a theme - Given a WP install - - When I run `wp theme install --force twentytwelve --version=1.0` - Then STDOUT should not be empty - - When I run `wp theme list --name=twentytwelve --field=update_version` - And save STDOUT as {UPDATE_VERSION} - - When I run `wp theme update twentytwelve --format=json` - Then STDOUT should contain: - """ - [{"name":"twentytwelve","old_version":"1.0","new_version":"{UPDATE_VERSION}","status":"Updated"}] - """ - - When I run `wp theme install --force twentytwelve --version=1.0` - Then STDOUT should not be empty - - When I run `wp theme update twentytwelve --format=csv` - Then STDOUT should contain: - """ - name,old_version,new_version,status - twentytwelve,1.0,{UPDATE_VERSION},Updated - """ - - Scenario: Automatically install parent theme for a child theme - Given a WP install - - When I try `wp theme status stargazer` - Then STDERR should contain: - """ - Error: The 'stargazer' theme could not be found. - """ - - When I run `wp theme install buntu` - Then STDOUT should contain: - """ - This theme requires a parent theme. Checking if it is installed - """ - - When I run `wp theme status stargazer` - Then STDOUT should contain: - """ - Theme stargazer details: - """ - And STDERR should be empty diff --git a/features/transient.feature b/features/transient.feature deleted file mode 100644 index 064d4d883..000000000 --- a/features/transient.feature +++ /dev/null @@ -1,85 +0,0 @@ -Feature: Manage WordPress transient cache - - Scenario: Transient CRUD - Given a WP install - - When I try `wp transient get foo` - Then STDERR should be: - """ - Warning: Transient with key "foo" is not set. - """ - - When I run `wp transient set foo bar` - Then STDOUT should be: - """ - Success: Transient added. - """ - - When I run `wp transient get foo` - Then STDOUT should be: - """ - bar - """ - - When I run `wp transient delete foo` - Then STDOUT should be: - """ - Success: Transient deleted. - """ - - Scenario: Network transient CRUD - Given a WP multisite install - And I run `wp site create --slug=foo` - - When I run `wp transient set foo bar --network` - Then STDOUT should be: - """ - Success: Transient added. - """ - - When I run `wp --url=example.com/foo transient get foo --network` - Then STDOUT should be: - """ - bar - """ - - When I try `wp transient get foo` - Then STDERR should be: - """ - Warning: Transient with key "foo" is not set. - """ - - When I run `wp transient delete foo --network` - Then STDOUT should be: - """ - Success: Transient deleted. - """ - - Scenario: Transient delete and other flags - Given a WP install - - When I try `wp transient delete` - Then STDERR should be: - """ - Error: Please specify transient key, or use --all or --expired. - """ - - When I run `wp transient set foo bar` - And I run `wp transient set foo2 bar2` - And I run `wp transient delete --all` - Then STDOUT should contain: - """ - transients deleted from the database. - """ - - When I try `wp transient get foo` - Then STDERR should be: - """ - Warning: Transient with key "foo" is not set. - """ - - When I try `wp transient get foo2` - Then STDERR should be: - """ - Warning: Transient with key "foo2" is not set. - """ diff --git a/features/upgradables.feature b/features/upgradables.feature deleted file mode 100644 index e0caaa1df..000000000 --- a/features/upgradables.feature +++ /dev/null @@ -1,187 +0,0 @@ -Feature: Manage WordPress themes and plugins - - Background: - Given an empty cache - - Scenario Outline: Installing, upgrading and deleting a theme or plugin - Given a WP install - And I run `wp <type> path` - And save STDOUT as {CONTENT_DIR} - - When I try `wp <type> is-installed <item>` - Then the return code should be 1 - And STDERR should be empty - - When I try `wp <type> get <item>` - Then the return code should be 1 - And STDERR should not be empty - - # Install an out of date <item> from WordPress.org repository - When I run `wp <type> install <item> --version=<version>` - Then STDOUT should contain: - """ - <type_name> installed successfully - """ - And the {SUITE_CACHE_DIR}/<type>/<item>-<version>.zip file should exist - - When I try `wp <type> is-installed <item>` - Then the return code should be 0 - - When I run `wp <type> get <item>` - Then STDOUT should be a table containing rows: - | Field | Value | - | title | <item_title> | - - When I run `wp <type> get <item> --field=title` - Then STDOUT should contain: - """ - <item_title> - """ - - When I run `wp <type> get <item> --field=title --format=json` - Then STDOUT should contain: - """ - "<item_title>" - """ - - When I run `wp <type> list` - Then STDOUT should be a table containing rows: - | name | status | update | version | - | <item> | inactive | available | <version> | - - When I run `wp <type> list --field=name` - Then STDOUT should contain: - """ - <item> - """ - - When I run `wp <type> list --field=name --format=json` - Then STDOUT should be a JSON array containing: - """ - ["<item>"] - """ - - When I run `wp <type> status` - Then STDOUT should contain: - """ - U = Update Available - """ - - When I run `wp <type> status <item>` - Then STDOUT should contain: - """ - Status: Inactive - Version: <version> (Update available) - """ - - When I run `wp <type> update <item>` - And save STDOUT 'Downloading update from .*\/<item>\.%s\.zip' as {NEW_VERSION} - And STDOUT should not be empty - Then STDOUT should not contain: - """ - Error - """ - And the {SUITE_CACHE_DIR}/<type>/<item>-{NEW_VERSION}.zip file should exist - - When I run `wp <type> update --all` - Then STDOUT should not be empty - - When I run `wp <type> status <item>` - Then STDOUT should not contain: - """ - (Update available) - """ - - When I run `wp <type> delete <item>` - Then STDOUT should contain: - """ - Deleted '<item>' <type>. - """ - - When I try `wp <type> status <item>` - Then the return code should be 1 - And STDERR should not be empty - - - # Install and update <item> from cache - When I run `wp <type> install <item> --version=<version>` - Then STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/<type>/<item>-<version>.zip'... - """ - - When I run `wp <type> update <item>` - Then STDOUT should contain: - """ - Using cached file '{SUITE_CACHE_DIR}/<type>/<item>-{NEW_VERSION}.zip'... - """ - - When I run `wp <type> delete <item>` - Then STDOUT should contain: - """ - Deleted '<item>' <type>. - """ - And the <file_to_check> file should not exist - - - # Install <item> from a local zip file - When I run `wp <type> install {SUITE_CACHE_DIR}/<type>/<item>-<version>.zip` - Then STDOUT should contain: - """ - <type_name> installed successfully. - """ - And the <file_to_check> file should exist - - When I run `wp <type> delete <item>` - Then STDOUT should contain: - """ - Deleted '<item>' <type>. - """ - And the <file_to_check> file should not exist - - # Install <item> from a remote zip file (standard URL with no GET parameters) - When I run `wp <type> install <zip_file>` - Then STDOUT should contain: - """ - <type_name> installed successfully. - """ - And the <file_to_check> file should exist - - When I run `wp <type> delete <item>` - Then STDOUT should contain: - """ - Deleted '<item>' <type>. - """ - And the <file_to_check> file should not exist - - # Install <item> from a remote zip file (complex URL with GET parameters) - When I run `wp <type> install '<zip_file>?AWSAccessKeyId=123&Expires=456&Signature=abcdef'` - Then STDOUT should contain: - """ - <type_name> installed successfully. - """ - And the <file_to_check> file should exist - - When I run `wp <type> delete <item>` - Then STDOUT should contain: - """ - Deleted '<item>' <type>. - """ - And the <file_to_check> file should not exist - - When I run `wp <type> search <item> --per-page=2 --fields=name,slug` - Then STDOUT should contain: - """ - Showing 2 of - """ - - When I try `wp <type> install an-impossible-slug-because-abc3fr` - Then STDERR should contain: - """ - Warning: Couldn't find 'an-impossible-slug-because-abc3fr' in the WordPress.org <type> directory. - """ - - Examples: - | type | type_name | item | item_title | version | zip_file | file_to_check | - | theme | Theme | p2 | P2 | 1.0.1 | https://wordpress.org/themes/download/p2.1.0.1.zip | {CONTENT_DIR}/p2/style.css | - | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | https://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | diff --git a/features/user-generate.feature b/features/user-generate.feature deleted file mode 100644 index cbe263b3c..000000000 --- a/features/user-generate.feature +++ /dev/null @@ -1,35 +0,0 @@ -Feature: Generate WP users - - Background: - Given a WP install - - Scenario: Generating and deleting users - When I run `wp user list --role=editor --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp user generate --count=10 --role=editor` - And I run `wp user list --role=editor --format=count` - Then STDOUT should be: - """ - 10 - """ - - When I try `wp user list --field=ID | xargs wp user delete invalid-user --yes` - And I run `wp user list --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Generating users and outputting ids - When I run `wp user generate --count=1 --format=ids` - Then save STDOUT as {USER_ID} - - When I run `wp user update {USER_ID} --display_name="foo"` - Then STDOUT should contain: - """ - Success: - """ diff --git a/features/user-import-csv.feature b/features/user-import-csv.feature deleted file mode 100644 index 990d29243..000000000 --- a/features/user-import-csv.feature +++ /dev/null @@ -1,134 +0,0 @@ -Feature: Import users from CSV - - Scenario: Importing users from a CSV file - Given a WP install - And a users.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - newuser1,newuser1@example.com,New User,author - admin,admin@example.com,Existing User,administrator - """ - - When I try `wp user import-csv users-incorrect.csv --skip-update` - Then STDERR should be: - """ - Error: Missing file: users-incorrect.csv - """ - - When I run `wp user import-csv users.csv` - Then STDOUT should not be empty - - When I run `wp user list --format=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp user list --format=json` - Then STDOUT should be JSON containing: - """ - [{ - "user_login":"admin", - "display_name":"Existing User", - "user_email":"admin@example.com", - "roles":"administrator" - }] - """ - - Scenario: Import new users on multisite - Given a WP multisite install - And a user-invalid.csv file: - """ - user_login,user_email,display_name,role - bob-jones,bobjones@example.com,Bob Jones,contributor - """ - And a user-valid.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - """ - - When I try `wp user import-csv user-invalid.csv` - Then STDERR should contain: - """ - lowercase letters (a-z) and numbers - """ - - When I run `wp user import-csv user-valid.csv` - Then STDOUT should not be empty - - When I run `wp user get bobjones --field=display_name` - Then STDOUT should be: - """ - Bob Jones - """ - - Scenario: Import new users but don't update existing - Given a WP install - And a users.csv file: - """ - user_login,user_email,display_name,role - bobjones,bobjones@example.com,Bob Jones,contributor - newuser1,newuser1@example.com,New User,author - admin,admin@example.com,Existing User,administrator - """ - - When I run `wp user create bobjones bobjones@example.com --display_name="Robert Jones" --role=administrator` - Then STDOUT should not be empty - - When I run `wp user import-csv users.csv --skip-update` - Then STDOUT should not be empty - - When I run `wp user list --format=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp user get bobjones --fields=user_login,display_name,user_email,roles --format=json` - Then STDOUT should be JSON containing: - """ - { - "user_login":"bobjones", - "display_name":"Robert Jones", - "user_email":"bobjones@example.com", - "roles":"administrator" - } - """ - - Scenario: Import users from a CSV file generated by `wp user list` - Given a WP install - - When I run `wp user delete 1 --yes` - And I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones" --role=contributor` - And I run `wp user create billjones billjones@example.com --display_name="Bill Jones" --role=administrator` - And I run `wp user add-role billjones author` - Then STDOUT should not be empty - - When I run `wp user list --field=user_login | wc -l` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp user list --format=csv > users.csv` - Then the users.csv file should exist - - When I run `wp user delete $(wp user list --format=ids) --yes` - Then STDOUT should not be empty - - When I run `wp user list --field=user_login | wc -l` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp user import-csv users.csv` - Then STDOUT should not be empty - - When I run `wp user list --fields=display_name,roles` - Then STDOUT should be a table containing rows: - | display_name | roles | - | Bob Jones | contributor | - | Bill Jones | administrator,author | diff --git a/features/user-list.feature b/features/user-list.feature deleted file mode 100644 index 44856eb01..000000000 --- a/features/user-list.feature +++ /dev/null @@ -1,28 +0,0 @@ -Feature: List WordPress users - - @require-wp-4.4 - Scenario: List users of specific roles - Given a WP install - And I run `wp user create bobjones bob@example.com --role=author` - And I run `wp user create sally sally@example.com --role=editor` - - When I run `wp user list --field=user_login` - Then STDOUT should be: - """ - admin - bobjones - sally - """ - - When I run `wp user list --role__in=administrator,editor --field=user_login` - Then STDOUT should be: - """ - admin - sally - """ - - When I run `wp user list --role__not_in=administrator,editor --field=user_login` - Then STDOUT should be: - """ - bobjones - """ diff --git a/features/user-meta.feature b/features/user-meta.feature deleted file mode 100644 index 4a8901ab4..000000000 --- a/features/user-meta.feature +++ /dev/null @@ -1,77 +0,0 @@ -Feature: Manage user custom fields - - Scenario: Usermeta CRUD - Given a WP install - - When I run `wp user-meta add 1 foo 'bar'` - Then STDOUT should not be empty - - When I run `wp user-meta get 1 foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp user-meta get 2 foo` - Then STDERR should be: - """ - Error: Invalid user ID, email or login: '2' - """ - - When I run `wp user-meta set admin foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run `wp user-meta get admin foo --format=json` - Then STDOUT should be: - """ - ["1","2"] - """ - - When I run `wp user-meta delete 1 foo` - Then STDOUT should not be empty - - When I try `wp user-meta get 1 foo` - Then the return code should be 1 - - When I run `wp user meta add 1 foo bar` - And I run `wp user meta add 1 foo bar2` - And I run `wp user meta add 1 foo bar3` - Then STDOUT should not be empty - - When I run `wp user meta delete 1 foo bar2` - And I run `wp user meta list 1 --keys=foo --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp user meta delete 1 foo` - And I run `wp user meta list 1 --keys=foo --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: List user meta - Given a WP install - - When I run `wp user meta set 1 foo '[ "1", "2" ]' --format=json` - Then STDOUT should not be empty - - When I run `wp user meta list 1 --format=json --keys=nickname,foo --fields=meta_key,meta_value` - Then STDOUT should be JSON containing: - """ - [{"meta_key":"nickname","meta_value":"admin"},{"meta_key":"foo","meta_value":["1","2"]}] - """ - - When I run `wp user meta list 1 --keys=nickname,foo` - Then STDOUT should be a table containing rows: - | user_id | meta_key | meta_value | - | 1 | nickname | admin | - | 1 | foo | ["1","2"] | - - When I run `wp user meta list admin --keys=nickname,foo` - Then STDOUT should be a table containing rows: - | user_id | meta_key | meta_value | - | 1 | nickname | admin | - | 1 | foo | ["1","2"] | diff --git a/features/user-session.feature b/features/user-session.feature deleted file mode 100644 index c4a576eb2..000000000 --- a/features/user-session.feature +++ /dev/null @@ -1,40 +0,0 @@ -Feature: Manage user session - - Background: - Given a WP install - - @require-wp-4.0 - Scenario: Destroy user sessions - When I run `wp eval 'wp_set_current_user(1);'` - And I run `wp eval 'wp_set_auth_cookie(1);'` - And I run `wp eval 'wp_set_current_user(1);'` - And I run `wp eval 'wp_set_auth_cookie(1);'` - And I run `wp user session list admin --format=count` - Then STDOUT should be: - """ - 2 - """ - - When I run `wp user session destroy admin` - Then STDOUT should be: - """ - Success: Destroyed session. 1 remaining. - """ - - When I run `wp user session list admin --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp user session destroy admin --all` - Then STDOUT should be: - """ - Success: Destroyed all sessions. - """ - - And I run `wp user session list admin --format=count` - Then STDOUT should be: - """ - 0 - """ diff --git a/features/user-term.feature b/features/user-term.feature deleted file mode 100644 index c5c81939c..000000000 --- a/features/user-term.feature +++ /dev/null @@ -1,115 +0,0 @@ -Feature: Manage user term - - Scenario: Userterm CRUD - Given a WP install - And a wp-content/plugins/test-add-tax/plugin.php file: - """ - <?php - // Plugin Name: Test Add Tax - - function add_cli_tax(){ - register_taxonomy( 'user_type', 'user' ); - } - - add_action('init','add_cli_tax'); - """ - And I run `wp plugin activate test-add-tax` - - - When I run `wp user term add 1 user_type foo` - Then STDOUT should be: - """ - Success: Added term. - """ - - When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | foo | foo | user_type | - - When I run `wp user term add 1 user_type bar` - Then STDOUT should be: - """ - Success: Added term. - """ - - When I run `wp user term list 1 user_type --fields=name,slug,taxonomy` - Then STDOUT should be a table containing rows: - | name | slug | taxonomy | - | foo | foo | user_type | - | bar | bar | user_type | - - When I run `wp user term list 1 user_type --format=ids` - Then STDOUT should be: - """ - 3 2 - """ - - When I run `wp user term set 1 user_type new` - Then STDOUT should be: - """ - Success: Set terms. - """ - - When I run `wp user term list 1 user_type --fields=name,slug,taxonomy --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp user term remove 1 user_type new` - Then STDOUT should be: - """ - Success: Deleted term. - """ - - When I run `wp user term list 1 user_type --fields=name,slug,taxonomy --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Multiple user term - Given a WP install - - And a wp-content/plugins/test-add-tax/plugin.php file: - """ - <?php - // Plugin Name: Test Add Tax - - function add_cli_tax(){ - register_taxonomy( 'user_type', 'user' ); - } - - add_action('init','add_cli_tax'); - """ - And I run `wp plugin activate test-add-tax` - - When I run `wp user term add 1 user_type apple` - And I run `wp user term add 1 user_type apple` - Then STDOUT should contain: - """ - Success: Added term. - """ - - When I run `wp user term set 1 user_type apple1 apple2` - Then STDOUT should contain: - """ - Success: Set terms. - """ - - When I run `wp user term list 1 user_type --format=json --fields=name,slug,taxonomy` - Then STDOUT should contain: - """ - [{"name":"apple1","slug":"apple1","taxonomy":"user_type"},{"name":"apple2","slug":"apple2","taxonomy":"user_type"}] - """ - - Scenario: Userterm Add invalid tax - Given a WP install - - When I try `wp user term add 1 boo foo2` - Then the return code should be 1 - And STDERR should be: - """ - Error: Invalid taxonomy boo. - """ \ No newline at end of file diff --git a/features/user.feature b/features/user.feature deleted file mode 100644 index be744c1b8..000000000 --- a/features/user.feature +++ /dev/null @@ -1,308 +0,0 @@ -Feature: Manage WordPress users - - Scenario: User CRUD operations - Given a WP install - - When I try `wp user get bogus-user` - Then the return code should be 1 - And STDOUT should be empty - - When I run `wp user create testuser2 testuser2@example.com --first_name=test --last_name=user --role=author --porcelain` - Then STDOUT should be a number - And save STDOUT as {USER_ID} - - When I run `wp user get {USER_ID}` - Then STDOUT should be a table containing rows: - | Field | Value | - | ID | {USER_ID} | - | roles | author | - - When I run `wp user meta get {USER_ID} first_name` - Then STDOUT should be: - """ - test - """ - - When I run `wp user list --fields=user_login,roles` - Then STDOUT should be a table containing rows: - | user_login | roles | - | testuser2 | author | - - When I run `wp user meta get {USER_ID} last_name` - Then STDOUT should be: - """ - user - """ - - When I run `wp user delete {USER_ID} --yes` - Then STDOUT should not be empty - - When I try `wp user create testuser2 testuser2@example.com --role=wrongrole --porcelain` - Then the return code should be 1 - Then STDOUT should be empty - - When I run `wp user create testuser testuser@example.com --porcelain` - Then STDOUT should be a number - And save STDOUT as {USER_ID} - - When I try the previous command again - Then the return code should be 1 - - When I run `wp user update {USER_ID} --display_name=Foo` - And I run `wp user get {USER_ID}` - Then STDOUT should be a table containing rows: - | Field | Value | - | ID | {USER_ID} | - | display_name | Foo | - - When I run `wp user get testuser@example.com` - Then STDOUT should be a table containing rows: - | Field | Value | - | ID | {USER_ID} | - | display_name | Foo | - - When I run `wp user delete {USER_ID} --yes` - Then STDOUT should not be empty - - Scenario: Reassigning user posts - Given a WP multisite install - - When I run `wp user create bobjones bob@example.com --role=author --porcelain` - And save STDOUT as {BOB_ID} - - And I run `wp user create sally sally@example.com --role=editor --porcelain` - And save STDOUT as {SALLY_ID} - - When I run `wp post generate --count=3 --post_author=bobjones` - And I run `wp post list --author={BOB_ID} --format=count` - Then STDOUT should be: - """ - 3 - """ - - When I run `wp user delete bobjones --reassign={SALLY_ID}` - And I run `wp post list --author={SALLY_ID} --format=count` - Then STDOUT should be: - """ - 3 - """ - - Scenario: Deleting user from the whole network - Given a WP multisite install - - When I run `wp user create bobjones bob@example.com --role=author --porcelain` - And save STDOUT as {BOB_ID} - - When I run `wp user get bobjones` - Then STDOUT should not be empty - - When I run `wp user delete bobjones --network --yes` - Then STDOUT should not be empty - - When I try `wp user get bobjones` - Then STDERR should not be empty - - Scenario: Create new users on multisite - Given a WP multisite install - - When I try `wp user create bob-jones bobjones@example.com` - Then STDERR should contain: - """ - lowercase letters (a-z) and numbers - """ - - When I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones"` - Then STDOUT should not be empty - - When I run `wp user get bobjones --field=display_name` - Then STDOUT should be: - """ - Bob Jones - """ - - Scenario: Managing user roles - Given a WP install - - When I run `wp user add-role 1 editor` - Then STDOUT should not be empty - And I run `wp user get 1 --field=roles` - Then STDOUT should be: - """ - administrator, editor - """ - - When I try `wp user add-role 1 edit` - Then STDERR should contain: - """ - Role doesn't exist - """ - - When I try `wp user set-role 1 edit` - Then STDERR should contain: - """ - Role doesn't exist - """ - - When I try `wp user remove-role 1 edit` - Then STDERR should contain: - """ - Role doesn't exist - """ - - When I run `wp user set-role 1 author` - Then STDOUT should not be empty - And I run `wp user get 1` - Then STDOUT should be a table containing rows: - | Field | Value | - | roles | author | - - When I run `wp user remove-role 1 editor` - Then STDOUT should not be empty - And I run `wp user get 1` - Then STDOUT should be a table containing rows: - | Field | Value | - | roles | author | - - When I run `wp user remove-role 1` - Then STDOUT should not be empty - And I run `wp user get 1` - Then STDOUT should be a table containing rows: - | Field | Value | - | roles | | - - Scenario: Managing user capabilities - Given a WP install - - When I run `wp user add-cap 1 edit_vip_product` - Then STDOUT should be: - """ - Success: Added 'edit_vip_product' capability for admin (1). - """ - - And I run `wp user list-caps 1 | tail -n 1` - Then STDOUT should be: - """ - edit_vip_product - """ - - And I run `wp user remove-cap 1 edit_vip_product` - Then STDOUT should be: - """ - Success: Removed 'edit_vip_product' cap for admin (1). - """ - - Scenario: Show password when creating a user - Given a WP install - - When I run `wp user create testrandompass testrandompass@example.com` - Then STDOUT should contain: - """ - Password: - """ - - When I run `wp user create testsuppliedpass testsuppliedpass@example.com --user_pass=suppliedpass` - Then STDOUT should not contain: - """ - Password: - """ - - Scenario: List network users - Given a WP multisite install - - When I run `wp user create testsubscriber testsubscriber@example.com` - Then STDOUT should contain: - """ - Success: Created user - """ - - When I run `wp user list --field=user_login` - Then STDOUT should contain: - """ - testsubscriber - """ - - When I run `wp user delete testsubscriber --yes` - Then STDOUT should contain: - """ - Success: Removed user - """ - - When I run `wp user list --field=user_login` - Then STDOUT should not contain: - """ - testsubscriber - """ - - When I run `wp user list --field=user_login --network` - Then STDOUT should contain: - """ - testsubscriber - """ - - Scenario: Listing user capabilities - Given a WP install - - When I run `wp user create bob bob@gmail.com --role=contributor` - And I run `wp user list-caps bob` - Then STDOUT should be: - """ - edit_posts - read - level_1 - level_0 - delete_posts - contributor - """ - - And I run `wp user list-caps bob --format=json` - Then STDOUT should be: - """ - [{"name":"edit_posts"},{"name":"read"},{"name":"level_1"},{"name":"level_0"},{"name":"delete_posts"},{"name":"contributor"}] - """ - - And I run `wp user list-caps bob --format=count` - Then STDOUT should be: - """ - 6 - """ - - Scenario: Make sure WordPress receives the slashed data it expects - Given a WP install - - When I run `wp user create slasheduser slasheduser@example.com --display_name='My\User' --porcelain` - Then save STDOUT as {USER_ID} - - When I run `wp user get {USER_ID} --field=display_name` - Then STDOUT should be: - """ - My\User - """ - - When I run `wp user update {USER_ID} --display_name='My\New\User'` - Then STDOUT should not be empty - - When I run `wp user get {USER_ID} --field=display_name` - Then STDOUT should be: - """ - My\New\User - """ - - Scenario: Don't send user creation emails by default - Given a WP multisite install - - When I run `wp user create testuser2 testuser2@example.com` - Then an email should not be sent - - When I run `wp user create testuser3 testuser3@example.com --send-email` - Then an email should be sent - - Scenario: List URLs of one or more users - Given a WP install - And I run `wp user create bob bob@gmail.com --role=contributor` - - When I run `wp user list --include=1,2 --field=url` - Then STDOUT should be: - """ - http://example.com/?author=1 - http://example.com/?author=2 - """ diff --git a/features/validation.feature b/features/validation.feature deleted file mode 100644 index a43178764..000000000 --- a/features/validation.feature +++ /dev/null @@ -1,48 +0,0 @@ -Feature: Argument validation - In order to catch errors fast - As a user - I need to see warnings and errors when I pass incorrect arguments - - Scenario: Passing zero arguments to a variadic command - Given a WP install - - When I try `wp plugin install` - Then the return code should be 1 - Then STDOUT should contain: - """ - usage: wp plugin install - """ - - Scenario: Validation for early commands - Given an empty directory - And WP files - - When I try `wp core config` - Then the return code should be 1 - And STDERR should contain: - """ - Parameter errors: - """ - And STDERR should contain: - """ - missing --dbname parameter - """ - - When I try `wp core config --invalid --other-invalid` - Then the return code should be 1 - And STDERR should contain: - """ - unknown --invalid parameter - """ - And STDERR should contain: - """ - unknown --other-invalid parameter - """ - - When I try `wp core version invalid` - Then the return code should be 1 - And STDERR should contain: - """ - Error: Too many positional arguments: invalid - """ - And STDOUT should be empty diff --git a/features/widget-reset.feature b/features/widget-reset.feature deleted file mode 100644 index f102ee377..000000000 --- a/features/widget-reset.feature +++ /dev/null @@ -1,155 +0,0 @@ -Feature: Reset WordPress sidebars - - Scenario: Reset sidebar - Given a WP install - - When I run `wp theme install twentytwelve --activate` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-1 --format=count` - Then STDOUT should be: - """ - 6 - """ - - When I run `wp widget reset sidebar-1` - And I run `wp widget list sidebar-1 --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I try `wp widget reset` - Then STDERR should be: - """ - Error: Please specify one or more sidebars, or use --all. - """ - - When I try `wp widget reset sidebar-1` - Then STDERR should be: - """ - Warning: Sidebar 'sidebar-1' is already empty. - """ - And STDOUT should be: - """ - Success: Sidebar already reset. - """ - And the return code should be 0 - - When I try `wp widget reset non-existing-sidebar-id` - Then STDERR should be: - """ - Warning: Invalid sidebar: non-existing-sidebar-id - Error: No sidebars reset. - """ - And the return code should be 1 - - When I run `wp widget add calendar sidebar-1 --title="Calendar"` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-1 --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I run `wp widget add search sidebar-2 --title="Quick Search"` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-2 --format=count` - Then STDOUT should be: - """ - 1 - """ - - When I try `wp widget reset sidebar-1 sidebar-2 non-existing-sidebar-id` - Then STDERR should be: - """ - Warning: Invalid sidebar: non-existing-sidebar-id - Error: Only reset 2 of 3 sidebars. - """ - And the return code should be 1 - - When I run `wp widget list sidebar-1 --format=count` - Then STDOUT should be: - """ - 0 - """ - - When I run `wp widget list sidebar-2 --format=count` - Then STDOUT should be: - """ - 0 - """ - - Scenario: Reset all sidebars - Given a WP install - - When I run `wp theme install twentytwelve --activate` - Then STDOUT should not be empty - - When I run `wp widget add calendar sidebar-1 --title="Calendar"` - Then STDOUT should not be empty - When I run `wp widget add search sidebar-2 --title="Quick Search"` - Then STDOUT should not be empty - When I run `wp widget add text sidebar-3 --title="Text"` - Then STDOUT should not be empty - - When I run `wp widget reset --all` - Then STDOUT should be: - """ - Sidebar 'sidebar-1' reset. - Sidebar 'sidebar-2' reset. - Sidebar 'sidebar-3' reset. - Success: Reset 3 of 3 sidebars. - """ - And the return code should be 0 - - When I run `wp widget list sidebar-1 --format=count` - Then STDOUT should be: - """ - 0 - """ - And I run `wp widget list sidebar-2 --format=count` - Then STDOUT should be: - """ - 0 - """ - And I run `wp widget list sidebar-3 --format=count` - Then STDOUT should be: - """ - 0 - """ - When I run `wp widget list wp_inactive_widgets --format=ids` - Then STDOUT should be: - """ - text-1 search-3 meta-2 categories-2 archives-2 recent-comments-2 recent-posts-2 search-2 calendar-1 - """ - - Scenario: Testing movement of widgets while reset - Given a WP install - - When I run `wp theme install twentytwelve --activate` - Then STDOUT should not be empty - - When I run `wp widget add calendar sidebar-2 --title="Calendar"` - Then STDOUT should not be empty - And I run `wp widget add search sidebar-2 --title="Quick Search"` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-2 --format=ids` - Then STDOUT should be: - """ - search-3 calendar-1 - """ - When I run `wp widget list wp_inactive_widgets --format=ids` - Then STDOUT should be empty - - When I run `wp widget reset sidebar-2` - And I run `wp widget list sidebar-2 --format=ids` - Then STDOUT should be empty - And I run `wp widget list wp_inactive_widgets --format=ids` - Then STDOUT should be: - """ - calendar-1 search-3 - """ diff --git a/features/widget.feature b/features/widget.feature deleted file mode 100644 index 4fbffa83a..000000000 --- a/features/widget.feature +++ /dev/null @@ -1,176 +0,0 @@ -Feature: Manage widgets in WordPress sidebar - - Background: - Given a WP install - When I run `wp theme install p2 --activate` - Then STDOUT should not be empty - - Scenario: Widget CRUD - When I run `wp widget list sidebar-1 --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | search | search-2 | 1 | - | recent-posts | recent-posts-2 | 2 | - | recent-comments | recent-comments-2 | 3 | - | archives | archives-2 | 4 | - | categories | categories-2 | 5 | - | meta | meta-2 | 6 | - - When I run `wp widget move recent-comments-2 --position=2` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-1 --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | search | search-2 | 1 | - | recent-comments | recent-comments-2 | 2 | - | recent-posts | recent-posts-2 | 3 | - | archives | archives-2 | 4 | - | categories | categories-2 | 5 | - | meta | meta-2 | 6 | - - When I run `wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets` - Then STDOUT should not be empty - - When I run `wp widget deactivate meta-2` - Then STDOUT should be: - """ - Success: Deactivated 1 of 1 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp widget list sidebar-1 --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | search | search-2 | 1 | - | recent-posts | recent-posts-2 | 2 | - | archives | archives-2 | 3 | - | categories | categories-2 | 4 | - - When I run `wp widget list wp_inactive_widgets --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | meta | meta-2 | 1 | - | recent-comments | recent-comments-2 | 2 | - - When I run `wp widget delete archives-2 recent-posts-2` - Then STDOUT should be: - """ - Success: Deleted 2 of 2 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp widget list sidebar-1 --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | search | search-2 | 1 | - | categories | categories-2 | 2 | - - When I run `wp widget add calendar sidebar-1 2` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-1 --fields=name,id,position` - Then STDOUT should be a table containing rows: - | name | id | position | - | search | search-2 | 1 | - | calendar | calendar-1 | 2 | - | categories | categories-2 | 3 | - - When I run `wp widget list sidebar-1 --format=ids` - Then STDOUT should be: - """ - search-2 calendar-1 categories-2 - """ - - When I run `wp widget update calendar-1 --title="Calendar"` - Then STDOUT should not be empty - - When I run `wp widget list sidebar-1 --fields=name,position,options` - Then STDOUT should be a table containing rows: - | name | position | options | - | calendar | 2 | {"title":"Calendar"} | - - Scenario: Validate sidebar widgets - When I try `wp widget update calendar-999` - Then STDERR should be: - """ - Error: Widget doesn't exist. - """ - And the return code should be 1 - - When I try `wp widget move calendar-999` - Then STDERR should be: - """ - Error: Widget doesn't exist. - """ - And the return code should be 1 - - Scenario: Return code is 0 when all widgets exist, deactivation - When I run `wp widget deactivate recent-posts-2` - Then STDOUT should be: - """ - Success: Deactivated 1 of 1 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp widget deactivate search-2 archives-2` - Then STDOUT should be: - """ - Success: Deactivated 2 of 2 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - Scenario: Return code is 0 when all widgets exist, deletion - When I run `wp widget delete recent-posts-2` - Then STDOUT should be: - """ - Success: Deleted 1 of 1 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - When I run `wp widget delete search-2 archives-2` - Then STDOUT should be: - """ - Success: Deleted 2 of 2 widgets. - """ - And STDERR should be empty - And the return code should be 0 - - Scenario: Return code is 1 when 1 or more widgets doesn't exist, deactivation - When I try `wp widget deactivate calendar-999` - Then STDERR should be: - """ - Warning: Widget 'calendar-999' doesn't exist. - Error: No widgets deactivated. - """ - And the return code should be 1 - - When I try `wp widget deactivate recent-posts-2 calendar-999` - Then STDERR should be: - """ - Warning: Widget 'calendar-999' doesn't exist. - Error: Only deactivated 1 of 2 widgets. - """ - And the return code should be 1 - - Scenario: Return code is 1 when 1 or more widgets doesn't exist, deletion - When I try `wp widget delete calendar-999` - Then STDERR should be: - """ - Warning: Widget 'calendar-999' doesn't exist. - Error: No widgets deleted. - """ - And the return code should be 1 - - When I try `wp widget delete recent-posts-2 calendar-999` - Then STDERR should be: - """ - Warning: Widget 'calendar-999' doesn't exist. - Error: Only deleted 1 of 2 widgets. - """ - And the return code should be 1 diff --git a/php/WP_CLI/CommandWithDBObject.php b/php/WP_CLI/CommandWithDBObject.php deleted file mode 100644 index f8655a287..000000000 --- a/php/WP_CLI/CommandWithDBObject.php +++ /dev/null @@ -1,193 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Base class for WP-CLI commands that deal with database objects. - * - * @package wp-cli - */ -abstract class CommandWithDBObject extends \WP_CLI_Command { - - /** - * @var string $object_type WordPress' expected name for the object. - */ - protected $obj_type; - - /** - * @var string $obj_id_key Key representing object's PK field in db. - */ - protected $obj_id_key = 'ID'; - - /** - * @var array $obj_fields Default fields to display for each object. - */ - protected $obj_fields = null; - - /** - * Create a given database object. - * Exits with status. - * - * @param array $args Arguments passed to command. Generally unused. - * @param array $assoc_args Parameters passed to command to be passed to callback. - * @param string $callback Function used to create object. - */ - protected function _create( $args, $assoc_args, $callback ) { - unset( $assoc_args[ $this->obj_id_key ] ); - - $obj_id = $callback( $assoc_args ); - - if ( is_wp_error( $obj_id ) ) { - \WP_CLI::error( $obj_id ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) - \WP_CLI::line( $obj_id ); - else - \WP_CLI::success( "Created $this->obj_type $obj_id." ); - } - - /** - * Update a given database object. - * Exits with status. - * - * @param array $args Collection of one or more object ids to update. - * @param array $assoc_args Fields => values to update on each object. - * @param string $callback Function used to update object. - */ - protected function _update( $args, $assoc_args, $callback ) { - $status = 0; - - if ( empty( $assoc_args ) ) { - \WP_CLI::error( "Need some fields to update." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( true ); - } - - foreach ( $args as $obj_id ) { - $params = array_merge( $assoc_args, array( $this->obj_id_key => $obj_id ) ); - - $status = $this->success_or_failure( $this->wp_error_to_resp( - $callback( $params ), - "Updated $this->obj_type $obj_id." - ) ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( false ); - } - - exit( $status ); - } - - /** - * Transforms arguments with '__' from CSV into expected arrays - * - * @param array $assoc_args - * @return array - */ - protected static function process_csv_arguments_to_arrays( $assoc_args ) { - foreach( $assoc_args as $k => $v ) { - if ( false !== strpos( $k, '__' ) ) { - $assoc_args[ $k ] = explode( ',', $v ); - } - } - return $assoc_args; - } - - /** - * Delete a given database object. - * Exits with status. - * - * @param array $args Collection of one or more object ids to delete. - * @param array $assoc_args Any arguments needed for the callback function. - * @param string $callback Function used to delete object. - */ - protected function _delete( $args, $assoc_args, $callback ) { - $status = 0; - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( true ); - } - - foreach ( $args as $obj_id ) { - $r = $callback( $obj_id, $assoc_args ); - $status = $this->success_or_failure( $r ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'defer-term-counting' ) ) { - wp_defer_term_counting( false ); - } - - exit( $status ); - } - - /** - * Format callback response to consistent format. - * - * @param WP_Error|true $r Response from CRUD callback. - * @param string $success_msg - * @return array - */ - protected function wp_error_to_resp( $r, $success_msg ) { - if ( is_wp_error( $r ) ) - return array( 'error', $r->get_error_message() ); - else - return array( 'success', $success_msg ); - } - - /** - * Display success or warning based on response; return proper exit code. - * - * @param array $r Formatted from a CRUD callback. - * @return int $status - */ - protected function success_or_failure( $r ) { - list( $type, $msg ) = $r; - - if ( 'success' == $type ) { - \WP_CLI::success( $msg ); - $status = 0; - } else { - \WP_CLI::warning( $msg ); - $status = 1; - } - - return $status; - } - - /** - * Get Formatter object based on supplied parameters. - * - * @param array $assoc_args Parameters passed to command. Determines formatting. - * @return \WP_CLI\Formatter - */ - protected function get_formatter( &$assoc_args ) { - - if ( ! empty( $assoc_args['fields'] ) ) { - if ( is_string( $assoc_args['fields'] ) ) { - $fields = explode( ',', $assoc_args['fields'] ); - } else { - $fields = $assoc_args['fields']; - } - } else { - $fields = $this->obj_fields; - } - return new \WP_CLI\Formatter( $assoc_args, $fields, $this->obj_type ); - } - - /** - * Given a callback, display the URL for one or more objects. - * - * @param array $args One or more object references. - * @param string $callback Function to get URL for the object. - */ - protected function _url( $args, $callback ) { - foreach ( $args as $obj_id ) { - $object = $this->fetcher->get_check( $obj_id ); - \WP_CLI::line( $callback( $object->{$this->obj_id_key} ) ); - } - } -} diff --git a/php/WP_CLI/CommandWithMeta.php b/php/WP_CLI/CommandWithMeta.php deleted file mode 100644 index 2d8a8c5c0..000000000 --- a/php/WP_CLI/CommandWithMeta.php +++ /dev/null @@ -1,273 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; - -/** - * Base class for WP-CLI commands that deal with metadata - * - * @package wp-cli - */ -abstract class CommandWithMeta extends \WP_CLI_Command { - - protected $meta_type; - - /** - * List all metadata associated with an object. - * - * <id> - * : ID for the object. - * - * [--keys=<keys>] - * : Limit output to metadata of specific keys. - * - * [--fields=<fields>] - * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. - * - * [--format=<format>] - * : Accepted values: table, csv, json, count. Default: table - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - list( $object_id ) = $args; - - $keys = ! empty( $assoc_args['keys'] ) ? explode( ',', $assoc_args['keys'] ) : array(); - - $object_id = $this->check_object_id( $object_id ); - - $metadata = get_metadata( $this->meta_type, $object_id ); - if ( ! $metadata ) { - $metadata = array(); - } - - $items = array(); - foreach( $metadata as $key => $values ) { - - // Skip if not requested - if ( ! empty( $keys ) && ! in_array( $key, $keys ) ) { - continue; - } - - foreach( $values as $item_value ) { - - $item_value = maybe_unserialize( $item_value ); - - $items[] = (object) array( - "{$this->meta_type}_id" => $object_id, - 'meta_key' => $key, - 'meta_value' => $item_value, - ); - - } - - } - - if ( ! empty( $assoc_args['fields'] ) ) { - $fields = explode( ',', $assoc_args['fields'] ); - } else { - $fields = $this->get_fields(); - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, $fields, $this->meta_type ); - $formatter->display_items( $items ); - - } - - /** - * Get meta field value. - * - * <id> - * : The ID of the object. - * - * <key> - * : The name of the meta field to get. - * - * [--format=<format>] - * : Accepted values: table, json. Default: table - */ - public function get( $args, $assoc_args ) { - list( $object_id, $meta_key ) = $args; - - $object_id = $this->check_object_id( $object_id ); - - $value = get_metadata( $this->meta_type, $object_id, $meta_key, true ); - - if ( '' === $value ) - die(1); - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Delete a meta field. - * - * <id> - * : The ID of the object. - * - * [<key>] - * : The name of the meta field to delete. - * - * [<value>] - * : The value to delete. If omitted, all rows with key will deleted. - * - * [--all] - * : Delete all meta for the object. - */ - public function delete( $args, $assoc_args ) { - list( $object_id ) = $args; - - $meta_key = ! empty( $args[1] ) ? $args[1] : ''; - $meta_value = ! empty( $args[2] ) ? $args[2] : ''; - - if ( empty( $meta_key ) && ! Utils\get_flag_value( $assoc_args, 'all' ) ) { - WP_CLI::error( 'Please specify a meta key, or use the --all flag.' ); - } - - $object_id = $this->check_object_id( $object_id ); - - if ( Utils\get_flag_value( $assoc_args, 'all' ) ) { - $errors = false; - foreach( get_metadata( $this->meta_type, $object_id ) as $meta_key => $values ) { - $success = delete_metadata( $this->meta_type, $object_id, $meta_key ); - if ( $success ) { - WP_CLI::log( "Deleted '{$meta_key}' custom field." ); - } else { - WP_CLI::warning( "Failed to delete '{$meta_key}' custom field." ); - $errors = true; - } - } - if ( $errors ) { - WP_CLI::error( 'Failed to delete all custom fields.' ); - } else { - WP_CLI::success( 'Deleted all custom fields.' ); - } - } else { - $success = delete_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); - if ( $success ) { - WP_CLI::success( "Deleted custom field." ); - } else { - WP_CLI::error( "Failed to delete custom field." ); - } - } - } - - /** - * Add a meta field. - * - * ## OPTIONS - * - * <id> - * : The ID of the object. - * - * <key> - * : The name of the meta field to create. - * - * [<value>] - * : The value of the meta field. If omitted, the value is read from STDIN. - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - */ - public function add( $args, $assoc_args ) { - list( $object_id, $meta_key ) = $args; - - $meta_value = WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); - $meta_value = WP_CLI::read_value( $meta_value, $assoc_args ); - - $object_id = $this->check_object_id( $object_id ); - - $meta_value = wp_slash( $meta_value ); - $success = add_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); - - if ( $success ) { - WP_CLI::success( "Added custom field." ); - } else { - WP_CLI::error( "Failed to add custom field." ); - } - } - - /** - * Update a meta field. - * - * ## OPTIONS - * - * <id> - * : The ID of the object. - * - * <key> - * : The name of the meta field to update. - * - * [<value>] - * : The new value. If omitted, the value is read from STDIN. - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - * - * @alias set - */ - public function update( $args, $assoc_args ) { - list( $object_id, $meta_key ) = $args; - - $meta_value = WP_CLI::get_value_from_arg_or_stdin( $args, 2 ); - $meta_value = WP_CLI::read_value( $meta_value, $assoc_args ); - - $object_id = $this->check_object_id( $object_id ); - - $meta_value = sanitize_meta( $meta_key, $meta_value, $this->meta_type ); - $old_value = sanitize_meta( $meta_key, get_metadata( $this->meta_type, $object_id, $meta_key, true ), $this->meta_type ); - - if ( $meta_value === $old_value ) { - WP_CLI::success( "Value passed for custom field '$meta_key' is unchanged." ); - } else { - $meta_value = wp_slash( $meta_value ); - $success = update_metadata( $this->meta_type, $object_id, $meta_key, $meta_value ); - - if ( $success ) { - WP_CLI::success( "Updated custom field '$meta_key'." ); - } else { - WP_CLI::error( "Failed to update custom field '$meta_key'." ); - } - - } - - } - - /** - * Get the fields for this object's meta - * - * @return array - */ - private function get_fields() { - return array( - "{$this->meta_type}_id", - 'meta_key', - 'meta_value', - ); - } - - /** - * Check that the object ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - // Needs to be set in subclass - return $object_id; - } - -} diff --git a/php/WP_CLI/CommandWithTerms.php b/php/WP_CLI/CommandWithTerms.php deleted file mode 100644 index 7296ac109..000000000 --- a/php/WP_CLI/CommandWithTerms.php +++ /dev/null @@ -1,244 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; - -/** - * Base class for WP-CLI commands that deal with terms - * - * @package wp-cli - */ -abstract class CommandWithTerms extends \WP_CLI_Command { - - /** - * @var string $object_type WordPress' expected name for the object. - */ - protected $obj_type; - - /** - * @var string $object_id WordPress' object id. - */ - protected $obj_id; - - /** - * @var array $obj_fields Default fields to display for each object. - */ - protected $obj_fields = array( - "term_id", - "name", - "slug", - "taxonomy" - ); - - /** - * List all terms associated with an object. - * - * <id> - * : ID for the object. - * - * <taxonomy>... - * : One or more taxonomies to list. - * - * [--fields=<fields>] - * : Limit the output to specific row fields. - * - * [--format=<format>] - * : Accepted values: table, csv, json, count, ids. Default: table - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each term: - * - * * term_id - * * name - * * slug - * * taxonomy - * - * These fields are optionally available: - * - * * term_taxonomy_id - * * description - * * term_group - * * parent - * * count - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - $defaults = array( - 'format' => 'table', - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $object_id = array_shift( $args ); - $taxonomy_names = $args; - $taxonomy_args = array(); - - $this->set_obj_id( $object_id ); - - foreach ( $taxonomy_names as $taxonomy ) { - $this->taxonomy_exists( $taxonomy ); - } - - if ( $assoc_args['format'] == 'ids' ) { - $taxonomy_args['fields'] = 'ids'; - } - - $items = wp_get_object_terms( $object_id, $taxonomy_names, $taxonomy_args ); - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $items ); - - } - - - /** - * Remove a term from an object. - * - * <id> - * : The ID of the object. - * - * <taxonomy> - * : The name of the term's taxonomy. - * - * <term>... - * : The name of the term or terms to be removed from the object. - */ - public function remove( $args, $assoc_args ) { - $object_id = array_shift( $args ); - $taxonomy = array_shift( $args ); - $terms = $args; - - $this->set_obj_id( $object_id ); - - $this->taxonomy_exists( $taxonomy ); - - $result = wp_remove_object_terms( $object_id, $terms, $taxonomy ); - - if ( ! is_wp_error( $result ) ) { - WP_CLI::success( "Deleted term." ); - } else { - WP_CLI::error( "Failed to delete term." ); - } - } - - /** - * Add a term to an object. - * - * Append the term to the existing set of terms on the object. - * - * <id> - * : The ID of the object. - * - * <taxonomy> - * : The name of the taxonomy type to be added. - * - * <term>... - * : The slug of the term or terms to be added. - */ - public function add( $args, $assoc_args ) { - $object_id = array_shift( $args ); - $taxonomy = array_shift( $args ); - $terms = $args; - - $this->set_obj_id( $object_id ); - - $this->taxonomy_exists( $taxonomy ); - - $result = wp_set_object_terms( $object_id, $terms, $taxonomy, true ); - - if ( ! is_wp_error( $result ) ) { - WP_CLI::success( "Added term." ); - } else { - WP_CLI::error( "Failed to add term." ); - } - } - - /** - * Set object terms. - * - * Replaces existing terms on the object. - * - * <id> - * : The ID of the object. - * - * <taxonomy> - * : The name of the taxonomy type to be updated. - * - * <term>... - * : The slug of the term or terms to be updated. - */ - public function set( $args, $assoc_args ) { - $object_id = array_shift( $args ); - $taxonomy = array_shift( $args ); - $terms = $args; - - $this->set_obj_id( $object_id ); - - $this->taxonomy_exists( $taxonomy ); - - $result = wp_set_object_terms( $object_id, $terms, $taxonomy, false ); - - if ( ! is_wp_error( $result ) ) { - WP_CLI::success( "Set terms." ); - } else { - WP_CLI::error( "Failed to set terms." ); - } - } - - /** - * Check if taxonomy exists - * - * @param $taxonomy - */ - protected function taxonomy_exists( $taxonomy ) { - - $taxonomy_names = get_object_taxonomies( $this->get_object_type() ); - - if ( ! in_array( $taxonomy, $taxonomy_names ) ) { - WP_CLI::error( "Invalid taxonomy {$taxonomy}." ); - } - } - - /** - * Set obj_id Class variable - * - * @param string $obj_id - */ - protected function set_obj_id( $obj_id ) { - $this->obj_id = $obj_id; - } - - /** - * Get obj_id Class variable - * - * @return string - */ - protected function get_obj_id() { - return $this->obj_id; - } - - - /** - * Get obj_type Class variable - * - * @return string $obj_type - */ - protected function get_object_type() { - return $this->obj_type; - } - - /** - * Get Formatter object based on supplied parameters. - * - * @param array $assoc_args Parameters passed to command. Determines formatting. - * - * @return WP_CLI\Formatter - */ - protected function get_formatter( &$assoc_args ) { - return new WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); - } -} - diff --git a/php/WP_CLI/CommandWithTranslation.php b/php/WP_CLI/CommandWithTranslation.php deleted file mode 100644 index a6670ca6a..000000000 --- a/php/WP_CLI/CommandWithTranslation.php +++ /dev/null @@ -1,474 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Base class for WP-CLI commands that deal with translations - * - * @package wp-cli - */ -abstract class CommandWithTranslation extends \WP_CLI_Command { - - protected $obj_type; - - protected $obj_fields = array( - 'language', - 'english_name', - 'native_name', - 'status', - 'update', - 'updated', - ); - - /** - * List all available languages. - * - * [--field=<field>] - * : Display the value of a single field - * - * [--<field>=<value>] - * : Filter results by key=value pairs. - * - * [--fields=<fields>] - * : Limit the output to specific fields. - * - * [--format=<format>] - * : Accepted values: table, csv, json. Default: table - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each translation: - * - * * language - * * english_name - * * native_name - * * status - * * update - * * updated - * - * These fields are optionally available: - * - * * version - * * package - * - * ## EXAMPLES - * - * # List language,english_name,status fields of available languages. - * $ wp core language list --fields=language,english_name,status - * +----------------+-------------------------+-------------+ - * | language | english_name | status | - * +----------------+-------------------------+-------------+ - * | ar | Arabic | uninstalled | - * | ary | Moroccan Arabic | uninstalled | - * | az | Azerbaijani | uninstalled | - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - $translations = $this->get_all_languages(); - $available = $this->get_installed_languages(); - - $updates = $this->get_translation_updates(); - - $current_locale = get_locale(); - $translations = array_map( function( $translation ) use ( $available, $current_locale, $updates ) { - $translation['status'] = ( in_array( $translation['language'], $available ) ) ? 'installed' : 'uninstalled'; - if ( $current_locale == $translation['language'] ) { - $translation['status'] = 'active'; - } - - $update = wp_list_filter( $updates, array( - 'language' => $translation['language'] - ) ); - if ( $update ) { - $translation['update'] = 'available'; - } else { - $translation['update'] = 'none'; - } - - return $translation; - }, $translations ); - - foreach( $translations as $key => $translation ) { - - $fields = array_keys( $translation ); - foreach( $fields as $field ) { - if ( isset( $assoc_args[ $field ] ) && $assoc_args[ $field ] != $translation[ $field ] ) { - unset( $translations[ $key ] ); - } - } - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $translations ); - - } - - /** - * Callback to sort array by a 'language' key. - */ - protected function sort_translations_callback( $a, $b ) { - return strnatcasecmp( $a['language'], $b['language'] ); - } - - /** - * Install a given language. - * - * Downloads the language pack from WordPress.org. - * - * <language> - * : Language code to install. - * - * [--activate] - * : If set, the language will be activated immediately after install. - * - * ## EXAMPLES - * - * # Install the Japanese language. - * $ wp core language install ja - * Success: Language installed. - * - * @subcommand install - */ - public function install( $args, $assoc_args ) { - - list( $language_code ) = $args; - - $available = $this->get_installed_languages(); - - if ( in_array( $language_code, $available ) ) { - \WP_CLI::warning( "Language '{$language_code}' already installed." ); - } else { - $response = $this->download_language_pack( $language_code ); - - if ( is_wp_error( $response ) ) { - \WP_CLI::error( $response ); - } else { - \WP_CLI::success( "Language installed." ); - } - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - $this->activate( array( $language_code ), array() ); - } - - } - - /** - * Update installed languages. - * - * Updates installed languages for core, plugins and themes. - * - * [--dry-run] - * : Preview which translations would be updated. - * - * ## EXAMPLES - * - * $ wp core language update - * Updating 'Japanese' translation for Akismet 3.1.11... - * Downloading translation from https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/ja.zip... - * Translation updated successfully. - * Updating 'Japanese' translation for Twenty Fifteen 1.5... - * Downloading translation from https://downloads.wordpress.org/translation/theme/twentyfifteen/1.5/ja.zip... - * Translation updated successfully. - * Success: Updated 2/2 translations. - * - * @subcommand update - */ - public function update( $args, $assoc_args ) { - - $updates = $this->get_translation_updates(); - if ( empty( $updates ) ) { - \WP_CLI::success( 'Translations are up to date.' ); - - return; - } - - // Gets a list of all languages. - $all_languages = $this->get_all_languages(); - - // Formats the updates list. - foreach ( $updates as $update ) { - if ( 'plugin' == $update->type ) { - $plugins = get_plugins( '/' . $update->slug ); - $plugin_data = array_shift( $plugins ); - $name = $plugin_data['Name']; - } elseif ( 'theme' == $update->type ) { - $theme_data = wp_get_theme( $update->slug ); - $name = $theme_data['Name']; - } else { // Core - $name = 'WordPress'; - } - - // Gets the translation data. - $translation = wp_list_filter( $all_languages, array( - 'language' => $update->language - ) ); - $translation = (object) reset( $translation ); - - $update->Type = ucfirst( $update->type ); - $update->Name = $name; - $update->Version = $update->version; - $update->Language = $translation->english_name; - } - - // Only preview which translations would be updated. - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { - \WP_CLI::line( sprintf( 'Available %d translations updates:', count( $updates ) ) ); - \WP_CLI\Utils\format_items( 'table', $updates, array( 'Type', 'Name', 'Version', 'Language' ) ); - - return; - } - - $upgrader = 'WP_CLI\\LanguagePackUpgrader'; - $results = array(); - - // Update translations. - foreach ( $updates as $update ) { - \WP_CLI::line( "Updating '{$update->Language}' translation for {$update->Name} {$update->Version}..." ); - - $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); - - $results[] = $result; - } - - $num_to_update = count( $updates ); - $num_updated = count( array_filter( $results ) ); - - $line = "Updated $num_updated/$num_to_update translations."; - - if ( $num_to_update == $num_updated ) { - \WP_CLI::success( $line ); - } else if ( $num_updated > 0 ) { - \WP_CLI::warning( $line ); - } else { - \WP_CLI::error( $line ); - } - - } - - /** - * Activate a given language. - * - * <language> - * : Language code to activate. - * - * ## EXAMPLES - * - * $ wp core language activate ja - * Success: Language activated. - * - * @subcommand activate - */ - public function activate( $args, $assoc_args ) { - - list( $language_code ) = $args; - - $available = $this->get_installed_languages(); - - if ( ! in_array( $language_code, $available ) ) { - \WP_CLI::error( "Language not installed." ); - } - - if ( $language_code == 'en_US' ) { - $language_code = ''; - } - - if ( $language_code === get_locale() ) { - \WP_CLI::warning( "Language '{$language_code}' already active." ); - - return; - } - - update_option( 'WPLANG', $language_code ); - \WP_CLI::success( "Language activated." ); - } - - /** - * Get all updates available for all translations - * - * @return array - */ - private function get_translation_updates() { - $available = $this->get_installed_languages(); - $func = function() use ( $available ) { - return $available; - }; - $filters = array( 'plugins_update_check_locales', 'themes_update_check_locales' ); - foreach( $filters as $filter ) { - add_filter( $filter, $func ); - } - $this->wp_clean_update_cache(); // Clear existing update caches. - wp_version_check(); // Check for Core translation updates. - wp_update_themes(); // Check for Theme translation updates. - wp_update_plugins(); // Check for Plugin translation updates. - foreach( $filters as $filter ) { - remove_filter( $filter, $func ); - } - $updates = wp_get_translation_updates(); // Retrieves a list of all translations updates available. - return $updates; - } - - /** - * Download a language pack. - * - * @see wp_download_language_pack() - * - * @param string $download Language code to download. - * @return string|WP_Error Returns the language code if successfully downloaded, or a WP_Error object on failure. - */ - private function download_language_pack( $download ) { - - $translations = $this->get_all_languages(); - - foreach ( $translations as $translation ) { - if ( $translation['language'] === $download ) { - $translation_to_load = true; - break; - } - } - - if ( empty( $translation_to_load ) ) { - return new \WP_Error( 'not_found', "Language '{$download}' not found." ); - } - $translation = (object) $translation; - - $translation->type = 'core'; - - $upgrader = 'WP_CLI\\LanguagePackUpgrader'; - $result = Utils\get_upgrader( $upgrader )->upgrade( $translation, array( 'clear_update_cache' => false ) ); - - if ( is_wp_error( $result ) ) { - return $result; - } else if ( ! $result ) { - return new \WP_Error( 'not_installed', "Could not install language '{$download}'." ); - } - - return $translation->language; - } - - /** - * Return a list of installed languages. - * - * @return array - */ - protected function get_installed_languages() { - $available = wp_get_installed_translations( $this->obj_type ); - $available = ! empty( $available['default'] ) ? array_keys( $available['default'] ) : array(); - $available[] = 'en_US'; - - return $available; - } - - /** - * Return a list of all languages - * - * @return array - */ - protected function get_all_languages() { - require_once ABSPATH . '/wp-admin/includes/translation-install.php'; - require ABSPATH . WPINC . '/version.php'; - - $response = translations_api( $this->obj_type, array( 'version' => $wp_version ) ); - if ( is_wp_error( $response ) ) { - \WP_CLI::error( $response ); - } - $translations = ! empty( $response['translations'] ) ? $response['translations'] : array(); - - $en_us = array( - 'language' => 'en_US', - 'english_name' => 'English (United States)', - 'native_name' => 'English (United States)', - 'updated' => '', - ); - - array_push( $translations, $en_us ); - uasort( $translations, array( $this, 'sort_translations_callback' ) ); - - return $translations; - } - - /** - * Uninstall a given language. - * - * <language> - * : Language code to uninstall. - * - * ## EXAMPLES - * - * $ wp core language uninstall ja - * Success: Language uninstalled. - * - * @subcommand uninstall - */ - public function uninstall( $args, $assoc_args ) { - global $wp_filesystem; - - list( $language_code ) = $args; - - $available = $this->get_installed_languages(); - - if ( ! in_array( $language_code, $available ) ) { - \WP_CLI::error( "Language not installed." ); - } - - $dir = 'core' === $this->obj_type ? '' : "/$this->obj_type"; - $files = scandir( WP_LANG_DIR . $dir ); - if ( ! $files ) { - \WP_CLI::error( "No files found in language directory." ); - } - - $current_locale = get_locale(); - if ( $language_code === $current_locale ) { - \WP_CLI::warning( "The '{$language_code}' language is active." ); - exit; - } - - // As of WP 4.0, no API for deleting a language pack - WP_Filesystem(); - $deleted = false; - foreach ( $files as $file ) { - if ( '.' === $file[0] || is_dir( $file ) ) { - continue; - } - $extension_length = strlen( $language_code ) + 4; - $ending = substr( $file, -$extension_length ); - if ( ! in_array( $file, array( $language_code . '.po', $language_code . '.mo' ) ) && ! in_array( $ending, array( '-' . $language_code . '.po', '-' . $language_code . '.mo' ) ) ) { - continue; - } - $deleted = $wp_filesystem->delete( WP_LANG_DIR . $dir . '/' . $file ); - } - - if ( $deleted ) { - \WP_CLI::success( "Language uninstalled." ); - } else { - \WP_CLI::error( "Couldn't uninstall language." ); - } - - } - - /** - * Get Formatter object based on supplied parameters. - * - * @param array $assoc_args Parameters passed to command. Determines formatting. - * @return \WP_CLI\Formatter - */ - protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); - } - - /** - * Replicates wp_clean_update_cache() for use in WP 4.0 - */ - private static function wp_clean_update_cache() { - if ( function_exists( 'wp_clean_plugins_cache' ) ) { - wp_clean_plugins_cache(); - } else { - delete_site_transient( 'update_plugins' ); - } - wp_clean_themes_cache(); - delete_site_transient( 'update_core' ); - } - -} diff --git a/php/WP_CLI/CommandWithUpgrade.php b/php/WP_CLI/CommandWithUpgrade.php deleted file mode 100755 index b82baadff..000000000 --- a/php/WP_CLI/CommandWithUpgrade.php +++ /dev/null @@ -1,501 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; -use WP_CLI\Utils; - -abstract class CommandWithUpgrade extends \WP_CLI_Command { - - protected $item_type; - protected $obj_fields; - - protected $upgrade_refresh; - protected $upgrade_transient; - - protected $chained_command = false; - - function __construct() { - // Do not automatically check translations updates after updating plugins/themes. - add_action( 'upgrader_process_complete', function() { - remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); - }, 1 ); - } - - abstract protected function get_upgrader_class( $force ); - - abstract protected function get_item_list(); - - /** - * @param array List of update candidates - * @param array List of item names - * @return array List of update candidates - */ - abstract protected function filter_item_list( $items, $args ); - - abstract protected function get_all_items(); - - abstract protected function get_status( $file ); - - abstract protected function status_single( $args ); - - abstract protected function install_from_repo( $slug, $assoc_args ); - - function status( $args ) { - // Force WordPress to check for updates - call_user_func( $this->upgrade_refresh ); - - if ( empty( $args ) ) { - $this->status_all(); - } else { - $this->status_single( $args ); - } - } - - private function status_all() { - $items = $this->get_all_items(); - - $n = count( $items ); - - // Not interested in the translation, just the number logic - \WP_CLI::log( sprintf( _n( - "%d installed {$this->item_type}:", - "%d installed {$this->item_type}s:", - $n ), $n ) ); - - $padding = $this->get_padding($items); - - foreach ( $items as $file => $details ) { - if ( $details['update'] ) { - $line = ' %yU%n'; - } else { - $line = ' '; - } - - $line .= $this->format_status( $details['status'], 'short' ); - $line .= " " . str_pad( $details['name'], $padding ). "%n"; - if ( !empty( $details['version'] ) ) { - $line .= " " . $details['version']; - } - - \WP_CLI::line( \WP_CLI::colorize( $line ) ); - } - - \WP_CLI::line(); - - $this->show_legend( $items ); - } - - private function get_padding( $items ) { - $max_len = 0; - - foreach ( $items as $details ) { - $len = strlen( $details['name'] ); - - if ( $len > $max_len ) { - $max_len = $len; - } - } - - return $max_len; - } - - private function show_legend( $items ) { - $statuses = array_unique( wp_list_pluck( $items, 'status' ) ); - - $legend_line = array(); - - foreach ( $statuses as $status ) { - $legend_line[] = sprintf( '%s%s = %s%%n', - $this->get_color( $status ), - $this->map['short'][ $status ], - $this->map['long'][ $status ] - ); - } - - if ( in_array( true, wp_list_pluck( $items, 'update' ) ) ) - $legend_line[] = '%yU = Update Available%n'; - - \WP_CLI::line( 'Legend: ' . \WP_CLI::colorize( implode( ', ', $legend_line ) ) ); - } - - function install( $args, $assoc_args ) { - - $successes = $errors = 0; - foreach ( $args as $slug ) { - - if ( empty( $slug ) ) { - WP_CLI::warning( "Ignoring ambigious empty slug value." ); - continue; - } - - $local_or_remote_zip_file = false; - $result = false; - - // Check if a URL to a remote or local zip has been specified - if ( strpos( $slug, '://' ) !== false || ( pathinfo( $slug, PATHINFO_EXTENSION ) === 'zip' && is_file( $slug ) ) ) { - $local_or_remote_zip_file = $slug; - } - - if ( $local_or_remote_zip_file ) { - // Install from local or remote zip file - $file_upgrader = $this->get_upgrader( $assoc_args ); - - $filter = false; - if ( strpos( $local_or_remote_zip_file, '://' ) !== false - && 'github.com' === parse_url( $local_or_remote_zip_file, PHP_URL_HOST ) ) { - $filter = function( $source, $remote_source, $upgrader ) use ( $local_or_remote_zip_file ) { - // Don't attempt to rename ZIPs uploaded to the releases page - if ( preg_match( '#github\.com/([^/]+)/([^/]+)/releases/download/#', $local_or_remote_zip_file ) || preg_match( '#github\.com/([^/]+)/([^/]+)/raw/#', $local_or_remote_zip_file ) ) { - return $source; - } - $branch_length = strlen( pathinfo( $local_or_remote_zip_file, PATHINFO_FILENAME ) ); - if ( $branch_length ) { - $new_path = substr( rtrim( $source, '/' ), 0, - ( $branch_length + 1 ) ) . '/'; - if ( $GLOBALS['wp_filesystem']->move( $source, $new_path ) ) { - WP_CLI::log( "Renamed Github-based project from '" . Utils\basename( $source ) . "' to '" . Utils\basename( $new_path ) . "'." ); - return $new_path; - } else { - return new \WP_Error( 'wpcli_install_gitub', "Couldn't move Github-based project to appropriate directory." ); - } - } - return $source; - }; - add_filter( 'upgrader_source_selection', $filter, 10, 3 ); - } - - if ( $file_upgrader->install( $local_or_remote_zip_file ) ) { - $slug = $file_upgrader->result['destination_name']; - $result = true; - if ( $filter ) { - remove_filter( 'upgrader_source_selection', $filter, 10 ); - } - $successes++; - } else { - $errors++; - } - } else { - // Assume a plugin/theme slug from the WordPress.org repository has been specified - $result = $this->install_from_repo( $slug, $assoc_args ); - - if ( is_null( $result ) ) { - $errors++; - } elseif ( is_wp_error( $result ) ) { - $key = $result->get_error_code(); - if ( in_array( $key, array( 'plugins_api_failed', 'themes_api_failed' ) ) - && ! empty( $result->error_data[ $key ] ) && in_array( $result->error_data[ $key ], array( 'N;', 'b:0;' ) ) ) { - \WP_CLI::warning( "Couldn't find '$slug' in the WordPress.org {$this->item_type} directory." ); - $errors++; - } else { - \WP_CLI::warning( "$slug: " . $result->get_error_message() ); - if ( 'already_installed' !== $key ) { - $errors++; - } - } - } else { - $successes++; - } - } - - if ( $result ) { - $this->chained_command = true; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate-network' ) ) { - \WP_CLI::log( "Network-activating '$slug'..." ); - $this->activate( array( $slug ), array( 'network' => true ) ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - \WP_CLI::log( "Activating '$slug'..." ); - $this->activate( array( $slug ) ); - } - $this->chained_command = false; - } - } - Utils\report_batch_operation_results( $this->item_type, 'install', count( $args ), $successes, $errors ); - } - - /** - * Prepare an API response for downloading a particular version of an item. - * - * @param object $response wordpress.org API response - * @param string $version The desired version of the package - */ - protected static function alter_api_response( $response, $version ) { - if ( $response->version == $version ) - return; - - // WordPress.org forces https, but still sometimes returns http - // See https://twitter.com/nacin/status/512362694205140992 - $response->download_link = str_replace( 'http://', 'https://', $response->download_link ); - - list( $link ) = explode( $response->slug, $response->download_link ); - - if ( false !== strpos( $response->download_link, '/theme/' ) ) - $download_type = 'theme'; - else if ( false !== strpos( $response->download_link, '/plugin/' ) ) - $download_type = 'plugin'; - else - $download_type = 'plugin/theme'; - - if ( 'dev' == $version ) { - $response->download_link = $link . $response->slug . '.zip'; - $response->version = 'Development Version'; - } else { - $response->download_link = $link . $response->slug . '.' . $version .'.zip'; - $response->version = $version; - - // check if the requested version exists - $response = wp_remote_head( $response->download_link ); - $response_code = wp_remote_retrieve_response_code( $response ); - if ( 200 !== $response_code ) { - \WP_CLI::error( sprintf( - "Can't find the requested %s's version %s in the WordPress.org %s repository (HTTP code %d).", - $download_type, $version, $download_type, $response_code ) ); - } - } - } - - protected function get_upgrader( $assoc_args ) { - $upgrader_class = $this->get_upgrader_class( \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ); - return \WP_CLI\Utils\get_upgrader( $upgrader_class ); - } - - protected function update_many( $args, $assoc_args ) { - call_user_func( $this->upgrade_refresh ); - - if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { - $logger = new \WP_CLI\Loggers\Quiet; - \WP_CLI::set_logger( $logger ); - } - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { - \WP_CLI::error( "Please specify one or more {$this->item_type}s, or use --all." ); - } - - $items = $this->get_item_list(); - - $errors = 0; - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - $items = $this->filter_item_list( $items, $args ); - $errors = count( $args ) - count( $items ); - } - - $items_to_update = wp_list_filter( $items, array( - 'update' => true - ) ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { - if ( empty( $items_to_update ) ) { - \WP_CLI::line( "No {$this->item_type} updates available." ); - return; - } - - if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { - \WP_CLI\Utils\format_items( $assoc_args['format'], $items_to_update, array( 'name', 'status', 'version', 'update_version' ) ); - } else if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { - \WP_CLI::line( "Available {$this->item_type} updates:" ); - foreach( $items_to_update as $item_to_update => $info ) { - \WP_CLI::log( "{$info['title']} update from version {$info['version']} to version {$info['update_version']}" ); - } - } else { - \WP_CLI::line( "Available {$this->item_type} updates:" ); - \WP_CLI\Utils\format_items( 'table', $items_to_update, array( 'name', 'status', 'version', 'update_version' ) ); - } - - return; - } - - $result = array(); - - // Only attempt to update if there is something to update - if ( !empty( $items_to_update ) ) { - $cache_manager = \WP_CLI::get_http_cache_manager(); - foreach ($items_to_update as $item) { - $cache_manager->whitelist_package($item['update_package'], $this->item_type, $item['name'], $item['update_version']); - } - $upgrader = $this->get_upgrader( $assoc_args ); - $result = $upgrader->bulk_upgrade( wp_list_pluck( $items_to_update, 'update_id' ) ); - } - - // Let the user know the results. - $num_to_update = count( $items_to_update ); - $num_updated = count( array_filter( $result ) ); - - if ( $num_to_update > 0 ) { - if ( ! empty( $assoc_args['format'] ) && 'summary' === $assoc_args['format'] ) { - foreach( $items_to_update as $item_to_update => $info ) { - $message = $result[ $info['update_id'] ] !== null ? 'updated successfully' : 'did not update'; - \WP_CLI::log( "{$info['title']} {$message} from version {$info['version']} to version {$info['update_version']}" ); - } - } else { - $status = array(); - foreach($items_to_update as $item_to_update => $info) { - $status[$item_to_update] = array( - 'name' => $info['name'], - 'old_version' => $info['version'], - 'new_version' => $info['update_version'], - 'status' => $result[ $info['update_id'] ] !== null ? 'Updated' : 'Error', - ); - } - - $format = 'table'; - if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'json', 'csv' ) ) ) { - $format = $assoc_args['format']; - } - - \WP_CLI\Utils\format_items( $format, $status, array( 'name', 'old_version', 'new_version', 'status' ) ); - } - } - Utils\report_batch_operation_results( $this->item_type, 'update', count( $args ), $num_updated, $errors ); - } - - protected function _list( $_, $assoc_args ) { - // Force WordPress to check for updates - call_user_func( $this->upgrade_refresh ); - - $all_items = $this->get_all_items(); - if ( !is_array( $all_items ) ) - \WP_CLI::error( "No {$this->item_type}s found." ); - - foreach ( $all_items as $key => &$item ) { - - if ( empty( $item['version'] ) ) - $item['version'] = ''; - - foreach ( $item as $field => &$value ) { - if ( $value === true ) { - $value = 'available'; - } else if ( $value === false ) { - $value = 'none'; - } - } - - foreach ( $this->obj_fields as $field ) { - if ( isset( $assoc_args[$field] ) - && $assoc_args[$field] != $item[$field] ) - unset( $all_items[$key] ); - } - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $all_items ); - } - - /** - * Check whether an item has an update available or not. - * - * @param string $slug The plugin/theme slug - * - * @return bool - */ - protected function has_update( $slug ) { - $update_list = get_site_transient( $this->upgrade_transient ); - - return isset( $update_list->response[ $slug ] ); - } - - /** - * Get the available update info - * - * @param string $slug The plugin/theme slug - * - * @return array|null - */ - protected function get_update_info( $slug ) { - $update_list = get_site_transient( $this->upgrade_transient ); - - if ( !isset( $update_list->response[ $slug ] ) ) - return null; - - return (array) $update_list->response[ $slug ]; - } - - private $map = array( - 'short' => array( - 'inactive' => 'I', - 'active' => 'A', - 'active-network' => 'N', - 'must-use' => 'M', - 'parent' => 'P', - ), - 'long' => array( - 'inactive' => 'Inactive', - 'active' => 'Active', - 'active-network' => 'Network Active', - 'must-use' => 'Must Use', - 'parent' => 'Parent', - ) - ); - - protected function format_status( $status, $format ) { - return $this->get_color( $status ) . $this->map[ $format ][ $status ]; - } - - private function get_color( $status ) { - static $colors = array( - 'inactive' => '', - 'active' => '%g', - 'active-network' => '%g', - 'must-use' => '%c', - 'parent' => '%p', - ); - - return $colors[ $status ]; - } - - /** - * Search wordpress.org repo. - * - * @param array $args A arguments array containing the search term in the first element. - * @param array $assoc_args Data passed in from command. - */ - protected function _search( $args, $assoc_args ) { - $term = $args[0]; - - $defaults = array( - 'per-page' => 10, - 'page' => 1, - 'fields' => implode( ',', array( 'name', 'slug', 'rating' ) ), - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - $fields = array(); - foreach( explode( ',', $assoc_args['fields'] ) as $field ) { - $fields[ $field ] = true; - } - - $formatter = $this->get_formatter( $assoc_args ); - - $api_args = array( - 'per_page' => (int) $assoc_args['per-page'], - 'page' => (int) $assoc_args['page'], - 'search' => $term, - 'fields' => $fields, - ); - - if ( 'plugin' == $this->item_type ) { - $api = plugins_api( 'query_plugins', $api_args ); - } else { - $api = themes_api( 'query_themes', $api_args ); - } - - if ( is_wp_error( $api ) ) - \WP_CLI::error( $api->get_error_message() . __( ' Try again' ) ); - - $plural = $this->item_type . 's'; - - if ( ! isset( $api->$plural ) ) - \WP_CLI::error( __( 'API error. Try Again.' ) ); - - $items = $api->$plural; - - $count = \WP_CLI\Utils\get_flag_value( $api->info, 'results', 'unknown' ); - \WP_CLI::success( sprintf( 'Showing %s of %s %s.', count( $items ), $count, $plural ) ); - - $formatter->display_items( $items ); - } - - protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->item_type ); - } -} - diff --git a/php/WP_CLI/Completions.php b/php/WP_CLI/Completions.php deleted file mode 100644 index 17484dd42..000000000 --- a/php/WP_CLI/Completions.php +++ /dev/null @@ -1,162 +0,0 @@ -<?php - -namespace WP_CLI; - -class Completions { - - private $words; - private $opts = array(); - - function __construct( $line ) { - // TODO: properly parse single and double quotes - $this->words = explode( ' ', $line ); - - // first word is always `wp` - array_shift( $this->words ); - - // last word is either empty or an incomplete subcommand - $this->cur_word = end( $this->words ); - if ( "" !== $this->cur_word && ! preg_match( "/^\-/", $this->cur_word ) ) { - array_pop( $this->words ); - } - - $is_alias = false; - $is_help = false; - if ( ! empty( $this->words[0] ) && preg_match( "/^@/", $this->words[0] ) ) { - array_shift( $this->words ); - // `wp @al` is false, but `wp @all ` is true. - if ( count( $this->words ) ) { - $is_alias = true; - } - } elseif ( ! empty( $this->words[0] ) && 'help' === $this->words[0] ) { - array_shift( $this->words ); - $is_help = true; - } - - $r = $this->get_command( $this->words ); - if ( !is_array( $r ) ) { - return; - } - - list( $command, $args, $assoc_args ) = $r; - - $spec = SynopsisParser::parse( $command->get_synopsis() ); - - foreach ( $spec as $arg ) { - if ( $arg['type'] == 'positional' && $arg['name'] == 'file' ) { - $this->add( '<file> ' ); - return; - } - } - - if ( $command->can_have_subcommands() ) { - // add completion when command is `wp` and alias isn't set. - if ( "wp" === $command->get_name() && false === $is_alias && false == $is_help ) { - $aliases = \WP_CLI::get_configurator()->get_aliases(); - foreach ( $aliases as $name => $_ ) { - $this->add( "$name " ); - } - } - foreach ( $command->get_subcommands() as $name => $_ ) { - $this->add( "$name " ); - } - } else { - foreach ( $spec as $arg ) { - if ( in_array( $arg['type'], array( 'flag', 'assoc' ) ) ) { - if ( isset( $assoc_args[ $arg['name'] ] ) ) { - continue; - } - - $opt = "--{$arg['name']}"; - - if ( $arg['type'] == 'flag' ) { - $opt .= ' '; - } elseif ( !$arg['value']['optional'] ) { - $opt .= '='; - } - - $this->add( $opt ); - } - } - - foreach ( $this->get_global_parameters() as $param => $runtime ) { - if ( isset( $assoc_args[ $param ] ) ) { - continue; - } - - $opt = "--{$param}"; - - if ( "" === $runtime || ! is_string( $runtime ) ) { - $opt .= ' '; - } else { - $opt .= '='; - } - - $this->add( $opt ); - } - } - - } - - private function get_command( $words ) { - $positional_args = $assoc_args = array(); - - foreach ( $words as $arg ) { - if ( preg_match( '|^--([^=]+)=?|', $arg, $matches ) ) { - $assoc_args[ $matches[1] ] = true; - } else { - $positional_args[] = $arg; - } - } - - $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); - if ( !is_array( $r ) && array_pop( $positional_args ) == $this->cur_word ) { - $r = \WP_CLI::get_runner()->find_command_to_run( $positional_args ); - } - - if ( !is_array( $r ) ) { - return $r; - } - - list( $command, $args ) = $r; - - return array( $command, $args, $assoc_args ); - } - - private function get_global_parameters() { - $params = array(); - foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { - if ( false === $details['runtime'] ) { - continue; - } elseif ( isset( $details['deprecated'] ) ) { - continue; - } elseif ( isset( $details['hidden'] ) ) { - continue; - } - $params[ $key ] = $details["runtime"]; - - // Add additional option like `--[no-]color`. - if ( true === $details["runtime"] ) { - $params[ "no-" . $key ] = ''; - } - } - - return $params; - } - - private function add( $opt ) { - if ( $this->cur_word !== '' ) { - if ( strpos( $opt, $this->cur_word ) !== 0 ) { - return; - } - } - - $this->opts[] = $opt; - } - - public function render() { - foreach ( $this->opts as $opt ) { - \WP_CLI::line( $opt ); - } - } -} diff --git a/php/WP_CLI/ComposerIO.php b/php/WP_CLI/ComposerIO.php deleted file mode 100644 index 85afaf9ff..000000000 --- a/php/WP_CLI/ComposerIO.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -namespace WP_CLI; - -use \Composer\IO\NullIO; -use \WP_CLI; - -/** - * A Composer IO class so we can provide some level of interactivity from WP-CLI - */ -class ComposerIO extends NullIO { - - /** - * {@inheritDoc} - */ - public function isVerbose() { - return true; - } - - /** - * {@inheritDoc} - */ - public function write( $messages, $newline = true, $verbosity = self::NORMAL ) { - self::output_clean_message( $messages ); - } - - /** - * {@inheritDoc} - */ - public function writeError( $messages, $newline = true, $verbosity = self::NORMAL ) { - self::output_clean_message( $messages ); - } - - private static function output_clean_message( $message ) { - $message = preg_replace( '#<(https?)([^>]+)>#', '$1$2', $message ); - WP_CLI::log( strip_tags( trim( $message ) ) ); - } - -} diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php deleted file mode 100644 index ce1dce901..000000000 --- a/php/WP_CLI/Configurator.php +++ /dev/null @@ -1,333 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Handles file- and runtime-based configuration values. - * - * @package WP_CLI - */ -class Configurator { - - /** - * @var array $spec Configurator argument specification. - */ - private $spec; - - /** - * @var array $config Values for keys defined in Configurator spec. - */ - private $config = array(); - - /** - * @var array $extra_config Extra config values not specified in spec. - */ - private $extra_config = array(); - - /** - * @var array $aliases Any aliases defined in config files. - */ - private $aliases = array(); - - /** - * @var string ALIAS_REGEX Regex pattern used to define an alias - */ - const ALIAS_REGEX = '^@[A-Za-z0-9-_\.\-]+$'; - - /** - * @var array ALIAS_SPEC Arguments that can be used in an alias - */ - private static $alias_spec = array( - 'user', - 'url', - 'path', - 'ssh', - 'http', - ); - - /** - * @param string $path Path to config spec file. - */ - function __construct( $path ) { - $this->spec = include $path; - - $defaults = array( - 'runtime' => false, - 'file' => false, - 'synopsis' => '', - 'default' => null, - 'multiple' => false, - ); - - foreach ( $this->spec as $key => &$details ) { - $details = array_merge( $defaults, $details ); - - $this->config[ $key ] = $details['default']; - } - } - - /** - * Get declared configuration values as an array. - * - * @return array - */ - function to_array() { - return array( $this->config, $this->extra_config ); - } - - /** - * Get configuration specification, i.e. list of accepted keys. - * - * @return array - */ - function get_spec() { - return $this->spec; - } - - /** - * Get any aliases defined in config files. - * - * @return array - */ - function get_aliases() { - if ( $runtime_alias = getenv( 'WP_CLI_RUNTIME_ALIAS' ) ) { - $returned_aliases = array(); - foreach( json_decode( $runtime_alias, true ) as $key => $value ) { - if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { - $returned_aliases[ $key ] = array(); - foreach( self::$alias_spec as $i ) { - if ( isset( $value[ $i ] ) ) { - $returned_aliases[ $key ][ $i ] = $value[ $i ]; - } - } - } - } - return $returned_aliases; - } else { - return $this->aliases; - } - } - - /** - * Splits a list of arguments into positional, associative and config. - * - * @param array(string) - * @return array(array) - */ - public function parse_args( $arguments ) { - list( $positional_args, $mixed_args, $global_assoc, $local_assoc ) = self::extract_assoc( $arguments ); - list( $assoc_args, $runtime_config ) = $this->unmix_assoc_args( $mixed_args, $global_assoc, $local_assoc ); - return array( $positional_args, $assoc_args, $runtime_config ); - } - - /** - * Splits positional args from associative args. - * - * @param array - * @return array(array) - */ - public static function extract_assoc( $arguments ) { - $positional_args = $assoc_args = $global_assoc = $local_assoc = array(); - - foreach ( $arguments as $arg ) { - $positional_arg = $assoc_arg = null; - - if ( preg_match( '|^--no-([^=]+)$|', $arg, $matches ) ) { - $assoc_arg = array( $matches[1], false ); - } elseif ( preg_match( '|^--([^=]+)$|', $arg, $matches ) ) { - $assoc_arg = array( $matches[1], true ); - } elseif ( preg_match( '|^--([^=]+)=(.*)|s', $arg, $matches ) ) { - $assoc_arg = array( $matches[1], $matches[2] ); - } else { - $positional = $arg; - } - - if ( ! is_null( $assoc_arg ) ) { - $assoc_args[] = $assoc_arg; - if ( count( $positional_args ) ) { - $local_assoc[] = $assoc_arg; - } else { - $global_assoc[] = $assoc_arg; - } - } else if ( ! is_null( $positional ) ) { - $positional_args[] = $positional; - } - - } - - return array( $positional_args, $assoc_args, $global_assoc, $local_assoc ); - } - - /** - * Separate runtime parameters from command-specific parameters. - * - * @param array $mixed_args - * @return array - */ - private function unmix_assoc_args( $mixed_args, $global_assoc = array(), $local_assoc = array() ) { - $assoc_args = $runtime_config = array(); - - if ( getenv( 'WP_CLI_STRICT_ARGS_MODE' ) ) { - foreach( $global_assoc as $tmp ) { - list( $key, $value ) = $tmp; - if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { - $this->assoc_arg_to_runtime_config( $key, $value, $runtime_config ); - } - } - foreach( $local_assoc as $tmp ) { - $assoc_args[ $tmp[0] ] = $tmp[1]; - } - } else { - foreach ( $mixed_args as $tmp ) { - list( $key, $value ) = $tmp; - - if ( isset( $this->spec[ $key ] ) && $this->spec[ $key ]['runtime'] !== false ) { - $this->assoc_arg_to_runtime_config( $key, $value, $runtime_config ); - } else { - $assoc_args[ $key ] = $value; - } - } - } - - return array( $assoc_args, $runtime_config ); - } - - /** - * Handle turning an $assoc_arg into a runtime arg. - */ - private function assoc_arg_to_runtime_config( $key, $value, &$runtime_config ) { - $details = $this->spec[ $key ]; - if ( isset( $details['deprecated'] ) ) { - fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); - } - - if ( $details['multiple'] ) { - $runtime_config[ $key ][] = $value; - } else { - $runtime_config[ $key ] = $value; - } - } - - /** - * Load a YAML file of parameters into scope. - * - * @param string $path Path to YAML file. - */ - public function merge_yml( $path, $current_alias = null ) { - $yaml = self::load_yml( $path ); - if ( ! empty( $yaml['_']['inherit'] ) ) { - $this->merge_yml( $yaml['_']['inherit'], $current_alias ); - } - foreach ( $yaml as $key => $value ) { - if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) { - $this->aliases[ $key ] = array(); - $is_alias = false; - foreach( self::$alias_spec as $i ) { - if ( isset( $value[ $i ] ) ) { - $this->aliases[ $key ][ $i ] = $value[ $i ]; - $is_alias = true; - } - } - // If it's not an alias, it might be a group of aliases - if ( ! $is_alias && is_array( $value ) ) { - $alias_group = array(); - foreach( $value as $i => $k ) { - if ( preg_match( '#' . self::ALIAS_REGEX . '#', $k ) ) { - $alias_group[] = $k; - } - } - $this->aliases[ $key ] = $alias_group; - } - } elseif ( !isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) { - if ( isset( $this->extra_config[ $key ] ) - && ! empty( $yaml['_']['merge'] ) - && is_array( $this->extra_config[ $key ] ) - && is_array( $value ) ) { - $this->extra_config[ $key ] = array_merge( $this->extra_config[ $key ], $value ); - } else { - $this->extra_config[ $key ] = $value; - } - } elseif ( $this->spec[ $key ]['multiple'] ) { - self::arrayify( $value ); - $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); - } else { - if ( $current_alias && in_array( $key, self::$alias_spec, true ) ) { - continue; - } - $this->config[ $key ] = $value; - } - } - } - - /** - * Merge an array of values into the configurator config. - * - * @param array $config - */ - public function merge_array( $config ) { - foreach ( $this->spec as $key => $details ) { - if ( false !== $details['runtime'] && isset( $config[ $key ] ) ) { - $value = $config[ $key ]; - - if ( $details['multiple'] ) { - self::arrayify( $value ); - $this->config[ $key ] = array_merge( $this->config[ $key ], $value ); - } else { - $this->config[ $key ] = $value; - } - } - } - } - - /** - * Load values from a YAML file. - * - * @param string $yml_file Path to the YAML file - * @return array $config Declared configuration values - */ - private static function load_yml( $yml_file ) { - if ( !$yml_file ) - return array(); - - $config = spyc_load_file( $yml_file ); - - // Make sure config-file-relative paths are made absolute. - $yml_file_dir = dirname( $yml_file ); - - if ( isset( $config['path'] ) ) - self::absolutize( $config['path'], $yml_file_dir ); - - if ( isset( $config['require'] ) ) { - self::arrayify( $config['require'] ); - foreach ( $config['require'] as &$path ) { - self::absolutize( $path, $yml_file_dir ); - } - } - - return $config; - } - - /** - * Conform a variable to an array. - * - * @param mixed $val A string or an array - */ - private static function arrayify( &$val ) { - if ( !is_array( $val ) ) { - $val = array( $val ); - } - } - - /** - * Make a path absolute. - * - * @param string $path Path to file. - * @param string $base Base path to prepend. - */ - private static function absolutize( &$path, $base ) { - if ( !empty( $path ) && !\WP_CLI\Utils\is_path_absolute( $path ) ) { - $path = $base . DIRECTORY_SEPARATOR . $path; - } - } - -} diff --git a/php/WP_CLI/CoreUpgrader.php b/php/WP_CLI/CoreUpgrader.php deleted file mode 100644 index c3ecad2d2..000000000 --- a/php/WP_CLI/CoreUpgrader.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; - -/** - * A Core Upgrader class that caches the download, and uses cached if available - * - * @package wp-cli - */ -class CoreUpgrader extends \Core_Upgrader { - - /** - * Caches the download, and uses cached if available. - * - * @access public - * - * @param string $package The URI of the package. If this is the full path to an - * existing local file, it will be returned untouched. - * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. - */ - public function download_package( $package ) { - - /** - * Filter whether to return the package. - * - * @since 3.7.0 - * - * @param bool $reply Whether to bail without returning the package. Default is false. - * @param string $package The package file name. - * @param object $this The WP_Upgrader instance. - */ - $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); - if ( false !== $reply ) { - return $reply; - } - - // Check if package is a local or remote file. Bail if it's local. - if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { - return $package; - } - - if ( empty( $package ) ) { - return new \WP_Error( 'no_package', $this->strings['no_package'] ); - } - - $filename = pathinfo( $package, PATHINFO_FILENAME ); - $ext = pathinfo( $package, PATHINFO_EXTENSION ); - - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.' . $ext; - - $cache = WP_CLI::get_cache(); - $update = $GLOBALS['wp_cli_update_obj']; - $cache_key = "core/{$filename}-{$update->locale}.{$ext}"; - $cache_file = $cache->has( $cache_key ); - - if ( $cache_file && false === stripos( $package, 'https://wordpress.org/nightly-builds/' ) ) { - WP_CLI::log( "Using cached file '$cache_file'..." ); - copy( $cache_file, $temp ); - return $temp; - } else { - /* - * Download to a temporary file because piping from cURL to tar is flaky - * on MinGW (and probably in other environments too). - */ - $headers = array( 'Accept' => 'application/json' ); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody. - 'filename' => $temp - ); - - $this->skin->feedback( 'downloading_package', $package ); - - /** @var \Requests_Response|null $req */ - $req = Utils\http_request( 'GET', $package, null, $headers, $options ); - if ( ! is_null( $req ) && $req->status_code !== 200 ) { - return new \WP_Error( 'download_failed', $this->strings['download_failed'] ); - } - if ( false === stripos( $package, 'https://wordpress.org/nightly-builds/' ) ) { - $cache->import( $cache_key, $temp ); - } - return $temp; - } - } -} diff --git a/php/WP_CLI/DestructivePluginUpgrader.php b/php/WP_CLI/DestructivePluginUpgrader.php deleted file mode 100644 index 7fc0d16db..000000000 --- a/php/WP_CLI/DestructivePluginUpgrader.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * A plugin upgrader class that clears the destination directory. - */ -class DestructivePluginUpgrader extends \Plugin_Upgrader { - - function install_package( $args = array() ) { - parent::upgrade_strings(); // needed for the 'remove_old' string - - $args['clear_destination'] = true; - $args['abort_if_destination_exists'] = false; - return parent::install_package( $args ); - } -} - diff --git a/php/WP_CLI/DestructiveThemeUpgrader.php b/php/WP_CLI/DestructiveThemeUpgrader.php deleted file mode 100644 index 599395ba8..000000000 --- a/php/WP_CLI/DestructiveThemeUpgrader.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * A theme upgrader class that clears the destination directory. - */ -class DestructiveThemeUpgrader extends \Theme_Upgrader { - - function install_package( $args = array() ) { - parent::upgrade_strings(); // needed for the 'remove_old' string - - $args['clear_destination'] = true; - $args['abort_if_destination_exists'] = false; - return parent::install_package( $args ); - } -} - diff --git a/php/WP_CLI/Dispatcher/CommandFactory.php b/php/WP_CLI/Dispatcher/CommandFactory.php deleted file mode 100644 index bd667fe05..000000000 --- a/php/WP_CLI/Dispatcher/CommandFactory.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -/** - * Creates CompositeCommand or Subcommand instances. - * - * @package WP_CLI - */ -class CommandFactory { - - /** - * Create a new CompositeCommand (or Subcommand if class has __invoke()) - * - * @param string $name Represents how the command should be invoked - * @param string $callable A subclass of WP_CLI_Command, a function, or a closure - * @param mixed $parent The new command's parent Composite (or Root) command - */ - public static function create( $name, $callable, $parent ) { - - if ( ( is_object( $callable ) && ( $callable instanceof \Closure ) ) - || ( is_string( $callable ) && function_exists( $callable ) ) ) { - $reflection = new \ReflectionFunction( $callable ); - $command = self::create_subcommand( $parent, $name, $callable, $reflection ); - } else if ( is_array( $callable ) && is_callable( $callable ) ) { - $reflection = new \ReflectionClass( $callable[0] ); - $command = self::create_subcommand( $parent, $name, array( $callable[0], $callable[1] ), - $reflection->getMethod( $callable[1] ) ); - } else { - $reflection = new \ReflectionClass( $callable ); - if ( $reflection->hasMethod( '__invoke' ) ) { - $class = is_object( $callable ) ? $callable : $reflection->name; - $command = self::create_subcommand( $parent, $name, array( $class, '__invoke' ), - $reflection->getMethod( '__invoke' ) ); - } else { - $command = self::create_composite_command( $parent, $name, $callable ); - } - } - - return $command; - } - - /** - * Create a new Subcommand instance. - * - * @param mixed $parent The new command's parent Composite command - * @param string $name Represents how the command should be invoked - * @param mixed $callable A callable function or closure, or class name and method - * @param object $reflection Reflection instance, for doc parsing - * @param string $class A subclass of WP_CLI_Command - * @param string $method Class method to be called upon invocation. - */ - private static function create_subcommand( $parent, $name, $callable, $reflection ) { - $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); - - if ( is_array( $callable ) ) { - if ( !$name ) - $name = $docparser->get_tag( 'subcommand' ); - - if ( !$name ) - $name = $reflection->name; - } - - $when_invoked = function ( $args, $assoc_args ) use ( $callable ) { - if ( is_array( $callable ) ) { - $callable[0] = is_object( $callable[0] ) ? $callable[0] : new $callable[0]; - call_user_func( array( $callable[0], $callable[1] ), $args, $assoc_args ); - } else { - call_user_func( $callable, $args, $assoc_args ); - } - }; - - return new Subcommand( $parent, $name, $docparser, $when_invoked ); - } - - /** - * Create a new Composite command instance. - * - * @param mixed $parent The new command's parent Root or Composite command - * @param string $name Represents how the command should be invoked - * @param mixed $callable - */ - private static function create_composite_command( $parent, $name, $callable ) { - $reflection = new \ReflectionClass( $callable ); - $docparser = new \WP_CLI\DocParser( $reflection->getDocComment() ); - - $container = new CompositeCommand( $parent, $name, $docparser ); - - foreach ( $reflection->getMethods() as $method ) { - if ( !self::is_good_method( $method ) ) - continue; - - $class = is_object( $callable ) ? $callable : $reflection->name; - $subcommand = self::create_subcommand( $container, false, array( $class, $method->name ), $method ); - - $subcommand_name = $subcommand->get_name(); - - $container->add_subcommand( $subcommand_name, $subcommand ); - } - - return $container; - } - - /** - * Check whether a method is actually callable. - * - * @param ReflectionMethod $method - * @return bool - */ - private static function is_good_method( $method ) { - return $method->isPublic() && !$method->isStatic() && 0 !== strpos( $method->getName(), '__' ); - } -} - diff --git a/php/WP_CLI/Dispatcher/CompositeCommand.php b/php/WP_CLI/Dispatcher/CompositeCommand.php deleted file mode 100644 index 53862245b..000000000 --- a/php/WP_CLI/Dispatcher/CompositeCommand.php +++ /dev/null @@ -1,300 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -use \WP_CLI\Utils; - -/** - * A non-leaf node in the command tree. - * Contains one or more Subcommands. - * - * @package WP_CLI - */ -class CompositeCommand { - - protected $name, $shortdesc, $synopsis, $docparser; - - protected $parent, $subcommands = array(); - - /** - * Instantiate a new CompositeCommand - * - * @param mixed $parent Parent command (either Root or Composite) - * @param string $name Represents how command should be invoked - * @param \WP_CLI\DocParser - */ - public function __construct( $parent, $name, $docparser ) { - $this->parent = $parent; - - $this->name = $name; - - $this->shortdesc = $docparser->get_shortdesc(); - $this->longdesc = $docparser->get_longdesc(); - $this->docparser = $docparser; - - $when_to_invoke = $docparser->get_tag( 'when' ); - if ( $when_to_invoke ) { - \WP_CLI::get_runner()->register_early_invoke( $when_to_invoke, $this ); - } - } - - /** - * Get the parent composite (or root) command - * - * @return mixed - */ - public function get_parent() { - return $this->parent; - } - - /** - * Add a named subcommand to this composite command's - * set of contained subcommands. - * - * @param string $name Represents how subcommand should be invoked - * @param \WP_CLI\Dispatcher\Subcommand - */ - public function add_subcommand( $name, $command ) { - $this->subcommands[ $name ] = $command; - } - - /** - * Remove a named subcommand from this composite command's set of contained - * subcommands - * - * @param string $name Represents how subcommand should be invoked - */ - public function remove_subcommand( $name ) { - if ( isset( $this->subcommands[ $name ] ) ) { - unset( $this->subcommands[ $name ] ); - } - } - - - /** - * Composite commands always contain subcommands. - * - * @return true - */ - public function can_have_subcommands() { - return true; - } - - /** - * Get the subcommands contained by this composite - * command. - * - * @return array - */ - public function get_subcommands() { - ksort( $this->subcommands ); - - return $this->subcommands; - } - - /** - * Get the name of this composite command. - * - * @return string - */ - public function get_name() { - return $this->name; - } - - /** - * Get the short description for this composite - * command. - * - * @return string - */ - public function get_shortdesc() { - return $this->shortdesc; - } - - /** - * Set the short description for this composite command. - * - * @param string - */ - public function set_shortdesc( $shortdesc ) { - $this->shortdesc = $shortdesc; - } - - /** - * Get the long description for this composite - * command. - * - * @return string - */ - public function get_longdesc() { - return $this->longdesc . $this->get_global_params(); - } - - /** - * Set the long description for this composite commmand - * - * @param string - */ - public function set_longdesc( $longdesc ) { - $this->longdesc = $longdesc; - } - - /** - * Get the synopsis for this composite command. - * As a collection of subcommands, the composite - * command is only intended to invoke those - * subcommands. - * - * @return string - */ - public function get_synopsis() { - return '<command>'; - } - - /** - * Get the usage for this composite command. - * - * @return string - */ - public function get_usage( $prefix ) { - return sprintf( "%s%s %s", - $prefix, - implode( ' ', get_path( $this ) ), - $this->get_synopsis() - ); - } - - /** - * Show the usage for all subcommands contained - * by the composite command. - */ - public function show_usage() { - $methods = $this->get_subcommands(); - - $i = 0; - - foreach ( $methods as $name => $subcommand ) { - $prefix = ( 0 == $i++ ) ? 'usage: ' : ' or: '; - - if ( \WP_CLI::get_runner()->is_command_disabled( $subcommand ) ) { - continue; - } - - \WP_CLI::line( $subcommand->get_usage( $prefix ) ); - } - - $cmd_name = implode( ' ', array_slice( get_path( $this ), 1 ) ); - - \WP_CLI::line(); - \WP_CLI::line( "See 'wp help $cmd_name <command>' for more information on a specific command." ); - } - - /** - * When a composite command is invoked, it shows usage - * docs for its subcommands. - * - * @param array $args - * @param array $assoc_args - * @param array $extra_args - */ - public function invoke( $args, $assoc_args, $extra_args ) { - $this->show_usage(); - } - - /** - * Given supplied arguments, find a contained - * subcommand - * - * @param array $args - * @return \WP_CLI\Dispatcher\Subcommand|false - */ - public function find_subcommand( &$args ) { - $name = array_shift( $args ); - - $subcommands = $this->get_subcommands(); - - if ( !isset( $subcommands[ $name ] ) ) { - $aliases = self::get_aliases( $subcommands ); - - if ( isset( $aliases[ $name ] ) ) { - $name = $aliases[ $name ]; - } - } - - if ( !isset( $subcommands[ $name ] ) ) - return false; - - return $subcommands[ $name ]; - } - - /** - * Get any registered aliases for this composite command's - * subcommands. - * - * @param array $subcommands - * @return array - */ - private static function get_aliases( $subcommands ) { - $aliases = array(); - - foreach ( $subcommands as $name => $subcommand ) { - $alias = $subcommand->get_alias(); - if ( $alias ) - $aliases[ $alias ] = $name; - } - - return $aliases; - } - - /** - * Composite commands can only be known by one name. - * - * @return false - */ - public function get_alias() { - return false; - } - - /*** - * Get the list of global parameters - * - * @param string $root_command whether to include or not root command specific description - * @return string - */ - protected function get_global_params( $root_command = false ) { - $binding = array(); - $binding['root_command'] = $root_command; - - if (! $this->can_have_subcommands() || ( is_object( $this->parent ) && get_class( $this->parent ) == 'WP_CLI\Dispatcher\CompositeCommand' )) { - $binding['is_subcommand'] = true; - } - - foreach ( \WP_CLI::get_configurator()->get_spec() as $key => $details ) { - if ( false === $details['runtime'] ) - continue; - - if ( isset( $details['deprecated'] ) ) - continue; - - if ( isset( $details['hidden'] ) ) - continue; - - if ( true === $details['runtime'] ) - $synopsis = "--[no-]$key"; - else - $synopsis = "--$key" . $details['runtime']; - - $binding['parameters'][] = array( - 'synopsis' => $synopsis, - 'desc' => $details['desc'] - ); - } - - if ( $this->get_subcommands() ) { - $binding['has_subcommands'] = true; - } - - return Utils\mustache_render( 'man-params.mustache', $binding ); - } -} - diff --git a/php/WP_CLI/Dispatcher/RootCommand.php b/php/WP_CLI/Dispatcher/RootCommand.php deleted file mode 100644 index 0b720aea0..000000000 --- a/php/WP_CLI/Dispatcher/RootCommand.php +++ /dev/null @@ -1,59 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -use \WP_CLI\Utils; - -/** - * The root node in the command tree. - * - * @package WP_CLI - */ -class RootCommand extends CompositeCommand { - - public function __construct() { - $this->parent = false; - - $this->name = 'wp'; - - $this->shortdesc = 'Manage WordPress through the command-line.'; - } - - /** - * Get the human-readable long description. - * - * @return string - */ - public function get_longdesc() { - return $this->get_global_params( true ); - } - - /** - * Find a subcommand registered on the root - * command. - * - * @param array $args - * @return \WP_CLI\Dispatcher\Subcommand|false - */ - public function find_subcommand( &$args ) { - $command = array_shift( $args ); - - Utils\load_command( $command ); - - if ( !isset( $this->subcommands[ $command ] ) ) { - return false; - } - - return $this->subcommands[ $command ]; - } - - /** - * Get all registered subcommands. - * - * @return array - */ - public function get_subcommands() { - return parent::get_subcommands(); - } -} - diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php deleted file mode 100644 index 2dd6b2750..000000000 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ /dev/null @@ -1,398 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -use WP_CLI; - -/** - * A leaf node in the command tree. - * - * @package WP_CLI - */ -class Subcommand extends CompositeCommand { - - private $alias; - - private $when_invoked; - - function __construct( $parent, $name, $docparser, $when_invoked ) { - parent::__construct( $parent, $name, $docparser ); - - $this->when_invoked = $when_invoked; - - $this->alias = $docparser->get_tag( 'alias' ); - - $this->synopsis = $docparser->get_synopsis(); - if ( !$this->synopsis && $this->longdesc ) { - $this->synopsis = self::extract_synopsis( $this->longdesc ); - } - } - - /** - * Extract the synopsis from PHPdoc string. - * - * @param string $longdesc Command docs via PHPdoc - * @return string - */ - private static function extract_synopsis( $longdesc ) { - preg_match_all( '/(.+?)[\r\n]+:/', $longdesc, $matches ); - return implode( ' ', $matches[1] ); - } - - /** - * Subcommands can't have subcommands because they - * represent code to be executed. - * - * @return bool - */ - function can_have_subcommands() { - return false; - } - - /** - * Get the synopsis string for this subcommand. - * A synopsis defines what runtime arguments are - * expected, useful to humans and argument validation. - * - * @return string - */ - function get_synopsis() { - return $this->synopsis; - } - - /** - * Set the synopsis string for this subcommand. - * - * @param string - */ - public function set_synopsis( $synopsis ) { - $this->synopsis = $synopsis; - } - - /** - * If an alias is set, grant access to it. - * Aliases permit subcommands to be instantiated - * with a secondary identity. - * - * @return string - */ - function get_alias() { - return $this->alias; - } - - /** - * Print the usage details to the end user. - * - * @param string $prefix - */ - function show_usage( $prefix = 'usage: ' ) { - \WP_CLI::line( $this->get_usage( $prefix ) ); - } - - /** - * Get the usage of the subcommand as a formatted string. - * - * @param string $prefix - * @return string - */ - function get_usage( $prefix ) { - return sprintf( "%s%s %s", - $prefix, - implode( ' ', get_path( $this ) ), - $this->get_synopsis() - ); - } - - /** - * Wrapper for CLI Tools' prompt() method. - * - * @param string $question - * @param string $default - * @return string|false - */ - private function prompt( $question, $default ) { - - $question .= ': '; - if ( function_exists( 'readline' ) ) { - return readline( $question ); - } else { - echo $question; - return stream_get_line( STDIN, 1024, PHP_EOL ); - } - } - - /** - * Interactively prompt the user for input - * based on defined synopsis and passed arguments. - * - * @param array $args - * @param array $assoc_args - * @return array - */ - private function prompt_args( $args, $assoc_args ) { - - $synopsis = $this->get_synopsis(); - - if ( ! $synopsis ) - return array( $args, $assoc_args ); - - $spec = array_filter( \WP_CLI\SynopsisParser::parse( $synopsis ), function( $spec_arg ) { - return in_array( $spec_arg['type'], array( 'generic', 'positional', 'assoc', 'flag' ) ); - }); - - $spec = array_values( $spec ); - - $prompt_args = WP_CLI::get_config( 'prompt' ); - if ( true !== $prompt_args ) { - $prompt_args = explode( ',', $prompt_args ); - } - - // 'positional' arguments are positional (aka zero-indexed) - // so $args needs to be reset before prompting for new arguments - $args = array(); - foreach( $spec as $key => $spec_arg ) { - - // When prompting for specific arguments (e.g. --prompt=user_pass), - // ignore all arguments that don't match - if ( is_array( $prompt_args ) ) { - if ( 'assoc' !== $spec_arg['type'] ) { - continue; - } - if ( ! in_array( $spec_arg['name'], $prompt_args, true ) ) { - continue; - } - } - - $current_prompt = ( $key + 1 ) . '/' . count( $spec ) . ' '; - $default = ( $spec_arg['optional'] ) ? '' : false; - - // 'generic' permits arbitrary key=value (e.g. [--<field>=<value>] ) - if ( 'generic' == $spec_arg['type'] ) { - - list( $key_token, $value_token ) = explode( '=', $spec_arg['token'] ); - - $repeat = false; - do { - if ( ! $repeat ) - $key_prompt = $current_prompt . $key_token; - else - $key_prompt = str_repeat( " ", strlen( $current_prompt ) ) . $key_token; - - $key = $this->prompt( $key_prompt, $default ); - if ( false === $key ) - return array( $args, $assoc_args ); - - if ( $key ) { - $key_prompt_count = strlen( $key_prompt ) - strlen( $value_token ) - 1; - $value_prompt = str_repeat( " ", $key_prompt_count ) . '=' . $value_token; - - $value = $this->prompt( $value_prompt, $default ); - if ( false === $value ) - return array( $args, $assoc_args ); - - $assoc_args[$key] = $value; - - $repeat = true; - $required = false; - } else { - $repeat = false; - } - - } while( $required || $repeat ); - - } else { - - $prompt = $current_prompt . $spec_arg['token']; - if ( 'flag' == $spec_arg['type'] ) - $prompt .= ' (Y/n)'; - - $response = $this->prompt( $prompt, $default ); - if ( false === $response ) - return array( $args, $assoc_args ); - - if ( $response ) { - switch ( $spec_arg['type'] ) { - case 'positional': - if ( $spec_arg['repeating'] ) - $response = explode( ' ', $response ); - else - $response = array( $response ); - $args = array_merge( $args, $response ); - break; - case 'assoc': - $assoc_args[$spec_arg['name']] = $response; - break; - case 'flag': - if ( 'Y' == $response ) - $assoc_args[$spec_arg['name']] = true; - break; - } - } - } - } - - return array( $args, $assoc_args ); - } - - /** - * Validate the supplied arguments to the command. - * Throws warnings or errors if arguments are missing - * or invalid. - * - * @param array $args - * @param array $assoc_args - * @param array $extra_args - * @return array list of invalid $assoc_args keys to unset - */ - private function validate_args( $args, $assoc_args, $extra_args ) { - $synopsis = $this->get_synopsis(); - if ( !$synopsis ) { - return array( array(), $args, $assoc_args, $extra_args ); - } - - $validator = new \WP_CLI\SynopsisValidator( $synopsis ); - - $cmd_path = implode( ' ', get_path( $this ) ); - foreach ( $validator->get_unknown() as $token ) { - \WP_CLI::warning( sprintf( - "The `%s` command has an invalid synopsis part: %s", - $cmd_path, $token - ) ); - } - - if ( !$validator->enough_positionals( $args ) ) { - $this->show_usage(); - exit(1); - } - - $unknown_positionals = $validator->unknown_positionals( $args ); - if ( !empty( $unknown_positionals ) ) { - \WP_CLI::error( 'Too many positional arguments: ' . - implode( ' ', $unknown_positionals ) ); - } - - $synopsis_spec = \WP_CLI\SynopsisParser::parse( $synopsis ); - $i = 0; - $errors = array( 'fatal' => array(), 'warning' => array() ); - $mock_doc = array( $this->get_shortdesc(), '' ); - $mock_doc = array_merge( $mock_doc, explode( PHP_EOL, $this->get_longdesc() ) ); - $mock_doc = '/**' . PHP_EOL . '* ' . implode( PHP_EOL . '* ', $mock_doc ) . PHP_EOL . '*/'; - $docparser = new \WP_CLI\DocParser( $mock_doc ); - foreach( $synopsis_spec as $spec ) { - if ( 'positional' === $spec['type'] ) { - $spec_args = $docparser->get_arg_args( $spec['name'] ); - if ( ! isset( $args[ $i ] ) ) { - if ( isset( $spec_args['default'] ) ) { - $args[ $i ] = $spec_args['default']; - } - } - if ( isset( $spec_args['options'] ) ) { - if ( ! empty( $spec['repeating'] ) ) { - do { - if ( isset( $args[ $i ] ) && ! in_array( $args[ $i ], $spec_args['options'] ) ) { - \WP_CLI::error( 'Invalid value specified for positional arg.' ); - } - $i++; - } while ( isset( $args[ $i ] ) ); - } else { - if ( isset( $args[ $i ] ) && ! in_array( $args[ $i ], $spec_args['options'] ) ) { - \WP_CLI::error( 'Invalid value specified for positional arg.' ); - } - } - } - $i++; - } else if ( 'assoc' === $spec['type'] ) { - $spec_args = $docparser->get_param_args( $spec['name'] ); - if ( ! isset( $assoc_args[ $spec['name'] ] ) && ! isset( $extra_args[ $spec['name'] ] ) ) { - if ( isset( $spec_args['default'] ) ) { - $assoc_args[ $spec['name'] ] = $spec_args['default']; - } - } - if ( isset( $assoc_args[ $spec['name'] ] ) && isset( $spec_args['options'] ) ) { - if ( ! in_array( $assoc_args[ $spec['name'] ], $spec_args['options'] ) ) { - $errors['fatal'][ $spec['name'] ] = "Invalid value specified for '{$spec['name']}'"; - } - } - } - } - - list( $returned_errors, $to_unset ) = $validator->validate_assoc( - array_merge( \WP_CLI::get_config(), $extra_args, $assoc_args ) - ); - foreach( array( 'fatal', 'warning' ) as $error_type ) { - $errors[ $error_type ] = array_merge( $errors[ $error_type ], $returned_errors[ $error_type ] ); - } - - if ( $this->name != 'help' ) { - foreach ( $validator->unknown_assoc( $assoc_args ) as $key ) { - $errors['fatal'][] = "unknown --$key parameter"; - } - } - - if ( !empty( $errors['fatal'] ) ) { - $out = 'Parameter errors:'; - foreach ( $errors['fatal'] as $key => $error ) { - $out .= "\n {$error}"; - if ( $desc = $docparser->get_param_desc( $key ) ) { - $out .= " ({$desc})"; - } - } - - \WP_CLI::error( $out ); - } - - array_map( '\\WP_CLI::warning', $errors['warning'] ); - - return array( $to_unset, $args, $assoc_args, $extra_args ); - } - - /** - * Invoke the subcommand with the supplied arguments. - * Given a --prompt argument, interactively request input - * from the end user. - * - * @param array $args - * @param array $assoc_args - */ - public function invoke( $args, $assoc_args, $extra_args ) { - static $prompted_once = false; - if ( \WP_CLI::get_config( 'prompt' ) && ! $prompted_once ) { - list( $args, $assoc_args ) = $this->prompt_args( $args, $assoc_args ); - $prompted_once = true; - } - - $extra_positionals = array(); - foreach( $extra_args as $k => $v ) { - if ( is_numeric( $k ) ) { - if ( ! isset( $args[ $k ] ) ) { - $extra_positionals[ $k ] = $v; - } - unset( $extra_args[ $k ] ); - } - } - $args = $args + $extra_positionals; - - list( $to_unset, $args, $assoc_args, $extra_args ) = $this->validate_args( $args, $assoc_args, $extra_args ); - - foreach ( $to_unset as $key ) { - unset( $assoc_args[ $key ] ); - } - - $path = get_path( $this->get_parent() ); - $parent = implode( ' ', array_slice( $path, 1 ) ); - $cmd = $this->name; - if ( $parent ) { - WP_CLI::do_hook( "before_invoke:{$parent}" ); - $cmd = $parent . ' ' . $cmd; - } - WP_CLI::do_hook( "before_invoke:{$cmd}" ); - - call_user_func( $this->when_invoked, $args, array_merge( $extra_args, $assoc_args ) ); - - if ( $parent ) { - WP_CLI::do_hook( "after_invoke:{$parent}" ); - } - WP_CLI::do_hook( "after_invoke:{$cmd}" ); - } -} - diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php deleted file mode 100644 index 7d3df5532..000000000 --- a/php/WP_CLI/DocParser.php +++ /dev/null @@ -1,190 +0,0 @@ -<?php - -namespace WP_CLI; - -use Spyc; - -/** - * Parse command attributes from its PHPdoc. - * Used to determine execution characteristics (arguments, etc.). - */ -class DocParser { - - /** - * @var string $docComment PHPdoc command for the command. - */ - protected $docComment; - - /** - * @param string $docComment - */ - public function __construct( $docComment ) { - $this->docComment = self::remove_decorations( $docComment ); - } - - /** - * Remove unused cruft from PHPdoc comment. - * - * @param string $comment PHPdoc comment. - * @return string - */ - private static function remove_decorations( $comment ) { - $comment = preg_replace( '|^/\*\*[\r\n]+|', '', $comment ); - $comment = preg_replace( '|\n[\t ]*\*/$|', '', $comment ); - $comment = preg_replace( '|^[\t ]*\* ?|m', '', $comment ); - - return $comment; - } - - /** - * Get the command's short description (e.g. summary). - * - * @return string - */ - public function get_shortdesc() { - if ( !preg_match( '|^([^@][^\n]+)\n*|', $this->docComment, $matches ) ) - return ''; - - return $matches[1]; - } - - /** - * Get the command's full description - * - * @return string - */ - public function get_longdesc() { - $shortdesc = $this->get_shortdesc(); - if ( !$shortdesc ) - return ''; - - $longdesc = substr( $this->docComment, strlen( $shortdesc ) ); - - $lines = array(); - foreach ( explode( "\n", $longdesc ) as $line ) { - if ( 0 === strpos( $line, '@' ) ) - break; - - $lines[] = $line; - } - $longdesc = trim( implode( $lines, "\n" ) ); - - return $longdesc; - } - - /** - * Get the value for a given tag (e.g. "@alias" or "@subcommand") - * - * @param string $name Name for the tag, without '@' - * @return string - */ - public function get_tag( $name ) { - if ( preg_match( '|^@' . $name . '\s+([a-z-_]+)|m', $this->docComment, $matches ) ) - return $matches[1]; - - return ''; - } - - /** - * Get the command's synopsis. - * - * @return string - */ - public function get_synopsis() { - if ( !preg_match( '|^@synopsis\s+(.+)|m', $this->docComment, $matches ) ) - return ''; - - return $matches[1]; - } - - /** - * Get the description for a given argument. - * - * @param string $name Argument's doc name. - * @return string - */ - public function get_arg_desc( $name ) { - - if ( preg_match( "/\[?<{$name}>.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { - return $matches[1]; - } - - return ''; - - } - - /** - * Get the arguments for a given argument. - * - * @param string $name Argument's doc name. - * @return mixed|null - */ - public function get_arg_args( $name ) { - return $this->get_arg_or_param_args( "/^\[?<{$name}>.*/" ); - } - - /** - * Get the description for a given parameter. - * - * @param string $key Parameter's key. - * @return string - */ - public function get_param_desc( $key ) { - - if ( preg_match( "/\[?--{$key}=.+\n: (.+?)(\n|$)/", $this->docComment, $matches ) ) { - return $matches[1]; - } - - return ''; - } - - /** - * Get the arguments for a given parameter. - * - * @param string $key Parameter's key. - * @return mixed|null - */ - public function get_param_args( $key ) { - return $this->get_arg_or_param_args( "/^\[?--{$key}=.*/" ); - } - - /** - * Get the args for an arg or param - * - * @param string $regex Pattern to match against - * @return array|null Interpreted YAML document, or null. - */ - private function get_arg_or_param_args( $regex ) { - $bits = explode( PHP_EOL, $this->docComment ); - $within_arg = $within_doc = false; - $document = array(); - foreach( $bits as $bit ) { - if ( preg_match( $regex, $bit ) ) { - $within_arg = true; - } - - if ( $within_arg && $within_doc && '---' === $bit ) { - $within_doc = false; - } - - if ( $within_arg && ! $within_doc && '---' === $bit ) { - $within_doc = true; - } - - if ( $within_doc ) { - $document[] = $bit; - } - - if ( $within_arg && '' === $bit ) { - $within_arg = false; - break; - } - } - - if ( $document ) { - return Spyc::YAMLLoadString( implode( PHP_EOL, $document ) ); - } - return null; - } - -} diff --git a/php/WP_CLI/ExitException.php b/php/WP_CLI/ExitException.php deleted file mode 100644 index 8a86dc3e0..000000000 --- a/php/WP_CLI/ExitException.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -namespace WP_CLI; - -class ExitException extends \Exception {} diff --git a/php/WP_CLI/Extractor.php b/php/WP_CLI/Extractor.php deleted file mode 100644 index 5d99c78ac..000000000 --- a/php/WP_CLI/Extractor.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php - -namespace WP_CLI; - -use Exception; -use PharData; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use WP_CLI; -use WP_CLI\Utils; -use ZipArchive; - -/** - * Extract a provided archive file. - */ -class Extractor { - - /** - * Extract the archive file to a specific destination. - * - * @param string $dest - */ - public static function extract( $tarball_or_zip, $dest ) { - if ( preg_match( '/\.zip$/', $tarball_or_zip ) ) { - return self::extract_zip( $tarball_or_zip, $dest ); - } - - if ( preg_match( '/\.tar\.gz$/', $tarball_or_zip ) ) { - return self::extract_tarball( $tarball_or_zip, $dest ); - } - throw new \Exception( 'Extension not supported.' ); - } - - /** - * Extract a ZIP file to a specific destination. - * - * @param string $zipfile - * @param string $dest - */ - private static function extract_zip( $zipfile, $dest ) { - if ( ! class_exists( 'ZipArchive' ) ) { - throw new Exception( 'Extracting a zip file requires ZipArchive.' ); - } - $zip = new ZipArchive(); - $res = $zip->open( $zipfile ); - if ( true === $res ) { - $tempdir = implode( DIRECTORY_SEPARATOR, Array ( - dirname( $zipfile ), - Utils\basename( $zipfile, '.zip' ), - $zip->getNameIndex( 0 ) - ) ); - - $zip->extractTo( dirname( $tempdir ) ); - $zip->close(); - - self::copy_overwrite_files( $tempdir, $dest ); - self::rmdir( dirname( $tempdir ) ); - } else { - throw Exception( $res ); - } - } - - /** - * Extract a tarball to a specific destination. - * - * @param string $tarball - * @param string $dest - */ - private static function extract_tarball( $tarball, $dest ) { - if ( ! class_exists( 'PharData' ) ) { - $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; - WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); - return; - } - $phar = new PharData( $tarball ); - $tempdir = implode( DIRECTORY_SEPARATOR, Array ( - dirname( $tarball ), - Utils\basename( $tarball, '.tar.gz' ), - $phar->getFileName() - ) ); - - $phar->extractTo( dirname( $tempdir ), null, true ); - - self::copy_overwrite_files( $tempdir, $dest ); - - self::rmdir( dirname( $tempdir ) ); - } - - public static function copy_overwrite_files( $source, $dest ) { - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::SELF_FIRST); - - $error = 0; - - if ( ! is_dir( $dest ) ) { - mkdir( $dest, 0777, true ); - } - - foreach ( $iterator as $item ) { - - $dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName(); - - if ( $item->isDir() ) { - if ( !is_dir( $dest_path ) ) { - mkdir( $dest_path ); - } - } else { - if ( file_exists( $dest_path ) && is_writable( $dest_path ) ) { - copy( $item, $dest_path ); - } elseif ( ! file_exists( $dest_path ) ) { - copy( $item, $dest_path ); - } else { - $error = 1; - WP_CLI::warning( "Unable to copy '" . $iterator->getSubPathName() . "' to current directory." ); - } - } - } - - if ( $error ) { - throw new Exception( 'There was an error overwriting existing files.' ); - } - } - - public static function rmdir( $dir ) { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ( $files as $fileinfo ) { - $todo = $fileinfo->isDir() ? 'rmdir' : 'unlink'; - $todo( $fileinfo->getRealPath() ); - } - rmdir( $dir ); - } - -} diff --git a/php/WP_CLI/Fetchers/Base.php b/php/WP_CLI/Fetchers/Base.php deleted file mode 100644 index 639efe103..000000000 --- a/php/WP_CLI/Fetchers/Base.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress entity for use in a subcommand. - */ -abstract class Base { - - /** - * @var string $msg The message to display when an item is not found - */ - protected $msg; - - /** - * @param string $arg The raw CLI argument - * @return mixed|false The item if found; false otherwise - */ - abstract public function get( $arg ); - - /** - * Like get(), but calls WP_CLI::error() instead of returning false. - * - * @param string $arg The raw CLI argument - */ - public function get_check( $arg ) { - $item = $this->get( $arg ); - - if ( ! $item ) { - \WP_CLI::error( sprintf( $this->msg, $arg ) ); - } - - return $item; - } - - /** - * @param array The raw CLI arguments - * @return array The list of found items - */ - public function get_many( $args ) { - $items = array(); - - foreach ( $args as $arg ) { - $item = $this->get( $arg ); - - if ( $item ) { - $items[] = $item; - } else { - \WP_CLI::warning( sprintf( $this->msg, $arg ) ); - } - } - - return $items; - } -} - diff --git a/php/WP_CLI/Fetchers/Comment.php b/php/WP_CLI/Fetchers/Comment.php deleted file mode 100644 index 0cf0f9a0c..000000000 --- a/php/WP_CLI/Fetchers/Comment.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress comment based on one of its attributes. - */ -class Comment extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "Could not find the comment with ID %d."; - - /** - * Get a comment object by ID - * - * @param int $arg - * @return object|false - */ - public function get( $arg ) { - $comment_id = (int) $arg; - $comment = get_comment( $comment_id ); - - if ( is_null( $comment ) ) { - return false; - } - - return $comment; - } -} - diff --git a/php/WP_CLI/Fetchers/Plugin.php b/php/WP_CLI/Fetchers/Plugin.php deleted file mode 100644 index 13ccfaf25..000000000 --- a/php/WP_CLI/Fetchers/Plugin.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress plugin based on one of its attributes. - */ -class Plugin extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "The '%s' plugin could not be found."; - - /** - * Get a plugin object by name - * - * @param string $name - * @return object|false - */ - public function get( $name ) { - foreach ( get_plugins() as $file => $_ ) { - if ( $file === "$name.php" || - ( $name && $file === $name ) || - ( dirname( $file ) === $name && $name !== '.' ) ) { - return (object) compact( 'name', 'file' ); - } - } - - return false; - } -} - diff --git a/php/WP_CLI/Fetchers/Post.php b/php/WP_CLI/Fetchers/Post.php deleted file mode 100644 index 20b7d9855..000000000 --- a/php/WP_CLI/Fetchers/Post.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress post based on one of its attributes. - */ -class Post extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "Could not find the post with ID %d."; - - /** - * Get a post object by ID - * - * @param int $arg - * @return WP_Post|false - */ - public function get( $arg ) { - return get_post( $arg ); - } -} - diff --git a/php/WP_CLI/Fetchers/Site.php b/php/WP_CLI/Fetchers/Site.php deleted file mode 100644 index 981e52b41..000000000 --- a/php/WP_CLI/Fetchers/Site.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress site based on one of its attributes. - */ -class Site extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "Could not find the site with ID %d."; - - /** - * Get a site object by ID - * - * @param int $site_id - * @return object|false - */ - public function get( $site_id ) { - return $this->_get_site( $site_id ); - } - - /** - * Get site (blog) data for a given id. - * - * @param int $site_id - * @return bool|array False if no site found with given id, array otherwise - */ - private function _get_site( $site_id ) { - global $wpdb; - - // Load site data - $site = $wpdb->get_row( $wpdb->prepare( - "SELECT * FROM $wpdb->blogs WHERE blog_id = %d", $site_id ) ); - - if ( !empty( $site ) ) { - // Only care about domain and path which are set here - return $site; - } - - return false; - } -} diff --git a/php/WP_CLI/Fetchers/Theme.php b/php/WP_CLI/Fetchers/Theme.php deleted file mode 100644 index d72a7ad12..000000000 --- a/php/WP_CLI/Fetchers/Theme.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress theme based on one of its attributes. - */ -class Theme extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "The '%s' theme could not be found."; - - /** - * Get a theme object by name - * - * @param string $name - * @return object|false - */ - public function get( $name ) { - $theme = wp_get_theme( $name ); - - if ( !$theme->exists() ) { - return false; - } - - return $theme; - } -} - diff --git a/php/WP_CLI/Fetchers/User.php b/php/WP_CLI/Fetchers/User.php deleted file mode 100644 index e7fe2f93d..000000000 --- a/php/WP_CLI/Fetchers/User.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -namespace WP_CLI\Fetchers; - -/** - * Fetch a WordPress user based on one of its attributes. - */ -class User extends Base { - - /** - * @var string $msg Error message to use when invalid data is provided - */ - protected $msg = "Invalid user ID, email or login: '%s'"; - - /** - * Get a user object by one of its identifying attributes - * - * @param mixed $id_email_or_login - * @return WP_User|false - */ - public function get( $id_email_or_login ) { - - if ( is_numeric( $id_email_or_login ) ) - $user = get_user_by( 'id', $id_email_or_login ); - else if ( is_email( $id_email_or_login ) ) - $user = get_user_by( 'email', $id_email_or_login ); - else - $user = get_user_by( 'login', $id_email_or_login ); - - return $user; - } -} - diff --git a/php/WP_CLI/FileCache.php b/php/WP_CLI/FileCache.php deleted file mode 100644 index 623807007..000000000 --- a/php/WP_CLI/FileCache.php +++ /dev/null @@ -1,335 +0,0 @@ -<?php - -/* - * This file is heavily inspired and use code from Composer(getcomposer.org), - * in particular Composer/Cache and Composer/Util/FileSystem from 1.0.0-alpha7 - * - * The original code and this file are both released under MIT license. - * - * The copyright holders of the original code are: - * (c) Nils Adermann <naderman@naderman.de> - * Jordi Boggiano <j.boggiano@seld.be> - */ - -namespace WP_CLI; - -use Symfony\Component\Finder\Finder; - -/** - * Reads/writes to a filesystem cache - */ -class FileCache { - - /** - * @var string cache path - */ - protected $root; - /** - * @var bool - */ - protected $enabled = true; - /** - * @var int files time to live - */ - protected $ttl; - /** - * @var int max total size - */ - protected $maxSize; - /** - * @var string key allowed chars (regex class) - */ - protected $whitelist; - - /** - * @param string $cacheDir location of the cache - * @param int $ttl cache files default time to live (expiration) - * @param int $maxSize max total cache size - * @param string $whitelist List of characters that are allowed in path names (used in a regex character class) - */ - public function __construct( $cacheDir, $ttl, $maxSize, $whitelist = 'a-z0-9._-' ) { - $this->root = rtrim( $cacheDir, '/\\' ) . '/'; - $this->ttl = (int) $ttl; - $this->maxSize = (int) $maxSize; - $this->whitelist = $whitelist; - - if ( !$this->ensure_dir_exists( $this->root ) ) { - $this->enabled = false; - } - - } - - /** - * Cache is enabled - * - * @return bool - */ - public function is_enabled() { - return $this->enabled; - } - - /** - * Cache root - * - * @return string - */ - public function get_root() { - return $this->root; - } - - - /** - * Check if a file is in cache and return its filename - * - * @param string $key cache key - * @param int $ttl time to live - * @return bool|string filename or false - */ - public function has( $key, $ttl = null ) { - if ( !$this->enabled ) { - return false; - } - - $filename = $this->filename( $key ); - - if ( !file_exists( $filename ) ) { - return false; - } - - // use ttl param or global ttl - if ( $ttl === null ) { - $ttl = $this->ttl; - } elseif ( $this->ttl > 0 ) { - $ttl = min( (int) $ttl, $this->ttl ); - } else { - $ttl = (int) $ttl; - } - - // - if ( $ttl > 0 && filemtime( $filename ) + $ttl < time() ) { - if ( $this->ttl > 0 && $ttl >= $this->ttl ) { - unlink( $filename ); - } - return false; - } - - return $filename; - } - - /** - * Write to cache file - * - * @param string $key cache key - * @param string $contents file contents - * @return bool - */ - public function write( $key, $contents ) { - $filename = $this->prepare_write( $key ); - - if ( $filename ) { - return file_put_contents( $filename, $contents ) && touch( $filename ); - } else { - return false; - } - } - - /** - * Read from cache file - * - * @param string $key cache key - * @param int $ttl time to live - * @return bool|string file contents or false - */ - public function read( $key, $ttl = null ) { - $filename = $this->has( $key, $ttl ); - - if ( $filename ) { - return file_get_contents( $filename ); - } else { - return false; - } - } - - /** - * Copy a file into the cache - * - * @param string $key cache key - * @param string $source source filename - * @return bool - */ - public function import( $key, $source ) { - $filename = $this->prepare_write( $key ); - - if ( $filename ) { - return copy( $source, $filename ) && touch( $filename ); - } else { - return false; - } - } - - /** - * Copy a file out of the cache - * - * @param string $key cache key - * @param string $target target filename - * @param int $ttl time to live - * @return bool - */ - public function export( $key, $target, $ttl = null ) { - $filename = $this->has( $key, $ttl ); - - if ( $filename ) { - return copy( $filename, $target ); - } else { - return false; - } - } - - /** - * Remove file from cache - * - * @param string $key cache key - * @return bool - */ - public function remove( $key ) { - if ( !$this->enabled ) { - return false; - } - - $filename = $this->filename( $key ); - - if ( file_exists( $filename ) ) { - return unlink( $filename ); - } else { - return false; - } - } - - /** - * Clean cache based on time to live and max size - * - * @return bool - */ - public function clean() { - if ( !$this->enabled ) { - return false; - } - - $ttl = $this->ttl; - $maxSize = $this->maxSize; - - // unlink expired files - if ( $ttl > 0 ) { - try { - $expire = new \DateTime(); - } catch ( \Exception $e ) { - \WP_CLI::error( $e->getMessage() ); - } - $expire->modify( '-' . $ttl . ' seconds' ); - - $finder = $this->get_finder()->date( 'until ' . $expire->format( 'Y-m-d H:i:s' ) ); - foreach ( $finder as $file ) { - unlink( $file->getRealPath() ); - } - } - - // unlink older files if max cache size is exceeded - if ( $maxSize > 0 ) { - $files = array_reverse( iterator_to_array( $this->get_finder()->sortByAccessedTime()->getIterator() ) ); - $total = 0; - - foreach ( $files as $file ) { - if ( $total + $file->getSize() <= $maxSize ) { - $total += $file->getSize(); - } else { - unlink( $file->getRealPath() ); - } - } - } - - return true; - } - - /** - * Ensure directory exists - * - * @param string $dir directory - * @return bool - */ - protected function ensure_dir_exists( $dir ) { - if ( !is_dir( $dir ) ) { - if ( file_exists( $dir ) ) { - // exists and not a dir - return false; - } - if ( !@mkdir( $dir, 0777, true ) ) { - return false; - } - } - - return true; - } - - /** - * Prepare cache write - * - * @param string $key cache key - * @return bool|string filename or false - */ - protected function prepare_write( $key ) { - if ( !$this->enabled ) { - return false; - } - - $filename = $this->filename( $key ); - - if ( !$this->ensure_dir_exists( dirname( $filename ) ) ) { - return false; - } - - return $filename; - } - - /** - * Validate cache key - * - * @param string $key cache key - * @return string relative filename - */ - protected function validate_key( $key ) { - $url_parts = parse_url( $key ); - if ( ! empty($url_parts['scheme']) ) { // is url - $parts = array('misc'); - $parts[] = $url_parts['scheme'] . '-' . $url_parts['host'] . - ( empty( $url_parts['port'] ) ? '' : '-' . $url_parts['port'] ); - $parts[] = substr($url_parts['path'], 1) . - ( empty( $url_parts['query'] ) ? '' : '-' . $url_parts['query'] ); - } else { - $key = str_replace( '\\', '/', $key ); - $parts = explode( '/', ltrim( $key ) ); - } - - $parts = preg_replace( "#[^{$this->whitelist}]#i", '-', $parts ); - - return implode( '/', $parts ); - } - - /** - * Filename from key - * - * @param string $key - * @return string filename - */ - protected function filename( $key ){ - return $this->root . $this->validate_key( $key ); - } - - /** - * Get a Finder that iterates in cache root only the files - * - * @return Finder - */ - protected function get_finder() { - return Finder::create()->in( $this->root )->files(); - } -} diff --git a/php/WP_CLI/Formatter.php b/php/WP_CLI/Formatter.php deleted file mode 100644 index 5ab4bb529..000000000 --- a/php/WP_CLI/Formatter.php +++ /dev/null @@ -1,334 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Output one or more items in a given format (e.g. table, JSON). - */ -class Formatter { - - /** - * @var array $args How the items should be output. - */ - private $args; - - /** - * @var string $prefix Standard prefix for object fields. - */ - private $prefix; - - /** - * @param array $assoc_args Output format arguments. - * @param array $fields Fields to display of each item. - * @param string $prefix Check if fields have a standard prefix. - */ - public function __construct( &$assoc_args, $fields = null, $prefix = false ) { - $format_args = array( - 'format' => 'table', - 'fields' => $fields, - 'field' => null - ); - - foreach ( array( 'format', 'fields', 'field' ) as $key ) { - if ( isset( $assoc_args[ $key ] ) ) { - $format_args[ $key ] = $assoc_args[ $key ]; - unset( $assoc_args[ $key ] ); - } - } - - if ( ! is_array( $format_args['fields'] ) ) { - $format_args['fields'] = explode( ',', $format_args['fields'] ); - } - - $format_args['fields'] = array_map( 'trim', $format_args['fields'] ); - - $this->args = $format_args; - $this->prefix = $prefix; - } - - /** - * Magic getter for arguments. - * - * @param string $key - * @return mixed - */ - public function __get( $key ) { - return $this->args[ $key ]; - } - - /** - * Display multiple items according to the output arguments. - * - * @param array $items - */ - public function display_items( $items ) { - if ( $this->args['field'] ) { - $this->show_single_field( $items, $this->args['field'] ); - } else { - if ( in_array( $this->args['format'], array( 'csv', 'json', 'table' ) ) ) { - $item = is_array( $items ) && ! empty( $items ) ? array_shift( $items ) : false; - if ( $item && ! empty( $this->args['fields'] ) ) { - foreach( $this->args['fields'] as &$field ) { - $field = $this->find_item_key( $item, $field ); - } - array_unshift( $items, $item ); - } - } - - if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) ) { - if ( is_object( $items ) && is_a( $items, 'Iterator' ) ) { - $items = \WP_CLI\Utils\iterator_map( $items, array( $this, 'transform_item_values_to_json' ) ); - } else { - $items = array_map( array( $this, 'transform_item_values_to_json' ), $items ); - } - } - - $this->format( $items ); - } - } - - /** - * Display a single item according to the output arguments. - * - * @param mixed $item - */ - public function display_item( $item ) { - if ( isset( $this->args['field'] ) ) { - $item = (object) $item; - $key = $this->find_item_key( $item, $this->args['field'] ); - $value = $item->$key; - if ( in_array( $this->args['format'], array( 'table', 'csv' ) ) && ( is_object( $value ) || is_array( $value ) ) ) { - $value = json_encode( $value ); - } - \WP_CLI::print_value( $value, array( 'format' => $this->args['format'] ) ); - } else { - $this->show_multiple_fields( $item, $this->args['format'] ); - } - } - - /** - * Format items according to arguments. - * - * @param array $items - */ - private function format( $items ) { - $fields = $this->args['fields']; - - switch ( $this->args['format'] ) { - case 'count': - if ( !is_array( $items ) ) { - $items = iterator_to_array( $items ); - } - echo count( $items ); - break; - - case 'ids': - if ( !is_array( $items ) ) { - $items = iterator_to_array( $items ); - } - echo implode( ' ', $items ); - break; - - case 'table': - self::show_table( $items, $fields ); - break; - - case 'csv': - \WP_CLI\Utils\write_csv( STDOUT, $items, $fields ); - break; - - case 'json': - case 'yaml': - $out = array(); - foreach ( $items as $item ) { - $out[] = \WP_CLI\Utils\pick_fields( $item, $fields ); - } - - if ( 'json' === $this->args['format'] ) { - echo json_encode( $out ); - } else if ( 'yaml' === $this->args['format'] ) { - echo \Spyc::YAMLDump( $out, 2, 0 ); - } - break; - - default: - \WP_CLI::error( 'Invalid format: ' . $this->args['format'] ); - } - } - - /** - * Show a single field from a list of items. - * - * @param array Array of objects to show fields from - * @param string The field to show - */ - private function show_single_field( $items, $field ) { - $key = null; - $values = array(); - - foreach ( $items as $item ) { - $item = (object) $item; - - if ( null === $key ) { - $key = $this->find_item_key( $item, $field ); - } - - if ( 'json' == $this->args['format'] ) { - $values[] = $item->$key; - } else { - \WP_CLI::print_value( $item->$key, array( 'format' => $this->args['format'] ) ); - } - } - - if ( 'json' == $this->args['format'] ) { - echo json_encode( $values ); - } - } - - /** - * Find an object's key. - * If $prefix is set, a key with that prefix will be prioritized. - * - * @param object $item - * @param string $field - * @return string $key - */ - private function find_item_key( $item, $field ) { - foreach ( array( $field, $this->prefix . '_' . $field ) as $maybe_key ) { - if ( ( is_object( $item ) && ( property_exists( $item, $maybe_key ) || isset( $item->$maybe_key ) ) ) || ( is_array( $item ) && array_key_exists( $maybe_key, $item ) ) ) { - $key = $maybe_key; - break; - } - } - - if ( ! isset( $key ) ) { - \WP_CLI::error( "Invalid field: $field." ); - } - - return $key; - } - - /** - * Show multiple fields of an object. - * - * @param object|array Data to display - * @param string Format to display the data in - */ - private function show_multiple_fields( $data, $format ) { - - $true_fields = array(); - foreach( $this->args['fields'] as $field ) { - $true_fields[] = $this->find_item_key( $data, $field ); - } - - foreach( $data as $key => $value ) { - if ( ! in_array( $key, $true_fields ) ) { - if ( is_array( $data ) ) { - unset( $data[ $key ] ); - } else if ( is_object( $data ) ) { - unset( $data->$key ); - } - } - } - - switch ( $format ) { - - case 'table': - case 'csv': - $rows = $this->assoc_array_to_rows( $data ); - $fields = array( 'Field', 'Value' ); - if ( 'table' == $format ) { - self::show_table( $rows, $fields ); - } else if ( 'csv' == $format ) { - \WP_CLI\Utils\write_csv( STDOUT, $rows, $fields ); - } - break; - - case 'yaml': - case 'json': - \WP_CLI::print_value( $data, array( 'format' => $format ) ); - break; - - default: - \WP_CLI::error( "Invalid format: " . $format ); - break; - - } - - } - - /** - * Show items in a \cli\Table. - * - * @param array $items - * @param array $fields - */ - private static function show_table( $items, $fields ) { - $table = new \cli\Table(); - - $enabled = \cli\Colors::shouldColorize(); - if ( $enabled ) { - \cli\Colors::disable( true ); - } - - $table->setHeaders( $fields ); - - foreach ( $items as $item ) { - $table->addRow( array_values( \WP_CLI\Utils\pick_fields( $item, $fields ) ) ); - } - - foreach( $table->getDisplayLines() as $line ) { - \WP_CLI::line( $line ); - } - - if ( $enabled ) { - \cli\Colors::enable( true ); - } - } - - /** - * Format an associative array as a table. - * - * @param array $fields Fields and values to format - * @return array $rows - */ - private function assoc_array_to_rows( $fields ) { - $rows = array(); - - foreach ( $fields as $field => $value ) { - - if ( ! is_string( $value ) ) { - $value = json_encode( $value ); - } - - $rows[] = (object) array( - 'Field' => $field, - 'Value' => $value - ); - } - - return $rows; - } - - /** - * Transforms objects and arrays to JSON as necessary - * - * @param mixed $item - * @return mixed - */ - public function transform_item_values_to_json( $item ) { - foreach( $this->args['fields'] as $field ) { - $true_field = $this->find_item_key( $item, $field ); - $value = is_object( $item ) ? $item->$true_field : $item[ $true_field ]; - if ( is_array( $value ) || is_object( $value ) ) { - if ( is_object( $item ) ) { - $item->$true_field = json_encode( $value ); - } else if ( is_array( $item ) ) { - $item[ $true_field ] = json_encode( $value ); - } - } - } - return $item; - } - -} diff --git a/php/WP_CLI/Iterators/CSV.php b/php/WP_CLI/Iterators/CSV.php deleted file mode 100644 index a349a3e3a..000000000 --- a/php/WP_CLI/Iterators/CSV.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php - -namespace WP_CLI\Iterators; - -/** - * Allows incrementally reading and parsing lines from a CSV file. - */ -class CSV implements \Iterator { - - const ROW_SIZE = 4096; - - private $filePointer; - - private $delimiter; - private $columns; - - private $currentIndex; - private $currentElement; - - public function __construct( $filename, $delimiter = ',' ) { - $this->filePointer = fopen( $filename, 'r' ); - if ( !$this->filePointer ) { - \WP_CLI::error( sprintf( 'Could not open file: %s', $filename ) ); - } - - $this->delimiter = $delimiter; - } - - public function rewind() { - rewind( $this->filePointer ); - - $this->columns = fgetcsv( $this->filePointer, self::ROW_SIZE, $this->delimiter ); - - $this->currentIndex = -1; - $this->next(); - } - - public function current() { - return $this->currentElement; - } - - public function key() { - return $this->currentIndex; - } - - public function next() { - $this->currentElement = false; - - while ( true ) { - $str = fgets( $this->filePointer ); - - if ( false === $str ) - break; - - $row = str_getcsv( $str, $this->delimiter ); - - $element = array(); - foreach ( $this->columns as $i => $key ) { - if ( isset( $row[ $i ] ) ) - $element[ $key ] = $row[ $i ]; - } - - if ( !empty( $element ) ) { - $this->currentElement = $element; - $this->currentIndex++; - - break; - } - } - } - - public function valid() { - return is_array( $this->currentElement ); - } -} - diff --git a/php/WP_CLI/Iterators/Exception.php b/php/WP_CLI/Iterators/Exception.php deleted file mode 100644 index e7320e077..000000000 --- a/php/WP_CLI/Iterators/Exception.php +++ /dev/null @@ -1,6 +0,0 @@ -<?php - -namespace WP_CLI\Iterators; - -class Exception extends \RuntimeException {} - diff --git a/php/WP_CLI/Iterators/Query.php b/php/WP_CLI/Iterators/Query.php deleted file mode 100644 index a5fdec554..000000000 --- a/php/WP_CLI/Iterators/Query.php +++ /dev/null @@ -1,127 +0,0 @@ -<?php - -namespace WP_CLI\Iterators; - -/** - * Iterates over results of a query, split into many queries via LIMIT and OFFSET - * - * @source https://gist.github.com/4060005 - */ -class Query implements \Iterator { - - private $chunk_size; - private $query = ''; - private $count_query = ''; - - private $global_index = 0; - private $index_in_results = 0; - private $results = array(); - private $row_count = 0; - private $offset = 0; - private $db = null; - private $depleted = false; - - /** - * Creates a new query iterator - * - * This will loop over all users, but will retrieve them 100 by 100: - * <code> - * foreach( new Iterators\Query( 'SELECT * FROM users', 100 ) as $user ) { - * tickle( $user ); - * } - * </code> - * - * @param string $query The query as a string. It shouldn't include any LIMIT clauses - * @param number $chunk_size How many rows to retrieve at once; default value is 500 (optional) - */ - public function __construct( $query, $chunk_size = 500 ) { - $this->query = $query; - - $this->count_query = preg_replace( '/^.*? FROM /', 'SELECT COUNT(*) FROM ', $query, 1, $replacements ); - if ( $replacements != 1 ) - $this->count_query = ''; - - $this->chunk_size = $chunk_size; - - $this->db = $GLOBALS['wpdb']; - } - - /** - * Reduces the offset when the query row count shrinks - * - * In cases where the iterated rows are being updated such that they will no - * longer be returned by the original query, the offset must be reduced to - * iterate over all remaining rows. - */ - private function adjust_offset_for_shrinking_result_set() { - if ( empty( $this->count_query ) ) - return; - - $row_count = $this->db->get_var( $this->count_query ); - - if ( $row_count < $this->row_count ) - $this->offset -= $this->row_count - $row_count; - - $this->row_count = $row_count; - } - - private function load_items_from_db() { - $this->adjust_offset_for_shrinking_result_set(); - - $query = $this->query . sprintf( ' LIMIT %d OFFSET %d', $this->chunk_size, $this->offset ); - $this->results = $this->db->get_results( $query ); - - if ( !$this->results ) { - if ( $this->db->last_error ) { - throw new Exception( 'Database error: ' . $this->db->last_error ); - } else { - return false; - } - } - - $this->offset += $this->chunk_size; - return true; - } - - function current() { - return $this->results[ $this->index_in_results ]; - } - - function key() { - return $this->global_index; - } - - function next() { - $this->index_in_results++; - $this->global_index++; - } - - function rewind() { - $this->results = array(); - $this->global_index = 0; - $this->index_in_results = 0; - $this->offset = 0; - $this->depleted = false; - } - - function valid() { - if ( $this->depleted ) { - return false; - } - - if ( !isset( $this->results[ $this->index_in_results ] ) ) { - $items_loaded = $this->load_items_from_db(); - - if ( !$items_loaded ) { - $this->rewind(); - $this->depleted = true; - return false; - } - - $this->index_in_results = 0; - } - - return true; - } -} - diff --git a/php/WP_CLI/Iterators/Table.php b/php/WP_CLI/Iterators/Table.php deleted file mode 100644 index c05c52ea9..000000000 --- a/php/WP_CLI/Iterators/Table.php +++ /dev/null @@ -1,85 +0,0 @@ -<?php - -namespace WP_CLI\Iterators; - -/** - * @source https://gist.github.com/4060005 - */ -class Table extends Query { - - /** - * Creates an iterator over a database table. - * - * <code> - * foreach( new Iterators\Table( array( 'table' => $wpdb->posts, 'fields' => array( 'ID', 'post_content' ) ) ) as $post ) { - * count_words_for( $post->ID, $post->post_content ); - * } - * </code> - * - * <code> - * foreach( new Iterators\Table( array( 'table' => $wpdb->posts, 'where' => 'ID = 8 OR post_status = "publish"' ) ) as $post ) { - * … - * } - * </code> - * - * <code> - * foreach( new PostIterator( array( 'table' => $wpdb->posts, 'where' => array( 'post_status' => 'publish', 'post_date_gmt BETWEEN x AND y' ) ) ) as $post ) { - * … - * } - * </code> - * - * - * @param array $args Supported arguments: - * table – the name of the database table - * fields – an array of columns to get from the table, '*' is a valid value and the default - * where – conditions for filtering rows. Supports two formats: - * = string – this will be the where clause - * = array – each element is treated as a condition if it's positional, or as column => value if - * it's a key/value pair. In the latter case the value is automatically quoted and escaped - * append - add arbitrary extra SQL - */ - function __construct( $args = array() ) { - $defaults = array( - 'fields' => '*', - 'where' => array(), - 'append' => '', - 'table' => null, - 'chunk_size' => 500 - ); - $table = $args['table']; - $args = array_merge( $defaults, $args ); - - $fields = self::build_fields( $args['fields'] ); - $conditions = self::build_where_conditions( $args['where'] ); - $where_sql = $conditions ? " WHERE $conditions" : ''; - $query = "SELECT $fields FROM `$table` $where_sql {$args['append']}"; - - parent::__construct( $query, $args['chunk_size'] ); - } - - private static function build_fields( $fields ) { - if ( '*' === $fields ) - return $fields; - - return implode( ', ', array_map( function ($v) { return "`$v`"; }, $fields ) ); - } - - private static function build_where_conditions( $where ) { - global $wpdb; - if ( is_array( $where ) ) { - $conditions = array(); - foreach( $where as $key => $value ) { - if ( is_array( $value ) ) { - $conditions[] = $key . ' IN (' . esc_sql( implode( ',', $value ) ) . ')'; - } else if ( is_numeric( $key ) ) { - $conditions[] = $value; - } else { - $conditions[] = $key . $wpdb->prepare( ' = %s', $value ); - } - } - $where = implode( ' AND ', $conditions ); - } - return $where; - } -} - diff --git a/php/WP_CLI/Iterators/Transform.php b/php/WP_CLI/Iterators/Transform.php deleted file mode 100644 index 0c8e05590..000000000 --- a/php/WP_CLI/Iterators/Transform.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace WP_CLI\Iterators; - -/** - * Aplies one or more callbacks to an item before returning it. - */ -class Transform extends \IteratorIterator { - - private $transformers = array(); - - public function add_transform( $fn ) { - $this->transformers[] = $fn; - } - - public function current() { - $value = parent::current(); - - foreach ( $this->transformers as $fn ) { - $value = call_user_func( $fn, $value ); - } - - return $value; - } -} - diff --git a/php/WP_CLI/LanguagePackUpgrader.php b/php/WP_CLI/LanguagePackUpgrader.php deleted file mode 100644 index f796c4e41..000000000 --- a/php/WP_CLI/LanguagePackUpgrader.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; - -/** - * A Language Pack Upgrader class that caches the download, and uses cached if available - * - * @package wp-cli - */ -class LanguagePackUpgrader extends \Language_Pack_Upgrader { - - /** - * Caches the download, and uses cached if available. - * - * @access public - * - * @param string $package The URI of the package. If this is the full path to an - * existing local file, it will be returned untouched. - * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object. - */ - public function download_package( $package ) { - - /** - * Filter whether to return the package. - * - * @since 3.7.0 - * - * @param bool $reply Whether to bail without returning the package. Default is false. - * @param string $package The package file name. - * @param object $this The WP_Upgrader instance. - */ - $reply = apply_filters( 'upgrader_pre_download', false, $package, $this ); - if ( false !== $reply ) { - return $reply; - } - - // Check if package is a local or remote file. Bail if it's local. - if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { - return $package; - } - - if ( empty( $package ) ) { - return new \WP_Error( 'no_package', $this->strings['no_package'] ); - } - - $language_update = $this->skin->language_update; - $type = $language_update->type; - $slug = empty( $language_update->slug ) ? 'default' : $language_update->slug; - $updated = strtotime( $language_update->updated ); - $version = $language_update->version; - $language = $language_update->language; - $ext = pathinfo( $package, PATHINFO_EXTENSION ); - - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid( 'wp_' ) . '.' . $ext; - - $cache = WP_CLI::get_cache(); - $cache_key = "translation/{$type}-{$slug}-{$version}-{$language}-{$updated}.{$ext}"; - $cache_file = $cache->has( $cache_key ); - - if ( $cache_file ) { - WP_CLI::log( "Using cached file '$cache_file'..." ); - copy( $cache_file, $temp ); - return $temp; - } else { - /* - * Download to a temporary file because piping from cURL to tar is flaky - * on MinGW (and probably in other environments too). - */ - $headers = array( 'Accept' => 'application/json' ); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody. - 'filename' => $temp - ); - - $this->skin->feedback( 'downloading_package', $package ); - - /** @var \Requests_Response|null $req */ - $req = Utils\http_request( 'GET', $package, null, $headers, $options ); - if ( ! is_null( $req ) && $req->status_code !== 200 ) { - return new \WP_Error( 'download_failed', $this->strings['download_failed'] ); - } - $cache->import( $cache_key, $temp ); - return $temp; - } - } -} diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php deleted file mode 100644 index 11b26e304..000000000 --- a/php/WP_CLI/Loggers/Base.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php - -namespace WP_CLI\Loggers; - -/** - * Base logger class - */ -abstract class Base { - - protected $in_color = false; - - abstract public function info( $message ); - - abstract public function success( $message ); - - abstract public function warning( $message ); - - /** - * Retrieve the runner instance from the base CLI object. This facilitates - * unit testing, where the WP_CLI instance isn't available - * - * @return Runner Instance of the runner class - */ - protected function get_runner() { - return \WP_CLI::get_runner(); - } - - /** - * Write a message to STDERR, prefixed with "Debug: ". - * - * @param string $message Message to write. - * @param string $group Organize debug message to a specific group. - */ - public function debug( $message, $group = false ) { - $debug = $this->get_runner()->config['debug']; - if ( ! $debug ) { - return; - } - if ( true !== $debug && $group !== $debug ) { - return; - } - $time = round( microtime( true ) - WP_CLI_START_MICROTIME, 3 ); - $prefix = 'Debug'; - if ( $group && true === $debug ) { - $prefix = 'Debug (' . $group . ')'; - } - $this->_line( "$message ({$time}s)", $prefix, '%B', STDERR ); - } - - /** - * Write a string to a resource. - * - * @param resource $handle Commonly STDOUT or STDERR. - * @param string $str Message to write. - */ - protected function write( $handle, $str ) { - fwrite( $handle, $str ); - } - - /** - * Output one line of message to a resource. - * - * @param string $message Message to write. - * @param string $label Prefix message with a label. - * @param string $color Colorize label with a given color. - * @param resource $handle Resource to write to. Defaults to STDOUT. - */ - protected function _line( $message, $label, $color, $handle = STDOUT ) { - $label = \cli\Colors::colorize( "$color$label:%n", $this->in_color ); - $this->write( $handle, "$label $message\n" ); - } - -} diff --git a/php/WP_CLI/Loggers/Execution.php b/php/WP_CLI/Loggers/Execution.php deleted file mode 100644 index 3b0ab7e79..000000000 --- a/php/WP_CLI/Loggers/Execution.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php - -namespace WP_CLI\Loggers; - -/** - * Execution logger captures all STDOUT and STDERR writes - */ -class Execution extends Base { - - /** - * Captured writes to STDOUT. - */ - public $stdout = ''; - - /** - * Captured writes to STDERR. - */ - public $stderr = ''; - - /** - * Write an informational message to STDOUT. - * - * @param string $message Message to write. - */ - public function info( $message ) { - $this->write( 'STDOUT', $message . "\n" ); - } - - /** - * Write a success message, prefixed with "Success: ". - * - * @param string $message Message to write. - */ - public function success( $message ) { - $this->_line( $message, 'Success', '%G' ); - } - - /** - * Write a warning message to STDERR, prefixed with "Warning: ". - * - * @param string $message Message to write. - */ - public function warning( $message ) { - $this->_line( $message, 'Warning', '%C', 'STDERR' ); - } - - /** - * Write an message to STDERR, prefixed with "Error: ". - * - * @param string $message Message to write. - */ - public function error( $message ) { - $this->_line( $message, 'Error', '%R', 'STDERR' ); - } - - /** - * Similar to error( $message ), but outputs $message in a red box - * - * @param array $message Message to write. - */ - public function error_multi_line( $message_lines ) { - $message = implode( "\n", $message_lines ); - - $this->write( 'STDERR', \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); - $this->write( 'STDERR', \WP_CLI::colorize( "%R---------%n\n\n" ) ); - } - - /** - * Write a string to a resource. - * - * @param resource $handle Commonly STDOUT or STDERR. - * @param string $str Message to write. - */ - protected function write( $handle, $str ) { - switch( $handle ) { - case 'STDOUT': - $this->stdout .= $str; - break; - case 'STDERR': - $this->stderr .= $str; - break; - } - } -} diff --git a/php/WP_CLI/Loggers/Quiet.php b/php/WP_CLI/Loggers/Quiet.php deleted file mode 100644 index e8de7be82..000000000 --- a/php/WP_CLI/Loggers/Quiet.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php - -namespace WP_CLI\Loggers; - -/** - * Quiet logger only logs errors. - */ -class Quiet extends Base { - - /** - * Informational messages aren't logged. - * - * @param string $message Message to write. - */ - public function info( $message ) { - // nothing - } - - /** - * Success messages aren't logged. - * - * @param string $message Message to write. - */ - public function success( $message ) { - // nothing - } - - /** - * Warning messages aren't logged. - * - * @param string $message Message to write. - */ - public function warning( $message ) { - // nothing - } - - /** - * Write an error message to STDERR, prefixed with "Error: ". - * - * @param string $message Message to write. - */ - public function error( $message ) { - $this->write( STDERR, \WP_CLI::colorize( "%RError:%n $message\n" ) ); - } - - /** - * Similar to error( $message ), but outputs $message in a red box - * - * @param array $message Message to write. - */ - public function error_multi_line( $message_lines ) { - $message = implode( "\n", $message_lines ); - - $this->write( STDERR, \WP_CLI::colorize( "%RError:%n\n$message\n" ) ); - $this->write( STDERR, \WP_CLI::colorize( "%R---------%n\n\n" ) ); - } -} diff --git a/php/WP_CLI/Loggers/Regular.php b/php/WP_CLI/Loggers/Regular.php deleted file mode 100644 index eeb392047..000000000 --- a/php/WP_CLI/Loggers/Regular.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php - -namespace WP_CLI\Loggers; - -/** - * Default logger for success, warning, error, and standard messages. - */ -class Regular extends Base { - - /** - * @param bool $in_color Whether or not to Colorize strings. - */ - function __construct( $in_color ) { - $this->in_color = $in_color; - } - - /** - * Write an informational message to STDOUT. - * - * @param string $message Message to write. - */ - public function info( $message ) { - $this->write( STDOUT, $message . "\n" ); - } - - /** - * Write a success message, prefixed with "Success: ". - * - * @param string $message Message to write. - */ - public function success( $message ) { - $this->_line( $message, 'Success', '%G' ); - } - - /** - * Write a warning message to STDERR, prefixed with "Warning: ". - * - * @param string $message Message to write. - */ - public function warning( $message ) { - $this->_line( $message, 'Warning', '%C', STDERR ); - } - - /** - * Write an message to STDERR, prefixed with "Error: ". - * - * @param string $message Message to write. - */ - public function error( $message ) { - $this->_line( $message, 'Error', '%R', STDERR ); - } - - /** - * Similar to error( $message ), but outputs $message in a red box - * - * @param array $message Message to write. - */ - public function error_multi_line( $message_lines ) { - // convert tabs to four spaces, as some shells will output the tabs as variable-length - $message_lines = array_map( function( $line ) { - return str_replace( "\t", ' ', $line ); - } , $message_lines ); - - $longest = max( array_map( 'strlen', $message_lines ) ); - - // write an empty line before the message - $empty_line = \cli\Colors::colorize( '%w%1 ' . str_repeat( ' ', $longest ) . ' %n' ); - $this->write( STDERR, "\n\t$empty_line\n" ); - - foreach ( $message_lines as $line ) { - $padding = str_repeat( ' ', $longest - strlen( $line ) ); - $line = \cli\Colors::colorize( "%w%1 $line $padding%n" ); - $this->write( STDERR, "\t$line\n" ); - } - - // write an empty line after the message - $this->write( STDERR, "\t$empty_line\n\n" ); - } -} diff --git a/php/WP_CLI/NoOp.php b/php/WP_CLI/NoOp.php deleted file mode 100644 index 1aca5f9b3..000000000 --- a/php/WP_CLI/NoOp.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Escape route for not doing anything. - */ -final class NoOp { - - function __set( $key, $value ) { - // do nothing - } - - function __call( $method, $args ) { - // do nothing - } -} - diff --git a/php/WP_CLI/NonDestructiveCoreUpgrader.php b/php/WP_CLI/NonDestructiveCoreUpgrader.php deleted file mode 100644 index ebad21cbd..000000000 --- a/php/WP_CLI/NonDestructiveCoreUpgrader.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * A Core Upgrader class that leaves packages intact by default. - * - * @package wp-cli - */ -class NonDestructiveCoreUpgrader extends CoreUpgrader { - function unpack_package($package, $delete_package = false) { - return parent::unpack_package( $package, $delete_package ); - } -} - diff --git a/php/WP_CLI/PackageManagerEventSubscriber.php b/php/WP_CLI/PackageManagerEventSubscriber.php deleted file mode 100644 index d515bd067..000000000 --- a/php/WP_CLI/PackageManagerEventSubscriber.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -namespace WP_CLI; - -use \Composer\DependencyResolver\Rule; -use \Composer\EventDispatcher\EventSubscriberInterface; -use \Composer\Installer\PackageEvent; -use Composer\Installer\PackageEvents; -use \WP_CLI; - -/** - * A Composer Event subscriber so we can keep track of what's happening inside Composer - */ -class PackageManagerEventSubscriber implements EventSubscriberInterface { - - public static function getSubscribedEvents() { - - return array( - PackageEvents::PRE_PACKAGE_INSTALL => 'pre_install', - PackageEvents::POST_PACKAGE_INSTALL => 'post_install', - ); - } - - public static function pre_install( PackageEvent $event ) { - $operation_message = $event->getOperation()->__toString(); - WP_CLI::log( ' - ' . $operation_message ); - } - - public static function post_install( PackageEvent $event ) { - - $operation = $event->getOperation(); - $reason = $operation->getReason(); - if ( $reason instanceof Rule ) { - - switch ( $reason->getReason() ) { - - case Rule::RULE_PACKAGE_CONFLICT; - case Rule::RULE_PACKAGE_SAME_NAME: - case Rule::RULE_PACKAGE_REQUIRES: - $composer_error = $reason->getPrettyString( $event->getPool() ); - break; - - } - - if ( ! empty( $composer_error ) ) { - WP_CLI::log( sprintf( " - Warning: %s", $composer_error ) ); - } - } - - } - -} diff --git a/php/WP_CLI/Process.php b/php/WP_CLI/Process.php deleted file mode 100644 index 74939c5d0..000000000 --- a/php/WP_CLI/Process.php +++ /dev/null @@ -1,75 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Run a system process, and learn what happened. - */ -class Process { - - /** - * @param string $command Command to execute. - * @param string $cwd Directory to execute the command in. - * @param array $env Environment variables to set when running the command. - */ - public static function create( $command, $cwd = null, $env = array() ) { - $proc = new self; - - $proc->command = $command; - $proc->cwd = $cwd; - $proc->env = $env; - - return $proc; - } - - private $command, $cwd, $env; - - private function __construct() {} - - /** - * Run the command. - * - * @return ProcessRun - */ - public function run() { - $cwd = $this->cwd; - - $descriptors = array( - 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); - - $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); - - $stdout = stream_get_contents( $pipes[1] ); - fclose( $pipes[1] ); - - $stderr = stream_get_contents( $pipes[2] ); - fclose( $pipes[2] ); - - return new ProcessRun( array( - 'stdout' => $stdout, - 'stderr' => $stderr, - 'return_code' => proc_close( $proc ), - 'command' => $this->command, - 'cwd' => $cwd, - 'env' => $this->env - ) ); - } - - /** - * Run the command, but throw an Exception on error. - * - * @return ProcessRun - */ - public function run_check() { - $r = $this->run(); - - if ( $r->return_code || !empty( $r->STDERR ) ) { - throw new \RuntimeException( $r ); - } - - return $r; - } -} diff --git a/php/WP_CLI/ProcessRun.php b/php/WP_CLI/ProcessRun.php deleted file mode 100644 index 4611cfbb6..000000000 --- a/php/WP_CLI/ProcessRun.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Results of an executed command. - */ -class ProcessRun { - - /** - * @var array $props Properties of executed command. - */ - public function __construct( $props ) { - foreach ( $props as $key => $value ) { - $this->$key = $value; - } - } - - /** - * Return properties of executed command as a string. - * - * @return string - */ - public function __toString() { - $out = "$ $this->command\n"; - $out .= "$this->stdout\n$this->stderr"; - $out .= "cwd: $this->cwd\n"; - $out .= "exit status: $this->return_code"; - - return $out; - } - -} diff --git a/php/WP_CLI/REPL.php b/php/WP_CLI/REPL.php deleted file mode 100644 index bd95c4fed..000000000 --- a/php/WP_CLI/REPL.php +++ /dev/null @@ -1,117 +0,0 @@ -<?php - -namespace WP_CLI; - -class REPL { - - private $prompt; - - public function __construct( $prompt ) { - $this->prompt = $prompt; - - $this->set_history_file(); - } - - public function start() { - while ( true ) { - $line = $this->prompt(); - - if ( '' === $line ) continue; - - $line = rtrim( $line, ';' ) . ';'; - - if ( self::starts_with( self::non_expressions(), $line ) ) { - ob_start(); - eval( $line ); - $out = ob_get_clean(); - if ( 0 < strlen ( $out ) ) { - $out = rtrim( $out, "\n" ) . "\n"; - } - fwrite( STDOUT, $out ); - } else { - if ( !self::starts_with( 'return', $line ) ) - $line = 'return ' . $line; - - // Write directly to STDOUT, to sidestep any output buffers created by plugins - ob_start(); - $evl = eval( $line ); - $out = ob_get_clean(); - if ( 0 < strlen ( $out ) ) { - echo rtrim( $out, "\n" ) . "\n"; - } - echo "=> "; - var_dump( $evl ); - fwrite( STDOUT, ob_get_clean() ); - } - } - } - - private static function non_expressions() { - return implode( '|', array( - 'echo', 'global', 'unset', 'function', - 'while', 'for', 'foreach', 'if', 'switch', - 'include', 'include\_once', 'require', 'require\_once' - ) ); - } - - private function prompt() { - $full_line = false; - - $done = false; - do { - $prompt = ( !$done && $full_line !== false ) ? '--> ' : $this->prompt; - - $fp = popen( self::create_prompt_cmd( $prompt, $this->history_file ), 'r' ); - - $line = fgets( $fp ); - - if ( !$line ) { - break; - } - - $line = rtrim( $line, "\n" ); - - if ( $line && '\\' == $line[ strlen( $line ) - 1 ] ) { - $line = substr( $line, 0, -1 ); - } else { - $done = true; - } - - $full_line .= $line; - - } while ( !$done ); - - if ( $full_line === false ) { - return 'exit'; - } - - return $full_line; - } - - private static function create_prompt_cmd( $prompt, $history_path ) { - $prompt = escapeshellarg( $prompt ); - $history_path = escapeshellarg( $history_path ); - - $cmd = "set -f; " - . "history -r $history_path; " - . "LINE=\"\"; " - . "read -re -p $prompt LINE; " - . "[ $? -eq 0 ] || exit; " - . "history -s \"\$LINE\"; " - . "history -w $history_path; " - . "echo \$LINE; "; - - return '/bin/bash -c ' . escapeshellarg( $cmd ); - } - - private function set_history_file() { - $data = getcwd() . get_current_user(); - - $this->history_file = \WP_CLI\Utils\get_temp_dir() . 'wp-cli-history-' . md5( $data ); - } - - private static function starts_with( $tokens, $line ) { - return preg_match( "/^($tokens)[\(\s]+/", $line ); - } -} - diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php deleted file mode 100644 index 4b76a4820..000000000 --- a/php/WP_CLI/Runner.php +++ /dev/null @@ -1,1355 +0,0 @@ -<?php - -namespace WP_CLI; - -use WP_CLI; -use WP_CLI\Utils; -use WP_CLI\Dispatcher; - -/** - * Performs the execution of a command. - * - * @package WP_CLI - */ -class Runner { - - private $global_config_path, $project_config_path; - - private $config, $extra_config; - - private $alias; - - private $aliases; - - private $arguments, $assoc_args; - - private $_early_invoke = array(); - - private $_global_config_path_debug; - - private $_project_config_path_debug; - - private $_required_files; - - public function __get( $key ) { - if ( '_' === $key[0] ) - return null; - - return $this->$key; - } - - /** - * Register a command for early invocation, generally before WordPress loads. - * - * @param string $when Named execution hook - * @param WP_CLI\Dispatcher\Subcommand $command - */ - public function register_early_invoke( $when, $command ) { - $this->_early_invoke[ $when ][] = array_slice( Dispatcher\get_path( $command ), 1 ); - } - - /** - * Perform the early invocation of a command. - * - * @param string $when Named execution hook - */ - private function do_early_invoke( $when ) { - if ( !isset( $this->_early_invoke[ $when ] ) ) - return; - - foreach ( $this->_early_invoke[ $when ] as $path ) { - if ( $this->cmd_starts_with( $path ) ) { - $this->_run_command(); - exit; - } - } - } - - /** - * Get the path to the global configuration YAML file. - * - * @return string|false - */ - private function get_global_config_path() { - - if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { - $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); - $this->_global_config_path_debug = 'Using global config from WP_CLI_CONFIG_PATH env var: ' . $config_path; - } else { - $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; - $this->_global_config_path_debug = 'Using default global config: ' . $config_path; - } - - if ( is_readable( $config_path ) ) { - return $config_path; - } else { - $this->_global_config_path_debug = 'No readable global config found'; - return false; - } - } - - /** - * Get the path to the project-specific configuration - * YAML file. - * wp-cli.local.yml takes priority over wp-cli.yml. - * - * @return string|false - */ - private function get_project_config_path() { - $config_files = array( - 'wp-cli.local.yml', - 'wp-cli.yml' - ); - - // Stop looking upward when we find we have emerged from a subdirectory - // install into a parent install - $project_config_path = Utils\find_file_upward( $config_files, getcwd(), function ( $dir ) { - static $wp_load_count = 0; - $wp_load_path = $dir . DIRECTORY_SEPARATOR . 'wp-load.php'; - if ( file_exists( $wp_load_path ) ) { - $wp_load_count += 1; - } - return $wp_load_count > 1; - } ); - if ( ! empty( $project_config_path ) ) { - $this->_project_config_path_debug = 'Using project config: ' . $project_config_path; - } else { - $this->_project_config_path_debug = 'No project config found'; - } - return $project_config_path; - } - - /** - * Get the path to the packages directory - * - * @return string - */ - public function get_packages_dir_path() { - if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { - $packages_dir = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/'; - } else { - $packages_dir = getenv( 'HOME' ) . '/.wp-cli/packages/'; - } - return $packages_dir; - } - - /** - * Attempts to find the path to the WP install inside index.php - * - * @param string $index_path - * @return string|false - */ - private static function extract_subdir_path( $index_path ) { - $index_code = file_get_contents( $index_path ); - - if ( !preg_match( '|^\s*require\s*\(?\s*(.+?)/wp-blog-header\.php([\'"])|m', $index_code, $matches ) ) { - return false; - } - - $wp_path_src = $matches[1] . $matches[2]; - $wp_path_src = Utils\replace_path_consts( $wp_path_src, $index_path ); - $wp_path = eval( "return $wp_path_src;" ); - - if ( !Utils\is_path_absolute( $wp_path ) ) { - $wp_path = dirname( $index_path ) . "/$wp_path"; - } - - return $wp_path; - } - - /** - * Find the directory that contains the WordPress files. - * Defaults to the current working dir. - * - * @return string An absolute path - */ - private function find_wp_root() { - if ( !empty( $this->config['path'] ) ) { - $path = $this->config['path']; - if ( !Utils\is_path_absolute( $path ) ) - $path = getcwd() . '/' . $path; - - return $path; - } - - if ( $this->cmd_starts_with( array( 'core', 'download' ) ) ) { - return getcwd(); - } - - $dir = getcwd(); - - while ( is_readable( $dir ) ) { - if ( file_exists( "$dir/wp-load.php" ) ) { - return $dir; - } - - if ( file_exists( "$dir/index.php" ) ) { - if ( $path = self::extract_subdir_path( "$dir/index.php" ) ) - return $path; - } - - $parent_dir = dirname( $dir ); - if ( empty($parent_dir) || $parent_dir === $dir ) { - break; - } - $dir = $parent_dir; - } - } - - /** - * Set WordPress root as a given path. - * - * @param string $path - */ - private static function set_wp_root( $path ) { - define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); - WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH, 'bootstrap' ); - - $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); - } - - /** - * Guess which URL context WP-CLI has been invoked under. - * - * @param array $assoc_args - * @return string|false - */ - private static function guess_url( $assoc_args ) { - if ( isset( $assoc_args['blog'] ) ) { - $assoc_args['url'] = $assoc_args['blog']; - } - - if ( isset( $assoc_args['url'] ) ) { - $url = $assoc_args['url']; - if ( true === $url ) { - WP_CLI::warning( 'The --url parameter expects a value.' ); - } - } - - if ( isset( $url ) ) { - return $url; - } - - return false; - } - - private function cmd_starts_with( $prefix ) { - return $prefix == array_slice( $this->arguments, 0, count( $prefix ) ); - } - - /** - * Given positional arguments, find the command to execute. - * - * @param array $args - * @return array|string Command, args, and path on success; error message on failure - */ - public function find_command_to_run( $args ) { - $command = \WP_CLI::get_root_command(); - - $cmd_path = array(); - - while ( !empty( $args ) && $command->can_have_subcommands() ) { - $cmd_path[] = $args[0]; - $full_name = implode( ' ', $cmd_path ); - - $subcommand = $command->find_subcommand( $args ); - - if ( !$subcommand ) { - if ( count( $cmd_path ) > 1 ) { - $child = array_pop( $cmd_path ); - $parent_name = implode( ' ', $cmd_path ); - return sprintf( - "'%s' is not a registered subcommand of '%s'. See 'wp help %s'.", - $child, - $parent_name, - $parent_name - ); - } else { - return sprintf( - "'%s' is not a registered wp command. See 'wp help'.", - $full_name - ); - } - } - - if ( $this->is_command_disabled( $subcommand ) ) { - return sprintf( - "The '%s' command has been disabled from the config file.", - $full_name - ); - } - - $command = $subcommand; - } - - return array( $command, $args, $cmd_path ); - } - - /** - * Find the WP-CLI command to run given arguments, and invoke it. - * - * @param array $args Positional arguments including command name - * @param array $assoc_args Associative arguments for the command. - * @param array $options Configuration options for the function. - */ - public function run_command( $args, $assoc_args = array(), $options = array() ) { - if ( ! empty( $options['back_compat_conversions'] ) ) { - list( $args, $assoc_args ) = self::back_compat_conversions( $args, $assoc_args ); - } - $r = $this->find_command_to_run( $args ); - if ( is_string( $r ) ) { - WP_CLI::error( $r ); - } - - list( $command, $final_args, $cmd_path ) = $r; - - $name = implode( ' ', $cmd_path ); - - if ( isset( $this->extra_config[ $name ] ) ) { - $extra_args = $this->extra_config[ $name ]; - } else { - $extra_args = array(); - } - - WP_CLI::debug( 'Running command: ' . $name, 'bootstrap' ); - try { - $command->invoke( $final_args, $assoc_args, $extra_args ); - } catch ( WP_CLI\Iterators\Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - } - - private function _run_command() { - $this->run_command( $this->arguments, $this->assoc_args ); - } - - /** - * Perform a command against a remote server over SSH - */ - private function run_ssh_command( $ssh ) { - - WP_CLI::do_hook( 'before_ssh' ); - - // host OR host/path/to/wordpress OR host:port/path/to/wordpress - $bits = Utils\parse_ssh_url( $ssh ); - $host = isset( $bits['host'] ) ? $bits['host'] : null; - $port = isset( $bits['port'] ) ? $bits['port'] : null; - $path = isset( $bits['path'] ) ? $bits['path'] : null; - - WP_CLI::debug( 'SSH host: ' . $host, 'bootstrap' ); - WP_CLI::debug( 'SSH port: ' . $port, 'bootstrap' ); - WP_CLI::debug( 'SSH path: ' . $path, 'bootstrap' ); - - $is_tty = function_exists( 'posix_isatty' ) && posix_isatty( STDOUT ); - - $pre_cmd = getenv( 'WP_CLI_SSH_PRE_CMD' ); - if ( $pre_cmd ) { - $pre_cmd = rtrim( $pre_cmd, ';' ) . '; '; - } - if ( $path ) { - $pre_cmd .= "cd {$path}; "; - } - $wp_binary = 'wp'; - $wp_args = array_slice( $GLOBALS['argv'], 1 ); - - if ( $this->alias && ! empty( $wp_args[0] ) && $this->alias === $wp_args[0] ) { - array_shift( $wp_args ); - $runtime_alias = array(); - foreach( $this->aliases[ $this->alias ] as $key => $value ) { - if ( 'ssh' === $key ) { - continue; - } - $runtime_alias[ $key ] = $value; - } - if ( ! empty( $runtime_alias ) ) { - $encoded_alias = json_encode( array( $this->alias => $runtime_alias ) ); - $wp_binary = "WP_CLI_RUNTIME_ALIAS='{$encoded_alias}' {$wp_binary} {$this->alias}"; - } - } - - foreach( $wp_args as $k => $v ) { - if ( preg_match( '#--ssh=#', $v ) ) { - unset( $wp_args[ $k ] ); - } - } - - $unescaped_command = sprintf( - 'ssh -q %s%s %s %s', - $port ? '-p ' . (int) $port . ' ' : '', - $host, - $is_tty ? '-t' : '-T', - $pre_cmd . $wp_binary . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) - ); - - WP_CLI::debug( 'Running SSH command: ' . $unescaped_command, 'bootstrap' ); - - $escaped_command = sprintf( - 'ssh -q %s%s %s %s', - $port ? '-p ' . (int) $port . ' ' : '', - escapeshellarg( $host ), - $is_tty ? '-t' : '-T', - escapeshellarg( $pre_cmd . $wp_binary . ' ' . implode( ' ', array_map( 'escapeshellarg', $wp_args ) ) ) - ); - - passthru( $escaped_command, $exit_code ); - if ( 255 === $exit_code ) { - WP_CLI::error( 'Cannot connect over SSH using provided configuration.', 255 ); - } else { - exit( $exit_code ); - } - } - - /** - * Check whether a given command is disabled by the config - * - * @return bool - */ - public function is_command_disabled( $command ) { - $path = implode( ' ', array_slice( \WP_CLI\Dispatcher\get_path( $command ), 1 ) ); - return in_array( $path, $this->config['disabled_commands'] ); - } - - /** - * Returns wp-config.php code, skipping the loading of wp-settings.php - * - * @return string - */ - public function get_wp_config_code() { - $wp_config_path = Utils\locate_wp_config(); - - $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); - - $found_wp_settings = false; - - $lines_to_run = array(); - - foreach ( $wp_config_code as $line ) { - if ( preg_match( '/^\s*require.+wp-settings\.php/', $line ) ) { - $found_wp_settings = true; - continue; - } - - $lines_to_run[] = $line; - } - - if ( !$found_wp_settings ) { - WP_CLI::error( 'Strange wp-config.php file: wp-settings.php is not loaded directly.' ); - } - - $source = implode( "\n", $lines_to_run ); - $source = Utils\replace_path_consts( $source, $wp_config_path ); - return preg_replace( '|^\s*\<\?php\s*|', '', $source ); - } - - /** - * Transparently convert deprecated syntaxes - * - * @param array $args - * @param array $assoc_args - * @return array - */ - private static function back_compat_conversions( $args, $assoc_args ) { - $top_level_aliases = array( - 'sql' => 'db', - 'blog' => 'site' - ); - if ( count( $args ) > 0 ) { - foreach ( $top_level_aliases as $old => $new ) { - if ( $old == $args[0] ) { - $args[0] = $new; - break; - } - } - } - - // *-meta -> * meta - if ( !empty( $args ) && preg_match( '/(post|comment|user|network)-meta/', $args[0], $matches ) ) { - array_shift( $args ); - array_unshift( $args, 'meta' ); - array_unshift( $args, $matches[1] ); - } - - // core (multsite-)install --admin_name= -> --admin_user= - if ( count( $args ) > 0 && 'core' == $args[0] && isset( $assoc_args['admin_name'] ) ) { - $assoc_args['admin_user'] = $assoc_args['admin_name']; - unset( $assoc_args['admin_name'] ); - } - - // site create --site_id= -> site create --network_id= - if ( count( $args ) >= 2 && 'site' === $args[0] && 'create' === $args[1] && isset( $assoc_args['site_id'] ) ) { - $assoc_args['network_id'] = $assoc_args['site_id']; - unset( $assoc_args['site_id'] ); - } - - // {plugin|theme} update-all -> {plugin|theme} update --all - if ( count( $args ) > 1 && in_array( $args[0], array( 'plugin', 'theme' ) ) - && $args[1] == 'update-all' - ) { - $args[1] = 'update'; - $assoc_args['all'] = true; - } - - // transient delete-expired -> transient delete --expired - if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-expired' === $args[1] ) { - $args[1] = 'delete'; - $assoc_args['expired'] = true; - } - - // transient delete-all -> transient delete --all - if ( count( $args ) > 1 && 'transient' === $args[0] && 'delete-all' === $args[1] ) { - $args[1] = 'delete'; - $assoc_args['all'] = true; - } - - // plugin scaffold -> scaffold plugin - if ( array( 'plugin', 'scaffold' ) == array_slice( $args, 0, 2 ) ) { - list( $args[0], $args[1] ) = array( $args[1], $args[0] ); - } - - // foo --help -> help foo - if ( isset( $assoc_args['help'] ) ) { - array_unshift( $args, 'help' ); - unset( $assoc_args['help'] ); - } - - // {post|user} list --ids -> {post|user} list --format=ids - if ( count( $args ) > 1 && in_array( $args[0], array( 'post', 'user' ) ) - && $args[1] == 'list' - && isset( $assoc_args['ids'] ) - ) { - $assoc_args['format'] = 'ids'; - unset( $assoc_args['ids'] ); - } - - // --json -> --format=json - if ( isset( $assoc_args['json'] ) ) { - $assoc_args['format'] = 'json'; - unset( $assoc_args['json'] ); - } - - // --{version|info} -> cli {version|info} - if ( empty( $args ) ) { - $special_flags = array( 'version', 'info' ); - foreach ( $special_flags as $key ) { - if ( isset( $assoc_args[ $key ] ) ) { - $args = array( 'cli', $key ); - unset( $assoc_args[ $key ] ); - break; - } - } - } - - // (post|comment|site|term) url --> (post|comment|site|term) list --*__in --field=url - if ( count( $args ) >= 2 && in_array( $args[0], array( 'post', 'comment', 'site', 'term' ) ) && 'url' === $args[1] ) { - switch ( $args[0] ) { - case 'post': - $post_ids = array_slice( $args, 2 ); - $args = array( 'post', 'list' ); - $assoc_args['post__in'] = implode( ',', $post_ids ); - $assoc_args['post_type'] = 'any'; - $assoc_args['orderby'] = 'post__in'; - $assoc_args['field'] = 'url'; - break; - case 'comment': - $comment_ids = array_slice( $args, 2 ); - $args = array( 'comment', 'list' ); - $assoc_args['comment__in'] = implode( ',', $comment_ids ); - $assoc_args['orderby'] = 'comment__in'; - $assoc_args['field'] = 'url'; - break; - case 'site': - $site_ids = array_slice( $args, 2 ); - $args = array( 'site', 'list' ); - $assoc_args['site__in'] = implode( ',', $site_ids ); - $assoc_args['field'] = 'url'; - break; - case 'term': - $taxonomy = ''; - if ( isset( $args[2] ) ) { - $taxonomy = $args[2]; - } - $term_ids = array_slice( $args, 3 ); - $args = array( 'term', 'list', $taxonomy ); - $assoc_args['include'] = implode( ',', $term_ids ); - $assoc_args['orderby'] = 'include'; - $assoc_args['field'] = 'url'; - break; - } - } - - return array( $args, $assoc_args ); - } - - /** - * Whether or not the output should be rendered in color - * - * @return bool - */ - public function in_color() { - return $this->colorize; - } - - private function init_colorization() { - if ( 'auto' === $this->config['color'] ) { - $this->colorize = ( !\cli\Shell::isPiped() && !\WP_CLI\Utils\is_windows() ); - } else { - $this->colorize = $this->config['color']; - } - } - - private function init_logger() { - if ( $this->config['quiet'] ) - $logger = new \WP_CLI\Loggers\Quiet; - else - $logger = new \WP_CLI\Loggers\Regular( $this->in_color() ); - - WP_CLI::set_logger( $logger ); - } - - /** - * Do WordPress core files exist? - * - * @return bool - */ - private function wp_exists() { - return is_readable( ABSPATH . 'wp-includes/version.php' ); - } - - private function check_wp_version() { - if ( !$this->wp_exists() ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } - - global $wp_version; - include ABSPATH . 'wp-includes/version.php'; - - $minimum_version = '3.7'; - - // @codingStandardsIgnoreStart - if ( version_compare( $wp_version, $minimum_version, '<' ) ) { - WP_CLI::error( - "WP-CLI needs WordPress $minimum_version or later to work properly. " . - "The version currently installed is $wp_version.\n" . - "Try running `wp core download --force`." - ); - } - // @codingStandardsIgnoreEnd - } - - private function init_config() { - $configurator = \WP_CLI::get_configurator(); - - $argv = array_slice( $GLOBALS['argv'], 1 ); - - if ( ! empty( $argv[0] ) && preg_match( '#' . Configurator::ALIAS_REGEX . '#', $argv[0], $matches ) ) { - $this->alias = array_shift( $argv ); - } else { - $this->alias = null; - } - - // File config - { - $this->global_config_path = $this->get_global_config_path(); - $this->project_config_path = $this->get_project_config_path(); - - $configurator->merge_yml( $this->global_config_path, $this->alias ); - $config = $configurator->to_array(); - $this->_required_files['global'] = $config[0]['require']; - $configurator->merge_yml( $this->project_config_path, $this->alias ); - $config = $configurator->to_array(); - $this->_required_files['project'] = $config[0]['require']; - } - - // Runtime config and args - { - list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); - - list( $this->arguments, $this->assoc_args ) = self::back_compat_conversions( - $args, $assoc_args ); - - $configurator->merge_array( $runtime_config ); - } - - list( $this->config, $this->extra_config ) = $configurator->to_array(); - $this->aliases = $configurator->get_aliases(); - if ( count( $this->aliases ) && ! isset( $this->aliases['@all'] ) ) { - $this->aliases = array_reverse( $this->aliases ); - $this->aliases['@all'] = 'Run command against every registered alias.'; - $this->aliases = array_reverse( $this->aliases ); - } - $this->_required_files['runtime'] = $this->config['require']; - } - - private function check_root() { - if ( $this->config['allow-root'] ) { - return; # they're aware of the risks! - } - if ( count( $this->arguments ) >= 2 && 'cli' === $this->arguments[0] && 'update' === $this->arguments[1] ) { - return; # make it easier to update root-owned copies - } - if ( !function_exists( 'posix_geteuid') ) { - return; # posix functions not available - } - if ( posix_geteuid() !== 0 ) { - return; # not root - } - - WP_CLI::error( - "YIKES! It looks like you're running this as root. You probably meant to " . - "run this as the user that your WordPress install exists under.\n" . - "\n" . - "If you REALLY mean to run this as root, we won't stop you, but just " . - "bear in mind that any code on this site will then have full control of " . - "your server, making it quite DANGEROUS.\n" . - "\n" . - "If you'd like to continue as root, please run this again, adding this " . - "flag: --allow-root\n" . - "\n" . - "If you'd like to run it as the user that this site is under, you can " . - "run the following to become the respective user:\n" . - "\n" . - " sudo -u USER -i -- wp <command>\n" . - "\n" - ); - } - - private function run_alias_group( $aliases ) { - $php_bin = WP_CLI::get_php_binary(); - - $script_path = $GLOBALS['argv'][0]; - - if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { - $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); - } else { - $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; - } - $config_path = escapeshellarg( $config_path ); - - foreach( $aliases as $alias ) { - WP_CLI::log( $alias ); - $args = implode( ' ', array_map( 'escapeshellarg', $this->arguments ) ); - $assoc_args = Utils\assoc_args_to_str( $this->assoc_args ); - $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$alias} {$args} {$assoc_args}"; - $proc = proc_open( $full_command, array( STDIN, STDOUT, STDERR ), $pipes ); - proc_close( $proc ); - } - } - - private function set_alias( $alias ) { - $orig_config = $this->config; - $alias_config = $this->aliases[ $this->alias ]; - $this->config = array_merge( $orig_config, $alias_config ); - foreach( $alias_config as $key => $_ ) { - if ( isset( $orig_config[ $key ] ) && ! is_null( $orig_config[ $key ] ) ) { - $this->assoc_args[ $key ] = $orig_config[ $key ]; - } - } - } - - public function start() { - $this->init_config(); - $this->init_colorization(); - $this->init_logger(); - - WP_CLI::debug( $this->_global_config_path_debug, 'bootstrap' ); - WP_CLI::debug( $this->_project_config_path_debug, 'bootstrap' ); - - $this->check_root(); - if ( $this->alias ) { - if ( '@all' === $this->alias && ! isset( $this->aliases['@all'] ) ) { - WP_CLI::error( "Cannot use '@all' when no aliases are registered." ); - } - - if ( '@all' === $this->alias && is_string( $this->aliases['@all'] ) ) { - $aliases = array_keys( $this->aliases ); - $k = array_search( '@all', $aliases ); - unset( $aliases[ $k ] ); - $this->run_alias_group( $aliases ); - exit; - } - - if ( ! array_key_exists( $this->alias, $this->aliases ) ) { - WP_CLI::error( "Alias '{$this->alias}' not found." ); - } - // Numerically indexed means a group of aliases - if ( isset( $this->aliases[ $this->alias ][0] ) ) { - $group_aliases = $this->aliases[ $this->alias ]; - $all_aliases = array_keys( $this->aliases ); - if ( $diff = array_diff( $group_aliases, $all_aliases ) ) { - WP_CLI::error( "Group '{$this->alias}' contains one or more invalid aliases: " . implode( ', ', $diff ) ); - } - $this->run_alias_group( $group_aliases ); - exit; - } else { - $this->set_alias( $this->alias ); - } - } - - if ( empty( $this->arguments ) ) - $this->arguments[] = 'help'; - - // Protect 'cli info' from most of the runtime, - // except when the command will be run over SSH - if ( 'cli' === $this->arguments[0] && ! empty( $this->arguments[1] ) && 'info' === $this->arguments[1] && ! $this->config['ssh'] ) { - $this->_run_command(); - exit; - } - - // Protect 'package' commands from most of the runtime too, - // except when the command will be run over SSH - if ( 'package' === $this->arguments[0] && ! $this->config['ssh'] ) { - $this->_run_command(); - exit; - } - - // Load bundled commands early, so that they're forced to use the same - // APIs as non-bundled commands. - Utils\load_all_commands(); - - $skip_packages = \WP_CLI::get_runner()->config['skip-packages']; - if ( true === $skip_packages ) { - WP_CLI::debug( 'Skipped loading packages.', 'bootstrap' ); - } else { - $package_autoload = $this->get_packages_dir_path() . 'vendor/autoload.php'; - if ( file_exists( $package_autoload ) ) { - WP_CLI::debug( 'Loading packages from: ' . $package_autoload, 'bootstrap' ); - require_once $package_autoload; - } else { - WP_CLI::debug( 'No package autoload found to load.', 'bootstrap' ); - } - } - - if ( isset( $this->config['http'] ) && ! class_exists( '\WP_REST_CLI\Runner' ) ) { - WP_CLI::error( "RESTful WP-CLI needs to be installed. Try 'wp package install wp-cli/restful'." ); - } - - if ( isset( $this->config['require'] ) ) { - foreach ( $this->config['require'] as $path ) { - if ( ! file_exists( $path ) ) { - $context = ''; - foreach( array( 'global', 'project', 'runtime' ) as $scope ) { - if ( in_array( $path, $this->_required_files[ $scope ] ) ) { - switch ( $scope ) { - case 'global': - $context = ' (from global ' . Utils\basename( $this->global_config_path ) . ')'; - break; - case 'project': - $context = ' (from project\'s ' . Utils\basename( $this->project_config_path ) . ')'; - break; - case 'runtime': - $context = ' (from runtime argument)'; - break; - } - break; - } - } - WP_CLI::error( sprintf( "Required file '%s' doesn't exist%s.", Utils\basename( $path ), $context ) ); - } - Utils\load_file( $path ); - WP_CLI::debug( 'Required file from config: ' . $path, 'bootstrap' ); - } - } - - if ( $this->config['ssh'] ) { - $this->run_ssh_command( $this->config['ssh'] ); - return; - } - - // Show synopsis if it's a composite command. - $r = $this->find_command_to_run( $this->arguments ); - if ( is_array( $r ) ) { - list( $command ) = $r; - - if ( $command->can_have_subcommands() ) { - $command->show_usage(); - exit; - } - } - - // Handle --path parameter - self::set_wp_root( $this->find_wp_root() ); - - // First try at showing man page - if ( ! empty( $this->arguments[0] ) && 'help' === $this->arguments[0] && ( ! $this->wp_exists() || ! Utils\locate_wp_config() || ( ! empty( $this->arguments[1] ) && ! empty( $this->arguments[2] ) && 'core' === $this->arguments[1] && in_array( $this->arguments[2], array( 'config', 'install', 'multisite-install', 'verify-checksums', 'version' ) ) ) ) ) { - $this->auto_check_update(); - $this->_run_command(); - } - - // Handle --url parameter - $url = self::guess_url( $this->config ); - if ( $url ) - \WP_CLI::set_url( $url ); - - $this->do_early_invoke( 'before_wp_load' ); - - $this->check_wp_version(); - - if ( $this->cmd_starts_with( array( 'core', 'config' ) ) ) { - $this->_run_command(); - exit; - } - - if ( !Utils\locate_wp_config() ) { - WP_CLI::error( - "'wp-config.php' not found.\n" . - "Either create one manually or use `wp core config`." ); - } - - if ( ( $this->cmd_starts_with( array( 'db' ) ) || $this->cmd_starts_with( array( 'help', 'db' ) ) ) - && ! $this->cmd_starts_with( array( 'db', 'tables' ) ) ) { - eval( $this->get_wp_config_code() ); - $this->_run_command(); - exit; - } - - if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) - || $this->cmd_starts_with( array( 'core', 'update-db' ) ) ) { - define( 'WP_INSTALLING', true ); - } - - if ( - count( $this->arguments ) >= 2 && - $this->arguments[0] == 'core' && - in_array( $this->arguments[1], array( 'install', 'multisite-install' ) ) - ) { - define( 'WP_INSTALLING', true ); - - // We really need a URL here - if ( !isset( $_SERVER['HTTP_HOST'] ) ) { - $url = 'http://example.com'; - \WP_CLI::set_url( $url ); - } - - if ( 'multisite-install' == $this->arguments[1] ) { - // need to fake some globals to skip the checks in wp-includes/ms-settings.php - $url_parts = Utils\parse_url( $url ); - self::fake_current_site_blog( $url_parts ); - - if ( !defined( 'COOKIEHASH' ) ) { - define( 'COOKIEHASH', md5( $url_parts['host'] ) ); - } - } - } - - if ( $this->cmd_starts_with( array( 'import') ) ) { - define( 'WP_LOAD_IMPORTERS', true ); - define( 'WP_IMPORTING', true ); - } - - if ( $this->cmd_starts_with( array( 'cron', 'event', 'run' ) ) ) { - define( 'DOING_CRON', true ); - } - - $this->load_wordpress(); - - $this->_run_command(); - - } - - /** - * Load WordPress, if it hasn't already been loaded - */ - public function load_wordpress() { - static $wp_cli_is_loaded; - // Globals not explicitly globalized in WordPress - global $site_id, $wpdb, $public, $current_site, $current_blog, $path, $shortcode_tags; - - if ( ! empty( $wp_cli_is_loaded ) ) { - return; - } - - $wp_cli_is_loaded = true; - - WP_CLI::debug( 'Begin WordPress load', 'bootstrap' ); - WP_CLI::do_hook( 'before_wp_load' ); - - $this->check_wp_version(); - - $wp_config_path = Utils\locate_wp_config(); - if ( ! $wp_config_path ) { - WP_CLI::error( - "'wp-config.php' not found.\n" . - "Either create one manually or use `wp core config`." ); - } - - WP_CLI::debug( 'wp-config.php path: ' . $wp_config_path, 'bootstrap' ); - WP_CLI::do_hook( 'before_wp_config_load' ); - - // Load wp-config.php code, in the global scope - $wp_cli_original_defined_vars = get_defined_vars(); - eval( $this->get_wp_config_code() ); - foreach( get_defined_vars() as $key => $var ) { - if ( array_key_exists( $key, $wp_cli_original_defined_vars ) || 'wp_cli_original_defined_vars' === $key ) { - continue; - } - global $$key; - $$key = $var; - } - - $this->maybe_update_url_from_domain_constant(); - WP_CLI::do_hook( 'after_wp_config_load' ); - - // Prevent error notice from wp_guess_url() when core isn't installed - if ( $this->cmd_starts_with( array( 'core', 'is-installed' ) ) - && ! defined( 'COOKIEHASH' ) ) { - define( 'COOKIEHASH', md5( 'wp-cli' ) ); - } - - // Load WP-CLI utilities - require WP_CLI_ROOT . '/php/utils-wp.php'; - - // Set up WordPress bootstrap actions and filters - $this->setup_bootstrap_hooks(); - - // Load Core, mu-plugins, plugins, themes etc. - if ( Utils\wp_version_compare( '4.6-alpha-37575', '>=' ) ) { - require ABSPATH . 'wp-settings.php'; - } else { - require WP_CLI_ROOT . '/php/wp-settings-cli.php'; - } - - // Fix memory limit. See http://core.trac.wordpress.org/ticket/14889 - @ini_set( 'memory_limit', -1 ); - - // Load all the admin APIs, for convenience - require ABSPATH . 'wp-admin/includes/admin.php'; - - add_filter( 'filesystem_method', function() { return 'direct'; }, 99 ); - - WP_CLI::debug( 'Loaded WordPress', 'bootstrap' ); - WP_CLI::do_hook( 'after_wp_load' ); - - } - - private static function fake_current_site_blog( $url_parts ) { - global $current_site, $current_blog; - - if ( !isset( $url_parts['path'] ) ) { - $url_parts['path'] = '/'; - } - - $current_site = (object) array( - 'id' => 1, - 'blog_id' => 1, - 'domain' => $url_parts['host'], - 'path' => $url_parts['path'], - 'cookie_domain' => $url_parts['host'], - 'site_name' => 'Fake Site', - ); - - $current_blog = (object) array( - 'blog_id' => 1, - 'site_id' => 1, - 'domain' => $url_parts['host'], - 'path' => $url_parts['path'], - 'public' => '1', - 'archived' => '0', - 'mature' => '0', - 'spam' => '0', - 'deleted' => '0', - 'lang_id' => '0', - ); - } - - /** - * Called after wp-config.php is eval'd, to potentially reset `--url` - */ - private function maybe_update_url_from_domain_constant() { - if ( ! empty( $this->config['url'] ) || ! empty( $this->config['blog'] ) ) { - return; - } - - if ( defined( 'DOMAIN_CURRENT_SITE' ) ) { - $url = DOMAIN_CURRENT_SITE; - if ( defined( 'PATH_CURRENT_SITE' ) ) { - $url .= PATH_CURRENT_SITE; - } - \WP_CLI::set_url( $url ); - } - } - - /** - * Set up hooks meant to run during the WordPress bootstrap process - */ - private function setup_bootstrap_hooks() { - - if ( $this->config['skip-plugins'] ) { - $this->setup_skip_plugins_filters(); - } - - if ( $this->config['skip-themes'] ) { - WP_CLI::add_wp_hook( 'setup_theme', array( $this, 'action_setup_theme_wp_cli_skip_themes' ), 999 ); - } - - WP_CLI::add_wp_hook( 'wp_die_handler', function() { return '\WP_CLI\Utils\wp_die_handler'; } ); - - // Prevent code from performing a redirect - WP_CLI::add_wp_hook( 'wp_redirect', 'WP_CLI\\Utils\\wp_redirect_handler' ); - - WP_CLI::add_wp_hook( 'nocache_headers', function( $headers ){ - // WordPress might be calling nocache_headers() because of a dead db - global $wpdb; - if ( ! empty( $wpdb->error ) ) { - Utils\wp_die_handler( $wpdb->error ); - } - // Otherwise, WP might be calling nocache_headers() because WP isn't installed - Utils\wp_not_installed(); - return $headers; - }); - - // ALTERNATE_WP_CRON might trigger a redirect, which we can't handle - if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) { - WP_CLI::add_wp_hook( 'muplugins_loaded', function() { - remove_action( 'init', 'wp_cron' ); - }); - } - - // Get rid of warnings when converting single site to multisite - if ( defined( 'WP_INSTALLING' ) && $this->is_multisite() ) { - $values = array( - 'ms_files_rewriting' => null, - 'active_sitewide_plugins' => array(), - '_site_transient_update_core' => null, - '_site_transient_update_themes' => null, - '_site_transient_update_plugins' => null, - 'WPLANG' => '', - ); - foreach ( $values as $key => $value ) { - WP_CLI::add_wp_hook( "pre_site_option_$key", function () use ( $values, $key ) { - return $values[ $key ]; - } ); - } - } - - // Always permit operations against sites, regardless of status - WP_CLI::add_wp_hook( 'ms_site_check', '__return_true' ); - - // Always permit operations against WordPress, regardless of maintenance mode - WP_CLI::add_wp_hook( 'enable_maintenance_mode', function() { - return false; - }); - - // Use our own debug mode handling instead of WP core - WP_CLI::add_wp_hook( 'enable_wp_debug_mode_checks', function( $ret ) { - Utils\wp_debug_mode(); - return false; - }); - - // Never load advanced-cache.php drop-in when WP-CLI is operating - WP_CLI::add_wp_hook( 'enable_loading_advanced_cache_dropin', function() { - return false; - }); - - // In a multisite install, die if unable to find site given in --url parameter - if ( $this->is_multisite() ) { - WP_CLI::add_wp_hook( 'ms_site_not_found', function( $current_site, $domain, $path ) { - WP_CLI::error( "Site {$domain}{$path} not found." ); - }, 10, 3 ); - } - - // The APC cache is not available on the command-line, so bail, to prevent cache poisoning - WP_CLI::add_wp_hook( 'muplugins_loaded', function() { - if ( $GLOBALS['_wp_using_ext_object_cache'] && class_exists( 'APC_Object_Cache' ) ) { - WP_CLI::warning( 'Running WP-CLI while the APC object cache is activated can result in cache corruption.' ); - WP_CLI::confirm( 'Given the consequences, do you wish to continue?' ); - } - }, 0 ); - - // Handle --user parameter - if ( ! defined( 'WP_INSTALLING' ) ) { - $config = $this->config; - WP_CLI::add_wp_hook( 'init', function() use ( $config ) { - if ( isset( $config['user'] ) ) { - $fetcher = new \WP_CLI\Fetchers\User; - $user = $fetcher->get_check( $config['user'] ); - wp_set_current_user( $user->ID ); - } else { - add_action( 'init', 'kses_remove_filters', 11 ); - } - }, 0 ); - } - - // Avoid uncaught exception when using wp_mail() without defined $_SERVER['SERVER_NAME'] - WP_CLI::add_wp_hook( 'wp_mail_from', function( $from_email ){ - if ( 'wordpress@' === $from_email ) { - $sitename = strtolower( parse_url( site_url(), PHP_URL_HOST ) ); - if ( substr( $sitename, 0, 4 ) == 'www.' ) { - $sitename = substr( $sitename, 4 ); - } - $from_email = 'wordpress@' . $sitename; - } - return $from_email; - }); - - } - - /** - * Set up the filters to skip the loaded plugins - */ - private function setup_skip_plugins_filters() { - $wp_cli_filter_active_plugins = function( $plugins ) { - $skipped_plugins = WP_CLI::get_runner()->config['skip-plugins']; - if ( true === $skipped_plugins ) { - return array(); - } - if ( ! is_array( $plugins ) ) { - return $plugins; - } - foreach( $plugins as $a => $b ) { - // active_sitewide_plugins stores plugin name as the key - if ( false !== strpos( current_filter(), 'active_sitewide_plugins' ) && Utils\is_plugin_skipped( $a ) ) { - unset( $plugins[ $a ] ); - // active_plugins stores plugin name as the value - } else if ( false !== strpos( current_filter(), 'active_plugins' ) && Utils\is_plugin_skipped( $b ) ) { - unset( $plugins[ $a ] ); - } - } - // Reindex because active_plugins expects a numeric index - if ( false !== strpos( current_filter(), 'active_plugins' ) ) { - $plugins = array_values( $plugins ); - } - return $plugins; - }; - - $hooks = array( - 'pre_site_option_active_sitewide_plugins', - 'site_option_active_sitewide_plugins', - 'pre_option_active_plugins', - 'option_active_plugins', - ); - foreach( $hooks as $hook ) { - WP_CLI::add_wp_hook( $hook, $wp_cli_filter_active_plugins, 999 ); - } - WP_CLI::add_wp_hook( 'plugins_loaded', function() use ( $hooks, $wp_cli_filter_active_plugins ) { - foreach( $hooks as $hook ) { - remove_filter( $hook, $wp_cli_filter_active_plugins, 999 ); - } - }, 0 ); - } - - /** - * Set up the filters to skip the loaded theme - */ - public function action_setup_theme_wp_cli_skip_themes() { - $wp_cli_filter_active_theme = function( $value ) { - $skipped_themes = WP_CLI::get_runner()->config['skip-themes']; - if ( true === $skipped_themes ) { - return ''; - } - if ( ! is_array( $skipped_themes ) ) { - $skipped_themes = explode( ',', $skipped_themes ); - } - // Always check against the stylesheet value - // This ensures a child theme can be skipped when template differs - if ( false !== stripos( current_filter(), 'option_template' ) ) { - $checked_value = get_option( 'stylesheet' ); - } else { - $checked_value = $value; - } - if ( '' === $checked_value || in_array( $checked_value, $skipped_themes ) ) { - return ''; - } - return $value; - }; - $hooks = array( - 'pre_option_template', - 'option_template', - 'pre_option_stylesheet', - 'option_stylesheet', - ); - foreach( $hooks as $hook ) { - add_filter( $hook, $wp_cli_filter_active_theme, 999 ); - } - // Clean up after the TEMPLATEPATH and STYLESHEETPATH constants are defined - WP_CLI::add_wp_hook( 'after_setup_theme', function() use ( $hooks, $wp_cli_filter_active_theme ) { - foreach( $hooks as $hook ) { - remove_filter( $hook, $wp_cli_filter_active_theme, 999 ); - } - }, 0 ); - } - - /** - * Whether or not this WordPress install is multisite. - * - * For use after wp-config.php has loaded, but before the rest of WordPress - * is loaded. - */ - private function is_multisite() { - if ( defined( 'MULTISITE' ) ) { - return MULTISITE; - } - - if ( defined( 'SUBDOMAIN_INSTALL' ) || defined( 'VHOST' ) || defined( 'SUNRISE' ) ) { - return true; - } - - return false; - } - - /** - * Check whether there's a WP-CLI update available, and suggest update if so. - */ - private function auto_check_update() { - - // `wp cli update` only works with Phars at this time. - if ( ! Utils\inside_phar() ) { - return; - } - - $existing_phar = realpath( $_SERVER['argv'][0] ); - // Phar needs to be writable to be easily updateable. - if ( ! is_writable( $existing_phar ) || ! is_writeable( dirname( $existing_phar ) ) ) { - return; - } - - // Only check for update when a human is operating. - if ( ! function_exists( 'posix_isatty' ) || ! posix_isatty( STDOUT ) ) { - return; - } - - // Allow hosts and other providers to disable automatic check update. - if ( getenv( 'WP_CLI_DISABLE_AUTO_CHECK_UPDATE' ) ) { - return; - } - - // Permit configuration of number of days between checks. - $days_between_checks = getenv( 'WP_CLI_AUTO_CHECK_UPDATE_DAYS' ); - if ( false === $days_between_checks ) { - $days_between_checks = 1; - } - - $cache = WP_CLI::get_cache(); - $cache_key = 'wp-cli-update-check'; - // Bail early on the first check, so we don't always check on an unwritable cache. - if ( ! $cache->has( $cache_key ) ) { - $cache->write( $cache_key, time() ); - return; - } - - // Bail if last check is still within our update check time period. - $last_check = (int) $cache->read( $cache_key ); - if ( time() - ( 24 * 60 * 60 * $days_between_checks ) < $last_check ) { - return; - } - - // In case the operation fails, ensure the timestamp has been updated. - $cache->write( $cache_key, time() ); - - // Check whether any updates are available. - ob_start(); - WP_CLI::run_command( array( 'cli', 'check-update' ), array( 'format' => 'count' ) ); - $count = ob_get_clean(); - if ( ! $count ) { - return; - } - - // Looks like an update is available, so let's prompt to update. - WP_CLI::run_command( array( 'cli', 'update' ) ); - // If the Phar was replaced, we can't proceed with the original process. - exit; - } - -} - diff --git a/php/WP_CLI/SearchReplacer.php b/php/WP_CLI/SearchReplacer.php deleted file mode 100644 index 1db298198..000000000 --- a/php/WP_CLI/SearchReplacer.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -namespace WP_CLI; - -class SearchReplacer { - - private $from, $to; - private $recurse_objects; - private $max_recursion; - - /** - * @param string $from String we're looking to replace. - * @param string $to What we want it to be replaced with. - * @param bool $recurse_objects Should objects be recursively replaced? - */ - function __construct( $from, $to, $recurse_objects = false, $regex = false, $regex_flags = '' ) { - $this->from = $from; - $this->to = $to; - $this->recurse_objects = $recurse_objects; - $this->regex = $regex; - $this->regex_flags = $regex_flags; - - // Get the XDebug nesting level. Will be zero (no limit) if no value is set - $this->max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) ); - } - - /** - * Take a serialised array and unserialise it replacing elements as needed and - * unserialising any subordinate arrays and performing the replace on those too. - * Ignores any serialized objects unless $recurse_objects is set to true. - * - * @param array|string $data The data to operate on. - * @param bool $serialised Does the value of $data need to be unserialized? - * - * @return array The original array with all elements replaced as needed. - */ - function run( $data, $serialised = false ) { - return $this->_run( $data, $serialised ); - } - - /** - * @param int $recursion_level Current recursion depth within the original data. - * @param array $visited_data Data that has been seen in previous recursion iterations. - */ - private function _run( $data, $serialised, $recursion_level = 0, $visited_data = array() ) { - - // some unseriliased data cannot be re-serialised eg. SimpleXMLElements - try { - - if ( $this->recurse_objects ) { - - // If we've reached the maximum recursion level, short circuit - if ( $this->max_recursion != 0 && $recursion_level >= $this->max_recursion ) { - return $data; - } - - if ( is_array( $data ) || is_object( $data ) ) { - // If we've seen this exact object or array before, short circuit - if ( in_array( $data, $visited_data, true ) ) { - return $data; // Avoid infinite loops when there's a cycle - } - // Add this data to the list of - $visited_data[] = $data; - } - } - - if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { - $data = $this->_run( $unserialized, true, $recursion_level + 1 ); - } - - elseif ( is_array( $data ) ) { - $keys = array_keys( $data ); - foreach ( $keys as $key ) { - $data[ $key ]= $this->_run( $data[$key], false, $recursion_level + 1, $visited_data ); - } - } - - elseif ( $this->recurse_objects && is_object( $data ) ) { - foreach ( $data as $key => $value ) { - $data->$key = $this->_run( $value, false, $recursion_level + 1, $visited_data ); - } - } - - else if ( is_string( $data ) ) { - if ( $this->regex ) { - $data = preg_replace( "/$this->from/$this->regex_flags", $this->to, $data ); - } else { - $data = str_replace( $this->from, $this->to, $data ); - } - } - - if ( $serialised ) - return serialize( $data ); - - } catch( Exception $error ) { - - } - - return $data; - } -} - diff --git a/php/WP_CLI/SynopsisParser.php b/php/WP_CLI/SynopsisParser.php deleted file mode 100644 index b79f8a3ff..000000000 --- a/php/WP_CLI/SynopsisParser.php +++ /dev/null @@ -1,157 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Generate a synopsis from a command's PHPdoc arguments. - * Turns something like "<object-id>..." - * into [ optional=>false, type=>positional, repeating=>true, name=>object-id ] - */ -class SynopsisParser { - - /** - * @param string A synopsis - * @return array List of parameters - */ - public static function parse( $synopsis ) { - $tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) ); - - $params = array(); - foreach ( $tokens as $token ) { - $param = self::classify_token( $token ); - - // Some types of parameters shouldn't be mandatory - if ( isset( $param['optional'] ) && !$param['optional'] ) { - if ( 'flag' === $param['type'] || ( 'assoc' === $param['type'] && $param['value']['optional'] ) ) { - $param['type'] = 'unknown'; - } - } - - $param['token'] = $token; - $params[] = $param; - } - - return $params; - } - - /** - * @param array A structured synopsis - * @return string Rendered synopsis - */ - public static function render( $synopsis ) { - if ( ! is_array( $synopsis ) ) { - return ''; - } - $bits = array( 'positional' => '', 'assoc' => '', 'generic' => '', 'flag' => '' ); - foreach( $bits as $key => &$value ) { - foreach( $synopsis as $arg ) { - if ( empty( $arg['type'] ) - || $key !== $arg['type'] ) { - continue; - } - - if ( empty( $arg['name'] ) && 'generic' !== $arg['type'] ) { - continue; - } - - if ( 'positional' === $key ) { - $rendered_arg = "<{$arg['name']}>"; - } else if ( 'assoc' === $key ) { - $rendered_arg = "--{$arg['name']}=<{$arg['name']}>"; - } else if ( 'generic' === $key ) { - $rendered_arg = "--<field>=<value>"; - } else if ( 'flag' === $key ) { - $rendered_arg = "--{$arg['name']}"; - } - if ( ! empty( $arg['repeating'] ) ) { - $rendered_arg = "{$rendered_arg}..."; - } - if ( ! empty( $arg['optional'] ) ) { - $rendered_arg = "[{$rendered_arg}]"; - } - $value .= "{$rendered_arg} "; - } - } - $rendered = ''; - foreach( $bits as $v ) { - if ( ! empty( $v ) ) { - $rendered .= $v; - } - } - return rtrim( $rendered, ' ' ); - } - - /** - * Classify argument attributes based on its syntax. - * - * @param string $token - * @return array $param - */ - private static function classify_token( $token ) { - $param = array(); - - list( $param['optional'], $token ) = self::is_optional( $token ); - list( $param['repeating'], $token ) = self::is_repeating( $token ); - - $p_name = '([a-z-_]+)'; - $p_value = '([a-zA-Z-_|,]+)'; - - if ( '--<field>=<value>' === $token ) { - $param['type'] = 'generic'; - } elseif ( preg_match( "/^<($p_value)>$/", $token, $matches ) ) { - $param['type'] = 'positional'; - $param['name'] = $matches[1]; - } elseif ( preg_match( "/^--(?:\\[no-\\])?$p_name/", $token, $matches ) ) { - $param['name'] = $matches[1]; - - $value = substr( $token, strlen( $matches[0] ) ); - - // substr returns false <= PHP 5.6, and '' PHP 7+ - if ( false === $value || '' === $value ) { - $param['type'] = 'flag'; - } else { - $param['type'] = 'assoc'; - - list( $param['value']['optional'], $value ) = self::is_optional( $value ); - - if ( preg_match( "/^=<$p_value>$/", $value, $matches ) ) { - $param['value']['name'] = $matches[1]; - } else { - $param = array( 'type' => 'unknown' ); - } - } - } else { - $param['type'] = 'unknown'; - } - - return $param; - } - - /** - * An optional parameter is surrounded by square brackets. - * - * @param string $token - * @return array - */ - private static function is_optional( $token ) { - if ( '[' == substr( $token, 0, 1 ) && ']' == substr( $token, -1 ) ) { - return array( true, substr( $token, 1, -1 ) ); - } else { - return array( false, $token ); - } - } - - /** - * A repeating parameter is followed by an ellipsis. - * - * @param string $token - * @return array - */ - private static function is_repeating( $token ) { - if ( '...' === substr( $token, -3 ) ) { - return array( true, substr( $token, 0, -3 ) ); - } else { - return array( false, $token ); - } - } -} diff --git a/php/WP_CLI/SynopsisValidator.php b/php/WP_CLI/SynopsisValidator.php deleted file mode 100644 index f2dd2e5ff..000000000 --- a/php/WP_CLI/SynopsisValidator.php +++ /dev/null @@ -1,163 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * Checks if the list of parameters matches the specification defined in the synopsis. - */ -class SynopsisValidator { - - /** - * @var array $spec Structured representation of command synopsis. - */ - private $spec = array(); - - /** - * @param string $synopsis Command's synopsis. - */ - public function __construct( $synopsis ) { - $this->spec = SynopsisParser::parse( $synopsis ); - } - - /** - * Get any unknown arugments. - * - * @return array - */ - public function get_unknown() { - return array_column( $this->query_spec( array( - 'type' => 'unknown', - ) ), 'token' ); - } - - /** - * Check whether there are enough positional arguments. - * - * @param array $args Positional arguments. - * @return bool - */ - public function enough_positionals( $args ) { - $positional = $this->query_spec( array( - 'type' => 'positional', - 'optional' => false, - ) ); - - return count( $args ) >= count( $positional ); - } - - /** - * Check for any unknown positionals. - * - * @param array $args Positional arguments. - * @return array - */ - public function unknown_positionals( $args ) { - $positional_repeating = $this->query_spec( array( - 'type' => 'positional', - 'repeating' => true, - ) ); - - // At least one positional supports as many as possible. - if ( !empty( $positional_repeating ) ) - return array(); - - $positional = $this->query_spec( array( - 'type' => 'positional', - 'repeating' => false, - ) ); - - return array_slice( $args, count( $positional ) ); - } - - /** - * Check that all required keys are present and that they have values. - * - * @param array $assoc_args Parameters passed to command. - * @return array - */ - public function validate_assoc( $assoc_args ) { - $assoc_spec = $this->query_spec( array( - 'type' => 'assoc', - ) ); - - $errors = array( - 'fatal' => array(), - 'warning' => array() - ); - - $to_unset = array(); - - foreach ( $assoc_spec as $param ) { - $key = $param['name']; - - if ( !isset( $assoc_args[ $key ] ) ) { - if ( !$param['optional'] ) { - $errors['fatal'][$key] = "missing --$key parameter"; - } - } else { - if ( true === $assoc_args[ $key ] && !$param['value']['optional'] ) { - $error_type = ( !$param['optional'] ) ? 'fatal' : 'warning'; - $errors[ $error_type ][$key] = "--$key parameter needs a value"; - - $to_unset[] = $key; - } - } - } - - return array( $errors, $to_unset ); - } - - /** - * Check whether there are unknown parameters supplied. - * - * @param array $assoc_args Parameters passed to command. - * @return array|false - */ - public function unknown_assoc( $assoc_args ) { - $generic = $this->query_spec( array( - 'type' => 'generic', - ) ); - - if ( count( $generic ) ) - return array(); - - $known_assoc = array(); - - foreach ( $this->spec as $param ) { - if ( in_array( $param['type'], array( 'assoc', 'flag' ) ) ) - $known_assoc[] = $param['name']; - } - - return array_diff( array_keys( $assoc_args ), $known_assoc ); - } - - /** - * Filters a list of associative arrays, based on a set of key => value arguments. - * - * @param array $args An array of key => value arguments to match against - * @param string $operator - * @return array - */ - private function query_spec( $args, $operator = 'AND' ) { - $operator = strtoupper( $operator ); - $count = count( $args ); - $filtered = array(); - - foreach ( $this->spec as $key => $to_match ) { - $matched = 0; - foreach ( $args as $m_key => $m_value ) { - if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) - $matched++; - } - - if ( ( 'AND' == $operator && $matched == $count ) - || ( 'OR' == $operator && $matched > 0 ) - || ( 'NOT' == $operator && 0 == $matched ) ) { - $filtered[$key] = $to_match; - } - } - - return $filtered; - } - -} diff --git a/php/WP_CLI/UpgraderSkin.php b/php/WP_CLI/UpgraderSkin.php deleted file mode 100644 index 37f3019d5..000000000 --- a/php/WP_CLI/UpgraderSkin.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php - -namespace WP_CLI; - -/** - * A Upgrader Skin for WordPress that only generates plain-text - * - * @package wp-cli - */ -class UpgraderSkin extends \WP_Upgrader_Skin { - - public $api; - - function header() {} - function footer() {} - function bulk_header() {} - function bulk_footer() {} - - function error( $error ) { - if ( !$error ) - return; - - if ( is_string( $error ) && isset( $this->upgrader->strings[ $error ] ) ) - $error = $this->upgrader->strings[ $error ]; - - // TODO: show all errors, not just the first one - \WP_CLI::warning( $error ); - } - - function feedback( $string ) { - - if ( 'parent_theme_prepare_install' === $string ) { - \WP_CLI::get_http_cache_manager()->whitelist_package( $this->api->download_link, 'theme', $this->api->slug, $this->api->version ); - } - - if ( isset( $this->upgrader->strings[$string] ) ) - $string = $this->upgrader->strings[$string]; - - if ( strpos($string, '%') !== false ) { - $args = func_get_args(); - $args = array_splice($args, 1); - if ( !empty($args) ) - $string = vsprintf($string, $args); - } - - if ( empty($string) ) - return; - - $string = str_replace( '…', '...', strip_tags( $string ) ); - $string = html_entity_decode( $string, ENT_QUOTES, get_bloginfo( 'charset' ) ); - - \WP_CLI::log( $string ); - } -} - diff --git a/php/WP_CLI/WpHttpCacheManager.php b/php/WP_CLI/WpHttpCacheManager.php deleted file mode 100644 index a9cad95db..000000000 --- a/php/WP_CLI/WpHttpCacheManager.php +++ /dev/null @@ -1,129 +0,0 @@ -<?php - - -namespace WP_CLI; -use WP_CLI; - - -/** - * Manage caching with whitelisting - * - * @package WP_CLI - */ -class WpHttpCacheManager { - - /** - * @var array map whitelisted urls to keys and ttls - */ - protected $whitelist = array(); - - /** - * @var FileCache - */ - protected $cache; - - /** - * @param FileCache $cache - */ - public function __construct( FileCache $cache ) { - $this->cache = $cache; - - // hook into wp http api - add_filter( 'pre_http_request', array($this, 'filter_pre_http_request'), 10, 3 ); - add_filter( 'http_response', array($this, 'filter_http_response'), 10, 3 ); - } - - /** - * short circuit wp http api with cached file - */ - public function filter_pre_http_request( $response, $args, $url ) { - // check if whitelisted - if ( !isset( $this->whitelist[$url] ) ) { - return $response; - } - // check if downloading - if ( 'GET' !== $args['method'] || empty( $args['filename'] ) ) { - return $response; - } - // check cache and export to designated location - $filename = $this->cache->has( $this->whitelist[$url]['key'], $this->whitelist[$url]['ttl'] ); - if ( $filename ) { - WP_CLI::log( sprintf( 'Using cached file \'%s\'...', $filename, $url ) ); - if ( copy( $filename, $args['filename'] ) ) { - // simulate successful download response - return array( - 'response' => array('code' => ( 200 ), 'message' => 'OK'), - 'filename' => $args['filename'] - ); - } else { - WP_CLI::error( sprintf( 'Error copying cached file %s to %s', $filename, $url ) ); - } - } - return $response; - } - - - /** - * cache wp http api downloads - * - * @param array $response - * @param array $args - * @param string $url - */ - public function filter_http_response( $response, $args, $url ) { - // check if whitelisted - if ( !isset( $this->whitelist[$url] ) ) { - return $response; - } - // check if downloading - if ( 'GET' !== $args['method'] || empty( $args['filename'] ) ) { - return $response; - } - // check if download was successful - if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { - return $response; - } - // cache downloaded file - $this->cache->import( $this->whitelist[$url]['key'], $response['filename']); - return $response; - } - - /** - * whitelist a package url - * - * @param string $url - * @param string $group package group (themes, plugins, ...) - * @param string $slug package slug - * @param string $version package version - * @param int $ttl - */ - public function whitelist_package( $url, $group, $slug, $version, $ttl = null ) { - $ext = pathinfo( parse_url( $url, PHP_URL_PATH ), PATHINFO_EXTENSION ); - $key = "$group/$slug-$version.$ext"; - $this->whitelist_url( $url, $key, $ttl ); - wp_update_plugins(); - } - - /** - * whitelist a url - * - * @param string $url - * @param string $key - * @param int $ttl - */ - public function whitelist_url( $url, $key = null, $ttl = null ) { - $key = $key ? : $url; - $this->whitelist[$url] = compact( 'key', 'ttl' ); - } - - /** - * check if url is whitelisted - * - * @param string $url - * @return bool - */ - public function is_whitelisted( $url ) { - return isset( $this->whitelist[$url] ); - } - -} diff --git a/php/boot-fs.php b/php/boot-fs.php deleted file mode 100644 index c39ea2a47..000000000 --- a/php/boot-fs.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -// This file needs to parse without error in PHP < 5.3 - -if ( 'cli' !== PHP_SAPI ) { - echo "Only CLI access.\n"; - die(-1); -} - -if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { - printf( "Error: WP-CLI requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); - die(-1); -} - -define( 'WP_CLI_ROOT', dirname( __DIR__ ) ); - -include WP_CLI_ROOT . '/php/wp-cli.php'; - diff --git a/php/boot-phar.php b/php/boot-phar.php deleted file mode 100644 index 35b82e3a2..000000000 --- a/php/boot-phar.php +++ /dev/null @@ -1,6 +0,0 @@ -<?php - -define( 'WP_CLI_ROOT', 'phar://wp-cli.phar' ); - -include WP_CLI_ROOT . '/php/wp-cli.php'; - diff --git a/php/class-wp-cli-command.php b/php/class-wp-cli-command.php deleted file mode 100644 index 0cccc51a4..000000000 --- a/php/class-wp-cli-command.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php - -/** - * Base class for WP-CLI commands - * - * @package wp-cli - */ -abstract class WP_CLI_Command { - - public function __construct() {} -} - diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php deleted file mode 100644 index f9b7bcab5..000000000 --- a/php/class-wp-cli.php +++ /dev/null @@ -1,1142 +0,0 @@ -<?php - -use \WP_CLI\ExitException; -use \WP_CLI\Dispatcher; -use \WP_CLI\FileCache; -use \WP_CLI\Process; -use \WP_CLI\WpHttpCacheManager; -use \WP_CLI\Utils; - -/** - * Various utilities for WP-CLI commands. - */ -class WP_CLI { - - private static $configurator; - - private static $logger; - - private static $hooks = array(), $hooks_passed = array(); - - private static $capture_exit = false; - - /** - * Set the logger instance. - * - * @param object $logger - */ - public static function set_logger( $logger ) { - self::$logger = $logger; - } - - /** - * Get the Configurator instance - * - * @return \WP_CLI\Configurator - */ - public static function get_configurator() { - static $configurator; - - if ( !$configurator ) { - $configurator = new WP_CLI\Configurator( WP_CLI_ROOT . '/php/config-spec.php' ); - } - - return $configurator; - } - - public static function get_root_command() { - static $root; - - if ( !$root ) { - $root = new Dispatcher\RootCommand; - } - - return $root; - } - - public static function get_runner() { - static $runner; - - if ( !$runner ) { - $runner = new WP_CLI\Runner; - } - - return $runner; - } - - /** - * @return FileCache - */ - public static function get_cache() { - static $cache; - - if ( !$cache ) { - $home = getenv( 'HOME' ); - if ( !$home ) { - // sometime in windows $HOME is not defined - $home = getenv( 'HOMEDRIVE' ) . getenv( 'HOMEPATH' ); - } - $dir = getenv( 'WP_CLI_CACHE_DIR' ) ? : "$home/.wp-cli/cache"; - - // 6 months, 300mb - $cache = new FileCache( $dir, 15552000, 314572800 ); - - // clean older files on shutdown with 1/50 probability - if ( 0 === mt_rand( 0, 50 ) ) { - register_shutdown_function( function () use ( $cache ) { - $cache->clean(); - } ); - } - } - - return $cache; - } - - /** - * Set the context in which WP-CLI should be run - */ - public static function set_url( $url ) { - WP_CLI::debug( 'Set URL: ' . $url, 'bootstrap' ); - $url_parts = Utils\parse_url( $url ); - self::set_url_params( $url_parts ); - } - - private static function set_url_params( $url_parts ) { - $f = function( $key ) use ( $url_parts ) { - return \WP_CLI\Utils\get_flag_value( $url_parts, $key, '' ); - }; - - if ( isset( $url_parts['host'] ) ) { - if ( isset( $url_parts['scheme'] ) && 'https' === strtolower( $url_parts['scheme'] ) ) { - $_SERVER['HTTPS'] = 'on'; - } - - $_SERVER['HTTP_HOST'] = $url_parts['host']; - if ( isset( $url_parts['port'] ) ) { - $_SERVER['HTTP_HOST'] .= ':' . $url_parts['port']; - } - - $_SERVER['SERVER_NAME'] = $url_parts['host']; - } - - $_SERVER['REQUEST_URI'] = $f('path') . ( isset( $url_parts['query'] ) ? '?' . $url_parts['query'] : '' ); - $_SERVER['SERVER_PORT'] = \WP_CLI\Utils\get_flag_value( $url_parts, 'port', '80' ); - $_SERVER['QUERY_STRING'] = $f('query'); - } - - /** - * @return WpHttpCacheManager - */ - public static function get_http_cache_manager() { - static $http_cacher; - - if ( !$http_cacher ) { - $http_cacher = new WpHttpCacheManager( self::get_cache() ); - } - - return $http_cacher; - } - - /** - * Colorize a string for output. - * - * Yes, you too can change the color of command line text. For instance, - * here's how `WP_CLI::success()` colorizes "Success: " - * - * ``` - * WP_CLI::colorize( "%GSuccess:%n " ) - * ``` - * - * Uses `\cli\Colors::colorize()` to transform color tokens to display - * settings. Choose from the following tokens (and note 'reset'): - * - * * %y => ['color' => 'yellow'], - * * %g => ['color' => 'green'], - * * %b => ['color' => 'blue'], - * * %r => ['color' => 'red'], - * * %p => ['color' => 'magenta'], - * * %m => ['color' => 'magenta'], - * * %c => ['color' => 'cyan'], - * * %w => ['color' => 'grey'], - * * %k => ['color' => 'black'], - * * %n => ['color' => 'reset'], - * * %Y => ['color' => 'yellow', 'style' => 'bright'], - * * %G => ['color' => 'green', 'style' => 'bright'], - * * %B => ['color' => 'blue', 'style' => 'bright'], - * * %R => ['color' => 'red', 'style' => 'bright'], - * * %P => ['color' => 'magenta', 'style' => 'bright'], - * * %M => ['color' => 'magenta', 'style' => 'bright'], - * * %C => ['color' => 'cyan', 'style' => 'bright'], - * * %W => ['color' => 'grey', 'style' => 'bright'], - * * %K => ['color' => 'black', 'style' => 'bright'], - * * %N => ['color' => 'reset', 'style' => 'bright'], - * * %3 => ['background' => 'yellow'], - * * %2 => ['background' => 'green'], - * * %4 => ['background' => 'blue'], - * * %1 => ['background' => 'red'], - * * %5 => ['background' => 'magenta'], - * * %6 => ['background' => 'cyan'], - * * %7 => ['background' => 'grey'], - * * %0 => ['background' => 'black'], - * * %F => ['style' => 'blink'], - * * %U => ['style' => 'underline'], - * * %8 => ['style' => 'inverse'], - * * %9 => ['style' => 'bright'], - * * %_ => ['style' => 'bright'] - * - * @access public - * @category Output - * - * @param string $string String to colorize for output, with color tokens. - * @return string Colorized string. - */ - public static function colorize( $string ) { - return \cli\Colors::colorize( $string, self::get_runner()->in_color() ); - } - - /** - * Schedule a callback to be executed at a certain point. - * - * Hooks conceptually are very similar to WordPress actions. WP-CLI hooks - * are typically called before WordPress is loaded. - * - * WP-CLI hooks include: - * - * * `before_invoke:<command>` - Just before a command is invoked. - * * `after_invoke:<command>` - Just after a command is involved. - * * `before_wp_load` - Just before the WP load process begins. - * * `before_wp_config_load` - After wp-config.php has been located. - * * `after_wp_config_load` - After wp-config.php has been loaded into scope. - * * `after_wp_load` - Just after the WP load process has completed. - * - * WP-CLI commands can create their own hooks with `WP_CLI::do_hook()`. - * - * ``` - * # `wp network meta` confirms command is executing in multisite context. - * WP_CLI::add_command( 'network meta', 'Network_Meta_Command', array( - * 'before_invoke' => function () { - * if ( !is_multisite() ) { - * WP_CLI::error( 'This is not a multisite install.' ); - * } - * } - * ) ); - * ``` - * - * @access public - * @category Registration - * - * @param string $when Identifier for the hook. - * @param mixed $callback Callback to execute when hook is called. - * @return null - */ - public static function add_hook( $when, $callback ) { - if ( in_array( $when, self::$hooks_passed ) ) - call_user_func( $callback ); - - self::$hooks[ $when ][] = $callback; - } - - /** - * Execute callbacks registered to a given hook. - * - * See `WP_CLI::add_hook()` for details on WP-CLI's internal hook system. - * Commands can provide and call their own hooks. - * - * @access public - * @category Registration - * - * @param string $when Identifier for the hook. - * @return null - */ - public static function do_hook( $when ) { - self::$hooks_passed[] = $when; - - if ( !isset( self::$hooks[ $when ] ) ) { - return; - } - - foreach ( self::$hooks[ $when ] as $callback ) { - if ( func_num_args() > 1 ) { - $args = array_slice( func_get_args(), 1 ); - call_user_func_array( $callback, $args ); - } else { - call_user_func( $callback ); - } - } - } - - /** - * Add a callback to a WordPress action or filter. - * - * `add_action()` without needing access to `add_action()`. If WordPress is - * already loaded though, you should use `add_action()` (and `add_filter()`) - * instead. - * - * @access public - * @category Registration - * - * @param string $tag Named WordPress action or filter. - * @param mixed $function_to_add Callable to execute when the action or filter is evaluated. - * @param integer $priority Priority to add the callback as. - * @param integer $accepted_args Number of arguments to pass to callback. - * @return true - */ - public static function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { - global $wp_filter, $merged_filters; - - if ( function_exists( 'add_filter' ) ) { - add_filter( $tag, $function_to_add, $priority, $accepted_args ); - } else { - $idx = self::wp_hook_build_unique_id( $tag, $function_to_add, $priority ); - $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); - unset( $merged_filters[ $tag ] ); - } - - return true; - } - - /** - * Build Unique ID for storage and retrieval. - * - * Essentially _wp_filter_build_unique_id() without needing access to _wp_filter_build_unique_id() - */ - private static function wp_hook_build_unique_id( $tag, $function, $priority ) { - global $wp_filter; - static $filter_id_count = 0; - - if ( is_string($function) ) - return $function; - - if ( is_object($function) ) { - // Closures are currently implemented as objects - $function = array( $function, '' ); - } else { - $function = (array) $function; - } - - if (is_object($function[0]) ) { - // Object Class Calling - if ( function_exists('spl_object_hash') ) { - return spl_object_hash($function[0]) . $function[1]; - } else { - $obj_idx = get_class($function[0]).$function[1]; - if ( !isset($function[0]->wp_filter_id) ) { - if ( false === $priority ) - return false; - $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; - $function[0]->wp_filter_id = $filter_id_count; - ++$filter_id_count; - } else { - $obj_idx .= $function[0]->wp_filter_id; - } - - return $obj_idx; - } - } elseif ( is_string( $function[0] ) ) { - // Static Calling - return $function[0] . '::' . $function[1]; - } - } - - /** - * Register a command to WP-CLI. - * - * WP-CLI supports using any callable class, function, or closure as a - * command. `WP_CLI::add_command()` is used for both internal and - * third-party command registration. - * - * Command arguments are parsed from PHPDoc by default, but also can be - * supplied as an optional third argument during registration. - * - * ``` - * # Register a custom 'foo' command to output a supplied positional param. - * # - * # $ wp foo bar - * # Success: bar - * - * /** - * * My awesome closure command - * * - * * <message> - * * : An awesome message to display - * * - * * @when before_wp_load - * *\/ - * $foo = function( $args ) { - * WP_CLI::success( $args[0] ); - * }; - * WP_CLI::add_command( 'foo', $foo ); - * ``` - * - * @access public - * @category Registration - * - * @param string $name Name for the command (e.g. "post list" or "site empty"). - * @param string $callable Command implementation as a class, function or closure. - * @param array $args { - * Optional An associative array with additional registration parameters. - * 'before_invoke' => callback to execute before invoking the command, - * 'after_invoke' => callback to execute after invoking the command, - * 'shortdesc' => short description (80 char or less) for the command, - * 'synopsis' => the synopsis for the command (string or array), - * 'when' => execute callback on a named WP-CLI hook (e.g. before_wp_load), - * } - * @return true True on success, hard error if registration failed. - */ - public static function add_command( $name, $callable, $args = array() ) { - $valid = false; - if ( is_callable( $callable ) ) { - $valid = true; - } else if ( is_string( $callable ) && class_exists( (string) $callable ) ) { - $valid = true; - } else if ( is_object( $callable ) ) { - $valid = true; - } - if ( ! $valid ) { - if ( is_array( $callable ) ) { - $callable[0] = is_object( $callable[0] ) ? get_class( $callable[0] ) : $callable[0]; - $callable = array( $callable[0], $callable[1] ); - } - WP_CLI::error( sprintf( "Callable %s does not exist, and cannot be registered as `wp %s`.", json_encode( $callable ), $name ) ); - } - - foreach( array( 'before_invoke', 'after_invoke' ) as $when ) { - if ( isset( $args[ $when ] ) ) { - self::add_hook( "{$when}:{$name}", $args[ $when ] ); - } - } - - $path = preg_split( '/\s+/', $name ); - - $leaf_name = array_pop( $path ); - $full_path = $path; - - $command = self::get_root_command(); - - while ( !empty( $path ) ) { - $subcommand_name = $path[0]; - $subcommand = $command->find_subcommand( $path ); - - // create an empty container - if ( !$subcommand ) { - $subcommand = new Dispatcher\CompositeCommand( $command, $subcommand_name, - new \WP_CLI\DocParser( '' ) ); - $command->add_subcommand( $subcommand_name, $subcommand ); - } - - $command = $subcommand; - } - - $leaf_command = Dispatcher\CommandFactory::create( $leaf_name, $callable, $command ); - - if ( ! $command->can_have_subcommands() ) { - throw new Exception( sprintf( "'%s' can't have subcommands.", - implode( ' ' , Dispatcher\get_path( $command ) ) ) ); - } - - if ( isset( $args['shortdesc'] ) ) { - $leaf_command->set_shortdesc( $args['shortdesc'] ); - } - - if ( isset( $args['synopsis'] ) ) { - if ( is_string( $args['synopsis'] ) ) { - $leaf_command->set_synopsis( $args['synopsis'] ); - } else if ( is_array( $args['synopsis'] ) ) { - $synopsis = \WP_CLI\SynopsisParser::render( $args['synopsis'] ); - $leaf_command->set_synopsis( $synopsis ); - $long_desc = ''; - $bits = explode( ' ', $synopsis ); - foreach( $args['synopsis'] as $key => $arg ) { - $long_desc .= $bits[ $key ] . PHP_EOL; - if ( ! empty( $arg['description'] ) ) { - $long_desc .= ': ' . $arg['description'] . PHP_EOL; - } - $yamlify = array(); - foreach( array( 'default', 'options' ) as $key ) { - if ( isset( $arg[ $key ] ) ) { - $yamlify[ $key ] = $arg[ $key ]; - } - } - if ( ! empty( $yamlify ) ) { - $long_desc .= \Spyc::YAMLDump( $yamlify ); - $long_desc .= '---' . PHP_EOL; - } - $long_desc .= PHP_EOL; - } - if ( ! empty( $long_desc ) ) { - $long_desc = rtrim( $long_desc, PHP_EOL ); - $long_desc = '## OPTIONS' . PHP_EOL . PHP_EOL . $long_desc; - $leaf_command->set_longdesc( $long_desc ); - } - } - } - - if ( isset( $args['when'] ) ) { - self::get_runner()->register_early_invoke( $args['when'], $leaf_command ); - } - - $command->add_subcommand( $leaf_name, $leaf_command ); - return true; - } - - /** - * Display informational message without prefix, and ignore `--quiet`. - * - * Message is written to STDOUT. `WP_CLI::log()` is typically recommended; - * `WP_CLI::line()` is included for historical compat. - * - * @access public - * @category Output - * - * @param string $message Message to display to the end user. - * @return null - */ - public static function line( $message = '' ) { - echo $message . "\n"; - } - - /** - * Display informational message without prefix. - * - * Message is written to STDOUT, or discarded when `--quiet` flag is supplied. - * - * ``` - * # `wp cli update` lets user know of each step in the update process. - * WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); - * ``` - * - * @access public - * @category Output - * - * @param string $message Message to write to STDOUT. - */ - public static function log( $message ) { - self::$logger->info( $message ); - } - - /** - * Display success message prefixed with "Success: ". - * - * Success message is written to STDOUT. - * - * Typically recommended to inform user of successful script conclusion. - * - * ``` - * # wp rewrite flush expects 'rewrite_rules' option to be set after flush. - * flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); - * if ( ! get_option( 'rewrite_rules' ) ) { - * WP_CLI::warning( "Rewrite rules are empty." ); - * } else { - * WP_CLI::success( 'Rewrite rules flushed.' ); - * } - * ``` - * - * @access public - * @category Output - * - * @param string $message Message to write to STDOUT. - * @return null - */ - public static function success( $message ) { - self::$logger->success( $message ); - } - - /** - * Display debug message prefixed with "Debug: " when `--debug` is used. - * - * Debug message is written to STDERR, and includes script execution time. - * - * Helpful for optionally showing greater detail when needed. Used throughout - * WP-CLI bootstrap process for easier debugging and profiling. - * - * ``` - * # Called in `WP_CLI\Runner::set_wp_root()`. - * private static function set_wp_root( $path ) { - * define( 'ABSPATH', rtrim( $path, '/' ) . '/' ); - * WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH ); - * $_SERVER['DOCUMENT_ROOT'] = realpath( $path ); - * } - * - * # Debug details only appear when `--debug` is used. - * # $ wp --debug - * # [...] - * # Debug: ABSPATH defined: /srv/www/wordpress-develop.dev/src/ (0.225s) - * ``` - * - * @access public - * @category Output - * - * @param string $message Message to write to STDERR. - * @param string $group Organize debug message to a specific group. - * @return null - */ - public static function debug( $message, $group = false ) { - self::$logger->debug( self::error_to_string( $message ), $group ); - } - - /** - * Display warning message prefixed with "Warning: ". - * - * Warning message is written to STDERR. - * - * Use instead of `WP_CLI::debug()` when script execution should be permitted - * to continue. - * - * ``` - * # `wp plugin activate` skips activation when plugin is network active. - * $status = $this->get_status( $plugin->file ); - * // Network-active is the highest level of activation status - * if ( 'active-network' === $status ) { - * WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); - * continue; - * } - * ``` - * - * @access public - * @category Output - * - * @param string $message Message to write to STDERR. - * @return null - */ - public static function warning( $message ) { - self::$logger->warning( self::error_to_string( $message ) ); - } - - /** - * Display error message prefixed with "Error: " and exit script. - * - * Error message is written to STDERR. Defaults to halting script execution - * with return code 1. - * - * Use `WP_CLI::warning()` instead when script execution should be permitted - * to continue. - * - * ``` - * # `wp cache flush` considers flush failure to be a fatal error. - * if ( false === wp_cache_flush() ) { - * WP_CLI::error( 'The object cache could not be flushed.' ); - * } - * ``` - * - * @access public - * @category Output - * - * @param string|WP_Error $message Message to write to STDERR. - * @param boolean|integer $exit True defaults to exit(1). - * @return null - */ - public static function error( $message, $exit = true ) { - if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) ) { - self::$logger->error( self::error_to_string( $message ) ); - } - - $return_code = false; - if ( true === $exit ) { - $return_code = 1; - } elseif ( is_int( $exit ) && $exit >= 1 ) { - $return_code = $exit; - } - - if ( $return_code ) { - if ( self::$capture_exit ) { - throw new ExitException( null, $return_code ); - } - exit( $return_code ); - } - } - - /** - * Halt script execution with a specific return code. - * - * Permits script execution to be overloaded by `WP_CLI::runcommand()` - * - * @access public - * @category Output - * - * @param integer $return_code - */ - public static function halt( $return_code ) { - if ( self::$capture_exit ) { - throw new ExitException( null, $return_code ); - } - exit( $return_code ); - } - - /** - * Display a multi-line error message in a red box. Doesn't exit script. - * - * Error message is written to STDERR. - * - * @access public - * @category Output - * - * @param array $message Multi-line error message to be displayed. - */ - public static function error_multi_line( $message_lines ) { - if ( ! isset( self::get_runner()->assoc_args[ 'completions' ] ) && is_array( $message_lines ) ) { - self::$logger->error_multi_line( array_map( array( __CLASS__, 'error_to_string' ), $message_lines ) ); - } - } - - /** - * Ask for confirmation before running a destructive operation. - * - * If 'y' is provided to the question, the script execution continues. If - * 'n' or any other response is provided to the question, script exits. - * - * ``` - * # `wp db drop` asks for confirmation before dropping the database. - * - * WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args ); - * ``` - * - * @access public - * @category Input - * - * @param string $question Question to display before the prompt. - * @param array $assoc_args Skips prompt if 'yes' is provided. - */ - public static function confirm( $question, $assoc_args = array() ) { - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'yes' ) ) { - fwrite( STDOUT, $question . " [y/n] " ); - - $answer = strtolower( trim( fgets( STDIN ) ) ); - - if ( 'y' != $answer ) - exit; - } - } - - /** - * Read value from a positional argument or from STDIN. - * - * @param array $args The list of positional arguments. - * @param int $index At which position to check for the value. - * - * @return string - */ - public static function get_value_from_arg_or_stdin( $args, $index ) { - if ( isset( $args[ $index ] ) ) { - $raw_value = $args[ $index ]; - } else { - // We don't use file_get_contents() here because it doesn't handle - // Ctrl-D properly, when typing in the value interactively. - $raw_value = ''; - while ( ( $line = fgets( STDIN ) ) !== false ) { - $raw_value .= $line; - } - } - - return $raw_value; - } - - /** - * Read a value, from various formats. - * - * @access public - * @category Input - * - * @param mixed $value - * @param array $assoc_args - */ - public static function read_value( $raw_value, $assoc_args = array() ) { - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { - $value = json_decode( $raw_value, true ); - if ( null === $value ) { - WP_CLI::error( sprintf( 'Invalid JSON: %s', $raw_value ) ); - } - } else { - $value = $raw_value; - } - - return $value; - } - - /** - * Display a value, in various formats - * - * @param mixed $value Value to display. - * @param array $assoc_args Arguments passed to the command, determining format. - */ - public static function print_value( $value, $assoc_args = array() ) { - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { - $value = json_encode( $value ); - } elseif ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'yaml' ) { - $value = Spyc::YAMLDump( $value, 2, 0 ); - } elseif ( is_array( $value ) || is_object( $value ) ) { - $value = var_export( $value ); - } - - echo $value . "\n"; - } - - /** - * Convert a wp_error into a string - * - * @param mixed $errors - * @return string - */ - public static function error_to_string( $errors ) { - if ( is_string( $errors ) ) { - return $errors; - } - - // Only json_encode() the data when it needs it - $render_data = function( $data ) { - if ( is_array( $data ) || is_object( $data ) ) { - return json_encode( $data ); - } else { - return '"' . $data . '"'; - } - }; - - if ( is_object( $errors ) && is_a( $errors, 'WP_Error' ) ) { - foreach ( $errors->get_error_messages() as $message ) { - if ( $errors->get_error_data() ) { - return $message . ' ' . $render_data( $errors->get_error_data() ); - } else { - return $message; - } - } - } - } - - /** - * Launch an arbitrary external process that takes over I/O. - * - * ``` - * # `wp core download` falls back to the `tar` binary when PharData isn't available - * if ( ! class_exists( 'PharData' ) ) { - * $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball"; - * WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) ); - * return; - * } - * ``` - * - * @access public - * @category Execution - * - * @param string $command External process to launch. - * @param boolean $exit_on_error Whether to exit if the command returns an elevated return code. - * @param boolean $return_detailed Whether to return an exit status (default) or detailed execution results. - * @return int|ProcessRun The command exit status, or a ProcessRun object for full details. - */ - public static function launch( $command, $exit_on_error = true, $return_detailed = false ) { - - $proc = Process::create( $command ); - $results = $proc->run(); - - if ( -1 == $results->return_code ) { - self::warning( "Spawned process returned exit code {$results->return_code}, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); - } - - if ( $results->return_code && $exit_on_error ) - exit( $results->return_code ); - - if ( $return_detailed ) { - return $results; - } else { - return $results->return_code; - } - } - - /** - * Run a WP-CLI command in a new process reusing the current runtime arguments. - * - * Use `WP_CLI::runcommand()` instead, which is easier to use and works better. - * - * Note: While this command does persist a limited set of runtime arguments, - * it *does not* persist environment variables. Practically speaking, WP-CLI - * packages won't be loaded when using WP_CLI::launch_self() because the - * launched process doesn't have access to the current process $HOME. - * - * @access public - * @category Execution - * - * @param string $command WP-CLI command to call. - * @param array $args Positional arguments to include when calling the command. - * @param array $assoc_args Associative arguments to include when calling the command. - * @param bool $exit_on_error Whether to exit if the command returns an elevated return code. - * @param bool $return_detailed Whether to return an exit status (default) or detailed execution results. - * @param array $runtime_args Override one or more global args (path,url,user,allow-root) - * @return int|ProcessRun The command exit status, or a ProcessRun instance - */ - public static function launch_self( $command, $args = array(), $assoc_args = array(), $exit_on_error = true, $return_detailed = false, $runtime_args = array() ) { - $reused_runtime_args = array( - 'path', - 'url', - 'user', - 'allow-root', - ); - - foreach ( $reused_runtime_args as $key ) { - if ( isset( $runtime_args[ $key ] ) ) { - $assoc_args[ $key ] = $runtime_args[ $key ]; - } else if ( $value = self::get_runner()->config[ $key ] ) - $assoc_args[ $key ] = $value; - } - - $php_bin = self::get_php_binary(); - - $script_path = $GLOBALS['argv'][0]; - - if ( getenv( 'WP_CLI_CONFIG_PATH' ) ) { - $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); - } else { - $config_path = getenv( 'HOME' ) . '/.wp-cli/config.yml'; - } - $config_path = escapeshellarg( $config_path ); - - $args = implode( ' ', array_map( 'escapeshellarg', $args ) ); - $assoc_args = \WP_CLI\Utils\assoc_args_to_str( $assoc_args ); - - $full_command = "WP_CLI_CONFIG_PATH={$config_path} {$php_bin} {$script_path} {$command} {$args} {$assoc_args}"; - - return self::launch( $full_command, $exit_on_error, $return_detailed ); - } - - /** - * Get the path to the PHP binary used when executing WP-CLI. - * - * Environment values permit specific binaries to be indicated. - * - * @access public - * @category System - * - * @return string - */ - public static function get_php_binary() { - if ( getenv( 'WP_CLI_PHP_USED' ) ) - return getenv( 'WP_CLI_PHP_USED' ); - - if ( getenv( 'WP_CLI_PHP' ) ) - return getenv( 'WP_CLI_PHP' ); - - if ( defined( 'PHP_BINARY' ) ) - return PHP_BINARY; - - return 'php'; - } - - /** - * Get values of global configuration parameters. - * - * Provides access to `--path=<path>`, `--url=<url>`, and other values of - * the [global configuration parameters](https://wp-cli.org/config/). - * - * ``` - * WP_CLI::log( 'The --url=<url> value is: ' . WP_CLI::get_config( 'url' ) ); - * ``` - * - * @access public - * @category Input - * - * @param string $key Get value for a specific global configuration parameter. - * @return mixed - */ - public static function get_config( $key = null ) { - if ( null === $key ) { - return self::get_runner()->config; - } - - if ( !isset( self::get_runner()->config[ $key ] ) ) { - self::warning( "Unknown config option '$key'." ); - return null; - } - - return self::get_runner()->config[ $key ]; - } - - /** - * Run a WP-CLI command. - * - * Launches a new child process to run a specified WP-CLI command. - * Optionally: - * - * * Run the command in an existing process. - * * Prevent halting script execution on error. - * * Capture and return STDOUT, or full details about command execution. - * * Parse JSON output if the command rendered it. - * - * ``` - * $options = array( - * 'return' => true, // Return 'STDOUT'; use 'all' for full object. - * 'parse' => 'json', // Parse captured STDOUT to JSON array. - * 'launch' => false, // Reuse the current process. - * 'exit_error' => true, // Halt script execution on error. - * ); - * $plugins = WP_CLI::runcommand( 'plugin list --format=json', $options ); - * ``` - * - * @access public - * @category Execution - * - * @param string $command WP-CLI command to run, including arguments. - * @param array $options Configuration options for command execution. - * @return mixed - */ - public static function runcommand( $command, $options = array() ) { - $defaults = array( - 'launch' => true, // Launch a new process, or reuse the existing. - 'exit_error' => true, // Exit on error by default. - 'return' => false, // Capture and return output, or render in realtime. - 'parse' => false, // Parse returned output as a particular format. - ); - $options = array_merge( $defaults, $options ); - $launch = $options['launch']; - $exit_error = $options['exit_error']; - $return = $options['return']; - $parse = $options['parse']; - $retval = null; - if ( $launch ) { - if ( $return ) { - $descriptors = array( - 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); - } else { - $descriptors = array( - 0 => STDIN, - 1 => STDOUT, - 2 => STDERR, - ); - } - - $php_bin = self::get_php_binary(); - $script_path = $GLOBALS['argv'][0]; - - // Persist runtime arguments unless they've been specified otherwise. - $configurator = \WP_CLI::get_configurator(); - $argv = array_slice( $GLOBALS['argv'], 1 ); - list( $_, $_, $runtime_config ) = $configurator->parse_args( $argv ); - foreach ( $runtime_config as $k => $v ) { - if ( preg_match( "|^--{$k}=?$|", $command ) ) { - unset( $runtime_config[ $k ] ); - } - } - $runtime_config = Utils\assoc_args_to_str( $runtime_config ); - - $runcommand = "{$php_bin} {$script_path} {$runtime_config} {$command}"; - - $proc = proc_open( $runcommand, $descriptors, $pipes, getcwd(), NULL ); - - if ( $return ) { - $stdout = stream_get_contents( $pipes[1] ); - fclose( $pipes[1] ); - $stderr = stream_get_contents( $pipes[2] ); - fclose( $pipes[2] ); - } - $return_code = proc_close( $proc ); - if ( -1 == $return_code ) { - self::warning( "Spawned process returned exit code -1, which could be caused by a custom compiled version of PHP that uses the --enable-sigchild option." ); - } else if ( $return_code && $exit_error ) { - exit( $return_code ); - } - if ( true === $return || 'stdout' === $return ) { - $retval = trim( $stdout ); - } else if ( 'stderr' === $return ) { - $retval = trim( $stderr ); - } else if ( 'return_code' === $return ) { - $retval = $return_code; - } else if ( 'all' === $return ) { - $retval = (object) array( - 'stdout' => trim( $stdout ), - 'stderr' => trim( $stderr ), - 'return_code' => $return_code, - ); - } - } else { - $configurator = self::get_configurator(); - $argv = Utils\parse_str_to_argv( $command ); - list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( $argv ); - if ( $return ) { - ob_start(); - $existing_logger = self::$logger; - self::$logger = new WP_CLI\Loggers\Execution; - } - if ( ! $exit_error ) { - self::$capture_exit = true; - } - try { - self::get_runner()->run_command( $args, $assoc_args, array( 'back_compat_conversions' => true ) ); - $return_code = 0; - } catch( ExitException $e ) { - $return_code = $e->getCode(); - } - if ( $return ) { - $execution_logger = self::$logger; - self::$logger = $existing_logger; - $stdout = trim( ob_get_clean() ); - $stderr = $execution_logger->stderr; - if ( true === $return || 'stdout' === $return ) { - $retval = trim( $stdout ); - } else if ( 'stderr' === $return ) { - $retval = trim( $stderr ); - } else if ( 'return_code' === $return ) { - $retval = $return_code; - } else if ( 'all' === $return ) { - $retval = (object) array( - 'stdout' => trim( $stdout ), - 'stderr' => trim( $stderr ), - 'return_code' => $return_code, - ); - } - } - if ( ! $exit_error ) { - self::$capture_exit = false; - } - } - if ( ( true === $return || 'stdout' === $return ) - && 'json' === $parse ) { - $retval = json_decode( $retval, true ); - } - return $retval; - } - - /** - * Run a given command within the current process using the same global - * parameters. - * - * Use `WP_CLI::runcommand()` instead, which is easier to use and works better. - * - * To run a command using a new process with the same global parameters, - * use WP_CLI::launch_self(). To run a command using a new process with - * different global parameters, use WP_CLI::launch(). - * - * ``` - * ob_start(); - * WP_CLI::run_command( array( 'cli', 'cmd-dump' ) ); - * $ret = ob_get_clean(); - * ``` - * - * @access public - * @category Execution - * - * @param array $args Positional arguments including command name. - * @param array $assoc_args - */ - public static function run_command( $args, $assoc_args = array() ) { - self::get_runner()->run_command( $args, $assoc_args ); - } - - - - // DEPRECATED STUFF - - public static function add_man_dir() { - trigger_error( 'WP_CLI::add_man_dir() is deprecated. Add docs inline.', E_USER_WARNING ); - } - - // back-compat - public static function out( $str ) { - fwrite( STDOUT, $str ); - } - - // back-compat - public static function addCommand( $name, $class ) { - trigger_error( sprintf( 'wp %s: %s is deprecated. use WP_CLI::add_command() instead.', - $name, __FUNCTION__ ), E_USER_WARNING ); - self::add_command( $name, $class ); - } -} diff --git a/php/commands/cache.php b/php/commands/cache.php deleted file mode 100644 index 96455d69c..000000000 --- a/php/commands/cache.php +++ /dev/null @@ -1,339 +0,0 @@ -<?php - -/** - * Manage the object cache. - * - * Use a persistent object cache drop-in to persist cache values between requests. - * - * ## EXAMPLES - * - * # Set cache. - * $ wp cache set my_key my_value my_group 300 - * Success: Set object 'my_key' in group 'my_group'. - * - * # Get cache. - * $ wp cache get my_key my_group - * my_value - * - * @package wp-cli - */ -class Cache_Command extends WP_CLI_Command { - - /** - * Add a value to the object cache. - * - * Errors if a value already exists for the key, which means the value can't - * be added. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * <value> - * : Value to add to the key. - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * [<expiration>] - * : Define how long to keep the value, in seconds. `0` means as long as possible. - * --- - * default: 0 - * --- - * - * ## EXAMPLES - * - * # Add cache. - * $ wp cache add my_key my_group my_value 300 - * Success: Added object 'my_key' in group 'my_value'. - */ - public function add( $args, $assoc_args ) { - list( $key, $value, $group, $expiration ) = $args; - - if ( ! wp_cache_add( $key, $value, $group, $expiration ) ) { - WP_CLI::error( "Could not add object '$key' in group '$group'. Does it already exist?" ); - } - - WP_CLI::success( "Added object '$key' in group '$group'." ); - } - - /** - * Decrement a value in the object cache. - * - * Errors if the value can't be decremented. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * [<offset>] - * : The amount by which to decrement the item's value. - * --- - * default: 1 - * --- - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * ## EXAMPLES - * - * # Decrease cache value. - * $ wp cache decr my_key 2 my_group - * 48 - */ - public function decr( $args, $assoc_args ) { - list( $key, $offset, $group ) = $args; - $value = wp_cache_decr( $key, $offset, $group ); - - if ( false === $value ) { - WP_CLI::error( 'The value was not decremented.' ); - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Remove a value from the object cache. - * - * Errors if the value can't be deleted. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * ## EXAMPLES - * - * # Delete cache. - * $ wp cache delete my_key my_group - * Success: Object deleted. - */ - public function delete( $args, $assoc_args ) { - list( $key, $group ) = $args; - $result = wp_cache_delete( $key, $group ); - - if ( false === $result ) { - WP_CLI::error( 'The object was not deleted.' ); - } - - WP_CLI::success( 'Object deleted.' ); - } - - /** - * Flush the object cache. - * - * For WordPress multisite instances using a persistent object cache, - * flushing the object cache will typically flush the cache for all sites. - * Beware of the performance impact when flushing the object cache in - * production. - * - * Errors if the object cache can't be flushed. - * - * ## EXAMPLES - * - * # Flush cache. - * $ wp cache flush - * Success: The cache was flushed. - */ - public function flush( $args, $assoc_args ) { - $value = wp_cache_flush(); - - if ( false === $value ) { - WP_CLI::error( 'The object cache could not be flushed.' ); - } - - WP_CLI::success( 'The cache was flushed.' ); - } - - /** - * Get a value from the object cache. - * - * Errors if the value doesn't exist. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * ___ - * - * ## EXAMPLES - * - * # Get cache. - * $ wp cache get my_key my_group - * my_value - */ - public function get( $args, $assoc_args ) { - list( $key, $group ) = $args; - $value = wp_cache_get( $key, $group ); - - if ( false === $value ) { - WP_CLI::error( "Object with key '$key' and group '$group' not found." ); - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Increment a value in the object cache. - * - * Errors if the value can't be incremented. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * [<offset>] - * : The amount by which to increment the item's value. - * --- - * default: 1 - * --- - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * ## EXAMPLES - * - * # Increase cache value. - * $ wp cache incr my_key 2 my_group - * 50 - */ - public function incr( $args, $assoc_args ) { - list( $key, $offset, $group ) = $args; - $value = wp_cache_incr( $key, $offset, $group ); - - if ( false === $value ) { - WP_CLI::error( 'The value was not incremented.' ); - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Replace a value in the object cache, if the value already exists. - * - * Errors if the value can't be replaced. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * <value> - * : Value to replace. - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * [<expiration>] - * : Define how long to keep the value, in seconds. `0` means as long as possible. - * --- - * default: 0 - * --- - * - * ## EXAMPLES - * - * # Replace cache. - * $ wp cache replace my_key new_value my_group - * Success: Replaced object 'my_key' in group 'my_group'. - */ - public function replace( $args, $assoc_args ) { - list( $key, $value, $group, $expiration ) = $args; - $result = wp_cache_replace( $key, $value, $group, $expiration ); - - if ( false === $result ) { - WP_CLI::error( "Could not replace object '$key' in group '$group'. Does it not exist?" ); - } - - WP_CLI::success( "Replaced object '$key' in group '$group'." ); - } - - /** - * Set a value to the object cache, regardless of whether it already exists. - * - * Errors if the value can't be set. - * - * ## OPTIONS - * - * <key> - * : Cache key. - * - * <value> - * : Value to set on the key. - * - * [<group>] - * : Method for grouping data within the cache which allows the same key to be used across groups. - * --- - * default: default - * --- - * - * [<expiration>] - * : Define how long to keep the value, in seconds. `0` means as long as possible. - * --- - * default: 0 - * --- - * - * ## EXAMPLES - * - * # Set cache. - * $ wp cache set my_key my_value my_group 300 - * Success: Set object 'my_key' in group 'my_group'. - */ - public function set( $args, $assoc_args ) { - list( $key, $value, $group, $expiration ) = $args; - $result = wp_cache_set( $key, $value, $group, $expiration ); - - if ( false === $result ) { - WP_CLI::error( "Could not add object '$key' in group '$group'." ); - } - - WP_CLI::success( "Set object '$key' in group '$group'." ); - } - - /** - * Attempts to determine which object cache is being used. - * - * Note that the guesses made by this function are based on the - * WP_Object_Cache classes that define the 3rd party object cache extension. - * Changes to those classes could render problems with this function's - * ability to determine which object cache is being used. - * - * ## EXAMPLES - * - * # Check cache type. - * $ wp cache type - * Default - */ - public function type( $args, $assoc_args ) { - $message = WP_CLI\Utils\wp_get_cache_type(); - WP_CLI::line( $message ); - } - -} - -WP_CLI::add_command( 'cache', 'Cache_Command' ); diff --git a/php/commands/cap.php b/php/commands/cap.php deleted file mode 100644 index c00001320..000000000 --- a/php/commands/cap.php +++ /dev/null @@ -1,179 +0,0 @@ -<?php - -/** - * Manage user capabilities. - * - * ## EXAMPLES - * - * # Add 'spectate' capability to 'author' role. - * $ wp cap add 'author' 'spectate' - * Success: Added 1 capability to 'author' role. - * - * # Add all caps from 'editor' role to 'author' role. - * $ wp cap list 'editor' | xargs wp cap add 'author' - * Success: Added 24 capabilities to 'author' role. - * - * # Remove all caps from 'editor' role that also appear in 'author' role. - * $ wp cap list 'author' | xargs wp cap remove 'editor' - * Success: Removed 34 capabilities from 'editor' role. - */ -class Capabilities_Command extends WP_CLI_Command { - - private $fields = array( - 'name' - ); - - /** - * List capabilities for a given role. - * - * ## OPTIONS - * - * <role> - * : Key for the role. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: list - * options: - * - list - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * # Display alphabetical list of Contributor capabilities. - * $ wp cap list 'contributor' | sort - * delete_posts - * edit_posts - * level_0 - * level_1 - * read - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $role_obj = self::get_role( $args[0] ); - - if ( 'list' === $assoc_args['format'] ) { - foreach ( array_keys( $role_obj->capabilities ) as $cap ) { - WP_CLI::line( $cap ); - } - } - else { - $output_caps = array(); - foreach ( array_keys( $role_obj->capabilities ) as $cap ) { - $output_cap = new stdClass; - - $output_cap->name = $cap; - - $output_caps[] = $output_cap; - } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_caps ); - } - } - - /** - * Add capabilities to a given role. - * - * ## OPTIONS - * - * <role> - * : Key for the role. - * - * <cap>... - * : One or more capabilities to add. - * - * ## EXAMPLES - * - * # Add 'spectate' capability to 'author' role. - * $ wp cap add author spectate - * Success: Added 1 capability to 'author' role. - */ - public function add( $args ) { - self::persistence_check(); - - $role = array_shift( $args ); - - $role_obj = self::get_role( $role ); - - $count = 0; - - foreach ( $args as $cap ) { - if ( $role_obj->has_cap( $cap ) ) - continue; - - $role_obj->add_cap( $cap ); - - $count++; - } - - $message = ( 1 === $count ) ? "Added %d capability to '%s' role." : "Added %d capabilities to '%s' role."; - WP_CLI::success( sprintf( $message, $count, $role ) ); - } - - /** - * Remove capabilities from a given role. - * - * ## OPTIONS - * - * <role> - * : Key for the role. - * - * <cap>... - * : One or more capabilities to remove. - * - * ## EXAMPLES - * - * # Remove 'spectate' capability from 'author' role. - * $ wp cap remove author spectate - * Success: Removed 1 capability from 'author' role. - */ - public function remove( $args ) { - self::persistence_check(); - - $role = array_shift( $args ); - - $role_obj = self::get_role( $role ); - - $count = 0; - - foreach ( $args as $cap ) { - if ( !$role_obj->has_cap( $cap ) ) - continue; - - $role_obj->remove_cap( $cap ); - - $count++; - } - - $message = ( 1 === $count ) ? "Removed %d capability from '%s' role." : "Removed %d capabilities from '%s' role."; - WP_CLI::success( sprintf( $message, $count, $role ) ); - } - - private static function get_role( $role ) { - global $wp_roles; - - $role_obj = $wp_roles->get_role( $role ); - - if ( !$role_obj ) - WP_CLI::error( "'$role' role not found." ); - - return $role_obj; - } - - private static function persistence_check() { - global $wp_roles; - - if ( !$wp_roles->use_db ) - WP_CLI::error( "Role definitions are not persistent." ); - } -} - -WP_CLI::add_command( 'cap', 'Capabilities_Command' ); - diff --git a/php/commands/cli.php b/php/commands/cli.php deleted file mode 100644 index 4bb76247d..000000000 --- a/php/commands/cli.php +++ /dev/null @@ -1,575 +0,0 @@ -<?php - -use \Composer\Semver\Comparator; -use \WP_CLI\Dispatcher; -use \WP_CLI\Utils; - -/** - * Manage WP-CLI itself. - * - * ## EXAMPLES - * - * # Display the version currently installed. - * $ wp cli version - * WP-CLI 0.24.1 - * - * # Check for updates to WP-CLI. - * $ wp cli check-update - * Success: WP-CLI is at the latest version. - * - * # Update WP-CLI to the latest stable release. - * $ wp cli update - * You have version 0.24.0. Would you like to update to 0.24.1? [y/n] y - * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar... - * New version works. Proceeding to replace. - * Success: Updated WP-CLI to 0.24.1. - * - * @when before_wp_load - */ -class CLI_Command extends WP_CLI_Command { - - private function command_to_array( $command ) { - $dump = array( - 'name' => $command->get_name(), - 'description' => $command->get_shortdesc(), - 'longdesc' => $command->get_longdesc(), - ); - - foreach ( $command->get_subcommands() as $subcommand ) { - $dump['subcommands'][] = self::command_to_array( $subcommand ); - } - - if ( empty( $dump['subcommands'] ) ) { - $dump['synopsis'] = (string) $command->get_synopsis(); - } - - return $dump; - } - - /** - * Print WP-CLI version. - * - * ## EXAMPLES - * - * # Display CLI version. - * $ wp cli version - * WP-CLI 0.24.1 - */ - public function version() { - WP_CLI::line( 'WP-CLI ' . WP_CLI_VERSION ); - } - - /** - * Print various details about the WP-CLI environment. - * - * Helpful for diagnostic purposes, this command shares: - * - * * PHP binary used. - * * PHP binary version. - * * php.ini configuration file used (which is typically different than web). - * * WP-CLI root dir: where WP-CLI is installed (if non-Phar install). - * * WP-CLI global config: where the global config YAML file is located. - * * WP-CLI project config: where the project config YAML file is located. - * * WP-CLI version: currently installed version. - * - * See [config docs](https://wp-cli.org/config/) for more details on global - * and project config YAML files. - * - * ## OPTIONS - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: list - * options: - * - list - * - json - * --- - * - * ## EXAMPLES - * - * # Display various data about the CLI environment. - * $ wp cli info - * PHP binary: /usr/bin/php5 - * PHP version: 5.5.9-1ubuntu4.16 - * php.ini used: /etc/php5/cli/php.ini - * WP-CLI root dir: phar://wp-cli.phar - * WP-CLI packages dir: /home/person/.wp-cli/packages/ - * WP-CLI global config: - * WP-CLI project config: - * WP-CLI version: 0.24.1 - */ - public function info( $_, $assoc_args ) { - $php_bin = WP_CLI::get_php_binary(); - - $runner = WP_CLI::get_runner(); - - $packages_dir = $runner->get_packages_dir_path(); - if ( ! is_dir( $packages_dir ) ) { - $packages_dir = null; - } - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) { - $info = array( - 'php_binary_path' => $php_bin, - 'global_config_path' => $runner->global_config_path, - 'project_config_path' => $runner->project_config_path, - 'wp_cli_dir_path' => WP_CLI_ROOT, - 'wp_cli_packages_dir_path' => $packages_dir, - 'wp_cli_version' => WP_CLI_VERSION, - ); - - WP_CLI::line( json_encode( $info ) ); - } else { - WP_CLI::line( "PHP binary:\t" . $php_bin ); - WP_CLI::line( "PHP version:\t" . PHP_VERSION ); - WP_CLI::line( "php.ini used:\t" . get_cfg_var( 'cfg_file_path' ) ); - WP_CLI::line( "WP-CLI root dir:\t" . WP_CLI_ROOT ); - WP_CLI::line( "WP-CLI packages dir:\t" . $packages_dir ); - WP_CLI::line( "WP-CLI global config:\t" . $runner->global_config_path ); - WP_CLI::line( "WP-CLI project config:\t" . $runner->project_config_path ); - WP_CLI::line( "WP-CLI version:\t" . WP_CLI_VERSION ); - } - } - - /** - * Check to see if there is a newer version of WP-CLI available. - * - * Queries the Github releases API. Returns available versions if there are - * updates available, or success message if using the latest release. - * - * ## OPTIONS - * - * [--patch] - * : Only list patch updates. - * - * [--minor] - * : Only list minor updates. - * - * [--major] - * : Only list major updates. - * - * [--field=<field>] - * : Prints the value of a single field for each update. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,update_type,package_url. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * # Check for update. - * $ wp cli check-update - * Success: WP-CLI is at the latest version. - * - * # Check for update and new version is available. - * $ wp cli check-update - * +---------+-------------+-------------------------------------------------------------------------------+ - * | version | update_type | package_url | - * +---------+-------------+-------------------------------------------------------------------------------+ - * | 0.24.1 | patch | https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar | - * +---------+-------------+-------------------------------------------------------------------------------+ - * - * @subcommand check-update - */ - public function check_update( $_, $assoc_args ) { - $updates = $this->get_updates( $assoc_args ); - - if ( $updates ) { - $formatter = new \WP_CLI\Formatter( - $assoc_args, - array( 'version', 'update_type', 'package_url' ) - ); - $formatter->display_items( $updates ); - } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { - $update_type = $this->get_update_type_str( $assoc_args ); - WP_CLI::success( "WP-CLI is at the latest{$update_type}version." ); - } - } - - /** - * Update WP-CLI to the latest release. - * - * Default behavior is to check the releases API for the newest stable - * version, and prompt if one is available. - * - * Use `--stable` to install or reinstall the latest stable version. - * - * Use `--nightly` to install the latest built version of the master branch. - * While not recommended for production, nightly contains the latest and - * greatest, and should be stable enough for development and staging - * environments. - * - * Only works for the Phar installation mechanism. - * - * ## OPTIONS - * - * [--patch] - * : Only perform patch updates. - * - * [--minor] - * : Only perform minor updates. - * - * [--major] - * : Only perform major updates. - * - * [--stable] - * : Update to the latest stable release. Skips update check. - * - * [--nightly] - * : Update to the latest built version of the master branch. Potentially unstable. - * - * [--yes] - * : Do not prompt for confirmation. - * - * ## EXAMPLES - * - * # Update CLI. - * $ wp cli update - * You have version 0.24.0. Would you like to update to 0.24.1? [y/n] y - * Downloading from https://github.com/wp-cli/wp-cli/releases/download/v0.24.1/wp-cli-0.24.1.phar... - * New version works. Proceeding to replace. - * Success: Updated WP-CLI to 0.24.1. - */ - public function update( $_, $assoc_args ) { - if ( ! Utils\inside_phar() ) { - WP_CLI::error( "You can only self-update Phar files." ); - } - - $old_phar = realpath( $_SERVER['argv'][0] ); - - if ( ! is_writable( $old_phar ) ) { - WP_CLI::error( sprintf( "%s is not writable by current user.", $old_phar ) ); - } else if ( ! is_writeable( dirname( $old_phar ) ) ) { - WP_CLI::error( sprintf( "%s is not writable by current user.", dirname( $old_phar ) ) ); - } - - if ( Utils\get_flag_value( $assoc_args, 'nightly' ) ) { - WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest nightly?', WP_CLI_VERSION ), $assoc_args ); - $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar'; - $md5_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar.md5'; - } else if ( Utils\get_flag_value( $assoc_args, 'stable' ) ) { - WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to the latest stable release?', WP_CLI_VERSION ), $assoc_args ); - $download_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar'; - $md5_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar.md5'; - } else { - - $updates = $this->get_updates( $assoc_args ); - - if ( empty( $updates ) ) { - $update_type = $this->get_update_type_str( $assoc_args ); - WP_CLI::success( "WP-CLI is at the latest{$update_type}version." ); - return; - } - - $newest = $updates[0]; - - WP_CLI::confirm( sprintf( 'You have version %s. Would you like to update to %s?', WP_CLI_VERSION, $newest['version'] ), $assoc_args ); - - $download_url = $newest['package_url']; - $md5_url = str_replace( '.phar', '.phar.md5', $download_url ); - } - - WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) ); - - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . '.phar'; - - $headers = array(); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody. - 'filename' => $temp - ); - - Utils\http_request( 'GET', $download_url, null, $headers, $options ); - - $md5_response = Utils\http_request( 'GET', $md5_url ); - if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$md5_response->status_code})." ); - } - $md5_file = md5_file( $temp ); - $release_hash = trim( $md5_response->body ); - if ( $md5_file === $release_hash ) { - WP_CLI::log( 'md5 hash verified: ' . $release_hash ); - } else { - WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$release_hash})." ); - } - - $allow_root = WP_CLI::get_runner()->config['allow-root'] ? '--allow-root' : ''; - $php_binary = WP_CLI::get_php_binary(); - $process = WP_CLI\Process::create( "{$php_binary} $temp --info {$allow_root}" ); - $result = $process->run(); - if ( 0 !== $result->return_code || false === stripos( $result->stdout, 'WP-CLI version:' ) ) { - $multi_line = explode( PHP_EOL, $result->stderr ); - WP_CLI::error_multi_line( $multi_line ); - WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli update again.' ); - } - - WP_CLI::log( 'New version works. Proceeding to replace.' ); - - $mode = fileperms( $old_phar ) & 511; - - if ( false === @chmod( $temp, $mode ) ) { - WP_CLI::error( sprintf( "Cannot chmod %s.", $temp ) ); - } - - class_exists( '\cli\Colors' ); // This autoloads \cli\Colors - after we move the file we no longer have access to this class. - - if ( false === @rename( $temp, $old_phar ) ) { - WP_CLI::error( sprintf( "Cannot move %s to %s", $temp, $old_phar ) ); - } - - if ( Utils\get_flag_value( $assoc_args, 'nightly' ) ) { - $updated_version = 'the latest nightly release'; - } else if ( Utils\get_flag_value( $assoc_args, 'stable' ) ) { - $updated_version = 'the latest stable release'; - } else { - $updated_version = $newest['version']; - } - WP_CLI::success( sprintf( 'Updated WP-CLI to %s.', $updated_version ) ); - } - - /** - * Returns update information. - */ - private function get_updates( $assoc_args ) { - $url = 'https://api.github.com/repos/wp-cli/wp-cli/releases'; - - $options = array( - 'timeout' => 30 - ); - - $headers = array( - 'Accept' => 'application/json' - ); - $response = Utils\http_request( 'GET', $url, $headers, $options ); - - if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( sprintf( "Failed to get latest version (HTTP code %d).", $response->status_code ) ); - } - - $release_data = json_decode( $response->body ); - - $updates = array( - 'major' => false, - 'minor' => false, - 'patch' => false, - ); - foreach ( $release_data as $release ) { - - // Get rid of leading "v" if there is one set. - $release_version = $release->tag_name; - if ( 'v' === substr( $release_version, 0, 1 ) ) { - $release_version = ltrim( $release_version, 'v' ); - } - - $update_type = Utils\get_named_sem_ver( $release_version, WP_CLI_VERSION ); - if ( ! $update_type ) { - continue; - } - - if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $release_version, $updates[ $update_type ]['version'] ) ) { - continue; - } - - $updates[ $update_type ] = array( - 'version' => $release_version, - 'update_type' => $update_type, - 'package_url' => $release->assets[0]->browser_download_url - ); - } - - foreach( $updates as $type => $value ) { - if ( empty( $value ) ) { - unset( $updates[ $type ] ); - } - } - - foreach( array( 'major', 'minor', 'patch' ) as $type ) { - if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { - return ! empty( $updates[ $type ] ) ? array( $updates[ $type ] ) : false; - } - } - - if ( empty( $updates ) && preg_match( '#-alpha-(.+)$#', WP_CLI_VERSION, $matches ) ) { - $version_url = 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/NIGHTLY_VERSION'; - $response = Utils\http_request( 'GET', $version_url ); - if ( ! $response->success || 200 !== $response->status_code ) { - WP_CLI::error( sprintf( "Failed to get current nightly version (HTTP code %d)", $response->status_code ) ); - } - $nightly_version = trim( $response->body ); - if ( WP_CLI_VERSION != $nightly_version ) { - $updates['nightly'] = array( - 'version' => $nightly_version, - 'update_type' => 'nightly', - 'package_url' => 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar', - ); - } - } - - return array_values( $updates ); - } - - /** - * Dump the list of global parameters, as JSON or in var_export format. - * - * ## OPTIONS - * - * [--with-values] - * : Display current values also. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: json - * options: - * - var_export - * - json - * --- - * - * ## EXAMPLES - * - * # Dump the list of global parameters. - * $ wp cli param-dump --format=var_export - * array ( - * 'path' => - * array ( - * 'runtime' => '=<path>', - * 'file' => '<path>', - * 'synopsis' => '', - * 'default' => NULL, - * 'multiple' => false, - * 'desc' => 'Path to the WordPress files.', - * ), - * 'url' => - * array ( - * - * @subcommand param-dump - */ - function param_dump( $_, $assoc_args ) { - $spec = \WP_CLI::get_configurator()->get_spec(); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'with-values' ) ) { - $config = \WP_CLI::get_configurator()->to_array(); - // Copy current config values to $spec - foreach ( $spec as $key => $value ) { - if ( isset( $config[0][$key] ) ) { - $current = $config[0][$key]; - } else { - $current = NULL; - } - $spec[$key]['current'] = $current; - } - } - - if ( 'var_export' === \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) ) { - var_export( $spec ); - } else { - echo json_encode( $spec ); - } - } - - /** - * Dump the list of installed commands, as JSON. - * - * ## EXAMPLES - * - * # Dump the list of installed commands. - * $ wp cli cmd-dump - * {"name":"wp","description":"Manage WordPress through the command-line.","longdesc":"\n\n## GLOBAL PARAMETERS\n\n --path=<path>\n Path to the WordPress files.\n\n --ssh=<ssh>\n Perform operation against a remote server over SSH.\n\n --url=<url>\n Pretend request came from given URL. In multisite, this argument is how the target site is specified. \n\n --user=<id|login|email>\n - * - * @subcommand cmd-dump - */ - public function cmd_dump() { - echo json_encode( self::command_to_array( WP_CLI::get_root_command() ) ); - } - - /** - * Generate tab completion strings. - * - * ## OPTIONS - * - * --line=<line> - * : The current command line to be executed. - * - * --point=<point> - * : The index to the current cursor position relative to the beginning of the command. - * - * ## EXAMPLES - * - * # Generate tab completion strings. - * $ wp cli completions --line='wp eva' --point=100 - * eval - * eval-file - */ - public function completions( $_, $assoc_args ) { - $line = substr( $assoc_args['line'], 0, $assoc_args['point'] ); - $compl = new \WP_CLI\Completions( $line ); - $compl->render(); - } - - /** - * List available WP-CLI aliases. - * - * Aliases are shorthand references to WordPress installs. For instance, - * `@dev` could refer to a development install and `@prod` could refer to - * a production install. This command gives you visibility in what - * registered aliases you have available. - * - * ## OPTIONS - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: yaml - * options: - * - yaml - * - json - * --- - * - * ## EXAMPLES - * - * # List all available aliases. - * $ wp cli alias - * --- - * @all: Run command against every registered alias. - * @prod: - * ssh: runcommand@runcommand.io~/webapps/production - * @dev: - * ssh: vagrant@192.168.50.10/srv/www/runcommand.dev - * @both: - * - @prod - * - @dev - * - * @alias aliases - */ - public function alias( $_, $assoc_args ) { - WP_CLI::print_value( WP_CLI::get_runner()->aliases, $assoc_args ); - } - - /** - * Get a string representing the type of update being checked for. - */ - private function get_update_type_str( $assoc_args ) { - $update_type = ' '; - foreach( array( 'major', 'minor', 'patch' ) as $type ) { - if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { - $update_type = ' ' . $type . ' '; - break; - } - } - return $update_type; - } - -} - -WP_CLI::add_command( 'cli', 'CLI_Command' ); diff --git a/php/commands/comment-meta.php b/php/commands/comment-meta.php deleted file mode 100644 index f16853124..000000000 --- a/php/commands/comment-meta.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -/** - * Manage comment custom fields. - * - * ## EXAMPLES - * - * # Set comment meta - * $ wp comment meta set 123 description "Mary is a WordPress developer." - * Success: Updated custom field 'description'. - * - * # Get comment meta - * $ wp comment meta get 123 description - * Mary is a WordPress developer. - * - * # Update comment meta - * $ wp comment meta update 123 description "Mary is an awesome WordPress developer." - * Success: Updated custom field 'description'. - * - * # Delete comment meta - * $ wp comment meta delete 123 description - * Success: Deleted custom field. - */ -class Comment_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'comment'; - - /** - * Check that the comment ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $fetcher = new \WP_CLI\Fetchers\Comment; - $comment = $fetcher->get_check( $object_id ); - return $comment->comment_ID; - } -} - -WP_CLI::add_command( 'comment meta', 'Comment_Meta_Command' ); diff --git a/php/commands/comment.php b/php/commands/comment.php deleted file mode 100644 index 8dd283b5a..000000000 --- a/php/commands/comment.php +++ /dev/null @@ -1,663 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage comments. - * - * ## EXAMPLES - * - * # Create a new comment. - * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" - * Success: Created comment 932. - * - * # Update an existing comment. - * $ wp comment update 123 --comment_author='That Guy' - * Success: Updated comment 123. - * - * # Delete an existing comment. - * $ wp comment delete 1337 --force - * Success: Deleted comment 1337. - * - * # Delete all spam comments. - * $ wp comment delete $(wp comment list --status=spam --format=ids) - * Success: Deleted comment 264. - * Success: Deleted comment 262. - * - * @package wp-cli - */ -class Comment_Command extends \WP_CLI\CommandWithDBObject { - - protected $obj_type = 'comment'; - protected $obj_id_key = 'comment_ID'; - protected $obj_fields = array( - 'comment_ID', - 'comment_post_ID', - 'comment_date', - 'comment_approved', - 'comment_author', - 'comment_author_email', - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\Comment; - } - - /** - * Create a new comment. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : Associative args for the new comment. See wp_insert_comment(). - * - * [--porcelain] - * : Output just the new comment id. - * - * ## EXAMPLES - * - * # Create comment. - * $ wp comment create --comment_post_ID=15 --comment_content="hello blog" --comment_author="wp-cli" - * Success: Created comment 932. - */ - public function create( $args, $assoc_args ) { - $assoc_args = wp_slash( $assoc_args ); - parent::_create( $args, $assoc_args, function ( $params ) { - if ( isset( $params['comment_post_ID'] ) ) { - $post_id = $params['comment_post_ID']; - $post = get_post( $post_id ); - if ( !$post ) { - return new WP_Error( 'no_post', "Can't find post $post_id." ); - } - } - - // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and - // avoid wp_die() formatted messages or notifications - $comment_id = wp_insert_comment( $params ); - - if ( !$comment_id ) { - return new WP_Error( 'db_error', 'Could not create comment.' ); - } - - return $comment_id; - } ); - } - - /** - * Update one or more comments. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of comments to update. - * - * --<field>=<value> - * : One or more fields to update. See wp_update_comment(). - * - * ## EXAMPLES - * - * # Update comment. - * $ wp comment update 123 --comment_author='That Guy' - * Success: Updated comment 123. - */ - public function update( $args, $assoc_args ) { - $assoc_args = wp_slash( $assoc_args ); - parent::_update( $args, $assoc_args, function ( $params ) { - if ( !wp_update_comment( $params ) ) { - return new WP_Error( 'Could not update comment.' ); - } - - return true; - } ); - } - - /** - * Generate some number of new dummy comments. - * - * Creates a specified number of new comments with dummy data. - * - * ## OPTIONS - * - * [--count=<number>] - * : How many comments to generate? - * --- - * default: 100 - * --- - * - * [--post_id=<post-id>] - * : Assign comments to a specific post. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: progress - * options: - * - progress - * - ids - * --- - * - * ## EXAMPLES - * - * # Generate comments for the given post. - * $ wp comment generate --format=ids --count=3 --post_id=123 - * 138 139 140 - * - * # Add meta to every generated comment. - * $ wp comment generate --format=ids --count=3 | xargs -d ' ' -I % wp comment meta add % foo bar - * Success: Added custom field. - * Success: Added custom field. - * Success: Added custom field. - */ - public function generate( $args, $assoc_args ) { - - $defaults = array( - 'count' => 100, - 'post_id' => null, - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); - - $notify = false; - if ( 'progress' === $format ) { - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); - } - - $comment_count = wp_count_comments(); - $total = (int )$comment_count->total_comments; - $limit = $total + $assoc_args['count']; - - for ( $i = $total; $i < $limit; $i++ ) { - $comment_id = wp_insert_comment( array( - 'comment_content' => "Comment {$i}", - 'comment_post_ID' => $assoc_args['post_id'], - ) ); - if ( 'progress' === $format ) { - $notify->tick(); - } else if ( 'ids' === $format ) { - if ( 'ids' === $format ) { - echo $comment_id; - if ( $i < $limit - 1 ) { - echo ' '; - } - } - } - } - - if ( 'progress' === $format ) { - $notify->finish(); - } - - } - - /** - * Get data of a single comment. - * - * ## OPTIONS - * - * <id> - * : The comment to get. - * - * [--field=<field>] - * : Instead of returning the whole comment, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get comment. - * $ wp comment get 21 --field=content - * Thanks for all the comments, everyone! - */ - public function get( $args, $assoc_args ) { - $comment_id = (int)$args[0]; - $comment = get_comment( $comment_id ); - if ( empty( $comment ) ) { - WP_CLI::error( "Invalid comment ID." ); - } - - if ( empty( $assoc_args['fields'] ) ) { - $comment_array = get_object_vars( $comment ); - $assoc_args['fields'] = array_keys( $comment_array ); - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $comment ); - } - - /** - * Get a list of comments. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : One or more args to pass to WP_Comment_Query. - * - * [--field=<field>] - * : Prints the value of a single field for each comment. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - ids - * - csv - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each comment: - * - * * comment_ID - * * comment_post_ID - * * comment_date - * * comment_approved - * * comment_author - * * comment_author_email - * - * These fields are optionally available: - * - * * comment_author_url - * * comment_author_IP - * * comment_date_gmt - * * comment_content - * * comment_karma - * * comment_agent - * * comment_type - * * comment_parent - * * user_id - * * url - * - * ## EXAMPLES - * - * # List comment IDs. - * $ wp comment list --field=ID - * 22 - * 23 - * 24 - * - * # List comments of a post. - * $ wp comment list --post_id=1 --fields=ID,comment_date,comment_author - * +------------+---------------------+----------------+ - * | comment_ID | comment_date | comment_author | - * +------------+---------------------+----------------+ - * | 1 | 2015-06-20 09:00:10 | Mr WordPress | - * +------------+---------------------+----------------+ - * - * # List approved comments. - * $ wp comment list --number=3 --status=approve --fields=ID,comment_date,comment_author - * +------------+---------------------+----------------+ - * | comment_ID | comment_date | comment_author | - * +------------+---------------------+----------------+ - * | 1 | 2015-06-20 09:00:10 | Mr WordPress | - * | 30 | 2013-03-14 12:35:07 | John Doe | - * | 29 | 2013-03-14 11:56:08 | Jane Doe | - * +------------+---------------------+----------------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - if ( 'ids' == $formatter->format ) { - $assoc_args['fields'] = 'comment_ID'; - } - - $assoc_args = self::process_csv_arguments_to_arrays( $assoc_args ); - - if ( ! empty( $assoc_args['comment__in'] ) - && ! empty( $assoc_args['orderby'] ) - && 'comment__in' === $assoc_args['orderby'] - && Utils\wp_version_compare( '4.4', '<' ) ) { - $comments = array(); - foreach( $assoc_args['comment__in'] as $comment_id ) { - $comment = get_comment( $comment_id ); - if ( $comment ) { - $comments[] = $comment; - } else { - WP_CLI::warning( sprintf( "Invalid comment %s.", $comment_id ) ); - } - } - } else { - $query = new WP_Comment_Query(); - $comments = $query->query( $assoc_args ); - } - - if ( 'ids' == $formatter->format ) { - $comments = wp_list_pluck( $comments, 'comment_ID' ); - } else { - $comments = array_map( function( $comment ){ - $comment->url = get_comment_link( $comment->comment_ID ); - return $comment; - }, $comments ); - } - - $formatter->display_items( $comments ); - } - - /** - * Delete a comment. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of comments to delete. - * - * [--force] - * : Skip the trash bin. - * - * ## EXAMPLES - * - * # Delete comment. - * $ wp comment delete 1337 --force - * Success: Deleted comment 1337. - * - * # Delete multiple comments. - * $ wp comment delete 1337 2341 --force - * Success: Deleted comment 1337. - * Success: Deleted comment 2341. - */ - public function delete( $args, $assoc_args ) { - parent::_delete( $args, $assoc_args, function ( $comment_id, $assoc_args ) { - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - - $status = wp_get_comment_status( $comment_id ); - $r = wp_delete_comment( $comment_id, $force ); - - if ( $r ) { - if ( $force || 'trash' === $status ) { - return array( 'success', "Deleted comment $comment_id." ); - } else { - return array( 'success', "Trashed comment $comment_id." ); - } - } else { - return array( 'error', "Failed deleting comment $comment_id." ); - } - } ); - } - - private function call( $args, $status, $success, $failure ) { - $comment_id = absint( $args ); - - $func = sprintf( 'wp_%s_comment', $status ); - - if ( $func( $comment_id ) ) { - WP_CLI::success( "$success comment $comment_id." ); - } else { - WP_CLI::error( "$failure comment $comment_id." ); - } - } - - private function set_status( $args, $status, $success ) { - $comment = $this->fetcher->get_check( $args ); - - $r = wp_set_comment_status( $comment->comment_ID, $status, true ); - - if ( is_wp_error( $r ) ) { - WP_CLI::error( $r ); - } else { - WP_CLI::success( "$success comment $comment->comment_ID." ); - } - } - - /** - * Trash a comment. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to trash. - * - * ## EXAMPLES - * - * # Trash comment. - * $ wp comment trash 1337 - * Success: Trashed comment 1337. - */ - public function trash( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->call( $id, __FUNCTION__, 'Trashed', 'Failed trashing' ); - } - } - - /** - * Untrash a comment. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to untrash. - * - * ## EXAMPLES - * - * # Untrash comment. - * $ wp comment untrash 1337 - * Success: Untrashed comment 1337. - */ - public function untrash( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->call( $id, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); - } - } - - /** - * Mark a comment as spam. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to mark as spam. - * - * ## EXAMPLES - * - * # Spam comment. - * $ wp comment spam 1337 - * Success: Marked as spam comment 1337. - */ - public function spam( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->call( $id, __FUNCTION__, 'Marked as spam', 'Failed marking as spam' ); - } - } - - /** - * Unmark a comment as spam. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to unmark as spam. - * - * ## EXAMPLES - * - * # Unspam comment. - * $ wp comment unspam 1337 - * Success: Unspammed comment 1337. - */ - public function unspam( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->call( $id, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); - } - } - - /** - * Approve a comment. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to approve. - * - * ## EXAMPLES - * - * # Approve comment. - * $ wp comment approve 1337 - * Success: Approved comment 1337. - */ - public function approve( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->set_status( $id, 'approve', "Approved" ); - } - } - - /** - * Unapprove a comment. - * - * ## OPTIONS - * - * <id>... - * : The IDs of the comments to unapprove. - * - * ## EXAMPLES - * - * # Unapprove comment. - * $ wp comment unapprove 1337 - * Success: Unapproved comment 1337. - */ - public function unapprove( $args, $assoc_args ) { - foreach( $args as $id ) { - $this->set_status( $id, 'hold', "Unapproved" ); - } - } - - /** - * Count comments, on whole blog or on a given post. - * - * ## OPTIONS - * - * [<post-id>] - * : The ID of the post to count comments in. - * - * ## EXAMPLES - * - * # Count comments on whole blog. - * $ wp comment count - * approved: 33 - * spam: 3 - * trash: 1 - * post-trashed: 0 - * all: 34 - * moderated: 1 - * total_comments: 37 - * - * # Count comments in a post. - * $ wp comment count 42 - * approved: 19 - * spam: 0 - * trash: 0 - * post-trashed: 0 - * all: 19 - * moderated: 0 - * total_comments: 19 - */ - public function count( $args, $assoc_args ) { - $post_id = \WP_CLI\Utils\get_flag_value( $args, 0, 0 ); - - $count = wp_count_comments( $post_id ); - - // Move total_comments to the end of the object - $total = $count->total_comments; - unset( $count->total_comments ); - $count->total_comments = $total; - - foreach ( $count as $status => $count ) { - WP_CLI::line( str_pad( "$status:", 17 ) . $count ); - } - } - - /** - * Recalculate the comment_count value for one or more posts. - * - * ## OPTIONS - * - * <id>... - * : IDs for one or more posts to update. - * - * ## EXAMPLES - * - * # Recount comment for the post. - * $ wp comment recount 123 - * Updated post 123 comment count to 67. - */ - public function recount( $args ) { - foreach( $args as $id ) { - wp_update_comment_count( $id ); - $post = get_post( $id ); - if ( $post ) { - WP_CLI::log( sprintf( "Updated post %d comment count to %d.", $post->ID, $post->comment_count ) ); - } else { - WP_CLI::warning( sprintf( "Post %d doesn't exist.", $post->ID ) ); - } - } - } - - /** - * Get status of a comment. - * - * ## OPTIONS - * - * <id> - * : The ID of the comment to check. - * - * ## EXAMPLES - * - * # Get status of comment. - * $ wp comment status 1337 - * approved - */ - public function status( $args, $assoc_args ) { - list( $comment_id ) = $args; - - $status = wp_get_comment_status( $comment_id ); - - if ( false === $status ) { - WP_CLI::error( "Could not check status of comment $comment_id." ); - } else { - WP_CLI::line( $status ); - } - } - - /** - * Verify whether a comment exists. - * - * Displays a success message if the comment does exist. - * - * ## OPTIONS - * - * <id> - * : The ID of the comment to check. - * - * ## EXAMPLES - * - * # Check whether comment exists. - * $ wp comment exists 1337 - * Success: Comment with ID 1337 exists. - */ - public function exists( $args ) { - if ( $this->fetcher->get( $args[0] ) ) { - WP_CLI::success( "Comment with ID $args[0] exists." ); - } - } -} - -WP_CLI::add_command( 'comment', 'Comment_Command' ); diff --git a/php/commands/core-language.php b/php/commands/core-language.php deleted file mode 100644 index bc180132a..000000000 --- a/php/commands/core-language.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -/** - * Manage core language. - * - * ## EXAMPLES - * - * # Install language - * $ wp core language install nl_NL - * Success: Language installed. - * - * # Activate language - * $ wp core language activate nl_NL - * Success: Language activated. - * - * # Uninstall language - * $ wp core language uninstall nl_NL - * Success: Language uninstalled. - * - * # List installed languages - * $ wp core language list --status=installed - * +----------+--------------+-------------+-----------+-----------+---------------------+ - * | language | english_name | native_name | status | update | updated | - * +----------+--------------+-------------+-----------+-----------+---------------------+ - * | nl_NL | Dutch | Nederlands | installed | available | 2016-05-13 08:12:50 | - * +----------+--------------+-------------+-----------+-----------+---------------------+ - */ -class Core_Language_Command extends WP_CLI\CommandWithTranslation { - - protected $obj_type = 'core'; - -} - -WP_CLI::add_command( 'core language', 'Core_Language_Command', array( - 'before_invoke' => function() { - if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { - WP_CLI::error( "Requires WordPress 4.0 or greater." ); - } - }) -); diff --git a/php/commands/core.php b/php/commands/core.php deleted file mode 100644 index ecb593f00..000000000 --- a/php/commands/core.php +++ /dev/null @@ -1,1532 +0,0 @@ -<?php - -use \Composer\Semver\Comparator; -use \WP_CLI\Extractor; -use \WP_CLI\Utils; - -/** - * Download, install, update and manage a WordPress install. - * - * ## EXAMPLES - * - * # Download WordPress core - * $ wp core download --locale=nl_NL - * Downloading WordPress 4.5.2 (nl_NL)... - * md5 hash verified: c5366d05b521831dd0b29dfc386e56a5 - * Success: WordPress downloaded. - * - * # Install WordPress - * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_password=strongpassword --admin_email=info@example.com - * Success: WordPress installed successfully. - * - * # Display the WordPress version - * $ wp core version - * 4.5.2 - * - * @package wp-cli - */ -class Core_Command extends WP_CLI_Command { - - /** - * Check for WordPress updates via Version Check API. - * - * Lists the most recent versions when there are updates available, - * or success message when up to date. - * - * ## OPTIONS - * - * [--minor] - * : Compare only the first two parts of the version number. - * - * [--major] - * : Compare only the first part of the version number. - * - * [--field=<field>] - * : Prints the value of a single field for each update. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. Defaults to version,update_type,package_url. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - count - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp core check-update - * +---------+-------------+-------------------------------------------------------------+ - * | version | update_type | package_url | - * +---------+-------------+-------------------------------------------------------------+ - * | 4.5.2 | major | https://downloads.wordpress.org/release/wordpress-4.5.2.zip | - * +---------+-------------+-------------------------------------------------------------+ - * - * @subcommand check-update - */ - function check_update( $_, $assoc_args ) { - - $updates = $this->get_updates( $assoc_args ); - if ( $updates ) { - $updates = array_reverse( $updates ); - $formatter = new \WP_CLI\Formatter( - $assoc_args, - array( 'version', 'update_type', 'package_url' ) - ); - $formatter->display_items( $updates ); - } else if ( empty( $assoc_args['format'] ) || 'table' == $assoc_args['format'] ) { - WP_CLI::success( "WordPress is at the latest version." ); - } - } - - /** - * Download core WordPress files. - * - * Downloads and extracts WordPress core files to the specified path. Uses - * an archive file stored in cache if WordPress has been previously - * downloaded. - * - * ## OPTIONS - * - * [--path=<path>] - * : Specify the path in which to install WordPress. - * - * [--locale=<locale>] - * : Select which language you want to download. - * - * [--version=<version>] - * : Select which version you want to download. Accepts a version number, 'latest' or 'nightly' - * - * [--force] - * : Overwrites existing files, if present. - * - * ## EXAMPLES - * - * $ wp core download --locale=nl_NL - * Downloading WordPress 4.5.2 (nl_NL)... - * md5 hash verified: c5366d05b521831dd0b29dfc386e56a5 - * Success: WordPress downloaded. - * - * @when before_wp_load - */ - public function download( $args, $assoc_args ) { - - $download_dir = ! empty( $assoc_args['path'] ) ? $assoc_args['path'] : ABSPATH; - $wordpress_present = is_readable( $download_dir . 'wp-load.php' ); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && $wordpress_present ) - WP_CLI::error( 'WordPress files seem to already be present here.' ); - - if ( ! is_dir( $download_dir ) ) { - if ( ! is_writable( dirname( $download_dir ) ) ) { - WP_CLI::error( sprintf( "Insufficient permission to create directory '%s'.", $download_dir ) ); - } - - WP_CLI::log( sprintf( "Creating directory '%s'.", $download_dir ) ); - $mkdir = \WP_CLI\Utils\is_windows() ? 'mkdir %s' : 'mkdir -p %s'; - WP_CLI::launch( Utils\esc_cmd( $mkdir, $download_dir ) ); - } - - if ( ! is_writable( $download_dir ) ) { - WP_CLI::error( sprintf( "'%s' is not writable by current user.", $download_dir ) ); - } - - $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', 'en_US' ); - - if ( isset( $assoc_args['version'] ) && 'latest' !== $assoc_args['version'] ) { - $version = $assoc_args['version']; - $version = ( in_array( strtolower( $version ), array( 'trunk', 'nightly' ) ) ? 'nightly' : $version ); - //nightly builds are only available in .zip format - $ext = ( 'nightly' === $version ? 'zip' : 'tar.gz' ); - $download_url = $this->get_download_url( $version, $locale, $ext ); - } else { - $offer = $this->get_download_offer( $locale ); - if ( !$offer ) { - WP_CLI::error( "The requested locale ($locale) was not found." ); - } - $version = $offer['current']; - $download_url = str_replace( '.zip', '.tar.gz', $offer['download'] ); - } - - if ( 'nightly' === $version && 'en_US' !== $locale ) { - WP_CLI::error( 'Nightly builds are only available for the en_US locale.' ); - } - - $from_version = ''; - if ( file_exists( $download_dir . 'wp-includes/version.php' ) ) { - global $wp_version; - require_once( $download_dir . 'wp-includes/version.php' ); - $from_version = $wp_version; - } - - WP_CLI::log( sprintf( 'Downloading WordPress %s (%s)...', $version, $locale ) ); - - $path_parts = pathinfo( $download_url ); - $extension = 'tar.gz'; - if ( 'zip' === $path_parts['extension'] ) { - $extension = 'zip'; - if ( ! class_exists( 'ZipArchive' ) ) { - WP_CLI::error( 'Extracting a zip file requires ZipArchive.' ); - } - } - - $cache = WP_CLI::get_cache(); - $cache_key = "core/wordpress-{$version}-{$locale}.{$extension}"; - $cache_file = $cache->has($cache_key); - - $bad_cache = false; - if ( $cache_file ) { - WP_CLI::log( "Using cached file '$cache_file'..." ); - try{ - Extractor::extract( $cache_file, $download_dir ); - } catch ( Exception $e ) { - WP_CLI::warning( "Extraction failed, downloading a new copy..." ); - $bad_cache = true; - } - } - - if ( ! $cache_file || $bad_cache ) { - // We need to use a temporary file because piping from cURL to tar is flaky - // on MinGW (and probably in other environments too). - $temp = \WP_CLI\Utils\get_temp_dir() . uniqid('wp_') . ".{$extension}"; - - $headers = array('Accept' => 'application/json'); - $options = array( - 'timeout' => 600, // 10 minutes ought to be enough for everybody - 'filename' => $temp - ); - - $response = Utils\http_request( 'GET', $download_url, null, $headers, $options ); - if ( 404 == $response->status_code ) { - WP_CLI::error( "Release not found. Double-check locale or version." ); - } else if ( 20 != substr( $response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access download URL (HTTP code {$response->status_code})." ); - } - - if ( 'nightly' !== $version ) { - $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); - if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})." ); - } - - $md5_file = md5_file( $temp ); - - if ( $md5_file === $md5_response->body ) { - WP_CLI::log( 'md5 hash verified: ' . $md5_file ); - } else { - WP_CLI::error( "md5 hash for download ({$md5_file}) is different than the release hash ({$md5_response->body})." ); - } - } else { - WP_CLI::warning( 'md5 hash checks are not available for nightly downloads.' ); - } - - try { - Extractor::extract( $temp, $download_dir ); - } catch ( Exception $e ) { - WP_CLI::error( "Couldn't extract WordPress archive. " . $e->getMessage() ); - } - - if ( 'nightly' !== $version ) { - $cache->import( $cache_key, $temp ); - } - unlink( $temp ); - } - - if ( $wordpress_present ) { - $this->cleanup_extra_files( $from_version, $version, $locale ); - } - - WP_CLI::success( 'WordPress downloaded.' ); - } - - private static function _read( $url ) { - $headers = array('Accept' => 'application/json'); - $response = Utils\http_request( 'GET', $url, null, $headers, array( 'timeout' => 30 ) ); - if ( 200 === $response->status_code ) { - return $response->body; - } else { - WP_CLI::error( "Couldn't fetch response from {$url} (HTTP code {$response->status_code})." ); - } - } - - private function get_download_offer( $locale ) { - $out = unserialize( self::_read( - 'https://api.wordpress.org/core/version-check/1.6/?locale=' . $locale ) ); - - $offer = $out['offers'][0]; - - if ( $offer['locale'] != $locale ) { - return false; - } - - return $offer; - } - - private static function get_initial_locale() { - include ABSPATH . '/wp-includes/version.php'; - - // @codingStandardsIgnoreStart - if ( isset( $wp_local_package ) ) - return $wp_local_package; - // @codingStandardsIgnoreEnd - - return ''; - } - - /** - * Generate a wp-config.php file. - * - * Creates a new wp-config.php with database constants, and verifies that - * the database constants are correct. - * - * ## OPTIONS - * - * --dbname=<dbname> - * : Set the database name. - * - * --dbuser=<dbuser> - * : Set the database user. - * - * [--dbpass=<dbpass>] - * : Set the database user password. - * - * [--dbhost=<dbhost>] - * : Set the database host. - * --- - * default: localhost - * --- - * - * [--dbprefix=<dbprefix>] - * : Set the database table prefix. - * --- - * default: wp_ - * --- - * - * [--dbcharset=<dbcharset>] - * : Set the database charset. - * --- - * default: utf8 - * --- - * - * [--dbcollate=<dbcollate>] - * : Set the database collation. - * --- - * default: - * --- - * - * [--locale=<locale>] - * : Set the WPLANG constant. Defaults to $wp_local_package variable. - * - * [--extra-php] - * : If set, the command copies additional PHP code into wp-config.php from STDIN. - * - * [--skip-salts] - * : If set, keys and salts won't be generated, but should instead be passed via `--extra-php`. - * - * [--skip-check] - * : If set, the database connection is not checked. - * - * [--force] - * : Overwrites existing files, if present. - * - * ## EXAMPLES - * - * # Standard wp-config.php file - * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --locale=ro_RO - * Success: Generated 'wp-config.php' file. - * - * # Enable WP_DEBUG and WP_DEBUG_LOG - * $ wp core config --dbname=testing --dbuser=wp --dbpass=securepswd --extra-php <<PHP - * $ define( 'WP_DEBUG', true ); - * $ define( 'WP_DEBUG_LOG', true ); - * $ PHP - * Success: Generated 'wp-config.php' file. - * - * # Avoid disclosing password to bash history by reading from password.txt - * $ wp core config --dbname=testing --dbuser=wp --prompt=dbpass < password.txt - * Success: Generated 'wp-config.php' file. - */ - public function config( $_, $assoc_args ) { - global $wp_version; - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && Utils\locate_wp_config() ) { - WP_CLI::error( "The 'wp-config.php' file already exists." ); - } - - $versions_path = ABSPATH . 'wp-includes/version.php'; - include $versions_path; - - $defaults = array( - 'dbhost' => 'localhost', - 'dbpass' => '', - 'dbprefix' => 'wp_', - 'dbcharset' => 'utf8', - 'dbcollate' => '', - 'locale' => self::get_initial_locale() - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - if ( preg_match( '|[^a-z0-9_]|i', $assoc_args['dbprefix'] ) ) - WP_CLI::error( '--dbprefix can only contain numbers, letters, and underscores.' ); - - // Check DB connection - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-check' ) ) { - Utils\run_mysql_command( 'mysql --no-defaults', array( - 'execute' => ';', - 'host' => $assoc_args['dbhost'], - 'user' => $assoc_args['dbuser'], - 'pass' => $assoc_args['dbpass'], - ) ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra-php' ) === true ) { - $assoc_args['extra-php'] = file_get_contents( 'php://stdin' ); - } - - // TODO: adapt more resilient code from wp-admin/setup-config.php - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-salts' ) ) { - $assoc_args['keys-and-salts'] = self::_read( - 'https://api.wordpress.org/secret-key/1.1/salt/' ); - } - - if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { - $assoc_args['add-wplang'] = true; - } else { - $assoc_args['add-wplang'] = false; - } - - $out = Utils\mustache_render( 'wp-config.mustache', $assoc_args ); - - $bytes_written = file_put_contents( ABSPATH . 'wp-config.php', $out ); - if ( ! $bytes_written ) { - WP_CLI::error( "Could not create new 'wp-config.php' file." ); - } else { - WP_CLI::success( "Generated 'wp-config.php' file." ); - } - } - - /** - * Check if WordPress is installed. - * - * Determines whether WordPress is installed by checking if the standard - * database tables are installed. Doesn't produce output; uses exit codes - * to communicate whether WordPress is installed. - * - * [--network] - * : Check if this is a multisite install. - * - * ## EXAMPLES - * - * # Check whether WordPress is installed; exit status 0 if installed, otherwise 1 - * $ wp core is-installed - * $ echo $? - * 1 - * - * # Bash script for checking whether WordPress is installed or not - * if ! $(wp core is-installed); then - * wp core install - * fi - * - * @subcommand is-installed - */ - public function is_installed( $_, $assoc_args ) { - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { - if ( is_blog_installed() && is_multisite() ) { - WP_CLI::halt( 0 ); - } else { - WP_CLI::halt( 1 ); - } - } else if ( is_blog_installed() ) { - WP_CLI::halt( 0 ); - } else { - WP_CLI::halt( 1 ); - } - } - - /** - * Runs the standard WordPress installation process. - * - * Creates the WordPress tables in the database using the URL, title, and - * default admin user details provided. Performs the famous 5 minute install - * in seconds or less. - * - * Note: if you've installed WordPress in a subdirectory, then you'll need - * to `wp option update siteurl` after `wp core install`. For instance, if - * WordPress is installed in the `/wp` directory and your domain is wp.dev, - * then you'll need to run `wp option update siteurl http://wp.dev/wp` for - * your WordPress install to function properly. - * - * Note: When using custom user tables (e.g. `CUSTOM_USER_TABLE`), the admin - * email and password are ignored if the user_login already exists. If the - * user_login doesn't exist, a new user will be created. - * - * ## OPTIONS - * - * --url=<url> - * : The address of the new site. - * - * --title=<site-title> - * : The title of the new site. - * - * --admin_user=<username> - * : The name of the admin user. - * - * [--admin_password=<password>] - * : The password for the admin user. Defaults to randomly generated string. - * - * --admin_email=<email> - * : The email address for the admin user. - * - * [--skip-email] - * : Don't send an email notification to the new admin user. - * - * ## EXAMPLES - * - * # Install WordPress in 5 seconds - * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_password=strongpassword --admin_email=info@example.com - * Success: WordPress installed successfully. - * - * # Install WordPress without disclosing admin_password to bash history - * $ wp core install --url=example.com --title=Example --admin_user=supervisor --admin_email=info@example.com --prompt=admin_password < admin_password.txt - */ - public function install( $args, $assoc_args ) { - if ( $this->_install( $assoc_args ) ) { - WP_CLI::success( 'WordPress installed successfully.' ); - } else { - WP_CLI::log( 'WordPress is already installed.' ); - } - } - - /** - * Transform a single-site install into a WordPress multisite install. - * - * Creates the multisite database tables, and adds the multisite constants - * to wp-config.php. - * - * For those using WordPress with Apache, remember to update the `.htaccess` - * file with the appropriate multisite rewrite rules. - * - * ## OPTIONS - * - * [--title=<network-title>] - * : The title of the new network. - * - * [--base=<url-path>] - * : Base path after the domain name that each site url will start with. - * --- - * default: / - * --- - * - * [--subdomains] - * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. - * - * ## EXAMPLES - * - * $ wp core multisite-convert - * Set up multisite database tables. - * Added multisite constants to wp-config.php. - * Success: Network installed. Don't forget to set up rewrite rules. - * - * @subcommand multisite-convert - * @alias install-network - */ - public function multisite_convert( $args, $assoc_args ) { - if ( is_multisite() ) - WP_CLI::error( 'This already is a multisite install.' ); - - $assoc_args = self::_set_multisite_defaults( $assoc_args ); - if ( !isset( $assoc_args['title'] ) ) { - $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), get_option( 'blogname' ) ); - } - - if ( $this->_multisite_convert( $assoc_args ) ) { - WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); - } - } - - /** - * Install WordPress multisite from scratch. - * - * Creates the WordPress tables in the database using the URL, title, and - * default admin user details provided. Then, creates the multisite tables - * in the database and adds multisite constants to the wp-config.php. - * - * ## OPTIONS - * - * [--url=<url>] - * : The address of the new site. - * - * [--base=<url-path>] - * : Base path after the domain name that each site url in the network will start with. - * --- - * default: / - * --- - * - * [--subdomains] - * : If passed, the network will use subdomains, instead of subdirectories. Doesn't work with 'localhost'. - * - * --title=<site-title> - * : The title of the new site. - * - * --admin_user=<username> - * : The name of the admin user. - * --- - * default: admin - * --- - * - * [--admin_password=<password>] - * : The password for the admin user. Defaults to randomly generated string. - * - * --admin_email=<email> - * : The email address for the admin user. - * - * [--skip-email] - * : Don't send an email notification to the new admin user. - * - * ## EXAMPLES - * - * $ wp core multisite-install --title="Welcome to the WordPress" \ - * > --admin_user="admin" --admin_password="password" \ - * > --admin_email="user@example.com" - * Single site database tables already present. - * Set up multisite database tables. - * Added multisite constants to wp-config.php. - * Success: Network installed. Don't forget to set up rewrite rules. - * - * @subcommand multisite-install - */ - public function multisite_install( $args, $assoc_args ) { - if ( $this->_install( $assoc_args ) ) { - WP_CLI::log( 'Created single site database tables.' ); - } else { - WP_CLI::log( 'Single site database tables already present.' ); - } - - $assoc_args = self::_set_multisite_defaults( $assoc_args ); - $assoc_args['title'] = sprintf( _x('%s Sites', 'Default network name' ), $assoc_args['title'] ); - - // Overwrite runtime args, to avoid mismatches. - $consts_to_args = array( - 'SUBDOMAIN_INSTALL' => 'subdomains', - 'PATH_CURRENT_SITE' => 'base', - 'SITE_ID_CURRENT_SITE' => 'site_id', - 'BLOG_ID_CURRENT_SITE' => 'blog_id', - ); - - foreach ( $consts_to_args as $const => $arg ) { - if ( defined( $const ) ) { - $assoc_args[ $arg ] = constant( $const ); - } - } - - if ( !$this->_multisite_convert( $assoc_args ) ) { - return; - } - - // Do the steps that were skipped by populate_network(), - // which checks is_multisite(). - if ( is_multisite() ) { - $site_user = get_user_by( 'email', $assoc_args['admin_email'] ); - self::add_site_admins( $site_user ); - $domain = self::get_clean_basedomain(); - self::create_initial_blog( - $assoc_args['site_id'], - $assoc_args['blog_id'], - $domain, - $assoc_args['base'], - $assoc_args['subdomains'], - $site_user - ); - } - - WP_CLI::success( "Network installed. Don't forget to set up rewrite rules." ); - } - - private static function _set_multisite_defaults( $assoc_args ) { - $defaults = array( - 'subdomains' => false, - 'base' => '/', - 'site_id' => 1, - 'blog_id' => 1, - ); - - return array_merge( $defaults, $assoc_args ); - } - - private function _install( $assoc_args ) { - if ( is_blog_installed() ) { - return false; - } - - if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-email' ) - && ! function_exists( 'wp_new_blog_notification' ) ) { - function wp_new_blog_notification() { - // Silence is golden - } - } - - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - - extract( wp_parse_args( $assoc_args, array( - 'title' => '', - 'admin_user' => '', - 'admin_email' => '', - 'admin_password' => '' - ) ), EXTR_SKIP ); - - // Support prompting for the `--url=<url>`, - // which is normally a runtime argument - if ( isset( $assoc_args['url'] ) ) { - WP_CLI::set_url( $assoc_args['url'] ); - } - - $public = true; - - // @codingStandardsIgnoreStart - if ( !is_email( $admin_email ) ) { - WP_CLI::error( "The '{$admin_email}' email address is invalid." ); - } - - $result = wp_install( $title, $admin_user, $admin_email, $public, '', $admin_password ); - - if ( is_wp_error( $result ) ) { - WP_CLI::error( 'Installation failed (' . WP_CLI::error_to_string($result) . ').' ); - } - // @codingStandardsIgnoreEnd - - if ( ! empty( $GLOBALS['wpdb']->last_error ) ) { - WP_CLI::error( 'Installation produced database errors, and may have partially or completely failed.' ); - } - - if ( empty( $admin_password ) ) { - WP_CLI::log( "Admin password: {$result['password']}" ); - } - - // Confirm the uploads directory exists - $upload_dir = wp_upload_dir(); - if ( ! empty( $upload_dir['error'] ) ) { - WP_CLI::warning( $upload_dir['error'] ); - } - - return true; - } - - private function _multisite_convert( $assoc_args ) { - global $wpdb; - - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - - $domain = self::get_clean_basedomain(); - if ( 'localhost' === $domain && ! empty( $assoc_args['subdomains'] ) ) { - WP_CLI::error( "Multisite with subdomains cannot be configured when domain is 'localhost'." ); - } - - // need to register the multisite tables manually for some reason - foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) - $wpdb->$table = $prefixed_table; - - install_network(); - - $result = populate_network( - $assoc_args['site_id'], - $domain, - get_option( 'admin_email' ), - $assoc_args['title'], - $assoc_args['base'], - $assoc_args['subdomains'] - ); - - if ( true === $result ) { - WP_CLI::log( 'Set up multisite database tables.' ); - } else if ( is_wp_error( $result ) ) { - switch ( $result->get_error_code() ) { - - case 'siteid_exists': - WP_CLI::log( $result->get_error_message() ); - return false; - - case 'no_wildcard_dns': - WP_CLI::warning( __( 'Wildcard DNS may not be configured correctly.' ) ); - break; - - default: - WP_CLI::error( $result ); - } - } - - // delete_site_option() cleans the alloptions cache to prevent dupe option - delete_site_option( 'upload_space_check_disabled' ); - update_site_option( 'upload_space_check_disabled', 1 ); - - if ( !is_multisite() ) { - $subdomain_export = Utils\get_flag_value( $assoc_args, 'subdomains' ) ? 'true' : 'false'; - $ms_config = <<<EOT -define( 'WP_ALLOW_MULTISITE', true ); -define( 'MULTISITE', true ); -define( 'SUBDOMAIN_INSTALL', {$subdomain_export} ); -\$base = '{$assoc_args['base']}'; -define( 'DOMAIN_CURRENT_SITE', '{$domain}' ); -define( 'PATH_CURRENT_SITE', '{$assoc_args['base']}' ); -define( 'SITE_ID_CURRENT_SITE', 1 ); -define( 'BLOG_ID_CURRENT_SITE', 1 ); -EOT; - - $wp_config_path = Utils\locate_wp_config(); - if ( is_writable( $wp_config_path ) && self::modify_wp_config( $ms_config ) ) { - WP_CLI::log( "Added multisite constants to 'wp-config.php'." ); - } else { - WP_CLI::warning( "Multisite constants could not be written to 'wp-config.php'. You may need to add them manually:" . PHP_EOL . $ms_config ); - } - } - - return true; - } - - // copied from populate_network() - private static function create_initial_blog( $network_id, $blog_id, $domain, $path, - $subdomain_install, $site_user ) { - global $wpdb, $current_site, $wp_rewrite; - - $current_site = new stdClass; - $current_site->domain = $domain; - $current_site->path = $path; - $current_site->site_name = ucfirst( $domain ); - $wpdb->insert( $wpdb->blogs, array( - 'site_id' => $network_id, - 'domain' => $domain, - 'path' => $path, - 'registered' => current_time( 'mysql' ) - ) ); - $current_site->blog_id = $blog_id = $wpdb->insert_id; - update_user_meta( $site_user->ID, 'source_domain', $domain ); - update_user_meta( $site_user->ID, 'primary_blog', $blog_id ); - - if ( $subdomain_install ) - $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); - else - $wp_rewrite->set_permalink_structure( '/blog/%year%/%monthnum%/%day%/%postname%/' ); - - flush_rewrite_rules(); - } - - // copied from populate_network() - private static function add_site_admins( $site_user ) { - $site_admins = array( $site_user->user_login ); - $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) ); - if ( $users ) { - foreach ( $users as $user ) { - if ( is_super_admin( $user->ID ) && !in_array( $user->user_login, $site_admins ) ) - $site_admins[] = $user->user_login; - } - } - - update_site_option( 'site_admins', $site_admins ); - } - - private static function modify_wp_config( $content ) { - $wp_config_path = Utils\locate_wp_config(); - - $token = "/* That's all, stop editing!"; - $config_contents = file_get_contents( $wp_config_path ); - if ( false === strpos( $config_contents, $token ) ) { - return false; - } - - list( $before, $after ) = explode( $token, $config_contents ); - - $content = PHP_EOL . PHP_EOL . trim( $content ) . PHP_EOL . PHP_EOL; - - file_put_contents( $wp_config_path, $before . $content . $token . $after ); - return true; - } - - private static function get_clean_basedomain() { - $domain = preg_replace( '|https?://|', '', get_option( 'siteurl' ) ); - if ( $slash = strpos( $domain, '/' ) ) - $domain = substr( $domain, 0, $slash ); - return $domain; - } - - /** - * Display the WordPress version. - * - * ## OPTIONS - * - * [--extra] - * : Show extended version information. - * - * ## EXAMPLES - * - * # Display the WordPress version - * $ wp core version - * 4.5.2 - * - * # Display WordPress version along with other information - * $ wp core version --extra - * WordPress version: 4.5.2 - * Database revision: 36686 - * TinyMCE version: 4.310 (4310-20160418) - * Package language: en_US - * - * @when before_wp_load - */ - public function version( $args = array(), $assoc_args = array() ) { - $details = self::get_wp_details(); - - // @codingStandardsIgnoreStart - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'extra' ) ) { - if ( preg_match( '/(\d)(\d+)-/', $details['tinymce_version'], $match ) ) { - $human_readable_tiny_mce = $match[1] . '.' . $match[2]; - } else { - $human_readable_tiny_mce = ''; - } - - echo \WP_CLI\Utils\mustache_render( 'versions.mustache', array( - 'wp-version' => $details['wp_version'], - 'db-version' => $details['wp_db_version'], - 'local-package' => ( empty( $details['wp_local_package'] ) ? - 'en_US' - : $details['wp_local_package'] - ), - 'mce-version' => ( $human_readable_tiny_mce ? - "$human_readable_tiny_mce ({$details['tinymce_version']})" - : $details['tinymce_version'] - ) - ) ); - } else { - WP_CLI::line( $details['wp_version'] ); - } - // @codingStandardsIgnoreEnd - } - - /** - * Verify WordPress files against WordPress.org's checksums. - * - * Downloads md5 checksums for the current version from WordPress.org, and - * compares those checksums against the currently installed files. - * - * For security, avoids loading WordPress when verifying checksums. - * - * ## OPTIONS - * - * [--version=<version>] - * : Verify checksums against a specific version of WordPress. - * - * [--locale=<locale>] - * : Verify checksums against a specific locale of WordPress. - * - * ## EXAMPLES - * - * # Verify checksums - * $ wp core verify-checksums - * Success: WordPress install verifies against checksums. - * - * # Verify checksums for given WordPress version - * $ wp core verify-checksums --version=4.0 - * Success: WordPress install verifies against checksums. - * - * # Verify checksums for given locale - * $ wp core verify-checksums --locale=en_US - * Success: WordPress install verifies against checksums. - * - * # Verify checksums for given locale - * $ wp core verify-checksums --locale=ja - * Warning: File doesn't verify against checksum: wp-includes/version.php - * Warning: File doesn't verify against checksum: readme.html - * Warning: File doesn't verify against checksum: wp-config-sample.php - * Error: WordPress install doesn't verify against checksums. - * - * @when before_wp_load - * - * @subcommand verify-checksums - */ - public function verify_checksums( $args, $assoc_args ) { - global $wp_version, $wp_local_package; - - if ( ! empty( $assoc_args['version'] ) ) { - $wp_version = $assoc_args['version']; - } - - if ( ! empty( $assoc_args['locale'] ) ) { - $wp_local_package = $assoc_args['locale']; - } - - if ( empty( $wp_version ) ) { - $details = self::get_wp_details(); - $wp_version = $details['wp_version']; - - if ( empty( $wp_local_package ) ) { - $wp_local_package = $details['wp_local_package']; - } - } - - $checksums = self::get_core_checksums( $wp_version, - ! empty( $wp_local_package ) ? $wp_local_package : 'en_US' ); - - if ( ! is_array( $checksums ) ) { - WP_CLI::error( "Couldn't get checksums from WordPress.org." ); - } - - $has_errors = false; - foreach ( $checksums as $file => $checksum ) { - // Skip files which get updated - if ( 'wp-content' == substr( $file, 0, 10 ) ) { - continue; - } - - if ( ! file_exists( ABSPATH . $file ) ) { - WP_CLI::warning( "File doesn't exist: {$file}" ); - $has_errors = true; - continue; - } - - $md5_file = md5_file( ABSPATH . $file ); - if ( $md5_file !== $checksum ) { - WP_CLI::warning( "File doesn't verify against checksum: {$file}" ); - $has_errors = true; - } - } - - $core_checksums_files = array_filter( array_keys( $checksums ), array( $this, 'only_core_files_filter' ) ); - $core_files = $this->get_wp_core_files(); - $additional_files = array_diff( $core_files, $core_checksums_files ); - - if ( ! empty( $additional_files ) ) { - foreach ( $additional_files as $additional_file ) { - WP_CLI::warning( "File should not exist: {$additional_file}" ); - } - } - - if ( ! $has_errors ) { - WP_CLI::success( "WordPress install verifies against checksums." ); - } else { - WP_CLI::error( "WordPress install doesn't verify against checksums." ); - } - } - - private function get_wp_core_files() { - $core_files = array(); - try { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( ABSPATH, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ( $files as $file_info ) { - $pathname = substr( $file_info->getPathname(), strlen( ABSPATH ) ); - if ( $file_info->isFile() && ( 0 === strpos( $pathname, 'wp-admin/' ) || 0 === strpos( $pathname, 'wp-includes/' ) ) ) { - $core_files[] = str_replace( ABSPATH, '', $file_info->getPathname() ); - } - } - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - return $core_files; - } - - private function only_core_files_filter( $file ) { - return ( 0 === strpos( $file, 'wp-admin/' ) || 0 === strpos( $file, 'wp-includes/' ) ); - } - - /** - * Get version information from `wp-includes/version.php`. - * - * @return array { - * @type string $wp_version The WordPress version. - * @type int $wp_db_version The WordPress DB revision. - * @type string $tinymce_version The TinyMCE version. - * @type string $wp_local_package The TinyMCE version. - * } - */ - private static function get_wp_details() { - $versions_path = ABSPATH . 'wp-includes/version.php'; - - if ( ! is_readable( $versions_path ) ) { - WP_CLI::error( - "This does not seem to be a WordPress install.\n" . - "Pass --path=`path/to/wordpress` or run `wp core download`." ); - } - - $version_content = file_get_contents( $versions_path, null, null, 6, 2048 ); - - $vars = array( 'wp_version', 'wp_db_version', 'tinymce_version', 'wp_local_package' ); - $result = array(); - - foreach ( $vars as $var_name ) { - $result[ $var_name ] = self::find_var( $var_name, $version_content ); - } - - return $result; - } - - /** - * Search for the value assigned to variable `$var_name` in PHP code `$code`. - * - * This is equivalent to matching the `\$VAR_NAME = ([^;]+)` regular expression and returning - * the first match either as a `string` or as an `integer` (depending if it's surrounded by - * quotes or not). - * - * @param string $var_name Variable name to search for. - * @param string $code PHP code to search in. - * - * @return int|string|null - */ - private static function find_var( $var_name, $code ) { - $start = strpos( $code, '$' . $var_name . ' = ' ); - - if ( ! $start ) { - return null; - } - - $start = $start + strlen( $var_name ) + 3; - $end = strpos( $code, ";", $start ); - - $value = substr( $code, $start, $end - $start ); - - if ( $value[0] = "'" ) { - return trim( $value, "'" ); - } else { - return intval( $value ); - } - } - - /** - * Security copy of the core function with Requests - Gets the checksums for the given version of WordPress. - * - * @param string $version Version string to query. - * @param string $locale Locale to query. - * @return bool|array False on failure. An array of checksums on success. - */ - private static function get_core_checksums( $version, $locale ) { - $url = 'https://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); - - $options = array( - 'timeout' => 30 - ); - - $headers = array( - 'Accept' => 'application/json' - ); - $response = Utils\http_request( 'GET', $url, null, $headers, $options ); - - if ( ! $response->success || 200 != $response->status_code ) - return false; - - $body = trim( $response->body ); - $body = json_decode( $body, true ); - - if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) - return false; - - return $body['checksums']; - } - - /** - * Update WordPress to a newer version. - * - * Defaults to updating WordPress to the latest version. - * - * If you see "Error: Another update is currently in progress.", you may - * need to run `wp option delete core_updater.lock` after verifying another - * update isn't actually running. - * - * ## OPTIONS - * - * [<zip>] - * : Path to zip file to use, instead of downloading from wordpress.org. - * - * [--minor] - * : Only perform updates for minor releases (e.g. update from WP 4.3 to 4.3.3 instead of 4.4.2). - * - * [--version=<version>] - * : Update to a specific version, instead of to the latest version. Alternatively accepts 'nightly'. - * - * [--force] - * : Update even when installed WP version is greater than the requested version. - * - * [--locale=<locale>] - * : Select which language you want to download. - * - * ## EXAMPLES - * - * # Update WordPress - * $ wp core update - * Updating to version 4.5.2 (en_US)... - * Downloading update from https://downloads.wordpress.org/release/wordpress-4.5.2-no-content.zip... - * Unpacking the update... - * Cleaning up files... - * No files found that need cleaned up - * Success: WordPress updated successfully. - * - * # Update WordPress to latest version of 3.8 release - * $ wp core update --version=3.8 ../latest.zip - * Updating to version 3.8 ()... - * Unpacking the update... - * Cleaning up files... - * File removed: wp-admin/js/tags-box.js - * ... - * File removed: wp-admin/js/updates.min. - * 377 files cleaned up - * Success: WordPress updated successfully. - * - * # Update WordPress to 3.1 forcefully - * $ wp core update --version=3.1 --force - * Updating to version 3.1 (en_US)... - * Downloading update from https://wordpress.org/wordpress-3.1.zip... - * Unpacking the update... - * Warning: Failed to fetch checksums. Please cleanup files manually. - * Success: WordPress updated successfully. - * - * @alias upgrade - */ - public function update( $args, $assoc_args ) { - global $wp_version; - - $update = $from_api = null; - $upgrader = 'WP_CLI\\CoreUpgrader'; - - if ( 'trunk' === Utils\get_flag_value( $assoc_args, 'version' ) ) { - $assoc_args['version'] = 'nightly'; - } - - if ( ! empty( $args[0] ) ) { - - // ZIP path or URL is given - $upgrader = 'WP_CLI\\NonDestructiveCoreUpgrader'; - $version = \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ); - - $update = (object) array( - 'response' => 'upgrade', - 'current' => $version, - 'download' => $args[0], - 'packages' => (object) array ( - 'partial' => null, - 'new_bundled' => null, - 'no_content' => null, - 'full' => $args[0], - ), - 'version' => $version, - 'locale' => null - ); - - } else if ( empty( $assoc_args['version'] ) ) { - - // Update to next release - wp_version_check(); - $from_api = get_site_transient( 'update_core' ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'minor' ) ) { - foreach( $from_api->updates as $offer ) { - $sem_ver = Utils\get_named_sem_ver( $offer->version, $wp_version ); - if ( ! $sem_ver || 'patch' !== $sem_ver ) { - continue; - } - $update = $offer; - break; - } - if ( empty( $update ) ) { - WP_CLI::success( 'WordPress is at the latest minor release.' ); - return; - } - } else { - if ( ! empty( $from_api->updates ) ) { - list( $update ) = $from_api->updates; - } - } - - } else if ( \WP_CLI\Utils\wp_version_compare( $assoc_args['version'], '<' ) - || 'nightly' === $assoc_args['version'] - || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { - - // Specific version is given - $version = $assoc_args['version']; - $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); - - $new_package = $this->get_download_url($version, $locale); - - $update = (object) array( - 'response' => 'upgrade', - 'current' => $assoc_args['version'], - 'download' => $new_package, - 'packages' => (object) array ( - 'partial' => null, - 'new_bundled' => null, - 'no_content' => null, - 'full' => $new_package, - ), - 'version' => $version, - 'locale' => $locale - ); - - } - - if ( ! empty( $update ) - && ( $update->version != $wp_version || \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) ) { - - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - - if ( $update->version ) { - WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." ); - } else { - WP_CLI::log( "Starting update..." ); - } - - $from_version = $wp_version; - - $GLOBALS['wp_cli_update_obj'] = $update; - $result = Utils\get_upgrader( $upgrader )->upgrade( $update ); - unset( $GLOBALS['wp_cli_update_obj'] ); - - if ( is_wp_error($result) ) { - $msg = WP_CLI::error_to_string( $result ); - if ( 'up_to_date' != $result->get_error_code() ) { - WP_CLI::error( $msg ); - } else { - WP_CLI::success( $msg ); - } - } else { - - if ( file_exists( ABSPATH . 'wp-includes/version.php' ) ) { - include( ABSPATH . 'wp-includes/version.php' ); - $to_version = $wp_version; - } - - $locale = \WP_CLI\Utils\get_flag_value( $assoc_args, 'locale', get_locale() ); - $this->cleanup_extra_files( $from_version, $to_version, $locale ); - - WP_CLI::success( 'WordPress updated successfully.' ); - } - - } else { - WP_CLI::success( 'WordPress is up to date.' ); - } - } - - /** - * Run the WordPress database update procedure. - * - * [--network] - * : Update databases for all sites on a network - * - * [--dry-run] - * : Compare database versions without performing the update. - * - * ## EXAMPLES - * - * # Update the WordPress database - * $ wp core update-db - * Success: WordPress database upgraded successfully from db version 36686 to 35700. - * - * # Update databases for all sites on a network - * $ wp core update-db --network - * WordPress database upgraded successfully from db version 35700 to 29630 on example.com/ - * Success: WordPress database upgraded on 123/123 sites - * - * @subcommand update-db - */ - function update_db( $_, $assoc_args ) { - global $wpdb, $wp_db_version, $wp_current_db_version; - - $network = Utils\get_flag_value( $assoc_args, 'network' ); - if ( $network && ! is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - $dry_run = Utils\get_flag_value( $assoc_args, 'dry-run' ); - if ( $dry_run ) { - WP_CLI::log( 'Performing a dry run, with no database modification.' ); - } - - if ( $network ) { - $iterator_args = array( - 'table' => $wpdb->blogs, - 'where' => array( 'spam' => 0, 'deleted' => 0, 'archived' => 0 ), - ); - $it = new \WP_CLI\Iterators\Table( $iterator_args ); - $success = $total = 0; - $site_ids = array(); - foreach( $it as $blog ) { - $total++; - $site_ids[] = $blog->site_id; - $url = $blog->domain . $blog->path; - $cmd = "--url={$url} core update-db"; - if ( $dry_run ) { - $cmd .= ' --dry-run'; - } - $process = WP_CLI::runcommand( $cmd, array( 'return' => 'all' ) ); - if ( 0 == $process->return_code ) { - // See if we can parse the stdout - if ( preg_match( '#Success: (.+)#', $process->stdout, $matches ) ) { - $message = rtrim( $matches[1], '.' ); - $message = "{$message} on {$url}"; - } else { - $message = "Database upgraded successfully on {$url}"; - } - WP_CLI::log( $message ); - $success++; - } else { - WP_CLI::warning( "Database failed to upgrade on {$url}" ); - } - } - if ( ! $dry_run && $total && $success == $total ) { - foreach( array_unique( $site_ids ) as $site_id ) { - update_metadata( 'site', $site_id, 'wpmu_upgrade_site', $wp_db_version ); - } - } - WP_CLI::success( sprintf( 'WordPress database upgraded on %d/%d sites.', $success, $total ) ); - } else { - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); - $wp_current_db_version = __get_option( 'db_version' ); - if ( $wp_db_version != $wp_current_db_version ) { - if ( $dry_run ) { - WP_CLI::success( "WordPress database will be upgraded from db version {$wp_current_db_version} to {$wp_db_version}." ); - } else { - wp_upgrade(); - WP_CLI::success( "WordPress database upgraded successfully from db version {$wp_current_db_version} to {$wp_db_version}." ); - } - } else { - WP_CLI::success( "WordPress database already at latest db version {$wp_db_version}." ); - } - } - } - - /** - * Gets download url based on version, locale and desired file type. - * - * @param $version - * @param string $locale - * @param string $file_type - * @return string - */ - private function get_download_url( $version, $locale = 'en_US', $file_type = 'zip' ) { - - if ( 'nightly' === $version ) { - if ( 'zip' === $file_type ) { - return 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; - } else { - WP_CLI::error( 'Nightly builds are only available in .zip format.' ); - } - } - - if ( 'en_US' === $locale ) { - $url = 'https://wordpress.org/wordpress-' . $version . '.' . $file_type; - - return $url; - } else { - $url = sprintf( - 'https://%s.wordpress.org/wordpress-%s-%s.' . $file_type, - substr($locale, 0, 2), - $version, - $locale - ); - - return $url; - } - } - - /** - * Returns update information - */ - private function get_updates( $assoc_args ) { - wp_version_check(); - $from_api = get_site_transient( 'update_core' ); - if ( ! $from_api ) { - return array(); - } - - $compare_version = str_replace( '-src', '', $GLOBALS['wp_version'] ); - - $updates = array( - 'major' => false, - 'minor' => false, - ); - foreach ( $from_api->updates as $offer ) { - - $update_type = Utils\get_named_sem_ver( $offer->version, $compare_version ); - if ( ! $update_type ) { - continue; - } - - // WordPress follow its own versioning which is roughly equivalent to semver - if ( 'minor' === $update_type ) { - $update_type = 'major'; - } else if ( 'patch' === $update_type ) { - $update_type = 'minor'; - } - - if ( ! empty( $updates[ $update_type ] ) && ! Comparator::greaterThan( $offer->version, $updates[ $update_type ]['version'] ) ) { - continue; - } - - $updates[ $update_type ] = array( - 'version' => $offer->version, - 'update_type' => $update_type, - 'package_url' => ! empty( $offer->packages->partial ) ? $offer->packages->partial : $offer->packages->full, - ); - } - - foreach( $updates as $type => $value ) { - if ( empty( $value ) ) { - unset( $updates[ $type ] ); - } - } - - foreach( array( 'major', 'minor' ) as $type ) { - if ( true === \WP_CLI\Utils\get_flag_value( $assoc_args, $type ) ) { - return ! empty( $updates[ $type ] ) ? array( $updates[ $type ] ) : false; - } - } - return array_values( $updates ); - } - - private function cleanup_extra_files( $version_from, $version_to, $locale ) { - if ( ! $version_from || ! $version_to ) { - WP_CLI::warning( 'Failed to find WordPress version. Please cleanup files manually.' ); - return; - } - - $old_checksums = self::get_core_checksums( $version_from, $locale ? $locale : 'en_US' ); - $new_checksums = self::get_core_checksums( $version_to, $locale ? $locale : 'en_US' ); - - if ( empty( $old_checksums ) || empty( $new_checksums ) ) { - WP_CLI::warning( 'Failed to fetch checksums. Please cleanup files manually.' ); - return; - } - - $files_to_remove = array_diff( array_keys( $old_checksums ), array_keys( $new_checksums ) ); - - if ( ! empty( $files_to_remove ) ) { - WP_CLI::log( 'Cleaning up files...' ); - - $count = 0; - foreach ( $files_to_remove as $file ) { - - // wp-content should be considered user data - if ( 0 === stripos( $file, 'wp-content' ) ) { - continue; - } - - if ( file_exists( ABSPATH . $file ) ) { - unlink( ABSPATH . $file ); - WP_CLI::log( 'File removed: ' . $file ); - $count++; - } - } - - if ( $count ) { - WP_CLI::log( number_format( $count ) . ' files cleaned up.' ); - } else { - WP_CLI::log( 'No files found that need cleaned up.' ); - } - } - } - -} - -WP_CLI::add_command( 'core', 'Core_Command' ); diff --git a/php/commands/eval-file.php b/php/commands/eval-file.php deleted file mode 100644 index d42391c93..000000000 --- a/php/commands/eval-file.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php - -class EvalFile_Command extends WP_CLI_Command { - - /** - * Load and execute a PHP file. - * - * ## OPTIONS - * - * <file> - * : The path to the PHP file to execute. - * - * [<arg>...] - * : One or more arguments to pass to the file. They are placed in the $args variable. - * - * [--skip-wordpress] - * : Load and execute file without loading WordPress. - * - * @when before_wp_load - * - * ## EXAMPLES - * - * wp eval-file my-code.php value1 value2 - */ - public function __invoke( $args, $assoc_args ) { - $file = array_shift( $args ); - - if ( !file_exists( $file ) ) { - WP_CLI::error( "'$file' does not exist." ); - } - - if ( null === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-wordpress' ) ) { - WP_CLI::get_runner()->load_wordpress(); - } - - self::_eval( $file, $args ); - } - - private static function _eval( $file, $args ) { - include( $file ); - } -} - -WP_CLI::add_command( 'eval-file', 'EvalFile_Command' ); - diff --git a/php/commands/eval.php b/php/commands/eval.php deleted file mode 100644 index e459b9d1d..000000000 --- a/php/commands/eval.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php - -class Eval_Command extends WP_CLI_Command { - - /** - * Execute arbitrary PHP code. - * - * ## OPTIONS - * - * <php-code> - * : The code to execute, as a string. - * - * [--skip-wordpress] - * : Execute code without loading WordPress. - * - * ## EXAMPLES - * - * # Display WordPress content directory. - * $ wp eval 'echo WP_CONTENT_DIR;' - * /var/www/wordpress/wp-content - * - * # Generate a random number. - * $ wp eval 'echo rand();' --skip-wordpress - * 479620423 - * - * @when before_wp_load - */ - public function __invoke( $args, $assoc_args ) { - - if ( null === \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-wordpress' ) ) { - WP_CLI::get_runner()->load_wordpress(); - } - - eval( $args[0] ); - } -} - -WP_CLI::add_command( 'eval', 'Eval_Command' ); diff --git a/php/commands/help.php b/php/commands/help.php deleted file mode 100644 index 31344a0fe..000000000 --- a/php/commands/help.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php - -use \WP_CLI\Utils; -use \WP_CLI\Dispatcher; - -class Help_Command extends WP_CLI_Command { - - /** - * Get help on WP-CLI, or on a specific command. - * - * ## OPTIONS - * - * [<command>...] - * : Get help on a specific command. - * - * ## EXAMPLES - * - * # get help for `core` command - * wp help core - * - * # get help for `core download` subcommand - * wp help core download - */ - function __invoke( $args, $assoc_args ) { - $command = self::find_subcommand( $args ); - - if ( $command ) { - - if ( WP_CLI::get_runner()->is_command_disabled( $command ) ) { - $path = implode( ' ', array_slice( \WP_CLI\Dispatcher\get_path( $command ), 1 ) ); - WP_CLI::error( sprintf( - "The '%s' command has been disabled from the config file.", - $path - ) ); - } - - self::show_help( $command ); - exit; - } - - // WordPress is already loaded, so there's no chance we'll find the command - if ( function_exists( 'add_filter' ) ) { - $command_string = implode( ' ', $args ); - \WP_CLI::error( sprintf( "'%s' is not a registered wp command.", $command_string ) ); - } - } - - private static function find_subcommand( $args ) { - $command = \WP_CLI::get_root_command(); - - while ( !empty( $args ) && $command && $command->can_have_subcommands() ) { - $command = $command->find_subcommand( $args ); - } - - return $command; - } - - private static function show_help( $command ) { - $out = self::get_initial_markdown( $command ); - - $longdesc = $command->get_longdesc(); - if ( $longdesc ) { - $out .= wordwrap( $longdesc, 90 ) . "\n"; - } - - // definition lists - $out = preg_replace_callback( '/([^\n]+)\n: (.+?)(\n\n|$)/s', array( __CLASS__, 'rewrap_param_desc' ), $out ); - - // Ensure all non-section headers are indented - $out = preg_replace( '#^([^\s^\#])#m', "\t$1", $out ); - - // section headers - $out = preg_replace( '/^## ([A-Z ]+)/m', WP_CLI::colorize( '%9\1%n' ), $out ); - - $out = str_replace( "\t", ' ', $out ); - - self::pass_through_pager( $out ); - } - - private static function rewrap_param_desc( $matches ) { - $param = $matches[1]; - $desc = self::indent( "\t\t", wordwrap( $matches[2] ) ); - return "\t$param\n$desc\n\n"; - } - - private static function indent( $whitespace, $text ) { - $lines = explode( "\n", $text ); - foreach ( $lines as &$line ) { - $line = $whitespace . $line; - } - return implode( $lines, "\n" ); - } - - private static function pass_through_pager( $out ) { - - if ( false === ( $pager = getenv( 'PAGER' ) ) ) { - $pager = Utils\is_windows() ? 'more' : 'less -r'; - } - - // convert string to file handle - $fd = fopen( "php://temp", "r+" ); - fputs( $fd, $out ); - rewind( $fd ); - - $descriptorspec = array( - 0 => $fd, - 1 => STDOUT, - 2 => STDERR - ); - - return proc_close( proc_open( $pager, $descriptorspec, $pipes ) ); - } - - private static function get_initial_markdown( $command ) { - $name = implode( ' ', Dispatcher\get_path( $command ) ); - - $binding = array( - 'name' => $name, - 'shortdesc' => $command->get_shortdesc(), - ); - - $binding['synopsis'] = wordwrap( "$name " . $command->get_synopsis(), 79 ); - - $alias = $command->get_alias(); - if ( $alias ) { - $binding['alias'] = $alias; - } - - if ( $command->can_have_subcommands() ) { - $binding['has-subcommands']['subcommands'] = self::render_subcommands( $command ); - } - - return Utils\mustache_render( 'man.mustache', $binding ); - } - - private static function render_subcommands( $command ) { - $subcommands = array(); - foreach ( $command->get_subcommands() as $subcommand ) { - - if ( WP_CLI::get_runner()->is_command_disabled( $subcommand ) ) { - continue; - } - - $subcommands[ $subcommand->get_name() ] = $subcommand->get_shortdesc(); - } - - $max_len = self::get_max_len( array_keys( $subcommands ) ); - - $lines = array(); - foreach ( $subcommands as $name => $desc ) { - $lines[] = str_pad( $name, $max_len ) . "\t\t\t" . $desc; - } - - return $lines; - } - - private static function get_max_len( $strings ) { - $max_len = 0; - foreach ( $strings as $str ) { - $len = strlen( $str ); - if ( $len > $max_len ) - $max_len = $len; - } - - return $max_len; - } - -} - -WP_CLI::add_command( 'help', 'Help_Command' ); - diff --git a/php/commands/menu-item.php b/php/commands/menu-item.php deleted file mode 100644 index 2b6f04b94..000000000 --- a/php/commands/menu-item.php +++ /dev/null @@ -1,503 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * List, add, and delete items associated with a menu. - * - * ## EXAMPLES - * - * # Add an existing post to an existing menu - * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" - * Success: Menu item added. - * - * # Create a new menu link item - * $ wp menu item add-custom sidebar-menu Apple http://apple.com - * Success: Menu item added. - * - * # Delete menu item - * $ wp menu item delete 45 - * Success: 1 menu item deleted. - */ -class Menu_Item_Command extends WP_CLI_Command { - - protected $obj_fields = array( - 'db_id', - 'type', - 'title', - 'link', - 'position', - ); - - /** - * Get a list of items associated with a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - ids - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each menu item: - * - * * db_id - * * type - * * title - * * link - * * position - * - * These fields are optionally available: - * - * * menu_item_parent - * * object_id - * * object - * * type - * * type_label - * * target - * * attr_title - * * description - * * classes - * * xfn - * - * ## EXAMPLES - * - * $ wp menu item list main-menu - * +-------+-----------+-------------+---------------------------------+----------+ - * | db_id | type | title | link | position | - * +-------+-----------+-------------+---------------------------------+----------+ - * | 5 | custom | Home | http://example.com | 1 | - * | 6 | post_type | Sample Page | http://example.com/sample-page/ | 2 | - * +-------+-----------+-------------+---------------------------------+----------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - $items = wp_get_nav_menu_items( $args[0] ); - if ( false === $items || is_wp_error( $items ) ) { - WP_CLI::error( "Invalid menu." ); - } - - // Correct position inconsistency and - // protected `url` param in WP-CLI - $items = array_map( function( $item ) use ( $assoc_args ) { - $item->position = $item->menu_order; - $item->link = $item->url; - return $item; - }, $items ); - - if ( ! empty( $assoc_args['format'] ) && 'ids' == $assoc_args['format'] ) { - $items = array_map( function( $item ) { - return $item->db_id; - }, $items ); - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_items( $items ); - - } - - /** - * Add a post as a menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <post-id> - * : Post ID to add to the menu. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-post sidebar-menu 33 --title="Custom Test Post" - * Success: Menu item added. - * - * @subcommand add-post - */ - public function add_post( $args, $assoc_args ) { - - $assoc_args['object-id'] = $args[1]; - unset( $args[1] ); - $post = get_post( $assoc_args['object-id'] ); - if ( ! $post ) { - WP_CLI::error( "Invalid post." ); - } - $assoc_args['object'] = $post->post_type; - - $this->add_or_update_item( 'add', 'post_type', $args, $assoc_args ); - } - - /** - * Add a taxonomy term as a menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <taxonomy> - * : Taxonomy of the term to be added. - * - * <term-id> - * : Term ID of the term to be added. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-term sidebar-menu post_tag 24 - * Success: Menu item added. - * - * @subcommand add-term - */ - public function add_term( $args, $assoc_args ) { - - $assoc_args['object'] = $args[1]; - unset( $args[1] ); - $assoc_args['object-id'] = $args[2]; - unset( $args[2] ); - - if ( ! get_term_by( 'id', $assoc_args['object-id'], $assoc_args['object'] ) ) { - WP_CLI::error( "Invalid term." ); - } - - $this->add_or_update_item( 'add', 'taxonomy', $args, $assoc_args ); - } - - /** - * Add a custom menu item. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <title> - * : Title for the link. - * - * <link> - * : Target URL for the link. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * [--porcelain] - * : Output just the new menu item id. - * - * ## EXAMPLES - * - * $ wp menu item add-custom sidebar-menu Apple http://apple.com - * Success: Menu item added. - * - * @subcommand add-custom - */ - public function add_custom( $args, $assoc_args ) { - - $assoc_args['title'] = $args[1]; - unset( $args[1] ); - $assoc_args['link'] = $args[2]; - unset( $args[2] ); - $this->add_or_update_item( 'add', 'custom', $args, $assoc_args ); - } - - /** - * Update a menu item. - * - * ## OPTIONS - * - * <db-id> - * : Database ID for the menu item. - * - * [--title=<title>] - * : Set a custom title for the menu item. - * - * [--link=<link>] - * : Set a custom url for the menu item. - * - * [--description=<description>] - * : Set a custom description for the menu item. - * - * [--attr-title=<attr-title>] - * : Set a custom title attribute for the menu item. - * - * [--target=<target>] - * : Set a custom link target for the menu item. - * - * [--classes=<classes>] - * : Set a custom link classes for the menu item. - * - * [--position=<position>] - * : Specify the position of this menu item. - * - * [--parent-id=<parent-id>] - * : Make this menu item a child of another menu item. - * - * ## EXAMPLES - * - * $ wp menu item update 45 --title=WordPress --link='http://wordpress.org' --target=_blank --position=2 - * Success: Menu item updated. - * - * @subcommand update - */ - public function update( $args, $assoc_args ) { - - // Shuffle the position of these. - $args[1] = $args[0]; - $terms = get_the_terms( $args[1], 'nav_menu' ); - if ( $terms && ! is_wp_error( $terms ) ) { - $args[0] = (int)$terms[0]->term_id; - } else { - $args[0] = 0; - } - $type = get_post_meta( $args[1], '_menu_item_type', true ); - $this->add_or_update_item( 'update', $type, $args, $assoc_args ); - - } - - /** - * Delete one or more items from a menu. - * - * ## OPTIONS - * - * <db-id>... - * : Database ID for the menu item(s). - * - * ## EXAMPLES - * - * $ wp menu item delete 45 - * Success: 1 menu item deleted. - * - * @subcommand delete - */ - public function delete( $args, $_ ) { - global $wpdb; - - $count = $errors = 0; - - foreach( $args as $arg ) { - - $parent_menu_id = (int) get_post_meta( $arg, '_menu_item_menu_item_parent', true ); - $ret = wp_delete_post( $arg, true ); - if ( ! $ret ) { - WP_CLI::warning( "Couldn't delete menu item {$arg}." ); - $errors++; - } else if ( $parent_menu_id ) { - $children = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value=%s", (int) $arg ) ); - if ( $children ) { - $children_query = $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %d WHERE meta_key = '_menu_item_menu_item_parent' AND meta_value=%s", $parent_menu_id, (int) $arg ); - $wpdb->query( $children_query ); - foreach( $children as $child ) { - clean_post_cache( $child ); - } - } - } - - if ( false != $ret ) { - $count++; - } - - } - - Utils\report_batch_operation_results( 'menu item', 'delete', count( $args ), $count, $errors ); - } - - /** - * Worker method to create new items or update existing ones. - */ - private function add_or_update_item( $method, $type, $args, $assoc_args ) { - - $menu = $args[0]; - $menu_item_db_id = \WP_CLI\Utils\get_flag_value( $args, 1, 0 ); - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - // `url` is protected in WP-CLI, so we use `link` instead - $assoc_args['url'] = \WP_CLI\Utils\get_flag_value( $assoc_args, 'link' ); - - // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 - if ( 'update' == $method ) { - - $menu_item_obj = get_post( $menu_item_db_id ); - $menu_item_obj = wp_setup_nav_menu_item( $menu_item_obj ); - - // Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140 - $position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order; - - $default_args = array( - 'position' => $position, - 'title' => $menu_item_obj->title, - 'url' => $menu_item_obj->url, - 'description' => $menu_item_obj->description, - 'object' => $menu_item_obj->object, - 'object-id' => $menu_item_obj->object_id, - 'parent-id' => $menu_item_obj->menu_item_parent, - 'attr-title' => $menu_item_obj->attr_title, - 'target' => $menu_item_obj->target, - 'classes' => implode( ' ', $menu_item_obj->classes ), // stored in the database as array - 'xfn' => $menu_item_obj->xfn, - 'status' => $menu_item_obj->post_status, - ); - - } else { - - $default_args = array( - 'position' => 0, - 'title' => '', - 'url' => '', - 'description' => '', - 'object' => '', - 'object-id' => 0, - 'parent-id' => 0, - 'attr-title' => '', - 'target' => '', - 'classes' => '', - 'xfn' => '', - // Core oddly defaults to 'draft' for create, - // and 'publish' for update - // Easiest to always work with publish - 'status' => 'publish', - ); - - } - - $menu_item_args = array(); - foreach( $default_args as $key => $default_value ) { - // wp_update_nav_menu_item() has a weird argument prefix - $new_key = 'menu-item-' . $key; - $menu_item_args[ $new_key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $default_value ); - } - - $menu_item_args['menu-item-type'] = $type; - $ret = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args ); - - if ( is_wp_error( $ret ) ) { - WP_CLI::error( $ret->get_error_message() ); - } else if ( ! $ret ) { - if ( 'add' == $method ) { - WP_CLI::error( "Couldn't add menu item." ); - } else if ( 'update' == $method ) { - WP_CLI::error( "Couldn't update menu item." ); - } - } else { - - /** - * Set the menu - * - * wp_update_nav_menu_item() *should* take care of this, but - * depends on wp_insert_post()'s "tax_input" argument, which - * is ignored if the user can't edit the taxonomy - * - * @see https://core.trac.wordpress.org/ticket/27113 - */ - if ( ! is_object_in_term( $ret, 'nav_menu', (int) $menu->term_id ) ) { - wp_set_object_terms( $ret, array( (int)$menu->term_id ), 'nav_menu' ); - } - - if ( 'add' == $method && ! empty( $assoc_args['porcelain'] ) ) { - WP_CLI::line( $ret ); - } else { - if ( 'add' == $method ) { - WP_CLI::success( "Menu item added." ); - } else if ( 'update' == $method ) { - WP_CLI::success( "Menu item updated." ); - } - } - } - - } - - protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields ); - } - -} - -WP_CLI::add_command( 'menu item', 'Menu_Item_Command' ); diff --git a/php/commands/menu-location.php b/php/commands/menu-location.php deleted file mode 100644 index 63fd3a9e9..000000000 --- a/php/commands/menu-location.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php - -/** - * Manage a menu's assignment to locations. - * - * ## EXAMPLES - * - * # List available menu locations - * $ wp menu location list - * +----------+-------------------+ - * | location | description | - * +----------+-------------------+ - * | primary | Primary Menu | - * | social | Social Links Menu | - * +----------+-------------------+ - * - * # Assign the 'primary-menu' menu to the 'primary' location - * $ wp menu location assign primary-menu primary - * Success: Assigned location to menu. - * - * # Remove the 'primary-menu' menu from the 'primary' location - * $ wp menu location remove primary-menu primary - * Success: Removed location from menu. - */ -class Menu_Location_Command extends WP_CLI_Command { - - /** - * List locations for the current theme. - * - * ## OPTIONS - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * - ids - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each location: - * - * * name - * * description - * - * ## EXAMPLES - * - * $ wp menu location list - * +----------+-------------------+ - * | location | description | - * +----------+-------------------+ - * | primary | Primary Menu | - * | social | Social Links Menu | - * +----------+-------------------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - - $locations = get_registered_nav_menus(); - $location_objs = array(); - foreach( $locations as $location => $description ) { - $location_obj = new \stdClass; - $location_obj->location = $location; - $location_obj->description = $description; - $location_objs[] = $location_obj; - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, array( 'location', 'description' ) ); - - if ( 'ids' == $formatter->format ) { - $ids = array_map( - function($o) { - return $o->location; - }, $location_objs - ); - $formatter->display_items( $ids ); - } else { - $formatter->display_items( $location_objs ); - } - } - - /** - * Assign a location to a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <location> - * : Location's slug. - * - * ## EXAMPLES - * - * $ wp menu location assign primary-menu primary - * Success: Assigned location primary to menu primary-menu. - * - * @subcommand assign - */ - public function assign( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu_obj = wp_get_nav_menu_object( $menu ); - if ( ! $menu_obj ) { - WP_CLI::error( "Invalid menu $menu." ); - } - - $locations = get_registered_nav_menus(); - if ( ! array_key_exists( $location, $locations ) ) { - WP_CLI::error( "Invalid location $location." ); - } - - $locations = get_nav_menu_locations(); - $locations[ $location ] = $menu_obj->term_id; - - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Assigned location $location to menu $menu." ); - } - - /** - * Remove a location from a menu. - * - * ## OPTIONS - * - * <menu> - * : The name, slug, or term ID for the menu. - * - * <location> - * : Location's slug. - * - * ## EXAMPLES - * - * $ wp menu location remove primary-menu primary - * Success: Removed location from menu. - * - * @subcommand remove - */ - public function remove( $args, $_ ) { - - list( $menu, $location ) = $args; - - $menu = wp_get_nav_menu_object( $menu ); - if ( ! $menu || is_wp_error( $menu ) ) { - WP_CLI::error( "Invalid menu." ); - } - - $locations = get_nav_menu_locations(); - if ( \WP_CLI\Utils\get_flag_value( $locations, $location ) != $menu->term_id ) { - WP_CLI::error( "Menu isn't assigned to location." ); - } - - $locations[ $location ] = 0; - set_theme_mod( 'nav_menu_locations', $locations ); - - WP_CLI::success( "Removed location from menu." ); - - } - -} - -WP_CLI::add_command( 'menu location', 'Menu_Location_Command' ); diff --git a/php/commands/menu.php b/php/commands/menu.php deleted file mode 100644 index 2a51a307b..000000000 --- a/php/commands/menu.php +++ /dev/null @@ -1,202 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * List, create, assign, and delete menus. - * - * ## EXAMPLES - * - * # Create a new menu - * $ wp menu create "My Menu" - * Success: Created menu 200. - * - * # List existing menus - * $ wp menu list - * +---------+----------+----------+-----------+-------+ - * | term_id | name | slug | locations | count | - * +---------+----------+----------+-----------+-------+ - * | 200 | My Menu | my-menu | | 0 | - * | 177 | Top Menu | top-menu | primary | 7 | - * +---------+----------+----------+-----------+-------+ - * - * # Create a new menu link item - * $ wp menu item add-custom my-menu Apple http://apple.com --porcelain - * 1922 - * - * # Assign the 'my-menu' menu to the 'primary' location - * $ wp menu location assign my-menu primary - * Success: Assigned location to menu. - * - * @package wp-cli - */ -class Menu_Command extends WP_CLI_Command { - - protected $obj_type = 'nav_menu'; - protected $obj_fields = array( - 'term_id', - 'name', - 'slug', - 'locations', - 'count', - ); - - /** - * Create a new menu. - * - * ## OPTIONS - * - * <menu-name> - * : A descriptive name for the menu. - * - * [--porcelain] - * : Output just the new menu id. - * - * ## EXAMPLES - * - * $ wp menu create "My Menu" - * Success: Created menu 200. - */ - public function create( $args, $assoc_args ) { - - $menu_id = wp_create_nav_menu( $args[0] ); - - if ( is_wp_error( $menu_id ) ) { - - WP_CLI::error( $menu_id->get_error_message() ); - - } else { - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { - WP_CLI::line( $menu_id ); - } else { - WP_CLI::success( "Created menu $menu_id." ); - } - - } - } - - /** - * Delete one or more menus. - * - * ## OPTIONS - * - * <menu>... - * : The name, slug, or term ID for the menu(s). - * - * ## EXAMPLES - * - * $ wp menu delete "My Menu" - * Success: 1 menu deleted. - */ - public function delete( $args, $_ ) { - - $count = $errors = 0; - foreach( $args as $arg ) { - $ret = wp_delete_nav_menu( $arg ); - if ( ! $ret || is_wp_error( $ret ) ) { - WP_CLI::warning( "Couldn't delete menu '{$arg}'." ); - $errors++; - } else { - WP_CLI::log( "Deleted menu '{$arg}'." ); - $count++; - } - } - - Utils\report_batch_operation_results( 'menu', 'delete', count( $args ), $count, $errors ); - } - - /** - * Get a list of menus. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - ids - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each menu: - * - * * term_id - * * name - * * slug - * * count - * - * These fields are optionally available: - * - * * term_group - * * term_taxonomy_id - * * taxonomy - * * description - * * parent - * * locations - * - * ## EXAMPLES - * - * $ wp menu list - * +---------+----------+----------+-----------+-------+ - * | term_id | name | slug | locations | count | - * +---------+----------+----------+-----------+-------+ - * | 200 | My Menu | my-menu | | 0 | - * | 177 | Top Menu | top-menu | primary | 7 | - * +---------+----------+----------+-----------+-------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - - $menus = wp_get_nav_menus(); - - $menu_locations = get_nav_menu_locations(); - foreach( $menus as &$menu ) { - - $menu->locations = array(); - foreach( $menu_locations as $location => $term_id ) { - - if ( $term_id == $menu->term_id ) { - $menu->locations[] = $location; - } - - } - - // Normalize the data for some output formats. - if ( ! isset( $assoc_args['format'] ) || in_array( $assoc_args['format'], array( 'csv', 'table' ) ) ) { - $menu->locations = implode( ',', $menu->locations ); - } - } - - $formatter = $this->get_formatter( $assoc_args ); - - if ( 'ids' == $formatter->format ) { - $ids = array_map( - function($o) { - return $o->term_id; - }, $menus - ); - $formatter->display_items( $ids ); - } else { - $formatter->display_items( $menus ); - } - } - - protected function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->obj_fields, $this->obj_type ); - } - -} - -WP_CLI::add_command( 'menu', 'Menu_Command' ); diff --git a/php/commands/network.php b/php/commands/network.php deleted file mode 100644 index 50905b567..000000000 --- a/php/commands/network.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -/** - * Manage network custom fields. - * - * ## EXAMPLES - * - * # Get a list of super-admins - * $ wp network meta get 1 site_admins - * array ( - * 0 => 'supervisor', - * ) - */ -class Network_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'site'; -} - -WP_CLI::add_command( 'network meta', 'Network_Meta_Command', array( - 'before_invoke' => function () { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - } -) ); - diff --git a/php/commands/option.php b/php/commands/option.php deleted file mode 100644 index 8216d8e5e..000000000 --- a/php/commands/option.php +++ /dev/null @@ -1,384 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage options. - * - * ## EXAMPLES - * - * # Get site URL. - * $ wp option get siteurl - * http://example.com - * - * # Add option. - * $ wp option add my_option foobar - * Success: Added 'my_option' option. - * - * # Update option. - * $ wp option update my_option '{"foo": "bar"}' --format=json - * Success: Updated 'my_option' option. - * - * # Delete option. - * $ wp option delete my_option - * Success: Deleted 'my_option' option. - * - * @package wp-cli - */ -class Option_Command extends WP_CLI_Command { - - /** - * Get the value for an option. - * - * ## OPTIONS - * - * <key> - * : Key for the option. - * - * [--format=<format>] - * : Get value in a particular format. - * --- - * default: var_export - * options: - * - var_export - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get option. - * $ wp option get home - * http://example.com - * - * # Get option in JSON format. - * $ wp option get active_plugins --format=json - * {"0":"dynamically-dynamic-sidebar\/dynamically-dynamic-sidebar.php","1":"monster-widget\/monster-widget.php","2":"show-current-template\/show-current-template.php","3":"theme-check\/theme-check.php","5":"wordpress-importer\/wordpress-importer.php"} - */ - public function get( $args, $assoc_args ) { - list( $key ) = $args; - - $value = get_option( $key ); - - if ( false === $value ) { - WP_CLI::halt( 1 ); - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Add a new option value. - * - * Errors if the option already exists. - * - * ## OPTIONS - * - * <key> - * : The name of the option to add. - * - * [<value>] - * : The value of the option to add. If ommited, the value is read from STDIN. - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - * - * [--autoload=<autoload>] - * : Should this option be automatically loaded. - * --- - * options: - * - 'yes' - * - 'no' - * --- - * - * ## EXAMPLES - * - * # Create an option by reading a JSON file. - * $ wp option add my_option --format=json < config.json - * Success: Added 'my_option' option. - */ - public function add( $args, $assoc_args ) { - $key = $args[0]; - - $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); - $value = WP_CLI::read_value( $value, $assoc_args ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'autoload' ) === 'no' ) { - $autoload = 'no'; - } else { - $autoload = 'yes'; - } - - if ( !add_option( $key, $value, '', $autoload ) ) { - WP_CLI::error( "Could not add option '$key'. Does it already exist?" ); - } else { - WP_CLI::success( "Added '$key' option." ); - } - } - - /** - * List options and their values. - * - * ## OPTIONS - * - * [--search=<pattern>] - * : Use wildcards ( * and ? ) to match option name. - * - * [--exclude=<pattern>] - * : Pattern to exclude. Use wildcards ( * and ? ) to match option name. - * - * [--autoload=<value>] - * : Match only autoload options when value is on, and only not-autoload option when off. - * - * [--transients] - * : List only transients. Use `--no-transients` to ignore all transients. - * - * [--field=<field>] - * : Prints the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. - * --- - * default: table - * options: - * - table - * - json - * - csv - * - count - * - yaml - * - total_bytes - * --- - * - * ## AVAILABLE FIELDS - * - * This field will be displayed by default for each matching option: - * - * * option_name - * * option_value - * - * These fields are optionally available: - * - * * autoload - * * size_bytes - * - * ## EXAMPLES - * - * # Get the total size of all autoload options. - * $ wp option list --autoload=on --format=total_bytes - * 33198 - * - * # Find biggest transients. - * $ wp option list --search="*_transient_*" --fields=option_name,size_bytes | sort -n -k 2 | tail - * option_name size_bytes - * _site_transient_timeout_theme_roots 10 - * _site_transient_theme_roots 76 - * _site_transient_update_themes 181 - * _site_transient_update_core 808 - * _site_transient_update_plugins 6645 - * - * # List all options begining with "i2f_". - * $ wp option list --search="i2f_*" - * +-------------+--------------+ - * | option_name | option_value | - * +-------------+--------------+ - * | i2f_version | 0.1.0 | - * +-------------+--------------+ - * - * # Delete all options begining with "theme_mods_". - * $ wp option list --search="theme_mods_*" --field=option_name | xargs -I % wp option delete % - * Success: Deleted 'theme_mods_twentysixteen' option. - * Success: Deleted 'theme_mods_twentyfifteen' option. - * Success: Deleted 'theme_mods_twentyfourteen' option. - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - global $wpdb; - $pattern = '%'; - $exclude = ''; - $fields = array( 'option_name', 'option_value' ); - $size_query = ",LENGTH(option_value) AS `size_bytes`"; - $autoload_query = ''; - - if ( isset( $assoc_args['search'] ) ) { - $pattern = self::esc_like( $assoc_args['search'] ); - // substitute wildcards - $pattern = str_replace( '*', '%', $pattern ); - $pattern = str_replace( '?', '_', $pattern ); - } - - if ( isset( $assoc_args['exclude'] ) ) { - $exclude = self::esc_like( $assoc_args['exclude'] ); - $exclude = str_replace( '*', '%', $exclude ); - $exclude = str_replace( '?', '_', $exclude ); - } - - if ( isset( $assoc_args['fields'] ) ) { - $fields = explode( ',', $assoc_args['fields'] ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { - $fields = array( 'size_bytes' ); - $size_query = ",SUM(LENGTH(option_value)) AS `size_bytes`"; - } - - if ( isset( $assoc_args['autoload'] ) ) { - if ( 'on' === $assoc_args['autoload'] ) { - $autoload_query = " AND autoload='yes'"; - } elseif ( 'off' === $assoc_args['autoload'] ) { - $autoload_query = " AND autoload='no'"; - } else { - WP_CLI::error( "Value of '--autoload' should be on or off." ); - } - } - - $transients_query = ''; - if ( true === Utils\get_flag_value( $assoc_args, 'transients', null ) ) { - $transients_query = " AND option_name LIKE '\_transient\_%' - OR option_name LIKE '\_site\_transient\_%'"; - } else if ( false === Utils\get_flag_value( $assoc_args, 'transients', null ) ) { - $transients_query = " AND option_name NOT LIKE '\_transient\_%' - AND option_name NOT LIKE '\_site\_transient\_%'"; - } - - $where = ''; - if ( $pattern ) { - $where .= $wpdb->prepare( "WHERE `option_name` LIKE %s", $pattern ); - } - - if ( $exclude ) { - $where .= $wpdb->prepare( " AND `option_name` NOT LIKE %s", $exclude ); - } - $where .= $autoload_query . $transients_query; - - $results = $wpdb->get_results( "SELECT `option_name`,`option_value`,`autoload`" . $size_query - . " FROM `$wpdb->options` {$where}" ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { - WP_CLI::line( $results[0]->size_bytes ); - } else { - $formatter = new \WP_CLI\Formatter( - $assoc_args, - $fields - ); - $formatter->display_items( $results ); - } - } - - /** - * Update an option value. - * - * ## OPTIONS - * - * <key> - * : The name of the option to update. - * - * [<value>] - * : The new value. If ommited, the value is read from STDIN. - * - * [--autoload=<autoload>] - * : Requires WP 4.2. Should this option be automatically loaded. - * --- - * options: - * - 'yes' - * - 'no' - * --- - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - * - * ## EXAMPLES - * - * # Update an option by reading from a file. - * $ wp option update my_option < value.txt - * Success: Updated 'my_option' option. - * - * # Update one option on multiple sites using xargs. - * $ wp site list --field=url | xargs -n1 -I {} sh -c 'wp --url={} option update my_option my_value' - * Success: Updated 'my_option' option. - * Success: Updated 'my_option' option. - * - * @alias set - */ - public function update( $args, $assoc_args ) { - $key = $args[0]; - - $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); - $value = WP_CLI::read_value( $value, $assoc_args ); - - $autoload = \WP_CLI\Utils\get_flag_value( $assoc_args, 'autoload' ); - if ( ! in_array( $autoload, array( 'yes', 'no' ) ) ) { - $autoload = null; - } - - $value = sanitize_option( $key, $value ); - $old_value = sanitize_option( $key, get_option( $key ) ); - - if ( $value === $old_value && is_null( $autoload ) ) { - WP_CLI::success( "Value passed for '$key' option is unchanged." ); - } else { - if ( update_option( $key, $value, $autoload ) ) { - WP_CLI::success( "Updated '$key' option." ); - } else { - WP_CLI::error( "Could not update option '$key'." ); - } - } - } - - /** - * Delete an option. - * - * ## OPTIONS - * - * <key> - * : Key for the option. - * - * ## EXAMPLES - * - * # Delete an option. - * $ wp option delete my_option - * Success: Deleted 'my_option' option. - */ - public function delete( $args ) { - list( $key ) = $args; - - if ( !delete_option( $key ) ) { - WP_CLI::error( "Could not delete '$key' option. Does it exist?" ); - } else { - WP_CLI::success( "Deleted '$key' option." ); - } - } - - private static function esc_like( $old ) { - global $wpdb; - - // Remove notices in 4.0 and support backwards compatibility - if( method_exists( $wpdb, 'esc_like' ) ) { - // 4.0 - $old = $wpdb->esc_like( $old ); - } else { - // 3.9 or less - $old = like_escape( esc_sql( $old ) ); - } - - return $old; - } -} - -WP_CLI::add_command( 'option', 'Option_Command' ); diff --git a/php/commands/package.php b/php/commands/package.php deleted file mode 100644 index 01f15ecd8..000000000 --- a/php/commands/package.php +++ /dev/null @@ -1,876 +0,0 @@ -<?php -use \Composer\Composer; -use \Composer\Config; -use \Composer\Config\JsonConfigSource; -use \Composer\DependencyResolver\Pool; -use \Composer\EventDispatcher\Event; -use \Composer\Factory; -use \Composer\IO\NullIO; -use \Composer\Installer; -use \Composer\Json\JsonFile; -use \Composer\Json\JsonManipulator; -use \Composer\Package; -use \Composer\Package\BasePackage; -use \Composer\Package\PackageInterface; -use \Composer\Package\Version\VersionParser; -use \Composer\Package\Version\VersionSelector; -use \Composer\Repository; -use \Composer\Repository\CompositeRepository; -use \Composer\Repository\ComposerRepository; -use \Composer\Repository\RepositoryManager; -use \Composer\Util\Filesystem; -use \WP_CLI\ComposerIO; -use \WP_CLI\Extractor; -use \WP_CLI\Utils; - -/** - * Manage WP-CLI packages. - * - * WP-CLI packages are community-maintained projects built on WP-CLI. They can - * contain WP-CLI commands, but they can also just extend WP-CLI in some way. - * - * Installable packages are listed in the - * [Package Index](http://wp-cli.org/package-index/). - * - * Learn how to create your own command from the - * [Commands Cookbook](http://wp-cli.org/docs/commands-cookbook/) - * - * ## EXAMPLES - * - * # List installed packages - * $ wp package list - * +-----------------------+------------------------------------------+---------+------------+ - * | name | description | authors | version | - * +-----------------------+------------------------------------------+---------+------------+ - * | wp-cli/server-command | Start a development server for WordPress | | dev-master | - * +-----------------------+------------------------------------------+---------+------------+ - * - * # Install the latest development version of the package - * $ wp package install wp-cli/server-command - * Installing package wp-cli/server-command (dev-master) - * Updating /home/person/.wp-cli/packages/composer.json to require the package... - * Using Composer to install the package... - * --- - * Loading composer repositories with package information - * Updating dependencies - * Resolving dependencies through SAT - * Dependency resolution completed in 0.005 seconds - * Analyzed 732 packages to resolve dependencies - * Analyzed 1034 rules to resolve dependencies - * - Installing package - * Writing lock file - * Generating autoload files - * --- - * Success: Package installed. - * - * # Uninstall package - * $ wp package uninstall wp-cli/server-command - * Removing require statement from /home/person/.wp-cli/packages/composer.json - * Deleting package directory /home/person/.wp-cli/packages/vendor/wp-cli/server-command - * Regenerating Composer autoload. - * Success: Uninstalled package. - * - * @package WP-CLI - * - * @when before_wp_load - */ -class Package_Command extends WP_CLI_Command { - - const PACKAGE_INDEX_URL = 'https://wp-cli.org/package-index/'; - - private $pool = false; - - /** - * Browse WP-CLI packages available for installation. - * - * Lists packages available for installation from the [Package Index](http://wp-cli.org/package-index/). - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each package: - * - * * name - * * description - * * authors - * * version - * - * There are no optionally available fields. - * - * ## EXAMPLES - * - * $ wp package browse --format=yaml - * --- - * 10up/mu-migration: - * name: 10up/mu-migration - * description: A set of WP-CLI commands to support the migration of single WordPress instances to multisite - * authors: Nícholas André - * version: dev-master, dev-develop - * aaemnnosttv/wp-cli-dotenv-command: - * name: aaemnnosttv/wp-cli-dotenv-command - * description: Dotenv commands for WP-CLI - * authors: Evan Mattson - * version: v0.1, v0.1-beta.1, v0.2, dev-master, dev-dev, dev-develop, dev-tests/behat - * aaemnnosttv/wp-cli-http-command: - * name: aaemnnosttv/wp-cli-http-command - * description: WP-CLI command for using the WordPress HTTP API - * authors: Evan Mattson - * version: dev-master - * - */ - public function browse( $_, $assoc_args ) { - $this->show_packages( 'browse', $this->get_community_packages(), $assoc_args ); - } - - /** - * Install a WP-CLI package. - * - * Packages are required to be a valid Composer package, and can be - * specified as: - * - * * Package name from WP-CLI's package index. - * * Git URL accessible by the current shell user. - * * Path to a directory on the local machine. - * * Local or remote .zip file. - * - * When installing a local directory, WP-CLI simply registers a - * reference to the directory. If you move or delete the directory, WP-CLI's - * reference breaks. - * - * When installing a .zip file, WP-CLI extracts the package to - * `~/.wp-cli/packages/local/<package-name>`. - * - * ## OPTIONS - * - * <name|git|path|zip> - * : Name, git URL, directory path, or .zip file for the package to install. - * Names can optionally include a version constraint - * (e.g. wp-cli/server-command:@stable). - * - * ## EXAMPLES - * - * # Install the latest development version from the package index. - * $ wp package install wp-cli/server-command - * Installing package wp-cli/server-command (dev-master) - * Updating /home/person/.wp-cli/packages/composer.json to require the package... - * Using Composer to install the package... - * --- - * Loading composer repositories with package information - * Updating dependencies - * Resolving dependencies through SAT - * Dependency resolution completed in 0.005 seconds - * Analyzed 732 packages to resolve dependencies - * Analyzed 1034 rules to resolve dependencies - * - Installing package - * Writing lock file - * Generating autoload files - * --- - * Success: Package installed. - * - * # Install the latest stable version. - * $ wp package install wp-cli/server-command:@stable - * - * # Install a package hosted at a git URL. - * $ wp package install git@github.com:runcommand/hook.git - * - * # Install a package in a .zip file. - * $ wp package install google-sitemap-generator-cli.zip - */ - public function install( $args, $assoc_args ) { - list( $package_name ) = $args; - - $git_package = $dir_package = false; - $version = 'dev-master'; - if ( '.git' === strtolower( substr( $package_name, -4, 4 ) ) ) { - $git_package = $package_name; - preg_match( '#([^:\/]+\/[^\/]+)\.git#', $package_name, $matches ); - if ( ! empty( $matches[1] ) ) { - $package_name = $matches[1]; - } else { - WP_CLI::error( "Couldn't parse package name from expected path '<name>/<package>'." ); - } - } else if ( ( false !== strpos( $package_name, '://' ) && false !== stripos( $package_name, '.zip' ) ) - || ( pathinfo( $package_name, PATHINFO_EXTENSION ) === 'zip' && is_file( $package_name ) ) ) { - // Download the remote ZIP file to a temp directory - if ( false !== strpos( $package_name, '://' ) ) { - $temp = Utils\get_temp_dir() . uniqid('package_') . ".zip"; - $options = array( - 'timeout' => 600, - 'filename' => $temp - ); - $response = Utils\http_request( 'GET', $package_name, null, array(), $options ); - if ( 20 != substr( $response->status_code, 0, 2 ) ) { - WP_CLI::error( "Couldn't download package." ); - } - $package_name = $temp; - } - $dir_package = Utils\get_temp_dir() . uniqid( 'package_' ); - try { - // Extract the package to get the package name - Extractor::extract( $package_name, $dir_package ); - list( $package_name, $version ) = self::get_package_name_and_version_from_dir_package( $dir_package ); - // Move to a location based on the package name - $local_dir = rtrim( WP_CLI::get_runner()->get_packages_dir_path(), '/' ) . '/local/'; - $actual_dir_package = $local_dir . str_replace( '/', '-', $package_name ); - Extractor::copy_overwrite_files( $dir_package, $actual_dir_package ); - Extractor::rmdir( $dir_package ); - // Behold, the extracted package - $dir_package = $actual_dir_package; - } catch ( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - } else if ( is_dir( $package_name ) && file_exists( $package_name . '/composer.json' ) ) { - $dir_package = $package_name; - if ( ! Utils\is_path_absolute( $dir_package ) ) { - $dir_package = getcwd() . DIRECTORY_SEPARATOR . $dir_package; - } - list( $package_name, $version ) = self::get_package_name_and_version_from_dir_package( $dir_package ); - } else { - if ( false !== strpos( $package_name, ':' ) ) { - list( $package_name, $version ) = explode( ':', $package_name ); - } - $package = $this->get_community_package_by_name( $package_name ); - if ( ! $package ) { - WP_CLI::error( "Invalid package." ); - } - } - - WP_CLI::log( sprintf( "Installing package %s (%s)", $package_name, $version ) ); - - $composer_json_obj = $this->get_composer_json(); - - // Add the 'require' to composer.json - WP_CLI::log( sprintf( "Updating %s to require the package...", $composer_json_obj->getPath() ) ); - $composer_backup = file_get_contents( $composer_json_obj->getPath() ); - $json_manipulator = new JsonManipulator( $composer_backup ); - $json_manipulator->addMainKey( 'name', 'wp-cli/wp-cli' ); - $json_manipulator->addMainKey( 'version', self::get_wp_cli_version_composer() ); - $json_manipulator->addLink( 'require', $package_name, $version ); - $json_manipulator->addConfigSetting( 'secure-http', true ); - - if ( $git_package ) { - WP_CLI::log( sprintf( 'Registering %s as a VCS repository...', $git_package ) ); - $json_manipulator->addRepository( $package_name, array( 'type' => 'vcs', 'url' => $git_package ) ); - } else if ( $dir_package ) { - WP_CLI::log( sprintf( 'Registering %s as a path repository...', $dir_package ) ); - $json_manipulator->addRepository( $package_name, array( 'type' => 'path', 'url' => $dir_package ) ); - } - - $composer_backup_decoded = json_decode( $composer_backup, true ); - // If the composer file does not contain the current package index repository, refresh the repository definition. - if ( empty( $composer_backup_decoded['repositories']['wp-cli']['url'] ) || self::PACKAGE_INDEX_URL != $composer_backup_decoded['repositories']['wp-cli']['url'] ) { - WP_CLI::log( 'Updating package index repository url...' ); - $json_manipulator->addRepository( 'wp-cli', array( 'type' => 'composer', 'url' => self::PACKAGE_INDEX_URL ) ); - } - - file_put_contents( $composer_json_obj->getPath(), $json_manipulator->getContents() ); - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - // Set up the EventSubscriber - $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber; - $composer->getEventDispatcher()->addSubscriber( $event_subscriber ); - - // Set up the installer - $install = Installer::create( new ComposerIO, $composer ); - $install->setUpdate( true ); // Installer class will only override composer.lock with this flag - $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. - - // Try running the installer, but revert composer.json if failed - WP_CLI::log( 'Using Composer to install the package...' ); - WP_CLI::log( '---' ); - $res = false; - try { - $res = $install->run(); - } catch ( Exception $e ) { - WP_CLI::warning( $e->getMessage() ); - } - WP_CLI::log( '---' ); - - if ( 0 === $res ) { - WP_CLI::success( "Package installed." ); - } else { - file_put_contents( $composer_json_obj->getPath(), $composer_backup ); - WP_CLI::error( "Package installation failed (Composer return code {$res}). Reverted composer.json" ); - } - } - - /** - * List installed WP-CLI packages. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each package: - * - * * name - * * authors - * * version - * * update - * * update_version - * - * These fields are optionally available: - * - * * description - * - * ## EXAMPLES - * - * $ wp package list - * +-----------------------+------------------------------------------+---------+------------+ - * | name | description | authors | version | - * +-----------------------+------------------------------------------+---------+------------+ - * | wp-cli/server-command | Start a development server for WordPress | | dev-master | - * +-----------------------+------------------------------------------+---------+------------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $this->show_packages( 'list', $this->get_installed_packages(), $assoc_args ); - } - - /** - * Get the path to an installed WP-CLI package, or the package directory. - * - * If you want to contribute to a package, this is a great way to jump to it. - * - * ## OPTIONS - * - * [<name>] - * : Name of the package to get the directory for. - * - * ## EXAMPLES - * - * # Get package path - * $ wp package path - * /home/person/.wp-cli/packages/ - * - * # Change directory to package path - * $ cd $(wp package path) && pwd - * /home/vagrant/.wp-cli/packages - */ - function path( $args ) { - $packages_dir = WP_CLI::get_runner()->get_packages_dir_path(); - if ( ! empty( $args ) ) { - $packages_dir .= 'vendor/' . $args[0]; - if ( ! is_dir( $packages_dir ) ) { - WP_CLI::error( 'Invalid package name.' ); - } - } - WP_CLI::line( $packages_dir ); - } - - /** - * Update all installed WP-CLI packages to their latest version. - * - * ## EXAMPLES - * - * $ wp package update - * Using Composer to update packages... - * --- - * Loading composer repositories with package information - * Updating dependencies - * Resolving dependencies through SAT - * Dependency resolution completed in 0.074 seconds - * Analyzed 1062 packages to resolve dependencies - * Analyzed 22383 rules to resolve dependencies - * Writing lock file - * Generating autoload files - * --- - * Success: Packages updated. - */ - public function update() { - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - // Set up the EventSubscriber - $event_subscriber = new \WP_CLI\PackageManagerEventSubscriber; - $composer->getEventDispatcher()->addSubscriber( $event_subscriber ); - - // Set up the installer - $install = Installer::create( new ComposerIO, $composer ); - $install->setUpdate( true ); // Installer class will only override composer.lock with this flag - $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. - WP_CLI::log( 'Using Composer to update packages...' ); - WP_CLI::log( '---' ); - $res = false; - try { - $res = $install->run(); - } catch ( Exception $e ) { - WP_CLI::warning( $e->getMessage() ); - } - WP_CLI::log( '---' ); - - if ( 0 === $res ) { - WP_CLI::success( "Packages updated." ); - } else { - WP_CLI::error( "Failed to update packages (Composer return code {$res})." ); - } - } - - /** - * Uninstall a WP-CLI package. - * - * ## OPTIONS - * - * <name> - * : Name of the package to uninstall. - * - * ## EXAMPLES - * - * $ wp package uninstall wp-cli/server-command - * Removing require statement from /home/person/.wp-cli/packages/composer.json - * Deleting package directory /home/person/.wp-cli/packages/vendor/wp-cli/server-command - * Regenerating Composer autoload. - * Success: Uninstalled package. - */ - public function uninstall( $args ) { - list( $package_name ) = $args; - - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - if ( false === ( $package = $this->get_installed_package_by_name( $package_name ) ) ) { - WP_CLI::error( "Package not installed." ); - } - - $composer_json_obj = $this->get_composer_json(); - - // Remove the 'require' from composer.json - $json_path = $composer_json_obj->getPath(); - WP_CLI::log( sprintf( 'Removing require statement from %s', $json_path ) ); - $composer_backup = file_get_contents( $composer_json_obj->getPath() ); - $manipulator = new JsonManipulator( $composer_backup ); - $manipulator->removeSubNode( 'require', $package_name ); - file_put_contents( $composer_json_obj->getPath(), $manipulator->getContents() ); - - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - // Set up the installer - $install = Installer::create( new NullIO, $composer ); - $install->setUpdate( true ); // Installer class will only override composer.lock with this flag - $install->setPreferSource( true ); // Use VCS when VCS for easier contributions. - - WP_CLI::log( 'Removing package directories and regenerating autoloader...' ); - $res = false; - try { - $res = $install->run(); - } catch ( Exception $e ) { - WP_CLI::warning( $e->getMessage() ); - } - - if ( 0 === $res ) { - WP_CLI::success( "Uninstalled package." ); - } else { - file_put_contents( $composer_json_obj->getPath(), $composer_backup ); - WP_CLI::error( "Package removal failed (Composer return code {$res})." ); - } - } - - /** - * Check whether a package is a WP-CLI community package based - * on membership in our package index. - * - * @param object $package A package object - * @return bool - */ - private function is_community_package( $package ) { - return $this->package_index()->hasPackage( $package ); - } - - /** - * Get a Composer instance. - */ - private function get_composer() { - $composer_path = $this->get_composer_json_path(); - - // Composer's auto-load generating code makes some assumptions about where - // the 'vendor-dir' is, and where Composer is running from. - // Best to just pretend we're installing a package from ~/.wp-cli or similar - chdir( pathinfo( $composer_path, PATHINFO_DIRNAME ) ); - - // Prevent DateTime error/warning when no timezone set - date_default_timezone_set( @date_default_timezone_get() ); - - return Factory::create( new NullIO, $composer_path ); - } - - /** - * Get all of the community packages. - * - * @return array - */ - private function get_community_packages() { - static $community_packages; - - if ( null === $community_packages ) { - try { - $community_packages = $this->package_index()->getPackages(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - } - - return $community_packages; - } - - /** - * Get the package index instance - * - * We need to construct the instance manually, because there's no way to select - * a particular instance using $composer->getRepositoryManager() - * - * @return ComposerRepository - */ - private function package_index() { - static $package_index; - - if ( !$package_index ) { - $config = new Config(); - $config->merge( array( - 'config' => array( - 'secure-http' => true, - 'home' => dirname( $this->get_composer_json_path() ), - ) - )); - $config->setConfigSource( new JsonConfigSource( $this->get_composer_json() ) ); - - try { - $package_index = new ComposerRepository( array( 'url' => self::PACKAGE_INDEX_URL ), new NullIO, $config ); - } catch ( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - } - - return $package_index; - } - - /** - * Display a set of packages - * - * @param string $context - * @param array - * @param array - */ - private function show_packages( $context, $packages, $assoc_args ) { - if ( 'list' === $context ) { - $default_fields = array( - 'name', - 'authors', - 'version', - 'update', - 'update_version', - ); - } else if ( 'browse' === $context ) { - $default_fields = array( - 'name', - 'description', - 'authors', - 'version', - ); - } - $defaults = array( - 'fields' => implode( ',', $default_fields ), - 'format' => 'table' - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $list = array(); - foreach ( $packages as $package ) { - $name = $package->getName(); - if ( isset( $list[ $name ] ) ) { - $list[ $name ]['version'][] = $package->getPrettyVersion(); - } else { - $package_output = array(); - $package_output['name'] = $package->getName(); - $package_output['description'] = $package->getDescription(); - $package_output['authors'] = implode( ', ', array_column( (array) $package->getAuthors(), 'name' ) ); - $package_output['version'] = array( $package->getPrettyVersion() ); - $update = 'none'; - $update_version = ''; - if ( 'list' === $context ) { - $latest = $this->find_latest_package( $package, $this->get_composer(), null ); - if ( $latest && $latest->getFullPrettyVersion() !== $package->getFullPrettyVersion() ) { - $update = 'available'; - $update_version = $latest->getPrettyVersion(); - } - } - $package_output['update'] = $update; - $package_output['update_version'] = $update_version; - $list[ $package_output['name'] ] = $package_output; - } - } - - $list = array_map( function( $package ){ - $package['version'] = implode( ', ', $package['version'] ); - return $package; - }, $list ); - - ksort( $list ); - if ( 'ids' === $assoc_args['format'] ) { - $list = array_keys( $list ); - } - WP_CLI\Utils\format_items( $assoc_args['format'], $list, $assoc_args['fields'] ); - } - - /** - * Get a community package by its name. - */ - private function get_community_package_by_name( $package_name ) { - foreach( $this->get_community_packages() as $package ) { - if ( $package_name == $package->getName() ) { - return $package; - } - } - return false; - } - - /** - * Get the installed community packages. - */ - private function get_installed_packages() { - try { - $composer = $this->get_composer(); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - $repo = $composer->getRepositoryManager()->getLocalRepository(); - $installed_packages = array(); - $existing = json_decode( file_get_contents( $this->get_composer_json_path() ), true ); - $installed_package_keys = ! empty( $existing['require'] ) ? array_keys( $existing['require'] ) : array(); - if ( empty( $installed_package_keys ) ) { - return array(); - } - $installed_packages = array(); - foreach( $repo->getCanonicalPackages() as $package ) { - if ( in_array( $package->getName(), $installed_package_keys, true ) ) { - $installed_packages[] = $package; - } - } - return $installed_packages; - } - - /** - * Get an installed package by its name. - */ - private function get_installed_package_by_name( $package_name ) { - foreach( $this->get_installed_packages() as $package ) { - if ( $package_name == $package->getName() ) { - return $package; - } - } - return false; - } - - /** - * Check if the package name provided is already installed. - */ - private function is_package_installed( $package_name ) { - if ( $this->get_installed_package_by_name( $package_name ) ) { - return true; - } else { - return false; - } - } - - /** - * Get the name of the package from the composer.json in a directory path - * - * @param string $dir_package - * @return string - */ - private static function get_package_name_and_version_from_dir_package( $dir_package ) { - $composer_file = $dir_package . '/composer.json'; - $package_name = ''; - $version = 'dev-master'; - if ( file_exists( $composer_file ) ) { - $composer_data = json_decode( file_get_contents( $composer_file ), true ); - if ( ! empty( $composer_data['name'] ) ) { - $package_name = $composer_data['name']; - } - if ( ! empty( $composer_data['version'] ) ) { - $version = $composer_data['version']; - } - } - if ( empty( $package_name ) ) { - WP_CLI::error( "Invalid package." ); - } - return array( $package_name, $version ); - } - - /** - * Get the composer.json object - */ - private function get_composer_json() { - return new JsonFile( $this->get_composer_json_path() ); - } - - /** - * Get the path to composer.json - */ - private function get_composer_json_path() { - static $composer_path; - - if ( null === $composer_path ) { - - if ( getenv( 'WP_CLI_PACKAGES_DIR' ) ) { - $composer_path = rtrim( getenv( 'WP_CLI_PACKAGES_DIR' ), '/' ) . '/composer.json'; - } else { - $composer_path = getenv( 'HOME' ) . '/.wp-cli/packages/composer.json'; - } - - // `composer.json` and its directory might need to be created - if ( ! file_exists( $composer_path ) ) { - $this->create_default_composer_json( $composer_path ); - } - } - - return $composer_path; - } - - /** - * Get the WP-CLI version for composer.json - */ - private static function get_wp_cli_version_composer() { - preg_match( '#^[0-9\.]+(-(alpha|beta)[^-]{0,})?#', WP_CLI_VERSION, $matches ); - return isset( $matches[0] ) ? $matches[0] : ''; - } - - /** - * Create a default composer.json, should one not already exist - * - * @param string $composer_path Where the composer.json should be created - * @return true|WP_Error - */ - private function create_default_composer_json( $composer_path ) { - - $composer_dir = pathinfo( $composer_path, PATHINFO_DIRNAME ); - if ( ! is_dir( $composer_dir ) ) { - \WP_CLI\Process::create( WP_CLI\Utils\esc_cmd( 'mkdir -p %s', $composer_dir ) )->run(); - } - - if ( ! is_dir( $composer_dir ) ) { - WP_CLI::error( "Composer directory for packages couldn't be created." ); - } - - $json_file = new JsonFile( $composer_path ); - - $author = (object)array( - 'name' => 'WP-CLI', - 'email' => 'noreply@wpcli.org' - ); - - $repositories = (object)array( - 'wp-cli' => (object)array( - 'type' => 'composer', - 'url' => self::PACKAGE_INDEX_URL, - ), - ); - - $options = array( - 'name' => 'wp-cli/wp-cli', - 'description' => 'Installed community packages used by WP-CLI', - 'version' => self::get_wp_cli_version_composer(), - 'authors' => array( $author ), - 'homepage' => self::PACKAGE_INDEX_URL, - 'require' => new stdClass, - 'require-dev' => new stdClass, - 'minimum-stability' => 'dev', - 'license' => 'MIT', - 'repositories' => $repositories, - ); - - try { - $json_file->write( $options ); - } catch( Exception $e ) { - WP_CLI::error( $e->getMessage() ); - } - - return true; - } - - /** - * Given a package, this finds the latest package matching it - * - * @param PackageInterface $package - * @param Composer $composer - * @param string $phpVersion - * @param bool $minorOnly - * - * @return PackageInterface|null - */ - private function find_latest_package( PackageInterface $package, Composer $composer, $phpVersion, $minorOnly = false ) { - // find the latest version allowed in this pool - $name = $package->getName(); - $versionSelector = new VersionSelector($this->get_pool($composer)); - $stability = $composer->getPackage()->getMinimumStability(); - $flags = $composer->getPackage()->getStabilityFlags(); - if (isset($flags[$name])) { - $stability = array_search($flags[$name], BasePackage::$stabilities, true); - } - $bestStability = $stability; - if ($composer->getPackage()->getPreferStable()) { - $bestStability = $package->getStability(); - } - $targetVersion = null; - if (0 === strpos($package->getVersion(), 'dev-')) { - $targetVersion = $package->getVersion(); - } - if ($targetVersion === null && $minorOnly) { - $targetVersion = '^' . $package->getVersion(); - } - return $versionSelector->findBestCandidate($name, $targetVersion, $phpVersion, $bestStability); - } - - private function get_pool( Composer $composer ) { - if (!$this->pool) { - $this->pool = new Pool($composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags()); - $this->pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories())); - } - return $this->pool; - } -} - -WP_CLI::add_command( 'package', 'Package_Command' ); diff --git a/php/commands/plugin.php b/php/commands/plugin.php deleted file mode 100644 index def295062..000000000 --- a/php/commands/plugin.php +++ /dev/null @@ -1,993 +0,0 @@ -<?php - -use \WP_CLI\Utils; - -/** - * Manage plugins. - * - * ## EXAMPLES - * - * # Activate plugin - * $ wp plugin activate hello-dolly - * Plugin 'hello-dolly' activated. - * Success: Activated 1 of 1 plugins. - * - * # Deactivate plugin - * $ wp plugin deactivate hello-dolly - * Plugin 'hello-dolly' deactivated. - * Success: Deactivated 1 of 1 plugins. - * - * # Delete plugin - * $ wp plugin delete hello-dolly - * Deleted 'hello-dolly' plugin. - * Success: Deleted 1 of 1 plugins. - * - * # Install the latest version from wordpress.org and activate - * $ wp plugin install bbpress --activate - * Installing bbPress (2.5.9) - * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.2.5.9.zip... - * Using cached file '/home/vagrant/.wp-cli/cache/plugin/bbpress-2.5.9.zip'... - * Unpacking the package... - * Installing the plugin... - * Plugin installed successfully. - * Activating 'bbpress'... - * Plugin 'bbpress' activated. - * Success: Installed 1 of 1 plugins. - * - * @package wp-cli - */ -class Plugin_Command extends \WP_CLI\CommandWithUpgrade { - - protected $item_type = 'plugin'; - protected $upgrade_refresh = 'wp_update_plugins'; - protected $upgrade_transient = 'update_plugins'; - - protected $obj_fields = array( - 'name', - 'status', - 'update', - 'version' - ); - - function __construct() { - require_once ABSPATH.'wp-admin/includes/plugin.php'; - require_once ABSPATH.'wp-admin/includes/plugin-install.php'; - - parent::__construct(); - - $this->fetcher = new \WP_CLI\Fetchers\Plugin; - } - - protected function get_upgrader_class( $force ) { - return $force ? '\\WP_CLI\\DestructivePluginUpgrader' : 'Plugin_Upgrader'; - } - - /** - * See the status of one or all plugins. - * - * ## OPTIONS - * - * [<plugin>] - * : A particular plugin to show the status for. - * - * ## EXAMPLES - * - * # Displays status of all plugins - * $ wp plugin status - * 5 installed plugins: - * I akismet 3.1.11 - * I easy-digital-downloads 2.5.16 - * A theme-check 20160523.1 - * I wen-logo-slider 2.0.3 - * M ns-pack 1.0.0 - * Legend: I = Inactive, A = Active, M = Must Use - * - * # Displays status of a plugin - * $ wp plugin status theme-check - * Plugin theme-check details: - * Name: Theme Check - * Status: Active - * Version: 20160523.1 - * Author: Otto42, pross - * Description: A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool! - */ - public function status( $args ) { - parent::status( $args ); - } - - /** - * Search the WordPress.org plugin directory. - * - * Displays plugins in the WordPress.org plugin directory matching a given - * search query. - * - * ## OPTIONS - * - * <search> - * : The string to search for. - * - * [--page=<page>] - * : Optional page to display. - * --- - * default: 1 - * --- - * - * [--per-page=<per-page>] - * : Optional number of results to display. - * --- - * default: 10 - * --- - * - * [--field=<field>] - * : Prints the value of a single field for each plugin. - * - * [--fields=<fields>] - * : Ask for specific fields from the API. Defaults to name,slug,author_profile,rating. Acceptable values: - * - * **name**: Plugin Name - * **slug**: Plugin Slug - * **version**: Current Version Number - * **author**: Plugin Author - * **author_profile**: Plugin Author Profile - * **contributors**: Plugin Contributors - * **requires**: Plugin Minimum Requirements - * **tested**: Plugin Tested Up To - * **compatibility**: Plugin Compatible With - * **rating**: Plugin Rating - * **num_ratings**: Number of Plugin Ratings - * **homepage**: Plugin Author's Homepage - * **description**: Plugin's Description - * **short_description**: Plugin's Short Description - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - count - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp plugin search dsgnwrks --per-page=20 --format=json - * Success: Showing 3 of 3 plugins. - * [{"name":"DsgnWrks Instagram Importer Debug","slug":"dsgnwrks-instagram-importer-debug","rating":0},{"name":"DsgnWrks Instagram Importer","slug":"dsgnwrks-instagram-importer","rating":84},{"name":"DsgnWrks Twitter Importer","slug":"dsgnwrks-twitter-importer","rating":80}] - * - * $ wp plugin search dsgnwrks --fields=name,version,slug,rating,num_ratings - * Success: Showing 3 of 3 plugins. - * +-----------------------------------+---------+-----------------------------------+--------+-------------+ - * | name | version | slug | rating | num_ratings | - * +-----------------------------------+---------+-----------------------------------+--------+-------------+ - * | DsgnWrks Instagram Importer Debug | 0.1.6 | dsgnwrks-instagram-importer-debug | 0 | 0 | - * | DsgnWrks Instagram Importer | 1.3.7 | dsgnwrks-instagram-importer | 84 | 23 | - * | DsgnWrks Twitter Importer | 1.1.1 | dsgnwrks-twitter-importer | 80 | 1 | - * +-----------------------------------+---------+-----------------------------------+--------+-------------+ - */ - public function search( $args, $assoc_args ) { - parent::_search( $args, $assoc_args ); - } - - protected function status_single( $args ) { - $plugin = $this->fetcher->get_check( $args[0] ); - $file = $plugin->file; - - $details = $this->get_details( $file ); - - $status = $this->format_status( $this->get_status( $file ), 'long' ); - - $version = $details['Version']; - - if ( $this->has_update( $file ) ) - $version .= ' (%gUpdate available%n)'; - - echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'plugin-status.mustache', array( - 'slug' => Utils\get_plugin_name( $file ), - 'status' => $status, - 'version' => $version, - 'name' => $details['Name'], - 'author' => $details['Author'], - 'description' => $details['Description'] - ) ) ); - } - - protected function get_all_items() { - $items = $this->get_item_list(); - - foreach ( get_mu_plugins() as $file => $mu_plugin ) { - $mu_version = ''; - if ( ! empty( $mu_plugin['Version'] ) ) { - $mu_version = $mu_plugin['Version']; - } - - $items[ $file ] = array( - 'name' => Utils\get_plugin_name( $file ), - 'status' => 'must-use', - 'update' => false, - 'update_version' => NULL, - 'update_package' => NULL, - 'version' => $mu_version, - 'update_id' => '', - 'title' => '', - 'description' => '', - ); - } - - return $items; - } - - /** - * Activate a plugin. - * - * ## OPTIONS - * - * [<plugin>...] - * : One or more plugins to activate. - * - * [--all] - * : If set, all plugins will be activated. - * - * [--network] - * : If set, the plugin will be activated for the entire multisite network. - * - * ## EXAMPLES - * - * # Activate plugin - * $ wp plugin activate hello-dolly - * Plugin 'hello-dolly' activated. - * Success: Activated 1 of 1 plugins. - * - * # Activate plugin in entire multisite network - * $ wp plugin activate hello-dolly --network - * Plugin 'hello-dolly' network activated. - * Success: Network activated 1 of 1 plugins. - */ - public function activate( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); - $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); - - if ( $all ) { - $args = array_map( function( $file ){ - return Utils\get_plugin_name( $file ); - }, array_keys( get_plugins() ) ); - } - - $successes = $errors = 0; - $plugins = $this->fetcher->get_many( $args ); - if ( count( $plugins ) < count( $args ) ) { - $errors = count( $args ) - count( $plugins ); - } - foreach ( $plugins as $plugin ) { - $status = $this->get_status( $plugin->file ); - if ( $all && in_array( $status, array( 'active', 'active-network' ) ) ) { - continue; - } - // Network-active is the highest level of activation status - if ( 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); - continue; - } - // Don't reactivate active plugins, but do let them become network-active - if ( ! $network_wide && 'active' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); - continue; - } - - // Plugins need to be deactivated before being network activated - if ( $network_wide && 'active' === $status ) { - deactivate_plugins( $plugin->file, false, false ); - } - - activate_plugin( $plugin->file, '', $network_wide ); - - $this->active_output( $plugin->name, $plugin->file, $network_wide, 'activate' ); - $successes++; - } - - if ( ! $this->chained_command ) { - $verb = $network_wide ? 'network activate' : 'activate'; - Utils\report_batch_operation_results( 'plugin', $verb, count( $args ), $successes, $errors ); - } - - } - - /** - * Deactivate a plugin. - * - * ## OPTIONS - * - * [<plugin>...] - * : One or more plugins to deactivate. - * - * [--uninstall] - * : Uninstall the plugin after deactivation. - * - * [--all] - * : If set, all plugins will be deactivated. - * - * [--network] - * : If set, the plugin will be deactivated for the entire multisite network. - * - * ## EXAMPLES - * - * # Deactivate plugin - * $ wp plugin deactivate hello-dolly - * Plugin 'hello-dolly' deactivated. - * Success: Deactivated 1 of 1 plugins. - */ - public function deactivate( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); - $disable_all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); - - if ( $disable_all ) { - $args = array_map( function( $file ){ - return Utils\get_plugin_name( $file ); - }, array_keys( get_plugins() ) ); - } - - $successes = $errors = 0; - $plugins = $this->fetcher->get_many( $args ); - if ( count( $plugins ) < count( $args ) ) { - $errors = count( $args ) - count( $plugins ); - } - - foreach ( $plugins as $plugin ) { - - $status = $this->get_status( $plugin->file ); - if ( $disable_all && ! in_array( $status, array( 'active', 'active-network' ) ) ) { - continue; - } - - // Network active plugins must be explicitly deactivated - if ( ! $network_wide && 'active-network' === $status ) { - WP_CLI::warning( "Plugin '{$plugin->name}' is network active and must be deactivated with --network flag." ); - $errors++; - continue; - } - - if ( ! in_array( $status, array( 'active', 'active-network' ) ) ) { - WP_CLI::warning( "Plugin '{$plugin->name}' isn't active." ); - continue; - } - - deactivate_plugins( $plugin->file, false, $network_wide ); - - if ( ! is_network_admin() ) { - update_option( 'recently_activated', - array( $plugin->file => time() ) + (array) get_option( 'recently_activated' ) ); - } else { - update_site_option( 'recently_activated', - array( $plugin->file => time() ) + (array) get_site_option( 'recently_activated' ) ); - } - - $this->active_output( $plugin->name, $plugin->file, $network_wide, 'deactivate' ); - $successes++; - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uninstall' ) ) { - WP_CLI::log( "Uninstalling '{$plugin->name}'..." ); - $this->chained_command = true; - $this->uninstall( array( $plugin->name ) ); - $this->chained_command = false; - } - - } - - if ( ! $this->chained_command ) { - $verb = $network_wide ? 'network deactivate' : 'deactivate'; - Utils\report_batch_operation_results( 'plugin', $verb, count( $args ), $successes, $errors ); - } - - } - - /** - * Toggle a plugin's activation state. - * - * If the plugin is active, then it will be deactivated. If the plugin is - * inactive, then it will be activated. - * - * ## OPTIONS - * - * <plugin>... - * : One or more plugins to toggle. - * - * [--network] - * : If set, the plugin will be toggled for the entire multisite network. - * - * ## EXAMPLES - * - * # Akismet is currently activated - * $ wp plugin toggle akismet - * Plugin 'akismet' deactivated. - * Success: Toggled 1 of 1 plugins. - * - * # Akismet is currently deactivated - * $ wp plugin toggle akismet - * Plugin 'akismet' activated. - * Success: Toggled 1 of 1 plugins. - */ - public function toggle( $args, $assoc_args = array() ) { - $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ); - - $successes = $errors = 0; - $plugins = $this->fetcher->get_many( $args ); - if ( count( $plugins ) < count( $args ) ) { - $errors = count( $args ) - count( $plugins ); - } - $this->chained_command = true; - foreach ( $plugins as $plugin ) { - if ( $this->check_active( $plugin->file, $network_wide ) ) { - $this->deactivate( array( $plugin->name ), $assoc_args ); - } else { - $this->activate( array( $plugin->name ), $assoc_args ); - } - $successes++; - } - $this->chained_command = false; - Utils\report_batch_operation_results( 'plugin', 'toggle', count( $args ), $successes, $errors ); - } - - /** - * Get the path to a plugin or to the plugin directory. - * - * ## OPTIONS - * - * [<plugin>] - * : The plugin to get the path to. If not set, will return the path to the - * plugins directory. - * - * [--dir] - * : If set, get the path to the closest parent directory, instead of the - * plugin file. - * - * ## EXAMPLES - * - * $ cd $(wp plugin path) && pwd - * /var/www/wordpress/wp-content/plugins - */ - public function path( $args, $assoc_args ) { - $path = untrailingslashit( WP_PLUGIN_DIR ); - - if ( !empty( $args ) ) { - $plugin = $this->fetcher->get_check( $args[0] ); - $path .= '/' . $plugin->file; - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'dir' ) ) - $path = dirname( $path ); - } - - WP_CLI::line( $path ); - } - - protected function install_from_repo( $slug, $assoc_args ) { - $api = plugins_api( 'plugin_information', array( 'slug' => $slug ) ); - - if ( is_wp_error( $api ) ) { - return $api; - } - - if ( isset( $assoc_args['version'] ) ) { - self::alter_api_response( $api, $assoc_args['version'] ); - } - - $status = install_plugin_install_status( $api ); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) && 'install' != $status['status'] ) { - // We know this will fail, so avoid a needless download of the package. - return new WP_Error( 'already_installed', 'Plugin already installed.' ); - } - - WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) != 'dev' ) { - WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); - } - $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - - return $result; - } - - /** - * Update one or more plugins. - * - * ## OPTIONS - * - * [<plugin>...] - * : One or more plugins to update. - * - * [--all] - * : If set, all plugins that have updates will be updated. - * - * [--format=<format>] - * : Output summary as table or summary. Defaults to table. - * - * [--version=<version>] - * : If set, the plugin will be updated to the specified version. - * - * [--dry-run] - * : Preview which plugins would be updated. - * - * ## EXAMPLES - * - * $ wp plugin update bbpress --version=dev - * Installing bbPress (Development Version) - * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.zip... - * Unpacking the package... - * Installing the plugin... - * Removing the old version of the plugin... - * Plugin updated successfully. - * Success: Updated 1 of 2 plugins. - * - * $ wp plugin update --all - * Enabling Maintenance mode... - * Downloading update from https://downloads.wordpress.org/plugin/akismet.3.1.11.zip... - * Unpacking the update... - * Installing the latest version... - * Removing the old version of the plugin... - * Plugin updated successfully. - * Downloading update from https://downloads.wordpress.org/plugin/nginx-champuru.3.2.0.zip... - * Unpacking the update... - * Installing the latest version... - * Removing the old version of the plugin... - * Plugin updated successfully. - * Disabling Maintenance mode... - * +------------------------+-------------+-------------+---------+ - * | name | old_version | new_version | status | - * +------------------------+-------------+-------------+---------+ - * | akismet | 3.1.3 | 3.1.11 | Updated | - * | nginx-cache-controller | 3.1.1 | 3.2.0 | Updated | - * +------------------------+-------------+-------------+---------+ - * Success: Updated 2 of 2 plugins. - * - * @alias upgrade - */ - function update( $args, $assoc_args ) { - if ( isset( $assoc_args['version'] ) ) { - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - $assoc_args['force'] = 1; - $this->install( array( $plugin->name ), $assoc_args ); - } - } else { - parent::update_many( $args, $assoc_args ); - } - } - - protected function get_item_list() { - $items = $duplicate_names = array(); - - foreach ( get_plugins() as $file => $details ) { - $update_info = $this->get_update_info( $file ); - - $name = Utils\get_plugin_name( $file ); - if ( ! isset( $duplicate_names[ $name ] ) ) { - $duplicate_names[ $name ] = array(); - } - $duplicate_names[ $name ][] = $file; - $items[ $file ] = array( - 'name' => $name, - 'status' => $this->get_status( $file ), - 'update' => (bool) $update_info, - 'update_version' => $update_info['new_version'], - 'update_package' => $update_info['package'], - 'version' => $details['Version'], - 'update_id' => $file, - 'title' => $details['Name'], - 'description' => $details['Description'], - ); - } - - foreach( $duplicate_names as $name => $files ) { - if ( count( $files ) <= 1 ) { - continue; - } - foreach( $files as $file ) { - $items[ $file ]['name'] = str_replace( '.' . pathinfo( $file, PATHINFO_EXTENSION ), '', $file ); - } - } - - return $items; - } - - protected function filter_item_list( $items, $args ) { - $basenames = wp_list_pluck( $this->fetcher->get_many( $args ), 'file' ); - return \WP_CLI\Utils\pick_fields( $items, $basenames ); - } - - /** - * Install a plugin. - * - * ## OPTIONS - * - * <plugin|zip|url>... - * : A plugin slug, the path to a local zip file, or URL to a remote zip file. - * - * [--version=<version>] - * : If set, get that particular version from wordpress.org, instead of the - * stable version. - * - * [--force] - * : If set, the command will overwrite any installed version of the plugin, without prompting - * for confirmation. - * - * [--activate] - * : If set, the plugin will be activated immediately after install. - * - * [--activate-network] - * : If set, the plugin will be network activated immediately after install - * - * ## EXAMPLES - * - * # Install the latest version from wordpress.org and activate - * $ wp plugin install bbpress --activate - * Installing bbPress (2.5.9) - * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.2.5.9.zip... - * Using cached file '/home/vagrant/.wp-cli/cache/plugin/bbpress-2.5.9.zip'... - * Unpacking the package... - * Installing the plugin... - * Plugin installed successfully. - * Activating 'bbpress'... - * Plugin 'bbpress' activated. - * Success: Installed 1 of 1 plugins. - * - * # Install the development version from wordpress.org - * $ wp plugin install bbpress --version=dev - * Installing bbPress (Development Version) - * Downloading install package from https://downloads.wordpress.org/plugin/bbpress.zip... - * Unpacking the package... - * Installing the plugin... - * Plugin installed successfully. - * Success: Installed 1 of 1 plugins. - * - * # Install from a local zip file - * $ wp plugin install ../my-plugin.zip - * Unpacking the package... - * Installing the plugin... - * Plugin installed successfully. - * Success: Installed 1 of 1 plugins. - * - * # Install from a remote zip file - * $ wp plugin install http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef - * Downloading install package from http://s3.amazonaws.com/bucketname/my-plugin.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef - * Unpacking the package... - * Installing the plugin... - * Plugin installed successfully. - * Success: Installed 1 of 1 plugins. - * - * # Update from a remote zip file - * $ wp plugin install https://github.com/envato/wp-envato-market/archive/master.zip --force - * Downloading install package from https://github.com/envato/wp-envato-market/archive/master.zip - * Unpacking the package... - * Installing the plugin... - * Renamed Github-based project from 'wp-envato-market-master' to 'wp-envato-market'. - * Plugin updated successfully - * Success: Installed 1 of 1 plugins. - * - * # Forcefully re-install all installed plugins - * $ wp plugin install $(wp plugin list --field=name) --force - * Installing Akismet (3.1.11) - * Downloading install package from https://downloads.wordpress.org/plugin/akismet.3.1.11.zip... - * Unpacking the package... - * Installing the plugin... - * Removing the old version of the plugin... - * Plugin updated successfully - * Success: Installed 1 of 1 plugins. - */ - public function install( $args, $assoc_args ) { - - if ( ! is_dir( WP_PLUGIN_DIR ) ) { - wp_mkdir_p( WP_PLUGIN_DIR ); - } - - parent::install( $args, $assoc_args ); - } - - /** - * Get details about an installed plugin. - * - * ## OPTIONS - * - * <plugin> - * : The plugin to get. - * - * [--field=<field>] - * : Instead of returning the whole plugin, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp plugin get bbpress --format=json - * {"name":"bbpress","title":"bbPress","author":"The bbPress Contributors","version":"2.6-alpha","description":"bbPress is forum software with a twist from the creators of WordPress.","status":"active"} - */ - public function get( $args, $assoc_args ) { - $plugin = $this->fetcher->get_check( $args[0] ); - $file = $plugin->file; - - $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); - - $plugin_obj = (object)array( - 'name' => Utils\get_plugin_name( $file ), - 'title' => $plugin_data['Name'], - 'author' => $plugin_data['Author'], - 'version' => $plugin_data['Version'], - 'description' => wordwrap( $plugin_data['Description'] ), - 'status' => $this->get_status( $file ), - ); - - if ( empty( $assoc_args['fields'] ) ) { - $plugin_array = get_object_vars( $plugin_obj ); - $assoc_args['fields'] = array_keys( $plugin_array ); - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $plugin_obj ); - } - - /** - * Uninstall a plugin. - * - * ## OPTIONS - * - * <plugin>... - * : One or more plugins to uninstall. - * - * [--deactivate] - * : Deactivate the plugin before uninstalling. Default behavior is to warn and skip if the plugin is active. - * - * [--skip-delete] - * : If set, the plugin files will not be deleted. Only the uninstall procedure - * will be run. - * - * ## EXAMPLES - * - * $ wp plugin uninstall hello - * Uninstalled and deleted 'hello' plugin. - * Success: Installed 1 of 1 plugins. - */ - public function uninstall( $args, $assoc_args = array() ) { - $successes = $errors = 0; - $plugins = $this->fetcher->get_many( $args ); - foreach ( $plugins as $plugin ) { - if ( is_plugin_active( $plugin->file ) && ! WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { - WP_CLI::warning( "The '{$plugin->name}' plugin is active." ); - $errors++; - continue; - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'deactivate' ) ) { - WP_CLI::log( "Deactivating '{$plugin->name}'..." ); - $this->chained_command = true; - $this->deactivate( array( $plugin->name ) ); - $this->chained_command = false; - } - - uninstall_plugin( $plugin->file ); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-delete' ) && $this->_delete( $plugin ) ) { - WP_CLI::log( "Uninstalled and deleted '$plugin->name' plugin." ); - } else { - WP_CLI::log( "Ran uninstall procedure for '$plugin->name' plugin without deleting." ); - } - $successes++; - } - if ( ! $this->chained_command ) { - Utils\report_batch_operation_results( 'plugin', 'uninstall', count( $args ), $successes, $errors ); - } - } - - /** - * Check if the plugin is installed. - * - * Returns exit code 0 when installed, 1 when uninstalled. - * - * ## OPTIONS - * - * <plugin> - * : The plugin to check. - * - * ## EXAMPLES - * - * # Check whether plugin is installed; exit status 0 if installed, otherwise 1 - * $ wp plugin is-installed hello-dolly - * $ echo $? - * 1 - * - * @subcommand is-installed - */ - public function is_installed( $args, $assoc_args = array() ) { - if ( $this->fetcher->get( $args[0] ) ) { - WP_CLI::halt( 0 ); - } else { - WP_CLI::halt( 1 ); - } - } - - /** - * Delete plugin files without deactivating or uninstalling. - * - * ## OPTIONS - * - * <plugin>... - * : One or more plugins to delete. - * - * ## EXAMPLES - * - * # Delete plugin - * $ wp plugin delete hello - * Deleted 'hello' plugin. - * Success: Deleted 1 of 1 plugins. - * - * # Delete inactive plugins - * $ wp plugin delete $(wp plugin list --status=inactive --field=name) - * Deleted 'tinymce-templates' plugin. - * Success: Deleted 1 of 1 plugins. - */ - public function delete( $args, $assoc_args = array() ) { - $successes = $errors = 0; - foreach ( $this->fetcher->get_many( $args ) as $plugin ) { - if ( $this->_delete( $plugin ) ) { - WP_CLI::log( "Deleted '{$plugin->name}' plugin." ); - $successes++; - } else { - $errors++; - } - } - if ( ! $this->chained_command ) { - Utils\report_batch_operation_results( 'plugin', 'delete', count( $args ), $successes, $errors ); - } - } - - /** - * Get a list of plugins. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : Filter results based on the value of a field. - * - * [--field=<field>] - * : Prints the value of a single field for each plugin. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - count - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each plugin: - * - * * name - * * status - * * update - * * version - * - * These fields are optionally available: - * - * * update_version - * * update_package - * * update_id - * * title - * * description - * - * ## EXAMPLES - * - * # List active plugins on the site. - * $ wp plugin list --status=active --format=json - * [{"name":"dynamic-hostname","status":"active","update":"none","version":"0.4.2"},{"name":"tinymce-templates","status":"active","update":"none","version":"4.4.3"},{"name":"wp-multibyte-patch","status":"active","update":"none","version":"2.4"},{"name":"wp-total-hacks","status":"active","update":"none","version":"2.0.1"}] - * - * # List plugins on each site in a network. - * $ wp site list --field=url | xargs -I % wp plugin list --url=% - * +---------+----------------+--------+---------+ - * | name | status | update | version | - * +---------+----------------+--------+---------+ - * | akismet | active-network | none | 3.1.11 | - * | hello | inactive | none | 1.6 | - * +---------+----------------+--------+---------+ - * +---------+----------------+--------+---------+ - * | name | status | update | version | - * +---------+----------------+--------+---------+ - * | akismet | active-network | none | 3.1.11 | - * | hello | inactive | none | 1.6 | - * +---------+----------------+--------+---------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - parent::_list( $_, $assoc_args ); - } - - /* PRIVATES */ - - private function check_active( $file, $network_wide ) { - $required = $network_wide ? 'active-network' : 'active'; - - return $required == $this->get_status( $file ); - } - - private function active_output( $name, $file, $network_wide, $action ) { - $network_wide = $network_wide || ( is_multisite() && is_network_only_plugin( $file ) ); - - $check = $this->check_active( $file, $network_wide ); - - if ( ( $action == "activate" ) ? $check : ! $check ) { - if ( $network_wide ) - WP_CLI::log( "Plugin '{$name}' network {$action}d." ); - else - WP_CLI::log( "Plugin '{$name}' {$action}d." ); - } else { - WP_CLI::warning( "Could not {$action} the '{$name}' plugin." ); - } - } - - protected function get_status( $file ) { - if ( is_plugin_active_for_network( $file ) ) - return 'active-network'; - - if ( is_plugin_active( $file ) ) - return 'active'; - - return 'inactive'; - } - - /** - * Get the details of a plugin. - * - * @param object - * @return array - */ - private function get_details( $file ) { - $plugin_folder = get_plugins( '/' . plugin_basename( dirname( $file ) ) ); - $plugin_file = Utils\basename( $file ); - - return $plugin_folder[$plugin_file]; - } - - private function _delete( $plugin ) { - $plugin_dir = dirname( $plugin->file ); - if ( '.' == $plugin_dir ) - $plugin_dir = $plugin->file; - - $path = path_join( WP_PLUGIN_DIR, $plugin_dir ); - - if ( \WP_CLI\Utils\is_windows() ) { - // Handles plugins that are not in own folders - // e.g. Hello Dolly -> plugins/hello.php - if ( is_file( $path ) ) { - $command = 'del /f /q '; - } else { - $command = 'rd /s /q '; - } - $path = str_replace( "/", "\\", $path ); - } else { - $command = 'rm -rf '; - } - - return ! WP_CLI::launch( $command . $path ); - } -} - -WP_CLI::add_command( 'plugin', 'Plugin_Command' ); diff --git a/php/commands/post-meta.php b/php/commands/post-meta.php deleted file mode 100644 index 868fbb9be..000000000 --- a/php/commands/post-meta.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -/** - * Manage post custom fields. - * - * ## EXAMPLES - * - * # Set post meta - * $ wp post meta set 123 _wp_page_template about.php - * Success: Updated custom field '_wp_page_template'. - * - * # Get post meta - * $ wp post meta get 123 _wp_page_template - * about.php - * - * # Update post meta - * $ wp post meta update 123 _wp_page_template contact.php - * Success: Updated custom field '_wp_page_template'. - * - * # Delete post meta - * $ wp post meta delete 123 _wp_page_template - * Success: Deleted custom field. - */ -class Post_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'post'; - - /** - * Check that the post ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $fetcher = new \WP_CLI\Fetchers\Post; - $post = $fetcher->get_check( $object_id ); - return $post->ID; - } -} - -WP_CLI::add_command( 'post meta', 'Post_Meta_Command' ); diff --git a/php/commands/post-term.php b/php/commands/post-term.php deleted file mode 100644 index 6ca2f49af..000000000 --- a/php/commands/post-term.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -/** - * Manage post terms. - * - * ## EXAMPLES - * - * # Set post terms - * $ wp post term set 123 test category - * Success: Set terms. - */ -class Post_Term_Command extends \WP_CLI\CommandWithTerms { - protected $obj_type = 'post'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\Post; - } - - protected function get_object_type() { - $post = $this->fetcher->get_check( $this->get_obj_id() ); - - return $post->post_type; - } -} - -WP_CLI::add_command( 'post term', 'Post_Term_Command' ); diff --git a/php/commands/post-type.php b/php/commands/post-type.php deleted file mode 100644 index 4159c52ab..000000000 --- a/php/commands/post-type.php +++ /dev/null @@ -1,173 +0,0 @@ -<?php -/** - * Manage post types. - * - * ## EXAMPLES - * - * # Get details about a post type - * $ wp post-type get page --fields=name,label,hierarchical --format=json - * {"name":"page","label":"Pages","hierarchical":true} - * - * # List post types with 'post' capability type - * $ wp post-type list --capability_type=post --fields=name,public - * +---------------+--------+ - * | name | public | - * +---------------+--------+ - * | post | 1 | - * | attachment | 1 | - * | revision | | - * | nav_menu_item | | - * +---------------+--------+ - * - * @package wp-cli - */ -class Post_Type_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'label', - 'description', - 'hierarchical', - 'public', - 'capability_type', - ); - - /** - * List registered post types. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : Filter by one or more fields (see get_post_types() first parameter for a list of available fields). - * - * [--field=<field>] - * : Prints the value of a single field for each post type. - * - * [--fields=<fields>] - * : Limit the output to specific post type fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each term: - * - * * name - * * label - * * description - * * hierarchical - * * public - * * capability_type - * - * There are no optionally available fields. - * - * ## EXAMPLES - * - * # List registered post types - * $ wp post-type list --format=csv - * name,label,description,hierarchical,public,capability_type - * post,Posts,,,1,post - * page,Pages,,1,1,page - * attachment,Media,,,1,post - * revision,Revisions,,,,post - * nav_menu_item,"Navigation Menu Items",,,,post - * - * # List post types with 'post' capability type - * $ wp post-type list --capability_type=post --fields=name,public - * +---------------+--------+ - * | name | public | - * +---------------+--------+ - * | post | 1 | - * | attachment | 1 | - * | revision | | - * | nav_menu_item | | - * +---------------+--------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $types = get_post_types( $assoc_args, 'objects' ); - - $formatter->display_items( $types ); - } - - /** - * Get details about a registered post type. - * - * ## OPTIONS - * - * <post-type> - * : Post type slug - * - * [--field=<field>] - * : Instead of returning the whole taxonomy, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get details about the 'page' post type. - * $ wp post-type get page --fields=name,label,hierarchical --format=json - * {"name":"page","label":"Pages","hierarchical":true} - */ - public function get( $args, $assoc_args ) { - $post_type = get_post_type_object( $args[0] ); - - if ( ! $post_type ) { - WP_CLI::error( "Post type {$args[0]} doesn't exist." ); - } - - if ( empty( $assoc_args['fields'] ) ) { - $default_fields = array_merge( $this->fields, array( - 'labels', - 'cap' - ) ); - - $assoc_args['fields'] = $default_fields; - } - - $data = array( - 'name' => $post_type->name, - 'label' => $post_type->label, - 'description' => $post_type->description, - 'hierarchical' => $post_type->hierarchical, - 'public' => $post_type->public, - 'capability_type' => $post_type->capability_type, - 'labels' => $post_type->labels, - 'cap' => $post_type->cap, - ); - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $data ); - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'post-type' ); - } -} - -WP_CLI::add_command( 'post-type', 'Post_Type_Command' ); diff --git a/php/commands/post.php b/php/commands/post.php deleted file mode 100644 index 15746263e..000000000 --- a/php/commands/post.php +++ /dev/null @@ -1,595 +0,0 @@ -<?php - -/** - * Manage posts. - * - * ## EXAMPLES - * - * # Create a new post. - * $ wp post create --post_type=post --post_title='A sample post' - * Success: Created post 123. - * - * # Update an existing post. - * $ wp post update 123 --post_status=draft - * Success: Updated post 123. - * - * # Delete an existing post. - * $ wp post delete 123 - * Success: Trashed post 123. - * - * @package wp-cli - */ -class Post_Command extends \WP_CLI\CommandWithDBObject { - - protected $obj_type = 'post'; - protected $obj_fields = array( - 'ID', - 'post_title', - 'post_name', - 'post_date', - 'post_status' - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\Post; - } - - /** - * Create a new post. - * - * ## OPTIONS - * - * [<file>] - * : Read post content from <file>. If this value is present, the - * `--post_content` argument will be ignored. - * - * Passing `-` as the filename will cause post content to - * be read from STDIN. - * - * [--<field>=<value>] - * : Associative args for the new post. See wp_insert_post(). - * - * [--edit] - * : Immediately open system's editor to write or edit post content. - * - * If content is read from a file, from STDIN, or from the `--post_content` - * argument, that text will be loaded into the editor. - * - * [--porcelain] - * : Output just the new post id. - * - * ## EXAMPLES - * - * # Create post and schedule for future - * $ wp post create --post_type=page --post_title='A future post' --post_status=future --post_date='2020-12-01 07:00:00' - * Success: Created post 1921. - * - * # Create post with content from given file - * $ wp post create ./post-content.txt --post_category=201,345 --post_title='Post from file' - * Success: Created post 1922. - */ - public function create( $args, $assoc_args ) { - if ( ! empty( $args[0] ) ) { - $assoc_args['post_content'] = $this->read_from_file_or_stdin( $args[0] ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'edit' ) ) { - $input = \WP_CLI\Utils\get_flag_value( $assoc_args, 'post_content', '' ); - - if ( $output = $this->_edit( $input, 'WP-CLI: New Post' ) ) - $assoc_args['post_content'] = $output; - else - $assoc_args['post_content'] = $input; - } - - if ( isset( $assoc_args['post_category'] ) ) { - $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); - } - - $assoc_args = wp_slash( $assoc_args ); - parent::_create( $args, $assoc_args, function ( $params ) { - return wp_insert_post( $params, true ); - } ); - } - - /** - * Update one or more existing posts. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of posts to update. - * - * [<file>] - * : Read post content from <file>. If this value is present, the - * `--post_content` argument will be ignored. - * - * Passing `-` as the filename will cause post content to - * be read from STDIN. - * - * --<field>=<value> - * : One or more fields to update. See wp_update_post(). - * - * [--defer-term-counting] - * : Recalculate term count in batch, for a performance boost. - * - * ## EXAMPLES - * - * $ wp post update 123 --post_name=something --post_status=draft - * Success: Updated post 123. - */ - public function update( $args, $assoc_args ) { - - foreach( $args as $key => $arg ) { - if ( is_numeric( $arg ) ) { - continue; - } - - $assoc_args['post_content'] = $this->read_from_file_or_stdin( $arg ); - unset( $args[ $key ] ); - break; - } - - if ( isset( $assoc_args['post_category'] ) ) { - $assoc_args['post_category'] = explode( ',', $assoc_args['post_category'] ); - } - - $assoc_args = wp_slash( $assoc_args ); - parent::_update( $args, $assoc_args, function ( $params ) { - return wp_update_post( $params, true ); - } ); - } - - /** - * Launch system editor to edit post content. - * - * ## OPTIONS - * - * <id> - * : The ID of the post to edit. - * - * ## EXAMPLES - * - * # Launch system editor to edit post - * $ wp post edit 123 - */ - public function edit( $args, $_ ) { - $post = $this->fetcher->get_check( $args[0] ); - - $r = $this->_edit( $post->post_content, "WP-CLI post {$post->ID}" ); - - if ( $r === false ) - \WP_CLI::warning( 'No change made to post content.', 'Aborted' ); - else - $this->update( $args, array( 'post_content' => $r ) ); - } - - protected function _edit( $content, $title ) { - $content = apply_filters( 'the_editor_content', $content ); - $output = \WP_CLI\Utils\launch_editor_for_input( $content, $title ); - return ( is_string( $output ) ) ? - apply_filters( 'content_save_pre', $output ) : $output; - } - - /** - * Get details about a post. - * - * ## OPTIONS - * - * <id> - * : The ID of the post to get. - * - * [--field=<field>] - * : Instead of returning the whole post, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Save the post content to a file - * $ wp post get 123 --field=content > file.txt - */ - public function get( $args, $assoc_args ) { - $post = $this->fetcher->get_check( $args[0] ); - - $post_arr = get_object_vars( $post ); - unset( $post_arr['filter'] ); - - if ( empty( $assoc_args['fields'] ) ) { - $assoc_args['fields'] = array_keys( $post_arr ); - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $post_arr ); - } - - /** - * Delete an existing post. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of posts to delete. - * - * [--force] - * : Skip the trash bin. - * - * [--defer-term-counting] - * : Recalculate term count in batch, for a performance boost. - * - * ## EXAMPLES - * - * # Delete post skipping trash - * $ wp post delete 123 --force - * Success: Deleted post 123. - * - * # Delete all pages - * $ wp post delete $(wp post list --post_type='page' --format=ids) - * Success: Trashed post 1164. - * Success: Trashed post 1186. - * - * # Delete all posts in the trash - * $ wp post delete $(wp post list --post_status=trash --format=ids) - * Success: Trashed post 1268. - * Success: Trashed post 1294. - */ - public function delete( $args, $assoc_args ) { - $defaults = array( - 'force' => false - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - parent::_delete( $args, $assoc_args, function ( $post_id, $assoc_args ) { - $status = get_post_status( $post_id ); - $post_type = get_post_type( $post_id ); - $r = wp_delete_post( $post_id, $assoc_args['force'] ); - - if ( $r ) { - $action = $assoc_args['force'] || 'trash' === $status || 'revision' === $post_type ? 'Deleted' : 'Trashed'; - - return array( 'success', "$action post $post_id." ); - } else { - return array( 'error', "Failed deleting post $post_id." ); - } - } ); - } - - /** - * Get a list of posts. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : One or more args to pass to WP_Query. - * - * [--field=<field>] - * : Prints the value of a single field for each post. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each post: - * - * * ID - * * post_title - * * post_name - * * post_date - * * post_status - * - * These fields are optionally available: - * - * * post_author - * * post_date_gmt - * * post_content - * * post_excerpt - * * comment_status - * * ping_status - * * post_password - * * to_ping - * * pinged - * * post_modified - * * post_modified_gmt - * * post_content_filtered - * * post_parent - * * guid - * * menu_order - * * post_type - * * post_mime_type - * * comment_count - * * filter - * * url - * - * ## EXAMPLES - * - * # List post - * $ wp post list --field=ID - * 568 - * 829 - * 1329 - * 1695 - * - * # List posts in JSON - * $ wp post list --post_type=post --posts_per_page=5 --format=json - * [{"ID":1,"post_title":"Hello world!","post_name":"hello-world","post_date":"2015-06-20 09:00:10","post_status":"publish"},{"ID":1178,"post_title":"Markup: HTML Tags and Formatting","post_name":"markup-html-tags-and-formatting","post_date":"2013-01-11 20:22:19","post_status":"draft"}] - * - * # List all pages - * $ wp post list --post_type=page --fields=post_title,post_status - * +-------------+-------------+ - * | post_title | post_status | - * +-------------+-------------+ - * | Sample Page | publish | - * +-------------+-------------+ - * - * # List ids of all pages and posts - * $ wp post list --post_type=page,post --format=ids - * 15 25 34 37 198 - * - * # List given posts - * $ wp post list --post__in=1,3 - * +----+--------------+-------------+---------------------+-------------+ - * | ID | post_title | post_name | post_date | post_status | - * +----+--------------+-------------+---------------------+-------------+ - * | 3 | Lorem Ipsum | lorem-ipsum | 2016-06-01 14:34:36 | publish | - * | 1 | Hello world! | hello-world | 2016-06-01 14:31:12 | publish | - * +----+--------------+-------------+---------------------+-------------+ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - $defaults = array( - 'posts_per_page' => -1, - 'post_status' => 'any', - ); - $query_args = array_merge( $defaults, $assoc_args ); - $query_args = self::process_csv_arguments_to_arrays( $query_args ); - if ( isset( $query_args['post_type'] ) && 'any' !== $query_args['post_type'] ) { - $query_args['post_type'] = explode( ',', $query_args['post_type'] ); - } - - if ( 'ids' == $formatter->format ) { - $query_args['fields'] = 'ids'; - $query = new WP_Query( $query_args ); - echo implode( ' ', $query->posts ); - } else if ( 'count' === $formatter->format ) { - $query_args['fields'] = 'ids'; - $query = new WP_Query( $query_args ); - $formatter->display_items( $query->posts ); - } else { - $query = new WP_Query( $query_args ); - $posts = array_map( function( $post ) { - $post->url = get_permalink( $post->ID ); - return $post; - }, $query->posts ); - $formatter->display_items( $posts ); - } - } - - /** - * Generate some posts. - * - * Creates a specified number of new posts with dummy data. - * - * ## OPTIONS - * - * [--count=<number>] - * : How many posts to generate? - * --- - * default: 100 - * --- - * - * [--post_type=<type>] - * : The type of the generated posts. - * --- - * default: post - * --- - * - * [--post_status=<status>] - * : The status of the generated posts. - * --- - * default: publish - * --- - * - * [--post_author=<login>] - * : The author of the generated posts. - * --- - * default: - * --- - * - * [--post_date=<yyyy-mm-dd>] - * : The date of the generated posts. Default: current date - * - * [--post_content] - * : If set, the command reads the post_content from STDIN. - * - * [--max_depth=<number>] - * : For hierarchical post types, generate child posts down to a certain depth. - * --- - * default: 1 - * --- - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: progress - * options: - * - progress - * - ids - * --- - * - * ## EXAMPLES - * - * # Generate posts. - * $ wp post generate --count=10 --post_type=page --post_date=1999-01-04 - * Generating posts 100% [================================================] 0:01 / 0:04 - * - * # Generate posts with fetched content. - * $ curl http://loripsum.net/api/5 | wp post generate --post_content --count=10 - * % Total % Received % Xferd Average Speed Time Time Time Current - * Dload Upload Total Spent Left Speed - * 100 2509 100 2509 0 0 616 0 0:00:04 0:00:04 --:--:-- 616 - * Generating posts 100% [================================================] 0:01 / 0:04 - * - * # Add meta to every generated posts. - * $ wp post generate --format=ids | xargs -d ' ' -I % wp post meta add % foo bar - * Success: Added custom field. - * Success: Added custom field. - * Success: Added custom field. - */ - public function generate( $args, $assoc_args ) { - global $wpdb; - - $defaults = array( - 'count' => 100, - 'max_depth' => 1, - 'post_type' => 'post', - 'post_status' => 'publish', - 'post_author' => false, - 'post_date' => current_time( 'mysql' ), - 'post_content' => '', - ); - extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); - - // @codingStandardsIgnoreStart - if ( !post_type_exists( $post_type ) ) { - WP_CLI::error( sprintf( "'%s' is not a registered post type.", $post_type ) ); - } - - if ( $post_author ) { - $user_fetcher = new \WP_CLI\Fetchers\User; - $post_author = $user_fetcher->get_check( $post_author )->ID; - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'post_content' ) ) { - $post_content = file_get_contents( 'php://stdin' ); - } - - // Get the total number of posts. - $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = %s", $post_type ) ); - - $label = get_post_type_object( $post_type )->labels->singular_name; - - $hierarchical = get_post_type_object( $post_type )->hierarchical; - - $limit = $count + $total; - - $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); - - $notify = false; - if ( 'progress' === $format ) { - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating posts', $count ); - } - - $previous_post_id = 0; - $current_depth = 1; - $current_parent = 0; - - for ( $i = $total; $i < $limit; $i++ ) { - - if ( $hierarchical ) { - - if( $this->maybe_make_child() && $current_depth < $max_depth ) { - - $current_parent = $previous_post_id; - $current_depth++; - - } else if( $this->maybe_reset_depth() ) { - - $current_depth = 1; - $current_parent = 0; - - } - } - - $args = array( - 'post_type' => $post_type, - 'post_title' => "$label $i", - 'post_status' => $post_status, - 'post_author' => $post_author, - 'post_parent' => $current_parent, - 'post_name' => "post-$i", - 'post_date' => $post_date, - 'post_content' => $post_content, - ); - - $post_id = wp_insert_post( $args, true ); - if ( is_wp_error( $post_id ) ) { - WP_CLI::warning( $post_id ); - } else { - $previous_post_id = $post_id; - if ( 'ids' === $format ) { - echo $post_id; - if ( $i < $limit - 1 ) { - echo ' '; - } - } - } - - if ( 'progress' === $format ) { - $notify->tick(); - } - } - if ( 'progress' === $format ) { - $notify->finish(); - } - // @codingStandardsIgnoreEnd - } - - private function maybe_make_child() { - // 50% chance of making child post - return ( mt_rand(1, 2) == 1 ); - } - - private function maybe_reset_depth() { - // 10% chance of reseting to root depth - return ( mt_rand(1, 10) == 7 ); - } - - /** - * Read post content from file or STDIN - * - * @param string $arg Supplied argument - * @return string - */ - private function read_from_file_or_stdin( $arg ) { - if ( $arg !== '-' ) { - $readfile = $arg; - if ( ! file_exists( $readfile ) || ! is_file( $readfile ) ) { - \WP_CLI::error( "Unable to read content from '$readfile'." ); - } - } else { - $readfile = 'php://stdin'; - } - return file_get_contents( $readfile ); - } -} - -WP_CLI::add_command( 'post', 'Post_Command' ); diff --git a/php/commands/rewrite.php b/php/commands/rewrite.php deleted file mode 100644 index c784a3d1e..000000000 --- a/php/commands/rewrite.php +++ /dev/null @@ -1,312 +0,0 @@ -<?php - -/** - * Manage rewrite rules. - * - * ## EXAMPLES - * - * # Flush rewrite rules - * $ wp rewrite flush - * Success: Rewrite rules flushed. - * - * # Update permalink structure - * $ wp rewrite structure '/%year%/%monthnum%/%postname%' - * Success: Rewrite structure set. - * - * # List rewrite rules - * $ wp rewrite list --format=csv - * match,query,source - * ^wp-json/?$,index.php?rest_route=/,other - * ^wp-json/(.*)?,index.php?rest_route=/$matches[1],other - * category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category - * category/(.+?)/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category - * category/(.+?)/embed/?$,index.php?category_name=$matches[1]&embed=true,category - * - * @package wp-cli - */ -class Rewrite_Command extends WP_CLI_Command { - - /** - * Flush rewrite rules. - * - * Resets WordPress' rewrite rules based on registered post types, etc. - * - * To regenerate a .htaccess file with WP-CLI, you'll need to add the mod_rewrite module - * to your wp-cli.yml or config.yml. For example: - * - * ``` - * apache_modules: - * - mod_rewrite - * ``` - * - * ## OPTIONS - * - * [--hard] - * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. Works only on single site installs. - * - * ## EXAMPLES - * - * $ wp rewrite flush - * Success: Rewrite rules flushed. - */ - public function flush( $args, $assoc_args ) { - // make sure we detect mod_rewrite if configured in apache_modules in config - self::apache_modules(); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { - WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) && is_multisite() ) { - WP_CLI::warning( "WordPress can't generate .htaccess file for a multisite install." ); - } - - flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ); - - if ( ! get_option( 'rewrite_rules' ) ) { - WP_CLI::warning( "Rewrite rules are empty, possibly because of a missing permalink_structure option. Use 'wp rewrite list' to verify, or 'wp rewrite structure' to update permalink_structure." ); - } else { - WP_CLI::success( 'Rewrite rules flushed.' ); - } - } - - /** - * Update the permalink structure. - * - * Sets the post permalink structure to the specified pattern. - * - * To regenerate a .htaccess file with WP-CLI, you'll need to add - * the mod_rewrite module to your [WP-CLI config](http://wp-cli.org/config/). - * For example: - * - * ``` - * apache_modules: - * - mod_rewrite - * ``` - * - * ## OPTIONS - * - * <permastruct> - * : The new permalink structure to apply. - * - * [--category-base=<base>] - * : Set the base for category permalinks, i.e. '/category/'. - * - * [--tag-base=<base>] - * : Set the base for tag permalinks, i.e. '/tag/'. - * - * [--hard] - * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. - * - * ## EXAMPLES - * - * $ wp rewrite structure '/%year%/%monthnum%/%postname%' - * Success: Rewrite structure set. - */ - public function structure( $args, $assoc_args ) { - global $wp_rewrite; - - // copypasta from /wp-admin/options-permalink.php - - $prefix = $blog_prefix = ''; - if ( is_multisite() && !is_subdomain_install() && is_main_site() ) - $blog_prefix = '/blog'; - - $permalink_structure = ( $args[0] == 'default' ) ? '' : $args[0]; - - if ( ! empty( $permalink_structure ) ) { - $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) ); - if ( $prefix && $blog_prefix ) - $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure ); - else - $permalink_structure = $blog_prefix . $permalink_structure; - } - $wp_rewrite->set_permalink_structure( $permalink_structure ); - - // Update category or tag bases - if ( isset( $assoc_args['category-base'] ) ) { - - $category_base = $assoc_args['category-base']; - if ( ! empty( $category_base ) ) - $category_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $category_base ) ); - $wp_rewrite->set_category_base( $category_base ); - } - - if ( isset( $assoc_args['tag-base'] ) ) { - - $tag_base = $assoc_args['tag-base']; - if ( ! empty( $tag_base ) ) - $tag_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $tag_base ) ); - $wp_rewrite->set_tag_base( $tag_base ); - } - - // make sure we detect mod_rewrite if configured in apache_modules in config - self::apache_modules(); - - // Launch a new process to flush rewrites because core expects flush - // to happen after rewrites are set - $new_assoc_args = array(); - $cmd = 'rewrite flush'; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) ) { - $cmd .= ' --hard'; - $new_assoc_args['hard'] = true; - if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ) ) ) { - WP_CLI::warning( "Regenerating a .htaccess file requires special configuration. See usage docs." ); - } - } - - $process_run = WP_CLI::runcommand( $cmd ); - if ( ! empty( $process_run->stderr ) ) { - // Strip "Warning: " - WP_CLI::warning( substr( $process_run->stderr, 9 ) ); - } - - WP_CLI::success( "Rewrite structure set." ); - } - - /** - * Get a list of the current rewrite rules. - * - * ## OPTIONS - * - * [--match=<url>] - * : Show rewrite rules matching a particular URL. - * - * [--source=<source>] - * : Show rewrite rules from a particular source. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to match,query,source. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp rewrite list --format=csv - * match,query,source - * ^wp-json/?$,index.php?rest_route=/,other - * ^wp-json/(.*)?,index.php?rest_route=/$matches[1],other - * category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category - * category/(.+?)/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category - * category/(.+?)/embed/?$,index.php?category_name=$matches[1]&embed=true,category - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - global $wp_rewrite; - - $rules = get_option( 'rewrite_rules' ); - if ( ! $rules ) { - $rules = array(); - WP_CLI::warning( 'No rewrite rules.' ); - } - - $defaults = array( - 'source' => '', - 'match' => '', - 'format' => 'table', - 'fields' => 'match,query,source', - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $rewrite_rules_by_source = array(); - $rewrite_rules_by_source['post'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->permalink_structure, EP_PERMALINK ); - $rewrite_rules_by_source['date'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_date_permastruct(), EP_DATE ); - $rewrite_rules_by_source['root'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . '/', EP_ROOT ); - $rewrite_rules_by_source['comments'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . $wp_rewrite->comments_base, EP_COMMENTS, true, true, true, false ); - $rewrite_rules_by_source['search'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_search_permastruct(), EP_SEARCH ); - $rewrite_rules_by_source['author'] = $wp_rewrite->generate_rewrite_rules($wp_rewrite->get_author_permastruct(), EP_AUTHORS ); - $rewrite_rules_by_source['page'] = $wp_rewrite->page_rewrite_rules(); - - // Extra permastructs including tags, categories, etc. - foreach ( $wp_rewrite->extra_permastructs as $permastructname => $permastruct ) { - if ( is_array( $permastruct ) ) { - $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct['struct'], $permastruct['ep_mask'], $permastruct['paged'], $permastruct['feed'], $permastruct['forcomments'], $permastruct['walk_dirs'], $permastruct['endpoints'] ); - } else { - $rewrite_rules_by_source[$permastructname] = $wp_rewrite->generate_rewrite_rules( $permastruct, EP_NONE ); - } - } - - // Apply the filters used in core just in case - foreach( $rewrite_rules_by_source as $source => $source_rules ) { - $rewrite_rules_by_source[$source] = apply_filters( $source . '_rewrite_rules', $source_rules ); - if ( 'post_tag' == $source ) - $rewrite_rules_by_source[$source] = apply_filters( 'tag_rewrite_rules', $source_rules ); - } - - $rule_list = array(); - foreach ( $rules as $match => $query ) { - - if ( ! empty( $assoc_args['match'] ) - && ! preg_match( "!^$match!", trim( $assoc_args['match'], '/' ) ) ) - continue; - - $source = 'other'; - foreach( $rewrite_rules_by_source as $rules_source => $source_rules ) { - if ( array_key_exists( $match, $source_rules ) ) { - $source = $rules_source; - } - } - - if ( ! empty( $assoc_args['source'] ) && $source != $assoc_args['source'] ) - continue; - - $rule_list[] = compact( 'match', 'query', 'source' ); - } - - WP_CLI\Utils\format_items( $assoc_args['format'], $rule_list, explode( ',', $assoc_args['fields'] ) ); - } - - /** - * Expose apache modules if present in config - * - * Implementation Notes: This function exposes a global function - * apache_get_modules and also sets the $is_apache global variable. - * - * This is so that flush_rewrite_rules will actually write out the - * .htaccess file for apache wordpress installations. There is a check - * to see: - * - * 1. if the $is_apache variable is set. - * 2. if the mod_rewrite module is returned from the apache_get_modules - * function. - * - * To get this to work with wp-cli you'll need to add the mod_rewrite module - * to your config.yml. For example - * - * ``` - * apache_modules: - * - mod_rewrite - * ``` - * - * If this isn't done then the .htaccess rewrite rules won't be flushed out - * to disk. - */ - private static function apache_modules() { - $mods = WP_CLI::get_config('apache_modules'); - if ( !empty( $mods ) && !function_exists( 'apache_get_modules' ) ) { - global $is_apache; - $is_apache = true; - - // needed for get_home_path() and .htaccess location - $_SERVER['SCRIPT_FILENAME'] = ABSPATH; - - function apache_get_modules() { - return WP_CLI::get_config( 'apache_modules' ); - } - } - } -} - -WP_CLI::add_command( 'rewrite', 'Rewrite_Command' ); - diff --git a/php/commands/role.php b/php/commands/role.php deleted file mode 100644 index 7f352936b..000000000 --- a/php/commands/role.php +++ /dev/null @@ -1,375 +0,0 @@ -<?php - -/** - * Manage user roles. - * - * ## EXAMPLES - * - * # List roles. - * $ wp role list --fields=role --format=csv - * role - * administrator - * editor - * author - * contributor - * subscriber - * - * # Check to see if a role exists. - * $ wp role exists editor - * Success: Role with ID 'editor' exists. - * - * # Create a new role. - * $ wp role create approver Approver - * Success: Role with key 'approver' created. - * - * # Delete an existing role. - * $ wp role delete approver - * Success: Role with key 'approver' deleted. - * - * # Reset existing roles to their default capabilities. - * $ wp role reset administrator author contributor - * Success: Reset 3/3 roles. - * - * @package wp-cli - */ -class Role_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'role' - ); - - /** - * List all roles. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each role: - * - * * name - * * role - * - * There are no optional fields. - * - * ## EXAMPLES - * - * # List roles. - * $ wp role list --fields=role --format=csv - * role - * administrator - * editor - * author - * contributor - * subscriber - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - global $wp_roles; - - $output_roles = array(); - foreach ( $wp_roles->roles as $key => $role ) { - $output_role = new stdClass; - - $output_role->name = $role['name']; - $output_role->role = $key; - - $output_roles[] = $output_role; - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_roles ); - } - - /** - * Check if a role exists. - * - * Exits with return code 0 if the role exists, 1 if it does not. - * - * ## OPTIONS - * - * <role-key> - * : The internal name of the role. - * - * ## EXAMPLES - * - * # Check if a role exists. - * $ wp role exists editor - * Success: Role with ID 'editor' exists. - */ - public function exists( $args ) { - global $wp_roles; - - if ( ! in_array($args[0], array_keys( $wp_roles->roles ) ) ) { - WP_CLI::error( "Role with ID '$args[0]' does not exist." ); - } - - WP_CLI::success( "Role with ID '$args[0]' exists." ); - } - - /** - * Create a new role. - * - * ## OPTIONS - * - * <role-key> - * : The internal name of the role. - * - * <role-name> - * : The publicly visible name of the role. - * - * [--clone=<role>] - * : Clone capabilities from an existing role. - * - * ## EXAMPLES - * - * # Create role for Approver. - * $ wp role create approver Approver - * Success: Role with key 'approver' created. - * - * # Create role for Product Administrator. - * $ wp role create productadmin "Product Administrator" - * Success: Role with key 'productadmin' created. - */ - public function create( $args, $assoc_args ) { - global $wp_roles; - - self::persistence_check(); - - $role_key = array_shift( $args ); - $role_name = array_shift( $args ); - - if ( empty( $role_key ) || empty( $role_name ) ) { - WP_CLI::error( "Can't create role, insufficient information provided."); - } - - $capabilities = false; - if ( ! empty( $assoc_args['clone'] ) ) { - $role_obj = $wp_roles->get_role( $assoc_args['clone'] ); - if ( ! $role_obj ) { - WP_CLI::error( "'{$assoc_args['clone']}' role not found." ); - } - $capabilities = array_keys( $role_obj->capabilities ); - } - - if ( add_role( $role_key, $role_name ) ) { - if ( ! empty( $capabilities ) ) { - $role_obj = $wp_roles->get_role( $role_key ); - foreach( $capabilities as $cap ) { - $role_obj->add_cap( $cap ); - } - WP_CLI::success( sprintf( "Role with key '%s' created. Cloned capabilities from '%s'.", $role_key, $assoc_args['clone'] ) ); - } else { - WP_CLI::success( sprintf( "Role with key '%s' created.", $role_key ) ); - } - } else { - WP_CLI::error( "Role couldn't be created." ); - } - } - - /** - * Delete an existing role. - * - * ## OPTIONS - * - * <role-key> - * : The internal name of the role. - * - * ## EXAMPLES - * - * # Delete approver role. - * $ wp role delete approver - * Success: Role with key 'approver' deleted. - * - * # Delete productadmin role. - * wp role delete productadmin - * Success: Role with key 'productadmin' deleted. - */ - public function delete( $args ) { - global $wp_roles; - - self::persistence_check(); - - $role_key = array_shift( $args ); - - if ( empty( $role_key ) || ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::error( "Role key not provided, or is invalid." ); - - remove_role( $role_key ); - - // Note: remove_role() doesn't indicate success or otherwise, so we have to - // check ourselves - if ( ! isset( $wp_roles->roles[$role_key] ) ) - WP_CLI::success( sprintf( "Role with key '%s' deleted.", $role_key ) ); - else - WP_CLI::error( sprintf( "Role with key '%s' could not be deleted.", $role_key ) ); - - } - - /** - * Reset any default role to default capabilities. - * - * ## OPTIONS - * - * [<role-key>...] - * : The internal name of one or more roles to reset. - * - * [--all] - * : If set, all default roles will be reset. - * - * ## EXAMPLES - * - * # Reset role. - * $ wp role reset administrator author contributor - * Success: Reset 1/3 roles. - * - * # Reset all default roles. - * $ wp role reset --all - * Success: All default roles reset. - */ - public function reset( $args, $assoc_args ) { - - self::persistence_check(); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) - WP_CLI::error( "Role key not provided, or is invalid." ); - - if ( ! function_exists( 'populate_roles' ) ) { - require_once( ABSPATH.'wp-admin/includes/schema.php' ); - } - - global $wp_roles; - $all_roles = array_keys( $wp_roles->roles ); - $preserve_args = $args; - - // Get our default roles. - $default_roles = $preserve = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' ); - $before = array(); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - foreach( $default_roles as $role ) { - $before[ $role ] = get_role( $role ); - remove_role( $role ); - $args[]= $role; - } - populate_roles(); - $not_affected_roles = array_diff( $all_roles, $default_roles ); - if ( ! empty( $not_affected_roles ) ) { - foreach ( $not_affected_roles as $not_affected_role ) { - WP_CLI::log( "Custom role '{$not_affected_role}' not affected." ); - } - } - } else { - - foreach ( $args as $k => $role_key ) { - $key = array_search( $role_key, $default_roles ); - if ( false !== $key ) { - unset( $preserve[ $key ] ); - $before[ $role_key ] = get_role( $role_key ); - remove_role( $role_key ); - } else { - unset( $args[ $k ] ); - } - } - - $not_affected_roles = array_diff( $preserve_args, $default_roles ); - if ( ! empty( $not_affected_roles ) ) { - foreach ( $not_affected_roles as $not_affected_role ) { - WP_CLI::log( "Custom role '{$not_affected_role}' not affected." ); - } - } - - // No roles were unset, bail. - if ( count( $default_roles ) == count( $preserve ) ) { - WP_CLI::error( 'Must specify a default role to reset.' ); - } - - // For the roles we're not resetting. - foreach ( $preserve as $k => $role ) { - /* save roles - * if get_role is null - * save role name for re-removal - */ - $roleobj = get_role( $role ); - $preserve[ $k ] = is_null( $roleobj ) ? $role : $roleobj; - - remove_role( $role ); - } - - // Put back all default roles and capabilities. - populate_roles(); - - // Restore the preserved roles. - foreach ( $preserve as $k => $roleobj ) { - // Re-remove after populating. - if ( is_a( $roleobj, 'WP_Role' ) ) { - remove_role( $roleobj->name ); - add_role( $roleobj->name, ucwords( $roleobj->name ), $roleobj->capabilities ); - } else { - // When not an object, that means the role didn't exist before. - remove_role( $roleobj ); - } - } - } - - $num_reset = 0; - $args = array_unique( $args ); - $num_to_reset = count( $args ); - foreach( $args as $role_key ) { - $after[ $role_key ] = get_role( $role_key ); - - if ( $after[ $role_key ] != $before[ $role_key ] ) { - ++$num_reset; - $restored_cap = array_diff_key( $after[ $role_key ]->capabilities, $before[ $role_key ]->capabilities ); - $removed_cap = array_diff_key( $before[ $role_key ]->capabilities, $after[ $role_key ]->capabilities ); - $restored_cap_count = count( $restored_cap ); - $removed_cap_count = count( $removed_cap ); - $restored_text = ( 1 === $restored_cap_count ) ? '%d capability' : '%d capabilities'; - $removed_text = ( 1 === $removed_cap_count ) ? '%d capability' : '%d capabilities'; - $message = "Restored ". $restored_text . " to and removed " . $removed_text . " from '%s' role."; - WP_CLI::log( sprintf( $message, $restored_cap_count, $removed_cap_count, $role_key ) ); - } else { - WP_CLI::log( "No changes necessary for '{$role_key}' role." ); - } - } - if ( $num_reset ) { - if ( 1 === count( $args ) ) { - WP_CLI::success( 'Role reset.' ); - } else { - WP_CLI::success( "{$num_reset} of {$num_to_reset} roles reset." ); - } - } else { - if ( 1 === count( $args ) ) { - WP_CLI::success( 'Role didn\'t need resetting.' ); - } else { - WP_CLI::success( 'No roles needed resetting.' ); - } - } - } - - private static function persistence_check() { - global $wp_roles; - - if ( !$wp_roles->use_db ) - WP_CLI::error( "Role definitions are not persistent." ); - } -} - -WP_CLI::add_command( 'role', 'Role_Command' ); diff --git a/php/commands/scaffold.php b/php/commands/scaffold.php deleted file mode 100644 index f76fc8f4e..000000000 --- a/php/commands/scaffold.php +++ /dev/null @@ -1,987 +0,0 @@ -<?php - -use WP_CLI\Utils; -use WP_CLI\Process; - -/** - * Generate code for post types, taxonomies, plugins, child themes. etc. - * - * ## EXAMPLES - * - * # Generate a new plugin with unit tests - * $ wp scaffold plugin sample-plugin - * Success: Created plugin files. - * Success: Created test files. - * - * # Generate theme based on _s - * $ wp scaffold _s sample-theme --theme_name="Sample Theme" --author="John Doe" - * Success: Created theme 'Sample Theme'. - * - * # Generate code for post type registration in given theme - * $ wp scaffold post-type movie --label=Movie --theme=simple-life - * Success: Created /var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php - * - * @package wp-cli - */ -class Scaffold_Command extends WP_CLI_Command { - - /** - * Generate PHP code for registering a custom post type. - * - * ## OPTIONS - * - * <slug> - * : The internal name of the post type. - * - * [--label=<label>] - * : The text used to translate the update messages. - * - * [--textdomain=<textdomain>] - * : The textdomain to use for the labels. - * - * [--dashicon=<dashicon>] - * : The dashicon to use in the menu. - * - * [--theme] - * : Create a file in the active theme directory, instead of sending to - * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. - * - * [--plugin=<plugin>] - * : Create a file in the given plugin's directory, instead of sending to STDOUT. - * - * [--raw] - * : Just generate the `register_post_type()` call and nothing else. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate a 'movie' post type for the 'simple-life' theme - * $ wp scaffold post-type movie --label=Movie --theme=simple-life - * Success: Created '/var/www/example.com/public_html/wp-content/themes/simple-life/post-types/movie.php'. - * - * @subcommand post-type - * - * @alias cpt - */ - public function post_type( $args, $assoc_args ) { - - if ( strlen( $args[0] ) > 20 ) { - WP_CLI::error( "Post type slugs cannot exceed 20 characters in length." ); - } - - $defaults = array( - 'textdomain' => '', - 'dashicon' => 'admin-post', - ); - - $this->_scaffold( $args[0], $assoc_args, $defaults, '/post-types/', array( - 'post_type.mustache', - 'post_type_extended.mustache' - ) ); - } - - /** - * Generate PHP code for registering a custom taxonomy. - * - * ## OPTIONS - * - * <slug> - * : The internal name of the taxonomy. - * - * [--post_types=<post-types>] - * : Post types to register for use with the taxonomy. - * - * [--label=<label>] - * : The text used to translate the update messages. - * - * [--textdomain=<textdomain>] - * : The textdomain to use for the labels. - * - * [--theme] - * : Create a file in the active theme directory, instead of sending to - * STDOUT. Specify a theme with `--theme=<theme>` to have the file placed in that theme. - * - * [--plugin=<plugin>] - * : Create a file in the given plugin's directory, instead of sending to STDOUT. - * - * [--raw] - * : Just generate the `register_taxonomy()` call and nothing else. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate PHP code for registering a custom taxonomy and save in a file - * $ wp scaffold taxonomy venue --post_types=event,presentation > taxonomy.php - * - * @subcommand taxonomy - * - * @alias tax - */ - public function taxonomy( $args, $assoc_args ) { - $defaults = array( - 'textdomain' => '', - 'post_types' => "'post'" - ); - - if ( isset( $assoc_args['post_types'] ) ) { - $assoc_args['post_types'] = $this->quote_comma_list_elements( $assoc_args['post_types'] ); - } - - $this->_scaffold( $args[0], $assoc_args, $defaults, '/taxonomies/', array( - 'taxonomy.mustache', - 'taxonomy_extended.mustache' - ) ); - } - - private function _scaffold( $slug, $assoc_args, $defaults, $subdir, $templates ) { - $wp_filesystem = $this->init_wp_filesystem(); - - $control_args = $this->extract_args( $assoc_args, array( - 'label' => preg_replace( '/_|-/', ' ', strtolower( $slug ) ), - 'theme' => false, - 'plugin' => false, - 'raw' => false, - ) ); - - $vars = $this->extract_args( $assoc_args, $defaults ); - - $vars['slug'] = $slug; - - $vars['textdomain'] = $this->get_textdomain( $vars['textdomain'], $control_args ); - - $vars['label'] = $control_args['label']; - - $vars['label_ucfirst'] = ucfirst( $vars['label'] ); - $vars['label_plural'] = $this->pluralize( $vars['label'] ); - $vars['label_plural_ucfirst'] = ucfirst( $vars['label_plural'] ); - - // We use the machine name for function declarations - $machine_name = preg_replace( '/-/', '_', $slug ); - $machine_name_plural = $this->pluralize( $slug ); - - list( $raw_template, $extended_template ) = $templates; - - $raw_output = Utils\mustache_render( $raw_template, $vars ); - - if ( ! $control_args['raw'] ) { - $vars = array_merge( $vars, array( - 'machine_name' => $machine_name, - 'output' => $raw_output - ) ); - - $final_output = Utils\mustache_render( $extended_template, $vars ); - } else { - $final_output = $raw_output; - } - - if ( $path = $this->get_output_path( $control_args, $subdir ) ) { - $filename = $path . $slug . '.php'; - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_written = $this->create_files( array( $filename => $final_output ), $force ); - $this->log_whether_files_written( - $files_written, - $skip_message = "Skipped creating '$filename'.", - $success_message = "Created '$filename'." - ); - - } else { - // STDOUT - echo $final_output; - } - } - - /** - * Generate starter code for a theme based on _s. - * - * See the [Underscores website](http://underscores.me/) for more details. - * - * ## OPTIONS - * - * <slug> - * : The slug for the new theme, used for prefixing functions. - * - * [--activate] - * : Activate the newly downloaded theme. - * - * [--enable-network] - * : Enable the newly downloaded theme for the entire network. - * - * [--theme_name=<title>] - * : What to put in the 'Theme Name:' header in 'style.css'. - * - * [--author=<full-name>] - * : What to put in the 'Author:' header in 'style.css'. - * - * [--author_uri=<uri>] - * : What to put in the 'Author URI:' header in 'style.css'. - * - * [--sassify] - * : Include stylesheets as SASS. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate a theme with name "Sample Theme" and author "John Doe" - * $ wp scaffold _s sample-theme --theme_name="Sample Theme" --author="John Doe" - * Success: Created theme 'Sample Theme'. - */ - public function _s( $args, $assoc_args ) { - - $theme_slug = $args[0]; - $theme_path = WP_CONTENT_DIR . "/themes"; - $url = "http://underscores.me"; - $timeout = 30; - - if ( in_array( $theme_slug, array( '.', '..' ) ) ) { - WP_CLI::error( "Invalid theme slug specified." ); - } - - if ( ! preg_match( '/^[a-z_]\w+$/i', str_replace( '-', '_', $theme_slug ) ) ) { - WP_CLI::error( "Invalid theme slug specified. Theme slugs can only contain letters, numbers, underscores and hyphens, and can only start with a letter or underscore." ); - } - - $data = wp_parse_args( $assoc_args, array( - 'theme_name' => ucfirst( $theme_slug ), - 'author' => "Me", - 'author_uri' => "", - ) ); - - $_s_theme_path = "$theme_path/$data[theme_name]"; - - if ( ! $this->check_target_directory( "theme", $_s_theme_path ) ) { - WP_CLI::error( "Invalid theme slug specified." ); - } - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $should_write_file = $this->prompt_if_files_will_be_overwritten( $_s_theme_path, $force ); - if ( ! $should_write_file ) { - WP_CLI::log( 'No files created' ); - die; - } - - $theme_description = "Custom theme: " . $data['theme_name'] . ", developed by " . $data['author']; - - $body = array(); - $body['underscoresme_name'] = $data['theme_name']; - $body['underscoresme_slug'] = $theme_slug; - $body['underscoresme_author'] = $data['author']; - $body['underscoresme_author_uri'] = $data['author_uri']; - $body['underscoresme_description'] = $theme_description; - $body['underscoresme_generate_submit'] = "Generate"; - $body['underscoresme_generate'] = "1"; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'sassify' ) ) { - $body['underscoresme_sass'] = 1; - } - - $tmpfname = wp_tempnam( $url ); - $response = wp_remote_post( $url, array( - 'timeout' => $timeout, - 'body' => $body, - 'stream' => true, - 'filename' => $tmpfname - ) ); - - if ( is_wp_error( $response ) ) { - WP_CLI::error( $response ); - } - - $response_code = wp_remote_retrieve_response_code( $response ); - if ( 200 != $response_code ) { - WP_CLI::error( "Couldn't create theme (received $response_code response)." ); - } - - $this->maybe_create_themes_dir(); - - $this->init_wp_filesystem(); - - $unzip_result = unzip_file( $tmpfname, $theme_path ); - unlink( $tmpfname ); - - if ( true === $unzip_result ) { - WP_CLI::success( "Created theme '{$data['theme_name']}'." ); - } else { - WP_CLI::error( "Could not decompress your theme files ('{$tmpfname}') at '{$theme_path}': {$unzip_result->get_error_message()}" ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'enable-network' ) ) { - WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); - } - } - - /** - * Generate child theme based on an existing theme. - * - * Creates a child theme folder with `functions.php` and `style.css` files. - * - * ## OPTIONS - * - * <slug> - * : The slug for the new child theme. - * - * --parent_theme=<slug> - * : What to put in the 'Template:' header in 'style.css'. - * - * [--theme_name=<title>] - * : What to put in the 'Theme Name:' header in 'style.css'. - * - * [--author=<full-name>] - * : What to put in the 'Author:' header in 'style.css'. - * - * [--author_uri=<uri>] - * : What to put in the 'Author URI:' header in 'style.css'. - * - * [--theme_uri=<uri>] - * : What to put in the 'Theme URI:' header in 'style.css'. - * - * [--activate] - * : Activate the newly created child theme. - * - * [--enable-network] - * : Enable the newly created child theme for the entire network. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate a 'sample-theme' child theme based on TwentySixteen - * $ wp scaffold child-theme sample-theme --parent_theme=twentysixteen - * Success: Created '/var/www/example.com/public_html/wp-content/themes/sample-theme'. - * - * @subcommand child-theme - */ - function child_theme( $args, $assoc_args ) { - $theme_slug = $args[0]; - - if ( in_array( $theme_slug, array( '.', '..' ) ) ) { - WP_CLI::error( "Invalid theme slug specified." ); - } - - $data = wp_parse_args( $assoc_args, array( - 'theme_name' => ucfirst( $theme_slug ), - 'author' => "Me", - 'author_uri' => "", - 'theme_uri' => "" - ) ); - $data['slug'] = $theme_slug; - $data['parent_theme_function_safe'] = str_replace( '-', '_', $data['parent_theme'] ); - - $data['description'] = ucfirst( $data['parent_theme'] ) . " child theme."; - - $theme_dir = WP_CONTENT_DIR . "/themes" . "/$theme_slug"; - - if ( ! $this->check_target_directory( "theme", $theme_dir ) ) { - WP_CLI::error( "Invalid theme slug specified." ); - } - - $theme_style_path = "$theme_dir/style.css"; - $theme_functions_path = "$theme_dir/functions.php"; - - $this->maybe_create_themes_dir(); - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_written = $this->create_files( array( - $theme_style_path => Utils\mustache_render( 'child_theme.mustache', $data ), - $theme_functions_path => Utils\mustache_render( 'child_theme_functions.mustache', $data ) - ), $force ); - $this->log_whether_files_written( - $files_written, - $skip_message = 'All theme files were skipped.', - $success_message = "Created '$theme_dir'." - ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - WP_CLI::run_command( array( 'theme', 'activate', $theme_slug ) ); - } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'enable-network' ) ) { - WP_CLI::run_command( array( 'theme', 'enable', $theme_slug ), array( 'network' => true ) ); - } - } - - private function get_output_path( $assoc_args, $subdir ) { - if ( $assoc_args['theme'] ) { - $theme = $assoc_args['theme']; - if ( is_string( $theme ) ) { - $path = get_theme_root( $theme ) . '/' . $theme; - } else { - $path = get_stylesheet_directory(); - } - } elseif ( $assoc_args['plugin'] ) { - $plugin = $assoc_args['plugin']; - $path = WP_PLUGIN_DIR . '/' . $plugin; - if ( ! is_dir( $path ) ) { - WP_CLI::error( "Can't find '$plugin' plugin." ); - } - } else { - return false; - } - - $path .= $subdir; - - return $path; - } - - /** - * Generate starter code for a plugin. - * - * The following files are always generated: - * - * * `plugin-slug.php` is the main PHP plugin file. - * * `readme.txt` is the readme file for the plugin. - * * `package.json` needed by NPM holds various metadata relevant to the project. Packages: `grunt`, `grunt-wp-i18n` and `grunt-wp-readme-to-markdown`. - * * `Gruntfile.js` is the JS file containing Grunt tasks. Tasks: `i18n` containing `addtextdomain` and `makepot`, `readme` containing `wp_readme_to_markdown`. - * * `.editorconfig` is the configuration file for Editor. - * * `.gitignore` tells which files (or patterns) git should ignore. - * * `.distignore` tells which files and folders should be ignored in distribution. - * - * The following files are also included unless the `--skip-tests` is used: - * - * * `phpunit.xml.dist` is the configuration file for PHPUnit. - * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. - * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. - * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. - * * `tests/test-sample.php` is a sample file containing test cases. - * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. - * - * ## OPTIONS - * - * <slug> - * : The internal name of the plugin. - * - * [--dir=<dirname>] - * : Put the new plugin in some arbitrary directory path. Plugin directory will be path plus supplied slug. - * - * [--plugin_name=<title>] - * : What to put in the 'Plugin Name:' header. - * - * [--plugin_description=<description>] - * : What to put in the 'Description:' header. - * - * [--plugin_author=<author>] - * : What to put in the 'Author:' header. - * - * [--plugin_author_uri=<url>] - * : What to put in the 'Author URI:' header. - * - * [--plugin_uri=<url>] - * : What to put in the 'Plugin URI:' header. - * - * [--skip-tests] - * : Don't generate files for unit testing. - * - * [--ci=<provider>] - * : Choose a configuration file for a continuous integration provider. - * --- - * default: travis - * options: - * - travis - * - circle - * - gitlab - * --- - * - * [--activate] - * : Activate the newly generated plugin. - * - * [--activate-network] - * : Network activate the newly generated plugin. - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * $ wp scaffold plugin sample-plugin - * Success: Created plugin files. - * Success: Created test files. - */ - function plugin( $args, $assoc_args ) { - $plugin_slug = $args[0]; - $plugin_name = ucwords( str_replace( '-', ' ', $plugin_slug ) ); - $plugin_package = str_replace( ' ', '_', $plugin_name ); - - if ( in_array( $plugin_slug, array( '.', '..' ) ) ) { - WP_CLI::error( "Invalid plugin slug specified." ); - } - - $data = wp_parse_args( $assoc_args, array( - 'plugin_slug' => $plugin_slug, - 'plugin_name' => $plugin_name, - 'plugin_package' => $plugin_package, - 'plugin_description' => 'PLUGIN DESCRIPTION HERE', - 'plugin_author' => 'YOUR NAME HERE', - 'plugin_author_uri' => 'YOUR SITE HERE', - 'plugin_uri' => 'PLUGIN SITE HERE', - 'plugin_tested_up_to' => get_bloginfo('version'), - ) ); - - $data['textdomain'] = $plugin_slug; - - if ( ! empty( $assoc_args['dir'] ) ) { - if ( ! is_dir( $assoc_args['dir'] ) ) { - WP_CLI::error( "Cannot create plugin in directory that doesn't exist." ); - } - $plugin_dir = $assoc_args['dir'] . "/$plugin_slug"; - } else { - $plugin_dir = WP_PLUGIN_DIR . "/$plugin_slug"; - $this->maybe_create_plugins_dir(); - - if ( ! $this->check_target_directory( "plugin", $plugin_dir ) ) { - WP_CLI::error( "Invalid plugin slug specified." ); - } - } - - $plugin_path = "$plugin_dir/$plugin_slug.php"; - $plugin_readme_path = "$plugin_dir/readme.txt"; - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_written = $this->create_files( array( - $plugin_path => Utils\mustache_render( 'plugin.mustache', $data ), - $plugin_readme_path => Utils\mustache_render( 'plugin-readme.mustache', $data ), - "$plugin_dir/package.json" => Utils\mustache_render( 'plugin-packages.mustache', $data ), - "$plugin_dir/Gruntfile.js" => Utils\mustache_render( 'plugin-gruntfile.mustache', $data ), - "$plugin_dir/.gitignore" => Utils\mustache_render( 'plugin-gitignore.mustache', $data ), - "$plugin_dir/.distignore" => Utils\mustache_render( 'plugin-distignore.mustache', $data ), - "$plugin_dir/.editorconfig" => file_get_contents( WP_CLI_ROOT . "/templates/.editorconfig" ), - ), $force ); - - $this->log_whether_files_written( - $files_written, - $skip_message = 'All plugin files were skipped.', - $success_message = 'Created plugin files.' - ); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-tests' ) ) { - WP_CLI::run_command( array( 'scaffold', 'plugin-tests', $plugin_slug ), array( 'dir' => $plugin_dir, 'ci' => $assoc_args['ci'], 'force' => $force ) ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate' ) ) { - WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug ) ); - } else if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'activate-network' ) ) { - WP_CLI::run_command( array( 'plugin', 'activate', $plugin_slug), array( 'network' => true ) ); - } - } - - /** - * Generate files needed for running PHPUnit tests in a plugin. - * - * The following files are generated by default: - * - * * `phpunit.xml.dist` is the configuration file for PHPUnit. - * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. - * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. - * * `tests/bootstrap.php` is the file that makes the current plugin active when running the test suite. - * * `tests/test-sample.php` is a sample file containing the actual tests. - * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. - * - * Learn more from the [plugin unit tests documentation](http://wp-cli.org/docs/plugin-unit-tests/). - * - * ## ENVIRONMENT - * - * The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment - * variable. - * - * ## OPTIONS - * - * [<plugin>] - * : The name of the plugin to generate test files for. - * - * [--dir=<dirname>] - * : Generate test files for a non-standard plugin path. If no plugin slug is specified, the directory name is used. - * - * [--ci=<provider>] - * : Choose a configuration file for a continuous integration provider. - * --- - * default: travis - * options: - * - travis - * - circle - * - gitlab - * --- - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate unit test files for plugin 'sample-plugin'. - * $ wp scaffold plugin-tests sample-plugin - * Success: Created test files. - * - * @subcommand plugin-tests - */ - public function plugin_tests( $args, $assoc_args ) { - $this->scaffold_plugin_theme_tests( $args, $assoc_args, 'plugin' ); - } - - /** - * Generate files needed for running PHPUnit tests in a theme. - * - * The following files are generated by default: - * - * * `phpunit.xml.dist` is the configuration file for PHPUnit. - * * `.travis.yml` is the configuration file for Travis CI. Use `--ci=<provider>` to select a different service. - * * `bin/install-wp-tests.sh` configures the WordPress test suite and a test database. - * * `tests/bootstrap.php` is the file that makes the current theme active when running the test suite. - * * `tests/test-sample.php` is a sample file containing the actual tests. - * * `phpcs.ruleset.xml` is a collenction of PHP_CodeSniffer rules. - * - * Learn more from the [plugin unit tests documentation](http://wp-cli.org/docs/plugin-unit-tests/). - * - * ## ENVIRONMENT - * - * The `tests/bootstrap.php` file looks for the WP_TESTS_DIR environment - * variable. - * - * ## OPTIONS - * - * [<theme>] - * : The name of the theme to generate test files for. - * - * [--dir=<dirname>] - * : Generate test files for a non-standard theme path. If no theme slug is specified, the directory name is used. - * - * [--ci=<provider>] - * : Choose a configuration file for a continuous integration provider. - * --- - * default: travis - * options: - * - travis - * - circle - * - gitlab - * --- - * - * [--force] - * : Overwrite files that already exist. - * - * ## EXAMPLES - * - * # Generate unit test files for theme 'twentysixteenchild'. - * $ wp scaffold theme-tests twentysixteenchild - * Success: Created test files. - * - * @subcommand theme-tests - */ - public function theme_tests( $args, $assoc_args ) { - $this->scaffold_plugin_theme_tests( $args, $assoc_args, 'theme' ); - } - - private function scaffold_plugin_theme_tests( $args, $assoc_args, $type ) { - $wp_filesystem = $this->init_wp_filesystem(); - - if ( ! empty( $args[0] ) ) { - $slug = $args[0]; - if ( in_array( $slug, array( '.', '..' ) ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } - if ( 'theme' === $type ) { - $theme = wp_get_theme( $slug ); - if ( $theme->exists() ) { - $target_dir = $theme->get_stylesheet_directory(); - } else { - WP_CLI::error( "Invalid {$type} slug specified." ); - } - } else { - $target_dir = WP_PLUGIN_DIR . "/$slug"; - } - if ( empty( $assoc_args['dir'] ) && ! is_dir( $target_dir ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } - if ( ! $this->check_target_directory( $type, $target_dir ) ) { - WP_CLI::error( "Invalid {$type} slug specified." ); - } - } - - if ( ! empty( $assoc_args['dir'] ) ) { - $target_dir = $assoc_args['dir']; - if ( ! is_dir( $target_dir ) ) { - WP_CLI::error( "Invalid {$type} directory specified." ); - } - if ( empty( $slug ) ) { - $slug = Utils\basename( $target_dir ); - } - } - - if ( empty( $slug ) || empty( $target_dir ) ) { - WP_CLI::error( "Invalid {$type} specified." ); - } - - $name = ucwords( str_replace( '-', ' ', $slug ) ); - $package = str_replace( ' ', '_', $name ); - - $tests_dir = "{$target_dir}/tests"; - $bin_dir = "{$target_dir}/bin"; - - $wp_filesystem->mkdir( $tests_dir ); - $wp_filesystem->mkdir( $bin_dir ); - - $wp_versions_to_test = array('latest'); - // Parse plugin readme.txt - if ( file_exists( $target_dir . '/readme.txt' ) ) { - $readme_content = file_get_contents( $target_dir . '/readme.txt' ); - - preg_match( '/Requires at least\:(.*)\n/m', $readme_content, $matches ); - if ( isset( $matches[1] ) && $matches[1] ) { - $wp_versions_to_test[] = trim( $matches[1] ); - } - preg_match( '/Tested up to\:(.*)\n/m', $readme_content, $matches ); - if ( isset( $matches[1] ) && $matches[1] ) { - $wp_versions_to_test[] = trim( $matches[1] ); - } - } - - $template_data = array( - "{$type}_slug" => $slug, - "{$type}_package" => $package, - ); - - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $files_to_create = array( - "$tests_dir/bootstrap.php" => Utils\mustache_render( "{$type}-bootstrap.mustache", $template_data ), - "$tests_dir/test-sample.php" => Utils\mustache_render( "{$type}-test-sample.mustache", $template_data ), - ); - if ( 'travis' === $assoc_args['ci'] ) { - $files_to_create["{$target_dir}/.travis.yml"] = Utils\mustache_render( 'plugin-travis.mustache', compact( 'wp_versions_to_test' ) ); - } else if ( 'circle' === $assoc_args['ci'] ) { - $files_to_create["{$target_dir}/circle.yml"] = Utils\mustache_render( 'plugin-circle.mustache' ); - } else if ( 'gitlab' === $assoc_args['ci'] ) { - $files_to_create["{$target_dir}/.gitlab-ci.yml"] = Utils\mustache_render( 'plugin-gitlab.mustache' ); - } - $files_written = $this->create_files( $files_to_create, $force ); - - $to_copy = array( - 'install-wp-tests.sh' => $bin_dir, - 'phpunit.xml.dist' => $target_dir, - 'phpcs.ruleset.xml' => $target_dir, - ); - - foreach ( $to_copy as $file => $dir ) { - $file_name = "$dir/$file"; - $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ); - $should_write_file = $this->prompt_if_files_will_be_overwritten( $file_name, $force ); - if ( ! $should_write_file ) { - continue; - } - $files_written[] = $file_name; - - $wp_filesystem->copy( WP_CLI_ROOT . "/templates/$file", $file_name, true ); - if ( 'install-wp-tests.sh' === $file ) { - if ( ! $wp_filesystem->chmod( "$dir/$file", 0755 ) ) { - WP_CLI::warning( "Couldn't mark 'install-wp-tests.sh' as executable." ); - } - } - } - $this->log_whether_files_written( - $files_written, - $skip_message = 'All test files were skipped.', - $success_message = 'Created test files.' - ); - } - - private function check_target_directory( $type, $target_dir ) { - if ( realpath( $target_dir ) ) { - $target_dir = realpath( $target_dir ); - } - - $parent_dir = dirname( $target_dir ); - - if ( "theme" === $type ) { - if ( WP_CONTENT_DIR . '/themes' === $parent_dir ) { - return true; - } - } elseif ( "plugin" === $type ) { - if ( WP_PLUGIN_DIR === $parent_dir ) { - return true; - } - } - - return false; - } - - private function create_files( $files_and_contents, $force ) { - $wp_filesystem = $this->init_wp_filesystem(); - $wrote_files = array(); - - foreach ( $files_and_contents as $filename => $contents ) { - $should_write_file = $this->prompt_if_files_will_be_overwritten( $filename, $force ); - if ( ! $should_write_file ) { - continue; - } - - $wp_filesystem->mkdir( dirname( $filename ) ); - - if ( ! $wp_filesystem->put_contents( $filename, $contents ) ) { - WP_CLI::error( "Error creating file: $filename" ); - } elseif ( $should_write_file ) { - $wrote_files[] = $filename; - } - } - return $wrote_files; - } - - private function prompt_if_files_will_be_overwritten( $filename, $force ) { - $should_write_file = true; - if ( ! file_exists( $filename ) ) { - return true; - } - - WP_CLI::warning( 'File already exists.' ); - WP_CLI::log( $filename ); - if ( ! $force ) { - do { - $answer = cli\prompt( - 'Skip this file, or replace it with scaffolding?', - $default = false, - $marker = '[s/r]: ' - ); - } while ( ! in_array( $answer, array( 's', 'r' ) ) ); - $should_write_file = 'r' === $answer; - } - - $outcome = $should_write_file ? 'Replacing' : 'Skipping'; - WP_CLI::log( $outcome . PHP_EOL ); - - return $should_write_file; - } - - private function log_whether_files_written( $files_written, $skip_message, $success_message ) { - if ( empty( $files_written ) ) { - WP_CLI::log( $skip_message ); - } else { - WP_CLI::success( $success_message ); - } - } - - /** - * If you're writing your files to your theme directory your textdomain also needs to be the same as your theme. - * Same goes for when plugin is being used. - */ - private function get_textdomain( $textdomain, $args ) { - if ( strlen( $textdomain ) ) { - return $textdomain; - } - - if ( $args['theme'] ) { - return strtolower( wp_get_theme()->template ); - } - - if ( $args['plugin'] && true !== $args['plugin'] ) { - return $args['plugin']; - } - - return 'YOUR-TEXTDOMAIN'; - } - - private function pluralize( $word ) { - $plural = array( - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)ix|ex$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(buffal|tomat)o$/i' => '\1oes', - '/(bu)s$/i' => '1ses', - '/(alias|status)/i' => '\1es', - '/(octop|vir)us$/i' => '1i', - '/(ax|test)is$/i' => '\1es', - '/s$/i' => 's', - '/$/' => 's' - ); - - $uncountable = array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep' ); - - $irregular = array( - 'person' => 'people', - 'man' => 'men', - 'woman' => 'women', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves' - ); - - $lowercased_word = strtolower( $word ); - - foreach ( $uncountable as $_uncountable ) { - if ( substr( $lowercased_word, ( - 1 * strlen( $_uncountable ) ) ) == $_uncountable ) { - return $word; - } - } - - foreach ( $irregular as $_plural => $_singular ) { - if ( preg_match( '/(' . $_plural . ')$/i', $word, $arr ) ) { - return preg_replace( '/(' . $_plural . ')$/i', substr( $arr[0], 0, 1 ) . substr( $_singular, 1 ), $word ); - } - } - - foreach ( $plural as $rule => $replacement ) { - if ( preg_match( $rule, $word ) ) { - return preg_replace( $rule, $replacement, $word ); - } - } - - return false; - } - - protected function extract_args( $assoc_args, $defaults ) { - $out = array(); - - foreach ( $defaults as $key => $value ) { - $out[ $key ] = \WP_CLI\Utils\get_flag_value( $assoc_args, $key, $value ); - } - - return $out; - } - - protected function quote_comma_list_elements( $comma_list ) { - return "'" . implode( "', '", explode( ',', $comma_list ) ) . "'"; - } - - /** - * Create the themes directory if it doesn't already exist - */ - protected function maybe_create_themes_dir() { - - $themes_dir = WP_CONTENT_DIR . '/themes'; - if ( ! is_dir( $themes_dir ) ) { - wp_mkdir_p( $themes_dir ); - } - - } - - /** - * Create the plugins directory if it doesn't already exist - */ - protected function maybe_create_plugins_dir() { - - if ( ! is_dir( WP_PLUGIN_DIR ) ) { - wp_mkdir_p( WP_PLUGIN_DIR ); - } - - } - - /** - * Initialize WP Filesystem - */ - private function init_wp_filesystem() { - global $wp_filesystem; - WP_Filesystem(); - - return $wp_filesystem; - } - -} - -WP_CLI::add_command( 'scaffold', 'Scaffold_Command' ); diff --git a/php/commands/search-replace.php b/php/commands/search-replace.php deleted file mode 100644 index 5a468be6d..000000000 --- a/php/commands/search-replace.php +++ /dev/null @@ -1,468 +0,0 @@ -<?php - -class Search_Replace_Command extends WP_CLI_Command { - - private $dry_run; - private $export_handle = false; - private $export_insert_size; - private $recurse_objects; - private $regex; - private $regex_flags; - private $skip_columns; - private $include_columns; - - /** - * Search/replace strings in the database. - * - * Searches through all rows in a selection of tables and replaces - * appearances of the first string with the second string. - * - * By default, the command uses tables registered to the $wpdb object. On - * multisite, this will just be the tables for the current site unless - * --network is specified. - * - * Search/replace intelligently handles PHP serialized data, and does not - * change primary key values. - * - * ## OPTIONS - * - * <old> - * : A string to search for within the database. - * - * <new> - * : Replace instances of the first string with this new string. - * - * [<table>...] - * : List of database tables to restrict the replacement to. Wildcards are - * supported, e.g. `'wp_*options'` or `'wp_post*'`. - * - * [--dry-run] - * : Run the entire search/replace operation and show report, but don't save - * changes to the database. - * - * [--network] - * : Search/replace through all the tables registered to $wpdb in a - * multisite install. - * - * [--all-tables-with-prefix] - * : Enable replacement on any tables that match the table prefix even if - * not registered on $wpdb. - * - * [--all-tables] - * : Enable replacement on ALL tables in the database, regardless of the - * prefix, and even if not registered on $wpdb. Overrides --network - * and --all-tables-with-prefix. - * - * [--export[=<file>]] - * : Write transformed data as SQL file instead of saving replacements to - * the database. If <file> is not supplied, will output to STDOUT. - * - * [--export_insert_size=<rows>] - * : Define number of rows in single INSERT statement when doing SQL export. - * You might want to change this depending on your database configuration - * (e.g. if you need to do fewer queries). Default: 50 - * - * [--skip-columns=<columns>] - * : Do not perform the replacement on specific columns. Use commas to - * specify multiple columns. - * - * [--include-columns=<columns>] - * : Perform the replacement on specific columns. Use commas to - * specify multiple columns. - * - * [--precise] - * : Force the use of PHP (instead of SQL) which is more thorough, - * but slower. - * - * [--recurse-objects] - * : Enable recursing into objects to replace strings. Defaults to true; - * pass --no-recurse-objects to disable. - * - * [--verbose] - * : Prints rows to the console as they're updated. - * - * [--regex] - * : Runs the search using a regular expression (without delimiters). - * Warning: search-replace will take about 15-20x longer when using --regex. - * - * [--regex-flags=<regex-flags>] - * : Pass PCRE modifiers to regex search-replace (e.g. 'i' for case-insensitivity). - * - * ## EXAMPLES - * - * # Search and replace but skip one column - * $ wp search-replace 'http://example.dev' 'http://example.com' --skip-columns=guid - * - * # Run search/replace operation but dont save in database - * $ wp search-replace 'foo' 'bar' wp_posts wp_postmeta wp_terms --dry-run - * - * # Run case-insensitive regex search/replace operation (slow) - * $ wp search-replace '\[foo id="([0-9]+)"' '[bar id="\1"' --regex --regex-flags='i' - * - * # Turn your production multisite database into a local dev database - * $ wp search-replace --url=example.com example.com example.dev 'wp_*options' wp_blogs - * - * # Search/replace to a SQL file without transforming the database - * $ wp search-replace foo bar --export=database.sql - * - * # Bash script: Search/replace production to development url (multisite compatible) - * #!/bin/bash - * if $(wp --url=http://example.com core is-installed --network); then - * wp search-replace --url=http://example.com 'http://example.com' 'http://example.dev' --recurse-objects --network --skip-columns=guid - * else - * wp search-replace 'http://example.com' 'http://example.dev' --recurse-objects --skip-columns=guid - * fi - */ - public function __invoke( $args, $assoc_args ) { - global $wpdb; - $old = array_shift( $args ); - $new = array_shift( $args ); - $total = 0; - $report = array(); - $this->dry_run = \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run' ); - $php_only = \WP_CLI\Utils\get_flag_value( $assoc_args, 'precise' ); - $this->recurse_objects = \WP_CLI\Utils\get_flag_value( $assoc_args, 'recurse-objects', true ); - $this->verbose = \WP_CLI\Utils\get_flag_value( $assoc_args, 'verbose' ); - $this->regex = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex' ); - $this->regex_flags = \WP_CLI\Utils\get_flag_value( $assoc_args, 'regex-flags' ); - - $this->skip_columns = explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-columns' ) ); - $this->include_columns = array_filter( explode( ',', \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-columns' ) ) ); - - if ( $old === $new && ! $this->regex ) { - WP_CLI::warning( "Replacement value '{$old}' is identical to search value '{$new}'. Skipping operation." ); - exit; - } - - if ( null !== ( $export = \WP_CLI\Utils\get_flag_value( $assoc_args, 'export' ) ) ) { - if ( $this->dry_run ) { - WP_CLI::error( 'You cannot supply --dry-run and --export at the same time.' ); - } - if ( true === $export ) { - $this->export_handle = STDOUT; - $this->verbose = false; - } else { - $this->export_handle = fopen( $assoc_args['export'], 'w' ); - if ( false === $this->export_handle ) { - WP_CLI::error( sprintf( 'Unable to open "%s" for writing.', $assoc_args['export'] ) ); - } - } - $export_insert_size = WP_CLI\Utils\get_flag_value( $assoc_args, 'export_insert_size', 50 ); - if ( (int) $export_insert_size == $export_insert_size && $export_insert_size > 0 ) { - $this->export_insert_size = $export_insert_size; - } - $php_only = true; - } - - if ( $this->regex_flags ) { - $php_only = true; - } - - // never mess with hashed passwords - $this->skip_columns[] = 'user_pass'; - - // Get table names based on leftover $args or supplied $assoc_args - $tables = \WP_CLI\Utils\wp_get_table_names( $args, $assoc_args ); - foreach ( $tables as $table ) { - - if ( $this->export_handle ) { - fwrite( $this->export_handle, "\nDROP TABLE IF EXISTS `$table`;\n" ); - $row = $wpdb->get_row( "SHOW CREATE TABLE `$table`", ARRAY_N ); - fwrite( $this->export_handle, $row[1] . ";\n" ); - list( $table_report, $total_rows ) = $this->php_export_table( $table, $old, $new ); - $report = array_merge( $report, $table_report ); - $total += $total_rows; - // Don't perform replacements on the actual database - continue; - } - - list( $primary_keys, $columns, $all_columns ) = self::get_columns( $table ); - - // since we'll be updating one row at a time, - // we need a primary key to identify the row - if ( empty( $primary_keys ) ) { - $report[] = array( $table, '', 'skipped' ); - continue; - } - - foreach ( $columns as $col ) { - if ( ! empty( $this->include_columns ) && ! in_array( $col, $this->include_columns ) ) { - continue; - } - - if ( in_array( $col, $this->skip_columns ) ) { - continue; - } - - if ( $this->verbose ) { - $this->start_time = microtime( true ); - WP_CLI::log( sprintf( 'Checking: %s.%s', $table, $col ) ); - } - - if ( ! $php_only && ! $this->regex ) { - $wpdb->last_error = ''; - $serialRow = $wpdb->get_row( "SELECT * FROM `$table` WHERE `$col` REGEXP '^[aiO]:[1-9]' LIMIT 1" ); - // When the regex triggers an error, we should fall back to PHP - if ( false !== strpos( $wpdb->last_error, 'ERROR 1139' ) ) { - $serialRow = true; - } - } - - if ( $php_only || $this->regex || NULL !== $serialRow ) { - $type = 'PHP'; - $count = $this->php_handle_col( $col, $primary_keys, $table, $old, $new ); - } else { - $type = 'SQL'; - $count = $this->sql_handle_col( $col, $table, $old, $new ); - } - - $report[] = array( $table, $col, $count, $type ); - - $total += $count; - } - } - - if ( $this->export_handle && STDOUT !== $this->export_handle ) { - fclose( $this->export_handle ); - } - - // Only informational output after this point - if ( WP_CLI::get_config( 'quiet' ) || STDOUT === $this->export_handle ) { - return; - } - - $table = new \cli\Table(); - $table->setHeaders( array( 'Table', 'Column', 'Replacements', 'Type' ) ); - $table->setRows( $report ); - $table->display(); - - if ( ! $this->dry_run ) { - if ( ! empty( $assoc_args['export'] ) ) { - $success_message = "Made {$total} replacements and exported to {$assoc_args['export']}."; - } else { - $success_message = "Made $total replacements."; - if ( $total && 'Default' !== WP_CLI\Utils\wp_get_cache_type() ) { - $success_message .= ' Please remember to flush your persistent object cache with `wp cache flush`.'; - } - } - WP_CLI::success( $success_message ); - } - else { - $success_message = ( 1 === $total ) ? '%d replacement to be made.' : '%d replacements to be made.'; - WP_CLI::success( sprintf( $success_message, $total ) ); - } - } - - private function php_export_table( $table, $old, $new ) { - list( $primary_keys, $columns, $all_columns ) = self::get_columns( $table ); - $chunk_size = getenv( 'BEHAT_RUN' ) ? 10 : 1000; - $args = array( - 'table' => $table, - 'fields' => $all_columns, - 'chunk_size' => $chunk_size - ); - - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex, $this->regex_flags ); - $col_counts = array_fill_keys( $all_columns, 0 ); - if ( $this->verbose ) { - $this->start_time = microtime( true ); - WP_CLI::log( sprintf( 'Checking: %s', $table ) ); - } - - $rows = array(); - foreach ( new \WP_CLI\Iterators\Table( $args ) as $i => $row ) { - $row_fields = array(); - foreach( $all_columns as $col ) { - $value = $row->$col; - if ( $value && ! in_array( $col, $primary_keys ) && ! in_array( $col, $this->skip_columns ) ) { - $new_value = $replacer->run( $value ); - if ( $new_value !== $value ) { - $col_counts[ $col ]++; - $value = $new_value; - } - } - $row_fields[ $col ] = $value; - } - $rows[] = $row_fields; - } - $this->write_sql_row_fields( $table, $rows ); - - $table_report = array(); - $total_rows = $total_cols = 0; - foreach ( $col_counts as $col => $col_count ) { - $table_report[] = array( $table, $col, $col_count, 'PHP' ); - if ( $col_count ) { - $total_cols++; - $total_rows += $col_count; - } - } - - if ( $this->verbose ) { - $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d columns and %d total rows affected using PHP (in %ss).', $total_cols, $total_rows, $time ) ); - } - - return array( $table_report, $total_rows ); - } - - private function sql_handle_col( $col, $table, $old, $new ) { - global $wpdb; - - if ( $this->dry_run ) { - $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`$col`) FROM `$table` WHERE `$col` LIKE %s;", '%' . self::esc_like( $old ) . '%' ) ); - } else { - $count = $wpdb->query( $wpdb->prepare( "UPDATE `$table` SET `$col` = REPLACE(`$col`, %s, %s);", $old, $new ) ); - } - - if ( $this->verbose ) { - $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected using SQL (in %ss).', $count, $time ) ); - } - return $count; - } - - private function php_handle_col( $col, $primary_keys, $table, $old, $new ) { - global $wpdb; - - $count = 0; - $replacer = new \WP_CLI\SearchReplacer( $old, $new, $this->recurse_objects, $this->regex, $this->regex_flags ); - - $where = $this->regex ? '' : " WHERE `$col`" . $wpdb->prepare( ' LIKE %s', '%' . self::esc_like( $old ) . '%' ); - $primary_keys_sql = esc_sql( implode( ',', $primary_keys ) ); - $col_sql = esc_sql( $col ); - $rows = $wpdb->get_results( "SELECT {$primary_keys_sql} FROM `{$table}` {$where}" ); - foreach ( $rows as $keys ) { - $where_sql = ''; - foreach( (array) $keys as $k => $v ) { - if ( strlen( $where_sql ) ) { - $where_sql .= ' AND '; - } - $where_sql .= "{$k}='{$v}'"; - } - $col_value = $wpdb->get_var( "SELECT {$col_sql} FROM `{$table}` WHERE {$where_sql}" ); - if ( '' === $col_value ) - continue; - - $value = $replacer->run( $col_value ); - - if ( $value === $col_value ) { - continue; - } - - if ( $this->dry_run ) { - if ( $value != $col_value ) - $count++; - } else { - $where = array(); - foreach( (array) $keys as $k => $v ) { - $where[ $k ] = $v; - } - - $count += $wpdb->update( $table, array( $col => $value ), $where ); - } - } - - if ( $this->verbose ) { - $time = round( microtime( true ) - $this->start_time, 3 ); - WP_CLI::log( sprintf( '%d rows affected using PHP (in %ss).', $count, $time ) ); - } - - return $count; - } - - private function write_sql_row_fields( $table, $rows ) { - global $wpdb; - - if(empty($rows)) { - return; - } - - $insert = "INSERT INTO `$table` ("; - $insert .= join( ', ', array_map( - function ( $field ) { - return "`$field`"; - }, - array_keys( $rows[0] ) - ) ); - $insert .= ') VALUES '; - $insert .= "\n"; - - $sql = $insert; - $values = array(); - - $index = 1; - $count = count( $rows ); - $export_insert_size = $this->export_insert_size; - - foreach($rows as $row_fields) { - $sql .= '(' . join( ', ', array_fill( 0, count( $row_fields ), '%s' ) ) . ')'; - $values = array_merge( $values, array_values( $row_fields ) ); - - // Add new insert statement if needed. Before this we close the previous with semicolon and write statement to sql-file. - // "Statement break" is needed: - // 1. When the loop is running every nth time (where n is insert statement size, $export_index_size). Remainder is zero also on first round, so it have to be excluded. - // $index % $export_insert_size == 0 && $index > 0 - // 2. Or when the loop is running last time - // $index == $count - if( ( $index % $export_insert_size == 0 && $index > 0 ) || $index == $count ) { - $sql .= ";\n"; - - $sql = $wpdb->prepare( $sql, array_values( $values ) ); - fwrite( $this->export_handle, $sql ); - - // If there is still rows to loop, reset $sql and $values variables. - if( $count > $index ) { - $sql = $insert; - $values = array(); - } - } else { // Otherwise just add comma and new line - $sql .= ",\n"; - } - - $index++; - } - } - - private static function get_columns( $table ) { - global $wpdb; - - $primary_keys = $text_columns = $all_columns = array(); - foreach ( $wpdb->get_results( "DESCRIBE `$table`" ) as $col ) { - if ( 'PRI' === $col->Key ) { - $primary_keys[] = $col->Field; - } - if ( self::is_text_col( $col->Type ) ) { - $text_columns[] = $col->Field; - } - $all_columns[] = $col->Field; - } - return array( $primary_keys, $text_columns, $all_columns ); - } - - private static function is_text_col( $type ) { - foreach ( array( 'text', 'varchar' ) as $token ) { - if ( false !== strpos( $type, $token ) ) - return true; - } - - return false; - } - - private static function esc_like( $old ) { - global $wpdb; - - // Remove notices in 4.0 and support backwards compatibility - if( method_exists( $wpdb, 'esc_like' ) ) { - // 4.0 - $old = $wpdb->esc_like( $old ); - } else { - // 3.9 or less - $old = like_escape( esc_sql( $old ) ); - } - - return $old; - } - -} - -WP_CLI::add_command( 'search-replace', 'Search_Replace_Command' ); diff --git a/php/commands/server.php b/php/commands/server.php deleted file mode 100644 index 8d6dd7e01..000000000 --- a/php/commands/server.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php - -class Server_Command extends WP_CLI_Command { - - /** - * Launch PHP's built-in web server for this specific WordPress installation. - * - * Uses `php -S` to launch a web server serving the WordPress webroot. - * <http://php.net/manual/en/features.commandline.webserver.php> - * - * ## OPTIONS - * - * [--host=<host>] - * : The hostname to bind the server to. - * --- - * default: localhost - * --- - * - * [--port=<port>] - * : The port number to bind the server to. - * --- - * default: 8080 - * --- - * - * [--docroot=<path>] - * : The path to use as the document root. If the path global parameter is - * set, the default value is it. - * - * [--config=<file>] - * : Configure the server with a specific .ini file. - * - * ## EXAMPLES - * - * # Make the instance available on any address (with port 8080) - * $ wp server --host=0.0.0.0 - * PHP 5.6.9 Development Server started at Tue May 24 01:27:11 2016 - * Listening on http://0.0.0.0:8080 - * Document root is / - * Press Ctrl-C to quit. - * - * # Run on port 80 (for multisite) - * $ sudo wp server --host=localhost.localdomain --port=80 - * PHP 5.6.9 Development Server started at Tue May 24 01:30:06 2016 - * Listening on http://localhost1.localdomain1:8080 - * Document root is / - * Press Ctrl-C to quit. - * - * # Configure the server with a specific .ini file - * $ wp server --config=development.ini - * PHP 7.0.9 Development Server started at Mon Aug 22 12:09:04 2016 - * Listening on http://localhost:8080 - * Document root is / - * Press Ctrl-C to quit. - * - * @when before_wp_load - */ - function __invoke( $_, $assoc_args ) { - $min_version = '5.4'; - if ( version_compare( PHP_VERSION, $min_version, '<' ) ) { - WP_CLI::error( "The `wp server` command requires PHP $min_version or newer." ); - } - - $defaults = array( - 'host' => 'localhost', - 'port' => 8080, - 'docroot' => ! is_null( WP_CLI::get_runner()->config['path'] ) ? WP_CLI::get_runner()->config['path'] : false, - 'config' => get_cfg_var( 'cfg_file_path' ) - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $docroot = $assoc_args['docroot']; - - if ( !$docroot ) { - $config_path = WP_CLI::get_runner()->project_config_path; - - if ( !$config_path ) { - $docroot = ABSPATH; - } else { - $docroot = dirname( $config_path ); - } - } - - $cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s -c %s %s', - WP_CLI::get_php_binary(), - $assoc_args['host'] . ':' . $assoc_args['port'], - $docroot, - $assoc_args['config'], - \WP_CLI\Utils\extract_from_phar( WP_CLI_ROOT . '/php/router.php' ) - ); - - $descriptors = array( STDIN, STDOUT, STDERR ); - - // https://bugs.php.net/bug.php?id=60181 - $options = array(); - if ( \WP_CLI\Utils\is_windows() ) { - $options["bypass_shell"] = TRUE; - } - - exit( proc_close( proc_open( $cmd, $descriptors, $pipes, NULL, NULL, $options ) ) ); - } -} - -WP_CLI::add_command( 'server', 'Server_Command' ); - diff --git a/php/commands/shell.php b/php/commands/shell.php deleted file mode 100644 index 113e793c2..000000000 --- a/php/commands/shell.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -class Shell_Command extends \WP_CLI_Command { - - /** - * Interactive PHP console. - * - * `wp shell` allows you to evaluate PHP statements and expressions - * interactively, from within a WordPress environment. Type a bit of code, - * hit enter, and see the code execute right before you. Because WordPress - * is loaded, you have access to all the functions, classes and globals - * that you can use within a WordPress plugin, for example. - * - * ## OPTIONS - * - * [--basic] - * : Start in fail-safe mode, even if Boris is available. - * - * ## EXAMPLES - * - * # Call get_bloginfo() to get the name of the site. - * $ wp shell - * wp> get_bloginfo( 'name' ); - * => string(6) "WP-CLI" - */ - public function __invoke( $_, $assoc_args ) { - $implementations = array( - '\\Psy\\Shell', - '\\Boris\\Boris', - '\\WP_CLI\\REPL', - ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'basic' ) ) { - $class = '\\WP_CLI\\REPL'; - } else { - foreach ( $implementations as $candidate ) { - if ( class_exists( $candidate ) ) { - $class = $candidate; - break; - } - } - } - - if ( '\\Psy\\Shell' == $class ) { - \Psy\Shell::debug(); - } else { - $repl = new $class( "wp> " ); - $repl->start(); - } - } -} - -\WP_CLI::add_command( 'shell', 'Shell_Command' ); - diff --git a/php/commands/sidebar.php b/php/commands/sidebar.php deleted file mode 100644 index 19773c38a..000000000 --- a/php/commands/sidebar.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php - -/** - * Manage sidebars. - * - * ## EXAMPLES - * - * # List sidebars - * $ wp sidebar list --fields=name,id --format=csv - * name,id - * "Widget Area",sidebar-1 - * "Inactive Widgets",wp_inactive_widgets - */ -class Sidebar_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'id', - 'description' - ); - - /** - * List registered sidebars. - * - * ## OPTIONS - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - ids - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each sidebar: - * - * * name - * * id - * * description - * - * These fields are optionally available: - * - * * class - * * before_widget - * * after_widget - * * before_title - * * after_title - * - * ## EXAMPLES - * - * $ wp sidebar list --fields=name,id --format=csv - * name,id - * "Widget Area",sidebar-1 - * "Inactive Widgets",wp_inactive_widgets - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - global $wp_registered_sidebars; - - \WP_CLI\Utils\wp_register_unused_sidebar(); - - if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { - $sidebars = wp_list_pluck( $wp_registered_sidebars, 'id' ); - } - else { - $sidebars = $wp_registered_sidebars; - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $sidebars ); - } - -} - -WP_CLI::add_command( 'sidebar', 'Sidebar_Command' ); diff --git a/php/commands/site-option.php b/php/commands/site-option.php deleted file mode 100644 index 96b1230eb..000000000 --- a/php/commands/site-option.php +++ /dev/null @@ -1,296 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage site options in a multisite install. - * - * ## EXAMPLES - * - * # Get site registration - * $ wp site option get registration - * none - * - * # Add site option - * $ wp site option add my_option foobar - * Success: Added 'my_option' site option. - * - * # Update site option - * $ wp site option update my_option '{"foo": "bar"}' --format=json - * Success: Updated 'my_option' site option. - * - * # Delete site option - * $ wp site option delete my_option - * Success: Deleted 'my_option' site option. - */ -class Site_Option_Command extends WP_CLI_Command { - - /** - * Get a site option. - * - * ## OPTIONS - * - * <key> - * : Key for the site option. - * - * [--format=<format>] - * : Get value in a particular format. - * --- - * default: var_export - * options: - * - var_export - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get site upload filetypes - * $ wp site option get upload_filetypes - * jpg jpeg png gif mov avi mpg - */ - public function get( $args, $assoc_args ) { - list( $key ) = $args; - - $value = get_site_option( $key ); - - if ( false === $value ) { - WP_CLI::halt(1); - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Add a site option. - * - * ## OPTIONS - * - * <key> - * : The name of the site option to add. - * - * [<value>] - * : The value of the site option to add. If ommited, the value is read from STDIN. - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - * - * ## EXAMPLES - * - * # Create a site option by reading a JSON file - * $ wp site option add my_option --format=json < config.json - * Success: Added 'my_option' site option. - */ - public function add( $args, $assoc_args ) { - $key = $args[0]; - - $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); - $value = WP_CLI::read_value( $value, $assoc_args ); - - if ( ! add_site_option( $key, $value ) ) { - WP_CLI::error( "Could not add site option '$key'. Does it already exist?" ); - } else { - WP_CLI::success( "Added '$key' site option." ); - } - } - - /** - * List site options. - * - * ## OPTIONS - * - * [--search=<pattern>] - * : Use wildcards ( * and ? ) to match option name. - * - * [--site_id=<id>] - * : Limit options to those of a particular site id. - * - * [--field=<field>] - * : Prints the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : The serialization format for the value. total_bytes displays the total size of matching options in bytes. - * --- - * default: table - * options: - * - table - * - json - * - csv - * - count - * - yaml - * - total_bytes - * --- - * - * ## AVAILABLE FIELDS - * - * This field will be displayed by default for each matching option: - * - * * meta_key - * * meta_value - * - * These fields are optionally available: - * - * * meta_id - * * site_id - * * size_bytes - * - * ## EXAMPLES - * - * # List all site options begining with "i2f_" - * $ wp site option list --search="i2f_*" - * +-------------+--------------+ - * | meta_key | meta_value | - * +-------------+--------------+ - * | i2f_version | 0.1.0 | - * +-------------+--------------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - global $wpdb; - $pattern = '%'; - $fields = array( 'meta_key', 'meta_value' ); - $size_query = ",LENGTH(meta_value) AS `size_bytes`"; - - if ( isset( $assoc_args['search'] ) ) { - $pattern = self::esc_like( $assoc_args['search'] ); - // substitute wildcards - $pattern = str_replace( '*', '%', $pattern ); - $pattern = str_replace( '?', '_', $pattern ); - } - - if ( isset( $assoc_args['fields'] ) ) { - $fields = explode( ',', $assoc_args['fields'] ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { - $fields = array( 'size_bytes' ); - $size_query = ",SUM(LENGTH(meta_value)) AS `size_bytes`"; - } - - $query = $wpdb->prepare( - "SELECT `meta_id`, `site_id`, `meta_key`,`meta_value`" . $size_query - . " FROM `$wpdb->sitemeta` WHERE `meta_key` LIKE %s", - $pattern - ); - - if ( $site_id = Utils\get_flag_value( $assoc_args, 'site_id' ) ) { - $query .= $wpdb->prepare( ' AND site_id=%d', $site_id ); - } - $results = $wpdb->get_results( $query ); - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) { - WP_CLI::line( $results[0]->size_bytes ); - } else { - $formatter = new \WP_CLI\Formatter( - $assoc_args, - $fields - ); - $formatter->display_items( $results ); - } - } - - /** - * Update a site option. - * - * ## OPTIONS - * - * <key> - * : The name of the site option to update. - * - * [<value>] - * : The new value. If ommited, the value is read from STDIN. - * - * [--format=<format>] - * : The serialization format for the value. - * --- - * default: plaintext - * options: - * - plaintext - * - json - * --- - * - * ## EXAMPLES - * - * # Update a site option by reading from a file - * $ wp site option update my_option < value.txt - * Success: Updated 'my_option' site option. - * - * @alias set - */ - public function update( $args, $assoc_args ) { - $key = $args[0]; - - $value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 ); - $value = WP_CLI::read_value( $value, $assoc_args ); - - $value = sanitize_option( $key, $value ); - $old_value = sanitize_option( $key, get_site_option( $key ) ); - - if ( $value === $old_value ) { - WP_CLI::success( "Value passed for '$key' site option is unchanged." ); - } else { - if ( update_site_option( $key, $value ) ) { - WP_CLI::success( "Updated '$key' site option." ); - } else { - WP_CLI::error( "Could not update site option '$key'." ); - } - } - } - - /** - * Delete a site option. - * - * ## OPTIONS - * - * <key> - * : Key for the site option. - * - * ## EXAMPLES - * - * $ wp site option delete my_option - * Success: Deleted 'my_option' site option. - */ - public function delete( $args ) { - list( $key ) = $args; - - if ( ! delete_site_option( $key ) ) { - WP_CLI::error( "Could not delete '$key' site option. Does it exist?" ); - } else { - WP_CLI::success( "Deleted '$key' site option." ); - } - } - - private static function esc_like( $old ) { - global $wpdb; - - // Remove notices in 4.0 and support backwards compatibility - if( method_exists( $wpdb, 'esc_like' ) ) { - // 4.0 - $old = $wpdb->esc_like( $old ); - } else { - // 3.9 or less - $old = like_escape( esc_sql( $old ) ); - } - - return $old; - } -} - -WP_CLI::add_command( 'site option', 'Site_Option_Command', array( - 'before_invoke' => function() { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - } -) ); diff --git a/php/commands/site.php b/php/commands/site.php deleted file mode 100644 index 433ce9cb2..000000000 --- a/php/commands/site.php +++ /dev/null @@ -1,690 +0,0 @@ -<?php - -/** - * Perform site-wide operations. - * - * ## EXAMPLES - * - * # Create site - * $ wp site create --slug=example - * Success: Site 3 created: www.example.com/example/ - * - * # Output a simple list of site URLs - * $ wp site list --field=url - * http://www.example.com/ - * http://www.example.com/subdir/ - * - * # Delete site - * $ wp site delete 123 - * Are you sure you want to delete the 'http://www.example.com/example' site? [y/n] y - * Success: The site at 'http://www.example.com/example' was deleted. - * - * @package wp-cli - */ -class Site_Command extends \WP_CLI\CommandWithDBObject { - - protected $obj_type = 'site'; - protected $obj_id_key = 'blog_id'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\Site; - } - - /** - * Delete comments. - */ - private function _empty_comments() { - global $wpdb; - - // Empty comments and comment cache - $comment_ids = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments" ); - foreach ( $comment_ids as $comment_id ) { - wp_cache_delete( $comment_id, 'comment' ); - wp_cache_delete( $comment_id, 'comment_meta' ); - } - $wpdb->query( "TRUNCATE $wpdb->comments" ); - $wpdb->query( "TRUNCATE $wpdb->commentmeta" ); - } - - /** - * Delete all posts. - */ - private function _empty_posts() { - global $wpdb; - - // Empty posts and post cache - $posts_query = "SELECT ID FROM $wpdb->posts"; - $posts = new WP_CLI\Iterators\Query( $posts_query, 10000 ); - - $taxonomies = get_taxonomies(); - - while ( $posts->valid() ) { - $post_id = $posts->current()->ID; - - wp_cache_delete( $post_id, 'posts' ); - wp_cache_delete( $post_id, 'post_meta' ); - foreach ( $taxonomies as $taxonomy ) - wp_cache_delete( $post_id, "{$taxonomy}_relationships" ); - wp_cache_delete( $wpdb->blogid . '-' . $post_id, 'global-posts' ); - - $posts->next(); - } - $wpdb->query( "TRUNCATE $wpdb->posts" ); - $wpdb->query( "TRUNCATE $wpdb->postmeta" ); - } - - /** - * Delete terms, taxonomies, and tax relationships. - */ - private function _empty_taxonomies() { - global $wpdb; - - // Empty taxonomies and terms - $terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy" ); - $ids = array(); - $taxonomies = array(); - foreach ( (array) $terms as $term ) { - $taxonomies[] = $term->taxonomy; - $ids[] = $term->term_id; - wp_cache_delete( $term->term_id, $term->taxonomy ); - } - - $taxonomies = array_unique( $taxonomies ); - $cleaned = array(); - foreach ( $taxonomies as $taxonomy ) { - if ( isset( $cleaned[$taxonomy] ) ) - continue; - $cleaned[$taxonomy] = true; - - wp_cache_delete( 'all_ids', $taxonomy ); - wp_cache_delete( 'get', $taxonomy ); - delete_option( "{$taxonomy}_children" ); - } - $wpdb->query( "TRUNCATE $wpdb->terms" ); - $wpdb->query( "TRUNCATE $wpdb->term_taxonomy" ); - $wpdb->query( "TRUNCATE $wpdb->term_relationships" ); - if ( ! empty( $wpdb->termmeta ) ) { - $wpdb->query( "TRUNCATE $wpdb->termmeta" ); - } - } - - /** - * Insert default terms. - */ - private function _insert_default_terms() { - global $wpdb; - - // Default category - $cat_name = __( 'Uncategorized' ); - - /* translators: Default category slug */ - $cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug' ) ); - - if ( global_terms_enabled() ) { - $cat_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM {$wpdb->sitecategories} WHERE category_nicename = %s", $cat_slug ) ); - if ( $cat_id == null ) { - $wpdb->insert( $wpdb->sitecategories, array('cat_ID' => 0, 'cat_name' => $cat_name, 'category_nicename' => $cat_slug, 'last_updated' => current_time('mysql', true)) ); - $cat_id = $wpdb->insert_id; - } - update_option('default_category', $cat_id); - } else { - $cat_id = 1; - } - - $wpdb->insert( $wpdb->terms, array('term_id' => $cat_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0) ); - $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $cat_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 1)); - } - - /** - * Empty a site of its content (posts, comments, terms, and meta). - * - * Truncates posts, comments, and terms tables to empty a site of its - * content. Doesn't affect site configuration (options) or users. - * - * If running a persistent object cache, make sure to flush the cache - * after emptying the site, as the cache values will be invalid otherwise. - * - * To also empty custom database tables, you'll need to hook into command - * execution: - * - * ``` - * WP_CLI::add_hook( 'after_invoke:site empty', function(){ - * global $wpdb; - * foreach( array( 'p2p', 'p2pmeta' ) as $table ) { - * $table = $wpdb->$table; - * $wpdb->query( "TRUNCATE $table" ); - * } - * }); - * ``` - * - * ## OPTIONS - * - * [--uploads] - * : Also delete *all* files in the site's in the uploads directory. - * - * [--yes] - * : Proceed to empty the site without a confirmation prompt. - * - * ## EXAMPLES - * - * $ wp site empty - * Are you sure you want to empty the site at http://www.example.com of all posts, comments, and terms? [y/n] y - * Success: The site at 'http://www.example.com' was emptied. - * - * @subcommand empty - */ - public function _empty( $args, $assoc_args ) { - - $upload_message = ''; - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'uploads' ) ) { - $upload_message = ', and delete its uploads directory'; - } - - WP_CLI::confirm( "Are you sure you want to empty the site at '" . site_url() . "' of all posts, comments, and terms" . $upload_message . "?", $assoc_args ); - - $this->_empty_posts(); - $this->_empty_comments(); - $this->_empty_taxonomies(); - $this->_insert_default_terms(); - - if ( ! empty( $upload_message ) ) { - $upload_dir = wp_upload_dir(); - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $upload_dir['basedir'], RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - - $files_to_unlink = $directories_to_delete = array(); - foreach ( $files as $fileinfo ) { - $realpath = $fileinfo->getRealPath(); - // Don't clobber subsites when operating on the main site - if ( is_main_site() && false !== stripos( $realpath, '/sites/' ) ) { - continue; - } - if ( $fileinfo->isDir() ) { - $directories_to_delete[] = $realpath; - } else { - $files_to_unlink[] = $realpath; - } - } - foreach( $files_to_unlink as $file ) { - unlink( $file ); - } - foreach( $directories_to_delete as $directory ) { - rmdir( $directory ); - } - rmdir( $upload_dir['basedir'] ); - } - - WP_CLI::success( "The site at '" . site_url() . "' was emptied." ); - } - - /** - * Delete a site in a multisite install. - * - * ## OPTIONS - * - * [<site-id>] - * : The id of the site to delete. If not provided, you must set the --slug parameter. - * - * [--slug=<slug>] - * : Path of the blog to be deleted. Subdomain on subdomain installs, directory on subdirectory installs. - * - * [--yes] - * : Answer yes to the confirmation message. - * - * [--keep-tables] - * : Delete the blog from the list, but don't drop it's tables. - * - * ## EXAMPLES - * - * $ wp site delete 123 - * Are you sure you want to delete the http://www.example.com/example site? [y/n] y - * Success: The site at 'http://www.example.com/example' was deleted. - */ - function delete( $args, $assoc_args ) { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - if ( isset( $assoc_args['slug'] ) ) { - $blog = get_blog_details( trim( $assoc_args['slug'], '/' ) ); - } else { - if ( empty( $args ) ) { - WP_CLI::error( "Need to specify a blog id." ); - } - - $blog_id = $args[0]; - - $blog = get_blog_details( $blog_id ); - } - - if ( !$blog ) { - WP_CLI::error( "Site not found." ); - } - - $site_url = trailingslashit( $blog->siteurl ); - - WP_CLI::confirm( "Are you sure you want to delete the '$site_url' site?", $assoc_args ); - - wpmu_delete_blog( $blog->blog_id, ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'keep-tables' ) ); - - WP_CLI::success( "The site at '$site_url' was deleted." ); - } - - /** - * Create a site in a multisite install. - * - * ## OPTIONS - * - * --slug=<slug> - * : Path for the new site. Subdomain on subdomain installs, directory on subdirectory installs. - * - * [--title=<title>] - * : Title of the new site. Default: prettified slug. - * - * [--email=<email>] - * : Email for Admin user. User will be created if none exists. Assignement to Super Admin if not included. - * - * [--network_id=<network-id>] - * : Network to associate new site with. Defaults to current network (typically 1). - * - * [--private] - * : If set, the new site will be non-public (not indexed) - * - * [--porcelain] - * : If set, only the site id will be output on success. - * - * ## EXAMPLES - * - * $ wp site create --slug=example - * Success: Site 3 created: http://www.example.com/example/ - */ - public function create( $_, $assoc_args ) { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - global $wpdb, $current_site; - - $base = $assoc_args['slug']; - $title = \WP_CLI\Utils\get_flag_value( $assoc_args, 'title', ucfirst( $base ) ); - - $email = empty( $assoc_args['email'] ) ? '' : $assoc_args['email']; - - // Network - if ( !empty( $assoc_args['network_id'] ) ) { - $network = $this->_get_network( $assoc_args['network_id'] ); - if ( $network === false ) { - WP_CLI::error( sprintf( 'Network with id %d does not exist.', $assoc_args['network_id'] ) ); - } - } - else { - $network = $current_site; - } - - $public = ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'private' ); - - // Sanitize - if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) { - $base = strtolower( $base ); - } - - // If not a subdomain install, make sure the domain isn't a reserved word - if ( !is_subdomain_install() ) { - $subdirectory_reserved_names = apply_filters( 'subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' ) ); - if ( in_array( $base, $subdirectory_reserved_names ) ) { - WP_CLI::error( 'The following words are reserved and cannot be used as blog names: ' . implode( ', ', $subdirectory_reserved_names ) ); - } - } - - // Check for valid email, if not, use the first Super Admin found - // Probably a more efficient way to do this so we dont query for the - // User twice if super admin - $email = sanitize_email( $email ); - if ( empty( $email ) || !is_email( $email ) ) { - $super_admins = get_super_admins(); - $email = ''; - if ( !empty( $super_admins ) && is_array( $super_admins ) ) { - // Just get the first one - $super_login = $super_admins[0]; - $super_user = get_user_by( 'login', $super_login ); - if ( $super_user ) { - $email = $super_user->user_email; - } - } - } - - if ( is_subdomain_install() ) { - $newdomain = $base . '.' . preg_replace( '|^www\.|', '', $current_site->domain ); - $path = $current_site->path; - $url = $newdomain; - } else { - $newdomain = $current_site->domain; - $path = $current_site->path . $base . '/'; - $url = $newdomain . $path; - } - - $user_id = email_exists( $email ); - if ( !$user_id ) { // Create a new user with a random password - $password = wp_generate_password( 12, false ); - $user_id = wpmu_create_user( $base, $password, $email ); - if ( false == $user_id ) { - WP_CLI::error( "Can't create user." ); - } - else { - wp_new_user_notification( $user_id, $password ); - } - } - - $wpdb->hide_errors(); - $title = wp_slash( $title ); - $id = wpmu_create_blog( $newdomain, $path, $title, $user_id, array( 'public' => $public ), $network->id ); - $wpdb->show_errors(); - if ( !is_wp_error( $id ) ) { - if ( !is_super_admin( $user_id ) && !get_user_option( 'primary_blog', $user_id ) ) { - update_user_option( $user_id, 'primary_blog', $id, true ); - } - // Prevent mailing admins of new sites - // @TODO argument to pass in? - // $content_mail = sprintf(__( "New site created by WP Command Line Interface\n\nAddress: %2s\nName: %3s"), get_site_url($id), stripslashes($title)); - // wp_mail(get_site_option('admin_email'), sprintf(__('[%s] New Site Created'), $current_site->site_name), $content_mail, 'From: "Site Admin" <'.get_site_option( 'admin_email').'>'); - } - else { - WP_CLI::error( $id->get_error_message() ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { - WP_CLI::line( $id ); - } else { - $site_url = trailingslashit( get_site_url( $id ) ); - WP_CLI::success( "Site $id created: $site_url" ); - } - } - - /** - * Get network data for a given id. - * - * @param int $network_id - * @return bool|array False if no network found with given id, array otherwise - */ - private function _get_network( $network_id ) { - global $wpdb; - - // Load network data - $networks = $wpdb->get_results( $wpdb->prepare( - "SELECT * FROM $wpdb->site WHERE id = %d", $network_id ) ); - - if ( !empty( $networks ) ) { - // Only care about domain and path which are set here - return $networks[0]; - } - - return false; - } - - /** - * List all sites in a multisite install. - * - * ## OPTIONS - * - * [--network=<id>] - * : The network to which the sites belong. - * - * [--<field>=<value>] - * : Filter by one or more fields (see "Available Fields" section). However, - * 'url' isn't an available filter, because it's created from domain + path. - * - * [--site__in=<value>] - * : Only list the sites with these blog_id values (comma-separated). - * - * [--field=<field>] - * : Prints the value of a single field for each site. - * - * [--fields=<fields>] - * : Comma-separated list of fields to show. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - count - * - ids - * - json - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each site: - * - * * blog_id - * * url - * * last_updated - * * registered - * - * These fields are optionally available: - * - * * site_id - * * domain - * * path - * * public - * * archived - * * mature - * * spam - * * deleted - * * lang_id - * - * ## EXAMPLES - * - * # Output a simple list of site URLs - * $ wp site list --field=url - * http://www.example.com/ - * http://www.example.com/subdir/ - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - global $wpdb; - - if ( isset( $assoc_args['fields'] ) ) { - $assoc_args['fields'] = preg_split( '/,[ \t]*/', $assoc_args['fields'] ); - } - - $defaults = array( - 'format' => 'table', - 'fields' => array( 'blog_id', 'url', 'last_updated', 'registered' ), - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $where = array(); - $append = ''; - - $site_cols = array( 'blog_id', 'last_updated', 'registered', 'site_id', 'domain', 'path', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' ); - foreach( $site_cols as $col ) { - if ( isset( $assoc_args[ $col ] ) ) { - $where[ $col ] = $assoc_args[ $col ]; - } - } - - if ( isset( $assoc_args['site__in'] ) ) { - $where['blog_id'] = explode( ',', $assoc_args['site__in'] ); - $append = "ORDER BY FIELD( blog_id, " . implode( ',', array_map( 'intval', $where['blog_id'] ) ) . " )"; - } - - if ( isset( $assoc_args['network'] ) ) { - $where['site_id'] = $assoc_args['network']; - } - - $iterator_args = array( - 'table' => $wpdb->blogs, - 'where' => $where, - 'append' => $append, - ); - $it = new \WP_CLI\Iterators\Table( $iterator_args ); - - $it = \WP_CLI\Utils\iterator_map( $it, function( $blog ) { - $blog->url = trailingslashit( get_site_url( $blog->blog_id ) ); - return $blog; - } ); - - if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { - $sites = iterator_to_array( $it ); - $ids = wp_list_pluck( $sites, 'blog_id' ); - $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); - $formatter->display_items( $ids ); - } - else { - $formatter = new \WP_CLI\Formatter( $assoc_args, null, 'site' ); - $formatter->display_items( $it ); - } - } - - /** - * Archive one or more sites. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to archive. - * - * ## EXAMPLES - * - * $ wp site archive 123 - * Success: Site 123 archived. - */ - public function archive( $args ) { - $this->update_site_status( $args, 'archived', 1 ); - } - - /** - * Unarchive one or more sites. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to unarchive. - * - * ## EXAMPLES - * - * $ wp site unarchive 123 - * Success: Site 123 unarchived. - */ - public function unarchive( $args ) { - $this->update_site_status( $args, 'archived', 0 ); - } - - /** - * Activate one or more sites. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to activate. - * - * ## EXAMPLES - * - * $ wp site activate 123 - * Success: Site 123 activated. - */ - public function activate( $args ) { - $this->update_site_status( $args, 'deleted', 0 ); - } - - /** - * Deactivate one or more sites. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to deactivate. - * - * ## EXAMPLES - * - * $ wp site deactivate 123 - * Success: Site 123 deactivated. - */ - public function deactivate( $args ) { - $this->update_site_status( $args, 'deleted', 1 ); - } - - /** - * Mark one or more sites as spam. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to be marked as spam. - * - * ## EXAMPLES - * - * $ wp site spam 123 - * Success: Site 123 marked as spam. - */ - public function spam( $args ) { - $this->update_site_status( $args, 'spam', 1 ); - } - - /** - * Remove one or more sites from spam. - * - * ## OPTIONS - * - * <id>... - * : One or more IDs of sites to remove from spam. - * - * ## EXAMPLES - * - * $ wp site unspam 123 - * Success: Site 123 removed from spam. - * - * @subcommand unspam - */ - public function unspam( $args ) { - $this->update_site_status( $args, 'spam', 0 ); - } - - private function update_site_status( $ids, $pref, $value ) { - if ( $pref == 'archived' && $value == 1 ) { - $action = 'archived'; - } else if ( $pref == 'archived' && $value == 0) { - $action = 'unarchived'; - } else if ( $pref == 'deleted' && $value == 1 ) { - $action = 'deactivated'; - } else if ( $pref == 'deleted' && $value == 0 ) { - $action = 'activated'; - } else if ( $pref == 'spam' && $value == 1 ) { - $action = 'marked as spam'; - } else if ( $pref == 'spam' && $value == 0 ) { - $action = 'removed from spam'; - } - - foreach ( $ids as $site_id ) { - $site = $this->fetcher->get_check( $site_id ); - - if ( is_main_site( $site->blog_id ) ) { - WP_CLI::warning( "You are not allowed to change the main site." ); - continue; - } - - $old_value = get_blog_status( $site->blog_id, $pref ); - - if ( $value == $old_value ) { - WP_CLI::warning( "Site {$site->blog_id} already {$action}." ); - continue; - } - - update_blog_status( $site->blog_id, $pref, $value ); - WP_CLI::success( "Site {$site->blog_id} {$action}." ); - } - } -} - -WP_CLI::add_command( 'site', 'Site_Command' ); diff --git a/php/commands/super-admin.php b/php/commands/super-admin.php deleted file mode 100644 index 4c79be9f4..000000000 --- a/php/commands/super-admin.php +++ /dev/null @@ -1,173 +0,0 @@ -<?php - -/** - * Manage super admins on WordPress multisite. - * - * ## EXAMPLES - * - * # List user with super-admin capabilities - * $ wp super-admin list - * supervisor - * administrator - * - * # Grant super-admin privileges to the user. - * $ wp super-admin add superadmin2 - * Success: Granted super-admin capabilities. - * - * # Revoke super-admin privileges to the user. - * $ wp super-admin remove superadmin2 - * Success: Revoked super-admin capabilities. - * - * @package wp-cli - */ -class Super_Admin_Command extends WP_CLI_Command { - - private $fields = array( - 'user_login' - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * List users with super admin capabilities. - * - * ## OPTIONS - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: list - * options: - * - list - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * # List user with super-admin capabilities - * $ wp super-admin list - * supervisor - * administrator - * - * @subcommand list - */ - public function _list( $_, $assoc_args ) { - $super_admins = self::get_admins(); - - if ( 'list' === $assoc_args['format'] ) { - foreach ( $super_admins as $user_login ) { - WP_CLI::line( $user_login ); - } - } - else { - $output_users = array(); - foreach ( $super_admins as $user_login ) { - $output_user = new stdClass; - - $output_user->user_login = $user_login; - - $output_users[] = $output_user; - } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_users ); - } - } - - /** - * Grant super admin privileges to one or more users. - * - * ## OPTIONS - * - * <user>... - * : One or more user IDs, user emails, or user logins. - * - * ## EXAMPLES - * - * $ wp super-admin add superadmin2 - * Success: Granted super-admin capabilities. - */ - public function add( $args, $_ ) { - - $successes = $errors = 0; - $users = $this->fetcher->get_many( $args ); - if ( count( $users ) != count( $args ) ) { - $errors = count( $args ) - count( $users ); - } - $user_logins = wp_list_pluck( $users, 'user_login' ); - $super_admins = self::get_admins(); - $num_super_admins = count( $super_admins ); - - foreach ( $user_logins as $user_login ) { - if ( in_array( $user_login, $super_admins ) ) { - WP_CLI::warning( "User '{$user_login}' already has super-admin capabilities." ); - continue; - } - - $super_admins[] = $user_login; - $successes++; - } - - if ( $num_super_admins === count( $super_admins ) ) { - if ( $errors ) { - $user_count = count( $args ); - WP_CLI::error( "Couldn't grant super-admin capabilities to {$errors} of {$user_count} users." ); - } else { - WP_CLI::success( 'Super admins remain unchanged.' ); - } - } else { - if ( update_site_option( 'site_admins' , $super_admins ) ) { - if ( $errors ) { - $user_count = count( $args ); - WP_CLI::error( "Only granted super-admin capabilities to {$successes} of {$user_count} users." ); - } else { - $message = $successes > 1 ? 'users' : 'user'; - WP_CLI::success( "Granted super-admin capabilities to {$successes} {$message}." ); - } - } else { - WP_CLI::error( 'Site options update failed.' ); - } - } - } - - /** - * Remove super admin privileges from one or more users. - * - * ## OPTIONS - * - * <user>... - * : One or more user IDs, user emails, or user logins. - * - * ## EXAMPLES - * - * $ wp super-admin remove superadmin2 - * Success: Revoked super-admin capabilities. - */ - public function remove( $args, $_ ) { - $users = $this->fetcher->get_many( $args ); - $user_logins = wp_list_pluck( $users, 'user_login' ); - - $super_admins = self::get_admins(); - $super_admins = array_diff( $super_admins, $user_logins ); - update_site_option( 'site_admins' , $super_admins ); - WP_CLI::success( 'Revoked super-admin capabilities.' ); - } - - private static function get_admins() { - // We don't use get_super_admins() because we don't want to mess with the global - return get_site_option( 'site_admins', array('admin') ); - } -} - -WP_CLI::add_command( 'super-admin', 'Super_Admin_Command', array( - 'before_invoke' => function () { - if ( !is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - } -) ); diff --git a/php/commands/taxonomy.php b/php/commands/taxonomy.php deleted file mode 100644 index 380fac575..000000000 --- a/php/commands/taxonomy.php +++ /dev/null @@ -1,201 +0,0 @@ -<?php -/** - * Manage taxonomies. - * - * ## EXAMPLES - * - * # List all taxonomies with 'post' object type. - * $ wp taxonomy list --object_type=post --fields=name,public - * +-------------+--------+ - * | name | public | - * +-------------+--------+ - * | category | 1 | - * | post_tag | 1 | - * | post_format | 1 | - * +-------------+--------+ - * - * # Get capabilities of 'post_tag' taxonomy. - * $ wp taxonomy get post_tag --field=cap - * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} - * - * @package wp-cli - */ -class Taxonomy_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'label', - 'description', - 'object_type', - 'show_tagcloud', - 'hierarchical', - 'public', - ); - - public function __construct() { - - if ( \WP_CLI\Utils\wp_version_compare( 3.7, '<' ) ) { - // remove description for wp <= 3.7 - $this->fields = array_values( array_diff( $this->fields, array( 'description' ) ) ); - } - - parent::__construct(); - } - - /** - * List registered taxonomies. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : Filter by one or more fields (see get_taxonomies() first parameter for a list of available fields). - * - * [--field=<field>] - * : Prints the value of a single field for each taxonomy. - * - * [--fields=<fields>] - * : Limit the output to specific taxonomy fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each term: - * - * * name - * * label - * * description - * * public - * * hierarchical - * - * There are no optionally available fields. - * - * ## EXAMPLES - * - * # List all taxonomies. - * $ wp taxonomy list --format=csv - * name,label,description,object_type,show_tagcloud,hierarchical,public - * category,Categories,,post,1,1,1 - * post_tag,Tags,,post,1,,1 - * nav_menu,"Navigation Menus",,nav_menu_item,,, - * link_category,"Link Categories",,link,1,, - * post_format,Format,,post,,,1 - * - * # List all taxonomies with 'post' object type. - * $ wp taxonomy list --object_type=post --fields=name,public - * +-------------+--------+ - * | name | public | - * +-------------+--------+ - * | category | 1 | - * | post_tag | 1 | - * | post_format | 1 | - * +-------------+--------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $formatter = $this->get_formatter( $assoc_args ); - - if ( isset( $assoc_args['object_type'] ) ) { - $assoc_args['object_type'] = array( $assoc_args['object_type'] ); - } - - $taxonomies = get_taxonomies( $assoc_args, 'objects' ); - - $taxonomies = array_map( function( $taxonomy ) { - $taxonomy->object_type = implode( ', ', $taxonomy->object_type ); - return $taxonomy; - }, $taxonomies ); - - $formatter->display_items( $taxonomies ); - } - - /** - * Get details about a registered taxonomy. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy slug. - * - * [--field=<field>] - * : Instead of returning the whole taxonomy, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get details of `category` taxonomy. - * $ wp taxonomy get category --fields=name,label,object_type - * +-------------+------------+ - * | Field | Value | - * +-------------+------------+ - * | name | category | - * | label | Categories | - * | object_type | ["post"] | - * +-------------+------------+ - * - * # Get capabilities of 'post_tag' taxonomy. - * $ wp taxonomy get post_tag --field=cap - * {"manage_terms":"manage_categories","edit_terms":"manage_categories","delete_terms":"manage_categories","assign_terms":"edit_posts"} - */ - public function get( $args, $assoc_args ) { - $taxonomy = get_taxonomy( $args[0] ); - - if ( ! $taxonomy ) { - WP_CLI::error( "Taxonomy {$args[0]} doesn't exist." ); - } - - if ( empty( $assoc_args['fields'] ) ) { - $default_fields = array_merge( $this->fields, array( - 'labels', - 'cap' - ) ); - - $assoc_args['fields'] = $default_fields; - } - - $data = array( - 'name' => $taxonomy->name, - 'label' => $taxonomy->label, - 'description' => $taxonomy->description, - 'object_type' => $taxonomy->object_type, - 'show_tagcloud' => $taxonomy->show_tagcloud, - 'hierarchical' => $taxonomy->hierarchical, - 'public' => $taxonomy->public, - 'labels' => $taxonomy->labels, - 'cap' => $taxonomy->cap, - ); - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $data ); - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'taxonomy' ); - } -} - -WP_CLI::add_command( 'taxonomy', 'Taxonomy_Command' ); diff --git a/php/commands/term-meta.php b/php/commands/term-meta.php deleted file mode 100644 index 53483b79a..000000000 --- a/php/commands/term-meta.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -/** - * Manage term custom fields. - * - * ## EXAMPLES - * - * # Set term meta - * $ wp term meta set 123 bio "Mary is a WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Get term meta - * $ wp term meta get 123 bio - * Mary is a WordPress developer. - * - * # Update term meta - * $ wp term meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Delete term meta - * $ wp term meta delete 123 bio - * Success: Deleted custom field. - */ -class Term_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'term'; - - /** - * Check that the term ID exists - * - * @param int - */ - protected function check_object_id( $object_id ) { - $term = get_term( $object_id ); - if ( ! $term ) { - WP_CLI::error( "Could not find the term with ID {$object_id}." ); - } - return $term->term_id; - } - -} - -WP_CLI::add_command( 'term meta', 'Term_Meta_Command', array( - 'before_invoke' => function() { - if ( \WP_CLI\Utils\wp_version_compare( '4.4', '<' ) ) { - WP_CLI::error( "Requires WordPress 4.4 or greater." ); - } - }) -); - diff --git a/php/commands/term.php b/php/commands/term.php deleted file mode 100644 index 0cf6a34fc..000000000 --- a/php/commands/term.php +++ /dev/null @@ -1,580 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage terms. - * - * ## EXAMPLES - * - * # Create a new term. - * $ wp term create category Apple --description="A type of fruit" - * Success: Created category 199. - * - * # Get details about a term. - * $ wp term get category 199 --format=json --fields=term_id,name,slug,count - * {"term_id":199,"name":"Apple","slug":"apple","count":1} - * - * # Update an existing term. - * $ wp term update category 15 --name=Apple - * Success: Term updated. - * - * # Get the term's URL. - * $ wp term list post_tag --include=123 --field=url - * http://example.com/tag/tips-and-tricks - * - * # Delete post category - * $ wp term delete category 15 - * Success: Deleted category 15. - * - * # Recount posts assigned to each categories and tags - * $ wp term recount category post_tag - * Success: Updated category term count - * Success: Updated post_tag term count - * - * @package wp-cli - */ -class Term_Command extends WP_CLI_Command { - - private $fields = array( - 'term_id', - 'term_taxonomy_id', - 'name', - 'slug', - 'description', - 'parent', - 'count', - ); - - /** - * List terms in a taxonomy. - * - * ## OPTIONS - * - * <taxonomy>... - * : List terms of one or more taxonomies - * - * [--<field>=<value>] - * : Filter by one or more fields (see get_terms() $args parameter for a list of fields). - * - * [--field=<field>] - * : Prints the value of a single field for each term. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each term: - * - * * term_id - * * term_taxonomy_id - * * name - * * slug - * * description - * * parent - * * count - * - * These fields are optionally available: - * - * * url - * - * ## EXAMPLES - * - * # List post categories - * $ wp term list category --format=csv - * term_id,term_taxonomy_id,name,slug,description,parent,count - * 2,2,aciform,aciform,,0,1 - * 3,3,antiquarianism,antiquarianism,,0,1 - * 4,4,arrangement,arrangement,,0,1 - * 5,5,asmodeus,asmodeus,,0,1 - * - * # List post tags - * $ wp term list post_tag --fields=name,slug - * +-----------+-------------+ - * | name | slug | - * +-----------+-------------+ - * | 8BIT | 8bit | - * | alignment | alignment-2 | - * | Articles | articles | - * | aside | aside | - * +-----------+-------------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - foreach ( $args as $taxonomy ) { - if ( ! taxonomy_exists( $taxonomy ) ) { - WP_CLI::error( "Taxonomy $taxonomy doesn't exist." ); - } - } - - $formatter = $this->get_formatter( $assoc_args ); - - $defaults = array( - 'hide_empty' => false, - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - if ( ! empty( $assoc_args['term_id'] ) ) { - $term = get_term_by( 'id', $assoc_args['term_id'], $args[0] ); - $terms = array( $term ); - } else if ( ! empty( $assoc_args['include'] ) - && ! empty( $assoc_args['orderby'] ) - && 'include' === $assoc_args['orderby'] - && Utils\wp_version_compare( '4.7', '<' ) ) { - $terms = array(); - $term_ids = explode( ',', $assoc_args['include'] ); - foreach( $term_ids as $term_id ) { - $term = get_term_by( 'id', $term_id, $args[0] ); - if ( $term && ! is_wp_error( $term ) ) { - $terms[] = $term; - } else { - WP_CLI::warning( sprintf( "Invalid term %s.", $term_id ) ); - } - } - } else { - $terms = get_terms( $args, $assoc_args ); - } - - $terms = array_map( function( $term ){ - $term->count = (int)$term->count; - $term->parent = (int)$term->parent; - $term->url = get_term_link( $term ); - return $term; - }, $terms ); - - if ( 'ids' == $formatter->format ) { - $terms = wp_list_pluck( $terms, 'term_id' ); - echo implode( ' ', $terms ); - } else { - $formatter->display_items( $terms ); - } - } - - /** - * Create a new term. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy for the new term. - * - * <term> - * : A name for the new term. - * - * [--slug=<slug>] - * : A unique slug for the new term. Defaults to sanitized version of name. - * - * [--description=<description>] - * : A description for the new term. - * - * [--parent=<term-id>] - * : A parent for the new term. - * - * [--porcelain] - * : Output just the new term id. - * - * ## EXAMPLES - * - * # Create a new category "Apple" with a description. - * $ wp term create category Apple --description="A type of fruit" - * Success: Created category 199. - */ - public function create( $args, $assoc_args ) { - - list( $taxonomy, $term ) = $args; - - $defaults = array( - 'slug' => sanitize_title( $term ), - 'description' => '', - 'parent' => 0, - ); - $assoc_args = wp_parse_args( $assoc_args, $defaults ); - - $porcelain = \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ); - unset( $assoc_args['porcelain'] ); - - // Compatibility for < WP 4.0 - if ( $assoc_args['parent'] > 0 && ! term_exists( (int) $assoc_args['parent'] ) ) { - WP_CLI::error( 'Parent term does not exist.' ); - } - - $assoc_args = wp_slash( $assoc_args ); - $term = wp_slash( $term ); - $ret = wp_insert_term( $term, $taxonomy, $assoc_args ); - - if ( is_wp_error( $ret ) ) { - WP_CLI::error( $ret->get_error_message() ); - } else { - if ( $porcelain ) - WP_CLI::line( $ret['term_id'] ); - else - WP_CLI::success( sprintf( "Created %s %d.", $taxonomy, $ret['term_id'] ) ); - } - } - - /** - * Get details about a term. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy of the term to get - * - * <term-id> - * : ID of the term to get - * - * [--field=<field>] - * : Instead of returning the whole term, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get details about a category with id 199. - * $ wp term get category 199 --format=json - * {"term_id":199,"name":"Apple","slug":"apple","term_group":0,"term_taxonomy_id":199,"taxonomy":"category","description":"A type of fruit","parent":0,"count":0,"filter":"raw"} - */ - public function get( $args, $assoc_args ) { - - list( $taxonomy, $term_id ) = $args; - $term = get_term_by( 'id', $term_id, $taxonomy ); - if ( ! $term ) { - WP_CLI::error( "Term doesn't exist." ); - } - - if ( empty( $assoc_args['fields'] ) ) { - $term_array = get_object_vars( $term ); - $assoc_args['fields'] = array_keys( $term_array ); - } - - $term->count = (int) $term->count; - $term->parent = (int) $term->parent; - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $term ); - } - - /** - * Update an existing term. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy of the term to update. - * - * <term-id> - * : ID for the term to update. - * - * [--name=<name>] - * : A new name for the term. - * - * [--slug=<slug>] - * : A new slug for the term. - * - * [--description=<description>] - * : A new description for the term. - * - * [--parent=<term-id>] - * : A new parent for the term. - * - * ## EXAMPLES - * - * # Change category with id 15 to use the name "Apple" - * $ wp term update category 15 --name=Apple - * Success: Term updated. - */ - public function update( $args, $assoc_args ) { - - list( $taxonomy, $term_id ) = $args; - - $defaults = array( - 'name' => null, - 'slug' => null, - 'description' => null, - 'parent' => null, - ); - $assoc_args = wp_parse_args( $assoc_args, $defaults ); - - foreach( $assoc_args as $key => $value ) { - if ( is_null( $value ) ) - unset( $assoc_args[$key] ); - } - - $assoc_args = wp_slash( $assoc_args ); - $ret = wp_update_term( $term_id, $taxonomy, $assoc_args ); - - if ( is_wp_error( $ret ) ) - WP_CLI::error( $ret->get_error_message() ); - else - WP_CLI::success( "Term updated." ); - } - - /** - * Delete an existing term. - * - * Errors if the term doesn't exist, or there was a problem in deleting it. - * - * ## OPTIONS - * - * <taxonomy> - * : Taxonomy of the term to delete. - * - * <term-id>... - * : One or more IDs of terms to delete. - * - * ## EXAMPLES - * - * # Delete post category - * $ wp term delete category 15 - * Deleted category 15. - * Success: Deleted 1 of 1 terms. - * - * # Delete all post tags - * $ wp term list post_tag --field=term_id | xargs wp term delete post_tag - * Deleted post_tag 159. - * Deleted post_tag 160. - * Deleted post_tag 161. - * Success: Deleted 3 of 3 terms. - */ - public function delete( $args ) { - $taxonomy = array_shift( $args ); - - $successes = $errors = 0; - foreach ( $args as $term_id ) { - $ret = wp_delete_term( $term_id, $taxonomy ); - - if ( is_wp_error( $ret ) ) { - WP_CLI::warning( $ret ); - $errors++; - } else if ( $ret ) { - WP_CLI::log( sprintf( "Deleted %s %d.", $taxonomy, $term_id ) ); - $successes++; - } else { - WP_CLI::warning( sprintf( "%s %d doesn't exist.", $taxonomy, $term_id ) ); - } - } - Utils\report_batch_operation_results( 'term', 'delete', count( $args ), $successes, $errors ); - } - - /** - * Generate some terms. - * - * Creates a specified number of new terms with dummy data. - * - * ## OPTIONS - * - * <taxonomy> - * : The taxonomy for the generated terms. - * - * [--count=<number>] - * : How many terms to generate? - * --- - * default: 100 - * --- - * - * [--max_depth=<number>] - * : Generate child terms down to a certain depth. - * --- - * default: 1 - * --- - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: progress - * options: - * - progress - * - ids - * --- - * - * ## EXAMPLES - * - * # Generate post categories. - * $ wp term generate category --count=10 - * Generating terms 100% [=========] 0:02 / 0:02 - * - * # Add meta to every generated term. - * $ wp term generate category --format=ids --count=3 | xargs -d ' ' -I % wp term meta add % foo bar - * Success: Added custom field. - * Success: Added custom field. - * Success: Added custom field. - */ - public function generate( $args, $assoc_args ) { - global $wpdb; - - list ( $taxonomy ) = $args; - - $defaults = array( - 'count' => 100, - 'max_depth' => 1, - ); - - extract( array_merge( $defaults, $assoc_args ), EXTR_SKIP ); - - if ( !taxonomy_exists( $taxonomy ) ) { - WP_CLI::error( sprintf( "'%s' is not a registered taxonomy.", $taxonomy ) ); - } - - $label = get_taxonomy( $taxonomy )->labels->singular_name; - $slug = sanitize_title_with_dashes( $label ); - - $hierarchical = get_taxonomy( $taxonomy )->hierarchical; - - $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); - - $notify = false; - if ( 'progress' === $format ) { - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating terms', $count ); - } - - $previous_term_id = 0; - $current_parent = 0; - $current_depth = 1; - - $max_id = (int) $wpdb->get_var( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy ORDER BY term_taxonomy_id DESC LIMIT 1" ); - - $suspend_cache_invalidation = wp_suspend_cache_invalidation( true ); - $created = array(); - - for ( $i = $max_id + 1; $i <= $max_id + $count; $i++ ) { - - if ( $hierarchical ) { - - if ( $previous_term_id && $this->maybe_make_child() && $current_depth < $max_depth ) { - - $current_parent = $previous_term_id; - $current_depth++; - - } else if ( $this->maybe_reset_depth() ) { - - $current_parent = 0; - $current_depth = 1; - - } - - } - - $args = array( - 'parent' => $current_parent, - 'slug' => $slug . "-$i", - ); - - $name = "$label $i"; - $term = wp_insert_term( $name, $taxonomy, $args ); - if ( is_wp_error( $term ) ) { - WP_CLI::warning( $term ); - } else { - $created[] = $term['term_id']; - $previous_term_id = $term['term_id']; - if ( 'ids' === $format ) { - echo $term['term_id']; - if ( $i < $max_id + $count ) { - echo ' '; - } - } - } - - if ( 'progress' === $format ) { - $notify->tick(); - } - } - - wp_suspend_cache_invalidation( $suspend_cache_invalidation ); - clean_term_cache( $created, $taxonomy ); - - if ( 'progress' === $format ) { - $notify->finish(); - } - } - - /** - * Recalculate number of posts assigned to each term. - * - * In instances where manual updates are made to the terms assigned to - * posts in the database, the number of posts associated with a term - * can become out-of-sync with the actual number of posts. - * - * This command runs wp_update_term_count() on the taxonomy's terms - * to bring the count back to the correct value. - * - * ## OPTIONS - * - * <taxonomy>... - * : One or more taxonomies to recalculate. - * - * ## EXAMPLES - * - * # Recount posts assigned to each categories and tags - * $ wp term recount category post_tag - * Success: Updated category term count. - * Success: Updated post_tag term count. - * - * # Recount all listed taxonomies - * $ wp taxonomy list --field=name | xargs wp term recount - * Success: Updated category term count. - * Success: Updated post_tag term count. - * Success: Updated nav_menu term count. - * Success: Updated link_category term count. - * Success: Updated post_format term count. - */ - public function recount( $args ) { - foreach( $args as $taxonomy ) { - - if ( ! taxonomy_exists( $taxonomy ) ) { - WP_CLI::warning( sprintf( "Taxonomy %s does not exist.", $taxonomy ) ); - } else { - - $terms = get_terms( $taxonomy, array( 'hide_empty' => false ) ); - $term_taxonomy_ids = wp_list_pluck( $terms, 'term_taxonomy_id' ); - - wp_update_term_count( $term_taxonomy_ids, $taxonomy ); - - WP_CLI::success( sprintf( "Updated %s term count.", $taxonomy ) ); - } - - } - } - - private function maybe_make_child() { - // 50% chance of making child term - return ( mt_rand(1, 2) == 1 ); - } - - private function maybe_reset_depth() { - // 10% chance of reseting to root depth - return ( mt_rand(1, 10) == 7 ); - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields, 'term' ); - } -} - -WP_CLI::add_command( 'term', 'Term_Command' ); diff --git a/php/commands/theme-mod.php b/php/commands/theme-mod.php deleted file mode 100644 index 22acea271..000000000 --- a/php/commands/theme-mod.php +++ /dev/null @@ -1,202 +0,0 @@ -<?php - -/** - * Manage theme mods. - * - * ## EXAMPLES - * - * # Set the 'background_color' theme mod to '000000'. - * $ wp theme mod set background_color 000000 - * Success: Theme mod background_color set to 000000 - * - * # Get single theme mod in JSON format. - * $ wp theme mod get background_color --format=json - * [{"key":"background_color","value":"dd3333"}] - * - * # Remove all theme mods. - * $ wp theme mod remove --all - * Success: Theme mods removed. - */ -class Theme_Mod_command extends WP_CLI_Command { - - private $fields = array( - 'key', - 'value' - ); - - /** - * Get one or more theme mods. - * - * ## OPTIONS - * - * [<mod>...] - * : One or more mods to get. - * - * [--field=<field>] - * : Returns the value of a single field. - * - * [--all] - * : List all theme mods - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - json - * - csv - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get all theme mods. - * $ wp theme mod get --all - * +------------------+---------+ - * | key | value | - * +------------------+---------+ - * | background_color | dd3333 | - * | link_color | #dd9933 | - * | main_text_color | #8224e3 | - * +------------------+---------+ - * - * # Get single theme mod in JSON format. - * $ wp theme mod get background_color --format=json - * [{"key":"background_color","value":"dd3333"}] - * - * # Get value of a single theme mod. - * $ wp theme mod get background_color --field=value - * dd3333 - * - * # Get multiple theme mods. - * $ wp theme mod get background_color header_textcolor - * +------------------+--------+ - * | key | value | - * +------------------+--------+ - * | background_color | dd3333 | - * | header_textcolor | | - * +------------------+--------+ - */ - public function get( $args = array(), $assoc_args = array() ) { - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { - WP_CLI::error( "You must specify at least one mod or use --all." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - $args = array(); - } - - $list = array(); - $mods = get_theme_mods(); - if ( ! is_array( $mods ) ) { - // if no mods are set (perhaps new theme), make sure foreach still works - $mods = array(); - } - foreach ( $mods as $k => $v ) { - // if mods were given, skip the others - if ( ! empty( $args ) && ! in_array( $k, $args ) ) continue; - - if ( is_array( $v ) ) { - $list[] = array( 'key' => $k, 'value' => '=>' ); - foreach ( $v as $_k => $_v ) { - $list[] = array( 'key' => " $_k", 'value' => $_v ); - } - } else { - $list[] = array( 'key' => $k, 'value' => $v ); - } - - } - - // For unset mods, show blank value - foreach ( $args as $mod ) { - if ( ! isset( $mods[ $mod ] ) ) { - $list[] = array( 'key' => $mod, 'value' => '' ); - } - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields, 'thememods' ); - $formatter->display_items( $list ); - - } - - /** - * Remove one or more theme mods. - * - * ## OPTIONS - * - * [<mod>...] - * : One or more mods to remove. - * - * [--all] - * : Remove all theme mods. - * - * ## EXAMPLES - * - * # Remove all theme mods. - * $ wp theme mod remove --all - * Success: Theme mods removed. - * - * # Remove single theme mod. - * $ wp theme mod remove background_color - * Success: 1 mod removed. - * - * # Remove multiple theme mods. - * $ wp theme mod remove background_color header_textcolor - * Success: 2 mods removed. - */ - public function remove( $args = array(), $assoc_args = array() ) { - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) { - WP_CLI::error( "You must specify at least one mod or use --all." ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) { - remove_theme_mods(); - WP_CLI::success( 'Theme mods removed.' ); - return; - } - - foreach ( $args as $mod ) { - remove_theme_mod( $mod ); - } - - $count = count( $args ); - $success_message = ( 1 === $count ) ? '%d mod removed.' : '%d mods removed.'; - WP_CLI::success( sprintf( $success_message, $count ) ); - - } - - /** - * Set the value of a theme mod. - * - * ## OPTIONS - * - * <mod> - * : The name of the theme mod to set or update. - * - * <value> - * : The new value. - * - * ## EXAMPLES - * - * # Set theme mod - * $ wp theme mod set background_color 000000 - * Success: Theme mod background_color set to 000000 - */ - public function set( $args = array(), $assoc_args = array() ) { - list( $mod, $value ) = $args; - - set_theme_mod( $mod, $value ); - - if ( $value == get_theme_mod( $mod ) ) { - WP_CLI::success( sprintf( "Theme mod %s set to %s.", $mod, $value ) ); - } else { - WP_CLI::success( sprintf( "Could not update theme mod %s.", $mod ) ); - } - } - -} - -WP_CLI::add_command( 'theme mod', 'Theme_Mod_Command' ); diff --git a/php/commands/theme.php b/php/commands/theme.php deleted file mode 100644 index 94fef1ea2..000000000 --- a/php/commands/theme.php +++ /dev/null @@ -1,776 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage themes. - * - * ## EXAMPLES - * - * # Install the latest version of a theme from wordpress.org and activate - * $ wp theme install twentysixteen --activate - * Installing Twenty Sixteen (1.2) - * Downloading install package from http://downloads.wordpress.org/theme/twentysixteen.1.2.zip... - * Unpacking the package... - * Installing the theme... - * Theme installed successfully. - * Activating 'twentysixteen'... - * Success: Switched to 'Twenty Sixteen' theme. - * - * # Get details of an installed theme - * $ wp theme get twentysixteen --fields=name,title,version - * +---------+----------------+ - * | Field | Value | - * +---------+----------------+ - * | name | Twenty Sixteen | - * | title | Twenty Sixteen | - * | version | 1.2 | - * +---------+----------------+ - * - * # Get status of theme - * $ wp theme status twentysixteen - * Theme twentysixteen details: - * Name: Twenty Sixteen - * Status: Active - * Version: 1.2 - * Author: the WordPress team - * - * @package wp-cli - */ -class Theme_Command extends \WP_CLI\CommandWithUpgrade { - - protected $item_type = 'theme'; - protected $upgrade_refresh = 'wp_update_themes'; - protected $upgrade_transient = 'update_themes'; - - protected $obj_fields = array( - 'name', - 'status', - 'update', - 'version' - ); - - function __construct() { - if ( is_multisite() ) { - $this->obj_fields[] = 'enabled'; - } - parent::__construct(); - - $this->fetcher = new \WP_CLI\Fetchers\Theme; - } - - protected function get_upgrader_class( $force ) { - return $force ? '\\WP_CLI\\DestructiveThemeUpgrader' : 'Theme_Upgrader'; - } - - /** - * See the status of one or all themes. - * - * ## OPTIONS - * - * [<theme>] - * : A particular theme to show the status for. - * - * ## EXAMPLES - * - * $ wp theme status twentysixteen - * Theme twentysixteen details: - * Name: Twenty Sixteen - * Status: Inactive - * Version: 1.2 - * Author: the WordPress team - */ - public function status( $args ) { - if ( isset( $args[0] ) ) { - $theme = $this->fetcher->get_check( $args[0] ); - $errors = $theme->errors(); - if ( is_wp_error( $errors ) ) { - $message = $errors->get_error_message(); - WP_CLI::error( $message ); - } - } - - parent::status( $args ); - } - - /** - * Search the WordPress.org theme directory. - * - * Displays themes in the WordPress.org theme directory matching a given - * search query. - * - * ## OPTIONS - * - * <search> - * : The string to search for. - * - * [--per-page=<per-page>] - * : Optional number of results to display. Defaults to 10. - * - * [--field=<field>] - * : Prints the value of a single field for each theme. - * - * [--fields=<fields>] - * : Ask for specific fields from the API. Defaults to name,slug,author,rating. Acceptable values: - * - * **name**: Theme Name - * **slug**: Theme Slug - * **version**: Current Version Number - * **author**: Theme Author - * **preview_url**: Theme Preview URL - * **screenshot_url**: Theme Screenshot URL - * **rating**: Theme Rating - * **num_ratings**: Number of Theme Ratings - * **homepage**: Theme Author's Homepage - * **description**: Theme Description - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp theme search photo --per-page=6 - * Success: Showing 6 of 203 themes. - * +----------------------+----------------------+--------+ - * | name | slug | rating | - * +----------------------+----------------------+--------+ - * | Photos | photos | 100 | - * | Infinite Photography | infinite-photography | 100 | - * | PhotoBook | photobook | 100 | - * | BG Photo Frame | bg-photo-frame | 0 | - * | fPhotography | fphotography | 0 | - * | Photo Perfect | photo-perfect | 98 | - * +----------------------+----------------------+--------+ - */ - public function search( $args, $assoc_args ) { - parent::_search( $args, $assoc_args ); - } - - protected function status_single( $args ) { - $theme = $this->fetcher->get_check( $args[0] ); - - $status = $this->format_status( $this->get_status( $theme ), 'long' ); - - $version = $theme->get('Version'); - if ( $this->has_update( $theme->get_stylesheet() ) ) - $version .= ' (%gUpdate available%n)'; - - echo WP_CLI::colorize( \WP_CLI\Utils\mustache_render( 'theme-status.mustache', array( - 'slug' => $theme->get_stylesheet(), - 'status' => $status, - 'version' => $version, - 'name' => $theme->get('Name'), - 'author' => $theme->get('Author'), - ) ) ); - } - - protected function get_all_items() { - return $this->get_item_list(); - } - - protected function get_status( $theme ) { - if ( $this->is_active_theme( $theme ) ) { - return 'active'; - } else if ( $theme->get_stylesheet_directory() === get_template_directory() ) { - return 'parent'; - } else { - return 'inactive'; - } - } - - /** - * Activate a theme. - * - * ## OPTIONS - * - * <theme> - * : The theme to activate. - * - * ## EXAMPLES - * - * $ wp theme activate twentysixteen - * Success: Switched to 'Twenty Sixteen' theme. - */ - public function activate( $args = array() ) { - $theme = $this->fetcher->get_check( $args[0] ); - - $errors = $theme->errors(); - if ( is_wp_error( $errors ) ) { - $message = $errors->get_error_message(); - WP_CLI::error( $message ); - } - - $name = $theme->get('Name'); - - if ( 'active' === $this->get_status( $theme ) ) { - WP_CLI::warning( "The '$name' theme is already active." ); - return; - } - - if ( $theme->get_stylesheet() != $theme->get_template() && ! $this->fetcher->get( $theme->get_template() ) ) { - WP_CLI::error( "The '{$theme->get_stylesheet()}' theme cannot be activated without its parent, '{$theme->get_template()}'." ); - } - - switch_theme( $theme->get_template(), $theme->get_stylesheet() ); - - if ( $this->is_active_theme( $theme ) ) { - WP_CLI::success( "Switched to '$name' theme." ); - } else { - WP_CLI::error( "Could not switch to '$name' theme." ); - } - } - - /** - * Enable a theme on a WordPress multisite install. - * - * Permits theme to be activated from the dashboard of a site on a WordPress - * multisite install. - * - * ## OPTIONS - * - * <theme> - * : The theme to enable. - * - * [--network] - * : If set, the theme is enabled for the entire network - * - * [--activate] - * : If set, the theme is activated for the current site. Note that - * the "network" flag has no influence on this. - * - * ## EXAMPLES - * - * # Enable theme - * $ wp theme enable twentysixteen - * Success: Enabled the 'Twenty Sixteen' theme. - * - * # Network enable theme - * $ wp theme enable twentysixteen --network - * Success: Network enabled the 'Twenty Sixteen' theme. - * - * # Network enable and activate theme for current site - * $ wp theme enable twentysixteen --activate - * Success: Enabled the 'Twenty Sixteen' theme. - * Success: Switched to 'Twenty Sixteen' theme. - */ - public function enable( $args, $assoc_args ) { - if ( ! is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - $theme = $this->fetcher->get_check( $args[0] ); - $name = $theme->get( 'Name' ); - - # If the --network flag is set, we'll be calling the (get|update)_site_option functions - $_site = ! empty( $assoc_args['network'] ) ? '_site' : ''; - - # Add the current theme to the allowed themes option or site option - $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); - if ( empty( $allowed_themes ) ) - $allowed_themes = array(); - $allowed_themes[ $theme->get_stylesheet() ] = true; - call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); - - if ( ! empty( $assoc_args['network'] ) ) - WP_CLI::success( "Network enabled the '$name' theme." ); - else - WP_CLI::success( "Enabled the '$name' theme." ); - - # If the --activate flag is set, activate the theme for the current site - if ( ! empty( $assoc_args['activate'] ) ) { - $this->activate( $args ); - } - } - - /** - * Disable a theme on a WordPress multisite install. - * - * Removes ability for a theme to be activated from the dashboard of a site - * on a WordPress multisite install. - * - * ## OPTIONS - * - * <theme> - * : The theme to disable. - * - * [--network] - * : If set, the theme is disabled on the network level. Note that - * individual sites may still have this theme enabled if it was - * enabled for them independently. - * - * ## EXAMPLES - * - * # Disable theme - * $ wp theme disable twentysixteen - * Success: Disabled the 'Twenty Sixteen' theme. - * - * # Disable theme in network level - * $ wp theme disable twentysixteen --network - * Success: Network disabled the 'Twenty Sixteen' theme. - */ - public function disable( $args, $assoc_args ) { - if ( ! is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - - $theme = $this->fetcher->get_check( $args[0] ); - $name = $theme->get( 'Name' ); - - # If the --network flag is set, we'll be calling the (get|update)_site_option functions - $_site = ! empty( $assoc_args['network'] ) ? '_site' : ''; - - # Add the current theme to the allowed themes option or site option - $allowed_themes = call_user_func( "get{$_site}_option", 'allowedthemes' ); - if ( ! empty( $allowed_themes[ $theme->get_stylesheet() ] ) ) - unset( $allowed_themes[ $theme->get_stylesheet() ] ); - call_user_func( "update{$_site}_option", 'allowedthemes', $allowed_themes ); - - if ( ! empty( $assoc_args['network'] ) ) - WP_CLI::success( "Network disabled the '$name' theme." ); - else - WP_CLI::success( "Disabled the '$name' theme." ); - } - - private function is_active_theme( $theme ) { - return $theme->get_stylesheet_directory() == get_stylesheet_directory(); - } - - /** - * Get the path to a theme or to the theme directory. - * - * ## OPTIONS - * - * [<theme>] - * : The theme to get the path to. Path includes "style.css" file. - * If not set, will return the path to the themes directory. - * - * [--dir] - * : If set, get the path to the closest parent directory, instead of the - * theme's "style.css" file. - * - * ## EXAMPLES - * - * # Get theme path - * $ wp theme path - * /var/www/example.com/public_html/wp-content/themes - * - * # Change directory to theme path - * $ cd $(wp theme path) - */ - public function path( $args, $assoc_args ) { - if ( empty( $args ) ) { - $path = WP_CONTENT_DIR . '/themes'; - } else { - $theme = $this->fetcher->get_check( $args[0] ); - - $path = $theme->get_stylesheet_directory(); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'dir' ) ) - $path .= '/style.css'; - } - - WP_CLI::line( $path ); - } - - protected function install_from_repo( $slug, $assoc_args ) { - $api = themes_api( 'theme_information', array( 'slug' => $slug ) ); - - if ( is_wp_error( $api ) ) { - return $api; - } - - if ( isset( $assoc_args['version'] ) ) { - self::alter_api_response( $api, $assoc_args['version'] ); - } - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'force' ) ) { - $theme = wp_get_theme( $slug ); - if ( $theme->exists() ) { - // We know this will fail, so avoid a needless download of the package. - return new WP_Error( 'already_installed', 'Theme already installed.' ); - } - // Clear cache so WP_Theme doesn't create a "missing theme" object. - $cache_hash = md5( $theme->theme_root . '/' . $theme->stylesheet ); - foreach( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key ) { - wp_cache_delete( $key . '-' . $cache_hash, 'themes' ); - } - } - - WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) ); - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'version' ) != 'dev' ) { - WP_CLI::get_http_cache_manager()->whitelist_package( $api->download_link, $this->item_type, $api->slug, $api->version ); - } - $result = $this->get_upgrader( $assoc_args )->install( $api->download_link ); - - return $result; - } - - protected function get_item_list() { - $items = array(); - - if ( is_multisite() ) { - $site_enabled = get_option( 'allowedthemes' ); - if ( empty( $site_enabled ) ) - $site_enabled = array(); - - $network_enabled = get_site_option( 'allowedthemes' ); - if ( empty( $network_enabled ) ) - $network_enabled = array(); - } - - foreach ( wp_get_themes() as $key => $theme ) { - $file = $theme->get_stylesheet_directory(); - $update_info = $this->get_update_info( $theme->get_stylesheet() ); - - $items[ $file ] = array( - 'name' => $key, - 'status' => $this->get_status( $theme ), - 'update' => (bool) $update_info, - 'update_version' => $update_info['new_version'], - 'update_package' => $update_info['package'], - 'version' => $theme->get('Version'), - 'update_id' => $theme->get_stylesheet(), - 'title' => $theme->get('Name'), - 'description' => $theme->get('Description'), - 'author' => $theme->get('Author'), - ); - - if ( is_multisite() ) { - if ( ! empty( $site_enabled[ $key ] ) && ! empty( $network_enabled[ $key ] ) ) - $items[ $file ]['enabled'] = 'network,site'; - elseif ( ! empty( $network_enabled[ $key ] ) ) - $items[ $file ]['enabled'] = 'network'; - elseif ( ! empty( $site_enabled[ $key ] ) ) - $items[ $file ]['enabled'] = 'site'; - else - $items[ $file ]['enabled'] = 'no'; - } - } - - return $items; - } - - protected function filter_item_list( $items, $args ) { - $theme_files = array(); - foreach ( $args as $arg ) { - $theme_files[] = $this->fetcher->get_check( $arg )->get_stylesheet_directory(); - } - - return \WP_CLI\Utils\pick_fields( $items, $theme_files ); - } - - /** - * Install a theme. - * - * ## OPTIONS - * - * <theme|zip|url>... - * : A theme slug, the path to a local zip file, or URL to a remote zip file. - * - * [--version=<version>] - * : If set, get that particular version from wordpress.org, instead of the - * stable version. - * - * [--force] - * : If set, the command will overwrite any installed version of the theme, without prompting - * for confirmation. - * - * [--activate] - * : If set, the theme will be activated immediately after install. - * - * ## EXAMPLES - * - * # Install the latest version from wordpress.org and activate - * $ wp theme install twentysixteen --activate - * Installing Twenty Sixteen (1.2) - * Downloading install package from http://downloads.wordpress.org/theme/twentysixteen.1.2.zip... - * Unpacking the package... - * Installing the theme... - * Theme installed successfully. - * Activating 'twentysixteen'... - * Success: Switched to 'Twenty Sixteen' theme. - * - * # Install from a local zip file - * $ wp theme install ../my-theme.zip - * - * # Install from a remote zip file - * $ wp theme install http://s3.amazonaws.com/bucketname/my-theme.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef - */ - function install( $args, $assoc_args ) { - - $theme_root = get_theme_root(); - if ( $theme_root && ! is_dir( $theme_root ) ) { - wp_mkdir_p( $theme_root ); - register_theme_directory( $theme_root ); - } - - parent::install( $args, $assoc_args ); - } - - /** - * Get details about a theme. - * - * ## OPTIONS - * - * <theme> - * : The theme to get. - * - * [--field=<field>] - * : Instead of returning the whole theme, returns the value of a single field. - * - * [--fields=<fields>] - * : Limit the output to specific fields. Defaults to all fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp theme get twentysixteen --fields=name,title,version - * +---------+----------------+ - * | Field | Value | - * +---------+----------------+ - * | name | Twenty Sixteen | - * | title | Twenty Sixteen | - * | version | 1.2 | - * +---------+----------------+ - */ - public function get( $args, $assoc_args ) { - $theme = $this->fetcher->get_check( $args[0] ); - - $errors = $theme->errors(); - if ( is_wp_error( $errors ) ) { - $message = $errors->get_error_message(); - WP_CLI::error( $message ); - } - - // WP_Theme object employs magic getter, unfortunately - $theme_vars = array( 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', - ); - $theme_obj = new stdClass; - foreach ( $theme_vars as $var ) { - $theme_obj->$var = $theme->$var; - } - - $theme_obj->description = wordwrap( $theme_obj->description ); - - if ( empty( $assoc_args['fields'] ) ) { - $assoc_args['fields'] = $theme_vars; - } - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $theme_obj ); - } - - /** - * Update one or more themes. - * - * ## OPTIONS - * - * [<theme>...] - * : One or more themes to update. - * - * [--all] - * : If set, all themes that have updates will be updated. - * - * [--format=<format>] - * : Output summary as table or summary. Defaults to table. - * - * [--version=<version>] - * : If set, the theme will be updated to the specified version. - * - * [--dry-run] - * : Preview which themes would be updated. - * - * ## EXAMPLES - * - * # Update multiple themes - * $ wp theme update twentyfifteen twentysixteen - * Downloading update from https://downloads.wordpress.org/theme/twentyfifteen.1.5.zip... - * Unpacking the update... - * Installing the latest version... - * Removing the old version of the theme... - * Theme updated successfully. - * Downloading update from https://downloads.wordpress.org/theme/twentysixteen.1.2.zip... - * Unpacking the update... - * Installing the latest version... - * Removing the old version of the theme... - * Theme updated successfully. - * +---------------+-------------+-------------+---------+ - * | name | old_version | new_version | status | - * +---------------+-------------+-------------+---------+ - * | twentyfifteen | 1.4 | 1.5 | Updated | - * | twentysixteen | 1.1 | 1.2 | Updated | - * +---------------+-------------+-------------+---------+ - * Success: Updated 2 of 2 themes. - * - * # Update all themes - * $ wp theme update --all - * - * @alias upgrade - */ - function update( $args, $assoc_args ) { - if ( isset( $assoc_args['version'] ) ) { - foreach ( $this->fetcher->get_many( $args ) as $theme ) { - $r = delete_theme( $theme->stylesheet ); - if ( is_wp_error( $r ) ) { - WP_CLI::warning( $r ); - } else { - $assoc_args['force'] = true; - $this->install( array( $theme->stylesheet ), $assoc_args ); - } - } - } else { - parent::update_many( $args, $assoc_args ); - } - } - - /** - * Check if the theme is installed. - * - * Returns exit code 0 when installed, 1 when uninstalled. - * - * ## OPTIONS - * - * <theme> - * : The theme to check. - * - * ## EXAMPLES - * - * # Check whether theme is installed; exit status 0 if installed, otherwise 1 - * $ wp theme is-installed hello-dolly - * $ echo $? - * 1 - * - * @subcommand is-installed - */ - public function is_installed( $args, $assoc_args = array() ) { - $theme = wp_get_theme( $args[0] ); - - if ( $theme->exists() ) { - WP_CLI::halt( 0 ); - } else { - WP_CLI::halt( 1 ); - } - } - - /** - * Delete a theme. - * - * Removes the theme from the filesystem. - * - * ## OPTIONS - * - * <theme>... - * : One or more themes to delete. - * - * ## EXAMPLES - * - * $ wp theme delete twentytwelve - * Deleted 'twentytwelve' theme. - * Success: Deleted 1 of 1 themes. - * - * @alias uninstall - */ - public function delete( $args ) { - $successes = $errors = 0; - foreach ( $this->fetcher->get_many( $args ) as $theme ) { - $theme_slug = $theme->get_stylesheet(); - - if ( $this->is_active_theme( $theme ) ) { - WP_CLI::warning( "Can't delete the currently active theme: $theme_slug" ); - $errors++; - continue; - } - - $r = delete_theme( $theme_slug ); - - if ( is_wp_error( $r ) ) { - WP_CLI::warning( $r ); - $errors++; - } else { - WP_CLI::log( "Deleted '$theme_slug' theme." ); - $successes++; - } - } - if ( ! $this->chained_command ) { - Utils\report_batch_operation_results( 'theme', 'delete', count( $args ), $successes, $errors ); - } - } - - /** - * Get a list of themes. - * - * ## OPTIONS - * - * [--<field>=<value>] - * : Filter results based on the value of a field. - * - * [--field=<field>] - * : Prints the value of a single field for each theme. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each theme: - * - * * name - * * status - * * update - * * version - * - * These fields are optionally available: - * - * * update_version - * * update_package - * * update_id - * * title - * * description - * - * ## EXAMPLES - * - * # List themes - * $ wp theme list --status=inactive --format=csv - * name,status,update,version - * twentyfourteen,inactive,none,1.7 - * twentysixteen,inactive,available,1.1 - * - * @subcommand list - */ - public function list_( $_, $assoc_args ) { - parent::_list( $_, $assoc_args ); - } -} - -WP_CLI::add_command( 'theme', 'Theme_Command' ); diff --git a/php/commands/transient.php b/php/commands/transient.php deleted file mode 100644 index 30bfe95af..000000000 --- a/php/commands/transient.php +++ /dev/null @@ -1,250 +0,0 @@ -<?php - -/** - * Manage transients. - * - * ## EXAMPLES - * - * # Set transient. - * $ wp transient set sample_key "test data" 3600 - * Success: Transient added. - * - * # Get transient. - * $ wp transient get sample_key - * test data - * - * # Delete transient. - * $ wp transient delete sample_key - * Success: Transient deleted. - * - * # Delete expired transients. - * $ wp transient delete --expired - * Success: 12 expired transients deleted from the database. - * - * # Delete all transients. - * $ wp transient delete --all - * Success: 14 transients deleted from the database. - */ -class Transient_Command extends WP_CLI_Command { - - /** - * Get a transient value. - * - * ## OPTIONS - * - * <key> - * : Key for the transient. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * [--network] - * : Get the value of the network transient, instead of the single site. - * - * ## EXAMPLES - * - * $ wp transient get sample_key - * test data - * - * $ wp transient get random_key - * Warning: Transient with key "random_key" is not set. - */ - public function get( $args, $assoc_args ) { - list( $key ) = $args; - - $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; - $value = $func( $key ); - - if ( false === $value ) { - WP_CLI::warning( 'Transient with key "' . $key . '" is not set.' ); - exit; - } - - WP_CLI::print_value( $value, $assoc_args ); - } - - /** - * Set a transient value. - * - * `<expiration>` is the time until expiration, in seconds. - * - * ## OPTIONS - * - * <key> - * : Key for the transient. - * - * <value> - * : Value to be set for the transient. - * - * [<expiration>] - * : Time until expiration, in seconds. - * - * [--network] - * : Set the transient value on the network, instead of single site. - * - * ## EXAMPLES - * - * $ wp transient set sample_key "test data" 3600 - * Success: Transient added. - */ - public function set( $args, $assoc_args ) { - list( $key, $value ) = $args; - - $expiration = \WP_CLI\Utils\get_flag_value( $args, 2, 0 ); - - $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'set_site_transient' : 'set_transient'; - if ( $func( $key, $value, $expiration ) ) { - WP_CLI::success( 'Transient added.' ); - } else { - WP_CLI::error( 'Transient could not be set.' ); - } - } - - /** - * Delete a transient value. - * - * ## OPTIONS - * - * [<key>] - * : Key for the transient. - * - * [--network] - * : Delete the value of a network transient, instead of that on a single site. - * - * [--all] - * : Delete all transients. - * - * [--expired] - * : Delete all expired transients. - * - * ## EXAMPLES - * - * # Delete transient. - * $ wp transient delete sample_key - * Success: Transient deleted. - * - * # Delete expired transients. - * $ wp transient delete --expired - * Success: 12 expired transients deleted from the database. - * - * # Delete all transients. - * $ wp transient delete --all - * Success: 14 transients deleted from the database. - */ - public function delete( $args, $assoc_args ) { - $key = ( ! empty( $args ) ) ? $args[0] : NULL; - - $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); - $expired = \WP_CLI\Utils\get_flag_value( $assoc_args, 'expired' ); - - if ( true === $all ) { - $this->delete_all(); - return; - } - else if ( true === $expired ) { - $this->delete_expired(); - return; - } - - if ( ! $key ) { - WP_CLI::error( 'Please specify transient key, or use --all or --expired.' ); - } - - $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'delete_site_transient' : 'delete_transient'; - - if ( $func( $key ) ) { - WP_CLI::success( 'Transient deleted.' ); - } else { - $func = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; - if ( $func( $key ) ) - WP_CLI::error( 'Transient was not deleted even though the transient appears to exist.' ); - else - WP_CLI::warning( 'Transient was not deleted; however, the transient does not appear to exist.' ); - } - } - - /** - * Determine type of transients implementation. - * - * Indicates whether the transients API is using an object cache or the - * options table. - * - * ## EXAMPLES - * - * $ wp transient type - * Transients are saved to the wp_options table. - */ - public function type() { - global $_wp_using_ext_object_cache, $wpdb; - - if ( $_wp_using_ext_object_cache ) - $message = 'Transients are saved to the object cache.'; - else - $message = 'Transients are saved to the ' . $wpdb->prefix . 'options table.'; - - WP_CLI::line( $message ); - } - - /** - * Delete all expired transients. - */ - private function delete_expired() { - global $wpdb, $_wp_using_ext_object_cache; - - // Always delete all transients from DB too. - $time = current_time('timestamp'); - $count = $wpdb->query( - "DELETE a, b FROM $wpdb->options a, $wpdb->options b WHERE - a.option_name LIKE '\_transient\_%' AND - a.option_name NOT LIKE '\_transient\_timeout\_%' AND - b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) ) - AND b.option_value < $time" - ); - - if ( $count > 0 ) { - WP_CLI::success( "$count expired transients deleted from the database." ); - } else { - WP_CLI::success( "No expired transients found." ); - } - - if ( $_wp_using_ext_object_cache ) { - WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); - } - } - - /** - * Delete all transients. - */ - private function delete_all() { - global $wpdb, $_wp_using_ext_object_cache; - - // Always delete all transients from DB too. - $count = $wpdb->query( - "DELETE FROM $wpdb->options - WHERE option_name LIKE '\_transient\_%' - OR option_name LIKE '\_site\_transient\_%'" - ); - - if ( $count > 0 ) { - WP_CLI::success( "$count transients deleted from the database." ); - } else { - WP_CLI::success( "No transients found." ); - } - - if ( $_wp_using_ext_object_cache ) { - WP_CLI::warning( 'Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.'); - } - } - -} - -WP_CLI::add_command( 'transient', 'Transient_Command' ); - diff --git a/php/commands/user-meta.php b/php/commands/user-meta.php deleted file mode 100644 index fbc4e666c..000000000 --- a/php/commands/user-meta.php +++ /dev/null @@ -1,213 +0,0 @@ -<?php - -/** - * Manage user custom fields. - * - * ## EXAMPLES - * - * # Add user meta - * $ wp user meta add 123 bio "Mary is an WordPress developer." - * Success: Added custom field. - * - * # List user meta - * $ wp user meta list 123 --keys=nickname,description,wp_capabilities - * +---------+-----------------+--------------------------------+ - * | user_id | meta_key | meta_value | - * +---------+-----------------+--------------------------------+ - * | 123 | nickname | supervisor | - * | 123 | description | Mary is a WordPress developer. | - * | 123 | wp_capabilities | {"administrator":true} | - * +---------+-----------------+--------------------------------+ - * - * # Update user meta - * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * # Delete user meta - * $ wp user meta delete 123 bio - * Success: Deleted custom field. - */ -class User_Meta_Command extends \WP_CLI\CommandWithMeta { - protected $meta_type = 'user'; - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * List all metadata associated with a user. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to get metadata for. - * - * [--keys=<keys>] - * : Limit output to metadata of specific keys. - * - * [--fields=<fields>] - * : Limit the output to specific row fields. Defaults to id,meta_key,meta_value. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * # List user meta - * $ wp user meta list 123 --keys=nickname,description,wp_capabilities - * +---------+-----------------+--------------------------------+ - * | user_id | meta_key | meta_value | - * +---------+-----------------+--------------------------------+ - * | 123 | nickname | supervisor | - * | 123 | description | Mary is a WordPress developer. | - * | 123 | wp_capabilities | {"administrator":true} | - * +---------+-----------------+--------------------------------+ - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::list_( $args, $assoc_args ); - } - - /** - * Get meta field value. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to get metadata for. - * - * <key> - * : The metadata key. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get user meta - * $ wp user meta get 123 bio - * Mary is an WordPress developer. - */ - public function get( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::get( $args, $assoc_args ); - } - - /** - * Delete a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to delete metadata from. - * - * <key> - * : The metadata key. - * - * [<value>] - * : The value to delete. If omitted, all rows with key will deleted. - * - * ## EXAMPLES - * - * # Delete user meta - * $ wp user meta delete 123 bio - * Success: Deleted custom field. - */ - public function delete( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::delete( $args, $assoc_args ); - } - - /** - * Add a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to add metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * [--format=<format>] - * : The serialization format for the value. Default is plaintext. - * - * ## EXAMPLES - * - * # Add user meta - * $ wp user meta add 123 bio "Mary is an WordPress developer." - * Success: Added custom field. - */ - public function add( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::add( $args, $assoc_args ); - } - - /** - * Update a meta field. - * - * ## OPTIONS - * - * <user> - * : The user login, user email, or user ID of the user to update metadata for. - * - * <key> - * : The metadata key. - * - * <value> - * : The new metadata value. - * - * [--format=<format>] - * : The serialization format for the value. Default is plaintext. - * - * ## EXAMPLES - * - * # Update user meta - * $ wp user meta update 123 bio "Mary is an awesome WordPress developer." - * Success: Updated custom field 'bio'. - * - * @alias set - */ - public function update( $args, $assoc_args ) { - $args = $this->replace_login_with_user_id( $args ); - parent::update( $args, $assoc_args ); - } - - /** - * Replace user_login value with user ID - * user meta is a special case that also supports user_login - * - * @param array - * @return array - */ - private function replace_login_with_user_id( $args ) { - $user = $this->fetcher->get_check( $args[0] ); - $args[0] = $user->ID; - return $args; - } - -} - -WP_CLI::add_command( 'user meta', 'User_Meta_Command' ); diff --git a/php/commands/user-session.php b/php/commands/user-session.php deleted file mode 100644 index 5d5445a7a..000000000 --- a/php/commands/user-session.php +++ /dev/null @@ -1,196 +0,0 @@ -<?php - -/** - * Manage a user's sessions. - * - * ## EXAMPLES - * - * # List a user's sessions. - * $ wp user session list admin@example.com --format=csv - * login_time,expiration_time,ip,ua - * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." - * - * # Destroy the most recent session of the given user. - * $ wp user session destroy admin - * Success: Destroyed session. 3 sessions remaining. - * - * @package wp-cli - */ -class User_Session_Command extends WP_CLI_Command { - - private $fields = array( - 'token', - 'login_time', - 'expiration_time', - 'ip', - 'ua', - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * Destroy a session for the given user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [<token>] - * : The token of the session to destroy. Defaults to the most recently created session. - * - * [--all] - * : Destroy all of the user's sessions. - * - * ## EXAMPLES - * - * # Destroy the most recent session of the given user. - * $ wp user session destroy admin - * Success: Destroyed session. 3 sessions remaining. - * - * # Destroy a specific session of the given user. - * $ wp user session destroy admin e073ad8540a9c2... - * Success: Destroyed session. 2 sessions remaining. - * - * # Destroy all the sessions of the given user. - * $ wp user session destroy admin --all - * Success: Destroyed all sessions. - * - * # Destroy all sessions for all users. - * $ wp user list --field=ID | xargs wp user session destroy --all - * Success: Destroyed all sessions. - * Success: Destroyed all sessions. - */ - public function destroy( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $token = \WP_CLI\Utils\get_flag_value( $args, 1, null ); - $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); - $manager = WP_Session_Tokens::get_instance( $user->ID ); - - if ( $token && $all ) { - WP_CLI::error( 'The --all flag cannot be specified along with a session token.' ); - } - - if ( $all ) { - $manager->destroy_all(); - WP_CLI::success( 'Destroyed all sessions.' ); - return; - } - - $sessions = $this->get_all_sessions( $manager ); - - if ( ! $token ) { - if ( empty( $sessions ) ) { - WP_CLI::success( 'No sessions to destroy.' ); - } - $last = end( $sessions ); - $token = $last['token']; - } - - if ( ! isset( $sessions[ $token ] ) ) { - WP_CLI::error( 'Session not found.' ); - } - - $this->destroy_session( $manager, $token ); - $remaining = count( $manager->get_all() ); - - WP_CLI::success( sprintf( 'Destroyed session. %s remaining.', $remaining ) ); - } - - /** - * List sessions for the given user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [--fields=<fields>] - * : Limit the output to specific fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * - count - * - ids - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each session: - * - * * token - * * login_time - * * expiration_time - * * ip - * * ua - * - * These fields are optionally available: - * - * * expiration - * * login - * - * ## EXAMPLES - * - * # List a user's sessions. - * $ wp user session list admin@example.com --format=csv - * login_time,expiration_time,ip,ua - * "2016-01-01 12:34:56","2016-02-01 12:34:56",127.0.0.1,"Mozilla/5.0..." - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $formatter = $this->get_formatter( $assoc_args ); - $manager = WP_Session_Tokens::get_instance( $user->ID ); - $sessions = $this->get_all_sessions( $manager ); - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', array_keys( $sessions ) ); - } else { - $formatter->display_items( $sessions ); - } - } - - protected function get_all_sessions( WP_Session_Tokens $manager ) { - // Make the private session data accessible to WP-CLI - $get_sessions = new ReflectionMethod( $manager, 'get_sessions' ); - $get_sessions->setAccessible( true ); - $sessions = $get_sessions->invoke( $manager ); - - array_walk( $sessions, function( & $session, $token ) { - $session['token'] = $token; - $session['login_time'] = date( 'Y-m-d H:i:s', $session['login'] ); - $session['expiration_time'] = date( 'Y-m-d H:i:s', $session['expiration'] ); - } ); - - return $sessions; - } - - protected function destroy_session( WP_Session_Tokens $manager, $token ) { - $update_session = new ReflectionMethod( $manager, 'update_session' ); - $update_session->setAccessible( true ); - return $update_session->invoke( $manager, $token, null ); - } - - private function get_formatter( &$assoc_args ) { - return new \WP_CLI\Formatter( $assoc_args, $this->fields ); - } - -} - -WP_CLI::add_command( 'user session', 'User_Session_Command', array( - 'before_invoke' => function() { - if ( \WP_CLI\Utils\wp_version_compare( '4.0', '<' ) ) { - WP_CLI::error( "Requires WordPress 4.0 or greater." ); - } - }) -); diff --git a/php/commands/user-term.php b/php/commands/user-term.php deleted file mode 100644 index f5406dfc5..000000000 --- a/php/commands/user-term.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -/** - * Manage user terms. - * - * ## EXAMPLES - * - * # Set user terms - * $ wp user term set 123 test category - * Success: Set terms. - */ -class User_Term_Command extends \WP_CLI\CommandWithTerms { - protected $obj_type = 'user'; -} - -WP_CLI::add_command( 'user term', 'User_Term_Command' ); diff --git a/php/commands/user.php b/php/commands/user.php deleted file mode 100644 index c53e04235..000000000 --- a/php/commands/user.php +++ /dev/null @@ -1,951 +0,0 @@ -<?php - -/** - * Manage users. - * - * ## EXAMPLES - * - * # List user IDs - * $ wp user list --field=ID - * 1 - * - * # Create a new user. - * $ wp user create bob bob@example.com --role=author - * Success: Created user 3. - * Password: k9**&I4vNH(& - * - * # Update an existing user. - * $ wp user update 123 --display_name=Mary --user_pass=marypass - * Success: Updated user 123. - * - * # Delete user 123 and reassign posts to user 567 - * $ wp user delete 123 --reassign=567 - * Success: Removed user 123 from http://example.com - * - * @package wp-cli - */ -class User_Command extends \WP_CLI\CommandWithDBObject { - - protected $obj_type = 'user'; - protected $obj_fields = array( - 'ID', - 'user_login', - 'display_name', - 'user_email', - 'user_registered', - 'roles' - ); - - private $cap_fields = array( - 'name' - ); - - public function __construct() { - $this->fetcher = new \WP_CLI\Fetchers\User; - } - - /** - * List users. - * - * ## OPTIONS - * - * [--role=<role>] - * : Only display users with a certain role. - * - * [--<field>=<value>] - * : Control output by one or more arguments of get_users(). - * - * [--network] - * : List all users in the network for multisite. - * - * [--field=<field>] - * : Prints the value of a single field for each user. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each user: - * - * * ID - * * user_login - * * display_name - * * user_email - * * user_registered - * * roles - * - * These fields are optionally available: - * - * * user_pass - * * user_nicename - * * user_url - * * user_activation_key - * * user_status - * * spam - * * deleted - * * caps - * * cap_key - * * allcaps - * * filter - * * url - * - * ## EXAMPLES - * - * # List user IDs - * $ wp user list --field=ID - * 1 - * - * # List users with administrator role - * $ wp user list --role=administrator --format=csv - * ID,user_login,display_name,user_email,user_registered,roles - * 1,supervisor,supervisor,supervisor@gmail.com,"2016-06-03 04:37:00",administrator - * - * # List users with only given fields - * $ wp user list --fields=display_name,user_email --format=json - * [{"display_name":"supervisor","user_email":"supervisor@gmail.com"}] - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) ) { - if ( ! is_multisite() ) { - WP_CLI::error( 'This is not a multisite install.' ); - } - $assoc_args['blog_id'] = 0; - if ( isset( $assoc_args['fields'] ) ) { - $fields = explode( ',', $assoc_args['fields'] ); - $assoc_args['fields'] = array_diff( $fields, array( 'roles' ) ); - } else { - $assoc_args['fields'] = array_diff( $this->obj_fields, array( 'roles' ) ); - } - } - - $formatter = $this->get_formatter( $assoc_args ); - - if ( in_array( $formatter->format, array( 'ids', 'count' ) ) ) { - $assoc_args['fields'] = 'ids'; - } else { - $assoc_args['fields'] = 'all_with_meta'; - } - - $assoc_args['count_total'] = false; - $assoc_args = self::process_csv_arguments_to_arrays( $assoc_args ); - $users = get_users( $assoc_args ); - - if ( 'ids' == $formatter->format ) { - echo implode( ' ', $users ); - } else if ( 'count' === $formatter->format ) { - $formatter->display_items( $users ); - } else { - $it = WP_CLI\Utils\iterator_map( $users, function ( $user ) { - if ( !is_object( $user ) ) - return $user; - - $user->roles = implode( ',', $user->roles ); - $user->url = get_author_posts_url( $user->ID, $user->user_nicename ); - return $user; - } ); - - $formatter->display_items( $it ); - } - } - - /** - * Get details about a user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [--field=<field>] - * : Instead of returning the whole user, returns the value of a single field. - * - * [--fields=<fields>] - * : Get a specific subset of the user's fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - json - * - yaml - * --- - * - * ## EXAMPLES - * - * # Get user - * $ wp user get 12 --field=login - * supervisor - * - * # Get user and export to JSON file - * $ wp user get bob --format=json > bob.json - */ - public function get( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - $user_data = $user->to_array(); - $user_data['roles'] = implode( ', ', $user->roles ); - - $formatter = $this->get_formatter( $assoc_args ); - $formatter->display_item( $user_data ); - } - - /** - * Delete one or more users from the current site. - * - * On multisite, `wp user delete` only removes the user from the current - * site. Include `--network` to also remove the user from the database, but - * make sure to reassign their posts prior to deleting the user. - * - * ## OPTIONS - * - * <user>... - * : The user login, user email, or user ID of the user(s) to delete. - * - * [--network] - * : On multisite, delete the user from the entire network. - * - * [--reassign=<user-id>] - * : User ID to reassign the posts to. - * - * [--yes] - * : Answer yes to any confirmation prompts. - * - * ## EXAMPLES - * - * # Delete user 123 and reassign posts to user 567 - * $ wp user delete 123 --reassign=567 - * Success: Removed user 123 from http://example.com - * - * # Delete all contributors and reassign their posts to user 2 - * $ wp user delete $(wp user list --role=contributor --field=ID) --reassign=2 - * Success: Removed user 813 from http://example.com - * Success: Removed user 578 from http://example.com - */ - public function delete( $args, $assoc_args ) { - $network = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); - $reassign = \WP_CLI\Utils\get_flag_value( $assoc_args, 'reassign' ); - - if ( $network && $reassign ) { - WP_CLI::error('Reassigning content to a different user is not supported on multisite.'); - } - - if ( !$reassign ) { - WP_CLI::confirm( '--reassign parameter not passed. All associated posts will be deleted. Proceed?', $assoc_args ); - } - - $users = $this->fetcher->get_many( $args ); - - parent::_delete( $users, $assoc_args, function ( $user ) use ( $network, $reassign ) { - $user_id = $user->ID; - - if ( $network ) { - $r = wpmu_delete_user( $user_id ); - $message = "Deleted user $user_id."; - } else { - $r = wp_delete_user( $user_id, $reassign ); - $message = "Removed user $user_id from " . home_url() . "."; - } - - if ( $r ) { - return array( 'success', $message ); - } else { - return array( 'error', "Failed deleting user $user_id." ); - } - } ); - } - - /** - * Create a new user. - * - * ## OPTIONS - * - * <user-login> - * : The login of the user to create. - * - * <user-email> - * : The email address of the user to create. - * - * [--role=<role>] - * : The role of the user to create. Default: default role - * - * [--user_pass=<password>] - * : The user password. Default: randomly generated - * - * [--user_registered=<yyyy-mm-dd>] - * : The date the user registered. Default: current date - * - * [--display_name=<name>] - * : The display name. - * - * [--first_name=<first_name>] - * : The user's first name. - * - * [--last_name=<last_name>] - * : The user's last name. - * - * [--send-email] - * : Send an email to the user with their new account details. - * - * [--porcelain] - * : Output just the new user id. - * - * ## EXAMPLES - * - * # Create user - * $ wp user create bob bob@example.com --role=author - * Success: Created user 3. - * Password: k9**&I4vNH(& - */ - public function create( $args, $assoc_args ) { - $user = new stdClass; - - list( $user->user_login, $user->user_email ) = $args; - - $assoc_args = wp_slash( $assoc_args ); - - if ( username_exists( $user->user_login ) ) { - WP_CLI::error( "The '{$user->user_login}' username is already registered." ); - } - - if ( !is_email( $user->user_email ) ) { - WP_CLI::error( "The '{$user->user_email}' email address is invalid." ); - } - - $user->user_registered = \WP_CLI\Utils\get_flag_value( - $assoc_args, - 'user_registered', - strftime( "%F %T", current_time('timestamp') ) - ); - - $user->display_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'display_name', false ); - - $user->first_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'first_name', false ); - - $user->last_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'last_name', false ); - - if ( isset( $assoc_args['user_pass'] ) ) { - $user->user_pass = $assoc_args['user_pass']; - } else { - $user->user_pass = wp_generate_password(); - $generated_pass = true; - } - - $user->role = \WP_CLI\Utils\get_flag_value( $assoc_args, 'role', get_option('default_role') ); - self::validate_role( $user->role ); - - if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - add_filter( 'send_password_change_email', '__return_false' ); - add_filter( 'send_email_change_email', '__return_false' ); - } - - if ( is_multisite() ) { - $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); - if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { - WP_CLI::error( $ret['errors'] ); - } - $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); - if ( ! $user_id ) { - WP_CLI::error( "Unknown error creating new user." ); - } - $user->ID = $user_id; - $user_id = wp_update_user( $user ); - if ( is_wp_error( $user_id ) ) { - WP_CLI::error( $user_id ); - } - } else { - $user_id = wp_insert_user( $user ); - } - - if ( ! $user_id || is_wp_error( $user_id ) ) { - if ( ! $user_id ) { - $user_id = 'Unknown error creating new user.'; - } - WP_CLI::error( $user_id ); - } else { - if ( false === $user->role ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - self::wp_new_user_notification( $user_id, $user->user_pass ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { - WP_CLI::line( $user_id ); - } else { - WP_CLI::success( "Created user $user_id." ); - if ( isset( $generated_pass ) ) - WP_CLI::line( "Password: $user->user_pass" ); - } - } - - /** - * Update an existing user. - * - * ## OPTIONS - * - * <user>... - * : The user login, user email or user ID of the user(s) to update. - * - * --<field>=<value> - * : One or more fields to update. For accepted fields, see wp_update_user(). - * - * ## EXAMPLES - * - * # Update user - * $ wp user update 123 --display_name=Mary --user_pass=marypass - * Success: Updated user 123. - */ - public function update( $args, $assoc_args ) { - if ( isset( $assoc_args['user_login'] ) ) { - WP_CLI::warning( "User logins can't be changed." ); - unset( $assoc_args['user_login'] ); - } - - $user_ids = array(); - foreach ( $this->fetcher->get_many( $args ) as $user ) { - $user_ids[] = $user->ID; - } - - $assoc_args = wp_slash( $assoc_args ); - parent::_update( $user_ids, $assoc_args, 'wp_update_user' ); - } - - /** - * Generate some users. - * - * Creates a specified number of new users with dummy data. - * - * ## OPTIONS - * - * [--count=<number>] - * : How many users to generate? - * --- - * default: 100 - * --- - * - * [--role=<role>] - * : The role of the generated users. Default: default role from WP - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: progress - * options: - * - progress - * - ids - * --- - * - * ## EXAMPLES - * - * # Add meta to every generated users. - * $ wp user generate --format=ids --count=3 | xargs -d ' ' -I % wp user meta add % foo bar - * Success: Added custom field. - * Success: Added custom field. - * Success: Added custom field. - */ - public function generate( $args, $assoc_args ) { - global $blog_id; - - $defaults = array( - 'count' => 100, - 'role' => get_option('default_role'), - ); - $assoc_args = array_merge( $defaults, $assoc_args ); - - $role = $assoc_args['role']; - - if ( ! empty( $role ) ) { - self::validate_role( $role ); - } - - $user_count = count_users(); - $total = $user_count['total_users']; - $limit = $assoc_args['count'] + $total; - - $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'progress' ); - - $notify = false; - if ( 'progress' === $format ) { - $notify = \WP_CLI\Utils\make_progress_bar( 'Generating users', $assoc_args['count'] ); - } - - for ( $i = $total; $i < $limit; $i++ ) { - $login = sprintf( 'user_%d_%d', $blog_id, $i ); - $name = "User $i"; - - $user_id = wp_insert_user( array( - 'user_login' => $login, - 'user_pass' => $login, - 'nickname' => $name, - 'display_name' => $name, - 'role' => $role - ) ); - - if ( false === $role ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - - if ( 'progress' === $format ) { - $notify->tick(); - } else if ( 'ids' === $format ) { - echo $user_id; - if ( $i < $limit - 1 ) { - echo ' '; - } - } - } - - if ( 'progress' === $format ) { - $notify->finish(); - } - } - - /** - * Set the user role. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [<role>] - * : Make the user have the specified role. If not passed, the default role is - * used. - * - * ## EXAMPLES - * - * $ wp user set-role 12 author - * Success: Added johndoe (12) to http://example.com as author. - * - * @subcommand set-role - */ - public function set_role( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - - $role = \WP_CLI\Utils\get_flag_value( $args, 1, get_option('default_role') ); - - self::validate_role( $role ); - - // Multisite - if ( function_exists( 'add_user_to_blog' ) ) - add_user_to_blog( get_current_blog_id(), $user->ID, $role ); - else - $user->set_role( $role ); - - WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}." ); - } - - /** - * Add a role for a user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * <role> - * : Add the specified role to the user. - * - * ## EXAMPLES - * - * $ wp user add-role 12 author - * Success: Added 'author' role for johndoe (12). - * - * @subcommand add-role - */ - public function add_role( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - - $role = $args[1]; - - self::validate_role( $role ); - - $user->add_role( $role ); - - WP_CLI::success( sprintf( "Added '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); - } - - /** - * Remove a user's role. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * [<role>] - * : A specific role to remove. - * - * ## EXAMPLES - * - * $ wp user remove-role 12 author - * Success: Removed 'author' role for johndoe (12). - * - * @subcommand remove-role - */ - public function remove_role( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - - if ( isset( $args[1] ) ) { - $role = $args[1]; - - self::validate_role( $role ); - - $user->remove_role( $role ); - - WP_CLI::success( sprintf( "Removed '%s' role for %s (%d).", $role, $user->user_login, $user->ID ) ); - } else { - // Multisite - if ( function_exists( 'remove_user_from_blog' ) ) - remove_user_from_blog( $user->ID, get_current_blog_id() ); - else - $user->remove_all_caps(); - - WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() . "." ); - } - } - - /** - * Add a capability to a user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * <cap> - * : The capability to add. - * - * ## EXAMPLES - * - * # Add a capability for a user - * $ wp user add-cap john create_premium_item - * Success: Added 'create_premium_item' capability for john (16). - * - * # Add a capability for a user - * $ wp user add-cap 15 edit_product - * Success: Added 'edit_product' capability for johndoe (15). - * - * @subcommand add-cap - */ - public function add_cap( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - if ( $user ) { - $cap = $args[1]; - $user->add_cap( $cap ); - - WP_CLI::success( sprintf( "Added '%s' capability for %s (%d).", $cap, $user->user_login, $user->ID ) ); - } - } - - /** - * Remove a user's capability. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or user login. - * - * <cap> - * : The capability to be removed. - * - * ## EXAMPLES - * - * $ wp user remove-cap 11 publish_newsletters - * Success: Removed 'publish_newsletters' cap for supervisor (11). - * - * @subcommand remove-cap - */ - public function remove_cap( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - if ( $user ) { - $cap = $args[1]; - $user->remove_cap( $cap ); - - WP_CLI::success( sprintf( "Removed '%s' cap for %s (%d).", $cap, $user->user_login, $user->ID ) ); - } - } - - /** - * List all capabilities for a user. - * - * ## OPTIONS - * - * <user> - * : User ID, user email, or login. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: list - * options: - * - list - * - table - * - csv - * - json - * - count - * - yaml - * --- - * - * ## EXAMPLES - * - * $ wp user list-caps 21 - * edit_product - * create_premium_item - * - * @subcommand list-caps - */ - public function list_caps( $args, $assoc_args ) { - $user = $this->fetcher->get_check( $args[0] ); - - if ( $user ) { - $user->get_role_caps(); - - $user_caps_list = $user->allcaps; - - $active_user_cap_list = array(); - - foreach ( $user_caps_list as $cap => $active ) { - if ( $active ) { - $active_user_cap_list[] = $cap; - } - } - - if ( 'list' === $assoc_args['format'] ) { - foreach ( $active_user_cap_list as $cap ) { - WP_CLI::line( $cap ); - } - } - else { - $output_caps = array(); - foreach ( $active_user_cap_list as $cap ) { - $output_cap = new stdClass; - - $output_cap->name = $cap; - - $output_caps[] = $output_cap; - } - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->cap_fields ); - $formatter->display_items( $output_caps ); - } - - } - } - - /** - * Import users from a CSV file. - * - * If the user already exists (matching the email address or login), then - * the user is updated unless the `--skip-update` flag is used. - * - * ## OPTIONS - * - * <file> - * : The local or remote CSV file of users to import. - * - * [--send-email] - * : Send an email to new users with their account details. - * - * [--skip-update] - * : Don't update users that already exist. - * - * ## EXAMPLES - * - * # Import users from local CSV file - * $ wp user import-csv /path/to/users.csv - * Success: bobjones created - * Success: newuser1 created - * Success: existinguser created - * - * # Import users from remote CSV file - * $ wp user import-csv http://example.com/users.csv - * - * Sample users.csv file: - * - * user_login,user_email,display_name,role - * bobjones,bobjones@example.com,Bob Jones,contributor - * newuser1,newuser1@example.com,New User,author - * existinguser,existinguser@example.com,Existing User,administrator - * - * @subcommand import-csv - */ - public function import_csv( $args, $assoc_args ) { - - $blog_users = get_users(); - - $filename = $args[0]; - - if ( 0 === stripos( $filename, 'http://' ) || 0 === stripos( $filename, 'https://' ) ) { - $response = wp_remote_head( $filename ); - $response_code = (string)wp_remote_retrieve_response_code( $response ); - if ( in_array( $response_code[0], array( 4, 5 ) ) ) { - WP_CLI::error( "Couldn't access remote CSV file (HTTP {$response_code} response)." ); - } - } else if ( ! file_exists( $filename ) ) { - WP_CLI::error( sprintf( "Missing file: %s", $filename ) ); - } - - foreach ( new \WP_CLI\Iterators\CSV( $filename ) as $i => $new_user ) { - $defaults = array( - 'role' => get_option('default_role'), - 'user_pass' => wp_generate_password(), - 'user_registered' => strftime( "%F %T", time() ), - 'display_name' => false, - ); - $new_user = array_merge( $defaults, $new_user ); - - $secondary_roles = array(); - if ( ! empty( $new_user['roles'] ) ) { - $roles = array_map( 'trim', explode( ',', $new_user['roles'] ) ); - $invalid_role = false; - foreach( $roles as $role ) { - if ( is_null( get_role( $role ) ) ) { - WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); - $invalid_role = true; - break; - } - } - if ( $invalid_role ) { - continue; - } - $new_user['role'] = array_shift( $roles ); - $secondary_roles = $roles; - } else if ( 'none' === $new_user['role'] ) { - $new_user['role'] = false; - } elseif ( is_null( get_role( $new_user['role'] ) ) ) { - WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); - continue; - } - - // User already exists and we just need to add them to the site if they aren't already there - $existing_user = get_user_by( 'email', $new_user['user_email'] ); - - if ( !$existing_user ) { - $existing_user = get_user_by( 'login', $new_user['user_login'] ); - } - - if ( $existing_user && \WP_CLI\Utils\get_flag_value( $assoc_args, 'skip-update' ) ) { - - WP_CLI::log( "{$existing_user->user_login} exists and has been skipped." ); - continue; - - } else if ( $existing_user ) { - - $new_user['ID'] = $existing_user->ID; - $user_id = wp_update_user( $new_user ); - - if ( !in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ) ) && is_multisite() && $new_user['role'] ) { - add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); - WP_CLI::log( "{$existing_user->user_login} added as {$new_user['role']}." ); - } - - // Create the user - } else { - unset( $new_user['ID'] ); // Unset else it will just return the ID - - if ( is_multisite() ) { - $ret = wpmu_validate_user_signup( $new_user['user_login'], $new_user['user_email'] ); - if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { - WP_CLI::warning( $ret['errors'] ); - continue; - } - $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_pass'], $new_user['user_email'] ); - if ( ! $user_id ) { - WP_CLI::warning( "Unknown error creating new user." ); - continue; - } - $new_user['ID'] = $user_id; - $user_id = wp_update_user( $new_user ); - if ( is_wp_error( $user_id ) ) { - WP_CLI::warning( $user_id ); - continue; - } - } else { - $user_id = wp_insert_user( $new_user ); - } - - if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'send-email' ) ) { - self::wp_new_user_notification( $user_id, $new_user['user_pass'] ); - } - } - - if ( is_wp_error( $user_id ) ) { - WP_CLI::warning( $user_id ); - continue; - - } else if ( $new_user['role'] === false ) { - delete_user_option( $user_id, 'capabilities' ); - delete_user_option( $user_id, 'user_level' ); - } - - $user = get_user_by( 'id', $user_id ); - foreach( $secondary_roles as $secondary_role ) { - $user->add_role( $secondary_role ); - } - - if ( !empty( $existing_user ) ) { - WP_CLI::success( $new_user['user_login'] . " updated." ); - } else { - WP_CLI::success( $new_user['user_login'] . " created." ); - } - } - } - - /** - * Check whether the role is valid - * - * @param string - */ - private static function validate_role( $role ) { - - if ( ! empty( $role ) && is_null( get_role( $role ) ) ) { - WP_CLI::error( sprintf( "Role doesn't exist: %s", $role ) ); - } - - } - - /** - * Acommodate three different behaviors for wp_new_user_notification() - * - 4.3.1 and above: expect second argument to be deprecated - * - 4.3: Second argument was repurposed as $notify - * - Below 4.3: Send the password in the notification - * - * @param string $user_id - * @param string $password - */ - private static function wp_new_user_notification( $user_id, $password ) { - if ( \WP_CLI\Utils\wp_version_compare( '4.3.1', '>=' ) ) { - wp_new_user_notification( $user_id, null, 'both' ); - } else if ( \WP_CLI\Utils\wp_version_compare( '4.3', '>=' ) ) { - wp_new_user_notification( $user_id, 'both' ); - } else { - wp_new_user_notification( $user_id, $password ); - } - } - -} - -WP_CLI::add_command( 'user', 'User_Command' ); diff --git a/php/commands/widget.php b/php/commands/widget.php deleted file mode 100644 index 56d4fa2a2..000000000 --- a/php/commands/widget.php +++ /dev/null @@ -1,654 +0,0 @@ -<?php - -use WP_CLI\Utils; - -/** - * Manage sidebar widgets. - * - * ## EXAMPLES - * - * # List widgets on a given sidebar - * $ wp widget list sidebar-1 - * +----------+------------+----------+----------------------+ - * | name | id | position | options | - * +----------+------------+----------+----------------------+ - * | meta | meta-6 | 1 | {"title":"Meta"} | - * | calendar | calendar-2 | 2 | {"title":"Calendar"} | - * +----------+------------+----------+----------------------+ - * - * # Add a calendar widget to the second position on the sidebar - * $ wp widget add calendar sidebar-1 2 - * Success: Added widget to sidebar. - * - * # Update option(s) associated with a given widget - * $ wp widget update calendar-1 --title="Calendar" - * Success: Widget updated. - * - * # Delete one or more widgets entirely - * $ wp widget delete calendar-2 archive-1 - * Success: 2 widgets removed from sidebar. - */ - -class Widget_Command extends WP_CLI_Command { - - private $fields = array( - 'name', - 'id', - 'position', - 'options', - ); - - /** - * List widgets associated with a sidebar. - * - * ## OPTIONS - * - * <sidebar-id> - * : ID for the corresponding sidebar. - * - * [--fields=<fields>] - * : Limit the output to specific object fields. - * - * [--format=<format>] - * : Render output in a particular format. - * --- - * default: table - * options: - * - table - * - csv - * - ids - * - json - * - count - * - yaml - * --- - * - * ## AVAILABLE FIELDS - * - * These fields will be displayed by default for each widget: - * - * * name - * * id - * * position - * * options - * - * There are no optionally available fields. - * - * ## EXAMPLES - * - * $ wp widget list sidebar-1 --fields=name,id --format=csv - * name,id - * meta,meta-5 - * search,search-3 - * - * @subcommand list - */ - public function list_( $args, $assoc_args ) { - - list( $sidebar_id ) = $args; - - $this->validate_sidebar( $sidebar_id ); - - $output_widgets = $this->get_sidebar_widgets( $sidebar_id ); - - if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) { - $output_widgets = wp_list_pluck( $output_widgets, 'id' ); - } - - $formatter = new \WP_CLI\Formatter( $assoc_args, $this->fields ); - $formatter->display_items( $output_widgets ); - - } - - /** - * Add a widget to a sidebar. - * - * Creates a new widget entry in the database, and associates it with the - * sidebar. - * - * ## OPTIONS - * - * <name> - * : Widget name. - * - * <sidebar-id> - * : ID for the corresponding sidebar. - * - * [<position>] - * : Widget's current position within the sidebar. Defaults to last - * - * [--<field>=<value>] - * : Widget option to add, with its new value - * - * ## EXAMPLES - * - * # Add a new calendar widget to sidebar-1 with title "Calendar" - * $ wp widget add calendar sidebar-1 2 --title="Calendar" - * Success: Added widget to sidebar. - * - * @subcommand add - */ - public function add( $args, $assoc_args ) { - - list( $name, $sidebar_id ) = $args; - $position = \WP_CLI\Utils\get_flag_value( $args, 2, 1 ) - 1; - $this->validate_sidebar( $sidebar_id ); - - if ( false == ( $widget = $this->get_widget_obj( $name ) ) ) { - WP_CLI::error( "Invalid widget type." ); - } - - /** - * Adding a widget is as easy as: - * 1. Creating a new widget option - * 2. Adding the widget to the sidebar - * 3. Positioning appropriately - */ - $widget_options = $option_keys = $this->get_widget_options( $name ); - if ( ! isset( $widget_options['_multiwidget'] ) ) { - $widget_options['_multiwidget'] = 1; - } - unset( $option_keys['_multiwidget'] ); - $option_keys = array_keys( $option_keys ); - $last_key = array_pop( $option_keys ); - $option_index = $last_key + 1; - $widget_options[ $option_index ] = $this->sanitize_widget_options( $name, $assoc_args, array() ); - $this->update_widget_options( $name, $widget_options ); - - $widget_id = $name . '-' . $option_index; - $this->move_sidebar_widget( $widget_id, null, $sidebar_id, null, $position ); - - WP_CLI::success( "Added widget to sidebar." ); - - - } - - /** - * Update options for an existing widget. - * - * ## OPTIONS - * - * <widget-id> - * : Unique ID for the widget - * - * [--<field>=<value>] - * : Field to update, with its new value - * - * ## EXAMPLES - * - * # Change calendar-1 widget title to "Our Calendar" - * $ wp widget update calendar-1 --title="Our Calendar" - * Success: Widget updated. - * - * @subcommand update - */ - public function update( $args, $assoc_args ) { - - list( $widget_id ) = $args; - if ( ! $this->validate_sidebar_widget( $widget_id ) ) { - WP_CLI::error( "Widget doesn't exist." ); - } - - if ( empty( $assoc_args ) ) { - WP_CLI::error( "No options specified to update." ); - } - - list( $name, $option_index ) = $this->get_widget_data( $widget_id ); - - $widget_options = $this->get_widget_options( $name ); - $clean_options = $this->sanitize_widget_options( $name, $assoc_args, $widget_options[ $option_index ] ); - $widget_options[ $option_index ] = array_merge( (array)$widget_options[ $option_index ], $clean_options ); - $this->update_widget_options( $name, $widget_options ); - - WP_CLI::success( "Widget updated." ); - - } - - /** - * Move the position of a widget. - * - * Changes the order of a widget in its existing sidebar, or moves it to a - * new sidebar. - * - * ## OPTIONS - * - * <widget-id> - * : Unique ID for the widget - * - * [--position=<position>] - * : Assign the widget to a new position. - * - * [--sidebar-id=<sidebar-id>] - * : Assign the widget to a new sidebar - * - * ## EXAMPLES - * - * # Change position of widget - * $ wp widget move recent-comments-2 --position=2 - * Success: Widget moved. - * - * # Move widget to Inactive Widgets - * $ wp widget move recent-comments-2 --sidebar-id=wp_inactive_widgets - * Success: Widget moved. - * - * @subcommand move - */ - public function move( $args, $assoc_args ) { - - list( $widget_id ) = $args; - if ( ! $this->validate_sidebar_widget( $widget_id ) ) { - WP_CLI::error( "Widget doesn't exist." ); - } - - if ( empty( $assoc_args['position'] ) && empty( $assoc_args['sidebar-id'] ) ) { - WP_CLI::error( "A new position or new sidebar must be specified." ); - } - - list( $name, $option_index, $current_sidebar_id, $current_sidebar_index ) = $this->get_widget_data( $widget_id ); - - $new_sidebar_id = ! empty( $assoc_args['sidebar-id'] ) ? $assoc_args['sidebar-id'] : $current_sidebar_id; - $this->validate_sidebar( $new_sidebar_id ); - - $new_sidebar_index = ! empty( $assoc_args['position'] ) ? $assoc_args['position'] - 1 : $current_sidebar_index; - // Moving between sidebars adds to the top - if ( $new_sidebar_id != $current_sidebar_id && $new_sidebar_index == $current_sidebar_index ) { - // Human-readable positions are different than numerically indexed array - $new_sidebar_index = 0; - } - - $this->move_sidebar_widget( $widget_id, $current_sidebar_id, $new_sidebar_id, $current_sidebar_index, $new_sidebar_index ); - - WP_CLI::success( "Widget moved." ); - - } - - /** - * Deactivate one or more widgets from an active sidebar. - * - * Moves widgets to Inactive Widgets. - * - * ## OPTIONS - * - * <widget-id>... - * : Unique ID for the widget(s) - * - * ## EXAMPLES - * - * # Deactivate the recent-comments-2 widget. - * $ wp widget deactivate recent-comments-2 - * Success: 1 widget deactivated. - * - * @subcommand deactivate - */ - public function deactivate( $args, $assoc_args ) { - - $count = $errors = 0; - - foreach( $args as $widget_id ) { - if ( ! $this->validate_sidebar_widget( $widget_id ) ) { - WP_CLI::warning( "Widget '{$widget_id}' doesn't exist." ); - $errors++; - continue; - } - - list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); - if ( 'wp_inactive_widgets' == $sidebar_id ) { - WP_CLI::warning( sprintf( "'%s' is already deactivated.", $widget_id ) ); - continue; - } - - $this->move_sidebar_widget( $widget_id, $sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); - - $count++; - - } - - Utils\report_batch_operation_results( 'widget', 'deactivate', count( $args ), $count, $errors ); - } - - /** - * Delete one or more widgets from a sidebar. - * - * ## OPTIONS - * - * <widget-id>... - * : Unique ID for the widget(s) - * - * ## EXAMPLES - * - * # Delete the recent-comments-2 widget from its sidebar. - * $ wp widget delete recent-comments-2 - * Success: Deleted 1 of 1 widgets. - * - * @subcommand delete - */ - public function delete( $args, $assoc_args ) { - - $count = $errors = 0; - - foreach( $args as $widget_id ) { - if ( ! $this->validate_sidebar_widget( $widget_id ) ) { - WP_CLI::warning( "Widget '{$widget_id}' doesn't exist." ); - $errors++; - continue; - } - - // Remove the widget's settings. - list( $name, $option_index, $sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); - $widget_options = $this->get_widget_options( $name ); - unset( $widget_options[ $option_index ] ); - $this->update_widget_options( $name, $widget_options ); - - // Remove the widget from the sidebar. - $all_widgets = $this->wp_get_sidebars_widgets(); - unset( $all_widgets[ $sidebar_id ][ $sidebar_index ] ); - $all_widgets[ $sidebar_id ] = array_values( $all_widgets[ $sidebar_id ] ); - update_option( 'sidebars_widgets', $all_widgets ); - - $count++; - } - - Utils\report_batch_operation_results( 'widget', 'delete', count( $args ), $count, $errors ); - } - - /** - * Reset sidebar. - * - * Removes all widgets from the sidebar and places them in Inactive Widgets. - * - * ## OPTIONS - * - * [<sidebar-id>...] - * : One or more sidebars to reset. - * - * [--all] - * : If set, all sidebars will be reset. - * - * ## EXAMPLES - * - * # Reset a sidebar - * $ wp widget reset sidebar-1 - * Success: Sidebar 'sidebar-1' reset. - * - * # Reset multiple sidebars - * $ wp widget reset sidebar-1 sidebar-2 - * Success: Sidebar 'sidebar-1' reset. - * Success: Sidebar 'sidebar-2' reset. - * - * # Reset all sidebars - * $ wp widget reset --all - * Success: Sidebar 'sidebar-1' reset. - * Success: Sidebar 'sidebar-2' reset. - * Success: Sidebar 'sidebar-3' reset. - */ - public function reset( $args, $assoc_args ) { - - global $wp_registered_sidebars; - - $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', false ); - - // Bail if no arguments and no all flag. - if ( ! $all && empty( $args ) ) { - WP_CLI::error( 'Please specify one or more sidebars, or use --all.' ); - } - - // Fetch all sidebars if all flag is set. - if ( $all ) { - $args = array_keys( $wp_registered_sidebars ); - } - - // Sidebar ID wp_inactive_widgets is reserved by WP core for inactive widgets. - if ( isset( $args['wp_inactive_widgets'] ) ) { - unset( $args['wp_inactive_widgets'] ); - } - - // Check if no registered sidebar. - if ( empty( $args ) ) { - WP_CLI::error( 'No sidebar registered.' ); - } - - $count = $errors = 0; - foreach ( $args as $sidebar_id ) { - if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { - WP_CLI::warning( sprintf( 'Invalid sidebar: %s', $sidebar_id ) ); - $errors++; - continue; - } - - $widgets = $this->get_sidebar_widgets( $sidebar_id ); - if ( empty( $widgets ) ) { - WP_CLI::warning( sprintf( "Sidebar '%s' is already empty.", $sidebar_id ) ); - } - else { - foreach ( $widgets as $widget ) { - $widget_id = $widget->id; - list( $name, $option_index, $new_sidebar_id, $sidebar_index ) = $this->get_widget_data( $widget_id ); - $this->move_sidebar_widget( $widget_id, $new_sidebar_id, 'wp_inactive_widgets', $sidebar_index, 0 ); - } - WP_CLI::log( sprintf( "Sidebar '%s' reset.", $sidebar_id ) ); - $count++; - } - } - - Utils\report_batch_operation_results( 'sidebar', 'reset', count( $args ), $count, $errors ); - } - - /** - * Check whether a sidebar is a valid sidebar - * - * @param string $sidebar_id - */ - private function validate_sidebar( $sidebar_id ) { - global $wp_registered_sidebars; - - \WP_CLI\Utils\wp_register_unused_sidebar(); - - if ( ! array_key_exists( $sidebar_id, $wp_registered_sidebars ) ) { - WP_CLI::error( "Invalid sidebar." ); - } - } - - /** - * Check whether the specified widget is on the sidebar - * - * @param string $widget_id - */ - private function validate_sidebar_widget( $widget_id ) { - - $sidebars_widgets = $this->wp_get_sidebars_widgets(); - - $widget_exists = false; - foreach( $sidebars_widgets as $sidebar_id => $widgets ) { - - if ( in_array( $widget_id, $widgets ) ) { - $widget_exists = true; - break; - } - - } - return $widget_exists; - } - - /** - * Get the widgets (and their associated data) for a given sidebar - * - * @param string $sidebar_id - * @return array - */ - private function get_sidebar_widgets( $sidebar_id ) { - - $all_widgets = $this->wp_get_sidebars_widgets(); - - if ( empty( $all_widgets[ $sidebar_id ] ) ) { - return array(); - } - - $prepared_widgets = array(); - foreach( $all_widgets[ $sidebar_id ] as $key => $widget_id ) { - - $prepared_widget = new stdClass; - - $parts = explode( '-', $widget_id ); - $option_index = array_pop( $parts ); - $widget_name = implode( '-', $parts ); - - $prepared_widget->name = $widget_name; - $prepared_widget->id = $widget_id; - $prepared_widget->position = $key + 1; - $widget_options = get_option( 'widget_' . $widget_name ); - $prepared_widget->options = $widget_options[ $option_index ]; - - $prepared_widgets[] = $prepared_widget; - } - - return $prepared_widgets; - } - - /** - * Re-implementation of wp_get_sidebars_widgets() - * because the original has a nasty global component - */ - private function wp_get_sidebars_widgets() { - $sidebars_widgets = get_option( 'sidebars_widgets', array() ); - - if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) { - unset( $sidebars_widgets['array_version'] ); - } - - return $sidebars_widgets; - } - - /** - * Get the widget's name, option index, sidebar, and sidebar index from its ID - * - * @param string $widget_id - * @return array - */ - private function get_widget_data( $widget_id ) { - - $parts = explode( '-', $widget_id ); - $option_index = array_pop( $parts ); - $name = implode( '-', $parts ); - - $sidebar_id = false; - $sidebar_index = false; - $all_widgets = $this->wp_get_sidebars_widgets(); - foreach( $all_widgets as $s_id => &$widgets ) { - - if ( false !== ( $key = array_search( $widget_id, $widgets ) ) ) { - $sidebar_id = $s_id; - $sidebar_index = $key; - break; - } - - } - - return array( $name, $option_index, $sidebar_id, $sidebar_index ); - } - - /** - * Get the options for a given widget - * - * @param string $name - * @return array - */ - private function get_widget_options( $name ) { - return get_option( 'widget_' . $name, array() ); - } - - /** - * Update the options for a given widget - * - * @param string $name - * @param mixed - */ - private function update_widget_options( $name, $value ) { - update_option( 'widget_' . $name, $value ); - } - - /** - * Reposition a widget within a sidebar or move to another sidebar. - * - * @param string $widget_id - * @param string|null $current_sidebar_id - * @param string $new_sidebar_id - * @param int|null $current_index - * @param int $new_index - */ - private function move_sidebar_widget( $widget_id, $current_sidebar_id, $new_sidebar_id, $current_index, $new_index ) { - - $all_widgets = $this->wp_get_sidebars_widgets(); - $needs_placement = true; - // Existing widget - if ( $current_sidebar_id && ! is_null( $current_index ) ) { - - $widgets = $all_widgets[ $current_sidebar_id ]; - if ( $current_sidebar_id !== $new_sidebar_id ) { - - unset( $widgets[ $current_index ] ); - - } else { - - $part = array_splice( $widgets, $current_index, 1 ); - array_splice( $widgets, $new_index, 0, $part ); - - $needs_placement = false; - - } - - $all_widgets[ $current_sidebar_id ] = array_values( $widgets ); - - } - - if ( $needs_placement ) { - $widgets = ! empty( $all_widgets[ $new_sidebar_id ] ) ? $all_widgets[ $new_sidebar_id ] : array(); - $before = array_slice( $widgets, 0, $new_index, true ); - $after = array_slice( $widgets, $new_index, count( $widgets ), true ); - $widgets = array_merge( $before, array( $widget_id ), $after ); - $all_widgets[ $new_sidebar_id ] = array_values( $widgets ); - } - - update_option( 'sidebars_widgets', $all_widgets ); - - } - - /** - * Get a widget's instantiated object based on its name - * - * @param string $id_base Name of the widget - * @return WP_Widget|false - */ - private function get_widget_obj( $id_base ) { - global $wp_widget_factory; - - $widget = wp_filter_object_list( $wp_widget_factory->widgets, array( 'id_base' => $id_base ) ); - if ( empty( $widget ) ) { - return false; - } - - return array_pop( $widget ); - } - - /** - * Clean up a widget's options based on its update callback - * - * @param string $id_base Name of the widget - * @param mixed $dirty_options - * @param mixed $old_options - * @return mixed - */ - private function sanitize_widget_options( $id_base, $dirty_options, $old_options ) { - - $widget = $this->get_widget_obj( $id_base ); - if ( empty( $widget ) ) { - return array(); - } - - // No easy way to determine expected array keys for $dirty_options - // because Widget API dependent on the form fields - return @$widget->update( $dirty_options, $old_options ); - - } - -} - -WP_CLI::add_command( 'widget', 'Widget_Command' ); diff --git a/php/config-spec.php b/php/config-spec.php deleted file mode 100644 index 63725e725..000000000 --- a/php/config-spec.php +++ /dev/null @@ -1,116 +0,0 @@ -<?php - -return array( - 'path' => array( - 'runtime' => '=<path>', - 'file' => '<path>', - 'desc' => 'Path to the WordPress files.', - ), - - 'ssh' => array( - 'runtime' => '=[<user>@]<host>[:<port>][<path>]', - 'file' => '[<user>@]<host>[:<port>][<path>]', - 'desc' => 'Perform operation against a remote server over SSH.', - ), - - 'http' => array( - 'runtime' => '=<http>', - 'file' => '<http>', - 'desc' => 'Perform operation against a remote WordPress install over HTTP.', - ), - - 'url' => array( - 'runtime' => '=<url>', - 'file' => '<url>', - 'desc' => 'Pretend request came from given URL. In multisite, this argument is how the target site is specified.', - ), - 'blog' => array( - 'deprecated' => 'Use --url instead.', - 'runtime' => '=<url>', - ), - - 'user' => array( - 'runtime' => '=<id|login|email>', - 'file' => '<id|login|email>', - 'desc' => 'Set the WordPress user.', - ), - - 'skip-plugins' => array( - 'runtime' => '[=<plugin>]', - 'file' => '<list>', - 'desc' => 'Skip loading all or some plugins. Note: mu-plugins are still loaded.', - 'default' => '', - ), - - 'skip-themes' => array( - 'runtime' => '[=<theme>]', - 'file' => '<list>', - 'desc' => 'Skip loading all or some themes.', - 'default' => '', - ), - - 'skip-packages' => array( - 'runtime' => '', - 'file' => '<bool>', - 'desc' => 'Skip loading all installed packages.', - 'default' => false, - ), - - 'require' => array( - 'runtime' => '=<path>', - 'file' => '<path>', - 'desc' => 'Load PHP file before running the command (may be used more than once).', - 'multiple' => true, - 'default' => array(), - ), - - 'disabled_commands' => array( - 'file' => '<list>', - 'default' => array(), - 'desc' => '(Sub)commands to disable.', - ), - - 'color' => array( - 'runtime' => true, - 'file' => '<bool>', - 'default' => 'auto', - 'desc' => 'Whether to colorize the output.', - ), - - 'debug' => array( - 'runtime' => '[=<group>]', - 'file' => '<group>', - 'default' => false, - 'desc' => 'Show all PHP errors; add verbosity to WP-CLI bootstrap.', - ), - - 'prompt' => array( - 'runtime' => '[=<assoc>]', - 'file' => false, - 'default' => false, - 'desc' => 'Prompt the user to enter values for all command arguments, or a subset specified as comma-separated values.', - ), - - 'quiet' => array( - 'runtime' => '', - 'file' => '<bool>', - 'default' => false, - 'desc' => 'Suppress informational messages.', - ), - - 'apache_modules' => array( - 'file' => '<list>', - 'desc' => 'List of Apache Modules that are to be reported as loaded.', - 'multiple' => true, - 'default' => array(), - ), - - # --allow-root => (NOT RECOMMENDED) Allow wp-cli to run as root. This poses - # a security risk, so you probably do not want to do this. - 'allow-root' => array( - 'file' => false, # Explicit. Just in case the default changes. - 'runtime' => '', - 'hidden' => true, - ), - -); diff --git a/php/dispatcher.php b/php/dispatcher.php deleted file mode 100644 index bd11a3927..000000000 --- a/php/dispatcher.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace WP_CLI\Dispatcher; - -/** - * Get the path to a command, e.g. "core download" - * - * @param WP_CLI\Dispatcher\Subcommand $command - * @return string - */ -function get_path( $command ) { - $path = array(); - - do { - array_unshift( $path, $command->get_name() ); - } while ( $command = $command->get_parent() ); - - return $path; -} - diff --git a/php/router.php b/php/router.php deleted file mode 100644 index 289840227..000000000 --- a/php/router.php +++ /dev/null @@ -1,112 +0,0 @@ -<?php -// Used by `wp server` to route requests. - -namespace WP_CLI\Router; - -/** - * This is a copy of WordPress's add_filter() function. - * - * We duplicate it because WordPress is not loaded yet. - */ -function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { - global $wp_filter, $merged_filters; - - $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); - $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); - unset( $merged_filters[ $tag ] ); - return true; -} - -/** - * This is a copy of WordPress's _wp_filter_build_unique_id() function. - * - * We duplicate it because WordPress is not loaded yet. - */ -function _wp_filter_build_unique_id($tag, $function, $priority) { - global $wp_filter; - static $filter_id_count = 0; - - if ( is_string($function) ) - return $function; - - if ( is_object($function) ) { - // Closures are currently implemented as objects - $function = array( $function, '' ); - } else { - $function = (array) $function; - } - - if (is_object($function[0]) ) { - // Object Class Calling - if ( function_exists('spl_object_hash') ) { - return spl_object_hash($function[0]) . $function[1]; - } else { - $obj_idx = get_class($function[0]).$function[1]; - if ( !isset($function[0]->wp_filter_id) ) { - if ( false === $priority ) - return false; - $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count; - $function[0]->wp_filter_id = $filter_id_count; - ++$filter_id_count; - } else { - $obj_idx .= $function[0]->wp_filter_id; - } - - return $obj_idx; - } - } else if ( is_string($function[0]) ) { - // Static Calling - return $function[0] . '::' . $function[1]; - } -} - -function _get_full_host( $url ) { - $parsed_url = parse_url( $url ); - - $host = $parsed_url['host']; - if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 ) - $host .= ':' . $parsed_url['port']; - - return $host; -} - -// We need to trick WordPress into using the URL set by `wp server`, especially on multisite. -add_filter( 'option_home', function ( $url ) { - $GLOBALS['_wp_cli_original_url'] = $url; - - return 'http://' . $_SERVER['HTTP_HOST']; -}, 20 ); - -add_filter( 'option_siteurl', function ( $url ) { - if ( !isset( $GLOBALS['_wp_cli_original_url'] ) ) - get_option('home'); // trigger the option_home filter - - $home_url_host = _get_full_host( $GLOBALS['_wp_cli_original_url'] ); - $site_url_host = _get_full_host( $url ); - - if ( $site_url_host == $home_url_host ) { - $url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url ); - } - - return $url; -}, 20 ); - -$root = $_SERVER['DOCUMENT_ROOT']; -$path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' ); - -if ( file_exists( $root.$path ) ) { - if ( is_dir( $root.$path ) && substr( $path, -1 ) !== '/' ) { - header( "Location: $path/" ); - exit; - } - - if ( strpos( $path, '.php' ) !== false ) { - chdir( dirname( $root.$path ) ); - require_once $root.$path; - } else { - return false; - } -} else { - chdir( $root ); - require_once 'index.php'; -} diff --git a/php/utils-wp.php b/php/utils-wp.php deleted file mode 100644 index f0c34292a..000000000 --- a/php/utils-wp.php +++ /dev/null @@ -1,358 +0,0 @@ -<?php - -// Utilities that depend on WordPress code. - -namespace WP_CLI\Utils; - -function wp_not_installed() { - if ( !is_blog_installed() && !defined( 'WP_INSTALLING' ) ) { - \WP_CLI::error( - "The site you have requested is not installed.\n" . - 'Run `wp core install`.' ); - } -} - -function wp_debug_mode() { - if ( \WP_CLI::get_config( 'debug' ) ) { - if ( !defined( 'WP_DEBUG' ) ) - define( 'WP_DEBUG', true ); - - error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT ); - } else { - if ( WP_DEBUG ) { - error_reporting( E_ALL ); - - if ( WP_DEBUG_DISPLAY ) - ini_set( 'display_errors', 1 ); - elseif ( null !== WP_DEBUG_DISPLAY ) - ini_set( 'display_errors', 0 ); - - if ( WP_DEBUG_LOG ) { - ini_set( 'log_errors', 1 ); - ini_set( 'error_log', WP_CONTENT_DIR . '/debug.log' ); - } - } else { - error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR ); - } - - if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) { - @ini_set( 'display_errors', 0 ); - } - } - - // XDebug already sends errors to STDERR - ini_set( 'display_errors', function_exists( 'xdebug_debug_zval' ) ? false : 'STDERR' ); -} - -function replace_wp_die_handler() { - \remove_filter( 'wp_die_handler', '_default_wp_die_handler' ); - \add_filter( 'wp_die_handler', function() { return __NAMESPACE__ . '\\' . 'wp_die_handler'; } ); -} - -function wp_die_handler( $message ) { - if ( $message instanceof \WP_Error ) { - $message = $message->get_error_message(); - } - - $original_message = $message = trim( $message ); - if ( preg_match( '|^\<h1>(.+?)</h1>|', $original_message, $matches ) ) { - $message = $matches[1] . '.'; - } - if ( preg_match( '|\<p>(.+?)</p>|', $original_message, $matches ) ) { - $message .= ' ' . $matches[1]; - } - - $search_replace = array( - '<code>' => '`', - '</code>' => '`', - ); - $message = str_replace( array_keys( $search_replace ), array_values( $search_replace ), $message ); - $message = strip_tags( $message ); - $message = html_entity_decode( $message, ENT_COMPAT, 'UTF-8' ); - - \WP_CLI::error( $message ); -} - -function wp_redirect_handler( $url ) { - \WP_CLI::warning( 'Some code is trying to do a URL redirect. Backtrace:' ); - - ob_start(); - debug_print_backtrace(); - fwrite( STDERR, ob_get_clean() ); - - return $url; -} - -function maybe_require( $since, $path ) { - if ( wp_version_compare( $since, '>=' ) ) { - require $path; - } -} - -function get_upgrader( $class ) { - if ( !class_exists( '\WP_Upgrader' ) ) - require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; - - return new $class( new \WP_CLI\UpgraderSkin ); -} - -/** - * Converts a plugin basename back into a friendly slug. - */ -function get_plugin_name( $basename ) { - if ( false === strpos( $basename, '/' ) ) - $name = basename( $basename, '.php' ); - else - $name = dirname( $basename ); - - return $name; -} - -function is_plugin_skipped( $file ) { - $name = get_plugin_name( str_replace( WP_PLUGIN_DIR . '/', '', $file ) ); - - $skipped_plugins = \WP_CLI::get_runner()->config['skip-plugins']; - if ( true === $skipped_plugins ) - return true; - - if ( ! is_array( $skipped_plugins ) ) { - $skipped_plugins = explode( ',', $skipped_plugins ); - } - - return in_array( $name, array_filter( $skipped_plugins ) ); -} - -function get_theme_name( $path ) { - return basename( $path ); -} - -function is_theme_skipped( $path ) { - $name = get_theme_name( $path ); - - $skipped_themes = \WP_CLI::get_runner()->config['skip-themes']; - if ( true === $skipped_themes ) - return true; - - if ( ! is_array( $skipped_themes ) ) { - $skipped_themes = explode( ',', $skipped_themes ); - } - - return in_array( $name, array_filter( $skipped_themes ) ); -} - -/** - * Register the sidebar for unused widgets - * Core does this in /wp-admin/widgets.php, which isn't helpful - */ -function wp_register_unused_sidebar() { - - register_sidebar(array( - 'name' => __('Inactive Widgets'), - 'id' => 'wp_inactive_widgets', - 'class' => 'inactive-sidebar', - 'description' => __( 'Drag widgets here to remove them from the sidebar but keep their settings.' ), - 'before_widget' => '', - 'after_widget' => '', - 'before_title' => '', - 'after_title' => '', - )); - -} - -/** - * Attempts to determine which object cache is being used. - * - * Note that the guesses made by this function are based on the WP_Object_Cache classes - * that define the 3rd party object cache extension. Changes to those classes could render - * problems with this function's ability to determine which object cache is being used. - * - * @return string - */ -function wp_get_cache_type() { - global $_wp_using_ext_object_cache, $wp_object_cache; - - if ( ! empty( $_wp_using_ext_object_cache ) ) { - // Test for Memcached PECL extension memcached object cache (https://github.com/tollmanz/wordpress-memcached-backend) - if ( isset( $wp_object_cache->m ) && is_a( $wp_object_cache->m, 'Memcached' ) ) { - $message = 'Memcached'; - - // Test for Memcache PECL extension memcached object cache (http://wordpress.org/extend/plugins/memcached/) - } elseif ( isset( $wp_object_cache->mc ) ) { - $is_memcache = true; - foreach ( $wp_object_cache->mc as $bucket ) { - if ( ! is_a( $bucket, 'Memcache' ) && ! is_a( $bucket, 'Memcached' ) ) - $is_memcache = false; - } - - if ( $is_memcache ) - $message = 'Memcache'; - - // Test for Xcache object cache (http://plugins.svn.wordpress.org/xcache/trunk/object-cache.php) - } elseif ( is_a( $wp_object_cache, 'XCache_Object_Cache' ) ) { - $message = 'Xcache'; - - // Test for WinCache object cache (http://wordpress.org/extend/plugins/wincache-object-cache-backend/) - } elseif ( class_exists( 'WinCache_Object_Cache' ) ) { - $message = 'WinCache'; - - // Test for APC object cache (http://wordpress.org/extend/plugins/apc/) - } elseif ( class_exists( 'APC_Object_Cache' ) ) { - $message = 'APC'; - - // Test for Redis Object Cache (https://github.com/alleyinteractive/wp-redis) - } elseif ( isset( $wp_object_cache->redis ) && is_a( $wp_object_cache->redis, 'Redis' ) ) { - $message = 'Redis'; - - // Test for WP LCache Object cache (https://github.com/lcache/wp-lcache) - } elseif ( isset( $wp_object_cache->lcache ) && is_a( $wp_object_cache->lcache, '\LCache\Integrated' ) ) { - $message = 'WP LCache'; - - } elseif( function_exists( 'w3_instance' ) ) { - $config = w3_instance( 'W3_Config' ); - if ( $config->get_boolean( 'objectcache.enabled' ) ) { - $message = 'W3TC ' . $config->get_string( 'objectcache.engine' ); - } else { - $message = 'Unknown'; - } - } else { - $message = 'Unknown'; - } - } else { - $message = 'Default'; - } - return $message; -} - -/** - * Clear all of the caches for memory management - */ -function wp_clear_object_cache() { - global $wpdb, $wp_object_cache; - - $wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); - - if ( ! is_object( $wp_object_cache ) ) { - return; - } - - $wp_object_cache->group_ops = array(); - $wp_object_cache->stats = array(); - $wp_object_cache->memcache_debug = array(); - $wp_object_cache->cache = array(); - - if ( is_callable( $wp_object_cache, '__remoteset' ) ) { - $wp_object_cache->__remoteset(); // important - } -} - -/** - * Get a set of tables in the database. - * - * Interprets common command-line options into a resolved set of table names. - * - * @param array $args Provided table names, or tables with wildcards. - * @param array $assoc_args Optional flags for groups of tables (e.g. --network) - * @return array $tables - */ -function wp_get_table_names( $args, $assoc_args = array() ) { - global $wpdb; - - // Prioritize any supplied $args as tables - if ( ! empty( $args ) ) { - $new_tables = array(); - $get_tables_for_glob = function( $glob ) { - global $wpdb; - static $all_tables = array(); - if ( ! $all_tables ) { - $all_tables = $wpdb->get_col( 'SHOW TABLES' ); - } - $tables = array(); - foreach ( $all_tables as $table) { - if ( fnmatch( $glob, $table ) ) { - $tables[] = $table; - } - } - return $tables; - }; - foreach( $args as $key => $table ) { - if ( false !== strpos( $table, '*' ) || false !== strpos( $table, '?' ) ) { - $expanded_tables = $get_tables_for_glob( $table ); - if ( empty( $expanded_tables ) ) { - \WP_CLI::error( "Couldn't find any tables matching: {$table}" ); - } - $new_tables = array_merge( $new_tables, $expanded_tables ); - } else { - $new_tables[] = $table; - } - } - return $new_tables; - } - - // Fall back to flag if no tables were passed - $table_type = 'wordpress'; - if ( get_flag_value( $assoc_args, 'network' ) ) { - $table_type = 'network'; - } - if ( get_flag_value( $assoc_args, 'all-tables-with-prefix' ) ) { - $table_type = 'all-tables-with-prefix'; - } - if ( get_flag_value( $assoc_args, 'all-tables' ) ) { - $table_type = 'all-tables'; - } - - $network = 'network' == $table_type; - - if ( 'all-tables' == $table_type ) { - return $wpdb->get_col( 'SHOW TABLES' ); - } - - $prefix = $network ? $wpdb->base_prefix : $wpdb->prefix; - // '_' is a special wildcard for MySQL LIKE queries - // so it needs to be escaped with '\', but then '\' needs to be escaped as well - $sql_prefix = str_replace( '_', '\\_', $prefix ); - $matching_tables = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $sql_prefix . '%' ) ); - - if ( 'all-tables-with-prefix' == $table_type ) { - return $matching_tables; - } - - if ( $scope = get_flag_value( $assoc_args, 'scope' ) ) { - return $wpdb->tables( $scope ); - } - - $allowed_tables = array(); - $allowed_table_types = array( 'tables', 'global_tables' ); - if ( $network ) { - $allowed_table_types[] = 'ms_global_tables'; - } - foreach( $allowed_table_types as $table_type ) { - foreach( $wpdb->$table_type as $table ) { - $allowed_tables[] = $prefix . $table; - } - } - - // Given our matching tables, also allow site-specific tables on the network - foreach( $matching_tables as $key => $matched_table ) { - - if ( in_array( $matched_table, $allowed_tables ) ) { - continue; - } - - if ( $network ) { - $valid_table = false; - foreach( array_merge( $wpdb->tables, $wpdb->old_tables ) as $maybe_site_table ) { - if ( preg_match( "#{$prefix}([\d]+)_{$maybe_site_table}#", $matched_table ) ) { - $valid_table = true; - } - } - if ( $valid_table ) { - continue; - } - } - - unset( $matching_tables[ $key ] ); - - } - - return array_values( $matching_tables ); -} diff --git a/php/utils.php b/php/utils.php deleted file mode 100644 index d476dc1e8..000000000 --- a/php/utils.php +++ /dev/null @@ -1,838 +0,0 @@ -<?php - -// Utilities that do NOT depend on WordPress code. - -namespace WP_CLI\Utils; - -use \Composer\Semver\Comparator; -use \Composer\Semver\Semver; -use \WP_CLI; -use \WP_CLI\Dispatcher; -use \WP_CLI\Iterators\Transform; - -function inside_phar() { - return 0 === strpos( WP_CLI_ROOT, 'phar://' ); -} - -// Files that need to be read by external programs have to be extracted from the Phar archive. -function extract_from_phar( $path ) { - if ( ! inside_phar() ) { - return $path; - } - - $fname = basename( $path ); - - $tmp_path = get_temp_dir() . "wp-cli-$fname"; - - copy( $path, $tmp_path ); - - register_shutdown_function( function() use ( $tmp_path ) { - @unlink( $tmp_path ); - } ); - - return $tmp_path; -} - -function load_dependencies() { - if ( inside_phar() ) { - require WP_CLI_ROOT . '/vendor/autoload.php'; - return; - } - - $has_autoload = false; - - foreach ( get_vendor_paths() as $vendor_path ) { - if ( file_exists( $vendor_path . '/autoload.php' ) ) { - require $vendor_path . '/autoload.php'; - $has_autoload = true; - break; - } - } - - if ( !$has_autoload ) { - fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); - exit(3); - } -} - -function get_vendor_paths() { - $vendor_paths = array( - WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) - WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone - ); - $maybe_composer_json = WP_CLI_ROOT . '/../../../composer.json'; - if ( file_exists( $maybe_composer_json ) && is_readable( $maybe_composer_json ) ) { - $composer = json_decode( file_get_contents( $maybe_composer_json ) ); - if ( ! empty( $composer->config ) && ! empty( $composer->config->{'vendor-dir'} ) ) { - array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->config->{'vendor-dir'} ); - } - } - return $vendor_paths; -} - -// Using require() directly inside a class grants access to private methods to the loaded code -function load_file( $path ) { - require_once $path; -} - -function load_command( $name ) { - $path = WP_CLI_ROOT . "/php/commands/$name.php"; - - if ( is_readable( $path ) ) { - include_once $path; - } -} - -function load_all_commands() { - $cmd_dir = WP_CLI_ROOT . '/php/commands'; - - $iterator = new \DirectoryIterator( $cmd_dir ); - - foreach ( $iterator as $filename ) { - if ( '.php' != substr( $filename, -4 ) ) - continue; - - include_once "$cmd_dir/$filename"; - } -} - -/** - * Like array_map(), except it returns a new iterator, instead of a modified array. - * - * Example: - * - * $arr = array('Football', 'Socker'); - * - * $it = iterator_map($arr, 'strtolower', function($val) { - * return str_replace('foo', 'bar', $val); - * }); - * - * foreach ( $it as $val ) { - * var_dump($val); - * } - * - * @param array|object Either a plain array or another iterator - * @param callback The function to apply to an element - * @return object An iterator that applies the given callback(s) - */ -function iterator_map( $it, $fn ) { - if ( is_array( $it ) ) { - $it = new \ArrayIterator( $it ); - } - - if ( !method_exists( $it, 'add_transform' ) ) { - $it = new Transform( $it ); - } - - foreach ( array_slice( func_get_args(), 1 ) as $fn ) { - $it->add_transform( $fn ); - } - - return $it; -} - -/** - * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true - * @param string|array The files (or file) to search for - * @param string|null The directory to start searching from; defaults to CWD - * @param callable Function which is passed the current dir each time a directory level is traversed - * @return null|string Null if the file was not found - */ -function find_file_upward( $files, $dir = null, $stop_check = null ) { - $files = (array) $files; - if ( is_null( $dir ) ) { - $dir = getcwd(); - } - while ( @is_readable( $dir ) ) { - // Stop walking up when the supplied callable returns true being passed the $dir - if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { - return null; - } - - foreach ( $files as $file ) { - $path = $dir . DIRECTORY_SEPARATOR . $file; - if ( file_exists( $path ) ) { - return $path; - } - } - - $parent_dir = dirname( $dir ); - if ( empty($parent_dir) || $parent_dir === $dir ) { - break; - } - $dir = $parent_dir; - } - return null; -} - -function is_path_absolute( $path ) { - // Windows - if ( isset($path[1]) && ':' === $path[1] ) - return true; - - return $path[0] === '/'; -} - -/** - * Composes positional arguments into a command string. - * - * @param array - * @return string - */ -function args_to_str( $args ) { - return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); -} - -/** - * Composes associative arguments into a command string. - * - * @param array - * @return string - */ -function assoc_args_to_str( $assoc_args ) { - $str = ''; - - foreach ( $assoc_args as $key => $value ) { - if ( true === $value ) - $str .= " --$key"; - else - $str .= " --$key=" . escapeshellarg( $value ); - } - - return $str; -} - -/** - * Given a template string and an arbitrary number of arguments, - * returns the final command, with the parameters escaped. - */ -function esc_cmd( $cmd ) { - if ( func_num_args() < 2 ) - trigger_error( 'esc_cmd() requires at least two arguments.', E_USER_WARNING ); - - $args = func_get_args(); - - $cmd = array_shift( $args ); - - return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); -} - -function locate_wp_config() { - static $path; - - if ( null === $path ) { - if ( file_exists( ABSPATH . 'wp-config.php' ) ) - $path = ABSPATH . 'wp-config.php'; - elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) - $path = ABSPATH . '../wp-config.php'; - else - $path = false; - - if ( $path ) - $path = realpath( $path ); - } - - return $path; -} - -function wp_version_compare( $since, $operator ) { - return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); -} - -/** - * Render a collection of items as an ASCII table, JSON, CSV, YAML, list of ids, or count. - * - * Given a collection of items with a consistent data structure: - * - * ``` - * $items = array( - * array( - * 'key' => 'foo', - * 'value' => 'bar', - * ) - * ); - * ``` - * - * Render `$items` as an ASCII table: - * - * ``` - * WP_CLI\Utils\format_items( 'table', $items, array( 'key', 'value' ) ); - * - * # +-----+-------+ - * # | key | value | - * # +-----+-------+ - * # | foo | bar | - * # +-----+-------+ - * ``` - * - * Or render `$items` as YAML: - * - * ``` - * WP_CLI\Utils\format_items( 'yaml', $items, array( 'key', 'value' ) ); - * - * # --- - * # - - * # key: foo - * # value: bar - * ``` - * - * @access public - * @category Output - * - * @param string $format Format to use: 'table', 'json', 'csv', 'yaml', 'ids', 'count' - * @param array $items An array of items to output. - * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list. - * @return null - */ -function format_items( $format, $items, $fields ) { - $assoc_args = compact( 'format', 'fields' ); - $formatter = new \WP_CLI\Formatter( $assoc_args ); - $formatter->display_items( $items ); -} - -/** - * Write data as CSV to a given file. - * - * @access public - * - * @param resource $fd File descriptor - * @param array $rows Array of rows to output - * @param array $headers List of CSV columns (optional) - */ -function write_csv( $fd, $rows, $headers = array() ) { - if ( ! empty( $headers ) ) { - fputcsv( $fd, $headers ); - } - - foreach ( $rows as $row ) { - if ( ! empty( $headers ) ) { - $row = pick_fields( $row, $headers ); - } - - fputcsv( $fd, array_values( $row ) ); - } -} - -/** - * Pick fields from an associative array or object. - * - * @param array|object Associative array or object to pick fields from - * @param array List of fields to pick - * @return array - */ -function pick_fields( $item, $fields ) { - $item = (object) $item; - - $values = array(); - - foreach ( $fields as $field ) { - $values[ $field ] = isset( $item->$field ) ? $item->$field : null; - } - - return $values; -} - -/** - * Launch system's $EDITOR for the user to edit some text. - * - * @access public - * @category Input - * - * @param string $content Some form of text to edit (e.g. post content) - * @return string|bool Edited text, if file is saved from editor; false, if no change to file. - */ -function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { - - $tmpdir = get_temp_dir(); - - do { - $tmpfile = basename( $filename ); - $tmpfile = preg_replace( '|\.[^.]*$|', '', $tmpfile ); - $tmpfile .= '-' . substr( md5( rand() ), 0, 6 ); - $tmpfile = $tmpdir . $tmpfile . '.tmp'; - $fp = @fopen( $tmpfile, 'x' ); - if ( ! $fp && is_writable( $tmpdir ) && file_exists( $tmpfile ) ) { - $tmpfile = ''; - continue; - } - if ( $fp ) { - fclose( $fp ); - } - } while( ! $tmpfile ); - - if ( ! $tmpfile ) { - \WP_CLI::error( 'Error creating temporary file.' ); - } - - $output = ''; - file_put_contents( $tmpfile, $input ); - - $editor = getenv( 'EDITOR' ); - if ( !$editor ) { - if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) ) - $editor = 'notepad'; - else - $editor = 'vi'; - } - - $descriptorspec = array( STDIN, STDOUT, STDERR ); - $process = proc_open( "$editor " . escapeshellarg( $tmpfile ), $descriptorspec, $pipes ); - $r = proc_close( $process ); - if ( $r ) { - exit( $r ); - } - - $output = file_get_contents( $tmpfile ); - - unlink( $tmpfile ); - - if ( $output === $input ) - return false; - - return $output; -} - -/** - * @param string MySQL host string, as defined in wp-config.php - * @return array - */ -function mysql_host_to_cli_args( $raw_host ) { - $assoc_args = array(); - - $host_parts = explode( ':', $raw_host ); - if ( count( $host_parts ) == 2 ) { - list( $assoc_args['host'], $extra ) = $host_parts; - $extra = trim( $extra ); - if ( is_numeric( $extra ) ) { - $assoc_args['port'] = intval( $extra ); - $assoc_args['protocol'] = 'tcp'; - } else if ( $extra !== '' ) { - $assoc_args['socket'] = $extra; - } - } else { - $assoc_args['host'] = $raw_host; - } - - return $assoc_args; -} - -function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { - if ( !$descriptors ) - $descriptors = array( STDIN, STDOUT, STDERR ); - - if ( isset( $assoc_args['host'] ) ) { - $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); - } - - $pass = $assoc_args['pass']; - unset( $assoc_args['pass'] ); - - $old_pass = getenv( 'MYSQL_PWD' ); - putenv( 'MYSQL_PWD=' . $pass ); - - $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); - - $proc = proc_open( $final_cmd, $descriptors, $pipes ); - if ( !$proc ) - exit(1); - - $r = proc_close( $proc ); - - putenv( 'MYSQL_PWD=' . $old_pass ); - - if ( $r ) exit( $r ); -} - -/** - * Render PHP or other types of files using Mustache templates. - * - * IMPORTANT: Automatic HTML escaping is disabled! - */ -function mustache_render( $template_name, $data = array() ) { - if ( ! file_exists( $template_name ) ) - $template_name = WP_CLI_ROOT . "/templates/$template_name"; - - $template = file_get_contents( $template_name ); - - $m = new \Mustache_Engine( array( - 'escape' => function ( $val ) { return $val; } - ) ); - - return $m->render( $template, $data ); -} - -/** - * Create a progress bar to display percent completion of a given operation. - * - * Progress bar is written to STDOUT, and disabled when command is piped. Progress - * advances with `$progress->tick()`, and completes with `$progress->finish()`. - * Process bar also indicates elapsed time and expected total time. - * - * ``` - * # `wp user generate` ticks progress bar each time a new user is created. - * # - * # $ wp user generate --count=500 - * # Generating users 22 % [=======> ] 0:05 / 0:23 - * - * $progress = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); - * for ( $i = 0; $i < $count; $i++ ) { - * // uses wp_insert_user() to insert the user - * $progress->tick(); - * } - * $progress->finish(); - * ``` - * - * @access public - * @category Output - * - * @param string $message Text to display before the progress bar. - * @param integer $count Total number of ticks to be performed. - * @return cli\progress\Bar|WP_CLI\NoOp - */ -function make_progress_bar( $message, $count ) { - if ( \cli\Shell::isPiped() ) - return new \WP_CLI\NoOp; - - return new \cli\progress\Bar( $message, $count ); -} - -function parse_url( $url ) { - $url_parts = \parse_url( $url ); - - if ( !isset( $url_parts['scheme'] ) ) { - $url_parts = parse_url( 'http://' . $url ); - } - - return $url_parts; -} - -/** - * Check if we're running in a Windows environment (cmd.exe). - */ -function is_windows() { - return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; -} - -/** - * Replace magic constants in some PHP source code. - * - * @param string $source The PHP code to manipulate. - * @param string $path The path to use instead of the magic constants - */ -function replace_path_consts( $source, $path ) { - $replacements = array( - '__FILE__' => "'$path'", - '__DIR__' => "'" . dirname( $path ) . "'" - ); - - $old = array_keys( $replacements ); - $new = array_values( $replacements ); - - return str_replace( $old, $new, $source ); -} - -/** - * Make a HTTP request to a remote URL. - * - * Wraps the Requests HTTP library to ensure every request includes a cert. - * - * ``` - * # `wp core download` verifies the hash for a downloaded WordPress archive - * - * $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); - * if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { - * WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); - * } - * ``` - * - * @access public - * - * @param string $method HTTP method (GET, POST, DELETE, etc.) - * @param string $url URL to make the HTTP request to. - * @param array $headers Add specific headers to the request. - * @param array $options - * @return object - */ -function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { - - $cert_path = '/rmccue/requests/library/Requests/Transport/cacert.pem'; - if ( inside_phar() ) { - // cURL can't read Phar archives - $options['verify'] = extract_from_phar( - WP_CLI_ROOT . '/vendor' . $cert_path ); - } else { - foreach( get_vendor_paths() as $vendor_path ) { - if ( file_exists( $vendor_path . $cert_path ) ) { - $options['verify'] = $vendor_path . $cert_path; - break; - } - } - if ( empty( $options['verify'] ) ){ - WP_CLI::error_log( "Cannot find SSL certificate." ); - } - } - - try { - $request = \Requests::request( $url, $headers, $data, $method, $options ); - return $request; - } catch( \Requests_Exception $ex ) { - // Handle SSL certificate issues gracefully - \WP_CLI::warning( $ex->getMessage() ); - $options['verify'] = false; - try { - return \Requests::request( $url, $headers, $data, $method, $options ); - } catch( \Requests_Exception $ex ) { - \WP_CLI::error( $ex->getMessage() ); - } - } -} - -/** - * Increments a version string using the "x.y.z-pre" format - * - * Can increment the major, minor or patch number by one - * If $new_version == "same" the version string is not changed - * If $new_version is not a known keyword, it will be used as the new version string directly - * - * @param string $current_version - * @param string $new_version - * @return string - */ -function increment_version( $current_version, $new_version ) { - // split version assuming the format is x.y.z-pre - $current_version = explode( '-', $current_version, 2 ); - $current_version[0] = explode( '.', $current_version[0] ); - - switch ( $new_version ) { - case 'same': - // do nothing - break; - - case 'patch': - $current_version[0][2]++; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - case 'minor': - $current_version[0][1]++; - $current_version[0][2] = 0; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - case 'major': - $current_version[0][0]++; - $current_version[0][1] = 0; - $current_version[0][2] = 0; - - $current_version = array( $current_version[0] ); // drop possible pre-release info - break; - - default: // not a keyword - $current_version = array( array( $new_version ) ); - break; - } - - // reconstruct version string - $current_version[0] = implode( '.', $current_version[0] ); - $current_version = implode( '-', $current_version ); - - return $current_version; -} - -/** - * Compare two version strings to get the named semantic version. - * - * @access public - * - * @param string $new_version - * @param string $original_version - * @return string $name 'major', 'minor', 'patch' - */ -function get_named_sem_ver( $new_version, $original_version ) { - - if ( ! Comparator::greaterThan( $new_version, $original_version ) ) { - return ''; - } - - $parts = explode( '-', $original_version ); - $bits = explode( '.', $parts[0] ); - $major = $bits[0]; - if ( isset( $bits[1] ) ) { - $minor = $bits[1]; - } - if ( isset( $bits[2] ) ) { - $patch = $bits[2]; - } - - if ( ! is_null( $minor ) && Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { - return 'patch'; - } else if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { - return 'minor'; - } else { - return 'major'; - } -} - -/** - * Return the flag value or, if it's not set, the $default value. - * - * Because flags can be negated (e.g. --no-quiet to negate --quiet), this - * function provides a safer alternative to using - * `isset( $assoc_args['quiet'] )` or similar. - * - * @access public - * @category Input - * - * @param array $assoc_args Arguments array. - * @param string $flag Flag to get the value. - * @param mixed $default Default value for the flag. Default: NULL - * @return mixed - */ -function get_flag_value( $assoc_args, $flag, $default = null ) { - return isset( $assoc_args[ $flag ] ) ? $assoc_args[ $flag ] : $default; -} - -/** - * Get the system's temp directory. Warns user if it isn't writable. - * - * @access public - * @category System - * - * @return string - */ -function get_temp_dir() { - static $temp = ''; - - $trailingslashit = function( $path ) { - return rtrim( $path ) . '/'; - }; - - if ( $temp ) - return $trailingslashit( $temp ); - - if ( function_exists( 'sys_get_temp_dir' ) ) { - $temp = sys_get_temp_dir(); - } else if ( ini_get( 'upload_tmp_dir' ) ) { - $temp = ini_get( 'upload_tmp_dir' ); - } else { - $temp = '/tmp/'; - } - - if ( ! @is_writable( $temp ) ) { - \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); - } - - return $trailingslashit( $temp ); -} - -/** - * Parse a SSH url for its host, port, and path. - * - * Similar to parse_url(), but adds support for defined SSH aliases. - * - * ``` - * host OR host/path/to/wordpress OR host:port/path/to/wordpress - * ``` - * - * @access public - * - * @return mixed - */ -function parse_ssh_url( $url, $component = -1 ) { - preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $url, $matches ); - $bits = array(); - foreach( array( - 1 => 'host', - 3 => 'port', - 4 => 'path', - ) as $i => $key ) { - if ( ! empty( $matches[ $i ] ) ) { - $bits[ $key ] = $matches[ $i ]; - } - } - switch ( $component ) { - case PHP_URL_HOST: - return isset( $bits['host'] ) ? $bits['host'] : null; - case PHP_URL_PATH: - return isset( $bits['path'] ) ? $bits['path'] : null; - case PHP_URL_PORT: - return isset( $bits['port'] ) ? $bits['port'] : null; - default: - return $bits; - } -} - -/** - * Report the results of the same operation against multiple resources. - * - * @access public - * @category Input - * - * @param string $noun Resource being affected (e.g. plugin) - * @param string $verb Type of action happening to the noun (e.g. activate) - * @param integer $total Total number of resource being affected. - * @param integer $successes Number of successful operations. - * @param integer $failures Number of failures. - */ -function report_batch_operation_results( $noun, $verb, $total, $successes, $failures ) { - $plural_noun = $noun . 's'; - if ( in_array( $verb, array( 'reset' ), true ) ) { - $past_tense_verb = $verb; - } else { - $past_tense_verb = 'e' === substr( $verb, -1 ) ? $verb . 'd' : $verb . 'ed'; - } - $past_tense_verb_upper = ucfirst( $past_tense_verb ); - if ( $failures ) { - if ( $successes ) { - WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}." ); - } else { - WP_CLI::error( "No {$plural_noun} {$past_tense_verb}." ); - } - } else { - if ( $successes ) { - WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); - } else { - $message = $total > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); - WP_CLI::success( "{$message} already {$past_tense_verb}." ); - } - } -} - -/** - * Parse a string of command line arguments into an $argv-esqe variable. - * - * @access public - * @category Input - * - * @param string $arguments - * @return array - */ -function parse_str_to_argv( $arguments ) { - preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $arguments, $matches ); - $argv = isset( $matches[0] ) ? $matches[0] : array(); - $argv = array_map( function( $arg ){ - foreach( array( '"', "'" ) as $char ) { - if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { - $arg = substr( $arg, 1, -1 ); - break; - } - } - return $arg; - }, $argv ); - return $argv; -} - -/** - * Locale-independent version of basename() - * - * @access public - * - * @param string $path - * @param string $suffix - * @return string - */ -function basename( $path, $suffix = '' ) { - return urldecode( \basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) ); -} diff --git a/php/wp-cli.php b/php/wp-cli.php deleted file mode 100644 index 7aa32bb46..000000000 --- a/php/wp-cli.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php - -// Can be used by plugins/themes to check if WP-CLI is running or not -define( 'WP_CLI', true ); -define( 'WP_CLI_VERSION', trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ) ); -define( 'WP_CLI_START_MICROTIME', microtime( true ) ); - -// Set common headers, to prevent warnings from plugins -$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0'; -$_SERVER['HTTP_USER_AGENT'] = ''; -$_SERVER['REQUEST_METHOD'] = 'GET'; -$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; - -include WP_CLI_ROOT . '/php/utils.php'; -include WP_CLI_ROOT . '/php/dispatcher.php'; -include WP_CLI_ROOT . '/php/class-wp-cli.php'; -include WP_CLI_ROOT . '/php/class-wp-cli-command.php'; - -\WP_CLI\Utils\load_dependencies(); - -WP_CLI::get_runner()->start(); diff --git a/php/wp-settings-cli.php b/php/wp-settings-cli.php deleted file mode 100644 index ab284d58b..000000000 --- a/php/wp-settings-cli.php +++ /dev/null @@ -1,439 +0,0 @@ -<?php -/** - * A modified version of wp-settings.php, tailored for CLI use. - */ - -use \WP_CLI\Utils; - -/** - * Stores the location of the WordPress directory of functions, classes, and core content. - * - * @since 1.0.0 - */ -define( 'WPINC', 'wp-includes' ); - -// Include files required for initialization. -require( ABSPATH . WPINC . '/load.php' ); -require( ABSPATH . WPINC . '/default-constants.php' ); -require( ABSPATH . WPINC . '/plugin.php' ); - -/* - * These can't be directly globalized in version.php. When updating, - * we're including version.php from another install and don't want - * these values to be overridden if already set. - */ -global $wp_version, $wp_db_version, $tinymce_version, $required_php_version, $required_mysql_version, $wp_local_package; -require( ABSPATH . WPINC . '/version.php' ); - -/** - * If not already configured, `$blog_id` will default to 1 in a single site - * configuration. In multisite, it will be overridden by default in ms-settings.php. - * - * @global int $blog_id - * @since 2.0.0 - */ -global $blog_id; - -// Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE. -wp_initial_constants(); - -// Check for the required PHP version and for the MySQL extension or a database drop-in. -wp_check_php_mysql_versions(); - -// Disable magic quotes at runtime. Magic quotes are added using wpdb later in wp-settings.php. -@ini_set( 'magic_quotes_runtime', 0 ); -@ini_set( 'magic_quotes_sybase', 0 ); - -// WordPress calculates offsets from UTC. -date_default_timezone_set( 'UTC' ); - -// Turn register_globals off. -wp_unregister_GLOBALS(); - -// Standardize $_SERVER variables across setups. -wp_fix_server_vars(); - -// Check if we're in maintenance mode. -// WP-CLI: run enable_maintenance_mode filter early for compat with < WP 4.6 -/** - * Filters whether to enable maintenance mode. - * - * This filter runs before it can be used by plugins. It is designed for - * non-web runtimes. If this filter returns true, maintenance mode will be - * active and the request will end. If false, the request will be allowed to - * continue processing even if maintenance mode should be active. - * - * @since 4.6.0 - * - * @param bool $enable_checks Whether to enable maintenance mode. Default true. - * @param int $upgrading The timestamp set in the .maintenance file. - */ -if ( apply_filters( 'enable_maintenance_mode', true ) ) { - wp_maintenance(); -} - -// Start loading timer. -timer_start(); - -// WP-CLI: run enable_wp_debug_mode_checks filter early for compat with < WP 4.6 -/** - * Filters whether to allow the debug mode check to occur. - * - * This filter runs before it can be used by plugins. It is designed for - * non-web run-times. Returning false causes the `WP_DEBUG` and related - * constants to not be checked and the default php values for errors - * will be used unless you take care to update them yourself. - * - * @since 4.6.0 - * - * @param bool $enable_debug_mode Whether to enable debug mode checks to occur. Default true. - */ -if ( apply_filters( 'enable_wp_debug_mode_checks', true ) ){ - wp_debug_mode(); -} - -/** - * Filters whether to enable loading of the advanced-cache.php drop-in. - * - * This filter runs before it can be used by plugins. It is designed for non-web - * run-times. If false is returned, advance-cache.php will never be loaded. - * - * @since 4.6.0 - * - * @param bool $enable_advanced_cache Whether to enable loading advanced-cache.php (if present). - * Default true. - */ -if ( WP_CACHE && apply_filters( 'enable_loading_advanced_cache_dropin', true ) ) { - // For an advanced caching plugin to use. Uses a static drop-in because you would only want one. - WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' ); -} - -// Define WP_LANG_DIR if not set. -wp_set_lang_dir(); - -// Load early WordPress files. -require( ABSPATH . WPINC . '/compat.php' ); -require( ABSPATH . WPINC . '/functions.php' ); -require( ABSPATH . WPINC . '/class-wp.php' ); -require( ABSPATH . WPINC . '/class-wp-error.php' ); -require( ABSPATH . WPINC . '/pomo/mo.php' ); - -// Include the wpdb class and, if present, a db.php database drop-in. -require_wp_db(); - -// WP-CLI: Handle db error ourselves, instead of waiting for dead_db() -global $wpdb; -if ( !empty( $wpdb->error ) ) - wp_die( $wpdb->error ); - -// Set the database table prefix and the format specifiers for database table columns. -// @codingStandardsIgnoreStart -$GLOBALS['table_prefix'] = $table_prefix; -// @codingStandardsIgnoreEnd -wp_set_wpdb_vars(); - -// Start the WordPress object cache, or an external object cache if the drop-in is present. -wp_start_object_cache(); - -// Attach the default filters. -require( ABSPATH . WPINC . '/default-filters.php' ); - -// Initialize multisite if enabled. -if ( is_multisite() ) { - Utils\maybe_require( '4.6-alpha-37575', ABSPATH . WPINC . '/class-wp-site-query.php' ); - Utils\maybe_require( '4.6-alpha-37896', ABSPATH . WPINC . '/class-wp-network-query.php' ); - require( ABSPATH . WPINC . '/ms-blogs.php' ); - require( ABSPATH . WPINC . '/ms-settings.php' ); -} elseif ( ! defined( 'MULTISITE' ) ) { - define( 'MULTISITE', false ); -} - -register_shutdown_function( 'shutdown_action_hook' ); - -// Stop most of WordPress from being loaded if we just want the basics. -if ( SHORTINIT ) - return false; - -// Load the L10n library. -require_once( ABSPATH . WPINC . '/l10n.php' ); - -// WP-CLI: Permit Utils\wp_not_installed() to run on < WP 4.0 -apply_filters( 'nocache_headers', array() ); - -// Run the installer if WordPress is not installed. -wp_not_installed(); - -// Load most of WordPress. -require( ABSPATH . WPINC . '/class-wp-walker.php' ); -require( ABSPATH . WPINC . '/class-wp-ajax-response.php' ); -require( ABSPATH . WPINC . '/formatting.php' ); -require( ABSPATH . WPINC . '/capabilities.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-roles.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-role.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-user.php' ); -require( ABSPATH . WPINC . '/query.php' ); -Utils\maybe_require( '3.7-alpha-25139', ABSPATH . WPINC . '/date.php' ); -require( ABSPATH . WPINC . '/theme.php' ); -require( ABSPATH . WPINC . '/class-wp-theme.php' ); -require( ABSPATH . WPINC . '/template.php' ); -require( ABSPATH . WPINC . '/user.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-user-query.php' ); -Utils\maybe_require( '4.0', ABSPATH . WPINC . '/session.php' ); -require( ABSPATH . WPINC . '/meta.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-meta-query.php' ); -Utils\maybe_require( '4.5-alpha-35776', ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php' ); -require( ABSPATH . WPINC . '/general-template.php' ); -require( ABSPATH . WPINC . '/link-template.php' ); -require( ABSPATH . WPINC . '/author-template.php' ); -require( ABSPATH . WPINC . '/post.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-page-dropdown.php' ); -Utils\maybe_require( '4.6-alpha-37890', ABSPATH . WPINC . '/class-wp-post-type.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-post.php' ); -require( ABSPATH . WPINC . '/post-template.php' ); -Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/revision.php' ); -Utils\maybe_require( '3.6-alpha-23451', ABSPATH . WPINC . '/post-formats.php' ); -require( ABSPATH . WPINC . '/post-thumbnail-template.php' ); -require( ABSPATH . WPINC . '/category.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-category.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-category-dropdown.php' ); -require( ABSPATH . WPINC . '/category-template.php' ); -require( ABSPATH . WPINC . '/comment.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-comment.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-comment-query.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-walker-comment.php' ); -require( ABSPATH . WPINC . '/comment-template.php' ); -require( ABSPATH . WPINC . '/rewrite.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-rewrite.php' ); -require( ABSPATH . WPINC . '/feed.php' ); -require( ABSPATH . WPINC . '/bookmark.php' ); -require( ABSPATH . WPINC . '/bookmark-template.php' ); -require( ABSPATH . WPINC . '/kses.php' ); -require( ABSPATH . WPINC . '/cron.php' ); -require( ABSPATH . WPINC . '/deprecated.php' ); -require( ABSPATH . WPINC . '/script-loader.php' ); -require( ABSPATH . WPINC . '/taxonomy.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-term.php' ); -Utils\maybe_require( '4.6-alpha-37575', ABSPATH . WPINC . '/class-wp-term-query.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-tax-query.php' ); -require( ABSPATH . WPINC . '/update.php' ); -require( ABSPATH . WPINC . '/canonical.php' ); -require( ABSPATH . WPINC . '/shortcodes.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/embed.php' ); -require( ABSPATH . WPINC . '/class-wp-embed.php' ); -require( ABSPATH . WPINC . '/media.php' ); -Utils\maybe_require( '4.4-alpha-34903', ABSPATH . WPINC . '/class-wp-oembed-controller.php' ); -require( ABSPATH . WPINC . '/http.php' ); -require_once( ABSPATH . WPINC . '/class-http.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-streams.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-curl.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-proxy.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-cookie.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-encoding.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-http-response.php' ); -Utils\maybe_require( '4.6-alpha-37438', ABSPATH . WPINC . '/class-wp-http-requests-response.php' ); -require( ABSPATH . WPINC . '/widgets.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/class-wp-widget-factory.php' ); -require( ABSPATH . WPINC . '/nav-menu.php' ); -require( ABSPATH . WPINC . '/nav-menu-template.php' ); -require( ABSPATH . WPINC . '/admin-bar.php' ); -Utils\maybe_require( '4.4-alpha-34928', ABSPATH . WPINC . '/rest-api.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' ); -Utils\maybe_require( '4.4-beta4-35719', ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' ); - -// Load multisite-specific files. -if ( is_multisite() ) { - require( ABSPATH . WPINC . '/ms-functions.php' ); - require( ABSPATH . WPINC . '/ms-default-filters.php' ); - require( ABSPATH . WPINC . '/ms-deprecated.php' ); -} - -// Define constants that rely on the API to obtain the default value. -// Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. -wp_plugin_directory_constants(); - -$symlinked_plugins_supported = function_exists( 'wp_register_plugin_realpath' ); -if ( $symlinked_plugins_supported ) { - $GLOBALS['wp_plugin_paths'] = array(); -} - -// Load must-use plugins. -foreach ( wp_get_mu_plugins() as $mu_plugin ) { - include_once( $mu_plugin ); -} -unset( $mu_plugin ); - -// Load network activated plugins. -if ( is_multisite() ) { - foreach( wp_get_active_network_plugins() as $network_plugin ) { - if ( $symlinked_plugins_supported ) - wp_register_plugin_realpath( $network_plugin ); - include_once( $network_plugin ); - } - unset( $network_plugin ); -} - -do_action( 'muplugins_loaded' ); - -if ( is_multisite() ) - ms_cookie_constants( ); - -// Define constants after multisite is loaded. Cookie-related constants may be overridden in ms_network_cookies(). -wp_cookie_constants( ); - -// Define and enforce our SSL constants -wp_ssl_constants( ); - -// Create common globals. -require( ABSPATH . WPINC . '/vars.php' ); - -// Make taxonomies and posts available to plugins and themes. -// @plugin authors: warning: these get registered again on the init hook. -create_initial_taxonomies(); -create_initial_post_types(); - -// Register the default theme directory root -register_theme_directory( get_theme_root() ); - -// Load active plugins. -foreach ( wp_get_active_and_valid_plugins() as $plugin ) { - if ( $symlinked_plugins_supported ) - wp_register_plugin_realpath( $plugin ); - include_once( $plugin ); -} -unset( $plugin, $symlinked_plugins_supported ); - -// Load pluggable functions. -require( ABSPATH . WPINC . '/pluggable.php' ); -require( ABSPATH . WPINC . '/pluggable-deprecated.php' ); - -// Set internal encoding. -wp_set_internal_encoding(); - -// Run wp_cache_postload() if object cache is enabled and the function exists. -if ( WP_CACHE && function_exists( 'wp_cache_postload' ) ) - wp_cache_postload(); - -do_action( 'plugins_loaded' ); - -// Define constants which affect functionality if not already defined. -wp_functionality_constants( ); - -// Add magic quotes and set up $_REQUEST ( $_GET + $_POST ) -wp_magic_quotes(); - -do_action( 'sanitize_comment_cookies' ); - -/** - * WordPress Query object - * @global object $wp_the_query - * @since 2.0.0 - */ -$GLOBALS['wp_the_query'] = new WP_Query(); - -/** - * Holds the reference to @see $wp_the_query - * Use this global for WordPress queries - * @global object $wp_query - * @since 1.5.0 - */ -$GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; - -/** - * Holds the WordPress Rewrite object for creating pretty URLs - * @global object $wp_rewrite - * @since 1.5.0 - */ -$GLOBALS['wp_rewrite'] = new WP_Rewrite(); - -/** - * WordPress Object - * @global object $wp - * @since 2.0.0 - */ -$GLOBALS['wp'] = new WP(); - -/** - * WordPress Widget Factory Object - * @global object $wp_widget_factory - * @since 2.8.0 - */ -$GLOBALS['wp_widget_factory'] = new WP_Widget_Factory(); - -/** - * WordPress User Roles - * @global object $wp_roles - * @since 2.0.0 - */ -$GLOBALS['wp_roles'] = new WP_Roles(); - -do_action( 'setup_theme' ); - -// Define the template related constants. -wp_templating_constants( ); - -// Load the default text localization domain. -load_default_textdomain(); - -$locale = get_locale(); -$locale_file = WP_LANG_DIR . "/$locale.php"; -if ( ( 0 === validate_file( $locale ) ) && is_readable( $locale_file ) ) - require( $locale_file ); -unset( $locale_file ); - -// Pull in locale data after loading text domain. -require_once( ABSPATH . WPINC . '/locale.php' ); - -/** - * WordPress Locale object for loading locale domain date and various strings. - * @global object $wp_locale - * @since 2.1.0 - */ -$GLOBALS['wp_locale'] = new WP_Locale(); - -// Load the functions for the active theme, for both parent and child theme if applicable. -global $pagenow; -if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { - if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) - include( STYLESHEETPATH . '/functions.php' ); - if ( file_exists( TEMPLATEPATH . '/functions.php' ) ) - include( TEMPLATEPATH . '/functions.php' ); -} - -do_action( 'after_setup_theme' ); - -// Set up current user. -$GLOBALS['wp']->init(); - -/** - * Most of WP is loaded at this stage, and the user is authenticated. WP continues - * to load on the init hook that follows (e.g. widgets), and many plugins instantiate - * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.). - * - * If you wish to plug an action once WP is loaded, use the wp_loaded hook below. - */ -do_action( 'init' ); - -// Check site status -# if ( is_multisite() ) { // WP-CLI -if ( is_multisite() && !defined('WP_INSTALLING') ) { - if ( true !== ( $file = ms_site_check() ) ) { - require( $file ); - die(); - } - unset($file); -} - -/** - * This hook is fired once WP, all plugins, and the theme are fully loaded and instantiated. - * - * AJAX requests should use wp-admin/admin-ajax.php. admin-ajax.php can handle requests for - * users not logged in. - * - * @link http://codex.wordpress.org/AJAX_in_Plugins - * - * @since 3.0.0 - */ -do_action('wp_loaded'); diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 529dae0ef..000000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,11 +0,0 @@ -<phpunit - bootstrap="tests/bootstrap.php" - colors="true" - > - <testsuites> - <testsuite> - <directory prefix="spec-" suffix=".php">tests/</directory> - <directory prefix="test-" suffix=".php">tests/</directory> - </testsuite> - </testsuites> -</phpunit> diff --git a/templates/.editorconfig b/templates/.editorconfig deleted file mode 100644 index 79207a40c..000000000 --- a/templates/.editorconfig +++ /dev/null @@ -1,22 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org - -# WordPress Coding Standards -# https://make.wordpress.org/core/handbook/coding-standards/ - -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_style = tab -indent_size = 4 - -[{.jshintrc,*.json,*.yml}] -indent_style = space -indent_size = 2 - -[{*.txt,wp-config-sample.php}] -end_of_line = crlf diff --git a/templates/child_theme.mustache b/templates/child_theme.mustache deleted file mode 100644 index 3fda10143..000000000 --- a/templates/child_theme.mustache +++ /dev/null @@ -1,9 +0,0 @@ -/* -Theme Name: {{theme_name}} -Theme URI: {{theme_uri}} -Description: {{description}} -Author: {{author}} -Author URI: {{author_uri}} -Template: {{parent_theme}} -Version: 0.1.0 -*/ diff --git a/templates/child_theme_functions.mustache b/templates/child_theme_functions.mustache deleted file mode 100644 index d654c23db..000000000 --- a/templates/child_theme_functions.mustache +++ /dev/null @@ -1,12 +0,0 @@ -<?php - -add_action( 'wp_enqueue_scripts', '{{parent_theme_function_safe}}_parent_theme_enqueue_styles' ); - -function {{parent_theme_function_safe}}_parent_theme_enqueue_styles() { - wp_enqueue_style( '{{parent_theme}}-style', get_template_directory_uri() . '/style.css' ); - wp_enqueue_style( '{{slug}}-style', - get_stylesheet_directory_uri() . '/style.css', - array( '{{parent_theme}}-style' ) - ); - -} diff --git a/templates/install-wp-tests.sh b/templates/install-wp-tests.sh deleted file mode 100644 index 73bb4c787..000000000 --- a/templates/install-wp-tests.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 3 ]; then - echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]" - exit 1 -fi - -DB_NAME=$1 -DB_USER=$2 -DB_PASS=$3 -DB_HOST=${4-localhost} -WP_VERSION=${5-latest} -SKIP_DB_CREATE=${6-false} - -WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} -WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} - -download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; - elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi -} - -if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then - WP_TESTS_TAG="tags/$WP_VERSION" -elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then - WP_TESTS_TAG="trunk" -else - # http serves a single offer, whereas https serves multiple. we only want one - download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json - grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json - LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') - if [[ -z "$LATEST_VERSION" ]]; then - echo "Latest WordPress version could not be found" - exit 1 - fi - WP_TESTS_TAG="tags/$LATEST_VERSION" -fi - -set -ex - -install_wp() { - - if [ -d $WP_CORE_DIR ]; then - return; - fi - - mkdir -p $WP_CORE_DIR - - if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then - mkdir -p /tmp/wordpress-nightly - download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip - unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/ - mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR - else - if [ $WP_VERSION == 'latest' ]; then - local ARCHIVE_NAME='latest' - else - local ARCHIVE_NAME="wordpress-$WP_VERSION" - fi - download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - fi - - download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php -} - -install_test_suite() { - # portable in-place argument for both GNU sed and Mac OSX sed - if [[ $(uname -s) == 'Darwin' ]]; then - local ioption='-i .bak' - else - local ioption='-i' - fi - - # set up testing suite if it doesn't yet exist - if [ ! -d $WP_TESTS_DIR ]; then - # set up testing suite - mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data - fi - - if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php - # remove all forward slashes in the end - WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php - fi - -} - -install_db() { - - if [ ${SKIP_DB_CREATE} = "true" ]; then - return 0 - fi - - # parse DB_HOST for port or socket references - local PARTS=(${DB_HOST//\:/ }) - local DB_HOSTNAME=${PARTS[0]}; - local DB_SOCK_OR_PORT=${PARTS[1]}; - local EXTRA="" - - if ! [ -z $DB_HOSTNAME ] ; then - if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then - EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" - elif ! [ -z $DB_SOCK_OR_PORT ] ; then - EXTRA=" --socket=$DB_SOCK_OR_PORT" - elif ! [ -z $DB_HOSTNAME ] ; then - EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" - fi - fi - - # create database - mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA -} - -install_wp -install_test_suite -install_db diff --git a/templates/man-params.mustache b/templates/man-params.mustache deleted file mode 100644 index d2786014e..000000000 --- a/templates/man-params.mustache +++ /dev/null @@ -1,18 +0,0 @@ -{{#is_subcommand}} - - -{{/is_subcommand}} -{{#has_subcommands}} - - -{{/has_subcommands}} -## GLOBAL PARAMETERS - -{{#parameters}} - {{synopsis}} - {{desc}} - -{{/parameters}} -{{#root_command}} - Run 'wp help <command>' to get more information on a specific command. -{{/root_command}} diff --git a/templates/man.mustache b/templates/man.mustache deleted file mode 100644 index fbb2e9bd6..000000000 --- a/templates/man.mustache +++ /dev/null @@ -1,28 +0,0 @@ -## NAME - - {{name}} - -{{#shortdesc}} -## DESCRIPTION - - {{shortdesc}} - -{{/shortdesc}} -## SYNOPSIS - - {{synopsis}} - -{{#alias}} -## ALIAS - - {{alias}} - -{{/alias}} -{{#has-subcommands}} -## SUBCOMMANDS - -{{#subcommands}} - {{.}} -{{/subcommands}} - -{{/has-subcommands}} diff --git a/templates/phpcs.ruleset.xml b/templates/phpcs.ruleset.xml deleted file mode 100644 index 210c25a14..000000000 --- a/templates/phpcs.ruleset.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<ruleset name="WordPress Coding Standards for Plugins"> - <description>Generally-applicable sniffs for WordPress plugins</description> - - <rule ref="WordPress-Core" /> - <rule ref="WordPress-Docs" /> - - <exclude-pattern>*/node_modules/*</exclude-pattern> - <exclude-pattern>*/vendor/*</exclude-pattern> -</ruleset> diff --git a/templates/phpunit.xml.dist b/templates/phpunit.xml.dist deleted file mode 100644 index 44f0fdb69..000000000 --- a/templates/phpunit.xml.dist +++ /dev/null @@ -1,14 +0,0 @@ -<phpunit - bootstrap="tests/bootstrap.php" - backupGlobals="false" - colors="true" - convertErrorsToExceptions="true" - convertNoticesToExceptions="true" - convertWarningsToExceptions="true" - > - <testsuites> - <testsuite> - <directory prefix="test-" suffix=".php">./tests/</directory> - </testsuite> - </testsuites> -</phpunit> diff --git a/templates/plugin-bootstrap.mustache b/templates/plugin-bootstrap.mustache deleted file mode 100644 index 05c21bf1e..000000000 --- a/templates/plugin-bootstrap.mustache +++ /dev/null @@ -1,25 +0,0 @@ -<?php -/** - * PHPUnit bootstrap file - * - * @package {{plugin_package}} - */ - -$_tests_dir = getenv( 'WP_TESTS_DIR' ); -if ( ! $_tests_dir ) { - $_tests_dir = '/tmp/wordpress-tests-lib'; -} - -// Give access to tests_add_filter() function. -require_once $_tests_dir . '/includes/functions.php'; - -/** - * Manually load the plugin being tested. - */ -function _manually_load_plugin() { - require dirname( dirname( __FILE__ ) ) . '/{{plugin_slug}}.php'; -} -tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' ); - -// Start up the WP testing environment. -require $_tests_dir . '/includes/bootstrap.php'; diff --git a/templates/plugin-circle.mustache b/templates/plugin-circle.mustache deleted file mode 100644 index 08647555e..000000000 --- a/templates/plugin-circle.mustache +++ /dev/null @@ -1,19 +0,0 @@ -machine: - php: - version: 5.6.22 - environment: - PATH: $HOME/.composer/vendor/bin:$PATH - -dependencies: - pre: - - sudo apt-get update; sudo apt-get install subversion - -test: - pre: - - bash bin/install-wp-tests.sh wordpress_test ubuntu '' 127.0.0.1 latest - - | - composer global require wp-coding-standards/wpcs - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs - override: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit diff --git a/templates/plugin-distignore.mustache b/templates/plugin-distignore.mustache deleted file mode 100644 index 35045412d..000000000 --- a/templates/plugin-distignore.mustache +++ /dev/null @@ -1,28 +0,0 @@ -# A set of files you probably don't want in your WordPress.org distribution -.distignore -.editorconfig -.git -.gitignore -.gitlab-ci.yml -.travis.yml -.DS_Store -Thumbs.db -behat.yml -bin -circle.yml -composer.json -composer.lock -Gruntfile.js -package.json -phpunit.xml -phpunit.xml.dist -multisite.xml -multisite.xml.dist -phpcs.ruleset.xml -README.md -wp-cli.local.yml -tests -vendor -node_modules -*.zip -*.tar.gz diff --git a/templates/plugin-gitignore.mustache b/templates/plugin-gitignore.mustache deleted file mode 100644 index 833593b8d..000000000 --- a/templates/plugin-gitignore.mustache +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -Thumbs.db -wp-cli.local.yml -node_modules/ -*.zip -*.tar.gz diff --git a/templates/plugin-gitlab.mustache b/templates/plugin-gitlab.mustache deleted file mode 100644 index 1e30cc5f6..000000000 --- a/templates/plugin-gitlab.mustache +++ /dev/null @@ -1,41 +0,0 @@ -variables: - # Configure mysql service (https://hub.docker.com/_/mysql/) - MYSQL_DATABASE: wordpress_tests - MYSQL_ROOT_PASSWORD: mysql - -before_script: - # Install dependencies - - # update the docker - - apt-get clean - - apt-get -yqq update - - # instll the required packages for the running CI tests - - apt-get -yqqf install zip unzip subversion mysql-client libmysqlclient-dev --fix-missing - - # PHP extensions - - docker-php-ext-enable mbstring mcrypt mysqli pdo_mysql intl gd zip bz2 - - # Set up WordPress tests - - bash bin/install-wp-tests.sh wordpress_tests root mysql mysql latest true - - # Install PHPCS and WPCS - - composer global require "squizlabs/php_codesniffer=*" - - composer global require "wp-coding-standards/wpcs" - - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs - -PHPunit:PHP5.3:MySQL: - image: tetraweb/php:5.3 - services: - - mysql:5.6 - script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit --configuration phpunit.xml.dist - -PHPunit:PHP5.6:MySQL: - image: tetraweb/php:5.6 - services: - - mysql:5.6 - script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit --configuration phpunit.xml.dist \ No newline at end of file diff --git a/templates/plugin-gruntfile.mustache b/templates/plugin-gruntfile.mustache deleted file mode 100644 index 86a021bfb..000000000 --- a/templates/plugin-gruntfile.mustache +++ /dev/null @@ -1,53 +0,0 @@ -module.exports = function( grunt ) { - - 'use strict'; - var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n'; - // Project configuration - grunt.initConfig( { - - pkg: grunt.file.readJSON( 'package.json' ), - - addtextdomain: { - options: { - textdomain: '{{textdomain}}', - }, - target: { - files: { - src: [ '*.php', '**/*.php', '!node_modules/**', '!php-tests/**', '!bin/**' ] - } - } - }, - - wp_readme_to_markdown: { - your_target: { - files: { - 'README.md': 'readme.txt' - } - }, - }, - - makepot: { - target: { - options: { - domainPath: '/languages', - mainFile: '{{plugin_slug}}.php', - potFilename: '{{plugin_slug}}.pot', - potHeaders: { - poedit: true, - 'x-poedit-keywordslist': true - }, - type: 'wp-plugin', - updateTimestamp: true - } - } - }, - } ); - - grunt.loadNpmTasks( 'grunt-wp-i18n' ); - grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' ); - grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] ); - grunt.registerTask( 'readme', ['wp_readme_to_markdown'] ); - - grunt.util.linefeed = '\n'; - -}; diff --git a/templates/plugin-packages.mustache b/templates/plugin-packages.mustache deleted file mode 100644 index 84a60ca66..000000000 --- a/templates/plugin-packages.mustache +++ /dev/null @@ -1,12 +0,0 @@ - -{ - "name": "{{plugin_slug}}", - "version": "0.1.0", - "main": "Gruntfile.js", - "author": "{{plugin_author}}", - "devDependencies": { - "grunt": "~0.4.5", - "grunt-wp-i18n": "~0.5.0", - "grunt-wp-readme-to-markdown": "~1.0.0" - } -} diff --git a/templates/plugin-readme.mustache b/templates/plugin-readme.mustache deleted file mode 100644 index 6d6953479..000000000 --- a/templates/plugin-readme.mustache +++ /dev/null @@ -1,114 +0,0 @@ -=== {{plugin_name}} === -Contributors: (this should be a list of wordpress.org userid's) -Donate link: http://example.com/ -Tags: comments, spam -Requires at least: 3.7 -Tested up to: {{plugin_tested_up_to}} -Stable tag: 0.1.0 -License: GPLv2 or later -License URI: http://www.gnu.org/licenses/gpl-2.0.html - -Here is a short description of the plugin. This should be no more than 150 characters. No markup here. - -== Description == - -This is the long description. No limit, and you can use Markdown (as well as in the following sections). - -For backwards compatibility, if this section is missing, the full length of the short description will be used, and -Markdown parsed. - -A few notes about the sections above: - -* "Contributors" is a comma separated list of wp.org/wp-plugins.org usernames -* "Tags" is a comma separated list of tags that apply to the plugin -* "Requires at least" is the lowest version that the plugin will work on -* "Tested up to" is the highest version that you've *successfully used to test the plugin*. Note that it might work on -higher versions... this is just the highest one you've verified. -* Stable tag should indicate the Subversion "tag" of the latest stable version, or "trunk," if you use `/trunk/` for -stable. - - Note that the `readme.txt` of the stable tag is the one that is considered the defining one for the plugin, so -if the `/trunk/readme.txt` file says that the stable tag is `4.3`, then it is `/tags/4.3/readme.txt` that'll be used -for displaying information about the plugin. In this situation, the only thing considered from the trunk `readme.txt` -is the stable tag pointer. Thus, if you develop in trunk, you can update the trunk `readme.txt` to reflect changes in -your in-development version, without having that information incorrectly disclosed about the current stable version -that lacks those changes -- as long as the trunk's `readme.txt` points to the correct stable tag. - - If no stable tag is provided, it is assumed that trunk is stable, but you should specify "trunk" if that's where -you put the stable version, in order to eliminate any doubt. - -== Installation == - -This section describes how to install the plugin and get it working. - -e.g. - -1. Upload `plugin-name.php` to the `/wp-content/plugins/` directory -1. Activate the plugin through the 'Plugins' menu in WordPress -1. Place `<?php do_action('plugin_name_hook'); ?>` in your templates - -== Frequently Asked Questions == - -= A question that someone might have = - -An answer to that question. - -= What about foo bar? = - -Answer to foo bar dilemma. - -== Screenshots == - -1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from -the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets -directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png` -(or jpg, jpeg, gif). -2. This is the second screen shot - -== Changelog == - -= 1.0 = -* A change since the previous version. -* Another change. - -= 0.5 = -* List versions from most recent at top to oldest at bottom. - -== Upgrade Notice == - -= 1.0 = -Upgrade notices describe the reason a user should upgrade. No more than 300 characters. - -= 0.5 = -This version fixes a security related bug. Upgrade immediately. - -== Arbitrary section == - -You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated -plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or -"installation." Arbitrary sections will be shown below the built-in sections outlined above. - -== A brief Markdown Example == - -Ordered list: - -1. Some feature -1. Another feature -1. Something else about the plugin - -Unordered list: - -* something -* something else -* third thing - -Here's a link to [WordPress](http://wordpress.org/ "Your favorite software") and one to [Markdown's Syntax Documentation][markdown syntax]. -Titles are optional, naturally. - -[markdown syntax]: http://daringfireball.net/projects/markdown/syntax - "Markdown is what the parser uses to process much of the readme file" - -Markdown uses email style notation for blockquotes and I've been told: -> Asterisks for *emphasis*. Double it up for **strong**. - -`<?php code(); // goes in backticks ?>` diff --git a/templates/plugin-status.mustache b/templates/plugin-status.mustache deleted file mode 100644 index 375862690..000000000 --- a/templates/plugin-status.mustache +++ /dev/null @@ -1,6 +0,0 @@ -Plugin %9{{slug}}%n details: - Name: {{name}} - Status: {{status}}%n - Version: {{version}} - Author: {{author}} - Description: {{description}} diff --git a/templates/plugin-test-sample.mustache b/templates/plugin-test-sample.mustache deleted file mode 100644 index 2e897d13d..000000000 --- a/templates/plugin-test-sample.mustache +++ /dev/null @@ -1,20 +0,0 @@ -<?php -/** - * Class SampleTest - * - * @package {{plugin_package}} - */ - -/** - * Sample test case. - */ -class SampleTest extends WP_UnitTestCase { - - /** - * A single example test. - */ - function test_sample() { - // Replace this with some actual testing code. - $this->assertTrue( true ); - } -} diff --git a/templates/plugin-travis.mustache b/templates/plugin-travis.mustache deleted file mode 100644 index ea4ed6309..000000000 --- a/templates/plugin-travis.mustache +++ /dev/null @@ -1,47 +0,0 @@ -sudo: false - -language: php - -notifications: - email: - on_success: never - on_failure: change - -branches: - only: - - master - -cache: - - composer - - $HOME/.composer/cache - -php: - - 5.3 - - 5.6 - -env: -{{#wp_versions_to_test}} - - WP_VERSION={{.}} WP_MULTISITE=0 -{{/wp_versions_to_test}} - -matrix: - include: - - php: 5.3 - env: WP_VERSION=latest WP_MULTISITE=1 - -before_script: - - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION - - export PATH="$HOME/.composer/vendor/bin:$PATH" - - | - if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then - composer global require "phpunit/phpunit=5.7.*" - else - composer global require "phpunit/phpunit=4.8.*" - fi - - | - composer global require wp-coding-standards/wpcs - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs - -script: - - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php') - - phpunit diff --git a/templates/plugin.mustache b/templates/plugin.mustache deleted file mode 100644 index fc502b67a..000000000 --- a/templates/plugin.mustache +++ /dev/null @@ -1,13 +0,0 @@ -<?php -/** - * Plugin Name: {{plugin_name}} - * Plugin URI: {{plugin_uri}} - * Description: {{plugin_description}} - * Author: {{plugin_author}} - * Author URI: {{plugin_author_uri}} - * Text Domain: {{textdomain}} - * Domain Path: /languages - * Version: 0.1.0 - * - * @package {{plugin_package}} - */ diff --git a/templates/post_type.mustache b/templates/post_type.mustache deleted file mode 100644 index 02f96e197..000000000 --- a/templates/post_type.mustache +++ /dev/null @@ -1,29 +0,0 @@ - register_post_type( '{{slug}}', array( - 'labels' => array( - 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - 'singular_name' => __( '{{label_ucfirst}}', '{{textdomain}}' ), - 'all_items' => __( 'All {{label_plural_ucfirst}}', '{{textdomain}}' ), - 'new_item' => __( 'New {{label}}', '{{textdomain}}' ), - 'add_new' => __( 'Add New', '{{textdomain}}' ), - 'add_new_item' => __( 'Add New {{label}}', '{{textdomain}}' ), - 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), - 'view_item' => __( 'View {{label}}', '{{textdomain}}' ), - 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), - 'not_found' => __( 'No {{label_plural}} found', '{{textdomain}}' ), - 'not_found_in_trash' => __( 'No {{label_plural}} found in trash', '{{textdomain}}' ), - 'parent_item_colon' => __( 'Parent {{label}}', '{{textdomain}}' ), - 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - ), - 'public' => true, - 'hierarchical' => false, - 'show_ui' => true, - 'show_in_nav_menus' => true, - 'supports' => array( 'title', 'editor' ), - 'has_archive' => true, - 'rewrite' => true, - 'query_var' => true, - 'menu_icon' => 'dashicons-{{dashicon}}', - 'show_in_rest' => true, - 'rest_base' => '{{slug}}', - 'rest_controller_class' => 'WP_REST_Posts_Controller', - ) ); diff --git a/templates/post_type_extended.mustache b/templates/post_type_extended.mustache deleted file mode 100644 index b8250fde9..000000000 --- a/templates/post_type_extended.mustache +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -function {{machine_name}}_init() { -{{output}} -} -add_action( 'init', '{{machine_name}}_init' ); - -function {{machine_name}}_updated_messages( $messages ) { - global $post; - - $permalink = get_permalink( $post ); - - $messages['{{slug}}'] = array( - 0 => '', // Unused. Messages start at index 1. - 1 => sprintf( __('{{label_ucfirst}} updated. <a target="_blank" href="%s">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), - 2 => __('Custom field updated.', '{{textdomain}}'), - 3 => __('Custom field deleted.', '{{textdomain}}'), - 4 => __('{{label_ucfirst}} updated.', '{{textdomain}}'), - /* translators: %s: date and time of the revision */ - 5 => isset($_GET['revision']) ? sprintf( __('{{label_ucfirst}} restored to revision from %s', '{{textdomain}}'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, - 6 => sprintf( __('{{label_ucfirst}} published. <a href="%s">View {{label}}</a>', '{{textdomain}}'), esc_url( $permalink ) ), - 7 => __('{{label_ucfirst}} saved.', '{{textdomain}}'), - 8 => sprintf( __('{{label_ucfirst}} submitted. <a target="_blank" href="%s">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), - 9 => sprintf( __('{{label_ucfirst}} scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview {{label}}</a>', '{{textdomain}}'), - // translators: Publish box date format, see http://php.net/date - date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( $permalink ) ), - 10 => sprintf( __('{{label_ucfirst}} draft updated. <a target="_blank" href="%s">Preview {{label}}</a>', '{{textdomain}}'), esc_url( add_query_arg( 'preview', 'true', $permalink ) ) ), - ); - - return $messages; -} -add_filter( 'post_updated_messages', '{{machine_name}}_updated_messages' ); diff --git a/templates/taxonomy.mustache b/templates/taxonomy.mustache deleted file mode 100644 index cb00da9d1..000000000 --- a/templates/taxonomy.mustache +++ /dev/null @@ -1,36 +0,0 @@ - register_taxonomy( '{{slug}}', array( {{post_types}} ), array( - 'hierarchical' => false, - 'public' => true, - 'show_in_nav_menus' => true, - 'show_ui' => true, - 'show_admin_column' => false, - 'query_var' => true, - 'rewrite' => true, - 'capabilities' => array( - 'manage_terms' => 'edit_posts', - 'edit_terms' => 'edit_posts', - 'delete_terms' => 'edit_posts', - 'assign_terms' => 'edit_posts' - ), - 'labels' => array( - 'name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - 'singular_name' => _x( '{{label_ucfirst}}', 'taxonomy general name', '{{textdomain}}' ), - 'search_items' => __( 'Search {{label_plural}}', '{{textdomain}}' ), - 'popular_items' => __( 'Popular {{label_plural}}', '{{textdomain}}' ), - 'all_items' => __( 'All {{label_plural}}', '{{textdomain}}' ), - 'parent_item' => __( 'Parent {{label}}', '{{textdomain}}' ), - 'parent_item_colon' => __( 'Parent {{label}}:', '{{textdomain}}' ), - 'edit_item' => __( 'Edit {{label}}', '{{textdomain}}' ), - 'update_item' => __( 'Update {{label}}', '{{textdomain}}' ), - 'add_new_item' => __( 'New {{label}}', '{{textdomain}}' ), - 'new_item_name' => __( 'New {{label}}', '{{textdomain}}' ), - 'separate_items_with_commas' => __( 'Separate {{label_plural}} with commas', '{{textdomain}}' ), - 'add_or_remove_items' => __( 'Add or remove {{label_plural}}', '{{textdomain}}' ), - 'choose_from_most_used' => __( 'Choose from the most used {{label_plural}}', '{{textdomain}}' ), - 'not_found' => __( 'No {{label_plural}} found.', '{{textdomain}}' ), - 'menu_name' => __( '{{label_plural_ucfirst}}', '{{textdomain}}' ), - ), - 'show_in_rest' => true, - 'rest_base' => '{{slug}}', - 'rest_controller_class' => 'WP_REST_Terms_Controller', - ) ); diff --git a/templates/taxonomy_extended.mustache b/templates/taxonomy_extended.mustache deleted file mode 100644 index e2e584a11..000000000 --- a/templates/taxonomy_extended.mustache +++ /dev/null @@ -1,6 +0,0 @@ -<?php - -function {{machine_name}}_init() { -{{output}} -} -add_action( 'init', '{{machine_name}}_init' ); diff --git a/templates/theme-bootstrap.mustache b/templates/theme-bootstrap.mustache deleted file mode 100644 index 82c81cfc0..000000000 --- a/templates/theme-bootstrap.mustache +++ /dev/null @@ -1,34 +0,0 @@ -<?php -/** - * PHPUnit bootstrap file - * - * @package {{theme_package}} - */ - -$_tests_dir = getenv( 'WP_TESTS_DIR' ); -if ( ! $_tests_dir ) { - $_tests_dir = '/tmp/wordpress-tests-lib'; -} - -// Give access to tests_add_filter() function. -require_once $_tests_dir . '/includes/functions.php'; - -function _register_theme() { - - $theme_dir = dirname( dirname( __FILE__ ) ); - $current_theme = basename( $theme_dir ); - - register_theme_directory( dirname( $theme_dir ) ); - - add_filter( 'pre_option_template', function() use ( $current_theme ) { - return $current_theme; - }); - add_filter( 'pre_option_stylesheet', function() use ( $current_theme ) { - return $current_theme; - }); -} -tests_add_filter( 'muplugins_loaded', '_register_theme' ); - - -// Start up the WP testing environment. -require $_tests_dir . '/includes/bootstrap.php'; diff --git a/templates/theme-status.mustache b/templates/theme-status.mustache deleted file mode 100644 index c53be6338..000000000 --- a/templates/theme-status.mustache +++ /dev/null @@ -1,5 +0,0 @@ -Theme %9{{slug}}%n details: - Name: {{name}} - Status: {{status}}%n - Version: {{version}} - Author: {{author}} diff --git a/templates/theme-test-sample.mustache b/templates/theme-test-sample.mustache deleted file mode 100644 index ec78927c6..000000000 --- a/templates/theme-test-sample.mustache +++ /dev/null @@ -1,20 +0,0 @@ -<?php -/** - * Class SampleTest - * - * @package {{theme_package}} - */ - -/** - * Sample test case. - */ -class SampleTest extends WP_UnitTestCase { - - /** - * A single example test. - */ - function test_sample() { - // Replace this with some actual testing code. - $this->assertTrue( true ); - } -} diff --git a/templates/versions.mustache b/templates/versions.mustache deleted file mode 100644 index a52954e82..000000000 --- a/templates/versions.mustache +++ /dev/null @@ -1,4 +0,0 @@ -WordPress version: {{wp-version}} -Database revision: {{db-version}} -TinyMCE version: {{mce-version}} -Package language: {{local-package}} diff --git a/templates/wp-config.mustache b/templates/wp-config.mustache deleted file mode 100644 index 265a925cc..000000000 --- a/templates/wp-config.mustache +++ /dev/null @@ -1,74 +0,0 @@ -<?php -/** - * The base configuration for WordPress - * - * The wp-config.php creation script uses this file during the - * installation. You don't have to use the web site, you can - * copy this file to "wp-config.php" and fill in the values. - * - * This file contains the following configurations: - * - * * MySQL settings - * * Secret keys - * * Database table prefix - * * ABSPATH - * - * @link https://codex.wordpress.org/Editing_wp-config.php - * - * @package WordPress - */ - -// ** MySQL settings ** // -/** The name of the database for WordPress */ -define( 'DB_NAME', '{{dbname}}' ); - -/** MySQL database username */ -define( 'DB_USER', '{{dbuser}}' ); - -/** MySQL database password */ -define( 'DB_PASSWORD', '{{dbpass}}' ); - -/** MySQL hostname */ -define( 'DB_HOST', '{{dbhost}}' ); - -/** Database Charset to use in creating database tables. */ -define( 'DB_CHARSET', '{{dbcharset}}' ); - -/** The Database Collate type. Don't change this if in doubt. */ -define( 'DB_COLLATE', '{{dbcollate}}' ); - -/** - * Authentication Unique Keys and Salts. - * - * Change these to different unique phrases! - * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} - * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. - * - * @since 2.6.0 - */ -{{#keys-and-salts}} -{{keys-and-salts}} -{{/keys-and-salts}} - -/** - * WordPress Database Table prefix. - * - * You can have multiple installations in one database if you give each - * a unique prefix. Only numbers, letters, and underscores please! - */ -$table_prefix = '{{dbprefix}}'; - -{{#add-wplang}} -define( 'WPLANG', '{{locale}}' ); -{{/add-wplang}} - -{{extra-php}} - -/* That's all, stop editing! Happy blogging. */ - -/** Absolute path to the WordPress directory. */ -if ( ! defined( 'ABSPATH' ) ) - define( 'ABSPATH', dirname( __FILE__ ) . '/' ); - -/** Sets up WordPress vars and included files. */ -require_once ABSPATH . 'wp-settings.php'; diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index cea88d887..000000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -require_once getcwd() . '/vendor/autoload.php'; -require_once getcwd() . '/php/utils.php'; - diff --git a/tests/test-arg-validation.php b/tests/test-arg-validation.php deleted file mode 100644 index 4a3b3680c..000000000 --- a/tests/test-arg-validation.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php - -use WP_CLI\SynopsisValidator; - -class ArgValidationTests extends PHPUnit_Framework_TestCase { - - function testMissingPositional() { - $validator = new SynopsisValidator( '<foo> <bar> [<baz>]' ); - - $this->assertFalse( $validator->enough_positionals( array() ) ); - $this->assertTrue( $validator->enough_positionals( array( 1, 2 ) ) ); - $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3, 4 ) ) ); - - $this->assertEquals( array( 4 ), $validator->unknown_positionals( array( 1, 2, 3, 4 ) ) ); - } - - function testRepeatingPositional() { - $validator = new SynopsisValidator( '<foo> [<bar>...]' ); - - $this->assertFalse( $validator->enough_positionals( array() ) ); - $this->assertTrue( $validator->enough_positionals( array( 1 ) ) ); - $this->assertTrue( $validator->enough_positionals( array( 1, 2, 3 ) ) ); - - $this->assertEmpty( $validator->unknown_positionals( array( 1, 2, 3 ) ) ); - } - - function testUnknownAssocEmpty() { - $validator = new SynopsisValidator( '' ); - - $assoc_args = array( 'foo' => true, 'bar' => false ); - $this->assertEquals( array_keys( $assoc_args ), $validator->unknown_assoc( $assoc_args ) ); - } - - function testUnknownAssoc() { - $validator = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); - - $assoc_args = array( 'type' => 'analog', 'brand' => true, 'flag' => true ); - $this->assertEmpty( $validator->unknown_assoc( $assoc_args ) ); - - $assoc_args['another'] = true; - $this->assertContains( 'another', $validator->unknown_assoc( $assoc_args ) ); - } - - function testMissingAssoc() { - $validator = new SynopsisValidator( '--type=<type> [--brand=<brand>] [--flag]' ); - - $assoc_args = array( 'brand' => true, 'flag' => true ); - list( $errors, $to_unset ) = $validator->validate_assoc( $assoc_args ); - - $this->assertCount( 1, $errors['fatal'] ); - $this->assertCount( 1, $errors['warning'] ); - } - - function testAssocWithOptionalValue() { - $validator = new SynopsisValidator( '[--network[=<id>]]' ); - - $assoc_args = array( 'network' => true ); - list( $errors, $to_unset ) = $validator->validate_assoc( $assoc_args ); - - $this->assertCount( 0, $errors['fatal'] ); - $this->assertCount( 0, $errors['warning'] ); - } -} - diff --git a/tests/test-configurator.php b/tests/test-configurator.php deleted file mode 100644 index ea13aaeb3..000000000 --- a/tests/test-configurator.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -use WP_CLI\Configurator; - -class ConfiguratorTest extends PHPUnit_Framework_TestCase { - - function testExtractAssoc() { - $args = Configurator::extract_assoc( array( 'foo', '--bar', '--baz=text' ) ); - - $this->assertCount( 1, $args[0] ); - $this->assertCount( 2, $args[1] ); - - $this->assertEquals( 'foo', $args[0][0] ); - - $this->assertEquals( 'bar', $args[1][0][0] ); - $this->assertTrue( $args[1][0][1] ); - - $this->assertEquals( 'baz', $args[1][1][0] ); - $this->assertEquals( 'text', $args[1][1][1] ); - - } - - function testExtractAssocNoValue() { - $args = Configurator::extract_assoc( array( 'foo', '--bar=', '--baz=text' ) ); - - $this->assertCount( 1, $args[0] ); - $this->assertCount( 2, $args[1] ); - - $this->assertEquals( 'foo', $args[0][0] ); - - $this->assertEquals( 'bar', $args[1][0][0] ); - $this->assertEmpty( $args[1][0][1] ); - - $this->assertEquals( 'baz', $args[1][1][0] ); - $this->assertEquals( 'text', $args[1][1][1] ); - - } - - function testExtractAssocGlobalLocal() { - $args = Configurator::extract_assoc( array( '--url=foo.dev', '--path=wp', 'foo', '--bar=', '--baz=text', '--url=bar.dev' ) ); - - $this->assertCount( 1, $args[0] ); - $this->assertCount( 5, $args[1] ); - $this->assertCount( 2, $args[2] ); - $this->assertCount( 3, $args[3] ); - - $this->assertEquals( 'url', $args[2][0][0] ); - $this->assertEquals( 'foo.dev', $args[2][0][1] ); - $this->assertEquals( 'url', $args[3][2][0] ); - $this->assertEquals( 'bar.dev', $args[3][2][1] ); - } - - function testExtractAssocDoubleDashInValue() { - $args = Configurator::extract_assoc( array( '--test=text--text' ) ); - - $this->assertCount( 0, $args[0] ); - $this->assertCount( 1, $args[1] ); - - $this->assertEquals( 'test', $args[1][0][0] ); - $this->assertEquals( 'text--text', $args[1][0][1] ); - - } - - -} diff --git a/tests/test-doc-parser.php b/tests/test-doc-parser.php deleted file mode 100644 index c82ed4e69..000000000 --- a/tests/test-doc-parser.php +++ /dev/null @@ -1,198 +0,0 @@ -<?php - -use WP_CLI\DocParser; - -class DocParserTests extends PHPUnit_Framework_TestCase { - - function test_empty() { - $doc = new DocParser( '' ); - - $this->assertEquals( '', $doc->get_shortdesc() ); - $this->assertEquals( '', $doc->get_longdesc() ); - $this->assertEquals( '', $doc->get_synopsis() ); - $this->assertEquals( '', $doc->get_tag('alias') ); - } - - function test_only_tags() { - $doc = new DocParser( <<<EOB -/** - * @alias rock-on - */ -EOB - ); - - $this->assertEquals( '', $doc->get_shortdesc() ); - $this->assertEquals( '', $doc->get_longdesc() ); - $this->assertEquals( '', $doc->get_synopsis() ); - $this->assertEquals( '', $doc->get_tag('foo') ); - $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); - } - - function test_no_longdesc() { - $doc = new DocParser( <<<EOB -/** - * Rock and roll! - * @alias rock-on - */ -EOB - ); - - $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); - $this->assertEquals( '', $doc->get_longdesc() ); - $this->assertEquals( '', $doc->get_synopsis() ); - $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); - } - - function test_complete() { - $doc = new DocParser( <<<EOB -/** - * Rock and roll! - * - * ## OPTIONS - * - * <genre>... - * : Start with one or more genres. - * - * --volume=<number> - * : Sets the volume. - * - * --artist=<artist-name> - * : Limit to a specific artist. - * - * ## EXAMPLES - * - * wp rock-on --volume=11 - * - * @synopsis [--volume=<number>] - * @alias rock-on - */ -EOB - ); - - $this->assertEquals( 'Rock and roll!', $doc->get_shortdesc() ); - $this->assertEquals( '[--volume=<number>]', $doc->get_synopsis() ); - $this->assertEquals( 'Start with one or more genres.', $doc->get_arg_desc( 'genre' ) ); - $this->assertEquals( 'Sets the volume.', $doc->get_param_desc( 'volume' ) ); - $this->assertEquals( 'rock-on', $doc->get_tag('alias') ); - - $longdesc = <<<EOB -## OPTIONS - -<genre>... -: Start with one or more genres. - ---volume=<number> -: Sets the volume. - ---artist=<artist-name> -: Limit to a specific artist. - -## EXAMPLES - -wp rock-on --volume=11 -EOB - ; - $this->assertEquals( $longdesc, $doc->get_longdesc() ); - } - - public function test_desc_parses_yaml() { - $longdesc = <<<EOB -Play some music loudly - -``` -# Here's an example of how you might run the command -wp rock-on electronic --volume=11 -``` - -## OPTIONS - -<genre>... -: Start with one or more genres. ---- -options: - - rock - - electronic -default: rock ---- - ---volume=<number> -: Sets the volume. ---- -default: 10 ---- - ---artist=<artist-name> -: Limit to a specific artist. - -## EXAMPLES - -wp rock-on electronic --volume=11 - -EOB; - $doc = new DocParser( $longdesc ); - $this->assertEquals( 'Start with one or more genres.', $doc->get_arg_desc( 'genre' ) ); - $this->assertEquals( 'Sets the volume.', $doc->get_param_desc( 'volume' ) ); - $this->assertEquals( array( - 'options' => array( 'rock', 'electronic' ), - 'default' => 'rock', - ), $doc->get_arg_args( 'genre' ) ); - $this->assertEquals( array( - 'default' => 10, - ), $doc->get_param_args( 'volume' ) ); - $this->assertNull( $doc->get_param_args( 'artist' ) ); - } - - public function test_desc_doesnt_parse_far_params_yaml() { - $longdesc = <<<EOB -## OPTIONS - -<hook> -: The name of the action or filter. - -[--format=<format>] -: List callbacks as a table, JSON, CSV, or YAML. ---- -default: table -options: - - table - - json - - csv - - yaml ---- -EOB; - $doc = new DocParser( $longdesc ); - $this->assertEquals( array( - 'default' => 'table', - 'options' => array( 'table', 'json', 'csv', 'yaml' ), - ), $doc->get_param_args( 'format' ) ); - $this->assertNull( $doc->get_arg_args( 'hook' ) ); - } - - public function test_desc_doesnt_parse_far_args_yaml() { - $longdesc = <<<EOB -## OPTIONS - -<hook> -: The name of the action or filter. - -<format> -: List callbacks as a table, JSON, CSV, or YAML. ---- -default: table -options: - - table - - json - - csv - - yaml ---- -EOB; - $doc = new DocParser( $longdesc ); - $this->assertEquals( array( - 'default' => 'table', - 'options' => array( 'table', 'json', 'csv', 'yaml' ), - ), $doc->get_arg_args( 'format' ) ); - $this->assertNull( $doc->get_arg_args( 'hook' ) ); - } - -} - diff --git a/tests/test-logging.php b/tests/test-logging.php deleted file mode 100644 index 98604965f..000000000 --- a/tests/test-logging.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -class MockRegularLogger extends WP_CLI\Loggers\Regular { - - protected function get_runner() { - return (object) array ( - 'config' => array ( - 'debug' => true - ) - ); - } - - protected function write( $handle, $str ) { - echo $str; - } -} - -class MockQuietLogger extends WP_CLI\Loggers\Quiet { - - protected function get_runner() { - return (object) array ( - 'config' => array ( - 'debug' => true - ) - ); - } -} - -class LoggingTests extends PHPUnit_Framework_TestCase { - - function testLogDebug() { - define( 'WP_CLI_START_MICROTIME', microtime( true ) ); - $message = 'This is a test message.'; - - $regularLogger = new MockRegularLogger( false ); - $this->expectOutputRegex( "/Debug: {$message} \(\d+\.*\d*s\)/" ); - $regularLogger->debug( $message ); - - $quietLogger = new MockQuietLogger(); - $this->expectOutputRegex( "/Debug: {$message} \(\d+\.*\d*s\)/" ); - $quietLogger->debug( $message ); - } - - function testLogEscaping() { - $logger = new MockRegularLogger( false ); - - $message = 'foo%20bar'; - - $this->expectOutputString( "Success: $message\n" ); - $logger->success( $message ); - } -} diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php deleted file mode 100644 index c08a8a475..000000000 --- a/tests/test-search-replace.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php - -class UnserializeReplaceTest extends PHPUnit_Framework_TestCase { - - private static function recursive_unserialize_replace( $from, $to, $data, $serialised = false, $recurse_objects = false ) { - $replacer = new \WP_CLI\SearchReplacer( $from, $to, $recurse_objects ); - return $replacer->run( $data, $serialised ); - } - - function testReplaceString() { - $orig = 'foo'; - $replacement = self::recursive_unserialize_replace( 'foo', 'bar', $orig ); - $this->assertEquals( 'bar', $replacement ); - } - - function testPrivateConstructor() { - $old_obj = ClassWithPrivateConstructor::get_instance(); - - $new_obj = self::recursive_unserialize_replace( 'foo', 'bar', $old_obj, false, true ); - $this->assertEquals( 'bar', $new_obj->prop ); - } - - function testObjectLoop() { - $old_object = new stdClass(); - $old_object->prop = 'foo'; - $old_object->self = $old_object; - - $new_obj = self::recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); - $this->assertEquals( 'bar', $new_obj->prop ); - } - - function testArrayLoop() { - $old_array = array( 'prop' => 'foo' ); - $old_array['self'] = &$old_array; - - $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); - $this->assertEquals( 'bar', $new_array['prop'] ); - } - - function testArraySameValues() { - $old_array = array( - 'prop1' => array( - 'foo', - ), - 'prop2' => array( - 'foo', - ), - ); - $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); - $this->assertEquals( 'bar', $new_array['prop1'][0] ); - $this->assertEquals( 'bar', $new_array['prop2'][0] ); - } - - function testMixedObjectArrayLoop() { - $old_object = new stdClass(); - $old_object->prop = 'foo'; - $old_object->array = array('prop' => 'foo'); - $old_object->array['object'] = $old_object; - - $new_object = self::recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true ); - $this->assertEquals( 'bar', $new_object->prop ); - $this->assertEquals( 'bar', $new_object->array['prop']); - } - - function testMixedArrayObjectLoop() { - $old_array = array( 'prop' => 'foo', 'object' => new stdClass() ); - $old_array['object']->prop = 'foo'; - $old_array['object']->array = &$old_array; - - $new_array = self::recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true ); - $this->assertEquals( 'bar', $new_array['prop'] ); - $this->assertEquals( 'bar', $new_array['object']->prop); - } -} - - -class ClassWithPrivateConstructor { - - public $prop = 'foo'; - - private function __construct() {} - - public static function get_instance() { - return new self; - } -} diff --git a/tests/test-synopsis.php b/tests/test-synopsis.php deleted file mode 100644 index 919227d9e..000000000 --- a/tests/test-synopsis.php +++ /dev/null @@ -1,175 +0,0 @@ -<?php - -use WP_CLI\SynopsisParser; - -class SynopsisParserTest extends PHPUnit_Framework_TestCase { - - function testEmpty() { - $r = SynopsisParser::parse( ' ' ); - - $this->assertEmpty( $r ); - } - - function testPositional() { - $r = SynopsisParser::parse( '<plugin|zip> [<bar>]' ); - - $this->assertCount( 2, $r ); - - $param = $r[0]; - $this->assertEquals( 'positional', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $param = $r[1]; - $this->assertEquals( 'positional', $param['type'] ); - $this->assertTrue( $param['optional'] ); - } - - function testFlag() { - $r = SynopsisParser::parse( '[--foo]' ); - - $this->assertCount( 1, $r ); - - $param = $r[0]; - $this->assertEquals( 'flag', $param['type'] ); - $this->assertTrue( $param['optional'] ); - - // flags can't be mandatory - $r = SynopsisParser::parse( '--foo' ); - - $this->assertCount( 1, $r ); - - $param = $r[0]; - $this->assertEquals( 'unknown', $param['type'] ); - } - - function testGeneric() { - $r = SynopsisParser::parse( '--<field>=<value> [--<field>=<value>] --<field>[=<value>] [--<field>[=<value>]]' ); - - $this->assertCount( 4, $r ); - - $param = $r[0]; - $this->assertEquals( 'generic', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $param = $r[1]; - $this->assertEquals( 'generic', $param['type'] ); - $this->assertTrue( $param['optional'] ); - - $param = $r[2]; - $this->assertEquals( 'unknown', $param['type'] ); - - $param = $r[3]; - $this->assertEquals( 'unknown', $param['type'] ); - } - - function testAssoc() { - $r = SynopsisParser::parse( '--foo=<value> [--bar=<value>] [--bar[=<value>]]' ); - - $this->assertCount( 3, $r ); - - $param = $r[0]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $param = $r[1]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertTrue( $param['optional'] ); - - $param = $r[2]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertTrue( $param['optional'] ); - $this->assertTrue( $param['value']['optional'] ); - } - - function testInvalidAssoc() { - $r = SynopsisParser::parse( '--bar[=<value>] --bar=[<value>] --count=100' ); - - $this->assertCount( 3, $r ); - - $this->assertEquals( 'unknown', $r[0]['type'] ); - $this->assertEquals( 'unknown', $r[1]['type'] ); - $this->assertEquals( 'unknown', $r[2]['type'] ); - } - - function testRepeating() { - $r = SynopsisParser::parse( '<positional>... [--<field>=<value>...]' ); - - $this->assertCount( 2, $r ); - - $param = $r[0]; - $this->assertEquals( 'positional', $param['type'] ); - $this->assertTrue( $param['repeating'] ); - - $param = $r[1]; - $this->assertEquals( 'generic', $param['type'] ); - $this->assertTrue( $param['repeating'] ); - } - - function testCombined() { - $r = SynopsisParser::parse( '<positional> --assoc=<someval> --<field>=<value> [--flag]' ); - - $this->assertCount( 4, $r ); - - $this->assertEquals( 'positional', $r[0]['type'] ); - $this->assertEquals( 'assoc', $r[1]['type'] ); - $this->assertEquals( 'generic', $r[2]['type'] ); - $this->assertEquals( 'flag', $r[3]['type'] ); - } - - function testAllowedValueCharacters() { - $r = SynopsisParser::parse( '--capitals=<VALUE> --hyphen=<val-ue> --combined=<VAL-ue> --disallowed=<wrong:char>' ); - - $this->assertCount( 4, $r ); - - $param = $r[0]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $param = $r[1]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $param = $r[2]; - $this->assertEquals( 'assoc', $param['type'] ); - $this->assertFalse( $param['optional'] ); - - $this->assertEquals( 'unknown', $r[3]['type'] ); - } - - function testRender() { - $a = array( - array( - 'name' => 'message', - 'type' => 'positional', - 'description' => 'A short message to display to the user.', - ), - array( - 'name' => 'secrets', - 'type' => 'positional', - 'description' => 'You may tell secrets, or you may not', - 'optional' => true, - 'repeating' => true, - ), - array( - 'name' => 'meal', - 'type' => 'assoc', - 'description' => 'A meal during the day or night.', - ), - array( - 'name' => 'snack', - 'type' => 'assoc', - 'description' => 'If you are hungry between meals, you should snack.', - 'optional' => true, - ) - ); - $this->assertEquals( '<message> [<secrets>...] --meal=<meal> [--snack=<snack>]', SynopsisParser::render( $a ) ); - } - - function testParseThenRender() { - $o = '<positional> --assoc=<assoc> --<field>=<value> [--flag]'; - $a = SynopsisParser::parse( $o ); - $r = SynopsisParser::render( $a ); - $this->assertEquals( $o, $r ); - } - -} diff --git a/tests/test-utils.php b/tests/test-utils.php deleted file mode 100644 index 358606913..000000000 --- a/tests/test-utils.php +++ /dev/null @@ -1,130 +0,0 @@ -<?php - -use WP_CLI\Utils; - -class UtilsTest extends PHPUnit_Framework_TestCase { - - function testIncrementVersion() { - // keyword increments - $this->assertEquals( - Utils\increment_version( '1.2.3-pre', 'same' ), - '1.2.3-pre' - ); - - $this->assertEquals( - Utils\increment_version( '1.2.3-pre', 'patch' ), - '1.2.4' - ); - - $this->assertEquals( - Utils\increment_version( '1.2.3-pre', 'minor' ), - '1.3.0' - ); - - $this->assertEquals( - Utils\increment_version( '1.2.3-pre', 'major' ), - '2.0.0' - ); - - // custom version string - $this->assertEquals( - Utils\increment_version( '1.2.3-pre', '4.5.6-alpha1' ), - '4.5.6-alpha1' - ); - } - - public function testGetSemVer() { - $original_version = '0.19.1'; - $this->assertEmpty( Utils\get_named_sem_ver( '0.18.0', $original_version ) ); - $this->assertEmpty( Utils\get_named_sem_ver( '0.19.1', $original_version ) ); - $this->assertEquals( 'patch', Utils\get_named_sem_ver( '0.19.2', $original_version ) ); - $this->assertEquals( 'minor', Utils\get_named_sem_ver( '0.20.0', $original_version ) ); - $this->assertEquals( 'minor', Utils\get_named_sem_ver( '0.20.3', $original_version ) ); - $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.0.0', $original_version ) ); - $this->assertEquals( 'major', Utils\get_named_sem_ver( '1.1.1', $original_version ) ); - } - - public function testGetSemVerWP() { - $original_version = '3.0'; - $this->assertEmpty( Utils\get_named_sem_ver( '2.8', $original_version ) ); - $this->assertEmpty( Utils\get_named_sem_ver( '2.9.1', $original_version ) ); - $this->assertEquals( 'patch', Utils\get_named_sem_ver( '3.0.1', $original_version ) ); - $this->assertEquals( 'minor', Utils\get_named_sem_ver( '3.1', $original_version ) ); - $this->assertEquals( 'minor', Utils\get_named_sem_ver( '3.1.1', $original_version ) ); - $this->assertEquals( 'major', Utils\get_named_sem_ver( '4.0', $original_version ) ); - $this->assertEquals( 'major', Utils\get_named_sem_ver( '4.1.1', $original_version ) ); - } - - public function testParseSSHUrl() { - $testcase = 'foo'; - $this->assertEquals( array( - 'host' => 'foo', - ), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( 'foo', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - - $testcase = 'foo.com'; - $this->assertEquals( array( - 'host' => 'foo.com', - ), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - - $testcase = 'foo.com:2222'; - $this->assertEquals( array( - 'host' => 'foo.com', - 'port' => 2222, - ), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( 2222, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - - $testcase = 'foo.com:2222/path/to/dir'; - $this->assertEquals( array( - 'host' => 'foo.com', - 'port' => 2222, - 'path' => '/path/to/dir', - ), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( 2222, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( '/path/to/dir', Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - - $testcase = 'foo.com~/path/to/dir'; - $this->assertEquals( array( - 'host' => 'foo.com', - 'path' => '~/path/to/dir', - ), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( 'foo.com', Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( '~/path/to/dir', Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - - // No host - $testcase = '~/path/to/dir'; - $this->assertEquals( array(), Utils\parse_ssh_url( $testcase ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_HOST ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PORT ) ); - $this->assertEquals( null, Utils\parse_ssh_url( $testcase, PHP_URL_PATH ) ); - } - - public function testParseStrToArgv() { - $this->assertEquals( array(), Utils\parse_str_to_argv( '' ) ); - $this->assertEquals( array( - 'option', - 'get', - 'home', - ), Utils\parse_str_to_argv( 'option get home' ) ); - $this->assertEquals( array( - 'core', - 'download', - '--path=/var/www/', - ), Utils\parse_str_to_argv( 'core download --path=/var/www/' ) ); - $this->assertEquals( array( - 'eval', - 'echo wp_get_current_user()->user_login;', - ), Utils\parse_str_to_argv( 'eval "echo wp_get_current_user()->user_login;"' ) ); - } - -} - diff --git a/utils/amp-paths.txt b/utils/amp-paths.txt deleted file mode 100644 index a6c891d3b..000000000 --- a/utils/amp-paths.txt +++ /dev/null @@ -1,5 +0,0 @@ -/Applications/MAMP/bin/php/php5.3*/bin/php -/Applications/MAMP/bin/php5*/bin/php -/Applications/MAMP/bin/php/php5.[34]*/bin/php -/Applications/xampp/xamppfiles/bin/php; -/opt/lampp/bin/php diff --git a/utils/contrib-list b/utils/contrib-list deleted file mode 100755 index f3c887b84..000000000 --- a/utils/contrib-list +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 1 ]; then - echo "usage: $(basename $0) v0.8.0..master [-l]" - exit 1 -fi - -prev_version=$1 -linked=$2 - -githubify() { - while read name; do - local url="https://github.com/$name" - local response_code=$(curl -o /dev/null --silent --head --write-out '%{http_code}\n' $url) - - if [ "200" != "$response_code" ]; then - echo "$response_code: $url" 1>&2; - fi - - echo " [$name]($url)" - done -} - -if [ '-l' == "$linked" ] -then - git log --format="%aN" $prev_version -- | sort -f | uniq | githubify | tr '\n' ',' - echo -else - git log --format="%aN <%aE>" $prev_version -- | sort -f | uniq -fi diff --git a/utils/convert-docs.php b/utils/convert-docs.php deleted file mode 100644 index b3b9668c8..000000000 --- a/utils/convert-docs.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -# usage: php utils/convert-docs.php man-src/*.txt - -function convert_file( $path ) { - $out = file_get_contents( $path ); - - // options to definition lists - $out = preg_replace_callback( '/\n\* (.+?):?\n\n\t/', function( $matches ) { - $arg = str_replace( '`', '', $matches[1] ); - - return "\n$arg\n: "; - }, $out ); - - // fix indentation - $out = preg_replace( '/^ ([^ ]+)/m', "\t\\1", $out ); - $out = str_replace( "\t", ' ', $out ); - - // prepend docblock notation - $out = preg_replace( '/^/m', "\t * ", $out ); - - file_put_contents( $path, $out ); -} - -foreach ( array_slice( $argv, 1 ) as $arg ) { - convert_file( $arg ); -} diff --git a/utils/find-php b/utils/find-php deleted file mode 100755 index f8d19f4a2..000000000 --- a/utils/find-php +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env sh - -# Special case for *AMP installers, since they normally don't set themselves -# as the default cli php out of the box. -for amp_php in $(cat $(dirname $0)/amp-paths.txt); do - if [ -x $amp_php ]; then - echo $amp_php - exit - fi -done - -which php || which php-cli - -if [ $? -eq 0 ]; then - exit -fi - -echo "no PHP binary found" >&2 -exit 1 diff --git a/utils/get-package-require-from-composer.php b/utils/get-package-require-from-composer.php deleted file mode 100644 index 33e30ccfd..000000000 --- a/utils/get-package-require-from-composer.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -$file = $argv[1]; -if ( ! file_exists( $file ) ) { - echo 'File does not exist.'; - exit(1); -} - -$contents = file_get_contents( $file ); -$composer = json_decode( $contents ); - -if ( empty( $composer ) || ! is_object( $composer ) ) { - echo 'Invalid composer.json for package.'; - exit(1); -} - -if ( empty( $composer->autoload->files ) ) { - echo 'composer.json must specify valid "autoload" => "files"'; - exit(1); -} - -echo implode( PHP_EOL, $composer->autoload->files ); -exit(0); \ No newline at end of file diff --git a/utils/make-phar-spec.php b/utils/make-phar-spec.php deleted file mode 100644 index d5f3165c4..000000000 --- a/utils/make-phar-spec.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -return array( - 'output' => array( - 'runtime' => '=<path>', - 'file' => '<path>', - 'desc' => 'Path to output file', - ), - - 'version' => array( - 'runtime' => '=<version>', - 'file' => '<version>', - 'desc' => 'New package version', - ), - - 'store-version' => array( - 'runtime' => '', - 'file' => '<bool>', - 'default' => false, - 'desc' => 'If true the contents of ./VERSION will be set to the value passed to --version', - ), - - 'quiet' => array( - 'runtime' => '', - 'file' => '<bool>', - 'default' => false, - 'desc' => 'Suppress informational messages', - ), -); - diff --git a/utils/make-phar.php b/utils/make-phar.php deleted file mode 100644 index 5370b482a..000000000 --- a/utils/make-phar.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php - -define( 'WP_CLI_ROOT', dirname( dirname( __FILE__ ) ) ); - -require WP_CLI_ROOT . '/vendor/autoload.php'; -require WP_CLI_ROOT . '/php/utils.php'; - -use Symfony\Component\Finder\Finder; -use WP_CLI\Utils; -use WP_CLI\Configurator; - -$configurator = new Configurator( WP_CLI_ROOT . '/utils/make-phar-spec.php' ); - -list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); - -if ( ! isset( $args[0] ) || empty( $args[0] ) ) { - echo "usage: php -dphar.readonly=0 $argv[0] <path> [--quiet] [--version=same|patch|minor|major|x.y.z] [--store-version]\n"; - exit(1); -} - -define( 'DEST_PATH', $args[0] ); - -define( 'BE_QUIET', isset( $runtime_config['quiet'] ) && $runtime_config['quiet'] ); - -$current_version = trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ); - -if ( isset( $runtime_config['version'] ) ) { - $new_version = $runtime_config['version']; - $new_version = Utils\increment_version( $current_version, $new_version ); - - if ( isset( $runtime_config['store-version'] ) && $runtime_config['store-version'] ) { - file_put_contents( WP_CLI_ROOT . '/VERSION', $new_version ); - } - - $current_version = $new_version; -} - -function add_file( $phar, $path ) { - $key = str_replace( WP_CLI_ROOT, '', $path ); - - if ( !BE_QUIET ) - echo "$key - $path\n"; - - $phar[ $key ] = file_get_contents( $path ); -} - -function set_file_contents( $phar, $path, $content ) { - $key = str_replace( WP_CLI_ROOT, '', $path ); - - if ( !BE_QUIET ) - echo "$key - $path\n"; - - $phar[ $key ] = $content; -} - -$phar = new Phar( DEST_PATH, 0, 'wp-cli.phar' ); - -$phar->startBuffering(); - -// PHP files -$finder = new Finder(); -$finder - ->files() - ->ignoreVCS(true) - ->name('*.php') - ->in(WP_CLI_ROOT . '/php') - ->in(WP_CLI_ROOT . '/features') - ->in(WP_CLI_ROOT . '/vendor/wp-cli') - ->in(WP_CLI_ROOT . '/vendor/mustache') - ->in(WP_CLI_ROOT . '/vendor/rmccue/requests') - ->in(WP_CLI_ROOT . '/vendor/composer') - ->in(WP_CLI_ROOT . '/vendor/psr') - ->in(WP_CLI_ROOT . '/vendor/seld') - ->in(WP_CLI_ROOT . '/vendor/symfony') - ->in(WP_CLI_ROOT . '/vendor/nb/oxymel') - ->in(WP_CLI_ROOT . '/vendor/ramsey/array_column') - ->in(WP_CLI_ROOT . '/vendor/mustangostang') - ->in(WP_CLI_ROOT . '/vendor/justinrainbow/json-schema') - ->exclude('test') - ->exclude('tests') - ->exclude('Test') - ->exclude('Tests') - ->exclude('php-cli-tools/examples') - ; - -foreach ( $finder as $file ) { - add_file( $phar, $file ); -} - -// other files -$finder = new Finder(); -$finder - ->files() - ->ignoreVCS(true) - ->ignoreDotFiles(false) - ->in( WP_CLI_ROOT . '/templates') - ; - -foreach ( $finder as $file ) { - add_file( $phar, $file ); -} - -add_file( $phar, WP_CLI_ROOT . '/vendor/autoload.php' ); -add_file( $phar, WP_CLI_ROOT . '/ci/behat-tags.php' ); -add_file( $phar, WP_CLI_ROOT . '/vendor/composer/ca-bundle/res/cacert.pem' ); -add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/LICENSE' ); -add_file( $phar, WP_CLI_ROOT . '/vendor/composer/composer/res/composer-schema.json' ); -add_file( $phar, WP_CLI_ROOT . '/vendor/rmccue/requests/library/Requests/Transport/cacert.pem' ); - -set_file_contents( $phar, WP_CLI_ROOT . '/VERSION', $current_version ); - -$phar->setStub( <<<EOB -#!/usr/bin/env php -<?php -Phar::mapPhar(); -include 'phar://wp-cli.phar/php/boot-phar.php'; -__HALT_COMPILER(); -?> -EOB -); - -$phar->stopBuffering(); - -echo "Generated " . DEST_PATH . "\n"; diff --git a/utils/test-phar-download b/utils/test-phar-download deleted file mode 100755 index f4c9ad7f4..000000000 --- a/utils/test-phar-download +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | md5sum | cut -d ' ' -f 1) - -echo "expected:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.md5) -echo "actual: " $actual_checksum - -actual_checksum=$(curl http://wp-cli.org/packages/phar/wp-cli.phar | sha512sum | cut -d ' ' -f 1) - -echo "expected SHA-512:" $(curl -s http://wp-cli.org/packages/phar/wp-cli.phar.sha512) -echo "actual SHA-512: " $actual_checksum diff --git a/utils/update-phar b/utils/update-phar deleted file mode 100755 index e2b16973e..000000000 --- a/utils/update-phar +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -version=${1-"same"} - -current_rev=$(git rev-parse HEAD) -current_rev=${current_rev:0:10} - -packages_repo=../wp-cli-packages - -fname="phar/wp-cli.phar" - -# generate archive -php -dphar.readonly=0 ./utils/make-phar.php $packages_repo/$fname --quiet --version=$version --store-version - -cd $packages_repo - -# smoke test -php $fname --version - -# check which wp-cli commit the previous Phar archive was based on -# can't use the md5 hash, since it will be different each time the -# archive is generated -new_commit_subj="update wp-cli.phar to wp-cli/wp-cli@$current_rev" - -current_commit_subj=$(git show -s --pretty=format:%s HEAD) - -if [ "$new_commit_subj" = "$current_commit_subj" ]; then - echo "already at latest revision" - exit 1 -fi - -# generate md5 checksum -if [ command -v md5sum > /dev/null ] -then - md5hash=$(md5sum $fname) -else - md5hash=$(md5 -r $fname) -fi - -echo $md5hash | cut -d ' ' -f 1 > $fname.md5 - -sha512sum $fname | cut -d ' ' -f 1 > $fname.sha512 - -git add $fname $fname.md5 $fname.sha512 - -git commit -m "$new_commit_subj" - -git push diff --git a/utils/wp-cli-updatedeb.sh b/utils/wp-cli-updatedeb.sh deleted file mode 100755 index 27a81182c..000000000 --- a/utils/wp-cli-updatedeb.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash -# -# Package wp-cli to be installed in Debian-compatible systems. -# Only the phar file is included. -# -# VERSION :0.2.2 -# DATE :2016-10-26 -# AUTHOR :Viktor Szépe <viktor@szepe.net> -# LICENSE :The MIT License (MIT) -# URL :https://github.com/wp-cli/wp-cli/tree/master/utils -# BASH-VERSION :4.2+ - -# packages source path -DIR="php-wpcli" -# phar URL -PHAR="https://github.com/wp-cli/builds/raw/gh-pages/phar/wp-cli.phar" - -die() { - local RET="$1" - shift - - echo -e "$@" >&2 - exit "$RET" -} - -dump_control() { - cat > DEBIAN/control <<EOF -Package: php-wpcli -Version: 0.0.0 -Architecture: all -Maintainer: Daniel Bachhuber <daniel@handbuilt.co> -Section: php -Priority: optional -Depends: php5-cli (>= 5.3.29) | php-cli | php7-cli, php5-mysql | php5-mysqlnd | php7.0-mysql, mysql-client | mariadb-client -Homepage: http://wp-cli.org/ -Description: wp-cli is a set of command-line tools for managing - WordPress installations. You can update plugins, set up multisite - installs and much more, without using a web browser. - -EOF -} - -# deb's dir -if ! [ -d "$DIR" ]; then - mkdir "$DIR" || die 1 "Cannot create directory here: ${PWD}" -fi - -pushd "$DIR" - -# control file -if ! [ -r DEBIAN/control ]; then - mkdir DEBIAN - dump_control -fi - -# copyright -if ! [ -r usr/share/doc/php-wpcli/copyright ];then - mkdir -p usr/share/doc/php-wpcli &> /dev/null - wget -nv -O usr/share/doc/php-wpcli/copyright https://github.com/wp-cli/wp-cli/raw/master/LICENSE.txt -fi - -# changelog -if ! [ -r usr/share/doc/php-wpcli/changelog.gz ];then - mkdir -p usr/share/doc/php-wpcli &> /dev/null - echo "Changelog can be found in the blog: http://wp-cli.org/blog/" \ - | gzip -n -9 > usr/share/doc/php-wpcli/changelog.gz -fi - -# minimal man page -if ! [ -r usr/share/man/man1/wp.1.gz ];then - mkdir -p usr/share/man/man1 &> /dev/null - { - echo '.TH "WP" "1"' - wp --help - } \ - | sed 's/^\([A-Z ]\+\)$/.SH "\1"/' \ - | sed 's/^ wp$/wp \\- A command line interface for WordPress/' \ - | gzip -n -9 > usr/share/man/man1/wp.1.gz -fi - -# content dirs -[ -d usr/bin ] || mkdir -p usr/bin - -# download current version -wget -nv -O usr/bin/wp "$PHAR" || die 3 "Phar download failure" -chmod +x usr/bin/wp || die 4 "chmod failure" - -# get version -WPCLI_VER="$(usr/bin/wp cli version|cut -d" " -f2)" -[ -z "$WPCLI_VER" ] && die 5 "Cannot get wp-cli version" -echo "Current version: ${WPCLI_VER}" - -# update version -sed -i "s/^Version: .*$/Version: ${WPCLI_VER}/" DEBIAN/control || die 6 "Version update failure" - -# update MD5-s -find usr -type f -exec md5sum \{\} \; > DEBIAN/md5sums || die 7 "md5sum creation failure" - -popd - -# build package in the current diretory -WPCLI_PKG="${PWD}/php-wpcli_${WPCLI_VER}_all.deb" -fakeroot dpkg-deb --build "$DIR" "$WPCLI_PKG" || die 8 "Packaging failed" - -# check package -lintian --display-info --display-experimental --pedantic --show-overrides php-wpcli_*_all.deb - -# optional steps -echo "sign it: dpkg-sig -k YOUR-KEY -s builder \"${WPCLI_PKG}\"" -echo "include in your repo: pushd /var/www/REPO-DIR" -echo " reprepro includedeb jessie \"${WPCLI_PKG}\" && popd" diff --git a/utils/wp-completion.bash b/utils/wp-completion.bash deleted file mode 100644 index 9df572b6d..000000000 --- a/utils/wp-completion.bash +++ /dev/null @@ -1,23 +0,0 @@ -# bash completion for the `wp` command - -_wp_complete() { - local OLD_IFS="$IFS" - local cur=${COMP_WORDS[COMP_CWORD]} - - IFS=$'\n'; # want to preserve spaces at the end - local opts="$(wp cli completions --line="$COMP_LINE" --point="$COMP_POINT")" - - if [[ "$opts" =~ \<file\>\s* ]] - then - COMPREPLY=( $(compgen -f -- $cur) ) - elif [[ $opts = "" ]] - then - COMPREPLY=( $(compgen -f -- $cur) ) - else - COMPREPLY=( ${opts[*]} ) - fi - - IFS="$OLD_IFS" - return 0 -} -complete -o nospace -F _wp_complete wp From 16ab805be36da659e5820c54d4fbbb3d5e4185e0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 8 Mar 2017 18:26:53 -0800 Subject: [PATCH 5336/5359] Use PSR-4 autoloading of existing classes; add remaining test files --- .distignore | 13 + .editorconfig | 25 + .gitignore | 7 + .travis.yml | 40 + LICENSE | 21 + README.md | 130 +++ bin/install-package-tests.sh | 40 + composer.json | 33 + export-command.php | 12 + features/bootstrap/FeatureContext.php | 345 +++++++ features/bootstrap/Process.php | 75 ++ features/bootstrap/ProcessRun.php | 33 + features/bootstrap/support.php | 194 ++++ features/bootstrap/utils.php | 838 ++++++++++++++++++ features/extra/no-mail.php | 7 + features/steps/given.php | 164 ++++ features/steps/then.php | 210 +++++ features/steps/when.php | 54 ++ .../functions.export.php => functions.php | 0 php/export/writers.php | 184 ---- .../export.php => src/Export_Command.php | 4 +- src/WP_Export_Base_Writer.php | 19 + src/WP_Export_Exception.php | 4 + src/WP_Export_File_Writer.php | 35 + .../WP_Export_Oxymel.php | 0 .../WP_Export_Query.php | 5 - src/WP_Export_Returner.php | 24 + src/WP_Export_Split_Files_Writer.php | 70 ++ src/WP_Export_Term_Exception.php | 4 + .../WP_Export_WXR_Formatter.php | 0 src/WP_Export_XML_Over_HTTP.php | 42 + src/WP_Iterator_Exception.php | 4 + src/WP_Map_Iterator.php | 13 + .../WP_Post_IDs_Iterator.php | 14 - utils/behat-tags.php | 46 + wp-cli.yml | 2 + 36 files changed, 2505 insertions(+), 206 deletions(-) create mode 100644 .distignore create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100755 bin/install-package-tests.sh create mode 100644 composer.json create mode 100644 export-command.php create mode 100644 features/bootstrap/FeatureContext.php create mode 100644 features/bootstrap/Process.php create mode 100644 features/bootstrap/ProcessRun.php create mode 100644 features/bootstrap/support.php create mode 100644 features/bootstrap/utils.php create mode 100644 features/extra/no-mail.php create mode 100644 features/steps/given.php create mode 100644 features/steps/then.php create mode 100644 features/steps/when.php rename php/export/functions.export.php => functions.php (100%) delete mode 100644 php/export/writers.php rename php/commands/export.php => src/Export_Command.php (99%) create mode 100644 src/WP_Export_Base_Writer.php create mode 100644 src/WP_Export_Exception.php create mode 100644 src/WP_Export_File_Writer.php rename php/export/class-wp-export-oxymel.php => src/WP_Export_Oxymel.php (100%) rename php/export/class-wp-export-query.php => src/WP_Export_Query.php (98%) create mode 100644 src/WP_Export_Returner.php create mode 100644 src/WP_Export_Split_Files_Writer.php create mode 100644 src/WP_Export_Term_Exception.php rename php/export/class-wp-export-wxr-formatter.php => src/WP_Export_WXR_Formatter.php (100%) create mode 100644 src/WP_Export_XML_Over_HTTP.php create mode 100644 src/WP_Iterator_Exception.php create mode 100644 src/WP_Map_Iterator.php rename php/export/iterators.php => src/WP_Post_IDs_Iterator.php (81%) create mode 100644 utils/behat-tags.php create mode 100644 wp-cli.yml diff --git a/.distignore b/.distignore new file mode 100644 index 000000000..b964b40c7 --- /dev/null +++ b/.distignore @@ -0,0 +1,13 @@ +.DS_Store +.git +.gitignore +.gitlab-ci.yml +.editorconfig +.travis.yml +behat.yml +circle.yml +bin/ +features/ +utils/ +*.zip +*.tar.gz diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..fa483b1bb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml,*.feature}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf + +[composer.json] +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f3b908269 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +wp-cli.local.yml +node_modules/ +vendor/ +*.zip +*.tar.gz +composer.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..6aa217ee1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,40 @@ +sudo: false + +language: php + +notifications: + email: + on_success: never + on_failure: change + +branches: + only: + - master + +cache: + - composer + - $HOME/.composer/cache + +env: + global: + - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + +matrix: + include: + - php: 7.1 + env: WP_VERSION=latest + - php: 7.0 + env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=trunk + - php: 5.3 + env: WP_VERSION=latest + +before_script: + - phpenv config-rm xdebug.ini + - composer validate + - bash bin/install-package-tests.sh + +script: ./vendor/bin/behat --format progress --strict diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..0c6145565 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2011-2017 WP-CLI Development Group (https://github.com/wp-cli/export-command/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..3d1cb84f5 --- /dev/null +++ b/README.md @@ -0,0 +1,130 @@ +wp-cli/export-command +===================== + +Manage exports. + +[![Build Status](https://travis-ci.org/wp-cli/export-command.svg?branch=master)](https://travis-ci.org/wp-cli/export-command) + +Quick links: [Using](#using) | [Installing](#installing) | [Contributing](#contributing) + +## Using + +~~~ +wp export [--dir=<dirname>] [--skip_comments] [--max_file_size=<MB>] [--start_date=<date>] [--end_date=<date>] [--post_type=<post-type>] [--post_type__not_in=<post-type>] [--post__in=<pid>] [--start_id=<pid>] [--author=<author>] [--category=<name>] [--post_status=<status>] [--filename_format=<format>] +~~~ + +Generates one or more WXR files containing authors, terms, posts, +comments, and attachments. WXR files do not include site configuration +(options) or the attachment files themselves. + +**OPTIONS** + + [--dir=<dirname>] + Full path to directory where WXR export files should be stored. Defaults + to current working directory. + + [--skip_comments] + Don't include comments in the WXR export file. + + [--max_file_size=<MB>] + A single export file should have this many megabytes. + --- + default: 15 + --- + +**FILTERS** + + [--start_date=<date>] + Export only posts published after this date, in format YYYY-MM-DD. + + [--end_date=<date>] + Export only posts published before this date, in format YYYY-MM-DD. + + [--post_type=<post-type>] + Export only posts with this post_type. Separate multiple post types with a + comma. + --- + default: any + --- + + [--post_type__not_in=<post-type>] + Export all post types except those identified. Separate multiple post types + with a comma. Defaults to none. + + [--post__in=<pid>] + Export all posts specified as a comma- or space-separated list of IDs. + + [--start_id=<pid>] + Export only posts with IDs greater than or equal to this post ID. + + [--author=<author>] + Export only posts by this author. Can be either user login or user ID. + + [--category=<name>] + Export only posts in this category. + + [--post_status=<status>] + Export only posts with this status. + + [--filename_format=<format>] + Use a custom format for export filenames. Defaults to '{site}.wordpress.{date}.{n}.xml'. + +**EXAMPLES** + + # Export posts published by the user between given start and end date + $ wp export --dir=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 + Starting export process... + Writing to file /tmp/staging.wordpress.2016-05-24.000.xml + Success: All done with export. + + # Export posts by IDs + $ wp export --dir=/tmp/ --post__in=123,124,125 + Starting export process... + Writing to file /tmp/staging.wordpress.2016-05-24.000.xml + Success: All done with export. + + # Export a random subset of content + $ wp export --post__in="$(wp post list --post_type=post --orderby=rand --posts_per_page=8 --format=ids)" + Starting export process... + Writing to file /var/www/example.com/public_html/staging.wordpress.2016-05-24.000.xml + Success: All done with export. + +## Installing + +Installing this package requires WP-CLI v0.23.0 or greater. Update to the latest stable release with `wp cli update`. + +Once you've done so, you can install this package with `wp package install wp-cli/export-command`. + +## Contributing + +We appreciate you taking the initiative to contribute to this project. + +Contributing isn’t limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. + +### Reporting a bug + +Think you’ve found a bug? We’d love for you to help us get it fixed. + +Before you create a new issue, you should [search existing issues](https://github.com/wp-cli/export-command/issues?q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version. + +Once you’ve done a bit of searching and discovered there isn’t an open or fixed issue for your bug, please [create a new issue](https://github.com/wp-cli/export-command/issues/new) with the following: + +1. What you were doing (e.g. "When I run `wp post list`"). +2. What you saw (e.g. "I see a fatal about a class being undefined."). +3. What you expected to see (e.g. "I expected to see the list of posts.") + +Include as much detail as you can, and clear steps to reproduce if possible. + +### Creating a pull request + +Want to contribute a new feature? Please first [open a new issue](https://github.com/wp-cli/export-command/issues/new) to discuss whether the feature is a good fit for the project. + +Once you've decided to commit the time to seeing your pull request through, please follow our guidelines for creating a pull request to make sure it's a pleasant experience: + +1. Create a feature branch for each contribution. +2. Submit your pull request early for feedback. +3. Include functional tests with your changes. [Read the WP-CLI documentation](https://wp-cli.org/docs/pull-requests/#functional-tests) for an introduction. +4. Follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). + + +*This README.md is generated dynamically from the project's codebase using `wp scaffold package-readme` ([doc](https://github.com/wp-cli/scaffold-package-command#wp-scaffold-package-readme)). To suggest changes, please submit a pull request against the corresponding part of the codebase.* diff --git a/bin/install-package-tests.sh b/bin/install-package-tests.sh new file mode 100755 index 000000000..3026f0826 --- /dev/null +++ b/bin/install-package-tests.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -ex + +WP_CLI_BIN_DIR=${WP_CLI_BIN_DIR-/tmp/wp-cli-phar} + +PACKAGE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )" + +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + +install_wp_cli() { + + # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR + mkdir -p $WP_CLI_BIN_DIR + download https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp + chmod +x $WP_CLI_BIN_DIR/wp + +} + +download_behat() { + + cd $PACKAGE_DIR + composer require --dev behat/behat='~2.5' + +} + +install_db() { + mysql -e 'CREATE DATABASE IF NOT EXISTS wp_cli_test;' -uroot + mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot +} + +install_wp_cli +download_behat +install_db diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..ae4ac0dc5 --- /dev/null +++ b/composer.json @@ -0,0 +1,33 @@ +{ + "name": "wp-cli/export-command", + "description": "Manage exports.", + "type": "wp-cli-package", + "homepage": "https://github.com/wp-cli/export-command", + "support": { + "issues": "https://github.com/wp-cli/export-command/issues" + }, + "license": "MIT", + "authors": [ + { + "name": "Daniel Bachhuber", + "email": "daniel@runcommand.io", + "homepage": "https://runcommand.io" + } + ], + "minimum-stability": "dev", + "autoload": { + "psr-4": {"": "src/"}, + "files": [ "export-command.php" ] + }, + "require": { + "nb/oxymel": "~0.1.0" + }, + "require-dev": { + "behat/behat": "~2.5" + }, + "extra": { + "commands": [ + "export" + ] + } +} diff --git a/export-command.php b/export-command.php new file mode 100644 index 000000000..4add2dfca --- /dev/null +++ b/export-command.php @@ -0,0 +1,12 @@ +<?php + +if ( ! class_exists( 'WP_CLI' ) ) { + return; +} + +$autoload = dirname( __FILE__ ) . '/vendor/autoload.php'; +if ( file_exists( $autoload ) ) { + require_once $autoload; +} + +WP_CLI::add_command( 'export', 'Export_Command' ); diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php new file mode 100644 index 000000000..cc72cc02c --- /dev/null +++ b/features/bootstrap/FeatureContext.php @@ -0,0 +1,345 @@ +<?php + +use Behat\Behat\Context\ClosuredContextInterface, + Behat\Behat\Context\TranslatedContextInterface, + Behat\Behat\Context\BehatContext, + Behat\Behat\Event\SuiteEvent; + +use \WP_CLI\Process; +use \WP_CLI\Utils; + +// Inside a community package +if ( file_exists( __DIR__ . '/utils.php' ) ) { + require_once __DIR__ . '/utils.php'; + require_once __DIR__ . '/Process.php'; + require_once __DIR__ . '/ProcessRun.php'; + $project_composer = dirname( dirname( dirname( __FILE__ ) ) ) . '/composer.json'; + if ( file_exists( $project_composer ) ) { + $composer = json_decode( file_get_contents( $project_composer ) ); + if ( ! empty( $composer->autoload->files ) ) { + $contents = 'require:' . PHP_EOL; + foreach( $composer->autoload->files as $file ) { + $contents .= ' - ' . dirname( dirname( dirname( __FILE__ ) ) ) . '/' . $file . PHP_EOL; + } + @mkdir( sys_get_temp_dir() . '/wp-cli-package-test/' ); + $project_config = sys_get_temp_dir() . '/wp-cli-package-test/config.yml'; + file_put_contents( $project_config, $contents ); + putenv( 'WP_CLI_CONFIG_PATH=' . $project_config ); + } + } +// Inside WP-CLI +} else { + require_once __DIR__ . '/../../php/utils.php'; + require_once __DIR__ . '/../../php/WP_CLI/Process.php'; + require_once __DIR__ . '/../../php/WP_CLI/ProcessRun.php'; + require_once __DIR__ . '/../../vendor/autoload.php'; +} + +/** + * Features context. + */ +class FeatureContext extends BehatContext implements ClosuredContextInterface { + + private static $cache_dir, $suite_cache_dir; + + private static $db_settings = array( + 'dbname' => 'wp_cli_test', + 'dbuser' => 'wp_cli_test', + 'dbpass' => 'password1', + 'dbhost' => '127.0.0.1', + ); + + private $running_procs = array(); + + public $variables = array(); + + /** + * Get the environment variables required for launched `wp` processes + * @beforeSuite + */ + private static function get_process_env_variables() { + // Ensure we're using the expected `wp` binary + $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); + $env = array( + 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), + 'BEHAT_RUN' => 1, + 'HOME' => '/tmp/wp-cli-home', + ); + if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { + $env['WP_CLI_CONFIG_PATH'] = $config_path; + } + return $env; + } + + // We cache the results of `wp core download` to improve test performance + // Ideally, we'd cache at the HTTP layer for more reliable tests + private static function cache_wp_files() { + self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test core-download-cache'; + + if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) + return; + + $cmd = Utils\esc_cmd( 'wp core download --force --path=%s', self::$cache_dir ); + if ( getenv( 'WP_VERSION' ) ) { + $cmd .= Utils\esc_cmd( ' --version=%s', getenv( 'WP_VERSION' ) ); + } + Process::create( $cmd, null, self::get_process_env_variables() )->run_check(); + } + + /** + * @BeforeSuite + */ + public static function prepare( SuiteEvent $event ) { + $result = Process::create( 'wp cli info', null, self::get_process_env_variables() )->run_check(); + echo PHP_EOL; + echo $result->stdout; + echo PHP_EOL; + self::cache_wp_files(); + $result = Process::create( Utils\esc_cmd( 'wp core version --path=%s', self::$cache_dir ) , null, self::get_process_env_variables() )->run_check(); + echo 'WordPress ' . $result->stdout; + echo PHP_EOL; + } + + /** + * @AfterSuite + */ + public static function afterSuite( SuiteEvent $event ) { + if ( self::$suite_cache_dir ) { + Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ), null, self::get_process_env_variables() )->run(); + } + } + + /** + * @BeforeScenario + */ + public function beforeScenario( $event ) { + $this->variables['SRC_DIR'] = realpath( __DIR__ . '/../..' ); + } + + /** + * @AfterScenario + */ + public function afterScenario( $event ) { + if ( isset( $this->variables['RUN_DIR'] ) ) { + // remove altered WP install, unless there's an error + if ( $event->getResult() < 4 ) { + $this->proc( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); + } + } + + // Remove WP-CLI package directory + if ( isset( $this->variables['PACKAGE_PATH'] ) ) { + $this->proc( Utils\esc_cmd( 'rm -rf %s', $this->variables['PACKAGE_PATH'] ) )->run(); + } + + foreach ( $this->running_procs as $proc ) { + self::terminate_proc( $proc ); + } + } + + /** + * Terminate a process and any of its children. + */ + private static function terminate_proc( $proc ) { + $status = proc_get_status( $proc ); + + $master_pid = $status['pid']; + + $output = `ps -o ppid,pid,command | grep $master_pid`; + + foreach ( explode( PHP_EOL, $output ) as $line ) { + if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) { + $parent = $matches[1]; + $child = $matches[2]; + + if ( $parent == $master_pid ) { + if ( ! posix_kill( (int) $child, 9 ) ) { + throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); + } + } + } + } + + if ( ! posix_kill( (int) $master_pid, 9 ) ) { + throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); + } + } + + public static function create_cache_dir() { + self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); + mkdir( self::$suite_cache_dir ); + return self::$suite_cache_dir; + } + + /** + * Initializes context. + * Every scenario gets it's own context object. + * + * @param array $parameters context parameters (set them up through behat.yml) + */ + public function __construct( array $parameters ) { + if ( getenv( 'WP_CLI_TEST_DBHOST' ) ) { + self::$db_settings['dbhost'] = getenv( 'WP_CLI_TEST_DBHOST' ); + } + $this->drop_db(); + $this->set_cache_dir(); + $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); + } + + public function getStepDefinitionResources() { + return glob( __DIR__ . '/../steps/*.php' ); + } + + public function getHookDefinitionResources() { + return array(); + } + + public function replace_variables( $str ) { + return preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); + } + + private function _replace_var( $matches ) { + $cmd = $matches[0]; + + foreach ( array_slice( $matches, 1 ) as $key ) { + $cmd = str_replace( '{' . $key . '}', $this->variables[ $key ], $cmd ); + } + + return $cmd; + } + + public function create_run_dir() { + if ( !isset( $this->variables['RUN_DIR'] ) ) { + $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); + mkdir( $this->variables['RUN_DIR'] ); + } + } + + public function build_phar( $version = 'same' ) { + $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; + + $this->proc( Utils\esc_cmd( + 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', + __DIR__ . '/../../utils/make-phar.php', + $this->variables['PHAR_PATH'], + $version + ) )->run_check(); + } + + private function set_cache_dir() { + $path = sys_get_temp_dir() . '/wp-cli-test-cache'; + $this->proc( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + $this->variables['CACHE_DIR'] = $path; + } + + private static function run_sql( $sql ) { + Utils\run_mysql_command( 'mysql --no-defaults', array( + 'execute' => $sql, + 'host' => self::$db_settings['dbhost'], + 'user' => self::$db_settings['dbuser'], + 'pass' => self::$db_settings['dbpass'], + ) ); + } + + public function create_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "CREATE DATABASE IF NOT EXISTS $dbname" ); + } + + public function drop_db() { + $dbname = self::$db_settings['dbname']; + self::run_sql( "DROP DATABASE IF EXISTS $dbname" ); + } + + public function proc( $command, $assoc_args = array(), $path = '' ) { + if ( !empty( $assoc_args ) ) + $command .= Utils\assoc_args_to_str( $assoc_args ); + + $env = self::get_process_env_variables(); + if ( isset( $this->variables['SUITE_CACHE_DIR'] ) ) { + $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; + } + + if ( isset( $this->variables['RUN_DIR'] ) ) { + $cwd = "{$this->variables['RUN_DIR']}/{$path}"; + } else { + $cwd = null; + } + + return Process::create( $command, $cwd, $env ); + } + + /** + * Start a background process. Will automatically be closed when the tests finish. + */ + public function background_proc( $cmd ) { + $descriptors = array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + + $proc = proc_open( $cmd, $descriptors, $pipes, $this->variables['RUN_DIR'], self::get_process_env_variables() ); + + sleep(1); + + $status = proc_get_status( $proc ); + + if ( !$status['running'] ) { + throw new RuntimeException( stream_get_contents( $pipes[2] ) ); + } else { + $this->running_procs[] = $proc; + } + } + + public function move_files( $src, $dest ) { + rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); + } + + public function add_line_to_wp_config( &$wp_config_code, $line ) { + $token = "/* That's all, stop editing!"; + + $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); + } + + public function download_wp( $subdir = '' ) { + $dest_dir = $this->variables['RUN_DIR'] . "/$subdir"; + + if ( $subdir ) { + mkdir( $dest_dir ); + } + + $this->proc( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); + + // disable emailing + mkdir( $dest_dir . '/wp-content/mu-plugins' ); + copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); + } + + public function create_config( $subdir = '' ) { + $params = self::$db_settings; + $params['dbprefix'] = $subdir ?: 'wp_'; + + $params['skip-salts'] = true; + $this->proc( 'wp core config', $params, $subdir )->run_check(); + } + + public function install_wp( $subdir = '' ) { + $this->create_db(); + $this->create_run_dir(); + $this->download_wp( $subdir ); + + $this->create_config( $subdir ); + + $install_args = array( + 'url' => 'http://example.com', + 'title' => 'WP CLI Site', + 'admin_user' => 'admin', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ); + + $this->proc( 'wp core install', $install_args, $subdir )->run_check(); + } +} + diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php new file mode 100644 index 000000000..74939c5d0 --- /dev/null +++ b/features/bootstrap/Process.php @@ -0,0 +1,75 @@ +<?php + +namespace WP_CLI; + +/** + * Run a system process, and learn what happened. + */ +class Process { + + /** + * @param string $command Command to execute. + * @param string $cwd Directory to execute the command in. + * @param array $env Environment variables to set when running the command. + */ + public static function create( $command, $cwd = null, $env = array() ) { + $proc = new self; + + $proc->command = $command; + $proc->cwd = $cwd; + $proc->env = $env; + + return $proc; + } + + private $command, $cwd, $env; + + private function __construct() {} + + /** + * Run the command. + * + * @return ProcessRun + */ + public function run() { + $cwd = $this->cwd; + + $descriptors = array( + 0 => STDIN, + 1 => array( 'pipe', 'w' ), + 2 => array( 'pipe', 'w' ), + ); + + $proc = proc_open( $this->command, $descriptors, $pipes, $cwd, $this->env ); + + $stdout = stream_get_contents( $pipes[1] ); + fclose( $pipes[1] ); + + $stderr = stream_get_contents( $pipes[2] ); + fclose( $pipes[2] ); + + return new ProcessRun( array( + 'stdout' => $stdout, + 'stderr' => $stderr, + 'return_code' => proc_close( $proc ), + 'command' => $this->command, + 'cwd' => $cwd, + 'env' => $this->env + ) ); + } + + /** + * Run the command, but throw an Exception on error. + * + * @return ProcessRun + */ + public function run_check() { + $r = $this->run(); + + if ( $r->return_code || !empty( $r->STDERR ) ) { + throw new \RuntimeException( $r ); + } + + return $r; + } +} diff --git a/features/bootstrap/ProcessRun.php b/features/bootstrap/ProcessRun.php new file mode 100644 index 000000000..4611cfbb6 --- /dev/null +++ b/features/bootstrap/ProcessRun.php @@ -0,0 +1,33 @@ +<?php + +namespace WP_CLI; + +/** + * Results of an executed command. + */ +class ProcessRun { + + /** + * @var array $props Properties of executed command. + */ + public function __construct( $props ) { + foreach ( $props as $key => $value ) { + $this->$key = $value; + } + } + + /** + * Return properties of executed command as a string. + * + * @return string + */ + public function __toString() { + $out = "$ $this->command\n"; + $out .= "$this->stdout\n$this->stderr"; + $out .= "cwd: $this->cwd\n"; + $out .= "exit status: $this->return_code"; + + return $out; + } + +} diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php new file mode 100644 index 000000000..75ee5fbd3 --- /dev/null +++ b/features/bootstrap/support.php @@ -0,0 +1,194 @@ +<?php + +// Utility functions used by Behat steps + +function assertEquals( $expected, $actual ) { + if ( $expected != $actual ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + +function assertNotEquals( $expected, $actual ) { + if ( $expected == $actual ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + +function assertNumeric( $actual ) { + if ( !is_numeric( $actual ) ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + +function assertNotNumeric( $actual ) { + if ( is_numeric( $actual ) ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + +function checkString( $output, $expected, $action, $message = false ) { + switch ( $action ) { + + case 'be': + $r = $expected === rtrim( $output, "\n" ); + break; + + case 'contain': + $r = false !== strpos( $output, $expected ); + break; + + case 'not contain': + $r = false === strpos( $output, $expected ); + break; + + default: + throw new Behat\Behat\Exception\PendingException(); + } + + if ( !$r ) { + if ( false === $message ) + $message = $output; + throw new Exception( $message ); + } +} + +function compareTables( $expected_rows, $actual_rows, $output ) { + // the first row is the header and must be present + if ( $expected_rows[0] != $actual_rows[0] ) { + throw new \Exception( $output ); + } + + unset( $actual_rows[0] ); + unset( $expected_rows[0] ); + + $missing_rows = array_diff( $expected_rows, $actual_rows ); + if ( !empty( $missing_rows ) ) { + throw new \Exception( $output ); + } +} + +function compareContents( $expected, $actual ) { + if ( gettype( $expected ) != gettype( $actual ) ) { + return false; + } + + if ( is_object( $expected ) ) { + foreach ( get_object_vars( $expected ) as $name => $value ) { + if ( ! compareContents( $value, $actual->$name ) ) + return false; + } + } else if ( is_array( $expected ) ) { + foreach ( $expected as $key => $value ) { + if ( ! compareContents( $value, $actual[$key] ) ) + return false; + } + } else { + return $expected === $actual; + } + + return true; +} + +/** + * Compare two strings containing JSON to ensure that @a $actualJson contains at + * least what the JSON string @a $expectedJson contains. + * + * @return whether or not @a $actualJson contains @a $expectedJson + * @retval true @a $actualJson contains @a $expectedJson + * @retval false @a $actualJson does not contain @a $expectedJson + * + * @param[in] $actualJson the JSON string to be tested + * @param[in] $expectedJson the expected JSON string + * + * Examples: + * expected: {'a':1,'array':[1,3,5]} + * + * 1 ) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: true + * + * 2 ) + * actual: {'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * element 'a' is missing from the root object + * + * 3 ) + * actual: {'a':0,'b':2,'c':3,'array':[1,2,3,4,5]} + * return: false + * the value of element 'a' is not 1 + * + * 4 ) + * actual: {'a':1,'b':2,'c':3,'array':[1,2,4,5]} + * return: false + * the contents of 'array' does not include 3 + */ +function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { + $actualValue = json_decode( $actualJson ); + $expectedValue = json_decode( $expectedJson ); + + if ( !$actualValue ) { + return false; + } + + return compareContents( $expectedValue, $actualValue ); +} + +/** + * Compare two strings to confirm $actualCSV contains $expectedCSV + * Both strings are expected to have headers for their CSVs. + * $actualCSV must match all data rows in $expectedCSV + * + * @param string A CSV string + * @param array A nested array of values + * @return bool Whether $actualCSV contains $expectedCSV + */ +function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { + $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); + + if ( empty( $actualCSV ) ) + return false; + + // Each sample must have headers + $actualHeaders = array_values( array_shift( $actualCSV ) ); + $expectedHeaders = array_values( array_shift( $expectedCSV ) ); + + // Each expectedCSV must exist somewhere in actualCSV in the proper column + $expectedResult = 0; + foreach ( $expectedCSV as $expected_row ) { + $expected_row = array_combine( $expectedHeaders, $expected_row ); + foreach ( $actualCSV as $actual_row ) { + + if ( count( $actualHeaders ) != count( $actual_row ) ) + continue; + + $actual_row = array_intersect_key( array_combine( $actualHeaders, $actual_row ), $expected_row ); + if ( $actual_row == $expected_row ) + $expectedResult++; + } + } + + return $expectedResult >= count( $expectedCSV ); +} + +/** + * Compare two strings containing YAML to ensure that @a $actualYaml contains at + * least what the YAML string @a $expectedYaml contains. + * + * @return whether or not @a $actualYaml contains @a $expectedJson + * @retval true @a $actualYaml contains @a $expectedJson + * @retval false @a $actualYaml does not contain @a $expectedJson + * + * @param[in] $actualYaml the YAML string to be tested + * @param[in] $expectedYaml the expected YAML string + */ +function checkThatYamlStringContainsYamlString( $actualYaml, $expectedYaml ) { + $actualValue = spyc_load( $actualYaml ); + $expectedValue = spyc_load( $expectedYaml ); + + if ( !$actualValue ) { + return false; + } + + return compareContents( $expectedValue, $actualValue ); +} + diff --git a/features/bootstrap/utils.php b/features/bootstrap/utils.php new file mode 100644 index 000000000..d476dc1e8 --- /dev/null +++ b/features/bootstrap/utils.php @@ -0,0 +1,838 @@ +<?php + +// Utilities that do NOT depend on WordPress code. + +namespace WP_CLI\Utils; + +use \Composer\Semver\Comparator; +use \Composer\Semver\Semver; +use \WP_CLI; +use \WP_CLI\Dispatcher; +use \WP_CLI\Iterators\Transform; + +function inside_phar() { + return 0 === strpos( WP_CLI_ROOT, 'phar://' ); +} + +// Files that need to be read by external programs have to be extracted from the Phar archive. +function extract_from_phar( $path ) { + if ( ! inside_phar() ) { + return $path; + } + + $fname = basename( $path ); + + $tmp_path = get_temp_dir() . "wp-cli-$fname"; + + copy( $path, $tmp_path ); + + register_shutdown_function( function() use ( $tmp_path ) { + @unlink( $tmp_path ); + } ); + + return $tmp_path; +} + +function load_dependencies() { + if ( inside_phar() ) { + require WP_CLI_ROOT . '/vendor/autoload.php'; + return; + } + + $has_autoload = false; + + foreach ( get_vendor_paths() as $vendor_path ) { + if ( file_exists( $vendor_path . '/autoload.php' ) ) { + require $vendor_path . '/autoload.php'; + $has_autoload = true; + break; + } + } + + if ( !$has_autoload ) { + fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); + exit(3); + } +} + +function get_vendor_paths() { + $vendor_paths = array( + WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) + WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone + ); + $maybe_composer_json = WP_CLI_ROOT . '/../../../composer.json'; + if ( file_exists( $maybe_composer_json ) && is_readable( $maybe_composer_json ) ) { + $composer = json_decode( file_get_contents( $maybe_composer_json ) ); + if ( ! empty( $composer->config ) && ! empty( $composer->config->{'vendor-dir'} ) ) { + array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->config->{'vendor-dir'} ); + } + } + return $vendor_paths; +} + +// Using require() directly inside a class grants access to private methods to the loaded code +function load_file( $path ) { + require_once $path; +} + +function load_command( $name ) { + $path = WP_CLI_ROOT . "/php/commands/$name.php"; + + if ( is_readable( $path ) ) { + include_once $path; + } +} + +function load_all_commands() { + $cmd_dir = WP_CLI_ROOT . '/php/commands'; + + $iterator = new \DirectoryIterator( $cmd_dir ); + + foreach ( $iterator as $filename ) { + if ( '.php' != substr( $filename, -4 ) ) + continue; + + include_once "$cmd_dir/$filename"; + } +} + +/** + * Like array_map(), except it returns a new iterator, instead of a modified array. + * + * Example: + * + * $arr = array('Football', 'Socker'); + * + * $it = iterator_map($arr, 'strtolower', function($val) { + * return str_replace('foo', 'bar', $val); + * }); + * + * foreach ( $it as $val ) { + * var_dump($val); + * } + * + * @param array|object Either a plain array or another iterator + * @param callback The function to apply to an element + * @return object An iterator that applies the given callback(s) + */ +function iterator_map( $it, $fn ) { + if ( is_array( $it ) ) { + $it = new \ArrayIterator( $it ); + } + + if ( !method_exists( $it, 'add_transform' ) ) { + $it = new Transform( $it ); + } + + foreach ( array_slice( func_get_args(), 1 ) as $fn ) { + $it->add_transform( $fn ); + } + + return $it; +} + +/** + * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true + * @param string|array The files (or file) to search for + * @param string|null The directory to start searching from; defaults to CWD + * @param callable Function which is passed the current dir each time a directory level is traversed + * @return null|string Null if the file was not found + */ +function find_file_upward( $files, $dir = null, $stop_check = null ) { + $files = (array) $files; + if ( is_null( $dir ) ) { + $dir = getcwd(); + } + while ( @is_readable( $dir ) ) { + // Stop walking up when the supplied callable returns true being passed the $dir + if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { + return null; + } + + foreach ( $files as $file ) { + $path = $dir . DIRECTORY_SEPARATOR . $file; + if ( file_exists( $path ) ) { + return $path; + } + } + + $parent_dir = dirname( $dir ); + if ( empty($parent_dir) || $parent_dir === $dir ) { + break; + } + $dir = $parent_dir; + } + return null; +} + +function is_path_absolute( $path ) { + // Windows + if ( isset($path[1]) && ':' === $path[1] ) + return true; + + return $path[0] === '/'; +} + +/** + * Composes positional arguments into a command string. + * + * @param array + * @return string + */ +function args_to_str( $args ) { + return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); +} + +/** + * Composes associative arguments into a command string. + * + * @param array + * @return string + */ +function assoc_args_to_str( $assoc_args ) { + $str = ''; + + foreach ( $assoc_args as $key => $value ) { + if ( true === $value ) + $str .= " --$key"; + else + $str .= " --$key=" . escapeshellarg( $value ); + } + + return $str; +} + +/** + * Given a template string and an arbitrary number of arguments, + * returns the final command, with the parameters escaped. + */ +function esc_cmd( $cmd ) { + if ( func_num_args() < 2 ) + trigger_error( 'esc_cmd() requires at least two arguments.', E_USER_WARNING ); + + $args = func_get_args(); + + $cmd = array_shift( $args ); + + return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); +} + +function locate_wp_config() { + static $path; + + if ( null === $path ) { + if ( file_exists( ABSPATH . 'wp-config.php' ) ) + $path = ABSPATH . 'wp-config.php'; + elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) + $path = ABSPATH . '../wp-config.php'; + else + $path = false; + + if ( $path ) + $path = realpath( $path ); + } + + return $path; +} + +function wp_version_compare( $since, $operator ) { + return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); +} + +/** + * Render a collection of items as an ASCII table, JSON, CSV, YAML, list of ids, or count. + * + * Given a collection of items with a consistent data structure: + * + * ``` + * $items = array( + * array( + * 'key' => 'foo', + * 'value' => 'bar', + * ) + * ); + * ``` + * + * Render `$items` as an ASCII table: + * + * ``` + * WP_CLI\Utils\format_items( 'table', $items, array( 'key', 'value' ) ); + * + * # +-----+-------+ + * # | key | value | + * # +-----+-------+ + * # | foo | bar | + * # +-----+-------+ + * ``` + * + * Or render `$items` as YAML: + * + * ``` + * WP_CLI\Utils\format_items( 'yaml', $items, array( 'key', 'value' ) ); + * + * # --- + * # - + * # key: foo + * # value: bar + * ``` + * + * @access public + * @category Output + * + * @param string $format Format to use: 'table', 'json', 'csv', 'yaml', 'ids', 'count' + * @param array $items An array of items to output. + * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list. + * @return null + */ +function format_items( $format, $items, $fields ) { + $assoc_args = compact( 'format', 'fields' ); + $formatter = new \WP_CLI\Formatter( $assoc_args ); + $formatter->display_items( $items ); +} + +/** + * Write data as CSV to a given file. + * + * @access public + * + * @param resource $fd File descriptor + * @param array $rows Array of rows to output + * @param array $headers List of CSV columns (optional) + */ +function write_csv( $fd, $rows, $headers = array() ) { + if ( ! empty( $headers ) ) { + fputcsv( $fd, $headers ); + } + + foreach ( $rows as $row ) { + if ( ! empty( $headers ) ) { + $row = pick_fields( $row, $headers ); + } + + fputcsv( $fd, array_values( $row ) ); + } +} + +/** + * Pick fields from an associative array or object. + * + * @param array|object Associative array or object to pick fields from + * @param array List of fields to pick + * @return array + */ +function pick_fields( $item, $fields ) { + $item = (object) $item; + + $values = array(); + + foreach ( $fields as $field ) { + $values[ $field ] = isset( $item->$field ) ? $item->$field : null; + } + + return $values; +} + +/** + * Launch system's $EDITOR for the user to edit some text. + * + * @access public + * @category Input + * + * @param string $content Some form of text to edit (e.g. post content) + * @return string|bool Edited text, if file is saved from editor; false, if no change to file. + */ +function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { + + $tmpdir = get_temp_dir(); + + do { + $tmpfile = basename( $filename ); + $tmpfile = preg_replace( '|\.[^.]*$|', '', $tmpfile ); + $tmpfile .= '-' . substr( md5( rand() ), 0, 6 ); + $tmpfile = $tmpdir . $tmpfile . '.tmp'; + $fp = @fopen( $tmpfile, 'x' ); + if ( ! $fp && is_writable( $tmpdir ) && file_exists( $tmpfile ) ) { + $tmpfile = ''; + continue; + } + if ( $fp ) { + fclose( $fp ); + } + } while( ! $tmpfile ); + + if ( ! $tmpfile ) { + \WP_CLI::error( 'Error creating temporary file.' ); + } + + $output = ''; + file_put_contents( $tmpfile, $input ); + + $editor = getenv( 'EDITOR' ); + if ( !$editor ) { + if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) ) + $editor = 'notepad'; + else + $editor = 'vi'; + } + + $descriptorspec = array( STDIN, STDOUT, STDERR ); + $process = proc_open( "$editor " . escapeshellarg( $tmpfile ), $descriptorspec, $pipes ); + $r = proc_close( $process ); + if ( $r ) { + exit( $r ); + } + + $output = file_get_contents( $tmpfile ); + + unlink( $tmpfile ); + + if ( $output === $input ) + return false; + + return $output; +} + +/** + * @param string MySQL host string, as defined in wp-config.php + * @return array + */ +function mysql_host_to_cli_args( $raw_host ) { + $assoc_args = array(); + + $host_parts = explode( ':', $raw_host ); + if ( count( $host_parts ) == 2 ) { + list( $assoc_args['host'], $extra ) = $host_parts; + $extra = trim( $extra ); + if ( is_numeric( $extra ) ) { + $assoc_args['port'] = intval( $extra ); + $assoc_args['protocol'] = 'tcp'; + } else if ( $extra !== '' ) { + $assoc_args['socket'] = $extra; + } + } else { + $assoc_args['host'] = $raw_host; + } + + return $assoc_args; +} + +function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { + if ( !$descriptors ) + $descriptors = array( STDIN, STDOUT, STDERR ); + + if ( isset( $assoc_args['host'] ) ) { + $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); + } + + $pass = $assoc_args['pass']; + unset( $assoc_args['pass'] ); + + $old_pass = getenv( 'MYSQL_PWD' ); + putenv( 'MYSQL_PWD=' . $pass ); + + $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); + + $proc = proc_open( $final_cmd, $descriptors, $pipes ); + if ( !$proc ) + exit(1); + + $r = proc_close( $proc ); + + putenv( 'MYSQL_PWD=' . $old_pass ); + + if ( $r ) exit( $r ); +} + +/** + * Render PHP or other types of files using Mustache templates. + * + * IMPORTANT: Automatic HTML escaping is disabled! + */ +function mustache_render( $template_name, $data = array() ) { + if ( ! file_exists( $template_name ) ) + $template_name = WP_CLI_ROOT . "/templates/$template_name"; + + $template = file_get_contents( $template_name ); + + $m = new \Mustache_Engine( array( + 'escape' => function ( $val ) { return $val; } + ) ); + + return $m->render( $template, $data ); +} + +/** + * Create a progress bar to display percent completion of a given operation. + * + * Progress bar is written to STDOUT, and disabled when command is piped. Progress + * advances with `$progress->tick()`, and completes with `$progress->finish()`. + * Process bar also indicates elapsed time and expected total time. + * + * ``` + * # `wp user generate` ticks progress bar each time a new user is created. + * # + * # $ wp user generate --count=500 + * # Generating users 22 % [=======> ] 0:05 / 0:23 + * + * $progress = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); + * for ( $i = 0; $i < $count; $i++ ) { + * // uses wp_insert_user() to insert the user + * $progress->tick(); + * } + * $progress->finish(); + * ``` + * + * @access public + * @category Output + * + * @param string $message Text to display before the progress bar. + * @param integer $count Total number of ticks to be performed. + * @return cli\progress\Bar|WP_CLI\NoOp + */ +function make_progress_bar( $message, $count ) { + if ( \cli\Shell::isPiped() ) + return new \WP_CLI\NoOp; + + return new \cli\progress\Bar( $message, $count ); +} + +function parse_url( $url ) { + $url_parts = \parse_url( $url ); + + if ( !isset( $url_parts['scheme'] ) ) { + $url_parts = parse_url( 'http://' . $url ); + } + + return $url_parts; +} + +/** + * Check if we're running in a Windows environment (cmd.exe). + */ +function is_windows() { + return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; +} + +/** + * Replace magic constants in some PHP source code. + * + * @param string $source The PHP code to manipulate. + * @param string $path The path to use instead of the magic constants + */ +function replace_path_consts( $source, $path ) { + $replacements = array( + '__FILE__' => "'$path'", + '__DIR__' => "'" . dirname( $path ) . "'" + ); + + $old = array_keys( $replacements ); + $new = array_values( $replacements ); + + return str_replace( $old, $new, $source ); +} + +/** + * Make a HTTP request to a remote URL. + * + * Wraps the Requests HTTP library to ensure every request includes a cert. + * + * ``` + * # `wp core download` verifies the hash for a downloaded WordPress archive + * + * $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); + * if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { + * WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); + * } + * ``` + * + * @access public + * + * @param string $method HTTP method (GET, POST, DELETE, etc.) + * @param string $url URL to make the HTTP request to. + * @param array $headers Add specific headers to the request. + * @param array $options + * @return object + */ +function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { + + $cert_path = '/rmccue/requests/library/Requests/Transport/cacert.pem'; + if ( inside_phar() ) { + // cURL can't read Phar archives + $options['verify'] = extract_from_phar( + WP_CLI_ROOT . '/vendor' . $cert_path ); + } else { + foreach( get_vendor_paths() as $vendor_path ) { + if ( file_exists( $vendor_path . $cert_path ) ) { + $options['verify'] = $vendor_path . $cert_path; + break; + } + } + if ( empty( $options['verify'] ) ){ + WP_CLI::error_log( "Cannot find SSL certificate." ); + } + } + + try { + $request = \Requests::request( $url, $headers, $data, $method, $options ); + return $request; + } catch( \Requests_Exception $ex ) { + // Handle SSL certificate issues gracefully + \WP_CLI::warning( $ex->getMessage() ); + $options['verify'] = false; + try { + return \Requests::request( $url, $headers, $data, $method, $options ); + } catch( \Requests_Exception $ex ) { + \WP_CLI::error( $ex->getMessage() ); + } + } +} + +/** + * Increments a version string using the "x.y.z-pre" format + * + * Can increment the major, minor or patch number by one + * If $new_version == "same" the version string is not changed + * If $new_version is not a known keyword, it will be used as the new version string directly + * + * @param string $current_version + * @param string $new_version + * @return string + */ +function increment_version( $current_version, $new_version ) { + // split version assuming the format is x.y.z-pre + $current_version = explode( '-', $current_version, 2 ); + $current_version[0] = explode( '.', $current_version[0] ); + + switch ( $new_version ) { + case 'same': + // do nothing + break; + + case 'patch': + $current_version[0][2]++; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + case 'minor': + $current_version[0][1]++; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + case 'major': + $current_version[0][0]++; + $current_version[0][1] = 0; + $current_version[0][2] = 0; + + $current_version = array( $current_version[0] ); // drop possible pre-release info + break; + + default: // not a keyword + $current_version = array( array( $new_version ) ); + break; + } + + // reconstruct version string + $current_version[0] = implode( '.', $current_version[0] ); + $current_version = implode( '-', $current_version ); + + return $current_version; +} + +/** + * Compare two version strings to get the named semantic version. + * + * @access public + * + * @param string $new_version + * @param string $original_version + * @return string $name 'major', 'minor', 'patch' + */ +function get_named_sem_ver( $new_version, $original_version ) { + + if ( ! Comparator::greaterThan( $new_version, $original_version ) ) { + return ''; + } + + $parts = explode( '-', $original_version ); + $bits = explode( '.', $parts[0] ); + $major = $bits[0]; + if ( isset( $bits[1] ) ) { + $minor = $bits[1]; + } + if ( isset( $bits[2] ) ) { + $patch = $bits[2]; + } + + if ( ! is_null( $minor ) && Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { + return 'patch'; + } else if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { + return 'minor'; + } else { + return 'major'; + } +} + +/** + * Return the flag value or, if it's not set, the $default value. + * + * Because flags can be negated (e.g. --no-quiet to negate --quiet), this + * function provides a safer alternative to using + * `isset( $assoc_args['quiet'] )` or similar. + * + * @access public + * @category Input + * + * @param array $assoc_args Arguments array. + * @param string $flag Flag to get the value. + * @param mixed $default Default value for the flag. Default: NULL + * @return mixed + */ +function get_flag_value( $assoc_args, $flag, $default = null ) { + return isset( $assoc_args[ $flag ] ) ? $assoc_args[ $flag ] : $default; +} + +/** + * Get the system's temp directory. Warns user if it isn't writable. + * + * @access public + * @category System + * + * @return string + */ +function get_temp_dir() { + static $temp = ''; + + $trailingslashit = function( $path ) { + return rtrim( $path ) . '/'; + }; + + if ( $temp ) + return $trailingslashit( $temp ); + + if ( function_exists( 'sys_get_temp_dir' ) ) { + $temp = sys_get_temp_dir(); + } else if ( ini_get( 'upload_tmp_dir' ) ) { + $temp = ini_get( 'upload_tmp_dir' ); + } else { + $temp = '/tmp/'; + } + + if ( ! @is_writable( $temp ) ) { + \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); + } + + return $trailingslashit( $temp ); +} + +/** + * Parse a SSH url for its host, port, and path. + * + * Similar to parse_url(), but adds support for defined SSH aliases. + * + * ``` + * host OR host/path/to/wordpress OR host:port/path/to/wordpress + * ``` + * + * @access public + * + * @return mixed + */ +function parse_ssh_url( $url, $component = -1 ) { + preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $url, $matches ); + $bits = array(); + foreach( array( + 1 => 'host', + 3 => 'port', + 4 => 'path', + ) as $i => $key ) { + if ( ! empty( $matches[ $i ] ) ) { + $bits[ $key ] = $matches[ $i ]; + } + } + switch ( $component ) { + case PHP_URL_HOST: + return isset( $bits['host'] ) ? $bits['host'] : null; + case PHP_URL_PATH: + return isset( $bits['path'] ) ? $bits['path'] : null; + case PHP_URL_PORT: + return isset( $bits['port'] ) ? $bits['port'] : null; + default: + return $bits; + } +} + +/** + * Report the results of the same operation against multiple resources. + * + * @access public + * @category Input + * + * @param string $noun Resource being affected (e.g. plugin) + * @param string $verb Type of action happening to the noun (e.g. activate) + * @param integer $total Total number of resource being affected. + * @param integer $successes Number of successful operations. + * @param integer $failures Number of failures. + */ +function report_batch_operation_results( $noun, $verb, $total, $successes, $failures ) { + $plural_noun = $noun . 's'; + if ( in_array( $verb, array( 'reset' ), true ) ) { + $past_tense_verb = $verb; + } else { + $past_tense_verb = 'e' === substr( $verb, -1 ) ? $verb . 'd' : $verb . 'ed'; + } + $past_tense_verb_upper = ucfirst( $past_tense_verb ); + if ( $failures ) { + if ( $successes ) { + WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}." ); + } else { + WP_CLI::error( "No {$plural_noun} {$past_tense_verb}." ); + } + } else { + if ( $successes ) { + WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); + } else { + $message = $total > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); + WP_CLI::success( "{$message} already {$past_tense_verb}." ); + } + } +} + +/** + * Parse a string of command line arguments into an $argv-esqe variable. + * + * @access public + * @category Input + * + * @param string $arguments + * @return array + */ +function parse_str_to_argv( $arguments ) { + preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $arguments, $matches ); + $argv = isset( $matches[0] ) ? $matches[0] : array(); + $argv = array_map( function( $arg ){ + foreach( array( '"', "'" ) as $char ) { + if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { + $arg = substr( $arg, 1, -1 ); + break; + } + } + return $arg; + }, $argv ); + return $argv; +} + +/** + * Locale-independent version of basename() + * + * @access public + * + * @param string $path + * @param string $suffix + * @return string + */ +function basename( $path, $suffix = '' ) { + return urldecode( \basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) ); +} diff --git a/features/extra/no-mail.php b/features/extra/no-mail.php new file mode 100644 index 000000000..de7a42272 --- /dev/null +++ b/features/extra/no-mail.php @@ -0,0 +1,7 @@ +<?php + +function wp_mail( $to ) { + // Log for testing purposes + WP_CLI::log( "WP-CLI test suite: Sent email to {$to}." ); +} + diff --git a/features/steps/given.php b/features/steps/given.php new file mode 100644 index 000000000..a1b6a1bb9 --- /dev/null +++ b/features/steps/given.php @@ -0,0 +1,164 @@ +<?php + +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode, + WP_CLI\Process; + +$steps->Given( '/^an empty directory$/', + function ( $world ) { + $world->create_run_dir(); + } +); + +$steps->Given( '/^an empty cache/', + function ( $world ) { + $world->variables['SUITE_CACHE_DIR'] = FeatureContext::create_cache_dir(); + } +); + +$steps->Given( '/^an? ([^\s]+) file:$/', + function ( $world, $path, PyStringNode $content ) { + $content = (string) $content . "\n"; + $full_path = $world->variables['RUN_DIR'] . "/$path"; + Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); + file_put_contents( $full_path, $content ); + } +); + +$steps->Given( '/^"([^"]+)" replaced with "([^"]+)" in the ([^\s]+) file$/', function( $world, $search, $replace, $path ) { + $full_path = $world->variables['RUN_DIR'] . "/$path"; + $contents = file_get_contents( $full_path ); + $contents = str_replace( $search, $replace, $contents ); + file_put_contents( $full_path, $contents ); +}); + +$steps->Given( '/^WP files$/', + function ( $world ) { + $world->download_wp(); + } +); + +$steps->Given( '/^wp-config\.php$/', + function ( $world ) { + $world->create_config(); + } +); + +$steps->Given( '/^a database$/', + function ( $world ) { + $world->create_db(); + } +); + +$steps->Given( '/^a WP install$/', + function ( $world ) { + $world->install_wp(); + } +); + +$steps->Given( "/^a WP install in '([^\s]+)'$/", + function ( $world, $subdir ) { + $world->install_wp( $subdir ); + } +); + +$steps->Given( '/^a WP multisite (subdirectory|subdomain)?\s?install$/', + function ( $world, $type = 'subdirectory' ) { + $world->install_wp(); + $subdomains = ! empty( $type ) && 'subdomain' === $type ? 1 : 0; + $world->proc( 'wp core install-network', array( 'title' => 'WP CLI Network', 'subdomains' => $subdomains ) )->run_check(); + } +); + +$steps->Given( '/^these installed and active plugins:$/', + function( $world, $stream ) { + $plugins = implode( ' ', array_map( 'trim', explode( PHP_EOL, (string)$stream ) ) ); + $world->proc( "wp plugin install $plugins --activate" )->run_check(); + } +); + +$steps->Given( '/^a custom wp-content directory$/', + function ( $world ) { + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $world->move_files( 'wp-content', 'my-content' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', dirname(__FILE__) . '/my-content' );" ); + + $world->move_files( 'my-content/plugins', 'my-plugins' ); + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_PLUGIN_DIR', __DIR__ . '/my-plugins' );" ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } +); + +$steps->Given( '/^download:$/', + function ( $world, TableNode $table ) { + foreach ( $table->getHash() as $row ) { + $path = $world->replace_variables( $row['path'] ); + if ( file_exists( $path ) ) { + // assume it's the same file and skip re-download + continue; + } + + Process::create( \WP_CLI\Utils\esc_cmd( 'curl -sSL %s > %s', $row['url'], $path ) )->run_check(); + } + } +); + +$steps->Given( '/^save (STDOUT|STDERR) ([\'].+[^\'])?\s?as \{(\w+)\}$/', + function ( $world, $stream, $output_filter, $key ) { + + $stream = strtolower( $stream ); + + if ( $output_filter ) { + $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; + if ( false !== preg_match( $output_filter, $world->result->$stream, $matches ) ) + $output = array_pop( $matches ); + else + $output = ''; + } else { + $output = $world->result->$stream; + } + $world->variables[ $key ] = trim( $output, "\n" ); + } +); + +$steps->Given( '/^a new Phar(?: with version "([^"]+)")$/', + function ( $world, $version ) { + $world->build_phar( $version ); + } +); + +$steps->Given( '/^save the (.+) file ([\'].+[^\'])?as \{(\w+)\}$/', + function ( $world, $filepath, $output_filter, $key ) { + $full_file = file_get_contents( $world->replace_variables( $filepath ) ); + + if ( $output_filter ) { + $output_filter = '/' . trim( str_replace( '%s', '(.+[^\b])', $output_filter ), "' " ) . '/'; + if ( false !== preg_match( $output_filter, $full_file, $matches ) ) + $output = array_pop( $matches ); + else + $output = ''; + } else { + $output = $full_file; + } + $world->variables[ $key ] = trim( $output, "\n" ); + } +); + +$steps->Given('/^a misconfigured WP_CONTENT_DIR constant directory$/', + function($world) { + $wp_config_path = $world->variables['RUN_DIR'] . "/wp-config.php"; + + $wp_config_code = file_get_contents( $wp_config_path ); + + $world->add_line_to_wp_config( $wp_config_code, + "define( 'WP_CONTENT_DIR', '' );" ); + + file_put_contents( $wp_config_path, $wp_config_code ); + } +); diff --git a/features/steps/then.php b/features/steps/then.php new file mode 100644 index 000000000..a5974f16c --- /dev/null +++ b/features/steps/then.php @@ -0,0 +1,210 @@ +<?php + +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode; + +$steps->Then( '/^the return code should be (\d+)$/', + function ( $world, $return_code ) { + if ( $return_code != $world->result->return_code ) { + throw new RuntimeException( $world->result ); + } + } +); + +$steps->Then( '/^(STDOUT|STDERR) should (be|contain|not contain):$/', + function ( $world, $stream, $action, PyStringNode $expected ) { + + $stream = strtolower( $stream ); + + $expected = $world->replace_variables( (string) $expected ); + + checkString( $world->result->$stream, $expected, $action, $world->result ); + } +); + +$steps->Then( '/^(STDOUT|STDERR) should be a number$/', + function ( $world, $stream ) { + + $stream = strtolower( $stream ); + + assertNumeric( trim( $world->result->$stream, "\n" ) ); + } +); + +$steps->Then( '/^(STDOUT|STDERR) should not be a number$/', + function ( $world, $stream ) { + + $stream = strtolower( $stream ); + + assertNotNumeric( trim( $world->result->$stream, "\n" ) ); + } +); + +$steps->Then( '/^STDOUT should be a table containing rows:$/', + function ( $world, TableNode $expected ) { + $output = $world->result->stdout; + $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); + + $expected_rows = array(); + foreach ( $expected->getRows() as $row ) { + $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); + } + + compareTables( $expected_rows, $actual_rows, $output ); + } +); + +$steps->Then( '/^STDOUT should end with a table containing rows:$/', + function ( $world, TableNode $expected ) { + $output = $world->result->stdout; + $actual_rows = explode( "\n", rtrim( $output, "\n" ) ); + + $expected_rows = array(); + foreach ( $expected->getRows() as $row ) { + $expected_rows[] = $world->replace_variables( implode( "\t", $row ) ); + } + + $start = array_search( $expected_rows[0], $actual_rows ); + + if ( false === $start ) + throw new \Exception( $world->result ); + + compareTables( $expected_rows, array_slice( $actual_rows, $start ), $output ); + } +); + +$steps->Then( '/^STDOUT should be JSON containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->stdout; + $expected = $world->replace_variables( (string) $expected ); + + if ( !checkThatJsonStringContainsJsonString( $output, $expected ) ) { + throw new \Exception( $world->result ); + } +}); + +$steps->Then( '/^STDOUT should be a JSON array containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->stdout; + $expected = $world->replace_variables( (string) $expected ); + + $actualValues = json_decode( $output ); + $expectedValues = json_decode( $expected ); + + $missing = array_diff( $expectedValues, $actualValues ); + if ( !empty( $missing ) ) { + throw new \Exception( $world->result ); + } +}); + +$steps->Then( '/^STDOUT should be CSV containing:$/', + function ( $world, TableNode $expected ) { + $output = $world->result->stdout; + + $expected_rows = $expected->getRows(); + foreach ( $expected as &$row ) { + foreach ( $row as &$value ) { + $value = $world->replace_variables( $value ); + } + } + + if ( ! checkThatCsvStringContainsValues( $output, $expected_rows ) ) + throw new \Exception( $world->result ); + } +); + +$steps->Then( '/^STDOUT should be YAML containing:$/', + function ( $world, PyStringNode $expected ) { + $output = $world->result->stdout; + $expected = $world->replace_variables( (string) $expected ); + + if ( !checkThatYamlStringContainsYamlString( $output, $expected ) ) { + throw new \Exception( $world->result ); + } +}); + +$steps->Then( '/^(STDOUT|STDERR) should be empty$/', + function ( $world, $stream ) { + + $stream = strtolower( $stream ); + + if ( !empty( $world->result->$stream ) ) { + throw new \Exception( $world->result ); + } + } +); + +$steps->Then( '/^(STDOUT|STDERR) should not be empty$/', + function ( $world, $stream ) { + + $stream = strtolower( $stream ); + + if ( '' === rtrim( $world->result->$stream, "\n" ) ) { + throw new Exception( $world->result ); + } + } +); + +$steps->Then( '/^(STDOUT|STDERR) should be a version string (<|<=|>|>=|==|=|!=|<>) ([+\w\.-]+)$/', + function ( $world, $stream, $operator, $goal_ver ) { + $stream = strtolower( $stream ); + if ( false === version_compare( trim( $world->result->$stream, "\n" ), $goal_ver, $operator ) ) { + throw new Exception( $world->result ); + } + } +); + +$steps->Then( '/^the (.+) (file|directory) should (exist|not exist|be:|contain:|not contain:)$/', + function ( $world, $path, $type, $action, $expected = null ) { + $path = $world->replace_variables( $path ); + + // If it's a relative path, make it relative to the current test dir + if ( '/' !== $path[0] ) + $path = $world->variables['RUN_DIR'] . "/$path"; + + if ( 'file' == $type ) { + $test = 'file_exists'; + } else if ( 'directory' == $type ) { + $test = 'is_dir'; + } + + switch ( $action ) { + case 'exist': + if ( ! $test( $path ) ) { + throw new Exception( $world->result ); + } + break; + case 'not exist': + if ( $test( $path ) ) { + throw new Exception( $world->result ); + } + break; + default: + if ( ! $test( $path ) ) { + throw new Exception( "$path doesn't exist." ); + } + $action = substr( $action, 0, -1 ); + $expected = $world->replace_variables( (string) $expected ); + if ( 'file' == $type ) { + $contents = file_get_contents( $path ); + } else if ( 'directory' == $type ) { + $files = glob( rtrim( $path, '/' ) . '/*' ); + foreach( $files as &$file ) { + $file = str_replace( $path . '/', '', $file ); + } + $contents = implode( PHP_EOL, $files ); + } + checkString( $contents, $expected, $action ); + } + } +); + +$steps->Then( '/^an email should (be sent|not be sent)$/', function( $world, $expected ) { + if ( 'be sent' === $expected ) { + assertNotEquals( 0, $world->email_sends ); + } else if ( 'not be sent' === $expected ) { + assertEquals( 0, $world->email_sends ); + } else { + throw new Exception( 'Invalid expectation' ); + } +}); diff --git a/features/steps/when.php b/features/steps/when.php new file mode 100644 index 000000000..afe3f7a0d --- /dev/null +++ b/features/steps/when.php @@ -0,0 +1,54 @@ +<?php + +use Behat\Gherkin\Node\PyStringNode, + Behat\Gherkin\Node\TableNode, + WP_CLI\Process; + +function invoke_proc( $proc, $mode ) { + $map = array( + 'run' => 'run_check', + 'try' => 'run' + ); + $method = $map[ $mode ]; + + return $proc->$method(); +} + +function capture_email_sends( $stdout ) { + $stdout = preg_replace( '#WP-CLI test suite: Sent email to.+\n?#', '', $stdout, -1, $email_sends ); + return array( $stdout, $email_sends ); +} + +$steps->When( '/^I launch in the background `([^`]+)`$/', + function ( $world, $cmd ) { + $world->background_proc( $cmd ); + } +); + +$steps->When( '/^I (run|try) `([^`]+)`$/', + function ( $world, $mode, $cmd ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd ), $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); + } +); + +$steps->When( "/^I (run|try) `([^`]+)` from '([^\s]+)'$/", + function ( $world, $mode, $cmd, $subdir ) { + $cmd = $world->replace_variables( $cmd ); + $world->result = invoke_proc( $world->proc( $cmd, array(), $subdir ), $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); + } +); + +$steps->When( '/^I (run|try) the previous command again$/', + function ( $world, $mode ) { + if ( !isset( $world->result ) ) + throw new \Exception( 'No previous command.' ); + + $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); + $world->result = invoke_proc( $proc, $mode ); + list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); + } +); + diff --git a/php/export/functions.export.php b/functions.php similarity index 100% rename from php/export/functions.export.php rename to functions.php diff --git a/php/export/writers.php b/php/export/writers.php deleted file mode 100644 index 989dd18e8..000000000 --- a/php/export/writers.php +++ /dev/null @@ -1,184 +0,0 @@ -<?php -abstract class WP_Export_Base_Writer { - protected $formatter; - - function __construct( $formatter ) { - $this->formatter = $formatter; - } - - public function export() { - $this->write( $this->formatter->before_posts() ); - foreach( $this->formatter->posts() as $post_in_wxr ) { - $this->write( $post_in_wxr ); - } - $this->write( $this->formatter->after_posts() ); - } - - abstract protected function write( $xml ); -} - -class WP_Export_XML_Over_HTTP extends WP_Export_Base_Writer { - private $file_name; - - function __construct( $formatter, $file_name ) { - parent::__construct( $formatter ); - $this->file_name = $file_name; - } - - public function export() { - try { - $export = $this->get_export(); - $this->send_headers(); - echo $export; - } catch ( WP_Export_Exception $e ) { - $message = apply_filters( 'export_error_message', $e->getMessage() ); - wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); - } catch ( WP_Export_Term_Exception $e ) { - do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); - $message = apply_filters( 'export_term_error_message', $e->getMessage() ); - wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); - } - } - - protected function write( $xml ) { - $this->result .= $xml; - } - - protected function get_export() { - $this->result = ''; - parent::export(); - return $this->result; - } - - protected function send_headers() { - header( 'Content-Description: File Transfer' ); - header( 'Content-Disposition: attachment; filename=' . $this->file_name ); - header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); - } -} - -class WP_Export_Returner extends WP_Export_Base_Writer { - private $result = ''; - - public function export() { - $this->private = ''; - try { - parent::export(); - } catch ( WP_Export_Exception $e ) { - $message = apply_filters( 'export_error_message', $e->getMessage() ); - return new WP_Error( 'wp-export-error', $message ); - - } catch ( WP_Export_Term_Exception $e ) { - do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); - $message = apply_filters( 'export_term_error_message', $e->getMessage() ); - return new WP_Error( 'wp-export-error', $message ); - } - return $this->result; - } - protected function write( $xml ) { - $this->result .= $xml; - } -} - -class WP_Export_File_Writer extends WP_Export_Base_Writer { - private $f; - private $file_name; - - public function __construct( $formatter, $file_name ) { - parent::__construct( $formatter ); - $this->file_name = $file_name; - } - - public function export() { - $this->f = fopen( $this->file_name, 'w' ); - if ( !$this->f ) { - throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) ); - } - - try { - parent::export(); - } catch ( WP_Export_Exception $e ) { - throw $e; - } catch ( WP_Export_Term_Exception $e ) { - throw $e; - } - - fclose( $this->f ); - } - - protected function write( $xml ) { - $res = fwrite( $this->f, $xml); - if ( false === $res ) { - throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); - } - } -} - -class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer { - private $result = ''; - private $f; - private $next_file_number = 0; - private $current_file_size = 0; - - function __construct( $formatter, $writer_args = array() ) { - parent::__construct( $formatter ); - //TODO: check if args are not missing - $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; - $this->destination_directory = $writer_args['destination_directory']; - $this->filename_template = $writer_args['filename_template']; - $this->before_posts_xml = $this->formatter->before_posts(); - $this->after_posts_xml = $this->formatter->after_posts(); - } - - public function export() { - $this->start_new_file(); - foreach( $this->formatter->posts() as $post_xml ) { - if ( $this->current_file_size + strlen( $post_xml ) > $this->max_file_size ) { - $this->start_new_file(); - } - $this->write( $post_xml ); - } - $this->close_current_file(); - } - - protected function write( $xml ) { - $res = fwrite( $this->f, $xml); - if ( false === $res ) { - throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); - } - $this->current_file_size += strlen( $xml ); - } - - private function start_new_file() { - if ( $this->f ) { - $this->close_current_file(); - } - $file_path = $this->next_file_path(); - $this->f = fopen( $file_path, 'w' ); - if ( !$this->f ) { - throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); - } - do_action( 'wp_export_new_file', $file_path ); - $this->current_file_size = 0; - $this->write( $this->before_posts_xml ); - } - - private function close_current_file() { - if ( !$this->f ) { - return; - } - $this->write( $this->after_posts_xml ); - fclose( $this->f ); - } - - private function next_file_name() { - $next_file_name = sprintf( $this->filename_template, $this->next_file_number ); - $this->next_file_number++; - return $next_file_name; - } - - private function next_file_path() { - return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name(); - } - -} diff --git a/php/commands/export.php b/src/Export_Command.php similarity index 99% rename from php/commands/export.php rename to src/Export_Command.php index e85b0f9ee..22ee9df37 100644 --- a/php/commands/export.php +++ b/src/Export_Command.php @@ -171,7 +171,7 @@ private static function load_export_api() { define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES ); } - require WP_CLI_ROOT . '/php/export/functions.export.php'; + require dirname( dirname( __FILE__ ) ) . '/functions.php'; } private function validate_args( $args ) { @@ -387,5 +387,3 @@ private function check_max_file_size( $size ) { return true; } } - -WP_CLI::add_command( 'export', 'Export_Command' ); diff --git a/src/WP_Export_Base_Writer.php b/src/WP_Export_Base_Writer.php new file mode 100644 index 000000000..21f7fd35e --- /dev/null +++ b/src/WP_Export_Base_Writer.php @@ -0,0 +1,19 @@ +<?php + +abstract class WP_Export_Base_Writer { + protected $formatter; + + function __construct( $formatter ) { + $this->formatter = $formatter; + } + + public function export() { + $this->write( $this->formatter->before_posts() ); + foreach( $this->formatter->posts() as $post_in_wxr ) { + $this->write( $post_in_wxr ); + } + $this->write( $this->formatter->after_posts() ); + } + + abstract protected function write( $xml ); +} diff --git a/src/WP_Export_Exception.php b/src/WP_Export_Exception.php new file mode 100644 index 000000000..604232212 --- /dev/null +++ b/src/WP_Export_Exception.php @@ -0,0 +1,4 @@ +<?php + +class WP_Export_Exception extends RuntimeException { +} diff --git a/src/WP_Export_File_Writer.php b/src/WP_Export_File_Writer.php new file mode 100644 index 000000000..82be6fae5 --- /dev/null +++ b/src/WP_Export_File_Writer.php @@ -0,0 +1,35 @@ +<?php + +class WP_Export_File_Writer extends WP_Export_Base_Writer { + private $f; + private $file_name; + + public function __construct( $formatter, $file_name ) { + parent::__construct( $formatter ); + $this->file_name = $file_name; + } + + public function export() { + $this->f = fopen( $this->file_name, 'w' ); + if ( !$this->f ) { + throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $this->file_name ) ); + } + + try { + parent::export(); + } catch ( WP_Export_Exception $e ) { + throw $e; + } catch ( WP_Export_Term_Exception $e ) { + throw $e; + } + + fclose( $this->f ); + } + + protected function write( $xml ) { + $res = fwrite( $this->f, $xml); + if ( false === $res ) { + throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); + } + } +} diff --git a/php/export/class-wp-export-oxymel.php b/src/WP_Export_Oxymel.php similarity index 100% rename from php/export/class-wp-export-oxymel.php rename to src/WP_Export_Oxymel.php diff --git a/php/export/class-wp-export-query.php b/src/WP_Export_Query.php similarity index 98% rename from php/export/class-wp-export-query.php rename to src/WP_Export_Query.php index 6258d2169..f31d9ee7e 100644 --- a/php/export/class-wp-export-query.php +++ b/src/WP_Export_Query.php @@ -370,8 +370,3 @@ private function get_comments_for_post( $post ) { } } -class WP_Export_Exception extends RuntimeException { -} - -class WP_Export_Term_Exception extends RuntimeException { -} diff --git a/src/WP_Export_Returner.php b/src/WP_Export_Returner.php new file mode 100644 index 000000000..24baadfab --- /dev/null +++ b/src/WP_Export_Returner.php @@ -0,0 +1,24 @@ +<?php + +class WP_Export_Returner extends WP_Export_Base_Writer { + private $result = ''; + + public function export() { + $this->private = ''; + try { + parent::export(); + } catch ( WP_Export_Exception $e ) { + $message = apply_filters( 'export_error_message', $e->getMessage() ); + return new WP_Error( 'wp-export-error', $message ); + + } catch ( WP_Export_Term_Exception $e ) { + do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); + $message = apply_filters( 'export_term_error_message', $e->getMessage() ); + return new WP_Error( 'wp-export-error', $message ); + } + return $this->result; + } + protected function write( $xml ) { + $this->result .= $xml; + } +} diff --git a/src/WP_Export_Split_Files_Writer.php b/src/WP_Export_Split_Files_Writer.php new file mode 100644 index 000000000..360e722d0 --- /dev/null +++ b/src/WP_Export_Split_Files_Writer.php @@ -0,0 +1,70 @@ +<?php + +class WP_Export_Split_Files_Writer extends WP_Export_Base_Writer { + private $result = ''; + private $f; + private $next_file_number = 0; + private $current_file_size = 0; + + function __construct( $formatter, $writer_args = array() ) { + parent::__construct( $formatter ); + //TODO: check if args are not missing + $this->max_file_size = is_null( $writer_args['max_file_size'] ) ? 15 * MB_IN_BYTES : $writer_args['max_file_size']; + $this->destination_directory = $writer_args['destination_directory']; + $this->filename_template = $writer_args['filename_template']; + $this->before_posts_xml = $this->formatter->before_posts(); + $this->after_posts_xml = $this->formatter->after_posts(); + } + + public function export() { + $this->start_new_file(); + foreach( $this->formatter->posts() as $post_xml ) { + if ( $this->current_file_size + strlen( $post_xml ) > $this->max_file_size ) { + $this->start_new_file(); + } + $this->write( $post_xml ); + } + $this->close_current_file(); + } + + protected function write( $xml ) { + $res = fwrite( $this->f, $xml); + if ( false === $res ) { + throw new WP_Export_Exception( __( 'WP Export: error writing to export file.' ) ); + } + $this->current_file_size += strlen( $xml ); + } + + private function start_new_file() { + if ( $this->f ) { + $this->close_current_file(); + } + $file_path = $this->next_file_path(); + $this->f = fopen( $file_path, 'w' ); + if ( !$this->f ) { + throw new WP_Export_Exception( sprintf( __( 'WP Export: error opening %s for writing.' ), $file_path ) ); + } + do_action( 'wp_export_new_file', $file_path ); + $this->current_file_size = 0; + $this->write( $this->before_posts_xml ); + } + + private function close_current_file() { + if ( !$this->f ) { + return; + } + $this->write( $this->after_posts_xml ); + fclose( $this->f ); + } + + private function next_file_name() { + $next_file_name = sprintf( $this->filename_template, $this->next_file_number ); + $this->next_file_number++; + return $next_file_name; + } + + private function next_file_path() { + return untrailingslashit( $this->destination_directory ) . DIRECTORY_SEPARATOR . $this->next_file_name(); + } + +} diff --git a/src/WP_Export_Term_Exception.php b/src/WP_Export_Term_Exception.php new file mode 100644 index 000000000..9326b48dd --- /dev/null +++ b/src/WP_Export_Term_Exception.php @@ -0,0 +1,4 @@ +<?php + +class WP_Export_Term_Exception extends RuntimeException { +} diff --git a/php/export/class-wp-export-wxr-formatter.php b/src/WP_Export_WXR_Formatter.php similarity index 100% rename from php/export/class-wp-export-wxr-formatter.php rename to src/WP_Export_WXR_Formatter.php diff --git a/src/WP_Export_XML_Over_HTTP.php b/src/WP_Export_XML_Over_HTTP.php new file mode 100644 index 000000000..1a7ee37a5 --- /dev/null +++ b/src/WP_Export_XML_Over_HTTP.php @@ -0,0 +1,42 @@ +<?php + + +class WP_Export_XML_Over_HTTP extends WP_Export_Base_Writer { + private $file_name; + + function __construct( $formatter, $file_name ) { + parent::__construct( $formatter ); + $this->file_name = $file_name; + } + + public function export() { + try { + $export = $this->get_export(); + $this->send_headers(); + echo $export; + } catch ( WP_Export_Exception $e ) { + $message = apply_filters( 'export_error_message', $e->getMessage() ); + wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); + } catch ( WP_Export_Term_Exception $e ) { + do_action( 'export_term_orphaned', $this->formatter->export->missing_parents ); + $message = apply_filters( 'export_term_error_message', $e->getMessage() ); + wp_die( $message, __( 'Export Error' ), array( 'back_link' => true ) ); + } + } + + protected function write( $xml ) { + $this->result .= $xml; + } + + protected function get_export() { + $this->result = ''; + parent::export(); + return $this->result; + } + + protected function send_headers() { + header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: attachment; filename=' . $this->file_name ); + header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true ); + } +} diff --git a/src/WP_Iterator_Exception.php b/src/WP_Iterator_Exception.php new file mode 100644 index 000000000..99151a899 --- /dev/null +++ b/src/WP_Iterator_Exception.php @@ -0,0 +1,4 @@ +<?php + +class WP_Iterator_Exception extends Exception { +} diff --git a/src/WP_Map_Iterator.php b/src/WP_Map_Iterator.php new file mode 100644 index 000000000..74daf2986 --- /dev/null +++ b/src/WP_Map_Iterator.php @@ -0,0 +1,13 @@ +<?php + +class WP_Map_Iterator extends IteratorIterator { + function __construct( $iterator, $callback ) { + $this->callback = $callback; + parent::__construct( $iterator ); + } + + function current() { + $original_current = parent::current(); + return call_user_func( $this->callback, $original_current ); + } +} diff --git a/php/export/iterators.php b/src/WP_Post_IDs_Iterator.php similarity index 81% rename from php/export/iterators.php rename to src/WP_Post_IDs_Iterator.php index 86572f56c..49ad84d38 100644 --- a/php/export/iterators.php +++ b/src/WP_Post_IDs_Iterator.php @@ -1,15 +1,4 @@ <?php -class WP_Map_Iterator extends IteratorIterator { - function __construct( $iterator, $callback ) { - $this->callback = $callback; - parent::__construct( $iterator ); - } - - function current() { - $original_current = parent::current(); - return call_user_func( $this->callback, $original_current ); - } -} class WP_Post_IDs_Iterator implements Iterator { private $limit = 100; @@ -75,6 +64,3 @@ private function load_next_posts_from_db() { return true; } } - -class WP_Iterator_Exception extends Exception { -} diff --git a/utils/behat-tags.php b/utils/behat-tags.php new file mode 100644 index 000000000..964711458 --- /dev/null +++ b/utils/behat-tags.php @@ -0,0 +1,46 @@ +<?php +/** + * Generate a list of tags to skip during the test run. + * + * Require a minimum version of WordPress: + * + * @require-wp-4.0 + * Scenario: Core translation CRUD + * + * Then use in bash script: + * + * BEHAT_TAGS=$(php behat-tags.php) + * vendor/bin/behat --format progress $BEHAT_TAGS + */ + +function version_tags( $prefix, $current, $operator = '<' ) { + if ( ! $current ) + return array(); + + exec( "grep '@{$prefix}-[0-9\.]*' -h -o features/*.feature | uniq", $existing_tags ); + + $skip_tags = array(); + + foreach ( $existing_tags as $tag ) { + $compare = str_replace( "@{$prefix}-", '', $tag ); + if ( version_compare( $current, $compare, $operator ) ) { + $skip_tags[] = $tag; + } + } + + return $skip_tags; +} + +$skip_tags = array_merge( + version_tags( 'require-wp', getenv( 'WP_VERSION' ), '<' ), + version_tags( 'require-php', PHP_VERSION, '<' ), + version_tags( 'less-than-php', PHP_VERSION, '>' ) +); + +# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +$skip_tags[] = '@github-api'; + +if ( !empty( $skip_tags ) ) { + echo '--tags=~' . implode( '&&~', $skip_tags ); +} + diff --git a/wp-cli.yml b/wp-cli.yml new file mode 100644 index 000000000..bc27a076c --- /dev/null +++ b/wp-cli.yml @@ -0,0 +1,2 @@ +require: + - export-command.php From 48c9fb88f812d56bcf1226fd409210e83f1b6e2f Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 8 Mar 2017 18:34:42 -0800 Subject: [PATCH 5337/5359] Update to a more helpful description --- README.md | 2 +- composer.json | 2 +- src/Export_Command.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3d1cb84f5..00ee0c8df 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ wp-cli/export-command ===================== -Manage exports. +Export WordPress content to a WXR file. [![Build Status](https://travis-ci.org/wp-cli/export-command.svg?branch=master)](https://travis-ci.org/wp-cli/export-command) diff --git a/composer.json b/composer.json index ae4ac0dc5..68318baeb 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "wp-cli/export-command", - "description": "Manage exports.", + "description": "Export WordPress content to a WXR file.", "type": "wp-cli-package", "homepage": "https://github.com/wp-cli/export-command", "support": { diff --git a/src/Export_Command.php b/src/Export_Command.php index 22ee9df37..153d30cb8 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -1,7 +1,7 @@ <?php /** - * Manage exports. + * Export WordPress content to a WXR file. * * ## EXAMPLES * From 16c61961cf8c26b48d6546e14f25fddb4635e00b Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 23 Mar 2017 15:51:47 -0700 Subject: [PATCH 5338/5359] Use Composer to install WP-CLI in tests Doing so ensures tests run against local copy of command, instead of Phar bundled version. --- .travis.yml | 15 ++++++++++---- bin/install-package-tests.sh | 30 --------------------------- composer.json | 6 +++++- export-command.php | 2 +- features/bootstrap/FeatureContext.php | 3 ++- 5 files changed, 19 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6aa217ee1..06ae36d0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,8 @@ cache: env: global: - - WP_CLI_BIN_DIR=/tmp/wp-cli-phar + - PATH="$TRAVIS_BUILD_DIR/vendor/bin:$PATH" + - WP_CLI_BIN_DIR="$TRAVIS_BUILD_DIR/vendor/bin" matrix: include: @@ -32,9 +33,15 @@ matrix: - php: 5.3 env: WP_VERSION=latest -before_script: +before_install: - phpenv config-rm xdebug.ini - - composer validate + +install: + - composer install - bash bin/install-package-tests.sh -script: ./vendor/bin/behat --format progress --strict +before_script: + - composer validate + +script: + - behat --format progress --strict diff --git a/bin/install-package-tests.sh b/bin/install-package-tests.sh index 3026f0826..2ff49dd8d 100755 --- a/bin/install-package-tests.sh +++ b/bin/install-package-tests.sh @@ -2,39 +2,9 @@ set -ex -WP_CLI_BIN_DIR=${WP_CLI_BIN_DIR-/tmp/wp-cli-phar} - -PACKAGE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )" - -download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; - elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi -} - -install_wp_cli() { - - # the Behat test suite will pick up the executable found in $WP_CLI_BIN_DIR - mkdir -p $WP_CLI_BIN_DIR - download https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar $WP_CLI_BIN_DIR/wp - chmod +x $WP_CLI_BIN_DIR/wp - -} - -download_behat() { - - cd $PACKAGE_DIR - composer require --dev behat/behat='~2.5' - -} - install_db() { mysql -e 'CREATE DATABASE IF NOT EXISTS wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot } -install_wp_cli -download_behat install_db diff --git a/composer.json b/composer.json index 68318baeb..b72073e90 100644 --- a/composer.json +++ b/composer.json @@ -20,12 +20,16 @@ "files": [ "export-command.php" ] }, "require": { - "nb/oxymel": "~0.1.0" + "nb/oxymel": "~0.1.0", + "wp-cli/wp-cli": "dev-master" }, "require-dev": { "behat/behat": "~2.5" }, "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + }, "commands": [ "export" ] diff --git a/export-command.php b/export-command.php index 4add2dfca..e3c427727 100644 --- a/export-command.php +++ b/export-command.php @@ -5,7 +5,7 @@ } $autoload = dirname( __FILE__ ) . '/vendor/autoload.php'; -if ( file_exists( $autoload ) ) { +if ( file_exists( $autoload ) && ! class_exists( 'Export_Command' ) ) { require_once $autoload; } diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index cc72cc02c..dfbbfa016 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -318,7 +318,8 @@ public function download_wp( $subdir = '' ) { public function create_config( $subdir = '' ) { $params = self::$db_settings; - $params['dbprefix'] = $subdir ?: 'wp_'; + // Replaces all characters that are not alphanumeric or an underscore into an underscore. + $params['dbprefix'] = $subdir ? preg_replace( '#[^a-zA-Z\_0-9]#', '_', $subdir ) : 'wp_'; $params['skip-salts'] = true; $this->proc( 'wp core config', $params, $subdir )->run_check(); From 31c0582b2c85f394327d7a4b23c9278a4f0ad559 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 24 Mar 2017 05:39:13 -0700 Subject: [PATCH 5339/5359] Remove unnecessary class_exists() check --- export-command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/export-command.php b/export-command.php index e3c427727..4add2dfca 100644 --- a/export-command.php +++ b/export-command.php @@ -5,7 +5,7 @@ } $autoload = dirname( __FILE__ ) . '/vendor/autoload.php'; -if ( file_exists( $autoload ) && ! class_exists( 'Export_Command' ) ) { +if ( file_exists( $autoload ) ) { require_once $autoload; } From 22db6bd4af9486aa79baccc3e632f5de5b61e8c9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 28 Mar 2017 10:22:34 -0700 Subject: [PATCH 5340/5359] Include `"prefer-stable": true,` to always prefer stability --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index b72073e90..8e6b955a8 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ } ], "minimum-stability": "dev", + "prefer-stable": true, "autoload": { "psr-4": {"": "src/"}, "files": [ "export-command.php" ] From f7701a7afeb145d0ac6b00ad0f11f8de9b9d54ea Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 4 Apr 2017 04:22:49 -0700 Subject: [PATCH 5341/5359] Require any WP-CLI, but install dev-master for tests --- .travis.yml | 1 + composer.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 06ae36d0f..1ad1d76c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ before_install: - phpenv config-rm xdebug.ini install: + - composer require wp-cli/wp-cli:dev-master - composer install - bash bin/install-package-tests.sh diff --git a/composer.json b/composer.json index 8e6b955a8..845ac8eed 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require": { "nb/oxymel": "~0.1.0", - "wp-cli/wp-cli": "dev-master" + "wp-cli/wp-cli": "*" }, "require-dev": { "behat/behat": "~2.5" From ee96d30e62ea0656f1128bf177c5de72d2270541 Mon Sep 17 00:00:00 2001 From: Alain Schlesser <alain.schlesser@gmail.com> Date: Tue, 4 Apr 2017 17:48:00 +0200 Subject: [PATCH 5342/5359] Correct `dev-master` alias. To allow for versions like 1.2.0 as well, the branch alias for `dev-master` needs to be changed from `1.0.x-dev` to `1.x-dev`. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 845ac8eed..35bc953d5 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" }, "commands": [ "export" From 4a62e2b33fe92a9e88e603c718278332a0398cbf Mon Sep 17 00:00:00 2001 From: Alain Schlesser <alain.schlesser@gmail.com> Date: Thu, 6 Apr 2017 10:57:19 +0200 Subject: [PATCH 5343/5359] Update testing framework. --- features/bootstrap/FeatureContext.php | 19 ++++++++++++++++--- features/bootstrap/utils.php | 6 +++++- utils/behat-tags.php | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index dfbbfa016..13bb008bf 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -59,9 +59,10 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { */ private static function get_process_env_variables() { // Ensure we're using the expected `wp` binary - $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . "/../../bin" ); + $bin_dir = getenv( 'WP_CLI_BIN_DIR' ) ?: realpath( __DIR__ . '/../../bin' ); + $vendor_dir = realpath( __DIR__ . '/../../vendor/bin' ); $env = array( - 'PATH' => $bin_dir . ':' . getenv( 'PATH' ), + 'PATH' => $bin_dir . ':' . $vendor_dir . ':' . getenv( 'PATH' ), 'BEHAT_RUN' => 1, 'HOME' => '/tmp/wp-cli-home', ); @@ -218,9 +219,21 @@ public function create_run_dir() { public function build_phar( $version = 'same' ) { $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; + // Test running against WP-CLI proper + $make_phar_path = __DIR__ . '/../../utils/make-phar.php'; + if ( ! file_exists( $make_phar_path ) ) { + // Test running against a package installed as a WP-CLI dependency + // WP-CLI installed as a project dependency + $make_phar_path = __DIR__ . '/../../../../../utils/make-phar.php'; + if ( ! file_exists( $make_phar_path ) ) { + // WP-CLI as a dependency of this project + $make_phar_path = __DIR__ . '/../../vendor/wp-cli/wp-cli/utils/make-phar.php'; + } + } + $this->proc( Utils\esc_cmd( 'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s', - __DIR__ . '/../../utils/make-phar.php', + $make_phar_path, $this->variables['PHAR_PATH'], $version ) )->run_check(); diff --git a/features/bootstrap/utils.php b/features/bootstrap/utils.php index d476dc1e8..a4867c57c 100644 --- a/features/bootstrap/utils.php +++ b/features/bootstrap/utils.php @@ -35,7 +35,11 @@ function extract_from_phar( $path ) { function load_dependencies() { if ( inside_phar() ) { - require WP_CLI_ROOT . '/vendor/autoload.php'; + if ( file_exists( WP_CLI_ROOT . '/vendor/autoload.php' ) ) { + require WP_CLI_ROOT . '/vendor/autoload.php'; + } elseif ( file_exists( dirname( dirname( WP_CLI_ROOT ) ) . '/autoload.php' ) ) { + require dirname( dirname( WP_CLI_ROOT ) ) . '/autoload.php'; + } return; } diff --git a/utils/behat-tags.php b/utils/behat-tags.php index 964711458..df836b830 100644 --- a/utils/behat-tags.php +++ b/utils/behat-tags.php @@ -40,6 +40,26 @@ function version_tags( $prefix, $current, $operator = '<' ) { # Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 $skip_tags[] = '@github-api'; +# Require PHP extension, eg 'imagick'. +function extension_tags() { + $extension_tags = array(); + exec( "grep '@require-extension-[A-Za-z_]*' -h -o features/*.feature | uniq", $extension_tags ); + + $skip_tags = array(); + + $substr_start = strlen( '@require-extension-' ); + foreach ( $extension_tags as $tag ) { + $extension = substr( $tag, $substr_start ); + if ( ! extension_loaded( $extension ) ) { + $skip_tags[] = $tag; + } + } + + return $skip_tags; +} + +$skip_tags = array_merge( $skip_tags, extension_tags() ); + if ( !empty( $skip_tags ) ) { echo '--tags=~' . implode( '&&~', $skip_tags ); } From f1620736f04fc9d0a65b5a901dd506759d712b4c Mon Sep 17 00:00:00 2001 From: Stephen Edgar <stephen@netweb.com.au> Date: Sun, 23 Apr 2017 12:12:18 +1000 Subject: [PATCH 5344/5359] Fix Travis CI caching for composer --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1ad1d76c3..5e7dbb281 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,9 @@ branches: - master cache: - - composer - - $HOME/.composer/cache + directories: + - vendor + - $HOME/.composer/cache env: global: From 5a7c2d05d3251db0dd1cc5a24b00bad7d4f1619d Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Tue, 30 May 2017 11:11:04 -0700 Subject: [PATCH 5345/5359] Clarify this command as a bundled command --- README.md | 6 ++++-- composer.json | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00ee0c8df..9e26696e6 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,11 @@ comments, and attachments. WXR files do not include site configuration ## Installing -Installing this package requires WP-CLI v0.23.0 or greater. Update to the latest stable release with `wp cli update`. +This package is included with WP-CLI itself, no additional installation necessary. -Once you've done so, you can install this package with `wp package install wp-cli/export-command`. +To install the latest version of this package over what's included in WP-CLI, run: + + wp package install git@github.com:wp-cli/export-command.git ## Contributing diff --git a/composer.json b/composer.json index 35bc953d5..c9b13aa63 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "branch-alias": { "dev-master": "1.x-dev" }, + "bundled": true, "commands": [ "export" ] From 090d40f2dc70b43e14be19785a1f9137701771ed Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Wed, 2 Aug 2017 09:57:45 -0700 Subject: [PATCH 5346/5359] Update package with latest scaffolded components --- .github/ISSUE_TEMPLATE | 11 + .github/PULL_REQUEST_TEMPLATE | 14 ++ .gitignore | 1 - .travis.yml | 4 +- CONTRIBUTING.md | 8 + README.md | 21 +- bin/test.sh | 13 + features/bootstrap/FeatureContext.php | 330 +++++++++++++++++++++++--- features/bootstrap/Process.php | 21 +- features/bootstrap/ProcessRun.php | 29 +++ features/bootstrap/support.php | 4 +- features/bootstrap/utils.php | 311 ++++++++++++++++++++---- features/steps/given.php | 49 +++- features/steps/then.php | 10 +- utils/behat-tags.php | 12 +- 15 files changed, 735 insertions(+), 103 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE create mode 100644 .github/PULL_REQUEST_TEMPLATE create mode 100644 CONTRIBUTING.md create mode 100644 bin/test.sh diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE new file mode 100644 index 000000000..6c06a141b --- /dev/null +++ b/.github/ISSUE_TEMPLATE @@ -0,0 +1,11 @@ +<!-- + +Thanks for creating a new issue! + +Found a bug or want to suggest an enhancement? Before completing your issue, please review our best practices: https://make.wordpress.org/cli/handbook/bug-reports/ + +Need help with something? GitHub issues aren't for general support questions, but there are other venues you can try: https://wp-cli.org/#support + +You can safely delete this comment. + +--> diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE new file mode 100644 index 000000000..12b980072 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE @@ -0,0 +1,14 @@ +<!-- + +Thanks for submitting a pull request! + +Here's an overview to our process: + +1. One of the project committers will soon provide a code review. +2. You are expected to address the code review comments in a timely manner. +3. Please make sure to include functional tests for your changes. +4. The reviewing committer will merge your pull request as soon as it passes code review (and provided it fits within the scope of the project). + +You can safely delete this comment. + +--> diff --git a/.gitignore b/.gitignore index f3b908269..54f24c800 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ node_modules/ vendor/ *.zip *.tar.gz -composer.lock diff --git a/.travis.yml b/.travis.yml index 5e7dbb281..c5798873c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,8 @@ matrix: env: WP_VERSION=latest - php: 5.6 env: WP_VERSION=latest + - php: 5.6 + env: WP_VERSION=3.7.11 - php: 5.6 env: WP_VERSION=trunk - php: 5.3 @@ -46,4 +48,4 @@ before_script: - composer validate script: - - behat --format progress --strict + - bash bin/test.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..fa86aa52d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,8 @@ +Contributing +============ + +We appreciate you taking the initiative to contribute to this project. + +Contributing isn’t limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. + +For a more thorough introduction, [check out WP-CLI's guide to contributing](https://make.wordpress.org/cli/handbook/contributing/). This package follows those policy and guidelines. diff --git a/README.md b/README.md index 9e26696e6..9e898ee4b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Export WordPress content to a WXR file. [![Build Status](https://travis-ci.org/wp-cli/export-command.svg?branch=master)](https://travis-ci.org/wp-cli/export-command) -Quick links: [Using](#using) | [Installing](#installing) | [Contributing](#contributing) +Quick links: [Using](#using) | [Installing](#installing) | [Contributing](#contributing) | [Support](#support) ## Using @@ -103,30 +103,25 @@ We appreciate you taking the initiative to contribute to this project. Contributing isn’t limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. +For a more thorough introduction, [check out WP-CLI's guide to contributing](https://make.wordpress.org/cli/handbook/contributing/). This package follows those policy and guidelines. + ### Reporting a bug Think you’ve found a bug? We’d love for you to help us get it fixed. Before you create a new issue, you should [search existing issues](https://github.com/wp-cli/export-command/issues?q=label%3Abug%20) to see if there’s an existing resolution to it, or if it’s already been fixed in a newer version. -Once you’ve done a bit of searching and discovered there isn’t an open or fixed issue for your bug, please [create a new issue](https://github.com/wp-cli/export-command/issues/new) with the following: - -1. What you were doing (e.g. "When I run `wp post list`"). -2. What you saw (e.g. "I see a fatal about a class being undefined."). -3. What you expected to see (e.g. "I expected to see the list of posts.") - -Include as much detail as you can, and clear steps to reproduce if possible. +Once you’ve done a bit of searching and discovered there isn’t an open or fixed issue for your bug, please [create a new issue](https://github.com/wp-cli/export-command/issues/new). Include as much detail as you can, and clear steps to reproduce if possible. For more guidance, [review our bug report documentation](https://make.wordpress.org/cli/handbook/bug-reports/). ### Creating a pull request Want to contribute a new feature? Please first [open a new issue](https://github.com/wp-cli/export-command/issues/new) to discuss whether the feature is a good fit for the project. -Once you've decided to commit the time to seeing your pull request through, please follow our guidelines for creating a pull request to make sure it's a pleasant experience: +Once you've decided to commit the time to seeing your pull request through, [please follow our guidelines for creating a pull request](https://make.wordpress.org/cli/handbook/pull-requests/) to make sure it's a pleasant experience. See "[Setting up](https://make.wordpress.org/cli/handbook/pull-requests/#setting-up)" for details specific to working on this package locally. + +## Support -1. Create a feature branch for each contribution. -2. Submit your pull request early for feedback. -3. Include functional tests with your changes. [Read the WP-CLI documentation](https://wp-cli.org/docs/pull-requests/#functional-tests) for an introduction. -4. Follow the [WordPress Coding Standards](http://make.wordpress.org/core/handbook/coding-standards/). +Github issues aren't for general support questions, but there are other venues you can try: http://wp-cli.org/#support *This README.md is generated dynamically from the project's codebase using `wp scaffold package-readme` ([doc](https://github.com/wp-cli/scaffold-package-command#wp-scaffold-package-readme)). To suggest changes, please submit a pull request against the corresponding part of the codebase.* diff --git a/bin/test.sh b/bin/test.sh new file mode 100644 index 000000000..bd3ae6e91 --- /dev/null +++ b/bin/test.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ex + +# Run the unit tests, if they exist +if [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ] +then + phpunit +fi + +# Run the functional tests +BEHAT_TAGS=$(php utils/behat-tags.php) +behat --format progress $BEHAT_TAGS --strict diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 13bb008bf..33620fa61 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -32,7 +32,11 @@ require_once __DIR__ . '/../../php/utils.php'; require_once __DIR__ . '/../../php/WP_CLI/Process.php'; require_once __DIR__ . '/../../php/WP_CLI/ProcessRun.php'; - require_once __DIR__ . '/../../vendor/autoload.php'; + if ( file_exists( __DIR__ . '/../../vendor/autoload.php' ) ) { + require_once __DIR__ . '/../../vendor/autoload.php'; + } else if ( file_exists( __DIR__ . '/../../../../autoload.php' ) ) { + require_once __DIR__ . '/../../../../autoload.php'; + } } /** @@ -40,8 +44,31 @@ */ class FeatureContext extends BehatContext implements ClosuredContextInterface { - private static $cache_dir, $suite_cache_dir; + /** + * The current working directory for scenarios that have a "Given a WP install" or "Given an empty directory" step. Variable RUN_DIR. Lives until the end of the scenario. + */ + private static $run_dir; + + /** + * Where WordPress core is downloaded to for caching, and which is copied to RUN_DIR during a "Given a WP install" step. Lives until manually deleted. + */ + private static $cache_dir; + + /** + * The directory that the WP-CLI cache (WP_CLI_CACHE_DIR, normally "$HOME/.wp-cli/cache") is set to on a "Given an empty cache" step. + * Variable SUITE_CACHE_DIR. Lives until the end of the scenario (or until another "Given an empty cache" step within the scenario). + */ + private static $suite_cache_dir; + + /** + * Where the current WP-CLI source repository is copied to for Composer-based tests with a "Given a dependency on current wp-cli" step. + * Variable COMPOSER_LOCAL_REPOSITORY. Lives until the end of the suite. + */ + private static $composer_local_repository; + /** + * The test database settings. All but `dbname` can be set via environment variables. The database is dropped at the start of each scenario and created on a "Given a WP install" step. + */ private static $db_settings = array( 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', @@ -49,13 +76,24 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface { 'dbhost' => '127.0.0.1', ); + /** + * Array of background process ids started by the current scenario. Used to terminate them at the end of the scenario. + */ private $running_procs = array(); + /** + * Array of variables available as {VARIABLE_NAME}. Some are always set: CORE_CONFIG_SETTINGS, SRC_DIR, CACHE_DIR, WP_VERSION-version-latest. Some are step-dependent: + * RUN_DIR, SUITE_CACHE_DIR, COMPOSER_LOCAL_REPOSITORY, PHAR_PATH. Scenarios can define their own variables using "Given save" steps. Variables are reset for each scenario. + */ public $variables = array(); + /** + * The current feature file and scenario line number as '<file>.<line>'. Used in RUN_DIR and SUITE_CACHE_DIR directory names. Set at the start of each scenario. + */ + private static $temp_dir_infix; + /** * Get the environment variables required for launched `wp` processes - * @beforeSuite */ private static function get_process_env_variables() { // Ensure we're using the expected `wp` binary @@ -69,13 +107,24 @@ private static function get_process_env_variables() { if ( $config_path = getenv( 'WP_CLI_CONFIG_PATH' ) ) { $env['WP_CLI_CONFIG_PATH'] = $config_path; } + if ( $term = getenv( 'TERM' ) ) { + $env['TERM'] = $term; + } + if ( $php_args = getenv( 'WP_CLI_PHP_ARGS' ) ) { + $env['WP_CLI_PHP_ARGS'] = $php_args; + } + if ( $travis_build_dir = getenv( 'TRAVIS_BUILD_DIR' ) ) { + $env['TRAVIS_BUILD_DIR'] = $travis_build_dir; + } return $env; } - // We cache the results of `wp core download` to improve test performance - // Ideally, we'd cache at the HTTP layer for more reliable tests + /** + * We cache the results of `wp core download` to improve test performance. + * Ideally, we'd cache at the HTTP layer for more reliable tests. + */ private static function cache_wp_files() { - self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test core-download-cache'; + self::$cache_dir = sys_get_temp_dir() . '/wp-cli-test-core-download-cache'; if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) return; @@ -105,8 +154,9 @@ public static function prepare( SuiteEvent $event ) { * @AfterSuite */ public static function afterSuite( SuiteEvent $event ) { - if ( self::$suite_cache_dir ) { - Process::create( Utils\esc_cmd( 'rm -r %s', self::$suite_cache_dir ), null, self::get_process_env_variables() )->run(); + if ( self::$composer_local_repository ) { + self::remove_dir( self::$composer_local_repository ); + self::$composer_local_repository = null; } } @@ -115,36 +165,49 @@ public static function afterSuite( SuiteEvent $event ) { */ public function beforeScenario( $event ) { $this->variables['SRC_DIR'] = realpath( __DIR__ . '/../..' ); + + // Used in the names of the RUN_DIR and SUITE_CACHE_DIR directories. + self::$temp_dir_infix = null; + if ( $file = self::get_event_file( $event, $line ) ) { + self::$temp_dir_infix = basename( $file ) . '.' . $line; + } } /** * @AfterScenario */ public function afterScenario( $event ) { - if ( isset( $this->variables['RUN_DIR'] ) ) { + + if ( self::$run_dir ) { // remove altered WP install, unless there's an error if ( $event->getResult() < 4 ) { - $this->proc( Utils\esc_cmd( 'rm -r %s', $this->variables['RUN_DIR'] ) )->run(); + self::remove_dir( self::$run_dir ); } + self::$run_dir = null; } - // Remove WP-CLI package directory + // Remove WP-CLI package directory if any. Set to `wp package path` by package-command and scaffold-package-command features, and by cli-info.feature. if ( isset( $this->variables['PACKAGE_PATH'] ) ) { - $this->proc( Utils\esc_cmd( 'rm -rf %s', $this->variables['PACKAGE_PATH'] ) )->run(); + self::remove_dir( $this->variables['PACKAGE_PATH'] ); + } + + // Remove SUITE_CACHE_DIR if any. + if ( self::$suite_cache_dir ) { + self::remove_dir( self::$suite_cache_dir ); + self::$suite_cache_dir = null; } + // Remove any background processes. foreach ( $this->running_procs as $proc ) { - self::terminate_proc( $proc ); + $status = proc_get_status( $proc ); + self::terminate_proc( $status['pid'] ); } } /** * Terminate a process and any of its children. */ - private static function terminate_proc( $proc ) { - $status = proc_get_status( $proc ); - - $master_pid = $status['pid']; + private static function terminate_proc( $master_pid ) { $output = `ps -o ppid,pid,command | grep $master_pid`; @@ -154,34 +217,51 @@ private static function terminate_proc( $proc ) { $child = $matches[2]; if ( $parent == $master_pid ) { - if ( ! posix_kill( (int) $child, 9 ) ) { - throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); - } + self::terminate_proc( $child ); } } } if ( ! posix_kill( (int) $master_pid, 9 ) ) { - throw new RuntimeException( posix_strerror( posix_get_last_error() ) ); + $errno = posix_get_last_error(); + // Ignore "No such process" error as that's what we want. + if ( 3 /*ESRCH*/ !== $errno ) { + throw new RuntimeException( posix_strerror( $errno ) ); + } } } + /** + * Create a temporary WP_CLI_CACHE_DIR. Exposed as SUITE_CACHE_DIR in "Given an empty cache" step. + */ public static function create_cache_dir() { - self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-suite-cache-", TRUE ); + if ( self::$suite_cache_dir ) { + self::remove_dir( self::$suite_cache_dir ); + } + self::$suite_cache_dir = sys_get_temp_dir() . '/' . uniqid( 'wp-cli-test-suite-cache-' . self::$temp_dir_infix . '-', TRUE ); mkdir( self::$suite_cache_dir ); return self::$suite_cache_dir; } /** * Initializes context. - * Every scenario gets it's own context object. + * Every scenario gets its own context object. * * @param array $parameters context parameters (set them up through behat.yml) */ public function __construct( array $parameters ) { + if ( getenv( 'WP_CLI_TEST_DBUSER' ) ) { + self::$db_settings['dbuser'] = getenv( 'WP_CLI_TEST_DBUSER' ); + } + + if ( false !== getenv( 'WP_CLI_TEST_DBPASS' ) ) { + self::$db_settings['dbpass'] = getenv( 'WP_CLI_TEST_DBPASS' ); + } + if ( getenv( 'WP_CLI_TEST_DBHOST' ) ) { self::$db_settings['dbhost'] = getenv( 'WP_CLI_TEST_DBHOST' ); } + $this->drop_db(); $this->set_cache_dir(); $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); @@ -195,10 +275,20 @@ public function getHookDefinitionResources() { return array(); } + /** + * Replace {VARIABLE_NAME}. Note that variable names can only contain uppercase letters and underscores (no numbers). + */ public function replace_variables( $str ) { - return preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); + $ret = preg_replace_callback( '/\{([A-Z_]+)\}/', array( $this, '_replace_var' ), $str ); + if ( false !== strpos( $str, '{WP_VERSION-' ) ) { + $ret = $this->_replace_wp_versions( $ret ); + } + return $ret; } + /** + * Replace variables callback. + */ private function _replace_var( $matches ) { $cmd = $matches[0]; @@ -209,9 +299,58 @@ private function _replace_var( $matches ) { return $cmd; } + /** + * Substitute "{WP_VERSION-version-latest}" variables. + */ + private function _replace_wp_versions( $str ) { + static $wp_versions = null; + if ( null === $wp_versions ) { + $wp_versions = array(); + + $response = Requests::get( 'https://api.wordpress.org/core/version-check/1.7/', null, array( 'timeout' => 30 ) ); + if ( 200 === $response->status_code && ( $body = json_decode( $response->body ) ) && is_object( $body ) && isset( $body->offers ) && is_array( $body->offers ) ) { + // Latest version alias. + $wp_versions["{WP_VERSION-latest}"] = count( $body->offers ) ? $body->offers[0]->version : ''; + foreach ( $body->offers as $offer ) { + $sub_ver = preg_replace( '/(^[0-9]+\.[0-9]+)\.[0-9]+$/', '$1', $offer->version ); + $sub_ver_key = "{WP_VERSION-{$sub_ver}-latest}"; + + $main_ver = preg_replace( '/(^[0-9]+)\.[0-9]+$/', '$1', $sub_ver ); + $main_ver_key = "{WP_VERSION-{$main_ver}-latest}"; + + if ( ! isset( $wp_versions[ $main_ver_key ] ) ) { + $wp_versions[ $main_ver_key ] = $offer->version; + } + if ( ! isset( $wp_versions[ $sub_ver_key ] ) ) { + $wp_versions[ $sub_ver_key ] = $offer->version; + } + } + } + } + return strtr( $str, $wp_versions ); + } + + /** + * Get the file and line number for the current behat event. + */ + private static function get_event_file( $event, &$line ) { + if ( method_exists( $event, 'getScenario' ) ) { + $scenario_feature = $event->getScenario(); + } elseif ( method_exists( $event, 'getFeature' ) ) { + $scenario_feature = $event->getFeature(); + } else { + return null; + } + $line = $scenario_feature->getLine(); + return $scenario_feature->getFile(); + } + + /** + * Create the RUN_DIR directory, unless already set for this scenario. + */ public function create_run_dir() { if ( !isset( $this->variables['RUN_DIR'] ) ) { - $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( "wp-cli-test-run-", TRUE ); + self::$run_dir = $this->variables['RUN_DIR'] = sys_get_temp_dir() . '/' . uniqid( 'wp-cli-test-run-' . self::$temp_dir_infix . '-', TRUE ); mkdir( $this->variables['RUN_DIR'] ); } } @@ -219,12 +358,12 @@ public function create_run_dir() { public function build_phar( $version = 'same' ) { $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar'; - // Test running against WP-CLI proper - $make_phar_path = __DIR__ . '/../../utils/make-phar.php'; + // Test running against a package installed as a WP-CLI dependency + // WP-CLI installed as a project dependency + $make_phar_path = __DIR__ . '/../../../../../utils/make-phar.php'; if ( ! file_exists( $make_phar_path ) ) { - // Test running against a package installed as a WP-CLI dependency - // WP-CLI installed as a project dependency - $make_phar_path = __DIR__ . '/../../../../../utils/make-phar.php'; + // Test running against WP-CLI proper + $make_phar_path = __DIR__ . '/../../utils/make-phar.php'; if ( ! file_exists( $make_phar_path ) ) { // WP-CLI as a dependency of this project $make_phar_path = __DIR__ . '/../../vendor/wp-cli/wp-cli/utils/make-phar.php'; @@ -239,14 +378,40 @@ public function build_phar( $version = 'same' ) { ) )->run_check(); } + public function download_phar( $version = 'same' ) { + if ( 'same' === $version ) { + $version = WP_CLI_VERSION; + } + + $download_url = sprintf( + 'https://github.com/wp-cli/wp-cli/releases/download/v%1$s/wp-cli-%1$s.phar', + $version + ); + + $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' + . uniqid( 'wp-cli-download-', true ) + . '.phar'; + + Process::create( Utils\esc_cmd( + 'curl -sSfL %1$s > %2$s && chmod +x %2$s', + $download_url, + $this->variables['PHAR_PATH'] + ) )->run_check(); + } + + /** + * CACHE_DIR is a cache for downloaded test data such as images. Lives until manually deleted. + */ private function set_cache_dir() { $path = sys_get_temp_dir() . '/wp-cli-test-cache'; - $this->proc( Utils\esc_cmd( 'mkdir -p %s', $path ) )->run_check(); + if ( ! file_exists( $path ) ) { + mkdir( $path ); + } $this->variables['CACHE_DIR'] = $path; } private static function run_sql( $sql ) { - Utils\run_mysql_command( 'mysql --no-defaults', array( + Utils\run_mysql_command( '/usr/bin/env mysql --no-defaults', array( 'execute' => $sql, 'host' => self::$db_settings['dbhost'], 'user' => self::$db_settings['dbuser'], @@ -309,6 +474,20 @@ public function move_files( $src, $dest ) { rename( $this->variables['RUN_DIR'] . "/$src", $this->variables['RUN_DIR'] . "/$dest" ); } + /** + * Remove a directory (recursive). + */ + public static function remove_dir( $dir ) { + Process::create( Utils\esc_cmd( 'rm -rf %s', $dir ) )->run_check(); + } + + /** + * Copy a directory (recursive). Destination directory must exist. + */ + public static function copy_dir( $src_dir, $dest_dir ) { + Process::create( Utils\esc_cmd( "cp -r %s/* %s", $src_dir, $dest_dir ) )->run_check(); + } + public function add_line_to_wp_config( &$wp_config_code, $line ) { $token = "/* That's all, stop editing!"; @@ -322,27 +501,34 @@ public function download_wp( $subdir = '' ) { mkdir( $dest_dir ); } - $this->proc( Utils\esc_cmd( "cp -r %s/* %s", self::$cache_dir, $dest_dir ) )->run_check(); + self::copy_dir( self::$cache_dir, $dest_dir ); // disable emailing mkdir( $dest_dir . '/wp-content/mu-plugins' ); copy( __DIR__ . '/../extra/no-mail.php', $dest_dir . '/wp-content/mu-plugins/no-mail.php' ); } - public function create_config( $subdir = '' ) { + public function create_config( $subdir = '', $extra_php = false ) { $params = self::$db_settings; + // Replaces all characters that are not alphanumeric or an underscore into an underscore. $params['dbprefix'] = $subdir ? preg_replace( '#[^a-zA-Z\_0-9]#', '_', $subdir ) : 'wp_'; $params['skip-salts'] = true; + + if( false !== $extra_php ) { + $params['extra-php'] = $extra_php; + } + $this->proc( 'wp core config', $params, $subdir )->run_check(); } public function install_wp( $subdir = '' ) { + $subdir = $this->replace_variables( $subdir ); + $this->create_db(); $this->create_run_dir(); $this->download_wp( $subdir ); - $this->create_config( $subdir ); $install_args = array( @@ -355,5 +541,77 @@ public function install_wp( $subdir = '' ) { $this->proc( 'wp core install', $install_args, $subdir )->run_check(); } -} + public function install_wp_with_composer() { + $this->create_run_dir(); + $this->create_db(); + + $yml_path = $this->variables['RUN_DIR'] . "/wp-cli.yml"; + file_put_contents( $yml_path, 'path: wordpress' ); + + $this->proc( 'composer init --name="wp-cli/composer-test" --type="project" --no-interaction' )->run_check(); + $this->proc( 'composer require johnpbloch/wordpress --optimize-autoloader --no-interaction' )->run_check(); + + $config_extra_php = "require_once dirname(__DIR__) . '/vendor/autoload.php';"; + $this->create_config( 'wordpress', $config_extra_php ); + + $install_args = array( + 'url' => 'http://localhost:8080', + 'title' => 'WP CLI Site with both WordPress and wp-cli as Composer dependencies', + 'admin_user' => 'admin', + 'admin_email' => 'admin@example.com', + 'admin_password' => 'password1' + ); + + $this->proc( 'wp core install', $install_args )->run_check(); + } + + public function composer_add_wp_cli_local_repository() { + if ( ! self::$composer_local_repository ) { + self::$composer_local_repository = sys_get_temp_dir() . '/' . uniqid( "wp-cli-composer-local-", TRUE ); + mkdir( self::$composer_local_repository ); + + $env = self::get_process_env_variables(); + $src = isset( $env['TRAVIS_BUILD_DIR'] ) ? $env['TRAVIS_BUILD_DIR'] : realpath( __DIR__ . '/../../' ); + + $dest = self::$composer_local_repository . '/'; + + self::copy_dir( $src, $dest ); + self::remove_dir( $dest . '.git' ); + self::remove_dir( $dest . 'vendor' ); + + $this->proc( "composer config repositories.wp-cli '{\"type\": \"path\", \"url\": \"$dest\", \"options\": {\"symlink\": false}}'" )->run_check(); + } + $this->variables['COMPOSER_LOCAL_REPOSITORY'] = self::$composer_local_repository; + } + + public function composer_require_current_wp_cli() { + $this->composer_add_wp_cli_local_repository(); + $this->proc( 'composer require wp-cli/wp-cli:dev-master --optimize-autoloader --no-interaction' )->run_check(); + } + + public function get_php_binary() { + if ( getenv( 'WP_CLI_PHP_USED' ) ) + return getenv( 'WP_CLI_PHP_USED' ); + + if ( getenv( 'WP_CLI_PHP' ) ) + return getenv( 'WP_CLI_PHP' ); + + if ( defined( 'PHP_BINARY' ) ) + return PHP_BINARY; + + return 'php'; + } + + public function start_php_server() { + $cmd = Utils\esc_cmd( '%s -S %s -t %s -c %s %s', + $this->get_php_binary(), + 'localhost:8080', + $this->variables['RUN_DIR'] . '/wordpress/', + get_cfg_var( 'cfg_file_path' ), + $this->variables['RUN_DIR'] . '/vendor/wp-cli/server-command/router.php' + ); + $this->background_proc( $cmd ); + } + +} diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 74939c5d0..858e1947e 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -6,11 +6,27 @@ * Run a system process, and learn what happened. */ class Process { + /** + * @var string The full command to execute by the system. + */ + private $command; + + /** + * @var string|null The path of the working directory for the process or NULL if not specified (defaults to current working directory). + */ + private $cwd; + + /** + * @var array Environment variables to set when running the command. + */ + private $env; /** * @param string $command Command to execute. * @param string $cwd Directory to execute the command in. * @param array $env Environment variables to set when running the command. + * + * @return Process */ public static function create( $command, $cwd = null, $env = array() ) { $proc = new self; @@ -22,8 +38,6 @@ public static function create( $command, $cwd = null, $env = array() ) { return $proc; } - private $command, $cwd, $env; - private function __construct() {} /** @@ -54,7 +68,7 @@ public function run() { 'return_code' => proc_close( $proc ), 'command' => $this->command, 'cwd' => $cwd, - 'env' => $this->env + 'env' => $this->env, ) ); } @@ -66,6 +80,7 @@ public function run() { public function run_check() { $r = $this->run(); + // $r->STDERR is incorrect, but kept incorrect for backwards-compat if ( $r->return_code || !empty( $r->STDERR ) ) { throw new \RuntimeException( $r ); } diff --git a/features/bootstrap/ProcessRun.php b/features/bootstrap/ProcessRun.php index 4611cfbb6..aedc5f65d 100644 --- a/features/bootstrap/ProcessRun.php +++ b/features/bootstrap/ProcessRun.php @@ -6,6 +6,35 @@ * Results of an executed command. */ class ProcessRun { + /** + * @var string The full command executed by the system. + */ + public $command; + + /** + * @var string Captured output from the process' STDOUT. + */ + public $stdout; + + /** + * @var string Captured output from the process' STDERR. + */ + public $stderr; + + /** + * @var string|null The path of the working directory for the process or NULL if not specified (defaults to current working directory). + */ + public $cwd; + + /** + * @var array Environment variables set for this process. + */ + public $env; + + /** + * @var int Exit code of the process. + */ + public $return_code; /** * @var array $props Properties of executed command. diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index 75ee5fbd3..a37a064f6 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -182,8 +182,8 @@ function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { * @param[in] $expectedYaml the expected YAML string */ function checkThatYamlStringContainsYamlString( $actualYaml, $expectedYaml ) { - $actualValue = spyc_load( $actualYaml ); - $expectedValue = spyc_load( $expectedYaml ); + $actualValue = Mustangostang\Spyc::YAMLLoad( $actualYaml ); + $expectedValue = Mustangostang\Spyc::YAMLLoad( $expectedYaml ); if ( !$actualValue ) { return false; diff --git a/features/bootstrap/utils.php b/features/bootstrap/utils.php index a4867c57c..46796053e 100644 --- a/features/bootstrap/utils.php +++ b/features/bootstrap/utils.php @@ -10,8 +10,10 @@ use \WP_CLI\Dispatcher; use \WP_CLI\Iterators\Transform; +const PHAR_STREAM_PREFIX = 'phar://'; + function inside_phar() { - return 0 === strpos( WP_CLI_ROOT, 'phar://' ); + return 0 === strpos( WP_CLI_ROOT, PHAR_STREAM_PREFIX ); } // Files that need to be read by external programs have to be extracted from the Phar archive. @@ -87,19 +89,6 @@ function load_command( $name ) { } } -function load_all_commands() { - $cmd_dir = WP_CLI_ROOT . '/php/commands'; - - $iterator = new \DirectoryIterator( $cmd_dir ); - - foreach ( $iterator as $filename ) { - if ( '.php' != substr( $filename, -4 ) ) - continue; - - include_once "$cmd_dir/$filename"; - } -} - /** * Like array_map(), except it returns a new iterator, instead of a modified array. * @@ -197,10 +186,15 @@ function assoc_args_to_str( $assoc_args ) { $str = ''; foreach ( $assoc_args as $key => $value ) { - if ( true === $value ) + if ( true === $value ) { $str .= " --$key"; - else + } elseif( is_array( $value ) ) { + foreach( $value as $_ => $v ) { + $str .= assoc_args_to_str( array( $key => $v ) ); + } + } else { $str .= " --$key=" . escapeshellarg( $value ); + } } return $str; @@ -347,6 +341,8 @@ function pick_fields( $item, $fields ) { */ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { + check_proc_available( 'launch_editor_for_input' ); + $tmpdir = get_temp_dir(); do { @@ -421,6 +417,8 @@ function mysql_host_to_cli_args( $raw_host ) { } function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { + check_proc_available( 'run_mysql_command' ); + if ( !$descriptors ) $descriptors = array( STDIN, STDOUT, STDERR ); @@ -434,7 +432,7 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { $old_pass = getenv( 'MYSQL_PWD' ); putenv( 'MYSQL_PWD=' . $pass ); - $final_cmd = $cmd . assoc_args_to_str( $assoc_args ); + $final_cmd = force_env_on_nix_systems( $cmd ) . assoc_args_to_str( $assoc_args ); $proc = proc_open( $final_cmd, $descriptors, $pipes ); if ( !$proc ) @@ -459,7 +457,7 @@ function mustache_render( $template_name, $data = array() ) { $template = file_get_contents( $template_name ); $m = new \Mustache_Engine( array( - 'escape' => function ( $val ) { return $val; } + 'escape' => function ( $val ) { return $val; }, ) ); return $m->render( $template, $data ); @@ -512,9 +510,11 @@ function parse_url( $url ) { /** * Check if we're running in a Windows environment (cmd.exe). + * + * @return bool */ function is_windows() { - return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + return false !== ( $test_is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ) ) ? (bool) $test_is_windows : strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } /** @@ -526,7 +526,7 @@ function is_windows() { function replace_path_consts( $source, $path ) { $replacements = array( '__FILE__' => "'$path'", - '__DIR__' => "'" . dirname( $path ) . "'" + '__DIR__' => "'" . dirname( $path ) . "'", ); $old = array_keys( $replacements ); @@ -563,7 +563,7 @@ function http_request( $method, $url, $data = null, $headers = array(), $options if ( inside_phar() ) { // cURL can't read Phar archives $options['verify'] = extract_from_phar( - WP_CLI_ROOT . '/vendor' . $cert_path ); + WP_CLI_VENDOR_DIR . $cert_path ); } else { foreach( get_vendor_paths() as $vendor_path ) { if ( file_exists( $vendor_path . $cert_path ) ) { @@ -572,7 +572,7 @@ function http_request( $method, $url, $data = null, $headers = array(), $options } } if ( empty( $options['verify'] ) ){ - WP_CLI::error_log( "Cannot find SSL certificate." ); + WP_CLI::error( "Cannot find SSL certificate." ); } } @@ -610,20 +610,20 @@ function increment_version( $current_version, $new_version ) { switch ( $new_version ) { case 'same': // do nothing - break; + break; case 'patch': $current_version[0][2]++; $current_version = array( $current_version[0] ); // drop possible pre-release info - break; + break; case 'minor': $current_version[0][1]++; $current_version[0][2] = 0; $current_version = array( $current_version[0] ); // drop possible pre-release info - break; + break; case 'major': $current_version[0][0]++; @@ -631,11 +631,11 @@ function increment_version( $current_version, $new_version ) { $current_version[0][2] = 0; $current_version = array( $current_version[0] ); // drop possible pre-release info - break; + break; default: // not a keyword $current_version = array( array( $new_version ) ); - break; + break; } // reconstruct version string @@ -698,6 +698,37 @@ function get_flag_value( $assoc_args, $flag, $default = null ) { return isset( $assoc_args[ $flag ] ) ? $assoc_args[ $flag ] : $default; } +/** + * Get the home directory. + * + * @access public + * @category System + * + * @return string + */ +function get_home_dir() { + $home = getenv( 'HOME' ); + if ( ! $home ) { + // In Windows $HOME may not be defined + $home = getenv( 'HOMEDRIVE' ) . getenv( 'HOMEPATH' ); + } + + return rtrim( $home, '/\\' ); +} + +/** + * Appends a trailing slash. + * + * @access public + * @category System + * + * @param string $string What to add the trailing slash to. + * @return string String with trailing slash added. + */ +function trailingslashit( $string ) { + return rtrim( $string, '/\\' ) . '/'; +} + /** * Get the system's temp directory. Warns user if it isn't writable. * @@ -709,17 +740,15 @@ function get_flag_value( $assoc_args, $flag, $default = null ) { function get_temp_dir() { static $temp = ''; - $trailingslashit = function( $path ) { - return rtrim( $path ) . '/'; - }; - - if ( $temp ) - return $trailingslashit( $temp ); + if ( $temp ) { + return $temp; + } - if ( function_exists( 'sys_get_temp_dir' ) ) { - $temp = sys_get_temp_dir(); - } else if ( ini_get( 'upload_tmp_dir' ) ) { - $temp = ini_get( 'upload_tmp_dir' ); + // `sys_get_temp_dir()` introduced PHP 5.2.1. + if ( $try = sys_get_temp_dir() ) { + $temp = trailingslashit( $try ); + } elseif ( $try = ini_get( 'upload_tmp_dir' ) ) { + $temp = trailingslashit( $try ); } else { $temp = '/tmp/'; } @@ -728,7 +757,7 @@ function get_temp_dir() { \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); } - return $trailingslashit( $temp ); + return $temp; } /** @@ -745,18 +774,24 @@ function get_temp_dir() { * @return mixed */ function parse_ssh_url( $url, $component = -1 ) { - preg_match( '#^([^:/~]+)(:([\d]+))?((/|~)(.+))?$#', $url, $matches ); + preg_match( '#^((docker|docker\-compose|ssh):)?(([^@:]+)@)?([^:/~]+)(:([\d]*))?((/|~)(.+))?$#', $url, $matches ); $bits = array(); foreach( array( - 1 => 'host', - 3 => 'port', - 4 => 'path', + 2 => 'scheme', + 4 => 'user', + 5 => 'host', + 7 => 'port', + 8 => 'path', ) as $i => $key ) { if ( ! empty( $matches[ $i ] ) ) { $bits[ $key ] = $matches[ $i ]; } } switch ( $component ) { + case PHP_URL_SCHEME: + return isset( $bits['scheme'] ) ? $bits['scheme'] : null; + case PHP_URL_USER: + return isset( $bits['user'] ) ? $bits['user'] : null; case PHP_URL_HOST: return isset( $bits['host'] ) ? $bits['host'] : null; case PHP_URL_PATH: @@ -840,3 +875,195 @@ function parse_str_to_argv( $arguments ) { function basename( $path, $suffix = '' ) { return urldecode( \basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) ); } + +/** + * Checks whether the output of the current script is a TTY or a pipe / redirect + * + * Returns true if STDOUT output is being redirected to a pipe or a file; false is + * output is being sent directly to the terminal. + * + * If an env variable SHELL_PIPE exists, returned result depends it's + * value. Strings like 1, 0, yes, no, that validate to booleans are accepted. + * + * To enable ASCII formatting even when shell is piped, use the + * ENV variable SHELL_PIPE=0 + * + * @access public + * + * @return bool + */ +function isPiped() { + $shellPipe = getenv('SHELL_PIPE'); + + if ($shellPipe !== false) { + return filter_var($shellPipe, FILTER_VALIDATE_BOOLEAN); + } else { + return (function_exists('posix_isatty') && !posix_isatty(STDOUT)); + } +} + +/** + * Expand within paths to their matching paths. + * + * Has no effect on paths which do not use glob patterns. + * + * @param string|array $paths Single path as a string, or an array of paths. + * @param int $flags Flags to pass to glob. + * + * @return array Expanded paths. + */ +function expand_globs( $paths, $flags = GLOB_BRACE ) { + $expanded = array(); + + foreach ( (array) $paths as $path ) { + $matching = array( $path ); + + if ( preg_match( '/[' . preg_quote( '*?[]{}!', '/' ) . ']/', $path ) ) { + $matching = glob( $path, $flags ) ?: array(); + } + + $expanded = array_merge( $expanded, $matching ); + } + + return array_unique( $expanded ); +} + +/** + * Get the closest suggestion for a mis-typed target term amongst a list of + * options. + * + * Uses the Levenshtein algorithm to calculate the relative "distance" between + * terms. + * + * If the "distance" to the closest term is higher than the threshold, an empty + * string is returned. + * + * @param string $target Target term to get a suggestion for. + * @param array $options Array with possible options. + * @param int $threshold Threshold above which to return an empty string. + * + * @return string + */ +function get_suggestion( $target, array $options, $threshold = 2 ) { + if ( empty( $options ) ) { + return ''; + } + foreach ( $options as $option ) { + $distance = levenshtein( $option, $target ); + $levenshtein[ $option ] = $distance; + } + + // Sort known command strings by distance to user entry. + asort( $levenshtein ); + + // Fetch the closest command string. + reset( $levenshtein ); + $suggestion = key( $levenshtein ); + + // Only return a suggestion if below a given threshold. + return $levenshtein[ $suggestion ] <= $threshold && $suggestion !== $target + ? (string) $suggestion + : ''; +} + +/** + * Get a Phar-safe version of a path. + * + * For paths inside a Phar, this strips the outer filesystem's location to + * reduce the path to what it needs to be within the Phar archive. + * + * Use the __FILE__ or __DIR__ constants as a starting point. + * + * @param string $path An absolute path that might be within a Phar. + * + * @return string A Phar-safe version of the path. + */ +function phar_safe_path( $path ) { + + if ( ! inside_phar() ) { + return $path; + } + + return str_replace( + PHAR_STREAM_PREFIX . WP_CLI_PHAR_PATH . '/', + PHAR_STREAM_PREFIX, + $path + ); +} + +/** + * Check whether a given Command object is part of the bundled set of + * commands. + * + * This function accepts both a fully qualified class name as a string as + * well as an object that extends `WP_CLI\Dispatcher\CompositeCommand`. + * + * @param \WP_CLI\Dispatcher\CompositeCommand|string $command + * + * @return bool + */ +function is_bundled_command( $command ) { + static $classes; + + if ( null === $classes ) { + $classes = array(); + $class_map = WP_CLI_VENDOR_DIR . '/composer/autoload_commands_classmap.php'; + if ( file_exists( WP_CLI_VENDOR_DIR . '/composer/') ) { + $classes = include $class_map; + } + } + + if ( is_object( $command ) ) { + $command = get_class( $command ); + } + + return is_string( $command ) + ? array_key_exists( $command, $classes ) + : false; +} + +/** + * Maybe prefix command string with "/usr/bin/env". + * Removes (if there) if Windows, adds (if not there) if not. + * + * @param string $command + * + * @return string + */ +function force_env_on_nix_systems( $command ) { + $env_prefix = '/usr/bin/env '; + $env_prefix_len = strlen( $env_prefix ); + if ( is_windows() ) { + if ( 0 === strncmp( $command, $env_prefix, $env_prefix_len ) ) { + $command = substr( $command, $env_prefix_len ); + } + } else { + if ( 0 !== strncmp( $command, $env_prefix, $env_prefix_len ) ) { + $command = $env_prefix . $command; + } + } + return $command; +} + +/** + * Check that `proc_open()` and `proc_close()` haven't been disabled. + * + * @param string $context Optional. If set will appear in error message. Default null. + * @param bool $return Optional. If set will return false rather than error out. Default false. + * + * @return bool + */ +function check_proc_available( $context = null, $return = false ) { + if ( ! function_exists( 'proc_open' ) || ! function_exists( 'proc_close' ) ) { + if ( $return ) { + return false; + } + $msg = 'The PHP functions `proc_open()` and/or `proc_close()` are disabled. Please check your PHP ini directive `disable_functions` or suhosin settings.'; + if ( $context ) { + WP_CLI::error( sprintf( "Cannot do '%s': %s", $context, $msg ) ); + } else { + WP_CLI::error( $msg ); + } + } + return true; +} diff --git a/features/steps/given.php b/features/steps/given.php index a1b6a1bb9..e7ae7bf6b 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -10,6 +10,22 @@ function ( $world ) { } ); +$steps->Given( '/^an? (empty|non-existent) ([^\s]+) directory$/', + function ( $world, $empty_or_nonexistent, $dir ) { + $dir = $world->replace_variables( $dir ); + if ( ! WP_CLI\Utils\is_path_absolute( $dir ) ) { + $dir = $world->variables['RUN_DIR'] . "/$dir"; + } + if ( 0 !== strpos( $dir, sys_get_temp_dir() ) ) { + throw new RuntimeException( sprintf( "Attempted to delete directory '%s' that is not in the temp directory '%s'. " . __FILE__ . ':' . __LINE__, $dir, sys_get_temp_dir() ) ); + } + $world->remove_dir( $dir ); + if ( 'empty' === $empty_or_nonexistent ) { + mkdir( $dir, 0777, true /*recursive*/ ); + } + } +); + $steps->Given( '/^an empty cache/', function ( $world ) { $world->variables['SUITE_CACHE_DIR'] = FeatureContext::create_cache_dir(); @@ -20,7 +36,10 @@ function ( $world ) { function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; $full_path = $world->variables['RUN_DIR'] . "/$path"; - Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); + $dir = dirname( $full_path ); + if ( ! file_exists( $dir ) ) { + mkdir( $dir, 0777, true /*recursive*/ ); + } file_put_contents( $full_path, $content ); } ); @@ -62,6 +81,12 @@ function ( $world, $subdir ) { } ); +$steps->Given( '/^a WP install with Composer$/', + function ( $world ) { + $world->install_wp_with_composer(); + } +); + $steps->Given( '/^a WP multisite (subdirectory|subdomain)?\s?install$/', function ( $world, $type = 'subdirectory' ) { $world->install_wp(); @@ -127,12 +152,18 @@ function ( $world, $stream, $output_filter, $key ) { } ); -$steps->Given( '/^a new Phar(?: with version "([^"]+)")$/', - function ( $world, $version ) { +$steps->Given( '/^a new Phar with (?:the same version|version "([^"]+)")$/', + function ( $world, $version = 'same' ) { $world->build_phar( $version ); } ); +$steps->Given( '/^a downloaded Phar with (?:the same version|version "([^"]+)")$/', + function ( $world, $version = 'same' ) { + $world->download_phar( $version ); + } +); + $steps->Given( '/^save the (.+) file ([\'].+[^\'])?as \{(\w+)\}$/', function ( $world, $filepath, $output_filter, $key ) { $full_file = file_get_contents( $world->replace_variables( $filepath ) ); @@ -162,3 +193,15 @@ function($world) { file_put_contents( $wp_config_path, $wp_config_code ); } ); + +$steps->Given( '/^a dependency on current wp-cli$/', + function ( $world ) { + $world->composer_require_current_wp_cli(); + } +); + +$steps->Given( '/^a PHP built-in web server$/', + function ( $world ) { + $world->start_php_server(); + } +); diff --git a/features/steps/then.php b/features/steps/then.php index a5974f16c..887555485 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -145,8 +145,9 @@ function ( $world, $stream ) { } ); -$steps->Then( '/^(STDOUT|STDERR) should be a version string (<|<=|>|>=|==|=|!=|<>) ([+\w\.-]+)$/', +$steps->Then( '/^(STDOUT|STDERR) should be a version string (<|<=|>|>=|==|=|!=|<>) ([+\w.{}-]+)$/', function ( $world, $stream, $operator, $goal_ver ) { + $goal_ver = $world->replace_variables( $goal_ver ); $stream = strtolower( $stream ); if ( false === version_compare( trim( $world->result->$stream, "\n" ), $goal_ver, $operator ) ) { throw new Exception( $world->result ); @@ -208,3 +209,10 @@ function ( $world, $path, $type, $action, $expected = null ) { throw new Exception( 'Invalid expectation' ); } }); + +$steps->Then( '/^the HTTP status code should be (\d+)$/', + function ( $world, $return_code ) { + $response = \Requests::request( 'http://localhost:8080' ); + assertEquals( $return_code, $response->status_code ); + } +); diff --git a/utils/behat-tags.php b/utils/behat-tags.php index df836b830..ee51fc91e 100644 --- a/utils/behat-tags.php +++ b/utils/behat-tags.php @@ -31,8 +31,15 @@ function version_tags( $prefix, $current, $operator = '<' ) { return $skip_tags; } +$wp_version_reqs = array(); +// Only apply @require-wp tags when WP_VERSION isn't 'latest' or 'nightly' +// 'latest' and 'nightly' are expected to work with all features +if ( ! in_array( getenv( 'WP_VERSION' ), array( 'latest', 'nightly', 'trunk' ), true ) ) { + $wp_version_reqs = version_tags( 'require-wp', getenv( 'WP_VERSION' ), '<' ); +} + $skip_tags = array_merge( - version_tags( 'require-wp', getenv( 'WP_VERSION' ), '<' ), + $wp_version_reqs, version_tags( 'require-php', PHP_VERSION, '<' ), version_tags( 'less-than-php', PHP_VERSION, '>' ) ); @@ -40,6 +47,9 @@ function version_tags( $prefix, $current, $operator = '<' ) { # Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 $skip_tags[] = '@github-api'; +# Skip tests known to be broken. +$skip_tags[] = '@broken'; + # Require PHP extension, eg 'imagick'. function extension_tags() { $extension_tags = array(); From 5b72469cb0b60394892d039db2ea8ab31c40c039 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Fri, 4 Aug 2017 07:37:11 -0400 Subject: [PATCH 5347/5359] Use `dist: precise` for PHP 5.3, `dist: trusty` for everything else --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c5798873c..0835aa68c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ sudo: false +dist: trusty language: php @@ -34,6 +35,7 @@ matrix: - php: 5.6 env: WP_VERSION=trunk - php: 5.3 + dist: precise env: WP_VERSION=latest before_install: From bbcc22a28044cab711964ad72fe9c014b43b5439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Fri, 18 Aug 2017 01:03:43 -0300 Subject: [PATCH 5348/5359] issue #9. Added wp export --stdout --- src/Export_Command.php | 51 ++++++++++++++++++++++++++------- src/WP_Export_Stdout_Writer.php | 22 ++++++++++++++ 2 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/WP_Export_Stdout_Writer.php diff --git a/src/Export_Command.php b/src/Export_Command.php index 153d30cb8..dcb420fc0 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -34,6 +34,9 @@ class Export_Command extends WP_CLI_Command { * [--dir=<dirname>] * : Full path to directory where WXR export files should be stored. Defaults * to current working directory. + + * [--stdout] + * : Output the whole XML using standard output (incompatible with --dir=) * * [--skip_comments] * : Don't include comments in the WXR export file. @@ -104,6 +107,7 @@ class Export_Command extends WP_CLI_Command { public function __invoke( $_, $assoc_args ) { $defaults = array( 'dir' => NULL, + 'stdout' => FALSE, 'start_date' => NULL, 'end_date' => NULL, 'post_type' => NULL, @@ -118,14 +122,23 @@ public function __invoke( $_, $assoc_args ) { 'filename_format' => '{site}.wordpress.{date}.{n}.xml', ); + + if (! empty( $assoc_args['stdout'] ) && ( ! empty( $assoc_args['dir'] ) || ! empty( $assoc_args['filename_format'] ) ) ) { + WP_CLI::error( "--stdout and --dir cannot be used together." ); + WP_CLI::halt(1); + } + $assoc_args = wp_parse_args( $assoc_args, $defaults ); + $this->validate_args( $assoc_args ); if ( !function_exists( 'wp_export' ) ) { self::load_export_api(); } - WP_CLI::log( 'Starting export process...' ); + if ( ! $this->stdout ) { + WP_CLI::log( 'Starting export process...' ); + } add_action( 'wp_export_new_file', function( $file_path ) { WP_CLI::log( sprintf( "Writing to file %s", $file_path ) ); @@ -133,20 +146,30 @@ public function __invoke( $_, $assoc_args ) { } ); try { - wp_export( array( - 'filters' => $this->export_args, - 'writer' => 'WP_Export_Split_Files_Writer', - 'writer_args' => array( - 'max_file_size' => $this->max_file_size * MB_IN_BYTES, - 'destination_directory' => $this->wxr_path, - 'filename_template' => self::get_filename_template( $assoc_args['filename_format'] ), - ) - ) ); + if ( $this->stdout ) { + wp_export( array( + 'filters' => $this->export_args, + 'writer' => 'WP_Export_Stdout_Writer', + 'writer_args' => array( ) + ) ); + } else { + wp_export( array( + 'filters' => $this->export_args, + 'writer' => 'WP_Export_Split_Files_Writer', + 'writer_args' => array( + 'max_file_size' => $this->max_file_size * MB_IN_BYTES, + 'destination_directory' => $this->wxr_path, + 'filename_template' => self::get_filename_template( $assoc_args['filename_format'] ), + ) + ) ); + } } catch ( Exception $e ) { WP_CLI::error( $e->getMessage() ); } - WP_CLI::success( 'All done with export.' ); + if ( ! $this->stdout ) { + WP_CLI::success( 'All done with export.' ); + } } private static function get_filename_template( $filename_format ) { @@ -185,6 +208,12 @@ private function validate_args( $args ) { } } + // called last to check possible mutual-exclusion with previous arguments + if (isset($args['stdout'])) { + $this->wxr_path = NULL; + $this->stdout = TRUE; + } + if ( $has_errors ) { WP_CLI::halt(1); } diff --git a/src/WP_Export_Stdout_Writer.php b/src/WP_Export_Stdout_Writer.php new file mode 100644 index 000000000..08501f466 --- /dev/null +++ b/src/WP_Export_Stdout_Writer.php @@ -0,0 +1,22 @@ +<?php + +class WP_Export_Stdout_Writer extends WP_Export_Base_Writer { + + function __construct( $formatter, $writer_args = array() ) { + parent::__construct( $formatter ); + //TODO: check if args are not missing + $this->before_posts_xml = $this->formatter->before_posts(); + $this->after_posts_xml = $this->formatter->after_posts(); + } + + public function export() { + // WP_CLI\Utils\wp_clear_object_cache(); ? + fwrite( STDOUT, $this->before_posts_xml ); + foreach( $this->formatter->posts() as $post_xml ) { + fwrite( STDOUT, $post_xml ); + } + fwrite( STDOUT, $this->after_posts_xml ); + } + + protected function write( $xml ) { } +} From 88fe77938f942e61731fe89a286d7093210a7db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Fri, 25 Aug 2017 16:46:30 -0300 Subject: [PATCH 5349/5359] =?UTF-8?q?issue=20#9.=20commit=20n=C2=B02?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/export.feature | 13 +++++++++++++ src/Export_Command.php | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/features/export.feature b/features/export.feature index f9376c598..eb5482633 100644 --- a/features/export.feature +++ b/features/export.feature @@ -479,3 +479,16 @@ Feature: Export content. """ 0 """ + + Scenario: Export a site to stdout + Given a WP install + And I run `wp comment generate --post_id=1 --count=1` + When I run `wp export --stdout` + Then STDOUT should not contain: + """ + Writing to file + """ + And STDOUT should contain: + """ + <generator> + """ diff --git a/src/Export_Command.php b/src/Export_Command.php index dcb420fc0..e8181ad5a 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -208,8 +208,7 @@ private function validate_args( $args ) { } } - // called last to check possible mutual-exclusion with previous arguments - if (isset($args['stdout'])) { + if ( $args['stdout'] ) { $this->wxr_path = NULL; $this->stdout = TRUE; } From 13bb8b43476d41b6a4217974a2f7b71b545f15b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Fri, 25 Aug 2017 21:51:07 -0300 Subject: [PATCH 5350/5359] minor fixes --- src/Export_Command.php | 5 ++--- src/WP_Export_Stdout_Writer.php | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Export_Command.php b/src/Export_Command.php index e8181ad5a..6d8b1aeda 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -34,7 +34,7 @@ class Export_Command extends WP_CLI_Command { * [--dir=<dirname>] * : Full path to directory where WXR export files should be stored. Defaults * to current working directory. - + * * [--stdout] * : Output the whole XML using standard output (incompatible with --dir=) * @@ -125,7 +125,6 @@ public function __invoke( $_, $assoc_args ) { if (! empty( $assoc_args['stdout'] ) && ( ! empty( $assoc_args['dir'] ) || ! empty( $assoc_args['filename_format'] ) ) ) { WP_CLI::error( "--stdout and --dir cannot be used together." ); - WP_CLI::halt(1); } $assoc_args = wp_parse_args( $assoc_args, $defaults ); @@ -150,7 +149,7 @@ public function __invoke( $_, $assoc_args ) { wp_export( array( 'filters' => $this->export_args, 'writer' => 'WP_Export_Stdout_Writer', - 'writer_args' => array( ) + 'writer_args' => NULL ) ); } else { wp_export( array( diff --git a/src/WP_Export_Stdout_Writer.php b/src/WP_Export_Stdout_Writer.php index 08501f466..cb86f20b3 100644 --- a/src/WP_Export_Stdout_Writer.php +++ b/src/WP_Export_Stdout_Writer.php @@ -2,9 +2,8 @@ class WP_Export_Stdout_Writer extends WP_Export_Base_Writer { - function __construct( $formatter, $writer_args = array() ) { + function __construct( $formatter, $writer_args ) { parent::__construct( $formatter ); - //TODO: check if args are not missing $this->before_posts_xml = $this->formatter->before_posts(); $this->after_posts_xml = $this->formatter->after_posts(); } From 4fa2f458102c3f102cf7393288dfb434cb99257c Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Aug 2017 04:38:16 -0700 Subject: [PATCH 5351/5359] Remove commented out cache clear call --- src/WP_Export_Stdout_Writer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/WP_Export_Stdout_Writer.php b/src/WP_Export_Stdout_Writer.php index cb86f20b3..6bb81cf7e 100644 --- a/src/WP_Export_Stdout_Writer.php +++ b/src/WP_Export_Stdout_Writer.php @@ -9,7 +9,6 @@ function __construct( $formatter, $writer_args ) { } public function export() { - // WP_CLI\Utils\wp_clear_object_cache(); ? fwrite( STDOUT, $this->before_posts_xml ); foreach( $this->formatter->posts() as $post_xml ) { fwrite( STDOUT, $post_xml ); From 5987b21b20d89741cda2d4fe630ab8b821730bd1 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Aug 2017 04:46:56 -0700 Subject: [PATCH 5352/5359] Add more robust tests to verify the export file is valid --- features/export.feature | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/features/export.feature b/features/export.feature index eb5482633..d4b1a37e5 100644 --- a/features/export.feature +++ b/features/export.feature @@ -483,7 +483,13 @@ Feature: Export content. Scenario: Export a site to stdout Given a WP install And I run `wp comment generate --post_id=1 --count=1` - When I run `wp export --stdout` + And I run `wp plugin install wordpress-importer --activate` + + When I run `wp export --stdout > export.xml` + Then STDOUT should be empty + And the return code should be 0 + + When I run `cat export.xml` Then STDOUT should not contain: """ Writing to file @@ -492,3 +498,27 @@ Feature: Export content. """ <generator> """ + + When I run `wp site empty --yes` + Then STDOUT should contain: + """ + Success: + """ + + When I run `wp comment list --format=count` + Then STDOUT should be: + """ + 0 + """ + + When I run `wp import export.xml --authors=skip` + Then STDOUT should contain: + """ + Success: + """ + + When I run `wp comment list --format=count` + Then STDOUT should be: + """ + 2 + """ From 2310e57bd0e660b382073d31111ba647dfc5e413 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Aug 2017 04:53:49 -0700 Subject: [PATCH 5353/5359] Add a test for error scenario --- features/export.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/export.feature b/features/export.feature index d4b1a37e5..93d4c9a83 100644 --- a/features/export.feature +++ b/features/export.feature @@ -522,3 +522,12 @@ Feature: Export content. """ 2 """ + + Scenario: Error when --stdout and --dir are both provided + Given a WP install + + When I try `wp export --stdout --dir=foo` + Then STDERR should be: + """ + Error: --stdout and --dir cannot be used together. + """ From 64a7820ab8898256ad0c2e6e31238c2863ab0ca9 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber <daniel@handbuilt.co> Date: Thu, 31 Aug 2017 04:54:38 -0700 Subject: [PATCH 5354/5359] Remove unnecessary double-quotes --- src/Export_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Export_Command.php b/src/Export_Command.php index 6d8b1aeda..17951770a 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -124,7 +124,7 @@ public function __invoke( $_, $assoc_args ) { if (! empty( $assoc_args['stdout'] ) && ( ! empty( $assoc_args['dir'] ) || ! empty( $assoc_args['filename_format'] ) ) ) { - WP_CLI::error( "--stdout and --dir cannot be used together." ); + WP_CLI::error( '--stdout and --dir cannot be used together.' ); } $assoc_args = wp_parse_args( $assoc_args, $defaults ); From f32a3ae043e0d76ecc3d8d200feffeac5636e476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Tue, 29 Aug 2017 13:19:40 -0300 Subject: [PATCH 5355/5359] wp export --limit --- features/export.feature | 14 ++++++++++++++ src/Export_Command.php | 15 +++++++++++++++ src/WP_Export_Query.php | 8 +++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/features/export.feature b/features/export.feature index 93d4c9a83..a4b8db79d 100644 --- a/features/export.feature +++ b/features/export.feature @@ -414,6 +414,20 @@ Feature: Export content. 0 """ + When I run `wp post generate --post_type=post --count=10` + And I run `wp post export --post_type=post --limit=1 --count | grep -cF '<wp:post_type>post</wp:post_type>'` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post generate --post_type=post --count=10` + And I run `wp post export --limit=1 --count | grep -cP '\<wp:post_type\>(?!attachment).+\</wp:post_type\>' + Then STDOUT should be: + """ + 1 + """ + When I run `wp import {EXPORT_FILE} --authors=skip` Then STDOUT should not be empty diff --git a/src/Export_Command.php b/src/Export_Command.php index 17951770a..78504b037 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -72,6 +72,9 @@ class Export_Command extends WP_CLI_Command { * [--start_id=<pid>] * : Export only posts with IDs greater than or equal to this post ID. * + * [--limit=<num>] + * : Export no more than <num> posts (excluding attachments). + * * [--author=<author>] * : Export only posts by this author. Can be either user login or user ID. * @@ -112,6 +115,7 @@ public function __invoke( $_, $assoc_args ) { 'end_date' => NULL, 'post_type' => NULL, 'post_type__not_in' => NULL, + 'limit' => -1, 'author' => NULL, 'category' => NULL, 'post_status' => NULL, @@ -360,6 +364,17 @@ private function check_author( $author ) { return true; } + private function check_limit( $num ) { + if ( !is_numeric( $num ) || $num <= 0) { + WP_CLI::warning( sprintf( "limit should be a positive integer.", $num ) ); + return false; + } + + $this->export_args['limit'] = (int)$num; + + return true; + } + private function check_category( $category ) { if ( is_null( $category ) ) return true; diff --git a/src/WP_Export_Query.php b/src/WP_Export_Query.php index f31d9ee7e..22de709b4 100644 --- a/src/WP_Export_Query.php +++ b/src/WP_Export_Query.php @@ -15,6 +15,7 @@ class WP_Export_Query { 'start_date' => null, 'end_date' => null, 'start_id' => null, + 'limit' => -1, 'category' => null, ); @@ -154,7 +155,7 @@ private function calculate_post_ids() { if ( $where ) $where = "WHERE $where"; $join = implode( ' ', array_filter( $this->joins ) ); - $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where" ); + $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where {$this->limit()}" ); $post_ids = array_merge( $post_ids, $this->attachments_for_specific_post_types( $post_ids ) ); return $post_ids; } @@ -260,6 +261,11 @@ private function category_where() { $this->wheres[] = $wpdb->prepare( 'tr.term_taxonomy_id = %d', $category->term_taxonomy_id ); } + private function limit() { + if ($this->filters['limit'] > 0) return "LIMIT {$this->filters['limit']}"; + else return ""; + } + private function attachments_for_specific_post_types( $post_ids ) { global $wpdb; if ( !$this->filters['post_type'] ) { From 58ed083cd6f50fd232b8f0dc4a8c64609938ac05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Thu, 31 Aug 2017 01:08:06 -0300 Subject: [PATCH 5356/5359] addressed review --- src/Export_Command.php | 4 ++-- src/WP_Export_Query.php | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Export_Command.php b/src/Export_Command.php index 78504b037..149764bfe 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -115,7 +115,7 @@ public function __invoke( $_, $assoc_args ) { 'end_date' => NULL, 'post_type' => NULL, 'post_type__not_in' => NULL, - 'limit' => -1, + 'limit' => NULL, 'author' => NULL, 'category' => NULL, 'post_status' => NULL, @@ -365,7 +365,7 @@ private function check_author( $author ) { } private function check_limit( $num ) { - if ( !is_numeric( $num ) || $num <= 0) { + if ( ! is_null( $num ) && ( ! is_numeric( $num ) || $num <= 0) ) { WP_CLI::warning( sprintf( "limit should be a positive integer.", $num ) ); return false; } diff --git a/src/WP_Export_Query.php b/src/WP_Export_Query.php index 22de709b4..baccb1105 100644 --- a/src/WP_Export_Query.php +++ b/src/WP_Export_Query.php @@ -15,7 +15,7 @@ class WP_Export_Query { 'start_date' => null, 'end_date' => null, 'start_id' => null, - 'limit' => -1, + 'limit' => NULL, 'category' => null, ); @@ -262,8 +262,12 @@ private function category_where() { } private function limit() { - if ($this->filters['limit'] > 0) return "LIMIT {$this->filters['limit']}"; - else return ""; + if ( $this->filters['limit'] > 0 ) { + return "LIMIT {$this->filters['limit']}"; + } + else { + return ""; + } } private function attachments_for_specific_post_types( $post_ids ) { From aedfad40f4bec8390be69bc16f110a1d080f2291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Thu, 31 Aug 2017 01:09:06 -0300 Subject: [PATCH 5357/5359] intended to have new tests to run. But access to dump output isn't easy (see PR#13) --- features/export.feature | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/features/export.feature b/features/export.feature index a4b8db79d..ff3fea436 100644 --- a/features/export.feature +++ b/features/export.feature @@ -414,27 +414,30 @@ Feature: Export content. 0 """ - When I run `wp post generate --post_type=post --count=10` - And I run `wp post export --post_type=post --limit=1 --count | grep -cF '<wp:post_type>post</wp:post_type>'` + When I run `wp import {EXPORT_FILE} --authors=skip` + Then STDOUT should not be empty + + When I run `wp post list --post_type=any --format=count` Then STDOUT should be: """ - 1 + 0 """ + Scenario: Export posts using --limit + Given a WP install + When I run `wp post generate --post_type=post --count=10` - And I run `wp post export --limit=1 --count | grep -cP '\<wp:post_type\>(?!attachment).+\</wp:post_type\>' + And I run `wp export --post_type=post --limit=1 && grep -cF '<wp:post_type>post</wp:post_type>' {EXPORT_FILE}` Then STDOUT should be: """ 1 """ - When I run `wp import {EXPORT_FILE} --authors=skip` - Then STDOUT should not be empty - - When I run `wp post list --post_type=any --format=count` + When I run `wp post generate --post_type=post --count=10` + And I run `wp export --limit=1 && grep -cP '\<wp:post_type\>(?!attachment).+\</wp:post_type\>' {EXPORT_FILE}` Then STDOUT should be: """ - 0 + 1 """ Scenario: Export a site with a custom filename format From 6bb2850da96aa02187d59b9c4c1b0ed42cc22600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Droz?= <raphael.droz+floss@gmail.com> Date: Tue, 5 Sep 2017 16:08:39 -0300 Subject: [PATCH 5358/5359] --limit test fix --- features/export.feature | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/export.feature b/features/export.feature index ff3fea436..01f3de861 100644 --- a/features/export.feature +++ b/features/export.feature @@ -427,14 +427,15 @@ Feature: Export content. Given a WP install When I run `wp post generate --post_type=post --count=10` - And I run `wp export --post_type=post --limit=1 && grep -cF '<wp:post_type>post</wp:post_type>' {EXPORT_FILE}` + And I run `wp export --post_type=post --limit=1 --stdout | grep -cF '<wp:post_type>post</wp:post_type>'` Then STDOUT should be: """ 1 """ When I run `wp post generate --post_type=post --count=10` - And I run `wp export --limit=1 && grep -cP '\<wp:post_type\>(?!attachment).+\</wp:post_type\>' {EXPORT_FILE}` + And I run `wp post generate --post_type=attachment --count=10` + And I run `wp export --limit=1 --stdout | grep -cP '\<wp:post_type\>(attachment|post)\</wp:post_type\>'` Then STDOUT should be: """ 1 From 04eb59db6ac1fa3cc86649d965fed474bb43351d Mon Sep 17 00:00:00 2001 From: Alain Schlesser <alain.schlesser@gmail.com> Date: Tue, 19 Sep 2017 19:16:32 +0200 Subject: [PATCH 5359/5359] Rename `--limit` to `--max_num_posts` This brings it more in line with other arguments like `--max-file-size`. --- features/export.feature | 6 +++--- src/Export_Command.php | 10 +++++----- src/WP_Export_Query.php | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/features/export.feature b/features/export.feature index 01f3de861..21b642188 100644 --- a/features/export.feature +++ b/features/export.feature @@ -423,11 +423,11 @@ Feature: Export content. 0 """ - Scenario: Export posts using --limit + Scenario: Export posts using --max_num_posts Given a WP install When I run `wp post generate --post_type=post --count=10` - And I run `wp export --post_type=post --limit=1 --stdout | grep -cF '<wp:post_type>post</wp:post_type>'` + And I run `wp export --post_type=post --max_num_posts=1 --stdout | grep -cF '<wp:post_type>post</wp:post_type>'` Then STDOUT should be: """ 1 @@ -435,7 +435,7 @@ Feature: Export content. When I run `wp post generate --post_type=post --count=10` And I run `wp post generate --post_type=attachment --count=10` - And I run `wp export --limit=1 --stdout | grep -cP '\<wp:post_type\>(attachment|post)\</wp:post_type\>'` + And I run `wp export --max_num_posts=1 --stdout | grep -cP '\<wp:post_type\>(attachment|post)\</wp:post_type\>'` Then STDOUT should be: """ 1 diff --git a/src/Export_Command.php b/src/Export_Command.php index 149764bfe..79e7c21c6 100644 --- a/src/Export_Command.php +++ b/src/Export_Command.php @@ -72,7 +72,7 @@ class Export_Command extends WP_CLI_Command { * [--start_id=<pid>] * : Export only posts with IDs greater than or equal to this post ID. * - * [--limit=<num>] + * [--max_num_posts=<num>] * : Export no more than <num> posts (excluding attachments). * * [--author=<author>] @@ -115,7 +115,7 @@ public function __invoke( $_, $assoc_args ) { 'end_date' => NULL, 'post_type' => NULL, 'post_type__not_in' => NULL, - 'limit' => NULL, + 'max_num_posts' => NULL, 'author' => NULL, 'category' => NULL, 'post_status' => NULL, @@ -364,13 +364,13 @@ private function check_author( $author ) { return true; } - private function check_limit( $num ) { + private function check_max_num_posts( $num ) { if ( ! is_null( $num ) && ( ! is_numeric( $num ) || $num <= 0) ) { - WP_CLI::warning( sprintf( "limit should be a positive integer.", $num ) ); + WP_CLI::warning( sprintf( "The --max_num_posts argument should be a positive integer.", $num ) ); return false; } - $this->export_args['limit'] = (int)$num; + $this->export_args['max_num_posts'] = (int)$num; return true; } diff --git a/src/WP_Export_Query.php b/src/WP_Export_Query.php index baccb1105..aac007183 100644 --- a/src/WP_Export_Query.php +++ b/src/WP_Export_Query.php @@ -15,7 +15,7 @@ class WP_Export_Query { 'start_date' => null, 'end_date' => null, 'start_id' => null, - 'limit' => NULL, + 'max_num_posts' => NULL, 'category' => null, ); @@ -155,7 +155,7 @@ private function calculate_post_ids() { if ( $where ) $where = "WHERE $where"; $join = implode( ' ', array_filter( $this->joins ) ); - $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where {$this->limit()}" ); + $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} AS p $join $where {$this->max_num_posts()}" ); $post_ids = array_merge( $post_ids, $this->attachments_for_specific_post_types( $post_ids ) ); return $post_ids; } @@ -261,9 +261,9 @@ private function category_where() { $this->wheres[] = $wpdb->prepare( 'tr.term_taxonomy_id = %d', $category->term_taxonomy_id ); } - private function limit() { - if ( $this->filters['limit'] > 0 ) { - return "LIMIT {$this->filters['limit']}"; + private function max_num_posts() { + if ( $this->filters['max_num_posts'] > 0 ) { + return "LIMIT {$this->filters['max_num_posts']}"; } else { return "";